From c8d866a25aa0499fa084074ebdc59c24ef9f2449 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Mon, 15 Oct 2018 16:40:57 +0000 Subject: Use GCD semaphore on macOS Unnamed POSIX semaphore doesn't work on macOS --- common/threads.c | 35 +++++++++++++++++++++++++++++++++++ common/threads.h | 8 ++++++++ 2 files changed, 43 insertions(+) diff --git a/common/threads.c b/common/threads.c index 6cfe383b..e8301297 100644 --- a/common/threads.c +++ b/common/threads.c @@ -631,6 +631,39 @@ void alcnd_destroy(alcnd_t *cond) } +#ifdef __APPLE__ + +int alsem_init(alsem_t *sem, unsigned int initial) +{ + *sem = dispatch_semaphore_create(initial); + return *sem ? althrd_success : althrd_error; +} + +void alsem_destroy(alsem_t *sem) +{ + dispatch_release(*sem); +} + +int alsem_post(alsem_t *sem) +{ + dispatch_semaphore_signal(*sem); + return althrd_success; +} + +int alsem_wait(alsem_t *sem) +{ + dispatch_semaphore_wait(*sem, DISPATCH_TIME_FOREVER); + return althrd_success; +} + +int alsem_trywait(alsem_t *sem) +{ + long value = dispatch_semaphore_wait(*sem, DISPATCH_TIME_NOW); + return value == 0 ? althrd_success : althrd_busy; +} + +#else /* !__APPLE__ */ + int alsem_init(alsem_t *sem, unsigned int initial) { if(sem_init(sem, 0, initial) == 0) @@ -665,6 +698,8 @@ int alsem_trywait(alsem_t *sem) return althrd_error; } +#endif /* __APPLE__ */ + int altss_create(altss_t *tss_id, altss_dtor_t callback) { diff --git a/common/threads.h b/common/threads.h index b0bebd8d..2d1b4e7f 100644 --- a/common/threads.h +++ b/common/threads.h @@ -130,13 +130,21 @@ inline int altss_set(altss_t tss_id, void *val) #include #include #include +#ifdef __APPLE__ +#include +#else /* !__APPLE__ */ #include +#endif /* __APPLE__ */ typedef pthread_t althrd_t; typedef pthread_mutex_t almtx_t; typedef pthread_cond_t alcnd_t; +#ifdef __APPLE__ +typedef dispatch_semaphore_t alsem_t; +#else /* !__APPLE__ */ typedef sem_t alsem_t; +#endif /* __APPLE__ */ typedef pthread_key_t altss_t; typedef pthread_once_t alonce_flag; -- cgit v1.2.3 From 08226bc6b0147b69a1afb74d83c6a8821e93601b Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Mon, 29 Oct 2018 02:05:45 +0100 Subject: Simplify some statements --- Alc/alconfig.c | 4 ++-- Alc/helpers.c | 2 +- Alc/panning.c | 2 +- OpenAL32/alAuxEffectSlot.c | 4 ++-- OpenAL32/alBuffer.c | 2 +- OpenAL32/alEffect.c | 4 ++-- OpenAL32/alFilter.c | 4 ++-- OpenAL32/alSource.c | 24 ++++++++++++------------ common/uintmap.c | 6 +++--- examples/alrecord.c | 10 +++++----- router/router.c | 6 +++--- utils/alsoft-config/mainwindow.cpp | 2 +- 12 files changed, 35 insertions(+), 35 deletions(-) diff --git a/Alc/alconfig.c b/Alc/alconfig.c index 3d0ed140..050391af 100644 --- a/Alc/alconfig.c +++ b/Alc/alconfig.c @@ -635,7 +635,7 @@ const char *GetConfigValue(const char *devName, const char *blockName, const cha int ConfigValueExists(const char *devName, const char *blockName, const char *keyName) { const char *val = GetConfigValue(devName, blockName, keyName, ""); - return !!val[0]; + return val[0] != 0; } int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret) @@ -692,7 +692,7 @@ int GetConfigValueBool(const char *devName, const char *blockName, const char *k { const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return !!def; + if(!val[0]) return def != 0; return (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || strcasecmp(val, "on") == 0 || atoi(val) != 0); } diff --git a/Alc/helpers.c b/Alc/helpers.c index d2cb6253..0d5087e6 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -842,7 +842,7 @@ static void DirectorySearch(const char *path, const char *ext, vector_al_string continue; len = strlen(dirent->d_name); - if(!(len > extlen)) + if(len <= extlen) continue; if(strcasecmp(dirent->d_name+len-extlen, ext) != 0) continue; diff --git a/Alc/panning.c b/Alc/panning.c index 2c0f3bf2..79627e78 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -730,7 +730,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz ); bformatdec_reset(device->AmbiDecoder, conf, count, device->Frequency, speakermap); - if(!(conf->ChanMask > 0xf)) + if(conf->ChanMask <= 0xf) { device->FOAOut.Ambi = device->Dry.Ambi; device->FOAOut.CoeffCount = device->Dry.CoeffCount; diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 8141e0f6..e1d84bb9 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -116,7 +116,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo context = GetContextRef(); if(!context) return; - if(!(n >= 0)) + if(n < 0) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d effect slots", n); if(n == 0) goto done; @@ -179,7 +179,7 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * if(!context) return; LockEffectSlotList(context); - if(!(n >= 0)) + if(n < 0) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effect slots", n); if(n == 0) goto done; diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index ed712434..0b8c27f5 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -77,7 +77,7 @@ AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) context = GetContextRef(); if(!context) return; - if(!(n >= 0)) + if(n < 0) alSetError(context, AL_INVALID_VALUE, "Generating %d buffers", n); else for(cur = 0;cur < n;cur++) { diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index c2a78a0c..05a6c0a3 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -81,7 +81,7 @@ AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) context = GetContextRef(); if(!context) return; - if(!(n >= 0)) + if(n < 0) alSetError(context, AL_INVALID_VALUE, "Generating %d effects", n); else for(cur = 0;cur < n;cur++) { @@ -109,7 +109,7 @@ AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects) device = context->Device; LockEffectList(device); - if(!(n >= 0)) + if(n < 0) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effects", n); for(i = 0;i < n;i++) { diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index e57653e0..01da4008 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -61,7 +61,7 @@ AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) context = GetContextRef(); if(!context) return; - if(!(n >= 0)) + if(n < 0) alSetError(context, AL_INVALID_VALUE, "Generating %d filters", n); else for(cur = 0;cur < n;cur++) { @@ -90,7 +90,7 @@ AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) device = context->Device; LockFilterList(device); - if(!(n >= 0)) + if(n < 0) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d filters", n); for(i = 0;i < n;i++) { diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index d7c68e4e..2e3a0e2a 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -988,7 +988,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid effect ID %u", values[0]); } - if(!((ALuint)values[1] < (ALuint)device->NumAuxSends)) + if((ALuint)values[1] >= (ALuint)device->NumAuxSends) { UnlockEffectSlotList(Context); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid send %u", values[1]); @@ -1683,7 +1683,7 @@ AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) context = GetContextRef(); if(!context) return; - if(!(n >= 0)) + if(n < 0) alSetError(context, AL_INVALID_VALUE, "Generating %d sources", n); else for(cur = 0;cur < n;cur++) { @@ -1710,7 +1710,7 @@ AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) if(!context) return; LockSourceList(context); - if(!(n >= 0)) + if(n < 0) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d sources", n); /* Check that all Sources are valid */ @@ -1761,7 +1761,7 @@ AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(FloatValsByProp(param) == 1)) + else if(FloatValsByProp(param) != 1) alSetError(Context, AL_INVALID_ENUM, "Invalid float property 0x%04x", param); else SetSourcefv(Source, Context, param, &value); @@ -1783,7 +1783,7 @@ AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1 LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(FloatValsByProp(param) == 3)) + else if(FloatValsByProp(param) != 3) alSetError(Context, AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); else { @@ -1810,7 +1810,7 @@ AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(!(FloatValsByProp(param) > 0)) + else if(FloatValsByProp(param) <= 0) alSetError(Context, AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); else SetSourcefv(Source, Context, param, values); @@ -1833,7 +1833,7 @@ AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble va LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(DoubleValsByProp(param) == 1)) + else if(DoubleValsByProp(param) != 1) alSetError(Context, AL_INVALID_ENUM, "Invalid double property 0x%04x", param); else { @@ -1858,7 +1858,7 @@ AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble v LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(DoubleValsByProp(param) == 3)) + else if(DoubleValsByProp(param) != 3) alSetError(Context, AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); else { @@ -1916,7 +1916,7 @@ AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(IntValsByProp(param) == 1)) + else if(IntValsByProp(param) != 1) alSetError(Context, AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); else SetSourceiv(Source, Context, param, &value); @@ -2568,7 +2568,7 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) if(!context) return; LockSourceList(context); - if(!(n >= 0)) + if(n < 0) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Pausing %d sources", n); for(i = 0;i < n;i++) { @@ -2612,7 +2612,7 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) if(!context) return; LockSourceList(context); - if(!(n >= 0)) + if(n < 0) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Stopping %d sources", n); for(i = 0;i < n;i++) { @@ -2664,7 +2664,7 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) if(!context) return; LockSourceList(context); - if(!(n >= 0)) + if(n < 0) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Rewinding %d sources", n); for(i = 0;i < n;i++) { diff --git a/common/uintmap.c b/common/uintmap.c index 18d52d64..3654779c 100644 --- a/common/uintmap.c +++ b/common/uintmap.c @@ -47,7 +47,7 @@ ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value) do { ALsizei step = count>>1; ALsizei i = pos+step; - if(!(map->keys[i] < key)) + if(map->keys[i] >= key) count = step; else { @@ -130,7 +130,7 @@ ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key) do { ALsizei step = count>>1; ALsizei i = pos+step; - if(!(map->keys[i] < key)) + if(map->keys[i] >= key) count = step; else { @@ -166,7 +166,7 @@ ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key) do { ALsizei step = count>>1; ALsizei i = pos+step; - if(!(map->keys[i] < key)) + if(map->keys[i] >= key) count = step; else { diff --git a/examples/alrecord.c b/examples/alrecord.c index 43b26d35..f60a3055 100644 --- a/examples/alrecord.c +++ b/examples/alrecord.c @@ -133,7 +133,7 @@ int main(int argc, char **argv) break; else if(strcmp(argv[0], "--channels") == 0 || strcmp(argv[0], "-c") == 0) { - if(!(argc > 1)) + if(argc < 2) { fprintf(stderr, "Missing argument for option: %s\n", argv[0]); return 1; @@ -150,7 +150,7 @@ int main(int argc, char **argv) } else if(strcmp(argv[0], "--bits") == 0 || strcmp(argv[0], "-b") == 0) { - if(!(argc > 1)) + if(argc < 2) { fprintf(stderr, "Missing argument for option: %s\n", argv[0]); return 1; @@ -168,7 +168,7 @@ int main(int argc, char **argv) } else if(strcmp(argv[0], "--rate") == 0 || strcmp(argv[0], "-r") == 0) { - if(!(argc > 1)) + if(argc < 2) { fprintf(stderr, "Missing argument for option: %s\n", argv[0]); return 1; @@ -185,7 +185,7 @@ int main(int argc, char **argv) } else if(strcmp(argv[0], "--time") == 0 || strcmp(argv[0], "-t") == 0) { - if(!(argc > 1)) + if(argc < 2) { fprintf(stderr, "Missing argument for option: %s\n", argv[0]); return 1; @@ -202,7 +202,7 @@ int main(int argc, char **argv) } else if(strcmp(argv[0], "--outfile") == 0 || strcmp(argv[0], "-o") == 0) { - if(!(argc > 1)) + if(argc < 2) { fprintf(stderr, "Missing argument for option: %s\n", argv[0]); return 1; diff --git a/router/router.c b/router/router.c index bff73776..9d4346a8 100644 --- a/router/router.c +++ b/router/router.c @@ -419,7 +419,7 @@ ALenum InsertPtrIntMapEntry(PtrIntMap *map, ALvoid *key, ALint value) do { ALsizei step = count>>1; ALsizei i = pos+step; - if(!(map->keys[i] < key)) + if(map->keys[i] >= key) count = step; else { @@ -485,7 +485,7 @@ ALint RemovePtrIntMapKey(PtrIntMap *map, ALvoid *key) do { ALsizei step = count>>1; ALsizei i = pos+step; - if(!(map->keys[i] < key)) + if(map->keys[i] >= key) count = step; else { @@ -521,7 +521,7 @@ ALint LookupPtrIntMapKey(PtrIntMap *map, ALvoid *key) do { ALsizei step = count>>1; ALsizei i = pos+step; - if(!(map->keys[i] < key)) + if(map->keys[i] >= key) count = step; else { diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 110fe4ed..56ac4f3f 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -916,7 +916,7 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("channels", getValueFromName(speakerModeList, ui->channelConfigCombo->currentText())); uint rate = ui->sampleRateCombo->currentText().toUInt(); - if(!(rate > 0)) + if(rate <= 0) settings.setValue("frequency", QString()); else settings.setValue("frequency", rate); -- cgit v1.2.3 From 7f8ef092aac523cf52c77e069cb6091370ab0a7a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 26 Oct 2018 14:11:54 -0700 Subject: Fix a couple internal headers to compile with C++ --- Alc/logging.h | 4 ++-- common/bool.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/logging.h b/Alc/logging.h index 785771c8..2d9f4063 100644 --- a/Alc/logging.h +++ b/Alc/logging.h @@ -17,7 +17,7 @@ extern "C" { extern FILE *LogFile; #if defined(__GNUC__) && !defined(_WIN32) -#define AL_PRINT(T, MSG, ...) fprintf(LogFile, "AL lib: %s %s: "MSG, T, __FUNCTION__ , ## __VA_ARGS__) +#define AL_PRINT(T, MSG, ...) fprintf(LogFile, "AL lib: %s %s: " MSG, T, __FUNCTION__ , ## __VA_ARGS__) #else void al_print(const char *type, const char *func, const char *fmt, ...) DECL_FORMAT(printf, 3,4); #define AL_PRINT(T, ...) al_print((T), __FUNCTION__, __VA_ARGS__) @@ -25,7 +25,7 @@ void al_print(const char *type, const char *func, const char *fmt, ...) DECL_FOR #ifdef __ANDROID__ #include -#define LOG_ANDROID(T, MSG, ...) __android_log_print(T, "openal", "AL lib: %s: "MSG, __FUNCTION__ , ## __VA_ARGS__) +#define LOG_ANDROID(T, MSG, ...) __android_log_print(T, "openal", "AL lib: %s: " MSG, __FUNCTION__ , ## __VA_ARGS__) #else #define LOG_ANDROID(T, MSG, ...) ((void)0) #endif diff --git a/common/bool.h b/common/bool.h index 6f714d09..dbb28e15 100644 --- a/common/bool.h +++ b/common/bool.h @@ -5,7 +5,7 @@ #include #endif -#ifndef bool +#if !defined(__cplusplus) && !defined(bool) #ifdef HAVE_C99_BOOL #define bool _Bool #else -- cgit v1.2.3 From f1058c635f629cb8e2adb791a3cf3bba7fe7c248 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Oct 2018 06:43:31 -0700 Subject: Handle C++-only compile flags in cmake --- CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 39b80250..c05bcb10 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,6 +65,7 @@ endif() SET(CPP_DEFS ) # C pre-process, not C++ SET(INC_PATHS ) SET(C_FLAGS ) +SET(CXX_FLAGS ) SET(LINKER_FLAGS ) SET(EXTRA_LIBS ) @@ -1382,7 +1383,7 @@ CONFIGURE_FILE( # Add a static library with common functions used by multiple targets ADD_LIBRARY(common STATIC ${COMMON_OBJS}) TARGET_COMPILE_DEFINITIONS(common PRIVATE ${CPP_DEFS}) -TARGET_COMPILE_OPTIONS(common PRIVATE ${C_FLAGS}) +TARGET_COMPILE_OPTIONS(common PRIVATE ${C_FLAGS} $<$:${CXX_FLAGS}>) UNSET(HAS_ROUTER) @@ -1415,7 +1416,7 @@ ELSE() ADD_LIBRARY(OpenAL SHARED router/router.c router/router.h router/alc.c router/al.c) TARGET_COMPILE_DEFINITIONS(OpenAL PRIVATE AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES ${CPP_DEFS}) - TARGET_COMPILE_OPTIONS(OpenAL PRIVATE ${C_FLAGS}) + TARGET_COMPILE_OPTIONS(OpenAL PRIVATE ${C_FLAGS} $<$:${CXX_FLAGS}>) TARGET_LINK_LIBRARIES(OpenAL PRIVATE ${LINKER_FLAGS} ${COMMON_LIB}) SET_TARGET_PROPERTIES(OpenAL PROPERTIES PREFIX "") SET_TARGET_PROPERTIES(OpenAL PROPERTIES OUTPUT_NAME ${LIBNAME}) @@ -1441,7 +1442,7 @@ TARGET_COMPILE_DEFINITIONS(${IMPL_TARGET} PRIVATE AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES ${CPP_DEFS}) TARGET_INCLUDE_DIRECTORIES(${IMPL_TARGET} PRIVATE "${OpenAL_SOURCE_DIR}/OpenAL32/Include" "${OpenAL_SOURCE_DIR}/Alc" ${INC_PATHS}) -TARGET_COMPILE_OPTIONS(${IMPL_TARGET} PRIVATE ${C_FLAGS}) +TARGET_COMPILE_OPTIONS(${IMPL_TARGET} PRIVATE ${C_FLAGS} $<$:${CXX_FLAGS}>) TARGET_LINK_LIBRARIES(${IMPL_TARGET} PRIVATE ${LINKER_FLAGS} ${COMMON_LIB} ${EXTRA_LIBS} ${MATH_LIB}) IF(TARGET build_version) -- cgit v1.2.3 From 5148a73a7bc8cc0cad1e157930c936c75e40da2e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Oct 2018 18:56:11 -0700 Subject: Add missing extern "C" --- OpenAL32/Include/sample_cvt.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/OpenAL32/Include/sample_cvt.h b/OpenAL32/Include/sample_cvt.h index c041760e..a3b53d44 100644 --- a/OpenAL32/Include/sample_cvt.h +++ b/OpenAL32/Include/sample_cvt.h @@ -4,6 +4,10 @@ #include "AL/al.h" #include "alBuffer.h" +#ifdef __cplusplus +extern "C" { +#endif + extern const ALshort muLawDecompressionTable[256]; extern const ALshort aLawDecompressionTable[256]; @@ -12,4 +16,8 @@ void Convert_ALshort_ALima4(ALshort *dst, const ALubyte *src, ALsizei numchans, void Convert_ALshort_ALmsadpcm(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len, ALsizei align); +#ifdef __cplusplus +} // extern "C" +#endif + #endif /* SAMPLE_CVT_H */ -- cgit v1.2.3 From fd1361c1982e28fe4be287cb41ae24c3fc926ae8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Oct 2018 18:58:58 -0700 Subject: Add a RESTRICT macro to help with C++ compatibility --- Alc/filters/defs.h | 4 ++-- Alc/filters/nfc.h | 6 +++--- Alc/hrtf.h | 4 ++-- CMakeLists.txt | 18 +++++++++--------- OpenAL32/Include/alu.h | 24 ++++++++++++------------ config.h.in | 3 +++ 6 files changed, 31 insertions(+), 28 deletions(-) diff --git a/Alc/filters/defs.h b/Alc/filters/defs.h index 133a85eb..beb4ab3e 100644 --- a/Alc/filters/defs.h +++ b/Alc/filters/defs.h @@ -84,7 +84,7 @@ inline void BiquadFilter_clear(BiquadFilter *filter) */ void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ); -inline void BiquadFilter_copyParams(BiquadFilter *restrict dst, const BiquadFilter *restrict src) +inline void BiquadFilter_copyParams(BiquadFilter *RESTRICT dst, const BiquadFilter *RESTRICT src) { dst->b0 = src->b0; dst->b1 = src->b1; @@ -93,7 +93,7 @@ inline void BiquadFilter_copyParams(BiquadFilter *restrict dst, const BiquadFilt dst->a2 = src->a2; } -void BiquadFilter_processC(BiquadFilter *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples); +void BiquadFilter_processC(BiquadFilter *filter, ALfloat *RESTRICT dst, const ALfloat *RESTRICT src, ALsizei numsamples); inline void BiquadFilter_passthru(BiquadFilter *filter, ALsizei numsamples) { diff --git a/Alc/filters/nfc.h b/Alc/filters/nfc.h index 12a5a18f..e02c00d8 100644 --- a/Alc/filters/nfc.h +++ b/Alc/filters/nfc.h @@ -38,12 +38,12 @@ void NfcFilterCreate(NfcFilter *nfc, const float w0, const float w1); void NfcFilterAdjust(NfcFilter *nfc, const float w0); /* Near-field control filter for first-order ambisonic channels (1-3). */ -void NfcFilterProcess1(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); +void NfcFilterProcess1(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRICT src, const int count); /* Near-field control filter for second-order ambisonic channels (4-8). */ -void NfcFilterProcess2(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); +void NfcFilterProcess2(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRICT src, const int count); /* Near-field control filter for third-order ambisonic channels (9-15). */ -void NfcFilterProcess3(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); +void NfcFilterProcess3(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRICT src, const int count); #endif /* FILTER_NFC_H */ diff --git a/Alc/hrtf.h b/Alc/hrtf.h index ab68929b..dab6a28e 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -71,7 +71,7 @@ struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry); void Hrtf_IncRef(struct Hrtf *hrtf); void Hrtf_DecRef(struct Hrtf *hrtf); -void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat (*coeffs)[2], ALsizei *delays); +void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat (*RESTRICT coeffs)[2], ALsizei *delays); /** * Produces HRTF filter coefficients for decoding B-Format, given a set of @@ -79,6 +79,6 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, * frequency gains for the decoder. The calculated impulse responses are * ordered and scaled according to the matrix input. */ -void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const struct AngularPoint *AmbiPoints, const ALfloat (*restrict AmbiMatrix)[MAX_AMBI_COEFFS], ALsizei AmbiCount, const ALfloat *restrict AmbiOrderHFGain); +void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const struct AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_COEFFS], ALsizei AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain); #endif /* ALC_HRTF_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index c05bcb10..6247af93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -155,17 +155,17 @@ ENDIF() SET(CPP_DEFS ${CPP_DEFS} _LARGEFILE_SOURCE _LARGE_FILES) SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_LARGEFILE_SOURCE -D_LARGE_FILES") +# C99 has restrict, but C++ does not, so we can only utilize __restrict. +SET(RESTRICT_DECL ) +CHECK_C_SOURCE_COMPILES("int *__restrict foo; + int main() {return 0;}" HAVE___RESTRICT) +IF(HAVE___RESTRICT) + SET(RESTRICT_DECL "__restrict") +ENDIF() + # MSVC may need workarounds for C99 restrict and inline IF(MSVC) - # TODO: Once we truly require C99, these restrict and inline checks should go - # away. - CHECK_C_SOURCE_COMPILES("int *restrict foo; - int main() {return 0;}" HAVE_RESTRICT) - IF(NOT HAVE_RESTRICT) - SET(CPP_DEFS ${CPP_DEFS} "restrict=") - SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Drestrict=") - ENDIF() - + # TODO: Once we truly require C99, this inline check should go away. CHECK_C_SOURCE_COMPILES("inline void foo(void) { } int main() {return 0;}" HAVE_INLINE) IF(NOT HAVE_INLINE) diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index c572fd71..03c388b4 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -87,8 +87,8 @@ typedef union InterpState { } InterpState; typedef const ALfloat* (*ResamplerFunc)(const InterpState *state, - const ALfloat *restrict src, ALsizei frac, ALint increment, - ALfloat *restrict dst, ALsizei dstlen + const ALfloat *RESTRICT src, ALsizei frac, ALint increment, + ALfloat *RESTRICT dst, ALsizei dstlen ); void BsincPrepare(const ALuint increment, BsincState *state, const struct BSincTable *table); @@ -306,25 +306,25 @@ void DeinitVoice(ALvoice *voice); typedef void (*MixerFunc)(const ALfloat *data, ALsizei OutChans, - ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, + ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, ALsizei BufferSize); typedef void (*RowMixerFunc)(ALfloat *OutBuffer, const ALfloat *gains, - const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, + const ALfloat (*RESTRICT data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize); -typedef void (*HrtfMixerFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, +typedef void (*HrtfMixerFunc)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, MixHrtfParams *hrtfparams, HrtfState *hrtfstate, ALsizei BufferSize); -typedef void (*HrtfMixerBlendFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, +typedef void (*HrtfMixerBlendFunc)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, HrtfState *hrtfstate, ALsizei BufferSize); -typedef void (*HrtfDirectMixerFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, +typedef void (*HrtfDirectMixerFunc)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - const ALfloat (*restrict Coeffs)[2], - ALfloat (*restrict Values)[2], ALsizei BufferSize); + const ALfloat (*RESTRICT Coeffs)[2], + ALfloat (*RESTRICT Values)[2], ALsizei BufferSize); #define GAIN_MIX_MAX (16.0f) /* +24dB */ @@ -491,8 +491,8 @@ inline float ScaleAzimuthFront(float azimuth, float scale) } -void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat*restrict coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*restrict coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); /** * ComputePanGains @@ -502,7 +502,7 @@ void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, con * coeffs are a 'slice' of a transform matrix for the input channel, used to * scale and orient the sound samples. */ -inline void ComputePanGains(const MixParams *dry, const ALfloat*restrict coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +inline void ComputePanGains(const MixParams *dry, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { if(dry->CoeffCount > 0) ComputePanningGainsMC(dry->Ambi.Coeffs, dry->NumChannels, dry->CoeffCount, diff --git a/config.h.in b/config.h.in index 9cc6c16b..5b4bdfde 100644 --- a/config.h.in +++ b/config.h.in @@ -8,6 +8,9 @@ /* Define a built-in call indicating an aligned data pointer */ #define ASSUME_ALIGNED(x, y) ${ASSUME_ALIGNED_DECL} +/* Define a restrict macro for non-aliased pointers */ +#define RESTRICT ${RESTRICT_DECL} + /* Define if HRTF data is embedded in the library */ #cmakedefine ALSOFT_EMBED_HRTF_DATA -- cgit v1.2.3 From 8a8ab68f1c9890f98dcd72dc4adacefa250f41df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Oct 2018 05:43:51 -0700 Subject: Add a more C++-friendly VECTOR_RESIZE --- Alc/vector.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/Alc/vector.h b/Alc/vector.h index ed9acfb0..a7be99d0 100644 --- a/Alc/vector.h +++ b/Alc/vector.h @@ -26,6 +26,7 @@ typedef const _##N* const_##N; #define VECTOR_INIT_STATIC() NULL #define VECTOR_DEINIT(_x) do { al_free((_x)); (_x) = NULL; } while(0) +#ifndef __cplusplus #define VECTOR_RESIZE(_x, _s, _c) do { \ size_t _size = (_s); \ size_t _cap = (_c); \ @@ -55,6 +56,37 @@ typedef const _##N* const_##N; (_x)->Size = _size; \ } while(0) \ +#else + +template +inline void do_vector_resize(T *&vec, size_t size, size_t cap) +{ + if(size > cap) + cap = size; + + if(!vec && cap == 0) + return; + + if((vec ? vec->Capacity : 0) < cap) + { + ptrdiff_t data_offset = vec ? (char*)(vec->Data) - (char*)(vec) : sizeof(*vec); + size_t old_size = (vec ? vec->Size : 0); + T *temp; + + temp = reinterpret_cast(al_calloc(16, data_offset + sizeof(vec->Data[0])*cap)); + assert(temp != nullptr); + if(vec) + memcpy(temp->Data, vec->Data, sizeof(vec->Data[0])*old_size); + + al_free(vec); + vec = temp; + vec->Capacity = cap; + } + vec->Size = size; +} +#define VECTOR_RESIZE(_x, _s, _c) do_vector_resize(_x, _s, _c) +#endif // __cplusplus + #define VECTOR_CAPACITY(_x) ((_x) ? (_x)->Capacity : 0) #define VECTOR_SIZE(_x) ((_x) ? (_x)->Size : 0) -- cgit v1.2.3 From 1d7b0f54bee766d685ab74f0c206547431f4f636 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Oct 2018 17:14:32 -0700 Subject: Add another missing extern "C" --- Alc/alconfig.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Alc/alconfig.h b/Alc/alconfig.h index 1e493e2e..cb8d8717 100644 --- a/Alc/alconfig.h +++ b/Alc/alconfig.h @@ -1,6 +1,10 @@ #ifndef ALCONFIG_H #define ALCONFIG_H +#ifdef __cplusplus +extern "C" { +#endif + void ReadALConfig(void); void FreeALConfig(void); @@ -14,4 +18,8 @@ int ConfigValueUInt(const char *devName, const char *blockName, const char *keyN int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret); int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret); +#ifdef __cplusplus +} // extern "C" +#endif + #endif /* ALCONFIG_H */ -- cgit v1.2.3 From 7d5a288e832b34e0117e1b1d7753847cf17f7e01 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Oct 2018 17:42:20 -0700 Subject: Add a couple casts for compiling with C++ Also avoid using __builtin_types_compatible_p, which seems broken with C++? --- Alc/polymorphism.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/polymorphism.h b/Alc/polymorphism.h index fa31fad2..e837b2a5 100644 --- a/Alc/polymorphism.h +++ b/Alc/polymorphism.h @@ -4,7 +4,7 @@ /* Macros to declare inheriting types, and to (down-)cast and up-cast. */ #define DERIVE_FROM_TYPE(t) t t##_parent #define STATIC_CAST(to, obj) (&(obj)->to##_parent) -#ifdef __GNUC__ +#if defined(__GNUC__) && !defined(__cplusplus) #define STATIC_UPCAST(to, from, obj) __extension__({ \ static_assert(__builtin_types_compatible_p(from, __typeof(*(obj))), \ "Invalid upcast object from type"); \ @@ -74,14 +74,14 @@ static void T##_Delete(void *ptr) { al_free(ptr); } /* Allocate and construct an object, with arguments. */ #define NEW_OBJ(_res, T) do { \ - _res = T##_New(sizeof(T)); \ + _res = (T*)T##_New(sizeof(T)); \ if(_res) \ { \ memset(_res, 0, sizeof(T)); \ T##_Construct(_res, EXTRACT_NEW_ARGS /* Allocate and construct an object, with no arguments. */ #define NEW_OBJ0(_res, T) do { \ - _res = T##_New(sizeof(T)); \ + _res = (T*)T##_New(sizeof(T)); \ if(_res) \ { \ memset(_res, 0, sizeof(T)); \ -- cgit v1.2.3 From e876b5011354047719c069dbf0384eba2a6551b2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Oct 2018 10:01:58 -0700 Subject: Remove unnecessary uses of IN_IDE_PARSER --- Alc/compat.h | 2 +- common/align.h | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Alc/compat.h b/Alc/compat.h index 495bfdf2..e0f6cbd9 100644 --- a/Alc/compat.h +++ b/Alc/compat.h @@ -23,7 +23,7 @@ FILE *al_fopen(const char *fname, const char *mode); #define al_fopen fopen -#if defined(HAVE_DLFCN_H) && !defined(IN_IDE_PARSER) +#if defined(HAVE_DLFCN_H) #define HAVE_DYNLOAD 1 #endif diff --git a/common/align.h b/common/align.h index e2dc81df..a5d8a20c 100644 --- a/common/align.h +++ b/common/align.h @@ -6,10 +6,7 @@ #endif #ifndef alignas -#if defined(IN_IDE_PARSER) -/* KDevelop has problems with our align macro, so just use nothing for parsing. */ -#define alignas(x) -#elif defined(HAVE_C11_ALIGNAS) +#if defined(HAVE_C11_ALIGNAS) #define alignas _Alignas #else /* NOTE: Our custom ALIGN macro can't take a type name like alignas can. For -- cgit v1.2.3 From 184241f2ef4935d3bf3e6df78991898bf339b92a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Oct 2018 10:17:30 -0700 Subject: Simplify a couple more checks --- OpenAL32/alSource.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 2e3a0e2a..1f76a069 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -1810,7 +1810,7 @@ AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(FloatValsByProp(param) <= 0) + else if(FloatValsByProp(param) < 1) alSetError(Context, AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); else SetSourcefv(Source, Context, param, values); @@ -1886,7 +1886,7 @@ AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdo alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6)) + else if((count=DoubleValsByProp(param)) < 1 || count > 6) alSetError(Context, AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); else { @@ -1938,7 +1938,7 @@ AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, AL LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(IntValsByProp(param) == 3)) + else if(IntValsByProp(param) != 3) alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); else { @@ -1965,7 +1965,7 @@ AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *val alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(!(IntValsByProp(param) > 0)) + else if(IntValsByProp(param) < 1) alSetError(Context, AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); else SetSourceiv(Source, Context, param, values); @@ -1988,7 +1988,7 @@ AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SO LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(Int64ValsByProp(param) == 1)) + else if(Int64ValsByProp(param) != 1) alSetError(Context, AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); else SetSourcei64v(Source, Context, param, &value); @@ -2010,7 +2010,7 @@ AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOF LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(Int64ValsByProp(param) == 3)) + else if(Int64ValsByProp(param) != 3) alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); else { @@ -2037,7 +2037,7 @@ AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALin alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(!(Int64ValsByProp(param) > 0)) + else if(Int64ValsByProp(param) < 1) alSetError(Context, AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); else SetSourcei64v(Source, Context, param, values); @@ -2061,7 +2061,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *val alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(!(FloatValsByProp(param) == 1)) + else if(FloatValsByProp(param) != 1) alSetError(Context, AL_INVALID_ENUM, "Invalid float property 0x%04x", param); else { @@ -2088,7 +2088,7 @@ AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *va alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(!(FloatValsByProp(param) == 3)) + else if(FloatValsByProp(param) != 3) alSetError(Context, AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); else { @@ -2120,7 +2120,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *va alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(!((count=FloatValsByProp(param)) > 0 && count <= 6)) + else if((count=FloatValsByProp(param)) < 1 && count > 6) alSetError(Context, AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); else { @@ -2151,7 +2151,7 @@ AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble * alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(!(DoubleValsByProp(param) == 1)) + else if(DoubleValsByProp(param) != 1) alSetError(Context, AL_INVALID_ENUM, "Invalid double property 0x%04x", param); else GetSourcedv(Source, Context, param, value); @@ -2173,7 +2173,7 @@ AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(!(DoubleValsByProp(param) == 3)) + else if(DoubleValsByProp(param) != 3) alSetError(Context, AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); else { @@ -2203,7 +2203,7 @@ AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(!(DoubleValsByProp(param) > 0)) + else if(DoubleValsByProp(param) < 1) alSetError(Context, AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); else GetSourcedv(Source, Context, param, values); @@ -2226,7 +2226,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(!(IntValsByProp(param) == 1)) + else if(IntValsByProp(param) != 1) alSetError(Context, AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); else GetSourceiv(Source, Context, param, value); @@ -2249,7 +2249,7 @@ AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(!(IntValsByProp(param) == 3)) + else if(IntValsByProp(param) != 3) alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); else { @@ -2280,7 +2280,7 @@ AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(!(IntValsByProp(param) > 0)) + else if(IntValsByProp(param) < 1) alSetError(Context, AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); else GetSourceiv(Source, Context, param, values); @@ -2303,7 +2303,7 @@ AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64S alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(!(Int64ValsByProp(param) == 1)) + else if(Int64ValsByProp(param) != 1) alSetError(Context, AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); else GetSourcei64v(Source, Context, param, value); @@ -2325,7 +2325,7 @@ AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(!(Int64ValsByProp(param) == 3)) + else if(Int64ValsByProp(param) != 3) alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); else { @@ -2355,7 +2355,7 @@ AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64 alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(!(Int64ValsByProp(param) > 0)) + else if(Int64ValsByProp(param) < 1) alSetError(Context, AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); else GetSourcei64v(Source, Context, param, values); -- cgit v1.2.3 From 903d878460056737b66c188544d6dc18c7b6dc07 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Oct 2018 11:32:50 -0700 Subject: Replace restrict with RESTRICT --- Alc/ALu.c | 26 +++++++-------- Alc/backends/jack.c | 4 +-- Alc/bformatdec.c | 6 ++-- Alc/bformatdec.h | 6 ++-- Alc/bs2b.c | 2 +- Alc/converter.c | 12 +++---- Alc/effects/autowah.c | 4 +-- Alc/effects/chorus.c | 10 +++--- Alc/effects/compressor.c | 4 +-- Alc/effects/dedicated.c | 4 +-- Alc/effects/distortion.c | 6 ++-- Alc/effects/echo.c | 6 ++-- Alc/effects/equalizer.c | 6 ++-- Alc/effects/fshifter.c | 6 ++-- Alc/effects/modulator.c | 6 ++-- Alc/effects/null.c | 4 +-- Alc/effects/pshifter.c | 6 ++-- Alc/effects/reverb.c | 36 ++++++++++---------- Alc/filters/filter.c | 4 +-- Alc/filters/nfc.c | 6 ++-- Alc/filters/splitter.c | 4 +-- Alc/filters/splitter.h | 4 +-- Alc/hrtf.c | 8 ++--- Alc/mastering.c | 30 ++++++++--------- Alc/mastering.h | 2 +- Alc/mixer/defs.h | 68 +++++++++++++++++++------------------- Alc/mixer/hrtf_inc.c | 12 +++---- Alc/mixer/mixer_c.c | 24 +++++++------- Alc/mixer/mixer_neon.c | 16 ++++----- Alc/mixer/mixer_sse.c | 12 +++---- Alc/mixer/mixer_sse2.c | 4 +-- Alc/mixer/mixer_sse41.c | 4 +-- Alc/mixvoice.c | 8 ++--- Alc/panning.c | 12 +++---- Alc/uhjfilter.c | 4 +-- Alc/uhjfilter.h | 2 +- OpenAL32/Include/alAuxEffectSlot.h | 4 +-- OpenAL32/Include/bs2b.h | 2 +- utils/makehrtf.c | 2 +- 39 files changed, 193 insertions(+), 193 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 03abb116..efa78110 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -80,7 +80,7 @@ extern inline size_t clampz(size_t val, size_t min, size_t max); extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu); extern inline ALfloat cubic(ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat mu); -extern inline void aluVectorSet(aluVector *restrict vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w); +extern inline void aluVectorSet(aluVector *RESTRICT vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w); extern inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row, ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3); @@ -1563,12 +1563,12 @@ static void ProcessParamUpdates(ALCcontext *ctx, const struct ALeffectslotArray } -static void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*restrict Buffer)[BUFFERSIZE], +static void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*RESTRICT Buffer)[BUFFERSIZE], int lidx, int ridx, int cidx, ALsizei SamplesToDo, ALsizei NumChannels) { - ALfloat (*restrict lsplit)[BUFFERSIZE] = ASSUME_ALIGNED(Stablizer->LSplit, 16); - ALfloat (*restrict rsplit)[BUFFERSIZE] = ASSUME_ALIGNED(Stablizer->RSplit, 16); + ALfloat (*RESTRICT lsplit)[BUFFERSIZE] = ASSUME_ALIGNED(Stablizer->LSplit, 16); + ALfloat (*RESTRICT rsplit)[BUFFERSIZE] = ASSUME_ALIGNED(Stablizer->RSplit, 16); ALsizei i; /* Apply an all-pass to all channels, except the front-left and front- @@ -1611,18 +1611,18 @@ static void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*restrict Buffer) } } -static void ApplyDistanceComp(ALfloat (*restrict Samples)[BUFFERSIZE], DistanceComp *distcomp, - ALfloat *restrict Values, ALsizei SamplesToDo, ALsizei numchans) +static void ApplyDistanceComp(ALfloat (*RESTRICT Samples)[BUFFERSIZE], DistanceComp *distcomp, + ALfloat *RESTRICT Values, ALsizei SamplesToDo, ALsizei numchans) { ALsizei i, c; Values = ASSUME_ALIGNED(Values, 16); for(c = 0;c < numchans;c++) { - ALfloat *restrict inout = ASSUME_ALIGNED(Samples[c], 16); + ALfloat *RESTRICT inout = ASSUME_ALIGNED(Samples[c], 16); const ALfloat gain = distcomp[c].Gain; const ALsizei base = distcomp[c].Length; - ALfloat *restrict distbuf = ASSUME_ALIGNED(distcomp[c].Buffer, 16); + ALfloat *RESTRICT distbuf = ASSUME_ALIGNED(distcomp[c].Buffer, 16); if(base == 0) { @@ -1654,7 +1654,7 @@ static void ApplyDistanceComp(ALfloat (*restrict Samples)[BUFFERSIZE], DistanceC } } -static void ApplyDither(ALfloat (*restrict Samples)[BUFFERSIZE], ALuint *dither_seed, +static void ApplyDither(ALfloat (*RESTRICT Samples)[BUFFERSIZE], ALuint *dither_seed, const ALfloat quant_scale, const ALsizei SamplesToDo, const ALsizei numchans) { @@ -1671,7 +1671,7 @@ static void ApplyDither(ALfloat (*restrict Samples)[BUFFERSIZE], ALuint *dither_ */ for(c = 0;c < numchans;c++) { - ALfloat *restrict samples = Samples[c]; + ALfloat *RESTRICT samples = Samples[c]; for(i = 0;i < SamplesToDo;i++) { ALfloat val = samples[i] * quant_scale; @@ -1712,7 +1712,7 @@ DECL_TEMPLATE(ALuint, Conv_ALint, 2147483648u) #undef DECL_TEMPLATE #define DECL_TEMPLATE(T, A) \ -static void Write##A(const ALfloat (*restrict InBuffer)[BUFFERSIZE], \ +static void Write##A(const ALfloat (*RESTRICT InBuffer)[BUFFERSIZE], \ ALvoid *OutBuffer, ALsizei Offset, ALsizei SamplesToDo, \ ALsizei numchans) \ { \ @@ -1723,8 +1723,8 @@ static void Write##A(const ALfloat (*restrict InBuffer)[BUFFERSIZE], \ \ for(j = 0;j < numchans;j++) \ { \ - const ALfloat *restrict in = ASSUME_ALIGNED(InBuffer[j], 16); \ - T *restrict out = (T*)OutBuffer + Offset*numchans + j; \ + const ALfloat *RESTRICT in = ASSUME_ALIGNED(InBuffer[j], 16); \ + T *RESTRICT out = (T*)OutBuffer + Offset*numchans + j; \ \ for(i = 0;i < SamplesToDo;i++) \ out[i*numchans] = Conv_##T(in[i]); \ diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index fdbe93f2..899d5a55 100644 --- a/Alc/backends/jack.c +++ b/Alc/backends/jack.c @@ -266,7 +266,7 @@ static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) todo = minu(numframes, data[0].len); for(c = 0;c < numchans;c++) { - const ALfloat *restrict in = ((ALfloat*)data[0].buf) + c; + const ALfloat *RESTRICT in = ((ALfloat*)data[0].buf) + c; for(i = 0;(jack_nframes_t)i < todo;i++) out[c][i] = in[i*numchans]; out[c] += todo; @@ -278,7 +278,7 @@ static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) { for(c = 0;c < numchans;c++) { - const ALfloat *restrict in = ((ALfloat*)data[1].buf) + c; + const ALfloat *RESTRICT in = ((ALfloat*)data[1].buf) + c; for(i = 0;(jack_nframes_t)i < todo;i++) out[c][i] = in[i*numchans]; out[c] += todo; diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 5233d06f..91eb8ca8 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -304,7 +304,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount } -void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo) +void bformatdec_process(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo) { ALsizei chan, i; @@ -350,7 +350,7 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU } -void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo) +void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo) { ALsizei i; @@ -473,7 +473,7 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat } } -void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo) +void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo) { ALsizei i, j; diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 2d7d1d62..3c081807 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -39,10 +39,10 @@ void bformatdec_free(struct BFormatDec **dec); void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS]); /* Decodes the ambisonic input to the given output channels. */ -void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo); +void bformatdec_process(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo); /* Up-samples a first-order input to the decoder's configuration. */ -void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo); +void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo); /* Stand-alone first-order upsampler. Kept here because it shares some stuff @@ -52,6 +52,6 @@ struct AmbiUpsampler *ambiup_alloc(); void ambiup_free(struct AmbiUpsampler **ambiup); void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat w_scale, ALfloat xyz_scale); -void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo); +void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo); #endif /* BFORMATDEC_H */ diff --git a/Alc/bs2b.c b/Alc/bs2b.c index e235e547..e0ce3249 100644 --- a/Alc/bs2b.c +++ b/Alc/bs2b.c @@ -129,7 +129,7 @@ void bs2b_clear(struct bs2b *bs2b) memset(&bs2b->last_sample, 0, sizeof(bs2b->last_sample)); } /* bs2b_clear */ -void bs2b_cross_feed(struct bs2b *bs2b, float *restrict Left, float *restrict Right, int SamplesToDo) +void bs2b_cross_feed(struct bs2b *bs2b, float *RESTRICT Left, float *RESTRICT Right, int SamplesToDo) { float lsamples[128][2]; float rsamples[128][2]; diff --git a/Alc/converter.c b/Alc/converter.c index ef2eb9af..5080f302 100644 --- a/Alc/converter.c +++ b/Alc/converter.c @@ -72,7 +72,7 @@ static inline ALfloat Sample_ALfloat(ALfloat val) { return val; } #define DECL_TEMPLATE(T) \ -static inline void Load_##T(ALfloat *restrict dst, const T *restrict src, \ +static inline void Load_##T(ALfloat *RESTRICT dst, const T *RESTRICT src, \ ALint srcstep, ALsizei samples) \ { \ ALsizei i; \ @@ -138,7 +138,7 @@ static inline ALfloat ALfloat_Sample(ALfloat val) { return val; } #define DECL_TEMPLATE(T) \ -static inline void Store_##T(T *restrict dst, const ALfloat *restrict src, \ +static inline void Store_##T(T *RESTRICT dst, const ALfloat *RESTRICT src, \ ALint dststep, ALsizei samples) \ { \ ALsizei i; \ @@ -235,8 +235,8 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs START_MIXER_MODE(); while(pos < dstframes && *srcframes > 0) { - ALfloat *restrict SrcData = ASSUME_ALIGNED(converter->mSrcSamples, 16); - ALfloat *restrict DstData = ASSUME_ALIGNED(converter->mDstSamples, 16); + ALfloat *RESTRICT SrcData = ASSUME_ALIGNED(converter->mSrcSamples, 16); + ALfloat *RESTRICT DstData = ASSUME_ALIGNED(converter->mDstSamples, 16); ALint prepcount = converter->mSrcPrepCount; ALsizei DataPosFrac = converter->mFracOffset; ALuint64 DataSize64; @@ -377,14 +377,14 @@ void DestroyChannelConverter(ChannelConverter **converter) #define DECL_TEMPLATE(T) \ -static void Mono2Stereo##T(ALfloat *restrict dst, const T *src, ALsizei frames)\ +static void Mono2Stereo##T(ALfloat *RESTRICT dst, const T *src, ALsizei frames)\ { \ ALsizei i; \ for(i = 0;i < frames;i++) \ dst[i*2 + 1] = dst[i*2 + 0] = Sample_##T(src[i]) * 0.707106781187f; \ } \ \ -static void Stereo2Mono##T(ALfloat *restrict dst, const T *src, ALsizei frames)\ +static void Stereo2Mono##T(ALfloat *RESTRICT dst, const T *src, ALsizei frames)\ { \ ALsizei i; \ for(i = 0;i < frames;i++) \ diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c index ba1180ef..f65f1be6 100644 --- a/Alc/effects/autowah.c +++ b/Alc/effects/autowah.c @@ -69,7 +69,7 @@ typedef struct ALautowahState { static ALvoid ALautowahState_Destruct(ALautowahState *state); static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *device); static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALautowahState) DEFINE_ALEFFECTSTATE_VTABLE(ALautowahState); @@ -134,7 +134,7 @@ static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *con state->Chans[i].TargetGains); } -static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { const ALfloat attack_rate = state->AttackRate; const ALfloat release_rate = state->ReleaseRate; diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index f2861cf5..725189b3 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -66,7 +66,7 @@ typedef struct ALchorusState { static ALvoid ALchorusState_Destruct(ALchorusState *state); static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device); static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props); -static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALchorusState) DEFINE_ALEFFECTSTATE_VTABLE(ALchorusState); @@ -188,7 +188,7 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Conte } } -static void GetTriangleDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range, +static void GetTriangleDelays(ALint *RESTRICT delays, ALsizei offset, const ALsizei lfo_range, const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, const ALsizei todo) { @@ -200,7 +200,7 @@ static void GetTriangleDelays(ALint *restrict delays, ALsizei offset, const ALsi } } -static void GetSinusoidDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range, +static void GetSinusoidDelays(ALint *RESTRICT delays, ALsizei offset, const ALsizei lfo_range, const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, const ALsizei todo) { @@ -213,12 +213,12 @@ static void GetSinusoidDelays(ALint *restrict delays, ALsizei offset, const ALsi } -static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { const ALsizei bufmask = state->BufferLength-1; const ALfloat feedback = state->feedback; const ALsizei avgdelay = (state->delay + (FRACTIONONE>>1)) >> FRACTIONBITS; - ALfloat *restrict delaybuf = state->SampleBuffer; + ALfloat *RESTRICT delaybuf = state->SampleBuffer; ALsizei offset = state->offset; ALsizei i, c; ALsizei base; diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index 2b4a76b0..d9b9f1e0 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -50,7 +50,7 @@ typedef struct ALcompressorState { static ALvoid ALcompressorState_Destruct(ALcompressorState *state); static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device); static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALcompressorState) DEFINE_ALEFFECTSTATE_VTABLE(ALcompressorState); @@ -102,7 +102,7 @@ static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCcontex ComputePanGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain, state->Gain[i]); } -static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { ALsizei i, j, k; ALsizei base; diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index 0e1fd389..59c13b77 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -39,7 +39,7 @@ typedef struct ALdedicatedState { static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state); static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *state, ALCdevice *device); static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALdedicatedState) DEFINE_ALEFFECTSTATE_VTABLE(ALdedicatedState); @@ -107,7 +107,7 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext } } -static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { MixSamples(SamplesIn[0], NumChannels, SamplesOut, state->CurrentGains, state->TargetGains, SamplesToDo, 0, SamplesToDo); diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index de8da4fe..f2a70bff 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -48,7 +48,7 @@ typedef struct ALdistortionState { static ALvoid ALdistortionState_Destruct(ALdistortionState *state); static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *device); static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALdistortionState) DEFINE_ALEFFECTSTATE_VTABLE(ALdistortionState); @@ -107,9 +107,9 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontex ComputePanGains(&device->Dry, coeffs, slot->Params.Gain*props->Distortion.Gain, state->Gain); } -static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALfloat (*restrict buffer)[BUFFERSIZE] = state->Buffer; + ALfloat (*RESTRICT buffer)[BUFFERSIZE] = state->Buffer; const ALfloat fc = state->edge_coeff; ALsizei base; ALsizei i, k; diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 4570fcb1..5c323986 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -58,7 +58,7 @@ typedef struct ALechoState { static ALvoid ALechoState_Destruct(ALechoState *state); static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device); static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALechoState) DEFINE_ALEFFECTSTATE_VTABLE(ALechoState); @@ -148,12 +148,12 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->Gains[1].Target); } -static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { const ALsizei mask = state->BufferLength-1; const ALsizei tap1 = state->Tap[0].delay; const ALsizei tap2 = state->Tap[1].delay; - ALfloat *restrict delaybuf = state->SampleBuffer; + ALfloat *RESTRICT delaybuf = state->SampleBuffer; ALsizei offset = state->Offset; ALfloat z1, z2, in, out; ALsizei base; diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 17106127..c62f8e80 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -90,7 +90,7 @@ typedef struct ALequalizerState { static ALvoid ALequalizerState_Destruct(ALequalizerState *state); static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevice *device); static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALequalizerState) DEFINE_ALEFFECTSTATE_VTABLE(ALequalizerState); @@ -176,9 +176,9 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext state->Chans[i].TargetGains); } -static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALfloat (*restrict temps)[BUFFERSIZE] = state->SampleBuffer; + ALfloat (*RESTRICT temps)[BUFFERSIZE] = state->SampleBuffer; ALsizei c; for(c = 0;c < MAX_EFFECT_CHANNELS;c++) diff --git a/Alc/effects/fshifter.c b/Alc/effects/fshifter.c index 7d72472a..6ada7dfa 100644 --- a/Alc/effects/fshifter.c +++ b/Alc/effects/fshifter.c @@ -64,7 +64,7 @@ typedef struct ALfshifterState { static ALvoid ALfshifterState_Destruct(ALfshifterState *state); static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *device); static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALfshifterState) DEFINE_ALEFFECTSTATE_VTABLE(ALfshifterState); @@ -147,10 +147,10 @@ static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *c ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); } -static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { static const ALcomplex complex_zero = { 0.0, 0.0 }; - ALfloat *restrict BufferOut = state->BufferOut; + ALfloat *RESTRICT BufferOut = state->BufferOut; ALsizei j, k, base; for(base = 0;base < SamplesToDo;) diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index e368adb8..dd3d1981 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -51,7 +51,7 @@ typedef struct ALmodulatorState { static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state); static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevice *device); static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALmodulatorState) DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState); @@ -82,7 +82,7 @@ static inline ALfloat One(ALsizei UNUSED(index)) } #define DECL_TEMPLATE(func) \ -static void Modulate##func(ALfloat *restrict dst, ALsizei index, \ +static void Modulate##func(ALfloat *RESTRICT dst, ALsizei index, \ const ALsizei step, ALsizei todo) \ { \ ALsizei i; \ @@ -162,7 +162,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext state->Chans[i].TargetGains); } -static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { const ALsizei step = state->step; ALsizei base; diff --git a/Alc/effects/null.c b/Alc/effects/null.c index e57359e3..6eaa001f 100644 --- a/Alc/effects/null.c +++ b/Alc/effects/null.c @@ -17,7 +17,7 @@ typedef struct ALnullState { static ALvoid ALnullState_Destruct(ALnullState *state); static ALboolean ALnullState_deviceUpdate(ALnullState *state, ALCdevice *device); static ALvoid ALnullState_update(ALnullState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALnullState_process(ALnullState *state, ALsizei samplesToDo, const ALfloat (*restrict samplesIn)[BUFFERSIZE], ALfloat (*restrict samplesOut)[BUFFERSIZE], ALsizei mumChannels); +static ALvoid ALnullState_process(ALnullState *state, ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei mumChannels); static void *ALnullState_New(size_t size); static void ALnullState_Delete(void *ptr); @@ -64,7 +64,7 @@ static ALvoid ALnullState_update(ALnullState* UNUSED(state), const ALCcontext* U * input to the output buffer. The result should be added to the output buffer, * not replace it. */ -static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALsizei UNUSED(samplesToDo), const ALfloatBUFFERSIZE*restrict UNUSED(samplesIn), ALfloatBUFFERSIZE*restrict UNUSED(samplesOut), ALsizei UNUSED(numChannels)) +static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALsizei UNUSED(samplesToDo), const ALfloatBUFFERSIZE*RESTRICT UNUSED(samplesIn), ALfloatBUFFERSIZE*RESTRICT UNUSED(samplesOut), ALsizei UNUSED(numChannels)) { } diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index ed18e9a8..35168eab 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -82,7 +82,7 @@ typedef struct ALpshifterState { static ALvoid ALpshifterState_Destruct(ALpshifterState *state); static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device); static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALpshifterState) DEFINE_ALEFFECTSTATE_VTABLE(ALpshifterState); @@ -211,7 +211,7 @@ static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *c ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); } -static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { /* Pitch shifter engine based on the work of Stephan Bernsee. * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/ @@ -219,7 +219,7 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD static const ALdouble expected = M_PI*2.0 / OVERSAMP; const ALdouble freq_per_bin = state->FreqPerBin; - ALfloat *restrict bufferOut = state->BufferOut; + ALfloat *RESTRICT bufferOut = state->BufferOut; ALsizei count = state->count; ALsizei i, j, k; diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 8ebc089e..ad4aae5c 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -334,7 +334,7 @@ typedef struct ReverbState { static ALvoid ReverbState_Destruct(ReverbState *State); static ALboolean ReverbState_deviceUpdate(ReverbState *State, ALCdevice *Device); static ALvoid ReverbState_update(ReverbState *State, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props); -static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ReverbState) DEFINE_ALEFFECTSTATE_VTABLE(ReverbState); @@ -1069,7 +1069,7 @@ static inline ALfloat FadedDelayLineOut(const DelayLineI *Delay, const ALsizei o static inline void DelayLineIn(const DelayLineI *Delay, ALsizei offset, const ALsizei c, - const ALfloat *restrict in, ALsizei count) + const ALfloat *RESTRICT in, ALsizei count) { ALsizei i; for(i = 0;i < count;i++) @@ -1114,7 +1114,7 @@ static inline void DelayLineIn(const DelayLineI *Delay, ALsizei offset, const AL * Where D is a diagonal matrix (of x), and S is a triangular matrix (of y) * whose combination of signs are being iterated. */ -static inline void VectorPartialScatter(ALfloat *restrict out, const ALfloat *restrict in, +static inline void VectorPartialScatter(ALfloat *RESTRICT out, const ALfloat *RESTRICT in, const ALfloat xCoeff, const ALfloat yCoeff) { out[0] = xCoeff*in[0] + yCoeff*( in[1] + -in[2] + in[3]); @@ -1128,7 +1128,7 @@ static inline void VectorPartialScatter(ALfloat *restrict out, const ALfloat *re /* Utilizes the above, but reverses the input channels. */ static inline void VectorScatterRevDelayIn(const DelayLineI *Delay, ALint offset, const ALfloat xCoeff, const ALfloat yCoeff, - const ALfloat (*restrict in)[MAX_UPDATE_SAMPLES], + const ALfloat (*RESTRICT in)[MAX_UPDATE_SAMPLES], const ALsizei count) { const DelayLineI delay = *Delay; @@ -1154,7 +1154,7 @@ static inline void VectorScatterRevDelayIn(const DelayLineI *Delay, ALint offset * Two static specializations are used for transitional (cross-faded) delay * line processing and non-transitional processing. */ -static void VectorAllpass_Unfaded(ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES], ALsizei offset, +static void VectorAllpass_Unfaded(ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES], ALsizei offset, const ALfloat xCoeff, const ALfloat yCoeff, ALsizei todo, VecAllpass *Vap) { @@ -1184,7 +1184,7 @@ static void VectorAllpass_Unfaded(ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES ++offset; } } -static void VectorAllpass_Faded(ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES], ALsizei offset, +static void VectorAllpass_Faded(ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES], ALsizei offset, const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, ALsizei todo, VecAllpass *Vap) { @@ -1243,9 +1243,9 @@ static void VectorAllpass_Faded(ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES], * line processing and non-transitional processing. */ static void EarlyReflection_Unfaded(ReverbState *State, ALsizei offset, const ALsizei todo, - ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) + ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) { - ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; + ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; const DelayLineI early_delay = State->Early.Delay; const DelayLineI main_delay = State->Delay; const ALfloat mixX = State->MixX; @@ -1294,9 +1294,9 @@ static void EarlyReflection_Unfaded(ReverbState *State, ALsizei offset, const AL VectorScatterRevDelayIn(&main_delay, late_feed_tap, mixX, mixY, out, todo); } static void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsizei todo, - const ALfloat fade, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) + const ALfloat fade, ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) { - ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; + ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; const DelayLineI early_delay = State->Early.Delay; const DelayLineI main_delay = State->Delay; const ALfloat mixX = State->MixX; @@ -1355,7 +1355,7 @@ static void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsi } /* Applies the two T60 damping filter sections. */ -static inline void LateT60Filter(ALfloat *restrict samples, const ALsizei todo, T60Filter *filter) +static inline void LateT60Filter(ALfloat *RESTRICT samples, const ALsizei todo, T60Filter *filter) { ALfloat temp[MAX_UPDATE_SAMPLES]; BiquadFilter_process(&filter->HFFilter, temp, samples, todo); @@ -1377,9 +1377,9 @@ static inline void LateT60Filter(ALfloat *restrict samples, const ALsizei todo, * processing and one for non-transitional processing. */ static void LateReverb_Unfaded(ReverbState *State, ALsizei offset, const ALsizei todo, - ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) + ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) { - ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; + ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; const DelayLineI late_delay = State->Late.Delay; const DelayLineI main_delay = State->Delay; const ALfloat mixX = State->MixX; @@ -1415,9 +1415,9 @@ static void LateReverb_Unfaded(ReverbState *State, ALsizei offset, const ALsizei VectorScatterRevDelayIn(&late_delay, offset, mixX, mixY, out, todo); } static void LateReverb_Faded(ReverbState *State, ALsizei offset, const ALsizei todo, - const ALfloat fade, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) + const ALfloat fade, ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) { - ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; + ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; const DelayLineI late_delay = State->Late.Delay; const DelayLineI main_delay = State->Delay; const ALfloat mixX = State->MixX; @@ -1466,10 +1466,10 @@ static void LateReverb_Faded(ReverbState *State, ALsizei offset, const ALsizei t VectorScatterRevDelayIn(&late_delay, offset, mixX, mixY, temps, todo); } -static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->TempSamples; - ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES] = State->MixSamples; + ALfloat (*RESTRICT afmt)[MAX_UPDATE_SAMPLES] = State->TempSamples; + ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES] = State->MixSamples; ALsizei fadeCount = State->FadeCount; ALsizei offset = State->Offset; ALsizei base, c; diff --git a/Alc/filters/filter.c b/Alc/filters/filter.c index 2b370f89..d05b0cae 100644 --- a/Alc/filters/filter.c +++ b/Alc/filters/filter.c @@ -8,7 +8,7 @@ #include "defs.h" extern inline void BiquadFilter_clear(BiquadFilter *filter); -extern inline void BiquadFilter_copyParams(BiquadFilter *restrict dst, const BiquadFilter *restrict src); +extern inline void BiquadFilter_copyParams(BiquadFilter *RESTRICT dst, const BiquadFilter *RESTRICT src); extern inline void BiquadFilter_passthru(BiquadFilter *filter, ALsizei numsamples); extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope); extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth); @@ -94,7 +94,7 @@ void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, } -void BiquadFilter_processC(BiquadFilter *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples) +void BiquadFilter_processC(BiquadFilter *filter, ALfloat *RESTRICT dst, const ALfloat *RESTRICT src, ALsizei numsamples) { const ALfloat a1 = filter->a1; const ALfloat a2 = filter->a2; diff --git a/Alc/filters/nfc.c b/Alc/filters/nfc.c index 8869d1d0..8d61bb37 100644 --- a/Alc/filters/nfc.c +++ b/Alc/filters/nfc.c @@ -222,7 +222,7 @@ void NfcFilterAdjust(NfcFilter *nfc, const float w0) } -void NfcFilterProcess1(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count) +void NfcFilterProcess1(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRICT src, const int count) { const float gain = nfc->first.gain; const float b1 = nfc->first.b1; @@ -243,7 +243,7 @@ void NfcFilterProcess1(NfcFilter *nfc, float *restrict dst, const float *restric nfc->first.z[0] = z1; } -void NfcFilterProcess2(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count) +void NfcFilterProcess2(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRICT src, const int count) { const float gain = nfc->second.gain; const float b1 = nfc->second.b1; @@ -269,7 +269,7 @@ void NfcFilterProcess2(NfcFilter *nfc, float *restrict dst, const float *restric nfc->second.z[1] = z2; } -void NfcFilterProcess3(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count) +void NfcFilterProcess3(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRICT src, const int count) { const float gain = nfc->third.gain; const float b1 = nfc->third.b1; diff --git a/Alc/filters/splitter.c b/Alc/filters/splitter.c index e99f4b95..6aed7493 100644 --- a/Alc/filters/splitter.c +++ b/Alc/filters/splitter.c @@ -27,7 +27,7 @@ void bandsplit_clear(BandSplitter *splitter) splitter->hp_z1 = 0.0f; } -void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout, +void bandsplit_process(BandSplitter *splitter, ALfloat *RESTRICT hpout, ALfloat *RESTRICT lpout, const ALfloat *input, ALsizei count) { ALfloat lp_coeff, hp_coeff, lp_y, hp_y, d; @@ -86,7 +86,7 @@ void splitterap_clear(SplitterAllpass *splitter) splitter->z1 = 0.0f; } -void splitterap_process(SplitterAllpass *splitter, ALfloat *restrict samples, ALsizei count) +void splitterap_process(SplitterAllpass *splitter, ALfloat *RESTRICT samples, ALsizei count) { ALfloat coeff, in, out; ALfloat z1; diff --git a/Alc/filters/splitter.h b/Alc/filters/splitter.h index a788bc3e..b2dc9b4a 100644 --- a/Alc/filters/splitter.h +++ b/Alc/filters/splitter.h @@ -14,7 +14,7 @@ typedef struct BandSplitter { void bandsplit_init(BandSplitter *splitter, ALfloat f0norm); void bandsplit_clear(BandSplitter *splitter); -void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout, +void bandsplit_process(BandSplitter *splitter, ALfloat *RESTRICT hpout, ALfloat *RESTRICT lpout, const ALfloat *input, ALsizei count); /* The all-pass portion of the band splitter. Applies the same phase shift @@ -27,7 +27,7 @@ typedef struct SplitterAllpass { void splitterap_init(SplitterAllpass *splitter, ALfloat f0norm); void splitterap_clear(SplitterAllpass *splitter); -void splitterap_process(SplitterAllpass *splitter, ALfloat *restrict samples, ALsizei count); +void splitterap_process(SplitterAllpass *splitter, ALfloat *RESTRICT samples, ALsizei count); typedef struct FrontStablizer { diff --git a/Alc/hrtf.c b/Alc/hrtf.c index ddbd3a28..ce602ee1 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -103,7 +103,7 @@ static ALsizei CalcAzIndex(ALsizei azcount, ALfloat az, ALfloat *mu) * and azimuth in radians. The coefficients are normalized. */ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, - ALfloat (*restrict coeffs)[2], ALsizei *delays) + ALfloat (*RESTRICT coeffs)[2], ALsizei *delays) { ALsizei evidx, azidx, idx[4]; ALsizei evoffset; @@ -183,7 +183,7 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, } for(c = 0;c < 4;c++) { - const ALfloat (*restrict srccoeffs)[2] = ASSUME_ALIGNED(Hrtf->coeffs+idx[c], 16); + const ALfloat (*RESTRICT srccoeffs)[2] = ASSUME_ALIGNED(Hrtf->coeffs+idx[c], 16); for(i = 0;i < Hrtf->irSize;i++) { coeffs[i][0] += srccoeffs[i][0] * blend[c]; @@ -193,7 +193,7 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, } -void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const struct AngularPoint *AmbiPoints, const ALfloat (*restrict AmbiMatrix)[MAX_AMBI_COEFFS], ALsizei AmbiCount, const ALfloat *restrict AmbiOrderHFGain) +void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const struct AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_COEFFS], ALsizei AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain) { /* Set this to 2 for dual-band HRTF processing. May require a higher quality * band-splitter, or better calculation of the new IR length to deal with the @@ -202,7 +202,7 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N #define NUM_BANDS 2 BandSplitter splitter; ALdouble (*tmpres)[HRIR_LENGTH][2]; - ALsizei *restrict idx; + ALsizei *RESTRICT idx; ALsizei min_delay = HRTF_HISTORY_LENGTH; ALsizei max_delay = 0; ALfloat temps[3][HRIR_LENGTH]; diff --git a/Alc/mastering.c b/Alc/mastering.c index 52ff5b23..dd4ed7e1 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -83,8 +83,8 @@ static ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALflo { const ALsizei mask = BUFFERSIZE - 1; const ALsizei length = Hold->Length; - ALfloat *restrict values = Hold->Values; - ALsizei *restrict expiries = Hold->Expiries; + ALfloat *RESTRICT values = Hold->Values; + ALsizei *RESTRICT expiries = Hold->Expiries; ALsizei lowerIndex = Hold->LowerIndex; ALsizei upperIndex = Hold->UpperIndex; @@ -122,7 +122,7 @@ static ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALflo static void ShiftSlidingHold(SlidingHold *Hold, const ALsizei n) { const ALsizei lowerIndex = Hold->LowerIndex; - ALsizei *restrict expiries = Hold->Expiries; + ALsizei *RESTRICT expiries = Hold->Expiries; ALsizei i = Hold->UpperIndex; if(lowerIndex < i) @@ -140,11 +140,11 @@ static void ShiftSlidingHold(SlidingHold *Hold, const ALsizei n) /* Multichannel compression is linked via the absolute maximum of all * channels. */ -static void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*restrict OutBuffer)[BUFFERSIZE]) +static void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]) { const ALsizei index = Comp->LookAhead; const ALsizei numChans = Comp->NumChans; - ALfloat *restrict sideChain = Comp->SideChain; + ALfloat *RESTRICT sideChain = Comp->SideChain; ALsizei c, i; ASSUME(SamplesToDo > 0); @@ -173,8 +173,8 @@ static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo) { const ALfloat a_crest = Comp->CrestCoeff; const ALsizei index = Comp->LookAhead; - const ALfloat *restrict sideChain = Comp->SideChain; - ALfloat *restrict crestFactor = Comp->CrestFactor; + const ALfloat *RESTRICT sideChain = Comp->SideChain; + ALfloat *RESTRICT crestFactor = Comp->CrestFactor; ALfloat y2_peak = Comp->LastPeakSq; ALfloat y2_rms = Comp->LastRmsSq; ALsizei i; @@ -202,7 +202,7 @@ static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo) static void PeakDetector(Compressor *Comp, const ALsizei SamplesToDo) { const ALsizei index = Comp->LookAhead; - ALfloat *restrict sideChain = Comp->SideChain; + ALfloat *RESTRICT sideChain = Comp->SideChain; ALsizei i; ASSUME(SamplesToDo > 0); @@ -223,7 +223,7 @@ static void PeakDetector(Compressor *Comp, const ALsizei SamplesToDo) static void PeakHoldDetector(Compressor *Comp, const ALsizei SamplesToDo) { const ALsizei index = Comp->LookAhead; - ALfloat *restrict sideChain = Comp->SideChain; + ALfloat *RESTRICT sideChain = Comp->SideChain; SlidingHold *hold = Comp->Hold; ALsizei i; @@ -260,8 +260,8 @@ static void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) const ALfloat release = Comp->Release; const ALfloat c_est = Comp->GainEstimate; const ALfloat a_adp = Comp->AdaptCoeff; - const ALfloat *restrict crestFactor = Comp->CrestFactor; - ALfloat *restrict sideChain = Comp->SideChain; + const ALfloat *RESTRICT crestFactor = Comp->CrestFactor; + ALfloat *RESTRICT sideChain = Comp->SideChain; ALfloat postGain = Comp->PostGain; ALfloat knee = Comp->Knee; ALfloat t_att = attack; @@ -353,13 +353,13 @@ static void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) * reaching the offending impulse. This is best used when operating as a * limiter. */ -static void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*restrict OutBuffer)[BUFFERSIZE]) +static void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]) { const ALsizei mask = BUFFERSIZE - 1; const ALsizei numChans = Comp->NumChans; const ALsizei indexIn = Comp->DelayIndex; const ALsizei indexOut = Comp->DelayIndex - Comp->LookAhead; - ALfloat (*restrict delay)[BUFFERSIZE] = Comp->Delay; + ALfloat (*RESTRICT delay)[BUFFERSIZE] = Comp->Delay; ALsizei c, i; ASSUME(SamplesToDo > 0); @@ -481,11 +481,11 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, return Comp; } -void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*restrict OutBuffer)[BUFFERSIZE]) +void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]) { const ALsizei numChans = Comp->NumChans; const ALfloat preGain = Comp->PreGain; - ALfloat *restrict sideChain; + ALfloat *RESTRICT sideChain; ALsizei c, i; ASSUME(SamplesToDo > 0); diff --git a/Alc/mastering.h b/Alc/mastering.h index b68b0de1..17f5e8be 100644 --- a/Alc/mastering.h +++ b/Alc/mastering.h @@ -42,7 +42,7 @@ struct Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRat const ALfloat AttackTime, const ALfloat ReleaseTime); void ApplyCompression(struct Compressor *Comp, const ALsizei SamplesToDo, - ALfloat (*restrict OutBuffer)[BUFFERSIZE]); + ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]); ALsizei GetCompressorLookAhead(const struct Compressor *Comp); diff --git a/Alc/mixer/defs.h b/Alc/mixer/defs.h index 8f6e3755..acb8a8c2 100644 --- a/Alc/mixer/defs.h +++ b/Alc/mixer/defs.h @@ -12,57 +12,57 @@ struct MixHrtfParams; struct HrtfState; /* C resamplers */ -const ALfloat *Resample_copy_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); -const ALfloat *Resample_point_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); -const ALfloat *Resample_lerp_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); -const ALfloat *Resample_cubic_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); -const ALfloat *Resample_bsinc_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_copy_C(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen); +const ALfloat *Resample_point_C(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen); +const ALfloat *Resample_lerp_C(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen); +const ALfloat *Resample_cubic_C(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen); +const ALfloat *Resample_bsinc_C(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen); /* C mixers */ -void MixHrtf_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, +void MixHrtf_C(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, ALsizei BufferSize); -void MixHrtfBlend_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, +void MixHrtfBlend_C(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, HrtfState *hrtfstate, ALsizei BufferSize); -void MixDirectHrtf_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, +void MixDirectHrtf_C(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], + const ALfloat (*RESTRICT Coeffs)[2], ALfloat (*RESTRICT Values)[2], ALsizei BufferSize); -void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], +void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, ALsizei BufferSize); void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, - const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, + const ALfloat (*RESTRICT data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize); /* SSE mixers */ -void MixHrtf_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, +void MixHrtf_SSE(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, ALsizei BufferSize); -void MixHrtfBlend_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, +void MixHrtfBlend_SSE(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, HrtfState *hrtfstate, ALsizei BufferSize); -void MixDirectHrtf_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, +void MixDirectHrtf_SSE(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], + const ALfloat (*RESTRICT Coeffs)[2], ALfloat (*RESTRICT Values)[2], ALsizei BufferSize); -void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], +void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, ALsizei BufferSize); void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, - const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, + const ALfloat (*RESTRICT data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize); /* SSE resamplers */ -inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *restrict frac_arr, ALsizei *restrict pos_arr, ALsizei size) +inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *RESTRICT frac_arr, ALsizei *RESTRICT pos_arr, ALsizei size) { ALsizei i; @@ -76,44 +76,44 @@ inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *restr } } -const ALfloat *Resample_lerp_SSE2(const InterpState *state, const ALfloat *restrict src, - ALsizei frac, ALint increment, ALfloat *restrict dst, +const ALfloat *Resample_lerp_SSE2(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei numsamples); -const ALfloat *Resample_lerp_SSE41(const InterpState *state, const ALfloat *restrict src, - ALsizei frac, ALint increment, ALfloat *restrict dst, +const ALfloat *Resample_lerp_SSE41(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei numsamples); -const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *restrict src, - ALsizei frac, ALint increment, ALfloat *restrict dst, +const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen); /* Neon mixers */ -void MixHrtf_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, +void MixHrtf_Neon(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, ALsizei BufferSize); -void MixHrtfBlend_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, +void MixHrtfBlend_Neon(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, HrtfState *hrtfstate, ALsizei BufferSize); -void MixDirectHrtf_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, +void MixDirectHrtf_Neon(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], + const ALfloat (*RESTRICT Coeffs)[2], ALfloat (*RESTRICT Values)[2], ALsizei BufferSize); -void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], +void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, ALsizei BufferSize); void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, - const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, + const ALfloat (*RESTRICT data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize); /* Neon resamplers */ -const ALfloat *Resample_lerp_Neon(const InterpState *state, const ALfloat *restrict src, - ALsizei frac, ALint increment, ALfloat *restrict dst, +const ALfloat *Resample_lerp_Neon(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei numsamples); -const ALfloat *Resample_bsinc_Neon(const InterpState *state, const ALfloat *restrict src, - ALsizei frac, ALint increment, ALfloat *restrict dst, +const ALfloat *Resample_bsinc_Neon(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen); #endif /* MIXER_DEFS_H */ diff --git a/Alc/mixer/hrtf_inc.c b/Alc/mixer/hrtf_inc.c index 3ef22f24..21840abd 100644 --- a/Alc/mixer/hrtf_inc.c +++ b/Alc/mixer/hrtf_inc.c @@ -9,13 +9,13 @@ #include "defs.h" -static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], const ALsizei irSize, - const ALfloat (*restrict Coeffs)[2], + const ALfloat (*RESTRICT Coeffs)[2], ALfloat left, ALfloat right); -void MixHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, +void MixHrtf(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, MixHrtfParams *hrtfparams, HrtfState *hrtfstate, ALsizei BufferSize) @@ -54,7 +54,7 @@ void MixHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, hrtfparams->Gain = gain + gainstep*stepcount; } -void MixHrtfBlend(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, +void MixHrtfBlend(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, HrtfState *hrtfstate, @@ -103,9 +103,9 @@ void MixHrtfBlend(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, newparams->Gain = newGain + newGainStep*stepcount; } -void MixDirectHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, +void MixDirectHrtf(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], + const ALfloat (*RESTRICT Coeffs)[2], ALfloat (*RESTRICT Values)[2], ALsizei BufferSize) { ALfloat insample; diff --git a/Alc/mixer/mixer_c.c b/Alc/mixer/mixer_c.c index 14d7c669..ea864dbc 100644 --- a/Alc/mixer/mixer_c.c +++ b/Alc/mixer/mixer_c.c @@ -9,13 +9,13 @@ #include "defs.h" -static inline ALfloat do_point(const InterpState* UNUSED(state), const ALfloat *restrict vals, ALsizei UNUSED(frac)) +static inline ALfloat do_point(const InterpState* UNUSED(state), const ALfloat *RESTRICT vals, ALsizei UNUSED(frac)) { return vals[0]; } -static inline ALfloat do_lerp(const InterpState* UNUSED(state), const ALfloat *restrict vals, ALsizei frac) +static inline ALfloat do_lerp(const InterpState* UNUSED(state), const ALfloat *RESTRICT vals, ALsizei frac) { return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); } -static inline ALfloat do_cubic(const InterpState* UNUSED(state), const ALfloat *restrict vals, ALsizei frac) +static inline ALfloat do_cubic(const InterpState* UNUSED(state), const ALfloat *RESTRICT vals, ALsizei frac) { return cubic(vals[0], vals[1], vals[2], vals[3], frac * (1.0f/FRACTIONONE)); } -static inline ALfloat do_bsinc(const InterpState *state, const ALfloat *restrict vals, ALsizei frac) +static inline ALfloat do_bsinc(const InterpState *state, const ALfloat *RESTRICT vals, ALsizei frac) { const ALfloat *fil, *scd, *phd, *spd; ALsizei j_f, pi; @@ -42,8 +42,8 @@ static inline ALfloat do_bsinc(const InterpState *state, const ALfloat *restrict } const ALfloat *Resample_copy_C(const InterpState* UNUSED(state), - const ALfloat *restrict src, ALsizei UNUSED(frac), ALint UNUSED(increment), - ALfloat *restrict dst, ALsizei numsamples) + const ALfloat *RESTRICT src, ALsizei UNUSED(frac), ALint UNUSED(increment), + ALfloat *RESTRICT dst, ALsizei numsamples) { #if defined(HAVE_SSE) || defined(HAVE_NEON) /* Avoid copying the source data if it's aligned like the destination. */ @@ -56,8 +56,8 @@ const ALfloat *Resample_copy_C(const InterpState* UNUSED(state), #define DECL_TEMPLATE(Tag, Sampler, O) \ const ALfloat *Resample_##Tag##_C(const InterpState *state, \ - const ALfloat *restrict src, ALsizei frac, ALint increment, \ - ALfloat *restrict dst, ALsizei numsamples) \ + const ALfloat *RESTRICT src, ALsizei frac, ALint increment, \ + ALfloat *RESTRICT dst, ALsizei numsamples) \ { \ const InterpState istate = *state; \ ALsizei i; \ @@ -84,9 +84,9 @@ DECL_TEMPLATE(bsinc, do_bsinc, istate.bsinc.l) #undef DECL_TEMPLATE -static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], const ALsizei IrSize, - const ALfloat (*restrict Coeffs)[2], + const ALfloat (*RESTRICT Coeffs)[2], ALfloat left, ALfloat right) { ALsizei c; @@ -104,7 +104,7 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], #include "hrtf_inc.c" -void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], +void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, ALsizei BufferSize) { @@ -150,7 +150,7 @@ void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[ * transform. And as the matrices are more or less static once set up, no * stepping is necessary. */ -void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) +void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*RESTRICT data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) { ALsizei c, i; diff --git a/Alc/mixer/mixer_neon.c b/Alc/mixer/mixer_neon.c index 9bf5521a..a035abc7 100644 --- a/Alc/mixer/mixer_neon.c +++ b/Alc/mixer/mixer_neon.c @@ -11,8 +11,8 @@ const ALfloat *Resample_lerp_Neon(const InterpState* UNUSED(state), - const ALfloat *restrict src, ALsizei frac, ALint increment, - ALfloat *restrict dst, ALsizei numsamples) + const ALfloat *RESTRICT src, ALsizei frac, ALint increment, + ALfloat *RESTRICT dst, ALsizei numsamples) { const int32x4_t increment4 = vdupq_n_s32(increment*4); const float32x4_t fracOne4 = vdupq_n_f32(1.0f/FRACTIONONE); @@ -67,8 +67,8 @@ const ALfloat *Resample_lerp_Neon(const InterpState* UNUSED(state), } const ALfloat *Resample_bsinc_Neon(const InterpState *state, - const ALfloat *restrict src, ALsizei frac, ALint increment, - ALfloat *restrict dst, ALsizei dstlen) + const ALfloat *RESTRICT src, ALsizei frac, ALint increment, + ALfloat *RESTRICT dst, ALsizei dstlen) { const ALfloat *const filter = state->bsinc.filter; const float32x4_t sf4 = vdupq_n_f32(state->bsinc.sf); @@ -127,9 +127,9 @@ const ALfloat *Resample_bsinc_Neon(const InterpState *state, } -static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], const ALsizei IrSize, - const ALfloat (*restrict Coeffs)[2], + const ALfloat (*RESTRICT Coeffs)[2], ALfloat left, ALfloat right) { ALsizei c; @@ -163,7 +163,7 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], #include "hrtf_inc.c" -void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], +void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, ALsizei BufferSize) { @@ -251,7 +251,7 @@ void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffe } } -void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) +void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*RESTRICT data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) { ALsizei c; diff --git a/Alc/mixer/mixer_sse.c b/Alc/mixer/mixer_sse.c index 725a5ebc..34055001 100644 --- a/Alc/mixer/mixer_sse.c +++ b/Alc/mixer/mixer_sse.c @@ -12,8 +12,8 @@ #include "defs.h" -const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *restrict src, - ALsizei frac, ALint increment, ALfloat *restrict dst, +const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) { const ALfloat *const filter = state->bsinc.filter; @@ -75,9 +75,9 @@ const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *restr } -static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], const ALsizei IrSize, - const ALfloat (*restrict Coeffs)[2], + const ALfloat (*RESTRICT Coeffs)[2], ALfloat left, ALfloat right) { const __m128 lrlr = _mm_setr_ps(left, right, left, right); @@ -135,7 +135,7 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], #include "hrtf_inc.c" -void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], +void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, ALsizei BufferSize) { @@ -218,7 +218,7 @@ void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer } } -void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) +void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*RESTRICT data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) { ALsizei c; diff --git a/Alc/mixer/mixer_sse2.c b/Alc/mixer/mixer_sse2.c index 9cbaeb0a..2432342f 100644 --- a/Alc/mixer/mixer_sse2.c +++ b/Alc/mixer/mixer_sse2.c @@ -28,8 +28,8 @@ const ALfloat *Resample_lerp_SSE2(const InterpState* UNUSED(state), - const ALfloat *restrict src, ALsizei frac, ALint increment, - ALfloat *restrict dst, ALsizei numsamples) + const ALfloat *RESTRICT src, ALsizei frac, ALint increment, + ALfloat *RESTRICT dst, ALsizei numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); diff --git a/Alc/mixer/mixer_sse41.c b/Alc/mixer/mixer_sse41.c index e92a3dd0..34b405f8 100644 --- a/Alc/mixer/mixer_sse41.c +++ b/Alc/mixer/mixer_sse41.c @@ -29,8 +29,8 @@ const ALfloat *Resample_lerp_SSE41(const InterpState* UNUSED(state), - const ALfloat *restrict src, ALsizei frac, ALint increment, - ALfloat *restrict dst, ALsizei numsamples) + const ALfloat *RESTRICT src, ALsizei frac, ALint increment, + ALfloat *RESTRICT dst, ALsizei numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); diff --git a/Alc/mixvoice.c b/Alc/mixvoice.c index d019b898..587f4a6b 100644 --- a/Alc/mixvoice.c +++ b/Alc/mixvoice.c @@ -45,7 +45,7 @@ static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!"); -extern inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *restrict frac_arr, ALsizei *restrict pos_arr, ALsizei size); +extern inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *RESTRICT frac_arr, ALsizei *RESTRICT pos_arr, ALsizei size); /* BSinc24 requires up to 23 extra samples before the current position, and 24 after. */ @@ -228,7 +228,7 @@ static inline ALfloat Sample_ALalaw(ALalaw val) { return aLawDecompressionTable[val] * (1.0f/32768.0f); } #define DECL_TEMPLATE(T) \ -static inline void Load_##T(ALfloat *restrict dst, const T *restrict src, \ +static inline void Load_##T(ALfloat *RESTRICT dst, const T *RESTRICT src, \ ALint srcstep, ALsizei samples) \ { \ ALsizei i; \ @@ -245,7 +245,7 @@ DECL_TEMPLATE(ALalaw) #undef DECL_TEMPLATE -static void LoadSamples(ALfloat *restrict dst, const ALvoid *restrict src, ALint srcstep, +static void LoadSamples(ALfloat *RESTRICT dst, const ALvoid *RESTRICT src, ALint srcstep, enum FmtType srctype, ALsizei samples) { #define HANDLE_FMT(ET, ST) case ET: Load_##ST(dst, src, srcstep, samples); break @@ -263,7 +263,7 @@ static void LoadSamples(ALfloat *restrict dst, const ALvoid *restrict src, ALint static const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, - ALfloat *restrict dst, const ALfloat *restrict src, + ALfloat *RESTRICT dst, const ALfloat *RESTRICT src, ALsizei numsamples, enum ActiveFilters type) { ALsizei i; diff --git a/Alc/panning.c b/Alc/panning.c index 79627e78..4328b30f 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -41,7 +41,7 @@ extern inline void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); extern inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); extern inline float ScaleAzimuthFront(float azimuth, float scale); -extern inline void ComputePanGains(const MixParams *dry, const ALfloat*restrict coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +extern inline void ComputePanGains(const MixParams *dry, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); static const ALsizei FuMa2ACN[MAX_AMBI_COEFFS] = { @@ -151,7 +151,7 @@ void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALf } -void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat*restrict coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { ALsizei i, j; @@ -166,7 +166,7 @@ void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, AL gains[i] = 0.0f; } -void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*restrict coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { ALsizei i; @@ -381,7 +381,7 @@ static const ChannelMap MonoCfg[1] = { }; static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, - const ALsizei *restrict chans_per_order) + const ALsizei *RESTRICT chans_per_order) { const char *devname = alstr_get_cstr(device->DeviceName); ALsizei i; @@ -845,8 +845,8 @@ static void InitHrtfPanning(ALCdevice *device) }; static const ALsizei IndexMap[6] = { 0, 1, 2, 3, 4, 8 }; static const ALsizei ChansPerOrder[MAX_AMBI_ORDER+1] = { 1, 3, 2, 0 }; - const ALfloat (*restrict AmbiMatrix)[MAX_AMBI_COEFFS] = AmbiMatrixFOA; - const ALfloat *restrict AmbiOrderHFGain = AmbiOrderHFGainFOA; + const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_COEFFS] = AmbiMatrixFOA; + const ALfloat *RESTRICT AmbiOrderHFGain = AmbiOrderHFGainFOA; ALsizei count = 4; ALsizei i; diff --git a/Alc/uhjfilter.c b/Alc/uhjfilter.c index 42b0bc40..6ee6fdb0 100644 --- a/Alc/uhjfilter.c +++ b/Alc/uhjfilter.c @@ -16,7 +16,7 @@ static const ALfloat Filter2CoeffSqr[4] = { 0.161758498368f, 0.733028932341f, 0.945349700329f, 0.990599156685f }; -static void allpass_process(AllPassState *state, ALfloat *restrict dst, const ALfloat *restrict src, const ALfloat aa, ALsizei todo) +static void allpass_process(AllPassState *state, ALfloat *RESTRICT dst, const ALfloat *RESTRICT src, const ALfloat aa, ALsizei todo) { ALfloat z1 = state->z[0]; ALfloat z2 = state->z[1]; @@ -55,7 +55,7 @@ static void allpass_process(AllPassState *state, ALfloat *restrict dst, const AL * know which is the intended result. */ -void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict RightOut, ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo) +void EncodeUhj2(Uhj2Encoder *enc, ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo) { ALfloat D[MAX_UPDATE_SAMPLES], S[MAX_UPDATE_SAMPLES]; ALfloat temp[2][MAX_UPDATE_SAMPLES]; diff --git a/Alc/uhjfilter.h b/Alc/uhjfilter.h index e773e0a7..9ea1fb44 100644 --- a/Alc/uhjfilter.h +++ b/Alc/uhjfilter.h @@ -44,6 +44,6 @@ typedef struct Uhj2Encoder { /* Encodes a 2-channel UHJ (stereo-compatible) signal from a B-Format input * signal. The input must use FuMa channel ordering and scaling. */ -void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict RightOut, ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo); +void EncodeUhj2(Uhj2Encoder *enc, ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo); #endif /* UHJFILTER_H */ diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 03ee97d6..97a3906d 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -30,7 +30,7 @@ struct ALeffectStateVtable { ALboolean (*const deviceUpdate)(ALeffectState *state, ALCdevice *device); void (*const update)(ALeffectState *state, const ALCcontext *context, const struct ALeffectslot *slot, const union ALeffectProps *props); - void (*const process)(ALeffectState *state, ALsizei samplesToDo, const ALfloat (*restrict samplesIn)[BUFFERSIZE], ALfloat (*restrict samplesOut)[BUFFERSIZE], ALsizei numChannels); + void (*const process)(ALeffectState *state, ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels); void (*const Delete)(void *ptr); }; @@ -44,7 +44,7 @@ typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE]; DECLARE_THUNK(T, ALeffectState, void, Destruct) \ DECLARE_THUNK1(T, ALeffectState, ALboolean, deviceUpdate, ALCdevice*) \ DECLARE_THUNK3(T, ALeffectState, void, update, const ALCcontext*, const ALeffectslot*, const ALeffectProps*) \ -DECLARE_THUNK4(T, ALeffectState, void, process, ALsizei, const ALfloatBUFFERSIZE*restrict, ALfloatBUFFERSIZE*restrict, ALsizei) \ +DECLARE_THUNK4(T, ALeffectState, void, process, ALsizei, const ALfloatBUFFERSIZE*RESTRICT, ALfloatBUFFERSIZE*RESTRICT, ALsizei) \ static void T##_ALeffectState_Delete(void *ptr) \ { return T##_Delete(STATIC_UPCAST(T, ALeffectState, (ALeffectState*)ptr)); } \ \ diff --git a/OpenAL32/Include/bs2b.h b/OpenAL32/Include/bs2b.h index e845d906..13cdf9a6 100644 --- a/OpenAL32/Include/bs2b.h +++ b/OpenAL32/Include/bs2b.h @@ -85,7 +85,7 @@ int bs2b_get_srate(struct bs2b *bs2b); /* Clear buffer */ void bs2b_clear(struct bs2b *bs2b); -void bs2b_cross_feed(struct bs2b *bs2b, float *restrict Left, float *restrict Right, int SamplesToDo); +void bs2b_cross_feed(struct bs2b *bs2b, float *RESTRICT Left, float *RESTRICT Right, int SamplesToDo); #ifdef __cplusplus } /* extern "C" */ diff --git a/utils/makehrtf.c b/utils/makehrtf.c index 0bd36849..eb174c8a 100644 --- a/utils/makehrtf.c +++ b/utils/makehrtf.c @@ -945,7 +945,7 @@ static inline uint dither_rng(uint *seed) // Performs a triangular probability density function dither. The input samples // should be normalized (-1 to +1). -static void TpdfDither(double *restrict out, const double *restrict in, const double scale, +static void TpdfDither(double *RESTRICT out, const double *RESTRICT in, const double scale, const int count, const int step, uint *seed) { static const double PRNG_SCALE = 1.0 / UINT_MAX; -- cgit v1.2.3 From ea3789d9851a46b603675f813a2e7a82ec4e04ed Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Oct 2018 11:35:43 -0700 Subject: Update version for AppVeyor --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 6d826eed..bc4d26c0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 1.19.0.{build} +version: 1.19.1.{build} environment: matrix: -- cgit v1.2.3 From 662e1c5cc2107d45895ac4f6d8c598c89016eaeb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Oct 2018 11:50:41 -0700 Subject: Fix some uses of RESTRICT --- Alc/ALu.c | 2 +- Alc/effects/modulator.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index efa78110..23996697 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -80,7 +80,7 @@ extern inline size_t clampz(size_t val, size_t min, size_t max); extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu); extern inline ALfloat cubic(ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat mu); -extern inline void aluVectorSet(aluVector *RESTRICT vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w); +extern inline void aluVectorSet(aluVector *vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w); extern inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row, ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3); diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index dd3d1981..87799dd7 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -35,7 +35,7 @@ typedef struct ALmodulatorState { DERIVE_FROM_TYPE(ALeffectState); - void (*GetSamples)(ALfloat*, ALsizei, const ALsizei, ALsizei); + void (*GetSamples)(ALfloat*RESTRICT, ALsizei, const ALsizei, ALsizei); ALsizei index; ALsizei step; -- cgit v1.2.3 From 5fea511ccec500f575898df33e9934dec075527c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Oct 2018 11:51:41 -0700 Subject: Fix some more headers for C++ --- common/align.h | 2 +- common/bool.h | 2 +- common/static_assert.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/align.h b/common/align.h index a5d8a20c..53a5806a 100644 --- a/common/align.h +++ b/common/align.h @@ -5,7 +5,7 @@ #include #endif -#ifndef alignas +#if !defined(alignas) && !defined(__cplusplus) #if defined(HAVE_C11_ALIGNAS) #define alignas _Alignas #else diff --git a/common/bool.h b/common/bool.h index dbb28e15..eb1d9174 100644 --- a/common/bool.h +++ b/common/bool.h @@ -5,7 +5,7 @@ #include #endif -#if !defined(__cplusplus) && !defined(bool) +#if !defined(bool) && !defined(__cplusplus) #ifdef HAVE_C99_BOOL #define bool _Bool #else diff --git a/common/static_assert.h b/common/static_assert.h index bf0ce065..3a554fb5 100644 --- a/common/static_assert.h +++ b/common/static_assert.h @@ -4,7 +4,7 @@ #include -#ifndef static_assert +#if !defined(static_assert) && !defined(__cplusplus) #ifdef HAVE_C11_STATIC_ASSERT #define static_assert _Static_assert #else -- cgit v1.2.3 From 3deb7c6ed5105a54c6cea01318099494ba1ee9b6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Oct 2018 20:50:57 -0700 Subject: Workaround C++ compatiility issues for atomic.h This isn't wholly correct since neither C11 or C++11 guarantee compatibility between atomic implementations. It's desired behavior and mostly works, see: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0943r1.html Alignment issues can be fixed with manual alignas() specifications, should the need arise. --- common/atomic.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/common/atomic.h b/common/atomic.h index 39daa1dc..d28298f2 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -17,6 +17,52 @@ #define CONST_CAST(T, V) ((T)(V)) #endif +#ifdef HAVE_C11_ATOMIC +#ifdef __cplusplus +/* C++11 doesn't support compatibility with C11 atomics. So instead, make C++11 + * atomic declarations global to emulate C11. There's no standard guarantee of + * ABI compatibility, but it's desired behavior that mostly works. See: + * + * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0943r1.html + * + * Any alignment issues arising from this can be fixed with explicit alignas() + * specifiers on affected variables. + * + * Only do this when C11 atomics are supported in C, since MSVC and pre-C11 + * compilers may use something else that is significantly different in C + * despite supporting C++11 atomics. + */ +#include + +#define _Atomic(T) std::atomic +using std::memory_order; +using std::memory_order_relaxed; +using std::memory_order_consume; +using std::memory_order_acquire; +using std::memory_order_release; +using std::memory_order_acq_rel; +using std::memory_order_seq_cst; + +using std::atomic_flag; + +using std::atomic_init; +using std::atomic_load_explicit; +using std::atomic_store_explicit; +using std::atomic_fetch_add_explicit; +using std::atomic_fetch_sub_explicit; +using std::atomic_exchange_explicit; +using std::atomic_compare_exchange_strong_explicit; +using std::atomic_compare_exchange_weak_explicit; +using std::atomic_flag_test_and_set_explicit; +using std::atomic_flag_clear_explicit; +using std::atomic_thread_fence; + +#else + +#include +#endif /* __cplusplus */ +#endif /* HAVE_C11_ATOMIC */ + #ifdef __cplusplus extern "C" { #endif @@ -24,8 +70,6 @@ extern "C" { /* Atomics using C11 */ #ifdef HAVE_C11_ATOMIC -#include - #define almemory_order memory_order #define almemory_order_relaxed memory_order_relaxed #define almemory_order_consume memory_order_consume @@ -34,7 +78,7 @@ extern "C" { #define almemory_order_acq_rel memory_order_acq_rel #define almemory_order_seq_cst memory_order_seq_cst -#define ATOMIC(T) T _Atomic +#define ATOMIC(T) _Atomic(T) #define ATOMIC_FLAG atomic_flag #define ATOMIC_INIT atomic_init @@ -415,9 +459,9 @@ inline void InitRef(RefCount *ptr, uint value) inline uint ReadRef(RefCount *ptr) { return ATOMIC_LOAD(ptr, almemory_order_acquire); } inline uint IncrementRef(RefCount *ptr) -{ return ATOMIC_ADD(ptr, 1, almemory_order_acq_rel)+1; } +{ return ATOMIC_ADD(ptr, 1u, almemory_order_acq_rel)+1; } inline uint DecrementRef(RefCount *ptr) -{ return ATOMIC_SUB(ptr, 1, almemory_order_acq_rel)-1; } +{ return ATOMIC_SUB(ptr, 1u, almemory_order_acq_rel)-1; } /* WARNING: A livelock is theoretically possible if another thread keeps -- cgit v1.2.3 From 71303b73a440a755d2dbd39fa9edfe3ed9ea355d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Oct 2018 20:55:45 -0700 Subject: Add a cmake option to static-link libstdc++ --- CMakeLists.txt | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6247af93..524b4e5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ INCLUDE(CheckSymbolExists) INCLUDE(CheckCCompilerFlag) INCLUDE(CheckCXXCompilerFlag) INCLUDE(CheckCSourceCompiles) +INCLUDE(CheckCXXSourceCompiles) INCLUDE(CheckTypeSize) include(CheckStructHasMember) include(CheckFileOffsetBits) @@ -163,7 +164,7 @@ IF(HAVE___RESTRICT) SET(RESTRICT_DECL "__restrict") ENDIF() -# MSVC may need workarounds for C99 restrict and inline +# MSVC may need workarounds for C99 inline IF(MSVC) # TODO: Once we truly require C99, this inline check should go away. CHECK_C_SOURCE_COMPILES("inline void foo(void) { } @@ -350,6 +351,25 @@ int main() set(CMAKE_REQUIRED_LIBRARIES ${OLD_REQUIRED_LIBRARIES}) unset(OLD_REQUIRED_LIBRARIES) endif() + + option(ALSOFT_STATIC_STDCXX "Static link libstdc++ with -static-libstdc++" OFF) + if(ALSOFT_STATIC_STDCXX) + set(OLD_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} -static-libstdc++) + check_cxx_source_compiles( +"#include +int main() +{ + return 0; +}" + HAVE_STATIC_LIBSTDCXX_SWITCH + ) + if(HAVE_STATIC_LIBSTDCXX_SWITCH) + SET(LINKER_FLAGS ${LINKER_FLAGS} -static-libstdc++) + endif() + set(CMAKE_REQUIRED_LIBRARIES ${OLD_REQUIRED_LIBRARIES}) + unset(OLD_REQUIRED_LIBRARIES) + endif() ENDIF() # Set visibility/export options if available -- cgit v1.2.3 From f17b930638e075e33677bfdd7c4dd68078b8ac82 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 Oct 2018 06:45:44 -0700 Subject: Add extern "C" for router.h --- router/router.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/router/router.h b/router/router.h index 32a91dcb..36c825d4 100644 --- a/router/router.h +++ b/router/router.h @@ -15,6 +15,10 @@ #include "threads.h" +#ifdef __cplusplus +extern "C" { +#endif + #ifndef UNUSED #if defined(__cplusplus) #define UNUSED(x) @@ -194,4 +198,8 @@ extern FILE *LogFile; } \ } while(0) +#ifdef __cplusplus +} // extern "C" +#endif + #endif /* ROUTER_ROUTER_H */ -- cgit v1.2.3 From a0d03e50e849d6f295d618cc4bde115af596e68a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 Oct 2018 07:06:03 -0700 Subject: Convert the router to C++ --- CMakeLists.txt | 2 +- router/al.c | 132 -------- router/al.cpp | 132 ++++++++ router/alc.c | 956 ----------------------------------------------------- router/alc.cpp | 959 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ router/router.c | 537 ------------------------------ router/router.cpp | 541 ++++++++++++++++++++++++++++++ 7 files changed, 1633 insertions(+), 1626 deletions(-) delete mode 100644 router/al.c create mode 100644 router/al.cpp delete mode 100644 router/alc.c create mode 100644 router/alc.cpp delete mode 100644 router/router.c create mode 100644 router/router.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 524b4e5e..d483aa0a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1433,7 +1433,7 @@ ELSE() ENDIF() IF(WIN32 AND ALSOFT_BUILD_ROUTER) - ADD_LIBRARY(OpenAL SHARED router/router.c router/router.h router/alc.c router/al.c) + ADD_LIBRARY(OpenAL SHARED router/router.cpp router/router.h router/alc.cpp router/al.cpp) TARGET_COMPILE_DEFINITIONS(OpenAL PRIVATE AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES ${CPP_DEFS}) TARGET_COMPILE_OPTIONS(OpenAL PRIVATE ${C_FLAGS} $<$:${CXX_FLAGS}>) diff --git a/router/al.c b/router/al.c deleted file mode 100644 index 8dd888d9..00000000 --- a/router/al.c +++ /dev/null @@ -1,132 +0,0 @@ - -#include "config.h" - -#include - -#include "AL/al.h" -#include "router.h" - - -atomic_DriverIfacePtr CurrentCtxDriver = ATOMIC_INIT_STATIC(NULL); - -#define DECL_THUNK1(R,n,T1) AL_API R AL_APIENTRY n(T1 a) \ -{ \ - DriverIface *iface = altss_get(ThreadCtxDriver); \ - if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ - return iface->n(a); \ -} -#define DECL_THUNK2(R,n,T1,T2) AL_API R AL_APIENTRY n(T1 a, T2 b) \ -{ \ - DriverIface *iface = altss_get(ThreadCtxDriver); \ - if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ - return iface->n(a, b); \ -} -#define DECL_THUNK3(R,n,T1,T2,T3) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c) \ -{ \ - DriverIface *iface = altss_get(ThreadCtxDriver); \ - if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ - return iface->n(a, b, c); \ -} -#define DECL_THUNK4(R,n,T1,T2,T3,T4) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c, T4 d) \ -{ \ - DriverIface *iface = altss_get(ThreadCtxDriver); \ - if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ - return iface->n(a, b, c, d); \ -} -#define DECL_THUNK5(R,n,T1,T2,T3,T4,T5) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c, T4 d, T5 e) \ -{ \ - DriverIface *iface = altss_get(ThreadCtxDriver); \ - if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ - return iface->n(a, b, c, d, e); \ -} - - -/* Ugly hack for some apps calling alGetError without a current context, and - * expecting it to be AL_NO_ERROR. - */ -AL_API ALenum AL_APIENTRY alGetError(void) -{ - DriverIface *iface = altss_get(ThreadCtxDriver); - if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire); - return iface ? iface->alGetError() : AL_NO_ERROR; -} - - -DECL_THUNK1(void, alDopplerFactor, ALfloat) -DECL_THUNK1(void, alDopplerVelocity, ALfloat) -DECL_THUNK1(void, alSpeedOfSound, ALfloat) -DECL_THUNK1(void, alDistanceModel, ALenum) - -DECL_THUNK1(void, alEnable, ALenum) -DECL_THUNK1(void, alDisable, ALenum) -DECL_THUNK1(ALboolean, alIsEnabled, ALenum) - -DECL_THUNK1(const ALchar*, alGetString, ALenum) -DECL_THUNK2(void, alGetBooleanv, ALenum, ALboolean*) -DECL_THUNK2(void, alGetIntegerv, ALenum, ALint*) -DECL_THUNK2(void, alGetFloatv, ALenum, ALfloat*) -DECL_THUNK2(void, alGetDoublev, ALenum, ALdouble*) -DECL_THUNK1(ALboolean, alGetBoolean, ALenum) -DECL_THUNK1(ALint, alGetInteger, ALenum) -DECL_THUNK1(ALfloat, alGetFloat, ALenum) -DECL_THUNK1(ALdouble, alGetDouble, ALenum) - -DECL_THUNK1(ALboolean, alIsExtensionPresent, const ALchar*) -DECL_THUNK1(void*, alGetProcAddress, const ALchar*) -DECL_THUNK1(ALenum, alGetEnumValue, const ALchar*) - -DECL_THUNK2(void, alListenerf, ALenum, ALfloat) -DECL_THUNK4(void, alListener3f, ALenum, ALfloat, ALfloat, ALfloat) -DECL_THUNK2(void, alListenerfv, ALenum, const ALfloat*) -DECL_THUNK2(void, alListeneri, ALenum, ALint) -DECL_THUNK4(void, alListener3i, ALenum, ALint, ALint, ALint) -DECL_THUNK2(void, alListeneriv, ALenum, const ALint*) -DECL_THUNK2(void, alGetListenerf, ALenum, ALfloat*) -DECL_THUNK4(void, alGetListener3f, ALenum, ALfloat*, ALfloat*, ALfloat*) -DECL_THUNK2(void, alGetListenerfv, ALenum, ALfloat*) -DECL_THUNK2(void, alGetListeneri, ALenum, ALint*) -DECL_THUNK4(void, alGetListener3i, ALenum, ALint*, ALint*, ALint*) -DECL_THUNK2(void, alGetListeneriv, ALenum, ALint*) - -DECL_THUNK2(void, alGenSources, ALsizei, ALuint*) -DECL_THUNK2(void, alDeleteSources, ALsizei, const ALuint*) -DECL_THUNK1(ALboolean, alIsSource, ALuint) -DECL_THUNK3(void, alSourcef, ALuint, ALenum, ALfloat) -DECL_THUNK5(void, alSource3f, ALuint, ALenum, ALfloat, ALfloat, ALfloat) -DECL_THUNK3(void, alSourcefv, ALuint, ALenum, const ALfloat*) -DECL_THUNK3(void, alSourcei, ALuint, ALenum, ALint) -DECL_THUNK5(void, alSource3i, ALuint, ALenum, ALint, ALint, ALint) -DECL_THUNK3(void, alSourceiv, ALuint, ALenum, const ALint*) -DECL_THUNK3(void, alGetSourcef, ALuint, ALenum, ALfloat*) -DECL_THUNK5(void, alGetSource3f, ALuint, ALenum, ALfloat*, ALfloat*, ALfloat*) -DECL_THUNK3(void, alGetSourcefv, ALuint, ALenum, ALfloat*) -DECL_THUNK3(void, alGetSourcei, ALuint, ALenum, ALint*) -DECL_THUNK5(void, alGetSource3i, ALuint, ALenum, ALint*, ALint*, ALint*) -DECL_THUNK3(void, alGetSourceiv, ALuint, ALenum, ALint*) -DECL_THUNK2(void, alSourcePlayv, ALsizei, const ALuint*) -DECL_THUNK2(void, alSourceStopv, ALsizei, const ALuint*) -DECL_THUNK2(void, alSourceRewindv, ALsizei, const ALuint*) -DECL_THUNK2(void, alSourcePausev, ALsizei, const ALuint*) -DECL_THUNK1(void, alSourcePlay, ALuint) -DECL_THUNK1(void, alSourceStop, ALuint) -DECL_THUNK1(void, alSourceRewind, ALuint) -DECL_THUNK1(void, alSourcePause, ALuint) -DECL_THUNK3(void, alSourceQueueBuffers, ALuint, ALsizei, const ALuint*) -DECL_THUNK3(void, alSourceUnqueueBuffers, ALuint, ALsizei, ALuint*) - -DECL_THUNK2(void, alGenBuffers, ALsizei, ALuint*) -DECL_THUNK2(void, alDeleteBuffers, ALsizei, const ALuint*) -DECL_THUNK1(ALboolean, alIsBuffer, ALuint) -DECL_THUNK3(void, alBufferf, ALuint, ALenum, ALfloat) -DECL_THUNK5(void, alBuffer3f, ALuint, ALenum, ALfloat, ALfloat, ALfloat) -DECL_THUNK3(void, alBufferfv, ALuint, ALenum, const ALfloat*) -DECL_THUNK3(void, alBufferi, ALuint, ALenum, ALint) -DECL_THUNK5(void, alBuffer3i, ALuint, ALenum, ALint, ALint, ALint) -DECL_THUNK3(void, alBufferiv, ALuint, ALenum, const ALint*) -DECL_THUNK3(void, alGetBufferf, ALuint, ALenum, ALfloat*) -DECL_THUNK5(void, alGetBuffer3f, ALuint, ALenum, ALfloat*, ALfloat*, ALfloat*) -DECL_THUNK3(void, alGetBufferfv, ALuint, ALenum, ALfloat*) -DECL_THUNK3(void, alGetBufferi, ALuint, ALenum, ALint*) -DECL_THUNK5(void, alGetBuffer3i, ALuint, ALenum, ALint*, ALint*, ALint*) -DECL_THUNK3(void, alGetBufferiv, ALuint, ALenum, ALint*) -DECL_THUNK5(void, alBufferData, ALuint, ALenum, const ALvoid*, ALsizei, ALsizei) diff --git a/router/al.cpp b/router/al.cpp new file mode 100644 index 00000000..1b4f413f --- /dev/null +++ b/router/al.cpp @@ -0,0 +1,132 @@ + +#include "config.h" + +#include + +#include "AL/al.h" +#include "router.h" + + +atomic_DriverIfacePtr CurrentCtxDriver = ATOMIC_INIT_STATIC(NULL); + +#define DECL_THUNK1(R,n,T1) AL_API R AL_APIENTRY n(T1 a) \ +{ \ + DriverIface *iface = reinterpret_cast(altss_get(ThreadCtxDriver));\ + if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ + return iface->n(a); \ +} +#define DECL_THUNK2(R,n,T1,T2) AL_API R AL_APIENTRY n(T1 a, T2 b) \ +{ \ + DriverIface *iface = reinterpret_cast(altss_get(ThreadCtxDriver));\ + if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ + return iface->n(a, b); \ +} +#define DECL_THUNK3(R,n,T1,T2,T3) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c) \ +{ \ + DriverIface *iface = reinterpret_cast(altss_get(ThreadCtxDriver));\ + if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ + return iface->n(a, b, c); \ +} +#define DECL_THUNK4(R,n,T1,T2,T3,T4) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c, T4 d) \ +{ \ + DriverIface *iface = reinterpret_cast(altss_get(ThreadCtxDriver));\ + if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ + return iface->n(a, b, c, d); \ +} +#define DECL_THUNK5(R,n,T1,T2,T3,T4,T5) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c, T4 d, T5 e) \ +{ \ + DriverIface *iface = reinterpret_cast(altss_get(ThreadCtxDriver));\ + if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ + return iface->n(a, b, c, d, e); \ +} + + +/* Ugly hack for some apps calling alGetError without a current context, and + * expecting it to be AL_NO_ERROR. + */ +AL_API ALenum AL_APIENTRY alGetError(void) +{ + DriverIface *iface = reinterpret_cast(altss_get(ThreadCtxDriver)); + if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire); + return iface ? iface->alGetError() : AL_NO_ERROR; +} + + +DECL_THUNK1(void, alDopplerFactor, ALfloat) +DECL_THUNK1(void, alDopplerVelocity, ALfloat) +DECL_THUNK1(void, alSpeedOfSound, ALfloat) +DECL_THUNK1(void, alDistanceModel, ALenum) + +DECL_THUNK1(void, alEnable, ALenum) +DECL_THUNK1(void, alDisable, ALenum) +DECL_THUNK1(ALboolean, alIsEnabled, ALenum) + +DECL_THUNK1(const ALchar*, alGetString, ALenum) +DECL_THUNK2(void, alGetBooleanv, ALenum, ALboolean*) +DECL_THUNK2(void, alGetIntegerv, ALenum, ALint*) +DECL_THUNK2(void, alGetFloatv, ALenum, ALfloat*) +DECL_THUNK2(void, alGetDoublev, ALenum, ALdouble*) +DECL_THUNK1(ALboolean, alGetBoolean, ALenum) +DECL_THUNK1(ALint, alGetInteger, ALenum) +DECL_THUNK1(ALfloat, alGetFloat, ALenum) +DECL_THUNK1(ALdouble, alGetDouble, ALenum) + +DECL_THUNK1(ALboolean, alIsExtensionPresent, const ALchar*) +DECL_THUNK1(void*, alGetProcAddress, const ALchar*) +DECL_THUNK1(ALenum, alGetEnumValue, const ALchar*) + +DECL_THUNK2(void, alListenerf, ALenum, ALfloat) +DECL_THUNK4(void, alListener3f, ALenum, ALfloat, ALfloat, ALfloat) +DECL_THUNK2(void, alListenerfv, ALenum, const ALfloat*) +DECL_THUNK2(void, alListeneri, ALenum, ALint) +DECL_THUNK4(void, alListener3i, ALenum, ALint, ALint, ALint) +DECL_THUNK2(void, alListeneriv, ALenum, const ALint*) +DECL_THUNK2(void, alGetListenerf, ALenum, ALfloat*) +DECL_THUNK4(void, alGetListener3f, ALenum, ALfloat*, ALfloat*, ALfloat*) +DECL_THUNK2(void, alGetListenerfv, ALenum, ALfloat*) +DECL_THUNK2(void, alGetListeneri, ALenum, ALint*) +DECL_THUNK4(void, alGetListener3i, ALenum, ALint*, ALint*, ALint*) +DECL_THUNK2(void, alGetListeneriv, ALenum, ALint*) + +DECL_THUNK2(void, alGenSources, ALsizei, ALuint*) +DECL_THUNK2(void, alDeleteSources, ALsizei, const ALuint*) +DECL_THUNK1(ALboolean, alIsSource, ALuint) +DECL_THUNK3(void, alSourcef, ALuint, ALenum, ALfloat) +DECL_THUNK5(void, alSource3f, ALuint, ALenum, ALfloat, ALfloat, ALfloat) +DECL_THUNK3(void, alSourcefv, ALuint, ALenum, const ALfloat*) +DECL_THUNK3(void, alSourcei, ALuint, ALenum, ALint) +DECL_THUNK5(void, alSource3i, ALuint, ALenum, ALint, ALint, ALint) +DECL_THUNK3(void, alSourceiv, ALuint, ALenum, const ALint*) +DECL_THUNK3(void, alGetSourcef, ALuint, ALenum, ALfloat*) +DECL_THUNK5(void, alGetSource3f, ALuint, ALenum, ALfloat*, ALfloat*, ALfloat*) +DECL_THUNK3(void, alGetSourcefv, ALuint, ALenum, ALfloat*) +DECL_THUNK3(void, alGetSourcei, ALuint, ALenum, ALint*) +DECL_THUNK5(void, alGetSource3i, ALuint, ALenum, ALint*, ALint*, ALint*) +DECL_THUNK3(void, alGetSourceiv, ALuint, ALenum, ALint*) +DECL_THUNK2(void, alSourcePlayv, ALsizei, const ALuint*) +DECL_THUNK2(void, alSourceStopv, ALsizei, const ALuint*) +DECL_THUNK2(void, alSourceRewindv, ALsizei, const ALuint*) +DECL_THUNK2(void, alSourcePausev, ALsizei, const ALuint*) +DECL_THUNK1(void, alSourcePlay, ALuint) +DECL_THUNK1(void, alSourceStop, ALuint) +DECL_THUNK1(void, alSourceRewind, ALuint) +DECL_THUNK1(void, alSourcePause, ALuint) +DECL_THUNK3(void, alSourceQueueBuffers, ALuint, ALsizei, const ALuint*) +DECL_THUNK3(void, alSourceUnqueueBuffers, ALuint, ALsizei, ALuint*) + +DECL_THUNK2(void, alGenBuffers, ALsizei, ALuint*) +DECL_THUNK2(void, alDeleteBuffers, ALsizei, const ALuint*) +DECL_THUNK1(ALboolean, alIsBuffer, ALuint) +DECL_THUNK3(void, alBufferf, ALuint, ALenum, ALfloat) +DECL_THUNK5(void, alBuffer3f, ALuint, ALenum, ALfloat, ALfloat, ALfloat) +DECL_THUNK3(void, alBufferfv, ALuint, ALenum, const ALfloat*) +DECL_THUNK3(void, alBufferi, ALuint, ALenum, ALint) +DECL_THUNK5(void, alBuffer3i, ALuint, ALenum, ALint, ALint, ALint) +DECL_THUNK3(void, alBufferiv, ALuint, ALenum, const ALint*) +DECL_THUNK3(void, alGetBufferf, ALuint, ALenum, ALfloat*) +DECL_THUNK5(void, alGetBuffer3f, ALuint, ALenum, ALfloat*, ALfloat*, ALfloat*) +DECL_THUNK3(void, alGetBufferfv, ALuint, ALenum, ALfloat*) +DECL_THUNK3(void, alGetBufferi, ALuint, ALenum, ALint*) +DECL_THUNK5(void, alGetBuffer3i, ALuint, ALenum, ALint*, ALint*, ALint*) +DECL_THUNK3(void, alGetBufferiv, ALuint, ALenum, ALint*) +DECL_THUNK5(void, alBufferData, ALuint, ALenum, const ALvoid*, ALsizei, ALsizei) diff --git a/router/alc.c b/router/alc.c deleted file mode 100644 index 946c7d4c..00000000 --- a/router/alc.c +++ /dev/null @@ -1,956 +0,0 @@ - -#include "config.h" - -#include -#include -#include -#include - -#include "AL/alc.h" -#include "router.h" -#include "almalloc.h" - - -#define COUNTOF(x) (sizeof(x)/sizeof(x[0])) - -#define DECL(x) { #x, (ALCvoid*)(x) } -static const struct { - const ALCchar *funcName; - ALCvoid *address; -} alcFunctions[] = { - DECL(alcCreateContext), - DECL(alcMakeContextCurrent), - DECL(alcProcessContext), - DECL(alcSuspendContext), - DECL(alcDestroyContext), - DECL(alcGetCurrentContext), - DECL(alcGetContextsDevice), - DECL(alcOpenDevice), - DECL(alcCloseDevice), - DECL(alcGetError), - DECL(alcIsExtensionPresent), - DECL(alcGetProcAddress), - DECL(alcGetEnumValue), - DECL(alcGetString), - DECL(alcGetIntegerv), - DECL(alcCaptureOpenDevice), - DECL(alcCaptureCloseDevice), - DECL(alcCaptureStart), - DECL(alcCaptureStop), - DECL(alcCaptureSamples), - - DECL(alcSetThreadContext), - DECL(alcGetThreadContext), - - DECL(alEnable), - DECL(alDisable), - DECL(alIsEnabled), - DECL(alGetString), - DECL(alGetBooleanv), - DECL(alGetIntegerv), - DECL(alGetFloatv), - DECL(alGetDoublev), - DECL(alGetBoolean), - DECL(alGetInteger), - DECL(alGetFloat), - DECL(alGetDouble), - DECL(alGetError), - DECL(alIsExtensionPresent), - DECL(alGetProcAddress), - DECL(alGetEnumValue), - DECL(alListenerf), - DECL(alListener3f), - DECL(alListenerfv), - DECL(alListeneri), - DECL(alListener3i), - DECL(alListeneriv), - DECL(alGetListenerf), - DECL(alGetListener3f), - DECL(alGetListenerfv), - DECL(alGetListeneri), - DECL(alGetListener3i), - DECL(alGetListeneriv), - DECL(alGenSources), - DECL(alDeleteSources), - DECL(alIsSource), - DECL(alSourcef), - DECL(alSource3f), - DECL(alSourcefv), - DECL(alSourcei), - DECL(alSource3i), - DECL(alSourceiv), - DECL(alGetSourcef), - DECL(alGetSource3f), - DECL(alGetSourcefv), - DECL(alGetSourcei), - DECL(alGetSource3i), - DECL(alGetSourceiv), - DECL(alSourcePlayv), - DECL(alSourceStopv), - DECL(alSourceRewindv), - DECL(alSourcePausev), - DECL(alSourcePlay), - DECL(alSourceStop), - DECL(alSourceRewind), - DECL(alSourcePause), - DECL(alSourceQueueBuffers), - DECL(alSourceUnqueueBuffers), - DECL(alGenBuffers), - DECL(alDeleteBuffers), - DECL(alIsBuffer), - DECL(alBufferData), - DECL(alBufferf), - DECL(alBuffer3f), - DECL(alBufferfv), - DECL(alBufferi), - DECL(alBuffer3i), - DECL(alBufferiv), - DECL(alGetBufferf), - DECL(alGetBuffer3f), - DECL(alGetBufferfv), - DECL(alGetBufferi), - DECL(alGetBuffer3i), - DECL(alGetBufferiv), - DECL(alDopplerFactor), - DECL(alDopplerVelocity), - DECL(alSpeedOfSound), - DECL(alDistanceModel), -}; -#undef DECL - -#define DECL(x) { #x, (x) } -static const struct { - const ALCchar *enumName; - ALCenum value; -} alcEnumerations[] = { - DECL(ALC_INVALID), - DECL(ALC_FALSE), - DECL(ALC_TRUE), - - DECL(ALC_MAJOR_VERSION), - DECL(ALC_MINOR_VERSION), - DECL(ALC_ATTRIBUTES_SIZE), - DECL(ALC_ALL_ATTRIBUTES), - DECL(ALC_DEFAULT_DEVICE_SPECIFIER), - DECL(ALC_DEVICE_SPECIFIER), - DECL(ALC_ALL_DEVICES_SPECIFIER), - DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER), - DECL(ALC_EXTENSIONS), - DECL(ALC_FREQUENCY), - DECL(ALC_REFRESH), - DECL(ALC_SYNC), - DECL(ALC_MONO_SOURCES), - DECL(ALC_STEREO_SOURCES), - DECL(ALC_CAPTURE_DEVICE_SPECIFIER), - DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER), - DECL(ALC_CAPTURE_SAMPLES), - - DECL(ALC_NO_ERROR), - DECL(ALC_INVALID_DEVICE), - DECL(ALC_INVALID_CONTEXT), - DECL(ALC_INVALID_ENUM), - DECL(ALC_INVALID_VALUE), - DECL(ALC_OUT_OF_MEMORY), - - DECL(AL_INVALID), - DECL(AL_NONE), - DECL(AL_FALSE), - DECL(AL_TRUE), - - DECL(AL_SOURCE_RELATIVE), - DECL(AL_CONE_INNER_ANGLE), - DECL(AL_CONE_OUTER_ANGLE), - DECL(AL_PITCH), - DECL(AL_POSITION), - DECL(AL_DIRECTION), - DECL(AL_VELOCITY), - DECL(AL_LOOPING), - DECL(AL_BUFFER), - DECL(AL_GAIN), - DECL(AL_MIN_GAIN), - DECL(AL_MAX_GAIN), - DECL(AL_ORIENTATION), - DECL(AL_REFERENCE_DISTANCE), - DECL(AL_ROLLOFF_FACTOR), - DECL(AL_CONE_OUTER_GAIN), - DECL(AL_MAX_DISTANCE), - DECL(AL_SEC_OFFSET), - DECL(AL_SAMPLE_OFFSET), - DECL(AL_BYTE_OFFSET), - DECL(AL_SOURCE_TYPE), - DECL(AL_STATIC), - DECL(AL_STREAMING), - DECL(AL_UNDETERMINED), - - DECL(AL_SOURCE_STATE), - DECL(AL_INITIAL), - DECL(AL_PLAYING), - DECL(AL_PAUSED), - DECL(AL_STOPPED), - - DECL(AL_BUFFERS_QUEUED), - DECL(AL_BUFFERS_PROCESSED), - - DECL(AL_FORMAT_MONO8), - DECL(AL_FORMAT_MONO16), - DECL(AL_FORMAT_STEREO8), - DECL(AL_FORMAT_STEREO16), - - DECL(AL_FREQUENCY), - DECL(AL_BITS), - DECL(AL_CHANNELS), - DECL(AL_SIZE), - - DECL(AL_UNUSED), - DECL(AL_PENDING), - DECL(AL_PROCESSED), - - DECL(AL_NO_ERROR), - DECL(AL_INVALID_NAME), - DECL(AL_INVALID_ENUM), - DECL(AL_INVALID_VALUE), - DECL(AL_INVALID_OPERATION), - DECL(AL_OUT_OF_MEMORY), - - DECL(AL_VENDOR), - DECL(AL_VERSION), - DECL(AL_RENDERER), - DECL(AL_EXTENSIONS), - - DECL(AL_DOPPLER_FACTOR), - DECL(AL_DOPPLER_VELOCITY), - DECL(AL_DISTANCE_MODEL), - DECL(AL_SPEED_OF_SOUND), - - DECL(AL_INVERSE_DISTANCE), - DECL(AL_INVERSE_DISTANCE_CLAMPED), - DECL(AL_LINEAR_DISTANCE), - DECL(AL_LINEAR_DISTANCE_CLAMPED), - DECL(AL_EXPONENT_DISTANCE), - DECL(AL_EXPONENT_DISTANCE_CLAMPED), -}; -#undef DECL - -static const ALCchar alcNoError[] = "No Error"; -static const ALCchar alcErrInvalidDevice[] = "Invalid Device"; -static const ALCchar alcErrInvalidContext[] = "Invalid Context"; -static const ALCchar alcErrInvalidEnum[] = "Invalid Enum"; -static const ALCchar alcErrInvalidValue[] = "Invalid Value"; -static const ALCchar alcErrOutOfMemory[] = "Out of Memory"; -static const ALCchar alcExtensionList[] = - "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE " - "ALC_EXT_thread_local_context"; - -static const ALCint alcMajorVersion = 1; -static const ALCint alcMinorVersion = 1; - - -static almtx_t EnumerationLock; -static almtx_t ContextSwitchLock; - -static ATOMIC(ALCenum) LastError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); -static PtrIntMap DeviceIfaceMap = PTRINTMAP_STATIC_INITIALIZE; -static PtrIntMap ContextIfaceMap = PTRINTMAP_STATIC_INITIALIZE; - - -typedef struct EnumeratedList { - ALCchar *Names; - ALCchar *NamesEnd; - ALCint *Indicies; - ALCsizei IndexSize; -} EnumeratedList; -static EnumeratedList DevicesList = { NULL, NULL, NULL, 0 }; -static EnumeratedList AllDevicesList = { NULL, NULL, NULL, 0 }; -static EnumeratedList CaptureDevicesList = { NULL, NULL, NULL, 0 }; - -static void ClearDeviceList(EnumeratedList *list) -{ - al_free(list->Names); - list->Names = NULL; - list->NamesEnd = NULL; - - al_free(list->Indicies); - list->Indicies = NULL; - list->IndexSize = 0; -} - -static void AppendDeviceList(EnumeratedList *list, const ALCchar *names, ALint idx) -{ - const ALCchar *name_end = names; - ALCsizei count = 0; - ALCchar *new_list; - ALCint *new_indicies; - size_t len; - ALCsizei i; - - if(!name_end) - return; - while(*name_end) - { - TRACE("Enumerated \"%s\", driver %d\n", name_end, idx); - count++; - name_end += strlen(name_end)+1; - } - if(names == name_end) - return; - - len = (list->NamesEnd - list->Names) + (name_end - names); - new_list = al_calloc(DEF_ALIGN, len + 1); - memcpy(new_list, list->Names, list->NamesEnd - list->Names); - memcpy(new_list + (list->NamesEnd - list->Names), names, name_end - names); - al_free(list->Names); - list->Names = new_list; - list->NamesEnd = list->Names + len; - - new_indicies = al_calloc(16, sizeof(ALCint)*(list->IndexSize + count)); - for(i = 0;i < list->IndexSize;i++) - new_indicies[i] = list->Indicies[i]; - for(i = 0;i < count;i++) - new_indicies[list->IndexSize+i] = idx; - al_free(list->Indicies); - list->Indicies = new_indicies; - list->IndexSize += count; -} - -static ALint GetDriverIndexForName(const EnumeratedList *list, const ALCchar *name) -{ - const ALCchar *devnames = list->Names; - const ALCint *index = list->Indicies; - - while(devnames && *devnames) - { - if(strcmp(name, devnames) == 0) - return *index; - devnames += strlen(devnames)+1; - index++; - } - return -1; -} - -void InitALC(void) -{ - almtx_init(&EnumerationLock, almtx_recursive); - almtx_init(&ContextSwitchLock, almtx_plain); -} - -void ReleaseALC(void) -{ - ClearDeviceList(&DevicesList); - ClearDeviceList(&AllDevicesList); - ClearDeviceList(&CaptureDevicesList); - - ResetPtrIntMap(&ContextIfaceMap); - ResetPtrIntMap(&DeviceIfaceMap); - - almtx_destroy(&ContextSwitchLock); - almtx_destroy(&EnumerationLock); -} - - -ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) -{ - ALCdevice *device = NULL; - ALint idx; - - /* Prior to the enumeration extension, apps would hardcode these names as a - * quality hint for the wrapper driver. Ignore them since there's no sane - * way to map them. - */ - if(devicename && (devicename[0] == '\0' || - strcmp(devicename, "DirectSound3D") == 0 || - strcmp(devicename, "DirectSound") == 0 || - strcmp(devicename, "MMSYSTEM") == 0)) - devicename = NULL; - if(devicename) - { - almtx_lock(&EnumerationLock); - if(!DevicesList.Names) - (void)alcGetString(NULL, ALC_DEVICE_SPECIFIER); - idx = GetDriverIndexForName(&DevicesList, devicename); - if(idx < 0) - { - if(!AllDevicesList.Names) - (void)alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); - idx = GetDriverIndexForName(&AllDevicesList, devicename); - } - almtx_unlock(&EnumerationLock); - if(idx < 0) - { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); - TRACE("Failed to find driver for name \"%s\"\n", devicename); - return NULL; - } - TRACE("Found driver %d for name \"%s\"\n", idx, devicename); - device = DriverList[idx].alcOpenDevice(devicename); - } - else - { - int i; - for(i = 0;i < DriverListSize;i++) - { - if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || - DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) - { - idx = i; - TRACE("Using default device from driver %d\n", idx); - device = DriverList[idx].alcOpenDevice(NULL); - break; - } - } - } - - if(device) - { - if(InsertPtrIntMapEntry(&DeviceIfaceMap, device, idx) != ALC_NO_ERROR) - { - DriverList[idx].alcCloseDevice(device); - device = NULL; - } - } - - return device; -} - -ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) -{ - ALint idx; - - if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0) - { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); - return ALC_FALSE; - } - if(!DriverList[idx].alcCloseDevice(device)) - return ALC_FALSE; - RemovePtrIntMapKey(&DeviceIfaceMap, device); - return ALC_TRUE; -} - - -ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrlist) -{ - ALCcontext *context; - ALint idx; - - if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0) - { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); - return ALC_FALSE; - } - context = DriverList[idx].alcCreateContext(device, attrlist); - if(context) - { - if(InsertPtrIntMapEntry(&ContextIfaceMap, context, idx) != ALC_NO_ERROR) - { - DriverList[idx].alcDestroyContext(context); - context = NULL; - } - } - - return context; -} - -ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) -{ - ALint idx = -1; - - almtx_lock(&ContextSwitchLock); - if(context) - { - idx = LookupPtrIntMapKey(&ContextIfaceMap, context); - if(idx < 0) - { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); - almtx_unlock(&ContextSwitchLock); - return ALC_FALSE; - } - if(!DriverList[idx].alcMakeContextCurrent(context)) - { - almtx_unlock(&ContextSwitchLock); - return ALC_FALSE; - } - } - - /* Unset the context from the old driver if it's different from the new - * current one. - */ - if(idx < 0) - { - DriverIface *oldiface = altss_get(ThreadCtxDriver); - if(oldiface) oldiface->alcSetThreadContext(NULL); - oldiface = ATOMIC_EXCHANGE_PTR_SEQ(&CurrentCtxDriver, NULL); - if(oldiface) oldiface->alcMakeContextCurrent(NULL); - } - else - { - DriverIface *oldiface = altss_get(ThreadCtxDriver); - if(oldiface && oldiface != &DriverList[idx]) - oldiface->alcSetThreadContext(NULL); - oldiface = ATOMIC_EXCHANGE_PTR_SEQ(&CurrentCtxDriver, &DriverList[idx]); - if(oldiface && oldiface != &DriverList[idx]) - oldiface->alcMakeContextCurrent(NULL); - } - almtx_unlock(&ContextSwitchLock); - altss_set(ThreadCtxDriver, NULL); - - return ALC_TRUE; -} - -ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context) -{ - if(context) - { - ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context); - if(idx >= 0) - return DriverList[idx].alcProcessContext(context); - } - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); -} - -ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context) -{ - if(context) - { - ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context); - if(idx >= 0) - return DriverList[idx].alcSuspendContext(context); - } - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); -} - -ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context) -{ - ALint idx; - - if(!context || (idx=LookupPtrIntMapKey(&ContextIfaceMap, context)) < 0) - { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); - return; - } - - DriverList[idx].alcDestroyContext(context); - RemovePtrIntMapKey(&ContextIfaceMap, context); -} - -ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) -{ - DriverIface *iface = altss_get(ThreadCtxDriver); - if(!iface) iface = ATOMIC_LOAD_SEQ(&CurrentCtxDriver); - return iface ? iface->alcGetCurrentContext() : NULL; -} - -ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context) -{ - if(context) - { - ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context); - if(idx >= 0) - return DriverList[idx].alcGetContextsDevice(context); - } - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); - return NULL; -} - - -ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) -{ - if(device) - { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); - if(idx < 0) return ALC_INVALID_DEVICE; - return DriverList[idx].alcGetError(device); - } - return ATOMIC_EXCHANGE_SEQ(&LastError, ALC_NO_ERROR); -} - -ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname) -{ - const char *ptr; - size_t len; - - if(device) - { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); - if(idx < 0) - { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); - return ALC_FALSE; - } - return DriverList[idx].alcIsExtensionPresent(device, extname); - } - - len = strlen(extname); - ptr = alcExtensionList; - while(ptr && *ptr) - { - if(strncasecmp(ptr, extname, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len]))) - return ALC_TRUE; - if((ptr=strchr(ptr, ' ')) != NULL) - { - do { - ++ptr; - } while(isspace(*ptr)); - } - } - return ALC_FALSE; -} - -ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname) -{ - size_t i; - - if(device) - { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); - if(idx < 0) - { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); - return NULL; - } - return DriverList[idx].alcGetProcAddress(device, funcname); - } - - for(i = 0;i < COUNTOF(alcFunctions);i++) - { - if(strcmp(funcname, alcFunctions[i].funcName) == 0) - return alcFunctions[i].address; - } - return NULL; -} - -ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname) -{ - size_t i; - - if(device) - { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); - if(idx < 0) - { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); - return 0; - } - return DriverList[idx].alcGetEnumValue(device, enumname); - } - - for(i = 0;i < COUNTOF(alcEnumerations);i++) - { - if(strcmp(enumname, alcEnumerations[i].enumName) == 0) - return alcEnumerations[i].value; - } - return 0; -} - -ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param) -{ - ALsizei i = 0; - - if(device) - { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); - if(idx < 0) - { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); - return NULL; - } - return DriverList[idx].alcGetString(device, param); - } - - switch(param) - { - case ALC_NO_ERROR: - return alcNoError; - case ALC_INVALID_ENUM: - return alcErrInvalidEnum; - case ALC_INVALID_VALUE: - return alcErrInvalidValue; - case ALC_INVALID_DEVICE: - return alcErrInvalidDevice; - case ALC_INVALID_CONTEXT: - return alcErrInvalidContext; - case ALC_OUT_OF_MEMORY: - return alcErrOutOfMemory; - case ALC_EXTENSIONS: - return alcExtensionList; - - case ALC_DEVICE_SPECIFIER: - almtx_lock(&EnumerationLock); - ClearDeviceList(&DevicesList); - for(i = 0;i < DriverListSize;i++) - { - /* Only enumerate names from drivers that support it. */ - if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || - DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) - AppendDeviceList(&DevicesList, - DriverList[i].alcGetString(NULL, ALC_DEVICE_SPECIFIER), i - ); - } - almtx_unlock(&EnumerationLock); - return DevicesList.Names; - - case ALC_ALL_DEVICES_SPECIFIER: - almtx_lock(&EnumerationLock); - ClearDeviceList(&AllDevicesList); - for(i = 0;i < DriverListSize;i++) - { - /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute - * standard enumeration. - */ - if(DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT")) - AppendDeviceList(&AllDevicesList, - DriverList[i].alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER), i - ); - else if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || - DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) - AppendDeviceList(&AllDevicesList, - DriverList[i].alcGetString(NULL, ALC_DEVICE_SPECIFIER), i - ); - } - almtx_unlock(&EnumerationLock); - return AllDevicesList.Names; - - case ALC_CAPTURE_DEVICE_SPECIFIER: - almtx_lock(&EnumerationLock); - ClearDeviceList(&CaptureDevicesList); - for(i = 0;i < DriverListSize;i++) - { - if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || - DriverList[i].alcIsExtensionPresent(NULL, "ALC_EXT_CAPTURE")) - AppendDeviceList(&CaptureDevicesList, - DriverList[i].alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER), i - ); - } - almtx_unlock(&EnumerationLock); - return CaptureDevicesList.Names; - - case ALC_DEFAULT_DEVICE_SPECIFIER: - for(i = 0;i < DriverListSize;i++) - { - if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || - DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) - return DriverList[i].alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); - } - return ""; - - case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: - for(i = 0;i < DriverListSize;i++) - { - if(DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT")) - return DriverList[i].alcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER); - } - return ""; - - case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: - for(i = 0;i < DriverListSize;i++) - { - if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || - DriverList[i].alcIsExtensionPresent(NULL, "ALC_EXT_CAPTURE")) - return DriverList[i].alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); - } - return ""; - - default: - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_ENUM); - break; - } - return NULL; -} - -ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) -{ - if(device) - { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); - if(idx < 0) - { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); - return; - } - return DriverList[idx].alcGetIntegerv(device, param, size, values); - } - - if(size <= 0 || values == NULL) - { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); - return; - } - - switch(param) - { - case ALC_MAJOR_VERSION: - if(size >= 1) - { - values[0] = alcMajorVersion; - return; - } - /*fall-through*/ - case ALC_MINOR_VERSION: - if(size >= 1) - { - values[0] = alcMinorVersion; - return; - } - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); - return; - - case ALC_ATTRIBUTES_SIZE: - case ALC_ALL_ATTRIBUTES: - case ALC_FREQUENCY: - case ALC_REFRESH: - case ALC_SYNC: - case ALC_MONO_SOURCES: - case ALC_STEREO_SOURCES: - case ALC_CAPTURE_SAMPLES: - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); - return; - - default: - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_ENUM); - return; - } -} - - -ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize) -{ - ALCdevice *device = NULL; - ALint idx; - - if(devicename && devicename[0] == '\0') - devicename = NULL; - if(devicename) - { - almtx_lock(&EnumerationLock); - if(!CaptureDevicesList.Names) - (void)alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); - idx = GetDriverIndexForName(&CaptureDevicesList, devicename); - almtx_unlock(&EnumerationLock); - if(idx < 0) - { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); - TRACE("Failed to find driver for name \"%s\"\n", devicename); - return NULL; - } - TRACE("Found driver %d for name \"%s\"\n", idx, devicename); - device = DriverList[idx].alcCaptureOpenDevice( - devicename, frequency, format, buffersize - ); - } - else - { - int i; - for(i = 0;i < DriverListSize;i++) - { - if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || - DriverList[i].alcIsExtensionPresent(NULL, "ALC_EXT_CAPTURE")) - { - idx = i; - TRACE("Using default capture device from driver %d\n", idx); - device = DriverList[idx].alcCaptureOpenDevice( - NULL, frequency, format, buffersize - ); - break; - } - } - } - - if(device) - { - if(InsertPtrIntMapEntry(&DeviceIfaceMap, device, idx) != ALC_NO_ERROR) - { - DriverList[idx].alcCaptureCloseDevice(device); - device = NULL; - } - } - - return device; -} - -ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) -{ - ALint idx; - - if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0) - { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); - return ALC_FALSE; - } - if(!DriverList[idx].alcCaptureCloseDevice(device)) - return ALC_FALSE; - RemovePtrIntMapKey(&DeviceIfaceMap, device); - return ALC_TRUE; -} - -ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) -{ - if(device) - { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); - if(idx >= 0) - return DriverList[idx].alcCaptureStart(device); - } - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); -} - -ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) -{ - if(device) - { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); - if(idx >= 0) - return DriverList[idx].alcCaptureStop(device); - } - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); -} - -ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) -{ - if(device) - { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); - if(idx >= 0) - return DriverList[idx].alcCaptureSamples(device, buffer, samples); - } - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); -} - - -ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) -{ - ALCenum err = ALC_INVALID_CONTEXT; - ALint idx; - - if(!context) - { - DriverIface *oldiface = altss_get(ThreadCtxDriver); - if(oldiface && !oldiface->alcSetThreadContext(NULL)) - return ALC_FALSE; - altss_set(ThreadCtxDriver, NULL); - return ALC_TRUE; - } - - idx = LookupPtrIntMapKey(&ContextIfaceMap, context); - if(idx >= 0) - { - if(DriverList[idx].alcSetThreadContext(context)) - { - DriverIface *oldiface = altss_get(ThreadCtxDriver); - if(oldiface != &DriverList[idx]) - { - altss_set(ThreadCtxDriver, &DriverList[idx]); - if(oldiface) oldiface->alcSetThreadContext(NULL); - } - return ALC_TRUE; - } - err = DriverList[idx].alcGetError(NULL); - } - ATOMIC_STORE_SEQ(&LastError, err); - return ALC_FALSE; -} - -ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) -{ - DriverIface *iface = altss_get(ThreadCtxDriver); - if(iface) return iface->alcGetThreadContext(); - return NULL; -} diff --git a/router/alc.cpp b/router/alc.cpp new file mode 100644 index 00000000..36275440 --- /dev/null +++ b/router/alc.cpp @@ -0,0 +1,959 @@ + +#include "config.h" + +#include +#include +#include +#include + +#include "AL/alc.h" +#include "router.h" +#include "almalloc.h" + + +#define COUNTOF(x) (sizeof(x)/sizeof(x[0])) + +#define DECL(x) { #x, (ALCvoid*)(x) } +static const struct { + const ALCchar *funcName; + ALCvoid *address; +} alcFunctions[] = { + DECL(alcCreateContext), + DECL(alcMakeContextCurrent), + DECL(alcProcessContext), + DECL(alcSuspendContext), + DECL(alcDestroyContext), + DECL(alcGetCurrentContext), + DECL(alcGetContextsDevice), + DECL(alcOpenDevice), + DECL(alcCloseDevice), + DECL(alcGetError), + DECL(alcIsExtensionPresent), + DECL(alcGetProcAddress), + DECL(alcGetEnumValue), + DECL(alcGetString), + DECL(alcGetIntegerv), + DECL(alcCaptureOpenDevice), + DECL(alcCaptureCloseDevice), + DECL(alcCaptureStart), + DECL(alcCaptureStop), + DECL(alcCaptureSamples), + + DECL(alcSetThreadContext), + DECL(alcGetThreadContext), + + DECL(alEnable), + DECL(alDisable), + DECL(alIsEnabled), + DECL(alGetString), + DECL(alGetBooleanv), + DECL(alGetIntegerv), + DECL(alGetFloatv), + DECL(alGetDoublev), + DECL(alGetBoolean), + DECL(alGetInteger), + DECL(alGetFloat), + DECL(alGetDouble), + DECL(alGetError), + DECL(alIsExtensionPresent), + DECL(alGetProcAddress), + DECL(alGetEnumValue), + DECL(alListenerf), + DECL(alListener3f), + DECL(alListenerfv), + DECL(alListeneri), + DECL(alListener3i), + DECL(alListeneriv), + DECL(alGetListenerf), + DECL(alGetListener3f), + DECL(alGetListenerfv), + DECL(alGetListeneri), + DECL(alGetListener3i), + DECL(alGetListeneriv), + DECL(alGenSources), + DECL(alDeleteSources), + DECL(alIsSource), + DECL(alSourcef), + DECL(alSource3f), + DECL(alSourcefv), + DECL(alSourcei), + DECL(alSource3i), + DECL(alSourceiv), + DECL(alGetSourcef), + DECL(alGetSource3f), + DECL(alGetSourcefv), + DECL(alGetSourcei), + DECL(alGetSource3i), + DECL(alGetSourceiv), + DECL(alSourcePlayv), + DECL(alSourceStopv), + DECL(alSourceRewindv), + DECL(alSourcePausev), + DECL(alSourcePlay), + DECL(alSourceStop), + DECL(alSourceRewind), + DECL(alSourcePause), + DECL(alSourceQueueBuffers), + DECL(alSourceUnqueueBuffers), + DECL(alGenBuffers), + DECL(alDeleteBuffers), + DECL(alIsBuffer), + DECL(alBufferData), + DECL(alBufferf), + DECL(alBuffer3f), + DECL(alBufferfv), + DECL(alBufferi), + DECL(alBuffer3i), + DECL(alBufferiv), + DECL(alGetBufferf), + DECL(alGetBuffer3f), + DECL(alGetBufferfv), + DECL(alGetBufferi), + DECL(alGetBuffer3i), + DECL(alGetBufferiv), + DECL(alDopplerFactor), + DECL(alDopplerVelocity), + DECL(alSpeedOfSound), + DECL(alDistanceModel), +}; +#undef DECL + +#define DECL(x) { #x, (x) } +static const struct { + const ALCchar *enumName; + ALCenum value; +} alcEnumerations[] = { + DECL(ALC_INVALID), + DECL(ALC_FALSE), + DECL(ALC_TRUE), + + DECL(ALC_MAJOR_VERSION), + DECL(ALC_MINOR_VERSION), + DECL(ALC_ATTRIBUTES_SIZE), + DECL(ALC_ALL_ATTRIBUTES), + DECL(ALC_DEFAULT_DEVICE_SPECIFIER), + DECL(ALC_DEVICE_SPECIFIER), + DECL(ALC_ALL_DEVICES_SPECIFIER), + DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER), + DECL(ALC_EXTENSIONS), + DECL(ALC_FREQUENCY), + DECL(ALC_REFRESH), + DECL(ALC_SYNC), + DECL(ALC_MONO_SOURCES), + DECL(ALC_STEREO_SOURCES), + DECL(ALC_CAPTURE_DEVICE_SPECIFIER), + DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER), + DECL(ALC_CAPTURE_SAMPLES), + + DECL(ALC_NO_ERROR), + DECL(ALC_INVALID_DEVICE), + DECL(ALC_INVALID_CONTEXT), + DECL(ALC_INVALID_ENUM), + DECL(ALC_INVALID_VALUE), + DECL(ALC_OUT_OF_MEMORY), + + DECL(AL_INVALID), + DECL(AL_NONE), + DECL(AL_FALSE), + DECL(AL_TRUE), + + DECL(AL_SOURCE_RELATIVE), + DECL(AL_CONE_INNER_ANGLE), + DECL(AL_CONE_OUTER_ANGLE), + DECL(AL_PITCH), + DECL(AL_POSITION), + DECL(AL_DIRECTION), + DECL(AL_VELOCITY), + DECL(AL_LOOPING), + DECL(AL_BUFFER), + DECL(AL_GAIN), + DECL(AL_MIN_GAIN), + DECL(AL_MAX_GAIN), + DECL(AL_ORIENTATION), + DECL(AL_REFERENCE_DISTANCE), + DECL(AL_ROLLOFF_FACTOR), + DECL(AL_CONE_OUTER_GAIN), + DECL(AL_MAX_DISTANCE), + DECL(AL_SEC_OFFSET), + DECL(AL_SAMPLE_OFFSET), + DECL(AL_BYTE_OFFSET), + DECL(AL_SOURCE_TYPE), + DECL(AL_STATIC), + DECL(AL_STREAMING), + DECL(AL_UNDETERMINED), + + DECL(AL_SOURCE_STATE), + DECL(AL_INITIAL), + DECL(AL_PLAYING), + DECL(AL_PAUSED), + DECL(AL_STOPPED), + + DECL(AL_BUFFERS_QUEUED), + DECL(AL_BUFFERS_PROCESSED), + + DECL(AL_FORMAT_MONO8), + DECL(AL_FORMAT_MONO16), + DECL(AL_FORMAT_STEREO8), + DECL(AL_FORMAT_STEREO16), + + DECL(AL_FREQUENCY), + DECL(AL_BITS), + DECL(AL_CHANNELS), + DECL(AL_SIZE), + + DECL(AL_UNUSED), + DECL(AL_PENDING), + DECL(AL_PROCESSED), + + DECL(AL_NO_ERROR), + DECL(AL_INVALID_NAME), + DECL(AL_INVALID_ENUM), + DECL(AL_INVALID_VALUE), + DECL(AL_INVALID_OPERATION), + DECL(AL_OUT_OF_MEMORY), + + DECL(AL_VENDOR), + DECL(AL_VERSION), + DECL(AL_RENDERER), + DECL(AL_EXTENSIONS), + + DECL(AL_DOPPLER_FACTOR), + DECL(AL_DOPPLER_VELOCITY), + DECL(AL_DISTANCE_MODEL), + DECL(AL_SPEED_OF_SOUND), + + DECL(AL_INVERSE_DISTANCE), + DECL(AL_INVERSE_DISTANCE_CLAMPED), + DECL(AL_LINEAR_DISTANCE), + DECL(AL_LINEAR_DISTANCE_CLAMPED), + DECL(AL_EXPONENT_DISTANCE), + DECL(AL_EXPONENT_DISTANCE_CLAMPED), +}; +#undef DECL + +static const ALCchar alcNoError[] = "No Error"; +static const ALCchar alcErrInvalidDevice[] = "Invalid Device"; +static const ALCchar alcErrInvalidContext[] = "Invalid Context"; +static const ALCchar alcErrInvalidEnum[] = "Invalid Enum"; +static const ALCchar alcErrInvalidValue[] = "Invalid Value"; +static const ALCchar alcErrOutOfMemory[] = "Out of Memory"; +static const ALCchar alcExtensionList[] = + "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE " + "ALC_EXT_thread_local_context"; + +static const ALCint alcMajorVersion = 1; +static const ALCint alcMinorVersion = 1; + + +static almtx_t EnumerationLock; +static almtx_t ContextSwitchLock; + +static ATOMIC(ALCenum) LastError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); +static PtrIntMap DeviceIfaceMap = PTRINTMAP_STATIC_INITIALIZE; +static PtrIntMap ContextIfaceMap = PTRINTMAP_STATIC_INITIALIZE; + + +typedef struct EnumeratedList { + ALCchar *Names; + ALCchar *NamesEnd; + ALCint *Indicies; + ALCsizei IndexSize; +} EnumeratedList; +static EnumeratedList DevicesList = { nullptr, nullptr, nullptr, 0 }; +static EnumeratedList AllDevicesList = { nullptr, nullptr, nullptr, 0 }; +static EnumeratedList CaptureDevicesList = { nullptr, nullptr, nullptr, 0 }; + +static void ClearDeviceList(EnumeratedList *list) +{ + al_free(list->Names); + list->Names = nullptr; + list->NamesEnd = nullptr; + + al_free(list->Indicies); + list->Indicies = nullptr; + list->IndexSize = 0; +} + +static void AppendDeviceList(EnumeratedList *list, const ALCchar *names, ALint idx) +{ + const ALCchar *name_end = names; + ALCsizei count = 0; + ALCchar *new_list; + ALCint *new_indicies; + size_t len; + ALCsizei i; + + if(!name_end) + return; + while(*name_end) + { + TRACE("Enumerated \"%s\", driver %d\n", name_end, idx); + count++; + name_end += strlen(name_end)+1; + } + if(names == name_end) + return; + + len = (list->NamesEnd - list->Names) + (name_end - names); + new_list = reinterpret_cast(al_calloc(DEF_ALIGN, len + 1)); + memcpy(new_list, list->Names, list->NamesEnd - list->Names); + memcpy(new_list + (list->NamesEnd - list->Names), names, name_end - names); + al_free(list->Names); + list->Names = new_list; + list->NamesEnd = list->Names + len; + + new_indicies = reinterpret_cast( + al_calloc(16, sizeof(ALCint)*(list->IndexSize + count))); + for(i = 0;i < list->IndexSize;i++) + new_indicies[i] = list->Indicies[i]; + for(i = 0;i < count;i++) + new_indicies[list->IndexSize+i] = idx; + al_free(list->Indicies); + list->Indicies = new_indicies; + list->IndexSize += count; +} + +static ALint GetDriverIndexForName(const EnumeratedList *list, const ALCchar *name) +{ + const ALCchar *devnames = list->Names; + const ALCint *index = list->Indicies; + + while(devnames && *devnames) + { + if(strcmp(name, devnames) == 0) + return *index; + devnames += strlen(devnames)+1; + index++; + } + return -1; +} + +void InitALC(void) +{ + almtx_init(&EnumerationLock, almtx_recursive); + almtx_init(&ContextSwitchLock, almtx_plain); +} + +void ReleaseALC(void) +{ + ClearDeviceList(&DevicesList); + ClearDeviceList(&AllDevicesList); + ClearDeviceList(&CaptureDevicesList); + + ResetPtrIntMap(&ContextIfaceMap); + ResetPtrIntMap(&DeviceIfaceMap); + + almtx_destroy(&ContextSwitchLock); + almtx_destroy(&EnumerationLock); +} + + +ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) +{ + ALCdevice *device = nullptr; + ALint idx; + + /* Prior to the enumeration extension, apps would hardcode these names as a + * quality hint for the wrapper driver. Ignore them since there's no sane + * way to map them. + */ + if(devicename && (devicename[0] == '\0' || + strcmp(devicename, "DirectSound3D") == 0 || + strcmp(devicename, "DirectSound") == 0 || + strcmp(devicename, "MMSYSTEM") == 0)) + devicename = nullptr; + if(devicename) + { + almtx_lock(&EnumerationLock); + if(!DevicesList.Names) + (void)alcGetString(nullptr, ALC_DEVICE_SPECIFIER); + idx = GetDriverIndexForName(&DevicesList, devicename); + if(idx < 0) + { + if(!AllDevicesList.Names) + (void)alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER); + idx = GetDriverIndexForName(&AllDevicesList, devicename); + } + almtx_unlock(&EnumerationLock); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); + TRACE("Failed to find driver for name \"%s\"\n", devicename); + return nullptr; + } + TRACE("Found driver %d for name \"%s\"\n", idx, devicename); + device = DriverList[idx].alcOpenDevice(devicename); + } + else + { + int i; + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) + { + idx = i; + TRACE("Using default device from driver %d\n", idx); + device = DriverList[idx].alcOpenDevice(nullptr); + break; + } + } + } + + if(device) + { + if(InsertPtrIntMapEntry(&DeviceIfaceMap, device, idx) != ALC_NO_ERROR) + { + DriverList[idx].alcCloseDevice(device); + device = nullptr; + } + } + + return device; +} + +ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) +{ + ALint idx; + + if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return ALC_FALSE; + } + if(!DriverList[idx].alcCloseDevice(device)) + return ALC_FALSE; + RemovePtrIntMapKey(&DeviceIfaceMap, device); + return ALC_TRUE; +} + + +ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrlist) +{ + ALCcontext *context; + ALint idx; + + if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return ALC_FALSE; + } + context = DriverList[idx].alcCreateContext(device, attrlist); + if(context) + { + if(InsertPtrIntMapEntry(&ContextIfaceMap, context, idx) != ALC_NO_ERROR) + { + DriverList[idx].alcDestroyContext(context); + context = nullptr; + } + } + + return context; +} + +ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) +{ + ALint idx = -1; + + almtx_lock(&ContextSwitchLock); + if(context) + { + idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); + almtx_unlock(&ContextSwitchLock); + return ALC_FALSE; + } + if(!DriverList[idx].alcMakeContextCurrent(context)) + { + almtx_unlock(&ContextSwitchLock); + return ALC_FALSE; + } + } + + /* Unset the context from the old driver if it's different from the new + * current one. + */ + if(idx < 0) + { + DriverIface *oldiface = reinterpret_cast(altss_get(ThreadCtxDriver)); + if(oldiface) oldiface->alcSetThreadContext(nullptr); + oldiface = reinterpret_cast( + ATOMIC_EXCHANGE_PTR_SEQ(&CurrentCtxDriver, (DriverIface*){nullptr})); + if(oldiface) oldiface->alcMakeContextCurrent(nullptr); + } + else + { + DriverIface *oldiface = reinterpret_cast(altss_get(ThreadCtxDriver)); + if(oldiface && oldiface != &DriverList[idx]) + oldiface->alcSetThreadContext(nullptr); + oldiface = reinterpret_cast( + ATOMIC_EXCHANGE_PTR_SEQ(&CurrentCtxDriver, &DriverList[idx])); + if(oldiface && oldiface != &DriverList[idx]) + oldiface->alcMakeContextCurrent(nullptr); + } + almtx_unlock(&ContextSwitchLock); + altss_set(ThreadCtxDriver, nullptr); + + return ALC_TRUE; +} + +ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context) +{ + if(context) + { + ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + if(idx >= 0) + return DriverList[idx].alcProcessContext(context); + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); +} + +ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context) +{ + if(context) + { + ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + if(idx >= 0) + return DriverList[idx].alcSuspendContext(context); + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); +} + +ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context) +{ + ALint idx; + + if(!context || (idx=LookupPtrIntMapKey(&ContextIfaceMap, context)) < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); + return; + } + + DriverList[idx].alcDestroyContext(context); + RemovePtrIntMapKey(&ContextIfaceMap, context); +} + +ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) +{ + DriverIface *iface = reinterpret_cast(altss_get(ThreadCtxDriver)); + if(!iface) iface = ATOMIC_LOAD_SEQ(&CurrentCtxDriver); + return iface ? iface->alcGetCurrentContext() : nullptr; +} + +ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context) +{ + if(context) + { + ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + if(idx >= 0) + return DriverList[idx].alcGetContextsDevice(context); + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); + return nullptr; +} + + +ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) +{ + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx < 0) return ALC_INVALID_DEVICE; + return DriverList[idx].alcGetError(device); + } + return ATOMIC_EXCHANGE_SEQ(&LastError, ALC_NO_ERROR); +} + +ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname) +{ + const char *ptr; + size_t len; + + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return ALC_FALSE; + } + return DriverList[idx].alcIsExtensionPresent(device, extname); + } + + len = strlen(extname); + ptr = alcExtensionList; + while(ptr && *ptr) + { + if(strncasecmp(ptr, extname, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len]))) + return ALC_TRUE; + if((ptr=strchr(ptr, ' ')) != nullptr) + { + do { + ++ptr; + } while(isspace(*ptr)); + } + } + return ALC_FALSE; +} + +ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname) +{ + size_t i; + + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return nullptr; + } + return DriverList[idx].alcGetProcAddress(device, funcname); + } + + for(i = 0;i < COUNTOF(alcFunctions);i++) + { + if(strcmp(funcname, alcFunctions[i].funcName) == 0) + return alcFunctions[i].address; + } + return nullptr; +} + +ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname) +{ + size_t i; + + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return 0; + } + return DriverList[idx].alcGetEnumValue(device, enumname); + } + + for(i = 0;i < COUNTOF(alcEnumerations);i++) + { + if(strcmp(enumname, alcEnumerations[i].enumName) == 0) + return alcEnumerations[i].value; + } + return 0; +} + +ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param) +{ + ALsizei i = 0; + + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return nullptr; + } + return DriverList[idx].alcGetString(device, param); + } + + switch(param) + { + case ALC_NO_ERROR: + return alcNoError; + case ALC_INVALID_ENUM: + return alcErrInvalidEnum; + case ALC_INVALID_VALUE: + return alcErrInvalidValue; + case ALC_INVALID_DEVICE: + return alcErrInvalidDevice; + case ALC_INVALID_CONTEXT: + return alcErrInvalidContext; + case ALC_OUT_OF_MEMORY: + return alcErrOutOfMemory; + case ALC_EXTENSIONS: + return alcExtensionList; + + case ALC_DEVICE_SPECIFIER: + almtx_lock(&EnumerationLock); + ClearDeviceList(&DevicesList); + for(i = 0;i < DriverListSize;i++) + { + /* Only enumerate names from drivers that support it. */ + if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) + AppendDeviceList(&DevicesList, + DriverList[i].alcGetString(nullptr, ALC_DEVICE_SPECIFIER), i + ); + } + almtx_unlock(&EnumerationLock); + return DevicesList.Names; + + case ALC_ALL_DEVICES_SPECIFIER: + almtx_lock(&EnumerationLock); + ClearDeviceList(&AllDevicesList); + for(i = 0;i < DriverListSize;i++) + { + /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute + * standard enumeration. + */ + if(DriverList[i].alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT")) + AppendDeviceList(&AllDevicesList, + DriverList[i].alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER), i + ); + else if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) + AppendDeviceList(&AllDevicesList, + DriverList[i].alcGetString(nullptr, ALC_DEVICE_SPECIFIER), i + ); + } + almtx_unlock(&EnumerationLock); + return AllDevicesList.Names; + + case ALC_CAPTURE_DEVICE_SPECIFIER: + almtx_lock(&EnumerationLock); + ClearDeviceList(&CaptureDevicesList); + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE")) + AppendDeviceList(&CaptureDevicesList, + DriverList[i].alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER), i + ); + } + almtx_unlock(&EnumerationLock); + return CaptureDevicesList.Names; + + case ALC_DEFAULT_DEVICE_SPECIFIER: + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) + return DriverList[i].alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER); + } + return ""; + + case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT")) + return DriverList[i].alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER); + } + return ""; + + case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE")) + return DriverList[i].alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); + } + return ""; + + default: + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_ENUM); + break; + } + return nullptr; +} + +ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) +{ + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return; + } + return DriverList[idx].alcGetIntegerv(device, param, size, values); + } + + if(size <= 0 || values == nullptr) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); + return; + } + + switch(param) + { + case ALC_MAJOR_VERSION: + if(size >= 1) + { + values[0] = alcMajorVersion; + return; + } + /*fall-through*/ + case ALC_MINOR_VERSION: + if(size >= 1) + { + values[0] = alcMinorVersion; + return; + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); + return; + + case ALC_ATTRIBUTES_SIZE: + case ALC_ALL_ATTRIBUTES: + case ALC_FREQUENCY: + case ALC_REFRESH: + case ALC_SYNC: + case ALC_MONO_SOURCES: + case ALC_STEREO_SOURCES: + case ALC_CAPTURE_SAMPLES: + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return; + + default: + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_ENUM); + return; + } +} + + +ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize) +{ + ALCdevice *device = nullptr; + ALint idx; + + if(devicename && devicename[0] == '\0') + devicename = nullptr; + if(devicename) + { + almtx_lock(&EnumerationLock); + if(!CaptureDevicesList.Names) + (void)alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER); + idx = GetDriverIndexForName(&CaptureDevicesList, devicename); + almtx_unlock(&EnumerationLock); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); + TRACE("Failed to find driver for name \"%s\"\n", devicename); + return nullptr; + } + TRACE("Found driver %d for name \"%s\"\n", idx, devicename); + device = DriverList[idx].alcCaptureOpenDevice( + devicename, frequency, format, buffersize + ); + } + else + { + int i; + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE")) + { + idx = i; + TRACE("Using default capture device from driver %d\n", idx); + device = DriverList[idx].alcCaptureOpenDevice( + nullptr, frequency, format, buffersize + ); + break; + } + } + } + + if(device) + { + if(InsertPtrIntMapEntry(&DeviceIfaceMap, device, idx) != ALC_NO_ERROR) + { + DriverList[idx].alcCaptureCloseDevice(device); + device = nullptr; + } + } + + return device; +} + +ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) +{ + ALint idx; + + if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return ALC_FALSE; + } + if(!DriverList[idx].alcCaptureCloseDevice(device)) + return ALC_FALSE; + RemovePtrIntMapKey(&DeviceIfaceMap, device); + return ALC_TRUE; +} + +ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) +{ + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx >= 0) + return DriverList[idx].alcCaptureStart(device); + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); +} + +ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) +{ + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx >= 0) + return DriverList[idx].alcCaptureStop(device); + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); +} + +ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) +{ + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx >= 0) + return DriverList[idx].alcCaptureSamples(device, buffer, samples); + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); +} + + +ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) +{ + ALCenum err = ALC_INVALID_CONTEXT; + ALint idx; + + if(!context) + { + DriverIface *oldiface = reinterpret_cast(altss_get(ThreadCtxDriver)); + if(oldiface && !oldiface->alcSetThreadContext(nullptr)) + return ALC_FALSE; + altss_set(ThreadCtxDriver, nullptr); + return ALC_TRUE; + } + + idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + if(idx >= 0) + { + if(DriverList[idx].alcSetThreadContext(context)) + { + DriverIface *oldiface = reinterpret_cast(altss_get(ThreadCtxDriver)); + if(oldiface != &DriverList[idx]) + { + altss_set(ThreadCtxDriver, &DriverList[idx]); + if(oldiface) oldiface->alcSetThreadContext(nullptr); + } + return ALC_TRUE; + } + err = DriverList[idx].alcGetError(nullptr); + } + ATOMIC_STORE_SEQ(&LastError, err); + return ALC_FALSE; +} + +ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) +{ + DriverIface *iface = reinterpret_cast(altss_get(ThreadCtxDriver)); + if(iface) return iface->alcGetThreadContext(); + return nullptr; +} diff --git a/router/router.c b/router/router.c deleted file mode 100644 index 9d4346a8..00000000 --- a/router/router.c +++ /dev/null @@ -1,537 +0,0 @@ - -#include "config.h" - -#include "router.h" - -#include -#include -#include - -#include "AL/alc.h" -#include "AL/al.h" -#include "almalloc.h" - -#include "version.h" - - -DriverIface *DriverList = NULL; -int DriverListSize = 0; -static int DriverListSizeMax = 0; - -altss_t ThreadCtxDriver; - -enum LogLevel LogLevel = LogLevel_Error; -FILE *LogFile; - -static void LoadDriverList(void); - - -BOOL APIENTRY DllMain(HINSTANCE UNUSED(module), DWORD reason, void* UNUSED(reserved)) -{ - const char *str; - int i; - - switch(reason) - { - case DLL_PROCESS_ATTACH: - LogFile = stderr; - str = getenv("ALROUTER_LOGFILE"); - if(str && *str != '\0') - { - FILE *f = fopen(str, "w"); - if(f == NULL) - ERR("Could not open log file: %s\n", str); - else - LogFile = f; - } - str = getenv("ALROUTER_LOGLEVEL"); - if(str && *str != '\0') - { - char *end = NULL; - long l = strtol(str, &end, 0); - if(!end || *end != '\0') - ERR("Invalid log level value: %s\n", str); - else if(l < LogLevel_None || l > LogLevel_Trace) - ERR("Log level out of range: %s\n", str); - else - LogLevel = l; - } - TRACE("Initializing router v0.1-%s %s\n", ALSOFT_GIT_COMMIT_HASH, ALSOFT_GIT_BRANCH); - LoadDriverList(); - - altss_create(&ThreadCtxDriver, NULL); - InitALC(); - break; - - case DLL_THREAD_ATTACH: - break; - case DLL_THREAD_DETACH: - althrd_thread_detach(); - break; - - case DLL_PROCESS_DETACH: - ReleaseALC(); - altss_delete(ThreadCtxDriver); - - for(i = 0;i < DriverListSize;i++) - { - if(DriverList[i].Module) - FreeLibrary(DriverList[i].Module); - } - al_free(DriverList); - DriverList = NULL; - DriverListSize = 0; - DriverListSizeMax = 0; - - if(LogFile && LogFile != stderr) - fclose(LogFile); - LogFile = NULL; - - althrd_deinit(); - break; - } - return TRUE; -} - - -#ifdef __GNUC__ -#define CAST_FUNC(x) (__typeof(x)) -#else -#define CAST_FUNC(x) (void*) -#endif - -static void AddModule(HMODULE module, const WCHAR *name) -{ - DriverIface newdrv; - int err = 0; - int i; - - for(i = 0;i < DriverListSize;i++) - { - if(DriverList[i].Module == module) - { - TRACE("Skipping already-loaded module %p\n", module); - FreeLibrary(module); - return; - } - if(wcscmp(DriverList[i].Name, name) == 0) - { - TRACE("Skipping similarly-named module %ls\n", name); - FreeLibrary(module); - return; - } - } - - if(DriverListSize == DriverListSizeMax) - { - int newmax = DriverListSizeMax ? DriverListSizeMax<<1 : 4; - void *newlist = al_calloc(DEF_ALIGN, sizeof(DriverList[0])*newmax); - if(!newlist) return; - - memcpy(newlist, DriverList, DriverListSize*sizeof(DriverList[0])); - al_free(DriverList); - DriverList = newlist; - DriverListSizeMax = newmax; - } - - memset(&newdrv, 0, sizeof(newdrv)); - /* Load required functions. */ -#define LOAD_PROC(x) do { \ - newdrv.x = CAST_FUNC(newdrv.x) GetProcAddress(module, #x); \ - if(!newdrv.x) \ - { \ - ERR("Failed to find entry point for %s in %ls\n", #x, name); \ - err = 1; \ - } \ -} while(0) - LOAD_PROC(alcCreateContext); - LOAD_PROC(alcMakeContextCurrent); - LOAD_PROC(alcProcessContext); - LOAD_PROC(alcSuspendContext); - LOAD_PROC(alcDestroyContext); - LOAD_PROC(alcGetCurrentContext); - LOAD_PROC(alcGetContextsDevice); - LOAD_PROC(alcOpenDevice); - LOAD_PROC(alcCloseDevice); - LOAD_PROC(alcGetError); - LOAD_PROC(alcIsExtensionPresent); - LOAD_PROC(alcGetProcAddress); - LOAD_PROC(alcGetEnumValue); - LOAD_PROC(alcGetString); - LOAD_PROC(alcGetIntegerv); - LOAD_PROC(alcCaptureOpenDevice); - LOAD_PROC(alcCaptureCloseDevice); - LOAD_PROC(alcCaptureStart); - LOAD_PROC(alcCaptureStop); - LOAD_PROC(alcCaptureSamples); - - LOAD_PROC(alEnable); - LOAD_PROC(alDisable); - LOAD_PROC(alIsEnabled); - LOAD_PROC(alGetString); - LOAD_PROC(alGetBooleanv); - LOAD_PROC(alGetIntegerv); - LOAD_PROC(alGetFloatv); - LOAD_PROC(alGetDoublev); - LOAD_PROC(alGetBoolean); - LOAD_PROC(alGetInteger); - LOAD_PROC(alGetFloat); - LOAD_PROC(alGetDouble); - LOAD_PROC(alGetError); - LOAD_PROC(alIsExtensionPresent); - LOAD_PROC(alGetProcAddress); - LOAD_PROC(alGetEnumValue); - LOAD_PROC(alListenerf); - LOAD_PROC(alListener3f); - LOAD_PROC(alListenerfv); - LOAD_PROC(alListeneri); - LOAD_PROC(alListener3i); - LOAD_PROC(alListeneriv); - LOAD_PROC(alGetListenerf); - LOAD_PROC(alGetListener3f); - LOAD_PROC(alGetListenerfv); - LOAD_PROC(alGetListeneri); - LOAD_PROC(alGetListener3i); - LOAD_PROC(alGetListeneriv); - LOAD_PROC(alGenSources); - LOAD_PROC(alDeleteSources); - LOAD_PROC(alIsSource); - LOAD_PROC(alSourcef); - LOAD_PROC(alSource3f); - LOAD_PROC(alSourcefv); - LOAD_PROC(alSourcei); - LOAD_PROC(alSource3i); - LOAD_PROC(alSourceiv); - LOAD_PROC(alGetSourcef); - LOAD_PROC(alGetSource3f); - LOAD_PROC(alGetSourcefv); - LOAD_PROC(alGetSourcei); - LOAD_PROC(alGetSource3i); - LOAD_PROC(alGetSourceiv); - LOAD_PROC(alSourcePlayv); - LOAD_PROC(alSourceStopv); - LOAD_PROC(alSourceRewindv); - LOAD_PROC(alSourcePausev); - LOAD_PROC(alSourcePlay); - LOAD_PROC(alSourceStop); - LOAD_PROC(alSourceRewind); - LOAD_PROC(alSourcePause); - LOAD_PROC(alSourceQueueBuffers); - LOAD_PROC(alSourceUnqueueBuffers); - LOAD_PROC(alGenBuffers); - LOAD_PROC(alDeleteBuffers); - LOAD_PROC(alIsBuffer); - LOAD_PROC(alBufferf); - LOAD_PROC(alBuffer3f); - LOAD_PROC(alBufferfv); - LOAD_PROC(alBufferi); - LOAD_PROC(alBuffer3i); - LOAD_PROC(alBufferiv); - LOAD_PROC(alGetBufferf); - LOAD_PROC(alGetBuffer3f); - LOAD_PROC(alGetBufferfv); - LOAD_PROC(alGetBufferi); - LOAD_PROC(alGetBuffer3i); - LOAD_PROC(alGetBufferiv); - LOAD_PROC(alBufferData); - LOAD_PROC(alDopplerFactor); - LOAD_PROC(alDopplerVelocity); - LOAD_PROC(alSpeedOfSound); - LOAD_PROC(alDistanceModel); - if(!err) - { - ALCint alc_ver[2] = { 0, 0 }; - wcsncpy(newdrv.Name, name, 32); - newdrv.Module = module; - newdrv.alcGetIntegerv(NULL, ALC_MAJOR_VERSION, 1, &alc_ver[0]); - newdrv.alcGetIntegerv(NULL, ALC_MINOR_VERSION, 1, &alc_ver[1]); - if(newdrv.alcGetError(NULL) == ALC_NO_ERROR) - newdrv.ALCVer = MAKE_ALC_VER(alc_ver[0], alc_ver[1]); - else - newdrv.ALCVer = MAKE_ALC_VER(1, 0); - -#undef LOAD_PROC -#define LOAD_PROC(x) do { \ - newdrv.x = CAST_FUNC(newdrv.x) newdrv.alcGetProcAddress(NULL, #x); \ - if(!newdrv.x) \ - { \ - ERR("Failed to find entry point for %s in %ls\n", #x, name); \ - err = 1; \ - } \ -} while(0) - if(newdrv.alcIsExtensionPresent(NULL, "ALC_EXT_thread_local_context")) - { - LOAD_PROC(alcSetThreadContext); - LOAD_PROC(alcGetThreadContext); - } - } - - if(!err) - { - TRACE("Loaded module %p, %ls, ALC %d.%d\n", module, name, - newdrv.ALCVer>>8, newdrv.ALCVer&255); - DriverList[DriverListSize++] = newdrv; - } -#undef LOAD_PROC -} - -static void SearchDrivers(WCHAR *path) -{ - WCHAR srchPath[MAX_PATH+1] = L""; - WIN32_FIND_DATAW fdata; - HANDLE srchHdl; - - TRACE("Searching for drivers in %ls...\n", path); - wcsncpy(srchPath, path, MAX_PATH); - wcsncat(srchPath, L"\\*oal.dll", MAX_PATH - lstrlenW(srchPath)); - srchHdl = FindFirstFileW(srchPath, &fdata); - if(srchHdl != INVALID_HANDLE_VALUE) - { - do { - HMODULE mod; - - wcsncpy(srchPath, path, MAX_PATH); - wcsncat(srchPath, L"\\", MAX_PATH - lstrlenW(srchPath)); - wcsncat(srchPath, fdata.cFileName, MAX_PATH - lstrlenW(srchPath)); - TRACE("Found %ls\n", srchPath); - - mod = LoadLibraryW(srchPath); - if(!mod) - WARN("Could not load %ls\n", srchPath); - else - AddModule(mod, fdata.cFileName); - } while(FindNextFileW(srchHdl, &fdata)); - FindClose(srchHdl); - } -} - -static WCHAR *strrchrW(WCHAR *str, WCHAR ch) -{ - WCHAR *res = NULL; - while(str && *str != '\0') - { - if(*str == ch) - res = str; - ++str; - } - return res; -} - -static int GetLoadedModuleDirectory(const WCHAR *name, WCHAR *moddir, DWORD length) -{ - HMODULE module = NULL; - WCHAR *sep0, *sep1; - - if(name) - { - module = GetModuleHandleW(name); - if(!module) return 0; - } - - if(GetModuleFileNameW(module, moddir, length) == 0) - return 0; - - sep0 = strrchrW(moddir, '/'); - if(sep0) sep1 = strrchrW(sep0+1, '\\'); - else sep1 = strrchrW(moddir, '\\'); - - if(sep1) *sep1 = '\0'; - else if(sep0) *sep0 = '\0'; - else *moddir = '\0'; - - return 1; -} - -void LoadDriverList(void) -{ - WCHAR dll_path[MAX_PATH+1] = L""; - WCHAR cwd_path[MAX_PATH+1] = L""; - WCHAR proc_path[MAX_PATH+1] = L""; - WCHAR sys_path[MAX_PATH+1] = L""; - int len; - - if(GetLoadedModuleDirectory(L"OpenAL32.dll", dll_path, MAX_PATH)) - TRACE("Got DLL path %ls\n", dll_path); - - GetCurrentDirectoryW(MAX_PATH, cwd_path); - len = lstrlenW(cwd_path); - if(len > 0 && (cwd_path[len-1] == '\\' || cwd_path[len-1] == '/')) - cwd_path[len-1] = '\0'; - TRACE("Got current working directory %ls\n", cwd_path); - - if(GetLoadedModuleDirectory(NULL, proc_path, MAX_PATH)) - TRACE("Got proc path %ls\n", proc_path); - - GetSystemDirectoryW(sys_path, MAX_PATH); - len = lstrlenW(sys_path); - if(len > 0 && (sys_path[len-1] == '\\' || sys_path[len-1] == '/')) - sys_path[len-1] = '\0'; - TRACE("Got system path %ls\n", sys_path); - - /* Don't search the DLL's path if it is the same as the current working - * directory, app's path, or system path (don't want to do duplicate - * searches, or increase the priority of the app or system path). - */ - if(dll_path[0] && - (!cwd_path[0] || wcscmp(dll_path, cwd_path) != 0) && - (!proc_path[0] || wcscmp(dll_path, proc_path) != 0) && - (!sys_path[0] || wcscmp(dll_path, sys_path) != 0)) - SearchDrivers(dll_path); - if(cwd_path[0] && - (!proc_path[0] || wcscmp(cwd_path, proc_path) != 0) && - (!sys_path[0] || wcscmp(cwd_path, sys_path) != 0)) - SearchDrivers(cwd_path); - if(proc_path[0] && (!sys_path[0] || wcscmp(proc_path, sys_path) != 0)) - SearchDrivers(proc_path); - if(sys_path[0]) - SearchDrivers(sys_path); -} - - -void InitPtrIntMap(PtrIntMap *map) -{ - map->keys = NULL; - map->values = NULL; - map->size = 0; - map->capacity = 0; - RWLockInit(&map->lock); -} - -void ResetPtrIntMap(PtrIntMap *map) -{ - WriteLock(&map->lock); - al_free(map->keys); - map->keys = NULL; - map->values = NULL; - map->size = 0; - map->capacity = 0; - WriteUnlock(&map->lock); -} - -ALenum InsertPtrIntMapEntry(PtrIntMap *map, ALvoid *key, ALint value) -{ - ALsizei pos = 0; - - WriteLock(&map->lock); - if(map->size > 0) - { - ALsizei count = map->size; - do { - ALsizei step = count>>1; - ALsizei i = pos+step; - if(map->keys[i] >= key) - count = step; - else - { - pos = i+1; - count -= step+1; - } - } while(count > 0); - } - - if(pos == map->size || map->keys[pos] != key) - { - if(map->size == map->capacity) - { - ALvoid **keys = NULL; - ALint *values; - ALsizei newcap; - - newcap = (map->capacity ? (map->capacity<<1) : 4); - if(newcap > map->capacity) - keys = al_calloc(16, (sizeof(map->keys[0])+sizeof(map->values[0]))*newcap); - if(!keys) - { - WriteUnlock(&map->lock); - return AL_OUT_OF_MEMORY; - } - values = (ALint*)&keys[newcap]; - - if(map->keys) - { - memcpy(keys, map->keys, map->size*sizeof(map->keys[0])); - memcpy(values, map->values, map->size*sizeof(map->values[0])); - } - al_free(map->keys); - map->keys = keys; - map->values = values; - map->capacity = newcap; - } - - if(pos < map->size) - { - memmove(&map->keys[pos+1], &map->keys[pos], - (map->size-pos)*sizeof(map->keys[0])); - memmove(&map->values[pos+1], &map->values[pos], - (map->size-pos)*sizeof(map->values[0])); - } - map->size++; - } - map->keys[pos] = key; - map->values[pos] = value; - WriteUnlock(&map->lock); - - return AL_NO_ERROR; -} - -ALint RemovePtrIntMapKey(PtrIntMap *map, ALvoid *key) -{ - ALint ret = -1; - WriteLock(&map->lock); - if(map->size > 0) - { - ALsizei pos = 0; - ALsizei count = map->size; - do { - ALsizei step = count>>1; - ALsizei i = pos+step; - if(map->keys[i] >= key) - count = step; - else - { - pos = i+1; - count -= step+1; - } - } while(count > 0); - if(pos < map->size && map->keys[pos] == key) - { - ret = map->values[pos]; - if(pos < map->size-1) - { - memmove(&map->keys[pos], &map->keys[pos+1], - (map->size-1-pos)*sizeof(map->keys[0])); - memmove(&map->values[pos], &map->values[pos+1], - (map->size-1-pos)*sizeof(map->values[0])); - } - map->size--; - } - } - WriteUnlock(&map->lock); - return ret; -} - -ALint LookupPtrIntMapKey(PtrIntMap *map, ALvoid *key) -{ - ALint ret = -1; - ReadLock(&map->lock); - if(map->size > 0) - { - ALsizei pos = 0; - ALsizei count = map->size; - do { - ALsizei step = count>>1; - ALsizei i = pos+step; - if(map->keys[i] >= key) - count = step; - else - { - pos = i+1; - count -= step+1; - } - } while(count > 0); - if(pos < map->size && map->keys[pos] == key) - ret = map->values[pos]; - } - ReadUnlock(&map->lock); - return ret; -} diff --git a/router/router.cpp b/router/router.cpp new file mode 100644 index 00000000..13cd3c69 --- /dev/null +++ b/router/router.cpp @@ -0,0 +1,541 @@ + +#include "config.h" + +#include "router.h" + +#include +#include +#include + +#include "AL/alc.h" +#include "AL/al.h" +#include "almalloc.h" + +#include "version.h" + + +DriverIface *DriverList = nullptr; +int DriverListSize = 0; +static int DriverListSizeMax = 0; + +altss_t ThreadCtxDriver; + +enum LogLevel LogLevel = LogLevel_Error; +FILE *LogFile; + +static void LoadDriverList(void); + + +BOOL APIENTRY DllMain(HINSTANCE UNUSED(module), DWORD reason, void* UNUSED(reserved)) +{ + const char *str; + int i; + + switch(reason) + { + case DLL_PROCESS_ATTACH: + LogFile = stderr; + str = getenv("ALROUTER_LOGFILE"); + if(str && *str != '\0') + { + FILE *f = fopen(str, "w"); + if(f == nullptr) + ERR("Could not open log file: %s\n", str); + else + LogFile = f; + } + str = getenv("ALROUTER_LOGLEVEL"); + if(str && *str != '\0') + { + char *end = nullptr; + long l = strtol(str, &end, 0); + if(!end || *end != '\0') + ERR("Invalid log level value: %s\n", str); + else if(l < LogLevel_None || l > LogLevel_Trace) + ERR("Log level out of range: %s\n", str); + else + LogLevel = static_cast(l); + } + TRACE("Initializing router v0.1-%s %s\n", ALSOFT_GIT_COMMIT_HASH, ALSOFT_GIT_BRANCH); + LoadDriverList(); + + altss_create(&ThreadCtxDriver, nullptr); + InitALC(); + break; + + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + althrd_thread_detach(); + break; + + case DLL_PROCESS_DETACH: + ReleaseALC(); + altss_delete(ThreadCtxDriver); + + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].Module) + FreeLibrary(DriverList[i].Module); + } + al_free(DriverList); + DriverList = nullptr; + DriverListSize = 0; + DriverListSizeMax = 0; + + if(LogFile && LogFile != stderr) + fclose(LogFile); + LogFile = nullptr; + + althrd_deinit(); + break; + } + return TRUE; +} + + +#ifdef __GNUC__ +#define CAST_FUNC(x) (__typeof(x)) +#else +#define CAST_FUNC(x) (void*) +#endif + +static void AddModule(HMODULE module, const WCHAR *name) +{ + DriverIface newdrv; + int err = 0; + int i; + + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].Module == module) + { + TRACE("Skipping already-loaded module %p\n", module); + FreeLibrary(module); + return; + } + if(wcscmp(DriverList[i].Name, name) == 0) + { + TRACE("Skipping similarly-named module %ls\n", name); + FreeLibrary(module); + return; + } + } + + if(DriverListSize == DriverListSizeMax) + { + int newmax = DriverListSizeMax ? DriverListSizeMax<<1 : 4; + void *newlist = al_calloc(DEF_ALIGN, sizeof(DriverList[0])*newmax); + if(!newlist) return; + + memcpy(newlist, DriverList, DriverListSize*sizeof(DriverList[0])); + al_free(DriverList); + DriverList = reinterpret_cast(newlist); + DriverListSizeMax = newmax; + } + + memset(&newdrv, 0, sizeof(newdrv)); + /* Load required functions. */ +#define LOAD_PROC(x) do { \ + newdrv.x = reinterpret_cast( \ + GetProcAddress(module, #x)); \ + if(!newdrv.x) \ + { \ + ERR("Failed to find entry point for %s in %ls\n", #x, name); \ + err = 1; \ + } \ +} while(0) + LOAD_PROC(alcCreateContext); + LOAD_PROC(alcMakeContextCurrent); + LOAD_PROC(alcProcessContext); + LOAD_PROC(alcSuspendContext); + LOAD_PROC(alcDestroyContext); + LOAD_PROC(alcGetCurrentContext); + LOAD_PROC(alcGetContextsDevice); + LOAD_PROC(alcOpenDevice); + LOAD_PROC(alcCloseDevice); + LOAD_PROC(alcGetError); + LOAD_PROC(alcIsExtensionPresent); + LOAD_PROC(alcGetProcAddress); + LOAD_PROC(alcGetEnumValue); + LOAD_PROC(alcGetString); + LOAD_PROC(alcGetIntegerv); + LOAD_PROC(alcCaptureOpenDevice); + LOAD_PROC(alcCaptureCloseDevice); + LOAD_PROC(alcCaptureStart); + LOAD_PROC(alcCaptureStop); + LOAD_PROC(alcCaptureSamples); + + LOAD_PROC(alEnable); + LOAD_PROC(alDisable); + LOAD_PROC(alIsEnabled); + LOAD_PROC(alGetString); + LOAD_PROC(alGetBooleanv); + LOAD_PROC(alGetIntegerv); + LOAD_PROC(alGetFloatv); + LOAD_PROC(alGetDoublev); + LOAD_PROC(alGetBoolean); + LOAD_PROC(alGetInteger); + LOAD_PROC(alGetFloat); + LOAD_PROC(alGetDouble); + LOAD_PROC(alGetError); + LOAD_PROC(alIsExtensionPresent); + LOAD_PROC(alGetProcAddress); + LOAD_PROC(alGetEnumValue); + LOAD_PROC(alListenerf); + LOAD_PROC(alListener3f); + LOAD_PROC(alListenerfv); + LOAD_PROC(alListeneri); + LOAD_PROC(alListener3i); + LOAD_PROC(alListeneriv); + LOAD_PROC(alGetListenerf); + LOAD_PROC(alGetListener3f); + LOAD_PROC(alGetListenerfv); + LOAD_PROC(alGetListeneri); + LOAD_PROC(alGetListener3i); + LOAD_PROC(alGetListeneriv); + LOAD_PROC(alGenSources); + LOAD_PROC(alDeleteSources); + LOAD_PROC(alIsSource); + LOAD_PROC(alSourcef); + LOAD_PROC(alSource3f); + LOAD_PROC(alSourcefv); + LOAD_PROC(alSourcei); + LOAD_PROC(alSource3i); + LOAD_PROC(alSourceiv); + LOAD_PROC(alGetSourcef); + LOAD_PROC(alGetSource3f); + LOAD_PROC(alGetSourcefv); + LOAD_PROC(alGetSourcei); + LOAD_PROC(alGetSource3i); + LOAD_PROC(alGetSourceiv); + LOAD_PROC(alSourcePlayv); + LOAD_PROC(alSourceStopv); + LOAD_PROC(alSourceRewindv); + LOAD_PROC(alSourcePausev); + LOAD_PROC(alSourcePlay); + LOAD_PROC(alSourceStop); + LOAD_PROC(alSourceRewind); + LOAD_PROC(alSourcePause); + LOAD_PROC(alSourceQueueBuffers); + LOAD_PROC(alSourceUnqueueBuffers); + LOAD_PROC(alGenBuffers); + LOAD_PROC(alDeleteBuffers); + LOAD_PROC(alIsBuffer); + LOAD_PROC(alBufferf); + LOAD_PROC(alBuffer3f); + LOAD_PROC(alBufferfv); + LOAD_PROC(alBufferi); + LOAD_PROC(alBuffer3i); + LOAD_PROC(alBufferiv); + LOAD_PROC(alGetBufferf); + LOAD_PROC(alGetBuffer3f); + LOAD_PROC(alGetBufferfv); + LOAD_PROC(alGetBufferi); + LOAD_PROC(alGetBuffer3i); + LOAD_PROC(alGetBufferiv); + LOAD_PROC(alBufferData); + LOAD_PROC(alDopplerFactor); + LOAD_PROC(alDopplerVelocity); + LOAD_PROC(alSpeedOfSound); + LOAD_PROC(alDistanceModel); + if(!err) + { + ALCint alc_ver[2] = { 0, 0 }; + wcsncpy(newdrv.Name, name, 32); + newdrv.Module = module; + newdrv.alcGetIntegerv(nullptr, ALC_MAJOR_VERSION, 1, &alc_ver[0]); + newdrv.alcGetIntegerv(nullptr, ALC_MINOR_VERSION, 1, &alc_ver[1]); + if(newdrv.alcGetError(nullptr) == ALC_NO_ERROR) + newdrv.ALCVer = MAKE_ALC_VER(alc_ver[0], alc_ver[1]); + else + newdrv.ALCVer = MAKE_ALC_VER(1, 0); + +#undef LOAD_PROC +#define LOAD_PROC(x) do { \ + newdrv.x = reinterpret_cast( \ + newdrv.alcGetProcAddress(nullptr, #x)); \ + if(!newdrv.x) \ + { \ + ERR("Failed to find entry point for %s in %ls\n", #x, name); \ + err = 1; \ + } \ +} while(0) + if(newdrv.alcIsExtensionPresent(nullptr, "ALC_EXT_thread_local_context")) + { + LOAD_PROC(alcSetThreadContext); + LOAD_PROC(alcGetThreadContext); + } + } + + if(!err) + { + TRACE("Loaded module %p, %ls, ALC %d.%d\n", module, name, + newdrv.ALCVer>>8, newdrv.ALCVer&255); + DriverList[DriverListSize++] = newdrv; + } +#undef LOAD_PROC +} + +static void SearchDrivers(WCHAR *path) +{ + WCHAR srchPath[MAX_PATH+1] = L""; + WIN32_FIND_DATAW fdata; + HANDLE srchHdl; + + TRACE("Searching for drivers in %ls...\n", path); + wcsncpy(srchPath, path, MAX_PATH); + wcsncat(srchPath, L"\\*oal.dll", MAX_PATH - lstrlenW(srchPath)); + srchHdl = FindFirstFileW(srchPath, &fdata); + if(srchHdl != INVALID_HANDLE_VALUE) + { + do { + HMODULE mod; + + wcsncpy(srchPath, path, MAX_PATH); + wcsncat(srchPath, L"\\", MAX_PATH - lstrlenW(srchPath)); + wcsncat(srchPath, fdata.cFileName, MAX_PATH - lstrlenW(srchPath)); + TRACE("Found %ls\n", srchPath); + + mod = LoadLibraryW(srchPath); + if(!mod) + WARN("Could not load %ls\n", srchPath); + else + AddModule(mod, fdata.cFileName); + } while(FindNextFileW(srchHdl, &fdata)); + FindClose(srchHdl); + } +} + +static WCHAR *strrchrW(WCHAR *str, WCHAR ch) +{ + WCHAR *res = nullptr; + while(str && *str != '\0') + { + if(*str == ch) + res = str; + ++str; + } + return res; +} + +static int GetLoadedModuleDirectory(const WCHAR *name, WCHAR *moddir, DWORD length) +{ + HMODULE module = nullptr; + WCHAR *sep0, *sep1; + + if(name) + { + module = GetModuleHandleW(name); + if(!module) return 0; + } + + if(GetModuleFileNameW(module, moddir, length) == 0) + return 0; + + sep0 = strrchrW(moddir, '/'); + if(sep0) sep1 = strrchrW(sep0+1, '\\'); + else sep1 = strrchrW(moddir, '\\'); + + if(sep1) *sep1 = '\0'; + else if(sep0) *sep0 = '\0'; + else *moddir = '\0'; + + return 1; +} + +void LoadDriverList(void) +{ + WCHAR dll_path[MAX_PATH+1] = L""; + WCHAR cwd_path[MAX_PATH+1] = L""; + WCHAR proc_path[MAX_PATH+1] = L""; + WCHAR sys_path[MAX_PATH+1] = L""; + int len; + + if(GetLoadedModuleDirectory(L"OpenAL32.dll", dll_path, MAX_PATH)) + TRACE("Got DLL path %ls\n", dll_path); + + GetCurrentDirectoryW(MAX_PATH, cwd_path); + len = lstrlenW(cwd_path); + if(len > 0 && (cwd_path[len-1] == '\\' || cwd_path[len-1] == '/')) + cwd_path[len-1] = '\0'; + TRACE("Got current working directory %ls\n", cwd_path); + + if(GetLoadedModuleDirectory(nullptr, proc_path, MAX_PATH)) + TRACE("Got proc path %ls\n", proc_path); + + GetSystemDirectoryW(sys_path, MAX_PATH); + len = lstrlenW(sys_path); + if(len > 0 && (sys_path[len-1] == '\\' || sys_path[len-1] == '/')) + sys_path[len-1] = '\0'; + TRACE("Got system path %ls\n", sys_path); + + /* Don't search the DLL's path if it is the same as the current working + * directory, app's path, or system path (don't want to do duplicate + * searches, or increase the priority of the app or system path). + */ + if(dll_path[0] && + (!cwd_path[0] || wcscmp(dll_path, cwd_path) != 0) && + (!proc_path[0] || wcscmp(dll_path, proc_path) != 0) && + (!sys_path[0] || wcscmp(dll_path, sys_path) != 0)) + SearchDrivers(dll_path); + if(cwd_path[0] && + (!proc_path[0] || wcscmp(cwd_path, proc_path) != 0) && + (!sys_path[0] || wcscmp(cwd_path, sys_path) != 0)) + SearchDrivers(cwd_path); + if(proc_path[0] && (!sys_path[0] || wcscmp(proc_path, sys_path) != 0)) + SearchDrivers(proc_path); + if(sys_path[0]) + SearchDrivers(sys_path); +} + + +void InitPtrIntMap(PtrIntMap *map) +{ + map->keys = nullptr; + map->values = nullptr; + map->size = 0; + map->capacity = 0; + RWLockInit(&map->lock); +} + +void ResetPtrIntMap(PtrIntMap *map) +{ + WriteLock(&map->lock); + al_free(map->keys); + map->keys = nullptr; + map->values = nullptr; + map->size = 0; + map->capacity = 0; + WriteUnlock(&map->lock); +} + +ALenum InsertPtrIntMapEntry(PtrIntMap *map, ALvoid *key, ALint value) +{ + ALsizei pos = 0; + + WriteLock(&map->lock); + if(map->size > 0) + { + ALsizei count = map->size; + do { + ALsizei step = count>>1; + ALsizei i = pos+step; + if(map->keys[i] >= key) + count = step; + else + { + pos = i+1; + count -= step+1; + } + } while(count > 0); + } + + if(pos == map->size || map->keys[pos] != key) + { + if(map->size == map->capacity) + { + ALvoid **keys = nullptr; + ALint *values; + ALsizei newcap; + + newcap = (map->capacity ? (map->capacity<<1) : 4); + if(newcap > map->capacity) + keys = reinterpret_cast( + al_calloc(16, (sizeof(map->keys[0])+sizeof(map->values[0]))*newcap) + ); + if(!keys) + { + WriteUnlock(&map->lock); + return AL_OUT_OF_MEMORY; + } + values = (ALint*)&keys[newcap]; + + if(map->keys) + { + memcpy(keys, map->keys, map->size*sizeof(map->keys[0])); + memcpy(values, map->values, map->size*sizeof(map->values[0])); + } + al_free(map->keys); + map->keys = keys; + map->values = values; + map->capacity = newcap; + } + + if(pos < map->size) + { + memmove(&map->keys[pos+1], &map->keys[pos], + (map->size-pos)*sizeof(map->keys[0])); + memmove(&map->values[pos+1], &map->values[pos], + (map->size-pos)*sizeof(map->values[0])); + } + map->size++; + } + map->keys[pos] = key; + map->values[pos] = value; + WriteUnlock(&map->lock); + + return AL_NO_ERROR; +} + +ALint RemovePtrIntMapKey(PtrIntMap *map, ALvoid *key) +{ + ALint ret = -1; + WriteLock(&map->lock); + if(map->size > 0) + { + ALsizei pos = 0; + ALsizei count = map->size; + do { + ALsizei step = count>>1; + ALsizei i = pos+step; + if(map->keys[i] >= key) + count = step; + else + { + pos = i+1; + count -= step+1; + } + } while(count > 0); + if(pos < map->size && map->keys[pos] == key) + { + ret = map->values[pos]; + if(pos < map->size-1) + { + memmove(&map->keys[pos], &map->keys[pos+1], + (map->size-1-pos)*sizeof(map->keys[0])); + memmove(&map->values[pos], &map->values[pos+1], + (map->size-1-pos)*sizeof(map->values[0])); + } + map->size--; + } + } + WriteUnlock(&map->lock); + return ret; +} + +ALint LookupPtrIntMapKey(PtrIntMap *map, ALvoid *key) +{ + ALint ret = -1; + ReadLock(&map->lock); + if(map->size > 0) + { + ALsizei pos = 0; + ALsizei count = map->size; + do { + ALsizei step = count>>1; + ALsizei i = pos+step; + if(map->keys[i] >= key) + count = step; + else + { + pos = i+1; + count -= step+1; + } + } while(count > 0); + if(pos < map->size && map->keys[pos] == key) + ret = map->values[pos]; + } + ReadUnlock(&map->lock); + return ret; +} -- cgit v1.2.3 From e75e0a342ecb78a47bebe0b7f5124dfb83c56f32 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 Oct 2018 07:30:46 -0700 Subject: Use C++ atomics and mutexes in the router --- router/al.cpp | 26 +++++----- router/alc.cpp | 142 ++++++++++++++++++++++++++---------------------------- router/router.cpp | 6 +-- router/router.h | 11 ++--- 4 files changed, 86 insertions(+), 99 deletions(-) diff --git a/router/al.cpp b/router/al.cpp index 1b4f413f..4c8b0006 100644 --- a/router/al.cpp +++ b/router/al.cpp @@ -7,36 +7,36 @@ #include "router.h" -atomic_DriverIfacePtr CurrentCtxDriver = ATOMIC_INIT_STATIC(NULL); +std::atomic CurrentCtxDriver{nullptr}; #define DECL_THUNK1(R,n,T1) AL_API R AL_APIENTRY n(T1 a) \ { \ - DriverIface *iface = reinterpret_cast(altss_get(ThreadCtxDriver));\ - if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ + DriverIface *iface = ThreadCtxDriver; \ + if(!iface) iface = CurrentCtxDriver.load(std::memory_order_acquire); \ return iface->n(a); \ } #define DECL_THUNK2(R,n,T1,T2) AL_API R AL_APIENTRY n(T1 a, T2 b) \ { \ - DriverIface *iface = reinterpret_cast(altss_get(ThreadCtxDriver));\ - if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ + DriverIface *iface = ThreadCtxDriver; \ + if(!iface) iface = CurrentCtxDriver.load(std::memory_order_acquire); \ return iface->n(a, b); \ } #define DECL_THUNK3(R,n,T1,T2,T3) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c) \ { \ - DriverIface *iface = reinterpret_cast(altss_get(ThreadCtxDriver));\ - if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ + DriverIface *iface = ThreadCtxDriver; \ + if(!iface) iface = CurrentCtxDriver.load(std::memory_order_acquire); \ return iface->n(a, b, c); \ } #define DECL_THUNK4(R,n,T1,T2,T3,T4) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c, T4 d) \ { \ - DriverIface *iface = reinterpret_cast(altss_get(ThreadCtxDriver));\ - if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ + DriverIface *iface = ThreadCtxDriver; \ + if(!iface) iface = CurrentCtxDriver.load(std::memory_order_acquire); \ return iface->n(a, b, c, d); \ } #define DECL_THUNK5(R,n,T1,T2,T3,T4,T5) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c, T4 d, T5 e) \ { \ - DriverIface *iface = reinterpret_cast(altss_get(ThreadCtxDriver));\ - if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ + DriverIface *iface = ThreadCtxDriver; \ + if(!iface) iface = CurrentCtxDriver.load(std::memory_order_acquire); \ return iface->n(a, b, c, d, e); \ } @@ -46,8 +46,8 @@ atomic_DriverIfacePtr CurrentCtxDriver = ATOMIC_INIT_STATIC(NULL); */ AL_API ALenum AL_APIENTRY alGetError(void) { - DriverIface *iface = reinterpret_cast(altss_get(ThreadCtxDriver)); - if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire); + DriverIface *iface = ThreadCtxDriver; + if(!iface) iface = CurrentCtxDriver.load(std::memory_order_acquire); return iface ? iface->alGetError() : AL_NO_ERROR; } diff --git a/router/alc.cpp b/router/alc.cpp index 36275440..b738f339 100644 --- a/router/alc.cpp +++ b/router/alc.cpp @@ -6,6 +6,8 @@ #include #include +#include + #include "AL/alc.h" #include "router.h" #include "almalloc.h" @@ -245,10 +247,10 @@ static const ALCint alcMajorVersion = 1; static const ALCint alcMinorVersion = 1; -static almtx_t EnumerationLock; -static almtx_t ContextSwitchLock; +static std::mutex EnumerationLock; +static std::mutex ContextSwitchLock; -static ATOMIC(ALCenum) LastError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); +static std::atomic LastError{ALC_NO_ERROR}; static PtrIntMap DeviceIfaceMap = PTRINTMAP_STATIC_INITIALIZE; static PtrIntMap ContextIfaceMap = PTRINTMAP_STATIC_INITIALIZE; @@ -330,8 +332,6 @@ static ALint GetDriverIndexForName(const EnumeratedList *list, const ALCchar *na void InitALC(void) { - almtx_init(&EnumerationLock, almtx_recursive); - almtx_init(&ContextSwitchLock, almtx_plain); } void ReleaseALC(void) @@ -342,9 +342,6 @@ void ReleaseALC(void) ResetPtrIntMap(&ContextIfaceMap); ResetPtrIntMap(&DeviceIfaceMap); - - almtx_destroy(&ContextSwitchLock); - almtx_destroy(&EnumerationLock); } @@ -364,20 +361,21 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) devicename = nullptr; if(devicename) { - almtx_lock(&EnumerationLock); - if(!DevicesList.Names) - (void)alcGetString(nullptr, ALC_DEVICE_SPECIFIER); - idx = GetDriverIndexForName(&DevicesList, devicename); - if(idx < 0) - { - if(!AllDevicesList.Names) - (void)alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER); - idx = GetDriverIndexForName(&AllDevicesList, devicename); + { std::lock_guard _{EnumerationLock}; + if(!DevicesList.Names) + (void)alcGetString(nullptr, ALC_DEVICE_SPECIFIER); + idx = GetDriverIndexForName(&DevicesList, devicename); + if(idx < 0) + { + if(!AllDevicesList.Names) + (void)alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER); + idx = GetDriverIndexForName(&AllDevicesList, devicename); + } } - almtx_unlock(&EnumerationLock); + if(idx < 0) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); + LastError.store(ALC_INVALID_VALUE); TRACE("Failed to find driver for name \"%s\"\n", devicename); return nullptr; } @@ -418,7 +416,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + LastError.store(ALC_INVALID_DEVICE); return ALC_FALSE; } if(!DriverList[idx].alcCloseDevice(device)) @@ -435,8 +433,8 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); - return ALC_FALSE; + LastError.store(ALC_INVALID_DEVICE); + return nullptr; } context = DriverList[idx].alcCreateContext(device, attrlist); if(context) @@ -455,21 +453,17 @@ ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) { ALint idx = -1; - almtx_lock(&ContextSwitchLock); + std::lock_guard _{ContextSwitchLock}; if(context) { idx = LookupPtrIntMapKey(&ContextIfaceMap, context); if(idx < 0) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); - almtx_unlock(&ContextSwitchLock); + LastError.store(ALC_INVALID_CONTEXT); return ALC_FALSE; } if(!DriverList[idx].alcMakeContextCurrent(context)) - { - almtx_unlock(&ContextSwitchLock); return ALC_FALSE; - } } /* Unset the context from the old driver if it's different from the new @@ -477,24 +471,21 @@ ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) */ if(idx < 0) { - DriverIface *oldiface = reinterpret_cast(altss_get(ThreadCtxDriver)); + DriverIface *oldiface = ThreadCtxDriver; if(oldiface) oldiface->alcSetThreadContext(nullptr); - oldiface = reinterpret_cast( - ATOMIC_EXCHANGE_PTR_SEQ(&CurrentCtxDriver, (DriverIface*){nullptr})); + oldiface = CurrentCtxDriver.exchange(nullptr); if(oldiface) oldiface->alcMakeContextCurrent(nullptr); } else { - DriverIface *oldiface = reinterpret_cast(altss_get(ThreadCtxDriver)); + DriverIface *oldiface = ThreadCtxDriver; if(oldiface && oldiface != &DriverList[idx]) oldiface->alcSetThreadContext(nullptr); - oldiface = reinterpret_cast( - ATOMIC_EXCHANGE_PTR_SEQ(&CurrentCtxDriver, &DriverList[idx])); + oldiface = CurrentCtxDriver.exchange(&DriverList[idx]); if(oldiface && oldiface != &DriverList[idx]) oldiface->alcMakeContextCurrent(nullptr); } - almtx_unlock(&ContextSwitchLock); - altss_set(ThreadCtxDriver, nullptr); + ThreadCtxDriver = nullptr; return ALC_TRUE; } @@ -507,7 +498,7 @@ ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context) if(idx >= 0) return DriverList[idx].alcProcessContext(context); } - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); + LastError.store(ALC_INVALID_CONTEXT); } ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context) @@ -518,7 +509,7 @@ ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context) if(idx >= 0) return DriverList[idx].alcSuspendContext(context); } - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); + LastError.store(ALC_INVALID_CONTEXT); } ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context) @@ -527,7 +518,7 @@ ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context) if(!context || (idx=LookupPtrIntMapKey(&ContextIfaceMap, context)) < 0) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); + LastError.store(ALC_INVALID_CONTEXT); return; } @@ -537,8 +528,8 @@ ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context) ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) { - DriverIface *iface = reinterpret_cast(altss_get(ThreadCtxDriver)); - if(!iface) iface = ATOMIC_LOAD_SEQ(&CurrentCtxDriver); + DriverIface *iface = ThreadCtxDriver; + if(!iface) iface = CurrentCtxDriver.load(); return iface ? iface->alcGetCurrentContext() : nullptr; } @@ -550,7 +541,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context) if(idx >= 0) return DriverList[idx].alcGetContextsDevice(context); } - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); + LastError.store(ALC_INVALID_CONTEXT); return nullptr; } @@ -563,7 +554,7 @@ ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) if(idx < 0) return ALC_INVALID_DEVICE; return DriverList[idx].alcGetError(device); } - return ATOMIC_EXCHANGE_SEQ(&LastError, ALC_NO_ERROR); + return LastError.exchange(ALC_NO_ERROR); } ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname) @@ -576,7 +567,7 @@ ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const A ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); if(idx < 0) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + LastError.store(ALC_INVALID_DEVICE); return ALC_FALSE; } return DriverList[idx].alcIsExtensionPresent(device, extname); @@ -607,7 +598,7 @@ ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *f ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); if(idx < 0) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + LastError.store(ALC_INVALID_DEVICE); return nullptr; } return DriverList[idx].alcGetProcAddress(device, funcname); @@ -630,7 +621,7 @@ ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *e ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); if(idx < 0) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + LastError.store(ALC_INVALID_DEVICE); return 0; } return DriverList[idx].alcGetEnumValue(device, enumname); @@ -653,7 +644,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); if(idx < 0) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + LastError.store(ALC_INVALID_DEVICE); return nullptr; } return DriverList[idx].alcGetString(device, param); @@ -677,7 +668,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para return alcExtensionList; case ALC_DEVICE_SPECIFIER: - almtx_lock(&EnumerationLock); + { std::lock_guard _{EnumerationLock}; ClearDeviceList(&DevicesList); for(i = 0;i < DriverListSize;i++) { @@ -688,11 +679,11 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para DriverList[i].alcGetString(nullptr, ALC_DEVICE_SPECIFIER), i ); } - almtx_unlock(&EnumerationLock); return DevicesList.Names; + } case ALC_ALL_DEVICES_SPECIFIER: - almtx_lock(&EnumerationLock); + { std::lock_guard _{EnumerationLock}; ClearDeviceList(&AllDevicesList); for(i = 0;i < DriverListSize;i++) { @@ -709,11 +700,11 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para DriverList[i].alcGetString(nullptr, ALC_DEVICE_SPECIFIER), i ); } - almtx_unlock(&EnumerationLock); return AllDevicesList.Names; + } case ALC_CAPTURE_DEVICE_SPECIFIER: - almtx_lock(&EnumerationLock); + { std::lock_guard _{EnumerationLock}; ClearDeviceList(&CaptureDevicesList); for(i = 0;i < DriverListSize;i++) { @@ -723,8 +714,8 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para DriverList[i].alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER), i ); } - almtx_unlock(&EnumerationLock); return CaptureDevicesList.Names; + } case ALC_DEFAULT_DEVICE_SPECIFIER: for(i = 0;i < DriverListSize;i++) @@ -753,7 +744,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para return ""; default: - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_ENUM); + LastError.store(ALC_INVALID_ENUM); break; } return nullptr; @@ -766,7 +757,7 @@ ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsi ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); if(idx < 0) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + LastError.store(ALC_INVALID_DEVICE); return; } return DriverList[idx].alcGetIntegerv(device, param, size, values); @@ -774,7 +765,7 @@ ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsi if(size <= 0 || values == nullptr) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); + LastError.store(ALC_INVALID_VALUE); return; } @@ -793,7 +784,7 @@ ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsi values[0] = alcMinorVersion; return; } - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); + LastError.store(ALC_INVALID_VALUE); return; case ALC_ATTRIBUTES_SIZE: @@ -804,11 +795,11 @@ ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsi case ALC_MONO_SOURCES: case ALC_STEREO_SOURCES: case ALC_CAPTURE_SAMPLES: - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + LastError.store(ALC_INVALID_DEVICE); return; default: - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_ENUM); + LastError.store(ALC_INVALID_ENUM); return; } } @@ -823,14 +814,15 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, devicename = nullptr; if(devicename) { - almtx_lock(&EnumerationLock); - if(!CaptureDevicesList.Names) - (void)alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER); - idx = GetDriverIndexForName(&CaptureDevicesList, devicename); - almtx_unlock(&EnumerationLock); + { std::lock_guard _{EnumerationLock}; + if(!CaptureDevicesList.Names) + (void)alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER); + idx = GetDriverIndexForName(&CaptureDevicesList, devicename); + } + if(idx < 0) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); + LastError.store(ALC_INVALID_VALUE); TRACE("Failed to find driver for name \"%s\"\n", devicename); return nullptr; } @@ -875,7 +867,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + LastError.store(ALC_INVALID_DEVICE); return ALC_FALSE; } if(!DriverList[idx].alcCaptureCloseDevice(device)) @@ -892,7 +884,7 @@ ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) if(idx >= 0) return DriverList[idx].alcCaptureStart(device); } - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + LastError.store(ALC_INVALID_DEVICE); } ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) @@ -903,7 +895,7 @@ ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) if(idx >= 0) return DriverList[idx].alcCaptureStop(device); } - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + LastError.store(ALC_INVALID_DEVICE); } ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) @@ -914,7 +906,7 @@ ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, if(idx >= 0) return DriverList[idx].alcCaptureSamples(device, buffer, samples); } - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + LastError.store(ALC_INVALID_DEVICE); } @@ -925,10 +917,10 @@ ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) if(!context) { - DriverIface *oldiface = reinterpret_cast(altss_get(ThreadCtxDriver)); + DriverIface *oldiface = ThreadCtxDriver; if(oldiface && !oldiface->alcSetThreadContext(nullptr)) return ALC_FALSE; - altss_set(ThreadCtxDriver, nullptr); + ThreadCtxDriver = nullptr; return ALC_TRUE; } @@ -937,23 +929,23 @@ ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) { if(DriverList[idx].alcSetThreadContext(context)) { - DriverIface *oldiface = reinterpret_cast(altss_get(ThreadCtxDriver)); + DriverIface *oldiface = ThreadCtxDriver; if(oldiface != &DriverList[idx]) { - altss_set(ThreadCtxDriver, &DriverList[idx]); + ThreadCtxDriver = &DriverList[idx]; if(oldiface) oldiface->alcSetThreadContext(nullptr); } return ALC_TRUE; } err = DriverList[idx].alcGetError(nullptr); } - ATOMIC_STORE_SEQ(&LastError, err); + LastError.store(err); return ALC_FALSE; } ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) { - DriverIface *iface = reinterpret_cast(altss_get(ThreadCtxDriver)); + DriverIface *iface = ThreadCtxDriver; if(iface) return iface->alcGetThreadContext(); return nullptr; } diff --git a/router/router.cpp b/router/router.cpp index 13cd3c69..95c0101d 100644 --- a/router/router.cpp +++ b/router/router.cpp @@ -18,7 +18,7 @@ DriverIface *DriverList = nullptr; int DriverListSize = 0; static int DriverListSizeMax = 0; -altss_t ThreadCtxDriver; +thread_local DriverIface *ThreadCtxDriver; enum LogLevel LogLevel = LogLevel_Error; FILE *LogFile; @@ -59,19 +59,16 @@ BOOL APIENTRY DllMain(HINSTANCE UNUSED(module), DWORD reason, void* UNUSED(reser TRACE("Initializing router v0.1-%s %s\n", ALSOFT_GIT_COMMIT_HASH, ALSOFT_GIT_BRANCH); LoadDriverList(); - altss_create(&ThreadCtxDriver, nullptr); InitALC(); break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: - althrd_thread_detach(); break; case DLL_PROCESS_DETACH: ReleaseALC(); - altss_delete(ThreadCtxDriver); for(i = 0;i < DriverListSize;i++) { @@ -87,7 +84,6 @@ BOOL APIENTRY DllMain(HINSTANCE UNUSED(module), DWORD reason, void* UNUSED(reser fclose(LogFile); LogFile = nullptr; - althrd_deinit(); break; } return TRUE; diff --git a/router/router.h b/router/router.h index 36c825d4..1a86da02 100644 --- a/router/router.h +++ b/router/router.h @@ -7,12 +7,12 @@ #include +#include + #include "AL/alc.h" #include "AL/al.h" #include "AL/alext.h" -#include "atomic.h" #include "rwlock.h" -#include "threads.h" #ifdef __cplusplus @@ -140,9 +140,8 @@ typedef struct DriverIface { extern DriverIface *DriverList; extern int DriverListSize; -extern altss_t ThreadCtxDriver; -typedef ATOMIC(DriverIface*) atomic_DriverIfacePtr; -extern atomic_DriverIfacePtr CurrentCtxDriver; +extern thread_local DriverIface *ThreadCtxDriver; +extern std::atomic CurrentCtxDriver; typedef struct PtrIntMap { @@ -154,7 +153,7 @@ typedef struct PtrIntMap { ALsizei capacity; RWLock lock; } PtrIntMap; -#define PTRINTMAP_STATIC_INITIALIZE { NULL, NULL, 0, 0, RWLOCK_STATIC_INITIALIZE } +#define PTRINTMAP_STATIC_INITIALIZE { nullptr, nullptr, 0, 0, RWLOCK_STATIC_INITIALIZE } void InitPtrIntMap(PtrIntMap *map); void ResetPtrIntMap(PtrIntMap *map); -- cgit v1.2.3 From c17e59f63ae6f6d49f913d446e66812b9912da3e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 Oct 2018 08:33:40 -0700 Subject: Use std::vector instead of custom dynamic arrays --- router/alc.cpp | 211 +++++++++++++++++++++++++++--------------------------- router/router.cpp | 57 +++++---------- router/router.h | 4 +- 3 files changed, 123 insertions(+), 149 deletions(-) diff --git a/router/alc.cpp b/router/alc.cpp index b738f339..ea2e340c 100644 --- a/router/alc.cpp +++ b/router/alc.cpp @@ -7,10 +7,10 @@ #include #include +#include #include "AL/alc.h" #include "router.h" -#include "almalloc.h" #define COUNTOF(x) (sizeof(x)/sizeof(x[0])) @@ -256,69 +256,45 @@ static PtrIntMap ContextIfaceMap = PTRINTMAP_STATIC_INITIALIZE; typedef struct EnumeratedList { - ALCchar *Names; - ALCchar *NamesEnd; - ALCint *Indicies; - ALCsizei IndexSize; -} EnumeratedList; -static EnumeratedList DevicesList = { nullptr, nullptr, nullptr, 0 }; -static EnumeratedList AllDevicesList = { nullptr, nullptr, nullptr, 0 }; -static EnumeratedList CaptureDevicesList = { nullptr, nullptr, nullptr, 0 }; - -static void ClearDeviceList(EnumeratedList *list) -{ - al_free(list->Names); - list->Names = nullptr; - list->NamesEnd = nullptr; + std::vector Names; + std::vector Indicies; - al_free(list->Indicies); - list->Indicies = nullptr; - list->IndexSize = 0; -} + void clear() + { + Names.clear(); + Indicies.clear(); + } +} EnumeratedList; +static EnumeratedList DevicesList; +static EnumeratedList AllDevicesList; +static EnumeratedList CaptureDevicesList; static void AppendDeviceList(EnumeratedList *list, const ALCchar *names, ALint idx) { const ALCchar *name_end = names; - ALCsizei count = 0; - ALCchar *new_list; - ALCint *new_indicies; - size_t len; - ALCsizei i; + if(!name_end) return; - if(!name_end) - return; + ALCsizei count = 0; while(*name_end) { TRACE("Enumerated \"%s\", driver %d\n", name_end, idx); - count++; + ++count; name_end += strlen(name_end)+1; } if(names == name_end) return; - len = (list->NamesEnd - list->Names) + (name_end - names); - new_list = reinterpret_cast(al_calloc(DEF_ALIGN, len + 1)); - memcpy(new_list, list->Names, list->NamesEnd - list->Names); - memcpy(new_list + (list->NamesEnd - list->Names), names, name_end - names); - al_free(list->Names); - list->Names = new_list; - list->NamesEnd = list->Names + len; - - new_indicies = reinterpret_cast( - al_calloc(16, sizeof(ALCint)*(list->IndexSize + count))); - for(i = 0;i < list->IndexSize;i++) - new_indicies[i] = list->Indicies[i]; - for(i = 0;i < count;i++) - new_indicies[list->IndexSize+i] = idx; - al_free(list->Indicies); - list->Indicies = new_indicies; - list->IndexSize += count; + list->Names.reserve(list->Names.size() + (name_end - names) + 1); + list->Names.insert(list->Names.cend(), names, name_end); + + list->Indicies.reserve(list->Indicies.size() + count); + list->Indicies.insert(list->Indicies.cend(), count, idx); } static ALint GetDriverIndexForName(const EnumeratedList *list, const ALCchar *name) { - const ALCchar *devnames = list->Names; - const ALCint *index = list->Indicies; + const ALCchar *devnames = list->Names.data(); + const ALCint *index = list->Indicies.data(); while(devnames && *devnames) { @@ -336,10 +312,6 @@ void InitALC(void) void ReleaseALC(void) { - ClearDeviceList(&DevicesList); - ClearDeviceList(&AllDevicesList); - ClearDeviceList(&CaptureDevicesList); - ResetPtrIntMap(&ContextIfaceMap); ResetPtrIntMap(&DeviceIfaceMap); } @@ -348,7 +320,7 @@ void ReleaseALC(void) ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) { ALCdevice *device = nullptr; - ALint idx; + ALint idx = 0; /* Prior to the enumeration extension, apps would hardcode these names as a * quality hint for the wrapper driver. Ignore them since there's no sane @@ -362,12 +334,12 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) if(devicename) { { std::lock_guard _{EnumerationLock}; - if(!DevicesList.Names) + if(DevicesList.Names.empty()) (void)alcGetString(nullptr, ALC_DEVICE_SPECIFIER); idx = GetDriverIndexForName(&DevicesList, devicename); if(idx < 0) { - if(!AllDevicesList.Names) + if(AllDevicesList.Names.empty()) (void)alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER); idx = GetDriverIndexForName(&AllDevicesList, devicename); } @@ -384,17 +356,16 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) } else { - int i; - for(i = 0;i < DriverListSize;i++) + for(const auto &drv : DriverList) { - if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || - DriverList[i].alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) + if(drv.ALCVer >= MAKE_ALC_VER(1, 1) || + drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) { - idx = i; TRACE("Using default device from driver %d\n", idx); - device = DriverList[idx].alcOpenDevice(nullptr); + device = drv.alcOpenDevice(nullptr); break; } + ++idx; } } @@ -637,8 +608,6 @@ ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *e ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param) { - ALsizei i = 0; - if(device) { ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); @@ -669,79 +638,110 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para case ALC_DEVICE_SPECIFIER: { std::lock_guard _{EnumerationLock}; - ClearDeviceList(&DevicesList); - for(i = 0;i < DriverListSize;i++) + DevicesList.clear(); + ALint idx = 0; + for(const auto &drv : DriverList) { /* Only enumerate names from drivers that support it. */ - if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || - DriverList[i].alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) + if(drv.ALCVer >= MAKE_ALC_VER(1, 1) || + drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) AppendDeviceList(&DevicesList, - DriverList[i].alcGetString(nullptr, ALC_DEVICE_SPECIFIER), i + drv.alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx ); + idx++; } - return DevicesList.Names; + /* Ensure the list is double-null termianted. */ + if(DevicesList.Names.empty()) + DevicesList.Names.emplace_back(0); + DevicesList.Names.emplace_back(0); + return DevicesList.Names.data(); } case ALC_ALL_DEVICES_SPECIFIER: { std::lock_guard _{EnumerationLock}; - ClearDeviceList(&AllDevicesList); - for(i = 0;i < DriverListSize;i++) + AllDevicesList.clear(); + ALint idx = 0; + for(const auto &drv : DriverList) { /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute * standard enumeration. */ - if(DriverList[i].alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT")) + if(drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT")) AppendDeviceList(&AllDevicesList, - DriverList[i].alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER), i + drv.alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER), idx ); - else if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || - DriverList[i].alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) + else if(drv.ALCVer >= MAKE_ALC_VER(1, 1) || + drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) AppendDeviceList(&AllDevicesList, - DriverList[i].alcGetString(nullptr, ALC_DEVICE_SPECIFIER), i + drv.alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx ); + ++idx; } - return AllDevicesList.Names; + /* Ensure the list is double-null termianted. */ + if(AllDevicesList.Names.empty()) + AllDevicesList.Names.emplace_back(0); + AllDevicesList.Names.emplace_back(0); + return AllDevicesList.Names.data(); } case ALC_CAPTURE_DEVICE_SPECIFIER: { std::lock_guard _{EnumerationLock}; - ClearDeviceList(&CaptureDevicesList); - for(i = 0;i < DriverListSize;i++) + CaptureDevicesList.clear(); + ALint idx = 0; + for(const auto &drv : DriverList) { - if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || - DriverList[i].alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE")) + if(drv.ALCVer >= MAKE_ALC_VER(1, 1) || + drv.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE")) AppendDeviceList(&CaptureDevicesList, - DriverList[i].alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER), i + drv.alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER), idx ); + ++idx; } - return CaptureDevicesList.Names; + /* Ensure the list is double-null termianted. */ + if(CaptureDevicesList.Names.empty()) + CaptureDevicesList.Names.emplace_back(0); + CaptureDevicesList.Names.emplace_back(0); + return CaptureDevicesList.Names.data(); } case ALC_DEFAULT_DEVICE_SPECIFIER: - for(i = 0;i < DriverListSize;i++) - { - if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || - DriverList[i].alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) - return DriverList[i].alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER); - } + { + auto drv = std::find_if(DriverList.cbegin(), DriverList.cend(), + [](const DriverIface &drv) -> bool + { + return drv.ALCVer >= MAKE_ALC_VER(1, 1) || + drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"); + } + ); + if(drv != DriverList.cend()) + return drv->alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER); return ""; + } case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: - for(i = 0;i < DriverListSize;i++) - { - if(DriverList[i].alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT")) - return DriverList[i].alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER); - } + { + auto drv = std::find_if(DriverList.cbegin(), DriverList.cend(), + [](const DriverIface &drv) -> bool + { return drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT"); } + ); + if(drv != DriverList.cend()) + return drv->alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER); return ""; + } case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: - for(i = 0;i < DriverListSize;i++) - { - if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || - DriverList[i].alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE")) - return DriverList[i].alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); - } + { + auto drv = std::find_if(DriverList.cbegin(), DriverList.cend(), + [](const DriverIface &drv) -> bool + { + return drv.ALCVer >= MAKE_ALC_VER(1, 1) || + drv.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"); + } + ); + if(drv != DriverList.cend()) + return drv->alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); return ""; + } default: LastError.store(ALC_INVALID_ENUM); @@ -808,14 +808,14 @@ ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsi ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize) { ALCdevice *device = nullptr; - ALint idx; + ALint idx = 0; if(devicename && devicename[0] == '\0') devicename = nullptr; if(devicename) { { std::lock_guard _{EnumerationLock}; - if(!CaptureDevicesList.Names) + if(CaptureDevicesList.Names.empty()) (void)alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER); idx = GetDriverIndexForName(&CaptureDevicesList, devicename); } @@ -833,19 +833,18 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, } else { - int i; - for(i = 0;i < DriverListSize;i++) + for(const auto &drv : DriverList) { - if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || - DriverList[i].alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE")) + if(drv.ALCVer >= MAKE_ALC_VER(1, 1) || + drv.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE")) { - idx = i; TRACE("Using default capture device from driver %d\n", idx); - device = DriverList[idx].alcCaptureOpenDevice( + device = drv.alcCaptureOpenDevice( nullptr, frequency, format, buffersize ); break; } + ++idx; } } diff --git a/router/router.cpp b/router/router.cpp index 95c0101d..4d0cf5a5 100644 --- a/router/router.cpp +++ b/router/router.cpp @@ -13,10 +13,7 @@ #include "version.h" - -DriverIface *DriverList = nullptr; -int DriverListSize = 0; -static int DriverListSizeMax = 0; +std::vector DriverList; thread_local DriverIface *ThreadCtxDriver; @@ -29,7 +26,6 @@ static void LoadDriverList(void); BOOL APIENTRY DllMain(HINSTANCE UNUSED(module), DWORD reason, void* UNUSED(reserved)) { const char *str; - int i; switch(reason) { @@ -70,15 +66,12 @@ BOOL APIENTRY DllMain(HINSTANCE UNUSED(module), DWORD reason, void* UNUSED(reser case DLL_PROCESS_DETACH: ReleaseALC(); - for(i = 0;i < DriverListSize;i++) + for(auto &drv : DriverList) { - if(DriverList[i].Module) - FreeLibrary(DriverList[i].Module); + if(drv.Module) + FreeLibrary(drv.Module); } - al_free(DriverList); - DriverList = nullptr; - DriverListSize = 0; - DriverListSizeMax = 0; + DriverList.clear(); if(LogFile && LogFile != stderr) fclose(LogFile); @@ -90,27 +83,17 @@ BOOL APIENTRY DllMain(HINSTANCE UNUSED(module), DWORD reason, void* UNUSED(reser } -#ifdef __GNUC__ -#define CAST_FUNC(x) (__typeof(x)) -#else -#define CAST_FUNC(x) (void*) -#endif - static void AddModule(HMODULE module, const WCHAR *name) { - DriverIface newdrv; - int err = 0; - int i; - - for(i = 0;i < DriverListSize;i++) + for(auto &drv : DriverList) { - if(DriverList[i].Module == module) + if(drv.Module == module) { TRACE("Skipping already-loaded module %p\n", module); FreeLibrary(module); return; } - if(wcscmp(DriverList[i].Name, name) == 0) + if(wcscmp(drv.Name, name) == 0) { TRACE("Skipping similarly-named module %ls\n", name); FreeLibrary(module); @@ -118,20 +101,11 @@ static void AddModule(HMODULE module, const WCHAR *name) } } - if(DriverListSize == DriverListSizeMax) - { - int newmax = DriverListSizeMax ? DriverListSizeMax<<1 : 4; - void *newlist = al_calloc(DEF_ALIGN, sizeof(DriverList[0])*newmax); - if(!newlist) return; - - memcpy(newlist, DriverList, DriverListSize*sizeof(DriverList[0])); - al_free(DriverList); - DriverList = reinterpret_cast(newlist); - DriverListSizeMax = newmax; - } + DriverList.emplace_back(); + DriverIface &newdrv = DriverList.back(); - memset(&newdrv, 0, sizeof(newdrv)); /* Load required functions. */ + int err = 0; #define LOAD_PROC(x) do { \ newdrv.x = reinterpret_cast( \ GetProcAddress(module, #x)); \ @@ -264,12 +238,13 @@ static void AddModule(HMODULE module, const WCHAR *name) } } - if(!err) + if(err) { - TRACE("Loaded module %p, %ls, ALC %d.%d\n", module, name, - newdrv.ALCVer>>8, newdrv.ALCVer&255); - DriverList[DriverListSize++] = newdrv; + DriverList.pop_back(); + return; } + TRACE("Loaded module %p, %ls, ALC %d.%d\n", module, name, + newdrv.ALCVer>>8, newdrv.ALCVer&255); #undef LOAD_PROC } diff --git a/router/router.h b/router/router.h index 1a86da02..c7d2c89e 100644 --- a/router/router.h +++ b/router/router.h @@ -7,6 +7,7 @@ #include +#include #include #include "AL/alc.h" @@ -137,8 +138,7 @@ typedef struct DriverIface { LPALDISTANCEMODEL alDistanceModel; } DriverIface; -extern DriverIface *DriverList; -extern int DriverListSize; +extern std::vector DriverList; extern thread_local DriverIface *ThreadCtxDriver; extern std::atomic CurrentCtxDriver; -- cgit v1.2.3 From ce212c911c8634fb9ccd9944b00dcd6c2b28d516 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 Oct 2018 09:24:39 -0700 Subject: Add a cmake option to static-link winpthread --- CMakeLists.txt | 47 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d483aa0a..076291e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -345,17 +345,19 @@ int main() }" HAVE_STATIC_LIBGCC_SWITCH ) - if(HAVE_STATIC_LIBGCC_SWITCH) - SET(LINKER_FLAGS ${LINKER_FLAGS} -static-libgcc) - endif() set(CMAKE_REQUIRED_LIBRARIES ${OLD_REQUIRED_LIBRARIES}) unset(OLD_REQUIRED_LIBRARIES) + + if(NOT HAVE_STATIC_LIBGCC_SWITCH) + message(FATAL_ERROR "Cannot static link libgcc") + endif() + set(LINKER_FLAGS ${LINKER_FLAGS} -static-libgcc) endif() - option(ALSOFT_STATIC_STDCXX "Static link libstdc++ with -static-libstdc++" OFF) + option(ALSOFT_STATIC_STDCXX "Static link libstdc++" OFF) if(ALSOFT_STATIC_STDCXX) set(OLD_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) - set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} -static-libstdc++) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} "-Wl,--push-state,-Bstatic,-lstdc++,--pop-state") check_cxx_source_compiles( "#include int main() @@ -364,11 +366,36 @@ int main() }" HAVE_STATIC_LIBSTDCXX_SWITCH ) - if(HAVE_STATIC_LIBSTDCXX_SWITCH) - SET(LINKER_FLAGS ${LINKER_FLAGS} -static-libstdc++) - endif() set(CMAKE_REQUIRED_LIBRARIES ${OLD_REQUIRED_LIBRARIES}) unset(OLD_REQUIRED_LIBRARIES) + + if(NOT HAVE_STATIC_LIBSTDCXX_SWITCH) + message(FATAL_ERROR "Cannot static link libstdc++") + endif() + set(LINKER_FLAGS ${LINKER_FLAGS} "-Wl,--push-state,-Bstatic,-lstdc++,--pop-state") + endif() + + if(WIN32) + option(ALSOFT_STATIC_WINPTHREAD "Static link libwinpthread" OFF) + if(ALSOFT_STATIC_WINPTHREAD) + set(OLD_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} "-Wl,--push-state,-Bstatic,-lwinpthread,--pop-state") + check_cxx_source_compiles( +"#include +int main() +{ + return 0; +}" + HAVE_STATIC_LIBWINPTHREAD_SWITCH + ) + set(CMAKE_REQUIRED_LIBRARIES ${OLD_REQUIRED_LIBRARIES}) + unset(OLD_REQUIRED_LIBRARIES) + + if(NOT HAVE_STATIC_LIBWINPTHREAD_SWITCH) + message(FATAL_ERROR "Cannot static link libwinpthread") + endif() + set(LINKER_FLAGS ${LINKER_FLAGS} "-Wl,--push-state,-Bstatic,-lwinpthread,--pop-state") + endif() endif() ENDIF() @@ -1437,7 +1464,7 @@ ELSE() TARGET_COMPILE_DEFINITIONS(OpenAL PRIVATE AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES ${CPP_DEFS}) TARGET_COMPILE_OPTIONS(OpenAL PRIVATE ${C_FLAGS} $<$:${CXX_FLAGS}>) - TARGET_LINK_LIBRARIES(OpenAL PRIVATE ${LINKER_FLAGS} ${COMMON_LIB}) + TARGET_LINK_LIBRARIES(OpenAL PRIVATE ${COMMON_LIB} ${LINKER_FLAGS}) SET_TARGET_PROPERTIES(OpenAL PROPERTIES PREFIX "") SET_TARGET_PROPERTIES(OpenAL PROPERTIES OUTPUT_NAME ${LIBNAME}) IF(TARGET build_version) @@ -1464,7 +1491,7 @@ TARGET_INCLUDE_DIRECTORIES(${IMPL_TARGET} PRIVATE "${OpenAL_SOURCE_DIR}/OpenAL32/Include" "${OpenAL_SOURCE_DIR}/Alc" ${INC_PATHS}) TARGET_COMPILE_OPTIONS(${IMPL_TARGET} PRIVATE ${C_FLAGS} $<$:${CXX_FLAGS}>) TARGET_LINK_LIBRARIES(${IMPL_TARGET} - PRIVATE ${LINKER_FLAGS} ${COMMON_LIB} ${EXTRA_LIBS} ${MATH_LIB}) + PRIVATE ${COMMON_LIB} ${LINKER_FLAGS} ${EXTRA_LIBS} ${MATH_LIB}) IF(TARGET build_version) ADD_DEPENDENCIES(${IMPL_TARGET} build_version) ENDIF() -- cgit v1.2.3 From e2a1dd4503be8cd1280be8d34826c4858c4d6ed2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 Oct 2018 09:31:52 -0700 Subject: Use std::wstring in place of some fixed WCHAR arrays --- router/router.cpp | 25 ++++--- router/router.h | 203 +++++++++++++++++++++++++++--------------------------- 2 files changed, 114 insertions(+), 114 deletions(-) diff --git a/router/router.cpp b/router/router.cpp index 4d0cf5a5..38d00e27 100644 --- a/router/router.cpp +++ b/router/router.cpp @@ -93,7 +93,7 @@ static void AddModule(HMODULE module, const WCHAR *name) FreeLibrary(module); return; } - if(wcscmp(drv.Name, name) == 0) + if(drv.Name == name) { TRACE("Skipping similarly-named module %ls\n", name); FreeLibrary(module); @@ -212,7 +212,7 @@ static void AddModule(HMODULE module, const WCHAR *name) if(!err) { ALCint alc_ver[2] = { 0, 0 }; - wcsncpy(newdrv.Name, name, 32); + newdrv.Name = name; newdrv.Module = module; newdrv.alcGetIntegerv(nullptr, ALC_MAJOR_VERSION, 1, &alc_ver[0]); newdrv.alcGetIntegerv(nullptr, ALC_MINOR_VERSION, 1, &alc_ver[1]); @@ -250,27 +250,26 @@ static void AddModule(HMODULE module, const WCHAR *name) static void SearchDrivers(WCHAR *path) { - WCHAR srchPath[MAX_PATH+1] = L""; WIN32_FIND_DATAW fdata; - HANDLE srchHdl; TRACE("Searching for drivers in %ls...\n", path); - wcsncpy(srchPath, path, MAX_PATH); - wcsncat(srchPath, L"\\*oal.dll", MAX_PATH - lstrlenW(srchPath)); - srchHdl = FindFirstFileW(srchPath, &fdata); + std::wstring srchPath = path; + srchPath += L"\\*oal.dll"; + + HANDLE srchHdl = FindFirstFileW(srchPath.c_str(), &fdata); if(srchHdl != INVALID_HANDLE_VALUE) { do { HMODULE mod; - wcsncpy(srchPath, path, MAX_PATH); - wcsncat(srchPath, L"\\", MAX_PATH - lstrlenW(srchPath)); - wcsncat(srchPath, fdata.cFileName, MAX_PATH - lstrlenW(srchPath)); - TRACE("Found %ls\n", srchPath); + srchPath = path; + srchPath += L"\\"; + srchPath += fdata.cFileName; + TRACE("Found %ls\n", srchPath.c_str()); - mod = LoadLibraryW(srchPath); + mod = LoadLibraryW(srchPath.c_str()); if(!mod) - WARN("Could not load %ls\n", srchPath); + WARN("Could not load %ls\n", srchPath.c_str()); else AddModule(mod, fdata.cFileName); } while(FindNextFileW(srchHdl, &fdata)); diff --git a/router/router.h b/router/router.h index c7d2c89e..3ac0ab40 100644 --- a/router/router.h +++ b/router/router.h @@ -9,6 +9,7 @@ #include #include +#include #include "AL/alc.h" #include "AL/al.h" @@ -35,107 +36,107 @@ extern "C" { #define MAKE_ALC_VER(major, minor) (((major)<<8) | (minor)) typedef struct DriverIface { - WCHAR Name[32]; - HMODULE Module; - int ALCVer; - - LPALCCREATECONTEXT alcCreateContext; - LPALCMAKECONTEXTCURRENT alcMakeContextCurrent; - LPALCPROCESSCONTEXT alcProcessContext; - LPALCSUSPENDCONTEXT alcSuspendContext; - LPALCDESTROYCONTEXT alcDestroyContext; - LPALCGETCURRENTCONTEXT alcGetCurrentContext; - LPALCGETCONTEXTSDEVICE alcGetContextsDevice; - LPALCOPENDEVICE alcOpenDevice; - LPALCCLOSEDEVICE alcCloseDevice; - LPALCGETERROR alcGetError; - LPALCISEXTENSIONPRESENT alcIsExtensionPresent; - LPALCGETPROCADDRESS alcGetProcAddress; - LPALCGETENUMVALUE alcGetEnumValue; - LPALCGETSTRING alcGetString; - LPALCGETINTEGERV alcGetIntegerv; - LPALCCAPTUREOPENDEVICE alcCaptureOpenDevice; - LPALCCAPTURECLOSEDEVICE alcCaptureCloseDevice; - LPALCCAPTURESTART alcCaptureStart; - LPALCCAPTURESTOP alcCaptureStop; - LPALCCAPTURESAMPLES alcCaptureSamples; - - PFNALCSETTHREADCONTEXTPROC alcSetThreadContext; - PFNALCGETTHREADCONTEXTPROC alcGetThreadContext; - - LPALENABLE alEnable; - LPALDISABLE alDisable; - LPALISENABLED alIsEnabled; - LPALGETSTRING alGetString; - LPALGETBOOLEANV alGetBooleanv; - LPALGETINTEGERV alGetIntegerv; - LPALGETFLOATV alGetFloatv; - LPALGETDOUBLEV alGetDoublev; - LPALGETBOOLEAN alGetBoolean; - LPALGETINTEGER alGetInteger; - LPALGETFLOAT alGetFloat; - LPALGETDOUBLE alGetDouble; - LPALGETERROR alGetError; - LPALISEXTENSIONPRESENT alIsExtensionPresent; - LPALGETPROCADDRESS alGetProcAddress; - LPALGETENUMVALUE alGetEnumValue; - LPALLISTENERF alListenerf; - LPALLISTENER3F alListener3f; - LPALLISTENERFV alListenerfv; - LPALLISTENERI alListeneri; - LPALLISTENER3I alListener3i; - LPALLISTENERIV alListeneriv; - LPALGETLISTENERF alGetListenerf; - LPALGETLISTENER3F alGetListener3f; - LPALGETLISTENERFV alGetListenerfv; - LPALGETLISTENERI alGetListeneri; - LPALGETLISTENER3I alGetListener3i; - LPALGETLISTENERIV alGetListeneriv; - LPALGENSOURCES alGenSources; - LPALDELETESOURCES alDeleteSources; - LPALISSOURCE alIsSource; - LPALSOURCEF alSourcef; - LPALSOURCE3F alSource3f; - LPALSOURCEFV alSourcefv; - LPALSOURCEI alSourcei; - LPALSOURCE3I alSource3i; - LPALSOURCEIV alSourceiv; - LPALGETSOURCEF alGetSourcef; - LPALGETSOURCE3F alGetSource3f; - LPALGETSOURCEFV alGetSourcefv; - LPALGETSOURCEI alGetSourcei; - LPALGETSOURCE3I alGetSource3i; - LPALGETSOURCEIV alGetSourceiv; - LPALSOURCEPLAYV alSourcePlayv; - LPALSOURCESTOPV alSourceStopv; - LPALSOURCEREWINDV alSourceRewindv; - LPALSOURCEPAUSEV alSourcePausev; - LPALSOURCEPLAY alSourcePlay; - LPALSOURCESTOP alSourceStop; - LPALSOURCEREWIND alSourceRewind; - LPALSOURCEPAUSE alSourcePause; - LPALSOURCEQUEUEBUFFERS alSourceQueueBuffers; - LPALSOURCEUNQUEUEBUFFERS alSourceUnqueueBuffers; - LPALGENBUFFERS alGenBuffers; - LPALDELETEBUFFERS alDeleteBuffers; - LPALISBUFFER alIsBuffer; - LPALBUFFERF alBufferf; - LPALBUFFER3F alBuffer3f; - LPALBUFFERFV alBufferfv; - LPALBUFFERI alBufferi; - LPALBUFFER3I alBuffer3i; - LPALBUFFERIV alBufferiv; - LPALGETBUFFERF alGetBufferf; - LPALGETBUFFER3F alGetBuffer3f; - LPALGETBUFFERFV alGetBufferfv; - LPALGETBUFFERI alGetBufferi; - LPALGETBUFFER3I alGetBuffer3i; - LPALGETBUFFERIV alGetBufferiv; - LPALBUFFERDATA alBufferData; - LPALDOPPLERFACTOR alDopplerFactor; - LPALDOPPLERVELOCITY alDopplerVelocity; - LPALSPEEDOFSOUND alSpeedOfSound; - LPALDISTANCEMODEL alDistanceModel; + std::wstring Name; + HMODULE Module{nullptr}; + int ALCVer{0}; + + LPALCCREATECONTEXT alcCreateContext{nullptr}; + LPALCMAKECONTEXTCURRENT alcMakeContextCurrent{nullptr}; + LPALCPROCESSCONTEXT alcProcessContext{nullptr}; + LPALCSUSPENDCONTEXT alcSuspendContext{nullptr}; + LPALCDESTROYCONTEXT alcDestroyContext{nullptr}; + LPALCGETCURRENTCONTEXT alcGetCurrentContext{nullptr}; + LPALCGETCONTEXTSDEVICE alcGetContextsDevice{nullptr}; + LPALCOPENDEVICE alcOpenDevice{nullptr}; + LPALCCLOSEDEVICE alcCloseDevice{nullptr}; + LPALCGETERROR alcGetError{nullptr}; + LPALCISEXTENSIONPRESENT alcIsExtensionPresent{nullptr}; + LPALCGETPROCADDRESS alcGetProcAddress{nullptr}; + LPALCGETENUMVALUE alcGetEnumValue{nullptr}; + LPALCGETSTRING alcGetString{nullptr}; + LPALCGETINTEGERV alcGetIntegerv{nullptr}; + LPALCCAPTUREOPENDEVICE alcCaptureOpenDevice{nullptr}; + LPALCCAPTURECLOSEDEVICE alcCaptureCloseDevice{nullptr}; + LPALCCAPTURESTART alcCaptureStart{nullptr}; + LPALCCAPTURESTOP alcCaptureStop{nullptr}; + LPALCCAPTURESAMPLES alcCaptureSamples{nullptr}; + + PFNALCSETTHREADCONTEXTPROC alcSetThreadContext{nullptr}; + PFNALCGETTHREADCONTEXTPROC alcGetThreadContext{nullptr}; + + LPALENABLE alEnable{nullptr}; + LPALDISABLE alDisable{nullptr}; + LPALISENABLED alIsEnabled{nullptr}; + LPALGETSTRING alGetString{nullptr}; + LPALGETBOOLEANV alGetBooleanv{nullptr}; + LPALGETINTEGERV alGetIntegerv{nullptr}; + LPALGETFLOATV alGetFloatv{nullptr}; + LPALGETDOUBLEV alGetDoublev{nullptr}; + LPALGETBOOLEAN alGetBoolean{nullptr}; + LPALGETINTEGER alGetInteger{nullptr}; + LPALGETFLOAT alGetFloat{nullptr}; + LPALGETDOUBLE alGetDouble{nullptr}; + LPALGETERROR alGetError{nullptr}; + LPALISEXTENSIONPRESENT alIsExtensionPresent{nullptr}; + LPALGETPROCADDRESS alGetProcAddress{nullptr}; + LPALGETENUMVALUE alGetEnumValue{nullptr}; + LPALLISTENERF alListenerf{nullptr}; + LPALLISTENER3F alListener3f{nullptr}; + LPALLISTENERFV alListenerfv{nullptr}; + LPALLISTENERI alListeneri{nullptr}; + LPALLISTENER3I alListener3i{nullptr}; + LPALLISTENERIV alListeneriv{nullptr}; + LPALGETLISTENERF alGetListenerf{nullptr}; + LPALGETLISTENER3F alGetListener3f{nullptr}; + LPALGETLISTENERFV alGetListenerfv{nullptr}; + LPALGETLISTENERI alGetListeneri{nullptr}; + LPALGETLISTENER3I alGetListener3i{nullptr}; + LPALGETLISTENERIV alGetListeneriv{nullptr}; + LPALGENSOURCES alGenSources{nullptr}; + LPALDELETESOURCES alDeleteSources{nullptr}; + LPALISSOURCE alIsSource{nullptr}; + LPALSOURCEF alSourcef{nullptr}; + LPALSOURCE3F alSource3f{nullptr}; + LPALSOURCEFV alSourcefv{nullptr}; + LPALSOURCEI alSourcei{nullptr}; + LPALSOURCE3I alSource3i{nullptr}; + LPALSOURCEIV alSourceiv{nullptr}; + LPALGETSOURCEF alGetSourcef{nullptr}; + LPALGETSOURCE3F alGetSource3f{nullptr}; + LPALGETSOURCEFV alGetSourcefv{nullptr}; + LPALGETSOURCEI alGetSourcei{nullptr}; + LPALGETSOURCE3I alGetSource3i{nullptr}; + LPALGETSOURCEIV alGetSourceiv{nullptr}; + LPALSOURCEPLAYV alSourcePlayv{nullptr}; + LPALSOURCESTOPV alSourceStopv{nullptr}; + LPALSOURCEREWINDV alSourceRewindv{nullptr}; + LPALSOURCEPAUSEV alSourcePausev{nullptr}; + LPALSOURCEPLAY alSourcePlay{nullptr}; + LPALSOURCESTOP alSourceStop{nullptr}; + LPALSOURCEREWIND alSourceRewind{nullptr}; + LPALSOURCEPAUSE alSourcePause{nullptr}; + LPALSOURCEQUEUEBUFFERS alSourceQueueBuffers{nullptr}; + LPALSOURCEUNQUEUEBUFFERS alSourceUnqueueBuffers{nullptr}; + LPALGENBUFFERS alGenBuffers{nullptr}; + LPALDELETEBUFFERS alDeleteBuffers{nullptr}; + LPALISBUFFER alIsBuffer{nullptr}; + LPALBUFFERF alBufferf{nullptr}; + LPALBUFFER3F alBuffer3f{nullptr}; + LPALBUFFERFV alBufferfv{nullptr}; + LPALBUFFERI alBufferi{nullptr}; + LPALBUFFER3I alBuffer3i{nullptr}; + LPALBUFFERIV alBufferiv{nullptr}; + LPALGETBUFFERF alGetBufferf{nullptr}; + LPALGETBUFFER3F alGetBuffer3f{nullptr}; + LPALGETBUFFERFV alGetBufferfv{nullptr}; + LPALGETBUFFERI alGetBufferi{nullptr}; + LPALGETBUFFER3I alGetBuffer3i{nullptr}; + LPALGETBUFFERIV alGetBufferiv{nullptr}; + LPALBUFFERDATA alBufferData{nullptr}; + LPALDOPPLERFACTOR alDopplerFactor{nullptr}; + LPALDOPPLERVELOCITY alDopplerVelocity{nullptr}; + LPALSPEEDOFSOUND alSpeedOfSound{nullptr}; + LPALDISTANCEMODEL alDistanceModel{nullptr}; } DriverIface; extern std::vector DriverList; -- cgit v1.2.3 From 44f91760b5d4d9c351100eb2b7b248309c6c32db Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 Oct 2018 10:00:27 -0700 Subject: Use std::array instead of raw arrays --- router/alc.cpp | 44 +++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/router/alc.cpp b/router/alc.cpp index ea2e340c..b90d9e41 100644 --- a/router/alc.cpp +++ b/router/alc.cpp @@ -13,13 +13,12 @@ #include "router.h" -#define COUNTOF(x) (sizeof(x)/sizeof(x[0])) - -#define DECL(x) { #x, (ALCvoid*)(x) } -static const struct { +#define DECL(x) { #x, reinterpret_cast(x) } +struct FuncExportEntry { const ALCchar *funcName; ALCvoid *address; -} alcFunctions[] = { +}; +static const std::array alcFunctions{{ DECL(alcCreateContext), DECL(alcMakeContextCurrent), DECL(alcProcessContext), @@ -117,14 +116,15 @@ static const struct { DECL(alDopplerVelocity), DECL(alSpeedOfSound), DECL(alDistanceModel), -}; +}}; #undef DECL #define DECL(x) { #x, (x) } -static const struct { +struct EnumExportEntry { const ALCchar *enumName; ALCenum value; -} alcEnumerations[] = { +}; +static const std::array alcEnumerations{{ DECL(ALC_INVALID), DECL(ALC_FALSE), DECL(ALC_TRUE), @@ -230,7 +230,7 @@ static const struct { DECL(AL_LINEAR_DISTANCE_CLAMPED), DECL(AL_EXPONENT_DISTANCE), DECL(AL_EXPONENT_DISTANCE_CLAMPED), -}; +}}; #undef DECL static const ALCchar alcNoError[] = "No Error"; @@ -562,8 +562,6 @@ ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const A ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname) { - size_t i; - if(device) { ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); @@ -575,18 +573,15 @@ ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *f return DriverList[idx].alcGetProcAddress(device, funcname); } - for(i = 0;i < COUNTOF(alcFunctions);i++) - { - if(strcmp(funcname, alcFunctions[i].funcName) == 0) - return alcFunctions[i].address; - } - return nullptr; + auto entry = std::find_if(alcFunctions.cbegin(), alcFunctions.cend(), + [funcname](const FuncExportEntry &entry) -> bool + { return strcmp(funcname, entry.funcName) == 0; } + ); + return (entry != alcFunctions.cend()) ? entry->address : nullptr; } ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname) { - size_t i; - if(device) { ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); @@ -598,12 +593,11 @@ ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *e return DriverList[idx].alcGetEnumValue(device, enumname); } - for(i = 0;i < COUNTOF(alcEnumerations);i++) - { - if(strcmp(enumname, alcEnumerations[i].enumName) == 0) - return alcEnumerations[i].value; - } - return 0; + auto entry = std::find_if(alcEnumerations.cbegin(), alcEnumerations.cend(), + [enumname](const EnumExportEntry &entry) -> bool + { return strcmp(enumname, entry.enumName) == 0; } + ); + return (entry != alcEnumerations.cend()) ? entry->value : 0; } ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param) -- cgit v1.2.3 From f747ac8882b6ca618fe28e1a4252f89cc3fa0d8c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 Oct 2018 13:47:01 -0700 Subject: Clean up the router's PtrIntMap --- router/alc.cpp | 62 +++++++++++--------------- router/router.cpp | 131 +++++++++++++++++++++++------------------------------- router/router.h | 40 +++++++---------- 3 files changed, 96 insertions(+), 137 deletions(-) diff --git a/router/alc.cpp b/router/alc.cpp index b90d9e41..343b792d 100644 --- a/router/alc.cpp +++ b/router/alc.cpp @@ -251,8 +251,8 @@ static std::mutex EnumerationLock; static std::mutex ContextSwitchLock; static std::atomic LastError{ALC_NO_ERROR}; -static PtrIntMap DeviceIfaceMap = PTRINTMAP_STATIC_INITIALIZE; -static PtrIntMap ContextIfaceMap = PTRINTMAP_STATIC_INITIALIZE; +static PtrIntMap DeviceIfaceMap; +static PtrIntMap ContextIfaceMap; typedef struct EnumeratedList { @@ -306,16 +306,6 @@ static ALint GetDriverIndexForName(const EnumeratedList *list, const ALCchar *na return -1; } -void InitALC(void) -{ -} - -void ReleaseALC(void) -{ - ResetPtrIntMap(&ContextIfaceMap); - ResetPtrIntMap(&DeviceIfaceMap); -} - ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) { @@ -371,7 +361,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) if(device) { - if(InsertPtrIntMapEntry(&DeviceIfaceMap, device, idx) != ALC_NO_ERROR) + if(DeviceIfaceMap.insert(device, idx) != ALC_NO_ERROR) { DriverList[idx].alcCloseDevice(device); device = nullptr; @@ -385,14 +375,14 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) { ALint idx; - if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0) + if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0) { LastError.store(ALC_INVALID_DEVICE); return ALC_FALSE; } if(!DriverList[idx].alcCloseDevice(device)) return ALC_FALSE; - RemovePtrIntMapKey(&DeviceIfaceMap, device); + DeviceIfaceMap.removeByKey(device); return ALC_TRUE; } @@ -402,7 +392,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ALCcontext *context; ALint idx; - if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0) + if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0) { LastError.store(ALC_INVALID_DEVICE); return nullptr; @@ -410,7 +400,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin context = DriverList[idx].alcCreateContext(device, attrlist); if(context) { - if(InsertPtrIntMapEntry(&ContextIfaceMap, context, idx) != ALC_NO_ERROR) + if(ContextIfaceMap.insert(context, idx) != ALC_NO_ERROR) { DriverList[idx].alcDestroyContext(context); context = nullptr; @@ -427,7 +417,7 @@ ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) std::lock_guard _{ContextSwitchLock}; if(context) { - idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + idx = ContextIfaceMap.lookupByKey(context); if(idx < 0) { LastError.store(ALC_INVALID_CONTEXT); @@ -465,7 +455,7 @@ ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context) { if(context) { - ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + ALint idx = ContextIfaceMap.lookupByKey(context); if(idx >= 0) return DriverList[idx].alcProcessContext(context); } @@ -476,7 +466,7 @@ ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context) { if(context) { - ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + ALint idx = ContextIfaceMap.lookupByKey(context); if(idx >= 0) return DriverList[idx].alcSuspendContext(context); } @@ -487,14 +477,14 @@ ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context) { ALint idx; - if(!context || (idx=LookupPtrIntMapKey(&ContextIfaceMap, context)) < 0) + if(!context || (idx=ContextIfaceMap.lookupByKey(context)) < 0) { LastError.store(ALC_INVALID_CONTEXT); return; } DriverList[idx].alcDestroyContext(context); - RemovePtrIntMapKey(&ContextIfaceMap, context); + ContextIfaceMap.removeByKey(context); } ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) @@ -508,7 +498,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context) { if(context) { - ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + ALint idx = ContextIfaceMap.lookupByKey(context); if(idx >= 0) return DriverList[idx].alcGetContextsDevice(context); } @@ -521,7 +511,7 @@ ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) { if(device) { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx < 0) return ALC_INVALID_DEVICE; return DriverList[idx].alcGetError(device); } @@ -535,7 +525,7 @@ ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const A if(device) { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx < 0) { LastError.store(ALC_INVALID_DEVICE); @@ -564,7 +554,7 @@ ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *f { if(device) { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx < 0) { LastError.store(ALC_INVALID_DEVICE); @@ -584,7 +574,7 @@ ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *e { if(device) { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx < 0) { LastError.store(ALC_INVALID_DEVICE); @@ -604,7 +594,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para { if(device) { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx < 0) { LastError.store(ALC_INVALID_DEVICE); @@ -748,7 +738,7 @@ ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsi { if(device) { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx < 0) { LastError.store(ALC_INVALID_DEVICE); @@ -844,7 +834,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, if(device) { - if(InsertPtrIntMapEntry(&DeviceIfaceMap, device, idx) != ALC_NO_ERROR) + if(DeviceIfaceMap.insert(device, idx) != ALC_NO_ERROR) { DriverList[idx].alcCaptureCloseDevice(device); device = nullptr; @@ -858,14 +848,14 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) { ALint idx; - if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0) + if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0) { LastError.store(ALC_INVALID_DEVICE); return ALC_FALSE; } if(!DriverList[idx].alcCaptureCloseDevice(device)) return ALC_FALSE; - RemovePtrIntMapKey(&DeviceIfaceMap, device); + DeviceIfaceMap.removeByKey(device); return ALC_TRUE; } @@ -873,7 +863,7 @@ ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) { if(device) { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx >= 0) return DriverList[idx].alcCaptureStart(device); } @@ -884,7 +874,7 @@ ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) { if(device) { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx >= 0) return DriverList[idx].alcCaptureStop(device); } @@ -895,7 +885,7 @@ ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, { if(device) { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx >= 0) return DriverList[idx].alcCaptureSamples(device, buffer, samples); } @@ -917,7 +907,7 @@ ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) return ALC_TRUE; } - idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + idx = ContextIfaceMap.lookupByKey(context); if(idx >= 0) { if(DriverList[idx].alcSetThreadContext(context)) diff --git a/router/router.cpp b/router/router.cpp index 38d00e27..049ac3bc 100644 --- a/router/router.cpp +++ b/router/router.cpp @@ -55,7 +55,6 @@ BOOL APIENTRY DllMain(HINSTANCE UNUSED(module), DWORD reason, void* UNUSED(reser TRACE("Initializing router v0.1-%s %s\n", ALSOFT_GIT_COMMIT_HASH, ALSOFT_GIT_BRANCH); LoadDriverList(); - InitALC(); break; case DLL_THREAD_ATTACH: @@ -64,8 +63,6 @@ BOOL APIENTRY DllMain(HINSTANCE UNUSED(module), DWORD reason, void* UNUSED(reser break; case DLL_PROCESS_DETACH: - ReleaseALC(); - for(auto &drv : DriverList) { if(drv.Module) @@ -360,38 +357,28 @@ void LoadDriverList(void) } -void InitPtrIntMap(PtrIntMap *map) -{ - map->keys = nullptr; - map->values = nullptr; - map->size = 0; - map->capacity = 0; - RWLockInit(&map->lock); -} - -void ResetPtrIntMap(PtrIntMap *map) +PtrIntMap::~PtrIntMap() { - WriteLock(&map->lock); - al_free(map->keys); - map->keys = nullptr; - map->values = nullptr; - map->size = 0; - map->capacity = 0; - WriteUnlock(&map->lock); + std::lock_guard maplock{mLock}; + al_free(mKeys); + mKeys = nullptr; + mValues = nullptr; + mSize = 0; + mCapacity = 0; } -ALenum InsertPtrIntMapEntry(PtrIntMap *map, ALvoid *key, ALint value) +ALenum PtrIntMap::insert(ALvoid *key, ALint value) { ALsizei pos = 0; - WriteLock(&map->lock); - if(map->size > 0) + std::lock_guard maplock{mLock}; + if(mSize > 0) { - ALsizei count = map->size; + ALsizei count = mSize; do { ALsizei step = count>>1; ALsizei i = pos+step; - if(map->keys[i] >= key) + if(mKeys[i] >= key) count = step; else { @@ -401,65 +388,60 @@ ALenum InsertPtrIntMapEntry(PtrIntMap *map, ALvoid *key, ALint value) } while(count > 0); } - if(pos == map->size || map->keys[pos] != key) + if(pos == mSize || mKeys[pos] != key) { - if(map->size == map->capacity) + if(mSize == mCapacity) { - ALvoid **keys = nullptr; - ALint *values; + ALvoid **newkeys = nullptr; + ALint *newvalues; ALsizei newcap; - newcap = (map->capacity ? (map->capacity<<1) : 4); - if(newcap > map->capacity) - keys = reinterpret_cast( - al_calloc(16, (sizeof(map->keys[0])+sizeof(map->values[0]))*newcap) + newcap = (mCapacity ? (mCapacity<<1) : 4); + if(newcap > mCapacity) + newkeys = reinterpret_cast( + al_calloc(16, (sizeof(mKeys[0])+sizeof(mValues[0]))*newcap) ); - if(!keys) - { - WriteUnlock(&map->lock); + if(!newkeys) return AL_OUT_OF_MEMORY; - } - values = (ALint*)&keys[newcap]; + newvalues = (ALint*)&newkeys[newcap]; - if(map->keys) + if(mKeys) { - memcpy(keys, map->keys, map->size*sizeof(map->keys[0])); - memcpy(values, map->values, map->size*sizeof(map->values[0])); + memcpy(newkeys, mKeys, mSize*sizeof(mKeys[0])); + memcpy(newvalues, mValues, mSize*sizeof(mValues[0])); } - al_free(map->keys); - map->keys = keys; - map->values = values; - map->capacity = newcap; + al_free(mKeys); + mKeys = newkeys; + mValues = newvalues; + mCapacity = newcap; } - if(pos < map->size) + if(pos < mSize) { - memmove(&map->keys[pos+1], &map->keys[pos], - (map->size-pos)*sizeof(map->keys[0])); - memmove(&map->values[pos+1], &map->values[pos], - (map->size-pos)*sizeof(map->values[0])); + memmove(&mKeys[pos+1], &mKeys[pos], (mSize-pos)*sizeof(mKeys[0])); + memmove(&mValues[pos+1], &mValues[pos], (mSize-pos)*sizeof(mValues[0])); } - map->size++; + mSize++; } - map->keys[pos] = key; - map->values[pos] = value; - WriteUnlock(&map->lock); + mKeys[pos] = key; + mValues[pos] = value; return AL_NO_ERROR; } -ALint RemovePtrIntMapKey(PtrIntMap *map, ALvoid *key) +ALint PtrIntMap::removeByKey(ALvoid *key) { ALint ret = -1; - WriteLock(&map->lock); - if(map->size > 0) + + std::lock_guard maplock{mLock}; + if(mSize > 0) { ALsizei pos = 0; - ALsizei count = map->size; + ALsizei count = mSize; do { ALsizei step = count>>1; ALsizei i = pos+step; - if(map->keys[i] >= key) + if(mKeys[i] >= key) count = step; else { @@ -467,35 +449,33 @@ ALint RemovePtrIntMapKey(PtrIntMap *map, ALvoid *key) count -= step+1; } } while(count > 0); - if(pos < map->size && map->keys[pos] == key) + if(pos < mSize && mKeys[pos] == key) { - ret = map->values[pos]; - if(pos < map->size-1) + ret = mValues[pos]; + if(pos < mSize-1) { - memmove(&map->keys[pos], &map->keys[pos+1], - (map->size-1-pos)*sizeof(map->keys[0])); - memmove(&map->values[pos], &map->values[pos+1], - (map->size-1-pos)*sizeof(map->values[0])); + memmove(&mKeys[pos], &mKeys[pos+1], (mSize-1-pos)*sizeof(mKeys[0])); + memmove(&mValues[pos], &mValues[pos+1], (mSize-1-pos)*sizeof(mValues[0])); } - map->size--; + mSize--; } } - WriteUnlock(&map->lock); return ret; } -ALint LookupPtrIntMapKey(PtrIntMap *map, ALvoid *key) +ALint PtrIntMap::lookupByKey(ALvoid* key) { ALint ret = -1; - ReadLock(&map->lock); - if(map->size > 0) + + std::lock_guard maplock{mLock}; + if(mSize > 0) { ALsizei pos = 0; - ALsizei count = map->size; + ALsizei count = mSize; do { ALsizei step = count>>1; ALsizei i = pos+step; - if(map->keys[i] >= key) + if(mKeys[i] >= key) count = step; else { @@ -503,9 +483,8 @@ ALint LookupPtrIntMapKey(PtrIntMap *map, ALvoid *key) count -= step+1; } } while(count > 0); - if(pos < map->size && map->keys[pos] == key) - ret = map->values[pos]; + if(pos < mSize && mKeys[pos] == key) + ret = mValues[pos]; } - ReadUnlock(&map->lock); return ret; } diff --git a/router/router.h b/router/router.h index 3ac0ab40..96db56ea 100644 --- a/router/router.h +++ b/router/router.h @@ -8,8 +8,9 @@ #include #include -#include #include +#include +#include #include "AL/alc.h" #include "AL/al.h" @@ -17,10 +18,6 @@ #include "rwlock.h" -#ifdef __cplusplus -extern "C" { -#endif - #ifndef UNUSED #if defined(__cplusplus) #define UNUSED(x) @@ -145,26 +142,23 @@ extern thread_local DriverIface *ThreadCtxDriver; extern std::atomic CurrentCtxDriver; -typedef struct PtrIntMap { - ALvoid **keys; +class PtrIntMap { + ALvoid **mKeys{nullptr}; /* Shares memory with keys. */ - ALint *values; + ALint *mValues{nullptr}; - ALsizei size; - ALsizei capacity; - RWLock lock; -} PtrIntMap; -#define PTRINTMAP_STATIC_INITIALIZE { nullptr, nullptr, 0, 0, RWLOCK_STATIC_INITIALIZE } + ALsizei mSize{0}; + ALsizei mCapacity{0}; + std::mutex mLock; -void InitPtrIntMap(PtrIntMap *map); -void ResetPtrIntMap(PtrIntMap *map); -ALenum InsertPtrIntMapEntry(PtrIntMap *map, ALvoid *key, ALint value); -ALint RemovePtrIntMapKey(PtrIntMap *map, ALvoid *key); -ALint LookupPtrIntMapKey(PtrIntMap *map, ALvoid *key); +public: + PtrIntMap() = default; + ~PtrIntMap(); - -void InitALC(void); -void ReleaseALC(void); + ALenum insert(ALvoid *key, ALint value); + ALint removeByKey(ALvoid *key); + ALint lookupByKey(ALvoid *key); +}; enum LogLevel { @@ -198,8 +192,4 @@ extern FILE *LogFile; } \ } while(0) -#ifdef __cplusplus -} // extern "C" -#endif - #endif /* ROUTER_ROUTER_H */ -- cgit v1.2.3 From 6a8f5e59508fb7f89a758edd8a70d6e61999ef1a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 Oct 2018 15:38:11 -0700 Subject: Build the router with AppVeyor --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index bc4d26c0..010a2da1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,6 +14,6 @@ install: build_script: - cd build - - cmake -G"%GEN%" -DALSOFT_REQUIRE_WINMM=ON -DALSOFT_REQUIRE_DSOUND=ON -DALSOFT_REQUIRE_WASAPI=ON -DALSOFT_EMBED_HRTF_DATA=YES .. + - cmake -G"%GEN%" -DALSOFT_BUILD_ROUTER=ON -DALSOFT_REQUIRE_WINMM=ON -DALSOFT_REQUIRE_DSOUND=ON -DALSOFT_REQUIRE_WASAPI=ON -DALSOFT_EMBED_HRTF_DATA=YES .. - cmake --build . --config %CFG% --clean-first -- cgit v1.2.3 From 08aa9d898bcd2ca653fc3354ec086c154e4932d6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 Oct 2018 16:32:25 -0700 Subject: Remove an unnecessary include --- router/router.h | 1 - 1 file changed, 1 deletion(-) diff --git a/router/router.h b/router/router.h index 96db56ea..41060ecd 100644 --- a/router/router.h +++ b/router/router.h @@ -15,7 +15,6 @@ #include "AL/alc.h" #include "AL/al.h" #include "AL/alext.h" -#include "rwlock.h" #ifndef UNUSED -- cgit v1.2.3 From 615c025b6786adfd38446559b48b453e1e6c4883 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 Oct 2018 16:35:14 -0700 Subject: Add a missing include for array --- router/alc.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/router/alc.cpp b/router/alc.cpp index 343b792d..c129198a 100644 --- a/router/alc.cpp +++ b/router/alc.cpp @@ -8,6 +8,7 @@ #include #include +#include #include "AL/alc.h" #include "router.h" -- cgit v1.2.3 From da150572f94ec354c8061c0bf1aafa0926c6dbc7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 Oct 2018 17:03:21 -0700 Subject: Clean up the DriverIface in its destructor --- router/router.cpp | 9 +-------- router/router.h | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/router/router.cpp b/router/router.cpp index 049ac3bc..66bf5dd3 100644 --- a/router/router.cpp +++ b/router/router.cpp @@ -63,11 +63,6 @@ BOOL APIENTRY DllMain(HINSTANCE UNUSED(module), DWORD reason, void* UNUSED(reser break; case DLL_PROCESS_DETACH: - for(auto &drv : DriverList) - { - if(drv.Module) - FreeLibrary(drv.Module); - } DriverList.clear(); if(LogFile && LogFile != stderr) @@ -98,7 +93,7 @@ static void AddModule(HMODULE module, const WCHAR *name) } } - DriverList.emplace_back(); + DriverList.emplace_back(name, module); DriverIface &newdrv = DriverList.back(); /* Load required functions. */ @@ -209,8 +204,6 @@ static void AddModule(HMODULE module, const WCHAR *name) if(!err) { ALCint alc_ver[2] = { 0, 0 }; - newdrv.Name = name; - newdrv.Module = module; newdrv.alcGetIntegerv(nullptr, ALC_MAJOR_VERSION, 1, &alc_ver[0]); newdrv.alcGetIntegerv(nullptr, ALC_MINOR_VERSION, 1, &alc_ver[1]); if(newdrv.alcGetError(nullptr) == ALC_NO_ERROR) diff --git a/router/router.h b/router/router.h index 41060ecd..d2574e74 100644 --- a/router/router.h +++ b/router/router.h @@ -31,7 +31,7 @@ #define MAKE_ALC_VER(major, minor) (((major)<<8) | (minor)) -typedef struct DriverIface { +struct DriverIface { std::wstring Name; HMODULE Module{nullptr}; int ALCVer{0}; @@ -133,7 +133,17 @@ typedef struct DriverIface { LPALDOPPLERVELOCITY alDopplerVelocity{nullptr}; LPALSPEEDOFSOUND alSpeedOfSound{nullptr}; LPALDISTANCEMODEL alDistanceModel{nullptr}; -} DriverIface; + + DriverIface(std::wstring name, HMODULE mod) + : Name(std::move(name)), Module(mod) + { } + ~DriverIface() + { + if(Module) + FreeLibrary(Module); + Module = nullptr; + } +}; extern std::vector DriverList; -- cgit v1.2.3 From 1e8c6df7b99f1db7aa38c91c885ed9866c9a7873 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Oct 2018 10:05:15 -0700 Subject: Add a C++ ContextRef helper to manage a ALCcontext reference --- OpenAL32/Include/alMain.h | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 0fd77491..b3380ae2 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -914,7 +914,41 @@ int EventThread(void *arg); vector_al_string SearchDataFiles(const char *match, const char *subdir); #ifdef __cplusplus -} +} // extern "C" + +/* Simple RAII context reference. Takes the reference of the provided + * ALCcontext, and decrements it when leaving scope. Movable (transfer + * reference) but not copyable (no new references). + */ +class ContextRef { + ALCcontext *mCtx{nullptr}; + + void release() noexcept + { + if(mCtx) + ALCcontext_DecRef(mCtx); + mCtx = nullptr; + } + +public: + ContextRef() noexcept = default; + explicit ContextRef(ALCcontext *ctx) noexcept : mCtx(ctx) { } + ~ContextRef() { release(); } + + ContextRef& operator=(const ContextRef&) = delete; + ContextRef& operator=(ContextRef&& rhs) noexcept + { + release(); + mCtx = rhs.mCtx; + rhs.mCtx = nullptr; + return *this; + } + + operator bool() const noexcept { return static_cast(mCtx); } + + ALCcontext* operator->() noexcept { return mCtx; } + ALCcontext* get() noexcept { return mCtx; } +}; #endif #endif -- cgit v1.2.3 From 4b7af24ed557dfa27126b783a4d86b25b02c3958 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Oct 2018 10:35:12 -0700 Subject: Add specializations for lock_guard and unique_lock to take almtx_t --- common/threads.h | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/common/threads.h b/common/threads.h index 2d1b4e7f..7fbe20cd 100644 --- a/common/threads.h +++ b/common/threads.h @@ -262,7 +262,66 @@ int altimespec_get(struct timespec *ts, int base); void al_nssleep(unsigned long nsec); #ifdef __cplusplus -} +} // extern "C" + +#include + +/* Add specializations for std::lock_guard and std::unique_lock which take an + * almtx_t and call the appropriate almtx_* functions. + */ +namespace std { + +template<> +class lock_guard { + almtx_t &mMtx; + +public: + using mutex_type = almtx_t; + + explicit lock_guard(almtx_t &mtx) : mMtx(mtx) { almtx_lock(&mMtx); } + lock_guard(almtx_t &mtx, std::adopt_lock_t) : mMtx(mtx) { } + ~lock_guard() { almtx_unlock(&mMtx); } + + lock_guard(const lock_guard&) = delete; + lock_guard& operator=(const lock_guard&) = delete; +}; + +template<> +class unique_lock { + almtx_t *mMtx{nullptr}; + bool mLocked{false}; + +public: + using mutex_type = almtx_t; + + explicit unique_lock(almtx_t &mtx) : mMtx(&mtx) { almtx_lock(mMtx); mLocked = true; } + unique_lock(unique_lock&& rhs) : mMtx(rhs.mMtx), mLocked(rhs.mLocked) + { rhs.mMtx = nullptr; rhs.mLocked = false; } + ~unique_lock() { if(mLocked) almtx_unlock(mMtx); } + + unique_lock& operator=(const unique_lock&) = delete; + unique_lock& operator=(unique_lock&& rhs) + { + if(mLocked) + almtx_unlock(mMtx); + mMtx = rhs.mMtx; rhs.mMtx = nullptr; + mLocked = rhs.mLocked; rhs.mLocked = false; + return *this; + } + + void lock() + { + almtx_lock(mMtx); + mLocked = true; + } + void unlock() + { + mLocked = false; + almtx_unlock(mMtx); + } +}; + +} // namespace std #endif #endif /* AL_THREADS_H */ -- cgit v1.2.3 From 624bc1c839ff892759e4432bfcf39f2d3343a1ee Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Oct 2018 10:37:16 -0700 Subject: Convert alBuffer.c to C++ A test to ensure everything works. --- CMakeLists.txt | 2 +- OpenAL32/alBuffer.c | 1305 ------------------------------------------------- OpenAL32/alBuffer.cpp | 1217 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1218 insertions(+), 1306 deletions(-) delete mode 100644 OpenAL32/alBuffer.c create mode 100644 OpenAL32/alBuffer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 076291e4..799703a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -816,7 +816,7 @@ SET(OPENAL_OBJS OpenAL32/Include/alAuxEffectSlot.h OpenAL32/alAuxEffectSlot.c OpenAL32/Include/alBuffer.h - OpenAL32/alBuffer.c + OpenAL32/alBuffer.cpp OpenAL32/Include/alEffect.h OpenAL32/alEffect.c OpenAL32/Include/alError.h diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c deleted file mode 100644 index 0b8c27f5..00000000 --- a/OpenAL32/alBuffer.c +++ /dev/null @@ -1,1305 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include -#include -#ifdef HAVE_MALLOC_H -#include -#endif - -#include "alMain.h" -#include "alu.h" -#include "alError.h" -#include "alBuffer.h" -#include "sample_cvt.h" - - -extern inline void LockBufferList(ALCdevice *device); -extern inline void UnlockBufferList(ALCdevice *device); -extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type); -extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); - -static ALbuffer *AllocBuffer(ALCcontext *context); -static void FreeBuffer(ALCdevice *device, ALbuffer *buffer); -static const ALchar *NameFromUserFmtType(enum UserFmtType type); -static void LoadData(ALCcontext *context, ALbuffer *buffer, ALuint freq, ALsizei size, - enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, - const ALvoid *data, ALbitfieldSOFT access); -static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type); -static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align); - -static inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) -{ - BufferSubList *sublist; - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= VECTOR_SIZE(device->BufferList))) - return NULL; - sublist = &VECTOR_ELEM(device->BufferList, lidx); - if(UNLIKELY(sublist->FreeMask & (U64(1)<Buffers + slidx; -} - - -#define INVALID_STORAGE_MASK ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT) -#define MAP_READ_WRITE_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT) -#define INVALID_MAP_FLAGS ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT) - - -AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) -{ - ALCcontext *context; - ALsizei cur = 0; - - context = GetContextRef(); - if(!context) return; - - if(n < 0) - alSetError(context, AL_INVALID_VALUE, "Generating %d buffers", n); - else for(cur = 0;cur < n;cur++) - { - ALbuffer *buffer = AllocBuffer(context); - if(!buffer) - { - alDeleteBuffers(cur, buffers); - break; - } - - buffers[cur] = buffer->id; - } - - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) -{ - ALCdevice *device; - ALCcontext *context; - ALbuffer *ALBuf; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - - LockBufferList(device); - if(UNLIKELY(n < 0)) - { - alSetError(context, AL_INVALID_VALUE, "Deleting %d buffers", n); - goto done; - } - - for(i = 0;i < n;i++) - { - if(!buffers[i]) - continue; - - /* Check for valid Buffer ID, and make sure it's not in use. */ - if((ALBuf=LookupBuffer(device, buffers[i])) == NULL) - { - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffers[i]); - goto done; - } - if(ReadRef(&ALBuf->ref) != 0) - { - alSetError(context, AL_INVALID_OPERATION, "Deleting in-use buffer %u", buffers[i]); - goto done; - } - } - for(i = 0;i < n;i++) - { - if((ALBuf=LookupBuffer(device, buffers[i])) != NULL) - FreeBuffer(device, ALBuf); - } - -done: - UnlockBufferList(device); - ALCcontext_DecRef(context); -} - -AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer) -{ - ALCcontext *context; - ALboolean ret; - - context = GetContextRef(); - if(!context) return AL_FALSE; - - LockBufferList(context->Device); - ret = ((!buffer || LookupBuffer(context->Device, buffer)) ? - AL_TRUE : AL_FALSE); - UnlockBufferList(context->Device); - - ALCcontext_DecRef(context); - - return ret; -} - - -AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq) -{ alBufferStorageSOFT(buffer, format, data, size, freq, 0); } - -AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags) -{ - enum UserFmtChannels srcchannels = UserFmtMono; - enum UserFmtType srctype = UserFmtUByte; - ALCdevice *device; - ALCcontext *context; - ALbuffer *albuf; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - LockBufferList(device); - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(size < 0)) - alSetError(context, AL_INVALID_VALUE, "Negative storage size %d", size); - else if(UNLIKELY(freq < 1)) - alSetError(context, AL_INVALID_VALUE, "Invalid sample rate %d", freq); - else if(UNLIKELY((flags&INVALID_STORAGE_MASK) != 0)) - alSetError(context, AL_INVALID_VALUE, "Invalid storage flags 0x%x", - flags&INVALID_STORAGE_MASK); - else if(UNLIKELY((flags&AL_MAP_PERSISTENT_BIT_SOFT) && !(flags&MAP_READ_WRITE_FLAGS))) - alSetError(context, AL_INVALID_VALUE, - "Declaring persistently mapped storage without read or write access"); - else if(UNLIKELY(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)) - alSetError(context, AL_INVALID_ENUM, "Invalid format 0x%04x", format); - else - LoadData(context, albuf, freq, size, srcchannels, srctype, data, flags); - - UnlockBufferList(device); - ALCcontext_DecRef(context); -} - -AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access) -{ - void *retval = NULL; - ALCdevice *device; - ALCcontext *context; - ALbuffer *albuf; - - context = GetContextRef(); - if(!context) return retval; - - device = context->Device; - LockBufferList(device); - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY((access&INVALID_MAP_FLAGS) != 0)) - alSetError(context, AL_INVALID_VALUE, "Invalid map flags 0x%x", access&INVALID_MAP_FLAGS); - else if(UNLIKELY(!(access&MAP_READ_WRITE_FLAGS))) - alSetError(context, AL_INVALID_VALUE, "Mapping buffer %u without read or write access", - buffer); - else - { - ALbitfieldSOFT unavailable = (albuf->Access^access) & access; - if(UNLIKELY(ReadRef(&albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT))) - alSetError(context, AL_INVALID_OPERATION, - "Mapping in-use buffer %u without persistent mapping", buffer); - else if(UNLIKELY(albuf->MappedAccess != 0)) - alSetError(context, AL_INVALID_OPERATION, "Mapping already-mapped buffer %u", buffer); - else if(UNLIKELY((unavailable&AL_MAP_READ_BIT_SOFT))) - alSetError(context, AL_INVALID_VALUE, - "Mapping buffer %u for reading without read access", buffer); - else if(UNLIKELY((unavailable&AL_MAP_WRITE_BIT_SOFT))) - alSetError(context, AL_INVALID_VALUE, - "Mapping buffer %u for writing without write access", buffer); - else if(UNLIKELY((unavailable&AL_MAP_PERSISTENT_BIT_SOFT))) - alSetError(context, AL_INVALID_VALUE, - "Mapping buffer %u persistently without persistent access", buffer); - else if(UNLIKELY(offset < 0 || offset >= albuf->OriginalSize || - length <= 0 || length > albuf->OriginalSize - offset)) - alSetError(context, AL_INVALID_VALUE, "Mapping invalid range %d+%d for buffer %u", - offset, length, buffer); - else - { - retval = (ALbyte*)albuf->data + offset; - albuf->MappedAccess = access; - albuf->MappedOffset = offset; - albuf->MappedSize = length; - } - } - UnlockBufferList(device); - - ALCcontext_DecRef(context); - return retval; -} - -AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer) -{ - ALCdevice *device; - ALCcontext *context; - ALbuffer *albuf; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - LockBufferList(device); - if((albuf=LookupBuffer(device, buffer)) == NULL) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(albuf->MappedAccess == 0) - alSetError(context, AL_INVALID_OPERATION, "Unmapping unmapped buffer %u", buffer); - else - { - albuf->MappedAccess = 0; - albuf->MappedOffset = 0; - albuf->MappedSize = 0; - } - UnlockBufferList(device); - - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length) -{ - ALCdevice *device; - ALCcontext *context; - ALbuffer *albuf; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - LockBufferList(device); - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT))) - alSetError(context, AL_INVALID_OPERATION, - "Flushing buffer %u while not mapped for writing", buffer); - else if(UNLIKELY(offset < albuf->MappedOffset || - offset >= albuf->MappedOffset+albuf->MappedSize || - length <= 0 || length > albuf->MappedOffset+albuf->MappedSize-offset)) - alSetError(context, AL_INVALID_VALUE, "Flushing invalid range %d+%d on buffer %u", - offset, length, buffer); - else - { - /* FIXME: Need to use some method of double-buffering for the mixer and - * app to hold separate memory, which can be safely transfered - * asynchronously. Currently we just say the app shouldn't write where - * OpenAL's reading, and hope for the best... - */ - ATOMIC_THREAD_FENCE(almemory_order_seq_cst); - } - UnlockBufferList(device); - - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length) -{ - enum UserFmtChannels srcchannels = UserFmtMono; - enum UserFmtType srctype = UserFmtUByte; - ALCdevice *device; - ALCcontext *context; - ALbuffer *albuf; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - LockBufferList(device); - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)) - alSetError(context, AL_INVALID_ENUM, "Invalid format 0x%04x", format); - else - { - ALsizei unpack_align, align; - ALsizei byte_align; - ALsizei frame_size; - ALsizei num_chans; - void *dst; - - unpack_align = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign); - align = SanitizeAlignment(srctype, unpack_align); - if(UNLIKELY(align < 1)) - alSetError(context, AL_INVALID_VALUE, "Invalid unpack alignment %d", unpack_align); - else if(UNLIKELY((long)srcchannels != (long)albuf->FmtChannels || - srctype != albuf->OriginalType)) - alSetError(context, AL_INVALID_ENUM, "Unpacking data with mismatched format"); - else if(UNLIKELY(align != albuf->OriginalAlign)) - alSetError(context, AL_INVALID_VALUE, - "Unpacking data with alignment %u does not match original alignment %u", - align, albuf->OriginalAlign); - else if(UNLIKELY(albuf->MappedAccess != 0)) - alSetError(context, AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u", - buffer); - else - { - num_chans = ChannelsFromFmt(albuf->FmtChannels); - frame_size = num_chans * BytesFromFmt(albuf->FmtType); - if(albuf->OriginalType == UserFmtIMA4) - byte_align = ((align-1)/2 + 4) * num_chans; - else if(albuf->OriginalType == UserFmtMSADPCM) - byte_align = ((align-2)/2 + 7) * num_chans; - else - byte_align = align * frame_size; - - if(UNLIKELY(offset < 0 || length < 0 || offset > albuf->OriginalSize || - length > albuf->OriginalSize-offset)) - alSetError(context, AL_INVALID_VALUE, "Invalid data sub-range %d+%d on buffer %u", - offset, length, buffer); - else if(UNLIKELY((offset%byte_align) != 0)) - alSetError(context, AL_INVALID_VALUE, - "Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)", - offset, byte_align, align); - else if(UNLIKELY((length%byte_align) != 0)) - alSetError(context, AL_INVALID_VALUE, - "Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)", - length, byte_align, align); - else - { - /* offset -> byte offset, length -> sample count */ - offset = offset/byte_align * align * frame_size; - length = length/byte_align * align; - - dst = (ALbyte*)albuf->data + offset; - if(srctype == UserFmtIMA4 && albuf->FmtType == FmtShort) - Convert_ALshort_ALima4(dst, data, num_chans, length, align); - else if(srctype == UserFmtMSADPCM && albuf->FmtType == FmtShort) - Convert_ALshort_ALmsadpcm(dst, data, num_chans, length, align); - else - { - assert((long)srctype == (long)albuf->FmtType); - memcpy(dst, data, length*frame_size); - } - } - } - } - UnlockBufferList(device); - - ALCcontext_DecRef(context); -} - - -AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint UNUSED(buffer), - ALuint UNUSED(samplerate), ALenum UNUSED(internalformat), ALsizei UNUSED(samples), - ALenum UNUSED(channels), ALenum UNUSED(type), const ALvoid *UNUSED(data)) -{ - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - alSetError(context, AL_INVALID_OPERATION, "alBufferSamplesSOFT not supported"); - - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint UNUSED(buffer), - ALsizei UNUSED(offset), ALsizei UNUSED(samples), - ALenum UNUSED(channels), ALenum UNUSED(type), const ALvoid *UNUSED(data)) -{ - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - alSetError(context, AL_INVALID_OPERATION, "alBufferSubSamplesSOFT not supported"); - - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint UNUSED(buffer), - ALsizei UNUSED(offset), ALsizei UNUSED(samples), - ALenum UNUSED(channels), ALenum UNUSED(type), ALvoid *UNUSED(data)) -{ - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - alSetError(context, AL_INVALID_OPERATION, "alGetBufferSamplesSOFT not supported"); - - ALCcontext_DecRef(context); -} - -AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum UNUSED(format)) -{ - ALCcontext *context; - - context = GetContextRef(); - if(!context) return AL_FALSE; - - alSetError(context, AL_INVALID_OPERATION, "alIsBufferFormatSupportedSOFT not supported"); - - ALCcontext_DecRef(context); - return AL_FALSE; -} - - -AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(value)) -{ - ALCdevice *device; - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - LockBufferList(device); - if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); - } - UnlockBufferList(device); - - ALCcontext_DecRef(context); -} - - -AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat UNUSED(value1), ALfloat UNUSED(value2), ALfloat UNUSED(value3)) -{ - ALCdevice *device; - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - LockBufferList(device); - if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); - } - UnlockBufferList(device); - - ALCcontext_DecRef(context); -} - - -AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values) -{ - ALCdevice *device; - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - LockBufferList(device); - if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!values)) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); - } - UnlockBufferList(device); - - ALCcontext_DecRef(context); -} - - -AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) -{ - ALCdevice *device; - ALCcontext *context; - ALbuffer *albuf; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - LockBufferList(device); - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else switch(param) - { - case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: - if(UNLIKELY(value < 0)) - alSetError(context, AL_INVALID_VALUE, "Invalid unpack block alignment %d", value); - else - ATOMIC_STORE_SEQ(&albuf->UnpackAlign, value); - break; - - case AL_PACK_BLOCK_ALIGNMENT_SOFT: - if(UNLIKELY(value < 0)) - alSetError(context, AL_INVALID_VALUE, "Invalid pack block alignment %d", value); - else - ATOMIC_STORE_SEQ(&albuf->PackAlign, value); - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); - } - UnlockBufferList(device); - - ALCcontext_DecRef(context); -} - - -AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint UNUSED(value1), ALint UNUSED(value2), ALint UNUSED(value3)) -{ - ALCdevice *device; - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - LockBufferList(device); - if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); - } - UnlockBufferList(device); - - ALCcontext_DecRef(context); -} - - -AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values) -{ - ALCdevice *device; - ALCcontext *context; - ALbuffer *albuf; - - if(values) - { - switch(param) - { - case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: - case AL_PACK_BLOCK_ALIGNMENT_SOFT: - alBufferi(buffer, param, values[0]); - return; - } - } - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - LockBufferList(device); - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!values)) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_LOOP_POINTS_SOFT: - if(UNLIKELY(ReadRef(&albuf->ref) != 0)) - alSetError(context, AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points", - buffer); - else if(UNLIKELY(values[0] >= values[1] || values[0] < 0 || values[1] > albuf->SampleLen)) - alSetError(context, AL_INVALID_VALUE, "Invalid loop point range %d -> %d o buffer %u", - values[0], values[1], buffer); - else - { - albuf->LoopStart = values[0]; - albuf->LoopEnd = values[1]; - } - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", - param); - } - UnlockBufferList(device); - - ALCcontext_DecRef(context); -} - - -AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value) -{ - ALCdevice *device; - ALCcontext *context; - ALbuffer *albuf; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - LockBufferList(device); - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!value)) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); - } - UnlockBufferList(device); - - ALCcontext_DecRef(context); -} - - -AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) -{ - ALCdevice *device; - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - LockBufferList(device); - if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!value1 || !value2 || !value3)) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); - } - UnlockBufferList(device); - - ALCcontext_DecRef(context); -} - - -AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values) -{ - ALCdevice *device; - ALCcontext *context; - - switch(param) - { - case AL_SEC_LENGTH_SOFT: - alGetBufferf(buffer, param, values); - return; - } - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - LockBufferList(device); - if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!values)) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); - } - UnlockBufferList(device); - - ALCcontext_DecRef(context); -} - - -AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value) -{ - ALCdevice *device; - ALCcontext *context; - ALbuffer *albuf; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - LockBufferList(device); - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!value)) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_FREQUENCY: - *value = albuf->Frequency; - break; - - case AL_BITS: - *value = BytesFromFmt(albuf->FmtType) * 8; - break; - - case AL_CHANNELS: - *value = ChannelsFromFmt(albuf->FmtChannels); - break; - - case AL_SIZE: - *value = albuf->SampleLen * FrameSizeFromFmt(albuf->FmtChannels, - albuf->FmtType); - break; - - case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: - *value = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign); - break; - - case AL_PACK_BLOCK_ALIGNMENT_SOFT: - *value = ATOMIC_LOAD_SEQ(&albuf->PackAlign); - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); - } - UnlockBufferList(device); - - ALCcontext_DecRef(context); -} - - -AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3) -{ - ALCdevice *device; - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - LockBufferList(device); - if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!value1 || !value2 || !value3)) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); - } - UnlockBufferList(device); - - ALCcontext_DecRef(context); -} - - -AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values) -{ - ALCdevice *device; - ALCcontext *context; - ALbuffer *albuf; - - switch(param) - { - case AL_FREQUENCY: - case AL_BITS: - case AL_CHANNELS: - case AL_SIZE: - case AL_INTERNAL_FORMAT_SOFT: - case AL_BYTE_LENGTH_SOFT: - case AL_SAMPLE_LENGTH_SOFT: - case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: - case AL_PACK_BLOCK_ALIGNMENT_SOFT: - alGetBufferi(buffer, param, values); - return; - } - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - LockBufferList(device); - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!values)) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_LOOP_POINTS_SOFT: - values[0] = albuf->LoopStart; - values[1] = albuf->LoopEnd; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", - param); - } - UnlockBufferList(device); - - ALCcontext_DecRef(context); -} - - -static const ALchar *NameFromUserFmtType(enum UserFmtType type) -{ - switch(type) - { - case UserFmtUByte: return "Unsigned Byte"; - case UserFmtShort: return "Signed Short"; - case UserFmtFloat: return "Float32"; - case UserFmtDouble: return "Float64"; - case UserFmtMulaw: return "muLaw"; - case UserFmtAlaw: return "aLaw"; - case UserFmtIMA4: return "IMA4 ADPCM"; - case UserFmtMSADPCM: return "MSADPCM"; - } - return ""; -} - -/* - * LoadData - * - * Loads the specified data into the buffer, using the specified format. - */ -static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALbitfieldSOFT access) -{ - enum FmtChannels DstChannels = FmtMono; - enum FmtType DstType = FmtUByte; - ALsizei NumChannels, FrameSize; - ALsizei SrcByteAlign; - ALsizei unpackalign; - ALsizei newsize; - ALsizei frames; - ALsizei align; - - if(UNLIKELY(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)) - SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer %u", - ALBuf->id); - - /* Currently no channel configurations need to be converted. */ - switch(SrcChannels) - { - case UserFmtMono: DstChannels = FmtMono; break; - case UserFmtStereo: DstChannels = FmtStereo; break; - case UserFmtRear: DstChannels = FmtRear; break; - case UserFmtQuad: DstChannels = FmtQuad; break; - case UserFmtX51: DstChannels = FmtX51; break; - case UserFmtX61: DstChannels = FmtX61; break; - case UserFmtX71: DstChannels = FmtX71; break; - case UserFmtBFormat2D: DstChannels = FmtBFormat2D; break; - case UserFmtBFormat3D: DstChannels = FmtBFormat3D; break; - } - if(UNLIKELY((long)SrcChannels != (long)DstChannels)) - SETERR_RETURN(context, AL_INVALID_ENUM,, "Invalid format"); - - /* IMA4 and MSADPCM convert to 16-bit short. */ - switch(SrcType) - { - case UserFmtUByte: DstType = FmtUByte; break; - case UserFmtShort: DstType = FmtShort; break; - case UserFmtFloat: DstType = FmtFloat; break; - case UserFmtDouble: DstType = FmtDouble; break; - case UserFmtAlaw: DstType = FmtAlaw; break; - case UserFmtMulaw: DstType = FmtMulaw; break; - case UserFmtIMA4: DstType = FmtShort; break; - case UserFmtMSADPCM: DstType = FmtShort; break; - } - - /* TODO: Currently we can only map samples when they're not converted. To - * allow it would need some kind of double-buffering to hold onto a copy of - * the original data. - */ - if((access&MAP_READ_WRITE_FLAGS)) - { - if(UNLIKELY((long)SrcType != (long)DstType)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "%s samples cannot be mapped", - NameFromUserFmtType(SrcType)); - } - - unpackalign = ATOMIC_LOAD_SEQ(&ALBuf->UnpackAlign); - if(UNLIKELY((align=SanitizeAlignment(SrcType, unpackalign)) < 1)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid unpack alignment %d for %s samples", - unpackalign, NameFromUserFmtType(SrcType)); - - if((access&AL_PRESERVE_DATA_BIT_SOFT)) - { - /* Can only preserve data with the same format and alignment. */ - if(UNLIKELY(ALBuf->FmtChannels != DstChannels || ALBuf->OriginalType != SrcType)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched format"); - if(UNLIKELY(ALBuf->OriginalAlign != align)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched alignment"); - } - - /* Convert the input/source size in bytes to sample frames using the unpack - * block alignment. - */ - if(SrcType == UserFmtIMA4) - SrcByteAlign = ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels); - else if(SrcType == UserFmtMSADPCM) - SrcByteAlign = ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels); - else - SrcByteAlign = align * FrameSizeFromUserFmt(SrcChannels, SrcType); - if(UNLIKELY((size%SrcByteAlign) != 0)) - SETERR_RETURN(context, AL_INVALID_VALUE,, - "Data size %d is not a multiple of frame size %d (%d unpack alignment)", - size, SrcByteAlign, align); - - if(UNLIKELY(size / SrcByteAlign > INT_MAX / align)) - SETERR_RETURN(context, AL_OUT_OF_MEMORY,, - "Buffer size overflow, %d blocks x %d samples per block", size/SrcByteAlign, align); - frames = size / SrcByteAlign * align; - - /* Convert the sample frames to the number of bytes needed for internal - * storage. - */ - NumChannels = ChannelsFromFmt(DstChannels); - FrameSize = NumChannels * BytesFromFmt(DstType); - if(UNLIKELY(frames > INT_MAX/FrameSize)) - SETERR_RETURN(context, AL_OUT_OF_MEMORY,, - "Buffer size overflow, %d frames x %d bytes per frame", frames, FrameSize); - newsize = frames*FrameSize; - - /* Round up to the next 16-byte multiple. This could reallocate only when - * increasing or the new size is less than half the current, but then the - * buffer's AL_SIZE would not be very reliable for accounting buffer memory - * usage, and reporting the real size could cause problems for apps that - * use AL_SIZE to try to get the buffer's play length. - */ - if(LIKELY(newsize <= INT_MAX-15)) - newsize = (newsize+15) & ~0xf; - if(newsize != ALBuf->BytesAlloc) - { - void *temp = al_malloc(16, (size_t)newsize); - if(UNLIKELY(!temp && newsize)) - SETERR_RETURN(context, AL_OUT_OF_MEMORY,, "Failed to allocate %d bytes of storage", - newsize); - if((access&AL_PRESERVE_DATA_BIT_SOFT)) - { - ALsizei tocopy = mini(newsize, ALBuf->BytesAlloc); - if(tocopy > 0) memcpy(temp, ALBuf->data, tocopy); - } - al_free(ALBuf->data); - ALBuf->data = temp; - ALBuf->BytesAlloc = newsize; - } - - if(SrcType == UserFmtIMA4) - { - assert(DstType == FmtShort); - if(data != NULL && ALBuf->data != NULL) - Convert_ALshort_ALima4(ALBuf->data, data, NumChannels, frames, align); - ALBuf->OriginalAlign = align; - } - else if(SrcType == UserFmtMSADPCM) - { - assert(DstType == FmtShort); - if(data != NULL && ALBuf->data != NULL) - Convert_ALshort_ALmsadpcm(ALBuf->data, data, NumChannels, frames, align); - ALBuf->OriginalAlign = align; - } - else - { - assert((long)SrcType == (long)DstType); - if(data != NULL && ALBuf->data != NULL) - memcpy(ALBuf->data, data, frames*FrameSize); - ALBuf->OriginalAlign = 1; - } - ALBuf->OriginalSize = size; - ALBuf->OriginalType = SrcType; - - ALBuf->Frequency = freq; - ALBuf->FmtChannels = DstChannels; - ALBuf->FmtType = DstType; - ALBuf->Access = access; - - ALBuf->SampleLen = frames; - ALBuf->LoopStart = 0; - ALBuf->LoopEnd = ALBuf->SampleLen; -} - - -ALsizei BytesFromUserFmt(enum UserFmtType type) -{ - switch(type) - { - case UserFmtUByte: return sizeof(ALubyte); - case UserFmtShort: return sizeof(ALshort); - case UserFmtFloat: return sizeof(ALfloat); - case UserFmtDouble: return sizeof(ALdouble); - case UserFmtMulaw: return sizeof(ALubyte); - case UserFmtAlaw: return sizeof(ALubyte); - case UserFmtIMA4: break; /* not handled here */ - case UserFmtMSADPCM: break; /* not handled here */ - } - return 0; -} -ALsizei ChannelsFromUserFmt(enum UserFmtChannels chans) -{ - switch(chans) - { - case UserFmtMono: return 1; - case UserFmtStereo: return 2; - case UserFmtRear: return 2; - case UserFmtQuad: return 4; - case UserFmtX51: return 6; - case UserFmtX61: return 7; - case UserFmtX71: return 8; - case UserFmtBFormat2D: return 3; - case UserFmtBFormat3D: return 4; - } - return 0; -} -static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, - enum UserFmtType *type) -{ - static const struct { - ALenum format; - enum UserFmtChannels channels; - enum UserFmtType type; - } list[] = { - { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte }, - { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort }, - { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat }, - { AL_FORMAT_MONO_DOUBLE_EXT, UserFmtMono, UserFmtDouble }, - { AL_FORMAT_MONO_IMA4, UserFmtMono, UserFmtIMA4 }, - { AL_FORMAT_MONO_MSADPCM_SOFT, UserFmtMono, UserFmtMSADPCM }, - { AL_FORMAT_MONO_MULAW, UserFmtMono, UserFmtMulaw }, - { AL_FORMAT_MONO_ALAW_EXT, UserFmtMono, UserFmtAlaw }, - - { AL_FORMAT_STEREO8, UserFmtStereo, UserFmtUByte }, - { AL_FORMAT_STEREO16, UserFmtStereo, UserFmtShort }, - { AL_FORMAT_STEREO_FLOAT32, UserFmtStereo, UserFmtFloat }, - { AL_FORMAT_STEREO_DOUBLE_EXT, UserFmtStereo, UserFmtDouble }, - { AL_FORMAT_STEREO_IMA4, UserFmtStereo, UserFmtIMA4 }, - { AL_FORMAT_STEREO_MSADPCM_SOFT, UserFmtStereo, UserFmtMSADPCM }, - { AL_FORMAT_STEREO_MULAW, UserFmtStereo, UserFmtMulaw }, - { AL_FORMAT_STEREO_ALAW_EXT, UserFmtStereo, UserFmtAlaw }, - - { AL_FORMAT_REAR8, UserFmtRear, UserFmtUByte }, - { AL_FORMAT_REAR16, UserFmtRear, UserFmtShort }, - { AL_FORMAT_REAR32, UserFmtRear, UserFmtFloat }, - { AL_FORMAT_REAR_MULAW, UserFmtRear, UserFmtMulaw }, - - { AL_FORMAT_QUAD8_LOKI, UserFmtQuad, UserFmtUByte }, - { AL_FORMAT_QUAD16_LOKI, UserFmtQuad, UserFmtShort }, - - { AL_FORMAT_QUAD8, UserFmtQuad, UserFmtUByte }, - { AL_FORMAT_QUAD16, UserFmtQuad, UserFmtShort }, - { AL_FORMAT_QUAD32, UserFmtQuad, UserFmtFloat }, - { AL_FORMAT_QUAD_MULAW, UserFmtQuad, UserFmtMulaw }, - - { AL_FORMAT_51CHN8, UserFmtX51, UserFmtUByte }, - { AL_FORMAT_51CHN16, UserFmtX51, UserFmtShort }, - { AL_FORMAT_51CHN32, UserFmtX51, UserFmtFloat }, - { AL_FORMAT_51CHN_MULAW, UserFmtX51, UserFmtMulaw }, - - { AL_FORMAT_61CHN8, UserFmtX61, UserFmtUByte }, - { AL_FORMAT_61CHN16, UserFmtX61, UserFmtShort }, - { AL_FORMAT_61CHN32, UserFmtX61, UserFmtFloat }, - { AL_FORMAT_61CHN_MULAW, UserFmtX61, UserFmtMulaw }, - - { AL_FORMAT_71CHN8, UserFmtX71, UserFmtUByte }, - { AL_FORMAT_71CHN16, UserFmtX71, UserFmtShort }, - { AL_FORMAT_71CHN32, UserFmtX71, UserFmtFloat }, - { AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw }, - - { AL_FORMAT_BFORMAT2D_8, UserFmtBFormat2D, UserFmtUByte }, - { AL_FORMAT_BFORMAT2D_16, UserFmtBFormat2D, UserFmtShort }, - { AL_FORMAT_BFORMAT2D_FLOAT32, UserFmtBFormat2D, UserFmtFloat }, - { AL_FORMAT_BFORMAT2D_MULAW, UserFmtBFormat2D, UserFmtMulaw }, - - { AL_FORMAT_BFORMAT3D_8, UserFmtBFormat3D, UserFmtUByte }, - { AL_FORMAT_BFORMAT3D_16, UserFmtBFormat3D, UserFmtShort }, - { AL_FORMAT_BFORMAT3D_FLOAT32, UserFmtBFormat3D, UserFmtFloat }, - { AL_FORMAT_BFORMAT3D_MULAW, UserFmtBFormat3D, UserFmtMulaw }, - }; - ALuint i; - - for(i = 0;i < COUNTOF(list);i++) - { - if(list[i].format == format) - { - *chans = list[i].channels; - *type = list[i].type; - return AL_TRUE; - } - } - - return AL_FALSE; -} - -ALsizei BytesFromFmt(enum FmtType type) -{ - switch(type) - { - case FmtUByte: return sizeof(ALubyte); - case FmtShort: return sizeof(ALshort); - case FmtFloat: return sizeof(ALfloat); - case FmtDouble: return sizeof(ALdouble); - case FmtMulaw: return sizeof(ALubyte); - case FmtAlaw: return sizeof(ALubyte); - } - return 0; -} -ALsizei ChannelsFromFmt(enum FmtChannels chans) -{ - switch(chans) - { - case FmtMono: return 1; - case FmtStereo: return 2; - case FmtRear: return 2; - case FmtQuad: return 4; - case FmtX51: return 6; - case FmtX61: return 7; - case FmtX71: return 8; - case FmtBFormat2D: return 3; - case FmtBFormat3D: return 4; - } - return 0; -} - -static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align) -{ - if(align < 0) - return 0; - - if(align == 0) - { - if(type == UserFmtIMA4) - { - /* Here is where things vary: - * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel - * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel - */ - return 65; - } - if(type == UserFmtMSADPCM) - return 64; - return 1; - } - - if(type == UserFmtIMA4) - { - /* IMA4 block alignment must be a multiple of 8, plus 1. */ - if((align&7) == 1) return align; - return 0; - } - if(type == UserFmtMSADPCM) - { - /* MSADPCM block alignment must be a multiple of 2. */ - if((align&1) == 0) return align; - return 0; - } - - return align; -} - - -static ALbuffer *AllocBuffer(ALCcontext *context) -{ - ALCdevice *device = context->Device; - BufferSubList *sublist, *subend; - ALbuffer *buffer = NULL; - ALsizei lidx = 0; - ALsizei slidx; - - almtx_lock(&device->BufferLock); - sublist = VECTOR_BEGIN(device->BufferList); - subend = VECTOR_END(device->BufferList); - for(;sublist != subend;++sublist) - { - if(sublist->FreeMask) - { - slidx = CTZ64(sublist->FreeMask); - buffer = sublist->Buffers + slidx; - break; - } - ++lidx; - } - if(UNLIKELY(!buffer)) - { - const BufferSubList empty_sublist = { 0, NULL }; - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ - if(UNLIKELY(VECTOR_SIZE(device->BufferList) >= 1<<25)) - { - almtx_unlock(&device->BufferLock); - alSetError(context, AL_OUT_OF_MEMORY, "Too many buffers allocated"); - return NULL; - } - lidx = (ALsizei)VECTOR_SIZE(device->BufferList); - VECTOR_PUSH_BACK(device->BufferList, empty_sublist); - sublist = &VECTOR_BACK(device->BufferList); - sublist->FreeMask = ~U64(0); - sublist->Buffers = al_calloc(16, sizeof(ALbuffer)*64); - if(UNLIKELY(!sublist->Buffers)) - { - VECTOR_POP_BACK(device->BufferList); - almtx_unlock(&device->BufferLock); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate buffer batch"); - return NULL; - } - - slidx = 0; - buffer = sublist->Buffers + slidx; - } - - memset(buffer, 0, sizeof(*buffer)); - - /* Add 1 to avoid buffer ID 0. */ - buffer->id = ((lidx<<6) | slidx) + 1; - - sublist->FreeMask &= ~(U64(1)<BufferLock); - - return buffer; -} - -static void FreeBuffer(ALCdevice *device, ALbuffer *buffer) -{ - ALuint id = buffer->id - 1; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; - - al_free(buffer->data); - memset(buffer, 0, sizeof(*buffer)); - - VECTOR_ELEM(device->BufferList, lidx).FreeMask |= U64(1) << slidx; -} - - -/* - * ReleaseALBuffers() - * - * INTERNAL: Called to destroy any buffers that still exist on the device - */ -ALvoid ReleaseALBuffers(ALCdevice *device) -{ - BufferSubList *sublist = VECTOR_BEGIN(device->BufferList); - BufferSubList *subend = VECTOR_END(device->BufferList); - size_t leftover = 0; - for(;sublist != subend;++sublist) - { - ALuint64 usemask = ~sublist->FreeMask; - while(usemask) - { - ALsizei idx = CTZ64(usemask); - ALbuffer *buffer = sublist->Buffers + idx; - - al_free(buffer->data); - memset(buffer, 0, sizeof(*buffer)); - ++leftover; - - usemask &= ~(U64(1) << idx); - } - sublist->FreeMask = ~usemask; - } - if(leftover > 0) - WARN("(%p) Deleted "SZFMT" Buffer%s\n", device, leftover, (leftover==1)?"":"s"); -} diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp new file mode 100644 index 00000000..94de991c --- /dev/null +++ b/OpenAL32/alBuffer.cpp @@ -0,0 +1,1217 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include +#ifdef HAVE_MALLOC_H +#include +#endif + +#include +#include + +#include "alMain.h" +#include "alu.h" +#include "alError.h" +#include "alBuffer.h" +#include "sample_cvt.h" + + +extern inline void LockBufferList(ALCdevice *device); +extern inline void UnlockBufferList(ALCdevice *device); +extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type); +extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); + +static ALbuffer *AllocBuffer(ALCcontext *context); +static void FreeBuffer(ALCdevice *device, ALbuffer *buffer); +static const ALchar *NameFromUserFmtType(enum UserFmtType type); +static void LoadData(ALCcontext *context, ALbuffer *buffer, ALuint freq, ALsizei size, + enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, + const ALvoid *data, ALbitfieldSOFT access); +static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type); +static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align); + +static inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= VECTOR_SIZE(device->BufferList))) + return nullptr; + BufferSubList *sublist = &VECTOR_ELEM(device->BufferList, lidx); + if(UNLIKELY(sublist->FreeMask & (U64(1)<Buffers + slidx; +} + +#define INVALID_STORAGE_MASK ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT) +#define MAP_READ_WRITE_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT) +#define INVALID_MAP_FLAGS ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT) + +AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(UNLIKELY(n < 0)) + { + alSetError(context.get(), AL_INVALID_VALUE, "Generating %d buffers", n); + return; + } + + if(LIKELY(n == 1)) + { + /* Special handling for the easy and normal case. */ + ALbuffer *buffer = AllocBuffer(context.get()); + if(buffer) buffers[0] = buffer->id; + } + else if(n > 1) + { + /* Store the allocated buffer IDs in a separate local list, to avoid + * modifying the user storage in case of failure. + */ + std::vector ids; + ids.reserve(n); + do { + ALbuffer *buffer = AllocBuffer(context.get()); + if(!buffer) + { + alDeleteBuffers(ids.size(), ids.data()); + return; + } + + ids.emplace_back(buffer->id); + } while(--n); + std::copy(ids.begin(), ids.end(), buffers); + } +} + +AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(UNLIKELY(n < 0)) + { + alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d buffers", n); + return; + } + if(UNLIKELY(n == 0)) + return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + /* First try to find any buffers that are invalid or in-use. */ + const ALuint *buffers_end = buffers + n; + auto invbuf = std::find_if(buffers, buffers_end, + [device, &context](ALuint bid) -> bool + { + if(!bid) return false; + ALbuffer *ALBuf = LookupBuffer(device, bid); + if(UNLIKELY(!ALBuf)) + { + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", bid); + return true; + } + if(UNLIKELY(ReadRef(&ALBuf->ref) != 0)) + { + alSetError(context.get(), AL_INVALID_OPERATION, "Deleting in-use buffer %u", bid); + return true; + } + return false; + } + ); + if(LIKELY(invbuf == buffers_end)) + { + /* All good. Delete non-0 buffer IDs. */ + std::for_each(buffers, buffers_end, + [device](ALuint bid) -> void + { if(bid) FreeBuffer(device, LookupBuffer(device, bid)); } + ); + } +} + +AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer) +{ + ContextRef context{GetContextRef()}; + if(LIKELY(context)) + { + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + if(!buffer || LookupBuffer(device, buffer)) + return AL_TRUE; + } + return AL_FALSE; +} + + +AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq) +{ alBufferStorageSOFT(buffer, format, data, size, freq, 0); } + +AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + enum UserFmtChannels srcchannels = UserFmtMono; + enum UserFmtType srctype = UserFmtUByte; + ALbuffer *albuf; + + if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(size < 0)) + alSetError(context.get(), AL_INVALID_VALUE, "Negative storage size %d", size); + else if(UNLIKELY(freq < 1)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid sample rate %d", freq); + else if(UNLIKELY((flags&INVALID_STORAGE_MASK) != 0)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid storage flags 0x%x", + flags&INVALID_STORAGE_MASK); + else if(UNLIKELY((flags&AL_MAP_PERSISTENT_BIT_SOFT) && !(flags&MAP_READ_WRITE_FLAGS))) + alSetError(context.get(), AL_INVALID_VALUE, + "Declaring persistently mapped storage without read or write access"); + else if(UNLIKELY(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid format 0x%04x", format); + else + LoadData(context.get(), albuf, freq, size, srcchannels, srctype, data, flags); +} + +AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return nullptr; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf; + if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY((access&INVALID_MAP_FLAGS) != 0)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid map flags 0x%x", access&INVALID_MAP_FLAGS); + else if(UNLIKELY(!(access&MAP_READ_WRITE_FLAGS))) + alSetError(context.get(), AL_INVALID_VALUE, "Mapping buffer %u without read or write access", + buffer); + else + { + ALbitfieldSOFT unavailable = (albuf->Access^access) & access; + if(UNLIKELY(ReadRef(&albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT))) + alSetError(context.get(), AL_INVALID_OPERATION, + "Mapping in-use buffer %u without persistent mapping", buffer); + else if(UNLIKELY(albuf->MappedAccess != 0)) + alSetError(context.get(), AL_INVALID_OPERATION, "Mapping already-mapped buffer %u", buffer); + else if(UNLIKELY((unavailable&AL_MAP_READ_BIT_SOFT))) + alSetError(context.get(), AL_INVALID_VALUE, + "Mapping buffer %u for reading without read access", buffer); + else if(UNLIKELY((unavailable&AL_MAP_WRITE_BIT_SOFT))) + alSetError(context.get(), AL_INVALID_VALUE, + "Mapping buffer %u for writing without write access", buffer); + else if(UNLIKELY((unavailable&AL_MAP_PERSISTENT_BIT_SOFT))) + alSetError(context.get(), AL_INVALID_VALUE, + "Mapping buffer %u persistently without persistent access", buffer); + else if(UNLIKELY(offset < 0 || offset >= albuf->OriginalSize || + length <= 0 || length > albuf->OriginalSize - offset)) + alSetError(context.get(), AL_INVALID_VALUE, "Mapping invalid range %d+%d for buffer %u", + offset, length, buffer); + else + { + void *retval = (ALbyte*)albuf->data + offset; + albuf->MappedAccess = access; + albuf->MappedOffset = offset; + albuf->MappedSize = length; + return retval; + } + } + + return nullptr; +} + +AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf; + if((albuf=LookupBuffer(device, buffer)) == nullptr) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(albuf->MappedAccess == 0) + alSetError(context.get(), AL_INVALID_OPERATION, "Unmapping unmapped buffer %u", buffer); + else + { + albuf->MappedAccess = 0; + albuf->MappedOffset = 0; + albuf->MappedSize = 0; + } +} + +AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf; + if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT))) + alSetError(context.get(), AL_INVALID_OPERATION, + "Flushing buffer %u while not mapped for writing", buffer); + else if(UNLIKELY(offset < albuf->MappedOffset || + offset >= albuf->MappedOffset+albuf->MappedSize || + length <= 0 || length > albuf->MappedOffset+albuf->MappedSize-offset)) + alSetError(context.get(), AL_INVALID_VALUE, "Flushing invalid range %d+%d on buffer %u", + offset, length, buffer); + else + { + /* FIXME: Need to use some method of double-buffering for the mixer and + * app to hold separate memory, which can be safely transfered + * asynchronously. Currently we just say the app shouldn't write where + * OpenAL's reading, and hope for the best... + */ + ATOMIC_THREAD_FENCE(almemory_order_seq_cst); + } +} + +AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + enum UserFmtChannels srcchannels = UserFmtMono; + enum UserFmtType srctype = UserFmtUByte; + ALbuffer *albuf; + + if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid format 0x%04x", format); + else + { + ALsizei unpack_align, align; + ALsizei byte_align; + ALsizei frame_size; + ALsizei num_chans; + + unpack_align = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign); + align = SanitizeAlignment(srctype, unpack_align); + if(UNLIKELY(align < 1)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid unpack alignment %d", unpack_align); + else if(UNLIKELY((long)srcchannels != (long)albuf->FmtChannels || + srctype != albuf->OriginalType)) + alSetError(context.get(), AL_INVALID_ENUM, "Unpacking data with mismatched format"); + else if(UNLIKELY(align != albuf->OriginalAlign)) + alSetError(context.get(), AL_INVALID_VALUE, + "Unpacking data with alignment %u does not match original alignment %u", + align, albuf->OriginalAlign); + else if(UNLIKELY(albuf->MappedAccess != 0)) + alSetError(context.get(), AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u", + buffer); + else + { + num_chans = ChannelsFromFmt(albuf->FmtChannels); + frame_size = num_chans * BytesFromFmt(albuf->FmtType); + if(albuf->OriginalType == UserFmtIMA4) + byte_align = ((align-1)/2 + 4) * num_chans; + else if(albuf->OriginalType == UserFmtMSADPCM) + byte_align = ((align-2)/2 + 7) * num_chans; + else + byte_align = align * frame_size; + + if(UNLIKELY(offset < 0 || length < 0 || offset > albuf->OriginalSize || + length > albuf->OriginalSize-offset)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid data sub-range %d+%d on buffer %u", + offset, length, buffer); + else if(UNLIKELY((offset%byte_align) != 0)) + alSetError(context.get(), AL_INVALID_VALUE, + "Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)", + offset, byte_align, align); + else if(UNLIKELY((length%byte_align) != 0)) + alSetError(context.get(), AL_INVALID_VALUE, + "Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)", + length, byte_align, align); + else + { + /* offset -> byte offset, length -> sample count */ + offset = offset/byte_align * align * frame_size; + length = length/byte_align * align; + + void *dst = static_cast(albuf->data) + offset; + if(srctype == UserFmtIMA4 && albuf->FmtType == FmtShort) + Convert_ALshort_ALima4(static_cast(dst), + static_cast(data), num_chans, length, align); + else if(srctype == UserFmtMSADPCM && albuf->FmtType == FmtShort) + Convert_ALshort_ALmsadpcm(static_cast(dst), + static_cast(data), num_chans, length, align); + else + { + assert((long)srctype == (long)albuf->FmtType); + memcpy(dst, data, length*frame_size); + } + } + } + } +} + + +AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint UNUSED(buffer), + ALuint UNUSED(samplerate), ALenum UNUSED(internalformat), ALsizei UNUSED(samples), + ALenum UNUSED(channels), ALenum UNUSED(type), const ALvoid *UNUSED(data)) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + alSetError(context.get(), AL_INVALID_OPERATION, "alBufferSamplesSOFT not supported"); +} + +AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint UNUSED(buffer), + ALsizei UNUSED(offset), ALsizei UNUSED(samples), + ALenum UNUSED(channels), ALenum UNUSED(type), const ALvoid *UNUSED(data)) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + alSetError(context.get(), AL_INVALID_OPERATION, "alBufferSubSamplesSOFT not supported"); +} + +AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint UNUSED(buffer), + ALsizei UNUSED(offset), ALsizei UNUSED(samples), + ALenum UNUSED(channels), ALenum UNUSED(type), ALvoid *UNUSED(data)) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + alSetError(context.get(), AL_INVALID_OPERATION, "alGetBufferSamplesSOFT not supported"); +} + +AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum UNUSED(format)) +{ + ContextRef context{GetContextRef()}; + if(!context) return AL_FALSE; + + alSetError(context.get(), AL_INVALID_OPERATION, "alIsBufferFormatSupportedSOFT not supported"); + return AL_FALSE; +} + + +AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(value)) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); + } +} + + +AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat UNUSED(value1), ALfloat UNUSED(value2), ALfloat UNUSED(value3)) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); + } +} + + +AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!values)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); + } +} + + +AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf; + if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else switch(param) + { + case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: + if(UNLIKELY(value < 0)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid unpack block alignment %d", value); + else + ATOMIC_STORE_SEQ(&albuf->UnpackAlign, value); + break; + + case AL_PACK_BLOCK_ALIGNMENT_SOFT: + if(UNLIKELY(value < 0)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid pack block alignment %d", value); + else + ATOMIC_STORE_SEQ(&albuf->PackAlign, value); + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); + } +} + + +AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint UNUSED(value1), ALint UNUSED(value2), ALint UNUSED(value3)) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); + } +} + + +AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values) +{ + if(values) + { + switch(param) + { + case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: + case AL_PACK_BLOCK_ALIGNMENT_SOFT: + alBufferi(buffer, param, values[0]); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf; + if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!values)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_LOOP_POINTS_SOFT: + if(UNLIKELY(ReadRef(&albuf->ref) != 0)) + alSetError(context.get(), AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points", + buffer); + else if(UNLIKELY(values[0] >= values[1] || values[0] < 0 || values[1] > albuf->SampleLen)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid loop point range %d -> %d o buffer %u", + values[0], values[1], buffer); + else + { + albuf->LoopStart = values[0]; + albuf->LoopEnd = values[1]; + } + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", + param); + } +} + + +AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf; + if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!value)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); + } +} + + +AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!value1 || !value2 || !value3)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); + } +} + + +AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values) +{ + switch(param) + { + case AL_SEC_LENGTH_SOFT: + alGetBufferf(buffer, param, values); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!values)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); + } +} + + +AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf; + if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!value)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_FREQUENCY: + *value = albuf->Frequency; + break; + + case AL_BITS: + *value = BytesFromFmt(albuf->FmtType) * 8; + break; + + case AL_CHANNELS: + *value = ChannelsFromFmt(albuf->FmtChannels); + break; + + case AL_SIZE: + *value = albuf->SampleLen * FrameSizeFromFmt(albuf->FmtChannels, + albuf->FmtType); + break; + + case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: + *value = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign); + break; + + case AL_PACK_BLOCK_ALIGNMENT_SOFT: + *value = ATOMIC_LOAD_SEQ(&albuf->PackAlign); + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); + } +} + + +AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!value1 || !value2 || !value3)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); + } +} + + +AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values) +{ + switch(param) + { + case AL_FREQUENCY: + case AL_BITS: + case AL_CHANNELS: + case AL_SIZE: + case AL_INTERNAL_FORMAT_SOFT: + case AL_BYTE_LENGTH_SOFT: + case AL_SAMPLE_LENGTH_SOFT: + case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: + case AL_PACK_BLOCK_ALIGNMENT_SOFT: + alGetBufferi(buffer, param, values); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf; + if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!values)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_LOOP_POINTS_SOFT: + values[0] = albuf->LoopStart; + values[1] = albuf->LoopEnd; + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", + param); + } +} + + +static const ALchar *NameFromUserFmtType(enum UserFmtType type) +{ + switch(type) + { + case UserFmtUByte: return "Unsigned Byte"; + case UserFmtShort: return "Signed Short"; + case UserFmtFloat: return "Float32"; + case UserFmtDouble: return "Float64"; + case UserFmtMulaw: return "muLaw"; + case UserFmtAlaw: return "aLaw"; + case UserFmtIMA4: return "IMA4 ADPCM"; + case UserFmtMSADPCM: return "MSADPCM"; + } + return ""; +} + +/* + * LoadData + * + * Loads the specified data into the buffer, using the specified format. + */ +static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALbitfieldSOFT access) +{ + enum FmtChannels DstChannels = FmtMono; + enum FmtType DstType = FmtUByte; + ALsizei NumChannels, FrameSize; + ALsizei SrcByteAlign; + ALsizei unpackalign; + ALsizei newsize; + ALsizei frames; + ALsizei align; + + if(UNLIKELY(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)) + SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer %u", + ALBuf->id); + + /* Currently no channel configurations need to be converted. */ + switch(SrcChannels) + { + case UserFmtMono: DstChannels = FmtMono; break; + case UserFmtStereo: DstChannels = FmtStereo; break; + case UserFmtRear: DstChannels = FmtRear; break; + case UserFmtQuad: DstChannels = FmtQuad; break; + case UserFmtX51: DstChannels = FmtX51; break; + case UserFmtX61: DstChannels = FmtX61; break; + case UserFmtX71: DstChannels = FmtX71; break; + case UserFmtBFormat2D: DstChannels = FmtBFormat2D; break; + case UserFmtBFormat3D: DstChannels = FmtBFormat3D; break; + } + if(UNLIKELY((long)SrcChannels != (long)DstChannels)) + SETERR_RETURN(context, AL_INVALID_ENUM,, "Invalid format"); + + /* IMA4 and MSADPCM convert to 16-bit short. */ + switch(SrcType) + { + case UserFmtUByte: DstType = FmtUByte; break; + case UserFmtShort: DstType = FmtShort; break; + case UserFmtFloat: DstType = FmtFloat; break; + case UserFmtDouble: DstType = FmtDouble; break; + case UserFmtAlaw: DstType = FmtAlaw; break; + case UserFmtMulaw: DstType = FmtMulaw; break; + case UserFmtIMA4: DstType = FmtShort; break; + case UserFmtMSADPCM: DstType = FmtShort; break; + } + + /* TODO: Currently we can only map samples when they're not converted. To + * allow it would need some kind of double-buffering to hold onto a copy of + * the original data. + */ + if((access&MAP_READ_WRITE_FLAGS)) + { + if(UNLIKELY((long)SrcType != (long)DstType)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "%s samples cannot be mapped", + NameFromUserFmtType(SrcType)); + } + + unpackalign = ATOMIC_LOAD_SEQ(&ALBuf->UnpackAlign); + if(UNLIKELY((align=SanitizeAlignment(SrcType, unpackalign)) < 1)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid unpack alignment %d for %s samples", + unpackalign, NameFromUserFmtType(SrcType)); + + if((access&AL_PRESERVE_DATA_BIT_SOFT)) + { + /* Can only preserve data with the same format and alignment. */ + if(UNLIKELY(ALBuf->FmtChannels != DstChannels || ALBuf->OriginalType != SrcType)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched format"); + if(UNLIKELY(ALBuf->OriginalAlign != align)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched alignment"); + } + + /* Convert the input/source size in bytes to sample frames using the unpack + * block alignment. + */ + if(SrcType == UserFmtIMA4) + SrcByteAlign = ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels); + else if(SrcType == UserFmtMSADPCM) + SrcByteAlign = ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels); + else + SrcByteAlign = align * FrameSizeFromUserFmt(SrcChannels, SrcType); + if(UNLIKELY((size%SrcByteAlign) != 0)) + SETERR_RETURN(context, AL_INVALID_VALUE,, + "Data size %d is not a multiple of frame size %d (%d unpack alignment)", + size, SrcByteAlign, align); + + if(UNLIKELY(size / SrcByteAlign > INT_MAX / align)) + SETERR_RETURN(context, AL_OUT_OF_MEMORY,, + "Buffer size overflow, %d blocks x %d samples per block", size/SrcByteAlign, align); + frames = size / SrcByteAlign * align; + + /* Convert the sample frames to the number of bytes needed for internal + * storage. + */ + NumChannels = ChannelsFromFmt(DstChannels); + FrameSize = NumChannels * BytesFromFmt(DstType); + if(UNLIKELY(frames > INT_MAX/FrameSize)) + SETERR_RETURN(context, AL_OUT_OF_MEMORY,, + "Buffer size overflow, %d frames x %d bytes per frame", frames, FrameSize); + newsize = frames*FrameSize; + + /* Round up to the next 16-byte multiple. This could reallocate only when + * increasing or the new size is less than half the current, but then the + * buffer's AL_SIZE would not be very reliable for accounting buffer memory + * usage, and reporting the real size could cause problems for apps that + * use AL_SIZE to try to get the buffer's play length. + */ + if(LIKELY(newsize <= INT_MAX-15)) + newsize = (newsize+15) & ~0xf; + if(newsize != ALBuf->BytesAlloc) + { + void *temp = al_malloc(16, (size_t)newsize); + if(UNLIKELY(!temp && newsize)) + SETERR_RETURN(context, AL_OUT_OF_MEMORY,, "Failed to allocate %d bytes of storage", + newsize); + if((access&AL_PRESERVE_DATA_BIT_SOFT)) + { + ALsizei tocopy = mini(newsize, ALBuf->BytesAlloc); + if(tocopy > 0) memcpy(temp, ALBuf->data, tocopy); + } + al_free(ALBuf->data); + ALBuf->data = temp; + ALBuf->BytesAlloc = newsize; + } + + if(SrcType == UserFmtIMA4) + { + assert(DstType == FmtShort); + if(data != nullptr && ALBuf->data != nullptr) + Convert_ALshort_ALima4(static_cast(ALBuf->data), + static_cast(data), NumChannels, frames, align); + ALBuf->OriginalAlign = align; + } + else if(SrcType == UserFmtMSADPCM) + { + assert(DstType == FmtShort); + if(data != nullptr && ALBuf->data != nullptr) + Convert_ALshort_ALmsadpcm(static_cast(ALBuf->data), + static_cast(data), NumChannels, frames, align); + ALBuf->OriginalAlign = align; + } + else + { + assert((long)SrcType == (long)DstType); + if(data != nullptr && ALBuf->data != nullptr) + memcpy(ALBuf->data, data, frames*FrameSize); + ALBuf->OriginalAlign = 1; + } + ALBuf->OriginalSize = size; + ALBuf->OriginalType = SrcType; + + ALBuf->Frequency = freq; + ALBuf->FmtChannels = DstChannels; + ALBuf->FmtType = DstType; + ALBuf->Access = access; + + ALBuf->SampleLen = frames; + ALBuf->LoopStart = 0; + ALBuf->LoopEnd = ALBuf->SampleLen; +} + + +ALsizei BytesFromUserFmt(enum UserFmtType type) +{ + switch(type) + { + case UserFmtUByte: return sizeof(ALubyte); + case UserFmtShort: return sizeof(ALshort); + case UserFmtFloat: return sizeof(ALfloat); + case UserFmtDouble: return sizeof(ALdouble); + case UserFmtMulaw: return sizeof(ALubyte); + case UserFmtAlaw: return sizeof(ALubyte); + case UserFmtIMA4: break; /* not handled here */ + case UserFmtMSADPCM: break; /* not handled here */ + } + return 0; +} +ALsizei ChannelsFromUserFmt(enum UserFmtChannels chans) +{ + switch(chans) + { + case UserFmtMono: return 1; + case UserFmtStereo: return 2; + case UserFmtRear: return 2; + case UserFmtQuad: return 4; + case UserFmtX51: return 6; + case UserFmtX61: return 7; + case UserFmtX71: return 8; + case UserFmtBFormat2D: return 3; + case UserFmtBFormat3D: return 4; + } + return 0; +} +static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, + enum UserFmtType *type) +{ + struct FormatMap { + ALenum format; + UserFmtChannels channels; + UserFmtType type; + }; + static const std::array list{{ + { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte }, + { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort }, + { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat }, + { AL_FORMAT_MONO_DOUBLE_EXT, UserFmtMono, UserFmtDouble }, + { AL_FORMAT_MONO_IMA4, UserFmtMono, UserFmtIMA4 }, + { AL_FORMAT_MONO_MSADPCM_SOFT, UserFmtMono, UserFmtMSADPCM }, + { AL_FORMAT_MONO_MULAW, UserFmtMono, UserFmtMulaw }, + { AL_FORMAT_MONO_ALAW_EXT, UserFmtMono, UserFmtAlaw }, + + { AL_FORMAT_STEREO8, UserFmtStereo, UserFmtUByte }, + { AL_FORMAT_STEREO16, UserFmtStereo, UserFmtShort }, + { AL_FORMAT_STEREO_FLOAT32, UserFmtStereo, UserFmtFloat }, + { AL_FORMAT_STEREO_DOUBLE_EXT, UserFmtStereo, UserFmtDouble }, + { AL_FORMAT_STEREO_IMA4, UserFmtStereo, UserFmtIMA4 }, + { AL_FORMAT_STEREO_MSADPCM_SOFT, UserFmtStereo, UserFmtMSADPCM }, + { AL_FORMAT_STEREO_MULAW, UserFmtStereo, UserFmtMulaw }, + { AL_FORMAT_STEREO_ALAW_EXT, UserFmtStereo, UserFmtAlaw }, + + { AL_FORMAT_REAR8, UserFmtRear, UserFmtUByte }, + { AL_FORMAT_REAR16, UserFmtRear, UserFmtShort }, + { AL_FORMAT_REAR32, UserFmtRear, UserFmtFloat }, + { AL_FORMAT_REAR_MULAW, UserFmtRear, UserFmtMulaw }, + + { AL_FORMAT_QUAD8_LOKI, UserFmtQuad, UserFmtUByte }, + { AL_FORMAT_QUAD16_LOKI, UserFmtQuad, UserFmtShort }, + + { AL_FORMAT_QUAD8, UserFmtQuad, UserFmtUByte }, + { AL_FORMAT_QUAD16, UserFmtQuad, UserFmtShort }, + { AL_FORMAT_QUAD32, UserFmtQuad, UserFmtFloat }, + { AL_FORMAT_QUAD_MULAW, UserFmtQuad, UserFmtMulaw }, + + { AL_FORMAT_51CHN8, UserFmtX51, UserFmtUByte }, + { AL_FORMAT_51CHN16, UserFmtX51, UserFmtShort }, + { AL_FORMAT_51CHN32, UserFmtX51, UserFmtFloat }, + { AL_FORMAT_51CHN_MULAW, UserFmtX51, UserFmtMulaw }, + + { AL_FORMAT_61CHN8, UserFmtX61, UserFmtUByte }, + { AL_FORMAT_61CHN16, UserFmtX61, UserFmtShort }, + { AL_FORMAT_61CHN32, UserFmtX61, UserFmtFloat }, + { AL_FORMAT_61CHN_MULAW, UserFmtX61, UserFmtMulaw }, + + { AL_FORMAT_71CHN8, UserFmtX71, UserFmtUByte }, + { AL_FORMAT_71CHN16, UserFmtX71, UserFmtShort }, + { AL_FORMAT_71CHN32, UserFmtX71, UserFmtFloat }, + { AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw }, + + { AL_FORMAT_BFORMAT2D_8, UserFmtBFormat2D, UserFmtUByte }, + { AL_FORMAT_BFORMAT2D_16, UserFmtBFormat2D, UserFmtShort }, + { AL_FORMAT_BFORMAT2D_FLOAT32, UserFmtBFormat2D, UserFmtFloat }, + { AL_FORMAT_BFORMAT2D_MULAW, UserFmtBFormat2D, UserFmtMulaw }, + + { AL_FORMAT_BFORMAT3D_8, UserFmtBFormat3D, UserFmtUByte }, + { AL_FORMAT_BFORMAT3D_16, UserFmtBFormat3D, UserFmtShort }, + { AL_FORMAT_BFORMAT3D_FLOAT32, UserFmtBFormat3D, UserFmtFloat }, + { AL_FORMAT_BFORMAT3D_MULAW, UserFmtBFormat3D, UserFmtMulaw }, + }}; + + for(const auto &fmt : list) + { + if(fmt.format == format) + { + *chans = fmt.channels; + *type = fmt.type; + return AL_TRUE; + } + } + + return AL_FALSE; +} + +ALsizei BytesFromFmt(enum FmtType type) +{ + switch(type) + { + case FmtUByte: return sizeof(ALubyte); + case FmtShort: return sizeof(ALshort); + case FmtFloat: return sizeof(ALfloat); + case FmtDouble: return sizeof(ALdouble); + case FmtMulaw: return sizeof(ALubyte); + case FmtAlaw: return sizeof(ALubyte); + } + return 0; +} +ALsizei ChannelsFromFmt(enum FmtChannels chans) +{ + switch(chans) + { + case FmtMono: return 1; + case FmtStereo: return 2; + case FmtRear: return 2; + case FmtQuad: return 4; + case FmtX51: return 6; + case FmtX61: return 7; + case FmtX71: return 8; + case FmtBFormat2D: return 3; + case FmtBFormat3D: return 4; + } + return 0; +} + +static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align) +{ + if(align < 0) + return 0; + + if(align == 0) + { + if(type == UserFmtIMA4) + { + /* Here is where things vary: + * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel + * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel + */ + return 65; + } + if(type == UserFmtMSADPCM) + return 64; + return 1; + } + + if(type == UserFmtIMA4) + { + /* IMA4 block alignment must be a multiple of 8, plus 1. */ + if((align&7) == 1) return align; + return 0; + } + if(type == UserFmtMSADPCM) + { + /* MSADPCM block alignment must be a multiple of 2. */ + if((align&1) == 0) return align; + return 0; + } + + return align; +} + + +static ALbuffer *AllocBuffer(ALCcontext *context) +{ + ALCdevice *device = context->Device; + BufferSubList *sublist, *subend; + ALbuffer *buffer = nullptr; + ALsizei lidx = 0; + ALsizei slidx; + + std::unique_lock buflock{device->BufferLock}; + + sublist = VECTOR_BEGIN(device->BufferList); + subend = VECTOR_END(device->BufferList); + for(;sublist != subend;++sublist) + { + if(sublist->FreeMask) + { + slidx = CTZ64(sublist->FreeMask); + buffer = sublist->Buffers + slidx; + break; + } + ++lidx; + } + if(UNLIKELY(!buffer)) + { + const BufferSubList empty_sublist = { 0, nullptr }; + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(VECTOR_SIZE(device->BufferList) >= 1<<25)) + { + buflock.unlock(); + alSetError(context, AL_OUT_OF_MEMORY, "Too many buffers allocated"); + return nullptr; + } + lidx = (ALsizei)VECTOR_SIZE(device->BufferList); + VECTOR_PUSH_BACK(device->BufferList, empty_sublist); + sublist = &VECTOR_BACK(device->BufferList); + sublist->FreeMask = ~U64(0); + sublist->Buffers = reinterpret_cast(al_calloc(16, sizeof(ALbuffer)*64)); + if(UNLIKELY(!sublist->Buffers)) + { + VECTOR_POP_BACK(device->BufferList); + buflock.unlock(); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate buffer batch"); + return nullptr; + } + + slidx = 0; + buffer = sublist->Buffers + slidx; + } + + memset(buffer, 0, sizeof(*buffer)); + + /* Add 1 to avoid buffer ID 0. */ + buffer->id = ((lidx<<6) | slidx) + 1; + + sublist->FreeMask &= ~(U64(1)<id - 1; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; + + al_free(buffer->data); + memset(buffer, 0, sizeof(*buffer)); + + VECTOR_ELEM(device->BufferList, lidx).FreeMask |= U64(1) << slidx; +} + + +/* + * ReleaseALBuffers() + * + * INTERNAL: Called to destroy any buffers that still exist on the device + */ +ALvoid ReleaseALBuffers(ALCdevice *device) +{ + BufferSubList *sublist = VECTOR_BEGIN(device->BufferList); + BufferSubList *subend = VECTOR_END(device->BufferList); + size_t leftover = 0; + for(;sublist != subend;++sublist) + { + ALuint64 usemask = ~sublist->FreeMask; + while(usemask) + { + ALsizei idx = CTZ64(usemask); + ALbuffer *buffer = sublist->Buffers + idx; + + al_free(buffer->data); + memset(buffer, 0, sizeof(*buffer)); + ++leftover; + + usemask &= ~(U64(1) << idx); + } + sublist->FreeMask = ~usemask; + } + if(leftover > 0) + WARN("(%p) Deleted " SZFMT " Buffer%s\n", device, leftover, (leftover==1)?"":"s"); +} -- cgit v1.2.3 From 4d422dfb24ac4668050ad7266198966788fac9f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Oct 2018 12:00:02 -0700 Subject: Fix some backup atomic macros --- common/atomic.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/atomic.h b/common/atomic.h index d28298f2..17e616bb 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -163,26 +163,26 @@ enum almemory_order { #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) #define WRAP_ADD(S, ret, dest, incr) __asm__ __volatile__( \ - "lock; xadd"S" %0,(%1)" \ + "lock; xadd" S " %0,(%1)" \ : "=r" (ret) \ : "r" (dest), "0" (incr) \ : "memory" \ ) #define WRAP_SUB(S, ret, dest, decr) __asm__ __volatile__( \ - "lock; xadd"S" %0,(%1)" \ + "lock; xadd" S " %0,(%1)" \ : "=r" (ret) \ : "r" (dest), "0" (-(decr)) \ : "memory" \ ) #define WRAP_XCHG(S, ret, dest, newval) __asm__ __volatile__( \ - "lock; xchg"S" %0,(%1)" \ + "lock; xchg" S " %0,(%1)" \ : "=r" (ret) \ : "r" (dest), "0" (newval) \ : "memory" \ ) #define WRAP_CMPXCHG(S, ret, dest, oldval, newval) __asm__ __volatile__( \ - "lock; cmpxchg"S" %2,(%1)" \ + "lock; cmpxchg" S " %2,(%1)" \ : "=a" (ret) \ : "r" (dest), "r" (newval), "0" (oldval) \ : "memory" \ -- cgit v1.2.3 From 77bac8eeaa25ca499515813640d09ccc2c511d51 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Oct 2018 12:01:07 -0700 Subject: Add a missing include --- OpenAL32/alBuffer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index 94de991c..49991633 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -28,6 +28,7 @@ #include #endif +#include #include #include -- cgit v1.2.3 From 9dba90fa207cc5323c3f687bbb34d4adc3a0e3f6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Oct 2018 13:00:08 -0700 Subject: Avoid assigning in an if statement --- OpenAL32/alBuffer.cpp | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index 49991633..25fe2d65 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -181,9 +181,9 @@ AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const enum UserFmtChannels srcchannels = UserFmtMono; enum UserFmtType srctype = UserFmtUByte; - ALbuffer *albuf; - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == nullptr)) + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(size < 0)) alSetError(context.get(), AL_INVALID_VALUE, "Negative storage size %d", size); @@ -209,8 +209,8 @@ AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei ALCdevice *device = context->Device; std::lock_guard _{device->BufferLock}; - ALbuffer *albuf; - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == nullptr)) + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY((access&INVALID_MAP_FLAGS) != 0)) alSetError(context.get(), AL_INVALID_VALUE, "Invalid map flags 0x%x", access&INVALID_MAP_FLAGS); @@ -259,8 +259,8 @@ AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer) ALCdevice *device = context->Device; std::lock_guard _{device->BufferLock}; - ALbuffer *albuf; - if((albuf=LookupBuffer(device, buffer)) == nullptr) + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(albuf->MappedAccess == 0) alSetError(context.get(), AL_INVALID_OPERATION, "Unmapping unmapped buffer %u", buffer); @@ -280,8 +280,8 @@ AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, A ALCdevice *device = context->Device; std::lock_guard _{device->BufferLock}; - ALbuffer *albuf; - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == nullptr)) + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT))) alSetError(context.get(), AL_INVALID_OPERATION, @@ -312,9 +312,9 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons enum UserFmtChannels srcchannels = UserFmtMono; enum UserFmtType srctype = UserFmtUByte; - ALbuffer *albuf; - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == nullptr)) + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)) alSetError(context.get(), AL_INVALID_ENUM, "Invalid format 0x%04x", format); @@ -490,8 +490,8 @@ AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) ALCdevice *device = context->Device; std::lock_guard _{device->BufferLock}; - ALbuffer *albuf; - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == nullptr)) + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else switch(param) { @@ -552,8 +552,8 @@ AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *val ALCdevice *device = context->Device; std::lock_guard _{device->BufferLock}; - ALbuffer *albuf; - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == nullptr)) + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!values)) alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); @@ -588,8 +588,8 @@ AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *val ALCdevice *device = context->Device; std::lock_guard _{device->BufferLock}; - ALbuffer *albuf; - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == nullptr)) + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!value)) alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); @@ -656,8 +656,8 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value ALCdevice *device = context->Device; std::lock_guard _{device->BufferLock}; - ALbuffer *albuf; - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == nullptr)) + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!value)) alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); @@ -737,8 +737,8 @@ AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values ALCdevice *device = context->Device; std::lock_guard _{device->BufferLock}; - ALbuffer *albuf; - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == nullptr)) + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!values)) alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); -- cgit v1.2.3 From 0e7986eaa826401b5ef80b033583eb9f24dbf813 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Oct 2018 13:20:37 -0700 Subject: Move some extern inline declarations to C --- Alc/ALc.c | 8 ++++++++ OpenAL32/alBuffer.cpp | 5 ----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 8bf2e1da..7d28b976 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1566,6 +1566,14 @@ void SetDefaultChannelOrder(ALCdevice *device) extern inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS], enum Channel chan); extern inline ALint GetChannelIdxByName(const RealMixParams *real, enum Channel chan); +/* NOTE: These shouldn't really be here, but C++ (alBuffer.cpp) won't turn + * these extern inline declarations into callable functions. + */ +extern inline void LockBufferList(ALCdevice *device); +extern inline void UnlockBufferList(ALCdevice *device); +extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type); +extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); + /* ALCcontext_DeferUpdates * diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index 25fe2d65..74f108e5 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -39,11 +39,6 @@ #include "sample_cvt.h" -extern inline void LockBufferList(ALCdevice *device); -extern inline void UnlockBufferList(ALCdevice *device); -extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type); -extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); - static ALbuffer *AllocBuffer(ALCcontext *context); static void FreeBuffer(ALCdevice *device, ALbuffer *buffer); static const ALchar *NameFromUserFmtType(enum UserFmtType type); -- cgit v1.2.3 From de275408fac8317d1e4148b8870c3cdf98b84569 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Oct 2018 13:31:14 -0700 Subject: Make a const array constexpr --- OpenAL32/alBuffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index 74f108e5..dc07e147 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -970,7 +970,7 @@ static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, UserFmtChannels channels; UserFmtType type; }; - static const std::array list{{ + static constexpr std::array list{{ { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte }, { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort }, { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat }, -- cgit v1.2.3 From d41fbd5c2de69e47e1419a158ff3cfeae5769baf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Oct 2018 20:09:14 -0700 Subject: Convert the PulseAudio backend to C++ --- Alc/backends/pulseaudio.c | 1920 ------------------------------------------- Alc/backends/pulseaudio.cpp | 1904 ++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 1905 insertions(+), 1921 deletions(-) delete mode 100644 Alc/backends/pulseaudio.c create mode 100644 Alc/backends/pulseaudio.cpp diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c deleted file mode 100644 index b34d7abc..00000000 --- a/Alc/backends/pulseaudio.c +++ /dev/null @@ -1,1920 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2009 by Konstantinos Natsakis - * Copyright (C) 2010 by Chris Robinson - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include - -#include "alMain.h" -#include "alu.h" -#include "alconfig.h" -#include "threads.h" -#include "compat.h" - -#include "backends/base.h" - -#include - -#if PA_API_VERSION == 12 - -#ifdef HAVE_DYNLOAD -static void *pa_handle; -#define MAKE_FUNC(x) static __typeof(x) * p##x -MAKE_FUNC(pa_context_unref); -MAKE_FUNC(pa_sample_spec_valid); -MAKE_FUNC(pa_frame_size); -MAKE_FUNC(pa_stream_drop); -MAKE_FUNC(pa_strerror); -MAKE_FUNC(pa_context_get_state); -MAKE_FUNC(pa_stream_get_state); -MAKE_FUNC(pa_threaded_mainloop_signal); -MAKE_FUNC(pa_stream_peek); -MAKE_FUNC(pa_threaded_mainloop_wait); -MAKE_FUNC(pa_threaded_mainloop_unlock); -MAKE_FUNC(pa_threaded_mainloop_in_thread); -MAKE_FUNC(pa_context_new); -MAKE_FUNC(pa_threaded_mainloop_stop); -MAKE_FUNC(pa_context_disconnect); -MAKE_FUNC(pa_threaded_mainloop_start); -MAKE_FUNC(pa_threaded_mainloop_get_api); -MAKE_FUNC(pa_context_set_state_callback); -MAKE_FUNC(pa_stream_write); -MAKE_FUNC(pa_xfree); -MAKE_FUNC(pa_stream_connect_record); -MAKE_FUNC(pa_stream_connect_playback); -MAKE_FUNC(pa_stream_readable_size); -MAKE_FUNC(pa_stream_writable_size); -MAKE_FUNC(pa_stream_is_corked); -MAKE_FUNC(pa_stream_cork); -MAKE_FUNC(pa_stream_is_suspended); -MAKE_FUNC(pa_stream_get_device_name); -MAKE_FUNC(pa_stream_get_latency); -MAKE_FUNC(pa_path_get_filename); -MAKE_FUNC(pa_get_binary_name); -MAKE_FUNC(pa_threaded_mainloop_free); -MAKE_FUNC(pa_context_errno); -MAKE_FUNC(pa_xmalloc); -MAKE_FUNC(pa_stream_unref); -MAKE_FUNC(pa_threaded_mainloop_accept); -MAKE_FUNC(pa_stream_set_write_callback); -MAKE_FUNC(pa_threaded_mainloop_new); -MAKE_FUNC(pa_context_connect); -MAKE_FUNC(pa_stream_set_buffer_attr); -MAKE_FUNC(pa_stream_get_buffer_attr); -MAKE_FUNC(pa_stream_get_sample_spec); -MAKE_FUNC(pa_stream_get_time); -MAKE_FUNC(pa_stream_set_read_callback); -MAKE_FUNC(pa_stream_set_state_callback); -MAKE_FUNC(pa_stream_set_moved_callback); -MAKE_FUNC(pa_stream_set_underflow_callback); -MAKE_FUNC(pa_stream_new_with_proplist); -MAKE_FUNC(pa_stream_disconnect); -MAKE_FUNC(pa_threaded_mainloop_lock); -MAKE_FUNC(pa_channel_map_init_auto); -MAKE_FUNC(pa_channel_map_parse); -MAKE_FUNC(pa_channel_map_snprint); -MAKE_FUNC(pa_channel_map_equal); -MAKE_FUNC(pa_context_get_server_info); -MAKE_FUNC(pa_context_get_sink_info_by_name); -MAKE_FUNC(pa_context_get_sink_info_list); -MAKE_FUNC(pa_context_get_source_info_by_name); -MAKE_FUNC(pa_context_get_source_info_list); -MAKE_FUNC(pa_operation_get_state); -MAKE_FUNC(pa_operation_unref); -MAKE_FUNC(pa_proplist_new); -MAKE_FUNC(pa_proplist_free); -MAKE_FUNC(pa_proplist_set); -MAKE_FUNC(pa_channel_map_superset); -MAKE_FUNC(pa_stream_set_buffer_attr_callback); -MAKE_FUNC(pa_stream_begin_write); -#undef MAKE_FUNC - -#define pa_context_unref ppa_context_unref -#define pa_sample_spec_valid ppa_sample_spec_valid -#define pa_frame_size ppa_frame_size -#define pa_stream_drop ppa_stream_drop -#define pa_strerror ppa_strerror -#define pa_context_get_state ppa_context_get_state -#define pa_stream_get_state ppa_stream_get_state -#define pa_threaded_mainloop_signal ppa_threaded_mainloop_signal -#define pa_stream_peek ppa_stream_peek -#define pa_threaded_mainloop_wait ppa_threaded_mainloop_wait -#define pa_threaded_mainloop_unlock ppa_threaded_mainloop_unlock -#define pa_threaded_mainloop_in_thread ppa_threaded_mainloop_in_thread -#define pa_context_new ppa_context_new -#define pa_threaded_mainloop_stop ppa_threaded_mainloop_stop -#define pa_context_disconnect ppa_context_disconnect -#define pa_threaded_mainloop_start ppa_threaded_mainloop_start -#define pa_threaded_mainloop_get_api ppa_threaded_mainloop_get_api -#define pa_context_set_state_callback ppa_context_set_state_callback -#define pa_stream_write ppa_stream_write -#define pa_xfree ppa_xfree -#define pa_stream_connect_record ppa_stream_connect_record -#define pa_stream_connect_playback ppa_stream_connect_playback -#define pa_stream_readable_size ppa_stream_readable_size -#define pa_stream_writable_size ppa_stream_writable_size -#define pa_stream_is_corked ppa_stream_is_corked -#define pa_stream_cork ppa_stream_cork -#define pa_stream_is_suspended ppa_stream_is_suspended -#define pa_stream_get_device_name ppa_stream_get_device_name -#define pa_stream_get_latency ppa_stream_get_latency -#define pa_path_get_filename ppa_path_get_filename -#define pa_get_binary_name ppa_get_binary_name -#define pa_threaded_mainloop_free ppa_threaded_mainloop_free -#define pa_context_errno ppa_context_errno -#define pa_xmalloc ppa_xmalloc -#define pa_stream_unref ppa_stream_unref -#define pa_threaded_mainloop_accept ppa_threaded_mainloop_accept -#define pa_stream_set_write_callback ppa_stream_set_write_callback -#define pa_threaded_mainloop_new ppa_threaded_mainloop_new -#define pa_context_connect ppa_context_connect -#define pa_stream_set_buffer_attr ppa_stream_set_buffer_attr -#define pa_stream_get_buffer_attr ppa_stream_get_buffer_attr -#define pa_stream_get_sample_spec ppa_stream_get_sample_spec -#define pa_stream_get_time ppa_stream_get_time -#define pa_stream_set_read_callback ppa_stream_set_read_callback -#define pa_stream_set_state_callback ppa_stream_set_state_callback -#define pa_stream_set_moved_callback ppa_stream_set_moved_callback -#define pa_stream_set_underflow_callback ppa_stream_set_underflow_callback -#define pa_stream_new_with_proplist ppa_stream_new_with_proplist -#define pa_stream_disconnect ppa_stream_disconnect -#define pa_threaded_mainloop_lock ppa_threaded_mainloop_lock -#define pa_channel_map_init_auto ppa_channel_map_init_auto -#define pa_channel_map_parse ppa_channel_map_parse -#define pa_channel_map_snprint ppa_channel_map_snprint -#define pa_channel_map_equal ppa_channel_map_equal -#define pa_context_get_server_info ppa_context_get_server_info -#define pa_context_get_sink_info_by_name ppa_context_get_sink_info_by_name -#define pa_context_get_sink_info_list ppa_context_get_sink_info_list -#define pa_context_get_source_info_by_name ppa_context_get_source_info_by_name -#define pa_context_get_source_info_list ppa_context_get_source_info_list -#define pa_operation_get_state ppa_operation_get_state -#define pa_operation_unref ppa_operation_unref -#define pa_proplist_new ppa_proplist_new -#define pa_proplist_free ppa_proplist_free -#define pa_proplist_set ppa_proplist_set -#define pa_channel_map_superset ppa_channel_map_superset -#define pa_stream_set_buffer_attr_callback ppa_stream_set_buffer_attr_callback -#define pa_stream_begin_write ppa_stream_begin_write - -#endif - -static ALCboolean pulse_load(void) -{ - ALCboolean ret = ALC_TRUE; -#ifdef HAVE_DYNLOAD - if(!pa_handle) - { - al_string missing_funcs = AL_STRING_INIT_STATIC(); - -#ifdef _WIN32 -#define PALIB "libpulse-0.dll" -#elif defined(__APPLE__) && defined(__MACH__) -#define PALIB "libpulse.0.dylib" -#else -#define PALIB "libpulse.so.0" -#endif - pa_handle = LoadLib(PALIB); - if(!pa_handle) - { - WARN("Failed to load %s\n", PALIB); - return ALC_FALSE; - } - -#define LOAD_FUNC(x) do { \ - p##x = GetSymbol(pa_handle, #x); \ - if(!(p##x)) { \ - ret = ALC_FALSE; \ - alstr_append_cstr(&missing_funcs, "\n" #x); \ - } \ -} while(0) - LOAD_FUNC(pa_context_unref); - LOAD_FUNC(pa_sample_spec_valid); - LOAD_FUNC(pa_stream_drop); - LOAD_FUNC(pa_frame_size); - LOAD_FUNC(pa_strerror); - LOAD_FUNC(pa_context_get_state); - LOAD_FUNC(pa_stream_get_state); - LOAD_FUNC(pa_threaded_mainloop_signal); - LOAD_FUNC(pa_stream_peek); - LOAD_FUNC(pa_threaded_mainloop_wait); - LOAD_FUNC(pa_threaded_mainloop_unlock); - LOAD_FUNC(pa_threaded_mainloop_in_thread); - LOAD_FUNC(pa_context_new); - LOAD_FUNC(pa_threaded_mainloop_stop); - LOAD_FUNC(pa_context_disconnect); - LOAD_FUNC(pa_threaded_mainloop_start); - LOAD_FUNC(pa_threaded_mainloop_get_api); - LOAD_FUNC(pa_context_set_state_callback); - LOAD_FUNC(pa_stream_write); - LOAD_FUNC(pa_xfree); - LOAD_FUNC(pa_stream_connect_record); - LOAD_FUNC(pa_stream_connect_playback); - LOAD_FUNC(pa_stream_readable_size); - LOAD_FUNC(pa_stream_writable_size); - LOAD_FUNC(pa_stream_is_corked); - LOAD_FUNC(pa_stream_cork); - LOAD_FUNC(pa_stream_is_suspended); - LOAD_FUNC(pa_stream_get_device_name); - LOAD_FUNC(pa_stream_get_latency); - LOAD_FUNC(pa_path_get_filename); - LOAD_FUNC(pa_get_binary_name); - LOAD_FUNC(pa_threaded_mainloop_free); - LOAD_FUNC(pa_context_errno); - LOAD_FUNC(pa_xmalloc); - LOAD_FUNC(pa_stream_unref); - LOAD_FUNC(pa_threaded_mainloop_accept); - LOAD_FUNC(pa_stream_set_write_callback); - LOAD_FUNC(pa_threaded_mainloop_new); - LOAD_FUNC(pa_context_connect); - LOAD_FUNC(pa_stream_set_buffer_attr); - LOAD_FUNC(pa_stream_get_buffer_attr); - LOAD_FUNC(pa_stream_get_sample_spec); - LOAD_FUNC(pa_stream_get_time); - LOAD_FUNC(pa_stream_set_read_callback); - LOAD_FUNC(pa_stream_set_state_callback); - LOAD_FUNC(pa_stream_set_moved_callback); - LOAD_FUNC(pa_stream_set_underflow_callback); - LOAD_FUNC(pa_stream_new_with_proplist); - LOAD_FUNC(pa_stream_disconnect); - LOAD_FUNC(pa_threaded_mainloop_lock); - LOAD_FUNC(pa_channel_map_init_auto); - LOAD_FUNC(pa_channel_map_parse); - LOAD_FUNC(pa_channel_map_snprint); - LOAD_FUNC(pa_channel_map_equal); - LOAD_FUNC(pa_context_get_server_info); - LOAD_FUNC(pa_context_get_sink_info_by_name); - LOAD_FUNC(pa_context_get_sink_info_list); - LOAD_FUNC(pa_context_get_source_info_by_name); - LOAD_FUNC(pa_context_get_source_info_list); - LOAD_FUNC(pa_operation_get_state); - LOAD_FUNC(pa_operation_unref); - LOAD_FUNC(pa_proplist_new); - LOAD_FUNC(pa_proplist_free); - LOAD_FUNC(pa_proplist_set); - LOAD_FUNC(pa_channel_map_superset); - LOAD_FUNC(pa_stream_set_buffer_attr_callback); - LOAD_FUNC(pa_stream_begin_write); -#undef LOAD_FUNC - - if(ret == ALC_FALSE) - { - WARN("Missing expected functions:%s\n", alstr_get_cstr(missing_funcs)); - CloseLib(pa_handle); - pa_handle = NULL; - } - alstr_reset(&missing_funcs); - } -#endif /* HAVE_DYNLOAD */ - return ret; -} - - -/* Global flags and properties */ -static pa_context_flags_t pulse_ctx_flags; -static pa_proplist *prop_filter; - - -/* PulseAudio Event Callbacks */ -static void context_state_callback(pa_context *context, void *pdata) -{ - pa_threaded_mainloop *loop = pdata; - pa_context_state_t state; - - state = pa_context_get_state(context); - if(state == PA_CONTEXT_READY || !PA_CONTEXT_IS_GOOD(state)) - pa_threaded_mainloop_signal(loop, 0); -} - -static void stream_state_callback(pa_stream *stream, void *pdata) -{ - pa_threaded_mainloop *loop = pdata; - pa_stream_state_t state; - - state = pa_stream_get_state(stream); - if(state == PA_STREAM_READY || !PA_STREAM_IS_GOOD(state)) - pa_threaded_mainloop_signal(loop, 0); -} - -static void stream_success_callback(pa_stream *UNUSED(stream), int UNUSED(success), void *pdata) -{ - pa_threaded_mainloop *loop = pdata; - pa_threaded_mainloop_signal(loop, 0); -} - -static void wait_for_operation(pa_operation *op, pa_threaded_mainloop *loop) -{ - if(op) - { - while(pa_operation_get_state(op) == PA_OPERATION_RUNNING) - pa_threaded_mainloop_wait(loop); - pa_operation_unref(op); - } -} - - -static pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent) -{ - const char *name = "OpenAL Soft"; - al_string binname = AL_STRING_INIT_STATIC(); - pa_context_state_t state; - pa_context *context; - int err; - - GetProcBinary(NULL, &binname); - if(!alstr_empty(binname)) - name = alstr_get_cstr(binname); - - context = pa_context_new(pa_threaded_mainloop_get_api(loop), name); - if(!context) - { - ERR("pa_context_new() failed\n"); - alstr_reset(&binname); - return NULL; - } - - pa_context_set_state_callback(context, context_state_callback, loop); - - if((err=pa_context_connect(context, NULL, pulse_ctx_flags, NULL)) >= 0) - { - while((state=pa_context_get_state(context)) != PA_CONTEXT_READY) - { - if(!PA_CONTEXT_IS_GOOD(state)) - { - err = pa_context_errno(context); - if(err > 0) err = -err; - break; - } - - pa_threaded_mainloop_wait(loop); - } - } - pa_context_set_state_callback(context, NULL, NULL); - - if(err < 0) - { - if(!silent) - ERR("Context did not connect: %s\n", pa_strerror(err)); - pa_context_unref(context); - context = NULL; - } - - alstr_reset(&binname); - return context; -} - - -static ALCboolean pulse_open(pa_threaded_mainloop **loop, pa_context **context, - void(*state_cb)(pa_context*,void*), void *ptr) -{ - if(!(*loop = pa_threaded_mainloop_new())) - { - ERR("pa_threaded_mainloop_new() failed!\n"); - return ALC_FALSE; - } - if(pa_threaded_mainloop_start(*loop) < 0) - { - ERR("pa_threaded_mainloop_start() failed\n"); - goto error; - } - - pa_threaded_mainloop_lock(*loop); - - *context = connect_context(*loop, AL_FALSE); - if(!*context) - { - pa_threaded_mainloop_unlock(*loop); - pa_threaded_mainloop_stop(*loop); - goto error; - } - pa_context_set_state_callback(*context, state_cb, ptr); - - pa_threaded_mainloop_unlock(*loop); - return ALC_TRUE; - -error: - pa_threaded_mainloop_free(*loop); - *loop = NULL; - - return ALC_FALSE; -} - -static void pulse_close(pa_threaded_mainloop *loop, pa_context *context, pa_stream *stream) -{ - pa_threaded_mainloop_lock(loop); - - if(stream) - { - pa_stream_set_state_callback(stream, NULL, NULL); - pa_stream_set_moved_callback(stream, NULL, NULL); - pa_stream_set_write_callback(stream, NULL, NULL); - pa_stream_set_buffer_attr_callback(stream, NULL, NULL); - pa_stream_disconnect(stream); - pa_stream_unref(stream); - } - - pa_context_disconnect(context); - pa_context_unref(context); - - pa_threaded_mainloop_unlock(loop); - - pa_threaded_mainloop_stop(loop); - pa_threaded_mainloop_free(loop); -} - - -typedef struct { - al_string name; - al_string device_name; -} DevMap; -TYPEDEF_VECTOR(DevMap, vector_DevMap) - -static vector_DevMap PlaybackDevices; -static vector_DevMap CaptureDevices; - -static void clear_devlist(vector_DevMap *list) -{ -#define DEINIT_STRS(i) (AL_STRING_DEINIT((i)->name),AL_STRING_DEINIT((i)->device_name)) - VECTOR_FOR_EACH(DevMap, *list, DEINIT_STRS); -#undef DEINIT_STRS - VECTOR_RESIZE(*list, 0, 0); -} - - -typedef struct ALCpulsePlayback { - DERIVE_FROM_TYPE(ALCbackend); - - al_string device_name; - - pa_buffer_attr attr; - pa_sample_spec spec; - - pa_threaded_mainloop *loop; - - pa_stream *stream; - pa_context *context; - - ATOMIC(ALenum) killNow; - althrd_t thread; -} ALCpulsePlayback; - -static void ALCpulsePlayback_deviceCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); -static void ALCpulsePlayback_probeDevices(void); - -static void ALCpulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata); -static void ALCpulsePlayback_contextStateCallback(pa_context *context, void *pdata); -static void ALCpulsePlayback_streamStateCallback(pa_stream *stream, void *pdata); -static void ALCpulsePlayback_streamWriteCallback(pa_stream *p, size_t nbytes, void *userdata); -static void ALCpulsePlayback_sinkInfoCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); -static void ALCpulsePlayback_sinkNameCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); -static void ALCpulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata); -static pa_stream *ALCpulsePlayback_connectStream(const char *device_name, pa_threaded_mainloop *loop, - pa_context *context, pa_stream_flags_t flags, - pa_buffer_attr *attr, pa_sample_spec *spec, - pa_channel_map *chanmap); -static int ALCpulsePlayback_mixerProc(void *ptr); - -static void ALCpulsePlayback_Construct(ALCpulsePlayback *self, ALCdevice *device); -static void ALCpulsePlayback_Destruct(ALCpulsePlayback *self); -static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name); -static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self); -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 ClockLatency ALCpulsePlayback_getClockLatency(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); - - self->loop = NULL; - AL_STRING_INIT(self->device_name); - ATOMIC_INIT(&self->killNow, AL_TRUE); -} - -static void ALCpulsePlayback_Destruct(ALCpulsePlayback *self) -{ - if(self->loop) - { - pulse_close(self->loop, self->context, self->stream); - self->loop = NULL; - self->context = NULL; - self->stream = NULL; - } - 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; - const DevMap *iter; - DevMap entry; - int count; - - if(eol) - { - pa_threaded_mainloop_signal(loop, 0); - return; - } - -#define MATCH_INFO_NAME(iter) (alstr_cmp_cstr((iter)->device_name, info->name) == 0) - VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_INFO_NAME); - if(iter != VECTOR_END(PlaybackDevices)) return; -#undef MATCH_INFO_NAME - - AL_STRING_INIT(entry.name); - AL_STRING_INIT(entry.device_name); - - alstr_copy_cstr(&entry.device_name, info->name); - - count = 0; - while(1) - { - alstr_copy_cstr(&entry.name, info->description); - if(count != 0) - { - char str[64]; - snprintf(str, sizeof(str), " #%d", count+1); - alstr_append_cstr(&entry.name, str); - } - -#define MATCH_ENTRY(i) (alstr_cmp(entry.name, (i)->name) == 0) - VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_ENTRY); - if(iter == VECTOR_END(PlaybackDevices)) break; -#undef MATCH_ENTRY - count++; - } - - TRACE("Got device \"%s\", \"%s\"\n", alstr_get_cstr(entry.name), alstr_get_cstr(entry.device_name)); - - VECTOR_PUSH_BACK(PlaybackDevices, entry); -} - -static void ALCpulsePlayback_probeDevices(void) -{ - pa_threaded_mainloop *loop; - - clear_devlist(&PlaybackDevices); - - if((loop=pa_threaded_mainloop_new()) && - pa_threaded_mainloop_start(loop) >= 0) - { - pa_context *context; - - pa_threaded_mainloop_lock(loop); - context = connect_context(loop, AL_FALSE); - if(context) - { - pa_operation *o; - pa_stream_flags_t flags; - pa_sample_spec spec; - pa_stream *stream; - - flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | - PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE; - - spec.format = PA_SAMPLE_S16NE; - spec.rate = 44100; - spec.channels = 2; - - stream = ALCpulsePlayback_connectStream(NULL, loop, context, flags, - NULL, &spec, NULL); - if(stream) - { - o = pa_context_get_sink_info_by_name(context, pa_stream_get_device_name(stream), - ALCpulsePlayback_deviceCallback, loop); - wait_for_operation(o, loop); - - pa_stream_disconnect(stream); - pa_stream_unref(stream); - stream = NULL; - } - - o = pa_context_get_sink_info_list(context, ALCpulsePlayback_deviceCallback, loop); - wait_for_operation(o, loop); - - pa_context_disconnect(context); - pa_context_unref(context); - } - pa_threaded_mainloop_unlock(loop); - pa_threaded_mainloop_stop(loop); - } - if(loop) - pa_threaded_mainloop_free(loop); -} - - -static void ALCpulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata) -{ - ALCpulsePlayback *self = pdata; - - self->attr = *pa_stream_get_buffer_attr(stream); - TRACE("minreq=%d, tlength=%d, prebuf=%d\n", self->attr.minreq, self->attr.tlength, self->attr.prebuf); - /* FIXME: Update the device's UpdateSize (and/or NumUpdates) using the new - * buffer attributes? Changing UpdateSize will change the ALC_REFRESH - * property, which probably shouldn't change between device resets. But - * leaving it alone means ALC_REFRESH will be off. - */ -} - -static void ALCpulsePlayback_contextStateCallback(pa_context *context, void *pdata) -{ - ALCpulsePlayback *self = pdata; - if(pa_context_get_state(context) == PA_CONTEXT_FAILED) - { - ERR("Received context failure!\n"); - aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice, "Playback state failure"); - } - pa_threaded_mainloop_signal(self->loop, 0); -} - -static void ALCpulsePlayback_streamStateCallback(pa_stream *stream, void *pdata) -{ - ALCpulsePlayback *self = pdata; - if(pa_stream_get_state(stream) == PA_STREAM_FAILED) - { - ERR("Received stream failure!\n"); - aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice, "Playback stream failure"); - } - pa_threaded_mainloop_signal(self->loop, 0); -} - -static void ALCpulsePlayback_streamWriteCallback(pa_stream* UNUSED(p), size_t UNUSED(nbytes), void *pdata) -{ - ALCpulsePlayback *self = pdata; - pa_threaded_mainloop_signal(self->loop, 0); -} - -static void ALCpulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) -{ - static const struct { - enum DevFmtChannels chans; - pa_channel_map map; - } chanmaps[] = { - { DevFmtX71, { 8, { - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, - PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, - PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT - } } }, - { DevFmtX61, { 7, { - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, - PA_CHANNEL_POSITION_REAR_CENTER, - PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT - } } }, - { DevFmtX51, { 6, { - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, - PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT - } } }, - { DevFmtX51Rear, { 6, { - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, - PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT - } } }, - { DevFmtQuad, { 4, { - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT - } } }, - { DevFmtStereo, { 2, { - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT - } } }, - { DevFmtMono, { 1, {PA_CHANNEL_POSITION_MONO} } } - }; - ALCpulsePlayback *self = pdata; - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - size_t i; - - if(eol) - { - pa_threaded_mainloop_signal(self->loop, 0); - return; - } - - for(i = 0;i < COUNTOF(chanmaps);i++) - { - if(pa_channel_map_superset(&info->channel_map, &chanmaps[i].map)) - { - if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) - device->FmtChans = chanmaps[i].chans; - break; - } - } - if(i == COUNTOF(chanmaps)) - { - char chanmap_str[PA_CHANNEL_MAP_SNPRINT_MAX] = ""; - pa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map); - WARN("Failed to find format for channel map:\n %s\n", chanmap_str); - } - - if(info->active_port) - TRACE("Active port: %s (%s)\n", info->active_port->name, info->active_port->description); - device->IsHeadphones = (info->active_port && - strcmp(info->active_port->name, "analog-output-headphones") == 0 && - device->FmtChans == DevFmtStereo); -} - -static void ALCpulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) -{ - ALCpulsePlayback *self = pdata; - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - - if(eol) - { - pa_threaded_mainloop_signal(self->loop, 0); - return; - } - - alstr_copy_cstr(&device->DeviceName, info->description); -} - - -static void ALCpulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata) -{ - ALCpulsePlayback *self = pdata; - - alstr_copy_cstr(&self->device_name, pa_stream_get_device_name(stream)); - - TRACE("Stream moved to %s\n", alstr_get_cstr(self->device_name)); -} - - -static pa_stream *ALCpulsePlayback_connectStream(const char *device_name, - pa_threaded_mainloop *loop, pa_context *context, - pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, - pa_channel_map *chanmap) -{ - pa_stream_state_t state; - pa_stream *stream; - - if(!device_name) - { - device_name = getenv("ALSOFT_PULSE_DEFAULT"); - if(device_name && !device_name[0]) - device_name = NULL; - } - - stream = pa_stream_new_with_proplist(context, "Playback Stream", spec, chanmap, prop_filter); - if(!stream) - { - ERR("pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context))); - return NULL; - } - - pa_stream_set_state_callback(stream, stream_state_callback, loop); - - if(pa_stream_connect_playback(stream, device_name, attr, flags, NULL, NULL) < 0) - { - ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(context))); - pa_stream_unref(stream); - return NULL; - } - - while((state=pa_stream_get_state(stream)) != PA_STREAM_READY) - { - if(!PA_STREAM_IS_GOOD(state)) - { - ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(context))); - pa_stream_unref(stream); - return NULL; - } - - pa_threaded_mainloop_wait(loop); - } - pa_stream_set_state_callback(stream, NULL, NULL); - - return stream; -} - - -static int ALCpulsePlayback_mixerProc(void *ptr) -{ - ALCpulsePlayback *self = ptr; - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - ALuint buffer_size; - size_t frame_size; - ssize_t len; - - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - pa_threaded_mainloop_lock(self->loop); - frame_size = pa_frame_size(&self->spec); - - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) - { - void *buf; - int ret; - - len = pa_stream_writable_size(self->stream); - if(len < 0) - { - ERR("Failed to get writable size: %ld", (long)len); - aluHandleDisconnect(device, "Failed to get writable size: %ld", (long)len); - break; - } - - /* Make sure we're going to write at least 2 'periods' (minreqs), in - * case the server increased it since starting playback. Also round up - * the number of writable periods if it's not an integer count. - */ - buffer_size = maxu((self->attr.tlength + self->attr.minreq/2) / self->attr.minreq, 2) * - self->attr.minreq; - - /* NOTE: This assumes pa_stream_writable_size returns between 0 and - * tlength, else there will be more latency than intended. - */ - len = mini(len - (ssize_t)self->attr.tlength, 0) + buffer_size; - if(len < (int32_t)self->attr.minreq) - { - if(pa_stream_is_corked(self->stream)) - { - pa_operation *o; - o = pa_stream_cork(self->stream, 0, NULL, NULL); - if(o) pa_operation_unref(o); - } - pa_threaded_mainloop_wait(self->loop); - continue; - } - - len -= len%self->attr.minreq; - len -= len%frame_size; - - buf = pa_xmalloc(len); - - aluMixData(device, buf, len/frame_size); - - ret = pa_stream_write(self->stream, buf, len, pa_xfree, 0, PA_SEEK_RELATIVE); - if(ret != PA_OK) ERR("Failed to write to stream: %d, %s\n", ret, pa_strerror(ret)); - } - pa_threaded_mainloop_unlock(self->loop); - - return 0; -} - - -static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name) -{ - const_al_string dev_name = AL_STRING_INIT_STATIC(); - const char *pulse_name = NULL; - pa_stream_flags_t flags; - pa_sample_spec spec; - - if(name) - { - const DevMap *iter; - - if(VECTOR_SIZE(PlaybackDevices) == 0) - ALCpulsePlayback_probeDevices(); - -#define MATCH_NAME(iter) (alstr_cmp_cstr((iter)->name, name) == 0) - VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); -#undef MATCH_NAME - if(iter == VECTOR_END(PlaybackDevices)) - return ALC_INVALID_VALUE; - pulse_name = alstr_get_cstr(iter->device_name); - dev_name = iter->name; - } - - if(!pulse_open(&self->loop, &self->context, ALCpulsePlayback_contextStateCallback, self)) - return ALC_INVALID_VALUE; - - pa_threaded_mainloop_lock(self->loop); - - flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | - PA_STREAM_FIX_CHANNELS; - if(!GetConfigValueBool(NULL, "pulse", "allow-moves", 0)) - flags |= PA_STREAM_DONT_MOVE; - - spec.format = PA_SAMPLE_S16NE; - 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) - { - pa_threaded_mainloop_unlock(self->loop); - pulse_close(self->loop, self->context, self->stream); - self->loop = NULL; - self->context = NULL; - return ALC_INVALID_VALUE; - } - pa_stream_set_moved_callback(self->stream, ALCpulsePlayback_streamMovedCallback, self); - - alstr_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream)); - if(alstr_empty(dev_name)) - { - pa_operation *o = pa_context_get_sink_info_by_name( - self->context, alstr_get_cstr(self->device_name), - ALCpulsePlayback_sinkNameCallback, self - ); - wait_for_operation(o, self->loop); - } - else - { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - alstr_copy(&device->DeviceName, dev_name); - } - - pa_threaded_mainloop_unlock(self->loop); - - return ALC_NO_ERROR; -} - -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; - pa_operation *o; - - pa_threaded_mainloop_lock(self->loop); - - if(self->stream) - { - pa_stream_set_state_callback(self->stream, NULL, NULL); - pa_stream_set_moved_callback(self->stream, NULL, NULL); - pa_stream_set_write_callback(self->stream, NULL, NULL); - pa_stream_set_buffer_attr_callback(self->stream, NULL, NULL); - pa_stream_disconnect(self->stream); - pa_stream_unref(self->stream); - self->stream = NULL; - } - - o = pa_context_get_sink_info_by_name(self->context, alstr_get_cstr(self->device_name), - ALCpulsePlayback_sinkInfoCallback, self); - wait_for_operation(o, self->loop); - - if(GetConfigValueBool(alstr_get_cstr(device->DeviceName), "pulse", "fix-rate", 0) || - !(device->Flags&DEVICE_FREQUENCY_REQUEST)) - flags |= PA_STREAM_FIX_RATE; - flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE; - flags |= PA_STREAM_ADJUST_LATENCY; - flags |= PA_STREAM_START_CORKED; - if(!GetConfigValueBool(NULL, "pulse", "allow-moves", 0)) - flags |= PA_STREAM_DONT_MOVE; - - switch(device->FmtType) - { - case DevFmtByte: - device->FmtType = DevFmtUByte; - /* fall-through */ - case DevFmtUByte: - self->spec.format = PA_SAMPLE_U8; - break; - case DevFmtUShort: - device->FmtType = DevFmtShort; - /* fall-through */ - case DevFmtShort: - self->spec.format = PA_SAMPLE_S16NE; - break; - case DevFmtUInt: - device->FmtType = DevFmtInt; - /* fall-through */ - case DevFmtInt: - self->spec.format = PA_SAMPLE_S32NE; - break; - case DevFmtFloat: - self->spec.format = PA_SAMPLE_FLOAT32NE; - break; - } - self->spec.rate = device->Frequency; - self->spec.channels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - - if(pa_sample_spec_valid(&self->spec) == 0) - { - ERR("Invalid sample format\n"); - pa_threaded_mainloop_unlock(self->loop); - return ALC_FALSE; - } - - switch(device->FmtChans) - { - case DevFmtMono: - mapname = "mono"; - break; - case DevFmtAmbi3D: - device->FmtChans = DevFmtStereo; - /*fall-through*/ - case DevFmtStereo: - mapname = "front-left,front-right"; - break; - case DevFmtQuad: - mapname = "front-left,front-right,rear-left,rear-right"; - break; - case DevFmtX51: - mapname = "front-left,front-right,front-center,lfe,side-left,side-right"; - break; - case DevFmtX51Rear: - mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right"; - break; - case DevFmtX61: - mapname = "front-left,front-right,front-center,lfe,rear-center,side-left,side-right"; - break; - case DevFmtX71: - mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right"; - break; - } - if(!pa_channel_map_parse(&chanmap, mapname)) - { - ERR("Failed to build channel map for %s\n", DevFmtChannelsString(device->FmtChans)); - pa_threaded_mainloop_unlock(self->loop); - return ALC_FALSE; - } - SetDefaultWFXChannelOrder(device); - - self->attr.fragsize = -1; - self->attr.prebuf = 0; - self->attr.minreq = device->UpdateSize * pa_frame_size(&self->spec); - self->attr.tlength = self->attr.minreq * maxu(device->NumUpdates, 2); - self->attr.maxlength = -1; - - self->stream = ALCpulsePlayback_connectStream(alstr_get_cstr(self->device_name), - self->loop, self->context, flags, &self->attr, &self->spec, &chanmap - ); - if(!self->stream) - { - pa_threaded_mainloop_unlock(self->loop); - return ALC_FALSE; - } - pa_stream_set_state_callback(self->stream, ALCpulsePlayback_streamStateCallback, self); - pa_stream_set_moved_callback(self->stream, ALCpulsePlayback_streamMovedCallback, self); - pa_stream_set_write_callback(self->stream, ALCpulsePlayback_streamWriteCallback, self); - - self->spec = *(pa_stream_get_sample_spec(self->stream)); - if(device->Frequency != self->spec.rate) - { - /* Server updated our playback rate, so modify the buffer attribs - * accordingly. */ - device->NumUpdates = (ALuint)clampd( - (ALdouble)device->NumUpdates/device->Frequency*self->spec.rate + 0.5, 2.0, 16.0 - ); - - self->attr.minreq = device->UpdateSize * pa_frame_size(&self->spec); - self->attr.tlength = self->attr.minreq * device->NumUpdates; - self->attr.maxlength = -1; - self->attr.prebuf = 0; - - o = pa_stream_set_buffer_attr(self->stream, &self->attr, - stream_success_callback, self->loop); - wait_for_operation(o, self->loop); - - device->Frequency = self->spec.rate; - } - - pa_stream_set_buffer_attr_callback(self->stream, ALCpulsePlayback_bufferAttrCallback, self); - ALCpulsePlayback_bufferAttrCallback(self->stream, self); - - device->NumUpdates = (ALuint)clampu64( - (self->attr.tlength + self->attr.minreq/2) / self->attr.minreq, 2, 16 - ); - device->UpdateSize = self->attr.minreq / pa_frame_size(&self->spec); - - /* HACK: prebuf should be 0 as that's what we set it to. However on some - * systems it comes back as non-0, so we have to make sure the device will - * write enough audio to start playback. The lack of manual start control - * may have unintended consequences, but it's better than not starting at - * all. - */ - if(self->attr.prebuf != 0) - { - ALuint len = self->attr.prebuf / pa_frame_size(&self->spec); - if(len <= device->UpdateSize*device->NumUpdates) - ERR("Non-0 prebuf, %u samples (%u bytes), device has %u samples\n", - len, self->attr.prebuf, device->UpdateSize*device->NumUpdates); - else - { - ERR("Large prebuf, %u samples (%u bytes), increasing device from %u samples", - len, self->attr.prebuf, device->UpdateSize*device->NumUpdates); - device->NumUpdates = (len+device->UpdateSize-1) / device->UpdateSize; - } - } - - pa_threaded_mainloop_unlock(self->loop); - return ALC_TRUE; -} - -static ALCboolean ALCpulsePlayback_start(ALCpulsePlayback *self) -{ - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); - if(althrd_create(&self->thread, ALCpulsePlayback_mixerProc, self) != althrd_success) - return ALC_FALSE; - return ALC_TRUE; -} - -static void ALCpulsePlayback_stop(ALCpulsePlayback *self) -{ - pa_operation *o; - int res; - - if(!self->stream || ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) - return; - - /* Signal the main loop in case PulseAudio isn't sending us audio requests - * (e.g. if the device is suspended). We need to lock the mainloop in case - * the mixer is between checking the killNow flag but before waiting for - * the signal. - */ - pa_threaded_mainloop_lock(self->loop); - pa_threaded_mainloop_unlock(self->loop); - pa_threaded_mainloop_signal(self->loop, 0); - althrd_join(self->thread, &res); - - pa_threaded_mainloop_lock(self->loop); - - o = pa_stream_cork(self->stream, 1, stream_success_callback, self->loop); - wait_for_operation(o, self->loop); - - pa_threaded_mainloop_unlock(self->loop); -} - - -static ClockLatency ALCpulsePlayback_getClockLatency(ALCpulsePlayback *self) -{ - ClockLatency ret; - pa_usec_t latency; - int neg, err; - - pa_threaded_mainloop_lock(self->loop); - ret.ClockTime = GetDeviceClockTime(STATIC_CAST(ALCbackend,self)->mDevice); - err = pa_stream_get_latency(self->stream, &latency, &neg); - pa_threaded_mainloop_unlock(self->loop); - - if(UNLIKELY(err != 0)) - { - /* 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); - latency = 0; - neg = 0; - } - else if(UNLIKELY(neg)) - latency = 0; - ret.Latency = (ALint64)minu64(latency, U64(0x7fffffffffffffff)/1000) * 1000; - - return ret; -} - - -static void ALCpulsePlayback_lock(ALCpulsePlayback *self) -{ - pa_threaded_mainloop_lock(self->loop); -} - -static void ALCpulsePlayback_unlock(ALCpulsePlayback *self) -{ - pa_threaded_mainloop_unlock(self->loop); -} - - -typedef struct ALCpulseCapture { - DERIVE_FROM_TYPE(ALCbackend); - - al_string device_name; - - const void *cap_store; - size_t cap_len; - size_t cap_remain; - - ALCuint last_readable; - - pa_buffer_attr attr; - pa_sample_spec spec; - - pa_threaded_mainloop *loop; - - pa_stream *stream; - pa_context *context; -} ALCpulseCapture; - -static void ALCpulseCapture_deviceCallback(pa_context *context, const pa_source_info *info, int eol, void *pdata); -static void ALCpulseCapture_probeDevices(void); - -static void ALCpulseCapture_contextStateCallback(pa_context *context, void *pdata); -static void ALCpulseCapture_streamStateCallback(pa_stream *stream, void *pdata); -static void ALCpulseCapture_sourceNameCallback(pa_context *context, const pa_source_info *info, int eol, void *pdata); -static void ALCpulseCapture_streamMovedCallback(pa_stream *stream, void *pdata); -static pa_stream *ALCpulseCapture_connectStream(const char *device_name, - pa_threaded_mainloop *loop, pa_context *context, - pa_stream_flags_t flags, pa_buffer_attr *attr, - pa_sample_spec *spec, pa_channel_map *chanmap); - -static void ALCpulseCapture_Construct(ALCpulseCapture *self, ALCdevice *device); -static void ALCpulseCapture_Destruct(ALCpulseCapture *self); -static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name); -static DECLARE_FORWARD(ALCpulseCapture, ALCbackend, ALCboolean, reset) -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 ClockLatency ALCpulseCapture_getClockLatency(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); - - self->loop = NULL; - AL_STRING_INIT(self->device_name); -} - -static void ALCpulseCapture_Destruct(ALCpulseCapture *self) -{ - if(self->loop) - { - pulse_close(self->loop, self->context, self->stream); - self->loop = NULL; - self->context = NULL; - self->stream = NULL; - } - 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; - const DevMap *iter; - DevMap entry; - int count; - - if(eol) - { - pa_threaded_mainloop_signal(loop, 0); - return; - } - -#define MATCH_INFO_NAME(iter) (alstr_cmp_cstr((iter)->device_name, info->name) == 0) - VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_INFO_NAME); - if(iter != VECTOR_END(CaptureDevices)) return; -#undef MATCH_INFO_NAME - - AL_STRING_INIT(entry.name); - AL_STRING_INIT(entry.device_name); - - alstr_copy_cstr(&entry.device_name, info->name); - - count = 0; - while(1) - { - alstr_copy_cstr(&entry.name, info->description); - if(count != 0) - { - char str[64]; - snprintf(str, sizeof(str), " #%d", count+1); - alstr_append_cstr(&entry.name, str); - } - -#define MATCH_ENTRY(i) (alstr_cmp(entry.name, (i)->name) == 0) - VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_ENTRY); - if(iter == VECTOR_END(CaptureDevices)) break; -#undef MATCH_ENTRY - count++; - } - - TRACE("Got device \"%s\", \"%s\"\n", alstr_get_cstr(entry.name), alstr_get_cstr(entry.device_name)); - - VECTOR_PUSH_BACK(CaptureDevices, entry); -} - -static void ALCpulseCapture_probeDevices(void) -{ - pa_threaded_mainloop *loop; - - clear_devlist(&CaptureDevices); - - if((loop=pa_threaded_mainloop_new()) && - pa_threaded_mainloop_start(loop) >= 0) - { - pa_context *context; - - pa_threaded_mainloop_lock(loop); - context = connect_context(loop, AL_FALSE); - if(context) - { - pa_operation *o; - pa_stream_flags_t flags; - pa_sample_spec spec; - pa_stream *stream; - - flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | - PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE; - - spec.format = PA_SAMPLE_S16NE; - spec.rate = 44100; - spec.channels = 1; - - stream = ALCpulseCapture_connectStream(NULL, loop, context, flags, - NULL, &spec, NULL); - if(stream) - { - o = pa_context_get_source_info_by_name(context, pa_stream_get_device_name(stream), - ALCpulseCapture_deviceCallback, loop); - wait_for_operation(o, loop); - - pa_stream_disconnect(stream); - pa_stream_unref(stream); - stream = NULL; - } - - o = pa_context_get_source_info_list(context, ALCpulseCapture_deviceCallback, loop); - wait_for_operation(o, loop); - - pa_context_disconnect(context); - pa_context_unref(context); - } - pa_threaded_mainloop_unlock(loop); - pa_threaded_mainloop_stop(loop); - } - if(loop) - pa_threaded_mainloop_free(loop); -} - - -static void ALCpulseCapture_contextStateCallback(pa_context *context, void *pdata) -{ - ALCpulseCapture *self = pdata; - if(pa_context_get_state(context) == PA_CONTEXT_FAILED) - { - ERR("Received context failure!\n"); - aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice, "Capture state failure"); - } - pa_threaded_mainloop_signal(self->loop, 0); -} - -static void ALCpulseCapture_streamStateCallback(pa_stream *stream, void *pdata) -{ - ALCpulseCapture *self = pdata; - if(pa_stream_get_state(stream) == PA_STREAM_FAILED) - { - ERR("Received stream failure!\n"); - aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice, "Capture stream failure"); - } - pa_threaded_mainloop_signal(self->loop, 0); -} - - -static void ALCpulseCapture_sourceNameCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata) -{ - ALCpulseCapture *self = pdata; - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - - if(eol) - { - pa_threaded_mainloop_signal(self->loop, 0); - return; - } - - alstr_copy_cstr(&device->DeviceName, info->description); -} - - -static void ALCpulseCapture_streamMovedCallback(pa_stream *stream, void *pdata) -{ - ALCpulseCapture *self = pdata; - - alstr_copy_cstr(&self->device_name, pa_stream_get_device_name(stream)); - - TRACE("Stream moved to %s\n", alstr_get_cstr(self->device_name)); -} - - -static pa_stream *ALCpulseCapture_connectStream(const char *device_name, - pa_threaded_mainloop *loop, pa_context *context, - pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, - pa_channel_map *chanmap) -{ - pa_stream_state_t state; - pa_stream *stream; - - stream = pa_stream_new_with_proplist(context, "Capture Stream", spec, chanmap, prop_filter); - if(!stream) - { - ERR("pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context))); - return NULL; - } - - pa_stream_set_state_callback(stream, stream_state_callback, loop); - - if(pa_stream_connect_record(stream, device_name, attr, flags) < 0) - { - ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(context))); - pa_stream_unref(stream); - return NULL; - } - - while((state=pa_stream_get_state(stream)) != PA_STREAM_READY) - { - if(!PA_STREAM_IS_GOOD(state)) - { - ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(context))); - pa_stream_unref(stream); - return NULL; - } - - pa_threaded_mainloop_wait(loop); - } - pa_stream_set_state_callback(stream, NULL, NULL); - - return stream; -} - - -static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - const char *pulse_name = NULL; - pa_stream_flags_t flags = 0; - const char *mapname = NULL; - pa_channel_map chanmap; - ALuint samples; - - if(name) - { - const DevMap *iter; - - if(VECTOR_SIZE(CaptureDevices) == 0) - ALCpulseCapture_probeDevices(); - -#define MATCH_NAME(iter) (alstr_cmp_cstr((iter)->name, name) == 0) - VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); -#undef MATCH_NAME - if(iter == VECTOR_END(CaptureDevices)) - return ALC_INVALID_VALUE; - pulse_name = alstr_get_cstr(iter->device_name); - alstr_copy(&device->DeviceName, iter->name); - } - - if(!pulse_open(&self->loop, &self->context, ALCpulseCapture_contextStateCallback, self)) - return ALC_INVALID_VALUE; - - pa_threaded_mainloop_lock(self->loop); - - switch(device->FmtType) - { - case DevFmtUByte: - self->spec.format = PA_SAMPLE_U8; - break; - case DevFmtShort: - self->spec.format = PA_SAMPLE_S16NE; - break; - case DevFmtInt: - self->spec.format = PA_SAMPLE_S32NE; - break; - case DevFmtFloat: - self->spec.format = PA_SAMPLE_FLOAT32NE; - break; - case DevFmtByte: - case DevFmtUShort: - case DevFmtUInt: - ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); - pa_threaded_mainloop_unlock(self->loop); - goto fail; - } - - switch(device->FmtChans) - { - case DevFmtMono: - mapname = "mono"; - break; - case DevFmtStereo: - mapname = "front-left,front-right"; - break; - case DevFmtQuad: - mapname = "front-left,front-right,rear-left,rear-right"; - break; - case DevFmtX51: - mapname = "front-left,front-right,front-center,lfe,side-left,side-right"; - break; - case DevFmtX51Rear: - mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right"; - break; - case DevFmtX61: - mapname = "front-left,front-right,front-center,lfe,rear-center,side-left,side-right"; - break; - case DevFmtX71: - mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right"; - break; - case DevFmtAmbi3D: - ERR("%s capture samples not supported\n", DevFmtChannelsString(device->FmtChans)); - pa_threaded_mainloop_unlock(self->loop); - goto fail; - } - if(!pa_channel_map_parse(&chanmap, mapname)) - { - ERR("Failed to build channel map for %s\n", DevFmtChannelsString(device->FmtChans)); - pa_threaded_mainloop_unlock(self->loop); - return ALC_FALSE; - } - - self->spec.rate = device->Frequency; - self->spec.channels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - - if(pa_sample_spec_valid(&self->spec) == 0) - { - ERR("Invalid sample format\n"); - pa_threaded_mainloop_unlock(self->loop); - goto fail; - } - - if(!pa_channel_map_init_auto(&chanmap, self->spec.channels, PA_CHANNEL_MAP_WAVEEX)) - { - ERR("Couldn't build map for channel count (%d)!\n", self->spec.channels); - pa_threaded_mainloop_unlock(self->loop); - goto fail; - } - - samples = device->UpdateSize * device->NumUpdates; - samples = maxu(samples, 100 * device->Frequency / 1000); - - self->attr.minreq = -1; - self->attr.prebuf = -1; - self->attr.maxlength = samples * pa_frame_size(&self->spec); - self->attr.tlength = -1; - self->attr.fragsize = minu(samples, 50*device->Frequency/1000) * - pa_frame_size(&self->spec); - - flags |= PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY; - if(!GetConfigValueBool(NULL, "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 - ); - if(!self->stream) - { - pa_threaded_mainloop_unlock(self->loop); - goto fail; - } - pa_stream_set_moved_callback(self->stream, ALCpulseCapture_streamMovedCallback, self); - pa_stream_set_state_callback(self->stream, ALCpulseCapture_streamStateCallback, self); - - alstr_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream)); - if(alstr_empty(device->DeviceName)) - { - pa_operation *o = pa_context_get_source_info_by_name( - self->context, alstr_get_cstr(self->device_name), - ALCpulseCapture_sourceNameCallback, self - ); - wait_for_operation(o, self->loop); - } - - pa_threaded_mainloop_unlock(self->loop); - return ALC_NO_ERROR; - -fail: - pulse_close(self->loop, self->context, self->stream); - self->loop = NULL; - self->context = NULL; - self->stream = NULL; - - return ALC_INVALID_VALUE; -} - -static ALCboolean ALCpulseCapture_start(ALCpulseCapture *self) -{ - pa_operation *o; - pa_threaded_mainloop_lock(self->loop); - o = pa_stream_cork(self->stream, 0, stream_success_callback, self->loop); - wait_for_operation(o, self->loop); - pa_threaded_mainloop_unlock(self->loop); - return ALC_TRUE; -} - -static void ALCpulseCapture_stop(ALCpulseCapture *self) -{ - pa_operation *o; - pa_threaded_mainloop_lock(self->loop); - o = pa_stream_cork(self->stream, 1, stream_success_callback, self->loop); - wait_for_operation(o, self->loop); - pa_threaded_mainloop_unlock(self->loop); -} - -static ALCenum ALCpulseCapture_captureSamples(ALCpulseCapture *self, ALCvoid *buffer, ALCuint samples) -{ - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - ALCuint todo = samples * pa_frame_size(&self->spec); - - /* Capture is done in fragment-sized chunks, so we loop until we get all - * that's available */ - self->last_readable -= todo; - pa_threaded_mainloop_lock(self->loop); - while(todo > 0) - { - size_t rem = todo; - - if(self->cap_len == 0) - { - pa_stream_state_t state; - - state = pa_stream_get_state(self->stream); - if(!PA_STREAM_IS_GOOD(state)) - { - aluHandleDisconnect(device, "Bad capture state: %u", state); - break; - } - if(pa_stream_peek(self->stream, &self->cap_store, &self->cap_len) < 0) - { - ERR("pa_stream_peek() failed: %s\n", - pa_strerror(pa_context_errno(self->context))); - aluHandleDisconnect(device, "Failed retrieving capture samples: %s", - pa_strerror(pa_context_errno(self->context))); - break; - } - self->cap_remain = self->cap_len; - } - if(rem > self->cap_remain) - rem = self->cap_remain; - - memcpy(buffer, self->cap_store, rem); - - buffer = (ALbyte*)buffer + rem; - todo -= rem; - - self->cap_store = (ALbyte*)self->cap_store + rem; - self->cap_remain -= rem; - if(self->cap_remain == 0) - { - pa_stream_drop(self->stream); - self->cap_len = 0; - } - } - pa_threaded_mainloop_unlock(self->loop); - if(todo > 0) - memset(buffer, ((device->FmtType==DevFmtUByte) ? 0x80 : 0), todo); - - return ALC_NO_ERROR; -} - -static ALCuint ALCpulseCapture_availableSamples(ALCpulseCapture *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - size_t readable = self->cap_remain; - - if(ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) - { - ssize_t got; - pa_threaded_mainloop_lock(self->loop); - got = pa_stream_readable_size(self->stream); - if(got < 0) - { - ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got)); - aluHandleDisconnect(device, "Failed getting readable size: %s", pa_strerror(got)); - } - else if((size_t)got > self->cap_len) - readable += got - self->cap_len; - pa_threaded_mainloop_unlock(self->loop); - } - - if(self->last_readable < readable) - self->last_readable = readable; - return self->last_readable / pa_frame_size(&self->spec); -} - - -static ClockLatency ALCpulseCapture_getClockLatency(ALCpulseCapture *self) -{ - ClockLatency ret; - pa_usec_t latency; - int neg, err; - - pa_threaded_mainloop_lock(self->loop); - ret.ClockTime = GetDeviceClockTime(STATIC_CAST(ALCbackend,self)->mDevice); - err = pa_stream_get_latency(self->stream, &latency, &neg); - pa_threaded_mainloop_unlock(self->loop); - - if(UNLIKELY(err != 0)) - { - ERR("Failed to get stream latency: 0x%x\n", err); - latency = 0; - neg = 0; - } - else if(UNLIKELY(neg)) - latency = 0; - ret.Latency = (ALint64)minu64(latency, U64(0x7fffffffffffffff)/1000) * 1000; - - return ret; -} - - -static void ALCpulseCapture_lock(ALCpulseCapture *self) -{ - pa_threaded_mainloop_lock(self->loop); -} - -static void ALCpulseCapture_unlock(ALCpulseCapture *self) -{ - pa_threaded_mainloop_unlock(self->loop); -} - - -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, al_string *outnames); -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; - - pulse_ctx_flags = 0; - if(!GetConfigValueBool(NULL, "pulse", "spawn-server", 1)) - pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN; - - if((loop=pa_threaded_mainloop_new()) && - pa_threaded_mainloop_start(loop) >= 0) - { - pa_context *context; - - pa_threaded_mainloop_lock(loop); - context = connect_context(loop, AL_TRUE); - if(context) - { - ret = ALC_TRUE; - - /* Some libraries (Phonon, Qt) set some pulseaudio properties - * through environment variables, which causes all streams in - * the process to inherit them. This attempts to filter those - * properties out by setting them to 0-length data. */ - prop_filter = pa_proplist_new(); - pa_proplist_set(prop_filter, PA_PROP_MEDIA_ROLE, NULL, 0); - pa_proplist_set(prop_filter, "phonon.streamid", NULL, 0); - - pa_context_disconnect(context); - pa_context_unref(context); - } - pa_threaded_mainloop_unlock(loop); - pa_threaded_mainloop_stop(loop); - } - if(loop) - pa_threaded_mainloop_free(loop); - } - - return ret; -} - -static void ALCpulseBackendFactory_deinit(ALCpulseBackendFactory* UNUSED(self)) -{ - clear_devlist(&PlaybackDevices); - VECTOR_DEINIT(PlaybackDevices); - - clear_devlist(&CaptureDevices); - VECTOR_DEINIT(CaptureDevices); - - if(prop_filter) - pa_proplist_free(prop_filter); - prop_filter = NULL; - - /* PulseAudio doesn't like being CloseLib'd sometimes */ -} - -static ALCboolean ALCpulseBackendFactory_querySupport(ALCpulseBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} - -static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) -{ - switch(type) - { -#define APPEND_OUTNAME(e) do { \ - if(!alstr_empty((e)->name)) \ - alstr_append_range(outnames, VECTOR_BEGIN((e)->name), \ - VECTOR_END((e)->name)+1); \ -} while(0) - case ALL_DEVICE_PROBE: - ALCpulsePlayback_probeDevices(); - VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_OUTNAME); - break; - - case CAPTURE_DEVICE_PROBE: - ALCpulseCapture_probeDevices(); - VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_OUTNAME); - break; -#undef APPEND_OUTNAME - } -} - -static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - { - ALCpulsePlayback *backend; - NEW_OBJ(backend, ALCpulsePlayback)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - if(type == ALCbackend_Capture) - { - ALCpulseCapture *backend; - NEW_OBJ(backend, ALCpulseCapture)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} - - -#else /* PA_API_VERSION == 12 */ - -#warning "Unsupported API version, backend will be unavailable!" - -typedef struct ALCpulseBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCpulseBackendFactory; -#define ALCPULSEBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCpulseBackendFactory, ALCbackendFactory) } } - -static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory* UNUSED(self)) -{ - return ALC_FALSE; -} - -static void ALCpulseBackendFactory_deinit(ALCpulseBackendFactory* UNUSED(self)) -{ -} - -static ALCboolean ALCpulseBackendFactory_querySupport(ALCpulseBackendFactory* UNUSED(self), ALCbackend_Type UNUSED(type)) -{ - return ALC_FALSE; -} - -static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), enum DevProbe UNUSED(type), al_string* UNUSED(outnames)) -{ -} - -static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory* UNUSED(self), ALCdevice* UNUSED(device), ALCbackend_Type UNUSED(type)) -{ - return NULL; -} - -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCpulseBackendFactory); - -#endif /* PA_API_VERSION == 12 */ - -ALCbackendFactory *ALCpulseBackendFactory_getFactory(void) -{ - static ALCpulseBackendFactory factory = ALCPULSEBACKENDFACTORY_INITIALIZER; - return STATIC_CAST(ALCbackendFactory, &factory); -} diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp new file mode 100644 index 00000000..b75716bc --- /dev/null +++ b/Alc/backends/pulseaudio.cpp @@ -0,0 +1,1904 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2009 by Konstantinos Natsakis + * Copyright (C) 2010 by Chris Robinson + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include + +#include +#include +#include +#include +#include + +#include "alMain.h" +#include "alu.h" +#include "alconfig.h" +#include "threads.h" +#include "compat.h" + +#include "backends/base.h" + +#include + +#if PA_API_VERSION == 12 + +#ifdef HAVE_DYNLOAD +static void *pa_handle; +#define MAKE_FUNC(x) static decltype(x) * p##x +MAKE_FUNC(pa_context_unref); +MAKE_FUNC(pa_sample_spec_valid); +MAKE_FUNC(pa_frame_size); +MAKE_FUNC(pa_stream_drop); +MAKE_FUNC(pa_strerror); +MAKE_FUNC(pa_context_get_state); +MAKE_FUNC(pa_stream_get_state); +MAKE_FUNC(pa_threaded_mainloop_signal); +MAKE_FUNC(pa_stream_peek); +MAKE_FUNC(pa_threaded_mainloop_wait); +MAKE_FUNC(pa_threaded_mainloop_unlock); +MAKE_FUNC(pa_threaded_mainloop_in_thread); +MAKE_FUNC(pa_context_new); +MAKE_FUNC(pa_threaded_mainloop_stop); +MAKE_FUNC(pa_context_disconnect); +MAKE_FUNC(pa_threaded_mainloop_start); +MAKE_FUNC(pa_threaded_mainloop_get_api); +MAKE_FUNC(pa_context_set_state_callback); +MAKE_FUNC(pa_stream_write); +MAKE_FUNC(pa_xfree); +MAKE_FUNC(pa_stream_connect_record); +MAKE_FUNC(pa_stream_connect_playback); +MAKE_FUNC(pa_stream_readable_size); +MAKE_FUNC(pa_stream_writable_size); +MAKE_FUNC(pa_stream_is_corked); +MAKE_FUNC(pa_stream_cork); +MAKE_FUNC(pa_stream_is_suspended); +MAKE_FUNC(pa_stream_get_device_name); +MAKE_FUNC(pa_stream_get_latency); +MAKE_FUNC(pa_path_get_filename); +MAKE_FUNC(pa_get_binary_name); +MAKE_FUNC(pa_threaded_mainloop_free); +MAKE_FUNC(pa_context_errno); +MAKE_FUNC(pa_xmalloc); +MAKE_FUNC(pa_stream_unref); +MAKE_FUNC(pa_threaded_mainloop_accept); +MAKE_FUNC(pa_stream_set_write_callback); +MAKE_FUNC(pa_threaded_mainloop_new); +MAKE_FUNC(pa_context_connect); +MAKE_FUNC(pa_stream_set_buffer_attr); +MAKE_FUNC(pa_stream_get_buffer_attr); +MAKE_FUNC(pa_stream_get_sample_spec); +MAKE_FUNC(pa_stream_get_time); +MAKE_FUNC(pa_stream_set_read_callback); +MAKE_FUNC(pa_stream_set_state_callback); +MAKE_FUNC(pa_stream_set_moved_callback); +MAKE_FUNC(pa_stream_set_underflow_callback); +MAKE_FUNC(pa_stream_new_with_proplist); +MAKE_FUNC(pa_stream_disconnect); +MAKE_FUNC(pa_threaded_mainloop_lock); +MAKE_FUNC(pa_channel_map_init_auto); +MAKE_FUNC(pa_channel_map_parse); +MAKE_FUNC(pa_channel_map_snprint); +MAKE_FUNC(pa_channel_map_equal); +MAKE_FUNC(pa_context_get_server_info); +MAKE_FUNC(pa_context_get_sink_info_by_name); +MAKE_FUNC(pa_context_get_sink_info_list); +MAKE_FUNC(pa_context_get_source_info_by_name); +MAKE_FUNC(pa_context_get_source_info_list); +MAKE_FUNC(pa_operation_get_state); +MAKE_FUNC(pa_operation_unref); +MAKE_FUNC(pa_proplist_new); +MAKE_FUNC(pa_proplist_free); +MAKE_FUNC(pa_proplist_set); +MAKE_FUNC(pa_channel_map_superset); +MAKE_FUNC(pa_stream_set_buffer_attr_callback); +MAKE_FUNC(pa_stream_begin_write); +#undef MAKE_FUNC + +#ifndef IN_IDE_PARSER +#define pa_context_unref ppa_context_unref +#define pa_sample_spec_valid ppa_sample_spec_valid +#define pa_frame_size ppa_frame_size +#define pa_stream_drop ppa_stream_drop +#define pa_strerror ppa_strerror +#define pa_context_get_state ppa_context_get_state +#define pa_stream_get_state ppa_stream_get_state +#define pa_threaded_mainloop_signal ppa_threaded_mainloop_signal +#define pa_stream_peek ppa_stream_peek +#define pa_threaded_mainloop_wait ppa_threaded_mainloop_wait +#define pa_threaded_mainloop_unlock ppa_threaded_mainloop_unlock +#define pa_threaded_mainloop_in_thread ppa_threaded_mainloop_in_thread +#define pa_context_new ppa_context_new +#define pa_threaded_mainloop_stop ppa_threaded_mainloop_stop +#define pa_context_disconnect ppa_context_disconnect +#define pa_threaded_mainloop_start ppa_threaded_mainloop_start +#define pa_threaded_mainloop_get_api ppa_threaded_mainloop_get_api +#define pa_context_set_state_callback ppa_context_set_state_callback +#define pa_stream_write ppa_stream_write +#define pa_xfree ppa_xfree +#define pa_stream_connect_record ppa_stream_connect_record +#define pa_stream_connect_playback ppa_stream_connect_playback +#define pa_stream_readable_size ppa_stream_readable_size +#define pa_stream_writable_size ppa_stream_writable_size +#define pa_stream_is_corked ppa_stream_is_corked +#define pa_stream_cork ppa_stream_cork +#define pa_stream_is_suspended ppa_stream_is_suspended +#define pa_stream_get_device_name ppa_stream_get_device_name +#define pa_stream_get_latency ppa_stream_get_latency +#define pa_path_get_filename ppa_path_get_filename +#define pa_get_binary_name ppa_get_binary_name +#define pa_threaded_mainloop_free ppa_threaded_mainloop_free +#define pa_context_errno ppa_context_errno +#define pa_xmalloc ppa_xmalloc +#define pa_stream_unref ppa_stream_unref +#define pa_threaded_mainloop_accept ppa_threaded_mainloop_accept +#define pa_stream_set_write_callback ppa_stream_set_write_callback +#define pa_threaded_mainloop_new ppa_threaded_mainloop_new +#define pa_context_connect ppa_context_connect +#define pa_stream_set_buffer_attr ppa_stream_set_buffer_attr +#define pa_stream_get_buffer_attr ppa_stream_get_buffer_attr +#define pa_stream_get_sample_spec ppa_stream_get_sample_spec +#define pa_stream_get_time ppa_stream_get_time +#define pa_stream_set_read_callback ppa_stream_set_read_callback +#define pa_stream_set_state_callback ppa_stream_set_state_callback +#define pa_stream_set_moved_callback ppa_stream_set_moved_callback +#define pa_stream_set_underflow_callback ppa_stream_set_underflow_callback +#define pa_stream_new_with_proplist ppa_stream_new_with_proplist +#define pa_stream_disconnect ppa_stream_disconnect +#define pa_threaded_mainloop_lock ppa_threaded_mainloop_lock +#define pa_channel_map_init_auto ppa_channel_map_init_auto +#define pa_channel_map_parse ppa_channel_map_parse +#define pa_channel_map_snprint ppa_channel_map_snprint +#define pa_channel_map_equal ppa_channel_map_equal +#define pa_context_get_server_info ppa_context_get_server_info +#define pa_context_get_sink_info_by_name ppa_context_get_sink_info_by_name +#define pa_context_get_sink_info_list ppa_context_get_sink_info_list +#define pa_context_get_source_info_by_name ppa_context_get_source_info_by_name +#define pa_context_get_source_info_list ppa_context_get_source_info_list +#define pa_operation_get_state ppa_operation_get_state +#define pa_operation_unref ppa_operation_unref +#define pa_proplist_new ppa_proplist_new +#define pa_proplist_free ppa_proplist_free +#define pa_proplist_set ppa_proplist_set +#define pa_channel_map_superset ppa_channel_map_superset +#define pa_stream_set_buffer_attr_callback ppa_stream_set_buffer_attr_callback +#define pa_stream_begin_write ppa_stream_begin_write +#endif /* IN_IDE_PARSER */ + +#endif + +static ALCboolean pulse_load(void) +{ + ALCboolean ret{ALC_TRUE}; +#ifdef HAVE_DYNLOAD + if(!pa_handle) + { + std::string missing_funcs; + +#ifdef _WIN32 +#define PALIB "libpulse-0.dll" +#elif defined(__APPLE__) && defined(__MACH__) +#define PALIB "libpulse.0.dylib" +#else +#define PALIB "libpulse.so.0" +#endif + pa_handle = LoadLib(PALIB); + if(!pa_handle) + { + WARN("Failed to load %s\n", PALIB); + return ALC_FALSE; + } + +#define LOAD_FUNC(x) do { \ + p##x = reinterpret_cast(GetSymbol(pa_handle, #x)); \ + if(!(p##x)) { \ + ret = ALC_FALSE; \ + missing_funcs += "\n" #x; \ + } \ +} while(0) + LOAD_FUNC(pa_context_unref); + LOAD_FUNC(pa_sample_spec_valid); + LOAD_FUNC(pa_stream_drop); + LOAD_FUNC(pa_frame_size); + LOAD_FUNC(pa_strerror); + LOAD_FUNC(pa_context_get_state); + LOAD_FUNC(pa_stream_get_state); + LOAD_FUNC(pa_threaded_mainloop_signal); + LOAD_FUNC(pa_stream_peek); + LOAD_FUNC(pa_threaded_mainloop_wait); + LOAD_FUNC(pa_threaded_mainloop_unlock); + LOAD_FUNC(pa_threaded_mainloop_in_thread); + LOAD_FUNC(pa_context_new); + LOAD_FUNC(pa_threaded_mainloop_stop); + LOAD_FUNC(pa_context_disconnect); + LOAD_FUNC(pa_threaded_mainloop_start); + LOAD_FUNC(pa_threaded_mainloop_get_api); + LOAD_FUNC(pa_context_set_state_callback); + LOAD_FUNC(pa_stream_write); + LOAD_FUNC(pa_xfree); + LOAD_FUNC(pa_stream_connect_record); + LOAD_FUNC(pa_stream_connect_playback); + LOAD_FUNC(pa_stream_readable_size); + LOAD_FUNC(pa_stream_writable_size); + LOAD_FUNC(pa_stream_is_corked); + LOAD_FUNC(pa_stream_cork); + LOAD_FUNC(pa_stream_is_suspended); + LOAD_FUNC(pa_stream_get_device_name); + LOAD_FUNC(pa_stream_get_latency); + LOAD_FUNC(pa_path_get_filename); + LOAD_FUNC(pa_get_binary_name); + LOAD_FUNC(pa_threaded_mainloop_free); + LOAD_FUNC(pa_context_errno); + LOAD_FUNC(pa_xmalloc); + LOAD_FUNC(pa_stream_unref); + LOAD_FUNC(pa_threaded_mainloop_accept); + LOAD_FUNC(pa_stream_set_write_callback); + LOAD_FUNC(pa_threaded_mainloop_new); + LOAD_FUNC(pa_context_connect); + LOAD_FUNC(pa_stream_set_buffer_attr); + LOAD_FUNC(pa_stream_get_buffer_attr); + LOAD_FUNC(pa_stream_get_sample_spec); + LOAD_FUNC(pa_stream_get_time); + LOAD_FUNC(pa_stream_set_read_callback); + LOAD_FUNC(pa_stream_set_state_callback); + LOAD_FUNC(pa_stream_set_moved_callback); + LOAD_FUNC(pa_stream_set_underflow_callback); + LOAD_FUNC(pa_stream_new_with_proplist); + LOAD_FUNC(pa_stream_disconnect); + LOAD_FUNC(pa_threaded_mainloop_lock); + LOAD_FUNC(pa_channel_map_init_auto); + LOAD_FUNC(pa_channel_map_parse); + LOAD_FUNC(pa_channel_map_snprint); + LOAD_FUNC(pa_channel_map_equal); + LOAD_FUNC(pa_context_get_server_info); + LOAD_FUNC(pa_context_get_sink_info_by_name); + LOAD_FUNC(pa_context_get_sink_info_list); + LOAD_FUNC(pa_context_get_source_info_by_name); + LOAD_FUNC(pa_context_get_source_info_list); + LOAD_FUNC(pa_operation_get_state); + LOAD_FUNC(pa_operation_unref); + LOAD_FUNC(pa_proplist_new); + LOAD_FUNC(pa_proplist_free); + LOAD_FUNC(pa_proplist_set); + LOAD_FUNC(pa_channel_map_superset); + LOAD_FUNC(pa_stream_set_buffer_attr_callback); + LOAD_FUNC(pa_stream_begin_write); +#undef LOAD_FUNC + + if(ret == ALC_FALSE) + { + WARN("Missing expected functions:%s\n", missing_funcs.c_str()); + CloseLib(pa_handle); + pa_handle = nullptr; + } + } +#endif /* HAVE_DYNLOAD */ + return ret; +} + + +/* *grumble* Don't use enums for bitflags. */ +inline pa_stream_flags_t operator|(pa_stream_flags_t lhs, pa_stream_flags_t rhs) +{ return pa_stream_flags_t(int(lhs) | int(rhs)); } + +inline pa_stream_flags_t operator|=(pa_stream_flags_t &lhs, pa_stream_flags_t rhs) +{ + lhs = pa_stream_flags_t(int(lhs) | int(rhs)); + return lhs; +} + +inline pa_context_flags_t operator|=(pa_context_flags_t &lhs, pa_context_flags_t rhs) +{ + lhs = pa_context_flags_t(int(lhs) | int(rhs)); + return lhs; +} + + +namespace { + +class palock_guard { + pa_threaded_mainloop *mLoop; + +public: + explicit palock_guard(pa_threaded_mainloop *loop) : mLoop(loop) + { pa_threaded_mainloop_lock(mLoop); } + ~palock_guard() { pa_threaded_mainloop_unlock(mLoop); } + + palock_guard(const palock_guard&) = delete; + palock_guard& operator=(const palock_guard&) = delete; +}; + +class unique_palock { + pa_threaded_mainloop *mLoop{nullptr}; + bool mLocked{false}; + +public: + unique_palock() noexcept = default; + explicit unique_palock(pa_threaded_mainloop *loop) : mLoop(loop) + { + pa_threaded_mainloop_lock(mLoop); + mLocked = true; + } + unique_palock(unique_palock&& rhs) : mLoop(rhs.mLoop), mLocked(rhs.mLocked) + { rhs.mLoop = nullptr; rhs.mLocked = false; } + ~unique_palock() { if(mLocked) pa_threaded_mainloop_unlock(mLoop); } + + unique_palock& operator=(const unique_palock&) = delete; + unique_palock& operator=(unique_palock&& rhs) + { + if(mLocked) + pa_threaded_mainloop_unlock(mLoop); + mLoop = rhs.mLoop; rhs.mLoop = nullptr; + mLocked = rhs.mLocked; rhs.mLocked = false; + return *this; + } + + void lock() + { + pa_threaded_mainloop_lock(mLoop); + mLocked = true; + } + void unlock() + { + mLocked = false; + pa_threaded_mainloop_unlock(mLoop); + } +}; + +} // namespace + + +/* Global flags and properties */ +static pa_context_flags_t pulse_ctx_flags; +static pa_proplist *prop_filter; + + +/* PulseAudio Event Callbacks */ +static void context_state_callback(pa_context *context, void *pdata) +{ + auto loop{reinterpret_cast(pdata)}; + auto state{pa_context_get_state(context)}; + if(state == PA_CONTEXT_READY || !PA_CONTEXT_IS_GOOD(state)) + pa_threaded_mainloop_signal(loop, 0); +} + +static void stream_state_callback(pa_stream *stream, void *pdata) +{ + auto loop{reinterpret_cast(pdata)}; + auto state{pa_stream_get_state(stream)}; + if(state == PA_STREAM_READY || !PA_STREAM_IS_GOOD(state)) + pa_threaded_mainloop_signal(loop, 0); +} + +static void stream_success_callback(pa_stream *UNUSED(stream), int UNUSED(success), void *pdata) +{ + auto loop{reinterpret_cast(pdata)}; + pa_threaded_mainloop_signal(loop, 0); +} + +static void wait_for_operation(pa_operation *op, pa_threaded_mainloop *loop) +{ + if(op) + { + while(pa_operation_get_state(op) == PA_OPERATION_RUNNING) + pa_threaded_mainloop_wait(loop); + pa_operation_unref(op); + } +} + + +static pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent) +{ + const char *name{"OpenAL Soft"}; + al_string binname{AL_STRING_INIT_STATIC()}; + + GetProcBinary(nullptr, &binname); + if(!alstr_empty(binname)) + name = alstr_get_cstr(binname); + + auto context{pa_context_new(pa_threaded_mainloop_get_api(loop), name)}; + if(!context) + { + ERR("pa_context_new() failed\n"); + alstr_reset(&binname); + return nullptr; + } + + pa_context_set_state_callback(context, context_state_callback, loop); + + int err; + if((err=pa_context_connect(context, nullptr, pulse_ctx_flags, nullptr)) >= 0) + { + pa_context_state_t state; + while((state=pa_context_get_state(context)) != PA_CONTEXT_READY) + { + if(!PA_CONTEXT_IS_GOOD(state)) + { + err = pa_context_errno(context); + if(err > 0) err = -err; + break; + } + + pa_threaded_mainloop_wait(loop); + } + } + pa_context_set_state_callback(context, nullptr, nullptr); + + if(err < 0) + { + if(!silent) + ERR("Context did not connect: %s\n", pa_strerror(err)); + pa_context_unref(context); + context = nullptr; + } + + alstr_reset(&binname); + return context; +} + + +using MainloopContextPair = std::pair; +static MainloopContextPair pulse_open(void(*state_cb)(pa_context*,void*), void *ptr) +{ + auto loop{pa_threaded_mainloop_new()}; + if(UNLIKELY(!loop)) + { + ERR("pa_threaded_mainloop_new() failed!\n"); + return {nullptr, nullptr}; + } + if(UNLIKELY(pa_threaded_mainloop_start(loop) < 0)) + { + ERR("pa_threaded_mainloop_start() failed\n"); + pa_threaded_mainloop_free(loop); + return {nullptr, nullptr}; + } + + unique_palock palock{loop}; + auto context{connect_context(loop, AL_FALSE)}; + if(UNLIKELY(!context)) + { + palock = unique_palock{}; + pa_threaded_mainloop_stop(loop); + pa_threaded_mainloop_free(loop); + return {nullptr, nullptr}; + } + pa_context_set_state_callback(context, state_cb, ptr); + return {loop, context}; +} + +static void pulse_close(pa_threaded_mainloop *loop, pa_context *context, pa_stream *stream) +{ + { palock_guard _{loop}; + if(stream) + { + pa_stream_set_state_callback(stream, nullptr, nullptr); + pa_stream_set_moved_callback(stream, nullptr, nullptr); + pa_stream_set_write_callback(stream, nullptr, nullptr); + pa_stream_set_buffer_attr_callback(stream, nullptr, nullptr); + pa_stream_disconnect(stream); + pa_stream_unref(stream); + } + + pa_context_disconnect(context); + pa_context_unref(context); + } + + pa_threaded_mainloop_stop(loop); + pa_threaded_mainloop_free(loop); +} + + +struct DevMap { + std::string name; + std::string device_name; +}; + +static std::vector PlaybackDevices; +static std::vector CaptureDevices; + + +struct PulsePlayback { + DERIVE_FROM_TYPE(ALCbackend); + + std::string device_name; + + pa_buffer_attr attr; + pa_sample_spec spec; + + pa_threaded_mainloop *loop{nullptr}; + + pa_stream *stream{nullptr}; + pa_context *context{nullptr}; + + std::atomic killNow{ALC_TRUE}; + std::thread thread; +}; + +static void PulsePlayback_deviceCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); +static void PulsePlayback_probeDevices(void); + +static void PulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata); +static void PulsePlayback_contextStateCallback(pa_context *context, void *pdata); +static void PulsePlayback_streamStateCallback(pa_stream *stream, void *pdata); +static void PulsePlayback_streamWriteCallback(pa_stream *p, size_t nbytes, void *userdata); +static void PulsePlayback_sinkInfoCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); +static void PulsePlayback_sinkNameCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); +static void PulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata); +static pa_stream *PulsePlayback_connectStream(const char *device_name, pa_threaded_mainloop *loop, + pa_context *context, pa_stream_flags_t flags, + pa_buffer_attr *attr, pa_sample_spec *spec, + pa_channel_map *chanmap); +static int PulsePlayback_mixerProc(PulsePlayback *self); + +static void PulsePlayback_Construct(PulsePlayback *self, ALCdevice *device); +static void PulsePlayback_Destruct(PulsePlayback *self); +static ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name); +static ALCboolean PulsePlayback_reset(PulsePlayback *self); +static ALCboolean PulsePlayback_start(PulsePlayback *self); +static void PulsePlayback_stop(PulsePlayback *self); +static DECLARE_FORWARD2(PulsePlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) +static DECLARE_FORWARD(PulsePlayback, ALCbackend, ALCuint, availableSamples) +static ClockLatency PulsePlayback_getClockLatency(PulsePlayback *self); +static void PulsePlayback_lock(PulsePlayback *self); +static void PulsePlayback_unlock(PulsePlayback *self); +DECLARE_DEFAULT_ALLOCATORS(PulsePlayback) + +DEFINE_ALCBACKEND_VTABLE(PulsePlayback); + + +static void PulsePlayback_Construct(PulsePlayback *self, ALCdevice *device) +{ + new (self) PulsePlayback(); + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(PulsePlayback, ALCbackend, self); +} + +static void PulsePlayback_Destruct(PulsePlayback *self) +{ + if(self->loop) + { + pulse_close(self->loop, self->context, self->stream); + self->loop = nullptr; + self->context = nullptr; + self->stream = nullptr; + } + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~PulsePlayback(); +} + + +static void PulsePlayback_deviceCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) +{ + auto loop{reinterpret_cast(pdata)}; + + if(eol) + { + pa_threaded_mainloop_signal(loop, 0); + return; + } + + if(std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + [info](const DevMap &entry) -> bool + { return entry.device_name == info->name; } + ) != PlaybackDevices.cend()) + return; + + PlaybackDevices.emplace_back(); + DevMap &newentry{PlaybackDevices.back()}; + + int count{0}; + while(1) + { + newentry.name = info->description; + if(count != 0) + { + newentry.name += " #"; + newentry.name += std::to_string(count+1); + } + + if(std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend()-1, + [&newentry](const DevMap &entry) -> bool + { return entry.name == newentry.name; } + ) == PlaybackDevices.cend()-1) + break; + count++; + } + newentry.device_name = info->name; + + TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str()); +} + +static void PulsePlayback_probeDevices(void) +{ + PlaybackDevices.clear(); + + auto loop{pa_threaded_mainloop_new()}; + if(loop && pa_threaded_mainloop_start(loop) >= 0) + { + unique_palock palock{loop}; + + auto context{connect_context(loop, AL_FALSE)}; + if(context) + { + pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | + PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE}; + + pa_sample_spec spec; + spec.format = PA_SAMPLE_S16NE; + spec.rate = 44100; + spec.channels = 2; + + auto stream{PulsePlayback_connectStream(nullptr, + loop, context, flags, nullptr, &spec, nullptr + )}; + if(stream) + { + auto op{pa_context_get_sink_info_by_name(context, + pa_stream_get_device_name(stream), PulsePlayback_deviceCallback, loop + )}; + wait_for_operation(op, loop); + + pa_stream_disconnect(stream); + pa_stream_unref(stream); + stream = nullptr; + } + + auto op{pa_context_get_sink_info_list(context, + PulsePlayback_deviceCallback, loop + )}; + wait_for_operation(op, loop); + + pa_context_disconnect(context); + pa_context_unref(context); + } + palock = unique_palock{}; + pa_threaded_mainloop_stop(loop); + } + if(loop) + pa_threaded_mainloop_free(loop); +} + + +static void PulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata) +{ + auto self{reinterpret_cast(pdata)}; + + self->attr = *pa_stream_get_buffer_attr(stream); + TRACE("minreq=%d, tlength=%d, prebuf=%d\n", self->attr.minreq, self->attr.tlength, self->attr.prebuf); + /* FIXME: Update the device's UpdateSize (and/or NumUpdates) using the new + * buffer attributes? Changing UpdateSize will change the ALC_REFRESH + * property, which probably shouldn't change between device resets. But + * leaving it alone means ALC_REFRESH will be off. + */ +} + +static void PulsePlayback_contextStateCallback(pa_context *context, void *pdata) +{ + auto self{reinterpret_cast(pdata)}; + if(pa_context_get_state(context) == PA_CONTEXT_FAILED) + { + ERR("Received context failure!\n"); + aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice, "Playback state failure"); + } + pa_threaded_mainloop_signal(self->loop, 0); +} + +static void PulsePlayback_streamStateCallback(pa_stream *stream, void *pdata) +{ + auto self{reinterpret_cast(pdata)}; + if(pa_stream_get_state(stream) == PA_STREAM_FAILED) + { + ERR("Received stream failure!\n"); + aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice, "Playback stream failure"); + } + pa_threaded_mainloop_signal(self->loop, 0); +} + +static void PulsePlayback_streamWriteCallback(pa_stream* UNUSED(p), size_t UNUSED(nbytes), void *pdata) +{ + auto self{reinterpret_cast(pdata)}; + pa_threaded_mainloop_signal(self->loop, 0); +} + +static void PulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) +{ + struct ChannelMap { + DevFmtChannels chans; + pa_channel_map map; + }; + static constexpr std::array chanmaps{{ + { DevFmtX71, { 8, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, + PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT + } } }, + { DevFmtX61, { 7, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_REAR_CENTER, + PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT + } } }, + { DevFmtX51, { 6, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT + } } }, + { DevFmtX51Rear, { 6, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT + } } }, + { DevFmtQuad, { 4, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT + } } }, + { DevFmtStereo, { 2, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT + } } }, + { DevFmtMono, { 1, {PA_CHANNEL_POSITION_MONO} } } + }}; + auto self{reinterpret_cast(pdata)}; + + if(eol) + { + pa_threaded_mainloop_signal(self->loop, 0); + return; + } + + ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; + auto chanmap{std::find_if(chanmaps.cbegin(), chanmaps.cend(), + [info](const ChannelMap &chanmap) -> bool + { return pa_channel_map_superset(&info->channel_map, &chanmap.map); } + )}; + if(chanmap != chanmaps.cend()) + { + if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) + device->FmtChans = chanmap->chans; + } + else + { + char chanmap_str[PA_CHANNEL_MAP_SNPRINT_MAX]{}; + pa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map); + WARN("Failed to find format for channel map:\n %s\n", chanmap_str); + } + + if(info->active_port) + TRACE("Active port: %s (%s)\n", info->active_port->name, info->active_port->description); + device->IsHeadphones = (info->active_port && + strcmp(info->active_port->name, "analog-output-headphones") == 0 && + device->FmtChans == DevFmtStereo); +} + +static void PulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) +{ + auto self{reinterpret_cast(pdata)}; + + if(eol) + { + pa_threaded_mainloop_signal(self->loop, 0); + return; + } + + ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; + alstr_copy_cstr(&device->DeviceName, info->description); +} + + +static void PulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata) +{ + auto self{reinterpret_cast(pdata)}; + + self->device_name = pa_stream_get_device_name(stream); + + TRACE("Stream moved to %s\n", self->device_name.c_str()); +} + + +static pa_stream *PulsePlayback_connectStream(const char *device_name, + pa_threaded_mainloop *loop, pa_context *context, + pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, + pa_channel_map *chanmap) +{ + if(!device_name) + { + device_name = getenv("ALSOFT_PULSE_DEFAULT"); + if(device_name && !device_name[0]) + device_name = nullptr; + } + + auto stream{pa_stream_new_with_proplist(context, + "Playback Stream", spec, chanmap, prop_filter + )}; + if(!stream) + { + ERR("pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context))); + return nullptr; + } + + pa_stream_set_state_callback(stream, stream_state_callback, loop); + + if(pa_stream_connect_playback(stream, device_name, attr, flags, nullptr, nullptr) < 0) + { + ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(context))); + pa_stream_unref(stream); + return nullptr; + } + + pa_stream_state_t state; + while((state=pa_stream_get_state(stream)) != PA_STREAM_READY) + { + if(!PA_STREAM_IS_GOOD(state)) + { + ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(context))); + pa_stream_unref(stream); + return nullptr; + } + + pa_threaded_mainloop_wait(loop); + } + pa_stream_set_state_callback(stream, nullptr, nullptr); + + return stream; +} + + +static int PulsePlayback_mixerProc(PulsePlayback *self) +{ + ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; + + SetRTPriority(); + althrd_setname(althrd_current(), MIXER_THREAD_NAME); + + unique_palock palock{self->loop}; + size_t frame_size{pa_frame_size(&self->spec)}; + + while(!self->killNow.load(almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + { + auto len{static_cast(pa_stream_writable_size(self->stream))}; + if(UNLIKELY(len < 0)) + { + ERR("Failed to get writable size: %ld", (long)len); + aluHandleDisconnect(device, "Failed to get writable size: %ld", (long)len); + break; + } + + /* Make sure we're going to write at least 2 'periods' (minreqs), in + * case the server increased it since starting playback. Also round up + * the number of writable periods if it's not an integer count. + */ + ALint buffer_size{static_cast(self->attr.minreq) * maxi( + (self->attr.tlength + self->attr.minreq/2) / self->attr.minreq, 2 + )}; + + /* NOTE: This assumes pa_stream_writable_size returns between 0 and + * tlength, else there will be more latency than intended. + */ + len = buffer_size - maxi((ssize_t)self->attr.tlength - len, 0); + if(len < self->attr.minreq) + { + if(pa_stream_is_corked(self->stream)) + { + auto op{pa_stream_cork(self->stream, 0, nullptr, nullptr)}; + if(op) pa_operation_unref(op); + } + pa_threaded_mainloop_wait(self->loop); + continue; + } + + len -= len%self->attr.minreq; + len -= len%frame_size; + + auto buf{pa_xmalloc(len)}; + aluMixData(device, buf, len/frame_size); + + auto ret{pa_stream_write(self->stream, buf, len, pa_xfree, 0, PA_SEEK_RELATIVE)}; + if(UNLIKELY(ret != PA_OK)) + ERR("Failed to write to stream: %d, %s\n", ret, pa_strerror(ret)); + } + + return 0; +} + + +static ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) +{ + const char *pulse_name{nullptr}; + const char *dev_name{nullptr}; + + if(name) + { + if(PlaybackDevices.empty()) + PulsePlayback_probeDevices(); + + auto iter{std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + [name](const DevMap &entry) -> bool + { return entry.name == name; } + )}; + if(iter == PlaybackDevices.cend()) + return ALC_INVALID_VALUE; + pulse_name = iter->device_name.c_str(); + dev_name = iter->name.c_str(); + } + + std::tie(self->loop, self->context) = pulse_open(PulsePlayback_contextStateCallback, self); + if(!self->loop) return ALC_INVALID_VALUE; + + unique_palock palock{self->loop}; + + pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | + PA_STREAM_FIX_CHANNELS}; + if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 0)) + flags |= PA_STREAM_DONT_MOVE; + + pa_sample_spec spec{}; + spec.format = PA_SAMPLE_S16NE; + spec.rate = 44100; + spec.channels = 2; + + TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); + self->stream = PulsePlayback_connectStream(pulse_name, self->loop, self->context, + flags, nullptr, &spec, nullptr); + if(!self->stream) + { + palock = unique_palock{}; + pulse_close(self->loop, self->context, self->stream); + self->loop = nullptr; + self->context = nullptr; + return ALC_INVALID_VALUE; + } + pa_stream_set_moved_callback(self->stream, PulsePlayback_streamMovedCallback, self); + + self->device_name = pa_stream_get_device_name(self->stream); + if(!dev_name) + { + auto o = pa_context_get_sink_info_by_name(self->context, + self->device_name.c_str(), PulsePlayback_sinkNameCallback, self + ); + wait_for_operation(o, self->loop); + } + else + { + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + alstr_copy_cstr(&device->DeviceName, dev_name); + } + + return ALC_NO_ERROR; +} + +static ALCboolean PulsePlayback_reset(PulsePlayback *self) +{ + unique_palock palock{self->loop}; + + if(self->stream) + { + pa_stream_set_state_callback(self->stream, nullptr, nullptr); + pa_stream_set_moved_callback(self->stream, nullptr, nullptr); + pa_stream_set_write_callback(self->stream, nullptr, nullptr); + pa_stream_set_buffer_attr_callback(self->stream, nullptr, nullptr); + pa_stream_disconnect(self->stream); + pa_stream_unref(self->stream); + self->stream = nullptr; + } + + auto op{pa_context_get_sink_info_by_name(self->context, + self->device_name.c_str(), PulsePlayback_sinkInfoCallback, self + )}; + wait_for_operation(op, self->loop); + + ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; + pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_ADJUST_LATENCY | + PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE}; + if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 0)) + flags |= PA_STREAM_DONT_MOVE; + if(GetConfigValueBool(alstr_get_cstr(device->DeviceName), "pulse", "fix-rate", 0) || + !(device->Flags&DEVICE_FREQUENCY_REQUEST)) + flags |= PA_STREAM_FIX_RATE; + + switch(device->FmtType) + { + case DevFmtByte: + device->FmtType = DevFmtUByte; + /* fall-through */ + case DevFmtUByte: + self->spec.format = PA_SAMPLE_U8; + break; + case DevFmtUShort: + device->FmtType = DevFmtShort; + /* fall-through */ + case DevFmtShort: + self->spec.format = PA_SAMPLE_S16NE; + break; + case DevFmtUInt: + device->FmtType = DevFmtInt; + /* fall-through */ + case DevFmtInt: + self->spec.format = PA_SAMPLE_S32NE; + break; + case DevFmtFloat: + self->spec.format = PA_SAMPLE_FLOAT32NE; + break; + } + self->spec.rate = device->Frequency; + self->spec.channels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + + if(pa_sample_spec_valid(&self->spec) == 0) + { + ERR("Invalid sample format\n"); + return ALC_FALSE; + } + + const char *mapname{nullptr}; + pa_channel_map chanmap; + switch(device->FmtChans) + { + case DevFmtMono: + mapname = "mono"; + break; + case DevFmtAmbi3D: + device->FmtChans = DevFmtStereo; + /*fall-through*/ + case DevFmtStereo: + mapname = "front-left,front-right"; + break; + case DevFmtQuad: + mapname = "front-left,front-right,rear-left,rear-right"; + break; + case DevFmtX51: + mapname = "front-left,front-right,front-center,lfe,side-left,side-right"; + break; + case DevFmtX51Rear: + mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right"; + break; + case DevFmtX61: + mapname = "front-left,front-right,front-center,lfe,rear-center,side-left,side-right"; + break; + case DevFmtX71: + mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right"; + break; + } + if(!pa_channel_map_parse(&chanmap, mapname)) + { + ERR("Failed to build channel map for %s\n", DevFmtChannelsString(device->FmtChans)); + return ALC_FALSE; + } + SetDefaultWFXChannelOrder(device); + + self->attr.fragsize = -1; + self->attr.prebuf = 0; + self->attr.minreq = device->UpdateSize * pa_frame_size(&self->spec); + self->attr.tlength = self->attr.minreq * maxu(device->NumUpdates, 2); + self->attr.maxlength = -1; + + self->stream = PulsePlayback_connectStream(self->device_name.c_str(), + self->loop, self->context, flags, &self->attr, &self->spec, &chanmap + ); + if(!self->stream) + return ALC_FALSE; + pa_stream_set_state_callback(self->stream, PulsePlayback_streamStateCallback, self); + pa_stream_set_moved_callback(self->stream, PulsePlayback_streamMovedCallback, self); + pa_stream_set_write_callback(self->stream, PulsePlayback_streamWriteCallback, self); + + self->spec = *(pa_stream_get_sample_spec(self->stream)); + if(device->Frequency != self->spec.rate) + { + /* Server updated our playback rate, so modify the buffer attribs + * accordingly. */ + device->NumUpdates = (ALuint)clampd( + (ALdouble)device->NumUpdates/device->Frequency*self->spec.rate + 0.5, 2.0, 16.0 + ); + + self->attr.minreq = device->UpdateSize * pa_frame_size(&self->spec); + self->attr.tlength = self->attr.minreq * device->NumUpdates; + self->attr.maxlength = -1; + self->attr.prebuf = 0; + + op = pa_stream_set_buffer_attr(self->stream, &self->attr, + stream_success_callback, self->loop); + wait_for_operation(op, self->loop); + + device->Frequency = self->spec.rate; + } + + pa_stream_set_buffer_attr_callback(self->stream, PulsePlayback_bufferAttrCallback, self); + PulsePlayback_bufferAttrCallback(self->stream, self); + + device->NumUpdates = (ALuint)clampu64( + (self->attr.tlength + self->attr.minreq/2) / self->attr.minreq, 2, 16 + ); + device->UpdateSize = self->attr.minreq / pa_frame_size(&self->spec); + + /* HACK: prebuf should be 0 as that's what we set it to. However on some + * systems it comes back as non-0, so we have to make sure the device will + * write enough audio to start playback. The lack of manual start control + * may have unintended consequences, but it's better than not starting at + * all. + */ + if(self->attr.prebuf != 0) + { + ALuint len{self->attr.prebuf / (ALuint)pa_frame_size(&self->spec)}; + if(len <= device->UpdateSize*device->NumUpdates) + ERR("Non-0 prebuf, %u samples (%u bytes), device has %u samples\n", + len, self->attr.prebuf, device->UpdateSize*device->NumUpdates); + else + { + ERR("Large prebuf, %u samples (%u bytes), increasing device from %u samples", + len, self->attr.prebuf, device->UpdateSize*device->NumUpdates); + device->NumUpdates = (len+device->UpdateSize-1) / device->UpdateSize; + } + } + + return ALC_TRUE; +} + +static ALCboolean PulsePlayback_start(PulsePlayback *self) +{ + try { + self->killNow.store(AL_FALSE, almemory_order_release); + self->thread = std::thread(PulsePlayback_mixerProc, self); + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Failed to start thread: %s\n", e.what()); + } + catch(...) { + ERR("Failed to start thread\n"); + } + return ALC_FALSE; +} + +static void PulsePlayback_stop(PulsePlayback *self) +{ + self->killNow.store(AL_TRUE, almemory_order_release); + if(!self->stream || !self->thread.joinable()) + return; + + /* Signal the main loop in case PulseAudio isn't sending us audio requests + * (e.g. if the device is suspended). We need to lock the mainloop in case + * the mixer is between checking the killNow flag but before waiting for + * the signal. + */ + unique_palock palock{self->loop}; + palock.unlock(); + + pa_threaded_mainloop_signal(self->loop, 0); + self->thread.join(); + + palock.lock(); + + auto o = pa_stream_cork(self->stream, 1, stream_success_callback, self->loop); + wait_for_operation(o, self->loop); +} + + +static ClockLatency PulsePlayback_getClockLatency(PulsePlayback *self) +{ + ClockLatency ret; + pa_usec_t latency; + int neg, err; + + { palock_guard _{self->loop}; + ret.ClockTime = GetDeviceClockTime(STATIC_CAST(ALCbackend,self)->mDevice); + err = pa_stream_get_latency(self->stream, &latency, &neg); + } + + if(UNLIKELY(err != 0)) + { + /* 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); + latency = 0; + neg = 0; + } + else if(UNLIKELY(neg)) + latency = 0; + ret.Latency = (ALint64)minu64(latency, U64(0x7fffffffffffffff)/1000) * 1000; + + return ret; +} + + +static void PulsePlayback_lock(PulsePlayback *self) +{ + pa_threaded_mainloop_lock(self->loop); +} + +static void PulsePlayback_unlock(PulsePlayback *self) +{ + pa_threaded_mainloop_unlock(self->loop); +} + + +struct PulseCapture { + DERIVE_FROM_TYPE(ALCbackend); + + std::string device_name; + + const void *cap_store{nullptr}; + size_t cap_len{0}; + size_t cap_remain{0}; + + ALCuint last_readable{0}; + + pa_buffer_attr attr; + pa_sample_spec spec; + + pa_threaded_mainloop *loop{nullptr}; + + pa_stream *stream{nullptr}; + pa_context *context{nullptr}; +}; + +static void PulseCapture_deviceCallback(pa_context *context, const pa_source_info *info, int eol, void *pdata); +static void PulseCapture_probeDevices(void); + +static void PulseCapture_contextStateCallback(pa_context *context, void *pdata); +static void PulseCapture_streamStateCallback(pa_stream *stream, void *pdata); +static void PulseCapture_sourceNameCallback(pa_context *context, const pa_source_info *info, int eol, void *pdata); +static void PulseCapture_streamMovedCallback(pa_stream *stream, void *pdata); +static pa_stream *PulseCapture_connectStream(const char *device_name, + pa_threaded_mainloop *loop, pa_context *context, + pa_stream_flags_t flags, pa_buffer_attr *attr, + pa_sample_spec *spec, pa_channel_map *chanmap); + +static void PulseCapture_Construct(PulseCapture *self, ALCdevice *device); +static void PulseCapture_Destruct(PulseCapture *self); +static ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name); +static DECLARE_FORWARD(PulseCapture, ALCbackend, ALCboolean, reset) +static ALCboolean PulseCapture_start(PulseCapture *self); +static void PulseCapture_stop(PulseCapture *self); +static ALCenum PulseCapture_captureSamples(PulseCapture *self, ALCvoid *buffer, ALCuint samples); +static ALCuint PulseCapture_availableSamples(PulseCapture *self); +static ClockLatency PulseCapture_getClockLatency(PulseCapture *self); +static void PulseCapture_lock(PulseCapture *self); +static void PulseCapture_unlock(PulseCapture *self); +DECLARE_DEFAULT_ALLOCATORS(PulseCapture) + +DEFINE_ALCBACKEND_VTABLE(PulseCapture); + + +static void PulseCapture_Construct(PulseCapture *self, ALCdevice *device) +{ + new (self) PulseCapture(); + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(PulseCapture, ALCbackend, self); +} + +static void PulseCapture_Destruct(PulseCapture *self) +{ + if(self->loop) + { + pulse_close(self->loop, self->context, self->stream); + self->loop = nullptr; + self->context = nullptr; + self->stream = nullptr; + } + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~PulseCapture(); +} + + +static void PulseCapture_deviceCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata) +{ + auto loop{reinterpret_cast(pdata)}; + + if(eol) + { + pa_threaded_mainloop_signal(loop, 0); + return; + } + + if(std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), + [info](const DevMap &entry) -> bool + { return entry.device_name == info->name; } + ) != CaptureDevices.cend()) + return; + + CaptureDevices.emplace_back(); + DevMap &newentry{CaptureDevices.back()}; + + int count{0}; + while(1) + { + newentry.name = info->description; + if(count != 0) + { + newentry.name += " #"; + newentry.name += std::to_string(count+1); + } + + if(std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend()-1, + [&newentry](const DevMap &entry) -> bool + { return entry.name == newentry.name; } + ) == CaptureDevices.cend()-1) + break; + count++; + } + newentry.device_name = info->name; + + TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str()); +} + +static void PulseCapture_probeDevices(void) +{ + CaptureDevices.clear(); + + auto loop{pa_threaded_mainloop_new()}; + if(loop && pa_threaded_mainloop_start(loop) >= 0) + { + unique_palock palock{loop}; + + auto context{connect_context(loop, AL_FALSE)}; + if(context) + { + pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | + PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE}; + + pa_sample_spec spec; + spec.format = PA_SAMPLE_S16NE; + spec.rate = 44100; + spec.channels = 1; + + auto stream{PulseCapture_connectStream(nullptr, + loop, context, flags, nullptr, &spec, nullptr + )}; + if(stream) + { + auto op{pa_context_get_source_info_by_name(context, + pa_stream_get_device_name(stream), PulseCapture_deviceCallback, loop + )}; + wait_for_operation(op, loop); + + pa_stream_disconnect(stream); + pa_stream_unref(stream); + stream = nullptr; + } + + auto op{pa_context_get_source_info_list(context, + PulseCapture_deviceCallback, loop + )}; + wait_for_operation(op, loop); + + pa_context_disconnect(context); + pa_context_unref(context); + } + palock.unlock(); + pa_threaded_mainloop_stop(loop); + } + if(loop) + pa_threaded_mainloop_free(loop); +} + + +static void PulseCapture_contextStateCallback(pa_context *context, void *pdata) +{ + auto self{reinterpret_cast(pdata)}; + if(pa_context_get_state(context) == PA_CONTEXT_FAILED) + { + ERR("Received context failure!\n"); + aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice, "Capture state failure"); + } + pa_threaded_mainloop_signal(self->loop, 0); +} + +static void PulseCapture_streamStateCallback(pa_stream *stream, void *pdata) +{ + auto self{reinterpret_cast(pdata)}; + if(pa_stream_get_state(stream) == PA_STREAM_FAILED) + { + ERR("Received stream failure!\n"); + aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice, "Capture stream failure"); + } + pa_threaded_mainloop_signal(self->loop, 0); +} + + +static void PulseCapture_sourceNameCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata) +{ + auto self{reinterpret_cast(pdata)}; + + if(eol) + { + pa_threaded_mainloop_signal(self->loop, 0); + return; + } + + ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; + alstr_copy_cstr(&device->DeviceName, info->description); +} + + +static void PulseCapture_streamMovedCallback(pa_stream *stream, void *pdata) +{ + auto self{reinterpret_cast(pdata)}; + + self->device_name = pa_stream_get_device_name(stream); + + TRACE("Stream moved to %s\n", self->device_name.c_str()); +} + + +static pa_stream *PulseCapture_connectStream(const char *device_name, + pa_threaded_mainloop *loop, pa_context *context, + pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, + pa_channel_map *chanmap) +{ + auto stream{pa_stream_new_with_proplist(context, + "Capture Stream", spec, chanmap, prop_filter + )}; + if(!stream) + { + ERR("pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context))); + return nullptr; + } + + pa_stream_set_state_callback(stream, stream_state_callback, loop); + + if(pa_stream_connect_record(stream, device_name, attr, flags) < 0) + { + ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(context))); + pa_stream_unref(stream); + return nullptr; + } + + pa_stream_state_t state; + while((state=pa_stream_get_state(stream)) != PA_STREAM_READY) + { + if(!PA_STREAM_IS_GOOD(state)) + { + ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(context))); + pa_stream_unref(stream); + return nullptr; + } + + pa_threaded_mainloop_wait(loop); + } + pa_stream_set_state_callback(stream, nullptr, nullptr); + + return stream; +} + + +static ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) +{ + ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; + const char *pulse_name{nullptr}; + + if(name) + { + if(CaptureDevices.empty()) + PulseCapture_probeDevices(); + + auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), + [name](const DevMap &entry) -> bool + { return entry.name == name; } + ); + if(iter == CaptureDevices.cend()) + return ALC_INVALID_VALUE; + pulse_name = iter->device_name.c_str(); + alstr_copy_cstr(&device->DeviceName, iter->name.c_str()); + } + + std::tie(self->loop, self->context) = pulse_open(PulseCapture_contextStateCallback, self); + if(!self->loop) return ALC_INVALID_VALUE; + + unique_palock palock{self->loop}; + + switch(device->FmtType) + { + case DevFmtUByte: + self->spec.format = PA_SAMPLE_U8; + break; + case DevFmtShort: + self->spec.format = PA_SAMPLE_S16NE; + break; + case DevFmtInt: + self->spec.format = PA_SAMPLE_S32NE; + break; + case DevFmtFloat: + self->spec.format = PA_SAMPLE_FLOAT32NE; + break; + case DevFmtByte: + case DevFmtUShort: + case DevFmtUInt: + ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); + return ALC_INVALID_VALUE; + } + + const char *mapname{nullptr}; + pa_channel_map chanmap; + switch(device->FmtChans) + { + case DevFmtMono: + mapname = "mono"; + break; + case DevFmtStereo: + mapname = "front-left,front-right"; + break; + case DevFmtQuad: + mapname = "front-left,front-right,rear-left,rear-right"; + break; + case DevFmtX51: + mapname = "front-left,front-right,front-center,lfe,side-left,side-right"; + break; + case DevFmtX51Rear: + mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right"; + break; + case DevFmtX61: + mapname = "front-left,front-right,front-center,lfe,rear-center,side-left,side-right"; + break; + case DevFmtX71: + mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right"; + break; + case DevFmtAmbi3D: + ERR("%s capture samples not supported\n", DevFmtChannelsString(device->FmtChans)); + return ALC_INVALID_VALUE; + } + if(!pa_channel_map_parse(&chanmap, mapname)) + { + ERR("Failed to build channel map for %s\n", DevFmtChannelsString(device->FmtChans)); + return ALC_INVALID_VALUE; + } + + self->spec.rate = device->Frequency; + self->spec.channels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + + if(pa_sample_spec_valid(&self->spec) == 0) + { + ERR("Invalid sample format\n"); + return ALC_INVALID_VALUE; + } + + if(!pa_channel_map_init_auto(&chanmap, self->spec.channels, PA_CHANNEL_MAP_WAVEEX)) + { + ERR("Couldn't build map for channel count (%d)!\n", self->spec.channels); + return ALC_INVALID_VALUE; + } + + ALuint samples{device->UpdateSize * device->NumUpdates}; + samples = maxu(samples, 100 * device->Frequency / 1000); + + self->attr.minreq = -1; + self->attr.prebuf = -1; + self->attr.maxlength = samples * pa_frame_size(&self->spec); + self->attr.tlength = -1; + self->attr.fragsize = minu(samples, 50*device->Frequency/1000) * + pa_frame_size(&self->spec); + + pa_stream_flags_t flags{PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY}; + if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 0)) + flags |= PA_STREAM_DONT_MOVE; + + TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); + self->stream = PulseCapture_connectStream(pulse_name, + self->loop, self->context, flags, &self->attr, &self->spec, &chanmap + ); + if(!self->stream) + return ALC_INVALID_VALUE; + pa_stream_set_moved_callback(self->stream, PulseCapture_streamMovedCallback, self); + pa_stream_set_state_callback(self->stream, PulseCapture_streamStateCallback, self); + + self->device_name = pa_stream_get_device_name(self->stream); + if(alstr_empty(device->DeviceName)) + { + pa_operation *o = pa_context_get_source_info_by_name(self->context, + self->device_name.c_str(), PulseCapture_sourceNameCallback, self + ); + wait_for_operation(o, self->loop); + } + + return ALC_NO_ERROR; +} + +static ALCboolean PulseCapture_start(PulseCapture *self) +{ + palock_guard _{self->loop}; + auto o = pa_stream_cork(self->stream, 0, stream_success_callback, self->loop); + wait_for_operation(o, self->loop); + return ALC_TRUE; +} + +static void PulseCapture_stop(PulseCapture *self) +{ + palock_guard _{self->loop}; + auto o = pa_stream_cork(self->stream, 1, stream_success_callback, self->loop); + wait_for_operation(o, self->loop); +} + +static ALCenum PulseCapture_captureSamples(PulseCapture *self, ALCvoid *buffer, ALCuint samples) +{ + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCuint todo = samples * pa_frame_size(&self->spec); + + /* Capture is done in fragment-sized chunks, so we loop until we get all + * that's available */ + self->last_readable -= todo; + unique_palock palock{self->loop}; + while(todo > 0) + { + size_t rem = todo; + + if(self->cap_len == 0) + { + auto state{pa_stream_get_state(self->stream)}; + if(!PA_STREAM_IS_GOOD(state)) + { + aluHandleDisconnect(device, "Bad capture state: %u", state); + return ALC_INVALID_DEVICE; + } + if(pa_stream_peek(self->stream, &self->cap_store, &self->cap_len) < 0) + { + ERR("pa_stream_peek() failed: %s\n", + pa_strerror(pa_context_errno(self->context))); + aluHandleDisconnect(device, "Failed retrieving capture samples: %s", + pa_strerror(pa_context_errno(self->context))); + return ALC_INVALID_DEVICE; + } + self->cap_remain = self->cap_len; + } + if(rem > self->cap_remain) + rem = self->cap_remain; + + memcpy(buffer, self->cap_store, rem); + + buffer = (ALbyte*)buffer + rem; + todo -= rem; + + self->cap_store = (ALbyte*)self->cap_store + rem; + self->cap_remain -= rem; + if(self->cap_remain == 0) + { + pa_stream_drop(self->stream); + self->cap_len = 0; + } + } + palock.unlock(); + if(todo > 0) + memset(buffer, ((device->FmtType==DevFmtUByte) ? 0x80 : 0), todo); + + return ALC_NO_ERROR; +} + +static ALCuint PulseCapture_availableSamples(PulseCapture *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + size_t readable = self->cap_remain; + + if(ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + { + palock_guard _{self->loop}; + auto got{static_cast(pa_stream_readable_size(self->stream))}; + if(got < 0) + { + ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got)); + aluHandleDisconnect(device, "Failed getting readable size: %s", pa_strerror(got)); + } + else if((size_t)got > self->cap_len) + readable += got - self->cap_len; + } + + if(self->last_readable < readable) + self->last_readable = readable; + return self->last_readable / pa_frame_size(&self->spec); +} + + +static ClockLatency PulseCapture_getClockLatency(PulseCapture *self) +{ + ClockLatency ret; + pa_usec_t latency; + int neg, err; + + { palock_guard _{self->loop}; + ret.ClockTime = GetDeviceClockTime(STATIC_CAST(ALCbackend,self)->mDevice); + err = pa_stream_get_latency(self->stream, &latency, &neg); + } + + if(UNLIKELY(err != 0)) + { + ERR("Failed to get stream latency: 0x%x\n", err); + latency = 0; + neg = 0; + } + else if(UNLIKELY(neg)) + latency = 0; + ret.Latency = (ALint64)minu64(latency, U64(0x7fffffffffffffff)/1000) * 1000; + + return ret; +} + + +static void PulseCapture_lock(PulseCapture *self) +{ + pa_threaded_mainloop_lock(self->loop); +} + +static void PulseCapture_unlock(PulseCapture *self) +{ + pa_threaded_mainloop_unlock(self->loop); +} + + +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, al_string *outnames); +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}; + + if(pulse_load()) + { + pulse_ctx_flags = PA_CONTEXT_NOFLAGS; + if(!GetConfigValueBool(nullptr, "pulse", "spawn-server", 1)) + pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN; + + auto loop{pa_threaded_mainloop_new()}; + if(loop && pa_threaded_mainloop_start(loop) >= 0) + { + unique_palock palock{loop}; + auto context = connect_context(loop, AL_TRUE); + if(context) + { + ret = ALC_TRUE; + + /* Some libraries (Phonon, Qt) set some pulseaudio properties + * through environment variables, which causes all streams in + * the process to inherit them. This attempts to filter those + * properties out by setting them to 0-length data. */ + prop_filter = pa_proplist_new(); + pa_proplist_set(prop_filter, PA_PROP_MEDIA_ROLE, nullptr, 0); + pa_proplist_set(prop_filter, "phonon.streamid", nullptr, 0); + + pa_context_disconnect(context); + pa_context_unref(context); + } + palock.unlock(); + pa_threaded_mainloop_stop(loop); + } + if(loop) + pa_threaded_mainloop_free(loop); + } + + return ret; +} + +static void ALCpulseBackendFactory_deinit(ALCpulseBackendFactory* UNUSED(self)) +{ + PlaybackDevices.clear(); + CaptureDevices.clear(); + + if(prop_filter) + pa_proplist_free(prop_filter); + prop_filter = nullptr; + + /* PulseAudio doesn't like being CloseLib'd sometimes */ +} + +static ALCboolean ALCpulseBackendFactory_querySupport(ALCpulseBackendFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Playback || type == ALCbackend_Capture) + return ALC_TRUE; + return ALC_FALSE; +} + +static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +{ + auto add_device{ + [outnames](const DevMap &entry) -> void + { + auto name{entry.name.c_str()}; + auto namelen{entry.name.length()}; + /* +1 to also append the null char (to ensure a null-separated list + * and double-null terminated list). + */ + alstr_append_range(outnames, name, name + namelen+1); + } + }; + switch(type) + { + case ALL_DEVICE_PROBE: + PulsePlayback_probeDevices(); + std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); + break; + + case CAPTURE_DEVICE_PROBE: + PulseCapture_probeDevices(); + std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); + break; + } +} + +static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + PulsePlayback *backend; + NEW_OBJ(backend, PulsePlayback)(device); + if(!backend) return nullptr; + return STATIC_CAST(ALCbackend, backend); + } + if(type == ALCbackend_Capture) + { + PulseCapture *backend; + NEW_OBJ(backend, PulseCapture)(device); + if(!backend) return nullptr; + return STATIC_CAST(ALCbackend, backend); + } + + return nullptr; +} + + +#else /* PA_API_VERSION == 12 */ + +#warning "Unsupported API version, backend will be unavailable!" + +typedef struct ALCpulseBackendFactory { + DERIVE_FROM_TYPE(ALCbackendFactory); +} ALCpulseBackendFactory; +#define ALCPULSEBACKENDFACTORY_INITIALIZER { GET_VTABLE2(ALCpulseBackendFactory, ALCbackendFactory) } + +static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory* UNUSED(self)) +{ + return ALC_FALSE; +} + +static void ALCpulseBackendFactory_deinit(ALCpulseBackendFactory* UNUSED(self)) +{ +} + +static ALCboolean ALCpulseBackendFactory_querySupport(ALCpulseBackendFactory* UNUSED(self), ALCbackend_Type UNUSED(type)) +{ + return ALC_FALSE; +} + +static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), enum DevProbe UNUSED(type), al_string* UNUSED(outnames)) +{ +} + +static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory* UNUSED(self), ALCdevice* UNUSED(device), ALCbackend_Type UNUSED(type)) +{ + return nullptr; +} + +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCpulseBackendFactory); + +#endif /* PA_API_VERSION == 12 */ + +ALCbackendFactory *ALCpulseBackendFactory_getFactory(void) +{ + static ALCpulseBackendFactory factory{ALCPULSEBACKENDFACTORY_INITIALIZER}; + return STATIC_CAST(ALCbackendFactory, &factory); +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 799703a5..ef6b731c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1201,7 +1201,7 @@ IF(PULSEAUDIO_FOUND) IF(ALSOFT_BACKEND_PULSEAUDIO) SET(HAVE_PULSEAUDIO 1) SET(BACKENDS "${BACKENDS} PulseAudio${IS_LINKED},") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/pulseaudio.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/pulseaudio.cpp) ADD_BACKEND_LIBS(${PULSEAUDIO_LIBRARIES}) SET(INC_PATHS ${INC_PATHS} ${PULSEAUDIO_INCLUDE_DIRS}) ENDIF() -- cgit v1.2.3 From 353bb1ed17ac5d6788e6ea43c3f0c9729257f959 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Oct 2018 22:10:26 -0700 Subject: Avoid uniform initialization on auto for integer types To work around a deficiency with early C++11 compilers (GCC 4.x). --- Alc/backends/pulseaudio.cpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index b75716bc..684377d3 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -375,7 +375,7 @@ static pa_proplist *prop_filter; static void context_state_callback(pa_context *context, void *pdata) { auto loop{reinterpret_cast(pdata)}; - auto state{pa_context_get_state(context)}; + pa_context_state_t state{pa_context_get_state(context)}; if(state == PA_CONTEXT_READY || !PA_CONTEXT_IS_GOOD(state)) pa_threaded_mainloop_signal(loop, 0); } @@ -383,7 +383,7 @@ static void context_state_callback(pa_context *context, void *pdata) static void stream_state_callback(pa_stream *stream, void *pdata) { auto loop{reinterpret_cast(pdata)}; - auto state{pa_stream_get_state(stream)}; + pa_stream_state_t state{pa_stream_get_state(stream)}; if(state == PA_STREAM_READY || !PA_STREAM_IS_GOOD(state)) pa_threaded_mainloop_signal(loop, 0); } @@ -874,7 +874,7 @@ static int PulsePlayback_mixerProc(PulsePlayback *self) while(!self->killNow.load(almemory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { - auto len{static_cast(pa_stream_writable_size(self->stream))}; + ssize_t len{static_cast(pa_stream_writable_size(self->stream))}; if(UNLIKELY(len < 0)) { ERR("Failed to get writable size: %ld", (long)len); @@ -911,7 +911,7 @@ static int PulsePlayback_mixerProc(PulsePlayback *self) auto buf{pa_xmalloc(len)}; aluMixData(device, buf, len/frame_size); - auto ret{pa_stream_write(self->stream, buf, len, pa_xfree, 0, PA_SEEK_RELATIVE)}; + int ret{pa_stream_write(self->stream, buf, len, pa_xfree, 0, PA_SEEK_RELATIVE)}; if(UNLIKELY(ret != PA_OK)) ERR("Failed to write to stream: %d, %s\n", ret, pa_strerror(ret)); } @@ -971,10 +971,10 @@ static ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) self->device_name = pa_stream_get_device_name(self->stream); if(!dev_name) { - auto o = pa_context_get_sink_info_by_name(self->context, + auto op = pa_context_get_sink_info_by_name(self->context, self->device_name.c_str(), PulsePlayback_sinkNameCallback, self ); - wait_for_operation(o, self->loop); + wait_for_operation(op, self->loop); } else { @@ -1185,8 +1185,8 @@ static void PulsePlayback_stop(PulsePlayback *self) palock.lock(); - auto o = pa_stream_cork(self->stream, 1, stream_success_callback, self->loop); - wait_for_operation(o, self->loop); + auto op = pa_stream_cork(self->stream, 1, stream_success_callback, self->loop); + wait_for_operation(op, self->loop); } @@ -1603,10 +1603,10 @@ static ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) self->device_name = pa_stream_get_device_name(self->stream); if(alstr_empty(device->DeviceName)) { - pa_operation *o = pa_context_get_source_info_by_name(self->context, + auto op{pa_context_get_source_info_by_name(self->context, self->device_name.c_str(), PulseCapture_sourceNameCallback, self - ); - wait_for_operation(o, self->loop); + )}; + wait_for_operation(op, self->loop); } return ALC_NO_ERROR; @@ -1615,16 +1615,16 @@ static ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) static ALCboolean PulseCapture_start(PulseCapture *self) { palock_guard _{self->loop}; - auto o = pa_stream_cork(self->stream, 0, stream_success_callback, self->loop); - wait_for_operation(o, self->loop); + auto op = pa_stream_cork(self->stream, 0, stream_success_callback, self->loop); + wait_for_operation(op, self->loop); return ALC_TRUE; } static void PulseCapture_stop(PulseCapture *self) { palock_guard _{self->loop}; - auto o = pa_stream_cork(self->stream, 1, stream_success_callback, self->loop); - wait_for_operation(o, self->loop); + auto op = pa_stream_cork(self->stream, 1, stream_success_callback, self->loop); + wait_for_operation(op, self->loop); } static ALCenum PulseCapture_captureSamples(PulseCapture *self, ALCvoid *buffer, ALCuint samples) @@ -1689,7 +1689,7 @@ static ALCuint PulseCapture_availableSamples(PulseCapture *self) if(ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { palock_guard _{self->loop}; - auto got{static_cast(pa_stream_readable_size(self->stream))}; + ssize_t got{static_cast(pa_stream_readable_size(self->stream))}; if(got < 0) { ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got)); @@ -1819,7 +1819,7 @@ static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), e [outnames](const DevMap &entry) -> void { auto name{entry.name.c_str()}; - auto namelen{entry.name.length()}; + size_t namelen{entry.name.length()}; /* +1 to also append the null char (to ensure a null-separated list * and double-null terminated list). */ -- cgit v1.2.3 From 759c3a996cc53be39cb1e57454ff77588b28bdc8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Nov 2018 08:04:21 -0700 Subject: Avoid all uniform initialization with auto Because of early C++11 (GCC 4.x) deficiencies, it's not interpreted correctly. Either declare the type name explicitly with uniform initization, or use auto with = initialization. It'll be fine when updating to GCC 5 or Clang 3.6. --- Alc/backends/pulseaudio.cpp | 130 ++++++++++++++++++++++---------------------- 1 file changed, 64 insertions(+), 66 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 684377d3..5b75d872 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -374,7 +374,7 @@ static pa_proplist *prop_filter; /* PulseAudio Event Callbacks */ static void context_state_callback(pa_context *context, void *pdata) { - auto loop{reinterpret_cast(pdata)}; + auto loop = reinterpret_cast(pdata); pa_context_state_t state{pa_context_get_state(context)}; if(state == PA_CONTEXT_READY || !PA_CONTEXT_IS_GOOD(state)) pa_threaded_mainloop_signal(loop, 0); @@ -382,7 +382,7 @@ static void context_state_callback(pa_context *context, void *pdata) static void stream_state_callback(pa_stream *stream, void *pdata) { - auto loop{reinterpret_cast(pdata)}; + auto loop = reinterpret_cast(pdata); pa_stream_state_t state{pa_stream_get_state(stream)}; if(state == PA_STREAM_READY || !PA_STREAM_IS_GOOD(state)) pa_threaded_mainloop_signal(loop, 0); @@ -390,7 +390,7 @@ static void stream_state_callback(pa_stream *stream, void *pdata) static void stream_success_callback(pa_stream *UNUSED(stream), int UNUSED(success), void *pdata) { - auto loop{reinterpret_cast(pdata)}; + auto loop = reinterpret_cast(pdata); pa_threaded_mainloop_signal(loop, 0); } @@ -414,7 +414,7 @@ static pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent) if(!alstr_empty(binname)) name = alstr_get_cstr(binname); - auto context{pa_context_new(pa_threaded_mainloop_get_api(loop), name)}; + pa_context *context{pa_context_new(pa_threaded_mainloop_get_api(loop), name)}; if(!context) { ERR("pa_context_new() failed\n"); @@ -458,7 +458,7 @@ static pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent) using MainloopContextPair = std::pair; static MainloopContextPair pulse_open(void(*state_cb)(pa_context*,void*), void *ptr) { - auto loop{pa_threaded_mainloop_new()}; + pa_threaded_mainloop *loop{pa_threaded_mainloop_new()}; if(UNLIKELY(!loop)) { ERR("pa_threaded_mainloop_new() failed!\n"); @@ -472,7 +472,7 @@ static MainloopContextPair pulse_open(void(*state_cb)(pa_context*,void*), void * } unique_palock palock{loop}; - auto context{connect_context(loop, AL_FALSE)}; + pa_context *context{connect_context(loop, AL_FALSE)}; if(UNLIKELY(!context)) { palock = unique_palock{}; @@ -587,7 +587,7 @@ static void PulsePlayback_Destruct(PulsePlayback *self) static void PulsePlayback_deviceCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) { - auto loop{reinterpret_cast(pdata)}; + auto loop = reinterpret_cast(pdata); if(eol) { @@ -630,12 +630,12 @@ static void PulsePlayback_probeDevices(void) { PlaybackDevices.clear(); - auto loop{pa_threaded_mainloop_new()}; + pa_threaded_mainloop *loop{pa_threaded_mainloop_new()}; if(loop && pa_threaded_mainloop_start(loop) >= 0) { unique_palock palock{loop}; - auto context{connect_context(loop, AL_FALSE)}; + pa_context *context{connect_context(loop, AL_FALSE)}; if(context) { pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | @@ -646,12 +646,12 @@ static void PulsePlayback_probeDevices(void) spec.rate = 44100; spec.channels = 2; - auto stream{PulsePlayback_connectStream(nullptr, + pa_stream *stream{PulsePlayback_connectStream(nullptr, loop, context, flags, nullptr, &spec, nullptr )}; if(stream) { - auto op{pa_context_get_sink_info_by_name(context, + pa_operation *op{pa_context_get_sink_info_by_name(context, pa_stream_get_device_name(stream), PulsePlayback_deviceCallback, loop )}; wait_for_operation(op, loop); @@ -661,7 +661,7 @@ static void PulsePlayback_probeDevices(void) stream = nullptr; } - auto op{pa_context_get_sink_info_list(context, + pa_operation *op{pa_context_get_sink_info_list(context, PulsePlayback_deviceCallback, loop )}; wait_for_operation(op, loop); @@ -679,7 +679,7 @@ static void PulsePlayback_probeDevices(void) static void PulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata) { - auto self{reinterpret_cast(pdata)}; + auto self = reinterpret_cast(pdata); self->attr = *pa_stream_get_buffer_attr(stream); TRACE("minreq=%d, tlength=%d, prebuf=%d\n", self->attr.minreq, self->attr.tlength, self->attr.prebuf); @@ -692,7 +692,7 @@ static void PulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata) static void PulsePlayback_contextStateCallback(pa_context *context, void *pdata) { - auto self{reinterpret_cast(pdata)}; + auto self = reinterpret_cast(pdata); if(pa_context_get_state(context) == PA_CONTEXT_FAILED) { ERR("Received context failure!\n"); @@ -703,7 +703,7 @@ static void PulsePlayback_contextStateCallback(pa_context *context, void *pdata) static void PulsePlayback_streamStateCallback(pa_stream *stream, void *pdata) { - auto self{reinterpret_cast(pdata)}; + auto self = reinterpret_cast(pdata); if(pa_stream_get_state(stream) == PA_STREAM_FAILED) { ERR("Received stream failure!\n"); @@ -714,7 +714,7 @@ static void PulsePlayback_streamStateCallback(pa_stream *stream, void *pdata) static void PulsePlayback_streamWriteCallback(pa_stream* UNUSED(p), size_t UNUSED(nbytes), void *pdata) { - auto self{reinterpret_cast(pdata)}; + auto self = reinterpret_cast(pdata); pa_threaded_mainloop_signal(self->loop, 0); } @@ -756,7 +756,7 @@ static void PulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa } } }, { DevFmtMono, { 1, {PA_CHANNEL_POSITION_MONO} } } }}; - auto self{reinterpret_cast(pdata)}; + auto self = reinterpret_cast(pdata); if(eol) { @@ -765,10 +765,10 @@ static void PulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa } ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; - auto chanmap{std::find_if(chanmaps.cbegin(), chanmaps.cend(), + auto chanmap = std::find_if(chanmaps.cbegin(), chanmaps.cend(), [info](const ChannelMap &chanmap) -> bool { return pa_channel_map_superset(&info->channel_map, &chanmap.map); } - )}; + ); if(chanmap != chanmaps.cend()) { if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) @@ -790,7 +790,7 @@ static void PulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa static void PulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) { - auto self{reinterpret_cast(pdata)}; + auto self = reinterpret_cast(pdata); if(eol) { @@ -805,7 +805,7 @@ static void PulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const pa static void PulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata) { - auto self{reinterpret_cast(pdata)}; + auto self = reinterpret_cast(pdata); self->device_name = pa_stream_get_device_name(stream); @@ -825,7 +825,7 @@ static pa_stream *PulsePlayback_connectStream(const char *device_name, device_name = nullptr; } - auto stream{pa_stream_new_with_proplist(context, + pa_stream *stream{pa_stream_new_with_proplist(context, "Playback Stream", spec, chanmap, prop_filter )}; if(!stream) @@ -898,7 +898,7 @@ static int PulsePlayback_mixerProc(PulsePlayback *self) { if(pa_stream_is_corked(self->stream)) { - auto op{pa_stream_cork(self->stream, 0, nullptr, nullptr)}; + pa_operation *op{pa_stream_cork(self->stream, 0, nullptr, nullptr)}; if(op) pa_operation_unref(op); } pa_threaded_mainloop_wait(self->loop); @@ -908,7 +908,7 @@ static int PulsePlayback_mixerProc(PulsePlayback *self) len -= len%self->attr.minreq; len -= len%frame_size; - auto buf{pa_xmalloc(len)}; + void *buf{pa_xmalloc(len)}; aluMixData(device, buf, len/frame_size); int ret{pa_stream_write(self->stream, buf, len, pa_xfree, 0, PA_SEEK_RELATIVE)}; @@ -930,10 +930,10 @@ static ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) if(PlaybackDevices.empty()) PulsePlayback_probeDevices(); - auto iter{std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), [name](const DevMap &entry) -> bool { return entry.name == name; } - )}; + ); if(iter == PlaybackDevices.cend()) return ALC_INVALID_VALUE; pulse_name = iter->device_name.c_str(); @@ -971,14 +971,14 @@ static ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) self->device_name = pa_stream_get_device_name(self->stream); if(!dev_name) { - auto op = pa_context_get_sink_info_by_name(self->context, + pa_operation *op{pa_context_get_sink_info_by_name(self->context, self->device_name.c_str(), PulsePlayback_sinkNameCallback, self - ); + )}; wait_for_operation(op, self->loop); } else { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; alstr_copy_cstr(&device->DeviceName, dev_name); } @@ -1000,7 +1000,7 @@ static ALCboolean PulsePlayback_reset(PulsePlayback *self) self->stream = nullptr; } - auto op{pa_context_get_sink_info_by_name(self->context, + pa_operation *op{pa_context_get_sink_info_by_name(self->context, self->device_name.c_str(), PulsePlayback_sinkInfoCallback, self )}; wait_for_operation(op, self->loop); @@ -1185,7 +1185,7 @@ static void PulsePlayback_stop(PulsePlayback *self) palock.lock(); - auto op = pa_stream_cork(self->stream, 1, stream_success_callback, self->loop); + pa_operation *op{pa_stream_cork(self->stream, 1, stream_success_callback, self->loop)}; wait_for_operation(op, self->loop); } @@ -1302,7 +1302,7 @@ static void PulseCapture_Destruct(PulseCapture *self) static void PulseCapture_deviceCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata) { - auto loop{reinterpret_cast(pdata)}; + auto loop = reinterpret_cast(pdata); if(eol) { @@ -1345,12 +1345,12 @@ static void PulseCapture_probeDevices(void) { CaptureDevices.clear(); - auto loop{pa_threaded_mainloop_new()}; + pa_threaded_mainloop *loop{pa_threaded_mainloop_new()}; if(loop && pa_threaded_mainloop_start(loop) >= 0) { unique_palock palock{loop}; - auto context{connect_context(loop, AL_FALSE)}; + pa_context *context{connect_context(loop, AL_FALSE)}; if(context) { pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | @@ -1361,12 +1361,12 @@ static void PulseCapture_probeDevices(void) spec.rate = 44100; spec.channels = 1; - auto stream{PulseCapture_connectStream(nullptr, + pa_stream *stream{PulseCapture_connectStream(nullptr, loop, context, flags, nullptr, &spec, nullptr )}; if(stream) { - auto op{pa_context_get_source_info_by_name(context, + pa_operation *op{pa_context_get_source_info_by_name(context, pa_stream_get_device_name(stream), PulseCapture_deviceCallback, loop )}; wait_for_operation(op, loop); @@ -1376,7 +1376,7 @@ static void PulseCapture_probeDevices(void) stream = nullptr; } - auto op{pa_context_get_source_info_list(context, + pa_operation *op{pa_context_get_source_info_list(context, PulseCapture_deviceCallback, loop )}; wait_for_operation(op, loop); @@ -1394,7 +1394,7 @@ static void PulseCapture_probeDevices(void) static void PulseCapture_contextStateCallback(pa_context *context, void *pdata) { - auto self{reinterpret_cast(pdata)}; + auto self = reinterpret_cast(pdata); if(pa_context_get_state(context) == PA_CONTEXT_FAILED) { ERR("Received context failure!\n"); @@ -1405,7 +1405,7 @@ static void PulseCapture_contextStateCallback(pa_context *context, void *pdata) static void PulseCapture_streamStateCallback(pa_stream *stream, void *pdata) { - auto self{reinterpret_cast(pdata)}; + auto self = reinterpret_cast(pdata); if(pa_stream_get_state(stream) == PA_STREAM_FAILED) { ERR("Received stream failure!\n"); @@ -1417,7 +1417,7 @@ static void PulseCapture_streamStateCallback(pa_stream *stream, void *pdata) static void PulseCapture_sourceNameCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata) { - auto self{reinterpret_cast(pdata)}; + auto self = reinterpret_cast(pdata); if(eol) { @@ -1432,7 +1432,7 @@ static void PulseCapture_sourceNameCallback(pa_context *UNUSED(context), const p static void PulseCapture_streamMovedCallback(pa_stream *stream, void *pdata) { - auto self{reinterpret_cast(pdata)}; + auto self = reinterpret_cast(pdata); self->device_name = pa_stream_get_device_name(stream); @@ -1445,7 +1445,7 @@ static pa_stream *PulseCapture_connectStream(const char *device_name, pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, pa_channel_map *chanmap) { - auto stream{pa_stream_new_with_proplist(context, + pa_stream *stream{pa_stream_new_with_proplist(context, "Capture Stream", spec, chanmap, prop_filter )}; if(!stream) @@ -1603,7 +1603,7 @@ static ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) self->device_name = pa_stream_get_device_name(self->stream); if(alstr_empty(device->DeviceName)) { - auto op{pa_context_get_source_info_by_name(self->context, + pa_operation *op{pa_context_get_source_info_by_name(self->context, self->device_name.c_str(), PulseCapture_sourceNameCallback, self )}; wait_for_operation(op, self->loop); @@ -1615,7 +1615,7 @@ static ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) static ALCboolean PulseCapture_start(PulseCapture *self) { palock_guard _{self->loop}; - auto op = pa_stream_cork(self->stream, 0, stream_success_callback, self->loop); + pa_operation *op{pa_stream_cork(self->stream, 0, stream_success_callback, self->loop)}; wait_for_operation(op, self->loop); return ALC_TRUE; } @@ -1623,14 +1623,14 @@ static ALCboolean PulseCapture_start(PulseCapture *self) static void PulseCapture_stop(PulseCapture *self) { palock_guard _{self->loop}; - auto op = pa_stream_cork(self->stream, 1, stream_success_callback, self->loop); + pa_operation *op{pa_stream_cork(self->stream, 1, stream_success_callback, self->loop)}; wait_for_operation(op, self->loop); } static ALCenum PulseCapture_captureSamples(PulseCapture *self, ALCvoid *buffer, ALCuint samples) { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - ALCuint todo = samples * pa_frame_size(&self->spec); + ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; + ALCuint todo{samples * static_cast(pa_frame_size(&self->spec))}; /* Capture is done in fragment-sized chunks, so we loop until we get all * that's available */ @@ -1638,11 +1638,11 @@ static ALCenum PulseCapture_captureSamples(PulseCapture *self, ALCvoid *buffer, unique_palock palock{self->loop}; while(todo > 0) { - size_t rem = todo; + size_t rem{todo}; if(self->cap_len == 0) { - auto state{pa_stream_get_state(self->stream)}; + pa_stream_state_t state{pa_stream_get_state(self->stream)}; if(!PA_STREAM_IS_GOOD(state)) { aluHandleDisconnect(device, "Bad capture state: %u", state); @@ -1683,19 +1683,19 @@ static ALCenum PulseCapture_captureSamples(PulseCapture *self, ALCvoid *buffer, static ALCuint PulseCapture_availableSamples(PulseCapture *self) { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - size_t readable = self->cap_remain; + ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; + size_t readable{self->cap_remain}; if(ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { palock_guard _{self->loop}; - ssize_t got{static_cast(pa_stream_readable_size(self->stream))}; - if(got < 0) + size_t got{pa_stream_readable_size(self->stream)}; + if(static_cast(got) < 0) { ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got)); aluHandleDisconnect(device, "Failed getting readable size: %s", pa_strerror(got)); } - else if((size_t)got > self->cap_len) + else if(got > self->cap_len) readable += got - self->cap_len; } @@ -1764,11 +1764,11 @@ static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory* UNUSED(sel if(!GetConfigValueBool(nullptr, "pulse", "spawn-server", 1)) pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN; - auto loop{pa_threaded_mainloop_new()}; + pa_threaded_mainloop *loop{pa_threaded_mainloop_new()}; if(loop && pa_threaded_mainloop_start(loop) >= 0) { unique_palock palock{loop}; - auto context = connect_context(loop, AL_TRUE); + pa_context *context{connect_context(loop, AL_TRUE)}; if(context) { ret = ALC_TRUE; @@ -1815,16 +1815,14 @@ static ALCboolean ALCpulseBackendFactory_querySupport(ALCpulseBackendFactory* UN static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { - auto add_device{ - [outnames](const DevMap &entry) -> void - { - auto name{entry.name.c_str()}; - size_t namelen{entry.name.length()}; - /* +1 to also append the null char (to ensure a null-separated list - * and double-null terminated list). - */ - alstr_append_range(outnames, name, name + namelen+1); - } + auto add_device = [outnames](const DevMap &entry) -> void + { + auto name{entry.name.c_str()}; + size_t namelen{entry.name.length()}; + /* +1 to also append the null char (to ensure a null-separated list + * and double-null terminated list). + */ + alstr_append_range(outnames, name, name + namelen+1); }; switch(type) { -- cgit v1.2.3 From 95966c4d923483da81627abaf2419a48d6dd8bab Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Nov 2018 08:15:47 -0700 Subject: Fix another use of auto uniform initialization --- Alc/backends/pulseaudio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 5b75d872..136d7e75 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -1817,7 +1817,7 @@ static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), e { auto add_device = [outnames](const DevMap &entry) -> void { - auto name{entry.name.c_str()}; + const char *name{entry.name.c_str()}; size_t namelen{entry.name.length()}; /* +1 to also append the null char (to ensure a null-separated list * and double-null terminated list). -- cgit v1.2.3 From ccf356a03dbfc871f4d29cb03ef4d45f9842f5c2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Nov 2018 08:17:23 -0700 Subject: Include a missing header for atomic --- Alc/backends/pulseaudio.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 136d7e75..439450cb 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From 48f877e85954caea71b6e41aebb54a46347746a7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Nov 2018 08:19:51 -0700 Subject: Remove unused header --- Alc/backends/pulseaudio.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 439450cb..004425ce 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -33,7 +33,6 @@ #include "alMain.h" #include "alu.h" #include "alconfig.h" -#include "threads.h" #include "compat.h" #include "backends/base.h" -- cgit v1.2.3 From d28c0eb5568180b143763fa5648e36d20d7fd575 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Nov 2018 08:41:23 -0700 Subject: Avoid uniform initialization with references Also doesn't work with GCC 4.x --- Alc/backends/pulseaudio.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 004425ce..bdcf3cb8 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -602,7 +602,7 @@ static void PulsePlayback_deviceCallback(pa_context *UNUSED(context), const pa_s return; PlaybackDevices.emplace_back(); - DevMap &newentry{PlaybackDevices.back()}; + DevMap &newentry = PlaybackDevices.back(); int count{0}; while(1) @@ -1317,7 +1317,7 @@ static void PulseCapture_deviceCallback(pa_context *UNUSED(context), const pa_so return; CaptureDevices.emplace_back(); - DevMap &newentry{CaptureDevices.back()}; + DevMap &newentry = CaptureDevices.back(); int count{0}; while(1) -- cgit v1.2.3 From 5d092a1c588eb3369e9e488b5fc608ce4288aacb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Nov 2018 08:43:31 -0700 Subject: Use the appropriate enums for standard atomics --- Alc/backends/pulseaudio.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index bdcf3cb8..b0c64d26 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -871,7 +871,7 @@ static int PulsePlayback_mixerProc(PulsePlayback *self) unique_palock palock{self->loop}; size_t frame_size{pa_frame_size(&self->spec)}; - while(!self->killNow.load(almemory_order_acquire) && + while(!self->killNow.load(std::memory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { ssize_t len{static_cast(pa_stream_writable_size(self->stream))}; @@ -1153,7 +1153,7 @@ static ALCboolean PulsePlayback_reset(PulsePlayback *self) static ALCboolean PulsePlayback_start(PulsePlayback *self) { try { - self->killNow.store(AL_FALSE, almemory_order_release); + self->killNow.store(AL_FALSE, std::memory_order_release); self->thread = std::thread(PulsePlayback_mixerProc, self); return ALC_TRUE; } @@ -1168,7 +1168,7 @@ static ALCboolean PulsePlayback_start(PulsePlayback *self) static void PulsePlayback_stop(PulsePlayback *self) { - self->killNow.store(AL_TRUE, almemory_order_release); + self->killNow.store(AL_TRUE, std::memory_order_release); if(!self->stream || !self->thread.joinable()) return; -- cgit v1.2.3 From cd68530ab4d340d61f524ea2d03176ed775e4e68 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Nov 2018 11:44:11 -0700 Subject: Simplify a couple loops --- Alc/backends/pulseaudio.cpp | 76 +++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index b0c64d26..a6f6564d 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -509,6 +509,10 @@ static void pulse_close(pa_threaded_mainloop *loop, pa_context *context, pa_stre struct DevMap { std::string name; std::string device_name; + + DevMap(std::string name_, std::string devname_) + : name{std::move(name_)}, device_name{std::move(devname_)} + { } }; static std::vector PlaybackDevices; @@ -595,34 +599,30 @@ static void PulsePlayback_deviceCallback(pa_context *UNUSED(context), const pa_s return; } + /* Skip this device is if it's already in the list. */ if(std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), [info](const DevMap &entry) -> bool { return entry.device_name == info->name; } ) != PlaybackDevices.cend()) return; - PlaybackDevices.emplace_back(); + /* Make sure the display name (description) is unique. Append a number + * counter as needed. + */ + int count{1}; + std::string newname{info->description}; + while(std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + [&newname](const DevMap &entry) -> bool + { return entry.name == newname; } + ) != PlaybackDevices.cend()) + { + newname = info->description; + newname += " #"; + newname += std::to_string(++count); + } + PlaybackDevices.emplace_back(std::move(newname), info->name); DevMap &newentry = PlaybackDevices.back(); - int count{0}; - while(1) - { - newentry.name = info->description; - if(count != 0) - { - newentry.name += " #"; - newentry.name += std::to_string(count+1); - } - - if(std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend()-1, - [&newentry](const DevMap &entry) -> bool - { return entry.name == newentry.name; } - ) == PlaybackDevices.cend()-1) - break; - count++; - } - newentry.device_name = info->name; - TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str()); } @@ -1310,34 +1310,30 @@ static void PulseCapture_deviceCallback(pa_context *UNUSED(context), const pa_so return; } + /* Skip this device is if it's already in the list. */ if(std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), [info](const DevMap &entry) -> bool { return entry.device_name == info->name; } ) != CaptureDevices.cend()) return; - CaptureDevices.emplace_back(); + /* Make sure the display name (description) is unique. Append a number + * counter as needed. + */ + int count{1}; + std::string newname{info->description}; + while(std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), + [&newname](const DevMap &entry) -> bool + { return entry.name == newname; } + ) != CaptureDevices.cend()) + { + newname = info->description; + newname += " #"; + newname += std::to_string(++count); + } + CaptureDevices.emplace_back(std::move(newname), std::string{info->name}); DevMap &newentry = CaptureDevices.back(); - int count{0}; - while(1) - { - newentry.name = info->description; - if(count != 0) - { - newentry.name += " #"; - newentry.name += std::to_string(count+1); - } - - if(std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend()-1, - [&newentry](const DevMap &entry) -> bool - { return entry.name == newentry.name; } - ) == CaptureDevices.cend()-1) - break; - count++; - } - newentry.device_name = info->name; - TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str()); } -- cgit v1.2.3 From 69162cf9c6dcf938d5c7d1f949f307142604c65a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Nov 2018 13:12:42 -0700 Subject: Use perfect forwarding to initialize DevMap entries --- Alc/backends/pulseaudio.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index a6f6564d..15f02e1a 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -510,8 +510,9 @@ struct DevMap { std::string name; std::string device_name; - DevMap(std::string name_, std::string devname_) - : name{std::move(name_)}, device_name{std::move(devname_)} + template + DevMap(StrT0&& name_, StrT1&& devname_) + : name{std::forward(name_)}, device_name{std::forward(devname_)} { } }; @@ -1331,7 +1332,7 @@ static void PulseCapture_deviceCallback(pa_context *UNUSED(context), const pa_so newname += " #"; newname += std::to_string(++count); } - CaptureDevices.emplace_back(std::move(newname), std::string{info->name}); + CaptureDevices.emplace_back(std::move(newname), info->name); DevMap &newentry = CaptureDevices.back(); TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str()); -- cgit v1.2.3 From 11967dc2dae5e8364dc78bea6f644570e06bf999 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Nov 2018 16:00:16 -0700 Subject: Use a wrapper function to simplify a check --- Alc/backends/pulseaudio.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 15f02e1a..a52a028d 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -516,6 +516,14 @@ struct DevMap { { } }; +static bool checkName(const std::vector &list, const std::string &name) +{ + return std::find_if(list.cbegin(), list.cend(), + [&name](const DevMap &entry) -> bool + { return entry.name == name; } + ) != list.cend(); +} + static std::vector PlaybackDevices; static std::vector CaptureDevices; @@ -612,10 +620,7 @@ static void PulsePlayback_deviceCallback(pa_context *UNUSED(context), const pa_s */ int count{1}; std::string newname{info->description}; - while(std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), - [&newname](const DevMap &entry) -> bool - { return entry.name == newname; } - ) != PlaybackDevices.cend()) + while(checkName(PlaybackDevices, newname)) { newname = info->description; newname += " #"; @@ -1323,10 +1328,7 @@ static void PulseCapture_deviceCallback(pa_context *UNUSED(context), const pa_so */ int count{1}; std::string newname{info->description}; - while(std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), - [&newname](const DevMap &entry) -> bool - { return entry.name == newname; } - ) != CaptureDevices.cend()) + while(checkName(CaptureDevices, newname)) { newname = info->description; newname += " #"; -- cgit v1.2.3 From c0ce71a17519652f6663b886be0a84598ab0c095 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Nov 2018 16:00:38 -0700 Subject: Fix a macro check --- Alc/converter.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/converter.h b/Alc/converter.h index b58fd831..3f0c6304 100644 --- a/Alc/converter.h +++ b/Alc/converter.h @@ -4,7 +4,7 @@ #include "alMain.h" #include "alu.h" -#ifdef __cpluspluc +#ifdef __cplusplus extern "C" { #endif @@ -48,7 +48,7 @@ void DestroyChannelConverter(ChannelConverter **converter); void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALfloat *dst, ALsizei frames); -#ifdef __cpluspluc +#ifdef __cplusplus } #endif -- cgit v1.2.3 From dee2905f4ad6294216fed58d8fa9831f6e8567a1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Nov 2018 16:10:46 -0700 Subject: Remove unused CXX_FLAGS variable The Visual Studio generators apparently don't like the $ expression. Since it's not actually used for anything at the moment, remove it. --- CMakeLists.txt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ef6b731c..ecee25d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,7 +66,6 @@ endif() SET(CPP_DEFS ) # C pre-process, not C++ SET(INC_PATHS ) SET(C_FLAGS ) -SET(CXX_FLAGS ) SET(LINKER_FLAGS ) SET(EXTRA_LIBS ) @@ -1430,7 +1429,7 @@ CONFIGURE_FILE( # Add a static library with common functions used by multiple targets ADD_LIBRARY(common STATIC ${COMMON_OBJS}) TARGET_COMPILE_DEFINITIONS(common PRIVATE ${CPP_DEFS}) -TARGET_COMPILE_OPTIONS(common PRIVATE ${C_FLAGS} $<$:${CXX_FLAGS}>) +TARGET_COMPILE_OPTIONS(common PRIVATE ${C_FLAGS}) UNSET(HAS_ROUTER) @@ -1463,7 +1462,7 @@ ELSE() ADD_LIBRARY(OpenAL SHARED router/router.cpp router/router.h router/alc.cpp router/al.cpp) TARGET_COMPILE_DEFINITIONS(OpenAL PRIVATE AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES ${CPP_DEFS}) - TARGET_COMPILE_OPTIONS(OpenAL PRIVATE ${C_FLAGS} $<$:${CXX_FLAGS}>) + TARGET_COMPILE_OPTIONS(OpenAL PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(OpenAL PRIVATE ${COMMON_LIB} ${LINKER_FLAGS}) SET_TARGET_PROPERTIES(OpenAL PROPERTIES PREFIX "") SET_TARGET_PROPERTIES(OpenAL PROPERTIES OUTPUT_NAME ${LIBNAME}) @@ -1489,7 +1488,7 @@ TARGET_COMPILE_DEFINITIONS(${IMPL_TARGET} PRIVATE AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES ${CPP_DEFS}) TARGET_INCLUDE_DIRECTORIES(${IMPL_TARGET} PRIVATE "${OpenAL_SOURCE_DIR}/OpenAL32/Include" "${OpenAL_SOURCE_DIR}/Alc" ${INC_PATHS}) -TARGET_COMPILE_OPTIONS(${IMPL_TARGET} PRIVATE ${C_FLAGS} $<$:${CXX_FLAGS}>) +TARGET_COMPILE_OPTIONS(${IMPL_TARGET} PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(${IMPL_TARGET} PRIVATE ${COMMON_LIB} ${LINKER_FLAGS} ${EXTRA_LIBS} ${MATH_LIB}) IF(TARGET build_version) -- cgit v1.2.3 From 1ca4e268f6b40bad3bd6723e28fde74316a72ed6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Nov 2018 16:26:42 -0700 Subject: Preliminary conversion of the WASAPI backend to C++ A very sparse conversion. Will clean up more later after seeing what MSVC does. --- Alc/backends/wasapi.c | 2045 ----------------------------------------------- Alc/backends/wasapi.cpp | 2035 ++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 2036 insertions(+), 2046 deletions(-) delete mode 100644 Alc/backends/wasapi.c create mode 100644 Alc/backends/wasapi.cpp diff --git a/Alc/backends/wasapi.c b/Alc/backends/wasapi.c deleted file mode 100644 index 971a1f72..00000000 --- a/Alc/backends/wasapi.c +++ /dev/null @@ -1,2045 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2011 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#define COBJMACROS -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef _WAVEFORMATEXTENSIBLE_ -#include -#include -#endif - -#include "alMain.h" -#include "alu.h" -#include "ringbuffer.h" -#include "threads.h" -#include "compat.h" -#include "alstring.h" -#include "converter.h" - -#include "backends/base.h" - - -DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); -DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); -DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); -DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23,0xe0, 0xc0,0xff,0xee,0x7f,0x0e, 4 ); - -#define MONO SPEAKER_FRONT_CENTER -#define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT) -#define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT) -#define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) -#define X5DOT1REAR (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT) -#define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) -#define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) -#define X7DOT1_WIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_FRONT_LEFT_OF_CENTER|SPEAKER_FRONT_RIGHT_OF_CENTER) - -#define REFTIME_PER_SEC ((REFERENCE_TIME)10000000) - -#define DEVNAME_HEAD "OpenAL Soft on " - - -/* Scales the given value using 64-bit integer math, ceiling the result. */ -static inline ALuint64 ScaleCeil(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale) -{ - return (val*new_scale + old_scale-1) / old_scale; -} - - -typedef struct { - al_string name; - al_string endpoint_guid; // obtained from PKEY_AudioEndpoint_GUID , set to "Unknown device GUID" if absent. - WCHAR *devid; -} DevMap; -TYPEDEF_VECTOR(DevMap, vector_DevMap) - -static void clear_devlist(vector_DevMap *list) -{ -#define CLEAR_DEVMAP(i) do { \ - AL_STRING_DEINIT((i)->name); \ - AL_STRING_DEINIT((i)->endpoint_guid); \ - free((i)->devid); \ - (i)->devid = NULL; \ -} while(0) - VECTOR_FOR_EACH(DevMap, *list, CLEAR_DEVMAP); - VECTOR_RESIZE(*list, 0, 0); -#undef CLEAR_DEVMAP -} - -static vector_DevMap PlaybackDevices; -static vector_DevMap CaptureDevices; - - -static HANDLE ThreadHdl; -static DWORD ThreadID; - -typedef struct { - HANDLE FinishedEvt; - HRESULT result; -} ThreadRequest; - -#define WM_USER_First (WM_USER+0) -#define WM_USER_OpenDevice (WM_USER+0) -#define WM_USER_ResetDevice (WM_USER+1) -#define WM_USER_StartDevice (WM_USER+2) -#define WM_USER_StopDevice (WM_USER+3) -#define WM_USER_CloseDevice (WM_USER+4) -#define WM_USER_Enumerate (WM_USER+5) -#define WM_USER_Last (WM_USER+5) - -static const char MessageStr[WM_USER_Last+1-WM_USER][20] = { - "Open Device", - "Reset Device", - "Start Device", - "Stop Device", - "Close Device", - "Enumerate Devices", -}; - -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) - return req->result; - ERR("Message response error: %lu\n", GetLastError()); - return E_FAIL; -} - - -static void get_device_name_and_guid(IMMDevice *device, al_string *name, al_string *guid) -{ - IPropertyStore *ps; - PROPVARIANT pvname; - PROPVARIANT pvguid; - HRESULT hr; - - alstr_copy_cstr(name, DEVNAME_HEAD); - - hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps); - if(FAILED(hr)) - { - WARN("OpenPropertyStore failed: 0x%08lx\n", hr); - alstr_append_cstr(name, "Unknown Device Name"); - if(guid!=NULL)alstr_copy_cstr(guid, "Unknown Device GUID"); - return; - } - - PropVariantInit(&pvname); - - hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pvname); - if(FAILED(hr)) - { - WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr); - alstr_append_cstr(name, "Unknown Device Name"); - } - else if(pvname.vt == VT_LPWSTR) - alstr_append_wcstr(name, pvname.pwszVal); - else - { - WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvname.vt); - alstr_append_cstr(name, "Unknown Device Name"); - } - PropVariantClear(&pvname); - - if(guid!=NULL){ - PropVariantInit(&pvguid); - - hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&PKEY_AudioEndpoint_GUID, &pvguid); - if(FAILED(hr)) - { - WARN("GetValue AudioEndpoint_GUID failed: 0x%08lx\n", hr); - alstr_copy_cstr(guid, "Unknown Device GUID"); - } - else if(pvguid.vt == VT_LPWSTR) - alstr_copy_wcstr(guid, pvguid.pwszVal); - else - { - WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvguid.vt); - alstr_copy_cstr(guid, "Unknown Device GUID"); - } - - PropVariantClear(&pvguid); - } - - IPropertyStore_Release(ps); -} - -static void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfactor) -{ - IPropertyStore *ps; - PROPVARIANT pvform; - HRESULT hr; - - hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps); - if(FAILED(hr)) - { - WARN("OpenPropertyStore failed: 0x%08lx\n", hr); - return; - } - - PropVariantInit(&pvform); - - hr = IPropertyStore_GetValue(ps, &PKEY_AudioEndpoint_FormFactor, &pvform); - if(FAILED(hr)) - WARN("GetValue AudioEndpoint_FormFactor failed: 0x%08lx\n", hr); - else if(pvform.vt == VT_UI4) - *formfactor = pvform.ulVal; - else if(pvform.vt == VT_EMPTY) - *formfactor = UnknownFormFactor; - else - WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvform.vt); - - PropVariantClear(&pvform); - IPropertyStore_Release(ps); -} - - -static void add_device(IMMDevice *device, const WCHAR *devid, vector_DevMap *list) -{ - int count = 0; - al_string tmpname; - DevMap entry; - - AL_STRING_INIT(tmpname); - AL_STRING_INIT(entry.name); - AL_STRING_INIT(entry.endpoint_guid); - - entry.devid = strdupW(devid); - get_device_name_and_guid(device, &tmpname, &entry.endpoint_guid); - - while(1) - { - const DevMap *iter; - - alstr_copy(&entry.name, tmpname); - if(count != 0) - { - char str[64]; - snprintf(str, sizeof(str), " #%d", count+1); - alstr_append_cstr(&entry.name, str); - } - -#define MATCH_ENTRY(i) (alstr_cmp(entry.name, (i)->name) == 0) - VECTOR_FIND_IF(iter, const DevMap, *list, MATCH_ENTRY); - if(iter == VECTOR_END(*list)) break; -#undef MATCH_ENTRY - count++; - } - - TRACE("Got device \"%s\", \"%s\", \"%ls\"\n", alstr_get_cstr(entry.name), alstr_get_cstr(entry.endpoint_guid), entry.devid); - VECTOR_PUSH_BACK(*list, entry); - - AL_STRING_DEINIT(tmpname); -} - -static WCHAR *get_device_id(IMMDevice *device) -{ - WCHAR *devid; - HRESULT hr; - - hr = IMMDevice_GetId(device, &devid); - if(FAILED(hr)) - { - ERR("Failed to get device id: %lx\n", hr); - return NULL; - } - - return devid; -} - -static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, vector_DevMap *list) -{ - IMMDeviceCollection *coll; - IMMDevice *defdev = NULL; - WCHAR *defdevid = NULL; - HRESULT hr; - UINT count; - 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 hr; - } - - count = 0; - hr = IMMDeviceCollection_GetCount(coll, &count); - if(SUCCEEDED(hr) && count > 0) - { - clear_devlist(list); - VECTOR_RESIZE(*list, 0, count); - - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, flowdir, - eMultimedia, &defdev); - } - if(SUCCEEDED(hr) && defdev != NULL) - { - defdevid = get_device_id(defdev); - if(defdevid) - add_device(defdev, defdevid, list); - } - - for(i = 0;i < count;++i) - { - IMMDevice *device; - WCHAR *devid; - - hr = IMMDeviceCollection_Item(coll, i, &device); - if(FAILED(hr)) continue; - - devid = get_device_id(device); - if(devid) - { - if(wcscmp(devid, defdevid) != 0) - add_device(device, devid, list); - CoTaskMemFree(devid); - } - IMMDevice_Release(device); - } - - if(defdev) IMMDevice_Release(defdev); - if(defdevid) CoTaskMemFree(defdevid); - IMMDeviceCollection_Release(coll); - - return S_OK; -} - - -/* Proxy interface used by the message handler. */ -struct ALCwasapiProxyVtable; - -typedef struct ALCwasapiProxy { - const struct ALCwasapiProxyVtable *vtbl; -} ALCwasapiProxy; - -struct ALCwasapiProxyVtable { - HRESULT (*const openProxy)(ALCwasapiProxy*); - void (*const closeProxy)(ALCwasapiProxy*); - - HRESULT (*const resetProxy)(ALCwasapiProxy*); - HRESULT (*const startProxy)(ALCwasapiProxy*); - void (*const stopProxy)(ALCwasapiProxy*); -}; - -#define DEFINE_ALCWASAPIPROXY_VTABLE(T) \ -DECLARE_THUNK(T, ALCwasapiProxy, HRESULT, openProxy) \ -DECLARE_THUNK(T, ALCwasapiProxy, void, closeProxy) \ -DECLARE_THUNK(T, ALCwasapiProxy, HRESULT, resetProxy) \ -DECLARE_THUNK(T, ALCwasapiProxy, HRESULT, startProxy) \ -DECLARE_THUNK(T, ALCwasapiProxy, void, stopProxy) \ - \ -static const struct ALCwasapiProxyVtable T##_ALCwasapiProxy_vtable = { \ - T##_ALCwasapiProxy_openProxy, \ - T##_ALCwasapiProxy_closeProxy, \ - T##_ALCwasapiProxy_resetProxy, \ - T##_ALCwasapiProxy_startProxy, \ - T##_ALCwasapiProxy_stopProxy, \ -} - -static void ALCwasapiProxy_Construct(ALCwasapiProxy* UNUSED(self)) { } -static void ALCwasapiProxy_Destruct(ALCwasapiProxy* UNUSED(self)) { } - -static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) -{ - ThreadRequest *req = ptr; - IMMDeviceEnumerator *Enumerator; - ALuint deviceCount = 0; - ALCwasapiProxy *proxy; - HRESULT hr, cohr; - MSG msg; - - TRACE("Starting message thread\n"); - - cohr = CoInitializeEx(NULL, COINIT_MULTITHREADED); - 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 \"%s\" (0x%04x, lparam=%p, wparam=%p)\n", - (msg.message >= WM_USER && msg.message <= WM_USER_Last) ? - MessageStr[msg.message-WM_USER] : "Unknown", - msg.message, (void*)msg.lParam, (void*)msg.wParam - ); - switch(msg.message) - { - case WM_USER_OpenDevice: - req = (ThreadRequest*)msg.wParam; - proxy = (ALCwasapiProxy*)msg.lParam; - - hr = cohr = S_OK; - if(++deviceCount == 1) - hr = cohr = CoInitializeEx(NULL, COINIT_MULTITHREADED); - 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 = (ALCwasapiProxy*)msg.lParam; - - hr = V0(proxy,resetProxy)(); - ReturnMsgResponse(req, hr); - continue; - - case WM_USER_StartDevice: - req = (ThreadRequest*)msg.wParam; - proxy = (ALCwasapiProxy*)msg.lParam; - - hr = V0(proxy,startProxy)(); - ReturnMsgResponse(req, hr); - continue; - - case WM_USER_StopDevice: - req = (ThreadRequest*)msg.wParam; - proxy = (ALCwasapiProxy*)msg.lParam; - - V0(proxy,stopProxy)(); - ReturnMsgResponse(req, S_OK); - continue; - - case WM_USER_CloseDevice: - req = (ThreadRequest*)msg.wParam; - proxy = (ALCwasapiProxy*)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 = CoInitializeEx(NULL, COINIT_MULTITHREADED); - 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 ALCwasapiPlayback { - DERIVE_FROM_TYPE(ALCbackend); - DERIVE_FROM_TYPE(ALCwasapiProxy); - - WCHAR *devid; - - IMMDevice *mmdev; - IAudioClient *client; - IAudioRenderClient *render; - HANDLE NotifyEvent; - - HANDLE MsgEvent; - - ATOMIC(UINT32) Padding; - - ATOMIC(int) killNow; - althrd_t thread; -} ALCwasapiPlayback; - -static int ALCwasapiPlayback_mixerProc(void *arg); - -static void ALCwasapiPlayback_Construct(ALCwasapiPlayback *self, ALCdevice *device); -static void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self); -static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *name); -static HRESULT ALCwasapiPlayback_openProxy(ALCwasapiPlayback *self); -static void ALCwasapiPlayback_closeProxy(ALCwasapiPlayback *self); -static ALCboolean ALCwasapiPlayback_reset(ALCwasapiPlayback *self); -static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self); -static ALCboolean ALCwasapiPlayback_start(ALCwasapiPlayback *self); -static HRESULT ALCwasapiPlayback_startProxy(ALCwasapiPlayback *self); -static void ALCwasapiPlayback_stop(ALCwasapiPlayback *self); -static void ALCwasapiPlayback_stopProxy(ALCwasapiPlayback *self); -static DECLARE_FORWARD2(ALCwasapiPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -static DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, ALCuint, availableSamples) -static ClockLatency ALCwasapiPlayback_getClockLatency(ALCwasapiPlayback *self); -static DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCwasapiPlayback) - -DEFINE_ALCWASAPIPROXY_VTABLE(ALCwasapiPlayback); -DEFINE_ALCBACKEND_VTABLE(ALCwasapiPlayback); - - -static void ALCwasapiPlayback_Construct(ALCwasapiPlayback *self, ALCdevice *device) -{ - SET_VTABLE2(ALCwasapiPlayback, ALCbackend, self); - SET_VTABLE2(ALCwasapiPlayback, ALCwasapiProxy, self); - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - ALCwasapiProxy_Construct(STATIC_CAST(ALCwasapiProxy, self)); - - self->devid = NULL; - - self->mmdev = NULL; - self->client = NULL; - self->render = NULL; - self->NotifyEvent = NULL; - - self->MsgEvent = NULL; - - ATOMIC_INIT(&self->Padding, 0); - - ATOMIC_INIT(&self->killNow, 0); -} - -static void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self) -{ - if(self->MsgEvent) - { - ThreadRequest req = { self->MsgEvent, 0 }; - if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) - (void)WaitForResponse(&req); - - CloseHandle(self->MsgEvent); - self->MsgEvent = NULL; - } - - if(self->NotifyEvent) - CloseHandle(self->NotifyEvent); - self->NotifyEvent = NULL; - - free(self->devid); - self->devid = NULL; - - 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; - - ALCwasapiProxy_Destruct(STATIC_CAST(ALCwasapiProxy, self)); - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(void *arg) -{ - ALCwasapiPlayback *self = arg; - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - UINT32 buffer_len, written; - ALuint update_size, len; - BYTE *buffer; - HRESULT hr; - - hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); - if(FAILED(hr)) - { - ERR("CoInitializeEx(NULL, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); - V0(device->Backend,lock)(); - aluHandleDisconnect(device, "COM init failed: 0x%08lx", hr); - V0(device->Backend,unlock)(); - return 1; - } - - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - update_size = device->UpdateSize; - buffer_len = update_size * device->NumUpdates; - while(!ATOMIC_LOAD(&self->killNow, almemory_order_relaxed)) - { - hr = IAudioClient_GetCurrentPadding(self->client, &written); - if(FAILED(hr)) - { - ERR("Failed to get padding: 0x%08lx\n", hr); - V0(device->Backend,lock)(); - aluHandleDisconnect(device, "Failed to retrieve buffer padding: 0x%08lx", hr); - V0(device->Backend,unlock)(); - break; - } - ATOMIC_STORE(&self->Padding, written, almemory_order_relaxed); - - len = buffer_len - written; - if(len < update_size) - { - DWORD res; - 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(self->render, len, &buffer); - if(SUCCEEDED(hr)) - { - ALCwasapiPlayback_lock(self); - aluMixData(device, buffer, len); - ATOMIC_STORE(&self->Padding, written + len, almemory_order_relaxed); - ALCwasapiPlayback_unlock(self); - hr = IAudioRenderClient_ReleaseBuffer(self->render, len, 0); - } - if(FAILED(hr)) - { - ERR("Failed to buffer data: 0x%08lx\n", hr); - V0(device->Backend,lock)(); - aluHandleDisconnect(device, "Failed to send playback samples: 0x%08lx", hr); - V0(device->Backend,unlock)(); - break; - } - } - ATOMIC_STORE(&self->Padding, 0, almemory_order_release); - - CoUninitialize(); - return 0; -} - - -static ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) -{ - memset(out, 0, sizeof(*out)); - if(in->wFormatTag == WAVE_FORMAT_EXTENSIBLE) - *out = *(const WAVEFORMATEXTENSIBLE*)in; - else if(in->wFormatTag == WAVE_FORMAT_PCM) - { - out->Format = *in; - out->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - out->Format.cbSize = sizeof(*out) - sizeof(*in); - if(out->Format.nChannels == 1) - out->dwChannelMask = MONO; - else if(out->Format.nChannels == 2) - out->dwChannelMask = STEREO; - else - ERR("Unhandled PCM channel count: %d\n", out->Format.nChannels); - out->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - } - else if(in->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) - { - out->Format = *in; - out->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - out->Format.cbSize = sizeof(*out) - sizeof(*in); - if(out->Format.nChannels == 1) - out->dwChannelMask = MONO; - else if(out->Format.nChannels == 2) - out->dwChannelMask = STEREO; - else - ERR("Unhandled IEEE float channel count: %d\n", out->Format.nChannels); - out->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - } - else - { - ERR("Unhandled format tag: 0x%04x\n", in->wFormatTag); - return ALC_FALSE; - } - return ALC_TRUE; -} - -static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *deviceName) -{ - HRESULT hr = S_OK; - - self->NotifyEvent = CreateEventW(NULL, FALSE, FALSE, NULL); - self->MsgEvent = CreateEventW(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; - - 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; -#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, deviceName) == 0 || \ - alstr_cmp_cstr((i)->endpoint_guid, deviceName) == 0) - VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); -#undef MATCH_NAME - if(iter == VECTOR_END(PlaybackDevices)) - { - int len; - if((len=MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, NULL, 0)) > 0) - { - WCHAR *wname = calloc(sizeof(WCHAR), len); - MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, wname, len); -#define MATCH_NAME(i) (wcscmp((i)->devid, wname) == 0) - VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); -#undef MATCH_NAME - free(wname); - } - } - if(iter == VECTOR_END(PlaybackDevices)) - WARN("Failed to find device name matching \"%s\"\n", deviceName); - else - { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - self->devid = strdupW(iter->devid); - alstr_copy(&device->DeviceName, iter->name); - hr = S_OK; - } - } - } - - if(SUCCEEDED(hr)) - { - ThreadRequest req = { self->MsgEvent, 0 }; - - hr = E_FAIL; - if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, 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 ALCwasapiPlayback_openProxy(ALCwasapiPlayback *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; - if(alstr_empty(device->DeviceName)) - get_device_name_and_guid(self->mmdev, &device->DeviceName, NULL); - } - - if(FAILED(hr)) - { - if(self->mmdev) - IMMDevice_Release(self->mmdev); - self->mmdev = NULL; - } - - return hr; -} - - -static void ALCwasapiPlayback_closeProxy(ALCwasapiPlayback *self) -{ - if(self->client) - IAudioClient_Release(self->client); - self->client = NULL; - - if(self->mmdev) - IMMDevice_Release(self->mmdev); - self->mmdev = NULL; -} - - -static ALCboolean ALCwasapiPlayback_reset(ALCwasapiPlayback *self) -{ - ThreadRequest req = { self->MsgEvent, 0 }; - HRESULT hr = E_FAIL; - - if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) - hr = WaitForResponse(&req); - - return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; -} - -static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - EndpointFormFactor formfactor = UnknownFormFactor; - WAVEFORMATEXTENSIBLE OutputType; - WAVEFORMATEX *wfx = NULL; - REFERENCE_TIME min_per, buf_time; - UINT32 buffer_len, min_len; - void *ptr = NULL; - HRESULT hr; - - 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); - return hr; - } - - if(!MakeExtensible(&OutputType, wfx)) - { - CoTaskMemFree(wfx); - return E_FAIL; - } - CoTaskMemFree(wfx); - wfx = NULL; - - buf_time = ScaleCeil(device->UpdateSize*device->NumUpdates, REFTIME_PER_SEC, - device->Frequency); - - if(!(device->Flags&DEVICE_FREQUENCY_REQUEST)) - device->Frequency = OutputType.Format.nSamplesPerSec; - if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) - { - if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) - device->FmtChans = DevFmtMono; - else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO) - device->FmtChans = DevFmtStereo; - else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD) - device->FmtChans = DevFmtQuad; - else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1) - device->FmtChans = DevFmtX51; - else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR) - device->FmtChans = DevFmtX51Rear; - else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1) - device->FmtChans = DevFmtX61; - else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE)) - device->FmtChans = DevFmtX71; - else - ERR("Unhandled channel config: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask); - } - - switch(device->FmtChans) - { - case DevFmtMono: - OutputType.Format.nChannels = 1; - OutputType.dwChannelMask = MONO; - break; - case DevFmtAmbi3D: - device->FmtChans = DevFmtStereo; - /*fall-through*/ - case DevFmtStereo: - OutputType.Format.nChannels = 2; - OutputType.dwChannelMask = STEREO; - break; - case DevFmtQuad: - OutputType.Format.nChannels = 4; - OutputType.dwChannelMask = QUAD; - break; - case DevFmtX51: - OutputType.Format.nChannels = 6; - OutputType.dwChannelMask = X5DOT1; - break; - case DevFmtX51Rear: - OutputType.Format.nChannels = 6; - OutputType.dwChannelMask = X5DOT1REAR; - break; - case DevFmtX61: - OutputType.Format.nChannels = 7; - OutputType.dwChannelMask = X6DOT1; - break; - case DevFmtX71: - OutputType.Format.nChannels = 8; - OutputType.dwChannelMask = X7DOT1; - break; - } - switch(device->FmtType) - { - case DevFmtByte: - device->FmtType = DevFmtUByte; - /* fall-through */ - case DevFmtUByte: - OutputType.Format.wBitsPerSample = 8; - OutputType.Samples.wValidBitsPerSample = 8; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - break; - case DevFmtUShort: - device->FmtType = DevFmtShort; - /* fall-through */ - case DevFmtShort: - OutputType.Format.wBitsPerSample = 16; - OutputType.Samples.wValidBitsPerSample = 16; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - break; - case DevFmtUInt: - device->FmtType = DevFmtInt; - /* fall-through */ - case DevFmtInt: - OutputType.Format.wBitsPerSample = 32; - OutputType.Samples.wValidBitsPerSample = 32; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - break; - case DevFmtFloat: - OutputType.Format.wBitsPerSample = 32; - OutputType.Samples.wValidBitsPerSample = 32; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - break; - } - OutputType.Format.nSamplesPerSec = device->Frequency; - - OutputType.Format.nBlockAlign = OutputType.Format.nChannels * - OutputType.Format.wBitsPerSample / 8; - OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * - OutputType.Format.nBlockAlign; - - 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(self->client, &wfx); - } - if(FAILED(hr)) - { - ERR("Failed to find a supported format: 0x%08lx\n", hr); - return hr; - } - - if(wfx != NULL) - { - if(!MakeExtensible(&OutputType, wfx)) - { - CoTaskMemFree(wfx); - return E_FAIL; - } - CoTaskMemFree(wfx); - wfx = NULL; - - device->Frequency = OutputType.Format.nSamplesPerSec; - if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) - device->FmtChans = DevFmtMono; - else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO) - device->FmtChans = DevFmtStereo; - else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD) - device->FmtChans = DevFmtQuad; - else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1) - device->FmtChans = DevFmtX51; - else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR) - device->FmtChans = DevFmtX51Rear; - else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1) - device->FmtChans = DevFmtX61; - else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE)) - device->FmtChans = DevFmtX71; - else - { - ERR("Unhandled extensible channels: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask); - device->FmtChans = DevFmtStereo; - OutputType.Format.nChannels = 2; - OutputType.dwChannelMask = STEREO; - } - - if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) - { - if(OutputType.Format.wBitsPerSample == 8) - device->FmtType = DevFmtUByte; - else if(OutputType.Format.wBitsPerSample == 16) - device->FmtType = DevFmtShort; - else if(OutputType.Format.wBitsPerSample == 32) - device->FmtType = DevFmtInt; - else - { - device->FmtType = DevFmtShort; - OutputType.Format.wBitsPerSample = 16; - } - } - else if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) - { - device->FmtType = DevFmtFloat; - OutputType.Format.wBitsPerSample = 32; - } - else - { - ERR("Unhandled format sub-type\n"); - device->FmtType = DevFmtShort; - OutputType.Format.wBitsPerSample = 16; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - } - OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; - } - get_device_formfactor(self->mmdev, &formfactor); - device->IsHeadphones = (device->FmtChans == DevFmtStereo && - (formfactor == Headphones || formfactor == Headset) - ); - - SetDefaultWFXChannelOrder(device); - - hr = IAudioClient_Initialize(self->client, AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_EVENTCALLBACK, - buf_time, 0, &OutputType.Format, NULL); - if(FAILED(hr)) - { - ERR("Failed to initialize audio client: 0x%08lx\n", hr); - return hr; - } - - hr = IAudioClient_GetDevicePeriod(self->client, &min_per, NULL); - if(SUCCEEDED(hr)) - { - min_len = (UINT32)ScaleCeil(min_per, device->Frequency, REFTIME_PER_SEC); - /* 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(self->client, &buffer_len); - } - if(FAILED(hr)) - { - ERR("Failed to get audio buffer info: 0x%08lx\n", hr); - return hr; - } - - device->UpdateSize = min_len; - device->NumUpdates = buffer_len / device->UpdateSize; - if(device->NumUpdates <= 1) - { - ERR("Audio client returned buffer_len < period*2; expect break up\n"); - device->NumUpdates = 2; - 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 ALCboolean ALCwasapiPlayback_start(ALCwasapiPlayback *self) -{ - ThreadRequest req = { self->MsgEvent, 0 }; - HRESULT hr = E_FAIL; - - if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) - hr = WaitForResponse(&req); - - return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; -} - -static HRESULT ALCwasapiPlayback_startProxy(ALCwasapiPlayback *self) -{ - HRESULT hr; - void *ptr; - - ResetEvent(self->NotifyEvent); - hr = IAudioClient_Start(self->client); - if(FAILED(hr)) - ERR("Failed to start audio client: 0x%08lx\n", hr); - - if(SUCCEEDED(hr)) - hr = IAudioClient_GetService(self->client, &IID_IAudioRenderClient, &ptr); - if(SUCCEEDED(hr)) - { - self->render = ptr; - ATOMIC_STORE(&self->killNow, 0, almemory_order_release); - if(althrd_create(&self->thread, ALCwasapiPlayback_mixerProc, self) != althrd_success) - { - if(self->render) - IAudioRenderClient_Release(self->render); - self->render = NULL; - IAudioClient_Stop(self->client); - ERR("Failed to start thread\n"); - hr = E_FAIL; - } - } - - return hr; -} - - -static void ALCwasapiPlayback_stop(ALCwasapiPlayback *self) -{ - ThreadRequest req = { self->MsgEvent, 0 }; - if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) - (void)WaitForResponse(&req); -} - -static void ALCwasapiPlayback_stopProxy(ALCwasapiPlayback *self) -{ - int res; - - if(!self->render) - return; - - ATOMIC_STORE_SEQ(&self->killNow, 1); - althrd_join(self->thread, &res); - - IAudioRenderClient_Release(self->render); - self->render = NULL; - IAudioClient_Stop(self->client); -} - - -static ClockLatency ALCwasapiPlayback_getClockLatency(ALCwasapiPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ClockLatency ret; - - ALCwasapiPlayback_lock(self); - ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = ATOMIC_LOAD(&self->Padding, almemory_order_relaxed) * DEVICE_CLOCK_RES / - device->Frequency; - ALCwasapiPlayback_unlock(self); - - return ret; -} - - -typedef struct ALCwasapiCapture { - DERIVE_FROM_TYPE(ALCbackend); - DERIVE_FROM_TYPE(ALCwasapiProxy); - - WCHAR *devid; - - IMMDevice *mmdev; - IAudioClient *client; - IAudioCaptureClient *capture; - HANDLE NotifyEvent; - - HANDLE MsgEvent; - - ChannelConverter *ChannelConv; - SampleConverter *SampleConv; - ll_ringbuffer_t *Ring; - - ATOMIC(int) killNow; - althrd_t thread; -} ALCwasapiCapture; - -static int ALCwasapiCapture_recordProc(void *arg); - -static void ALCwasapiCapture_Construct(ALCwasapiCapture *self, ALCdevice *device); -static void ALCwasapiCapture_Destruct(ALCwasapiCapture *self); -static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *name); -static HRESULT ALCwasapiCapture_openProxy(ALCwasapiCapture *self); -static void ALCwasapiCapture_closeProxy(ALCwasapiCapture *self); -static DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, ALCboolean, reset) -static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self); -static ALCboolean ALCwasapiCapture_start(ALCwasapiCapture *self); -static HRESULT ALCwasapiCapture_startProxy(ALCwasapiCapture *self); -static void ALCwasapiCapture_stop(ALCwasapiCapture *self); -static void ALCwasapiCapture_stopProxy(ALCwasapiCapture *self); -static ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, ALCuint samples); -static ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self); -static DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCwasapiCapture) - -DEFINE_ALCWASAPIPROXY_VTABLE(ALCwasapiCapture); -DEFINE_ALCBACKEND_VTABLE(ALCwasapiCapture); - - -static void ALCwasapiCapture_Construct(ALCwasapiCapture *self, ALCdevice *device) -{ - SET_VTABLE2(ALCwasapiCapture, ALCbackend, self); - SET_VTABLE2(ALCwasapiCapture, ALCwasapiProxy, self); - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - ALCwasapiProxy_Construct(STATIC_CAST(ALCwasapiProxy, self)); - - self->devid = NULL; - - self->mmdev = NULL; - self->client = NULL; - self->capture = NULL; - self->NotifyEvent = NULL; - - self->MsgEvent = NULL; - - self->ChannelConv = NULL; - self->SampleConv = NULL; - self->Ring = NULL; - - ATOMIC_INIT(&self->killNow, 0); -} - -static void ALCwasapiCapture_Destruct(ALCwasapiCapture *self) -{ - if(self->MsgEvent) - { - ThreadRequest req = { self->MsgEvent, 0 }; - if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) - (void)WaitForResponse(&req); - - CloseHandle(self->MsgEvent); - self->MsgEvent = NULL; - } - - if(self->NotifyEvent != NULL) - CloseHandle(self->NotifyEvent); - self->NotifyEvent = NULL; - - ll_ringbuffer_free(self->Ring); - self->Ring = NULL; - - DestroySampleConverter(&self->SampleConv); - DestroyChannelConverter(&self->ChannelConv); - - free(self->devid); - self->devid = NULL; - - ALCwasapiProxy_Destruct(STATIC_CAST(ALCwasapiProxy, self)); - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -FORCE_ALIGN int ALCwasapiCapture_recordProc(void *arg) -{ - ALCwasapiCapture *self = arg; - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ALfloat *samples = NULL; - size_t samplesmax = 0; - HRESULT hr; - - hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); - if(FAILED(hr)) - { - ERR("CoInitializeEx(NULL, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); - V0(device->Backend,lock)(); - aluHandleDisconnect(device, "COM init failed: 0x%08lx", hr); - V0(device->Backend,unlock)(); - return 1; - } - - althrd_setname(althrd_current(), RECORD_THREAD_NAME); - - while(!ATOMIC_LOAD(&self->killNow, almemory_order_relaxed)) - { - UINT32 avail; - DWORD res; - - hr = IAudioCaptureClient_GetNextPacketSize(self->capture, &avail); - if(FAILED(hr)) - ERR("Failed to get next packet size: 0x%08lx\n", hr); - else if(avail > 0) - { - UINT32 numsamples; - DWORD flags; - BYTE *rdata; - - hr = IAudioCaptureClient_GetBuffer(self->capture, - &rdata, &numsamples, &flags, NULL, NULL - ); - if(FAILED(hr)) - ERR("Failed to get capture buffer: 0x%08lx\n", hr); - else - { - ll_ringbuffer_data_t data[2]; - size_t dstframes = 0; - - if(self->ChannelConv) - { - if(samplesmax < numsamples) - { - size_t newmax = RoundUp(numsamples, 4096); - ALfloat *tmp = al_calloc(DEF_ALIGN, newmax*2*sizeof(ALfloat)); - al_free(samples); - samples = tmp; - samplesmax = newmax; - } - ChannelConverterInput(self->ChannelConv, rdata, samples, numsamples); - rdata = (BYTE*)samples; - } - - ll_ringbuffer_get_write_vector(self->Ring, data); - - if(self->SampleConv) - { - const ALvoid *srcdata = rdata; - ALsizei srcframes = numsamples; - - dstframes = SampleConverterInput(self->SampleConv, - &srcdata, &srcframes, data[0].buf, (ALsizei)minz(data[0].len, INT_MAX) - ); - if(srcframes > 0 && dstframes == data[0].len && data[1].len > 0) - { - /* If some source samples remain, all of the first dest - * block was filled, and there's space in the second - * dest block, do another run for the second block. - */ - dstframes += SampleConverterInput(self->SampleConv, - &srcdata, &srcframes, data[1].buf, (ALsizei)minz(data[1].len, INT_MAX) - ); - } - } - else - { - ALuint framesize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, - device->AmbiOrder); - size_t len1 = minz(data[0].len, numsamples); - size_t len2 = minz(data[1].len, numsamples-len1); - - memcpy(data[0].buf, rdata, len1*framesize); - if(len2 > 0) - memcpy(data[1].buf, rdata+len1*framesize, len2*framesize); - dstframes = len1 + len2; - } - - ll_ringbuffer_write_advance(self->Ring, dstframes); - - hr = IAudioCaptureClient_ReleaseBuffer(self->capture, numsamples); - if(FAILED(hr)) ERR("Failed to release capture buffer: 0x%08lx\n", hr); - } - } - - if(FAILED(hr)) - { - V0(device->Backend,lock)(); - aluHandleDisconnect(device, "Failed to capture samples: 0x%08lx", hr); - V0(device->Backend,unlock)(); - break; - } - - res = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE); - if(res != WAIT_OBJECT_0) - ERR("WaitForSingleObjectEx error: 0x%lx\n", res); - } - - al_free(samples); - samples = NULL; - samplesmax = 0; - - CoUninitialize(); - return 0; -} - - -static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *deviceName) -{ - HRESULT hr = S_OK; - - self->NotifyEvent = CreateEventW(NULL, FALSE, FALSE, NULL); - self->MsgEvent = CreateEventW(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; - - if(VECTOR_SIZE(CaptureDevices) == 0) - { - ThreadRequest req = { self->MsgEvent, 0 }; - if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, CAPTURE_DEVICE_PROBE)) - (void)WaitForResponse(&req); - } - - hr = E_FAIL; -#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, deviceName) == 0 || \ - alstr_cmp_cstr((i)->endpoint_guid, deviceName) == 0) - VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); -#undef MATCH_NAME - if(iter == VECTOR_END(CaptureDevices)) - { - int len; - if((len=MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, NULL, 0)) > 0) - { - WCHAR *wname = calloc(sizeof(WCHAR), len); - MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, wname, len); -#define MATCH_NAME(i) (wcscmp((i)->devid, wname) == 0) - VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); -#undef MATCH_NAME - free(wname); - } - } - if(iter == VECTOR_END(CaptureDevices)) - WARN("Failed to find device name matching \"%s\"\n", deviceName); - else - { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - self->devid = strdupW(iter->devid); - alstr_copy(&device->DeviceName, iter->name); - hr = S_OK; - } - } - } - - if(SUCCEEDED(hr)) - { - ThreadRequest req = { self->MsgEvent, 0 }; - - hr = E_FAIL; - if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, 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; - } - else - { - ThreadRequest req = { self->MsgEvent, 0 }; - - hr = E_FAIL; - if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) - hr = WaitForResponse(&req); - else - ERR("Failed to post thread message: %lu\n", GetLastError()); - - if(FAILED(hr)) - { - if(hr == E_OUTOFMEMORY) - return ALC_OUT_OF_MEMORY; - return ALC_INVALID_VALUE; - } - } - - return ALC_NO_ERROR; -} - -static HRESULT ALCwasapiCapture_openProxy(ALCwasapiCapture *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, eCapture, 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; - if(alstr_empty(device->DeviceName)) - get_device_name_and_guid(self->mmdev, &device->DeviceName, NULL); - } - - if(FAILED(hr)) - { - if(self->mmdev) - IMMDevice_Release(self->mmdev); - self->mmdev = NULL; - } - - return hr; -} - - -static void ALCwasapiCapture_closeProxy(ALCwasapiCapture *self) -{ - if(self->client) - IAudioClient_Release(self->client); - self->client = NULL; - - if(self->mmdev) - IMMDevice_Release(self->mmdev); - self->mmdev = NULL; -} - - -static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - WAVEFORMATEXTENSIBLE OutputType; - WAVEFORMATEX *wfx = NULL; - enum DevFmtType srcType; - REFERENCE_TIME buf_time; - UINT32 buffer_len; - void *ptr = NULL; - HRESULT hr; - - 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; - - buf_time = ScaleCeil(device->UpdateSize*device->NumUpdates, REFTIME_PER_SEC, - device->Frequency); - // Make sure buffer is at least 100ms in size - buf_time = maxu64(buf_time, REFTIME_PER_SEC/10); - device->UpdateSize = (ALuint)ScaleCeil(buf_time, device->Frequency, REFTIME_PER_SEC) / - device->NumUpdates; - - OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - switch(device->FmtChans) - { - case DevFmtMono: - OutputType.Format.nChannels = 1; - OutputType.dwChannelMask = MONO; - break; - case DevFmtStereo: - OutputType.Format.nChannels = 2; - OutputType.dwChannelMask = STEREO; - break; - case DevFmtQuad: - OutputType.Format.nChannels = 4; - OutputType.dwChannelMask = QUAD; - break; - case DevFmtX51: - OutputType.Format.nChannels = 6; - OutputType.dwChannelMask = X5DOT1; - break; - case DevFmtX51Rear: - OutputType.Format.nChannels = 6; - OutputType.dwChannelMask = X5DOT1REAR; - break; - case DevFmtX61: - OutputType.Format.nChannels = 7; - OutputType.dwChannelMask = X6DOT1; - break; - case DevFmtX71: - OutputType.Format.nChannels = 8; - OutputType.dwChannelMask = X7DOT1; - break; - - case DevFmtAmbi3D: - return E_FAIL; - } - switch(device->FmtType) - { - /* NOTE: Signedness doesn't matter, the converter will handle it. */ - case DevFmtByte: - case DevFmtUByte: - OutputType.Format.wBitsPerSample = 8; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - break; - case DevFmtShort: - case DevFmtUShort: - OutputType.Format.wBitsPerSample = 16; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - break; - case DevFmtInt: - case DevFmtUInt: - OutputType.Format.wBitsPerSample = 32; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - break; - case DevFmtFloat: - OutputType.Format.wBitsPerSample = 32; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - break; - } - OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; - OutputType.Format.nSamplesPerSec = device->Frequency; - - OutputType.Format.nBlockAlign = OutputType.Format.nChannels * - OutputType.Format.wBitsPerSample / 8; - OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * - OutputType.Format.nBlockAlign; - OutputType.Format.cbSize = sizeof(OutputType) - sizeof(OutputType.Format); - - hr = IAudioClient_IsFormatSupported(self->client, - AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx - ); - if(FAILED(hr)) - { - ERR("Failed to check format support: 0x%08lx\n", hr); - return hr; - } - - DestroySampleConverter(&self->SampleConv); - DestroyChannelConverter(&self->ChannelConv); - - if(wfx != NULL) - { - if(!(wfx->nChannels == OutputType.Format.nChannels || - (wfx->nChannels == 1 && OutputType.Format.nChannels == 2) || - (wfx->nChannels == 2 && OutputType.Format.nChannels == 1))) - { - ERR("Failed to get matching format, wanted: %s %s %uhz, got: %d channel%s %d-bit %luhz\n", - DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), - device->Frequency, wfx->nChannels, (wfx->nChannels==1)?"":"s", wfx->wBitsPerSample, - wfx->nSamplesPerSec); - CoTaskMemFree(wfx); - return E_FAIL; - } - - if(!MakeExtensible(&OutputType, wfx)) - { - CoTaskMemFree(wfx); - return E_FAIL; - } - CoTaskMemFree(wfx); - wfx = NULL; - } - - if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) - { - if(OutputType.Format.wBitsPerSample == 8) - srcType = DevFmtUByte; - else if(OutputType.Format.wBitsPerSample == 16) - srcType = DevFmtShort; - else if(OutputType.Format.wBitsPerSample == 32) - srcType = DevFmtInt; - else - { - ERR("Unhandled integer bit depth: %d\n", OutputType.Format.wBitsPerSample); - return E_FAIL; - } - } - else if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) - { - if(OutputType.Format.wBitsPerSample == 32) - srcType = DevFmtFloat; - else - { - ERR("Unhandled float bit depth: %d\n", OutputType.Format.wBitsPerSample); - return E_FAIL; - } - } - else - { - ERR("Unhandled format sub-type\n"); - return E_FAIL; - } - - if(device->FmtChans == DevFmtMono && OutputType.Format.nChannels == 2) - { - self->ChannelConv = CreateChannelConverter(srcType, DevFmtStereo, - device->FmtChans); - if(!self->ChannelConv) - { - ERR("Failed to create %s stereo-to-mono converter\n", DevFmtTypeString(srcType)); - return E_FAIL; - } - TRACE("Created %s stereo-to-mono converter\n", DevFmtTypeString(srcType)); - /* The channel converter always outputs float, so change the input type - * for the resampler/type-converter. - */ - srcType = DevFmtFloat; - } - else if(device->FmtChans == DevFmtStereo && OutputType.Format.nChannels == 1) - { - self->ChannelConv = CreateChannelConverter(srcType, DevFmtMono, - device->FmtChans); - if(!self->ChannelConv) - { - ERR("Failed to create %s mono-to-stereo converter\n", DevFmtTypeString(srcType)); - return E_FAIL; - } - TRACE("Created %s mono-to-stereo converter\n", DevFmtTypeString(srcType)); - srcType = DevFmtFloat; - } - - if(device->Frequency != OutputType.Format.nSamplesPerSec || device->FmtType != srcType) - { - self->SampleConv = CreateSampleConverter( - srcType, device->FmtType, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder), - OutputType.Format.nSamplesPerSec, device->Frequency - ); - if(!self->SampleConv) - { - ERR("Failed to create converter for %s format, dst: %s %uhz, src: %s %luhz\n", - DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), - device->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec); - return E_FAIL; - } - TRACE("Created converter for %s format, dst: %s %uhz, src: %s %luhz\n", - DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), - device->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec); - } - - hr = IAudioClient_Initialize(self->client, - AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, - buf_time, 0, &OutputType.Format, NULL - ); - if(FAILED(hr)) - { - ERR("Failed to initialize audio client: 0x%08lx\n", hr); - return hr; - } - - hr = IAudioClient_GetBufferSize(self->client, &buffer_len); - if(FAILED(hr)) - { - ERR("Failed to get buffer size: 0x%08lx\n", hr); - return hr; - } - - buffer_len = maxu(device->UpdateSize*device->NumUpdates, buffer_len); - ll_ringbuffer_free(self->Ring); - self->Ring = ll_ringbuffer_create(buffer_len, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), - false - ); - if(!self->Ring) - { - ERR("Failed to allocate capture ring buffer\n"); - return E_OUTOFMEMORY; - } - - 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 ALCboolean ALCwasapiCapture_start(ALCwasapiCapture *self) -{ - ThreadRequest req = { self->MsgEvent, 0 }; - HRESULT hr = E_FAIL; - - if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) - hr = WaitForResponse(&req); - - return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; -} - -static HRESULT ALCwasapiCapture_startProxy(ALCwasapiCapture *self) -{ - HRESULT hr; - void *ptr; - - ResetEvent(self->NotifyEvent); - hr = IAudioClient_Start(self->client); - if(FAILED(hr)) - { - ERR("Failed to start audio client: 0x%08lx\n", hr); - return hr; - } - - hr = IAudioClient_GetService(self->client, &IID_IAudioCaptureClient, &ptr); - if(SUCCEEDED(hr)) - { - self->capture = ptr; - ATOMIC_STORE(&self->killNow, 0, almemory_order_release); - if(althrd_create(&self->thread, ALCwasapiCapture_recordProc, self) != althrd_success) - { - ERR("Failed to start thread\n"); - IAudioCaptureClient_Release(self->capture); - self->capture = NULL; - hr = E_FAIL; - } - } - - if(FAILED(hr)) - { - IAudioClient_Stop(self->client); - IAudioClient_Reset(self->client); - } - - return hr; -} - - -static void ALCwasapiCapture_stop(ALCwasapiCapture *self) -{ - ThreadRequest req = { self->MsgEvent, 0 }; - if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) - (void)WaitForResponse(&req); -} - -static void ALCwasapiCapture_stopProxy(ALCwasapiCapture *self) -{ - int res; - - if(!self->capture) - return; - - ATOMIC_STORE_SEQ(&self->killNow, 1); - althrd_join(self->thread, &res); - - IAudioCaptureClient_Release(self->capture); - self->capture = NULL; - IAudioClient_Stop(self->client); - IAudioClient_Reset(self->client); -} - - -ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self) -{ - return (ALuint)ll_ringbuffer_read_space(self->Ring); -} - -ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, ALCuint samples) -{ - if(ALCwasapiCapture_availableSamples(self) < samples) - return ALC_INVALID_VALUE; - ll_ringbuffer_read(self->Ring, buffer, samples); - return ALC_NO_ERROR; -} - - -typedef struct ALCwasapiBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCwasapiBackendFactory; -#define ALCWASAPIBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwasapiBackendFactory, ALCbackendFactory) } } - -static ALCboolean ALCwasapiBackendFactory_init(ALCwasapiBackendFactory *self); -static void ALCwasapiBackendFactory_deinit(ALCwasapiBackendFactory *self); -static ALCboolean ALCwasapiBackendFactory_querySupport(ALCwasapiBackendFactory *self, ALCbackend_Type type); -static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory *self, enum DevProbe type, al_string *outnames); -static ALCbackend* ALCwasapiBackendFactory_createBackend(ALCwasapiBackendFactory *self, ALCdevice *device, ALCbackend_Type type); - -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwasapiBackendFactory); - - -static ALCboolean ALCwasapiBackendFactory_init(ALCwasapiBackendFactory* UNUSED(self)) -{ - static HRESULT InitResult; - - VECTOR_INIT(PlaybackDevices); - VECTOR_INIT(CaptureDevices); - - if(!ThreadHdl) - { - ThreadRequest req; - InitResult = E_FAIL; - - req.FinishedEvt = CreateEventW(NULL, FALSE, FALSE, NULL); - if(req.FinishedEvt == NULL) - ERR("Failed to create event: %lu\n", GetLastError()); - else - { - ThreadHdl = CreateThread(NULL, 0, ALCwasapiProxy_messageHandler, &req, 0, &ThreadID); - if(ThreadHdl != NULL) - InitResult = WaitForResponse(&req); - CloseHandle(req.FinishedEvt); - } - } - - return SUCCEEDED(InitResult) ? ALC_TRUE : ALC_FALSE; -} - -static void ALCwasapiBackendFactory_deinit(ALCwasapiBackendFactory* UNUSED(self)) -{ - clear_devlist(&PlaybackDevices); - VECTOR_DEINIT(PlaybackDevices); - - clear_devlist(&CaptureDevices); - VECTOR_DEINIT(CaptureDevices); - - if(ThreadHdl) - { - TRACE("Sending WM_QUIT to Thread %04lx\n", ThreadID); - PostThreadMessage(ThreadID, WM_QUIT, 0, 0); - CloseHandle(ThreadHdl); - ThreadHdl = NULL; - } -} - -static ALCboolean ALCwasapiBackendFactory_querySupport(ALCwasapiBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} - -static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) -{ - ThreadRequest req = { NULL, 0 }; - - req.FinishedEvt = CreateEventW(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) - { -#define APPEND_OUTNAME(e) do { \ - if(!alstr_empty((e)->name)) \ - alstr_append_range(outnames, VECTOR_BEGIN((e)->name), \ - VECTOR_END((e)->name)+1); \ -} while(0) - case ALL_DEVICE_PROBE: - VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_OUTNAME); - break; - - case CAPTURE_DEVICE_PROBE: - VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_OUTNAME); - break; -#undef APPEND_OUTNAME - } - CloseHandle(req.FinishedEvt); - req.FinishedEvt = NULL; - } -} - -static ALCbackend* ALCwasapiBackendFactory_createBackend(ALCwasapiBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - { - ALCwasapiPlayback *backend; - NEW_OBJ(backend, ALCwasapiPlayback)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - if(type == ALCbackend_Capture) - { - ALCwasapiCapture *backend; - NEW_OBJ(backend, ALCwasapiCapture)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} - - -ALCbackendFactory *ALCwasapiBackendFactory_getFactory(void) -{ - static ALCwasapiBackendFactory factory = ALCWASAPIBACKENDFACTORY_INITIALIZER; - return STATIC_CAST(ALCbackendFactory, &factory); -} diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp new file mode 100644 index 00000000..099f9886 --- /dev/null +++ b/Alc/backends/wasapi.cpp @@ -0,0 +1,2035 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2011 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef _WAVEFORMATEXTENSIBLE_ +#include +#include +#endif + +#include + +#include "alMain.h" +#include "alu.h" +#include "ringbuffer.h" +#include "threads.h" +#include "compat.h" +#include "alstring.h" +#include "converter.h" + +#include "backends/base.h" + + +DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23,0xe0, 0xc0,0xff,0xee,0x7f,0x0e, 4 ); + +#define MONO SPEAKER_FRONT_CENTER +#define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT) +#define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT) +#define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) +#define X5DOT1REAR (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT) +#define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) +#define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) +#define X7DOT1_WIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_FRONT_LEFT_OF_CENTER|SPEAKER_FRONT_RIGHT_OF_CENTER) + +#define REFTIME_PER_SEC ((REFERENCE_TIME)10000000) + +#define DEVNAME_HEAD "OpenAL Soft on " + + +/* Scales the given value using 64-bit integer math, ceiling the result. */ +static inline ALuint64 ScaleCeil(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale) +{ + return (val*new_scale + old_scale-1) / old_scale; +} + + +typedef struct { + al_string name; + al_string endpoint_guid; // obtained from PKEY_AudioEndpoint_GUID , set to "Unknown device GUID" if absent. + WCHAR *devid; +} DevMap; +TYPEDEF_VECTOR(DevMap, vector_DevMap) + +static void clear_devlist(vector_DevMap *list) +{ +#define CLEAR_DEVMAP(i) do { \ + AL_STRING_DEINIT((i)->name); \ + AL_STRING_DEINIT((i)->endpoint_guid); \ + free((i)->devid); \ + (i)->devid = nullptr; \ +} while(0) + VECTOR_FOR_EACH(DevMap, *list, CLEAR_DEVMAP); + VECTOR_RESIZE(*list, 0, 0); +#undef CLEAR_DEVMAP +} + +static vector_DevMap PlaybackDevices; +static vector_DevMap CaptureDevices; + + +static HANDLE ThreadHdl; +static DWORD ThreadID; + +typedef struct { + HANDLE FinishedEvt; + HRESULT result; +} ThreadRequest; + +#define WM_USER_First (WM_USER+0) +#define WM_USER_OpenDevice (WM_USER+0) +#define WM_USER_ResetDevice (WM_USER+1) +#define WM_USER_StartDevice (WM_USER+2) +#define WM_USER_StopDevice (WM_USER+3) +#define WM_USER_CloseDevice (WM_USER+4) +#define WM_USER_Enumerate (WM_USER+5) +#define WM_USER_Last (WM_USER+5) + +static const char MessageStr[WM_USER_Last+1-WM_USER][20] = { + "Open Device", + "Reset Device", + "Start Device", + "Stop Device", + "Close Device", + "Enumerate Devices", +}; + +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) + return req->result; + ERR("Message response error: %lu\n", GetLastError()); + return E_FAIL; +} + + +static void get_device_name_and_guid(IMMDevice *device, al_string *name, al_string *guid) +{ + IPropertyStore *ps; + PROPVARIANT pvname; + PROPVARIANT pvguid; + HRESULT hr; + + alstr_copy_cstr(name, DEVNAME_HEAD); + + hr = device->OpenPropertyStore(STGM_READ, &ps); + if(FAILED(hr)) + { + WARN("OpenPropertyStore failed: 0x%08lx\n", hr); + alstr_append_cstr(name, "Unknown Device Name"); + if(guid) alstr_copy_cstr(guid, "Unknown Device GUID"); + return; + } + + PropVariantInit(&pvname); + + hr = ps->GetValue(reinterpret_cast(DEVPKEY_Device_FriendlyName), &pvname); + if(FAILED(hr)) + { + WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr); + alstr_append_cstr(name, "Unknown Device Name"); + } + else if(pvname.vt == VT_LPWSTR) + alstr_append_wcstr(name, pvname.pwszVal); + else + { + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvname.vt); + alstr_append_cstr(name, "Unknown Device Name"); + } + PropVariantClear(&pvname); + + if(guid) + { + PropVariantInit(&pvguid); + + hr = ps->GetValue(reinterpret_cast(PKEY_AudioEndpoint_GUID), &pvguid); + if(FAILED(hr)) + { + WARN("GetValue AudioEndpoint_GUID failed: 0x%08lx\n", hr); + alstr_copy_cstr(guid, "Unknown Device GUID"); + } + else if(pvguid.vt == VT_LPWSTR) + alstr_copy_wcstr(guid, pvguid.pwszVal); + else + { + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvguid.vt); + alstr_copy_cstr(guid, "Unknown Device GUID"); + } + + PropVariantClear(&pvguid); + } + + ps->Release(); +} + +static void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfactor) +{ + IPropertyStore *ps; + PROPVARIANT pvform; + HRESULT hr; + + hr = device->OpenPropertyStore(STGM_READ, &ps); + if(FAILED(hr)) + { + WARN("OpenPropertyStore failed: 0x%08lx\n", hr); + return; + } + + PropVariantInit(&pvform); + + hr = ps->GetValue(reinterpret_cast(PKEY_AudioEndpoint_FormFactor), &pvform); + if(FAILED(hr)) + WARN("GetValue AudioEndpoint_FormFactor failed: 0x%08lx\n", hr); + else if(pvform.vt == VT_UI4) + *formfactor = static_cast(pvform.ulVal); + else if(pvform.vt == VT_EMPTY) + *formfactor = UnknownFormFactor; + else + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvform.vt); + + PropVariantClear(&pvform); + ps->Release(); +} + + +static void add_device(IMMDevice *device, const WCHAR *devid, vector_DevMap *list) +{ + int count = 0; + al_string tmpname; + DevMap entry; + + AL_STRING_INIT(tmpname); + AL_STRING_INIT(entry.name); + AL_STRING_INIT(entry.endpoint_guid); + + entry.devid = strdupW(devid); + get_device_name_and_guid(device, &tmpname, &entry.endpoint_guid); + + while(1) + { + const DevMap *iter; + + alstr_copy(&entry.name, tmpname); + if(count != 0) + { + char str[64]; + snprintf(str, sizeof(str), " #%d", count+1); + alstr_append_cstr(&entry.name, str); + } + +#define MATCH_ENTRY(i) (alstr_cmp(entry.name, (i)->name) == 0) + VECTOR_FIND_IF(iter, const DevMap, *list, MATCH_ENTRY); + if(iter == VECTOR_END(*list)) break; +#undef MATCH_ENTRY + count++; + } + + TRACE("Got device \"%s\", \"%s\", \"%ls\"\n", alstr_get_cstr(entry.name), alstr_get_cstr(entry.endpoint_guid), entry.devid); + VECTOR_PUSH_BACK(*list, entry); + + AL_STRING_DEINIT(tmpname); +} + +static WCHAR *get_device_id(IMMDevice *device) +{ + WCHAR *devid; + HRESULT hr; + + hr = device->GetId(&devid); + if(FAILED(hr)) + { + ERR("Failed to get device id: %lx\n", hr); + return nullptr; + } + + return devid; +} + +static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, vector_DevMap *list) +{ + IMMDeviceCollection *coll; + IMMDevice *defdev = nullptr; + WCHAR *defdevid = nullptr; + HRESULT hr; + UINT count; + UINT i; + + hr = devenum->EnumAudioEndpoints(flowdir, DEVICE_STATE_ACTIVE, &coll); + if(FAILED(hr)) + { + ERR("Failed to enumerate audio endpoints: 0x%08lx\n", hr); + return hr; + } + + count = 0; + hr = coll->GetCount(&count); + if(SUCCEEDED(hr) && count > 0) + { + clear_devlist(list); + VECTOR_RESIZE(*list, 0, count); + + hr = devenum->GetDefaultAudioEndpoint(flowdir, eMultimedia, &defdev); + } + if(SUCCEEDED(hr) && defdev != nullptr) + { + defdevid = get_device_id(defdev); + if(defdevid) + add_device(defdev, defdevid, list); + } + + for(i = 0;i < count;++i) + { + IMMDevice *device; + WCHAR *devid; + + hr = coll->Item(i, &device); + if(FAILED(hr)) continue; + + devid = get_device_id(device); + if(devid) + { + if(wcscmp(devid, defdevid) != 0) + add_device(device, devid, list); + CoTaskMemFree(devid); + } + device->Release(); + } + + if(defdev) defdev->Release(); + if(defdevid) CoTaskMemFree(defdevid); + coll->Release(); + + return S_OK; +} + + +/* Proxy interface used by the message handler. */ +struct ALCwasapiProxyVtable; + +typedef struct ALCwasapiProxy { + const struct ALCwasapiProxyVtable *vtbl; +} ALCwasapiProxy; + +struct ALCwasapiProxyVtable { + HRESULT (*const openProxy)(ALCwasapiProxy*); + void (*const closeProxy)(ALCwasapiProxy*); + + HRESULT (*const resetProxy)(ALCwasapiProxy*); + HRESULT (*const startProxy)(ALCwasapiProxy*); + void (*const stopProxy)(ALCwasapiProxy*); +}; + +#define DEFINE_ALCWASAPIPROXY_VTABLE(T) \ +DECLARE_THUNK(T, ALCwasapiProxy, HRESULT, openProxy) \ +DECLARE_THUNK(T, ALCwasapiProxy, void, closeProxy) \ +DECLARE_THUNK(T, ALCwasapiProxy, HRESULT, resetProxy) \ +DECLARE_THUNK(T, ALCwasapiProxy, HRESULT, startProxy) \ +DECLARE_THUNK(T, ALCwasapiProxy, void, stopProxy) \ + \ +static const struct ALCwasapiProxyVtable T##_ALCwasapiProxy_vtable = { \ + T##_ALCwasapiProxy_openProxy, \ + T##_ALCwasapiProxy_closeProxy, \ + T##_ALCwasapiProxy_resetProxy, \ + T##_ALCwasapiProxy_startProxy, \ + T##_ALCwasapiProxy_stopProxy, \ +} + +static void ALCwasapiProxy_Construct(ALCwasapiProxy* UNUSED(self)) { } +static void ALCwasapiProxy_Destruct(ALCwasapiProxy* UNUSED(self)) { } + +static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) +{ + auto req = reinterpret_cast(ptr); + ALuint deviceCount = 0; + ALCwasapiProxy *proxy; + HRESULT hr, cohr; + MSG msg; + + TRACE("Starting message thread\n"); + + cohr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + if(FAILED(cohr)) + { + WARN("Failed to initialize COM: 0x%08lx\n", cohr); + ReturnMsgResponse(req, cohr); + return 0; + } + + hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, 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; + } + auto Enumerator = reinterpret_cast(ptr); + Enumerator->Release(); + Enumerator = nullptr; + + 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, nullptr, WM_USER, WM_USER, PM_NOREMOVE); + + TRACE("Message thread initialization complete\n"); + ReturnMsgResponse(req, S_OK); + + TRACE("Starting message loop\n"); + while(GetMessage(&msg, nullptr, WM_USER_First, WM_USER_Last)) + { + TRACE("Got message \"%s\" (0x%04x, lparam=%p, wparam=%p)\n", + (msg.message >= WM_USER && msg.message <= WM_USER_Last) ? + MessageStr[msg.message-WM_USER] : "Unknown", + msg.message, (void*)msg.lParam, (void*)msg.wParam + ); + switch(msg.message) + { + case WM_USER_OpenDevice: + req = reinterpret_cast(msg.wParam); + proxy = reinterpret_cast(msg.lParam); + + hr = cohr = S_OK; + if(++deviceCount == 1) + hr = cohr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + 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 = reinterpret_cast(msg.wParam); + proxy = reinterpret_cast(msg.lParam); + + hr = V0(proxy,resetProxy)(); + ReturnMsgResponse(req, hr); + continue; + + case WM_USER_StartDevice: + req = reinterpret_cast(msg.wParam); + proxy = reinterpret_cast(msg.lParam); + + hr = V0(proxy,startProxy)(); + ReturnMsgResponse(req, hr); + continue; + + case WM_USER_StopDevice: + req = reinterpret_cast(msg.wParam); + proxy = reinterpret_cast(msg.lParam); + + V0(proxy,stopProxy)(); + ReturnMsgResponse(req, S_OK); + continue; + + case WM_USER_CloseDevice: + req = reinterpret_cast(msg.wParam); + proxy = reinterpret_cast(msg.lParam); + + V0(proxy,closeProxy)(); + if(--deviceCount == 0) + CoUninitialize(); + + ReturnMsgResponse(req, S_OK); + continue; + + case WM_USER_Enumerate: + req = reinterpret_cast(msg.wParam); + + hr = cohr = S_OK; + if(++deviceCount == 1) + hr = cohr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + if(SUCCEEDED(hr)) + hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, &ptr); + if(SUCCEEDED(hr)) + { + Enumerator = reinterpret_cast(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); + + Enumerator->Release(); + Enumerator = nullptr; + } + + 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 ALCwasapiPlayback { + DERIVE_FROM_TYPE(ALCbackend); + DERIVE_FROM_TYPE(ALCwasapiProxy); + + WCHAR *devid; + + IMMDevice *mmdev; + IAudioClient *client; + IAudioRenderClient *render; + HANDLE NotifyEvent; + + HANDLE MsgEvent; + + ATOMIC(UINT32) Padding; + + ATOMIC(int) killNow; + althrd_t thread; +} ALCwasapiPlayback; + +static int ALCwasapiPlayback_mixerProc(void *arg); + +static void ALCwasapiPlayback_Construct(ALCwasapiPlayback *self, ALCdevice *device); +static void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self); +static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *name); +static HRESULT ALCwasapiPlayback_openProxy(ALCwasapiPlayback *self); +static void ALCwasapiPlayback_closeProxy(ALCwasapiPlayback *self); +static ALCboolean ALCwasapiPlayback_reset(ALCwasapiPlayback *self); +static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self); +static ALCboolean ALCwasapiPlayback_start(ALCwasapiPlayback *self); +static HRESULT ALCwasapiPlayback_startProxy(ALCwasapiPlayback *self); +static void ALCwasapiPlayback_stop(ALCwasapiPlayback *self); +static void ALCwasapiPlayback_stopProxy(ALCwasapiPlayback *self); +static DECLARE_FORWARD2(ALCwasapiPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) +static DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, ALCuint, availableSamples) +static ClockLatency ALCwasapiPlayback_getClockLatency(ALCwasapiPlayback *self); +static DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCwasapiPlayback) + +DEFINE_ALCWASAPIPROXY_VTABLE(ALCwasapiPlayback); +DEFINE_ALCBACKEND_VTABLE(ALCwasapiPlayback); + + +static void ALCwasapiPlayback_Construct(ALCwasapiPlayback *self, ALCdevice *device) +{ + SET_VTABLE2(ALCwasapiPlayback, ALCbackend, self); + SET_VTABLE2(ALCwasapiPlayback, ALCwasapiProxy, self); + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + ALCwasapiProxy_Construct(STATIC_CAST(ALCwasapiProxy, self)); + + self->devid = nullptr; + + self->mmdev = nullptr; + self->client = nullptr; + self->render = nullptr; + self->NotifyEvent = nullptr; + + self->MsgEvent = nullptr; + + ATOMIC_INIT(&self->Padding, 0u); + + ATOMIC_INIT(&self->killNow, 0); +} + +static void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self) +{ + if(self->MsgEvent) + { + ThreadRequest req = { self->MsgEvent, 0 }; + if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + (void)WaitForResponse(&req); + + CloseHandle(self->MsgEvent); + self->MsgEvent = nullptr; + } + + if(self->NotifyEvent) + CloseHandle(self->NotifyEvent); + self->NotifyEvent = nullptr; + + free(self->devid); + self->devid = nullptr; + + if(self->NotifyEvent != nullptr) + CloseHandle(self->NotifyEvent); + self->NotifyEvent = nullptr; + if(self->MsgEvent != nullptr) + CloseHandle(self->MsgEvent); + self->MsgEvent = nullptr; + + free(self->devid); + self->devid = nullptr; + + ALCwasapiProxy_Destruct(STATIC_CAST(ALCwasapiProxy, self)); + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + + +FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(void *arg) +{ + auto self = reinterpret_cast(arg); + ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + IAudioClient *client = self->client; + IAudioRenderClient *render = self->render; + UINT32 buffer_len, written; + ALuint update_size, len; + BYTE *buffer; + HRESULT hr; + + hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + if(FAILED(hr)) + { + ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); + V0(device->Backend,lock)(); + aluHandleDisconnect(device, "COM init failed: 0x%08lx", hr); + V0(device->Backend,unlock)(); + return 1; + } + + SetRTPriority(); + althrd_setname(althrd_current(), MIXER_THREAD_NAME); + + update_size = device->UpdateSize; + buffer_len = update_size * device->NumUpdates; + while(!ATOMIC_LOAD(&self->killNow, almemory_order_relaxed)) + { + hr = client->GetCurrentPadding(&written); + if(FAILED(hr)) + { + ERR("Failed to get padding: 0x%08lx\n", hr); + V0(device->Backend,lock)(); + aluHandleDisconnect(device, "Failed to retrieve buffer padding: 0x%08lx", hr); + V0(device->Backend,unlock)(); + break; + } + ATOMIC_STORE(&self->Padding, written, almemory_order_relaxed); + + len = buffer_len - written; + if(len < update_size) + { + DWORD res; + res = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE); + if(res != WAIT_OBJECT_0) + ERR("WaitForSingleObjectEx error: 0x%lx\n", res); + continue; + } + len -= len%update_size; + + hr = render->GetBuffer(len, &buffer); + if(SUCCEEDED(hr)) + { + ALCwasapiPlayback_lock(self); + aluMixData(device, buffer, len); + ATOMIC_STORE(&self->Padding, written + len, almemory_order_relaxed); + ALCwasapiPlayback_unlock(self); + hr = render->ReleaseBuffer(len, 0); + } + if(FAILED(hr)) + { + ERR("Failed to buffer data: 0x%08lx\n", hr); + V0(device->Backend,lock)(); + aluHandleDisconnect(device, "Failed to send playback samples: 0x%08lx", hr); + V0(device->Backend,unlock)(); + break; + } + } + ATOMIC_STORE(&self->Padding, 0u, almemory_order_release); + + CoUninitialize(); + return 0; +} + + +static ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) +{ + memset(out, 0, sizeof(*out)); + if(in->wFormatTag == WAVE_FORMAT_EXTENSIBLE) + *out = *(const WAVEFORMATEXTENSIBLE*)in; + else if(in->wFormatTag == WAVE_FORMAT_PCM) + { + out->Format = *in; + out->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + out->Format.cbSize = sizeof(*out) - sizeof(*in); + if(out->Format.nChannels == 1) + out->dwChannelMask = MONO; + else if(out->Format.nChannels == 2) + out->dwChannelMask = STEREO; + else + ERR("Unhandled PCM channel count: %d\n", out->Format.nChannels); + out->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + } + else if(in->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) + { + out->Format = *in; + out->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + out->Format.cbSize = sizeof(*out) - sizeof(*in); + if(out->Format.nChannels == 1) + out->dwChannelMask = MONO; + else if(out->Format.nChannels == 2) + out->dwChannelMask = STEREO; + else + ERR("Unhandled IEEE float channel count: %d\n", out->Format.nChannels); + out->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + } + else + { + ERR("Unhandled format tag: 0x%04x\n", in->wFormatTag); + return ALC_FALSE; + } + return ALC_TRUE; +} + +static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *deviceName) +{ + HRESULT hr = S_OK; + + self->NotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + self->MsgEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + if(self->NotifyEvent == nullptr || self->MsgEvent == nullptr) + { + ERR("Failed to create message events: %lu\n", GetLastError()); + hr = E_FAIL; + } + + if(SUCCEEDED(hr)) + { + if(deviceName) + { + const DevMap *iter; + + 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; +#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, deviceName) == 0 || \ + alstr_cmp_cstr((i)->endpoint_guid, deviceName) == 0) + VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); +#undef MATCH_NAME + if(iter == VECTOR_END(PlaybackDevices)) + { + int len; + if((len=MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, nullptr, 0)) > 0) + { + std::vector wname(len); + MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, wname.data(), len); +#define MATCH_NAME(i) (wcscmp((i)->devid, wname.data()) == 0) + VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); +#undef MATCH_NAME + } + } + if(iter == VECTOR_END(PlaybackDevices)) + WARN("Failed to find device name matching \"%s\"\n", deviceName); + else + { + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + self->devid = strdupW(iter->devid); + alstr_copy(&device->DeviceName, iter->name); + hr = S_OK; + } + } + } + + if(SUCCEEDED(hr)) + { + ThreadRequest req = { self->MsgEvent, 0 }; + + hr = E_FAIL; + if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + hr = WaitForResponse(&req); + else + ERR("Failed to post thread message: %lu\n", GetLastError()); + } + + if(FAILED(hr)) + { + if(self->NotifyEvent != nullptr) + CloseHandle(self->NotifyEvent); + self->NotifyEvent = nullptr; + if(self->MsgEvent != nullptr) + CloseHandle(self->MsgEvent); + self->MsgEvent = nullptr; + + free(self->devid); + self->devid = nullptr; + + ERR("Device init failed: 0x%08lx\n", hr); + return ALC_INVALID_VALUE; + } + + return ALC_NO_ERROR; +} + +static HRESULT ALCwasapiPlayback_openProxy(ALCwasapiPlayback *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + void *ptr; + HRESULT hr; + + hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, &ptr); + if(SUCCEEDED(hr)) + { + auto Enumerator = reinterpret_cast(ptr); + if(!self->devid) + hr = Enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &self->mmdev); + else + hr = Enumerator->GetDevice(self->devid, &self->mmdev); + Enumerator->Release(); + } + if(SUCCEEDED(hr)) + hr = self->mmdev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); + if(SUCCEEDED(hr)) + { + self->client = reinterpret_cast(ptr); + if(alstr_empty(device->DeviceName)) + get_device_name_and_guid(self->mmdev, &device->DeviceName, nullptr); + } + + if(FAILED(hr)) + { + if(self->mmdev) + self->mmdev->Release(); + self->mmdev = nullptr; + } + + return hr; +} + + +static void ALCwasapiPlayback_closeProxy(ALCwasapiPlayback *self) +{ + if(self->client) + self->client->Release(); + self->client = nullptr; + + if(self->mmdev) + self->mmdev->Release(); + self->mmdev = nullptr; +} + + +static ALCboolean ALCwasapiPlayback_reset(ALCwasapiPlayback *self) +{ + ThreadRequest req = { self->MsgEvent, 0 }; + HRESULT hr = E_FAIL; + + if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + hr = WaitForResponse(&req); + + return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; +} + +static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + EndpointFormFactor formfactor = UnknownFormFactor; + WAVEFORMATEXTENSIBLE OutputType; + WAVEFORMATEX *wfx = nullptr; + REFERENCE_TIME min_per, buf_time; + UINT32 buffer_len, min_len; + void *ptr = nullptr; + HRESULT hr; + + if(self->client) + self->client->Release(); + self->client = nullptr; + + hr = self->mmdev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); + if(FAILED(hr)) + { + ERR("Failed to reactivate audio client: 0x%08lx\n", hr); + return hr; + } + self->client = reinterpret_cast(ptr); + + hr = self->client->GetMixFormat(&wfx); + if(FAILED(hr)) + { + ERR("Failed to get mix format: 0x%08lx\n", hr); + return hr; + } + + if(!MakeExtensible(&OutputType, wfx)) + { + CoTaskMemFree(wfx); + return E_FAIL; + } + CoTaskMemFree(wfx); + wfx = nullptr; + + buf_time = ScaleCeil(device->UpdateSize*device->NumUpdates, REFTIME_PER_SEC, + device->Frequency); + + if(!(device->Flags&DEVICE_FREQUENCY_REQUEST)) + device->Frequency = OutputType.Format.nSamplesPerSec; + if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) + { + if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) + device->FmtChans = DevFmtMono; + else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO) + device->FmtChans = DevFmtStereo; + else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD) + device->FmtChans = DevFmtQuad; + else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1) + device->FmtChans = DevFmtX51; + else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR) + device->FmtChans = DevFmtX51Rear; + else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1) + device->FmtChans = DevFmtX61; + else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE)) + device->FmtChans = DevFmtX71; + else + ERR("Unhandled channel config: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask); + } + + switch(device->FmtChans) + { + case DevFmtMono: + OutputType.Format.nChannels = 1; + OutputType.dwChannelMask = MONO; + break; + case DevFmtAmbi3D: + device->FmtChans = DevFmtStereo; + /*fall-through*/ + case DevFmtStereo: + OutputType.Format.nChannels = 2; + OutputType.dwChannelMask = STEREO; + break; + case DevFmtQuad: + OutputType.Format.nChannels = 4; + OutputType.dwChannelMask = QUAD; + break; + case DevFmtX51: + OutputType.Format.nChannels = 6; + OutputType.dwChannelMask = X5DOT1; + break; + case DevFmtX51Rear: + OutputType.Format.nChannels = 6; + OutputType.dwChannelMask = X5DOT1REAR; + break; + case DevFmtX61: + OutputType.Format.nChannels = 7; + OutputType.dwChannelMask = X6DOT1; + break; + case DevFmtX71: + OutputType.Format.nChannels = 8; + OutputType.dwChannelMask = X7DOT1; + break; + } + switch(device->FmtType) + { + case DevFmtByte: + device->FmtType = DevFmtUByte; + /* fall-through */ + case DevFmtUByte: + OutputType.Format.wBitsPerSample = 8; + OutputType.Samples.wValidBitsPerSample = 8; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtUShort: + device->FmtType = DevFmtShort; + /* fall-through */ + case DevFmtShort: + OutputType.Format.wBitsPerSample = 16; + OutputType.Samples.wValidBitsPerSample = 16; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtUInt: + device->FmtType = DevFmtInt; + /* fall-through */ + case DevFmtInt: + OutputType.Format.wBitsPerSample = 32; + OutputType.Samples.wValidBitsPerSample = 32; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtFloat: + OutputType.Format.wBitsPerSample = 32; + OutputType.Samples.wValidBitsPerSample = 32; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + break; + } + OutputType.Format.nSamplesPerSec = device->Frequency; + + OutputType.Format.nBlockAlign = OutputType.Format.nChannels * + OutputType.Format.wBitsPerSample / 8; + OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * + OutputType.Format.nBlockAlign; + + hr = self->client->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); + if(FAILED(hr)) + { + ERR("Failed to check format support: 0x%08lx\n", hr); + hr = self->client->GetMixFormat(&wfx); + } + if(FAILED(hr)) + { + ERR("Failed to find a supported format: 0x%08lx\n", hr); + return hr; + } + + if(wfx != nullptr) + { + if(!MakeExtensible(&OutputType, wfx)) + { + CoTaskMemFree(wfx); + return E_FAIL; + } + CoTaskMemFree(wfx); + wfx = nullptr; + + device->Frequency = OutputType.Format.nSamplesPerSec; + if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) + device->FmtChans = DevFmtMono; + else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO) + device->FmtChans = DevFmtStereo; + else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD) + device->FmtChans = DevFmtQuad; + else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1) + device->FmtChans = DevFmtX51; + else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR) + device->FmtChans = DevFmtX51Rear; + else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1) + device->FmtChans = DevFmtX61; + else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE)) + device->FmtChans = DevFmtX71; + else + { + ERR("Unhandled extensible channels: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask); + device->FmtChans = DevFmtStereo; + OutputType.Format.nChannels = 2; + OutputType.dwChannelMask = STEREO; + } + + if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_PCM)) + { + if(OutputType.Format.wBitsPerSample == 8) + device->FmtType = DevFmtUByte; + else if(OutputType.Format.wBitsPerSample == 16) + device->FmtType = DevFmtShort; + else if(OutputType.Format.wBitsPerSample == 32) + device->FmtType = DevFmtInt; + else + { + device->FmtType = DevFmtShort; + OutputType.Format.wBitsPerSample = 16; + } + } + else if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) + { + device->FmtType = DevFmtFloat; + OutputType.Format.wBitsPerSample = 32; + } + else + { + ERR("Unhandled format sub-type\n"); + device->FmtType = DevFmtShort; + OutputType.Format.wBitsPerSample = 16; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + } + OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; + } + get_device_formfactor(self->mmdev, &formfactor); + device->IsHeadphones = (device->FmtChans == DevFmtStereo && + (formfactor == Headphones || formfactor == Headset) + ); + + SetDefaultWFXChannelOrder(device); + + hr = self->client->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + buf_time, 0, &OutputType.Format, nullptr); + if(FAILED(hr)) + { + ERR("Failed to initialize audio client: 0x%08lx\n", hr); + return hr; + } + + hr = self->client->GetDevicePeriod(&min_per, nullptr); + if(SUCCEEDED(hr)) + { + min_len = (UINT32)ScaleCeil(min_per, device->Frequency, REFTIME_PER_SEC); + /* 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 = self->client->GetBufferSize(&buffer_len); + } + if(FAILED(hr)) + { + ERR("Failed to get audio buffer info: 0x%08lx\n", hr); + return hr; + } + + device->UpdateSize = min_len; + device->NumUpdates = buffer_len / device->UpdateSize; + if(device->NumUpdates <= 1) + { + ERR("Audio client returned buffer_len < period*2; expect break up\n"); + device->NumUpdates = 2; + device->UpdateSize = buffer_len / device->NumUpdates; + } + + hr = self->client->SetEventHandle(self->NotifyEvent); + if(FAILED(hr)) + { + ERR("Failed to set event handle: 0x%08lx\n", hr); + return hr; + } + + return hr; +} + + +static ALCboolean ALCwasapiPlayback_start(ALCwasapiPlayback *self) +{ + ThreadRequest req = { self->MsgEvent, 0 }; + HRESULT hr = E_FAIL; + + if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + hr = WaitForResponse(&req); + + return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; +} + +static HRESULT ALCwasapiPlayback_startProxy(ALCwasapiPlayback *self) +{ + HRESULT hr; + void *ptr; + + ResetEvent(self->NotifyEvent); + hr = self->client->Start(); + if(FAILED(hr)) + ERR("Failed to start audio client: 0x%08lx\n", hr); + + if(SUCCEEDED(hr)) + hr = self->client->GetService(IID_IAudioRenderClient, &ptr); + if(SUCCEEDED(hr)) + { + self->render = reinterpret_cast(ptr); + ATOMIC_STORE(&self->killNow, 0, almemory_order_release); + if(althrd_create(&self->thread, ALCwasapiPlayback_mixerProc, self) != althrd_success) + { + if(self->render) + self->render->Release(); + self->render = nullptr; + self->client->Stop(); + ERR("Failed to start thread\n"); + hr = E_FAIL; + } + } + + return hr; +} + + +static void ALCwasapiPlayback_stop(ALCwasapiPlayback *self) +{ + ThreadRequest req = { self->MsgEvent, 0 }; + if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + (void)WaitForResponse(&req); +} + +static void ALCwasapiPlayback_stopProxy(ALCwasapiPlayback *self) +{ + int res; + + if(!self->render) + return; + + ATOMIC_STORE_SEQ(&self->killNow, 1); + althrd_join(self->thread, &res); + + self->render->Release(); + self->render = nullptr; + self->client->Stop(); +} + + +static ClockLatency ALCwasapiPlayback_getClockLatency(ALCwasapiPlayback *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ClockLatency ret; + + ALCwasapiPlayback_lock(self); + ret.ClockTime = GetDeviceClockTime(device); + ret.Latency = ATOMIC_LOAD(&self->Padding, almemory_order_relaxed) * DEVICE_CLOCK_RES / + device->Frequency; + ALCwasapiPlayback_unlock(self); + + return ret; +} + + +typedef struct ALCwasapiCapture { + DERIVE_FROM_TYPE(ALCbackend); + DERIVE_FROM_TYPE(ALCwasapiProxy); + + WCHAR *devid; + + IMMDevice *mmdev; + IAudioClient *client; + IAudioCaptureClient *capture; + HANDLE NotifyEvent; + + HANDLE MsgEvent; + + ChannelConverter *ChannelConv; + SampleConverter *SampleConv; + ll_ringbuffer_t *Ring; + + ATOMIC(int) killNow; + althrd_t thread; +} ALCwasapiCapture; + +static int ALCwasapiCapture_recordProc(void *arg); + +static void ALCwasapiCapture_Construct(ALCwasapiCapture *self, ALCdevice *device); +static void ALCwasapiCapture_Destruct(ALCwasapiCapture *self); +static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *name); +static HRESULT ALCwasapiCapture_openProxy(ALCwasapiCapture *self); +static void ALCwasapiCapture_closeProxy(ALCwasapiCapture *self); +static DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, ALCboolean, reset) +static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self); +static ALCboolean ALCwasapiCapture_start(ALCwasapiCapture *self); +static HRESULT ALCwasapiCapture_startProxy(ALCwasapiCapture *self); +static void ALCwasapiCapture_stop(ALCwasapiCapture *self); +static void ALCwasapiCapture_stopProxy(ALCwasapiCapture *self); +static ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, ALCuint samples); +static ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self); +static DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCwasapiCapture) + +DEFINE_ALCWASAPIPROXY_VTABLE(ALCwasapiCapture); +DEFINE_ALCBACKEND_VTABLE(ALCwasapiCapture); + + +static void ALCwasapiCapture_Construct(ALCwasapiCapture *self, ALCdevice *device) +{ + SET_VTABLE2(ALCwasapiCapture, ALCbackend, self); + SET_VTABLE2(ALCwasapiCapture, ALCwasapiProxy, self); + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + ALCwasapiProxy_Construct(STATIC_CAST(ALCwasapiProxy, self)); + + self->devid = nullptr; + + self->mmdev = nullptr; + self->client = nullptr; + self->capture = nullptr; + self->NotifyEvent = nullptr; + + self->MsgEvent = nullptr; + + self->ChannelConv = nullptr; + self->SampleConv = nullptr; + self->Ring = nullptr; + + ATOMIC_INIT(&self->killNow, 0); +} + +static void ALCwasapiCapture_Destruct(ALCwasapiCapture *self) +{ + if(self->MsgEvent) + { + ThreadRequest req = { self->MsgEvent, 0 }; + if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + (void)WaitForResponse(&req); + + CloseHandle(self->MsgEvent); + self->MsgEvent = nullptr; + } + + if(self->NotifyEvent != nullptr) + CloseHandle(self->NotifyEvent); + self->NotifyEvent = nullptr; + + ll_ringbuffer_free(self->Ring); + self->Ring = nullptr; + + DestroySampleConverter(&self->SampleConv); + DestroyChannelConverter(&self->ChannelConv); + + free(self->devid); + self->devid = nullptr; + + ALCwasapiProxy_Destruct(STATIC_CAST(ALCwasapiProxy, self)); + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + + +FORCE_ALIGN int ALCwasapiCapture_recordProc(void *arg) +{ + auto self = reinterpret_cast(arg); + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + IAudioCaptureClient *capture = self->capture; + ALfloat *samples = nullptr; + size_t samplesmax = 0; + HRESULT hr; + + hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + if(FAILED(hr)) + { + ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); + V0(device->Backend,lock)(); + aluHandleDisconnect(device, "COM init failed: 0x%08lx", hr); + V0(device->Backend,unlock)(); + return 1; + } + + althrd_setname(althrd_current(), RECORD_THREAD_NAME); + + while(!ATOMIC_LOAD(&self->killNow, almemory_order_relaxed)) + { + UINT32 avail; + DWORD res; + + hr = capture->GetNextPacketSize(&avail); + if(FAILED(hr)) + ERR("Failed to get next packet size: 0x%08lx\n", hr); + else if(avail > 0) + { + UINT32 numsamples; + DWORD flags; + BYTE *rdata; + + hr = capture->GetBuffer(&rdata, &numsamples, &flags, nullptr, nullptr); + if(FAILED(hr)) + ERR("Failed to get capture buffer: 0x%08lx\n", hr); + else + { + ll_ringbuffer_data_t data[2]; + size_t dstframes = 0; + + if(self->ChannelConv) + { + if(samplesmax < numsamples) + { + size_t newmax = RoundUp(numsamples, 4096); + void *tmp = al_calloc(DEF_ALIGN, newmax*2*sizeof(ALfloat)); + al_free(samples); + samples = reinterpret_cast(tmp); + samplesmax = newmax; + } + ChannelConverterInput(self->ChannelConv, rdata, samples, numsamples); + rdata = (BYTE*)samples; + } + + ll_ringbuffer_get_write_vector(self->Ring, data); + + if(self->SampleConv) + { + const ALvoid *srcdata = rdata; + ALsizei srcframes = numsamples; + + dstframes = SampleConverterInput(self->SampleConv, + &srcdata, &srcframes, data[0].buf, (ALsizei)minz(data[0].len, INT_MAX) + ); + if(srcframes > 0 && dstframes == data[0].len && data[1].len > 0) + { + /* If some source samples remain, all of the first dest + * block was filled, and there's space in the second + * dest block, do another run for the second block. + */ + dstframes += SampleConverterInput(self->SampleConv, + &srcdata, &srcframes, data[1].buf, (ALsizei)minz(data[1].len, INT_MAX) + ); + } + } + else + { + ALuint framesize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, + device->AmbiOrder); + size_t len1 = minz(data[0].len, numsamples); + size_t len2 = minz(data[1].len, numsamples-len1); + + memcpy(data[0].buf, rdata, len1*framesize); + if(len2 > 0) + memcpy(data[1].buf, rdata+len1*framesize, len2*framesize); + dstframes = len1 + len2; + } + + ll_ringbuffer_write_advance(self->Ring, dstframes); + + hr = capture->ReleaseBuffer(numsamples); + if(FAILED(hr)) ERR("Failed to release capture buffer: 0x%08lx\n", hr); + } + } + + if(FAILED(hr)) + { + V0(device->Backend,lock)(); + aluHandleDisconnect(device, "Failed to capture samples: 0x%08lx", hr); + V0(device->Backend,unlock)(); + break; + } + + res = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE); + if(res != WAIT_OBJECT_0) + ERR("WaitForSingleObjectEx error: 0x%lx\n", res); + } + + al_free(samples); + samples = nullptr; + samplesmax = 0; + + CoUninitialize(); + return 0; +} + + +static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *deviceName) +{ + HRESULT hr = S_OK; + + self->NotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + self->MsgEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + if(self->NotifyEvent == nullptr || self->MsgEvent == nullptr) + { + ERR("Failed to create message events: %lu\n", GetLastError()); + hr = E_FAIL; + } + + if(SUCCEEDED(hr)) + { + if(deviceName) + { + const DevMap *iter; + + if(VECTOR_SIZE(CaptureDevices) == 0) + { + ThreadRequest req = { self->MsgEvent, 0 }; + if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, CAPTURE_DEVICE_PROBE)) + (void)WaitForResponse(&req); + } + + hr = E_FAIL; +#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, deviceName) == 0 || \ + alstr_cmp_cstr((i)->endpoint_guid, deviceName) == 0) + VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); +#undef MATCH_NAME + if(iter == VECTOR_END(CaptureDevices)) + { + int len; + if((len=MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, nullptr, 0)) > 0) + { + std::vector wname(len); + MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, wname.data(), len); +#define MATCH_NAME(i) (wcscmp((i)->devid, wname.data()) == 0) + VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); +#undef MATCH_NAME + } + } + if(iter == VECTOR_END(CaptureDevices)) + WARN("Failed to find device name matching \"%s\"\n", deviceName); + else + { + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + self->devid = strdupW(iter->devid); + alstr_copy(&device->DeviceName, iter->name); + hr = S_OK; + } + } + } + + if(SUCCEEDED(hr)) + { + ThreadRequest req = { self->MsgEvent, 0 }; + + hr = E_FAIL; + if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + hr = WaitForResponse(&req); + else + ERR("Failed to post thread message: %lu\n", GetLastError()); + } + + if(FAILED(hr)) + { + if(self->NotifyEvent != nullptr) + CloseHandle(self->NotifyEvent); + self->NotifyEvent = nullptr; + if(self->MsgEvent != nullptr) + CloseHandle(self->MsgEvent); + self->MsgEvent = nullptr; + + free(self->devid); + self->devid = nullptr; + + ERR("Device init failed: 0x%08lx\n", hr); + return ALC_INVALID_VALUE; + } + else + { + ThreadRequest req = { self->MsgEvent, 0 }; + + hr = E_FAIL; + if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + hr = WaitForResponse(&req); + else + ERR("Failed to post thread message: %lu\n", GetLastError()); + + if(FAILED(hr)) + { + if(hr == E_OUTOFMEMORY) + return ALC_OUT_OF_MEMORY; + return ALC_INVALID_VALUE; + } + } + + return ALC_NO_ERROR; +} + +static HRESULT ALCwasapiCapture_openProxy(ALCwasapiCapture *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + void *ptr; + HRESULT hr; + + hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, &ptr); + if(SUCCEEDED(hr)) + { + auto Enumerator = reinterpret_cast(ptr); + if(!self->devid) + hr = Enumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, &self->mmdev); + else + hr = Enumerator->GetDevice(self->devid, &self->mmdev); + Enumerator->Release(); + } + if(SUCCEEDED(hr)) + hr = self->mmdev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); + if(SUCCEEDED(hr)) + { + self->client = reinterpret_cast(ptr); + if(alstr_empty(device->DeviceName)) + get_device_name_and_guid(self->mmdev, &device->DeviceName, nullptr); + } + + if(FAILED(hr)) + { + if(self->mmdev) + self->mmdev->Release(); + self->mmdev = nullptr; + } + + return hr; +} + + +static void ALCwasapiCapture_closeProxy(ALCwasapiCapture *self) +{ + if(self->client) + self->client->Release(); + self->client = nullptr; + + if(self->mmdev) + self->mmdev->Release(); + self->mmdev = nullptr; +} + + +static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + WAVEFORMATEXTENSIBLE OutputType; + WAVEFORMATEX *wfx = nullptr; + enum DevFmtType srcType; + REFERENCE_TIME buf_time; + UINT32 buffer_len; + void *ptr = nullptr; + HRESULT hr; + + if(self->client) + self->client->Release(); + self->client = nullptr; + + hr = self->mmdev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); + if(FAILED(hr)) + { + ERR("Failed to reactivate audio client: 0x%08lx\n", hr); + return hr; + } + self->client = reinterpret_cast(ptr); + + buf_time = ScaleCeil(device->UpdateSize*device->NumUpdates, REFTIME_PER_SEC, + device->Frequency); + // Make sure buffer is at least 100ms in size + buf_time = maxu64(buf_time, REFTIME_PER_SEC/10); + device->UpdateSize = (ALuint)ScaleCeil(buf_time, device->Frequency, REFTIME_PER_SEC) / + device->NumUpdates; + + OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + switch(device->FmtChans) + { + case DevFmtMono: + OutputType.Format.nChannels = 1; + OutputType.dwChannelMask = MONO; + break; + case DevFmtStereo: + OutputType.Format.nChannels = 2; + OutputType.dwChannelMask = STEREO; + break; + case DevFmtQuad: + OutputType.Format.nChannels = 4; + OutputType.dwChannelMask = QUAD; + break; + case DevFmtX51: + OutputType.Format.nChannels = 6; + OutputType.dwChannelMask = X5DOT1; + break; + case DevFmtX51Rear: + OutputType.Format.nChannels = 6; + OutputType.dwChannelMask = X5DOT1REAR; + break; + case DevFmtX61: + OutputType.Format.nChannels = 7; + OutputType.dwChannelMask = X6DOT1; + break; + case DevFmtX71: + OutputType.Format.nChannels = 8; + OutputType.dwChannelMask = X7DOT1; + break; + + case DevFmtAmbi3D: + return E_FAIL; + } + switch(device->FmtType) + { + /* NOTE: Signedness doesn't matter, the converter will handle it. */ + case DevFmtByte: + case DevFmtUByte: + OutputType.Format.wBitsPerSample = 8; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtShort: + case DevFmtUShort: + OutputType.Format.wBitsPerSample = 16; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtInt: + case DevFmtUInt: + OutputType.Format.wBitsPerSample = 32; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtFloat: + OutputType.Format.wBitsPerSample = 32; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + break; + } + OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; + OutputType.Format.nSamplesPerSec = device->Frequency; + + OutputType.Format.nBlockAlign = OutputType.Format.nChannels * + OutputType.Format.wBitsPerSample / 8; + OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * + OutputType.Format.nBlockAlign; + OutputType.Format.cbSize = sizeof(OutputType) - sizeof(OutputType.Format); + + hr = self->client->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); + if(FAILED(hr)) + { + ERR("Failed to check format support: 0x%08lx\n", hr); + return hr; + } + + DestroySampleConverter(&self->SampleConv); + DestroyChannelConverter(&self->ChannelConv); + + if(wfx != nullptr) + { + if(!(wfx->nChannels == OutputType.Format.nChannels || + (wfx->nChannels == 1 && OutputType.Format.nChannels == 2) || + (wfx->nChannels == 2 && OutputType.Format.nChannels == 1))) + { + ERR("Failed to get matching format, wanted: %s %s %uhz, got: %d channel%s %d-bit %luhz\n", + DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), + device->Frequency, wfx->nChannels, (wfx->nChannels==1)?"":"s", wfx->wBitsPerSample, + wfx->nSamplesPerSec); + CoTaskMemFree(wfx); + return E_FAIL; + } + + if(!MakeExtensible(&OutputType, wfx)) + { + CoTaskMemFree(wfx); + return E_FAIL; + } + CoTaskMemFree(wfx); + wfx = nullptr; + } + + if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_PCM)) + { + if(OutputType.Format.wBitsPerSample == 8) + srcType = DevFmtUByte; + else if(OutputType.Format.wBitsPerSample == 16) + srcType = DevFmtShort; + else if(OutputType.Format.wBitsPerSample == 32) + srcType = DevFmtInt; + else + { + ERR("Unhandled integer bit depth: %d\n", OutputType.Format.wBitsPerSample); + return E_FAIL; + } + } + else if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) + { + if(OutputType.Format.wBitsPerSample == 32) + srcType = DevFmtFloat; + else + { + ERR("Unhandled float bit depth: %d\n", OutputType.Format.wBitsPerSample); + return E_FAIL; + } + } + else + { + ERR("Unhandled format sub-type\n"); + return E_FAIL; + } + + if(device->FmtChans == DevFmtMono && OutputType.Format.nChannels == 2) + { + self->ChannelConv = CreateChannelConverter(srcType, DevFmtStereo, device->FmtChans); + if(!self->ChannelConv) + { + ERR("Failed to create %s stereo-to-mono converter\n", DevFmtTypeString(srcType)); + return E_FAIL; + } + TRACE("Created %s stereo-to-mono converter\n", DevFmtTypeString(srcType)); + /* The channel converter always outputs float, so change the input type + * for the resampler/type-converter. + */ + srcType = DevFmtFloat; + } + else if(device->FmtChans == DevFmtStereo && OutputType.Format.nChannels == 1) + { + self->ChannelConv = CreateChannelConverter(srcType, DevFmtMono, device->FmtChans); + if(!self->ChannelConv) + { + ERR("Failed to create %s mono-to-stereo converter\n", DevFmtTypeString(srcType)); + return E_FAIL; + } + TRACE("Created %s mono-to-stereo converter\n", DevFmtTypeString(srcType)); + srcType = DevFmtFloat; + } + + if(device->Frequency != OutputType.Format.nSamplesPerSec || device->FmtType != srcType) + { + self->SampleConv = CreateSampleConverter( + srcType, device->FmtType, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder), + OutputType.Format.nSamplesPerSec, device->Frequency + ); + if(!self->SampleConv) + { + ERR("Failed to create converter for %s format, dst: %s %uhz, src: %s %luhz\n", + DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), + device->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec); + return E_FAIL; + } + TRACE("Created converter for %s format, dst: %s %uhz, src: %s %luhz\n", + DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), + device->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec); + } + + hr = self->client->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + buf_time, 0, &OutputType.Format, nullptr); + if(FAILED(hr)) + { + ERR("Failed to initialize audio client: 0x%08lx\n", hr); + return hr; + } + + hr = self->client->GetBufferSize(&buffer_len); + if(FAILED(hr)) + { + ERR("Failed to get buffer size: 0x%08lx\n", hr); + return hr; + } + + buffer_len = maxu(device->UpdateSize*device->NumUpdates, buffer_len); + ll_ringbuffer_free(self->Ring); + self->Ring = ll_ringbuffer_create(buffer_len, + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), + false + ); + if(!self->Ring) + { + ERR("Failed to allocate capture ring buffer\n"); + return E_OUTOFMEMORY; + } + + hr = self->client->SetEventHandle(self->NotifyEvent); + if(FAILED(hr)) + { + ERR("Failed to set event handle: 0x%08lx\n", hr); + return hr; + } + + return hr; +} + + +static ALCboolean ALCwasapiCapture_start(ALCwasapiCapture *self) +{ + ThreadRequest req = { self->MsgEvent, 0 }; + HRESULT hr = E_FAIL; + + if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + hr = WaitForResponse(&req); + + return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; +} + +static HRESULT ALCwasapiCapture_startProxy(ALCwasapiCapture *self) +{ + HRESULT hr; + void *ptr; + + ResetEvent(self->NotifyEvent); + hr = self->client->Start(); + if(FAILED(hr)) + { + ERR("Failed to start audio client: 0x%08lx\n", hr); + return hr; + } + + hr = self->client->GetService(IID_IAudioCaptureClient, &ptr); + if(SUCCEEDED(hr)) + { + self->capture = reinterpret_cast(ptr); + ATOMIC_STORE(&self->killNow, 0, almemory_order_release); + if(althrd_create(&self->thread, ALCwasapiCapture_recordProc, self) != althrd_success) + { + ERR("Failed to start thread\n"); + self->capture->Release(); + self->capture = nullptr; + hr = E_FAIL; + } + } + + if(FAILED(hr)) + { + self->client->Stop(); + self->client->Reset(); + } + + return hr; +} + + +static void ALCwasapiCapture_stop(ALCwasapiCapture *self) +{ + ThreadRequest req = { self->MsgEvent, 0 }; + if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + (void)WaitForResponse(&req); +} + +static void ALCwasapiCapture_stopProxy(ALCwasapiCapture *self) +{ + int res; + + if(!self->capture) + return; + + ATOMIC_STORE_SEQ(&self->killNow, 1); + althrd_join(self->thread, &res); + + self->capture->Release(); + self->capture = nullptr; + self->client->Stop(); + self->client->Reset(); +} + + +ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self) +{ + return (ALuint)ll_ringbuffer_read_space(self->Ring); +} + +ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, ALCuint samples) +{ + if(ALCwasapiCapture_availableSamples(self) < samples) + return ALC_INVALID_VALUE; + ll_ringbuffer_read(self->Ring, reinterpret_cast(buffer), samples); + return ALC_NO_ERROR; +} + + +typedef struct ALCwasapiBackendFactory { + DERIVE_FROM_TYPE(ALCbackendFactory); +} ALCwasapiBackendFactory; +#define ALCWASAPIBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwasapiBackendFactory, ALCbackendFactory) } } + +static ALCboolean ALCwasapiBackendFactory_init(ALCwasapiBackendFactory *self); +static void ALCwasapiBackendFactory_deinit(ALCwasapiBackendFactory *self); +static ALCboolean ALCwasapiBackendFactory_querySupport(ALCwasapiBackendFactory *self, ALCbackend_Type type); +static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory *self, enum DevProbe type, al_string *outnames); +static ALCbackend* ALCwasapiBackendFactory_createBackend(ALCwasapiBackendFactory *self, ALCdevice *device, ALCbackend_Type type); + +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwasapiBackendFactory); + + +static ALCboolean ALCwasapiBackendFactory_init(ALCwasapiBackendFactory* UNUSED(self)) +{ + static HRESULT InitResult; + + VECTOR_INIT(PlaybackDevices); + VECTOR_INIT(CaptureDevices); + + if(!ThreadHdl) + { + ThreadRequest req; + InitResult = E_FAIL; + + req.FinishedEvt = CreateEventW(nullptr, FALSE, FALSE, nullptr); + if(req.FinishedEvt == nullptr) + ERR("Failed to create event: %lu\n", GetLastError()); + else + { + ThreadHdl = CreateThread(nullptr, 0, ALCwasapiProxy_messageHandler, &req, 0, &ThreadID); + if(ThreadHdl != nullptr) + InitResult = WaitForResponse(&req); + CloseHandle(req.FinishedEvt); + } + } + + return SUCCEEDED(InitResult) ? ALC_TRUE : ALC_FALSE; +} + +static void ALCwasapiBackendFactory_deinit(ALCwasapiBackendFactory* UNUSED(self)) +{ + clear_devlist(&PlaybackDevices); + VECTOR_DEINIT(PlaybackDevices); + + clear_devlist(&CaptureDevices); + VECTOR_DEINIT(CaptureDevices); + + if(ThreadHdl) + { + TRACE("Sending WM_QUIT to Thread %04lx\n", ThreadID); + PostThreadMessage(ThreadID, WM_QUIT, 0, 0); + CloseHandle(ThreadHdl); + ThreadHdl = nullptr; + } +} + +static ALCboolean ALCwasapiBackendFactory_querySupport(ALCwasapiBackendFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Playback || type == ALCbackend_Capture) + return ALC_TRUE; + return ALC_FALSE; +} + +static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +{ + ThreadRequest req = { nullptr, 0 }; + + req.FinishedEvt = CreateEventW(nullptr, FALSE, FALSE, nullptr); + if(req.FinishedEvt == nullptr) + 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) + { +#define APPEND_OUTNAME(e) do { \ + if(!alstr_empty((e)->name)) \ + alstr_append_range(outnames, VECTOR_BEGIN((e)->name), \ + VECTOR_END((e)->name)+1); \ +} while(0) + case ALL_DEVICE_PROBE: + VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_OUTNAME); + break; + + case CAPTURE_DEVICE_PROBE: + VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_OUTNAME); + break; +#undef APPEND_OUTNAME + } + CloseHandle(req.FinishedEvt); + req.FinishedEvt = nullptr; + } +} + +static ALCbackend* ALCwasapiBackendFactory_createBackend(ALCwasapiBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCwasapiPlayback *backend; + NEW_OBJ(backend, ALCwasapiPlayback)(device); + if(!backend) return nullptr; + return STATIC_CAST(ALCbackend, backend); + } + if(type == ALCbackend_Capture) + { + ALCwasapiCapture *backend; + NEW_OBJ(backend, ALCwasapiCapture)(device); + if(!backend) return nullptr; + return STATIC_CAST(ALCbackend, backend); + } + + return nullptr; +} + + +ALCbackendFactory *ALCwasapiBackendFactory_getFactory(void) +{ + static ALCwasapiBackendFactory factory = ALCWASAPIBACKENDFACTORY_INITIALIZER; + return STATIC_CAST(ALCbackendFactory, &factory); +} diff --git a/CMakeLists.txt b/CMakeLists.txt index ecee25d7..f4c0ae4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1158,7 +1158,7 @@ IF(HAVE_WINDOWS_H) IF(ALSOFT_BACKEND_WASAPI) SET(HAVE_WASAPI 1) SET(BACKENDS "${BACKENDS} WASAPI,") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/wasapi.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/wasapi.cpp) ENDIF() ENDIF() -- cgit v1.2.3 From 434582b8e35b9fcd4566d82d50aca58251258331 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Nov 2018 20:18:51 -0700 Subject: Use an anonymous namespace instead of static for some things --- Alc/backends/pulseaudio.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index a52a028d..b6f7940b 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -506,6 +506,8 @@ static void pulse_close(pa_threaded_mainloop *loop, pa_context *context, pa_stre } +namespace { + struct DevMap { std::string name; std::string device_name; @@ -516,7 +518,7 @@ struct DevMap { { } }; -static bool checkName(const std::vector &list, const std::string &name) +bool checkName(const std::vector &list, const std::string &name) { return std::find_if(list.cbegin(), list.cend(), [&name](const DevMap &entry) -> bool @@ -524,8 +526,10 @@ static bool checkName(const std::vector &list, const std::string &name) ) != list.cend(); } -static std::vector PlaybackDevices; -static std::vector CaptureDevices; +std::vector PlaybackDevices; +std::vector CaptureDevices; + +} // namespace struct PulsePlayback { -- cgit v1.2.3 From a90b17113a40d1ebb557eac3c89d61681e43ee9c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Nov 2018 21:39:34 -0700 Subject: Use more C++ types where possible --- Alc/backends/wasapi.cpp | 633 ++++++++++++++++++++++-------------------------- 1 file changed, 290 insertions(+), 343 deletions(-) diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 099f9886..d12fbe84 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -38,12 +38,15 @@ #include #endif +#include +#include #include +#include +#include #include "alMain.h" #include "alu.h" #include "ringbuffer.h" -#include "threads.h" #include "compat.h" #include "alstring.h" #include "converter.h" @@ -73,43 +76,65 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x /* Scales the given value using 64-bit integer math, ceiling the result. */ -static inline ALuint64 ScaleCeil(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale) +static inline ALint64 ScaleCeil(ALint64 val, ALint64 new_scale, ALint64 old_scale) { return (val*new_scale + old_scale-1) / old_scale; } -typedef struct { - al_string name; - al_string endpoint_guid; // obtained from PKEY_AudioEndpoint_GUID , set to "Unknown device GUID" if absent. - WCHAR *devid; -} DevMap; -TYPEDEF_VECTOR(DevMap, vector_DevMap) +namespace { + +struct DevMap { + std::string name; + std::string endpoint_guid; // obtained from PKEY_AudioEndpoint_GUID , set to "Unknown device GUID" if absent. + std::wstring devid; + + template + DevMap(T0&& name_, T1&& guid_, T2&& devid_) + : name{std::forward(name_)} + , endpoint_guid{std::forward(guid_)} + , devid{std::forward(devid_)} + { } +}; -static void clear_devlist(vector_DevMap *list) +bool checkName(const std::vector &list, const std::string &name) { -#define CLEAR_DEVMAP(i) do { \ - AL_STRING_DEINIT((i)->name); \ - AL_STRING_DEINIT((i)->endpoint_guid); \ - free((i)->devid); \ - (i)->devid = nullptr; \ -} while(0) - VECTOR_FOR_EACH(DevMap, *list, CLEAR_DEVMAP); - VECTOR_RESIZE(*list, 0, 0); -#undef CLEAR_DEVMAP + return std::find_if(list.cbegin(), list.cend(), + [&name](const DevMap &entry) -> bool + { return entry.name == name; } + ) != list.cend(); } -static vector_DevMap PlaybackDevices; -static vector_DevMap CaptureDevices; +std::vector PlaybackDevices; +std::vector CaptureDevices; + +std::string wstr_to_string(const WCHAR *wstr) +{ + std::string ret; -static HANDLE ThreadHdl; -static DWORD ThreadID; + int len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr); + if(len > 0) + { + ret.resize(len); + WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &ret[0], len, nullptr, nullptr); + ret.pop_back(); + } + + return ret; +} -typedef struct { + +HANDLE ThreadHdl; +DWORD ThreadID; + +struct ThreadRequest { HANDLE FinishedEvt; HRESULT result; -} ThreadRequest; +}; + +} // namespace + #define WM_USER_First (WM_USER+0) #define WM_USER_OpenDevice (WM_USER+0) @@ -144,78 +169,72 @@ static HRESULT WaitForResponse(ThreadRequest *req) } -static void get_device_name_and_guid(IMMDevice *device, al_string *name, al_string *guid) +using NameGUIDPair = std::pair; +static NameGUIDPair get_device_name_and_guid(IMMDevice *device) { - IPropertyStore *ps; - PROPVARIANT pvname; - PROPVARIANT pvguid; - HRESULT hr; - - alstr_copy_cstr(name, DEVNAME_HEAD); + std::string name{DEVNAME_HEAD}; - hr = device->OpenPropertyStore(STGM_READ, &ps); + IPropertyStore *ps; + HRESULT hr = device->OpenPropertyStore(STGM_READ, &ps); if(FAILED(hr)) { WARN("OpenPropertyStore failed: 0x%08lx\n", hr); - alstr_append_cstr(name, "Unknown Device Name"); - if(guid) alstr_copy_cstr(guid, "Unknown Device GUID"); - return; + return { name+"Unknown Device Name", "Unknown Device GUID" }; } + PROPVARIANT pvname; PropVariantInit(&pvname); hr = ps->GetValue(reinterpret_cast(DEVPKEY_Device_FriendlyName), &pvname); if(FAILED(hr)) { WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr); - alstr_append_cstr(name, "Unknown Device Name"); + name += "Unknown Device Name"; } else if(pvname.vt == VT_LPWSTR) - alstr_append_wcstr(name, pvname.pwszVal); + name += wstr_to_string(pvname.pwszVal); else { WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvname.vt); - alstr_append_cstr(name, "Unknown Device Name"); + name += "Unknown Device Name"; } PropVariantClear(&pvname); - if(guid) - { - PropVariantInit(&pvguid); - - hr = ps->GetValue(reinterpret_cast(PKEY_AudioEndpoint_GUID), &pvguid); - if(FAILED(hr)) - { - WARN("GetValue AudioEndpoint_GUID failed: 0x%08lx\n", hr); - alstr_copy_cstr(guid, "Unknown Device GUID"); - } - else if(pvguid.vt == VT_LPWSTR) - alstr_copy_wcstr(guid, pvguid.pwszVal); - else - { - WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvguid.vt); - alstr_copy_cstr(guid, "Unknown Device GUID"); - } + std::string guid; + PROPVARIANT pvguid; + PropVariantInit(&pvguid); - PropVariantClear(&pvguid); + hr = ps->GetValue(reinterpret_cast(PKEY_AudioEndpoint_GUID), &pvguid); + if(FAILED(hr)) + { + WARN("GetValue AudioEndpoint_GUID failed: 0x%08lx\n", hr); + guid = "Unknown Device GUID"; + } + else if(pvname.vt == VT_LPWSTR) + guid = wstr_to_string(pvname.pwszVal); + else + { + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvguid.vt); + guid = "Unknown Device GUID"; } + PropVariantClear(&pvguid); ps->Release(); + + return {name, guid}; } static void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfactor) { IPropertyStore *ps; - PROPVARIANT pvform; - HRESULT hr; - - hr = device->OpenPropertyStore(STGM_READ, &ps); + HRESULT hr = device->OpenPropertyStore(STGM_READ, &ps); if(FAILED(hr)) { WARN("OpenPropertyStore failed: 0x%08lx\n", hr); return; } + PROPVARIANT pvform; PropVariantInit(&pvform); hr = ps->GetValue(reinterpret_cast(PKEY_AudioEndpoint_FormFactor), &pvform); @@ -233,50 +252,31 @@ static void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfac } -static void add_device(IMMDevice *device, const WCHAR *devid, vector_DevMap *list) +static void add_device(IMMDevice *device, const WCHAR *devid, std::vector &list) { - int count = 0; - al_string tmpname; - DevMap entry; - - AL_STRING_INIT(tmpname); - AL_STRING_INIT(entry.name); - AL_STRING_INIT(entry.endpoint_guid); - - entry.devid = strdupW(devid); - get_device_name_and_guid(device, &tmpname, &entry.endpoint_guid); + std::string basename, guidstr; + std::tie(basename, guidstr) = get_device_name_and_guid(device); - while(1) + int count{1}; + std::string newname{basename}; + while(checkName(PlaybackDevices, newname)) { - const DevMap *iter; - - alstr_copy(&entry.name, tmpname); - if(count != 0) - { - char str[64]; - snprintf(str, sizeof(str), " #%d", count+1); - alstr_append_cstr(&entry.name, str); - } - -#define MATCH_ENTRY(i) (alstr_cmp(entry.name, (i)->name) == 0) - VECTOR_FIND_IF(iter, const DevMap, *list, MATCH_ENTRY); - if(iter == VECTOR_END(*list)) break; -#undef MATCH_ENTRY - count++; + newname = basename; + newname += " #"; + newname += std::to_string(++count); } + list.emplace_back(std::move(newname), std::move(guidstr), devid); + const DevMap &newentry = list.back(); - TRACE("Got device \"%s\", \"%s\", \"%ls\"\n", alstr_get_cstr(entry.name), alstr_get_cstr(entry.endpoint_guid), entry.devid); - VECTOR_PUSH_BACK(*list, entry); - - AL_STRING_DEINIT(tmpname); + TRACE("Got device \"%s\", \"%s\", \"%ls\"\n", newentry.name.c_str(), + newentry.endpoint_guid.c_str(), newentry.devid.c_str()); } static WCHAR *get_device_id(IMMDevice *device) { WCHAR *devid; - HRESULT hr; - hr = device->GetId(&devid); + HRESULT hr = device->GetId(&devid); if(FAILED(hr)) { ERR("Failed to get device id: %lx\n", hr); @@ -286,28 +286,24 @@ static WCHAR *get_device_id(IMMDevice *device) return devid; } -static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, vector_DevMap *list) +static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, std::vector &list) { IMMDeviceCollection *coll; - IMMDevice *defdev = nullptr; - WCHAR *defdevid = nullptr; - HRESULT hr; - UINT count; - UINT i; - - hr = devenum->EnumAudioEndpoints(flowdir, DEVICE_STATE_ACTIVE, &coll); + HRESULT hr = devenum->EnumAudioEndpoints(flowdir, DEVICE_STATE_ACTIVE, &coll); if(FAILED(hr)) { ERR("Failed to enumerate audio endpoints: 0x%08lx\n", hr); return hr; } - count = 0; + IMMDevice *defdev{nullptr}; + WCHAR *defdevid{nullptr}; + UINT count{0}; hr = coll->GetCount(&count); if(SUCCEEDED(hr) && count > 0) { - clear_devlist(list); - VECTOR_RESIZE(*list, 0, count); + list.clear(); + list.reserve(count); hr = devenum->GetDefaultAudioEndpoint(flowdir, eMultimedia, &defdev); } @@ -318,15 +314,13 @@ static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ve add_device(defdev, defdevid, list); } - for(i = 0;i < count;++i) + for(UINT i{0};i < count;++i) { IMMDevice *device; - WCHAR *devid; - hr = coll->Item(i, &device); if(FAILED(hr)) continue; - devid = get_device_id(device); + WCHAR *devid = get_device_id(device); if(devid) { if(wcscmp(devid, defdevid) != 0) @@ -381,14 +375,10 @@ static void ALCwasapiProxy_Destruct(ALCwasapiProxy* UNUSED(self)) { } static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) { auto req = reinterpret_cast(ptr); - ALuint deviceCount = 0; - ALCwasapiProxy *proxy; - HRESULT hr, cohr; - MSG msg; TRACE("Starting message thread\n"); - cohr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + HRESULT cohr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if(FAILED(cohr)) { WARN("Failed to initialize COM: 0x%08lx\n", cohr); @@ -396,7 +386,8 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) return 0; } - hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, &ptr); + HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, + IID_IMMDeviceEnumerator, &ptr); if(FAILED(hr)) { WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr); @@ -414,12 +405,14 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) * returning success, otherwise PostThreadMessage may fail if it gets * called before GetMessage. */ + MSG msg; PeekMessage(&msg, nullptr, WM_USER, WM_USER, PM_NOREMOVE); TRACE("Message thread initialization complete\n"); ReturnMsgResponse(req, S_OK); TRACE("Starting message loop\n"); + ALuint deviceCount{0}; while(GetMessage(&msg, nullptr, WM_USER_First, WM_USER_Last)) { TRACE("Got message \"%s\" (0x%04x, lparam=%p, wparam=%p)\n", @@ -427,6 +420,8 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) MessageStr[msg.message-WM_USER] : "Unknown", msg.message, (void*)msg.lParam, (void*)msg.wParam ); + + ALCwasapiProxy *proxy{nullptr}; switch(msg.message) { case WM_USER_OpenDevice: @@ -495,9 +490,9 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) Enumerator = reinterpret_cast(ptr); if(msg.lParam == ALL_DEVICE_PROBE) - hr = probe_devices(Enumerator, eRender, &PlaybackDevices); + hr = probe_devices(Enumerator, eRender, PlaybackDevices); else if(msg.lParam == CAPTURE_DEVICE_PROBE) - hr = probe_devices(Enumerator, eCapture, &CaptureDevices); + hr = probe_devices(Enumerator, eCapture, CaptureDevices); Enumerator->Release(); Enumerator = nullptr; @@ -524,22 +519,22 @@ typedef struct ALCwasapiPlayback { DERIVE_FROM_TYPE(ALCbackend); DERIVE_FROM_TYPE(ALCwasapiProxy); - WCHAR *devid; + std::wstring devid; - IMMDevice *mmdev; - IAudioClient *client; - IAudioRenderClient *render; - HANDLE NotifyEvent; + IMMDevice *mmdev{nullptr}; + IAudioClient *client{nullptr}; + IAudioRenderClient *render{nullptr}; + HANDLE NotifyEvent{nullptr}; - HANDLE MsgEvent; + HANDLE MsgEvent{nullptr}; - ATOMIC(UINT32) Padding; + std::atomic Padding{0u}; - ATOMIC(int) killNow; - althrd_t thread; + std::atomic killNow{AL_TRUE}; + std::thread thread; } ALCwasapiPlayback; -static int ALCwasapiPlayback_mixerProc(void *arg); +static int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self); static void ALCwasapiPlayback_Construct(ALCwasapiPlayback *self, ALCdevice *device); static void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self); @@ -565,23 +560,11 @@ DEFINE_ALCBACKEND_VTABLE(ALCwasapiPlayback); static void ALCwasapiPlayback_Construct(ALCwasapiPlayback *self, ALCdevice *device) { + new (self) ALCwasapiPlayback{}; SET_VTABLE2(ALCwasapiPlayback, ALCbackend, self); SET_VTABLE2(ALCwasapiPlayback, ALCwasapiProxy, self); ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); ALCwasapiProxy_Construct(STATIC_CAST(ALCwasapiProxy, self)); - - self->devid = nullptr; - - self->mmdev = nullptr; - self->client = nullptr; - self->render = nullptr; - self->NotifyEvent = nullptr; - - self->MsgEvent = nullptr; - - ATOMIC_INIT(&self->Padding, 0u); - - ATOMIC_INIT(&self->killNow, 0); } static void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self) @@ -600,9 +583,6 @@ static void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self) CloseHandle(self->NotifyEvent); self->NotifyEvent = nullptr; - free(self->devid); - self->devid = nullptr; - if(self->NotifyEvent != nullptr) CloseHandle(self->NotifyEvent); self->NotifyEvent = nullptr; @@ -610,26 +590,19 @@ static void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self) CloseHandle(self->MsgEvent); self->MsgEvent = nullptr; - free(self->devid); - self->devid = nullptr; - ALCwasapiProxy_Destruct(STATIC_CAST(ALCwasapiProxy, self)); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCwasapiPlayback(); } -FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(void *arg) +FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self) { - auto self = reinterpret_cast(arg); ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; - IAudioClient *client = self->client; - IAudioRenderClient *render = self->render; - UINT32 buffer_len, written; - ALuint update_size, len; - BYTE *buffer; - HRESULT hr; + IAudioClient *client{self->client}; + IAudioRenderClient *render{self->render}; - hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if(FAILED(hr)) { ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); @@ -642,10 +615,11 @@ FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(void *arg) SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); - update_size = device->UpdateSize; - buffer_len = update_size * device->NumUpdates; - while(!ATOMIC_LOAD(&self->killNow, almemory_order_relaxed)) + ALuint update_size{device->UpdateSize}; + UINT32 buffer_len{update_size * device->NumUpdates}; + while(!self->killNow.load(std::memory_order_relaxed)) { + UINT32 written; hr = client->GetCurrentPadding(&written); if(FAILED(hr)) { @@ -655,9 +629,9 @@ FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(void *arg) V0(device->Backend,unlock)(); break; } - ATOMIC_STORE(&self->Padding, written, almemory_order_relaxed); + self->Padding.store(written, std::memory_order_relaxed); - len = buffer_len - written; + ALuint len{buffer_len - written}; if(len < update_size) { DWORD res; @@ -668,12 +642,13 @@ FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(void *arg) } len -= len%update_size; + BYTE *buffer; hr = render->GetBuffer(len, &buffer); if(SUCCEEDED(hr)) { ALCwasapiPlayback_lock(self); aluMixData(device, buffer, len); - ATOMIC_STORE(&self->Padding, written + len, almemory_order_relaxed); + self->Padding.store(written + len, std::memory_order_relaxed); ALCwasapiPlayback_unlock(self); hr = render->ReleaseBuffer(len, 0); } @@ -686,7 +661,7 @@ FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(void *arg) break; } } - ATOMIC_STORE(&self->Padding, 0u, almemory_order_release); + self->Padding.store(0u, std::memory_order_release); CoUninitialize(); return 0; @@ -748,9 +723,7 @@ static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *de { if(deviceName) { - const DevMap *iter; - - if(VECTOR_SIZE(PlaybackDevices) == 0) + if(PlaybackDevices.empty()) { ThreadRequest req = { self->MsgEvent, 0 }; if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, ALL_DEVICE_PROBE)) @@ -758,29 +731,30 @@ static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *de } hr = E_FAIL; -#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, deviceName) == 0 || \ - alstr_cmp_cstr((i)->endpoint_guid, deviceName) == 0) - VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); -#undef MATCH_NAME - if(iter == VECTOR_END(PlaybackDevices)) + auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + [deviceName](const DevMap &entry) -> bool + { return entry.name == deviceName || entry.endpoint_guid == deviceName; } + ); + if(iter == PlaybackDevices.cend()) { int len; if((len=MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, nullptr, 0)) > 0) { std::vector wname(len); MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, wname.data(), len); -#define MATCH_NAME(i) (wcscmp((i)->devid, wname.data()) == 0) - VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); -#undef MATCH_NAME + iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + [&wname](const DevMap &entry) -> bool + { return entry.devid == wname.data(); } + ); } } - if(iter == VECTOR_END(PlaybackDevices)) + if(iter == PlaybackDevices.cend()) WARN("Failed to find device name matching \"%s\"\n", deviceName); else { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - self->devid = strdupW(iter->devid); - alstr_copy(&device->DeviceName, iter->name); + self->devid = iter->devid; + alstr_copy_range(&device->DeviceName, &*iter->name.cbegin(), &*iter->name.cend()); hr = S_OK; } } @@ -788,7 +762,7 @@ static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *de if(SUCCEEDED(hr)) { - ThreadRequest req = { self->MsgEvent, 0 }; + ThreadRequest req{ self->MsgEvent, 0 }; hr = E_FAIL; if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) @@ -806,8 +780,7 @@ static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *de CloseHandle(self->MsgEvent); self->MsgEvent = nullptr; - free(self->devid); - self->devid = nullptr; + self->devid.clear(); ERR("Device init failed: 0x%08lx\n", hr); return ALC_INVALID_VALUE; @@ -826,10 +799,10 @@ static HRESULT ALCwasapiPlayback_openProxy(ALCwasapiPlayback *self) if(SUCCEEDED(hr)) { auto Enumerator = reinterpret_cast(ptr); - if(!self->devid) + if(self->devid.empty()) hr = Enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &self->mmdev); else - hr = Enumerator->GetDevice(self->devid, &self->mmdev); + hr = Enumerator->GetDevice(self->devid.c_str(), &self->mmdev); Enumerator->Release(); } if(SUCCEEDED(hr)) @@ -838,7 +811,11 @@ static HRESULT ALCwasapiPlayback_openProxy(ALCwasapiPlayback *self) { self->client = reinterpret_cast(ptr); if(alstr_empty(device->DeviceName)) - get_device_name_and_guid(self->mmdev, &device->DeviceName, nullptr); + { + std::string devname; + std::tie(devname, std::ignore) = get_device_name_and_guid(self->mmdev); + alstr_copy_range(&device->DeviceName, &*devname.cbegin(), &*devname.cend()); + } } if(FAILED(hr)) @@ -866,8 +843,8 @@ static void ALCwasapiPlayback_closeProxy(ALCwasapiPlayback *self) static ALCboolean ALCwasapiPlayback_reset(ALCwasapiPlayback *self) { - ThreadRequest req = { self->MsgEvent, 0 }; - HRESULT hr = E_FAIL; + ThreadRequest req{ self->MsgEvent, 0 }; + HRESULT hr{E_FAIL}; if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) hr = WaitForResponse(&req); @@ -1136,8 +1113,8 @@ static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self) static ALCboolean ALCwasapiPlayback_start(ALCwasapiPlayback *self) { - ThreadRequest req = { self->MsgEvent, 0 }; - HRESULT hr = E_FAIL; + ThreadRequest req{ self->MsgEvent, 0 }; + HRESULT hr{E_FAIL}; if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) hr = WaitForResponse(&req); @@ -1153,45 +1130,48 @@ static HRESULT ALCwasapiPlayback_startProxy(ALCwasapiPlayback *self) ResetEvent(self->NotifyEvent); hr = self->client->Start(); if(FAILED(hr)) + { ERR("Failed to start audio client: 0x%08lx\n", hr); + return hr; + } - if(SUCCEEDED(hr)) - hr = self->client->GetService(IID_IAudioRenderClient, &ptr); + hr = self->client->GetService(IID_IAudioRenderClient, &ptr); if(SUCCEEDED(hr)) { self->render = reinterpret_cast(ptr); - ATOMIC_STORE(&self->killNow, 0, almemory_order_release); - if(althrd_create(&self->thread, ALCwasapiPlayback_mixerProc, self) != althrd_success) - { - if(self->render) - self->render->Release(); + try { + self->killNow.store(AL_FALSE, std::memory_order_release); + self->thread = std::thread(ALCwasapiPlayback_mixerProc, self); + } + catch(...) { + self->render->Release(); self->render = nullptr; - self->client->Stop(); ERR("Failed to start thread\n"); hr = E_FAIL; } } + if(FAILED(hr)) + self->client->Stop(); + return hr; } static void ALCwasapiPlayback_stop(ALCwasapiPlayback *self) { - ThreadRequest req = { self->MsgEvent, 0 }; + ThreadRequest req{ self->MsgEvent, 0 }; if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) (void)WaitForResponse(&req); } static void ALCwasapiPlayback_stopProxy(ALCwasapiPlayback *self) { - int res; - - if(!self->render) + if(!self->render || !self->thread.joinable()) return; - ATOMIC_STORE_SEQ(&self->killNow, 1); - althrd_join(self->thread, &res); + self->killNow.store(AL_TRUE); + self->thread.join(); self->render->Release(); self->render = nullptr; @@ -1206,7 +1186,7 @@ static ClockLatency ALCwasapiPlayback_getClockLatency(ALCwasapiPlayback *self) ALCwasapiPlayback_lock(self); ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = ATOMIC_LOAD(&self->Padding, almemory_order_relaxed) * DEVICE_CLOCK_RES / + ret.Latency = self->Padding.load(std::memory_order_relaxed) * DEVICE_CLOCK_RES / device->Frequency; ALCwasapiPlayback_unlock(self); @@ -1218,24 +1198,24 @@ typedef struct ALCwasapiCapture { DERIVE_FROM_TYPE(ALCbackend); DERIVE_FROM_TYPE(ALCwasapiProxy); - WCHAR *devid; + std::wstring devid; - IMMDevice *mmdev; - IAudioClient *client; - IAudioCaptureClient *capture; - HANDLE NotifyEvent; + IMMDevice *mmdev{nullptr}; + IAudioClient *client{nullptr}; + IAudioCaptureClient *capture{nullptr}; + HANDLE NotifyEvent{nullptr}; - HANDLE MsgEvent; + HANDLE MsgEvent{nullptr}; - ChannelConverter *ChannelConv; - SampleConverter *SampleConv; - ll_ringbuffer_t *Ring; + ChannelConverter *ChannelConv{nullptr}; + SampleConverter *SampleConv{nullptr}; + ll_ringbuffer_t *Ring{nullptr}; - ATOMIC(int) killNow; - althrd_t thread; + std::atomic killNow{AL_TRUE}; + std::thread thread; } ALCwasapiCapture; -static int ALCwasapiCapture_recordProc(void *arg); +static int ALCwasapiCapture_recordProc(ALCwasapiCapture *self); static void ALCwasapiCapture_Construct(ALCwasapiCapture *self, ALCdevice *device); static void ALCwasapiCapture_Destruct(ALCwasapiCapture *self); @@ -1261,32 +1241,18 @@ DEFINE_ALCBACKEND_VTABLE(ALCwasapiCapture); static void ALCwasapiCapture_Construct(ALCwasapiCapture *self, ALCdevice *device) { + new (self) ALCwasapiCapture{}; SET_VTABLE2(ALCwasapiCapture, ALCbackend, self); SET_VTABLE2(ALCwasapiCapture, ALCwasapiProxy, self); ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); ALCwasapiProxy_Construct(STATIC_CAST(ALCwasapiProxy, self)); - - self->devid = nullptr; - - self->mmdev = nullptr; - self->client = nullptr; - self->capture = nullptr; - self->NotifyEvent = nullptr; - - self->MsgEvent = nullptr; - - self->ChannelConv = nullptr; - self->SampleConv = nullptr; - self->Ring = nullptr; - - ATOMIC_INIT(&self->killNow, 0); } static void ALCwasapiCapture_Destruct(ALCwasapiCapture *self) { if(self->MsgEvent) { - ThreadRequest req = { self->MsgEvent, 0 }; + ThreadRequest req{ self->MsgEvent, 0 }; if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) (void)WaitForResponse(&req); @@ -1304,24 +1270,18 @@ static void ALCwasapiCapture_Destruct(ALCwasapiCapture *self) DestroySampleConverter(&self->SampleConv); DestroyChannelConverter(&self->ChannelConv); - free(self->devid); - self->devid = nullptr; - ALCwasapiProxy_Destruct(STATIC_CAST(ALCwasapiProxy, self)); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCwasapiCapture(); } -FORCE_ALIGN int ALCwasapiCapture_recordProc(void *arg) +FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) { - auto self = reinterpret_cast(arg); - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - IAudioCaptureClient *capture = self->capture; - ALfloat *samples = nullptr; - size_t samplesmax = 0; - HRESULT hr; + ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + IAudioCaptureClient *capture{self->capture}; - hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if(FAILED(hr)) { ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); @@ -1333,7 +1293,8 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(void *arg) althrd_setname(althrd_current(), RECORD_THREAD_NAME); - while(!ATOMIC_LOAD(&self->killNow, almemory_order_relaxed)) + std::vector samples; + while(!self->killNow.load(std::memory_order_relaxed)) { UINT32 avail; DWORD res; @@ -1352,25 +1313,17 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(void *arg) ERR("Failed to get capture buffer: 0x%08lx\n", hr); else { - ll_ringbuffer_data_t data[2]; - size_t dstframes = 0; - if(self->ChannelConv) { - if(samplesmax < numsamples) - { - size_t newmax = RoundUp(numsamples, 4096); - void *tmp = al_calloc(DEF_ALIGN, newmax*2*sizeof(ALfloat)); - al_free(samples); - samples = reinterpret_cast(tmp); - samplesmax = newmax; - } - ChannelConverterInput(self->ChannelConv, rdata, samples, numsamples); - rdata = (BYTE*)samples; + samples.resize(numsamples*2); + ChannelConverterInput(self->ChannelConv, rdata, samples.data(), numsamples); + rdata = reinterpret_cast(samples.data()); } + ll_ringbuffer_data_t data[2]; ll_ringbuffer_get_write_vector(self->Ring, data); + size_t dstframes; if(self->SampleConv) { const ALvoid *srcdata = rdata; @@ -1423,10 +1376,6 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(void *arg) ERR("WaitForSingleObjectEx error: 0x%lx\n", res); } - al_free(samples); - samples = nullptr; - samplesmax = 0; - CoUninitialize(); return 0; } @@ -1434,7 +1383,7 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(void *arg) static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *deviceName) { - HRESULT hr = S_OK; + HRESULT hr{S_OK}; self->NotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); self->MsgEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); @@ -1448,39 +1397,38 @@ static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *devi { if(deviceName) { - const DevMap *iter; - - if(VECTOR_SIZE(CaptureDevices) == 0) + if(CaptureDevices.empty()) { - ThreadRequest req = { self->MsgEvent, 0 }; + ThreadRequest req{ self->MsgEvent, 0 }; if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, CAPTURE_DEVICE_PROBE)) (void)WaitForResponse(&req); } hr = E_FAIL; -#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, deviceName) == 0 || \ - alstr_cmp_cstr((i)->endpoint_guid, deviceName) == 0) - VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); -#undef MATCH_NAME - if(iter == VECTOR_END(CaptureDevices)) + auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), + [deviceName](const DevMap &entry) -> bool + { return entry.name == deviceName || entry.endpoint_guid == deviceName; } + ); + if(iter == CaptureDevices.cend()) { int len; if((len=MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, nullptr, 0)) > 0) { std::vector wname(len); MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, wname.data(), len); -#define MATCH_NAME(i) (wcscmp((i)->devid, wname.data()) == 0) - VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); -#undef MATCH_NAME + iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), + [&wname](const DevMap &entry) -> bool + { return entry.devid == wname.data(); } + ); } } - if(iter == VECTOR_END(CaptureDevices)) + if(iter == CaptureDevices.cend()) WARN("Failed to find device name matching \"%s\"\n", deviceName); else { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - self->devid = strdupW(iter->devid); - alstr_copy(&device->DeviceName, iter->name); + self->devid = iter->devid; + alstr_copy_range(&device->DeviceName, &*iter->name.cbegin(), &*iter->name.cend()); hr = S_OK; } } @@ -1488,7 +1436,7 @@ static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *devi if(SUCCEEDED(hr)) { - ThreadRequest req = { self->MsgEvent, 0 }; + ThreadRequest req{ self->MsgEvent, 0 }; hr = E_FAIL; if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) @@ -1506,15 +1454,14 @@ static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *devi CloseHandle(self->MsgEvent); self->MsgEvent = nullptr; - free(self->devid); - self->devid = nullptr; + self->devid.clear(); ERR("Device init failed: 0x%08lx\n", hr); return ALC_INVALID_VALUE; } else { - ThreadRequest req = { self->MsgEvent, 0 }; + ThreadRequest req{ self->MsgEvent, 0 }; hr = E_FAIL; if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) @@ -1535,18 +1482,18 @@ static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *devi static HRESULT ALCwasapiCapture_openProxy(ALCwasapiCapture *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - void *ptr; - HRESULT hr; + ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; - hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, &ptr); + void *ptr; + HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, + IID_IMMDeviceEnumerator, &ptr); if(SUCCEEDED(hr)) { auto Enumerator = reinterpret_cast(ptr); - if(!self->devid) + if(self->devid.empty()) hr = Enumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, &self->mmdev); else - hr = Enumerator->GetDevice(self->devid, &self->mmdev); + hr = Enumerator->GetDevice(self->devid.c_str(), &self->mmdev); Enumerator->Release(); } if(SUCCEEDED(hr)) @@ -1555,7 +1502,11 @@ static HRESULT ALCwasapiCapture_openProxy(ALCwasapiCapture *self) { self->client = reinterpret_cast(ptr); if(alstr_empty(device->DeviceName)) - get_device_name_and_guid(self->mmdev, &device->DeviceName, nullptr); + { + std::string devname; + std::tie(devname, std::ignore) = get_device_name_and_guid(self->mmdev); + alstr_copy_range(&device->DeviceName, &*devname.cbegin(), &*devname.cend()); + } } if(FAILED(hr)) @@ -1583,34 +1534,30 @@ static void ALCwasapiCapture_closeProxy(ALCwasapiCapture *self) static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - WAVEFORMATEXTENSIBLE OutputType; - WAVEFORMATEX *wfx = nullptr; - enum DevFmtType srcType; - REFERENCE_TIME buf_time; - UINT32 buffer_len; - void *ptr = nullptr; - HRESULT hr; + ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; - if(self->client) - self->client->Release(); + IAudioClient *client{self->client}; self->client = nullptr; + if(client) client->Release(); + client = nullptr; - hr = self->mmdev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); + void *ptr; + HRESULT hr{self->mmdev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr)}; if(FAILED(hr)) { ERR("Failed to reactivate audio client: 0x%08lx\n", hr); return hr; } - self->client = reinterpret_cast(ptr); + client = self->client = reinterpret_cast(ptr); - buf_time = ScaleCeil(device->UpdateSize*device->NumUpdates, REFTIME_PER_SEC, - device->Frequency); + REFERENCE_TIME buf_time{ScaleCeil(device->UpdateSize*device->NumUpdates, REFTIME_PER_SEC, + device->Frequency)}; // Make sure buffer is at least 100ms in size buf_time = maxu64(buf_time, REFTIME_PER_SEC/10); device->UpdateSize = (ALuint)ScaleCeil(buf_time, device->Frequency, REFTIME_PER_SEC) / device->NumUpdates; + WAVEFORMATEXTENSIBLE OutputType; OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; switch(device->FmtChans) { @@ -1678,7 +1625,8 @@ static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) OutputType.Format.nBlockAlign; OutputType.Format.cbSize = sizeof(OutputType) - sizeof(OutputType.Format); - hr = self->client->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); + WAVEFORMATEX *wfx; + hr = client->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); if(FAILED(hr)) { ERR("Failed to check format support: 0x%08lx\n", hr); @@ -1711,6 +1659,7 @@ static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) wfx = nullptr; } + enum DevFmtType srcType; if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_PCM)) { if(OutputType.Format.wBitsPerSample == 8) @@ -1785,15 +1734,16 @@ static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) device->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec); } - hr = self->client->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, - buf_time, 0, &OutputType.Format, nullptr); + hr = client->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + buf_time, 0, &OutputType.Format, nullptr); if(FAILED(hr)) { ERR("Failed to initialize audio client: 0x%08lx\n", hr); return hr; } - hr = self->client->GetBufferSize(&buffer_len); + UINT32 buffer_len; + hr = client->GetBufferSize(&buffer_len); if(FAILED(hr)) { ERR("Failed to get buffer size: 0x%08lx\n", hr); @@ -1812,7 +1762,7 @@ static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) return E_OUTOFMEMORY; } - hr = self->client->SetEventHandle(self->NotifyEvent); + hr = client->SetEventHandle(self->NotifyEvent); if(FAILED(hr)) { ERR("Failed to set event handle: 0x%08lx\n", hr); @@ -1825,8 +1775,8 @@ static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) static ALCboolean ALCwasapiCapture_start(ALCwasapiCapture *self) { - ThreadRequest req = { self->MsgEvent, 0 }; - HRESULT hr = E_FAIL; + ThreadRequest req{ self->MsgEvent, 0 }; + HRESULT hr{E_FAIL}; if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) hr = WaitForResponse(&req); @@ -1836,35 +1786,37 @@ static ALCboolean ALCwasapiCapture_start(ALCwasapiCapture *self) static HRESULT ALCwasapiCapture_startProxy(ALCwasapiCapture *self) { - HRESULT hr; - void *ptr; - ResetEvent(self->NotifyEvent); - hr = self->client->Start(); + + IAudioClient *client{self->client}; + HRESULT hr{client->Start()}; if(FAILED(hr)) { ERR("Failed to start audio client: 0x%08lx\n", hr); return hr; } - hr = self->client->GetService(IID_IAudioCaptureClient, &ptr); + void *ptr; + hr = client->GetService(IID_IAudioCaptureClient, &ptr); if(SUCCEEDED(hr)) { self->capture = reinterpret_cast(ptr); - ATOMIC_STORE(&self->killNow, 0, almemory_order_release); - if(althrd_create(&self->thread, ALCwasapiCapture_recordProc, self) != althrd_success) - { - ERR("Failed to start thread\n"); + try { + self->killNow.store(AL_FALSE, std::memory_order_release); + self->thread = std::thread(ALCwasapiCapture_recordProc, self); + } + catch(...) { self->capture->Release(); self->capture = nullptr; + ERR("Failed to start thread\n"); hr = E_FAIL; } } if(FAILED(hr)) { - self->client->Stop(); - self->client->Reset(); + client->Stop(); + client->Reset(); } return hr; @@ -1873,20 +1825,18 @@ static HRESULT ALCwasapiCapture_startProxy(ALCwasapiCapture *self) static void ALCwasapiCapture_stop(ALCwasapiCapture *self) { - ThreadRequest req = { self->MsgEvent, 0 }; + ThreadRequest req{ self->MsgEvent, 0 }; if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) (void)WaitForResponse(&req); } static void ALCwasapiCapture_stopProxy(ALCwasapiCapture *self) { - int res; - - if(!self->capture) + if(!self->capture || !self->thread.joinable()) return; - ATOMIC_STORE_SEQ(&self->killNow, 1); - althrd_join(self->thread, &res); + self->killNow.store(AL_TRUE); + self->thread.join(); self->capture->Release(); self->capture = nullptr; @@ -1895,12 +1845,12 @@ static void ALCwasapiCapture_stopProxy(ALCwasapiCapture *self) } -ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self) +static ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self) { return (ALuint)ll_ringbuffer_read_space(self->Ring); } -ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, ALCuint samples) +static ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, ALCuint samples) { if(ALCwasapiCapture_availableSamples(self) < samples) return ALC_INVALID_VALUE; @@ -1912,7 +1862,7 @@ ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, typedef struct ALCwasapiBackendFactory { DERIVE_FROM_TYPE(ALCbackendFactory); } ALCwasapiBackendFactory; -#define ALCWASAPIBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwasapiBackendFactory, ALCbackendFactory) } } +#define ALCWASAPIBACKENDFACTORY_INITIALIZER { GET_VTABLE2(ALCwasapiBackendFactory, ALCbackendFactory) } static ALCboolean ALCwasapiBackendFactory_init(ALCwasapiBackendFactory *self); static void ALCwasapiBackendFactory_deinit(ALCwasapiBackendFactory *self); @@ -1927,9 +1877,6 @@ static ALCboolean ALCwasapiBackendFactory_init(ALCwasapiBackendFactory* UNUSED(s { static HRESULT InitResult; - VECTOR_INIT(PlaybackDevices); - VECTOR_INIT(CaptureDevices); - if(!ThreadHdl) { ThreadRequest req; @@ -1952,11 +1899,8 @@ static ALCboolean ALCwasapiBackendFactory_init(ALCwasapiBackendFactory* UNUSED(s static void ALCwasapiBackendFactory_deinit(ALCwasapiBackendFactory* UNUSED(self)) { - clear_devlist(&PlaybackDevices); - VECTOR_DEINIT(PlaybackDevices); - - clear_devlist(&CaptureDevices); - VECTOR_DEINIT(CaptureDevices); + PlaybackDevices.clear(); + CaptureDevices.clear(); if(ThreadHdl) { @@ -1976,31 +1920,34 @@ static ALCboolean ALCwasapiBackendFactory_querySupport(ALCwasapiBackendFactory* static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { - ThreadRequest req = { nullptr, 0 }; + ThreadRequest req{ nullptr, 0 }; req.FinishedEvt = CreateEventW(nullptr, FALSE, FALSE, nullptr); if(req.FinishedEvt == nullptr) ERR("Failed to create event: %lu\n", GetLastError()); else { + auto add_device = [outnames](const DevMap &entry) -> void + { + const char *name{entry.name.c_str()}; + size_t namelen{entry.name.length()}; + /* +1 to also append the null char (to ensure a null-separated list + * and double-null terminated list). + */ + alstr_append_range(outnames, name, name + namelen+1); + }; HRESULT hr = E_FAIL; if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, type)) hr = WaitForResponse(&req); if(SUCCEEDED(hr)) switch(type) { -#define APPEND_OUTNAME(e) do { \ - if(!alstr_empty((e)->name)) \ - alstr_append_range(outnames, VECTOR_BEGIN((e)->name), \ - VECTOR_END((e)->name)+1); \ -} while(0) case ALL_DEVICE_PROBE: - VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_OUTNAME); + std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); break; case CAPTURE_DEVICE_PROBE: - VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_OUTNAME); + std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); break; -#undef APPEND_OUTNAME } CloseHandle(req.FinishedEvt); req.FinishedEvt = nullptr; @@ -2030,6 +1977,6 @@ static ALCbackend* ALCwasapiBackendFactory_createBackend(ALCwasapiBackendFactory ALCbackendFactory *ALCwasapiBackendFactory_getFactory(void) { - static ALCwasapiBackendFactory factory = ALCWASAPIBACKENDFACTORY_INITIALIZER; + static ALCwasapiBackendFactory factory{ALCWASAPIBACKENDFACTORY_INITIALIZER}; return STATIC_CAST(ALCbackendFactory, &factory); } -- cgit v1.2.3 From 7307c2d5aa4a5cae73f05451ddbc1c4dcc9fad20 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Nov 2018 21:42:26 -0700 Subject: Workaround some issue with DEFINE_GUID in C++ --- Alc/backends/wasapi.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index d12fbe84..35d67a90 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -54,8 +54,10 @@ #include "backends/base.h" -DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); -DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +extern "C" { +extern const GUID KSDATAFORMAT_SUBTYPE_PCM; +extern const GUID KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; +} // extern "C" DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); -- cgit v1.2.3 From 66df771d96d98acdf7c31d0ca5729b06502ae7d0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Nov 2018 23:52:53 -0700 Subject: Make the polymorphism macros less hacky in C++ In particular, it relies on derived structs using C++-style inheritence. Any implementation's source that's converted to C++ will consequently need to make that change. --- Alc/backends/pulseaudio.cpp | 69 ++--- Alc/backends/wasapi.cpp | 594 +++++++++++++++++++++----------------------- Alc/polymorphism.h | 9 +- 3 files changed, 327 insertions(+), 345 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index b6f7940b..719205c4 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -532,9 +532,7 @@ std::vector CaptureDevices; } // namespace -struct PulsePlayback { - DERIVE_FROM_TYPE(ALCbackend); - +struct PulsePlayback final : public ALCbackend { std::string device_name; pa_buffer_attr attr; @@ -1241,9 +1239,7 @@ static void PulsePlayback_unlock(PulsePlayback *self) } -struct PulseCapture { - DERIVE_FROM_TYPE(ALCbackend); - +struct PulseCapture final : public ALCbackend { std::string device_name; const void *cap_store{nullptr}; @@ -1744,20 +1740,25 @@ static void PulseCapture_unlock(PulseCapture *self) } -typedef struct ALCpulseBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCpulseBackendFactory; -#define ALCPULSEBACKENDFACTORY_INITIALIZER { GET_VTABLE2(ALCpulseBackendFactory, ALCbackendFactory) } +struct PulseBackendFactory final : public ALCbackendFactory { + PulseBackendFactory() noexcept; +}; +#define ALCPULSEBACKENDFACTORY_INITIALIZER GET_VTABLE2(PulseBackendFactory, ALCbackendFactory) + +static ALCboolean PulseBackendFactory_init(PulseBackendFactory *self); +static void PulseBackendFactory_deinit(PulseBackendFactory *self); +static ALCboolean PulseBackendFactory_querySupport(PulseBackendFactory *self, ALCbackend_Type type); +static void PulseBackendFactory_probe(PulseBackendFactory *self, enum DevProbe type, al_string *outnames); +static ALCbackend* PulseBackendFactory_createBackend(PulseBackendFactory *self, ALCdevice *device, ALCbackend_Type type); +DEFINE_ALCBACKENDFACTORY_VTABLE(PulseBackendFactory); -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, al_string *outnames); -static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCpulseBackendFactory); +PulseBackendFactory::PulseBackendFactory() noexcept + : ALCbackendFactory{ALCPULSEBACKENDFACTORY_INITIALIZER} +{ +} -static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory* UNUSED(self)) +static ALCboolean PulseBackendFactory_init(PulseBackendFactory* UNUSED(self)) { ALCboolean ret{ALC_FALSE}; @@ -1797,7 +1798,7 @@ static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory* UNUSED(sel return ret; } -static void ALCpulseBackendFactory_deinit(ALCpulseBackendFactory* UNUSED(self)) +static void PulseBackendFactory_deinit(PulseBackendFactory* UNUSED(self)) { PlaybackDevices.clear(); CaptureDevices.clear(); @@ -1809,14 +1810,14 @@ static void ALCpulseBackendFactory_deinit(ALCpulseBackendFactory* UNUSED(self)) /* PulseAudio doesn't like being CloseLib'd sometimes */ } -static ALCboolean ALCpulseBackendFactory_querySupport(ALCpulseBackendFactory* UNUSED(self), ALCbackend_Type type) +static ALCboolean PulseBackendFactory_querySupport(PulseBackendFactory* UNUSED(self), ALCbackend_Type type) { if(type == ALCbackend_Playback || type == ALCbackend_Capture) return ALC_TRUE; return ALC_FALSE; } -static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +static void PulseBackendFactory_probe(PulseBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { auto add_device = [outnames](const DevMap &entry) -> void { @@ -1841,7 +1842,7 @@ static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), e } } -static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +static ALCbackend* PulseBackendFactory_createBackend(PulseBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) { @@ -1866,40 +1867,44 @@ static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory* #warning "Unsupported API version, backend will be unavailable!" -typedef struct ALCpulseBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCpulseBackendFactory; -#define ALCPULSEBACKENDFACTORY_INITIALIZER { GET_VTABLE2(ALCpulseBackendFactory, ALCbackendFactory) } +struct PulseBackendFactory final : public ALCbackendFactory { + PulseBackendFactory() noexcept; +}; +#define ALCPULSEBACKENDFACTORY_INITIALIZER GET_VTABLE2(PulseBackendFactory, ALCbackendFactory) -static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory* UNUSED(self)) +static ALCboolean PulseBackendFactory_init(PulseBackendFactory* UNUSED(self)) { return ALC_FALSE; } -static void ALCpulseBackendFactory_deinit(ALCpulseBackendFactory* UNUSED(self)) +static void PulseBackendFactory_deinit(PulseBackendFactory* UNUSED(self)) { } -static ALCboolean ALCpulseBackendFactory_querySupport(ALCpulseBackendFactory* UNUSED(self), ALCbackend_Type UNUSED(type)) +static ALCboolean PulseBackendFactory_querySupport(PulseBackendFactory* UNUSED(self), ALCbackend_Type UNUSED(type)) { return ALC_FALSE; } -static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), enum DevProbe UNUSED(type), al_string* UNUSED(outnames)) +static void PulseBackendFactory_probe(PulseBackendFactory* UNUSED(self), enum DevProbe UNUSED(type), al_string* UNUSED(outnames)) { } -static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory* UNUSED(self), ALCdevice* UNUSED(device), ALCbackend_Type UNUSED(type)) +static ALCbackend* PulseBackendFactory_createBackend(PulseBackendFactory* UNUSED(self), ALCdevice* UNUSED(device), ALCbackend_Type UNUSED(type)) { return nullptr; } -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCpulseBackendFactory); +DEFINE_ALCBACKENDFACTORY_VTABLE(PulseBackendFactory); + +PulseBackendFactory::PulseBackendFactory() noexcept + : ALCbackendFactory{ALCPULSEBACKENDFACTORY_INITIALIZER} +{ } #endif /* PA_API_VERSION == 12 */ ALCbackendFactory *ALCpulseBackendFactory_getFactory(void) { - static ALCpulseBackendFactory factory{ALCPULSEBACKENDFACTORY_INITIALIZER}; + static PulseBackendFactory factory{}; return STATIC_CAST(ALCbackendFactory, &factory); } diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 35d67a90..ddb3ced0 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -341,40 +341,16 @@ static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, st /* Proxy interface used by the message handler. */ -struct ALCwasapiProxyVtable; +struct WasapiProxy { + virtual HRESULT openProxy() = 0; + virtual void closeProxy() = 0; -typedef struct ALCwasapiProxy { - const struct ALCwasapiProxyVtable *vtbl; -} ALCwasapiProxy; - -struct ALCwasapiProxyVtable { - HRESULT (*const openProxy)(ALCwasapiProxy*); - void (*const closeProxy)(ALCwasapiProxy*); - - HRESULT (*const resetProxy)(ALCwasapiProxy*); - HRESULT (*const startProxy)(ALCwasapiProxy*); - void (*const stopProxy)(ALCwasapiProxy*); + virtual HRESULT resetProxy() = 0; + virtual HRESULT startProxy() = 0; + virtual void stopProxy() = 0; }; -#define DEFINE_ALCWASAPIPROXY_VTABLE(T) \ -DECLARE_THUNK(T, ALCwasapiProxy, HRESULT, openProxy) \ -DECLARE_THUNK(T, ALCwasapiProxy, void, closeProxy) \ -DECLARE_THUNK(T, ALCwasapiProxy, HRESULT, resetProxy) \ -DECLARE_THUNK(T, ALCwasapiProxy, HRESULT, startProxy) \ -DECLARE_THUNK(T, ALCwasapiProxy, void, stopProxy) \ - \ -static const struct ALCwasapiProxyVtable T##_ALCwasapiProxy_vtable = { \ - T##_ALCwasapiProxy_openProxy, \ - T##_ALCwasapiProxy_closeProxy, \ - T##_ALCwasapiProxy_resetProxy, \ - T##_ALCwasapiProxy_startProxy, \ - T##_ALCwasapiProxy_stopProxy, \ -} - -static void ALCwasapiProxy_Construct(ALCwasapiProxy* UNUSED(self)) { } -static void ALCwasapiProxy_Destruct(ALCwasapiProxy* UNUSED(self)) { } - -static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) +static DWORD CALLBACK WasapiProxy_messageHandler(void *ptr) { auto req = reinterpret_cast(ptr); @@ -423,18 +399,18 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) msg.message, (void*)msg.lParam, (void*)msg.wParam ); - ALCwasapiProxy *proxy{nullptr}; + WasapiProxy *proxy{nullptr}; switch(msg.message) { case WM_USER_OpenDevice: req = reinterpret_cast(msg.wParam); - proxy = reinterpret_cast(msg.lParam); + proxy = reinterpret_cast(msg.lParam); hr = cohr = S_OK; if(++deviceCount == 1) hr = cohr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if(SUCCEEDED(hr)) - hr = V0(proxy,openProxy)(); + hr = proxy->openProxy(); if(FAILED(hr)) { if(--deviceCount == 0 && SUCCEEDED(cohr)) @@ -446,33 +422,33 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) case WM_USER_ResetDevice: req = reinterpret_cast(msg.wParam); - proxy = reinterpret_cast(msg.lParam); + proxy = reinterpret_cast(msg.lParam); - hr = V0(proxy,resetProxy)(); + hr = proxy->resetProxy(); ReturnMsgResponse(req, hr); continue; case WM_USER_StartDevice: req = reinterpret_cast(msg.wParam); - proxy = reinterpret_cast(msg.lParam); + proxy = reinterpret_cast(msg.lParam); - hr = V0(proxy,startProxy)(); + hr = proxy->startProxy(); ReturnMsgResponse(req, hr); continue; case WM_USER_StopDevice: req = reinterpret_cast(msg.wParam); - proxy = reinterpret_cast(msg.lParam); + proxy = reinterpret_cast(msg.lParam); - V0(proxy,stopProxy)(); + proxy->stopProxy(); ReturnMsgResponse(req, S_OK); continue; case WM_USER_CloseDevice: req = reinterpret_cast(msg.wParam); - proxy = reinterpret_cast(msg.lParam); + proxy = reinterpret_cast(msg.lParam); - V0(proxy,closeProxy)(); + proxy->closeProxy(); if(--deviceCount == 0) CoUninitialize(); @@ -517,38 +493,37 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) } -typedef struct ALCwasapiPlayback { - DERIVE_FROM_TYPE(ALCbackend); - DERIVE_FROM_TYPE(ALCwasapiProxy); +struct ALCwasapiPlayback final : public ALCbackend, WasapiProxy { + HRESULT openProxy() override; + void closeProxy() override; - std::wstring devid; + HRESULT resetProxy() override; + HRESULT startProxy() override; + void stopProxy() override; + + std::wstring mDevId; - IMMDevice *mmdev{nullptr}; - IAudioClient *client{nullptr}; - IAudioRenderClient *render{nullptr}; - HANDLE NotifyEvent{nullptr}; + IMMDevice *mMMDev{nullptr}; + IAudioClient *mClient{nullptr}; + IAudioRenderClient *mRender{nullptr}; + HANDLE mNotifyEvent{nullptr}; - HANDLE MsgEvent{nullptr}; + HANDLE mMsgEvent{nullptr}; - std::atomic Padding{0u}; + std::atomic mPadding{0u}; - std::atomic killNow{AL_TRUE}; - std::thread thread; -} ALCwasapiPlayback; + std::atomic mKillNow{AL_TRUE}; + std::thread mThread; +}; static int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self); static void ALCwasapiPlayback_Construct(ALCwasapiPlayback *self, ALCdevice *device); static void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self); static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *name); -static HRESULT ALCwasapiPlayback_openProxy(ALCwasapiPlayback *self); -static void ALCwasapiPlayback_closeProxy(ALCwasapiPlayback *self); static ALCboolean ALCwasapiPlayback_reset(ALCwasapiPlayback *self); -static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self); static ALCboolean ALCwasapiPlayback_start(ALCwasapiPlayback *self); -static HRESULT ALCwasapiPlayback_startProxy(ALCwasapiPlayback *self); static void ALCwasapiPlayback_stop(ALCwasapiPlayback *self); -static void ALCwasapiPlayback_stopProxy(ALCwasapiPlayback *self); static DECLARE_FORWARD2(ALCwasapiPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) static DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, ALCuint, availableSamples) static ClockLatency ALCwasapiPlayback_getClockLatency(ALCwasapiPlayback *self); @@ -556,7 +531,6 @@ static DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, void, lock) static DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCwasapiPlayback) -DEFINE_ALCWASAPIPROXY_VTABLE(ALCwasapiPlayback); DEFINE_ALCBACKEND_VTABLE(ALCwasapiPlayback); @@ -564,35 +538,29 @@ static void ALCwasapiPlayback_Construct(ALCwasapiPlayback *self, ALCdevice *devi { new (self) ALCwasapiPlayback{}; SET_VTABLE2(ALCwasapiPlayback, ALCbackend, self); - SET_VTABLE2(ALCwasapiPlayback, ALCwasapiProxy, self); ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - ALCwasapiProxy_Construct(STATIC_CAST(ALCwasapiProxy, self)); } static void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self) { - if(self->MsgEvent) + if(self->mMsgEvent) { - ThreadRequest req = { self->MsgEvent, 0 }; - if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + ThreadRequest req = { self->mMsgEvent, 0 }; + auto proxy = static_cast(self); + if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)proxy)) (void)WaitForResponse(&req); - CloseHandle(self->MsgEvent); - self->MsgEvent = nullptr; + CloseHandle(self->mMsgEvent); + self->mMsgEvent = nullptr; } - if(self->NotifyEvent) - CloseHandle(self->NotifyEvent); - self->NotifyEvent = nullptr; + if(self->mNotifyEvent != nullptr) + CloseHandle(self->mNotifyEvent); + self->mNotifyEvent = nullptr; + if(self->mMsgEvent != nullptr) + CloseHandle(self->mMsgEvent); + self->mMsgEvent = nullptr; - if(self->NotifyEvent != nullptr) - CloseHandle(self->NotifyEvent); - self->NotifyEvent = nullptr; - if(self->MsgEvent != nullptr) - CloseHandle(self->MsgEvent); - self->MsgEvent = nullptr; - - ALCwasapiProxy_Destruct(STATIC_CAST(ALCwasapiProxy, self)); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCwasapiPlayback(); } @@ -601,8 +569,8 @@ static void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self) FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self) { ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; - IAudioClient *client{self->client}; - IAudioRenderClient *render{self->render}; + IAudioClient *client{self->mClient}; + IAudioRenderClient *render{self->mRender}; HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if(FAILED(hr)) @@ -619,7 +587,7 @@ FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self) ALuint update_size{device->UpdateSize}; UINT32 buffer_len{update_size * device->NumUpdates}; - while(!self->killNow.load(std::memory_order_relaxed)) + while(!self->mKillNow.load(std::memory_order_relaxed)) { UINT32 written; hr = client->GetCurrentPadding(&written); @@ -631,13 +599,13 @@ FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self) V0(device->Backend,unlock)(); break; } - self->Padding.store(written, std::memory_order_relaxed); + self->mPadding.store(written, std::memory_order_relaxed); ALuint len{buffer_len - written}; if(len < update_size) { DWORD res; - res = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE); + res = WaitForSingleObjectEx(self->mNotifyEvent, 2000, FALSE); if(res != WAIT_OBJECT_0) ERR("WaitForSingleObjectEx error: 0x%lx\n", res); continue; @@ -650,7 +618,7 @@ FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self) { ALCwasapiPlayback_lock(self); aluMixData(device, buffer, len); - self->Padding.store(written + len, std::memory_order_relaxed); + self->mPadding.store(written + len, std::memory_order_relaxed); ALCwasapiPlayback_unlock(self); hr = render->ReleaseBuffer(len, 0); } @@ -663,7 +631,7 @@ FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self) break; } } - self->Padding.store(0u, std::memory_order_release); + self->mPadding.store(0u, std::memory_order_release); CoUninitialize(); return 0; @@ -713,9 +681,9 @@ static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *de { HRESULT hr = S_OK; - self->NotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - self->MsgEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - if(self->NotifyEvent == nullptr || self->MsgEvent == nullptr) + self->mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + self->mMsgEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + if(self->mNotifyEvent == nullptr || self->mMsgEvent == nullptr) { ERR("Failed to create message events: %lu\n", GetLastError()); hr = E_FAIL; @@ -727,7 +695,7 @@ static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *de { if(PlaybackDevices.empty()) { - ThreadRequest req = { self->MsgEvent, 0 }; + ThreadRequest req = { self->mMsgEvent, 0 }; if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, ALL_DEVICE_PROBE)) (void)WaitForResponse(&req); } @@ -755,7 +723,7 @@ static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *de else { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - self->devid = iter->devid; + self->mDevId = iter->devid; alstr_copy_range(&device->DeviceName, &*iter->name.cbegin(), &*iter->name.cend()); hr = S_OK; } @@ -764,10 +732,11 @@ static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *de if(SUCCEEDED(hr)) { - ThreadRequest req{ self->MsgEvent, 0 }; + ThreadRequest req{ self->mMsgEvent, 0 }; + auto proxy = static_cast(self); hr = E_FAIL; - if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)proxy)) hr = WaitForResponse(&req); else ERR("Failed to post thread message: %lu\n", GetLastError()); @@ -775,14 +744,14 @@ static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *de if(FAILED(hr)) { - if(self->NotifyEvent != nullptr) - CloseHandle(self->NotifyEvent); - self->NotifyEvent = nullptr; - if(self->MsgEvent != nullptr) - CloseHandle(self->MsgEvent); - self->MsgEvent = nullptr; + if(self->mNotifyEvent != nullptr) + CloseHandle(self->mNotifyEvent); + self->mNotifyEvent = nullptr; + if(self->mMsgEvent != nullptr) + CloseHandle(self->mMsgEvent); + self->mMsgEvent = nullptr; - self->devid.clear(); + self->mDevId.clear(); ERR("Device init failed: 0x%08lx\n", hr); return ALC_INVALID_VALUE; @@ -791,99 +760,94 @@ static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *de return ALC_NO_ERROR; } -static HRESULT ALCwasapiPlayback_openProxy(ALCwasapiPlayback *self) +HRESULT ALCwasapiPlayback::openProxy() { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - void *ptr; - HRESULT hr; + ALCdevice *device = STATIC_CAST(ALCbackend, this)->mDevice; - hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, &ptr); + void *ptr; + HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, &ptr); if(SUCCEEDED(hr)) { auto Enumerator = reinterpret_cast(ptr); - if(self->devid.empty()) - hr = Enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &self->mmdev); + if(mDevId.empty()) + hr = Enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &mMMDev); else - hr = Enumerator->GetDevice(self->devid.c_str(), &self->mmdev); + hr = Enumerator->GetDevice(mDevId.c_str(), &mMMDev); Enumerator->Release(); } if(SUCCEEDED(hr)) - hr = self->mmdev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); + hr = mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); if(SUCCEEDED(hr)) { - self->client = reinterpret_cast(ptr); + mClient = reinterpret_cast(ptr); if(alstr_empty(device->DeviceName)) { std::string devname; - std::tie(devname, std::ignore) = get_device_name_and_guid(self->mmdev); + std::tie(devname, std::ignore) = get_device_name_and_guid(mMMDev); alstr_copy_range(&device->DeviceName, &*devname.cbegin(), &*devname.cend()); } } if(FAILED(hr)) { - if(self->mmdev) - self->mmdev->Release(); - self->mmdev = nullptr; + if(mMMDev) + mMMDev->Release(); + mMMDev = nullptr; } return hr; } - -static void ALCwasapiPlayback_closeProxy(ALCwasapiPlayback *self) +void ALCwasapiPlayback::closeProxy() { - if(self->client) - self->client->Release(); - self->client = nullptr; + if(mClient) + mClient->Release(); + mClient = nullptr; - if(self->mmdev) - self->mmdev->Release(); - self->mmdev = nullptr; + if(mMMDev) + mMMDev->Release(); + mMMDev = nullptr; } static ALCboolean ALCwasapiPlayback_reset(ALCwasapiPlayback *self) { - ThreadRequest req{ self->MsgEvent, 0 }; + ThreadRequest req{ self->mMsgEvent, 0 }; HRESULT hr{E_FAIL}; - if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + auto proxy = static_cast(self); + if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)proxy)) hr = WaitForResponse(&req); return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; } -static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self) +HRESULT ALCwasapiPlayback::resetProxy() { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - EndpointFormFactor formfactor = UnknownFormFactor; - WAVEFORMATEXTENSIBLE OutputType; - WAVEFORMATEX *wfx = nullptr; - REFERENCE_TIME min_per, buf_time; - UINT32 buffer_len, min_len; - void *ptr = nullptr; - HRESULT hr; + ALCdevice *device{STATIC_CAST(ALCbackend, this)->mDevice}; - if(self->client) - self->client->Release(); - self->client = nullptr; + if(mClient) + mClient->Release(); + mClient = nullptr; - hr = self->mmdev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); + void *ptr; + HRESULT hr = mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); if(FAILED(hr)) { ERR("Failed to reactivate audio client: 0x%08lx\n", hr); return hr; } - self->client = reinterpret_cast(ptr); + mClient = reinterpret_cast(ptr); - hr = self->client->GetMixFormat(&wfx); + WAVEFORMATEX *wfx; + hr = mClient->GetMixFormat(&wfx); if(FAILED(hr)) { ERR("Failed to get mix format: 0x%08lx\n", hr); return hr; } + WAVEFORMATEXTENSIBLE OutputType; if(!MakeExtensible(&OutputType, wfx)) { CoTaskMemFree(wfx); @@ -892,8 +856,8 @@ static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self) CoTaskMemFree(wfx); wfx = nullptr; - buf_time = ScaleCeil(device->UpdateSize*device->NumUpdates, REFTIME_PER_SEC, - device->Frequency); + REFERENCE_TIME buf_time{ScaleCeil(device->UpdateSize*device->NumUpdates, REFTIME_PER_SEC, + device->Frequency)}; if(!(device->Flags&DEVICE_FREQUENCY_REQUEST)) device->Frequency = OutputType.Format.nSamplesPerSec; @@ -990,11 +954,11 @@ static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self) OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * OutputType.Format.nBlockAlign; - hr = self->client->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); + hr = mClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); if(FAILED(hr)) { ERR("Failed to check format support: 0x%08lx\n", hr); - hr = self->client->GetMixFormat(&wfx); + hr = mClient->GetMixFormat(&wfx); } if(FAILED(hr)) { @@ -1063,29 +1027,33 @@ static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self) } OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; } - get_device_formfactor(self->mmdev, &formfactor); + + EndpointFormFactor formfactor = UnknownFormFactor; + get_device_formfactor(mMMDev, &formfactor); device->IsHeadphones = (device->FmtChans == DevFmtStereo && (formfactor == Headphones || formfactor == Headset) ); SetDefaultWFXChannelOrder(device); - hr = self->client->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, - buf_time, 0, &OutputType.Format, nullptr); + hr = mClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + buf_time, 0, &OutputType.Format, nullptr); if(FAILED(hr)) { ERR("Failed to initialize audio client: 0x%08lx\n", hr); return hr; } - hr = self->client->GetDevicePeriod(&min_per, nullptr); + UINT32 buffer_len, min_len; + REFERENCE_TIME min_per; + hr = mClient->GetDevicePeriod(&min_per, nullptr); if(SUCCEEDED(hr)) { min_len = (UINT32)ScaleCeil(min_per, device->Frequency, REFTIME_PER_SEC); /* 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 = self->client->GetBufferSize(&buffer_len); + hr = mClient->GetBufferSize(&buffer_len); } if(FAILED(hr)) { @@ -1102,7 +1070,7 @@ static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self) device->UpdateSize = buffer_len / device->NumUpdates; } - hr = self->client->SetEventHandle(self->NotifyEvent); + hr = mClient->SetEventHandle(mNotifyEvent); if(FAILED(hr)) { ERR("Failed to set event handle: 0x%08lx\n", hr); @@ -1115,46 +1083,46 @@ static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self) static ALCboolean ALCwasapiPlayback_start(ALCwasapiPlayback *self) { - ThreadRequest req{ self->MsgEvent, 0 }; + ThreadRequest req{ self->mMsgEvent, 0 }; HRESULT hr{E_FAIL}; - if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + auto proxy = static_cast(self); + if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)proxy)) hr = WaitForResponse(&req); return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; } -static HRESULT ALCwasapiPlayback_startProxy(ALCwasapiPlayback *self) +HRESULT ALCwasapiPlayback::startProxy() { - HRESULT hr; - void *ptr; + ResetEvent(mNotifyEvent); - ResetEvent(self->NotifyEvent); - hr = self->client->Start(); + HRESULT hr = mClient->Start(); if(FAILED(hr)) { ERR("Failed to start audio client: 0x%08lx\n", hr); return hr; } - hr = self->client->GetService(IID_IAudioRenderClient, &ptr); + void *ptr; + hr = mClient->GetService(IID_IAudioRenderClient, &ptr); if(SUCCEEDED(hr)) { - self->render = reinterpret_cast(ptr); + mRender = reinterpret_cast(ptr); try { - self->killNow.store(AL_FALSE, std::memory_order_release); - self->thread = std::thread(ALCwasapiPlayback_mixerProc, self); + mKillNow.store(AL_FALSE, std::memory_order_release); + mThread = std::thread(ALCwasapiPlayback_mixerProc, this); } catch(...) { - self->render->Release(); - self->render = nullptr; + mRender->Release(); + mRender = nullptr; ERR("Failed to start thread\n"); hr = E_FAIL; } } if(FAILED(hr)) - self->client->Stop(); + mClient->Stop(); return hr; } @@ -1162,33 +1130,34 @@ static HRESULT ALCwasapiPlayback_startProxy(ALCwasapiPlayback *self) static void ALCwasapiPlayback_stop(ALCwasapiPlayback *self) { - ThreadRequest req{ self->MsgEvent, 0 }; - if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + ThreadRequest req{ self->mMsgEvent, 0 }; + auto proxy = static_cast(self); + if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)proxy)) (void)WaitForResponse(&req); } -static void ALCwasapiPlayback_stopProxy(ALCwasapiPlayback *self) +void ALCwasapiPlayback::stopProxy() { - if(!self->render || !self->thread.joinable()) + if(!mRender || !mThread.joinable()) return; - self->killNow.store(AL_TRUE); - self->thread.join(); + mKillNow.store(AL_TRUE); + mThread.join(); - self->render->Release(); - self->render = nullptr; - self->client->Stop(); + mRender->Release(); + mRender = nullptr; + mClient->Stop(); } static ClockLatency ALCwasapiPlayback_getClockLatency(ALCwasapiPlayback *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; ClockLatency ret; ALCwasapiPlayback_lock(self); + ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = self->Padding.load(std::memory_order_relaxed) * DEVICE_CLOCK_RES / + ret.Latency = self->mPadding.load(std::memory_order_relaxed) * DEVICE_CLOCK_RES / device->Frequency; ALCwasapiPlayback_unlock(self); @@ -1196,40 +1165,39 @@ static ClockLatency ALCwasapiPlayback_getClockLatency(ALCwasapiPlayback *self) } -typedef struct ALCwasapiCapture { - DERIVE_FROM_TYPE(ALCbackend); - DERIVE_FROM_TYPE(ALCwasapiProxy); +struct ALCwasapiCapture final : public ALCbackend, WasapiProxy { + HRESULT openProxy() override; + void closeProxy() override; - std::wstring devid; + HRESULT resetProxy() override; + HRESULT startProxy() override; + void stopProxy() override; + + std::wstring mDevId; - IMMDevice *mmdev{nullptr}; - IAudioClient *client{nullptr}; - IAudioCaptureClient *capture{nullptr}; - HANDLE NotifyEvent{nullptr}; + IMMDevice *mMMDev{nullptr}; + IAudioClient *mClient{nullptr}; + IAudioCaptureClient *mCapture{nullptr}; + HANDLE mNotifyEvent{nullptr}; - HANDLE MsgEvent{nullptr}; + HANDLE mMsgEvent{nullptr}; - ChannelConverter *ChannelConv{nullptr}; - SampleConverter *SampleConv{nullptr}; - ll_ringbuffer_t *Ring{nullptr}; + ChannelConverter *mChannelConv{nullptr}; + SampleConverter *mSampleConv{nullptr}; + ll_ringbuffer_t *mRing{nullptr}; - std::atomic killNow{AL_TRUE}; - std::thread thread; -} ALCwasapiCapture; + std::atomic mKillNow{AL_TRUE}; + std::thread mThread; +}; static int ALCwasapiCapture_recordProc(ALCwasapiCapture *self); static void ALCwasapiCapture_Construct(ALCwasapiCapture *self, ALCdevice *device); static void ALCwasapiCapture_Destruct(ALCwasapiCapture *self); static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *name); -static HRESULT ALCwasapiCapture_openProxy(ALCwasapiCapture *self); -static void ALCwasapiCapture_closeProxy(ALCwasapiCapture *self); static DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, ALCboolean, reset) -static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self); static ALCboolean ALCwasapiCapture_start(ALCwasapiCapture *self); -static HRESULT ALCwasapiCapture_startProxy(ALCwasapiCapture *self); static void ALCwasapiCapture_stop(ALCwasapiCapture *self); -static void ALCwasapiCapture_stopProxy(ALCwasapiCapture *self); static ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, ALCuint samples); static ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self); static DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, ClockLatency, getClockLatency) @@ -1237,7 +1205,6 @@ static DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, void, lock) static DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCwasapiCapture) -DEFINE_ALCWASAPIPROXY_VTABLE(ALCwasapiCapture); DEFINE_ALCBACKEND_VTABLE(ALCwasapiCapture); @@ -1245,34 +1212,32 @@ static void ALCwasapiCapture_Construct(ALCwasapiCapture *self, ALCdevice *device { new (self) ALCwasapiCapture{}; SET_VTABLE2(ALCwasapiCapture, ALCbackend, self); - SET_VTABLE2(ALCwasapiCapture, ALCwasapiProxy, self); ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - ALCwasapiProxy_Construct(STATIC_CAST(ALCwasapiProxy, self)); } static void ALCwasapiCapture_Destruct(ALCwasapiCapture *self) { - if(self->MsgEvent) + if(self->mMsgEvent) { - ThreadRequest req{ self->MsgEvent, 0 }; - if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + ThreadRequest req{ self->mMsgEvent, 0 }; + auto proxy = static_cast(self); + if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)proxy)) (void)WaitForResponse(&req); - CloseHandle(self->MsgEvent); - self->MsgEvent = nullptr; + CloseHandle(self->mMsgEvent); + self->mMsgEvent = nullptr; } - if(self->NotifyEvent != nullptr) - CloseHandle(self->NotifyEvent); - self->NotifyEvent = nullptr; + if(self->mNotifyEvent != nullptr) + CloseHandle(self->mNotifyEvent); + self->mNotifyEvent = nullptr; - ll_ringbuffer_free(self->Ring); - self->Ring = nullptr; + ll_ringbuffer_free(self->mRing); + self->mRing = nullptr; - DestroySampleConverter(&self->SampleConv); - DestroyChannelConverter(&self->ChannelConv); + DestroySampleConverter(&self->mSampleConv); + DestroyChannelConverter(&self->mChannelConv); - ALCwasapiProxy_Destruct(STATIC_CAST(ALCwasapiProxy, self)); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCwasapiCapture(); } @@ -1281,7 +1246,7 @@ static void ALCwasapiCapture_Destruct(ALCwasapiCapture *self) FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) { ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; - IAudioCaptureClient *capture{self->capture}; + IAudioCaptureClient *capture{self->mCapture}; HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if(FAILED(hr)) @@ -1296,7 +1261,7 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) althrd_setname(althrd_current(), RECORD_THREAD_NAME); std::vector samples; - while(!self->killNow.load(std::memory_order_relaxed)) + while(!self->mKillNow.load(std::memory_order_relaxed)) { UINT32 avail; DWORD res; @@ -1315,23 +1280,23 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) ERR("Failed to get capture buffer: 0x%08lx\n", hr); else { - if(self->ChannelConv) + if(self->mChannelConv) { samples.resize(numsamples*2); - ChannelConverterInput(self->ChannelConv, rdata, samples.data(), numsamples); + ChannelConverterInput(self->mChannelConv, rdata, samples.data(), numsamples); rdata = reinterpret_cast(samples.data()); } ll_ringbuffer_data_t data[2]; - ll_ringbuffer_get_write_vector(self->Ring, data); + ll_ringbuffer_get_write_vector(self->mRing, data); size_t dstframes; - if(self->SampleConv) + if(self->mSampleConv) { const ALvoid *srcdata = rdata; ALsizei srcframes = numsamples; - dstframes = SampleConverterInput(self->SampleConv, + dstframes = SampleConverterInput(self->mSampleConv, &srcdata, &srcframes, data[0].buf, (ALsizei)minz(data[0].len, INT_MAX) ); if(srcframes > 0 && dstframes == data[0].len && data[1].len > 0) @@ -1340,7 +1305,7 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) * block was filled, and there's space in the second * dest block, do another run for the second block. */ - dstframes += SampleConverterInput(self->SampleConv, + dstframes += SampleConverterInput(self->mSampleConv, &srcdata, &srcframes, data[1].buf, (ALsizei)minz(data[1].len, INT_MAX) ); } @@ -1358,7 +1323,7 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) dstframes = len1 + len2; } - ll_ringbuffer_write_advance(self->Ring, dstframes); + ll_ringbuffer_write_advance(self->mRing, dstframes); hr = capture->ReleaseBuffer(numsamples); if(FAILED(hr)) ERR("Failed to release capture buffer: 0x%08lx\n", hr); @@ -1373,7 +1338,7 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) break; } - res = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE); + res = WaitForSingleObjectEx(self->mNotifyEvent, 2000, FALSE); if(res != WAIT_OBJECT_0) ERR("WaitForSingleObjectEx error: 0x%lx\n", res); } @@ -1387,9 +1352,9 @@ static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *devi { HRESULT hr{S_OK}; - self->NotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - self->MsgEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - if(self->NotifyEvent == nullptr || self->MsgEvent == nullptr) + self->mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + self->mMsgEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + if(self->mNotifyEvent == nullptr || self->mMsgEvent == nullptr) { ERR("Failed to create message events: %lu\n", GetLastError()); hr = E_FAIL; @@ -1401,7 +1366,7 @@ static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *devi { if(CaptureDevices.empty()) { - ThreadRequest req{ self->MsgEvent, 0 }; + ThreadRequest req{ self->mMsgEvent, 0 }; if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, CAPTURE_DEVICE_PROBE)) (void)WaitForResponse(&req); } @@ -1429,7 +1394,7 @@ static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *devi else { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - self->devid = iter->devid; + self->mDevId = iter->devid; alstr_copy_range(&device->DeviceName, &*iter->name.cbegin(), &*iter->name.cend()); hr = S_OK; } @@ -1438,10 +1403,11 @@ static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *devi if(SUCCEEDED(hr)) { - ThreadRequest req{ self->MsgEvent, 0 }; + ThreadRequest req{ self->mMsgEvent, 0 }; hr = E_FAIL; - if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + auto proxy = static_cast(self); + if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)proxy)) hr = WaitForResponse(&req); else ERR("Failed to post thread message: %lu\n", GetLastError()); @@ -1449,24 +1415,25 @@ static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *devi if(FAILED(hr)) { - if(self->NotifyEvent != nullptr) - CloseHandle(self->NotifyEvent); - self->NotifyEvent = nullptr; - if(self->MsgEvent != nullptr) - CloseHandle(self->MsgEvent); - self->MsgEvent = nullptr; + if(self->mNotifyEvent != nullptr) + CloseHandle(self->mNotifyEvent); + self->mNotifyEvent = nullptr; + if(self->mMsgEvent != nullptr) + CloseHandle(self->mMsgEvent); + self->mMsgEvent = nullptr; - self->devid.clear(); + self->mDevId.clear(); ERR("Device init failed: 0x%08lx\n", hr); return ALC_INVALID_VALUE; } else { - ThreadRequest req{ self->MsgEvent, 0 }; + ThreadRequest req{ self->mMsgEvent, 0 }; hr = E_FAIL; - if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + auto proxy = static_cast(self); + if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)proxy)) hr = WaitForResponse(&req); else ERR("Failed to post thread message: %lu\n", GetLastError()); @@ -1482,9 +1449,9 @@ static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *devi return ALC_NO_ERROR; } -static HRESULT ALCwasapiCapture_openProxy(ALCwasapiCapture *self) +HRESULT ALCwasapiCapture::openProxy() { - ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + ALCdevice *device{STATIC_CAST(ALCbackend, this)->mDevice}; void *ptr; HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, @@ -1492,65 +1459,62 @@ static HRESULT ALCwasapiCapture_openProxy(ALCwasapiCapture *self) if(SUCCEEDED(hr)) { auto Enumerator = reinterpret_cast(ptr); - if(self->devid.empty()) - hr = Enumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, &self->mmdev); + if(mDevId.empty()) + hr = Enumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, &mMMDev); else - hr = Enumerator->GetDevice(self->devid.c_str(), &self->mmdev); + hr = Enumerator->GetDevice(mDevId.c_str(), &mMMDev); Enumerator->Release(); } if(SUCCEEDED(hr)) - hr = self->mmdev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); + hr = mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); if(SUCCEEDED(hr)) { - self->client = reinterpret_cast(ptr); + mClient = reinterpret_cast(ptr); if(alstr_empty(device->DeviceName)) { std::string devname; - std::tie(devname, std::ignore) = get_device_name_and_guid(self->mmdev); + std::tie(devname, std::ignore) = get_device_name_and_guid(mMMDev); alstr_copy_range(&device->DeviceName, &*devname.cbegin(), &*devname.cend()); } } if(FAILED(hr)) { - if(self->mmdev) - self->mmdev->Release(); - self->mmdev = nullptr; + if(mMMDev) + mMMDev->Release(); + mMMDev = nullptr; } return hr; } - -static void ALCwasapiCapture_closeProxy(ALCwasapiCapture *self) +void ALCwasapiCapture::closeProxy() { - if(self->client) - self->client->Release(); - self->client = nullptr; + if(mClient) + mClient->Release(); + mClient = nullptr; - if(self->mmdev) - self->mmdev->Release(); - self->mmdev = nullptr; + if(mMMDev) + mMMDev->Release(); + mMMDev = nullptr; } - -static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) +HRESULT ALCwasapiCapture::resetProxy() { - ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + ALCdevice *device{STATIC_CAST(ALCbackend, this)->mDevice}; - IAudioClient *client{self->client}; - self->client = nullptr; - if(client) client->Release(); - client = nullptr; + if(mClient) + mClient->Release(); + mClient = nullptr; void *ptr; - HRESULT hr{self->mmdev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr)}; + HRESULT hr{mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr)}; if(FAILED(hr)) { ERR("Failed to reactivate audio client: 0x%08lx\n", hr); return hr; } - client = self->client = reinterpret_cast(ptr); + mClient = reinterpret_cast(ptr); REFERENCE_TIME buf_time{ScaleCeil(device->UpdateSize*device->NumUpdates, REFTIME_PER_SEC, device->Frequency)}; @@ -1628,15 +1592,15 @@ static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) OutputType.Format.cbSize = sizeof(OutputType) - sizeof(OutputType.Format); WAVEFORMATEX *wfx; - hr = client->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); + hr = mClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); if(FAILED(hr)) { ERR("Failed to check format support: 0x%08lx\n", hr); return hr; } - DestroySampleConverter(&self->SampleConv); - DestroyChannelConverter(&self->ChannelConv); + DestroySampleConverter(&mSampleConv); + DestroyChannelConverter(&mChannelConv); if(wfx != nullptr) { @@ -1694,8 +1658,8 @@ static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) if(device->FmtChans == DevFmtMono && OutputType.Format.nChannels == 2) { - self->ChannelConv = CreateChannelConverter(srcType, DevFmtStereo, device->FmtChans); - if(!self->ChannelConv) + mChannelConv = CreateChannelConverter(srcType, DevFmtStereo, device->FmtChans); + if(!mChannelConv) { ERR("Failed to create %s stereo-to-mono converter\n", DevFmtTypeString(srcType)); return E_FAIL; @@ -1708,8 +1672,8 @@ static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) } else if(device->FmtChans == DevFmtStereo && OutputType.Format.nChannels == 1) { - self->ChannelConv = CreateChannelConverter(srcType, DevFmtMono, device->FmtChans); - if(!self->ChannelConv) + mChannelConv = CreateChannelConverter(srcType, DevFmtMono, device->FmtChans); + if(!mChannelConv) { ERR("Failed to create %s mono-to-stereo converter\n", DevFmtTypeString(srcType)); return E_FAIL; @@ -1720,11 +1684,11 @@ static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) if(device->Frequency != OutputType.Format.nSamplesPerSec || device->FmtType != srcType) { - self->SampleConv = CreateSampleConverter( + mSampleConv = CreateSampleConverter( srcType, device->FmtType, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder), OutputType.Format.nSamplesPerSec, device->Frequency ); - if(!self->SampleConv) + if(!mSampleConv) { ERR("Failed to create converter for %s format, dst: %s %uhz, src: %s %luhz\n", DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), @@ -1736,8 +1700,8 @@ static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) device->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec); } - hr = client->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, - buf_time, 0, &OutputType.Format, nullptr); + hr = mClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + buf_time, 0, &OutputType.Format, nullptr); if(FAILED(hr)) { ERR("Failed to initialize audio client: 0x%08lx\n", hr); @@ -1745,7 +1709,7 @@ static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) } UINT32 buffer_len; - hr = client->GetBufferSize(&buffer_len); + hr = mClient->GetBufferSize(&buffer_len); if(FAILED(hr)) { ERR("Failed to get buffer size: 0x%08lx\n", hr); @@ -1753,18 +1717,18 @@ static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) } buffer_len = maxu(device->UpdateSize*device->NumUpdates, buffer_len); - ll_ringbuffer_free(self->Ring); - self->Ring = ll_ringbuffer_create(buffer_len, + ll_ringbuffer_free(mRing); + mRing = ll_ringbuffer_create(buffer_len, FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), false ); - if(!self->Ring) + if(!mRing) { ERR("Failed to allocate capture ring buffer\n"); return E_OUTOFMEMORY; } - hr = client->SetEventHandle(self->NotifyEvent); + hr = mClient->SetEventHandle(mNotifyEvent); if(FAILED(hr)) { ERR("Failed to set event handle: 0x%08lx\n", hr); @@ -1777,21 +1741,21 @@ static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) static ALCboolean ALCwasapiCapture_start(ALCwasapiCapture *self) { - ThreadRequest req{ self->MsgEvent, 0 }; + ThreadRequest req{ self->mMsgEvent, 0 }; HRESULT hr{E_FAIL}; - if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + auto proxy = static_cast(self); + if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)proxy)) hr = WaitForResponse(&req); return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; } -static HRESULT ALCwasapiCapture_startProxy(ALCwasapiCapture *self) +HRESULT ALCwasapiCapture::startProxy() { - ResetEvent(self->NotifyEvent); + ResetEvent(mNotifyEvent); - IAudioClient *client{self->client}; - HRESULT hr{client->Start()}; + HRESULT hr{mClient->Start()}; if(FAILED(hr)) { ERR("Failed to start audio client: 0x%08lx\n", hr); @@ -1799,17 +1763,17 @@ static HRESULT ALCwasapiCapture_startProxy(ALCwasapiCapture *self) } void *ptr; - hr = client->GetService(IID_IAudioCaptureClient, &ptr); + hr = mClient->GetService(IID_IAudioCaptureClient, &ptr); if(SUCCEEDED(hr)) { - self->capture = reinterpret_cast(ptr); + mCapture = reinterpret_cast(ptr); try { - self->killNow.store(AL_FALSE, std::memory_order_release); - self->thread = std::thread(ALCwasapiCapture_recordProc, self); + mKillNow.store(AL_FALSE, std::memory_order_release); + mThread = std::thread(ALCwasapiCapture_recordProc, this); } catch(...) { - self->capture->Release(); - self->capture = nullptr; + mCapture->Release(); + mCapture = nullptr; ERR("Failed to start thread\n"); hr = E_FAIL; } @@ -1817,8 +1781,8 @@ static HRESULT ALCwasapiCapture_startProxy(ALCwasapiCapture *self) if(FAILED(hr)) { - client->Stop(); - client->Reset(); + mClient->Stop(); + mClient->Reset(); } return hr; @@ -1827,44 +1791,45 @@ static HRESULT ALCwasapiCapture_startProxy(ALCwasapiCapture *self) static void ALCwasapiCapture_stop(ALCwasapiCapture *self) { - ThreadRequest req{ self->MsgEvent, 0 }; - if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + ThreadRequest req{ self->mMsgEvent, 0 }; + auto proxy = static_cast(self); + if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)proxy)) (void)WaitForResponse(&req); } -static void ALCwasapiCapture_stopProxy(ALCwasapiCapture *self) +void ALCwasapiCapture::stopProxy() { - if(!self->capture || !self->thread.joinable()) + if(!mCapture || !mThread.joinable()) return; - self->killNow.store(AL_TRUE); - self->thread.join(); + mKillNow.store(AL_TRUE); + mThread.join(); - self->capture->Release(); - self->capture = nullptr; - self->client->Stop(); - self->client->Reset(); + mCapture->Release(); + mCapture = nullptr; + mClient->Stop(); + mClient->Reset(); } static ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self) { - return (ALuint)ll_ringbuffer_read_space(self->Ring); + return (ALuint)ll_ringbuffer_read_space(self->mRing); } static ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, ALCuint samples) { if(ALCwasapiCapture_availableSamples(self) < samples) return ALC_INVALID_VALUE; - ll_ringbuffer_read(self->Ring, reinterpret_cast(buffer), samples); + ll_ringbuffer_read(self->mRing, reinterpret_cast(buffer), samples); return ALC_NO_ERROR; } -typedef struct ALCwasapiBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCwasapiBackendFactory; -#define ALCWASAPIBACKENDFACTORY_INITIALIZER { GET_VTABLE2(ALCwasapiBackendFactory, ALCbackendFactory) } +struct ALCwasapiBackendFactory final : public ALCbackendFactory { + ALCwasapiBackendFactory() noexcept; +}; +#define ALCWASAPIBACKENDFACTORY_INITIALIZER GET_VTABLE2(ALCwasapiBackendFactory, ALCbackendFactory) static ALCboolean ALCwasapiBackendFactory_init(ALCwasapiBackendFactory *self); static void ALCwasapiBackendFactory_deinit(ALCwasapiBackendFactory *self); @@ -1874,6 +1839,11 @@ static ALCbackend* ALCwasapiBackendFactory_createBackend(ALCwasapiBackendFactory DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwasapiBackendFactory); +ALCwasapiBackendFactory::ALCwasapiBackendFactory() noexcept + : ALCbackendFactory{ALCWASAPIBACKENDFACTORY_INITIALIZER} +{ +} + static ALCboolean ALCwasapiBackendFactory_init(ALCwasapiBackendFactory* UNUSED(self)) { @@ -1889,7 +1859,7 @@ static ALCboolean ALCwasapiBackendFactory_init(ALCwasapiBackendFactory* UNUSED(s ERR("Failed to create event: %lu\n", GetLastError()); else { - ThreadHdl = CreateThread(nullptr, 0, ALCwasapiProxy_messageHandler, &req, 0, &ThreadID); + ThreadHdl = CreateThread(nullptr, 0, WasapiProxy_messageHandler, &req, 0, &ThreadID); if(ThreadHdl != nullptr) InitResult = WaitForResponse(&req); CloseHandle(req.FinishedEvt); @@ -1979,6 +1949,6 @@ static ALCbackend* ALCwasapiBackendFactory_createBackend(ALCwasapiBackendFactory ALCbackendFactory *ALCwasapiBackendFactory_getFactory(void) { - static ALCwasapiBackendFactory factory{ALCWASAPIBACKENDFACTORY_INITIALIZER}; + static ALCwasapiBackendFactory factory{}; return STATIC_CAST(ALCbackendFactory, &factory); } diff --git a/Alc/polymorphism.h b/Alc/polymorphism.h index e837b2a5..bc0a5681 100644 --- a/Alc/polymorphism.h +++ b/Alc/polymorphism.h @@ -2,9 +2,15 @@ #define POLYMORPHISM_H /* Macros to declare inheriting types, and to (down-)cast and up-cast. */ +#ifdef __cplusplus +#define STATIC_CAST(to, obj) static_cast(obj) +#define STATIC_UPCAST(to, from, obj) static_cast(obj) +#else + #define DERIVE_FROM_TYPE(t) t t##_parent #define STATIC_CAST(to, obj) (&(obj)->to##_parent) -#if defined(__GNUC__) && !defined(__cplusplus) + +#if defined(__GNUC__) #define STATIC_UPCAST(to, from, obj) __extension__({ \ static_assert(__builtin_types_compatible_p(from, __typeof(*(obj))), \ "Invalid upcast object from type"); \ @@ -13,6 +19,7 @@ #else #define STATIC_UPCAST(to, from, obj) ((to*)((char*)(obj) - offsetof(to, from##_parent))) #endif +#endif /* __cplusplus */ /* Defines method forwards, which call the given parent's (T2's) implementation. */ #define DECLARE_FORWARD(T1, T2, rettype, func) \ -- cgit v1.2.3 From d66664122a9ba1abea41fd088e8661fff40070e3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Nov 2018 00:13:07 -0700 Subject: Try another fix to declare GUIDs in C++ --- Alc/backends/wasapi.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index ddb3ced0..a390911b 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -54,10 +54,16 @@ #include "backends/base.h" -extern "C" { -extern const GUID KSDATAFORMAT_SUBTYPE_PCM; -extern const GUID KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; -} // extern "C" +/* Some headers seem to define these as macros for __uuidof, which is annoying + * since some headers don't declare them at all. Hopefully the ifdef is enough + * to tell if they need to be declared. + */ +#ifndef KSDATAFORMAT_SUBTYPE_PCM +DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +#endif +#ifndef KSDATAFORMAT_SUBTYPE_IEEE_FLOAT +DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +#endif DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); -- cgit v1.2.3 From aaa31d987f92f767af0d5d9633da5bab9d7862b8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Nov 2018 00:42:50 -0700 Subject: Check the correct propvariant object --- Alc/backends/wasapi.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index a390911b..a32f41ac 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -117,7 +117,7 @@ std::vector PlaybackDevices; std::vector CaptureDevices; -std::string wstr_to_string(const WCHAR *wstr) +std::string wstr_to_utf8(const WCHAR *wstr) { std::string ret; @@ -200,7 +200,7 @@ static NameGUIDPair get_device_name_and_guid(IMMDevice *device) name += "Unknown Device Name"; } else if(pvname.vt == VT_LPWSTR) - name += wstr_to_string(pvname.pwszVal); + name += wstr_to_utf8(pvname.pwszVal); else { WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvname.vt); @@ -218,8 +218,8 @@ static NameGUIDPair get_device_name_and_guid(IMMDevice *device) WARN("GetValue AudioEndpoint_GUID failed: 0x%08lx\n", hr); guid = "Unknown Device GUID"; } - else if(pvname.vt == VT_LPWSTR) - guid = wstr_to_string(pvname.pwszVal); + else if(pvguid.vt == VT_LPWSTR) + guid = wstr_to_utf8(pvguid.pwszVal); else { WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvguid.vt); -- cgit v1.2.3 From 4ec757c1de78241a2094f57d348e795d0e311b0f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Nov 2018 09:22:12 -0700 Subject: Specify the correct array size for casting --- Alc/mastering.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/mastering.c b/Alc/mastering.c index dd4ed7e1..902ad259 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -466,11 +466,11 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, Comp->Hold->Values[0] = -INFINITY; Comp->Hold->Expiries[0] = hold; Comp->Hold->Length = hold; - Comp->Delay = (ALfloat(*)[])(Comp->Hold + 1); + Comp->Delay = (ALfloat(*)[BUFFERSIZE])(Comp->Hold + 1); } else { - Comp->Delay = (ALfloat(*)[])(Comp + 1); + Comp->Delay = (ALfloat(*)[BUFFERSIZE])(Comp + 1); } } -- cgit v1.2.3 From e20d2cdbce2fd696fa65635aa1242a9b614c05cb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Nov 2018 09:25:19 -0700 Subject: Use HUGE_VALF instead of INFINITY Older MSVC lacks INFINITY, and we define a HUGE_VALF fallback when needed. --- Alc/mastering.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Alc/mastering.c b/Alc/mastering.c index 902ad259..5b02194a 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -6,6 +6,7 @@ #include "alu.h" #include "almalloc.h" #include "static_assert.h" +#include "math_defs.h" /* These structures assume BUFFERSIZE is a power of 2. */ @@ -463,7 +464,7 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, if(hold > 0) { Comp->Hold = (SlidingHold*)(Comp + 1); - Comp->Hold->Values[0] = -INFINITY; + Comp->Hold->Values[0] = -HUGE_VALF; Comp->Hold->Expiries[0] = hold; Comp->Hold->Length = hold; Comp->Delay = (ALfloat(*)[BUFFERSIZE])(Comp->Hold + 1); -- cgit v1.2.3 From 9e8e3c146fc80976dd6e547e5267f890713d7a5c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Nov 2018 09:39:57 -0700 Subject: Workaround lack of roundf with early MSVC --- Alc/mastering.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Alc/mastering.c b/Alc/mastering.c index 5b02194a..5ccf3a9e 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -9,6 +9,18 @@ #include "math_defs.h" +/* Early MSVC lacks round/roundf */ +#if defined(_MSC_VER) && _MSC_VER < 1800 +static double round(double val) +{ + if(val < 0.0) + return ceil(val-0.5); + return floor(val+0.5); +} +#define roundf(f) ((float)round((float)(f))) +#endif + + /* These structures assume BUFFERSIZE is a power of 2. */ static_assert((BUFFERSIZE & (BUFFERSIZE-1)) == 0, "BUFFERSIZE is not a power of 2"); -- cgit v1.2.3 From b54c4b02c796a1762705f51985c467a041f2d579 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Nov 2018 13:32:42 -0700 Subject: Add a wrapper to manage PROPVARIANT objects --- Alc/backends/wasapi.cpp | 61 ++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index a32f41ac..8310974f 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -92,6 +92,24 @@ static inline ALint64 ScaleCeil(ALint64 val, ALint64 new_scale, ALint64 old_scal namespace { +struct PropVariant { + PROPVARIANT mProp; + +public: + PropVariant() { PropVariantInit(&mProp); } + ~PropVariant() { clear(); } + + void clear() { PropVariantClear(&mProp); } + + PROPVARIANT* get() noexcept { return &mProp; } + + PROPVARIANT& operator*() noexcept { return mProp; } + const PROPVARIANT& operator*() const noexcept { return mProp; } + + PROPVARIANT* operator->() noexcept { return &mProp; } + const PROPVARIANT* operator->() const noexcept { return &mProp; } +}; + struct DevMap { std::string name; std::string endpoint_guid; // obtained from PKEY_AudioEndpoint_GUID , set to "Unknown device GUID" if absent. @@ -181,6 +199,7 @@ using NameGUIDPair = std::pair; static NameGUIDPair get_device_name_and_guid(IMMDevice *device) { std::string name{DEVNAME_HEAD}; + std::string guid; IPropertyStore *ps; HRESULT hr = device->OpenPropertyStore(STGM_READ, &ps); @@ -190,43 +209,36 @@ static NameGUIDPair get_device_name_and_guid(IMMDevice *device) return { name+"Unknown Device Name", "Unknown Device GUID" }; } - PROPVARIANT pvname; - PropVariantInit(&pvname); - - hr = ps->GetValue(reinterpret_cast(DEVPKEY_Device_FriendlyName), &pvname); + PropVariant pvprop; + hr = ps->GetValue(reinterpret_cast(DEVPKEY_Device_FriendlyName), pvprop.get()); if(FAILED(hr)) { WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr); name += "Unknown Device Name"; } - else if(pvname.vt == VT_LPWSTR) - name += wstr_to_utf8(pvname.pwszVal); + else if(pvprop->vt == VT_LPWSTR) + name += wstr_to_utf8(pvprop->pwszVal); else { - WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvname.vt); + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvprop->vt); name += "Unknown Device Name"; } - PropVariantClear(&pvname); - std::string guid; - PROPVARIANT pvguid; - PropVariantInit(&pvguid); - - hr = ps->GetValue(reinterpret_cast(PKEY_AudioEndpoint_GUID), &pvguid); + pvprop.clear(); + hr = ps->GetValue(reinterpret_cast(PKEY_AudioEndpoint_GUID), pvprop.get()); if(FAILED(hr)) { WARN("GetValue AudioEndpoint_GUID failed: 0x%08lx\n", hr); guid = "Unknown Device GUID"; } - else if(pvguid.vt == VT_LPWSTR) - guid = wstr_to_utf8(pvguid.pwszVal); + else if(pvprop->vt == VT_LPWSTR) + guid = wstr_to_utf8(pvprop->pwszVal); else { - WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvguid.vt); + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvprop->vt); guid = "Unknown Device GUID"; } - PropVariantClear(&pvguid); ps->Release(); return {name, guid}; @@ -242,20 +254,17 @@ static void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfac return; } - PROPVARIANT pvform; - PropVariantInit(&pvform); - - hr = ps->GetValue(reinterpret_cast(PKEY_AudioEndpoint_FormFactor), &pvform); + PropVariant pvform; + hr = ps->GetValue(reinterpret_cast(PKEY_AudioEndpoint_FormFactor), pvform.get()); if(FAILED(hr)) WARN("GetValue AudioEndpoint_FormFactor failed: 0x%08lx\n", hr); - else if(pvform.vt == VT_UI4) - *formfactor = static_cast(pvform.ulVal); - else if(pvform.vt == VT_EMPTY) + else if(pvform->vt == VT_UI4) + *formfactor = static_cast(pvform->ulVal); + else if(pvform->vt == VT_EMPTY) *formfactor = UnknownFormFactor; else - WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvform.vt); + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvform->vt); - PropVariantClear(&pvform); ps->Release(); } -- cgit v1.2.3 From a7dcc1c6d107e5c5401151c50c89e137f2bb0c0b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Nov 2018 14:56:10 -0700 Subject: Expand the anonymous namespaces --- Alc/backends/pulseaudio.cpp | 32 ++++++++++++++------------------ Alc/backends/wasapi.cpp | 27 ++++++++++++++------------- 2 files changed, 28 insertions(+), 31 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 719205c4..e2845032 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -41,9 +41,11 @@ #if PA_API_VERSION == 12 +namespace { + #ifdef HAVE_DYNLOAD -static void *pa_handle; -#define MAKE_FUNC(x) static decltype(x) * p##x +void *pa_handle; +#define MAKE_FUNC(x) decltype(x) * p##x MAKE_FUNC(pa_context_unref); MAKE_FUNC(pa_sample_spec_valid); MAKE_FUNC(pa_frame_size); @@ -185,7 +187,7 @@ MAKE_FUNC(pa_stream_begin_write); #endif -static ALCboolean pulse_load(void) +ALCboolean pulse_load(void) { ALCboolean ret{ALC_TRUE}; #ifdef HAVE_DYNLOAD @@ -312,8 +314,6 @@ inline pa_context_flags_t operator|=(pa_context_flags_t &lhs, pa_context_flags_t } -namespace { - class palock_guard { pa_threaded_mainloop *mLoop; @@ -363,16 +363,14 @@ public: } }; -} // namespace - /* Global flags and properties */ -static pa_context_flags_t pulse_ctx_flags; -static pa_proplist *prop_filter; +pa_context_flags_t pulse_ctx_flags; +pa_proplist *prop_filter; /* PulseAudio Event Callbacks */ -static void context_state_callback(pa_context *context, void *pdata) +void context_state_callback(pa_context *context, void *pdata) { auto loop = reinterpret_cast(pdata); pa_context_state_t state{pa_context_get_state(context)}; @@ -380,7 +378,7 @@ static void context_state_callback(pa_context *context, void *pdata) pa_threaded_mainloop_signal(loop, 0); } -static void stream_state_callback(pa_stream *stream, void *pdata) +void stream_state_callback(pa_stream *stream, void *pdata) { auto loop = reinterpret_cast(pdata); pa_stream_state_t state{pa_stream_get_state(stream)}; @@ -388,13 +386,13 @@ static void stream_state_callback(pa_stream *stream, void *pdata) pa_threaded_mainloop_signal(loop, 0); } -static void stream_success_callback(pa_stream *UNUSED(stream), int UNUSED(success), void *pdata) +void stream_success_callback(pa_stream *UNUSED(stream), int UNUSED(success), void *pdata) { auto loop = reinterpret_cast(pdata); pa_threaded_mainloop_signal(loop, 0); } -static void wait_for_operation(pa_operation *op, pa_threaded_mainloop *loop) +void wait_for_operation(pa_operation *op, pa_threaded_mainloop *loop) { if(op) { @@ -405,7 +403,7 @@ static void wait_for_operation(pa_operation *op, pa_threaded_mainloop *loop) } -static pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent) +pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent) { const char *name{"OpenAL Soft"}; al_string binname{AL_STRING_INIT_STATIC()}; @@ -456,7 +454,7 @@ static pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent) using MainloopContextPair = std::pair; -static MainloopContextPair pulse_open(void(*state_cb)(pa_context*,void*), void *ptr) +MainloopContextPair pulse_open(void(*state_cb)(pa_context*,void*), void *ptr) { pa_threaded_mainloop *loop{pa_threaded_mainloop_new()}; if(UNLIKELY(!loop)) @@ -484,7 +482,7 @@ static MainloopContextPair pulse_open(void(*state_cb)(pa_context*,void*), void * return {loop, context}; } -static void pulse_close(pa_threaded_mainloop *loop, pa_context *context, pa_stream *stream) +void pulse_close(pa_threaded_mainloop *loop, pa_context *context, pa_stream *stream) { { palock_guard _{loop}; if(stream) @@ -506,8 +504,6 @@ static void pulse_close(pa_threaded_mainloop *loop, pa_context *context, pa_stre } -namespace { - struct DevMap { std::string name; std::string device_name; diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 8310974f..2dc44c87 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -69,6 +69,9 @@ DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23,0xe0, 0xc0,0xff,0xee,0x7f,0x0e, 4 ); + +namespace { + #define MONO SPEAKER_FRONT_CENTER #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT) #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT) @@ -84,14 +87,12 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x /* Scales the given value using 64-bit integer math, ceiling the result. */ -static inline ALint64 ScaleCeil(ALint64 val, ALint64 new_scale, ALint64 old_scale) +inline ALint64 ScaleCeil(ALint64 val, ALint64 new_scale, ALint64 old_scale) { return (val*new_scale + old_scale-1) / old_scale; } -namespace { - struct PropVariant { PROPVARIANT mProp; @@ -159,8 +160,6 @@ struct ThreadRequest { HRESULT result; }; -} // namespace - #define WM_USER_First (WM_USER+0) #define WM_USER_OpenDevice (WM_USER+0) @@ -180,13 +179,13 @@ static const char MessageStr[WM_USER_Last+1-WM_USER][20] = { "Enumerate Devices", }; -static inline void ReturnMsgResponse(ThreadRequest *req, HRESULT res) +inline void ReturnMsgResponse(ThreadRequest *req, HRESULT res) { req->result = res; SetEvent(req->FinishedEvt); } -static HRESULT WaitForResponse(ThreadRequest *req) +HRESULT WaitForResponse(ThreadRequest *req) { if(WaitForSingleObject(req->FinishedEvt, INFINITE) == WAIT_OBJECT_0) return req->result; @@ -196,7 +195,7 @@ static HRESULT WaitForResponse(ThreadRequest *req) using NameGUIDPair = std::pair; -static NameGUIDPair get_device_name_and_guid(IMMDevice *device) +NameGUIDPair get_device_name_and_guid(IMMDevice *device) { std::string name{DEVNAME_HEAD}; std::string guid; @@ -244,7 +243,7 @@ static NameGUIDPair get_device_name_and_guid(IMMDevice *device) return {name, guid}; } -static void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfactor) +void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfactor) { IPropertyStore *ps; HRESULT hr = device->OpenPropertyStore(STGM_READ, &ps); @@ -269,7 +268,7 @@ static void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfac } -static void add_device(IMMDevice *device, const WCHAR *devid, std::vector &list) +void add_device(IMMDevice *device, const WCHAR *devid, std::vector &list) { std::string basename, guidstr; std::tie(basename, guidstr) = get_device_name_and_guid(device); @@ -289,7 +288,7 @@ static void add_device(IMMDevice *device, const WCHAR *devid, std::vector &list) +HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, std::vector &list) { IMMDeviceCollection *coll; HRESULT hr = devenum->EnumAudioEndpoints(flowdir, DEVICE_STATE_ACTIVE, &coll); @@ -365,7 +364,7 @@ struct WasapiProxy { virtual void stopProxy() = 0; }; -static DWORD CALLBACK WasapiProxy_messageHandler(void *ptr) +DWORD CALLBACK WasapiProxy_messageHandler(void *ptr) { auto req = reinterpret_cast(ptr); @@ -507,6 +506,8 @@ static DWORD CALLBACK WasapiProxy_messageHandler(void *ptr) return 0; } +} // namespace + struct ALCwasapiPlayback final : public ALCbackend, WasapiProxy { HRESULT openProxy() override; -- cgit v1.2.3 From 5482efc9214d180e1f67fc528f593098ad20a678 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Nov 2018 18:48:08 -0700 Subject: Make the polymorphic allocators allocate cleared memory --- Alc/effects/null.c | 2 +- Alc/polymorphism.h | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Alc/effects/null.c b/Alc/effects/null.c index 6eaa001f..82ea5d26 100644 --- a/Alc/effects/null.c +++ b/Alc/effects/null.c @@ -73,7 +73,7 @@ static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALsizei UNUSED(sam */ static void *ALnullState_New(size_t size) { - return al_malloc(16, size); + return al_calloc(16, size); } /* This frees the memory used by the object, after it has been destructed. diff --git a/Alc/polymorphism.h b/Alc/polymorphism.h index bc0a5681..83d5585f 100644 --- a/Alc/polymorphism.h +++ b/Alc/polymorphism.h @@ -61,7 +61,7 @@ static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c, a /* Defines the default functions used to (de)allocate a polymorphic object. */ #define DECLARE_DEFAULT_ALLOCATORS(T) \ -static void* T##_New(size_t size) { return al_malloc(16, size); } \ +static void* T##_New(size_t size) { return al_calloc(16, size); } \ static void T##_Delete(void *ptr) { al_free(ptr); } @@ -84,14 +84,12 @@ static void T##_Delete(void *ptr) { al_free(ptr); } _res = (T*)T##_New(sizeof(T)); \ if(_res) \ { \ - memset(_res, 0, sizeof(T)); \ T##_Construct(_res, EXTRACT_NEW_ARGS /* Allocate and construct an object, with no arguments. */ #define NEW_OBJ0(_res, T) do { \ _res = (T*)T##_New(sizeof(T)); \ if(_res) \ { \ - memset(_res, 0, sizeof(T)); \ T##_Construct(_res EXTRACT_NEW_ARGS /* Destructs and deallocate an object. */ -- cgit v1.2.3 From e9d17c51912bbec566279290a435e504ace7aa0c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Nov 2018 12:55:02 -0700 Subject: Move wstr_to_utf8 to compat.h --- Alc/backends/wasapi.cpp | 16 ---------------- Alc/compat.h | 23 +++++++++++++++++++++++ 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 2dc44c87..f2adf328 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -136,22 +136,6 @@ std::vector PlaybackDevices; std::vector CaptureDevices; -std::string wstr_to_utf8(const WCHAR *wstr) -{ - std::string ret; - - int len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr); - if(len > 0) - { - ret.resize(len); - WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &ret[0], len, nullptr, nullptr); - ret.pop_back(); - } - - return ret; -} - - HANDLE ThreadHdl; DWORD ThreadID; diff --git a/Alc/compat.h b/Alc/compat.h index e0f6cbd9..c478c01d 100644 --- a/Alc/compat.h +++ b/Alc/compat.h @@ -19,6 +19,29 @@ FILE *al_fopen(const char *fname, const char *mode); #define HAVE_DYNLOAD 1 +#ifdef __cplusplus +} // extern "C" + +#include + +inline std::string wstr_to_utf8(const WCHAR *wstr) +{ + std::string ret; + + int len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr); + if(len > 0) + { + ret.resize(len); + WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &ret[0], len, nullptr, nullptr); + ret.pop_back(); + } + + return ret; +} + +extern "C" { +#endif /* __cplusplus */ + #else #define al_fopen fopen -- cgit v1.2.3 From 18e1d10338deda77cff58f21c2e1687442c6190d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Nov 2018 14:39:16 -0700 Subject: Convert the UHJ encoder to C++ --- Alc/uhjfilter.c | 120 ---------------------------------------------------- Alc/uhjfilter.cpp | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ Alc/uhjfilter.h | 8 ++++ CMakeLists.txt | 2 +- 4 files changed, 133 insertions(+), 121 deletions(-) delete mode 100644 Alc/uhjfilter.c create mode 100644 Alc/uhjfilter.cpp diff --git a/Alc/uhjfilter.c b/Alc/uhjfilter.c deleted file mode 100644 index 6ee6fdb0..00000000 --- a/Alc/uhjfilter.c +++ /dev/null @@ -1,120 +0,0 @@ - -#include "config.h" - -#include "alu.h" -#include "uhjfilter.h" - -/* This is the maximum number of samples processed for each inner loop - * iteration. */ -#define MAX_UPDATE_SAMPLES 128 - - -static const ALfloat Filter1CoeffSqr[4] = { - 0.479400865589f, 0.876218493539f, 0.976597589508f, 0.997499255936f -}; -static const ALfloat Filter2CoeffSqr[4] = { - 0.161758498368f, 0.733028932341f, 0.945349700329f, 0.990599156685f -}; - -static void allpass_process(AllPassState *state, ALfloat *RESTRICT dst, const ALfloat *RESTRICT src, const ALfloat aa, ALsizei todo) -{ - ALfloat z1 = state->z[0]; - ALfloat z2 = state->z[1]; - ALsizei i; - - for(i = 0;i < todo;i++) - { - ALfloat input = src[i]; - ALfloat output = input*aa + z1; - z1 = z2; z2 = output*aa - input; - dst[i] = output; - } - - state->z[0] = z1; - state->z[1] = z2; -} - - -/* NOTE: There seems to be a bit of an inconsistency in how this encoding is - * supposed to work. Some references, such as - * - * http://members.tripod.com/martin_leese/Ambisonic/UHJ_file_format.html - * - * specify a pre-scaling of sqrt(2) on the W channel input, while other - * references, such as - * - * https://en.wikipedia.org/wiki/Ambisonic_UHJ_format#Encoding.5B1.5D - * and - * https://wiki.xiph.org/Ambisonics#UHJ_format - * - * do not. The sqrt(2) scaling is in line with B-Format decoder coefficients - * which include such a scaling for the W channel input, however the original - * source for this equation is a 1985 paper by Michael Gerzon, which does not - * apparently include the scaling. Applying the extra scaling creates a louder - * result with a narrower stereo image compared to not scaling, and I don't - * know which is the intended result. - */ - -void EncodeUhj2(Uhj2Encoder *enc, ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo) -{ - ALfloat D[MAX_UPDATE_SAMPLES], S[MAX_UPDATE_SAMPLES]; - ALfloat temp[2][MAX_UPDATE_SAMPLES]; - ALsizei base, i; - - ASSUME(SamplesToDo > 0); - - for(base = 0;base < SamplesToDo;) - { - ALsizei todo = mini(SamplesToDo - base, MAX_UPDATE_SAMPLES); - ASSUME(todo > 0); - - /* D = 0.6554516*Y */ - for(i = 0;i < todo;i++) - temp[0][i] = 0.6554516f*InSamples[2][base+i]; - allpass_process(&enc->Filter1_Y[0], temp[1], temp[0], Filter1CoeffSqr[0], todo); - allpass_process(&enc->Filter1_Y[1], temp[0], temp[1], Filter1CoeffSqr[1], todo); - allpass_process(&enc->Filter1_Y[2], temp[1], temp[0], Filter1CoeffSqr[2], todo); - allpass_process(&enc->Filter1_Y[3], temp[0], temp[1], Filter1CoeffSqr[3], todo); - /* NOTE: Filter1 requires a 1 sample delay for the final output, so - * take the last processed sample from the previous run as the first - * output sample. - */ - D[0] = enc->LastY; - for(i = 1;i < todo;i++) - D[i] = temp[0][i-1]; - enc->LastY = temp[0][i-1]; - - /* D += j(-0.3420201*W + 0.5098604*X) */ - for(i = 0;i < todo;i++) - temp[0][i] = -0.3420201f*InSamples[0][base+i] + - 0.5098604f*InSamples[1][base+i]; - allpass_process(&enc->Filter2_WX[0], temp[1], temp[0], Filter2CoeffSqr[0], todo); - allpass_process(&enc->Filter2_WX[1], temp[0], temp[1], Filter2CoeffSqr[1], todo); - allpass_process(&enc->Filter2_WX[2], temp[1], temp[0], Filter2CoeffSqr[2], todo); - allpass_process(&enc->Filter2_WX[3], temp[0], temp[1], Filter2CoeffSqr[3], todo); - for(i = 0;i < todo;i++) - D[i] += temp[0][i]; - - /* S = 0.9396926*W + 0.1855740*X */ - for(i = 0;i < todo;i++) - temp[0][i] = 0.9396926f*InSamples[0][base+i] + - 0.1855740f*InSamples[1][base+i]; - allpass_process(&enc->Filter1_WX[0], temp[1], temp[0], Filter1CoeffSqr[0], todo); - allpass_process(&enc->Filter1_WX[1], temp[0], temp[1], Filter1CoeffSqr[1], todo); - allpass_process(&enc->Filter1_WX[2], temp[1], temp[0], Filter1CoeffSqr[2], todo); - allpass_process(&enc->Filter1_WX[3], temp[0], temp[1], Filter1CoeffSqr[3], todo); - S[0] = enc->LastWX; - for(i = 1;i < todo;i++) - S[i] = temp[0][i-1]; - enc->LastWX = temp[0][i-1]; - - /* Left = (S + D)/2.0 */ - for(i = 0;i < todo;i++) - *(LeftOut++) += (S[i] + D[i]) * 0.5f; - /* Right = (S - D)/2.0 */ - for(i = 0;i < todo;i++) - *(RightOut++) += (S[i] - D[i]) * 0.5f; - - base += todo; - } -} diff --git a/Alc/uhjfilter.cpp b/Alc/uhjfilter.cpp new file mode 100644 index 00000000..4fae721f --- /dev/null +++ b/Alc/uhjfilter.cpp @@ -0,0 +1,124 @@ + +#include "config.h" + +#include "alu.h" +#include "uhjfilter.h" + +namespace { + +/* This is the maximum number of samples processed for each inner loop + * iteration. */ +#define MAX_UPDATE_SAMPLES 128 + + +constexpr ALfloat Filter1CoeffSqr[4] = { + 0.479400865589f, 0.876218493539f, 0.976597589508f, 0.997499255936f +}; +constexpr ALfloat Filter2CoeffSqr[4] = { + 0.161758498368f, 0.733028932341f, 0.945349700329f, 0.990599156685f +}; + +void allpass_process(AllPassState *state, ALfloat *RESTRICT dst, const ALfloat *RESTRICT src, const ALfloat aa, ALsizei todo) +{ + ALfloat z1 = state->z[0]; + ALfloat z2 = state->z[1]; + ALsizei i; + + for(i = 0;i < todo;i++) + { + ALfloat input = src[i]; + ALfloat output = input*aa + z1; + z1 = z2; z2 = output*aa - input; + dst[i] = output; + } + + state->z[0] = z1; + state->z[1] = z2; +} + +} // namespace + + +/* NOTE: There seems to be a bit of an inconsistency in how this encoding is + * supposed to work. Some references, such as + * + * http://members.tripod.com/martin_leese/Ambisonic/UHJ_file_format.html + * + * specify a pre-scaling of sqrt(2) on the W channel input, while other + * references, such as + * + * https://en.wikipedia.org/wiki/Ambisonic_UHJ_format#Encoding.5B1.5D + * and + * https://wiki.xiph.org/Ambisonics#UHJ_format + * + * do not. The sqrt(2) scaling is in line with B-Format decoder coefficients + * which include such a scaling for the W channel input, however the original + * source for this equation is a 1985 paper by Michael Gerzon, which does not + * apparently include the scaling. Applying the extra scaling creates a louder + * result with a narrower stereo image compared to not scaling, and I don't + * know which is the intended result. + */ + +void EncodeUhj2(Uhj2Encoder *enc, ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo) +{ + ALfloat D[MAX_UPDATE_SAMPLES], S[MAX_UPDATE_SAMPLES]; + ALfloat temp[2][MAX_UPDATE_SAMPLES]; + ALsizei base, i; + + ASSUME(SamplesToDo > 0); + + for(base = 0;base < SamplesToDo;) + { + ALsizei todo = mini(SamplesToDo - base, MAX_UPDATE_SAMPLES); + ASSUME(todo > 0); + + /* D = 0.6554516*Y */ + for(i = 0;i < todo;i++) + temp[0][i] = 0.6554516f*InSamples[2][base+i]; + allpass_process(&enc->Filter1_Y[0], temp[1], temp[0], Filter1CoeffSqr[0], todo); + allpass_process(&enc->Filter1_Y[1], temp[0], temp[1], Filter1CoeffSqr[1], todo); + allpass_process(&enc->Filter1_Y[2], temp[1], temp[0], Filter1CoeffSqr[2], todo); + allpass_process(&enc->Filter1_Y[3], temp[0], temp[1], Filter1CoeffSqr[3], todo); + /* NOTE: Filter1 requires a 1 sample delay for the final output, so + * take the last processed sample from the previous run as the first + * output sample. + */ + D[0] = enc->LastY; + for(i = 1;i < todo;i++) + D[i] = temp[0][i-1]; + enc->LastY = temp[0][i-1]; + + /* D += j(-0.3420201*W + 0.5098604*X) */ + for(i = 0;i < todo;i++) + temp[0][i] = -0.3420201f*InSamples[0][base+i] + + 0.5098604f*InSamples[1][base+i]; + allpass_process(&enc->Filter2_WX[0], temp[1], temp[0], Filter2CoeffSqr[0], todo); + allpass_process(&enc->Filter2_WX[1], temp[0], temp[1], Filter2CoeffSqr[1], todo); + allpass_process(&enc->Filter2_WX[2], temp[1], temp[0], Filter2CoeffSqr[2], todo); + allpass_process(&enc->Filter2_WX[3], temp[0], temp[1], Filter2CoeffSqr[3], todo); + for(i = 0;i < todo;i++) + D[i] += temp[0][i]; + + /* S = 0.9396926*W + 0.1855740*X */ + for(i = 0;i < todo;i++) + temp[0][i] = 0.9396926f*InSamples[0][base+i] + + 0.1855740f*InSamples[1][base+i]; + allpass_process(&enc->Filter1_WX[0], temp[1], temp[0], Filter1CoeffSqr[0], todo); + allpass_process(&enc->Filter1_WX[1], temp[0], temp[1], Filter1CoeffSqr[1], todo); + allpass_process(&enc->Filter1_WX[2], temp[1], temp[0], Filter1CoeffSqr[2], todo); + allpass_process(&enc->Filter1_WX[3], temp[0], temp[1], Filter1CoeffSqr[3], todo); + S[0] = enc->LastWX; + for(i = 1;i < todo;i++) + S[i] = temp[0][i-1]; + enc->LastWX = temp[0][i-1]; + + /* Left = (S + D)/2.0 */ + for(i = 0;i < todo;i++) + *(LeftOut++) += (S[i] + D[i]) * 0.5f; + /* Right = (S - D)/2.0 */ + for(i = 0;i < todo;i++) + *(RightOut++) += (S[i] - D[i]) * 0.5f; + + base += todo; + } +} diff --git a/Alc/uhjfilter.h b/Alc/uhjfilter.h index 9ea1fb44..211425ed 100644 --- a/Alc/uhjfilter.h +++ b/Alc/uhjfilter.h @@ -5,6 +5,10 @@ #include "alMain.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef struct AllPassState { ALfloat z[2]; } AllPassState; @@ -46,4 +50,8 @@ typedef struct Uhj2Encoder { */ void EncodeUhj2(Uhj2Encoder *enc, ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo); +#ifdef __cplusplus +} // extern "C" +#endif + #endif /* UHJFILTER_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index f4c0ae4c..eb02a366 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -872,7 +872,7 @@ SET(ALC_OBJS Alc/vector.h Alc/hrtf.c Alc/hrtf.h - Alc/uhjfilter.c + Alc/uhjfilter.cpp Alc/uhjfilter.h Alc/ambdec.c Alc/ambdec.h -- cgit v1.2.3 From 12d5b638f2afc0a8b762bd5e5e8056e85c72d189 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Nov 2018 15:23:15 -0700 Subject: Convert the band-split filter to C++ --- Alc/filters/splitter.c | 109 ----------------------------------------------- Alc/filters/splitter.cpp | 109 +++++++++++++++++++++++++++++++++++++++++++++++ Alc/filters/splitter.h | 7 +++ CMakeLists.txt | 2 +- 4 files changed, 117 insertions(+), 110 deletions(-) delete mode 100644 Alc/filters/splitter.c create mode 100644 Alc/filters/splitter.cpp diff --git a/Alc/filters/splitter.c b/Alc/filters/splitter.c deleted file mode 100644 index 6aed7493..00000000 --- a/Alc/filters/splitter.c +++ /dev/null @@ -1,109 +0,0 @@ - -#include "config.h" - -#include "splitter.h" - -#include "math_defs.h" - - -void bandsplit_init(BandSplitter *splitter, ALfloat f0norm) -{ - ALfloat w = f0norm * F_TAU; - ALfloat cw = cosf(w); - if(cw > FLT_EPSILON) - splitter->coeff = (sinf(w) - 1.0f) / cw; - else - splitter->coeff = cw * -0.5f; - - splitter->lp_z1 = 0.0f; - splitter->lp_z2 = 0.0f; - splitter->hp_z1 = 0.0f; -} - -void bandsplit_clear(BandSplitter *splitter) -{ - splitter->lp_z1 = 0.0f; - splitter->lp_z2 = 0.0f; - splitter->hp_z1 = 0.0f; -} - -void bandsplit_process(BandSplitter *splitter, ALfloat *RESTRICT hpout, ALfloat *RESTRICT lpout, - const ALfloat *input, ALsizei count) -{ - ALfloat lp_coeff, hp_coeff, lp_y, hp_y, d; - ALfloat lp_z1, lp_z2, hp_z1; - ALsizei i; - - ASSUME(count > 0); - - hp_coeff = splitter->coeff; - lp_coeff = splitter->coeff*0.5f + 0.5f; - lp_z1 = splitter->lp_z1; - lp_z2 = splitter->lp_z2; - hp_z1 = splitter->hp_z1; - for(i = 0;i < count;i++) - { - ALfloat in = input[i]; - - /* Low-pass sample processing. */ - d = (in - lp_z1) * lp_coeff; - lp_y = lp_z1 + d; - lp_z1 = lp_y + d; - - d = (lp_y - lp_z2) * lp_coeff; - lp_y = lp_z2 + d; - lp_z2 = lp_y + d; - - lpout[i] = lp_y; - - /* All-pass sample processing. */ - hp_y = in*hp_coeff + hp_z1; - hp_z1 = in - hp_y*hp_coeff; - - /* High-pass generated from removing low-passed output. */ - hpout[i] = hp_y - lp_y; - } - splitter->lp_z1 = lp_z1; - splitter->lp_z2 = lp_z2; - splitter->hp_z1 = hp_z1; -} - - -void splitterap_init(SplitterAllpass *splitter, ALfloat f0norm) -{ - ALfloat w = f0norm * F_TAU; - ALfloat cw = cosf(w); - if(cw > FLT_EPSILON) - splitter->coeff = (sinf(w) - 1.0f) / cw; - else - splitter->coeff = cw * -0.5f; - - splitter->z1 = 0.0f; -} - -void splitterap_clear(SplitterAllpass *splitter) -{ - splitter->z1 = 0.0f; -} - -void splitterap_process(SplitterAllpass *splitter, ALfloat *RESTRICT samples, ALsizei count) -{ - ALfloat coeff, in, out; - ALfloat z1; - ALsizei i; - - ASSUME(count > 0); - - coeff = splitter->coeff; - z1 = splitter->z1; - for(i = 0;i < count;i++) - { - in = samples[i]; - - out = in*coeff + z1; - z1 = in - out*coeff; - - samples[i] = out; - } - splitter->z1 = z1; -} diff --git a/Alc/filters/splitter.cpp b/Alc/filters/splitter.cpp new file mode 100644 index 00000000..6aed7493 --- /dev/null +++ b/Alc/filters/splitter.cpp @@ -0,0 +1,109 @@ + +#include "config.h" + +#include "splitter.h" + +#include "math_defs.h" + + +void bandsplit_init(BandSplitter *splitter, ALfloat f0norm) +{ + ALfloat w = f0norm * F_TAU; + ALfloat cw = cosf(w); + if(cw > FLT_EPSILON) + splitter->coeff = (sinf(w) - 1.0f) / cw; + else + splitter->coeff = cw * -0.5f; + + splitter->lp_z1 = 0.0f; + splitter->lp_z2 = 0.0f; + splitter->hp_z1 = 0.0f; +} + +void bandsplit_clear(BandSplitter *splitter) +{ + splitter->lp_z1 = 0.0f; + splitter->lp_z2 = 0.0f; + splitter->hp_z1 = 0.0f; +} + +void bandsplit_process(BandSplitter *splitter, ALfloat *RESTRICT hpout, ALfloat *RESTRICT lpout, + const ALfloat *input, ALsizei count) +{ + ALfloat lp_coeff, hp_coeff, lp_y, hp_y, d; + ALfloat lp_z1, lp_z2, hp_z1; + ALsizei i; + + ASSUME(count > 0); + + hp_coeff = splitter->coeff; + lp_coeff = splitter->coeff*0.5f + 0.5f; + lp_z1 = splitter->lp_z1; + lp_z2 = splitter->lp_z2; + hp_z1 = splitter->hp_z1; + for(i = 0;i < count;i++) + { + ALfloat in = input[i]; + + /* Low-pass sample processing. */ + d = (in - lp_z1) * lp_coeff; + lp_y = lp_z1 + d; + lp_z1 = lp_y + d; + + d = (lp_y - lp_z2) * lp_coeff; + lp_y = lp_z2 + d; + lp_z2 = lp_y + d; + + lpout[i] = lp_y; + + /* All-pass sample processing. */ + hp_y = in*hp_coeff + hp_z1; + hp_z1 = in - hp_y*hp_coeff; + + /* High-pass generated from removing low-passed output. */ + hpout[i] = hp_y - lp_y; + } + splitter->lp_z1 = lp_z1; + splitter->lp_z2 = lp_z2; + splitter->hp_z1 = hp_z1; +} + + +void splitterap_init(SplitterAllpass *splitter, ALfloat f0norm) +{ + ALfloat w = f0norm * F_TAU; + ALfloat cw = cosf(w); + if(cw > FLT_EPSILON) + splitter->coeff = (sinf(w) - 1.0f) / cw; + else + splitter->coeff = cw * -0.5f; + + splitter->z1 = 0.0f; +} + +void splitterap_clear(SplitterAllpass *splitter) +{ + splitter->z1 = 0.0f; +} + +void splitterap_process(SplitterAllpass *splitter, ALfloat *RESTRICT samples, ALsizei count) +{ + ALfloat coeff, in, out; + ALfloat z1; + ALsizei i; + + ASSUME(count > 0); + + coeff = splitter->coeff; + z1 = splitter->z1; + for(i = 0;i < count;i++) + { + in = samples[i]; + + out = in*coeff + z1; + z1 = in - out*coeff; + + samples[i] = out; + } + splitter->z1 = z1; +} diff --git a/Alc/filters/splitter.h b/Alc/filters/splitter.h index b2dc9b4a..a996917c 100644 --- a/Alc/filters/splitter.h +++ b/Alc/filters/splitter.h @@ -3,6 +3,9 @@ #include "alMain.h" +#ifdef __cplusplus +extern "C" { +#endif /* Band splitter. Splits a signal into two phase-matching frequency bands. */ typedef struct BandSplitter { @@ -37,4 +40,8 @@ typedef struct FrontStablizer { alignas(16) ALfloat RSplit[2][BUFFERSIZE]; } FrontStablizer; +#ifdef __cplusplus +} // extern "C" +#endif + #endif /* FILTER_SPLITTER_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index eb02a366..138de1c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -861,7 +861,7 @@ SET(ALC_OBJS Alc/filters/filter.c Alc/filters/nfc.c Alc/filters/nfc.h - Alc/filters/splitter.c + Alc/filters/splitter.cpp Alc/filters/splitter.h Alc/helpers.c Alc/alstring.h -- cgit v1.2.3 From 67f9efdad45f4da65d1f02d95d878c5f6fc03bb1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Nov 2018 15:32:09 -0700 Subject: Convert the BFormat decoder to C++ --- Alc/bformatdec.c | 492 ----------------------------------------------------- Alc/bformatdec.cpp | 492 +++++++++++++++++++++++++++++++++++++++++++++++++++++ Alc/bformatdec.h | 13 +- CMakeLists.txt | 2 +- 4 files changed, 503 insertions(+), 496 deletions(-) delete mode 100644 Alc/bformatdec.c create mode 100644 Alc/bformatdec.cpp diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c deleted file mode 100644 index 91eb8ca8..00000000 --- a/Alc/bformatdec.c +++ /dev/null @@ -1,492 +0,0 @@ - -#include "config.h" - -#include "bformatdec.h" -#include "ambdec.h" -#include "filters/splitter.h" -#include "alu.h" - -#include "bool.h" -#include "threads.h" -#include "almalloc.h" - - -/* NOTE: These are scale factors as applied to Ambisonics content. Decoder - * coefficients should be divided by these values to get proper N3D scalings. - */ -const ALfloat N3D2N3DScale[MAX_AMBI_COEFFS] = { - 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f -}; -const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = { - 1.000000000f, /* ACN 0 (W), sqrt(1) */ - 1.732050808f, /* ACN 1 (Y), sqrt(3) */ - 1.732050808f, /* ACN 2 (Z), sqrt(3) */ - 1.732050808f, /* ACN 3 (X), sqrt(3) */ - 2.236067978f, /* ACN 4 (V), sqrt(5) */ - 2.236067978f, /* ACN 5 (T), sqrt(5) */ - 2.236067978f, /* ACN 6 (R), sqrt(5) */ - 2.236067978f, /* ACN 7 (S), sqrt(5) */ - 2.236067978f, /* ACN 8 (U), sqrt(5) */ - 2.645751311f, /* ACN 9 (Q), sqrt(7) */ - 2.645751311f, /* ACN 10 (O), sqrt(7) */ - 2.645751311f, /* ACN 11 (M), sqrt(7) */ - 2.645751311f, /* ACN 12 (K), sqrt(7) */ - 2.645751311f, /* ACN 13 (L), sqrt(7) */ - 2.645751311f, /* ACN 14 (N), sqrt(7) */ - 2.645751311f, /* ACN 15 (P), sqrt(7) */ -}; -const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = { - 1.414213562f, /* ACN 0 (W), sqrt(2) */ - 1.732050808f, /* ACN 1 (Y), sqrt(3) */ - 1.732050808f, /* ACN 2 (Z), sqrt(3) */ - 1.732050808f, /* ACN 3 (X), sqrt(3) */ - 1.936491673f, /* ACN 4 (V), sqrt(15)/2 */ - 1.936491673f, /* ACN 5 (T), sqrt(15)/2 */ - 2.236067978f, /* ACN 6 (R), sqrt(5) */ - 1.936491673f, /* ACN 7 (S), sqrt(15)/2 */ - 1.936491673f, /* ACN 8 (U), sqrt(15)/2 */ - 2.091650066f, /* ACN 9 (Q), sqrt(35/8) */ - 1.972026594f, /* ACN 10 (O), sqrt(35)/3 */ - 2.231093404f, /* ACN 11 (M), sqrt(224/45) */ - 2.645751311f, /* ACN 12 (K), sqrt(7) */ - 2.231093404f, /* ACN 13 (L), sqrt(224/45) */ - 1.972026594f, /* ACN 14 (N), sqrt(35)/3 */ - 2.091650066f, /* ACN 15 (P), sqrt(35/8) */ -}; - - -#define HF_BAND 0 -#define LF_BAND 1 -#define NUM_BANDS 2 - -/* These points are in AL coordinates! */ -static const ALfloat Ambi3DPoints[8][3] = { - { -0.577350269f, 0.577350269f, -0.577350269f }, - { 0.577350269f, 0.577350269f, -0.577350269f }, - { -0.577350269f, 0.577350269f, 0.577350269f }, - { 0.577350269f, 0.577350269f, 0.577350269f }, - { -0.577350269f, -0.577350269f, -0.577350269f }, - { 0.577350269f, -0.577350269f, -0.577350269f }, - { -0.577350269f, -0.577350269f, 0.577350269f }, - { 0.577350269f, -0.577350269f, 0.577350269f }, -}; -static const ALfloat Ambi3DDecoder[8][MAX_AMBI_COEFFS] = { - { 0.125f, 0.125f, 0.125f, 0.125f }, - { 0.125f, -0.125f, 0.125f, 0.125f }, - { 0.125f, 0.125f, 0.125f, -0.125f }, - { 0.125f, -0.125f, 0.125f, -0.125f }, - { 0.125f, 0.125f, -0.125f, 0.125f }, - { 0.125f, -0.125f, -0.125f, 0.125f }, - { 0.125f, 0.125f, -0.125f, -0.125f }, - { 0.125f, -0.125f, -0.125f, -0.125f }, -}; -static const ALfloat Ambi3DDecoderHFScale[MAX_AMBI_COEFFS] = { - 2.0f, - 1.15470054f, 1.15470054f, 1.15470054f -}; - - -/* NOTE: BandSplitter filters are unused with single-band decoding */ -typedef struct BFormatDec { - ALuint Enabled; /* Bitfield of enabled channels. */ - - union { - alignas(16) ALfloat Dual[MAX_OUTPUT_CHANNELS][NUM_BANDS][MAX_AMBI_COEFFS]; - alignas(16) ALfloat Single[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; - } Matrix; - - BandSplitter XOver[MAX_AMBI_COEFFS]; - - ALfloat (*Samples)[BUFFERSIZE]; - /* These two alias into Samples */ - ALfloat (*SamplesHF)[BUFFERSIZE]; - ALfloat (*SamplesLF)[BUFFERSIZE]; - - alignas(16) ALfloat ChannelMix[BUFFERSIZE]; - - struct { - BandSplitter XOver; - ALfloat Gains[NUM_BANDS]; - } UpSampler[4]; - - ALsizei NumChannels; - ALboolean DualBand; -} BFormatDec; - -BFormatDec *bformatdec_alloc() -{ - return al_calloc(16, sizeof(BFormatDec)); -} - -void bformatdec_free(BFormatDec **dec) -{ - if(dec && *dec) - { - al_free((*dec)->Samples); - (*dec)->Samples = NULL; - (*dec)->SamplesHF = NULL; - (*dec)->SamplesLF = NULL; - - al_free(*dec); - *dec = NULL; - } -} - -void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS]) -{ - static const ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = { - 0, 1, 3, 4, 8, 9, 15 - }; - const ALfloat *coeff_scale = N3D2N3DScale; - bool periphonic; - ALfloat ratio; - ALsizei i; - - al_free(dec->Samples); - dec->Samples = NULL; - dec->SamplesHF = NULL; - dec->SamplesLF = NULL; - - dec->NumChannels = chancount; - dec->Samples = al_calloc(16, dec->NumChannels*2 * sizeof(dec->Samples[0])); - dec->SamplesHF = dec->Samples; - dec->SamplesLF = dec->SamplesHF + dec->NumChannels; - - dec->Enabled = 0; - for(i = 0;i < conf->NumSpeakers;i++) - dec->Enabled |= 1 << chanmap[i]; - - if(conf->CoeffScale == ADS_SN3D) - coeff_scale = SN3D2N3DScale; - else if(conf->CoeffScale == ADS_FuMa) - coeff_scale = FuMa2N3DScale; - - memset(dec->UpSampler, 0, sizeof(dec->UpSampler)); - ratio = 400.0f / (ALfloat)srate; - for(i = 0;i < 4;i++) - bandsplit_init(&dec->UpSampler[i].XOver, ratio); - if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) - { - periphonic = true; - - dec->UpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H3P : - (conf->ChanMask > 0xf) ? W_SCALE_2H2P : 1.0f; - dec->UpSampler[0].Gains[LF_BAND] = 1.0f; - for(i = 1;i < 4;i++) - { - dec->UpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H3P : - (conf->ChanMask > 0xf) ? XYZ_SCALE_2H2P : 1.0f; - dec->UpSampler[i].Gains[LF_BAND] = 1.0f; - } - } - else - { - periphonic = false; - - dec->UpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H0P : - (conf->ChanMask > 0xf) ? W_SCALE_2H0P : 1.0f; - dec->UpSampler[0].Gains[LF_BAND] = 1.0f; - for(i = 1;i < 3;i++) - { - dec->UpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H0P : - (conf->ChanMask > 0xf) ? XYZ_SCALE_2H0P : 1.0f; - dec->UpSampler[i].Gains[LF_BAND] = 1.0f; - } - dec->UpSampler[3].Gains[HF_BAND] = 0.0f; - dec->UpSampler[3].Gains[LF_BAND] = 0.0f; - } - - memset(&dec->Matrix, 0, sizeof(dec->Matrix)); - if(conf->FreqBands == 1) - { - dec->DualBand = AL_FALSE; - for(i = 0;i < conf->NumSpeakers;i++) - { - ALsizei chan = chanmap[i]; - ALfloat gain; - ALsizei j, k; - - if(!periphonic) - { - for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++) - { - ALsizei l = map2DTo3D[j]; - if(j == 0) gain = conf->HFOrderGain[0]; - else if(j == 1) gain = conf->HFOrderGain[1]; - else if(j == 3) gain = conf->HFOrderGain[2]; - else if(j == 5) gain = conf->HFOrderGain[3]; - if((conf->ChanMask&(1<Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] * - gain; - } - } - else - { - for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++) - { - if(j == 0) gain = conf->HFOrderGain[0]; - else if(j == 1) gain = conf->HFOrderGain[1]; - else if(j == 4) gain = conf->HFOrderGain[2]; - else if(j == 9) gain = conf->HFOrderGain[3]; - if((conf->ChanMask&(1<Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * - gain; - } - } - } - } - else - { - dec->DualBand = AL_TRUE; - - ratio = conf->XOverFreq / (ALfloat)srate; - for(i = 0;i < MAX_AMBI_COEFFS;i++) - bandsplit_init(&dec->XOver[i], ratio); - - ratio = powf(10.0f, conf->XOverRatio / 40.0f); - for(i = 0;i < conf->NumSpeakers;i++) - { - ALsizei chan = chanmap[i]; - ALfloat gain; - ALsizei j, k; - - if(!periphonic) - { - for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++) - { - ALsizei l = map2DTo3D[j]; - if(j == 0) gain = conf->HFOrderGain[0] * ratio; - else if(j == 1) gain = conf->HFOrderGain[1] * ratio; - else if(j == 3) gain = conf->HFOrderGain[2] * ratio; - else if(j == 5) gain = conf->HFOrderGain[3] * ratio; - if((conf->ChanMask&(1<Matrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] / - coeff_scale[l] * gain; - } - for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++) - { - ALsizei l = map2DTo3D[j]; - if(j == 0) gain = conf->LFOrderGain[0] / ratio; - else if(j == 1) gain = conf->LFOrderGain[1] / ratio; - else if(j == 3) gain = conf->LFOrderGain[2] / ratio; - else if(j == 5) gain = conf->LFOrderGain[3] / ratio; - if((conf->ChanMask&(1<Matrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] / - coeff_scale[l] * gain; - } - } - else - { - for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++) - { - if(j == 0) gain = conf->HFOrderGain[0] * ratio; - else if(j == 1) gain = conf->HFOrderGain[1] * ratio; - else if(j == 4) gain = conf->HFOrderGain[2] * ratio; - else if(j == 9) gain = conf->HFOrderGain[3] * ratio; - if((conf->ChanMask&(1<Matrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] / - coeff_scale[j] * gain; - } - for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++) - { - if(j == 0) gain = conf->LFOrderGain[0] / ratio; - else if(j == 1) gain = conf->LFOrderGain[1] / ratio; - else if(j == 4) gain = conf->LFOrderGain[2] / ratio; - else if(j == 9) gain = conf->LFOrderGain[3] / ratio; - if((conf->ChanMask&(1<Matrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] / - coeff_scale[j] * gain; - } - } - } - } -} - - -void bformatdec_process(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo) -{ - ALsizei chan, i; - - OutBuffer = ASSUME_ALIGNED(OutBuffer, 16); - if(dec->DualBand) - { - for(i = 0;i < dec->NumChannels;i++) - bandsplit_process(&dec->XOver[i], dec->SamplesHF[i], dec->SamplesLF[i], - InSamples[i], SamplesToDo); - - for(chan = 0;chan < OutChannels;chan++) - { - if(!(dec->Enabled&(1<ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); - MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][HF_BAND], - dec->SamplesHF, dec->NumChannels, 0, SamplesToDo - ); - MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][LF_BAND], - dec->SamplesLF, dec->NumChannels, 0, SamplesToDo - ); - - for(i = 0;i < SamplesToDo;i++) - OutBuffer[chan][i] += dec->ChannelMix[i]; - } - } - else - { - for(chan = 0;chan < OutChannels;chan++) - { - if(!(dec->Enabled&(1<ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); - MixRowSamples(dec->ChannelMix, dec->Matrix.Single[chan], InSamples, - dec->NumChannels, 0, SamplesToDo); - - for(i = 0;i < SamplesToDo;i++) - OutBuffer[chan][i] += dec->ChannelMix[i]; - } - } -} - - -void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo) -{ - ALsizei i; - - /* This up-sampler leverages the differences observed in dual-band second- - * and third-order decoder matrices compared to first-order. For the same - * output channel configuration, the low-frequency matrix has identical - * coefficients in the shared input channels, while the high-frequency - * matrix has extra scalars applied to the W channel and X/Y/Z channels. - * Mixing the first-order content into the higher-order stream with the - * appropriate counter-scales applied to the HF response results in the - * subsequent higher-order decode generating the same response as a first- - * order decode. - */ - for(i = 0;i < InChannels;i++) - { - /* First, split the first-order components into low and high frequency - * bands. - */ - bandsplit_process(&dec->UpSampler[i].XOver, - dec->Samples[HF_BAND], dec->Samples[LF_BAND], - InSamples[i], SamplesToDo - ); - - /* Now write each band to the output. */ - MixRowSamples(OutBuffer[i], dec->UpSampler[i].Gains, - dec->Samples, NUM_BANDS, 0, SamplesToDo - ); - } -} - - -#define INVALID_UPSAMPLE_INDEX INT_MAX - -static ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn) -{ - ALsizei i; - for(i = 0;i < numchans;i++) - { - if(chans[i].Index == acn) - return i; - } - return INVALID_UPSAMPLE_INDEX; -} -#define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a)) - -typedef struct AmbiUpsampler { - alignas(16) ALfloat Samples[NUM_BANDS][BUFFERSIZE]; - - BandSplitter XOver[4]; - - ALfloat Gains[4][MAX_OUTPUT_CHANNELS][NUM_BANDS]; -} AmbiUpsampler; - -AmbiUpsampler *ambiup_alloc() -{ - return al_calloc(16, sizeof(AmbiUpsampler)); -} - -void ambiup_free(struct AmbiUpsampler **ambiup) -{ - if(ambiup) - { - al_free(*ambiup); - *ambiup = NULL; - } -} - -void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat w_scale, ALfloat xyz_scale) -{ - ALfloat ratio; - ALsizei i; - - ratio = 400.0f / (ALfloat)device->Frequency; - for(i = 0;i < 4;i++) - bandsplit_init(&ambiup->XOver[i], ratio); - - memset(ambiup->Gains, 0, sizeof(ambiup->Gains)); - if(device->Dry.CoeffCount > 0) - { - ALfloat encgains[8][MAX_OUTPUT_CHANNELS]; - ALsizei j; - size_t k; - - for(k = 0;k < COUNTOF(Ambi3DPoints);k++) - { - ALfloat coeffs[MAX_AMBI_COEFFS] = { 0.0f }; - CalcDirectionCoeffs(Ambi3DPoints[k], 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, 1.0f, encgains[k]); - } - - /* Combine the matrices that do the in->virt and virt->out conversions - * so we get a single in->out conversion. NOTE: the Encoder matrix - * (encgains) and output are transposed, so the input channels line up - * with the rows and the output channels line up with the columns. - */ - for(i = 0;i < 4;i++) - { - for(j = 0;j < device->Dry.NumChannels;j++) - { - ALdouble gain = 0.0; - for(k = 0;k < COUNTOF(Ambi3DDecoder);k++) - gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][j]; - ambiup->Gains[i][j][HF_BAND] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]); - ambiup->Gains[i][j][LF_BAND] = (ALfloat)gain; - } - } - } - else - { - for(i = 0;i < 4;i++) - { - ALsizei index = GetChannelForACN(device->Dry, i); - if(index != INVALID_UPSAMPLE_INDEX) - { - ALfloat scale = device->Dry.Ambi.Map[index].Scale; - ambiup->Gains[i][index][HF_BAND] = scale * ((i==0) ? w_scale : xyz_scale); - ambiup->Gains[i][index][LF_BAND] = scale; - } - } - } -} - -void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo) -{ - ALsizei i, j; - - for(i = 0;i < 4;i++) - { - bandsplit_process(&ambiup->XOver[i], - ambiup->Samples[HF_BAND], ambiup->Samples[LF_BAND], - InSamples[i], SamplesToDo - ); - - for(j = 0;j < OutChannels;j++) - MixRowSamples(OutBuffer[j], ambiup->Gains[i][j], - ambiup->Samples, NUM_BANDS, 0, SamplesToDo - ); - } -} diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp new file mode 100644 index 00000000..a0893f89 --- /dev/null +++ b/Alc/bformatdec.cpp @@ -0,0 +1,492 @@ + +#include "config.h" + +#include "bformatdec.h" +#include "ambdec.h" +#include "filters/splitter.h" +#include "alu.h" + +#include "bool.h" +#include "threads.h" +#include "almalloc.h" + + +/* NOTE: These are scale factors as applied to Ambisonics content. Decoder + * coefficients should be divided by these values to get proper N3D scalings. + */ +const ALfloat N3D2N3DScale[MAX_AMBI_COEFFS] = { + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f +}; +const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = { + 1.000000000f, /* ACN 0 (W), sqrt(1) */ + 1.732050808f, /* ACN 1 (Y), sqrt(3) */ + 1.732050808f, /* ACN 2 (Z), sqrt(3) */ + 1.732050808f, /* ACN 3 (X), sqrt(3) */ + 2.236067978f, /* ACN 4 (V), sqrt(5) */ + 2.236067978f, /* ACN 5 (T), sqrt(5) */ + 2.236067978f, /* ACN 6 (R), sqrt(5) */ + 2.236067978f, /* ACN 7 (S), sqrt(5) */ + 2.236067978f, /* ACN 8 (U), sqrt(5) */ + 2.645751311f, /* ACN 9 (Q), sqrt(7) */ + 2.645751311f, /* ACN 10 (O), sqrt(7) */ + 2.645751311f, /* ACN 11 (M), sqrt(7) */ + 2.645751311f, /* ACN 12 (K), sqrt(7) */ + 2.645751311f, /* ACN 13 (L), sqrt(7) */ + 2.645751311f, /* ACN 14 (N), sqrt(7) */ + 2.645751311f, /* ACN 15 (P), sqrt(7) */ +}; +const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = { + 1.414213562f, /* ACN 0 (W), sqrt(2) */ + 1.732050808f, /* ACN 1 (Y), sqrt(3) */ + 1.732050808f, /* ACN 2 (Z), sqrt(3) */ + 1.732050808f, /* ACN 3 (X), sqrt(3) */ + 1.936491673f, /* ACN 4 (V), sqrt(15)/2 */ + 1.936491673f, /* ACN 5 (T), sqrt(15)/2 */ + 2.236067978f, /* ACN 6 (R), sqrt(5) */ + 1.936491673f, /* ACN 7 (S), sqrt(15)/2 */ + 1.936491673f, /* ACN 8 (U), sqrt(15)/2 */ + 2.091650066f, /* ACN 9 (Q), sqrt(35/8) */ + 1.972026594f, /* ACN 10 (O), sqrt(35)/3 */ + 2.231093404f, /* ACN 11 (M), sqrt(224/45) */ + 2.645751311f, /* ACN 12 (K), sqrt(7) */ + 2.231093404f, /* ACN 13 (L), sqrt(224/45) */ + 1.972026594f, /* ACN 14 (N), sqrt(35)/3 */ + 2.091650066f, /* ACN 15 (P), sqrt(35/8) */ +}; + + +#define HF_BAND 0 +#define LF_BAND 1 +#define NUM_BANDS 2 + +/* These points are in AL coordinates! */ +static const ALfloat Ambi3DPoints[8][3] = { + { -0.577350269f, 0.577350269f, -0.577350269f }, + { 0.577350269f, 0.577350269f, -0.577350269f }, + { -0.577350269f, 0.577350269f, 0.577350269f }, + { 0.577350269f, 0.577350269f, 0.577350269f }, + { -0.577350269f, -0.577350269f, -0.577350269f }, + { 0.577350269f, -0.577350269f, -0.577350269f }, + { -0.577350269f, -0.577350269f, 0.577350269f }, + { 0.577350269f, -0.577350269f, 0.577350269f }, +}; +static const ALfloat Ambi3DDecoder[8][MAX_AMBI_COEFFS] = { + { 0.125f, 0.125f, 0.125f, 0.125f }, + { 0.125f, -0.125f, 0.125f, 0.125f }, + { 0.125f, 0.125f, 0.125f, -0.125f }, + { 0.125f, -0.125f, 0.125f, -0.125f }, + { 0.125f, 0.125f, -0.125f, 0.125f }, + { 0.125f, -0.125f, -0.125f, 0.125f }, + { 0.125f, 0.125f, -0.125f, -0.125f }, + { 0.125f, -0.125f, -0.125f, -0.125f }, +}; +static const ALfloat Ambi3DDecoderHFScale[MAX_AMBI_COEFFS] = { + 2.0f, + 1.15470054f, 1.15470054f, 1.15470054f +}; + + +/* NOTE: BandSplitter filters are unused with single-band decoding */ +typedef struct BFormatDec { + ALuint Enabled; /* Bitfield of enabled channels. */ + + union { + alignas(16) ALfloat Dual[MAX_OUTPUT_CHANNELS][NUM_BANDS][MAX_AMBI_COEFFS]; + alignas(16) ALfloat Single[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; + } Matrix; + + BandSplitter XOver[MAX_AMBI_COEFFS]; + + ALfloat (*Samples)[BUFFERSIZE]; + /* These two alias into Samples */ + ALfloat (*SamplesHF)[BUFFERSIZE]; + ALfloat (*SamplesLF)[BUFFERSIZE]; + + alignas(16) ALfloat ChannelMix[BUFFERSIZE]; + + struct { + BandSplitter XOver; + ALfloat Gains[NUM_BANDS]; + } UpSampler[4]; + + ALsizei NumChannels; + ALboolean DualBand; +} BFormatDec; + +BFormatDec *bformatdec_alloc() +{ + return reinterpret_cast(al_calloc(16, sizeof(BFormatDec))); +} + +void bformatdec_free(BFormatDec **dec) +{ + if(dec && *dec) + { + al_free((*dec)->Samples); + (*dec)->Samples = NULL; + (*dec)->SamplesHF = NULL; + (*dec)->SamplesLF = NULL; + + al_free(*dec); + *dec = NULL; + } +} + +void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS]) +{ + static const ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = { + 0, 1, 3, 4, 8, 9, 15 + }; + const ALfloat *coeff_scale = N3D2N3DScale; + bool periphonic; + ALfloat ratio; + ALsizei i; + + al_free(dec->Samples); + dec->Samples = NULL; + dec->SamplesHF = NULL; + dec->SamplesLF = NULL; + + dec->NumChannels = chancount; + dec->Samples = reinterpret_cast(al_calloc(16, + dec->NumChannels*2 * sizeof(dec->Samples[0]))); + dec->SamplesHF = dec->Samples; + dec->SamplesLF = dec->SamplesHF + dec->NumChannels; + + dec->Enabled = 0; + for(i = 0;i < conf->NumSpeakers;i++) + dec->Enabled |= 1 << chanmap[i]; + + if(conf->CoeffScale == ADS_SN3D) + coeff_scale = SN3D2N3DScale; + else if(conf->CoeffScale == ADS_FuMa) + coeff_scale = FuMa2N3DScale; + + memset(dec->UpSampler, 0, sizeof(dec->UpSampler)); + ratio = 400.0f / (ALfloat)srate; + for(i = 0;i < 4;i++) + bandsplit_init(&dec->UpSampler[i].XOver, ratio); + if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) + { + periphonic = true; + + dec->UpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H3P : + (conf->ChanMask > 0xf) ? W_SCALE_2H2P : 1.0f; + dec->UpSampler[0].Gains[LF_BAND] = 1.0f; + for(i = 1;i < 4;i++) + { + dec->UpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H3P : + (conf->ChanMask > 0xf) ? XYZ_SCALE_2H2P : 1.0f; + dec->UpSampler[i].Gains[LF_BAND] = 1.0f; + } + } + else + { + periphonic = false; + + dec->UpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H0P : + (conf->ChanMask > 0xf) ? W_SCALE_2H0P : 1.0f; + dec->UpSampler[0].Gains[LF_BAND] = 1.0f; + for(i = 1;i < 3;i++) + { + dec->UpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H0P : + (conf->ChanMask > 0xf) ? XYZ_SCALE_2H0P : 1.0f; + dec->UpSampler[i].Gains[LF_BAND] = 1.0f; + } + dec->UpSampler[3].Gains[HF_BAND] = 0.0f; + dec->UpSampler[3].Gains[LF_BAND] = 0.0f; + } + + memset(&dec->Matrix, 0, sizeof(dec->Matrix)); + if(conf->FreqBands == 1) + { + dec->DualBand = AL_FALSE; + for(i = 0;i < conf->NumSpeakers;i++) + { + ALsizei chan = chanmap[i]; + ALfloat gain; + ALsizei j, k; + + if(!periphonic) + { + for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++) + { + ALsizei l = map2DTo3D[j]; + if(j == 0) gain = conf->HFOrderGain[0]; + else if(j == 1) gain = conf->HFOrderGain[1]; + else if(j == 3) gain = conf->HFOrderGain[2]; + else if(j == 5) gain = conf->HFOrderGain[3]; + if((conf->ChanMask&(1<Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] * + gain; + } + } + else + { + for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++) + { + if(j == 0) gain = conf->HFOrderGain[0]; + else if(j == 1) gain = conf->HFOrderGain[1]; + else if(j == 4) gain = conf->HFOrderGain[2]; + else if(j == 9) gain = conf->HFOrderGain[3]; + if((conf->ChanMask&(1<Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * + gain; + } + } + } + } + else + { + dec->DualBand = AL_TRUE; + + ratio = conf->XOverFreq / (ALfloat)srate; + for(i = 0;i < MAX_AMBI_COEFFS;i++) + bandsplit_init(&dec->XOver[i], ratio); + + ratio = powf(10.0f, conf->XOverRatio / 40.0f); + for(i = 0;i < conf->NumSpeakers;i++) + { + ALsizei chan = chanmap[i]; + ALfloat gain; + ALsizei j, k; + + if(!periphonic) + { + for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++) + { + ALsizei l = map2DTo3D[j]; + if(j == 0) gain = conf->HFOrderGain[0] * ratio; + else if(j == 1) gain = conf->HFOrderGain[1] * ratio; + else if(j == 3) gain = conf->HFOrderGain[2] * ratio; + else if(j == 5) gain = conf->HFOrderGain[3] * ratio; + if((conf->ChanMask&(1<Matrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] / + coeff_scale[l] * gain; + } + for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++) + { + ALsizei l = map2DTo3D[j]; + if(j == 0) gain = conf->LFOrderGain[0] / ratio; + else if(j == 1) gain = conf->LFOrderGain[1] / ratio; + else if(j == 3) gain = conf->LFOrderGain[2] / ratio; + else if(j == 5) gain = conf->LFOrderGain[3] / ratio; + if((conf->ChanMask&(1<Matrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] / + coeff_scale[l] * gain; + } + } + else + { + for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++) + { + if(j == 0) gain = conf->HFOrderGain[0] * ratio; + else if(j == 1) gain = conf->HFOrderGain[1] * ratio; + else if(j == 4) gain = conf->HFOrderGain[2] * ratio; + else if(j == 9) gain = conf->HFOrderGain[3] * ratio; + if((conf->ChanMask&(1<Matrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] / + coeff_scale[j] * gain; + } + for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++) + { + if(j == 0) gain = conf->LFOrderGain[0] / ratio; + else if(j == 1) gain = conf->LFOrderGain[1] / ratio; + else if(j == 4) gain = conf->LFOrderGain[2] / ratio; + else if(j == 9) gain = conf->LFOrderGain[3] / ratio; + if((conf->ChanMask&(1<Matrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] / + coeff_scale[j] * gain; + } + } + } + } +} + + +void bformatdec_process(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo) +{ + ALsizei chan, i; + + if(dec->DualBand) + { + for(i = 0;i < dec->NumChannels;i++) + bandsplit_process(&dec->XOver[i], dec->SamplesHF[i], dec->SamplesLF[i], + InSamples[i], SamplesToDo); + + for(chan = 0;chan < OutChannels;chan++) + { + if(!(dec->Enabled&(1<ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); + MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][HF_BAND], + dec->SamplesHF, dec->NumChannels, 0, SamplesToDo + ); + MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][LF_BAND], + dec->SamplesLF, dec->NumChannels, 0, SamplesToDo + ); + + for(i = 0;i < SamplesToDo;i++) + OutBuffer[chan][i] += dec->ChannelMix[i]; + } + } + else + { + for(chan = 0;chan < OutChannels;chan++) + { + if(!(dec->Enabled&(1<ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); + MixRowSamples(dec->ChannelMix, dec->Matrix.Single[chan], InSamples, + dec->NumChannels, 0, SamplesToDo); + + for(i = 0;i < SamplesToDo;i++) + OutBuffer[chan][i] += dec->ChannelMix[i]; + } + } +} + + +void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo) +{ + ALsizei i; + + /* This up-sampler leverages the differences observed in dual-band second- + * and third-order decoder matrices compared to first-order. For the same + * output channel configuration, the low-frequency matrix has identical + * coefficients in the shared input channels, while the high-frequency + * matrix has extra scalars applied to the W channel and X/Y/Z channels. + * Mixing the first-order content into the higher-order stream with the + * appropriate counter-scales applied to the HF response results in the + * subsequent higher-order decode generating the same response as a first- + * order decode. + */ + for(i = 0;i < InChannels;i++) + { + /* First, split the first-order components into low and high frequency + * bands. + */ + bandsplit_process(&dec->UpSampler[i].XOver, + dec->Samples[HF_BAND], dec->Samples[LF_BAND], + InSamples[i], SamplesToDo + ); + + /* Now write each band to the output. */ + MixRowSamples(OutBuffer[i], dec->UpSampler[i].Gains, + dec->Samples, NUM_BANDS, 0, SamplesToDo + ); + } +} + + +#define INVALID_UPSAMPLE_INDEX INT_MAX + +static ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn) +{ + ALsizei i; + for(i = 0;i < numchans;i++) + { + if(chans[i].Index == acn) + return i; + } + return INVALID_UPSAMPLE_INDEX; +} +#define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a)) + +typedef struct AmbiUpsampler { + alignas(16) ALfloat Samples[NUM_BANDS][BUFFERSIZE]; + + BandSplitter XOver[4]; + + ALfloat Gains[4][MAX_OUTPUT_CHANNELS][NUM_BANDS]; +} AmbiUpsampler; + +AmbiUpsampler *ambiup_alloc() +{ + return reinterpret_cast(al_calloc(16, sizeof(AmbiUpsampler))); +} + +void ambiup_free(struct AmbiUpsampler **ambiup) +{ + if(ambiup) + { + al_free(*ambiup); + *ambiup = NULL; + } +} + +void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat w_scale, ALfloat xyz_scale) +{ + ALfloat ratio; + ALsizei i; + + ratio = 400.0f / (ALfloat)device->Frequency; + for(i = 0;i < 4;i++) + bandsplit_init(&ambiup->XOver[i], ratio); + + memset(ambiup->Gains, 0, sizeof(ambiup->Gains)); + if(device->Dry.CoeffCount > 0) + { + ALfloat encgains[8][MAX_OUTPUT_CHANNELS]; + ALsizei j; + size_t k; + + for(k = 0;k < COUNTOF(Ambi3DPoints);k++) + { + ALfloat coeffs[MAX_AMBI_COEFFS] = { 0.0f }; + CalcDirectionCoeffs(Ambi3DPoints[k], 0.0f, coeffs); + ComputePanGains(&device->Dry, coeffs, 1.0f, encgains[k]); + } + + /* Combine the matrices that do the in->virt and virt->out conversions + * so we get a single in->out conversion. NOTE: the Encoder matrix + * (encgains) and output are transposed, so the input channels line up + * with the rows and the output channels line up with the columns. + */ + for(i = 0;i < 4;i++) + { + for(j = 0;j < device->Dry.NumChannels;j++) + { + ALdouble gain = 0.0; + for(k = 0;k < COUNTOF(Ambi3DDecoder);k++) + gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][j]; + ambiup->Gains[i][j][HF_BAND] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]); + ambiup->Gains[i][j][LF_BAND] = (ALfloat)gain; + } + } + } + else + { + for(i = 0;i < 4;i++) + { + ALsizei index = GetChannelForACN(device->Dry, i); + if(index != INVALID_UPSAMPLE_INDEX) + { + ALfloat scale = device->Dry.Ambi.Map[index].Scale; + ambiup->Gains[i][index][HF_BAND] = scale * ((i==0) ? w_scale : xyz_scale); + ambiup->Gains[i][index][LF_BAND] = scale; + } + } + } +} + +void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo) +{ + ALsizei i, j; + + for(i = 0;i < 4;i++) + { + bandsplit_process(&ambiup->XOver[i], + ambiup->Samples[HF_BAND], ambiup->Samples[LF_BAND], + InSamples[i], SamplesToDo + ); + + for(j = 0;j < OutChannels;j++) + MixRowSamples(OutBuffer[j], ambiup->Gains[i][j], + ambiup->Samples, NUM_BANDS, 0, SamplesToDo + ); + } +} diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 3c081807..964a89f9 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -3,6 +3,9 @@ #include "alMain.h" +#ifdef __cplusplus +extern "C" { +#endif /* These are the necessary scales for first-order HF responses to play over * higher-order 2D (non-periphonic) decoders. @@ -24,9 +27,9 @@ /* NOTE: These are scale factors as applied to Ambisonics content. Decoder * coefficients should be divided by these values to get proper N3D scalings. */ -const ALfloat N3D2N3DScale[MAX_AMBI_COEFFS]; -const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS]; -const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS]; +extern const ALfloat N3D2N3DScale[MAX_AMBI_COEFFS]; +extern const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS]; +extern const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS]; struct AmbDecConf; @@ -54,4 +57,8 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo); +#ifdef __cplusplus +} // extern "C" +#endif + #endif /* BFORMATDEC_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 138de1c3..2743bcaa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -876,7 +876,7 @@ SET(ALC_OBJS Alc/uhjfilter.h Alc/ambdec.c Alc/ambdec.h - Alc/bformatdec.c + Alc/bformatdec.cpp Alc/bformatdec.h Alc/panning.c Alc/polymorphism.h -- cgit v1.2.3 From ba5ec8b0741398272ec52f0177e17ee776226f73 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Nov 2018 18:00:05 -0700 Subject: Be more C++-friendly with the B-Format decoder --- Alc/bformatdec.cpp | 140 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 88 insertions(+), 52 deletions(-) diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index a0893f89..7a3e8ab6 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -1,6 +1,9 @@ #include "config.h" +#include +#include + #include "bformatdec.h" #include "ambdec.h" #include "filters/splitter.h" @@ -56,12 +59,14 @@ const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = { }; +namespace { + #define HF_BAND 0 #define LF_BAND 1 #define NUM_BANDS 2 /* These points are in AL coordinates! */ -static const ALfloat Ambi3DPoints[8][3] = { +const ALfloat Ambi3DPoints[8][3] = { { -0.577350269f, 0.577350269f, -0.577350269f }, { 0.577350269f, 0.577350269f, -0.577350269f }, { -0.577350269f, 0.577350269f, 0.577350269f }, @@ -71,7 +76,7 @@ static const ALfloat Ambi3DPoints[8][3] = { { -0.577350269f, -0.577350269f, 0.577350269f }, { 0.577350269f, -0.577350269f, 0.577350269f }, }; -static const ALfloat Ambi3DDecoder[8][MAX_AMBI_COEFFS] = { +const ALfloat Ambi3DDecoder[8][MAX_AMBI_COEFFS] = { { 0.125f, 0.125f, 0.125f, 0.125f }, { 0.125f, -0.125f, 0.125f, 0.125f }, { 0.125f, 0.125f, 0.125f, -0.125f }, @@ -81,14 +86,61 @@ static const ALfloat Ambi3DDecoder[8][MAX_AMBI_COEFFS] = { { 0.125f, 0.125f, -0.125f, -0.125f }, { 0.125f, -0.125f, -0.125f, -0.125f }, }; -static const ALfloat Ambi3DDecoderHFScale[MAX_AMBI_COEFFS] = { +const ALfloat Ambi3DDecoderHFScale[MAX_AMBI_COEFFS] = { 2.0f, 1.15470054f, 1.15470054f, 1.15470054f }; +#define INVALID_UPSAMPLE_INDEX INT_MAX +ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn) +{ + ALsizei i; + for(i = 0;i < numchans;i++) + { + if(chans[i].Index == acn) + return i; + } + return INVALID_UPSAMPLE_INDEX; +} +#define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a)) + + +template +class aligned_allocator : public std::allocator { +public: + using size_type = size_t; + using pointer = T*; + using const_pointer = const T*; + + template + struct rebind { + using other = aligned_allocator; + }; + + pointer allocate(size_type n, const void* = nullptr) + { return reinterpret_cast(al_malloc(alignment, n)); } + + void deallocate(pointer p, size_type) + { al_free(p); } + + aligned_allocator() : std::allocator() { } + aligned_allocator(const aligned_allocator &a) : std::allocator(a) { } + template + aligned_allocator(const aligned_allocator &a) + : std::allocator(a) + { } + ~aligned_allocator() { } +}; + +template +using aligned_vector = std::vector>; + +} // namespace + + /* NOTE: BandSplitter filters are unused with single-band decoding */ -typedef struct BFormatDec { +struct BFormatDec { ALuint Enabled; /* Bitfield of enabled channels. */ union { @@ -98,10 +150,10 @@ typedef struct BFormatDec { BandSplitter XOver[MAX_AMBI_COEFFS]; - ALfloat (*Samples)[BUFFERSIZE]; + aligned_vector, 16> Samples; /* These two alias into Samples */ - ALfloat (*SamplesHF)[BUFFERSIZE]; - ALfloat (*SamplesLF)[BUFFERSIZE]; + std::array *SamplesHF; + std::array *SamplesLF; alignas(16) ALfloat ChannelMix[BUFFERSIZE]; @@ -112,30 +164,26 @@ typedef struct BFormatDec { ALsizei NumChannels; ALboolean DualBand; -} BFormatDec; + + void *operator new(size_t size) { return al_malloc(alignof(BFormatDec), size); } + void operator delete(void *block) { al_free(block); } +}; BFormatDec *bformatdec_alloc() -{ - return reinterpret_cast(al_calloc(16, sizeof(BFormatDec))); -} +{ return new BFormatDec{}; } void bformatdec_free(BFormatDec **dec) { if(dec && *dec) { - al_free((*dec)->Samples); - (*dec)->Samples = NULL; - (*dec)->SamplesHF = NULL; - (*dec)->SamplesLF = NULL; - - al_free(*dec); - *dec = NULL; + delete *dec; + *dec = nullptr; } } void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS]) { - static const ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = { + constexpr ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; const ALfloat *coeff_scale = N3D2N3DScale; @@ -143,15 +191,13 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount ALfloat ratio; ALsizei i; - al_free(dec->Samples); - dec->Samples = NULL; - dec->SamplesHF = NULL; - dec->SamplesLF = NULL; + dec->Samples.clear(); + dec->SamplesHF = nullptr; + dec->SamplesLF = nullptr; dec->NumChannels = chancount; - dec->Samples = reinterpret_cast(al_calloc(16, - dec->NumChannels*2 * sizeof(dec->Samples[0]))); - dec->SamplesHF = dec->Samples; + dec->Samples.resize(dec->NumChannels * 2); + dec->SamplesHF = dec->Samples.data(); dec->SamplesLF = dec->SamplesHF + dec->NumChannels; dec->Enabled = 0; @@ -312,7 +358,7 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BU if(dec->DualBand) { for(i = 0;i < dec->NumChannels;i++) - bandsplit_process(&dec->XOver[i], dec->SamplesHF[i], dec->SamplesLF[i], + bandsplit_process(&dec->XOver[i], dec->SamplesHF[i].data(), dec->SamplesLF[i].data(), InSamples[i], SamplesToDo); for(chan = 0;chan < OutChannels;chan++) @@ -322,10 +368,12 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BU memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][HF_BAND], - dec->SamplesHF, dec->NumChannels, 0, SamplesToDo + &reinterpret_cast(dec->SamplesHF[0]), + dec->NumChannels, 0, SamplesToDo ); MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][LF_BAND], - dec->SamplesLF, dec->NumChannels, 0, SamplesToDo + &reinterpret_cast(dec->SamplesLF[0]), + dec->NumChannels, 0, SamplesToDo ); for(i = 0;i < SamplesToDo;i++) @@ -370,51 +418,39 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[B * bands. */ bandsplit_process(&dec->UpSampler[i].XOver, - dec->Samples[HF_BAND], dec->Samples[LF_BAND], + dec->Samples[HF_BAND].data(), dec->Samples[LF_BAND].data(), InSamples[i], SamplesToDo ); /* Now write each band to the output. */ MixRowSamples(OutBuffer[i], dec->UpSampler[i].Gains, - dec->Samples, NUM_BANDS, 0, SamplesToDo + &reinterpret_cast(dec->Samples[0]), + NUM_BANDS, 0, SamplesToDo ); } } -#define INVALID_UPSAMPLE_INDEX INT_MAX - -static ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn) -{ - ALsizei i; - for(i = 0;i < numchans;i++) - { - if(chans[i].Index == acn) - return i; - } - return INVALID_UPSAMPLE_INDEX; -} -#define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a)) - -typedef struct AmbiUpsampler { +struct AmbiUpsampler { alignas(16) ALfloat Samples[NUM_BANDS][BUFFERSIZE]; BandSplitter XOver[4]; ALfloat Gains[4][MAX_OUTPUT_CHANNELS][NUM_BANDS]; -} AmbiUpsampler; + + void *operator new(size_t size) { return al_malloc(alignof(AmbiUpsampler), size); } + void operator delete(void *block) { al_free(block); } +}; AmbiUpsampler *ambiup_alloc() -{ - return reinterpret_cast(al_calloc(16, sizeof(AmbiUpsampler))); -} +{ return new AmbiUpsampler{}; } void ambiup_free(struct AmbiUpsampler **ambiup) { if(ambiup) { - al_free(*ambiup); - *ambiup = NULL; + delete *ambiup; + *ambiup = nullptr; } } -- cgit v1.2.3 From 4bfaa173c41076051b63aee85ab20572fdce46c2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Nov 2018 19:02:11 -0700 Subject: Convert panning.c to C++ --- Alc/ALu.c | 5 + Alc/ambdec.h | 8 + Alc/hrtf.h | 8 + Alc/panning.c | 1239 ------------------------------------------------------- Alc/panning.cpp | 1236 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 6 files changed, 1258 insertions(+), 1240 deletions(-) delete mode 100644 Alc/panning.c create mode 100644 Alc/panning.cpp diff --git a/Alc/ALu.c b/Alc/ALu.c index 23996697..ee3ed68f 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -90,6 +90,11 @@ extern inline void aluMatrixfSet(aluMatrixf *matrix, ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23, ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33); +extern inline void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); +extern inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); +extern inline float ScaleAzimuthFront(float azimuth, float scale); +extern inline void ComputePanGains(const MixParams *dry, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); + /* Cone scalar */ ALfloat ConeScale = 1.0f; diff --git a/Alc/ambdec.h b/Alc/ambdec.h index 0bb84072..7776ae11 100644 --- a/Alc/ambdec.h +++ b/Alc/ambdec.h @@ -4,6 +4,10 @@ #include "alstring.h" #include "alMain.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Helpers to read .ambdec configuration files. */ enum AmbDecScaleType { @@ -43,4 +47,8 @@ void ambdec_init(AmbDecConf *conf); void ambdec_deinit(AmbDecConf *conf); int ambdec_load(AmbDecConf *conf, const char *fname); +#ifdef __cplusplus +} // extern "C" +#endif + #endif /* AMBDEC_H */ diff --git a/Alc/hrtf.h b/Alc/hrtf.h index dab6a28e..1cdfe568 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -9,6 +9,10 @@ #include "atomic.h" +#ifdef __cplusplus +extern "C" { +#endif + #define HRTF_HISTORY_BITS (6) #define HRTF_HISTORY_LENGTH (1< -#include -#include -#include -#include - -#include "alMain.h" -#include "alAuxEffectSlot.h" -#include "alu.h" -#include "alconfig.h" -#include "bool.h" -#include "ambdec.h" -#include "bformatdec.h" -#include "filters/splitter.h" -#include "uhjfilter.h" -#include "bs2b.h" - - -extern inline void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); -extern inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); -extern inline float ScaleAzimuthFront(float azimuth, float scale); -extern inline void ComputePanGains(const MixParams *dry, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); - - -static const ALsizei FuMa2ACN[MAX_AMBI_COEFFS] = { - 0, /* W */ - 3, /* X */ - 1, /* Y */ - 2, /* Z */ - 6, /* R */ - 7, /* S */ - 5, /* T */ - 8, /* U */ - 4, /* V */ - 12, /* K */ - 13, /* L */ - 11, /* M */ - 14, /* N */ - 10, /* O */ - 15, /* P */ - 9, /* Q */ -}; -static const ALsizei ACN2ACN[MAX_AMBI_COEFFS] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15 -}; - - -void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread, - ALfloat coeffs[MAX_AMBI_COEFFS]) -{ - /* Zeroth-order */ - coeffs[0] = 1.0f; /* ACN 0 = 1 */ - /* First-order */ - coeffs[1] = SQRTF_3 * y; /* ACN 1 = sqrt(3) * Y */ - coeffs[2] = SQRTF_3 * z; /* ACN 2 = sqrt(3) * Z */ - coeffs[3] = SQRTF_3 * x; /* ACN 3 = sqrt(3) * X */ - /* Second-order */ - coeffs[4] = 3.872983346f * x * y; /* ACN 4 = sqrt(15) * X * Y */ - coeffs[5] = 3.872983346f * y * z; /* ACN 5 = sqrt(15) * Y * Z */ - coeffs[6] = 1.118033989f * (3.0f*z*z - 1.0f); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */ - coeffs[7] = 3.872983346f * x * z; /* ACN 7 = sqrt(15) * X * Z */ - coeffs[8] = 1.936491673f * (x*x - y*y); /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */ - /* Third-order */ - coeffs[9] = 2.091650066f * y * (3.0f*x*x - y*y); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */ - coeffs[10] = 10.246950766f * z * x * y; /* ACN 10 = sqrt(105) * Z * X * Y */ - coeffs[11] = 1.620185175f * y * (5.0f*z*z - 1.0f); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */ - coeffs[12] = 1.322875656f * z * (5.0f*z*z - 3.0f); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */ - coeffs[13] = 1.620185175f * x * (5.0f*z*z - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */ - coeffs[14] = 5.123475383f * z * (x*x - y*y); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */ - coeffs[15] = 2.091650066f * x * (x*x - 3.0f*y*y); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */ - - if(spread > 0.0f) - { - /* Implement the spread by using a spherical source that subtends the - * angle spread. See: - * http://www.ppsloan.org/publications/StupidSH36.pdf - Appendix A3 - * - * When adjusted for N3D normalization instead of SN3D, these - * calculations are: - * - * ZH0 = -sqrt(pi) * (-1+ca); - * ZH1 = 0.5*sqrt(pi) * sa*sa; - * ZH2 = -0.5*sqrt(pi) * ca*(-1+ca)*(ca+1); - * ZH3 = -0.125*sqrt(pi) * (-1+ca)*(ca+1)*(5*ca*ca - 1); - * ZH4 = -0.125*sqrt(pi) * ca*(-1+ca)*(ca+1)*(7*ca*ca - 3); - * ZH5 = -0.0625*sqrt(pi) * (-1+ca)*(ca+1)*(21*ca*ca*ca*ca - 14*ca*ca + 1); - * - * The gain of the source is compensated for size, so that the - * loundness doesn't depend on the spread. Thus: - * - * ZH0 = 1.0f; - * ZH1 = 0.5f * (ca+1.0f); - * ZH2 = 0.5f * (ca+1.0f)*ca; - * ZH3 = 0.125f * (ca+1.0f)*(5.0f*ca*ca - 1.0f); - * ZH4 = 0.125f * (ca+1.0f)*(7.0f*ca*ca - 3.0f)*ca; - * ZH5 = 0.0625f * (ca+1.0f)*(21.0f*ca*ca*ca*ca - 14.0f*ca*ca + 1.0f); - */ - ALfloat ca = cosf(spread * 0.5f); - /* Increase the source volume by up to +3dB for a full spread. */ - ALfloat scale = sqrtf(1.0f + spread/F_TAU); - - ALfloat ZH0_norm = scale; - ALfloat ZH1_norm = 0.5f * (ca+1.f) * scale; - ALfloat ZH2_norm = 0.5f * (ca+1.f)*ca * scale; - ALfloat ZH3_norm = 0.125f * (ca+1.f)*(5.f*ca*ca-1.f) * scale; - - /* Zeroth-order */ - coeffs[0] *= ZH0_norm; - /* First-order */ - coeffs[1] *= ZH1_norm; - coeffs[2] *= ZH1_norm; - coeffs[3] *= ZH1_norm; - /* Second-order */ - coeffs[4] *= ZH2_norm; - coeffs[5] *= ZH2_norm; - coeffs[6] *= ZH2_norm; - coeffs[7] *= ZH2_norm; - coeffs[8] *= ZH2_norm; - /* Third-order */ - coeffs[9] *= ZH3_norm; - coeffs[10] *= ZH3_norm; - coeffs[11] *= ZH3_norm; - coeffs[12] *= ZH3_norm; - coeffs[13] *= ZH3_norm; - coeffs[14] *= ZH3_norm; - coeffs[15] *= ZH3_norm; - } -} - - -void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) -{ - ALsizei i, j; - - for(i = 0;i < numchans;i++) - { - float gain = 0.0f; - for(j = 0;j < numcoeffs;j++) - gain += chancoeffs[i][j]*coeffs[j]; - gains[i] = clampf(gain, 0.0f, 1.0f) * ingain; - } - for(;i < MAX_OUTPUT_CHANNELS;i++) - gains[i] = 0.0f; -} - -void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) -{ - ALsizei i; - - for(i = 0;i < numchans;i++) - gains[i] = chanmap[i].Scale * coeffs[chanmap[i].Index] * ingain; - for(;i < MAX_OUTPUT_CHANNELS;i++) - gains[i] = 0.0f; -} - - -static inline const char *GetLabelFromChannel(enum Channel channel) -{ - switch(channel) - { - case FrontLeft: return "front-left"; - case FrontRight: return "front-right"; - case FrontCenter: return "front-center"; - case LFE: return "lfe"; - case BackLeft: return "back-left"; - case BackRight: return "back-right"; - case BackCenter: return "back-center"; - case SideLeft: return "side-left"; - case SideRight: return "side-right"; - - case UpperFrontLeft: return "upper-front-left"; - case UpperFrontRight: return "upper-front-right"; - case UpperBackLeft: return "upper-back-left"; - case UpperBackRight: return "upper-back-right"; - case LowerFrontLeft: return "lower-front-left"; - case LowerFrontRight: return "lower-front-right"; - case LowerBackLeft: return "lower-back-left"; - case LowerBackRight: return "lower-back-right"; - - case Aux0: return "aux-0"; - case Aux1: return "aux-1"; - case Aux2: return "aux-2"; - case Aux3: return "aux-3"; - case Aux4: return "aux-4"; - case Aux5: return "aux-5"; - case Aux6: return "aux-6"; - case Aux7: return "aux-7"; - case Aux8: return "aux-8"; - case Aux9: return "aux-9"; - case Aux10: return "aux-10"; - case Aux11: return "aux-11"; - case Aux12: return "aux-12"; - case Aux13: return "aux-13"; - case Aux14: return "aux-14"; - case Aux15: return "aux-15"; - - case InvalidChannel: break; - } - return "(unknown)"; -} - - -typedef struct ChannelMap { - enum Channel ChanName; - ChannelConfig Config; -} ChannelMap; - -static void SetChannelMap(const enum Channel devchans[MAX_OUTPUT_CHANNELS], - ChannelConfig *ambicoeffs, const ChannelMap *chanmap, - ALsizei count, ALsizei *outcount) -{ - ALsizei maxchans = 0; - ALsizei i, j; - - for(i = 0;i < count;i++) - { - ALint idx = GetChannelIndex(devchans, chanmap[i].ChanName); - if(idx < 0) - { - ERR("Failed to find %s channel in device\n", - GetLabelFromChannel(chanmap[i].ChanName)); - continue; - } - - maxchans = maxi(maxchans, idx+1); - for(j = 0;j < MAX_AMBI_COEFFS;j++) - ambicoeffs[idx][j] = chanmap[i].Config[j]; - } - *outcount = mini(maxchans, MAX_OUTPUT_CHANNELS); -} - -static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei speakermap[MAX_OUTPUT_CHANNELS]) -{ - ALsizei i; - - for(i = 0;i < conf->NumSpeakers;i++) - { - enum Channel ch; - int chidx = -1; - - /* NOTE: AmbDec does not define any standard speaker names, however - * for this to work we have to by able to find the output channel - * the speaker definition corresponds to. Therefore, OpenAL Soft - * requires these channel labels to be recognized: - * - * LF = Front left - * RF = Front right - * LS = Side left - * RS = Side right - * LB = Back left - * RB = Back right - * CE = Front center - * CB = Back center - * - * Additionally, surround51 will acknowledge back speakers for side - * channels, and surround51rear will acknowledge side speakers for - * back channels, to avoid issues with an ambdec expecting 5.1 to - * use the side channels when the device is configured for back, - * and vice-versa. - */ - if(alstr_cmp_cstr(conf->Speakers[i].Name, "LF") == 0) - ch = FrontLeft; - else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RF") == 0) - ch = FrontRight; - else if(alstr_cmp_cstr(conf->Speakers[i].Name, "CE") == 0) - ch = FrontCenter; - else if(alstr_cmp_cstr(conf->Speakers[i].Name, "LS") == 0) - { - if(device->FmtChans == DevFmtX51Rear) - ch = BackLeft; - else - ch = SideLeft; - } - else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RS") == 0) - { - if(device->FmtChans == DevFmtX51Rear) - ch = BackRight; - else - ch = SideRight; - } - else if(alstr_cmp_cstr(conf->Speakers[i].Name, "LB") == 0) - { - if(device->FmtChans == DevFmtX51) - ch = SideLeft; - else - ch = BackLeft; - } - else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RB") == 0) - { - if(device->FmtChans == DevFmtX51) - ch = SideRight; - else - ch = BackRight; - } - else if(alstr_cmp_cstr(conf->Speakers[i].Name, "CB") == 0) - ch = BackCenter; - else - { - const char *name = alstr_get_cstr(conf->Speakers[i].Name); - unsigned int n; - char c; - - if(sscanf(name, "AUX%u%c", &n, &c) == 1 && n < 16) - ch = Aux0+n; - else - { - ERR("AmbDec speaker label \"%s\" not recognized\n", name); - return false; - } - } - chidx = GetChannelIdxByName(&device->RealOut, ch); - if(chidx == -1) - { - ERR("Failed to lookup AmbDec speaker label %s\n", - alstr_get_cstr(conf->Speakers[i].Name)); - return false; - } - speakermap[i] = chidx; - } - - return true; -} - - -static const ChannelMap MonoCfg[1] = { - { FrontCenter, { 1.0f } }, -}, StereoCfg[2] = { - { FrontLeft, { 5.00000000e-1f, 2.88675135e-1f, 0.0f, 5.52305643e-2f } }, - { FrontRight, { 5.00000000e-1f, -2.88675135e-1f, 0.0f, 5.52305643e-2f } }, -}, QuadCfg[4] = { - { BackLeft, { 3.53553391e-1f, 2.04124145e-1f, 0.0f, -2.04124145e-1f } }, - { FrontLeft, { 3.53553391e-1f, 2.04124145e-1f, 0.0f, 2.04124145e-1f } }, - { FrontRight, { 3.53553391e-1f, -2.04124145e-1f, 0.0f, 2.04124145e-1f } }, - { BackRight, { 3.53553391e-1f, -2.04124145e-1f, 0.0f, -2.04124145e-1f } }, -}, X51SideCfg[4] = { - { SideLeft, { 3.33000782e-1f, 1.89084803e-1f, 0.0f, -2.00042375e-1f, -2.12307769e-2f, 0.0f, 0.0f, 0.0f, -1.14579885e-2f } }, - { FrontLeft, { 1.88542860e-1f, 1.27709292e-1f, 0.0f, 1.66295695e-1f, 7.30571517e-2f, 0.0f, 0.0f, 0.0f, 2.10901184e-2f } }, - { FrontRight, { 1.88542860e-1f, -1.27709292e-1f, 0.0f, 1.66295695e-1f, -7.30571517e-2f, 0.0f, 0.0f, 0.0f, 2.10901184e-2f } }, - { SideRight, { 3.33000782e-1f, -1.89084803e-1f, 0.0f, -2.00042375e-1f, 2.12307769e-2f, 0.0f, 0.0f, 0.0f, -1.14579885e-2f } }, -}, X51RearCfg[4] = { - { BackLeft, { 3.33000782e-1f, 1.89084803e-1f, 0.0f, -2.00042375e-1f, -2.12307769e-2f, 0.0f, 0.0f, 0.0f, -1.14579885e-2f } }, - { FrontLeft, { 1.88542860e-1f, 1.27709292e-1f, 0.0f, 1.66295695e-1f, 7.30571517e-2f, 0.0f, 0.0f, 0.0f, 2.10901184e-2f } }, - { FrontRight, { 1.88542860e-1f, -1.27709292e-1f, 0.0f, 1.66295695e-1f, -7.30571517e-2f, 0.0f, 0.0f, 0.0f, 2.10901184e-2f } }, - { BackRight, { 3.33000782e-1f, -1.89084803e-1f, 0.0f, -2.00042375e-1f, 2.12307769e-2f, 0.0f, 0.0f, 0.0f, -1.14579885e-2f } }, -}, X61Cfg[6] = { - { SideLeft, { 2.04460341e-1f, 2.17177926e-1f, 0.0f, -4.39996780e-2f, -2.60790269e-2f, 0.0f, 0.0f, 0.0f, -6.87239792e-2f } }, - { FrontLeft, { 1.58923161e-1f, 9.21772680e-2f, 0.0f, 1.59658796e-1f, 6.66278083e-2f, 0.0f, 0.0f, 0.0f, 3.84686854e-2f } }, - { FrontRight, { 1.58923161e-1f, -9.21772680e-2f, 0.0f, 1.59658796e-1f, -6.66278083e-2f, 0.0f, 0.0f, 0.0f, 3.84686854e-2f } }, - { SideRight, { 2.04460341e-1f, -2.17177926e-1f, 0.0f, -4.39996780e-2f, 2.60790269e-2f, 0.0f, 0.0f, 0.0f, -6.87239792e-2f } }, - { BackCenter, { 2.50001688e-1f, 0.00000000e+0f, 0.0f, -2.50000094e-1f, 0.00000000e+0f, 0.0f, 0.0f, 0.0f, 6.05133395e-2f } }, -}, X71Cfg[6] = { - { BackLeft, { 2.04124145e-1f, 1.08880247e-1f, 0.0f, -1.88586120e-1f, -1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, 3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, - { SideLeft, { 2.04124145e-1f, 2.17760495e-1f, 0.0f, 0.00000000e+0f, 0.00000000e+0f, 0.0f, 0.0f, 0.0f, -1.49071198e-1f, -3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, - { FrontLeft, { 2.04124145e-1f, 1.08880247e-1f, 0.0f, 1.88586120e-1f, 1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, 3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, - { FrontRight, { 2.04124145e-1f, -1.08880247e-1f, 0.0f, 1.88586120e-1f, -1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, -3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, - { SideRight, { 2.04124145e-1f, -2.17760495e-1f, 0.0f, 0.00000000e+0f, 0.00000000e+0f, 0.0f, 0.0f, 0.0f, -1.49071198e-1f, 3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, - { BackRight, { 2.04124145e-1f, -1.08880247e-1f, 0.0f, -1.88586120e-1f, 1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, -3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, -}; - -static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, - const ALsizei *RESTRICT chans_per_order) -{ - const char *devname = alstr_get_cstr(device->DeviceName); - ALsizei i; - - if(GetConfigValueBool(devname, "decoder", "nfc", 1) && ctrl_dist > 0.0f) - { - /* NFC is only used when AvgSpeakerDist is greater than 0, and can only - * be used when rendering to an ambisonic buffer. - */ - device->AvgSpeakerDist = minf(ctrl_dist, 10.0f); - TRACE("Using near-field reference distance: %.2f meters\n", device->AvgSpeakerDist); - - for(i = 0;i < order+1;i++) - device->NumChannelsPerOrder[i] = chans_per_order[i]; - for(;i < MAX_AMBI_ORDER+1;i++) - device->NumChannelsPerOrder[i] = 0; - } -} - -static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) -{ - const char *devname = alstr_get_cstr(device->DeviceName); - ALfloat maxdist = 0.0f; - size_t total = 0; - ALsizei i; - - for(i = 0;i < conf->NumSpeakers;i++) - maxdist = maxf(maxdist, conf->Speakers[i].Distance); - - if(GetConfigValueBool(devname, "decoder", "distance-comp", 1) && maxdist > 0.0f) - { - ALfloat srate = (ALfloat)device->Frequency; - for(i = 0;i < conf->NumSpeakers;i++) - { - ALsizei chan = speakermap[i]; - ALfloat delay; - - /* Distance compensation only delays in steps of the sample rate. - * This is a bit less accurate since the delay time falls to the - * nearest sample time, but it's far simpler as it doesn't have to - * deal with phase offsets. This means at 48khz, for instance, the - * distance delay will be in steps of about 7 millimeters. - */ - delay = floorf((maxdist-conf->Speakers[i].Distance) / SPEEDOFSOUNDMETRESPERSEC * - srate + 0.5f); - if(delay >= (ALfloat)MAX_DELAY_LENGTH) - ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n", - alstr_get_cstr(conf->Speakers[i].Name), delay, MAX_DELAY_LENGTH); - - device->ChannelDelay[chan].Length = (ALsizei)clampf( - delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1) - ); - device->ChannelDelay[chan].Gain = conf->Speakers[i].Distance / maxdist; - TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan, - alstr_get_cstr(conf->Speakers[i].Name), device->ChannelDelay[chan].Length, - device->ChannelDelay[chan].Gain - ); - - /* Round up to the next 4th sample, so each channel buffer starts - * 16-byte aligned. - */ - total += RoundUp(device->ChannelDelay[chan].Length, 4); - } - } - - if(total > 0) - { - device->ChannelDelay[0].Buffer = al_calloc(16, total * sizeof(ALfloat)); - for(i = 1;i < MAX_OUTPUT_CHANNELS;i++) - { - size_t len = RoundUp(device->ChannelDelay[i-1].Length, 4); - device->ChannelDelay[i].Buffer = device->ChannelDelay[i-1].Buffer + len; - } - } -} - -static void InitPanning(ALCdevice *device) -{ - const ChannelMap *chanmap = NULL; - ALsizei coeffcount = 0; - ALsizei count = 0; - ALsizei i, j; - - switch(device->FmtChans) - { - case DevFmtMono: - count = COUNTOF(MonoCfg); - chanmap = MonoCfg; - coeffcount = 1; - break; - - case DevFmtStereo: - count = COUNTOF(StereoCfg); - chanmap = StereoCfg; - coeffcount = 4; - break; - - case DevFmtQuad: - count = COUNTOF(QuadCfg); - chanmap = QuadCfg; - coeffcount = 4; - break; - - case DevFmtX51: - count = COUNTOF(X51SideCfg); - chanmap = X51SideCfg; - coeffcount = 9; - break; - - case DevFmtX51Rear: - count = COUNTOF(X51RearCfg); - chanmap = X51RearCfg; - coeffcount = 9; - break; - - case DevFmtX61: - count = COUNTOF(X61Cfg); - chanmap = X61Cfg; - coeffcount = 9; - break; - - case DevFmtX71: - count = COUNTOF(X71Cfg); - chanmap = X71Cfg; - coeffcount = 16; - break; - - case DevFmtAmbi3D: - break; - } - - if(device->FmtChans == DevFmtAmbi3D) - { - const char *devname = alstr_get_cstr(device->DeviceName); - const ALsizei *acnmap = (device->AmbiLayout == AmbiLayout_FuMa) ? FuMa2ACN : ACN2ACN; - const ALfloat *n3dscale = (device->AmbiScale == AmbiNorm_FuMa) ? FuMa2N3DScale : - (device->AmbiScale == AmbiNorm_SN3D) ? SN3D2N3DScale : - /*(device->AmbiScale == AmbiNorm_N3D) ?*/ N3D2N3DScale; - ALfloat nfc_delay = 0.0f; - - count = (device->AmbiOrder == 3) ? 16 : - (device->AmbiOrder == 2) ? 9 : - (device->AmbiOrder == 1) ? 4 : 1; - for(i = 0;i < count;i++) - { - ALsizei acn = acnmap[i]; - device->Dry.Ambi.Map[i].Scale = 1.0f/n3dscale[acn]; - device->Dry.Ambi.Map[i].Index = acn; - } - device->Dry.CoeffCount = 0; - device->Dry.NumChannels = count; - - if(device->AmbiOrder < 2) - { - device->FOAOut.Ambi = device->Dry.Ambi; - device->FOAOut.CoeffCount = device->Dry.CoeffCount; - device->FOAOut.NumChannels = 0; - } - else - { - ALfloat w_scale=1.0f, xyz_scale=1.0f; - - /* FOA output is always ACN+N3D for higher-order ambisonic output. - * The upsampler expects this and will convert it for output. - */ - memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); - for(i = 0;i < 4;i++) - { - device->FOAOut.Ambi.Map[i].Scale = 1.0f; - device->FOAOut.Ambi.Map[i].Index = i; - } - device->FOAOut.CoeffCount = 0; - device->FOAOut.NumChannels = 4; - - if(device->AmbiOrder >= 3) - { - w_scale = W_SCALE_3H3P; - xyz_scale = XYZ_SCALE_3H3P; - } - else - { - w_scale = W_SCALE_2H2P; - xyz_scale = XYZ_SCALE_2H2P; - } - ambiup_reset(device->AmbiUp, device, w_scale, xyz_scale); - } - - if(ConfigValueFloat(devname, "decoder", "nfc-ref-delay", &nfc_delay) && nfc_delay > 0.0f) - { - static const ALsizei chans_per_order[MAX_AMBI_ORDER+1] = { - 1, 3, 5, 7 - }; - nfc_delay = clampf(nfc_delay, 0.001f, 1000.0f); - InitNearFieldCtrl(device, nfc_delay * SPEEDOFSOUNDMETRESPERSEC, - device->AmbiOrder, chans_per_order); - } - } - else - { - ALfloat w_scale, xyz_scale; - - SetChannelMap(device->RealOut.ChannelName, device->Dry.Ambi.Coeffs, - chanmap, count, &device->Dry.NumChannels); - device->Dry.CoeffCount = coeffcount; - - w_scale = (device->Dry.CoeffCount > 9) ? W_SCALE_3H0P : - (device->Dry.CoeffCount > 4) ? W_SCALE_2H0P : 1.0f; - xyz_scale = (device->Dry.CoeffCount > 9) ? XYZ_SCALE_3H0P : - (device->Dry.CoeffCount > 4) ? XYZ_SCALE_2H0P : 1.0f; - - memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); - for(i = 0;i < device->Dry.NumChannels;i++) - { - device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0] * w_scale; - for(j = 1;j < 4;j++) - device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * xyz_scale; - } - device->FOAOut.CoeffCount = 4; - device->FOAOut.NumChannels = 0; - } - device->RealOut.NumChannels = 0; -} - -static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) -{ - ChannelMap chanmap[MAX_OUTPUT_CHANNELS]; - const ALfloat *coeff_scale = N3D2N3DScale; - ALfloat w_scale = 1.0f; - ALfloat xyz_scale = 1.0f; - ALsizei i, j; - - if(conf->FreqBands != 1) - ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n", - conf->XOverFreq); - - if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) - { - if(conf->ChanMask > 0x1ff) - { - w_scale = W_SCALE_3H3P; - xyz_scale = XYZ_SCALE_3H3P; - } - else if(conf->ChanMask > 0xf) - { - w_scale = W_SCALE_2H2P; - xyz_scale = XYZ_SCALE_2H2P; - } - } - else - { - if(conf->ChanMask > 0x1ff) - { - w_scale = W_SCALE_3H0P; - xyz_scale = XYZ_SCALE_3H0P; - } - else if(conf->ChanMask > 0xf) - { - w_scale = W_SCALE_2H0P; - xyz_scale = XYZ_SCALE_2H0P; - } - } - - if(conf->CoeffScale == ADS_SN3D) - coeff_scale = SN3D2N3DScale; - else if(conf->CoeffScale == ADS_FuMa) - coeff_scale = FuMa2N3DScale; - - for(i = 0;i < conf->NumSpeakers;i++) - { - ALsizei chan = speakermap[i]; - ALfloat gain; - ALsizei k = 0; - - for(j = 0;j < MAX_AMBI_COEFFS;j++) - chanmap[i].Config[j] = 0.0f; - - chanmap[i].ChanName = device->RealOut.ChannelName[chan]; - for(j = 0;j < MAX_AMBI_COEFFS;j++) - { - if(j == 0) gain = conf->HFOrderGain[0]; - else if(j == 1) gain = conf->HFOrderGain[1]; - else if(j == 4) gain = conf->HFOrderGain[2]; - else if(j == 9) gain = conf->HFOrderGain[3]; - if((conf->ChanMask&(1<HFMatrix[i][k++] / coeff_scale[j] * gain; - } - } - - SetChannelMap(device->RealOut.ChannelName, device->Dry.Ambi.Coeffs, chanmap, - conf->NumSpeakers, &device->Dry.NumChannels); - device->Dry.CoeffCount = (conf->ChanMask > 0x1ff) ? 16 : - (conf->ChanMask > 0xf) ? 9 : 4; - - memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); - for(i = 0;i < device->Dry.NumChannels;i++) - { - device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0] * w_scale; - for(j = 1;j < 4;j++) - device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * xyz_scale; - } - device->FOAOut.CoeffCount = 4; - device->FOAOut.NumChannels = 0; - - device->RealOut.NumChannels = 0; - - InitDistanceComp(device, conf, speakermap); -} - -static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) -{ - static const ALsizei chans_per_order2d[MAX_AMBI_ORDER+1] = { 1, 2, 2, 2 }; - static const ALsizei chans_per_order3d[MAX_AMBI_ORDER+1] = { 1, 3, 5, 7 }; - ALfloat avg_dist; - ALsizei count; - ALsizei i; - - if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) - { - count = (conf->ChanMask > 0x1ff) ? 16 : - (conf->ChanMask > 0xf) ? 9 : 4; - for(i = 0;i < count;i++) - { - device->Dry.Ambi.Map[i].Scale = 1.0f; - device->Dry.Ambi.Map[i].Index = i; - } - } - else - { - static const int map[MAX_AMBI2D_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; - - count = (conf->ChanMask > 0x1ff) ? 7 : - (conf->ChanMask > 0xf) ? 5 : 3; - for(i = 0;i < count;i++) - { - device->Dry.Ambi.Map[i].Scale = 1.0f; - device->Dry.Ambi.Map[i].Index = map[i]; - } - } - device->Dry.CoeffCount = 0; - device->Dry.NumChannels = count; - - TRACE("Enabling %s-band %s-order%s ambisonic decoder\n", - (conf->FreqBands == 1) ? "single" : "dual", - (conf->ChanMask > 0xf) ? (conf->ChanMask > 0x1ff) ? "third" : "second" : "first", - (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? " periphonic" : "" - ); - bformatdec_reset(device->AmbiDecoder, conf, count, device->Frequency, speakermap); - - if(conf->ChanMask <= 0xf) - { - device->FOAOut.Ambi = device->Dry.Ambi; - device->FOAOut.CoeffCount = device->Dry.CoeffCount; - device->FOAOut.NumChannels = 0; - } - else - { - memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); - if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) - { - count = 4; - for(i = 0;i < count;i++) - { - device->FOAOut.Ambi.Map[i].Scale = 1.0f; - device->FOAOut.Ambi.Map[i].Index = i; - } - } - else - { - static const int map[3] = { 0, 1, 3 }; - count = 3; - for(i = 0;i < count;i++) - { - device->FOAOut.Ambi.Map[i].Scale = 1.0f; - device->FOAOut.Ambi.Map[i].Index = map[i]; - } - } - device->FOAOut.CoeffCount = 0; - device->FOAOut.NumChannels = count; - } - - device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - - avg_dist = 0.0f; - for(i = 0;i < conf->NumSpeakers;i++) - avg_dist += conf->Speakers[i].Distance; - avg_dist /= (ALfloat)conf->NumSpeakers; - InitNearFieldCtrl(device, avg_dist, - (conf->ChanMask > 0x1ff) ? 3 : (conf->ChanMask > 0xf) ? 2 : 1, - (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? chans_per_order3d : chans_per_order2d - ); - - InitDistanceComp(device, conf, speakermap); -} - -static void InitHrtfPanning(ALCdevice *device) -{ - /* NOTE: azimuth goes clockwise. */ - static const struct AngularPoint AmbiPoints[] = { - { DEG2RAD( 90.0f), DEG2RAD( 0.0f) }, - { DEG2RAD( 35.2643897f), DEG2RAD( 45.0f) }, - { DEG2RAD( 35.2643897f), DEG2RAD( 135.0f) }, - { DEG2RAD( 35.2643897f), DEG2RAD(-135.0f) }, - { DEG2RAD( 35.2643897f), DEG2RAD( -45.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( 0.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( 45.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( 90.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( 135.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( 180.0f) }, - { DEG2RAD( 0.0f), DEG2RAD(-135.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( -90.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( -45.0f) }, - { DEG2RAD(-35.2643897f), DEG2RAD( 45.0f) }, - { DEG2RAD(-35.2643897f), DEG2RAD( 135.0f) }, - { DEG2RAD(-35.2643897f), DEG2RAD(-135.0f) }, - { DEG2RAD(-35.2643897f), DEG2RAD( -45.0f) }, - { DEG2RAD(-90.0f), DEG2RAD( 0.0f) }, - }; - static const ALfloat AmbiMatrixFOA[][MAX_AMBI_COEFFS] = { - { 5.55555556e-02f, 0.00000000e+00f, 1.23717915e-01f, 0.00000000e+00f }, - { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f }, - { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f }, - { 5.55555556e-02f, 5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f }, - { 5.55555556e-02f, 5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f }, - { 5.55555556e-02f, 0.00000000e+00f, 0.00000000e+00f, 8.66025404e-02f }, - { 5.55555556e-02f, -6.12372435e-02f, 0.00000000e+00f, 6.12372435e-02f }, - { 5.55555556e-02f, -8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f }, - { 5.55555556e-02f, -6.12372435e-02f, 0.00000000e+00f, -6.12372435e-02f }, - { 5.55555556e-02f, 0.00000000e+00f, 0.00000000e+00f, -8.66025404e-02f }, - { 5.55555556e-02f, 6.12372435e-02f, 0.00000000e+00f, -6.12372435e-02f }, - { 5.55555556e-02f, 8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f }, - { 5.55555556e-02f, 6.12372435e-02f, 0.00000000e+00f, 6.12372435e-02f }, - { 5.55555556e-02f, -5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f }, - { 5.55555556e-02f, -5.00000000e-02f, -7.14285715e-02f, -5.00000000e-02f }, - { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, -5.00000000e-02f }, - { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f }, - { 5.55555556e-02f, 0.00000000e+00f, -1.23717915e-01f, 0.00000000e+00f }, - }, AmbiMatrixHOA[][MAX_AMBI_COEFFS] = { - { 5.55555556e-02f, 0.00000000e+00f, 1.23717915e-01f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, - { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, 5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, 5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, 0.00000000e+00f, 0.00000000e+00f, 8.66025404e-02f, 0.00000000e+00f, 1.29099445e-01f }, - { 5.55555556e-02f, -6.12372435e-02f, 0.00000000e+00f, 6.12372435e-02f, -6.83467648e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, -8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -1.29099445e-01f }, - { 5.55555556e-02f, -6.12372435e-02f, 0.00000000e+00f, -6.12372435e-02f, 6.83467648e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, 0.00000000e+00f, 0.00000000e+00f, -8.66025404e-02f, 0.00000000e+00f, 1.29099445e-01f }, - { 5.55555556e-02f, 6.12372435e-02f, 0.00000000e+00f, -6.12372435e-02f, -6.83467648e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, 8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -1.29099445e-01f }, - { 5.55555556e-02f, 6.12372435e-02f, 0.00000000e+00f, 6.12372435e-02f, 6.83467648e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, -5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, -5.00000000e-02f, -7.14285715e-02f, -5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, -5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, 0.00000000e+00f, -1.23717915e-01f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, - }; - static const ALfloat AmbiOrderHFGainFOA[MAX_AMBI_ORDER+1] = { - 3.00000000e+00f, 1.73205081e+00f - }, AmbiOrderHFGainHOA[MAX_AMBI_ORDER+1] = { - 2.40192231e+00f, 1.86052102e+00f, 9.60768923e-01f - }; - static const ALsizei IndexMap[6] = { 0, 1, 2, 3, 4, 8 }; - static const ALsizei ChansPerOrder[MAX_AMBI_ORDER+1] = { 1, 3, 2, 0 }; - const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_COEFFS] = AmbiMatrixFOA; - const ALfloat *RESTRICT AmbiOrderHFGain = AmbiOrderHFGainFOA; - ALsizei count = 4; - ALsizei i; - - static_assert(COUNTOF(AmbiPoints) == COUNTOF(AmbiMatrixFOA), "FOA Ambisonic HRTF mismatch"); - static_assert(COUNTOF(AmbiPoints) == COUNTOF(AmbiMatrixHOA), "HOA Ambisonic HRTF mismatch"); - - if(device->AmbiUp) - { - AmbiMatrix = AmbiMatrixHOA; - AmbiOrderHFGain = AmbiOrderHFGainHOA; - count = COUNTOF(IndexMap); - } - - device->Hrtf = al_calloc(16, FAM_SIZE(DirectHrtfState, Chan, count)); - - for(i = 0;i < count;i++) - { - device->Dry.Ambi.Map[i].Scale = 1.0f; - device->Dry.Ambi.Map[i].Index = IndexMap[i]; - } - device->Dry.CoeffCount = 0; - device->Dry.NumChannels = count; - - if(device->AmbiUp) - { - memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); - for(i = 0;i < 4;i++) - { - device->FOAOut.Ambi.Map[i].Scale = 1.0f; - device->FOAOut.Ambi.Map[i].Index = i; - } - device->FOAOut.CoeffCount = 0; - device->FOAOut.NumChannels = 4; - - ambiup_reset(device->AmbiUp, device, AmbiOrderHFGainFOA[0] / AmbiOrderHFGain[0], - AmbiOrderHFGainFOA[1] / AmbiOrderHFGain[1]); - } - else - { - device->FOAOut.Ambi = device->Dry.Ambi; - device->FOAOut.CoeffCount = device->Dry.CoeffCount; - device->FOAOut.NumChannels = 0; - } - - device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - - BuildBFormatHrtf(device->HrtfHandle, - device->Hrtf, device->Dry.NumChannels, AmbiPoints, AmbiMatrix, COUNTOF(AmbiPoints), - AmbiOrderHFGain - ); - - InitNearFieldCtrl(device, device->HrtfHandle->distance, device->AmbiUp ? 2 : 1, - ChansPerOrder); -} - -static void InitUhjPanning(ALCdevice *device) -{ - ALsizei count = 3; - ALsizei i; - - for(i = 0;i < count;i++) - { - ALsizei acn = FuMa2ACN[i]; - device->Dry.Ambi.Map[i].Scale = 1.0f/FuMa2N3DScale[acn]; - device->Dry.Ambi.Map[i].Index = acn; - } - device->Dry.CoeffCount = 0; - device->Dry.NumChannels = count; - - device->FOAOut.Ambi = device->Dry.Ambi; - device->FOAOut.CoeffCount = device->Dry.CoeffCount; - device->FOAOut.NumChannels = 0; - - device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); -} - -void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq) -{ - /* Hold the HRTF the device last used, in case it's used again. */ - struct Hrtf *old_hrtf = device->HrtfHandle; - const char *mode; - bool headphones; - int bs2blevel; - size_t i; - - al_free(device->Hrtf); - device->Hrtf = NULL; - device->HrtfHandle = NULL; - alstr_clear(&device->HrtfName); - device->Render_Mode = NormalRender; - - memset(&device->Dry.Ambi, 0, sizeof(device->Dry.Ambi)); - device->Dry.CoeffCount = 0; - device->Dry.NumChannels = 0; - for(i = 0;i < MAX_AMBI_ORDER+1;i++) - device->NumChannelsPerOrder[i] = 0; - - device->AvgSpeakerDist = 0.0f; - memset(device->ChannelDelay, 0, sizeof(device->ChannelDelay)); - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - { - device->ChannelDelay[i].Gain = 1.0f; - device->ChannelDelay[i].Length = 0; - } - - al_free(device->Stablizer); - device->Stablizer = NULL; - - if(device->FmtChans != DevFmtStereo) - { - ALsizei speakermap[MAX_OUTPUT_CHANNELS]; - const char *devname, *layout = NULL; - AmbDecConf conf, *pconf = NULL; - - if(old_hrtf) - Hrtf_DecRef(old_hrtf); - old_hrtf = NULL; - if(hrtf_appreq == Hrtf_Enable) - device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; - - ambdec_init(&conf); - - devname = alstr_get_cstr(device->DeviceName); - switch(device->FmtChans) - { - case DevFmtQuad: layout = "quad"; break; - case DevFmtX51: /* fall-through */ - case DevFmtX51Rear: layout = "surround51"; break; - case DevFmtX61: layout = "surround61"; break; - case DevFmtX71: layout = "surround71"; break; - /* Mono, Stereo, and Ambisonics output don't use custom decoders. */ - case DevFmtMono: - case DevFmtStereo: - case DevFmtAmbi3D: - break; - } - if(layout) - { - const char *fname; - if(ConfigValueStr(devname, "decoder", layout, &fname)) - { - if(!ambdec_load(&conf, fname)) - ERR("Failed to load layout file %s\n", fname); - else - { - if(conf.ChanMask > 0xffff) - ERR("Unsupported channel mask 0x%04x (max 0xffff)\n", conf.ChanMask); - else - { - if(MakeSpeakerMap(device, &conf, speakermap)) - pconf = &conf; - } - } - } - } - - if(pconf && GetConfigValueBool(devname, "decoder", "hq-mode", 0)) - { - ambiup_free(&device->AmbiUp); - if(!device->AmbiDecoder) - device->AmbiDecoder = bformatdec_alloc(); - } - else - { - bformatdec_free(&device->AmbiDecoder); - if(device->FmtChans != DevFmtAmbi3D || device->AmbiOrder < 2) - ambiup_free(&device->AmbiUp); - else - { - if(!device->AmbiUp) - device->AmbiUp = ambiup_alloc(); - } - } - - if(!pconf) - InitPanning(device); - else if(device->AmbiDecoder) - InitHQPanning(device, pconf, speakermap); - else - InitCustomPanning(device, pconf, speakermap); - - /* Enable the stablizer only for formats that have front-left, front- - * right, and front-center outputs. - */ - switch(device->FmtChans) - { - case DevFmtX51: - case DevFmtX51Rear: - case DevFmtX61: - case DevFmtX71: - if(GetConfigValueBool(devname, NULL, "front-stablizer", 0)) - { - /* Initialize band-splitting filters for the front-left and - * front-right channels, with a crossover at 5khz (could be - * higher). - */ - ALfloat scale = (ALfloat)(5000.0 / device->Frequency); - FrontStablizer *stablizer = al_calloc(16, sizeof(*stablizer)); - - bandsplit_init(&stablizer->LFilter, scale); - stablizer->RFilter = stablizer->LFilter; - - /* Initialize all-pass filters for all other channels. */ - splitterap_init(&stablizer->APFilter[0], scale); - for(i = 1;i < (size_t)device->RealOut.NumChannels;i++) - stablizer->APFilter[i] = stablizer->APFilter[0]; - - device->Stablizer = stablizer; - } - break; - case DevFmtMono: - case DevFmtStereo: - case DevFmtQuad: - case DevFmtAmbi3D: - break; - } - TRACE("Front stablizer %s\n", device->Stablizer ? "enabled" : "disabled"); - - ambdec_deinit(&conf); - return; - } - - bformatdec_free(&device->AmbiDecoder); - - headphones = device->IsHeadphones; - if(device->Type != Loopback) - { - const char *mode; - if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "stereo-mode", &mode)) - { - if(strcasecmp(mode, "headphones") == 0) - headphones = true; - else if(strcasecmp(mode, "speakers") == 0) - headphones = false; - else if(strcasecmp(mode, "auto") != 0) - ERR("Unexpected stereo-mode: %s\n", mode); - } - } - - if(hrtf_userreq == Hrtf_Default) - { - bool usehrtf = (headphones && hrtf_appreq != Hrtf_Disable) || - (hrtf_appreq == Hrtf_Enable); - if(!usehrtf) goto no_hrtf; - - device->HrtfStatus = ALC_HRTF_ENABLED_SOFT; - if(headphones && hrtf_appreq != Hrtf_Disable) - device->HrtfStatus = ALC_HRTF_HEADPHONES_DETECTED_SOFT; - } - else - { - if(hrtf_userreq != Hrtf_Enable) - { - if(hrtf_appreq == Hrtf_Enable) - device->HrtfStatus = ALC_HRTF_DENIED_SOFT; - goto no_hrtf; - } - device->HrtfStatus = ALC_HRTF_REQUIRED_SOFT; - } - - if(VECTOR_SIZE(device->HrtfList) == 0) - { - VECTOR_DEINIT(device->HrtfList); - device->HrtfList = EnumerateHrtf(device->DeviceName); - } - - if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->HrtfList)) - { - const EnumeratedHrtf *entry = &VECTOR_ELEM(device->HrtfList, hrtf_id); - struct Hrtf *hrtf = GetLoadedHrtf(entry->hrtf); - if(hrtf && hrtf->sampleRate == device->Frequency) - { - device->HrtfHandle = hrtf; - alstr_copy(&device->HrtfName, entry->name); - } - else if(hrtf) - Hrtf_DecRef(hrtf); - } - - for(i = 0;!device->HrtfHandle && i < VECTOR_SIZE(device->HrtfList);i++) - { - const EnumeratedHrtf *entry = &VECTOR_ELEM(device->HrtfList, i); - struct Hrtf *hrtf = GetLoadedHrtf(entry->hrtf); - if(hrtf && hrtf->sampleRate == device->Frequency) - { - device->HrtfHandle = hrtf; - alstr_copy(&device->HrtfName, entry->name); - } - else if(hrtf) - Hrtf_DecRef(hrtf); - } - - if(device->HrtfHandle) - { - if(old_hrtf) - Hrtf_DecRef(old_hrtf); - old_hrtf = NULL; - - device->Render_Mode = HrtfRender; - if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "hrtf-mode", &mode)) - { - if(strcasecmp(mode, "full") == 0) - device->Render_Mode = HrtfRender; - else if(strcasecmp(mode, "basic") == 0) - device->Render_Mode = NormalRender; - else - ERR("Unexpected hrtf-mode: %s\n", mode); - } - - if(device->Render_Mode == HrtfRender) - { - /* Don't bother with HOA when using full HRTF rendering. Nothing - * needs it, and it eases the CPU/memory load. - */ - ambiup_free(&device->AmbiUp); - } - else - { - if(!device->AmbiUp) - device->AmbiUp = ambiup_alloc(); - } - - TRACE("%s HRTF rendering enabled, using \"%s\"\n", - ((device->Render_Mode == HrtfRender) ? "Full" : "Basic"), - alstr_get_cstr(device->HrtfName) - ); - InitHrtfPanning(device); - return; - } - device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; - -no_hrtf: - if(old_hrtf) - Hrtf_DecRef(old_hrtf); - old_hrtf = NULL; - TRACE("HRTF disabled\n"); - - device->Render_Mode = StereoPair; - - ambiup_free(&device->AmbiUp); - - bs2blevel = ((headphones && hrtf_appreq != Hrtf_Disable) || - (hrtf_appreq == Hrtf_Enable)) ? 5 : 0; - if(device->Type != Loopback) - ConfigValueInt(alstr_get_cstr(device->DeviceName), NULL, "cf_level", &bs2blevel); - if(bs2blevel > 0 && bs2blevel <= 6) - { - device->Bs2b = al_calloc(16, sizeof(*device->Bs2b)); - bs2b_set_params(device->Bs2b, bs2blevel, device->Frequency); - TRACE("BS2B enabled\n"); - InitPanning(device); - return; - } - - TRACE("BS2B disabled\n"); - - if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "stereo-encoding", &mode)) - { - if(strcasecmp(mode, "uhj") == 0) - device->Render_Mode = NormalRender; - else if(strcasecmp(mode, "panpot") != 0) - ERR("Unexpected stereo-encoding: %s\n", mode); - } - if(device->Render_Mode == NormalRender) - { - device->Uhj_Encoder = al_calloc(16, sizeof(Uhj2Encoder)); - TRACE("UHJ enabled\n"); - InitUhjPanning(device); - return; - } - - TRACE("UHJ disabled\n"); - InitPanning(device); -} - - -void aluInitEffectPanning(ALeffectslot *slot) -{ - ALsizei i; - - memset(slot->ChanMap, 0, sizeof(slot->ChanMap)); - slot->NumChannels = 0; - - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - { - slot->ChanMap[i].Scale = 1.0f; - slot->ChanMap[i].Index = i; - } - slot->NumChannels = i; -} diff --git a/Alc/panning.cpp b/Alc/panning.cpp new file mode 100644 index 00000000..b9133ecf --- /dev/null +++ b/Alc/panning.cpp @@ -0,0 +1,1236 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2010 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "alMain.h" +#include "alAuxEffectSlot.h" +#include "alu.h" +#include "alconfig.h" +#include "bool.h" +#include "ambdec.h" +#include "bformatdec.h" +#include "filters/splitter.h" +#include "uhjfilter.h" +#include "bs2b.h" + + +static const ALsizei FuMa2ACN[MAX_AMBI_COEFFS] = { + 0, /* W */ + 3, /* X */ + 1, /* Y */ + 2, /* Z */ + 6, /* R */ + 7, /* S */ + 5, /* T */ + 8, /* U */ + 4, /* V */ + 12, /* K */ + 13, /* L */ + 11, /* M */ + 14, /* N */ + 10, /* O */ + 15, /* P */ + 9, /* Q */ +}; +static const ALsizei ACN2ACN[MAX_AMBI_COEFFS] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 +}; + + +void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread, + ALfloat coeffs[MAX_AMBI_COEFFS]) +{ + /* Zeroth-order */ + coeffs[0] = 1.0f; /* ACN 0 = 1 */ + /* First-order */ + coeffs[1] = SQRTF_3 * y; /* ACN 1 = sqrt(3) * Y */ + coeffs[2] = SQRTF_3 * z; /* ACN 2 = sqrt(3) * Z */ + coeffs[3] = SQRTF_3 * x; /* ACN 3 = sqrt(3) * X */ + /* Second-order */ + coeffs[4] = 3.872983346f * x * y; /* ACN 4 = sqrt(15) * X * Y */ + coeffs[5] = 3.872983346f * y * z; /* ACN 5 = sqrt(15) * Y * Z */ + coeffs[6] = 1.118033989f * (3.0f*z*z - 1.0f); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */ + coeffs[7] = 3.872983346f * x * z; /* ACN 7 = sqrt(15) * X * Z */ + coeffs[8] = 1.936491673f * (x*x - y*y); /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */ + /* Third-order */ + coeffs[9] = 2.091650066f * y * (3.0f*x*x - y*y); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */ + coeffs[10] = 10.246950766f * z * x * y; /* ACN 10 = sqrt(105) * Z * X * Y */ + coeffs[11] = 1.620185175f * y * (5.0f*z*z - 1.0f); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */ + coeffs[12] = 1.322875656f * z * (5.0f*z*z - 3.0f); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */ + coeffs[13] = 1.620185175f * x * (5.0f*z*z - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */ + coeffs[14] = 5.123475383f * z * (x*x - y*y); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */ + coeffs[15] = 2.091650066f * x * (x*x - 3.0f*y*y); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */ + + if(spread > 0.0f) + { + /* Implement the spread by using a spherical source that subtends the + * angle spread. See: + * http://www.ppsloan.org/publications/StupidSH36.pdf - Appendix A3 + * + * When adjusted for N3D normalization instead of SN3D, these + * calculations are: + * + * ZH0 = -sqrt(pi) * (-1+ca); + * ZH1 = 0.5*sqrt(pi) * sa*sa; + * ZH2 = -0.5*sqrt(pi) * ca*(-1+ca)*(ca+1); + * ZH3 = -0.125*sqrt(pi) * (-1+ca)*(ca+1)*(5*ca*ca - 1); + * ZH4 = -0.125*sqrt(pi) * ca*(-1+ca)*(ca+1)*(7*ca*ca - 3); + * ZH5 = -0.0625*sqrt(pi) * (-1+ca)*(ca+1)*(21*ca*ca*ca*ca - 14*ca*ca + 1); + * + * The gain of the source is compensated for size, so that the + * loundness doesn't depend on the spread. Thus: + * + * ZH0 = 1.0f; + * ZH1 = 0.5f * (ca+1.0f); + * ZH2 = 0.5f * (ca+1.0f)*ca; + * ZH3 = 0.125f * (ca+1.0f)*(5.0f*ca*ca - 1.0f); + * ZH4 = 0.125f * (ca+1.0f)*(7.0f*ca*ca - 3.0f)*ca; + * ZH5 = 0.0625f * (ca+1.0f)*(21.0f*ca*ca*ca*ca - 14.0f*ca*ca + 1.0f); + */ + ALfloat ca = cosf(spread * 0.5f); + /* Increase the source volume by up to +3dB for a full spread. */ + ALfloat scale = sqrtf(1.0f + spread/F_TAU); + + ALfloat ZH0_norm = scale; + ALfloat ZH1_norm = 0.5f * (ca+1.f) * scale; + ALfloat ZH2_norm = 0.5f * (ca+1.f)*ca * scale; + ALfloat ZH3_norm = 0.125f * (ca+1.f)*(5.f*ca*ca-1.f) * scale; + + /* Zeroth-order */ + coeffs[0] *= ZH0_norm; + /* First-order */ + coeffs[1] *= ZH1_norm; + coeffs[2] *= ZH1_norm; + coeffs[3] *= ZH1_norm; + /* Second-order */ + coeffs[4] *= ZH2_norm; + coeffs[5] *= ZH2_norm; + coeffs[6] *= ZH2_norm; + coeffs[7] *= ZH2_norm; + coeffs[8] *= ZH2_norm; + /* Third-order */ + coeffs[9] *= ZH3_norm; + coeffs[10] *= ZH3_norm; + coeffs[11] *= ZH3_norm; + coeffs[12] *= ZH3_norm; + coeffs[13] *= ZH3_norm; + coeffs[14] *= ZH3_norm; + coeffs[15] *= ZH3_norm; + } +} + + +void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +{ + ALsizei i, j; + + for(i = 0;i < numchans;i++) + { + float gain = 0.0f; + for(j = 0;j < numcoeffs;j++) + gain += chancoeffs[i][j]*coeffs[j]; + gains[i] = clampf(gain, 0.0f, 1.0f) * ingain; + } + for(;i < MAX_OUTPUT_CHANNELS;i++) + gains[i] = 0.0f; +} + +void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +{ + ALsizei i; + + for(i = 0;i < numchans;i++) + gains[i] = chanmap[i].Scale * coeffs[chanmap[i].Index] * ingain; + for(;i < MAX_OUTPUT_CHANNELS;i++) + gains[i] = 0.0f; +} + + +static inline const char *GetLabelFromChannel(enum Channel channel) +{ + switch(channel) + { + case FrontLeft: return "front-left"; + case FrontRight: return "front-right"; + case FrontCenter: return "front-center"; + case LFE: return "lfe"; + case BackLeft: return "back-left"; + case BackRight: return "back-right"; + case BackCenter: return "back-center"; + case SideLeft: return "side-left"; + case SideRight: return "side-right"; + + case UpperFrontLeft: return "upper-front-left"; + case UpperFrontRight: return "upper-front-right"; + case UpperBackLeft: return "upper-back-left"; + case UpperBackRight: return "upper-back-right"; + case LowerFrontLeft: return "lower-front-left"; + case LowerFrontRight: return "lower-front-right"; + case LowerBackLeft: return "lower-back-left"; + case LowerBackRight: return "lower-back-right"; + + case Aux0: return "aux-0"; + case Aux1: return "aux-1"; + case Aux2: return "aux-2"; + case Aux3: return "aux-3"; + case Aux4: return "aux-4"; + case Aux5: return "aux-5"; + case Aux6: return "aux-6"; + case Aux7: return "aux-7"; + case Aux8: return "aux-8"; + case Aux9: return "aux-9"; + case Aux10: return "aux-10"; + case Aux11: return "aux-11"; + case Aux12: return "aux-12"; + case Aux13: return "aux-13"; + case Aux14: return "aux-14"; + case Aux15: return "aux-15"; + + case InvalidChannel: break; + } + return "(unknown)"; +} + + +typedef struct ChannelMap { + enum Channel ChanName; + ChannelConfig Config; +} ChannelMap; + +static void SetChannelMap(const enum Channel devchans[MAX_OUTPUT_CHANNELS], + ChannelConfig *ambicoeffs, const ChannelMap *chanmap, + ALsizei count, ALsizei *outcount) +{ + ALsizei maxchans = 0; + ALsizei i, j; + + for(i = 0;i < count;i++) + { + ALint idx = GetChannelIndex(devchans, chanmap[i].ChanName); + if(idx < 0) + { + ERR("Failed to find %s channel in device\n", + GetLabelFromChannel(chanmap[i].ChanName)); + continue; + } + + maxchans = maxi(maxchans, idx+1); + for(j = 0;j < MAX_AMBI_COEFFS;j++) + ambicoeffs[idx][j] = chanmap[i].Config[j]; + } + *outcount = mini(maxchans, MAX_OUTPUT_CHANNELS); +} + +static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei speakermap[MAX_OUTPUT_CHANNELS]) +{ + ALsizei i; + + for(i = 0;i < conf->NumSpeakers;i++) + { + enum Channel ch; + int chidx = -1; + + /* NOTE: AmbDec does not define any standard speaker names, however + * for this to work we have to by able to find the output channel + * the speaker definition corresponds to. Therefore, OpenAL Soft + * requires these channel labels to be recognized: + * + * LF = Front left + * RF = Front right + * LS = Side left + * RS = Side right + * LB = Back left + * RB = Back right + * CE = Front center + * CB = Back center + * + * Additionally, surround51 will acknowledge back speakers for side + * channels, and surround51rear will acknowledge side speakers for + * back channels, to avoid issues with an ambdec expecting 5.1 to + * use the side channels when the device is configured for back, + * and vice-versa. + */ + if(alstr_cmp_cstr(conf->Speakers[i].Name, "LF") == 0) + ch = FrontLeft; + else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RF") == 0) + ch = FrontRight; + else if(alstr_cmp_cstr(conf->Speakers[i].Name, "CE") == 0) + ch = FrontCenter; + else if(alstr_cmp_cstr(conf->Speakers[i].Name, "LS") == 0) + { + if(device->FmtChans == DevFmtX51Rear) + ch = BackLeft; + else + ch = SideLeft; + } + else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RS") == 0) + { + if(device->FmtChans == DevFmtX51Rear) + ch = BackRight; + else + ch = SideRight; + } + else if(alstr_cmp_cstr(conf->Speakers[i].Name, "LB") == 0) + { + if(device->FmtChans == DevFmtX51) + ch = SideLeft; + else + ch = BackLeft; + } + else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RB") == 0) + { + if(device->FmtChans == DevFmtX51) + ch = SideRight; + else + ch = BackRight; + } + else if(alstr_cmp_cstr(conf->Speakers[i].Name, "CB") == 0) + ch = BackCenter; + else + { + const char *name = alstr_get_cstr(conf->Speakers[i].Name); + unsigned int n; + char c; + + if(sscanf(name, "AUX%u%c", &n, &c) == 1 && n < 16) + ch = static_cast(Aux0+n); + else + { + ERR("AmbDec speaker label \"%s\" not recognized\n", name); + return false; + } + } + chidx = GetChannelIdxByName(&device->RealOut, ch); + if(chidx == -1) + { + ERR("Failed to lookup AmbDec speaker label %s\n", + alstr_get_cstr(conf->Speakers[i].Name)); + return false; + } + speakermap[i] = chidx; + } + + return true; +} + + +static const ChannelMap MonoCfg[1] = { + { FrontCenter, { 1.0f } }, +}, StereoCfg[2] = { + { FrontLeft, { 5.00000000e-1f, 2.88675135e-1f, 0.0f, 5.52305643e-2f } }, + { FrontRight, { 5.00000000e-1f, -2.88675135e-1f, 0.0f, 5.52305643e-2f } }, +}, QuadCfg[4] = { + { BackLeft, { 3.53553391e-1f, 2.04124145e-1f, 0.0f, -2.04124145e-1f } }, + { FrontLeft, { 3.53553391e-1f, 2.04124145e-1f, 0.0f, 2.04124145e-1f } }, + { FrontRight, { 3.53553391e-1f, -2.04124145e-1f, 0.0f, 2.04124145e-1f } }, + { BackRight, { 3.53553391e-1f, -2.04124145e-1f, 0.0f, -2.04124145e-1f } }, +}, X51SideCfg[4] = { + { SideLeft, { 3.33000782e-1f, 1.89084803e-1f, 0.0f, -2.00042375e-1f, -2.12307769e-2f, 0.0f, 0.0f, 0.0f, -1.14579885e-2f } }, + { FrontLeft, { 1.88542860e-1f, 1.27709292e-1f, 0.0f, 1.66295695e-1f, 7.30571517e-2f, 0.0f, 0.0f, 0.0f, 2.10901184e-2f } }, + { FrontRight, { 1.88542860e-1f, -1.27709292e-1f, 0.0f, 1.66295695e-1f, -7.30571517e-2f, 0.0f, 0.0f, 0.0f, 2.10901184e-2f } }, + { SideRight, { 3.33000782e-1f, -1.89084803e-1f, 0.0f, -2.00042375e-1f, 2.12307769e-2f, 0.0f, 0.0f, 0.0f, -1.14579885e-2f } }, +}, X51RearCfg[4] = { + { BackLeft, { 3.33000782e-1f, 1.89084803e-1f, 0.0f, -2.00042375e-1f, -2.12307769e-2f, 0.0f, 0.0f, 0.0f, -1.14579885e-2f } }, + { FrontLeft, { 1.88542860e-1f, 1.27709292e-1f, 0.0f, 1.66295695e-1f, 7.30571517e-2f, 0.0f, 0.0f, 0.0f, 2.10901184e-2f } }, + { FrontRight, { 1.88542860e-1f, -1.27709292e-1f, 0.0f, 1.66295695e-1f, -7.30571517e-2f, 0.0f, 0.0f, 0.0f, 2.10901184e-2f } }, + { BackRight, { 3.33000782e-1f, -1.89084803e-1f, 0.0f, -2.00042375e-1f, 2.12307769e-2f, 0.0f, 0.0f, 0.0f, -1.14579885e-2f } }, +}, X61Cfg[6] = { + { SideLeft, { 2.04460341e-1f, 2.17177926e-1f, 0.0f, -4.39996780e-2f, -2.60790269e-2f, 0.0f, 0.0f, 0.0f, -6.87239792e-2f } }, + { FrontLeft, { 1.58923161e-1f, 9.21772680e-2f, 0.0f, 1.59658796e-1f, 6.66278083e-2f, 0.0f, 0.0f, 0.0f, 3.84686854e-2f } }, + { FrontRight, { 1.58923161e-1f, -9.21772680e-2f, 0.0f, 1.59658796e-1f, -6.66278083e-2f, 0.0f, 0.0f, 0.0f, 3.84686854e-2f } }, + { SideRight, { 2.04460341e-1f, -2.17177926e-1f, 0.0f, -4.39996780e-2f, 2.60790269e-2f, 0.0f, 0.0f, 0.0f, -6.87239792e-2f } }, + { BackCenter, { 2.50001688e-1f, 0.00000000e+0f, 0.0f, -2.50000094e-1f, 0.00000000e+0f, 0.0f, 0.0f, 0.0f, 6.05133395e-2f } }, +}, X71Cfg[6] = { + { BackLeft, { 2.04124145e-1f, 1.08880247e-1f, 0.0f, -1.88586120e-1f, -1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, 3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, + { SideLeft, { 2.04124145e-1f, 2.17760495e-1f, 0.0f, 0.00000000e+0f, 0.00000000e+0f, 0.0f, 0.0f, 0.0f, -1.49071198e-1f, -3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, + { FrontLeft, { 2.04124145e-1f, 1.08880247e-1f, 0.0f, 1.88586120e-1f, 1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, 3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, + { FrontRight, { 2.04124145e-1f, -1.08880247e-1f, 0.0f, 1.88586120e-1f, -1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, -3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, + { SideRight, { 2.04124145e-1f, -2.17760495e-1f, 0.0f, 0.00000000e+0f, 0.00000000e+0f, 0.0f, 0.0f, 0.0f, -1.49071198e-1f, 3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, + { BackRight, { 2.04124145e-1f, -1.08880247e-1f, 0.0f, -1.88586120e-1f, 1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, -3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, +}; + +static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, + const ALsizei *RESTRICT chans_per_order) +{ + const char *devname = alstr_get_cstr(device->DeviceName); + ALsizei i; + + if(GetConfigValueBool(devname, "decoder", "nfc", 1) && ctrl_dist > 0.0f) + { + /* NFC is only used when AvgSpeakerDist is greater than 0, and can only + * be used when rendering to an ambisonic buffer. + */ + device->AvgSpeakerDist = minf(ctrl_dist, 10.0f); + TRACE("Using near-field reference distance: %.2f meters\n", device->AvgSpeakerDist); + + for(i = 0;i < order+1;i++) + device->NumChannelsPerOrder[i] = chans_per_order[i]; + for(;i < MAX_AMBI_ORDER+1;i++) + device->NumChannelsPerOrder[i] = 0; + } +} + +static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) +{ + const char *devname = alstr_get_cstr(device->DeviceName); + ALfloat maxdist = 0.0f; + size_t total = 0; + ALsizei i; + + for(i = 0;i < conf->NumSpeakers;i++) + maxdist = maxf(maxdist, conf->Speakers[i].Distance); + + if(GetConfigValueBool(devname, "decoder", "distance-comp", 1) && maxdist > 0.0f) + { + ALfloat srate = (ALfloat)device->Frequency; + for(i = 0;i < conf->NumSpeakers;i++) + { + ALsizei chan = speakermap[i]; + ALfloat delay; + + /* Distance compensation only delays in steps of the sample rate. + * This is a bit less accurate since the delay time falls to the + * nearest sample time, but it's far simpler as it doesn't have to + * deal with phase offsets. This means at 48khz, for instance, the + * distance delay will be in steps of about 7 millimeters. + */ + delay = floorf((maxdist-conf->Speakers[i].Distance) / SPEEDOFSOUNDMETRESPERSEC * + srate + 0.5f); + if(delay >= (ALfloat)MAX_DELAY_LENGTH) + ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n", + alstr_get_cstr(conf->Speakers[i].Name), delay, MAX_DELAY_LENGTH); + + device->ChannelDelay[chan].Length = (ALsizei)clampf( + delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1) + ); + device->ChannelDelay[chan].Gain = conf->Speakers[i].Distance / maxdist; + TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan, + alstr_get_cstr(conf->Speakers[i].Name), device->ChannelDelay[chan].Length, + device->ChannelDelay[chan].Gain + ); + + /* Round up to the next 4th sample, so each channel buffer starts + * 16-byte aligned. + */ + total += RoundUp(device->ChannelDelay[chan].Length, 4); + } + } + + if(total > 0) + { + device->ChannelDelay[0].Buffer = reinterpret_cast( + al_calloc(16, total * sizeof(ALfloat))); + for(i = 1;i < MAX_OUTPUT_CHANNELS;i++) + { + size_t len = RoundUp(device->ChannelDelay[i-1].Length, 4); + device->ChannelDelay[i].Buffer = device->ChannelDelay[i-1].Buffer + len; + } + } +} + +static void InitPanning(ALCdevice *device) +{ + const ChannelMap *chanmap = NULL; + ALsizei coeffcount = 0; + ALsizei count = 0; + ALsizei i, j; + + switch(device->FmtChans) + { + case DevFmtMono: + count = COUNTOF(MonoCfg); + chanmap = MonoCfg; + coeffcount = 1; + break; + + case DevFmtStereo: + count = COUNTOF(StereoCfg); + chanmap = StereoCfg; + coeffcount = 4; + break; + + case DevFmtQuad: + count = COUNTOF(QuadCfg); + chanmap = QuadCfg; + coeffcount = 4; + break; + + case DevFmtX51: + count = COUNTOF(X51SideCfg); + chanmap = X51SideCfg; + coeffcount = 9; + break; + + case DevFmtX51Rear: + count = COUNTOF(X51RearCfg); + chanmap = X51RearCfg; + coeffcount = 9; + break; + + case DevFmtX61: + count = COUNTOF(X61Cfg); + chanmap = X61Cfg; + coeffcount = 9; + break; + + case DevFmtX71: + count = COUNTOF(X71Cfg); + chanmap = X71Cfg; + coeffcount = 16; + break; + + case DevFmtAmbi3D: + break; + } + + if(device->FmtChans == DevFmtAmbi3D) + { + const char *devname = alstr_get_cstr(device->DeviceName); + const ALsizei *acnmap = (device->AmbiLayout == AmbiLayout_FuMa) ? FuMa2ACN : ACN2ACN; + const ALfloat *n3dscale = (device->AmbiScale == AmbiNorm_FuMa) ? FuMa2N3DScale : + (device->AmbiScale == AmbiNorm_SN3D) ? SN3D2N3DScale : + /*(device->AmbiScale == AmbiNorm_N3D) ?*/ N3D2N3DScale; + ALfloat nfc_delay = 0.0f; + + count = (device->AmbiOrder == 3) ? 16 : + (device->AmbiOrder == 2) ? 9 : + (device->AmbiOrder == 1) ? 4 : 1; + for(i = 0;i < count;i++) + { + ALsizei acn = acnmap[i]; + device->Dry.Ambi.Map[i].Scale = 1.0f/n3dscale[acn]; + device->Dry.Ambi.Map[i].Index = acn; + } + device->Dry.CoeffCount = 0; + device->Dry.NumChannels = count; + + if(device->AmbiOrder < 2) + { + device->FOAOut.Ambi = device->Dry.Ambi; + device->FOAOut.CoeffCount = device->Dry.CoeffCount; + device->FOAOut.NumChannels = 0; + } + else + { + ALfloat w_scale=1.0f, xyz_scale=1.0f; + + /* FOA output is always ACN+N3D for higher-order ambisonic output. + * The upsampler expects this and will convert it for output. + */ + memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); + for(i = 0;i < 4;i++) + { + device->FOAOut.Ambi.Map[i].Scale = 1.0f; + device->FOAOut.Ambi.Map[i].Index = i; + } + device->FOAOut.CoeffCount = 0; + device->FOAOut.NumChannels = 4; + + if(device->AmbiOrder >= 3) + { + w_scale = W_SCALE_3H3P; + xyz_scale = XYZ_SCALE_3H3P; + } + else + { + w_scale = W_SCALE_2H2P; + xyz_scale = XYZ_SCALE_2H2P; + } + ambiup_reset(device->AmbiUp, device, w_scale, xyz_scale); + } + + if(ConfigValueFloat(devname, "decoder", "nfc-ref-delay", &nfc_delay) && nfc_delay > 0.0f) + { + static const ALsizei chans_per_order[MAX_AMBI_ORDER+1] = { + 1, 3, 5, 7 + }; + nfc_delay = clampf(nfc_delay, 0.001f, 1000.0f); + InitNearFieldCtrl(device, nfc_delay * SPEEDOFSOUNDMETRESPERSEC, + device->AmbiOrder, chans_per_order); + } + } + else + { + ALfloat w_scale, xyz_scale; + + SetChannelMap(device->RealOut.ChannelName, device->Dry.Ambi.Coeffs, + chanmap, count, &device->Dry.NumChannels); + device->Dry.CoeffCount = coeffcount; + + w_scale = (device->Dry.CoeffCount > 9) ? W_SCALE_3H0P : + (device->Dry.CoeffCount > 4) ? W_SCALE_2H0P : 1.0f; + xyz_scale = (device->Dry.CoeffCount > 9) ? XYZ_SCALE_3H0P : + (device->Dry.CoeffCount > 4) ? XYZ_SCALE_2H0P : 1.0f; + + memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); + for(i = 0;i < device->Dry.NumChannels;i++) + { + device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0] * w_scale; + for(j = 1;j < 4;j++) + device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * xyz_scale; + } + device->FOAOut.CoeffCount = 4; + device->FOAOut.NumChannels = 0; + } + device->RealOut.NumChannels = 0; +} + +static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) +{ + ChannelMap chanmap[MAX_OUTPUT_CHANNELS]; + const ALfloat *coeff_scale = N3D2N3DScale; + ALfloat w_scale = 1.0f; + ALfloat xyz_scale = 1.0f; + ALsizei i, j; + + if(conf->FreqBands != 1) + ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n", + conf->XOverFreq); + + if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) + { + if(conf->ChanMask > 0x1ff) + { + w_scale = W_SCALE_3H3P; + xyz_scale = XYZ_SCALE_3H3P; + } + else if(conf->ChanMask > 0xf) + { + w_scale = W_SCALE_2H2P; + xyz_scale = XYZ_SCALE_2H2P; + } + } + else + { + if(conf->ChanMask > 0x1ff) + { + w_scale = W_SCALE_3H0P; + xyz_scale = XYZ_SCALE_3H0P; + } + else if(conf->ChanMask > 0xf) + { + w_scale = W_SCALE_2H0P; + xyz_scale = XYZ_SCALE_2H0P; + } + } + + if(conf->CoeffScale == ADS_SN3D) + coeff_scale = SN3D2N3DScale; + else if(conf->CoeffScale == ADS_FuMa) + coeff_scale = FuMa2N3DScale; + + for(i = 0;i < conf->NumSpeakers;i++) + { + ALsizei chan = speakermap[i]; + ALfloat gain; + ALsizei k = 0; + + for(j = 0;j < MAX_AMBI_COEFFS;j++) + chanmap[i].Config[j] = 0.0f; + + chanmap[i].ChanName = device->RealOut.ChannelName[chan]; + for(j = 0;j < MAX_AMBI_COEFFS;j++) + { + if(j == 0) gain = conf->HFOrderGain[0]; + else if(j == 1) gain = conf->HFOrderGain[1]; + else if(j == 4) gain = conf->HFOrderGain[2]; + else if(j == 9) gain = conf->HFOrderGain[3]; + if((conf->ChanMask&(1<HFMatrix[i][k++] / coeff_scale[j] * gain; + } + } + + SetChannelMap(device->RealOut.ChannelName, device->Dry.Ambi.Coeffs, chanmap, + conf->NumSpeakers, &device->Dry.NumChannels); + device->Dry.CoeffCount = (conf->ChanMask > 0x1ff) ? 16 : + (conf->ChanMask > 0xf) ? 9 : 4; + + memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); + for(i = 0;i < device->Dry.NumChannels;i++) + { + device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0] * w_scale; + for(j = 1;j < 4;j++) + device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * xyz_scale; + } + device->FOAOut.CoeffCount = 4; + device->FOAOut.NumChannels = 0; + + device->RealOut.NumChannels = 0; + + InitDistanceComp(device, conf, speakermap); +} + +static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) +{ + static const ALsizei chans_per_order2d[MAX_AMBI_ORDER+1] = { 1, 2, 2, 2 }; + static const ALsizei chans_per_order3d[MAX_AMBI_ORDER+1] = { 1, 3, 5, 7 }; + ALfloat avg_dist; + ALsizei count; + ALsizei i; + + if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) + { + count = (conf->ChanMask > 0x1ff) ? 16 : + (conf->ChanMask > 0xf) ? 9 : 4; + for(i = 0;i < count;i++) + { + device->Dry.Ambi.Map[i].Scale = 1.0f; + device->Dry.Ambi.Map[i].Index = i; + } + } + else + { + static const int map[MAX_AMBI2D_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; + + count = (conf->ChanMask > 0x1ff) ? 7 : + (conf->ChanMask > 0xf) ? 5 : 3; + for(i = 0;i < count;i++) + { + device->Dry.Ambi.Map[i].Scale = 1.0f; + device->Dry.Ambi.Map[i].Index = map[i]; + } + } + device->Dry.CoeffCount = 0; + device->Dry.NumChannels = count; + + TRACE("Enabling %s-band %s-order%s ambisonic decoder\n", + (conf->FreqBands == 1) ? "single" : "dual", + (conf->ChanMask > 0xf) ? (conf->ChanMask > 0x1ff) ? "third" : "second" : "first", + (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? " periphonic" : "" + ); + bformatdec_reset(device->AmbiDecoder, conf, count, device->Frequency, speakermap); + + if(conf->ChanMask <= 0xf) + { + device->FOAOut.Ambi = device->Dry.Ambi; + device->FOAOut.CoeffCount = device->Dry.CoeffCount; + device->FOAOut.NumChannels = 0; + } + else + { + memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); + if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) + { + count = 4; + for(i = 0;i < count;i++) + { + device->FOAOut.Ambi.Map[i].Scale = 1.0f; + device->FOAOut.Ambi.Map[i].Index = i; + } + } + else + { + static const int map[3] = { 0, 1, 3 }; + count = 3; + for(i = 0;i < count;i++) + { + device->FOAOut.Ambi.Map[i].Scale = 1.0f; + device->FOAOut.Ambi.Map[i].Index = map[i]; + } + } + device->FOAOut.CoeffCount = 0; + device->FOAOut.NumChannels = count; + } + + device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + + avg_dist = 0.0f; + for(i = 0;i < conf->NumSpeakers;i++) + avg_dist += conf->Speakers[i].Distance; + avg_dist /= (ALfloat)conf->NumSpeakers; + InitNearFieldCtrl(device, avg_dist, + (conf->ChanMask > 0x1ff) ? 3 : (conf->ChanMask > 0xf) ? 2 : 1, + (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? chans_per_order3d : chans_per_order2d + ); + + InitDistanceComp(device, conf, speakermap); +} + +static void InitHrtfPanning(ALCdevice *device) +{ + /* NOTE: azimuth goes clockwise. */ + static const struct AngularPoint AmbiPoints[] = { + { DEG2RAD( 90.0f), DEG2RAD( 0.0f) }, + { DEG2RAD( 35.2643897f), DEG2RAD( 45.0f) }, + { DEG2RAD( 35.2643897f), DEG2RAD( 135.0f) }, + { DEG2RAD( 35.2643897f), DEG2RAD(-135.0f) }, + { DEG2RAD( 35.2643897f), DEG2RAD( -45.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( 0.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( 45.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( 90.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( 135.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( 180.0f) }, + { DEG2RAD( 0.0f), DEG2RAD(-135.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( -90.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( -45.0f) }, + { DEG2RAD(-35.2643897f), DEG2RAD( 45.0f) }, + { DEG2RAD(-35.2643897f), DEG2RAD( 135.0f) }, + { DEG2RAD(-35.2643897f), DEG2RAD(-135.0f) }, + { DEG2RAD(-35.2643897f), DEG2RAD( -45.0f) }, + { DEG2RAD(-90.0f), DEG2RAD( 0.0f) }, + }; + static const ALfloat AmbiMatrixFOA[][MAX_AMBI_COEFFS] = { + { 5.55555556e-02f, 0.00000000e+00f, 1.23717915e-01f, 0.00000000e+00f }, + { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f }, + { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f }, + { 5.55555556e-02f, 5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f }, + { 5.55555556e-02f, 5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f }, + { 5.55555556e-02f, 0.00000000e+00f, 0.00000000e+00f, 8.66025404e-02f }, + { 5.55555556e-02f, -6.12372435e-02f, 0.00000000e+00f, 6.12372435e-02f }, + { 5.55555556e-02f, -8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f }, + { 5.55555556e-02f, -6.12372435e-02f, 0.00000000e+00f, -6.12372435e-02f }, + { 5.55555556e-02f, 0.00000000e+00f, 0.00000000e+00f, -8.66025404e-02f }, + { 5.55555556e-02f, 6.12372435e-02f, 0.00000000e+00f, -6.12372435e-02f }, + { 5.55555556e-02f, 8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f }, + { 5.55555556e-02f, 6.12372435e-02f, 0.00000000e+00f, 6.12372435e-02f }, + { 5.55555556e-02f, -5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f }, + { 5.55555556e-02f, -5.00000000e-02f, -7.14285715e-02f, -5.00000000e-02f }, + { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, -5.00000000e-02f }, + { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f }, + { 5.55555556e-02f, 0.00000000e+00f, -1.23717915e-01f, 0.00000000e+00f }, + }, AmbiMatrixHOA[][MAX_AMBI_COEFFS] = { + { 5.55555556e-02f, 0.00000000e+00f, 1.23717915e-01f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, 5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, 5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, 0.00000000e+00f, 0.00000000e+00f, 8.66025404e-02f, 0.00000000e+00f, 1.29099445e-01f }, + { 5.55555556e-02f, -6.12372435e-02f, 0.00000000e+00f, 6.12372435e-02f, -6.83467648e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, -8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -1.29099445e-01f }, + { 5.55555556e-02f, -6.12372435e-02f, 0.00000000e+00f, -6.12372435e-02f, 6.83467648e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, 0.00000000e+00f, 0.00000000e+00f, -8.66025404e-02f, 0.00000000e+00f, 1.29099445e-01f }, + { 5.55555556e-02f, 6.12372435e-02f, 0.00000000e+00f, -6.12372435e-02f, -6.83467648e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, 8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -1.29099445e-01f }, + { 5.55555556e-02f, 6.12372435e-02f, 0.00000000e+00f, 6.12372435e-02f, 6.83467648e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, -5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, -5.00000000e-02f, -7.14285715e-02f, -5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, -5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, 0.00000000e+00f, -1.23717915e-01f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + }; + static const ALfloat AmbiOrderHFGainFOA[MAX_AMBI_ORDER+1] = { + 3.00000000e+00f, 1.73205081e+00f + }, AmbiOrderHFGainHOA[MAX_AMBI_ORDER+1] = { + 2.40192231e+00f, 1.86052102e+00f, 9.60768923e-01f + }; + static const ALsizei IndexMap[6] = { 0, 1, 2, 3, 4, 8 }; + static const ALsizei ChansPerOrder[MAX_AMBI_ORDER+1] = { 1, 3, 2, 0 }; + const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_COEFFS] = AmbiMatrixFOA; + const ALfloat *RESTRICT AmbiOrderHFGain = AmbiOrderHFGainFOA; + ALsizei count = 4; + ALsizei i; + + static_assert(COUNTOF(AmbiPoints) == COUNTOF(AmbiMatrixFOA), "FOA Ambisonic HRTF mismatch"); + static_assert(COUNTOF(AmbiPoints) == COUNTOF(AmbiMatrixHOA), "HOA Ambisonic HRTF mismatch"); + + if(device->AmbiUp) + { + AmbiMatrix = AmbiMatrixHOA; + AmbiOrderHFGain = AmbiOrderHFGainHOA; + count = COUNTOF(IndexMap); + } + + device->Hrtf = reinterpret_cast( + al_calloc(16, FAM_SIZE(DirectHrtfState, Chan, count))); + + for(i = 0;i < count;i++) + { + device->Dry.Ambi.Map[i].Scale = 1.0f; + device->Dry.Ambi.Map[i].Index = IndexMap[i]; + } + device->Dry.CoeffCount = 0; + device->Dry.NumChannels = count; + + if(device->AmbiUp) + { + memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); + for(i = 0;i < 4;i++) + { + device->FOAOut.Ambi.Map[i].Scale = 1.0f; + device->FOAOut.Ambi.Map[i].Index = i; + } + device->FOAOut.CoeffCount = 0; + device->FOAOut.NumChannels = 4; + + ambiup_reset(device->AmbiUp, device, AmbiOrderHFGainFOA[0] / AmbiOrderHFGain[0], + AmbiOrderHFGainFOA[1] / AmbiOrderHFGain[1]); + } + else + { + device->FOAOut.Ambi = device->Dry.Ambi; + device->FOAOut.CoeffCount = device->Dry.CoeffCount; + device->FOAOut.NumChannels = 0; + } + + device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + + BuildBFormatHrtf(device->HrtfHandle, + device->Hrtf, device->Dry.NumChannels, AmbiPoints, AmbiMatrix, COUNTOF(AmbiPoints), + AmbiOrderHFGain + ); + + InitNearFieldCtrl(device, device->HrtfHandle->distance, device->AmbiUp ? 2 : 1, + ChansPerOrder); +} + +static void InitUhjPanning(ALCdevice *device) +{ + ALsizei count = 3; + ALsizei i; + + for(i = 0;i < count;i++) + { + ALsizei acn = FuMa2ACN[i]; + device->Dry.Ambi.Map[i].Scale = 1.0f/FuMa2N3DScale[acn]; + device->Dry.Ambi.Map[i].Index = acn; + } + device->Dry.CoeffCount = 0; + device->Dry.NumChannels = count; + + device->FOAOut.Ambi = device->Dry.Ambi; + device->FOAOut.CoeffCount = device->Dry.CoeffCount; + device->FOAOut.NumChannels = 0; + + device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); +} + +void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq) +{ + /* Hold the HRTF the device last used, in case it's used again. */ + struct Hrtf *old_hrtf = device->HrtfHandle; + const char *mode; + bool headphones; + int bs2blevel; + size_t i; + + al_free(device->Hrtf); + device->Hrtf = NULL; + device->HrtfHandle = NULL; + alstr_clear(&device->HrtfName); + device->Render_Mode = NormalRender; + + memset(&device->Dry.Ambi, 0, sizeof(device->Dry.Ambi)); + device->Dry.CoeffCount = 0; + device->Dry.NumChannels = 0; + for(i = 0;i < MAX_AMBI_ORDER+1;i++) + device->NumChannelsPerOrder[i] = 0; + + device->AvgSpeakerDist = 0.0f; + memset(device->ChannelDelay, 0, sizeof(device->ChannelDelay)); + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + { + device->ChannelDelay[i].Gain = 1.0f; + device->ChannelDelay[i].Length = 0; + } + + al_free(device->Stablizer); + device->Stablizer = NULL; + + if(device->FmtChans != DevFmtStereo) + { + ALsizei speakermap[MAX_OUTPUT_CHANNELS]; + const char *devname, *layout = NULL; + AmbDecConf conf, *pconf = NULL; + + if(old_hrtf) + Hrtf_DecRef(old_hrtf); + old_hrtf = NULL; + if(hrtf_appreq == Hrtf_Enable) + device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + + ambdec_init(&conf); + + devname = alstr_get_cstr(device->DeviceName); + switch(device->FmtChans) + { + case DevFmtQuad: layout = "quad"; break; + case DevFmtX51: /* fall-through */ + case DevFmtX51Rear: layout = "surround51"; break; + case DevFmtX61: layout = "surround61"; break; + case DevFmtX71: layout = "surround71"; break; + /* Mono, Stereo, and Ambisonics output don't use custom decoders. */ + case DevFmtMono: + case DevFmtStereo: + case DevFmtAmbi3D: + break; + } + if(layout) + { + const char *fname; + if(ConfigValueStr(devname, "decoder", layout, &fname)) + { + if(!ambdec_load(&conf, fname)) + ERR("Failed to load layout file %s\n", fname); + else + { + if(conf.ChanMask > 0xffff) + ERR("Unsupported channel mask 0x%04x (max 0xffff)\n", conf.ChanMask); + else + { + if(MakeSpeakerMap(device, &conf, speakermap)) + pconf = &conf; + } + } + } + } + + if(pconf && GetConfigValueBool(devname, "decoder", "hq-mode", 0)) + { + ambiup_free(&device->AmbiUp); + if(!device->AmbiDecoder) + device->AmbiDecoder = bformatdec_alloc(); + } + else + { + bformatdec_free(&device->AmbiDecoder); + if(device->FmtChans != DevFmtAmbi3D || device->AmbiOrder < 2) + ambiup_free(&device->AmbiUp); + else + { + if(!device->AmbiUp) + device->AmbiUp = ambiup_alloc(); + } + } + + if(!pconf) + InitPanning(device); + else if(device->AmbiDecoder) + InitHQPanning(device, pconf, speakermap); + else + InitCustomPanning(device, pconf, speakermap); + + /* Enable the stablizer only for formats that have front-left, front- + * right, and front-center outputs. + */ + switch(device->FmtChans) + { + case DevFmtX51: + case DevFmtX51Rear: + case DevFmtX61: + case DevFmtX71: + if(GetConfigValueBool(devname, NULL, "front-stablizer", 0)) + { + /* Initialize band-splitting filters for the front-left and + * front-right channels, with a crossover at 5khz (could be + * higher). + */ + ALfloat scale = (ALfloat)(5000.0 / device->Frequency); + FrontStablizer *stablizer = reinterpret_cast( + al_calloc(16, sizeof(*stablizer))); + + bandsplit_init(&stablizer->LFilter, scale); + stablizer->RFilter = stablizer->LFilter; + + /* Initialize all-pass filters for all other channels. */ + splitterap_init(&stablizer->APFilter[0], scale); + for(i = 1;i < (size_t)device->RealOut.NumChannels;i++) + stablizer->APFilter[i] = stablizer->APFilter[0]; + + device->Stablizer = stablizer; + } + break; + case DevFmtMono: + case DevFmtStereo: + case DevFmtQuad: + case DevFmtAmbi3D: + break; + } + TRACE("Front stablizer %s\n", device->Stablizer ? "enabled" : "disabled"); + + ambdec_deinit(&conf); + return; + } + + bformatdec_free(&device->AmbiDecoder); + + headphones = device->IsHeadphones; + if(device->Type != Loopback) + { + const char *mode; + if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "stereo-mode", &mode)) + { + if(strcasecmp(mode, "headphones") == 0) + headphones = true; + else if(strcasecmp(mode, "speakers") == 0) + headphones = false; + else if(strcasecmp(mode, "auto") != 0) + ERR("Unexpected stereo-mode: %s\n", mode); + } + } + + if(hrtf_userreq == Hrtf_Default) + { + bool usehrtf = (headphones && hrtf_appreq != Hrtf_Disable) || + (hrtf_appreq == Hrtf_Enable); + if(!usehrtf) goto no_hrtf; + + device->HrtfStatus = ALC_HRTF_ENABLED_SOFT; + if(headphones && hrtf_appreq != Hrtf_Disable) + device->HrtfStatus = ALC_HRTF_HEADPHONES_DETECTED_SOFT; + } + else + { + if(hrtf_userreq != Hrtf_Enable) + { + if(hrtf_appreq == Hrtf_Enable) + device->HrtfStatus = ALC_HRTF_DENIED_SOFT; + goto no_hrtf; + } + device->HrtfStatus = ALC_HRTF_REQUIRED_SOFT; + } + + if(VECTOR_SIZE(device->HrtfList) == 0) + { + VECTOR_DEINIT(device->HrtfList); + device->HrtfList = EnumerateHrtf(device->DeviceName); + } + + if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->HrtfList)) + { + const EnumeratedHrtf *entry = &VECTOR_ELEM(device->HrtfList, hrtf_id); + struct Hrtf *hrtf = GetLoadedHrtf(entry->hrtf); + if(hrtf && hrtf->sampleRate == device->Frequency) + { + device->HrtfHandle = hrtf; + alstr_copy(&device->HrtfName, entry->name); + } + else if(hrtf) + Hrtf_DecRef(hrtf); + } + + for(i = 0;!device->HrtfHandle && i < VECTOR_SIZE(device->HrtfList);i++) + { + const EnumeratedHrtf *entry = &VECTOR_ELEM(device->HrtfList, i); + struct Hrtf *hrtf = GetLoadedHrtf(entry->hrtf); + if(hrtf && hrtf->sampleRate == device->Frequency) + { + device->HrtfHandle = hrtf; + alstr_copy(&device->HrtfName, entry->name); + } + else if(hrtf) + Hrtf_DecRef(hrtf); + } + + if(device->HrtfHandle) + { + if(old_hrtf) + Hrtf_DecRef(old_hrtf); + old_hrtf = NULL; + + device->Render_Mode = HrtfRender; + if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "hrtf-mode", &mode)) + { + if(strcasecmp(mode, "full") == 0) + device->Render_Mode = HrtfRender; + else if(strcasecmp(mode, "basic") == 0) + device->Render_Mode = NormalRender; + else + ERR("Unexpected hrtf-mode: %s\n", mode); + } + + if(device->Render_Mode == HrtfRender) + { + /* Don't bother with HOA when using full HRTF rendering. Nothing + * needs it, and it eases the CPU/memory load. + */ + ambiup_free(&device->AmbiUp); + } + else + { + if(!device->AmbiUp) + device->AmbiUp = ambiup_alloc(); + } + + TRACE("%s HRTF rendering enabled, using \"%s\"\n", + ((device->Render_Mode == HrtfRender) ? "Full" : "Basic"), + alstr_get_cstr(device->HrtfName) + ); + InitHrtfPanning(device); + return; + } + device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + +no_hrtf: + if(old_hrtf) + Hrtf_DecRef(old_hrtf); + old_hrtf = NULL; + TRACE("HRTF disabled\n"); + + device->Render_Mode = StereoPair; + + ambiup_free(&device->AmbiUp); + + bs2blevel = ((headphones && hrtf_appreq != Hrtf_Disable) || + (hrtf_appreq == Hrtf_Enable)) ? 5 : 0; + if(device->Type != Loopback) + ConfigValueInt(alstr_get_cstr(device->DeviceName), NULL, "cf_level", &bs2blevel); + if(bs2blevel > 0 && bs2blevel <= 6) + { + device->Bs2b = reinterpret_cast(al_calloc(16, sizeof(*device->Bs2b))); + bs2b_set_params(device->Bs2b, bs2blevel, device->Frequency); + TRACE("BS2B enabled\n"); + InitPanning(device); + return; + } + + TRACE("BS2B disabled\n"); + + if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "stereo-encoding", &mode)) + { + if(strcasecmp(mode, "uhj") == 0) + device->Render_Mode = NormalRender; + else if(strcasecmp(mode, "panpot") != 0) + ERR("Unexpected stereo-encoding: %s\n", mode); + } + if(device->Render_Mode == NormalRender) + { + device->Uhj_Encoder = reinterpret_cast(al_calloc(16, sizeof(Uhj2Encoder))); + TRACE("UHJ enabled\n"); + InitUhjPanning(device); + return; + } + + TRACE("UHJ disabled\n"); + InitPanning(device); +} + + +void aluInitEffectPanning(ALeffectslot *slot) +{ + ALsizei i; + + memset(slot->ChanMap, 0, sizeof(slot->ChanMap)); + slot->NumChannels = 0; + + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + { + slot->ChanMap[i].Scale = 1.0f; + slot->ChanMap[i].Index = i; + } + slot->NumChannels = i; +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 2743bcaa..4a97741b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -878,7 +878,7 @@ SET(ALC_OBJS Alc/ambdec.h Alc/bformatdec.cpp Alc/bformatdec.h - Alc/panning.c + Alc/panning.cpp Alc/polymorphism.h Alc/mixvoice.c Alc/mixer/defs.h -- cgit v1.2.3 From 96819237d6317c62959dd25bcd37d17e3fa790e8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Nov 2018 19:51:23 -0700 Subject: Convert ambdec.c to C++ --- Alc/ambdec.c | 566 ----------------------------------------------------- Alc/ambdec.cpp | 520 ++++++++++++++++++++++++++++++++++++++++++++++++ Alc/ambdec.h | 35 ++-- Alc/bformatdec.cpp | 4 +- Alc/panning.cpp | 33 ++-- CMakeLists.txt | 2 +- 6 files changed, 551 insertions(+), 609 deletions(-) delete mode 100644 Alc/ambdec.c create mode 100644 Alc/ambdec.cpp diff --git a/Alc/ambdec.c b/Alc/ambdec.c deleted file mode 100644 index da114335..00000000 --- a/Alc/ambdec.c +++ /dev/null @@ -1,566 +0,0 @@ - -#include "config.h" - -#include "ambdec.h" - -#include -#include -#include - -#include "compat.h" - - -static char *lstrip(char *line) -{ - while(isspace(line[0])) - line++; - return line; -} - -static char *rstrip(char *line) -{ - size_t len = strlen(line); - while(len > 0 && isspace(line[len-1])) - len--; - line[len] = 0; - 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; -} - - -/* Custom strtok_r, since we can't rely on it existing. */ -static char *my_strtok_r(char *str, const char *delim, char **saveptr) -{ - /* Sanity check and update internal pointer. */ - if(!saveptr || !delim) return NULL; - if(str) *saveptr = str; - str = *saveptr; - - /* Nothing more to do with this string. */ - if(!str) return NULL; - - /* Find the first non-delimiter character. */ - while(*str != '\0' && strchr(delim, *str) != NULL) - str++; - if(*str == '\0') - { - /* End of string. */ - *saveptr = NULL; - return NULL; - } - - /* Find the next delimiter character. */ - *saveptr = strpbrk(str, delim); - if(*saveptr) *((*saveptr)++) = '\0'; - - return str; -} - -static char *read_int(ALint *num, const char *line, int base) -{ - char *end; - *num = strtol(line, &end, base); - if(end && *end != '\0') - end = lstrip(end); - return end; -} - -static char *read_uint(ALuint *num, const char *line, int base) -{ - char *end; - *num = strtoul(line, &end, base); - if(end && *end != '\0') - end = lstrip(end); - return end; -} - -static char *read_float(ALfloat *num, const char *line) -{ - char *end; -#ifdef HAVE_STRTOF - *num = strtof(line, &end); -#else - *num = (ALfloat)strtod(line, &end); -#endif - if(end && *end != '\0') - end = lstrip(end); - return end; -} - - -char *read_clipped_line(FILE *f, char **buffer, size_t *maxlen) -{ - while(readline(f, buffer, maxlen)) - { - char *line, *comment; - - line = lstrip(*buffer); - comment = strchr(line, '#'); - if(comment) *(comment++) = 0; - - line = rstrip(line); - if(line[0]) return line; - } - return NULL; -} - -static int load_ambdec_speakers(AmbDecConf *conf, FILE *f, char **buffer, size_t *maxlen, char **saveptr) -{ - ALsizei cur = 0; - while(cur < conf->NumSpeakers) - { - const char *cmd = my_strtok_r(NULL, " \t", saveptr); - if(!cmd) - { - char *line = read_clipped_line(f, buffer, maxlen); - if(!line) - { - ERR("Unexpected end of file\n"); - return 0; - } - cmd = my_strtok_r(line, " \t", saveptr); - } - - if(strcmp(cmd, "add_spkr") == 0) - { - const char *name = my_strtok_r(NULL, " \t", saveptr); - const char *dist = my_strtok_r(NULL, " \t", saveptr); - const char *az = my_strtok_r(NULL, " \t", saveptr); - const char *elev = my_strtok_r(NULL, " \t", saveptr); - const char *conn = my_strtok_r(NULL, " \t", saveptr); - - if(!name) WARN("Name not specified for speaker %u\n", cur+1); - else alstr_copy_cstr(&conf->Speakers[cur].Name, name); - if(!dist) WARN("Distance not specified for speaker %u\n", cur+1); - else read_float(&conf->Speakers[cur].Distance, dist); - if(!az) WARN("Azimuth not specified for speaker %u\n", cur+1); - else read_float(&conf->Speakers[cur].Azimuth, az); - if(!elev) WARN("Elevation not specified for speaker %u\n", cur+1); - else read_float(&conf->Speakers[cur].Elevation, elev); - if(!conn) TRACE("Connection not specified for speaker %u\n", cur+1); - else alstr_copy_cstr(&conf->Speakers[cur].Connection, conn); - - cur++; - } - else - { - ERR("Unexpected speakers command: %s\n", cmd); - return 0; - } - - cmd = my_strtok_r(NULL, " \t", saveptr); - if(cmd) - { - ERR("Unexpected junk on line: %s\n", cmd); - return 0; - } - } - - return 1; -} - -static int load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsizei maxrow, FILE *f, char **buffer, size_t *maxlen, char **saveptr) -{ - int gotgains = 0; - ALsizei cur = 0; - while(cur < maxrow) - { - const char *cmd = my_strtok_r(NULL, " \t", saveptr); - if(!cmd) - { - char *line = read_clipped_line(f, buffer, maxlen); - if(!line) - { - ERR("Unexpected end of file\n"); - return 0; - } - cmd = my_strtok_r(line, " \t", saveptr); - } - - if(strcmp(cmd, "order_gain") == 0) - { - ALuint curgain = 0; - char *line; - while((line=my_strtok_r(NULL, " \t", saveptr)) != NULL) - { - ALfloat value; - line = read_float(&value, line); - if(line && *line != '\0') - { - ERR("Extra junk on gain %u: %s\n", curgain+1, line); - return 0; - } - if(curgain < MAX_AMBI_ORDER+1) - gains[curgain] = value; - curgain++; - } - while(curgain < MAX_AMBI_ORDER+1) - gains[curgain++] = 0.0f; - gotgains = 1; - } - else if(strcmp(cmd, "add_row") == 0) - { - ALuint curidx = 0; - char *line; - while((line=my_strtok_r(NULL, " \t", saveptr)) != NULL) - { - ALfloat value; - line = read_float(&value, line); - if(line && *line != '\0') - { - ERR("Extra junk on matrix element %ux%u: %s\n", cur, curidx, line); - return 0; - } - if(curidx < MAX_AMBI_COEFFS) - matrix[cur][curidx] = value; - curidx++; - } - while(curidx < MAX_AMBI_COEFFS) - matrix[cur][curidx++] = 0.0f; - cur++; - } - else - { - ERR("Unexpected speakers command: %s\n", cmd); - return 0; - } - - cmd = my_strtok_r(NULL, " \t", saveptr); - if(cmd) - { - ERR("Unexpected junk on line: %s\n", cmd); - return 0; - } - } - - if(!gotgains) - { - ERR("Matrix order_gain not specified\n"); - return 0; - } - - return 1; -} - -void ambdec_init(AmbDecConf *conf) -{ - ALsizei i; - - memset(conf, 0, sizeof(*conf)); - AL_STRING_INIT(conf->Description); - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - { - AL_STRING_INIT(conf->Speakers[i].Name); - AL_STRING_INIT(conf->Speakers[i].Connection); - } -} - -void ambdec_deinit(AmbDecConf *conf) -{ - ALsizei i; - - alstr_reset(&conf->Description); - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - { - alstr_reset(&conf->Speakers[i].Name); - alstr_reset(&conf->Speakers[i].Connection); - } - memset(conf, 0, sizeof(*conf)); -} - -int ambdec_load(AmbDecConf *conf, const char *fname) -{ - char *buffer = NULL; - size_t maxlen = 0; - char *line; - FILE *f; - - f = al_fopen(fname, "r"); - if(!f) - { - ERR("Failed to open: %s\n", fname); - return 0; - } - - while((line=read_clipped_line(f, &buffer, &maxlen)) != NULL) - { - char *saveptr; - char *command; - - command = my_strtok_r(line, "/ \t", &saveptr); - if(!command) - { - ERR("Malformed line: %s\n", line); - goto fail; - } - - if(strcmp(command, "description") == 0) - { - char *value = my_strtok_r(NULL, "", &saveptr); - alstr_copy_cstr(&conf->Description, lstrip(value)); - } - else if(strcmp(command, "version") == 0) - { - line = my_strtok_r(NULL, "", &saveptr); - line = read_uint(&conf->Version, line, 10); - if(line && *line != '\0') - { - ERR("Extra junk after version: %s\n", line); - goto fail; - } - if(conf->Version != 3) - { - ERR("Unsupported version: %u\n", conf->Version); - goto fail; - } - } - else if(strcmp(command, "dec") == 0) - { - const char *dec = my_strtok_r(NULL, "/ \t", &saveptr); - if(strcmp(dec, "chan_mask") == 0) - { - line = my_strtok_r(NULL, "", &saveptr); - line = read_uint(&conf->ChanMask, line, 16); - if(line && *line != '\0') - { - ERR("Extra junk after mask: %s\n", line); - goto fail; - } - } - else if(strcmp(dec, "freq_bands") == 0) - { - line = my_strtok_r(NULL, "", &saveptr); - line = read_uint(&conf->FreqBands, line, 10); - if(line && *line != '\0') - { - ERR("Extra junk after freq_bands: %s\n", line); - goto fail; - } - if(conf->FreqBands != 1 && conf->FreqBands != 2) - { - ERR("Invalid freq_bands value: %u\n", conf->FreqBands); - goto fail; - } - } - else if(strcmp(dec, "speakers") == 0) - { - line = my_strtok_r(NULL, "", &saveptr); - line = read_int(&conf->NumSpeakers, line, 10); - if(line && *line != '\0') - { - ERR("Extra junk after speakers: %s\n", line); - goto fail; - } - if(conf->NumSpeakers > MAX_OUTPUT_CHANNELS) - { - ERR("Unsupported speaker count: %u\n", conf->NumSpeakers); - goto fail; - } - } - else if(strcmp(dec, "coeff_scale") == 0) - { - line = my_strtok_r(NULL, " \t", &saveptr); - if(strcmp(line, "n3d") == 0) - conf->CoeffScale = ADS_N3D; - else if(strcmp(line, "sn3d") == 0) - conf->CoeffScale = ADS_SN3D; - else if(strcmp(line, "fuma") == 0) - conf->CoeffScale = ADS_FuMa; - else - { - ERR("Unsupported coeff scale: %s\n", line); - goto fail; - } - } - else - { - ERR("Unexpected /dec option: %s\n", dec); - goto fail; - } - } - else if(strcmp(command, "opt") == 0) - { - const char *opt = my_strtok_r(NULL, "/ \t", &saveptr); - if(strcmp(opt, "xover_freq") == 0) - { - line = my_strtok_r(NULL, "", &saveptr); - line = read_float(&conf->XOverFreq, line); - if(line && *line != '\0') - { - ERR("Extra junk after xover_freq: %s\n", line); - goto fail; - } - } - else if(strcmp(opt, "xover_ratio") == 0) - { - line = my_strtok_r(NULL, "", &saveptr); - line = read_float(&conf->XOverRatio, line); - if(line && *line != '\0') - { - ERR("Extra junk after xover_ratio: %s\n", line); - goto fail; - } - } - else if(strcmp(opt, "input_scale") == 0 || strcmp(opt, "nfeff_comp") == 0 || - strcmp(opt, "delay_comp") == 0 || strcmp(opt, "level_comp") == 0) - { - /* Unused */ - my_strtok_r(NULL, " \t", &saveptr); - } - else - { - ERR("Unexpected /opt option: %s\n", opt); - goto fail; - } - } - else if(strcmp(command, "speakers") == 0) - { - const char *value = my_strtok_r(NULL, "/ \t", &saveptr); - if(strcmp(value, "{") != 0) - { - ERR("Expected { after %s command, got %s\n", command, value); - goto fail; - } - if(!load_ambdec_speakers(conf, f, &buffer, &maxlen, &saveptr)) - goto fail; - value = my_strtok_r(NULL, "/ \t", &saveptr); - if(!value) - { - line = read_clipped_line(f, &buffer, &maxlen); - if(!line) - { - ERR("Unexpected end of file\n"); - goto fail; - } - value = my_strtok_r(line, "/ \t", &saveptr); - } - if(strcmp(value, "}") != 0) - { - ERR("Expected } after speaker definitions, got %s\n", value); - goto fail; - } - } - else if(strcmp(command, "lfmatrix") == 0 || strcmp(command, "hfmatrix") == 0 || - strcmp(command, "matrix") == 0) - { - const char *value = my_strtok_r(NULL, "/ \t", &saveptr); - if(strcmp(value, "{") != 0) - { - ERR("Expected { after %s command, got %s\n", command, value); - goto fail; - } - if(conf->FreqBands == 1) - { - if(strcmp(command, "matrix") != 0) - { - ERR("Unexpected \"%s\" type for a single-band decoder\n", command); - goto fail; - } - if(!load_ambdec_matrix(conf->HFOrderGain, conf->HFMatrix, conf->NumSpeakers, - f, &buffer, &maxlen, &saveptr)) - goto fail; - } - else - { - if(strcmp(command, "lfmatrix") == 0) - { - if(!load_ambdec_matrix(conf->LFOrderGain, conf->LFMatrix, conf->NumSpeakers, - f, &buffer, &maxlen, &saveptr)) - goto fail; - } - else if(strcmp(command, "hfmatrix") == 0) - { - if(!load_ambdec_matrix(conf->HFOrderGain, conf->HFMatrix, conf->NumSpeakers, - f, &buffer, &maxlen, &saveptr)) - goto fail; - } - else - { - ERR("Unexpected \"%s\" type for a dual-band decoder\n", command); - goto fail; - } - } - value = my_strtok_r(NULL, "/ \t", &saveptr); - if(!value) - { - line = read_clipped_line(f, &buffer, &maxlen); - if(!line) - { - ERR("Unexpected end of file\n"); - goto fail; - } - value = my_strtok_r(line, "/ \t", &saveptr); - } - if(strcmp(value, "}") != 0) - { - ERR("Expected } after matrix definitions, got %s\n", value); - goto fail; - } - } - else if(strcmp(command, "end") == 0) - { - line = my_strtok_r(NULL, "/ \t", &saveptr); - if(line) - { - ERR("Unexpected junk on end: %s\n", line); - goto fail; - } - - fclose(f); - free(buffer); - return 1; - } - else - { - ERR("Unexpected command: %s\n", command); - goto fail; - } - - line = my_strtok_r(NULL, "/ \t", &saveptr); - if(line) - { - ERR("Unexpected junk on line: %s\n", line); - goto fail; - } - } - ERR("Unexpected end of file\n"); - -fail: - fclose(f); - free(buffer); - return 0; -} diff --git a/Alc/ambdec.cpp b/Alc/ambdec.cpp new file mode 100644 index 00000000..f3c96dfa --- /dev/null +++ b/Alc/ambdec.cpp @@ -0,0 +1,520 @@ + +#include "config.h" + +#include "ambdec.h" + +#include +#include +#include + +#include + +#include "compat.h" + + +static char *lstrip(char *line) +{ + while(isspace(line[0])) + line++; + return line; +} + +static char *rstrip(char *line) +{ + size_t len = strlen(line); + while(len > 0 && isspace(line[len-1])) + len--; + line[len] = 0; + return line; +} + +static int readline(FILE *f, std::vector &output) +{ + int c; + while((c=fgetc(f)) != EOF && (c == '\r' || c == '\n')) { + } + if(c == EOF) + return 0; + + output.clear(); + do { + output.emplace_back(c); + } while((c=fgetc(f)) != EOF && c != '\r' && c != '\n'); + output.emplace_back((c=0)); + + return 1; +} + + +/* Custom strtok_r, since we can't rely on it existing. */ +static char *my_strtok_r(char *str, const char *delim, char **saveptr) +{ + /* Sanity check and update internal pointer. */ + if(!saveptr || !delim) return nullptr; + if(str) *saveptr = str; + str = *saveptr; + + /* Nothing more to do with this string. */ + if(!str) return nullptr; + + /* Find the first non-delimiter character. */ + while(*str != '\0' && strchr(delim, *str) != nullptr) + str++; + if(*str == '\0') + { + /* End of string. */ + *saveptr = nullptr; + return nullptr; + } + + /* Find the next delimiter character. */ + *saveptr = strpbrk(str, delim); + if(*saveptr) *((*saveptr)++) = '\0'; + + return str; +} + +static char *read_int(ALint *num, const char *line, int base) +{ + char *end; + *num = strtol(line, &end, base); + if(end && *end != '\0') + end = lstrip(end); + return end; +} + +static char *read_uint(ALuint *num, const char *line, int base) +{ + char *end; + *num = strtoul(line, &end, base); + if(end && *end != '\0') + end = lstrip(end); + return end; +} + +static char *read_float(ALfloat *num, const char *line) +{ + char *end; +#ifdef HAVE_STRTOF + *num = strtof(line, &end); +#else + *num = (ALfloat)strtod(line, &end); +#endif + if(end && *end != '\0') + end = lstrip(end); + return end; +} + + +char *read_clipped_line(FILE *f, std::vector &buffer) +{ + while(readline(f, buffer)) + { + char *line, *comment; + + line = lstrip(buffer.data()); + comment = strchr(line, '#'); + if(comment) *(comment++) = 0; + + line = rstrip(line); + if(line[0]) return line; + } + return nullptr; +} + +static int load_ambdec_speakers(AmbDecConf *conf, FILE *f, std::vector &buffer, char **saveptr) +{ + ALsizei cur = 0; + while(cur < conf->NumSpeakers) + { + const char *cmd = my_strtok_r(nullptr, " \t", saveptr); + if(!cmd) + { + char *line = read_clipped_line(f, buffer); + if(!line) + { + ERR("Unexpected end of file\n"); + return 0; + } + cmd = my_strtok_r(line, " \t", saveptr); + } + + if(strcmp(cmd, "add_spkr") == 0) + { + const char *name = my_strtok_r(nullptr, " \t", saveptr); + const char *dist = my_strtok_r(nullptr, " \t", saveptr); + const char *az = my_strtok_r(nullptr, " \t", saveptr); + const char *elev = my_strtok_r(nullptr, " \t", saveptr); + const char *conn = my_strtok_r(nullptr, " \t", saveptr); + + if(!name) WARN("Name not specified for speaker %u\n", cur+1); + else conf->Speakers[cur].Name = name; + if(!dist) WARN("Distance not specified for speaker %u\n", cur+1); + else read_float(&conf->Speakers[cur].Distance, dist); + if(!az) WARN("Azimuth not specified for speaker %u\n", cur+1); + else read_float(&conf->Speakers[cur].Azimuth, az); + if(!elev) WARN("Elevation not specified for speaker %u\n", cur+1); + else read_float(&conf->Speakers[cur].Elevation, elev); + if(!conn) TRACE("Connection not specified for speaker %u\n", cur+1); + else conf->Speakers[cur].Connection = conn; + + cur++; + } + else + { + ERR("Unexpected speakers command: %s\n", cmd); + return 0; + } + + cmd = my_strtok_r(nullptr, " \t", saveptr); + if(cmd) + { + ERR("Unexpected junk on line: %s\n", cmd); + return 0; + } + } + + return 1; +} + +static int load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsizei maxrow, FILE *f, std::vector &buffer, char **saveptr) +{ + int gotgains = 0; + ALsizei cur = 0; + while(cur < maxrow) + { + const char *cmd = my_strtok_r(nullptr, " \t", saveptr); + if(!cmd) + { + char *line = read_clipped_line(f, buffer); + if(!line) + { + ERR("Unexpected end of file\n"); + return 0; + } + cmd = my_strtok_r(line, " \t", saveptr); + } + + if(strcmp(cmd, "order_gain") == 0) + { + ALuint curgain = 0; + char *line; + while((line=my_strtok_r(nullptr, " \t", saveptr)) != nullptr) + { + ALfloat value; + line = read_float(&value, line); + if(line && *line != '\0') + { + ERR("Extra junk on gain %u: %s\n", curgain+1, line); + return 0; + } + if(curgain < MAX_AMBI_ORDER+1) + gains[curgain] = value; + curgain++; + } + while(curgain < MAX_AMBI_ORDER+1) + gains[curgain++] = 0.0f; + gotgains = 1; + } + else if(strcmp(cmd, "add_row") == 0) + { + ALuint curidx = 0; + char *line; + while((line=my_strtok_r(nullptr, " \t", saveptr)) != nullptr) + { + ALfloat value; + line = read_float(&value, line); + if(line && *line != '\0') + { + ERR("Extra junk on matrix element %ux%u: %s\n", cur, curidx, line); + return 0; + } + if(curidx < MAX_AMBI_COEFFS) + matrix[cur][curidx] = value; + curidx++; + } + while(curidx < MAX_AMBI_COEFFS) + matrix[cur][curidx++] = 0.0f; + cur++; + } + else + { + ERR("Unexpected speakers command: %s\n", cmd); + return 0; + } + + cmd = my_strtok_r(nullptr, " \t", saveptr); + if(cmd) + { + ERR("Unexpected junk on line: %s\n", cmd); + return 0; + } + } + + if(!gotgains) + { + ERR("Matrix order_gain not specified\n"); + return 0; + } + + return 1; +} + +int AmbDecConf::load(const char *fname) +{ + std::vector buffer; + char *line; + FILE *f; + + f = al_fopen(fname, "r"); + if(!f) + { + ERR("Failed to open: %s\n", fname); + return 0; + } + + while((line=read_clipped_line(f, buffer)) != nullptr) + { + char *saveptr; + char *command; + + command = my_strtok_r(line, "/ \t", &saveptr); + if(!command) + { + ERR("Malformed line: %s\n", line); + goto fail; + } + + if(strcmp(command, "description") == 0) + { + char *value = my_strtok_r(nullptr, "", &saveptr); + Description = lstrip(value); + } + else if(strcmp(command, "version") == 0) + { + line = my_strtok_r(nullptr, "", &saveptr); + line = read_uint(&Version, line, 10); + if(line && *line != '\0') + { + ERR("Extra junk after version: %s\n", line); + goto fail; + } + if(Version != 3) + { + ERR("Unsupported version: %u\n", Version); + goto fail; + } + } + else if(strcmp(command, "dec") == 0) + { + const char *dec = my_strtok_r(nullptr, "/ \t", &saveptr); + if(strcmp(dec, "chan_mask") == 0) + { + line = my_strtok_r(nullptr, "", &saveptr); + line = read_uint(&ChanMask, line, 16); + if(line && *line != '\0') + { + ERR("Extra junk after mask: %s\n", line); + goto fail; + } + } + else if(strcmp(dec, "freq_bands") == 0) + { + line = my_strtok_r(nullptr, "", &saveptr); + line = read_uint(&FreqBands, line, 10); + if(line && *line != '\0') + { + ERR("Extra junk after freq_bands: %s\n", line); + goto fail; + } + if(FreqBands != 1 && FreqBands != 2) + { + ERR("Invalid freq_bands value: %u\n", FreqBands); + goto fail; + } + } + else if(strcmp(dec, "speakers") == 0) + { + line = my_strtok_r(nullptr, "", &saveptr); + line = read_int(&NumSpeakers, line, 10); + if(line && *line != '\0') + { + ERR("Extra junk after speakers: %s\n", line); + goto fail; + } + if(NumSpeakers > MAX_OUTPUT_CHANNELS) + { + ERR("Unsupported speaker count: %u\n", NumSpeakers); + goto fail; + } + } + else if(strcmp(dec, "coeff_scale") == 0) + { + line = my_strtok_r(nullptr, " \t", &saveptr); + if(strcmp(line, "n3d") == 0) + CoeffScale = AmbDecScale::N3D; + else if(strcmp(line, "sn3d") == 0) + CoeffScale = AmbDecScale::SN3D; + else if(strcmp(line, "fuma") == 0) + CoeffScale = AmbDecScale::FuMa; + else + { + ERR("Unsupported coeff scale: %s\n", line); + goto fail; + } + } + else + { + ERR("Unexpected /dec option: %s\n", dec); + goto fail; + } + } + else if(strcmp(command, "opt") == 0) + { + const char *opt = my_strtok_r(nullptr, "/ \t", &saveptr); + if(strcmp(opt, "xover_freq") == 0) + { + line = my_strtok_r(nullptr, "", &saveptr); + line = read_float(&XOverFreq, line); + if(line && *line != '\0') + { + ERR("Extra junk after xover_freq: %s\n", line); + goto fail; + } + } + else if(strcmp(opt, "xover_ratio") == 0) + { + line = my_strtok_r(nullptr, "", &saveptr); + line = read_float(&XOverRatio, line); + if(line && *line != '\0') + { + ERR("Extra junk after xover_ratio: %s\n", line); + goto fail; + } + } + else if(strcmp(opt, "input_scale") == 0 || strcmp(opt, "nfeff_comp") == 0 || + strcmp(opt, "delay_comp") == 0 || strcmp(opt, "level_comp") == 0) + { + /* Unused */ + my_strtok_r(nullptr, " \t", &saveptr); + } + else + { + ERR("Unexpected /opt option: %s\n", opt); + goto fail; + } + } + else if(strcmp(command, "speakers") == 0) + { + const char *value = my_strtok_r(nullptr, "/ \t", &saveptr); + if(strcmp(value, "{") != 0) + { + ERR("Expected { after %s command, got %s\n", command, value); + goto fail; + } + if(!load_ambdec_speakers(this, f, buffer, &saveptr)) + goto fail; + value = my_strtok_r(nullptr, "/ \t", &saveptr); + if(!value) + { + line = read_clipped_line(f, buffer); + if(!line) + { + ERR("Unexpected end of file\n"); + goto fail; + } + value = my_strtok_r(line, "/ \t", &saveptr); + } + if(strcmp(value, "}") != 0) + { + ERR("Expected } after speaker definitions, got %s\n", value); + goto fail; + } + } + else if(strcmp(command, "lfmatrix") == 0 || strcmp(command, "hfmatrix") == 0 || + strcmp(command, "matrix") == 0) + { + const char *value = my_strtok_r(nullptr, "/ \t", &saveptr); + if(strcmp(value, "{") != 0) + { + ERR("Expected { after %s command, got %s\n", command, value); + goto fail; + } + if(FreqBands == 1) + { + if(strcmp(command, "matrix") != 0) + { + ERR("Unexpected \"%s\" type for a single-band decoder\n", command); + goto fail; + } + if(!load_ambdec_matrix(HFOrderGain, HFMatrix, NumSpeakers, f, buffer, &saveptr)) + goto fail; + } + else + { + if(strcmp(command, "lfmatrix") == 0) + { + if(!load_ambdec_matrix(LFOrderGain, LFMatrix, NumSpeakers, f, buffer, + &saveptr)) + goto fail; + } + else if(strcmp(command, "hfmatrix") == 0) + { + if(!load_ambdec_matrix(HFOrderGain, HFMatrix, NumSpeakers, f, buffer, + &saveptr)) + goto fail; + } + else + { + ERR("Unexpected \"%s\" type for a dual-band decoder\n", command); + goto fail; + } + } + value = my_strtok_r(nullptr, "/ \t", &saveptr); + if(!value) + { + line = read_clipped_line(f, buffer); + if(!line) + { + ERR("Unexpected end of file\n"); + goto fail; + } + value = my_strtok_r(line, "/ \t", &saveptr); + } + if(strcmp(value, "}") != 0) + { + ERR("Expected } after matrix definitions, got %s\n", value); + goto fail; + } + } + else if(strcmp(command, "end") == 0) + { + line = my_strtok_r(nullptr, "/ \t", &saveptr); + if(line) + { + ERR("Unexpected junk on end: %s\n", line); + goto fail; + } + + fclose(f); + return 1; + } + else + { + ERR("Unexpected command: %s\n", command); + goto fail; + } + + line = my_strtok_r(nullptr, "/ \t", &saveptr); + if(line) + { + ERR("Unexpected junk on line: %s\n", line); + goto fail; + } + } + ERR("Unexpected end of file\n"); + +fail: + fclose(f); + return 0; +} diff --git a/Alc/ambdec.h b/Alc/ambdec.h index 7776ae11..d6d154fb 100644 --- a/Alc/ambdec.h +++ b/Alc/ambdec.h @@ -1,38 +1,35 @@ #ifndef AMBDEC_H #define AMBDEC_H -#include "alstring.h" -#include "alMain.h" +#include -#ifdef __cplusplus -extern "C" { -#endif +#include "alMain.h" /* Helpers to read .ambdec configuration files. */ -enum AmbDecScaleType { - ADS_N3D, - ADS_SN3D, - ADS_FuMa, +enum class AmbDecScale { + N3D, + SN3D, + FuMa, }; -typedef struct AmbDecConf { - al_string Description; +struct AmbDecConf { + std::string Description; ALuint Version; /* Must be 3 */ ALuint ChanMask; ALuint FreqBands; /* Must be 1 or 2 */ ALsizei NumSpeakers; - enum AmbDecScaleType CoeffScale; + AmbDecScale CoeffScale; ALfloat XOverFreq; ALfloat XOverRatio; struct { - al_string Name; + std::string Name; ALfloat Distance; ALfloat Azimuth; ALfloat Elevation; - al_string Connection; + std::string Connection; } Speakers[MAX_OUTPUT_CHANNELS]; /* Unused when FreqBands == 1 */ @@ -41,14 +38,8 @@ typedef struct AmbDecConf { ALfloat HFOrderGain[MAX_AMBI_ORDER+1]; ALfloat HFMatrix[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; -} AmbDecConf; -void ambdec_init(AmbDecConf *conf); -void ambdec_deinit(AmbDecConf *conf); -int ambdec_load(AmbDecConf *conf, const char *fname); - -#ifdef __cplusplus -} // extern "C" -#endif + int load(const char *fname); +}; #endif /* AMBDEC_H */ diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 7a3e8ab6..2e0e3b3b 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -204,9 +204,9 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount for(i = 0;i < conf->NumSpeakers;i++) dec->Enabled |= 1 << chanmap[i]; - if(conf->CoeffScale == ADS_SN3D) + if(conf->CoeffScale == AmbDecScale::SN3D) coeff_scale = SN3D2N3DScale; - else if(conf->CoeffScale == ADS_FuMa) + else if(conf->CoeffScale == AmbDecScale::FuMa) coeff_scale = FuMa2N3DScale; memset(dec->UpSampler, 0, sizeof(dec->UpSampler)); diff --git a/Alc/panning.cpp b/Alc/panning.cpp index b9133ecf..db476884 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -275,45 +275,45 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei sp * use the side channels when the device is configured for back, * and vice-versa. */ - if(alstr_cmp_cstr(conf->Speakers[i].Name, "LF") == 0) + if(conf->Speakers[i].Name == "LF") ch = FrontLeft; - else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RF") == 0) + else if(conf->Speakers[i].Name == "RF") ch = FrontRight; - else if(alstr_cmp_cstr(conf->Speakers[i].Name, "CE") == 0) + else if(conf->Speakers[i].Name == "CE") ch = FrontCenter; - else if(alstr_cmp_cstr(conf->Speakers[i].Name, "LS") == 0) + else if(conf->Speakers[i].Name == "LS") { if(device->FmtChans == DevFmtX51Rear) ch = BackLeft; else ch = SideLeft; } - else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RS") == 0) + else if(conf->Speakers[i].Name == "RS") { if(device->FmtChans == DevFmtX51Rear) ch = BackRight; else ch = SideRight; } - else if(alstr_cmp_cstr(conf->Speakers[i].Name, "LB") == 0) + else if(conf->Speakers[i].Name == "LB") { if(device->FmtChans == DevFmtX51) ch = SideLeft; else ch = BackLeft; } - else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RB") == 0) + else if(conf->Speakers[i].Name == "RB") { if(device->FmtChans == DevFmtX51) ch = SideRight; else ch = BackRight; } - else if(alstr_cmp_cstr(conf->Speakers[i].Name, "CB") == 0) + else if(conf->Speakers[i].Name == "CB") ch = BackCenter; else { - const char *name = alstr_get_cstr(conf->Speakers[i].Name); + const char *name = conf->Speakers[i].Name.c_str(); unsigned int n; char c; @@ -329,7 +329,7 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei sp if(chidx == -1) { ERR("Failed to lookup AmbDec speaker label %s\n", - alstr_get_cstr(conf->Speakers[i].Name)); + conf->Speakers[i].Name.c_str()); return false; } speakermap[i] = chidx; @@ -423,14 +423,14 @@ static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const AL srate + 0.5f); if(delay >= (ALfloat)MAX_DELAY_LENGTH) ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n", - alstr_get_cstr(conf->Speakers[i].Name), delay, MAX_DELAY_LENGTH); + conf->Speakers[i].Name.c_str(), delay, MAX_DELAY_LENGTH); device->ChannelDelay[chan].Length = (ALsizei)clampf( delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1) ); device->ChannelDelay[chan].Gain = conf->Speakers[i].Distance / maxdist; TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan, - alstr_get_cstr(conf->Speakers[i].Name), device->ChannelDelay[chan].Length, + conf->Speakers[i].Name.c_str(), device->ChannelDelay[chan].Length, device->ChannelDelay[chan].Gain ); @@ -639,9 +639,9 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A } } - if(conf->CoeffScale == ADS_SN3D) + if(conf->CoeffScale == AmbDecScale::SN3D) coeff_scale = SN3D2N3DScale; - else if(conf->CoeffScale == ADS_FuMa) + else if(conf->CoeffScale == AmbDecScale::FuMa) coeff_scale = FuMa2N3DScale; for(i = 0;i < conf->NumSpeakers;i++) @@ -963,8 +963,6 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(hrtf_appreq == Hrtf_Enable) device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; - ambdec_init(&conf); - devname = alstr_get_cstr(device->DeviceName); switch(device->FmtChans) { @@ -984,7 +982,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf const char *fname; if(ConfigValueStr(devname, "decoder", layout, &fname)) { - if(!ambdec_load(&conf, fname)) + if(!conf.load(fname)) ERR("Failed to load layout file %s\n", fname); else { @@ -1062,7 +1060,6 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf } TRACE("Front stablizer %s\n", device->Stablizer ? "enabled" : "disabled"); - ambdec_deinit(&conf); return; } diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a97741b..6d4d41d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -874,7 +874,7 @@ SET(ALC_OBJS Alc/hrtf.h Alc/uhjfilter.cpp Alc/uhjfilter.h - Alc/ambdec.c + Alc/ambdec.cpp Alc/ambdec.h Alc/bformatdec.cpp Alc/bformatdec.h -- cgit v1.2.3 From 087fdd3ca983da6b0727adaa33f7519abf0ed296 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 4 Nov 2018 15:19:48 -0800 Subject: Properly mark arrays constexpr and/or static --- Alc/bformatdec.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 2e0e3b3b..c9e7b567 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -66,7 +66,7 @@ namespace { #define NUM_BANDS 2 /* These points are in AL coordinates! */ -const ALfloat Ambi3DPoints[8][3] = { +constexpr ALfloat Ambi3DPoints[8][3] = { { -0.577350269f, 0.577350269f, -0.577350269f }, { 0.577350269f, 0.577350269f, -0.577350269f }, { -0.577350269f, 0.577350269f, 0.577350269f }, @@ -76,7 +76,7 @@ const ALfloat Ambi3DPoints[8][3] = { { -0.577350269f, -0.577350269f, 0.577350269f }, { 0.577350269f, -0.577350269f, 0.577350269f }, }; -const ALfloat Ambi3DDecoder[8][MAX_AMBI_COEFFS] = { +constexpr ALfloat Ambi3DDecoder[8][MAX_AMBI_COEFFS] = { { 0.125f, 0.125f, 0.125f, 0.125f }, { 0.125f, -0.125f, 0.125f, 0.125f }, { 0.125f, 0.125f, 0.125f, -0.125f }, @@ -86,7 +86,7 @@ const ALfloat Ambi3DDecoder[8][MAX_AMBI_COEFFS] = { { 0.125f, 0.125f, -0.125f, -0.125f }, { 0.125f, -0.125f, -0.125f, -0.125f }, }; -const ALfloat Ambi3DDecoderHFScale[MAX_AMBI_COEFFS] = { +constexpr ALfloat Ambi3DDecoderHFScale[MAX_AMBI_COEFFS] = { 2.0f, 1.15470054f, 1.15470054f, 1.15470054f }; @@ -183,7 +183,7 @@ void bformatdec_free(BFormatDec **dec) void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS]) { - constexpr ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = { + static constexpr ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; const ALfloat *coeff_scale = N3D2N3DScale; -- cgit v1.2.3 From 26f7007507b8a25cb56cb243c232f18ffc901a89 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 4 Nov 2018 15:21:03 -0800 Subject: Allocate the appropriate amount in the aligned allocator --- Alc/bformatdec.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index c9e7b567..7d1e36ff 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -119,7 +119,7 @@ public: }; pointer allocate(size_type n, const void* = nullptr) - { return reinterpret_cast(al_malloc(alignment, n)); } + { return reinterpret_cast(al_malloc(alignment, n*sizeof(T))); } void deallocate(pointer p, size_type) { al_free(p); } -- cgit v1.2.3 From 4dafb7dab136e85ebf362a309dd4feabd1e3b1a1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 4 Nov 2018 15:24:24 -0800 Subject: Use C++ to read and parse ambdec files --- Alc/ambdec.cpp | 575 ++++++++++++++++++++++++--------------------------------- Alc/compat.h | 176 ++++++++++++++++++ 2 files changed, 417 insertions(+), 334 deletions(-) diff --git a/Alc/ambdec.cpp b/Alc/ambdec.cpp index f3c96dfa..4239a694 100644 --- a/Alc/ambdec.cpp +++ b/Alc/ambdec.cpp @@ -3,235 +3,177 @@ #include "ambdec.h" -#include -#include -#include +#include +#include -#include +#include +#include +#include +#include #include "compat.h" -static char *lstrip(char *line) -{ - while(isspace(line[0])) - line++; - return line; -} +namespace { -static char *rstrip(char *line) +int readline(std::istream &f, std::string &output) { - size_t len = strlen(line); - while(len > 0 && isspace(line[len-1])) - len--; - line[len] = 0; - return line; -} - -static int readline(FILE *f, std::vector &output) -{ - int c; - while((c=fgetc(f)) != EOF && (c == '\r' || c == '\n')) { - } - if(c == EOF) - return 0; + while(f.good() && f.peek() == '\n') + f.ignore(); - output.clear(); - do { - output.emplace_back(c); - } while((c=fgetc(f)) != EOF && c != '\r' && c != '\n'); - output.emplace_back((c=0)); - - return 1; + std::getline(f, output); + return !output.empty(); } - -/* Custom strtok_r, since we can't rely on it existing. */ -static char *my_strtok_r(char *str, const char *delim, char **saveptr) +bool read_clipped_line(std::istream &f, std::string &buffer) { - /* Sanity check and update internal pointer. */ - if(!saveptr || !delim) return nullptr; - if(str) *saveptr = str; - str = *saveptr; - - /* Nothing more to do with this string. */ - if(!str) return nullptr; - - /* Find the first non-delimiter character. */ - while(*str != '\0' && strchr(delim, *str) != nullptr) - str++; - if(*str == '\0') + while(readline(f, buffer)) { - /* End of string. */ - *saveptr = nullptr; - return nullptr; + std::size_t pos{0}; + while(pos < buffer.length() && std::isspace(buffer[pos])) + pos++; + buffer.erase(0, pos); + + std::size_t cmtpos{buffer.find_first_of('#')}; + if(cmtpos < buffer.length()) + buffer.resize(cmtpos); + while(!buffer.empty() && std::isspace(buffer.back())) + buffer.pop_back(); + + if(!buffer.empty()) + return true; } - - /* Find the next delimiter character. */ - *saveptr = strpbrk(str, delim); - if(*saveptr) *((*saveptr)++) = '\0'; - - return str; + return false; } -static char *read_int(ALint *num, const char *line, int base) -{ - char *end; - *num = strtol(line, &end, base); - if(end && *end != '\0') - end = lstrip(end); - return end; -} -static char *read_uint(ALuint *num, const char *line, int base) +std::string read_word(std::istream &f) { - char *end; - *num = strtoul(line, &end, base); - if(end && *end != '\0') - end = lstrip(end); - return end; + std::string ret; + f >> ret; + return ret; } -static char *read_float(ALfloat *num, const char *line) +bool is_at_end(const std::string &buffer, std::size_t endpos) { - char *end; -#ifdef HAVE_STRTOF - *num = strtof(line, &end); -#else - *num = (ALfloat)strtod(line, &end); -#endif - if(end && *end != '\0') - end = lstrip(end); - return end; + while(endpos < buffer.length() && std::isspace(buffer[endpos])) + ++endpos; + if(endpos < buffer.length()) + return false; + return true; } -char *read_clipped_line(FILE *f, std::vector &buffer) -{ - while(readline(f, buffer)) - { - char *line, *comment; - - line = lstrip(buffer.data()); - comment = strchr(line, '#'); - if(comment) *(comment++) = 0; - - line = rstrip(line); - if(line[0]) return line; - } - return nullptr; -} - -static int load_ambdec_speakers(AmbDecConf *conf, FILE *f, std::vector &buffer, char **saveptr) +bool load_ambdec_speakers(AmbDecConf *conf, std::istream &f, std::string &buffer) { ALsizei cur = 0; while(cur < conf->NumSpeakers) { - const char *cmd = my_strtok_r(nullptr, " \t", saveptr); - if(!cmd) + std::istringstream istr{buffer}; + + std::string cmd = read_word(istr); + if(cmd.empty()) { - char *line = read_clipped_line(f, buffer); - if(!line) + if(!read_clipped_line(f, buffer)) { ERR("Unexpected end of file\n"); - return 0; + return false; } - cmd = my_strtok_r(line, " \t", saveptr); + istr = std::istringstream{buffer}; + cmd = read_word(istr); } - if(strcmp(cmd, "add_spkr") == 0) + if(cmd == "add_spkr") { - const char *name = my_strtok_r(nullptr, " \t", saveptr); - const char *dist = my_strtok_r(nullptr, " \t", saveptr); - const char *az = my_strtok_r(nullptr, " \t", saveptr); - const char *elev = my_strtok_r(nullptr, " \t", saveptr); - const char *conn = my_strtok_r(nullptr, " \t", saveptr); - - if(!name) WARN("Name not specified for speaker %u\n", cur+1); - else conf->Speakers[cur].Name = name; - if(!dist) WARN("Distance not specified for speaker %u\n", cur+1); - else read_float(&conf->Speakers[cur].Distance, dist); - if(!az) WARN("Azimuth not specified for speaker %u\n", cur+1); - else read_float(&conf->Speakers[cur].Azimuth, az); - if(!elev) WARN("Elevation not specified for speaker %u\n", cur+1); - else read_float(&conf->Speakers[cur].Elevation, elev); - if(!conn) TRACE("Connection not specified for speaker %u\n", cur+1); - else conf->Speakers[cur].Connection = conn; + istr >> conf->Speakers[cur].Name; + if(istr.fail()) WARN("Name not specified for speaker %u\n", cur+1); + istr >> conf->Speakers[cur].Distance; + if(istr.fail()) WARN("Distance not specified for speaker %u\n", cur+1); + istr >> conf->Speakers[cur].Azimuth; + if(istr.fail()) WARN("Azimuth not specified for speaker %u\n", cur+1); + istr >> conf->Speakers[cur].Elevation; + if(istr.fail()) WARN("Elevation not specified for speaker %u\n", cur+1); + istr >> conf->Speakers[cur].Connection; + if(istr.fail()) TRACE("Connection not specified for speaker %u\n", cur+1); cur++; } else { - ERR("Unexpected speakers command: %s\n", cmd); - return 0; + ERR("Unexpected speakers command: %s\n", cmd.c_str()); + return false; } - cmd = my_strtok_r(nullptr, " \t", saveptr); - if(cmd) + istr.clear(); + std::streamsize endpos{istr.tellg()}; + if(!is_at_end(buffer, endpos)) { - ERR("Unexpected junk on line: %s\n", cmd); - return 0; + ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); + return false; } + buffer.clear(); } - return 1; + return true; } -static int load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsizei maxrow, FILE *f, std::vector &buffer, char **saveptr) +bool load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsizei maxrow, std::istream &f, std::string &buffer) { - int gotgains = 0; + bool gotgains = false; ALsizei cur = 0; while(cur < maxrow) { - const char *cmd = my_strtok_r(nullptr, " \t", saveptr); - if(!cmd) + std::istringstream istr{buffer}; + std::string cmd; + + istr >> cmd; + if(cmd.empty()) { - char *line = read_clipped_line(f, buffer); - if(!line) + if(!read_clipped_line(f, buffer)) { ERR("Unexpected end of file\n"); - return 0; + return false; } - cmd = my_strtok_r(line, " \t", saveptr); + istr = std::istringstream{buffer}; + istr >> cmd; } - if(strcmp(cmd, "order_gain") == 0) + if(cmd == "order_gain") { ALuint curgain = 0; - char *line; - while((line=my_strtok_r(nullptr, " \t", saveptr)) != nullptr) + float value; + while(istr.good()) { - ALfloat value; - line = read_float(&value, line); - if(line && *line != '\0') + istr >> value; + if(istr.fail()) break; + if(!istr.eof() && !std::isspace(istr.peek())) { - ERR("Extra junk on gain %u: %s\n", curgain+1, line); - return 0; + ERR("Extra junk on gain %u: %s\n", curgain+1, buffer.c_str()+istr.tellg()); + return false; } if(curgain < MAX_AMBI_ORDER+1) - gains[curgain] = value; - curgain++; + gains[curgain++] = value; } while(curgain < MAX_AMBI_ORDER+1) gains[curgain++] = 0.0f; - gotgains = 1; + gotgains = true; } - else if(strcmp(cmd, "add_row") == 0) + else if(cmd == "add_row") { ALuint curidx = 0; - char *line; - while((line=my_strtok_r(nullptr, " \t", saveptr)) != nullptr) + float value; + while(istr.good()) { - ALfloat value; - line = read_float(&value, line); - if(line && *line != '\0') + istr >> value; + if(istr.fail()) break; + if(!istr.eof() && !std::isspace(istr.peek())) { - ERR("Extra junk on matrix element %ux%u: %s\n", cur, curidx, line); - return 0; + ERR("Extra junk on matrix element %ux%u: %s\n", cur, curidx, + buffer.c_str()+istr.tellg()); + return false; } if(curidx < MAX_AMBI_COEFFS) - matrix[cur][curidx] = value; - curidx++; + matrix[cur][curidx++] = value; } while(curidx < MAX_AMBI_COEFFS) matrix[cur][curidx++] = 0.0f; @@ -239,282 +181,247 @@ static int load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS] } else { - ERR("Unexpected speakers command: %s\n", cmd); - return 0; + ERR("Unexpected matrix command: %s\n", cmd.c_str()); + return false; } - cmd = my_strtok_r(nullptr, " \t", saveptr); - if(cmd) + istr.clear(); + std::streamsize endpos{istr.tellg()}; + if(!is_at_end(buffer, endpos)) { - ERR("Unexpected junk on line: %s\n", cmd); - return 0; + ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); + return false; } + buffer.clear(); } if(!gotgains) { ERR("Matrix order_gain not specified\n"); - return 0; + return false; } - return 1; + return true; } +} // namespace + int AmbDecConf::load(const char *fname) { - std::vector buffer; - char *line; - FILE *f; - - f = al_fopen(fname, "r"); - if(!f) + al::ifstream f{fname}; + if(!f.is_open()) { ERR("Failed to open: %s\n", fname); return 0; } - while((line=read_clipped_line(f, buffer)) != nullptr) + std::string buffer; + while(read_clipped_line(f, buffer)) { - char *saveptr; - char *command; + std::istringstream istr{buffer}; + std::string command; - command = my_strtok_r(line, "/ \t", &saveptr); - if(!command) + istr >> command; + if(command.empty()) { - ERR("Malformed line: %s\n", line); - goto fail; + ERR("Malformed line: %s\n", buffer.c_str()); + return 0; } - if(strcmp(command, "description") == 0) + if(command == "/description") + istr >> Description; + else if(command == "/version") { - char *value = my_strtok_r(nullptr, "", &saveptr); - Description = lstrip(value); - } - else if(strcmp(command, "version") == 0) - { - line = my_strtok_r(nullptr, "", &saveptr); - line = read_uint(&Version, line, 10); - if(line && *line != '\0') + istr >> Version; + if(!istr.eof() && !std::isspace(istr.peek())) { - ERR("Extra junk after version: %s\n", line); - goto fail; + ERR("Extra junk after version: %s\n", buffer.c_str()+istr.tellg()); + return 0; } if(Version != 3) { ERR("Unsupported version: %u\n", Version); - goto fail; + return 0; } } - else if(strcmp(command, "dec") == 0) + else if(command == "/dec/chan_mask") { - const char *dec = my_strtok_r(nullptr, "/ \t", &saveptr); - if(strcmp(dec, "chan_mask") == 0) + istr >> std::hex >> ChanMask >> std::dec; + if(!istr.eof() && !std::isspace(istr.peek())) { - line = my_strtok_r(nullptr, "", &saveptr); - line = read_uint(&ChanMask, line, 16); - if(line && *line != '\0') - { - ERR("Extra junk after mask: %s\n", line); - goto fail; - } + ERR("Extra junk after mask: %s\n", buffer.c_str()+istr.tellg()); + return 0; } - else if(strcmp(dec, "freq_bands") == 0) + } + else if(command == "/dec/freq_bands") + { + istr >> FreqBands; + if(!istr.eof() && !std::isspace(istr.peek())) { - line = my_strtok_r(nullptr, "", &saveptr); - line = read_uint(&FreqBands, line, 10); - if(line && *line != '\0') - { - ERR("Extra junk after freq_bands: %s\n", line); - goto fail; - } - if(FreqBands != 1 && FreqBands != 2) - { - ERR("Invalid freq_bands value: %u\n", FreqBands); - goto fail; - } + ERR("Extra junk after freq_bands: %s\n", buffer.c_str()+istr.tellg()); + return 0; } - else if(strcmp(dec, "speakers") == 0) + if(FreqBands != 1 && FreqBands != 2) { - line = my_strtok_r(nullptr, "", &saveptr); - line = read_int(&NumSpeakers, line, 10); - if(line && *line != '\0') - { - ERR("Extra junk after speakers: %s\n", line); - goto fail; - } - if(NumSpeakers > MAX_OUTPUT_CHANNELS) - { - ERR("Unsupported speaker count: %u\n", NumSpeakers); - goto fail; - } + ERR("Invalid freq_bands value: %u\n", FreqBands); + return 0; } - else if(strcmp(dec, "coeff_scale") == 0) + } + else if(command == "/dec/speakers") + { + istr >> NumSpeakers; + if(!istr.eof() && !std::isspace(istr.peek())) { - line = my_strtok_r(nullptr, " \t", &saveptr); - if(strcmp(line, "n3d") == 0) - CoeffScale = AmbDecScale::N3D; - else if(strcmp(line, "sn3d") == 0) - CoeffScale = AmbDecScale::SN3D; - else if(strcmp(line, "fuma") == 0) - CoeffScale = AmbDecScale::FuMa; - else - { - ERR("Unsupported coeff scale: %s\n", line); - goto fail; - } + ERR("Extra junk after speakers: %s\n", buffer.c_str()+istr.tellg()); + return 0; } - else + if(NumSpeakers > MAX_OUTPUT_CHANNELS) { - ERR("Unexpected /dec option: %s\n", dec); - goto fail; + ERR("Unsupported speaker count: %u\n", NumSpeakers); + return 0; } } - else if(strcmp(command, "opt") == 0) + else if(command == "/dec/coeff_scale") { - const char *opt = my_strtok_r(nullptr, "/ \t", &saveptr); - if(strcmp(opt, "xover_freq") == 0) - { - line = my_strtok_r(nullptr, "", &saveptr); - line = read_float(&XOverFreq, line); - if(line && *line != '\0') - { - ERR("Extra junk after xover_freq: %s\n", line); - goto fail; - } - } - else if(strcmp(opt, "xover_ratio") == 0) + std::string scale = read_word(istr); + if(scale == "n3d") CoeffScale = AmbDecScale::N3D; + else if(scale == "sn3d") CoeffScale = AmbDecScale::SN3D; + else if(scale == "fuma") CoeffScale = AmbDecScale::FuMa; + else { - line = my_strtok_r(nullptr, "", &saveptr); - line = read_float(&XOverRatio, line); - if(line && *line != '\0') - { - ERR("Extra junk after xover_ratio: %s\n", line); - goto fail; - } + ERR("Unsupported coeff scale: %s\n", scale.c_str()); + return 0; } - else if(strcmp(opt, "input_scale") == 0 || strcmp(opt, "nfeff_comp") == 0 || - strcmp(opt, "delay_comp") == 0 || strcmp(opt, "level_comp") == 0) + } + else if(command == "/opt/xover_freq") + { + istr >> XOverFreq; + if(!istr.eof() && !std::isspace(istr.peek())) { - /* Unused */ - my_strtok_r(nullptr, " \t", &saveptr); + ERR("Extra junk after xover_freq: %s\n", buffer.c_str()+istr.tellg()); + return 0; } - else + } + else if(command == "/opt/xover_ratio") + { + istr >> XOverRatio; + if(!istr.eof() && !std::isspace(istr.peek())) { - ERR("Unexpected /opt option: %s\n", opt); - goto fail; + ERR("Extra junk after xover_ratio: %s\n", buffer.c_str()+istr.tellg()); + return 0; } } - else if(strcmp(command, "speakers") == 0) + else if(command == "/opt/input_scale" || command == "/opt/nfeff_comp" || + command == "/opt/delay_comp" || command == "/opt/level_comp") { - const char *value = my_strtok_r(nullptr, "/ \t", &saveptr); - if(strcmp(value, "{") != 0) + /* Unused */ + read_word(istr); + } + else if(command == "/speakers/{") + { + std::streamsize endpos{istr.tellg()}; + if(!is_at_end(buffer, endpos)) { - ERR("Expected { after %s command, got %s\n", command, value); - goto fail; + ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); + return 0; } - if(!load_ambdec_speakers(this, f, buffer, &saveptr)) - goto fail; - value = my_strtok_r(nullptr, "/ \t", &saveptr); - if(!value) + buffer.clear(); + + if(!load_ambdec_speakers(this, f, buffer)) + return 0; + + if(!read_clipped_line(f, buffer)) { - line = read_clipped_line(f, buffer); - if(!line) - { - ERR("Unexpected end of file\n"); - goto fail; - } - value = my_strtok_r(line, "/ \t", &saveptr); + ERR("Unexpected end of file\n"); + return 0; } - if(strcmp(value, "}") != 0) + istr = std::istringstream{buffer}; + std::string endmark = read_word(istr); + if(endmark != "/}") { - ERR("Expected } after speaker definitions, got %s\n", value); - goto fail; + ERR("Expected /} after speaker definitions, got %s\n", endmark.c_str()); + return 0; } } - else if(strcmp(command, "lfmatrix") == 0 || strcmp(command, "hfmatrix") == 0 || - strcmp(command, "matrix") == 0) + else if(command == "/lfmatrix/{" || command == "/hfmatrix/{" || command == "/matrix/{") { - const char *value = my_strtok_r(nullptr, "/ \t", &saveptr); - if(strcmp(value, "{") != 0) + std::streamsize endpos{istr.tellg()}; + if(!is_at_end(buffer, endpos)) { - ERR("Expected { after %s command, got %s\n", command, value); - goto fail; + ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); + return 0; } + buffer.clear(); + if(FreqBands == 1) { - if(strcmp(command, "matrix") != 0) + if(command != "/matrix/{") { - ERR("Unexpected \"%s\" type for a single-band decoder\n", command); - goto fail; + ERR("Unexpected \"%s\" type for a single-band decoder\n", command.c_str()); + return 0; } - if(!load_ambdec_matrix(HFOrderGain, HFMatrix, NumSpeakers, f, buffer, &saveptr)) - goto fail; + if(!load_ambdec_matrix(HFOrderGain, HFMatrix, NumSpeakers, f, buffer)) + return 0; } else { - if(strcmp(command, "lfmatrix") == 0) + if(command == "/lfmatrix/{") { - if(!load_ambdec_matrix(LFOrderGain, LFMatrix, NumSpeakers, f, buffer, - &saveptr)) - goto fail; + if(!load_ambdec_matrix(LFOrderGain, LFMatrix, NumSpeakers, f, buffer)) + return 0; } - else if(strcmp(command, "hfmatrix") == 0) + else if(command == "/hfmatrix/{") { - if(!load_ambdec_matrix(HFOrderGain, HFMatrix, NumSpeakers, f, buffer, - &saveptr)) - goto fail; + if(!load_ambdec_matrix(HFOrderGain, HFMatrix, NumSpeakers, f, buffer)) + return 0; } else { - ERR("Unexpected \"%s\" type for a dual-band decoder\n", command); - goto fail; + ERR("Unexpected \"%s\" type for a dual-band decoder\n", command.c_str()); + return 0; } } - value = my_strtok_r(nullptr, "/ \t", &saveptr); - if(!value) + + if(!read_clipped_line(f, buffer)) { - line = read_clipped_line(f, buffer); - if(!line) - { - ERR("Unexpected end of file\n"); - goto fail; - } - value = my_strtok_r(line, "/ \t", &saveptr); + ERR("Unexpected end of file\n"); + return 0; } - if(strcmp(value, "}") != 0) + istr = std::istringstream{buffer}; + std::string endmark = read_word(istr); + if(endmark != "/}") { - ERR("Expected } after matrix definitions, got %s\n", value); - goto fail; + ERR("Expected /} after matrix definitions, got %s\n", endmark.c_str()); + return 0; } } - else if(strcmp(command, "end") == 0) + else if(command == "/end") { - line = my_strtok_r(nullptr, "/ \t", &saveptr); - if(line) + std::streamsize endpos{istr.tellg()}; + if(!is_at_end(buffer, endpos)) { - ERR("Unexpected junk on end: %s\n", line); - goto fail; + ERR("Unexpected junk on end: %s\n", buffer.c_str()+endpos); + return 0; } - fclose(f); return 1; } else { - ERR("Unexpected command: %s\n", command); - goto fail; + ERR("Unexpected command: %s\n", command.c_str()); + return 0; } - line = my_strtok_r(nullptr, "/ \t", &saveptr); - if(line) + istr.clear(); + std::streamsize endpos{istr.tellg()}; + if(!is_at_end(buffer, endpos)) { - ERR("Unexpected junk on line: %s\n", line); - goto fail; + ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); + return 0; } + buffer.clear(); } ERR("Unexpected end of file\n"); -fail: - fclose(f); return 0; } diff --git a/Alc/compat.h b/Alc/compat.h index c478c01d..1c348c34 100644 --- a/Alc/compat.h +++ b/Alc/compat.h @@ -22,7 +22,9 @@ FILE *al_fopen(const char *fname, const char *mode); #ifdef __cplusplus } // extern "C" +#include #include +#include inline std::string wstr_to_utf8(const WCHAR *wstr) { @@ -39,6 +41,164 @@ inline std::string wstr_to_utf8(const WCHAR *wstr) return ret; } +inline std::wstring utf8_to_wstr(const char *str) +{ + std::wstring ret; + + int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + if(len > 0) + { + ret.resize(len); + MultiByteToWideChar(CP_UTF8, 0, str, -1, &ret[0], len); + ret.pop_back(); + } + + return ret; +} + + +namespace al { + +// Windows' std::ifstream fails with non-ANSI paths since the standard only +// specifies names using const char* (or std::string). MSVC has a non-standard +// extension using const wchar_t* (or std::wstring?) to handle Unicode paths, +// but not all Windows compilers support it. So we have to make our own istream +// that accepts UTF-8 paths and forwards to Unicode-aware I/O functions. +class filebuf final : public std::streambuf { + std::array mBuffer; + HANDLE mFile{INVALID_HANDLE_VALUE}; + + int_type underflow() override + { + if(mFile != INVALID_HANDLE_VALUE && gptr() == egptr()) + { + // Read in the next chunk of data, and set the pointers on success + DWORD got = 0; + if(ReadFile(mFile, mBuffer.data(), (DWORD)mBuffer.size(), &got, nullptr)) + setg(mBuffer.data(), mBuffer.data(), mBuffer.data()+got); + } + if(gptr() == egptr()) + return traits_type::eof(); + return traits_type::to_int_type(*gptr()); + } + + pos_type seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) override + { + if(mFile == INVALID_HANDLE_VALUE || (mode&std::ios_base::out) || !(mode&std::ios_base::in)) + return traits_type::eof(); + + LARGE_INTEGER fpos; + switch(whence) + { + case std::ios_base::beg: + fpos.QuadPart = offset; + if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_BEGIN)) + return traits_type::eof(); + break; + + case std::ios_base::cur: + // If the offset remains in the current buffer range, just + // update the pointer. + if((offset >= 0 && offset < off_type(egptr()-gptr())) || + (offset < 0 && -offset <= off_type(gptr()-eback()))) + { + // Get the current file offset to report the correct read + // offset. + fpos.QuadPart = 0; + if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_CURRENT)) + return traits_type::eof(); + setg(eback(), gptr()+offset, egptr()); + return fpos.QuadPart - off_type(egptr()-gptr()); + } + // Need to offset for the file offset being at egptr() while + // the requested offset is relative to gptr(). + offset -= off_type(egptr()-gptr()); + fpos.QuadPart = offset; + if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_CURRENT)) + return traits_type::eof(); + break; + + case std::ios_base::end: + fpos.QuadPart = offset; + if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_END)) + return traits_type::eof(); + break; + + default: + return traits_type::eof(); + } + setg(nullptr, nullptr, nullptr); + return fpos.QuadPart; + } + + pos_type seekpos(pos_type pos, std::ios_base::openmode mode) override + { + // Simplified version of seekoff + if(mFile == INVALID_HANDLE_VALUE || (mode&std::ios_base::out) || !(mode&std::ios_base::in)) + return traits_type::eof(); + + LARGE_INTEGER fpos; + fpos.QuadPart = pos; + if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_BEGIN)) + return traits_type::eof(); + + setg(nullptr, nullptr, nullptr); + return fpos.QuadPart; + } + +public: + bool open(const wchar_t *filename) + { + mFile = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + if(mFile == INVALID_HANDLE_VALUE) return false; + return true; + } + bool open(const char *filename) + { + std::wstring wname{utf8_to_wstr(filename)}; + return open(wname.c_str()); + } + + bool is_open() const noexcept { return mFile != INVALID_HANDLE_VALUE; } + + filebuf() = default; + ~filebuf() override + { + if(mFile != INVALID_HANDLE_VALUE) + CloseHandle(mFile); + mFile = INVALID_HANDLE_VALUE; + } +}; + +// Inherit from std::istream to use our custom streambuf +class ifstream final : public std::istream { + filebuf mStreamBuf; + +public: + ifstream(const std::wstring &filename) : ifstream{filename.c_str()} { } + ifstream(const wchar_t *filename) : std::istream{nullptr} + { + init(&mStreamBuf); + + // Set the failbit if the file failed to open. + if(!mStreamBuf.open(filename)) clear(failbit); + } + + ifstream(const std::string &filename) : ifstream{filename.c_str()} { } + ifstream(const char *filename) : std::istream{nullptr} + { + init(&mStreamBuf); + + // Set the failbit if the file failed to open. + if(!mStreamBuf.open(filename)) clear(failbit); + } + + bool is_open() const noexcept { return mStreamBuf.is_open(); } +}; + +} // namespace al + extern "C" { #endif /* __cplusplus */ @@ -50,6 +210,22 @@ extern "C" { #define HAVE_DYNLOAD 1 #endif + +#ifdef __cplusplus +} // extern "C" + +#include + +namespace al { + +using filebuf = std::filebuf; +using ifstream = std::ifstream; + +} // namespace al + +extern "C" { +#endif /* __cplusplus */ + #endif struct FileMapping { -- cgit v1.2.3 From 9fa31fcd07bcc1855a374f6d8a867503f9b49704 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 4 Nov 2018 19:11:07 -0800 Subject: Avoid moving istringstreams Doesn't work with GCC 4.x. Hopefully swapping does. --- Alc/ambdec.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/Alc/ambdec.cpp b/Alc/ambdec.cpp index 4239a694..306b942b 100644 --- a/Alc/ambdec.cpp +++ b/Alc/ambdec.cpp @@ -71,7 +71,7 @@ bool load_ambdec_speakers(AmbDecConf *conf, std::istream &f, std::string &buffer { std::istringstream istr{buffer}; - std::string cmd = read_word(istr); + std::string cmd{read_word(istr)}; if(cmd.empty()) { if(!read_clipped_line(f, buffer)) @@ -79,8 +79,7 @@ bool load_ambdec_speakers(AmbDecConf *conf, std::istream &f, std::string &buffer ERR("Unexpected end of file\n"); return false; } - istr = std::istringstream{buffer}; - cmd = read_word(istr); + continue; } if(cmd == "add_spkr") @@ -124,9 +123,8 @@ bool load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsi while(cur < maxrow) { std::istringstream istr{buffer}; - std::string cmd; - istr >> cmd; + std::string cmd{read_word(istr)}; if(cmd.empty()) { if(!read_clipped_line(f, buffer)) @@ -134,8 +132,7 @@ bool load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsi ERR("Unexpected end of file\n"); return false; } - istr = std::istringstream{buffer}; - istr >> cmd; + continue; } if(cmd == "order_gain") @@ -219,9 +216,8 @@ int AmbDecConf::load(const char *fname) while(read_clipped_line(f, buffer)) { std::istringstream istr{buffer}; - std::string command; - istr >> command; + std::string command{read_word(istr)}; if(command.empty()) { ERR("Malformed line: %s\n", buffer.c_str()); @@ -335,13 +331,14 @@ int AmbDecConf::load(const char *fname) ERR("Unexpected end of file\n"); return 0; } - istr = std::istringstream{buffer}; - std::string endmark = read_word(istr); + std::istringstream istr2{buffer}; + std::string endmark{read_word(istr2)}; if(endmark != "/}") { ERR("Expected /} after speaker definitions, got %s\n", endmark.c_str()); return 0; } + istr.swap(istr2); } else if(command == "/lfmatrix/{" || command == "/hfmatrix/{" || command == "/matrix/{") { @@ -387,13 +384,14 @@ int AmbDecConf::load(const char *fname) ERR("Unexpected end of file\n"); return 0; } - istr = std::istringstream{buffer}; - std::string endmark = read_word(istr); + std::istringstream istr2{buffer}; + std::string endmark{read_word(istr2)}; if(endmark != "/}") { ERR("Expected /} after matrix definitions, got %s\n", endmark.c_str()); return 0; } + istr.swap(istr2); } else if(command == "/end") { -- cgit v1.2.3 From 3b664041bab1e87af4831ddbe23960e44c4acfbc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 6 Nov 2018 02:17:20 -0800 Subject: Convert the DSound backend to C++ --- Alc/backends/dsound.c | 1079 ----------------------------------------------- Alc/backends/dsound.cpp | 1051 +++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 1052 insertions(+), 1080 deletions(-) delete mode 100644 Alc/backends/dsound.c create mode 100644 Alc/backends/dsound.cpp diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c deleted file mode 100644 index c368cffb..00000000 --- a/Alc/backends/dsound.c +++ /dev/null @@ -1,1079 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include -#include -#include -#ifndef _WAVEFORMATEXTENSIBLE_ -#include -#include -#endif - -#include "alMain.h" -#include "alu.h" -#include "ringbuffer.h" -#include "threads.h" -#include "compat.h" -#include "alstring.h" - -#include "backends/base.h" - -#ifndef DSSPEAKER_5POINT1 -# define DSSPEAKER_5POINT1 0x00000006 -#endif -#ifndef DSSPEAKER_5POINT1_BACK -# define DSSPEAKER_5POINT1_BACK 0x00000006 -#endif -#ifndef DSSPEAKER_7POINT1 -# define DSSPEAKER_7POINT1 0x00000007 -#endif -#ifndef DSSPEAKER_7POINT1_SURROUND -# define DSSPEAKER_7POINT1_SURROUND 0x00000008 -#endif -#ifndef DSSPEAKER_5POINT1_SURROUND -# define DSSPEAKER_5POINT1_SURROUND 0x00000009 -#endif - - -DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); -DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define DEVNAME_HEAD "OpenAL Soft on " - - -#ifdef HAVE_DYNLOAD -static void *ds_handle; -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 DirectSoundEnumerateW pDirectSoundEnumerateW -#define DirectSoundCaptureCreate pDirectSoundCaptureCreate -#define DirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW -#endif - - -static ALCboolean DSoundLoad(void) -{ -#ifdef HAVE_DYNLOAD - if(!ds_handle) - { - ds_handle = LoadLib("dsound.dll"); - if(ds_handle == NULL) - { - ERR("Failed to load dsound.dll\n"); - return ALC_FALSE; - } - -#define LOAD_FUNC(f) do { \ - p##f = GetSymbol(ds_handle, #f); \ - if(p##f == NULL) { \ - CloseLib(ds_handle); \ - ds_handle = NULL; \ - return ALC_FALSE; \ - } \ -} while(0) - LOAD_FUNC(DirectSoundCreate); - LOAD_FUNC(DirectSoundEnumerateW); - LOAD_FUNC(DirectSoundCaptureCreate); - LOAD_FUNC(DirectSoundCaptureEnumerateW); -#undef LOAD_FUNC - } -#endif - return ALC_TRUE; -} - - -#define MAX_UPDATES 128 - -typedef struct { - al_string name; - GUID guid; -} DevMap; -TYPEDEF_VECTOR(DevMap, vector_DevMap) - -static vector_DevMap PlaybackDevices; -static vector_DevMap CaptureDevices; - -static void clear_devlist(vector_DevMap *list) -{ -#define DEINIT_STR(i) AL_STRING_DEINIT((i)->name) - VECTOR_FOR_EACH(DevMap, *list, DEINIT_STR); - VECTOR_RESIZE(*list, 0, 0); -#undef DEINIT_STR -} - -static BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR* UNUSED(drvname), void *data) -{ - vector_DevMap *devices = data; - OLECHAR *guidstr = NULL; - DevMap entry; - HRESULT hr; - int count; - - if(!guid) - return TRUE; - - AL_STRING_INIT(entry.name); - - count = 0; - while(1) - { - const DevMap *iter; - - alstr_copy_cstr(&entry.name, DEVNAME_HEAD); - alstr_append_wcstr(&entry.name, desc); - if(count != 0) - { - char str[64]; - snprintf(str, sizeof(str), " #%d", count+1); - alstr_append_cstr(&entry.name, str); - } - -#define MATCH_ENTRY(i) (alstr_cmp(entry.name, (i)->name) == 0) - VECTOR_FIND_IF(iter, const DevMap, *devices, MATCH_ENTRY); - if(iter == VECTOR_END(*devices)) break; -#undef MATCH_ENTRY - count++; - } - entry.guid = *guid; - - hr = StringFromCLSID(guid, &guidstr); - if(SUCCEEDED(hr)) - { - TRACE("Got device \"%s\", GUID \"%ls\"\n", alstr_get_cstr(entry.name), guidstr); - CoTaskMemFree(guidstr); - } - - VECTOR_PUSH_BACK(*devices, entry); - - return TRUE; -} - - -typedef struct ALCdsoundPlayback { - DERIVE_FROM_TYPE(ALCbackend); - - IDirectSound *DS; - IDirectSoundBuffer *PrimaryBuffer; - IDirectSoundBuffer *Buffer; - IDirectSoundNotify *Notifies; - HANDLE NotifyEvent; - - ATOMIC(ALenum) killNow; - althrd_t thread; -} ALCdsoundPlayback; - -static int ALCdsoundPlayback_mixerProc(void *ptr); - -static void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device); -static void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self); -static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *name); -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, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCdsoundPlayback) - -DEFINE_ALCBACKEND_VTABLE(ALCdsoundPlayback); - - -static void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCdsoundPlayback, ALCbackend, self); - - self->DS = NULL; - self->PrimaryBuffer = NULL; - self->Buffer = NULL; - self->Notifies = NULL; - self->NotifyEvent = NULL; - ATOMIC_INIT(&self->killNow, AL_TRUE); -} - -static void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self) -{ - 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; - - if(self->DS) - IDirectSound_Release(self->DS); - self->DS = NULL; - if(self->NotifyEvent) - CloseHandle(self->NotifyEvent); - self->NotifyEvent = NULL; - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr) -{ - ALCdsoundPlayback *self = ptr; - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - DSBCAPS DSBCaps; - DWORD LastCursor = 0; - DWORD PlayCursor; - void *WritePtr1, *WritePtr2; - DWORD WriteCnt1, WriteCnt2; - BOOL Playing = FALSE; - DWORD FrameSize; - DWORD FragSize; - DWORD avail; - HRESULT err; - - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - memset(&DSBCaps, 0, sizeof(DSBCaps)); - DSBCaps.dwSize = sizeof(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, "Failure retrieving playback buffer info: 0x%lx", err); - ALCdevice_Unlock(device); - return 1; - } - - FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - FragSize = device->UpdateSize * FrameSize; - - IDirectSoundBuffer_GetCurrentPosition(self->Buffer, &LastCursor, NULL); - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) - { - // Get current play cursor - IDirectSoundBuffer_GetCurrentPosition(self->Buffer, &PlayCursor, NULL); - avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes; - - if(avail < FragSize) - { - if(!Playing) - { - 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, "Failure starting playback: 0x%lx", err); - ALCdevice_Unlock(device); - return 1; - } - Playing = TRUE; - } - - avail = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE); - if(avail != WAIT_OBJECT_0) - ERR("WaitForSingleObjectEx error: 0x%lx\n", avail); - continue; - } - avail -= avail%FragSize; - - // Lock output buffer - WriteCnt1 = 0; - 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(self->Buffer); - if(SUCCEEDED(err)) - { - Playing = FALSE; - LastCursor = 0; - err = IDirectSoundBuffer_Lock(self->Buffer, 0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0); - } - } - - // Successfully locked the output buffer - if(SUCCEEDED(err)) - { - // If we have an active context, mix data directly into output buffer otherwise fill with silence - ALCdevice_Lock(device); - aluMixData(device, WritePtr1, WriteCnt1/FrameSize); - aluMixData(device, WritePtr2, WriteCnt2/FrameSize); - ALCdevice_Unlock(device); - - // Unlock output buffer only when successfully locked - IDirectSoundBuffer_Unlock(self->Buffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); - } - else - { - ERR("Buffer lock error: %#lx\n", err); - ALCdevice_Lock(device); - aluHandleDisconnect(device, "Failed to lock output buffer: 0x%lx", err); - ALCdevice_Unlock(device); - return 1; - } - - // Update old write cursor location - LastCursor += WriteCnt1+WriteCnt2; - LastCursor %= DSBCaps.dwBufferBytes; - } - - return 0; -} - -static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *deviceName) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - const GUID *guid = NULL; - HRESULT hr, hrcom; - - if(VECTOR_SIZE(PlaybackDevices) == 0) - { - /* Initialize COM to prevent name truncation */ - hrcom = CoInitialize(NULL); - hr = DirectSoundEnumerateW(DSoundEnumDevices, &PlaybackDevices); - if(FAILED(hr)) - ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr); - if(SUCCEEDED(hrcom)) - CoUninitialize(); - } - - if(!deviceName && VECTOR_SIZE(PlaybackDevices) > 0) - { - deviceName = alstr_get_cstr(VECTOR_FRONT(PlaybackDevices).name); - guid = &VECTOR_FRONT(PlaybackDevices).guid; - } - else - { - const DevMap *iter; - -#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, deviceName) == 0) - VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); -#undef MATCH_NAME - if(iter == VECTOR_END(PlaybackDevices)) - return ALC_INVALID_VALUE; - guid = &iter->guid; - } - - hr = DS_OK; - self->NotifyEvent = CreateEventW(NULL, FALSE, FALSE, NULL); - if(self->NotifyEvent == NULL) - hr = E_FAIL; - - //DirectSound Init code - if(SUCCEEDED(hr)) - hr = DirectSoundCreate(guid, &self->DS, NULL); - if(SUCCEEDED(hr)) - hr = IDirectSound_SetCooperativeLevel(self->DS, GetForegroundWindow(), DSSCL_PRIORITY); - if(FAILED(hr)) - { - 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; - } - - alstr_copy_cstr(&device->DeviceName, deviceName); - - return ALC_NO_ERROR; -} - -static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - DSBUFFERDESC DSBDescription; - WAVEFORMATEXTENSIBLE OutputType; - DWORD speakers; - HRESULT hr; - - memset(&OutputType, 0, sizeof(OutputType)); - - 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) - { - case DevFmtByte: - device->FmtType = DevFmtUByte; - break; - case DevFmtFloat: - if((device->Flags&DEVICE_SAMPLE_TYPE_REQUEST)) - break; - /* fall-through */ - case DevFmtUShort: - device->FmtType = DevFmtShort; - break; - case DevFmtUInt: - device->FmtType = DevFmtInt; - break; - case DevFmtUByte: - case DevFmtShort: - case DevFmtInt: - break; - } - - hr = IDirectSound_GetSpeakerConfig(self->DS, &speakers); - if(SUCCEEDED(hr)) - { - speakers = DSSPEAKER_CONFIG(speakers); - if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) - { - if(speakers == DSSPEAKER_MONO) - device->FmtChans = DevFmtMono; - else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE) - device->FmtChans = DevFmtStereo; - else if(speakers == DSSPEAKER_QUAD) - device->FmtChans = DevFmtQuad; - else if(speakers == DSSPEAKER_5POINT1_SURROUND) - device->FmtChans = DevFmtX51; - else if(speakers == DSSPEAKER_5POINT1_BACK) - device->FmtChans = DevFmtX51Rear; - else if(speakers == DSSPEAKER_7POINT1 || speakers == DSSPEAKER_7POINT1_SURROUND) - device->FmtChans = DevFmtX71; - else - ERR("Unknown system speaker config: 0x%lx\n", speakers); - } - device->IsHeadphones = (device->FmtChans == DevFmtStereo && - speakers == DSSPEAKER_HEADPHONE); - - switch(device->FmtChans) - { - case DevFmtMono: - OutputType.dwChannelMask = SPEAKER_FRONT_CENTER; - break; - case DevFmtAmbi3D: - device->FmtChans = DevFmtStereo; - /*fall-through*/ - case DevFmtStereo: - OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT; - break; - case DevFmtQuad: - OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_BACK_LEFT | - SPEAKER_BACK_RIGHT; - break; - case DevFmtX51: - OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_SIDE_LEFT | - SPEAKER_SIDE_RIGHT; - break; - case DevFmtX51Rear: - OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_BACK_LEFT | - SPEAKER_BACK_RIGHT; - break; - case DevFmtX61: - OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_BACK_CENTER | - SPEAKER_SIDE_LEFT | - SPEAKER_SIDE_RIGHT; - break; - case DevFmtX71: - OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_BACK_LEFT | - SPEAKER_BACK_RIGHT | - SPEAKER_SIDE_LEFT | - SPEAKER_SIDE_RIGHT; - break; - } - -retry_open: - hr = S_OK; - OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; - OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - OutputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; - OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8; - OutputType.Format.nSamplesPerSec = device->Frequency; - OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign; - OutputType.Format.cbSize = 0; - } - - if(OutputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat) - { - OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; - OutputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); - if(device->FmtType == DevFmtFloat) - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - else - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - - if(self->PrimaryBuffer) - IDirectSoundBuffer_Release(self->PrimaryBuffer); - self->PrimaryBuffer = NULL; - } - else - { - if(SUCCEEDED(hr) && !self->PrimaryBuffer) - { - memset(&DSBDescription,0,sizeof(DSBUFFERDESC)); - DSBDescription.dwSize=sizeof(DSBUFFERDESC); - DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER; - hr = IDirectSound_CreateSoundBuffer(self->DS, &DSBDescription, &self->PrimaryBuffer, NULL); - } - if(SUCCEEDED(hr)) - hr = IDirectSoundBuffer_SetFormat(self->PrimaryBuffer,&OutputType.Format); - } - - if(SUCCEEDED(hr)) - { - if(device->NumUpdates > MAX_UPDATES) - { - device->UpdateSize = (device->UpdateSize*device->NumUpdates + - MAX_UPDATES-1) / MAX_UPDATES; - device->NumUpdates = MAX_UPDATES; - } - - memset(&DSBDescription,0,sizeof(DSBUFFERDESC)); - DSBDescription.dwSize=sizeof(DSBUFFERDESC); - DSBDescription.dwFlags=DSBCAPS_CTRLPOSITIONNOTIFY|DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_GLOBALFOCUS; - DSBDescription.dwBufferBytes=device->UpdateSize * device->NumUpdates * - OutputType.Format.nBlockAlign; - DSBDescription.lpwfxFormat=&OutputType.Format; - hr = IDirectSound_CreateSoundBuffer(self->DS, &DSBDescription, &self->Buffer, NULL); - if(FAILED(hr) && device->FmtType == DevFmtFloat) - { - device->FmtType = DevFmtShort; - goto retry_open; - } - } - - if(SUCCEEDED(hr)) - { - hr = IDirectSoundBuffer_QueryInterface(self->Buffer, &IID_IDirectSoundNotify, (void**)&self->Notifies); - if(SUCCEEDED(hr)) - { - DSBPOSITIONNOTIFY notifies[MAX_UPDATES]; - ALuint i; - - for(i = 0;i < device->NumUpdates;++i) - { - notifies[i].dwOffset = i * device->UpdateSize * - OutputType.Format.nBlockAlign; - notifies[i].hEventNotify = self->NotifyEvent; - } - if(IDirectSoundNotify_SetNotificationPositions(self->Notifies, device->NumUpdates, notifies) != DS_OK) - hr = E_FAIL; - } - } - - if(FAILED(hr)) - { - 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(self->NotifyEvent); - SetDefaultWFXChannelOrder(device); - - return ALC_TRUE; -} - -static ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self) -{ - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); - if(althrd_create(&self->thread, ALCdsoundPlayback_mixerProc, self) != althrd_success) - return ALC_FALSE; - - return ALC_TRUE; -} - -static void ALCdsoundPlayback_stop(ALCdsoundPlayback *self) -{ - int res; - - if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) - return; - althrd_join(self->thread, &res); - - IDirectSoundBuffer_Stop(self->Buffer); -} - - - -typedef struct ALCdsoundCapture { - DERIVE_FROM_TYPE(ALCbackend); - - IDirectSoundCapture *DSC; - IDirectSoundCaptureBuffer *DSCbuffer; - DWORD BufferBytes; - DWORD Cursor; - - ll_ringbuffer_t *Ring; -} ALCdsoundCapture; - -static void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device); -static void ALCdsoundCapture_Destruct(ALCdsoundCapture *self); -static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *name); -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, ClockLatency, getClockLatency) -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); - - self->DSC = NULL; - self->DSCbuffer = NULL; - self->Ring = NULL; -} - -static void ALCdsoundCapture_Destruct(ALCdsoundCapture *self) -{ - ll_ringbuffer_free(self->Ring); - self->Ring = NULL; - - if(self->DSCbuffer != NULL) - { - IDirectSoundCaptureBuffer_Stop(self->DSCbuffer); - IDirectSoundCaptureBuffer_Release(self->DSCbuffer); - self->DSCbuffer = NULL; - } - - if(self->DSC) - IDirectSoundCapture_Release(self->DSC); - self->DSC = NULL; - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - WAVEFORMATEXTENSIBLE InputType; - DSCBUFFERDESC DSCBDescription; - const GUID *guid = NULL; - HRESULT hr, hrcom; - ALuint samples; - - if(VECTOR_SIZE(CaptureDevices) == 0) - { - /* Initialize COM to prevent name truncation */ - hrcom = CoInitialize(NULL); - hr = DirectSoundCaptureEnumerateW(DSoundEnumDevices, &CaptureDevices); - if(FAILED(hr)) - ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr); - if(SUCCEEDED(hrcom)) - CoUninitialize(); - } - - if(!deviceName && VECTOR_SIZE(CaptureDevices) > 0) - { - deviceName = alstr_get_cstr(VECTOR_FRONT(CaptureDevices).name); - guid = &VECTOR_FRONT(CaptureDevices).guid; - } - else - { - const DevMap *iter; - -#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, deviceName) == 0) - VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); -#undef MATCH_NAME - if(iter == VECTOR_END(CaptureDevices)) - return ALC_INVALID_VALUE; - guid = &iter->guid; - } - - switch(device->FmtType) - { - case DevFmtByte: - case DevFmtUShort: - case DevFmtUInt: - WARN("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); - return ALC_INVALID_ENUM; - - case DevFmtUByte: - case DevFmtShort: - case DevFmtInt: - case DevFmtFloat: - break; - } - - memset(&InputType, 0, sizeof(InputType)); - switch(device->FmtChans) - { - case DevFmtMono: - InputType.dwChannelMask = SPEAKER_FRONT_CENTER; - break; - case DevFmtStereo: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT; - break; - case DevFmtQuad: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_BACK_LEFT | - SPEAKER_BACK_RIGHT; - break; - case DevFmtX51: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_SIDE_LEFT | - SPEAKER_SIDE_RIGHT; - break; - case DevFmtX51Rear: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_BACK_LEFT | - SPEAKER_BACK_RIGHT; - break; - case DevFmtX61: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_BACK_CENTER | - SPEAKER_SIDE_LEFT | - SPEAKER_SIDE_RIGHT; - break; - case DevFmtX71: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_BACK_LEFT | - SPEAKER_BACK_RIGHT | - SPEAKER_SIDE_LEFT | - SPEAKER_SIDE_RIGHT; - break; - case DevFmtAmbi3D: - WARN("%s capture not supported\n", DevFmtChannelsString(device->FmtChans)); - return ALC_INVALID_ENUM; - } - - InputType.Format.wFormatTag = WAVE_FORMAT_PCM; - InputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - InputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; - InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8; - InputType.Format.nSamplesPerSec = device->Frequency; - InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign; - InputType.Format.cbSize = 0; - InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample; - if(device->FmtType == DevFmtFloat) - InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - else - InputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - - if(InputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat) - { - InputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); - } - - samples = device->UpdateSize * device->NumUpdates; - samples = maxu(samples, 100 * device->Frequency / 1000); - - memset(&DSCBDescription, 0, sizeof(DSCBUFFERDESC)); - DSCBDescription.dwSize = sizeof(DSCBUFFERDESC); - DSCBDescription.dwFlags = 0; - DSCBDescription.dwBufferBytes = samples * InputType.Format.nBlockAlign; - DSCBDescription.lpwfxFormat = &InputType.Format; - - //DirectSoundCapture Init code - hr = DirectSoundCaptureCreate(guid, &self->DSC, NULL); - if(SUCCEEDED(hr)) - hr = IDirectSoundCapture_CreateCaptureBuffer(self->DSC, &DSCBDescription, &self->DSCbuffer, NULL); - if(SUCCEEDED(hr)) - { - self->Ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, - InputType.Format.nBlockAlign, false); - if(self->Ring == NULL) - hr = DSERR_OUTOFMEMORY; - } - - if(FAILED(hr)) - { - ERR("Device init failed: 0x%08lx\n", hr); - - ll_ringbuffer_free(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; - - return ALC_INVALID_VALUE; - } - - self->BufferBytes = DSCBDescription.dwBufferBytes; - SetDefaultWFXChannelOrder(device); - - alstr_copy_cstr(&device->DeviceName, deviceName); - - return ALC_NO_ERROR; -} - -static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self) -{ - HRESULT hr; - - hr = IDirectSoundCaptureBuffer_Start(self->DSCbuffer, DSCBSTART_LOOPING); - if(FAILED(hr)) - { - ERR("start failed: 0x%08lx\n", hr); - aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, - "Failure starting capture: 0x%lx", hr); - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static void ALCdsoundCapture_stop(ALCdsoundCapture *self) -{ - HRESULT hr; - - hr = IDirectSoundCaptureBuffer_Stop(self->DSCbuffer); - if(FAILED(hr)) - { - ERR("stop failed: 0x%08lx\n", hr); - aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, - "Failure stopping capture: 0x%lx", hr); - } -} - -static ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint samples) -{ - ll_ringbuffer_read(self->Ring, buffer, samples); - return ALC_NO_ERROR; -} - -static ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - DWORD ReadCursor, LastCursor, BufferBytes, NumBytes; - void *ReadPtr1, *ReadPtr2; - DWORD ReadCnt1, ReadCnt2; - DWORD FrameSize; - HRESULT hr; - - if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) - goto done; - - FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - BufferBytes = self->BufferBytes; - LastCursor = self->Cursor; - - hr = IDirectSoundCaptureBuffer_GetCurrentPosition(self->DSCbuffer, NULL, &ReadCursor); - if(SUCCEEDED(hr)) - { - NumBytes = (ReadCursor-LastCursor + BufferBytes) % BufferBytes; - if(NumBytes == 0) - goto done; - hr = IDirectSoundCaptureBuffer_Lock(self->DSCbuffer, LastCursor, NumBytes, - &ReadPtr1, &ReadCnt1, - &ReadPtr2, &ReadCnt2, 0); - } - if(SUCCEEDED(hr)) - { - ll_ringbuffer_write(self->Ring, ReadPtr1, ReadCnt1/FrameSize); - if(ReadPtr2 != NULL) - ll_ringbuffer_write(self->Ring, ReadPtr2, ReadCnt2/FrameSize); - hr = IDirectSoundCaptureBuffer_Unlock(self->DSCbuffer, - ReadPtr1, ReadCnt1, - ReadPtr2, ReadCnt2); - self->Cursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes; - } - - if(FAILED(hr)) - { - ERR("update failed: 0x%08lx\n", hr); - aluHandleDisconnect(device, "Failure retrieving capture data: 0x%lx", hr); - } - -done: - return (ALCuint)ll_ringbuffer_read_space(self->Ring); -} - - -typedef struct ALCdsoundBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCdsoundBackendFactory; -#define ALCDSOUNDBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCdsoundBackendFactory, ALCbackendFactory) } } - -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, al_string *outnames); -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; - return ALC_TRUE; -} - -static void ALCdsoundBackendFactory_deinit(ALCdsoundBackendFactory* UNUSED(self)) -{ - clear_devlist(&PlaybackDevices); - VECTOR_DEINIT(PlaybackDevices); - - clear_devlist(&CaptureDevices); - VECTOR_DEINIT(CaptureDevices); - -#ifdef HAVE_DYNLOAD - if(ds_handle) - CloseLib(ds_handle); - ds_handle = NULL; -#endif -} - -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, al_string *outnames) -{ - HRESULT hr, hrcom; - - /* Initialize COM to prevent name truncation */ - hrcom = CoInitialize(NULL); - switch(type) - { -#define APPEND_OUTNAME(e) do { \ - if(!alstr_empty((e)->name)) \ - alstr_append_range(outnames, VECTOR_BEGIN((e)->name), \ - VECTOR_END((e)->name)+1); \ -} while(0) - case ALL_DEVICE_PROBE: - clear_devlist(&PlaybackDevices); - hr = DirectSoundEnumerateW(DSoundEnumDevices, &PlaybackDevices); - if(FAILED(hr)) - ERR("Error enumerating DirectSound playback devices (0x%lx)!\n", hr); - VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_OUTNAME); - break; - - case CAPTURE_DEVICE_PROBE: - clear_devlist(&CaptureDevices); - hr = DirectSoundCaptureEnumerateW(DSoundEnumDevices, &CaptureDevices); - if(FAILED(hr)) - ERR("Error enumerating DirectSound capture devices (0x%lx)!\n", hr); - VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_OUTNAME); - break; -#undef APPEND_OUTNAME - } - if(SUCCEEDED(hrcom)) - CoUninitialize(); -} - -static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - { - ALCdsoundPlayback *backend; - NEW_OBJ(backend, ALCdsoundPlayback)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - if(type == ALCbackend_Capture) - { - ALCdsoundCapture *backend; - NEW_OBJ(backend, ALCdsoundCapture)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp new file mode 100644 index 00000000..4edad4e4 --- /dev/null +++ b/Alc/backends/dsound.cpp @@ -0,0 +1,1051 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#ifndef _WAVEFORMATEXTENSIBLE_ +#include +#include +#endif + +#include +#include +#include +#include +#include + +#include "alMain.h" +#include "alu.h" +#include "ringbuffer.h" +#include "compat.h" + +#include "backends/base.h" + +#ifndef DSSPEAKER_5POINT1 +# define DSSPEAKER_5POINT1 0x00000006 +#endif +#ifndef DSSPEAKER_5POINT1_BACK +# define DSSPEAKER_5POINT1_BACK 0x00000006 +#endif +#ifndef DSSPEAKER_7POINT1 +# define DSSPEAKER_7POINT1 0x00000007 +#endif +#ifndef DSSPEAKER_7POINT1_SURROUND +# define DSSPEAKER_7POINT1_SURROUND 0x00000008 +#endif +#ifndef DSSPEAKER_5POINT1_SURROUND +# define DSSPEAKER_5POINT1_SURROUND 0x00000009 +#endif + + +/* Some headers seem to define these as macros for __uuidof, which is annoying + * since some headers don't declare them at all. Hopefully the ifdef is enough + * to tell if they need to be declared. + */ +#ifndef KSDATAFORMAT_SUBTYPE_PCM +DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +#endif +#ifndef KSDATAFORMAT_SUBTYPE_IEEE_FLOAT +DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +#endif + +namespace { + +#define DEVNAME_HEAD "OpenAL Soft on " + + +#ifdef HAVE_DYNLOAD +static void *ds_handle; +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 DirectSoundEnumerateW pDirectSoundEnumerateW +#define DirectSoundCaptureCreate pDirectSoundCaptureCreate +#define DirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW +#endif + + +static ALCboolean DSoundLoad(void) +{ +#ifdef HAVE_DYNLOAD + if(!ds_handle) + { + ds_handle = LoadLib("dsound.dll"); + if(!ds_handle) + { + ERR("Failed to load dsound.dll\n"); + return ALC_FALSE; + } + +#define LOAD_FUNC(f) do { \ + p##f = reinterpret_cast(GetSymbol(ds_handle, #f)); \ + if(!p##f) \ + { \ + CloseLib(ds_handle); \ + ds_handle = nullptr; \ + return ALC_FALSE; \ + } \ +} while(0) + LOAD_FUNC(DirectSoundCreate); + LOAD_FUNC(DirectSoundEnumerateW); + LOAD_FUNC(DirectSoundCaptureCreate); + LOAD_FUNC(DirectSoundCaptureEnumerateW); +#undef LOAD_FUNC + } +#endif + return ALC_TRUE; +} + + +#define MAX_UPDATES 128 + +struct DevMap { + std::string name; + GUID guid; + + template + DevMap(T0&& name_, T1&& guid_) + : name{std::forward(name_)}, guid{std::forward(guid_)} + { } +}; + +std::vector PlaybackDevices; +std::vector CaptureDevices; + +bool checkName(const std::vector &list, const std::string &name) +{ + return std::find_if(list.cbegin(), list.cend(), + [&name](const DevMap &entry) -> bool + { return entry.name == name; } + ) != list.cend(); +} + +BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR* UNUSED(drvname), void *data) +{ + if(!guid) + return TRUE; + + auto& devices = *reinterpret_cast*>(data); + const std::string basename{DEVNAME_HEAD + wstr_to_utf8(desc)}; + + int count{1}; + std::string newname{basename}; + while(checkName(devices, newname)) + { + newname = basename; + newname += " #"; + newname += std::to_string(++count); + } + devices.emplace_back(std::move(newname), *guid); + const DevMap &newentry = devices.back(); + + OLECHAR *guidstr{nullptr}; + HRESULT hr{StringFromCLSID(*guid, &guidstr)}; + if(SUCCEEDED(hr)) + { + TRACE("Got device \"%s\", GUID \"%ls\"\n", newentry.name.c_str(), guidstr); + CoTaskMemFree(guidstr); + } + + return TRUE; +} + +} // namespace + + +struct ALCdsoundPlayback final : public ALCbackend { + IDirectSound *DS{nullptr}; + IDirectSoundBuffer *PrimaryBuffer{nullptr}; + IDirectSoundBuffer *Buffer{nullptr}; + IDirectSoundNotify *Notifies{nullptr}; + HANDLE NotifyEvent{nullptr}; + + std::atomic killNow{AL_TRUE}; + std::thread thread; +}; + +static int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self); + +static void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device); +static void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self); +static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *name); +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, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCdsoundPlayback) + +DEFINE_ALCBACKEND_VTABLE(ALCdsoundPlayback); + + +static void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device) +{ + new (self) ALCdsoundPlayback{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCdsoundPlayback, ALCbackend, self); +} + +static void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self) +{ + if(self->Notifies) + self->Notifies->Release(); + self->Notifies = nullptr; + if(self->Buffer) + self->Buffer->Release(); + self->Buffer = nullptr; + if(self->PrimaryBuffer) + self->PrimaryBuffer->Release(); + self->PrimaryBuffer = nullptr; + + if(self->DS) + self->DS->Release(); + self->DS = nullptr; + if(self->NotifyEvent) + CloseHandle(self->NotifyEvent); + self->NotifyEvent = nullptr; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCdsoundPlayback(); +} + + +FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + + SetRTPriority(); + althrd_setname(althrd_current(), MIXER_THREAD_NAME); + + IDirectSoundBuffer *const Buffer{self->Buffer}; + + DSBCAPS DSBCaps{}; + DSBCaps.dwSize = sizeof(DSBCaps); + HRESULT err{Buffer->GetCaps(&DSBCaps)}; + if(FAILED(err)) + { + ERR("Failed to get buffer caps: 0x%lx\n", err); + ALCdevice_Lock(device); + aluHandleDisconnect(device, "Failure retrieving playback buffer info: 0x%lx", err); + ALCdevice_Unlock(device); + return 1; + } + + ALsizei FrameSize{FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder)}; + DWORD FragSize{device->UpdateSize * FrameSize}; + + bool Playing{false}; + DWORD LastCursor{0u}; + Buffer->GetCurrentPosition(&LastCursor, nullptr); + while(!self->killNow.load(almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + { + // Get current play cursor + DWORD PlayCursor; + Buffer->GetCurrentPosition(&PlayCursor, nullptr); + DWORD avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes; + + if(avail < FragSize) + { + if(!Playing) + { + err = Buffer->Play(0, 0, DSBPLAY_LOOPING); + if(FAILED(err)) + { + ERR("Failed to play buffer: 0x%lx\n", err); + ALCdevice_Lock(device); + aluHandleDisconnect(device, "Failure starting playback: 0x%lx", err); + ALCdevice_Unlock(device); + return 1; + } + Playing = true; + } + + avail = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE); + if(avail != WAIT_OBJECT_0) + ERR("WaitForSingleObjectEx error: 0x%lx\n", avail); + continue; + } + avail -= avail%FragSize; + + // Lock output buffer + void *WritePtr1, *WritePtr2; + DWORD WriteCnt1{0u}, WriteCnt2{0u}; + err = Buffer->Lock(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 = Buffer->Restore(); + if(SUCCEEDED(err)) + { + Playing = false; + LastCursor = 0; + err = Buffer->Lock(0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, + &WritePtr2, &WriteCnt2, 0); + } + } + + // Successfully locked the output buffer + if(SUCCEEDED(err)) + { + // If we have an active context, mix data directly into output buffer otherwise fill with silence + ALCdevice_Lock(device); + aluMixData(device, WritePtr1, WriteCnt1/FrameSize); + aluMixData(device, WritePtr2, WriteCnt2/FrameSize); + ALCdevice_Unlock(device); + + // Unlock output buffer only when successfully locked + Buffer->Unlock(WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); + } + else + { + ERR("Buffer lock error: %#lx\n", err); + ALCdevice_Lock(device); + aluHandleDisconnect(device, "Failed to lock output buffer: 0x%lx", err); + ALCdevice_Unlock(device); + return 1; + } + + // Update old write cursor location + LastCursor += WriteCnt1+WriteCnt2; + LastCursor %= DSBCaps.dwBufferBytes; + } + + return 0; +} + +static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *deviceName) +{ + ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + + HRESULT hr; + if(PlaybackDevices.empty()) + { + /* Initialize COM to prevent name truncation */ + HRESULT hrcom{CoInitialize(nullptr)}; + hr = DirectSoundEnumerateW(DSoundEnumDevices, &PlaybackDevices); + if(FAILED(hr)) + ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr); + if(SUCCEEDED(hrcom)) + CoUninitialize(); + } + + const GUID *guid{nullptr}; + if(!deviceName && !PlaybackDevices.empty()) + { + deviceName = PlaybackDevices[0].name.c_str(); + guid = &PlaybackDevices[0].guid; + } + else + { + auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + [deviceName](const DevMap &entry) -> bool + { return entry.name == deviceName; } + ); + if(iter == PlaybackDevices.cend()) + return ALC_INVALID_VALUE; + guid = &iter->guid; + } + + hr = DS_OK; + self->NotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + if(!self->NotifyEvent) hr = E_FAIL; + + //DirectSound Init code + if(SUCCEEDED(hr)) + hr = DirectSoundCreate(guid, &self->DS, nullptr); + if(SUCCEEDED(hr)) + hr = self->DS->SetCooperativeLevel(GetForegroundWindow(), DSSCL_PRIORITY); + if(FAILED(hr)) + { + ERR("Device init failed: 0x%08lx\n", hr); + return ALC_INVALID_VALUE; + } + + alstr_copy_cstr(&device->DeviceName, deviceName); + + return ALC_NO_ERROR; +} + +static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + + if(self->Notifies) + self->Notifies->Release(); + self->Notifies = nullptr; + if(self->Buffer) + self->Buffer->Release(); + self->Buffer = nullptr; + if(self->PrimaryBuffer) + self->PrimaryBuffer->Release(); + self->PrimaryBuffer = nullptr; + + switch(device->FmtType) + { + case DevFmtByte: + device->FmtType = DevFmtUByte; + break; + case DevFmtFloat: + if((device->Flags&DEVICE_SAMPLE_TYPE_REQUEST)) + break; + /* fall-through */ + case DevFmtUShort: + device->FmtType = DevFmtShort; + break; + case DevFmtUInt: + device->FmtType = DevFmtInt; + break; + case DevFmtUByte: + case DevFmtShort: + case DevFmtInt: + break; + } + + WAVEFORMATEXTENSIBLE OutputType{}; + DWORD speakers; + HRESULT hr{self->DS->GetSpeakerConfig(&speakers)}; + if(SUCCEEDED(hr)) + { + speakers = DSSPEAKER_CONFIG(speakers); + if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) + { + if(speakers == DSSPEAKER_MONO) + device->FmtChans = DevFmtMono; + else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE) + device->FmtChans = DevFmtStereo; + else if(speakers == DSSPEAKER_QUAD) + device->FmtChans = DevFmtQuad; + else if(speakers == DSSPEAKER_5POINT1_SURROUND) + device->FmtChans = DevFmtX51; + else if(speakers == DSSPEAKER_5POINT1_BACK) + device->FmtChans = DevFmtX51Rear; + else if(speakers == DSSPEAKER_7POINT1 || speakers == DSSPEAKER_7POINT1_SURROUND) + device->FmtChans = DevFmtX71; + else + ERR("Unknown system speaker config: 0x%lx\n", speakers); + } + device->IsHeadphones = (device->FmtChans == DevFmtStereo && + speakers == DSSPEAKER_HEADPHONE); + + switch(device->FmtChans) + { + case DevFmtMono: + OutputType.dwChannelMask = SPEAKER_FRONT_CENTER; + break; + case DevFmtAmbi3D: + device->FmtChans = DevFmtStereo; + /*fall-through*/ + case DevFmtStereo: + OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT; + break; + case DevFmtQuad: + OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT; + break; + case DevFmtX51: + OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + break; + case DevFmtX51Rear: + OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT; + break; + case DevFmtX61: + OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_CENTER | + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + break; + case DevFmtX71: + OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT | + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + break; + } + +retry_open: + hr = S_OK; + OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; + OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + OutputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8; + OutputType.Format.nSamplesPerSec = device->Frequency; + OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign; + OutputType.Format.cbSize = 0; + } + + if(OutputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat) + { + OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; + OutputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); + if(device->FmtType == DevFmtFloat) + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + else + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + + if(self->PrimaryBuffer) + self->PrimaryBuffer->Release(); + self->PrimaryBuffer = nullptr; + } + else + { + if(SUCCEEDED(hr) && !self->PrimaryBuffer) + { + DSBUFFERDESC DSBDescription{}; + DSBDescription.dwSize = sizeof(DSBDescription); + DSBDescription.dwFlags = DSBCAPS_PRIMARYBUFFER; + hr = self->DS->CreateSoundBuffer(&DSBDescription, &self->PrimaryBuffer, nullptr); + } + if(SUCCEEDED(hr)) + hr = self->PrimaryBuffer->SetFormat(&OutputType.Format); + } + + if(SUCCEEDED(hr)) + { + if(device->NumUpdates > MAX_UPDATES) + { + device->UpdateSize = (device->UpdateSize*device->NumUpdates + + MAX_UPDATES-1) / MAX_UPDATES; + device->NumUpdates = MAX_UPDATES; + } + + DSBUFFERDESC DSBDescription{}; + DSBDescription.dwSize = sizeof(DSBDescription); + DSBDescription.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2 | + DSBCAPS_GLOBALFOCUS; + DSBDescription.dwBufferBytes = device->UpdateSize * device->NumUpdates * + OutputType.Format.nBlockAlign; + DSBDescription.lpwfxFormat = &OutputType.Format; + + hr = self->DS->CreateSoundBuffer(&DSBDescription, &self->Buffer, nullptr); + if(FAILED(hr) && device->FmtType == DevFmtFloat) + { + device->FmtType = DevFmtShort; + goto retry_open; + } + } + + if(SUCCEEDED(hr)) + { + void *ptr; + hr = self->Buffer->QueryInterface(IID_IDirectSoundNotify, &ptr); + if(SUCCEEDED(hr)) + { + auto Notifies = reinterpret_cast(ptr); + self->Notifies = Notifies; + + device->NumUpdates = minu(device->NumUpdates, MAX_UPDATES); + + std::array nots; + for(ALuint i{0};i < device->NumUpdates;++i) + { + nots[i].dwOffset = i * device->UpdateSize * OutputType.Format.nBlockAlign; + nots[i].hEventNotify = self->NotifyEvent; + } + if(Notifies->SetNotificationPositions(device->NumUpdates, nots.data()) != DS_OK) + hr = E_FAIL; + } + } + + if(FAILED(hr)) + { + if(self->Notifies) + self->Notifies->Release(); + self->Notifies = nullptr; + if(self->Buffer) + self->Buffer->Release(); + self->Buffer = nullptr; + if(self->PrimaryBuffer) + self->PrimaryBuffer->Release(); + self->PrimaryBuffer = nullptr; + return ALC_FALSE; + } + + ResetEvent(self->NotifyEvent); + SetDefaultWFXChannelOrder(device); + + return ALC_TRUE; +} + +static ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self) +{ + try { + self->killNow.store(AL_FALSE, almemory_order_release); + self->thread = std::thread(ALCdsoundPlayback_mixerProc, self); + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Failed to start mixing thread: %s\n", e.what()); + } + catch(...) { + } + return ALC_FALSE; +} + +static void ALCdsoundPlayback_stop(ALCdsoundPlayback *self) +{ + if(self->killNow.exchange(AL_TRUE, almemory_order_acq_rel) || !self->thread.joinable()) + return; + + self->thread.join(); + + self->Buffer->Stop(); +} + + +struct ALCdsoundCapture final : public ALCbackend { + IDirectSoundCapture *DSC{nullptr}; + IDirectSoundCaptureBuffer *DSCbuffer{nullptr}; + DWORD BufferBytes{0u}; + DWORD Cursor{0u}; + + ll_ringbuffer_t *Ring{nullptr}; +}; + +static void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device); +static void ALCdsoundCapture_Destruct(ALCdsoundCapture *self); +static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *name); +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, ClockLatency, getClockLatency) +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) +{ + new (self) ALCdsoundCapture{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCdsoundCapture, ALCbackend, self); +} + +static void ALCdsoundCapture_Destruct(ALCdsoundCapture *self) +{ + ll_ringbuffer_free(self->Ring); + self->Ring = nullptr; + + if(self->DSCbuffer) + { + self->DSCbuffer->Stop(); + self->DSCbuffer->Release(); + self->DSCbuffer = nullptr; + } + + if(self->DSC) + self->DSC->Release(); + self->DSC = nullptr; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCdsoundCapture(); +} + + +static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + + HRESULT hr; + if(CaptureDevices.empty()) + { + /* Initialize COM to prevent name truncation */ + HRESULT hrcom{CoInitialize(nullptr)}; + hr = DirectSoundCaptureEnumerateW(DSoundEnumDevices, &CaptureDevices); + if(FAILED(hr)) + ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr); + if(SUCCEEDED(hrcom)) + CoUninitialize(); + } + + const GUID *guid{nullptr}; + if(!deviceName && !CaptureDevices.empty()) + { + deviceName = CaptureDevices[0].name.c_str(); + guid = &CaptureDevices[0].guid; + } + else + { + auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), + [deviceName](const DevMap &entry) -> bool + { return entry.name == deviceName; } + ); + if(iter == CaptureDevices.cend()) + return ALC_INVALID_VALUE; + guid = &iter->guid; + } + + switch(device->FmtType) + { + case DevFmtByte: + case DevFmtUShort: + case DevFmtUInt: + WARN("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); + return ALC_INVALID_ENUM; + + case DevFmtUByte: + case DevFmtShort: + case DevFmtInt: + case DevFmtFloat: + break; + } + + WAVEFORMATEXTENSIBLE InputType{}; + switch(device->FmtChans) + { + case DevFmtMono: + InputType.dwChannelMask = SPEAKER_FRONT_CENTER; + break; + case DevFmtStereo: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT; + break; + case DevFmtQuad: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT; + break; + case DevFmtX51: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + break; + case DevFmtX51Rear: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT; + break; + case DevFmtX61: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_CENTER | + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + break; + case DevFmtX71: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT | + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + break; + case DevFmtAmbi3D: + WARN("%s capture not supported\n", DevFmtChannelsString(device->FmtChans)); + return ALC_INVALID_ENUM; + } + + InputType.Format.wFormatTag = WAVE_FORMAT_PCM; + InputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + InputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8; + InputType.Format.nSamplesPerSec = device->Frequency; + InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign; + InputType.Format.cbSize = 0; + InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample; + if(device->FmtType == DevFmtFloat) + InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + else + InputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + + if(InputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat) + { + InputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); + } + + ALuint samples{device->UpdateSize * device->NumUpdates}; + samples = maxu(samples, 100 * device->Frequency / 1000); + + DSCBUFFERDESC DSCBDescription{}; + DSCBDescription.dwSize = sizeof(DSCBDescription); + DSCBDescription.dwFlags = 0; + DSCBDescription.dwBufferBytes = samples * InputType.Format.nBlockAlign; + DSCBDescription.lpwfxFormat = &InputType.Format; + + //DirectSoundCapture Init code + hr = DirectSoundCaptureCreate(guid, &self->DSC, nullptr); + if(SUCCEEDED(hr)) + self->DSC->CreateCaptureBuffer(&DSCBDescription, &self->DSCbuffer, nullptr); + if(SUCCEEDED(hr)) + { + self->Ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, + InputType.Format.nBlockAlign, false); + if(!self->Ring) hr = DSERR_OUTOFMEMORY; + } + + if(FAILED(hr)) + { + ERR("Device init failed: 0x%08lx\n", hr); + + ll_ringbuffer_free(self->Ring); + self->Ring = nullptr; + if(self->DSCbuffer) + self->DSCbuffer->Release(); + self->DSCbuffer = nullptr; + if(self->DSC) + self->DSC->Release(); + self->DSC = nullptr; + + return ALC_INVALID_VALUE; + } + + self->BufferBytes = DSCBDescription.dwBufferBytes; + SetDefaultWFXChannelOrder(device); + + alstr_copy_cstr(&device->DeviceName, deviceName); + + return ALC_NO_ERROR; +} + +static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self) +{ + HRESULT hr{self->DSCbuffer->Start(DSCBSTART_LOOPING)}; + if(FAILED(hr)) + { + ERR("start failed: 0x%08lx\n", hr); + aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, + "Failure starting capture: 0x%lx", hr); + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static void ALCdsoundCapture_stop(ALCdsoundCapture *self) +{ + HRESULT hr{self->DSCbuffer->Stop()}; + if(FAILED(hr)) + { + ERR("stop failed: 0x%08lx\n", hr); + aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, + "Failure stopping capture: 0x%lx", hr); + } +} + +static ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint samples) +{ + ll_ringbuffer_read(self->Ring, reinterpret_cast(buffer), samples); + return ALC_NO_ERROR; +} + +static ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + + if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + return ll_ringbuffer_read_space(self->Ring); + + ALsizei FrameSize{FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder)}; + DWORD BufferBytes{self->BufferBytes}; + DWORD LastCursor{self->Cursor}; + + DWORD ReadCursor; + void *ReadPtr1, *ReadPtr2; + DWORD ReadCnt1, ReadCnt2; + HRESULT hr{self->DSCbuffer->GetCurrentPosition(nullptr, &ReadCursor)}; + if(SUCCEEDED(hr)) + { + DWORD NumBytes{(ReadCursor-LastCursor + BufferBytes) % BufferBytes}; + if(!NumBytes) return ll_ringbuffer_read_space(self->Ring); + hr = self->DSCbuffer->Lock(LastCursor, NumBytes, &ReadPtr1, &ReadCnt1, + &ReadPtr2, &ReadCnt2, 0); + } + if(SUCCEEDED(hr)) + { + ll_ringbuffer_write(self->Ring, reinterpret_cast(ReadPtr1), + ReadCnt1/FrameSize); + if(ReadPtr2 != nullptr) + ll_ringbuffer_write(self->Ring, reinterpret_cast(ReadPtr2), + ReadCnt2/FrameSize); + hr = self->DSCbuffer->Unlock(ReadPtr1, ReadCnt1, ReadPtr2, ReadCnt2); + self->Cursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes; + } + + if(FAILED(hr)) + { + ERR("update failed: 0x%08lx\n", hr); + aluHandleDisconnect(device, "Failure retrieving capture data: 0x%lx", hr); + } + + return ll_ringbuffer_read_space(self->Ring); +} + + +struct ALCdsoundBackendFactory final : public ALCbackendFactory { + ALCdsoundBackendFactory() noexcept; +}; +#define ALCDSOUNDBACKENDFACTORY_INITIALIZER GET_VTABLE2(ALCdsoundBackendFactory, ALCbackendFactory) + +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, al_string *outnames); +static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory *self, ALCdevice *device, ALCbackend_Type type); +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCdsoundBackendFactory); + + +ALCdsoundBackendFactory::ALCdsoundBackendFactory() noexcept + : ALCbackendFactory{ALCDSOUNDBACKENDFACTORY_INITIALIZER} +{ } + + +ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void) +{ + static ALCdsoundBackendFactory factory{}; + return STATIC_CAST(ALCbackendFactory, &factory); +} + + +static ALCboolean ALCdsoundBackendFactory_init(ALCdsoundBackendFactory* UNUSED(self)) +{ + if(!DSoundLoad()) + return ALC_FALSE; + return ALC_TRUE; +} + +static void ALCdsoundBackendFactory_deinit(ALCdsoundBackendFactory* UNUSED(self)) +{ + PlaybackDevices.clear(); + CaptureDevices.clear(); + +#ifdef HAVE_DYNLOAD + if(ds_handle) + CloseLib(ds_handle); + ds_handle = nullptr; +#endif +} + +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, al_string *outnames) +{ + auto add_device = [outnames](const DevMap &entry) -> void + { + const char *name{entry.name.c_str()}; + size_t namelen{entry.name.length()}; + /* +1 to also append the null char (to ensure a null-separated list and + * double-null terminated list). + */ + alstr_append_range(outnames, name, name + namelen+1); + }; + + /* Initialize COM to prevent name truncation */ + HRESULT hr; + HRESULT hrcom{CoInitialize(nullptr)}; + switch(type) + { + case ALL_DEVICE_PROBE: + PlaybackDevices.clear(); + hr = DirectSoundEnumerateW(DSoundEnumDevices, &PlaybackDevices); + if(FAILED(hr)) + ERR("Error enumerating DirectSound playback devices (0x%lx)!\n", hr); + std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); + break; + + case CAPTURE_DEVICE_PROBE: + CaptureDevices.clear(); + hr = DirectSoundCaptureEnumerateW(DSoundEnumDevices, &CaptureDevices); + if(FAILED(hr)) + ERR("Error enumerating DirectSound capture devices (0x%lx)!\n", hr); + std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); + break; + } + if(SUCCEEDED(hrcom)) + CoUninitialize(); +} + +static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCdsoundPlayback *backend; + NEW_OBJ(backend, ALCdsoundPlayback)(device); + if(!backend) return nullptr; + return STATIC_CAST(ALCbackend, backend); + } + + if(type == ALCbackend_Capture) + { + ALCdsoundCapture *backend; + NEW_OBJ(backend, ALCdsoundCapture)(device); + if(!backend) return nullptr; + return STATIC_CAST(ALCbackend, backend); + } + + return nullptr; +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d4d41d6..414fd956 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1145,7 +1145,7 @@ IF(HAVE_WINDOWS_H) IF(ALSOFT_BACKEND_DSOUND) SET(HAVE_DSOUND 1) SET(BACKENDS "${BACKENDS} DirectSound${IS_LINKED},") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/dsound.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/dsound.cpp) ADD_BACKEND_LIBS(${DSOUND_LIBRARIES}) SET(INC_PATHS ${INC_PATHS} ${DSOUND_INCLUDE_DIRS}) ENDIF() -- cgit v1.2.3 From d76e9800dabcb1142be2daf69875e165a6da36ed Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 6 Nov 2018 18:55:00 -0800 Subject: Use a more appropriate type for the result of tellg --- Alc/ambdec.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Alc/ambdec.cpp b/Alc/ambdec.cpp index 306b942b..088d4a85 100644 --- a/Alc/ambdec.cpp +++ b/Alc/ambdec.cpp @@ -104,7 +104,7 @@ bool load_ambdec_speakers(AmbDecConf *conf, std::istream &f, std::string &buffer } istr.clear(); - std::streamsize endpos{istr.tellg()}; + std::istream::pos_type endpos{istr.tellg()}; if(!is_at_end(buffer, endpos)) { ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); @@ -183,7 +183,7 @@ bool load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsi } istr.clear(); - std::streamsize endpos{istr.tellg()}; + std::istream::pos_type endpos{istr.tellg()}; if(!is_at_end(buffer, endpos)) { ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); @@ -315,7 +315,7 @@ int AmbDecConf::load(const char *fname) } else if(command == "/speakers/{") { - std::streamsize endpos{istr.tellg()}; + std::istream::pos_type endpos{istr.tellg()}; if(!is_at_end(buffer, endpos)) { ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); @@ -342,7 +342,7 @@ int AmbDecConf::load(const char *fname) } else if(command == "/lfmatrix/{" || command == "/hfmatrix/{" || command == "/matrix/{") { - std::streamsize endpos{istr.tellg()}; + std::istream::pos_type endpos{istr.tellg()}; if(!is_at_end(buffer, endpos)) { ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); @@ -395,7 +395,7 @@ int AmbDecConf::load(const char *fname) } else if(command == "/end") { - std::streamsize endpos{istr.tellg()}; + std::istream::pos_type endpos{istr.tellg()}; if(!is_at_end(buffer, endpos)) { ERR("Unexpected junk on end: %s\n", buffer.c_str()+endpos); @@ -411,7 +411,7 @@ int AmbDecConf::load(const char *fname) } istr.clear(); - std::streamsize endpos{istr.tellg()}; + std::istream::pos_type endpos{istr.tellg()}; if(!is_at_end(buffer, endpos)) { ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); -- cgit v1.2.3 From 27fbccfb23bf6212c8e4a3ecf4bd61ff764fbfd4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 6 Nov 2018 19:14:17 -0800 Subject: Don't directly declare standard function names --- common/math_defs.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/common/math_defs.h b/common/math_defs.h index aa79b695..1b24bec4 100644 --- a/common/math_defs.h +++ b/common/math_defs.h @@ -33,21 +33,23 @@ static const union msvc_inf_hack { #endif #ifndef HAVE_LOG2F -static inline float log2f(float f) +static inline float my_log2f(float f) { return logf(f) / logf(2.0f); } +#define log2f my_log2f #endif #ifndef HAVE_CBRTF -static inline float cbrtf(float f) +static inline float my_cbrtf(float f) { return powf(f, 1.0f/3.0f); } +#define cbrtf my_cbrtf #endif #ifndef HAVE_COPYSIGNF -static inline float copysignf(float x, float y) +static inline float my_copysignf(float x, float y) { union { float f; @@ -57,6 +59,7 @@ static inline float copysignf(float x, float y) ux.u |= (uy.u&0x80000000u); return ux.f; } +#define copysignf my_copysignf #endif #define DEG2RAD(x) ((float)(x) * (float)(M_PI/180.0)) -- cgit v1.2.3 From bf63c3d3d8224e2aea6177087e3436db6a046623 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 6 Nov 2018 19:15:09 -0800 Subject: Don't set _FILE_OFFSET_BITS on Android --- CMakeLists.txt | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 414fd956..567b3d20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -146,14 +146,17 @@ if(NOT WIN32) UNSET(OLD_REQUIRED_FLAGS) ENDIF() -# Set defines for large file support -CHECK_FILE_OFFSET_BITS() -IF(_FILE_OFFSET_BITS) - SET(CPP_DEFS ${CPP_DEFS} "_FILE_OFFSET_BITS=${_FILE_OFFSET_BITS}") - SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_FILE_OFFSET_BITS=${_FILE_OFFSET_BITS}") -ENDIF() -SET(CPP_DEFS ${CPP_DEFS} _LARGEFILE_SOURCE _LARGE_FILES) -SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_LARGEFILE_SOURCE -D_LARGE_FILES") +# Set defines for large file support. Don't set this for Android targets. See: +# https://android-developers.googleblog.com/2017/09/introducing-android-native-development.html +IF(NOT ANDROID) + CHECK_FILE_OFFSET_BITS() + IF(_FILE_OFFSET_BITS) + SET(CPP_DEFS ${CPP_DEFS} "_FILE_OFFSET_BITS=${_FILE_OFFSET_BITS}") + SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_FILE_OFFSET_BITS=${_FILE_OFFSET_BITS}") + ENDIF() + SET(CPP_DEFS ${CPP_DEFS} _LARGEFILE_SOURCE _LARGE_FILES) + SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_LARGEFILE_SOURCE -D_LARGE_FILES") +ENDIF() # C99 has restrict, but C++ does not, so we can only utilize __restrict. SET(RESTRICT_DECL ) -- cgit v1.2.3 From 9d4af941b9516a95190bbef2d15c1c13f31b5306 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 6 Nov 2018 19:23:00 -0800 Subject: Update Travis build images GCC 4.x is too problematic with C++11. Ubuntu Xenial has GCC 5 which has more complete C++11 conformance. For Android, NDK r16 includes libc++ as an alternative to the deprecated GCC 4.9's libstdc++. --- .travis.yml | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 426eef40..6c9bd78b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: c matrix: include: - os: linux - dist: trusty + dist: xenial - os: linux dist: trusty env: @@ -24,17 +24,17 @@ install: fi - > if [[ "${TRAVIS_OS_NAME}" == "linux" && "${BUILD_ANDROID}" == "true" ]]; then - curl -o ~/android-ndk.zip https://dl.google.com/android/repository/android-ndk-r15-linux-x86_64.zip + curl -o ~/android-ndk.zip https://dl.google.com/android/repository/android-ndk-r16b-linux-x86_64.zip unzip -q ~/android-ndk.zip -d ~ \ - 'android-ndk-r15/build/cmake/*' \ - 'android-ndk-r15/build/core/toolchains/arm-linux-androideabi-*/*' \ - 'android-ndk-r15/platforms/android-14/arch-arm/*' \ - 'android-ndk-r15/source.properties' \ - 'android-ndk-r15/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi-v7a/*' \ - 'android-ndk-r15/sources/cxx-stl/gnu-libstdc++/4.9/include/*' \ - 'android-ndk-r15/sysroot/*' \ - 'android-ndk-r15/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/*' \ - 'android-ndk-r15/toolchains/llvm/prebuilt/linux-x86_64/*' + 'android-ndk-r16b/build/cmake/*' \ + 'android-ndk-r16b/build/core/toolchains/arm-linux-androideabi-*/*' \ + 'android-ndk-r16b/platforms/android-14/arch-arm/*' \ + 'android-ndk-r16b/source.properties' \ + 'android-ndk-r16b/sources/cxx-stl/llvm-libc++/4.9/libs/armeabi-v7a/*' \ + 'android-ndk-r16b/sources/cxx-stl/llvm-libc++/4.9/include/*' \ + 'android-ndk-r16b/sysroot/*' \ + 'android-ndk-r16b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/*' \ + 'android-ndk-r16b/toolchains/llvm/prebuilt/linux-x86_64/*' fi script: - > @@ -51,7 +51,8 @@ script: - > if [[ "${TRAVIS_OS_NAME}" == "linux" && "${BUILD_ANDROID}" == "true" ]]; then cmake \ - -DCMAKE_TOOLCHAIN_FILE=~/android-ndk-r15/build/cmake/android.toolchain.cmake \ + -DANDROID_STL=c++_shared \ + -DCMAKE_TOOLCHAIN_FILE=~/android-ndk-r16b/build/cmake/android.toolchain.cmake \ -DALSOFT_REQUIRE_OPENSL=ON \ -DALSOFT_EMBED_HRTF_DATA=YES \ . -- cgit v1.2.3 From 8954d3a438b66e63ff4370ea965717e55f408fc3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 6 Nov 2018 19:34:19 -0800 Subject: Fix Android extraction paths --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6c9bd78b..fb1f1a52 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,8 +30,8 @@ install: 'android-ndk-r16b/build/core/toolchains/arm-linux-androideabi-*/*' \ 'android-ndk-r16b/platforms/android-14/arch-arm/*' \ 'android-ndk-r16b/source.properties' \ - 'android-ndk-r16b/sources/cxx-stl/llvm-libc++/4.9/libs/armeabi-v7a/*' \ - 'android-ndk-r16b/sources/cxx-stl/llvm-libc++/4.9/include/*' \ + 'android-ndk-r16b/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/*' \ + 'android-ndk-r16b/sources/cxx-stl/llvm-libc++/include/*' \ 'android-ndk-r16b/sysroot/*' \ 'android-ndk-r16b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/*' \ 'android-ndk-r16b/toolchains/llvm/prebuilt/linux-x86_64/*' -- cgit v1.2.3 From 620ae6491bf79c6a415c8501767da84e779580ff Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 6 Nov 2018 19:43:14 -0800 Subject: Handle CMake policy CMP0075 --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 567b3d20..0d67911e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,9 @@ IF(COMMAND CMAKE_POLICY) IF(POLICY CMP0054) CMAKE_POLICY(SET CMP0054 NEW) ENDIF(POLICY CMP0054) + IF(POLICY CMP0075) + CMAKE_POLICY(SET CMP0075 NEW) + ENDIF(POLICY CMP0075) ENDIF(COMMAND CMAKE_POLICY) SET(CMAKE_MODULE_PATH "${OpenAL_SOURCE_DIR}/cmake") -- cgit v1.2.3 From aeb3849904f1a3c700e2340cbf26addda7b8f8da Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 6 Nov 2018 20:04:28 -0800 Subject: Also extract the Android support includes --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index fb1f1a52..e24ed7d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,6 +30,7 @@ install: 'android-ndk-r16b/build/core/toolchains/arm-linux-androideabi-*/*' \ 'android-ndk-r16b/platforms/android-14/arch-arm/*' \ 'android-ndk-r16b/source.properties' \ + 'android-ndk-r16b/sources/android/support/include/*' \ 'android-ndk-r16b/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/*' \ 'android-ndk-r16b/sources/cxx-stl/llvm-libc++/include/*' \ 'android-ndk-r16b/sysroot/*' \ -- cgit v1.2.3 From 3cb0999a2332f0b58aa94c8b7897b55926b08ae6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 6 Nov 2018 21:33:08 -0800 Subject: Use the proper enum values for atomic ops --- Alc/backends/dsound.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 4edad4e4..e5efe706 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -267,7 +267,7 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) bool Playing{false}; DWORD LastCursor{0u}; Buffer->GetCurrentPosition(&LastCursor, nullptr); - while(!self->killNow.load(almemory_order_acquire) && + while(!self->killNow.load(std::memory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { // Get current play cursor @@ -623,7 +623,7 @@ retry_open: static ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self) { try { - self->killNow.store(AL_FALSE, almemory_order_release); + self->killNow.store(AL_FALSE, std::memory_order_release); self->thread = std::thread(ALCdsoundPlayback_mixerProc, self); return ALC_TRUE; } @@ -637,7 +637,7 @@ static ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self) static void ALCdsoundPlayback_stop(ALCdsoundPlayback *self) { - if(self->killNow.exchange(AL_TRUE, almemory_order_acq_rel) || !self->thread.joinable()) + if(self->killNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->thread.joinable()) return; self->thread.join(); -- cgit v1.2.3 From 5e5e2f654e72adada54ed426152a5db8e4f8c59b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 6 Nov 2018 21:45:40 -0800 Subject: Disable MSVC warning C4200 "nonstandard extension used: zero-sized array in struct/union" --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d67911e..e4cf5445 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -290,7 +290,7 @@ ENDIF() IF(MSVC) SET(CPP_DEFS ${CPP_DEFS} _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE) - SET(C_FLAGS ${C_FLAGS} /wd4098) + SET(C_FLAGS ${C_FLAGS} /wd4098 /wd4200) IF(NOT DXSDK_DIR) STRING(REGEX REPLACE "\\\\" "/" DXSDK_DIR "$ENV{DXSDK_DIR}") -- cgit v1.2.3 From 41aa9845c46a8eeaf8f1776b4586885d3271474a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 7 Nov 2018 18:26:33 -0800 Subject: Hide function pointer wrapper macros for IDE parsing --- Alc/backends/alsa.c | 2 ++ Alc/backends/dsound.cpp | 2 ++ Alc/backends/jack.c | 2 ++ Alc/backends/portaudio.c | 2 ++ 4 files changed, 8 insertions(+) diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index a967fff0..6f22ae60 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -119,6 +119,7 @@ static void *alsa_handle; ALSA_FUNCS(MAKE_FUNC); #undef MAKE_FUNC +#ifndef IN_IDE_PARSER #define snd_strerror psnd_strerror #define snd_pcm_open psnd_pcm_open #define snd_pcm_close psnd_pcm_close @@ -192,6 +193,7 @@ ALSA_FUNCS(MAKE_FUNC); #define snd_card_next psnd_card_next #define snd_config_update_free_global psnd_config_update_free_global #endif +#endif static ALCboolean alsa_load(void) diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index e5efe706..e760e9f5 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -85,11 +85,13 @@ static HRESULT (WINAPI *pDirectSoundEnumerateW)(LPDSENUMCALLBACKW pDSEnumCallbac static HRESULT (WINAPI *pDirectSoundCaptureCreate)(const GUID *pcGuidDevice, IDirectSoundCapture **ppDSC, IUnknown *pUnkOuter); static HRESULT (WINAPI *pDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW pDSEnumCallback, void *pContext); +#ifndef IN_IDE_PARSER #define DirectSoundCreate pDirectSoundCreate #define DirectSoundEnumerateW pDirectSoundEnumerateW #define DirectSoundCaptureCreate pDirectSoundCaptureCreate #define DirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW #endif +#endif static ALCboolean DSoundLoad(void) diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index 899d5a55..8f934687 100644 --- a/Alc/backends/jack.c +++ b/Alc/backends/jack.c @@ -68,6 +68,7 @@ JACK_FUNCS(MAKE_FUNC); static __typeof(jack_error_callback) * pjack_error_callback; #undef MAKE_FUNC +#ifndef IN_IDE_PARSER #define jack_client_open pjack_client_open #define jack_client_close pjack_client_close #define jack_client_name_size pjack_client_name_size @@ -89,6 +90,7 @@ static __typeof(jack_error_callback) * pjack_error_callback; #define jack_get_buffer_size pjack_get_buffer_size #define jack_error_callback (*pjack_error_callback) #endif +#endif static jack_options_t ClientOptions = JackNullOption; diff --git a/Alc/backends/portaudio.c b/Alc/backends/portaudio.c index 6a6cfa31..7bc3c230 100644 --- a/Alc/backends/portaudio.c +++ b/Alc/backends/portaudio.c @@ -53,6 +53,7 @@ MAKE_FUNC(Pa_GetDefaultInputDevice); MAKE_FUNC(Pa_GetStreamInfo); #undef MAKE_FUNC +#ifndef IN_IDE_PARSER #define Pa_Initialize pPa_Initialize #define Pa_Terminate pPa_Terminate #define Pa_GetErrorText pPa_GetErrorText @@ -64,6 +65,7 @@ MAKE_FUNC(Pa_GetStreamInfo); #define Pa_GetDefaultInputDevice pPa_GetDefaultInputDevice #define Pa_GetStreamInfo pPa_GetStreamInfo #endif +#endif static ALCboolean pa_load(void) { -- cgit v1.2.3 From c354ba2d2ed92543d68ebeb84b1f7de591b71daf Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 8 Nov 2018 14:18:34 +0400 Subject: Fix Resample_bsinc_SSE pointer casts. Regression was introduced in 5ec11a017c. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 39b80250..6fea142a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -402,7 +402,7 @@ int main() IF(HAVE___BUILTIN_ASSUME_ALIGNED) SET(ASSUME_ALIGNED_DECL "__builtin_assume_aligned(x, y)") ELSE() - SET(ASSUME_ALIGNED_DECL "x") + SET(ASSUME_ALIGNED_DECL "(x)") ENDIF() SET(SSE_SWITCH "") -- cgit v1.2.3 From 4eed3e923634267cef0244fc5e3f029adbddc9fe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 7 Nov 2018 21:47:46 -0800 Subject: Move static functions to an anonymous namespace --- OpenAL32/alBuffer.cpp | 891 +++++++++++++++++++++++++------------------------- 1 file changed, 440 insertions(+), 451 deletions(-) diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index dc07e147..b33dc584 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -23,13 +23,13 @@ #include #include #include -#include #ifdef HAVE_MALLOC_H #include #endif #include #include +#include #include #include "alMain.h" @@ -39,31 +39,388 @@ #include "sample_cvt.h" -static ALbuffer *AllocBuffer(ALCcontext *context); -static void FreeBuffer(ALCdevice *device, ALbuffer *buffer); -static const ALchar *NameFromUserFmtType(enum UserFmtType type); -static void LoadData(ALCcontext *context, ALbuffer *buffer, ALuint freq, ALsizei size, - enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, - const ALvoid *data, ALbitfieldSOFT access); -static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type); -static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align); +namespace { -static inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) +constexpr ALbitfieldSOFT INVALID_STORAGE_MASK{~unsigned(AL_MAP_READ_BIT_SOFT | + AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT)}; +constexpr ALbitfieldSOFT MAP_READ_WRITE_FLAGS{AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT}; +constexpr ALbitfieldSOFT INVALID_MAP_FLAGS{~unsigned(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | + AL_MAP_PERSISTENT_BIT_SOFT)}; + + +ALbuffer *AllocBuffer(ALCcontext *context) +{ + ALCdevice *device = context->Device; + std::unique_lock buflock{device->BufferLock}; + + ALbuffer *buffer{nullptr}; + ALsizei lidx{0}, slidx{0}; + BufferSubList *sublist{VECTOR_BEGIN(device->BufferList)}; + BufferSubList *subend{VECTOR_END(device->BufferList)}; + for(;sublist != subend;++sublist) + { + if(sublist->FreeMask) + { + slidx = CTZ64(sublist->FreeMask); + buffer = sublist->Buffers + slidx; + break; + } + ++lidx; + } + if(UNLIKELY(!buffer)) + { + static constexpr BufferSubList empty_sublist{ 0, nullptr }; + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(VECTOR_SIZE(device->BufferList) >= 1<<25)) + { + buflock.unlock(); + alSetError(context, AL_OUT_OF_MEMORY, "Too many buffers allocated"); + return nullptr; + } + lidx = (ALsizei)VECTOR_SIZE(device->BufferList); + VECTOR_PUSH_BACK(device->BufferList, empty_sublist); + sublist = &VECTOR_BACK(device->BufferList); + sublist->FreeMask = ~U64(0); + sublist->Buffers = reinterpret_cast(al_calloc(16, sizeof(ALbuffer)*64)); + if(UNLIKELY(!sublist->Buffers)) + { + VECTOR_POP_BACK(device->BufferList); + buflock.unlock(); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate buffer batch"); + return nullptr; + } + + slidx = 0; + buffer = sublist->Buffers + slidx; + } + + memset(buffer, 0, sizeof(*buffer)); + + /* Add 1 to avoid buffer ID 0. */ + buffer->id = ((lidx<<6) | slidx) + 1; + + sublist->FreeMask &= ~(U64(1)<id - 1}; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; + + al_free(buffer->data); + memset(buffer, 0, sizeof(*buffer)); + + VECTOR_ELEM(device->BufferList, lidx).FreeMask |= U64(1) << slidx; +} + +inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) { ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; if(UNLIKELY(lidx >= VECTOR_SIZE(device->BufferList))) return nullptr; - BufferSubList *sublist = &VECTOR_ELEM(device->BufferList, lidx); + BufferSubList *sublist{&VECTOR_ELEM(device->BufferList, lidx)}; if(UNLIKELY(sublist->FreeMask & (U64(1)<Buffers + slidx; } -#define INVALID_STORAGE_MASK ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT) -#define MAP_READ_WRITE_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT) -#define INVALID_MAP_FLAGS ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT) + +ALsizei SanitizeAlignment(UserFmtType type, ALsizei align) +{ + if(align < 0) + return 0; + + if(align == 0) + { + if(type == UserFmtIMA4) + { + /* Here is where things vary: + * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel + * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel + */ + return 65; + } + if(type == UserFmtMSADPCM) + return 64; + return 1; + } + + if(type == UserFmtIMA4) + { + /* IMA4 block alignment must be a multiple of 8, plus 1. */ + if((align&7) == 1) return align; + return 0; + } + if(type == UserFmtMSADPCM) + { + /* MSADPCM block alignment must be a multiple of 2. */ + if((align&1) == 0) return align; + return 0; + } + + return align; +} + + +const ALchar *NameFromUserFmtType(UserFmtType type) +{ + switch(type) + { + case UserFmtUByte: return "Unsigned Byte"; + case UserFmtShort: return "Signed Short"; + case UserFmtFloat: return "Float32"; + case UserFmtDouble: return "Float64"; + case UserFmtMulaw: return "muLaw"; + case UserFmtAlaw: return "aLaw"; + case UserFmtIMA4: return "IMA4 ADPCM"; + case UserFmtMSADPCM: return "MSADPCM"; + } + return ""; +} + +/* + * LoadData + * + * Loads the specified data into the buffer, using the specified format. + */ +void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, UserFmtChannels SrcChannels, UserFmtType SrcType, const ALvoid *data, ALbitfieldSOFT access) +{ + if(UNLIKELY(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)) + SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer %u", + ALBuf->id); + + /* Currently no channel configurations need to be converted. */ + FmtChannels DstChannels{FmtMono}; + switch(SrcChannels) + { + case UserFmtMono: DstChannels = FmtMono; break; + case UserFmtStereo: DstChannels = FmtStereo; break; + case UserFmtRear: DstChannels = FmtRear; break; + case UserFmtQuad: DstChannels = FmtQuad; break; + case UserFmtX51: DstChannels = FmtX51; break; + case UserFmtX61: DstChannels = FmtX61; break; + case UserFmtX71: DstChannels = FmtX71; break; + case UserFmtBFormat2D: DstChannels = FmtBFormat2D; break; + case UserFmtBFormat3D: DstChannels = FmtBFormat3D; break; + } + if(UNLIKELY((long)SrcChannels != (long)DstChannels)) + SETERR_RETURN(context, AL_INVALID_ENUM,, "Invalid format"); + + /* IMA4 and MSADPCM convert to 16-bit short. */ + FmtType DstType{FmtUByte}; + switch(SrcType) + { + case UserFmtUByte: DstType = FmtUByte; break; + case UserFmtShort: DstType = FmtShort; break; + case UserFmtFloat: DstType = FmtFloat; break; + case UserFmtDouble: DstType = FmtDouble; break; + case UserFmtAlaw: DstType = FmtAlaw; break; + case UserFmtMulaw: DstType = FmtMulaw; break; + case UserFmtIMA4: DstType = FmtShort; break; + case UserFmtMSADPCM: DstType = FmtShort; break; + } + + /* TODO: Currently we can only map samples when they're not converted. To + * allow it would need some kind of double-buffering to hold onto a copy of + * the original data. + */ + if((access&MAP_READ_WRITE_FLAGS)) + { + if(UNLIKELY((long)SrcType != (long)DstType)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "%s samples cannot be mapped", + NameFromUserFmtType(SrcType)); + } + + ALsizei unpackalign{ATOMIC_LOAD_SEQ(&ALBuf->UnpackAlign)}; + ALsizei align{SanitizeAlignment(SrcType, unpackalign)}; + if(UNLIKELY(align < 1)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid unpack alignment %d for %s samples", + unpackalign, NameFromUserFmtType(SrcType)); + + if((access&AL_PRESERVE_DATA_BIT_SOFT)) + { + /* Can only preserve data with the same format and alignment. */ + if(UNLIKELY(ALBuf->FmtChannels != DstChannels || ALBuf->OriginalType != SrcType)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched format"); + if(UNLIKELY(ALBuf->OriginalAlign != align)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched alignment"); + } + + /* Convert the input/source size in bytes to sample frames using the unpack + * block alignment. + */ + ALsizei SrcByteAlign{ + (SrcType == UserFmtIMA4) ? ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels) : + (SrcType == UserFmtMSADPCM) ? ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels) : + align * FrameSizeFromUserFmt(SrcChannels, SrcType) + }; + if(UNLIKELY((size%SrcByteAlign) != 0)) + SETERR_RETURN(context, AL_INVALID_VALUE,, + "Data size %d is not a multiple of frame size %d (%d unpack alignment)", + size, SrcByteAlign, align); + + if(UNLIKELY(size/SrcByteAlign > std::numeric_limits::max()/align)) + SETERR_RETURN(context, AL_OUT_OF_MEMORY,, + "Buffer size overflow, %d blocks x %d samples per block", size/SrcByteAlign, align); + ALsizei frames{size / SrcByteAlign * align}; + + /* Convert the sample frames to the number of bytes needed for internal + * storage. + */ + ALsizei NumChannels{ChannelsFromFmt(DstChannels)}; + ALsizei FrameSize{NumChannels * BytesFromFmt(DstType)}; + if(UNLIKELY(frames > std::numeric_limits::max()/FrameSize)) + SETERR_RETURN(context, AL_OUT_OF_MEMORY,, + "Buffer size overflow, %d frames x %d bytes per frame", frames, FrameSize); + ALsizei newsize{frames*FrameSize}; + + /* Round up to the next 16-byte multiple. This could reallocate only when + * increasing or the new size is less than half the current, but then the + * buffer's AL_SIZE would not be very reliable for accounting buffer memory + * usage, and reporting the real size could cause problems for apps that + * use AL_SIZE to try to get the buffer's play length. + */ + if(LIKELY(newsize <= std::numeric_limits::max()-15)) + newsize = (newsize+15) & ~0xf; + if(newsize != ALBuf->BytesAlloc) + { + void *temp{al_malloc(16, (size_t)newsize)}; + if(UNLIKELY(!temp && newsize)) + SETERR_RETURN(context, AL_OUT_OF_MEMORY,, "Failed to allocate %d bytes of storage", + newsize); + if((access&AL_PRESERVE_DATA_BIT_SOFT)) + { + ALsizei tocopy{std::min(newsize, ALBuf->BytesAlloc)}; + if(tocopy > 0) memcpy(temp, ALBuf->data, tocopy); + } + al_free(ALBuf->data); + ALBuf->data = temp; + ALBuf->BytesAlloc = newsize; + } + + if(SrcType == UserFmtIMA4) + { + assert(DstType == FmtShort); + if(data != nullptr && ALBuf->data != nullptr) + Convert_ALshort_ALima4(static_cast(ALBuf->data), + static_cast(data), NumChannels, frames, align); + ALBuf->OriginalAlign = align; + } + else if(SrcType == UserFmtMSADPCM) + { + assert(DstType == FmtShort); + if(data != nullptr && ALBuf->data != nullptr) + Convert_ALshort_ALmsadpcm(static_cast(ALBuf->data), + static_cast(data), NumChannels, frames, align); + ALBuf->OriginalAlign = align; + } + else + { + assert((long)SrcType == (long)DstType); + if(data != nullptr && ALBuf->data != nullptr) + memcpy(ALBuf->data, data, frames*FrameSize); + ALBuf->OriginalAlign = 1; + } + ALBuf->OriginalSize = size; + ALBuf->OriginalType = SrcType; + + ALBuf->Frequency = freq; + ALBuf->FmtChannels = DstChannels; + ALBuf->FmtType = DstType; + ALBuf->Access = access; + + ALBuf->SampleLen = frames; + ALBuf->LoopStart = 0; + ALBuf->LoopEnd = ALBuf->SampleLen; +} + +ALboolean DecomposeUserFormat(ALenum format, UserFmtChannels *chans, UserFmtType *type) +{ + struct FormatMap { + ALenum format; + UserFmtChannels channels; + UserFmtType type; + }; + static constexpr std::array list{{ + { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte }, + { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort }, + { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat }, + { AL_FORMAT_MONO_DOUBLE_EXT, UserFmtMono, UserFmtDouble }, + { AL_FORMAT_MONO_IMA4, UserFmtMono, UserFmtIMA4 }, + { AL_FORMAT_MONO_MSADPCM_SOFT, UserFmtMono, UserFmtMSADPCM }, + { AL_FORMAT_MONO_MULAW, UserFmtMono, UserFmtMulaw }, + { AL_FORMAT_MONO_ALAW_EXT, UserFmtMono, UserFmtAlaw }, + + { AL_FORMAT_STEREO8, UserFmtStereo, UserFmtUByte }, + { AL_FORMAT_STEREO16, UserFmtStereo, UserFmtShort }, + { AL_FORMAT_STEREO_FLOAT32, UserFmtStereo, UserFmtFloat }, + { AL_FORMAT_STEREO_DOUBLE_EXT, UserFmtStereo, UserFmtDouble }, + { AL_FORMAT_STEREO_IMA4, UserFmtStereo, UserFmtIMA4 }, + { AL_FORMAT_STEREO_MSADPCM_SOFT, UserFmtStereo, UserFmtMSADPCM }, + { AL_FORMAT_STEREO_MULAW, UserFmtStereo, UserFmtMulaw }, + { AL_FORMAT_STEREO_ALAW_EXT, UserFmtStereo, UserFmtAlaw }, + + { AL_FORMAT_REAR8, UserFmtRear, UserFmtUByte }, + { AL_FORMAT_REAR16, UserFmtRear, UserFmtShort }, + { AL_FORMAT_REAR32, UserFmtRear, UserFmtFloat }, + { AL_FORMAT_REAR_MULAW, UserFmtRear, UserFmtMulaw }, + + { AL_FORMAT_QUAD8_LOKI, UserFmtQuad, UserFmtUByte }, + { AL_FORMAT_QUAD16_LOKI, UserFmtQuad, UserFmtShort }, + + { AL_FORMAT_QUAD8, UserFmtQuad, UserFmtUByte }, + { AL_FORMAT_QUAD16, UserFmtQuad, UserFmtShort }, + { AL_FORMAT_QUAD32, UserFmtQuad, UserFmtFloat }, + { AL_FORMAT_QUAD_MULAW, UserFmtQuad, UserFmtMulaw }, + + { AL_FORMAT_51CHN8, UserFmtX51, UserFmtUByte }, + { AL_FORMAT_51CHN16, UserFmtX51, UserFmtShort }, + { AL_FORMAT_51CHN32, UserFmtX51, UserFmtFloat }, + { AL_FORMAT_51CHN_MULAW, UserFmtX51, UserFmtMulaw }, + + { AL_FORMAT_61CHN8, UserFmtX61, UserFmtUByte }, + { AL_FORMAT_61CHN16, UserFmtX61, UserFmtShort }, + { AL_FORMAT_61CHN32, UserFmtX61, UserFmtFloat }, + { AL_FORMAT_61CHN_MULAW, UserFmtX61, UserFmtMulaw }, + + { AL_FORMAT_71CHN8, UserFmtX71, UserFmtUByte }, + { AL_FORMAT_71CHN16, UserFmtX71, UserFmtShort }, + { AL_FORMAT_71CHN32, UserFmtX71, UserFmtFloat }, + { AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw }, + + { AL_FORMAT_BFORMAT2D_8, UserFmtBFormat2D, UserFmtUByte }, + { AL_FORMAT_BFORMAT2D_16, UserFmtBFormat2D, UserFmtShort }, + { AL_FORMAT_BFORMAT2D_FLOAT32, UserFmtBFormat2D, UserFmtFloat }, + { AL_FORMAT_BFORMAT2D_MULAW, UserFmtBFormat2D, UserFmtMulaw }, + + { AL_FORMAT_BFORMAT3D_8, UserFmtBFormat3D, UserFmtUByte }, + { AL_FORMAT_BFORMAT3D_16, UserFmtBFormat3D, UserFmtShort }, + { AL_FORMAT_BFORMAT3D_FLOAT32, UserFmtBFormat3D, UserFmtFloat }, + { AL_FORMAT_BFORMAT3D_MULAW, UserFmtBFormat3D, UserFmtMulaw }, + }}; + + for(const auto &fmt : list) + { + if(fmt.format == format) + { + *chans = fmt.channels; + *type = fmt.type; + return AL_TRUE; + } + } + + return AL_FALSE; +} + +} // namespace + AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) { @@ -174,8 +531,8 @@ AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALCdevice *device = context->Device; std::lock_guard _{device->BufferLock}; - enum UserFmtChannels srcchannels = UserFmtMono; - enum UserFmtType srctype = UserFmtUByte; + UserFmtChannels srcchannels{UserFmtMono}; + UserFmtType srctype{UserFmtUByte}; ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) @@ -305,8 +662,8 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons ALCdevice *device = context->Device; std::lock_guard _{device->BufferLock}; - enum UserFmtChannels srcchannels = UserFmtMono; - enum UserFmtType srctype = UserFmtUByte; + UserFmtChannels srcchannels{UserFmtMono}; + UserFmtType srctype{UserFmtUByte}; ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) @@ -680,258 +1037,78 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value break; case AL_PACK_BLOCK_ALIGNMENT_SOFT: - *value = ATOMIC_LOAD_SEQ(&albuf->PackAlign); - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); - } -} - - -AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3) -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!value1 || !value2 || !value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); - } -} - - -AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values) -{ - switch(param) - { - case AL_FREQUENCY: - case AL_BITS: - case AL_CHANNELS: - case AL_SIZE: - case AL_INTERNAL_FORMAT_SOFT: - case AL_BYTE_LENGTH_SOFT: - case AL_SAMPLE_LENGTH_SOFT: - case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: - case AL_PACK_BLOCK_ALIGNMENT_SOFT: - alGetBufferi(buffer, param, values); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!values)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_LOOP_POINTS_SOFT: - values[0] = albuf->LoopStart; - values[1] = albuf->LoopEnd; - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", - param); - } -} - - -static const ALchar *NameFromUserFmtType(enum UserFmtType type) -{ - switch(type) - { - case UserFmtUByte: return "Unsigned Byte"; - case UserFmtShort: return "Signed Short"; - case UserFmtFloat: return "Float32"; - case UserFmtDouble: return "Float64"; - case UserFmtMulaw: return "muLaw"; - case UserFmtAlaw: return "aLaw"; - case UserFmtIMA4: return "IMA4 ADPCM"; - case UserFmtMSADPCM: return "MSADPCM"; - } - return ""; -} - -/* - * LoadData - * - * Loads the specified data into the buffer, using the specified format. - */ -static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALbitfieldSOFT access) -{ - enum FmtChannels DstChannels = FmtMono; - enum FmtType DstType = FmtUByte; - ALsizei NumChannels, FrameSize; - ALsizei SrcByteAlign; - ALsizei unpackalign; - ALsizei newsize; - ALsizei frames; - ALsizei align; - - if(UNLIKELY(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)) - SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer %u", - ALBuf->id); - - /* Currently no channel configurations need to be converted. */ - switch(SrcChannels) - { - case UserFmtMono: DstChannels = FmtMono; break; - case UserFmtStereo: DstChannels = FmtStereo; break; - case UserFmtRear: DstChannels = FmtRear; break; - case UserFmtQuad: DstChannels = FmtQuad; break; - case UserFmtX51: DstChannels = FmtX51; break; - case UserFmtX61: DstChannels = FmtX61; break; - case UserFmtX71: DstChannels = FmtX71; break; - case UserFmtBFormat2D: DstChannels = FmtBFormat2D; break; - case UserFmtBFormat3D: DstChannels = FmtBFormat3D; break; - } - if(UNLIKELY((long)SrcChannels != (long)DstChannels)) - SETERR_RETURN(context, AL_INVALID_ENUM,, "Invalid format"); - - /* IMA4 and MSADPCM convert to 16-bit short. */ - switch(SrcType) - { - case UserFmtUByte: DstType = FmtUByte; break; - case UserFmtShort: DstType = FmtShort; break; - case UserFmtFloat: DstType = FmtFloat; break; - case UserFmtDouble: DstType = FmtDouble; break; - case UserFmtAlaw: DstType = FmtAlaw; break; - case UserFmtMulaw: DstType = FmtMulaw; break; - case UserFmtIMA4: DstType = FmtShort; break; - case UserFmtMSADPCM: DstType = FmtShort; break; - } - - /* TODO: Currently we can only map samples when they're not converted. To - * allow it would need some kind of double-buffering to hold onto a copy of - * the original data. - */ - if((access&MAP_READ_WRITE_FLAGS)) - { - if(UNLIKELY((long)SrcType != (long)DstType)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "%s samples cannot be mapped", - NameFromUserFmtType(SrcType)); - } - - unpackalign = ATOMIC_LOAD_SEQ(&ALBuf->UnpackAlign); - if(UNLIKELY((align=SanitizeAlignment(SrcType, unpackalign)) < 1)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid unpack alignment %d for %s samples", - unpackalign, NameFromUserFmtType(SrcType)); - - if((access&AL_PRESERVE_DATA_BIT_SOFT)) - { - /* Can only preserve data with the same format and alignment. */ - if(UNLIKELY(ALBuf->FmtChannels != DstChannels || ALBuf->OriginalType != SrcType)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched format"); - if(UNLIKELY(ALBuf->OriginalAlign != align)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched alignment"); - } - - /* Convert the input/source size in bytes to sample frames using the unpack - * block alignment. - */ - if(SrcType == UserFmtIMA4) - SrcByteAlign = ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels); - else if(SrcType == UserFmtMSADPCM) - SrcByteAlign = ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels); - else - SrcByteAlign = align * FrameSizeFromUserFmt(SrcChannels, SrcType); - if(UNLIKELY((size%SrcByteAlign) != 0)) - SETERR_RETURN(context, AL_INVALID_VALUE,, - "Data size %d is not a multiple of frame size %d (%d unpack alignment)", - size, SrcByteAlign, align); - - if(UNLIKELY(size / SrcByteAlign > INT_MAX / align)) - SETERR_RETURN(context, AL_OUT_OF_MEMORY,, - "Buffer size overflow, %d blocks x %d samples per block", size/SrcByteAlign, align); - frames = size / SrcByteAlign * align; - - /* Convert the sample frames to the number of bytes needed for internal - * storage. - */ - NumChannels = ChannelsFromFmt(DstChannels); - FrameSize = NumChannels * BytesFromFmt(DstType); - if(UNLIKELY(frames > INT_MAX/FrameSize)) - SETERR_RETURN(context, AL_OUT_OF_MEMORY,, - "Buffer size overflow, %d frames x %d bytes per frame", frames, FrameSize); - newsize = frames*FrameSize; - - /* Round up to the next 16-byte multiple. This could reallocate only when - * increasing or the new size is less than half the current, but then the - * buffer's AL_SIZE would not be very reliable for accounting buffer memory - * usage, and reporting the real size could cause problems for apps that - * use AL_SIZE to try to get the buffer's play length. - */ - if(LIKELY(newsize <= INT_MAX-15)) - newsize = (newsize+15) & ~0xf; - if(newsize != ALBuf->BytesAlloc) - { - void *temp = al_malloc(16, (size_t)newsize); - if(UNLIKELY(!temp && newsize)) - SETERR_RETURN(context, AL_OUT_OF_MEMORY,, "Failed to allocate %d bytes of storage", - newsize); - if((access&AL_PRESERVE_DATA_BIT_SOFT)) - { - ALsizei tocopy = mini(newsize, ALBuf->BytesAlloc); - if(tocopy > 0) memcpy(temp, ALBuf->data, tocopy); - } - al_free(ALBuf->data); - ALBuf->data = temp; - ALBuf->BytesAlloc = newsize; - } - - if(SrcType == UserFmtIMA4) - { - assert(DstType == FmtShort); - if(data != nullptr && ALBuf->data != nullptr) - Convert_ALshort_ALima4(static_cast(ALBuf->data), - static_cast(data), NumChannels, frames, align); - ALBuf->OriginalAlign = align; + *value = ATOMIC_LOAD_SEQ(&albuf->PackAlign); + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); } - else if(SrcType == UserFmtMSADPCM) +} + + +AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!value1 || !value2 || !value3)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) { - assert(DstType == FmtShort); - if(data != nullptr && ALBuf->data != nullptr) - Convert_ALshort_ALmsadpcm(static_cast(ALBuf->data), - static_cast(data), NumChannels, frames, align); - ALBuf->OriginalAlign = align; + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); } - else +} + + +AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values) +{ + switch(param) { - assert((long)SrcType == (long)DstType); - if(data != nullptr && ALBuf->data != nullptr) - memcpy(ALBuf->data, data, frames*FrameSize); - ALBuf->OriginalAlign = 1; + case AL_FREQUENCY: + case AL_BITS: + case AL_CHANNELS: + case AL_SIZE: + case AL_INTERNAL_FORMAT_SOFT: + case AL_BYTE_LENGTH_SOFT: + case AL_SAMPLE_LENGTH_SOFT: + case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: + case AL_PACK_BLOCK_ALIGNMENT_SOFT: + alGetBufferi(buffer, param, values); + return; } - ALBuf->OriginalSize = size; - ALBuf->OriginalType = SrcType; - ALBuf->Frequency = freq; - ALBuf->FmtChannels = DstChannels; - ALBuf->FmtType = DstType; - ALBuf->Access = access; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - ALBuf->SampleLen = frames; - ALBuf->LoopStart = 0; - ALBuf->LoopEnd = ALBuf->SampleLen; + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!values)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_LOOP_POINTS_SOFT: + values[0] = albuf->LoopStart; + values[1] = albuf->LoopEnd; + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", + param); + } } -ALsizei BytesFromUserFmt(enum UserFmtType type) +ALsizei BytesFromUserFmt(UserFmtType type) { switch(type) { @@ -946,7 +1123,7 @@ ALsizei BytesFromUserFmt(enum UserFmtType type) } return 0; } -ALsizei ChannelsFromUserFmt(enum UserFmtChannels chans) +ALsizei ChannelsFromUserFmt(UserFmtChannels chans) { switch(chans) { @@ -962,86 +1139,8 @@ ALsizei ChannelsFromUserFmt(enum UserFmtChannels chans) } return 0; } -static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, - enum UserFmtType *type) -{ - struct FormatMap { - ALenum format; - UserFmtChannels channels; - UserFmtType type; - }; - static constexpr std::array list{{ - { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte }, - { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort }, - { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat }, - { AL_FORMAT_MONO_DOUBLE_EXT, UserFmtMono, UserFmtDouble }, - { AL_FORMAT_MONO_IMA4, UserFmtMono, UserFmtIMA4 }, - { AL_FORMAT_MONO_MSADPCM_SOFT, UserFmtMono, UserFmtMSADPCM }, - { AL_FORMAT_MONO_MULAW, UserFmtMono, UserFmtMulaw }, - { AL_FORMAT_MONO_ALAW_EXT, UserFmtMono, UserFmtAlaw }, - - { AL_FORMAT_STEREO8, UserFmtStereo, UserFmtUByte }, - { AL_FORMAT_STEREO16, UserFmtStereo, UserFmtShort }, - { AL_FORMAT_STEREO_FLOAT32, UserFmtStereo, UserFmtFloat }, - { AL_FORMAT_STEREO_DOUBLE_EXT, UserFmtStereo, UserFmtDouble }, - { AL_FORMAT_STEREO_IMA4, UserFmtStereo, UserFmtIMA4 }, - { AL_FORMAT_STEREO_MSADPCM_SOFT, UserFmtStereo, UserFmtMSADPCM }, - { AL_FORMAT_STEREO_MULAW, UserFmtStereo, UserFmtMulaw }, - { AL_FORMAT_STEREO_ALAW_EXT, UserFmtStereo, UserFmtAlaw }, - - { AL_FORMAT_REAR8, UserFmtRear, UserFmtUByte }, - { AL_FORMAT_REAR16, UserFmtRear, UserFmtShort }, - { AL_FORMAT_REAR32, UserFmtRear, UserFmtFloat }, - { AL_FORMAT_REAR_MULAW, UserFmtRear, UserFmtMulaw }, - - { AL_FORMAT_QUAD8_LOKI, UserFmtQuad, UserFmtUByte }, - { AL_FORMAT_QUAD16_LOKI, UserFmtQuad, UserFmtShort }, - - { AL_FORMAT_QUAD8, UserFmtQuad, UserFmtUByte }, - { AL_FORMAT_QUAD16, UserFmtQuad, UserFmtShort }, - { AL_FORMAT_QUAD32, UserFmtQuad, UserFmtFloat }, - { AL_FORMAT_QUAD_MULAW, UserFmtQuad, UserFmtMulaw }, - - { AL_FORMAT_51CHN8, UserFmtX51, UserFmtUByte }, - { AL_FORMAT_51CHN16, UserFmtX51, UserFmtShort }, - { AL_FORMAT_51CHN32, UserFmtX51, UserFmtFloat }, - { AL_FORMAT_51CHN_MULAW, UserFmtX51, UserFmtMulaw }, - - { AL_FORMAT_61CHN8, UserFmtX61, UserFmtUByte }, - { AL_FORMAT_61CHN16, UserFmtX61, UserFmtShort }, - { AL_FORMAT_61CHN32, UserFmtX61, UserFmtFloat }, - { AL_FORMAT_61CHN_MULAW, UserFmtX61, UserFmtMulaw }, - - { AL_FORMAT_71CHN8, UserFmtX71, UserFmtUByte }, - { AL_FORMAT_71CHN16, UserFmtX71, UserFmtShort }, - { AL_FORMAT_71CHN32, UserFmtX71, UserFmtFloat }, - { AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw }, - - { AL_FORMAT_BFORMAT2D_8, UserFmtBFormat2D, UserFmtUByte }, - { AL_FORMAT_BFORMAT2D_16, UserFmtBFormat2D, UserFmtShort }, - { AL_FORMAT_BFORMAT2D_FLOAT32, UserFmtBFormat2D, UserFmtFloat }, - { AL_FORMAT_BFORMAT2D_MULAW, UserFmtBFormat2D, UserFmtMulaw }, - - { AL_FORMAT_BFORMAT3D_8, UserFmtBFormat3D, UserFmtUByte }, - { AL_FORMAT_BFORMAT3D_16, UserFmtBFormat3D, UserFmtShort }, - { AL_FORMAT_BFORMAT3D_FLOAT32, UserFmtBFormat3D, UserFmtFloat }, - { AL_FORMAT_BFORMAT3D_MULAW, UserFmtBFormat3D, UserFmtMulaw }, - }}; - - for(const auto &fmt : list) - { - if(fmt.format == format) - { - *chans = fmt.channels; - *type = fmt.type; - return AL_TRUE; - } - } - - return AL_FALSE; -} -ALsizei BytesFromFmt(enum FmtType type) +ALsizei BytesFromFmt(FmtType type) { switch(type) { @@ -1054,7 +1153,7 @@ ALsizei BytesFromFmt(enum FmtType type) } return 0; } -ALsizei ChannelsFromFmt(enum FmtChannels chans) +ALsizei ChannelsFromFmt(FmtChannels chans) { switch(chans) { @@ -1071,116 +1170,6 @@ ALsizei ChannelsFromFmt(enum FmtChannels chans) return 0; } -static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align) -{ - if(align < 0) - return 0; - - if(align == 0) - { - if(type == UserFmtIMA4) - { - /* Here is where things vary: - * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel - * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel - */ - return 65; - } - if(type == UserFmtMSADPCM) - return 64; - return 1; - } - - if(type == UserFmtIMA4) - { - /* IMA4 block alignment must be a multiple of 8, plus 1. */ - if((align&7) == 1) return align; - return 0; - } - if(type == UserFmtMSADPCM) - { - /* MSADPCM block alignment must be a multiple of 2. */ - if((align&1) == 0) return align; - return 0; - } - - return align; -} - - -static ALbuffer *AllocBuffer(ALCcontext *context) -{ - ALCdevice *device = context->Device; - BufferSubList *sublist, *subend; - ALbuffer *buffer = nullptr; - ALsizei lidx = 0; - ALsizei slidx; - - std::unique_lock buflock{device->BufferLock}; - - sublist = VECTOR_BEGIN(device->BufferList); - subend = VECTOR_END(device->BufferList); - for(;sublist != subend;++sublist) - { - if(sublist->FreeMask) - { - slidx = CTZ64(sublist->FreeMask); - buffer = sublist->Buffers + slidx; - break; - } - ++lidx; - } - if(UNLIKELY(!buffer)) - { - const BufferSubList empty_sublist = { 0, nullptr }; - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ - if(UNLIKELY(VECTOR_SIZE(device->BufferList) >= 1<<25)) - { - buflock.unlock(); - alSetError(context, AL_OUT_OF_MEMORY, "Too many buffers allocated"); - return nullptr; - } - lidx = (ALsizei)VECTOR_SIZE(device->BufferList); - VECTOR_PUSH_BACK(device->BufferList, empty_sublist); - sublist = &VECTOR_BACK(device->BufferList); - sublist->FreeMask = ~U64(0); - sublist->Buffers = reinterpret_cast(al_calloc(16, sizeof(ALbuffer)*64)); - if(UNLIKELY(!sublist->Buffers)) - { - VECTOR_POP_BACK(device->BufferList); - buflock.unlock(); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate buffer batch"); - return nullptr; - } - - slidx = 0; - buffer = sublist->Buffers + slidx; - } - - memset(buffer, 0, sizeof(*buffer)); - - /* Add 1 to avoid buffer ID 0. */ - buffer->id = ((lidx<<6) | slidx) + 1; - - sublist->FreeMask &= ~(U64(1)<id - 1; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; - - al_free(buffer->data); - memset(buffer, 0, sizeof(*buffer)); - - VECTOR_ELEM(device->BufferList, lidx).FreeMask |= U64(1) << slidx; -} - /* * ReleaseALBuffers() -- cgit v1.2.3 From 29435ad9668198dd8dc7c21182f3663ec27dd81f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Nov 2018 04:15:16 -0800 Subject: Prevent MSVC's dumb min/max macros --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ba1db905..e7a35edc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -289,7 +289,7 @@ IF(NOT CMAKE_DEBUG_POSTFIX) ENDIF() IF(MSVC) - SET(CPP_DEFS ${CPP_DEFS} _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE) + SET(CPP_DEFS ${CPP_DEFS} _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE NOMIXMAX) SET(C_FLAGS ${C_FLAGS} /wd4098 /wd4200) IF(NOT DXSDK_DIR) -- cgit v1.2.3 From b27ccb8aa63864ac3efe6f2f2e0b854279b1e7d1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Nov 2018 12:21:25 -0800 Subject: Fix a macro typo --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e7a35edc..3bf84f27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -289,7 +289,7 @@ IF(NOT CMAKE_DEBUG_POSTFIX) ENDIF() IF(MSVC) - SET(CPP_DEFS ${CPP_DEFS} _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE NOMIXMAX) + SET(CPP_DEFS ${CPP_DEFS} _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE NOMINMAX) SET(C_FLAGS ${C_FLAGS} /wd4098 /wd4200) IF(NOT DXSDK_DIR) -- cgit v1.2.3 From d71e50f7f7170ce91dd238ed5a7bd57177907df9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Nov 2018 14:09:13 -0800 Subject: Avoid using out parameters --- OpenAL32/alBuffer.cpp | 154 ++++++++++++++++++++++++++------------------------ 1 file changed, 81 insertions(+), 73 deletions(-) diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index b33dc584..d6a8f6c2 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -27,6 +27,7 @@ #include #endif +#include #include #include #include @@ -341,14 +342,15 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U ALBuf->LoopEnd = ALBuf->SampleLen; } -ALboolean DecomposeUserFormat(ALenum format, UserFmtChannels *chans, UserFmtType *type) +using DecompResult = std::tuple; +DecompResult DecomposeUserFormat(ALenum format) { struct FormatMap { ALenum format; UserFmtChannels channels; UserFmtType type; }; - static constexpr std::array list{{ + static constexpr std::array UserFmtList{{ { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte }, { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort }, { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat }, @@ -406,17 +408,18 @@ ALboolean DecomposeUserFormat(ALenum format, UserFmtChannels *chans, UserFmtType { AL_FORMAT_BFORMAT3D_MULAW, UserFmtBFormat3D, UserFmtMulaw }, }}; - for(const auto &fmt : list) + DecompResult ret{}; + for(const auto &fmt : UserFmtList) { if(fmt.format == format) { - *chans = fmt.channels; - *type = fmt.type; - return AL_TRUE; + std::get<0>(ret) = true; + std::get<1>(ret) = fmt.channels; + std::get<2>(ret) = fmt.type; + break; } } - - return AL_FALSE; + return ret; } } // namespace @@ -531,9 +534,6 @@ AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALCdevice *device = context->Device; std::lock_guard _{device->BufferLock}; - UserFmtChannels srcchannels{UserFmtMono}; - UserFmtType srctype{UserFmtUByte}; - ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); @@ -547,10 +547,18 @@ AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const else if(UNLIKELY((flags&AL_MAP_PERSISTENT_BIT_SOFT) && !(flags&MAP_READ_WRITE_FLAGS))) alSetError(context.get(), AL_INVALID_VALUE, "Declaring persistently mapped storage without read or write access"); - else if(UNLIKELY(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid format 0x%04x", format); else - LoadData(context.get(), albuf, freq, size, srcchannels, srctype, data, flags); + { + UserFmtType srctype{UserFmtUByte}; + UserFmtChannels srcchannels{UserFmtMono}; + bool success; + + std::tie(success, srcchannels, srctype) = DecomposeUserFormat(format); + if(UNLIKELY(!success)) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid format 0x%04x", format); + else + LoadData(context.get(), albuf, freq, size, srcchannels, srctype, data, flags); + } } AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access) @@ -662,76 +670,76 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons ALCdevice *device = context->Device; std::lock_guard _{device->BufferLock}; - UserFmtChannels srcchannels{UserFmtMono}; - UserFmtType srctype{UserFmtUByte}; - ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) + { alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)) + return; + } + + UserFmtType srctype{UserFmtUByte}; + UserFmtChannels srcchannels{UserFmtMono}; + bool success; + std::tie(success, srcchannels, srctype) = DecomposeUserFormat(format); + if(UNLIKELY(!success)) + { alSetError(context.get(), AL_INVALID_ENUM, "Invalid format 0x%04x", format); + return; + } + + ALsizei unpack_align{ATOMIC_LOAD_SEQ(&albuf->UnpackAlign)}; + ALsizei align{SanitizeAlignment(srctype, unpack_align)}; + if(UNLIKELY(align < 1)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid unpack alignment %d", unpack_align); + else if(UNLIKELY((long)srcchannels != (long)albuf->FmtChannels || + srctype != albuf->OriginalType)) + alSetError(context.get(), AL_INVALID_ENUM, "Unpacking data with mismatched format"); + else if(UNLIKELY(align != albuf->OriginalAlign)) + alSetError(context.get(), AL_INVALID_VALUE, + "Unpacking data with alignment %u does not match original alignment %u", + align, albuf->OriginalAlign); + else if(UNLIKELY(albuf->MappedAccess != 0)) + alSetError(context.get(), AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u", + buffer); else { - ALsizei unpack_align, align; - ALsizei byte_align; - ALsizei frame_size; - ALsizei num_chans; - - unpack_align = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign); - align = SanitizeAlignment(srctype, unpack_align); - if(UNLIKELY(align < 1)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid unpack alignment %d", unpack_align); - else if(UNLIKELY((long)srcchannels != (long)albuf->FmtChannels || - srctype != albuf->OriginalType)) - alSetError(context.get(), AL_INVALID_ENUM, "Unpacking data with mismatched format"); - else if(UNLIKELY(align != albuf->OriginalAlign)) + ALsizei num_chans{ChannelsFromFmt(albuf->FmtChannels)}; + ALsizei frame_size{num_chans * BytesFromFmt(albuf->FmtType)}; + ALsizei byte_align{ + (albuf->OriginalType == UserFmtIMA4) ? ((align-1)/2 + 4) * num_chans : + (albuf->OriginalType == UserFmtMSADPCM) ? ((align-2)/2 + 7) * num_chans : + (align * frame_size) + }; + + if(UNLIKELY(offset < 0 || length < 0 || offset > albuf->OriginalSize || + length > albuf->OriginalSize-offset)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid data sub-range %d+%d on buffer %u", + offset, length, buffer); + else if(UNLIKELY((offset%byte_align) != 0)) alSetError(context.get(), AL_INVALID_VALUE, - "Unpacking data with alignment %u does not match original alignment %u", - align, albuf->OriginalAlign); - else if(UNLIKELY(albuf->MappedAccess != 0)) - alSetError(context.get(), AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u", - buffer); + "Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)", + offset, byte_align, align); + else if(UNLIKELY((length%byte_align) != 0)) + alSetError(context.get(), AL_INVALID_VALUE, + "Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)", + length, byte_align, align); else { - num_chans = ChannelsFromFmt(albuf->FmtChannels); - frame_size = num_chans * BytesFromFmt(albuf->FmtType); - if(albuf->OriginalType == UserFmtIMA4) - byte_align = ((align-1)/2 + 4) * num_chans; - else if(albuf->OriginalType == UserFmtMSADPCM) - byte_align = ((align-2)/2 + 7) * num_chans; - else - byte_align = align * frame_size; - - if(UNLIKELY(offset < 0 || length < 0 || offset > albuf->OriginalSize || - length > albuf->OriginalSize-offset)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid data sub-range %d+%d on buffer %u", - offset, length, buffer); - else if(UNLIKELY((offset%byte_align) != 0)) - alSetError(context.get(), AL_INVALID_VALUE, - "Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)", - offset, byte_align, align); - else if(UNLIKELY((length%byte_align) != 0)) - alSetError(context.get(), AL_INVALID_VALUE, - "Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)", - length, byte_align, align); + /* offset -> byte offset, length -> sample count */ + offset = offset/byte_align * align * frame_size; + length = length/byte_align * align; + + void *dst = static_cast(albuf->data) + offset; + if(srctype == UserFmtIMA4 && albuf->FmtType == FmtShort) + Convert_ALshort_ALima4(static_cast(dst), + static_cast(data), num_chans, length, align); + else if(srctype == UserFmtMSADPCM && albuf->FmtType == FmtShort) + Convert_ALshort_ALmsadpcm(static_cast(dst), + static_cast(data), num_chans, length, align); else { - /* offset -> byte offset, length -> sample count */ - offset = offset/byte_align * align * frame_size; - length = length/byte_align * align; - - void *dst = static_cast(albuf->data) + offset; - if(srctype == UserFmtIMA4 && albuf->FmtType == FmtShort) - Convert_ALshort_ALima4(static_cast(dst), - static_cast(data), num_chans, length, align); - else if(srctype == UserFmtMSADPCM && albuf->FmtType == FmtShort) - Convert_ALshort_ALmsadpcm(static_cast(dst), - static_cast(data), num_chans, length, align); - else - { - assert((long)srctype == (long)albuf->FmtType); - memcpy(dst, data, length*frame_size); - } + assert((long)srctype == (long)albuf->FmtType); + memcpy(dst, data, length*frame_size); } } } -- cgit v1.2.3 From 34c836c4906d46f43e7cc8cd88c00b31c05c1b7b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Nov 2018 14:25:05 -0800 Subject: Disambiguate operation order --- OpenAL32/alBuffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index d6a8f6c2..c04b8664 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -260,7 +260,7 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U ALsizei SrcByteAlign{ (SrcType == UserFmtIMA4) ? ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels) : (SrcType == UserFmtMSADPCM) ? ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels) : - align * FrameSizeFromUserFmt(SrcChannels, SrcType) + (align * FrameSizeFromUserFmt(SrcChannels, SrcType)) }; if(UNLIKELY((size%SrcByteAlign) != 0)) SETERR_RETURN(context, AL_INVALID_VALUE,, -- cgit v1.2.3 From 75eeb6ba4bfa42fb922ac61b290102c6b44d7b59 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Nov 2018 20:32:31 -0800 Subject: Convert the WinMM backend to C++ --- Alc/backends/winmm.c | 786 ------------------------------------------------ Alc/backends/winmm.cpp | 793 +++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 794 insertions(+), 787 deletions(-) delete mode 100644 Alc/backends/winmm.c create mode 100644 Alc/backends/winmm.cpp diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c deleted file mode 100644 index 0d4a02b8..00000000 --- a/Alc/backends/winmm.c +++ /dev/null @@ -1,786 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include -#include - -#include "alMain.h" -#include "alu.h" -#include "ringbuffer.h" -#include "threads.h" - -#include "backends/base.h" - -#ifndef WAVE_FORMAT_IEEE_FLOAT -#define WAVE_FORMAT_IEEE_FLOAT 0x0003 -#endif - -#define DEVNAME_HEAD "OpenAL Soft on " - - -static vector_al_string PlaybackDevices; -static vector_al_string CaptureDevices; - -static void clear_devlist(vector_al_string *list) -{ - VECTOR_FOR_EACH(al_string, *list, alstr_reset); - VECTOR_RESIZE(*list, 0, 0); -} - - -static void ProbePlaybackDevices(void) -{ - ALuint numdevs; - ALuint i; - - clear_devlist(&PlaybackDevices); - - numdevs = waveOutGetNumDevs(); - VECTOR_RESIZE(PlaybackDevices, 0, numdevs); - for(i = 0;i < numdevs;i++) - { - WAVEOUTCAPSW WaveCaps; - const al_string *iter; - al_string dname; - - AL_STRING_INIT(dname); - if(waveOutGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR) - { - ALuint count = 0; - while(1) - { - alstr_copy_cstr(&dname, DEVNAME_HEAD); - alstr_append_wcstr(&dname, WaveCaps.szPname); - if(count != 0) - { - char str[64]; - snprintf(str, sizeof(str), " #%d", count+1); - alstr_append_cstr(&dname, str); - } - count++; - -#define MATCH_ENTRY(i) (alstr_cmp(dname, *(i)) == 0) - VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_ENTRY); - if(iter == VECTOR_END(PlaybackDevices)) break; -#undef MATCH_ENTRY - } - - TRACE("Got device \"%s\", ID %u\n", alstr_get_cstr(dname), i); - } - VECTOR_PUSH_BACK(PlaybackDevices, dname); - } -} - -static void ProbeCaptureDevices(void) -{ - ALuint numdevs; - ALuint i; - - clear_devlist(&CaptureDevices); - - numdevs = waveInGetNumDevs(); - VECTOR_RESIZE(CaptureDevices, 0, numdevs); - for(i = 0;i < numdevs;i++) - { - WAVEINCAPSW WaveCaps; - const al_string *iter; - al_string dname; - - AL_STRING_INIT(dname); - if(waveInGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR) - { - ALuint count = 0; - while(1) - { - alstr_copy_cstr(&dname, DEVNAME_HEAD); - alstr_append_wcstr(&dname, WaveCaps.szPname); - if(count != 0) - { - char str[64]; - snprintf(str, sizeof(str), " #%d", count+1); - alstr_append_cstr(&dname, str); - } - count++; - -#define MATCH_ENTRY(i) (alstr_cmp(dname, *(i)) == 0) - VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_ENTRY); - if(iter == VECTOR_END(CaptureDevices)) break; -#undef MATCH_ENTRY - } - - TRACE("Got device \"%s\", ID %u\n", alstr_get_cstr(dname), i); - } - VECTOR_PUSH_BACK(CaptureDevices, dname); - } -} - - -typedef struct ALCwinmmPlayback { - DERIVE_FROM_TYPE(ALCbackend); - - RefCount WaveBuffersCommitted; - WAVEHDR WaveBuffer[4]; - - HWAVEOUT OutHdl; - - WAVEFORMATEX Format; - - ATOMIC(ALenum) killNow; - althrd_t thread; -} ALCwinmmPlayback; - -static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device); -static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self); - -static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); -static int ALCwinmmPlayback_mixerProc(void *arg); - -static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *name); -static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self); -static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self); -static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self); -static DECLARE_FORWARD2(ALCwinmmPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCwinmmPlayback) - -DEFINE_ALCBACKEND_VTABLE(ALCwinmmPlayback); - - -static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCwinmmPlayback, ALCbackend, self); - - InitRef(&self->WaveBuffersCommitted, 0); - self->OutHdl = NULL; - - ATOMIC_INIT(&self->killNow, AL_TRUE); -} - -static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self) -{ - if(self->OutHdl) - waveOutClose(self->OutHdl); - self->OutHdl = 0; - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -/* ALCwinmmPlayback_waveOutProc - * - * Posts a message to 'ALCwinmmPlayback_mixerProc' everytime a WaveOut Buffer - * is completed and returns to the application (for more data) - */ -static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2)) -{ - ALCwinmmPlayback *self = (ALCwinmmPlayback*)instance; - - if(msg != WOM_DONE) - return; - - DecrementRef(&self->WaveBuffersCommitted); - PostThreadMessage(self->thread, msg, 0, param1); -} - -FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(void *arg) -{ - ALCwinmmPlayback *self = arg; - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - WAVEHDR *WaveHdr; - MSG msg; - - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - while(GetMessage(&msg, NULL, 0, 0)) - { - if(msg.message != WOM_DONE) - continue; - - if(ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) - { - if(ReadRef(&self->WaveBuffersCommitted) == 0) - break; - continue; - } - - WaveHdr = ((WAVEHDR*)msg.lParam); - ALCwinmmPlayback_lock(self); - aluMixData(device, WaveHdr->lpData, WaveHdr->dwBufferLength / - self->Format.nBlockAlign); - ALCwinmmPlayback_unlock(self); - - // Send buffer back to play more data - waveOutWrite(self->OutHdl, WaveHdr, sizeof(WAVEHDR)); - IncrementRef(&self->WaveBuffersCommitted); - } - - return 0; -} - - -static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *deviceName) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - const al_string *iter; - UINT DeviceID; - MMRESULT res; - - if(VECTOR_SIZE(PlaybackDevices) == 0) - ProbePlaybackDevices(); - - // Find the Device ID matching the deviceName if valid -#define MATCH_DEVNAME(iter) (!alstr_empty(*(iter)) && \ - (!deviceName || alstr_cmp_cstr(*(iter), deviceName) == 0)) - VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_DEVNAME); - if(iter == VECTOR_END(PlaybackDevices)) - return ALC_INVALID_VALUE; -#undef MATCH_DEVNAME - - DeviceID = (UINT)(iter - VECTOR_BEGIN(PlaybackDevices)); - -retry_open: - memset(&self->Format, 0, sizeof(WAVEFORMATEX)); - if(device->FmtType == DevFmtFloat) - { - self->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; - self->Format.wBitsPerSample = 32; - } - else - { - self->Format.wFormatTag = WAVE_FORMAT_PCM; - if(device->FmtType == DevFmtUByte || device->FmtType == DevFmtByte) - self->Format.wBitsPerSample = 8; - else - self->Format.wBitsPerSample = 16; - } - self->Format.nChannels = ((device->FmtChans == DevFmtMono) ? 1 : 2); - self->Format.nBlockAlign = self->Format.wBitsPerSample * - self->Format.nChannels / 8; - self->Format.nSamplesPerSec = device->Frequency; - self->Format.nAvgBytesPerSec = self->Format.nSamplesPerSec * - self->Format.nBlockAlign; - self->Format.cbSize = 0; - - if((res=waveOutOpen(&self->OutHdl, DeviceID, &self->Format, (DWORD_PTR)&ALCwinmmPlayback_waveOutProc, (DWORD_PTR)self, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) - { - if(device->FmtType == DevFmtFloat) - { - device->FmtType = DevFmtShort; - goto retry_open; - } - ERR("waveOutOpen failed: %u\n", res); - goto failure; - } - - alstr_copy(&device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID)); - return ALC_NO_ERROR; - -failure: - if(self->OutHdl) - waveOutClose(self->OutHdl); - self->OutHdl = NULL; - - return ALC_INVALID_VALUE; -} - -static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - - device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize * - self->Format.nSamplesPerSec / - device->Frequency); - device->UpdateSize = (device->UpdateSize*device->NumUpdates + 3) / 4; - device->NumUpdates = 4; - device->Frequency = self->Format.nSamplesPerSec; - - if(self->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) - { - if(self->Format.wBitsPerSample == 32) - device->FmtType = DevFmtFloat; - else - { - ERR("Unhandled IEEE float sample depth: %d\n", self->Format.wBitsPerSample); - return ALC_FALSE; - } - } - else if(self->Format.wFormatTag == WAVE_FORMAT_PCM) - { - if(self->Format.wBitsPerSample == 16) - device->FmtType = DevFmtShort; - else if(self->Format.wBitsPerSample == 8) - device->FmtType = DevFmtUByte; - else - { - ERR("Unhandled PCM sample depth: %d\n", self->Format.wBitsPerSample); - return ALC_FALSE; - } - } - else - { - ERR("Unhandled format tag: 0x%04x\n", self->Format.wFormatTag); - return ALC_FALSE; - } - - if(self->Format.nChannels == 2) - device->FmtChans = DevFmtStereo; - else if(self->Format.nChannels == 1) - device->FmtChans = DevFmtMono; - else - { - ERR("Unhandled channel count: %d\n", self->Format.nChannels); - return ALC_FALSE; - } - SetDefaultWFXChannelOrder(device); - - return ALC_TRUE; -} - -static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ALbyte *BufferData; - ALint BufferSize; - ALuint i; - - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); - if(althrd_create(&self->thread, ALCwinmmPlayback_mixerProc, self) != althrd_success) - return ALC_FALSE; - - InitRef(&self->WaveBuffersCommitted, 0); - - // Create 4 Buffers - BufferSize = device->UpdateSize*device->NumUpdates / 4; - BufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - - BufferData = calloc(4, BufferSize); - for(i = 0;i < 4;i++) - { - memset(&self->WaveBuffer[i], 0, sizeof(WAVEHDR)); - self->WaveBuffer[i].dwBufferLength = BufferSize; - self->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData : - (self->WaveBuffer[i-1].lpData + - self->WaveBuffer[i-1].dwBufferLength)); - waveOutPrepareHeader(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); - waveOutWrite(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); - IncrementRef(&self->WaveBuffersCommitted); - } - - return ALC_TRUE; -} - -static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self) -{ - void *buffer = NULL; - int i; - - if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) - return; - althrd_join(self->thread, &i); - - // Release the wave buffers - for(i = 0;i < 4;i++) - { - waveOutUnprepareHeader(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); - if(i == 0) buffer = self->WaveBuffer[i].lpData; - self->WaveBuffer[i].lpData = NULL; - } - free(buffer); -} - - - -typedef struct ALCwinmmCapture { - DERIVE_FROM_TYPE(ALCbackend); - - RefCount WaveBuffersCommitted; - WAVEHDR WaveBuffer[4]; - - HWAVEIN InHdl; - - ll_ringbuffer_t *Ring; - - WAVEFORMATEX Format; - - ATOMIC(ALenum) killNow; - althrd_t thread; -} ALCwinmmCapture; - -static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device); -static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self); - -static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); -static int ALCwinmmCapture_captureProc(void *arg); - -static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name); -static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ALCboolean, reset) -static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self); -static void ALCwinmmCapture_stop(ALCwinmmCapture *self); -static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples); -static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self); -static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCwinmmCapture) - -DEFINE_ALCBACKEND_VTABLE(ALCwinmmCapture); - - -static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCwinmmCapture, ALCbackend, self); - - InitRef(&self->WaveBuffersCommitted, 0); - self->InHdl = NULL; - - ATOMIC_INIT(&self->killNow, AL_TRUE); -} - -static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self) -{ - void *buffer = NULL; - int i; - - /* Tell the processing thread to quit and wait for it to do so. */ - if(!ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) - { - PostThreadMessage(self->thread, WM_QUIT, 0, 0); - - althrd_join(self->thread, &i); - - /* Make sure capture is stopped and all pending buffers are flushed. */ - waveInReset(self->InHdl); - - // Release the wave buffers - for(i = 0;i < 4;i++) - { - waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); - if(i == 0) buffer = self->WaveBuffer[i].lpData; - self->WaveBuffer[i].lpData = NULL; - } - free(buffer); - } - - ll_ringbuffer_free(self->Ring); - self->Ring = NULL; - - // Close the Wave device - if(self->InHdl) - waveInClose(self->InHdl); - self->InHdl = 0; - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -/* ALCwinmmCapture_waveInProc - * - * Posts a message to 'ALCwinmmCapture_captureProc' everytime a WaveIn Buffer - * is completed and returns to the application (with more data). - */ -static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2)) -{ - ALCwinmmCapture *self = (ALCwinmmCapture*)instance; - - if(msg != WIM_DATA) - return; - - DecrementRef(&self->WaveBuffersCommitted); - PostThreadMessage(self->thread, msg, 0, param1); -} - -static int ALCwinmmCapture_captureProc(void *arg) -{ - ALCwinmmCapture *self = arg; - WAVEHDR *WaveHdr; - MSG msg; - - althrd_setname(althrd_current(), RECORD_THREAD_NAME); - - while(GetMessage(&msg, NULL, 0, 0)) - { - if(msg.message != WIM_DATA) - continue; - /* Don't wait for other buffers to finish before quitting. We're - * closing so we don't need them. */ - if(ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) - break; - - WaveHdr = ((WAVEHDR*)msg.lParam); - ll_ringbuffer_write(self->Ring, WaveHdr->lpData, - WaveHdr->dwBytesRecorded / self->Format.nBlockAlign - ); - - // Send buffer back to capture more data - waveInAddBuffer(self->InHdl, WaveHdr, sizeof(WAVEHDR)); - IncrementRef(&self->WaveBuffersCommitted); - } - - return 0; -} - - -static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - const al_string *iter; - ALbyte *BufferData = NULL; - DWORD CapturedDataSize; - ALint BufferSize; - UINT DeviceID; - MMRESULT res; - ALuint i; - - if(VECTOR_SIZE(CaptureDevices) == 0) - ProbeCaptureDevices(); - - // Find the Device ID matching the deviceName if valid -#define MATCH_DEVNAME(iter) (!alstr_empty(*(iter)) && (!name || alstr_cmp_cstr(*iter, name) == 0)) - VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_DEVNAME); - if(iter == VECTOR_END(CaptureDevices)) - return ALC_INVALID_VALUE; -#undef MATCH_DEVNAME - - DeviceID = (UINT)(iter - VECTOR_BEGIN(CaptureDevices)); - - switch(device->FmtChans) - { - case DevFmtMono: - case DevFmtStereo: - break; - - case DevFmtQuad: - case DevFmtX51: - case DevFmtX51Rear: - case DevFmtX61: - case DevFmtX71: - case DevFmtAmbi3D: - return ALC_INVALID_ENUM; - } - - switch(device->FmtType) - { - case DevFmtUByte: - case DevFmtShort: - case DevFmtInt: - case DevFmtFloat: - break; - - case DevFmtByte: - case DevFmtUShort: - case DevFmtUInt: - return ALC_INVALID_ENUM; - } - - memset(&self->Format, 0, sizeof(WAVEFORMATEX)); - self->Format.wFormatTag = ((device->FmtType == DevFmtFloat) ? - WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM); - self->Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - self->Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; - self->Format.nBlockAlign = self->Format.wBitsPerSample * - self->Format.nChannels / 8; - self->Format.nSamplesPerSec = device->Frequency; - self->Format.nAvgBytesPerSec = self->Format.nSamplesPerSec * - self->Format.nBlockAlign; - self->Format.cbSize = 0; - - if((res=waveInOpen(&self->InHdl, DeviceID, &self->Format, (DWORD_PTR)&ALCwinmmCapture_waveInProc, (DWORD_PTR)self, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) - { - ERR("waveInOpen failed: %u\n", res); - goto failure; - } - - // Allocate circular memory buffer for the captured audio - CapturedDataSize = device->UpdateSize*device->NumUpdates; - - // Make sure circular buffer is at least 100ms in size - if(CapturedDataSize < (self->Format.nSamplesPerSec / 10)) - CapturedDataSize = self->Format.nSamplesPerSec / 10; - - self->Ring = ll_ringbuffer_create(CapturedDataSize, self->Format.nBlockAlign, false); - if(!self->Ring) goto failure; - - InitRef(&self->WaveBuffersCommitted, 0); - - // Create 4 Buffers of 50ms each - BufferSize = self->Format.nAvgBytesPerSec / 20; - BufferSize -= (BufferSize % self->Format.nBlockAlign); - - BufferData = calloc(4, BufferSize); - if(!BufferData) goto failure; - - for(i = 0;i < 4;i++) - { - memset(&self->WaveBuffer[i], 0, sizeof(WAVEHDR)); - self->WaveBuffer[i].dwBufferLength = BufferSize; - self->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData : - (self->WaveBuffer[i-1].lpData + - self->WaveBuffer[i-1].dwBufferLength)); - self->WaveBuffer[i].dwFlags = 0; - self->WaveBuffer[i].dwLoops = 0; - waveInPrepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); - waveInAddBuffer(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); - IncrementRef(&self->WaveBuffersCommitted); - } - - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); - if(althrd_create(&self->thread, ALCwinmmCapture_captureProc, self) != althrd_success) - goto failure; - - alstr_copy(&device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID)); - return ALC_NO_ERROR; - -failure: - if(BufferData) - { - for(i = 0;i < 4;i++) - waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); - free(BufferData); - } - - ll_ringbuffer_free(self->Ring); - self->Ring = NULL; - - if(self->InHdl) - waveInClose(self->InHdl); - self->InHdl = NULL; - - return ALC_INVALID_VALUE; -} - -static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self) -{ - waveInStart(self->InHdl); - return ALC_TRUE; -} - -static void ALCwinmmCapture_stop(ALCwinmmCapture *self) -{ - waveInStop(self->InHdl); -} - -static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples) -{ - ll_ringbuffer_read(self->Ring, buffer, samples); - return ALC_NO_ERROR; -} - -static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self) -{ - return (ALCuint)ll_ringbuffer_read_space(self->Ring); -} - - -typedef struct ALCwinmmBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCwinmmBackendFactory; -#define ALCWINMMBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwinmmBackendFactory, ALCbackendFactory) } } - -static ALCboolean ALCwinmmBackendFactory_init(ALCwinmmBackendFactory *self); -static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory *self); -static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory *self, ALCbackend_Type type); -static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory *self, enum DevProbe type, al_string *outnames); -static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory *self, ALCdevice *device, ALCbackend_Type type); - -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwinmmBackendFactory); - - -static ALCboolean ALCwinmmBackendFactory_init(ALCwinmmBackendFactory* UNUSED(self)) -{ - VECTOR_INIT(PlaybackDevices); - VECTOR_INIT(CaptureDevices); - - return ALC_TRUE; -} - -static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory* UNUSED(self)) -{ - clear_devlist(&PlaybackDevices); - VECTOR_DEINIT(PlaybackDevices); - - clear_devlist(&CaptureDevices); - VECTOR_DEINIT(CaptureDevices); -} - -static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} - -static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) -{ - switch(type) - { -#define APPEND_OUTNAME(n) do { \ - if(!alstr_empty(*(n))) \ - alstr_append_range(outnames, VECTOR_BEGIN(*(n)), VECTOR_END(*(n))+1); \ -} while(0) - case ALL_DEVICE_PROBE: - ProbePlaybackDevices(); - VECTOR_FOR_EACH(const al_string, PlaybackDevices, APPEND_OUTNAME); - break; - - case CAPTURE_DEVICE_PROBE: - ProbeCaptureDevices(); - VECTOR_FOR_EACH(const al_string, CaptureDevices, APPEND_OUTNAME); - break; -#undef APPEND_OUTNAME - } -} - -static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - { - ALCwinmmPlayback *backend; - NEW_OBJ(backend, ALCwinmmPlayback)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - if(type == ALCbackend_Capture) - { - ALCwinmmCapture *backend; - NEW_OBJ(backend, ALCwinmmCapture)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} - -ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void) -{ - static ALCwinmmBackendFactory factory = ALCWINMMBACKENDFACTORY_INITIALIZER; - return STATIC_CAST(ALCbackendFactory, &factory); -} diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp new file mode 100644 index 00000000..c32298a9 --- /dev/null +++ b/Alc/backends/winmm.cpp @@ -0,0 +1,793 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include +#include + +#include "alMain.h" +#include "alu.h" +#include "ringbuffer.h" +#include "threads.h" + +#include "backends/base.h" + +namespace { + +#ifndef WAVE_FORMAT_IEEE_FLOAT +#define WAVE_FORMAT_IEEE_FLOAT 0x0003 +#endif + +#define DEVNAME_HEAD "OpenAL Soft on " + + +vector_al_string PlaybackDevices; +vector_al_string CaptureDevices; + +void clear_devlist(vector_al_string *list) +{ + VECTOR_FOR_EACH(al_string, *list, alstr_reset); + VECTOR_RESIZE(*list, 0, 0); +} + + +void ProbePlaybackDevices(void) +{ + ALuint numdevs; + ALuint i; + + clear_devlist(&PlaybackDevices); + + numdevs = waveOutGetNumDevs(); + VECTOR_RESIZE(PlaybackDevices, 0, numdevs); + for(i = 0;i < numdevs;i++) + { + WAVEOUTCAPSW WaveCaps; + const al_string *iter; + al_string dname; + + AL_STRING_INIT(dname); + if(waveOutGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR) + { + ALuint count = 0; + while(1) + { + alstr_copy_cstr(&dname, DEVNAME_HEAD); + alstr_append_wcstr(&dname, WaveCaps.szPname); + if(count != 0) + { + char str[64]; + snprintf(str, sizeof(str), " #%d", count+1); + alstr_append_cstr(&dname, str); + } + count++; + +#define MATCH_ENTRY(i) (alstr_cmp(dname, *(i)) == 0) + VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_ENTRY); + if(iter == VECTOR_END(PlaybackDevices)) break; +#undef MATCH_ENTRY + } + + TRACE("Got device \"%s\", ID %u\n", alstr_get_cstr(dname), i); + } + VECTOR_PUSH_BACK(PlaybackDevices, dname); + } +} + +void ProbeCaptureDevices(void) +{ + ALuint numdevs; + ALuint i; + + clear_devlist(&CaptureDevices); + + numdevs = waveInGetNumDevs(); + VECTOR_RESIZE(CaptureDevices, 0, numdevs); + for(i = 0;i < numdevs;i++) + { + WAVEINCAPSW WaveCaps; + const al_string *iter; + al_string dname; + + AL_STRING_INIT(dname); + if(waveInGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR) + { + ALuint count = 0; + while(1) + { + alstr_copy_cstr(&dname, DEVNAME_HEAD); + alstr_append_wcstr(&dname, WaveCaps.szPname); + if(count != 0) + { + char str[64]; + snprintf(str, sizeof(str), " #%d", count+1); + alstr_append_cstr(&dname, str); + } + count++; + +#define MATCH_ENTRY(i) (alstr_cmp(dname, *(i)) == 0) + VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_ENTRY); + if(iter == VECTOR_END(CaptureDevices)) break; +#undef MATCH_ENTRY + } + + TRACE("Got device \"%s\", ID %u\n", alstr_get_cstr(dname), i); + } + VECTOR_PUSH_BACK(CaptureDevices, dname); + } +} + +} // namespace + +struct ALCwinmmPlayback final : public ALCbackend { + RefCount WaveBuffersCommitted; + WAVEHDR WaveBuffer[4]; + + HWAVEOUT OutHdl; + + WAVEFORMATEX Format; + + ATOMIC(ALenum) killNow; + althrd_t thread; +}; + +static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device); +static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self); + +static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); +static int ALCwinmmPlayback_mixerProc(void *arg); + +static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *name); +static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self); +static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self); +static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self); +static DECLARE_FORWARD2(ALCwinmmPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) +static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCwinmmPlayback) + +DEFINE_ALCBACKEND_VTABLE(ALCwinmmPlayback); + + +static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device) +{ + new (self) ALCwinmmPlayback{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCwinmmPlayback, ALCbackend, self); + + InitRef(&self->WaveBuffersCommitted, 0); + self->OutHdl = NULL; + + ATOMIC_INIT(&self->killNow, AL_TRUE); +} + +static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self) +{ + if(self->OutHdl) + waveOutClose(self->OutHdl); + self->OutHdl = 0; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCwinmmPlayback(); +} + + +/* ALCwinmmPlayback_waveOutProc + * + * Posts a message to 'ALCwinmmPlayback_mixerProc' everytime a WaveOut Buffer + * is completed and returns to the application (for more data) + */ +static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2)) +{ + ALCwinmmPlayback *self = (ALCwinmmPlayback*)instance; + + if(msg != WOM_DONE) + return; + + DecrementRef(&self->WaveBuffersCommitted); + PostThreadMessage(self->thread, msg, 0, param1); +} + +FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(void *arg) +{ + auto self = static_cast(arg); + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + WAVEHDR *WaveHdr; + MSG msg; + + SetRTPriority(); + althrd_setname(althrd_current(), MIXER_THREAD_NAME); + + while(GetMessage(&msg, NULL, 0, 0)) + { + if(msg.message != WOM_DONE) + continue; + + if(ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) + { + if(ReadRef(&self->WaveBuffersCommitted) == 0) + break; + continue; + } + + WaveHdr = ((WAVEHDR*)msg.lParam); + ALCwinmmPlayback_lock(self); + aluMixData(device, WaveHdr->lpData, WaveHdr->dwBufferLength / + self->Format.nBlockAlign); + ALCwinmmPlayback_unlock(self); + + // Send buffer back to play more data + waveOutWrite(self->OutHdl, WaveHdr, sizeof(WAVEHDR)); + IncrementRef(&self->WaveBuffersCommitted); + } + + return 0; +} + + +static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *deviceName) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + const al_string *iter; + UINT DeviceID; + MMRESULT res; + + if(VECTOR_SIZE(PlaybackDevices) == 0) + ProbePlaybackDevices(); + + // Find the Device ID matching the deviceName if valid +#define MATCH_DEVNAME(iter) (!alstr_empty(*(iter)) && \ + (!deviceName || alstr_cmp_cstr(*(iter), deviceName) == 0)) + VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_DEVNAME); + if(iter == VECTOR_END(PlaybackDevices)) + return ALC_INVALID_VALUE; +#undef MATCH_DEVNAME + + DeviceID = (UINT)(iter - VECTOR_BEGIN(PlaybackDevices)); + +retry_open: + memset(&self->Format, 0, sizeof(WAVEFORMATEX)); + if(device->FmtType == DevFmtFloat) + { + self->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + self->Format.wBitsPerSample = 32; + } + else + { + self->Format.wFormatTag = WAVE_FORMAT_PCM; + if(device->FmtType == DevFmtUByte || device->FmtType == DevFmtByte) + self->Format.wBitsPerSample = 8; + else + self->Format.wBitsPerSample = 16; + } + self->Format.nChannels = ((device->FmtChans == DevFmtMono) ? 1 : 2); + self->Format.nBlockAlign = self->Format.wBitsPerSample * + self->Format.nChannels / 8; + self->Format.nSamplesPerSec = device->Frequency; + self->Format.nAvgBytesPerSec = self->Format.nSamplesPerSec * + self->Format.nBlockAlign; + self->Format.cbSize = 0; + + if((res=waveOutOpen(&self->OutHdl, DeviceID, &self->Format, (DWORD_PTR)&ALCwinmmPlayback_waveOutProc, (DWORD_PTR)self, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) + { + if(device->FmtType == DevFmtFloat) + { + device->FmtType = DevFmtShort; + goto retry_open; + } + ERR("waveOutOpen failed: %u\n", res); + goto failure; + } + + alstr_copy(&device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID)); + return ALC_NO_ERROR; + +failure: + if(self->OutHdl) + waveOutClose(self->OutHdl); + self->OutHdl = NULL; + + return ALC_INVALID_VALUE; +} + +static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + + device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize * + self->Format.nSamplesPerSec / + device->Frequency); + device->UpdateSize = (device->UpdateSize*device->NumUpdates + 3) / 4; + device->NumUpdates = 4; + device->Frequency = self->Format.nSamplesPerSec; + + if(self->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) + { + if(self->Format.wBitsPerSample == 32) + device->FmtType = DevFmtFloat; + else + { + ERR("Unhandled IEEE float sample depth: %d\n", self->Format.wBitsPerSample); + return ALC_FALSE; + } + } + else if(self->Format.wFormatTag == WAVE_FORMAT_PCM) + { + if(self->Format.wBitsPerSample == 16) + device->FmtType = DevFmtShort; + else if(self->Format.wBitsPerSample == 8) + device->FmtType = DevFmtUByte; + else + { + ERR("Unhandled PCM sample depth: %d\n", self->Format.wBitsPerSample); + return ALC_FALSE; + } + } + else + { + ERR("Unhandled format tag: 0x%04x\n", self->Format.wFormatTag); + return ALC_FALSE; + } + + if(self->Format.nChannels == 2) + device->FmtChans = DevFmtStereo; + else if(self->Format.nChannels == 1) + device->FmtChans = DevFmtMono; + else + { + ERR("Unhandled channel count: %d\n", self->Format.nChannels); + return ALC_FALSE; + } + SetDefaultWFXChannelOrder(device); + + return ALC_TRUE; +} + +static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALbyte *BufferData; + ALint BufferSize; + ALuint i; + + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); + if(althrd_create(&self->thread, ALCwinmmPlayback_mixerProc, self) != althrd_success) + return ALC_FALSE; + + InitRef(&self->WaveBuffersCommitted, 0); + + // Create 4 Buffers + BufferSize = device->UpdateSize*device->NumUpdates / 4; + BufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + + BufferData = static_cast(calloc(4, BufferSize)); + for(i = 0;i < 4;i++) + { + memset(&self->WaveBuffer[i], 0, sizeof(WAVEHDR)); + self->WaveBuffer[i].dwBufferLength = BufferSize; + self->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData : + (self->WaveBuffer[i-1].lpData + + self->WaveBuffer[i-1].dwBufferLength)); + waveOutPrepareHeader(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + waveOutWrite(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + IncrementRef(&self->WaveBuffersCommitted); + } + + return ALC_TRUE; +} + +static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self) +{ + void *buffer = NULL; + int i; + + if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) + return; + althrd_join(self->thread, &i); + + // Release the wave buffers + for(i = 0;i < 4;i++) + { + waveOutUnprepareHeader(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + if(i == 0) buffer = self->WaveBuffer[i].lpData; + self->WaveBuffer[i].lpData = NULL; + } + free(buffer); +} + + + +struct ALCwinmmCapture final : public ALCbackend { + RefCount WaveBuffersCommitted; + WAVEHDR WaveBuffer[4]; + + HWAVEIN InHdl; + + ll_ringbuffer_t *Ring; + + WAVEFORMATEX Format; + + ATOMIC(ALenum) killNow; + althrd_t thread; +}; + +static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device); +static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self); + +static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); +static int ALCwinmmCapture_captureProc(void *arg); + +static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name); +static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ALCboolean, reset) +static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self); +static void ALCwinmmCapture_stop(ALCwinmmCapture *self); +static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples); +static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self); +static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCwinmmCapture) + +DEFINE_ALCBACKEND_VTABLE(ALCwinmmCapture); + + +static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device) +{ + new (self) ALCwinmmCapture{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCwinmmCapture, ALCbackend, self); + + InitRef(&self->WaveBuffersCommitted, 0); + self->InHdl = NULL; + + ATOMIC_INIT(&self->killNow, AL_TRUE); +} + +static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self) +{ + void *buffer = NULL; + int i; + + /* Tell the processing thread to quit and wait for it to do so. */ + if(!ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) + { + PostThreadMessage(self->thread, WM_QUIT, 0, 0); + + althrd_join(self->thread, &i); + + /* Make sure capture is stopped and all pending buffers are flushed. */ + waveInReset(self->InHdl); + + // Release the wave buffers + for(i = 0;i < 4;i++) + { + waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + if(i == 0) buffer = self->WaveBuffer[i].lpData; + self->WaveBuffer[i].lpData = NULL; + } + free(buffer); + } + + ll_ringbuffer_free(self->Ring); + self->Ring = NULL; + + // Close the Wave device + if(self->InHdl) + waveInClose(self->InHdl); + self->InHdl = 0; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCwinmmCapture(); +} + + +/* ALCwinmmCapture_waveInProc + * + * Posts a message to 'ALCwinmmCapture_captureProc' everytime a WaveIn Buffer + * is completed and returns to the application (with more data). + */ +static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2)) +{ + ALCwinmmCapture *self = (ALCwinmmCapture*)instance; + + if(msg != WIM_DATA) + return; + + DecrementRef(&self->WaveBuffersCommitted); + PostThreadMessage(self->thread, msg, 0, param1); +} + +static int ALCwinmmCapture_captureProc(void *arg) +{ + auto self = static_cast(arg); + WAVEHDR *WaveHdr; + MSG msg; + + althrd_setname(althrd_current(), RECORD_THREAD_NAME); + + while(GetMessage(&msg, NULL, 0, 0)) + { + if(msg.message != WIM_DATA) + continue; + /* Don't wait for other buffers to finish before quitting. We're + * closing so we don't need them. */ + if(ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) + break; + + WaveHdr = ((WAVEHDR*)msg.lParam); + ll_ringbuffer_write(self->Ring, WaveHdr->lpData, + WaveHdr->dwBytesRecorded / self->Format.nBlockAlign + ); + + // Send buffer back to capture more data + waveInAddBuffer(self->InHdl, WaveHdr, sizeof(WAVEHDR)); + IncrementRef(&self->WaveBuffersCommitted); + } + + return 0; +} + + +static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + const al_string *iter; + ALbyte *BufferData = NULL; + DWORD CapturedDataSize; + ALint BufferSize; + UINT DeviceID; + MMRESULT res; + ALuint i; + + if(VECTOR_SIZE(CaptureDevices) == 0) + ProbeCaptureDevices(); + + // Find the Device ID matching the deviceName if valid +#define MATCH_DEVNAME(iter) (!alstr_empty(*(iter)) && (!name || alstr_cmp_cstr(*iter, name) == 0)) + VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_DEVNAME); + if(iter == VECTOR_END(CaptureDevices)) + return ALC_INVALID_VALUE; +#undef MATCH_DEVNAME + + DeviceID = (UINT)(iter - VECTOR_BEGIN(CaptureDevices)); + + switch(device->FmtChans) + { + case DevFmtMono: + case DevFmtStereo: + break; + + case DevFmtQuad: + case DevFmtX51: + case DevFmtX51Rear: + case DevFmtX61: + case DevFmtX71: + case DevFmtAmbi3D: + return ALC_INVALID_ENUM; + } + + switch(device->FmtType) + { + case DevFmtUByte: + case DevFmtShort: + case DevFmtInt: + case DevFmtFloat: + break; + + case DevFmtByte: + case DevFmtUShort: + case DevFmtUInt: + return ALC_INVALID_ENUM; + } + + memset(&self->Format, 0, sizeof(WAVEFORMATEX)); + self->Format.wFormatTag = ((device->FmtType == DevFmtFloat) ? + WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM); + self->Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + self->Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + self->Format.nBlockAlign = self->Format.wBitsPerSample * + self->Format.nChannels / 8; + self->Format.nSamplesPerSec = device->Frequency; + self->Format.nAvgBytesPerSec = self->Format.nSamplesPerSec * + self->Format.nBlockAlign; + self->Format.cbSize = 0; + + if((res=waveInOpen(&self->InHdl, DeviceID, &self->Format, (DWORD_PTR)&ALCwinmmCapture_waveInProc, (DWORD_PTR)self, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) + { + ERR("waveInOpen failed: %u\n", res); + goto failure; + } + + // Allocate circular memory buffer for the captured audio + CapturedDataSize = device->UpdateSize*device->NumUpdates; + + // Make sure circular buffer is at least 100ms in size + if(CapturedDataSize < (self->Format.nSamplesPerSec / 10)) + CapturedDataSize = self->Format.nSamplesPerSec / 10; + + self->Ring = ll_ringbuffer_create(CapturedDataSize, self->Format.nBlockAlign, false); + if(!self->Ring) goto failure; + + InitRef(&self->WaveBuffersCommitted, 0); + + // Create 4 Buffers of 50ms each + BufferSize = self->Format.nAvgBytesPerSec / 20; + BufferSize -= (BufferSize % self->Format.nBlockAlign); + + BufferData = static_cast(calloc(4, BufferSize)); + if(!BufferData) goto failure; + + for(i = 0;i < 4;i++) + { + memset(&self->WaveBuffer[i], 0, sizeof(WAVEHDR)); + self->WaveBuffer[i].dwBufferLength = BufferSize; + self->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData : + (self->WaveBuffer[i-1].lpData + + self->WaveBuffer[i-1].dwBufferLength)); + self->WaveBuffer[i].dwFlags = 0; + self->WaveBuffer[i].dwLoops = 0; + waveInPrepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + waveInAddBuffer(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + IncrementRef(&self->WaveBuffersCommitted); + } + + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); + if(althrd_create(&self->thread, ALCwinmmCapture_captureProc, self) != althrd_success) + goto failure; + + alstr_copy(&device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID)); + return ALC_NO_ERROR; + +failure: + if(BufferData) + { + for(i = 0;i < 4;i++) + waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + free(BufferData); + } + + ll_ringbuffer_free(self->Ring); + self->Ring = NULL; + + if(self->InHdl) + waveInClose(self->InHdl); + self->InHdl = NULL; + + return ALC_INVALID_VALUE; +} + +static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self) +{ + waveInStart(self->InHdl); + return ALC_TRUE; +} + +static void ALCwinmmCapture_stop(ALCwinmmCapture *self) +{ + waveInStop(self->InHdl); +} + +static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples) +{ + ll_ringbuffer_read(self->Ring, static_cast(buffer), samples); + return ALC_NO_ERROR; +} + +static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self) +{ + return (ALCuint)ll_ringbuffer_read_space(self->Ring); +} + + +struct ALCwinmmBackendFactory final : public ALCbackendFactory { + ALCwinmmBackendFactory() noexcept; +}; +#define ALCWINMMBACKENDFACTORY_INITIALIZER GET_VTABLE2(ALCwinmmBackendFactory, ALCbackendFactory) + +static ALCboolean ALCwinmmBackendFactory_init(ALCwinmmBackendFactory *self); +static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory *self); +static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory *self, ALCbackend_Type type); +static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory *self, enum DevProbe type, al_string *outnames); +static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory *self, ALCdevice *device, ALCbackend_Type type); + +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwinmmBackendFactory); + +ALCwinmmBackendFactory::ALCwinmmBackendFactory() noexcept + : ALCbackendFactory{ALCWINMMBACKENDFACTORY_INITIALIZER} +{ } + + +static ALCboolean ALCwinmmBackendFactory_init(ALCwinmmBackendFactory* UNUSED(self)) +{ + VECTOR_INIT(PlaybackDevices); + VECTOR_INIT(CaptureDevices); + + return ALC_TRUE; +} + +static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory* UNUSED(self)) +{ + clear_devlist(&PlaybackDevices); + VECTOR_DEINIT(PlaybackDevices); + + clear_devlist(&CaptureDevices); + VECTOR_DEINIT(CaptureDevices); +} + +static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Playback || type == ALCbackend_Capture) + return ALC_TRUE; + return ALC_FALSE; +} + +static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +{ + switch(type) + { +#define APPEND_OUTNAME(n) do { \ + if(!alstr_empty(*(n))) \ + alstr_append_range(outnames, VECTOR_BEGIN(*(n)), VECTOR_END(*(n))+1); \ +} while(0) + case ALL_DEVICE_PROBE: + ProbePlaybackDevices(); + VECTOR_FOR_EACH(const al_string, PlaybackDevices, APPEND_OUTNAME); + break; + + case CAPTURE_DEVICE_PROBE: + ProbeCaptureDevices(); + VECTOR_FOR_EACH(const al_string, CaptureDevices, APPEND_OUTNAME); + break; +#undef APPEND_OUTNAME + } +} + +static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCwinmmPlayback *backend; + NEW_OBJ(backend, ALCwinmmPlayback)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + if(type == ALCbackend_Capture) + { + ALCwinmmCapture *backend; + NEW_OBJ(backend, ALCwinmmCapture)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + + return NULL; +} + +ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void) +{ + static ALCwinmmBackendFactory factory{}; + return STATIC_CAST(ALCbackendFactory, &factory); +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 3bf84f27..e59b93c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1138,7 +1138,7 @@ IF(HAVE_WINDOWS_H) IF(ALSOFT_BACKEND_WINMM) SET(HAVE_WINMM 1) SET(BACKENDS "${BACKENDS} WinMM,") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/winmm.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/winmm.cpp) SET(EXTRA_LIBS winmm ${EXTRA_LIBS}) ENDIF() ENDIF() -- cgit v1.2.3 From 55c860deece653bfed07ee5a62f5320283502da3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 9 Nov 2018 01:34:59 -0800 Subject: Use C++ with the winmm backend --- Alc/backends/winmm.cpp | 595 +++++++++++++++++++++++-------------------------- 1 file changed, 277 insertions(+), 318 deletions(-) diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index c32298a9..40a34b16 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -27,137 +27,119 @@ #include #include +#include +#include +#include +#include +#include +#include + #include "alMain.h" #include "alu.h" #include "ringbuffer.h" #include "threads.h" +#include "compat.h" #include "backends/base.h" -namespace { - #ifndef WAVE_FORMAT_IEEE_FLOAT #define WAVE_FORMAT_IEEE_FLOAT 0x0003 #endif -#define DEVNAME_HEAD "OpenAL Soft on " +namespace { +#define DEVNAME_HEAD "OpenAL Soft on " -vector_al_string PlaybackDevices; -vector_al_string CaptureDevices; -void clear_devlist(vector_al_string *list) -{ - VECTOR_FOR_EACH(al_string, *list, alstr_reset); - VECTOR_RESIZE(*list, 0, 0); -} +std::vector PlaybackDevices; +std::vector CaptureDevices; +bool checkName(const std::vector &list, const std::string &name) +{ return std::find(list.cbegin(), list.cend(), name) != list.cend(); } void ProbePlaybackDevices(void) { - ALuint numdevs; - ALuint i; - - clear_devlist(&PlaybackDevices); + PlaybackDevices.clear(); - numdevs = waveOutGetNumDevs(); - VECTOR_RESIZE(PlaybackDevices, 0, numdevs); - for(i = 0;i < numdevs;i++) + ALuint numdevs{waveOutGetNumDevs()}; + PlaybackDevices.reserve(numdevs); + for(ALuint i{0};i < numdevs;i++) { - WAVEOUTCAPSW WaveCaps; - const al_string *iter; - al_string dname; + std::string dname; - AL_STRING_INIT(dname); + WAVEOUTCAPSW WaveCaps{}; if(waveOutGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR) { - ALuint count = 0; - while(1) + const std::string basename{DEVNAME_HEAD + wstr_to_utf8(WaveCaps.szPname)}; + + int count{1}; + std::string newname{basename}; + while(checkName(PlaybackDevices, newname)) { - alstr_copy_cstr(&dname, DEVNAME_HEAD); - alstr_append_wcstr(&dname, WaveCaps.szPname); - if(count != 0) - { - char str[64]; - snprintf(str, sizeof(str), " #%d", count+1); - alstr_append_cstr(&dname, str); - } - count++; - -#define MATCH_ENTRY(i) (alstr_cmp(dname, *(i)) == 0) - VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_ENTRY); - if(iter == VECTOR_END(PlaybackDevices)) break; -#undef MATCH_ENTRY + newname = basename; + newname += " #"; + newname += std::to_string(++count); } + dname = std::move(newname); - TRACE("Got device \"%s\", ID %u\n", alstr_get_cstr(dname), i); + TRACE("Got device \"%s\", ID %u\n", dname.c_str(), i); } - VECTOR_PUSH_BACK(PlaybackDevices, dname); + PlaybackDevices.emplace_back(std::move(dname)); } } void ProbeCaptureDevices(void) { - ALuint numdevs; - ALuint i; - - clear_devlist(&CaptureDevices); + CaptureDevices.clear(); - numdevs = waveInGetNumDevs(); - VECTOR_RESIZE(CaptureDevices, 0, numdevs); - for(i = 0;i < numdevs;i++) + ALuint numdevs{waveInGetNumDevs()}; + CaptureDevices.reserve(numdevs); + for(ALuint i{0};i < numdevs;i++) { - WAVEINCAPSW WaveCaps; - const al_string *iter; - al_string dname; + std::string dname; - AL_STRING_INIT(dname); + WAVEINCAPSW WaveCaps{}; if(waveInGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR) { - ALuint count = 0; - while(1) + const std::string basename{DEVNAME_HEAD + wstr_to_utf8(WaveCaps.szPname)}; + + int count{1}; + std::string newname{basename}; + while(checkName(CaptureDevices, newname)) { - alstr_copy_cstr(&dname, DEVNAME_HEAD); - alstr_append_wcstr(&dname, WaveCaps.szPname); - if(count != 0) - { - char str[64]; - snprintf(str, sizeof(str), " #%d", count+1); - alstr_append_cstr(&dname, str); - } - count++; - -#define MATCH_ENTRY(i) (alstr_cmp(dname, *(i)) == 0) - VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_ENTRY); - if(iter == VECTOR_END(CaptureDevices)) break; -#undef MATCH_ENTRY + newname = basename; + newname += " #"; + newname += std::to_string(++count); } + dname = std::move(newname); - TRACE("Got device \"%s\", ID %u\n", alstr_get_cstr(dname), i); + TRACE("Got device \"%s\", ID %u\n", dname.c_str(), i); } - VECTOR_PUSH_BACK(CaptureDevices, dname); + CaptureDevices.emplace_back(std::move(dname)); } } } // namespace struct ALCwinmmPlayback final : public ALCbackend { - RefCount WaveBuffersCommitted; - WAVEHDR WaveBuffer[4]; + std::atomic Writable{0u}; + alsem_t Sem; + int Idx{0}; + std::array WaveBuffer; - HWAVEOUT OutHdl; + HWAVEOUT OutHdl{nullptr}; - WAVEFORMATEX Format; + WAVEFORMATEX Format{}; - ATOMIC(ALenum) killNow; - althrd_t thread; + std::atomic killNow{AL_TRUE}; + std::thread thread; }; static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device); static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self); static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); -static int ALCwinmmPlayback_mixerProc(void *arg); +static int ALCwinmmPlayback_mixerProc(ALCwinmmPlayback *self); static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *name); static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self); @@ -179,17 +161,20 @@ static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCwinmmPlayback, ALCbackend, self); - InitRef(&self->WaveBuffersCommitted, 0); - self->OutHdl = NULL; - - ATOMIC_INIT(&self->killNow, AL_TRUE); + alsem_init(&self->Sem, 0); + std::fill(self->WaveBuffer.begin(), self->WaveBuffer.end(), WAVEHDR{}); } static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self) { if(self->OutHdl) waveOutClose(self->OutHdl); - self->OutHdl = 0; + self->OutHdl = nullptr; + + al_free(self->WaveBuffer[0].lpData); + std::fill(self->WaveBuffer.begin(), self->WaveBuffer.end(), WAVEHDR{}); + + alsem_destroy(&self->Sem); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCwinmmPlayback(); @@ -201,49 +186,50 @@ static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self) * Posts a message to 'ALCwinmmPlayback_mixerProc' everytime a WaveOut Buffer * is completed and returns to the application (for more data) */ -static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2)) +static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT UNUSED(device), UINT msg, + DWORD_PTR instance, DWORD_PTR UNUSED(param1), + DWORD_PTR UNUSED(param2)) { - ALCwinmmPlayback *self = (ALCwinmmPlayback*)instance; - if(msg != WOM_DONE) return; - DecrementRef(&self->WaveBuffersCommitted); - PostThreadMessage(self->thread, msg, 0, param1); + auto self = reinterpret_cast(instance); + self->Writable.fetch_add(1, std::memory_order_acq_rel); + alsem_post(&self->Sem); } -FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(void *arg) +FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(ALCwinmmPlayback *self) { - auto self = static_cast(arg); ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - WAVEHDR *WaveHdr; - MSG msg; SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); - while(GetMessage(&msg, NULL, 0, 0)) + ALCwinmmPlayback_lock(self); + while(!self->killNow.load(std::memory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { - if(msg.message != WOM_DONE) - continue; - - if(ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) + ALsizei todo = self->Writable.load(std::memory_order_acquire); + if(todo < 1) { - if(ReadRef(&self->WaveBuffersCommitted) == 0) - break; + ALCwinmmPlayback_unlock(self); + alsem_wait(&self->Sem); + ALCwinmmPlayback_lock(self); continue; } - WaveHdr = ((WAVEHDR*)msg.lParam); - ALCwinmmPlayback_lock(self); - aluMixData(device, WaveHdr->lpData, WaveHdr->dwBufferLength / - self->Format.nBlockAlign); - ALCwinmmPlayback_unlock(self); + int widx{self->Idx}; + do { + WAVEHDR &waveHdr = self->WaveBuffer[widx]; + widx = (widx+1) % self->WaveBuffer.size(); - // Send buffer back to play more data - waveOutWrite(self->OutHdl, WaveHdr, sizeof(WAVEHDR)); - IncrementRef(&self->WaveBuffersCommitted); + aluMixData(device, waveHdr.lpData, device->UpdateSize); + self->Writable.fetch_sub(1, std::memory_order_acq_rel); + waveOutWrite(self->OutHdl, &waveHdr, sizeof(WAVEHDR)); + } while(--todo); + self->Idx = widx; } + ALCwinmmPlayback_unlock(self); return 0; } @@ -252,22 +238,16 @@ FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(void *arg) static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *deviceName) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - const al_string *iter; - UINT DeviceID; - MMRESULT res; - if(VECTOR_SIZE(PlaybackDevices) == 0) + if(PlaybackDevices.empty()) ProbePlaybackDevices(); // Find the Device ID matching the deviceName if valid -#define MATCH_DEVNAME(iter) (!alstr_empty(*(iter)) && \ - (!deviceName || alstr_cmp_cstr(*(iter), deviceName) == 0)) - VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_DEVNAME); - if(iter == VECTOR_END(PlaybackDevices)) - return ALC_INVALID_VALUE; -#undef MATCH_DEVNAME - - DeviceID = (UINT)(iter - VECTOR_BEGIN(PlaybackDevices)); + auto iter = deviceName ? + std::find(PlaybackDevices.cbegin(), PlaybackDevices.cend(), deviceName) : + PlaybackDevices.cbegin(); + if(iter == PlaybackDevices.cend()) return ALC_INVALID_VALUE; + UINT DeviceID{static_cast(std::distance(PlaybackDevices.cbegin(), iter))}; retry_open: memset(&self->Format, 0, sizeof(WAVEFORMATEX)); @@ -292,7 +272,10 @@ retry_open: self->Format.nBlockAlign; self->Format.cbSize = 0; - if((res=waveOutOpen(&self->OutHdl, DeviceID, &self->Format, (DWORD_PTR)&ALCwinmmPlayback_waveOutProc, (DWORD_PTR)self, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) + MMRESULT res{waveOutOpen(&self->OutHdl, DeviceID, &self->Format, + (DWORD_PTR)&ALCwinmmPlayback_waveOutProc, (DWORD_PTR)self, CALLBACK_FUNCTION + )}; + if(res != MMSYSERR_NOERROR) { if(device->FmtType == DevFmtFloat) { @@ -300,18 +283,11 @@ retry_open: goto retry_open; } ERR("waveOutOpen failed: %u\n", res); - goto failure; + return ALC_INVALID_VALUE; } - alstr_copy(&device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID)); + alstr_copy_cstr(&device->DeviceName, PlaybackDevices[DeviceID].c_str()); return ALC_NO_ERROR; - -failure: - if(self->OutHdl) - waveOutClose(self->OutHdl); - self->OutHdl = NULL; - - return ALC_INVALID_VALUE; } static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self) @@ -364,84 +340,86 @@ static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self) } SetDefaultWFXChannelOrder(device); - return ALC_TRUE; -} + ALuint BufferSize{device->UpdateSize * + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder)}; -static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ALbyte *BufferData; - ALint BufferSize; - ALuint i; - - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); - if(althrd_create(&self->thread, ALCwinmmPlayback_mixerProc, self) != althrd_success) - return ALC_FALSE; - - InitRef(&self->WaveBuffersCommitted, 0); - - // Create 4 Buffers - BufferSize = device->UpdateSize*device->NumUpdates / 4; - BufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - - BufferData = static_cast(calloc(4, BufferSize)); - for(i = 0;i < 4;i++) + al_free(self->WaveBuffer[0].lpData); + self->WaveBuffer[0] = WAVEHDR{}; + self->WaveBuffer[0].lpData = static_cast(al_calloc(16, + BufferSize * self->WaveBuffer.size())); + self->WaveBuffer[0].dwBufferLength = BufferSize; + for(size_t i{1};i < self->WaveBuffer.size();i++) { - memset(&self->WaveBuffer[i], 0, sizeof(WAVEHDR)); + self->WaveBuffer[i] = WAVEHDR{}; + self->WaveBuffer[i].lpData = self->WaveBuffer[i-1].lpData + + self->WaveBuffer[i-1].dwBufferLength; self->WaveBuffer[i].dwBufferLength = BufferSize; - self->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData : - (self->WaveBuffer[i-1].lpData + - self->WaveBuffer[i-1].dwBufferLength)); - waveOutPrepareHeader(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); - waveOutWrite(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); - IncrementRef(&self->WaveBuffersCommitted); } + self->Idx = 0; return ALC_TRUE; } -static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self) +static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self) { - void *buffer = NULL; - int i; - - if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) - return; - althrd_join(self->thread, &i); + try { + std::for_each(self->WaveBuffer.begin(), self->WaveBuffer.end(), + [self](WAVEHDR &waveHdr) -> void + { waveOutPrepareHeader(self->OutHdl, &waveHdr, sizeof(WAVEHDR)); } + ); + self->Writable.store(self->WaveBuffer.size(), std::memory_order_release); - // Release the wave buffers - for(i = 0;i < 4;i++) - { - waveOutUnprepareHeader(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); - if(i == 0) buffer = self->WaveBuffer[i].lpData; - self->WaveBuffer[i].lpData = NULL; + self->killNow.store(AL_FALSE, std::memory_order_release); + self->thread = std::thread(ALCwinmmPlayback_mixerProc, self); + return ALC_TRUE; } - free(buffer); + catch(std::exception& e) { + ERR("Failed to start mixing thread: %s\n", e.what()); + } + catch(...) { + } + return ALC_FALSE; } +static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self) +{ + if(self->killNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->thread.joinable()) + return; + self->thread.join(); + + while(self->Writable.load(std::memory_order_acquire) < self->WaveBuffer.size()) + alsem_wait(&self->Sem); + std::for_each(self->WaveBuffer.begin(), self->WaveBuffer.end(), + [self](WAVEHDR &waveHdr) -> void + { waveOutUnprepareHeader(self->OutHdl, &waveHdr, sizeof(WAVEHDR)); } + ); + self->Writable.store(0, std::memory_order_release); +} struct ALCwinmmCapture final : public ALCbackend { - RefCount WaveBuffersCommitted; - WAVEHDR WaveBuffer[4]; + std::atomic Readable{0u}; + alsem_t Sem; + int Idx{0}; + std::array WaveBuffer; - HWAVEIN InHdl; + HWAVEIN InHdl{nullptr}; - ll_ringbuffer_t *Ring; + ll_ringbuffer_t *Ring{nullptr}; - WAVEFORMATEX Format; + WAVEFORMATEX Format{}; - ATOMIC(ALenum) killNow; - althrd_t thread; + std::atomic killNow{AL_TRUE}; + std::thread thread; }; static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device); static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self); static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); -static int ALCwinmmCapture_captureProc(void *arg); +static int ALCwinmmCapture_captureProc(ALCwinmmCapture *self); -static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name); +static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName); static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ALCboolean, reset) static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self); static void ALCwinmmCapture_stop(ALCwinmmCapture *self); @@ -461,44 +439,24 @@ static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device) ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCwinmmCapture, ALCbackend, self); - InitRef(&self->WaveBuffersCommitted, 0); - self->InHdl = NULL; - - ATOMIC_INIT(&self->killNow, AL_TRUE); + alsem_init(&self->Sem, 0); + std::fill(self->WaveBuffer.begin(), self->WaveBuffer.end(), WAVEHDR{}); } static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self) { - void *buffer = NULL; - int i; - - /* Tell the processing thread to quit and wait for it to do so. */ - if(!ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) - { - PostThreadMessage(self->thread, WM_QUIT, 0, 0); - - althrd_join(self->thread, &i); - - /* Make sure capture is stopped and all pending buffers are flushed. */ - waveInReset(self->InHdl); + // Close the Wave device + if(self->InHdl) + waveInClose(self->InHdl); + self->InHdl = nullptr; - // Release the wave buffers - for(i = 0;i < 4;i++) - { - waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); - if(i == 0) buffer = self->WaveBuffer[i].lpData; - self->WaveBuffer[i].lpData = NULL; - } - free(buffer); - } + al_free(self->WaveBuffer[0].lpData); + std::fill(self->WaveBuffer.begin(), self->WaveBuffer.end(), WAVEHDR{}); ll_ringbuffer_free(self->Ring); - self->Ring = NULL; + self->Ring = nullptr; - // Close the Wave device - if(self->InHdl) - waveInClose(self->InHdl); - self->InHdl = 0; + alsem_destroy(&self->Sem); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCwinmmCapture(); @@ -510,70 +468,69 @@ static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self) * Posts a message to 'ALCwinmmCapture_captureProc' everytime a WaveIn Buffer * is completed and returns to the application (with more data). */ -static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2)) +static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN UNUSED(device), UINT msg, + DWORD_PTR instance, DWORD_PTR UNUSED(param1), + DWORD_PTR UNUSED(param2)) { - ALCwinmmCapture *self = (ALCwinmmCapture*)instance; - if(msg != WIM_DATA) return; - DecrementRef(&self->WaveBuffersCommitted); - PostThreadMessage(self->thread, msg, 0, param1); + auto self = reinterpret_cast(instance); + self->Readable.fetch_add(1, std::memory_order_acq_rel); + alsem_post(&self->Sem); } -static int ALCwinmmCapture_captureProc(void *arg) +static int ALCwinmmCapture_captureProc(ALCwinmmCapture *self) { - auto self = static_cast(arg); - WAVEHDR *WaveHdr; - MSG msg; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; althrd_setname(althrd_current(), RECORD_THREAD_NAME); - while(GetMessage(&msg, NULL, 0, 0)) + ALCwinmmCapture_lock(self); + while(!self->killNow.load(std::memory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { - if(msg.message != WIM_DATA) + ALsizei todo = self->Readable.load(std::memory_order_acquire); + if(todo < 1) + { + ALCwinmmCapture_unlock(self); + alsem_wait(&self->Sem); + ALCwinmmCapture_lock(self); continue; - /* Don't wait for other buffers to finish before quitting. We're - * closing so we don't need them. */ - if(ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) - break; - - WaveHdr = ((WAVEHDR*)msg.lParam); - ll_ringbuffer_write(self->Ring, WaveHdr->lpData, - WaveHdr->dwBytesRecorded / self->Format.nBlockAlign - ); + } - // Send buffer back to capture more data - waveInAddBuffer(self->InHdl, WaveHdr, sizeof(WAVEHDR)); - IncrementRef(&self->WaveBuffersCommitted); + int widx{self->Idx}; + do { + WAVEHDR &waveHdr = self->WaveBuffer[widx]; + widx = (widx+1) % self->WaveBuffer.size(); + + ll_ringbuffer_write(self->Ring, waveHdr.lpData, + waveHdr.dwBytesRecorded / self->Format.nBlockAlign + ); + self->Readable.fetch_sub(1, std::memory_order_acq_rel); + waveInAddBuffer(self->InHdl, &waveHdr, sizeof(WAVEHDR)); + } while(--todo); + self->Idx = widx; } + ALCwinmmCapture_unlock(self); return 0; } -static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name) +static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - const al_string *iter; - ALbyte *BufferData = NULL; - DWORD CapturedDataSize; - ALint BufferSize; - UINT DeviceID; - MMRESULT res; - ALuint i; - - if(VECTOR_SIZE(CaptureDevices) == 0) + + if(CaptureDevices.empty()) ProbeCaptureDevices(); // Find the Device ID matching the deviceName if valid -#define MATCH_DEVNAME(iter) (!alstr_empty(*(iter)) && (!name || alstr_cmp_cstr(*iter, name) == 0)) - VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_DEVNAME); - if(iter == VECTOR_END(CaptureDevices)) - return ALC_INVALID_VALUE; -#undef MATCH_DEVNAME - - DeviceID = (UINT)(iter - VECTOR_BEGIN(CaptureDevices)); + auto iter = deviceName ? + std::find(CaptureDevices.cbegin(), CaptureDevices.cend(), deviceName) : + CaptureDevices.cbegin(); + if(iter == CaptureDevices.cend()) return ALC_INVALID_VALUE; + UINT DeviceID{static_cast(std::distance(CaptureDevices.cbegin(), iter))}; switch(device->FmtChans) { @@ -605,8 +562,8 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name) } memset(&self->Format, 0, sizeof(WAVEFORMATEX)); - self->Format.wFormatTag = ((device->FmtType == DevFmtFloat) ? - WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM); + self->Format.wFormatTag = (device->FmtType == DevFmtFloat) ? + WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM; self->Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); self->Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; self->Format.nBlockAlign = self->Format.wBitsPerSample * @@ -616,79 +573,83 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name) self->Format.nBlockAlign; self->Format.cbSize = 0; - if((res=waveInOpen(&self->InHdl, DeviceID, &self->Format, (DWORD_PTR)&ALCwinmmCapture_waveInProc, (DWORD_PTR)self, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) + MMRESULT res{waveInOpen(&self->InHdl, DeviceID, &self->Format, + (DWORD_PTR)&ALCwinmmCapture_waveInProc, (DWORD_PTR)self, CALLBACK_FUNCTION + )}; + if(res != MMSYSERR_NOERROR) { ERR("waveInOpen failed: %u\n", res); - goto failure; + return ALC_INVALID_VALUE; } - // Allocate circular memory buffer for the captured audio - CapturedDataSize = device->UpdateSize*device->NumUpdates; + // Ensure each buffer is 50ms each + DWORD BufferSize{self->Format.nAvgBytesPerSec / 20}; + BufferSize -= (BufferSize % self->Format.nBlockAlign); + // Allocate circular memory buffer for the captured audio // Make sure circular buffer is at least 100ms in size - if(CapturedDataSize < (self->Format.nSamplesPerSec / 10)) - CapturedDataSize = self->Format.nSamplesPerSec / 10; + DWORD CapturedDataSize{std::max(device->UpdateSize*device->NumUpdates, + BufferSize*self->WaveBuffer.size())}; self->Ring = ll_ringbuffer_create(CapturedDataSize, self->Format.nBlockAlign, false); - if(!self->Ring) goto failure; - - InitRef(&self->WaveBuffersCommitted, 0); - - // Create 4 Buffers of 50ms each - BufferSize = self->Format.nAvgBytesPerSec / 20; - BufferSize -= (BufferSize % self->Format.nBlockAlign); + if(!self->Ring) return ALC_INVALID_VALUE; - BufferData = static_cast(calloc(4, BufferSize)); - if(!BufferData) goto failure; - - for(i = 0;i < 4;i++) + al_free(self->WaveBuffer[0].lpData); + self->WaveBuffer[0] = WAVEHDR{}; + self->WaveBuffer[0].lpData = static_cast(al_calloc(16, BufferSize*4)); + self->WaveBuffer[0].dwBufferLength = BufferSize; + for(size_t i{1};i < self->WaveBuffer.size();++i) { - memset(&self->WaveBuffer[i], 0, sizeof(WAVEHDR)); - self->WaveBuffer[i].dwBufferLength = BufferSize; - self->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData : - (self->WaveBuffer[i-1].lpData + - self->WaveBuffer[i-1].dwBufferLength)); - self->WaveBuffer[i].dwFlags = 0; - self->WaveBuffer[i].dwLoops = 0; - waveInPrepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); - waveInAddBuffer(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); - IncrementRef(&self->WaveBuffersCommitted); + self->WaveBuffer[i] = WAVEHDR{}; + self->WaveBuffer[i].lpData = self->WaveBuffer[i-1].lpData + + self->WaveBuffer[i-1].dwBufferLength; + self->WaveBuffer[i].dwBufferLength = self->WaveBuffer[i-1].dwBufferLength; } - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); - if(althrd_create(&self->thread, ALCwinmmCapture_captureProc, self) != althrd_success) - goto failure; - - alstr_copy(&device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID)); + alstr_copy_cstr(&device->DeviceName, CaptureDevices[DeviceID].c_str()); return ALC_NO_ERROR; - -failure: - if(BufferData) - { - for(i = 0;i < 4;i++) - waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); - free(BufferData); - } - - ll_ringbuffer_free(self->Ring); - self->Ring = NULL; - - if(self->InHdl) - waveInClose(self->InHdl); - self->InHdl = NULL; - - return ALC_INVALID_VALUE; } static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self) { - waveInStart(self->InHdl); - return ALC_TRUE; + try { + for(size_t i{0};i < self->WaveBuffer.size();++i) + { + waveInPrepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + waveInAddBuffer(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + } + + self->killNow.store(AL_FALSE, std::memory_order_release); + self->thread = std::thread(ALCwinmmCapture_captureProc, self); + + waveInStart(self->InHdl); + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Failed to start mixing thread: %s\n", e.what()); + } + catch(...) { + } + return ALC_FALSE; } static void ALCwinmmCapture_stop(ALCwinmmCapture *self) { waveInStop(self->InHdl); + + self->killNow.store(AL_TRUE, std::memory_order_release); + if(self->thread.joinable()) + { + alsem_post(&self->Sem); + self->thread.join(); + } + + waveInReset(self->InHdl); + for(size_t i{0};i < self->WaveBuffer.size();++i) + waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + + self->Readable.store(0, std::memory_order_release); + self->Idx = 0; } static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples) @@ -723,19 +684,13 @@ ALCwinmmBackendFactory::ALCwinmmBackendFactory() noexcept static ALCboolean ALCwinmmBackendFactory_init(ALCwinmmBackendFactory* UNUSED(self)) { - VECTOR_INIT(PlaybackDevices); - VECTOR_INIT(CaptureDevices); - return ALC_TRUE; } static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory* UNUSED(self)) { - clear_devlist(&PlaybackDevices); - VECTOR_DEINIT(PlaybackDevices); - - clear_devlist(&CaptureDevices); - VECTOR_DEINIT(CaptureDevices); + PlaybackDevices.clear(); + CaptureDevices.clear(); } static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory* UNUSED(self), ALCbackend_Type type) @@ -747,22 +702,26 @@ static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory* UN static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { + auto add_device = [outnames](const std::string &dname) -> void + { + const char *name{dname.c_str()}; + size_t namelen{dname.length()}; + /* +1 to also append the null char (to ensure a null-separated list and + * double-null terminated list). + */ + alstr_append_range(outnames, name, name + namelen+1); + }; switch(type) { -#define APPEND_OUTNAME(n) do { \ - if(!alstr_empty(*(n))) \ - alstr_append_range(outnames, VECTOR_BEGIN(*(n)), VECTOR_END(*(n))+1); \ -} while(0) case ALL_DEVICE_PROBE: ProbePlaybackDevices(); - VECTOR_FOR_EACH(const al_string, PlaybackDevices, APPEND_OUTNAME); + std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); break; case CAPTURE_DEVICE_PROBE: ProbeCaptureDevices(); - VECTOR_FOR_EACH(const al_string, CaptureDevices, APPEND_OUTNAME); + std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); break; -#undef APPEND_OUTNAME } } @@ -772,18 +731,18 @@ static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory* { ALCwinmmPlayback *backend; NEW_OBJ(backend, ALCwinmmPlayback)(device); - if(!backend) return NULL; + if(!backend) return nullptr; return STATIC_CAST(ALCbackend, backend); } if(type == ALCbackend_Capture) { ALCwinmmCapture *backend; NEW_OBJ(backend, ALCwinmmCapture)(device); - if(!backend) return NULL; + if(!backend) return nullptr; return STATIC_CAST(ALCbackend, backend); } - return NULL; + return nullptr; } ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void) -- cgit v1.2.3 From b2cdfe58ebf5c39fc618347945fe52ddf91632ff Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 9 Nov 2018 01:55:54 -0800 Subject: Convert the wave backend to C++ --- Alc/backends/wave.c | 453 ------------------------------------------------- Alc/backends/wave.cpp | 461 ++++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 462 insertions(+), 454 deletions(-) delete mode 100644 Alc/backends/wave.c create mode 100644 Alc/backends/wave.cpp diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c deleted file mode 100644 index 390b2a5f..00000000 --- a/Alc/backends/wave.c +++ /dev/null @@ -1,453 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include -#include - -#include "alMain.h" -#include "alu.h" -#include "alconfig.h" -#include "threads.h" -#include "compat.h" - -#include "backends/base.h" - - -static const ALCchar waveDevice[] = "Wave File Writer"; - -static const ALubyte SUBTYPE_PCM[] = { - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, - 0x00, 0x38, 0x9b, 0x71 -}; -static const ALubyte SUBTYPE_FLOAT[] = { - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, - 0x00, 0x38, 0x9b, 0x71 -}; - -static const ALubyte SUBTYPE_BFORMAT_PCM[] = { - 0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1, - 0xca, 0x00, 0x00, 0x00 -}; - -static const ALubyte SUBTYPE_BFORMAT_FLOAT[] = { - 0x03, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1, - 0xca, 0x00, 0x00, 0x00 -}; - -static void fwrite16le(ALushort val, FILE *f) -{ - ALubyte data[2] = { val&0xff, (val>>8)&0xff }; - fwrite(data, 1, 2, f); -} - -static void fwrite32le(ALuint val, FILE *f) -{ - ALubyte data[4] = { val&0xff, (val>>8)&0xff, (val>>16)&0xff, (val>>24)&0xff }; - fwrite(data, 1, 4, f); -} - - -typedef struct ALCwaveBackend { - DERIVE_FROM_TYPE(ALCbackend); - - FILE *mFile; - long mDataStart; - - ALvoid *mBuffer; - ALuint mSize; - - ATOMIC(ALenum) killNow; - althrd_t thread; -} ALCwaveBackend; - -static int ALCwaveBackend_mixerProc(void *ptr); - -static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device); -static void ALCwaveBackend_Destruct(ALCwaveBackend *self); -static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name); -static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self); -static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self); -static void ALCwaveBackend_stop(ALCwaveBackend *self); -static DECLARE_FORWARD2(ALCwaveBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCwaveBackend) - -DEFINE_ALCBACKEND_VTABLE(ALCwaveBackend); - - -static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCwaveBackend, ALCbackend, self); - - self->mFile = NULL; - self->mDataStart = -1; - - self->mBuffer = NULL; - self->mSize = 0; - - ATOMIC_INIT(&self->killNow, AL_TRUE); -} - -static void ALCwaveBackend_Destruct(ALCwaveBackend *self) -{ - if(self->mFile) - fclose(self->mFile); - self->mFile = NULL; - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - -static int ALCwaveBackend_mixerProc(void *ptr) -{ - ALCwaveBackend *self = (ALCwaveBackend*)ptr; - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - struct timespec now, start; - ALint64 avail, done; - ALuint frameSize; - size_t fs; - const long restTime = (long)((ALuint64)device->UpdateSize * 1000000000 / - device->Frequency / 2); - - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - - done = 0; - if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC) - { - ERR("Failed to get starting time\n"); - return 1; - } - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) - { - if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC) - { - ERR("Failed to get current time\n"); - return 1; - } - - avail = (now.tv_sec - start.tv_sec) * device->Frequency; - avail += (ALint64)(now.tv_nsec - start.tv_nsec) * device->Frequency / 1000000000; - if(avail < done) - { - /* 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(restTime); - else while(avail-done >= device->UpdateSize) - { - ALCwaveBackend_lock(self); - aluMixData(device, self->mBuffer, device->UpdateSize); - ALCwaveBackend_unlock(self); - done += device->UpdateSize; - - if(!IS_LITTLE_ENDIAN) - { - ALuint bytesize = BytesFromDevFmt(device->FmtType); - ALuint i; - - if(bytesize == 2) - { - ALushort *samples = self->mBuffer; - ALuint len = self->mSize / 2; - for(i = 0;i < len;i++) - { - ALushort samp = samples[i]; - samples[i] = (samp>>8) | (samp<<8); - } - } - else if(bytesize == 4) - { - ALuint *samples = self->mBuffer; - ALuint len = self->mSize / 4; - for(i = 0;i < len;i++) - { - ALuint samp = samples[i]; - samples[i] = (samp>>24) | ((samp>>8)&0x0000ff00) | - ((samp<<8)&0x00ff0000) | (samp<<24); - } - } - } - - fs = fwrite(self->mBuffer, frameSize, device->UpdateSize, self->mFile); - (void)fs; - if(ferror(self->mFile)) - { - ERR("Error writing to file\n"); - ALCdevice_Lock(device); - aluHandleDisconnect(device, "Failed to write playback samples"); - ALCdevice_Unlock(device); - break; - } - } - } - - return 0; -} - - -static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name) -{ - ALCdevice *device; - const char *fname; - - fname = GetConfigValue(NULL, "wave", "file", ""); - if(!fname[0]) return ALC_INVALID_VALUE; - - if(!name) - name = waveDevice; - else if(strcmp(name, waveDevice) != 0) - return ALC_INVALID_VALUE; - - self->mFile = al_fopen(fname, "wb"); - if(!self->mFile) - { - ERR("Could not open file '%s': %s\n", fname, strerror(errno)); - return ALC_INVALID_VALUE; - } - - device = STATIC_CAST(ALCbackend, self)->mDevice; - alstr_copy_cstr(&device->DeviceName, name); - - return ALC_NO_ERROR; -} - -static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ALuint channels=0, bits=0, chanmask=0; - int isbformat = 0; - size_t val; - - fseek(self->mFile, 0, SEEK_SET); - clearerr(self->mFile); - - if(GetConfigValueBool(NULL, "wave", "bformat", 0)) - { - device->FmtChans = DevFmtAmbi3D; - device->AmbiOrder = 1; - } - - switch(device->FmtType) - { - case DevFmtByte: - device->FmtType = DevFmtUByte; - break; - case DevFmtUShort: - device->FmtType = DevFmtShort; - break; - case DevFmtUInt: - device->FmtType = DevFmtInt; - break; - case DevFmtUByte: - case DevFmtShort: - case DevFmtInt: - case DevFmtFloat: - break; - } - switch(device->FmtChans) - { - case DevFmtMono: chanmask = 0x04; break; - case DevFmtStereo: chanmask = 0x01 | 0x02; break; - case DevFmtQuad: chanmask = 0x01 | 0x02 | 0x10 | 0x20; break; - case DevFmtX51: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x200 | 0x400; break; - case DevFmtX51Rear: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020; break; - case DevFmtX61: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400; break; - case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break; - case DevFmtAmbi3D: - /* .amb output requires FuMa */ - device->AmbiLayout = AmbiLayout_FuMa; - device->AmbiScale = AmbiNorm_FuMa; - isbformat = 1; - chanmask = 0; - break; - } - bits = BytesFromDevFmt(device->FmtType) * 8; - channels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - - fputs("RIFF", self->mFile); - fwrite32le(0xFFFFFFFF, self->mFile); // 'RIFF' header len; filled in at close - - fputs("WAVE", self->mFile); - - fputs("fmt ", self->mFile); - fwrite32le(40, self->mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE - - // 16-bit val, format type id (extensible: 0xFFFE) - fwrite16le(0xFFFE, self->mFile); - // 16-bit val, channel count - fwrite16le(channels, self->mFile); - // 32-bit val, frequency - fwrite32le(device->Frequency, self->mFile); - // 32-bit val, bytes per second - fwrite32le(device->Frequency * channels * bits / 8, self->mFile); - // 16-bit val, frame size - fwrite16le(channels * bits / 8, self->mFile); - // 16-bit val, bits per sample - fwrite16le(bits, self->mFile); - // 16-bit val, extra byte count - fwrite16le(22, self->mFile); - // 16-bit val, valid bits per sample - fwrite16le(bits, self->mFile); - // 32-bit val, channel mask - fwrite32le(chanmask, self->mFile); - // 16 byte GUID, sub-type format - val = fwrite((device->FmtType == DevFmtFloat) ? - (isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) : - (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM), 1, 16, self->mFile); - (void)val; - - fputs("data", self->mFile); - fwrite32le(0xFFFFFFFF, self->mFile); // 'data' header len; filled in at close - - if(ferror(self->mFile)) - { - ERR("Error writing header: %s\n", strerror(errno)); - return ALC_FALSE; - } - self->mDataStart = ftell(self->mFile); - - SetDefaultWFXChannelOrder(device); - - return ALC_TRUE; -} - -static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - - self->mSize = device->UpdateSize * FrameSizeFromDevFmt( - device->FmtChans, device->FmtType, device->AmbiOrder - ); - self->mBuffer = malloc(self->mSize); - if(!self->mBuffer) - { - ERR("Buffer malloc failed\n"); - return ALC_FALSE; - } - - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); - if(althrd_create(&self->thread, ALCwaveBackend_mixerProc, self) != althrd_success) - { - free(self->mBuffer); - self->mBuffer = NULL; - self->mSize = 0; - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static void ALCwaveBackend_stop(ALCwaveBackend *self) -{ - ALuint dataLen; - long size; - int res; - - if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) - return; - althrd_join(self->thread, &res); - - free(self->mBuffer); - self->mBuffer = NULL; - - size = ftell(self->mFile); - if(size > 0) - { - dataLen = size - self->mDataStart; - if(fseek(self->mFile, self->mDataStart-4, SEEK_SET) == 0) - fwrite32le(dataLen, self->mFile); // 'data' header len - if(fseek(self->mFile, 4, SEEK_SET) == 0) - fwrite32le(size-8, self->mFile); // 'WAVE' header len - } -} - - -typedef struct ALCwaveBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCwaveBackendFactory; -#define ALCWAVEBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwaveBackendFactory, ALCbackendFactory) } } - -ALCbackendFactory *ALCwaveBackendFactory_getFactory(void); - -static ALCboolean ALCwaveBackendFactory_init(ALCwaveBackendFactory *self); -static DECLARE_FORWARD(ALCwaveBackendFactory, ALCbackendFactory, void, deinit) -static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory *self, ALCbackend_Type type); -static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory *self, enum DevProbe type, al_string *outnames); -static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwaveBackendFactory); - - -ALCbackendFactory *ALCwaveBackendFactory_getFactory(void) -{ - static ALCwaveBackendFactory factory = ALCWAVEBACKENDFACTORY_INITIALIZER; - return STATIC_CAST(ALCbackendFactory, &factory); -} - - -static ALCboolean ALCwaveBackendFactory_init(ALCwaveBackendFactory* UNUSED(self)) -{ - return ALC_TRUE; -} - -static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - return !!ConfigValueExists(NULL, "wave", "file"); - return ALC_FALSE; -} - -static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) -{ - switch(type) - { - case ALL_DEVICE_PROBE: - alstr_append_range(outnames, waveDevice, waveDevice+sizeof(waveDevice)); - break; - case CAPTURE_DEVICE_PROBE: - break; - } -} - -static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - { - ALCwaveBackend *backend; - NEW_OBJ(backend, ALCwaveBackend)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp new file mode 100644 index 00000000..d4e5bf97 --- /dev/null +++ b/Alc/backends/wave.cpp @@ -0,0 +1,461 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "alMain.h" +#include "alu.h" +#include "alconfig.h" +#include "threads.h" +#include "compat.h" + +#include "backends/base.h" + + +namespace { + +constexpr ALCchar waveDevice[] = "Wave File Writer"; + +constexpr ALubyte SUBTYPE_PCM[]{ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, + 0x00, 0x38, 0x9b, 0x71 +}; +constexpr ALubyte SUBTYPE_FLOAT[]{ + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, + 0x00, 0x38, 0x9b, 0x71 +}; + +constexpr ALubyte SUBTYPE_BFORMAT_PCM[]{ + 0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1, + 0xca, 0x00, 0x00, 0x00 +}; + +constexpr ALubyte SUBTYPE_BFORMAT_FLOAT[]{ + 0x03, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1, + 0xca, 0x00, 0x00, 0x00 +}; + +void fwrite16le(ALushort val, FILE *f) +{ + ALubyte data[2]{ static_cast(val&0xff), static_cast((val>>8)&0xff) }; + fwrite(data, 1, 2, f); +} + +void fwrite32le(ALuint val, FILE *f) +{ + ALubyte data[4]{ static_cast(val&0xff), static_cast((val>>8)&0xff), + static_cast((val>>16)&0xff), static_cast((val>>24)&0xff) }; + fwrite(data, 1, 4, f); +} + +} // namespace + + +struct ALCwaveBackend final : public ALCbackend { + FILE *mFile; + long mDataStart; + + ALvoid *mBuffer; + ALuint mSize; + + ATOMIC(ALenum) killNow; + althrd_t thread; +}; + +static int ALCwaveBackend_mixerProc(void *ptr); + +static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device); +static void ALCwaveBackend_Destruct(ALCwaveBackend *self); +static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name); +static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self); +static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self); +static void ALCwaveBackend_stop(ALCwaveBackend *self); +static DECLARE_FORWARD2(ALCwaveBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCwaveBackend) + +DEFINE_ALCBACKEND_VTABLE(ALCwaveBackend); + + +static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device) +{ + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCwaveBackend, ALCbackend, self); + + self->mFile = nullptr; + self->mDataStart = -1; + + self->mBuffer = nullptr; + self->mSize = 0; + + ATOMIC_INIT(&self->killNow, AL_TRUE); +} + +static void ALCwaveBackend_Destruct(ALCwaveBackend *self) +{ + if(self->mFile) + fclose(self->mFile); + self->mFile = nullptr; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + +static int ALCwaveBackend_mixerProc(void *ptr) +{ + ALCwaveBackend *self = (ALCwaveBackend*)ptr; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + struct timespec now, start; + ALint64 avail, done; + ALuint frameSize; + size_t fs; + const long restTime = (long)((ALuint64)device->UpdateSize * 1000000000 / + device->Frequency / 2); + + althrd_setname(althrd_current(), MIXER_THREAD_NAME); + + frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + + done = 0; + if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC) + { + ERR("Failed to get starting time\n"); + return 1; + } + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + { + if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC) + { + ERR("Failed to get current time\n"); + return 1; + } + + avail = (now.tv_sec - start.tv_sec) * device->Frequency; + avail += (ALint64)(now.tv_nsec - start.tv_nsec) * device->Frequency / 1000000000; + if(avail < done) + { + /* 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(restTime); + else while(avail-done >= device->UpdateSize) + { + ALCwaveBackend_lock(self); + aluMixData(device, self->mBuffer, device->UpdateSize); + ALCwaveBackend_unlock(self); + done += device->UpdateSize; + + if(!IS_LITTLE_ENDIAN) + { + ALuint bytesize = BytesFromDevFmt(device->FmtType); + ALuint i; + + if(bytesize == 2) + { + ALushort *samples = static_cast(self->mBuffer); + ALuint len = self->mSize / 2; + for(i = 0;i < len;i++) + { + ALushort samp = samples[i]; + samples[i] = (samp>>8) | (samp<<8); + } + } + else if(bytesize == 4) + { + ALuint *samples = static_cast(self->mBuffer); + ALuint len = self->mSize / 4; + for(i = 0;i < len;i++) + { + ALuint samp = samples[i]; + samples[i] = (samp>>24) | ((samp>>8)&0x0000ff00) | + ((samp<<8)&0x00ff0000) | (samp<<24); + } + } + } + + fs = fwrite(self->mBuffer, frameSize, device->UpdateSize, self->mFile); + (void)fs; + if(ferror(self->mFile)) + { + ERR("Error writing to file\n"); + ALCdevice_Lock(device); + aluHandleDisconnect(device, "Failed to write playback samples"); + ALCdevice_Unlock(device); + break; + } + } + } + + return 0; +} + + +static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name) +{ + ALCdevice *device; + const char *fname; + + fname = GetConfigValue(nullptr, "wave", "file", ""); + if(!fname[0]) return ALC_INVALID_VALUE; + + if(!name) + name = waveDevice; + else if(strcmp(name, waveDevice) != 0) + return ALC_INVALID_VALUE; + + self->mFile = al_fopen(fname, "wb"); + if(!self->mFile) + { + ERR("Could not open file '%s': %s\n", fname, strerror(errno)); + return ALC_INVALID_VALUE; + } + + device = STATIC_CAST(ALCbackend, self)->mDevice; + alstr_copy_cstr(&device->DeviceName, name); + + return ALC_NO_ERROR; +} + +static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALuint channels=0, bits=0, chanmask=0; + int isbformat = 0; + size_t val; + + fseek(self->mFile, 0, SEEK_SET); + clearerr(self->mFile); + + if(GetConfigValueBool(nullptr, "wave", "bformat", 0)) + { + device->FmtChans = DevFmtAmbi3D; + device->AmbiOrder = 1; + } + + switch(device->FmtType) + { + case DevFmtByte: + device->FmtType = DevFmtUByte; + break; + case DevFmtUShort: + device->FmtType = DevFmtShort; + break; + case DevFmtUInt: + device->FmtType = DevFmtInt; + break; + case DevFmtUByte: + case DevFmtShort: + case DevFmtInt: + case DevFmtFloat: + break; + } + switch(device->FmtChans) + { + case DevFmtMono: chanmask = 0x04; break; + case DevFmtStereo: chanmask = 0x01 | 0x02; break; + case DevFmtQuad: chanmask = 0x01 | 0x02 | 0x10 | 0x20; break; + case DevFmtX51: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x200 | 0x400; break; + case DevFmtX51Rear: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020; break; + case DevFmtX61: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400; break; + case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break; + case DevFmtAmbi3D: + /* .amb output requires FuMa */ + device->AmbiLayout = AmbiLayout_FuMa; + device->AmbiScale = AmbiNorm_FuMa; + isbformat = 1; + chanmask = 0; + break; + } + bits = BytesFromDevFmt(device->FmtType) * 8; + channels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + + fputs("RIFF", self->mFile); + fwrite32le(0xFFFFFFFF, self->mFile); // 'RIFF' header len; filled in at close + + fputs("WAVE", self->mFile); + + fputs("fmt ", self->mFile); + fwrite32le(40, self->mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE + + // 16-bit val, format type id (extensible: 0xFFFE) + fwrite16le(0xFFFE, self->mFile); + // 16-bit val, channel count + fwrite16le(channels, self->mFile); + // 32-bit val, frequency + fwrite32le(device->Frequency, self->mFile); + // 32-bit val, bytes per second + fwrite32le(device->Frequency * channels * bits / 8, self->mFile); + // 16-bit val, frame size + fwrite16le(channels * bits / 8, self->mFile); + // 16-bit val, bits per sample + fwrite16le(bits, self->mFile); + // 16-bit val, extra byte count + fwrite16le(22, self->mFile); + // 16-bit val, valid bits per sample + fwrite16le(bits, self->mFile); + // 32-bit val, channel mask + fwrite32le(chanmask, self->mFile); + // 16 byte GUID, sub-type format + val = fwrite((device->FmtType == DevFmtFloat) ? + (isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) : + (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM), 1, 16, self->mFile); + (void)val; + + fputs("data", self->mFile); + fwrite32le(0xFFFFFFFF, self->mFile); // 'data' header len; filled in at close + + if(ferror(self->mFile)) + { + ERR("Error writing header: %s\n", strerror(errno)); + return ALC_FALSE; + } + self->mDataStart = ftell(self->mFile); + + SetDefaultWFXChannelOrder(device); + + return ALC_TRUE; +} + +static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + + self->mSize = device->UpdateSize * FrameSizeFromDevFmt( + device->FmtChans, device->FmtType, device->AmbiOrder + ); + self->mBuffer = malloc(self->mSize); + if(!self->mBuffer) + { + ERR("Buffer malloc failed\n"); + return ALC_FALSE; + } + + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); + if(althrd_create(&self->thread, ALCwaveBackend_mixerProc, self) != althrd_success) + { + free(self->mBuffer); + self->mBuffer = nullptr; + self->mSize = 0; + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static void ALCwaveBackend_stop(ALCwaveBackend *self) +{ + ALuint dataLen; + long size; + int res; + + if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) + return; + althrd_join(self->thread, &res); + + free(self->mBuffer); + self->mBuffer = nullptr; + + size = ftell(self->mFile); + if(size > 0) + { + dataLen = size - self->mDataStart; + if(fseek(self->mFile, self->mDataStart-4, SEEK_SET) == 0) + fwrite32le(dataLen, self->mFile); // 'data' header len + if(fseek(self->mFile, 4, SEEK_SET) == 0) + fwrite32le(size-8, self->mFile); // 'WAVE' header len + } +} + + +struct ALCwaveBackendFactory final : public ALCbackendFactory { + ALCwaveBackendFactory() noexcept; +}; +#define ALCWAVEBACKENDFACTORY_INITIALIZER GET_VTABLE2(ALCwaveBackendFactory, ALCbackendFactory) + +ALCbackendFactory *ALCwaveBackendFactory_getFactory(void); + +static ALCboolean ALCwaveBackendFactory_init(ALCwaveBackendFactory *self); +static DECLARE_FORWARD(ALCwaveBackendFactory, ALCbackendFactory, void, deinit) +static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory *self, ALCbackend_Type type); +static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory *self, enum DevProbe type, al_string *outnames); +static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory *self, ALCdevice *device, ALCbackend_Type type); +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwaveBackendFactory); + + +ALCwaveBackendFactory::ALCwaveBackendFactory() noexcept + : ALCbackendFactory{ALCWAVEBACKENDFACTORY_INITIALIZER} +{ +} + + +static ALCboolean ALCwaveBackendFactory_init(ALCwaveBackendFactory* UNUSED(self)) +{ + return ALC_TRUE; +} + +static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + return !!ConfigValueExists(nullptr, "wave", "file"); + return ALC_FALSE; +} + +static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +{ + switch(type) + { + case ALL_DEVICE_PROBE: + alstr_append_range(outnames, waveDevice, waveDevice+sizeof(waveDevice)); + break; + case CAPTURE_DEVICE_PROBE: + break; + } +} + +static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCwaveBackend *backend; + NEW_OBJ(backend, ALCwaveBackend)(device); + if(!backend) return nullptr; + return STATIC_CAST(ALCbackend, backend); + } + + return nullptr; +} + +ALCbackendFactory *ALCwaveBackendFactory_getFactory(void) +{ + static ALCwaveBackendFactory factory{}; + return STATIC_CAST(ALCbackendFactory, &factory); +} diff --git a/CMakeLists.txt b/CMakeLists.txt index e59b93c4..b9eb49a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1306,7 +1306,7 @@ ENDIF() OPTION(ALSOFT_BACKEND_WAVE "Enable Wave Writer backend" ON) IF(ALSOFT_BACKEND_WAVE) SET(HAVE_WAVE 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/wave.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/wave.cpp) SET(BACKENDS "${BACKENDS} WaveFile,") ENDIF() -- cgit v1.2.3 From b327a50a15a6b0a9991fe59fa5dc775f195b7994 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 9 Nov 2018 02:55:28 -0800 Subject: Add missing consttructor and destructor calls for the wave backend --- Alc/backends/wave.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index d4e5bf97..4f3947e5 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -104,6 +104,7 @@ DEFINE_ALCBACKEND_VTABLE(ALCwaveBackend); static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device) { + new (self) ALCwaveBackend{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCwaveBackend, ALCbackend, self); @@ -123,6 +124,7 @@ static void ALCwaveBackend_Destruct(ALCwaveBackend *self) self->mFile = nullptr; ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCwaveBackend(); } static int ALCwaveBackend_mixerProc(void *ptr) -- cgit v1.2.3 From 781ca7c58b9aac363afffb75b017e4dcffebb0ad Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 9 Nov 2018 02:57:39 -0800 Subject: Convert the loopback backend to C++ --- Alc/backends/loopback.c | 128 ------------------------------------------- Alc/backends/loopback.cpp | 135 ++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 136 insertions(+), 129 deletions(-) delete mode 100644 Alc/backends/loopback.c create mode 100644 Alc/backends/loopback.cpp diff --git a/Alc/backends/loopback.c b/Alc/backends/loopback.c deleted file mode 100644 index e9940086..00000000 --- a/Alc/backends/loopback.c +++ /dev/null @@ -1,128 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2011 by Chris Robinson - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include - -#include "alMain.h" -#include "alu.h" - -#include "backends/base.h" - - -typedef struct ALCloopback { - DERIVE_FROM_TYPE(ALCbackend); -} ALCloopback; - -static void ALCloopback_Construct(ALCloopback *self, ALCdevice *device); -static DECLARE_FORWARD(ALCloopback, ALCbackend, void, Destruct) -static ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name); -static ALCboolean ALCloopback_reset(ALCloopback *self); -static ALCboolean ALCloopback_start(ALCloopback *self); -static void ALCloopback_stop(ALCloopback *self); -static DECLARE_FORWARD2(ALCloopback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCloopback, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCloopback, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCloopback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCloopback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCloopback) -DEFINE_ALCBACKEND_VTABLE(ALCloopback); - - -static void ALCloopback_Construct(ALCloopback *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCloopback, ALCbackend, self); -} - - -static ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - - alstr_copy_cstr(&device->DeviceName, name); - return ALC_NO_ERROR; -} - -static ALCboolean ALCloopback_reset(ALCloopback *self) -{ - SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice); - return ALC_TRUE; -} - -static ALCboolean ALCloopback_start(ALCloopback* UNUSED(self)) -{ - return ALC_TRUE; -} - -static void ALCloopback_stop(ALCloopback* UNUSED(self)) -{ -} - - -typedef struct ALCloopbackFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCloopbackFactory; -#define ALCNULLBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCloopbackFactory, ALCbackendFactory) } } - -ALCbackendFactory *ALCloopbackFactory_getFactory(void); -static ALCboolean ALCloopbackFactory_init(ALCloopbackFactory *self); -static DECLARE_FORWARD(ALCloopbackFactory, ALCbackendFactory, void, deinit) -static ALCboolean ALCloopbackFactory_querySupport(ALCloopbackFactory *self, ALCbackend_Type type); -static void ALCloopbackFactory_probe(ALCloopbackFactory *self, enum DevProbe type, al_string *outnames); -static ALCbackend* ALCloopbackFactory_createBackend(ALCloopbackFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCloopbackFactory); - - -ALCbackendFactory *ALCloopbackFactory_getFactory(void) -{ - static ALCloopbackFactory factory = ALCNULLBACKENDFACTORY_INITIALIZER; - return STATIC_CAST(ALCbackendFactory, &factory); -} - -static ALCboolean ALCloopbackFactory_init(ALCloopbackFactory* UNUSED(self)) -{ - return ALC_TRUE; -} - -static ALCboolean ALCloopbackFactory_querySupport(ALCloopbackFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Loopback) - return ALC_TRUE; - return ALC_FALSE; -} - -static void ALCloopbackFactory_probe(ALCloopbackFactory* UNUSED(self), enum DevProbe UNUSED(type), al_string* UNUSED(outnames)) -{ -} - -static ALCbackend* ALCloopbackFactory_createBackend(ALCloopbackFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -{ - if(type == ALCbackend_Loopback) - { - ALCloopback *backend; - NEW_OBJ(backend, ALCloopback)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} diff --git a/Alc/backends/loopback.cpp b/Alc/backends/loopback.cpp new file mode 100644 index 00000000..dd012ae5 --- /dev/null +++ b/Alc/backends/loopback.cpp @@ -0,0 +1,135 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2011 by Chris Robinson + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "alMain.h" +#include "alu.h" + +#include "backends/base.h" + + +struct ALCloopback final : public ALCbackend { +}; + +static void ALCloopback_Construct(ALCloopback *self, ALCdevice *device); +static void ALCloopback_Destruct(ALCloopback *self); +static ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name); +static ALCboolean ALCloopback_reset(ALCloopback *self); +static ALCboolean ALCloopback_start(ALCloopback *self); +static void ALCloopback_stop(ALCloopback *self); +static DECLARE_FORWARD2(ALCloopback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +static DECLARE_FORWARD(ALCloopback, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(ALCloopback, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCloopback, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCloopback, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCloopback) +DEFINE_ALCBACKEND_VTABLE(ALCloopback); + + +static void ALCloopback_Construct(ALCloopback *self, ALCdevice *device) +{ + new (self) ALCloopback{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCloopback, ALCbackend, self); +} + +static void ALCloopback_Destruct(ALCloopback *self) +{ + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCloopback(); +} + + +static ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + + alstr_copy_cstr(&device->DeviceName, name); + return ALC_NO_ERROR; +} + +static ALCboolean ALCloopback_reset(ALCloopback *self) +{ + SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice); + return ALC_TRUE; +} + +static ALCboolean ALCloopback_start(ALCloopback* UNUSED(self)) +{ + return ALC_TRUE; +} + +static void ALCloopback_stop(ALCloopback* UNUSED(self)) +{ +} + + +struct ALCloopbackFactory final : public ALCbackendFactory { + ALCloopbackFactory() noexcept; +}; + +ALCbackendFactory *ALCloopbackFactory_getFactory(void); +static ALCboolean ALCloopbackFactory_init(ALCloopbackFactory *self); +static DECLARE_FORWARD(ALCloopbackFactory, ALCbackendFactory, void, deinit) +static ALCboolean ALCloopbackFactory_querySupport(ALCloopbackFactory *self, ALCbackend_Type type); +static void ALCloopbackFactory_probe(ALCloopbackFactory *self, enum DevProbe type, al_string *outnames); +static ALCbackend* ALCloopbackFactory_createBackend(ALCloopbackFactory *self, ALCdevice *device, ALCbackend_Type type); +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCloopbackFactory); + +ALCloopbackFactory::ALCloopbackFactory() noexcept + : ALCbackendFactory{GET_VTABLE2(ALCloopbackFactory, ALCbackendFactory)} +{ } + + +static ALCboolean ALCloopbackFactory_init(ALCloopbackFactory* UNUSED(self)) +{ + return ALC_TRUE; +} + +static ALCboolean ALCloopbackFactory_querySupport(ALCloopbackFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Loopback) + return ALC_TRUE; + return ALC_FALSE; +} + +static void ALCloopbackFactory_probe(ALCloopbackFactory* UNUSED(self), enum DevProbe UNUSED(type), al_string* UNUSED(outnames)) +{ +} + +static ALCbackend* ALCloopbackFactory_createBackend(ALCloopbackFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Loopback) + { + ALCloopback *backend; + NEW_OBJ(backend, ALCloopback)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + + return NULL; +} + +ALCbackendFactory *ALCloopbackFactory_getFactory(void) +{ + static ALCloopbackFactory factory{}; + return STATIC_CAST(ALCbackendFactory, &factory); +} diff --git a/CMakeLists.txt b/CMakeLists.txt index b9eb49a1..b51c0367 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1031,7 +1031,7 @@ SET(ALC_OBJS ${ALC_OBJS} Alc/backends/base.c Alc/backends/base.h # Default backends, always available - Alc/backends/loopback.c + Alc/backends/loopback.cpp Alc/backends/null.c ) -- cgit v1.2.3 From e8679e72140438b7fb9d2fe672914b056d1a3171 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 9 Nov 2018 03:46:30 -0800 Subject: Convert the null backend to C++ --- Alc/backends/null.c | 220 ----------------------------------------------- Alc/backends/null.cpp | 232 ++++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 233 insertions(+), 221 deletions(-) delete mode 100644 Alc/backends/null.c create mode 100644 Alc/backends/null.cpp diff --git a/Alc/backends/null.c b/Alc/backends/null.c deleted file mode 100644 index d1c110e8..00000000 --- a/Alc/backends/null.c +++ /dev/null @@ -1,220 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2010 by Chris Robinson - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#ifdef HAVE_WINDOWS_H -#include -#endif - -#include "alMain.h" -#include "alu.h" -#include "threads.h" -#include "compat.h" - -#include "backends/base.h" - - -typedef struct ALCnullBackend { - DERIVE_FROM_TYPE(ALCbackend); - - ATOMIC(int) killNow; - althrd_t thread; -} ALCnullBackend; - -static int ALCnullBackend_mixerProc(void *ptr); - -static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device); -static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, Destruct) -static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name); -static ALCboolean ALCnullBackend_reset(ALCnullBackend *self); -static ALCboolean ALCnullBackend_start(ALCnullBackend *self); -static void ALCnullBackend_stop(ALCnullBackend *self); -static DECLARE_FORWARD2(ALCnullBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCnullBackend, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCnullBackend, ALCbackend, ClockLatency, getClockLatency) -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"; - - -static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCnullBackend, ALCbackend, self); - - ATOMIC_INIT(&self->killNow, AL_TRUE); -} - - -static int ALCnullBackend_mixerProc(void *ptr) -{ - ALCnullBackend *self = (ALCnullBackend*)ptr; - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - struct timespec now, start; - ALuint64 avail, done; - const long restTime = (long)((ALuint64)device->UpdateSize * 1000000000 / - device->Frequency / 2); - - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - done = 0; - if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC) - { - ERR("Failed to get starting time\n"); - return 1; - } - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) - { - if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC) - { - ERR("Failed to get current time\n"); - return 1; - } - - avail = (now.tv_sec - start.tv_sec) * device->Frequency; - avail += (ALint64)(now.tv_nsec - start.tv_nsec) * device->Frequency / 1000000000; - if(avail < done) - { - /* 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(restTime); - else while(avail-done >= device->UpdateSize) - { - ALCnullBackend_lock(self); - aluMixData(device, NULL, device->UpdateSize); - ALCnullBackend_unlock(self); - done += device->UpdateSize; - } - } - - return 0; -} - - -static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name) -{ - ALCdevice *device; - - if(!name) - name = nullDevice; - else if(strcmp(name, nullDevice) != 0) - return ALC_INVALID_VALUE; - - device = STATIC_CAST(ALCbackend, self)->mDevice; - alstr_copy_cstr(&device->DeviceName, name); - - return ALC_NO_ERROR; -} - -static ALCboolean ALCnullBackend_reset(ALCnullBackend *self) -{ - SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice); - return ALC_TRUE; -} - -static ALCboolean ALCnullBackend_start(ALCnullBackend *self) -{ - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); - if(althrd_create(&self->thread, ALCnullBackend_mixerProc, self) != althrd_success) - return ALC_FALSE; - return ALC_TRUE; -} - -static void ALCnullBackend_stop(ALCnullBackend *self) -{ - int res; - - if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) - return; - althrd_join(self->thread, &res); -} - - -typedef struct ALCnullBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCnullBackendFactory; -#define ALCNULLBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCnullBackendFactory, ALCbackendFactory) } } - -ALCbackendFactory *ALCnullBackendFactory_getFactory(void); - -static ALCboolean ALCnullBackendFactory_init(ALCnullBackendFactory *self); -static DECLARE_FORWARD(ALCnullBackendFactory, ALCbackendFactory, void, deinit) -static ALCboolean ALCnullBackendFactory_querySupport(ALCnullBackendFactory *self, ALCbackend_Type type); -static void ALCnullBackendFactory_probe(ALCnullBackendFactory *self, enum DevProbe type, al_string *outnames); -static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCnullBackendFactory); - - -ALCbackendFactory *ALCnullBackendFactory_getFactory(void) -{ - static ALCnullBackendFactory factory = ALCNULLBACKENDFACTORY_INITIALIZER; - return STATIC_CAST(ALCbackendFactory, &factory); -} - - -static ALCboolean ALCnullBackendFactory_init(ALCnullBackendFactory* UNUSED(self)) -{ - return ALC_TRUE; -} - -static ALCboolean ALCnullBackendFactory_querySupport(ALCnullBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - return ALC_TRUE; - return ALC_FALSE; -} - -static void ALCnullBackendFactory_probe(ALCnullBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) -{ - switch(type) - { - case ALL_DEVICE_PROBE: - case CAPTURE_DEVICE_PROBE: - alstr_append_range(outnames, nullDevice, nullDevice+sizeof(nullDevice)); - break; - } -} - -static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - { - ALCnullBackend *backend; - NEW_OBJ(backend, ALCnullBackend)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp new file mode 100644 index 00000000..2e1c6ac9 --- /dev/null +++ b/Alc/backends/null.cpp @@ -0,0 +1,232 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2010 by Chris Robinson + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include "alMain.h" +#include "alu.h" +#include "threads.h" +#include "compat.h" + +#include "backends/base.h" + + +namespace { + +constexpr ALCchar nullDevice[] = "No Output"; + +} // namespace + +struct ALCnullBackend final : public ALCbackend { + ATOMIC(int) killNow; + althrd_t thread; +}; + +static int ALCnullBackend_mixerProc(void *ptr); + +static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device); +static void ALCnullBackend_Destruct(ALCnullBackend *self); +static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name); +static ALCboolean ALCnullBackend_reset(ALCnullBackend *self); +static ALCboolean ALCnullBackend_start(ALCnullBackend *self); +static void ALCnullBackend_stop(ALCnullBackend *self); +static DECLARE_FORWARD2(ALCnullBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +static DECLARE_FORWARD(ALCnullBackend, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(ALCnullBackend, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCnullBackend) + +DEFINE_ALCBACKEND_VTABLE(ALCnullBackend); + + +static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device) +{ + new (self) ALCnullBackend{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCnullBackend, ALCbackend, self); + + ATOMIC_INIT(&self->killNow, AL_TRUE); +} + +static void ALCnullBackend_Destruct(ALCnullBackend *self) +{ + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCnullBackend(); +} + + +static int ALCnullBackend_mixerProc(void *ptr) +{ + ALCnullBackend *self = (ALCnullBackend*)ptr; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + struct timespec now, start; + ALuint64 avail, done; + const long restTime = (long)((ALuint64)device->UpdateSize * 1000000000 / + device->Frequency / 2); + + SetRTPriority(); + althrd_setname(althrd_current(), MIXER_THREAD_NAME); + + done = 0; + if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC) + { + ERR("Failed to get starting time\n"); + return 1; + } + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + { + if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC) + { + ERR("Failed to get current time\n"); + return 1; + } + + avail = (now.tv_sec - start.tv_sec) * device->Frequency; + avail += (ALint64)(now.tv_nsec - start.tv_nsec) * device->Frequency / 1000000000; + if(avail < done) + { + /* 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(restTime); + else while(avail-done >= device->UpdateSize) + { + ALCnullBackend_lock(self); + aluMixData(device, NULL, device->UpdateSize); + ALCnullBackend_unlock(self); + done += device->UpdateSize; + } + } + + return 0; +} + + +static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name) +{ + ALCdevice *device; + + if(!name) + name = nullDevice; + else if(strcmp(name, nullDevice) != 0) + return ALC_INVALID_VALUE; + + device = STATIC_CAST(ALCbackend, self)->mDevice; + alstr_copy_cstr(&device->DeviceName, name); + + return ALC_NO_ERROR; +} + +static ALCboolean ALCnullBackend_reset(ALCnullBackend *self) +{ + SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice); + return ALC_TRUE; +} + +static ALCboolean ALCnullBackend_start(ALCnullBackend *self) +{ + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); + if(althrd_create(&self->thread, ALCnullBackend_mixerProc, self) != althrd_success) + return ALC_FALSE; + return ALC_TRUE; +} + +static void ALCnullBackend_stop(ALCnullBackend *self) +{ + int res; + + if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) + return; + althrd_join(self->thread, &res); +} + + +struct ALCnullBackendFactory final : public ALCbackendFactory { + ALCnullBackendFactory() noexcept; +}; + +ALCbackendFactory *ALCnullBackendFactory_getFactory(void); + +static ALCboolean ALCnullBackendFactory_init(ALCnullBackendFactory *self); +static DECLARE_FORWARD(ALCnullBackendFactory, ALCbackendFactory, void, deinit) +static ALCboolean ALCnullBackendFactory_querySupport(ALCnullBackendFactory *self, ALCbackend_Type type); +static void ALCnullBackendFactory_probe(ALCnullBackendFactory *self, enum DevProbe type, al_string *outnames); +static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory *self, ALCdevice *device, ALCbackend_Type type); +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCnullBackendFactory); + +ALCnullBackendFactory::ALCnullBackendFactory() noexcept + : ALCbackendFactory{GET_VTABLE2(ALCnullBackendFactory, ALCbackendFactory)} +{ +} + + +ALCbackendFactory *ALCnullBackendFactory_getFactory(void) +{ + static ALCnullBackendFactory factory{}; + return STATIC_CAST(ALCbackendFactory, &factory); +} + + +static ALCboolean ALCnullBackendFactory_init(ALCnullBackendFactory* UNUSED(self)) +{ + return ALC_TRUE; +} + +static ALCboolean ALCnullBackendFactory_querySupport(ALCnullBackendFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + return ALC_TRUE; + return ALC_FALSE; +} + +static void ALCnullBackendFactory_probe(ALCnullBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +{ + switch(type) + { + case ALL_DEVICE_PROBE: + case CAPTURE_DEVICE_PROBE: + alstr_append_range(outnames, nullDevice, nullDevice+sizeof(nullDevice)); + break; + } +} + +static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCnullBackend *backend; + NEW_OBJ(backend, ALCnullBackend)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + + return NULL; +} diff --git a/CMakeLists.txt b/CMakeLists.txt index b51c0367..3731e82e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1032,7 +1032,7 @@ SET(ALC_OBJS ${ALC_OBJS} Alc/backends/base.h # Default backends, always available Alc/backends/loopback.cpp - Alc/backends/null.c + Alc/backends/null.cpp ) # Check ALSA backend -- cgit v1.2.3 From db56fd5e3df68808b44880012397dd18a644cba5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 9 Nov 2018 18:08:42 -0800 Subject: Convert hrtf.c to C++ --- Alc/hrtf.c | 1465 -------------------------------------------------------- Alc/hrtf.cpp | 1410 +++++++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 1411 insertions(+), 1466 deletions(-) delete mode 100644 Alc/hrtf.c create mode 100644 Alc/hrtf.cpp diff --git a/Alc/hrtf.c b/Alc/hrtf.c deleted file mode 100644 index ce602ee1..00000000 --- a/Alc/hrtf.c +++ /dev/null @@ -1,1465 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2011 by Chris Robinson - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "alMain.h" -#include "alSource.h" -#include "alu.h" -#include "hrtf.h" -#include "alconfig.h" -#include "filters/splitter.h" - -#include "compat.h" -#include "almalloc.h" - - -/* Current data set limits defined by the makehrtf utility. */ -#define MIN_IR_SIZE (8) -#define MAX_IR_SIZE (512) -#define MOD_IR_SIZE (8) - -#define MIN_FD_COUNT (1) -#define MAX_FD_COUNT (16) - -#define MIN_FD_DISTANCE (50) -#define MAX_FD_DISTANCE (2500) - -#define MIN_EV_COUNT (5) -#define MAX_EV_COUNT (128) - -#define MIN_AZ_COUNT (1) -#define MAX_AZ_COUNT (128) - -#define MAX_HRIR_DELAY (HRTF_HISTORY_LENGTH-1) - -struct HrtfEntry { - struct HrtfEntry *next; - struct Hrtf *handle; - char filename[]; -}; - -static const ALchar magicMarker00[8] = "MinPHR00"; -static const ALchar magicMarker01[8] = "MinPHR01"; -static const ALchar magicMarker02[8] = "MinPHR02"; - -/* First value for pass-through coefficients (remaining are 0), used for omni- - * directional sounds. */ -static const ALfloat PassthruCoeff = 0.707106781187f/*sqrt(0.5)*/; - -static ATOMIC_FLAG LoadedHrtfLock = ATOMIC_FLAG_INIT; -static struct HrtfEntry *LoadedHrtfs = NULL; - - -/* Calculate the elevation index given the polar elevation in radians. This - * will return an index between 0 and (evcount - 1). - */ -static ALsizei CalcEvIndex(ALsizei evcount, ALfloat ev, ALfloat *mu) -{ - ALsizei idx; - ev = (F_PI_2+ev) * (evcount-1) / F_PI; - idx = float2int(ev); - - *mu = ev - idx; - return mini(idx, evcount-1); -} - -/* Calculate the azimuth index given the polar azimuth in radians. This will - * return an index between 0 and (azcount - 1). - */ -static ALsizei CalcAzIndex(ALsizei azcount, ALfloat az, ALfloat *mu) -{ - ALsizei idx; - az = (F_TAU+az) * azcount / F_TAU; - - idx = float2int(az); - *mu = az - idx; - return idx % azcount; -} - -/* Calculates static HRIR coefficients and delays for the given polar elevation - * and azimuth in radians. The coefficients are normalized. - */ -void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, - ALfloat (*RESTRICT coeffs)[2], ALsizei *delays) -{ - ALsizei evidx, azidx, idx[4]; - ALsizei evoffset; - ALfloat emu, amu[2]; - ALfloat blend[4]; - ALfloat dirfact; - ALsizei i, c; - - dirfact = 1.0f - (spread / F_TAU); - - /* Claculate the lower elevation index. */ - evidx = CalcEvIndex(Hrtf->evCount, elevation, &emu); - evoffset = Hrtf->evOffset[evidx]; - - /* Calculate lower azimuth index. */ - azidx= CalcAzIndex(Hrtf->azCount[evidx], azimuth, &amu[0]); - - /* Calculate the lower HRIR indices. */ - idx[0] = evoffset + azidx; - idx[1] = evoffset + ((azidx+1) % Hrtf->azCount[evidx]); - if(evidx < Hrtf->evCount-1) - { - /* Increment elevation to the next (upper) index. */ - evidx++; - evoffset = Hrtf->evOffset[evidx]; - - /* Calculate upper azimuth index. */ - azidx = CalcAzIndex(Hrtf->azCount[evidx], azimuth, &amu[1]); - - /* Calculate the upper HRIR indices. */ - idx[2] = evoffset + azidx; - idx[3] = evoffset + ((azidx+1) % Hrtf->azCount[evidx]); - } - else - { - /* If the lower elevation is the top index, the upper elevation is the - * same as the lower. - */ - amu[1] = amu[0]; - idx[2] = idx[0]; - idx[3] = idx[1]; - } - - /* Calculate bilinear blending weights, attenuated according to the - * directional panning factor. - */ - blend[0] = (1.0f-emu) * (1.0f-amu[0]) * dirfact; - blend[1] = (1.0f-emu) * ( amu[0]) * dirfact; - blend[2] = ( emu) * (1.0f-amu[1]) * dirfact; - blend[3] = ( emu) * ( amu[1]) * dirfact; - - /* Calculate the blended HRIR delays. */ - delays[0] = fastf2i( - Hrtf->delays[idx[0]][0]*blend[0] + Hrtf->delays[idx[1]][0]*blend[1] + - Hrtf->delays[idx[2]][0]*blend[2] + Hrtf->delays[idx[3]][0]*blend[3] - ); - delays[1] = fastf2i( - Hrtf->delays[idx[0]][1]*blend[0] + Hrtf->delays[idx[1]][1]*blend[1] + - Hrtf->delays[idx[2]][1]*blend[2] + Hrtf->delays[idx[3]][1]*blend[3] - ); - - /* Calculate the sample offsets for the HRIR indices. */ - idx[0] *= Hrtf->irSize; - idx[1] *= Hrtf->irSize; - idx[2] *= Hrtf->irSize; - idx[3] *= Hrtf->irSize; - - ASSUME(Hrtf->irSize >= MIN_IR_SIZE && (Hrtf->irSize%MOD_IR_SIZE) == 0); - coeffs = ASSUME_ALIGNED(coeffs, 16); - /* Calculate the blended HRIR coefficients. */ - coeffs[0][0] = PassthruCoeff * (1.0f-dirfact); - coeffs[0][1] = PassthruCoeff * (1.0f-dirfact); - for(i = 1;i < Hrtf->irSize;i++) - { - coeffs[i][0] = 0.0f; - coeffs[i][1] = 0.0f; - } - for(c = 0;c < 4;c++) - { - const ALfloat (*RESTRICT srccoeffs)[2] = ASSUME_ALIGNED(Hrtf->coeffs+idx[c], 16); - for(i = 0;i < Hrtf->irSize;i++) - { - coeffs[i][0] += srccoeffs[i][0] * blend[c]; - coeffs[i][1] += srccoeffs[i][1] * blend[c]; - } - } -} - - -void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const struct AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_COEFFS], ALsizei AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain) -{ -/* Set this to 2 for dual-band HRTF processing. May require a higher quality - * band-splitter, or better calculation of the new IR length to deal with the - * tail generated by the filter. - */ -#define NUM_BANDS 2 - BandSplitter splitter; - ALdouble (*tmpres)[HRIR_LENGTH][2]; - ALsizei *RESTRICT idx; - ALsizei min_delay = HRTF_HISTORY_LENGTH; - ALsizei max_delay = 0; - ALfloat temps[3][HRIR_LENGTH]; - ALsizei max_length; - ALsizei i, c, b; - - idx = al_calloc(DEF_ALIGN, AmbiCount*sizeof(*idx)); - - for(c = 0;c < AmbiCount;c++) - { - ALuint evidx, azidx; - ALuint evoffset; - ALuint azcount; - - /* Calculate elevation index. */ - evidx = (ALsizei)((F_PI_2+AmbiPoints[c].Elev) * (Hrtf->evCount-1) / F_PI + 0.5f); - evidx = clampi(evidx, 0, Hrtf->evCount-1); - - azcount = Hrtf->azCount[evidx]; - evoffset = Hrtf->evOffset[evidx]; - - /* Calculate azimuth index for this elevation. */ - azidx = (ALsizei)((F_TAU+AmbiPoints[c].Azim) * azcount / F_TAU + 0.5f) % azcount; - - /* Calculate indices for left and right channels. */ - idx[c] = evoffset + azidx; - - min_delay = mini(min_delay, mini(Hrtf->delays[idx[c]][0], Hrtf->delays[idx[c]][1])); - max_delay = maxi(max_delay, maxi(Hrtf->delays[idx[c]][0], Hrtf->delays[idx[c]][1])); - } - - tmpres = al_calloc(16, NumChannels * sizeof(*tmpres)); - - memset(temps, 0, sizeof(temps)); - bandsplit_init(&splitter, 400.0f / (ALfloat)Hrtf->sampleRate); - for(c = 0;c < AmbiCount;c++) - { - const ALfloat (*fir)[2] = &Hrtf->coeffs[idx[c] * Hrtf->irSize]; - ALsizei ldelay = Hrtf->delays[idx[c]][0] - min_delay; - ALsizei rdelay = Hrtf->delays[idx[c]][1] - min_delay; - - if(NUM_BANDS == 1) - { - for(i = 0;i < NumChannels;++i) - { - ALdouble mult = (ALdouble)AmbiOrderHFGain[(ALsizei)sqrt(i)] * AmbiMatrix[c][i]; - ALsizei lidx = ldelay, ridx = rdelay; - ALsizei j = 0; - while(lidx < HRIR_LENGTH && ridx < HRIR_LENGTH && j < Hrtf->irSize) - { - tmpres[i][lidx++][0] += fir[j][0] * mult; - tmpres[i][ridx++][1] += fir[j][1] * mult; - j++; - } - } - } - else - { - /* Band-split left HRIR into low and high frequency responses. */ - bandsplit_clear(&splitter); - for(i = 0;i < Hrtf->irSize;i++) - temps[2][i] = fir[i][0]; - bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); - - /* Apply left ear response with delay. */ - for(i = 0;i < NumChannels;++i) - { - ALfloat hfgain = AmbiOrderHFGain[(ALsizei)sqrt(i)]; - for(b = 0;b < NUM_BANDS;b++) - { - ALdouble mult = AmbiMatrix[c][i] * (ALdouble)((b==0) ? hfgain : 1.0); - ALsizei lidx = ldelay; - ALsizei j = 0; - while(lidx < HRIR_LENGTH) - tmpres[i][lidx++][0] += temps[b][j++] * mult; - } - } - - /* Band-split right HRIR into low and high frequency responses. */ - bandsplit_clear(&splitter); - for(i = 0;i < Hrtf->irSize;i++) - temps[2][i] = fir[i][1]; - bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); - - /* Apply right ear response with delay. */ - for(i = 0;i < NumChannels;++i) - { - ALfloat hfgain = AmbiOrderHFGain[(ALsizei)sqrt(i)]; - for(b = 0;b < NUM_BANDS;b++) - { - ALdouble mult = AmbiMatrix[c][i] * (ALdouble)((b==0) ? hfgain : 1.0); - ALsizei ridx = rdelay; - ALsizei j = 0; - while(ridx < HRIR_LENGTH) - tmpres[i][ridx++][1] += temps[b][j++] * mult; - } - } - } - } - - for(i = 0;i < NumChannels;++i) - { - int idx; - for(idx = 0;idx < HRIR_LENGTH;idx++) - { - state->Chan[i].Coeffs[idx][0] = (ALfloat)tmpres[i][idx][0]; - state->Chan[i].Coeffs[idx][1] = (ALfloat)tmpres[i][idx][1]; - } - } - al_free(tmpres); - tmpres = NULL; - al_free(idx); - idx = NULL; - - if(NUM_BANDS == 1) - max_length = mini(max_delay-min_delay + Hrtf->irSize, HRIR_LENGTH); - else - { - /* Increase the IR size by 2/3rds to account for the tail generated by - * the band-split filter. - */ - const ALsizei irsize = mini(Hrtf->irSize*5/3, HRIR_LENGTH); - max_length = mini(max_delay-min_delay + irsize, HRIR_LENGTH); - } - /* Round up to the next IR size multiple. */ - max_length += MOD_IR_SIZE-1; - max_length -= max_length%MOD_IR_SIZE; - - TRACE("Skipped delay: %d, max delay: %d, new FIR length: %d\n", - min_delay, max_delay-min_delay, max_length); - state->IrSize = max_length; -#undef NUM_BANDS -} - - -static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, - ALfloat distance, ALsizei evCount, ALsizei irCount, const ALubyte *azCount, - const ALushort *evOffset, const ALfloat (*coeffs)[2], const ALubyte (*delays)[2], - const char *filename) -{ - struct Hrtf *Hrtf; - size_t total; - - total = sizeof(struct Hrtf); - total += sizeof(Hrtf->azCount[0])*evCount; - total = RoundUp(total, sizeof(ALushort)); /* Align for ushort fields */ - total += sizeof(Hrtf->evOffset[0])*evCount; - total = RoundUp(total, 16); /* Align for coefficients using SIMD */ - total += sizeof(Hrtf->coeffs[0])*irSize*irCount; - total += sizeof(Hrtf->delays[0])*irCount; - - Hrtf = al_calloc(16, total); - if(Hrtf == NULL) - ERR("Out of memory allocating storage for %s.\n", filename); - else - { - uintptr_t offset = sizeof(struct Hrtf); - char *base = (char*)Hrtf; - ALushort *_evOffset; - ALubyte *_azCount; - ALubyte (*_delays)[2]; - ALfloat (*_coeffs)[2]; - ALsizei i; - - InitRef(&Hrtf->ref, 0); - Hrtf->sampleRate = rate; - Hrtf->irSize = irSize; - Hrtf->distance = distance; - Hrtf->evCount = evCount; - - /* Set up pointers to storage following the main HRTF struct. */ - _azCount = (ALubyte*)(base + offset); - offset += sizeof(_azCount[0])*evCount; - - offset = RoundUp(offset, sizeof(ALushort)); /* Align for ushort fields */ - _evOffset = (ALushort*)(base + offset); - offset += sizeof(_evOffset[0])*evCount; - - offset = RoundUp(offset, 16); /* Align for coefficients using SIMD */ - _coeffs = (ALfloat(*)[2])(base + offset); - offset += sizeof(_coeffs[0])*irSize*irCount; - - _delays = (ALubyte(*)[2])(base + offset); - offset += sizeof(_delays[0])*irCount; - - assert(offset == total); - - /* Copy input data to storage. */ - for(i = 0;i < evCount;i++) _azCount[i] = azCount[i]; - for(i = 0;i < evCount;i++) _evOffset[i] = evOffset[i]; - for(i = 0;i < irSize*irCount;i++) - { - _coeffs[i][0] = coeffs[i][0]; - _coeffs[i][1] = coeffs[i][1]; - } - for(i = 0;i < irCount;i++) - { - _delays[i][0] = delays[i][0]; - _delays[i][1] = delays[i][1]; - } - - /* Finally, assign the storage pointers. */ - Hrtf->azCount = _azCount; - Hrtf->evOffset = _evOffset; - Hrtf->coeffs = _coeffs; - Hrtf->delays = _delays; - } - - return Hrtf; -} - -static ALubyte GetLE_ALubyte(const ALubyte **data, size_t *len) -{ - ALubyte ret = (*data)[0]; - *data += 1; *len -= 1; - return ret; -} - -static ALshort GetLE_ALshort(const ALubyte **data, size_t *len) -{ - ALshort ret = (*data)[0] | ((*data)[1]<<8); - *data += 2; *len -= 2; - return ret; -} - -static ALushort GetLE_ALushort(const ALubyte **data, size_t *len) -{ - ALushort ret = (*data)[0] | ((*data)[1]<<8); - *data += 2; *len -= 2; - return ret; -} - -static ALint GetLE_ALint24(const ALubyte **data, size_t *len) -{ - ALint ret = (*data)[0] | ((*data)[1]<<8) | ((*data)[2]<<16); - *data += 3; *len -= 3; - return (ret^0x800000) - 0x800000; -} - -static ALuint GetLE_ALuint(const ALubyte **data, size_t *len) -{ - ALuint ret = (*data)[0] | ((*data)[1]<<8) | ((*data)[2]<<16) | ((*data)[3]<<24); - *data += 4; *len -= 4; - return ret; -} - -static const ALubyte *Get_ALubytePtr(const ALubyte **data, size_t *len, size_t size) -{ - const ALubyte *ret = *data; - *data += size; *len -= size; - return ret; -} - -static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char *filename) -{ - struct Hrtf *Hrtf = NULL; - ALboolean failed = AL_FALSE; - ALuint rate = 0; - ALushort irCount = 0; - ALushort irSize = 0; - ALubyte evCount = 0; - ALubyte *azCount = NULL; - ALushort *evOffset = NULL; - ALfloat (*coeffs)[2] = NULL; - ALubyte (*delays)[2] = NULL; - ALsizei i, j; - - if(datalen < 9) - { - ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n", filename, 9, datalen); - return NULL; - } - - rate = GetLE_ALuint(&data, &datalen); - - irCount = GetLE_ALushort(&data, &datalen); - - irSize = GetLE_ALushort(&data, &datalen); - - evCount = GetLE_ALubyte(&data, &datalen); - - if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) - { - ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", - irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE); - failed = AL_TRUE; - } - if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT) - { - ERR("Unsupported elevation count: evCount=%d (%d to %d)\n", - evCount, MIN_EV_COUNT, MAX_EV_COUNT); - failed = AL_TRUE; - } - if(failed) - return NULL; - - if(datalen < evCount*2u) - { - ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n", filename, evCount*2, datalen); - return NULL; - } - - azCount = malloc(sizeof(azCount[0])*evCount); - evOffset = malloc(sizeof(evOffset[0])*evCount); - if(azCount == NULL || evOffset == NULL) - { - ERR("Out of memory.\n"); - failed = AL_TRUE; - } - - if(!failed) - { - evOffset[0] = GetLE_ALushort(&data, &datalen); - for(i = 1;i < evCount;i++) - { - evOffset[i] = GetLE_ALushort(&data, &datalen); - if(evOffset[i] <= evOffset[i-1]) - { - ERR("Invalid evOffset: evOffset[%d]=%d (last=%d)\n", - i, evOffset[i], evOffset[i-1]); - failed = AL_TRUE; - } - - azCount[i-1] = evOffset[i] - evOffset[i-1]; - if(azCount[i-1] < MIN_AZ_COUNT || azCount[i-1] > MAX_AZ_COUNT) - { - ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", - i-1, azCount[i-1], MIN_AZ_COUNT, MAX_AZ_COUNT); - failed = AL_TRUE; - } - } - if(irCount <= evOffset[i-1]) - { - ERR("Invalid evOffset: evOffset[%d]=%d (irCount=%d)\n", - i-1, evOffset[i-1], irCount); - failed = AL_TRUE; - } - - azCount[i-1] = irCount - evOffset[i-1]; - if(azCount[i-1] < MIN_AZ_COUNT || azCount[i-1] > MAX_AZ_COUNT) - { - ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", - i-1, azCount[i-1], MIN_AZ_COUNT, MAX_AZ_COUNT); - failed = AL_TRUE; - } - } - - if(!failed) - { - coeffs = malloc(sizeof(coeffs[0])*irSize*irCount); - delays = malloc(sizeof(delays[0])*irCount); - if(coeffs == NULL || delays == NULL) - { - ERR("Out of memory.\n"); - failed = AL_TRUE; - } - } - - if(!failed) - { - size_t reqsize = 2*irSize*irCount + irCount; - if(datalen < reqsize) - { - ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT")\n", - filename, reqsize, datalen); - failed = AL_TRUE; - } - } - - if(!failed) - { - for(i = 0;i < irCount;i++) - { - for(j = 0;j < irSize;j++) - coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f; - } - - for(i = 0;i < irCount;i++) - { - delays[i][0] = GetLE_ALubyte(&data, &datalen); - if(delays[i][0] > MAX_HRIR_DELAY) - { - ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); - failed = AL_TRUE; - } - } - } - - if(!failed) - { - /* Mirror the left ear responses to the right ear. */ - for(i = 0;i < evCount;i++) - { - ALushort evoffset = evOffset[i]; - ALubyte azcount = azCount[i]; - for(j = 0;j < azcount;j++) - { - ALsizei lidx = evoffset + j; - ALsizei ridx = evoffset + ((azcount-j) % azcount); - ALsizei k; - - for(k = 0;k < irSize;k++) - coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; - delays[ridx][1] = delays[lidx][0]; - } - } - - Hrtf = CreateHrtfStore(rate, irSize, 0.0f, evCount, irCount, azCount, - evOffset, coeffs, delays, filename); - } - - free(azCount); - free(evOffset); - free(coeffs); - free(delays); - return Hrtf; -} - -static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char *filename) -{ - struct Hrtf *Hrtf = NULL; - ALboolean failed = AL_FALSE; - ALuint rate = 0; - ALushort irCount = 0; - ALushort irSize = 0; - ALubyte evCount = 0; - const ALubyte *azCount = NULL; - ALushort *evOffset = NULL; - ALfloat (*coeffs)[2] = NULL; - ALubyte (*delays)[2] = NULL; - ALsizei i, j; - - if(datalen < 6) - { - ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", filename, 6, datalen); - return NULL; - } - - rate = GetLE_ALuint(&data, &datalen); - - irSize = GetLE_ALubyte(&data, &datalen); - - evCount = GetLE_ALubyte(&data, &datalen); - - if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) - { - ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", - irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE); - failed = AL_TRUE; - } - if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT) - { - ERR("Unsupported elevation count: evCount=%d (%d to %d)\n", - evCount, MIN_EV_COUNT, MAX_EV_COUNT); - failed = AL_TRUE; - } - if(failed) - return NULL; - - if(datalen < evCount) - { - ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", filename, evCount, datalen); - return NULL; - } - - azCount = Get_ALubytePtr(&data, &datalen, evCount); - - evOffset = malloc(sizeof(evOffset[0])*evCount); - if(azCount == NULL || evOffset == NULL) - { - ERR("Out of memory.\n"); - failed = AL_TRUE; - } - - if(!failed) - { - for(i = 0;i < evCount;i++) - { - if(azCount[i] < MIN_AZ_COUNT || azCount[i] > MAX_AZ_COUNT) - { - ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", - i, azCount[i], MIN_AZ_COUNT, MAX_AZ_COUNT); - failed = AL_TRUE; - } - } - } - - if(!failed) - { - evOffset[0] = 0; - irCount = azCount[0]; - for(i = 1;i < evCount;i++) - { - evOffset[i] = evOffset[i-1] + azCount[i-1]; - irCount += azCount[i]; - } - - coeffs = malloc(sizeof(coeffs[0])*irSize*irCount); - delays = malloc(sizeof(delays[0])*irCount); - if(coeffs == NULL || delays == NULL) - { - ERR("Out of memory.\n"); - failed = AL_TRUE; - } - } - - if(!failed) - { - size_t reqsize = 2*irSize*irCount + irCount; - if(datalen < reqsize) - { - ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT"\n", - filename, reqsize, datalen); - failed = AL_TRUE; - } - } - - if(!failed) - { - for(i = 0;i < irCount;i++) - { - for(j = 0;j < irSize;j++) - coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f; - } - - for(i = 0;i < irCount;i++) - { - delays[i][0] = GetLE_ALubyte(&data, &datalen); - if(delays[i][0] > MAX_HRIR_DELAY) - { - ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); - failed = AL_TRUE; - } - } - } - - if(!failed) - { - /* Mirror the left ear responses to the right ear. */ - for(i = 0;i < evCount;i++) - { - ALushort evoffset = evOffset[i]; - ALubyte azcount = azCount[i]; - for(j = 0;j < azcount;j++) - { - ALsizei lidx = evoffset + j; - ALsizei ridx = evoffset + ((azcount-j) % azcount); - ALsizei k; - - for(k = 0;k < irSize;k++) - coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; - delays[ridx][1] = delays[lidx][0]; - } - } - - Hrtf = CreateHrtfStore(rate, irSize, 0.0f, evCount, irCount, azCount, - evOffset, coeffs, delays, filename); - } - - free(evOffset); - free(coeffs); - free(delays); - return Hrtf; -} - -#define SAMPLETYPE_S16 0 -#define SAMPLETYPE_S24 1 - -#define CHANTYPE_LEFTONLY 0 -#define CHANTYPE_LEFTRIGHT 1 - -static struct Hrtf *LoadHrtf02(const ALubyte *data, size_t datalen, const char *filename) -{ - struct Hrtf *Hrtf = NULL; - ALboolean failed = AL_FALSE; - ALuint rate = 0; - ALubyte sampleType; - ALubyte channelType; - ALushort irCount = 0; - ALushort irSize = 0; - ALubyte fdCount = 0; - ALushort distance = 0; - ALubyte evCount = 0; - const ALubyte *azCount = NULL; - ALushort *evOffset = NULL; - ALfloat (*coeffs)[2] = NULL; - ALubyte (*delays)[2] = NULL; - ALsizei i, j; - - if(datalen < 8) - { - ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", filename, 8, datalen); - return NULL; - } - - rate = GetLE_ALuint(&data, &datalen); - sampleType = GetLE_ALubyte(&data, &datalen); - channelType = GetLE_ALubyte(&data, &datalen); - - irSize = GetLE_ALubyte(&data, &datalen); - - fdCount = GetLE_ALubyte(&data, &datalen); - - if(sampleType > SAMPLETYPE_S24) - { - ERR("Unsupported sample type: %d\n", sampleType); - failed = AL_TRUE; - } - if(channelType > CHANTYPE_LEFTRIGHT) - { - ERR("Unsupported channel type: %d\n", channelType); - failed = AL_TRUE; - } - - if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) - { - ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", - irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE); - failed = AL_TRUE; - } - if(fdCount != 1) - { - ERR("Multiple field-depths not supported: fdCount=%d (%d to %d)\n", - evCount, MIN_FD_COUNT, MAX_FD_COUNT); - failed = AL_TRUE; - } - if(failed) - return NULL; - - for(i = 0;i < fdCount;i++) - { - if(datalen < 3) - { - ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", filename, 3, datalen); - return NULL; - } - - distance = GetLE_ALushort(&data, &datalen); - if(distance < MIN_FD_DISTANCE || distance > MAX_FD_DISTANCE) - { - ERR("Unsupported field distance: distance=%d (%dmm to %dmm)\n", - distance, MIN_FD_DISTANCE, MAX_FD_DISTANCE); - failed = AL_TRUE; - } - - evCount = GetLE_ALubyte(&data, &datalen); - if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT) - { - ERR("Unsupported elevation count: evCount=%d (%d to %d)\n", - evCount, MIN_EV_COUNT, MAX_EV_COUNT); - failed = AL_TRUE; - } - if(failed) - return NULL; - - if(datalen < evCount) - { - ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", filename, evCount, datalen); - return NULL; - } - - azCount = Get_ALubytePtr(&data, &datalen, evCount); - for(j = 0;j < evCount;j++) - { - if(azCount[j] < MIN_AZ_COUNT || azCount[j] > MAX_AZ_COUNT) - { - ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", - j, azCount[j], MIN_AZ_COUNT, MAX_AZ_COUNT); - failed = AL_TRUE; - } - } - } - if(failed) - return NULL; - - evOffset = malloc(sizeof(evOffset[0])*evCount); - if(azCount == NULL || evOffset == NULL) - { - ERR("Out of memory.\n"); - failed = AL_TRUE; - } - - if(!failed) - { - evOffset[0] = 0; - irCount = azCount[0]; - for(i = 1;i < evCount;i++) - { - evOffset[i] = evOffset[i-1] + azCount[i-1]; - irCount += azCount[i]; - } - - coeffs = malloc(sizeof(coeffs[0])*irSize*irCount); - delays = malloc(sizeof(delays[0])*irCount); - if(coeffs == NULL || delays == NULL) - { - ERR("Out of memory.\n"); - failed = AL_TRUE; - } - } - - if(!failed) - { - size_t reqsize = 2*irSize*irCount + irCount; - if(datalen < reqsize) - { - ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT"\n", - filename, reqsize, datalen); - failed = AL_TRUE; - } - } - - if(!failed) - { - if(channelType == CHANTYPE_LEFTONLY) - { - if(sampleType == SAMPLETYPE_S16) - for(i = 0;i < irCount;i++) - { - for(j = 0;j < irSize;j++) - coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f; - } - else if(sampleType == SAMPLETYPE_S24) - for(i = 0;i < irCount;i++) - { - for(j = 0;j < irSize;j++) - coeffs[i*irSize + j][0] = GetLE_ALint24(&data, &datalen) / 8388608.0f; - } - - for(i = 0;i < irCount;i++) - { - delays[i][0] = GetLE_ALubyte(&data, &datalen); - if(delays[i][0] > MAX_HRIR_DELAY) - { - ERR("Invalid delays[%d][0]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); - failed = AL_TRUE; - } - } - } - else if(channelType == CHANTYPE_LEFTRIGHT) - { - if(sampleType == SAMPLETYPE_S16) - for(i = 0;i < irCount;i++) - { - for(j = 0;j < irSize;j++) - { - coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f; - coeffs[i*irSize + j][1] = GetLE_ALshort(&data, &datalen) / 32768.0f; - } - } - else if(sampleType == SAMPLETYPE_S24) - for(i = 0;i < irCount;i++) - { - for(j = 0;j < irSize;j++) - { - coeffs[i*irSize + j][0] = GetLE_ALint24(&data, &datalen) / 8388608.0f; - coeffs[i*irSize + j][1] = GetLE_ALint24(&data, &datalen) / 8388608.0f; - } - } - - for(i = 0;i < irCount;i++) - { - delays[i][0] = GetLE_ALubyte(&data, &datalen); - if(delays[i][0] > MAX_HRIR_DELAY) - { - ERR("Invalid delays[%d][0]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); - failed = AL_TRUE; - } - delays[i][1] = GetLE_ALubyte(&data, &datalen); - if(delays[i][1] > MAX_HRIR_DELAY) - { - ERR("Invalid delays[%d][1]: %d (%d)\n", i, delays[i][1], MAX_HRIR_DELAY); - failed = AL_TRUE; - } - } - } - } - - if(!failed) - { - if(channelType == CHANTYPE_LEFTONLY) - { - /* Mirror the left ear responses to the right ear. */ - for(i = 0;i < evCount;i++) - { - ALushort evoffset = evOffset[i]; - ALubyte azcount = azCount[i]; - for(j = 0;j < azcount;j++) - { - ALsizei lidx = evoffset + j; - ALsizei ridx = evoffset + ((azcount-j) % azcount); - ALsizei k; - - for(k = 0;k < irSize;k++) - coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; - delays[ridx][1] = delays[lidx][0]; - } - } - } - - Hrtf = CreateHrtfStore(rate, irSize, - (ALfloat)distance / 1000.0f, evCount, irCount, azCount, evOffset, - coeffs, delays, filename - ); - } - - free(evOffset); - free(coeffs); - free(delays); - return Hrtf; -} - - -static void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename) -{ - EnumeratedHrtf entry = { AL_STRING_INIT_STATIC(), NULL }; - struct HrtfEntry *loaded_entry; - const EnumeratedHrtf *iter; - const char *name; - const char *ext; - int i; - - /* Check if this file has already been loaded globally. */ - loaded_entry = LoadedHrtfs; - while(loaded_entry) - { - if(alstr_cmp_cstr(filename, loaded_entry->filename) == 0) - { - /* Check if this entry has already been added to the list. */ -#define MATCH_ENTRY(i) (loaded_entry == (i)->hrtf) - VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_ENTRY); -#undef MATCH_ENTRY - if(iter != VECTOR_END(*list)) - { - TRACE("Skipping duplicate file entry %s\n", alstr_get_cstr(filename)); - return; - } - - break; - } - loaded_entry = loaded_entry->next; - } - - if(!loaded_entry) - { - TRACE("Got new file \"%s\"\n", alstr_get_cstr(filename)); - - loaded_entry = al_calloc(DEF_ALIGN, - FAM_SIZE(struct HrtfEntry, filename, alstr_length(filename)+1) - ); - loaded_entry->next = LoadedHrtfs; - loaded_entry->handle = NULL; - strcpy(loaded_entry->filename, alstr_get_cstr(filename)); - LoadedHrtfs = loaded_entry; - } - - /* TODO: Get a human-readable name from the HRTF data (possibly coming in a - * format update). */ - name = strrchr(alstr_get_cstr(filename), '/'); - if(!name) name = strrchr(alstr_get_cstr(filename), '\\'); - if(!name) name = alstr_get_cstr(filename); - else ++name; - - ext = strrchr(name, '.'); - - i = 0; - do { - if(!ext) - alstr_copy_cstr(&entry.name, name); - else - alstr_copy_range(&entry.name, name, ext); - if(i != 0) - { - char str[64]; - snprintf(str, sizeof(str), " #%d", i+1); - alstr_append_cstr(&entry.name, str); - } - ++i; - -#define MATCH_NAME(i) (alstr_cmp(entry.name, (i)->name) == 0) - VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_NAME); -#undef MATCH_NAME - } while(iter != VECTOR_END(*list)); - entry.hrtf = loaded_entry; - - TRACE("Adding entry \"%s\" from file \"%s\"\n", alstr_get_cstr(entry.name), - alstr_get_cstr(filename)); - VECTOR_PUSH_BACK(*list, entry); -} - -/* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer - * for input instead of opening the given filename. - */ -static void AddBuiltInEntry(vector_EnumeratedHrtf *list, const_al_string filename, ALuint residx) -{ - EnumeratedHrtf entry = { AL_STRING_INIT_STATIC(), NULL }; - struct HrtfEntry *loaded_entry; - struct Hrtf *hrtf = NULL; - const EnumeratedHrtf *iter; - const char *name; - const char *ext; - int i; - - loaded_entry = LoadedHrtfs; - while(loaded_entry) - { - if(alstr_cmp_cstr(filename, loaded_entry->filename) == 0) - { -#define MATCH_ENTRY(i) (loaded_entry == (i)->hrtf) - VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_ENTRY); -#undef MATCH_ENTRY - if(iter != VECTOR_END(*list)) - { - TRACE("Skipping duplicate file entry %s\n", alstr_get_cstr(filename)); - return; - } - - break; - } - loaded_entry = loaded_entry->next; - } - - if(!loaded_entry) - { - size_t namelen = alstr_length(filename)+32; - - TRACE("Got new file \"%s\"\n", alstr_get_cstr(filename)); - - loaded_entry = al_calloc(DEF_ALIGN, - FAM_SIZE(struct HrtfEntry, filename, namelen) - ); - loaded_entry->next = LoadedHrtfs; - loaded_entry->handle = hrtf; - snprintf(loaded_entry->filename, namelen, "!%u_%s", - residx, alstr_get_cstr(filename)); - LoadedHrtfs = loaded_entry; - } - - /* TODO: Get a human-readable name from the HRTF data (possibly coming in a - * format update). */ - name = strrchr(alstr_get_cstr(filename), '/'); - if(!name) name = strrchr(alstr_get_cstr(filename), '\\'); - if(!name) name = alstr_get_cstr(filename); - else ++name; - - ext = strrchr(name, '.'); - - i = 0; - do { - if(!ext) - alstr_copy_cstr(&entry.name, name); - else - alstr_copy_range(&entry.name, name, ext); - if(i != 0) - { - char str[64]; - snprintf(str, sizeof(str), " #%d", i+1); - alstr_append_cstr(&entry.name, str); - } - ++i; - -#define MATCH_NAME(i) (alstr_cmp(entry.name, (i)->name) == 0) - VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_NAME); -#undef MATCH_NAME - } while(iter != VECTOR_END(*list)); - entry.hrtf = loaded_entry; - - TRACE("Adding built-in entry \"%s\"\n", alstr_get_cstr(entry.name)); - VECTOR_PUSH_BACK(*list, entry); -} - - -#define IDR_DEFAULT_44100_MHR 1 -#define IDR_DEFAULT_48000_MHR 2 - -#ifndef ALSOFT_EMBED_HRTF_DATA - -static const ALubyte *GetResource(int UNUSED(name), size_t *size) -{ - *size = 0; - return NULL; -} - -#else - -#include "default-44100.mhr.h" -#include "default-48000.mhr.h" - -static const ALubyte *GetResource(int name, size_t *size) -{ - if(name == IDR_DEFAULT_44100_MHR) - { - *size = sizeof(hrtf_default_44100); - return hrtf_default_44100; - } - if(name == IDR_DEFAULT_48000_MHR) - { - *size = sizeof(hrtf_default_48000); - return hrtf_default_48000; - } - *size = 0; - return NULL; -} -#endif - -vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname) -{ - vector_EnumeratedHrtf list = VECTOR_INIT_STATIC(); - const char *defaulthrtf = ""; - const char *pathlist = ""; - bool usedefaults = true; - - if(ConfigValueStr(alstr_get_cstr(devname), NULL, "hrtf-paths", &pathlist)) - { - al_string pname = AL_STRING_INIT_STATIC(); - while(pathlist && *pathlist) - { - const char *next, *end; - - while(isspace(*pathlist) || *pathlist == ',') - pathlist++; - if(*pathlist == '\0') - continue; - - next = strchr(pathlist, ','); - if(next) - end = next++; - else - { - end = pathlist + strlen(pathlist); - usedefaults = false; - } - - while(end != pathlist && isspace(*(end-1))) - --end; - if(end != pathlist) - { - vector_al_string flist; - size_t i; - - alstr_copy_range(&pname, pathlist, end); - - flist = SearchDataFiles(".mhr", alstr_get_cstr(pname)); - for(i = 0;i < VECTOR_SIZE(flist);i++) - AddFileEntry(&list, VECTOR_ELEM(flist, i)); - VECTOR_FOR_EACH(al_string, flist, alstr_reset); - VECTOR_DEINIT(flist); - } - - pathlist = next; - } - - alstr_reset(&pname); - } - else if(ConfigValueExists(alstr_get_cstr(devname), NULL, "hrtf_tables")) - ERR("The hrtf_tables option is deprecated, please use hrtf-paths instead.\n"); - - if(usedefaults) - { - al_string ename = AL_STRING_INIT_STATIC(); - vector_al_string flist; - const ALubyte *rdata; - size_t rsize, i; - - flist = SearchDataFiles(".mhr", "openal/hrtf"); - for(i = 0;i < VECTOR_SIZE(flist);i++) - AddFileEntry(&list, VECTOR_ELEM(flist, i)); - VECTOR_FOR_EACH(al_string, flist, alstr_reset); - VECTOR_DEINIT(flist); - - rdata = GetResource(IDR_DEFAULT_44100_MHR, &rsize); - if(rdata != NULL && rsize > 0) - { - alstr_copy_cstr(&ename, "Built-In 44100hz"); - AddBuiltInEntry(&list, ename, IDR_DEFAULT_44100_MHR); - } - - rdata = GetResource(IDR_DEFAULT_48000_MHR, &rsize); - if(rdata != NULL && rsize > 0) - { - alstr_copy_cstr(&ename, "Built-In 48000hz"); - AddBuiltInEntry(&list, ename, IDR_DEFAULT_48000_MHR); - } - alstr_reset(&ename); - } - - if(VECTOR_SIZE(list) > 1 && ConfigValueStr(alstr_get_cstr(devname), NULL, "default-hrtf", &defaulthrtf)) - { - const EnumeratedHrtf *iter; - /* Find the preferred HRTF and move it to the front of the list. */ -#define FIND_ENTRY(i) (alstr_cmp_cstr((i)->name, defaulthrtf) == 0) - VECTOR_FIND_IF(iter, const EnumeratedHrtf, list, FIND_ENTRY); -#undef FIND_ENTRY - if(iter == VECTOR_END(list)) - WARN("Failed to find default HRTF \"%s\"\n", defaulthrtf); - else if(iter != VECTOR_BEGIN(list)) - { - EnumeratedHrtf entry = *iter; - memmove(&VECTOR_ELEM(list,1), &VECTOR_ELEM(list,0), - (iter-VECTOR_BEGIN(list))*sizeof(EnumeratedHrtf)); - VECTOR_ELEM(list,0) = entry; - } - } - - return list; -} - -void FreeHrtfList(vector_EnumeratedHrtf *list) -{ -#define CLEAR_ENTRY(i) alstr_reset(&(i)->name) - VECTOR_FOR_EACH(EnumeratedHrtf, *list, CLEAR_ENTRY); - VECTOR_DEINIT(*list); -#undef CLEAR_ENTRY -} - -struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry) -{ - struct Hrtf *hrtf = NULL; - struct FileMapping fmap; - const ALubyte *rdata; - const char *name; - ALuint residx; - size_t rsize; - char ch; - - while(ATOMIC_FLAG_TEST_AND_SET(&LoadedHrtfLock, almemory_order_seq_cst)) - althrd_yield(); - - if(entry->handle) - { - hrtf = entry->handle; - Hrtf_IncRef(hrtf); - goto done; - } - - fmap.ptr = NULL; - fmap.len = 0; - if(sscanf(entry->filename, "!%u%c", &residx, &ch) == 2 && ch == '_') - { - name = strchr(entry->filename, ch)+1; - - TRACE("Loading %s...\n", name); - rdata = GetResource(residx, &rsize); - if(rdata == NULL || rsize == 0) - { - ERR("Could not get resource %u, %s\n", residx, name); - goto done; - } - } - else - { - name = entry->filename; - - TRACE("Loading %s...\n", entry->filename); - fmap = MapFileToMem(entry->filename); - if(fmap.ptr == NULL) - { - ERR("Could not open %s\n", entry->filename); - goto done; - } - - rdata = fmap.ptr; - rsize = fmap.len; - } - - if(rsize < sizeof(magicMarker02)) - ERR("%s data is too short ("SZFMT" bytes)\n", name, rsize); - else if(memcmp(rdata, magicMarker02, sizeof(magicMarker02)) == 0) - { - TRACE("Detected data set format v2\n"); - hrtf = LoadHrtf02(rdata+sizeof(magicMarker02), - rsize-sizeof(magicMarker02), name - ); - } - else if(memcmp(rdata, magicMarker01, sizeof(magicMarker01)) == 0) - { - TRACE("Detected data set format v1\n"); - hrtf = LoadHrtf01(rdata+sizeof(magicMarker01), - rsize-sizeof(magicMarker01), name - ); - } - else if(memcmp(rdata, magicMarker00, sizeof(magicMarker00)) == 0) - { - TRACE("Detected data set format v0\n"); - hrtf = LoadHrtf00(rdata+sizeof(magicMarker00), - rsize-sizeof(magicMarker00), name - ); - } - else - ERR("Invalid header in %s: \"%.8s\"\n", name, (const char*)rdata); - if(fmap.ptr) - UnmapFileMem(&fmap); - - if(!hrtf) - { - ERR("Failed to load %s\n", name); - goto done; - } - entry->handle = hrtf; - Hrtf_IncRef(hrtf); - - TRACE("Loaded HRTF support for format: %s %uhz\n", - DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); - -done: - ATOMIC_FLAG_CLEAR(&LoadedHrtfLock, almemory_order_seq_cst); - return hrtf; -} - - -void Hrtf_IncRef(struct Hrtf *hrtf) -{ - uint ref = IncrementRef(&hrtf->ref); - TRACEREF("%p increasing refcount to %u\n", hrtf, ref); -} - -void Hrtf_DecRef(struct Hrtf *hrtf) -{ - struct HrtfEntry *Hrtf; - uint ref = DecrementRef(&hrtf->ref); - TRACEREF("%p decreasing refcount to %u\n", hrtf, ref); - if(ref == 0) - { - while(ATOMIC_FLAG_TEST_AND_SET(&LoadedHrtfLock, almemory_order_seq_cst)) - althrd_yield(); - - Hrtf = LoadedHrtfs; - while(Hrtf != NULL) - { - /* Need to double-check that it's still unused, as another device - * could've reacquired this HRTF after its reference went to 0 and - * before the lock was taken. - */ - if(hrtf == Hrtf->handle && ReadRef(&hrtf->ref) == 0) - { - al_free(Hrtf->handle); - Hrtf->handle = NULL; - TRACE("Unloaded unused HRTF %s\n", Hrtf->filename); - } - Hrtf = Hrtf->next; - } - - ATOMIC_FLAG_CLEAR(&LoadedHrtfLock, almemory_order_seq_cst); - } -} - - -void FreeHrtfs(void) -{ - struct HrtfEntry *Hrtf = LoadedHrtfs; - LoadedHrtfs = NULL; - - while(Hrtf != NULL) - { - struct HrtfEntry *next = Hrtf->next; - al_free(Hrtf->handle); - al_free(Hrtf); - Hrtf = next; - } -} diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp new file mode 100644 index 00000000..ce7c46f3 --- /dev/null +++ b/Alc/hrtf.cpp @@ -0,0 +1,1410 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2011 by Chris Robinson + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "alMain.h" +#include "alSource.h" +#include "alu.h" +#include "hrtf.h" +#include "alconfig.h" +#include "filters/splitter.h" + +#include "compat.h" +#include "almalloc.h" + + +struct HrtfEntry { + struct HrtfEntry *next; + struct Hrtf *handle; + char filename[]; +}; + +namespace { + +/* Current data set limits defined by the makehrtf utility. */ +#define MIN_IR_SIZE (8) +#define MAX_IR_SIZE (512) +#define MOD_IR_SIZE (8) + +#define MIN_FD_COUNT (1) +#define MAX_FD_COUNT (16) + +#define MIN_FD_DISTANCE (50) +#define MAX_FD_DISTANCE (2500) + +#define MIN_EV_COUNT (5) +#define MAX_EV_COUNT (128) + +#define MIN_AZ_COUNT (1) +#define MAX_AZ_COUNT (128) + +#define MAX_HRIR_DELAY (HRTF_HISTORY_LENGTH-1) + +constexpr ALchar magicMarker00[8]{'M','i','n','P','H','R','0','0'}; +constexpr ALchar magicMarker01[8]{'M','i','n','P','H','R','0','1'}; +constexpr ALchar magicMarker02[8]{'M','i','n','P','H','R','0','2'}; + +/* First value for pass-through coefficients (remaining are 0), used for omni- + * directional sounds. */ +constexpr ALfloat PassthruCoeff = 0.707106781187f/*sqrt(0.5)*/; + +ATOMIC_FLAG LoadedHrtfLock = ATOMIC_FLAG_INIT; +struct HrtfEntry *LoadedHrtfs = NULL; + + +/* Calculate the elevation index given the polar elevation in radians. This + * will return an index between 0 and (evcount - 1). + */ +ALsizei CalcEvIndex(ALsizei evcount, ALfloat ev, ALfloat *mu) +{ + ALsizei idx; + ev = (F_PI_2+ev) * (evcount-1) / F_PI; + idx = float2int(ev); + + *mu = ev - idx; + return mini(idx, evcount-1); +} + +/* Calculate the azimuth index given the polar azimuth in radians. This will + * return an index between 0 and (azcount - 1). + */ +ALsizei CalcAzIndex(ALsizei azcount, ALfloat az, ALfloat *mu) +{ + ALsizei idx; + az = (F_TAU+az) * azcount / F_TAU; + + idx = float2int(az); + *mu = az - idx; + return idx % azcount; +} + +} // namespace + + +/* Calculates static HRIR coefficients and delays for the given polar elevation + * and azimuth in radians. The coefficients are normalized. + */ +void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, + ALfloat (*RESTRICT coeffs)[2], ALsizei *delays) +{ + ALsizei evidx, azidx, idx[4]; + ALsizei evoffset; + ALfloat emu, amu[2]; + ALfloat blend[4]; + ALfloat dirfact; + ALsizei i, c; + + dirfact = 1.0f - (spread / F_TAU); + + /* Claculate the lower elevation index. */ + evidx = CalcEvIndex(Hrtf->evCount, elevation, &emu); + evoffset = Hrtf->evOffset[evidx]; + + /* Calculate lower azimuth index. */ + azidx= CalcAzIndex(Hrtf->azCount[evidx], azimuth, &amu[0]); + + /* Calculate the lower HRIR indices. */ + idx[0] = evoffset + azidx; + idx[1] = evoffset + ((azidx+1) % Hrtf->azCount[evidx]); + if(evidx < Hrtf->evCount-1) + { + /* Increment elevation to the next (upper) index. */ + evidx++; + evoffset = Hrtf->evOffset[evidx]; + + /* Calculate upper azimuth index. */ + azidx = CalcAzIndex(Hrtf->azCount[evidx], azimuth, &amu[1]); + + /* Calculate the upper HRIR indices. */ + idx[2] = evoffset + azidx; + idx[3] = evoffset + ((azidx+1) % Hrtf->azCount[evidx]); + } + else + { + /* If the lower elevation is the top index, the upper elevation is the + * same as the lower. + */ + amu[1] = amu[0]; + idx[2] = idx[0]; + idx[3] = idx[1]; + } + + /* Calculate bilinear blending weights, attenuated according to the + * directional panning factor. + */ + blend[0] = (1.0f-emu) * (1.0f-amu[0]) * dirfact; + blend[1] = (1.0f-emu) * ( amu[0]) * dirfact; + blend[2] = ( emu) * (1.0f-amu[1]) * dirfact; + blend[3] = ( emu) * ( amu[1]) * dirfact; + + /* Calculate the blended HRIR delays. */ + delays[0] = fastf2i( + Hrtf->delays[idx[0]][0]*blend[0] + Hrtf->delays[idx[1]][0]*blend[1] + + Hrtf->delays[idx[2]][0]*blend[2] + Hrtf->delays[idx[3]][0]*blend[3] + ); + delays[1] = fastf2i( + Hrtf->delays[idx[0]][1]*blend[0] + Hrtf->delays[idx[1]][1]*blend[1] + + Hrtf->delays[idx[2]][1]*blend[2] + Hrtf->delays[idx[3]][1]*blend[3] + ); + + /* Calculate the sample offsets for the HRIR indices. */ + idx[0] *= Hrtf->irSize; + idx[1] *= Hrtf->irSize; + idx[2] *= Hrtf->irSize; + idx[3] *= Hrtf->irSize; + + ASSUME(Hrtf->irSize >= MIN_IR_SIZE && (Hrtf->irSize%MOD_IR_SIZE) == 0); + + /* Calculate the blended HRIR coefficients. */ + coeffs[0][0] = PassthruCoeff * (1.0f-dirfact); + coeffs[0][1] = PassthruCoeff * (1.0f-dirfact); + for(i = 1;i < Hrtf->irSize;i++) + { + coeffs[i][0] = 0.0f; + coeffs[i][1] = 0.0f; + } + for(c = 0;c < 4;c++) + { + const ALfloat (*RESTRICT srccoeffs)[2] = Hrtf->coeffs + idx[c]; + for(i = 0;i < Hrtf->irSize;i++) + { + coeffs[i][0] += srccoeffs[i][0] * blend[c]; + coeffs[i][1] += srccoeffs[i][1] * blend[c]; + } + } +} + + +void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const struct AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_COEFFS], ALsizei AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain) +{ +/* Set this to 2 for dual-band HRTF processing. May require a higher quality + * band-splitter, or better calculation of the new IR length to deal with the + * tail generated by the filter. + */ +#define NUM_BANDS 2 + ALsizei min_delay{HRTF_HISTORY_LENGTH}; + ALsizei max_delay{0}; + std::vector idx(AmbiCount); + for(ALsizei c{0};c < AmbiCount;c++) + { + ALuint evidx, azidx; + ALuint evoffset; + ALuint azcount; + + /* Calculate elevation index. */ + evidx = (ALsizei)((F_PI_2+AmbiPoints[c].Elev) * (Hrtf->evCount-1) / F_PI + 0.5f); + evidx = clampi(evidx, 0, Hrtf->evCount-1); + + azcount = Hrtf->azCount[evidx]; + evoffset = Hrtf->evOffset[evidx]; + + /* Calculate azimuth index for this elevation. */ + azidx = (ALsizei)((F_TAU+AmbiPoints[c].Azim) * azcount / F_TAU + 0.5f) % azcount; + + /* Calculate indices for left and right channels. */ + idx[c] = evoffset + azidx; + + min_delay = mini(min_delay, mini(Hrtf->delays[idx[c]][0], Hrtf->delays[idx[c]][1])); + max_delay = maxi(max_delay, maxi(Hrtf->delays[idx[c]][0], Hrtf->delays[idx[c]][1])); + } + + std::vector,HRIR_LENGTH>> tmpres(NumChannels); + ALfloat temps[3][HRIR_LENGTH]{}; + + BandSplitter splitter; + bandsplit_init(&splitter, 400.0f / (ALfloat)Hrtf->sampleRate); + for(ALsizei c{0};c < AmbiCount;++c) + { + const ALfloat (*fir)[2] = &Hrtf->coeffs[idx[c] * Hrtf->irSize]; + ALsizei ldelay = Hrtf->delays[idx[c]][0] - min_delay; + ALsizei rdelay = Hrtf->delays[idx[c]][1] - min_delay; + + if(NUM_BANDS == 1) + { + for(ALsizei i{0};i < NumChannels;++i) + { + ALdouble mult = (ALdouble)AmbiOrderHFGain[(ALsizei)sqrt(i)] * AmbiMatrix[c][i]; + ALsizei lidx = ldelay, ridx = rdelay; + ALsizei j = 0; + while(lidx < HRIR_LENGTH && ridx < HRIR_LENGTH && j < Hrtf->irSize) + { + tmpres[i][lidx++][0] += fir[j][0] * mult; + tmpres[i][ridx++][1] += fir[j][1] * mult; + j++; + } + } + } + else + { + /* Band-split left HRIR into low and high frequency responses. */ + bandsplit_clear(&splitter); + for(ALsizei i{0};i < Hrtf->irSize;++i) + temps[2][i] = fir[i][0]; + bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); + + /* Apply left ear response with delay. */ + for(ALsizei i{0};i < NumChannels;++i) + { + ALdouble hfgain = AmbiOrderHFGain[(ALsizei)sqrt(i)]; + for(ALsizei b{0};b < NUM_BANDS;++b) + { + ALdouble mult = AmbiMatrix[c][i] * ((b==0) ? hfgain : 1.0); + ALsizei lidx = ldelay; + ALsizei j = 0; + while(lidx < HRIR_LENGTH) + tmpres[i][lidx++][0] += temps[b][j++] * mult; + } + } + + /* Band-split right HRIR into low and high frequency responses. */ + bandsplit_clear(&splitter); + for(ALsizei i{0};i < Hrtf->irSize;++i) + temps[2][i] = fir[i][1]; + bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); + + /* Apply right ear response with delay. */ + for(ALsizei i{0};i < NumChannels;++i) + { + ALdouble hfgain = AmbiOrderHFGain[(ALsizei)sqrt(i)]; + for(ALsizei b{0};b < NUM_BANDS;++b) + { + ALdouble mult = AmbiMatrix[c][i] * ((b==0) ? hfgain : 1.0); + ALsizei ridx = rdelay; + ALsizei j = 0; + while(ridx < HRIR_LENGTH) + tmpres[i][ridx++][1] += temps[b][j++] * mult; + } + } + } + } + + for(ALsizei i{0};i < NumChannels;++i) + { + for(ALsizei idx{0};idx < HRIR_LENGTH;idx++) + { + state->Chan[i].Coeffs[idx][0] = (ALfloat)tmpres[i][idx][0]; + state->Chan[i].Coeffs[idx][1] = (ALfloat)tmpres[i][idx][1]; + } + } + tmpres.clear(); + idx.clear(); + + ALsizei max_length; + if(NUM_BANDS == 1) + max_length = mini(max_delay-min_delay + Hrtf->irSize, HRIR_LENGTH); + else + { + /* Increase the IR size by 2/3rds to account for the tail generated by + * the band-split filter. + */ + const ALsizei irsize = mini(Hrtf->irSize*5/3, HRIR_LENGTH); + max_length = mini(max_delay-min_delay + irsize, HRIR_LENGTH); + } + /* Round up to the next IR size multiple. */ + max_length += MOD_IR_SIZE-1; + max_length -= max_length%MOD_IR_SIZE; + + TRACE("Skipped delay: %d, max delay: %d, new FIR length: %d\n", + min_delay, max_delay-min_delay, max_length); + state->IrSize = max_length; +#undef NUM_BANDS +} + + +static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, + ALfloat distance, ALsizei evCount, ALsizei irCount, const ALubyte *azCount, + const ALushort *evOffset, const ALfloat (*coeffs)[2], const ALubyte (*delays)[2], + const char *filename) +{ + struct Hrtf *Hrtf; + size_t total; + + total = sizeof(struct Hrtf); + total += sizeof(Hrtf->azCount[0])*evCount; + total = RoundUp(total, sizeof(ALushort)); /* Align for ushort fields */ + total += sizeof(Hrtf->evOffset[0])*evCount; + total = RoundUp(total, 16); /* Align for coefficients using SIMD */ + total += sizeof(Hrtf->coeffs[0])*irSize*irCount; + total += sizeof(Hrtf->delays[0])*irCount; + + Hrtf = static_cast(al_calloc(16, total)); + if(Hrtf == NULL) + ERR("Out of memory allocating storage for %s.\n", filename); + else + { + uintptr_t offset = sizeof(struct Hrtf); + char *base = (char*)Hrtf; + ALushort *_evOffset; + ALubyte *_azCount; + ALubyte (*_delays)[2]; + ALfloat (*_coeffs)[2]; + ALsizei i; + + InitRef(&Hrtf->ref, 0); + Hrtf->sampleRate = rate; + Hrtf->irSize = irSize; + Hrtf->distance = distance; + Hrtf->evCount = evCount; + + /* Set up pointers to storage following the main HRTF struct. */ + _azCount = reinterpret_cast(base + offset); + offset += sizeof(_azCount[0])*evCount; + + offset = RoundUp(offset, sizeof(ALushort)); /* Align for ushort fields */ + _evOffset = reinterpret_cast(base + offset); + offset += sizeof(_evOffset[0])*evCount; + + offset = RoundUp(offset, 16); /* Align for coefficients using SIMD */ + _coeffs = reinterpret_cast(base + offset); + offset += sizeof(_coeffs[0])*irSize*irCount; + + _delays = reinterpret_cast(base + offset); + offset += sizeof(_delays[0])*irCount; + + assert(offset == total); + + /* Copy input data to storage. */ + for(i = 0;i < evCount;i++) _azCount[i] = azCount[i]; + for(i = 0;i < evCount;i++) _evOffset[i] = evOffset[i]; + for(i = 0;i < irSize*irCount;i++) + { + _coeffs[i][0] = coeffs[i][0]; + _coeffs[i][1] = coeffs[i][1]; + } + for(i = 0;i < irCount;i++) + { + _delays[i][0] = delays[i][0]; + _delays[i][1] = delays[i][1]; + } + + /* Finally, assign the storage pointers. */ + Hrtf->azCount = _azCount; + Hrtf->evOffset = _evOffset; + Hrtf->coeffs = _coeffs; + Hrtf->delays = _delays; + } + + return Hrtf; +} + +static ALubyte GetLE_ALubyte(const ALubyte **data, size_t *len) +{ + ALubyte ret = (*data)[0]; + *data += 1; *len -= 1; + return ret; +} + +static ALshort GetLE_ALshort(const ALubyte **data, size_t *len) +{ + ALshort ret = (*data)[0] | ((*data)[1]<<8); + *data += 2; *len -= 2; + return ret; +} + +static ALushort GetLE_ALushort(const ALubyte **data, size_t *len) +{ + ALushort ret = (*data)[0] | ((*data)[1]<<8); + *data += 2; *len -= 2; + return ret; +} + +static ALint GetLE_ALint24(const ALubyte **data, size_t *len) +{ + ALint ret = (*data)[0] | ((*data)[1]<<8) | ((*data)[2]<<16); + *data += 3; *len -= 3; + return (ret^0x800000) - 0x800000; +} + +static ALuint GetLE_ALuint(const ALubyte **data, size_t *len) +{ + ALuint ret = (*data)[0] | ((*data)[1]<<8) | ((*data)[2]<<16) | ((*data)[3]<<24); + *data += 4; *len -= 4; + return ret; +} + +static const ALubyte *Get_ALubytePtr(const ALubyte **data, size_t *len, size_t size) +{ + const ALubyte *ret = *data; + *data += size; *len -= size; + return ret; +} + +static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char *filename) +{ + struct Hrtf *Hrtf = NULL; + ALboolean failed = AL_FALSE; + ALuint rate = 0; + ALushort irCount = 0; + ALushort irSize = 0; + ALubyte evCount = 0; + std::vector azCount; + std::vector evOffset; + std::vector> coeffs; + std::vector> delays; + ALsizei i, j; + + if(datalen < 9) + { + ERR("Unexpected end of %s data (req %d, rem " SZFMT ")\n", filename, 9, datalen); + return NULL; + } + + rate = GetLE_ALuint(&data, &datalen); + + irCount = GetLE_ALushort(&data, &datalen); + + irSize = GetLE_ALushort(&data, &datalen); + + evCount = GetLE_ALubyte(&data, &datalen); + + if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) + { + ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", + irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE); + failed = AL_TRUE; + } + if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT) + { + ERR("Unsupported elevation count: evCount=%d (%d to %d)\n", + evCount, MIN_EV_COUNT, MAX_EV_COUNT); + failed = AL_TRUE; + } + if(failed) + return NULL; + + if(datalen < evCount*2u) + { + ERR("Unexpected end of %s data (req %d, rem " SZFMT ")\n", filename, evCount*2, datalen); + return NULL; + } + + azCount.resize(evCount); + evOffset.resize(evCount); + + evOffset[0] = GetLE_ALushort(&data, &datalen); + for(i = 1;i < evCount;i++) + { + evOffset[i] = GetLE_ALushort(&data, &datalen); + if(evOffset[i] <= evOffset[i-1]) + { + ERR("Invalid evOffset: evOffset[%d]=%d (last=%d)\n", + i, evOffset[i], evOffset[i-1]); + failed = AL_TRUE; + } + + azCount[i-1] = evOffset[i] - evOffset[i-1]; + if(azCount[i-1] < MIN_AZ_COUNT || azCount[i-1] > MAX_AZ_COUNT) + { + ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", + i-1, azCount[i-1], MIN_AZ_COUNT, MAX_AZ_COUNT); + failed = AL_TRUE; + } + } + if(irCount <= evOffset[i-1]) + { + ERR("Invalid evOffset: evOffset[%d]=%d (irCount=%d)\n", + i-1, evOffset[i-1], irCount); + failed = AL_TRUE; + } + + azCount[i-1] = irCount - evOffset[i-1]; + if(azCount[i-1] < MIN_AZ_COUNT || azCount[i-1] > MAX_AZ_COUNT) + { + ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", + i-1, azCount[i-1], MIN_AZ_COUNT, MAX_AZ_COUNT); + failed = AL_TRUE; + } + + if(!failed) + { + coeffs.resize(irSize*irCount); + delays.resize(irCount); + + size_t reqsize = 2*irSize*irCount + irCount; + if(datalen < reqsize) + { + ERR("Unexpected end of %s data (req " SZFMT ", rem " SZFMT ")\n", + filename, reqsize, datalen); + failed = AL_TRUE; + } + } + + if(!failed) + { + for(i = 0;i < irCount;i++) + { + for(j = 0;j < irSize;j++) + coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f; + } + + for(i = 0;i < irCount;i++) + { + delays[i][0] = GetLE_ALubyte(&data, &datalen); + if(delays[i][0] > MAX_HRIR_DELAY) + { + ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); + failed = AL_TRUE; + } + } + } + + if(!failed) + { + /* Mirror the left ear responses to the right ear. */ + for(i = 0;i < evCount;i++) + { + ALushort evoffset = evOffset[i]; + ALubyte azcount = azCount[i]; + for(j = 0;j < azcount;j++) + { + ALsizei lidx = evoffset + j; + ALsizei ridx = evoffset + ((azcount-j) % azcount); + ALsizei k; + + for(k = 0;k < irSize;k++) + coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; + delays[ridx][1] = delays[lidx][0]; + } + } + + Hrtf = CreateHrtfStore(rate, irSize, 0.0f, evCount, irCount, azCount.data(), + evOffset.data(), &reinterpret_cast(coeffs[0]), + &reinterpret_cast(delays[0]), filename); + } + + return Hrtf; +} + +static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char *filename) +{ + struct Hrtf *Hrtf = NULL; + ALboolean failed = AL_FALSE; + ALuint rate = 0; + ALushort irCount = 0; + ALushort irSize = 0; + ALubyte evCount = 0; + const ALubyte *azCount = NULL; + std::vector evOffset; + std::vector> coeffs; + std::vector> delays; + ALsizei i, j; + + if(datalen < 6) + { + ERR("Unexpected end of %s data (req %d, rem " SZFMT "\n", filename, 6, datalen); + return NULL; + } + + rate = GetLE_ALuint(&data, &datalen); + + irSize = GetLE_ALubyte(&data, &datalen); + + evCount = GetLE_ALubyte(&data, &datalen); + + if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) + { + ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", + irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE); + failed = AL_TRUE; + } + if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT) + { + ERR("Unsupported elevation count: evCount=%d (%d to %d)\n", + evCount, MIN_EV_COUNT, MAX_EV_COUNT); + failed = AL_TRUE; + } + if(failed) + return NULL; + + if(datalen < evCount) + { + ERR("Unexpected end of %s data (req %d, rem " SZFMT "\n", filename, evCount, datalen); + return NULL; + } + + azCount = Get_ALubytePtr(&data, &datalen, evCount); + + evOffset.resize(evCount); + + for(i = 0;i < evCount;i++) + { + if(azCount[i] < MIN_AZ_COUNT || azCount[i] > MAX_AZ_COUNT) + { + ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", + i, azCount[i], MIN_AZ_COUNT, MAX_AZ_COUNT); + failed = AL_TRUE; + } + } + + if(!failed) + { + evOffset[0] = 0; + irCount = azCount[0]; + for(i = 1;i < evCount;i++) + { + evOffset[i] = evOffset[i-1] + azCount[i-1]; + irCount += azCount[i]; + } + + coeffs.resize(irSize*irCount); + delays.resize(irCount); + + size_t reqsize = 2*irSize*irCount + irCount; + if(datalen < reqsize) + { + ERR("Unexpected end of %s data (req " SZFMT ", rem " SZFMT "\n", + filename, reqsize, datalen); + failed = AL_TRUE; + } + } + + if(!failed) + { + for(i = 0;i < irCount;i++) + { + for(j = 0;j < irSize;j++) + coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f; + } + + for(i = 0;i < irCount;i++) + { + delays[i][0] = GetLE_ALubyte(&data, &datalen); + if(delays[i][0] > MAX_HRIR_DELAY) + { + ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); + failed = AL_TRUE; + } + } + } + + if(!failed) + { + /* Mirror the left ear responses to the right ear. */ + for(i = 0;i < evCount;i++) + { + ALushort evoffset = evOffset[i]; + ALubyte azcount = azCount[i]; + for(j = 0;j < azcount;j++) + { + ALsizei lidx = evoffset + j; + ALsizei ridx = evoffset + ((azcount-j) % azcount); + ALsizei k; + + for(k = 0;k < irSize;k++) + coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; + delays[ridx][1] = delays[lidx][0]; + } + } + + Hrtf = CreateHrtfStore(rate, irSize, 0.0f, evCount, irCount, azCount, evOffset.data(), + &reinterpret_cast(coeffs[0]), + &reinterpret_cast(delays[0]), filename); + } + + return Hrtf; +} + +#define SAMPLETYPE_S16 0 +#define SAMPLETYPE_S24 1 + +#define CHANTYPE_LEFTONLY 0 +#define CHANTYPE_LEFTRIGHT 1 + +static struct Hrtf *LoadHrtf02(const ALubyte *data, size_t datalen, const char *filename) +{ + struct Hrtf *Hrtf = NULL; + ALboolean failed = AL_FALSE; + ALuint rate = 0; + ALubyte sampleType; + ALubyte channelType; + ALushort irCount = 0; + ALushort irSize = 0; + ALubyte fdCount = 0; + ALushort distance = 0; + ALubyte evCount = 0; + const ALubyte *azCount = NULL; + std::vector evOffset; + std::vector> coeffs; + std::vector> delays; + ALsizei i, j; + + if(datalen < 8) + { + ERR("Unexpected end of %s data (req %d, rem " SZFMT "\n", filename, 8, datalen); + return NULL; + } + + rate = GetLE_ALuint(&data, &datalen); + sampleType = GetLE_ALubyte(&data, &datalen); + channelType = GetLE_ALubyte(&data, &datalen); + + irSize = GetLE_ALubyte(&data, &datalen); + + fdCount = GetLE_ALubyte(&data, &datalen); + + if(sampleType > SAMPLETYPE_S24) + { + ERR("Unsupported sample type: %d\n", sampleType); + failed = AL_TRUE; + } + if(channelType > CHANTYPE_LEFTRIGHT) + { + ERR("Unsupported channel type: %d\n", channelType); + failed = AL_TRUE; + } + + if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) + { + ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", + irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE); + failed = AL_TRUE; + } + if(fdCount != 1) + { + ERR("Multiple field-depths not supported: fdCount=%d (%d to %d)\n", + evCount, MIN_FD_COUNT, MAX_FD_COUNT); + failed = AL_TRUE; + } + if(failed) + return NULL; + + for(i = 0;i < fdCount;i++) + { + if(datalen < 3) + { + ERR("Unexpected end of %s data (req %d, rem " SZFMT "\n", filename, 3, datalen); + return NULL; + } + + distance = GetLE_ALushort(&data, &datalen); + if(distance < MIN_FD_DISTANCE || distance > MAX_FD_DISTANCE) + { + ERR("Unsupported field distance: distance=%d (%dmm to %dmm)\n", + distance, MIN_FD_DISTANCE, MAX_FD_DISTANCE); + failed = AL_TRUE; + } + + evCount = GetLE_ALubyte(&data, &datalen); + if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT) + { + ERR("Unsupported elevation count: evCount=%d (%d to %d)\n", + evCount, MIN_EV_COUNT, MAX_EV_COUNT); + failed = AL_TRUE; + } + if(failed) + return NULL; + + if(datalen < evCount) + { + ERR("Unexpected end of %s data (req %d, rem " SZFMT "\n", filename, evCount, datalen); + return NULL; + } + + azCount = Get_ALubytePtr(&data, &datalen, evCount); + for(j = 0;j < evCount;j++) + { + if(azCount[j] < MIN_AZ_COUNT || azCount[j] > MAX_AZ_COUNT) + { + ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", + j, azCount[j], MIN_AZ_COUNT, MAX_AZ_COUNT); + failed = AL_TRUE; + } + } + } + if(failed) + return NULL; + + evOffset.resize(evCount); + + evOffset[0] = 0; + irCount = azCount[0]; + for(i = 1;i < evCount;i++) + { + evOffset[i] = evOffset[i-1] + azCount[i-1]; + irCount += azCount[i]; + } + + coeffs.resize(irSize*irCount); + delays.resize(irCount); + + size_t reqsize = 2*irSize*irCount + irCount; + if(datalen < reqsize) + { + ERR("Unexpected end of %s data (req " SZFMT ", rem " SZFMT "\n", + filename, reqsize, datalen); + failed = AL_TRUE; + } + + if(!failed) + { + if(channelType == CHANTYPE_LEFTONLY) + { + if(sampleType == SAMPLETYPE_S16) + for(i = 0;i < irCount;i++) + { + for(j = 0;j < irSize;j++) + coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f; + } + else if(sampleType == SAMPLETYPE_S24) + for(i = 0;i < irCount;i++) + { + for(j = 0;j < irSize;j++) + coeffs[i*irSize + j][0] = GetLE_ALint24(&data, &datalen) / 8388608.0f; + } + + for(i = 0;i < irCount;i++) + { + delays[i][0] = GetLE_ALubyte(&data, &datalen); + if(delays[i][0] > MAX_HRIR_DELAY) + { + ERR("Invalid delays[%d][0]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); + failed = AL_TRUE; + } + } + } + else if(channelType == CHANTYPE_LEFTRIGHT) + { + if(sampleType == SAMPLETYPE_S16) + for(i = 0;i < irCount;i++) + { + for(j = 0;j < irSize;j++) + { + coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f; + coeffs[i*irSize + j][1] = GetLE_ALshort(&data, &datalen) / 32768.0f; + } + } + else if(sampleType == SAMPLETYPE_S24) + for(i = 0;i < irCount;i++) + { + for(j = 0;j < irSize;j++) + { + coeffs[i*irSize + j][0] = GetLE_ALint24(&data, &datalen) / 8388608.0f; + coeffs[i*irSize + j][1] = GetLE_ALint24(&data, &datalen) / 8388608.0f; + } + } + + for(i = 0;i < irCount;i++) + { + delays[i][0] = GetLE_ALubyte(&data, &datalen); + if(delays[i][0] > MAX_HRIR_DELAY) + { + ERR("Invalid delays[%d][0]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); + failed = AL_TRUE; + } + delays[i][1] = GetLE_ALubyte(&data, &datalen); + if(delays[i][1] > MAX_HRIR_DELAY) + { + ERR("Invalid delays[%d][1]: %d (%d)\n", i, delays[i][1], MAX_HRIR_DELAY); + failed = AL_TRUE; + } + } + } + } + + if(!failed) + { + if(channelType == CHANTYPE_LEFTONLY) + { + /* Mirror the left ear responses to the right ear. */ + for(i = 0;i < evCount;i++) + { + ALushort evoffset = evOffset[i]; + ALubyte azcount = azCount[i]; + for(j = 0;j < azcount;j++) + { + ALsizei lidx = evoffset + j; + ALsizei ridx = evoffset + ((azcount-j) % azcount); + ALsizei k; + + for(k = 0;k < irSize;k++) + coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; + delays[ridx][1] = delays[lidx][0]; + } + } + } + + Hrtf = CreateHrtfStore(rate, irSize, + (ALfloat)distance / 1000.0f, evCount, irCount, azCount, evOffset.data(), + &reinterpret_cast(coeffs[0]), + &reinterpret_cast(delays[0]), filename + ); + } + + return Hrtf; +} + + +static void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename) +{ + EnumeratedHrtf entry = { AL_STRING_INIT_STATIC(), NULL }; + HrtfEntry *loaded_entry; + const EnumeratedHrtf *iter; + const char *name; + const char *ext; + int i; + + /* Check if this file has already been loaded globally. */ + loaded_entry = LoadedHrtfs; + while(loaded_entry) + { + if(alstr_cmp_cstr(filename, loaded_entry->filename) == 0) + { + /* Check if this entry has already been added to the list. */ +#define MATCH_ENTRY(i) (loaded_entry == (i)->hrtf) + VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_ENTRY); +#undef MATCH_ENTRY + if(iter != VECTOR_END(*list)) + { + TRACE("Skipping duplicate file entry %s\n", alstr_get_cstr(filename)); + return; + } + + break; + } + loaded_entry = loaded_entry->next; + } + + if(!loaded_entry) + { + TRACE("Got new file \"%s\"\n", alstr_get_cstr(filename)); + + loaded_entry = static_cast(al_calloc(DEF_ALIGN, + FAM_SIZE(struct HrtfEntry, filename, alstr_length(filename)+1) + )); + loaded_entry->next = LoadedHrtfs; + loaded_entry->handle = NULL; + strcpy(loaded_entry->filename, alstr_get_cstr(filename)); + LoadedHrtfs = loaded_entry; + } + + /* TODO: Get a human-readable name from the HRTF data (possibly coming in a + * format update). */ + name = strrchr(alstr_get_cstr(filename), '/'); + if(!name) name = strrchr(alstr_get_cstr(filename), '\\'); + if(!name) name = alstr_get_cstr(filename); + else ++name; + + ext = strrchr(name, '.'); + + i = 0; + do { + if(!ext) + alstr_copy_cstr(&entry.name, name); + else + alstr_copy_range(&entry.name, name, ext); + if(i != 0) + { + char str[64]; + snprintf(str, sizeof(str), " #%d", i+1); + alstr_append_cstr(&entry.name, str); + } + ++i; + +#define MATCH_NAME(i) (alstr_cmp(entry.name, (i)->name) == 0) + VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_NAME); +#undef MATCH_NAME + } while(iter != VECTOR_END(*list)); + entry.hrtf = loaded_entry; + + TRACE("Adding entry \"%s\" from file \"%s\"\n", alstr_get_cstr(entry.name), + alstr_get_cstr(filename)); + VECTOR_PUSH_BACK(*list, entry); +} + +/* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer + * for input instead of opening the given filename. + */ +static void AddBuiltInEntry(vector_EnumeratedHrtf *list, const_al_string filename, ALuint residx) +{ + EnumeratedHrtf entry = { AL_STRING_INIT_STATIC(), NULL }; + HrtfEntry *loaded_entry; + struct Hrtf *hrtf = NULL; + const EnumeratedHrtf *iter; + const char *name; + const char *ext; + int i; + + loaded_entry = LoadedHrtfs; + while(loaded_entry) + { + if(alstr_cmp_cstr(filename, loaded_entry->filename) == 0) + { +#define MATCH_ENTRY(i) (loaded_entry == (i)->hrtf) + VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_ENTRY); +#undef MATCH_ENTRY + if(iter != VECTOR_END(*list)) + { + TRACE("Skipping duplicate file entry %s\n", alstr_get_cstr(filename)); + return; + } + + break; + } + loaded_entry = loaded_entry->next; + } + + if(!loaded_entry) + { + size_t namelen = alstr_length(filename)+32; + + TRACE("Got new file \"%s\"\n", alstr_get_cstr(filename)); + + loaded_entry = static_cast(al_calloc(DEF_ALIGN, + FAM_SIZE(struct HrtfEntry, filename, namelen) + )); + loaded_entry->next = LoadedHrtfs; + loaded_entry->handle = hrtf; + snprintf(loaded_entry->filename, namelen, "!%u_%s", + residx, alstr_get_cstr(filename)); + LoadedHrtfs = loaded_entry; + } + + /* TODO: Get a human-readable name from the HRTF data (possibly coming in a + * format update). */ + name = strrchr(alstr_get_cstr(filename), '/'); + if(!name) name = strrchr(alstr_get_cstr(filename), '\\'); + if(!name) name = alstr_get_cstr(filename); + else ++name; + + ext = strrchr(name, '.'); + + i = 0; + do { + if(!ext) + alstr_copy_cstr(&entry.name, name); + else + alstr_copy_range(&entry.name, name, ext); + if(i != 0) + { + char str[64]; + snprintf(str, sizeof(str), " #%d", i+1); + alstr_append_cstr(&entry.name, str); + } + ++i; + +#define MATCH_NAME(i) (alstr_cmp(entry.name, (i)->name) == 0) + VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_NAME); +#undef MATCH_NAME + } while(iter != VECTOR_END(*list)); + entry.hrtf = loaded_entry; + + TRACE("Adding built-in entry \"%s\"\n", alstr_get_cstr(entry.name)); + VECTOR_PUSH_BACK(*list, entry); +} + + +#define IDR_DEFAULT_44100_MHR 1 +#define IDR_DEFAULT_48000_MHR 2 + +#ifndef ALSOFT_EMBED_HRTF_DATA + +static const ALubyte *GetResource(int UNUSED(name), size_t *size) +{ + *size = 0; + return NULL; +} + +#else + +#include "default-44100.mhr.h" +#include "default-48000.mhr.h" + +static const ALubyte *GetResource(int name, size_t *size) +{ + if(name == IDR_DEFAULT_44100_MHR) + { + *size = sizeof(hrtf_default_44100); + return hrtf_default_44100; + } + if(name == IDR_DEFAULT_48000_MHR) + { + *size = sizeof(hrtf_default_48000); + return hrtf_default_48000; + } + *size = 0; + return NULL; +} +#endif + +vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname) +{ + vector_EnumeratedHrtf list = VECTOR_INIT_STATIC(); + const char *defaulthrtf = ""; + const char *pathlist = ""; + bool usedefaults = true; + + if(ConfigValueStr(alstr_get_cstr(devname), NULL, "hrtf-paths", &pathlist)) + { + al_string pname = AL_STRING_INIT_STATIC(); + while(pathlist && *pathlist) + { + const char *next, *end; + + while(isspace(*pathlist) || *pathlist == ',') + pathlist++; + if(*pathlist == '\0') + continue; + + next = strchr(pathlist, ','); + if(next) + end = next++; + else + { + end = pathlist + strlen(pathlist); + usedefaults = false; + } + + while(end != pathlist && isspace(*(end-1))) + --end; + if(end != pathlist) + { + vector_al_string flist; + size_t i; + + alstr_copy_range(&pname, pathlist, end); + + flist = SearchDataFiles(".mhr", alstr_get_cstr(pname)); + for(i = 0;i < VECTOR_SIZE(flist);i++) + AddFileEntry(&list, VECTOR_ELEM(flist, i)); + VECTOR_FOR_EACH(al_string, flist, alstr_reset); + VECTOR_DEINIT(flist); + } + + pathlist = next; + } + + alstr_reset(&pname); + } + else if(ConfigValueExists(alstr_get_cstr(devname), NULL, "hrtf_tables")) + ERR("The hrtf_tables option is deprecated, please use hrtf-paths instead.\n"); + + if(usedefaults) + { + al_string ename = AL_STRING_INIT_STATIC(); + vector_al_string flist; + const ALubyte *rdata; + size_t rsize, i; + + flist = SearchDataFiles(".mhr", "openal/hrtf"); + for(i = 0;i < VECTOR_SIZE(flist);i++) + AddFileEntry(&list, VECTOR_ELEM(flist, i)); + VECTOR_FOR_EACH(al_string, flist, alstr_reset); + VECTOR_DEINIT(flist); + + rdata = GetResource(IDR_DEFAULT_44100_MHR, &rsize); + if(rdata != NULL && rsize > 0) + { + alstr_copy_cstr(&ename, "Built-In 44100hz"); + AddBuiltInEntry(&list, ename, IDR_DEFAULT_44100_MHR); + } + + rdata = GetResource(IDR_DEFAULT_48000_MHR, &rsize); + if(rdata != NULL && rsize > 0) + { + alstr_copy_cstr(&ename, "Built-In 48000hz"); + AddBuiltInEntry(&list, ename, IDR_DEFAULT_48000_MHR); + } + alstr_reset(&ename); + } + + if(VECTOR_SIZE(list) > 1 && ConfigValueStr(alstr_get_cstr(devname), NULL, "default-hrtf", &defaulthrtf)) + { + const EnumeratedHrtf *iter; + /* Find the preferred HRTF and move it to the front of the list. */ +#define FIND_ENTRY(i) (alstr_cmp_cstr((i)->name, defaulthrtf) == 0) + VECTOR_FIND_IF(iter, const EnumeratedHrtf, list, FIND_ENTRY); +#undef FIND_ENTRY + if(iter == VECTOR_END(list)) + WARN("Failed to find default HRTF \"%s\"\n", defaulthrtf); + else if(iter != VECTOR_BEGIN(list)) + { + EnumeratedHrtf entry = *iter; + memmove(&VECTOR_ELEM(list,1), &VECTOR_ELEM(list,0), + (iter-VECTOR_BEGIN(list))*sizeof(EnumeratedHrtf)); + VECTOR_ELEM(list,0) = entry; + } + } + + return list; +} + +void FreeHrtfList(vector_EnumeratedHrtf *list) +{ +#define CLEAR_ENTRY(i) alstr_reset(&(i)->name) + VECTOR_FOR_EACH(EnumeratedHrtf, *list, CLEAR_ENTRY); + VECTOR_DEINIT(*list); +#undef CLEAR_ENTRY +} + +struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry) +{ + struct Hrtf *hrtf = NULL; + struct FileMapping fmap; + const ALubyte *rdata; + const char *name; + ALuint residx; + size_t rsize; + char ch; + + while(ATOMIC_FLAG_TEST_AND_SET(&LoadedHrtfLock, almemory_order_seq_cst)) + althrd_yield(); + + if(entry->handle) + { + hrtf = entry->handle; + Hrtf_IncRef(hrtf); + goto done; + } + + fmap.ptr = NULL; + fmap.len = 0; + if(sscanf(entry->filename, "!%u%c", &residx, &ch) == 2 && ch == '_') + { + name = strchr(entry->filename, ch)+1; + + TRACE("Loading %s...\n", name); + rdata = GetResource(residx, &rsize); + if(rdata == NULL || rsize == 0) + { + ERR("Could not get resource %u, %s\n", residx, name); + goto done; + } + } + else + { + name = entry->filename; + + TRACE("Loading %s...\n", entry->filename); + fmap = MapFileToMem(entry->filename); + if(fmap.ptr == NULL) + { + ERR("Could not open %s\n", entry->filename); + goto done; + } + + rdata = static_cast(fmap.ptr); + rsize = fmap.len; + } + + if(rsize < sizeof(magicMarker02)) + ERR("%s data is too short (" SZFMT " bytes)\n", name, rsize); + else if(memcmp(rdata, magicMarker02, sizeof(magicMarker02)) == 0) + { + TRACE("Detected data set format v2\n"); + hrtf = LoadHrtf02(rdata+sizeof(magicMarker02), + rsize-sizeof(magicMarker02), name + ); + } + else if(memcmp(rdata, magicMarker01, sizeof(magicMarker01)) == 0) + { + TRACE("Detected data set format v1\n"); + hrtf = LoadHrtf01(rdata+sizeof(magicMarker01), + rsize-sizeof(magicMarker01), name + ); + } + else if(memcmp(rdata, magicMarker00, sizeof(magicMarker00)) == 0) + { + TRACE("Detected data set format v0\n"); + hrtf = LoadHrtf00(rdata+sizeof(magicMarker00), + rsize-sizeof(magicMarker00), name + ); + } + else + ERR("Invalid header in %s: \"%.8s\"\n", name, (const char*)rdata); + if(fmap.ptr) + UnmapFileMem(&fmap); + + if(!hrtf) + { + ERR("Failed to load %s\n", name); + goto done; + } + entry->handle = hrtf; + Hrtf_IncRef(hrtf); + + TRACE("Loaded HRTF support for format: %s %uhz\n", + DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); + +done: + ATOMIC_FLAG_CLEAR(&LoadedHrtfLock, almemory_order_seq_cst); + return hrtf; +} + + +void Hrtf_IncRef(struct Hrtf *hrtf) +{ + uint ref = IncrementRef(&hrtf->ref); + TRACEREF("%p increasing refcount to %u\n", hrtf, ref); +} + +void Hrtf_DecRef(struct Hrtf *hrtf) +{ + struct HrtfEntry *Hrtf; + uint ref = DecrementRef(&hrtf->ref); + TRACEREF("%p decreasing refcount to %u\n", hrtf, ref); + if(ref == 0) + { + while(ATOMIC_FLAG_TEST_AND_SET(&LoadedHrtfLock, almemory_order_seq_cst)) + althrd_yield(); + + Hrtf = LoadedHrtfs; + while(Hrtf != NULL) + { + /* Need to double-check that it's still unused, as another device + * could've reacquired this HRTF after its reference went to 0 and + * before the lock was taken. + */ + if(hrtf == Hrtf->handle && ReadRef(&hrtf->ref) == 0) + { + al_free(Hrtf->handle); + Hrtf->handle = NULL; + TRACE("Unloaded unused HRTF %s\n", Hrtf->filename); + } + Hrtf = Hrtf->next; + } + + ATOMIC_FLAG_CLEAR(&LoadedHrtfLock, almemory_order_seq_cst); + } +} + + +void FreeHrtfs(void) +{ + struct HrtfEntry *Hrtf = LoadedHrtfs; + LoadedHrtfs = NULL; + + while(Hrtf != NULL) + { + struct HrtfEntry *next = Hrtf->next; + al_free(Hrtf->handle); + al_free(Hrtf); + Hrtf = next; + } +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 3731e82e..920e3d81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -876,7 +876,7 @@ SET(ALC_OBJS Alc/fpu_modes.h Alc/logging.h Alc/vector.h - Alc/hrtf.c + Alc/hrtf.cpp Alc/hrtf.h Alc/uhjfilter.cpp Alc/uhjfilter.h -- cgit v1.2.3 From add776ddbb859548e78d390bf54baebe169105d1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 9 Nov 2018 21:56:05 -0800 Subject: Handle the open mode in al::ifstream --- Alc/compat.h | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/Alc/compat.h b/Alc/compat.h index 1c348c34..25bb0c45 100644 --- a/Alc/compat.h +++ b/Alc/compat.h @@ -147,17 +147,25 @@ class filebuf final : public std::streambuf { } public: - bool open(const wchar_t *filename) + bool open(const wchar_t *filename, std::ios_base::openmode mode) { - mFile = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); - if(mFile == INVALID_HANDLE_VALUE) return false; + if((mode&std::ios_base::out) || !(mode&std::ios_base::in)) + return false; + HANDLE f{CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)}; + if(f == INVALID_HANDLE_VALUE) return false; + + if(mFile != INVALID_HANDLE_VALUE) + CloseHandle(mFile); + mFile = f; + + setg(nullptr, nullptr, nullptr); return true; } - bool open(const char *filename) + bool open(const char *filename, std::ios_base::openmode mode) { std::wstring wname{utf8_to_wstr(filename)}; - return open(wname.c_str()); + return open(wname.c_str(), mode); } bool is_open() const noexcept { return mFile != INVALID_HANDLE_VALUE; } @@ -176,22 +184,30 @@ class ifstream final : public std::istream { filebuf mStreamBuf; public: - ifstream(const std::wstring &filename) : ifstream{filename.c_str()} { } - ifstream(const wchar_t *filename) : std::istream{nullptr} + ifstream(const std::wstring &filename, std::ios_base::openmode mode = std::ios_base::in) + : ifstream(filename.c_str(), mode) { } + ifstream(const wchar_t *filename, std::ios_base::openmode mode = std::ios_base::in) + : std::istream{nullptr} { init(&mStreamBuf); // Set the failbit if the file failed to open. - if(!mStreamBuf.open(filename)) clear(failbit); + if((mode&std::ios_base::out) || + !mStreamBuf.open(filename, mode|std::ios_base::in)) + clear(failbit); } - ifstream(const std::string &filename) : ifstream{filename.c_str()} { } - ifstream(const char *filename) : std::istream{nullptr} + ifstream(const std::string &filename, std::ios_base::openmode mode = std::ios_base::in) + : ifstream(filename.c_str(), mode) { } + ifstream(const char *filename, std::ios_base::openmode mode = std::ios_base::in) + : std::istream{nullptr} { init(&mStreamBuf); // Set the failbit if the file failed to open. - if(!mStreamBuf.open(filename)) clear(failbit); + if((mode&std::ios_base::out) || + !mStreamBuf.open(filename, mode|std::ios_base::in)) + clear(failbit); } bool is_open() const noexcept { return mStreamBuf.is_open(); } -- cgit v1.2.3 From d8163a416a00780bced89fd0efca9e641637395f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 9 Nov 2018 23:47:42 -0800 Subject: Use C++ more in hrtf.cpp --- Alc/hrtf.cpp | 938 ++++++++++++++++++++++++++++------------------------------- 1 file changed, 439 insertions(+), 499 deletions(-) diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index ce7c46f3..b2dc1ec8 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -23,8 +23,11 @@ #include #include +#include #include #include +#include +#include #include #include "AL/al.h" @@ -73,10 +76,80 @@ constexpr ALchar magicMarker02[8]{'M','i','n','P','H','R','0','2'}; /* First value for pass-through coefficients (remaining are 0), used for omni- * directional sounds. */ -constexpr ALfloat PassthruCoeff = 0.707106781187f/*sqrt(0.5)*/; +constexpr ALfloat PassthruCoeff{0.707106781187f/*sqrt(0.5)*/}; -ATOMIC_FLAG LoadedHrtfLock = ATOMIC_FLAG_INIT; -struct HrtfEntry *LoadedHrtfs = NULL; +std::mutex LoadedHrtfLock; +HrtfEntry *LoadedHrtfs{nullptr}; + + +class databuf final : public std::streambuf { + int_type underflow() override + { return traits_type::eof(); } + + pos_type seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) override + { + if((mode&std::ios_base::out) || !(mode&std::ios_base::in)) + return traits_type::eof(); + + char_type *cur; + switch(whence) + { + case std::ios_base::beg: + if(offset < 0 || offset > egptr()-eback()) + return traits_type::eof(); + cur = eback() + offset; + break; + + case std::ios_base::cur: + if((offset >= 0 && offset > egptr()-gptr()) || + (offset < 0 && -offset > gptr()-eback())) + return traits_type::eof(); + cur = gptr() + offset; + break; + + case std::ios_base::end: + if(offset > 0 || -offset > egptr()-eback()) + return traits_type::eof(); + cur = egptr() + offset; + break; + + default: + return traits_type::eof(); + } + + setg(eback(), cur, egptr()); + return cur - eback(); + } + + pos_type seekpos(pos_type pos, std::ios_base::openmode mode) override + { + // Simplified version of seekoff + if((mode&std::ios_base::out) || !(mode&std::ios_base::in)) + return traits_type::eof(); + + if(pos < 0 || pos > egptr()-eback()) + return traits_type::eof(); + + setg(eback(), eback() + pos, egptr()); + return pos; + } + +public: + databuf(const char_type *start, const char_type *end) noexcept + { + setg(const_cast(start), const_cast(start), + const_cast(end)); + } +}; + +class idstream final : public std::istream { + databuf mStreamBuf; + +public: + idstream(const char *start, const char *end) + : std::istream{nullptr}, mStreamBuf{start, end} + { init(&mStreamBuf); } +}; /* Calculate the elevation index given the polar elevation in radians. This @@ -84,9 +157,8 @@ struct HrtfEntry *LoadedHrtfs = NULL; */ ALsizei CalcEvIndex(ALsizei evcount, ALfloat ev, ALfloat *mu) { - ALsizei idx; ev = (F_PI_2+ev) * (evcount-1) / F_PI; - idx = float2int(ev); + ALsizei idx{float2int(ev)}; *mu = ev - idx; return mini(idx, evcount-1); @@ -97,10 +169,9 @@ ALsizei CalcEvIndex(ALsizei evcount, ALfloat ev, ALfloat *mu) */ ALsizei CalcAzIndex(ALsizei azcount, ALfloat az, ALfloat *mu) { - ALsizei idx; az = (F_TAU+az) * azcount / F_TAU; + ALsizei idx{float2int(az)}; - idx = float2int(az); *mu = az - idx; return idx % azcount; } @@ -114,25 +185,22 @@ ALsizei CalcAzIndex(ALsizei azcount, ALfloat az, ALfloat *mu) void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat (*RESTRICT coeffs)[2], ALsizei *delays) { - ALsizei evidx, azidx, idx[4]; - ALsizei evoffset; - ALfloat emu, amu[2]; - ALfloat blend[4]; - ALfloat dirfact; - ALsizei i, c; - - dirfact = 1.0f - (spread / F_TAU); + ALfloat dirfact{1.0f - (spread / F_TAU)}; /* Claculate the lower elevation index. */ - evidx = CalcEvIndex(Hrtf->evCount, elevation, &emu); - evoffset = Hrtf->evOffset[evidx]; + ALfloat emu; + ALsizei evidx{CalcEvIndex(Hrtf->evCount, elevation, &emu)}; + ALsizei evoffset{Hrtf->evOffset[evidx]}; /* Calculate lower azimuth index. */ - azidx= CalcAzIndex(Hrtf->azCount[evidx], azimuth, &amu[0]); + ALfloat amu[2]; + ALsizei azidx{CalcAzIndex(Hrtf->azCount[evidx], azimuth, &amu[0])}; /* Calculate the lower HRIR indices. */ - idx[0] = evoffset + azidx; - idx[1] = evoffset + ((azidx+1) % Hrtf->azCount[evidx]); + ALsizei idx[4]{ + evoffset + azidx, + evoffset + ((azidx+1) % Hrtf->azCount[evidx]) + }; if(evidx < Hrtf->evCount-1) { /* Increment elevation to the next (upper) index. */ @@ -159,10 +227,12 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, /* Calculate bilinear blending weights, attenuated according to the * directional panning factor. */ - blend[0] = (1.0f-emu) * (1.0f-amu[0]) * dirfact; - blend[1] = (1.0f-emu) * ( amu[0]) * dirfact; - blend[2] = ( emu) * (1.0f-amu[1]) * dirfact; - blend[3] = ( emu) * ( amu[1]) * dirfact; + ALfloat blend[4]{ + (1.0f-emu) * (1.0f-amu[0]) * dirfact, + (1.0f-emu) * ( amu[0]) * dirfact, + ( emu) * (1.0f-amu[1]) * dirfact, + ( emu) * ( amu[1]) * dirfact + }; /* Calculate the blended HRIR delays. */ delays[0] = fastf2i( @@ -185,15 +255,15 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, /* Calculate the blended HRIR coefficients. */ coeffs[0][0] = PassthruCoeff * (1.0f-dirfact); coeffs[0][1] = PassthruCoeff * (1.0f-dirfact); - for(i = 1;i < Hrtf->irSize;i++) + for(ALsizei i{1};i < Hrtf->irSize;i++) { coeffs[i][0] = 0.0f; coeffs[i][1] = 0.0f; } - for(c = 0;c < 4;c++) + for(ALsizei c{0};c < 4;c++) { const ALfloat (*RESTRICT srccoeffs)[2] = Hrtf->coeffs + idx[c]; - for(i = 0;i < Hrtf->irSize;i++) + for(ALsizei i{0};i < Hrtf->irSize;i++) { coeffs[i][0] += srccoeffs[i][0] * blend[c]; coeffs[i][1] += srccoeffs[i][1] * blend[c]; @@ -338,10 +408,11 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N } -static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, - ALfloat distance, ALsizei evCount, ALsizei irCount, const ALubyte *azCount, - const ALushort *evOffset, const ALfloat (*coeffs)[2], const ALubyte (*delays)[2], - const char *filename) +namespace { + +struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALfloat distance, ALsizei evCount, + ALsizei irCount, const ALubyte *azCount, const ALushort *evOffset, const ALfloat (*coeffs)[2], + const ALubyte (*delays)[2], const char *filename) { struct Hrtf *Hrtf; size_t total; @@ -355,7 +426,7 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, total += sizeof(Hrtf->delays[0])*irCount; Hrtf = static_cast(al_calloc(16, total)); - if(Hrtf == NULL) + if(Hrtf == nullptr) ERR("Out of memory allocating storage for %s.\n", filename); else { @@ -414,76 +485,55 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, return Hrtf; } -static ALubyte GetLE_ALubyte(const ALubyte **data, size_t *len) +ALubyte GetLE_ALubyte(std::istream &data) { - ALubyte ret = (*data)[0]; - *data += 1; *len -= 1; - return ret; + return static_cast(data.get()); } -static ALshort GetLE_ALshort(const ALubyte **data, size_t *len) +ALshort GetLE_ALshort(std::istream &data) { - ALshort ret = (*data)[0] | ((*data)[1]<<8); - *data += 2; *len -= 2; - return ret; + int ret = data.get(); + ret |= data.get() << 8; + return static_cast((ret^32768) - 32768); } -static ALushort GetLE_ALushort(const ALubyte **data, size_t *len) +ALushort GetLE_ALushort(std::istream &data) { - ALushort ret = (*data)[0] | ((*data)[1]<<8); - *data += 2; *len -= 2; - return ret; + int ret = data.get(); + ret |= data.get() << 8; + return static_cast(ret); } -static ALint GetLE_ALint24(const ALubyte **data, size_t *len) +ALint GetLE_ALint24(std::istream &data) { - ALint ret = (*data)[0] | ((*data)[1]<<8) | ((*data)[2]<<16); - *data += 3; *len -= 3; - return (ret^0x800000) - 0x800000; + int ret = data.get(); + ret |= data.get() << 8; + ret |= data.get() << 16; + return (ret^8388608) - 8388608; } -static ALuint GetLE_ALuint(const ALubyte **data, size_t *len) +ALuint GetLE_ALuint(std::istream &data) { - ALuint ret = (*data)[0] | ((*data)[1]<<8) | ((*data)[2]<<16) | ((*data)[3]<<24); - *data += 4; *len -= 4; + int ret = data.get(); + ret |= data.get() << 8; + ret |= data.get() << 16; + ret |= data.get() << 24; return ret; } -static const ALubyte *Get_ALubytePtr(const ALubyte **data, size_t *len, size_t size) +struct Hrtf *LoadHrtf00(std::istream &data, const char *filename) { - const ALubyte *ret = *data; - *data += size; *len -= size; - return ret; -} - -static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char *filename) -{ - struct Hrtf *Hrtf = NULL; - ALboolean failed = AL_FALSE; - ALuint rate = 0; - ALushort irCount = 0; - ALushort irSize = 0; - ALubyte evCount = 0; - std::vector azCount; - std::vector evOffset; - std::vector> coeffs; - std::vector> delays; - ALsizei i, j; - - if(datalen < 9) + ALuint rate{GetLE_ALuint(data)}; + ALushort irCount{GetLE_ALushort(data)}; + ALushort irSize{GetLE_ALushort(data)}; + ALubyte evCount{GetLE_ALubyte(data)}; + if(!data || data.eof()) { - ERR("Unexpected end of %s data (req %d, rem " SZFMT ")\n", filename, 9, datalen); - return NULL; + ERR("Failed reading %s\n", filename); + return nullptr; } - rate = GetLE_ALuint(&data, &datalen); - - irCount = GetLE_ALushort(&data, &datalen); - - irSize = GetLE_ALushort(&data, &datalen); - - evCount = GetLE_ALubyte(&data, &datalen); - + ALboolean failed{AL_FALSE}; if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) { ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", @@ -497,28 +547,37 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char * failed = AL_TRUE; } if(failed) - return NULL; + return nullptr; - if(datalen < evCount*2u) + std::vector evOffset(evCount); + for(auto &val : evOffset) + val = GetLE_ALushort(data); + if(!data || data.eof()) { - ERR("Unexpected end of %s data (req %d, rem " SZFMT ")\n", filename, evCount*2, datalen); - return NULL; + ERR("Failed reading %s\n", filename); + return nullptr; } - - azCount.resize(evCount); - evOffset.resize(evCount); - - evOffset[0] = GetLE_ALushort(&data, &datalen); - for(i = 1;i < evCount;i++) + for(ALsizei i{1};i < evCount;i++) { - evOffset[i] = GetLE_ALushort(&data, &datalen); if(evOffset[i] <= evOffset[i-1]) { ERR("Invalid evOffset: evOffset[%d]=%d (last=%d)\n", i, evOffset[i], evOffset[i-1]); failed = AL_TRUE; } + } + if(irCount <= evOffset.back()) + { + ERR("Invalid evOffset: evOffset[" SZFMT "]=%d (irCount=%d)\n", + evOffset.size()-1, evOffset.back(), irCount); + failed = AL_TRUE; + } + if(failed) + return nullptr; + std::vector azCount(evCount); + for(ALsizei i{1};i < evCount;i++) + { azCount[i-1] = evOffset[i] - evOffset[i-1]; if(azCount[i-1] < MIN_AZ_COUNT || azCount[i-1] > MAX_AZ_COUNT) { @@ -527,107 +586,71 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char * failed = AL_TRUE; } } - if(irCount <= evOffset[i-1]) + azCount.back() = irCount - evOffset.back(); + if(azCount.back() < MIN_AZ_COUNT || azCount.back() > MAX_AZ_COUNT) { - ERR("Invalid evOffset: evOffset[%d]=%d (irCount=%d)\n", - i-1, evOffset[i-1], irCount); + ERR("Unsupported azimuth count: azCount[" SZFMT "]=%d (%d to %d)\n", + azCount.size()-1, azCount.back(), MIN_AZ_COUNT, MAX_AZ_COUNT); failed = AL_TRUE; } - - azCount[i-1] = irCount - evOffset[i-1]; - if(azCount[i-1] < MIN_AZ_COUNT || azCount[i-1] > MAX_AZ_COUNT) + if(failed) + return nullptr; + + std::vector> coeffs(irSize*irCount); + std::vector> delays(irCount); + for(auto &val : coeffs) + val[0] = GetLE_ALshort(data) / 32768.0f; + for(auto &val : delays) + val[0] = GetLE_ALubyte(data); + if(!data || data.eof()) { - ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", - i-1, azCount[i-1], MIN_AZ_COUNT, MAX_AZ_COUNT); - failed = AL_TRUE; + ERR("Failed reading %s\n", filename); + return nullptr; } - - if(!failed) + for(ALsizei i{0};i < irCount;i++) { - coeffs.resize(irSize*irCount); - delays.resize(irCount); - - size_t reqsize = 2*irSize*irCount + irCount; - if(datalen < reqsize) + if(delays[i][0] > MAX_HRIR_DELAY) { - ERR("Unexpected end of %s data (req " SZFMT ", rem " SZFMT ")\n", - filename, reqsize, datalen); + ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); failed = AL_TRUE; } } + if(failed) + return nullptr; - if(!failed) - { - for(i = 0;i < irCount;i++) - { - for(j = 0;j < irSize;j++) - coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f; - } - - for(i = 0;i < irCount;i++) - { - delays[i][0] = GetLE_ALubyte(&data, &datalen); - if(delays[i][0] > MAX_HRIR_DELAY) - { - ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); - failed = AL_TRUE; - } - } - } - - if(!failed) + /* Mirror the left ear responses to the right ear. */ + for(ALsizei i{0};i < evCount;i++) { - /* Mirror the left ear responses to the right ear. */ - for(i = 0;i < evCount;i++) + ALushort evoffset = evOffset[i]; + ALubyte azcount = azCount[i]; + for(ALsizei j{0};j < azcount;j++) { - ALushort evoffset = evOffset[i]; - ALubyte azcount = azCount[i]; - for(j = 0;j < azcount;j++) - { - ALsizei lidx = evoffset + j; - ALsizei ridx = evoffset + ((azcount-j) % azcount); - ALsizei k; + ALsizei lidx = evoffset + j; + ALsizei ridx = evoffset + ((azcount-j) % azcount); - for(k = 0;k < irSize;k++) - coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; - delays[ridx][1] = delays[lidx][0]; - } + for(ALsizei k{0};k < irSize;k++) + coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; + delays[ridx][1] = delays[lidx][0]; } - - Hrtf = CreateHrtfStore(rate, irSize, 0.0f, evCount, irCount, azCount.data(), - evOffset.data(), &reinterpret_cast(coeffs[0]), - &reinterpret_cast(delays[0]), filename); } - return Hrtf; + return CreateHrtfStore(rate, irSize, 0.0f, evCount, irCount, azCount.data(), + evOffset.data(), &reinterpret_cast(coeffs[0]), + &reinterpret_cast(delays[0]), filename); } -static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char *filename) +static struct Hrtf *LoadHrtf01(std::istream &data, const char *filename) { - struct Hrtf *Hrtf = NULL; - ALboolean failed = AL_FALSE; - ALuint rate = 0; - ALushort irCount = 0; - ALushort irSize = 0; - ALubyte evCount = 0; - const ALubyte *azCount = NULL; - std::vector evOffset; - std::vector> coeffs; - std::vector> delays; - ALsizei i, j; - - if(datalen < 6) + ALuint rate{GetLE_ALuint(data)}; + ALushort irSize{GetLE_ALubyte(data)}; + ALubyte evCount{GetLE_ALubyte(data)}; + if(!data || data.eof()) { - ERR("Unexpected end of %s data (req %d, rem " SZFMT "\n", filename, 6, datalen); - return NULL; + ERR("Failed reading %s\n", filename); + return nullptr; } - rate = GetLE_ALuint(&data, &datalen); - - irSize = GetLE_ALubyte(&data, &datalen); - - evCount = GetLE_ALubyte(&data, &datalen); - + ALboolean failed{AL_FALSE}; if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) { ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", @@ -641,19 +664,16 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char * failed = AL_TRUE; } if(failed) - return NULL; + return nullptr; - if(datalen < evCount) + std::vector azCount(evCount); + data.read(reinterpret_cast(azCount.data()), evCount); + if(!data || data.eof() || data.gcount() < evCount) { - ERR("Unexpected end of %s data (req %d, rem " SZFMT "\n", filename, evCount, datalen); - return NULL; + ERR("Failed reading %s\n", filename); + return nullptr; } - - azCount = Get_ALubytePtr(&data, &datalen, evCount); - - evOffset.resize(evCount); - - for(i = 0;i < evCount;i++) + for(ALsizei i{0};i < evCount;++i) { if(azCount[i] < MIN_AZ_COUNT || azCount[i] > MAX_AZ_COUNT) { @@ -662,73 +682,59 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char * failed = AL_TRUE; } } + if(failed) + return nullptr; - if(!failed) + std::vector evOffset(evCount); + evOffset[0] = 0; + ALushort irCount{azCount[0]}; + for(ALsizei i{1};i < evCount;i++) { - evOffset[0] = 0; - irCount = azCount[0]; - for(i = 1;i < evCount;i++) - { - evOffset[i] = evOffset[i-1] + azCount[i-1]; - irCount += azCount[i]; - } - - coeffs.resize(irSize*irCount); - delays.resize(irCount); - - size_t reqsize = 2*irSize*irCount + irCount; - if(datalen < reqsize) - { - ERR("Unexpected end of %s data (req " SZFMT ", rem " SZFMT "\n", - filename, reqsize, datalen); - failed = AL_TRUE; - } + evOffset[i] = evOffset[i-1] + azCount[i-1]; + irCount += azCount[i]; } - if(!failed) + std::vector> coeffs(irSize*irCount); + std::vector> delays(irCount); + for(auto &val : coeffs) + val[0] = GetLE_ALshort(data) / 32768.0f; + for(auto &val : delays) + val[0] = GetLE_ALubyte(data); + if(!data || data.eof()) { - for(i = 0;i < irCount;i++) - { - for(j = 0;j < irSize;j++) - coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f; - } - - for(i = 0;i < irCount;i++) + ERR("Failed reading %s\n", filename); + return nullptr; + } + for(ALsizei i{0};i < irCount;i++) + { + if(delays[i][0] > MAX_HRIR_DELAY) { - delays[i][0] = GetLE_ALubyte(&data, &datalen); - if(delays[i][0] > MAX_HRIR_DELAY) - { - ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); - failed = AL_TRUE; - } + ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); + failed = AL_TRUE; } } + if(failed) + return nullptr; - if(!failed) + /* Mirror the left ear responses to the right ear. */ + for(ALsizei i{0};i < evCount;i++) { - /* Mirror the left ear responses to the right ear. */ - for(i = 0;i < evCount;i++) + ALushort evoffset = evOffset[i]; + ALubyte azcount = azCount[i]; + for(ALsizei j{0};j < azcount;j++) { - ALushort evoffset = evOffset[i]; - ALubyte azcount = azCount[i]; - for(j = 0;j < azcount;j++) - { - ALsizei lidx = evoffset + j; - ALsizei ridx = evoffset + ((azcount-j) % azcount); - ALsizei k; + ALsizei lidx = evoffset + j; + ALsizei ridx = evoffset + ((azcount-j) % azcount); - for(k = 0;k < irSize;k++) - coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; - delays[ridx][1] = delays[lidx][0]; - } + for(ALsizei k{0};k < irSize;k++) + coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; + delays[ridx][1] = delays[lidx][0]; } - - Hrtf = CreateHrtfStore(rate, irSize, 0.0f, evCount, irCount, azCount, evOffset.data(), - &reinterpret_cast(coeffs[0]), - &reinterpret_cast(delays[0]), filename); } - return Hrtf; + return CreateHrtfStore(rate, irSize, 0.0f, evCount, irCount, azCount.data(), + evOffset.data(), &reinterpret_cast(coeffs[0]), + &reinterpret_cast(delays[0]), filename); } #define SAMPLETYPE_S16 0 @@ -737,38 +743,20 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char * #define CHANTYPE_LEFTONLY 0 #define CHANTYPE_LEFTRIGHT 1 -static struct Hrtf *LoadHrtf02(const ALubyte *data, size_t datalen, const char *filename) +struct Hrtf *LoadHrtf02(std::istream &data, const char *filename) { - struct Hrtf *Hrtf = NULL; - ALboolean failed = AL_FALSE; - ALuint rate = 0; - ALubyte sampleType; - ALubyte channelType; - ALushort irCount = 0; - ALushort irSize = 0; - ALubyte fdCount = 0; - ALushort distance = 0; - ALubyte evCount = 0; - const ALubyte *azCount = NULL; - std::vector evOffset; - std::vector> coeffs; - std::vector> delays; - ALsizei i, j; - - if(datalen < 8) + ALuint rate{GetLE_ALuint(data)}; + ALubyte sampleType{GetLE_ALubyte(data)}; + ALubyte channelType{GetLE_ALubyte(data)}; + ALushort irSize{GetLE_ALubyte(data)}; + ALubyte fdCount{GetLE_ALubyte(data)}; + if(!data || data.eof()) { - ERR("Unexpected end of %s data (req %d, rem " SZFMT "\n", filename, 8, datalen); - return NULL; + ERR("Failed reading %s\n", filename); + return nullptr; } - rate = GetLE_ALuint(&data, &datalen); - sampleType = GetLE_ALubyte(&data, &datalen); - channelType = GetLE_ALubyte(&data, &datalen); - - irSize = GetLE_ALubyte(&data, &datalen); - - fdCount = GetLE_ALubyte(&data, &datalen); - + ALboolean failed{AL_FALSE}; if(sampleType > SAMPLETYPE_S24) { ERR("Unsupported sample type: %d\n", sampleType); @@ -789,29 +777,31 @@ static struct Hrtf *LoadHrtf02(const ALubyte *data, size_t datalen, const char * if(fdCount != 1) { ERR("Multiple field-depths not supported: fdCount=%d (%d to %d)\n", - evCount, MIN_FD_COUNT, MAX_FD_COUNT); + fdCount, MIN_FD_COUNT, MAX_FD_COUNT); failed = AL_TRUE; } if(failed) - return NULL; + return nullptr; - for(i = 0;i < fdCount;i++) + ALushort distance{}; + ALubyte evCount{}; + std::vector azCount; + for(ALsizei i{0};i < fdCount;i++) { - if(datalen < 3) + distance = GetLE_ALushort(data); + evCount = GetLE_ALubyte(data); + if(!data || data.eof()) { - ERR("Unexpected end of %s data (req %d, rem " SZFMT "\n", filename, 3, datalen); - return NULL; + ERR("Failed reading %s\n", filename); + return nullptr; } - distance = GetLE_ALushort(&data, &datalen); if(distance < MIN_FD_DISTANCE || distance > MAX_FD_DISTANCE) { ERR("Unsupported field distance: distance=%d (%dmm to %dmm)\n", distance, MIN_FD_DISTANCE, MAX_FD_DISTANCE); failed = AL_TRUE; } - - evCount = GetLE_ALubyte(&data, &datalen); if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT) { ERR("Unsupported elevation count: evCount=%d (%d to %d)\n", @@ -819,16 +809,17 @@ static struct Hrtf *LoadHrtf02(const ALubyte *data, size_t datalen, const char * failed = AL_TRUE; } if(failed) - return NULL; + return nullptr; - if(datalen < evCount) + azCount.resize(evCount); + data.read(reinterpret_cast(azCount.data()), evCount); + if(!data || data.eof() || data.gcount() < evCount) { - ERR("Unexpected end of %s data (req %d, rem " SZFMT "\n", filename, evCount, datalen); - return NULL; + ERR("Failed reading %s\n", filename); + return nullptr; } - azCount = Get_ALubytePtr(&data, &datalen, evCount); - for(j = 0;j < evCount;j++) + for(ALsizei j{0};j < evCount;j++) { if(azCount[j] < MIN_AZ_COUNT || azCount[j] > MAX_AZ_COUNT) { @@ -837,145 +828,131 @@ static struct Hrtf *LoadHrtf02(const ALubyte *data, size_t datalen, const char * failed = AL_TRUE; } } + if(failed) + return nullptr; } - if(failed) - return NULL; - - evOffset.resize(evCount); + std::vector evOffset(evCount); evOffset[0] = 0; - irCount = azCount[0]; - for(i = 1;i < evCount;i++) + ALushort irCount{azCount[0]}; + for(ALsizei i{1};i < evCount;++i) { evOffset[i] = evOffset[i-1] + azCount[i-1]; irCount += azCount[i]; } - coeffs.resize(irSize*irCount); - delays.resize(irCount); - - size_t reqsize = 2*irSize*irCount + irCount; - if(datalen < reqsize) + std::vector> coeffs(irSize*irCount); + std::vector> delays(irCount); + if(channelType == CHANTYPE_LEFTONLY) { - ERR("Unexpected end of %s data (req " SZFMT ", rem " SZFMT "\n", - filename, reqsize, datalen); - failed = AL_TRUE; + if(sampleType == SAMPLETYPE_S16) + { + for(auto &val : coeffs) + val[0] = GetLE_ALshort(data) / 32768.0f; + } + else if(sampleType == SAMPLETYPE_S24) + { + for(auto &val : coeffs) + val[0] = GetLE_ALint24(data) / 8388608.0f; + } + for(auto &val : delays) + val[0] = GetLE_ALubyte(data); + if(!data || data.eof()) + { + ERR("Failed reading %s\n", filename); + return nullptr; + } + for(ALsizei i{0};i < irCount;++i) + { + if(delays[i][0] > MAX_HRIR_DELAY) + { + ERR("Invalid delays[%d][0]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); + failed = AL_TRUE; + } + } } - - if(!failed) + else if(channelType == CHANTYPE_LEFTRIGHT) { - if(channelType == CHANTYPE_LEFTONLY) + if(sampleType == SAMPLETYPE_S16) { - if(sampleType == SAMPLETYPE_S16) - for(i = 0;i < irCount;i++) - { - for(j = 0;j < irSize;j++) - coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f; - } - else if(sampleType == SAMPLETYPE_S24) - for(i = 0;i < irCount;i++) - { - for(j = 0;j < irSize;j++) - coeffs[i*irSize + j][0] = GetLE_ALint24(&data, &datalen) / 8388608.0f; - } - - for(i = 0;i < irCount;i++) + for(auto &val : coeffs) { - delays[i][0] = GetLE_ALubyte(&data, &datalen); - if(delays[i][0] > MAX_HRIR_DELAY) - { - ERR("Invalid delays[%d][0]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); - failed = AL_TRUE; - } + val[0] = GetLE_ALshort(data) / 32768.0f; + val[1] = GetLE_ALshort(data) / 32768.0f; } } - else if(channelType == CHANTYPE_LEFTRIGHT) + else if(sampleType == SAMPLETYPE_S24) { - if(sampleType == SAMPLETYPE_S16) - for(i = 0;i < irCount;i++) - { - for(j = 0;j < irSize;j++) - { - coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f; - coeffs[i*irSize + j][1] = GetLE_ALshort(&data, &datalen) / 32768.0f; - } - } - else if(sampleType == SAMPLETYPE_S24) - for(i = 0;i < irCount;i++) - { - for(j = 0;j < irSize;j++) - { - coeffs[i*irSize + j][0] = GetLE_ALint24(&data, &datalen) / 8388608.0f; - coeffs[i*irSize + j][1] = GetLE_ALint24(&data, &datalen) / 8388608.0f; - } - } + for(auto &val : coeffs) + { + val[0] = GetLE_ALint24(data) / 8388608.0f; + val[1] = GetLE_ALint24(data) / 8388608.0f; + } + } + for(auto &val : delays) + { + val[0] = GetLE_ALubyte(data); + val[1] = GetLE_ALubyte(data); + } + if(!data || data.eof()) + { + ERR("Failed reading %s\n", filename); + return nullptr; + } - for(i = 0;i < irCount;i++) + for(ALsizei i{0};i < irCount;++i) + { + if(delays[i][0] > MAX_HRIR_DELAY) { - delays[i][0] = GetLE_ALubyte(&data, &datalen); - if(delays[i][0] > MAX_HRIR_DELAY) - { - ERR("Invalid delays[%d][0]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); - failed = AL_TRUE; - } - delays[i][1] = GetLE_ALubyte(&data, &datalen); - if(delays[i][1] > MAX_HRIR_DELAY) - { - ERR("Invalid delays[%d][1]: %d (%d)\n", i, delays[i][1], MAX_HRIR_DELAY); - failed = AL_TRUE; - } + ERR("Invalid delays[%d][0]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); + failed = AL_TRUE; + } + if(delays[i][1] > MAX_HRIR_DELAY) + { + ERR("Invalid delays[%d][1]: %d (%d)\n", i, delays[i][1], MAX_HRIR_DELAY); + failed = AL_TRUE; } } } + if(failed) + return nullptr; - if(!failed) + if(channelType == CHANTYPE_LEFTONLY) { - if(channelType == CHANTYPE_LEFTONLY) + /* Mirror the left ear responses to the right ear. */ + for(ALsizei i{0};i < evCount;i++) { - /* Mirror the left ear responses to the right ear. */ - for(i = 0;i < evCount;i++) + ALushort evoffset = evOffset[i]; + ALubyte azcount = azCount[i]; + for(ALsizei j{0};j < azcount;j++) { - ALushort evoffset = evOffset[i]; - ALubyte azcount = azCount[i]; - for(j = 0;j < azcount;j++) - { - ALsizei lidx = evoffset + j; - ALsizei ridx = evoffset + ((azcount-j) % azcount); - ALsizei k; + ALsizei lidx = evoffset + j; + ALsizei ridx = evoffset + ((azcount-j) % azcount); - for(k = 0;k < irSize;k++) - coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; - delays[ridx][1] = delays[lidx][0]; - } + for(ALsizei k{0};k < irSize;k++) + coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; + delays[ridx][1] = delays[lidx][0]; } } - - Hrtf = CreateHrtfStore(rate, irSize, - (ALfloat)distance / 1000.0f, evCount, irCount, azCount, evOffset.data(), - &reinterpret_cast(coeffs[0]), - &reinterpret_cast(delays[0]), filename - ); } - return Hrtf; + return CreateHrtfStore(rate, irSize, + (ALfloat)distance / 1000.0f, evCount, irCount, azCount.data(), evOffset.data(), + &reinterpret_cast(coeffs[0]), + &reinterpret_cast(delays[0]), filename + ); } -static void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename) +void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename) { - EnumeratedHrtf entry = { AL_STRING_INIT_STATIC(), NULL }; - HrtfEntry *loaded_entry; - const EnumeratedHrtf *iter; - const char *name; - const char *ext; - int i; - /* Check if this file has already been loaded globally. */ - loaded_entry = LoadedHrtfs; + HrtfEntry *loaded_entry{LoadedHrtfs}; while(loaded_entry) { if(alstr_cmp_cstr(filename, loaded_entry->filename) == 0) { + const EnumeratedHrtf *iter; /* Check if this entry has already been added to the list. */ #define MATCH_ENTRY(i) (loaded_entry == (i)->hrtf) VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_ENTRY); @@ -999,21 +976,23 @@ static void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename) FAM_SIZE(struct HrtfEntry, filename, alstr_length(filename)+1) )); loaded_entry->next = LoadedHrtfs; - loaded_entry->handle = NULL; + loaded_entry->handle = nullptr; strcpy(loaded_entry->filename, alstr_get_cstr(filename)); LoadedHrtfs = loaded_entry; } /* TODO: Get a human-readable name from the HRTF data (possibly coming in a * format update). */ - name = strrchr(alstr_get_cstr(filename), '/'); + const char *name{strrchr(alstr_get_cstr(filename), '/')}; if(!name) name = strrchr(alstr_get_cstr(filename), '\\'); if(!name) name = alstr_get_cstr(filename); else ++name; - ext = strrchr(name, '.'); + const char *ext{strrchr(name, '.')}; - i = 0; + EnumeratedHrtf entry = { AL_STRING_INIT_STATIC(), nullptr }; + const EnumeratedHrtf *iter{}; + int i{0}; do { if(!ext) alstr_copy_cstr(&entry.name, name); @@ -1033,29 +1012,21 @@ static void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename) } while(iter != VECTOR_END(*list)); entry.hrtf = loaded_entry; - TRACE("Adding entry \"%s\" from file \"%s\"\n", alstr_get_cstr(entry.name), - alstr_get_cstr(filename)); + TRACE("Adding file entry \"%s\"\n", alstr_get_cstr(entry.name)); VECTOR_PUSH_BACK(*list, entry); } /* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer * for input instead of opening the given filename. */ -static void AddBuiltInEntry(vector_EnumeratedHrtf *list, const_al_string filename, ALuint residx) +void AddBuiltInEntry(vector_EnumeratedHrtf *list, const_al_string filename, ALuint residx) { - EnumeratedHrtf entry = { AL_STRING_INIT_STATIC(), NULL }; - HrtfEntry *loaded_entry; - struct Hrtf *hrtf = NULL; - const EnumeratedHrtf *iter; - const char *name; - const char *ext; - int i; - - loaded_entry = LoadedHrtfs; + HrtfEntry *loaded_entry{LoadedHrtfs}; while(loaded_entry) { if(alstr_cmp_cstr(filename, loaded_entry->filename) == 0) { + const EnumeratedHrtf *iter{}; #define MATCH_ENTRY(i) (loaded_entry == (i)->hrtf) VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_ENTRY); #undef MATCH_ENTRY @@ -1080,7 +1051,7 @@ static void AddBuiltInEntry(vector_EnumeratedHrtf *list, const_al_string filenam FAM_SIZE(struct HrtfEntry, filename, namelen) )); loaded_entry->next = LoadedHrtfs; - loaded_entry->handle = hrtf; + loaded_entry->handle = nullptr; snprintf(loaded_entry->filename, namelen, "!%u_%s", residx, alstr_get_cstr(filename)); LoadedHrtfs = loaded_entry; @@ -1088,14 +1059,16 @@ static void AddBuiltInEntry(vector_EnumeratedHrtf *list, const_al_string filenam /* TODO: Get a human-readable name from the HRTF data (possibly coming in a * format update). */ - name = strrchr(alstr_get_cstr(filename), '/'); + const char *name{strrchr(alstr_get_cstr(filename), '/')}; if(!name) name = strrchr(alstr_get_cstr(filename), '\\'); if(!name) name = alstr_get_cstr(filename); else ++name; - ext = strrchr(name, '.'); + const char *ext{strrchr(name, '.')}; - i = 0; + EnumeratedHrtf entry{AL_STRING_INIT_STATIC(), nullptr}; + const EnumeratedHrtf *iter{}; + int i{0}; do { if(!ext) alstr_copy_cstr(&entry.name, name); @@ -1123,44 +1096,36 @@ static void AddBuiltInEntry(vector_EnumeratedHrtf *list, const_al_string filenam #define IDR_DEFAULT_44100_MHR 1 #define IDR_DEFAULT_48000_MHR 2 +struct ResData { const char *data; size_t size; }; #ifndef ALSOFT_EMBED_HRTF_DATA -static const ALubyte *GetResource(int UNUSED(name), size_t *size) -{ - *size = 0; - return NULL; -} +ResData GetResource(int UNUSED(name)) +{ return {nullptr, 0u}; } #else #include "default-44100.mhr.h" #include "default-48000.mhr.h" -static const ALubyte *GetResource(int name, size_t *size) +ResData GetResource(int name) { if(name == IDR_DEFAULT_44100_MHR) - { - *size = sizeof(hrtf_default_44100); - return hrtf_default_44100; - } + return {reinterpret_cast(hrtf_default_44100), sizeof(hrtf_default_44100)}; if(name == IDR_DEFAULT_48000_MHR) - { - *size = sizeof(hrtf_default_48000); - return hrtf_default_48000; - } - *size = 0; - return NULL; + return {reinterpret_cast(hrtf_default_48000), sizeof(hrtf_default_48000)}; + return {nullptr, 0u}; } #endif +} // namespace + + vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname) { - vector_EnumeratedHrtf list = VECTOR_INIT_STATIC(); - const char *defaulthrtf = ""; - const char *pathlist = ""; - bool usedefaults = true; - - if(ConfigValueStr(alstr_get_cstr(devname), NULL, "hrtf-paths", &pathlist)) + vector_EnumeratedHrtf list{VECTOR_INIT_STATIC()}; + bool usedefaults{true}; + const char *pathlist{""}; + if(ConfigValueStr(alstr_get_cstr(devname), nullptr, "hrtf-paths", &pathlist)) { al_string pname = AL_STRING_INIT_STATIC(); while(pathlist && *pathlist) @@ -1185,13 +1150,10 @@ vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname) --end; if(end != pathlist) { - vector_al_string flist; - size_t i; - alstr_copy_range(&pname, pathlist, end); - flist = SearchDataFiles(".mhr", alstr_get_cstr(pname)); - for(i = 0;i < VECTOR_SIZE(flist);i++) + vector_al_string flist{SearchDataFiles(".mhr", alstr_get_cstr(pname))}; + for(size_t i{0};i < VECTOR_SIZE(flist);i++) AddFileEntry(&list, VECTOR_ELEM(flist, i)); VECTOR_FOR_EACH(al_string, flist, alstr_reset); VECTOR_DEINIT(flist); @@ -1202,31 +1164,27 @@ vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname) alstr_reset(&pname); } - else if(ConfigValueExists(alstr_get_cstr(devname), NULL, "hrtf_tables")) + else if(ConfigValueExists(alstr_get_cstr(devname), nullptr, "hrtf_tables")) ERR("The hrtf_tables option is deprecated, please use hrtf-paths instead.\n"); if(usedefaults) { - al_string ename = AL_STRING_INIT_STATIC(); - vector_al_string flist; - const ALubyte *rdata; - size_t rsize, i; - - flist = SearchDataFiles(".mhr", "openal/hrtf"); - for(i = 0;i < VECTOR_SIZE(flist);i++) + vector_al_string flist{SearchDataFiles(".mhr", "openal/hrtf")}; + for(size_t i{0};i < VECTOR_SIZE(flist);i++) AddFileEntry(&list, VECTOR_ELEM(flist, i)); VECTOR_FOR_EACH(al_string, flist, alstr_reset); VECTOR_DEINIT(flist); - rdata = GetResource(IDR_DEFAULT_44100_MHR, &rsize); - if(rdata != NULL && rsize > 0) + al_string ename = AL_STRING_INIT_STATIC(); + ResData res{GetResource(IDR_DEFAULT_44100_MHR)}; + if(res.data != nullptr && res.size > 0) { alstr_copy_cstr(&ename, "Built-In 44100hz"); AddBuiltInEntry(&list, ename, IDR_DEFAULT_44100_MHR); } - rdata = GetResource(IDR_DEFAULT_48000_MHR, &rsize); - if(rdata != NULL && rsize > 0) + res = GetResource(IDR_DEFAULT_48000_MHR); + if(res.data != nullptr && res.size > 0) { alstr_copy_cstr(&ename, "Built-In 48000hz"); AddBuiltInEntry(&list, ename, IDR_DEFAULT_48000_MHR); @@ -1234,9 +1192,10 @@ vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname) alstr_reset(&ename); } - if(VECTOR_SIZE(list) > 1 && ConfigValueStr(alstr_get_cstr(devname), NULL, "default-hrtf", &defaulthrtf)) + const char *defaulthrtf{""}; + if(VECTOR_SIZE(list) > 1 && ConfigValueStr(alstr_get_cstr(devname), nullptr, "default-hrtf", &defaulthrtf)) { - const EnumeratedHrtf *iter; + const EnumeratedHrtf *iter{}; /* Find the preferred HRTF and move it to the front of the list. */ #define FIND_ENTRY(i) (alstr_cmp_cstr((i)->name, defaulthrtf) == 0) VECTOR_FIND_IF(iter, const EnumeratedHrtf, list, FIND_ENTRY); @@ -1245,7 +1204,7 @@ vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname) WARN("Failed to find default HRTF \"%s\"\n", defaulthrtf); else if(iter != VECTOR_BEGIN(list)) { - EnumeratedHrtf entry = *iter; + EnumeratedHrtf entry{*iter}; memmove(&VECTOR_ELEM(list,1), &VECTOR_ELEM(list,0), (iter-VECTOR_BEGIN(list))*sizeof(EnumeratedHrtf)); VECTOR_ELEM(list,0) = entry; @@ -1265,95 +1224,80 @@ void FreeHrtfList(vector_EnumeratedHrtf *list) struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry) { - struct Hrtf *hrtf = NULL; - struct FileMapping fmap; - const ALubyte *rdata; - const char *name; - ALuint residx; - size_t rsize; - char ch; - - while(ATOMIC_FLAG_TEST_AND_SET(&LoadedHrtfLock, almemory_order_seq_cst)) - althrd_yield(); + std::lock_guard _{LoadedHrtfLock}; if(entry->handle) { - hrtf = entry->handle; + Hrtf *hrtf{entry->handle}; Hrtf_IncRef(hrtf); - goto done; + return hrtf; } - fmap.ptr = NULL; - fmap.len = 0; + std::unique_ptr stream; + const char *name{""}; + ALuint residx{}; + char ch{}; if(sscanf(entry->filename, "!%u%c", &residx, &ch) == 2 && ch == '_') { name = strchr(entry->filename, ch)+1; TRACE("Loading %s...\n", name); - rdata = GetResource(residx, &rsize); - if(rdata == NULL || rsize == 0) + ResData res{GetResource(residx)}; + if(!res.data || res.size == 0) { ERR("Could not get resource %u, %s\n", residx, name); - goto done; + return nullptr; } + stream.reset(new idstream{res.data, res.data+res.size}); } else { name = entry->filename; TRACE("Loading %s...\n", entry->filename); - fmap = MapFileToMem(entry->filename); - if(fmap.ptr == NULL) + std::unique_ptr fstr{new al::ifstream{entry->filename, std::ios::binary}}; + if(!fstr->is_open()) { ERR("Could not open %s\n", entry->filename); - goto done; + return nullptr; } - - rdata = static_cast(fmap.ptr); - rsize = fmap.len; + stream = std::move(fstr); } - if(rsize < sizeof(magicMarker02)) - ERR("%s data is too short (" SZFMT " bytes)\n", name, rsize); - else if(memcmp(rdata, magicMarker02, sizeof(magicMarker02)) == 0) + Hrtf *hrtf{}; + char magic[sizeof(magicMarker02)]; + stream->read(magic, sizeof(magic)); + if(stream->gcount() < static_cast(sizeof(magicMarker02))) + ERR("%s data is too short (" SZFMT " bytes)\n", name, stream->gcount()); + else if(memcmp(magic, magicMarker02, sizeof(magicMarker02)) == 0) { TRACE("Detected data set format v2\n"); - hrtf = LoadHrtf02(rdata+sizeof(magicMarker02), - rsize-sizeof(magicMarker02), name - ); + hrtf = LoadHrtf02(*stream, name); } - else if(memcmp(rdata, magicMarker01, sizeof(magicMarker01)) == 0) + else if(memcmp(magic, magicMarker01, sizeof(magicMarker01)) == 0) { TRACE("Detected data set format v1\n"); - hrtf = LoadHrtf01(rdata+sizeof(magicMarker01), - rsize-sizeof(magicMarker01), name - ); + hrtf = LoadHrtf01(*stream, name); } - else if(memcmp(rdata, magicMarker00, sizeof(magicMarker00)) == 0) + else if(memcmp(magic, magicMarker00, sizeof(magicMarker00)) == 0) { TRACE("Detected data set format v0\n"); - hrtf = LoadHrtf00(rdata+sizeof(magicMarker00), - rsize-sizeof(magicMarker00), name - ); + hrtf = LoadHrtf00(*stream, name); } else - ERR("Invalid header in %s: \"%.8s\"\n", name, (const char*)rdata); - if(fmap.ptr) - UnmapFileMem(&fmap); + ERR("Invalid header in %s: \"%.8s\"\n", name, magic); + stream.reset(); if(!hrtf) - { ERR("Failed to load %s\n", name); - goto done; + else + { + entry->handle = hrtf; + Hrtf_IncRef(hrtf); + TRACE("Loaded HRTF support for format: %s %uhz\n", + DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); } - entry->handle = hrtf; - Hrtf_IncRef(hrtf); - - TRACE("Loaded HRTF support for format: %s %uhz\n", - DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); -done: - ATOMIC_FLAG_CLEAR(&LoadedHrtfLock, almemory_order_seq_cst); return hrtf; } @@ -1366,16 +1310,14 @@ void Hrtf_IncRef(struct Hrtf *hrtf) void Hrtf_DecRef(struct Hrtf *hrtf) { - struct HrtfEntry *Hrtf; uint ref = DecrementRef(&hrtf->ref); TRACEREF("%p decreasing refcount to %u\n", hrtf, ref); if(ref == 0) { - while(ATOMIC_FLAG_TEST_AND_SET(&LoadedHrtfLock, almemory_order_seq_cst)) - althrd_yield(); + std::lock_guard _{LoadedHrtfLock}; - Hrtf = LoadedHrtfs; - while(Hrtf != NULL) + struct HrtfEntry *Hrtf{LoadedHrtfs}; + while(Hrtf != nullptr) { /* Need to double-check that it's still unused, as another device * could've reacquired this HRTF after its reference went to 0 and @@ -1384,25 +1326,23 @@ void Hrtf_DecRef(struct Hrtf *hrtf) if(hrtf == Hrtf->handle && ReadRef(&hrtf->ref) == 0) { al_free(Hrtf->handle); - Hrtf->handle = NULL; + Hrtf->handle = nullptr; TRACE("Unloaded unused HRTF %s\n", Hrtf->filename); } Hrtf = Hrtf->next; } - - ATOMIC_FLAG_CLEAR(&LoadedHrtfLock, almemory_order_seq_cst); } } void FreeHrtfs(void) { - struct HrtfEntry *Hrtf = LoadedHrtfs; - LoadedHrtfs = NULL; + struct HrtfEntry *Hrtf{LoadedHrtfs}; + LoadedHrtfs = nullptr; - while(Hrtf != NULL) + while(Hrtf != nullptr) { - struct HrtfEntry *next = Hrtf->next; + struct HrtfEntry *next{Hrtf->next}; al_free(Hrtf->handle); al_free(Hrtf); Hrtf = next; -- cgit v1.2.3 From 68bcf81756d160f9bf1c6c68b9d83611754ff54a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 9 Nov 2018 23:51:29 -0800 Subject: Remove the unused file mapping calls --- Alc/compat.h | 13 -------- Alc/helpers.c | 103 ---------------------------------------------------------- 2 files changed, 116 deletions(-) diff --git a/Alc/compat.h b/Alc/compat.h index 25bb0c45..3a5d66c2 100644 --- a/Alc/compat.h +++ b/Alc/compat.h @@ -244,19 +244,6 @@ extern "C" { #endif -struct FileMapping { -#ifdef _WIN32 - HANDLE file; - HANDLE fmap; -#else - int fd; -#endif - void *ptr; - size_t len; -}; -struct FileMapping MapFileToMem(const char *fname); -void UnmapFileMem(const struct FileMapping *mapping); - void GetProcBinary(al_string *path, al_string *fname); #ifdef HAVE_DYNLOAD diff --git a/Alc/helpers.c b/Alc/helpers.c index 0d5087e6..41e4fdc9 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -614,68 +614,6 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) return results; } - -struct FileMapping MapFileToMem(const char *fname) -{ - struct FileMapping ret = { NULL, NULL, NULL, 0 }; - MEMORY_BASIC_INFORMATION meminfo; - HANDLE file, fmap; - WCHAR *wname; - void *ptr; - - wname = FromUTF8(fname); - - file = CreateFileW(wname, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if(file == INVALID_HANDLE_VALUE) - { - ERR("Failed to open %s: %lu\n", fname, GetLastError()); - free(wname); - return ret; - } - free(wname); - wname = NULL; - - fmap = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL); - if(!fmap) - { - ERR("Failed to create map for %s: %lu\n", fname, GetLastError()); - CloseHandle(file); - return ret; - } - - ptr = MapViewOfFile(fmap, FILE_MAP_READ, 0, 0, 0); - if(!ptr) - { - ERR("Failed to map %s: %lu\n", fname, GetLastError()); - CloseHandle(fmap); - CloseHandle(file); - return ret; - } - - if(VirtualQuery(ptr, &meminfo, sizeof(meminfo)) != sizeof(meminfo)) - { - ERR("Failed to get map size for %s: %lu\n", fname, GetLastError()); - UnmapViewOfFile(ptr); - CloseHandle(fmap); - CloseHandle(file); - return ret; - } - - ret.file = file; - ret.fmap = fmap; - ret.ptr = ptr; - ret.len = meminfo.RegionSize; - return ret; -} - -void UnmapFileMem(const struct FileMapping *mapping) -{ - UnmapViewOfFile(mapping->ptr); - CloseHandle(mapping->fmap); - CloseHandle(mapping->file); -} - #else void GetProcBinary(al_string *path, al_string *fname) @@ -959,47 +897,6 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) return results; } - -struct FileMapping MapFileToMem(const char *fname) -{ - struct FileMapping ret = { -1, NULL, 0 }; - struct stat sbuf; - void *ptr; - int fd; - - fd = open(fname, O_RDONLY, 0); - if(fd == -1) - { - ERR("Failed to open %s: (%d) %s\n", fname, errno, strerror(errno)); - return ret; - } - if(fstat(fd, &sbuf) == -1) - { - ERR("Failed to stat %s: (%d) %s\n", fname, errno, strerror(errno)); - close(fd); - return ret; - } - - ptr = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if(ptr == MAP_FAILED) - { - ERR("Failed to map %s: (%d) %s\n", fname, errno, strerror(errno)); - close(fd); - return ret; - } - - ret.fd = fd; - ret.ptr = ptr; - ret.len = sbuf.st_size; - return ret; -} - -void UnmapFileMem(const struct FileMapping *mapping) -{ - munmap(mapping->ptr, mapping->len); - close(mapping->fd); -} - #endif -- cgit v1.2.3 From 981205de36aa05388d431a0c41fff1136aec327d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 10 Nov 2018 00:01:34 -0800 Subject: Remove unused strdupW --- Alc/compat.h | 2 -- Alc/helpers.c | 16 ---------------- 2 files changed, 18 deletions(-) diff --git a/Alc/compat.h b/Alc/compat.h index 3a5d66c2..77845d73 100644 --- a/Alc/compat.h +++ b/Alc/compat.h @@ -12,8 +12,6 @@ extern "C" { #define WIN32_LEAN_AND_MEAN #include -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); diff --git a/Alc/helpers.c b/Alc/helpers.c index 41e4fdc9..000b9576 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -429,22 +429,6 @@ void *GetSymbol(void *handle, const char *name) return ret; } -WCHAR *strdupW(const WCHAR *str) -{ - const WCHAR *n; - WCHAR *ret; - size_t len; - - n = str; - while(*n) n++; - len = n - str; - - ret = calloc(sizeof(WCHAR), len+1); - if(ret != NULL) - memcpy(ret, str, sizeof(WCHAR)*len); - return ret; -} - FILE *al_fopen(const char *fname, const char *mode) { WCHAR *wname=NULL, *wmode=NULL; -- cgit v1.2.3 From 5ec644f859390b13fd47260c97ae34c21d5ca5f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 10 Nov 2018 00:13:35 -0800 Subject: Convert alconfig to C++ --- Alc/alconfig.c | 698 ------------------------------------------------------ Alc/alconfig.cpp | 699 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 700 insertions(+), 699 deletions(-) delete mode 100644 Alc/alconfig.c create mode 100644 Alc/alconfig.cpp diff --git a/Alc/alconfig.c b/Alc/alconfig.c deleted file mode 100644 index 050391af..00000000 --- a/Alc/alconfig.c +++ /dev/null @@ -1,698 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * 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 -#include -#include -#include -#ifdef _WIN32_IE -#include -#include -#endif -#ifdef __APPLE__ -#include -#endif - -#include "alMain.h" -#include "alconfig.h" -#include "compat.h" -#include "bool.h" - - -typedef struct ConfigEntry { - char *key; - char *value; -} ConfigEntry; - -typedef struct ConfigBlock { - ConfigEntry *entries; - unsigned int entryCount; -} ConfigBlock; -static ConfigBlock cfgBlock; - - -static char *lstrip(char *line) -{ - while(isspace(line[0])) - line++; - return line; -} - -static char *rstrip(char *line) -{ - size_t len = strlen(line); - while(len > 0 && isspace(line[len-1])) - len--; - line[len] = 0; - 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 - { - bool hasbraces; - char envname[1024]; - size_t k = 0; - - hasbraces = (*str == '{'); - if(hasbraces) str++; - - while((isalnum(*str) || *str == '_') && k < sizeof(envname)-1) - envname[k++] = *(str++); - envname[k++] = '\0'; - - if(hasbraces && *str != '}') - continue; - - if(hasbraces) str++; - 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(readline(f, &buffer, &maxlen)) - { - char *line, *comment; - char key[256] = ""; - char value[256] = ""; - - line = rstrip(lstrip(buffer)); - if(!line[0]) continue; - - if(line[0] == '[') - { - char *section = line+1; - char *endsection; - - endsection = strchr(section, ']'); - if(!endsection || section == endsection) - { - ERR("config parse error: bad line \"%s\"\n", line); - continue; - } - if(endsection[1] != 0) - { - char *end = endsection+1; - while(isspace(*end)) - ++end; - if(*end != 0 && *end != '#') - { - ERR("config parse error: bad line \"%s\"\n", line); - continue; - } - } - *endsection = 0; - - if(strcasecmp(section, "general") == 0) - curSection[0] = 0; - else - { - size_t len, p = 0; - do { - char *nextp = strchr(section, '%'); - if(!nextp) - { - strncpy(curSection+p, section, sizeof(curSection)-1-p); - break; - } - - len = nextp - section; - if(len > sizeof(curSection)-1-p) - len = sizeof(curSection)-1-p; - strncpy(curSection+p, section, len); - p += len; - section = nextp; - - if(((section[1] >= '0' && section[1] <= '9') || - (section[1] >= 'a' && section[1] <= 'f') || - (section[1] >= 'A' && section[1] <= 'F')) && - ((section[2] >= '0' && section[2] <= '9') || - (section[2] >= 'a' && section[2] <= 'f') || - (section[2] >= 'A' && section[2] <= 'F'))) - { - unsigned char b = 0; - if(section[1] >= '0' && section[1] <= '9') - b = (section[1]-'0') << 4; - else if(section[1] >= 'a' && section[1] <= 'f') - b = (section[1]-'a'+0xa) << 4; - else if(section[1] >= 'A' && section[1] <= 'F') - b = (section[1]-'A'+0x0a) << 4; - if(section[2] >= '0' && section[2] <= '9') - b |= (section[2]-'0'); - else if(section[2] >= 'a' && section[2] <= 'f') - b |= (section[2]-'a'+0xa); - else if(section[2] >= 'A' && section[2] <= 'F') - b |= (section[2]-'A'+0x0a); - if(p < sizeof(curSection)-1) - curSection[p++] = b; - section += 3; - } - else if(section[1] == '%') - { - if(p < sizeof(curSection)-1) - curSection[p++] = '%'; - section += 2; - } - else - { - if(p < sizeof(curSection)-1) - curSection[p++] = '%'; - section += 1; - } - if(p < sizeof(curSection)-1) - curSection[p] = 0; - } while(p < sizeof(curSection)-1 && *section != 0); - curSection[sizeof(curSection)-1] = 0; - } - - continue; - } - - comment = strchr(line, '#'); - if(comment) *(comment++) = 0; - if(!line[0]) continue; - - if(sscanf(line, "%255[^=] = \"%255[^\"]\"", key, value) == 2 || - sscanf(line, "%255[^=] = '%255[^\']'", key, value) == 2 || - sscanf(line, "%255[^=] = %255[^\n]", key, value) == 2) - { - /* sscanf doesn't handle '' or "" as empty values, so clip it - * 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); - } - - /* Check if we already have this option set */ - ent = cfgBlock.entries; - while((unsigned int)(ent-cfgBlock.entries) < cfgBlock.entryCount) - { - if(strcasecmp(ent->key, key) == 0) - break; - ent++; - } - - if((unsigned int)(ent-cfgBlock.entries) >= cfgBlock.entryCount) - { - /* Allocate a new option entry */ - ent = realloc(cfgBlock.entries, (cfgBlock.entryCount+1)*sizeof(ConfigEntry)); - if(!ent) - { - ERR("config parse error: error reallocating config entries\n"); - continue; - } - cfgBlock.entries = ent; - ent = cfgBlock.entries + cfgBlock.entryCount; - cfgBlock.entryCount++; - - ent->key = strdup(key); - ent->value = NULL; - } - - free(ent->value); - ent->value = expdup(value); - - TRACE("found '%s' = '%s'\n", ent->key, ent->value); - } - - free(buffer); -} - -#ifdef _WIN32 -void ReadALConfig(void) -{ - al_string ppath = AL_STRING_INIT_STATIC(); - WCHAR buffer[MAX_PATH]; - const WCHAR *str; - FILE *f; - - if(SHGetSpecialFolderPathW(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE) - { - al_string filepath = AL_STRING_INIT_STATIC(); - alstr_copy_wcstr(&filepath, buffer); - alstr_append_cstr(&filepath, "\\alsoft.ini"); - - TRACE("Loading config %s...\n", alstr_get_cstr(filepath)); - f = al_fopen(alstr_get_cstr(filepath), "rt"); - if(f) - { - LoadConfigFromFile(f); - fclose(f); - } - alstr_reset(&filepath); - } - - GetProcBinary(&ppath, NULL); - if(!alstr_empty(ppath)) - { - alstr_append_cstr(&ppath, "\\alsoft.ini"); - TRACE("Loading config %s...\n", alstr_get_cstr(ppath)); - f = al_fopen(alstr_get_cstr(ppath), "r"); - if(f) - { - LoadConfigFromFile(f); - fclose(f); - } - } - - if((str=_wgetenv(L"ALSOFT_CONF")) != NULL && *str) - { - al_string filepath = AL_STRING_INIT_STATIC(); - alstr_copy_wcstr(&filepath, str); - - TRACE("Loading config %s...\n", alstr_get_cstr(filepath)); - f = al_fopen(alstr_get_cstr(filepath), "rt"); - if(f) - { - LoadConfigFromFile(f); - fclose(f); - } - alstr_reset(&filepath); - } - - alstr_reset(&ppath); -} -#else -void ReadALConfig(void) -{ - al_string confpaths = AL_STRING_INIT_STATIC(); - al_string fname = AL_STRING_INIT_STATIC(); - const char *str; - FILE *f; - - str = "/etc/openal/alsoft.conf"; - - TRACE("Loading config %s...\n", str); - f = al_fopen(str, "r"); - if(f) - { - LoadConfigFromFile(f); - fclose(f); - } - - if(!(str=getenv("XDG_CONFIG_DIRS")) || str[0] == 0) - str = "/etc/xdg"; - alstr_copy_cstr(&confpaths, str); - /* Go through the list in reverse, since "the order of base directories - * denotes their importance; the first directory listed is the most - * important". Ergo, we need to load the settings from the later dirs - * first so that the settings in the earlier dirs override them. - */ - while(!alstr_empty(confpaths)) - { - char *next = strrchr(alstr_get_cstr(confpaths), ':'); - if(next) - { - size_t len = next - alstr_get_cstr(confpaths); - alstr_copy_cstr(&fname, next+1); - VECTOR_RESIZE(confpaths, len, len+1); - VECTOR_ELEM(confpaths, len) = 0; - } - else - { - alstr_reset(&fname); - fname = confpaths; - AL_STRING_INIT(confpaths); - } - - if(alstr_empty(fname) || VECTOR_FRONT(fname) != '/') - WARN("Ignoring XDG config dir: %s\n", alstr_get_cstr(fname)); - else - { - if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/alsoft.conf"); - else alstr_append_cstr(&fname, "alsoft.conf"); - - TRACE("Loading config %s...\n", alstr_get_cstr(fname)); - f = al_fopen(alstr_get_cstr(fname), "r"); - if(f) - { - LoadConfigFromFile(f); - fclose(f); - } - } - alstr_clear(&fname); - } - -#ifdef __APPLE__ - CFBundleRef mainBundle = CFBundleGetMainBundle(); - if(mainBundle) - { - unsigned char fileName[PATH_MAX]; - CFURLRef configURL; - - if((configURL=CFBundleCopyResourceURL(mainBundle, CFSTR(".alsoftrc"), CFSTR(""), NULL)) && - CFURLGetFileSystemRepresentation(configURL, true, fileName, sizeof(fileName))) - { - f = al_fopen((const char*)fileName, "r"); - if(f) - { - LoadConfigFromFile(f); - fclose(f); - } - } - } -#endif - - if((str=getenv("HOME")) != NULL && *str) - { - alstr_copy_cstr(&fname, str); - if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/.alsoftrc"); - else alstr_append_cstr(&fname, ".alsoftrc"); - - TRACE("Loading config %s...\n", alstr_get_cstr(fname)); - f = al_fopen(alstr_get_cstr(fname), "r"); - if(f) - { - LoadConfigFromFile(f); - fclose(f); - } - } - - if((str=getenv("XDG_CONFIG_HOME")) != NULL && str[0] != 0) - { - alstr_copy_cstr(&fname, str); - if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/alsoft.conf"); - else alstr_append_cstr(&fname, "alsoft.conf"); - } - else - { - alstr_clear(&fname); - if((str=getenv("HOME")) != NULL && str[0] != 0) - { - alstr_copy_cstr(&fname, str); - if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/.config/alsoft.conf"); - else alstr_append_cstr(&fname, ".config/alsoft.conf"); - } - } - if(!alstr_empty(fname)) - { - TRACE("Loading config %s...\n", alstr_get_cstr(fname)); - f = al_fopen(alstr_get_cstr(fname), "r"); - if(f) - { - LoadConfigFromFile(f); - fclose(f); - } - } - - alstr_clear(&fname); - GetProcBinary(&fname, NULL); - if(!alstr_empty(fname)) - { - if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/alsoft.conf"); - else alstr_append_cstr(&fname, "alsoft.conf"); - - TRACE("Loading config %s...\n", alstr_get_cstr(fname)); - f = al_fopen(alstr_get_cstr(fname), "r"); - if(f) - { - LoadConfigFromFile(f); - fclose(f); - } - } - - if((str=getenv("ALSOFT_CONF")) != NULL && *str) - { - TRACE("Loading config %s...\n", str); - f = al_fopen(str, "r"); - if(f) - { - LoadConfigFromFile(f); - fclose(f); - } - } - - alstr_reset(&fname); - alstr_reset(&confpaths); -} -#endif - -void FreeALConfig(void) -{ - unsigned int i; - - for(i = 0;i < cfgBlock.entryCount;i++) - { - free(cfgBlock.entries[i].key); - free(cfgBlock.entries[i].value); - } - free(cfgBlock.entries); -} - -const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def) -{ - unsigned int i; - char key[256]; - - if(!keyName) - return def; - - if(blockName && strcasecmp(blockName, "general") != 0) - { - if(devName) - snprintf(key, sizeof(key), "%s/%s/%s", blockName, devName, keyName); - else - snprintf(key, sizeof(key), "%s/%s", blockName, keyName); - } - else - { - if(devName) - snprintf(key, sizeof(key), "%s/%s", devName, keyName); - else - { - strncpy(key, keyName, sizeof(key)-1); - key[sizeof(key)-1] = 0; - } - } - - for(i = 0;i < cfgBlock.entryCount;i++) - { - if(strcmp(cfgBlock.entries[i].key, key) == 0) - { - TRACE("Found %s = \"%s\"\n", key, cfgBlock.entries[i].value); - if(cfgBlock.entries[i].value[0]) - return cfgBlock.entries[i].value; - return def; - } - } - - if(!devName) - { - TRACE("Key %s not found\n", key); - return def; - } - return GetConfigValue(NULL, blockName, keyName, def); -} - -int ConfigValueExists(const char *devName, const char *blockName, const char *keyName) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - return val[0] != 0; -} - -int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return 0; - - *ret = val; - return 1; -} - -int ConfigValueInt(const char *devName, const char *blockName, const char *keyName, int *ret) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return 0; - - *ret = strtol(val, NULL, 0); - return 1; -} - -int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return 0; - - *ret = strtoul(val, NULL, 0); - return 1; -} - -int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return 0; - -#ifdef HAVE_STRTOF - *ret = strtof(val, NULL); -#else - *ret = (float)strtod(val, NULL); -#endif - return 1; -} - -int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return 0; - - *ret = (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || - strcasecmp(val, "on") == 0 || atoi(val) != 0); - return 1; -} - -int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - - if(!val[0]) return def != 0; - return (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || - strcasecmp(val, "on") == 0 || atoi(val) != 0); -} diff --git a/Alc/alconfig.cpp b/Alc/alconfig.cpp new file mode 100644 index 00000000..f617a669 --- /dev/null +++ b/Alc/alconfig.cpp @@ -0,0 +1,699 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * 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 +#include +#include +#include +#ifdef _WIN32_IE +#include +#include +#endif +#ifdef __APPLE__ +#include +#endif + +#include "alMain.h" +#include "alconfig.h" +#include "compat.h" +#include "bool.h" + + +typedef struct ConfigEntry { + char *key; + char *value; +} ConfigEntry; + +typedef struct ConfigBlock { + ConfigEntry *entries; + unsigned int entryCount; +} ConfigBlock; +static ConfigBlock cfgBlock; + + +static char *lstrip(char *line) +{ + while(isspace(line[0])) + line++; + return line; +} + +static char *rstrip(char *line) +{ + size_t len = strlen(line); + while(len > 0 && isspace(line[len-1])) + len--; + line[len] = 0; + 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 = nullptr; + 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 = static_cast(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 = nullptr; + 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 + { + bool hasbraces; + char envname[1024]; + size_t k = 0; + + hasbraces = (*str == '{'); + if(hasbraces) str++; + + while((isalnum(*str) || *str == '_') && k < sizeof(envname)-1) + envname[k++] = *(str++); + envname[k++] = '\0'; + + if(hasbraces && *str != '}') + continue; + + if(hasbraces) str++; + if((addstr=getenv(envname)) == nullptr) + continue; + addstrlen = strlen(addstr); + } + } + if(addstrlen == 0) + continue; + + if(addstrlen >= maxlen-len) + { + void *temp = nullptr; + 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 = static_cast(temp); + maxlen = newmax; + } + + for(i = 0;i < addstrlen;i++) + output[len++] = addstr[i]; + output[len] = '\0'; + } + + return output ? output : static_cast(calloc(1, 1)); +} + + +static void LoadConfigFromFile(FILE *f) +{ + char curSection[128] = ""; + char *buffer = nullptr; + size_t maxlen = 0; + ConfigEntry *ent; + + while(readline(f, &buffer, &maxlen)) + { + char *line, *comment; + char key[256] = ""; + char value[256] = ""; + + line = rstrip(lstrip(buffer)); + if(!line[0]) continue; + + if(line[0] == '[') + { + char *section = line+1; + char *endsection; + + endsection = strchr(section, ']'); + if(!endsection || section == endsection) + { + ERR("config parse error: bad line \"%s\"\n", line); + continue; + } + if(endsection[1] != 0) + { + char *end = endsection+1; + while(isspace(*end)) + ++end; + if(*end != 0 && *end != '#') + { + ERR("config parse error: bad line \"%s\"\n", line); + continue; + } + } + *endsection = 0; + + if(strcasecmp(section, "general") == 0) + curSection[0] = 0; + else + { + size_t len, p = 0; + do { + char *nextp = strchr(section, '%'); + if(!nextp) + { + strncpy(curSection+p, section, sizeof(curSection)-1-p); + break; + } + + len = nextp - section; + if(len > sizeof(curSection)-1-p) + len = sizeof(curSection)-1-p; + strncpy(curSection+p, section, len); + p += len; + section = nextp; + + if(((section[1] >= '0' && section[1] <= '9') || + (section[1] >= 'a' && section[1] <= 'f') || + (section[1] >= 'A' && section[1] <= 'F')) && + ((section[2] >= '0' && section[2] <= '9') || + (section[2] >= 'a' && section[2] <= 'f') || + (section[2] >= 'A' && section[2] <= 'F'))) + { + unsigned char b = 0; + if(section[1] >= '0' && section[1] <= '9') + b = (section[1]-'0') << 4; + else if(section[1] >= 'a' && section[1] <= 'f') + b = (section[1]-'a'+0xa) << 4; + else if(section[1] >= 'A' && section[1] <= 'F') + b = (section[1]-'A'+0x0a) << 4; + if(section[2] >= '0' && section[2] <= '9') + b |= (section[2]-'0'); + else if(section[2] >= 'a' && section[2] <= 'f') + b |= (section[2]-'a'+0xa); + else if(section[2] >= 'A' && section[2] <= 'F') + b |= (section[2]-'A'+0x0a); + if(p < sizeof(curSection)-1) + curSection[p++] = b; + section += 3; + } + else if(section[1] == '%') + { + if(p < sizeof(curSection)-1) + curSection[p++] = '%'; + section += 2; + } + else + { + if(p < sizeof(curSection)-1) + curSection[p++] = '%'; + section += 1; + } + if(p < sizeof(curSection)-1) + curSection[p] = 0; + } while(p < sizeof(curSection)-1 && *section != 0); + curSection[sizeof(curSection)-1] = 0; + } + + continue; + } + + comment = strchr(line, '#'); + if(comment) *(comment++) = 0; + if(!line[0]) continue; + + if(sscanf(line, "%255[^=] = \"%255[^\"]\"", key, value) == 2 || + sscanf(line, "%255[^=] = '%255[^\']'", key, value) == 2 || + sscanf(line, "%255[^=] = %255[^\n]", key, value) == 2) + { + /* sscanf doesn't handle '' or "" as empty values, so clip it + * 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); + } + + /* Check if we already have this option set */ + ent = cfgBlock.entries; + while((unsigned int)(ent-cfgBlock.entries) < cfgBlock.entryCount) + { + if(strcasecmp(ent->key, key) == 0) + break; + ent++; + } + + if((unsigned int)(ent-cfgBlock.entries) >= cfgBlock.entryCount) + { + /* Allocate a new option entry */ + ent = static_cast(realloc(cfgBlock.entries, + (cfgBlock.entryCount+1)*sizeof(ConfigEntry))); + if(!ent) + { + ERR("config parse error: error reallocating config entries\n"); + continue; + } + cfgBlock.entries = ent; + ent = cfgBlock.entries + cfgBlock.entryCount; + cfgBlock.entryCount++; + + ent->key = strdup(key); + ent->value = nullptr; + } + + free(ent->value); + ent->value = expdup(value); + + TRACE("found '%s' = '%s'\n", ent->key, ent->value); + } + + free(buffer); +} + +#ifdef _WIN32 +void ReadALConfig(void) +{ + al_string ppath = AL_STRING_INIT_STATIC(); + WCHAR buffer[MAX_PATH]; + const WCHAR *str; + FILE *f; + + if(SHGetSpecialFolderPathW(nullptr, buffer, CSIDL_APPDATA, FALSE) != FALSE) + { + al_string filepath = AL_STRING_INIT_STATIC(); + alstr_copy_wcstr(&filepath, buffer); + alstr_append_cstr(&filepath, "\\alsoft.ini"); + + TRACE("Loading config %s...\n", alstr_get_cstr(filepath)); + f = al_fopen(alstr_get_cstr(filepath), "rt"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + alstr_reset(&filepath); + } + + GetProcBinary(&ppath, nullptr); + if(!alstr_empty(ppath)) + { + alstr_append_cstr(&ppath, "\\alsoft.ini"); + TRACE("Loading config %s...\n", alstr_get_cstr(ppath)); + f = al_fopen(alstr_get_cstr(ppath), "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + } + + if((str=_wgetenv(L"ALSOFT_CONF")) != nullptr && *str) + { + al_string filepath = AL_STRING_INIT_STATIC(); + alstr_copy_wcstr(&filepath, str); + + TRACE("Loading config %s...\n", alstr_get_cstr(filepath)); + f = al_fopen(alstr_get_cstr(filepath), "rt"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + alstr_reset(&filepath); + } + + alstr_reset(&ppath); +} +#else +void ReadALConfig(void) +{ + al_string confpaths = AL_STRING_INIT_STATIC(); + al_string fname = AL_STRING_INIT_STATIC(); + const char *str; + FILE *f; + + str = "/etc/openal/alsoft.conf"; + + TRACE("Loading config %s...\n", str); + f = al_fopen(str, "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + + if(!(str=getenv("XDG_CONFIG_DIRS")) || str[0] == 0) + str = "/etc/xdg"; + alstr_copy_cstr(&confpaths, str); + /* Go through the list in reverse, since "the order of base directories + * denotes their importance; the first directory listed is the most + * important". Ergo, we need to load the settings from the later dirs + * first so that the settings in the earlier dirs override them. + */ + while(!alstr_empty(confpaths)) + { + char *next = strrchr(alstr_get_cstr(confpaths), ':'); + if(next) + { + size_t len = next - alstr_get_cstr(confpaths); + alstr_copy_cstr(&fname, next+1); + VECTOR_RESIZE(confpaths, len, len+1); + VECTOR_ELEM(confpaths, len) = 0; + } + else + { + alstr_reset(&fname); + fname = confpaths; + AL_STRING_INIT(confpaths); + } + + if(alstr_empty(fname) || VECTOR_FRONT(fname) != '/') + WARN("Ignoring XDG config dir: %s\n", alstr_get_cstr(fname)); + else + { + if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/alsoft.conf"); + else alstr_append_cstr(&fname, "alsoft.conf"); + + TRACE("Loading config %s...\n", alstr_get_cstr(fname)); + f = al_fopen(alstr_get_cstr(fname), "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + } + alstr_clear(&fname); + } + +#ifdef __APPLE__ + CFBundleRef mainBundle = CFBundleGetMainBundle(); + if(mainBundle) + { + unsigned char fileName[PATH_MAX]; + CFURLRef configURL; + + if((configURL=CFBundleCopyResourceURL(mainBundle, CFSTR(".alsoftrc"), CFSTR(""), nullptr)) && + CFURLGetFileSystemRepresentation(configURL, true, fileName, sizeof(fileName))) + { + f = al_fopen((const char*)fileName, "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + } + } +#endif + + if((str=getenv("HOME")) != nullptr && *str) + { + alstr_copy_cstr(&fname, str); + if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/.alsoftrc"); + else alstr_append_cstr(&fname, ".alsoftrc"); + + TRACE("Loading config %s...\n", alstr_get_cstr(fname)); + f = al_fopen(alstr_get_cstr(fname), "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + } + + if((str=getenv("XDG_CONFIG_HOME")) != nullptr && str[0] != 0) + { + alstr_copy_cstr(&fname, str); + if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/alsoft.conf"); + else alstr_append_cstr(&fname, "alsoft.conf"); + } + else + { + alstr_clear(&fname); + if((str=getenv("HOME")) != nullptr && str[0] != 0) + { + alstr_copy_cstr(&fname, str); + if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/.config/alsoft.conf"); + else alstr_append_cstr(&fname, ".config/alsoft.conf"); + } + } + if(!alstr_empty(fname)) + { + TRACE("Loading config %s...\n", alstr_get_cstr(fname)); + f = al_fopen(alstr_get_cstr(fname), "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + } + + alstr_clear(&fname); + GetProcBinary(&fname, nullptr); + if(!alstr_empty(fname)) + { + if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/alsoft.conf"); + else alstr_append_cstr(&fname, "alsoft.conf"); + + TRACE("Loading config %s...\n", alstr_get_cstr(fname)); + f = al_fopen(alstr_get_cstr(fname), "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + } + + if((str=getenv("ALSOFT_CONF")) != nullptr && *str) + { + TRACE("Loading config %s...\n", str); + f = al_fopen(str, "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + } + + alstr_reset(&fname); + alstr_reset(&confpaths); +} +#endif + +void FreeALConfig(void) +{ + unsigned int i; + + for(i = 0;i < cfgBlock.entryCount;i++) + { + free(cfgBlock.entries[i].key); + free(cfgBlock.entries[i].value); + } + free(cfgBlock.entries); +} + +const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def) +{ + unsigned int i; + char key[256]; + + if(!keyName) + return def; + + if(blockName && strcasecmp(blockName, "general") != 0) + { + if(devName) + snprintf(key, sizeof(key), "%s/%s/%s", blockName, devName, keyName); + else + snprintf(key, sizeof(key), "%s/%s", blockName, keyName); + } + else + { + if(devName) + snprintf(key, sizeof(key), "%s/%s", devName, keyName); + else + { + strncpy(key, keyName, sizeof(key)-1); + key[sizeof(key)-1] = 0; + } + } + + for(i = 0;i < cfgBlock.entryCount;i++) + { + if(strcmp(cfgBlock.entries[i].key, key) == 0) + { + TRACE("Found %s = \"%s\"\n", key, cfgBlock.entries[i].value); + if(cfgBlock.entries[i].value[0]) + return cfgBlock.entries[i].value; + return def; + } + } + + if(!devName) + { + TRACE("Key %s not found\n", key); + return def; + } + return GetConfigValue(nullptr, blockName, keyName, def); +} + +int ConfigValueExists(const char *devName, const char *blockName, const char *keyName) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + return val[0] != 0; +} + +int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + if(!val[0]) return 0; + + *ret = val; + return 1; +} + +int ConfigValueInt(const char *devName, const char *blockName, const char *keyName, int *ret) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + if(!val[0]) return 0; + + *ret = strtol(val, nullptr, 0); + return 1; +} + +int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + if(!val[0]) return 0; + + *ret = strtoul(val, nullptr, 0); + return 1; +} + +int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + if(!val[0]) return 0; + +#ifdef HAVE_STRTOF + *ret = strtof(val, nullptr); +#else + *ret = (float)strtod(val, nullptr); +#endif + return 1; +} + +int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + if(!val[0]) return 0; + + *ret = (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || + strcasecmp(val, "on") == 0 || atoi(val) != 0); + return 1; +} + +int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + + if(!val[0]) return def != 0; + return (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || + strcasecmp(val, "on") == 0 || atoi(val) != 0); +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 920e3d81..6079c25b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -841,7 +841,7 @@ SET(OPENAL_OBJS SET(ALC_OBJS Alc/ALc.c Alc/ALu.c - Alc/alconfig.c + Alc/alconfig.cpp Alc/alconfig.h Alc/bs2b.c Alc/converter.c -- cgit v1.2.3 From 58eb0e754d19237ca66d705834081a236e307484 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 10 Nov 2018 03:42:18 -0800 Subject: Load config files using C++ Specifically, avoid al_fopen --- Alc/alconfig.cpp | 491 ++++++++++++++++++++----------------------------------- 1 file changed, 178 insertions(+), 313 deletions(-) diff --git a/Alc/alconfig.cpp b/Alc/alconfig.cpp index f617a669..29593205 100644 --- a/Alc/alconfig.cpp +++ b/Alc/alconfig.cpp @@ -28,10 +28,9 @@ #include "config.h" -#include -#include -#include -#include +#include +#include +#include #ifdef _WIN32_IE #include #include @@ -40,93 +39,61 @@ #include #endif +#include +#include +#include + #include "alMain.h" #include "alconfig.h" #include "compat.h" #include "bool.h" -typedef struct ConfigEntry { - char *key; - char *value; -} ConfigEntry; +namespace { -typedef struct ConfigBlock { - ConfigEntry *entries; - unsigned int entryCount; -} ConfigBlock; -static ConfigBlock cfgBlock; +struct ConfigEntry { + std::string key; + std::string value; + template + ConfigEntry(T0&& key_, T1&& val_) + : key{std::forward(key_)}, value{std::forward(val_)} + { } +}; +std::vector ConfOpts; -static char *lstrip(char *line) -{ - while(isspace(line[0])) - line++; - return line; -} -static char *rstrip(char *line) +std::string &lstrip(std::string &line) { - size_t len = strlen(line); - while(len > 0 && isspace(line[len-1])) - len--; - line[len] = 0; + size_t pos{0}; + while(pos < line.length() && std::isspace(line[pos])) + ++pos; + line.erase(0, pos); return line; } -static int readline(FILE *f, char **output, size_t *maxlen) +bool readline(std::istream &f, std::string &output) { - 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 = nullptr; - 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; - } + while(f.good() && f.peek() == '\n') + f.ignore(); - *output = static_cast(temp); - *maxlen = newmax; - } - (*output)[len++] = c; - (*output)[len] = '\0'; - } while((c=fgetc(f)) != EOF && c != '\r' && c != '\n'); - - return 1; + return std::getline(f, output) && !output.empty(); } - -static char *expdup(const char *str) +std:: string expdup(const char *str) { - char *output = nullptr; - size_t maxlen = 0; - size_t len = 0; + std::string output; while(*str != '\0') { const char *addstr; size_t addstrlen; - size_t i; if(str[0] != '$') { - const char *next = strchr(str, '$'); + const char *next = std::strchr(str, '$'); addstr = str; - addstrlen = next ? (size_t)(next-str) : strlen(str); + addstrlen = next ? (size_t)(next-str) : std::strlen(str); str += addstrlen; } @@ -135,86 +102,60 @@ static char *expdup(const char *str) str++; if(*str == '$') { - const char *next = strchr(str+1, '$'); + const char *next = std::strchr(str+1, '$'); addstr = str; - addstrlen = next ? (size_t)(next-str) : strlen(str); + addstrlen = next ? (size_t)(next-str) : std::strlen(str); str += addstrlen; } else { - bool hasbraces; - char envname[1024]; - size_t k = 0; - - hasbraces = (*str == '{'); + bool hasbraces{(*str == '{')}; if(hasbraces) str++; - while((isalnum(*str) || *str == '_') && k < sizeof(envname)-1) - envname[k++] = *(str++); - envname[k++] = '\0'; + std::string envname; + while((std::isalnum(*str) || *str == '_')) + envname += *(str++); if(hasbraces && *str != '}') continue; if(hasbraces) str++; - if((addstr=getenv(envname)) == nullptr) + if((addstr=std::getenv(envname.c_str())) == nullptr) continue; - addstrlen = strlen(addstr); + addstrlen = std::strlen(addstr); } } if(addstrlen == 0) continue; - if(addstrlen >= maxlen-len) - { - void *temp = nullptr; - 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 = static_cast(temp); - maxlen = newmax; - } - - for(i = 0;i < addstrlen;i++) - output[len++] = addstr[i]; - output[len] = '\0'; + output.append(addstr, addstrlen); } - return output ? output : static_cast(calloc(1, 1)); + return output; } - -static void LoadConfigFromFile(FILE *f) +void LoadConfigFromFile(std::istream &f) { - char curSection[128] = ""; - char *buffer = nullptr; - size_t maxlen = 0; - ConfigEntry *ent; + std::string curSection; + std::string buffer; - while(readline(f, &buffer, &maxlen)) + while(readline(f, buffer)) { - char *line, *comment; - char key[256] = ""; - char value[256] = ""; + while(!buffer.empty() && std::isspace(buffer.back())) + buffer.pop_back(); + if(lstrip(buffer).empty()) + continue; - line = rstrip(lstrip(buffer)); - if(!line[0]) continue; + buffer.push_back(0); + char *line{&buffer[0]}; if(line[0] == '[') { char *section = line+1; char *endsection; - endsection = strchr(section, ']'); + endsection = std::strchr(section, ']'); if(!endsection || section == endsection) { ERR("config parse error: bad line \"%s\"\n", line); @@ -223,7 +164,7 @@ static void LoadConfigFromFile(FILE *f) if(endsection[1] != 0) { char *end = endsection+1; - while(isspace(*end)) + while(std::isspace(*end)) ++end; if(*end != 0 && *end != '#') { @@ -233,24 +174,18 @@ static void LoadConfigFromFile(FILE *f) } *endsection = 0; - if(strcasecmp(section, "general") == 0) - curSection[0] = 0; - else + curSection.clear(); + if(strcasecmp(section, "general") != 0) { - size_t len, p = 0; do { - char *nextp = strchr(section, '%'); + char *nextp = std::strchr(section, '%'); if(!nextp) { - strncpy(curSection+p, section, sizeof(curSection)-1-p); + curSection += section; break; } - len = nextp - section; - if(len > sizeof(curSection)-1-p) - len = sizeof(curSection)-1-p; - strncpy(curSection+p, section, len); - p += len; + curSection.append(section, nextp); section = nextp; if(((section[1] >= '0' && section[1] <= '9') || @@ -273,42 +208,38 @@ static void LoadConfigFromFile(FILE *f) b |= (section[2]-'a'+0xa); else if(section[2] >= 'A' && section[2] <= 'F') b |= (section[2]-'A'+0x0a); - if(p < sizeof(curSection)-1) - curSection[p++] = b; + curSection += static_cast(b); section += 3; } else if(section[1] == '%') { - if(p < sizeof(curSection)-1) - curSection[p++] = '%'; + curSection += '%'; section += 2; } else { - if(p < sizeof(curSection)-1) - curSection[p++] = '%'; + curSection += '%'; section += 1; } - if(p < sizeof(curSection)-1) - curSection[p] = 0; - } while(p < sizeof(curSection)-1 && *section != 0); - curSection[sizeof(curSection)-1] = 0; + } while(*section != 0); } continue; } - comment = strchr(line, '#'); + char *comment{std::strchr(line, '#')}; if(comment) *(comment++) = 0; if(!line[0]) continue; - if(sscanf(line, "%255[^=] = \"%255[^\"]\"", key, value) == 2 || - sscanf(line, "%255[^=] = '%255[^\']'", key, value) == 2 || - sscanf(line, "%255[^=] = %255[^\n]", key, value) == 2) + char key[256]{}; + char value[256]{}; + if(std::sscanf(line, "%255[^=] = \"%255[^\"]\"", key, value) == 2 || + std::sscanf(line, "%255[^=] = '%255[^\']'", key, value) == 2 || + std::sscanf(line, "%255[^=] = %255[^\n]", key, value) == 2) { /* sscanf doesn't handle '' or "" as empty values, so clip it * manually. */ - if(strcmp(value, "\"\"") == 0 || strcmp(value, "''") == 0) + if(std::strcmp(value, "\"\"") == 0 || std::strcmp(value, "''") == 0) value[0] = 0; } else if(sscanf(line, "%255[^=] %255[=]", key, value) == 2) @@ -321,102 +252,73 @@ static void LoadConfigFromFile(FILE *f) ERR("config parse error: malformed option line: \"%s\"\n\n", line); continue; } - rstrip(key); - if(curSection[0] != 0) + std::string fullKey; + if(!curSection.empty()) { - size_t len = strlen(curSection); - memmove(&key[len+1], key, sizeof(key)-1-len); - key[len] = '/'; - memcpy(key, curSection, len); + fullKey += curSection; + fullKey += '/'; } + fullKey += key; + while(!fullKey.empty() && std::isspace(fullKey.back())) + fullKey.pop_back(); /* Check if we already have this option set */ - ent = cfgBlock.entries; - while((unsigned int)(ent-cfgBlock.entries) < cfgBlock.entryCount) - { - if(strcasecmp(ent->key, key) == 0) - break; - ent++; - } - - if((unsigned int)(ent-cfgBlock.entries) >= cfgBlock.entryCount) + auto ent = std::find_if(ConfOpts.begin(), ConfOpts.end(), + [&fullKey](const ConfigEntry &entry) -> bool + { return entry.key == fullKey; } + ); + if(ent != ConfOpts.end()) + ent->value = expdup(value); + else { - /* Allocate a new option entry */ - ent = static_cast(realloc(cfgBlock.entries, - (cfgBlock.entryCount+1)*sizeof(ConfigEntry))); - if(!ent) - { - ERR("config parse error: error reallocating config entries\n"); - continue; - } - cfgBlock.entries = ent; - ent = cfgBlock.entries + cfgBlock.entryCount; - cfgBlock.entryCount++; - - ent->key = strdup(key); - ent->value = nullptr; + ConfOpts.emplace_back(std::move(fullKey), expdup(value)); + ent = ConfOpts.end()-1; } - free(ent->value); - ent->value = expdup(value); - - TRACE("found '%s' = '%s'\n", ent->key, ent->value); + TRACE("found '%s' = '%s'\n", ent->key.c_str(), ent->value.c_str()); } - - free(buffer); + ConfOpts.shrink_to_fit(); } +} // namespace + + #ifdef _WIN32 void ReadALConfig(void) { - al_string ppath = AL_STRING_INIT_STATIC(); WCHAR buffer[MAX_PATH]; - const WCHAR *str; - FILE *f; - if(SHGetSpecialFolderPathW(nullptr, buffer, CSIDL_APPDATA, FALSE) != FALSE) { - al_string filepath = AL_STRING_INIT_STATIC(); - alstr_copy_wcstr(&filepath, buffer); - alstr_append_cstr(&filepath, "\\alsoft.ini"); + std::string filepath{wstr_to_utf8(buffer)}; + filepath += "\\alsoft.ini"; - TRACE("Loading config %s...\n", alstr_get_cstr(filepath)); - f = al_fopen(alstr_get_cstr(filepath), "rt"); - if(f) - { + TRACE("Loading config %s...\n", filepath.c_str()); + al::ifstream f{filepath}; + if(f.is_open()) LoadConfigFromFile(f); - fclose(f); - } - alstr_reset(&filepath); } + al_string ppath = AL_STRING_INIT_STATIC(); GetProcBinary(&ppath, nullptr); if(!alstr_empty(ppath)) { alstr_append_cstr(&ppath, "\\alsoft.ini"); TRACE("Loading config %s...\n", alstr_get_cstr(ppath)); - f = al_fopen(alstr_get_cstr(ppath), "r"); - if(f) - { + al::ifstream f{alstr_get_cstr(ppath)}; + if(f.is_open()) LoadConfigFromFile(f); - fclose(f); - } } - if((str=_wgetenv(L"ALSOFT_CONF")) != nullptr && *str) + const WCHAR *str{_wgetenv(L"ALSOFT_CONF")}; + if(str != nullptr && *str) { - al_string filepath = AL_STRING_INIT_STATIC(); - alstr_copy_wcstr(&filepath, str); + std::string filepath{wstr_to_utf8(str)}; - TRACE("Loading config %s...\n", alstr_get_cstr(filepath)); - f = al_fopen(alstr_get_cstr(filepath), "rt"); - if(f) - { + TRACE("Loading config %s...\n", filepath.c_str()); + al::ifstream f{filepath}; + if(f.is_open()) LoadConfigFromFile(f); - fclose(f); - } - alstr_reset(&filepath); } alstr_reset(&ppath); @@ -424,62 +326,50 @@ void ReadALConfig(void) #else void ReadALConfig(void) { - al_string confpaths = AL_STRING_INIT_STATIC(); - al_string fname = AL_STRING_INIT_STATIC(); - const char *str; - FILE *f; - - str = "/etc/openal/alsoft.conf"; + const char *str{"/etc/openal/alsoft.conf"}; TRACE("Loading config %s...\n", str); - f = al_fopen(str, "r"); - if(f) - { + al::ifstream f{str}; + if(f.is_open()) LoadConfigFromFile(f); - fclose(f); - } + f.close(); if(!(str=getenv("XDG_CONFIG_DIRS")) || str[0] == 0) str = "/etc/xdg"; - alstr_copy_cstr(&confpaths, str); + std::string confpaths = str; /* Go through the list in reverse, since "the order of base directories * denotes their importance; the first directory listed is the most * important". Ergo, we need to load the settings from the later dirs * first so that the settings in the earlier dirs override them. */ - while(!alstr_empty(confpaths)) + std::string fname; + while(!confpaths.empty()) { - char *next = strrchr(alstr_get_cstr(confpaths), ':'); - if(next) + auto next = confpaths.find_last_of(':'); + if(next < confpaths.length()) { - size_t len = next - alstr_get_cstr(confpaths); - alstr_copy_cstr(&fname, next+1); - VECTOR_RESIZE(confpaths, len, len+1); - VECTOR_ELEM(confpaths, len) = 0; + fname = confpaths.substr(next+1); + confpaths.erase(next); } else { - alstr_reset(&fname); fname = confpaths; - AL_STRING_INIT(confpaths); + confpaths.clear(); } - if(alstr_empty(fname) || VECTOR_FRONT(fname) != '/') - WARN("Ignoring XDG config dir: %s\n", alstr_get_cstr(fname)); + if(fname.empty() || fname.front() != '/') + WARN("Ignoring XDG config dir: %s\n", fname.c_str()); else { - if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/alsoft.conf"); - else alstr_append_cstr(&fname, "alsoft.conf"); + if(fname.back() != '/') fname += "/alsoft.conf"; + else fname += "alsoft.conf"; - TRACE("Loading config %s...\n", alstr_get_cstr(fname)); - f = al_fopen(alstr_get_cstr(fname), "r"); - if(f) - { + TRACE("Loading config %s...\n", fname.c_str()); + al::ifstream f{fname}; + if(f.is_open()) LoadConfigFromFile(f); - fclose(f); - } } - alstr_clear(&fname); + fname.clear(); } #ifdef __APPLE__ @@ -492,142 +382,121 @@ void ReadALConfig(void) if((configURL=CFBundleCopyResourceURL(mainBundle, CFSTR(".alsoftrc"), CFSTR(""), nullptr)) && CFURLGetFileSystemRepresentation(configURL, true, fileName, sizeof(fileName))) { - f = al_fopen((const char*)fileName, "r"); - if(f) - { + al::ifstream f{reinterpret_cast(fileName)}; + if(f.is_open()) LoadConfigFromFile(f); - fclose(f); - } } } #endif if((str=getenv("HOME")) != nullptr && *str) { - alstr_copy_cstr(&fname, str); - if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/.alsoftrc"); - else alstr_append_cstr(&fname, ".alsoftrc"); + fname = str; + if(fname.back() != '/') fname += "/.alsoftrc"; + else fname += ".alsoftrc"; - TRACE("Loading config %s...\n", alstr_get_cstr(fname)); - f = al_fopen(alstr_get_cstr(fname), "r"); - if(f) - { + TRACE("Loading config %s...\n", fname.c_str()); + al::ifstream f{fname}; + if(f.is_open()) LoadConfigFromFile(f); - fclose(f); - } } if((str=getenv("XDG_CONFIG_HOME")) != nullptr && str[0] != 0) { - alstr_copy_cstr(&fname, str); - if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/alsoft.conf"); - else alstr_append_cstr(&fname, "alsoft.conf"); + fname = str; + if(fname.back() != '/') fname += "/alsoft.conf"; + else fname += "alsoft.conf"; } else { - alstr_clear(&fname); + fname.clear(); if((str=getenv("HOME")) != nullptr && str[0] != 0) { - alstr_copy_cstr(&fname, str); - if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/.config/alsoft.conf"); - else alstr_append_cstr(&fname, ".config/alsoft.conf"); + fname = str; + if(fname.back() != '/') fname += "/.config/alsoft.conf"; + else fname += ".config/alsoft.conf"; } } - if(!alstr_empty(fname)) + if(!fname.empty()) { - TRACE("Loading config %s...\n", alstr_get_cstr(fname)); - f = al_fopen(alstr_get_cstr(fname), "r"); - if(f) - { + TRACE("Loading config %s...\n", fname.c_str()); + al::ifstream f{fname}; + if(f.is_open()) LoadConfigFromFile(f); - fclose(f); - } } - alstr_clear(&fname); - GetProcBinary(&fname, nullptr); - if(!alstr_empty(fname)) + al_string ppath = AL_STRING_INIT_STATIC(); + GetProcBinary(&ppath, nullptr); + if(!alstr_empty(ppath)) { - if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/alsoft.conf"); - else alstr_append_cstr(&fname, "alsoft.conf"); + if(VECTOR_BACK(ppath) != '/') alstr_append_cstr(&ppath, "/alsoft.conf"); + else alstr_append_cstr(&ppath, "alsoft.conf"); - TRACE("Loading config %s...\n", alstr_get_cstr(fname)); - f = al_fopen(alstr_get_cstr(fname), "r"); - if(f) - { + TRACE("Loading config %s...\n", alstr_get_cstr(ppath)); + al::ifstream f{alstr_get_cstr(ppath)}; + if(f.is_open()) LoadConfigFromFile(f); - fclose(f); - } } if((str=getenv("ALSOFT_CONF")) != nullptr && *str) { TRACE("Loading config %s...\n", str); - f = al_fopen(str, "r"); - if(f) - { + al::ifstream f{str}; + if(f.is_open()) LoadConfigFromFile(f); - fclose(f); - } } - alstr_reset(&fname); - alstr_reset(&confpaths); + alstr_reset(&ppath); } #endif void FreeALConfig(void) { - unsigned int i; - - for(i = 0;i < cfgBlock.entryCount;i++) - { - free(cfgBlock.entries[i].key); - free(cfgBlock.entries[i].value); - } - free(cfgBlock.entries); + ConfOpts.clear(); } const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def) { - unsigned int i; - char key[256]; - if(!keyName) return def; + std::string key; if(blockName && strcasecmp(blockName, "general") != 0) { + key = blockName; if(devName) - snprintf(key, sizeof(key), "%s/%s/%s", blockName, devName, keyName); - else - snprintf(key, sizeof(key), "%s/%s", blockName, keyName); + { + key += '/'; + key += devName; + } + key += '/'; + key += keyName; } else { if(devName) - snprintf(key, sizeof(key), "%s/%s", devName, keyName); - else { - strncpy(key, keyName, sizeof(key)-1); - key[sizeof(key)-1] = 0; + key = devName; + key += '/'; } + key += keyName; } - for(i = 0;i < cfgBlock.entryCount;i++) + auto iter = std::find_if(ConfOpts.cbegin(), ConfOpts.cend(), + [&key](const ConfigEntry &entry) -> bool + { return entry.key == key; } + ); + if(iter != ConfOpts.cend()) { - if(strcmp(cfgBlock.entries[i].key, key) == 0) - { - TRACE("Found %s = \"%s\"\n", key, cfgBlock.entries[i].value); - if(cfgBlock.entries[i].value[0]) - return cfgBlock.entries[i].value; - return def; - } + TRACE("Found %s = \"%s\"\n", key.c_str(), iter->value.c_str()); + if(!iter->value.empty()) + return iter->value.c_str(); + return def; } if(!devName) { - TRACE("Key %s not found\n", key); + TRACE("Key %s not found\n", key.c_str()); return def; } return GetConfigValue(nullptr, blockName, keyName, def); @@ -653,7 +522,7 @@ int ConfigValueInt(const char *devName, const char *blockName, const char *keyNa const char *val = GetConfigValue(devName, blockName, keyName, ""); if(!val[0]) return 0; - *ret = strtol(val, nullptr, 0); + *ret = std::strtol(val, nullptr, 0); return 1; } @@ -662,7 +531,7 @@ int ConfigValueUInt(const char *devName, const char *blockName, const char *keyN const char *val = GetConfigValue(devName, blockName, keyName, ""); if(!val[0]) return 0; - *ret = strtoul(val, nullptr, 0); + *ret = std::strtoul(val, nullptr, 0); return 1; } @@ -671,11 +540,7 @@ int ConfigValueFloat(const char *devName, const char *blockName, const char *key const char *val = GetConfigValue(devName, blockName, keyName, ""); if(!val[0]) return 0; -#ifdef HAVE_STRTOF - *ret = strtof(val, nullptr); -#else - *ret = (float)strtod(val, nullptr); -#endif + *ret = std::strtof(val, nullptr); return 1; } -- cgit v1.2.3 From dc31969b04395db71d8162587f55cf81e7e69aac Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 10 Nov 2018 04:27:10 -0800 Subject: Get rid of the last few al_fopen calls --- Alc/ALc.c | 17 ++++++++++++++++- Alc/backends/wave.cpp | 16 ++++++++++------ Alc/compat.h | 5 ----- Alc/helpers.c | 20 -------------------- 4 files changed, 26 insertions(+), 32 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 7d28b976..ae55e9b4 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -918,7 +918,22 @@ static void alc_initconfig(void) str = getenv("ALSOFT_LOGFILE"); if(str && str[0]) { - FILE *logfile = al_fopen(str, "wt"); +#ifdef _WIN32 + FILE *logfile = NULL; + int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + if(len > 0) + { + WCHAR *wname = calloc(sizeof(WCHAR), len); + if(wname) + { + MultiByteToWideChar(CP_UTF8, 0, str, -1, wname, len); + logfile = _wfopen(wname, L"wt"); + free(wname); + } + } +#else + FILE *logfile = fopen(str, "wt"); +#endif if(logfile) LogFile = logfile; else ERR("Failed to open log file '%s'\n", str); } diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index 4f3947e5..ec67342a 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -223,10 +223,7 @@ static int ALCwaveBackend_mixerProc(void *ptr) static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name) { - ALCdevice *device; - const char *fname; - - fname = GetConfigValue(nullptr, "wave", "file", ""); + const char *fname{GetConfigValue(nullptr, "wave", "file", "")}; if(!fname[0]) return ALC_INVALID_VALUE; if(!name) @@ -234,14 +231,21 @@ static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name) else if(strcmp(name, waveDevice) != 0) return ALC_INVALID_VALUE; - self->mFile = al_fopen(fname, "wb"); +#ifdef _WIN32 + { + std::wstring wname = utf8_to_wstr(fname); + self->mFile = _wfopen(wname.c_str(), L"wb"); + } +#else + self->mFile = fopen(fname, "wb"); +#endif if(!self->mFile) { ERR("Could not open file '%s': %s\n", fname, strerror(errno)); return ALC_INVALID_VALUE; } - device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; diff --git a/Alc/compat.h b/Alc/compat.h index 77845d73..15eca1d4 100644 --- a/Alc/compat.h +++ b/Alc/compat.h @@ -12,9 +12,6 @@ extern "C" { #define WIN32_LEAN_AND_MEAN #include -/* 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 #ifdef __cplusplus @@ -218,8 +215,6 @@ extern "C" { #else -#define al_fopen fopen - #if defined(HAVE_DLFCN_H) #define HAVE_DYNLOAD 1 #endif diff --git a/Alc/helpers.c b/Alc/helpers.c index 000b9576..064e03f5 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -429,26 +429,6 @@ void *GetSymbol(void *handle, const char *name) return ret; } -FILE *al_fopen(const char *fname, const char *mode) -{ - WCHAR *wname=NULL, *wmode=NULL; - FILE *file = NULL; - - 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); - - free(wname); - free(wmode); - - return file; -} - void al_print(const char *type, const char *func, const char *fmt, ...) { -- cgit v1.2.3 From 3939878cc0ac9e9043ee1cb30113136c2a8958e1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 10 Nov 2018 19:31:23 -0800 Subject: Use standard timing methods for the null and wave backends --- Alc/backends/null.cpp | 57 ++++++++++++++++++++++++----------------------- Alc/backends/wave.cpp | 61 ++++++++++++++++++++++++++------------------------- 2 files changed, 61 insertions(+), 57 deletions(-) diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 2e1c6ac9..4c1d3956 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -25,6 +25,9 @@ #include #endif +#include +#include + #include "alMain.h" #include "alu.h" #include "threads.h" @@ -35,6 +38,10 @@ namespace { +using std::chrono::seconds; +using std::chrono::milliseconds; +using std::chrono::nanoseconds; + constexpr ALCchar nullDevice[] = "No Output"; } // namespace @@ -82,48 +89,44 @@ static int ALCnullBackend_mixerProc(void *ptr) { ALCnullBackend *self = (ALCnullBackend*)ptr; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - struct timespec now, start; - ALuint64 avail, done; - const long restTime = (long)((ALuint64)device->UpdateSize * 1000000000 / - device->Frequency / 2); + const milliseconds restTime{device->UpdateSize*1000/device->Frequency / 2}; SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); - done = 0; - if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC) - { - ERR("Failed to get starting time\n"); - return 1; - } + ALint64 done{0}; + auto start = std::chrono::steady_clock::now(); while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { - if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC) - { - ERR("Failed to get current time\n"); - return 1; - } + auto now = std::chrono::steady_clock::now(); - avail = (now.tv_sec - start.tv_sec) * device->Frequency; - avail += (ALint64)(now.tv_nsec - start.tv_nsec) * device->Frequency / 1000000000; - if(avail < done) + /* This converts from nanoseconds to nanosamples, then to samples. */ + ALint64 avail{std::chrono::duration_cast((now-start) * device->Frequency).count()}; + if(avail-done < device->UpdateSize) { - /* 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; + std::this_thread::sleep_for(restTime); + continue; } - - if(avail-done < device->UpdateSize) - al_nssleep(restTime); - else while(avail-done >= device->UpdateSize) + while(avail-done >= device->UpdateSize) { ALCnullBackend_lock(self); - aluMixData(device, NULL, device->UpdateSize); + aluMixData(device, nullptr, device->UpdateSize); ALCnullBackend_unlock(self); done += device->UpdateSize; } + + /* For every completed second, increment the start time and reduce the + * samples done. This prevents the difference between the start time + * and current time from growing too large, while maintaining the + * correct number of samples to render. + */ + if(done >= device->Frequency) + { + seconds s{done/device->Frequency}; + start += s; + done -= device->Frequency*s.count(); + } } return 0; diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index ec67342a..d5611783 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -25,6 +25,9 @@ #include #include +#include +#include + #include "alMain.h" #include "alu.h" #include "alconfig.h" @@ -36,6 +39,10 @@ namespace { +using std::chrono::seconds; +using std::chrono::milliseconds; +using std::chrono::nanoseconds; + constexpr ALCchar waveDevice[] = "Wave File Writer"; constexpr ALubyte SUBTYPE_PCM[]{ @@ -131,45 +138,27 @@ static int ALCwaveBackend_mixerProc(void *ptr) { ALCwaveBackend *self = (ALCwaveBackend*)ptr; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - struct timespec now, start; - ALint64 avail, done; - ALuint frameSize; - size_t fs; - const long restTime = (long)((ALuint64)device->UpdateSize * 1000000000 / - device->Frequency / 2); + const milliseconds restTime{device->UpdateSize*1000/device->Frequency / 2}; althrd_setname(althrd_current(), MIXER_THREAD_NAME); - frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + ALsizei frameSize{FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder)}; - done = 0; - if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC) - { - ERR("Failed to get starting time\n"); - return 1; - } + ALint64 done{0}; + auto start = std::chrono::steady_clock::now(); while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { - if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC) - { - ERR("Failed to get current time\n"); - return 1; - } + auto now = std::chrono::steady_clock::now(); - avail = (now.tv_sec - start.tv_sec) * device->Frequency; - avail += (ALint64)(now.tv_nsec - start.tv_nsec) * device->Frequency / 1000000000; - if(avail < done) + /* This converts from nanoseconds to nanosamples, then to samples. */ + ALint64 avail{std::chrono::duration_cast((now-start) * device->Frequency).count()}; + if(avail-done < device->UpdateSize) { - /* 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; + std::this_thread::sleep_for(restTime); + continue; } - - if(avail-done < device->UpdateSize) - al_nssleep(restTime); - else while(avail-done >= device->UpdateSize) + while(avail-done >= device->UpdateSize) { ALCwaveBackend_lock(self); aluMixData(device, self->mBuffer, device->UpdateSize); @@ -204,7 +193,7 @@ static int ALCwaveBackend_mixerProc(void *ptr) } } - fs = fwrite(self->mBuffer, frameSize, device->UpdateSize, self->mFile); + size_t fs{fwrite(self->mBuffer, frameSize, device->UpdateSize, self->mFile)}; (void)fs; if(ferror(self->mFile)) { @@ -215,6 +204,18 @@ static int ALCwaveBackend_mixerProc(void *ptr) break; } } + + /* For every completed second, increment the start time and reduce the + * samples done. This prevents the difference between the start time + * and current time from growing too large, while maintaining the + * correct number of samples to render. + */ + if(done >= device->Frequency) + { + seconds s{done/device->Frequency}; + start += s; + done -= device->Frequency*s.count(); + } } return 0; -- cgit v1.2.3 From 2f42f74418f079e2ef8f081a7faf915c5eb131b4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 10 Nov 2018 19:38:52 -0800 Subject: Ensure ambdec parsing stops at unexpected EOF --- Alc/ambdec.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Alc/ambdec.cpp b/Alc/ambdec.cpp index 088d4a85..b3978551 100644 --- a/Alc/ambdec.cpp +++ b/Alc/ambdec.cpp @@ -21,8 +21,7 @@ int readline(std::istream &f, std::string &output) while(f.good() && f.peek() == '\n') f.ignore(); - std::getline(f, output); - return !output.empty(); + return std::getline(f, output) && !output.empty(); } bool read_clipped_line(std::istream &f, std::string &buffer) -- cgit v1.2.3 From f3ce7bc7dcf20275d93974755c42486d812d771f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 10 Nov 2018 21:09:54 -0800 Subject: Move altimespec_get and al_nssleep to examples' common code --- CMakeLists.txt | 2 +- common/threads.c | 72 --------------------------------------------- common/threads.h | 26 ---------------- examples/common/alhelpers.c | 69 +++++++++++++++++++++++++++++++++++++++++++ examples/common/alhelpers.h | 11 +++++++ 5 files changed, 81 insertions(+), 99 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6079c25b..dc3bad12 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1675,7 +1675,7 @@ IF(ALSOFT_EXAMPLES) ADD_EXECUTABLE(alrecord examples/alrecord.c) TARGET_COMPILE_DEFINITIONS(alrecord PRIVATE ${CPP_DEFS}) TARGET_COMPILE_OPTIONS(alrecord PRIVATE ${C_FLAGS}) - TARGET_LINK_LIBRARIES(alrecord PRIVATE ${LINKER_FLAGS} common OpenAL) + TARGET_LINK_LIBRARIES(alrecord PRIVATE ${LINKER_FLAGS} ex-common common OpenAL) IF(ALSOFT_INSTALL) INSTALL(TARGETS alrecord diff --git a/common/threads.c b/common/threads.c index e8301297..de9fc452 100644 --- a/common/threads.c +++ b/common/threads.c @@ -174,21 +174,6 @@ int althrd_join(althrd_t thr, int *res) return althrd_success; } -int althrd_sleep(const struct timespec *ts, struct timespec* UNUSED(rem)) -{ - DWORD msec; - - if(ts->tv_sec < 0 || ts->tv_sec >= (0x7fffffff / 1000) || - ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000) - return -2; - - msec = (DWORD)(ts->tv_sec * 1000); - msec += (DWORD)((ts->tv_nsec+999999) / 1000000); - Sleep(msec); - - return 0; -} - int almtx_init(almtx_t *mtx, int type) { @@ -381,27 +366,6 @@ void altss_delete(altss_t tss_id) } -int altimespec_get(struct timespec *ts, int base) -{ - static_assert(sizeof(FILETIME) == sizeof(ULARGE_INTEGER), - "Size of FILETIME does not match ULARGE_INTEGER"); - if(base == AL_TIME_UTC) - { - union { - FILETIME ftime; - ULARGE_INTEGER ulint; - } systime; - GetSystemTimeAsFileTime(&systime.ftime); - /* FILETIME is in 100-nanosecond units, or 1/10th of a microsecond. */ - ts->tv_sec = systime.ulint.QuadPart/10000000; - ts->tv_nsec = (systime.ulint.QuadPart%10000000) * 100; - return base; - } - - return 0; -} - - void alcall_once(alonce_flag *once, void (*callback)(void)) { LONG ret; @@ -447,7 +411,6 @@ void althrd_thread_detach(void) #endif -extern inline int althrd_sleep(const struct timespec *ts, struct timespec *rem); extern inline void alcall_once(alonce_flag *once, void (*callback)(void)); extern inline void althrd_deinit(void); @@ -713,39 +676,4 @@ void altss_delete(altss_t tss_id) pthread_key_delete(tss_id); } - -int altimespec_get(struct timespec *ts, int base) -{ - if(base == AL_TIME_UTC) - { - int ret; -#if _POSIX_TIMERS > 0 - ret = clock_gettime(CLOCK_REALTIME, ts); - if(ret == 0) return base; -#else /* _POSIX_TIMERS > 0 */ - struct timeval tv; - ret = gettimeofday(&tv, NULL); - if(ret == 0) - { - ts->tv_sec = tv.tv_sec; - ts->tv_nsec = tv.tv_usec * 1000; - return base; - } -#endif - } - - return 0; -} - #endif - - -void al_nssleep(unsigned long nsec) -{ - struct timespec ts, rem; - ts.tv_sec = nsec / 1000000000ul; - ts.tv_nsec = nsec % 1000000000ul; - - while(althrd_sleep(&ts, &rem) == -1) - ts = rem; -} diff --git a/common/threads.h b/common/threads.h index 7fbe20cd..c2168cdf 100644 --- a/common/threads.h +++ b/common/threads.h @@ -34,21 +34,11 @@ typedef int (*althrd_start_t)(void*); typedef void (*altss_dtor_t)(void*); -#define AL_TIME_UTC 1 - - #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include -#ifndef HAVE_STRUCT_TIMESPEC -struct timespec { - time_t tv_sec; - long tv_nsec; -}; -#endif - typedef DWORD althrd_t; typedef CRITICAL_SECTION almtx_t; #if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 @@ -62,7 +52,6 @@ typedef LONG alonce_flag; #define AL_ONCE_FLAG_INIT 0 -int althrd_sleep(const struct timespec *ts, struct timespec *rem); void alcall_once(alonce_flag *once, void (*callback)(void)); void althrd_deinit(void); @@ -171,17 +160,6 @@ inline void althrd_yield(void) sched_yield(); } -inline int althrd_sleep(const struct timespec *ts, struct timespec *rem) -{ - int ret = nanosleep(ts, rem); - if(ret != 0) - { - ret = ((errno==EINTR) ? -1 : -2); - errno = 0; - } - return ret; -} - inline int almtx_lock(almtx_t *mtx) { @@ -257,10 +235,6 @@ int alsem_trywait(alsem_t *sem); int altss_create(altss_t *tss_id, altss_dtor_t callback); void altss_delete(altss_t tss_id); -int altimespec_get(struct timespec *ts, int base); - -void al_nssleep(unsigned long nsec); - #ifdef __cplusplus } // extern "C" diff --git a/examples/common/alhelpers.c b/examples/common/alhelpers.c index fab039e9..657c10d3 100644 --- a/examples/common/alhelpers.c +++ b/examples/common/alhelpers.c @@ -114,3 +114,72 @@ const char *FormatName(ALenum format) } return "Unknown Format"; } + + +#ifdef _WIN32 + +#define WIN32_LEAN_AND_MEAN +#include +#include + +int altimespec_get(struct timespec *ts, int base) +{ + if(base == AL_TIME_UTC) + { + union { + FILETIME ftime; + ULARGE_INTEGER ulint; + } systime; + GetSystemTimeAsFileTime(&systime.ftime); + /* FILETIME is in 100-nanosecond units, or 1/10th of a microsecond. */ + ts->tv_sec = systime.ulint.QuadPart/10000000; + ts->tv_nsec = (systime.ulint.QuadPart%10000000) * 100; + return base; + } + + return 0; +} + +void al_nssleep(unsigned long nsec) +{ + Sleep(nsec / 1000000); +} + +#else + +#include +#include + +int altimespec_get(struct timespec *ts, int base) +{ + if(base == AL_TIME_UTC) + { + int ret; +#if _POSIX_TIMERS > 0 + ret = clock_gettime(CLOCK_REALTIME, ts); + if(ret == 0) return base; +#else /* _POSIX_TIMERS > 0 */ + struct timeval tv; + ret = gettimeofday(&tv, NULL); + if(ret == 0) + { + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; + return base; + } +#endif + } + + return 0; +} + +void al_nssleep(unsigned long nsec) +{ + struct timespec ts, rem; + ts.tv_sec = nsec / 1000000000ul; + ts.tv_nsec = nsec % 1000000000ul; + while(nanosleep(&ts, &rem) == -1 && errno == EINTR) + ts = rem; +} + +#endif diff --git a/examples/common/alhelpers.h b/examples/common/alhelpers.h index 41a7ce58..e3e638ac 100644 --- a/examples/common/alhelpers.h +++ b/examples/common/alhelpers.h @@ -18,6 +18,17 @@ const char *FormatName(ALenum type); int InitAL(char ***argv, int *argc); void CloseAL(void); +/* Cross-platform timeget and sleep functions. */ +#ifndef HAVE_STRUCT_TIMESPEC +struct timespec { + time_t tv_sec; + long tv_nsec; +}; +#endif +#define AL_TIME_UTC 1 +int altimespec_get(struct timespec *ts, int base); +void al_nssleep(unsigned long nsec); + #ifdef __cplusplus } #endif /* __cplusplus */ -- cgit v1.2.3 From 5bc2918e16c0ec5b43837ed0a12bfa1f7187103a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 10 Nov 2018 22:53:03 -0800 Subject: Remove the unused condition variable APIs --- common/threads.c | 152 ------------------------------------------------------- common/threads.h | 12 ----- 2 files changed, 164 deletions(-) diff --git a/common/threads.c b/common/threads.c index de9fc452..16604267 100644 --- a/common/threads.c +++ b/common/threads.c @@ -192,125 +192,6 @@ void almtx_destroy(almtx_t *mtx) DeleteCriticalSection(mtx); } -#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 -int alcnd_init(alcnd_t *cond) -{ - InitializeConditionVariable(cond); - return althrd_success; -} - -int alcnd_signal(alcnd_t *cond) -{ - WakeConditionVariable(cond); - return althrd_success; -} - -int alcnd_broadcast(alcnd_t *cond) -{ - WakeAllConditionVariable(cond); - return althrd_success; -} - -int alcnd_wait(alcnd_t *cond, almtx_t *mtx) -{ - if(SleepConditionVariableCS(cond, mtx, INFINITE) != 0) - return althrd_success; - return althrd_error; -} - -void alcnd_destroy(alcnd_t* UNUSED(cond)) -{ - /* Nothing to delete? */ -} - -#else - -/* WARNING: This is a rather poor implementation of condition variables, with - * known problems. However, it's simple, efficient, and good enough for now to - * not require Vista. Based on "Strategies for Implementing POSIX Condition - * Variables" by Douglas C. Schmidt and Irfan Pyarali: - * http://www.cs.wustl.edu/~schmidt/win32-cv-1.html - */ -/* A better solution may be using Wine's implementation. It requires internals - * (NtCreateKeyedEvent, NtReleaseKeyedEvent, and NtWaitForKeyedEvent) from - * ntdll, and implemention of exchange and compare-exchange for RefCounts. - */ - -typedef struct { - RefCount wait_count; - - HANDLE events[2]; -} _int_alcnd_t; -enum { - SIGNAL = 0, - BROADCAST = 1 -}; - -int alcnd_init(alcnd_t *cond) -{ - _int_alcnd_t *icond = calloc(1, sizeof(*icond)); - if(!icond) return althrd_nomem; - - InitRef(&icond->wait_count, 0); - - icond->events[SIGNAL] = CreateEventW(NULL, FALSE, FALSE, NULL); - icond->events[BROADCAST] = CreateEventW(NULL, TRUE, FALSE, NULL); - if(!icond->events[SIGNAL] || !icond->events[BROADCAST]) - { - if(icond->events[SIGNAL]) - CloseHandle(icond->events[SIGNAL]); - if(icond->events[BROADCAST]) - CloseHandle(icond->events[BROADCAST]); - free(icond); - return althrd_error; - } - - cond->Ptr = icond; - return althrd_success; -} - -int alcnd_signal(alcnd_t *cond) -{ - _int_alcnd_t *icond = cond->Ptr; - if(ReadRef(&icond->wait_count) > 0) - SetEvent(icond->events[SIGNAL]); - return althrd_success; -} - -int alcnd_broadcast(alcnd_t *cond) -{ - _int_alcnd_t *icond = cond->Ptr; - if(ReadRef(&icond->wait_count) > 0) - SetEvent(icond->events[BROADCAST]); - return althrd_success; -} - -int alcnd_wait(alcnd_t *cond, almtx_t *mtx) -{ - _int_alcnd_t *icond = cond->Ptr; - int res; - - IncrementRef(&icond->wait_count); - LeaveCriticalSection(mtx); - - res = WaitForMultipleObjects(2, icond->events, FALSE, INFINITE); - - if(DecrementRef(&icond->wait_count) == 0 && res == WAIT_OBJECT_0+BROADCAST) - ResetEvent(icond->events[BROADCAST]); - EnterCriticalSection(mtx); - - return althrd_success; -} - -void alcnd_destroy(alcnd_t *cond) -{ - _int_alcnd_t *icond = cond->Ptr; - CloseHandle(icond->events[SIGNAL]); - CloseHandle(icond->events[BROADCAST]); - free(icond); -} -#endif /* defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 */ - int alsem_init(alsem_t *sem, unsigned int initial) { @@ -560,39 +441,6 @@ void almtx_destroy(almtx_t *mtx) pthread_mutex_destroy(mtx); } -int alcnd_init(alcnd_t *cond) -{ - if(pthread_cond_init(cond, NULL) == 0) - return althrd_success; - return althrd_error; -} - -int alcnd_signal(alcnd_t *cond) -{ - if(pthread_cond_signal(cond) == 0) - return althrd_success; - return althrd_error; -} - -int alcnd_broadcast(alcnd_t *cond) -{ - if(pthread_cond_broadcast(cond) == 0) - return althrd_success; - return althrd_error; -} - -int alcnd_wait(alcnd_t *cond, almtx_t *mtx) -{ - if(pthread_cond_wait(cond, mtx) == 0) - return althrd_success; - return althrd_error; -} - -void alcnd_destroy(alcnd_t *cond) -{ - pthread_cond_destroy(cond); -} - #ifdef __APPLE__ diff --git a/common/threads.h b/common/threads.h index c2168cdf..2cc65557 100644 --- a/common/threads.h +++ b/common/threads.h @@ -41,11 +41,6 @@ typedef void (*altss_dtor_t)(void*); typedef DWORD althrd_t; typedef CRITICAL_SECTION almtx_t; -#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 -typedef CONDITION_VARIABLE alcnd_t; -#else -typedef struct { void *Ptr; } alcnd_t; -#endif typedef HANDLE alsem_t; typedef DWORD altss_t; typedef LONG alonce_flag; @@ -128,7 +123,6 @@ inline int altss_set(altss_t tss_id, void *val) typedef pthread_t althrd_t; typedef pthread_mutex_t almtx_t; -typedef pthread_cond_t alcnd_t; #ifdef __APPLE__ typedef dispatch_semaphore_t alsem_t; #else /* !__APPLE__ */ @@ -220,12 +214,6 @@ void althrd_setname(althrd_t thr, const char *name); int almtx_init(almtx_t *mtx, int type); void almtx_destroy(almtx_t *mtx); -int alcnd_init(alcnd_t *cond); -int alcnd_signal(alcnd_t *cond); -int alcnd_broadcast(alcnd_t *cond); -int alcnd_wait(alcnd_t *cond, almtx_t *mtx); -void alcnd_destroy(alcnd_t *cond); - int alsem_init(alsem_t *sem, unsigned int initial); void alsem_destroy(alsem_t *sem); int alsem_post(alsem_t *sem); -- cgit v1.2.3 From f99b16daa9b38cb2da8717be65db29da2fa518af Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Nov 2018 00:33:04 -0800 Subject: Use C++ threads in the null and wave backends --- Alc/backends/null.cpp | 30 +++++++++++++++++------------- Alc/backends/wave.cpp | 42 +++++++++++++++++++++--------------------- 2 files changed, 38 insertions(+), 34 deletions(-) diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 4c1d3956..ccb1327f 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -30,7 +30,6 @@ #include "alMain.h" #include "alu.h" -#include "threads.h" #include "compat.h" #include "backends/base.h" @@ -48,10 +47,10 @@ constexpr ALCchar nullDevice[] = "No Output"; struct ALCnullBackend final : public ALCbackend { ATOMIC(int) killNow; - althrd_t thread; + std::thread thread; }; -static int ALCnullBackend_mixerProc(void *ptr); +static int ALCnullBackend_mixerProc(ALCnullBackend *self); static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device); static void ALCnullBackend_Destruct(ALCnullBackend *self); @@ -85,9 +84,8 @@ static void ALCnullBackend_Destruct(ALCnullBackend *self) } -static int ALCnullBackend_mixerProc(void *ptr) +static int ALCnullBackend_mixerProc(ALCnullBackend *self) { - ALCnullBackend *self = (ALCnullBackend*)ptr; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; const milliseconds restTime{device->UpdateSize*1000/device->Frequency / 2}; @@ -156,19 +154,25 @@ static ALCboolean ALCnullBackend_reset(ALCnullBackend *self) static ALCboolean ALCnullBackend_start(ALCnullBackend *self) { - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); - if(althrd_create(&self->thread, ALCnullBackend_mixerProc, self) != althrd_success) - return ALC_FALSE; - return ALC_TRUE; + try { + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); + self->thread = std::thread(ALCnullBackend_mixerProc, self); + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Failed to start mixing thread: %s\n", e.what()); + } + catch(...) { + } + return ALC_FALSE; } static void ALCnullBackend_stop(ALCnullBackend *self) { - int res; - - if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) + if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel) || + !self->thread.joinable()) return; - althrd_join(self->thread, &res); + self->thread.join(); } diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index d5611783..118ed309 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -31,7 +31,6 @@ #include "alMain.h" #include "alu.h" #include "alconfig.h" -#include "threads.h" #include "compat.h" #include "backends/base.h" @@ -88,10 +87,10 @@ struct ALCwaveBackend final : public ALCbackend { ALuint mSize; ATOMIC(ALenum) killNow; - althrd_t thread; + std::thread thread; }; -static int ALCwaveBackend_mixerProc(void *ptr); +static int ALCwaveBackend_mixerProc(ALCwaveBackend *self); static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device); static void ALCwaveBackend_Destruct(ALCwaveBackend *self); @@ -134,9 +133,8 @@ static void ALCwaveBackend_Destruct(ALCwaveBackend *self) self->~ALCwaveBackend(); } -static int ALCwaveBackend_mixerProc(void *ptr) +static int ALCwaveBackend_mixerProc(ALCwaveBackend *self) { - ALCwaveBackend *self = (ALCwaveBackend*)ptr; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; const milliseconds restTime{device->UpdateSize*1000/device->Frequency / 2}; @@ -366,35 +364,37 @@ static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self) return ALC_FALSE; } - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); - if(althrd_create(&self->thread, ALCwaveBackend_mixerProc, self) != althrd_success) - { - free(self->mBuffer); - self->mBuffer = nullptr; - self->mSize = 0; - return ALC_FALSE; + try { + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); + self->thread = std::thread(ALCwaveBackend_mixerProc, self); + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Failed to start mixing thread: %s\n", e.what()); + } + catch(...) { } - return ALC_TRUE; + free(self->mBuffer); + self->mBuffer = nullptr; + self->mSize = 0; + return ALC_FALSE; } static void ALCwaveBackend_stop(ALCwaveBackend *self) { - ALuint dataLen; - long size; - int res; - - if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) + if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel) || + !self->thread.joinable()) return; - althrd_join(self->thread, &res); + self->thread.join(); free(self->mBuffer); self->mBuffer = nullptr; - size = ftell(self->mFile); + long size{ftell(self->mFile)}; if(size > 0) { - dataLen = size - self->mDataStart; + long dataLen{size - self->mDataStart}; if(fseek(self->mFile, self->mDataStart-4, SEEK_SET) == 0) fwrite32le(dataLen, self->mFile); // 'data' header len if(fseek(self->mFile, 4, SEEK_SET) == 0) -- cgit v1.2.3 From 2db82bea6f10b9cea7cc821fcafa2489f7a44bb5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Nov 2018 00:47:57 -0800 Subject: Define the examples' common library earlier --- CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dc3bad12..06a64f88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1672,6 +1672,11 @@ IF(ALSOFT_TESTS) ENDIF() IF(ALSOFT_EXAMPLES) + # Add a static library with common functions used by multiple targets + ADD_LIBRARY(ex-common STATIC examples/common/alhelpers.c) + TARGET_COMPILE_DEFINITIONS(ex-common PRIVATE ${CPP_DEFS}) + TARGET_COMPILE_OPTIONS(ex-common PRIVATE ${C_FLAGS}) + ADD_EXECUTABLE(alrecord examples/alrecord.c) TARGET_COMPILE_DEFINITIONS(alrecord PRIVATE ${CPP_DEFS}) TARGET_COMPILE_OPTIONS(alrecord PRIVATE ${C_FLAGS}) @@ -1689,11 +1694,6 @@ IF(ALSOFT_EXAMPLES) IF(SDL2_FOUND) IF(SDL_SOUND_FOUND) - # Add a static library with common functions used by multiple targets - ADD_LIBRARY(ex-common STATIC examples/common/alhelpers.c) - TARGET_COMPILE_DEFINITIONS(ex-common PRIVATE ${CPP_DEFS}) - TARGET_COMPILE_OPTIONS(ex-common PRIVATE ${C_FLAGS}) - ADD_EXECUTABLE(alplay examples/alplay.c) TARGET_COMPILE_DEFINITIONS(alplay PRIVATE ${CPP_DEFS}) TARGET_INCLUDE_DIRECTORIES(alplay -- cgit v1.2.3 From d3c4bab7bb0590a976bc70301d655638b7ec0f51 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Nov 2018 03:29:43 -0800 Subject: Use a vector in the wave backend --- Alc/backends/wave.cpp | 43 +++++++++++++------------------------------ 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index 118ed309..2b10d286 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -27,6 +27,7 @@ #include #include +#include #include "alMain.h" #include "alu.h" @@ -83,8 +84,7 @@ struct ALCwaveBackend final : public ALCbackend { FILE *mFile; long mDataStart; - ALvoid *mBuffer; - ALuint mSize; + std::vector mBuffer; ATOMIC(ALenum) killNow; std::thread thread; @@ -117,9 +117,6 @@ static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device) self->mFile = nullptr; self->mDataStart = -1; - self->mBuffer = nullptr; - self->mSize = 0; - ATOMIC_INIT(&self->killNow, AL_TRUE); } @@ -159,7 +156,7 @@ static int ALCwaveBackend_mixerProc(ALCwaveBackend *self) while(avail-done >= device->UpdateSize) { ALCwaveBackend_lock(self); - aluMixData(device, self->mBuffer, device->UpdateSize); + aluMixData(device, self->mBuffer.data(), device->UpdateSize); ALCwaveBackend_unlock(self); done += device->UpdateSize; @@ -170,8 +167,8 @@ static int ALCwaveBackend_mixerProc(ALCwaveBackend *self) if(bytesize == 2) { - ALushort *samples = static_cast(self->mBuffer); - ALuint len = self->mSize / 2; + ALushort *samples = reinterpret_cast(self->mBuffer.data()); + ALuint len = self->mBuffer.size() / 2; for(i = 0;i < len;i++) { ALushort samp = samples[i]; @@ -180,8 +177,8 @@ static int ALCwaveBackend_mixerProc(ALCwaveBackend *self) } else if(bytesize == 4) { - ALuint *samples = static_cast(self->mBuffer); - ALuint len = self->mSize / 4; + ALuint *samples = reinterpret_cast(self->mBuffer.data()); + ALuint len = self->mBuffer.size() / 4; for(i = 0;i < len;i++) { ALuint samp = samples[i]; @@ -191,7 +188,7 @@ static int ALCwaveBackend_mixerProc(ALCwaveBackend *self) } } - size_t fs{fwrite(self->mBuffer, frameSize, device->UpdateSize, self->mFile)}; + size_t fs{fwrite(self->mBuffer.data(), frameSize, device->UpdateSize, self->mFile)}; (void)fs; if(ferror(self->mFile)) { @@ -347,23 +344,16 @@ static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) SetDefaultWFXChannelOrder(device); + ALuint bufsize{FrameSizeFromDevFmt( + device->FmtChans, device->FmtType, device->AmbiOrder + ) * device->UpdateSize}; + self->mBuffer.resize(bufsize); + return ALC_TRUE; } static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - - self->mSize = device->UpdateSize * FrameSizeFromDevFmt( - device->FmtChans, device->FmtType, device->AmbiOrder - ); - self->mBuffer = malloc(self->mSize); - if(!self->mBuffer) - { - ERR("Buffer malloc failed\n"); - return ALC_FALSE; - } - try { ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); self->thread = std::thread(ALCwaveBackend_mixerProc, self); @@ -374,10 +364,6 @@ static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self) } catch(...) { } - - free(self->mBuffer); - self->mBuffer = nullptr; - self->mSize = 0; return ALC_FALSE; } @@ -388,9 +374,6 @@ static void ALCwaveBackend_stop(ALCwaveBackend *self) return; self->thread.join(); - free(self->mBuffer); - self->mBuffer = nullptr; - long size{ftell(self->mFile)}; if(size > 0) { -- cgit v1.2.3 From 58a71a1a00b2cbacd00679f9136233dae23a7ca7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Nov 2018 14:56:25 -0800 Subject: Convert helpers.c to C++ --- Alc/ALc.c | 5 + Alc/ALu.c | 16 + Alc/cpu_caps.h | 8 + Alc/fpu_modes.h | 7 + Alc/helpers.c | 1050 ------------------------------------------------------- Alc/helpers.cpp | 1027 +++++++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 7 files changed, 1064 insertions(+), 1051 deletions(-) delete mode 100644 Alc/helpers.c create mode 100644 Alc/helpers.cpp diff --git a/Alc/ALc.c b/Alc/ALc.c index ae55e9b4..a483c94f 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1589,6 +1589,11 @@ extern inline void UnlockBufferList(ALCdevice *device); extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type); extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); +extern inline void alstr_reset(al_string *str); +extern inline size_t alstr_length(const_al_string str); +extern inline ALboolean alstr_empty(const_al_string str); +extern inline const al_string_char_type *alstr_get_cstr(const_al_string str); + /* ALCcontext_DeferUpdates * diff --git a/Alc/ALu.c b/Alc/ALu.c index ee3ed68f..b6ea504a 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -49,6 +49,22 @@ #include "backends/base.h" +extern inline ALuint NextPowerOf2(ALuint value); +extern inline size_t RoundUp(size_t value, size_t r); +extern inline ALint fastf2i(ALfloat f); +extern inline int float2int(float f); +extern inline float fast_roundf(float f); +#ifndef __GNUC__ +#if defined(HAVE_BITSCANFORWARD64_INTRINSIC) +extern inline int msvc64_ctz64(ALuint64 v); +#elif defined(HAVE_BITSCANFORWARD_INTRINSIC) +extern inline int msvc_ctz64(ALuint64 v); +#else +extern inline int fallback_popcnt64(ALuint64 v); +extern inline int fallback_ctz64(ALuint64 value); +#endif +#endif + extern inline ALfloat minf(ALfloat a, ALfloat b); extern inline ALfloat maxf(ALfloat a, ALfloat b); extern inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max); diff --git a/Alc/cpu_caps.h b/Alc/cpu_caps.h index 328d470e..1d867f37 100644 --- a/Alc/cpu_caps.h +++ b/Alc/cpu_caps.h @@ -1,6 +1,10 @@ #ifndef CPU_CAPS_H #define CPU_CAPS_H +#ifdef __cplusplus +extern "C" { +#endif + extern int CPUCapFlags; enum { CPU_CAP_SSE = 1<<0, @@ -12,4 +16,8 @@ enum { void FillCPUCaps(int capfilter); +#ifdef __cplusplus +} // extern "C" +#endif + #endif /* CPU_CAPS_H */ diff --git a/Alc/fpu_modes.h b/Alc/fpu_modes.h index eb305967..e8858ad9 100644 --- a/Alc/fpu_modes.h +++ b/Alc/fpu_modes.h @@ -5,6 +5,9 @@ #include #endif +#ifdef __cplusplus +extern "C" { +#endif typedef struct FPUCtl { #if defined(__GNUC__) && defined(HAVE_SSE) @@ -31,4 +34,8 @@ void RestoreFPUMode(const FPUCtl *ctl); #endif #define LEAVE_MIXER_MODE() RestoreFPUMode(&_oldMode) +#ifdef __cplusplus +} // extern "C" +#endif + #endif /* FPU_MODES_H */ diff --git a/Alc/helpers.c b/Alc/helpers.c deleted file mode 100644 index 064e03f5..00000000 --- a/Alc/helpers.c +++ /dev/null @@ -1,1050 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2011 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * 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 -#include -#include -#include -#include -#ifdef HAVE_MALLOC_H -#include -#endif -#ifdef HAVE_DIRENT_H -#include -#endif -#ifdef HAVE_PROC_PIDPATH -#include -#endif - -#ifdef __FreeBSD__ -#include -#include -#endif - -#ifndef AL_NO_UID_DEFS -#if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H) -#define INITGUID -#include -#ifdef HAVE_GUIDDEF_H -#include -#else -#include -#endif - -DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71); -DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71); - -DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf,0x08, 0x00,0xa0,0xc9,0x25,0xcd,0x16); - -DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e,0x3d, 0xc4,0x57,0x92,0x91,0x69,0x2e); -DEFINE_GUID(IID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6); -DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2); -DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2); -DEFINE_GUID(IID_IAudioCaptureClient, 0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x18,0x5c,0x39,0x5c,0xd3,0x17); - -#ifdef HAVE_WASAPI -#include -#include -#include -DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); -DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); -DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23,0xe0, 0xc0,0xff,0xee,0x7f,0x0e, 4 ); -#endif -#endif -#endif /* AL_NO_UID_DEFS */ - -#ifdef HAVE_DLFCN_H -#include -#endif -#ifdef HAVE_INTRIN_H -#include -#endif -#ifdef HAVE_CPUID_H -#include -#endif -#ifdef HAVE_SYS_SYSCONF_H -#include -#endif -#ifdef HAVE_FLOAT_H -#include -#endif -#ifdef HAVE_IEEEFP_H -#include -#endif - -#ifndef _WIN32 -#include -#include -#include -#include -#include -#elif defined(_WIN32_IE) -#include -#endif - -#include "alMain.h" -#include "alu.h" -#include "cpu_caps.h" -#include "fpu_modes.h" -#include "atomic.h" -#include "uintmap.h" -#include "vector.h" -#include "alstring.h" -#include "compat.h" -#include "threads.h" - - -extern inline ALuint NextPowerOf2(ALuint value); -extern inline size_t RoundUp(size_t value, size_t r); -extern inline ALint fastf2i(ALfloat f); -extern inline int float2int(float f); -extern inline float fast_roundf(float f); -#ifndef __GNUC__ -#if defined(HAVE_BITSCANFORWARD64_INTRINSIC) -extern inline int msvc64_ctz64(ALuint64 v); -#elif defined(HAVE_BITSCANFORWARD_INTRINSIC) -extern inline int msvc_ctz64(ALuint64 v); -#else -extern inline int fallback_popcnt64(ALuint64 v); -extern inline int fallback_ctz64(ALuint64 value); -#endif -#endif - - -#if defined(HAVE_GCC_GET_CPUID) && (defined(__i386__) || defined(__x86_64__) || \ - defined(_M_IX86) || defined(_M_X64)) -typedef unsigned int reg_type; -static inline void get_cpuid(int f, reg_type *regs) -{ __get_cpuid(f, ®s[0], ®s[1], ®s[2], ®s[3]); } -#define CAN_GET_CPUID -#elif defined(HAVE_CPUID_INTRINSIC) && (defined(__i386__) || defined(__x86_64__) || \ - defined(_M_IX86) || defined(_M_X64)) -typedef int reg_type; -static inline void get_cpuid(int f, reg_type *regs) -{ (__cpuid)(regs, f); } -#define CAN_GET_CPUID -#endif - -int CPUCapFlags = 0; - -void FillCPUCaps(int capfilter) -{ - int caps = 0; - -/* FIXME: We really should get this for all available CPUs in case different - * CPUs have different caps (is that possible on one machine?). */ -#ifdef CAN_GET_CPUID - union { - reg_type regs[4]; - char str[sizeof(reg_type[4])]; - } cpuinf[3] = {{ { 0, 0, 0, 0 } }}; - - get_cpuid(0, cpuinf[0].regs); - if(cpuinf[0].regs[0] == 0) - ERR("Failed to get CPUID\n"); - else - { - unsigned int maxfunc = cpuinf[0].regs[0]; - unsigned int maxextfunc; - - get_cpuid(0x80000000, cpuinf[0].regs); - maxextfunc = cpuinf[0].regs[0]; - - TRACE("Detected max CPUID function: 0x%x (ext. 0x%x)\n", maxfunc, maxextfunc); - - TRACE("Vendor ID: \"%.4s%.4s%.4s\"\n", cpuinf[0].str+4, cpuinf[0].str+12, cpuinf[0].str+8); - if(maxextfunc >= 0x80000004) - { - get_cpuid(0x80000002, cpuinf[0].regs); - get_cpuid(0x80000003, cpuinf[1].regs); - get_cpuid(0x80000004, cpuinf[2].regs); - TRACE("Name: \"%.16s%.16s%.16s\"\n", cpuinf[0].str, cpuinf[1].str, cpuinf[2].str); - } - - if(maxfunc >= 1) - { - get_cpuid(1, cpuinf[0].regs); - if((cpuinf[0].regs[3]&(1<<25))) - caps |= CPU_CAP_SSE; - if((caps&CPU_CAP_SSE) && (cpuinf[0].regs[3]&(1<<26))) - caps |= CPU_CAP_SSE2; - if((caps&CPU_CAP_SSE2) && (cpuinf[0].regs[2]&(1<<0))) - caps |= CPU_CAP_SSE3; - if((caps&CPU_CAP_SSE3) && (cpuinf[0].regs[2]&(1<<19))) - caps |= CPU_CAP_SSE4_1; - } - } -#else - /* Assume support for whatever's supported if we can't check for it */ -#if defined(HAVE_SSE4_1) -#warning "Assuming SSE 4.1 run-time support!" - caps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1; -#elif defined(HAVE_SSE3) -#warning "Assuming SSE 3 run-time support!" - caps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3; -#elif defined(HAVE_SSE2) -#warning "Assuming SSE 2 run-time support!" - caps |= CPU_CAP_SSE | CPU_CAP_SSE2; -#elif defined(HAVE_SSE) -#warning "Assuming SSE run-time support!" - caps |= CPU_CAP_SSE; -#endif -#endif -#ifdef HAVE_NEON - FILE *file = fopen("/proc/cpuinfo", "rt"); - if(!file) - ERR("Failed to open /proc/cpuinfo, cannot check for NEON support\n"); - else - { - al_string features = AL_STRING_INIT_STATIC(); - char buf[256]; - - while(fgets(buf, sizeof(buf), file) != NULL) - { - if(strncmp(buf, "Features\t:", 10) != 0) - continue; - - alstr_copy_cstr(&features, buf+10); - while(VECTOR_BACK(features) != '\n') - { - if(fgets(buf, sizeof(buf), file) == NULL) - break; - alstr_append_cstr(&features, buf); - } - break; - } - fclose(file); - file = NULL; - - if(!alstr_empty(features)) - { - const char *str = alstr_get_cstr(features); - while(isspace(str[0])) ++str; - - TRACE("Got features string:%s\n", str); - while((str=strstr(str, "neon")) != NULL) - { - if(isspace(*(str-1)) && (str[4] == 0 || isspace(str[4]))) - { - caps |= CPU_CAP_NEON; - break; - } - ++str; - } - } - - alstr_reset(&features); - } -#endif - - TRACE("Extensions:%s%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_SSE3) ? ((caps&CPU_CAP_SSE3) ? " +SSE3" : " -SSE3") : ""), - ((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; -} - - -void SetMixerFPUMode(FPUCtl *ctl) -{ -#if defined(__GNUC__) && defined(HAVE_SSE) - if((CPUCapFlags&CPU_CAP_SSE)) - { - __asm__ __volatile__("stmxcsr %0" : "=m" (*&ctl->sse_state)); - unsigned int sseState = ctl->sse_state; - sseState |= 0x8000; /* set flush-to-zero */ - if((CPUCapFlags&CPU_CAP_SSE2)) - sseState |= 0x0040; /* set denormals-are-zero */ - __asm__ __volatile__("ldmxcsr %0" : : "m" (*&sseState)); - } - -#elif defined(HAVE___CONTROL87_2) - - __control87_2(0, 0, &ctl->state, &ctl->sse_state); - _control87(_DN_FLUSH, _MCW_DN); - -#elif defined(HAVE__CONTROLFP) - - ctl->state = _controlfp(0, 0); - _controlfp(_DN_FLUSH, _MCW_DN); -#endif -} - -void RestoreFPUMode(const FPUCtl *ctl) -{ -#if defined(__GNUC__) && defined(HAVE_SSE) - if((CPUCapFlags&CPU_CAP_SSE)) - __asm__ __volatile__("ldmxcsr %0" : : "m" (*&ctl->sse_state)); - -#elif defined(HAVE___CONTROL87_2) - - int mode; - __control87_2(ctl->state, _MCW_DN, &mode, NULL); - __control87_2(ctl->sse_state, _MCW_DN, NULL, &mode); - -#elif defined(HAVE__CONTROLFP) - - _controlfp(ctl->state, _MCW_DN); -#endif -} - - -static int StringSortCompare(const void *str1, const void *str2) -{ - return alstr_cmp(*(const_al_string*)str1, *(const_al_string*)str2); -} - -#ifdef _WIN32 - -static WCHAR *strrchrW(WCHAR *str, WCHAR ch) -{ - WCHAR *ret = NULL; - while(*str) - { - if(*str == ch) - ret = str; - ++str; - } - return ret; -} - -void GetProcBinary(al_string *path, al_string *fname) -{ - WCHAR *pathname, *sep; - DWORD pathlen; - DWORD len; - - pathlen = 256; - pathname = malloc(pathlen * sizeof(pathname[0])); - while(pathlen > 0 && (len=GetModuleFileNameW(NULL, pathname, pathlen)) == pathlen) - { - free(pathname); - pathlen <<= 1; - pathname = malloc(pathlen * sizeof(pathname[0])); - } - if(len == 0) - { - free(pathname); - ERR("Failed to get process name: error %lu\n", GetLastError()); - return; - } - - pathname[len] = 0; - if((sep=strrchrW(pathname, '\\')) != NULL) - { - WCHAR *sep2 = strrchrW(sep+1, '/'); - if(sep2) sep = sep2; - } - else - sep = strrchrW(pathname, '/'); - - if(sep) - { - if(path) alstr_copy_wrange(path, pathname, sep); - if(fname) alstr_copy_wcstr(fname, sep+1); - } - else - { - if(path) alstr_clear(path); - if(fname) alstr_copy_wcstr(fname, pathname); - } - free(pathname); - - if(path && fname) - TRACE("Got: %s, %s\n", alstr_get_cstr(*path), alstr_get_cstr(*fname)); - else if(path) TRACE("Got path: %s\n", alstr_get_cstr(*path)); - else if(fname) TRACE("Got filename: %s\n", alstr_get_cstr(*fname)); -} - - -static WCHAR *FromUTF8(const char *str) -{ - WCHAR *out = NULL; - int len; - - if((len=MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)) > 0) - { - out = calloc(sizeof(WCHAR), len); - MultiByteToWideChar(CP_UTF8, 0, str, -1, out, len); - } - return out; -} - - -void *LoadLib(const char *name) -{ - HANDLE hdl = NULL; - WCHAR *wname; - - 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) -{ - void *ret; - - ret = (void*)GetProcAddress((HANDLE)handle, name); - if(ret == NULL) - ERR("Failed to load %s\n", name); - return ret; -} - - -void al_print(const char *type, const char *func, const char *fmt, ...) -{ - char str[1024]; - WCHAR *wstr; - va_list ap; - - va_start(ap, fmt); - vsnprintf(str, sizeof(str), fmt, ap); - va_end(ap); - - str[sizeof(str)-1] = 0; - wstr = FromUTF8(str); - if(!wstr) - fprintf(LogFile, "AL lib: %s %s: %s", type, func, str); - else - { - fprintf(LogFile, "AL lib: %s %s: %ls", type, func, wstr); - free(wstr); - wstr = NULL; - } - fflush(LogFile); -} - - -static inline int is_slash(int c) -{ return (c == '\\' || c == '/'); } - -static void DirectorySearch(const char *path, const char *ext, vector_al_string *results) -{ - al_string pathstr = AL_STRING_INIT_STATIC(); - WIN32_FIND_DATAW fdata; - WCHAR *wpath; - HANDLE hdl; - - alstr_copy_cstr(&pathstr, path); - alstr_append_cstr(&pathstr, "\\*"); - alstr_append_cstr(&pathstr, ext); - - TRACE("Searching %s\n", alstr_get_cstr(pathstr)); - - wpath = FromUTF8(alstr_get_cstr(pathstr)); - - hdl = FindFirstFileW(wpath, &fdata); - if(hdl != INVALID_HANDLE_VALUE) - { - size_t base = VECTOR_SIZE(*results); - do { - al_string str = AL_STRING_INIT_STATIC(); - alstr_copy_cstr(&str, path); - alstr_append_char(&str, '\\'); - alstr_append_wcstr(&str, fdata.cFileName); - TRACE("Got result %s\n", alstr_get_cstr(str)); - VECTOR_PUSH_BACK(*results, str); - } while(FindNextFileW(hdl, &fdata)); - FindClose(hdl); - - if(VECTOR_SIZE(*results) > base) - qsort(VECTOR_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, - sizeof(VECTOR_FRONT(*results)), StringSortCompare); - } - - free(wpath); - alstr_reset(&pathstr); -} - -vector_al_string SearchDataFiles(const char *ext, const char *subdir) -{ - static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA }; - static RefCount search_lock; - vector_al_string results = VECTOR_INIT_STATIC(); - size_t i; - - while(ATOMIC_EXCHANGE_SEQ(&search_lock, 1) == 1) - althrd_yield(); - - /* If the path is absolute, use it directly. */ - if(isalpha(subdir[0]) && subdir[1] == ':' && is_slash(subdir[2])) - { - al_string path = AL_STRING_INIT_STATIC(); - alstr_copy_cstr(&path, subdir); -#define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) - VECTOR_FOR_EACH(char, path, FIX_SLASH); -#undef FIX_SLASH - - DirectorySearch(alstr_get_cstr(path), ext, &results); - - alstr_reset(&path); - } - else if(subdir[0] == '\\' && subdir[1] == '\\' && subdir[2] == '?' && subdir[3] == '\\') - DirectorySearch(subdir, ext, &results); - else - { - al_string path = AL_STRING_INIT_STATIC(); - WCHAR *cwdbuf; - - /* Search the app-local directory. */ - if((cwdbuf=_wgetenv(L"ALSOFT_LOCAL_PATH")) && *cwdbuf != '\0') - { - alstr_copy_wcstr(&path, cwdbuf); - if(is_slash(VECTOR_BACK(path))) - { - VECTOR_POP_BACK(path); - *VECTOR_END(path) = 0; - } - } - else if(!(cwdbuf=_wgetcwd(NULL, 0))) - alstr_copy_cstr(&path, "."); - else - { - alstr_copy_wcstr(&path, cwdbuf); - if(is_slash(VECTOR_BACK(path))) - { - VECTOR_POP_BACK(path); - *VECTOR_END(path) = 0; - } - free(cwdbuf); - } -#define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) - VECTOR_FOR_EACH(char, path, FIX_SLASH); -#undef FIX_SLASH - DirectorySearch(alstr_get_cstr(path), ext, &results); - - /* Search the local and global data dirs. */ - for(i = 0;i < COUNTOF(ids);i++) - { - WCHAR buffer[MAX_PATH]; - if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) != FALSE) - { - alstr_copy_wcstr(&path, buffer); - if(!is_slash(VECTOR_BACK(path))) - alstr_append_char(&path, '\\'); - alstr_append_cstr(&path, subdir); -#define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) - VECTOR_FOR_EACH(char, path, FIX_SLASH); -#undef FIX_SLASH - - DirectorySearch(alstr_get_cstr(path), ext, &results); - } - } - - alstr_reset(&path); - } - - ATOMIC_STORE_SEQ(&search_lock, 0); - - return results; -} - -#else - -void GetProcBinary(al_string *path, al_string *fname) -{ - char *pathname = NULL; - size_t pathlen; - -#ifdef __FreeBSD__ - int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; - if(sysctl(mib, 4, NULL, &pathlen, NULL, 0) == -1) - WARN("Failed to sysctl kern.proc.pathname: %s\n", strerror(errno)); - else - { - pathname = malloc(pathlen + 1); - sysctl(mib, 4, (void*)pathname, &pathlen, NULL, 0); - pathname[pathlen] = 0; - } -#endif -#ifdef HAVE_PROC_PIDPATH - if(!pathname) - { - const pid_t pid = getpid(); - char procpath[PROC_PIDPATHINFO_MAXSIZE]; - int ret; - - ret = proc_pidpath(pid, procpath, sizeof(procpath)); - if(ret < 1) - { - WARN("proc_pidpath(%d, ...) failed: %s\n", pid, strerror(errno)); - free(pathname); - pathname = NULL; - } - else - { - pathlen = strlen(procpath); - pathname = strdup(procpath); - } - } -#endif - if(!pathname) - { - const char *selfname; - ssize_t len; - - pathlen = 256; - pathname = malloc(pathlen); - - selfname = "/proc/self/exe"; - len = readlink(selfname, pathname, pathlen); - if(len == -1 && errno == ENOENT) - { - selfname = "/proc/self/file"; - len = readlink(selfname, pathname, pathlen); - } - if(len == -1 && errno == ENOENT) - { - selfname = "/proc/curproc/exe"; - len = readlink(selfname, pathname, pathlen); - } - if(len == -1 && errno == ENOENT) - { - selfname = "/proc/curproc/file"; - len = readlink(selfname, pathname, pathlen); - } - - while(len > 0 && (size_t)len == pathlen) - { - free(pathname); - pathlen <<= 1; - pathname = malloc(pathlen); - len = readlink(selfname, pathname, pathlen); - } - if(len <= 0) - { - free(pathname); - WARN("Failed to readlink %s: %s\n", selfname, strerror(errno)); - return; - } - - pathname[len] = 0; - } - - char *sep = strrchr(pathname, '/'); - if(sep) - { - if(path) alstr_copy_range(path, pathname, sep); - if(fname) alstr_copy_cstr(fname, sep+1); - } - else - { - if(path) alstr_clear(path); - if(fname) alstr_copy_cstr(fname, pathname); - } - free(pathname); - - if(path && fname) - TRACE("Got: %s, %s\n", alstr_get_cstr(*path), alstr_get_cstr(*fname)); - else if(path) TRACE("Got path: %s\n", alstr_get_cstr(*path)); - else if(fname) TRACE("Got filename: %s\n", alstr_get_cstr(*fname)); -} - - -#ifdef HAVE_DLFCN_H - -void *LoadLib(const char *name) -{ - const char *err; - void *handle; - - dlerror(); - handle = dlopen(name, RTLD_NOW); - if((err=dlerror()) != NULL) - handle = NULL; - return handle; -} -void CloseLib(void *handle) -{ dlclose(handle); } -void *GetSymbol(void *handle, const char *name) -{ - const char *err; - void *sym; - - dlerror(); - sym = dlsym(handle, name); - if((err=dlerror()) != NULL) - { - WARN("Failed to load %s: %s\n", name, err); - sym = NULL; - } - return sym; -} - -#endif /* HAVE_DLFCN_H */ - -void al_print(const char *type, const char *func, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - fprintf(LogFile, "AL lib: %s %s: ", type, func); - vfprintf(LogFile, fmt, ap); - va_end(ap); - - fflush(LogFile); -} - - -static void DirectorySearch(const char *path, const char *ext, vector_al_string *results) -{ - size_t extlen = strlen(ext); - DIR *dir; - - TRACE("Searching %s for *%s\n", path, ext); - dir = opendir(path); - if(dir != NULL) - { - size_t base = VECTOR_SIZE(*results); - struct dirent *dirent; - while((dirent=readdir(dir)) != NULL) - { - al_string str; - size_t len; - if(strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) - continue; - - len = strlen(dirent->d_name); - if(len <= extlen) - continue; - if(strcasecmp(dirent->d_name+len-extlen, ext) != 0) - continue; - - AL_STRING_INIT(str); - alstr_copy_cstr(&str, path); - if(VECTOR_BACK(str) != '/') - alstr_append_char(&str, '/'); - alstr_append_cstr(&str, dirent->d_name); - TRACE("Got result %s\n", alstr_get_cstr(str)); - VECTOR_PUSH_BACK(*results, str); - } - closedir(dir); - - if(VECTOR_SIZE(*results) > base) - qsort(VECTOR_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, - sizeof(VECTOR_FRONT(*results)), StringSortCompare); - } -} - -vector_al_string SearchDataFiles(const char *ext, const char *subdir) -{ - static RefCount search_lock; - vector_al_string results = VECTOR_INIT_STATIC(); - - while(ATOMIC_EXCHANGE_SEQ(&search_lock, 1) == 1) - althrd_yield(); - - if(subdir[0] == '/') - DirectorySearch(subdir, ext, &results); - else - { - al_string path = AL_STRING_INIT_STATIC(); - const char *str, *next; - - /* Search the app-local directory. */ - if((str=getenv("ALSOFT_LOCAL_PATH")) && *str != '\0') - DirectorySearch(str, ext, &results); - else - { - size_t cwdlen = 256; - char *cwdbuf = malloc(cwdlen); - while(!getcwd(cwdbuf, cwdlen)) - { - free(cwdbuf); - cwdbuf = NULL; - if(errno != ERANGE) - break; - cwdlen <<= 1; - cwdbuf = malloc(cwdlen); - } - if(!cwdbuf) - DirectorySearch(".", ext, &results); - else - { - DirectorySearch(cwdbuf, ext, &results); - free(cwdbuf); - cwdbuf = NULL; - } - } - - // Search local data dir - if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0') - { - alstr_copy_cstr(&path, str); - if(VECTOR_BACK(path) != '/') - alstr_append_char(&path, '/'); - alstr_append_cstr(&path, subdir); - DirectorySearch(alstr_get_cstr(path), ext, &results); - } - else if((str=getenv("HOME")) != NULL && str[0] != '\0') - { - alstr_copy_cstr(&path, str); - if(VECTOR_BACK(path) == '/') - { - VECTOR_POP_BACK(path); - *VECTOR_END(path) = 0; - } - alstr_append_cstr(&path, "/.local/share/"); - alstr_append_cstr(&path, subdir); - DirectorySearch(alstr_get_cstr(path), ext, &results); - } - - // Search global data dirs - 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') - { - next = strchr(str, ':'); - if(!next) - alstr_copy_cstr(&path, str); - else - { - alstr_copy_range(&path, str, next); - ++next; - } - if(!alstr_empty(path)) - { - if(VECTOR_BACK(path) != '/') - alstr_append_char(&path, '/'); - alstr_append_cstr(&path, subdir); - - DirectorySearch(alstr_get_cstr(path), ext, &results); - } - } - - alstr_reset(&path); - } - - ATOMIC_STORE_SEQ(&search_lock, 0); - - return results; -} - -#endif - - -void SetRTPriority(void) -{ - ALboolean failed = AL_FALSE; - -#ifdef _WIN32 - if(RTPrioLevel > 0) - failed = !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); -#elif defined(HAVE_PTHREAD_SETSCHEDPARAM) && !defined(__OpenBSD__) - if(RTPrioLevel > 0) - { - struct sched_param param; - /* Use the minimum real-time priority possible for now (on Linux this - * should be 1 for SCHED_RR) */ - param.sched_priority = sched_get_priority_min(SCHED_RR); - failed = !!pthread_setschedparam(pthread_self(), SCHED_RR, ¶m); - } -#else - /* Real-time priority not available */ - failed = (RTPrioLevel>0); -#endif - if(failed) - ERR("Failed to set priority level for thread\n"); -} - - -extern inline void alstr_reset(al_string *str); -extern inline size_t alstr_length(const_al_string str); -extern inline ALboolean alstr_empty(const_al_string str); -extern inline const al_string_char_type *alstr_get_cstr(const_al_string str); - -void alstr_clear(al_string *str) -{ - if(!alstr_empty(*str)) - { - /* 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_RESIZE(*str, 0, 1); - VECTOR_ELEM(*str, 0) = 0; - } -} - -static inline int alstr_compare(const al_string_char_type *str1, size_t str1len, - const al_string_char_type *str2, size_t str2len) -{ - size_t complen = (str1len < str2len) ? str1len : str2len; - int ret = memcmp(str1, str2, complen); - if(ret == 0) - { - if(str1len > str2len) return 1; - if(str1len < str2len) return -1; - } - return ret; -} -int alstr_cmp(const_al_string str1, const_al_string str2) -{ - return alstr_compare(&VECTOR_FRONT(str1), alstr_length(str1), - &VECTOR_FRONT(str2), alstr_length(str2)); -} -int alstr_cmp_cstr(const_al_string str1, const al_string_char_type *str2) -{ - return alstr_compare(&VECTOR_FRONT(str1), alstr_length(str1), - str2, strlen(str2)); -} - -void alstr_copy(al_string *str, const_al_string from) -{ - size_t len = alstr_length(from); - size_t i; - - VECTOR_RESIZE(*str, len, len+1); - for(i = 0;i < len;i++) - VECTOR_ELEM(*str, i) = VECTOR_ELEM(from, i); - VECTOR_ELEM(*str, i) = 0; -} - -void alstr_copy_cstr(al_string *str, const al_string_char_type *from) -{ - size_t len = strlen(from); - size_t i; - - VECTOR_RESIZE(*str, len, len+1); - for(i = 0;i < len;i++) - VECTOR_ELEM(*str, i) = from[i]; - VECTOR_ELEM(*str, i) = 0; -} - -void alstr_copy_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to) -{ - size_t len = to - from; - size_t i; - - VECTOR_RESIZE(*str, len, len+1); - for(i = 0;i < len;i++) - VECTOR_ELEM(*str, i) = from[i]; - VECTOR_ELEM(*str, i) = 0; -} - -void alstr_append_char(al_string *str, const al_string_char_type c) -{ - size_t len = alstr_length(*str); - VECTOR_RESIZE(*str, len+1, len+2); - VECTOR_BACK(*str) = c; - VECTOR_ELEM(*str, len+1) = 0; -} - -void alstr_append_cstr(al_string *str, const al_string_char_type *from) -{ - size_t len = strlen(from); - if(len != 0) - { - size_t base = alstr_length(*str); - size_t i; - - VECTOR_RESIZE(*str, base+len, base+len+1); - for(i = 0;i < len;i++) - VECTOR_ELEM(*str, base+i) = from[i]; - VECTOR_ELEM(*str, base+i) = 0; - } -} - -void alstr_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to) -{ - size_t len = to - from; - if(len != 0) - { - size_t base = alstr_length(*str); - size_t i; - - VECTOR_RESIZE(*str, base+len, base+len+1); - for(i = 0;i < len;i++) - VECTOR_ELEM(*str, base+i) = from[i]; - VECTOR_ELEM(*str, base+i) = 0; - } -} - -#ifdef _WIN32 -void alstr_copy_wcstr(al_string *str, const wchar_t *from) -{ - int len; - if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0) - { - VECTOR_RESIZE(*str, len-1, len); - WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_FRONT(*str), len, NULL, NULL); - VECTOR_ELEM(*str, len-1) = 0; - } -} - -void alstr_append_wcstr(al_string *str, const wchar_t *from) -{ - int len; - if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0) - { - size_t base = alstr_length(*str); - VECTOR_RESIZE(*str, base+len-1, base+len); - WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_ELEM(*str, base), len, NULL, NULL); - VECTOR_ELEM(*str, base+len-1) = 0; - } -} - -void alstr_copy_wrange(al_string *str, const wchar_t *from, const wchar_t *to) -{ - int len; - if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), NULL, 0, NULL, NULL)) > 0) - { - VECTOR_RESIZE(*str, len, len+1); - WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_FRONT(*str), len+1, NULL, NULL); - VECTOR_ELEM(*str, len) = 0; - } -} - -void alstr_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to) -{ - int len; - if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), NULL, 0, NULL, NULL)) > 0) - { - size_t base = alstr_length(*str); - VECTOR_RESIZE(*str, base+len, base+len+1); - WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_ELEM(*str, base), len+1, NULL, NULL); - VECTOR_ELEM(*str, base+len) = 0; - } -} -#endif diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp new file mode 100644 index 00000000..abd010e6 --- /dev/null +++ b/Alc/helpers.cpp @@ -0,0 +1,1027 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2011 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * 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 +#include +#include +#include +#include +#ifdef HAVE_MALLOC_H +#include +#endif +#ifdef HAVE_DIRENT_H +#include +#endif +#ifdef HAVE_PROC_PIDPATH +#include +#endif + +#ifdef __FreeBSD__ +#include +#include +#endif + +#ifndef AL_NO_UID_DEFS +#if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H) +#define INITGUID +#include +#ifdef HAVE_GUIDDEF_H +#include +#else +#include +#endif + +DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71); +DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71); + +DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf,0x08, 0x00,0xa0,0xc9,0x25,0xcd,0x16); + +DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e,0x3d, 0xc4,0x57,0x92,0x91,0x69,0x2e); +DEFINE_GUID(IID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6); +DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2); +DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2); +DEFINE_GUID(IID_IAudioCaptureClient, 0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x18,0x5c,0x39,0x5c,0xd3,0x17); + +#ifdef HAVE_WASAPI +#include +#include +#include +DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23,0xe0, 0xc0,0xff,0xee,0x7f,0x0e, 4 ); +#endif +#endif +#endif /* AL_NO_UID_DEFS */ + +#ifdef HAVE_DLFCN_H +#include +#endif +#ifdef HAVE_INTRIN_H +#include +#endif +#ifdef HAVE_CPUID_H +#include +#endif +#ifdef HAVE_SYS_SYSCONF_H +#include +#endif +#ifdef HAVE_FLOAT_H +#include +#endif +#ifdef HAVE_IEEEFP_H +#include +#endif + +#ifndef _WIN32 +#include +#include +#include +#include +#include +#elif defined(_WIN32_IE) +#include +#endif + +#include "alMain.h" +#include "alu.h" +#include "cpu_caps.h" +#include "fpu_modes.h" +#include "atomic.h" +#include "uintmap.h" +#include "vector.h" +#include "alstring.h" +#include "compat.h" +#include "threads.h" + + +#if defined(HAVE_GCC_GET_CPUID) && (defined(__i386__) || defined(__x86_64__) || \ + defined(_M_IX86) || defined(_M_X64)) +typedef unsigned int reg_type; +static inline void get_cpuid(int f, reg_type *regs) +{ __get_cpuid(f, ®s[0], ®s[1], ®s[2], ®s[3]); } +#define CAN_GET_CPUID +#elif defined(HAVE_CPUID_INTRINSIC) && (defined(__i386__) || defined(__x86_64__) || \ + defined(_M_IX86) || defined(_M_X64)) +typedef int reg_type; +static inline void get_cpuid(int f, reg_type *regs) +{ (__cpuid)(regs, f); } +#define CAN_GET_CPUID +#endif + +int CPUCapFlags = 0; + +void FillCPUCaps(int capfilter) +{ + int caps = 0; + +/* FIXME: We really should get this for all available CPUs in case different + * CPUs have different caps (is that possible on one machine?). */ +#ifdef CAN_GET_CPUID + union { + reg_type regs[4]; + char str[sizeof(reg_type[4])]; + } cpuinf[3] = {{ { 0, 0, 0, 0 } }}; + + get_cpuid(0, cpuinf[0].regs); + if(cpuinf[0].regs[0] == 0) + ERR("Failed to get CPUID\n"); + else + { + unsigned int maxfunc = cpuinf[0].regs[0]; + unsigned int maxextfunc; + + get_cpuid(0x80000000, cpuinf[0].regs); + maxextfunc = cpuinf[0].regs[0]; + + TRACE("Detected max CPUID function: 0x%x (ext. 0x%x)\n", maxfunc, maxextfunc); + + TRACE("Vendor ID: \"%.4s%.4s%.4s\"\n", cpuinf[0].str+4, cpuinf[0].str+12, cpuinf[0].str+8); + if(maxextfunc >= 0x80000004) + { + get_cpuid(0x80000002, cpuinf[0].regs); + get_cpuid(0x80000003, cpuinf[1].regs); + get_cpuid(0x80000004, cpuinf[2].regs); + TRACE("Name: \"%.16s%.16s%.16s\"\n", cpuinf[0].str, cpuinf[1].str, cpuinf[2].str); + } + + if(maxfunc >= 1) + { + get_cpuid(1, cpuinf[0].regs); + if((cpuinf[0].regs[3]&(1<<25))) + caps |= CPU_CAP_SSE; + if((caps&CPU_CAP_SSE) && (cpuinf[0].regs[3]&(1<<26))) + caps |= CPU_CAP_SSE2; + if((caps&CPU_CAP_SSE2) && (cpuinf[0].regs[2]&(1<<0))) + caps |= CPU_CAP_SSE3; + if((caps&CPU_CAP_SSE3) && (cpuinf[0].regs[2]&(1<<19))) + caps |= CPU_CAP_SSE4_1; + } + } +#else + /* Assume support for whatever's supported if we can't check for it */ +#if defined(HAVE_SSE4_1) +#warning "Assuming SSE 4.1 run-time support!" + caps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1; +#elif defined(HAVE_SSE3) +#warning "Assuming SSE 3 run-time support!" + caps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3; +#elif defined(HAVE_SSE2) +#warning "Assuming SSE 2 run-time support!" + caps |= CPU_CAP_SSE | CPU_CAP_SSE2; +#elif defined(HAVE_SSE) +#warning "Assuming SSE run-time support!" + caps |= CPU_CAP_SSE; +#endif +#endif +#ifdef HAVE_NEON + FILE *file = fopen("/proc/cpuinfo", "rt"); + if(!file) + ERR("Failed to open /proc/cpuinfo, cannot check for NEON support\n"); + else + { + al_string features = AL_STRING_INIT_STATIC(); + char buf[256]; + + while(fgets(buf, sizeof(buf), file) != NULL) + { + if(strncmp(buf, "Features\t:", 10) != 0) + continue; + + alstr_copy_cstr(&features, buf+10); + while(VECTOR_BACK(features) != '\n') + { + if(fgets(buf, sizeof(buf), file) == NULL) + break; + alstr_append_cstr(&features, buf); + } + break; + } + fclose(file); + file = NULL; + + if(!alstr_empty(features)) + { + const char *str = alstr_get_cstr(features); + while(isspace(str[0])) ++str; + + TRACE("Got features string:%s\n", str); + while((str=strstr(str, "neon")) != NULL) + { + if(isspace(*(str-1)) && (str[4] == 0 || isspace(str[4]))) + { + caps |= CPU_CAP_NEON; + break; + } + ++str; + } + } + + alstr_reset(&features); + } +#endif + + TRACE("Extensions:%s%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_SSE3) ? ((caps&CPU_CAP_SSE3) ? " +SSE3" : " -SSE3") : ""), + ((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; +} + + +void SetMixerFPUMode(FPUCtl *ctl) +{ +#if defined(__GNUC__) && defined(HAVE_SSE) + if((CPUCapFlags&CPU_CAP_SSE)) + { + __asm__ __volatile__("stmxcsr %0" : "=m" (*&ctl->sse_state)); + unsigned int sseState = ctl->sse_state; + sseState |= 0x8000; /* set flush-to-zero */ + if((CPUCapFlags&CPU_CAP_SSE2)) + sseState |= 0x0040; /* set denormals-are-zero */ + __asm__ __volatile__("ldmxcsr %0" : : "m" (*&sseState)); + } + +#elif defined(HAVE___CONTROL87_2) + + __control87_2(0, 0, &ctl->state, &ctl->sse_state); + _control87(_DN_FLUSH, _MCW_DN); + +#elif defined(HAVE__CONTROLFP) + + ctl->state = _controlfp(0, 0); + _controlfp(_DN_FLUSH, _MCW_DN); +#endif +} + +void RestoreFPUMode(const FPUCtl *ctl) +{ +#if defined(__GNUC__) && defined(HAVE_SSE) + if((CPUCapFlags&CPU_CAP_SSE)) + __asm__ __volatile__("ldmxcsr %0" : : "m" (*&ctl->sse_state)); + +#elif defined(HAVE___CONTROL87_2) + + int mode; + __control87_2(ctl->state, _MCW_DN, &mode, NULL); + __control87_2(ctl->sse_state, _MCW_DN, NULL, &mode); + +#elif defined(HAVE__CONTROLFP) + + _controlfp(ctl->state, _MCW_DN); +#endif +} + + +static int StringSortCompare(const void *str1, const void *str2) +{ + return alstr_cmp(*(const_al_string*)str1, *(const_al_string*)str2); +} + +#ifdef _WIN32 + +static WCHAR *strrchrW(WCHAR *str, WCHAR ch) +{ + WCHAR *ret = NULL; + while(*str) + { + if(*str == ch) + ret = str; + ++str; + } + return ret; +} + +void GetProcBinary(al_string *path, al_string *fname) +{ + WCHAR *pathname, *sep; + DWORD pathlen; + DWORD len; + + pathlen = 256; + pathname = static_cast(malloc(pathlen * sizeof(pathname[0]))); + while(pathlen > 0 && (len=GetModuleFileNameW(NULL, pathname, pathlen)) == pathlen) + { + free(pathname); + pathlen <<= 1; + pathname = static_cast(malloc(pathlen * sizeof(pathname[0]))); + } + if(len == 0) + { + free(pathname); + ERR("Failed to get process name: error %lu\n", GetLastError()); + return; + } + + pathname[len] = 0; + if((sep=strrchrW(pathname, '\\')) != NULL) + { + WCHAR *sep2 = strrchrW(sep+1, '/'); + if(sep2) sep = sep2; + } + else + sep = strrchrW(pathname, '/'); + + if(sep) + { + if(path) alstr_copy_wrange(path, pathname, sep); + if(fname) alstr_copy_wcstr(fname, sep+1); + } + else + { + if(path) alstr_clear(path); + if(fname) alstr_copy_wcstr(fname, pathname); + } + free(pathname); + + if(path && fname) + TRACE("Got: %s, %s\n", alstr_get_cstr(*path), alstr_get_cstr(*fname)); + else if(path) TRACE("Got path: %s\n", alstr_get_cstr(*path)); + else if(fname) TRACE("Got filename: %s\n", alstr_get_cstr(*fname)); +} + + +static WCHAR *FromUTF8(const char *str) +{ + WCHAR *out = NULL; + int len; + + if((len=MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)) > 0) + { + out = static_cast(calloc(sizeof(WCHAR), len)); + MultiByteToWideChar(CP_UTF8, 0, str, -1, out, len); + } + return out; +} + + +void *LoadLib(const char *name) +{ + HANDLE hdl = NULL; + WCHAR *wname; + + 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(reinterpret_cast(handle)); } +void *GetSymbol(void *handle, const char *name) +{ + void *ret; + + ret = reinterpret_cast(GetProcAddress(reinterpret_cast(handle), name)); + if(!ret) ERR("Failed to load %s\n", name); + return ret; +} + + +void al_print(const char *type, const char *func, const char *fmt, ...) +{ + char str[1024]; + WCHAR *wstr; + va_list ap; + + va_start(ap, fmt); + vsnprintf(str, sizeof(str), fmt, ap); + va_end(ap); + + str[sizeof(str)-1] = 0; + wstr = FromUTF8(str); + if(!wstr) + fprintf(LogFile, "AL lib: %s %s: %s", type, func, str); + else + { + fprintf(LogFile, "AL lib: %s %s: %ls", type, func, wstr); + free(wstr); + wstr = NULL; + } + fflush(LogFile); +} + + +static inline int is_slash(int c) +{ return (c == '\\' || c == '/'); } + +static void DirectorySearch(const char *path, const char *ext, vector_al_string *results) +{ + al_string pathstr = AL_STRING_INIT_STATIC(); + WIN32_FIND_DATAW fdata; + WCHAR *wpath; + HANDLE hdl; + + alstr_copy_cstr(&pathstr, path); + alstr_append_cstr(&pathstr, "\\*"); + alstr_append_cstr(&pathstr, ext); + + TRACE("Searching %s\n", alstr_get_cstr(pathstr)); + + wpath = FromUTF8(alstr_get_cstr(pathstr)); + + hdl = FindFirstFileW(wpath, &fdata); + if(hdl != INVALID_HANDLE_VALUE) + { + size_t base = VECTOR_SIZE(*results); + do { + al_string str = AL_STRING_INIT_STATIC(); + alstr_copy_cstr(&str, path); + alstr_append_char(&str, '\\'); + alstr_append_wcstr(&str, fdata.cFileName); + TRACE("Got result %s\n", alstr_get_cstr(str)); + VECTOR_PUSH_BACK(*results, str); + } while(FindNextFileW(hdl, &fdata)); + FindClose(hdl); + + if(VECTOR_SIZE(*results) > base) + qsort(VECTOR_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, + sizeof(VECTOR_FRONT(*results)), StringSortCompare); + } + + free(wpath); + alstr_reset(&pathstr); +} + +vector_al_string SearchDataFiles(const char *ext, const char *subdir) +{ + static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA }; + static RefCount search_lock; + vector_al_string results = VECTOR_INIT_STATIC(); + size_t i; + + while(ATOMIC_EXCHANGE_SEQ(&search_lock, 1u) == 1u) + althrd_yield(); + + /* If the path is absolute, use it directly. */ + if(isalpha(subdir[0]) && subdir[1] == ':' && is_slash(subdir[2])) + { + al_string path = AL_STRING_INIT_STATIC(); + alstr_copy_cstr(&path, subdir); +#define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) + VECTOR_FOR_EACH(char, path, FIX_SLASH); +#undef FIX_SLASH + + DirectorySearch(alstr_get_cstr(path), ext, &results); + + alstr_reset(&path); + } + else if(subdir[0] == '\\' && subdir[1] == '\\' && subdir[2] == '?' && subdir[3] == '\\') + DirectorySearch(subdir, ext, &results); + else + { + al_string path = AL_STRING_INIT_STATIC(); + WCHAR *cwdbuf; + + /* Search the app-local directory. */ + if((cwdbuf=_wgetenv(L"ALSOFT_LOCAL_PATH")) && *cwdbuf != '\0') + { + alstr_copy_wcstr(&path, cwdbuf); + if(is_slash(VECTOR_BACK(path))) + { + VECTOR_POP_BACK(path); + *VECTOR_END(path) = 0; + } + } + else if(!(cwdbuf=_wgetcwd(NULL, 0))) + alstr_copy_cstr(&path, "."); + else + { + alstr_copy_wcstr(&path, cwdbuf); + if(is_slash(VECTOR_BACK(path))) + { + VECTOR_POP_BACK(path); + *VECTOR_END(path) = 0; + } + free(cwdbuf); + } +#define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) + VECTOR_FOR_EACH(char, path, FIX_SLASH); +#undef FIX_SLASH + DirectorySearch(alstr_get_cstr(path), ext, &results); + + /* Search the local and global data dirs. */ + for(i = 0;i < COUNTOF(ids);i++) + { + WCHAR buffer[MAX_PATH]; + if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) != FALSE) + { + alstr_copy_wcstr(&path, buffer); + if(!is_slash(VECTOR_BACK(path))) + alstr_append_char(&path, '\\'); + alstr_append_cstr(&path, subdir); +#define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) + VECTOR_FOR_EACH(char, path, FIX_SLASH); +#undef FIX_SLASH + + DirectorySearch(alstr_get_cstr(path), ext, &results); + } + } + + alstr_reset(&path); + } + + ATOMIC_STORE_SEQ(&search_lock, 0u); + + return results; +} + +#else + +void GetProcBinary(al_string *path, al_string *fname) +{ + char *pathname = NULL; + size_t pathlen; + +#ifdef __FreeBSD__ + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + if(sysctl(mib, 4, NULL, &pathlen, NULL, 0) == -1) + WARN("Failed to sysctl kern.proc.pathname: %s\n", strerror(errno)); + else + { + pathname = malloc(pathlen + 1); + sysctl(mib, 4, (void*)pathname, &pathlen, NULL, 0); + pathname[pathlen] = 0; + } +#endif +#ifdef HAVE_PROC_PIDPATH + if(!pathname) + { + const pid_t pid = getpid(); + char procpath[PROC_PIDPATHINFO_MAXSIZE]; + int ret; + + ret = proc_pidpath(pid, procpath, sizeof(procpath)); + if(ret < 1) + { + WARN("proc_pidpath(%d, ...) failed: %s\n", pid, strerror(errno)); + free(pathname); + pathname = NULL; + } + else + { + pathlen = strlen(procpath); + pathname = strdup(procpath); + } + } +#endif + if(!pathname) + { + const char *selfname; + ssize_t len; + + pathlen = 256; + pathname = static_cast(malloc(pathlen)); + + selfname = "/proc/self/exe"; + len = readlink(selfname, pathname, pathlen); + if(len == -1 && errno == ENOENT) + { + selfname = "/proc/self/file"; + len = readlink(selfname, pathname, pathlen); + } + if(len == -1 && errno == ENOENT) + { + selfname = "/proc/curproc/exe"; + len = readlink(selfname, pathname, pathlen); + } + if(len == -1 && errno == ENOENT) + { + selfname = "/proc/curproc/file"; + len = readlink(selfname, pathname, pathlen); + } + + while(len > 0 && (size_t)len == pathlen) + { + free(pathname); + pathlen <<= 1; + pathname = static_cast(malloc(pathlen)); + len = readlink(selfname, pathname, pathlen); + } + if(len <= 0) + { + free(pathname); + WARN("Failed to readlink %s: %s\n", selfname, strerror(errno)); + return; + } + + pathname[len] = 0; + } + + char *sep = strrchr(pathname, '/'); + if(sep) + { + if(path) alstr_copy_range(path, pathname, sep); + if(fname) alstr_copy_cstr(fname, sep+1); + } + else + { + if(path) alstr_clear(path); + if(fname) alstr_copy_cstr(fname, pathname); + } + free(pathname); + + if(path && fname) + TRACE("Got: %s, %s\n", alstr_get_cstr(*path), alstr_get_cstr(*fname)); + else if(path) TRACE("Got path: %s\n", alstr_get_cstr(*path)); + else if(fname) TRACE("Got filename: %s\n", alstr_get_cstr(*fname)); +} + + +#ifdef HAVE_DLFCN_H + +void *LoadLib(const char *name) +{ + const char *err; + void *handle; + + dlerror(); + handle = dlopen(name, RTLD_NOW); + if((err=dlerror()) != NULL) + handle = NULL; + return handle; +} +void CloseLib(void *handle) +{ dlclose(handle); } +void *GetSymbol(void *handle, const char *name) +{ + const char *err; + void *sym; + + dlerror(); + sym = dlsym(handle, name); + if((err=dlerror()) != NULL) + { + WARN("Failed to load %s: %s\n", name, err); + sym = NULL; + } + return sym; +} + +#endif /* HAVE_DLFCN_H */ + +void al_print(const char *type, const char *func, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(LogFile, "AL lib: %s %s: ", type, func); + vfprintf(LogFile, fmt, ap); + va_end(ap); + + fflush(LogFile); +} + + +static void DirectorySearch(const char *path, const char *ext, vector_al_string *results) +{ + size_t extlen = strlen(ext); + DIR *dir; + + TRACE("Searching %s for *%s\n", path, ext); + dir = opendir(path); + if(dir != NULL) + { + size_t base = VECTOR_SIZE(*results); + struct dirent *dirent; + while((dirent=readdir(dir)) != NULL) + { + al_string str; + size_t len; + if(strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) + continue; + + len = strlen(dirent->d_name); + if(len <= extlen) + continue; + if(strcasecmp(dirent->d_name+len-extlen, ext) != 0) + continue; + + AL_STRING_INIT(str); + alstr_copy_cstr(&str, path); + if(VECTOR_BACK(str) != '/') + alstr_append_char(&str, '/'); + alstr_append_cstr(&str, dirent->d_name); + TRACE("Got result %s\n", alstr_get_cstr(str)); + VECTOR_PUSH_BACK(*results, str); + } + closedir(dir); + + if(VECTOR_SIZE(*results) > base) + qsort(VECTOR_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, + sizeof(VECTOR_FRONT(*results)), StringSortCompare); + } +} + +vector_al_string SearchDataFiles(const char *ext, const char *subdir) +{ + static RefCount search_lock; + vector_al_string results = VECTOR_INIT_STATIC(); + + while(ATOMIC_EXCHANGE_SEQ(&search_lock, 1u) == 1u) + althrd_yield(); + + if(subdir[0] == '/') + DirectorySearch(subdir, ext, &results); + else + { + al_string path = AL_STRING_INIT_STATIC(); + const char *str, *next; + + /* Search the app-local directory. */ + if((str=getenv("ALSOFT_LOCAL_PATH")) && *str != '\0') + DirectorySearch(str, ext, &results); + else + { + size_t cwdlen = 256; + char *cwdbuf = static_cast(malloc(cwdlen)); + while(!getcwd(cwdbuf, cwdlen)) + { + free(cwdbuf); + cwdbuf = NULL; + if(errno != ERANGE) + break; + cwdlen <<= 1; + cwdbuf = static_cast(malloc(cwdlen)); + } + if(!cwdbuf) + DirectorySearch(".", ext, &results); + else + { + DirectorySearch(cwdbuf, ext, &results); + free(cwdbuf); + cwdbuf = NULL; + } + } + + // Search local data dir + if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0') + { + alstr_copy_cstr(&path, str); + if(VECTOR_BACK(path) != '/') + alstr_append_char(&path, '/'); + alstr_append_cstr(&path, subdir); + DirectorySearch(alstr_get_cstr(path), ext, &results); + } + else if((str=getenv("HOME")) != NULL && str[0] != '\0') + { + alstr_copy_cstr(&path, str); + if(VECTOR_BACK(path) == '/') + { + VECTOR_POP_BACK(path); + *VECTOR_END(path) = 0; + } + alstr_append_cstr(&path, "/.local/share/"); + alstr_append_cstr(&path, subdir); + DirectorySearch(alstr_get_cstr(path), ext, &results); + } + + // Search global data dirs + 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') + { + next = strchr(str, ':'); + if(!next) + alstr_copy_cstr(&path, str); + else + { + alstr_copy_range(&path, str, next); + ++next; + } + if(!alstr_empty(path)) + { + if(VECTOR_BACK(path) != '/') + alstr_append_char(&path, '/'); + alstr_append_cstr(&path, subdir); + + DirectorySearch(alstr_get_cstr(path), ext, &results); + } + } + + alstr_reset(&path); + } + + ATOMIC_STORE_SEQ(&search_lock, 0u); + + return results; +} + +#endif + + +void SetRTPriority(void) +{ + ALboolean failed = AL_FALSE; + +#ifdef _WIN32 + if(RTPrioLevel > 0) + failed = !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); +#elif defined(HAVE_PTHREAD_SETSCHEDPARAM) && !defined(__OpenBSD__) + if(RTPrioLevel > 0) + { + struct sched_param param; + /* Use the minimum real-time priority possible for now (on Linux this + * should be 1 for SCHED_RR) */ + param.sched_priority = sched_get_priority_min(SCHED_RR); + failed = !!pthread_setschedparam(pthread_self(), SCHED_RR, ¶m); + } +#else + /* Real-time priority not available */ + failed = (RTPrioLevel>0); +#endif + if(failed) + ERR("Failed to set priority level for thread\n"); +} + + +void alstr_clear(al_string *str) +{ + if(!alstr_empty(*str)) + { + /* 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_RESIZE(*str, 0, 1); + VECTOR_ELEM(*str, 0) = 0; + } +} + +static inline int alstr_compare(const al_string_char_type *str1, size_t str1len, + const al_string_char_type *str2, size_t str2len) +{ + size_t complen = (str1len < str2len) ? str1len : str2len; + int ret = memcmp(str1, str2, complen); + if(ret == 0) + { + if(str1len > str2len) return 1; + if(str1len < str2len) return -1; + } + return ret; +} +int alstr_cmp(const_al_string str1, const_al_string str2) +{ + return alstr_compare(&VECTOR_FRONT(str1), alstr_length(str1), + &VECTOR_FRONT(str2), alstr_length(str2)); +} +int alstr_cmp_cstr(const_al_string str1, const al_string_char_type *str2) +{ + return alstr_compare(&VECTOR_FRONT(str1), alstr_length(str1), + str2, strlen(str2)); +} + +void alstr_copy(al_string *str, const_al_string from) +{ + size_t len = alstr_length(from); + size_t i; + + VECTOR_RESIZE(*str, len, len+1); + for(i = 0;i < len;i++) + VECTOR_ELEM(*str, i) = VECTOR_ELEM(from, i); + VECTOR_ELEM(*str, i) = 0; +} + +void alstr_copy_cstr(al_string *str, const al_string_char_type *from) +{ + size_t len = strlen(from); + size_t i; + + VECTOR_RESIZE(*str, len, len+1); + for(i = 0;i < len;i++) + VECTOR_ELEM(*str, i) = from[i]; + VECTOR_ELEM(*str, i) = 0; +} + +void alstr_copy_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to) +{ + size_t len = to - from; + size_t i; + + VECTOR_RESIZE(*str, len, len+1); + for(i = 0;i < len;i++) + VECTOR_ELEM(*str, i) = from[i]; + VECTOR_ELEM(*str, i) = 0; +} + +void alstr_append_char(al_string *str, const al_string_char_type c) +{ + size_t len = alstr_length(*str); + VECTOR_RESIZE(*str, len+1, len+2); + VECTOR_BACK(*str) = c; + VECTOR_ELEM(*str, len+1) = 0; +} + +void alstr_append_cstr(al_string *str, const al_string_char_type *from) +{ + size_t len = strlen(from); + if(len != 0) + { + size_t base = alstr_length(*str); + size_t i; + + VECTOR_RESIZE(*str, base+len, base+len+1); + for(i = 0;i < len;i++) + VECTOR_ELEM(*str, base+i) = from[i]; + VECTOR_ELEM(*str, base+i) = 0; + } +} + +void alstr_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to) +{ + size_t len = to - from; + if(len != 0) + { + size_t base = alstr_length(*str); + size_t i; + + VECTOR_RESIZE(*str, base+len, base+len+1); + for(i = 0;i < len;i++) + VECTOR_ELEM(*str, base+i) = from[i]; + VECTOR_ELEM(*str, base+i) = 0; + } +} + +#ifdef _WIN32 +void alstr_copy_wcstr(al_string *str, const wchar_t *from) +{ + int len; + if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0) + { + VECTOR_RESIZE(*str, len-1, len); + WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_FRONT(*str), len, NULL, NULL); + VECTOR_ELEM(*str, len-1) = 0; + } +} + +void alstr_append_wcstr(al_string *str, const wchar_t *from) +{ + int len; + if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0) + { + size_t base = alstr_length(*str); + VECTOR_RESIZE(*str, base+len-1, base+len); + WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_ELEM(*str, base), len, NULL, NULL); + VECTOR_ELEM(*str, base+len-1) = 0; + } +} + +void alstr_copy_wrange(al_string *str, const wchar_t *from, const wchar_t *to) +{ + int len; + if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), NULL, 0, NULL, NULL)) > 0) + { + VECTOR_RESIZE(*str, len, len+1); + WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_FRONT(*str), len+1, NULL, NULL); + VECTOR_ELEM(*str, len) = 0; + } +} + +void alstr_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to) +{ + int len; + if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), NULL, 0, NULL, NULL)) > 0) + { + size_t base = alstr_length(*str); + VECTOR_RESIZE(*str, base+len, base+len+1); + WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_ELEM(*str, base), len+1, NULL, NULL); + VECTOR_ELEM(*str, base+len) = 0; + } +} +#endif diff --git a/CMakeLists.txt b/CMakeLists.txt index 06a64f88..ff8d6149 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -869,7 +869,7 @@ SET(ALC_OBJS Alc/filters/nfc.h Alc/filters/splitter.cpp Alc/filters/splitter.h - Alc/helpers.c + Alc/helpers.cpp Alc/alstring.h Alc/compat.h Alc/cpu_caps.h -- cgit v1.2.3 From 4793e5c4ae3472b1f931ec48f913614710a6d12c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Nov 2018 16:09:24 -0800 Subject: Use C++ for GetProcBinary --- Alc/alconfig.cpp | 28 ++++----- Alc/backends/pulseaudio.cpp | 9 +-- Alc/compat.h | 7 ++- Alc/helpers.cpp | 140 ++++++++++++++++---------------------------- 4 files changed, 69 insertions(+), 115 deletions(-) diff --git a/Alc/alconfig.cpp b/Alc/alconfig.cpp index 29593205..fedb6703 100644 --- a/Alc/alconfig.cpp +++ b/Alc/alconfig.cpp @@ -299,13 +299,12 @@ void ReadALConfig(void) LoadConfigFromFile(f); } - al_string ppath = AL_STRING_INIT_STATIC(); - GetProcBinary(&ppath, nullptr); - if(!alstr_empty(ppath)) + PathNamePair ppath = GetProcBinary(); + if(!ppath.path.empty()) { - alstr_append_cstr(&ppath, "\\alsoft.ini"); - TRACE("Loading config %s...\n", alstr_get_cstr(ppath)); - al::ifstream f{alstr_get_cstr(ppath)}; + ppath.path += "\\alsoft.ini"; + TRACE("Loading config %s...\n", ppath.path.c_str()); + al::ifstream f{ppath.path.c_str()}; if(f.is_open()) LoadConfigFromFile(f); } @@ -320,8 +319,6 @@ void ReadALConfig(void) if(f.is_open()) LoadConfigFromFile(f); } - - alstr_reset(&ppath); } #else void ReadALConfig(void) @@ -425,15 +422,14 @@ void ReadALConfig(void) LoadConfigFromFile(f); } - al_string ppath = AL_STRING_INIT_STATIC(); - GetProcBinary(&ppath, nullptr); - if(!alstr_empty(ppath)) + PathNamePair ppath = GetProcBinary(); + if(!ppath.path.empty()) { - if(VECTOR_BACK(ppath) != '/') alstr_append_cstr(&ppath, "/alsoft.conf"); - else alstr_append_cstr(&ppath, "alsoft.conf"); + if(ppath.path.back() != '/') ppath.path += "/alsoft.conf"; + else ppath.path += "alsoft.conf"; - TRACE("Loading config %s...\n", alstr_get_cstr(ppath)); - al::ifstream f{alstr_get_cstr(ppath)}; + TRACE("Loading config %s...\n", ppath.path.c_str()); + al::ifstream f{ppath.path}; if(f.is_open()) LoadConfigFromFile(f); } @@ -445,8 +441,6 @@ void ReadALConfig(void) if(f.is_open()) LoadConfigFromFile(f); } - - alstr_reset(&ppath); } #endif diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index e2845032..2a2de2a6 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -406,17 +406,15 @@ void wait_for_operation(pa_operation *op, pa_threaded_mainloop *loop) pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent) { const char *name{"OpenAL Soft"}; - al_string binname{AL_STRING_INIT_STATIC()}; - GetProcBinary(nullptr, &binname); - if(!alstr_empty(binname)) - name = alstr_get_cstr(binname); + PathNamePair binname = GetProcBinary(); + if(!binname.fname.empty()) + name = binname.fname.c_str(); pa_context *context{pa_context_new(pa_threaded_mainloop_get_api(loop), name)}; if(!context) { ERR("pa_context_new() failed\n"); - alstr_reset(&binname); return nullptr; } @@ -448,7 +446,6 @@ pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent) context = nullptr; } - alstr_reset(&binname); return context; } diff --git a/Alc/compat.h b/Alc/compat.h index 15eca1d4..31c84d48 100644 --- a/Alc/compat.h +++ b/Alc/compat.h @@ -237,8 +237,6 @@ extern "C" { #endif -void GetProcBinary(al_string *path, al_string *fname); - #ifdef HAVE_DYNLOAD void *LoadLib(const char *name); void CloseLib(void *handle); @@ -247,6 +245,11 @@ void *GetSymbol(void *handle, const char *name); #ifdef __cplusplus } /* extern "C" */ + +#include + +struct PathNamePair { std::string path, fname; }; +PathNamePair GetProcBinary(void); #endif #endif /* AL_COMPAT_H */ diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index abd010e6..dede9e06 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -109,6 +109,10 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x #include #endif +#include +#include +#include + #include "alMain.h" #include "alu.h" #include "cpu_caps.h" @@ -310,64 +314,37 @@ static int StringSortCompare(const void *str1, const void *str2) #ifdef _WIN32 -static WCHAR *strrchrW(WCHAR *str, WCHAR ch) +PathNamePair GetProcBinary() { - WCHAR *ret = NULL; - while(*str) - { - if(*str == ch) - ret = str; - ++str; - } - return ret; -} + PathNamePair ret; -void GetProcBinary(al_string *path, al_string *fname) -{ - WCHAR *pathname, *sep; - DWORD pathlen; + std::vector fullpath(256); DWORD len; - - pathlen = 256; - pathname = static_cast(malloc(pathlen * sizeof(pathname[0]))); - while(pathlen > 0 && (len=GetModuleFileNameW(NULL, pathname, pathlen)) == pathlen) - { - free(pathname); - pathlen <<= 1; - pathname = static_cast(malloc(pathlen * sizeof(pathname[0]))); - } + while((len=GetModuleFileNameW(nullptr, fullpath.data(), fullpath.size())) == fullpath.size()) + fullpath.resize(fullpath.size() << 1); if(len == 0) { - free(pathname); ERR("Failed to get process name: error %lu\n", GetLastError()); - return; + return ret; } - pathname[len] = 0; - if((sep=strrchrW(pathname, '\\')) != NULL) - { - WCHAR *sep2 = strrchrW(sep+1, '/'); - if(sep2) sep = sep2; - } - else - sep = strrchrW(pathname, '/'); + fullpath.resize(len); + if(fullpath.back() != 0) + fullpath.push_back(0); - if(sep) + auto sep = std::find(fullpath.rbegin()+1, fullpath.rend(), '\\'); + sep = std::find(fullpath.rbegin()+1, sep, '/'); + if(sep != fullpath.rend()) { - if(path) alstr_copy_wrange(path, pathname, sep); - if(fname) alstr_copy_wcstr(fname, sep+1); + *sep = 0; + ret.fname = wstr_to_utf8(&*sep + 1); + ret.path = wstr_to_utf8(fullpath.data()); } else - { - if(path) alstr_clear(path); - if(fname) alstr_copy_wcstr(fname, pathname); - } - free(pathname); + ret.fname = wstr_to_utf8(fullpath.data()); - if(path && fname) - TRACE("Got: %s, %s\n", alstr_get_cstr(*path), alstr_get_cstr(*fname)); - else if(path) TRACE("Got path: %s\n", alstr_get_cstr(*path)); - else if(fname) TRACE("Got filename: %s\n", alstr_get_cstr(*fname)); + TRACE("Got: %s, %s\n", ret.path.c_str(), ret.fname.c_str()); + return ret; } @@ -562,24 +539,25 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) #else -void GetProcBinary(al_string *path, al_string *fname) +PathNamePair GetProcBinary() { - char *pathname = NULL; - size_t pathlen; + PathNamePair ret; + std::vector pathname; #ifdef __FreeBSD__ + size_t pathlen; int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; if(sysctl(mib, 4, NULL, &pathlen, NULL, 0) == -1) WARN("Failed to sysctl kern.proc.pathname: %s\n", strerror(errno)); else { - pathname = malloc(pathlen + 1); - sysctl(mib, 4, (void*)pathname, &pathlen, NULL, 0); + pathname.resize(pathlen + 1); + sysctl(mib, 4, pathname.data(), &pathlen, nullptr, 0); pathname[pathlen] = 0; } #endif #ifdef HAVE_PROC_PIDPATH - if(!pathname) + if(pathname.empty()) { const pid_t pid = getpid(); char procpath[PROC_PIDPATHINFO_MAXSIZE]; @@ -587,78 +565,60 @@ void GetProcBinary(al_string *path, al_string *fname) ret = proc_pidpath(pid, procpath, sizeof(procpath)); if(ret < 1) - { WARN("proc_pidpath(%d, ...) failed: %s\n", pid, strerror(errno)); - free(pathname); - pathname = NULL; - } else - { - pathlen = strlen(procpath); - pathname = strdup(procpath); - } + pathname.append(procpath, procpath+strlen(procpath)); } #endif - if(!pathname) + if(pathname.empty()) { - const char *selfname; - ssize_t len; - - pathlen = 256; - pathname = static_cast(malloc(pathlen)); + pathname.resize(256); - selfname = "/proc/self/exe"; - len = readlink(selfname, pathname, pathlen); + const char *selfname{"/proc/self/exe"}; + ssize_t len{readlink(selfname, pathname.data(), pathname.size())}; if(len == -1 && errno == ENOENT) { selfname = "/proc/self/file"; - len = readlink(selfname, pathname, pathlen); + len = readlink(selfname, pathname.data(), pathname.size()); } if(len == -1 && errno == ENOENT) { selfname = "/proc/curproc/exe"; - len = readlink(selfname, pathname, pathlen); + len = readlink(selfname, pathname.data(), pathname.size()); } if(len == -1 && errno == ENOENT) { selfname = "/proc/curproc/file"; - len = readlink(selfname, pathname, pathlen); + len = readlink(selfname, pathname.data(), pathname.size()); } - while(len > 0 && (size_t)len == pathlen) + while(len > 0 && (size_t)len == pathname.size()) { - free(pathname); - pathlen <<= 1; - pathname = static_cast(malloc(pathlen)); - len = readlink(selfname, pathname, pathlen); + pathname.resize(pathname.size() << 1); + len = readlink(selfname, pathname.data(), pathname.size()); } if(len <= 0) { - free(pathname); WARN("Failed to readlink %s: %s\n", selfname, strerror(errno)); - return; + return ret; } pathname[len] = 0; } + while(!pathname.empty() && pathname.back() == 0) + pathname.pop_back(); - char *sep = strrchr(pathname, '/'); - if(sep) + auto sep = std::find(pathname.crbegin(), pathname.crend(), '/'); + if(sep != pathname.crend()) { - if(path) alstr_copy_range(path, pathname, sep); - if(fname) alstr_copy_cstr(fname, sep+1); + ret.path = std::string(pathname.cbegin(), sep.base()-1); + ret.fname = std::string(sep.base(), pathname.cend()); } else - { - if(path) alstr_clear(path); - if(fname) alstr_copy_cstr(fname, pathname); - } - free(pathname); + ret.fname = std::string(pathname.cbegin(), pathname.cend()); - if(path && fname) - TRACE("Got: %s, %s\n", alstr_get_cstr(*path), alstr_get_cstr(*fname)); - else if(path) TRACE("Got path: %s\n", alstr_get_cstr(*path)); - else if(fname) TRACE("Got filename: %s\n", alstr_get_cstr(*fname)); + TRACE("Got: %s, %s\n", ret.path.c_str(), ret.fname.c_str()); + return ret; } -- cgit v1.2.3 From 51ed335833dab0cee5fc325e3a5c1968da934a49 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Nov 2018 19:17:40 -0800 Subject: Use C++ more with helpers.cpp --- Alc/helpers.cpp | 365 +++++++++++++++++----------------------------- Alc/hrtf.cpp | 84 ++++------- OpenAL32/Include/alMain.h | 8 +- 3 files changed, 171 insertions(+), 286 deletions(-) diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index dede9e06..bfb458b7 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -109,6 +109,7 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x #include #endif +#include #include #include #include @@ -213,7 +214,7 @@ void FillCPUCaps(int capfilter) al_string features = AL_STRING_INIT_STATIC(); char buf[256]; - while(fgets(buf, sizeof(buf), file) != NULL) + while(fgets(buf, sizeof(buf), file) != nullptr) { if(strncmp(buf, "Features\t:", 10) != 0) continue; @@ -221,14 +222,14 @@ void FillCPUCaps(int capfilter) alstr_copy_cstr(&features, buf+10); while(VECTOR_BACK(features) != '\n') { - if(fgets(buf, sizeof(buf), file) == NULL) + if(fgets(buf, sizeof(buf), file) == nullptr) break; alstr_append_cstr(&features, buf); } break; } fclose(file); - file = NULL; + file = nullptr; if(!alstr_empty(features)) { @@ -236,7 +237,7 @@ void FillCPUCaps(int capfilter) while(isspace(str[0])) ++str; TRACE("Got features string:%s\n", str); - while((str=strstr(str, "neon")) != NULL) + while((str=strstr(str, "neon")) != nullptr) { if(isspace(*(str-1)) && (str[4] == 0 || isspace(str[4]))) { @@ -297,8 +298,8 @@ void RestoreFPUMode(const FPUCtl *ctl) #elif defined(HAVE___CONTROL87_2) int mode; - __control87_2(ctl->state, _MCW_DN, &mode, NULL); - __control87_2(ctl->sse_state, _MCW_DN, NULL, &mode); + __control87_2(ctl->state, _MCW_DN, &mode, nullptr); + __control87_2(ctl->sse_state, _MCW_DN, nullptr, &mode); #elif defined(HAVE__CONTROLFP) @@ -307,11 +308,6 @@ void RestoreFPUMode(const FPUCtl *ctl) } -static int StringSortCompare(const void *str1, const void *str2) -{ - return alstr_cmp(*(const_al_string*)str1, *(const_al_string*)str2); -} - #ifdef _WIN32 PathNamePair GetProcBinary() @@ -348,42 +344,16 @@ PathNamePair GetProcBinary() } -static WCHAR *FromUTF8(const char *str) -{ - WCHAR *out = NULL; - int len; - - if((len=MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)) > 0) - { - out = static_cast(calloc(sizeof(WCHAR), len)); - MultiByteToWideChar(CP_UTF8, 0, str, -1, out, len); - } - return out; -} - - void *LoadLib(const char *name) { - HANDLE hdl = NULL; - WCHAR *wname; - - wname = FromUTF8(name); - if(!wname) - ERR("Failed to convert UTF-8 filename: \"%s\"\n", name); - else - { - hdl = LoadLibraryW(wname); - free(wname); - } - return hdl; + std::wstring wname{utf8_to_wstr(name)}; + return LoadLibraryW(wname.c_str()); } void CloseLib(void *handle) -{ FreeLibrary(reinterpret_cast(handle)); } +{ FreeLibrary(static_cast(handle)); } void *GetSymbol(void *handle, const char *name) { - void *ret; - - ret = reinterpret_cast(GetProcAddress(reinterpret_cast(handle), name)); + void *ret{reinterpret_cast(GetProcAddress(static_cast(handle), name))}; if(!ret) ERR("Failed to load %s\n", name); return ret; } @@ -392,23 +362,15 @@ void *GetSymbol(void *handle, const char *name) void al_print(const char *type, const char *func, const char *fmt, ...) { char str[1024]; - WCHAR *wstr; va_list ap; va_start(ap, fmt); vsnprintf(str, sizeof(str), fmt, ap); va_end(ap); - str[sizeof(str)-1] = 0; - wstr = FromUTF8(str); - if(!wstr) - fprintf(LogFile, "AL lib: %s %s: %s", type, func, str); - else - { - fprintf(LogFile, "AL lib: %s %s: %ls", type, func, wstr); - free(wstr); - wstr = NULL; - } + + std::wstring wstr{utf8_to_wstr(str)}; + fprintf(LogFile, "AL lib: %s %s: %ls", type, func, wstr.c_str()); fflush(LogFile); } @@ -416,124 +378,93 @@ void al_print(const char *type, const char *func, const char *fmt, ...) static inline int is_slash(int c) { return (c == '\\' || c == '/'); } -static void DirectorySearch(const char *path, const char *ext, vector_al_string *results) +static void DirectorySearch(const char *path, const char *ext, std::vector *const results) { - al_string pathstr = AL_STRING_INIT_STATIC(); - WIN32_FIND_DATAW fdata; - WCHAR *wpath; - HANDLE hdl; - - alstr_copy_cstr(&pathstr, path); - alstr_append_cstr(&pathstr, "\\*"); - alstr_append_cstr(&pathstr, ext); - - TRACE("Searching %s\n", alstr_get_cstr(pathstr)); - - wpath = FromUTF8(alstr_get_cstr(pathstr)); + std::string pathstr{path}; + pathstr += "\\*"; + pathstr += ext; + TRACE("Searching %s\n", pathstr.c_str()); - hdl = FindFirstFileW(wpath, &fdata); + std::wstring wpath{utf8_to_wstr(pathstr.c_str())}; + WIN32_FIND_DATAW fdata; + HANDLE hdl{FindFirstFileW(wpath.c_str(), &fdata)}; if(hdl != INVALID_HANDLE_VALUE) { - size_t base = VECTOR_SIZE(*results); + size_t base = results->size(); do { - al_string str = AL_STRING_INIT_STATIC(); - alstr_copy_cstr(&str, path); - alstr_append_char(&str, '\\'); - alstr_append_wcstr(&str, fdata.cFileName); - TRACE("Got result %s\n", alstr_get_cstr(str)); - VECTOR_PUSH_BACK(*results, str); + results->emplace_back(); + std::string &str = results->back(); + str = path; + str += '\\'; + str += wstr_to_utf8(fdata.cFileName); + TRACE("Got result %s\n", str.c_str()); } while(FindNextFileW(hdl, &fdata)); FindClose(hdl); - if(VECTOR_SIZE(*results) > base) - qsort(VECTOR_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, - sizeof(VECTOR_FRONT(*results)), StringSortCompare); + std::sort(results->begin()+base, results->end()); } - - free(wpath); - alstr_reset(&pathstr); } -vector_al_string SearchDataFiles(const char *ext, const char *subdir) +std::vector SearchDataFiles(const char *ext, const char *subdir) { - static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA }; - static RefCount search_lock; - vector_al_string results = VECTOR_INIT_STATIC(); - size_t i; + static std::atomic search_lock{AL_FALSE}; - while(ATOMIC_EXCHANGE_SEQ(&search_lock, 1u) == 1u) + while(search_lock.exchange(AL_TRUE) == AL_TRUE) althrd_yield(); /* If the path is absolute, use it directly. */ + std::vector results; if(isalpha(subdir[0]) && subdir[1] == ':' && is_slash(subdir[2])) { - al_string path = AL_STRING_INIT_STATIC(); - alstr_copy_cstr(&path, subdir); -#define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) - VECTOR_FOR_EACH(char, path, FIX_SLASH); -#undef FIX_SLASH - - DirectorySearch(alstr_get_cstr(path), ext, &results); - - alstr_reset(&path); + std::string path{subdir}; + std::replace(path.begin(), path.end(), '/', '\\'); + DirectorySearch(path.c_str(), ext, &results); } else if(subdir[0] == '\\' && subdir[1] == '\\' && subdir[2] == '?' && subdir[3] == '\\') DirectorySearch(subdir, ext, &results); else { - al_string path = AL_STRING_INIT_STATIC(); - WCHAR *cwdbuf; + std::string path; /* Search the app-local directory. */ - if((cwdbuf=_wgetenv(L"ALSOFT_LOCAL_PATH")) && *cwdbuf != '\0') + WCHAR *cwdbuf{_wgetenv(L"ALSOFT_LOCAL_PATH")}; + if(cwdbuf && *cwdbuf != '\0') { - alstr_copy_wcstr(&path, cwdbuf); - if(is_slash(VECTOR_BACK(path))) - { - VECTOR_POP_BACK(path); - *VECTOR_END(path) = 0; - } + path = wstr_to_utf8(cwdbuf); + if(is_slash(path.back())) + path.pop_back(); } - else if(!(cwdbuf=_wgetcwd(NULL, 0))) - alstr_copy_cstr(&path, "."); + else if(!(cwdbuf=_wgetcwd(nullptr, 0))) + path = "."; else { - alstr_copy_wcstr(&path, cwdbuf); - if(is_slash(VECTOR_BACK(path))) - { - VECTOR_POP_BACK(path); - *VECTOR_END(path) = 0; - } + path = wstr_to_utf8(cwdbuf); + if(is_slash(path.back())) + path.pop_back(); free(cwdbuf); } -#define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) - VECTOR_FOR_EACH(char, path, FIX_SLASH); -#undef FIX_SLASH - DirectorySearch(alstr_get_cstr(path), ext, &results); + std::replace(path.begin(), path.end(), '/', '\\'); + DirectorySearch(path.c_str(), ext, &results); /* Search the local and global data dirs. */ - for(i = 0;i < COUNTOF(ids);i++) + static constexpr int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA }; + for(int id : ids) { WCHAR buffer[MAX_PATH]; - if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) != FALSE) - { - alstr_copy_wcstr(&path, buffer); - if(!is_slash(VECTOR_BACK(path))) - alstr_append_char(&path, '\\'); - alstr_append_cstr(&path, subdir); -#define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) - VECTOR_FOR_EACH(char, path, FIX_SLASH); -#undef FIX_SLASH - - DirectorySearch(alstr_get_cstr(path), ext, &results); - } - } + if(SHGetSpecialFolderPathW(nullptr, buffer, id, FALSE) == FALSE) + continue; - alstr_reset(&path); - } + path = wstr_to_utf8(buffer); + if(!is_slash(path.back())) + path += '\\'; + path += subdir; + std::replace(path.begin(), path.end(), '/', '\\'); - ATOMIC_STORE_SEQ(&search_lock, 0u); + DirectorySearch(path.c_str(), ext, &results); + } + } + search_lock.store(AL_FALSE); return results; } @@ -547,7 +478,7 @@ PathNamePair GetProcBinary() #ifdef __FreeBSD__ size_t pathlen; int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; - if(sysctl(mib, 4, NULL, &pathlen, NULL, 0) == -1) + if(sysctl(mib, 4, nullptr, &pathlen, nullptr, 0) == -1) WARN("Failed to sysctl kern.proc.pathname: %s\n", strerror(errno)); else { @@ -626,28 +557,23 @@ PathNamePair GetProcBinary() void *LoadLib(const char *name) { - const char *err; - void *handle; - dlerror(); - handle = dlopen(name, RTLD_NOW); - if((err=dlerror()) != NULL) - handle = NULL; + void *handle{dlopen(name, RTLD_NOW)}; + const char *err{dlerror()}; + if(err) handle = nullptr; return handle; } void CloseLib(void *handle) { dlclose(handle); } void *GetSymbol(void *handle, const char *name) { - const char *err; - void *sym; - dlerror(); - sym = dlsym(handle, name); - if((err=dlerror()) != NULL) + void *sym{dlsym(handle, name)}; + const char *err{dlerror()}; + if(err) { WARN("Failed to load %s: %s\n", name, err); - sym = NULL; + sym = nullptr; } return sym; } @@ -667,139 +593,122 @@ void al_print(const char *type, const char *func, const char *fmt, ...) } -static void DirectorySearch(const char *path, const char *ext, vector_al_string *results) +static void DirectorySearch(const char *path, const char *ext, std::vector *const results) { - size_t extlen = strlen(ext); - DIR *dir; - TRACE("Searching %s for *%s\n", path, ext); - dir = opendir(path); - if(dir != NULL) + DIR *dir{opendir(path)}; + if(dir != nullptr) { - size_t base = VECTOR_SIZE(*results); + const size_t extlen = strlen(ext); + size_t base = results->size(); + struct dirent *dirent; - while((dirent=readdir(dir)) != NULL) + while((dirent=readdir(dir)) != nullptr) { - al_string str; - size_t len; if(strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) continue; - len = strlen(dirent->d_name); - if(len <= extlen) - continue; + size_t len{strlen(dirent->d_name)}; + if(len <= extlen) continue; if(strcasecmp(dirent->d_name+len-extlen, ext) != 0) continue; - AL_STRING_INIT(str); - alstr_copy_cstr(&str, path); - if(VECTOR_BACK(str) != '/') - alstr_append_char(&str, '/'); - alstr_append_cstr(&str, dirent->d_name); - TRACE("Got result %s\n", alstr_get_cstr(str)); - VECTOR_PUSH_BACK(*results, str); + results->emplace_back(); + std::string &str = results->back(); + str = path; + if(str.back() != '/') + str.push_back('/'); + str += dirent->d_name; + TRACE("Got result %s\n", str.c_str()); } closedir(dir); - if(VECTOR_SIZE(*results) > base) - qsort(VECTOR_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, - sizeof(VECTOR_FRONT(*results)), StringSortCompare); + std::sort(results->begin()+base, results->end()); } } -vector_al_string SearchDataFiles(const char *ext, const char *subdir) +std::vector SearchDataFiles(const char *ext, const char *subdir) { - static RefCount search_lock; - vector_al_string results = VECTOR_INIT_STATIC(); + static std::atomic search_lock{AL_FALSE}; - while(ATOMIC_EXCHANGE_SEQ(&search_lock, 1u) == 1u) + while(search_lock.exchange(AL_TRUE) == AL_TRUE) althrd_yield(); + std::vector results; if(subdir[0] == '/') DirectorySearch(subdir, ext, &results); else { - al_string path = AL_STRING_INIT_STATIC(); - const char *str, *next; - /* Search the app-local directory. */ - if((str=getenv("ALSOFT_LOCAL_PATH")) && *str != '\0') + const char *str{getenv("ALSOFT_LOCAL_PATH")}; + if(str && *str != '\0') DirectorySearch(str, ext, &results); else { - size_t cwdlen = 256; - char *cwdbuf = static_cast(malloc(cwdlen)); - while(!getcwd(cwdbuf, cwdlen)) + std::vector cwdbuf(256); + while(!getcwd(cwdbuf.data(), cwdbuf.size())) { - free(cwdbuf); - cwdbuf = NULL; if(errno != ERANGE) + { + cwdbuf.clear(); break; - cwdlen <<= 1; - cwdbuf = static_cast(malloc(cwdlen)); + } + cwdbuf.resize(cwdbuf.size() << 1); } - if(!cwdbuf) + if(cwdbuf.empty()) DirectorySearch(".", ext, &results); else { - DirectorySearch(cwdbuf, ext, &results); - free(cwdbuf); - cwdbuf = NULL; + DirectorySearch(cwdbuf.data(), ext, &results); + cwdbuf.clear(); } } // Search local data dir - if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0') + if((str=getenv("XDG_DATA_HOME")) != nullptr && str[0] != '\0') { - alstr_copy_cstr(&path, str); - if(VECTOR_BACK(path) != '/') - alstr_append_char(&path, '/'); - alstr_append_cstr(&path, subdir); - DirectorySearch(alstr_get_cstr(path), ext, &results); + std::string path{str}; + if(path.back() != '/') + path += '/'; + path += subdir; + DirectorySearch(path.c_str(), ext, &results); } - else if((str=getenv("HOME")) != NULL && str[0] != '\0') + else if((str=getenv("HOME")) != nullptr && str[0] != '\0') { - alstr_copy_cstr(&path, str); - if(VECTOR_BACK(path) == '/') - { - VECTOR_POP_BACK(path); - *VECTOR_END(path) = 0; - } - alstr_append_cstr(&path, "/.local/share/"); - alstr_append_cstr(&path, subdir); - DirectorySearch(alstr_get_cstr(path), ext, &results); + std::string path{str}; + if(path.back() == '/') + path.pop_back(); + path += "/.local/share/"; + path += subdir; + DirectorySearch(path.c_str(), ext, &results); } // Search global data dirs - if((str=getenv("XDG_DATA_DIRS")) == NULL || str[0] == '\0') + if((str=getenv("XDG_DATA_DIRS")) == nullptr || str[0] == '\0') str = "/usr/local/share/:/usr/share/"; - next = str; - while((str=next) != NULL && str[0] != '\0') + const char *next{str}; + while((str=next) != nullptr && str[0] != '\0') { next = strchr(str, ':'); + + std::string path; if(!next) - alstr_copy_cstr(&path, str); + path = str; else + path.append(str, next++); + if(!path.empty()) { - alstr_copy_range(&path, str, next); - ++next; - } - if(!alstr_empty(path)) - { - if(VECTOR_BACK(path) != '/') - alstr_append_char(&path, '/'); - alstr_append_cstr(&path, subdir); + if(path.back() != '/') + path += '/'; + path += subdir; - DirectorySearch(alstr_get_cstr(path), ext, &results); + DirectorySearch(path.c_str(), ext, &results); } } - - alstr_reset(&path); } - ATOMIC_STORE_SEQ(&search_lock, 0u); - + search_lock.store(AL_FALSE); return results; } @@ -942,10 +851,10 @@ void alstr_append_range(al_string *str, const al_string_char_type *from, const a void alstr_copy_wcstr(al_string *str, const wchar_t *from) { int len; - if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0) + if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, nullptr, 0, nullptr, nullptr)) > 0) { VECTOR_RESIZE(*str, len-1, len); - WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_FRONT(*str), len, NULL, NULL); + WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_FRONT(*str), len, nullptr, nullptr); VECTOR_ELEM(*str, len-1) = 0; } } @@ -953,11 +862,11 @@ void alstr_copy_wcstr(al_string *str, const wchar_t *from) void alstr_append_wcstr(al_string *str, const wchar_t *from) { int len; - if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0) + if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, nullptr, 0, nullptr, nullptr)) > 0) { size_t base = alstr_length(*str); VECTOR_RESIZE(*str, base+len-1, base+len); - WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_ELEM(*str, base), len, NULL, NULL); + WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_ELEM(*str, base), len, nullptr, nullptr); VECTOR_ELEM(*str, base+len-1) = 0; } } @@ -965,10 +874,10 @@ void alstr_append_wcstr(al_string *str, const wchar_t *from) void alstr_copy_wrange(al_string *str, const wchar_t *from, const wchar_t *to) { int len; - if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), NULL, 0, NULL, NULL)) > 0) + if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), nullptr, 0, nullptr, nullptr)) > 0) { VECTOR_RESIZE(*str, len, len+1); - WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_FRONT(*str), len+1, NULL, NULL); + WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_FRONT(*str), len+1, nullptr, nullptr); VECTOR_ELEM(*str, len) = 0; } } @@ -976,11 +885,11 @@ void alstr_copy_wrange(al_string *str, const wchar_t *from, const wchar_t *to) void alstr_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to) { int len; - if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), NULL, 0, NULL, NULL)) > 0) + if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), nullptr, 0, nullptr, nullptr)) > 0) { size_t base = alstr_length(*str); VECTOR_RESIZE(*str, base+len, base+len+1); - WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_ELEM(*str, base), len+1, NULL, NULL); + WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_ELEM(*str, base), len+1, nullptr, nullptr); VECTOR_ELEM(*str, base+len) = 0; } } diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index b2dc1ec8..9b57ede7 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -944,13 +944,13 @@ struct Hrtf *LoadHrtf02(std::istream &data, const char *filename) } -void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename) +void AddFileEntry(vector_EnumeratedHrtf *list, const std::string &filename) { /* Check if this file has already been loaded globally. */ HrtfEntry *loaded_entry{LoadedHrtfs}; while(loaded_entry) { - if(alstr_cmp_cstr(filename, loaded_entry->filename) == 0) + if(filename == loaded_entry->filename) { const EnumeratedHrtf *iter; /* Check if this entry has already been added to the list. */ @@ -959,7 +959,7 @@ void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename) #undef MATCH_ENTRY if(iter != VECTOR_END(*list)) { - TRACE("Skipping duplicate file entry %s\n", alstr_get_cstr(filename)); + TRACE("Skipping duplicate file entry %s\n", filename.c_str()); return; } @@ -970,34 +970,34 @@ void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename) if(!loaded_entry) { - TRACE("Got new file \"%s\"\n", alstr_get_cstr(filename)); + TRACE("Got new file \"%s\"\n", filename.c_str()); loaded_entry = static_cast(al_calloc(DEF_ALIGN, - FAM_SIZE(struct HrtfEntry, filename, alstr_length(filename)+1) + FAM_SIZE(struct HrtfEntry, filename, filename.length()+1) )); loaded_entry->next = LoadedHrtfs; loaded_entry->handle = nullptr; - strcpy(loaded_entry->filename, alstr_get_cstr(filename)); + strcpy(loaded_entry->filename, filename.c_str()); LoadedHrtfs = loaded_entry; } /* TODO: Get a human-readable name from the HRTF data (possibly coming in a * format update). */ - const char *name{strrchr(alstr_get_cstr(filename), '/')}; - if(!name) name = strrchr(alstr_get_cstr(filename), '\\'); - if(!name) name = alstr_get_cstr(filename); - else ++name; + size_t namepos = filename.find_last_of('/')+1; + if(!namepos) namepos = filename.find_last_of('\\')+1; - const char *ext{strrchr(name, '.')}; + size_t extpos{filename.find_last_of('.')}; + if(extpos <= namepos) extpos = std::string::npos; EnumeratedHrtf entry = { AL_STRING_INIT_STATIC(), nullptr }; const EnumeratedHrtf *iter{}; int i{0}; do { - if(!ext) - alstr_copy_cstr(&entry.name, name); + if(extpos == std::string::npos) + alstr_copy_range(&entry.name, &*(filename.begin()+namepos), &*filename.end()); else - alstr_copy_range(&entry.name, name, ext); + alstr_copy_range(&entry.name, &*(filename.begin()+namepos), + &*(filename.begin()+extpos)); if(i != 0) { char str[64]; @@ -1019,12 +1019,12 @@ void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename) /* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer * for input instead of opening the given filename. */ -void AddBuiltInEntry(vector_EnumeratedHrtf *list, const_al_string filename, ALuint residx) +void AddBuiltInEntry(vector_EnumeratedHrtf *list, const std::string &filename, ALuint residx) { HrtfEntry *loaded_entry{LoadedHrtfs}; while(loaded_entry) { - if(alstr_cmp_cstr(filename, loaded_entry->filename) == 0) + if(filename == loaded_entry->filename) { const EnumeratedHrtf *iter{}; #define MATCH_ENTRY(i) (loaded_entry == (i)->hrtf) @@ -1032,7 +1032,7 @@ void AddBuiltInEntry(vector_EnumeratedHrtf *list, const_al_string filename, ALui #undef MATCH_ENTRY if(iter != VECTOR_END(*list)) { - TRACE("Skipping duplicate file entry %s\n", alstr_get_cstr(filename)); + TRACE("Skipping duplicate file entry %s\n", filename.c_str()); return; } @@ -1043,9 +1043,9 @@ void AddBuiltInEntry(vector_EnumeratedHrtf *list, const_al_string filename, ALui if(!loaded_entry) { - size_t namelen = alstr_length(filename)+32; + size_t namelen = filename.length()+32; - TRACE("Got new file \"%s\"\n", alstr_get_cstr(filename)); + TRACE("Got new file \"%s\"\n", filename.c_str()); loaded_entry = static_cast(al_calloc(DEF_ALIGN, FAM_SIZE(struct HrtfEntry, filename, namelen) @@ -1053,27 +1053,18 @@ void AddBuiltInEntry(vector_EnumeratedHrtf *list, const_al_string filename, ALui loaded_entry->next = LoadedHrtfs; loaded_entry->handle = nullptr; snprintf(loaded_entry->filename, namelen, "!%u_%s", - residx, alstr_get_cstr(filename)); + residx, filename.c_str()); LoadedHrtfs = loaded_entry; } /* TODO: Get a human-readable name from the HRTF data (possibly coming in a * format update). */ - const char *name{strrchr(alstr_get_cstr(filename), '/')}; - if(!name) name = strrchr(alstr_get_cstr(filename), '\\'); - if(!name) name = alstr_get_cstr(filename); - else ++name; - - const char *ext{strrchr(name, '.')}; EnumeratedHrtf entry{AL_STRING_INIT_STATIC(), nullptr}; const EnumeratedHrtf *iter{}; int i{0}; do { - if(!ext) - alstr_copy_cstr(&entry.name, name); - else - alstr_copy_range(&entry.name, name, ext); + alstr_copy_range(&entry.name, &*filename.cbegin(), &*filename.cend()); if(i != 0) { char str[64]; @@ -1123,11 +1114,11 @@ ResData GetResource(int name) vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname) { vector_EnumeratedHrtf list{VECTOR_INIT_STATIC()}; + bool usedefaults{true}; const char *pathlist{""}; if(ConfigValueStr(alstr_get_cstr(devname), nullptr, "hrtf-paths", &pathlist)) { - al_string pname = AL_STRING_INIT_STATIC(); while(pathlist && *pathlist) { const char *next, *end; @@ -1150,46 +1141,29 @@ vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname) --end; if(end != pathlist) { - alstr_copy_range(&pname, pathlist, end); - - vector_al_string flist{SearchDataFiles(".mhr", alstr_get_cstr(pname))}; - for(size_t i{0};i < VECTOR_SIZE(flist);i++) - AddFileEntry(&list, VECTOR_ELEM(flist, i)); - VECTOR_FOR_EACH(al_string, flist, alstr_reset); - VECTOR_DEINIT(flist); + const std::string pname{pathlist, end}; + for(const auto &fname : SearchDataFiles(".mhr", pname.c_str())) + AddFileEntry(&list, fname); } pathlist = next; } - - alstr_reset(&pname); } else if(ConfigValueExists(alstr_get_cstr(devname), nullptr, "hrtf_tables")) ERR("The hrtf_tables option is deprecated, please use hrtf-paths instead.\n"); if(usedefaults) { - vector_al_string flist{SearchDataFiles(".mhr", "openal/hrtf")}; - for(size_t i{0};i < VECTOR_SIZE(flist);i++) - AddFileEntry(&list, VECTOR_ELEM(flist, i)); - VECTOR_FOR_EACH(al_string, flist, alstr_reset); - VECTOR_DEINIT(flist); + for(const auto &fname : SearchDataFiles(".mhr", "openal/hrtf")) + AddFileEntry(&list, fname); - al_string ename = AL_STRING_INIT_STATIC(); ResData res{GetResource(IDR_DEFAULT_44100_MHR)}; if(res.data != nullptr && res.size > 0) - { - alstr_copy_cstr(&ename, "Built-In 44100hz"); - AddBuiltInEntry(&list, ename, IDR_DEFAULT_44100_MHR); - } + AddBuiltInEntry(&list, "Built-In 44100hz", IDR_DEFAULT_44100_MHR); res = GetResource(IDR_DEFAULT_48000_MHR); if(res.data != nullptr && res.size > 0) - { - alstr_copy_cstr(&ename, "Built-In 48000hz"); - AddBuiltInEntry(&list, ename, IDR_DEFAULT_48000_MHR); - } - alstr_reset(&ename); + AddBuiltInEntry(&list, "Built-In 48000hz", IDR_DEFAULT_48000_MHR); } const char *defaulthrtf{""}; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index b3380ae2..9826c6b2 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -99,6 +99,9 @@ #ifdef __cplusplus +#include +#include + extern "C" { #endif @@ -910,12 +913,11 @@ inline void UnlockEffectSlotList(ALCcontext *context) int EventThread(void *arg); - -vector_al_string SearchDataFiles(const char *match, const char *subdir); - #ifdef __cplusplus } // extern "C" +std::vector SearchDataFiles(const char *match, const char *subdir); + /* Simple RAII context reference. Takes the reference of the provided * ALCcontext, and decrements it when leaving scope. Movable (transfer * reference) but not copyable (no new references). -- cgit v1.2.3 From f8bda31c72e073cfc36cc4b42574347657817c54 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Nov 2018 20:40:02 -0800 Subject: Remove unused wstr functions --- Alc/alstring.h | 9 --------- Alc/helpers.cpp | 48 ------------------------------------------------ 2 files changed, 57 deletions(-) diff --git a/Alc/alstring.h b/Alc/alstring.h index 923a5ea2..f991310f 100644 --- a/Alc/alstring.h +++ b/Alc/alstring.h @@ -42,15 +42,6 @@ void alstr_append_char(al_string *str, const al_string_char_type c); void alstr_append_cstr(al_string *str, const al_string_char_type *from); void alstr_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to); -#ifdef _WIN32 -#include -/* Windows-only methods to deal with WideChar strings. */ -void alstr_copy_wcstr(al_string *str, const wchar_t *from); -void alstr_append_wcstr(al_string *str, const wchar_t *from); -void alstr_copy_wrange(al_string *str, const wchar_t *from, const wchar_t *to); -void alstr_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to); -#endif - #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index bfb458b7..864278bb 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -846,51 +846,3 @@ void alstr_append_range(al_string *str, const al_string_char_type *from, const a VECTOR_ELEM(*str, base+i) = 0; } } - -#ifdef _WIN32 -void alstr_copy_wcstr(al_string *str, const wchar_t *from) -{ - int len; - if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, nullptr, 0, nullptr, nullptr)) > 0) - { - VECTOR_RESIZE(*str, len-1, len); - WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_FRONT(*str), len, nullptr, nullptr); - VECTOR_ELEM(*str, len-1) = 0; - } -} - -void alstr_append_wcstr(al_string *str, const wchar_t *from) -{ - int len; - if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, nullptr, 0, nullptr, nullptr)) > 0) - { - size_t base = alstr_length(*str); - VECTOR_RESIZE(*str, base+len-1, base+len); - WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_ELEM(*str, base), len, nullptr, nullptr); - VECTOR_ELEM(*str, base+len-1) = 0; - } -} - -void alstr_copy_wrange(al_string *str, const wchar_t *from, const wchar_t *to) -{ - int len; - if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), nullptr, 0, nullptr, nullptr)) > 0) - { - VECTOR_RESIZE(*str, len, len+1); - WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_FRONT(*str), len+1, nullptr, nullptr); - VECTOR_ELEM(*str, len) = 0; - } -} - -void alstr_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to) -{ - int len; - if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), nullptr, 0, nullptr, nullptr)) > 0) - { - size_t base = alstr_length(*str); - VECTOR_RESIZE(*str, base+len, base+len+1); - WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_ELEM(*str, base), len+1, nullptr, nullptr); - VECTOR_ELEM(*str, base+len) = 0; - } -} -#endif -- cgit v1.2.3 From 5848dab92d3172ea2f50e0d82f9628fb20c62bd9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Nov 2018 20:40:37 -0800 Subject: Make AmbDecConf::load noexcept To ease the ovewrhead of destructors that call C (non-noexcept) functions. --- Alc/ambdec.cpp | 2 +- Alc/ambdec.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/ambdec.cpp b/Alc/ambdec.cpp index b3978551..c408a2af 100644 --- a/Alc/ambdec.cpp +++ b/Alc/ambdec.cpp @@ -202,7 +202,7 @@ bool load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsi } // namespace -int AmbDecConf::load(const char *fname) +int AmbDecConf::load(const char *fname) noexcept { al::ifstream f{fname}; if(!f.is_open()) diff --git a/Alc/ambdec.h b/Alc/ambdec.h index d6d154fb..33e74d36 100644 --- a/Alc/ambdec.h +++ b/Alc/ambdec.h @@ -39,7 +39,7 @@ struct AmbDecConf { ALfloat HFOrderGain[MAX_AMBI_ORDER+1]; ALfloat HFMatrix[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; - int load(const char *fname); + int load(const char *fname) noexcept; }; #endif /* AMBDEC_H */ -- cgit v1.2.3 From c23ea494eabd1695b8c43f00bff4b5820c0cd56c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Nov 2018 22:19:32 -0800 Subject: Fix getting the process binary for FreeBSD or macOS --- Alc/helpers.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index 864278bb..0505c729 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -484,21 +484,19 @@ PathNamePair GetProcBinary() { pathname.resize(pathlen + 1); sysctl(mib, 4, pathname.data(), &pathlen, nullptr, 0); - pathname[pathlen] = 0; + pathname.resize(pathlen); } #endif #ifdef HAVE_PROC_PIDPATH if(pathname.empty()) { - const pid_t pid = getpid(); - char procpath[PROC_PIDPATHINFO_MAXSIZE]; - int ret; - - ret = proc_pidpath(pid, procpath, sizeof(procpath)); + char procpath[PROC_PIDPATHINFO_MAXSIZE]{}; + const pid_t pid{getpid()}; + const int ret{proc_pidpath(pid, procpath, sizeof(procpath))}; if(ret < 1) - WARN("proc_pidpath(%d, ...) failed: %s\n", pid, strerror(errno)); + ERR("proc_pidpath(%d, ...) failed: %s\n", pid, strerror(errno)); else - pathname.append(procpath, procpath+strlen(procpath)); + pathname.insert(pathname.end(), procpath, procpath+strlen(procpath)); } #endif if(pathname.empty()) -- cgit v1.2.3 From c66db3cdf63f13a7d30b0e2b86a60661216e28a5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Nov 2018 22:27:37 -0800 Subject: Use the correct type for __control87_2 --- Alc/helpers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index 0505c729..ce526c1e 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -297,7 +297,7 @@ void RestoreFPUMode(const FPUCtl *ctl) #elif defined(HAVE___CONTROL87_2) - int mode; + unsigned int mode; __control87_2(ctl->state, _MCW_DN, &mode, nullptr); __control87_2(ctl->sse_state, _MCW_DN, nullptr, &mode); -- cgit v1.2.3 From 4def2a60f20cff8e9cc7b9b78e09008ef06041ce Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Nov 2018 23:05:21 -0800 Subject: Clean up helpers.cpp some --- Alc/helpers.cpp | 236 ++++++++++++++++++++++++++------------------------------ 1 file changed, 108 insertions(+), 128 deletions(-) diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index ce526c1e..cb479f4b 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -109,7 +109,7 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x #include #endif -#include +#include #include #include #include @@ -118,7 +118,6 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x #include "alu.h" #include "cpu_caps.h" #include "fpu_modes.h" -#include "atomic.h" #include "uintmap.h" #include "vector.h" #include "alstring.h" @@ -407,10 +406,8 @@ static void DirectorySearch(const char *path, const char *ext, std::vector SearchDataFiles(const char *ext, const char *subdir) { - static std::atomic search_lock{AL_FALSE}; - - while(search_lock.exchange(AL_TRUE) == AL_TRUE) - althrd_yield(); + static std::mutex search_lock; + std::lock_guard _{search_lock}; /* If the path is absolute, use it directly. */ std::vector results; @@ -419,52 +416,53 @@ std::vector SearchDataFiles(const char *ext, const char *subdir) std::string path{subdir}; std::replace(path.begin(), path.end(), '/', '\\'); DirectorySearch(path.c_str(), ext, &results); + return results; } - else if(subdir[0] == '\\' && subdir[1] == '\\' && subdir[2] == '?' && subdir[3] == '\\') + if(subdir[0] == '\\' && subdir[1] == '\\' && subdir[2] == '?' && subdir[3] == '\\') + { DirectorySearch(subdir, ext, &results); + return results; + } + + std::string path; + + /* Search the app-local directory. */ + WCHAR *cwdbuf{_wgetenv(L"ALSOFT_LOCAL_PATH")}; + if(cwdbuf && *cwdbuf != '\0') + { + path = wstr_to_utf8(cwdbuf); + if(is_slash(path.back())) + path.pop_back(); + } + else if(!(cwdbuf=_wgetcwd(nullptr, 0))) + path = "."; else { - std::string path; + path = wstr_to_utf8(cwdbuf); + if(is_slash(path.back())) + path.pop_back(); + free(cwdbuf); + } + std::replace(path.begin(), path.end(), '/', '\\'); + DirectorySearch(path.c_str(), ext, &results); - /* Search the app-local directory. */ - WCHAR *cwdbuf{_wgetenv(L"ALSOFT_LOCAL_PATH")}; - if(cwdbuf && *cwdbuf != '\0') - { - path = wstr_to_utf8(cwdbuf); - if(is_slash(path.back())) - path.pop_back(); - } - else if(!(cwdbuf=_wgetcwd(nullptr, 0))) - path = "."; - else - { - path = wstr_to_utf8(cwdbuf); - if(is_slash(path.back())) - path.pop_back(); - free(cwdbuf); - } + /* Search the local and global data dirs. */ + static constexpr int ids[2]{ CSIDL_APPDATA, CSIDL_COMMON_APPDATA }; + for(int id : ids) + { + WCHAR buffer[MAX_PATH]; + if(SHGetSpecialFolderPathW(nullptr, buffer, id, FALSE) == FALSE) + continue; + + path = wstr_to_utf8(buffer); + if(!is_slash(path.back())) + path += '\\'; + path += subdir; std::replace(path.begin(), path.end(), '/', '\\'); - DirectorySearch(path.c_str(), ext, &results); - - /* Search the local and global data dirs. */ - static constexpr int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA }; - for(int id : ids) - { - WCHAR buffer[MAX_PATH]; - if(SHGetSpecialFolderPathW(nullptr, buffer, id, FALSE) == FALSE) - continue; - path = wstr_to_utf8(buffer); - if(!is_slash(path.back())) - path += '\\'; - path += subdir; - std::replace(path.begin(), path.end(), '/', '\\'); - - DirectorySearch(path.c_str(), ext, &results); - } + DirectorySearch(path.c_str(), ext, &results); } - search_lock.store(AL_FALSE); return results; } @@ -492,8 +490,7 @@ PathNamePair GetProcBinary() { char procpath[PROC_PIDPATHINFO_MAXSIZE]{}; const pid_t pid{getpid()}; - const int ret{proc_pidpath(pid, procpath, sizeof(procpath))}; - if(ret < 1) + if(proc_pidpath(pid, procpath, sizeof(procpath)) < 1) ERR("proc_pidpath(%d, ...) failed: %s\n", pid, strerror(errno)); else pathname.insert(pathname.end(), procpath, procpath+strlen(procpath)); @@ -532,7 +529,7 @@ PathNamePair GetProcBinary() return ret; } - pathname[len] = 0; + pathname.resize(len); } while(!pathname.empty() && pathname.back() == 0) pathname.pop_back(); @@ -627,86 +624,79 @@ static void DirectorySearch(const char *path, const char *ext, std::vector SearchDataFiles(const char *ext, const char *subdir) { - static std::atomic search_lock{AL_FALSE}; - - while(search_lock.exchange(AL_TRUE) == AL_TRUE) - althrd_yield(); + static std::mutex search_lock; + std::lock_guard _{search_lock}; std::vector results; if(subdir[0] == '/') + { DirectorySearch(subdir, ext, &results); + return results; + } + + /* Search the app-local directory. */ + const char *str{getenv("ALSOFT_LOCAL_PATH")}; + if(str && *str != '\0') + DirectorySearch(str, ext, &results); else { - /* Search the app-local directory. */ - const char *str{getenv("ALSOFT_LOCAL_PATH")}; - if(str && *str != '\0') - DirectorySearch(str, ext, &results); - else + std::vector cwdbuf(256); + while(!getcwd(cwdbuf.data(), cwdbuf.size())) { - std::vector cwdbuf(256); - while(!getcwd(cwdbuf.data(), cwdbuf.size())) - { - if(errno != ERANGE) - { - cwdbuf.clear(); - break; - } - cwdbuf.resize(cwdbuf.size() << 1); - } - if(cwdbuf.empty()) - DirectorySearch(".", ext, &results); - else + if(errno != ERANGE) { - DirectorySearch(cwdbuf.data(), ext, &results); cwdbuf.clear(); + break; } + cwdbuf.resize(cwdbuf.size() << 1); } - - // Search local data dir - if((str=getenv("XDG_DATA_HOME")) != nullptr && str[0] != '\0') - { - std::string path{str}; - if(path.back() != '/') - path += '/'; - path += subdir; - DirectorySearch(path.c_str(), ext, &results); - } - else if((str=getenv("HOME")) != nullptr && str[0] != '\0') + if(cwdbuf.empty()) + DirectorySearch(".", ext, &results); + else { - std::string path{str}; - if(path.back() == '/') - path.pop_back(); - path += "/.local/share/"; - path += subdir; - DirectorySearch(path.c_str(), ext, &results); + DirectorySearch(cwdbuf.data(), ext, &results); + cwdbuf.clear(); } + } + + // Search local data dir + if((str=getenv("XDG_DATA_HOME")) != nullptr && str[0] != '\0') + { + std::string path{str}; + if(path.back() != '/') + path += '/'; + path += subdir; + DirectorySearch(path.c_str(), ext, &results); + } + else if((str=getenv("HOME")) != nullptr && str[0] != '\0') + { + std::string path{str}; + if(path.back() == '/') + path.pop_back(); + path += "/.local/share/"; + path += subdir; + DirectorySearch(path.c_str(), ext, &results); + } - // Search global data dirs - if((str=getenv("XDG_DATA_DIRS")) == nullptr || str[0] == '\0') - str = "/usr/local/share/:/usr/share/"; + // Search global data dirs + if((str=getenv("XDG_DATA_DIRS")) == nullptr || str[0] == '\0') + str = "/usr/local/share/:/usr/share/"; - const char *next{str}; - while((str=next) != nullptr && str[0] != '\0') - { - next = strchr(str, ':'); - - std::string path; - if(!next) - path = str; - else - path.append(str, next++); - if(!path.empty()) - { - if(path.back() != '/') - path += '/'; - path += subdir; + const char *next{str}; + while((str=next) != nullptr && str[0] != '\0') + { + next = strchr(str, ':'); - DirectorySearch(path.c_str(), ext, &results); - } - } + std::string path = (next ? std::string(str, next++) : std::string(str)); + if(path.empty()) continue; + + if(path.back() != '/') + path += '/'; + path += subdir; + + DirectorySearch(path.c_str(), ext, &results); } - search_lock.store(AL_FALSE); return results; } @@ -777,34 +767,28 @@ int alstr_cmp_cstr(const_al_string str1, const al_string_char_type *str2) void alstr_copy(al_string *str, const_al_string from) { size_t len = alstr_length(from); - size_t i; - VECTOR_RESIZE(*str, len, len+1); - for(i = 0;i < len;i++) + for(size_t i{0};i < len;i++) VECTOR_ELEM(*str, i) = VECTOR_ELEM(from, i); - VECTOR_ELEM(*str, i) = 0; + VECTOR_ELEM(*str, len) = 0; } void alstr_copy_cstr(al_string *str, const al_string_char_type *from) { size_t len = strlen(from); - size_t i; - VECTOR_RESIZE(*str, len, len+1); - for(i = 0;i < len;i++) + for(size_t i{0};i < len;i++) VECTOR_ELEM(*str, i) = from[i]; - VECTOR_ELEM(*str, i) = 0; + VECTOR_ELEM(*str, len) = 0; } void alstr_copy_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to) { size_t len = to - from; - size_t i; - VECTOR_RESIZE(*str, len, len+1); - for(i = 0;i < len;i++) + for(size_t i{0};i < len;i++) VECTOR_ELEM(*str, i) = from[i]; - VECTOR_ELEM(*str, i) = 0; + VECTOR_ELEM(*str, len) = 0; } void alstr_append_char(al_string *str, const al_string_char_type c) @@ -821,12 +805,10 @@ void alstr_append_cstr(al_string *str, const al_string_char_type *from) if(len != 0) { size_t base = alstr_length(*str); - size_t i; - VECTOR_RESIZE(*str, base+len, base+len+1); - for(i = 0;i < len;i++) + for(size_t i{0};i < len;i++) VECTOR_ELEM(*str, base+i) = from[i]; - VECTOR_ELEM(*str, base+i) = 0; + VECTOR_ELEM(*str, base+len) = 0; } } @@ -836,11 +818,9 @@ void alstr_append_range(al_string *str, const al_string_char_type *from, const a if(len != 0) { size_t base = alstr_length(*str); - size_t i; - VECTOR_RESIZE(*str, base+len, base+len+1); - for(i = 0;i < len;i++) + for(size_t i{0};i < len;i++) VECTOR_ELEM(*str, base+i) = from[i]; - VECTOR_ELEM(*str, base+i) = 0; + VECTOR_ELEM(*str, base+len) = 0; } } -- cgit v1.2.3 From c0f2858f3d47323205bb90b3b1cc7db2553e6917 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Nov 2018 18:05:16 -0800 Subject: Split Windows-specific SetRTPriority --- Alc/helpers.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index cb479f4b..833be68e 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -466,6 +466,14 @@ std::vector SearchDataFiles(const char *ext, const char *subdir) return results; } +void SetRTPriority(void) +{ + bool failed = false; + if(RTPrioLevel > 0) + failed = !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); + if(failed) ERR("Failed to set priority level for thread\n"); +} + #else PathNamePair GetProcBinary() @@ -700,17 +708,10 @@ std::vector SearchDataFiles(const char *ext, const char *subdir) return results; } -#endif - - void SetRTPriority(void) { - ALboolean failed = AL_FALSE; - -#ifdef _WIN32 - if(RTPrioLevel > 0) - failed = !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); -#elif defined(HAVE_PTHREAD_SETSCHEDPARAM) && !defined(__OpenBSD__) + bool failed = false; +#if defined(HAVE_PTHREAD_SETSCHEDPARAM) && !defined(__OpenBSD__) if(RTPrioLevel > 0) { struct sched_param param; @@ -727,6 +728,8 @@ void SetRTPriority(void) ERR("Failed to set priority level for thread\n"); } +#endif + void alstr_clear(al_string *str) { -- cgit v1.2.3 From d4d0b1fdd48e1c056fad9cbe3e063fc9de1a0b75 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Nov 2018 19:02:38 -0800 Subject: Use a regular char* for the HRTF string name --- Alc/ALc.c | 7 ++++--- Alc/panning.cpp | 25 ++++++++++++++++++------- OpenAL32/Include/alMain.h | 2 +- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index a483c94f..fc68236d 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2429,7 +2429,7 @@ static void InitDevice(ALCdevice *device, enum DeviceType type) device->ChannelDelay[i].Buffer = NULL; } - AL_STRING_INIT(device->HrtfName); + device->HrtfName = NULL; VECTOR_INIT(device->HrtfList); device->HrtfHandle = NULL; device->Hrtf = NULL; @@ -2493,7 +2493,8 @@ static ALCvoid FreeDevice(ALCdevice *device) VECTOR_DEINIT(device->FilterList); almtx_destroy(&device->FilterLock); - AL_STRING_DEINIT(device->HrtfName); + al_free(device->HrtfName); + device->HrtfName = NULL; FreeHrtfList(&device->HrtfList); if(device->HrtfHandle) Hrtf_DecRef(device->HrtfHandle); @@ -3190,7 +3191,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para else { almtx_lock(&Device->BackendLock); - value = (Device->HrtfHandle ? alstr_get_cstr(Device->HrtfName) : ""); + value = ((Device->HrtfHandle && Device->HrtfName) ? Device->HrtfName : ""); almtx_unlock(&Device->BackendLock); ALCdevice_DecRef(Device); } diff --git a/Alc/panning.cpp b/Alc/panning.cpp index db476884..e39abab9 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -38,7 +38,9 @@ #include "bs2b.h" -static const ALsizei FuMa2ACN[MAX_AMBI_COEFFS] = { +namespace { + +constexpr ALsizei FuMa2ACN[MAX_AMBI_COEFFS] = { 0, /* W */ 3, /* X */ 1, /* Y */ @@ -56,11 +58,20 @@ static const ALsizei FuMa2ACN[MAX_AMBI_COEFFS] = { 15, /* P */ 9, /* Q */ }; -static const ALsizei ACN2ACN[MAX_AMBI_COEFFS] = { +constexpr ALsizei ACN2ACN[MAX_AMBI_COEFFS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; +char *alstrdup(const_al_string str) +{ + const size_t len{alstr_length(str)}; + char *ret{static_cast(al_calloc(DEF_ALIGN, len+1))}; + memcpy(ret, alstr_get_cstr(str), len); + return ret; +} + +} // namespace void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]) @@ -931,7 +942,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf al_free(device->Hrtf); device->Hrtf = NULL; device->HrtfHandle = NULL; - alstr_clear(&device->HrtfName); + al_free(device->HrtfName); + device->HrtfName = NULL; device->Render_Mode = NormalRender; memset(&device->Dry.Ambi, 0, sizeof(device->Dry.Ambi)); @@ -1114,7 +1126,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(hrtf && hrtf->sampleRate == device->Frequency) { device->HrtfHandle = hrtf; - alstr_copy(&device->HrtfName, entry->name); + device->HrtfName = alstrdup(entry->name); } else if(hrtf) Hrtf_DecRef(hrtf); @@ -1127,7 +1139,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(hrtf && hrtf->sampleRate == device->Frequency) { device->HrtfHandle = hrtf; - alstr_copy(&device->HrtfName, entry->name); + device->HrtfName = alstrdup(entry->name); } else if(hrtf) Hrtf_DecRef(hrtf); @@ -1164,8 +1176,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf } TRACE("%s HRTF rendering enabled, using \"%s\"\n", - ((device->Render_Mode == HrtfRender) ? "Full" : "Basic"), - alstr_get_cstr(device->HrtfName) + ((device->Render_Mode == HrtfRender) ? "Full" : "Basic"), device->HrtfName ); InitHrtfPanning(device); return; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 9826c6b2..03d07c0d 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -656,7 +656,7 @@ struct ALCdevice_struct { /* HRTF state and info */ struct DirectHrtfState *Hrtf; - al_string HrtfName; + char *HrtfName; struct Hrtf *HrtfHandle; vector_EnumeratedHrtf HrtfList; ALCenum HrtfStatus; -- cgit v1.2.3 From a6d780574de081865ec673cb5c930a2c7796f43a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Nov 2018 22:26:12 -0800 Subject: Make the enumerated HRTF entry name a char* Would ideally be a std::string with the HRTF name itself, but they're still seen in C code. --- Alc/ALc.c | 2 +- Alc/hrtf.cpp | 45 +++++++++++++++++++++++++-------------------- Alc/panning.cpp | 6 +++--- OpenAL32/Include/alMain.h | 2 +- 4 files changed, 30 insertions(+), 25 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index fc68236d..4e2402ca 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -4677,7 +4677,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum { case ALC_HRTF_SPECIFIER_SOFT: if(index >= 0 && (size_t)index < VECTOR_SIZE(device->HrtfList)) - str = alstr_get_cstr(VECTOR_ELEM(device->HrtfList, index).name); + str = VECTOR_ELEM(device->HrtfList, index).name; else alcSetError(device, ALC_INVALID_VALUE); break; diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 9b57ede7..153b57b6 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -82,6 +82,14 @@ std::mutex LoadedHrtfLock; HrtfEntry *LoadedHrtfs{nullptr}; +char *alstrdup(const std::string &str) +{ + const size_t len{str.length()}; + char *ret{static_cast(al_calloc(DEF_ALIGN, len+1))}; + memcpy(ret, str.data(), len); + return ret; +} + class databuf final : public std::streambuf { int_type underflow() override { return traits_type::eof(); } @@ -989,30 +997,28 @@ void AddFileEntry(vector_EnumeratedHrtf *list, const std::string &filename) size_t extpos{filename.find_last_of('.')}; if(extpos <= namepos) extpos = std::string::npos; - EnumeratedHrtf entry = { AL_STRING_INIT_STATIC(), nullptr }; const EnumeratedHrtf *iter{}; + std::string newname; int i{0}; do { if(extpos == std::string::npos) - alstr_copy_range(&entry.name, &*(filename.begin()+namepos), &*filename.end()); + newname = filename.substr(namepos); else - alstr_copy_range(&entry.name, &*(filename.begin()+namepos), - &*(filename.begin()+extpos)); + newname = filename.substr(namepos, extpos-namepos); if(i != 0) { - char str[64]; - snprintf(str, sizeof(str), " #%d", i+1); - alstr_append_cstr(&entry.name, str); + newname += " #"; + newname += std::to_string(i+1); } ++i; -#define MATCH_NAME(i) (alstr_cmp(entry.name, (i)->name) == 0) +#define MATCH_NAME(i) (newname == (i)->name) VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_NAME); #undef MATCH_NAME } while(iter != VECTOR_END(*list)); - entry.hrtf = loaded_entry; + EnumeratedHrtf entry{ alstrdup(newname), loaded_entry }; - TRACE("Adding file entry \"%s\"\n", alstr_get_cstr(entry.name)); + TRACE("Adding file entry \"%s\"\n", entry.name); VECTOR_PUSH_BACK(*list, entry); } @@ -1060,26 +1066,25 @@ void AddBuiltInEntry(vector_EnumeratedHrtf *list, const std::string &filename, A /* TODO: Get a human-readable name from the HRTF data (possibly coming in a * format update). */ - EnumeratedHrtf entry{AL_STRING_INIT_STATIC(), nullptr}; const EnumeratedHrtf *iter{}; + std::string newname; int i{0}; do { - alstr_copy_range(&entry.name, &*filename.cbegin(), &*filename.cend()); + newname = filename; if(i != 0) { - char str[64]; - snprintf(str, sizeof(str), " #%d", i+1); - alstr_append_cstr(&entry.name, str); + newname += " #"; + newname += std::to_string(i+1); } ++i; -#define MATCH_NAME(i) (alstr_cmp(entry.name, (i)->name) == 0) +#define MATCH_NAME(i) (newname == (i)->name) VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_NAME); #undef MATCH_NAME } while(iter != VECTOR_END(*list)); - entry.hrtf = loaded_entry; + EnumeratedHrtf entry{ alstrdup(newname), loaded_entry }; - TRACE("Adding built-in entry \"%s\"\n", alstr_get_cstr(entry.name)); + TRACE("Adding built-in entry \"%s\"\n", entry.name); VECTOR_PUSH_BACK(*list, entry); } @@ -1171,7 +1176,7 @@ vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname) { const EnumeratedHrtf *iter{}; /* Find the preferred HRTF and move it to the front of the list. */ -#define FIND_ENTRY(i) (alstr_cmp_cstr((i)->name, defaulthrtf) == 0) +#define FIND_ENTRY(i) (strcmp((i)->name, defaulthrtf) == 0) VECTOR_FIND_IF(iter, const EnumeratedHrtf, list, FIND_ENTRY); #undef FIND_ENTRY if(iter == VECTOR_END(list)) @@ -1190,7 +1195,7 @@ vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname) void FreeHrtfList(vector_EnumeratedHrtf *list) { -#define CLEAR_ENTRY(i) alstr_reset(&(i)->name) +#define CLEAR_ENTRY(i) al_free((i)->name) VECTOR_FOR_EACH(EnumeratedHrtf, *list, CLEAR_ENTRY); VECTOR_DEINIT(*list); #undef CLEAR_ENTRY diff --git a/Alc/panning.cpp b/Alc/panning.cpp index e39abab9..1d1eb7ef 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -63,11 +63,11 @@ constexpr ALsizei ACN2ACN[MAX_AMBI_COEFFS] = { 8, 9, 10, 11, 12, 13, 14, 15 }; -char *alstrdup(const_al_string str) +char *alstrdup(const char *str) { - const size_t len{alstr_length(str)}; + const size_t len{strlen(str)}; char *ret{static_cast(al_calloc(DEF_ALIGN, len+1))}; - memcpy(ret, alstr_get_cstr(str), len); + memcpy(ret, str, len); return ret; } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 03d07c0d..8cb22615 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -562,7 +562,7 @@ TYPEDEF_VECTOR(ALeffectslotPtr, vector_ALeffectslotPtr) typedef struct EnumeratedHrtf { - al_string name; + char *name; struct HrtfEntry *hrtf; } EnumeratedHrtf; -- cgit v1.2.3 From e7ab5053e4374273a4da41fb3622565c40e646e2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Nov 2018 22:57:39 -0800 Subject: Convert the SDL2 backend to C++ --- Alc/backends/sdl2.c | 288 ------------------------------------------------- Alc/backends/sdl2.cpp | 291 ++++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 292 insertions(+), 289 deletions(-) delete mode 100644 Alc/backends/sdl2.c create mode 100644 Alc/backends/sdl2.cpp diff --git a/Alc/backends/sdl2.c b/Alc/backends/sdl2.c deleted file mode 100644 index 3495e6bf..00000000 --- a/Alc/backends/sdl2.c +++ /dev/null @@ -1,288 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2018 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alu.h" -#include "threads.h" -#include "compat.h" - -#include "backends/base.h" - - -#ifdef _WIN32 -#define DEVNAME_PREFIX "OpenAL Soft on " -#else -#define DEVNAME_PREFIX "" -#endif - -typedef struct ALCsdl2Backend { - DERIVE_FROM_TYPE(ALCbackend); - - SDL_AudioDeviceID deviceID; - ALsizei frameSize; - - ALuint Frequency; - enum DevFmtChannels FmtChans; - enum DevFmtType FmtType; - ALuint UpdateSize; -} ALCsdl2Backend; - -static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device); -static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self); -static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name); -static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self); -static ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self); -static void ALCsdl2Backend_stop(ALCsdl2Backend *self); -static DECLARE_FORWARD2(ALCsdl2Backend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ClockLatency, getClockLatency) -static void ALCsdl2Backend_lock(ALCsdl2Backend *self); -static void ALCsdl2Backend_unlock(ALCsdl2Backend *self); -DECLARE_DEFAULT_ALLOCATORS(ALCsdl2Backend) - -DEFINE_ALCBACKEND_VTABLE(ALCsdl2Backend); - -static const ALCchar defaultDeviceName[] = DEVNAME_PREFIX "Default Device"; - -static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCsdl2Backend, ALCbackend, self); - - self->deviceID = 0; - self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - self->Frequency = device->Frequency; - self->FmtChans = device->FmtChans; - self->FmtType = device->FmtType; - self->UpdateSize = device->UpdateSize; -} - -static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self) -{ - if(self->deviceID) - SDL_CloseAudioDevice(self->deviceID); - self->deviceID = 0; - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -static void ALCsdl2Backend_audioCallback(void *ptr, Uint8 *stream, int len) -{ - ALCsdl2Backend *self = (ALCsdl2Backend*)ptr; - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - - assert((len % self->frameSize) == 0); - aluMixData(device, stream, len / self->frameSize); -} - -static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - SDL_AudioSpec want, have; - - SDL_zero(want); - SDL_zero(have); - - want.freq = device->Frequency; - switch(device->FmtType) - { - case DevFmtUByte: want.format = AUDIO_U8; break; - case DevFmtByte: want.format = AUDIO_S8; break; - case DevFmtUShort: want.format = AUDIO_U16SYS; break; - case DevFmtShort: want.format = AUDIO_S16SYS; break; - case DevFmtUInt: /* fall-through */ - case DevFmtInt: want.format = AUDIO_S32SYS; break; - case DevFmtFloat: want.format = AUDIO_F32; break; - } - want.channels = (device->FmtChans == DevFmtMono) ? 1 : 2; - want.samples = device->UpdateSize; - want.callback = ALCsdl2Backend_audioCallback; - want.userdata = self; - - /* Passing NULL to SDL_OpenAudioDevice opens a default, which isn't - * necessarily the first in the list. - */ - if(!name || strcmp(name, defaultDeviceName) == 0) - self->deviceID = SDL_OpenAudioDevice(NULL, SDL_FALSE, &want, &have, - SDL_AUDIO_ALLOW_ANY_CHANGE); - else - { - const size_t prefix_len = strlen(DEVNAME_PREFIX); - if(strncmp(name, DEVNAME_PREFIX, prefix_len) == 0) - self->deviceID = SDL_OpenAudioDevice(name+prefix_len, SDL_FALSE, &want, &have, - SDL_AUDIO_ALLOW_ANY_CHANGE); - else - self->deviceID = SDL_OpenAudioDevice(name, SDL_FALSE, &want, &have, - SDL_AUDIO_ALLOW_ANY_CHANGE); - } - if(self->deviceID == 0) - return ALC_INVALID_VALUE; - - device->Frequency = have.freq; - if(have.channels == 1) - device->FmtChans = DevFmtMono; - else if(have.channels == 2) - device->FmtChans = DevFmtStereo; - else - { - ERR("Got unhandled SDL channel count: %d\n", (int)have.channels); - return ALC_INVALID_VALUE; - } - switch(have.format) - { - case AUDIO_U8: device->FmtType = DevFmtUByte; break; - case AUDIO_S8: device->FmtType = DevFmtByte; break; - case AUDIO_U16SYS: device->FmtType = DevFmtUShort; break; - case AUDIO_S16SYS: device->FmtType = DevFmtShort; break; - case AUDIO_S32SYS: device->FmtType = DevFmtInt; break; - case AUDIO_F32SYS: device->FmtType = DevFmtFloat; break; - default: - ERR("Got unsupported SDL format: 0x%04x\n", have.format); - return ALC_INVALID_VALUE; - } - device->UpdateSize = have.samples; - device->NumUpdates = 2; /* SDL always (tries to) use two periods. */ - - self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - self->Frequency = device->Frequency; - self->FmtChans = device->FmtChans; - self->FmtType = device->FmtType; - self->UpdateSize = device->UpdateSize; - - alstr_copy_cstr(&device->DeviceName, name ? name : defaultDeviceName); - - return ALC_NO_ERROR; -} - -static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - device->Frequency = self->Frequency; - device->FmtChans = self->FmtChans; - device->FmtType = self->FmtType; - device->UpdateSize = self->UpdateSize; - device->NumUpdates = 2; - SetDefaultWFXChannelOrder(device); - return ALC_TRUE; -} - -static ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self) -{ - SDL_PauseAudioDevice(self->deviceID, 0); - return ALC_TRUE; -} - -static void ALCsdl2Backend_stop(ALCsdl2Backend *self) -{ - SDL_PauseAudioDevice(self->deviceID, 1); -} - -static void ALCsdl2Backend_lock(ALCsdl2Backend *self) -{ - SDL_LockAudioDevice(self->deviceID); -} - -static void ALCsdl2Backend_unlock(ALCsdl2Backend *self) -{ - SDL_UnlockAudioDevice(self->deviceID); -} - - -typedef struct ALCsdl2BackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCsdl2BackendFactory; -#define ALCsdl2BACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCsdl2BackendFactory, ALCbackendFactory) } } - -ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void); - -static ALCboolean ALCsdl2BackendFactory_init(ALCsdl2BackendFactory *self); -static void ALCsdl2BackendFactory_deinit(ALCsdl2BackendFactory *self); -static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory *self, ALCbackend_Type type); -static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory *self, enum DevProbe type, al_string *outnames); -static ALCbackend* ALCsdl2BackendFactory_createBackend(ALCsdl2BackendFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsdl2BackendFactory); - - -ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void) -{ - static ALCsdl2BackendFactory factory = ALCsdl2BACKENDFACTORY_INITIALIZER; - return STATIC_CAST(ALCbackendFactory, &factory); -} - - -static ALCboolean ALCsdl2BackendFactory_init(ALCsdl2BackendFactory* UNUSED(self)) -{ - if(SDL_InitSubSystem(SDL_INIT_AUDIO) == 0) - return AL_TRUE; - return ALC_FALSE; -} - -static void ALCsdl2BackendFactory_deinit(ALCsdl2BackendFactory* UNUSED(self)) -{ - SDL_QuitSubSystem(SDL_INIT_AUDIO); -} - -static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - return ALC_TRUE; - return ALC_FALSE; -} - -static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) -{ - int num_devices, i; - al_string name; - - if(type != ALL_DEVICE_PROBE) - return; - - AL_STRING_INIT(name); - num_devices = SDL_GetNumAudioDevices(SDL_FALSE); - - alstr_append_range(outnames, defaultDeviceName, defaultDeviceName+sizeof(defaultDeviceName)); - for(i = 0;i < num_devices;++i) - { - alstr_copy_cstr(&name, DEVNAME_PREFIX); - alstr_append_cstr(&name, SDL_GetAudioDeviceName(i, SDL_FALSE)); - if(!alstr_empty(name)) - alstr_append_range(outnames, VECTOR_BEGIN(name), VECTOR_END(name)+1); - } - alstr_reset(&name); -} - -static ALCbackend* ALCsdl2BackendFactory_createBackend(ALCsdl2BackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - { - ALCsdl2Backend *backend; - NEW_OBJ(backend, ALCsdl2Backend)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} diff --git a/Alc/backends/sdl2.cpp b/Alc/backends/sdl2.cpp new file mode 100644 index 00000000..cf81e1f0 --- /dev/null +++ b/Alc/backends/sdl2.cpp @@ -0,0 +1,291 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2018 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include + +#include "alMain.h" +#include "alu.h" +#include "threads.h" +#include "compat.h" + +#include "backends/base.h" + + +#ifdef _WIN32 +#define DEVNAME_PREFIX "OpenAL Soft on " +#else +#define DEVNAME_PREFIX "" +#endif + +struct ALCsdl2Backend final : public ALCbackend { + SDL_AudioDeviceID deviceID; + ALsizei frameSize; + + ALuint Frequency; + enum DevFmtChannels FmtChans; + enum DevFmtType FmtType; + ALuint UpdateSize; +}; + +static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device); +static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self); +static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name); +static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self); +static ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self); +static void ALCsdl2Backend_stop(ALCsdl2Backend *self); +static DECLARE_FORWARD2(ALCsdl2Backend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ClockLatency, getClockLatency) +static void ALCsdl2Backend_lock(ALCsdl2Backend *self); +static void ALCsdl2Backend_unlock(ALCsdl2Backend *self); +DECLARE_DEFAULT_ALLOCATORS(ALCsdl2Backend) + +DEFINE_ALCBACKEND_VTABLE(ALCsdl2Backend); + +static const ALCchar defaultDeviceName[] = DEVNAME_PREFIX "Default Device"; + +static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device) +{ + new (self) ALCsdl2Backend{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCsdl2Backend, ALCbackend, self); + + self->deviceID = 0; + self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + self->Frequency = device->Frequency; + self->FmtChans = device->FmtChans; + self->FmtType = device->FmtType; + self->UpdateSize = device->UpdateSize; +} + +static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self) +{ + if(self->deviceID) + SDL_CloseAudioDevice(self->deviceID); + self->deviceID = 0; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCsdl2Backend(); +} + + +static void ALCsdl2Backend_audioCallback(void *ptr, Uint8 *stream, int len) +{ + ALCsdl2Backend *self = static_cast(ptr); + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + + assert((len % self->frameSize) == 0); + aluMixData(device, stream, len / self->frameSize); +} + +static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + SDL_AudioSpec want, have; + + SDL_zero(want); + SDL_zero(have); + + want.freq = device->Frequency; + switch(device->FmtType) + { + case DevFmtUByte: want.format = AUDIO_U8; break; + case DevFmtByte: want.format = AUDIO_S8; break; + case DevFmtUShort: want.format = AUDIO_U16SYS; break; + case DevFmtShort: want.format = AUDIO_S16SYS; break; + case DevFmtUInt: /* fall-through */ + case DevFmtInt: want.format = AUDIO_S32SYS; break; + case DevFmtFloat: want.format = AUDIO_F32; break; + } + want.channels = (device->FmtChans == DevFmtMono) ? 1 : 2; + want.samples = device->UpdateSize; + want.callback = ALCsdl2Backend_audioCallback; + want.userdata = self; + + /* Passing nullptr to SDL_OpenAudioDevice opens a default, which isn't + * necessarily the first in the list. + */ + if(!name || strcmp(name, defaultDeviceName) == 0) + self->deviceID = SDL_OpenAudioDevice(nullptr, SDL_FALSE, &want, &have, + SDL_AUDIO_ALLOW_ANY_CHANGE); + else + { + const size_t prefix_len = strlen(DEVNAME_PREFIX); + if(strncmp(name, DEVNAME_PREFIX, prefix_len) == 0) + self->deviceID = SDL_OpenAudioDevice(name+prefix_len, SDL_FALSE, &want, &have, + SDL_AUDIO_ALLOW_ANY_CHANGE); + else + self->deviceID = SDL_OpenAudioDevice(name, SDL_FALSE, &want, &have, + SDL_AUDIO_ALLOW_ANY_CHANGE); + } + if(self->deviceID == 0) + return ALC_INVALID_VALUE; + + device->Frequency = have.freq; + if(have.channels == 1) + device->FmtChans = DevFmtMono; + else if(have.channels == 2) + device->FmtChans = DevFmtStereo; + else + { + ERR("Got unhandled SDL channel count: %d\n", (int)have.channels); + return ALC_INVALID_VALUE; + } + switch(have.format) + { + case AUDIO_U8: device->FmtType = DevFmtUByte; break; + case AUDIO_S8: device->FmtType = DevFmtByte; break; + case AUDIO_U16SYS: device->FmtType = DevFmtUShort; break; + case AUDIO_S16SYS: device->FmtType = DevFmtShort; break; + case AUDIO_S32SYS: device->FmtType = DevFmtInt; break; + case AUDIO_F32SYS: device->FmtType = DevFmtFloat; break; + default: + ERR("Got unsupported SDL format: 0x%04x\n", have.format); + return ALC_INVALID_VALUE; + } + device->UpdateSize = have.samples; + device->NumUpdates = 2; /* SDL always (tries to) use two periods. */ + + self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + self->Frequency = device->Frequency; + self->FmtChans = device->FmtChans; + self->FmtType = device->FmtType; + self->UpdateSize = device->UpdateSize; + + alstr_copy_cstr(&device->DeviceName, name ? name : defaultDeviceName); + + return ALC_NO_ERROR; +} + +static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + device->Frequency = self->Frequency; + device->FmtChans = self->FmtChans; + device->FmtType = self->FmtType; + device->UpdateSize = self->UpdateSize; + device->NumUpdates = 2; + SetDefaultWFXChannelOrder(device); + return ALC_TRUE; +} + +static ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self) +{ + SDL_PauseAudioDevice(self->deviceID, 0); + return ALC_TRUE; +} + +static void ALCsdl2Backend_stop(ALCsdl2Backend *self) +{ + SDL_PauseAudioDevice(self->deviceID, 1); +} + +static void ALCsdl2Backend_lock(ALCsdl2Backend *self) +{ + SDL_LockAudioDevice(self->deviceID); +} + +static void ALCsdl2Backend_unlock(ALCsdl2Backend *self) +{ + SDL_UnlockAudioDevice(self->deviceID); +} + + +struct ALCsdl2BackendFactory final : public ALCbackendFactory { + ALCsdl2BackendFactory() noexcept; +}; + +ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void); + +static ALCboolean ALCsdl2BackendFactory_init(ALCsdl2BackendFactory *self); +static void ALCsdl2BackendFactory_deinit(ALCsdl2BackendFactory *self); +static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory *self, ALCbackend_Type type); +static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory *self, enum DevProbe type, al_string *outnames); +static ALCbackend* ALCsdl2BackendFactory_createBackend(ALCsdl2BackendFactory *self, ALCdevice *device, ALCbackend_Type type); +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsdl2BackendFactory); + + +ALCsdl2BackendFactory::ALCsdl2BackendFactory() noexcept + : ALCbackendFactory{GET_VTABLE2(ALCsdl2BackendFactory, ALCbackendFactory)} +{ } + +ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void) +{ + static ALCsdl2BackendFactory factory{}; + return STATIC_CAST(ALCbackendFactory, &factory); +} + + +static ALCboolean ALCsdl2BackendFactory_init(ALCsdl2BackendFactory* UNUSED(self)) +{ + if(SDL_InitSubSystem(SDL_INIT_AUDIO) == 0) + return AL_TRUE; + return ALC_FALSE; +} + +static void ALCsdl2BackendFactory_deinit(ALCsdl2BackendFactory* UNUSED(self)) +{ + SDL_QuitSubSystem(SDL_INIT_AUDIO); +} + +static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + return ALC_TRUE; + return ALC_FALSE; +} + +static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +{ + if(type != ALL_DEVICE_PROBE) + return; + + int num_devices{SDL_GetNumAudioDevices(SDL_FALSE)}; + + alstr_append_range(outnames, defaultDeviceName, defaultDeviceName+sizeof(defaultDeviceName)); + for(int i{0};i < num_devices;++i) + { + std::string name{DEVNAME_PREFIX}; + name += SDL_GetAudioDeviceName(i, SDL_FALSE); + if(!name.empty()) + { + const char *namestr{name.c_str()}; + alstr_append_range(outnames, namestr, namestr+name.length()+1); + } + } +} + +static ALCbackend* ALCsdl2BackendFactory_createBackend(ALCsdl2BackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCsdl2Backend *backend; + NEW_OBJ(backend, ALCsdl2Backend)(device); + if(!backend) return nullptr; + return STATIC_CAST(ALCbackend, backend); + } + + return nullptr; +} diff --git a/CMakeLists.txt b/CMakeLists.txt index ff8d6149..a2ebccdb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1292,7 +1292,7 @@ IF(SDL2_FOUND) OPTION(ALSOFT_BACKEND_SDL2 "Enable SDL2 backend" OFF) IF(ALSOFT_BACKEND_SDL2) SET(HAVE_SDL2 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/sdl2.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/sdl2.cpp) SET(BACKENDS "${BACKENDS} SDL2,") SET(EXTRA_LIBS ${SDL2_LIBRARY} ${EXTRA_LIBS}) SET(INC_PATHS ${INC_PATHS} ${SDL2_INCLUDE_DIR}) -- cgit v1.2.3 From efae7bfb72de4e354457345a4f2474083fd6b9d6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Nov 2018 23:06:31 -0800 Subject: Convert the Solaris backend to C++ --- Alc/backends/solaris.c | 360 ---------------------------------------------- Alc/backends/solaris.cpp | 363 +++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 364 insertions(+), 361 deletions(-) delete mode 100644 Alc/backends/solaris.c create mode 100644 Alc/backends/solaris.cpp diff --git a/Alc/backends/solaris.c b/Alc/backends/solaris.c deleted file mode 100644 index 71282204..00000000 --- a/Alc/backends/solaris.c +++ /dev/null @@ -1,360 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "alMain.h" -#include "alu.h" -#include "alconfig.h" -#include "threads.h" -#include "compat.h" - -#include "backends/base.h" - -#include - - -typedef struct ALCsolarisBackend { - DERIVE_FROM_TYPE(ALCbackend); - - int fd; - - ALubyte *mix_data; - int data_size; - - ATOMIC(ALenum) killNow; - althrd_t thread; -} ALCsolarisBackend; - -static int ALCsolarisBackend_mixerProc(void *ptr); - -static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *device); -static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self); -static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *name); -static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self); -static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self); -static void ALCsolarisBackend_stop(ALCsolarisBackend *self); -static DECLARE_FORWARD2(ALCsolarisBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCsolarisBackend) - -DEFINE_ALCBACKEND_VTABLE(ALCsolarisBackend); - - -static const ALCchar solaris_device[] = "Solaris Default"; - -static const char *solaris_driver = "/dev/audio"; - - -static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCsolarisBackend, ALCbackend, self); - - self->fd = -1; - self->mix_data = NULL; - ATOMIC_INIT(&self->killNow, AL_FALSE); -} - -static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self) -{ - if(self->fd != -1) - close(self->fd); - self->fd = -1; - - free(self->mix_data); - self->mix_data = NULL; - self->data_size = 0; - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -static int ALCsolarisBackend_mixerProc(void *ptr) -{ - ALCsolarisBackend *self = ptr; - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - struct timeval timeout; - ALubyte *write_ptr; - ALint frame_size; - ALint to_write; - ssize_t wrote; - fd_set wfds; - int sret; - - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - - ALCsolarisBackend_lock(self); - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) - { - FD_ZERO(&wfds); - FD_SET(self->fd, &wfds); - timeout.tv_sec = 1; - timeout.tv_usec = 0; - - ALCsolarisBackend_unlock(self); - sret = select(self->fd+1, NULL, &wfds, NULL, &timeout); - ALCsolarisBackend_lock(self); - if(sret < 0) - { - if(errno == EINTR) - continue; - ERR("select failed: %s\n", strerror(errno)); - aluHandleDisconnect(device, "Failed to wait for playback buffer: %s", strerror(errno)); - break; - } - else if(sret == 0) - { - WARN("select timeout\n"); - continue; - } - - write_ptr = self->mix_data; - to_write = self->data_size; - aluMixData(device, write_ptr, to_write/frame_size); - while(to_write > 0 && !ATOMIC_LOAD_SEQ(&self->killNow)) - { - wrote = write(self->fd, write_ptr, to_write); - if(wrote < 0) - { - if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) - continue; - ERR("write failed: %s\n", strerror(errno)); - aluHandleDisconnect(device, "Failed to write playback samples: %s", - strerror(errno)); - break; - } - - to_write -= wrote; - write_ptr += wrote; - } - } - ALCsolarisBackend_unlock(self); - - return 0; -} - - -static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *name) -{ - ALCdevice *device; - - if(!name) - name = solaris_device; - else if(strcmp(name, solaris_device) != 0) - return ALC_INVALID_VALUE; - - self->fd = open(solaris_driver, O_WRONLY); - if(self->fd == -1) - { - ERR("Could not open %s: %s\n", solaris_driver, strerror(errno)); - return ALC_INVALID_VALUE; - } - - device = STATIC_CAST(ALCbackend,self)->mDevice; - alstr_copy_cstr(&device->DeviceName, name); - - return ALC_NO_ERROR; -} - -static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - audio_info_t info; - ALsizei frameSize; - ALsizei numChannels; - - AUDIO_INITINFO(&info); - - info.play.sample_rate = device->Frequency; - - if(device->FmtChans != DevFmtMono) - device->FmtChans = DevFmtStereo; - numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - info.play.channels = numChannels; - - switch(device->FmtType) - { - case DevFmtByte: - info.play.precision = 8; - info.play.encoding = AUDIO_ENCODING_LINEAR; - break; - case DevFmtUByte: - info.play.precision = 8; - info.play.encoding = AUDIO_ENCODING_LINEAR8; - break; - case DevFmtUShort: - case DevFmtInt: - case DevFmtUInt: - case DevFmtFloat: - device->FmtType = DevFmtShort; - /* fall-through */ - case DevFmtShort: - info.play.precision = 16; - info.play.encoding = AUDIO_ENCODING_LINEAR; - break; - } - - frameSize = numChannels * BytesFromDevFmt(device->FmtType); - info.play.buffer_size = device->UpdateSize*device->NumUpdates * frameSize; - - if(ioctl(self->fd, AUDIO_SETINFO, &info) < 0) - { - ERR("ioctl failed: %s\n", strerror(errno)); - return ALC_FALSE; - } - - if(ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != (ALsizei)info.play.channels) - { - ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(device->FmtChans), info.play.channels); - return ALC_FALSE; - } - - if(!((info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR8 && device->FmtType == DevFmtUByte) || - (info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtByte) || - (info.play.precision == 16 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtShort) || - (info.play.precision == 32 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtInt))) - { - ERR("Could not set %s samples, got %d (0x%x)\n", DevFmtTypeString(device->FmtType), - info.play.precision, info.play.encoding); - return ALC_FALSE; - } - - device->Frequency = info.play.sample_rate; - device->UpdateSize = (info.play.buffer_size/device->NumUpdates) + 1; - - SetDefaultChannelOrder(device); - - free(self->mix_data); - self->data_size = device->UpdateSize * FrameSizeFromDevFmt( - device->FmtChans, device->FmtType, device->AmbiOrder - ); - self->mix_data = calloc(1, self->data_size); - - return ALC_TRUE; -} - -static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self) -{ - ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE); - if(althrd_create(&self->thread, ALCsolarisBackend_mixerProc, self) != althrd_success) - return ALC_FALSE; - return ALC_TRUE; -} - -static void ALCsolarisBackend_stop(ALCsolarisBackend *self) -{ - int res; - - if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE)) - return; - - althrd_join(self->thread, &res); - - if(ioctl(self->fd, AUDIO_DRAIN) < 0) - ERR("Error draining device: %s\n", strerror(errno)); -} - - -typedef struct ALCsolarisBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCsolarisBackendFactory; -#define ALCSOLARISBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCsolarisBackendFactory, ALCbackendFactory) } } - -ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void); - -static ALCboolean ALCsolarisBackendFactory_init(ALCsolarisBackendFactory *self); -static DECLARE_FORWARD(ALCsolarisBackendFactory, ALCbackendFactory, void, deinit) -static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory *self, ALCbackend_Type type); -static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory *self, enum DevProbe type, al_string *outnames); -static ALCbackend* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsolarisBackendFactory); - - -ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void) -{ - static ALCsolarisBackendFactory factory = ALCSOLARISBACKENDFACTORY_INITIALIZER; - return STATIC_CAST(ALCbackendFactory, &factory); -} - - -static ALCboolean ALCsolarisBackendFactory_init(ALCsolarisBackendFactory* UNUSED(self)) -{ - ConfigValueStr(NULL, "solaris", "device", &solaris_driver); - return ALC_TRUE; -} - -static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - return ALC_TRUE; - return ALC_FALSE; -} - -static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) -{ - switch(type) - { - case ALL_DEVICE_PROBE: - { -#ifdef HAVE_STAT - struct stat buf; - if(stat(solaris_driver, &buf) == 0) -#endif - alstr_append_range(outnames, solaris_device, solaris_device+sizeof(solaris_device)); - } - break; - - case CAPTURE_DEVICE_PROBE: - break; - } -} - -ALCbackend* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - { - ALCsolarisBackend *backend; - NEW_OBJ(backend, ALCsolarisBackend)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp new file mode 100644 index 00000000..953163fd --- /dev/null +++ b/Alc/backends/solaris.cpp @@ -0,0 +1,363 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "alMain.h" +#include "alu.h" +#include "alconfig.h" +#include "threads.h" +#include "compat.h" + +#include "backends/base.h" + +#include + + +struct ALCsolarisBackend final : public ALCbackend { + int fd; + + ALubyte *mix_data; + int data_size; + + ATOMIC(ALenum) killNow; + althrd_t thread; +}; + +static int ALCsolarisBackend_mixerProc(void *ptr); + +static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *device); +static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self); +static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *name); +static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self); +static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self); +static void ALCsolarisBackend_stop(ALCsolarisBackend *self); +static DECLARE_FORWARD2(ALCsolarisBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCsolarisBackend) + +DEFINE_ALCBACKEND_VTABLE(ALCsolarisBackend); + + +static const ALCchar solaris_device[] = "Solaris Default"; + +static const char *solaris_driver = "/dev/audio"; + + +static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *device) +{ + new (self) ALCsolarisBackend{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCsolarisBackend, ALCbackend, self); + + self->fd = -1; + self->mix_data = nullptr; + ATOMIC_INIT(&self->killNow, AL_FALSE); +} + +static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self) +{ + if(self->fd != -1) + close(self->fd); + self->fd = -1; + + free(self->mix_data); + self->mix_data = nullptr; + self->data_size = 0; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCsolarisBackend(); +} + + +static int ALCsolarisBackend_mixerProc(void *ptr) +{ + ALCsolarisBackend *self = static_cast(ptr); + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + struct timeval timeout; + ALubyte *write_ptr; + ALint frame_size; + ALint to_write; + ssize_t wrote; + fd_set wfds; + int sret; + + SetRTPriority(); + althrd_setname(althrd_current(), MIXER_THREAD_NAME); + + frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + + ALCsolarisBackend_lock(self); + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + { + FD_ZERO(&wfds); + FD_SET(self->fd, &wfds); + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + ALCsolarisBackend_unlock(self); + sret = select(self->fd+1, nullptr, &wfds, nullptr, &timeout); + ALCsolarisBackend_lock(self); + if(sret < 0) + { + if(errno == EINTR) + continue; + ERR("select failed: %s\n", strerror(errno)); + aluHandleDisconnect(device, "Failed to wait for playback buffer: %s", strerror(errno)); + break; + } + else if(sret == 0) + { + WARN("select timeout\n"); + continue; + } + + write_ptr = self->mix_data; + to_write = self->data_size; + aluMixData(device, write_ptr, to_write/frame_size); + while(to_write > 0 && !ATOMIC_LOAD_SEQ(&self->killNow)) + { + wrote = write(self->fd, write_ptr, to_write); + if(wrote < 0) + { + if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) + continue; + ERR("write failed: %s\n", strerror(errno)); + aluHandleDisconnect(device, "Failed to write playback samples: %s", + strerror(errno)); + break; + } + + to_write -= wrote; + write_ptr += wrote; + } + } + ALCsolarisBackend_unlock(self); + + return 0; +} + + +static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *name) +{ + ALCdevice *device; + + if(!name) + name = solaris_device; + else if(strcmp(name, solaris_device) != 0) + return ALC_INVALID_VALUE; + + self->fd = open(solaris_driver, O_WRONLY); + if(self->fd == -1) + { + ERR("Could not open %s: %s\n", solaris_driver, strerror(errno)); + return ALC_INVALID_VALUE; + } + + device = STATIC_CAST(ALCbackend,self)->mDevice; + alstr_copy_cstr(&device->DeviceName, name); + + return ALC_NO_ERROR; +} + +static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + audio_info_t info; + ALsizei frameSize; + ALsizei numChannels; + + AUDIO_INITINFO(&info); + + info.play.sample_rate = device->Frequency; + + if(device->FmtChans != DevFmtMono) + device->FmtChans = DevFmtStereo; + numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + info.play.channels = numChannels; + + switch(device->FmtType) + { + case DevFmtByte: + info.play.precision = 8; + info.play.encoding = AUDIO_ENCODING_LINEAR; + break; + case DevFmtUByte: + info.play.precision = 8; + info.play.encoding = AUDIO_ENCODING_LINEAR8; + break; + case DevFmtUShort: + case DevFmtInt: + case DevFmtUInt: + case DevFmtFloat: + device->FmtType = DevFmtShort; + /* fall-through */ + case DevFmtShort: + info.play.precision = 16; + info.play.encoding = AUDIO_ENCODING_LINEAR; + break; + } + + frameSize = numChannels * BytesFromDevFmt(device->FmtType); + info.play.buffer_size = device->UpdateSize*device->NumUpdates * frameSize; + + if(ioctl(self->fd, AUDIO_SETINFO, &info) < 0) + { + ERR("ioctl failed: %s\n", strerror(errno)); + return ALC_FALSE; + } + + if(ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != (ALsizei)info.play.channels) + { + ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(device->FmtChans), info.play.channels); + return ALC_FALSE; + } + + if(!((info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR8 && device->FmtType == DevFmtUByte) || + (info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtByte) || + (info.play.precision == 16 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtShort) || + (info.play.precision == 32 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtInt))) + { + ERR("Could not set %s samples, got %d (0x%x)\n", DevFmtTypeString(device->FmtType), + info.play.precision, info.play.encoding); + return ALC_FALSE; + } + + device->Frequency = info.play.sample_rate; + device->UpdateSize = (info.play.buffer_size/device->NumUpdates) + 1; + + SetDefaultChannelOrder(device); + + free(self->mix_data); + self->data_size = device->UpdateSize * FrameSizeFromDevFmt( + device->FmtChans, device->FmtType, device->AmbiOrder + ); + self->mix_data = static_cast(calloc(1, self->data_size)); + + return ALC_TRUE; +} + +static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self) +{ + ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE); + if(althrd_create(&self->thread, ALCsolarisBackend_mixerProc, self) != althrd_success) + return ALC_FALSE; + return ALC_TRUE; +} + +static void ALCsolarisBackend_stop(ALCsolarisBackend *self) +{ + int res; + + if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE)) + return; + + althrd_join(self->thread, &res); + + if(ioctl(self->fd, AUDIO_DRAIN) < 0) + ERR("Error draining device: %s\n", strerror(errno)); +} + + +struct ALCsolarisBackendFactory final : public ALCbackendFactory { + ALCsolarisBackendFactory() noexcept; +}; + +ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void); + +static ALCboolean ALCsolarisBackendFactory_init(ALCsolarisBackendFactory *self); +static DECLARE_FORWARD(ALCsolarisBackendFactory, ALCbackendFactory, void, deinit) +static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory *self, ALCbackend_Type type); +static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory *self, enum DevProbe type, al_string *outnames); +static ALCbackend* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory *self, ALCdevice *device, ALCbackend_Type type); +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsolarisBackendFactory); + + +ALCsolarisBackendFactory::ALCsolarisBackendFactory() noexcept + : ALCbackendFactory{GET_VTABLE2(ALCsolarisBackendFactory, ALCbackendFactory)} +{ } + +ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void) +{ + static ALCsolarisBackendFactory factory{}; + return STATIC_CAST(ALCbackendFactory, &factory); +} + + +static ALCboolean ALCsolarisBackendFactory_init(ALCsolarisBackendFactory* UNUSED(self)) +{ + ConfigValueStr(nullptr, "solaris", "device", &solaris_driver); + return ALC_TRUE; +} + +static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + return ALC_TRUE; + return ALC_FALSE; +} + +static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +{ + switch(type) + { + case ALL_DEVICE_PROBE: + { +#ifdef HAVE_STAT + struct stat buf; + if(stat(solaris_driver, &buf) == 0) +#endif + alstr_append_range(outnames, solaris_device, solaris_device+sizeof(solaris_device)); + } + break; + + case CAPTURE_DEVICE_PROBE: + break; + } +} + +ALCbackend* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCsolarisBackend *backend; + NEW_OBJ(backend, ALCsolarisBackend)(device); + if(!backend) return nullptr; + return STATIC_CAST(ALCbackend, backend); + } + + return nullptr; +} diff --git a/CMakeLists.txt b/CMakeLists.txt index a2ebccdb..9ec92f17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1079,7 +1079,7 @@ IF(AUDIOIO_FOUND) IF(ALSOFT_BACKEND_SOLARIS) SET(HAVE_SOLARIS 1) SET(BACKENDS "${BACKENDS} Solaris,") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/solaris.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/solaris.cpp) SET(INC_PATHS ${INC_PATHS} ${AUDIOIO_INCLUDE_DIRS}) ENDIF() ENDIF() -- cgit v1.2.3 From dd9ccde055da78d357acb3b28620858ca5a25e57 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Nov 2018 23:17:27 -0800 Subject: Convert the SoundIO backend to C++ --- Alc/backends/sndio.c | 600 ------------------------------------------------ Alc/backends/sndio.cpp | 603 +++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 604 insertions(+), 601 deletions(-) delete mode 100644 Alc/backends/sndio.c create mode 100644 Alc/backends/sndio.cpp diff --git a/Alc/backends/sndio.c b/Alc/backends/sndio.c deleted file mode 100644 index dd174cba..00000000 --- a/Alc/backends/sndio.c +++ /dev/null @@ -1,600 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include "alMain.h" -#include "alu.h" -#include "threads.h" -#include "ringbuffer.h" - -#include "backends/base.h" - -#include - - -static const ALCchar sndio_device[] = "SndIO Default"; - - -typedef struct SndioPlayback { - DERIVE_FROM_TYPE(ALCbackend); - - struct sio_hdl *sndHandle; - - ALvoid *mix_data; - ALsizei data_size; - - ATOMIC(int) killNow; - althrd_t thread; -} SndioPlayback; - -static int SndioPlayback_mixerProc(void *ptr); - -static void SndioPlayback_Construct(SndioPlayback *self, ALCdevice *device); -static void SndioPlayback_Destruct(SndioPlayback *self); -static ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name); -static ALCboolean SndioPlayback_reset(SndioPlayback *self); -static ALCboolean SndioPlayback_start(SndioPlayback *self); -static void SndioPlayback_stop(SndioPlayback *self); -static DECLARE_FORWARD2(SndioPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(SndioPlayback, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(SndioPlayback, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(SndioPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(SndioPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(SndioPlayback) - -DEFINE_ALCBACKEND_VTABLE(SndioPlayback); - - -static void SndioPlayback_Construct(SndioPlayback *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(SndioPlayback, ALCbackend, self); - - self->sndHandle = NULL; - self->mix_data = NULL; - ATOMIC_INIT(&self->killNow, AL_TRUE); -} - -static void SndioPlayback_Destruct(SndioPlayback *self) -{ - if(self->sndHandle) - sio_close(self->sndHandle); - self->sndHandle = NULL; - - al_free(self->mix_data); - self->mix_data = NULL; - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -static int SndioPlayback_mixerProc(void *ptr) -{ - SndioPlayback *self = (SndioPlayback*)ptr; - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ALsizei frameSize; - size_t wrote; - - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) - { - ALsizei len = self->data_size; - ALubyte *WritePtr = self->mix_data; - - SndioPlayback_lock(self); - aluMixData(device, WritePtr, len/frameSize); - SndioPlayback_unlock(self); - while(len > 0 && !ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) - { - wrote = sio_write(self->sndHandle, WritePtr, len); - if(wrote == 0) - { - ERR("sio_write failed\n"); - ALCdevice_Lock(device); - aluHandleDisconnect(device, "Failed to write playback samples"); - ALCdevice_Unlock(device); - break; - } - - len -= wrote; - WritePtr += wrote; - } - } - - return 0; -} - - -static ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - - if(!name) - name = sndio_device; - else if(strcmp(name, sndio_device) != 0) - return ALC_INVALID_VALUE; - - self->sndHandle = sio_open(NULL, SIO_PLAY, 0); - if(self->sndHandle == NULL) - { - ERR("Could not open device\n"); - return ALC_INVALID_VALUE; - } - - alstr_copy_cstr(&device->DeviceName, name); - - return ALC_NO_ERROR; -} - -static ALCboolean SndioPlayback_reset(SndioPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - struct sio_par par; - - sio_initpar(&par); - - par.rate = device->Frequency; - par.pchan = ((device->FmtChans != DevFmtMono) ? 2 : 1); - - switch(device->FmtType) - { - case DevFmtByte: - par.bits = 8; - par.sig = 1; - break; - case DevFmtUByte: - par.bits = 8; - par.sig = 0; - break; - case DevFmtFloat: - case DevFmtShort: - par.bits = 16; - par.sig = 1; - break; - case DevFmtUShort: - par.bits = 16; - par.sig = 0; - break; - case DevFmtInt: - par.bits = 32; - par.sig = 1; - break; - case DevFmtUInt: - par.bits = 32; - par.sig = 0; - break; - } - par.le = SIO_LE_NATIVE; - - par.round = device->UpdateSize; - par.appbufsz = device->UpdateSize * (device->NumUpdates-1); - if(!par.appbufsz) par.appbufsz = device->UpdateSize; - - if(!sio_setpar(self->sndHandle, &par) || !sio_getpar(self->sndHandle, &par)) - { - ERR("Failed to set device parameters\n"); - return ALC_FALSE; - } - - if(par.bits != par.bps*8) - { - ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8); - return ALC_FALSE; - } - - device->Frequency = par.rate; - device->FmtChans = ((par.pchan==1) ? DevFmtMono : DevFmtStereo); - - if(par.bits == 8 && par.sig == 1) - device->FmtType = DevFmtByte; - else if(par.bits == 8 && par.sig == 0) - device->FmtType = DevFmtUByte; - else if(par.bits == 16 && par.sig == 1) - device->FmtType = DevFmtShort; - else if(par.bits == 16 && par.sig == 0) - device->FmtType = DevFmtUShort; - else if(par.bits == 32 && par.sig == 1) - device->FmtType = DevFmtInt; - else if(par.bits == 32 && par.sig == 0) - device->FmtType = DevFmtUInt; - else - { - ERR("Unhandled sample format: %s %u-bit\n", (par.sig?"signed":"unsigned"), par.bits); - return ALC_FALSE; - } - - device->UpdateSize = par.round; - device->NumUpdates = (par.bufsz/par.round) + 1; - - SetDefaultChannelOrder(device); - - return ALC_TRUE; -} - -static ALCboolean SndioPlayback_start(SndioPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - - self->data_size = device->UpdateSize * FrameSizeFromDevFmt( - device->FmtChans, device->FmtType, device->AmbiOrder - ); - al_free(self->mix_data); - self->mix_data = al_calloc(16, self->data_size); - - if(!sio_start(self->sndHandle)) - { - ERR("Error starting playback\n"); - return ALC_FALSE; - } - - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); - if(althrd_create(&self->thread, SndioPlayback_mixerProc, self) != althrd_success) - { - sio_stop(self->sndHandle); - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static void SndioPlayback_stop(SndioPlayback *self) -{ - int res; - - if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) - return; - althrd_join(self->thread, &res); - - if(!sio_stop(self->sndHandle)) - ERR("Error stopping device\n"); - - al_free(self->mix_data); - self->mix_data = NULL; -} - - -typedef struct SndioCapture { - DERIVE_FROM_TYPE(ALCbackend); - - struct sio_hdl *sndHandle; - - ll_ringbuffer_t *ring; - - ATOMIC(int) killNow; - althrd_t thread; -} SndioCapture; - -static int SndioCapture_recordProc(void *ptr); - -static void SndioCapture_Construct(SndioCapture *self, ALCdevice *device); -static void SndioCapture_Destruct(SndioCapture *self); -static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name); -static DECLARE_FORWARD(SndioCapture, ALCbackend, ALCboolean, reset) -static ALCboolean SndioCapture_start(SndioCapture *self); -static void SndioCapture_stop(SndioCapture *self); -static ALCenum SndioCapture_captureSamples(SndioCapture *self, void *buffer, ALCuint samples); -static ALCuint SndioCapture_availableSamples(SndioCapture *self); -static DECLARE_FORWARD(SndioCapture, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(SndioCapture, ALCbackend, void, lock) -static DECLARE_FORWARD(SndioCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(SndioCapture) - -DEFINE_ALCBACKEND_VTABLE(SndioCapture); - - -static void SndioCapture_Construct(SndioCapture *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(SndioCapture, ALCbackend, self); - - self->sndHandle = NULL; - self->ring = NULL; - ATOMIC_INIT(&self->killNow, AL_TRUE); -} - -static void SndioCapture_Destruct(SndioCapture *self) -{ - if(self->sndHandle) - sio_close(self->sndHandle); - self->sndHandle = NULL; - - ll_ringbuffer_free(self->ring); - self->ring = NULL; - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -static int SndioCapture_recordProc(void* ptr) -{ - SndioCapture *self = (SndioCapture*)ptr; - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ALsizei frameSize; - - SetRTPriority(); - althrd_setname(althrd_current(), RECORD_THREAD_NAME); - - frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) - { - ll_ringbuffer_data_t data[2]; - size_t total, todo; - - ll_ringbuffer_get_write_vector(self->ring, data); - todo = data[0].len + data[1].len; - if(todo == 0) - { - static char junk[4096]; - sio_read(self->sndHandle, junk, minz(sizeof(junk)/frameSize, device->UpdateSize)*frameSize); - continue; - } - - total = 0; - data[0].len *= frameSize; - data[1].len *= frameSize; - todo = minz(todo, device->UpdateSize) * frameSize; - while(total < todo) - { - size_t got; - - if(!data[0].len) - data[0] = data[1]; - - got = sio_read(self->sndHandle, data[0].buf, minz(todo-total, data[0].len)); - if(!got) - { - SndioCapture_lock(self); - aluHandleDisconnect(device, "Failed to read capture samples"); - SndioCapture_unlock(self); - break; - } - - data[0].buf += got; - data[0].len -= got; - total += got; - } - ll_ringbuffer_write_advance(self->ring, total / frameSize); - } - - return 0; -} - - -static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - struct sio_par par; - - if(!name) - name = sndio_device; - else if(strcmp(name, sndio_device) != 0) - return ALC_INVALID_VALUE; - - self->sndHandle = sio_open(NULL, SIO_REC, 0); - if(self->sndHandle == NULL) - { - ERR("Could not open device\n"); - return ALC_INVALID_VALUE; - } - - sio_initpar(&par); - - switch(device->FmtType) - { - case DevFmtByte: - par.bps = 1; - par.sig = 1; - break; - case DevFmtUByte: - par.bps = 1; - par.sig = 0; - break; - case DevFmtShort: - par.bps = 2; - par.sig = 1; - break; - case DevFmtUShort: - par.bps = 2; - par.sig = 0; - break; - case DevFmtInt: - par.bps = 4; - par.sig = 1; - break; - case DevFmtUInt: - par.bps = 4; - par.sig = 0; - break; - case DevFmtFloat: - ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); - return ALC_INVALID_VALUE; - } - par.bits = par.bps * 8; - par.le = SIO_LE_NATIVE; - par.msb = SIO_LE_NATIVE ? 0 : 1; - par.rchan = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - par.rate = device->Frequency; - - par.appbufsz = maxu(device->UpdateSize*device->NumUpdates, (device->Frequency+9)/10); - par.round = clampu(par.appbufsz/device->NumUpdates, (device->Frequency+99)/100, - (device->Frequency+19)/20); - - device->UpdateSize = par.round; - device->NumUpdates = maxu(par.appbufsz/par.round, 1); - - if(!sio_setpar(self->sndHandle, &par) || !sio_getpar(self->sndHandle, &par)) - { - ERR("Failed to set device parameters\n"); - return ALC_INVALID_VALUE; - } - - if(par.bits != par.bps*8) - { - ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8); - return ALC_INVALID_VALUE; - } - - if(!((device->FmtType == DevFmtByte && par.bits == 8 && par.sig != 0) || - (device->FmtType == DevFmtUByte && par.bits == 8 && par.sig == 0) || - (device->FmtType == DevFmtShort && par.bits == 16 && par.sig != 0) || - (device->FmtType == DevFmtUShort && par.bits == 16 && par.sig == 0) || - (device->FmtType == DevFmtInt && par.bits == 32 && par.sig != 0) || - (device->FmtType == DevFmtUInt && par.bits == 32 && par.sig == 0)) || - ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != (ALsizei)par.rchan || - device->Frequency != par.rate) - { - ERR("Failed to set format %s %s %uhz, got %c%u %u-channel %uhz instead\n", - DevFmtTypeString(device->FmtType), DevFmtChannelsString(device->FmtChans), - device->Frequency, par.sig?'s':'u', par.bits, par.rchan, par.rate); - return ALC_INVALID_VALUE; - } - - self->ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, par.bps*par.rchan, 0); - if(!self->ring) - { - ERR("Failed to allocate %u-byte ringbuffer\n", - device->UpdateSize*device->NumUpdates*par.bps*par.rchan); - return ALC_OUT_OF_MEMORY; - } - - SetDefaultChannelOrder(device); - - alstr_copy_cstr(&device->DeviceName, name); - - return ALC_NO_ERROR; -} - -static ALCboolean SndioCapture_start(SndioCapture *self) -{ - if(!sio_start(self->sndHandle)) - { - ERR("Error starting playback\n"); - return ALC_FALSE; - } - - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); - if(althrd_create(&self->thread, SndioCapture_recordProc, self) != althrd_success) - { - sio_stop(self->sndHandle); - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static void SndioCapture_stop(SndioCapture *self) -{ - int res; - - if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) - return; - althrd_join(self->thread, &res); - - if(!sio_stop(self->sndHandle)) - ERR("Error stopping device\n"); -} - -static ALCenum SndioCapture_captureSamples(SndioCapture *self, void *buffer, ALCuint samples) -{ - ll_ringbuffer_read(self->ring, buffer, samples); - return ALC_NO_ERROR; -} - -static ALCuint SndioCapture_availableSamples(SndioCapture *self) -{ - return ll_ringbuffer_read_space(self->ring); -} - - -typedef struct SndioBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} SndioBackendFactory; -#define SNDIOBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(SndioBackendFactory, ALCbackendFactory) } } - -ALCbackendFactory *SndioBackendFactory_getFactory(void); - -static ALCboolean SndioBackendFactory_init(SndioBackendFactory *self); -static DECLARE_FORWARD(SndioBackendFactory, ALCbackendFactory, void, deinit) -static ALCboolean SndioBackendFactory_querySupport(SndioBackendFactory *self, ALCbackend_Type type); -static void SndioBackendFactory_probe(SndioBackendFactory *self, enum DevProbe type, al_string *outnames); -static ALCbackend* SndioBackendFactory_createBackend(SndioBackendFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(SndioBackendFactory); - -ALCbackendFactory *SndioBackendFactory_getFactory(void) -{ - static SndioBackendFactory factory = SNDIOBACKENDFACTORY_INITIALIZER; - return STATIC_CAST(ALCbackendFactory, &factory); -} - -static ALCboolean SndioBackendFactory_init(SndioBackendFactory* UNUSED(self)) -{ - /* No dynamic loading */ - return ALC_TRUE; -} - -static ALCboolean SndioBackendFactory_querySupport(SndioBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} - -static void SndioBackendFactory_probe(SndioBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) -{ - switch(type) - { - case ALL_DEVICE_PROBE: - case CAPTURE_DEVICE_PROBE: - alstr_append_range(outnames, sndio_device, sndio_device+sizeof(sndio_device)); - break; - } -} - -static ALCbackend* SndioBackendFactory_createBackend(SndioBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - { - SndioPlayback *backend; - NEW_OBJ(backend, SndioPlayback)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - if(type == ALCbackend_Capture) - { - SndioCapture *backend; - NEW_OBJ(backend, SndioCapture)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp new file mode 100644 index 00000000..e35ce34e --- /dev/null +++ b/Alc/backends/sndio.cpp @@ -0,0 +1,603 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include "alMain.h" +#include "alu.h" +#include "threads.h" +#include "ringbuffer.h" + +#include "backends/base.h" + +#include + + +static const ALCchar sndio_device[] = "SndIO Default"; + + +struct SndioPlayback final : public ALCbackend { + struct sio_hdl *sndHandle; + + ALvoid *mix_data; + ALsizei data_size; + + ATOMIC(int) killNow; + althrd_t thread; +}; + +static int SndioPlayback_mixerProc(void *ptr); + +static void SndioPlayback_Construct(SndioPlayback *self, ALCdevice *device); +static void SndioPlayback_Destruct(SndioPlayback *self); +static ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name); +static ALCboolean SndioPlayback_reset(SndioPlayback *self); +static ALCboolean SndioPlayback_start(SndioPlayback *self); +static void SndioPlayback_stop(SndioPlayback *self); +static DECLARE_FORWARD2(SndioPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +static DECLARE_FORWARD(SndioPlayback, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(SndioPlayback, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(SndioPlayback, ALCbackend, void, lock) +static DECLARE_FORWARD(SndioPlayback, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(SndioPlayback) + +DEFINE_ALCBACKEND_VTABLE(SndioPlayback); + + +static void SndioPlayback_Construct(SndioPlayback *self, ALCdevice *device) +{ + new (self) SndioPlayback{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(SndioPlayback, ALCbackend, self); + + self->sndHandle = nullptr; + self->mix_data = nullptr; + ATOMIC_INIT(&self->killNow, AL_TRUE); +} + +static void SndioPlayback_Destruct(SndioPlayback *self) +{ + if(self->sndHandle) + sio_close(self->sndHandle); + self->sndHandle = nullptr; + + al_free(self->mix_data); + self->mix_data = nullptr; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~SndioPlayback(); +} + + +static int SndioPlayback_mixerProc(void *ptr) +{ + SndioPlayback *self = static_cast(ptr); + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALsizei frameSize; + size_t wrote; + + SetRTPriority(); + althrd_setname(althrd_current(), MIXER_THREAD_NAME); + + frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + { + ALsizei len = self->data_size; + ALubyte *WritePtr = static_cast(self->mix_data); + + SndioPlayback_lock(self); + aluMixData(device, WritePtr, len/frameSize); + SndioPlayback_unlock(self); + while(len > 0 && !ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) + { + wrote = sio_write(self->sndHandle, WritePtr, len); + if(wrote == 0) + { + ERR("sio_write failed\n"); + ALCdevice_Lock(device); + aluHandleDisconnect(device, "Failed to write playback samples"); + ALCdevice_Unlock(device); + break; + } + + len -= wrote; + WritePtr += wrote; + } + } + + return 0; +} + + +static ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + + if(!name) + name = sndio_device; + else if(strcmp(name, sndio_device) != 0) + return ALC_INVALID_VALUE; + + self->sndHandle = sio_open(nullptr, SIO_PLAY, 0); + if(self->sndHandle == nullptr) + { + ERR("Could not open device\n"); + return ALC_INVALID_VALUE; + } + + alstr_copy_cstr(&device->DeviceName, name); + + return ALC_NO_ERROR; +} + +static ALCboolean SndioPlayback_reset(SndioPlayback *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + struct sio_par par; + + sio_initpar(&par); + + par.rate = device->Frequency; + par.pchan = ((device->FmtChans != DevFmtMono) ? 2 : 1); + + switch(device->FmtType) + { + case DevFmtByte: + par.bits = 8; + par.sig = 1; + break; + case DevFmtUByte: + par.bits = 8; + par.sig = 0; + break; + case DevFmtFloat: + case DevFmtShort: + par.bits = 16; + par.sig = 1; + break; + case DevFmtUShort: + par.bits = 16; + par.sig = 0; + break; + case DevFmtInt: + par.bits = 32; + par.sig = 1; + break; + case DevFmtUInt: + par.bits = 32; + par.sig = 0; + break; + } + par.le = SIO_LE_NATIVE; + + par.round = device->UpdateSize; + par.appbufsz = device->UpdateSize * (device->NumUpdates-1); + if(!par.appbufsz) par.appbufsz = device->UpdateSize; + + if(!sio_setpar(self->sndHandle, &par) || !sio_getpar(self->sndHandle, &par)) + { + ERR("Failed to set device parameters\n"); + return ALC_FALSE; + } + + if(par.bits != par.bps*8) + { + ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8); + return ALC_FALSE; + } + + device->Frequency = par.rate; + device->FmtChans = ((par.pchan==1) ? DevFmtMono : DevFmtStereo); + + if(par.bits == 8 && par.sig == 1) + device->FmtType = DevFmtByte; + else if(par.bits == 8 && par.sig == 0) + device->FmtType = DevFmtUByte; + else if(par.bits == 16 && par.sig == 1) + device->FmtType = DevFmtShort; + else if(par.bits == 16 && par.sig == 0) + device->FmtType = DevFmtUShort; + else if(par.bits == 32 && par.sig == 1) + device->FmtType = DevFmtInt; + else if(par.bits == 32 && par.sig == 0) + device->FmtType = DevFmtUInt; + else + { + ERR("Unhandled sample format: %s %u-bit\n", (par.sig?"signed":"unsigned"), par.bits); + return ALC_FALSE; + } + + device->UpdateSize = par.round; + device->NumUpdates = (par.bufsz/par.round) + 1; + + SetDefaultChannelOrder(device); + + return ALC_TRUE; +} + +static ALCboolean SndioPlayback_start(SndioPlayback *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + + self->data_size = device->UpdateSize * FrameSizeFromDevFmt( + device->FmtChans, device->FmtType, device->AmbiOrder + ); + al_free(self->mix_data); + self->mix_data = al_calloc(16, self->data_size); + + if(!sio_start(self->sndHandle)) + { + ERR("Error starting playback\n"); + return ALC_FALSE; + } + + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); + if(althrd_create(&self->thread, SndioPlayback_mixerProc, self) != althrd_success) + { + sio_stop(self->sndHandle); + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static void SndioPlayback_stop(SndioPlayback *self) +{ + int res; + + if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) + return; + althrd_join(self->thread, &res); + + if(!sio_stop(self->sndHandle)) + ERR("Error stopping device\n"); + + al_free(self->mix_data); + self->mix_data = nullptr; +} + + +struct SndioCapture final : public ALCbackend { + struct sio_hdl *sndHandle; + + ll_ringbuffer_t *ring; + + ATOMIC(int) killNow; + althrd_t thread; +}; + +static int SndioCapture_recordProc(void *ptr); + +static void SndioCapture_Construct(SndioCapture *self, ALCdevice *device); +static void SndioCapture_Destruct(SndioCapture *self); +static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name); +static DECLARE_FORWARD(SndioCapture, ALCbackend, ALCboolean, reset) +static ALCboolean SndioCapture_start(SndioCapture *self); +static void SndioCapture_stop(SndioCapture *self); +static ALCenum SndioCapture_captureSamples(SndioCapture *self, void *buffer, ALCuint samples); +static ALCuint SndioCapture_availableSamples(SndioCapture *self); +static DECLARE_FORWARD(SndioCapture, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(SndioCapture, ALCbackend, void, lock) +static DECLARE_FORWARD(SndioCapture, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(SndioCapture) + +DEFINE_ALCBACKEND_VTABLE(SndioCapture); + + +static void SndioCapture_Construct(SndioCapture *self, ALCdevice *device) +{ + new (self) SndioCapture{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(SndioCapture, ALCbackend, self); + + self->sndHandle = nullptr; + self->ring = nullptr; + ATOMIC_INIT(&self->killNow, AL_TRUE); +} + +static void SndioCapture_Destruct(SndioCapture *self) +{ + if(self->sndHandle) + sio_close(self->sndHandle); + self->sndHandle = nullptr; + + ll_ringbuffer_free(self->ring); + self->ring = nullptr; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~SndioCapture(); +} + + +static int SndioCapture_recordProc(void* ptr) +{ + SndioCapture *self = static_cast(ptr); + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALsizei frameSize; + + SetRTPriority(); + althrd_setname(althrd_current(), RECORD_THREAD_NAME); + + frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + { + ll_ringbuffer_data_t data[2]; + size_t total, todo; + + ll_ringbuffer_get_write_vector(self->ring, data); + todo = data[0].len + data[1].len; + if(todo == 0) + { + static char junk[4096]; + sio_read(self->sndHandle, junk, minz(sizeof(junk)/frameSize, device->UpdateSize)*frameSize); + continue; + } + + total = 0; + data[0].len *= frameSize; + data[1].len *= frameSize; + todo = minz(todo, device->UpdateSize) * frameSize; + while(total < todo) + { + size_t got; + + if(!data[0].len) + data[0] = data[1]; + + got = sio_read(self->sndHandle, data[0].buf, minz(todo-total, data[0].len)); + if(!got) + { + SndioCapture_lock(self); + aluHandleDisconnect(device, "Failed to read capture samples"); + SndioCapture_unlock(self); + break; + } + + data[0].buf += got; + data[0].len -= got; + total += got; + } + ll_ringbuffer_write_advance(self->ring, total / frameSize); + } + + return 0; +} + + +static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + struct sio_par par; + + if(!name) + name = sndio_device; + else if(strcmp(name, sndio_device) != 0) + return ALC_INVALID_VALUE; + + self->sndHandle = sio_open(nullptr, SIO_REC, 0); + if(self->sndHandle == nullptr) + { + ERR("Could not open device\n"); + return ALC_INVALID_VALUE; + } + + sio_initpar(&par); + + switch(device->FmtType) + { + case DevFmtByte: + par.bps = 1; + par.sig = 1; + break; + case DevFmtUByte: + par.bps = 1; + par.sig = 0; + break; + case DevFmtShort: + par.bps = 2; + par.sig = 1; + break; + case DevFmtUShort: + par.bps = 2; + par.sig = 0; + break; + case DevFmtInt: + par.bps = 4; + par.sig = 1; + break; + case DevFmtUInt: + par.bps = 4; + par.sig = 0; + break; + case DevFmtFloat: + ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); + return ALC_INVALID_VALUE; + } + par.bits = par.bps * 8; + par.le = SIO_LE_NATIVE; + par.msb = SIO_LE_NATIVE ? 0 : 1; + par.rchan = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + par.rate = device->Frequency; + + par.appbufsz = maxu(device->UpdateSize*device->NumUpdates, (device->Frequency+9)/10); + par.round = clampu(par.appbufsz/device->NumUpdates, (device->Frequency+99)/100, + (device->Frequency+19)/20); + + device->UpdateSize = par.round; + device->NumUpdates = maxu(par.appbufsz/par.round, 1); + + if(!sio_setpar(self->sndHandle, &par) || !sio_getpar(self->sndHandle, &par)) + { + ERR("Failed to set device parameters\n"); + return ALC_INVALID_VALUE; + } + + if(par.bits != par.bps*8) + { + ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8); + return ALC_INVALID_VALUE; + } + + if(!((device->FmtType == DevFmtByte && par.bits == 8 && par.sig != 0) || + (device->FmtType == DevFmtUByte && par.bits == 8 && par.sig == 0) || + (device->FmtType == DevFmtShort && par.bits == 16 && par.sig != 0) || + (device->FmtType == DevFmtUShort && par.bits == 16 && par.sig == 0) || + (device->FmtType == DevFmtInt && par.bits == 32 && par.sig != 0) || + (device->FmtType == DevFmtUInt && par.bits == 32 && par.sig == 0)) || + ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != (ALsizei)par.rchan || + device->Frequency != par.rate) + { + ERR("Failed to set format %s %s %uhz, got %c%u %u-channel %uhz instead\n", + DevFmtTypeString(device->FmtType), DevFmtChannelsString(device->FmtChans), + device->Frequency, par.sig?'s':'u', par.bits, par.rchan, par.rate); + return ALC_INVALID_VALUE; + } + + self->ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, par.bps*par.rchan, 0); + if(!self->ring) + { + ERR("Failed to allocate %u-byte ringbuffer\n", + device->UpdateSize*device->NumUpdates*par.bps*par.rchan); + return ALC_OUT_OF_MEMORY; + } + + SetDefaultChannelOrder(device); + + alstr_copy_cstr(&device->DeviceName, name); + + return ALC_NO_ERROR; +} + +static ALCboolean SndioCapture_start(SndioCapture *self) +{ + if(!sio_start(self->sndHandle)) + { + ERR("Error starting playback\n"); + return ALC_FALSE; + } + + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); + if(althrd_create(&self->thread, SndioCapture_recordProc, self) != althrd_success) + { + sio_stop(self->sndHandle); + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static void SndioCapture_stop(SndioCapture *self) +{ + int res; + + if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) + return; + althrd_join(self->thread, &res); + + if(!sio_stop(self->sndHandle)) + ERR("Error stopping device\n"); +} + +static ALCenum SndioCapture_captureSamples(SndioCapture *self, void *buffer, ALCuint samples) +{ + ll_ringbuffer_read(self->ring, static_cast(buffer), samples); + return ALC_NO_ERROR; +} + +static ALCuint SndioCapture_availableSamples(SndioCapture *self) +{ + return ll_ringbuffer_read_space(self->ring); +} + + +struct SndioBackendFactory final : public ALCbackendFactory { + SndioBackendFactory() noexcept; +}; + +ALCbackendFactory *SndioBackendFactory_getFactory(void); + +static ALCboolean SndioBackendFactory_init(SndioBackendFactory *self); +static DECLARE_FORWARD(SndioBackendFactory, ALCbackendFactory, void, deinit) +static ALCboolean SndioBackendFactory_querySupport(SndioBackendFactory *self, ALCbackend_Type type); +static void SndioBackendFactory_probe(SndioBackendFactory *self, enum DevProbe type, al_string *outnames); +static ALCbackend* SndioBackendFactory_createBackend(SndioBackendFactory *self, ALCdevice *device, ALCbackend_Type type); +DEFINE_ALCBACKENDFACTORY_VTABLE(SndioBackendFactory); + +SndioBackendFactory::SndioBackendFactory() noexcept + : ALCbackendFactory{GET_VTABLE2(SndioBackendFactory, ALCbackendFactory)} +{ } + +ALCbackendFactory *SndioBackendFactory_getFactory(void) +{ + static SndioBackendFactory factory{}; + return STATIC_CAST(ALCbackendFactory, &factory); +} + +static ALCboolean SndioBackendFactory_init(SndioBackendFactory* UNUSED(self)) +{ + /* No dynamic loading */ + return ALC_TRUE; +} + +static ALCboolean SndioBackendFactory_querySupport(SndioBackendFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Playback || type == ALCbackend_Capture) + return ALC_TRUE; + return ALC_FALSE; +} + +static void SndioBackendFactory_probe(SndioBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +{ + switch(type) + { + case ALL_DEVICE_PROBE: + case CAPTURE_DEVICE_PROBE: + alstr_append_range(outnames, sndio_device, sndio_device+sizeof(sndio_device)); + break; + } +} + +static ALCbackend* SndioBackendFactory_createBackend(SndioBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + SndioPlayback *backend; + NEW_OBJ(backend, SndioPlayback)(device); + if(!backend) return nullptr; + return STATIC_CAST(ALCbackend, backend); + } + if(type == ALCbackend_Capture) + { + SndioCapture *backend; + NEW_OBJ(backend, SndioCapture)(device); + if(!backend) return nullptr; + return STATIC_CAST(ALCbackend, backend); + } + + return nullptr; +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ec92f17..7b4a32b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1095,7 +1095,7 @@ IF(SOUNDIO_FOUND) IF(ALSOFT_BACKEND_SNDIO) SET(HAVE_SNDIO 1) SET(BACKENDS "${BACKENDS} SndIO (linked),") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/sndio.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/sndio.cpp) SET(EXTRA_LIBS ${SOUNDIO_LIBRARIES} ${EXTRA_LIBS}) SET(INC_PATHS ${INC_PATHS} ${SOUNDIO_INCLUDE_DIRS}) ENDIF() -- cgit v1.2.3 From d9a47ab63ceb6947a2ac31ae0c73fbfb7ab845cc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Nov 2018 23:32:11 -0800 Subject: Convert the PortAudio backend to C++ --- Alc/backends/portaudio.c | 557 -------------------------------------------- Alc/backends/portaudio.cpp | 559 +++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 560 insertions(+), 558 deletions(-) delete mode 100644 Alc/backends/portaudio.c create mode 100644 Alc/backends/portaudio.cpp diff --git a/Alc/backends/portaudio.c b/Alc/backends/portaudio.c deleted file mode 100644 index 7bc3c230..00000000 --- a/Alc/backends/portaudio.c +++ /dev/null @@ -1,557 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include "alMain.h" -#include "alu.h" -#include "alconfig.h" -#include "ringbuffer.h" -#include "compat.h" - -#include "backends/base.h" - -#include - - -static const ALCchar pa_device[] = "PortAudio Default"; - - -#ifdef HAVE_DYNLOAD -static void *pa_handle; -#define MAKE_FUNC(x) static __typeof(x) * p##x -MAKE_FUNC(Pa_Initialize); -MAKE_FUNC(Pa_Terminate); -MAKE_FUNC(Pa_GetErrorText); -MAKE_FUNC(Pa_StartStream); -MAKE_FUNC(Pa_StopStream); -MAKE_FUNC(Pa_OpenStream); -MAKE_FUNC(Pa_CloseStream); -MAKE_FUNC(Pa_GetDefaultOutputDevice); -MAKE_FUNC(Pa_GetDefaultInputDevice); -MAKE_FUNC(Pa_GetStreamInfo); -#undef MAKE_FUNC - -#ifndef IN_IDE_PARSER -#define Pa_Initialize pPa_Initialize -#define Pa_Terminate pPa_Terminate -#define Pa_GetErrorText pPa_GetErrorText -#define Pa_StartStream pPa_StartStream -#define Pa_StopStream pPa_StopStream -#define Pa_OpenStream pPa_OpenStream -#define Pa_CloseStream pPa_CloseStream -#define Pa_GetDefaultOutputDevice pPa_GetDefaultOutputDevice -#define Pa_GetDefaultInputDevice pPa_GetDefaultInputDevice -#define Pa_GetStreamInfo pPa_GetStreamInfo -#endif -#endif - -static ALCboolean pa_load(void) -{ - PaError err; - -#ifdef HAVE_DYNLOAD - if(!pa_handle) - { -#ifdef _WIN32 -# define PALIB "portaudio.dll" -#elif defined(__APPLE__) && defined(__MACH__) -# define PALIB "libportaudio.2.dylib" -#elif defined(__OpenBSD__) -# define PALIB "libportaudio.so" -#else -# define PALIB "libportaudio.so.2" -#endif - - pa_handle = LoadLib(PALIB); - if(!pa_handle) - return ALC_FALSE; - -#define LOAD_FUNC(f) do { \ - p##f = GetSymbol(pa_handle, #f); \ - if(p##f == NULL) \ - { \ - CloseLib(pa_handle); \ - pa_handle = NULL; \ - return ALC_FALSE; \ - } \ -} while(0) - LOAD_FUNC(Pa_Initialize); - LOAD_FUNC(Pa_Terminate); - LOAD_FUNC(Pa_GetErrorText); - LOAD_FUNC(Pa_StartStream); - LOAD_FUNC(Pa_StopStream); - LOAD_FUNC(Pa_OpenStream); - LOAD_FUNC(Pa_CloseStream); - LOAD_FUNC(Pa_GetDefaultOutputDevice); - LOAD_FUNC(Pa_GetDefaultInputDevice); - LOAD_FUNC(Pa_GetStreamInfo); -#undef LOAD_FUNC - - if((err=Pa_Initialize()) != paNoError) - { - ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err)); - CloseLib(pa_handle); - pa_handle = NULL; - return ALC_FALSE; - } - } -#else - if((err=Pa_Initialize()) != paNoError) - { - ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err)); - return ALC_FALSE; - } -#endif - return ALC_TRUE; -} - - -typedef struct ALCportPlayback { - DERIVE_FROM_TYPE(ALCbackend); - - PaStream *stream; - PaStreamParameters params; - ALuint update_size; -} ALCportPlayback; - -static int ALCportPlayback_WriteCallback(const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, - const PaStreamCallbackFlags statusFlags, void *userData); - -static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device); -static void ALCportPlayback_Destruct(ALCportPlayback *self); -static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name); -static ALCboolean ALCportPlayback_reset(ALCportPlayback *self); -static ALCboolean ALCportPlayback_start(ALCportPlayback *self); -static void ALCportPlayback_stop(ALCportPlayback *self); -static DECLARE_FORWARD2(ALCportPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCportPlayback) - -DEFINE_ALCBACKEND_VTABLE(ALCportPlayback); - - -static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCportPlayback, ALCbackend, self); - - self->stream = NULL; -} - -static void ALCportPlayback_Destruct(ALCportPlayback *self) -{ - PaError err = self->stream ? Pa_CloseStream(self->stream) : paNoError; - if(err != paNoError) - ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); - self->stream = NULL; - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -static int ALCportPlayback_WriteCallback(const void *UNUSED(inputBuffer), void *outputBuffer, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo), - const PaStreamCallbackFlags UNUSED(statusFlags), void *userData) -{ - ALCportPlayback *self = userData; - - ALCportPlayback_lock(self); - aluMixData(STATIC_CAST(ALCbackend, self)->mDevice, outputBuffer, framesPerBuffer); - ALCportPlayback_unlock(self); - return 0; -} - - -static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - PaError err; - - if(!name) - name = pa_device; - else if(strcmp(name, pa_device) != 0) - return ALC_INVALID_VALUE; - - self->update_size = device->UpdateSize; - - self->params.device = -1; - if(!ConfigValueInt(NULL, "port", "device", &self->params.device) || - self->params.device < 0) - self->params.device = Pa_GetDefaultOutputDevice(); - self->params.suggestedLatency = (device->UpdateSize*device->NumUpdates) / - (float)device->Frequency; - self->params.hostApiSpecificStreamInfo = NULL; - - self->params.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2); - - switch(device->FmtType) - { - case DevFmtByte: - self->params.sampleFormat = paInt8; - break; - case DevFmtUByte: - self->params.sampleFormat = paUInt8; - break; - case DevFmtUShort: - /* fall-through */ - case DevFmtShort: - self->params.sampleFormat = paInt16; - break; - case DevFmtUInt: - /* fall-through */ - case DevFmtInt: - self->params.sampleFormat = paInt32; - break; - case DevFmtFloat: - self->params.sampleFormat = paFloat32; - break; - } - -retry_open: - err = Pa_OpenStream(&self->stream, NULL, &self->params, - device->Frequency, device->UpdateSize, paNoFlag, - ALCportPlayback_WriteCallback, self - ); - if(err != paNoError) - { - if(self->params.sampleFormat == paFloat32) - { - self->params.sampleFormat = paInt16; - goto retry_open; - } - ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); - return ALC_INVALID_VALUE; - } - - alstr_copy_cstr(&device->DeviceName, name); - - return ALC_NO_ERROR; - -} - -static ALCboolean ALCportPlayback_reset(ALCportPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - const PaStreamInfo *streamInfo; - - streamInfo = Pa_GetStreamInfo(self->stream); - device->Frequency = streamInfo->sampleRate; - device->UpdateSize = self->update_size; - - if(self->params.sampleFormat == paInt8) - device->FmtType = DevFmtByte; - else if(self->params.sampleFormat == paUInt8) - device->FmtType = DevFmtUByte; - else if(self->params.sampleFormat == paInt16) - device->FmtType = DevFmtShort; - else if(self->params.sampleFormat == paInt32) - device->FmtType = DevFmtInt; - else if(self->params.sampleFormat == paFloat32) - device->FmtType = DevFmtFloat; - else - { - ERR("Unexpected sample format: 0x%lx\n", self->params.sampleFormat); - return ALC_FALSE; - } - - if(self->params.channelCount == 2) - device->FmtChans = DevFmtStereo; - else if(self->params.channelCount == 1) - device->FmtChans = DevFmtMono; - else - { - ERR("Unexpected channel count: %u\n", self->params.channelCount); - return ALC_FALSE; - } - SetDefaultChannelOrder(device); - - return ALC_TRUE; -} - -static ALCboolean ALCportPlayback_start(ALCportPlayback *self) -{ - PaError err; - - err = Pa_StartStream(self->stream); - if(err != paNoError) - { - ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err)); - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static void ALCportPlayback_stop(ALCportPlayback *self) -{ - PaError err = Pa_StopStream(self->stream); - if(err != paNoError) - ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); -} - - -typedef struct ALCportCapture { - DERIVE_FROM_TYPE(ALCbackend); - - PaStream *stream; - PaStreamParameters params; - - ll_ringbuffer_t *ring; -} ALCportCapture; - -static int ALCportCapture_ReadCallback(const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, - const PaStreamCallbackFlags statusFlags, void *userData); - -static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device); -static void ALCportCapture_Destruct(ALCportCapture *self); -static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name); -static DECLARE_FORWARD(ALCportCapture, ALCbackend, ALCboolean, reset) -static ALCboolean ALCportCapture_start(ALCportCapture *self); -static void ALCportCapture_stop(ALCportCapture *self); -static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples); -static ALCuint ALCportCapture_availableSamples(ALCportCapture *self); -static DECLARE_FORWARD(ALCportCapture, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCportCapture) - -DEFINE_ALCBACKEND_VTABLE(ALCportCapture); - - -static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCportCapture, ALCbackend, self); - - self->stream = NULL; - self->ring = NULL; -} - -static void ALCportCapture_Destruct(ALCportCapture *self) -{ - PaError err = self->stream ? Pa_CloseStream(self->stream) : paNoError; - if(err != paNoError) - ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); - self->stream = NULL; - - ll_ringbuffer_free(self->ring); - self->ring = NULL; - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -static int ALCportCapture_ReadCallback(const void *inputBuffer, void *UNUSED(outputBuffer), - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo), - const PaStreamCallbackFlags UNUSED(statusFlags), void *userData) -{ - ALCportCapture *self = userData; - size_t writable = ll_ringbuffer_write_space(self->ring); - - if(framesPerBuffer > writable) - framesPerBuffer = writable; - ll_ringbuffer_write(self->ring, inputBuffer, framesPerBuffer); - return 0; -} - - -static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ALuint samples, frame_size; - PaError err; - - if(!name) - name = pa_device; - else if(strcmp(name, pa_device) != 0) - return ALC_INVALID_VALUE; - - samples = device->UpdateSize * device->NumUpdates; - samples = maxu(samples, 100 * device->Frequency / 1000); - frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - - self->ring = ll_ringbuffer_create(samples, frame_size, false); - if(self->ring == NULL) return ALC_INVALID_VALUE; - - self->params.device = -1; - if(!ConfigValueInt(NULL, "port", "capture", &self->params.device) || - self->params.device < 0) - self->params.device = Pa_GetDefaultInputDevice(); - self->params.suggestedLatency = 0.0f; - self->params.hostApiSpecificStreamInfo = NULL; - - switch(device->FmtType) - { - case DevFmtByte: - self->params.sampleFormat = paInt8; - break; - case DevFmtUByte: - self->params.sampleFormat = paUInt8; - break; - case DevFmtShort: - self->params.sampleFormat = paInt16; - break; - case DevFmtInt: - self->params.sampleFormat = paInt32; - break; - case DevFmtFloat: - self->params.sampleFormat = paFloat32; - break; - case DevFmtUInt: - case DevFmtUShort: - ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); - return ALC_INVALID_VALUE; - } - self->params.channelCount = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - - err = Pa_OpenStream(&self->stream, &self->params, NULL, - device->Frequency, paFramesPerBufferUnspecified, paNoFlag, - ALCportCapture_ReadCallback, self - ); - if(err != paNoError) - { - ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); - return ALC_INVALID_VALUE; - } - - alstr_copy_cstr(&device->DeviceName, name); - - return ALC_NO_ERROR; -} - - -static ALCboolean ALCportCapture_start(ALCportCapture *self) -{ - PaError err = Pa_StartStream(self->stream); - if(err != paNoError) - { - ERR("Error starting stream: %s\n", Pa_GetErrorText(err)); - return ALC_FALSE; - } - return ALC_TRUE; -} - -static void ALCportCapture_stop(ALCportCapture *self) -{ - PaError err = Pa_StopStream(self->stream); - if(err != paNoError) - ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); -} - - -static ALCuint ALCportCapture_availableSamples(ALCportCapture *self) -{ - return ll_ringbuffer_read_space(self->ring); -} - -static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples) -{ - ll_ringbuffer_read(self->ring, buffer, samples); - return ALC_NO_ERROR; -} - - -typedef struct ALCportBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCportBackendFactory; -#define ALCPORTBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCportBackendFactory, ALCbackendFactory) } } - -static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory *self); -static void ALCportBackendFactory_deinit(ALCportBackendFactory *self); -static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory *self, ALCbackend_Type type); -static void ALCportBackendFactory_probe(ALCportBackendFactory *self, enum DevProbe type, al_string *outnames); -static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCportBackendFactory); - - -static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory* UNUSED(self)) -{ - if(!pa_load()) - return ALC_FALSE; - return ALC_TRUE; -} - -static void ALCportBackendFactory_deinit(ALCportBackendFactory* UNUSED(self)) -{ -#ifdef HAVE_DYNLOAD - if(pa_handle) - { - Pa_Terminate(); - CloseLib(pa_handle); - pa_handle = NULL; - } -#else - Pa_Terminate(); -#endif -} - -static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} - -static void ALCportBackendFactory_probe(ALCportBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) -{ - switch(type) - { - case ALL_DEVICE_PROBE: - case CAPTURE_DEVICE_PROBE: - alstr_append_range(outnames, pa_device, pa_device+sizeof(pa_device)); - break; - } -} - -static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - { - ALCportPlayback *backend; - NEW_OBJ(backend, ALCportPlayback)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - if(type == ALCbackend_Capture) - { - ALCportCapture *backend; - NEW_OBJ(backend, ALCportCapture)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} - -ALCbackendFactory *ALCportBackendFactory_getFactory(void) -{ - static ALCportBackendFactory factory = ALCPORTBACKENDFACTORY_INITIALIZER; - return STATIC_CAST(ALCbackendFactory, &factory); -} diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp new file mode 100644 index 00000000..e1b1c265 --- /dev/null +++ b/Alc/backends/portaudio.cpp @@ -0,0 +1,559 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include "alMain.h" +#include "alu.h" +#include "alconfig.h" +#include "ringbuffer.h" +#include "compat.h" + +#include "backends/base.h" + +#include + + +static const ALCchar pa_device[] = "PortAudio Default"; + + +#ifdef HAVE_DYNLOAD +static void *pa_handle; +#define MAKE_FUNC(x) static __typeof(x) * p##x +MAKE_FUNC(Pa_Initialize); +MAKE_FUNC(Pa_Terminate); +MAKE_FUNC(Pa_GetErrorText); +MAKE_FUNC(Pa_StartStream); +MAKE_FUNC(Pa_StopStream); +MAKE_FUNC(Pa_OpenStream); +MAKE_FUNC(Pa_CloseStream); +MAKE_FUNC(Pa_GetDefaultOutputDevice); +MAKE_FUNC(Pa_GetDefaultInputDevice); +MAKE_FUNC(Pa_GetStreamInfo); +#undef MAKE_FUNC + +#ifndef IN_IDE_PARSER +#define Pa_Initialize pPa_Initialize +#define Pa_Terminate pPa_Terminate +#define Pa_GetErrorText pPa_GetErrorText +#define Pa_StartStream pPa_StartStream +#define Pa_StopStream pPa_StopStream +#define Pa_OpenStream pPa_OpenStream +#define Pa_CloseStream pPa_CloseStream +#define Pa_GetDefaultOutputDevice pPa_GetDefaultOutputDevice +#define Pa_GetDefaultInputDevice pPa_GetDefaultInputDevice +#define Pa_GetStreamInfo pPa_GetStreamInfo +#endif +#endif + +static ALCboolean pa_load(void) +{ + PaError err; + +#ifdef HAVE_DYNLOAD + if(!pa_handle) + { +#ifdef _WIN32 +# define PALIB "portaudio.dll" +#elif defined(__APPLE__) && defined(__MACH__) +# define PALIB "libportaudio.2.dylib" +#elif defined(__OpenBSD__) +# define PALIB "libportaudio.so" +#else +# define PALIB "libportaudio.so.2" +#endif + + pa_handle = LoadLib(PALIB); + if(!pa_handle) + return ALC_FALSE; + +#define LOAD_FUNC(f) do { \ + p##f = reinterpret_cast(GetSymbol(pa_handle, #f)); \ + if(p##f == nullptr) \ + { \ + CloseLib(pa_handle); \ + pa_handle = nullptr; \ + return ALC_FALSE; \ + } \ +} while(0) + LOAD_FUNC(Pa_Initialize); + LOAD_FUNC(Pa_Terminate); + LOAD_FUNC(Pa_GetErrorText); + LOAD_FUNC(Pa_StartStream); + LOAD_FUNC(Pa_StopStream); + LOAD_FUNC(Pa_OpenStream); + LOAD_FUNC(Pa_CloseStream); + LOAD_FUNC(Pa_GetDefaultOutputDevice); + LOAD_FUNC(Pa_GetDefaultInputDevice); + LOAD_FUNC(Pa_GetStreamInfo); +#undef LOAD_FUNC + + if((err=Pa_Initialize()) != paNoError) + { + ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err)); + CloseLib(pa_handle); + pa_handle = nullptr; + return ALC_FALSE; + } + } +#else + if((err=Pa_Initialize()) != paNoError) + { + ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err)); + return ALC_FALSE; + } +#endif + return ALC_TRUE; +} + + +struct ALCportPlayback final : public ALCbackend { + PaStream *stream; + PaStreamParameters params; + ALuint update_size; +}; + +static int ALCportPlayback_WriteCallback(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, + const PaStreamCallbackFlags statusFlags, void *userData); + +static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device); +static void ALCportPlayback_Destruct(ALCportPlayback *self); +static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name); +static ALCboolean ALCportPlayback_reset(ALCportPlayback *self); +static ALCboolean ALCportPlayback_start(ALCportPlayback *self); +static void ALCportPlayback_stop(ALCportPlayback *self); +static DECLARE_FORWARD2(ALCportPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) +static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCportPlayback) + +DEFINE_ALCBACKEND_VTABLE(ALCportPlayback); + + +static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device) +{ + new (self) ALCportPlayback{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCportPlayback, ALCbackend, self); + + self->stream = nullptr; +} + +static void ALCportPlayback_Destruct(ALCportPlayback *self) +{ + PaError err = self->stream ? Pa_CloseStream(self->stream) : paNoError; + if(err != paNoError) + ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); + self->stream = nullptr; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCportPlayback(); +} + + +static int ALCportPlayback_WriteCallback(const void *UNUSED(inputBuffer), void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo), + const PaStreamCallbackFlags UNUSED(statusFlags), void *userData) +{ + ALCportPlayback *self = static_cast(userData); + + ALCportPlayback_lock(self); + aluMixData(STATIC_CAST(ALCbackend, self)->mDevice, outputBuffer, framesPerBuffer); + ALCportPlayback_unlock(self); + return 0; +} + + +static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + PaError err; + + if(!name) + name = pa_device; + else if(strcmp(name, pa_device) != 0) + return ALC_INVALID_VALUE; + + self->update_size = device->UpdateSize; + + self->params.device = -1; + if(!ConfigValueInt(nullptr, "port", "device", &self->params.device) || + self->params.device < 0) + self->params.device = Pa_GetDefaultOutputDevice(); + self->params.suggestedLatency = (device->UpdateSize*device->NumUpdates) / + (float)device->Frequency; + self->params.hostApiSpecificStreamInfo = nullptr; + + self->params.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2); + + switch(device->FmtType) + { + case DevFmtByte: + self->params.sampleFormat = paInt8; + break; + case DevFmtUByte: + self->params.sampleFormat = paUInt8; + break; + case DevFmtUShort: + /* fall-through */ + case DevFmtShort: + self->params.sampleFormat = paInt16; + break; + case DevFmtUInt: + /* fall-through */ + case DevFmtInt: + self->params.sampleFormat = paInt32; + break; + case DevFmtFloat: + self->params.sampleFormat = paFloat32; + break; + } + +retry_open: + err = Pa_OpenStream(&self->stream, nullptr, &self->params, + device->Frequency, device->UpdateSize, paNoFlag, + ALCportPlayback_WriteCallback, self + ); + if(err != paNoError) + { + if(self->params.sampleFormat == paFloat32) + { + self->params.sampleFormat = paInt16; + goto retry_open; + } + ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); + return ALC_INVALID_VALUE; + } + + alstr_copy_cstr(&device->DeviceName, name); + + return ALC_NO_ERROR; + +} + +static ALCboolean ALCportPlayback_reset(ALCportPlayback *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + const PaStreamInfo *streamInfo; + + streamInfo = Pa_GetStreamInfo(self->stream); + device->Frequency = streamInfo->sampleRate; + device->UpdateSize = self->update_size; + + if(self->params.sampleFormat == paInt8) + device->FmtType = DevFmtByte; + else if(self->params.sampleFormat == paUInt8) + device->FmtType = DevFmtUByte; + else if(self->params.sampleFormat == paInt16) + device->FmtType = DevFmtShort; + else if(self->params.sampleFormat == paInt32) + device->FmtType = DevFmtInt; + else if(self->params.sampleFormat == paFloat32) + device->FmtType = DevFmtFloat; + else + { + ERR("Unexpected sample format: 0x%lx\n", self->params.sampleFormat); + return ALC_FALSE; + } + + if(self->params.channelCount == 2) + device->FmtChans = DevFmtStereo; + else if(self->params.channelCount == 1) + device->FmtChans = DevFmtMono; + else + { + ERR("Unexpected channel count: %u\n", self->params.channelCount); + return ALC_FALSE; + } + SetDefaultChannelOrder(device); + + return ALC_TRUE; +} + +static ALCboolean ALCportPlayback_start(ALCportPlayback *self) +{ + PaError err; + + err = Pa_StartStream(self->stream); + if(err != paNoError) + { + ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err)); + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static void ALCportPlayback_stop(ALCportPlayback *self) +{ + PaError err = Pa_StopStream(self->stream); + if(err != paNoError) + ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); +} + + +struct ALCportCapture final : public ALCbackend { + PaStream *stream; + PaStreamParameters params; + + ll_ringbuffer_t *ring; +}; + +static int ALCportCapture_ReadCallback(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, + const PaStreamCallbackFlags statusFlags, void *userData); + +static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device); +static void ALCportCapture_Destruct(ALCportCapture *self); +static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name); +static DECLARE_FORWARD(ALCportCapture, ALCbackend, ALCboolean, reset) +static ALCboolean ALCportCapture_start(ALCportCapture *self); +static void ALCportCapture_stop(ALCportCapture *self); +static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples); +static ALCuint ALCportCapture_availableSamples(ALCportCapture *self); +static DECLARE_FORWARD(ALCportCapture, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCportCapture) + +DEFINE_ALCBACKEND_VTABLE(ALCportCapture); + + +static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device) +{ + new (self) ALCportCapture{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCportCapture, ALCbackend, self); + + self->stream = nullptr; + self->ring = nullptr; +} + +static void ALCportCapture_Destruct(ALCportCapture *self) +{ + PaError err = self->stream ? Pa_CloseStream(self->stream) : paNoError; + if(err != paNoError) + ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); + self->stream = nullptr; + + ll_ringbuffer_free(self->ring); + self->ring = nullptr; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCportCapture(); +} + + +static int ALCportCapture_ReadCallback(const void *inputBuffer, void *UNUSED(outputBuffer), + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo), + const PaStreamCallbackFlags UNUSED(statusFlags), void *userData) +{ + ALCportCapture *self = static_cast(userData); + size_t writable = ll_ringbuffer_write_space(self->ring); + + if(framesPerBuffer > writable) framesPerBuffer = writable; + ll_ringbuffer_write(self->ring, static_cast(inputBuffer), framesPerBuffer); + return 0; +} + + +static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALuint samples, frame_size; + PaError err; + + if(!name) + name = pa_device; + else if(strcmp(name, pa_device) != 0) + return ALC_INVALID_VALUE; + + samples = device->UpdateSize * device->NumUpdates; + samples = maxu(samples, 100 * device->Frequency / 1000); + frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + + self->ring = ll_ringbuffer_create(samples, frame_size, false); + if(self->ring == nullptr) return ALC_INVALID_VALUE; + + self->params.device = -1; + if(!ConfigValueInt(nullptr, "port", "capture", &self->params.device) || + self->params.device < 0) + self->params.device = Pa_GetDefaultInputDevice(); + self->params.suggestedLatency = 0.0f; + self->params.hostApiSpecificStreamInfo = nullptr; + + switch(device->FmtType) + { + case DevFmtByte: + self->params.sampleFormat = paInt8; + break; + case DevFmtUByte: + self->params.sampleFormat = paUInt8; + break; + case DevFmtShort: + self->params.sampleFormat = paInt16; + break; + case DevFmtInt: + self->params.sampleFormat = paInt32; + break; + case DevFmtFloat: + self->params.sampleFormat = paFloat32; + break; + case DevFmtUInt: + case DevFmtUShort: + ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); + return ALC_INVALID_VALUE; + } + self->params.channelCount = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + + err = Pa_OpenStream(&self->stream, &self->params, nullptr, + device->Frequency, paFramesPerBufferUnspecified, paNoFlag, + ALCportCapture_ReadCallback, self + ); + if(err != paNoError) + { + ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); + return ALC_INVALID_VALUE; + } + + alstr_copy_cstr(&device->DeviceName, name); + + return ALC_NO_ERROR; +} + + +static ALCboolean ALCportCapture_start(ALCportCapture *self) +{ + PaError err = Pa_StartStream(self->stream); + if(err != paNoError) + { + ERR("Error starting stream: %s\n", Pa_GetErrorText(err)); + return ALC_FALSE; + } + return ALC_TRUE; +} + +static void ALCportCapture_stop(ALCportCapture *self) +{ + PaError err = Pa_StopStream(self->stream); + if(err != paNoError) + ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); +} + + +static ALCuint ALCportCapture_availableSamples(ALCportCapture *self) +{ + return ll_ringbuffer_read_space(self->ring); +} + +static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples) +{ + ll_ringbuffer_read(self->ring, static_cast(buffer), samples); + return ALC_NO_ERROR; +} + + +struct ALCportBackendFactory final : public ALCbackendFactory { + ALCportBackendFactory() noexcept; +}; + +static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory *self); +static void ALCportBackendFactory_deinit(ALCportBackendFactory *self); +static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory *self, ALCbackend_Type type); +static void ALCportBackendFactory_probe(ALCportBackendFactory *self, enum DevProbe type, al_string *outnames); +static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory *self, ALCdevice *device, ALCbackend_Type type); +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCportBackendFactory); + + +ALCportBackendFactory::ALCportBackendFactory() noexcept + : ALCbackendFactory{GET_VTABLE2(ALCportBackendFactory, ALCbackendFactory)} +{ } + +static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory* UNUSED(self)) +{ + if(!pa_load()) + return ALC_FALSE; + return ALC_TRUE; +} + +static void ALCportBackendFactory_deinit(ALCportBackendFactory* UNUSED(self)) +{ +#ifdef HAVE_DYNLOAD + if(pa_handle) + { + Pa_Terminate(); + CloseLib(pa_handle); + pa_handle = nullptr; + } +#else + Pa_Terminate(); +#endif +} + +static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Playback || type == ALCbackend_Capture) + return ALC_TRUE; + return ALC_FALSE; +} + +static void ALCportBackendFactory_probe(ALCportBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +{ + switch(type) + { + case ALL_DEVICE_PROBE: + case CAPTURE_DEVICE_PROBE: + alstr_append_range(outnames, pa_device, pa_device+sizeof(pa_device)); + break; + } +} + +static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCportPlayback *backend; + NEW_OBJ(backend, ALCportPlayback)(device); + if(!backend) return nullptr; + return STATIC_CAST(ALCbackend, backend); + } + if(type == ALCbackend_Capture) + { + ALCportCapture *backend; + NEW_OBJ(backend, ALCportCapture)(device); + if(!backend) return nullptr; + return STATIC_CAST(ALCbackend, backend); + } + + return nullptr; +} + +ALCbackendFactory *ALCportBackendFactory_getFactory(void) +{ + static ALCportBackendFactory factory{}; + return STATIC_CAST(ALCbackendFactory, &factory); +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b4a32b2..a4fbae2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1189,7 +1189,7 @@ IF(PORTAUDIO_FOUND) IF(ALSOFT_BACKEND_PORTAUDIO) SET(HAVE_PORTAUDIO 1) SET(BACKENDS "${BACKENDS} PortAudio${IS_LINKED},") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/portaudio.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/portaudio.cpp) ADD_BACKEND_LIBS(${PORTAUDIO_LIBRARIES}) SET(INC_PATHS ${INC_PATHS} ${PORTAUDIO_INCLUDE_DIRS}) ENDIF() -- cgit v1.2.3 From c93b7ca0daf453b963f27d8d44dbb94cc8d581dd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Nov 2018 23:49:11 -0800 Subject: Convert the OSS backend to C++ --- Alc/backends/oss.c | 869 -------------------------------------------------- Alc/backends/oss.cpp | 875 +++++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 876 insertions(+), 870 deletions(-) delete mode 100644 Alc/backends/oss.c create mode 100644 Alc/backends/oss.cpp diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c deleted file mode 100644 index 71faad25..00000000 --- a/Alc/backends/oss.c +++ /dev/null @@ -1,869 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "alMain.h" -#include "alu.h" -#include "alconfig.h" -#include "ringbuffer.h" -#include "threads.h" -#include "compat.h" - -#include "backends/base.h" - -#include - -/* - * The OSS documentation talks about SOUND_MIXER_READ, but the header - * only contains MIXER_READ. Play safe. Same for WRITE. - */ -#ifndef SOUND_MIXER_READ -#define SOUND_MIXER_READ MIXER_READ -#endif -#ifndef SOUND_MIXER_WRITE -#define SOUND_MIXER_WRITE MIXER_WRITE -#endif - -#if defined(SOUND_VERSION) && (SOUND_VERSION < 0x040000) -#define ALC_OSS_COMPAT -#endif -#ifndef SNDCTL_AUDIOINFO -#define ALC_OSS_COMPAT -#endif - -/* - * FreeBSD strongly discourages the use of specific devices, - * such as those returned in oss_audioinfo.devnode - */ -#ifdef __FreeBSD__ -#define ALC_OSS_DEVNODE_TRUC -#endif - -struct oss_device { - const ALCchar *handle; - const char *path; - struct oss_device *next; -}; - -static struct oss_device oss_playback = { - "OSS Default", - "/dev/dsp", - NULL -}; - -static struct oss_device oss_capture = { - "OSS Default", - "/dev/dsp", - NULL -}; - -#ifdef ALC_OSS_COMPAT - -#define DSP_CAP_OUTPUT 0x00020000 -#define DSP_CAP_INPUT 0x00010000 -static void ALCossListPopulate(struct oss_device *UNUSED(devlist), int UNUSED(type_flag)) -{ -} - -#else - -#ifndef HAVE_STRNLEN -static size_t strnlen(const char *str, size_t maxlen) -{ - const char *end = memchr(str, 0, maxlen); - if(!end) return maxlen; - return end - str; -} -#endif - -static void ALCossListAppend(struct oss_device *list, const char *handle, size_t hlen, const char *path, size_t plen) -{ - struct oss_device *next; - struct oss_device *last; - size_t i; - - /* skip the first item "OSS Default" */ - last = list; - next = list->next; -#ifdef ALC_OSS_DEVNODE_TRUC - for(i = 0;i < plen;i++) - { - if(path[i] == '.') - { - if(strncmp(path + i, handle + hlen + i - plen, plen - i) == 0) - hlen = hlen + i - plen; - plen = i; - } - } -#else - (void)i; -#endif - if(handle[0] == '\0') - { - handle = path; - hlen = plen; - } - - while(next != NULL) - { - if(strncmp(next->path, path, plen) == 0) - return; - last = next; - next = next->next; - } - - next = (struct oss_device*)malloc(sizeof(struct oss_device) + hlen + plen + 2); - next->handle = (char*)(next + 1); - next->path = next->handle + hlen + 1; - next->next = NULL; - last->next = next; - - strncpy((char*)next->handle, handle, hlen); - ((char*)next->handle)[hlen] = '\0'; - strncpy((char*)next->path, path, plen); - ((char*)next->path)[plen] = '\0'; - - TRACE("Got device \"%s\", \"%s\"\n", next->handle, next->path); -} - -static void ALCossListPopulate(struct oss_device *devlist, int type_flag) -{ - struct oss_sysinfo si; - struct oss_audioinfo ai; - int fd, i; - - if((fd=open("/dev/mixer", O_RDONLY)) < 0) - { - TRACE("Could not open /dev/mixer: %s\n", strerror(errno)); - return; - } - if(ioctl(fd, SNDCTL_SYSINFO, &si) == -1) - { - TRACE("SNDCTL_SYSINFO failed: %s\n", strerror(errno)); - goto done; - } - for(i = 0;i < si.numaudios;i++) - { - const char *handle; - size_t len; - - ai.dev = i; - if(ioctl(fd, SNDCTL_AUDIOINFO, &ai) == -1) - { - ERR("SNDCTL_AUDIOINFO (%d) failed: %s\n", i, strerror(errno)); - continue; - } - if(ai.devnode[0] == '\0') - continue; - - if(ai.handle[0] != '\0') - { - len = strnlen(ai.handle, sizeof(ai.handle)); - handle = ai.handle; - } - else - { - len = strnlen(ai.name, sizeof(ai.name)); - handle = ai.name; - } - if((ai.caps&type_flag)) - ALCossListAppend(devlist, handle, len, ai.devnode, - strnlen(ai.devnode, sizeof(ai.devnode))); - } - -done: - close(fd); -} - -#endif - -static void ALCossListFree(struct oss_device *list) -{ - struct oss_device *cur; - if(list == NULL) - return; - - /* skip the first item "OSS Default" */ - cur = list->next; - list->next = NULL; - - while(cur != NULL) - { - struct oss_device *next = cur->next; - free(cur); - cur = next; - } -} - -static int log2i(ALCuint x) -{ - int y = 0; - while (x > 1) - { - x >>= 1; - y++; - } - return y; -} - -typedef struct ALCplaybackOSS { - DERIVE_FROM_TYPE(ALCbackend); - - int fd; - - ALubyte *mix_data; - int data_size; - - ATOMIC(ALenum) killNow; - althrd_t thread; -} ALCplaybackOSS; - -static int ALCplaybackOSS_mixerProc(void *ptr); - -static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device); -static void ALCplaybackOSS_Destruct(ALCplaybackOSS *self); -static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name); -static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self); -static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self); -static void ALCplaybackOSS_stop(ALCplaybackOSS *self); -static DECLARE_FORWARD2(ALCplaybackOSS, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCplaybackOSS) -DEFINE_ALCBACKEND_VTABLE(ALCplaybackOSS); - - -static int ALCplaybackOSS_mixerProc(void *ptr) -{ - ALCplaybackOSS *self = (ALCplaybackOSS*)ptr; - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - struct timeval timeout; - ALubyte *write_ptr; - ALint frame_size; - ALint to_write; - ssize_t wrote; - fd_set wfds; - int sret; - - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - - ALCplaybackOSS_lock(self); - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) - { - FD_ZERO(&wfds); - FD_SET(self->fd, &wfds); - timeout.tv_sec = 1; - timeout.tv_usec = 0; - - ALCplaybackOSS_unlock(self); - sret = select(self->fd+1, NULL, &wfds, NULL, &timeout); - ALCplaybackOSS_lock(self); - if(sret < 0) - { - if(errno == EINTR) - continue; - ERR("select failed: %s\n", strerror(errno)); - aluHandleDisconnect(device, "Failed waiting for playback buffer: %s", strerror(errno)); - break; - } - else if(sret == 0) - { - WARN("select timeout\n"); - continue; - } - - write_ptr = self->mix_data; - to_write = self->data_size; - aluMixData(device, write_ptr, to_write/frame_size); - while(to_write > 0 && !ATOMIC_LOAD_SEQ(&self->killNow)) - { - wrote = write(self->fd, write_ptr, to_write); - if(wrote < 0) - { - if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) - continue; - ERR("write failed: %s\n", strerror(errno)); - aluHandleDisconnect(device, "Failed writing playback samples: %s", - strerror(errno)); - break; - } - - to_write -= wrote; - write_ptr += wrote; - } - } - ALCplaybackOSS_unlock(self); - - return 0; -} - - -static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCplaybackOSS, ALCbackend, self); - - self->fd = -1; - ATOMIC_INIT(&self->killNow, AL_FALSE); -} - -static void ALCplaybackOSS_Destruct(ALCplaybackOSS *self) -{ - if(self->fd != -1) - close(self->fd); - self->fd = -1; - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - -static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) -{ - struct oss_device *dev = &oss_playback; - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - - if(!name || strcmp(name, dev->handle) == 0) - name = dev->handle; - else - { - if(!dev->next) - { - ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT); - dev = &oss_playback; - } - while(dev != NULL) - { - if (strcmp(dev->handle, name) == 0) - break; - dev = dev->next; - } - if(dev == NULL) - { - WARN("Could not find \"%s\" in device list\n", name); - return ALC_INVALID_VALUE; - } - } - - self->fd = open(dev->path, O_WRONLY); - if(self->fd == -1) - { - ERR("Could not open %s: %s\n", dev->path, strerror(errno)); - return ALC_INVALID_VALUE; - } - - alstr_copy_cstr(&device->DeviceName, name); - - return ALC_NO_ERROR; -} - -static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - int numFragmentsLogSize; - int log2FragmentSize; - unsigned int periods; - audio_buf_info info; - ALuint frameSize; - int numChannels; - int ossFormat; - int ossSpeed; - char *err; - - switch(device->FmtType) - { - case DevFmtByte: - ossFormat = AFMT_S8; - break; - case DevFmtUByte: - ossFormat = AFMT_U8; - break; - case DevFmtUShort: - case DevFmtInt: - case DevFmtUInt: - case DevFmtFloat: - device->FmtType = DevFmtShort; - /* fall-through */ - case DevFmtShort: - ossFormat = AFMT_S16_NE; - break; - } - - periods = device->NumUpdates; - numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - ossSpeed = device->Frequency; - frameSize = numChannels * BytesFromDevFmt(device->FmtType); - /* According to the OSS spec, 16 bytes (log2(16)) is the minimum. */ - log2FragmentSize = maxi(log2i(device->UpdateSize*frameSize), 4); - numFragmentsLogSize = (periods << 16) | log2FragmentSize; - -#define CHECKERR(func) if((func) < 0) { \ - err = #func; \ - goto err; \ -} - /* Don't fail if SETFRAGMENT fails. We can handle just about anything - * that's reported back via GETOSPACE */ - ioctl(self->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize); - CHECKERR(ioctl(self->fd, SNDCTL_DSP_SETFMT, &ossFormat)); - CHECKERR(ioctl(self->fd, SNDCTL_DSP_CHANNELS, &numChannels)); - CHECKERR(ioctl(self->fd, SNDCTL_DSP_SPEED, &ossSpeed)); - CHECKERR(ioctl(self->fd, SNDCTL_DSP_GETOSPACE, &info)); - if(0) - { - err: - ERR("%s failed: %s\n", err, strerror(errno)); - return ALC_FALSE; - } -#undef CHECKERR - - if((int)ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != numChannels) - { - ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); - return ALC_FALSE; - } - - if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) || - (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) || - (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort))) - { - ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat); - return ALC_FALSE; - } - - device->Frequency = ossSpeed; - device->UpdateSize = info.fragsize / frameSize; - device->NumUpdates = info.fragments; - - SetDefaultChannelOrder(device); - - return ALC_TRUE; -} - -static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - - self->data_size = device->UpdateSize * FrameSizeFromDevFmt( - device->FmtChans, device->FmtType, device->AmbiOrder - ); - self->mix_data = calloc(1, self->data_size); - - ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE); - if(althrd_create(&self->thread, ALCplaybackOSS_mixerProc, self) != althrd_success) - { - free(self->mix_data); - self->mix_data = NULL; - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static void ALCplaybackOSS_stop(ALCplaybackOSS *self) -{ - int res; - - if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE)) - return; - althrd_join(self->thread, &res); - - if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0) - ERR("Error resetting device: %s\n", strerror(errno)); - - free(self->mix_data); - self->mix_data = NULL; -} - - -typedef struct ALCcaptureOSS { - DERIVE_FROM_TYPE(ALCbackend); - - int fd; - - ll_ringbuffer_t *ring; - - ATOMIC(ALenum) killNow; - althrd_t thread; -} ALCcaptureOSS; - -static int ALCcaptureOSS_recordProc(void *ptr); - -static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device); -static void ALCcaptureOSS_Destruct(ALCcaptureOSS *self); -static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name); -static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ALCboolean, reset) -static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self); -static void ALCcaptureOSS_stop(ALCcaptureOSS *self); -static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples); -static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self); -static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCcaptureOSS) -DEFINE_ALCBACKEND_VTABLE(ALCcaptureOSS); - - -static int ALCcaptureOSS_recordProc(void *ptr) -{ - ALCcaptureOSS *self = (ALCcaptureOSS*)ptr; - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - struct timeval timeout; - int frame_size; - fd_set rfds; - ssize_t amt; - int sret; - - SetRTPriority(); - althrd_setname(althrd_current(), RECORD_THREAD_NAME); - - frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - - while(!ATOMIC_LOAD_SEQ(&self->killNow)) - { - ll_ringbuffer_data_t vec[2]; - - FD_ZERO(&rfds); - FD_SET(self->fd, &rfds); - timeout.tv_sec = 1; - timeout.tv_usec = 0; - - sret = select(self->fd+1, &rfds, NULL, NULL, &timeout); - if(sret < 0) - { - if(errno == EINTR) - continue; - ERR("select failed: %s\n", strerror(errno)); - aluHandleDisconnect(device, "Failed to check capture samples: %s", strerror(errno)); - break; - } - else if(sret == 0) - { - WARN("select timeout\n"); - continue; - } - - ll_ringbuffer_get_write_vector(self->ring, vec); - if(vec[0].len > 0) - { - amt = read(self->fd, vec[0].buf, vec[0].len*frame_size); - if(amt < 0) - { - ERR("read failed: %s\n", strerror(errno)); - ALCcaptureOSS_lock(self); - aluHandleDisconnect(device, "Failed reading capture samples: %s", strerror(errno)); - ALCcaptureOSS_unlock(self); - break; - } - ll_ringbuffer_write_advance(self->ring, amt/frame_size); - } - } - - return 0; -} - - -static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCcaptureOSS, ALCbackend, self); - - self->fd = -1; - self->ring = NULL; - ATOMIC_INIT(&self->killNow, AL_FALSE); -} - -static void ALCcaptureOSS_Destruct(ALCcaptureOSS *self) -{ - if(self->fd != -1) - close(self->fd); - self->fd = -1; - - ll_ringbuffer_free(self->ring); - self->ring = NULL; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - -static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - struct oss_device *dev = &oss_capture; - int numFragmentsLogSize; - int log2FragmentSize; - unsigned int periods; - audio_buf_info info; - ALuint frameSize; - int numChannels; - int ossFormat; - int ossSpeed; - char *err; - - if(!name || strcmp(name, dev->handle) == 0) - name = dev->handle; - else - { - if(!dev->next) - { - ALCossListPopulate(&oss_capture, DSP_CAP_INPUT); - dev = &oss_capture; - } - while(dev != NULL) - { - if (strcmp(dev->handle, name) == 0) - break; - dev = dev->next; - } - if(dev == NULL) - { - WARN("Could not find \"%s\" in device list\n", name); - return ALC_INVALID_VALUE; - } - } - - self->fd = open(dev->path, O_RDONLY); - if(self->fd == -1) - { - ERR("Could not open %s: %s\n", dev->path, strerror(errno)); - return ALC_INVALID_VALUE; - } - - switch(device->FmtType) - { - case DevFmtByte: - ossFormat = AFMT_S8; - break; - case DevFmtUByte: - ossFormat = AFMT_U8; - break; - case DevFmtShort: - ossFormat = AFMT_S16_NE; - break; - case DevFmtUShort: - case DevFmtInt: - case DevFmtUInt: - case DevFmtFloat: - ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); - return ALC_INVALID_VALUE; - } - - periods = 4; - numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - frameSize = numChannels * BytesFromDevFmt(device->FmtType); - ossSpeed = device->Frequency; - log2FragmentSize = log2i(device->UpdateSize * device->NumUpdates * - frameSize / periods); - - /* according to the OSS spec, 16 bytes are the minimum */ - if (log2FragmentSize < 4) - log2FragmentSize = 4; - numFragmentsLogSize = (periods << 16) | log2FragmentSize; - -#define CHECKERR(func) if((func) < 0) { \ - err = #func; \ - goto err; \ -} - CHECKERR(ioctl(self->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize)); - CHECKERR(ioctl(self->fd, SNDCTL_DSP_SETFMT, &ossFormat)); - CHECKERR(ioctl(self->fd, SNDCTL_DSP_CHANNELS, &numChannels)); - CHECKERR(ioctl(self->fd, SNDCTL_DSP_SPEED, &ossSpeed)); - CHECKERR(ioctl(self->fd, SNDCTL_DSP_GETISPACE, &info)); - if(0) - { - err: - ERR("%s failed: %s\n", err, strerror(errno)); - close(self->fd); - self->fd = -1; - return ALC_INVALID_VALUE; - } -#undef CHECKERR - - if((int)ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != numChannels) - { - ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); - close(self->fd); - self->fd = -1; - return ALC_INVALID_VALUE; - } - - if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) || - (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) || - (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort))) - { - ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat); - close(self->fd); - self->fd = -1; - return ALC_INVALID_VALUE; - } - - self->ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, frameSize, false); - if(!self->ring) - { - ERR("Ring buffer create failed\n"); - close(self->fd); - self->fd = -1; - return ALC_OUT_OF_MEMORY; - } - - alstr_copy_cstr(&device->DeviceName, name); - - return ALC_NO_ERROR; -} - -static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self) -{ - ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE); - if(althrd_create(&self->thread, ALCcaptureOSS_recordProc, self) != althrd_success) - return ALC_FALSE; - return ALC_TRUE; -} - -static void ALCcaptureOSS_stop(ALCcaptureOSS *self) -{ - int res; - - if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE)) - return; - - althrd_join(self->thread, &res); - - if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0) - ERR("Error resetting device: %s\n", strerror(errno)); -} - -static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples) -{ - ll_ringbuffer_read(self->ring, buffer, samples); - return ALC_NO_ERROR; -} - -static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self) -{ - return ll_ringbuffer_read_space(self->ring); -} - - -typedef struct ALCossBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCossBackendFactory; -#define ALCOSSBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCossBackendFactory, ALCbackendFactory) } } - -ALCbackendFactory *ALCossBackendFactory_getFactory(void); - -static ALCboolean ALCossBackendFactory_init(ALCossBackendFactory *self); -static void ALCossBackendFactory_deinit(ALCossBackendFactory *self); -static ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory *self, ALCbackend_Type type); -static void ALCossBackendFactory_probe(ALCossBackendFactory *self, enum DevProbe type, al_string *outnames); -static ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCossBackendFactory); - - -ALCbackendFactory *ALCossBackendFactory_getFactory(void) -{ - static ALCossBackendFactory factory = ALCOSSBACKENDFACTORY_INITIALIZER; - return STATIC_CAST(ALCbackendFactory, &factory); -} - - -ALCboolean ALCossBackendFactory_init(ALCossBackendFactory* UNUSED(self)) -{ - ConfigValueStr(NULL, "oss", "device", &oss_playback.path); - ConfigValueStr(NULL, "oss", "capture", &oss_capture.path); - - return ALC_TRUE; -} - -void ALCossBackendFactory_deinit(ALCossBackendFactory* UNUSED(self)) -{ - ALCossListFree(&oss_playback); - ALCossListFree(&oss_capture); -} - - -ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} - -void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) -{ - struct oss_device *cur = NULL; - switch(type) - { - case ALL_DEVICE_PROBE: - ALCossListFree(&oss_playback); - ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT); - cur = &oss_playback; - break; - - case CAPTURE_DEVICE_PROBE: - ALCossListFree(&oss_capture); - ALCossListPopulate(&oss_capture, DSP_CAP_INPUT); - cur = &oss_capture; - break; - } - while(cur != NULL) - { -#ifdef HAVE_STAT - struct stat buf; - if(stat(cur->path, &buf) == 0) -#endif - alstr_append_range(outnames, cur->handle, cur->handle+strlen(cur->handle)+1); - cur = cur->next; - } -} - -ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - { - ALCplaybackOSS *backend; - NEW_OBJ(backend, ALCplaybackOSS)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - if(type == ALCbackend_Capture) - { - ALCcaptureOSS *backend; - NEW_OBJ(backend, ALCcaptureOSS)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp new file mode 100644 index 00000000..03e8d3ef --- /dev/null +++ b/Alc/backends/oss.cpp @@ -0,0 +1,875 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "alMain.h" +#include "alu.h" +#include "alconfig.h" +#include "ringbuffer.h" +#include "threads.h" +#include "compat.h" + +#include "backends/base.h" + +#include + +/* + * The OSS documentation talks about SOUND_MIXER_READ, but the header + * only contains MIXER_READ. Play safe. Same for WRITE. + */ +#ifndef SOUND_MIXER_READ +#define SOUND_MIXER_READ MIXER_READ +#endif +#ifndef SOUND_MIXER_WRITE +#define SOUND_MIXER_WRITE MIXER_WRITE +#endif + +#if defined(SOUND_VERSION) && (SOUND_VERSION < 0x040000) +#define ALC_OSS_COMPAT +#endif +#ifndef SNDCTL_AUDIOINFO +#define ALC_OSS_COMPAT +#endif + +/* + * FreeBSD strongly discourages the use of specific devices, + * such as those returned in oss_audioinfo.devnode + */ +#ifdef __FreeBSD__ +#define ALC_OSS_DEVNODE_TRUC +#endif + +struct oss_device { + const ALCchar *handle; + const char *path; + struct oss_device *next; +}; + +static struct oss_device oss_playback = { + "OSS Default", + "/dev/dsp", + nullptr +}; + +static struct oss_device oss_capture = { + "OSS Default", + "/dev/dsp", + nullptr +}; + +#ifdef ALC_OSS_COMPAT + +#define DSP_CAP_OUTPUT 0x00020000 +#define DSP_CAP_INPUT 0x00010000 +static void ALCossListPopulate(struct oss_device *UNUSED(devlist), int UNUSED(type_flag)) +{ +} + +#else + +#ifndef HAVE_STRNLEN +static size_t my_strnlen(const char *str, size_t maxlen) +{ + const char *end = static_cast(memchr(str, 0, maxlen)); + if(!end) return maxlen; + return end - str; +} +#define strnlen my_strnlen +#endif + +static void ALCossListAppend(struct oss_device *list, const char *handle, size_t hlen, const char *path, size_t plen) +{ + struct oss_device *next; + struct oss_device *last; + size_t i; + + /* skip the first item "OSS Default" */ + last = list; + next = list->next; +#ifdef ALC_OSS_DEVNODE_TRUC + for(i = 0;i < plen;i++) + { + if(path[i] == '.') + { + if(strncmp(path + i, handle + hlen + i - plen, plen - i) == 0) + hlen = hlen + i - plen; + plen = i; + } + } +#else + (void)i; +#endif + if(handle[0] == '\0') + { + handle = path; + hlen = plen; + } + + while(next != nullptr) + { + if(strncmp(next->path, path, plen) == 0) + return; + last = next; + next = next->next; + } + + next = (struct oss_device*)malloc(sizeof(struct oss_device) + hlen + plen + 2); + next->handle = (char*)(next + 1); + next->path = next->handle + hlen + 1; + next->next = nullptr; + last->next = next; + + strncpy((char*)next->handle, handle, hlen); + ((char*)next->handle)[hlen] = '\0'; + strncpy((char*)next->path, path, plen); + ((char*)next->path)[plen] = '\0'; + + TRACE("Got device \"%s\", \"%s\"\n", next->handle, next->path); +} + +static void ALCossListPopulate(struct oss_device *devlist, int type_flag) +{ + struct oss_sysinfo si; + struct oss_audioinfo ai; + int fd, i; + + if((fd=open("/dev/mixer", O_RDONLY)) < 0) + { + TRACE("Could not open /dev/mixer: %s\n", strerror(errno)); + return; + } + if(ioctl(fd, SNDCTL_SYSINFO, &si) == -1) + { + TRACE("SNDCTL_SYSINFO failed: %s\n", strerror(errno)); + goto done; + } + for(i = 0;i < si.numaudios;i++) + { + const char *handle; + size_t len; + + ai.dev = i; + if(ioctl(fd, SNDCTL_AUDIOINFO, &ai) == -1) + { + ERR("SNDCTL_AUDIOINFO (%d) failed: %s\n", i, strerror(errno)); + continue; + } + if(ai.devnode[0] == '\0') + continue; + + if(ai.handle[0] != '\0') + { + len = strnlen(ai.handle, sizeof(ai.handle)); + handle = ai.handle; + } + else + { + len = strnlen(ai.name, sizeof(ai.name)); + handle = ai.name; + } + if((ai.caps&type_flag)) + ALCossListAppend(devlist, handle, len, ai.devnode, + strnlen(ai.devnode, sizeof(ai.devnode))); + } + +done: + close(fd); +} + +#endif + +static void ALCossListFree(struct oss_device *list) +{ + struct oss_device *cur; + if(list == nullptr) + return; + + /* skip the first item "OSS Default" */ + cur = list->next; + list->next = nullptr; + + while(cur != nullptr) + { + struct oss_device *next = cur->next; + free(cur); + cur = next; + } +} + +static int log2i(ALCuint x) +{ + int y = 0; + while (x > 1) + { + x >>= 1; + y++; + } + return y; +} + +struct ALCplaybackOSS final : public ALCbackend { + int fd; + + ALubyte *mix_data; + int data_size; + + ATOMIC(ALenum) killNow; + althrd_t thread; +}; + +static int ALCplaybackOSS_mixerProc(void *ptr); + +static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device); +static void ALCplaybackOSS_Destruct(ALCplaybackOSS *self); +static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name); +static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self); +static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self); +static void ALCplaybackOSS_stop(ALCplaybackOSS *self); +static DECLARE_FORWARD2(ALCplaybackOSS, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) +static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCplaybackOSS) +DEFINE_ALCBACKEND_VTABLE(ALCplaybackOSS); + + +static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device) +{ + new (self) ALCplaybackOSS{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCplaybackOSS, ALCbackend, self); + + self->fd = -1; + ATOMIC_INIT(&self->killNow, AL_FALSE); +} + +static void ALCplaybackOSS_Destruct(ALCplaybackOSS *self) +{ + if(self->fd != -1) + close(self->fd); + self->fd = -1; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCplaybackOSS(); +} + + +static int ALCplaybackOSS_mixerProc(void *ptr) +{ + ALCplaybackOSS *self = static_cast(ptr); + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + struct timeval timeout; + ALubyte *write_ptr; + ALint frame_size; + ALint to_write; + ssize_t wrote; + fd_set wfds; + int sret; + + SetRTPriority(); + althrd_setname(althrd_current(), MIXER_THREAD_NAME); + + frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + + ALCplaybackOSS_lock(self); + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + { + FD_ZERO(&wfds); + FD_SET(self->fd, &wfds); + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + ALCplaybackOSS_unlock(self); + sret = select(self->fd+1, nullptr, &wfds, nullptr, &timeout); + ALCplaybackOSS_lock(self); + if(sret < 0) + { + if(errno == EINTR) + continue; + ERR("select failed: %s\n", strerror(errno)); + aluHandleDisconnect(device, "Failed waiting for playback buffer: %s", strerror(errno)); + break; + } + else if(sret == 0) + { + WARN("select timeout\n"); + continue; + } + + write_ptr = self->mix_data; + to_write = self->data_size; + aluMixData(device, write_ptr, to_write/frame_size); + while(to_write > 0 && !ATOMIC_LOAD_SEQ(&self->killNow)) + { + wrote = write(self->fd, write_ptr, to_write); + if(wrote < 0) + { + if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) + continue; + ERR("write failed: %s\n", strerror(errno)); + aluHandleDisconnect(device, "Failed writing playback samples: %s", + strerror(errno)); + break; + } + + to_write -= wrote; + write_ptr += wrote; + } + } + ALCplaybackOSS_unlock(self); + + return 0; +} + + +static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) +{ + struct oss_device *dev = &oss_playback; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + + if(!name || strcmp(name, dev->handle) == 0) + name = dev->handle; + else + { + if(!dev->next) + { + ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT); + dev = &oss_playback; + } + while(dev != nullptr) + { + if (strcmp(dev->handle, name) == 0) + break; + dev = dev->next; + } + if(dev == nullptr) + { + WARN("Could not find \"%s\" in device list\n", name); + return ALC_INVALID_VALUE; + } + } + + self->fd = open(dev->path, O_WRONLY); + if(self->fd == -1) + { + ERR("Could not open %s: %s\n", dev->path, strerror(errno)); + return ALC_INVALID_VALUE; + } + + alstr_copy_cstr(&device->DeviceName, name); + + return ALC_NO_ERROR; +} + +static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + int numFragmentsLogSize; + int log2FragmentSize; + unsigned int periods; + audio_buf_info info; + ALuint frameSize; + int numChannels; + int ossFormat; + int ossSpeed; + const char *err; + + switch(device->FmtType) + { + case DevFmtByte: + ossFormat = AFMT_S8; + break; + case DevFmtUByte: + ossFormat = AFMT_U8; + break; + case DevFmtUShort: + case DevFmtInt: + case DevFmtUInt: + case DevFmtFloat: + device->FmtType = DevFmtShort; + /* fall-through */ + case DevFmtShort: + ossFormat = AFMT_S16_NE; + break; + } + + periods = device->NumUpdates; + numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + ossSpeed = device->Frequency; + frameSize = numChannels * BytesFromDevFmt(device->FmtType); + /* According to the OSS spec, 16 bytes (log2(16)) is the minimum. */ + log2FragmentSize = maxi(log2i(device->UpdateSize*frameSize), 4); + numFragmentsLogSize = (periods << 16) | log2FragmentSize; + +#define CHECKERR(func) if((func) < 0) { \ + err = #func; \ + goto err; \ +} + /* Don't fail if SETFRAGMENT fails. We can handle just about anything + * that's reported back via GETOSPACE */ + ioctl(self->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize); + CHECKERR(ioctl(self->fd, SNDCTL_DSP_SETFMT, &ossFormat)); + CHECKERR(ioctl(self->fd, SNDCTL_DSP_CHANNELS, &numChannels)); + CHECKERR(ioctl(self->fd, SNDCTL_DSP_SPEED, &ossSpeed)); + CHECKERR(ioctl(self->fd, SNDCTL_DSP_GETOSPACE, &info)); + if(0) + { + err: + ERR("%s failed: %s\n", err, strerror(errno)); + return ALC_FALSE; + } +#undef CHECKERR + + if((int)ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != numChannels) + { + ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); + return ALC_FALSE; + } + + if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) || + (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) || + (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort))) + { + ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat); + return ALC_FALSE; + } + + device->Frequency = ossSpeed; + device->UpdateSize = info.fragsize / frameSize; + device->NumUpdates = info.fragments; + + SetDefaultChannelOrder(device); + + return ALC_TRUE; +} + +static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + + self->data_size = device->UpdateSize * FrameSizeFromDevFmt( + device->FmtChans, device->FmtType, device->AmbiOrder + ); + self->mix_data = static_cast(calloc(1, self->data_size)); + + ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE); + if(althrd_create(&self->thread, ALCplaybackOSS_mixerProc, self) != althrd_success) + { + free(self->mix_data); + self->mix_data = nullptr; + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static void ALCplaybackOSS_stop(ALCplaybackOSS *self) +{ + int res; + + if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE)) + return; + althrd_join(self->thread, &res); + + if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0) + ERR("Error resetting device: %s\n", strerror(errno)); + + free(self->mix_data); + self->mix_data = nullptr; +} + + +struct ALCcaptureOSS final : public ALCbackend { + int fd; + + ll_ringbuffer_t *ring; + + ATOMIC(ALenum) killNow; + althrd_t thread; +}; + +static int ALCcaptureOSS_recordProc(void *ptr); + +static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device); +static void ALCcaptureOSS_Destruct(ALCcaptureOSS *self); +static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name); +static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ALCboolean, reset) +static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self); +static void ALCcaptureOSS_stop(ALCcaptureOSS *self); +static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples); +static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self); +static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCcaptureOSS) +DEFINE_ALCBACKEND_VTABLE(ALCcaptureOSS); + + +static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device) +{ + new (self) ALCcaptureOSS{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCcaptureOSS, ALCbackend, self); + + self->fd = -1; + self->ring = nullptr; + ATOMIC_INIT(&self->killNow, AL_FALSE); +} + +static void ALCcaptureOSS_Destruct(ALCcaptureOSS *self) +{ + if(self->fd != -1) + close(self->fd); + self->fd = -1; + + ll_ringbuffer_free(self->ring); + self->ring = nullptr; + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCcaptureOSS(); +} + + +static int ALCcaptureOSS_recordProc(void *ptr) +{ + ALCcaptureOSS *self = static_cast(ptr); + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + struct timeval timeout; + int frame_size; + fd_set rfds; + ssize_t amt; + int sret; + + SetRTPriority(); + althrd_setname(althrd_current(), RECORD_THREAD_NAME); + + frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + + while(!ATOMIC_LOAD_SEQ(&self->killNow)) + { + ll_ringbuffer_data_t vec[2]; + + FD_ZERO(&rfds); + FD_SET(self->fd, &rfds); + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + sret = select(self->fd+1, &rfds, nullptr, nullptr, &timeout); + if(sret < 0) + { + if(errno == EINTR) + continue; + ERR("select failed: %s\n", strerror(errno)); + aluHandleDisconnect(device, "Failed to check capture samples: %s", strerror(errno)); + break; + } + else if(sret == 0) + { + WARN("select timeout\n"); + continue; + } + + ll_ringbuffer_get_write_vector(self->ring, vec); + if(vec[0].len > 0) + { + amt = read(self->fd, vec[0].buf, vec[0].len*frame_size); + if(amt < 0) + { + ERR("read failed: %s\n", strerror(errno)); + ALCcaptureOSS_lock(self); + aluHandleDisconnect(device, "Failed reading capture samples: %s", strerror(errno)); + ALCcaptureOSS_unlock(self); + break; + } + ll_ringbuffer_write_advance(self->ring, amt/frame_size); + } + } + + return 0; +} + + +static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + struct oss_device *dev = &oss_capture; + int numFragmentsLogSize; + int log2FragmentSize; + unsigned int periods; + audio_buf_info info; + ALuint frameSize; + int numChannels; + int ossFormat; + int ossSpeed; + const char *err; + + if(!name || strcmp(name, dev->handle) == 0) + name = dev->handle; + else + { + if(!dev->next) + { + ALCossListPopulate(&oss_capture, DSP_CAP_INPUT); + dev = &oss_capture; + } + while(dev != nullptr) + { + if (strcmp(dev->handle, name) == 0) + break; + dev = dev->next; + } + if(dev == nullptr) + { + WARN("Could not find \"%s\" in device list\n", name); + return ALC_INVALID_VALUE; + } + } + + self->fd = open(dev->path, O_RDONLY); + if(self->fd == -1) + { + ERR("Could not open %s: %s\n", dev->path, strerror(errno)); + return ALC_INVALID_VALUE; + } + + switch(device->FmtType) + { + case DevFmtByte: + ossFormat = AFMT_S8; + break; + case DevFmtUByte: + ossFormat = AFMT_U8; + break; + case DevFmtShort: + ossFormat = AFMT_S16_NE; + break; + case DevFmtUShort: + case DevFmtInt: + case DevFmtUInt: + case DevFmtFloat: + ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); + return ALC_INVALID_VALUE; + } + + periods = 4; + numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + frameSize = numChannels * BytesFromDevFmt(device->FmtType); + ossSpeed = device->Frequency; + log2FragmentSize = log2i(device->UpdateSize * device->NumUpdates * + frameSize / periods); + + /* according to the OSS spec, 16 bytes are the minimum */ + if (log2FragmentSize < 4) + log2FragmentSize = 4; + numFragmentsLogSize = (periods << 16) | log2FragmentSize; + +#define CHECKERR(func) if((func) < 0) { \ + err = #func; \ + goto err; \ +} + CHECKERR(ioctl(self->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize)); + CHECKERR(ioctl(self->fd, SNDCTL_DSP_SETFMT, &ossFormat)); + CHECKERR(ioctl(self->fd, SNDCTL_DSP_CHANNELS, &numChannels)); + CHECKERR(ioctl(self->fd, SNDCTL_DSP_SPEED, &ossSpeed)); + CHECKERR(ioctl(self->fd, SNDCTL_DSP_GETISPACE, &info)); + if(0) + { + err: + ERR("%s failed: %s\n", err, strerror(errno)); + close(self->fd); + self->fd = -1; + return ALC_INVALID_VALUE; + } +#undef CHECKERR + + if((int)ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != numChannels) + { + ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); + close(self->fd); + self->fd = -1; + return ALC_INVALID_VALUE; + } + + if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) || + (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) || + (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort))) + { + ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat); + close(self->fd); + self->fd = -1; + return ALC_INVALID_VALUE; + } + + self->ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, frameSize, false); + if(!self->ring) + { + ERR("Ring buffer create failed\n"); + close(self->fd); + self->fd = -1; + return ALC_OUT_OF_MEMORY; + } + + alstr_copy_cstr(&device->DeviceName, name); + + return ALC_NO_ERROR; +} + +static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self) +{ + ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE); + if(althrd_create(&self->thread, ALCcaptureOSS_recordProc, self) != althrd_success) + return ALC_FALSE; + return ALC_TRUE; +} + +static void ALCcaptureOSS_stop(ALCcaptureOSS *self) +{ + int res; + + if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE)) + return; + + althrd_join(self->thread, &res); + + if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0) + ERR("Error resetting device: %s\n", strerror(errno)); +} + +static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples) +{ + ll_ringbuffer_read(self->ring, static_cast(buffer), samples); + return ALC_NO_ERROR; +} + +static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self) +{ + return ll_ringbuffer_read_space(self->ring); +} + + +struct ALCossBackendFactory final : public ALCbackendFactory { + ALCossBackendFactory() noexcept; +}; + +ALCbackendFactory *ALCossBackendFactory_getFactory(void); + +static ALCboolean ALCossBackendFactory_init(ALCossBackendFactory *self); +static void ALCossBackendFactory_deinit(ALCossBackendFactory *self); +static ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory *self, ALCbackend_Type type); +static void ALCossBackendFactory_probe(ALCossBackendFactory *self, enum DevProbe type, al_string *outnames); +static ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory *self, ALCdevice *device, ALCbackend_Type type); +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCossBackendFactory); + + +ALCossBackendFactory::ALCossBackendFactory() noexcept + : ALCbackendFactory{GET_VTABLE2(ALCossBackendFactory, ALCbackendFactory)} +{ } + +ALCbackendFactory *ALCossBackendFactory_getFactory(void) +{ + static ALCossBackendFactory factory{}; + return STATIC_CAST(ALCbackendFactory, &factory); +} + + +ALCboolean ALCossBackendFactory_init(ALCossBackendFactory* UNUSED(self)) +{ + ConfigValueStr(nullptr, "oss", "device", &oss_playback.path); + ConfigValueStr(nullptr, "oss", "capture", &oss_capture.path); + + return ALC_TRUE; +} + +void ALCossBackendFactory_deinit(ALCossBackendFactory* UNUSED(self)) +{ + ALCossListFree(&oss_playback); + ALCossListFree(&oss_capture); +} + + +ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Playback || type == ALCbackend_Capture) + return ALC_TRUE; + return ALC_FALSE; +} + +void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +{ + struct oss_device *cur = nullptr; + switch(type) + { + case ALL_DEVICE_PROBE: + ALCossListFree(&oss_playback); + ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT); + cur = &oss_playback; + break; + + case CAPTURE_DEVICE_PROBE: + ALCossListFree(&oss_capture); + ALCossListPopulate(&oss_capture, DSP_CAP_INPUT); + cur = &oss_capture; + break; + } + while(cur != nullptr) + { +#ifdef HAVE_STAT + struct stat buf; + if(stat(cur->path, &buf) == 0) +#endif + alstr_append_range(outnames, cur->handle, cur->handle+strlen(cur->handle)+1); + cur = cur->next; + } +} + +ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCplaybackOSS *backend; + NEW_OBJ(backend, ALCplaybackOSS)(device); + if(!backend) return nullptr; + return STATIC_CAST(ALCbackend, backend); + } + if(type == ALCbackend_Capture) + { + ALCcaptureOSS *backend; + NEW_OBJ(backend, ALCcaptureOSS)(device); + if(!backend) return nullptr; + return STATIC_CAST(ALCbackend, backend); + } + + return nullptr; +} diff --git a/CMakeLists.txt b/CMakeLists.txt index a4fbae2d..b4c0c8f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1060,7 +1060,7 @@ IF(OSS_FOUND) IF(ALSOFT_BACKEND_OSS) SET(HAVE_OSS 1) SET(BACKENDS "${BACKENDS} OSS,") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/oss.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/oss.cpp) IF(OSS_LIBRARIES) SET(EXTRA_LIBS ${OSS_LIBRARIES} ${EXTRA_LIBS}) ENDIF() -- cgit v1.2.3 From 51a1310902d45220cc89f498403d91ee57905c90 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Nov 2018 00:33:25 -0800 Subject: Convert the OpenSL backend to C++ --- Alc/backends/opensl.c | 1070 ---------------------------------------------- Alc/backends/opensl.cpp | 1074 +++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 1075 insertions(+), 1071 deletions(-) delete mode 100644 Alc/backends/opensl.c create mode 100644 Alc/backends/opensl.cpp diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c deleted file mode 100644 index d8ae001b..00000000 --- a/Alc/backends/opensl.c +++ /dev/null @@ -1,1070 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* This is an OpenAL backend for Android using the native audio APIs based on - * OpenSL ES 1.0.1. It is based on source code for the native-audio sample app - * bundled with NDK. - */ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alu.h" -#include "ringbuffer.h" -#include "threads.h" -#include "compat.h" - -#include "backends/base.h" - -#include -#include -#include - -/* Helper macros */ -#define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS -#define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS - - -static const ALCchar opensl_device[] = "OpenSL"; - - -static SLuint32 GetChannelMask(enum DevFmtChannels chans) -{ - switch(chans) - { - case DevFmtMono: return SL_SPEAKER_FRONT_CENTER; - case DevFmtStereo: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT; - case DevFmtQuad: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; - case DevFmtX51: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; - case DevFmtX51Rear: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; - case DevFmtX61: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_BACK_CENTER| - SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; - case DevFmtX71: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT| - SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; - case DevFmtAmbi3D: - break; - } - return 0; -} - -#ifdef SL_DATAFORMAT_PCM_EX -static SLuint32 GetTypeRepresentation(enum DevFmtType type) -{ - switch(type) - { - case DevFmtUByte: - case DevFmtUShort: - case DevFmtUInt: - return SL_PCM_REPRESENTATION_UNSIGNED_INT; - case DevFmtByte: - case DevFmtShort: - case DevFmtInt: - return SL_PCM_REPRESENTATION_SIGNED_INT; - case DevFmtFloat: - return SL_PCM_REPRESENTATION_FLOAT; - } - return 0; -} -#endif - -static const char *res_str(SLresult result) -{ - switch(result) - { - case SL_RESULT_SUCCESS: return "Success"; - case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated"; - case SL_RESULT_PARAMETER_INVALID: return "Parameter invalid"; - case SL_RESULT_MEMORY_FAILURE: return "Memory failure"; - case SL_RESULT_RESOURCE_ERROR: return "Resource error"; - case SL_RESULT_RESOURCE_LOST: return "Resource lost"; - case SL_RESULT_IO_ERROR: return "I/O error"; - case SL_RESULT_BUFFER_INSUFFICIENT: return "Buffer insufficient"; - case SL_RESULT_CONTENT_CORRUPTED: return "Content corrupted"; - case SL_RESULT_CONTENT_UNSUPPORTED: return "Content unsupported"; - case SL_RESULT_CONTENT_NOT_FOUND: return "Content not found"; - case SL_RESULT_PERMISSION_DENIED: return "Permission denied"; - case SL_RESULT_FEATURE_UNSUPPORTED: return "Feature unsupported"; - case SL_RESULT_INTERNAL_ERROR: return "Internal error"; - case SL_RESULT_UNKNOWN_ERROR: return "Unknown error"; - case SL_RESULT_OPERATION_ABORTED: return "Operation aborted"; - case SL_RESULT_CONTROL_LOST: return "Control lost"; -#ifdef SL_RESULT_READONLY - case SL_RESULT_READONLY: return "ReadOnly"; -#endif -#ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED - case SL_RESULT_ENGINEOPTION_UNSUPPORTED: return "Engine option unsupported"; -#endif -#ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE - case SL_RESULT_SOURCE_SINK_INCOMPATIBLE: return "Source/Sink incompatible"; -#endif - } - return "Unknown error code"; -} - -#define PRINTERR(x, s) do { \ - if((x) != SL_RESULT_SUCCESS) \ - ERR("%s: %s\n", (s), res_str((x))); \ -} while(0) - - -typedef struct ALCopenslPlayback { - DERIVE_FROM_TYPE(ALCbackend); - - /* engine interfaces */ - SLObjectItf mEngineObj; - SLEngineItf mEngine; - - /* output mix interfaces */ - SLObjectItf mOutputMix; - - /* buffer queue player interfaces */ - SLObjectItf mBufferQueueObj; - - ll_ringbuffer_t *mRing; - alsem_t mSem; - - ALsizei mFrameSize; - - ATOMIC(ALenum) mKillNow; - althrd_t mThread; -} ALCopenslPlayback; - -static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf bq, void *context); -static int ALCopenslPlayback_mixerProc(void *arg); - -static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *device); -static void ALCopenslPlayback_Destruct(ALCopenslPlayback *self); -static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name); -static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self); -static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self); -static void ALCopenslPlayback_stop(ALCopenslPlayback *self); -static DECLARE_FORWARD2(ALCopenslPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, ALCuint, availableSamples) -static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self); -static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCopenslPlayback) - -DEFINE_ALCBACKEND_VTABLE(ALCopenslPlayback); - - -static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCopenslPlayback, ALCbackend, self); - - self->mEngineObj = NULL; - self->mEngine = NULL; - self->mOutputMix = NULL; - self->mBufferQueueObj = NULL; - - self->mRing = NULL; - alsem_init(&self->mSem, 0); - - self->mFrameSize = 0; - - ATOMIC_INIT(&self->mKillNow, AL_FALSE); -} - -static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self) -{ - if(self->mBufferQueueObj != NULL) - VCALL0(self->mBufferQueueObj,Destroy)(); - self->mBufferQueueObj = NULL; - - if(self->mOutputMix) - VCALL0(self->mOutputMix,Destroy)(); - self->mOutputMix = NULL; - - if(self->mEngineObj) - VCALL0(self->mEngineObj,Destroy)(); - self->mEngineObj = NULL; - self->mEngine = NULL; - - ll_ringbuffer_free(self->mRing); - self->mRing = NULL; - - alsem_destroy(&self->mSem); - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -/* this callback handler is called every time a buffer finishes playing */ -static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), void *context) -{ - ALCopenslPlayback *self = context; - - /* A note on the ringbuffer usage: The buffer queue seems to hold on to the - * pointer passed to the Enqueue method, rather than copying the audio. - * Consequently, the ringbuffer contains the audio that is currently queued - * and waiting to play. This process() callback is called when a buffer is - * finished, so we simply move the read pointer up to indicate the space is - * available for writing again, and wake up the mixer thread to mix and - * queue more audio. - */ - ll_ringbuffer_read_advance(self->mRing, 1); - - alsem_post(&self->mSem); -} - - -static int ALCopenslPlayback_mixerProc(void *arg) -{ - ALCopenslPlayback *self = arg; - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - SLAndroidSimpleBufferQueueItf bufferQueue; - ll_ringbuffer_data_t data[2]; - SLPlayItf player; - SLresult result; - - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue); - PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player); - PRINTERR(result, "bufferQueue->GetInterface SL_IID_PLAY"); - } - - ALCopenslPlayback_lock(self); - if(SL_RESULT_SUCCESS != result) - aluHandleDisconnect(device, "Failed to get playback buffer: 0x%08x", result); - - while(SL_RESULT_SUCCESS == result && - !ATOMIC_LOAD(&self->mKillNow, almemory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) - { - size_t todo; - - if(ll_ringbuffer_write_space(self->mRing) == 0) - { - SLuint32 state = 0; - - result = VCALL(player,GetPlayState)(&state); - PRINTERR(result, "player->GetPlayState"); - if(SL_RESULT_SUCCESS == result && state != SL_PLAYSTATE_PLAYING) - { - result = VCALL(player,SetPlayState)(SL_PLAYSTATE_PLAYING); - PRINTERR(result, "player->SetPlayState"); - } - if(SL_RESULT_SUCCESS != result) - { - aluHandleDisconnect(device, "Failed to start platback: 0x%08x", result); - break; - } - - if(ll_ringbuffer_write_space(self->mRing) == 0) - { - ALCopenslPlayback_unlock(self); - alsem_wait(&self->mSem); - ALCopenslPlayback_lock(self); - continue; - } - } - - ll_ringbuffer_get_write_vector(self->mRing, data); - - aluMixData(device, data[0].buf, data[0].len*device->UpdateSize); - if(data[1].len > 0) - aluMixData(device, data[1].buf, data[1].len*device->UpdateSize); - - todo = data[0].len+data[1].len; - ll_ringbuffer_write_advance(self->mRing, todo); - - for(size_t i = 0;i < todo;i++) - { - if(!data[0].len) - { - data[0] = data[1]; - data[1].buf = NULL; - data[1].len = 0; - } - - result = VCALL(bufferQueue,Enqueue)(data[0].buf, device->UpdateSize*self->mFrameSize); - PRINTERR(result, "bufferQueue->Enqueue"); - if(SL_RESULT_SUCCESS != result) - { - aluHandleDisconnect(device, "Failed to queue audio: 0x%08x", result); - break; - } - - data[0].len--; - data[0].buf += device->UpdateSize*self->mFrameSize; - } - } - ALCopenslPlayback_unlock(self); - - return 0; -} - - -static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - SLresult result; - - if(!name) - name = opensl_device; - else if(strcmp(name, opensl_device) != 0) - return ALC_INVALID_VALUE; - - // create engine - result = slCreateEngine(&self->mEngineObj, 0, NULL, 0, NULL, NULL); - PRINTERR(result, "slCreateEngine"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(self->mEngineObj,Realize)(SL_BOOLEAN_FALSE); - PRINTERR(result, "engine->Realize"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(self->mEngineObj,GetInterface)(SL_IID_ENGINE, &self->mEngine); - PRINTERR(result, "engine->GetInterface"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(self->mEngine,CreateOutputMix)(&self->mOutputMix, 0, NULL, NULL); - PRINTERR(result, "engine->CreateOutputMix"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(self->mOutputMix,Realize)(SL_BOOLEAN_FALSE); - PRINTERR(result, "outputMix->Realize"); - } - - if(SL_RESULT_SUCCESS != result) - { - if(self->mOutputMix != NULL) - VCALL0(self->mOutputMix,Destroy)(); - self->mOutputMix = NULL; - - if(self->mEngineObj != NULL) - VCALL0(self->mEngineObj,Destroy)(); - self->mEngineObj = NULL; - self->mEngine = NULL; - - return ALC_INVALID_VALUE; - } - - alstr_copy_cstr(&device->DeviceName, name); - - return ALC_NO_ERROR; -} - -static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - SLDataLocator_AndroidSimpleBufferQueue loc_bufq; - SLDataLocator_OutputMix loc_outmix; - SLDataSource audioSrc; - SLDataSink audioSnk; - ALuint sampleRate; - SLInterfaceID ids[2]; - SLboolean reqs[2]; - SLresult result; - - if(self->mBufferQueueObj != NULL) - VCALL0(self->mBufferQueueObj,Destroy)(); - self->mBufferQueueObj = NULL; - - ll_ringbuffer_free(self->mRing); - self->mRing = NULL; - - sampleRate = device->Frequency; -#if 0 - if(!(device->Flags&DEVICE_FREQUENCY_REQUEST)) - { - /* FIXME: Disabled until I figure out how to get the Context needed for - * the getSystemService call. - */ - JNIEnv *env = Android_GetJNIEnv(); - jobject jctx = Android_GetContext(); - - /* Get necessary stuff for using java.lang.Integer, - * android.content.Context, and android.media.AudioManager. - */ - jclass int_cls = JCALL(env,FindClass)("java/lang/Integer"); - jmethodID int_parseint = JCALL(env,GetStaticMethodID)(int_cls, - "parseInt", "(Ljava/lang/String;)I" - ); - TRACE("Integer: %p, parseInt: %p\n", int_cls, int_parseint); - - jclass ctx_cls = JCALL(env,FindClass)("android/content/Context"); - jfieldID ctx_audsvc = JCALL(env,GetStaticFieldID)(ctx_cls, - "AUDIO_SERVICE", "Ljava/lang/String;" - ); - jmethodID ctx_getSysSvc = JCALL(env,GetMethodID)(ctx_cls, - "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;" - ); - TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n", - ctx_cls, ctx_audsvc, ctx_getSysSvc); - - jclass audmgr_cls = JCALL(env,FindClass)("android/media/AudioManager"); - jfieldID audmgr_prop_out_srate = JCALL(env,GetStaticFieldID)(audmgr_cls, - "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;" - ); - jmethodID audmgr_getproperty = JCALL(env,GetMethodID)(audmgr_cls, - "getProperty", "(Ljava/lang/String;)Ljava/lang/String;" - ); - TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n", - audmgr_cls, audmgr_prop_out_srate, audmgr_getproperty); - - const char *strchars; - jstring strobj; - - /* Now make the calls. */ - //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE); - strobj = JCALL(env,GetStaticObjectField)(ctx_cls, ctx_audsvc); - jobject audMgr = JCALL(env,CallObjectMethod)(jctx, ctx_getSysSvc, strobj); - strchars = JCALL(env,GetStringUTFChars)(strobj, NULL); - TRACE("Context.getSystemService(%s) = %p\n", strchars, audMgr); - JCALL(env,ReleaseStringUTFChars)(strobj, strchars); - - //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE); - strobj = JCALL(env,GetStaticObjectField)(audmgr_cls, audmgr_prop_out_srate); - jstring srateStr = JCALL(env,CallObjectMethod)(audMgr, audmgr_getproperty, strobj); - strchars = JCALL(env,GetStringUTFChars)(strobj, NULL); - TRACE("audMgr.getProperty(%s) = %p\n", strchars, srateStr); - JCALL(env,ReleaseStringUTFChars)(strobj, strchars); - - //int sampleRate = Integer.parseInt(srateStr); - sampleRate = JCALL(env,CallStaticIntMethod)(int_cls, int_parseint, srateStr); - - strchars = JCALL(env,GetStringUTFChars)(srateStr, NULL); - TRACE("Got system sample rate %uhz (%s)\n", sampleRate, strchars); - JCALL(env,ReleaseStringUTFChars)(srateStr, strchars); - - if(!sampleRate) sampleRate = device->Frequency; - else sampleRate = maxu(sampleRate, MIN_OUTPUT_RATE); - } -#endif - - if(sampleRate != device->Frequency) - { - device->NumUpdates = (device->NumUpdates*sampleRate + (device->Frequency>>1)) / - device->Frequency; - device->NumUpdates = maxu(device->NumUpdates, 2); - device->Frequency = sampleRate; - } - - device->FmtChans = DevFmtStereo; - device->FmtType = DevFmtShort; - - SetDefaultWFXChannelOrder(device); - self->mFrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - - - loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; - loc_bufq.numBuffers = device->NumUpdates; - -#ifdef SL_DATAFORMAT_PCM_EX - SLDataFormat_PCM_EX format_pcm; - format_pcm.formatType = SL_DATAFORMAT_PCM_EX; - format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - format_pcm.sampleRate = device->Frequency * 1000; - format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; - format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(device->FmtChans); - format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : - SL_BYTEORDER_BIGENDIAN; - format_pcm.representation = GetTypeRepresentation(device->FmtType); -#else - SLDataFormat_PCM format_pcm; - format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - format_pcm.samplesPerSec = device->Frequency * 1000; - format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; - format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(device->FmtChans); - format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : - SL_BYTEORDER_BIGENDIAN; -#endif - - audioSrc.pLocator = &loc_bufq; - audioSrc.pFormat = &format_pcm; - - loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; - loc_outmix.outputMix = self->mOutputMix; - audioSnk.pLocator = &loc_outmix; - audioSnk.pFormat = NULL; - - - ids[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE; - reqs[0] = SL_BOOLEAN_TRUE; - ids[1] = SL_IID_ANDROIDCONFIGURATION; - reqs[1] = SL_BOOLEAN_FALSE; - - result = VCALL(self->mEngine,CreateAudioPlayer)(&self->mBufferQueueObj, - &audioSrc, &audioSnk, COUNTOF(ids), ids, reqs - ); - PRINTERR(result, "engine->CreateAudioPlayer"); - if(SL_RESULT_SUCCESS == result) - { - /* Set the stream type to "media" (games, music, etc), if possible. */ - SLAndroidConfigurationItf config; - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config); - PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION"); - if(SL_RESULT_SUCCESS == result) - { - SLint32 streamType = SL_ANDROID_STREAM_MEDIA; - result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_STREAM_TYPE, - &streamType, sizeof(streamType) - ); - PRINTERR(result, "config->SetConfiguration"); - } - - /* Clear any error since this was optional. */ - result = SL_RESULT_SUCCESS; - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(self->mBufferQueueObj,Realize)(SL_BOOLEAN_FALSE); - PRINTERR(result, "bufferQueue->Realize"); - } - if(SL_RESULT_SUCCESS == result) - { - self->mRing = ll_ringbuffer_create(device->NumUpdates, - self->mFrameSize*device->UpdateSize, true - ); - if(!self->mRing) - { - ERR("Out of memory allocating ring buffer %ux%u %u\n", device->UpdateSize, - device->NumUpdates, self->mFrameSize); - result = SL_RESULT_MEMORY_FAILURE; - } - } - - if(SL_RESULT_SUCCESS != result) - { - if(self->mBufferQueueObj != NULL) - VCALL0(self->mBufferQueueObj,Destroy)(); - self->mBufferQueueObj = NULL; - - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self) -{ - SLAndroidSimpleBufferQueueItf bufferQueue; - SLresult result; - - ll_ringbuffer_reset(self->mRing); - - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue); - PRINTERR(result, "bufferQueue->GetInterface"); - if(SL_RESULT_SUCCESS != result) - return ALC_FALSE; - - result = VCALL(bufferQueue,RegisterCallback)(ALCopenslPlayback_process, self); - PRINTERR(result, "bufferQueue->RegisterCallback"); - if(SL_RESULT_SUCCESS != result) - return ALC_FALSE; - - ATOMIC_STORE_SEQ(&self->mKillNow, AL_FALSE); - if(althrd_create(&self->mThread, ALCopenslPlayback_mixerProc, self) != althrd_success) - { - ERR("Failed to start mixer thread\n"); - return ALC_FALSE; - } - - return ALC_TRUE; -} - - -static void ALCopenslPlayback_stop(ALCopenslPlayback *self) -{ - SLAndroidSimpleBufferQueueItf bufferQueue; - SLPlayItf player; - SLresult result; - int res; - - if(ATOMIC_EXCHANGE_SEQ(&self->mKillNow, AL_TRUE)) - return; - - alsem_post(&self->mSem); - althrd_join(self->mThread, &res); - - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player); - PRINTERR(result, "bufferQueue->GetInterface"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(player,SetPlayState)(SL_PLAYSTATE_STOPPED); - PRINTERR(result, "player->SetPlayState"); - } - - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue); - PRINTERR(result, "bufferQueue->GetInterface"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL0(bufferQueue,Clear)(); - PRINTERR(result, "bufferQueue->Clear"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(bufferQueue,RegisterCallback)(NULL, NULL); - PRINTERR(result, "bufferQueue->RegisterCallback"); - } - if(SL_RESULT_SUCCESS == result) - { - SLAndroidSimpleBufferQueueState state; - do { - althrd_yield(); - result = VCALL(bufferQueue,GetState)(&state); - } while(SL_RESULT_SUCCESS == result && state.count > 0); - PRINTERR(result, "bufferQueue->GetState"); - } -} - -static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ClockLatency ret; - - ALCopenslPlayback_lock(self); - ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = ll_ringbuffer_read_space(self->mRing)*device->UpdateSize * - DEVICE_CLOCK_RES / device->Frequency; - ALCopenslPlayback_unlock(self); - - return ret; -} - - -typedef struct ALCopenslCapture { - DERIVE_FROM_TYPE(ALCbackend); - - /* engine interfaces */ - SLObjectItf mEngineObj; - SLEngineItf mEngine; - - /* recording interfaces */ - SLObjectItf mRecordObj; - - ll_ringbuffer_t *mRing; - ALCuint mSplOffset; - - ALsizei mFrameSize; -} ALCopenslCapture; - -static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf bq, void *context); - -static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device); -static void ALCopenslCapture_Destruct(ALCopenslCapture *self); -static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name); -static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, ALCboolean, reset) -static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self); -static void ALCopenslCapture_stop(ALCopenslCapture *self); -static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid *buffer, ALCuint samples); -static ALCuint ALCopenslCapture_availableSamples(ALCopenslCapture *self); -static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCopenslCapture) -DEFINE_ALCBACKEND_VTABLE(ALCopenslCapture); - - -static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), void *context) -{ - ALCopenslCapture *self = context; - /* A new chunk has been written into the ring buffer, advance it. */ - ll_ringbuffer_write_advance(self->mRing, 1); -} - - -static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCopenslCapture, ALCbackend, self); - - self->mEngineObj = NULL; - self->mEngine = NULL; - - self->mRecordObj = NULL; - - self->mRing = NULL; - self->mSplOffset = 0; - - self->mFrameSize = 0; -} - -static void ALCopenslCapture_Destruct(ALCopenslCapture *self) -{ - if(self->mRecordObj != NULL) - VCALL0(self->mRecordObj,Destroy)(); - self->mRecordObj = NULL; - - if(self->mEngineObj != NULL) - VCALL0(self->mEngineObj,Destroy)(); - self->mEngineObj = NULL; - self->mEngine = NULL; - - ll_ringbuffer_free(self->mRing); - self->mRing = NULL; - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - -static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - SLDataLocator_AndroidSimpleBufferQueue loc_bq; - SLAndroidSimpleBufferQueueItf bufferQueue; - SLDataLocator_IODevice loc_dev; - SLDataSource audioSrc; - SLDataSink audioSnk; - SLresult result; - - if(!name) - name = opensl_device; - else if(strcmp(name, opensl_device) != 0) - return ALC_INVALID_VALUE; - - result = slCreateEngine(&self->mEngineObj, 0, NULL, 0, NULL, NULL); - PRINTERR(result, "slCreateEngine"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(self->mEngineObj,Realize)(SL_BOOLEAN_FALSE); - PRINTERR(result, "engine->Realize"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(self->mEngineObj,GetInterface)(SL_IID_ENGINE, &self->mEngine); - PRINTERR(result, "engine->GetInterface"); - } - if(SL_RESULT_SUCCESS == result) - { - /* Ensure the total length is at least 100ms */ - ALsizei length = maxi(device->NumUpdates * device->UpdateSize, - device->Frequency / 10); - /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */ - ALsizei update_len = clampi(device->NumUpdates*device->UpdateSize / 3, - device->Frequency / 100, - device->Frequency / 100 * 5); - - device->UpdateSize = update_len; - device->NumUpdates = (length+update_len-1) / update_len; - - self->mFrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - } - loc_dev.locatorType = SL_DATALOCATOR_IODEVICE; - loc_dev.deviceType = SL_IODEVICE_AUDIOINPUT; - loc_dev.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT; - loc_dev.device = NULL; - - audioSrc.pLocator = &loc_dev; - audioSrc.pFormat = NULL; - - loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; - loc_bq.numBuffers = device->NumUpdates; - -#ifdef SL_DATAFORMAT_PCM_EX - SLDataFormat_PCM_EX format_pcm; - format_pcm.formatType = SL_DATAFORMAT_PCM_EX; - format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - format_pcm.sampleRate = device->Frequency * 1000; - format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; - format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(device->FmtChans); - format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : - SL_BYTEORDER_BIGENDIAN; - format_pcm.representation = GetTypeRepresentation(device->FmtType); -#else - SLDataFormat_PCM format_pcm; - format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - format_pcm.samplesPerSec = device->Frequency * 1000; - format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; - format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(device->FmtChans); - format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : - SL_BYTEORDER_BIGENDIAN; -#endif - - audioSnk.pLocator = &loc_bq; - audioSnk.pFormat = &format_pcm; - - if(SL_RESULT_SUCCESS == result) - { - const SLInterfaceID ids[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }; - const SLboolean reqs[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }; - - result = VCALL(self->mEngine,CreateAudioRecorder)(&self->mRecordObj, - &audioSrc, &audioSnk, COUNTOF(ids), ids, reqs - ); - PRINTERR(result, "engine->CreateAudioRecorder"); - } - if(SL_RESULT_SUCCESS == result) - { - /* Set the record preset to "generic", if possible. */ - SLAndroidConfigurationItf config; - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config); - PRINTERR(result, "recordObj->GetInterface SL_IID_ANDROIDCONFIGURATION"); - if(SL_RESULT_SUCCESS == result) - { - SLuint32 preset = SL_ANDROID_RECORDING_PRESET_GENERIC; - result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_RECORDING_PRESET, - &preset, sizeof(preset) - ); - PRINTERR(result, "config->SetConfiguration"); - } - - /* Clear any error since this was optional. */ - result = SL_RESULT_SUCCESS; - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(self->mRecordObj,Realize)(SL_BOOLEAN_FALSE); - PRINTERR(result, "recordObj->Realize"); - } - - if(SL_RESULT_SUCCESS == result) - { - self->mRing = ll_ringbuffer_create(device->NumUpdates, - device->UpdateSize*self->mFrameSize, false - ); - - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue); - PRINTERR(result, "recordObj->GetInterface"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(bufferQueue,RegisterCallback)(ALCopenslCapture_process, self); - PRINTERR(result, "bufferQueue->RegisterCallback"); - } - if(SL_RESULT_SUCCESS == result) - { - ALsizei chunk_size = device->UpdateSize * self->mFrameSize; - ll_ringbuffer_data_t data[2]; - size_t i; - - ll_ringbuffer_get_write_vector(self->mRing, data); - for(i = 0;i < data[0].len && SL_RESULT_SUCCESS == result;i++) - { - result = VCALL(bufferQueue,Enqueue)(data[0].buf + chunk_size*i, chunk_size); - PRINTERR(result, "bufferQueue->Enqueue"); - } - for(i = 0;i < data[1].len && SL_RESULT_SUCCESS == result;i++) - { - result = VCALL(bufferQueue,Enqueue)(data[1].buf + chunk_size*i, chunk_size); - PRINTERR(result, "bufferQueue->Enqueue"); - } - } - - if(SL_RESULT_SUCCESS != result) - { - if(self->mRecordObj != NULL) - VCALL0(self->mRecordObj,Destroy)(); - self->mRecordObj = NULL; - - if(self->mEngineObj != NULL) - VCALL0(self->mEngineObj,Destroy)(); - self->mEngineObj = NULL; - self->mEngine = NULL; - - return ALC_INVALID_VALUE; - } - - alstr_copy_cstr(&device->DeviceName, name); - - return ALC_NO_ERROR; -} - -static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self) -{ - SLRecordItf record; - SLresult result; - - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_RECORD, &record); - PRINTERR(result, "recordObj->GetInterface"); - - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(record,SetRecordState)(SL_RECORDSTATE_RECORDING); - PRINTERR(result, "record->SetRecordState"); - } - - if(SL_RESULT_SUCCESS != result) - { - ALCopenslCapture_lock(self); - aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, - "Failed to start capture: 0x%08x", result); - ALCopenslCapture_unlock(self); - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static void ALCopenslCapture_stop(ALCopenslCapture *self) -{ - SLRecordItf record; - SLresult result; - - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_RECORD, &record); - PRINTERR(result, "recordObj->GetInterface"); - - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(record,SetRecordState)(SL_RECORDSTATE_PAUSED); - PRINTERR(result, "record->SetRecordState"); - } -} - -static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid *buffer, ALCuint samples) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ALsizei chunk_size = device->UpdateSize * self->mFrameSize; - SLAndroidSimpleBufferQueueItf bufferQueue; - ll_ringbuffer_data_t data[2]; - SLresult result; - ALCuint i; - - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue); - PRINTERR(result, "recordObj->GetInterface"); - - /* Read the desired samples from the ring buffer then advance its read - * pointer. - */ - ll_ringbuffer_get_read_vector(self->mRing, data); - for(i = 0;i < samples;) - { - ALCuint rem = minu(samples - i, device->UpdateSize - self->mSplOffset); - memcpy((ALCbyte*)buffer + i*self->mFrameSize, - data[0].buf + self->mSplOffset*self->mFrameSize, - rem * self->mFrameSize); - - self->mSplOffset += rem; - if(self->mSplOffset == device->UpdateSize) - { - /* Finished a chunk, reset the offset and advance the read pointer. */ - self->mSplOffset = 0; - - ll_ringbuffer_read_advance(self->mRing, 1); - result = VCALL(bufferQueue,Enqueue)(data[0].buf, chunk_size); - PRINTERR(result, "bufferQueue->Enqueue"); - if(SL_RESULT_SUCCESS != result) break; - - data[0].len--; - if(!data[0].len) - data[0] = data[1]; - else - data[0].buf += chunk_size; - } - - i += rem; - } - - if(SL_RESULT_SUCCESS != result) - { - ALCopenslCapture_lock(self); - aluHandleDisconnect(device, "Failed to update capture buffer: 0x%08x", result); - ALCopenslCapture_unlock(self); - return ALC_INVALID_DEVICE; - } - - return ALC_NO_ERROR; -} - -static ALCuint ALCopenslCapture_availableSamples(ALCopenslCapture *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - return ll_ringbuffer_read_space(self->mRing) * device->UpdateSize; -} - - -typedef struct ALCopenslBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCopenslBackendFactory; -#define ALCOPENSLBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCopenslBackendFactory, ALCbackendFactory) } } - -static ALCboolean ALCopenslBackendFactory_init(ALCopenslBackendFactory* UNUSED(self)) -{ - return ALC_TRUE; -} - -static void ALCopenslBackendFactory_deinit(ALCopenslBackendFactory* UNUSED(self)) -{ -} - -static ALCboolean ALCopenslBackendFactory_querySupport(ALCopenslBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} - -static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) -{ - switch(type) - { - case ALL_DEVICE_PROBE: - case CAPTURE_DEVICE_PROBE: - alstr_append_range(outnames, opensl_device, opensl_device+sizeof(opensl_device)); - break; - } -} - -static ALCbackend* ALCopenslBackendFactory_createBackend(ALCopenslBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - { - ALCopenslPlayback *backend; - NEW_OBJ(backend, ALCopenslPlayback)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - if(type == ALCbackend_Capture) - { - ALCopenslCapture *backend; - NEW_OBJ(backend, ALCopenslCapture)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} - -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCopenslBackendFactory); - - -ALCbackendFactory *ALCopenslBackendFactory_getFactory(void) -{ - static ALCopenslBackendFactory factory = ALCOPENSLBACKENDFACTORY_INITIALIZER; - return STATIC_CAST(ALCbackendFactory, &factory); -} diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp new file mode 100644 index 00000000..a8bb57eb --- /dev/null +++ b/Alc/backends/opensl.cpp @@ -0,0 +1,1074 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* This is an OpenAL backend for Android using the native audio APIs based on + * OpenSL ES 1.0.1. It is based on source code for the native-audio sample app + * bundled with NDK. + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alu.h" +#include "ringbuffer.h" +#include "threads.h" +#include "compat.h" + +#include "backends/base.h" + +#include +#include +#include + +/* Helper macros */ +#define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS +#define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS + + +static const ALCchar opensl_device[] = "OpenSL"; + + +static SLuint32 GetChannelMask(enum DevFmtChannels chans) +{ + switch(chans) + { + case DevFmtMono: return SL_SPEAKER_FRONT_CENTER; + case DevFmtStereo: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT; + case DevFmtQuad: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| + SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; + case DevFmtX51: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| + SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| + SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; + case DevFmtX51Rear: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| + SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| + SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; + case DevFmtX61: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| + SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| + SL_SPEAKER_BACK_CENTER| + SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; + case DevFmtX71: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| + SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| + SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT| + SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; + case DevFmtAmbi3D: + break; + } + return 0; +} + +#ifdef SL_DATAFORMAT_PCM_EX +static SLuint32 GetTypeRepresentation(enum DevFmtType type) +{ + switch(type) + { + case DevFmtUByte: + case DevFmtUShort: + case DevFmtUInt: + return SL_PCM_REPRESENTATION_UNSIGNED_INT; + case DevFmtByte: + case DevFmtShort: + case DevFmtInt: + return SL_PCM_REPRESENTATION_SIGNED_INT; + case DevFmtFloat: + return SL_PCM_REPRESENTATION_FLOAT; + } + return 0; +} +#endif + +static const char *res_str(SLresult result) +{ + switch(result) + { + case SL_RESULT_SUCCESS: return "Success"; + case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated"; + case SL_RESULT_PARAMETER_INVALID: return "Parameter invalid"; + case SL_RESULT_MEMORY_FAILURE: return "Memory failure"; + case SL_RESULT_RESOURCE_ERROR: return "Resource error"; + case SL_RESULT_RESOURCE_LOST: return "Resource lost"; + case SL_RESULT_IO_ERROR: return "I/O error"; + case SL_RESULT_BUFFER_INSUFFICIENT: return "Buffer insufficient"; + case SL_RESULT_CONTENT_CORRUPTED: return "Content corrupted"; + case SL_RESULT_CONTENT_UNSUPPORTED: return "Content unsupported"; + case SL_RESULT_CONTENT_NOT_FOUND: return "Content not found"; + case SL_RESULT_PERMISSION_DENIED: return "Permission denied"; + case SL_RESULT_FEATURE_UNSUPPORTED: return "Feature unsupported"; + case SL_RESULT_INTERNAL_ERROR: return "Internal error"; + case SL_RESULT_UNKNOWN_ERROR: return "Unknown error"; + case SL_RESULT_OPERATION_ABORTED: return "Operation aborted"; + case SL_RESULT_CONTROL_LOST: return "Control lost"; +#ifdef SL_RESULT_READONLY + case SL_RESULT_READONLY: return "ReadOnly"; +#endif +#ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED + case SL_RESULT_ENGINEOPTION_UNSUPPORTED: return "Engine option unsupported"; +#endif +#ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE + case SL_RESULT_SOURCE_SINK_INCOMPATIBLE: return "Source/Sink incompatible"; +#endif + } + return "Unknown error code"; +} + +#define PRINTERR(x, s) do { \ + if((x) != SL_RESULT_SUCCESS) \ + ERR("%s: %s\n", (s), res_str((x))); \ +} while(0) + + +struct ALCopenslPlayback final : public ALCbackend { + /* engine interfaces */ + SLObjectItf mEngineObj; + SLEngineItf mEngine; + + /* output mix interfaces */ + SLObjectItf mOutputMix; + + /* buffer queue player interfaces */ + SLObjectItf mBufferQueueObj; + + ll_ringbuffer_t *mRing; + alsem_t mSem; + + ALsizei mFrameSize; + + ATOMIC(ALenum) mKillNow; + althrd_t mThread; +}; + +static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf bq, void *context); +static int ALCopenslPlayback_mixerProc(void *arg); + +static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *device); +static void ALCopenslPlayback_Destruct(ALCopenslPlayback *self); +static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name); +static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self); +static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self); +static void ALCopenslPlayback_stop(ALCopenslPlayback *self); +static DECLARE_FORWARD2(ALCopenslPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, ALCuint, availableSamples) +static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self); +static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCopenslPlayback) + +DEFINE_ALCBACKEND_VTABLE(ALCopenslPlayback); + + +static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *device) +{ + new (self) ALCopenslPlayback{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCopenslPlayback, ALCbackend, self); + + self->mEngineObj = NULL; + self->mEngine = NULL; + self->mOutputMix = NULL; + self->mBufferQueueObj = NULL; + + self->mRing = NULL; + alsem_init(&self->mSem, 0); + + self->mFrameSize = 0; + + ATOMIC_INIT(&self->mKillNow, AL_FALSE); +} + +static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self) +{ + if(self->mBufferQueueObj != NULL) + VCALL0(self->mBufferQueueObj,Destroy)(); + self->mBufferQueueObj = NULL; + + if(self->mOutputMix) + VCALL0(self->mOutputMix,Destroy)(); + self->mOutputMix = NULL; + + if(self->mEngineObj) + VCALL0(self->mEngineObj,Destroy)(); + self->mEngineObj = NULL; + self->mEngine = NULL; + + ll_ringbuffer_free(self->mRing); + self->mRing = NULL; + + alsem_destroy(&self->mSem); + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCopenslPlayback(); +} + + +/* this callback handler is called every time a buffer finishes playing */ +static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), void *context) +{ + ALCopenslPlayback *self = static_cast(context); + + /* A note on the ringbuffer usage: The buffer queue seems to hold on to the + * pointer passed to the Enqueue method, rather than copying the audio. + * Consequently, the ringbuffer contains the audio that is currently queued + * and waiting to play. This process() callback is called when a buffer is + * finished, so we simply move the read pointer up to indicate the space is + * available for writing again, and wake up the mixer thread to mix and + * queue more audio. + */ + ll_ringbuffer_read_advance(self->mRing, 1); + + alsem_post(&self->mSem); +} + + +static int ALCopenslPlayback_mixerProc(void *arg) +{ + ALCopenslPlayback *self = static_cast(arg); + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + SLAndroidSimpleBufferQueueItf bufferQueue; + ll_ringbuffer_data_t data[2]; + SLPlayItf player; + SLresult result; + + SetRTPriority(); + althrd_setname(althrd_current(), MIXER_THREAD_NAME); + + result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &bufferQueue); + PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE"); + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player); + PRINTERR(result, "bufferQueue->GetInterface SL_IID_PLAY"); + } + + ALCopenslPlayback_lock(self); + if(SL_RESULT_SUCCESS != result) + aluHandleDisconnect(device, "Failed to get playback buffer: 0x%08x", result); + + while(SL_RESULT_SUCCESS == result && + !ATOMIC_LOAD(&self->mKillNow, almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + { + size_t todo; + + if(ll_ringbuffer_write_space(self->mRing) == 0) + { + SLuint32 state = 0; + + result = VCALL(player,GetPlayState)(&state); + PRINTERR(result, "player->GetPlayState"); + if(SL_RESULT_SUCCESS == result && state != SL_PLAYSTATE_PLAYING) + { + result = VCALL(player,SetPlayState)(SL_PLAYSTATE_PLAYING); + PRINTERR(result, "player->SetPlayState"); + } + if(SL_RESULT_SUCCESS != result) + { + aluHandleDisconnect(device, "Failed to start platback: 0x%08x", result); + break; + } + + if(ll_ringbuffer_write_space(self->mRing) == 0) + { + ALCopenslPlayback_unlock(self); + alsem_wait(&self->mSem); + ALCopenslPlayback_lock(self); + continue; + } + } + + ll_ringbuffer_get_write_vector(self->mRing, data); + + aluMixData(device, data[0].buf, data[0].len*device->UpdateSize); + if(data[1].len > 0) + aluMixData(device, data[1].buf, data[1].len*device->UpdateSize); + + todo = data[0].len+data[1].len; + ll_ringbuffer_write_advance(self->mRing, todo); + + for(size_t i = 0;i < todo;i++) + { + if(!data[0].len) + { + data[0] = data[1]; + data[1].buf = NULL; + data[1].len = 0; + } + + result = VCALL(bufferQueue,Enqueue)(data[0].buf, device->UpdateSize*self->mFrameSize); + PRINTERR(result, "bufferQueue->Enqueue"); + if(SL_RESULT_SUCCESS != result) + { + aluHandleDisconnect(device, "Failed to queue audio: 0x%08x", result); + break; + } + + data[0].len--; + data[0].buf += device->UpdateSize*self->mFrameSize; + } + } + ALCopenslPlayback_unlock(self); + + return 0; +} + + +static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + SLresult result; + + if(!name) + name = opensl_device; + else if(strcmp(name, opensl_device) != 0) + return ALC_INVALID_VALUE; + + // create engine + result = slCreateEngine(&self->mEngineObj, 0, NULL, 0, NULL, NULL); + PRINTERR(result, "slCreateEngine"); + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(self->mEngineObj,Realize)(SL_BOOLEAN_FALSE); + PRINTERR(result, "engine->Realize"); + } + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(self->mEngineObj,GetInterface)(SL_IID_ENGINE, &self->mEngine); + PRINTERR(result, "engine->GetInterface"); + } + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(self->mEngine,CreateOutputMix)(&self->mOutputMix, 0, NULL, NULL); + PRINTERR(result, "engine->CreateOutputMix"); + } + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(self->mOutputMix,Realize)(SL_BOOLEAN_FALSE); + PRINTERR(result, "outputMix->Realize"); + } + + if(SL_RESULT_SUCCESS != result) + { + if(self->mOutputMix != NULL) + VCALL0(self->mOutputMix,Destroy)(); + self->mOutputMix = NULL; + + if(self->mEngineObj != NULL) + VCALL0(self->mEngineObj,Destroy)(); + self->mEngineObj = NULL; + self->mEngine = NULL; + + return ALC_INVALID_VALUE; + } + + alstr_copy_cstr(&device->DeviceName, name); + + return ALC_NO_ERROR; +} + +static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + SLDataLocator_AndroidSimpleBufferQueue loc_bufq; + SLDataLocator_OutputMix loc_outmix; + SLDataSource audioSrc; + SLDataSink audioSnk; + ALuint sampleRate; + SLInterfaceID ids[2]; + SLboolean reqs[2]; + SLresult result; + + if(self->mBufferQueueObj != NULL) + VCALL0(self->mBufferQueueObj,Destroy)(); + self->mBufferQueueObj = NULL; + + ll_ringbuffer_free(self->mRing); + self->mRing = NULL; + + sampleRate = device->Frequency; +#if 0 + if(!(device->Flags&DEVICE_FREQUENCY_REQUEST)) + { + /* FIXME: Disabled until I figure out how to get the Context needed for + * the getSystemService call. + */ + JNIEnv *env = Android_GetJNIEnv(); + jobject jctx = Android_GetContext(); + + /* Get necessary stuff for using java.lang.Integer, + * android.content.Context, and android.media.AudioManager. + */ + jclass int_cls = JCALL(env,FindClass)("java/lang/Integer"); + jmethodID int_parseint = JCALL(env,GetStaticMethodID)(int_cls, + "parseInt", "(Ljava/lang/String;)I" + ); + TRACE("Integer: %p, parseInt: %p\n", int_cls, int_parseint); + + jclass ctx_cls = JCALL(env,FindClass)("android/content/Context"); + jfieldID ctx_audsvc = JCALL(env,GetStaticFieldID)(ctx_cls, + "AUDIO_SERVICE", "Ljava/lang/String;" + ); + jmethodID ctx_getSysSvc = JCALL(env,GetMethodID)(ctx_cls, + "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;" + ); + TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n", + ctx_cls, ctx_audsvc, ctx_getSysSvc); + + jclass audmgr_cls = JCALL(env,FindClass)("android/media/AudioManager"); + jfieldID audmgr_prop_out_srate = JCALL(env,GetStaticFieldID)(audmgr_cls, + "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;" + ); + jmethodID audmgr_getproperty = JCALL(env,GetMethodID)(audmgr_cls, + "getProperty", "(Ljava/lang/String;)Ljava/lang/String;" + ); + TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n", + audmgr_cls, audmgr_prop_out_srate, audmgr_getproperty); + + const char *strchars; + jstring strobj; + + /* Now make the calls. */ + //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE); + strobj = JCALL(env,GetStaticObjectField)(ctx_cls, ctx_audsvc); + jobject audMgr = JCALL(env,CallObjectMethod)(jctx, ctx_getSysSvc, strobj); + strchars = JCALL(env,GetStringUTFChars)(strobj, NULL); + TRACE("Context.getSystemService(%s) = %p\n", strchars, audMgr); + JCALL(env,ReleaseStringUTFChars)(strobj, strchars); + + //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE); + strobj = JCALL(env,GetStaticObjectField)(audmgr_cls, audmgr_prop_out_srate); + jstring srateStr = JCALL(env,CallObjectMethod)(audMgr, audmgr_getproperty, strobj); + strchars = JCALL(env,GetStringUTFChars)(strobj, NULL); + TRACE("audMgr.getProperty(%s) = %p\n", strchars, srateStr); + JCALL(env,ReleaseStringUTFChars)(strobj, strchars); + + //int sampleRate = Integer.parseInt(srateStr); + sampleRate = JCALL(env,CallStaticIntMethod)(int_cls, int_parseint, srateStr); + + strchars = JCALL(env,GetStringUTFChars)(srateStr, NULL); + TRACE("Got system sample rate %uhz (%s)\n", sampleRate, strchars); + JCALL(env,ReleaseStringUTFChars)(srateStr, strchars); + + if(!sampleRate) sampleRate = device->Frequency; + else sampleRate = maxu(sampleRate, MIN_OUTPUT_RATE); + } +#endif + + if(sampleRate != device->Frequency) + { + device->NumUpdates = (device->NumUpdates*sampleRate + (device->Frequency>>1)) / + device->Frequency; + device->NumUpdates = maxu(device->NumUpdates, 2); + device->Frequency = sampleRate; + } + + device->FmtChans = DevFmtStereo; + device->FmtType = DevFmtShort; + + SetDefaultWFXChannelOrder(device); + self->mFrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + + + loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; + loc_bufq.numBuffers = device->NumUpdates; + +#ifdef SL_DATAFORMAT_PCM_EX + SLDataFormat_PCM_EX format_pcm; + format_pcm.formatType = SL_DATAFORMAT_PCM_EX; + format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + format_pcm.sampleRate = device->Frequency * 1000; + format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + format_pcm.containerSize = format_pcm.bitsPerSample; + format_pcm.channelMask = GetChannelMask(device->FmtChans); + format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : + SL_BYTEORDER_BIGENDIAN; + format_pcm.representation = GetTypeRepresentation(device->FmtType); +#else + SLDataFormat_PCM format_pcm; + format_pcm.formatType = SL_DATAFORMAT_PCM; + format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + format_pcm.samplesPerSec = device->Frequency * 1000; + format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + format_pcm.containerSize = format_pcm.bitsPerSample; + format_pcm.channelMask = GetChannelMask(device->FmtChans); + format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : + SL_BYTEORDER_BIGENDIAN; +#endif + + audioSrc.pLocator = &loc_bufq; + audioSrc.pFormat = &format_pcm; + + loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; + loc_outmix.outputMix = self->mOutputMix; + audioSnk.pLocator = &loc_outmix; + audioSnk.pFormat = NULL; + + + ids[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE; + reqs[0] = SL_BOOLEAN_TRUE; + ids[1] = SL_IID_ANDROIDCONFIGURATION; + reqs[1] = SL_BOOLEAN_FALSE; + + result = VCALL(self->mEngine,CreateAudioPlayer)(&self->mBufferQueueObj, + &audioSrc, &audioSnk, COUNTOF(ids), ids, reqs + ); + PRINTERR(result, "engine->CreateAudioPlayer"); + if(SL_RESULT_SUCCESS == result) + { + /* Set the stream type to "media" (games, music, etc), if possible. */ + SLAndroidConfigurationItf config; + result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config); + PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION"); + if(SL_RESULT_SUCCESS == result) + { + SLint32 streamType = SL_ANDROID_STREAM_MEDIA; + result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_STREAM_TYPE, + &streamType, sizeof(streamType) + ); + PRINTERR(result, "config->SetConfiguration"); + } + + /* Clear any error since this was optional. */ + result = SL_RESULT_SUCCESS; + } + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(self->mBufferQueueObj,Realize)(SL_BOOLEAN_FALSE); + PRINTERR(result, "bufferQueue->Realize"); + } + if(SL_RESULT_SUCCESS == result) + { + self->mRing = ll_ringbuffer_create(device->NumUpdates, + self->mFrameSize*device->UpdateSize, true + ); + if(!self->mRing) + { + ERR("Out of memory allocating ring buffer %ux%u %u\n", device->UpdateSize, + device->NumUpdates, self->mFrameSize); + result = SL_RESULT_MEMORY_FAILURE; + } + } + + if(SL_RESULT_SUCCESS != result) + { + if(self->mBufferQueueObj != NULL) + VCALL0(self->mBufferQueueObj,Destroy)(); + self->mBufferQueueObj = NULL; + + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self) +{ + SLAndroidSimpleBufferQueueItf bufferQueue; + SLresult result; + + ll_ringbuffer_reset(self->mRing); + + result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &bufferQueue); + PRINTERR(result, "bufferQueue->GetInterface"); + if(SL_RESULT_SUCCESS != result) + return ALC_FALSE; + + result = VCALL(bufferQueue,RegisterCallback)(ALCopenslPlayback_process, self); + PRINTERR(result, "bufferQueue->RegisterCallback"); + if(SL_RESULT_SUCCESS != result) + return ALC_FALSE; + + ATOMIC_STORE_SEQ(&self->mKillNow, AL_FALSE); + if(althrd_create(&self->mThread, ALCopenslPlayback_mixerProc, self) != althrd_success) + { + ERR("Failed to start mixer thread\n"); + return ALC_FALSE; + } + + return ALC_TRUE; +} + + +static void ALCopenslPlayback_stop(ALCopenslPlayback *self) +{ + SLAndroidSimpleBufferQueueItf bufferQueue; + SLPlayItf player; + SLresult result; + int res; + + if(ATOMIC_EXCHANGE_SEQ(&self->mKillNow, AL_TRUE)) + return; + + alsem_post(&self->mSem); + althrd_join(self->mThread, &res); + + result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player); + PRINTERR(result, "bufferQueue->GetInterface"); + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(player,SetPlayState)(SL_PLAYSTATE_STOPPED); + PRINTERR(result, "player->SetPlayState"); + } + + result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &bufferQueue); + PRINTERR(result, "bufferQueue->GetInterface"); + if(SL_RESULT_SUCCESS == result) + { + result = VCALL0(bufferQueue,Clear)(); + PRINTERR(result, "bufferQueue->Clear"); + } + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(bufferQueue,RegisterCallback)(NULL, NULL); + PRINTERR(result, "bufferQueue->RegisterCallback"); + } + if(SL_RESULT_SUCCESS == result) + { + SLAndroidSimpleBufferQueueState state; + do { + althrd_yield(); + result = VCALL(bufferQueue,GetState)(&state); + } while(SL_RESULT_SUCCESS == result && state.count > 0); + PRINTERR(result, "bufferQueue->GetState"); + } +} + +static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ClockLatency ret; + + ALCopenslPlayback_lock(self); + ret.ClockTime = GetDeviceClockTime(device); + ret.Latency = ll_ringbuffer_read_space(self->mRing)*device->UpdateSize * + DEVICE_CLOCK_RES / device->Frequency; + ALCopenslPlayback_unlock(self); + + return ret; +} + + +struct ALCopenslCapture final : public ALCbackend { + /* engine interfaces */ + SLObjectItf mEngineObj; + SLEngineItf mEngine; + + /* recording interfaces */ + SLObjectItf mRecordObj; + + ll_ringbuffer_t *mRing; + ALCuint mSplOffset; + + ALsizei mFrameSize; +}; + +static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf bq, void *context); + +static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device); +static void ALCopenslCapture_Destruct(ALCopenslCapture *self); +static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name); +static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, ALCboolean, reset) +static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self); +static void ALCopenslCapture_stop(ALCopenslCapture *self); +static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid *buffer, ALCuint samples); +static ALCuint ALCopenslCapture_availableSamples(ALCopenslCapture *self); +static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCopenslCapture) +DEFINE_ALCBACKEND_VTABLE(ALCopenslCapture); + + +static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device) +{ + new (self) ALCopenslCapture{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCopenslCapture, ALCbackend, self); + + self->mEngineObj = NULL; + self->mEngine = NULL; + + self->mRecordObj = NULL; + + self->mRing = NULL; + self->mSplOffset = 0; + + self->mFrameSize = 0; +} + +static void ALCopenslCapture_Destruct(ALCopenslCapture *self) +{ + if(self->mRecordObj != NULL) + VCALL0(self->mRecordObj,Destroy)(); + self->mRecordObj = NULL; + + if(self->mEngineObj != NULL) + VCALL0(self->mEngineObj,Destroy)(); + self->mEngineObj = NULL; + self->mEngine = NULL; + + ll_ringbuffer_free(self->mRing); + self->mRing = NULL; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCopenslCapture(); +} + + +static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), void *context) +{ + ALCopenslCapture *self = static_cast(context); + /* A new chunk has been written into the ring buffer, advance it. */ + ll_ringbuffer_write_advance(self->mRing, 1); +} + + +static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + SLDataLocator_AndroidSimpleBufferQueue loc_bq; + SLAndroidSimpleBufferQueueItf bufferQueue; + SLDataLocator_IODevice loc_dev; + SLDataSource audioSrc; + SLDataSink audioSnk; + SLresult result; + + if(!name) + name = opensl_device; + else if(strcmp(name, opensl_device) != 0) + return ALC_INVALID_VALUE; + + result = slCreateEngine(&self->mEngineObj, 0, NULL, 0, NULL, NULL); + PRINTERR(result, "slCreateEngine"); + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(self->mEngineObj,Realize)(SL_BOOLEAN_FALSE); + PRINTERR(result, "engine->Realize"); + } + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(self->mEngineObj,GetInterface)(SL_IID_ENGINE, &self->mEngine); + PRINTERR(result, "engine->GetInterface"); + } + if(SL_RESULT_SUCCESS == result) + { + /* Ensure the total length is at least 100ms */ + ALsizei length = maxi(device->NumUpdates * device->UpdateSize, + device->Frequency / 10); + /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */ + ALsizei update_len = clampi(device->NumUpdates*device->UpdateSize / 3, + device->Frequency / 100, + device->Frequency / 100 * 5); + + device->UpdateSize = update_len; + device->NumUpdates = (length+update_len-1) / update_len; + + self->mFrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + } + loc_dev.locatorType = SL_DATALOCATOR_IODEVICE; + loc_dev.deviceType = SL_IODEVICE_AUDIOINPUT; + loc_dev.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT; + loc_dev.device = NULL; + + audioSrc.pLocator = &loc_dev; + audioSrc.pFormat = NULL; + + loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; + loc_bq.numBuffers = device->NumUpdates; + +#ifdef SL_DATAFORMAT_PCM_EX + SLDataFormat_PCM_EX format_pcm; + format_pcm.formatType = SL_DATAFORMAT_PCM_EX; + format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + format_pcm.sampleRate = device->Frequency * 1000; + format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + format_pcm.containerSize = format_pcm.bitsPerSample; + format_pcm.channelMask = GetChannelMask(device->FmtChans); + format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : + SL_BYTEORDER_BIGENDIAN; + format_pcm.representation = GetTypeRepresentation(device->FmtType); +#else + SLDataFormat_PCM format_pcm; + format_pcm.formatType = SL_DATAFORMAT_PCM; + format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + format_pcm.samplesPerSec = device->Frequency * 1000; + format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + format_pcm.containerSize = format_pcm.bitsPerSample; + format_pcm.channelMask = GetChannelMask(device->FmtChans); + format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : + SL_BYTEORDER_BIGENDIAN; +#endif + + audioSnk.pLocator = &loc_bq; + audioSnk.pFormat = &format_pcm; + + if(SL_RESULT_SUCCESS == result) + { + const SLInterfaceID ids[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }; + const SLboolean reqs[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }; + + result = VCALL(self->mEngine,CreateAudioRecorder)(&self->mRecordObj, + &audioSrc, &audioSnk, COUNTOF(ids), ids, reqs + ); + PRINTERR(result, "engine->CreateAudioRecorder"); + } + if(SL_RESULT_SUCCESS == result) + { + /* Set the record preset to "generic", if possible. */ + SLAndroidConfigurationItf config; + result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config); + PRINTERR(result, "recordObj->GetInterface SL_IID_ANDROIDCONFIGURATION"); + if(SL_RESULT_SUCCESS == result) + { + SLuint32 preset = SL_ANDROID_RECORDING_PRESET_GENERIC; + result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_RECORDING_PRESET, + &preset, sizeof(preset) + ); + PRINTERR(result, "config->SetConfiguration"); + } + + /* Clear any error since this was optional. */ + result = SL_RESULT_SUCCESS; + } + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(self->mRecordObj,Realize)(SL_BOOLEAN_FALSE); + PRINTERR(result, "recordObj->Realize"); + } + + if(SL_RESULT_SUCCESS == result) + { + self->mRing = ll_ringbuffer_create(device->NumUpdates, + device->UpdateSize*self->mFrameSize, false + ); + + result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &bufferQueue); + PRINTERR(result, "recordObj->GetInterface"); + } + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(bufferQueue,RegisterCallback)(ALCopenslCapture_process, self); + PRINTERR(result, "bufferQueue->RegisterCallback"); + } + if(SL_RESULT_SUCCESS == result) + { + ALsizei chunk_size = device->UpdateSize * self->mFrameSize; + ll_ringbuffer_data_t data[2]; + size_t i; + + ll_ringbuffer_get_write_vector(self->mRing, data); + for(i = 0;i < data[0].len && SL_RESULT_SUCCESS == result;i++) + { + result = VCALL(bufferQueue,Enqueue)(data[0].buf + chunk_size*i, chunk_size); + PRINTERR(result, "bufferQueue->Enqueue"); + } + for(i = 0;i < data[1].len && SL_RESULT_SUCCESS == result;i++) + { + result = VCALL(bufferQueue,Enqueue)(data[1].buf + chunk_size*i, chunk_size); + PRINTERR(result, "bufferQueue->Enqueue"); + } + } + + if(SL_RESULT_SUCCESS != result) + { + if(self->mRecordObj != NULL) + VCALL0(self->mRecordObj,Destroy)(); + self->mRecordObj = NULL; + + if(self->mEngineObj != NULL) + VCALL0(self->mEngineObj,Destroy)(); + self->mEngineObj = NULL; + self->mEngine = NULL; + + return ALC_INVALID_VALUE; + } + + alstr_copy_cstr(&device->DeviceName, name); + + return ALC_NO_ERROR; +} + +static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self) +{ + SLRecordItf record; + SLresult result; + + result = VCALL(self->mRecordObj,GetInterface)(SL_IID_RECORD, &record); + PRINTERR(result, "recordObj->GetInterface"); + + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(record,SetRecordState)(SL_RECORDSTATE_RECORDING); + PRINTERR(result, "record->SetRecordState"); + } + + if(SL_RESULT_SUCCESS != result) + { + ALCopenslCapture_lock(self); + aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, + "Failed to start capture: 0x%08x", result); + ALCopenslCapture_unlock(self); + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static void ALCopenslCapture_stop(ALCopenslCapture *self) +{ + SLRecordItf record; + SLresult result; + + result = VCALL(self->mRecordObj,GetInterface)(SL_IID_RECORD, &record); + PRINTERR(result, "recordObj->GetInterface"); + + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(record,SetRecordState)(SL_RECORDSTATE_PAUSED); + PRINTERR(result, "record->SetRecordState"); + } +} + +static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid *buffer, ALCuint samples) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALsizei chunk_size = device->UpdateSize * self->mFrameSize; + SLAndroidSimpleBufferQueueItf bufferQueue; + ll_ringbuffer_data_t data[2]; + SLresult result; + ALCuint i; + + result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &bufferQueue); + PRINTERR(result, "recordObj->GetInterface"); + + /* Read the desired samples from the ring buffer then advance its read + * pointer. + */ + ll_ringbuffer_get_read_vector(self->mRing, data); + for(i = 0;i < samples;) + { + ALCuint rem = minu(samples - i, device->UpdateSize - self->mSplOffset); + memcpy((ALCbyte*)buffer + i*self->mFrameSize, + data[0].buf + self->mSplOffset*self->mFrameSize, + rem * self->mFrameSize); + + self->mSplOffset += rem; + if(self->mSplOffset == device->UpdateSize) + { + /* Finished a chunk, reset the offset and advance the read pointer. */ + self->mSplOffset = 0; + + ll_ringbuffer_read_advance(self->mRing, 1); + result = VCALL(bufferQueue,Enqueue)(data[0].buf, chunk_size); + PRINTERR(result, "bufferQueue->Enqueue"); + if(SL_RESULT_SUCCESS != result) break; + + data[0].len--; + if(!data[0].len) + data[0] = data[1]; + else + data[0].buf += chunk_size; + } + + i += rem; + } + + if(SL_RESULT_SUCCESS != result) + { + ALCopenslCapture_lock(self); + aluHandleDisconnect(device, "Failed to update capture buffer: 0x%08x", result); + ALCopenslCapture_unlock(self); + return ALC_INVALID_DEVICE; + } + + return ALC_NO_ERROR; +} + +static ALCuint ALCopenslCapture_availableSamples(ALCopenslCapture *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + return ll_ringbuffer_read_space(self->mRing) * device->UpdateSize; +} + + +struct ALCopenslBackendFactory final : public ALCbackendFactory { + ALCopenslBackendFactory() noexcept; +}; + +static ALCboolean ALCopenslBackendFactory_init(ALCopenslBackendFactory* UNUSED(self)) +{ + return ALC_TRUE; +} + +static void ALCopenslBackendFactory_deinit(ALCopenslBackendFactory* UNUSED(self)) +{ +} + +static ALCboolean ALCopenslBackendFactory_querySupport(ALCopenslBackendFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Playback || type == ALCbackend_Capture) + return ALC_TRUE; + return ALC_FALSE; +} + +static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +{ + switch(type) + { + case ALL_DEVICE_PROBE: + case CAPTURE_DEVICE_PROBE: + alstr_append_range(outnames, opensl_device, opensl_device+sizeof(opensl_device)); + break; + } +} + +static ALCbackend* ALCopenslBackendFactory_createBackend(ALCopenslBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCopenslPlayback *backend; + NEW_OBJ(backend, ALCopenslPlayback)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + if(type == ALCbackend_Capture) + { + ALCopenslCapture *backend; + NEW_OBJ(backend, ALCopenslCapture)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + + return NULL; +} + +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCopenslBackendFactory); + + +ALCopenslBackendFactory::ALCopenslBackendFactory() noexcept + : ALCbackendFactory{GET_VTABLE2(ALCopenslBackendFactory, ALCbackendFactory)} +{ } + +ALCbackendFactory *ALCopenslBackendFactory_getFactory(void) +{ + static ALCopenslBackendFactory factory{}; + return STATIC_CAST(ALCbackendFactory, &factory); +} diff --git a/CMakeLists.txt b/CMakeLists.txt index b4c0c8f0..61133c50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1274,7 +1274,7 @@ IF(HAVE_SLES_OPENSLES_ANDROID_H) OPTION(ALSOFT_BACKEND_OPENSL "Enable OpenSL backend" ON) IF(ALSOFT_BACKEND_OPENSL) SET(HAVE_OPENSL 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/opensl.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/opensl.cpp) SET(BACKENDS "${BACKENDS} OpenSL,") SET(EXTRA_LIBS OpenSLES ${EXTRA_LIBS}) ENDIF() -- cgit v1.2.3 From 1f34af47189b2fdbea313d884b9971a10dffe61b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Nov 2018 01:20:15 -0800 Subject: Convert the JACK backend to C++ --- Alc/backends/jack.c | 609 -------------------------------------------------- Alc/backends/jack.cpp | 608 +++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 609 insertions(+), 610 deletions(-) delete mode 100644 Alc/backends/jack.c create mode 100644 Alc/backends/jack.cpp diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c deleted file mode 100644 index 8f934687..00000000 --- a/Alc/backends/jack.c +++ /dev/null @@ -1,609 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include "alMain.h" -#include "alu.h" -#include "alconfig.h" -#include "ringbuffer.h" -#include "threads.h" -#include "compat.h" - -#include "backends/base.h" - -#include -#include - - -static const ALCchar jackDevice[] = "JACK Default"; - - -#ifdef HAVE_DYNLOAD -#define JACK_FUNCS(MAGIC) \ - MAGIC(jack_client_open); \ - MAGIC(jack_client_close); \ - MAGIC(jack_client_name_size); \ - MAGIC(jack_get_client_name); \ - MAGIC(jack_connect); \ - MAGIC(jack_activate); \ - MAGIC(jack_deactivate); \ - MAGIC(jack_port_register); \ - MAGIC(jack_port_unregister); \ - MAGIC(jack_port_get_buffer); \ - MAGIC(jack_port_name); \ - MAGIC(jack_get_ports); \ - MAGIC(jack_free); \ - MAGIC(jack_get_sample_rate); \ - MAGIC(jack_set_error_function); \ - MAGIC(jack_set_process_callback); \ - MAGIC(jack_set_buffer_size_callback); \ - MAGIC(jack_set_buffer_size); \ - MAGIC(jack_get_buffer_size); - -static void *jack_handle; -#define MAKE_FUNC(f) static __typeof(f) * p##f -JACK_FUNCS(MAKE_FUNC); -static __typeof(jack_error_callback) * pjack_error_callback; -#undef MAKE_FUNC - -#ifndef IN_IDE_PARSER -#define jack_client_open pjack_client_open -#define jack_client_close pjack_client_close -#define jack_client_name_size pjack_client_name_size -#define jack_get_client_name pjack_get_client_name -#define jack_connect pjack_connect -#define jack_activate pjack_activate -#define jack_deactivate pjack_deactivate -#define jack_port_register pjack_port_register -#define jack_port_unregister pjack_port_unregister -#define jack_port_get_buffer pjack_port_get_buffer -#define jack_port_name pjack_port_name -#define jack_get_ports pjack_get_ports -#define jack_free pjack_free -#define jack_get_sample_rate pjack_get_sample_rate -#define jack_set_error_function pjack_set_error_function -#define jack_set_process_callback pjack_set_process_callback -#define jack_set_buffer_size_callback pjack_set_buffer_size_callback -#define jack_set_buffer_size pjack_set_buffer_size -#define jack_get_buffer_size pjack_get_buffer_size -#define jack_error_callback (*pjack_error_callback) -#endif -#endif - - -static jack_options_t ClientOptions = JackNullOption; - -static ALCboolean jack_load(void) -{ - ALCboolean error = ALC_FALSE; - -#ifdef HAVE_DYNLOAD - if(!jack_handle) - { - al_string missing_funcs = AL_STRING_INIT_STATIC(); - -#ifdef _WIN32 -#define JACKLIB "libjack.dll" -#else -#define JACKLIB "libjack.so.0" -#endif - jack_handle = LoadLib(JACKLIB); - if(!jack_handle) - { - WARN("Failed to load %s\n", JACKLIB); - return ALC_FALSE; - } - - error = ALC_FALSE; -#define LOAD_FUNC(f) do { \ - p##f = GetSymbol(jack_handle, #f); \ - if(p##f == NULL) { \ - error = ALC_TRUE; \ - alstr_append_cstr(&missing_funcs, "\n" #f); \ - } \ -} while(0) - JACK_FUNCS(LOAD_FUNC); -#undef LOAD_FUNC - /* Optional symbols. These don't exist in all versions of JACK. */ -#define LOAD_SYM(f) p##f = GetSymbol(jack_handle, #f) - LOAD_SYM(jack_error_callback); -#undef LOAD_SYM - - if(error) - { - WARN("Missing expected functions:%s\n", alstr_get_cstr(missing_funcs)); - CloseLib(jack_handle); - jack_handle = NULL; - } - alstr_reset(&missing_funcs); - } -#endif - - return !error; -} - - -typedef struct ALCjackPlayback { - DERIVE_FROM_TYPE(ALCbackend); - - jack_client_t *Client; - jack_port_t *Port[MAX_OUTPUT_CHANNELS]; - - ll_ringbuffer_t *Ring; - alsem_t Sem; - - ATOMIC(ALenum) killNow; - althrd_t thread; -} ALCjackPlayback; - -static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg); - -static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg); -static int ALCjackPlayback_mixerProc(void *arg); - -static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device); -static void ALCjackPlayback_Destruct(ALCjackPlayback *self); -static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name); -static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self); -static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self); -static void ALCjackPlayback_stop(ALCjackPlayback *self); -static DECLARE_FORWARD2(ALCjackPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, ALCuint, availableSamples) -static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self); -static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCjackPlayback) - -DEFINE_ALCBACKEND_VTABLE(ALCjackPlayback); - - -static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device) -{ - ALuint i; - - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCjackPlayback, ALCbackend, self); - - alsem_init(&self->Sem, 0); - - self->Client = NULL; - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - self->Port[i] = NULL; - self->Ring = NULL; - - ATOMIC_INIT(&self->killNow, AL_TRUE); -} - -static void ALCjackPlayback_Destruct(ALCjackPlayback *self) -{ - ALuint i; - - if(self->Client) - { - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - { - if(self->Port[i]) - jack_port_unregister(self->Client, self->Port[i]); - self->Port[i] = NULL; - } - jack_client_close(self->Client); - self->Client = NULL; - } - - alsem_destroy(&self->Sem); - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg) -{ - ALCjackPlayback *self = arg; - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - ALuint bufsize; - - ALCjackPlayback_lock(self); - device->UpdateSize = numframes; - device->NumUpdates = 2; - - bufsize = device->UpdateSize; - if(ConfigValueUInt(alstr_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize)) - bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); - device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize; - - TRACE("%u update size x%u\n", device->UpdateSize, device->NumUpdates); - - ll_ringbuffer_free(self->Ring); - self->Ring = ll_ringbuffer_create(bufsize, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), - true - ); - if(!self->Ring) - { - ERR("Failed to reallocate ringbuffer\n"); - aluHandleDisconnect(device, "Failed to reallocate %u-sample buffer", bufsize); - } - ALCjackPlayback_unlock(self); - return 0; -} - - -static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) -{ - ALCjackPlayback *self = arg; - jack_default_audio_sample_t *out[MAX_OUTPUT_CHANNELS]; - ll_ringbuffer_data_t data[2]; - jack_nframes_t total = 0; - jack_nframes_t todo; - ALsizei i, c, numchans; - - ll_ringbuffer_get_read_vector(self->Ring, data); - - for(c = 0;c < MAX_OUTPUT_CHANNELS && self->Port[c];c++) - out[c] = jack_port_get_buffer(self->Port[c], numframes); - numchans = c; - - todo = minu(numframes, data[0].len); - for(c = 0;c < numchans;c++) - { - const ALfloat *RESTRICT in = ((ALfloat*)data[0].buf) + c; - for(i = 0;(jack_nframes_t)i < todo;i++) - out[c][i] = in[i*numchans]; - out[c] += todo; - } - total += todo; - - todo = minu(numframes-total, data[1].len); - if(todo > 0) - { - for(c = 0;c < numchans;c++) - { - const ALfloat *RESTRICT in = ((ALfloat*)data[1].buf) + c; - for(i = 0;(jack_nframes_t)i < todo;i++) - out[c][i] = in[i*numchans]; - out[c] += todo; - } - total += todo; - } - - ll_ringbuffer_read_advance(self->Ring, total); - alsem_post(&self->Sem); - - if(numframes > total) - { - todo = numframes-total; - for(c = 0;c < numchans;c++) - { - for(i = 0;(jack_nframes_t)i < todo;i++) - out[c][i] = 0.0f; - } - } - - return 0; -} - -static int ALCjackPlayback_mixerProc(void *arg) -{ - ALCjackPlayback *self = arg; - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - ll_ringbuffer_data_t data[2]; - - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - ALCjackPlayback_lock(self); - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) - { - ALuint todo, len1, len2; - - if(ll_ringbuffer_write_space(self->Ring) < device->UpdateSize) - { - ALCjackPlayback_unlock(self); - alsem_wait(&self->Sem); - ALCjackPlayback_lock(self); - continue; - } - - ll_ringbuffer_get_write_vector(self->Ring, data); - todo = data[0].len + data[1].len; - todo -= todo%device->UpdateSize; - - len1 = minu(data[0].len, todo); - len2 = minu(data[1].len, todo-len1); - - aluMixData(device, data[0].buf, len1); - if(len2 > 0) - aluMixData(device, data[1].buf, len2); - ll_ringbuffer_write_advance(self->Ring, todo); - } - ALCjackPlayback_unlock(self); - - return 0; -} - - -static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - const char *client_name = "alsoft"; - jack_status_t status; - - if(!name) - name = jackDevice; - else if(strcmp(name, jackDevice) != 0) - return ALC_INVALID_VALUE; - - self->Client = jack_client_open(client_name, ClientOptions, &status, NULL); - if(self->Client == NULL) - { - ERR("jack_client_open() failed, status = 0x%02x\n", status); - return ALC_INVALID_VALUE; - } - if((status&JackServerStarted)) - TRACE("JACK server started\n"); - if((status&JackNameNotUnique)) - { - client_name = jack_get_client_name(self->Client); - TRACE("Client name not unique, got `%s' instead\n", client_name); - } - - jack_set_process_callback(self->Client, ALCjackPlayback_process, self); - jack_set_buffer_size_callback(self->Client, ALCjackPlayback_bufferSizeNotify, self); - - alstr_copy_cstr(&device->DeviceName, name); - - return ALC_NO_ERROR; -} - -static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ALsizei numchans, i; - ALuint bufsize; - - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - { - if(self->Port[i]) - jack_port_unregister(self->Client, self->Port[i]); - self->Port[i] = NULL; - } - - /* Ignore the requested buffer metrics and just keep one JACK-sized buffer - * ready for when requested. - */ - device->Frequency = jack_get_sample_rate(self->Client); - device->UpdateSize = jack_get_buffer_size(self->Client); - device->NumUpdates = 2; - - bufsize = device->UpdateSize; - if(ConfigValueUInt(alstr_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize)) - bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); - device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize; - - /* Force 32-bit float output. */ - device->FmtType = DevFmtFloat; - - numchans = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - for(i = 0;i < numchans;i++) - { - char name[64]; - snprintf(name, sizeof(name), "channel_%d", i+1); - self->Port[i] = jack_port_register(self->Client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); - if(self->Port[i] == NULL) - { - ERR("Not enough JACK ports available for %s output\n", DevFmtChannelsString(device->FmtChans)); - if(i == 0) return ALC_FALSE; - break; - } - } - if(i < numchans) - { - if(i == 1) - device->FmtChans = DevFmtMono; - else - { - for(--i;i >= 2;i--) - { - jack_port_unregister(self->Client, self->Port[i]); - self->Port[i] = NULL; - } - device->FmtChans = DevFmtStereo; - } - } - - ll_ringbuffer_free(self->Ring); - self->Ring = ll_ringbuffer_create(bufsize, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), - true - ); - if(!self->Ring) - { - ERR("Failed to allocate ringbuffer\n"); - return ALC_FALSE; - } - - SetDefaultChannelOrder(device); - - return ALC_TRUE; -} - -static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self) -{ - const char **ports; - ALsizei i; - - if(jack_activate(self->Client)) - { - ERR("Failed to activate client\n"); - return ALC_FALSE; - } - - ports = jack_get_ports(self->Client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); - if(ports == NULL) - { - ERR("No physical playback ports found\n"); - jack_deactivate(self->Client); - return ALC_FALSE; - } - for(i = 0;i < MAX_OUTPUT_CHANNELS && self->Port[i];i++) - { - if(!ports[i]) - { - ERR("No physical playback port for \"%s\"\n", jack_port_name(self->Port[i])); - break; - } - if(jack_connect(self->Client, jack_port_name(self->Port[i]), ports[i])) - ERR("Failed to connect output port \"%s\" to \"%s\"\n", jack_port_name(self->Port[i]), ports[i]); - } - jack_free(ports); - - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); - if(althrd_create(&self->thread, ALCjackPlayback_mixerProc, self) != althrd_success) - { - jack_deactivate(self->Client); - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static void ALCjackPlayback_stop(ALCjackPlayback *self) -{ - int res; - - if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) - return; - - alsem_post(&self->Sem); - althrd_join(self->thread, &res); - - jack_deactivate(self->Client); -} - - -static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ClockLatency ret; - - ALCjackPlayback_lock(self); - ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = ll_ringbuffer_read_space(self->Ring) * DEVICE_CLOCK_RES / - device->Frequency; - ALCjackPlayback_unlock(self); - - return ret; -} - - -static void jack_msg_handler(const char *message) -{ - WARN("%s\n", message); -} - -typedef struct ALCjackBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCjackBackendFactory; -#define ALCJACKBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCjackBackendFactory, ALCbackendFactory) } } - -static ALCboolean ALCjackBackendFactory_init(ALCjackBackendFactory* UNUSED(self)) -{ - void (*old_error_cb)(const char*); - jack_client_t *client; - jack_status_t status; - - if(!jack_load()) - return ALC_FALSE; - - if(!GetConfigValueBool(NULL, "jack", "spawn-server", 0)) - ClientOptions |= JackNoStartServer; - - old_error_cb = (&jack_error_callback ? jack_error_callback : NULL); - jack_set_error_function(jack_msg_handler); - client = jack_client_open("alsoft", ClientOptions, &status, NULL); - jack_set_error_function(old_error_cb); - if(client == NULL) - { - WARN("jack_client_open() failed, 0x%02x\n", status); - if((status&JackServerFailed) && !(ClientOptions&JackNoStartServer)) - ERR("Unable to connect to JACK server\n"); - return ALC_FALSE; - } - - jack_client_close(client); - return ALC_TRUE; -} - -static void ALCjackBackendFactory_deinit(ALCjackBackendFactory* UNUSED(self)) -{ -#ifdef HAVE_DYNLOAD - if(jack_handle) - CloseLib(jack_handle); - jack_handle = NULL; -#endif -} - -static ALCboolean ALCjackBackendFactory_querySupport(ALCjackBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - return ALC_TRUE; - return ALC_FALSE; -} - -static void ALCjackBackendFactory_probe(ALCjackBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) -{ - switch(type) - { - case ALL_DEVICE_PROBE: - alstr_append_range(outnames, jackDevice, jackDevice+sizeof(jackDevice)); - break; - - case CAPTURE_DEVICE_PROBE: - break; - } -} - -static ALCbackend* ALCjackBackendFactory_createBackend(ALCjackBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - { - ALCjackPlayback *backend; - NEW_OBJ(backend, ALCjackPlayback)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} - -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCjackBackendFactory); - - -ALCbackendFactory *ALCjackBackendFactory_getFactory(void) -{ - static ALCjackBackendFactory factory = ALCJACKBACKENDFACTORY_INITIALIZER; - return STATIC_CAST(ALCbackendFactory, &factory); -} diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp new file mode 100644 index 00000000..db5e4a83 --- /dev/null +++ b/Alc/backends/jack.cpp @@ -0,0 +1,608 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include "alMain.h" +#include "alu.h" +#include "alconfig.h" +#include "ringbuffer.h" +#include "threads.h" +#include "compat.h" + +#include "backends/base.h" + +#include +#include + + +static const ALCchar jackDevice[] = "JACK Default"; + + +#ifdef HAVE_DYNLOAD +#define JACK_FUNCS(MAGIC) \ + MAGIC(jack_client_open); \ + MAGIC(jack_client_close); \ + MAGIC(jack_client_name_size); \ + MAGIC(jack_get_client_name); \ + MAGIC(jack_connect); \ + MAGIC(jack_activate); \ + MAGIC(jack_deactivate); \ + MAGIC(jack_port_register); \ + MAGIC(jack_port_unregister); \ + MAGIC(jack_port_get_buffer); \ + MAGIC(jack_port_name); \ + MAGIC(jack_get_ports); \ + MAGIC(jack_free); \ + MAGIC(jack_get_sample_rate); \ + MAGIC(jack_set_error_function); \ + MAGIC(jack_set_process_callback); \ + MAGIC(jack_set_buffer_size_callback); \ + MAGIC(jack_set_buffer_size); \ + MAGIC(jack_get_buffer_size); + +static void *jack_handle; +#define MAKE_FUNC(f) static decltype(f) * p##f +JACK_FUNCS(MAKE_FUNC); +static decltype(jack_error_callback) * pjack_error_callback; +#undef MAKE_FUNC + +#ifndef IN_IDE_PARSER +#define jack_client_open pjack_client_open +#define jack_client_close pjack_client_close +#define jack_client_name_size pjack_client_name_size +#define jack_get_client_name pjack_get_client_name +#define jack_connect pjack_connect +#define jack_activate pjack_activate +#define jack_deactivate pjack_deactivate +#define jack_port_register pjack_port_register +#define jack_port_unregister pjack_port_unregister +#define jack_port_get_buffer pjack_port_get_buffer +#define jack_port_name pjack_port_name +#define jack_get_ports pjack_get_ports +#define jack_free pjack_free +#define jack_get_sample_rate pjack_get_sample_rate +#define jack_set_error_function pjack_set_error_function +#define jack_set_process_callback pjack_set_process_callback +#define jack_set_buffer_size_callback pjack_set_buffer_size_callback +#define jack_set_buffer_size pjack_set_buffer_size +#define jack_get_buffer_size pjack_get_buffer_size +#define jack_error_callback (*pjack_error_callback) +#endif +#endif + + +static jack_options_t ClientOptions = JackNullOption; + +static ALCboolean jack_load(void) +{ + ALCboolean error = ALC_FALSE; + +#ifdef HAVE_DYNLOAD + if(!jack_handle) + { + al_string missing_funcs = AL_STRING_INIT_STATIC(); + +#ifdef _WIN32 +#define JACKLIB "libjack.dll" +#else +#define JACKLIB "libjack.so.0" +#endif + jack_handle = LoadLib(JACKLIB); + if(!jack_handle) + { + WARN("Failed to load %s\n", JACKLIB); + return ALC_FALSE; + } + + error = ALC_FALSE; +#define LOAD_FUNC(f) do { \ + p##f = reinterpret_cast(GetSymbol(jack_handle, #f)); \ + if(p##f == nullptr) { \ + error = ALC_TRUE; \ + alstr_append_cstr(&missing_funcs, "\n" #f); \ + } \ +} while(0) + JACK_FUNCS(LOAD_FUNC); +#undef LOAD_FUNC + /* Optional symbols. These don't exist in all versions of JACK. */ +#define LOAD_SYM(f) p##f = reinterpret_cast(GetSymbol(jack_handle, #f)) + LOAD_SYM(jack_error_callback); +#undef LOAD_SYM + + if(error) + { + WARN("Missing expected functions:%s\n", alstr_get_cstr(missing_funcs)); + CloseLib(jack_handle); + jack_handle = NULL; + } + alstr_reset(&missing_funcs); + } +#endif + + return !error; +} + + +struct ALCjackPlayback final : public ALCbackend { + jack_client_t *Client; + jack_port_t *Port[MAX_OUTPUT_CHANNELS]; + + ll_ringbuffer_t *Ring; + alsem_t Sem; + + ATOMIC(ALenum) killNow; + althrd_t thread; +}; + +static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg); + +static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg); +static int ALCjackPlayback_mixerProc(void *arg); + +static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device); +static void ALCjackPlayback_Destruct(ALCjackPlayback *self); +static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name); +static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self); +static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self); +static void ALCjackPlayback_stop(ALCjackPlayback *self); +static DECLARE_FORWARD2(ALCjackPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, ALCuint, availableSamples) +static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self); +static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCjackPlayback) + +DEFINE_ALCBACKEND_VTABLE(ALCjackPlayback); + + +static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device) +{ + new (self) ALCjackPlayback{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCjackPlayback, ALCbackend, self); + + alsem_init(&self->Sem, 0); + + self->Client = NULL; + for(ALsizei i{0};i < MAX_OUTPUT_CHANNELS;i++) + self->Port[i] = NULL; + self->Ring = NULL; + + ATOMIC_INIT(&self->killNow, AL_TRUE); +} + +static void ALCjackPlayback_Destruct(ALCjackPlayback *self) +{ + if(self->Client) + { + for(ALsizei i{0};i < MAX_OUTPUT_CHANNELS;i++) + { + if(self->Port[i]) + jack_port_unregister(self->Client, self->Port[i]); + self->Port[i] = NULL; + } + jack_client_close(self->Client); + self->Client = NULL; + } + + alsem_destroy(&self->Sem); + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCjackPlayback(); +} + + +static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg) +{ + ALCjackPlayback *self = static_cast(arg); + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALuint bufsize; + + ALCjackPlayback_lock(self); + device->UpdateSize = numframes; + device->NumUpdates = 2; + + bufsize = device->UpdateSize; + if(ConfigValueUInt(alstr_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize)) + bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); + device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize; + + TRACE("%u update size x%u\n", device->UpdateSize, device->NumUpdates); + + ll_ringbuffer_free(self->Ring); + self->Ring = ll_ringbuffer_create(bufsize, + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), + true + ); + if(!self->Ring) + { + ERR("Failed to reallocate ringbuffer\n"); + aluHandleDisconnect(device, "Failed to reallocate %u-sample buffer", bufsize); + } + ALCjackPlayback_unlock(self); + return 0; +} + + +static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) +{ + ALCjackPlayback *self = static_cast(arg); + jack_default_audio_sample_t *out[MAX_OUTPUT_CHANNELS]; + ll_ringbuffer_data_t data[2]; + jack_nframes_t total = 0; + jack_nframes_t todo; + ALsizei i, c, numchans; + + ll_ringbuffer_get_read_vector(self->Ring, data); + + for(c = 0;c < MAX_OUTPUT_CHANNELS && self->Port[c];c++) + out[c] = static_cast(jack_port_get_buffer(self->Port[c], numframes)); + numchans = c; + + todo = minu(numframes, data[0].len); + for(c = 0;c < numchans;c++) + { + const ALfloat *RESTRICT in = ((ALfloat*)data[0].buf) + c; + for(i = 0;(jack_nframes_t)i < todo;i++) + out[c][i] = in[i*numchans]; + out[c] += todo; + } + total += todo; + + todo = minu(numframes-total, data[1].len); + if(todo > 0) + { + for(c = 0;c < numchans;c++) + { + const ALfloat *RESTRICT in = ((ALfloat*)data[1].buf) + c; + for(i = 0;(jack_nframes_t)i < todo;i++) + out[c][i] = in[i*numchans]; + out[c] += todo; + } + total += todo; + } + + ll_ringbuffer_read_advance(self->Ring, total); + alsem_post(&self->Sem); + + if(numframes > total) + { + todo = numframes-total; + for(c = 0;c < numchans;c++) + { + for(i = 0;(jack_nframes_t)i < todo;i++) + out[c][i] = 0.0f; + } + } + + return 0; +} + +static int ALCjackPlayback_mixerProc(void *arg) +{ + ALCjackPlayback *self = static_cast(arg); + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ll_ringbuffer_data_t data[2]; + + SetRTPriority(); + althrd_setname(althrd_current(), MIXER_THREAD_NAME); + + ALCjackPlayback_lock(self); + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + { + ALuint todo, len1, len2; + + if(ll_ringbuffer_write_space(self->Ring) < device->UpdateSize) + { + ALCjackPlayback_unlock(self); + alsem_wait(&self->Sem); + ALCjackPlayback_lock(self); + continue; + } + + ll_ringbuffer_get_write_vector(self->Ring, data); + todo = data[0].len + data[1].len; + todo -= todo%device->UpdateSize; + + len1 = minu(data[0].len, todo); + len2 = minu(data[1].len, todo-len1); + + aluMixData(device, data[0].buf, len1); + if(len2 > 0) + aluMixData(device, data[1].buf, len2); + ll_ringbuffer_write_advance(self->Ring, todo); + } + ALCjackPlayback_unlock(self); + + return 0; +} + + +static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + const char *client_name = "alsoft"; + jack_status_t status; + + if(!name) + name = jackDevice; + else if(strcmp(name, jackDevice) != 0) + return ALC_INVALID_VALUE; + + self->Client = jack_client_open(client_name, ClientOptions, &status, NULL); + if(self->Client == NULL) + { + ERR("jack_client_open() failed, status = 0x%02x\n", status); + return ALC_INVALID_VALUE; + } + if((status&JackServerStarted)) + TRACE("JACK server started\n"); + if((status&JackNameNotUnique)) + { + client_name = jack_get_client_name(self->Client); + TRACE("Client name not unique, got `%s' instead\n", client_name); + } + + jack_set_process_callback(self->Client, ALCjackPlayback_process, self); + jack_set_buffer_size_callback(self->Client, ALCjackPlayback_bufferSizeNotify, self); + + alstr_copy_cstr(&device->DeviceName, name); + + return ALC_NO_ERROR; +} + +static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALsizei numchans, i; + ALuint bufsize; + + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + { + if(self->Port[i]) + jack_port_unregister(self->Client, self->Port[i]); + self->Port[i] = NULL; + } + + /* Ignore the requested buffer metrics and just keep one JACK-sized buffer + * ready for when requested. + */ + device->Frequency = jack_get_sample_rate(self->Client); + device->UpdateSize = jack_get_buffer_size(self->Client); + device->NumUpdates = 2; + + bufsize = device->UpdateSize; + if(ConfigValueUInt(alstr_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize)) + bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); + device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize; + + /* Force 32-bit float output. */ + device->FmtType = DevFmtFloat; + + numchans = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + for(i = 0;i < numchans;i++) + { + char name[64]; + snprintf(name, sizeof(name), "channel_%d", i+1); + self->Port[i] = jack_port_register(self->Client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + if(self->Port[i] == NULL) + { + ERR("Not enough JACK ports available for %s output\n", DevFmtChannelsString(device->FmtChans)); + if(i == 0) return ALC_FALSE; + break; + } + } + if(i < numchans) + { + if(i == 1) + device->FmtChans = DevFmtMono; + else + { + for(--i;i >= 2;i--) + { + jack_port_unregister(self->Client, self->Port[i]); + self->Port[i] = NULL; + } + device->FmtChans = DevFmtStereo; + } + } + + ll_ringbuffer_free(self->Ring); + self->Ring = ll_ringbuffer_create(bufsize, + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), + true + ); + if(!self->Ring) + { + ERR("Failed to allocate ringbuffer\n"); + return ALC_FALSE; + } + + SetDefaultChannelOrder(device); + + return ALC_TRUE; +} + +static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self) +{ + const char **ports; + ALsizei i; + + if(jack_activate(self->Client)) + { + ERR("Failed to activate client\n"); + return ALC_FALSE; + } + + ports = jack_get_ports(self->Client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); + if(ports == NULL) + { + ERR("No physical playback ports found\n"); + jack_deactivate(self->Client); + return ALC_FALSE; + } + for(i = 0;i < MAX_OUTPUT_CHANNELS && self->Port[i];i++) + { + if(!ports[i]) + { + ERR("No physical playback port for \"%s\"\n", jack_port_name(self->Port[i])); + break; + } + if(jack_connect(self->Client, jack_port_name(self->Port[i]), ports[i])) + ERR("Failed to connect output port \"%s\" to \"%s\"\n", jack_port_name(self->Port[i]), ports[i]); + } + jack_free(ports); + + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); + if(althrd_create(&self->thread, ALCjackPlayback_mixerProc, self) != althrd_success) + { + jack_deactivate(self->Client); + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static void ALCjackPlayback_stop(ALCjackPlayback *self) +{ + int res; + + if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) + return; + + alsem_post(&self->Sem); + althrd_join(self->thread, &res); + + jack_deactivate(self->Client); +} + + +static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ClockLatency ret; + + ALCjackPlayback_lock(self); + ret.ClockTime = GetDeviceClockTime(device); + ret.Latency = ll_ringbuffer_read_space(self->Ring) * DEVICE_CLOCK_RES / + device->Frequency; + ALCjackPlayback_unlock(self); + + return ret; +} + + +static void jack_msg_handler(const char *message) +{ + WARN("%s\n", message); +} + +struct ALCjackBackendFactory final : public ALCbackendFactory { + ALCjackBackendFactory() noexcept; +}; + +static ALCboolean ALCjackBackendFactory_init(ALCjackBackendFactory* UNUSED(self)) +{ + void (*old_error_cb)(const char*); + jack_client_t *client; + jack_status_t status; + + if(!jack_load()) + return ALC_FALSE; + + if(!GetConfigValueBool(NULL, "jack", "spawn-server", 0)) + ClientOptions = static_cast(ClientOptions | JackNoStartServer); + + old_error_cb = (&jack_error_callback ? jack_error_callback : NULL); + jack_set_error_function(jack_msg_handler); + client = jack_client_open("alsoft", ClientOptions, &status, NULL); + jack_set_error_function(old_error_cb); + if(client == NULL) + { + WARN("jack_client_open() failed, 0x%02x\n", status); + if((status&JackServerFailed) && !(ClientOptions&JackNoStartServer)) + ERR("Unable to connect to JACK server\n"); + return ALC_FALSE; + } + + jack_client_close(client); + return ALC_TRUE; +} + +static void ALCjackBackendFactory_deinit(ALCjackBackendFactory* UNUSED(self)) +{ +#ifdef HAVE_DYNLOAD + if(jack_handle) + CloseLib(jack_handle); + jack_handle = NULL; +#endif +} + +static ALCboolean ALCjackBackendFactory_querySupport(ALCjackBackendFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + return ALC_TRUE; + return ALC_FALSE; +} + +static void ALCjackBackendFactory_probe(ALCjackBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +{ + switch(type) + { + case ALL_DEVICE_PROBE: + alstr_append_range(outnames, jackDevice, jackDevice+sizeof(jackDevice)); + break; + + case CAPTURE_DEVICE_PROBE: + break; + } +} + +static ALCbackend* ALCjackBackendFactory_createBackend(ALCjackBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCjackPlayback *backend; + NEW_OBJ(backend, ALCjackPlayback)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + + return NULL; +} + +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCjackBackendFactory); + + +ALCjackBackendFactory::ALCjackBackendFactory() noexcept + : ALCbackendFactory{GET_VTABLE2(ALCjackBackendFactory, ALCbackendFactory)} +{ } + +ALCbackendFactory *ALCjackBackendFactory_getFactory(void) +{ + static ALCjackBackendFactory factory{}; + return STATIC_CAST(ALCbackendFactory, &factory); +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 61133c50..1cb56c54 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1223,7 +1223,7 @@ IF(JACK_FOUND) IF(ALSOFT_BACKEND_JACK) SET(HAVE_JACK 1) SET(BACKENDS "${BACKENDS} JACK${IS_LINKED},") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/jack.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/jack.cpp) ADD_BACKEND_LIBS(${JACK_LIBRARIES}) SET(INC_PATHS ${INC_PATHS} ${JACK_INCLUDE_DIRS}) ENDIF() -- cgit v1.2.3 From 74d1337cc74c3fab3622188e55c9234257511ac3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Nov 2018 01:36:17 -0800 Subject: Convert the ALSA backend to C++ --- Alc/backends/alsa.c | 1466 ------------------------------------------------ Alc/backends/alsa.cpp | 1470 +++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 1471 insertions(+), 1467 deletions(-) delete mode 100644 Alc/backends/alsa.c create mode 100644 Alc/backends/alsa.cpp diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c deleted file mode 100644 index 6f22ae60..00000000 --- a/Alc/backends/alsa.c +++ /dev/null @@ -1,1466 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include "alMain.h" -#include "alu.h" -#include "alconfig.h" -#include "ringbuffer.h" -#include "threads.h" -#include "compat.h" - -#include "backends/base.h" - -#include - - -static const ALCchar alsaDevice[] = "ALSA Default"; - - -#ifdef HAVE_DYNLOAD -#define ALSA_FUNCS(MAGIC) \ - MAGIC(snd_strerror); \ - MAGIC(snd_pcm_open); \ - MAGIC(snd_pcm_close); \ - MAGIC(snd_pcm_nonblock); \ - MAGIC(snd_pcm_frames_to_bytes); \ - MAGIC(snd_pcm_bytes_to_frames); \ - MAGIC(snd_pcm_hw_params_malloc); \ - MAGIC(snd_pcm_hw_params_free); \ - MAGIC(snd_pcm_hw_params_any); \ - MAGIC(snd_pcm_hw_params_current); \ - MAGIC(snd_pcm_hw_params_set_access); \ - MAGIC(snd_pcm_hw_params_set_format); \ - MAGIC(snd_pcm_hw_params_set_channels); \ - MAGIC(snd_pcm_hw_params_set_periods_near); \ - MAGIC(snd_pcm_hw_params_set_rate_near); \ - MAGIC(snd_pcm_hw_params_set_rate); \ - MAGIC(snd_pcm_hw_params_set_rate_resample); \ - MAGIC(snd_pcm_hw_params_set_buffer_time_near); \ - MAGIC(snd_pcm_hw_params_set_period_time_near); \ - MAGIC(snd_pcm_hw_params_set_buffer_size_near); \ - MAGIC(snd_pcm_hw_params_set_period_size_near); \ - MAGIC(snd_pcm_hw_params_set_buffer_size_min); \ - MAGIC(snd_pcm_hw_params_get_buffer_time_min); \ - MAGIC(snd_pcm_hw_params_get_buffer_time_max); \ - MAGIC(snd_pcm_hw_params_get_period_time_min); \ - MAGIC(snd_pcm_hw_params_get_period_time_max); \ - MAGIC(snd_pcm_hw_params_get_buffer_size); \ - MAGIC(snd_pcm_hw_params_get_period_size); \ - MAGIC(snd_pcm_hw_params_get_access); \ - MAGIC(snd_pcm_hw_params_get_periods); \ - MAGIC(snd_pcm_hw_params_test_format); \ - MAGIC(snd_pcm_hw_params_test_channels); \ - MAGIC(snd_pcm_hw_params); \ - MAGIC(snd_pcm_sw_params_malloc); \ - MAGIC(snd_pcm_sw_params_current); \ - MAGIC(snd_pcm_sw_params_set_avail_min); \ - MAGIC(snd_pcm_sw_params_set_stop_threshold); \ - MAGIC(snd_pcm_sw_params); \ - MAGIC(snd_pcm_sw_params_free); \ - MAGIC(snd_pcm_prepare); \ - MAGIC(snd_pcm_start); \ - MAGIC(snd_pcm_resume); \ - MAGIC(snd_pcm_reset); \ - MAGIC(snd_pcm_wait); \ - MAGIC(snd_pcm_delay); \ - MAGIC(snd_pcm_state); \ - MAGIC(snd_pcm_avail_update); \ - MAGIC(snd_pcm_areas_silence); \ - MAGIC(snd_pcm_mmap_begin); \ - MAGIC(snd_pcm_mmap_commit); \ - MAGIC(snd_pcm_readi); \ - MAGIC(snd_pcm_writei); \ - MAGIC(snd_pcm_drain); \ - MAGIC(snd_pcm_drop); \ - MAGIC(snd_pcm_recover); \ - MAGIC(snd_pcm_info_malloc); \ - MAGIC(snd_pcm_info_free); \ - MAGIC(snd_pcm_info_set_device); \ - MAGIC(snd_pcm_info_set_subdevice); \ - MAGIC(snd_pcm_info_set_stream); \ - MAGIC(snd_pcm_info_get_name); \ - MAGIC(snd_ctl_pcm_next_device); \ - MAGIC(snd_ctl_pcm_info); \ - MAGIC(snd_ctl_open); \ - MAGIC(snd_ctl_close); \ - MAGIC(snd_ctl_card_info_malloc); \ - MAGIC(snd_ctl_card_info_free); \ - MAGIC(snd_ctl_card_info); \ - MAGIC(snd_ctl_card_info_get_name); \ - MAGIC(snd_ctl_card_info_get_id); \ - MAGIC(snd_card_next); \ - MAGIC(snd_config_update_free_global) - -static void *alsa_handle; -#define MAKE_FUNC(f) static __typeof(f) * p##f -ALSA_FUNCS(MAKE_FUNC); -#undef MAKE_FUNC - -#ifndef IN_IDE_PARSER -#define snd_strerror psnd_strerror -#define snd_pcm_open psnd_pcm_open -#define snd_pcm_close psnd_pcm_close -#define snd_pcm_nonblock psnd_pcm_nonblock -#define snd_pcm_frames_to_bytes psnd_pcm_frames_to_bytes -#define snd_pcm_bytes_to_frames psnd_pcm_bytes_to_frames -#define snd_pcm_hw_params_malloc psnd_pcm_hw_params_malloc -#define snd_pcm_hw_params_free psnd_pcm_hw_params_free -#define snd_pcm_hw_params_any psnd_pcm_hw_params_any -#define snd_pcm_hw_params_current psnd_pcm_hw_params_current -#define snd_pcm_hw_params_set_access psnd_pcm_hw_params_set_access -#define snd_pcm_hw_params_set_format psnd_pcm_hw_params_set_format -#define snd_pcm_hw_params_set_channels psnd_pcm_hw_params_set_channels -#define snd_pcm_hw_params_set_periods_near psnd_pcm_hw_params_set_periods_near -#define snd_pcm_hw_params_set_rate_near psnd_pcm_hw_params_set_rate_near -#define snd_pcm_hw_params_set_rate psnd_pcm_hw_params_set_rate -#define snd_pcm_hw_params_set_rate_resample psnd_pcm_hw_params_set_rate_resample -#define snd_pcm_hw_params_set_buffer_time_near psnd_pcm_hw_params_set_buffer_time_near -#define snd_pcm_hw_params_set_period_time_near psnd_pcm_hw_params_set_period_time_near -#define snd_pcm_hw_params_set_buffer_size_near psnd_pcm_hw_params_set_buffer_size_near -#define snd_pcm_hw_params_set_period_size_near psnd_pcm_hw_params_set_period_size_near -#define snd_pcm_hw_params_set_buffer_size_min psnd_pcm_hw_params_set_buffer_size_min -#define snd_pcm_hw_params_get_buffer_time_min psnd_pcm_hw_params_get_buffer_time_min -#define snd_pcm_hw_params_get_buffer_time_max psnd_pcm_hw_params_get_buffer_time_max -#define snd_pcm_hw_params_get_period_time_min psnd_pcm_hw_params_get_period_time_min -#define snd_pcm_hw_params_get_period_time_max psnd_pcm_hw_params_get_period_time_max -#define snd_pcm_hw_params_get_buffer_size psnd_pcm_hw_params_get_buffer_size -#define snd_pcm_hw_params_get_period_size psnd_pcm_hw_params_get_period_size -#define snd_pcm_hw_params_get_access psnd_pcm_hw_params_get_access -#define snd_pcm_hw_params_get_periods psnd_pcm_hw_params_get_periods -#define snd_pcm_hw_params_test_format psnd_pcm_hw_params_test_format -#define snd_pcm_hw_params_test_channels psnd_pcm_hw_params_test_channels -#define snd_pcm_hw_params psnd_pcm_hw_params -#define snd_pcm_sw_params_malloc psnd_pcm_sw_params_malloc -#define snd_pcm_sw_params_current psnd_pcm_sw_params_current -#define snd_pcm_sw_params_set_avail_min psnd_pcm_sw_params_set_avail_min -#define snd_pcm_sw_params_set_stop_threshold psnd_pcm_sw_params_set_stop_threshold -#define snd_pcm_sw_params psnd_pcm_sw_params -#define snd_pcm_sw_params_free psnd_pcm_sw_params_free -#define snd_pcm_prepare psnd_pcm_prepare -#define snd_pcm_start psnd_pcm_start -#define snd_pcm_resume psnd_pcm_resume -#define snd_pcm_reset psnd_pcm_reset -#define snd_pcm_wait psnd_pcm_wait -#define snd_pcm_delay psnd_pcm_delay -#define snd_pcm_state psnd_pcm_state -#define snd_pcm_avail_update psnd_pcm_avail_update -#define snd_pcm_areas_silence psnd_pcm_areas_silence -#define snd_pcm_mmap_begin psnd_pcm_mmap_begin -#define snd_pcm_mmap_commit psnd_pcm_mmap_commit -#define snd_pcm_readi psnd_pcm_readi -#define snd_pcm_writei psnd_pcm_writei -#define snd_pcm_drain psnd_pcm_drain -#define snd_pcm_drop psnd_pcm_drop -#define snd_pcm_recover psnd_pcm_recover -#define snd_pcm_info_malloc psnd_pcm_info_malloc -#define snd_pcm_info_free psnd_pcm_info_free -#define snd_pcm_info_set_device psnd_pcm_info_set_device -#define snd_pcm_info_set_subdevice psnd_pcm_info_set_subdevice -#define snd_pcm_info_set_stream psnd_pcm_info_set_stream -#define snd_pcm_info_get_name psnd_pcm_info_get_name -#define snd_ctl_pcm_next_device psnd_ctl_pcm_next_device -#define snd_ctl_pcm_info psnd_ctl_pcm_info -#define snd_ctl_open psnd_ctl_open -#define snd_ctl_close psnd_ctl_close -#define snd_ctl_card_info_malloc psnd_ctl_card_info_malloc -#define snd_ctl_card_info_free psnd_ctl_card_info_free -#define snd_ctl_card_info psnd_ctl_card_info -#define snd_ctl_card_info_get_name psnd_ctl_card_info_get_name -#define snd_ctl_card_info_get_id psnd_ctl_card_info_get_id -#define snd_card_next psnd_card_next -#define snd_config_update_free_global psnd_config_update_free_global -#endif -#endif - - -static ALCboolean alsa_load(void) -{ - ALCboolean error = ALC_FALSE; - -#ifdef HAVE_DYNLOAD - if(!alsa_handle) - { - al_string missing_funcs = AL_STRING_INIT_STATIC(); - - alsa_handle = LoadLib("libasound.so.2"); - if(!alsa_handle) - { - WARN("Failed to load %s\n", "libasound.so.2"); - return ALC_FALSE; - } - - error = ALC_FALSE; -#define LOAD_FUNC(f) do { \ - p##f = GetSymbol(alsa_handle, #f); \ - if(p##f == NULL) { \ - error = ALC_TRUE; \ - alstr_append_cstr(&missing_funcs, "\n" #f); \ - } \ -} while(0) - ALSA_FUNCS(LOAD_FUNC); -#undef LOAD_FUNC - - if(error) - { - WARN("Missing expected functions:%s\n", alstr_get_cstr(missing_funcs)); - CloseLib(alsa_handle); - alsa_handle = NULL; - } - alstr_reset(&missing_funcs); - } -#endif - - return !error; -} - - -typedef struct { - al_string name; - al_string device_name; -} DevMap; -TYPEDEF_VECTOR(DevMap, vector_DevMap) - -static vector_DevMap PlaybackDevices; -static vector_DevMap CaptureDevices; - -static void clear_devlist(vector_DevMap *devlist) -{ -#define FREE_DEV(i) do { \ - AL_STRING_DEINIT((i)->name); \ - AL_STRING_DEINIT((i)->device_name); \ -} while(0) - VECTOR_FOR_EACH(DevMap, *devlist, FREE_DEV); - VECTOR_RESIZE(*devlist, 0, 0); -#undef FREE_DEV -} - - -static const char *prefix_name(snd_pcm_stream_t stream) -{ - assert(stream == SND_PCM_STREAM_PLAYBACK || stream == SND_PCM_STREAM_CAPTURE); - return (stream==SND_PCM_STREAM_PLAYBACK) ? "device-prefix" : "capture-prefix"; -} - -static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList) -{ - const char *main_prefix = "plughw:"; - snd_ctl_t *handle; - snd_ctl_card_info_t *info; - snd_pcm_info_t *pcminfo; - int card, err, dev; - DevMap entry; - - clear_devlist(DeviceList); - - snd_ctl_card_info_malloc(&info); - snd_pcm_info_malloc(&pcminfo); - - AL_STRING_INIT(entry.name); - AL_STRING_INIT(entry.device_name); - alstr_copy_cstr(&entry.name, alsaDevice); - alstr_copy_cstr(&entry.device_name, GetConfigValue( - NULL, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ? "device" : "capture", "default" - )); - VECTOR_PUSH_BACK(*DeviceList, entry); - - if(stream == SND_PCM_STREAM_PLAYBACK) - { - const char *customdevs, *sep, *next; - next = GetConfigValue(NULL, "alsa", "custom-devices", ""); - while((customdevs=next) != NULL && customdevs[0]) - { - next = strchr(customdevs, ';'); - sep = strchr(customdevs, '='); - if(!sep) - { - al_string spec = AL_STRING_INIT_STATIC(); - if(next) - alstr_copy_range(&spec, customdevs, next++); - else - alstr_copy_cstr(&spec, customdevs); - ERR("Invalid ALSA device specification \"%s\"\n", alstr_get_cstr(spec)); - alstr_reset(&spec); - continue; - } - - AL_STRING_INIT(entry.name); - AL_STRING_INIT(entry.device_name); - alstr_copy_range(&entry.name, customdevs, sep++); - if(next) - alstr_copy_range(&entry.device_name, sep, next++); - else - alstr_copy_cstr(&entry.device_name, sep); - TRACE("Got device \"%s\", \"%s\"\n", alstr_get_cstr(entry.name), - alstr_get_cstr(entry.device_name)); - VECTOR_PUSH_BACK(*DeviceList, entry); - } - } - - card = -1; - if((err=snd_card_next(&card)) < 0) - ERR("Failed to find a card: %s\n", snd_strerror(err)); - ConfigValueStr(NULL, "alsa", prefix_name(stream), &main_prefix); - while(card >= 0) - { - const char *card_prefix = main_prefix; - const char *cardname, *cardid; - char name[256]; - - snprintf(name, sizeof(name), "hw:%d", card); - if((err = snd_ctl_open(&handle, name, 0)) < 0) - { - ERR("control open (hw:%d): %s\n", card, snd_strerror(err)); - goto next_card; - } - if((err = snd_ctl_card_info(handle, info)) < 0) - { - ERR("control hardware info (hw:%d): %s\n", card, snd_strerror(err)); - snd_ctl_close(handle); - goto next_card; - } - - cardname = snd_ctl_card_info_get_name(info); - cardid = snd_ctl_card_info_get_id(info); - - snprintf(name, sizeof(name), "%s-%s", prefix_name(stream), cardid); - ConfigValueStr(NULL, "alsa", name, &card_prefix); - - dev = -1; - while(1) - { - const char *device_prefix = card_prefix; - const char *devname; - char device[128]; - - if(snd_ctl_pcm_next_device(handle, &dev) < 0) - ERR("snd_ctl_pcm_next_device failed\n"); - if(dev < 0) - break; - - snd_pcm_info_set_device(pcminfo, dev); - snd_pcm_info_set_subdevice(pcminfo, 0); - snd_pcm_info_set_stream(pcminfo, stream); - if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) - { - if(err != -ENOENT) - ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err)); - continue; - } - - devname = snd_pcm_info_get_name(pcminfo); - - snprintf(name, sizeof(name), "%s-%s-%d", prefix_name(stream), cardid, dev); - ConfigValueStr(NULL, "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); - - TRACE("Got device \"%s\", \"%s\"\n", name, device); - AL_STRING_INIT(entry.name); - AL_STRING_INIT(entry.device_name); - alstr_copy_cstr(&entry.name, name); - alstr_copy_cstr(&entry.device_name, device); - VECTOR_PUSH_BACK(*DeviceList, entry); - } - snd_ctl_close(handle); - next_card: - if(snd_card_next(&card) < 0) { - ERR("snd_card_next failed\n"); - break; - } - } - - snd_pcm_info_free(pcminfo); - snd_ctl_card_info_free(info); -} - - -static int verify_state(snd_pcm_t *handle) -{ - snd_pcm_state_t state = snd_pcm_state(handle); - int err; - - switch(state) - { - case SND_PCM_STATE_OPEN: - case SND_PCM_STATE_SETUP: - case SND_PCM_STATE_PREPARED: - case SND_PCM_STATE_RUNNING: - case SND_PCM_STATE_DRAINING: - case SND_PCM_STATE_PAUSED: - /* All Okay */ - break; - - case SND_PCM_STATE_XRUN: - if((err=snd_pcm_recover(handle, -EPIPE, 1)) < 0) - return err; - break; - case SND_PCM_STATE_SUSPENDED: - if((err=snd_pcm_recover(handle, -ESTRPIPE, 1)) < 0) - return err; - break; - case SND_PCM_STATE_DISCONNECTED: - return -ENODEV; - } - - return state; -} - - -typedef struct ALCplaybackAlsa { - DERIVE_FROM_TYPE(ALCbackend); - - snd_pcm_t *pcmHandle; - - ALvoid *buffer; - ALsizei size; - - ATOMIC(ALenum) killNow; - althrd_t thread; -} ALCplaybackAlsa; - -static int ALCplaybackAlsa_mixerProc(void *ptr); -static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr); - -static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device); -static void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self); -static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name); -static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self); -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 ClockLatency ALCplaybackAlsa_getClockLatency(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) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCplaybackAlsa, ALCbackend, self); - - self->pcmHandle = NULL; - self->buffer = NULL; - - ATOMIC_INIT(&self->killNow, AL_TRUE); -} - -void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self) -{ - if(self->pcmHandle) - snd_pcm_close(self->pcmHandle); - self->pcmHandle = NULL; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -static int ALCplaybackAlsa_mixerProc(void *ptr) -{ - ALCplaybackAlsa *self = (ALCplaybackAlsa*)ptr; - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - const snd_pcm_channel_area_t *areas = NULL; - snd_pcm_uframes_t update_size, num_updates; - snd_pcm_sframes_t avail, commitres; - snd_pcm_uframes_t offset, frames; - char *WritePtr; - int err; - - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - update_size = device->UpdateSize; - num_updates = device->NumUpdates; - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) - { - int state = verify_state(self->pcmHandle); - if(state < 0) - { - ERR("Invalid state detected: %s\n", snd_strerror(state)); - ALCplaybackAlsa_lock(self); - aluHandleDisconnect(device, "Bad state: %s", snd_strerror(state)); - ALCplaybackAlsa_unlock(self); - break; - } - - avail = snd_pcm_avail_update(self->pcmHandle); - if(avail < 0) - { - ERR("available update failed: %s\n", snd_strerror(avail)); - continue; - } - - if((snd_pcm_uframes_t)avail > update_size*(num_updates+1)) - { - WARN("available samples exceeds the buffer size\n"); - snd_pcm_reset(self->pcmHandle); - continue; - } - - // make sure there's frames to process - if((snd_pcm_uframes_t)avail < update_size) - { - if(state != SND_PCM_STATE_RUNNING) - { - err = snd_pcm_start(self->pcmHandle); - if(err < 0) - { - ERR("start failed: %s\n", snd_strerror(err)); - continue; - } - } - if(snd_pcm_wait(self->pcmHandle, 1000) == 0) - ERR("Wait timeout... buffer size too low?\n"); - continue; - } - avail -= avail%update_size; - - // it is possible that contiguous areas are smaller, thus we use a loop - ALCplaybackAlsa_lock(self); - while(avail > 0) - { - frames = avail; - - err = snd_pcm_mmap_begin(self->pcmHandle, &areas, &offset, &frames); - if(err < 0) - { - ERR("mmap begin error: %s\n", snd_strerror(err)); - break; - } - - WritePtr = (char*)areas->addr + (offset * areas->step / 8); - aluMixData(device, WritePtr, frames); - - commitres = snd_pcm_mmap_commit(self->pcmHandle, offset, frames); - if(commitres < 0 || (commitres-frames) != 0) - { - ERR("mmap commit error: %s\n", - snd_strerror(commitres >= 0 ? -EPIPE : commitres)); - break; - } - - avail -= frames; - } - ALCplaybackAlsa_unlock(self); - } - - return 0; -} - -static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr) -{ - ALCplaybackAlsa *self = (ALCplaybackAlsa*)ptr; - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - snd_pcm_uframes_t update_size, num_updates; - snd_pcm_sframes_t avail; - char *WritePtr; - int err; - - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - update_size = device->UpdateSize; - num_updates = device->NumUpdates; - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) - { - int state = verify_state(self->pcmHandle); - if(state < 0) - { - ERR("Invalid state detected: %s\n", snd_strerror(state)); - ALCplaybackAlsa_lock(self); - aluHandleDisconnect(device, "Bad state: %s", snd_strerror(state)); - ALCplaybackAlsa_unlock(self); - break; - } - - avail = snd_pcm_avail_update(self->pcmHandle); - if(avail < 0) - { - ERR("available update failed: %s\n", snd_strerror(avail)); - continue; - } - - if((snd_pcm_uframes_t)avail > update_size*num_updates) - { - WARN("available samples exceeds the buffer size\n"); - snd_pcm_reset(self->pcmHandle); - continue; - } - - if((snd_pcm_uframes_t)avail < update_size) - { - if(state != SND_PCM_STATE_RUNNING) - { - err = snd_pcm_start(self->pcmHandle); - if(err < 0) - { - ERR("start failed: %s\n", snd_strerror(err)); - continue; - } - } - if(snd_pcm_wait(self->pcmHandle, 1000) == 0) - ERR("Wait timeout... buffer size too low?\n"); - continue; - } - - ALCplaybackAlsa_lock(self); - WritePtr = self->buffer; - avail = snd_pcm_bytes_to_frames(self->pcmHandle, self->size); - aluMixData(device, WritePtr, avail); - - while(avail > 0) - { - int ret = snd_pcm_writei(self->pcmHandle, WritePtr, avail); - switch (ret) - { - case -EAGAIN: - continue; -#if ESTRPIPE != EPIPE - case -ESTRPIPE: -#endif - case -EPIPE: - case -EINTR: - ret = snd_pcm_recover(self->pcmHandle, ret, 1); - if(ret < 0) - avail = 0; - break; - default: - if (ret >= 0) - { - WritePtr += snd_pcm_frames_to_bytes(self->pcmHandle, ret); - avail -= ret; - } - break; - } - if (ret < 0) - { - ret = snd_pcm_prepare(self->pcmHandle); - if(ret < 0) - break; - } - } - ALCplaybackAlsa_unlock(self); - } - - return 0; -} - - -static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - const char *driver = NULL; - int err; - - if(name) - { - const DevMap *iter; - - if(VECTOR_SIZE(PlaybackDevices) == 0) - probe_devices(SND_PCM_STREAM_PLAYBACK, &PlaybackDevices); - -#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, name) == 0) - VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); -#undef MATCH_NAME - if(iter == VECTOR_END(PlaybackDevices)) - return ALC_INVALID_VALUE; - driver = alstr_get_cstr(iter->device_name); - } - else - { - name = alsaDevice; - driver = GetConfigValue(NULL, "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) - { - ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(err)); - return ALC_OUT_OF_MEMORY; - } - - /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */ - snd_config_update_free_global(); - - alstr_copy_cstr(&device->DeviceName, name); - - return ALC_NO_ERROR; -} - -static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - snd_pcm_uframes_t periodSizeInFrames; - 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; - unsigned int periods; - unsigned int rate; - const char *funcerr; - int allowmmap; - int dir; - int err; - - switch(device->FmtType) - { - case DevFmtByte: - format = SND_PCM_FORMAT_S8; - break; - case DevFmtUByte: - format = SND_PCM_FORMAT_U8; - break; - case DevFmtShort: - format = SND_PCM_FORMAT_S16; - break; - case DevFmtUShort: - format = SND_PCM_FORMAT_U16; - break; - case DevFmtInt: - format = SND_PCM_FORMAT_S32; - break; - case DevFmtUInt: - format = SND_PCM_FORMAT_U32; - break; - case DevFmtFloat: - format = SND_PCM_FORMAT_FLOAT; - break; - } - - allowmmap = GetConfigValueBool(alstr_get_cstr(device->DeviceName), "alsa", "mmap", 1); - periods = device->NumUpdates; - periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency; - bufferLen = periodLen * periods; - rate = device->Frequency; - - snd_pcm_hw_params_malloc(&hp); -#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error - CHECK(snd_pcm_hw_params_any(self->pcmHandle, hp)); - /* set interleaved access */ - if(!allowmmap || snd_pcm_hw_params_set_access(self->pcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) - { - /* No mmap */ - CHECK(snd_pcm_hw_params_set_access(self->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); - } - /* test and set format (implicitly sets sample bits) */ - if(snd_pcm_hw_params_test_format(self->pcmHandle, hp, format) < 0) - { - static const struct { - snd_pcm_format_t format; - enum DevFmtType fmttype; - } formatlist[] = { - { SND_PCM_FORMAT_FLOAT, DevFmtFloat }, - { SND_PCM_FORMAT_S32, DevFmtInt }, - { SND_PCM_FORMAT_U32, DevFmtUInt }, - { SND_PCM_FORMAT_S16, DevFmtShort }, - { SND_PCM_FORMAT_U16, DevFmtUShort }, - { SND_PCM_FORMAT_S8, DevFmtByte }, - { SND_PCM_FORMAT_U8, DevFmtUByte }, - }; - size_t k; - - for(k = 0;k < COUNTOF(formatlist);k++) - { - format = formatlist[k].format; - if(snd_pcm_hw_params_test_format(self->pcmHandle, hp, format) >= 0) - { - device->FmtType = formatlist[k].fmttype; - break; - } - } - } - CHECK(snd_pcm_hw_params_set_format(self->pcmHandle, hp, format)); - /* test and set channels (implicitly sets frame bits) */ - if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder)) < 0) - { - static const enum DevFmtChannels channellist[] = { - DevFmtStereo, - DevFmtQuad, - DevFmtX51, - DevFmtX71, - DevFmtMono, - }; - size_t k; - - for(k = 0;k < COUNTOF(channellist);k++) - { - if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(channellist[k], 0)) >= 0) - { - device->FmtChans = channellist[k]; - device->AmbiOrder = 0; - break; - } - } - } - CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder))); - /* set rate (implicitly constrains period/buffer parameters) */ - if(!GetConfigValueBool(alstr_get_cstr(device->DeviceName), "alsa", "allow-resampler", 0) || - !(device->Flags&DEVICE_FREQUENCY_REQUEST)) - { - if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0) - ERR("Failed to disable ALSA resampler\n"); - } - else if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 1) < 0) - ERR("Failed to enable ALSA resampler\n"); - CHECK(snd_pcm_hw_params_set_rate_near(self->pcmHandle, hp, &rate, NULL)); - /* set buffer time (implicitly constrains period/buffer parameters) */ - if((err=snd_pcm_hw_params_set_buffer_time_near(self->pcmHandle, hp, &bufferLen, NULL)) < 0) - ERR("snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err)); - /* set period time (implicitly sets buffer size/bytes/time and period size/bytes) */ - if((err=snd_pcm_hw_params_set_period_time_near(self->pcmHandle, hp, &periodLen, NULL)) < 0) - ERR("snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err)); - /* install and prepare hardware configuration */ - CHECK(snd_pcm_hw_params(self->pcmHandle, hp)); - /* retrieve configuration info */ - CHECK(snd_pcm_hw_params_get_access(hp, &access)); - CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL)); - CHECK(snd_pcm_hw_params_get_periods(hp, &periods, &dir)); - if(dir != 0) - WARN("Inexact period count: %u (%d)\n", periods, dir); - - snd_pcm_hw_params_free(hp); - hp = NULL; - snd_pcm_sw_params_malloc(&sp); - - CHECK(snd_pcm_sw_params_current(self->pcmHandle, sp)); - CHECK(snd_pcm_sw_params_set_avail_min(self->pcmHandle, sp, periodSizeInFrames)); - CHECK(snd_pcm_sw_params_set_stop_threshold(self->pcmHandle, sp, periodSizeInFrames*periods)); - CHECK(snd_pcm_sw_params(self->pcmHandle, sp)); -#undef CHECK - snd_pcm_sw_params_free(sp); - sp = NULL; - - device->NumUpdates = periods; - device->UpdateSize = periodSizeInFrames; - device->Frequency = rate; - - SetDefaultChannelOrder(device); - - return ALC_TRUE; - -error: - ERR("%s failed: %s\n", funcerr, snd_strerror(err)); - if(hp) snd_pcm_hw_params_free(hp); - if(sp) snd_pcm_sw_params_free(sp); - return ALC_FALSE; -} - -static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - int (*thread_func)(void*) = NULL; - snd_pcm_hw_params_t *hp = NULL; - snd_pcm_access_t access; - const char *funcerr; - int err; - - snd_pcm_hw_params_malloc(&hp); -#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error - CHECK(snd_pcm_hw_params_current(self->pcmHandle, hp)); - /* retrieve configuration info */ - CHECK(snd_pcm_hw_params_get_access(hp, &access)); -#undef CHECK - snd_pcm_hw_params_free(hp); - hp = NULL; - - self->size = snd_pcm_frames_to_bytes(self->pcmHandle, device->UpdateSize); - if(access == SND_PCM_ACCESS_RW_INTERLEAVED) - { - self->buffer = al_malloc(16, self->size); - if(!self->buffer) - { - ERR("buffer malloc failed\n"); - return ALC_FALSE; - } - thread_func = ALCplaybackAlsa_mixerNoMMapProc; - } - else - { - err = snd_pcm_prepare(self->pcmHandle); - if(err < 0) - { - ERR("snd_pcm_prepare(data->pcmHandle) failed: %s\n", snd_strerror(err)); - return ALC_FALSE; - } - thread_func = ALCplaybackAlsa_mixerProc; - } - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); - if(althrd_create(&self->thread, thread_func, self) != althrd_success) - { - ERR("Could not create playback thread\n"); - al_free(self->buffer); - self->buffer = NULL; - return ALC_FALSE; - } - - return ALC_TRUE; - -error: - ERR("%s failed: %s\n", funcerr, snd_strerror(err)); - if(hp) snd_pcm_hw_params_free(hp); - return ALC_FALSE; -} - -static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self) -{ - int res; - - if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) - return; - althrd_join(self->thread, &res); - - al_free(self->buffer); - self->buffer = NULL; -} - -static ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - snd_pcm_sframes_t delay = 0; - ClockLatency ret; - int err; - - ALCplaybackAlsa_lock(self); - ret.ClockTime = GetDeviceClockTime(device); - if((err=snd_pcm_delay(self->pcmHandle, &delay)) < 0) - { - ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); - delay = 0; - } - if(delay < 0) delay = 0; - ret.Latency = delay * DEVICE_CLOCK_RES / device->Frequency; - ALCplaybackAlsa_unlock(self); - - return ret; -} - - -typedef struct ALCcaptureAlsa { - DERIVE_FROM_TYPE(ALCbackend); - - snd_pcm_t *pcmHandle; - - ALvoid *buffer; - ALsizei size; - - ALboolean doCapture; - ll_ringbuffer_t *ring; - - snd_pcm_sframes_t last_avail; -} ALCcaptureAlsa; - -static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device); -static void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self); -static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name); -static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, ALCboolean, reset) -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 ClockLatency ALCcaptureAlsa_getClockLatency(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) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCcaptureAlsa, ALCbackend, self); - - self->pcmHandle = NULL; - self->buffer = NULL; - self->ring = NULL; -} - -void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self) -{ - if(self->pcmHandle) - snd_pcm_close(self->pcmHandle); - self->pcmHandle = NULL; - - al_free(self->buffer); - self->buffer = NULL; - - ll_ringbuffer_free(self->ring); - self->ring = NULL; - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - const char *driver = NULL; - snd_pcm_hw_params_t *hp; - snd_pcm_uframes_t bufferSizeInFrames; - snd_pcm_uframes_t periodSizeInFrames; - ALboolean needring = AL_FALSE; - snd_pcm_format_t format = -1; - const char *funcerr; - int err; - - if(name) - { - const DevMap *iter; - - if(VECTOR_SIZE(CaptureDevices) == 0) - probe_devices(SND_PCM_STREAM_CAPTURE, &CaptureDevices); - -#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, name) == 0) - VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); -#undef MATCH_NAME - if(iter == VECTOR_END(CaptureDevices)) - return ALC_INVALID_VALUE; - driver = alstr_get_cstr(iter->device_name); - } - else - { - name = alsaDevice; - driver = GetConfigValue(NULL, "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) - { - ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err)); - return ALC_INVALID_VALUE; - } - - /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */ - snd_config_update_free_global(); - - switch(device->FmtType) - { - case DevFmtByte: - format = SND_PCM_FORMAT_S8; - break; - case DevFmtUByte: - format = SND_PCM_FORMAT_U8; - break; - case DevFmtShort: - format = SND_PCM_FORMAT_S16; - break; - case DevFmtUShort: - format = SND_PCM_FORMAT_U16; - break; - case DevFmtInt: - format = SND_PCM_FORMAT_S32; - break; - case DevFmtUInt: - format = SND_PCM_FORMAT_U32; - break; - case DevFmtFloat: - format = SND_PCM_FORMAT_FLOAT; - break; - } - - funcerr = NULL; - bufferSizeInFrames = maxu(device->UpdateSize*device->NumUpdates, - 100*device->Frequency/1000); - periodSizeInFrames = minu(bufferSizeInFrames, 25*device->Frequency/1000); - - snd_pcm_hw_params_malloc(&hp); -#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error - CHECK(snd_pcm_hw_params_any(self->pcmHandle, hp)); - /* set interleaved access */ - CHECK(snd_pcm_hw_params_set_access(self->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); - /* set format (implicitly sets sample bits) */ - CHECK(snd_pcm_hw_params_set_format(self->pcmHandle, hp, format)); - /* set channels (implicitly sets frame bits) */ - CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder))); - /* set rate (implicitly constrains period/buffer parameters) */ - CHECK(snd_pcm_hw_params_set_rate(self->pcmHandle, hp, device->Frequency, 0)); - /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ - if(snd_pcm_hw_params_set_buffer_size_min(self->pcmHandle, hp, &bufferSizeInFrames) < 0) - { - TRACE("Buffer too large, using intermediate ring buffer\n"); - needring = AL_TRUE; - CHECK(snd_pcm_hw_params_set_buffer_size_near(self->pcmHandle, hp, &bufferSizeInFrames)); - } - /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ - CHECK(snd_pcm_hw_params_set_period_size_near(self->pcmHandle, hp, &periodSizeInFrames, NULL)); - /* install and prepare hardware configuration */ - CHECK(snd_pcm_hw_params(self->pcmHandle, hp)); - /* retrieve configuration info */ - CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL)); -#undef CHECK - snd_pcm_hw_params_free(hp); - hp = NULL; - - if(needring) - { - self->ring = ll_ringbuffer_create( - device->UpdateSize*device->NumUpdates, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), - false - ); - if(!self->ring) - { - ERR("ring buffer create failed\n"); - goto error2; - } - } - - alstr_copy_cstr(&device->DeviceName, name); - - return ALC_NO_ERROR; - -error: - ERR("%s failed: %s\n", funcerr, snd_strerror(err)); - if(hp) snd_pcm_hw_params_free(hp); - -error2: - ll_ringbuffer_free(self->ring); - self->ring = NULL; - snd_pcm_close(self->pcmHandle); - self->pcmHandle = NULL; - - return ALC_INVALID_VALUE; -} - -static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self) -{ - int err = snd_pcm_prepare(self->pcmHandle); - if(err < 0) - ERR("prepare failed: %s\n", snd_strerror(err)); - else - { - err = snd_pcm_start(self->pcmHandle); - if(err < 0) - ERR("start failed: %s\n", snd_strerror(err)); - } - if(err < 0) - { - aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, "Capture state failure: %s", - snd_strerror(err)); - return ALC_FALSE; - } - - self->doCapture = AL_TRUE; - return ALC_TRUE; -} - -static void ALCcaptureAlsa_stop(ALCcaptureAlsa *self) -{ - ALCuint avail; - int err; - - /* OpenAL requires access to unread audio after stopping, but ALSA's - * snd_pcm_drain is unreliable and snd_pcm_drop drops it. Capture what's - * available now so it'll be available later after the drop. */ - avail = ALCcaptureAlsa_availableSamples(self); - if(!self->ring && avail > 0) - { - /* The ring buffer implicitly captures when checking availability. - * Direct access needs to explicitly capture it into temp storage. */ - ALsizei size; - void *ptr; - - size = snd_pcm_frames_to_bytes(self->pcmHandle, avail); - ptr = al_malloc(16, size); - if(ptr) - { - ALCcaptureAlsa_captureSamples(self, ptr, avail); - al_free(self->buffer); - self->buffer = ptr; - self->size = size; - } - } - err = snd_pcm_drop(self->pcmHandle); - if(err < 0) - ERR("drop failed: %s\n", snd_strerror(err)); - self->doCapture = AL_FALSE; -} - -static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALCuint samples) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - - if(self->ring) - { - ll_ringbuffer_read(self->ring, buffer, samples); - return ALC_NO_ERROR; - } - - self->last_avail -= samples; - while(ATOMIC_LOAD(&device->Connected, almemory_order_acquire) && samples > 0) - { - snd_pcm_sframes_t amt = 0; - - if(self->size > 0) - { - /* First get any data stored from the last stop */ - amt = snd_pcm_bytes_to_frames(self->pcmHandle, self->size); - if((snd_pcm_uframes_t)amt > samples) amt = samples; - - amt = snd_pcm_frames_to_bytes(self->pcmHandle, amt); - memcpy(buffer, self->buffer, amt); - - if(self->size > amt) - { - memmove(self->buffer, self->buffer+amt, self->size - amt); - self->size -= amt; - } - else - { - al_free(self->buffer); - self->buffer = NULL; - self->size = 0; - } - amt = snd_pcm_bytes_to_frames(self->pcmHandle, amt); - } - else if(self->doCapture) - amt = snd_pcm_readi(self->pcmHandle, buffer, samples); - if(amt < 0) - { - ERR("read error: %s\n", snd_strerror(amt)); - - if(amt == -EAGAIN) - continue; - if((amt=snd_pcm_recover(self->pcmHandle, amt, 1)) >= 0) - { - amt = snd_pcm_start(self->pcmHandle); - if(amt >= 0) - amt = snd_pcm_avail_update(self->pcmHandle); - } - if(amt < 0) - { - ERR("restore error: %s\n", snd_strerror(amt)); - aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(amt)); - break; - } - /* If the amount available is less than what's asked, we lost it - * during recovery. So just give silence instead. */ - if((snd_pcm_uframes_t)amt < samples) - break; - continue; - } - - buffer = (ALbyte*)buffer + amt; - samples -= amt; - } - if(samples > 0) - memset(buffer, ((device->FmtType == DevFmtUByte) ? 0x80 : 0), - snd_pcm_frames_to_bytes(self->pcmHandle, samples)); - - return ALC_NO_ERROR; -} - -static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - snd_pcm_sframes_t avail = 0; - - if(ATOMIC_LOAD(&device->Connected, almemory_order_acquire) && self->doCapture) - avail = snd_pcm_avail_update(self->pcmHandle); - if(avail < 0) - { - ERR("avail update failed: %s\n", snd_strerror(avail)); - - if((avail=snd_pcm_recover(self->pcmHandle, avail, 1)) >= 0) - { - if(self->doCapture) - avail = snd_pcm_start(self->pcmHandle); - if(avail >= 0) - avail = snd_pcm_avail_update(self->pcmHandle); - } - if(avail < 0) - { - ERR("restore error: %s\n", snd_strerror(avail)); - aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(avail)); - } - } - - if(!self->ring) - { - if(avail < 0) avail = 0; - avail += snd_pcm_bytes_to_frames(self->pcmHandle, self->size); - if(avail > self->last_avail) self->last_avail = avail; - return self->last_avail; - } - - while(avail > 0) - { - ll_ringbuffer_data_t vec[2]; - snd_pcm_sframes_t amt; - - ll_ringbuffer_get_write_vector(self->ring, vec); - if(vec[0].len == 0) break; - - amt = (vec[0].len < (snd_pcm_uframes_t)avail) ? - vec[0].len : (snd_pcm_uframes_t)avail; - amt = snd_pcm_readi(self->pcmHandle, vec[0].buf, amt); - if(amt < 0) - { - ERR("read error: %s\n", snd_strerror(amt)); - - if(amt == -EAGAIN) - continue; - if((amt=snd_pcm_recover(self->pcmHandle, amt, 1)) >= 0) - { - if(self->doCapture) - amt = snd_pcm_start(self->pcmHandle); - if(amt >= 0) - amt = snd_pcm_avail_update(self->pcmHandle); - } - if(amt < 0) - { - ERR("restore error: %s\n", snd_strerror(amt)); - aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(amt)); - break; - } - avail = amt; - continue; - } - - ll_ringbuffer_write_advance(self->ring, amt); - avail -= amt; - } - - return ll_ringbuffer_read_space(self->ring); -} - -static ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - snd_pcm_sframes_t delay = 0; - ClockLatency ret; - int err; - - ALCcaptureAlsa_lock(self); - ret.ClockTime = GetDeviceClockTime(device); - if((err=snd_pcm_delay(self->pcmHandle, &delay)) < 0) - { - ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); - delay = 0; - } - if(delay < 0) delay = 0; - ret.Latency = delay * DEVICE_CLOCK_RES / device->Frequency; - ALCcaptureAlsa_unlock(self); - - return ret; -} - - -typedef struct ALCalsaBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCalsaBackendFactory; -#define ALCALSABACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCalsaBackendFactory, ALCbackendFactory) } } - -static ALCboolean ALCalsaBackendFactory_init(ALCalsaBackendFactory* UNUSED(self)) -{ - VECTOR_INIT(PlaybackDevices); - VECTOR_INIT(CaptureDevices); - - if(!alsa_load()) - return ALC_FALSE; - return ALC_TRUE; -} - -static void ALCalsaBackendFactory_deinit(ALCalsaBackendFactory* UNUSED(self)) -{ - clear_devlist(&PlaybackDevices); - VECTOR_DEINIT(PlaybackDevices); - - clear_devlist(&CaptureDevices); - VECTOR_DEINIT(CaptureDevices); - -#ifdef HAVE_DYNLOAD - if(alsa_handle) - CloseLib(alsa_handle); - alsa_handle = NULL; -#endif -} - -static ALCboolean ALCalsaBackendFactory_querySupport(ALCalsaBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} - -static void ALCalsaBackendFactory_probe(ALCalsaBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) -{ - switch(type) - { -#define APPEND_OUTNAME(i) do { \ - if(!alstr_empty((i)->name)) \ - alstr_append_range(outnames, VECTOR_BEGIN((i)->name), \ - VECTOR_END((i)->name)+1); \ -} while(0) - case ALL_DEVICE_PROBE: - probe_devices(SND_PCM_STREAM_PLAYBACK, &PlaybackDevices); - VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_OUTNAME); - break; - - case CAPTURE_DEVICE_PROBE: - probe_devices(SND_PCM_STREAM_CAPTURE, &CaptureDevices); - VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_OUTNAME); - break; -#undef APPEND_OUTNAME - } -} - -static ALCbackend* ALCalsaBackendFactory_createBackend(ALCalsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - { - ALCplaybackAlsa *backend; - NEW_OBJ(backend, ALCplaybackAlsa)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - if(type == ALCbackend_Capture) - { - ALCcaptureAlsa *backend; - NEW_OBJ(backend, ALCcaptureAlsa)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} - -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCalsaBackendFactory); - - -ALCbackendFactory *ALCalsaBackendFactory_getFactory(void) -{ - static ALCalsaBackendFactory factory = ALCALSABACKENDFACTORY_INITIALIZER; - return STATIC_CAST(ALCbackendFactory, &factory); -} diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp new file mode 100644 index 00000000..f9323bdb --- /dev/null +++ b/Alc/backends/alsa.cpp @@ -0,0 +1,1470 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include "alMain.h" +#include "alu.h" +#include "alconfig.h" +#include "ringbuffer.h" +#include "threads.h" +#include "compat.h" + +#include "backends/base.h" + +#include + + +static const ALCchar alsaDevice[] = "ALSA Default"; + + +#ifdef HAVE_DYNLOAD +#define ALSA_FUNCS(MAGIC) \ + MAGIC(snd_strerror); \ + MAGIC(snd_pcm_open); \ + MAGIC(snd_pcm_close); \ + MAGIC(snd_pcm_nonblock); \ + MAGIC(snd_pcm_frames_to_bytes); \ + MAGIC(snd_pcm_bytes_to_frames); \ + MAGIC(snd_pcm_hw_params_malloc); \ + MAGIC(snd_pcm_hw_params_free); \ + MAGIC(snd_pcm_hw_params_any); \ + MAGIC(snd_pcm_hw_params_current); \ + MAGIC(snd_pcm_hw_params_set_access); \ + MAGIC(snd_pcm_hw_params_set_format); \ + MAGIC(snd_pcm_hw_params_set_channels); \ + MAGIC(snd_pcm_hw_params_set_periods_near); \ + MAGIC(snd_pcm_hw_params_set_rate_near); \ + MAGIC(snd_pcm_hw_params_set_rate); \ + MAGIC(snd_pcm_hw_params_set_rate_resample); \ + MAGIC(snd_pcm_hw_params_set_buffer_time_near); \ + MAGIC(snd_pcm_hw_params_set_period_time_near); \ + MAGIC(snd_pcm_hw_params_set_buffer_size_near); \ + MAGIC(snd_pcm_hw_params_set_period_size_near); \ + MAGIC(snd_pcm_hw_params_set_buffer_size_min); \ + MAGIC(snd_pcm_hw_params_get_buffer_time_min); \ + MAGIC(snd_pcm_hw_params_get_buffer_time_max); \ + MAGIC(snd_pcm_hw_params_get_period_time_min); \ + MAGIC(snd_pcm_hw_params_get_period_time_max); \ + MAGIC(snd_pcm_hw_params_get_buffer_size); \ + MAGIC(snd_pcm_hw_params_get_period_size); \ + MAGIC(snd_pcm_hw_params_get_access); \ + MAGIC(snd_pcm_hw_params_get_periods); \ + MAGIC(snd_pcm_hw_params_test_format); \ + MAGIC(snd_pcm_hw_params_test_channels); \ + MAGIC(snd_pcm_hw_params); \ + MAGIC(snd_pcm_sw_params_malloc); \ + MAGIC(snd_pcm_sw_params_current); \ + MAGIC(snd_pcm_sw_params_set_avail_min); \ + MAGIC(snd_pcm_sw_params_set_stop_threshold); \ + MAGIC(snd_pcm_sw_params); \ + MAGIC(snd_pcm_sw_params_free); \ + MAGIC(snd_pcm_prepare); \ + MAGIC(snd_pcm_start); \ + MAGIC(snd_pcm_resume); \ + MAGIC(snd_pcm_reset); \ + MAGIC(snd_pcm_wait); \ + MAGIC(snd_pcm_delay); \ + MAGIC(snd_pcm_state); \ + MAGIC(snd_pcm_avail_update); \ + MAGIC(snd_pcm_areas_silence); \ + MAGIC(snd_pcm_mmap_begin); \ + MAGIC(snd_pcm_mmap_commit); \ + MAGIC(snd_pcm_readi); \ + MAGIC(snd_pcm_writei); \ + MAGIC(snd_pcm_drain); \ + MAGIC(snd_pcm_drop); \ + MAGIC(snd_pcm_recover); \ + MAGIC(snd_pcm_info_malloc); \ + MAGIC(snd_pcm_info_free); \ + MAGIC(snd_pcm_info_set_device); \ + MAGIC(snd_pcm_info_set_subdevice); \ + MAGIC(snd_pcm_info_set_stream); \ + MAGIC(snd_pcm_info_get_name); \ + MAGIC(snd_ctl_pcm_next_device); \ + MAGIC(snd_ctl_pcm_info); \ + MAGIC(snd_ctl_open); \ + MAGIC(snd_ctl_close); \ + MAGIC(snd_ctl_card_info_malloc); \ + MAGIC(snd_ctl_card_info_free); \ + MAGIC(snd_ctl_card_info); \ + MAGIC(snd_ctl_card_info_get_name); \ + MAGIC(snd_ctl_card_info_get_id); \ + MAGIC(snd_card_next); \ + MAGIC(snd_config_update_free_global) + +static void *alsa_handle; +#define MAKE_FUNC(f) static decltype(f) * p##f +ALSA_FUNCS(MAKE_FUNC); +#undef MAKE_FUNC + +#ifndef IN_IDE_PARSER +#define snd_strerror psnd_strerror +#define snd_pcm_open psnd_pcm_open +#define snd_pcm_close psnd_pcm_close +#define snd_pcm_nonblock psnd_pcm_nonblock +#define snd_pcm_frames_to_bytes psnd_pcm_frames_to_bytes +#define snd_pcm_bytes_to_frames psnd_pcm_bytes_to_frames +#define snd_pcm_hw_params_malloc psnd_pcm_hw_params_malloc +#define snd_pcm_hw_params_free psnd_pcm_hw_params_free +#define snd_pcm_hw_params_any psnd_pcm_hw_params_any +#define snd_pcm_hw_params_current psnd_pcm_hw_params_current +#define snd_pcm_hw_params_set_access psnd_pcm_hw_params_set_access +#define snd_pcm_hw_params_set_format psnd_pcm_hw_params_set_format +#define snd_pcm_hw_params_set_channels psnd_pcm_hw_params_set_channels +#define snd_pcm_hw_params_set_periods_near psnd_pcm_hw_params_set_periods_near +#define snd_pcm_hw_params_set_rate_near psnd_pcm_hw_params_set_rate_near +#define snd_pcm_hw_params_set_rate psnd_pcm_hw_params_set_rate +#define snd_pcm_hw_params_set_rate_resample psnd_pcm_hw_params_set_rate_resample +#define snd_pcm_hw_params_set_buffer_time_near psnd_pcm_hw_params_set_buffer_time_near +#define snd_pcm_hw_params_set_period_time_near psnd_pcm_hw_params_set_period_time_near +#define snd_pcm_hw_params_set_buffer_size_near psnd_pcm_hw_params_set_buffer_size_near +#define snd_pcm_hw_params_set_period_size_near psnd_pcm_hw_params_set_period_size_near +#define snd_pcm_hw_params_set_buffer_size_min psnd_pcm_hw_params_set_buffer_size_min +#define snd_pcm_hw_params_get_buffer_time_min psnd_pcm_hw_params_get_buffer_time_min +#define snd_pcm_hw_params_get_buffer_time_max psnd_pcm_hw_params_get_buffer_time_max +#define snd_pcm_hw_params_get_period_time_min psnd_pcm_hw_params_get_period_time_min +#define snd_pcm_hw_params_get_period_time_max psnd_pcm_hw_params_get_period_time_max +#define snd_pcm_hw_params_get_buffer_size psnd_pcm_hw_params_get_buffer_size +#define snd_pcm_hw_params_get_period_size psnd_pcm_hw_params_get_period_size +#define snd_pcm_hw_params_get_access psnd_pcm_hw_params_get_access +#define snd_pcm_hw_params_get_periods psnd_pcm_hw_params_get_periods +#define snd_pcm_hw_params_test_format psnd_pcm_hw_params_test_format +#define snd_pcm_hw_params_test_channels psnd_pcm_hw_params_test_channels +#define snd_pcm_hw_params psnd_pcm_hw_params +#define snd_pcm_sw_params_malloc psnd_pcm_sw_params_malloc +#define snd_pcm_sw_params_current psnd_pcm_sw_params_current +#define snd_pcm_sw_params_set_avail_min psnd_pcm_sw_params_set_avail_min +#define snd_pcm_sw_params_set_stop_threshold psnd_pcm_sw_params_set_stop_threshold +#define snd_pcm_sw_params psnd_pcm_sw_params +#define snd_pcm_sw_params_free psnd_pcm_sw_params_free +#define snd_pcm_prepare psnd_pcm_prepare +#define snd_pcm_start psnd_pcm_start +#define snd_pcm_resume psnd_pcm_resume +#define snd_pcm_reset psnd_pcm_reset +#define snd_pcm_wait psnd_pcm_wait +#define snd_pcm_delay psnd_pcm_delay +#define snd_pcm_state psnd_pcm_state +#define snd_pcm_avail_update psnd_pcm_avail_update +#define snd_pcm_areas_silence psnd_pcm_areas_silence +#define snd_pcm_mmap_begin psnd_pcm_mmap_begin +#define snd_pcm_mmap_commit psnd_pcm_mmap_commit +#define snd_pcm_readi psnd_pcm_readi +#define snd_pcm_writei psnd_pcm_writei +#define snd_pcm_drain psnd_pcm_drain +#define snd_pcm_drop psnd_pcm_drop +#define snd_pcm_recover psnd_pcm_recover +#define snd_pcm_info_malloc psnd_pcm_info_malloc +#define snd_pcm_info_free psnd_pcm_info_free +#define snd_pcm_info_set_device psnd_pcm_info_set_device +#define snd_pcm_info_set_subdevice psnd_pcm_info_set_subdevice +#define snd_pcm_info_set_stream psnd_pcm_info_set_stream +#define snd_pcm_info_get_name psnd_pcm_info_get_name +#define snd_ctl_pcm_next_device psnd_ctl_pcm_next_device +#define snd_ctl_pcm_info psnd_ctl_pcm_info +#define snd_ctl_open psnd_ctl_open +#define snd_ctl_close psnd_ctl_close +#define snd_ctl_card_info_malloc psnd_ctl_card_info_malloc +#define snd_ctl_card_info_free psnd_ctl_card_info_free +#define snd_ctl_card_info psnd_ctl_card_info +#define snd_ctl_card_info_get_name psnd_ctl_card_info_get_name +#define snd_ctl_card_info_get_id psnd_ctl_card_info_get_id +#define snd_card_next psnd_card_next +#define snd_config_update_free_global psnd_config_update_free_global +#endif +#endif + + +static ALCboolean alsa_load(void) +{ + ALCboolean error = ALC_FALSE; + +#ifdef HAVE_DYNLOAD + if(!alsa_handle) + { + al_string missing_funcs = AL_STRING_INIT_STATIC(); + + alsa_handle = LoadLib("libasound.so.2"); + if(!alsa_handle) + { + WARN("Failed to load %s\n", "libasound.so.2"); + return ALC_FALSE; + } + + error = ALC_FALSE; +#define LOAD_FUNC(f) do { \ + p##f = reinterpret_cast(GetSymbol(alsa_handle, #f)); \ + if(p##f == NULL) { \ + error = ALC_TRUE; \ + alstr_append_cstr(&missing_funcs, "\n" #f); \ + } \ +} while(0) + ALSA_FUNCS(LOAD_FUNC); +#undef LOAD_FUNC + + if(error) + { + WARN("Missing expected functions:%s\n", alstr_get_cstr(missing_funcs)); + CloseLib(alsa_handle); + alsa_handle = NULL; + } + alstr_reset(&missing_funcs); + } +#endif + + return !error; +} + + +typedef struct { + al_string name; + al_string device_name; +} DevMap; +TYPEDEF_VECTOR(DevMap, vector_DevMap) + +static vector_DevMap PlaybackDevices; +static vector_DevMap CaptureDevices; + +static void clear_devlist(vector_DevMap *devlist) +{ +#define FREE_DEV(i) do { \ + AL_STRING_DEINIT((i)->name); \ + AL_STRING_DEINIT((i)->device_name); \ +} while(0) + VECTOR_FOR_EACH(DevMap, *devlist, FREE_DEV); + VECTOR_RESIZE(*devlist, 0, 0); +#undef FREE_DEV +} + + +static const char *prefix_name(snd_pcm_stream_t stream) +{ + assert(stream == SND_PCM_STREAM_PLAYBACK || stream == SND_PCM_STREAM_CAPTURE); + return (stream==SND_PCM_STREAM_PLAYBACK) ? "device-prefix" : "capture-prefix"; +} + +static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList) +{ + const char *main_prefix = "plughw:"; + snd_ctl_t *handle; + snd_ctl_card_info_t *info; + snd_pcm_info_t *pcminfo; + int card, err, dev; + DevMap entry; + + clear_devlist(DeviceList); + + snd_ctl_card_info_malloc(&info); + snd_pcm_info_malloc(&pcminfo); + + AL_STRING_INIT(entry.name); + AL_STRING_INIT(entry.device_name); + alstr_copy_cstr(&entry.name, alsaDevice); + alstr_copy_cstr(&entry.device_name, GetConfigValue( + NULL, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ? "device" : "capture", "default" + )); + VECTOR_PUSH_BACK(*DeviceList, entry); + + if(stream == SND_PCM_STREAM_PLAYBACK) + { + const char *customdevs, *sep, *next; + next = GetConfigValue(NULL, "alsa", "custom-devices", ""); + while((customdevs=next) != NULL && customdevs[0]) + { + next = strchr(customdevs, ';'); + sep = strchr(customdevs, '='); + if(!sep) + { + al_string spec = AL_STRING_INIT_STATIC(); + if(next) + alstr_copy_range(&spec, customdevs, next++); + else + alstr_copy_cstr(&spec, customdevs); + ERR("Invalid ALSA device specification \"%s\"\n", alstr_get_cstr(spec)); + alstr_reset(&spec); + continue; + } + + AL_STRING_INIT(entry.name); + AL_STRING_INIT(entry.device_name); + alstr_copy_range(&entry.name, customdevs, sep++); + if(next) + alstr_copy_range(&entry.device_name, sep, next++); + else + alstr_copy_cstr(&entry.device_name, sep); + TRACE("Got device \"%s\", \"%s\"\n", alstr_get_cstr(entry.name), + alstr_get_cstr(entry.device_name)); + VECTOR_PUSH_BACK(*DeviceList, entry); + } + } + + card = -1; + if((err=snd_card_next(&card)) < 0) + ERR("Failed to find a card: %s\n", snd_strerror(err)); + ConfigValueStr(NULL, "alsa", prefix_name(stream), &main_prefix); + while(card >= 0) + { + const char *card_prefix = main_prefix; + const char *cardname, *cardid; + char name[256]; + + snprintf(name, sizeof(name), "hw:%d", card); + if((err = snd_ctl_open(&handle, name, 0)) < 0) + { + ERR("control open (hw:%d): %s\n", card, snd_strerror(err)); + goto next_card; + } + if((err = snd_ctl_card_info(handle, info)) < 0) + { + ERR("control hardware info (hw:%d): %s\n", card, snd_strerror(err)); + snd_ctl_close(handle); + goto next_card; + } + + cardname = snd_ctl_card_info_get_name(info); + cardid = snd_ctl_card_info_get_id(info); + + snprintf(name, sizeof(name), "%s-%s", prefix_name(stream), cardid); + ConfigValueStr(NULL, "alsa", name, &card_prefix); + + dev = -1; + while(1) + { + const char *device_prefix = card_prefix; + const char *devname; + char device[128]; + + if(snd_ctl_pcm_next_device(handle, &dev) < 0) + ERR("snd_ctl_pcm_next_device failed\n"); + if(dev < 0) + break; + + snd_pcm_info_set_device(pcminfo, dev); + snd_pcm_info_set_subdevice(pcminfo, 0); + snd_pcm_info_set_stream(pcminfo, stream); + if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) + { + if(err != -ENOENT) + ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err)); + continue; + } + + devname = snd_pcm_info_get_name(pcminfo); + + snprintf(name, sizeof(name), "%s-%s-%d", prefix_name(stream), cardid, dev); + ConfigValueStr(NULL, "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); + + TRACE("Got device \"%s\", \"%s\"\n", name, device); + AL_STRING_INIT(entry.name); + AL_STRING_INIT(entry.device_name); + alstr_copy_cstr(&entry.name, name); + alstr_copy_cstr(&entry.device_name, device); + VECTOR_PUSH_BACK(*DeviceList, entry); + } + snd_ctl_close(handle); + next_card: + if(snd_card_next(&card) < 0) { + ERR("snd_card_next failed\n"); + break; + } + } + + snd_pcm_info_free(pcminfo); + snd_ctl_card_info_free(info); +} + + +static int verify_state(snd_pcm_t *handle) +{ + snd_pcm_state_t state = snd_pcm_state(handle); + int err; + + switch(state) + { + case SND_PCM_STATE_OPEN: + case SND_PCM_STATE_SETUP: + case SND_PCM_STATE_PREPARED: + case SND_PCM_STATE_RUNNING: + case SND_PCM_STATE_DRAINING: + case SND_PCM_STATE_PAUSED: + /* All Okay */ + break; + + case SND_PCM_STATE_XRUN: + if((err=snd_pcm_recover(handle, -EPIPE, 1)) < 0) + return err; + break; + case SND_PCM_STATE_SUSPENDED: + if((err=snd_pcm_recover(handle, -ESTRPIPE, 1)) < 0) + return err; + break; + case SND_PCM_STATE_DISCONNECTED: + return -ENODEV; + } + + return state; +} + + +struct ALCplaybackAlsa final : public ALCbackend { + snd_pcm_t *pcmHandle; + + ALvoid *buffer; + ALsizei size; + + ATOMIC(ALenum) killNow; + althrd_t thread; +}; + +static int ALCplaybackAlsa_mixerProc(void *ptr); +static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr); + +static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device); +static void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self); +static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name); +static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self); +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 ClockLatency ALCplaybackAlsa_getClockLatency(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) +{ + new (self) ALCplaybackAlsa{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCplaybackAlsa, ALCbackend, self); + + self->pcmHandle = NULL; + self->buffer = NULL; + + ATOMIC_INIT(&self->killNow, AL_TRUE); +} + +void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self) +{ + if(self->pcmHandle) + snd_pcm_close(self->pcmHandle); + self->pcmHandle = NULL; + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCplaybackAlsa(); +} + + +static int ALCplaybackAlsa_mixerProc(void *ptr) +{ + ALCplaybackAlsa *self = static_cast(ptr); + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + const snd_pcm_channel_area_t *areas = NULL; + snd_pcm_uframes_t update_size, num_updates; + snd_pcm_sframes_t avail, commitres; + snd_pcm_uframes_t offset, frames; + char *WritePtr; + int err; + + SetRTPriority(); + althrd_setname(althrd_current(), MIXER_THREAD_NAME); + + update_size = device->UpdateSize; + num_updates = device->NumUpdates; + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) + { + int state = verify_state(self->pcmHandle); + if(state < 0) + { + ERR("Invalid state detected: %s\n", snd_strerror(state)); + ALCplaybackAlsa_lock(self); + aluHandleDisconnect(device, "Bad state: %s", snd_strerror(state)); + ALCplaybackAlsa_unlock(self); + break; + } + + avail = snd_pcm_avail_update(self->pcmHandle); + if(avail < 0) + { + ERR("available update failed: %s\n", snd_strerror(avail)); + continue; + } + + if((snd_pcm_uframes_t)avail > update_size*(num_updates+1)) + { + WARN("available samples exceeds the buffer size\n"); + snd_pcm_reset(self->pcmHandle); + continue; + } + + // make sure there's frames to process + if((snd_pcm_uframes_t)avail < update_size) + { + if(state != SND_PCM_STATE_RUNNING) + { + err = snd_pcm_start(self->pcmHandle); + if(err < 0) + { + ERR("start failed: %s\n", snd_strerror(err)); + continue; + } + } + if(snd_pcm_wait(self->pcmHandle, 1000) == 0) + ERR("Wait timeout... buffer size too low?\n"); + continue; + } + avail -= avail%update_size; + + // it is possible that contiguous areas are smaller, thus we use a loop + ALCplaybackAlsa_lock(self); + while(avail > 0) + { + frames = avail; + + err = snd_pcm_mmap_begin(self->pcmHandle, &areas, &offset, &frames); + if(err < 0) + { + ERR("mmap begin error: %s\n", snd_strerror(err)); + break; + } + + WritePtr = (char*)areas->addr + (offset * areas->step / 8); + aluMixData(device, WritePtr, frames); + + commitres = snd_pcm_mmap_commit(self->pcmHandle, offset, frames); + if(commitres < 0 || (commitres-frames) != 0) + { + ERR("mmap commit error: %s\n", + snd_strerror(commitres >= 0 ? -EPIPE : commitres)); + break; + } + + avail -= frames; + } + ALCplaybackAlsa_unlock(self); + } + + return 0; +} + +static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr) +{ + ALCplaybackAlsa *self = static_cast(ptr); + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + snd_pcm_uframes_t update_size, num_updates; + snd_pcm_sframes_t avail; + char *WritePtr; + int err; + + SetRTPriority(); + althrd_setname(althrd_current(), MIXER_THREAD_NAME); + + update_size = device->UpdateSize; + num_updates = device->NumUpdates; + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) + { + int state = verify_state(self->pcmHandle); + if(state < 0) + { + ERR("Invalid state detected: %s\n", snd_strerror(state)); + ALCplaybackAlsa_lock(self); + aluHandleDisconnect(device, "Bad state: %s", snd_strerror(state)); + ALCplaybackAlsa_unlock(self); + break; + } + + avail = snd_pcm_avail_update(self->pcmHandle); + if(avail < 0) + { + ERR("available update failed: %s\n", snd_strerror(avail)); + continue; + } + + if((snd_pcm_uframes_t)avail > update_size*num_updates) + { + WARN("available samples exceeds the buffer size\n"); + snd_pcm_reset(self->pcmHandle); + continue; + } + + if((snd_pcm_uframes_t)avail < update_size) + { + if(state != SND_PCM_STATE_RUNNING) + { + err = snd_pcm_start(self->pcmHandle); + if(err < 0) + { + ERR("start failed: %s\n", snd_strerror(err)); + continue; + } + } + if(snd_pcm_wait(self->pcmHandle, 1000) == 0) + ERR("Wait timeout... buffer size too low?\n"); + continue; + } + + ALCplaybackAlsa_lock(self); + WritePtr = static_cast(self->buffer); + avail = snd_pcm_bytes_to_frames(self->pcmHandle, self->size); + aluMixData(device, WritePtr, avail); + + while(avail > 0) + { + int ret = snd_pcm_writei(self->pcmHandle, WritePtr, avail); + switch (ret) + { + case -EAGAIN: + continue; +#if ESTRPIPE != EPIPE + case -ESTRPIPE: +#endif + case -EPIPE: + case -EINTR: + ret = snd_pcm_recover(self->pcmHandle, ret, 1); + if(ret < 0) + avail = 0; + break; + default: + if (ret >= 0) + { + WritePtr += snd_pcm_frames_to_bytes(self->pcmHandle, ret); + avail -= ret; + } + break; + } + if (ret < 0) + { + ret = snd_pcm_prepare(self->pcmHandle); + if(ret < 0) + break; + } + } + ALCplaybackAlsa_unlock(self); + } + + return 0; +} + + +static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + const char *driver = NULL; + int err; + + if(name) + { + const DevMap *iter; + + if(VECTOR_SIZE(PlaybackDevices) == 0) + probe_devices(SND_PCM_STREAM_PLAYBACK, &PlaybackDevices); + +#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, name) == 0) + VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); +#undef MATCH_NAME + if(iter == VECTOR_END(PlaybackDevices)) + return ALC_INVALID_VALUE; + driver = alstr_get_cstr(iter->device_name); + } + else + { + name = alsaDevice; + driver = GetConfigValue(NULL, "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) + { + ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(err)); + return ALC_OUT_OF_MEMORY; + } + + /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */ + snd_config_update_free_global(); + + alstr_copy_cstr(&device->DeviceName, name); + + return ALC_NO_ERROR; +} + +static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + snd_pcm_uframes_t periodSizeInFrames; + unsigned int periodLen, bufferLen; + snd_pcm_sw_params_t *sp = NULL; + snd_pcm_hw_params_t *hp = NULL; + snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN; + snd_pcm_access_t access; + unsigned int periods; + unsigned int rate; + const char *funcerr; + int allowmmap; + int dir; + int err; + + switch(device->FmtType) + { + case DevFmtByte: + format = SND_PCM_FORMAT_S8; + break; + case DevFmtUByte: + format = SND_PCM_FORMAT_U8; + break; + case DevFmtShort: + format = SND_PCM_FORMAT_S16; + break; + case DevFmtUShort: + format = SND_PCM_FORMAT_U16; + break; + case DevFmtInt: + format = SND_PCM_FORMAT_S32; + break; + case DevFmtUInt: + format = SND_PCM_FORMAT_U32; + break; + case DevFmtFloat: + format = SND_PCM_FORMAT_FLOAT; + break; + } + + allowmmap = GetConfigValueBool(alstr_get_cstr(device->DeviceName), "alsa", "mmap", 1); + periods = device->NumUpdates; + periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency; + bufferLen = periodLen * periods; + rate = device->Frequency; + + snd_pcm_hw_params_malloc(&hp); +#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error + CHECK(snd_pcm_hw_params_any(self->pcmHandle, hp)); + /* set interleaved access */ + if(!allowmmap || snd_pcm_hw_params_set_access(self->pcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) + { + /* No mmap */ + CHECK(snd_pcm_hw_params_set_access(self->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); + } + /* test and set format (implicitly sets sample bits) */ + if(snd_pcm_hw_params_test_format(self->pcmHandle, hp, format) < 0) + { + static const struct { + snd_pcm_format_t format; + enum DevFmtType fmttype; + } formatlist[] = { + { SND_PCM_FORMAT_FLOAT, DevFmtFloat }, + { SND_PCM_FORMAT_S32, DevFmtInt }, + { SND_PCM_FORMAT_U32, DevFmtUInt }, + { SND_PCM_FORMAT_S16, DevFmtShort }, + { SND_PCM_FORMAT_U16, DevFmtUShort }, + { SND_PCM_FORMAT_S8, DevFmtByte }, + { SND_PCM_FORMAT_U8, DevFmtUByte }, + }; + size_t k; + + for(k = 0;k < COUNTOF(formatlist);k++) + { + format = formatlist[k].format; + if(snd_pcm_hw_params_test_format(self->pcmHandle, hp, format) >= 0) + { + device->FmtType = formatlist[k].fmttype; + break; + } + } + } + CHECK(snd_pcm_hw_params_set_format(self->pcmHandle, hp, format)); + /* test and set channels (implicitly sets frame bits) */ + if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder)) < 0) + { + static const enum DevFmtChannels channellist[] = { + DevFmtStereo, + DevFmtQuad, + DevFmtX51, + DevFmtX71, + DevFmtMono, + }; + size_t k; + + for(k = 0;k < COUNTOF(channellist);k++) + { + if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(channellist[k], 0)) >= 0) + { + device->FmtChans = channellist[k]; + device->AmbiOrder = 0; + break; + } + } + } + CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder))); + /* set rate (implicitly constrains period/buffer parameters) */ + if(!GetConfigValueBool(alstr_get_cstr(device->DeviceName), "alsa", "allow-resampler", 0) || + !(device->Flags&DEVICE_FREQUENCY_REQUEST)) + { + if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0) + ERR("Failed to disable ALSA resampler\n"); + } + else if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 1) < 0) + ERR("Failed to enable ALSA resampler\n"); + CHECK(snd_pcm_hw_params_set_rate_near(self->pcmHandle, hp, &rate, NULL)); + /* set buffer time (implicitly constrains period/buffer parameters) */ + if((err=snd_pcm_hw_params_set_buffer_time_near(self->pcmHandle, hp, &bufferLen, NULL)) < 0) + ERR("snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err)); + /* set period time (implicitly sets buffer size/bytes/time and period size/bytes) */ + if((err=snd_pcm_hw_params_set_period_time_near(self->pcmHandle, hp, &periodLen, NULL)) < 0) + ERR("snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err)); + /* install and prepare hardware configuration */ + CHECK(snd_pcm_hw_params(self->pcmHandle, hp)); + /* retrieve configuration info */ + CHECK(snd_pcm_hw_params_get_access(hp, &access)); + CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL)); + CHECK(snd_pcm_hw_params_get_periods(hp, &periods, &dir)); + if(dir != 0) + WARN("Inexact period count: %u (%d)\n", periods, dir); + + snd_pcm_hw_params_free(hp); + hp = NULL; + snd_pcm_sw_params_malloc(&sp); + + CHECK(snd_pcm_sw_params_current(self->pcmHandle, sp)); + CHECK(snd_pcm_sw_params_set_avail_min(self->pcmHandle, sp, periodSizeInFrames)); + CHECK(snd_pcm_sw_params_set_stop_threshold(self->pcmHandle, sp, periodSizeInFrames*periods)); + CHECK(snd_pcm_sw_params(self->pcmHandle, sp)); +#undef CHECK + snd_pcm_sw_params_free(sp); + sp = NULL; + + device->NumUpdates = periods; + device->UpdateSize = periodSizeInFrames; + device->Frequency = rate; + + SetDefaultChannelOrder(device); + + return ALC_TRUE; + +error: + ERR("%s failed: %s\n", funcerr, snd_strerror(err)); + if(hp) snd_pcm_hw_params_free(hp); + if(sp) snd_pcm_sw_params_free(sp); + return ALC_FALSE; +} + +static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + int (*thread_func)(void*) = NULL; + snd_pcm_hw_params_t *hp = NULL; + snd_pcm_access_t access; + const char *funcerr; + int err; + + snd_pcm_hw_params_malloc(&hp); +#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error + CHECK(snd_pcm_hw_params_current(self->pcmHandle, hp)); + /* retrieve configuration info */ + CHECK(snd_pcm_hw_params_get_access(hp, &access)); +#undef CHECK + snd_pcm_hw_params_free(hp); + hp = NULL; + + self->size = snd_pcm_frames_to_bytes(self->pcmHandle, device->UpdateSize); + if(access == SND_PCM_ACCESS_RW_INTERLEAVED) + { + self->buffer = al_malloc(16, self->size); + if(!self->buffer) + { + ERR("buffer malloc failed\n"); + return ALC_FALSE; + } + thread_func = ALCplaybackAlsa_mixerNoMMapProc; + } + else + { + err = snd_pcm_prepare(self->pcmHandle); + if(err < 0) + { + ERR("snd_pcm_prepare(data->pcmHandle) failed: %s\n", snd_strerror(err)); + return ALC_FALSE; + } + thread_func = ALCplaybackAlsa_mixerProc; + } + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); + if(althrd_create(&self->thread, thread_func, self) != althrd_success) + { + ERR("Could not create playback thread\n"); + al_free(self->buffer); + self->buffer = NULL; + return ALC_FALSE; + } + + return ALC_TRUE; + +error: + ERR("%s failed: %s\n", funcerr, snd_strerror(err)); + if(hp) snd_pcm_hw_params_free(hp); + return ALC_FALSE; +} + +static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self) +{ + int res; + + if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) + return; + althrd_join(self->thread, &res); + + al_free(self->buffer); + self->buffer = NULL; +} + +static ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + snd_pcm_sframes_t delay = 0; + ClockLatency ret; + int err; + + ALCplaybackAlsa_lock(self); + ret.ClockTime = GetDeviceClockTime(device); + if((err=snd_pcm_delay(self->pcmHandle, &delay)) < 0) + { + ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); + delay = 0; + } + if(delay < 0) delay = 0; + ret.Latency = delay * DEVICE_CLOCK_RES / device->Frequency; + ALCplaybackAlsa_unlock(self); + + return ret; +} + + +struct ALCcaptureAlsa final : public ALCbackend { + snd_pcm_t *pcmHandle; + + ALvoid *buffer; + ALsizei size; + + ALboolean doCapture; + ll_ringbuffer_t *ring; + + snd_pcm_sframes_t last_avail; +}; + +static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device); +static void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self); +static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name); +static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, ALCboolean, reset) +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 ClockLatency ALCcaptureAlsa_getClockLatency(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) +{ + new (self) ALCcaptureAlsa{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCcaptureAlsa, ALCbackend, self); + + self->pcmHandle = NULL; + self->buffer = NULL; + self->ring = NULL; +} + +void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self) +{ + if(self->pcmHandle) + snd_pcm_close(self->pcmHandle); + self->pcmHandle = NULL; + + al_free(self->buffer); + self->buffer = NULL; + + ll_ringbuffer_free(self->ring); + self->ring = NULL; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCcaptureAlsa(); +} + + +static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + const char *driver = NULL; + snd_pcm_hw_params_t *hp; + snd_pcm_uframes_t bufferSizeInFrames; + snd_pcm_uframes_t periodSizeInFrames; + ALboolean needring = AL_FALSE; + snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN; + const char *funcerr; + int err; + + if(name) + { + const DevMap *iter; + + if(VECTOR_SIZE(CaptureDevices) == 0) + probe_devices(SND_PCM_STREAM_CAPTURE, &CaptureDevices); + +#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, name) == 0) + VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); +#undef MATCH_NAME + if(iter == VECTOR_END(CaptureDevices)) + return ALC_INVALID_VALUE; + driver = alstr_get_cstr(iter->device_name); + } + else + { + name = alsaDevice; + driver = GetConfigValue(NULL, "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) + { + ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err)); + return ALC_INVALID_VALUE; + } + + /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */ + snd_config_update_free_global(); + + switch(device->FmtType) + { + case DevFmtByte: + format = SND_PCM_FORMAT_S8; + break; + case DevFmtUByte: + format = SND_PCM_FORMAT_U8; + break; + case DevFmtShort: + format = SND_PCM_FORMAT_S16; + break; + case DevFmtUShort: + format = SND_PCM_FORMAT_U16; + break; + case DevFmtInt: + format = SND_PCM_FORMAT_S32; + break; + case DevFmtUInt: + format = SND_PCM_FORMAT_U32; + break; + case DevFmtFloat: + format = SND_PCM_FORMAT_FLOAT; + break; + } + + funcerr = NULL; + bufferSizeInFrames = maxu(device->UpdateSize*device->NumUpdates, + 100*device->Frequency/1000); + periodSizeInFrames = minu(bufferSizeInFrames, 25*device->Frequency/1000); + + snd_pcm_hw_params_malloc(&hp); +#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error + CHECK(snd_pcm_hw_params_any(self->pcmHandle, hp)); + /* set interleaved access */ + CHECK(snd_pcm_hw_params_set_access(self->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); + /* set format (implicitly sets sample bits) */ + CHECK(snd_pcm_hw_params_set_format(self->pcmHandle, hp, format)); + /* set channels (implicitly sets frame bits) */ + CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder))); + /* set rate (implicitly constrains period/buffer parameters) */ + CHECK(snd_pcm_hw_params_set_rate(self->pcmHandle, hp, device->Frequency, 0)); + /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ + if(snd_pcm_hw_params_set_buffer_size_min(self->pcmHandle, hp, &bufferSizeInFrames) < 0) + { + TRACE("Buffer too large, using intermediate ring buffer\n"); + needring = AL_TRUE; + CHECK(snd_pcm_hw_params_set_buffer_size_near(self->pcmHandle, hp, &bufferSizeInFrames)); + } + /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ + CHECK(snd_pcm_hw_params_set_period_size_near(self->pcmHandle, hp, &periodSizeInFrames, NULL)); + /* install and prepare hardware configuration */ + CHECK(snd_pcm_hw_params(self->pcmHandle, hp)); + /* retrieve configuration info */ + CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL)); +#undef CHECK + snd_pcm_hw_params_free(hp); + hp = NULL; + + if(needring) + { + self->ring = ll_ringbuffer_create( + device->UpdateSize*device->NumUpdates, + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), + false + ); + if(!self->ring) + { + ERR("ring buffer create failed\n"); + goto error2; + } + } + + alstr_copy_cstr(&device->DeviceName, name); + + return ALC_NO_ERROR; + +error: + ERR("%s failed: %s\n", funcerr, snd_strerror(err)); + if(hp) snd_pcm_hw_params_free(hp); + +error2: + ll_ringbuffer_free(self->ring); + self->ring = NULL; + snd_pcm_close(self->pcmHandle); + self->pcmHandle = NULL; + + return ALC_INVALID_VALUE; +} + +static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self) +{ + int err = snd_pcm_prepare(self->pcmHandle); + if(err < 0) + ERR("prepare failed: %s\n", snd_strerror(err)); + else + { + err = snd_pcm_start(self->pcmHandle); + if(err < 0) + ERR("start failed: %s\n", snd_strerror(err)); + } + if(err < 0) + { + aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, "Capture state failure: %s", + snd_strerror(err)); + return ALC_FALSE; + } + + self->doCapture = AL_TRUE; + return ALC_TRUE; +} + +static void ALCcaptureAlsa_stop(ALCcaptureAlsa *self) +{ + ALCuint avail; + int err; + + /* OpenAL requires access to unread audio after stopping, but ALSA's + * snd_pcm_drain is unreliable and snd_pcm_drop drops it. Capture what's + * available now so it'll be available later after the drop. */ + avail = ALCcaptureAlsa_availableSamples(self); + if(!self->ring && avail > 0) + { + /* The ring buffer implicitly captures when checking availability. + * Direct access needs to explicitly capture it into temp storage. */ + ALsizei size; + void *ptr; + + size = snd_pcm_frames_to_bytes(self->pcmHandle, avail); + ptr = al_malloc(16, size); + if(ptr) + { + ALCcaptureAlsa_captureSamples(self, ptr, avail); + al_free(self->buffer); + self->buffer = ptr; + self->size = size; + } + } + err = snd_pcm_drop(self->pcmHandle); + if(err < 0) + ERR("drop failed: %s\n", snd_strerror(err)); + self->doCapture = AL_FALSE; +} + +static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALCuint samples) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + + if(self->ring) + { + ll_ringbuffer_read(self->ring, static_cast(buffer), samples); + return ALC_NO_ERROR; + } + + self->last_avail -= samples; + while(ATOMIC_LOAD(&device->Connected, almemory_order_acquire) && samples > 0) + { + snd_pcm_sframes_t amt = 0; + + if(self->size > 0) + { + /* First get any data stored from the last stop */ + amt = snd_pcm_bytes_to_frames(self->pcmHandle, self->size); + if((snd_pcm_uframes_t)amt > samples) amt = samples; + + amt = snd_pcm_frames_to_bytes(self->pcmHandle, amt); + memcpy(buffer, self->buffer, amt); + + if(self->size > amt) + { + memmove(self->buffer, static_cast(self->buffer)+amt, self->size - amt); + self->size -= amt; + } + else + { + al_free(self->buffer); + self->buffer = NULL; + self->size = 0; + } + amt = snd_pcm_bytes_to_frames(self->pcmHandle, amt); + } + else if(self->doCapture) + amt = snd_pcm_readi(self->pcmHandle, buffer, samples); + if(amt < 0) + { + ERR("read error: %s\n", snd_strerror(amt)); + + if(amt == -EAGAIN) + continue; + if((amt=snd_pcm_recover(self->pcmHandle, amt, 1)) >= 0) + { + amt = snd_pcm_start(self->pcmHandle); + if(amt >= 0) + amt = snd_pcm_avail_update(self->pcmHandle); + } + if(amt < 0) + { + ERR("restore error: %s\n", snd_strerror(amt)); + aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(amt)); + break; + } + /* If the amount available is less than what's asked, we lost it + * during recovery. So just give silence instead. */ + if((snd_pcm_uframes_t)amt < samples) + break; + continue; + } + + buffer = (ALbyte*)buffer + amt; + samples -= amt; + } + if(samples > 0) + memset(buffer, ((device->FmtType == DevFmtUByte) ? 0x80 : 0), + snd_pcm_frames_to_bytes(self->pcmHandle, samples)); + + return ALC_NO_ERROR; +} + +static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + snd_pcm_sframes_t avail = 0; + + if(ATOMIC_LOAD(&device->Connected, almemory_order_acquire) && self->doCapture) + avail = snd_pcm_avail_update(self->pcmHandle); + if(avail < 0) + { + ERR("avail update failed: %s\n", snd_strerror(avail)); + + if((avail=snd_pcm_recover(self->pcmHandle, avail, 1)) >= 0) + { + if(self->doCapture) + avail = snd_pcm_start(self->pcmHandle); + if(avail >= 0) + avail = snd_pcm_avail_update(self->pcmHandle); + } + if(avail < 0) + { + ERR("restore error: %s\n", snd_strerror(avail)); + aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(avail)); + } + } + + if(!self->ring) + { + if(avail < 0) avail = 0; + avail += snd_pcm_bytes_to_frames(self->pcmHandle, self->size); + if(avail > self->last_avail) self->last_avail = avail; + return self->last_avail; + } + + while(avail > 0) + { + ll_ringbuffer_data_t vec[2]; + snd_pcm_sframes_t amt; + + ll_ringbuffer_get_write_vector(self->ring, vec); + if(vec[0].len == 0) break; + + amt = (vec[0].len < (snd_pcm_uframes_t)avail) ? + vec[0].len : (snd_pcm_uframes_t)avail; + amt = snd_pcm_readi(self->pcmHandle, vec[0].buf, amt); + if(amt < 0) + { + ERR("read error: %s\n", snd_strerror(amt)); + + if(amt == -EAGAIN) + continue; + if((amt=snd_pcm_recover(self->pcmHandle, amt, 1)) >= 0) + { + if(self->doCapture) + amt = snd_pcm_start(self->pcmHandle); + if(amt >= 0) + amt = snd_pcm_avail_update(self->pcmHandle); + } + if(amt < 0) + { + ERR("restore error: %s\n", snd_strerror(amt)); + aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(amt)); + break; + } + avail = amt; + continue; + } + + ll_ringbuffer_write_advance(self->ring, amt); + avail -= amt; + } + + return ll_ringbuffer_read_space(self->ring); +} + +static ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + snd_pcm_sframes_t delay = 0; + ClockLatency ret; + int err; + + ALCcaptureAlsa_lock(self); + ret.ClockTime = GetDeviceClockTime(device); + if((err=snd_pcm_delay(self->pcmHandle, &delay)) < 0) + { + ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); + delay = 0; + } + if(delay < 0) delay = 0; + ret.Latency = delay * DEVICE_CLOCK_RES / device->Frequency; + ALCcaptureAlsa_unlock(self); + + return ret; +} + + +struct ALCalsaBackendFactory final : public ALCbackendFactory { + ALCalsaBackendFactory() noexcept; +}; + +static ALCboolean ALCalsaBackendFactory_init(ALCalsaBackendFactory* UNUSED(self)) +{ + VECTOR_INIT(PlaybackDevices); + VECTOR_INIT(CaptureDevices); + + if(!alsa_load()) + return ALC_FALSE; + return ALC_TRUE; +} + +static void ALCalsaBackendFactory_deinit(ALCalsaBackendFactory* UNUSED(self)) +{ + clear_devlist(&PlaybackDevices); + VECTOR_DEINIT(PlaybackDevices); + + clear_devlist(&CaptureDevices); + VECTOR_DEINIT(CaptureDevices); + +#ifdef HAVE_DYNLOAD + if(alsa_handle) + CloseLib(alsa_handle); + alsa_handle = NULL; +#endif +} + +static ALCboolean ALCalsaBackendFactory_querySupport(ALCalsaBackendFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Playback || type == ALCbackend_Capture) + return ALC_TRUE; + return ALC_FALSE; +} + +static void ALCalsaBackendFactory_probe(ALCalsaBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +{ + switch(type) + { +#define APPEND_OUTNAME(i) do { \ + if(!alstr_empty((i)->name)) \ + alstr_append_range(outnames, VECTOR_BEGIN((i)->name), \ + VECTOR_END((i)->name)+1); \ +} while(0) + case ALL_DEVICE_PROBE: + probe_devices(SND_PCM_STREAM_PLAYBACK, &PlaybackDevices); + VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_OUTNAME); + break; + + case CAPTURE_DEVICE_PROBE: + probe_devices(SND_PCM_STREAM_CAPTURE, &CaptureDevices); + VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_OUTNAME); + break; +#undef APPEND_OUTNAME + } +} + +static ALCbackend* ALCalsaBackendFactory_createBackend(ALCalsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCplaybackAlsa *backend; + NEW_OBJ(backend, ALCplaybackAlsa)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + if(type == ALCbackend_Capture) + { + ALCcaptureAlsa *backend; + NEW_OBJ(backend, ALCcaptureAlsa)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + + return NULL; +} + +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCalsaBackendFactory); + + +ALCalsaBackendFactory::ALCalsaBackendFactory() noexcept + : ALCbackendFactory{GET_VTABLE2(ALCalsaBackendFactory, ALCbackendFactory)} +{ +} + +ALCbackendFactory *ALCalsaBackendFactory_getFactory(void) +{ + static ALCalsaBackendFactory factory{}; + return STATIC_CAST(ALCbackendFactory, &factory); +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cb56c54..826b06e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1043,7 +1043,7 @@ IF(ALSA_FOUND) IF(ALSOFT_BACKEND_ALSA) SET(HAVE_ALSA 1) SET(BACKENDS "${BACKENDS} ALSA${IS_LINKED},") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/alsa.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/alsa.cpp) ADD_BACKEND_LIBS(${ALSA_LIBRARIES}) SET(INC_PATHS ${INC_PATHS} ${ALSA_INCLUDE_DIRS}) ENDIF() -- cgit v1.2.3 From 09ea1d58f63ad3fe248b1e59c0a3634447ce672d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Nov 2018 01:39:42 -0800 Subject: Convert the backend base to C++ --- Alc/ALc.c | 5 +++ Alc/backends/base.c | 84 --------------------------------------------------- Alc/backends/base.cpp | 79 ++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 4 files changed, 85 insertions(+), 85 deletions(-) delete mode 100644 Alc/backends/base.c create mode 100644 Alc/backends/base.cpp diff --git a/Alc/ALc.c b/Alc/ALc.c index 4e2402ca..cc51a3d7 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1589,6 +1589,11 @@ extern inline void UnlockBufferList(ALCdevice *device); extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type); extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); +extern inline ALuint64 GetDeviceClockTime(ALCdevice *device); +extern inline void ALCdevice_Lock(ALCdevice *device); +extern inline void ALCdevice_Unlock(ALCdevice *device); +extern inline ClockLatency GetClockLatency(ALCdevice *device); + extern inline void alstr_reset(al_string *str); extern inline size_t alstr_length(const_al_string str); extern inline ALboolean alstr_empty(const_al_string str); diff --git a/Alc/backends/base.c b/Alc/backends/base.c deleted file mode 100644 index 9d8614b1..00000000 --- a/Alc/backends/base.c +++ /dev/null @@ -1,84 +0,0 @@ - -#include "config.h" - -#include - -#include "alMain.h" -#include "alu.h" - -#include "backends/base.h" - - -extern inline ALuint64 GetDeviceClockTime(ALCdevice *device); -extern inline void ALCdevice_Lock(ALCdevice *device); -extern inline void ALCdevice_Unlock(ALCdevice *device); -extern inline ClockLatency GetClockLatency(ALCdevice *device); - -/* Base ALCbackend method implementations. */ -void ALCbackend_Construct(ALCbackend *self, ALCdevice *device) -{ - int ret = almtx_init(&self->mMutex, almtx_recursive); - assert(ret == althrd_success); - self->mDevice = device; -} - -void ALCbackend_Destruct(ALCbackend *self) -{ - almtx_destroy(&self->mMutex); -} - -ALCboolean ALCbackend_reset(ALCbackend* UNUSED(self)) -{ - return ALC_FALSE; -} - -ALCenum ALCbackend_captureSamples(ALCbackend* UNUSED(self), void* UNUSED(buffer), ALCuint UNUSED(samples)) -{ - return ALC_INVALID_DEVICE; -} - -ALCuint ALCbackend_availableSamples(ALCbackend* UNUSED(self)) -{ - return 0; -} - -ClockLatency ALCbackend_getClockLatency(ALCbackend *self) -{ - ALCdevice *device = self->mDevice; - ALuint refcount; - ClockLatency ret; - - do { - while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) - althrd_yield(); - ret.ClockTime = GetDeviceClockTime(device); - ATOMIC_THREAD_FENCE(almemory_order_acquire); - } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); - - /* NOTE: The device will generally have about all but one periods filled at - * any given time during playback. Without a more accurate measurement from - * the output, this is an okay approximation. - */ - ret.Latency = device->UpdateSize * DEVICE_CLOCK_RES / device->Frequency * - maxu(device->NumUpdates-1, 1); - - return ret; -} - -void ALCbackend_lock(ALCbackend *self) -{ - int ret = almtx_lock(&self->mMutex); - assert(ret == althrd_success); -} - -void ALCbackend_unlock(ALCbackend *self) -{ - int ret = almtx_unlock(&self->mMutex); - assert(ret == althrd_success); -} - - -/* Base ALCbackendFactory method implementations. */ -void ALCbackendFactory_deinit(ALCbackendFactory* UNUSED(self)) -{ -} diff --git a/Alc/backends/base.cpp b/Alc/backends/base.cpp new file mode 100644 index 00000000..8173f554 --- /dev/null +++ b/Alc/backends/base.cpp @@ -0,0 +1,79 @@ + +#include "config.h" + +#include + +#include "alMain.h" +#include "alu.h" + +#include "backends/base.h" + + +/* Base ALCbackend method implementations. */ +void ALCbackend_Construct(ALCbackend *self, ALCdevice *device) +{ + int ret = almtx_init(&self->mMutex, almtx_recursive); + assert(ret == althrd_success); + self->mDevice = device; +} + +void ALCbackend_Destruct(ALCbackend *self) +{ + almtx_destroy(&self->mMutex); +} + +ALCboolean ALCbackend_reset(ALCbackend* UNUSED(self)) +{ + return ALC_FALSE; +} + +ALCenum ALCbackend_captureSamples(ALCbackend* UNUSED(self), void* UNUSED(buffer), ALCuint UNUSED(samples)) +{ + return ALC_INVALID_DEVICE; +} + +ALCuint ALCbackend_availableSamples(ALCbackend* UNUSED(self)) +{ + return 0; +} + +ClockLatency ALCbackend_getClockLatency(ALCbackend *self) +{ + ALCdevice *device = self->mDevice; + ALuint refcount; + ClockLatency ret; + + do { + while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) + althrd_yield(); + ret.ClockTime = GetDeviceClockTime(device); + ATOMIC_THREAD_FENCE(almemory_order_acquire); + } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); + + /* NOTE: The device will generally have about all but one periods filled at + * any given time during playback. Without a more accurate measurement from + * the output, this is an okay approximation. + */ + ret.Latency = device->UpdateSize * DEVICE_CLOCK_RES / device->Frequency * + maxu(device->NumUpdates-1, 1); + + return ret; +} + +void ALCbackend_lock(ALCbackend *self) +{ + int ret = almtx_lock(&self->mMutex); + assert(ret == althrd_success); +} + +void ALCbackend_unlock(ALCbackend *self) +{ + int ret = almtx_unlock(&self->mMutex); + assert(ret == althrd_success); +} + + +/* Base ALCbackendFactory method implementations. */ +void ALCbackendFactory_deinit(ALCbackendFactory* UNUSED(self)) +{ +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 826b06e6..0ff8f2b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1028,7 +1028,7 @@ ENDIF() SET(BACKENDS "") SET(ALC_OBJS ${ALC_OBJS} - Alc/backends/base.c + Alc/backends/base.cpp Alc/backends/base.h # Default backends, always available Alc/backends/loopback.cpp -- cgit v1.2.3 From 0ff349a714eac9bc0cf6cbdaafbddcec79f2442e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Nov 2018 01:56:34 -0800 Subject: Convert the QSA backend to C++ This may very well not work, since there's no testing and my IDE is not able to show real problems over the incompatibilities with ALSA headers. --- Alc/backends/qsa.c | 1068 ------------------------------------------------- Alc/backends/qsa.cpp | 1078 ++++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 1079 insertions(+), 1069 deletions(-) delete mode 100644 Alc/backends/qsa.c create mode 100644 Alc/backends/qsa.cpp diff --git a/Alc/backends/qsa.c b/Alc/backends/qsa.c deleted file mode 100644 index 81645096..00000000 --- a/Alc/backends/qsa.c +++ /dev/null @@ -1,1068 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2011-2013 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "alMain.h" -#include "alu.h" -#include "threads.h" - -#include "backends/base.h" - - -typedef struct { - snd_pcm_t* pcmHandle; - int audio_fd; - - snd_pcm_channel_setup_t csetup; - snd_pcm_channel_params_t cparams; - - ALvoid* buffer; - ALsizei size; - - ATOMIC(ALenum) killNow; - althrd_t thread; -} qsa_data; - -typedef struct { - ALCchar* name; - int card; - int dev; -} DevMap; -TYPEDEF_VECTOR(DevMap, vector_DevMap) - -static vector_DevMap DeviceNameMap; -static vector_DevMap CaptureNameMap; - -static const ALCchar qsaDevice[] = "QSA Default"; - -static const struct { - int32_t format; -} formatlist[] = { - {SND_PCM_SFMT_FLOAT_LE}, - {SND_PCM_SFMT_S32_LE}, - {SND_PCM_SFMT_U32_LE}, - {SND_PCM_SFMT_S16_LE}, - {SND_PCM_SFMT_U16_LE}, - {SND_PCM_SFMT_S8}, - {SND_PCM_SFMT_U8}, - {0}, -}; - -static const struct { - int32_t rate; -} ratelist[] = { - {192000}, - {176400}, - {96000}, - {88200}, - {48000}, - {44100}, - {32000}, - {24000}, - {22050}, - {16000}, - {12000}, - {11025}, - {8000}, - {0}, -}; - -static const struct { - int32_t channels; -} channellist[] = { - {8}, - {7}, - {6}, - {4}, - {2}, - {1}, - {0}, -}; - -static void deviceList(int type, vector_DevMap *devmap) -{ - snd_ctl_t* handle; - snd_pcm_info_t pcminfo; - int max_cards, card, err, dev; - DevMap entry; - char name[1024]; - struct snd_ctl_hw_info info; - - max_cards = snd_cards(); - if(max_cards < 0) - return; - -#define FREE_NAME(iter) free((iter)->name) - VECTOR_FOR_EACH(DevMap, *devmap, FREE_NAME); -#undef FREE_NAME - VECTOR_RESIZE(*devmap, 0, max_cards+1); - - entry.name = strdup(qsaDevice); - entry.card = 0; - entry.dev = 0; - VECTOR_PUSH_BACK(*devmap, entry); - - for(card = 0;card < max_cards;card++) - { - if((err=snd_ctl_open(&handle, card)) < 0) - continue; - - if((err=snd_ctl_hw_info(handle, &info)) < 0) - { - snd_ctl_close(handle); - continue; - } - - for(dev = 0;dev < (int)info.pcmdevs;dev++) - { - if((err=snd_ctl_pcm_info(handle, dev, &pcminfo)) < 0) - continue; - - if((type==SND_PCM_CHANNEL_PLAYBACK && (pcminfo.flags&SND_PCM_INFO_PLAYBACK)) || - (type==SND_PCM_CHANNEL_CAPTURE && (pcminfo.flags&SND_PCM_INFO_CAPTURE))) - { - snprintf(name, sizeof(name), "%s [%s] (hw:%d,%d)", info.name, pcminfo.name, card, dev); - entry.name = strdup(name); - entry.card = card; - entry.dev = dev; - - VECTOR_PUSH_BACK(*devmap, entry); - TRACE("Got device \"%s\", card %d, dev %d\n", name, card, dev); - } - } - snd_ctl_close(handle); - } -} - - -/* Wrappers to use an old-style backend with the new interface. */ -typedef struct PlaybackWrapper { - DERIVE_FROM_TYPE(ALCbackend); - qsa_data *ExtraData; -} PlaybackWrapper; - -static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device); -static void PlaybackWrapper_Destruct(PlaybackWrapper *self); -static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name); -static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self); -static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self); -static void PlaybackWrapper_stop(PlaybackWrapper *self); -static DECLARE_FORWARD2(PlaybackWrapper, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, lock) -static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(PlaybackWrapper) -DEFINE_ALCBACKEND_VTABLE(PlaybackWrapper); - - -FORCE_ALIGN static int qsa_proc_playback(void *ptr) -{ - PlaybackWrapper *self = ptr; - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - qsa_data *data = self->ExtraData; - snd_pcm_channel_status_t status; - struct sched_param param; - struct timeval timeout; - char* write_ptr; - fd_set wfds; - ALint len; - int sret; - - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - /* Increase default 10 priority to 11 to avoid jerky sound */ - SchedGet(0, 0, ¶m); - param.sched_priority=param.sched_curpriority+1; - SchedSet(0, 0, SCHED_NOCHANGE, ¶m); - - const ALint frame_size = FrameSizeFromDevFmt( - device->FmtChans, device->FmtType, device->AmbiOrder - ); - - V0(device->Backend,lock)(); - while(!ATOMIC_LOAD(&data->killNow, almemory_order_acquire)) - { - FD_ZERO(&wfds); - FD_SET(data->audio_fd, &wfds); - timeout.tv_sec=2; - timeout.tv_usec=0; - - /* Select also works like time slice to OS */ - V0(device->Backend,unlock)(); - sret = select(data->audio_fd+1, NULL, &wfds, NULL, &timeout); - V0(device->Backend,lock)(); - if(sret == -1) - { - ERR("select error: %s\n", strerror(errno)); - aluHandleDisconnect(device, "Failed waiting for playback buffer: %s", strerror(errno)); - break; - } - if(sret == 0) - { - ERR("select timeout\n"); - continue; - } - - len = data->size; - write_ptr = data->buffer; - aluMixData(device, write_ptr, len/frame_size); - while(len>0 && !ATOMIC_LOAD(&data->killNow, almemory_order_acquire)) - { - int wrote = snd_pcm_plugin_write(data->pcmHandle, write_ptr, len); - if(wrote <= 0) - { - if(errno==EAGAIN || errno==EWOULDBLOCK) - continue; - - memset(&status, 0, sizeof(status)); - status.channel = SND_PCM_CHANNEL_PLAYBACK; - - snd_pcm_plugin_status(data->pcmHandle, &status); - - /* we need to reinitialize the sound channel if we've underrun the buffer */ - if(status.status == SND_PCM_STATUS_UNDERRUN || - status.status == SND_PCM_STATUS_READY) - { - if(snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK) < 0) - { - aluHandleDisconnect(device, "Playback recovery failed"); - break; - } - } - } - else - { - write_ptr += wrote; - len -= wrote; - } - } - } - V0(device->Backend,unlock)(); - - return 0; -} - -/************/ -/* Playback */ -/************/ - -static ALCenum qsa_open_playback(PlaybackWrapper *self, const ALCchar* deviceName) -{ - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - qsa_data *data; - int card, dev; - int status; - - data = (qsa_data*)calloc(1, sizeof(qsa_data)); - if(data == NULL) - return ALC_OUT_OF_MEMORY; - ATOMIC_INIT(&data->killNow, AL_TRUE); - - if(!deviceName) - deviceName = qsaDevice; - - if(strcmp(deviceName, qsaDevice) == 0) - status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_PLAYBACK); - else - { - const DevMap *iter; - - if(VECTOR_SIZE(DeviceNameMap) == 0) - deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap); - -#define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0) - VECTOR_FIND_IF(iter, const DevMap, DeviceNameMap, MATCH_DEVNAME); -#undef MATCH_DEVNAME - if(iter == VECTOR_END(DeviceNameMap)) - { - free(data); - return ALC_INVALID_DEVICE; - } - - status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_PLAYBACK); - } - - if(status < 0) - { - free(data); - return ALC_INVALID_DEVICE; - } - - data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK); - if(data->audio_fd < 0) - { - snd_pcm_close(data->pcmHandle); - free(data); - return ALC_INVALID_DEVICE; - } - - alstr_copy_cstr(&device->DeviceName, deviceName); - self->ExtraData = data; - - return ALC_NO_ERROR; -} - -static void qsa_close_playback(PlaybackWrapper *self) -{ - qsa_data *data = self->ExtraData; - - if (data->buffer!=NULL) - { - free(data->buffer); - data->buffer=NULL; - } - - snd_pcm_close(data->pcmHandle); - free(data); - - self->ExtraData = NULL; -} - -static ALCboolean qsa_reset_playback(PlaybackWrapper *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - qsa_data *data = self->ExtraData; - int32_t format=-1; - - switch(device->FmtType) - { - case DevFmtByte: - format=SND_PCM_SFMT_S8; - break; - case DevFmtUByte: - format=SND_PCM_SFMT_U8; - break; - case DevFmtShort: - format=SND_PCM_SFMT_S16_LE; - break; - case DevFmtUShort: - format=SND_PCM_SFMT_U16_LE; - break; - case DevFmtInt: - format=SND_PCM_SFMT_S32_LE; - break; - case DevFmtUInt: - format=SND_PCM_SFMT_U32_LE; - break; - case DevFmtFloat: - format=SND_PCM_SFMT_FLOAT_LE; - break; - } - - /* we actually don't want to block on writes */ - snd_pcm_nonblock_mode(data->pcmHandle, 1); - /* Disable mmap to control data transfer to the audio device */ - snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_MMAP); - snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_BUFFER_PARTIAL_BLOCKS); - - // configure a sound channel - memset(&data->cparams, 0, sizeof(data->cparams)); - data->cparams.channel=SND_PCM_CHANNEL_PLAYBACK; - data->cparams.mode=SND_PCM_MODE_BLOCK; - data->cparams.start_mode=SND_PCM_START_FULL; - data->cparams.stop_mode=SND_PCM_STOP_STOP; - - data->cparams.buf.block.frag_size=device->UpdateSize * - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - data->cparams.buf.block.frags_max=device->NumUpdates; - data->cparams.buf.block.frags_min=device->NumUpdates; - - data->cparams.format.interleave=1; - data->cparams.format.rate=device->Frequency; - data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - data->cparams.format.format=format; - - if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0) - { - int original_rate=data->cparams.format.rate; - int original_voices=data->cparams.format.voices; - int original_format=data->cparams.format.format; - int it; - int jt; - - for (it=0; it<1; it++) - { - /* Check for second pass */ - if (it==1) - { - original_rate=ratelist[0].rate; - original_voices=channellist[0].channels; - original_format=formatlist[0].format; - } - - do { - /* At first downgrade sample format */ - jt=0; - do { - if (formatlist[jt].format==data->cparams.format.format) - { - data->cparams.format.format=formatlist[jt+1].format; - break; - } - if (formatlist[jt].format==0) - { - data->cparams.format.format=0; - break; - } - jt++; - } while(1); - - if (data->cparams.format.format==0) - { - data->cparams.format.format=original_format; - - /* At secod downgrade sample rate */ - jt=0; - do { - if (ratelist[jt].rate==data->cparams.format.rate) - { - data->cparams.format.rate=ratelist[jt+1].rate; - break; - } - if (ratelist[jt].rate==0) - { - data->cparams.format.rate=0; - break; - } - jt++; - } while(1); - - if (data->cparams.format.rate==0) - { - data->cparams.format.rate=original_rate; - data->cparams.format.format=original_format; - - /* At third downgrade channels number */ - jt=0; - do { - if(channellist[jt].channels==data->cparams.format.voices) - { - data->cparams.format.voices=channellist[jt+1].channels; - break; - } - if (channellist[jt].channels==0) - { - data->cparams.format.voices=0; - break; - } - jt++; - } while(1); - } - - if (data->cparams.format.voices==0) - { - break; - } - } - - data->cparams.buf.block.frag_size=device->UpdateSize* - data->cparams.format.voices* - snd_pcm_format_width(data->cparams.format.format)/8; - data->cparams.buf.block.frags_max=device->NumUpdates; - data->cparams.buf.block.frags_min=device->NumUpdates; - if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0) - { - continue; - } - else - { - break; - } - } while(1); - - if (data->cparams.format.voices!=0) - { - break; - } - } - - if (data->cparams.format.voices==0) - { - return ALC_FALSE; - } - } - - if ((snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK))<0) - { - return ALC_FALSE; - } - - memset(&data->csetup, 0, sizeof(data->csetup)); - data->csetup.channel=SND_PCM_CHANNEL_PLAYBACK; - if (snd_pcm_plugin_setup(data->pcmHandle, &data->csetup)<0) - { - return ALC_FALSE; - } - - /* now fill back to the our AL device */ - device->Frequency=data->cparams.format.rate; - - switch (data->cparams.format.voices) - { - case 1: - device->FmtChans=DevFmtMono; - break; - case 2: - device->FmtChans=DevFmtStereo; - break; - case 4: - device->FmtChans=DevFmtQuad; - break; - case 6: - device->FmtChans=DevFmtX51; - break; - case 7: - device->FmtChans=DevFmtX61; - break; - case 8: - device->FmtChans=DevFmtX71; - break; - default: - device->FmtChans=DevFmtMono; - break; - } - - switch (data->cparams.format.format) - { - case SND_PCM_SFMT_S8: - device->FmtType=DevFmtByte; - break; - case SND_PCM_SFMT_U8: - device->FmtType=DevFmtUByte; - break; - case SND_PCM_SFMT_S16_LE: - device->FmtType=DevFmtShort; - break; - case SND_PCM_SFMT_U16_LE: - device->FmtType=DevFmtUShort; - break; - case SND_PCM_SFMT_S32_LE: - device->FmtType=DevFmtInt; - break; - case SND_PCM_SFMT_U32_LE: - device->FmtType=DevFmtUInt; - break; - case SND_PCM_SFMT_FLOAT_LE: - device->FmtType=DevFmtFloat; - break; - default: - device->FmtType=DevFmtShort; - break; - } - - SetDefaultChannelOrder(device); - - device->UpdateSize=data->csetup.buf.block.frag_size/ - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - device->NumUpdates=data->csetup.buf.block.frags; - - data->size=data->csetup.buf.block.frag_size; - data->buffer=malloc(data->size); - if (!data->buffer) - { - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static ALCboolean qsa_start_playback(PlaybackWrapper *self) -{ - qsa_data *data = self->ExtraData; - - ATOMIC_STORE(&data->killNow, AL_FALSE, almemory_order_release); - if(althrd_create(&data->thread, qsa_proc_playback, self) != althrd_success) - return ALC_FALSE; - - return ALC_TRUE; -} - -static void qsa_stop_playback(PlaybackWrapper *self) -{ - qsa_data *data = self->ExtraData; - int res; - - if(ATOMIC_EXCHANGE(&data->killNow, AL_TRUE, almemory_order_acq_rel)) - return; - althrd_join(data->thread, &res); -} - - -static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(PlaybackWrapper, ALCbackend, self); - - self->ExtraData = NULL; -} - -static void PlaybackWrapper_Destruct(PlaybackWrapper *self) -{ - if(self->ExtraData) - qsa_close_playback(self); - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - -static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name) -{ - return qsa_open_playback(self, name); -} - -static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self) -{ - return qsa_reset_playback(self); -} - -static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self) -{ - return qsa_start_playback(self); -} - -static void PlaybackWrapper_stop(PlaybackWrapper *self) -{ - qsa_stop_playback(self); -} - - - -/***********/ -/* Capture */ -/***********/ - -typedef struct CaptureWrapper { - DERIVE_FROM_TYPE(ALCbackend); - qsa_data *ExtraData; -} CaptureWrapper; - -static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device); -static void CaptureWrapper_Destruct(CaptureWrapper *self); -static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name); -static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ALCboolean, reset) -static ALCboolean CaptureWrapper_start(CaptureWrapper *self); -static void CaptureWrapper_stop(CaptureWrapper *self); -static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples); -static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self); -static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, lock) -static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(CaptureWrapper) -DEFINE_ALCBACKEND_VTABLE(CaptureWrapper); - - -static ALCenum qsa_open_capture(CaptureWrapper *self, const ALCchar *deviceName) -{ - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - qsa_data *data; - int card, dev; - int format=-1; - int status; - - data=(qsa_data*)calloc(1, sizeof(qsa_data)); - if (data==NULL) - { - return ALC_OUT_OF_MEMORY; - } - - if(!deviceName) - deviceName = qsaDevice; - - if(strcmp(deviceName, qsaDevice) == 0) - status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_CAPTURE); - else - { - const DevMap *iter; - - if(VECTOR_SIZE(CaptureNameMap) == 0) - deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap); - -#define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0) - VECTOR_FIND_IF(iter, const DevMap, CaptureNameMap, MATCH_DEVNAME); -#undef MATCH_DEVNAME - if(iter == VECTOR_END(CaptureNameMap)) - { - free(data); - return ALC_INVALID_DEVICE; - } - - status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_CAPTURE); - } - - if(status < 0) - { - free(data); - return ALC_INVALID_DEVICE; - } - - data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE); - if(data->audio_fd < 0) - { - snd_pcm_close(data->pcmHandle); - free(data); - return ALC_INVALID_DEVICE; - } - - alstr_copy_cstr(&device->DeviceName, deviceName); - self->ExtraData = data; - - switch (device->FmtType) - { - case DevFmtByte: - format=SND_PCM_SFMT_S8; - break; - case DevFmtUByte: - format=SND_PCM_SFMT_U8; - break; - case DevFmtShort: - format=SND_PCM_SFMT_S16_LE; - break; - case DevFmtUShort: - format=SND_PCM_SFMT_U16_LE; - break; - case DevFmtInt: - format=SND_PCM_SFMT_S32_LE; - break; - case DevFmtUInt: - format=SND_PCM_SFMT_U32_LE; - break; - case DevFmtFloat: - format=SND_PCM_SFMT_FLOAT_LE; - break; - } - - /* we actually don't want to block on reads */ - snd_pcm_nonblock_mode(data->pcmHandle, 1); - /* Disable mmap to control data transfer to the audio device */ - snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_MMAP); - - /* configure a sound channel */ - memset(&data->cparams, 0, sizeof(data->cparams)); - data->cparams.mode=SND_PCM_MODE_BLOCK; - data->cparams.channel=SND_PCM_CHANNEL_CAPTURE; - data->cparams.start_mode=SND_PCM_START_GO; - data->cparams.stop_mode=SND_PCM_STOP_STOP; - - data->cparams.buf.block.frag_size=device->UpdateSize* - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - data->cparams.buf.block.frags_max=device->NumUpdates; - data->cparams.buf.block.frags_min=device->NumUpdates; - - data->cparams.format.interleave=1; - data->cparams.format.rate=device->Frequency; - data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - data->cparams.format.format=format; - - if(snd_pcm_plugin_params(data->pcmHandle, &data->cparams) < 0) - { - snd_pcm_close(data->pcmHandle); - free(data); - - return ALC_INVALID_VALUE; - } - - return ALC_NO_ERROR; -} - -static void qsa_close_capture(CaptureWrapper *self) -{ - qsa_data *data = self->ExtraData; - - if (data->pcmHandle!=NULL) - snd_pcm_close(data->pcmHandle); - - free(data); - self->ExtraData = NULL; -} - -static void qsa_start_capture(CaptureWrapper *self) -{ - qsa_data *data = self->ExtraData; - int rstatus; - - if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0) - { - ERR("capture prepare failed: %s\n", snd_strerror(rstatus)); - return; - } - - memset(&data->csetup, 0, sizeof(data->csetup)); - data->csetup.channel=SND_PCM_CHANNEL_CAPTURE; - if ((rstatus=snd_pcm_plugin_setup(data->pcmHandle, &data->csetup))<0) - { - ERR("capture setup failed: %s\n", snd_strerror(rstatus)); - return; - } - - snd_pcm_capture_go(data->pcmHandle); -} - -static void qsa_stop_capture(CaptureWrapper *self) -{ - qsa_data *data = self->ExtraData; - snd_pcm_capture_flush(data->pcmHandle); -} - -static ALCuint qsa_available_samples(CaptureWrapper *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - qsa_data *data = self->ExtraData; - snd_pcm_channel_status_t status; - ALint frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - ALint free_size; - int rstatus; - - memset(&status, 0, sizeof (status)); - status.channel=SND_PCM_CHANNEL_CAPTURE; - snd_pcm_plugin_status(data->pcmHandle, &status); - if ((status.status==SND_PCM_STATUS_OVERRUN) || - (status.status==SND_PCM_STATUS_READY)) - { - if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0) - { - ERR("capture prepare failed: %s\n", snd_strerror(rstatus)); - aluHandleDisconnect(device, "Failed capture recovery: %s", snd_strerror(rstatus)); - return 0; - } - - snd_pcm_capture_go(data->pcmHandle); - return 0; - } - - free_size=data->csetup.buf.block.frag_size*data->csetup.buf.block.frags; - free_size-=status.free; - - return free_size/frame_size; -} - -static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuint samples) -{ - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - qsa_data *data = self->ExtraData; - char* read_ptr; - snd_pcm_channel_status_t status; - fd_set rfds; - int selectret; - struct timeval timeout; - int bytes_read; - ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - ALint len=samples*frame_size; - int rstatus; - - read_ptr=buffer; - - while (len>0) - { - FD_ZERO(&rfds); - FD_SET(data->audio_fd, &rfds); - timeout.tv_sec=2; - timeout.tv_usec=0; - - /* Select also works like time slice to OS */ - bytes_read=0; - selectret=select(data->audio_fd+1, &rfds, NULL, NULL, &timeout); - switch (selectret) - { - case -1: - aluHandleDisconnect(device, "Failed to check capture samples"); - return ALC_INVALID_DEVICE; - case 0: - break; - default: - if (FD_ISSET(data->audio_fd, &rfds)) - { - bytes_read=snd_pcm_plugin_read(data->pcmHandle, read_ptr, len); - break; - } - break; - } - - if (bytes_read<=0) - { - if ((errno==EAGAIN) || (errno==EWOULDBLOCK)) - { - continue; - } - - memset(&status, 0, sizeof (status)); - status.channel=SND_PCM_CHANNEL_CAPTURE; - snd_pcm_plugin_status(data->pcmHandle, &status); - - /* we need to reinitialize the sound channel if we've overrun the buffer */ - if ((status.status==SND_PCM_STATUS_OVERRUN) || - (status.status==SND_PCM_STATUS_READY)) - { - if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0) - { - ERR("capture prepare failed: %s\n", snd_strerror(rstatus)); - aluHandleDisconnect(device, "Failed capture recovery: %s", - snd_strerror(rstatus)); - return ALC_INVALID_DEVICE; - } - snd_pcm_capture_go(data->pcmHandle); - } - } - else - { - read_ptr+=bytes_read; - len-=bytes_read; - } - } - - return ALC_NO_ERROR; -} - - -static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(CaptureWrapper, ALCbackend, self); - - self->ExtraData = NULL; -} - -static void CaptureWrapper_Destruct(CaptureWrapper *self) -{ - if(self->ExtraData) - qsa_close_capture(self); - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - -static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name) -{ - return qsa_open_capture(self, name); -} - -static ALCboolean CaptureWrapper_start(CaptureWrapper *self) -{ - qsa_start_capture(self); - return ALC_TRUE; -} - -static void CaptureWrapper_stop(CaptureWrapper *self) -{ - qsa_stop_capture(self); -} - -static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples) -{ - return qsa_capture_samples(self, buffer, samples); -} - -static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self) -{ - return qsa_available_samples(self); -} - - -typedef struct ALCqsaBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCqsaBackendFactory; -#define ALCQSABACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCqsaBackendFactory, ALCbackendFactory) } } - -static ALCboolean ALCqsaBackendFactory_init(ALCqsaBackendFactory* UNUSED(self)); -static void ALCqsaBackendFactory_deinit(ALCqsaBackendFactory* UNUSED(self)); -static ALCboolean ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory* UNUSED(self), ALCbackend_Type type); -static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames); -static ALCbackend* ALCqsaBackendFactory_createBackend(ALCqsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCqsaBackendFactory); - -static ALCboolean ALCqsaBackendFactory_init(ALCqsaBackendFactory* UNUSED(self)) -{ - return ALC_TRUE; -} - -static void ALCqsaBackendFactory_deinit(ALCqsaBackendFactory* UNUSED(self)) -{ -#define FREE_NAME(iter) free((iter)->name) - VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME); - VECTOR_DEINIT(DeviceNameMap); - - VECTOR_FOR_EACH(DevMap, CaptureNameMap, FREE_NAME); - VECTOR_DEINIT(CaptureNameMap); -#undef FREE_NAME -} - -static ALCboolean ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} - -static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) -{ - switch (type) - { -#define APPEND_OUTNAME(e) do { \ - const char *n_ = (e)->name; \ - if(n_ && n_[0]) \ - alstr_append_range(outnames, n_, n_+strlen(n_)+1); \ -} while(0) - case ALL_DEVICE_PROBE: - deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap); - VECTOR_FOR_EACH(const DevMap, DeviceNameMap, APPEND_OUTNAME); - break; - - case CAPTURE_DEVICE_PROBE: - deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap); - VECTOR_FOR_EACH(const DevMap, CaptureNameMap, APPEND_OUTNAME); - break; -#undef APPEND_OUTNAME - } -} - -static ALCbackend* ALCqsaBackendFactory_createBackend(ALCqsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - { - PlaybackWrapper *backend; - NEW_OBJ(backend, PlaybackWrapper)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - if(type == ALCbackend_Capture) - { - CaptureWrapper *backend; - NEW_OBJ(backend, CaptureWrapper)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} - -ALCbackendFactory *ALCqsaBackendFactory_getFactory(void) -{ - static ALCqsaBackendFactory factory = ALCQSABACKENDFACTORY_INITIALIZER; - return STATIC_CAST(ALCbackendFactory, &factory); -} diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp new file mode 100644 index 00000000..778e9e44 --- /dev/null +++ b/Alc/backends/qsa.cpp @@ -0,0 +1,1078 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2011-2013 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "alMain.h" +#include "alu.h" +#include "threads.h" + +#include "backends/base.h" + + +namespace { + +struct qsa_data { + snd_pcm_t* pcmHandle; + int audio_fd; + + snd_pcm_channel_setup_t csetup; + snd_pcm_channel_params_t cparams; + + ALvoid* buffer; + ALsizei size; + + ATOMIC(ALenum) killNow; + althrd_t thread; +}; + +struct DevMap { + ALCchar* name; + int card; + int dev; +}; +TYPEDEF_VECTOR(DevMap, vector_DevMap) + +vector_DevMap DeviceNameMap; +vector_DevMap CaptureNameMap; + +constexpr ALCchar qsaDevice[] = "QSA Default"; + +constexpr struct { + int32_t format; +} formatlist[] = { + {SND_PCM_SFMT_FLOAT_LE}, + {SND_PCM_SFMT_S32_LE}, + {SND_PCM_SFMT_U32_LE}, + {SND_PCM_SFMT_S16_LE}, + {SND_PCM_SFMT_U16_LE}, + {SND_PCM_SFMT_S8}, + {SND_PCM_SFMT_U8}, + {0}, +}; + +constexpr struct { + int32_t rate; +} ratelist[] = { + {192000}, + {176400}, + {96000}, + {88200}, + {48000}, + {44100}, + {32000}, + {24000}, + {22050}, + {16000}, + {12000}, + {11025}, + {8000}, + {0}, +}; + +constexpr struct { + int32_t channels; +} channellist[] = { + {8}, + {7}, + {6}, + {4}, + {2}, + {1}, + {0}, +}; + +void deviceList(int type, vector_DevMap *devmap) +{ + snd_ctl_t* handle; + snd_pcm_info_t pcminfo; + int max_cards, card, err, dev; + DevMap entry; + char name[1024]; + struct snd_ctl_hw_info info; + + max_cards = snd_cards(); + if(max_cards < 0) + return; + +#define FREE_NAME(iter) free((iter)->name) + VECTOR_FOR_EACH(DevMap, *devmap, FREE_NAME); +#undef FREE_NAME + VECTOR_RESIZE(*devmap, 0, max_cards+1); + + entry.name = strdup(qsaDevice); + entry.card = 0; + entry.dev = 0; + VECTOR_PUSH_BACK(*devmap, entry); + + for(card = 0;card < max_cards;card++) + { + if((err=snd_ctl_open(&handle, card)) < 0) + continue; + + if((err=snd_ctl_hw_info(handle, &info)) < 0) + { + snd_ctl_close(handle); + continue; + } + + for(dev = 0;dev < (int)info.pcmdevs;dev++) + { + if((err=snd_ctl_pcm_info(handle, dev, &pcminfo)) < 0) + continue; + + if((type==SND_PCM_CHANNEL_PLAYBACK && (pcminfo.flags&SND_PCM_INFO_PLAYBACK)) || + (type==SND_PCM_CHANNEL_CAPTURE && (pcminfo.flags&SND_PCM_INFO_CAPTURE))) + { + snprintf(name, sizeof(name), "%s [%s] (hw:%d,%d)", info.name, pcminfo.name, card, dev); + entry.name = strdup(name); + entry.card = card; + entry.dev = dev; + + VECTOR_PUSH_BACK(*devmap, entry); + TRACE("Got device \"%s\", card %d, dev %d\n", name, card, dev); + } + } + snd_ctl_close(handle); + } +} + +} // namespace + + +/* Wrappers to use an old-style backend with the new interface. */ +struct PlaybackWrapper final : public ALCbackend { + qsa_data *ExtraData; +}; + +static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device); +static void PlaybackWrapper_Destruct(PlaybackWrapper *self); +static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name); +static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self); +static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self); +static void PlaybackWrapper_stop(PlaybackWrapper *self); +static DECLARE_FORWARD2(PlaybackWrapper, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, lock) +static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(PlaybackWrapper) +DEFINE_ALCBACKEND_VTABLE(PlaybackWrapper); + + +FORCE_ALIGN static int qsa_proc_playback(void *ptr) +{ + PlaybackWrapper *self = ptr; + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + qsa_data *data = self->ExtraData; + snd_pcm_channel_status_t status; + struct sched_param param; + struct timeval timeout; + char* write_ptr; + fd_set wfds; + ALint len; + int sret; + + SetRTPriority(); + althrd_setname(althrd_current(), MIXER_THREAD_NAME); + + /* Increase default 10 priority to 11 to avoid jerky sound */ + SchedGet(0, 0, ¶m); + param.sched_priority=param.sched_curpriority+1; + SchedSet(0, 0, SCHED_NOCHANGE, ¶m); + + const ALint frame_size = FrameSizeFromDevFmt( + device->FmtChans, device->FmtType, device->AmbiOrder + ); + + V0(device->Backend,lock)(); + while(!ATOMIC_LOAD(&data->killNow, almemory_order_acquire)) + { + FD_ZERO(&wfds); + FD_SET(data->audio_fd, &wfds); + timeout.tv_sec=2; + timeout.tv_usec=0; + + /* Select also works like time slice to OS */ + V0(device->Backend,unlock)(); + sret = select(data->audio_fd+1, NULL, &wfds, NULL, &timeout); + V0(device->Backend,lock)(); + if(sret == -1) + { + ERR("select error: %s\n", strerror(errno)); + aluHandleDisconnect(device, "Failed waiting for playback buffer: %s", strerror(errno)); + break; + } + if(sret == 0) + { + ERR("select timeout\n"); + continue; + } + + len = data->size; + write_ptr = static_cast(data->buffer); + aluMixData(device, write_ptr, len/frame_size); + while(len>0 && !ATOMIC_LOAD(&data->killNow, almemory_order_acquire)) + { + int wrote = snd_pcm_plugin_write(data->pcmHandle, write_ptr, len); + if(wrote <= 0) + { + if(errno==EAGAIN || errno==EWOULDBLOCK) + continue; + + memset(&status, 0, sizeof(status)); + status.channel = SND_PCM_CHANNEL_PLAYBACK; + + snd_pcm_plugin_status(data->pcmHandle, &status); + + /* we need to reinitialize the sound channel if we've underrun the buffer */ + if(status.status == SND_PCM_STATUS_UNDERRUN || + status.status == SND_PCM_STATUS_READY) + { + if(snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK) < 0) + { + aluHandleDisconnect(device, "Playback recovery failed"); + break; + } + } + } + else + { + write_ptr += wrote; + len -= wrote; + } + } + } + V0(device->Backend,unlock)(); + + return 0; +} + +/************/ +/* Playback */ +/************/ + +static ALCenum qsa_open_playback(PlaybackWrapper *self, const ALCchar* deviceName) +{ + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + qsa_data *data; + int card, dev; + int status; + + data = (qsa_data*)calloc(1, sizeof(qsa_data)); + if(data == NULL) + return ALC_OUT_OF_MEMORY; + ATOMIC_INIT(&data->killNow, AL_TRUE); + + if(!deviceName) + deviceName = qsaDevice; + + if(strcmp(deviceName, qsaDevice) == 0) + status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_PLAYBACK); + else + { + const DevMap *iter; + + if(VECTOR_SIZE(DeviceNameMap) == 0) + deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap); + +#define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0) + VECTOR_FIND_IF(iter, const DevMap, DeviceNameMap, MATCH_DEVNAME); +#undef MATCH_DEVNAME + if(iter == VECTOR_END(DeviceNameMap)) + { + free(data); + return ALC_INVALID_DEVICE; + } + + status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_PLAYBACK); + } + + if(status < 0) + { + free(data); + return ALC_INVALID_DEVICE; + } + + data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK); + if(data->audio_fd < 0) + { + snd_pcm_close(data->pcmHandle); + free(data); + return ALC_INVALID_DEVICE; + } + + alstr_copy_cstr(&device->DeviceName, deviceName); + self->ExtraData = data; + + return ALC_NO_ERROR; +} + +static void qsa_close_playback(PlaybackWrapper *self) +{ + qsa_data *data = self->ExtraData; + + if (data->buffer!=NULL) + { + free(data->buffer); + data->buffer=NULL; + } + + snd_pcm_close(data->pcmHandle); + free(data); + + self->ExtraData = NULL; +} + +static ALCboolean qsa_reset_playback(PlaybackWrapper *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + qsa_data *data = self->ExtraData; + int32_t format=-1; + + switch(device->FmtType) + { + case DevFmtByte: + format=SND_PCM_SFMT_S8; + break; + case DevFmtUByte: + format=SND_PCM_SFMT_U8; + break; + case DevFmtShort: + format=SND_PCM_SFMT_S16_LE; + break; + case DevFmtUShort: + format=SND_PCM_SFMT_U16_LE; + break; + case DevFmtInt: + format=SND_PCM_SFMT_S32_LE; + break; + case DevFmtUInt: + format=SND_PCM_SFMT_U32_LE; + break; + case DevFmtFloat: + format=SND_PCM_SFMT_FLOAT_LE; + break; + } + + /* we actually don't want to block on writes */ + snd_pcm_nonblock_mode(data->pcmHandle, 1); + /* Disable mmap to control data transfer to the audio device */ + snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_MMAP); + snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_BUFFER_PARTIAL_BLOCKS); + + // configure a sound channel + memset(&data->cparams, 0, sizeof(data->cparams)); + data->cparams.channel=SND_PCM_CHANNEL_PLAYBACK; + data->cparams.mode=SND_PCM_MODE_BLOCK; + data->cparams.start_mode=SND_PCM_START_FULL; + data->cparams.stop_mode=SND_PCM_STOP_STOP; + + data->cparams.buf.block.frag_size=device->UpdateSize * + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + data->cparams.buf.block.frags_max=device->NumUpdates; + data->cparams.buf.block.frags_min=device->NumUpdates; + + data->cparams.format.interleave=1; + data->cparams.format.rate=device->Frequency; + data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + data->cparams.format.format=format; + + if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0) + { + int original_rate=data->cparams.format.rate; + int original_voices=data->cparams.format.voices; + int original_format=data->cparams.format.format; + int it; + int jt; + + for (it=0; it<1; it++) + { + /* Check for second pass */ + if (it==1) + { + original_rate=ratelist[0].rate; + original_voices=channellist[0].channels; + original_format=formatlist[0].format; + } + + do { + /* At first downgrade sample format */ + jt=0; + do { + if (formatlist[jt].format==data->cparams.format.format) + { + data->cparams.format.format=formatlist[jt+1].format; + break; + } + if (formatlist[jt].format==0) + { + data->cparams.format.format=0; + break; + } + jt++; + } while(1); + + if (data->cparams.format.format==0) + { + data->cparams.format.format=original_format; + + /* At secod downgrade sample rate */ + jt=0; + do { + if (ratelist[jt].rate==data->cparams.format.rate) + { + data->cparams.format.rate=ratelist[jt+1].rate; + break; + } + if (ratelist[jt].rate==0) + { + data->cparams.format.rate=0; + break; + } + jt++; + } while(1); + + if (data->cparams.format.rate==0) + { + data->cparams.format.rate=original_rate; + data->cparams.format.format=original_format; + + /* At third downgrade channels number */ + jt=0; + do { + if(channellist[jt].channels==data->cparams.format.voices) + { + data->cparams.format.voices=channellist[jt+1].channels; + break; + } + if (channellist[jt].channels==0) + { + data->cparams.format.voices=0; + break; + } + jt++; + } while(1); + } + + if (data->cparams.format.voices==0) + { + break; + } + } + + data->cparams.buf.block.frag_size=device->UpdateSize* + data->cparams.format.voices* + snd_pcm_format_width(data->cparams.format.format)/8; + data->cparams.buf.block.frags_max=device->NumUpdates; + data->cparams.buf.block.frags_min=device->NumUpdates; + if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0) + { + continue; + } + else + { + break; + } + } while(1); + + if (data->cparams.format.voices!=0) + { + break; + } + } + + if (data->cparams.format.voices==0) + { + return ALC_FALSE; + } + } + + if ((snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK))<0) + { + return ALC_FALSE; + } + + memset(&data->csetup, 0, sizeof(data->csetup)); + data->csetup.channel=SND_PCM_CHANNEL_PLAYBACK; + if (snd_pcm_plugin_setup(data->pcmHandle, &data->csetup)<0) + { + return ALC_FALSE; + } + + /* now fill back to the our AL device */ + device->Frequency=data->cparams.format.rate; + + switch (data->cparams.format.voices) + { + case 1: + device->FmtChans=DevFmtMono; + break; + case 2: + device->FmtChans=DevFmtStereo; + break; + case 4: + device->FmtChans=DevFmtQuad; + break; + case 6: + device->FmtChans=DevFmtX51; + break; + case 7: + device->FmtChans=DevFmtX61; + break; + case 8: + device->FmtChans=DevFmtX71; + break; + default: + device->FmtChans=DevFmtMono; + break; + } + + switch (data->cparams.format.format) + { + case SND_PCM_SFMT_S8: + device->FmtType=DevFmtByte; + break; + case SND_PCM_SFMT_U8: + device->FmtType=DevFmtUByte; + break; + case SND_PCM_SFMT_S16_LE: + device->FmtType=DevFmtShort; + break; + case SND_PCM_SFMT_U16_LE: + device->FmtType=DevFmtUShort; + break; + case SND_PCM_SFMT_S32_LE: + device->FmtType=DevFmtInt; + break; + case SND_PCM_SFMT_U32_LE: + device->FmtType=DevFmtUInt; + break; + case SND_PCM_SFMT_FLOAT_LE: + device->FmtType=DevFmtFloat; + break; + default: + device->FmtType=DevFmtShort; + break; + } + + SetDefaultChannelOrder(device); + + device->UpdateSize=data->csetup.buf.block.frag_size/ + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + device->NumUpdates=data->csetup.buf.block.frags; + + data->size=data->csetup.buf.block.frag_size; + data->buffer=malloc(data->size); + if (!data->buffer) + { + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static ALCboolean qsa_start_playback(PlaybackWrapper *self) +{ + qsa_data *data = self->ExtraData; + + ATOMIC_STORE(&data->killNow, AL_FALSE, almemory_order_release); + if(althrd_create(&data->thread, qsa_proc_playback, self) != althrd_success) + return ALC_FALSE; + + return ALC_TRUE; +} + +static void qsa_stop_playback(PlaybackWrapper *self) +{ + qsa_data *data = self->ExtraData; + int res; + + if(ATOMIC_EXCHANGE(&data->killNow, AL_TRUE, almemory_order_acq_rel)) + return; + althrd_join(data->thread, &res); +} + + +static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device) +{ + new (self) PlaybackWrapper{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(PlaybackWrapper, ALCbackend, self); + + self->ExtraData = NULL; +} + +static void PlaybackWrapper_Destruct(PlaybackWrapper *self) +{ + if(self->ExtraData) + qsa_close_playback(self); + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~PlaybackWrapper(); +} + +static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name) +{ + return qsa_open_playback(self, name); +} + +static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self) +{ + return qsa_reset_playback(self); +} + +static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self) +{ + return qsa_start_playback(self); +} + +static void PlaybackWrapper_stop(PlaybackWrapper *self) +{ + qsa_stop_playback(self); +} + + + +/***********/ +/* Capture */ +/***********/ + +struct CaptureWrapper final : public ALCbackend { + qsa_data *ExtraData; +}; + +static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device); +static void CaptureWrapper_Destruct(CaptureWrapper *self); +static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name); +static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ALCboolean, reset) +static ALCboolean CaptureWrapper_start(CaptureWrapper *self); +static void CaptureWrapper_stop(CaptureWrapper *self); +static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples); +static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self); +static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, lock) +static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(CaptureWrapper) +DEFINE_ALCBACKEND_VTABLE(CaptureWrapper); + + +static ALCenum qsa_open_capture(CaptureWrapper *self, const ALCchar *deviceName) +{ + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + qsa_data *data; + int card, dev; + int format=-1; + int status; + + data=(qsa_data*)calloc(1, sizeof(qsa_data)); + if (data==NULL) + { + return ALC_OUT_OF_MEMORY; + } + + if(!deviceName) + deviceName = qsaDevice; + + if(strcmp(deviceName, qsaDevice) == 0) + status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_CAPTURE); + else + { + const DevMap *iter; + + if(VECTOR_SIZE(CaptureNameMap) == 0) + deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap); + +#define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0) + VECTOR_FIND_IF(iter, const DevMap, CaptureNameMap, MATCH_DEVNAME); +#undef MATCH_DEVNAME + if(iter == VECTOR_END(CaptureNameMap)) + { + free(data); + return ALC_INVALID_DEVICE; + } + + status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_CAPTURE); + } + + if(status < 0) + { + free(data); + return ALC_INVALID_DEVICE; + } + + data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE); + if(data->audio_fd < 0) + { + snd_pcm_close(data->pcmHandle); + free(data); + return ALC_INVALID_DEVICE; + } + + alstr_copy_cstr(&device->DeviceName, deviceName); + self->ExtraData = data; + + switch (device->FmtType) + { + case DevFmtByte: + format=SND_PCM_SFMT_S8; + break; + case DevFmtUByte: + format=SND_PCM_SFMT_U8; + break; + case DevFmtShort: + format=SND_PCM_SFMT_S16_LE; + break; + case DevFmtUShort: + format=SND_PCM_SFMT_U16_LE; + break; + case DevFmtInt: + format=SND_PCM_SFMT_S32_LE; + break; + case DevFmtUInt: + format=SND_PCM_SFMT_U32_LE; + break; + case DevFmtFloat: + format=SND_PCM_SFMT_FLOAT_LE; + break; + } + + /* we actually don't want to block on reads */ + snd_pcm_nonblock_mode(data->pcmHandle, 1); + /* Disable mmap to control data transfer to the audio device */ + snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_MMAP); + + /* configure a sound channel */ + memset(&data->cparams, 0, sizeof(data->cparams)); + data->cparams.mode=SND_PCM_MODE_BLOCK; + data->cparams.channel=SND_PCM_CHANNEL_CAPTURE; + data->cparams.start_mode=SND_PCM_START_GO; + data->cparams.stop_mode=SND_PCM_STOP_STOP; + + data->cparams.buf.block.frag_size=device->UpdateSize* + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + data->cparams.buf.block.frags_max=device->NumUpdates; + data->cparams.buf.block.frags_min=device->NumUpdates; + + data->cparams.format.interleave=1; + data->cparams.format.rate=device->Frequency; + data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + data->cparams.format.format=format; + + if(snd_pcm_plugin_params(data->pcmHandle, &data->cparams) < 0) + { + snd_pcm_close(data->pcmHandle); + free(data); + + return ALC_INVALID_VALUE; + } + + return ALC_NO_ERROR; +} + +static void qsa_close_capture(CaptureWrapper *self) +{ + qsa_data *data = self->ExtraData; + + if (data->pcmHandle!=NULL) + snd_pcm_close(data->pcmHandle); + + free(data); + self->ExtraData = NULL; +} + +static void qsa_start_capture(CaptureWrapper *self) +{ + qsa_data *data = self->ExtraData; + int rstatus; + + if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0) + { + ERR("capture prepare failed: %s\n", snd_strerror(rstatus)); + return; + } + + memset(&data->csetup, 0, sizeof(data->csetup)); + data->csetup.channel=SND_PCM_CHANNEL_CAPTURE; + if ((rstatus=snd_pcm_plugin_setup(data->pcmHandle, &data->csetup))<0) + { + ERR("capture setup failed: %s\n", snd_strerror(rstatus)); + return; + } + + snd_pcm_capture_go(data->pcmHandle); +} + +static void qsa_stop_capture(CaptureWrapper *self) +{ + qsa_data *data = self->ExtraData; + snd_pcm_capture_flush(data->pcmHandle); +} + +static ALCuint qsa_available_samples(CaptureWrapper *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + qsa_data *data = self->ExtraData; + snd_pcm_channel_status_t status; + ALint frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + ALint free_size; + int rstatus; + + memset(&status, 0, sizeof (status)); + status.channel=SND_PCM_CHANNEL_CAPTURE; + snd_pcm_plugin_status(data->pcmHandle, &status); + if ((status.status==SND_PCM_STATUS_OVERRUN) || + (status.status==SND_PCM_STATUS_READY)) + { + if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0) + { + ERR("capture prepare failed: %s\n", snd_strerror(rstatus)); + aluHandleDisconnect(device, "Failed capture recovery: %s", snd_strerror(rstatus)); + return 0; + } + + snd_pcm_capture_go(data->pcmHandle); + return 0; + } + + free_size=data->csetup.buf.block.frag_size*data->csetup.buf.block.frags; + free_size-=status.free; + + return free_size/frame_size; +} + +static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuint samples) +{ + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + qsa_data *data = self->ExtraData; + char* read_ptr; + snd_pcm_channel_status_t status; + fd_set rfds; + int selectret; + struct timeval timeout; + int bytes_read; + ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + ALint len=samples*frame_size; + int rstatus; + + read_ptr = static_cast(buffer); + + while (len>0) + { + FD_ZERO(&rfds); + FD_SET(data->audio_fd, &rfds); + timeout.tv_sec=2; + timeout.tv_usec=0; + + /* Select also works like time slice to OS */ + bytes_read=0; + selectret=select(data->audio_fd+1, &rfds, NULL, NULL, &timeout); + switch (selectret) + { + case -1: + aluHandleDisconnect(device, "Failed to check capture samples"); + return ALC_INVALID_DEVICE; + case 0: + break; + default: + if (FD_ISSET(data->audio_fd, &rfds)) + { + bytes_read=snd_pcm_plugin_read(data->pcmHandle, read_ptr, len); + break; + } + break; + } + + if (bytes_read<=0) + { + if ((errno==EAGAIN) || (errno==EWOULDBLOCK)) + { + continue; + } + + memset(&status, 0, sizeof (status)); + status.channel=SND_PCM_CHANNEL_CAPTURE; + snd_pcm_plugin_status(data->pcmHandle, &status); + + /* we need to reinitialize the sound channel if we've overrun the buffer */ + if ((status.status==SND_PCM_STATUS_OVERRUN) || + (status.status==SND_PCM_STATUS_READY)) + { + if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0) + { + ERR("capture prepare failed: %s\n", snd_strerror(rstatus)); + aluHandleDisconnect(device, "Failed capture recovery: %s", + snd_strerror(rstatus)); + return ALC_INVALID_DEVICE; + } + snd_pcm_capture_go(data->pcmHandle); + } + } + else + { + read_ptr+=bytes_read; + len-=bytes_read; + } + } + + return ALC_NO_ERROR; +} + + +static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device) +{ + new (self) CaptureWrapper{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(CaptureWrapper, ALCbackend, self); + + self->ExtraData = NULL; +} + +static void CaptureWrapper_Destruct(CaptureWrapper *self) +{ + if(self->ExtraData) + qsa_close_capture(self); + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~CaptureWrapper(); +} + +static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name) +{ + return qsa_open_capture(self, name); +} + +static ALCboolean CaptureWrapper_start(CaptureWrapper *self) +{ + qsa_start_capture(self); + return ALC_TRUE; +} + +static void CaptureWrapper_stop(CaptureWrapper *self) +{ + qsa_stop_capture(self); +} + +static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples) +{ + return qsa_capture_samples(self, buffer, samples); +} + +static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self) +{ + return qsa_available_samples(self); +} + + +struct ALCqsaBackendFactory final : public ALCbackendFactory { + ALCqsaBackendFactory() noexcept; +}; + +static ALCboolean ALCqsaBackendFactory_init(ALCqsaBackendFactory* UNUSED(self)); +static void ALCqsaBackendFactory_deinit(ALCqsaBackendFactory* UNUSED(self)); +static ALCboolean ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory* UNUSED(self), ALCbackend_Type type); +static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames); +static ALCbackend* ALCqsaBackendFactory_createBackend(ALCqsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type); +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCqsaBackendFactory); + +ALCqsaBackendFactory::ALCqsaBackendFactory() noexcept + : ALCbackendFactory{GET_VTABLE2(ALCqsaBackendFactory, ALCbackendFactory)} +{ } + + +static ALCboolean ALCqsaBackendFactory_init(ALCqsaBackendFactory* UNUSED(self)) +{ + return ALC_TRUE; +} + +static void ALCqsaBackendFactory_deinit(ALCqsaBackendFactory* UNUSED(self)) +{ +#define FREE_NAME(iter) free((iter)->name) + VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME); + VECTOR_DEINIT(DeviceNameMap); + + VECTOR_FOR_EACH(DevMap, CaptureNameMap, FREE_NAME); + VECTOR_DEINIT(CaptureNameMap); +#undef FREE_NAME +} + +static ALCboolean ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Playback || type == ALCbackend_Capture) + return ALC_TRUE; + return ALC_FALSE; +} + +static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +{ + switch (type) + { +#define APPEND_OUTNAME(e) do { \ + const char *n_ = (e)->name; \ + if(n_ && n_[0]) \ + alstr_append_range(outnames, n_, n_+strlen(n_)+1); \ +} while(0) + case ALL_DEVICE_PROBE: + deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap); + VECTOR_FOR_EACH(const DevMap, DeviceNameMap, APPEND_OUTNAME); + break; + + case CAPTURE_DEVICE_PROBE: + deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap); + VECTOR_FOR_EACH(const DevMap, CaptureNameMap, APPEND_OUTNAME); + break; +#undef APPEND_OUTNAME + } +} + +static ALCbackend* ALCqsaBackendFactory_createBackend(ALCqsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + PlaybackWrapper *backend; + NEW_OBJ(backend, PlaybackWrapper)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + if(type == ALCbackend_Capture) + { + CaptureWrapper *backend; + NEW_OBJ(backend, CaptureWrapper)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + + return NULL; +} + +ALCbackendFactory *ALCqsaBackendFactory_getFactory(void) +{ + static ALCqsaBackendFactory factory{}; + return STATIC_CAST(ALCbackendFactory, &factory); +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ff8f2b8..639fa2a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1112,7 +1112,7 @@ IF(QSA_FOUND) IF(ALSOFT_BACKEND_QSA) SET(HAVE_QSA 1) SET(BACKENDS "${BACKENDS} QSA (linked),") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/qsa.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/qsa.cpp) SET(EXTRA_LIBS ${QSA_LIBRARIES} ${EXTRA_LIBS}) SET(INC_PATHS ${INC_PATHS} ${QSA_INCLUDE_DIRS}) ENDIF() -- cgit v1.2.3 From 2445bfd578d8208baa4fdb4e4c4774f1df6e4ba9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Nov 2018 02:09:21 -0800 Subject: Convert the CoreAudio backend to C++ --- Alc/backends/coreaudio.c | 816 -------------------------------------------- Alc/backends/coreaudio.cpp | 820 +++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 821 insertions(+), 817 deletions(-) delete mode 100644 Alc/backends/coreaudio.c create mode 100644 Alc/backends/coreaudio.cpp diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c deleted file mode 100644 index adb01fa6..00000000 --- a/Alc/backends/coreaudio.c +++ /dev/null @@ -1,816 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include "alMain.h" -#include "alu.h" -#include "ringbuffer.h" - -#include -#include -#include - -#include "backends/base.h" - - -static const ALCchar ca_device[] = "CoreAudio Default"; - - -typedef struct ALCcoreAudioPlayback { - DERIVE_FROM_TYPE(ALCbackend); - - AudioUnit audioUnit; - - ALuint frameSize; - AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD -} ALCcoreAudioPlayback; - -static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device); -static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self); -static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name); -static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self); -static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self); -static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self); -static DECLARE_FORWARD2(ALCcoreAudioPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioPlayback) - -DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioPlayback); - - -static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCcoreAudioPlayback, ALCbackend, self); - - self->frameSize = 0; - memset(&self->format, 0, sizeof(self->format)); -} - -static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self) -{ - AudioUnitUninitialize(self->audioUnit); - AudioComponentInstanceDispose(self->audioUnit); - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -static OSStatus ALCcoreAudioPlayback_MixerProc(void *inRefCon, - AudioUnitRenderActionFlags* UNUSED(ioActionFlags), const AudioTimeStamp* UNUSED(inTimeStamp), - UInt32 UNUSED(inBusNumber), UInt32 UNUSED(inNumberFrames), AudioBufferList *ioData) -{ - ALCcoreAudioPlayback *self = inRefCon; - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - - ALCcoreAudioPlayback_lock(self); - aluMixData(device, ioData->mBuffers[0].mData, - ioData->mBuffers[0].mDataByteSize / self->frameSize); - ALCcoreAudioPlayback_unlock(self); - - return noErr; -} - - -static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - AudioComponentDescription desc; - AudioComponent comp; - OSStatus err; - - if(!name) - name = ca_device; - else if(strcmp(name, ca_device) != 0) - return ALC_INVALID_VALUE; - - /* open the default output unit */ - desc.componentType = kAudioUnitType_Output; -#if TARGET_OS_IOS - desc.componentSubType = kAudioUnitSubType_RemoteIO; -#else - desc.componentSubType = kAudioUnitSubType_DefaultOutput; -#endif - desc.componentManufacturer = kAudioUnitManufacturer_Apple; - desc.componentFlags = 0; - desc.componentFlagsMask = 0; - - comp = AudioComponentFindNext(NULL, &desc); - if(comp == NULL) - { - ERR("AudioComponentFindNext failed\n"); - return ALC_INVALID_VALUE; - } - - err = AudioComponentInstanceNew(comp, &self->audioUnit); - if(err != noErr) - { - ERR("AudioComponentInstanceNew failed\n"); - return ALC_INVALID_VALUE; - } - - /* init and start the default audio unit... */ - err = AudioUnitInitialize(self->audioUnit); - if(err != noErr) - { - ERR("AudioUnitInitialize failed\n"); - AudioComponentInstanceDispose(self->audioUnit); - return ALC_INVALID_VALUE; - } - - alstr_copy_cstr(&device->DeviceName, name); - return ALC_NO_ERROR; -} - -static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - AudioStreamBasicDescription streamFormat; - AURenderCallbackStruct input; - OSStatus err; - UInt32 size; - - err = AudioUnitUninitialize(self->audioUnit); - if(err != noErr) - ERR("-- AudioUnitUninitialize failed.\n"); - - /* retrieve default output unit's properties (output side) */ - size = sizeof(AudioStreamBasicDescription); - err = AudioUnitGetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, &size); - if(err != noErr || size != sizeof(AudioStreamBasicDescription)) - { - ERR("AudioUnitGetProperty failed\n"); - return ALC_FALSE; - } - -#if 0 - TRACE("Output streamFormat of default output unit -\n"); - TRACE(" streamFormat.mFramesPerPacket = %d\n", streamFormat.mFramesPerPacket); - TRACE(" streamFormat.mChannelsPerFrame = %d\n", streamFormat.mChannelsPerFrame); - TRACE(" streamFormat.mBitsPerChannel = %d\n", streamFormat.mBitsPerChannel); - TRACE(" streamFormat.mBytesPerPacket = %d\n", streamFormat.mBytesPerPacket); - TRACE(" streamFormat.mBytesPerFrame = %d\n", streamFormat.mBytesPerFrame); - TRACE(" streamFormat.mSampleRate = %5.0f\n", streamFormat.mSampleRate); -#endif - - /* set default output unit's input side to match output side */ - err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, size); - if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); - return ALC_FALSE; - } - - if(device->Frequency != streamFormat.mSampleRate) - { - device->NumUpdates = (ALuint)((ALuint64)device->NumUpdates * - streamFormat.mSampleRate / - device->Frequency); - device->Frequency = streamFormat.mSampleRate; - } - - /* FIXME: How to tell what channels are what in the output device, and how - * to specify what we're giving? eg, 6.0 vs 5.1 */ - switch(streamFormat.mChannelsPerFrame) - { - case 1: - device->FmtChans = DevFmtMono; - break; - case 2: - device->FmtChans = DevFmtStereo; - break; - case 4: - device->FmtChans = DevFmtQuad; - break; - case 6: - device->FmtChans = DevFmtX51; - break; - case 7: - device->FmtChans = DevFmtX61; - break; - case 8: - device->FmtChans = DevFmtX71; - break; - default: - ERR("Unhandled channel count (%d), using Stereo\n", streamFormat.mChannelsPerFrame); - device->FmtChans = DevFmtStereo; - streamFormat.mChannelsPerFrame = 2; - break; - } - SetDefaultWFXChannelOrder(device); - - /* use channel count and sample rate from the default output unit's current - * parameters, but reset everything else */ - streamFormat.mFramesPerPacket = 1; - streamFormat.mFormatFlags = 0; - switch(device->FmtType) - { - case DevFmtUByte: - device->FmtType = DevFmtByte; - /* fall-through */ - case DevFmtByte: - streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; - streamFormat.mBitsPerChannel = 8; - break; - case DevFmtUShort: - device->FmtType = DevFmtShort; - /* fall-through */ - case DevFmtShort: - streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; - streamFormat.mBitsPerChannel = 16; - break; - case DevFmtUInt: - device->FmtType = DevFmtInt; - /* fall-through */ - case DevFmtInt: - streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; - streamFormat.mBitsPerChannel = 32; - break; - case DevFmtFloat: - streamFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat; - streamFormat.mBitsPerChannel = 32; - break; - } - streamFormat.mBytesPerFrame = streamFormat.mChannelsPerFrame * - streamFormat.mBitsPerChannel / 8; - streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame; - streamFormat.mFormatID = kAudioFormatLinearPCM; - streamFormat.mFormatFlags |= kAudioFormatFlagsNativeEndian | - kLinearPCMFormatFlagIsPacked; - - err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription)); - if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); - return ALC_FALSE; - } - - /* setup callback */ - self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - input.inputProc = ALCcoreAudioPlayback_MixerProc; - input.inputProcRefCon = self; - - err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct)); - if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); - return ALC_FALSE; - } - - /* init the default audio unit... */ - err = AudioUnitInitialize(self->audioUnit); - if(err != noErr) - { - ERR("AudioUnitInitialize failed\n"); - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self) -{ - OSStatus err = AudioOutputUnitStart(self->audioUnit); - if(err != noErr) - { - ERR("AudioOutputUnitStart failed\n"); - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self) -{ - OSStatus err = AudioOutputUnitStop(self->audioUnit); - if(err != noErr) - ERR("AudioOutputUnitStop failed\n"); -} - - - - -typedef struct ALCcoreAudioCapture { - DERIVE_FROM_TYPE(ALCbackend); - - AudioUnit audioUnit; - - ALuint frameSize; - ALdouble sampleRateRatio; // Ratio of hardware sample rate / requested sample rate - AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD - - AudioConverterRef audioConverter; // Sample rate converter if needed - AudioBufferList *bufferList; // Buffer for data coming from the input device - ALCvoid *resampleBuffer; // Buffer for returned RingBuffer data when resampling - - ll_ringbuffer_t *ring; -} ALCcoreAudioCapture; - -static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device); -static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self); -static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name); -static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ALCboolean, reset) -static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self); -static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self); -static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples); -static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self); -static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioCapture) - -DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioCapture); - - -static AudioBufferList *allocate_buffer_list(UInt32 channelCount, UInt32 byteSize) -{ - AudioBufferList *list; - - list = calloc(1, FAM_SIZE(AudioBufferList, mBuffers, 1) + byteSize); - if(list) - { - list->mNumberBuffers = 1; - - list->mBuffers[0].mNumberChannels = channelCount; - list->mBuffers[0].mDataByteSize = byteSize; - list->mBuffers[0].mData = &list->mBuffers[1]; - } - return list; -} - -static void destroy_buffer_list(AudioBufferList *list) -{ - free(list); -} - - -static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCcoreAudioCapture, ALCbackend, self); - - self->audioUnit = 0; - self->audioConverter = NULL; - self->bufferList = NULL; - self->resampleBuffer = NULL; - self->ring = NULL; -} - -static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self) -{ - ll_ringbuffer_free(self->ring); - self->ring = NULL; - - free(self->resampleBuffer); - self->resampleBuffer = NULL; - - destroy_buffer_list(self->bufferList); - self->bufferList = NULL; - - if(self->audioConverter) - AudioConverterDispose(self->audioConverter); - self->audioConverter = NULL; - - if(self->audioUnit) - AudioComponentInstanceDispose(self->audioUnit); - self->audioUnit = 0; - - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -static OSStatus ALCcoreAudioCapture_RecordProc(void *inRefCon, - AudioUnitRenderActionFlags* UNUSED(ioActionFlags), - const AudioTimeStamp *inTimeStamp, UInt32 UNUSED(inBusNumber), - UInt32 inNumberFrames, AudioBufferList* UNUSED(ioData)) -{ - ALCcoreAudioCapture *self = inRefCon; - AudioUnitRenderActionFlags flags = 0; - OSStatus err; - - // fill the bufferList with data from the input device - err = AudioUnitRender(self->audioUnit, &flags, inTimeStamp, 1, inNumberFrames, self->bufferList); - if(err != noErr) - { - ERR("AudioUnitRender error: %d\n", err); - return err; - } - - ll_ringbuffer_write(self->ring, self->bufferList->mBuffers[0].mData, inNumberFrames); - - return noErr; -} - -static OSStatus ALCcoreAudioCapture_ConvertCallback(AudioConverterRef UNUSED(inAudioConverter), - UInt32 *ioNumberDataPackets, AudioBufferList *ioData, - AudioStreamPacketDescription** UNUSED(outDataPacketDescription), - void *inUserData) -{ - ALCcoreAudioCapture *self = inUserData; - - // Read from the ring buffer and store temporarily in a large buffer - ll_ringbuffer_read(self->ring, self->resampleBuffer, *ioNumberDataPackets); - - // Set the input data - ioData->mNumberBuffers = 1; - ioData->mBuffers[0].mNumberChannels = self->format.mChannelsPerFrame; - ioData->mBuffers[0].mData = self->resampleBuffer; - ioData->mBuffers[0].mDataByteSize = (*ioNumberDataPackets) * self->format.mBytesPerFrame; - - return noErr; -} - - -static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - AudioStreamBasicDescription requestedFormat; // The application requested format - AudioStreamBasicDescription hardwareFormat; // The hardware format - AudioStreamBasicDescription outputFormat; // The AudioUnit output format - AURenderCallbackStruct input; - AudioComponentDescription desc; - UInt32 outputFrameCount; - UInt32 propertySize; - AudioObjectPropertyAddress propertyAddress; - UInt32 enableIO; - AudioComponent comp; - OSStatus err; - - if(!name) - name = ca_device; - else if(strcmp(name, ca_device) != 0) - return ALC_INVALID_VALUE; - - desc.componentType = kAudioUnitType_Output; -#if TARGET_OS_IOS - desc.componentSubType = kAudioUnitSubType_RemoteIO; -#else - desc.componentSubType = kAudioUnitSubType_HALOutput; -#endif - desc.componentManufacturer = kAudioUnitManufacturer_Apple; - desc.componentFlags = 0; - desc.componentFlagsMask = 0; - - // Search for component with given description - comp = AudioComponentFindNext(NULL, &desc); - if(comp == NULL) - { - ERR("AudioComponentFindNext failed\n"); - return ALC_INVALID_VALUE; - } - - // Open the component - err = AudioComponentInstanceNew(comp, &self->audioUnit); - if(err != noErr) - { - ERR("AudioComponentInstanceNew failed\n"); - goto error; - } - - // Turn off AudioUnit output - enableIO = 0; - err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint)); - if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); - goto error; - } - - // Turn on AudioUnit input - enableIO = 1; - err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint)); - if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); - goto error; - } - -#if !TARGET_OS_IOS - // Get the default input device - AudioDeviceID inputDevice = kAudioDeviceUnknown; - - propertySize = sizeof(AudioDeviceID); - propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; - propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; - propertyAddress.mElement = kAudioObjectPropertyElementMaster; - - err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, &inputDevice); - if(err != noErr) - { - ERR("AudioObjectGetPropertyData failed\n"); - goto error; - } - if(inputDevice == kAudioDeviceUnknown) - { - ERR("No input device found\n"); - goto error; - } - - // Track the input device - err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID)); - if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); - goto error; - } -#endif - - // set capture callback - input.inputProc = ALCcoreAudioCapture_RecordProc; - input.inputProcRefCon = self; - - err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct)); - if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); - goto error; - } - - // Initialize the device - err = AudioUnitInitialize(self->audioUnit); - if(err != noErr) - { - ERR("AudioUnitInitialize failed\n"); - goto error; - } - - // Get the hardware format - propertySize = sizeof(AudioStreamBasicDescription); - err = AudioUnitGetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize); - if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription)) - { - ERR("AudioUnitGetProperty failed\n"); - goto error; - } - - // Set up the requested format description - switch(device->FmtType) - { - case DevFmtUByte: - requestedFormat.mBitsPerChannel = 8; - requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked; - break; - case DevFmtShort: - requestedFormat.mBitsPerChannel = 16; - requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; - break; - case DevFmtInt: - requestedFormat.mBitsPerChannel = 32; - requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; - break; - case DevFmtFloat: - requestedFormat.mBitsPerChannel = 32; - requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked; - break; - case DevFmtByte: - case DevFmtUShort: - case DevFmtUInt: - ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); - goto error; - } - - switch(device->FmtChans) - { - case DevFmtMono: - requestedFormat.mChannelsPerFrame = 1; - break; - case DevFmtStereo: - requestedFormat.mChannelsPerFrame = 2; - break; - - case DevFmtQuad: - case DevFmtX51: - case DevFmtX51Rear: - case DevFmtX61: - case DevFmtX71: - case DevFmtAmbi3D: - ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans)); - goto error; - } - - requestedFormat.mBytesPerFrame = requestedFormat.mChannelsPerFrame * requestedFormat.mBitsPerChannel / 8; - requestedFormat.mBytesPerPacket = requestedFormat.mBytesPerFrame; - requestedFormat.mSampleRate = device->Frequency; - requestedFormat.mFormatID = kAudioFormatLinearPCM; - requestedFormat.mReserved = 0; - requestedFormat.mFramesPerPacket = 1; - - // save requested format description for later use - self->format = requestedFormat; - self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - - // Use intermediate format for sample rate conversion (outputFormat) - // Set sample rate to the same as hardware for resampling later - outputFormat = requestedFormat; - outputFormat.mSampleRate = hardwareFormat.mSampleRate; - - // Determine sample rate ratio for resampling - self->sampleRateRatio = outputFormat.mSampleRate / device->Frequency; - - // The output format should be the requested format, but using the hardware sample rate - // This is because the AudioUnit will automatically scale other properties, except for sample rate - err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat)); - if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); - goto error; - } - - // Set the AudioUnit output format frame count - outputFrameCount = device->UpdateSize * self->sampleRateRatio; - err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount)); - if(err != noErr) - { - ERR("AudioUnitSetProperty failed: %d\n", err); - goto error; - } - - // Set up sample converter - err = AudioConverterNew(&outputFormat, &requestedFormat, &self->audioConverter); - if(err != noErr) - { - ERR("AudioConverterNew failed: %d\n", err); - goto error; - } - - // Create a buffer for use in the resample callback - self->resampleBuffer = malloc(device->UpdateSize * self->frameSize * self->sampleRateRatio); - - // Allocate buffer for the AudioUnit output - self->bufferList = allocate_buffer_list(outputFormat.mChannelsPerFrame, device->UpdateSize * self->frameSize * self->sampleRateRatio); - if(self->bufferList == NULL) - goto error; - - self->ring = ll_ringbuffer_create( - (size_t)ceil(device->UpdateSize*self->sampleRateRatio*device->NumUpdates), - self->frameSize, false - ); - if(!self->ring) goto error; - - alstr_copy_cstr(&device->DeviceName, name); - - return ALC_NO_ERROR; - -error: - ll_ringbuffer_free(self->ring); - self->ring = NULL; - free(self->resampleBuffer); - self->resampleBuffer = NULL; - destroy_buffer_list(self->bufferList); - self->bufferList = NULL; - - if(self->audioConverter) - AudioConverterDispose(self->audioConverter); - self->audioConverter = NULL; - if(self->audioUnit) - AudioComponentInstanceDispose(self->audioUnit); - self->audioUnit = 0; - - return ALC_INVALID_VALUE; -} - - -static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self) -{ - OSStatus err = AudioOutputUnitStart(self->audioUnit); - if(err != noErr) - { - ERR("AudioOutputUnitStart failed\n"); - return ALC_FALSE; - } - return ALC_TRUE; -} - -static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self) -{ - OSStatus err = AudioOutputUnitStop(self->audioUnit); - if(err != noErr) - ERR("AudioOutputUnitStop failed\n"); -} - -static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples) -{ - union { - ALbyte _[sizeof(AudioBufferList) + sizeof(AudioBuffer)]; - AudioBufferList list; - } audiobuf = { { 0 } }; - UInt32 frameCount; - OSStatus err; - - // If no samples are requested, just return - if(samples == 0) return ALC_NO_ERROR; - - // Point the resampling buffer to the capture buffer - audiobuf.list.mNumberBuffers = 1; - audiobuf.list.mBuffers[0].mNumberChannels = self->format.mChannelsPerFrame; - audiobuf.list.mBuffers[0].mDataByteSize = samples * self->frameSize; - audiobuf.list.mBuffers[0].mData = buffer; - - // Resample into another AudioBufferList - frameCount = samples; - err = AudioConverterFillComplexBuffer(self->audioConverter, - ALCcoreAudioCapture_ConvertCallback, self, &frameCount, &audiobuf.list, NULL - ); - if(err != noErr) - { - ERR("AudioConverterFillComplexBuffer error: %d\n", err); - return ALC_INVALID_VALUE; - } - return ALC_NO_ERROR; -} - -static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self) -{ - return ll_ringbuffer_read_space(self->ring) / self->sampleRateRatio; -} - - -typedef struct ALCcoreAudioBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCcoreAudioBackendFactory; -#define ALCCOREAUDIOBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCcoreAudioBackendFactory, ALCbackendFactory) } } - -ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void); - -static ALCboolean ALCcoreAudioBackendFactory_init(ALCcoreAudioBackendFactory *self); -static DECLARE_FORWARD(ALCcoreAudioBackendFactory, ALCbackendFactory, void, deinit) -static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFactory *self, ALCbackend_Type type); -static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory *self, enum DevProbe type, al_string *outnames); -static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCcoreAudioBackendFactory); - - -ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void) -{ - static ALCcoreAudioBackendFactory factory = ALCCOREAUDIOBACKENDFACTORY_INITIALIZER; - return STATIC_CAST(ALCbackendFactory, &factory); -} - - -static ALCboolean ALCcoreAudioBackendFactory_init(ALCcoreAudioBackendFactory* UNUSED(self)) -{ - return ALC_TRUE; -} - -static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} - -static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) -{ - switch(type) - { - case ALL_DEVICE_PROBE: - case CAPTURE_DEVICE_PROBE: - alstr_append_range(outnames, ca_device, ca_device+sizeof(ca_device)); - break; - } -} - -static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - { - ALCcoreAudioPlayback *backend; - NEW_OBJ(backend, ALCcoreAudioPlayback)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - if(type == ALCbackend_Capture) - { - ALCcoreAudioCapture *backend; - NEW_OBJ(backend, ALCcoreAudioCapture)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp new file mode 100644 index 00000000..08cdeeaa --- /dev/null +++ b/Alc/backends/coreaudio.cpp @@ -0,0 +1,820 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include "alMain.h" +#include "alu.h" +#include "ringbuffer.h" + +#include +#include +#include + +#include "backends/base.h" + + +static const ALCchar ca_device[] = "CoreAudio Default"; + + +struct ALCcoreAudioPlayback final : public ALCbackend { + AudioUnit audioUnit; + + ALuint frameSize; + AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD +}; + +static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device); +static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self); +static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name); +static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self); +static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self); +static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self); +static DECLARE_FORWARD2(ALCcoreAudioPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioPlayback) + +DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioPlayback); + + +static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device) +{ + new (self) ALCcoreAudioPlayback{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCcoreAudioPlayback, ALCbackend, self); + + self->frameSize = 0; + memset(&self->format, 0, sizeof(self->format)); +} + +static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self) +{ + AudioUnitUninitialize(self->audioUnit); + AudioComponentInstanceDispose(self->audioUnit); + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCcoreAudioPlayback(); +} + + +static OSStatus ALCcoreAudioPlayback_MixerProc(void *inRefCon, + AudioUnitRenderActionFlags* UNUSED(ioActionFlags), const AudioTimeStamp* UNUSED(inTimeStamp), + UInt32 UNUSED(inBusNumber), UInt32 UNUSED(inNumberFrames), AudioBufferList *ioData) +{ + ALCcoreAudioPlayback *self = static_cast(inRefCon); + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + + ALCcoreAudioPlayback_lock(self); + aluMixData(device, ioData->mBuffers[0].mData, + ioData->mBuffers[0].mDataByteSize / self->frameSize); + ALCcoreAudioPlayback_unlock(self); + + return noErr; +} + + +static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + AudioComponentDescription desc; + AudioComponent comp; + OSStatus err; + + if(!name) + name = ca_device; + else if(strcmp(name, ca_device) != 0) + return ALC_INVALID_VALUE; + + /* open the default output unit */ + desc.componentType = kAudioUnitType_Output; +#if TARGET_OS_IOS + desc.componentSubType = kAudioUnitSubType_RemoteIO; +#else + desc.componentSubType = kAudioUnitSubType_DefaultOutput; +#endif + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + comp = AudioComponentFindNext(NULL, &desc); + if(comp == NULL) + { + ERR("AudioComponentFindNext failed\n"); + return ALC_INVALID_VALUE; + } + + err = AudioComponentInstanceNew(comp, &self->audioUnit); + if(err != noErr) + { + ERR("AudioComponentInstanceNew failed\n"); + return ALC_INVALID_VALUE; + } + + /* init and start the default audio unit... */ + err = AudioUnitInitialize(self->audioUnit); + if(err != noErr) + { + ERR("AudioUnitInitialize failed\n"); + AudioComponentInstanceDispose(self->audioUnit); + return ALC_INVALID_VALUE; + } + + alstr_copy_cstr(&device->DeviceName, name); + return ALC_NO_ERROR; +} + +static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + AudioStreamBasicDescription streamFormat; + AURenderCallbackStruct input; + OSStatus err; + UInt32 size; + + err = AudioUnitUninitialize(self->audioUnit); + if(err != noErr) + ERR("-- AudioUnitUninitialize failed.\n"); + + /* retrieve default output unit's properties (output side) */ + size = sizeof(AudioStreamBasicDescription); + err = AudioUnitGetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, &size); + if(err != noErr || size != sizeof(AudioStreamBasicDescription)) + { + ERR("AudioUnitGetProperty failed\n"); + return ALC_FALSE; + } + +#if 0 + TRACE("Output streamFormat of default output unit -\n"); + TRACE(" streamFormat.mFramesPerPacket = %d\n", streamFormat.mFramesPerPacket); + TRACE(" streamFormat.mChannelsPerFrame = %d\n", streamFormat.mChannelsPerFrame); + TRACE(" streamFormat.mBitsPerChannel = %d\n", streamFormat.mBitsPerChannel); + TRACE(" streamFormat.mBytesPerPacket = %d\n", streamFormat.mBytesPerPacket); + TRACE(" streamFormat.mBytesPerFrame = %d\n", streamFormat.mBytesPerFrame); + TRACE(" streamFormat.mSampleRate = %5.0f\n", streamFormat.mSampleRate); +#endif + + /* set default output unit's input side to match output side */ + err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, size); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + return ALC_FALSE; + } + + if(device->Frequency != streamFormat.mSampleRate) + { + device->NumUpdates = (ALuint)((ALuint64)device->NumUpdates * + streamFormat.mSampleRate / + device->Frequency); + device->Frequency = streamFormat.mSampleRate; + } + + /* FIXME: How to tell what channels are what in the output device, and how + * to specify what we're giving? eg, 6.0 vs 5.1 */ + switch(streamFormat.mChannelsPerFrame) + { + case 1: + device->FmtChans = DevFmtMono; + break; + case 2: + device->FmtChans = DevFmtStereo; + break; + case 4: + device->FmtChans = DevFmtQuad; + break; + case 6: + device->FmtChans = DevFmtX51; + break; + case 7: + device->FmtChans = DevFmtX61; + break; + case 8: + device->FmtChans = DevFmtX71; + break; + default: + ERR("Unhandled channel count (%d), using Stereo\n", streamFormat.mChannelsPerFrame); + device->FmtChans = DevFmtStereo; + streamFormat.mChannelsPerFrame = 2; + break; + } + SetDefaultWFXChannelOrder(device); + + /* use channel count and sample rate from the default output unit's current + * parameters, but reset everything else */ + streamFormat.mFramesPerPacket = 1; + streamFormat.mFormatFlags = 0; + switch(device->FmtType) + { + case DevFmtUByte: + device->FmtType = DevFmtByte; + /* fall-through */ + case DevFmtByte: + streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; + streamFormat.mBitsPerChannel = 8; + break; + case DevFmtUShort: + device->FmtType = DevFmtShort; + /* fall-through */ + case DevFmtShort: + streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; + streamFormat.mBitsPerChannel = 16; + break; + case DevFmtUInt: + device->FmtType = DevFmtInt; + /* fall-through */ + case DevFmtInt: + streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; + streamFormat.mBitsPerChannel = 32; + break; + case DevFmtFloat: + streamFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat; + streamFormat.mBitsPerChannel = 32; + break; + } + streamFormat.mBytesPerFrame = streamFormat.mChannelsPerFrame * + streamFormat.mBitsPerChannel / 8; + streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame; + streamFormat.mFormatID = kAudioFormatLinearPCM; + streamFormat.mFormatFlags |= kAudioFormatFlagsNativeEndian | + kLinearPCMFormatFlagIsPacked; + + err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + return ALC_FALSE; + } + + /* setup callback */ + self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + input.inputProc = ALCcoreAudioPlayback_MixerProc; + input.inputProcRefCon = self; + + err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + return ALC_FALSE; + } + + /* init the default audio unit... */ + err = AudioUnitInitialize(self->audioUnit); + if(err != noErr) + { + ERR("AudioUnitInitialize failed\n"); + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self) +{ + OSStatus err = AudioOutputUnitStart(self->audioUnit); + if(err != noErr) + { + ERR("AudioOutputUnitStart failed\n"); + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self) +{ + OSStatus err = AudioOutputUnitStop(self->audioUnit); + if(err != noErr) + ERR("AudioOutputUnitStop failed\n"); +} + + +struct ALCcoreAudioCapture final : public ALCbackend { + AudioUnit audioUnit; + + ALuint frameSize; + ALdouble sampleRateRatio; // Ratio of hardware sample rate / requested sample rate + AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD + + AudioConverterRef audioConverter; // Sample rate converter if needed + AudioBufferList *bufferList; // Buffer for data coming from the input device + ALCvoid *resampleBuffer; // Buffer for returned RingBuffer data when resampling + + ll_ringbuffer_t *ring; +}; + +static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device); +static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self); +static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name); +static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ALCboolean, reset) +static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self); +static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self); +static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples); +static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self); +static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioCapture) + +DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioCapture); + + +static AudioBufferList *allocate_buffer_list(UInt32 channelCount, UInt32 byteSize) +{ + AudioBufferList *list; + + list = static_cast(calloc(1, + FAM_SIZE(AudioBufferList, mBuffers, 1) + byteSize)); + if(list) + { + list->mNumberBuffers = 1; + + list->mBuffers[0].mNumberChannels = channelCount; + list->mBuffers[0].mDataByteSize = byteSize; + list->mBuffers[0].mData = &list->mBuffers[1]; + } + return list; +} + +static void destroy_buffer_list(AudioBufferList *list) +{ + free(list); +} + + +static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device) +{ + new (self) ALCcoreAudioCapture{}; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCcoreAudioCapture, ALCbackend, self); + + self->audioUnit = 0; + self->audioConverter = NULL; + self->bufferList = NULL; + self->resampleBuffer = NULL; + self->ring = NULL; +} + +static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self) +{ + ll_ringbuffer_free(self->ring); + self->ring = NULL; + + free(self->resampleBuffer); + self->resampleBuffer = NULL; + + destroy_buffer_list(self->bufferList); + self->bufferList = NULL; + + if(self->audioConverter) + AudioConverterDispose(self->audioConverter); + self->audioConverter = NULL; + + if(self->audioUnit) + AudioComponentInstanceDispose(self->audioUnit); + self->audioUnit = 0; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCcoreAudioCapture(); +} + + +static OSStatus ALCcoreAudioCapture_RecordProc(void *inRefCon, + AudioUnitRenderActionFlags* UNUSED(ioActionFlags), + const AudioTimeStamp *inTimeStamp, UInt32 UNUSED(inBusNumber), + UInt32 inNumberFrames, AudioBufferList* UNUSED(ioData)) +{ + ALCcoreAudioCapture *self = static_cast(inRefCon); + AudioUnitRenderActionFlags flags = 0; + OSStatus err; + + // fill the bufferList with data from the input device + err = AudioUnitRender(self->audioUnit, &flags, inTimeStamp, 1, inNumberFrames, self->bufferList); + if(err != noErr) + { + ERR("AudioUnitRender error: %d\n", err); + return err; + } + + ll_ringbuffer_write(self->ring, static_cast(self->bufferList->mBuffers[0].mData), + inNumberFrames); + return noErr; +} + +static OSStatus ALCcoreAudioCapture_ConvertCallback(AudioConverterRef UNUSED(inAudioConverter), + UInt32 *ioNumberDataPackets, AudioBufferList *ioData, + AudioStreamPacketDescription** UNUSED(outDataPacketDescription), + void *inUserData) +{ + ALCcoreAudioCapture *self = reinterpret_cast(inUserData); + + // Read from the ring buffer and store temporarily in a large buffer + ll_ringbuffer_read(self->ring, static_cast(self->resampleBuffer), *ioNumberDataPackets); + + // Set the input data + ioData->mNumberBuffers = 1; + ioData->mBuffers[0].mNumberChannels = self->format.mChannelsPerFrame; + ioData->mBuffers[0].mData = self->resampleBuffer; + ioData->mBuffers[0].mDataByteSize = (*ioNumberDataPackets) * self->format.mBytesPerFrame; + + return noErr; +} + + +static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + AudioStreamBasicDescription requestedFormat; // The application requested format + AudioStreamBasicDescription hardwareFormat; // The hardware format + AudioStreamBasicDescription outputFormat; // The AudioUnit output format + AURenderCallbackStruct input; + AudioComponentDescription desc; + UInt32 outputFrameCount; + UInt32 propertySize; + AudioObjectPropertyAddress propertyAddress; + UInt32 enableIO; + AudioComponent comp; + OSStatus err; + + if(!name) + name = ca_device; + else if(strcmp(name, ca_device) != 0) + return ALC_INVALID_VALUE; + + desc.componentType = kAudioUnitType_Output; +#if TARGET_OS_IOS + desc.componentSubType = kAudioUnitSubType_RemoteIO; +#else + desc.componentSubType = kAudioUnitSubType_HALOutput; +#endif + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + // Search for component with given description + comp = AudioComponentFindNext(NULL, &desc); + if(comp == NULL) + { + ERR("AudioComponentFindNext failed\n"); + return ALC_INVALID_VALUE; + } + + // Open the component + err = AudioComponentInstanceNew(comp, &self->audioUnit); + if(err != noErr) + { + ERR("AudioComponentInstanceNew failed\n"); + goto error; + } + + // Turn off AudioUnit output + enableIO = 0; + err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + goto error; + } + + // Turn on AudioUnit input + enableIO = 1; + err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + goto error; + } + +#if !TARGET_OS_IOS + { + // Get the default input device + AudioDeviceID inputDevice = kAudioDeviceUnknown; + + propertySize = sizeof(AudioDeviceID); + propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; + propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; + propertyAddress.mElement = kAudioObjectPropertyElementMaster; + + err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, &inputDevice); + if(err != noErr) + { + ERR("AudioObjectGetPropertyData failed\n"); + goto error; + } + if(inputDevice == kAudioDeviceUnknown) + { + ERR("No input device found\n"); + goto error; + } + + // Track the input device + err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + goto error; + } + } +#endif + + // set capture callback + input.inputProc = ALCcoreAudioCapture_RecordProc; + input.inputProcRefCon = self; + + err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + goto error; + } + + // Initialize the device + err = AudioUnitInitialize(self->audioUnit); + if(err != noErr) + { + ERR("AudioUnitInitialize failed\n"); + goto error; + } + + // Get the hardware format + propertySize = sizeof(AudioStreamBasicDescription); + err = AudioUnitGetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize); + if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription)) + { + ERR("AudioUnitGetProperty failed\n"); + goto error; + } + + // Set up the requested format description + switch(device->FmtType) + { + case DevFmtUByte: + requestedFormat.mBitsPerChannel = 8; + requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked; + break; + case DevFmtShort: + requestedFormat.mBitsPerChannel = 16; + requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; + break; + case DevFmtInt: + requestedFormat.mBitsPerChannel = 32; + requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; + break; + case DevFmtFloat: + requestedFormat.mBitsPerChannel = 32; + requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked; + break; + case DevFmtByte: + case DevFmtUShort: + case DevFmtUInt: + ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); + goto error; + } + + switch(device->FmtChans) + { + case DevFmtMono: + requestedFormat.mChannelsPerFrame = 1; + break; + case DevFmtStereo: + requestedFormat.mChannelsPerFrame = 2; + break; + + case DevFmtQuad: + case DevFmtX51: + case DevFmtX51Rear: + case DevFmtX61: + case DevFmtX71: + case DevFmtAmbi3D: + ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans)); + goto error; + } + + requestedFormat.mBytesPerFrame = requestedFormat.mChannelsPerFrame * requestedFormat.mBitsPerChannel / 8; + requestedFormat.mBytesPerPacket = requestedFormat.mBytesPerFrame; + requestedFormat.mSampleRate = device->Frequency; + requestedFormat.mFormatID = kAudioFormatLinearPCM; + requestedFormat.mReserved = 0; + requestedFormat.mFramesPerPacket = 1; + + // save requested format description for later use + self->format = requestedFormat; + self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + + // Use intermediate format for sample rate conversion (outputFormat) + // Set sample rate to the same as hardware for resampling later + outputFormat = requestedFormat; + outputFormat.mSampleRate = hardwareFormat.mSampleRate; + + // Determine sample rate ratio for resampling + self->sampleRateRatio = outputFormat.mSampleRate / device->Frequency; + + // The output format should be the requested format, but using the hardware sample rate + // This is because the AudioUnit will automatically scale other properties, except for sample rate + err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + goto error; + } + + // Set the AudioUnit output format frame count + outputFrameCount = device->UpdateSize * self->sampleRateRatio; + err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed: %d\n", err); + goto error; + } + + // Set up sample converter + err = AudioConverterNew(&outputFormat, &requestedFormat, &self->audioConverter); + if(err != noErr) + { + ERR("AudioConverterNew failed: %d\n", err); + goto error; + } + + // Create a buffer for use in the resample callback + self->resampleBuffer = malloc(device->UpdateSize * self->frameSize * self->sampleRateRatio); + + // Allocate buffer for the AudioUnit output + self->bufferList = allocate_buffer_list(outputFormat.mChannelsPerFrame, device->UpdateSize * self->frameSize * self->sampleRateRatio); + if(self->bufferList == NULL) + goto error; + + self->ring = ll_ringbuffer_create( + (size_t)ceil(device->UpdateSize*self->sampleRateRatio*device->NumUpdates), + self->frameSize, false + ); + if(!self->ring) goto error; + + alstr_copy_cstr(&device->DeviceName, name); + + return ALC_NO_ERROR; + +error: + ll_ringbuffer_free(self->ring); + self->ring = NULL; + free(self->resampleBuffer); + self->resampleBuffer = NULL; + destroy_buffer_list(self->bufferList); + self->bufferList = NULL; + + if(self->audioConverter) + AudioConverterDispose(self->audioConverter); + self->audioConverter = NULL; + if(self->audioUnit) + AudioComponentInstanceDispose(self->audioUnit); + self->audioUnit = 0; + + return ALC_INVALID_VALUE; +} + + +static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self) +{ + OSStatus err = AudioOutputUnitStart(self->audioUnit); + if(err != noErr) + { + ERR("AudioOutputUnitStart failed\n"); + return ALC_FALSE; + } + return ALC_TRUE; +} + +static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self) +{ + OSStatus err = AudioOutputUnitStop(self->audioUnit); + if(err != noErr) + ERR("AudioOutputUnitStop failed\n"); +} + +static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples) +{ + union { + ALbyte _[sizeof(AudioBufferList) + sizeof(AudioBuffer)]; + AudioBufferList list; + } audiobuf = { { 0 } }; + UInt32 frameCount; + OSStatus err; + + // If no samples are requested, just return + if(samples == 0) return ALC_NO_ERROR; + + // Point the resampling buffer to the capture buffer + audiobuf.list.mNumberBuffers = 1; + audiobuf.list.mBuffers[0].mNumberChannels = self->format.mChannelsPerFrame; + audiobuf.list.mBuffers[0].mDataByteSize = samples * self->frameSize; + audiobuf.list.mBuffers[0].mData = buffer; + + // Resample into another AudioBufferList + frameCount = samples; + err = AudioConverterFillComplexBuffer(self->audioConverter, + ALCcoreAudioCapture_ConvertCallback, self, &frameCount, &audiobuf.list, NULL + ); + if(err != noErr) + { + ERR("AudioConverterFillComplexBuffer error: %d\n", err); + return ALC_INVALID_VALUE; + } + return ALC_NO_ERROR; +} + +static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self) +{ + return ll_ringbuffer_read_space(self->ring) / self->sampleRateRatio; +} + + +struct ALCcoreAudioBackendFactory final : public ALCbackendFactory { + ALCcoreAudioBackendFactory() noexcept; +}; + +ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void); + +static ALCboolean ALCcoreAudioBackendFactory_init(ALCcoreAudioBackendFactory *self); +static DECLARE_FORWARD(ALCcoreAudioBackendFactory, ALCbackendFactory, void, deinit) +static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFactory *self, ALCbackend_Type type); +static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory *self, enum DevProbe type, al_string *outnames); +static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory *self, ALCdevice *device, ALCbackend_Type type); +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCcoreAudioBackendFactory); + + +ALCcoreAudioBackendFactory::ALCcoreAudioBackendFactory() noexcept + : ALCbackendFactory{GET_VTABLE2(ALCcoreAudioBackendFactory, ALCbackendFactory)} +{ } + +ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void) +{ + static ALCcoreAudioBackendFactory factory{}; + return STATIC_CAST(ALCbackendFactory, &factory); +} + + +static ALCboolean ALCcoreAudioBackendFactory_init(ALCcoreAudioBackendFactory* UNUSED(self)) +{ + return ALC_TRUE; +} + +static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Playback || ALCbackend_Capture) + return ALC_TRUE; + return ALC_FALSE; +} + +static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +{ + switch(type) + { + case ALL_DEVICE_PROBE: + case CAPTURE_DEVICE_PROBE: + alstr_append_range(outnames, ca_device, ca_device+sizeof(ca_device)); + break; + } +} + +static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCcoreAudioPlayback *backend; + NEW_OBJ(backend, ALCcoreAudioPlayback)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + if(type == ALCbackend_Capture) + { + ALCcoreAudioCapture *backend; + NEW_OBJ(backend, ALCcoreAudioCapture)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + + return NULL; +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 639fa2a2..a822bc0f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1242,7 +1242,7 @@ IF(COREAUDIO_FRAMEWORK) OPTION(ALSOFT_BACKEND_COREAUDIO "Enable CoreAudio backend" ON) IF(ALSOFT_BACKEND_COREAUDIO) SET(HAVE_COREAUDIO 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/coreaudio.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/coreaudio.cpp) SET(BACKENDS "${BACKENDS} CoreAudio,") SET(EXTRA_LIBS ${COREAUDIO_FRAMEWORK} ${EXTRA_LIBS}) SET(EXTRA_LIBS /System/Library/Frameworks/AudioUnit.framework ${EXTRA_LIBS}) -- cgit v1.2.3 From 6f635d3b1a3c80767dd7f1ba6c9ccce78ac35efc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Nov 2018 02:15:10 -0800 Subject: Make ReadALConfig noexcept in C++ --- Alc/alconfig.cpp | 4 ++-- Alc/alconfig.h | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Alc/alconfig.cpp b/Alc/alconfig.cpp index fedb6703..5198f830 100644 --- a/Alc/alconfig.cpp +++ b/Alc/alconfig.cpp @@ -285,7 +285,7 @@ void LoadConfigFromFile(std::istream &f) #ifdef _WIN32 -void ReadALConfig(void) +void ReadALConfig(void) noexcept { WCHAR buffer[MAX_PATH]; if(SHGetSpecialFolderPathW(nullptr, buffer, CSIDL_APPDATA, FALSE) != FALSE) @@ -321,7 +321,7 @@ void ReadALConfig(void) } } #else -void ReadALConfig(void) +void ReadALConfig(void) noexcept { const char *str{"/etc/openal/alsoft.conf"}; diff --git a/Alc/alconfig.h b/Alc/alconfig.h index cb8d8717..627ef48a 100644 --- a/Alc/alconfig.h +++ b/Alc/alconfig.h @@ -2,10 +2,13 @@ #define ALCONFIG_H #ifdef __cplusplus +#define NOEXCEPT noexcept extern "C" { +#else +#define NOEXCEPT #endif -void ReadALConfig(void); +void ReadALConfig(void) NOEXCEPT; void FreeALConfig(void); int ConfigValueExists(const char *devName, const char *blockName, const char *keyName); -- cgit v1.2.3 From 0dfb805fa2f85bed47612a75628d7d9742877b26 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Nov 2018 06:29:02 -0800 Subject: Use utf8_to_wstr to convert UTF-8 to wstring --- Alc/backends/wasapi.cpp | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index f2adf328..50c0baa8 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -707,16 +707,11 @@ static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *de ); if(iter == PlaybackDevices.cend()) { - int len; - if((len=MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, nullptr, 0)) > 0) - { - std::vector wname(len); - MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, wname.data(), len); - iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), - [&wname](const DevMap &entry) -> bool - { return entry.devid == wname.data(); } - ); - } + std::wstring wname{utf8_to_wstr(deviceName)}; + iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + [&wname](const DevMap &entry) -> bool + { return entry.devid == wname; } + ); } if(iter == PlaybackDevices.cend()) WARN("Failed to find device name matching \"%s\"\n", deviceName); @@ -1378,16 +1373,11 @@ static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *devi ); if(iter == CaptureDevices.cend()) { - int len; - if((len=MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, nullptr, 0)) > 0) - { - std::vector wname(len); - MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, wname.data(), len); - iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), - [&wname](const DevMap &entry) -> bool - { return entry.devid == wname.data(); } - ); - } + std::wstring wname{utf8_to_wstr(deviceName)}; + iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), + [&wname](const DevMap &entry) -> bool + { return entry.devid == wname; } + ); } if(iter == CaptureDevices.cend()) WARN("Failed to find device name matching \"%s\"\n", deviceName); -- cgit v1.2.3 From 7088f4e34a8557f2c73ee6635b3c7bf4ec958c63 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Nov 2018 18:05:10 -0800 Subject: Avoid calling through the vtable in the backends --- Alc/backends/dsound.cpp | 16 ++++++++-------- Alc/backends/qsa.cpp | 10 +++++----- Alc/backends/sndio.cpp | 4 ++-- Alc/backends/wasapi.cpp | 20 ++++++++++---------- Alc/backends/wave.cpp | 4 ++-- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index e760e9f5..10650175 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -257,9 +257,9 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) if(FAILED(err)) { ERR("Failed to get buffer caps: 0x%lx\n", err); - ALCdevice_Lock(device); + ALCdsoundPlayback_lock(self); aluHandleDisconnect(device, "Failure retrieving playback buffer info: 0x%lx", err); - ALCdevice_Unlock(device); + ALCdsoundPlayback_unlock(self); return 1; } @@ -285,9 +285,9 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) if(FAILED(err)) { ERR("Failed to play buffer: 0x%lx\n", err); - ALCdevice_Lock(device); + ALCdsoundPlayback_lock(self); aluHandleDisconnect(device, "Failure starting playback: 0x%lx", err); - ALCdevice_Unlock(device); + ALCdsoundPlayback_unlock(self); return 1; } Playing = true; @@ -323,10 +323,10 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) if(SUCCEEDED(err)) { // If we have an active context, mix data directly into output buffer otherwise fill with silence - ALCdevice_Lock(device); + ALCdsoundPlayback_lock(self); aluMixData(device, WritePtr1, WriteCnt1/FrameSize); aluMixData(device, WritePtr2, WriteCnt2/FrameSize); - ALCdevice_Unlock(device); + ALCdsoundPlayback_unlock(self); // Unlock output buffer only when successfully locked Buffer->Unlock(WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); @@ -334,9 +334,9 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) else { ERR("Buffer lock error: %#lx\n", err); - ALCdevice_Lock(device); + ALCdsoundPlayback_lock(self); aluHandleDisconnect(device, "Failed to lock output buffer: 0x%lx", err); - ALCdevice_Unlock(device); + ALCdsoundPlayback_unlock(self); return 1; } diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index 778e9e44..b2890705 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -188,7 +188,7 @@ DEFINE_ALCBACKEND_VTABLE(PlaybackWrapper); FORCE_ALIGN static int qsa_proc_playback(void *ptr) { - PlaybackWrapper *self = ptr; + PlaybackWrapper *self = static_cast(ptr); ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; qsa_data *data = self->ExtraData; snd_pcm_channel_status_t status; @@ -211,7 +211,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) device->FmtChans, device->FmtType, device->AmbiOrder ); - V0(device->Backend,lock)(); + PlaybackWrapper_lock(self); while(!ATOMIC_LOAD(&data->killNow, almemory_order_acquire)) { FD_ZERO(&wfds); @@ -220,9 +220,9 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) timeout.tv_usec=0; /* Select also works like time slice to OS */ - V0(device->Backend,unlock)(); + PlaybackWrapper_unlock(self); sret = select(data->audio_fd+1, NULL, &wfds, NULL, &timeout); - V0(device->Backend,lock)(); + PlaybackWrapper_lock(self); if(sret == -1) { ERR("select error: %s\n", strerror(errno)); @@ -269,7 +269,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) } } } - V0(device->Backend,unlock)(); + PlaybackWrapper_unlock(self); return 0; } diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index e35ce34e..818e107c 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -117,9 +117,9 @@ static int SndioPlayback_mixerProc(void *ptr) if(wrote == 0) { ERR("sio_write failed\n"); - ALCdevice_Lock(device); + SndioPlayback_lock(self); aluHandleDisconnect(device, "Failed to write playback samples"); - ALCdevice_Unlock(device); + SndioPlayback_unlock(self); break; } diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 50c0baa8..22edc09f 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -576,9 +576,9 @@ FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self) if(FAILED(hr)) { ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); - V0(device->Backend,lock)(); + ALCwasapiPlayback_lock(self); aluHandleDisconnect(device, "COM init failed: 0x%08lx", hr); - V0(device->Backend,unlock)(); + ALCwasapiPlayback_unlock(self); return 1; } @@ -594,9 +594,9 @@ FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self) if(FAILED(hr)) { ERR("Failed to get padding: 0x%08lx\n", hr); - V0(device->Backend,lock)(); + ALCwasapiPlayback_lock(self); aluHandleDisconnect(device, "Failed to retrieve buffer padding: 0x%08lx", hr); - V0(device->Backend,unlock)(); + ALCwasapiPlayback_unlock(self); break; } self->mPadding.store(written, std::memory_order_relaxed); @@ -625,9 +625,9 @@ FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self) if(FAILED(hr)) { ERR("Failed to buffer data: 0x%08lx\n", hr); - V0(device->Backend,lock)(); + ALCwasapiPlayback_lock(self); aluHandleDisconnect(device, "Failed to send playback samples: 0x%08lx", hr); - V0(device->Backend,unlock)(); + ALCwasapiPlayback_unlock(self); break; } } @@ -1247,9 +1247,9 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) if(FAILED(hr)) { ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); - V0(device->Backend,lock)(); + ALCwasapiCapture_lock(self); aluHandleDisconnect(device, "COM init failed: 0x%08lx", hr); - V0(device->Backend,unlock)(); + ALCwasapiCapture_unlock(self); return 1; } @@ -1327,9 +1327,9 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) if(FAILED(hr)) { - V0(device->Backend,lock)(); + ALCwasapiCapture_lock(self); aluHandleDisconnect(device, "Failed to capture samples: 0x%08lx", hr); - V0(device->Backend,unlock)(); + ALCwasapiCapture_unlock(self); break; } diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index 2b10d286..ea57ba65 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -193,9 +193,9 @@ static int ALCwaveBackend_mixerProc(ALCwaveBackend *self) if(ferror(self->mFile)) { ERR("Error writing to file\n"); - ALCdevice_Lock(device); + ALCwaveBackend_lock(self); aluHandleDisconnect(device, "Failed to write playback samples"); - ALCdevice_Unlock(device); + ALCwaveBackend_unlock(self); break; } } -- cgit v1.2.3 From 5867c7b8c213aa47659e7c6e6cafddc643d9ea76 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Nov 2018 19:45:26 -0800 Subject: Don't bother inlining some functions --- Alc/ALc.c | 3 --- Alc/backends/base.cpp | 14 ++++++++++++++ Alc/backends/base.h | 16 +++------------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index cc51a3d7..79bf2cce 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1590,9 +1590,6 @@ extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum User extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); extern inline ALuint64 GetDeviceClockTime(ALCdevice *device); -extern inline void ALCdevice_Lock(ALCdevice *device); -extern inline void ALCdevice_Unlock(ALCdevice *device); -extern inline ClockLatency GetClockLatency(ALCdevice *device); extern inline void alstr_reset(al_string *str); extern inline size_t alstr_length(const_al_string str); diff --git a/Alc/backends/base.cpp b/Alc/backends/base.cpp index 8173f554..4a20518d 100644 --- a/Alc/backends/base.cpp +++ b/Alc/backends/base.cpp @@ -9,6 +9,20 @@ #include "backends/base.h" +void ALCdevice_Lock(ALCdevice *device) +{ V0(device->Backend,lock)(); } + +void ALCdevice_Unlock(ALCdevice *device) +{ V0(device->Backend,unlock)(); } + +ClockLatency GetClockLatency(ALCdevice *device) +{ + ClockLatency ret = V0(device->Backend,getClockLatency)(); + ret.Latency += device->FixedLatency; + return ret; +} + + /* Base ALCbackend method implementations. */ void ALCbackend_Construct(ALCbackend *self, ALCdevice *device) { diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 03db56e9..bf60a744 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -156,20 +156,10 @@ ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void); ALCbackendFactory *ALCloopbackFactory_getFactory(void); -inline void ALCdevice_Lock(ALCdevice *device) -{ V0(device->Backend,lock)(); } - -inline void ALCdevice_Unlock(ALCdevice *device) -{ V0(device->Backend,unlock)(); } - - -inline ClockLatency GetClockLatency(ALCdevice *device) -{ - ClockLatency ret = V0(device->Backend,getClockLatency)(); - ret.Latency += device->FixedLatency; - return ret; -} +void ALCdevice_Lock(ALCdevice *device); +void ALCdevice_Unlock(ALCdevice *device); +ClockLatency GetClockLatency(ALCdevice *device); #ifdef __cplusplus } /* extern "C" */ -- cgit v1.2.3 From a5f68c21214e6f85ade835cd29045026797ac2a4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Nov 2018 20:26:32 -0800 Subject: Avoid using ATOMIC_FLAG Although it cant potentially be better than a regular atomic, it presents compatibility issues when non-C11 atomics are mixed with C++ --- Alc/ALc.c | 14 +++++++------- OpenAL32/Include/alAuxEffectSlot.h | 2 +- OpenAL32/Include/alListener.h | 2 +- OpenAL32/Include/alMain.h | 2 +- OpenAL32/Include/alSource.h | 2 +- OpenAL32/alAuxEffectSlot.c | 6 +++--- OpenAL32/alListener.c | 4 ++-- OpenAL32/alSource.c | 13 +++++-------- OpenAL32/alState.c | 2 +- common/atomic.h | 30 ------------------------------ common/rwlock.c | 10 +++++----- common/rwlock.h | 9 +++++---- 12 files changed, 32 insertions(+), 64 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 79bf2cce..414e1bfa 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1624,9 +1624,9 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) while((ATOMIC_LOAD(&context->UpdateCount, almemory_order_acquire)&1) != 0) althrd_yield(); - if(!ATOMIC_FLAG_TEST_AND_SET(&context->PropsClean, almemory_order_acq_rel)) + if(!ATOMIC_EXCHANGE(&context->PropsClean, AL_TRUE, almemory_order_acq_rel)) UpdateContextProps(context); - if(!ATOMIC_FLAG_TEST_AND_SET(&context->Listener->PropsClean, almemory_order_acq_rel)) + if(!ATOMIC_EXCHANGE(&context->Listener->PropsClean, AL_TRUE, almemory_order_acq_rel)) UpdateListenerProps(context); UpdateAllEffectSlotProps(context); UpdateAllSourceProps(context); @@ -2330,7 +2330,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } } - ATOMIC_FLAG_CLEAR(&source->PropsClean, almemory_order_release); + ATOMIC_STORE(&source->PropsClean, AL_FALSE, almemory_order_release); } } @@ -2367,9 +2367,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } almtx_unlock(&context->SourceLock); - ATOMIC_FLAG_TEST_AND_SET(&context->PropsClean, almemory_order_release); + ATOMIC_STORE(&context->PropsClean, AL_TRUE, almemory_order_release); UpdateContextProps(context); - ATOMIC_FLAG_TEST_AND_SET(&context->Listener->PropsClean, almemory_order_release); + ATOMIC_STORE(&context->Listener->PropsClean, AL_TRUE, almemory_order_release); UpdateListenerProps(context); UpdateAllSourceProps(context); almtx_unlock(&context->PropLock); @@ -2606,7 +2606,7 @@ static ALvoid InitContext(ALCcontext *Context) listener->Up[0] = 0.0f; listener->Up[1] = 1.0f; listener->Up[2] = 0.0f; - ATOMIC_FLAG_TEST_AND_SET(&listener->PropsClean, almemory_order_relaxed); + ATOMIC_INIT(&listener->PropsClean, AL_TRUE); ATOMIC_INIT(&listener->Update, NULL); @@ -2642,7 +2642,7 @@ static ALvoid InitContext(ALCcontext *Context) Context->DopplerVelocity = 1.0f; Context->SpeedOfSound = SPEEDOFSOUNDMETRESPERSEC; Context->MetersPerUnit = AL_DEFAULT_METERS_PER_UNIT; - ATOMIC_FLAG_TEST_AND_SET(&Context->PropsClean, almemory_order_relaxed); + ATOMIC_INIT(&Context->PropsClean, AL_TRUE); ATOMIC_INIT(&Context->DeferUpdates, AL_FALSE); alsem_init(&Context->EventSem, 0); Context->AsyncEvents = NULL; diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 97a3906d..16de9a79 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -111,7 +111,7 @@ typedef struct ALeffectslot { ALeffectState *State; } Effect; - ATOMIC_FLAG PropsClean; + ATOMIC(ALenum) PropsClean; RefCount ref; diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h index 0d80a8d7..9efadf47 100644 --- a/OpenAL32/Include/alListener.h +++ b/OpenAL32/Include/alListener.h @@ -36,7 +36,7 @@ typedef struct ALlistener { ALfloat Up[3]; ALfloat Gain; - ATOMIC_FLAG PropsClean; + ATOMIC(ALenum) PropsClean; /* Pointer to the most recent property values that are awaiting an update. */ diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 8cb22615..666a8ade 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -808,7 +808,7 @@ struct ALCcontext_struct { ALfloat SpeedOfSound; ALfloat MetersPerUnit; - ATOMIC_FLAG PropsClean; + ATOMIC(ALenum) PropsClean; ATOMIC(ALenum) DeferUpdates; almtx_t PropLock; diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 5f07c09d..f7749de3 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -98,7 +98,7 @@ typedef struct ALsource { /** Source Buffer Queue head. */ ALbufferlistitem *queue; - ATOMIC_FLAG PropsClean; + ATOMIC(ALenum) PropsClean; /* Index into the context's Voices array. Lazily updated, only checked and * reset when looking up the voice. diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index e1d84bb9..4758646f 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -103,7 +103,7 @@ static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \ UpdateEffectSlotProps(slot, context); \ else \ - ATOMIC_FLAG_CLEAR(&slot->PropsClean, almemory_order_release); \ + ATOMIC_STORE(&slot->PropsClean, AL_FALSE, almemory_order_release); \ } while(0) @@ -679,7 +679,7 @@ ALenum InitEffectSlot(ALeffectslot *slot) slot->Gain = 1.0; slot->AuxSendAuto = AL_TRUE; - ATOMIC_FLAG_TEST_AND_SET(&slot->PropsClean, almemory_order_relaxed); + ATOMIC_INIT(&slot->PropsClean, AL_TRUE); InitRef(&slot->ref, 0); ATOMIC_INIT(&slot->Update, NULL); @@ -773,7 +773,7 @@ void UpdateAllEffectSlotProps(ALCcontext *context) for(i = 0;i < auxslots->count;i++) { ALeffectslot *slot = auxslots->slot[i]; - if(!ATOMIC_FLAG_TEST_AND_SET(&slot->PropsClean, almemory_order_acq_rel)) + if(!ATOMIC_EXCHANGE(&slot->PropsClean, AL_TRUE, almemory_order_acq_rel)) UpdateEffectSlotProps(slot, context); } UnlockEffectSlotList(context); diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c index f1ac3ff4..700fa0af 100644 --- a/OpenAL32/alListener.c +++ b/OpenAL32/alListener.c @@ -30,7 +30,7 @@ if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \ UpdateListenerProps(context); \ else \ - ATOMIC_FLAG_CLEAR(&listener->PropsClean, almemory_order_release); \ + ATOMIC_STORE(&listener->PropsClean, AL_FALSE, almemory_order_release);\ } while(0) @@ -60,7 +60,7 @@ AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) UpdateContextProps(context); else - ATOMIC_FLAG_CLEAR(&context->PropsClean, almemory_order_release); + ATOMIC_STORE(&context->PropsClean, AL_FALSE, almemory_order_release); break; default: diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 1f76a069..2eb69cb9 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -519,7 +519,7 @@ static ALint Int64ValsByProp(ALenum prop) (voice=GetSourceVoice(Source, Context)) != NULL) \ UpdateSourceProps(Source, voice, device->NumAuxSends, Context); \ else \ - ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release); \ + ATOMIC_STORE(&Source->PropsClean, AL_FALSE, almemory_order_release); \ } while(0) static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values) @@ -1036,7 +1036,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p if((voice=GetSourceVoice(Source, Context)) != NULL) UpdateSourceProps(Source, voice, device->NumAuxSends, Context); else - ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release); + ATOMIC_STORE(&Source->PropsClean, AL_FALSE, almemory_order_release); } else { @@ -2488,7 +2488,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) voice = context->Voices[vidx]; ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acquire); + ATOMIC_EXCHANGE(&source->PropsClean, AL_TRUE, almemory_order_acquire); UpdateSourceProps(source, voice, device->NumAuxSends, context); /* A source that's not playing or paused has any offset applied when it @@ -3109,10 +3109,7 @@ static void InitSourceParams(ALsource *Source, ALsizei num_sends) Source->queue = NULL; - /* No way to do an 'init' here, so just test+set with relaxed ordering and - * ignore the test. - */ - ATOMIC_FLAG_TEST_AND_SET(&Source->PropsClean, almemory_order_relaxed); + ATOMIC_INIT(&Source->PropsClean, AL_TRUE); Source->VoiceIdx = -1; } @@ -3246,7 +3243,7 @@ void UpdateAllSourceProps(ALCcontext *context) { ALvoice *voice = context->Voices[pos]; ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire); - if(source && !ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acq_rel)) + if(source && !ATOMIC_EXCHANGE(&source->PropsClean, AL_TRUE, almemory_order_acq_rel)) UpdateSourceProps(source, voice, num_sends, context); } } diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index ce93e143..8be08435 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -68,7 +68,7 @@ AL_API const ALchar* AL_APIENTRY alsoft_get_version(void) if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \ UpdateContextProps(context); \ else \ - ATOMIC_FLAG_CLEAR(&context->PropsClean, almemory_order_release); \ + ATOMIC_STORE(&context->PropsClean, AL_FALSE, almemory_order_release); \ } while(0) diff --git a/common/atomic.h b/common/atomic.h index 17e616bb..2c81f62f 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -43,8 +43,6 @@ using std::memory_order_release; using std::memory_order_acq_rel; using std::memory_order_seq_cst; -using std::atomic_flag; - using std::atomic_init; using std::atomic_load_explicit; using std::atomic_store_explicit; @@ -53,8 +51,6 @@ using std::atomic_fetch_sub_explicit; using std::atomic_exchange_explicit; using std::atomic_compare_exchange_strong_explicit; using std::atomic_compare_exchange_weak_explicit; -using std::atomic_flag_test_and_set_explicit; -using std::atomic_flag_clear_explicit; using std::atomic_thread_fence; #else @@ -79,11 +75,9 @@ extern "C" { #define almemory_order_seq_cst memory_order_seq_cst #define ATOMIC(T) _Atomic(T) -#define ATOMIC_FLAG atomic_flag #define ATOMIC_INIT atomic_init #define ATOMIC_INIT_STATIC ATOMIC_VAR_INIT -/*#define ATOMIC_FLAG_INIT ATOMIC_FLAG_INIT*/ #define ATOMIC_LOAD atomic_load_explicit #define ATOMIC_STORE atomic_store_explicit @@ -95,9 +89,6 @@ extern "C" { #define ATOMIC_COMPARE_EXCHANGE_STRONG atomic_compare_exchange_strong_explicit #define ATOMIC_COMPARE_EXCHANGE_WEAK atomic_compare_exchange_weak_explicit -#define ATOMIC_FLAG_TEST_AND_SET atomic_flag_test_and_set_explicit -#define ATOMIC_FLAG_CLEAR atomic_flag_clear_explicit - #define ATOMIC_THREAD_FENCE atomic_thread_fence /* Atomics using GCC intrinsics */ @@ -113,11 +104,9 @@ enum almemory_order { }; #define ATOMIC(T) struct { T volatile value; } -#define ATOMIC_FLAG ATOMIC(int) #define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0) #define ATOMIC_INIT_STATIC(_newval) {(_newval)} -#define ATOMIC_FLAG_INIT ATOMIC_INIT_STATIC(0) #define ATOMIC_LOAD(_val, _MO) __extension__({ \ __typeof((_val)->value) _r = (_val)->value; \ @@ -142,15 +131,6 @@ enum almemory_order { *(_oldval) == _o; \ }) -#define ATOMIC_FLAG_TEST_AND_SET(_val, _MO) __extension__({ \ - __asm__ __volatile__("" ::: "memory"); \ - __sync_lock_test_and_set(&(_val)->value, 1); \ -}) -#define ATOMIC_FLAG_CLEAR(_val, _MO) __extension__({ \ - __sync_lock_release(&(_val)->value); \ - __asm__ __volatile__("" ::: "memory"); \ -}) - #define ATOMIC_THREAD_FENCE(order) do { \ enum { must_be_constant = (order) }; \ @@ -421,16 +401,6 @@ void *_al_invalid_atomic_ptr_size(); /* not defined */ #define ATOMIC_COMPARE_EXCHANGE_PTR_WEAK ATOMIC_COMPARE_EXCHANGE_PTR_STRONG #endif -/* If no ATOMIC_FLAG is defined, simulate one with an atomic int using exchange - * and store ops. - */ -#ifndef ATOMIC_FLAG -#define ATOMIC_FLAG ATOMIC(int) -#define ATOMIC_FLAG_INIT ATOMIC_INIT_STATIC(0) -#define ATOMIC_FLAG_TEST_AND_SET(_val, _MO) ATOMIC_EXCHANGE(_val, 1, _MO) -#define ATOMIC_FLAG_CLEAR(_val, _MO) ATOMIC_STORE(_val, 0, _MO) -#endif - #define ATOMIC_LOAD_SEQ(_val) ATOMIC_LOAD(_val, almemory_order_seq_cst) #define ATOMIC_STORE_SEQ(_val, _newval) ATOMIC_STORE(_val, _newval, almemory_order_seq_cst) diff --git a/common/rwlock.c b/common/rwlock.c index 67cf3acf..44237282 100644 --- a/common/rwlock.c +++ b/common/rwlock.c @@ -11,19 +11,19 @@ /* A simple spinlock. Yield the thread while the given integer is set by * another. Could probably be improved... */ #define LOCK(l) do { \ - while(ATOMIC_FLAG_TEST_AND_SET(&(l), almemory_order_acq_rel) == true) \ + while(ATOMIC_EXCHANGE(&(l), 1, almemory_order_acq_rel) == true) \ althrd_yield(); \ } while(0) -#define UNLOCK(l) ATOMIC_FLAG_CLEAR(&(l), almemory_order_release) +#define UNLOCK(l) ATOMIC_STORE(&(l), 0, almemory_order_release) void RWLockInit(RWLock *lock) { InitRef(&lock->read_count, 0); InitRef(&lock->write_count, 0); - ATOMIC_FLAG_CLEAR(&lock->read_lock, almemory_order_relaxed); - ATOMIC_FLAG_CLEAR(&lock->read_entry_lock, almemory_order_relaxed); - ATOMIC_FLAG_CLEAR(&lock->write_lock, almemory_order_relaxed); + ATOMIC_INIT(&lock->read_lock, 0); + ATOMIC_INIT(&lock->read_entry_lock, 0); + ATOMIC_INIT(&lock->write_lock, 0); } void ReadLock(RWLock *lock) diff --git a/common/rwlock.h b/common/rwlock.h index 8e36fa1a..fee1b070 100644 --- a/common/rwlock.h +++ b/common/rwlock.h @@ -11,12 +11,13 @@ extern "C" { typedef struct { RefCount read_count; RefCount write_count; - ATOMIC_FLAG read_lock; - ATOMIC_FLAG read_entry_lock; - ATOMIC_FLAG write_lock; + ATOMIC(int) read_lock; + ATOMIC(int) read_entry_lock; + ATOMIC(int) write_lock; } RWLock; #define RWLOCK_STATIC_INITIALIZE { ATOMIC_INIT_STATIC(0), ATOMIC_INIT_STATIC(0), \ - ATOMIC_FLAG_INIT, ATOMIC_FLAG_INIT, ATOMIC_FLAG_INIT } + ATOMIC_INIT_STATIC(0), ATOMIC_INIT_STATIC(0), \ + ATOMIC_INIT_STATIC(0) } void RWLockInit(RWLock *lock); void ReadLock(RWLock *lock); -- cgit v1.2.3 From 6510a44dbad72a4d83b987c9607293798b991f1b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Nov 2018 23:07:23 -0800 Subject: Use C++ more with the ALSA backend --- Alc/backends/alsa.cpp | 635 ++++++++++++++++++++++---------------------------- 1 file changed, 276 insertions(+), 359 deletions(-) diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index f9323bdb..35942e6b 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -24,11 +24,16 @@ #include #include +#include +#include +#include +#include +#include + #include "alMain.h" #include "alu.h" #include "alconfig.h" #include "ringbuffer.h" -#include "threads.h" #include "compat.h" #include "backends/base.h" @@ -36,7 +41,9 @@ #include -static const ALCchar alsaDevice[] = "ALSA Default"; +namespace { + +constexpr ALCchar alsaDevice[] = "ALSA Default"; #ifdef HAVE_DYNLOAD @@ -115,7 +122,7 @@ static const ALCchar alsaDevice[] = "ALSA Default"; MAGIC(snd_config_update_free_global) static void *alsa_handle; -#define MAKE_FUNC(f) static decltype(f) * p##f +#define MAKE_FUNC(f) decltype(f) * p##f ALSA_FUNCS(MAKE_FUNC); #undef MAKE_FUNC @@ -196,14 +203,14 @@ ALSA_FUNCS(MAKE_FUNC); #endif -static ALCboolean alsa_load(void) +bool alsa_load(void) { - ALCboolean error = ALC_FALSE; + bool error{false}; #ifdef HAVE_DYNLOAD if(!alsa_handle) { - al_string missing_funcs = AL_STRING_INIT_STATIC(); + std::string missing_funcs; alsa_handle = LoadLib("libasound.so.2"); if(!alsa_handle) @@ -215,9 +222,9 @@ static ALCboolean alsa_load(void) error = ALC_FALSE; #define LOAD_FUNC(f) do { \ p##f = reinterpret_cast(GetSymbol(alsa_handle, #f)); \ - if(p##f == NULL) { \ - error = ALC_TRUE; \ - alstr_append_cstr(&missing_funcs, "\n" #f); \ + if(p##f == nullptr) { \ + error = true; \ + missing_funcs += "\n" #f; \ } \ } while(0) ALSA_FUNCS(LOAD_FUNC); @@ -225,11 +232,10 @@ static ALCboolean alsa_load(void) if(error) { - WARN("Missing expected functions:%s\n", alstr_get_cstr(missing_funcs)); + WARN("Missing expected functions:%s\n", missing_funcs.c_str()); CloseLib(alsa_handle); - alsa_handle = NULL; + alsa_handle = nullptr; } - alstr_reset(&missing_funcs); } #endif @@ -237,174 +243,158 @@ static ALCboolean alsa_load(void) } -typedef struct { - al_string name; - al_string device_name; -} DevMap; -TYPEDEF_VECTOR(DevMap, vector_DevMap) +struct DevMap { + std::string name; + std::string device_name; -static vector_DevMap PlaybackDevices; -static vector_DevMap CaptureDevices; + template + DevMap(StrT0&& name_, StrT1&& devname_) + : name{std::forward(name_)}, device_name{std::forward(devname_)} + { } +}; -static void clear_devlist(vector_DevMap *devlist) -{ -#define FREE_DEV(i) do { \ - AL_STRING_DEINIT((i)->name); \ - AL_STRING_DEINIT((i)->device_name); \ -} while(0) - VECTOR_FOR_EACH(DevMap, *devlist, FREE_DEV); - VECTOR_RESIZE(*devlist, 0, 0); -#undef FREE_DEV -} +std::vector PlaybackDevices; +std::vector CaptureDevices; -static const char *prefix_name(snd_pcm_stream_t stream) +const char *prefix_name(snd_pcm_stream_t stream) { assert(stream == SND_PCM_STREAM_PLAYBACK || stream == SND_PCM_STREAM_CAPTURE); return (stream==SND_PCM_STREAM_PLAYBACK) ? "device-prefix" : "capture-prefix"; } -static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList) +std::vector probe_devices(snd_pcm_stream_t stream) { - const char *main_prefix = "plughw:"; - snd_ctl_t *handle; - snd_ctl_card_info_t *info; - snd_pcm_info_t *pcminfo; - int card, err, dev; - DevMap entry; - - clear_devlist(DeviceList); + std::vector devlist; + snd_ctl_card_info_t *info; snd_ctl_card_info_malloc(&info); + snd_pcm_info_t *pcminfo; snd_pcm_info_malloc(&pcminfo); - AL_STRING_INIT(entry.name); - AL_STRING_INIT(entry.device_name); - alstr_copy_cstr(&entry.name, alsaDevice); - alstr_copy_cstr(&entry.device_name, GetConfigValue( - NULL, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ? "device" : "capture", "default" - )); - VECTOR_PUSH_BACK(*DeviceList, entry); + devlist.emplace_back(alsaDevice, + GetConfigValue(nullptr, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ? "device" : "capture", + "default") + ); if(stream == SND_PCM_STREAM_PLAYBACK) { - const char *customdevs, *sep, *next; - next = GetConfigValue(NULL, "alsa", "custom-devices", ""); - while((customdevs=next) != NULL && customdevs[0]) + const char *customdevs; + const char *next{GetConfigValue(nullptr, "alsa", "custom-devices", "")}; + while((customdevs=next) != nullptr && customdevs[0]) { next = strchr(customdevs, ';'); - sep = strchr(customdevs, '='); + const char *sep{strchr(customdevs, '=')}; if(!sep) { - al_string spec = AL_STRING_INIT_STATIC(); - if(next) - alstr_copy_range(&spec, customdevs, next++); - else - alstr_copy_cstr(&spec, customdevs); - ERR("Invalid ALSA device specification \"%s\"\n", alstr_get_cstr(spec)); - alstr_reset(&spec); + std::string spec{next ? std::string(customdevs, next++) : std::string(customdevs)}; + ERR("Invalid ALSA device specification \"%s\"\n", spec.c_str()); continue; } - AL_STRING_INIT(entry.name); - AL_STRING_INIT(entry.device_name); - alstr_copy_range(&entry.name, customdevs, sep++); - if(next) - alstr_copy_range(&entry.device_name, sep, next++); - else - alstr_copy_cstr(&entry.device_name, sep); - TRACE("Got device \"%s\", \"%s\"\n", alstr_get_cstr(entry.name), - alstr_get_cstr(entry.device_name)); - VECTOR_PUSH_BACK(*DeviceList, entry); + const char *oldsep{sep++}; + devlist.emplace_back(std::string(customdevs, oldsep), + next ? std::string(sep, next++) : std::string(sep)); + const auto &entry = devlist.back(); + TRACE("Got device \"%s\", \"%s\"\n", entry.name.c_str(), entry.device_name.c_str()); } } - card = -1; - if((err=snd_card_next(&card)) < 0) - ERR("Failed to find a card: %s\n", snd_strerror(err)); - ConfigValueStr(NULL, "alsa", prefix_name(stream), &main_prefix); - while(card >= 0) + const char *main_prefix{"plughw:"}; + ConfigValueStr(nullptr, "alsa", prefix_name(stream), &main_prefix); + + int card{-1}; + int err{snd_card_next(&card)}; + for(;err >= 0 && card >= 0;err = snd_card_next(&card)) { - const char *card_prefix = main_prefix; - const char *cardname, *cardid; - char name[256]; + std::string name{"hw:" + std::to_string(card)}; - snprintf(name, sizeof(name), "hw:%d", card); - if((err = snd_ctl_open(&handle, name, 0)) < 0) + snd_ctl_t *handle; + if((err=snd_ctl_open(&handle, name.c_str(), 0)) < 0) { ERR("control open (hw:%d): %s\n", card, snd_strerror(err)); - goto next_card; + continue; } - if((err = snd_ctl_card_info(handle, info)) < 0) + if((err=snd_ctl_card_info(handle, info)) < 0) { ERR("control hardware info (hw:%d): %s\n", card, snd_strerror(err)); snd_ctl_close(handle); - goto next_card; + continue; } - cardname = snd_ctl_card_info_get_name(info); - cardid = snd_ctl_card_info_get_id(info); + const char *cardname{snd_ctl_card_info_get_name(info)}; + const char *cardid{snd_ctl_card_info_get_id(info)}; + name = prefix_name(stream); + name += '-'; + name += cardid; - snprintf(name, sizeof(name), "%s-%s", prefix_name(stream), cardid); - ConfigValueStr(NULL, "alsa", name, &card_prefix); + const char *card_prefix{main_prefix}; + ConfigValueStr(nullptr, "alsa", name.c_str(), &card_prefix); - dev = -1; + int dev{-1}; while(1) { - const char *device_prefix = card_prefix; - const char *devname; - char device[128]; - if(snd_ctl_pcm_next_device(handle, &dev) < 0) ERR("snd_ctl_pcm_next_device failed\n"); - if(dev < 0) - break; + if(dev < 0) break; snd_pcm_info_set_device(pcminfo, dev); snd_pcm_info_set_subdevice(pcminfo, 0); snd_pcm_info_set_stream(pcminfo, stream); - if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) + if((err=snd_ctl_pcm_info(handle, pcminfo)) < 0) { if(err != -ENOENT) ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err)); continue; } - devname = snd_pcm_info_get_name(pcminfo); - - snprintf(name, sizeof(name), "%s-%s-%d", prefix_name(stream), cardid, dev); - ConfigValueStr(NULL, "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); - - TRACE("Got device \"%s\", \"%s\"\n", name, device); - AL_STRING_INIT(entry.name); - AL_STRING_INIT(entry.device_name); - alstr_copy_cstr(&entry.name, name); - alstr_copy_cstr(&entry.device_name, device); - VECTOR_PUSH_BACK(*DeviceList, entry); + /* "prefix-cardid-dev" */ + name = prefix_name(stream); + name += '-'; + name += cardid; + name += '-'; + name += std::to_string(dev); + const char *device_prefix{card_prefix}; + ConfigValueStr(nullptr, "alsa", name.c_str(), &device_prefix); + + /* "CardName, PcmName (CARD=cardid,DEV=dev)" */ + name = cardname; + name += ", "; + name += snd_pcm_info_get_name(pcminfo); + name += " (CARD="; + name += cardid; + name += ",DEV="; + name += std::to_string(dev); + name += ')'; + + /* "devprefixCARD=cardid,DEV=dev" */ + std::string device{device_prefix}; + device += "CARD="; + device += cardid; + device += ",DEV="; + device += std::to_string(dev); + + devlist.emplace_back(std::move(name), std::move(device)); + const auto &entry = devlist.back(); + TRACE("Got device \"%s\", \"%s\"\n", entry.name.c_str(), entry.device_name.c_str()); } snd_ctl_close(handle); - next_card: - if(snd_card_next(&card) < 0) { - ERR("snd_card_next failed\n"); - break; - } } + if(err < 0) + ERR("snd_card_next failed: %s\n", snd_strerror(err)); snd_pcm_info_free(pcminfo); snd_ctl_card_info_free(info); + + return devlist; } -static int verify_state(snd_pcm_t *handle) +int verify_state(snd_pcm_t *handle) { - snd_pcm_state_t state = snd_pcm_state(handle); - int err; + snd_pcm_state_t state{snd_pcm_state(handle)}; + int err; switch(state) { case SND_PCM_STATE_OPEN: @@ -431,19 +421,20 @@ static int verify_state(snd_pcm_t *handle) return state; } +} // namespace + struct ALCplaybackAlsa final : public ALCbackend { - snd_pcm_t *pcmHandle; + snd_pcm_t *pcmHandle{nullptr}; - ALvoid *buffer; - ALsizei size; + std::vector buffer; - ATOMIC(ALenum) killNow; - althrd_t thread; + std::atomic killNow{AL_TRUE}; + std::thread thread; }; -static int ALCplaybackAlsa_mixerProc(void *ptr); -static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr); +static int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self); +static int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self); static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device); static void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self); @@ -466,42 +457,31 @@ static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device) new (self) ALCplaybackAlsa{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCplaybackAlsa, ALCbackend, self); - - self->pcmHandle = NULL; - self->buffer = NULL; - - ATOMIC_INIT(&self->killNow, AL_TRUE); } void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self) { if(self->pcmHandle) snd_pcm_close(self->pcmHandle); - self->pcmHandle = NULL; + self->pcmHandle = nullptr; + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCplaybackAlsa(); } -static int ALCplaybackAlsa_mixerProc(void *ptr) +static int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) { - ALCplaybackAlsa *self = static_cast(ptr); - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - const snd_pcm_channel_area_t *areas = NULL; - snd_pcm_uframes_t update_size, num_updates; - snd_pcm_sframes_t avail, commitres; - snd_pcm_uframes_t offset, frames; - char *WritePtr; - int err; + ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); - update_size = device->UpdateSize; - num_updates = device->NumUpdates; - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) + snd_pcm_uframes_t update_size{device->UpdateSize}; + snd_pcm_uframes_t num_updates{device->NumUpdates}; + while(!self->killNow.load(std::memory_order_acquire)) { - int state = verify_state(self->pcmHandle); + int state{verify_state(self->pcmHandle)}; if(state < 0) { ERR("Invalid state detected: %s\n", snd_strerror(state)); @@ -511,7 +491,7 @@ static int ALCplaybackAlsa_mixerProc(void *ptr) break; } - avail = snd_pcm_avail_update(self->pcmHandle); + snd_pcm_sframes_t avail{snd_pcm_avail_update(self->pcmHandle)}; if(avail < 0) { ERR("available update failed: %s\n", snd_strerror(avail)); @@ -530,7 +510,7 @@ static int ALCplaybackAlsa_mixerProc(void *ptr) { if(state != SND_PCM_STATE_RUNNING) { - err = snd_pcm_start(self->pcmHandle); + int err{snd_pcm_start(self->pcmHandle)}; if(err < 0) { ERR("start failed: %s\n", snd_strerror(err)); @@ -547,19 +527,21 @@ static int ALCplaybackAlsa_mixerProc(void *ptr) ALCplaybackAlsa_lock(self); while(avail > 0) { - frames = avail; + snd_pcm_uframes_t frames{static_cast(avail)}; - err = snd_pcm_mmap_begin(self->pcmHandle, &areas, &offset, &frames); + const snd_pcm_channel_area_t *areas{}; + snd_pcm_uframes_t offset{}; + int err{snd_pcm_mmap_begin(self->pcmHandle, &areas, &offset, &frames)}; if(err < 0) { ERR("mmap begin error: %s\n", snd_strerror(err)); break; } - WritePtr = (char*)areas->addr + (offset * areas->step / 8); + char *WritePtr{(char*)areas->addr + (offset * areas->step / 8)}; aluMixData(device, WritePtr, frames); - commitres = snd_pcm_mmap_commit(self->pcmHandle, offset, frames); + snd_pcm_sframes_t commitres{snd_pcm_mmap_commit(self->pcmHandle, offset, frames)}; if(commitres < 0 || (commitres-frames) != 0) { ERR("mmap commit error: %s\n", @@ -575,23 +557,18 @@ static int ALCplaybackAlsa_mixerProc(void *ptr) return 0; } -static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr) +static int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self) { - ALCplaybackAlsa *self = static_cast(ptr); - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - snd_pcm_uframes_t update_size, num_updates; - snd_pcm_sframes_t avail; - char *WritePtr; - int err; + ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); - update_size = device->UpdateSize; - num_updates = device->NumUpdates; - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) + snd_pcm_uframes_t update_size{device->UpdateSize}; + snd_pcm_uframes_t num_updates{device->NumUpdates}; + while(!self->killNow.load(std::memory_order_acquire)) { - int state = verify_state(self->pcmHandle); + int state{verify_state(self->pcmHandle)}; if(state < 0) { ERR("Invalid state detected: %s\n", snd_strerror(state)); @@ -601,7 +578,7 @@ static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr) break; } - avail = snd_pcm_avail_update(self->pcmHandle); + snd_pcm_sframes_t avail{snd_pcm_avail_update(self->pcmHandle)}; if(avail < 0) { ERR("available update failed: %s\n", snd_strerror(avail)); @@ -619,7 +596,7 @@ static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr) { if(state != SND_PCM_STATE_RUNNING) { - err = snd_pcm_start(self->pcmHandle); + int err{snd_pcm_start(self->pcmHandle)}; if(err < 0) { ERR("start failed: %s\n", snd_strerror(err)); @@ -632,10 +609,9 @@ static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr) } ALCplaybackAlsa_lock(self); - WritePtr = static_cast(self->buffer); - avail = snd_pcm_bytes_to_frames(self->pcmHandle, self->size); + char *WritePtr{self->buffer.data()}; + avail = snd_pcm_bytes_to_frames(self->pcmHandle, self->buffer.size()); aluMixData(device, WritePtr, avail); - while(avail > 0) { int ret = snd_pcm_writei(self->pcmHandle, WritePtr, avail); @@ -676,32 +652,28 @@ static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr) static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - const char *driver = NULL; - int err; - + const char *driver{}; if(name) { - const DevMap *iter; - - if(VECTOR_SIZE(PlaybackDevices) == 0) - probe_devices(SND_PCM_STREAM_PLAYBACK, &PlaybackDevices); + if(PlaybackDevices.empty()) + PlaybackDevices = probe_devices(SND_PCM_STREAM_PLAYBACK); -#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, name) == 0) - VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); -#undef MATCH_NAME - if(iter == VECTOR_END(PlaybackDevices)) + auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + [name](const DevMap &entry) -> bool + { return entry.name == name; } + ); + if(iter == PlaybackDevices.cend()) return ALC_INVALID_VALUE; - driver = alstr_get_cstr(iter->device_name); + driver = iter->device_name.c_str(); } else { name = alsaDevice; - driver = GetConfigValue(NULL, "alsa", "device", "default"); + driver = GetConfigValue(nullptr, "alsa", "device", "default"); } TRACE("Opening device \"%s\"\n", driver); - err = snd_pcm_open(&self->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); + int err{snd_pcm_open(&self->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)}; if(err < 0) { ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(err)); @@ -711,6 +683,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(); + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; @@ -718,20 +691,9 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name) static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - snd_pcm_uframes_t periodSizeInFrames; - unsigned int periodLen, bufferLen; - snd_pcm_sw_params_t *sp = NULL; - snd_pcm_hw_params_t *hp = NULL; - snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN; - snd_pcm_access_t access; - unsigned int periods; - unsigned int rate; - const char *funcerr; - int allowmmap; - int dir; - int err; + ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + snd_pcm_format_t format{SND_PCM_FORMAT_UNKNOWN}; switch(device->FmtType) { case DevFmtByte: @@ -757,12 +719,18 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) break; } - allowmmap = GetConfigValueBool(alstr_get_cstr(device->DeviceName), "alsa", "mmap", 1); - periods = device->NumUpdates; - periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency; - bufferLen = periodLen * periods; - rate = device->Frequency; + bool allowmmap{!!GetConfigValueBool(alstr_get_cstr(device->DeviceName), "alsa", "mmap", 1)}; + ALuint periods{device->NumUpdates}; + ALuint periodLen{static_cast(device->UpdateSize * U64(1000000) / device->Frequency)}; + ALuint bufferLen{periodLen * periods}; + ALuint rate{device->Frequency}; + snd_pcm_uframes_t periodSizeInFrames; + snd_pcm_sw_params_t *sp{}; + snd_pcm_hw_params_t *hp{}; + snd_pcm_access_t access; + const char *funcerr; + int dir, err; snd_pcm_hw_params_malloc(&hp); #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error CHECK(snd_pcm_hw_params_any(self->pcmHandle, hp)); @@ -787,14 +755,13 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) { SND_PCM_FORMAT_S8, DevFmtByte }, { SND_PCM_FORMAT_U8, DevFmtUByte }, }; - size_t k; - for(k = 0;k < COUNTOF(formatlist);k++) + for(const auto &fmt : formatlist) { - format = formatlist[k].format; + format = fmt.format; if(snd_pcm_hw_params_test_format(self->pcmHandle, hp, format) >= 0) { - device->FmtType = formatlist[k].fmttype; + device->FmtType = fmt.fmttype; break; } } @@ -810,13 +777,12 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) DevFmtX71, DevFmtMono, }; - size_t k; - for(k = 0;k < COUNTOF(channellist);k++) + for(const auto &chan : channellist) { - if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(channellist[k], 0)) >= 0) + if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(chan, 0)) >= 0) { - device->FmtChans = channellist[k]; + device->FmtChans = chan; device->AmbiOrder = 0; break; } @@ -832,33 +798,33 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) } else if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 1) < 0) ERR("Failed to enable ALSA resampler\n"); - CHECK(snd_pcm_hw_params_set_rate_near(self->pcmHandle, hp, &rate, NULL)); + CHECK(snd_pcm_hw_params_set_rate_near(self->pcmHandle, hp, &rate, nullptr)); /* set buffer time (implicitly constrains period/buffer parameters) */ - if((err=snd_pcm_hw_params_set_buffer_time_near(self->pcmHandle, hp, &bufferLen, NULL)) < 0) + if((err=snd_pcm_hw_params_set_buffer_time_near(self->pcmHandle, hp, &bufferLen, nullptr)) < 0) ERR("snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err)); /* set period time (implicitly sets buffer size/bytes/time and period size/bytes) */ - if((err=snd_pcm_hw_params_set_period_time_near(self->pcmHandle, hp, &periodLen, NULL)) < 0) + if((err=snd_pcm_hw_params_set_period_time_near(self->pcmHandle, hp, &periodLen, nullptr)) < 0) ERR("snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err)); /* install and prepare hardware configuration */ CHECK(snd_pcm_hw_params(self->pcmHandle, hp)); + /* retrieve configuration info */ CHECK(snd_pcm_hw_params_get_access(hp, &access)); - CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL)); + CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, nullptr)); CHECK(snd_pcm_hw_params_get_periods(hp, &periods, &dir)); if(dir != 0) WARN("Inexact period count: %u (%d)\n", periods, dir); - snd_pcm_hw_params_free(hp); - hp = NULL; - snd_pcm_sw_params_malloc(&sp); + hp = nullptr; + snd_pcm_sw_params_malloc(&sp); CHECK(snd_pcm_sw_params_current(self->pcmHandle, sp)); CHECK(snd_pcm_sw_params_set_avail_min(self->pcmHandle, sp, periodSizeInFrames)); CHECK(snd_pcm_sw_params_set_stop_threshold(self->pcmHandle, sp, periodSizeInFrames*periods)); CHECK(snd_pcm_sw_params(self->pcmHandle, sp)); #undef CHECK snd_pcm_sw_params_free(sp); - sp = NULL; + sp = nullptr; device->NumUpdates = periods; device->UpdateSize = periodSizeInFrames; @@ -877,9 +843,9 @@ error: static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - int (*thread_func)(void*) = NULL; - snd_pcm_hw_params_t *hp = NULL; + ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + int (*thread_func)(ALCplaybackAlsa*){}; + snd_pcm_hw_params_t *hp{}; snd_pcm_access_t access; const char *funcerr; int err; @@ -891,17 +857,11 @@ static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) CHECK(snd_pcm_hw_params_get_access(hp, &access)); #undef CHECK snd_pcm_hw_params_free(hp); - hp = NULL; + hp = nullptr; - self->size = snd_pcm_frames_to_bytes(self->pcmHandle, device->UpdateSize); if(access == SND_PCM_ACCESS_RW_INTERLEAVED) { - self->buffer = al_malloc(16, self->size); - if(!self->buffer) - { - ERR("buffer malloc failed\n"); - return ALC_FALSE; - } + self->buffer.resize(snd_pcm_frames_to_bytes(self->pcmHandle, device->UpdateSize)); thread_func = ALCplaybackAlsa_mixerNoMMapProc; } else @@ -914,16 +874,19 @@ static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) } thread_func = ALCplaybackAlsa_mixerProc; } - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); - if(althrd_create(&self->thread, thread_func, self) != althrd_success) - { - ERR("Could not create playback thread\n"); - al_free(self->buffer); - self->buffer = NULL; - return ALC_FALSE; - } - return ALC_TRUE; + try { + self->killNow.store(AL_FALSE, std::memory_order_release); + self->thread = std::thread(thread_func, self); + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Could not create playback thread: %s\n", e.what()); + } + catch(...) { + } + self->buffer.clear(); + return ALC_FALSE; error: ERR("%s failed: %s\n", funcerr, snd_strerror(err)); @@ -933,32 +896,29 @@ error: static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self) { - int res; - - if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) + if(self->killNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->thread.joinable()) return; - althrd_join(self->thread, &res); - al_free(self->buffer); - self->buffer = NULL; + self->thread.join(); + + self->buffer.clear(); } static ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - snd_pcm_sframes_t delay = 0; + ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; ClockLatency ret; - int err; ALCplaybackAlsa_lock(self); ret.ClockTime = GetDeviceClockTime(device); - if((err=snd_pcm_delay(self->pcmHandle, &delay)) < 0) + snd_pcm_sframes_t delay{}; + int err{snd_pcm_delay(self->pcmHandle, &delay)}; + if(err < 0) { ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); delay = 0; } - if(delay < 0) delay = 0; - ret.Latency = delay * DEVICE_CLOCK_RES / device->Frequency; + ret.Latency = std::max(0, delay) * DEVICE_CLOCK_RES / device->Frequency; ALCplaybackAlsa_unlock(self); return ret; @@ -966,15 +926,14 @@ static ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self) struct ALCcaptureAlsa final : public ALCbackend { - snd_pcm_t *pcmHandle; + snd_pcm_t *pcmHandle{nullptr}; - ALvoid *buffer; - ALsizei size; + std::vector buffer; - ALboolean doCapture; - ll_ringbuffer_t *ring; + bool doCapture{false}; + ll_ringbuffer_t *ring{nullptr}; - snd_pcm_sframes_t last_avail; + snd_pcm_sframes_t last_avail{0}; }; static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device); @@ -998,23 +957,16 @@ static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device) new (self) ALCcaptureAlsa{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCcaptureAlsa, ALCbackend, self); - - self->pcmHandle = NULL; - self->buffer = NULL; - self->ring = NULL; } void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self) { if(self->pcmHandle) snd_pcm_close(self->pcmHandle); - self->pcmHandle = NULL; - - al_free(self->buffer); - self->buffer = NULL; + self->pcmHandle = nullptr; ll_ringbuffer_free(self->ring); - self->ring = NULL; + self->ring = nullptr; ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCcaptureAlsa(); @@ -1024,37 +976,28 @@ void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self) static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - const char *driver = NULL; - snd_pcm_hw_params_t *hp; - snd_pcm_uframes_t bufferSizeInFrames; - snd_pcm_uframes_t periodSizeInFrames; - ALboolean needring = AL_FALSE; - snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN; - const char *funcerr; - int err; - + const char *driver{}; if(name) { - const DevMap *iter; - - if(VECTOR_SIZE(CaptureDevices) == 0) - probe_devices(SND_PCM_STREAM_CAPTURE, &CaptureDevices); + if(CaptureDevices.empty()) + CaptureDevices = probe_devices(SND_PCM_STREAM_CAPTURE); -#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, name) == 0) - VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); -#undef MATCH_NAME - if(iter == VECTOR_END(CaptureDevices)) + auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), + [name](const DevMap &entry) -> bool + { return entry.name == name; } + ); + if(iter == CaptureDevices.cend()) return ALC_INVALID_VALUE; - driver = alstr_get_cstr(iter->device_name); + driver = iter->device_name.c_str(); } else { name = alsaDevice; - driver = GetConfigValue(NULL, "alsa", "capture", "default"); + driver = GetConfigValue(nullptr, "alsa", "capture", "default"); } TRACE("Opening device \"%s\"\n", driver); - err = snd_pcm_open(&self->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); + int err{snd_pcm_open(&self->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)}; if(err < 0) { ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err)); @@ -1064,6 +1007,7 @@ 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(); + snd_pcm_format_t format{SND_PCM_FORMAT_UNKNOWN}; switch(device->FmtType) { case DevFmtByte: @@ -1089,11 +1033,13 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) break; } - funcerr = NULL; - bufferSizeInFrames = maxu(device->UpdateSize*device->NumUpdates, - 100*device->Frequency/1000); - periodSizeInFrames = minu(bufferSizeInFrames, 25*device->Frequency/1000); + snd_pcm_uframes_t bufferSizeInFrames{maxu(device->UpdateSize*device->NumUpdates, + 100*device->Frequency/1000)}; + snd_pcm_uframes_t periodSizeInFrames{minu(bufferSizeInFrames, 25*device->Frequency/1000)}; + bool needring{false}; + const char *funcerr{}; + snd_pcm_hw_params_t *hp{}; snd_pcm_hw_params_malloc(&hp); #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error CHECK(snd_pcm_hw_params_any(self->pcmHandle, hp)); @@ -1109,18 +1055,18 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) if(snd_pcm_hw_params_set_buffer_size_min(self->pcmHandle, hp, &bufferSizeInFrames) < 0) { TRACE("Buffer too large, using intermediate ring buffer\n"); - needring = AL_TRUE; + needring = true; CHECK(snd_pcm_hw_params_set_buffer_size_near(self->pcmHandle, hp, &bufferSizeInFrames)); } /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ - CHECK(snd_pcm_hw_params_set_period_size_near(self->pcmHandle, hp, &periodSizeInFrames, NULL)); + CHECK(snd_pcm_hw_params_set_period_size_near(self->pcmHandle, hp, &periodSizeInFrames, nullptr)); /* install and prepare hardware configuration */ CHECK(snd_pcm_hw_params(self->pcmHandle, hp)); /* retrieve configuration info */ - CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL)); + CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, nullptr)); #undef CHECK snd_pcm_hw_params_free(hp); - hp = NULL; + hp = nullptr; if(needring) { @@ -1146,16 +1092,16 @@ error: error2: ll_ringbuffer_free(self->ring); - self->ring = NULL; + self->ring = nullptr; snd_pcm_close(self->pcmHandle); - self->pcmHandle = NULL; + self->pcmHandle = nullptr; return ALC_INVALID_VALUE; } static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self) { - int err = snd_pcm_prepare(self->pcmHandle); + int err{snd_pcm_prepare(self->pcmHandle)}; if(err < 0) ERR("prepare failed: %s\n", snd_strerror(err)); else @@ -1171,40 +1117,28 @@ static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self) return ALC_FALSE; } - self->doCapture = AL_TRUE; + self->doCapture = true; return ALC_TRUE; } static void ALCcaptureAlsa_stop(ALCcaptureAlsa *self) { - ALCuint avail; - int err; - /* OpenAL requires access to unread audio after stopping, but ALSA's * snd_pcm_drain is unreliable and snd_pcm_drop drops it. Capture what's * available now so it'll be available later after the drop. */ - avail = ALCcaptureAlsa_availableSamples(self); + ALCuint avail{ALCcaptureAlsa_availableSamples(self)}; if(!self->ring && avail > 0) { /* The ring buffer implicitly captures when checking availability. * Direct access needs to explicitly capture it into temp storage. */ - ALsizei size; - void *ptr; - - size = snd_pcm_frames_to_bytes(self->pcmHandle, avail); - ptr = al_malloc(16, size); - if(ptr) - { - ALCcaptureAlsa_captureSamples(self, ptr, avail); - al_free(self->buffer); - self->buffer = ptr; - self->size = size; - } + std::vector temp(snd_pcm_frames_to_bytes(self->pcmHandle, avail)); + ALCcaptureAlsa_captureSamples(self, temp.data(), avail); + self->buffer = std::move(temp); } - err = snd_pcm_drop(self->pcmHandle); + int err{snd_pcm_drop(self->pcmHandle)}; if(err < 0) ERR("drop failed: %s\n", snd_strerror(err)); - self->doCapture = AL_FALSE; + self->doCapture = false; } static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALCuint samples) @@ -1220,28 +1154,18 @@ static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buff self->last_avail -= samples; while(ATOMIC_LOAD(&device->Connected, almemory_order_acquire) && samples > 0) { - snd_pcm_sframes_t amt = 0; + snd_pcm_sframes_t amt{0}; - if(self->size > 0) + if(self->buffer.size() > 0) { /* First get any data stored from the last stop */ - amt = snd_pcm_bytes_to_frames(self->pcmHandle, self->size); + amt = snd_pcm_bytes_to_frames(self->pcmHandle, self->buffer.size()); if((snd_pcm_uframes_t)amt > samples) amt = samples; amt = snd_pcm_frames_to_bytes(self->pcmHandle, amt); - memcpy(buffer, self->buffer, amt); + memcpy(buffer, self->buffer.data(), amt); - if(self->size > amt) - { - memmove(self->buffer, static_cast(self->buffer)+amt, self->size - amt); - self->size -= amt; - } - else - { - al_free(self->buffer); - self->buffer = NULL; - self->size = 0; - } + self->buffer.erase(self->buffer.begin(), self->buffer.begin()+amt); amt = snd_pcm_bytes_to_frames(self->pcmHandle, amt); } else if(self->doCapture) @@ -1284,8 +1208,8 @@ static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buff static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - snd_pcm_sframes_t avail = 0; + snd_pcm_sframes_t avail{0}; if(ATOMIC_LOAD(&device->Connected, almemory_order_acquire) && self->doCapture) avail = snd_pcm_avail_update(self->pcmHandle); if(avail < 0) @@ -1309,7 +1233,7 @@ static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) if(!self->ring) { if(avail < 0) avail = 0; - avail += snd_pcm_bytes_to_frames(self->pcmHandle, self->size); + avail += snd_pcm_bytes_to_frames(self->pcmHandle, self->buffer.size()); if(avail > self->last_avail) self->last_avail = avail; return self->last_avail; } @@ -1317,13 +1241,10 @@ static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) while(avail > 0) { ll_ringbuffer_data_t vec[2]; - snd_pcm_sframes_t amt; - ll_ringbuffer_get_write_vector(self->ring, vec); if(vec[0].len == 0) break; - amt = (vec[0].len < (snd_pcm_uframes_t)avail) ? - vec[0].len : (snd_pcm_uframes_t)avail; + snd_pcm_sframes_t amt{std::min(vec[0].len, avail)}; amt = snd_pcm_readi(self->pcmHandle, vec[0].buf, amt); if(amt < 0) { @@ -1357,20 +1278,19 @@ static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) static ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - snd_pcm_sframes_t delay = 0; + ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; ClockLatency ret; - int err; ALCcaptureAlsa_lock(self); ret.ClockTime = GetDeviceClockTime(device); - if((err=snd_pcm_delay(self->pcmHandle, &delay)) < 0) + snd_pcm_sframes_t delay{}; + int err{snd_pcm_delay(self->pcmHandle, &delay)}; + if(err < 0) { ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); delay = 0; } - if(delay < 0) delay = 0; - ret.Latency = delay * DEVICE_CLOCK_RES / device->Frequency; + ret.Latency = std::max(0, delay) * DEVICE_CLOCK_RES / device->Frequency; ALCcaptureAlsa_unlock(self); return ret; @@ -1383,9 +1303,6 @@ struct ALCalsaBackendFactory final : public ALCbackendFactory { static ALCboolean ALCalsaBackendFactory_init(ALCalsaBackendFactory* UNUSED(self)) { - VECTOR_INIT(PlaybackDevices); - VECTOR_INIT(CaptureDevices); - if(!alsa_load()) return ALC_FALSE; return ALC_TRUE; @@ -1393,16 +1310,13 @@ static ALCboolean ALCalsaBackendFactory_init(ALCalsaBackendFactory* UNUSED(self) static void ALCalsaBackendFactory_deinit(ALCalsaBackendFactory* UNUSED(self)) { - clear_devlist(&PlaybackDevices); - VECTOR_DEINIT(PlaybackDevices); - - clear_devlist(&CaptureDevices); - VECTOR_DEINIT(CaptureDevices); + PlaybackDevices.clear(); + CaptureDevices.clear(); #ifdef HAVE_DYNLOAD if(alsa_handle) CloseLib(alsa_handle); - alsa_handle = NULL; + alsa_handle = nullptr; #endif } @@ -1415,23 +1329,26 @@ static ALCboolean ALCalsaBackendFactory_querySupport(ALCalsaBackendFactory* UNUS static void ALCalsaBackendFactory_probe(ALCalsaBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { + auto add_device = [outnames](const DevMap &entry) -> void + { + const char *name{entry.name.c_str()}; + size_t namelen{entry.name.length()}; + /* +1 to also append the null char (to ensure a null-separated list + * and double-null terminated list). + */ + alstr_append_range(outnames, name, name + namelen+1); + }; switch(type) { -#define APPEND_OUTNAME(i) do { \ - if(!alstr_empty((i)->name)) \ - alstr_append_range(outnames, VECTOR_BEGIN((i)->name), \ - VECTOR_END((i)->name)+1); \ -} while(0) case ALL_DEVICE_PROBE: - probe_devices(SND_PCM_STREAM_PLAYBACK, &PlaybackDevices); - VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_OUTNAME); + PlaybackDevices = probe_devices(SND_PCM_STREAM_PLAYBACK); + std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); break; case CAPTURE_DEVICE_PROBE: - probe_devices(SND_PCM_STREAM_CAPTURE, &CaptureDevices); - VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_OUTNAME); + CaptureDevices = probe_devices(SND_PCM_STREAM_CAPTURE); + std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); break; -#undef APPEND_OUTNAME } } @@ -1441,18 +1358,18 @@ static ALCbackend* ALCalsaBackendFactory_createBackend(ALCalsaBackendFactory* UN { ALCplaybackAlsa *backend; NEW_OBJ(backend, ALCplaybackAlsa)(device); - if(!backend) return NULL; + if(!backend) return nullptr; return STATIC_CAST(ALCbackend, backend); } if(type == ALCbackend_Capture) { ALCcaptureAlsa *backend; NEW_OBJ(backend, ALCcaptureAlsa)(device); - if(!backend) return NULL; + if(!backend) return nullptr; return STATIC_CAST(ALCbackend, backend); } - return NULL; + return nullptr; } DEFINE_ALCBACKENDFACTORY_VTABLE(ALCalsaBackendFactory); -- cgit v1.2.3 From c3ee2061295dca521449bcea8aa14f092c83986c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Nov 2018 23:23:46 -0800 Subject: Use an anonymous namespace in the OSS backend --- Alc/backends/oss.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 03e8d3ef..279a2b99 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -70,19 +70,21 @@ #define ALC_OSS_DEVNODE_TRUC #endif +namespace { + struct oss_device { const ALCchar *handle; const char *path; struct oss_device *next; }; -static struct oss_device oss_playback = { +struct oss_device oss_playback = { "OSS Default", "/dev/dsp", nullptr }; -static struct oss_device oss_capture = { +struct oss_device oss_capture = { "OSS Default", "/dev/dsp", nullptr @@ -92,14 +94,14 @@ static struct oss_device oss_capture = { #define DSP_CAP_OUTPUT 0x00020000 #define DSP_CAP_INPUT 0x00010000 -static void ALCossListPopulate(struct oss_device *UNUSED(devlist), int UNUSED(type_flag)) +void ALCossListPopulate(struct oss_device *UNUSED(devlist), int UNUSED(type_flag)) { } #else #ifndef HAVE_STRNLEN -static size_t my_strnlen(const char *str, size_t maxlen) +size_t my_strnlen(const char *str, size_t maxlen) { const char *end = static_cast(memchr(str, 0, maxlen)); if(!end) return maxlen; @@ -108,7 +110,7 @@ static size_t my_strnlen(const char *str, size_t maxlen) #define strnlen my_strnlen #endif -static void ALCossListAppend(struct oss_device *list, const char *handle, size_t hlen, const char *path, size_t plen) +void ALCossListAppend(struct oss_device *list, const char *handle, size_t hlen, const char *path, size_t plen) { struct oss_device *next; struct oss_device *last; @@ -158,7 +160,7 @@ static void ALCossListAppend(struct oss_device *list, const char *handle, size_t TRACE("Got device \"%s\", \"%s\"\n", next->handle, next->path); } -static void ALCossListPopulate(struct oss_device *devlist, int type_flag) +void ALCossListPopulate(struct oss_device *devlist, int type_flag) { struct oss_sysinfo si; struct oss_audioinfo ai; @@ -209,7 +211,7 @@ done: #endif -static void ALCossListFree(struct oss_device *list) +void ALCossListFree(struct oss_device *list) { struct oss_device *cur; if(list == nullptr) @@ -227,7 +229,7 @@ static void ALCossListFree(struct oss_device *list) } } -static int log2i(ALCuint x) +int log2i(ALCuint x) { int y = 0; while (x > 1) @@ -238,6 +240,8 @@ static int log2i(ALCuint x) return y; } +} // namespace + struct ALCplaybackOSS final : public ALCbackend { int fd; -- cgit v1.2.3 From 6ae217d0052bcd1434e573fa16ea325996baf209 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Nov 2018 23:26:42 -0800 Subject: Fix some comment indentation --- Alc/backends/alsa.cpp | 6 +++--- Alc/backends/pulseaudio.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index 35942e6b..d40261cb 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -1333,9 +1333,9 @@ static void ALCalsaBackendFactory_probe(ALCalsaBackendFactory* UNUSED(self), enu { const char *name{entry.name.c_str()}; size_t namelen{entry.name.length()}; - /* +1 to also append the null char (to ensure a null-separated list - * and double-null terminated list). - */ + /* +1 to also append the null char (to ensure a null-separated list and + * double-null terminated list). + */ alstr_append_range(outnames, name, name + namelen+1); }; switch(type) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 2a2de2a6..09b55229 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -1816,9 +1816,9 @@ static void PulseBackendFactory_probe(PulseBackendFactory* UNUSED(self), enum De { const char *name{entry.name.c_str()}; size_t namelen{entry.name.length()}; - /* +1 to also append the null char (to ensure a null-separated list - * and double-null terminated list). - */ + /* +1 to also append the null char (to ensure a null-separated list and + * double-null terminated list). + */ alstr_append_range(outnames, name, name + namelen+1); }; switch(type) -- cgit v1.2.3 From b15dcea4bb0a18b1dd5b426a07f237c3c7ff118d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 14 Nov 2018 00:07:50 -0800 Subject: Move extern inline declarations to their own C source --- Alc/ALc.c | 19 ------- Alc/ALu.c | 63 ----------------------- Alc/filters/filter.c | 6 --- Alc/inldefs.c | 122 +++++++++++++++++++++++++++++++++++++++++++++ Alc/mixvoice.c | 3 -- CMakeLists.txt | 1 + OpenAL32/alAuxEffectSlot.c | 3 -- OpenAL32/alEffect.c | 4 -- OpenAL32/alFilter.c | 3 -- 9 files changed, 123 insertions(+), 101 deletions(-) create mode 100644 Alc/inldefs.c diff --git a/Alc/ALc.c b/Alc/ALc.c index 414e1bfa..3468f6a3 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1304,7 +1304,6 @@ const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) return "(unknown channels)"; } -extern inline ALsizei FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type, ALsizei ambiorder); ALsizei BytesFromDevFmt(enum DevFmtType type) { switch(type) @@ -1578,24 +1577,6 @@ void SetDefaultChannelOrder(ALCdevice *device) } } -extern inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS], enum Channel chan); -extern inline ALint GetChannelIdxByName(const RealMixParams *real, enum Channel chan); - -/* NOTE: These shouldn't really be here, but C++ (alBuffer.cpp) won't turn - * these extern inline declarations into callable functions. - */ -extern inline void LockBufferList(ALCdevice *device); -extern inline void UnlockBufferList(ALCdevice *device); -extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type); -extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); - -extern inline ALuint64 GetDeviceClockTime(ALCdevice *device); - -extern inline void alstr_reset(al_string *str); -extern inline size_t alstr_length(const_al_string str); -extern inline ALboolean alstr_empty(const_al_string str); -extern inline const al_string_char_type *alstr_get_cstr(const_al_string str); - /* ALCcontext_DeferUpdates * diff --git a/Alc/ALu.c b/Alc/ALu.c index b6ea504a..4d03fc0b 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -49,69 +49,6 @@ #include "backends/base.h" -extern inline ALuint NextPowerOf2(ALuint value); -extern inline size_t RoundUp(size_t value, size_t r); -extern inline ALint fastf2i(ALfloat f); -extern inline int float2int(float f); -extern inline float fast_roundf(float f); -#ifndef __GNUC__ -#if defined(HAVE_BITSCANFORWARD64_INTRINSIC) -extern inline int msvc64_ctz64(ALuint64 v); -#elif defined(HAVE_BITSCANFORWARD_INTRINSIC) -extern inline int msvc_ctz64(ALuint64 v); -#else -extern inline int fallback_popcnt64(ALuint64 v); -extern inline int fallback_ctz64(ALuint64 value); -#endif -#endif - -extern inline ALfloat minf(ALfloat a, ALfloat b); -extern inline ALfloat maxf(ALfloat a, ALfloat b); -extern inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max); - -extern inline ALdouble mind(ALdouble a, ALdouble b); -extern inline ALdouble maxd(ALdouble a, ALdouble b); -extern inline ALdouble clampd(ALdouble val, ALdouble min, ALdouble max); - -extern inline ALuint minu(ALuint a, ALuint b); -extern inline ALuint maxu(ALuint a, ALuint b); -extern inline ALuint clampu(ALuint val, ALuint min, ALuint max); - -extern inline ALint mini(ALint a, ALint b); -extern inline ALint maxi(ALint a, ALint b); -extern inline ALint clampi(ALint val, ALint min, ALint max); - -extern inline ALint64 mini64(ALint64 a, ALint64 b); -extern inline ALint64 maxi64(ALint64 a, ALint64 b); -extern inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max); - -extern inline ALuint64 minu64(ALuint64 a, ALuint64 b); -extern inline ALuint64 maxu64(ALuint64 a, ALuint64 b); -extern inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max); - -extern inline size_t minz(size_t a, size_t b); -extern inline size_t maxz(size_t a, size_t b); -extern inline size_t clampz(size_t val, size_t min, size_t max); - -extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu); -extern inline ALfloat cubic(ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat mu); - -extern inline void aluVectorSet(aluVector *vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w); - -extern inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row, - ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3); -extern inline void aluMatrixfSet(aluMatrixf *matrix, - ALfloat m00, ALfloat m01, ALfloat m02, ALfloat m03, - ALfloat m10, ALfloat m11, ALfloat m12, ALfloat m13, - ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23, - ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33); - -extern inline void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); -extern inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); -extern inline float ScaleAzimuthFront(float azimuth, float scale); -extern inline void ComputePanGains(const MixParams *dry, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); - - /* Cone scalar */ ALfloat ConeScale = 1.0f; diff --git a/Alc/filters/filter.c b/Alc/filters/filter.c index d05b0cae..838a9a5d 100644 --- a/Alc/filters/filter.c +++ b/Alc/filters/filter.c @@ -7,12 +7,6 @@ #include "alMain.h" #include "defs.h" -extern inline void BiquadFilter_clear(BiquadFilter *filter); -extern inline void BiquadFilter_copyParams(BiquadFilter *RESTRICT dst, const BiquadFilter *RESTRICT src); -extern inline void BiquadFilter_passthru(BiquadFilter *filter, ALsizei numsamples); -extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope); -extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth); - void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ) { diff --git a/Alc/inldefs.c b/Alc/inldefs.c new file mode 100644 index 00000000..dd66da13 --- /dev/null +++ b/Alc/inldefs.c @@ -0,0 +1,122 @@ + +#include "config.h" + +#include "alMain.h" +#include "alu.h" +#include "filters/defs.h" +#include "mixer/defs.h" +#include "alBuffer.h" +#include "alEffect.h" +#include "alstring.h" + +#include "backends/base.h" + +/* This is a place to dump inline function instantiations, to generate function + * bodies for calls that can't be inlined. C++ does not have a way to do this + * explicitly, so as long as there is C code calling inline functions, a body + * must be explicitly instantiated in case of non-inlined calls. + * + * This just makes it easier to keep track of everything, while things are + * converted to C++. + */ + +extern inline ALsizei FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type, ALsizei ambiorder); + +extern inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS], enum Channel chan); +extern inline ALint GetChannelIdxByName(const RealMixParams *real, enum Channel chan); + +extern inline void LockBufferList(ALCdevice *device); +extern inline void UnlockBufferList(ALCdevice *device); +extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type); +extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); + +extern inline ALuint64 GetDeviceClockTime(ALCdevice *device); + + +extern inline void alstr_reset(al_string *str); +extern inline size_t alstr_length(const_al_string str); +extern inline ALboolean alstr_empty(const_al_string str); +extern inline const al_string_char_type *alstr_get_cstr(const_al_string str); + + +extern inline ALuint NextPowerOf2(ALuint value); +extern inline size_t RoundUp(size_t value, size_t r); +extern inline ALint fastf2i(ALfloat f); +extern inline int float2int(float f); +extern inline float fast_roundf(float f); +#ifndef __GNUC__ +#if defined(HAVE_BITSCANFORWARD64_INTRINSIC) +extern inline int msvc64_ctz64(ALuint64 v); +#elif defined(HAVE_BITSCANFORWARD_INTRINSIC) +extern inline int msvc_ctz64(ALuint64 v); +#else +extern inline int fallback_popcnt64(ALuint64 v); +extern inline int fallback_ctz64(ALuint64 value); +#endif +#endif + +extern inline ALfloat minf(ALfloat a, ALfloat b); +extern inline ALfloat maxf(ALfloat a, ALfloat b); +extern inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max); + +extern inline ALdouble mind(ALdouble a, ALdouble b); +extern inline ALdouble maxd(ALdouble a, ALdouble b); +extern inline ALdouble clampd(ALdouble val, ALdouble min, ALdouble max); + +extern inline ALuint minu(ALuint a, ALuint b); +extern inline ALuint maxu(ALuint a, ALuint b); +extern inline ALuint clampu(ALuint val, ALuint min, ALuint max); + +extern inline ALint mini(ALint a, ALint b); +extern inline ALint maxi(ALint a, ALint b); +extern inline ALint clampi(ALint val, ALint min, ALint max); + +extern inline ALint64 mini64(ALint64 a, ALint64 b); +extern inline ALint64 maxi64(ALint64 a, ALint64 b); +extern inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max); + +extern inline ALuint64 minu64(ALuint64 a, ALuint64 b); +extern inline ALuint64 maxu64(ALuint64 a, ALuint64 b); +extern inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max); + +extern inline size_t minz(size_t a, size_t b); +extern inline size_t maxz(size_t a, size_t b); +extern inline size_t clampz(size_t val, size_t min, size_t max); + +extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu); +extern inline ALfloat cubic(ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat mu); + +extern inline void aluVectorSet(aluVector *vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w); + +extern inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row, + ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3); +extern inline void aluMatrixfSet(aluMatrixf *matrix, + ALfloat m00, ALfloat m01, ALfloat m02, ALfloat m03, + ALfloat m10, ALfloat m11, ALfloat m12, ALfloat m13, + ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23, + ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33); + +extern inline void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); +extern inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); +extern inline float ScaleAzimuthFront(float azimuth, float scale); +extern inline void ComputePanGains(const MixParams *dry, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); + +extern inline void BiquadFilter_clear(BiquadFilter *filter); +extern inline void BiquadFilter_copyParams(BiquadFilter *RESTRICT dst, const BiquadFilter *RESTRICT src); +extern inline void BiquadFilter_passthru(BiquadFilter *filter, ALsizei numsamples); +extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope); +extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth); + + +extern inline void LockFilterList(ALCdevice *device); +extern inline void UnlockFilterList(ALCdevice *device); + +extern inline void LockEffectList(ALCdevice *device); +extern inline void UnlockEffectList(ALCdevice *device); +extern inline ALboolean IsReverbEffect(ALenum type); + +extern inline void LockEffectSlotList(ALCcontext *context); +extern inline void UnlockEffectSlotList(ALCcontext *context); + + +extern inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *RESTRICT frac_arr, ALsizei *RESTRICT pos_arr, ALsizei size); diff --git a/Alc/mixvoice.c b/Alc/mixvoice.c index 587f4a6b..ffbcdb25 100644 --- a/Alc/mixvoice.c +++ b/Alc/mixvoice.c @@ -45,9 +45,6 @@ static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!"); -extern inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *RESTRICT frac_arr, ALsizei *RESTRICT pos_arr, ALsizei size); - - /* BSinc24 requires up to 23 extra samples before the current position, and 24 after. */ static_assert(MAX_RESAMPLE_PADDING >= 24, "MAX_RESAMPLE_PADDING must be at least 24!"); diff --git a/CMakeLists.txt b/CMakeLists.txt index a822bc0f..11cf7da6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -846,6 +846,7 @@ SET(ALC_OBJS Alc/bs2b.c Alc/converter.c Alc/converter.h + Alc/inldefs.c Alc/inprogext.h Alc/mastering.c Alc/mastering.h diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 4758646f..297aa1b6 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -35,9 +35,6 @@ #include "almalloc.h" -extern inline void LockEffectSlotList(ALCcontext *context); -extern inline void UnlockEffectSlotList(ALCcontext *context); - static void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context); static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context); diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index 05a6c0a3..67214957 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -31,10 +31,6 @@ #include "alError.h" -extern inline void LockEffectList(ALCdevice *device); -extern inline void UnlockEffectList(ALCdevice *device); -extern inline ALboolean IsReverbEffect(ALenum type); - const struct EffectList EffectList[EFFECTLIST_SIZE] = { { "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB }, { "reverb", REVERB_EFFECT, AL_EFFECT_REVERB }, diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index 01da4008..3803fae6 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -31,9 +31,6 @@ #define FILTER_MIN_GAIN 0.0f #define FILTER_MAX_GAIN 4.0f /* +12dB */ -extern inline void LockFilterList(ALCdevice *device); -extern inline void UnlockFilterList(ALCdevice *device); - static ALfilter *AllocFilter(ALCcontext *context); static void FreeFilter(ALCdevice *device, ALfilter *filter); static void InitFilterParams(ALfilter *filter, ALenum type); -- cgit v1.2.3 From dfcb6d3e6df973d4d92b37f1d8decd833575d281 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 14 Nov 2018 02:41:21 -0800 Subject: More clearly check if the buffer is not empty --- Alc/backends/alsa.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index d40261cb..15308632 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -1156,7 +1156,7 @@ static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buff { snd_pcm_sframes_t amt{0}; - if(self->buffer.size() > 0) + if(!self->buffer.empty()) { /* First get any data stored from the last stop */ amt = snd_pcm_bytes_to_frames(self->pcmHandle, self->buffer.size()); -- cgit v1.2.3 From 3021a426c027fb88bf13b36ad825b9686001a5c9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 14 Nov 2018 04:15:44 -0800 Subject: Convert ALc.c to C++ --- Alc/ALc.c | 4715 ----------------------------------------------------- Alc/alc.cpp | 4696 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Alc/filters/nfc.h | 8 + Alc/mastering.h | 8 + CMakeLists.txt | 2 +- 5 files changed, 4713 insertions(+), 4716 deletions(-) delete mode 100644 Alc/ALc.c create mode 100644 Alc/alc.cpp diff --git a/Alc/ALc.c b/Alc/ALc.c deleted file mode 100644 index 3468f6a3..00000000 --- a/Alc/ALc.c +++ /dev/null @@ -1,4715 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "version.h" - -#include -#include -#include -#include -#include -#include - -#include "alMain.h" -#include "alSource.h" -#include "alListener.h" -#include "alSource.h" -#include "alBuffer.h" -#include "alFilter.h" -#include "alEffect.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "mastering.h" -#include "bformatdec.h" -#include "alu.h" -#include "alconfig.h" -#include "ringbuffer.h" - -#include "fpu_modes.h" -#include "cpu_caps.h" -#include "compat.h" -#include "threads.h" -#include "alstring.h" -#include "almalloc.h" - -#include "backends/base.h" - - -/************************************************ - * Backends - ************************************************/ -struct BackendInfo { - const char *name; - ALCbackendFactory* (*getFactory)(void); -}; - -static struct BackendInfo BackendList[] = { -#ifdef HAVE_JACK - { "jack", ALCjackBackendFactory_getFactory }, -#endif -#ifdef HAVE_PULSEAUDIO - { "pulse", ALCpulseBackendFactory_getFactory }, -#endif -#ifdef HAVE_ALSA - { "alsa", ALCalsaBackendFactory_getFactory }, -#endif -#ifdef HAVE_COREAUDIO - { "core", ALCcoreAudioBackendFactory_getFactory }, -#endif -#ifdef HAVE_SOLARIS - { "solaris", ALCsolarisBackendFactory_getFactory }, -#endif -#ifdef HAVE_SNDIO - { "sndio", SndioBackendFactory_getFactory }, -#endif -#ifdef HAVE_OSS - { "oss", ALCossBackendFactory_getFactory }, -#endif -#ifdef HAVE_QSA - { "qsa", ALCqsaBackendFactory_getFactory }, -#endif -#ifdef HAVE_WASAPI - { "wasapi", ALCwasapiBackendFactory_getFactory }, -#endif -#ifdef HAVE_DSOUND - { "dsound", ALCdsoundBackendFactory_getFactory }, -#endif -#ifdef HAVE_WINMM - { "winmm", ALCwinmmBackendFactory_getFactory }, -#endif -#ifdef HAVE_PORTAUDIO - { "port", ALCportBackendFactory_getFactory }, -#endif -#ifdef HAVE_OPENSL - { "opensl", ALCopenslBackendFactory_getFactory }, -#endif -#ifdef HAVE_SDL2 - { "sdl2", ALCsdl2BackendFactory_getFactory }, -#endif - - { "null", ALCnullBackendFactory_getFactory }, -#ifdef HAVE_WAVE - { "wave", ALCwaveBackendFactory_getFactory }, -#endif -}; -static ALsizei BackendListSize = COUNTOF(BackendList); -#undef EmptyFuncs - -static struct BackendInfo PlaybackBackend; -static struct BackendInfo CaptureBackend; - - -/************************************************ - * Functions, enums, and errors - ************************************************/ -#define DECL(x) { #x, (ALCvoid*)(x) } -static const struct { - const ALCchar *funcName; - ALCvoid *address; -} alcFunctions[] = { - DECL(alcCreateContext), - DECL(alcMakeContextCurrent), - DECL(alcProcessContext), - DECL(alcSuspendContext), - DECL(alcDestroyContext), - DECL(alcGetCurrentContext), - DECL(alcGetContextsDevice), - DECL(alcOpenDevice), - DECL(alcCloseDevice), - DECL(alcGetError), - DECL(alcIsExtensionPresent), - DECL(alcGetProcAddress), - DECL(alcGetEnumValue), - DECL(alcGetString), - DECL(alcGetIntegerv), - DECL(alcCaptureOpenDevice), - DECL(alcCaptureCloseDevice), - DECL(alcCaptureStart), - DECL(alcCaptureStop), - DECL(alcCaptureSamples), - - DECL(alcSetThreadContext), - DECL(alcGetThreadContext), - - DECL(alcLoopbackOpenDeviceSOFT), - DECL(alcIsRenderFormatSupportedSOFT), - DECL(alcRenderSamplesSOFT), - - DECL(alcDevicePauseSOFT), - DECL(alcDeviceResumeSOFT), - - DECL(alcGetStringiSOFT), - DECL(alcResetDeviceSOFT), - - DECL(alcGetInteger64vSOFT), - - DECL(alEnable), - DECL(alDisable), - DECL(alIsEnabled), - DECL(alGetString), - DECL(alGetBooleanv), - DECL(alGetIntegerv), - DECL(alGetFloatv), - DECL(alGetDoublev), - DECL(alGetBoolean), - DECL(alGetInteger), - DECL(alGetFloat), - DECL(alGetDouble), - DECL(alGetError), - DECL(alIsExtensionPresent), - DECL(alGetProcAddress), - DECL(alGetEnumValue), - DECL(alListenerf), - DECL(alListener3f), - DECL(alListenerfv), - DECL(alListeneri), - DECL(alListener3i), - DECL(alListeneriv), - DECL(alGetListenerf), - DECL(alGetListener3f), - DECL(alGetListenerfv), - DECL(alGetListeneri), - DECL(alGetListener3i), - DECL(alGetListeneriv), - DECL(alGenSources), - DECL(alDeleteSources), - DECL(alIsSource), - DECL(alSourcef), - DECL(alSource3f), - DECL(alSourcefv), - DECL(alSourcei), - DECL(alSource3i), - DECL(alSourceiv), - DECL(alGetSourcef), - DECL(alGetSource3f), - DECL(alGetSourcefv), - DECL(alGetSourcei), - DECL(alGetSource3i), - DECL(alGetSourceiv), - DECL(alSourcePlayv), - DECL(alSourceStopv), - DECL(alSourceRewindv), - DECL(alSourcePausev), - DECL(alSourcePlay), - DECL(alSourceStop), - DECL(alSourceRewind), - DECL(alSourcePause), - DECL(alSourceQueueBuffers), - DECL(alSourceUnqueueBuffers), - DECL(alGenBuffers), - DECL(alDeleteBuffers), - DECL(alIsBuffer), - DECL(alBufferData), - DECL(alBufferf), - DECL(alBuffer3f), - DECL(alBufferfv), - DECL(alBufferi), - DECL(alBuffer3i), - DECL(alBufferiv), - DECL(alGetBufferf), - DECL(alGetBuffer3f), - DECL(alGetBufferfv), - DECL(alGetBufferi), - DECL(alGetBuffer3i), - DECL(alGetBufferiv), - DECL(alDopplerFactor), - DECL(alDopplerVelocity), - DECL(alSpeedOfSound), - DECL(alDistanceModel), - - DECL(alGenFilters), - DECL(alDeleteFilters), - DECL(alIsFilter), - DECL(alFilteri), - DECL(alFilteriv), - DECL(alFilterf), - DECL(alFilterfv), - DECL(alGetFilteri), - DECL(alGetFilteriv), - DECL(alGetFilterf), - DECL(alGetFilterfv), - DECL(alGenEffects), - DECL(alDeleteEffects), - DECL(alIsEffect), - DECL(alEffecti), - DECL(alEffectiv), - DECL(alEffectf), - DECL(alEffectfv), - DECL(alGetEffecti), - DECL(alGetEffectiv), - DECL(alGetEffectf), - DECL(alGetEffectfv), - DECL(alGenAuxiliaryEffectSlots), - DECL(alDeleteAuxiliaryEffectSlots), - DECL(alIsAuxiliaryEffectSlot), - DECL(alAuxiliaryEffectSloti), - DECL(alAuxiliaryEffectSlotiv), - DECL(alAuxiliaryEffectSlotf), - DECL(alAuxiliaryEffectSlotfv), - DECL(alGetAuxiliaryEffectSloti), - DECL(alGetAuxiliaryEffectSlotiv), - DECL(alGetAuxiliaryEffectSlotf), - DECL(alGetAuxiliaryEffectSlotfv), - - DECL(alDeferUpdatesSOFT), - DECL(alProcessUpdatesSOFT), - - DECL(alSourcedSOFT), - DECL(alSource3dSOFT), - DECL(alSourcedvSOFT), - DECL(alGetSourcedSOFT), - DECL(alGetSource3dSOFT), - DECL(alGetSourcedvSOFT), - DECL(alSourcei64SOFT), - DECL(alSource3i64SOFT), - DECL(alSourcei64vSOFT), - DECL(alGetSourcei64SOFT), - DECL(alGetSource3i64SOFT), - DECL(alGetSourcei64vSOFT), - - DECL(alGetStringiSOFT), - - DECL(alBufferStorageSOFT), - DECL(alMapBufferSOFT), - DECL(alUnmapBufferSOFT), - DECL(alFlushMappedBufferSOFT), - - DECL(alEventControlSOFT), - DECL(alEventCallbackSOFT), - DECL(alGetPointerSOFT), - DECL(alGetPointervSOFT), -}; -#undef DECL - -#define DECL(x) { #x, (x) } -static const struct { - const ALCchar *enumName; - ALCenum value; -} alcEnumerations[] = { - DECL(ALC_INVALID), - DECL(ALC_FALSE), - DECL(ALC_TRUE), - - DECL(ALC_MAJOR_VERSION), - DECL(ALC_MINOR_VERSION), - DECL(ALC_ATTRIBUTES_SIZE), - DECL(ALC_ALL_ATTRIBUTES), - DECL(ALC_DEFAULT_DEVICE_SPECIFIER), - DECL(ALC_DEVICE_SPECIFIER), - DECL(ALC_ALL_DEVICES_SPECIFIER), - DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER), - DECL(ALC_EXTENSIONS), - DECL(ALC_FREQUENCY), - DECL(ALC_REFRESH), - DECL(ALC_SYNC), - DECL(ALC_MONO_SOURCES), - DECL(ALC_STEREO_SOURCES), - DECL(ALC_CAPTURE_DEVICE_SPECIFIER), - DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER), - DECL(ALC_CAPTURE_SAMPLES), - DECL(ALC_CONNECTED), - - DECL(ALC_EFX_MAJOR_VERSION), - DECL(ALC_EFX_MINOR_VERSION), - DECL(ALC_MAX_AUXILIARY_SENDS), - - DECL(ALC_FORMAT_CHANNELS_SOFT), - DECL(ALC_FORMAT_TYPE_SOFT), - - DECL(ALC_MONO_SOFT), - DECL(ALC_STEREO_SOFT), - DECL(ALC_QUAD_SOFT), - DECL(ALC_5POINT1_SOFT), - DECL(ALC_6POINT1_SOFT), - DECL(ALC_7POINT1_SOFT), - DECL(ALC_BFORMAT3D_SOFT), - - DECL(ALC_BYTE_SOFT), - DECL(ALC_UNSIGNED_BYTE_SOFT), - DECL(ALC_SHORT_SOFT), - DECL(ALC_UNSIGNED_SHORT_SOFT), - DECL(ALC_INT_SOFT), - DECL(ALC_UNSIGNED_INT_SOFT), - DECL(ALC_FLOAT_SOFT), - - DECL(ALC_HRTF_SOFT), - DECL(ALC_DONT_CARE_SOFT), - DECL(ALC_HRTF_STATUS_SOFT), - DECL(ALC_HRTF_DISABLED_SOFT), - DECL(ALC_HRTF_ENABLED_SOFT), - DECL(ALC_HRTF_DENIED_SOFT), - DECL(ALC_HRTF_REQUIRED_SOFT), - DECL(ALC_HRTF_HEADPHONES_DETECTED_SOFT), - DECL(ALC_HRTF_UNSUPPORTED_FORMAT_SOFT), - DECL(ALC_NUM_HRTF_SPECIFIERS_SOFT), - DECL(ALC_HRTF_SPECIFIER_SOFT), - DECL(ALC_HRTF_ID_SOFT), - - DECL(ALC_AMBISONIC_LAYOUT_SOFT), - DECL(ALC_AMBISONIC_SCALING_SOFT), - DECL(ALC_AMBISONIC_ORDER_SOFT), - DECL(ALC_ACN_SOFT), - DECL(ALC_FUMA_SOFT), - DECL(ALC_N3D_SOFT), - DECL(ALC_SN3D_SOFT), - - DECL(ALC_OUTPUT_LIMITER_SOFT), - - DECL(ALC_NO_ERROR), - DECL(ALC_INVALID_DEVICE), - DECL(ALC_INVALID_CONTEXT), - DECL(ALC_INVALID_ENUM), - DECL(ALC_INVALID_VALUE), - DECL(ALC_OUT_OF_MEMORY), - - - DECL(AL_INVALID), - DECL(AL_NONE), - DECL(AL_FALSE), - DECL(AL_TRUE), - - DECL(AL_SOURCE_RELATIVE), - DECL(AL_CONE_INNER_ANGLE), - DECL(AL_CONE_OUTER_ANGLE), - DECL(AL_PITCH), - DECL(AL_POSITION), - DECL(AL_DIRECTION), - DECL(AL_VELOCITY), - DECL(AL_LOOPING), - DECL(AL_BUFFER), - DECL(AL_GAIN), - DECL(AL_MIN_GAIN), - DECL(AL_MAX_GAIN), - DECL(AL_ORIENTATION), - DECL(AL_REFERENCE_DISTANCE), - DECL(AL_ROLLOFF_FACTOR), - DECL(AL_CONE_OUTER_GAIN), - DECL(AL_MAX_DISTANCE), - DECL(AL_SEC_OFFSET), - DECL(AL_SAMPLE_OFFSET), - DECL(AL_BYTE_OFFSET), - DECL(AL_SOURCE_TYPE), - DECL(AL_STATIC), - DECL(AL_STREAMING), - DECL(AL_UNDETERMINED), - DECL(AL_METERS_PER_UNIT), - DECL(AL_LOOP_POINTS_SOFT), - DECL(AL_DIRECT_CHANNELS_SOFT), - - DECL(AL_DIRECT_FILTER), - DECL(AL_AUXILIARY_SEND_FILTER), - DECL(AL_AIR_ABSORPTION_FACTOR), - DECL(AL_ROOM_ROLLOFF_FACTOR), - DECL(AL_CONE_OUTER_GAINHF), - DECL(AL_DIRECT_FILTER_GAINHF_AUTO), - DECL(AL_AUXILIARY_SEND_FILTER_GAIN_AUTO), - DECL(AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO), - - DECL(AL_SOURCE_STATE), - DECL(AL_INITIAL), - DECL(AL_PLAYING), - DECL(AL_PAUSED), - DECL(AL_STOPPED), - - DECL(AL_BUFFERS_QUEUED), - DECL(AL_BUFFERS_PROCESSED), - - DECL(AL_FORMAT_MONO8), - DECL(AL_FORMAT_MONO16), - DECL(AL_FORMAT_MONO_FLOAT32), - DECL(AL_FORMAT_MONO_DOUBLE_EXT), - DECL(AL_FORMAT_STEREO8), - DECL(AL_FORMAT_STEREO16), - DECL(AL_FORMAT_STEREO_FLOAT32), - 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), - DECL(AL_FORMAT_QUAD16), - DECL(AL_FORMAT_QUAD32), - DECL(AL_FORMAT_51CHN8), - DECL(AL_FORMAT_51CHN16), - DECL(AL_FORMAT_51CHN32), - DECL(AL_FORMAT_61CHN8), - DECL(AL_FORMAT_61CHN16), - DECL(AL_FORMAT_61CHN32), - DECL(AL_FORMAT_71CHN8), - DECL(AL_FORMAT_71CHN16), - DECL(AL_FORMAT_71CHN32), - DECL(AL_FORMAT_REAR8), - DECL(AL_FORMAT_REAR16), - DECL(AL_FORMAT_REAR32), - DECL(AL_FORMAT_MONO_MULAW), - DECL(AL_FORMAT_MONO_MULAW_EXT), - DECL(AL_FORMAT_STEREO_MULAW), - DECL(AL_FORMAT_STEREO_MULAW_EXT), - DECL(AL_FORMAT_QUAD_MULAW), - DECL(AL_FORMAT_51CHN_MULAW), - DECL(AL_FORMAT_61CHN_MULAW), - DECL(AL_FORMAT_71CHN_MULAW), - DECL(AL_FORMAT_REAR_MULAW), - DECL(AL_FORMAT_MONO_ALAW_EXT), - DECL(AL_FORMAT_STEREO_ALAW_EXT), - - DECL(AL_FORMAT_BFORMAT2D_8), - DECL(AL_FORMAT_BFORMAT2D_16), - DECL(AL_FORMAT_BFORMAT2D_FLOAT32), - DECL(AL_FORMAT_BFORMAT2D_MULAW), - DECL(AL_FORMAT_BFORMAT3D_8), - DECL(AL_FORMAT_BFORMAT3D_16), - DECL(AL_FORMAT_BFORMAT3D_FLOAT32), - DECL(AL_FORMAT_BFORMAT3D_MULAW), - - DECL(AL_FREQUENCY), - DECL(AL_BITS), - DECL(AL_CHANNELS), - DECL(AL_SIZE), - DECL(AL_UNPACK_BLOCK_ALIGNMENT_SOFT), - DECL(AL_PACK_BLOCK_ALIGNMENT_SOFT), - - DECL(AL_SOURCE_RADIUS), - - DECL(AL_STEREO_ANGLES), - - DECL(AL_UNUSED), - DECL(AL_PENDING), - DECL(AL_PROCESSED), - - DECL(AL_NO_ERROR), - DECL(AL_INVALID_NAME), - DECL(AL_INVALID_ENUM), - DECL(AL_INVALID_VALUE), - DECL(AL_INVALID_OPERATION), - DECL(AL_OUT_OF_MEMORY), - - DECL(AL_VENDOR), - DECL(AL_VERSION), - DECL(AL_RENDERER), - DECL(AL_EXTENSIONS), - - DECL(AL_DOPPLER_FACTOR), - DECL(AL_DOPPLER_VELOCITY), - DECL(AL_DISTANCE_MODEL), - DECL(AL_SPEED_OF_SOUND), - DECL(AL_SOURCE_DISTANCE_MODEL), - DECL(AL_DEFERRED_UPDATES_SOFT), - DECL(AL_GAIN_LIMIT_SOFT), - - DECL(AL_INVERSE_DISTANCE), - DECL(AL_INVERSE_DISTANCE_CLAMPED), - DECL(AL_LINEAR_DISTANCE), - DECL(AL_LINEAR_DISTANCE_CLAMPED), - DECL(AL_EXPONENT_DISTANCE), - DECL(AL_EXPONENT_DISTANCE_CLAMPED), - - DECL(AL_FILTER_TYPE), - DECL(AL_FILTER_NULL), - DECL(AL_FILTER_LOWPASS), - DECL(AL_FILTER_HIGHPASS), - DECL(AL_FILTER_BANDPASS), - - 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), - DECL(AL_EFFECT_EAXREVERB), - DECL(AL_EFFECT_CHORUS), - DECL(AL_EFFECT_DISTORTION), - DECL(AL_EFFECT_ECHO), - DECL(AL_EFFECT_FLANGER), - DECL(AL_EFFECT_PITCH_SHIFTER), - DECL(AL_EFFECT_FREQUENCY_SHIFTER), -#if 0 - DECL(AL_EFFECT_VOCAL_MORPHER), -#endif - DECL(AL_EFFECT_RING_MODULATOR), - DECL(AL_EFFECT_AUTOWAH), - DECL(AL_EFFECT_COMPRESSOR), - DECL(AL_EFFECT_EQUALIZER), - DECL(AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT), - DECL(AL_EFFECT_DEDICATED_DIALOGUE), - - DECL(AL_EFFECTSLOT_EFFECT), - DECL(AL_EFFECTSLOT_GAIN), - DECL(AL_EFFECTSLOT_AUXILIARY_SEND_AUTO), - DECL(AL_EFFECTSLOT_NULL), - - DECL(AL_EAXREVERB_DENSITY), - DECL(AL_EAXREVERB_DIFFUSION), - DECL(AL_EAXREVERB_GAIN), - DECL(AL_EAXREVERB_GAINHF), - DECL(AL_EAXREVERB_GAINLF), - DECL(AL_EAXREVERB_DECAY_TIME), - DECL(AL_EAXREVERB_DECAY_HFRATIO), - DECL(AL_EAXREVERB_DECAY_LFRATIO), - DECL(AL_EAXREVERB_REFLECTIONS_GAIN), - DECL(AL_EAXREVERB_REFLECTIONS_DELAY), - DECL(AL_EAXREVERB_REFLECTIONS_PAN), - DECL(AL_EAXREVERB_LATE_REVERB_GAIN), - DECL(AL_EAXREVERB_LATE_REVERB_DELAY), - DECL(AL_EAXREVERB_LATE_REVERB_PAN), - DECL(AL_EAXREVERB_ECHO_TIME), - DECL(AL_EAXREVERB_ECHO_DEPTH), - DECL(AL_EAXREVERB_MODULATION_TIME), - DECL(AL_EAXREVERB_MODULATION_DEPTH), - DECL(AL_EAXREVERB_AIR_ABSORPTION_GAINHF), - DECL(AL_EAXREVERB_HFREFERENCE), - DECL(AL_EAXREVERB_LFREFERENCE), - DECL(AL_EAXREVERB_ROOM_ROLLOFF_FACTOR), - DECL(AL_EAXREVERB_DECAY_HFLIMIT), - - DECL(AL_REVERB_DENSITY), - DECL(AL_REVERB_DIFFUSION), - DECL(AL_REVERB_GAIN), - DECL(AL_REVERB_GAINHF), - DECL(AL_REVERB_DECAY_TIME), - DECL(AL_REVERB_DECAY_HFRATIO), - DECL(AL_REVERB_REFLECTIONS_GAIN), - DECL(AL_REVERB_REFLECTIONS_DELAY), - DECL(AL_REVERB_LATE_REVERB_GAIN), - DECL(AL_REVERB_LATE_REVERB_DELAY), - DECL(AL_REVERB_AIR_ABSORPTION_GAINHF), - DECL(AL_REVERB_ROOM_ROLLOFF_FACTOR), - DECL(AL_REVERB_DECAY_HFLIMIT), - - DECL(AL_CHORUS_WAVEFORM), - DECL(AL_CHORUS_PHASE), - DECL(AL_CHORUS_RATE), - DECL(AL_CHORUS_DEPTH), - DECL(AL_CHORUS_FEEDBACK), - DECL(AL_CHORUS_DELAY), - - DECL(AL_DISTORTION_EDGE), - DECL(AL_DISTORTION_GAIN), - DECL(AL_DISTORTION_LOWPASS_CUTOFF), - DECL(AL_DISTORTION_EQCENTER), - DECL(AL_DISTORTION_EQBANDWIDTH), - - DECL(AL_ECHO_DELAY), - DECL(AL_ECHO_LRDELAY), - DECL(AL_ECHO_DAMPING), - DECL(AL_ECHO_FEEDBACK), - DECL(AL_ECHO_SPREAD), - - DECL(AL_FLANGER_WAVEFORM), - DECL(AL_FLANGER_PHASE), - DECL(AL_FLANGER_RATE), - DECL(AL_FLANGER_DEPTH), - DECL(AL_FLANGER_FEEDBACK), - DECL(AL_FLANGER_DELAY), - - DECL(AL_FREQUENCY_SHIFTER_FREQUENCY), - DECL(AL_FREQUENCY_SHIFTER_LEFT_DIRECTION), - DECL(AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION), - - DECL(AL_RING_MODULATOR_FREQUENCY), - DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF), - DECL(AL_RING_MODULATOR_WAVEFORM), - - DECL(AL_PITCH_SHIFTER_COARSE_TUNE), - DECL(AL_PITCH_SHIFTER_FINE_TUNE), - - DECL(AL_COMPRESSOR_ONOFF), - - DECL(AL_EQUALIZER_LOW_GAIN), - DECL(AL_EQUALIZER_LOW_CUTOFF), - DECL(AL_EQUALIZER_MID1_GAIN), - DECL(AL_EQUALIZER_MID1_CENTER), - DECL(AL_EQUALIZER_MID1_WIDTH), - DECL(AL_EQUALIZER_MID2_GAIN), - DECL(AL_EQUALIZER_MID2_CENTER), - DECL(AL_EQUALIZER_MID2_WIDTH), - DECL(AL_EQUALIZER_HIGH_GAIN), - DECL(AL_EQUALIZER_HIGH_CUTOFF), - - DECL(AL_DEDICATED_GAIN), - - DECL(AL_AUTOWAH_ATTACK_TIME), - DECL(AL_AUTOWAH_RELEASE_TIME), - DECL(AL_AUTOWAH_RESONANCE), - DECL(AL_AUTOWAH_PEAK_GAIN), - - DECL(AL_NUM_RESAMPLERS_SOFT), - DECL(AL_DEFAULT_RESAMPLER_SOFT), - DECL(AL_SOURCE_RESAMPLER_SOFT), - DECL(AL_RESAMPLER_NAME_SOFT), - - DECL(AL_SOURCE_SPATIALIZE_SOFT), - DECL(AL_AUTO_SOFT), - - DECL(AL_MAP_READ_BIT_SOFT), - DECL(AL_MAP_WRITE_BIT_SOFT), - DECL(AL_MAP_PERSISTENT_BIT_SOFT), - DECL(AL_PRESERVE_DATA_BIT_SOFT), - - DECL(AL_EVENT_CALLBACK_FUNCTION_SOFT), - DECL(AL_EVENT_CALLBACK_USER_PARAM_SOFT), - DECL(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT), - DECL(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT), - DECL(AL_EVENT_TYPE_ERROR_SOFT), - DECL(AL_EVENT_TYPE_PERFORMANCE_SOFT), - DECL(AL_EVENT_TYPE_DEPRECATED_SOFT), -}; -#undef DECL - -static const ALCchar alcNoError[] = "No Error"; -static const ALCchar alcErrInvalidDevice[] = "Invalid Device"; -static const ALCchar alcErrInvalidContext[] = "Invalid Context"; -static const ALCchar alcErrInvalidEnum[] = "Invalid Enum"; -static const ALCchar alcErrInvalidValue[] = "Invalid Value"; -static const ALCchar alcErrOutOfMemory[] = "Out of Memory"; - - -/************************************************ - * Global variables - ************************************************/ - -/* Enumerated device names */ -static const ALCchar alcDefaultName[] = "OpenAL Soft\0"; - -static al_string alcAllDevicesList; -static al_string alcCaptureDeviceList; - -/* Default is always the first in the list */ -static ALCchar *alcDefaultAllDevicesSpecifier; -static ALCchar *alcCaptureDefaultDeviceSpecifier; - -/* Default context extensions */ -static const ALchar alExtList[] = - "AL_EXT_ALAW " - "AL_EXT_BFORMAT " - "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_BFORMAT " - "AL_EXT_MULAW_MCFORMATS " - "AL_EXT_OFFSET " - "AL_EXT_source_distance_model " - "AL_EXT_SOURCE_RADIUS " - "AL_EXT_STEREO_ANGLES " - "AL_LOKI_quadriphonic " - "AL_SOFT_block_alignment " - "AL_SOFT_deferred_updates " - "AL_SOFT_direct_channels " - "AL_SOFTX_events " - "AL_SOFTX_filter_gain_ex " - "AL_SOFT_gain_clamp_ex " - "AL_SOFT_loop_points " - "AL_SOFTX_map_buffer " - "AL_SOFT_MSADPCM " - "AL_SOFT_source_latency " - "AL_SOFT_source_length " - "AL_SOFT_source_resampler " - "AL_SOFT_source_spatialize"; - -static ATOMIC(ALCenum) LastNullDeviceError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); - -/* Thread-local current context */ -static altss_t LocalContext; -/* Process-wide current context */ -static ATOMIC(ALCcontext*) GlobalContext = ATOMIC_INIT_STATIC(NULL); - -/* Mixing thread piority level */ -ALint RTPrioLevel; - -FILE *LogFile; -#ifdef _DEBUG -enum LogLevel LogLevel = LogWarning; -#else -enum LogLevel LogLevel = LogError; -#endif - -/* Flag to trap ALC device errors */ -static ALCboolean TrapALCError = ALC_FALSE; - -/* One-time configuration init control */ -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; - -/* Flag to specify if alcSuspendContext/alcProcessContext should defer/process - * updates. - */ -static ALCboolean SuspendDefers = ALC_TRUE; - - -/************************************************ - * ALC information - ************************************************/ -static const ALCchar alcNoDeviceExtList[] = - "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE " - "ALC_EXT_thread_local_context ALC_SOFT_loopback"; -static const ALCchar alcExtensionList[] = - "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE " - "ALC_EXT_DEDICATED ALC_EXT_disconnect ALC_EXT_EFX " - "ALC_EXT_thread_local_context ALC_SOFT_device_clock ALC_SOFT_HRTF " - "ALC_SOFT_loopback ALC_SOFT_output_limiter ALC_SOFT_pause_device"; -static const ALCint alcMajorVersion = 1; -static const ALCint alcMinorVersion = 1; - -static const ALCint alcEFXMajorVersion = 1; -static const ALCint alcEFXMinorVersion = 0; - - -/************************************************ - * Device lists - ************************************************/ -static ATOMIC(ALCdevice*) DeviceList = ATOMIC_INIT_STATIC(NULL); - -static almtx_t ListLock; -static inline void LockLists(void) -{ - int ret = almtx_lock(&ListLock); - assert(ret == althrd_success); -} -static inline void UnlockLists(void) -{ - int ret = almtx_unlock(&ListLock); - assert(ret == althrd_success); -} - -/************************************************ - * Library initialization - ************************************************/ -#if defined(_WIN32) -static void alc_init(void); -static void alc_deinit(void); -static void alc_deinit_safe(void); - -#ifndef AL_LIBTYPE_STATIC -BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD reason, LPVOID lpReserved) -{ - 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); - alc_init(); - break; - - case DLL_THREAD_DETACH: - althrd_thread_detach(); - break; - - case DLL_PROCESS_DETACH: - if(!lpReserved) - alc_deinit(); - else - alc_deinit_safe(); - break; - } - return TRUE; -} -#elif defined(_MSC_VER) -#pragma section(".CRT$XCU",read) -static void alc_constructor(void); -static void alc_destructor(void); -__declspec(allocate(".CRT$XCU")) void (__cdecl* alc_constructor_)(void) = alc_constructor; - -static void alc_constructor(void) -{ - atexit(alc_destructor); - alc_init(); -} - -static void alc_destructor(void) -{ - alc_deinit(); -} -#elif defined(HAVE_GCC_DESTRUCTOR) -static void alc_init(void) __attribute__((constructor)); -static void alc_deinit(void) __attribute__((destructor)); -#else -#error "No static initialization available on this platform!" -#endif - -#elif defined(HAVE_GCC_DESTRUCTOR) - -static void alc_init(void) __attribute__((constructor)); -static void alc_deinit(void) __attribute__((destructor)); - -#else -#error "No global initialization available on this platform!" -#endif - -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; - - str = getenv("__ALSOFT_REVERSE_Z"); - if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1)) - ZScale *= -1.0f; - - str = getenv("__ALSOFT_REVERB_IGNORES_SOUND_SPEED"); - if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1)) - OverrideReverbSpeedOfSound = AL_TRUE; - - ret = altss_create(&LocalContext, ReleaseThreadCtx); - assert(ret == althrd_success); - - ret = almtx_init(&ListLock, almtx_recursive); - assert(ret == althrd_success); -} - -static void alc_initconfig(void) -{ - const char *devs, *str; - int capfilter; - float valf; - int i, n; - - str = getenv("ALSOFT_LOGLEVEL"); - if(str) - { - long lvl = strtol(str, NULL, 0); - if(lvl >= NoLog && lvl <= LogRef) - LogLevel = lvl; - } - - str = getenv("ALSOFT_LOGFILE"); - if(str && str[0]) - { -#ifdef _WIN32 - FILE *logfile = NULL; - int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); - if(len > 0) - { - WCHAR *wname = calloc(sizeof(WCHAR), len); - if(wname) - { - MultiByteToWideChar(CP_UTF8, 0, str, -1, wname, len); - logfile = _wfopen(wname, L"wt"); - free(wname); - } - } -#else - FILE *logfile = fopen(str, "wt"); -#endif - if(logfile) LogFile = logfile; - else ERR("Failed to open log file '%s'\n", str); - } - - TRACE("Initializing library v%s-%s %s\n", ALSOFT_VERSION, - ALSOFT_GIT_COMMIT_HASH, ALSOFT_GIT_BRANCH); - { - char buf[1024] = ""; - int len = 0; - - if(BackendListSize > 0) - len += snprintf(buf, sizeof(buf), "%s", BackendList[0].name); - for(i = 1;i < BackendListSize;i++) - len += snprintf(buf+len, sizeof(buf)-len, ", %s", BackendList[i].name); - TRACE("Supported backends: %s\n", buf); - } - ReadALConfig(); - - str = getenv("__ALSOFT_SUSPEND_CONTEXT"); - if(str && *str) - { - if(strcasecmp(str, "ignore") == 0) - { - SuspendDefers = ALC_FALSE; - TRACE("Selected context suspend behavior, \"ignore\"\n"); - } - else - ERR("Unhandled context suspend behavior setting: \"%s\"\n", str); - } - - capfilter = 0; -#if defined(HAVE_SSE4_1) - capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1; -#elif defined(HAVE_SSE3) - capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3; -#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; -#endif - if(ConfigValueStr(NULL, NULL, "disable-cpu-exts", &str)) - { - if(strcasecmp(str, "all") == 0) - capfilter = 0; - else - { - size_t len; - const char *next = str; - - do { - str = next; - while(isspace(str[0])) - str++; - next = strchr(str, ','); - - if(!str[0] || str[0] == ',') - continue; - - len = (next ? ((size_t)(next-str)) : strlen(str)); - while(len > 0 && isspace(str[len-1])) - len--; - if(len == 3 && strncasecmp(str, "sse", len) == 0) - capfilter &= ~CPU_CAP_SSE; - else if(len == 4 && strncasecmp(str, "sse2", len) == 0) - capfilter &= ~CPU_CAP_SSE2; - else if(len == 4 && strncasecmp(str, "sse3", len) == 0) - capfilter &= ~CPU_CAP_SSE3; - 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 - WARN("Invalid CPU extension \"%s\"\n", str); - } while(next++); - } - } - FillCPUCaps(capfilter); - -#ifdef _WIN32 - RTPrioLevel = 1; -#else - RTPrioLevel = 0; -#endif - ConfigValueInt(NULL, NULL, "rt-prio", &RTPrioLevel); - - aluInit(); - aluInitMixer(); - - str = getenv("ALSOFT_TRAP_ERROR"); - if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1)) - { - TrapALError = AL_TRUE; - TrapALCError = AL_TRUE; - } - else - { - str = getenv("ALSOFT_TRAP_AL_ERROR"); - if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1)) - TrapALError = AL_TRUE; - TrapALError = GetConfigValueBool(NULL, NULL, "trap-al-error", TrapALError); - - str = getenv("ALSOFT_TRAP_ALC_ERROR"); - if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1)) - TrapALCError = ALC_TRUE; - TrapALCError = GetConfigValueBool(NULL, NULL, "trap-alc-error", TrapALCError); - } - - if(ConfigValueFloat(NULL, "reverb", "boost", &valf)) - ReverbBoost *= powf(10.0f, valf / 20.0f); - - if(((devs=getenv("ALSOFT_DRIVERS")) && devs[0]) || - ConfigValueStr(NULL, NULL, "drivers", &devs)) - { - int n; - size_t len; - const char *next = devs; - int endlist, delitem; - - i = 0; - do { - devs = next; - while(isspace(devs[0])) - devs++; - next = strchr(devs, ','); - - delitem = (devs[0] == '-'); - if(devs[0] == '-') devs++; - - if(!devs[0] || devs[0] == ',') - { - endlist = 0; - continue; - } - endlist = 1; - - len = (next ? ((size_t)(next-devs)) : strlen(devs)); - while(len > 0 && isspace(devs[len-1])) - len--; -#ifdef HAVE_WASAPI - /* HACK: For backwards compatibility, convert backend references of - * mmdevapi to wasapi. This should eventually be removed. - */ - if(len == 8 && strncmp(devs, "mmdevapi", len) == 0) - { - devs = "wasapi"; - len = 6; - } -#endif - for(n = i;n < BackendListSize;n++) - { - if(len == strlen(BackendList[n].name) && - strncmp(BackendList[n].name, devs, len) == 0) - { - if(delitem) - { - for(;n+1 < BackendListSize;n++) - BackendList[n] = BackendList[n+1]; - BackendListSize--; - } - else - { - struct BackendInfo Bkp = BackendList[n]; - for(;n > i;n--) - BackendList[n] = BackendList[n-1]; - BackendList[n] = Bkp; - - i++; - } - break; - } - } - } while(next++); - - if(endlist) - BackendListSize = i; - } - - for(n = i = 0;i < BackendListSize && (!PlaybackBackend.name || !CaptureBackend.name);i++) - { - ALCbackendFactory *factory; - BackendList[n] = BackendList[i]; - - factory = BackendList[n].getFactory(); - if(!V0(factory,init)()) - { - WARN("Failed to initialize backend \"%s\"\n", BackendList[n].name); - continue; - } - - TRACE("Initialized backend \"%s\"\n", BackendList[n].name); - if(!PlaybackBackend.name && V(factory,querySupport)(ALCbackend_Playback)) - { - PlaybackBackend = BackendList[n]; - TRACE("Added \"%s\" for playback\n", PlaybackBackend.name); - } - if(!CaptureBackend.name && V(factory,querySupport)(ALCbackend_Capture)) - { - CaptureBackend = BackendList[n]; - TRACE("Added \"%s\" for capture\n", CaptureBackend.name); - } - n++; - } - BackendListSize = n; - - { - ALCbackendFactory *factory = ALCloopbackFactory_getFactory(); - V0(factory,init)(); - } - - if(!PlaybackBackend.name) - WARN("No playback backend available!\n"); - if(!CaptureBackend.name) - WARN("No capture backend available!\n"); - - if(ConfigValueStr(NULL, NULL, "excludefx", &str)) - { - size_t len; - const char *next = str; - - do { - str = next; - next = strchr(str, ','); - - if(!str[0] || next == str) - continue; - - len = (next ? ((size_t)(next-str)) : strlen(str)); - for(n = 0;n < EFFECTLIST_SIZE;n++) - { - if(len == strlen(EffectList[n].name) && - strncmp(EffectList[n].name, str, len) == 0) - DisabledEffects[EffectList[n].type] = AL_TRUE; - } - } while(next++); - } - - InitEffect(&DefaultEffect); - str = getenv("ALSOFT_DEFAULT_REVERB"); - if((str && str[0]) || ConfigValueStr(NULL, NULL, "default-reverb", &str)) - LoadReverbPreset(str, &DefaultEffect); -} -#define DO_INITCONFIG() alcall_once(&alc_config_once, alc_initconfig) - - -/************************************************ - * Library deinitialization - ************************************************/ -static void alc_cleanup(void) -{ - ALCdevice *dev; - - AL_STRING_DEINIT(alcAllDevicesList); - AL_STRING_DEINIT(alcCaptureDeviceList); - - free(alcDefaultAllDevicesSpecifier); - alcDefaultAllDevicesSpecifier = NULL; - free(alcCaptureDefaultDeviceSpecifier); - alcCaptureDefaultDeviceSpecifier = NULL; - - if((dev=ATOMIC_EXCHANGE_PTR_SEQ(&DeviceList, NULL)) != NULL) - { - ALCuint num = 0; - do { - num++; - dev = ATOMIC_LOAD(&dev->next, almemory_order_relaxed); - } while(dev != NULL); - ERR("%u device%s not closed\n", num, (num>1)?"s":""); - } -} - -static void alc_deinit_safe(void) -{ - alc_cleanup(); - - FreeHrtfs(); - FreeALConfig(); - - almtx_destroy(&ListLock); - altss_delete(LocalContext); - - if(LogFile != stderr) - fclose(LogFile); - LogFile = NULL; - - althrd_deinit(); -} - -static void alc_deinit(void) -{ - int i; - - alc_cleanup(); - - memset(&PlaybackBackend, 0, sizeof(PlaybackBackend)); - memset(&CaptureBackend, 0, sizeof(CaptureBackend)); - - for(i = 0;i < BackendListSize;i++) - { - ALCbackendFactory *factory = BackendList[i].getFactory(); - V0(factory,deinit)(); - } - { - ALCbackendFactory *factory = ALCloopbackFactory_getFactory(); - V0(factory,deinit)(); - } - - alc_deinit_safe(); -} - - -/************************************************ - * Device enumeration - ************************************************/ -static void ProbeDevices(al_string *list, struct BackendInfo *backendinfo, enum DevProbe type) -{ - DO_INITCONFIG(); - - LockLists(); - alstr_clear(list); - - if(backendinfo->getFactory) - { - ALCbackendFactory *factory = backendinfo->getFactory(); - V(factory,probe)(type, list); - } - - UnlockLists(); -} -static void ProbeAllDevicesList(void) -{ ProbeDevices(&alcAllDevicesList, &PlaybackBackend, ALL_DEVICE_PROBE); } -static void ProbeCaptureDeviceList(void) -{ ProbeDevices(&alcCaptureDeviceList, &CaptureBackend, CAPTURE_DEVICE_PROBE); } - - -/************************************************ - * Device format information - ************************************************/ -const ALCchar *DevFmtTypeString(enum DevFmtType type) -{ - switch(type) - { - case DevFmtByte: return "Signed Byte"; - case DevFmtUByte: return "Unsigned Byte"; - case DevFmtShort: return "Signed Short"; - case DevFmtUShort: return "Unsigned Short"; - case DevFmtInt: return "Signed Int"; - case DevFmtUInt: return "Unsigned Int"; - case DevFmtFloat: return "Float"; - } - return "(unknown type)"; -} -const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) -{ - switch(chans) - { - case DevFmtMono: return "Mono"; - case DevFmtStereo: return "Stereo"; - case DevFmtQuad: return "Quadraphonic"; - case DevFmtX51: return "5.1 Surround"; - case DevFmtX51Rear: return "5.1 Surround (Rear)"; - case DevFmtX61: return "6.1 Surround"; - case DevFmtX71: return "7.1 Surround"; - case DevFmtAmbi3D: return "Ambisonic 3D"; - } - return "(unknown channels)"; -} - -ALsizei BytesFromDevFmt(enum DevFmtType type) -{ - switch(type) - { - case DevFmtByte: return sizeof(ALbyte); - case DevFmtUByte: return sizeof(ALubyte); - case DevFmtShort: return sizeof(ALshort); - case DevFmtUShort: return sizeof(ALushort); - case DevFmtInt: return sizeof(ALint); - case DevFmtUInt: return sizeof(ALuint); - case DevFmtFloat: return sizeof(ALfloat); - } - return 0; -} -ALsizei ChannelsFromDevFmt(enum DevFmtChannels chans, ALsizei ambiorder) -{ - switch(chans) - { - case DevFmtMono: return 1; - case DevFmtStereo: return 2; - case DevFmtQuad: return 4; - case DevFmtX51: return 6; - case DevFmtX51Rear: return 6; - case DevFmtX61: return 7; - case DevFmtX71: return 8; - case DevFmtAmbi3D: return (ambiorder >= 3) ? 16 : - (ambiorder == 2) ? 9 : - (ambiorder == 1) ? 4 : 1; - } - return 0; -} - -static ALboolean DecomposeDevFormat(ALenum format, enum DevFmtChannels *chans, - enum DevFmtType *type) -{ - static const struct { - ALenum format; - enum DevFmtChannels channels; - enum DevFmtType type; - } list[] = { - { AL_FORMAT_MONO8, DevFmtMono, DevFmtUByte }, - { AL_FORMAT_MONO16, DevFmtMono, DevFmtShort }, - { AL_FORMAT_MONO_FLOAT32, DevFmtMono, DevFmtFloat }, - - { AL_FORMAT_STEREO8, DevFmtStereo, DevFmtUByte }, - { AL_FORMAT_STEREO16, DevFmtStereo, DevFmtShort }, - { AL_FORMAT_STEREO_FLOAT32, DevFmtStereo, DevFmtFloat }, - - { AL_FORMAT_QUAD8, DevFmtQuad, DevFmtUByte }, - { AL_FORMAT_QUAD16, DevFmtQuad, DevFmtShort }, - { AL_FORMAT_QUAD32, DevFmtQuad, DevFmtFloat }, - - { AL_FORMAT_51CHN8, DevFmtX51, DevFmtUByte }, - { AL_FORMAT_51CHN16, DevFmtX51, DevFmtShort }, - { AL_FORMAT_51CHN32, DevFmtX51, DevFmtFloat }, - - { AL_FORMAT_61CHN8, DevFmtX61, DevFmtUByte }, - { AL_FORMAT_61CHN16, DevFmtX61, DevFmtShort }, - { AL_FORMAT_61CHN32, DevFmtX61, DevFmtFloat }, - - { AL_FORMAT_71CHN8, DevFmtX71, DevFmtUByte }, - { AL_FORMAT_71CHN16, DevFmtX71, DevFmtShort }, - { AL_FORMAT_71CHN32, DevFmtX71, DevFmtFloat }, - }; - ALuint i; - - for(i = 0;i < COUNTOF(list);i++) - { - if(list[i].format == format) - { - *chans = list[i].channels; - *type = list[i].type; - return AL_TRUE; - } - } - - return AL_FALSE; -} - -static ALCboolean IsValidALCType(ALCenum type) -{ - switch(type) - { - case ALC_BYTE_SOFT: - case ALC_UNSIGNED_BYTE_SOFT: - case ALC_SHORT_SOFT: - case ALC_UNSIGNED_SHORT_SOFT: - case ALC_INT_SOFT: - case ALC_UNSIGNED_INT_SOFT: - case ALC_FLOAT_SOFT: - return ALC_TRUE; - } - return ALC_FALSE; -} - -static ALCboolean IsValidALCChannels(ALCenum channels) -{ - switch(channels) - { - case ALC_MONO_SOFT: - case ALC_STEREO_SOFT: - case ALC_QUAD_SOFT: - case ALC_5POINT1_SOFT: - case ALC_6POINT1_SOFT: - case ALC_7POINT1_SOFT: - case ALC_BFORMAT3D_SOFT: - return ALC_TRUE; - } - return ALC_FALSE; -} - -static ALCboolean IsValidAmbiLayout(ALCenum layout) -{ - switch(layout) - { - case ALC_ACN_SOFT: - case ALC_FUMA_SOFT: - return ALC_TRUE; - } - return ALC_FALSE; -} - -static ALCboolean IsValidAmbiScaling(ALCenum scaling) -{ - switch(scaling) - { - case ALC_N3D_SOFT: - case ALC_SN3D_SOFT: - case ALC_FUMA_SOFT: - return ALC_TRUE; - } - return ALC_FALSE; -} - -/************************************************ - * Miscellaneous ALC helpers - ************************************************/ - -/* SetDefaultWFXChannelOrder - * - * Sets the default channel order used by WaveFormatEx. - */ -void SetDefaultWFXChannelOrder(ALCdevice *device) -{ - ALsizei i; - - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - device->RealOut.ChannelName[i] = InvalidChannel; - - switch(device->FmtChans) - { - case DevFmtMono: - device->RealOut.ChannelName[0] = FrontCenter; - break; - case DevFmtStereo: - device->RealOut.ChannelName[0] = FrontLeft; - device->RealOut.ChannelName[1] = FrontRight; - break; - case DevFmtQuad: - device->RealOut.ChannelName[0] = FrontLeft; - device->RealOut.ChannelName[1] = FrontRight; - device->RealOut.ChannelName[2] = BackLeft; - device->RealOut.ChannelName[3] = BackRight; - break; - case DevFmtX51: - device->RealOut.ChannelName[0] = FrontLeft; - device->RealOut.ChannelName[1] = FrontRight; - device->RealOut.ChannelName[2] = FrontCenter; - device->RealOut.ChannelName[3] = LFE; - device->RealOut.ChannelName[4] = SideLeft; - device->RealOut.ChannelName[5] = SideRight; - break; - case DevFmtX51Rear: - device->RealOut.ChannelName[0] = FrontLeft; - device->RealOut.ChannelName[1] = FrontRight; - device->RealOut.ChannelName[2] = FrontCenter; - device->RealOut.ChannelName[3] = LFE; - device->RealOut.ChannelName[4] = BackLeft; - device->RealOut.ChannelName[5] = BackRight; - break; - case DevFmtX61: - device->RealOut.ChannelName[0] = FrontLeft; - device->RealOut.ChannelName[1] = FrontRight; - device->RealOut.ChannelName[2] = FrontCenter; - device->RealOut.ChannelName[3] = LFE; - device->RealOut.ChannelName[4] = BackCenter; - device->RealOut.ChannelName[5] = SideLeft; - device->RealOut.ChannelName[6] = SideRight; - break; - case DevFmtX71: - device->RealOut.ChannelName[0] = FrontLeft; - device->RealOut.ChannelName[1] = FrontRight; - device->RealOut.ChannelName[2] = FrontCenter; - device->RealOut.ChannelName[3] = LFE; - device->RealOut.ChannelName[4] = BackLeft; - device->RealOut.ChannelName[5] = BackRight; - device->RealOut.ChannelName[6] = SideLeft; - device->RealOut.ChannelName[7] = SideRight; - break; - case DevFmtAmbi3D: - device->RealOut.ChannelName[0] = Aux0; - if(device->AmbiOrder > 0) - { - device->RealOut.ChannelName[1] = Aux1; - device->RealOut.ChannelName[2] = Aux2; - device->RealOut.ChannelName[3] = Aux3; - } - if(device->AmbiOrder > 1) - { - device->RealOut.ChannelName[4] = Aux4; - device->RealOut.ChannelName[5] = Aux5; - device->RealOut.ChannelName[6] = Aux6; - device->RealOut.ChannelName[7] = Aux7; - device->RealOut.ChannelName[8] = Aux8; - } - if(device->AmbiOrder > 2) - { - device->RealOut.ChannelName[9] = Aux9; - device->RealOut.ChannelName[10] = Aux10; - device->RealOut.ChannelName[11] = Aux11; - device->RealOut.ChannelName[12] = Aux12; - device->RealOut.ChannelName[13] = Aux13; - device->RealOut.ChannelName[14] = Aux14; - device->RealOut.ChannelName[15] = Aux15; - } - break; - } -} - -/* SetDefaultChannelOrder - * - * Sets the default channel order used by most non-WaveFormatEx-based APIs. - */ -void SetDefaultChannelOrder(ALCdevice *device) -{ - ALsizei i; - - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - device->RealOut.ChannelName[i] = InvalidChannel; - - switch(device->FmtChans) - { - case DevFmtX51Rear: - device->RealOut.ChannelName[0] = FrontLeft; - device->RealOut.ChannelName[1] = FrontRight; - device->RealOut.ChannelName[2] = BackLeft; - device->RealOut.ChannelName[3] = BackRight; - device->RealOut.ChannelName[4] = FrontCenter; - device->RealOut.ChannelName[5] = LFE; - return; - case DevFmtX71: - device->RealOut.ChannelName[0] = FrontLeft; - device->RealOut.ChannelName[1] = FrontRight; - device->RealOut.ChannelName[2] = BackLeft; - device->RealOut.ChannelName[3] = BackRight; - device->RealOut.ChannelName[4] = FrontCenter; - device->RealOut.ChannelName[5] = LFE; - device->RealOut.ChannelName[6] = SideLeft; - device->RealOut.ChannelName[7] = SideRight; - return; - - /* Same as WFX order */ - case DevFmtMono: - case DevFmtStereo: - case DevFmtQuad: - case DevFmtX51: - case DevFmtX61: - case DevFmtAmbi3D: - SetDefaultWFXChannelOrder(device); - break; - } -} - - -/* ALCcontext_DeferUpdates - * - * Defers/suspends updates for the given context's listener and sources. This - * does *NOT* stop mixing, but rather prevents certain property changes from - * taking effect. - */ -void ALCcontext_DeferUpdates(ALCcontext *context) -{ - ATOMIC_STORE_SEQ(&context->DeferUpdates, AL_TRUE); -} - -/* ALCcontext_ProcessUpdates - * - * Resumes update processing after being deferred. - */ -void ALCcontext_ProcessUpdates(ALCcontext *context) -{ - almtx_lock(&context->PropLock); - if(ATOMIC_EXCHANGE_SEQ(&context->DeferUpdates, AL_FALSE)) - { - /* Tell the mixer to stop applying updates, then wait for any active - * updating to finish, before providing updates. - */ - ATOMIC_STORE_SEQ(&context->HoldUpdates, AL_TRUE); - while((ATOMIC_LOAD(&context->UpdateCount, almemory_order_acquire)&1) != 0) - althrd_yield(); - - if(!ATOMIC_EXCHANGE(&context->PropsClean, AL_TRUE, almemory_order_acq_rel)) - UpdateContextProps(context); - if(!ATOMIC_EXCHANGE(&context->Listener->PropsClean, AL_TRUE, almemory_order_acq_rel)) - UpdateListenerProps(context); - UpdateAllEffectSlotProps(context); - UpdateAllSourceProps(context); - - /* Now with all updates declared, let the mixer continue applying them - * so they all happen at once. - */ - ATOMIC_STORE_SEQ(&context->HoldUpdates, AL_FALSE); - } - almtx_unlock(&context->PropLock); -} - - -/* alcSetError - * - * Stores the latest ALC device error - */ -static void alcSetError(ALCdevice *device, ALCenum errorCode) -{ - WARN("Error generated on device %p, code 0x%04x\n", device, errorCode); - if(TrapALCError) - { -#ifdef _WIN32 - /* DebugBreak() will cause an exception if there is no debugger */ - if(IsDebuggerPresent()) - DebugBreak(); -#elif defined(SIGTRAP) - raise(SIGTRAP); -#endif - } - - if(device) - ATOMIC_STORE_SEQ(&device->LastError, errorCode); - else - ATOMIC_STORE_SEQ(&LastNullDeviceError, errorCode); -} - - -static struct Compressor *CreateDeviceLimiter(const ALCdevice *device, const ALfloat threshold) -{ - return CompressorInit(device->RealOut.NumChannels, device->Frequency, - AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, 0.001f, 0.002f, - 0.0f, 0.0f, threshold, INFINITY, 0.0f, 0.020f, 0.200f); -} - -/* UpdateClockBase - * - * Updates the device's base clock time with however many samples have been - * done. This is used so frequency changes on the device don't cause the time - * to jump forward or back. Must not be called while the device is running/ - * mixing. - */ -static inline void UpdateClockBase(ALCdevice *device) -{ - IncrementRef(&device->MixCount); - device->ClockBase += device->SamplesDone * DEVICE_CLOCK_RES / device->Frequency; - device->SamplesDone = 0; - IncrementRef(&device->MixCount); -} - -/* UpdateDeviceParams - * - * Updates device parameters according to the attribute list (caller is - * responsible for holding the list lock). - */ -static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) -{ - enum HrtfRequestMode hrtf_userreq = Hrtf_Default; - enum HrtfRequestMode hrtf_appreq = Hrtf_Default; - ALCenum gainLimiter = device->LimiterState; - const ALsizei old_sends = device->NumAuxSends; - ALsizei new_sends = device->NumAuxSends; - enum DevFmtChannels oldChans; - enum DevFmtType oldType; - ALboolean update_failed; - ALCsizei hrtf_id = -1; - ALCcontext *context; - ALCuint oldFreq; - size_t size; - ALCsizei i; - int val; - - // Check for attributes - if(device->Type == Loopback) - { - ALCsizei numMono, numStereo, numSends; - ALCenum alayout = AL_NONE; - ALCenum ascale = AL_NONE; - ALCenum schans = AL_NONE; - ALCenum stype = AL_NONE; - ALCsizei attrIdx = 0; - ALCsizei aorder = 0; - ALCuint freq = 0; - - if(!attrList) - { - WARN("Missing attributes for loopback device\n"); - return ALC_INVALID_VALUE; - } - - numMono = device->NumMonoSources; - numStereo = device->NumStereoSources; - numSends = old_sends; - -#define TRACE_ATTR(a, v) TRACE("Loopback %s = %d\n", #a, v) - while(attrList[attrIdx]) - { - switch(attrList[attrIdx]) - { - case ALC_FORMAT_CHANNELS_SOFT: - schans = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_FORMAT_CHANNELS_SOFT, schans); - if(!IsValidALCChannels(schans)) - return ALC_INVALID_VALUE; - break; - - case ALC_FORMAT_TYPE_SOFT: - stype = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_FORMAT_TYPE_SOFT, stype); - if(!IsValidALCType(stype)) - return ALC_INVALID_VALUE; - break; - - case ALC_FREQUENCY: - freq = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_FREQUENCY, freq); - if(freq < MIN_OUTPUT_RATE) - return ALC_INVALID_VALUE; - break; - - case ALC_AMBISONIC_LAYOUT_SOFT: - alayout = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_AMBISONIC_LAYOUT_SOFT, alayout); - if(!IsValidAmbiLayout(alayout)) - return ALC_INVALID_VALUE; - break; - - case ALC_AMBISONIC_SCALING_SOFT: - ascale = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_AMBISONIC_SCALING_SOFT, ascale); - if(!IsValidAmbiScaling(ascale)) - return ALC_INVALID_VALUE; - break; - - case ALC_AMBISONIC_ORDER_SOFT: - aorder = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_AMBISONIC_ORDER_SOFT, aorder); - if(aorder < 1 || aorder > MAX_AMBI_ORDER) - return ALC_INVALID_VALUE; - break; - - case ALC_MONO_SOURCES: - numMono = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_MONO_SOURCES, numMono); - numMono = maxi(numMono, 0); - break; - - case ALC_STEREO_SOURCES: - numStereo = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); - numStereo = maxi(numStereo, 0); - break; - - case ALC_MAX_AUXILIARY_SENDS: - numSends = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_MAX_AUXILIARY_SENDS, numSends); - numSends = clampi(numSends, 0, MAX_SENDS); - break; - - case ALC_HRTF_SOFT: - TRACE_ATTR(ALC_HRTF_SOFT, attrList[attrIdx + 1]); - if(attrList[attrIdx + 1] == ALC_FALSE) - hrtf_appreq = Hrtf_Disable; - else if(attrList[attrIdx + 1] == ALC_TRUE) - hrtf_appreq = Hrtf_Enable; - else - hrtf_appreq = Hrtf_Default; - break; - - case ALC_HRTF_ID_SOFT: - hrtf_id = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_HRTF_ID_SOFT, hrtf_id); - break; - - case ALC_OUTPUT_LIMITER_SOFT: - gainLimiter = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_OUTPUT_LIMITER_SOFT, gainLimiter); - break; - - default: - TRACE("Loopback 0x%04X = %d (0x%x)\n", attrList[attrIdx], - attrList[attrIdx + 1], attrList[attrIdx + 1]); - break; - } - - attrIdx += 2; - } -#undef TRACE_ATTR - - if(!schans || !stype || !freq) - { - WARN("Missing format for loopback device\n"); - return ALC_INVALID_VALUE; - } - if(schans == ALC_BFORMAT3D_SOFT && (!alayout || !ascale || !aorder)) - { - WARN("Missing ambisonic info for loopback device\n"); - return ALC_INVALID_VALUE; - } - - if((device->Flags&DEVICE_RUNNING)) - V0(device->Backend,stop)(); - device->Flags &= ~DEVICE_RUNNING; - - UpdateClockBase(device); - - device->Frequency = freq; - device->FmtChans = schans; - device->FmtType = stype; - if(schans == ALC_BFORMAT3D_SOFT) - { - device->AmbiOrder = aorder; - device->AmbiLayout = alayout; - device->AmbiScale = ascale; - } - - if(numMono > INT_MAX-numStereo) - numMono = INT_MAX-numStereo; - numMono += numStereo; - if(ConfigValueInt(NULL, NULL, "sources", &numMono)) - { - if(numMono <= 0) - numMono = 256; - } - else - numMono = maxi(numMono, 256); - numStereo = mini(numStereo, numMono); - numMono -= numStereo; - device->SourcesMax = numMono + numStereo; - - device->NumMonoSources = numMono; - device->NumStereoSources = numStereo; - - if(ConfigValueInt(NULL, NULL, "sends", &new_sends)) - new_sends = mini(numSends, clampi(new_sends, 0, MAX_SENDS)); - else - new_sends = numSends; - } - else if(attrList && attrList[0]) - { - ALCsizei numMono, numStereo, numSends; - ALCsizei attrIdx = 0; - ALCuint freq; - - /* If a context is already running on the device, stop playback so the - * device attributes can be updated. */ - if((device->Flags&DEVICE_RUNNING)) - V0(device->Backend,stop)(); - device->Flags &= ~DEVICE_RUNNING; - - UpdateClockBase(device); - - freq = device->Frequency; - numMono = device->NumMonoSources; - numStereo = device->NumStereoSources; - numSends = old_sends; - -#define TRACE_ATTR(a, v) TRACE("%s = %d\n", #a, v) - while(attrList[attrIdx]) - { - switch(attrList[attrIdx]) - { - case ALC_FREQUENCY: - freq = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_FREQUENCY, freq); - device->Flags |= DEVICE_FREQUENCY_REQUEST; - break; - - case ALC_MONO_SOURCES: - numMono = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_MONO_SOURCES, numMono); - numMono = maxi(numMono, 0); - break; - - case ALC_STEREO_SOURCES: - numStereo = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); - numStereo = maxi(numStereo, 0); - break; - - case ALC_MAX_AUXILIARY_SENDS: - numSends = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_MAX_AUXILIARY_SENDS, numSends); - numSends = clampi(numSends, 0, MAX_SENDS); - break; - - case ALC_HRTF_SOFT: - TRACE_ATTR(ALC_HRTF_SOFT, attrList[attrIdx + 1]); - if(attrList[attrIdx + 1] == ALC_FALSE) - hrtf_appreq = Hrtf_Disable; - else if(attrList[attrIdx + 1] == ALC_TRUE) - hrtf_appreq = Hrtf_Enable; - else - hrtf_appreq = Hrtf_Default; - break; - - case ALC_HRTF_ID_SOFT: - hrtf_id = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_HRTF_ID_SOFT, hrtf_id); - break; - - case ALC_OUTPUT_LIMITER_SOFT: - gainLimiter = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_OUTPUT_LIMITER_SOFT, gainLimiter); - break; - - default: - TRACE("0x%04X = %d (0x%x)\n", attrList[attrIdx], - attrList[attrIdx + 1], attrList[attrIdx + 1]); - break; - } - - attrIdx += 2; - } -#undef TRACE_ATTR - - ConfigValueUInt(alstr_get_cstr(device->DeviceName), NULL, "frequency", &freq); - freq = maxu(freq, MIN_OUTPUT_RATE); - - device->UpdateSize = (ALuint64)device->UpdateSize * freq / - device->Frequency; - /* SSE and Neon do best with the update size being a multiple of 4 */ - if((CPUCapFlags&(CPU_CAP_SSE|CPU_CAP_NEON)) != 0) - device->UpdateSize = (device->UpdateSize+3)&~3; - - device->Frequency = freq; - - if(numMono > INT_MAX-numStereo) - numMono = INT_MAX-numStereo; - numMono += numStereo; - if(ConfigValueInt(alstr_get_cstr(device->DeviceName), NULL, "sources", &numMono)) - { - if(numMono <= 0) - numMono = 256; - } - else - numMono = maxi(numMono, 256); - numStereo = mini(numStereo, numMono); - numMono -= numStereo; - device->SourcesMax = numMono + numStereo; - - device->NumMonoSources = numMono; - device->NumStereoSources = numStereo; - - if(ConfigValueInt(alstr_get_cstr(device->DeviceName), NULL, "sends", &new_sends)) - new_sends = mini(numSends, clampi(new_sends, 0, MAX_SENDS)); - else - new_sends = numSends; - } - - if((device->Flags&DEVICE_RUNNING)) - return ALC_NO_ERROR; - - al_free(device->Uhj_Encoder); - device->Uhj_Encoder = NULL; - - al_free(device->Bs2b); - device->Bs2b = NULL; - - al_free(device->ChannelDelay[0].Buffer); - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - { - device->ChannelDelay[i].Length = 0; - device->ChannelDelay[i].Buffer = NULL; - } - - al_free(device->Dry.Buffer); - device->Dry.Buffer = NULL; - device->Dry.NumChannels = 0; - device->FOAOut.Buffer = NULL; - device->FOAOut.NumChannels = 0; - device->RealOut.Buffer = NULL; - device->RealOut.NumChannels = 0; - - UpdateClockBase(device); - device->FixedLatency = 0; - - device->DitherSeed = DITHER_RNG_SEED; - - /************************************************************************* - * Update device format request if HRTF is requested - */ - device->HrtfStatus = ALC_HRTF_DISABLED_SOFT; - if(device->Type != Loopback) - { - const char *hrtf; - if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "hrtf", &hrtf)) - { - if(strcasecmp(hrtf, "true") == 0) - hrtf_userreq = Hrtf_Enable; - else if(strcasecmp(hrtf, "false") == 0) - hrtf_userreq = Hrtf_Disable; - else if(strcasecmp(hrtf, "auto") != 0) - ERR("Unexpected hrtf value: %s\n", hrtf); - } - - if(hrtf_userreq == Hrtf_Enable || (hrtf_userreq != Hrtf_Disable && hrtf_appreq == Hrtf_Enable)) - { - struct Hrtf *hrtf = NULL; - if(VECTOR_SIZE(device->HrtfList) == 0) - { - VECTOR_DEINIT(device->HrtfList); - device->HrtfList = EnumerateHrtf(device->DeviceName); - } - if(VECTOR_SIZE(device->HrtfList) > 0) - { - if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->HrtfList)) - hrtf = GetLoadedHrtf(VECTOR_ELEM(device->HrtfList, hrtf_id).hrtf); - else - hrtf = GetLoadedHrtf(VECTOR_ELEM(device->HrtfList, 0).hrtf); - } - - if(hrtf) - { - device->FmtChans = DevFmtStereo; - device->Frequency = hrtf->sampleRate; - device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_FREQUENCY_REQUEST; - if(device->HrtfHandle) - Hrtf_DecRef(device->HrtfHandle); - device->HrtfHandle = hrtf; - } - else - { - hrtf_userreq = Hrtf_Default; - hrtf_appreq = Hrtf_Disable; - device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; - } - } - } - - oldFreq = device->Frequency; - oldChans = device->FmtChans; - oldType = device->FmtType; - - TRACE("Pre-reset: %s%s, %s%s, %s%uhz, %u update size x%d\n", - (device->Flags&DEVICE_CHANNELS_REQUEST)?"*":"", DevFmtChannelsString(device->FmtChans), - (device->Flags&DEVICE_SAMPLE_TYPE_REQUEST)?"*":"", DevFmtTypeString(device->FmtType), - (device->Flags&DEVICE_FREQUENCY_REQUEST)?"*":"", device->Frequency, - device->UpdateSize, device->NumUpdates - ); - - if(V0(device->Backend,reset)() == ALC_FALSE) - return ALC_INVALID_DEVICE; - - if(device->FmtChans != oldChans && (device->Flags&DEVICE_CHANNELS_REQUEST)) - { - ERR("Failed to set %s, got %s instead\n", DevFmtChannelsString(oldChans), - DevFmtChannelsString(device->FmtChans)); - device->Flags &= ~DEVICE_CHANNELS_REQUEST; - } - if(device->FmtType != oldType && (device->Flags&DEVICE_SAMPLE_TYPE_REQUEST)) - { - ERR("Failed to set %s, got %s instead\n", DevFmtTypeString(oldType), - DevFmtTypeString(device->FmtType)); - device->Flags &= ~DEVICE_SAMPLE_TYPE_REQUEST; - } - if(device->Frequency != oldFreq && (device->Flags&DEVICE_FREQUENCY_REQUEST)) - { - ERR("Failed to set %uhz, got %uhz instead\n", oldFreq, device->Frequency); - device->Flags &= ~DEVICE_FREQUENCY_REQUEST; - } - - if((device->UpdateSize&3) != 0) - { - if((CPUCapFlags&CPU_CAP_SSE)) - WARN("SSE performs best with multiple of 4 update sizes (%u)\n", device->UpdateSize); - if((CPUCapFlags&CPU_CAP_NEON)) - WARN("NEON performs best with multiple of 4 update sizes (%u)\n", device->UpdateSize); - } - - TRACE("Post-reset: %s, %s, %uhz, %u update size x%d\n", - DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), - device->Frequency, device->UpdateSize, device->NumUpdates - ); - - aluInitRenderer(device, hrtf_id, hrtf_appreq, hrtf_userreq); - TRACE("Channel config, Dry: %d, FOA: %d, Real: %d\n", device->Dry.NumChannels, - device->FOAOut.NumChannels, device->RealOut.NumChannels); - - /* Allocate extra channels for any post-filter output. */ - size = (device->Dry.NumChannels + device->FOAOut.NumChannels + - device->RealOut.NumChannels)*sizeof(device->Dry.Buffer[0]); - - TRACE("Allocating "SZFMT" channels, "SZFMT" bytes\n", size/sizeof(device->Dry.Buffer[0]), size); - device->Dry.Buffer = al_calloc(16, size); - if(!device->Dry.Buffer) - { - ERR("Failed to allocate "SZFMT" bytes for mix buffer\n", size); - return ALC_INVALID_DEVICE; - } - - if(device->RealOut.NumChannels != 0) - device->RealOut.Buffer = device->Dry.Buffer + device->Dry.NumChannels + - device->FOAOut.NumChannels; - else - { - device->RealOut.Buffer = device->Dry.Buffer; - device->RealOut.NumChannels = device->Dry.NumChannels; - } - - if(device->FOAOut.NumChannels != 0) - device->FOAOut.Buffer = device->Dry.Buffer + device->Dry.NumChannels; - else - { - device->FOAOut.Buffer = device->Dry.Buffer; - device->FOAOut.NumChannels = device->Dry.NumChannels; - } - - device->NumAuxSends = new_sends; - TRACE("Max sources: %d (%d + %d), effect slots: %d, sends: %d\n", - device->SourcesMax, device->NumMonoSources, device->NumStereoSources, - device->AuxiliaryEffectSlotMax, device->NumAuxSends); - - device->DitherDepth = 0.0f; - if(GetConfigValueBool(alstr_get_cstr(device->DeviceName), NULL, "dither", 1)) - { - ALint depth = 0; - ConfigValueInt(alstr_get_cstr(device->DeviceName), NULL, "dither-depth", &depth); - if(depth <= 0) - { - switch(device->FmtType) - { - case DevFmtByte: - case DevFmtUByte: - depth = 8; - break; - case DevFmtShort: - case DevFmtUShort: - depth = 16; - break; - case DevFmtInt: - case DevFmtUInt: - case DevFmtFloat: - break; - } - } - - if(depth > 0) - { - depth = clampi(depth, 2, 24); - device->DitherDepth = powf(2.0f, (ALfloat)(depth-1)); - } - } - if(!(device->DitherDepth > 0.0f)) - TRACE("Dithering disabled\n"); - else - TRACE("Dithering enabled (%g-bit, %g)\n", log2f(device->DitherDepth)+1.0f, - device->DitherDepth); - - device->LimiterState = gainLimiter; - if(ConfigValueBool(alstr_get_cstr(device->DeviceName), NULL, "output-limiter", &val)) - gainLimiter = val ? ALC_TRUE : ALC_FALSE; - - /* Valid values for gainLimiter are ALC_DONT_CARE_SOFT, ALC_TRUE, and - * ALC_FALSE. For ALC_DONT_CARE_SOFT, use the limiter for integer-based - * output (where samples must be clamped), and don't for floating-point - * (which can take unclamped samples). - */ - if(gainLimiter == ALC_DONT_CARE_SOFT) - { - switch(device->FmtType) - { - case DevFmtByte: - case DevFmtUByte: - case DevFmtShort: - case DevFmtUShort: - case DevFmtInt: - case DevFmtUInt: - gainLimiter = ALC_TRUE; - break; - case DevFmtFloat: - gainLimiter = ALC_FALSE; - break; - } - } - if(gainLimiter != ALC_FALSE) - { - ALfloat thrshld = 1.0f; - switch(device->FmtType) - { - case DevFmtByte: - case DevFmtUByte: - thrshld = 127.0f / 128.0f; - break; - case DevFmtShort: - case DevFmtUShort: - thrshld = 32767.0f / 32768.0f; - break; - case DevFmtInt: - case DevFmtUInt: - case DevFmtFloat: - break; - } - if(device->DitherDepth > 0.0f) - thrshld -= 1.0f / device->DitherDepth; - - al_free(device->Limiter); - device->Limiter = CreateDeviceLimiter(device, log10f(thrshld) * 20.0f); - device->FixedLatency += (ALuint)(GetCompressorLookAhead(device->Limiter) * - DEVICE_CLOCK_RES / device->Frequency); - } - else - { - al_free(device->Limiter); - device->Limiter = NULL; - } - TRACE("Output limiter %s\n", device->Limiter ? "enabled" : "disabled"); - - aluSelectPostProcess(device); - - TRACE("Fixed device latency: %uns\n", device->FixedLatency); - - /* Need to delay returning failure until replacement Send arrays have been - * allocated with the appropriate size. - */ - update_failed = AL_FALSE; - START_MIXER_MODE(); - context = ATOMIC_LOAD_SEQ(&device->ContextList); - while(context) - { - SourceSubList *sublist, *subend; - struct ALvoiceProps *vprops; - ALsizei pos; - - if(context->DefaultSlot) - { - ALeffectslot *slot = context->DefaultSlot; - ALeffectState *state = slot->Effect.State; - - state->OutBuffer = device->Dry.Buffer; - state->OutChannels = device->Dry.NumChannels; - if(V(state,deviceUpdate)(device) == AL_FALSE) - update_failed = AL_TRUE; - else - UpdateEffectSlotProps(slot, context); - } - - almtx_lock(&context->PropLock); - almtx_lock(&context->EffectSlotLock); - for(pos = 0;pos < (ALsizei)VECTOR_SIZE(context->EffectSlotList);pos++) - { - ALeffectslot *slot = VECTOR_ELEM(context->EffectSlotList, pos); - ALeffectState *state = slot->Effect.State; - - state->OutBuffer = device->Dry.Buffer; - state->OutChannels = device->Dry.NumChannels; - if(V(state,deviceUpdate)(device) == AL_FALSE) - update_failed = AL_TRUE; - else - UpdateEffectSlotProps(slot, context); - } - almtx_unlock(&context->EffectSlotLock); - - almtx_lock(&context->SourceLock); - sublist = VECTOR_BEGIN(context->SourceList); - subend = VECTOR_END(context->SourceList); - for(;sublist != subend;++sublist) - { - ALuint64 usemask = ~sublist->FreeMask; - while(usemask) - { - ALsizei idx = CTZ64(usemask); - ALsource *source = sublist->Sources + idx; - - usemask &= ~(U64(1) << idx); - - if(old_sends != device->NumAuxSends) - { - ALvoid *sends = al_calloc(16, device->NumAuxSends*sizeof(source->Send[0])); - ALsizei s; - - memcpy(sends, source->Send, - mini(device->NumAuxSends, old_sends)*sizeof(source->Send[0]) - ); - for(s = device->NumAuxSends;s < old_sends;s++) - { - if(source->Send[s].Slot) - DecrementRef(&source->Send[s].Slot->ref); - source->Send[s].Slot = NULL; - } - al_free(source->Send); - source->Send = sends; - for(s = old_sends;s < device->NumAuxSends;s++) - { - source->Send[s].Slot = NULL; - source->Send[s].Gain = 1.0f; - source->Send[s].GainHF = 1.0f; - source->Send[s].HFReference = LOWPASSFREQREF; - source->Send[s].GainLF = 1.0f; - source->Send[s].LFReference = HIGHPASSFREQREF; - } - } - - ATOMIC_STORE(&source->PropsClean, AL_FALSE, almemory_order_release); - } - } - - /* Clear any pre-existing voice property structs, in case the number of - * auxiliary sends is changing. Active sources will have updates - * respecified in UpdateAllSourceProps. - */ - vprops = ATOMIC_EXCHANGE_PTR(&context->FreeVoiceProps, NULL, almemory_order_acq_rel); - while(vprops) - { - struct ALvoiceProps *next = ATOMIC_LOAD(&vprops->next, almemory_order_relaxed); - al_free(vprops); - vprops = next; - } - - AllocateVoices(context, context->MaxVoices, old_sends); - for(pos = 0;pos < context->VoiceCount;pos++) - { - ALvoice *voice = context->Voices[pos]; - - al_free(ATOMIC_EXCHANGE_PTR(&voice->Update, NULL, almemory_order_acq_rel)); - - if(ATOMIC_LOAD(&voice->Source, almemory_order_acquire) == NULL) - continue; - - if(device->AvgSpeakerDist > 0.0f) - { - /* Reinitialize the NFC filters for new parameters. */ - ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / - (device->AvgSpeakerDist * device->Frequency); - for(i = 0;i < voice->NumChannels;i++) - NfcFilterCreate(&voice->Direct.Params[i].NFCtrlFilter, 0.0f, w1); - } - } - almtx_unlock(&context->SourceLock); - - ATOMIC_STORE(&context->PropsClean, AL_TRUE, almemory_order_release); - UpdateContextProps(context); - ATOMIC_STORE(&context->Listener->PropsClean, AL_TRUE, almemory_order_release); - UpdateListenerProps(context); - UpdateAllSourceProps(context); - almtx_unlock(&context->PropLock); - - context = ATOMIC_LOAD(&context->next, almemory_order_relaxed); - } - END_MIXER_MODE(); - if(update_failed) - return ALC_INVALID_DEVICE; - - if(!(device->Flags&DEVICE_PAUSED)) - { - if(V0(device->Backend,start)() == ALC_FALSE) - return ALC_INVALID_DEVICE; - device->Flags |= DEVICE_RUNNING; - } - - return ALC_NO_ERROR; -} - - -static void InitDevice(ALCdevice *device, enum DeviceType type) -{ - ALsizei i; - - InitRef(&device->ref, 1); - ATOMIC_INIT(&device->Connected, ALC_TRUE); - device->Type = type; - ATOMIC_INIT(&device->LastError, ALC_NO_ERROR); - - device->Flags = 0; - device->Render_Mode = NormalRender; - device->AvgSpeakerDist = 0.0f; - device->LimiterState = ALC_DONT_CARE_SOFT; - - ATOMIC_INIT(&device->ContextList, NULL); - - device->ClockBase = 0; - device->SamplesDone = 0; - device->FixedLatency = 0; - - device->SourcesMax = 0; - device->AuxiliaryEffectSlotMax = 0; - device->NumAuxSends = 0; - - device->Dry.Buffer = NULL; - device->Dry.NumChannels = 0; - device->FOAOut.Buffer = NULL; - device->FOAOut.NumChannels = 0; - device->RealOut.Buffer = NULL; - device->RealOut.NumChannels = 0; - - AL_STRING_INIT(device->DeviceName); - - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - { - device->ChannelDelay[i].Gain = 1.0f; - device->ChannelDelay[i].Length = 0; - device->ChannelDelay[i].Buffer = NULL; - } - - device->HrtfName = NULL; - VECTOR_INIT(device->HrtfList); - device->HrtfHandle = NULL; - device->Hrtf = NULL; - device->Bs2b = NULL; - device->Uhj_Encoder = NULL; - device->AmbiDecoder = NULL; - device->AmbiUp = NULL; - device->Stablizer = NULL; - device->Limiter = NULL; - - VECTOR_INIT(device->BufferList); - almtx_init(&device->BufferLock, almtx_plain); - - VECTOR_INIT(device->EffectList); - almtx_init(&device->EffectLock, almtx_plain); - - VECTOR_INIT(device->FilterList); - almtx_init(&device->FilterLock, almtx_plain); - - almtx_init(&device->BackendLock, almtx_plain); - device->Backend = NULL; - - ATOMIC_INIT(&device->next, NULL); -} - -/* FreeDevice - * - * Frees the device structure, and destroys any objects the app failed to - * delete. Called once there's no more references on the device. - */ -static ALCvoid FreeDevice(ALCdevice *device) -{ - ALsizei i; - - TRACE("%p\n", device); - - if(device->Backend) - DELETE_OBJ(device->Backend); - device->Backend = NULL; - - almtx_destroy(&device->BackendLock); - - ReleaseALBuffers(device); -#define FREE_BUFFERSUBLIST(x) al_free((x)->Buffers) - VECTOR_FOR_EACH(BufferSubList, device->BufferList, FREE_BUFFERSUBLIST); -#undef FREE_BUFFERSUBLIST - VECTOR_DEINIT(device->BufferList); - almtx_destroy(&device->BufferLock); - - ReleaseALEffects(device); -#define FREE_EFFECTSUBLIST(x) al_free((x)->Effects) - VECTOR_FOR_EACH(EffectSubList, device->EffectList, FREE_EFFECTSUBLIST); -#undef FREE_EFFECTSUBLIST - VECTOR_DEINIT(device->EffectList); - almtx_destroy(&device->EffectLock); - - ReleaseALFilters(device); -#define FREE_FILTERSUBLIST(x) al_free((x)->Filters) - VECTOR_FOR_EACH(FilterSubList, device->FilterList, FREE_FILTERSUBLIST); -#undef FREE_FILTERSUBLIST - VECTOR_DEINIT(device->FilterList); - almtx_destroy(&device->FilterLock); - - al_free(device->HrtfName); - device->HrtfName = NULL; - FreeHrtfList(&device->HrtfList); - if(device->HrtfHandle) - Hrtf_DecRef(device->HrtfHandle); - device->HrtfHandle = NULL; - al_free(device->Hrtf); - device->Hrtf = NULL; - - al_free(device->Bs2b); - device->Bs2b = NULL; - - al_free(device->Uhj_Encoder); - device->Uhj_Encoder = NULL; - - bformatdec_free(&device->AmbiDecoder); - ambiup_free(&device->AmbiUp); - - al_free(device->Stablizer); - device->Stablizer = NULL; - - al_free(device->Limiter); - device->Limiter = NULL; - - al_free(device->ChannelDelay[0].Buffer); - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - { - device->ChannelDelay[i].Gain = 1.0f; - device->ChannelDelay[i].Length = 0; - device->ChannelDelay[i].Buffer = NULL; - } - - AL_STRING_DEINIT(device->DeviceName); - - al_free(device->Dry.Buffer); - device->Dry.Buffer = NULL; - device->Dry.NumChannels = 0; - device->FOAOut.Buffer = NULL; - device->FOAOut.NumChannels = 0; - device->RealOut.Buffer = NULL; - device->RealOut.NumChannels = 0; - - al_free(device); -} - - -void ALCdevice_IncRef(ALCdevice *device) -{ - uint ref; - ref = IncrementRef(&device->ref); - TRACEREF("%p increasing refcount to %u\n", device, ref); -} - -void ALCdevice_DecRef(ALCdevice *device) -{ - uint ref; - ref = DecrementRef(&device->ref); - TRACEREF("%p decreasing refcount to %u\n", device, ref); - if(ref == 0) FreeDevice(device); -} - -/* VerifyDevice - * - * Checks if the device handle is valid, and increments its ref count if so. - */ -static ALCboolean VerifyDevice(ALCdevice **device) -{ - ALCdevice *tmpDevice; - - LockLists(); - tmpDevice = ATOMIC_LOAD_SEQ(&DeviceList); - while(tmpDevice) - { - if(tmpDevice == *device) - { - ALCdevice_IncRef(tmpDevice); - UnlockLists(); - return ALC_TRUE; - } - tmpDevice = ATOMIC_LOAD(&tmpDevice->next, almemory_order_relaxed); - } - UnlockLists(); - - *device = NULL; - return ALC_FALSE; -} - - -/* InitContext - * - * Initializes context fields - */ -static ALvoid InitContext(ALCcontext *Context) -{ - ALlistener *listener = Context->Listener; - struct ALeffectslotArray *auxslots; - - //Initialise listener - listener->Gain = 1.0f; - listener->Position[0] = 0.0f; - listener->Position[1] = 0.0f; - listener->Position[2] = 0.0f; - listener->Velocity[0] = 0.0f; - listener->Velocity[1] = 0.0f; - listener->Velocity[2] = 0.0f; - listener->Forward[0] = 0.0f; - listener->Forward[1] = 0.0f; - listener->Forward[2] = -1.0f; - listener->Up[0] = 0.0f; - listener->Up[1] = 1.0f; - listener->Up[2] = 0.0f; - ATOMIC_INIT(&listener->PropsClean, AL_TRUE); - - ATOMIC_INIT(&listener->Update, NULL); - - //Validate Context - InitRef(&Context->UpdateCount, 0); - ATOMIC_INIT(&Context->HoldUpdates, AL_FALSE); - Context->GainBoost = 1.0f; - almtx_init(&Context->PropLock, almtx_plain); - ATOMIC_INIT(&Context->LastError, AL_NO_ERROR); - VECTOR_INIT(Context->SourceList); - Context->NumSources = 0; - almtx_init(&Context->SourceLock, almtx_plain); - VECTOR_INIT(Context->EffectSlotList); - almtx_init(&Context->EffectSlotLock, almtx_plain); - - if(Context->DefaultSlot) - { - auxslots = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, 1)); - auxslots->count = 1; - auxslots->slot[0] = Context->DefaultSlot; - } - else - { - auxslots = al_calloc(DEF_ALIGN, sizeof(struct ALeffectslotArray)); - auxslots->count = 0; - } - ATOMIC_INIT(&Context->ActiveAuxSlots, auxslots); - - //Set globals - Context->DistanceModel = DefaultDistanceModel; - Context->SourceDistanceModel = AL_FALSE; - Context->DopplerFactor = 1.0f; - Context->DopplerVelocity = 1.0f; - Context->SpeedOfSound = SPEEDOFSOUNDMETRESPERSEC; - Context->MetersPerUnit = AL_DEFAULT_METERS_PER_UNIT; - ATOMIC_INIT(&Context->PropsClean, AL_TRUE); - ATOMIC_INIT(&Context->DeferUpdates, AL_FALSE); - alsem_init(&Context->EventSem, 0); - Context->AsyncEvents = NULL; - ATOMIC_INIT(&Context->EnabledEvts, 0); - almtx_init(&Context->EventCbLock, almtx_plain); - Context->EventCb = NULL; - Context->EventParam = NULL; - - ATOMIC_INIT(&Context->Update, NULL); - ATOMIC_INIT(&Context->FreeContextProps, NULL); - ATOMIC_INIT(&Context->FreeListenerProps, NULL); - ATOMIC_INIT(&Context->FreeVoiceProps, NULL); - ATOMIC_INIT(&Context->FreeEffectslotProps, NULL); - - Context->ExtensionList = alExtList; - - - listener->Params.Matrix = IdentityMatrixf; - aluVectorSet(&listener->Params.Velocity, 0.0f, 0.0f, 0.0f, 0.0f); - listener->Params.Gain = listener->Gain; - listener->Params.MetersPerUnit = Context->MetersPerUnit; - listener->Params.DopplerFactor = Context->DopplerFactor; - listener->Params.SpeedOfSound = Context->SpeedOfSound * Context->DopplerVelocity; - listener->Params.ReverbSpeedOfSound = listener->Params.SpeedOfSound * - listener->Params.MetersPerUnit; - listener->Params.SourceDistanceModel = Context->SourceDistanceModel; - listener->Params.DistanceModel = Context->DistanceModel; - - - Context->AsyncEvents = ll_ringbuffer_create(63, sizeof(AsyncEvent), false); - if(althrd_create(&Context->EventThread, EventThread, Context) != althrd_success) - ERR("Failed to start event thread! Expect problems.\n"); -} - - -/* FreeContext - * - * Cleans up the context, and destroys any remaining objects the app failed to - * delete. Called once there's no more references on the context. - */ -static void FreeContext(ALCcontext *context) -{ - ALlistener *listener = context->Listener; - struct ALeffectslotArray *auxslots; - struct ALeffectslotProps *eprops; - struct ALlistenerProps *lprops; - struct ALcontextProps *cprops; - struct ALvoiceProps *vprops; - size_t count; - ALsizei i; - - TRACE("%p\n", context); - - if((cprops=ATOMIC_LOAD(&context->Update, almemory_order_acquire)) != NULL) - { - TRACE("Freed unapplied context update %p\n", cprops); - al_free(cprops); - } - - count = 0; - cprops = ATOMIC_LOAD(&context->FreeContextProps, almemory_order_acquire); - while(cprops) - { - struct ALcontextProps *next = ATOMIC_LOAD(&cprops->next, almemory_order_acquire); - al_free(cprops); - cprops = next; - ++count; - } - TRACE("Freed "SZFMT" context property object%s\n", count, (count==1)?"":"s"); - - if(context->DefaultSlot) - { - DeinitEffectSlot(context->DefaultSlot); - context->DefaultSlot = NULL; - } - - auxslots = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, NULL, almemory_order_relaxed); - al_free(auxslots); - - ReleaseALSources(context); -#define FREE_SOURCESUBLIST(x) al_free((x)->Sources) - VECTOR_FOR_EACH(SourceSubList, context->SourceList, FREE_SOURCESUBLIST); -#undef FREE_SOURCESUBLIST - VECTOR_DEINIT(context->SourceList); - context->NumSources = 0; - almtx_destroy(&context->SourceLock); - - count = 0; - eprops = ATOMIC_LOAD(&context->FreeEffectslotProps, almemory_order_relaxed); - while(eprops) - { - struct ALeffectslotProps *next = ATOMIC_LOAD(&eprops->next, almemory_order_relaxed); - if(eprops->State) ALeffectState_DecRef(eprops->State); - al_free(eprops); - eprops = next; - ++count; - } - TRACE("Freed "SZFMT" AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s"); - - ReleaseALAuxiliaryEffectSlots(context); -#define FREE_EFFECTSLOTPTR(x) al_free(*(x)) - VECTOR_FOR_EACH(ALeffectslotPtr, context->EffectSlotList, FREE_EFFECTSLOTPTR); -#undef FREE_EFFECTSLOTPTR - VECTOR_DEINIT(context->EffectSlotList); - almtx_destroy(&context->EffectSlotLock); - - count = 0; - vprops = ATOMIC_LOAD(&context->FreeVoiceProps, almemory_order_relaxed); - while(vprops) - { - struct ALvoiceProps *next = ATOMIC_LOAD(&vprops->next, almemory_order_relaxed); - al_free(vprops); - vprops = next; - ++count; - } - TRACE("Freed "SZFMT" voice property object%s\n", count, (count==1)?"":"s"); - - for(i = 0;i < context->VoiceCount;i++) - DeinitVoice(context->Voices[i]); - al_free(context->Voices); - context->Voices = NULL; - context->VoiceCount = 0; - context->MaxVoices = 0; - - if((lprops=ATOMIC_LOAD(&listener->Update, almemory_order_acquire)) != NULL) - { - TRACE("Freed unapplied listener update %p\n", lprops); - al_free(lprops); - } - count = 0; - lprops = ATOMIC_LOAD(&context->FreeListenerProps, almemory_order_acquire); - while(lprops) - { - struct ALlistenerProps *next = ATOMIC_LOAD(&lprops->next, almemory_order_acquire); - al_free(lprops); - lprops = next; - ++count; - } - TRACE("Freed "SZFMT" listener property object%s\n", count, (count==1)?"":"s"); - - almtx_destroy(&context->EventCbLock); - alsem_destroy(&context->EventSem); - - ll_ringbuffer_free(context->AsyncEvents); - context->AsyncEvents = NULL; - - almtx_destroy(&context->PropLock); - - ALCdevice_DecRef(context->Device); - context->Device = NULL; - - //Invalidate context - memset(context, 0, sizeof(ALCcontext)); - al_free(context); -} - -/* ReleaseContext - * - * Removes the context reference from the given device and removes it from - * being current on the running thread or globally. Returns true if other - * contexts still exist on the device. - */ -static bool ReleaseContext(ALCcontext *context, ALCdevice *device) -{ - static const AsyncEvent kill_evt = ASYNC_EVENT(EventType_KillThread); - ALCcontext *origctx, *newhead; - bool ret = true; - - if(altss_get(LocalContext) == context) - { - WARN("%p released while current on thread\n", context); - altss_set(LocalContext, NULL); - ALCcontext_DecRef(context); - } - - origctx = context; - if(ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&GlobalContext, &origctx, NULL)) - ALCcontext_DecRef(context); - - V0(device->Backend,lock)(); - origctx = context; - newhead = ATOMIC_LOAD(&context->next, almemory_order_relaxed); - if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&device->ContextList, &origctx, newhead)) - { - ALCcontext *list; - do { - /* origctx is what the desired context failed to match. Try - * swapping out the next one in the list. - */ - list = origctx; - origctx = context; - } while(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&list->next, &origctx, newhead)); - } - else - ret = !!newhead; - V0(device->Backend,unlock)(); - - /* Make sure the context is finished and no longer processing in the mixer - * before sending the message queue kill event. The backend's lock does - * this, although waiting for a non-odd mix count would work too. - */ - - while(ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1) == 0) - althrd_yield(); - alsem_post(&context->EventSem); - althrd_join(context->EventThread, NULL); - - ALCcontext_DecRef(context); - return ret; -} - -static void ALCcontext_IncRef(ALCcontext *context) -{ - uint ref = IncrementRef(&context->ref); - TRACEREF("%p increasing refcount to %u\n", context, ref); -} - -void ALCcontext_DecRef(ALCcontext *context) -{ - uint ref = DecrementRef(&context->ref); - TRACEREF("%p decreasing refcount to %u\n", context, ref); - if(ref == 0) FreeContext(context); -} - -static void ReleaseThreadCtx(void *ptr) -{ - ALCcontext *context = ptr; - uint ref = DecrementRef(&context->ref); - TRACEREF("%p decreasing refcount to %u\n", context, ref); - ERR("Context %p current for thread being destroyed, possible leak!\n", context); -} - -/* VerifyContext - * - * Checks that the given context is valid, and increments its reference count. - */ -static ALCboolean VerifyContext(ALCcontext **context) -{ - ALCdevice *dev; - - LockLists(); - dev = ATOMIC_LOAD_SEQ(&DeviceList); - while(dev) - { - ALCcontext *ctx = ATOMIC_LOAD(&dev->ContextList, almemory_order_acquire); - while(ctx) - { - if(ctx == *context) - { - ALCcontext_IncRef(ctx); - UnlockLists(); - return ALC_TRUE; - } - ctx = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed); - } - dev = ATOMIC_LOAD(&dev->next, almemory_order_relaxed); - } - UnlockLists(); - - *context = NULL; - return ALC_FALSE; -} - - -/* GetContextRef - * - * Returns the currently active context for this thread, and adds a reference - * without locking it. - */ -ALCcontext *GetContextRef(void) -{ - ALCcontext *context; - - context = altss_get(LocalContext); - if(context) - ALCcontext_IncRef(context); - else - { - LockLists(); - context = ATOMIC_LOAD_SEQ(&GlobalContext); - if(context) - ALCcontext_IncRef(context); - UnlockLists(); - } - - return context; -} - - -void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) -{ - ALCdevice *device = context->Device; - ALsizei num_sends = device->NumAuxSends; - struct ALvoiceProps *props; - size_t sizeof_props; - size_t sizeof_voice; - ALvoice **voices; - ALvoice *voice; - ALsizei v = 0; - size_t size; - - if(num_voices == context->MaxVoices && num_sends == old_sends) - return; - - /* Allocate the voice pointers, voices, and the voices' stored source - * property set (including the dynamically-sized Send[] array) in one - * chunk. - */ - sizeof_voice = RoundUp(FAM_SIZE(ALvoice, Send, num_sends), 16); - sizeof_props = RoundUp(FAM_SIZE(struct ALvoiceProps, Send, num_sends), 16); - size = sizeof(ALvoice*) + sizeof_voice + sizeof_props; - - voices = al_calloc(16, RoundUp(size*num_voices, 16)); - /* The voice and property objects are stored interleaved since they're - * paired together. - */ - voice = (ALvoice*)((char*)voices + RoundUp(num_voices*sizeof(ALvoice*), 16)); - props = (struct ALvoiceProps*)((char*)voice + sizeof_voice); - - if(context->Voices) - { - const ALsizei v_count = mini(context->VoiceCount, num_voices); - const ALsizei s_count = mini(old_sends, num_sends); - - for(;v < v_count;v++) - { - ALvoice *old_voice = context->Voices[v]; - ALsizei i; - - /* Copy the old voice data and source property set to the new - * storage. - */ - *voice = *old_voice; - for(i = 0;i < s_count;i++) - voice->Send[i] = old_voice->Send[i]; - *props = *(old_voice->Props); - for(i = 0;i < s_count;i++) - props->Send[i] = old_voice->Props->Send[i]; - - /* Set this voice's property set pointer and voice reference. */ - voice->Props = props; - voices[v] = voice; - - /* Increment pointers to the next storage space. */ - voice = (ALvoice*)((char*)props + sizeof_props); - props = (struct ALvoiceProps*)((char*)voice + sizeof_voice); - } - /* Deinit any left over voices that weren't copied over to the new - * array. NOTE: If this does anything, v equals num_voices and - * num_voices is less than VoiceCount, so the following loop won't do - * anything. - */ - for(;v < context->VoiceCount;v++) - DeinitVoice(context->Voices[v]); - } - /* Finish setting the voices' property set pointers and references. */ - for(;v < num_voices;v++) - { - ATOMIC_INIT(&voice->Update, NULL); - - voice->Props = props; - voices[v] = voice; - - voice = (ALvoice*)((char*)props + sizeof_props); - props = (struct ALvoiceProps*)((char*)voice + sizeof_voice); - } - - al_free(context->Voices); - context->Voices = voices; - context->MaxVoices = num_voices; - context->VoiceCount = mini(context->VoiceCount, num_voices); -} - - -/************************************************ - * Standard ALC functions - ************************************************/ - -/* alcGetError - * - * Return last ALC generated error code for the given device -*/ -ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) -{ - ALCenum errorCode; - - if(VerifyDevice(&device)) - { - errorCode = ATOMIC_EXCHANGE_SEQ(&device->LastError, ALC_NO_ERROR); - ALCdevice_DecRef(device); - } - else - errorCode = ATOMIC_EXCHANGE_SEQ(&LastNullDeviceError, ALC_NO_ERROR); - - return errorCode; -} - - -/* alcSuspendContext - * - * Suspends updates for the given context - */ -ALC_API ALCvoid ALC_APIENTRY alcSuspendContext(ALCcontext *context) -{ - if(!SuspendDefers) - return; - - if(!VerifyContext(&context)) - alcSetError(NULL, ALC_INVALID_CONTEXT); - else - { - ALCcontext_DeferUpdates(context); - ALCcontext_DecRef(context); - } -} - -/* alcProcessContext - * - * Resumes processing updates for the given context - */ -ALC_API ALCvoid ALC_APIENTRY alcProcessContext(ALCcontext *context) -{ - if(!SuspendDefers) - return; - - if(!VerifyContext(&context)) - alcSetError(NULL, ALC_INVALID_CONTEXT); - else - { - ALCcontext_ProcessUpdates(context); - ALCcontext_DecRef(context); - } -} - - -/* alcGetString - * - * Returns information about the device, and error strings - */ -ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum param) -{ - const ALCchar *value = NULL; - - switch(param) - { - case ALC_NO_ERROR: - value = alcNoError; - break; - - case ALC_INVALID_ENUM: - value = alcErrInvalidEnum; - break; - - case ALC_INVALID_VALUE: - value = alcErrInvalidValue; - break; - - case ALC_INVALID_DEVICE: - value = alcErrInvalidDevice; - break; - - case ALC_INVALID_CONTEXT: - value = alcErrInvalidContext; - break; - - case ALC_OUT_OF_MEMORY: - value = alcErrOutOfMemory; - break; - - case ALC_DEVICE_SPECIFIER: - value = alcDefaultName; - break; - - case ALC_ALL_DEVICES_SPECIFIER: - if(VerifyDevice(&Device)) - { - value = alstr_get_cstr(Device->DeviceName); - ALCdevice_DecRef(Device); - } - else - { - ProbeAllDevicesList(); - value = alstr_get_cstr(alcAllDevicesList); - } - break; - - case ALC_CAPTURE_DEVICE_SPECIFIER: - if(VerifyDevice(&Device)) - { - value = alstr_get_cstr(Device->DeviceName); - ALCdevice_DecRef(Device); - } - else - { - ProbeCaptureDeviceList(); - value = alstr_get_cstr(alcCaptureDeviceList); - } - break; - - /* Default devices are always first in the list */ - case ALC_DEFAULT_DEVICE_SPECIFIER: - value = alcDefaultName; - break; - - case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: - if(alstr_empty(alcAllDevicesList)) - ProbeAllDevicesList(); - - VerifyDevice(&Device); - - free(alcDefaultAllDevicesSpecifier); - alcDefaultAllDevicesSpecifier = strdup(alstr_get_cstr(alcAllDevicesList)); - if(!alcDefaultAllDevicesSpecifier) - alcSetError(Device, ALC_OUT_OF_MEMORY); - - value = alcDefaultAllDevicesSpecifier; - if(Device) ALCdevice_DecRef(Device); - break; - - case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: - if(alstr_empty(alcCaptureDeviceList)) - ProbeCaptureDeviceList(); - - VerifyDevice(&Device); - - free(alcCaptureDefaultDeviceSpecifier); - alcCaptureDefaultDeviceSpecifier = strdup(alstr_get_cstr(alcCaptureDeviceList)); - if(!alcCaptureDefaultDeviceSpecifier) - alcSetError(Device, ALC_OUT_OF_MEMORY); - - value = alcCaptureDefaultDeviceSpecifier; - if(Device) ALCdevice_DecRef(Device); - break; - - case ALC_EXTENSIONS: - if(!VerifyDevice(&Device)) - value = alcNoDeviceExtList; - else - { - value = alcExtensionList; - ALCdevice_DecRef(Device); - } - break; - - case ALC_HRTF_SPECIFIER_SOFT: - if(!VerifyDevice(&Device)) - alcSetError(NULL, ALC_INVALID_DEVICE); - else - { - almtx_lock(&Device->BackendLock); - value = ((Device->HrtfHandle && Device->HrtfName) ? Device->HrtfName : ""); - almtx_unlock(&Device->BackendLock); - ALCdevice_DecRef(Device); - } - break; - - default: - VerifyDevice(&Device); - alcSetError(Device, ALC_INVALID_ENUM); - if(Device) ALCdevice_DecRef(Device); - break; - } - - return value; -} - - -static inline ALCsizei NumAttrsForDevice(ALCdevice *device) -{ - if(device->Type == Capture) return 9; - if(device->Type != Loopback) return 29; - if(device->FmtChans == DevFmtAmbi3D) - return 35; - return 29; -} - -static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) -{ - ALCsizei i; - - if(size <= 0 || values == NULL) - { - alcSetError(device, ALC_INVALID_VALUE); - return 0; - } - - if(!device) - { - switch(param) - { - case ALC_MAJOR_VERSION: - values[0] = alcMajorVersion; - return 1; - case ALC_MINOR_VERSION: - values[0] = alcMinorVersion; - return 1; - - case ALC_ATTRIBUTES_SIZE: - case ALC_ALL_ATTRIBUTES: - case ALC_FREQUENCY: - case ALC_REFRESH: - case ALC_SYNC: - case ALC_MONO_SOURCES: - case ALC_STEREO_SOURCES: - case ALC_CAPTURE_SAMPLES: - case ALC_FORMAT_CHANNELS_SOFT: - case ALC_FORMAT_TYPE_SOFT: - case ALC_AMBISONIC_LAYOUT_SOFT: - case ALC_AMBISONIC_SCALING_SOFT: - case ALC_AMBISONIC_ORDER_SOFT: - case ALC_MAX_AMBISONIC_ORDER_SOFT: - alcSetError(NULL, ALC_INVALID_DEVICE); - return 0; - - default: - alcSetError(NULL, ALC_INVALID_ENUM); - return 0; - } - return 0; - } - - if(device->Type == Capture) - { - switch(param) - { - case ALC_ATTRIBUTES_SIZE: - values[0] = NumAttrsForDevice(device); - return 1; - - case ALC_ALL_ATTRIBUTES: - if(size < NumAttrsForDevice(device)) - { - alcSetError(device, ALC_INVALID_VALUE); - return 0; - } - - i = 0; - almtx_lock(&device->BackendLock); - values[i++] = ALC_MAJOR_VERSION; - values[i++] = alcMajorVersion; - values[i++] = ALC_MINOR_VERSION; - values[i++] = alcMinorVersion; - values[i++] = ALC_CAPTURE_SAMPLES; - values[i++] = V0(device->Backend,availableSamples)(); - values[i++] = ALC_CONNECTED; - values[i++] = ATOMIC_LOAD(&device->Connected, almemory_order_relaxed); - almtx_unlock(&device->BackendLock); - - values[i++] = 0; - return i; - - case ALC_MAJOR_VERSION: - values[0] = alcMajorVersion; - return 1; - case ALC_MINOR_VERSION: - values[0] = alcMinorVersion; - return 1; - - case ALC_CAPTURE_SAMPLES: - almtx_lock(&device->BackendLock); - values[0] = V0(device->Backend,availableSamples)(); - almtx_unlock(&device->BackendLock); - return 1; - - case ALC_CONNECTED: - values[0] = ATOMIC_LOAD(&device->Connected, almemory_order_acquire); - return 1; - - default: - alcSetError(device, ALC_INVALID_ENUM); - return 0; - } - return 0; - } - - /* render device */ - switch(param) - { - case ALC_ATTRIBUTES_SIZE: - values[0] = NumAttrsForDevice(device); - return 1; - - case ALC_ALL_ATTRIBUTES: - if(size < NumAttrsForDevice(device)) - { - alcSetError(device, ALC_INVALID_VALUE); - return 0; - } - - i = 0; - almtx_lock(&device->BackendLock); - values[i++] = ALC_MAJOR_VERSION; - values[i++] = alcMajorVersion; - values[i++] = ALC_MINOR_VERSION; - values[i++] = alcMinorVersion; - values[i++] = ALC_EFX_MAJOR_VERSION; - values[i++] = alcEFXMajorVersion; - values[i++] = ALC_EFX_MINOR_VERSION; - values[i++] = alcEFXMinorVersion; - - values[i++] = ALC_FREQUENCY; - values[i++] = device->Frequency; - if(device->Type != Loopback) - { - values[i++] = ALC_REFRESH; - values[i++] = device->Frequency / device->UpdateSize; - - values[i++] = ALC_SYNC; - values[i++] = ALC_FALSE; - } - else - { - if(device->FmtChans == DevFmtAmbi3D) - { - values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; - values[i++] = device->AmbiLayout; - - values[i++] = ALC_AMBISONIC_SCALING_SOFT; - values[i++] = device->AmbiScale; - - values[i++] = ALC_AMBISONIC_ORDER_SOFT; - values[i++] = device->AmbiOrder; - } - - values[i++] = ALC_FORMAT_CHANNELS_SOFT; - values[i++] = device->FmtChans; - - values[i++] = ALC_FORMAT_TYPE_SOFT; - values[i++] = device->FmtType; - } - - values[i++] = ALC_MONO_SOURCES; - values[i++] = device->NumMonoSources; - - values[i++] = ALC_STEREO_SOURCES; - values[i++] = device->NumStereoSources; - - values[i++] = ALC_MAX_AUXILIARY_SENDS; - values[i++] = device->NumAuxSends; - - values[i++] = ALC_HRTF_SOFT; - values[i++] = (device->HrtfHandle ? ALC_TRUE : ALC_FALSE); - - values[i++] = ALC_HRTF_STATUS_SOFT; - values[i++] = device->HrtfStatus; - - values[i++] = ALC_OUTPUT_LIMITER_SOFT; - values[i++] = device->Limiter ? ALC_TRUE : ALC_FALSE; - - values[i++] = ALC_MAX_AMBISONIC_ORDER_SOFT; - values[i++] = MAX_AMBI_ORDER; - almtx_unlock(&device->BackendLock); - - values[i++] = 0; - return i; - - case ALC_MAJOR_VERSION: - values[0] = alcMajorVersion; - return 1; - - case ALC_MINOR_VERSION: - values[0] = alcMinorVersion; - return 1; - - case ALC_EFX_MAJOR_VERSION: - values[0] = alcEFXMajorVersion; - return 1; - - case ALC_EFX_MINOR_VERSION: - values[0] = alcEFXMinorVersion; - return 1; - - case ALC_FREQUENCY: - values[0] = device->Frequency; - return 1; - - case ALC_REFRESH: - if(device->Type == Loopback) - { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; - } - almtx_lock(&device->BackendLock); - values[0] = device->Frequency / device->UpdateSize; - almtx_unlock(&device->BackendLock); - return 1; - - case ALC_SYNC: - if(device->Type == Loopback) - { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; - } - values[0] = ALC_FALSE; - return 1; - - case ALC_FORMAT_CHANNELS_SOFT: - if(device->Type != Loopback) - { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; - } - values[0] = device->FmtChans; - return 1; - - case ALC_FORMAT_TYPE_SOFT: - if(device->Type != Loopback) - { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; - } - values[0] = device->FmtType; - return 1; - - case ALC_AMBISONIC_LAYOUT_SOFT: - if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) - { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; - } - values[0] = device->AmbiLayout; - return 1; - - case ALC_AMBISONIC_SCALING_SOFT: - if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) - { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; - } - values[0] = device->AmbiScale; - return 1; - - case ALC_AMBISONIC_ORDER_SOFT: - if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) - { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; - } - values[0] = device->AmbiOrder; - return 1; - - case ALC_MONO_SOURCES: - values[0] = device->NumMonoSources; - return 1; - - case ALC_STEREO_SOURCES: - values[0] = device->NumStereoSources; - return 1; - - case ALC_MAX_AUXILIARY_SENDS: - values[0] = device->NumAuxSends; - return 1; - - case ALC_CONNECTED: - values[0] = ATOMIC_LOAD(&device->Connected, almemory_order_acquire); - return 1; - - case ALC_HRTF_SOFT: - values[0] = (device->HrtfHandle ? ALC_TRUE : ALC_FALSE); - return 1; - - case ALC_HRTF_STATUS_SOFT: - values[0] = device->HrtfStatus; - return 1; - - case ALC_NUM_HRTF_SPECIFIERS_SOFT: - almtx_lock(&device->BackendLock); - FreeHrtfList(&device->HrtfList); - device->HrtfList = EnumerateHrtf(device->DeviceName); - values[0] = (ALCint)VECTOR_SIZE(device->HrtfList); - almtx_unlock(&device->BackendLock); - return 1; - - case ALC_OUTPUT_LIMITER_SOFT: - values[0] = device->Limiter ? ALC_TRUE : ALC_FALSE; - return 1; - - case ALC_MAX_AMBISONIC_ORDER_SOFT: - values[0] = MAX_AMBI_ORDER; - return 1; - - default: - alcSetError(device, ALC_INVALID_ENUM); - return 0; - } - return 0; -} - -/* alcGetIntegerv - * - * Returns information about the device and the version of OpenAL - */ -ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) -{ - VerifyDevice(&device); - if(size <= 0 || values == NULL) - alcSetError(device, ALC_INVALID_VALUE); - else - GetIntegerv(device, param, size, values); - if(device) ALCdevice_DecRef(device); -} - -ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALCsizei size, ALCint64SOFT *values) -{ - ALCint *ivals; - ALsizei i; - - VerifyDevice(&device); - if(size <= 0 || values == NULL) - alcSetError(device, ALC_INVALID_VALUE); - else if(!device || device->Type == Capture) - { - ivals = malloc(size * sizeof(ALCint)); - size = GetIntegerv(device, pname, size, ivals); - for(i = 0;i < size;i++) - values[i] = ivals[i]; - free(ivals); - } - else /* render device */ - { - ClockLatency clock; - ALuint64 basecount; - ALuint samplecount; - ALuint refcount; - - switch(pname) - { - case ALC_ATTRIBUTES_SIZE: - *values = NumAttrsForDevice(device)+4; - break; - - case ALC_ALL_ATTRIBUTES: - if(size < NumAttrsForDevice(device)+4) - alcSetError(device, ALC_INVALID_VALUE); - else - { - i = 0; - almtx_lock(&device->BackendLock); - values[i++] = ALC_FREQUENCY; - values[i++] = device->Frequency; - - if(device->Type != Loopback) - { - values[i++] = ALC_REFRESH; - values[i++] = device->Frequency / device->UpdateSize; - - values[i++] = ALC_SYNC; - values[i++] = ALC_FALSE; - } - else - { - if(device->FmtChans == DevFmtAmbi3D) - { - values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; - values[i++] = device->AmbiLayout; - - values[i++] = ALC_AMBISONIC_SCALING_SOFT; - values[i++] = device->AmbiScale; - - values[i++] = ALC_AMBISONIC_ORDER_SOFT; - values[i++] = device->AmbiOrder; - } - - values[i++] = ALC_FORMAT_CHANNELS_SOFT; - values[i++] = device->FmtChans; - - values[i++] = ALC_FORMAT_TYPE_SOFT; - values[i++] = device->FmtType; - } - - values[i++] = ALC_MONO_SOURCES; - values[i++] = device->NumMonoSources; - - values[i++] = ALC_STEREO_SOURCES; - values[i++] = device->NumStereoSources; - - values[i++] = ALC_MAX_AUXILIARY_SENDS; - values[i++] = device->NumAuxSends; - - values[i++] = ALC_HRTF_SOFT; - values[i++] = (device->HrtfHandle ? ALC_TRUE : ALC_FALSE); - - values[i++] = ALC_HRTF_STATUS_SOFT; - values[i++] = device->HrtfStatus; - - values[i++] = ALC_OUTPUT_LIMITER_SOFT; - values[i++] = device->Limiter ? ALC_TRUE : ALC_FALSE; - - clock = GetClockLatency(device); - values[i++] = ALC_DEVICE_CLOCK_SOFT; - values[i++] = clock.ClockTime; - - values[i++] = ALC_DEVICE_LATENCY_SOFT; - values[i++] = clock.Latency; - almtx_unlock(&device->BackendLock); - - values[i++] = 0; - } - break; - - case ALC_DEVICE_CLOCK_SOFT: - almtx_lock(&device->BackendLock); - do { - while(((refcount=ReadRef(&device->MixCount))&1) != 0) - althrd_yield(); - basecount = device->ClockBase; - samplecount = device->SamplesDone; - } while(refcount != ReadRef(&device->MixCount)); - *values = basecount + (samplecount*DEVICE_CLOCK_RES/device->Frequency); - almtx_unlock(&device->BackendLock); - break; - - case ALC_DEVICE_LATENCY_SOFT: - almtx_lock(&device->BackendLock); - clock = GetClockLatency(device); - almtx_unlock(&device->BackendLock); - *values = clock.Latency; - break; - - case ALC_DEVICE_CLOCK_LATENCY_SOFT: - if(size < 2) - alcSetError(device, ALC_INVALID_VALUE); - else - { - almtx_lock(&device->BackendLock); - clock = GetClockLatency(device); - almtx_unlock(&device->BackendLock); - values[0] = clock.ClockTime; - values[1] = clock.Latency; - } - break; - - default: - ivals = malloc(size * sizeof(ALCint)); - size = GetIntegerv(device, pname, size, ivals); - for(i = 0;i < size;i++) - values[i] = ivals[i]; - free(ivals); - break; - } - } - if(device) - ALCdevice_DecRef(device); -} - - -/* alcIsExtensionPresent - * - * Determines if there is support for a particular extension - */ -ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extName) -{ - ALCboolean bResult = ALC_FALSE; - - VerifyDevice(&device); - - if(!extName) - alcSetError(device, ALC_INVALID_VALUE); - else - { - size_t len = strlen(extName); - const char *ptr = (device ? alcExtensionList : alcNoDeviceExtList); - while(ptr && *ptr) - { - if(strncasecmp(ptr, extName, len) == 0 && - (ptr[len] == '\0' || isspace(ptr[len]))) - { - bResult = ALC_TRUE; - break; - } - if((ptr=strchr(ptr, ' ')) != NULL) - { - do { - ++ptr; - } while(isspace(*ptr)); - } - } - } - if(device) - ALCdevice_DecRef(device); - return bResult; -} - - -/* alcGetProcAddress - * - * Retrieves the function address for a particular extension function - */ -ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcName) -{ - ALCvoid *ptr = NULL; - - if(!funcName) - { - VerifyDevice(&device); - alcSetError(device, ALC_INVALID_VALUE); - if(device) ALCdevice_DecRef(device); - } - else - { - size_t i = 0; - for(i = 0;i < COUNTOF(alcFunctions);i++) - { - if(strcmp(alcFunctions[i].funcName, funcName) == 0) - { - ptr = alcFunctions[i].address; - break; - } - } - } - - return ptr; -} - - -/* alcGetEnumValue - * - * Get the value for a particular ALC enumeration name - */ -ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumName) -{ - ALCenum val = 0; - - if(!enumName) - { - VerifyDevice(&device); - alcSetError(device, ALC_INVALID_VALUE); - if(device) ALCdevice_DecRef(device); - } - else - { - size_t i = 0; - for(i = 0;i < COUNTOF(alcEnumerations);i++) - { - if(strcmp(alcEnumerations[i].enumName, enumName) == 0) - { - val = alcEnumerations[i].value; - break; - } - } - } - - return val; -} - - -/* alcCreateContext - * - * Create and attach a context to the given device. - */ -ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrList) -{ - ALCcontext *ALContext; - ALfloat valf; - ALCenum err; - - /* Explicitly hold the list lock while taking the BackendLock in case the - * device is asynchronously destropyed, to ensure this new context is - * properly cleaned up after being made. - */ - LockLists(); - if(!VerifyDevice(&device) || device->Type == Capture || - !ATOMIC_LOAD(&device->Connected, almemory_order_relaxed)) - { - UnlockLists(); - alcSetError(device, ALC_INVALID_DEVICE); - if(device) ALCdevice_DecRef(device); - return NULL; - } - almtx_lock(&device->BackendLock); - UnlockLists(); - - ATOMIC_STORE_SEQ(&device->LastError, ALC_NO_ERROR); - - if(device->Type == Playback && DefaultEffect.type != AL_EFFECT_NULL) - ALContext = al_calloc(16, sizeof(ALCcontext)+sizeof(ALlistener)+sizeof(ALeffectslot)); - else - ALContext = al_calloc(16, sizeof(ALCcontext)+sizeof(ALlistener)); - if(!ALContext) - { - almtx_unlock(&device->BackendLock); - - alcSetError(device, ALC_OUT_OF_MEMORY); - ALCdevice_DecRef(device); - return NULL; - } - - InitRef(&ALContext->ref, 1); - ALContext->Listener = (ALlistener*)ALContext->_listener_mem; - ALContext->DefaultSlot = NULL; - - ALContext->Voices = NULL; - ALContext->VoiceCount = 0; - ALContext->MaxVoices = 0; - ATOMIC_INIT(&ALContext->ActiveAuxSlots, NULL); - ALContext->Device = device; - ATOMIC_INIT(&ALContext->next, NULL); - - if((err=UpdateDeviceParams(device, attrList)) != ALC_NO_ERROR) - { - almtx_unlock(&device->BackendLock); - - al_free(ALContext); - ALContext = NULL; - - alcSetError(device, err); - if(err == ALC_INVALID_DEVICE) - { - V0(device->Backend,lock)(); - aluHandleDisconnect(device, "Device update failure"); - V0(device->Backend,unlock)(); - } - ALCdevice_DecRef(device); - return NULL; - } - AllocateVoices(ALContext, 256, device->NumAuxSends); - - if(DefaultEffect.type != AL_EFFECT_NULL && device->Type == Playback) - { - ALContext->DefaultSlot = (ALeffectslot*)(ALContext->_listener_mem + sizeof(ALlistener)); - if(InitEffectSlot(ALContext->DefaultSlot) == AL_NO_ERROR) - aluInitEffectPanning(ALContext->DefaultSlot); - else - { - ALContext->DefaultSlot = NULL; - ERR("Failed to initialize the default effect slot\n"); - } - } - - ALCdevice_IncRef(ALContext->Device); - InitContext(ALContext); - - if(ConfigValueFloat(alstr_get_cstr(device->DeviceName), NULL, "volume-adjust", &valf)) - { - if(!isfinite(valf)) - ERR("volume-adjust must be finite: %f\n", valf); - else - { - ALfloat db = clampf(valf, -24.0f, 24.0f); - if(db != valf) - WARN("volume-adjust clamped: %f, range: +/-%f\n", valf, 24.0f); - ALContext->GainBoost = powf(10.0f, db/20.0f); - TRACE("volume-adjust gain: %f\n", ALContext->GainBoost); - } - } - UpdateListenerProps(ALContext); - - { - ALCcontext *head = ATOMIC_LOAD_SEQ(&device->ContextList); - do { - ATOMIC_STORE(&ALContext->next, head, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK_SEQ(&device->ContextList, &head, - ALContext) == 0); - } - almtx_unlock(&device->BackendLock); - - if(ALContext->DefaultSlot) - { - if(InitializeEffect(ALContext, ALContext->DefaultSlot, &DefaultEffect) == AL_NO_ERROR) - UpdateEffectSlotProps(ALContext->DefaultSlot, ALContext); - else - ERR("Failed to initialize the default effect\n"); - } - - ALCdevice_DecRef(device); - - TRACE("Created context %p\n", ALContext); - return ALContext; -} - -/* alcDestroyContext - * - * Remove a context from its device - */ -ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) -{ - ALCdevice *Device; - - LockLists(); - if(!VerifyContext(&context)) - { - UnlockLists(); - alcSetError(NULL, ALC_INVALID_CONTEXT); - return; - } - - Device = context->Device; - if(Device) - { - almtx_lock(&Device->BackendLock); - if(!ReleaseContext(context, Device)) - { - V0(Device->Backend,stop)(); - Device->Flags &= ~DEVICE_RUNNING; - } - almtx_unlock(&Device->BackendLock); - } - UnlockLists(); - - ALCcontext_DecRef(context); -} - - -/* alcGetCurrentContext - * - * Returns the currently active context on the calling thread - */ -ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) -{ - ALCcontext *Context = altss_get(LocalContext); - if(!Context) Context = ATOMIC_LOAD_SEQ(&GlobalContext); - return Context; -} - -/* alcGetThreadContext - * - * Returns the currently active thread-local context - */ -ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) -{ - return altss_get(LocalContext); -} - - -/* alcMakeContextCurrent - * - * Makes the given context the active process-wide context, and removes the - * thread-local context for the calling thread. - */ -ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) -{ - /* context must be valid or NULL */ - if(context && !VerifyContext(&context)) - { - alcSetError(NULL, ALC_INVALID_CONTEXT); - return ALC_FALSE; - } - /* context's reference count is already incremented */ - context = ATOMIC_EXCHANGE_PTR_SEQ(&GlobalContext, context); - if(context) ALCcontext_DecRef(context); - - if((context=altss_get(LocalContext)) != NULL) - { - altss_set(LocalContext, NULL); - ALCcontext_DecRef(context); - } - - return ALC_TRUE; -} - -/* alcSetThreadContext - * - * Makes the given context the active context for the current thread - */ -ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) -{ - ALCcontext *old; - - /* context must be valid or NULL */ - if(context && !VerifyContext(&context)) - { - alcSetError(NULL, ALC_INVALID_CONTEXT); - return ALC_FALSE; - } - /* context's reference count is already incremented */ - old = altss_get(LocalContext); - altss_set(LocalContext, context); - if(old) ALCcontext_DecRef(old); - - return ALC_TRUE; -} - - -/* alcGetContextsDevice - * - * Returns the device that a particular context is attached to - */ -ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *Context) -{ - ALCdevice *Device; - - if(!VerifyContext(&Context)) - { - alcSetError(NULL, ALC_INVALID_CONTEXT); - return NULL; - } - Device = Context->Device; - ALCcontext_DecRef(Context); - - return Device; -} - - -/* alcOpenDevice - * - * Opens the named device. - */ -ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) -{ - ALCbackendFactory *factory; - const ALCchar *fmt; - ALCdevice *device; - ALCenum err; - - DO_INITCONFIG(); - - if(!PlaybackBackend.name) - { - alcSetError(NULL, ALC_INVALID_VALUE); - return NULL; - } - - if(deviceName && (!deviceName[0] || strcasecmp(deviceName, alcDefaultName) == 0 || strcasecmp(deviceName, "openal-soft") == 0 -#ifdef _WIN32 - /* Some old Windows apps hardcode these expecting OpenAL to use a - * specific audio API, even when they're not enumerated. Creative's - * router effectively ignores them too. - */ - || strcasecmp(deviceName, "DirectSound3D") == 0 || strcasecmp(deviceName, "DirectSound") == 0 - || strcasecmp(deviceName, "MMSYSTEM") == 0 -#endif - )) - deviceName = NULL; - - device = al_calloc(16, sizeof(ALCdevice)); - if(!device) - { - alcSetError(NULL, ALC_OUT_OF_MEMORY); - return NULL; - } - - //Validate device - InitDevice(device, Playback); - - //Set output format - device->FmtChans = DevFmtChannelsDefault; - device->FmtType = DevFmtTypeDefault; - device->Frequency = DEFAULT_OUTPUT_RATE; - device->IsHeadphones = AL_FALSE; - device->AmbiLayout = AmbiLayout_Default; - device->AmbiScale = AmbiNorm_Default; - device->LimiterState = ALC_TRUE; - device->NumUpdates = 3; - device->UpdateSize = 1024; - - device->SourcesMax = 256; - device->AuxiliaryEffectSlotMax = 64; - device->NumAuxSends = DEFAULT_SENDS; - - if(ConfigValueStr(deviceName, NULL, "channels", &fmt)) - { - static const struct { - const char name[16]; - enum DevFmtChannels chans; - ALsizei order; - } chanlist[] = { - { "mono", DevFmtMono, 0 }, - { "stereo", DevFmtStereo, 0 }, - { "quad", DevFmtQuad, 0 }, - { "surround51", DevFmtX51, 0 }, - { "surround61", DevFmtX61, 0 }, - { "surround71", DevFmtX71, 0 }, - { "surround51rear", DevFmtX51Rear, 0 }, - { "ambi1", DevFmtAmbi3D, 1 }, - { "ambi2", DevFmtAmbi3D, 2 }, - { "ambi3", DevFmtAmbi3D, 3 }, - }; - size_t i; - - for(i = 0;i < COUNTOF(chanlist);i++) - { - if(strcasecmp(chanlist[i].name, fmt) == 0) - { - device->FmtChans = chanlist[i].chans; - device->AmbiOrder = chanlist[i].order; - device->Flags |= DEVICE_CHANNELS_REQUEST; - break; - } - } - if(i == COUNTOF(chanlist)) - ERR("Unsupported channels: %s\n", fmt); - } - if(ConfigValueStr(deviceName, NULL, "sample-type", &fmt)) - { - static const struct { - const char name[16]; - enum DevFmtType type; - } typelist[] = { - { "int8", DevFmtByte }, - { "uint8", DevFmtUByte }, - { "int16", DevFmtShort }, - { "uint16", DevFmtUShort }, - { "int32", DevFmtInt }, - { "uint32", DevFmtUInt }, - { "float32", DevFmtFloat }, - }; - size_t i; - - for(i = 0;i < COUNTOF(typelist);i++) - { - if(strcasecmp(typelist[i].name, fmt) == 0) - { - device->FmtType = typelist[i].type; - device->Flags |= DEVICE_SAMPLE_TYPE_REQUEST; - break; - } - } - if(i == COUNTOF(typelist)) - ERR("Unsupported sample-type: %s\n", fmt); - } - - if(ConfigValueUInt(deviceName, NULL, "frequency", &device->Frequency)) - { - device->Flags |= DEVICE_FREQUENCY_REQUEST; - if(device->Frequency < MIN_OUTPUT_RATE) - ERR("%uhz request clamped to %uhz minimum\n", device->Frequency, MIN_OUTPUT_RATE); - device->Frequency = maxu(device->Frequency, MIN_OUTPUT_RATE); - } - - ConfigValueUInt(deviceName, NULL, "periods", &device->NumUpdates); - device->NumUpdates = clampu(device->NumUpdates, 2, 16); - - ConfigValueUInt(deviceName, NULL, "period_size", &device->UpdateSize); - device->UpdateSize = clampu(device->UpdateSize, 64, 8192); - if((CPUCapFlags&(CPU_CAP_SSE|CPU_CAP_NEON)) != 0) - device->UpdateSize = (device->UpdateSize+3)&~3; - - ConfigValueUInt(deviceName, NULL, "sources", &device->SourcesMax); - if(device->SourcesMax == 0) device->SourcesMax = 256; - - ConfigValueUInt(deviceName, NULL, "slots", &device->AuxiliaryEffectSlotMax); - if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 64; - else device->AuxiliaryEffectSlotMax = minu(device->AuxiliaryEffectSlotMax, INT_MAX); - - if(ConfigValueInt(deviceName, NULL, "sends", &device->NumAuxSends)) - device->NumAuxSends = clampi( - DEFAULT_SENDS, 0, clampi(device->NumAuxSends, 0, MAX_SENDS) - ); - - device->NumStereoSources = 1; - device->NumMonoSources = device->SourcesMax - device->NumStereoSources; - - factory = PlaybackBackend.getFactory(); - device->Backend = V(factory,createBackend)(device, ALCbackend_Playback); - if(!device->Backend) - { - FreeDevice(device); - alcSetError(NULL, ALC_OUT_OF_MEMORY); - return NULL; - } - - // Find a playback device to open - if((err=V(device->Backend,open)(deviceName)) != ALC_NO_ERROR) - { - FreeDevice(device); - alcSetError(NULL, err); - return NULL; - } - - if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "ambi-format", &fmt)) - { - if(strcasecmp(fmt, "fuma") == 0) - { - device->AmbiLayout = AmbiLayout_FuMa; - device->AmbiScale = AmbiNorm_FuMa; - } - else if(strcasecmp(fmt, "acn+sn3d") == 0) - { - device->AmbiLayout = AmbiLayout_ACN; - device->AmbiScale = AmbiNorm_SN3D; - } - else if(strcasecmp(fmt, "acn+n3d") == 0) - { - device->AmbiLayout = AmbiLayout_ACN; - device->AmbiScale = AmbiNorm_N3D; - } - else - ERR("Unsupported ambi-format: %s\n", fmt); - } - - { - ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); - do { - ATOMIC_STORE(&device->next, head, almemory_order_relaxed); - } while(!ATOMIC_COMPARE_EXCHANGE_PTR_WEAK_SEQ(&DeviceList, &head, device)); - } - - TRACE("Created device %p, \"%s\"\n", device, alstr_get_cstr(device->DeviceName)); - return device; -} - -/* alcCloseDevice - * - * Closes the given device. - */ -ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) -{ - ALCdevice *iter, *origdev, *nextdev; - ALCcontext *ctx; - - LockLists(); - iter = ATOMIC_LOAD_SEQ(&DeviceList); - do { - if(iter == device) - break; - iter = ATOMIC_LOAD(&iter->next, almemory_order_relaxed); - } while(iter != NULL); - if(!iter || iter->Type == Capture) - { - alcSetError(iter, ALC_INVALID_DEVICE); - UnlockLists(); - return ALC_FALSE; - } - almtx_lock(&device->BackendLock); - - origdev = device; - nextdev = ATOMIC_LOAD(&device->next, almemory_order_relaxed); - if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&DeviceList, &origdev, nextdev)) - { - ALCdevice *list; - do { - list = origdev; - origdev = device; - } while(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&list->next, &origdev, nextdev)); - } - UnlockLists(); - - ctx = ATOMIC_LOAD_SEQ(&device->ContextList); - while(ctx != NULL) - { - ALCcontext *next = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed); - WARN("Releasing context %p\n", ctx); - ReleaseContext(ctx, device); - ctx = next; - } - if((device->Flags&DEVICE_RUNNING)) - V0(device->Backend,stop)(); - device->Flags &= ~DEVICE_RUNNING; - almtx_unlock(&device->BackendLock); - - ALCdevice_DecRef(device); - - return ALC_TRUE; -} - - -/************************************************ - * ALC capture functions - ************************************************/ -ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei samples) -{ - ALCbackendFactory *factory; - ALCdevice *device = NULL; - ALCenum err; - - DO_INITCONFIG(); - - if(!CaptureBackend.name) - { - alcSetError(NULL, ALC_INVALID_VALUE); - return NULL; - } - - if(samples <= 0) - { - alcSetError(NULL, ALC_INVALID_VALUE); - return NULL; - } - - if(deviceName && (!deviceName[0] || strcasecmp(deviceName, alcDefaultName) == 0 || strcasecmp(deviceName, "openal-soft") == 0)) - deviceName = NULL; - - device = al_calloc(16, sizeof(ALCdevice)); - if(!device) - { - alcSetError(NULL, ALC_OUT_OF_MEMORY); - return NULL; - } - - //Validate device - InitDevice(device, Capture); - - device->Frequency = frequency; - device->Flags |= DEVICE_FREQUENCY_REQUEST; - - if(DecomposeDevFormat(format, &device->FmtChans, &device->FmtType) == AL_FALSE) - { - FreeDevice(device); - alcSetError(NULL, ALC_INVALID_ENUM); - return NULL; - } - device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_SAMPLE_TYPE_REQUEST; - device->IsHeadphones = AL_FALSE; - device->AmbiOrder = 0; - device->AmbiLayout = AmbiLayout_Default; - device->AmbiScale = AmbiNorm_Default; - - device->UpdateSize = samples; - device->NumUpdates = 1; - - factory = CaptureBackend.getFactory(); - device->Backend = V(factory,createBackend)(device, ALCbackend_Capture); - if(!device->Backend) - { - FreeDevice(device); - alcSetError(NULL, ALC_OUT_OF_MEMORY); - return NULL; - } - - TRACE("Capture format: %s, %s, %uhz, %u update size x%d\n", - DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), - device->Frequency, device->UpdateSize, device->NumUpdates - ); - if((err=V(device->Backend,open)(deviceName)) != ALC_NO_ERROR) - { - FreeDevice(device); - alcSetError(NULL, err); - return NULL; - } - - { - ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); - do { - ATOMIC_STORE(&device->next, head, almemory_order_relaxed); - } while(!ATOMIC_COMPARE_EXCHANGE_PTR_WEAK_SEQ(&DeviceList, &head, device)); - } - - TRACE("Created device %p, \"%s\"\n", device, alstr_get_cstr(device->DeviceName)); - return device; -} - -ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) -{ - ALCdevice *iter, *origdev, *nextdev; - - LockLists(); - iter = ATOMIC_LOAD_SEQ(&DeviceList); - do { - if(iter == device) - break; - iter = ATOMIC_LOAD(&iter->next, almemory_order_relaxed); - } while(iter != NULL); - if(!iter || iter->Type != Capture) - { - alcSetError(iter, ALC_INVALID_DEVICE); - UnlockLists(); - return ALC_FALSE; - } - - origdev = device; - nextdev = ATOMIC_LOAD(&device->next, almemory_order_relaxed); - if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&DeviceList, &origdev, nextdev)) - { - ALCdevice *list; - do { - list = origdev; - origdev = device; - } while(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&list->next, &origdev, nextdev)); - } - UnlockLists(); - - almtx_lock(&device->BackendLock); - if((device->Flags&DEVICE_RUNNING)) - V0(device->Backend,stop)(); - device->Flags &= ~DEVICE_RUNNING; - almtx_unlock(&device->BackendLock); - - ALCdevice_DecRef(device); - - return ALC_TRUE; -} - -ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) -{ - if(!VerifyDevice(&device) || device->Type != Capture) - alcSetError(device, ALC_INVALID_DEVICE); - else - { - almtx_lock(&device->BackendLock); - if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) - alcSetError(device, ALC_INVALID_DEVICE); - else if(!(device->Flags&DEVICE_RUNNING)) - { - if(V0(device->Backend,start)()) - device->Flags |= DEVICE_RUNNING; - else - { - aluHandleDisconnect(device, "Device start failure"); - alcSetError(device, ALC_INVALID_DEVICE); - } - } - almtx_unlock(&device->BackendLock); - } - - if(device) ALCdevice_DecRef(device); -} - -ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) -{ - if(!VerifyDevice(&device) || device->Type != Capture) - alcSetError(device, ALC_INVALID_DEVICE); - else - { - almtx_lock(&device->BackendLock); - if((device->Flags&DEVICE_RUNNING)) - V0(device->Backend,stop)(); - device->Flags &= ~DEVICE_RUNNING; - almtx_unlock(&device->BackendLock); - } - - if(device) ALCdevice_DecRef(device); -} - -ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) -{ - if(!VerifyDevice(&device) || device->Type != Capture) - alcSetError(device, ALC_INVALID_DEVICE); - else - { - ALCenum err = ALC_INVALID_VALUE; - - almtx_lock(&device->BackendLock); - if(samples >= 0 && V0(device->Backend,availableSamples)() >= (ALCuint)samples) - err = V(device->Backend,captureSamples)(buffer, samples); - almtx_unlock(&device->BackendLock); - - if(err != ALC_NO_ERROR) - alcSetError(device, err); - } - if(device) ALCdevice_DecRef(device); -} - - -/************************************************ - * ALC loopback functions - ************************************************/ - -/* alcLoopbackOpenDeviceSOFT - * - * Open a loopback device, for manual rendering. - */ -ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName) -{ - ALCbackendFactory *factory; - ALCdevice *device; - - DO_INITCONFIG(); - - /* Make sure the device name, if specified, is us. */ - if(deviceName && strcmp(deviceName, alcDefaultName) != 0) - { - alcSetError(NULL, ALC_INVALID_VALUE); - return NULL; - } - - device = al_calloc(16, sizeof(ALCdevice)); - if(!device) - { - alcSetError(NULL, ALC_OUT_OF_MEMORY); - return NULL; - } - - //Validate device - InitDevice(device, Loopback); - - device->SourcesMax = 256; - device->AuxiliaryEffectSlotMax = 64; - device->NumAuxSends = DEFAULT_SENDS; - - //Set output format - device->NumUpdates = 0; - device->UpdateSize = 0; - - device->Frequency = DEFAULT_OUTPUT_RATE; - device->FmtChans = DevFmtChannelsDefault; - device->FmtType = DevFmtTypeDefault; - device->IsHeadphones = AL_FALSE; - device->AmbiLayout = AmbiLayout_Default; - device->AmbiScale = AmbiNorm_Default; - - ConfigValueUInt(NULL, NULL, "sources", &device->SourcesMax); - if(device->SourcesMax == 0) device->SourcesMax = 256; - - ConfigValueUInt(NULL, NULL, "slots", &device->AuxiliaryEffectSlotMax); - if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 64; - else device->AuxiliaryEffectSlotMax = minu(device->AuxiliaryEffectSlotMax, INT_MAX); - - if(ConfigValueInt(NULL, NULL, "sends", &device->NumAuxSends)) - device->NumAuxSends = clampi( - DEFAULT_SENDS, 0, clampi(device->NumAuxSends, 0, MAX_SENDS) - ); - - device->NumStereoSources = 1; - device->NumMonoSources = device->SourcesMax - device->NumStereoSources; - - factory = ALCloopbackFactory_getFactory(); - device->Backend = V(factory,createBackend)(device, ALCbackend_Loopback); - if(!device->Backend) - { - al_free(device); - alcSetError(NULL, ALC_OUT_OF_MEMORY); - return NULL; - } - - // Open the "backend" - V(device->Backend,open)("Loopback"); - - { - ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); - do { - ATOMIC_STORE(&device->next, head, almemory_order_relaxed); - } while(!ATOMIC_COMPARE_EXCHANGE_PTR_WEAK_SEQ(&DeviceList, &head, device)); - } - - TRACE("Created device %p\n", device); - return device; -} - -/* alcIsRenderFormatSupportedSOFT - * - * Determines if the loopback device supports the given format for rendering. - */ -ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type) -{ - ALCboolean ret = ALC_FALSE; - - if(!VerifyDevice(&device) || device->Type != Loopback) - alcSetError(device, ALC_INVALID_DEVICE); - else if(freq <= 0) - alcSetError(device, ALC_INVALID_VALUE); - else - { - if(IsValidALCType(type) && IsValidALCChannels(channels) && freq >= MIN_OUTPUT_RATE) - ret = ALC_TRUE; - } - if(device) ALCdevice_DecRef(device); - - return ret; -} - -/* alcRenderSamplesSOFT - * - * Renders some samples into a buffer, using the format last set by the - * attributes given to alcCreateContext. - */ -FORCE_ALIGN ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) -{ - if(!VerifyDevice(&device) || device->Type != Loopback) - alcSetError(device, ALC_INVALID_DEVICE); - else if(samples < 0 || (samples > 0 && buffer == NULL)) - alcSetError(device, ALC_INVALID_VALUE); - else - { - V0(device->Backend,lock)(); - aluMixData(device, buffer, samples); - V0(device->Backend,unlock)(); - } - if(device) ALCdevice_DecRef(device); -} - - -/************************************************ - * ALC DSP pause/resume functions - ************************************************/ - -/* alcDevicePauseSOFT - * - * Pause the DSP to stop audio processing. - */ -ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device) -{ - if(!VerifyDevice(&device) || device->Type != Playback) - alcSetError(device, ALC_INVALID_DEVICE); - else - { - almtx_lock(&device->BackendLock); - if((device->Flags&DEVICE_RUNNING)) - V0(device->Backend,stop)(); - device->Flags &= ~DEVICE_RUNNING; - device->Flags |= DEVICE_PAUSED; - almtx_unlock(&device->BackendLock); - } - if(device) ALCdevice_DecRef(device); -} - -/* alcDeviceResumeSOFT - * - * Resume the DSP to restart audio processing. - */ -ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) -{ - if(!VerifyDevice(&device) || device->Type != Playback) - alcSetError(device, ALC_INVALID_DEVICE); - else - { - almtx_lock(&device->BackendLock); - if((device->Flags&DEVICE_PAUSED)) - { - device->Flags &= ~DEVICE_PAUSED; - if(ATOMIC_LOAD_SEQ(&device->ContextList) != NULL) - { - if(V0(device->Backend,start)() != ALC_FALSE) - device->Flags |= DEVICE_RUNNING; - else - { - V0(device->Backend,lock)(); - aluHandleDisconnect(device, "Device start failure"); - V0(device->Backend,unlock)(); - alcSetError(device, ALC_INVALID_DEVICE); - } - } - } - almtx_unlock(&device->BackendLock); - } - if(device) ALCdevice_DecRef(device); -} - - -/************************************************ - * ALC HRTF functions - ************************************************/ - -/* alcGetStringiSOFT - * - * Gets a string parameter at the given index. - */ -ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index) -{ - const ALCchar *str = NULL; - - if(!VerifyDevice(&device) || device->Type == Capture) - alcSetError(device, ALC_INVALID_DEVICE); - else switch(paramName) - { - case ALC_HRTF_SPECIFIER_SOFT: - if(index >= 0 && (size_t)index < VECTOR_SIZE(device->HrtfList)) - str = VECTOR_ELEM(device->HrtfList, index).name; - else - alcSetError(device, ALC_INVALID_VALUE); - break; - - default: - alcSetError(device, ALC_INVALID_ENUM); - break; - } - if(device) ALCdevice_DecRef(device); - - return str; -} - -/* alcResetDeviceSOFT - * - * Resets the given device output, using the specified attribute list. - */ -ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs) -{ - ALCenum err; - - LockLists(); - if(!VerifyDevice(&device) || device->Type == Capture || - !ATOMIC_LOAD(&device->Connected, almemory_order_relaxed)) - { - UnlockLists(); - alcSetError(device, ALC_INVALID_DEVICE); - if(device) ALCdevice_DecRef(device); - return ALC_FALSE; - } - almtx_lock(&device->BackendLock); - UnlockLists(); - - err = UpdateDeviceParams(device, attribs); - almtx_unlock(&device->BackendLock); - - if(err != ALC_NO_ERROR) - { - alcSetError(device, err); - if(err == ALC_INVALID_DEVICE) - { - V0(device->Backend,lock)(); - aluHandleDisconnect(device, "Device start failure"); - V0(device->Backend,unlock)(); - } - ALCdevice_DecRef(device); - return ALC_FALSE; - } - ALCdevice_DecRef(device); - - return ALC_TRUE; -} diff --git a/Alc/alc.cpp b/Alc/alc.cpp new file mode 100644 index 00000000..b46f1986 --- /dev/null +++ b/Alc/alc.cpp @@ -0,0 +1,4696 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "version.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "alMain.h" +#include "alSource.h" +#include "alListener.h" +#include "alSource.h" +#include "alBuffer.h" +#include "alFilter.h" +#include "alEffect.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "mastering.h" +#include "bformatdec.h" +#include "alu.h" +#include "alconfig.h" +#include "ringbuffer.h" + +#include "fpu_modes.h" +#include "cpu_caps.h" +#include "compat.h" +#include "threads.h" +#include "alstring.h" +#include "almalloc.h" + +#include "backends/base.h" + + +/************************************************ + * Backends + ************************************************/ +struct BackendInfo { + const char *name; + ALCbackendFactory* (*getFactory)(void); +}; + +static struct BackendInfo BackendList[] = { +#ifdef HAVE_JACK + { "jack", ALCjackBackendFactory_getFactory }, +#endif +#ifdef HAVE_PULSEAUDIO + { "pulse", ALCpulseBackendFactory_getFactory }, +#endif +#ifdef HAVE_ALSA + { "alsa", ALCalsaBackendFactory_getFactory }, +#endif +#ifdef HAVE_COREAUDIO + { "core", ALCcoreAudioBackendFactory_getFactory }, +#endif +#ifdef HAVE_SOLARIS + { "solaris", ALCsolarisBackendFactory_getFactory }, +#endif +#ifdef HAVE_SNDIO + { "sndio", SndioBackendFactory_getFactory }, +#endif +#ifdef HAVE_OSS + { "oss", ALCossBackendFactory_getFactory }, +#endif +#ifdef HAVE_QSA + { "qsa", ALCqsaBackendFactory_getFactory }, +#endif +#ifdef HAVE_WASAPI + { "wasapi", ALCwasapiBackendFactory_getFactory }, +#endif +#ifdef HAVE_DSOUND + { "dsound", ALCdsoundBackendFactory_getFactory }, +#endif +#ifdef HAVE_WINMM + { "winmm", ALCwinmmBackendFactory_getFactory }, +#endif +#ifdef HAVE_PORTAUDIO + { "port", ALCportBackendFactory_getFactory }, +#endif +#ifdef HAVE_OPENSL + { "opensl", ALCopenslBackendFactory_getFactory }, +#endif +#ifdef HAVE_SDL2 + { "sdl2", ALCsdl2BackendFactory_getFactory }, +#endif + + { "null", ALCnullBackendFactory_getFactory }, +#ifdef HAVE_WAVE + { "wave", ALCwaveBackendFactory_getFactory }, +#endif +}; +static ALsizei BackendListSize = COUNTOF(BackendList); +#undef EmptyFuncs + +static struct BackendInfo PlaybackBackend; +static struct BackendInfo CaptureBackend; + + +/************************************************ + * Functions, enums, and errors + ************************************************/ +#define DECL(x) { #x, (ALCvoid*)(x) } +static const struct { + const ALCchar *funcName; + ALCvoid *address; +} alcFunctions[] = { + DECL(alcCreateContext), + DECL(alcMakeContextCurrent), + DECL(alcProcessContext), + DECL(alcSuspendContext), + DECL(alcDestroyContext), + DECL(alcGetCurrentContext), + DECL(alcGetContextsDevice), + DECL(alcOpenDevice), + DECL(alcCloseDevice), + DECL(alcGetError), + DECL(alcIsExtensionPresent), + DECL(alcGetProcAddress), + DECL(alcGetEnumValue), + DECL(alcGetString), + DECL(alcGetIntegerv), + DECL(alcCaptureOpenDevice), + DECL(alcCaptureCloseDevice), + DECL(alcCaptureStart), + DECL(alcCaptureStop), + DECL(alcCaptureSamples), + + DECL(alcSetThreadContext), + DECL(alcGetThreadContext), + + DECL(alcLoopbackOpenDeviceSOFT), + DECL(alcIsRenderFormatSupportedSOFT), + DECL(alcRenderSamplesSOFT), + + DECL(alcDevicePauseSOFT), + DECL(alcDeviceResumeSOFT), + + DECL(alcGetStringiSOFT), + DECL(alcResetDeviceSOFT), + + DECL(alcGetInteger64vSOFT), + + DECL(alEnable), + DECL(alDisable), + DECL(alIsEnabled), + DECL(alGetString), + DECL(alGetBooleanv), + DECL(alGetIntegerv), + DECL(alGetFloatv), + DECL(alGetDoublev), + DECL(alGetBoolean), + DECL(alGetInteger), + DECL(alGetFloat), + DECL(alGetDouble), + DECL(alGetError), + DECL(alIsExtensionPresent), + DECL(alGetProcAddress), + DECL(alGetEnumValue), + DECL(alListenerf), + DECL(alListener3f), + DECL(alListenerfv), + DECL(alListeneri), + DECL(alListener3i), + DECL(alListeneriv), + DECL(alGetListenerf), + DECL(alGetListener3f), + DECL(alGetListenerfv), + DECL(alGetListeneri), + DECL(alGetListener3i), + DECL(alGetListeneriv), + DECL(alGenSources), + DECL(alDeleteSources), + DECL(alIsSource), + DECL(alSourcef), + DECL(alSource3f), + DECL(alSourcefv), + DECL(alSourcei), + DECL(alSource3i), + DECL(alSourceiv), + DECL(alGetSourcef), + DECL(alGetSource3f), + DECL(alGetSourcefv), + DECL(alGetSourcei), + DECL(alGetSource3i), + DECL(alGetSourceiv), + DECL(alSourcePlayv), + DECL(alSourceStopv), + DECL(alSourceRewindv), + DECL(alSourcePausev), + DECL(alSourcePlay), + DECL(alSourceStop), + DECL(alSourceRewind), + DECL(alSourcePause), + DECL(alSourceQueueBuffers), + DECL(alSourceUnqueueBuffers), + DECL(alGenBuffers), + DECL(alDeleteBuffers), + DECL(alIsBuffer), + DECL(alBufferData), + DECL(alBufferf), + DECL(alBuffer3f), + DECL(alBufferfv), + DECL(alBufferi), + DECL(alBuffer3i), + DECL(alBufferiv), + DECL(alGetBufferf), + DECL(alGetBuffer3f), + DECL(alGetBufferfv), + DECL(alGetBufferi), + DECL(alGetBuffer3i), + DECL(alGetBufferiv), + DECL(alDopplerFactor), + DECL(alDopplerVelocity), + DECL(alSpeedOfSound), + DECL(alDistanceModel), + + DECL(alGenFilters), + DECL(alDeleteFilters), + DECL(alIsFilter), + DECL(alFilteri), + DECL(alFilteriv), + DECL(alFilterf), + DECL(alFilterfv), + DECL(alGetFilteri), + DECL(alGetFilteriv), + DECL(alGetFilterf), + DECL(alGetFilterfv), + DECL(alGenEffects), + DECL(alDeleteEffects), + DECL(alIsEffect), + DECL(alEffecti), + DECL(alEffectiv), + DECL(alEffectf), + DECL(alEffectfv), + DECL(alGetEffecti), + DECL(alGetEffectiv), + DECL(alGetEffectf), + DECL(alGetEffectfv), + DECL(alGenAuxiliaryEffectSlots), + DECL(alDeleteAuxiliaryEffectSlots), + DECL(alIsAuxiliaryEffectSlot), + DECL(alAuxiliaryEffectSloti), + DECL(alAuxiliaryEffectSlotiv), + DECL(alAuxiliaryEffectSlotf), + DECL(alAuxiliaryEffectSlotfv), + DECL(alGetAuxiliaryEffectSloti), + DECL(alGetAuxiliaryEffectSlotiv), + DECL(alGetAuxiliaryEffectSlotf), + DECL(alGetAuxiliaryEffectSlotfv), + + DECL(alDeferUpdatesSOFT), + DECL(alProcessUpdatesSOFT), + + DECL(alSourcedSOFT), + DECL(alSource3dSOFT), + DECL(alSourcedvSOFT), + DECL(alGetSourcedSOFT), + DECL(alGetSource3dSOFT), + DECL(alGetSourcedvSOFT), + DECL(alSourcei64SOFT), + DECL(alSource3i64SOFT), + DECL(alSourcei64vSOFT), + DECL(alGetSourcei64SOFT), + DECL(alGetSource3i64SOFT), + DECL(alGetSourcei64vSOFT), + + DECL(alGetStringiSOFT), + + DECL(alBufferStorageSOFT), + DECL(alMapBufferSOFT), + DECL(alUnmapBufferSOFT), + DECL(alFlushMappedBufferSOFT), + + DECL(alEventControlSOFT), + DECL(alEventCallbackSOFT), + DECL(alGetPointerSOFT), + DECL(alGetPointervSOFT), +}; +#undef DECL + +#define DECL(x) { #x, (x) } +static const struct { + const ALCchar *enumName; + ALCenum value; +} alcEnumerations[] = { + DECL(ALC_INVALID), + DECL(ALC_FALSE), + DECL(ALC_TRUE), + + DECL(ALC_MAJOR_VERSION), + DECL(ALC_MINOR_VERSION), + DECL(ALC_ATTRIBUTES_SIZE), + DECL(ALC_ALL_ATTRIBUTES), + DECL(ALC_DEFAULT_DEVICE_SPECIFIER), + DECL(ALC_DEVICE_SPECIFIER), + DECL(ALC_ALL_DEVICES_SPECIFIER), + DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER), + DECL(ALC_EXTENSIONS), + DECL(ALC_FREQUENCY), + DECL(ALC_REFRESH), + DECL(ALC_SYNC), + DECL(ALC_MONO_SOURCES), + DECL(ALC_STEREO_SOURCES), + DECL(ALC_CAPTURE_DEVICE_SPECIFIER), + DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER), + DECL(ALC_CAPTURE_SAMPLES), + DECL(ALC_CONNECTED), + + DECL(ALC_EFX_MAJOR_VERSION), + DECL(ALC_EFX_MINOR_VERSION), + DECL(ALC_MAX_AUXILIARY_SENDS), + + DECL(ALC_FORMAT_CHANNELS_SOFT), + DECL(ALC_FORMAT_TYPE_SOFT), + + DECL(ALC_MONO_SOFT), + DECL(ALC_STEREO_SOFT), + DECL(ALC_QUAD_SOFT), + DECL(ALC_5POINT1_SOFT), + DECL(ALC_6POINT1_SOFT), + DECL(ALC_7POINT1_SOFT), + DECL(ALC_BFORMAT3D_SOFT), + + DECL(ALC_BYTE_SOFT), + DECL(ALC_UNSIGNED_BYTE_SOFT), + DECL(ALC_SHORT_SOFT), + DECL(ALC_UNSIGNED_SHORT_SOFT), + DECL(ALC_INT_SOFT), + DECL(ALC_UNSIGNED_INT_SOFT), + DECL(ALC_FLOAT_SOFT), + + DECL(ALC_HRTF_SOFT), + DECL(ALC_DONT_CARE_SOFT), + DECL(ALC_HRTF_STATUS_SOFT), + DECL(ALC_HRTF_DISABLED_SOFT), + DECL(ALC_HRTF_ENABLED_SOFT), + DECL(ALC_HRTF_DENIED_SOFT), + DECL(ALC_HRTF_REQUIRED_SOFT), + DECL(ALC_HRTF_HEADPHONES_DETECTED_SOFT), + DECL(ALC_HRTF_UNSUPPORTED_FORMAT_SOFT), + DECL(ALC_NUM_HRTF_SPECIFIERS_SOFT), + DECL(ALC_HRTF_SPECIFIER_SOFT), + DECL(ALC_HRTF_ID_SOFT), + + DECL(ALC_AMBISONIC_LAYOUT_SOFT), + DECL(ALC_AMBISONIC_SCALING_SOFT), + DECL(ALC_AMBISONIC_ORDER_SOFT), + DECL(ALC_ACN_SOFT), + DECL(ALC_FUMA_SOFT), + DECL(ALC_N3D_SOFT), + DECL(ALC_SN3D_SOFT), + + DECL(ALC_OUTPUT_LIMITER_SOFT), + + DECL(ALC_NO_ERROR), + DECL(ALC_INVALID_DEVICE), + DECL(ALC_INVALID_CONTEXT), + DECL(ALC_INVALID_ENUM), + DECL(ALC_INVALID_VALUE), + DECL(ALC_OUT_OF_MEMORY), + + + DECL(AL_INVALID), + DECL(AL_NONE), + DECL(AL_FALSE), + DECL(AL_TRUE), + + DECL(AL_SOURCE_RELATIVE), + DECL(AL_CONE_INNER_ANGLE), + DECL(AL_CONE_OUTER_ANGLE), + DECL(AL_PITCH), + DECL(AL_POSITION), + DECL(AL_DIRECTION), + DECL(AL_VELOCITY), + DECL(AL_LOOPING), + DECL(AL_BUFFER), + DECL(AL_GAIN), + DECL(AL_MIN_GAIN), + DECL(AL_MAX_GAIN), + DECL(AL_ORIENTATION), + DECL(AL_REFERENCE_DISTANCE), + DECL(AL_ROLLOFF_FACTOR), + DECL(AL_CONE_OUTER_GAIN), + DECL(AL_MAX_DISTANCE), + DECL(AL_SEC_OFFSET), + DECL(AL_SAMPLE_OFFSET), + DECL(AL_BYTE_OFFSET), + DECL(AL_SOURCE_TYPE), + DECL(AL_STATIC), + DECL(AL_STREAMING), + DECL(AL_UNDETERMINED), + DECL(AL_METERS_PER_UNIT), + DECL(AL_LOOP_POINTS_SOFT), + DECL(AL_DIRECT_CHANNELS_SOFT), + + DECL(AL_DIRECT_FILTER), + DECL(AL_AUXILIARY_SEND_FILTER), + DECL(AL_AIR_ABSORPTION_FACTOR), + DECL(AL_ROOM_ROLLOFF_FACTOR), + DECL(AL_CONE_OUTER_GAINHF), + DECL(AL_DIRECT_FILTER_GAINHF_AUTO), + DECL(AL_AUXILIARY_SEND_FILTER_GAIN_AUTO), + DECL(AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO), + + DECL(AL_SOURCE_STATE), + DECL(AL_INITIAL), + DECL(AL_PLAYING), + DECL(AL_PAUSED), + DECL(AL_STOPPED), + + DECL(AL_BUFFERS_QUEUED), + DECL(AL_BUFFERS_PROCESSED), + + DECL(AL_FORMAT_MONO8), + DECL(AL_FORMAT_MONO16), + DECL(AL_FORMAT_MONO_FLOAT32), + DECL(AL_FORMAT_MONO_DOUBLE_EXT), + DECL(AL_FORMAT_STEREO8), + DECL(AL_FORMAT_STEREO16), + DECL(AL_FORMAT_STEREO_FLOAT32), + 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), + DECL(AL_FORMAT_QUAD16), + DECL(AL_FORMAT_QUAD32), + DECL(AL_FORMAT_51CHN8), + DECL(AL_FORMAT_51CHN16), + DECL(AL_FORMAT_51CHN32), + DECL(AL_FORMAT_61CHN8), + DECL(AL_FORMAT_61CHN16), + DECL(AL_FORMAT_61CHN32), + DECL(AL_FORMAT_71CHN8), + DECL(AL_FORMAT_71CHN16), + DECL(AL_FORMAT_71CHN32), + DECL(AL_FORMAT_REAR8), + DECL(AL_FORMAT_REAR16), + DECL(AL_FORMAT_REAR32), + DECL(AL_FORMAT_MONO_MULAW), + DECL(AL_FORMAT_MONO_MULAW_EXT), + DECL(AL_FORMAT_STEREO_MULAW), + DECL(AL_FORMAT_STEREO_MULAW_EXT), + DECL(AL_FORMAT_QUAD_MULAW), + DECL(AL_FORMAT_51CHN_MULAW), + DECL(AL_FORMAT_61CHN_MULAW), + DECL(AL_FORMAT_71CHN_MULAW), + DECL(AL_FORMAT_REAR_MULAW), + DECL(AL_FORMAT_MONO_ALAW_EXT), + DECL(AL_FORMAT_STEREO_ALAW_EXT), + + DECL(AL_FORMAT_BFORMAT2D_8), + DECL(AL_FORMAT_BFORMAT2D_16), + DECL(AL_FORMAT_BFORMAT2D_FLOAT32), + DECL(AL_FORMAT_BFORMAT2D_MULAW), + DECL(AL_FORMAT_BFORMAT3D_8), + DECL(AL_FORMAT_BFORMAT3D_16), + DECL(AL_FORMAT_BFORMAT3D_FLOAT32), + DECL(AL_FORMAT_BFORMAT3D_MULAW), + + DECL(AL_FREQUENCY), + DECL(AL_BITS), + DECL(AL_CHANNELS), + DECL(AL_SIZE), + DECL(AL_UNPACK_BLOCK_ALIGNMENT_SOFT), + DECL(AL_PACK_BLOCK_ALIGNMENT_SOFT), + + DECL(AL_SOURCE_RADIUS), + + DECL(AL_STEREO_ANGLES), + + DECL(AL_UNUSED), + DECL(AL_PENDING), + DECL(AL_PROCESSED), + + DECL(AL_NO_ERROR), + DECL(AL_INVALID_NAME), + DECL(AL_INVALID_ENUM), + DECL(AL_INVALID_VALUE), + DECL(AL_INVALID_OPERATION), + DECL(AL_OUT_OF_MEMORY), + + DECL(AL_VENDOR), + DECL(AL_VERSION), + DECL(AL_RENDERER), + DECL(AL_EXTENSIONS), + + DECL(AL_DOPPLER_FACTOR), + DECL(AL_DOPPLER_VELOCITY), + DECL(AL_DISTANCE_MODEL), + DECL(AL_SPEED_OF_SOUND), + DECL(AL_SOURCE_DISTANCE_MODEL), + DECL(AL_DEFERRED_UPDATES_SOFT), + DECL(AL_GAIN_LIMIT_SOFT), + + DECL(AL_INVERSE_DISTANCE), + DECL(AL_INVERSE_DISTANCE_CLAMPED), + DECL(AL_LINEAR_DISTANCE), + DECL(AL_LINEAR_DISTANCE_CLAMPED), + DECL(AL_EXPONENT_DISTANCE), + DECL(AL_EXPONENT_DISTANCE_CLAMPED), + + DECL(AL_FILTER_TYPE), + DECL(AL_FILTER_NULL), + DECL(AL_FILTER_LOWPASS), + DECL(AL_FILTER_HIGHPASS), + DECL(AL_FILTER_BANDPASS), + + 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), + DECL(AL_EFFECT_EAXREVERB), + DECL(AL_EFFECT_CHORUS), + DECL(AL_EFFECT_DISTORTION), + DECL(AL_EFFECT_ECHO), + DECL(AL_EFFECT_FLANGER), + DECL(AL_EFFECT_PITCH_SHIFTER), + DECL(AL_EFFECT_FREQUENCY_SHIFTER), +#if 0 + DECL(AL_EFFECT_VOCAL_MORPHER), +#endif + DECL(AL_EFFECT_RING_MODULATOR), + DECL(AL_EFFECT_AUTOWAH), + DECL(AL_EFFECT_COMPRESSOR), + DECL(AL_EFFECT_EQUALIZER), + DECL(AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT), + DECL(AL_EFFECT_DEDICATED_DIALOGUE), + + DECL(AL_EFFECTSLOT_EFFECT), + DECL(AL_EFFECTSLOT_GAIN), + DECL(AL_EFFECTSLOT_AUXILIARY_SEND_AUTO), + DECL(AL_EFFECTSLOT_NULL), + + DECL(AL_EAXREVERB_DENSITY), + DECL(AL_EAXREVERB_DIFFUSION), + DECL(AL_EAXREVERB_GAIN), + DECL(AL_EAXREVERB_GAINHF), + DECL(AL_EAXREVERB_GAINLF), + DECL(AL_EAXREVERB_DECAY_TIME), + DECL(AL_EAXREVERB_DECAY_HFRATIO), + DECL(AL_EAXREVERB_DECAY_LFRATIO), + DECL(AL_EAXREVERB_REFLECTIONS_GAIN), + DECL(AL_EAXREVERB_REFLECTIONS_DELAY), + DECL(AL_EAXREVERB_REFLECTIONS_PAN), + DECL(AL_EAXREVERB_LATE_REVERB_GAIN), + DECL(AL_EAXREVERB_LATE_REVERB_DELAY), + DECL(AL_EAXREVERB_LATE_REVERB_PAN), + DECL(AL_EAXREVERB_ECHO_TIME), + DECL(AL_EAXREVERB_ECHO_DEPTH), + DECL(AL_EAXREVERB_MODULATION_TIME), + DECL(AL_EAXREVERB_MODULATION_DEPTH), + DECL(AL_EAXREVERB_AIR_ABSORPTION_GAINHF), + DECL(AL_EAXREVERB_HFREFERENCE), + DECL(AL_EAXREVERB_LFREFERENCE), + DECL(AL_EAXREVERB_ROOM_ROLLOFF_FACTOR), + DECL(AL_EAXREVERB_DECAY_HFLIMIT), + + DECL(AL_REVERB_DENSITY), + DECL(AL_REVERB_DIFFUSION), + DECL(AL_REVERB_GAIN), + DECL(AL_REVERB_GAINHF), + DECL(AL_REVERB_DECAY_TIME), + DECL(AL_REVERB_DECAY_HFRATIO), + DECL(AL_REVERB_REFLECTIONS_GAIN), + DECL(AL_REVERB_REFLECTIONS_DELAY), + DECL(AL_REVERB_LATE_REVERB_GAIN), + DECL(AL_REVERB_LATE_REVERB_DELAY), + DECL(AL_REVERB_AIR_ABSORPTION_GAINHF), + DECL(AL_REVERB_ROOM_ROLLOFF_FACTOR), + DECL(AL_REVERB_DECAY_HFLIMIT), + + DECL(AL_CHORUS_WAVEFORM), + DECL(AL_CHORUS_PHASE), + DECL(AL_CHORUS_RATE), + DECL(AL_CHORUS_DEPTH), + DECL(AL_CHORUS_FEEDBACK), + DECL(AL_CHORUS_DELAY), + + DECL(AL_DISTORTION_EDGE), + DECL(AL_DISTORTION_GAIN), + DECL(AL_DISTORTION_LOWPASS_CUTOFF), + DECL(AL_DISTORTION_EQCENTER), + DECL(AL_DISTORTION_EQBANDWIDTH), + + DECL(AL_ECHO_DELAY), + DECL(AL_ECHO_LRDELAY), + DECL(AL_ECHO_DAMPING), + DECL(AL_ECHO_FEEDBACK), + DECL(AL_ECHO_SPREAD), + + DECL(AL_FLANGER_WAVEFORM), + DECL(AL_FLANGER_PHASE), + DECL(AL_FLANGER_RATE), + DECL(AL_FLANGER_DEPTH), + DECL(AL_FLANGER_FEEDBACK), + DECL(AL_FLANGER_DELAY), + + DECL(AL_FREQUENCY_SHIFTER_FREQUENCY), + DECL(AL_FREQUENCY_SHIFTER_LEFT_DIRECTION), + DECL(AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION), + + DECL(AL_RING_MODULATOR_FREQUENCY), + DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF), + DECL(AL_RING_MODULATOR_WAVEFORM), + + DECL(AL_PITCH_SHIFTER_COARSE_TUNE), + DECL(AL_PITCH_SHIFTER_FINE_TUNE), + + DECL(AL_COMPRESSOR_ONOFF), + + DECL(AL_EQUALIZER_LOW_GAIN), + DECL(AL_EQUALIZER_LOW_CUTOFF), + DECL(AL_EQUALIZER_MID1_GAIN), + DECL(AL_EQUALIZER_MID1_CENTER), + DECL(AL_EQUALIZER_MID1_WIDTH), + DECL(AL_EQUALIZER_MID2_GAIN), + DECL(AL_EQUALIZER_MID2_CENTER), + DECL(AL_EQUALIZER_MID2_WIDTH), + DECL(AL_EQUALIZER_HIGH_GAIN), + DECL(AL_EQUALIZER_HIGH_CUTOFF), + + DECL(AL_DEDICATED_GAIN), + + DECL(AL_AUTOWAH_ATTACK_TIME), + DECL(AL_AUTOWAH_RELEASE_TIME), + DECL(AL_AUTOWAH_RESONANCE), + DECL(AL_AUTOWAH_PEAK_GAIN), + + DECL(AL_NUM_RESAMPLERS_SOFT), + DECL(AL_DEFAULT_RESAMPLER_SOFT), + DECL(AL_SOURCE_RESAMPLER_SOFT), + DECL(AL_RESAMPLER_NAME_SOFT), + + DECL(AL_SOURCE_SPATIALIZE_SOFT), + DECL(AL_AUTO_SOFT), + + DECL(AL_MAP_READ_BIT_SOFT), + DECL(AL_MAP_WRITE_BIT_SOFT), + DECL(AL_MAP_PERSISTENT_BIT_SOFT), + DECL(AL_PRESERVE_DATA_BIT_SOFT), + + DECL(AL_EVENT_CALLBACK_FUNCTION_SOFT), + DECL(AL_EVENT_CALLBACK_USER_PARAM_SOFT), + DECL(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT), + DECL(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT), + DECL(AL_EVENT_TYPE_ERROR_SOFT), + DECL(AL_EVENT_TYPE_PERFORMANCE_SOFT), + DECL(AL_EVENT_TYPE_DEPRECATED_SOFT), +}; +#undef DECL + +static const ALCchar alcNoError[] = "No Error"; +static const ALCchar alcErrInvalidDevice[] = "Invalid Device"; +static const ALCchar alcErrInvalidContext[] = "Invalid Context"; +static const ALCchar alcErrInvalidEnum[] = "Invalid Enum"; +static const ALCchar alcErrInvalidValue[] = "Invalid Value"; +static const ALCchar alcErrOutOfMemory[] = "Out of Memory"; + + +/************************************************ + * Global variables + ************************************************/ + +/* Enumerated device names */ +static const ALCchar alcDefaultName[] = "OpenAL Soft\0"; + +static al_string alcAllDevicesList; +static al_string alcCaptureDeviceList; + +/* Default is always the first in the list */ +static ALCchar *alcDefaultAllDevicesSpecifier; +static ALCchar *alcCaptureDefaultDeviceSpecifier; + +/* Default context extensions */ +static const ALchar alExtList[] = + "AL_EXT_ALAW " + "AL_EXT_BFORMAT " + "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_BFORMAT " + "AL_EXT_MULAW_MCFORMATS " + "AL_EXT_OFFSET " + "AL_EXT_source_distance_model " + "AL_EXT_SOURCE_RADIUS " + "AL_EXT_STEREO_ANGLES " + "AL_LOKI_quadriphonic " + "AL_SOFT_block_alignment " + "AL_SOFT_deferred_updates " + "AL_SOFT_direct_channels " + "AL_SOFTX_events " + "AL_SOFTX_filter_gain_ex " + "AL_SOFT_gain_clamp_ex " + "AL_SOFT_loop_points " + "AL_SOFTX_map_buffer " + "AL_SOFT_MSADPCM " + "AL_SOFT_source_latency " + "AL_SOFT_source_length " + "AL_SOFT_source_resampler " + "AL_SOFT_source_spatialize"; + +static ATOMIC(ALCenum) LastNullDeviceError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); + +/* Thread-local current context */ +static altss_t LocalContext; +/* Process-wide current context */ +static ATOMIC(ALCcontext*) GlobalContext = ATOMIC_INIT_STATIC(nullptr); + +/* Mixing thread piority level */ +ALint RTPrioLevel; + +FILE *LogFile; +#ifdef _DEBUG +enum LogLevel LogLevel = LogWarning; +#else +enum LogLevel LogLevel = LogError; +#endif + +/* Flag to trap ALC device errors */ +static ALCboolean TrapALCError = ALC_FALSE; + +/* One-time configuration init control */ +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; + +/* Flag to specify if alcSuspendContext/alcProcessContext should defer/process + * updates. + */ +static ALCboolean SuspendDefers = ALC_TRUE; + + +/************************************************ + * ALC information + ************************************************/ +static const ALCchar alcNoDeviceExtList[] = + "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE " + "ALC_EXT_thread_local_context ALC_SOFT_loopback"; +static const ALCchar alcExtensionList[] = + "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE " + "ALC_EXT_DEDICATED ALC_EXT_disconnect ALC_EXT_EFX " + "ALC_EXT_thread_local_context ALC_SOFT_device_clock ALC_SOFT_HRTF " + "ALC_SOFT_loopback ALC_SOFT_output_limiter ALC_SOFT_pause_device"; +static const ALCint alcMajorVersion = 1; +static const ALCint alcMinorVersion = 1; + +static const ALCint alcEFXMajorVersion = 1; +static const ALCint alcEFXMinorVersion = 0; + + +/************************************************ + * Device lists + ************************************************/ +static std::atomic DeviceList{nullptr}; + +static almtx_t ListLock; +static inline void LockLists(void) +{ + int ret = almtx_lock(&ListLock); + assert(ret == althrd_success); +} +static inline void UnlockLists(void) +{ + int ret = almtx_unlock(&ListLock); + assert(ret == althrd_success); +} + +/************************************************ + * Library initialization + ************************************************/ +#if defined(_WIN32) +static void alc_init(void); +static void alc_deinit(void); +static void alc_deinit_safe(void); + +#ifndef AL_LIBTYPE_STATIC +BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD reason, LPVOID lpReserved) +{ + 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); + alc_init(); + break; + + case DLL_THREAD_DETACH: + althrd_thread_detach(); + break; + + case DLL_PROCESS_DETACH: + if(!lpReserved) + alc_deinit(); + else + alc_deinit_safe(); + break; + } + return TRUE; +} +#elif defined(_MSC_VER) +#pragma section(".CRT$XCU",read) +static void alc_constructor(void); +static void alc_destructor(void); +__declspec(allocate(".CRT$XCU")) void (__cdecl* alc_constructor_)(void) = alc_constructor; + +static void alc_constructor(void) +{ + atexit(alc_destructor); + alc_init(); +} + +static void alc_destructor(void) +{ + alc_deinit(); +} +#elif defined(HAVE_GCC_DESTRUCTOR) +static void alc_init(void) __attribute__((constructor)); +static void alc_deinit(void) __attribute__((destructor)); +#else +#error "No static initialization available on this platform!" +#endif + +#elif defined(HAVE_GCC_DESTRUCTOR) + +static void alc_init(void) __attribute__((constructor)); +static void alc_deinit(void) __attribute__((destructor)); + +#else +#error "No global initialization available on this platform!" +#endif + +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, nullptr, 0) == 1)) + ConeScale *= 0.5f; + + str = getenv("__ALSOFT_REVERSE_Z"); + if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) + ZScale *= -1.0f; + + str = getenv("__ALSOFT_REVERB_IGNORES_SOUND_SPEED"); + if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) + OverrideReverbSpeedOfSound = AL_TRUE; + + ret = altss_create(&LocalContext, ReleaseThreadCtx); + assert(ret == althrd_success); + + ret = almtx_init(&ListLock, almtx_recursive); + assert(ret == althrd_success); +} + +static void alc_initconfig(void) +{ + const char *devs, *str; + int capfilter; + float valf; + int i, n; + + str = getenv("ALSOFT_LOGLEVEL"); + if(str) + { + long lvl = strtol(str, nullptr, 0); + if(lvl >= NoLog && lvl <= LogRef) + LogLevel = static_cast(lvl); + } + + str = getenv("ALSOFT_LOGFILE"); + if(str && str[0]) + { +#ifdef _WIN32 + std::wstring wname{utf8_to_wstr(str)}; + FILE *logfile = _wfopen(wname.c_str(), L"wt"); +#else + FILE *logfile = fopen(str, "wt"); +#endif + if(logfile) LogFile = logfile; + else ERR("Failed to open log file '%s'\n", str); + } + + TRACE("Initializing library v%s-%s %s\n", ALSOFT_VERSION, + ALSOFT_GIT_COMMIT_HASH, ALSOFT_GIT_BRANCH); + { + char buf[1024] = ""; + int len = 0; + + if(BackendListSize > 0) + len += snprintf(buf, sizeof(buf), "%s", BackendList[0].name); + for(i = 1;i < BackendListSize;i++) + len += snprintf(buf+len, sizeof(buf)-len, ", %s", BackendList[i].name); + TRACE("Supported backends: %s\n", buf); + } + ReadALConfig(); + + str = getenv("__ALSOFT_SUSPEND_CONTEXT"); + if(str && *str) + { + if(strcasecmp(str, "ignore") == 0) + { + SuspendDefers = ALC_FALSE; + TRACE("Selected context suspend behavior, \"ignore\"\n"); + } + else + ERR("Unhandled context suspend behavior setting: \"%s\"\n", str); + } + + capfilter = 0; +#if defined(HAVE_SSE4_1) + capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1; +#elif defined(HAVE_SSE3) + capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3; +#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; +#endif + if(ConfigValueStr(nullptr, nullptr, "disable-cpu-exts", &str)) + { + if(strcasecmp(str, "all") == 0) + capfilter = 0; + else + { + size_t len; + const char *next = str; + + do { + str = next; + while(isspace(str[0])) + str++; + next = strchr(str, ','); + + if(!str[0] || str[0] == ',') + continue; + + len = (next ? ((size_t)(next-str)) : strlen(str)); + while(len > 0 && isspace(str[len-1])) + len--; + if(len == 3 && strncasecmp(str, "sse", len) == 0) + capfilter &= ~CPU_CAP_SSE; + else if(len == 4 && strncasecmp(str, "sse2", len) == 0) + capfilter &= ~CPU_CAP_SSE2; + else if(len == 4 && strncasecmp(str, "sse3", len) == 0) + capfilter &= ~CPU_CAP_SSE3; + 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 + WARN("Invalid CPU extension \"%s\"\n", str); + } while(next++); + } + } + FillCPUCaps(capfilter); + +#ifdef _WIN32 + RTPrioLevel = 1; +#else + RTPrioLevel = 0; +#endif + ConfigValueInt(nullptr, nullptr, "rt-prio", &RTPrioLevel); + + aluInit(); + aluInitMixer(); + + str = getenv("ALSOFT_TRAP_ERROR"); + if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) + { + TrapALError = AL_TRUE; + TrapALCError = AL_TRUE; + } + else + { + str = getenv("ALSOFT_TRAP_AL_ERROR"); + if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) + TrapALError = AL_TRUE; + TrapALError = GetConfigValueBool(nullptr, nullptr, "trap-al-error", TrapALError); + + str = getenv("ALSOFT_TRAP_ALC_ERROR"); + if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) + TrapALCError = ALC_TRUE; + TrapALCError = GetConfigValueBool(nullptr, nullptr, "trap-alc-error", TrapALCError); + } + + if(ConfigValueFloat(nullptr, "reverb", "boost", &valf)) + ReverbBoost *= powf(10.0f, valf / 20.0f); + + if(((devs=getenv("ALSOFT_DRIVERS")) && devs[0]) || + ConfigValueStr(nullptr, nullptr, "drivers", &devs)) + { + int n; + size_t len; + const char *next = devs; + int endlist, delitem; + + i = 0; + do { + devs = next; + while(isspace(devs[0])) + devs++; + next = strchr(devs, ','); + + delitem = (devs[0] == '-'); + if(devs[0] == '-') devs++; + + if(!devs[0] || devs[0] == ',') + { + endlist = 0; + continue; + } + endlist = 1; + + len = (next ? ((size_t)(next-devs)) : strlen(devs)); + while(len > 0 && isspace(devs[len-1])) + len--; +#ifdef HAVE_WASAPI + /* HACK: For backwards compatibility, convert backend references of + * mmdevapi to wasapi. This should eventually be removed. + */ + if(len == 8 && strncmp(devs, "mmdevapi", len) == 0) + { + devs = "wasapi"; + len = 6; + } +#endif + for(n = i;n < BackendListSize;n++) + { + if(len == strlen(BackendList[n].name) && + strncmp(BackendList[n].name, devs, len) == 0) + { + if(delitem) + { + for(;n+1 < BackendListSize;n++) + BackendList[n] = BackendList[n+1]; + BackendListSize--; + } + else + { + struct BackendInfo Bkp = BackendList[n]; + for(;n > i;n--) + BackendList[n] = BackendList[n-1]; + BackendList[n] = Bkp; + + i++; + } + break; + } + } + } while(next++); + + if(endlist) + BackendListSize = i; + } + + for(n = i = 0;i < BackendListSize && (!PlaybackBackend.name || !CaptureBackend.name);i++) + { + ALCbackendFactory *factory; + BackendList[n] = BackendList[i]; + + factory = BackendList[n].getFactory(); + if(!V0(factory,init)()) + { + WARN("Failed to initialize backend \"%s\"\n", BackendList[n].name); + continue; + } + + TRACE("Initialized backend \"%s\"\n", BackendList[n].name); + if(!PlaybackBackend.name && V(factory,querySupport)(ALCbackend_Playback)) + { + PlaybackBackend = BackendList[n]; + TRACE("Added \"%s\" for playback\n", PlaybackBackend.name); + } + if(!CaptureBackend.name && V(factory,querySupport)(ALCbackend_Capture)) + { + CaptureBackend = BackendList[n]; + TRACE("Added \"%s\" for capture\n", CaptureBackend.name); + } + n++; + } + BackendListSize = n; + + { + ALCbackendFactory *factory = ALCloopbackFactory_getFactory(); + V0(factory,init)(); + } + + if(!PlaybackBackend.name) + WARN("No playback backend available!\n"); + if(!CaptureBackend.name) + WARN("No capture backend available!\n"); + + if(ConfigValueStr(nullptr, nullptr, "excludefx", &str)) + { + size_t len; + const char *next = str; + + do { + str = next; + next = strchr(str, ','); + + if(!str[0] || next == str) + continue; + + len = (next ? ((size_t)(next-str)) : strlen(str)); + for(n = 0;n < EFFECTLIST_SIZE;n++) + { + if(len == strlen(EffectList[n].name) && + strncmp(EffectList[n].name, str, len) == 0) + DisabledEffects[EffectList[n].type] = AL_TRUE; + } + } while(next++); + } + + InitEffect(&DefaultEffect); + str = getenv("ALSOFT_DEFAULT_REVERB"); + if((str && str[0]) || ConfigValueStr(nullptr, nullptr, "default-reverb", &str)) + LoadReverbPreset(str, &DefaultEffect); +} +#define DO_INITCONFIG() alcall_once(&alc_config_once, alc_initconfig) + + +/************************************************ + * Library deinitialization + ************************************************/ +static void alc_cleanup(void) +{ + AL_STRING_DEINIT(alcAllDevicesList); + AL_STRING_DEINIT(alcCaptureDeviceList); + + free(alcDefaultAllDevicesSpecifier); + alcDefaultAllDevicesSpecifier = nullptr; + free(alcCaptureDefaultDeviceSpecifier); + alcCaptureDefaultDeviceSpecifier = nullptr; + + if(ALCdevice *dev{DeviceList.exchange(nullptr)}) + { + ALCuint num = 0; + do { + num++; + dev = ATOMIC_LOAD(&dev->next, almemory_order_relaxed); + } while(dev != nullptr); + ERR("%u device%s not closed\n", num, (num>1)?"s":""); + } +} + +static void alc_deinit_safe(void) +{ + alc_cleanup(); + + FreeHrtfs(); + FreeALConfig(); + + almtx_destroy(&ListLock); + altss_delete(LocalContext); + + if(LogFile != stderr) + fclose(LogFile); + LogFile = nullptr; + + althrd_deinit(); +} + +static void alc_deinit(void) +{ + int i; + + alc_cleanup(); + + memset(&PlaybackBackend, 0, sizeof(PlaybackBackend)); + memset(&CaptureBackend, 0, sizeof(CaptureBackend)); + + for(i = 0;i < BackendListSize;i++) + { + ALCbackendFactory *factory = BackendList[i].getFactory(); + V0(factory,deinit)(); + } + { + ALCbackendFactory *factory = ALCloopbackFactory_getFactory(); + V0(factory,deinit)(); + } + + alc_deinit_safe(); +} + + +/************************************************ + * Device enumeration + ************************************************/ +static void ProbeDevices(al_string *list, struct BackendInfo *backendinfo, enum DevProbe type) +{ + DO_INITCONFIG(); + + LockLists(); + alstr_clear(list); + + if(backendinfo->getFactory) + { + ALCbackendFactory *factory = backendinfo->getFactory(); + V(factory,probe)(type, list); + } + + UnlockLists(); +} +static void ProbeAllDevicesList(void) +{ ProbeDevices(&alcAllDevicesList, &PlaybackBackend, ALL_DEVICE_PROBE); } +static void ProbeCaptureDeviceList(void) +{ ProbeDevices(&alcCaptureDeviceList, &CaptureBackend, CAPTURE_DEVICE_PROBE); } + + +/************************************************ + * Device format information + ************************************************/ +const ALCchar *DevFmtTypeString(enum DevFmtType type) +{ + switch(type) + { + case DevFmtByte: return "Signed Byte"; + case DevFmtUByte: return "Unsigned Byte"; + case DevFmtShort: return "Signed Short"; + case DevFmtUShort: return "Unsigned Short"; + case DevFmtInt: return "Signed Int"; + case DevFmtUInt: return "Unsigned Int"; + case DevFmtFloat: return "Float"; + } + return "(unknown type)"; +} +const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) +{ + switch(chans) + { + case DevFmtMono: return "Mono"; + case DevFmtStereo: return "Stereo"; + case DevFmtQuad: return "Quadraphonic"; + case DevFmtX51: return "5.1 Surround"; + case DevFmtX51Rear: return "5.1 Surround (Rear)"; + case DevFmtX61: return "6.1 Surround"; + case DevFmtX71: return "7.1 Surround"; + case DevFmtAmbi3D: return "Ambisonic 3D"; + } + return "(unknown channels)"; +} + +ALsizei BytesFromDevFmt(enum DevFmtType type) +{ + switch(type) + { + case DevFmtByte: return sizeof(ALbyte); + case DevFmtUByte: return sizeof(ALubyte); + case DevFmtShort: return sizeof(ALshort); + case DevFmtUShort: return sizeof(ALushort); + case DevFmtInt: return sizeof(ALint); + case DevFmtUInt: return sizeof(ALuint); + case DevFmtFloat: return sizeof(ALfloat); + } + return 0; +} +ALsizei ChannelsFromDevFmt(enum DevFmtChannels chans, ALsizei ambiorder) +{ + switch(chans) + { + case DevFmtMono: return 1; + case DevFmtStereo: return 2; + case DevFmtQuad: return 4; + case DevFmtX51: return 6; + case DevFmtX51Rear: return 6; + case DevFmtX61: return 7; + case DevFmtX71: return 8; + case DevFmtAmbi3D: return (ambiorder >= 3) ? 16 : + (ambiorder == 2) ? 9 : + (ambiorder == 1) ? 4 : 1; + } + return 0; +} + +static ALboolean DecomposeDevFormat(ALenum format, enum DevFmtChannels *chans, + enum DevFmtType *type) +{ + static const struct { + ALenum format; + enum DevFmtChannels channels; + enum DevFmtType type; + } list[] = { + { AL_FORMAT_MONO8, DevFmtMono, DevFmtUByte }, + { AL_FORMAT_MONO16, DevFmtMono, DevFmtShort }, + { AL_FORMAT_MONO_FLOAT32, DevFmtMono, DevFmtFloat }, + + { AL_FORMAT_STEREO8, DevFmtStereo, DevFmtUByte }, + { AL_FORMAT_STEREO16, DevFmtStereo, DevFmtShort }, + { AL_FORMAT_STEREO_FLOAT32, DevFmtStereo, DevFmtFloat }, + + { AL_FORMAT_QUAD8, DevFmtQuad, DevFmtUByte }, + { AL_FORMAT_QUAD16, DevFmtQuad, DevFmtShort }, + { AL_FORMAT_QUAD32, DevFmtQuad, DevFmtFloat }, + + { AL_FORMAT_51CHN8, DevFmtX51, DevFmtUByte }, + { AL_FORMAT_51CHN16, DevFmtX51, DevFmtShort }, + { AL_FORMAT_51CHN32, DevFmtX51, DevFmtFloat }, + + { AL_FORMAT_61CHN8, DevFmtX61, DevFmtUByte }, + { AL_FORMAT_61CHN16, DevFmtX61, DevFmtShort }, + { AL_FORMAT_61CHN32, DevFmtX61, DevFmtFloat }, + + { AL_FORMAT_71CHN8, DevFmtX71, DevFmtUByte }, + { AL_FORMAT_71CHN16, DevFmtX71, DevFmtShort }, + { AL_FORMAT_71CHN32, DevFmtX71, DevFmtFloat }, + }; + ALuint i; + + for(i = 0;i < COUNTOF(list);i++) + { + if(list[i].format == format) + { + *chans = list[i].channels; + *type = list[i].type; + return AL_TRUE; + } + } + + return AL_FALSE; +} + +static ALCboolean IsValidALCType(ALCenum type) +{ + switch(type) + { + case ALC_BYTE_SOFT: + case ALC_UNSIGNED_BYTE_SOFT: + case ALC_SHORT_SOFT: + case ALC_UNSIGNED_SHORT_SOFT: + case ALC_INT_SOFT: + case ALC_UNSIGNED_INT_SOFT: + case ALC_FLOAT_SOFT: + return ALC_TRUE; + } + return ALC_FALSE; +} + +static ALCboolean IsValidALCChannels(ALCenum channels) +{ + switch(channels) + { + case ALC_MONO_SOFT: + case ALC_STEREO_SOFT: + case ALC_QUAD_SOFT: + case ALC_5POINT1_SOFT: + case ALC_6POINT1_SOFT: + case ALC_7POINT1_SOFT: + case ALC_BFORMAT3D_SOFT: + return ALC_TRUE; + } + return ALC_FALSE; +} + +static ALCboolean IsValidAmbiLayout(ALCenum layout) +{ + switch(layout) + { + case ALC_ACN_SOFT: + case ALC_FUMA_SOFT: + return ALC_TRUE; + } + return ALC_FALSE; +} + +static ALCboolean IsValidAmbiScaling(ALCenum scaling) +{ + switch(scaling) + { + case ALC_N3D_SOFT: + case ALC_SN3D_SOFT: + case ALC_FUMA_SOFT: + return ALC_TRUE; + } + return ALC_FALSE; +} + +/************************************************ + * Miscellaneous ALC helpers + ************************************************/ + +/* SetDefaultWFXChannelOrder + * + * Sets the default channel order used by WaveFormatEx. + */ +void SetDefaultWFXChannelOrder(ALCdevice *device) +{ + ALsizei i; + + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + device->RealOut.ChannelName[i] = InvalidChannel; + + switch(device->FmtChans) + { + case DevFmtMono: + device->RealOut.ChannelName[0] = FrontCenter; + break; + case DevFmtStereo: + device->RealOut.ChannelName[0] = FrontLeft; + device->RealOut.ChannelName[1] = FrontRight; + break; + case DevFmtQuad: + device->RealOut.ChannelName[0] = FrontLeft; + device->RealOut.ChannelName[1] = FrontRight; + device->RealOut.ChannelName[2] = BackLeft; + device->RealOut.ChannelName[3] = BackRight; + break; + case DevFmtX51: + device->RealOut.ChannelName[0] = FrontLeft; + device->RealOut.ChannelName[1] = FrontRight; + device->RealOut.ChannelName[2] = FrontCenter; + device->RealOut.ChannelName[3] = LFE; + device->RealOut.ChannelName[4] = SideLeft; + device->RealOut.ChannelName[5] = SideRight; + break; + case DevFmtX51Rear: + device->RealOut.ChannelName[0] = FrontLeft; + device->RealOut.ChannelName[1] = FrontRight; + device->RealOut.ChannelName[2] = FrontCenter; + device->RealOut.ChannelName[3] = LFE; + device->RealOut.ChannelName[4] = BackLeft; + device->RealOut.ChannelName[5] = BackRight; + break; + case DevFmtX61: + device->RealOut.ChannelName[0] = FrontLeft; + device->RealOut.ChannelName[1] = FrontRight; + device->RealOut.ChannelName[2] = FrontCenter; + device->RealOut.ChannelName[3] = LFE; + device->RealOut.ChannelName[4] = BackCenter; + device->RealOut.ChannelName[5] = SideLeft; + device->RealOut.ChannelName[6] = SideRight; + break; + case DevFmtX71: + device->RealOut.ChannelName[0] = FrontLeft; + device->RealOut.ChannelName[1] = FrontRight; + device->RealOut.ChannelName[2] = FrontCenter; + device->RealOut.ChannelName[3] = LFE; + device->RealOut.ChannelName[4] = BackLeft; + device->RealOut.ChannelName[5] = BackRight; + device->RealOut.ChannelName[6] = SideLeft; + device->RealOut.ChannelName[7] = SideRight; + break; + case DevFmtAmbi3D: + device->RealOut.ChannelName[0] = Aux0; + if(device->AmbiOrder > 0) + { + device->RealOut.ChannelName[1] = Aux1; + device->RealOut.ChannelName[2] = Aux2; + device->RealOut.ChannelName[3] = Aux3; + } + if(device->AmbiOrder > 1) + { + device->RealOut.ChannelName[4] = Aux4; + device->RealOut.ChannelName[5] = Aux5; + device->RealOut.ChannelName[6] = Aux6; + device->RealOut.ChannelName[7] = Aux7; + device->RealOut.ChannelName[8] = Aux8; + } + if(device->AmbiOrder > 2) + { + device->RealOut.ChannelName[9] = Aux9; + device->RealOut.ChannelName[10] = Aux10; + device->RealOut.ChannelName[11] = Aux11; + device->RealOut.ChannelName[12] = Aux12; + device->RealOut.ChannelName[13] = Aux13; + device->RealOut.ChannelName[14] = Aux14; + device->RealOut.ChannelName[15] = Aux15; + } + break; + } +} + +/* SetDefaultChannelOrder + * + * Sets the default channel order used by most non-WaveFormatEx-based APIs. + */ +void SetDefaultChannelOrder(ALCdevice *device) +{ + ALsizei i; + + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + device->RealOut.ChannelName[i] = InvalidChannel; + + switch(device->FmtChans) + { + case DevFmtX51Rear: + device->RealOut.ChannelName[0] = FrontLeft; + device->RealOut.ChannelName[1] = FrontRight; + device->RealOut.ChannelName[2] = BackLeft; + device->RealOut.ChannelName[3] = BackRight; + device->RealOut.ChannelName[4] = FrontCenter; + device->RealOut.ChannelName[5] = LFE; + return; + case DevFmtX71: + device->RealOut.ChannelName[0] = FrontLeft; + device->RealOut.ChannelName[1] = FrontRight; + device->RealOut.ChannelName[2] = BackLeft; + device->RealOut.ChannelName[3] = BackRight; + device->RealOut.ChannelName[4] = FrontCenter; + device->RealOut.ChannelName[5] = LFE; + device->RealOut.ChannelName[6] = SideLeft; + device->RealOut.ChannelName[7] = SideRight; + return; + + /* Same as WFX order */ + case DevFmtMono: + case DevFmtStereo: + case DevFmtQuad: + case DevFmtX51: + case DevFmtX61: + case DevFmtAmbi3D: + SetDefaultWFXChannelOrder(device); + break; + } +} + + +/* ALCcontext_DeferUpdates + * + * Defers/suspends updates for the given context's listener and sources. This + * does *NOT* stop mixing, but rather prevents certain property changes from + * taking effect. + */ +void ALCcontext_DeferUpdates(ALCcontext *context) +{ + ATOMIC_STORE_SEQ(&context->DeferUpdates, AL_TRUE); +} + +/* ALCcontext_ProcessUpdates + * + * Resumes update processing after being deferred. + */ +void ALCcontext_ProcessUpdates(ALCcontext *context) +{ + almtx_lock(&context->PropLock); + if(ATOMIC_EXCHANGE_SEQ(&context->DeferUpdates, AL_FALSE)) + { + /* Tell the mixer to stop applying updates, then wait for any active + * updating to finish, before providing updates. + */ + ATOMIC_STORE_SEQ(&context->HoldUpdates, AL_TRUE); + while((ATOMIC_LOAD(&context->UpdateCount, almemory_order_acquire)&1) != 0) + althrd_yield(); + + if(!ATOMIC_EXCHANGE(&context->PropsClean, AL_TRUE, almemory_order_acq_rel)) + UpdateContextProps(context); + if(!ATOMIC_EXCHANGE(&context->Listener->PropsClean, AL_TRUE, almemory_order_acq_rel)) + UpdateListenerProps(context); + UpdateAllEffectSlotProps(context); + UpdateAllSourceProps(context); + + /* Now with all updates declared, let the mixer continue applying them + * so they all happen at once. + */ + ATOMIC_STORE_SEQ(&context->HoldUpdates, AL_FALSE); + } + almtx_unlock(&context->PropLock); +} + + +/* alcSetError + * + * Stores the latest ALC device error + */ +static void alcSetError(ALCdevice *device, ALCenum errorCode) +{ + WARN("Error generated on device %p, code 0x%04x\n", device, errorCode); + if(TrapALCError) + { +#ifdef _WIN32 + /* DebugBreak() will cause an exception if there is no debugger */ + if(IsDebuggerPresent()) + DebugBreak(); +#elif defined(SIGTRAP) + raise(SIGTRAP); +#endif + } + + if(device) + ATOMIC_STORE_SEQ(&device->LastError, errorCode); + else + ATOMIC_STORE_SEQ(&LastNullDeviceError, errorCode); +} + + +static struct Compressor *CreateDeviceLimiter(const ALCdevice *device, const ALfloat threshold) +{ + return CompressorInit(device->RealOut.NumChannels, device->Frequency, + AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, 0.001f, 0.002f, + 0.0f, 0.0f, threshold, INFINITY, 0.0f, 0.020f, 0.200f); +} + +/* UpdateClockBase + * + * Updates the device's base clock time with however many samples have been + * done. This is used so frequency changes on the device don't cause the time + * to jump forward or back. Must not be called while the device is running/ + * mixing. + */ +static inline void UpdateClockBase(ALCdevice *device) +{ + IncrementRef(&device->MixCount); + device->ClockBase += device->SamplesDone * DEVICE_CLOCK_RES / device->Frequency; + device->SamplesDone = 0; + IncrementRef(&device->MixCount); +} + +/* UpdateDeviceParams + * + * Updates device parameters according to the attribute list (caller is + * responsible for holding the list lock). + */ +static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) +{ + enum HrtfRequestMode hrtf_userreq = Hrtf_Default; + enum HrtfRequestMode hrtf_appreq = Hrtf_Default; + ALCenum gainLimiter = device->LimiterState; + const ALsizei old_sends = device->NumAuxSends; + ALsizei new_sends = device->NumAuxSends; + enum DevFmtChannels oldChans; + enum DevFmtType oldType; + ALboolean update_failed; + ALCsizei hrtf_id = -1; + ALCcontext *context; + ALCuint oldFreq; + size_t size; + ALCsizei i; + int val; + + // Check for attributes + if(device->Type == Loopback) + { + ALCsizei numMono, numStereo, numSends; + ALCenum alayout = AL_NONE; + ALCenum ascale = AL_NONE; + ALCenum schans = AL_NONE; + ALCenum stype = AL_NONE; + ALCsizei attrIdx = 0; + ALCsizei aorder = 0; + ALCuint freq = 0; + + if(!attrList) + { + WARN("Missing attributes for loopback device\n"); + return ALC_INVALID_VALUE; + } + + numMono = device->NumMonoSources; + numStereo = device->NumStereoSources; + numSends = old_sends; + +#define TRACE_ATTR(a, v) TRACE("Loopback %s = %d\n", #a, v) + while(attrList[attrIdx]) + { + switch(attrList[attrIdx]) + { + case ALC_FORMAT_CHANNELS_SOFT: + schans = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_FORMAT_CHANNELS_SOFT, schans); + if(!IsValidALCChannels(schans)) + return ALC_INVALID_VALUE; + break; + + case ALC_FORMAT_TYPE_SOFT: + stype = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_FORMAT_TYPE_SOFT, stype); + if(!IsValidALCType(stype)) + return ALC_INVALID_VALUE; + break; + + case ALC_FREQUENCY: + freq = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_FREQUENCY, freq); + if(freq < MIN_OUTPUT_RATE) + return ALC_INVALID_VALUE; + break; + + case ALC_AMBISONIC_LAYOUT_SOFT: + alayout = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_AMBISONIC_LAYOUT_SOFT, alayout); + if(!IsValidAmbiLayout(alayout)) + return ALC_INVALID_VALUE; + break; + + case ALC_AMBISONIC_SCALING_SOFT: + ascale = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_AMBISONIC_SCALING_SOFT, ascale); + if(!IsValidAmbiScaling(ascale)) + return ALC_INVALID_VALUE; + break; + + case ALC_AMBISONIC_ORDER_SOFT: + aorder = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_AMBISONIC_ORDER_SOFT, aorder); + if(aorder < 1 || aorder > MAX_AMBI_ORDER) + return ALC_INVALID_VALUE; + break; + + case ALC_MONO_SOURCES: + numMono = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_MONO_SOURCES, numMono); + numMono = maxi(numMono, 0); + break; + + case ALC_STEREO_SOURCES: + numStereo = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); + numStereo = maxi(numStereo, 0); + break; + + case ALC_MAX_AUXILIARY_SENDS: + numSends = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_MAX_AUXILIARY_SENDS, numSends); + numSends = clampi(numSends, 0, MAX_SENDS); + break; + + case ALC_HRTF_SOFT: + TRACE_ATTR(ALC_HRTF_SOFT, attrList[attrIdx + 1]); + if(attrList[attrIdx + 1] == ALC_FALSE) + hrtf_appreq = Hrtf_Disable; + else if(attrList[attrIdx + 1] == ALC_TRUE) + hrtf_appreq = Hrtf_Enable; + else + hrtf_appreq = Hrtf_Default; + break; + + case ALC_HRTF_ID_SOFT: + hrtf_id = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_HRTF_ID_SOFT, hrtf_id); + break; + + case ALC_OUTPUT_LIMITER_SOFT: + gainLimiter = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_OUTPUT_LIMITER_SOFT, gainLimiter); + break; + + default: + TRACE("Loopback 0x%04X = %d (0x%x)\n", attrList[attrIdx], + attrList[attrIdx + 1], attrList[attrIdx + 1]); + break; + } + + attrIdx += 2; + } +#undef TRACE_ATTR + + if(!schans || !stype || !freq) + { + WARN("Missing format for loopback device\n"); + return ALC_INVALID_VALUE; + } + if(schans == ALC_BFORMAT3D_SOFT && (!alayout || !ascale || !aorder)) + { + WARN("Missing ambisonic info for loopback device\n"); + return ALC_INVALID_VALUE; + } + + if((device->Flags&DEVICE_RUNNING)) + V0(device->Backend,stop)(); + device->Flags &= ~DEVICE_RUNNING; + + UpdateClockBase(device); + + device->Frequency = freq; + device->FmtChans = static_cast(schans); + device->FmtType = static_cast(stype); + if(schans == ALC_BFORMAT3D_SOFT) + { + device->AmbiOrder = aorder; + device->AmbiLayout = static_cast(alayout); + device->AmbiScale = static_cast(ascale); + } + + if(numMono > INT_MAX-numStereo) + numMono = INT_MAX-numStereo; + numMono += numStereo; + if(ConfigValueInt(nullptr, nullptr, "sources", &numMono)) + { + if(numMono <= 0) + numMono = 256; + } + else + numMono = maxi(numMono, 256); + numStereo = mini(numStereo, numMono); + numMono -= numStereo; + device->SourcesMax = numMono + numStereo; + + device->NumMonoSources = numMono; + device->NumStereoSources = numStereo; + + if(ConfigValueInt(nullptr, nullptr, "sends", &new_sends)) + new_sends = mini(numSends, clampi(new_sends, 0, MAX_SENDS)); + else + new_sends = numSends; + } + else if(attrList && attrList[0]) + { + ALCsizei numMono, numStereo, numSends; + ALCsizei attrIdx = 0; + ALCuint freq; + + /* If a context is already running on the device, stop playback so the + * device attributes can be updated. */ + if((device->Flags&DEVICE_RUNNING)) + V0(device->Backend,stop)(); + device->Flags &= ~DEVICE_RUNNING; + + UpdateClockBase(device); + + freq = device->Frequency; + numMono = device->NumMonoSources; + numStereo = device->NumStereoSources; + numSends = old_sends; + +#define TRACE_ATTR(a, v) TRACE("%s = %d\n", #a, v) + while(attrList[attrIdx]) + { + switch(attrList[attrIdx]) + { + case ALC_FREQUENCY: + freq = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_FREQUENCY, freq); + device->Flags |= DEVICE_FREQUENCY_REQUEST; + break; + + case ALC_MONO_SOURCES: + numMono = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_MONO_SOURCES, numMono); + numMono = maxi(numMono, 0); + break; + + case ALC_STEREO_SOURCES: + numStereo = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); + numStereo = maxi(numStereo, 0); + break; + + case ALC_MAX_AUXILIARY_SENDS: + numSends = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_MAX_AUXILIARY_SENDS, numSends); + numSends = clampi(numSends, 0, MAX_SENDS); + break; + + case ALC_HRTF_SOFT: + TRACE_ATTR(ALC_HRTF_SOFT, attrList[attrIdx + 1]); + if(attrList[attrIdx + 1] == ALC_FALSE) + hrtf_appreq = Hrtf_Disable; + else if(attrList[attrIdx + 1] == ALC_TRUE) + hrtf_appreq = Hrtf_Enable; + else + hrtf_appreq = Hrtf_Default; + break; + + case ALC_HRTF_ID_SOFT: + hrtf_id = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_HRTF_ID_SOFT, hrtf_id); + break; + + case ALC_OUTPUT_LIMITER_SOFT: + gainLimiter = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_OUTPUT_LIMITER_SOFT, gainLimiter); + break; + + default: + TRACE("0x%04X = %d (0x%x)\n", attrList[attrIdx], + attrList[attrIdx + 1], attrList[attrIdx + 1]); + break; + } + + attrIdx += 2; + } +#undef TRACE_ATTR + + ConfigValueUInt(alstr_get_cstr(device->DeviceName), nullptr, "frequency", &freq); + freq = maxu(freq, MIN_OUTPUT_RATE); + + device->UpdateSize = (ALuint64)device->UpdateSize * freq / + device->Frequency; + /* SSE and Neon do best with the update size being a multiple of 4 */ + if((CPUCapFlags&(CPU_CAP_SSE|CPU_CAP_NEON)) != 0) + device->UpdateSize = (device->UpdateSize+3)&~3; + + device->Frequency = freq; + + if(numMono > INT_MAX-numStereo) + numMono = INT_MAX-numStereo; + numMono += numStereo; + if(ConfigValueInt(alstr_get_cstr(device->DeviceName), nullptr, "sources", &numMono)) + { + if(numMono <= 0) + numMono = 256; + } + else + numMono = maxi(numMono, 256); + numStereo = mini(numStereo, numMono); + numMono -= numStereo; + device->SourcesMax = numMono + numStereo; + + device->NumMonoSources = numMono; + device->NumStereoSources = numStereo; + + if(ConfigValueInt(alstr_get_cstr(device->DeviceName), nullptr, "sends", &new_sends)) + new_sends = mini(numSends, clampi(new_sends, 0, MAX_SENDS)); + else + new_sends = numSends; + } + + if((device->Flags&DEVICE_RUNNING)) + return ALC_NO_ERROR; + + al_free(device->Uhj_Encoder); + device->Uhj_Encoder = nullptr; + + al_free(device->Bs2b); + device->Bs2b = nullptr; + + al_free(device->ChannelDelay[0].Buffer); + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + { + device->ChannelDelay[i].Length = 0; + device->ChannelDelay[i].Buffer = nullptr; + } + + al_free(device->Dry.Buffer); + device->Dry.Buffer = nullptr; + device->Dry.NumChannels = 0; + device->FOAOut.Buffer = nullptr; + device->FOAOut.NumChannels = 0; + device->RealOut.Buffer = nullptr; + device->RealOut.NumChannels = 0; + + UpdateClockBase(device); + device->FixedLatency = 0; + + device->DitherSeed = DITHER_RNG_SEED; + + /************************************************************************* + * Update device format request if HRTF is requested + */ + device->HrtfStatus = ALC_HRTF_DISABLED_SOFT; + if(device->Type != Loopback) + { + const char *hrtf; + if(ConfigValueStr(alstr_get_cstr(device->DeviceName), nullptr, "hrtf", &hrtf)) + { + if(strcasecmp(hrtf, "true") == 0) + hrtf_userreq = Hrtf_Enable; + else if(strcasecmp(hrtf, "false") == 0) + hrtf_userreq = Hrtf_Disable; + else if(strcasecmp(hrtf, "auto") != 0) + ERR("Unexpected hrtf value: %s\n", hrtf); + } + + if(hrtf_userreq == Hrtf_Enable || (hrtf_userreq != Hrtf_Disable && hrtf_appreq == Hrtf_Enable)) + { + struct Hrtf *hrtf = nullptr; + if(VECTOR_SIZE(device->HrtfList) == 0) + { + VECTOR_DEINIT(device->HrtfList); + device->HrtfList = EnumerateHrtf(device->DeviceName); + } + if(VECTOR_SIZE(device->HrtfList) > 0) + { + if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->HrtfList)) + hrtf = GetLoadedHrtf(VECTOR_ELEM(device->HrtfList, hrtf_id).hrtf); + else + hrtf = GetLoadedHrtf(VECTOR_ELEM(device->HrtfList, 0).hrtf); + } + + if(hrtf) + { + device->FmtChans = DevFmtStereo; + device->Frequency = hrtf->sampleRate; + device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_FREQUENCY_REQUEST; + if(device->HrtfHandle) + Hrtf_DecRef(device->HrtfHandle); + device->HrtfHandle = hrtf; + } + else + { + hrtf_userreq = Hrtf_Default; + hrtf_appreq = Hrtf_Disable; + device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + } + } + } + + oldFreq = device->Frequency; + oldChans = device->FmtChans; + oldType = device->FmtType; + + TRACE("Pre-reset: %s%s, %s%s, %s%uhz, %u update size x%d\n", + (device->Flags&DEVICE_CHANNELS_REQUEST)?"*":"", DevFmtChannelsString(device->FmtChans), + (device->Flags&DEVICE_SAMPLE_TYPE_REQUEST)?"*":"", DevFmtTypeString(device->FmtType), + (device->Flags&DEVICE_FREQUENCY_REQUEST)?"*":"", device->Frequency, + device->UpdateSize, device->NumUpdates + ); + + if(V0(device->Backend,reset)() == ALC_FALSE) + return ALC_INVALID_DEVICE; + + if(device->FmtChans != oldChans && (device->Flags&DEVICE_CHANNELS_REQUEST)) + { + ERR("Failed to set %s, got %s instead\n", DevFmtChannelsString(oldChans), + DevFmtChannelsString(device->FmtChans)); + device->Flags &= ~DEVICE_CHANNELS_REQUEST; + } + if(device->FmtType != oldType && (device->Flags&DEVICE_SAMPLE_TYPE_REQUEST)) + { + ERR("Failed to set %s, got %s instead\n", DevFmtTypeString(oldType), + DevFmtTypeString(device->FmtType)); + device->Flags &= ~DEVICE_SAMPLE_TYPE_REQUEST; + } + if(device->Frequency != oldFreq && (device->Flags&DEVICE_FREQUENCY_REQUEST)) + { + ERR("Failed to set %uhz, got %uhz instead\n", oldFreq, device->Frequency); + device->Flags &= ~DEVICE_FREQUENCY_REQUEST; + } + + if((device->UpdateSize&3) != 0) + { + if((CPUCapFlags&CPU_CAP_SSE)) + WARN("SSE performs best with multiple of 4 update sizes (%u)\n", device->UpdateSize); + if((CPUCapFlags&CPU_CAP_NEON)) + WARN("NEON performs best with multiple of 4 update sizes (%u)\n", device->UpdateSize); + } + + TRACE("Post-reset: %s, %s, %uhz, %u update size x%d\n", + DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), + device->Frequency, device->UpdateSize, device->NumUpdates + ); + + aluInitRenderer(device, hrtf_id, hrtf_appreq, hrtf_userreq); + TRACE("Channel config, Dry: %d, FOA: %d, Real: %d\n", device->Dry.NumChannels, + device->FOAOut.NumChannels, device->RealOut.NumChannels); + + /* Allocate extra channels for any post-filter output. */ + size = (device->Dry.NumChannels + device->FOAOut.NumChannels + + device->RealOut.NumChannels)*sizeof(device->Dry.Buffer[0]); + + TRACE("Allocating " SZFMT " channels, " SZFMT " bytes\n", size/sizeof(device->Dry.Buffer[0]), size); + device->Dry.Buffer = static_cast(al_calloc(16, size)); + if(!device->Dry.Buffer) + { + ERR("Failed to allocate " SZFMT " bytes for mix buffer\n", size); + return ALC_INVALID_DEVICE; + } + + if(device->RealOut.NumChannels != 0) + device->RealOut.Buffer = device->Dry.Buffer + device->Dry.NumChannels + + device->FOAOut.NumChannels; + else + { + device->RealOut.Buffer = device->Dry.Buffer; + device->RealOut.NumChannels = device->Dry.NumChannels; + } + + if(device->FOAOut.NumChannels != 0) + device->FOAOut.Buffer = device->Dry.Buffer + device->Dry.NumChannels; + else + { + device->FOAOut.Buffer = device->Dry.Buffer; + device->FOAOut.NumChannels = device->Dry.NumChannels; + } + + device->NumAuxSends = new_sends; + TRACE("Max sources: %d (%d + %d), effect slots: %d, sends: %d\n", + device->SourcesMax, device->NumMonoSources, device->NumStereoSources, + device->AuxiliaryEffectSlotMax, device->NumAuxSends); + + device->DitherDepth = 0.0f; + if(GetConfigValueBool(alstr_get_cstr(device->DeviceName), nullptr, "dither", 1)) + { + ALint depth = 0; + ConfigValueInt(alstr_get_cstr(device->DeviceName), nullptr, "dither-depth", &depth); + if(depth <= 0) + { + switch(device->FmtType) + { + case DevFmtByte: + case DevFmtUByte: + depth = 8; + break; + case DevFmtShort: + case DevFmtUShort: + depth = 16; + break; + case DevFmtInt: + case DevFmtUInt: + case DevFmtFloat: + break; + } + } + + if(depth > 0) + { + depth = clampi(depth, 2, 24); + device->DitherDepth = powf(2.0f, (ALfloat)(depth-1)); + } + } + if(!(device->DitherDepth > 0.0f)) + TRACE("Dithering disabled\n"); + else + TRACE("Dithering enabled (%g-bit, %g)\n", log2f(device->DitherDepth)+1.0f, + device->DitherDepth); + + device->LimiterState = gainLimiter; + if(ConfigValueBool(alstr_get_cstr(device->DeviceName), nullptr, "output-limiter", &val)) + gainLimiter = val ? ALC_TRUE : ALC_FALSE; + + /* Valid values for gainLimiter are ALC_DONT_CARE_SOFT, ALC_TRUE, and + * ALC_FALSE. For ALC_DONT_CARE_SOFT, use the limiter for integer-based + * output (where samples must be clamped), and don't for floating-point + * (which can take unclamped samples). + */ + if(gainLimiter == ALC_DONT_CARE_SOFT) + { + switch(device->FmtType) + { + case DevFmtByte: + case DevFmtUByte: + case DevFmtShort: + case DevFmtUShort: + case DevFmtInt: + case DevFmtUInt: + gainLimiter = ALC_TRUE; + break; + case DevFmtFloat: + gainLimiter = ALC_FALSE; + break; + } + } + if(gainLimiter != ALC_FALSE) + { + ALfloat thrshld = 1.0f; + switch(device->FmtType) + { + case DevFmtByte: + case DevFmtUByte: + thrshld = 127.0f / 128.0f; + break; + case DevFmtShort: + case DevFmtUShort: + thrshld = 32767.0f / 32768.0f; + break; + case DevFmtInt: + case DevFmtUInt: + case DevFmtFloat: + break; + } + if(device->DitherDepth > 0.0f) + thrshld -= 1.0f / device->DitherDepth; + + al_free(device->Limiter); + device->Limiter = CreateDeviceLimiter(device, log10f(thrshld) * 20.0f); + device->FixedLatency += (ALuint)(GetCompressorLookAhead(device->Limiter) * + DEVICE_CLOCK_RES / device->Frequency); + } + else + { + al_free(device->Limiter); + device->Limiter = nullptr; + } + TRACE("Output limiter %s\n", device->Limiter ? "enabled" : "disabled"); + + aluSelectPostProcess(device); + + TRACE("Fixed device latency: %uns\n", device->FixedLatency); + + /* Need to delay returning failure until replacement Send arrays have been + * allocated with the appropriate size. + */ + update_failed = AL_FALSE; + START_MIXER_MODE(); + context = ATOMIC_LOAD_SEQ(&device->ContextList); + while(context) + { + SourceSubList *sublist, *subend; + struct ALvoiceProps *vprops; + ALsizei pos; + + if(context->DefaultSlot) + { + ALeffectslot *slot = context->DefaultSlot; + ALeffectState *state = slot->Effect.State; + + state->OutBuffer = device->Dry.Buffer; + state->OutChannels = device->Dry.NumChannels; + if(V(state,deviceUpdate)(device) == AL_FALSE) + update_failed = AL_TRUE; + else + UpdateEffectSlotProps(slot, context); + } + + almtx_lock(&context->PropLock); + almtx_lock(&context->EffectSlotLock); + for(pos = 0;pos < (ALsizei)VECTOR_SIZE(context->EffectSlotList);pos++) + { + ALeffectslot *slot = VECTOR_ELEM(context->EffectSlotList, pos); + ALeffectState *state = slot->Effect.State; + + state->OutBuffer = device->Dry.Buffer; + state->OutChannels = device->Dry.NumChannels; + if(V(state,deviceUpdate)(device) == AL_FALSE) + update_failed = AL_TRUE; + else + UpdateEffectSlotProps(slot, context); + } + almtx_unlock(&context->EffectSlotLock); + + almtx_lock(&context->SourceLock); + sublist = VECTOR_BEGIN(context->SourceList); + subend = VECTOR_END(context->SourceList); + for(;sublist != subend;++sublist) + { + ALuint64 usemask = ~sublist->FreeMask; + while(usemask) + { + ALsizei idx = CTZ64(usemask); + ALsource *source = sublist->Sources + idx; + + usemask &= ~(U64(1) << idx); + + if(old_sends != device->NumAuxSends) + { + ALvoid *sends = al_calloc(16, device->NumAuxSends*sizeof(source->Send[0])); + ALsizei s; + + memcpy(sends, source->Send, + mini(device->NumAuxSends, old_sends)*sizeof(source->Send[0]) + ); + for(s = device->NumAuxSends;s < old_sends;s++) + { + if(source->Send[s].Slot) + DecrementRef(&source->Send[s].Slot->ref); + source->Send[s].Slot = nullptr; + } + al_free(source->Send); + source->Send = static_castSend)>(sends); + for(s = old_sends;s < device->NumAuxSends;s++) + { + source->Send[s].Slot = nullptr; + source->Send[s].Gain = 1.0f; + source->Send[s].GainHF = 1.0f; + source->Send[s].HFReference = LOWPASSFREQREF; + source->Send[s].GainLF = 1.0f; + source->Send[s].LFReference = HIGHPASSFREQREF; + } + } + + ATOMIC_STORE(&source->PropsClean, AL_FALSE, almemory_order_release); + } + } + + /* Clear any pre-existing voice property structs, in case the number of + * auxiliary sends is changing. Active sources will have updates + * respecified in UpdateAllSourceProps. + */ + vprops = ATOMIC_EXCHANGE_PTR(&context->FreeVoiceProps, static_cast(nullptr), + almemory_order_acq_rel); + while(vprops) + { + struct ALvoiceProps *next = ATOMIC_LOAD(&vprops->next, almemory_order_relaxed); + al_free(vprops); + vprops = next; + } + + AllocateVoices(context, context->MaxVoices, old_sends); + for(pos = 0;pos < context->VoiceCount;pos++) + { + ALvoice *voice = context->Voices[pos]; + + al_free(ATOMIC_EXCHANGE_PTR(&voice->Update, static_cast(nullptr), + almemory_order_acq_rel)); + + if(ATOMIC_LOAD(&voice->Source, almemory_order_acquire) == nullptr) + continue; + + if(device->AvgSpeakerDist > 0.0f) + { + /* Reinitialize the NFC filters for new parameters. */ + ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / + (device->AvgSpeakerDist * device->Frequency); + for(i = 0;i < voice->NumChannels;i++) + NfcFilterCreate(&voice->Direct.Params[i].NFCtrlFilter, 0.0f, w1); + } + } + almtx_unlock(&context->SourceLock); + + ATOMIC_STORE(&context->PropsClean, AL_TRUE, almemory_order_release); + UpdateContextProps(context); + ATOMIC_STORE(&context->Listener->PropsClean, AL_TRUE, almemory_order_release); + UpdateListenerProps(context); + UpdateAllSourceProps(context); + almtx_unlock(&context->PropLock); + + context = ATOMIC_LOAD(&context->next, almemory_order_relaxed); + } + END_MIXER_MODE(); + if(update_failed) + return ALC_INVALID_DEVICE; + + if(!(device->Flags&DEVICE_PAUSED)) + { + if(V0(device->Backend,start)() == ALC_FALSE) + return ALC_INVALID_DEVICE; + device->Flags |= DEVICE_RUNNING; + } + + return ALC_NO_ERROR; +} + + +static void InitDevice(ALCdevice *device, enum DeviceType type) +{ + ALsizei i; + + InitRef(&device->ref, 1); + ATOMIC_INIT(&device->Connected, ALC_TRUE); + device->Type = type; + ATOMIC_INIT(&device->LastError, ALC_NO_ERROR); + + device->Flags = 0; + device->Render_Mode = NormalRender; + device->AvgSpeakerDist = 0.0f; + device->LimiterState = ALC_DONT_CARE_SOFT; + + ATOMIC_INIT(&device->ContextList, static_cast(nullptr)); + + device->ClockBase = 0; + device->SamplesDone = 0; + device->FixedLatency = 0; + + device->SourcesMax = 0; + device->AuxiliaryEffectSlotMax = 0; + device->NumAuxSends = 0; + + device->Dry.Buffer = nullptr; + device->Dry.NumChannels = 0; + device->FOAOut.Buffer = nullptr; + device->FOAOut.NumChannels = 0; + device->RealOut.Buffer = nullptr; + device->RealOut.NumChannels = 0; + + AL_STRING_INIT(device->DeviceName); + + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + { + device->ChannelDelay[i].Gain = 1.0f; + device->ChannelDelay[i].Length = 0; + device->ChannelDelay[i].Buffer = nullptr; + } + + device->HrtfName = nullptr; + VECTOR_INIT(device->HrtfList); + device->HrtfHandle = nullptr; + device->Hrtf = nullptr; + device->Bs2b = nullptr; + device->Uhj_Encoder = nullptr; + device->AmbiDecoder = nullptr; + device->AmbiUp = nullptr; + device->Stablizer = nullptr; + device->Limiter = nullptr; + + VECTOR_INIT(device->BufferList); + almtx_init(&device->BufferLock, almtx_plain); + + VECTOR_INIT(device->EffectList); + almtx_init(&device->EffectLock, almtx_plain); + + VECTOR_INIT(device->FilterList); + almtx_init(&device->FilterLock, almtx_plain); + + almtx_init(&device->BackendLock, almtx_plain); + device->Backend = nullptr; + + ATOMIC_INIT(&device->next, static_cast(nullptr)); +} + +/* FreeDevice + * + * Frees the device structure, and destroys any objects the app failed to + * delete. Called once there's no more references on the device. + */ +static ALCvoid FreeDevice(ALCdevice *device) +{ + ALsizei i; + + TRACE("%p\n", device); + + if(device->Backend) + DELETE_OBJ(device->Backend); + device->Backend = nullptr; + + almtx_destroy(&device->BackendLock); + + ReleaseALBuffers(device); +#define FREE_BUFFERSUBLIST(x) al_free((x)->Buffers) + VECTOR_FOR_EACH(BufferSubList, device->BufferList, FREE_BUFFERSUBLIST); +#undef FREE_BUFFERSUBLIST + VECTOR_DEINIT(device->BufferList); + almtx_destroy(&device->BufferLock); + + ReleaseALEffects(device); +#define FREE_EFFECTSUBLIST(x) al_free((x)->Effects) + VECTOR_FOR_EACH(EffectSubList, device->EffectList, FREE_EFFECTSUBLIST); +#undef FREE_EFFECTSUBLIST + VECTOR_DEINIT(device->EffectList); + almtx_destroy(&device->EffectLock); + + ReleaseALFilters(device); +#define FREE_FILTERSUBLIST(x) al_free((x)->Filters) + VECTOR_FOR_EACH(FilterSubList, device->FilterList, FREE_FILTERSUBLIST); +#undef FREE_FILTERSUBLIST + VECTOR_DEINIT(device->FilterList); + almtx_destroy(&device->FilterLock); + + al_free(device->HrtfName); + device->HrtfName = nullptr; + FreeHrtfList(&device->HrtfList); + if(device->HrtfHandle) + Hrtf_DecRef(device->HrtfHandle); + device->HrtfHandle = nullptr; + al_free(device->Hrtf); + device->Hrtf = nullptr; + + al_free(device->Bs2b); + device->Bs2b = nullptr; + + al_free(device->Uhj_Encoder); + device->Uhj_Encoder = nullptr; + + bformatdec_free(&device->AmbiDecoder); + ambiup_free(&device->AmbiUp); + + al_free(device->Stablizer); + device->Stablizer = nullptr; + + al_free(device->Limiter); + device->Limiter = nullptr; + + al_free(device->ChannelDelay[0].Buffer); + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + { + device->ChannelDelay[i].Gain = 1.0f; + device->ChannelDelay[i].Length = 0; + device->ChannelDelay[i].Buffer = nullptr; + } + + AL_STRING_DEINIT(device->DeviceName); + + al_free(device->Dry.Buffer); + device->Dry.Buffer = nullptr; + device->Dry.NumChannels = 0; + device->FOAOut.Buffer = nullptr; + device->FOAOut.NumChannels = 0; + device->RealOut.Buffer = nullptr; + device->RealOut.NumChannels = 0; + + al_free(device); +} + + +void ALCdevice_IncRef(ALCdevice *device) +{ + uint ref; + ref = IncrementRef(&device->ref); + TRACEREF("%p increasing refcount to %u\n", device, ref); +} + +void ALCdevice_DecRef(ALCdevice *device) +{ + uint ref; + ref = DecrementRef(&device->ref); + TRACEREF("%p decreasing refcount to %u\n", device, ref); + if(ref == 0) FreeDevice(device); +} + +/* VerifyDevice + * + * Checks if the device handle is valid, and increments its ref count if so. + */ +static ALCboolean VerifyDevice(ALCdevice **device) +{ + LockLists(); + ALCdevice *tmpDevice{DeviceList.load()}; + while(tmpDevice) + { + if(tmpDevice == *device) + { + ALCdevice_IncRef(tmpDevice); + UnlockLists(); + return ALC_TRUE; + } + tmpDevice = ATOMIC_LOAD(&tmpDevice->next, almemory_order_relaxed); + } + UnlockLists(); + + *device = nullptr; + return ALC_FALSE; +} + + +/* InitContext + * + * Initializes context fields + */ +static ALvoid InitContext(ALCcontext *Context) +{ + ALlistener *listener = Context->Listener; + struct ALeffectslotArray *auxslots; + + //Initialise listener + listener->Gain = 1.0f; + listener->Position[0] = 0.0f; + listener->Position[1] = 0.0f; + listener->Position[2] = 0.0f; + listener->Velocity[0] = 0.0f; + listener->Velocity[1] = 0.0f; + listener->Velocity[2] = 0.0f; + listener->Forward[0] = 0.0f; + listener->Forward[1] = 0.0f; + listener->Forward[2] = -1.0f; + listener->Up[0] = 0.0f; + listener->Up[1] = 1.0f; + listener->Up[2] = 0.0f; + ATOMIC_INIT(&listener->PropsClean, AL_TRUE); + + ATOMIC_INIT(&listener->Update, static_cast(nullptr)); + + //Validate Context + InitRef(&Context->UpdateCount, 0); + ATOMIC_INIT(&Context->HoldUpdates, AL_FALSE); + Context->GainBoost = 1.0f; + almtx_init(&Context->PropLock, almtx_plain); + ATOMIC_INIT(&Context->LastError, AL_NO_ERROR); + VECTOR_INIT(Context->SourceList); + Context->NumSources = 0; + almtx_init(&Context->SourceLock, almtx_plain); + VECTOR_INIT(Context->EffectSlotList); + almtx_init(&Context->EffectSlotLock, almtx_plain); + + if(Context->DefaultSlot) + { + auxslots = static_cast(al_calloc(DEF_ALIGN, + FAM_SIZE(struct ALeffectslotArray, slot, 1))); + auxslots->count = 1; + auxslots->slot[0] = Context->DefaultSlot; + } + else + { + auxslots = static_cast(al_calloc(DEF_ALIGN, + sizeof(struct ALeffectslotArray))); + auxslots->count = 0; + } + ATOMIC_INIT(&Context->ActiveAuxSlots, auxslots); + + //Set globals + Context->DistanceModel = DefaultDistanceModel; + Context->SourceDistanceModel = AL_FALSE; + Context->DopplerFactor = 1.0f; + Context->DopplerVelocity = 1.0f; + Context->SpeedOfSound = SPEEDOFSOUNDMETRESPERSEC; + Context->MetersPerUnit = AL_DEFAULT_METERS_PER_UNIT; + ATOMIC_INIT(&Context->PropsClean, AL_TRUE); + ATOMIC_INIT(&Context->DeferUpdates, AL_FALSE); + alsem_init(&Context->EventSem, 0); + Context->AsyncEvents = nullptr; + ATOMIC_INIT(&Context->EnabledEvts, 0u); + almtx_init(&Context->EventCbLock, almtx_plain); + Context->EventCb = nullptr; + Context->EventParam = nullptr; + + ATOMIC_INIT(&Context->Update, static_cast(nullptr)); + ATOMIC_INIT(&Context->FreeContextProps, static_cast(nullptr)); + ATOMIC_INIT(&Context->FreeListenerProps, static_cast(nullptr)); + ATOMIC_INIT(&Context->FreeVoiceProps, static_cast(nullptr)); + ATOMIC_INIT(&Context->FreeEffectslotProps, static_cast(nullptr)); + + Context->ExtensionList = alExtList; + + + listener->Params.Matrix = IdentityMatrixf; + aluVectorSet(&listener->Params.Velocity, 0.0f, 0.0f, 0.0f, 0.0f); + listener->Params.Gain = listener->Gain; + listener->Params.MetersPerUnit = Context->MetersPerUnit; + listener->Params.DopplerFactor = Context->DopplerFactor; + listener->Params.SpeedOfSound = Context->SpeedOfSound * Context->DopplerVelocity; + listener->Params.ReverbSpeedOfSound = listener->Params.SpeedOfSound * + listener->Params.MetersPerUnit; + listener->Params.SourceDistanceModel = Context->SourceDistanceModel; + listener->Params.DistanceModel = Context->DistanceModel; + + + Context->AsyncEvents = ll_ringbuffer_create(63, sizeof(AsyncEvent), false); + if(althrd_create(&Context->EventThread, EventThread, Context) != althrd_success) + ERR("Failed to start event thread! Expect problems.\n"); +} + + +/* FreeContext + * + * Cleans up the context, and destroys any remaining objects the app failed to + * delete. Called once there's no more references on the context. + */ +static void FreeContext(ALCcontext *context) +{ + ALlistener *listener = context->Listener; + struct ALeffectslotArray *auxslots; + struct ALeffectslotProps *eprops; + struct ALlistenerProps *lprops; + struct ALcontextProps *cprops; + struct ALvoiceProps *vprops; + size_t count; + ALsizei i; + + TRACE("%p\n", context); + + if((cprops=ATOMIC_LOAD(&context->Update, almemory_order_acquire)) != nullptr) + { + TRACE("Freed unapplied context update %p\n", cprops); + al_free(cprops); + } + + count = 0; + cprops = ATOMIC_LOAD(&context->FreeContextProps, almemory_order_acquire); + while(cprops) + { + struct ALcontextProps *next = ATOMIC_LOAD(&cprops->next, almemory_order_acquire); + al_free(cprops); + cprops = next; + ++count; + } + TRACE("Freed " SZFMT " context property object%s\n", count, (count==1)?"":"s"); + + if(context->DefaultSlot) + { + DeinitEffectSlot(context->DefaultSlot); + context->DefaultSlot = nullptr; + } + + auxslots = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, + static_cast(nullptr), almemory_order_relaxed); + al_free(auxslots); + + ReleaseALSources(context); +#define FREE_SOURCESUBLIST(x) al_free((x)->Sources) + VECTOR_FOR_EACH(SourceSubList, context->SourceList, FREE_SOURCESUBLIST); +#undef FREE_SOURCESUBLIST + VECTOR_DEINIT(context->SourceList); + context->NumSources = 0; + almtx_destroy(&context->SourceLock); + + count = 0; + eprops = ATOMIC_LOAD(&context->FreeEffectslotProps, almemory_order_relaxed); + while(eprops) + { + struct ALeffectslotProps *next = ATOMIC_LOAD(&eprops->next, almemory_order_relaxed); + if(eprops->State) ALeffectState_DecRef(eprops->State); + al_free(eprops); + eprops = next; + ++count; + } + TRACE("Freed " SZFMT " AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s"); + + ReleaseALAuxiliaryEffectSlots(context); +#define FREE_EFFECTSLOTPTR(x) al_free(*(x)) + VECTOR_FOR_EACH(ALeffectslotPtr, context->EffectSlotList, FREE_EFFECTSLOTPTR); +#undef FREE_EFFECTSLOTPTR + VECTOR_DEINIT(context->EffectSlotList); + almtx_destroy(&context->EffectSlotLock); + + count = 0; + vprops = ATOMIC_LOAD(&context->FreeVoiceProps, almemory_order_relaxed); + while(vprops) + { + struct ALvoiceProps *next = ATOMIC_LOAD(&vprops->next, almemory_order_relaxed); + al_free(vprops); + vprops = next; + ++count; + } + TRACE("Freed " SZFMT " voice property object%s\n", count, (count==1)?"":"s"); + + for(i = 0;i < context->VoiceCount;i++) + DeinitVoice(context->Voices[i]); + al_free(context->Voices); + context->Voices = nullptr; + context->VoiceCount = 0; + context->MaxVoices = 0; + + if((lprops=ATOMIC_LOAD(&listener->Update, almemory_order_acquire)) != nullptr) + { + TRACE("Freed unapplied listener update %p\n", lprops); + al_free(lprops); + } + count = 0; + lprops = ATOMIC_LOAD(&context->FreeListenerProps, almemory_order_acquire); + while(lprops) + { + struct ALlistenerProps *next = ATOMIC_LOAD(&lprops->next, almemory_order_acquire); + al_free(lprops); + lprops = next; + ++count; + } + TRACE("Freed " SZFMT " listener property object%s\n", count, (count==1)?"":"s"); + + almtx_destroy(&context->EventCbLock); + alsem_destroy(&context->EventSem); + + ll_ringbuffer_free(context->AsyncEvents); + context->AsyncEvents = nullptr; + + almtx_destroy(&context->PropLock); + + ALCdevice_DecRef(context->Device); + context->Device = nullptr; + + //Invalidate context + memset(context, 0, sizeof(ALCcontext)); + al_free(context); +} + +/* ReleaseContext + * + * Removes the context reference from the given device and removes it from + * being current on the running thread or globally. Returns true if other + * contexts still exist on the device. + */ +static bool ReleaseContext(ALCcontext *context, ALCdevice *device) +{ + static const AsyncEvent kill_evt = ASYNC_EVENT(EventType_KillThread); + ALCcontext *origctx, *newhead; + bool ret = true; + + if(altss_get(LocalContext) == context) + { + WARN("%p released while current on thread\n", context); + altss_set(LocalContext, nullptr); + ALCcontext_DecRef(context); + } + + origctx = context; + if(ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&GlobalContext, &origctx, static_cast(nullptr))) + ALCcontext_DecRef(context); + + V0(device->Backend,lock)(); + origctx = context; + newhead = ATOMIC_LOAD(&context->next, almemory_order_relaxed); + if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&device->ContextList, &origctx, newhead)) + { + ALCcontext *list; + do { + /* origctx is what the desired context failed to match. Try + * swapping out the next one in the list. + */ + list = origctx; + origctx = context; + } while(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&list->next, &origctx, newhead)); + } + else + ret = !!newhead; + V0(device->Backend,unlock)(); + + /* Make sure the context is finished and no longer processing in the mixer + * before sending the message queue kill event. The backend's lock does + * this, although waiting for a non-odd mix count would work too. + */ + + while(ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1) == 0) + althrd_yield(); + alsem_post(&context->EventSem); + althrd_join(context->EventThread, nullptr); + + ALCcontext_DecRef(context); + return ret; +} + +static void ALCcontext_IncRef(ALCcontext *context) +{ + uint ref = IncrementRef(&context->ref); + TRACEREF("%p increasing refcount to %u\n", context, ref); +} + +void ALCcontext_DecRef(ALCcontext *context) +{ + uint ref = DecrementRef(&context->ref); + TRACEREF("%p decreasing refcount to %u\n", context, ref); + if(ref == 0) FreeContext(context); +} + +static void ReleaseThreadCtx(void *ptr) +{ + ALCcontext *context = static_cast(ptr); + uint ref = DecrementRef(&context->ref); + TRACEREF("%p decreasing refcount to %u\n", context, ref); + ERR("Context %p current for thread being destroyed, possible leak!\n", context); +} + +/* VerifyContext + * + * Checks that the given context is valid, and increments its reference count. + */ +static ALCboolean VerifyContext(ALCcontext **context) +{ + LockLists(); + ALCdevice *dev{DeviceList.load()}; + while(dev) + { + ALCcontext *ctx = ATOMIC_LOAD(&dev->ContextList, almemory_order_acquire); + while(ctx) + { + if(ctx == *context) + { + ALCcontext_IncRef(ctx); + UnlockLists(); + return ALC_TRUE; + } + ctx = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed); + } + dev = ATOMIC_LOAD(&dev->next, almemory_order_relaxed); + } + UnlockLists(); + + *context = nullptr; + return ALC_FALSE; +} + + +/* GetContextRef + * + * Returns the currently active context for this thread, and adds a reference + * without locking it. + */ +ALCcontext *GetContextRef(void) +{ + ALCcontext *context{static_cast(altss_get(LocalContext))}; + if(context) + ALCcontext_IncRef(context); + else + { + LockLists(); + context = ATOMIC_LOAD_SEQ(&GlobalContext); + if(context) ALCcontext_IncRef(context); + UnlockLists(); + } + + return context; +} + + +void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) +{ + ALCdevice *device = context->Device; + ALsizei num_sends = device->NumAuxSends; + struct ALvoiceProps *props; + size_t sizeof_props; + size_t sizeof_voice; + ALvoice **voices; + ALvoice *voice; + ALsizei v = 0; + size_t size; + + if(num_voices == context->MaxVoices && num_sends == old_sends) + return; + + /* Allocate the voice pointers, voices, and the voices' stored source + * property set (including the dynamically-sized Send[] array) in one + * chunk. + */ + sizeof_voice = RoundUp(FAM_SIZE(ALvoice, Send, num_sends), 16); + sizeof_props = RoundUp(FAM_SIZE(struct ALvoiceProps, Send, num_sends), 16); + size = sizeof(ALvoice*) + sizeof_voice + sizeof_props; + + voices = static_cast(al_calloc(16, RoundUp(size*num_voices, 16))); + /* The voice and property objects are stored interleaved since they're + * paired together. + */ + voice = (ALvoice*)((char*)voices + RoundUp(num_voices*sizeof(ALvoice*), 16)); + props = (struct ALvoiceProps*)((char*)voice + sizeof_voice); + + if(context->Voices) + { + const ALsizei v_count = mini(context->VoiceCount, num_voices); + const ALsizei s_count = mini(old_sends, num_sends); + + for(;v < v_count;v++) + { + ALvoice *old_voice = context->Voices[v]; + ALsizei i; + + /* Copy the old voice data and source property set to the new + * storage. + */ + memcpy(voice, old_voice, sizeof(*voice)); + for(i = 0;i < s_count;i++) + voice->Send[i] = old_voice->Send[i]; + + memcpy(props, old_voice->Props, sizeof(*props)); + for(i = 0;i < s_count;i++) + props->Send[i] = old_voice->Props->Send[i]; + + /* Set this voice's property set pointer and voice reference. */ + voice->Props = props; + voices[v] = voice; + + /* Increment pointers to the next storage space. */ + voice = (ALvoice*)((char*)props + sizeof_props); + props = (struct ALvoiceProps*)((char*)voice + sizeof_voice); + } + /* Deinit any left over voices that weren't copied over to the new + * array. NOTE: If this does anything, v equals num_voices and + * num_voices is less than VoiceCount, so the following loop won't do + * anything. + */ + for(;v < context->VoiceCount;v++) + DeinitVoice(context->Voices[v]); + } + /* Finish setting the voices' property set pointers and references. */ + for(;v < num_voices;v++) + { + ATOMIC_INIT(&voice->Update, static_cast(nullptr)); + + voice->Props = props; + voices[v] = voice; + + voice = (ALvoice*)((char*)props + sizeof_props); + props = (struct ALvoiceProps*)((char*)voice + sizeof_voice); + } + + al_free(context->Voices); + context->Voices = voices; + context->MaxVoices = num_voices; + context->VoiceCount = mini(context->VoiceCount, num_voices); +} + + +/************************************************ + * Standard ALC functions + ************************************************/ + +/* alcGetError + * + * Return last ALC generated error code for the given device +*/ +ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) +{ + ALCenum errorCode; + + if(VerifyDevice(&device)) + { + errorCode = ATOMIC_EXCHANGE_SEQ(&device->LastError, ALC_NO_ERROR); + ALCdevice_DecRef(device); + } + else + errorCode = ATOMIC_EXCHANGE_SEQ(&LastNullDeviceError, ALC_NO_ERROR); + + return errorCode; +} + + +/* alcSuspendContext + * + * Suspends updates for the given context + */ +ALC_API ALCvoid ALC_APIENTRY alcSuspendContext(ALCcontext *context) +{ + if(!SuspendDefers) + return; + + if(!VerifyContext(&context)) + alcSetError(nullptr, ALC_INVALID_CONTEXT); + else + { + ALCcontext_DeferUpdates(context); + ALCcontext_DecRef(context); + } +} + +/* alcProcessContext + * + * Resumes processing updates for the given context + */ +ALC_API ALCvoid ALC_APIENTRY alcProcessContext(ALCcontext *context) +{ + if(!SuspendDefers) + return; + + if(!VerifyContext(&context)) + alcSetError(nullptr, ALC_INVALID_CONTEXT); + else + { + ALCcontext_ProcessUpdates(context); + ALCcontext_DecRef(context); + } +} + + +/* alcGetString + * + * Returns information about the device, and error strings + */ +ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum param) +{ + const ALCchar *value = nullptr; + + switch(param) + { + case ALC_NO_ERROR: + value = alcNoError; + break; + + case ALC_INVALID_ENUM: + value = alcErrInvalidEnum; + break; + + case ALC_INVALID_VALUE: + value = alcErrInvalidValue; + break; + + case ALC_INVALID_DEVICE: + value = alcErrInvalidDevice; + break; + + case ALC_INVALID_CONTEXT: + value = alcErrInvalidContext; + break; + + case ALC_OUT_OF_MEMORY: + value = alcErrOutOfMemory; + break; + + case ALC_DEVICE_SPECIFIER: + value = alcDefaultName; + break; + + case ALC_ALL_DEVICES_SPECIFIER: + if(VerifyDevice(&Device)) + { + value = alstr_get_cstr(Device->DeviceName); + ALCdevice_DecRef(Device); + } + else + { + ProbeAllDevicesList(); + value = alstr_get_cstr(alcAllDevicesList); + } + break; + + case ALC_CAPTURE_DEVICE_SPECIFIER: + if(VerifyDevice(&Device)) + { + value = alstr_get_cstr(Device->DeviceName); + ALCdevice_DecRef(Device); + } + else + { + ProbeCaptureDeviceList(); + value = alstr_get_cstr(alcCaptureDeviceList); + } + break; + + /* Default devices are always first in the list */ + case ALC_DEFAULT_DEVICE_SPECIFIER: + value = alcDefaultName; + break; + + case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: + if(alstr_empty(alcAllDevicesList)) + ProbeAllDevicesList(); + + VerifyDevice(&Device); + + free(alcDefaultAllDevicesSpecifier); + alcDefaultAllDevicesSpecifier = strdup(alstr_get_cstr(alcAllDevicesList)); + if(!alcDefaultAllDevicesSpecifier) + alcSetError(Device, ALC_OUT_OF_MEMORY); + + value = alcDefaultAllDevicesSpecifier; + if(Device) ALCdevice_DecRef(Device); + break; + + case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: + if(alstr_empty(alcCaptureDeviceList)) + ProbeCaptureDeviceList(); + + VerifyDevice(&Device); + + free(alcCaptureDefaultDeviceSpecifier); + alcCaptureDefaultDeviceSpecifier = strdup(alstr_get_cstr(alcCaptureDeviceList)); + if(!alcCaptureDefaultDeviceSpecifier) + alcSetError(Device, ALC_OUT_OF_MEMORY); + + value = alcCaptureDefaultDeviceSpecifier; + if(Device) ALCdevice_DecRef(Device); + break; + + case ALC_EXTENSIONS: + if(!VerifyDevice(&Device)) + value = alcNoDeviceExtList; + else + { + value = alcExtensionList; + ALCdevice_DecRef(Device); + } + break; + + case ALC_HRTF_SPECIFIER_SOFT: + if(!VerifyDevice(&Device)) + alcSetError(nullptr, ALC_INVALID_DEVICE); + else + { + almtx_lock(&Device->BackendLock); + value = ((Device->HrtfHandle && Device->HrtfName) ? Device->HrtfName : ""); + almtx_unlock(&Device->BackendLock); + ALCdevice_DecRef(Device); + } + break; + + default: + VerifyDevice(&Device); + alcSetError(Device, ALC_INVALID_ENUM); + if(Device) ALCdevice_DecRef(Device); + break; + } + + return value; +} + + +static inline ALCsizei NumAttrsForDevice(ALCdevice *device) +{ + if(device->Type == Capture) return 9; + if(device->Type != Loopback) return 29; + if(device->FmtChans == DevFmtAmbi3D) + return 35; + return 29; +} + +static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) +{ + ALCsizei i; + + if(size <= 0 || values == nullptr) + { + alcSetError(device, ALC_INVALID_VALUE); + return 0; + } + + if(!device) + { + switch(param) + { + case ALC_MAJOR_VERSION: + values[0] = alcMajorVersion; + return 1; + case ALC_MINOR_VERSION: + values[0] = alcMinorVersion; + return 1; + + case ALC_ATTRIBUTES_SIZE: + case ALC_ALL_ATTRIBUTES: + case ALC_FREQUENCY: + case ALC_REFRESH: + case ALC_SYNC: + case ALC_MONO_SOURCES: + case ALC_STEREO_SOURCES: + case ALC_CAPTURE_SAMPLES: + case ALC_FORMAT_CHANNELS_SOFT: + case ALC_FORMAT_TYPE_SOFT: + case ALC_AMBISONIC_LAYOUT_SOFT: + case ALC_AMBISONIC_SCALING_SOFT: + case ALC_AMBISONIC_ORDER_SOFT: + case ALC_MAX_AMBISONIC_ORDER_SOFT: + alcSetError(nullptr, ALC_INVALID_DEVICE); + return 0; + + default: + alcSetError(nullptr, ALC_INVALID_ENUM); + return 0; + } + return 0; + } + + if(device->Type == Capture) + { + switch(param) + { + case ALC_ATTRIBUTES_SIZE: + values[0] = NumAttrsForDevice(device); + return 1; + + case ALC_ALL_ATTRIBUTES: + if(size < NumAttrsForDevice(device)) + { + alcSetError(device, ALC_INVALID_VALUE); + return 0; + } + + i = 0; + almtx_lock(&device->BackendLock); + values[i++] = ALC_MAJOR_VERSION; + values[i++] = alcMajorVersion; + values[i++] = ALC_MINOR_VERSION; + values[i++] = alcMinorVersion; + values[i++] = ALC_CAPTURE_SAMPLES; + values[i++] = V0(device->Backend,availableSamples)(); + values[i++] = ALC_CONNECTED; + values[i++] = ATOMIC_LOAD(&device->Connected, almemory_order_relaxed); + almtx_unlock(&device->BackendLock); + + values[i++] = 0; + return i; + + case ALC_MAJOR_VERSION: + values[0] = alcMajorVersion; + return 1; + case ALC_MINOR_VERSION: + values[0] = alcMinorVersion; + return 1; + + case ALC_CAPTURE_SAMPLES: + almtx_lock(&device->BackendLock); + values[0] = V0(device->Backend,availableSamples)(); + almtx_unlock(&device->BackendLock); + return 1; + + case ALC_CONNECTED: + values[0] = ATOMIC_LOAD(&device->Connected, almemory_order_acquire); + return 1; + + default: + alcSetError(device, ALC_INVALID_ENUM); + return 0; + } + return 0; + } + + /* render device */ + switch(param) + { + case ALC_ATTRIBUTES_SIZE: + values[0] = NumAttrsForDevice(device); + return 1; + + case ALC_ALL_ATTRIBUTES: + if(size < NumAttrsForDevice(device)) + { + alcSetError(device, ALC_INVALID_VALUE); + return 0; + } + + i = 0; + almtx_lock(&device->BackendLock); + values[i++] = ALC_MAJOR_VERSION; + values[i++] = alcMajorVersion; + values[i++] = ALC_MINOR_VERSION; + values[i++] = alcMinorVersion; + values[i++] = ALC_EFX_MAJOR_VERSION; + values[i++] = alcEFXMajorVersion; + values[i++] = ALC_EFX_MINOR_VERSION; + values[i++] = alcEFXMinorVersion; + + values[i++] = ALC_FREQUENCY; + values[i++] = device->Frequency; + if(device->Type != Loopback) + { + values[i++] = ALC_REFRESH; + values[i++] = device->Frequency / device->UpdateSize; + + values[i++] = ALC_SYNC; + values[i++] = ALC_FALSE; + } + else + { + if(device->FmtChans == DevFmtAmbi3D) + { + values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; + values[i++] = device->AmbiLayout; + + values[i++] = ALC_AMBISONIC_SCALING_SOFT; + values[i++] = device->AmbiScale; + + values[i++] = ALC_AMBISONIC_ORDER_SOFT; + values[i++] = device->AmbiOrder; + } + + values[i++] = ALC_FORMAT_CHANNELS_SOFT; + values[i++] = device->FmtChans; + + values[i++] = ALC_FORMAT_TYPE_SOFT; + values[i++] = device->FmtType; + } + + values[i++] = ALC_MONO_SOURCES; + values[i++] = device->NumMonoSources; + + values[i++] = ALC_STEREO_SOURCES; + values[i++] = device->NumStereoSources; + + values[i++] = ALC_MAX_AUXILIARY_SENDS; + values[i++] = device->NumAuxSends; + + values[i++] = ALC_HRTF_SOFT; + values[i++] = (device->HrtfHandle ? ALC_TRUE : ALC_FALSE); + + values[i++] = ALC_HRTF_STATUS_SOFT; + values[i++] = device->HrtfStatus; + + values[i++] = ALC_OUTPUT_LIMITER_SOFT; + values[i++] = device->Limiter ? ALC_TRUE : ALC_FALSE; + + values[i++] = ALC_MAX_AMBISONIC_ORDER_SOFT; + values[i++] = MAX_AMBI_ORDER; + almtx_unlock(&device->BackendLock); + + values[i++] = 0; + return i; + + case ALC_MAJOR_VERSION: + values[0] = alcMajorVersion; + return 1; + + case ALC_MINOR_VERSION: + values[0] = alcMinorVersion; + return 1; + + case ALC_EFX_MAJOR_VERSION: + values[0] = alcEFXMajorVersion; + return 1; + + case ALC_EFX_MINOR_VERSION: + values[0] = alcEFXMinorVersion; + return 1; + + case ALC_FREQUENCY: + values[0] = device->Frequency; + return 1; + + case ALC_REFRESH: + if(device->Type == Loopback) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + almtx_lock(&device->BackendLock); + values[0] = device->Frequency / device->UpdateSize; + almtx_unlock(&device->BackendLock); + return 1; + + case ALC_SYNC: + if(device->Type == Loopback) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = ALC_FALSE; + return 1; + + case ALC_FORMAT_CHANNELS_SOFT: + if(device->Type != Loopback) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = device->FmtChans; + return 1; + + case ALC_FORMAT_TYPE_SOFT: + if(device->Type != Loopback) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = device->FmtType; + return 1; + + case ALC_AMBISONIC_LAYOUT_SOFT: + if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = device->AmbiLayout; + return 1; + + case ALC_AMBISONIC_SCALING_SOFT: + if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = device->AmbiScale; + return 1; + + case ALC_AMBISONIC_ORDER_SOFT: + if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = device->AmbiOrder; + return 1; + + case ALC_MONO_SOURCES: + values[0] = device->NumMonoSources; + return 1; + + case ALC_STEREO_SOURCES: + values[0] = device->NumStereoSources; + return 1; + + case ALC_MAX_AUXILIARY_SENDS: + values[0] = device->NumAuxSends; + return 1; + + case ALC_CONNECTED: + values[0] = ATOMIC_LOAD(&device->Connected, almemory_order_acquire); + return 1; + + case ALC_HRTF_SOFT: + values[0] = (device->HrtfHandle ? ALC_TRUE : ALC_FALSE); + return 1; + + case ALC_HRTF_STATUS_SOFT: + values[0] = device->HrtfStatus; + return 1; + + case ALC_NUM_HRTF_SPECIFIERS_SOFT: + almtx_lock(&device->BackendLock); + FreeHrtfList(&device->HrtfList); + device->HrtfList = EnumerateHrtf(device->DeviceName); + values[0] = (ALCint)VECTOR_SIZE(device->HrtfList); + almtx_unlock(&device->BackendLock); + return 1; + + case ALC_OUTPUT_LIMITER_SOFT: + values[0] = device->Limiter ? ALC_TRUE : ALC_FALSE; + return 1; + + case ALC_MAX_AMBISONIC_ORDER_SOFT: + values[0] = MAX_AMBI_ORDER; + return 1; + + default: + alcSetError(device, ALC_INVALID_ENUM); + return 0; + } + return 0; +} + +/* alcGetIntegerv + * + * Returns information about the device and the version of OpenAL + */ +ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) +{ + VerifyDevice(&device); + if(size <= 0 || values == nullptr) + alcSetError(device, ALC_INVALID_VALUE); + else + GetIntegerv(device, param, size, values); + if(device) ALCdevice_DecRef(device); +} + +ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALCsizei size, ALCint64SOFT *values) +{ + ALsizei i; + + VerifyDevice(&device); + if(size <= 0 || values == nullptr) + alcSetError(device, ALC_INVALID_VALUE); + else if(!device || device->Type == Capture) + { + std::vector ivals(size); + size = GetIntegerv(device, pname, size, ivals.data()); + for(i = 0;i < size;i++) + values[i] = ivals[i]; + } + else /* render device */ + { + ClockLatency clock; + ALuint64 basecount; + ALuint samplecount; + ALuint refcount; + + switch(pname) + { + case ALC_ATTRIBUTES_SIZE: + *values = NumAttrsForDevice(device)+4; + break; + + case ALC_ALL_ATTRIBUTES: + if(size < NumAttrsForDevice(device)+4) + alcSetError(device, ALC_INVALID_VALUE); + else + { + i = 0; + almtx_lock(&device->BackendLock); + values[i++] = ALC_FREQUENCY; + values[i++] = device->Frequency; + + if(device->Type != Loopback) + { + values[i++] = ALC_REFRESH; + values[i++] = device->Frequency / device->UpdateSize; + + values[i++] = ALC_SYNC; + values[i++] = ALC_FALSE; + } + else + { + if(device->FmtChans == DevFmtAmbi3D) + { + values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; + values[i++] = device->AmbiLayout; + + values[i++] = ALC_AMBISONIC_SCALING_SOFT; + values[i++] = device->AmbiScale; + + values[i++] = ALC_AMBISONIC_ORDER_SOFT; + values[i++] = device->AmbiOrder; + } + + values[i++] = ALC_FORMAT_CHANNELS_SOFT; + values[i++] = device->FmtChans; + + values[i++] = ALC_FORMAT_TYPE_SOFT; + values[i++] = device->FmtType; + } + + values[i++] = ALC_MONO_SOURCES; + values[i++] = device->NumMonoSources; + + values[i++] = ALC_STEREO_SOURCES; + values[i++] = device->NumStereoSources; + + values[i++] = ALC_MAX_AUXILIARY_SENDS; + values[i++] = device->NumAuxSends; + + values[i++] = ALC_HRTF_SOFT; + values[i++] = (device->HrtfHandle ? ALC_TRUE : ALC_FALSE); + + values[i++] = ALC_HRTF_STATUS_SOFT; + values[i++] = device->HrtfStatus; + + values[i++] = ALC_OUTPUT_LIMITER_SOFT; + values[i++] = device->Limiter ? ALC_TRUE : ALC_FALSE; + + clock = GetClockLatency(device); + values[i++] = ALC_DEVICE_CLOCK_SOFT; + values[i++] = clock.ClockTime; + + values[i++] = ALC_DEVICE_LATENCY_SOFT; + values[i++] = clock.Latency; + almtx_unlock(&device->BackendLock); + + values[i++] = 0; + } + break; + + case ALC_DEVICE_CLOCK_SOFT: + almtx_lock(&device->BackendLock); + do { + while(((refcount=ReadRef(&device->MixCount))&1) != 0) + althrd_yield(); + basecount = device->ClockBase; + samplecount = device->SamplesDone; + } while(refcount != ReadRef(&device->MixCount)); + *values = basecount + (samplecount*DEVICE_CLOCK_RES/device->Frequency); + almtx_unlock(&device->BackendLock); + break; + + case ALC_DEVICE_LATENCY_SOFT: + almtx_lock(&device->BackendLock); + clock = GetClockLatency(device); + almtx_unlock(&device->BackendLock); + *values = clock.Latency; + break; + + case ALC_DEVICE_CLOCK_LATENCY_SOFT: + if(size < 2) + alcSetError(device, ALC_INVALID_VALUE); + else + { + almtx_lock(&device->BackendLock); + clock = GetClockLatency(device); + almtx_unlock(&device->BackendLock); + values[0] = clock.ClockTime; + values[1] = clock.Latency; + } + break; + + default: + std::vector ivals(size); + size = GetIntegerv(device, pname, size, ivals.data()); + for(i = 0;i < size;i++) + values[i] = ivals[i]; + break; + } + } + if(device) + ALCdevice_DecRef(device); +} + + +/* alcIsExtensionPresent + * + * Determines if there is support for a particular extension + */ +ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extName) +{ + ALCboolean bResult = ALC_FALSE; + + VerifyDevice(&device); + + if(!extName) + alcSetError(device, ALC_INVALID_VALUE); + else + { + size_t len = strlen(extName); + const char *ptr = (device ? alcExtensionList : alcNoDeviceExtList); + while(ptr && *ptr) + { + if(strncasecmp(ptr, extName, len) == 0 && + (ptr[len] == '\0' || isspace(ptr[len]))) + { + bResult = ALC_TRUE; + break; + } + if((ptr=strchr(ptr, ' ')) != nullptr) + { + do { + ++ptr; + } while(isspace(*ptr)); + } + } + } + if(device) + ALCdevice_DecRef(device); + return bResult; +} + + +/* alcGetProcAddress + * + * Retrieves the function address for a particular extension function + */ +ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcName) +{ + ALCvoid *ptr = nullptr; + + if(!funcName) + { + VerifyDevice(&device); + alcSetError(device, ALC_INVALID_VALUE); + if(device) ALCdevice_DecRef(device); + } + else + { + size_t i = 0; + for(i = 0;i < COUNTOF(alcFunctions);i++) + { + if(strcmp(alcFunctions[i].funcName, funcName) == 0) + { + ptr = alcFunctions[i].address; + break; + } + } + } + + return ptr; +} + + +/* alcGetEnumValue + * + * Get the value for a particular ALC enumeration name + */ +ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumName) +{ + ALCenum val = 0; + + if(!enumName) + { + VerifyDevice(&device); + alcSetError(device, ALC_INVALID_VALUE); + if(device) ALCdevice_DecRef(device); + } + else + { + size_t i = 0; + for(i = 0;i < COUNTOF(alcEnumerations);i++) + { + if(strcmp(alcEnumerations[i].enumName, enumName) == 0) + { + val = alcEnumerations[i].value; + break; + } + } + } + + return val; +} + + +/* alcCreateContext + * + * Create and attach a context to the given device. + */ +ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrList) +{ + ALCcontext *ALContext; + ALfloat valf; + ALCenum err; + + /* Explicitly hold the list lock while taking the BackendLock in case the + * device is asynchronously destropyed, to ensure this new context is + * properly cleaned up after being made. + */ + LockLists(); + if(!VerifyDevice(&device) || device->Type == Capture || + !ATOMIC_LOAD(&device->Connected, almemory_order_relaxed)) + { + UnlockLists(); + alcSetError(device, ALC_INVALID_DEVICE); + if(device) ALCdevice_DecRef(device); + return nullptr; + } + almtx_lock(&device->BackendLock); + UnlockLists(); + + ATOMIC_STORE_SEQ(&device->LastError, ALC_NO_ERROR); + + if(device->Type == Playback && DefaultEffect.type != AL_EFFECT_NULL) + ALContext = static_cast(al_calloc(16, + sizeof(ALCcontext)+sizeof(ALlistener)+sizeof(ALeffectslot))); + else + ALContext = static_cast(al_calloc(16, sizeof(ALCcontext)+sizeof(ALlistener))); + if(!ALContext) + { + almtx_unlock(&device->BackendLock); + + alcSetError(device, ALC_OUT_OF_MEMORY); + ALCdevice_DecRef(device); + return nullptr; + } + + InitRef(&ALContext->ref, 1); + ALContext->Listener = (ALlistener*)ALContext->_listener_mem; + ALContext->DefaultSlot = nullptr; + + ALContext->Voices = nullptr; + ALContext->VoiceCount = 0; + ALContext->MaxVoices = 0; + ATOMIC_INIT(&ALContext->ActiveAuxSlots, static_cast(nullptr)); + ALContext->Device = device; + ATOMIC_INIT(&ALContext->next, static_cast(nullptr)); + + if((err=UpdateDeviceParams(device, attrList)) != ALC_NO_ERROR) + { + almtx_unlock(&device->BackendLock); + + al_free(ALContext); + ALContext = nullptr; + + alcSetError(device, err); + if(err == ALC_INVALID_DEVICE) + { + V0(device->Backend,lock)(); + aluHandleDisconnect(device, "Device update failure"); + V0(device->Backend,unlock)(); + } + ALCdevice_DecRef(device); + return nullptr; + } + AllocateVoices(ALContext, 256, device->NumAuxSends); + + if(DefaultEffect.type != AL_EFFECT_NULL && device->Type == Playback) + { + ALContext->DefaultSlot = (ALeffectslot*)(ALContext->_listener_mem + sizeof(ALlistener)); + if(InitEffectSlot(ALContext->DefaultSlot) == AL_NO_ERROR) + aluInitEffectPanning(ALContext->DefaultSlot); + else + { + ALContext->DefaultSlot = nullptr; + ERR("Failed to initialize the default effect slot\n"); + } + } + + ALCdevice_IncRef(ALContext->Device); + InitContext(ALContext); + + if(ConfigValueFloat(alstr_get_cstr(device->DeviceName), nullptr, "volume-adjust", &valf)) + { + if(!isfinite(valf)) + ERR("volume-adjust must be finite: %f\n", valf); + else + { + ALfloat db = clampf(valf, -24.0f, 24.0f); + if(db != valf) + WARN("volume-adjust clamped: %f, range: +/-%f\n", valf, 24.0f); + ALContext->GainBoost = powf(10.0f, db/20.0f); + TRACE("volume-adjust gain: %f\n", ALContext->GainBoost); + } + } + UpdateListenerProps(ALContext); + + { + ALCcontext *head = ATOMIC_LOAD_SEQ(&device->ContextList); + do { + ATOMIC_STORE(&ALContext->next, head, almemory_order_relaxed); + } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK_SEQ(&device->ContextList, &head, + ALContext) == 0); + } + almtx_unlock(&device->BackendLock); + + if(ALContext->DefaultSlot) + { + if(InitializeEffect(ALContext, ALContext->DefaultSlot, &DefaultEffect) == AL_NO_ERROR) + UpdateEffectSlotProps(ALContext->DefaultSlot, ALContext); + else + ERR("Failed to initialize the default effect\n"); + } + + ALCdevice_DecRef(device); + + TRACE("Created context %p\n", ALContext); + return ALContext; +} + +/* alcDestroyContext + * + * Remove a context from its device + */ +ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) +{ + ALCdevice *Device; + + LockLists(); + if(!VerifyContext(&context)) + { + UnlockLists(); + alcSetError(nullptr, ALC_INVALID_CONTEXT); + return; + } + + Device = context->Device; + if(Device) + { + almtx_lock(&Device->BackendLock); + if(!ReleaseContext(context, Device)) + { + V0(Device->Backend,stop)(); + Device->Flags &= ~DEVICE_RUNNING; + } + almtx_unlock(&Device->BackendLock); + } + UnlockLists(); + + ALCcontext_DecRef(context); +} + + +/* alcGetCurrentContext + * + * Returns the currently active context on the calling thread + */ +ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) +{ + ALCcontext *Context{static_cast(altss_get(LocalContext))}; + if(!Context) Context = ATOMIC_LOAD_SEQ(&GlobalContext); + return Context; +} + +/* alcGetThreadContext + * + * Returns the currently active thread-local context + */ +ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) +{ + return static_cast(altss_get(LocalContext)); +} + + +/* alcMakeContextCurrent + * + * Makes the given context the active process-wide context, and removes the + * thread-local context for the calling thread. + */ +ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) +{ + /* context must be valid or nullptr */ + if(context && !VerifyContext(&context)) + { + alcSetError(nullptr, ALC_INVALID_CONTEXT); + return ALC_FALSE; + } + /* context's reference count is already incremented */ + context = ATOMIC_EXCHANGE_PTR_SEQ(&GlobalContext, context); + if(context) ALCcontext_DecRef(context); + + if((context=static_cast(altss_get(LocalContext))) != nullptr) + { + altss_set(LocalContext, nullptr); + ALCcontext_DecRef(context); + } + + return ALC_TRUE; +} + +/* alcSetThreadContext + * + * Makes the given context the active context for the current thread + */ +ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) +{ + /* context must be valid or nullptr */ + if(context && !VerifyContext(&context)) + { + alcSetError(nullptr, ALC_INVALID_CONTEXT); + return ALC_FALSE; + } + /* context's reference count is already incremented */ + ALCcontext *old{static_cast(altss_get(LocalContext))}; + altss_set(LocalContext, context); + if(old) ALCcontext_DecRef(old); + + return ALC_TRUE; +} + + +/* alcGetContextsDevice + * + * Returns the device that a particular context is attached to + */ +ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *Context) +{ + if(!VerifyContext(&Context)) + { + alcSetError(nullptr, ALC_INVALID_CONTEXT); + return nullptr; + } + ALCdevice *Device{Context->Device}; + ALCcontext_DecRef(Context); + + return Device; +} + + +/* alcOpenDevice + * + * Opens the named device. + */ +ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) +{ + ALCbackendFactory *factory; + const ALCchar *fmt; + ALCdevice *device; + ALCenum err; + + DO_INITCONFIG(); + + if(!PlaybackBackend.name) + { + alcSetError(nullptr, ALC_INVALID_VALUE); + return nullptr; + } + + if(deviceName && (!deviceName[0] || strcasecmp(deviceName, alcDefaultName) == 0 || strcasecmp(deviceName, "openal-soft") == 0 +#ifdef _WIN32 + /* Some old Windows apps hardcode these expecting OpenAL to use a + * specific audio API, even when they're not enumerated. Creative's + * router effectively ignores them too. + */ + || strcasecmp(deviceName, "DirectSound3D") == 0 || strcasecmp(deviceName, "DirectSound") == 0 + || strcasecmp(deviceName, "MMSYSTEM") == 0 +#endif + )) + deviceName = nullptr; + + device = static_cast(al_calloc(16, sizeof(ALCdevice))); + if(!device) + { + alcSetError(nullptr, ALC_OUT_OF_MEMORY); + return nullptr; + } + + //Validate device + InitDevice(device, Playback); + + //Set output format + device->FmtChans = DevFmtChannelsDefault; + device->FmtType = DevFmtTypeDefault; + device->Frequency = DEFAULT_OUTPUT_RATE; + device->IsHeadphones = AL_FALSE; + device->AmbiLayout = AmbiLayout_Default; + device->AmbiScale = AmbiNorm_Default; + device->LimiterState = ALC_TRUE; + device->NumUpdates = 3; + device->UpdateSize = 1024; + + device->SourcesMax = 256; + device->AuxiliaryEffectSlotMax = 64; + device->NumAuxSends = DEFAULT_SENDS; + + if(ConfigValueStr(deviceName, nullptr, "channels", &fmt)) + { + static const struct { + const char name[16]; + enum DevFmtChannels chans; + ALsizei order; + } chanlist[] = { + { "mono", DevFmtMono, 0 }, + { "stereo", DevFmtStereo, 0 }, + { "quad", DevFmtQuad, 0 }, + { "surround51", DevFmtX51, 0 }, + { "surround61", DevFmtX61, 0 }, + { "surround71", DevFmtX71, 0 }, + { "surround51rear", DevFmtX51Rear, 0 }, + { "ambi1", DevFmtAmbi3D, 1 }, + { "ambi2", DevFmtAmbi3D, 2 }, + { "ambi3", DevFmtAmbi3D, 3 }, + }; + size_t i; + + for(i = 0;i < COUNTOF(chanlist);i++) + { + if(strcasecmp(chanlist[i].name, fmt) == 0) + { + device->FmtChans = chanlist[i].chans; + device->AmbiOrder = chanlist[i].order; + device->Flags |= DEVICE_CHANNELS_REQUEST; + break; + } + } + if(i == COUNTOF(chanlist)) + ERR("Unsupported channels: %s\n", fmt); + } + if(ConfigValueStr(deviceName, nullptr, "sample-type", &fmt)) + { + static const struct { + const char name[16]; + enum DevFmtType type; + } typelist[] = { + { "int8", DevFmtByte }, + { "uint8", DevFmtUByte }, + { "int16", DevFmtShort }, + { "uint16", DevFmtUShort }, + { "int32", DevFmtInt }, + { "uint32", DevFmtUInt }, + { "float32", DevFmtFloat }, + }; + size_t i; + + for(i = 0;i < COUNTOF(typelist);i++) + { + if(strcasecmp(typelist[i].name, fmt) == 0) + { + device->FmtType = typelist[i].type; + device->Flags |= DEVICE_SAMPLE_TYPE_REQUEST; + break; + } + } + if(i == COUNTOF(typelist)) + ERR("Unsupported sample-type: %s\n", fmt); + } + + if(ConfigValueUInt(deviceName, nullptr, "frequency", &device->Frequency)) + { + device->Flags |= DEVICE_FREQUENCY_REQUEST; + if(device->Frequency < MIN_OUTPUT_RATE) + ERR("%uhz request clamped to %uhz minimum\n", device->Frequency, MIN_OUTPUT_RATE); + device->Frequency = maxu(device->Frequency, MIN_OUTPUT_RATE); + } + + ConfigValueUInt(deviceName, nullptr, "periods", &device->NumUpdates); + device->NumUpdates = clampu(device->NumUpdates, 2, 16); + + ConfigValueUInt(deviceName, nullptr, "period_size", &device->UpdateSize); + device->UpdateSize = clampu(device->UpdateSize, 64, 8192); + if((CPUCapFlags&(CPU_CAP_SSE|CPU_CAP_NEON)) != 0) + device->UpdateSize = (device->UpdateSize+3)&~3; + + ConfigValueUInt(deviceName, nullptr, "sources", &device->SourcesMax); + if(device->SourcesMax == 0) device->SourcesMax = 256; + + ConfigValueUInt(deviceName, nullptr, "slots", &device->AuxiliaryEffectSlotMax); + if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 64; + else device->AuxiliaryEffectSlotMax = minu(device->AuxiliaryEffectSlotMax, INT_MAX); + + if(ConfigValueInt(deviceName, nullptr, "sends", &device->NumAuxSends)) + device->NumAuxSends = clampi( + DEFAULT_SENDS, 0, clampi(device->NumAuxSends, 0, MAX_SENDS) + ); + + device->NumStereoSources = 1; + device->NumMonoSources = device->SourcesMax - device->NumStereoSources; + + factory = PlaybackBackend.getFactory(); + device->Backend = V(factory,createBackend)(device, ALCbackend_Playback); + if(!device->Backend) + { + FreeDevice(device); + alcSetError(nullptr, ALC_OUT_OF_MEMORY); + return nullptr; + } + + // Find a playback device to open + if((err=V(device->Backend,open)(deviceName)) != ALC_NO_ERROR) + { + FreeDevice(device); + alcSetError(nullptr, err); + return nullptr; + } + + if(ConfigValueStr(alstr_get_cstr(device->DeviceName), nullptr, "ambi-format", &fmt)) + { + if(strcasecmp(fmt, "fuma") == 0) + { + device->AmbiLayout = AmbiLayout_FuMa; + device->AmbiScale = AmbiNorm_FuMa; + } + else if(strcasecmp(fmt, "acn+sn3d") == 0) + { + device->AmbiLayout = AmbiLayout_ACN; + device->AmbiScale = AmbiNorm_SN3D; + } + else if(strcasecmp(fmt, "acn+n3d") == 0) + { + device->AmbiLayout = AmbiLayout_ACN; + device->AmbiScale = AmbiNorm_N3D; + } + else + ERR("Unsupported ambi-format: %s\n", fmt); + } + + { + ALCdevice *head{DeviceList.load()}; + do { + ATOMIC_STORE(&device->next, head, almemory_order_relaxed); + } while(!DeviceList.compare_exchange_weak(head, device)); + } + + TRACE("Created device %p, \"%s\"\n", device, alstr_get_cstr(device->DeviceName)); + return device; +} + +/* alcCloseDevice + * + * Closes the given device. + */ +ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) +{ + LockLists(); + ALCdevice *iter{DeviceList.load()}; + do { + if(iter == device) + break; + iter = ATOMIC_LOAD(&iter->next, almemory_order_relaxed); + } while(iter != nullptr); + if(!iter || iter->Type == Capture) + { + alcSetError(iter, ALC_INVALID_DEVICE); + UnlockLists(); + return ALC_FALSE; + } + almtx_lock(&device->BackendLock); + + ALCdevice *origdev{device}; + ALCdevice *nextdev{ATOMIC_LOAD(&device->next, almemory_order_relaxed)}; + if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&DeviceList, &origdev, nextdev)) + { + ALCdevice *list; + do { + list = origdev; + origdev = device; + } while(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&list->next, &origdev, nextdev)); + } + UnlockLists(); + + ALCcontext *ctx{ATOMIC_LOAD_SEQ(&device->ContextList)}; + while(ctx != nullptr) + { + ALCcontext *next = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed); + WARN("Releasing context %p\n", ctx); + ReleaseContext(ctx, device); + ctx = next; + } + if((device->Flags&DEVICE_RUNNING)) + V0(device->Backend,stop)(); + device->Flags &= ~DEVICE_RUNNING; + almtx_unlock(&device->BackendLock); + + ALCdevice_DecRef(device); + + return ALC_TRUE; +} + + +/************************************************ + * ALC capture functions + ************************************************/ +ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei samples) +{ + ALCbackendFactory *factory; + ALCdevice *device = nullptr; + ALCenum err; + + DO_INITCONFIG(); + + if(!CaptureBackend.name) + { + alcSetError(nullptr, ALC_INVALID_VALUE); + return nullptr; + } + + if(samples <= 0) + { + alcSetError(nullptr, ALC_INVALID_VALUE); + return nullptr; + } + + if(deviceName && (!deviceName[0] || strcasecmp(deviceName, alcDefaultName) == 0 || strcasecmp(deviceName, "openal-soft") == 0)) + deviceName = nullptr; + + device = static_cast(al_calloc(16, sizeof(ALCdevice))); + if(!device) + { + alcSetError(nullptr, ALC_OUT_OF_MEMORY); + return nullptr; + } + + //Validate device + InitDevice(device, Capture); + + device->Frequency = frequency; + device->Flags |= DEVICE_FREQUENCY_REQUEST; + + if(DecomposeDevFormat(format, &device->FmtChans, &device->FmtType) == AL_FALSE) + { + FreeDevice(device); + alcSetError(nullptr, ALC_INVALID_ENUM); + return nullptr; + } + device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_SAMPLE_TYPE_REQUEST; + device->IsHeadphones = AL_FALSE; + device->AmbiOrder = 0; + device->AmbiLayout = AmbiLayout_Default; + device->AmbiScale = AmbiNorm_Default; + + device->UpdateSize = samples; + device->NumUpdates = 1; + + factory = CaptureBackend.getFactory(); + device->Backend = V(factory,createBackend)(device, ALCbackend_Capture); + if(!device->Backend) + { + FreeDevice(device); + alcSetError(nullptr, ALC_OUT_OF_MEMORY); + return nullptr; + } + + TRACE("Capture format: %s, %s, %uhz, %u update size x%d\n", + DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), + device->Frequency, device->UpdateSize, device->NumUpdates + ); + if((err=V(device->Backend,open)(deviceName)) != ALC_NO_ERROR) + { + FreeDevice(device); + alcSetError(nullptr, err); + return nullptr; + } + + { + ALCdevice *head{DeviceList.load()}; + do { + ATOMIC_STORE(&device->next, head, almemory_order_relaxed); + } while(!DeviceList.compare_exchange_weak(head, device)); + } + + TRACE("Created device %p, \"%s\"\n", device, alstr_get_cstr(device->DeviceName)); + return device; +} + +ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) +{ + + LockLists(); + ALCdevice *iter{DeviceList.load()}; + do { + if(iter == device) + break; + iter = ATOMIC_LOAD(&iter->next, almemory_order_relaxed); + } while(iter != nullptr); + if(!iter || iter->Type != Capture) + { + alcSetError(iter, ALC_INVALID_DEVICE); + UnlockLists(); + return ALC_FALSE; + } + + ALCdevice *origdev{device}; + ALCdevice *nextdev{ATOMIC_LOAD(&device->next, almemory_order_relaxed)}; + if(!DeviceList.compare_exchange_strong(origdev, nextdev)) + { + ALCdevice *list; + do { + list = origdev; + origdev = device; + } while(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&list->next, &origdev, nextdev)); + } + UnlockLists(); + + almtx_lock(&device->BackendLock); + if((device->Flags&DEVICE_RUNNING)) + V0(device->Backend,stop)(); + device->Flags &= ~DEVICE_RUNNING; + almtx_unlock(&device->BackendLock); + + ALCdevice_DecRef(device); + + return ALC_TRUE; +} + +ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) +{ + if(!VerifyDevice(&device) || device->Type != Capture) + alcSetError(device, ALC_INVALID_DEVICE); + else + { + almtx_lock(&device->BackendLock); + if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + alcSetError(device, ALC_INVALID_DEVICE); + else if(!(device->Flags&DEVICE_RUNNING)) + { + if(V0(device->Backend,start)()) + device->Flags |= DEVICE_RUNNING; + else + { + aluHandleDisconnect(device, "Device start failure"); + alcSetError(device, ALC_INVALID_DEVICE); + } + } + almtx_unlock(&device->BackendLock); + } + + if(device) ALCdevice_DecRef(device); +} + +ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) +{ + if(!VerifyDevice(&device) || device->Type != Capture) + alcSetError(device, ALC_INVALID_DEVICE); + else + { + almtx_lock(&device->BackendLock); + if((device->Flags&DEVICE_RUNNING)) + V0(device->Backend,stop)(); + device->Flags &= ~DEVICE_RUNNING; + almtx_unlock(&device->BackendLock); + } + + if(device) ALCdevice_DecRef(device); +} + +ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) +{ + if(!VerifyDevice(&device) || device->Type != Capture) + alcSetError(device, ALC_INVALID_DEVICE); + else + { + ALCenum err = ALC_INVALID_VALUE; + + almtx_lock(&device->BackendLock); + if(samples >= 0 && V0(device->Backend,availableSamples)() >= (ALCuint)samples) + err = V(device->Backend,captureSamples)(buffer, samples); + almtx_unlock(&device->BackendLock); + + if(err != ALC_NO_ERROR) + alcSetError(device, err); + } + if(device) ALCdevice_DecRef(device); +} + + +/************************************************ + * ALC loopback functions + ************************************************/ + +/* alcLoopbackOpenDeviceSOFT + * + * Open a loopback device, for manual rendering. + */ +ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName) +{ + ALCbackendFactory *factory; + ALCdevice *device; + + DO_INITCONFIG(); + + /* Make sure the device name, if specified, is us. */ + if(deviceName && strcmp(deviceName, alcDefaultName) != 0) + { + alcSetError(nullptr, ALC_INVALID_VALUE); + return nullptr; + } + + device = static_cast(al_calloc(16, sizeof(ALCdevice))); + if(!device) + { + alcSetError(nullptr, ALC_OUT_OF_MEMORY); + return nullptr; + } + + //Validate device + InitDevice(device, Loopback); + + device->SourcesMax = 256; + device->AuxiliaryEffectSlotMax = 64; + device->NumAuxSends = DEFAULT_SENDS; + + //Set output format + device->NumUpdates = 0; + device->UpdateSize = 0; + + device->Frequency = DEFAULT_OUTPUT_RATE; + device->FmtChans = DevFmtChannelsDefault; + device->FmtType = DevFmtTypeDefault; + device->IsHeadphones = AL_FALSE; + device->AmbiLayout = AmbiLayout_Default; + device->AmbiScale = AmbiNorm_Default; + + ConfigValueUInt(nullptr, nullptr, "sources", &device->SourcesMax); + if(device->SourcesMax == 0) device->SourcesMax = 256; + + ConfigValueUInt(nullptr, nullptr, "slots", &device->AuxiliaryEffectSlotMax); + if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 64; + else device->AuxiliaryEffectSlotMax = minu(device->AuxiliaryEffectSlotMax, INT_MAX); + + if(ConfigValueInt(nullptr, nullptr, "sends", &device->NumAuxSends)) + device->NumAuxSends = clampi( + DEFAULT_SENDS, 0, clampi(device->NumAuxSends, 0, MAX_SENDS) + ); + + device->NumStereoSources = 1; + device->NumMonoSources = device->SourcesMax - device->NumStereoSources; + + factory = ALCloopbackFactory_getFactory(); + device->Backend = V(factory,createBackend)(device, ALCbackend_Loopback); + if(!device->Backend) + { + al_free(device); + alcSetError(nullptr, ALC_OUT_OF_MEMORY); + return nullptr; + } + + // Open the "backend" + V(device->Backend,open)("Loopback"); + + { + ALCdevice *head{DeviceList.load()}; + do { + ATOMIC_STORE(&device->next, head, almemory_order_relaxed); + } while(!DeviceList.compare_exchange_weak(head, device)); + } + + TRACE("Created device %p\n", device); + return device; +} + +/* alcIsRenderFormatSupportedSOFT + * + * Determines if the loopback device supports the given format for rendering. + */ +ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type) +{ + ALCboolean ret = ALC_FALSE; + + if(!VerifyDevice(&device) || device->Type != Loopback) + alcSetError(device, ALC_INVALID_DEVICE); + else if(freq <= 0) + alcSetError(device, ALC_INVALID_VALUE); + else + { + if(IsValidALCType(type) && IsValidALCChannels(channels) && freq >= MIN_OUTPUT_RATE) + ret = ALC_TRUE; + } + if(device) ALCdevice_DecRef(device); + + return ret; +} + +/* alcRenderSamplesSOFT + * + * Renders some samples into a buffer, using the format last set by the + * attributes given to alcCreateContext. + */ +FORCE_ALIGN ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) +{ + if(!VerifyDevice(&device) || device->Type != Loopback) + alcSetError(device, ALC_INVALID_DEVICE); + else if(samples < 0 || (samples > 0 && buffer == nullptr)) + alcSetError(device, ALC_INVALID_VALUE); + else + { + V0(device->Backend,lock)(); + aluMixData(device, buffer, samples); + V0(device->Backend,unlock)(); + } + if(device) ALCdevice_DecRef(device); +} + + +/************************************************ + * ALC DSP pause/resume functions + ************************************************/ + +/* alcDevicePauseSOFT + * + * Pause the DSP to stop audio processing. + */ +ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device) +{ + if(!VerifyDevice(&device) || device->Type != Playback) + alcSetError(device, ALC_INVALID_DEVICE); + else + { + almtx_lock(&device->BackendLock); + if((device->Flags&DEVICE_RUNNING)) + V0(device->Backend,stop)(); + device->Flags &= ~DEVICE_RUNNING; + device->Flags |= DEVICE_PAUSED; + almtx_unlock(&device->BackendLock); + } + if(device) ALCdevice_DecRef(device); +} + +/* alcDeviceResumeSOFT + * + * Resume the DSP to restart audio processing. + */ +ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) +{ + if(!VerifyDevice(&device) || device->Type != Playback) + alcSetError(device, ALC_INVALID_DEVICE); + else + { + almtx_lock(&device->BackendLock); + if((device->Flags&DEVICE_PAUSED)) + { + device->Flags &= ~DEVICE_PAUSED; + if(ATOMIC_LOAD_SEQ(&device->ContextList) != nullptr) + { + if(V0(device->Backend,start)() != ALC_FALSE) + device->Flags |= DEVICE_RUNNING; + else + { + V0(device->Backend,lock)(); + aluHandleDisconnect(device, "Device start failure"); + V0(device->Backend,unlock)(); + alcSetError(device, ALC_INVALID_DEVICE); + } + } + } + almtx_unlock(&device->BackendLock); + } + if(device) ALCdevice_DecRef(device); +} + + +/************************************************ + * ALC HRTF functions + ************************************************/ + +/* alcGetStringiSOFT + * + * Gets a string parameter at the given index. + */ +ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index) +{ + const ALCchar *str = nullptr; + + if(!VerifyDevice(&device) || device->Type == Capture) + alcSetError(device, ALC_INVALID_DEVICE); + else switch(paramName) + { + case ALC_HRTF_SPECIFIER_SOFT: + if(index >= 0 && (size_t)index < VECTOR_SIZE(device->HrtfList)) + str = VECTOR_ELEM(device->HrtfList, index).name; + else + alcSetError(device, ALC_INVALID_VALUE); + break; + + default: + alcSetError(device, ALC_INVALID_ENUM); + break; + } + if(device) ALCdevice_DecRef(device); + + return str; +} + +/* alcResetDeviceSOFT + * + * Resets the given device output, using the specified attribute list. + */ +ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs) +{ + ALCenum err; + + LockLists(); + if(!VerifyDevice(&device) || device->Type == Capture || + !ATOMIC_LOAD(&device->Connected, almemory_order_relaxed)) + { + UnlockLists(); + alcSetError(device, ALC_INVALID_DEVICE); + if(device) ALCdevice_DecRef(device); + return ALC_FALSE; + } + almtx_lock(&device->BackendLock); + UnlockLists(); + + err = UpdateDeviceParams(device, attribs); + almtx_unlock(&device->BackendLock); + + if(err != ALC_NO_ERROR) + { + alcSetError(device, err); + if(err == ALC_INVALID_DEVICE) + { + V0(device->Backend,lock)(); + aluHandleDisconnect(device, "Device start failure"); + V0(device->Backend,unlock)(); + } + ALCdevice_DecRef(device); + return ALC_FALSE; + } + ALCdevice_DecRef(device); + + return ALC_TRUE; +} diff --git a/Alc/filters/nfc.h b/Alc/filters/nfc.h index e02c00d8..d59280d0 100644 --- a/Alc/filters/nfc.h +++ b/Alc/filters/nfc.h @@ -1,6 +1,10 @@ #ifndef FILTER_NFC_H #define FILTER_NFC_H +#ifdef __cplusplus +extern "C" { +#endif + struct NfcFilter1 { float base_gain, gain; float b1, a1; @@ -46,4 +50,8 @@ void NfcFilterProcess2(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRIC /* Near-field control filter for third-order ambisonic channels (9-15). */ void NfcFilterProcess3(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRICT src, const int count); +#ifdef __cplusplus +} // extern "C" +#endif + #endif /* FILTER_NFC_H */ diff --git a/Alc/mastering.h b/Alc/mastering.h index 17f5e8be..7738a4aa 100644 --- a/Alc/mastering.h +++ b/Alc/mastering.h @@ -6,6 +6,10 @@ /* For BUFFERSIZE. */ #include "alMain.h" +#ifdef __cplusplus +extern "C" { +#endif + struct Compressor; /* The compressor is initialized with the following settings: @@ -46,4 +50,8 @@ void ApplyCompression(struct Compressor *Comp, const ALsizei SamplesToDo, ALsizei GetCompressorLookAhead(const struct Compressor *Comp); +#ifdef __cplusplus +} // extern "C" +#endif + #endif /* MASTERING_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 11cf7da6..a992d76c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -839,7 +839,7 @@ SET(OPENAL_OBJS OpenAL32/sample_cvt.c ) SET(ALC_OBJS - Alc/ALc.c + Alc/alc.cpp Alc/ALu.c Alc/alconfig.cpp Alc/alconfig.h -- cgit v1.2.3 From 46301a087cfa106979dd1bab5574737020c9f94f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 14 Nov 2018 06:17:47 -0800 Subject: Use C++ a bit more with alc.cpp --- Alc/alc.cpp | 210 ++++++++++++++++++++-------------------------- OpenAL32/Include/alMain.h | 11 ++- 2 files changed, 98 insertions(+), 123 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index b46f1986..ab8f8fbe 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -30,6 +30,8 @@ #include #include +#include +#include #include #include @@ -58,6 +60,8 @@ #include "backends/base.h" +namespace { + /************************************************ * Backends ************************************************/ @@ -66,7 +70,7 @@ struct BackendInfo { ALCbackendFactory* (*getFactory)(void); }; -static struct BackendInfo BackendList[] = { +struct BackendInfo BackendList[] = { #ifdef HAVE_JACK { "jack", ALCjackBackendFactory_getFactory }, #endif @@ -115,18 +119,18 @@ static struct BackendInfo BackendList[] = { { "wave", ALCwaveBackendFactory_getFactory }, #endif }; -static ALsizei BackendListSize = COUNTOF(BackendList); +ALsizei BackendListSize = COUNTOF(BackendList); #undef EmptyFuncs -static struct BackendInfo PlaybackBackend; -static struct BackendInfo CaptureBackend; +struct BackendInfo PlaybackBackend; +struct BackendInfo CaptureBackend; /************************************************ * Functions, enums, and errors ************************************************/ #define DECL(x) { #x, (ALCvoid*)(x) } -static const struct { +constexpr struct { const ALCchar *funcName; ALCvoid *address; } alcFunctions[] = { @@ -305,7 +309,7 @@ static const struct { #undef DECL #define DECL(x) { #x, (x) } -static const struct { +constexpr struct { const ALCchar *enumName; ALCenum value; } alcEnumerations[] = { @@ -688,12 +692,12 @@ static const struct { }; #undef DECL -static const ALCchar alcNoError[] = "No Error"; -static const ALCchar alcErrInvalidDevice[] = "Invalid Device"; -static const ALCchar alcErrInvalidContext[] = "Invalid Context"; -static const ALCchar alcErrInvalidEnum[] = "Invalid Enum"; -static const ALCchar alcErrInvalidValue[] = "Invalid Value"; -static const ALCchar alcErrOutOfMemory[] = "Out of Memory"; +constexpr ALCchar alcNoError[] = "No Error"; +constexpr ALCchar alcErrInvalidDevice[] = "Invalid Device"; +constexpr ALCchar alcErrInvalidContext[] = "Invalid Context"; +constexpr ALCchar alcErrInvalidEnum[] = "Invalid Enum"; +constexpr ALCchar alcErrInvalidValue[] = "Invalid Value"; +constexpr ALCchar alcErrOutOfMemory[] = "Out of Memory"; /************************************************ @@ -701,17 +705,17 @@ static const ALCchar alcErrOutOfMemory[] = "Out of Memory"; ************************************************/ /* Enumerated device names */ -static const ALCchar alcDefaultName[] = "OpenAL Soft\0"; +constexpr ALCchar alcDefaultName[] = "OpenAL Soft\0"; -static al_string alcAllDevicesList; -static al_string alcCaptureDeviceList; +al_string alcAllDevicesList; +al_string alcCaptureDeviceList; /* Default is always the first in the list */ -static ALCchar *alcDefaultAllDevicesSpecifier; -static ALCchar *alcCaptureDefaultDeviceSpecifier; +std::string alcDefaultAllDevicesSpecifier; +std::string alcCaptureDefaultDeviceSpecifier; /* Default context extensions */ -static const ALchar alExtList[] = +constexpr ALchar alExtList[] = "AL_EXT_ALAW " "AL_EXT_BFORMAT " "AL_EXT_DOUBLE " @@ -742,72 +746,64 @@ static const ALchar alExtList[] = "AL_SOFT_source_resampler " "AL_SOFT_source_spatialize"; -static ATOMIC(ALCenum) LastNullDeviceError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); +std::atomic LastNullDeviceError{ALC_NO_ERROR}; /* Thread-local current context */ -static altss_t LocalContext; +altss_t LocalContext; /* Process-wide current context */ -static ATOMIC(ALCcontext*) GlobalContext = ATOMIC_INIT_STATIC(nullptr); - -/* Mixing thread piority level */ -ALint RTPrioLevel; - -FILE *LogFile; -#ifdef _DEBUG -enum LogLevel LogLevel = LogWarning; -#else -enum LogLevel LogLevel = LogError; -#endif +std::atomic GlobalContext{nullptr}; /* Flag to trap ALC device errors */ -static ALCboolean TrapALCError = ALC_FALSE; +bool TrapALCError{false}; /* One-time configuration init control */ -static alonce_flag alc_config_once = AL_ONCE_FLAG_INIT; +std::once_flag alc_config_once{}; /* Default effect that applies to sources that don't have an effect on send 0 */ -static ALeffect DefaultEffect; +ALeffect DefaultEffect; /* Flag to specify if alcSuspendContext/alcProcessContext should defer/process * updates. */ -static ALCboolean SuspendDefers = ALC_TRUE; +bool SuspendDefers{true}; /************************************************ * ALC information ************************************************/ -static const ALCchar alcNoDeviceExtList[] = +constexpr ALCchar alcNoDeviceExtList[] = "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE " "ALC_EXT_thread_local_context ALC_SOFT_loopback"; -static const ALCchar alcExtensionList[] = +constexpr ALCchar alcExtensionList[] = "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE " "ALC_EXT_DEDICATED ALC_EXT_disconnect ALC_EXT_EFX " "ALC_EXT_thread_local_context ALC_SOFT_device_clock ALC_SOFT_HRTF " "ALC_SOFT_loopback ALC_SOFT_output_limiter ALC_SOFT_pause_device"; -static const ALCint alcMajorVersion = 1; -static const ALCint alcMinorVersion = 1; +constexpr ALCint alcMajorVersion = 1; +constexpr ALCint alcMinorVersion = 1; -static const ALCint alcEFXMajorVersion = 1; -static const ALCint alcEFXMinorVersion = 0; +constexpr ALCint alcEFXMajorVersion = 1; +constexpr ALCint alcEFXMinorVersion = 0; /************************************************ * Device lists ************************************************/ -static std::atomic DeviceList{nullptr}; +std::atomic DeviceList{nullptr}; -static almtx_t ListLock; -static inline void LockLists(void) -{ - int ret = almtx_lock(&ListLock); - assert(ret == althrd_success); -} -static inline void UnlockLists(void) -{ - int ret = almtx_unlock(&ListLock); - assert(ret == althrd_success); -} +std::recursive_mutex ListLock; + +} // namespace + +/* Mixing thread piority level */ +ALint RTPrioLevel; + +FILE *LogFile; +#ifdef _DEBUG +enum LogLevel LogLevel = LogWarning; +#else +enum LogLevel LogLevel = LogError; +#endif /************************************************ * Library initialization @@ -899,9 +895,6 @@ static void alc_init(void) ret = altss_create(&LocalContext, ReleaseThreadCtx); assert(ret == althrd_success); - - ret = almtx_init(&ListLock, almtx_recursive); - assert(ret == althrd_success); } static void alc_initconfig(void) @@ -951,7 +944,7 @@ static void alc_initconfig(void) { if(strcasecmp(str, "ignore") == 0) { - SuspendDefers = ALC_FALSE; + SuspendDefers = false; TRACE("Selected context suspend behavior, \"ignore\"\n"); } else @@ -1023,7 +1016,7 @@ static void alc_initconfig(void) if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) { TrapALError = AL_TRUE; - TrapALCError = AL_TRUE; + TrapALCError = true; } else { @@ -1034,8 +1027,8 @@ static void alc_initconfig(void) str = getenv("ALSOFT_TRAP_ALC_ERROR"); if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) - TrapALCError = ALC_TRUE; - TrapALCError = GetConfigValueBool(nullptr, nullptr, "trap-alc-error", TrapALCError); + TrapALCError = true; + TrapALCError = !!GetConfigValueBool(nullptr, nullptr, "trap-alc-error", TrapALCError); } if(ConfigValueFloat(nullptr, "reverb", "boost", &valf)) @@ -1172,7 +1165,7 @@ static void alc_initconfig(void) if((str && str[0]) || ConfigValueStr(nullptr, nullptr, "default-reverb", &str)) LoadReverbPreset(str, &DefaultEffect); } -#define DO_INITCONFIG() alcall_once(&alc_config_once, alc_initconfig) +#define DO_INITCONFIG() std::call_once(alc_config_once, alc_initconfig) /************************************************ @@ -1183,10 +1176,8 @@ static void alc_cleanup(void) AL_STRING_DEINIT(alcAllDevicesList); AL_STRING_DEINIT(alcCaptureDeviceList); - free(alcDefaultAllDevicesSpecifier); - alcDefaultAllDevicesSpecifier = nullptr; - free(alcCaptureDefaultDeviceSpecifier); - alcCaptureDefaultDeviceSpecifier = nullptr; + alcDefaultAllDevicesSpecifier.clear(); + alcCaptureDefaultDeviceSpecifier.clear(); if(ALCdevice *dev{DeviceList.exchange(nullptr)}) { @@ -1206,7 +1197,6 @@ static void alc_deinit_safe(void) FreeHrtfs(); FreeALConfig(); - almtx_destroy(&ListLock); altss_delete(LocalContext); if(LogFile != stderr) @@ -1246,16 +1236,13 @@ static void ProbeDevices(al_string *list, struct BackendInfo *backendinfo, enum { DO_INITCONFIG(); - LockLists(); + std::lock_guard _{ListLock}; alstr_clear(list); - if(backendinfo->getFactory) { ALCbackendFactory *factory = backendinfo->getFactory(); V(factory,probe)(type, list); } - - UnlockLists(); } static void ProbeAllDevicesList(void) { ProbeDevices(&alcAllDevicesList, &PlaybackBackend, ALL_DEVICE_PROBE); } @@ -1634,7 +1621,7 @@ static void alcSetError(ALCdevice *device, ALCenum errorCode) if(device) ATOMIC_STORE_SEQ(&device->LastError, errorCode); else - ATOMIC_STORE_SEQ(&LastNullDeviceError, errorCode); + LastNullDeviceError.store(errorCode); } @@ -2311,8 +2298,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) * auxiliary sends is changing. Active sources will have updates * respecified in UpdateAllSourceProps. */ - vprops = ATOMIC_EXCHANGE_PTR(&context->FreeVoiceProps, static_cast(nullptr), - almemory_order_acq_rel); + vprops = static_cast(ATOMIC_EXCHANGE_PTR(&context->FreeVoiceProps, + static_cast(nullptr), almemory_order_acq_rel)); while(vprops) { struct ALvoiceProps *next = ATOMIC_LOAD(&vprops->next, almemory_order_relaxed); @@ -2537,19 +2524,17 @@ void ALCdevice_DecRef(ALCdevice *device) */ static ALCboolean VerifyDevice(ALCdevice **device) { - LockLists(); + std::lock_guard _{ListLock}; ALCdevice *tmpDevice{DeviceList.load()}; while(tmpDevice) { if(tmpDevice == *device) { ALCdevice_IncRef(tmpDevice); - UnlockLists(); return ALC_TRUE; } tmpDevice = ATOMIC_LOAD(&tmpDevice->next, almemory_order_relaxed); } - UnlockLists(); *device = nullptr; return ALC_FALSE; @@ -2661,7 +2646,6 @@ static ALvoid InitContext(ALCcontext *Context) static void FreeContext(ALCcontext *context) { ALlistener *listener = context->Listener; - struct ALeffectslotArray *auxslots; struct ALeffectslotProps *eprops; struct ALlistenerProps *lprops; struct ALcontextProps *cprops; @@ -2694,9 +2678,8 @@ static void FreeContext(ALCcontext *context) context->DefaultSlot = nullptr; } - auxslots = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, - static_cast(nullptr), almemory_order_relaxed); - al_free(auxslots); + al_free(ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, + static_cast(nullptr), almemory_order_relaxed)); ReleaseALSources(context); #define FREE_SOURCESUBLIST(x) al_free((x)->Sources) @@ -2795,7 +2778,7 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) } origctx = context; - if(ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&GlobalContext, &origctx, static_cast(nullptr))) + if(GlobalContext.compare_exchange_strong(origctx, nullptr)) ALCcontext_DecRef(context); V0(device->Backend,lock)(); @@ -2857,7 +2840,7 @@ static void ReleaseThreadCtx(void *ptr) */ static ALCboolean VerifyContext(ALCcontext **context) { - LockLists(); + std::lock_guard _{ListLock}; ALCdevice *dev{DeviceList.load()}; while(dev) { @@ -2867,14 +2850,12 @@ static ALCboolean VerifyContext(ALCcontext **context) if(ctx == *context) { ALCcontext_IncRef(ctx); - UnlockLists(); return ALC_TRUE; } ctx = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed); } dev = ATOMIC_LOAD(&dev->next, almemory_order_relaxed); } - UnlockLists(); *context = nullptr; return ALC_FALSE; @@ -2893,10 +2874,9 @@ ALCcontext *GetContextRef(void) ALCcontext_IncRef(context); else { - LockLists(); - context = ATOMIC_LOAD_SEQ(&GlobalContext); + std::lock_guard _{ListLock}; + context = GlobalContext.load(std::memory_order_acquire); if(context) ALCcontext_IncRef(context); - UnlockLists(); } return context; @@ -3007,7 +2987,7 @@ ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) ALCdevice_DecRef(device); } else - errorCode = ATOMIC_EXCHANGE_SEQ(&LastNullDeviceError, ALC_NO_ERROR); + errorCode = LastNullDeviceError.exchange(ALC_NO_ERROR); return errorCode; } @@ -3125,12 +3105,8 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para VerifyDevice(&Device); - free(alcDefaultAllDevicesSpecifier); - alcDefaultAllDevicesSpecifier = strdup(alstr_get_cstr(alcAllDevicesList)); - if(!alcDefaultAllDevicesSpecifier) - alcSetError(Device, ALC_OUT_OF_MEMORY); - - value = alcDefaultAllDevicesSpecifier; + alcDefaultAllDevicesSpecifier = alstr_get_cstr(alcAllDevicesList); + value = alcDefaultAllDevicesSpecifier.c_str(); if(Device) ALCdevice_DecRef(Device); break; @@ -3140,12 +3116,8 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para VerifyDevice(&Device); - free(alcCaptureDefaultDeviceSpecifier); - alcCaptureDefaultDeviceSpecifier = strdup(alstr_get_cstr(alcCaptureDeviceList)); - if(!alcCaptureDefaultDeviceSpecifier) - alcSetError(Device, ALC_OUT_OF_MEMORY); - - value = alcCaptureDefaultDeviceSpecifier; + alcCaptureDefaultDeviceSpecifier = alstr_get_cstr(alcCaptureDeviceList); + value = alcCaptureDefaultDeviceSpecifier.c_str(); if(Device) ALCdevice_DecRef(Device); break; @@ -3772,17 +3744,17 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin * device is asynchronously destropyed, to ensure this new context is * properly cleaned up after being made. */ - LockLists(); + std::unique_lock listlock{ListLock}; if(!VerifyDevice(&device) || device->Type == Capture || !ATOMIC_LOAD(&device->Connected, almemory_order_relaxed)) { - UnlockLists(); + listlock.unlock(); alcSetError(device, ALC_INVALID_DEVICE); if(device) ALCdevice_DecRef(device); return nullptr; } almtx_lock(&device->BackendLock); - UnlockLists(); + listlock.unlock(); ATOMIC_STORE_SEQ(&device->LastError, ALC_NO_ERROR); @@ -3889,17 +3861,15 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin */ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) { - ALCdevice *Device; - - LockLists(); + std::unique_lock listlock{ListLock}; if(!VerifyContext(&context)) { - UnlockLists(); + listlock.unlock(); alcSetError(nullptr, ALC_INVALID_CONTEXT); return; } - Device = context->Device; + ALCdevice* Device{context->Device}; if(Device) { almtx_lock(&Device->BackendLock); @@ -3910,7 +3880,7 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) } almtx_unlock(&Device->BackendLock); } - UnlockLists(); + listlock.unlock(); ALCcontext_DecRef(context); } @@ -3923,7 +3893,7 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) { ALCcontext *Context{static_cast(altss_get(LocalContext))}; - if(!Context) Context = ATOMIC_LOAD_SEQ(&GlobalContext); + if(!Context) Context = GlobalContext.load(); return Context; } @@ -3951,7 +3921,7 @@ ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) return ALC_FALSE; } /* context's reference count is already incremented */ - context = ATOMIC_EXCHANGE_PTR_SEQ(&GlobalContext, context); + context = GlobalContext.exchange(context); if(context) ALCcontext_DecRef(context); if((context=static_cast(altss_get(LocalContext))) != nullptr) @@ -4206,7 +4176,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) */ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) { - LockLists(); + std::unique_lock listlock{ListLock}; ALCdevice *iter{DeviceList.load()}; do { if(iter == device) @@ -4216,14 +4186,13 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) if(!iter || iter->Type == Capture) { alcSetError(iter, ALC_INVALID_DEVICE); - UnlockLists(); return ALC_FALSE; } almtx_lock(&device->BackendLock); ALCdevice *origdev{device}; ALCdevice *nextdev{ATOMIC_LOAD(&device->next, almemory_order_relaxed)}; - if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&DeviceList, &origdev, nextdev)) + if(!DeviceList.compare_exchange_strong(origdev, nextdev)) { ALCdevice *list; do { @@ -4231,7 +4200,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) origdev = device; } while(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&list->next, &origdev, nextdev)); } - UnlockLists(); + listlock.unlock(); ALCcontext *ctx{ATOMIC_LOAD_SEQ(&device->ContextList)}; while(ctx != nullptr) @@ -4339,8 +4308,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) { + std::unique_lock listlock{ListLock}; - LockLists(); ALCdevice *iter{DeviceList.load()}; do { if(iter == device) @@ -4350,7 +4319,6 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) if(!iter || iter->Type != Capture) { alcSetError(iter, ALC_INVALID_DEVICE); - UnlockLists(); return ALC_FALSE; } @@ -4364,7 +4332,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) origdev = device; } while(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&list->next, &origdev, nextdev)); } - UnlockLists(); + listlock.unlock(); almtx_lock(&device->BackendLock); if((device->Flags&DEVICE_RUNNING)) @@ -4663,17 +4631,17 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi { ALCenum err; - LockLists(); + std::unique_lock listlock{ListLock}; if(!VerifyDevice(&device) || device->Type == Capture || !ATOMIC_LOAD(&device->Connected, almemory_order_relaxed)) { - UnlockLists(); + listlock.unlock(); alcSetError(device, ALC_INVALID_DEVICE); if(device) ALCdevice_DecRef(device); return ALC_FALSE; } almtx_lock(&device->BackendLock); - UnlockLists(); + listlock.unlock(); err = UpdateDeviceParams(device, attribs); almtx_unlock(&device->BackendLock); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 666a8ade..b9ace4db 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -32,6 +32,15 @@ #include "threads.h" +#ifndef __cplusplus +#define COUNTOF(x) (sizeof(x) / sizeof(0[x])) +#else +template +constexpr inline size_t countof(const T(&)[N]) noexcept +{ return N; } +#define COUNTOF countof +#endif + #if defined(_WIN64) #define SZFMT "%I64u" #elif defined(_WIN32) @@ -197,8 +206,6 @@ static const union { #define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1) #endif -#define COUNTOF(x) (sizeof(x) / sizeof(0[x])) - struct ll_ringbuffer; struct Hrtf; -- cgit v1.2.3 From c4d3444a6dc2ff365dbbf568313719f15ebd7fac Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 14 Nov 2018 17:01:19 -0800 Subject: Use std::pow and std::log2 --- Alc/alc.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index ab8f8fbe..4f021a78 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -22,13 +22,13 @@ #include "version.h" -#include #include #include #include #include #include +#include #include #include #include @@ -1032,7 +1032,7 @@ static void alc_initconfig(void) } if(ConfigValueFloat(nullptr, "reverb", "boost", &valf)) - ReverbBoost *= powf(10.0f, valf / 20.0f); + ReverbBoost *= std::pow(10.0f, valf / 20.0f); if(((devs=getenv("ALSOFT_DRIVERS")) && devs[0]) || ConfigValueStr(nullptr, nullptr, "drivers", &devs)) @@ -2137,13 +2137,13 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(depth > 0) { depth = clampi(depth, 2, 24); - device->DitherDepth = powf(2.0f, (ALfloat)(depth-1)); + device->DitherDepth = std::pow(2.0f, (ALfloat)(depth-1)); } } if(!(device->DitherDepth > 0.0f)) TRACE("Dithering disabled\n"); else - TRACE("Dithering enabled (%g-bit, %g)\n", log2f(device->DitherDepth)+1.0f, + TRACE("Dithering enabled (%d-bit, %g)\n", float2int(std::log2(device->DitherDepth)+0.5)+1, device->DitherDepth); device->LimiterState = gainLimiter; @@ -2194,7 +2194,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) thrshld -= 1.0f / device->DitherDepth; al_free(device->Limiter); - device->Limiter = CreateDeviceLimiter(device, log10f(thrshld) * 20.0f); + device->Limiter = CreateDeviceLimiter(device, std::log10(thrshld) * 20.0f); device->FixedLatency += (ALuint)(GetCompressorLookAhead(device->Limiter) * DEVICE_CLOCK_RES / device->Frequency); } @@ -3826,7 +3826,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ALfloat db = clampf(valf, -24.0f, 24.0f); if(db != valf) WARN("volume-adjust clamped: %f, range: +/-%f\n", valf, 24.0f); - ALContext->GainBoost = powf(10.0f, db/20.0f); + ALContext->GainBoost = std::pow(10.0f, db/20.0f); TRACE("volume-adjust gain: %f\n", ALContext->GainBoost); } } -- cgit v1.2.3 From 3b1b029a7597d5b5f571f819f0bab4b8a33e5810 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 14 Nov 2018 17:08:14 -0800 Subject: Remove some now-unused function checks --- CMakeLists.txt | 3 --- common/math_defs.h | 8 -------- config.h.in | 9 --------- 3 files changed, 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a992d76c..5cd54ba9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -604,8 +604,6 @@ CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN) CHECK_SYMBOL_EXISTS(_aligned_malloc malloc.h HAVE__ALIGNED_MALLOC) CHECK_SYMBOL_EXISTS(proc_pidpath libproc.h HAVE_PROC_PIDPATH) CHECK_SYMBOL_EXISTS(lrintf math.h HAVE_LRINTF) -CHECK_SYMBOL_EXISTS(modff math.h HAVE_MODFF) -CHECK_SYMBOL_EXISTS(log2f math.h HAVE_LOG2F) CHECK_SYMBOL_EXISTS(cbrtf math.h HAVE_CBRTF) CHECK_SYMBOL_EXISTS(copysignf math.h HAVE_COPYSIGNF) @@ -615,7 +613,6 @@ IF(HAVE_FLOAT_H) ENDIF() CHECK_FUNCTION_EXISTS(stat HAVE_STAT) -CHECK_FUNCTION_EXISTS(strtof HAVE_STRTOF) CHECK_FUNCTION_EXISTS(strcasecmp HAVE_STRCASECMP) IF(NOT HAVE_STRCASECMP) CHECK_FUNCTION_EXISTS(_stricmp HAVE__STRICMP) diff --git a/common/math_defs.h b/common/math_defs.h index 1b24bec4..3e8dbe76 100644 --- a/common/math_defs.h +++ b/common/math_defs.h @@ -32,14 +32,6 @@ static const union msvc_inf_hack { #define HUGE_VALF (msvc_inf_union.f) #endif -#ifndef HAVE_LOG2F -static inline float my_log2f(float f) -{ - return logf(f) / logf(2.0f); -} -#define log2f my_log2f -#endif - #ifndef HAVE_CBRTF static inline float my_cbrtf(float f) { diff --git a/config.h.in b/config.h.in index 5b4bdfde..7895dc88 100644 --- a/config.h.in +++ b/config.h.in @@ -92,21 +92,12 @@ /* Define if we have the lrintf function */ #cmakedefine HAVE_LRINTF -/* Define if we have the modff function */ -#cmakedefine HAVE_MODFF - -/* Define if we have the log2f function */ -#cmakedefine HAVE_LOG2F - /* Define if we have the cbrtf function */ #cmakedefine HAVE_CBRTF /* Define if we have the copysignf function */ #cmakedefine HAVE_COPYSIGNF -/* Define if we have the strtof function */ -#cmakedefine HAVE_STRTOF - /* Define if we have the strnlen function */ #cmakedefine HAVE_STRNLEN -- cgit v1.2.3 From 83dec6b97535aadcbbfe2a75a7a405190786fe57 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 14 Nov 2018 19:16:50 -0800 Subject: Use a C++ vector for enumerated OSS devices --- Alc/backends/oss.cpp | 301 +++++++++++++++++++++++++-------------------------- 1 file changed, 146 insertions(+), 155 deletions(-) diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 279a2b99..24609954 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -33,6 +33,10 @@ #include #include +#include +#include +#include + #include "alMain.h" #include "alu.h" #include "alconfig.h" @@ -72,30 +76,39 @@ namespace { -struct oss_device { - const ALCchar *handle; - const char *path; - struct oss_device *next; -}; +constexpr char DefaultName[] = "OSS Default"; +const char *DefaultPlayback{"/dev/dsp"}; +const char *DefaultCapture{"/dev/dsp"}; -struct oss_device oss_playback = { - "OSS Default", - "/dev/dsp", - nullptr -}; +struct DevMap { + std::string name; + std::string device_name; -struct oss_device oss_capture = { - "OSS Default", - "/dev/dsp", - nullptr + template + DevMap(StrT0&& name_, StrT1&& devname_) + : name{std::forward(name_)}, device_name{std::forward(devname_)} + { } }; +bool checkName(const std::vector &list, const std::string &name) +{ + return std::find_if(list.cbegin(), list.cend(), + [&name](const DevMap &entry) -> bool + { return entry.name == name; } + ) != list.cend(); +} + +std::vector PlaybackDevices; +std::vector CaptureDevices; + + #ifdef ALC_OSS_COMPAT #define DSP_CAP_OUTPUT 0x00020000 #define DSP_CAP_INPUT 0x00010000 -void ALCossListPopulate(struct oss_device *UNUSED(devlist), int UNUSED(type_flag)) +void ALCossListPopulate(std::vector *devlist, int type) { + devlist->emplace_back(DefaultName, (type==DSP_CAP_INPUT) ? DefaultCapture : DefaultPlayback); } #else @@ -110,17 +123,10 @@ size_t my_strnlen(const char *str, size_t maxlen) #define strnlen my_strnlen #endif -void ALCossListAppend(struct oss_device *list, const char *handle, size_t hlen, const char *path, size_t plen) +void ALCossListAppend(std::vector *list, const char *handle, size_t hlen, const char *path, size_t plen) { - struct oss_device *next; - struct oss_device *last; - size_t i; - - /* skip the first item "OSS Default" */ - last = list; - next = list->next; #ifdef ALC_OSS_DEVNODE_TRUC - for(i = 0;i < plen;i++) + for(size_t i{0};i < plen;i++) { if(path[i] == '.') { @@ -129,8 +135,6 @@ void ALCossListAppend(struct oss_device *list, const char *handle, size_t hlen, plen = i; } } -#else - (void)i; #endif if(handle[0] == '\0') { @@ -138,58 +142,63 @@ void ALCossListAppend(struct oss_device *list, const char *handle, size_t hlen, hlen = plen; } - while(next != nullptr) + std::string basename{handle, hlen}; + basename.erase(std::find(basename.begin(), basename.end(), '\0'), basename.end()); + std::string devname{path, plen}; + devname.erase(std::find(devname.begin(), devname.end(), '\0'), devname.end()); + + auto iter = std::find_if(list->cbegin(), list->cend(), + [&devname](const DevMap &entry) -> bool + { return entry.device_name == devname; } + ); + if(iter != list->cend()) + return; + + int count{1}; + std::string newname{basename}; + while(checkName(PlaybackDevices, newname)) { - if(strncmp(next->path, path, plen) == 0) - return; - last = next; - next = next->next; + newname = basename; + newname += " #"; + newname += std::to_string(++count); } - next = (struct oss_device*)malloc(sizeof(struct oss_device) + hlen + plen + 2); - next->handle = (char*)(next + 1); - next->path = next->handle + hlen + 1; - next->next = nullptr; - last->next = next; + list->emplace_back(std::move(newname), std::move(devname)); + const DevMap &entry = list->back(); - strncpy((char*)next->handle, handle, hlen); - ((char*)next->handle)[hlen] = '\0'; - strncpy((char*)next->path, path, plen); - ((char*)next->path)[plen] = '\0'; - - TRACE("Got device \"%s\", \"%s\"\n", next->handle, next->path); + TRACE("Got device \"%s\", \"%s\"\n", entry.name.c_str(), entry.device_name.c_str()); } -void ALCossListPopulate(struct oss_device *devlist, int type_flag) +void ALCossListPopulate(std::vector *devlist, int type_flag) { - struct oss_sysinfo si; - struct oss_audioinfo ai; - int fd, i; - - if((fd=open("/dev/mixer", O_RDONLY)) < 0) + int fd{open("/dev/mixer", O_RDONLY)}; + if(fd < 0) { TRACE("Could not open /dev/mixer: %s\n", strerror(errno)); - return; + goto done; } + + struct oss_sysinfo si; if(ioctl(fd, SNDCTL_SYSINFO, &si) == -1) { TRACE("SNDCTL_SYSINFO failed: %s\n", strerror(errno)); goto done; } - for(i = 0;i < si.numaudios;i++) - { - const char *handle; - size_t len; + for(int i{0};i < si.numaudios;i++) + { + struct oss_audioinfo ai; ai.dev = i; if(ioctl(fd, SNDCTL_AUDIOINFO, &ai) == -1) { ERR("SNDCTL_AUDIOINFO (%d) failed: %s\n", i, strerror(errno)); continue; } - if(ai.devnode[0] == '\0') + if(!(ai.caps&type_flag) || ai.devnode[0] == '\0') continue; + const char *handle; + size_t len; if(ai.handle[0] != '\0') { len = strnlen(ai.handle, sizeof(ai.handle)); @@ -200,35 +209,34 @@ void ALCossListPopulate(struct oss_device *devlist, int type_flag) len = strnlen(ai.name, sizeof(ai.name)); handle = ai.name; } - if((ai.caps&type_flag)) - ALCossListAppend(devlist, handle, len, ai.devnode, - strnlen(ai.devnode, sizeof(ai.devnode))); + + ALCossListAppend(devlist, handle, len, ai.devnode, + strnlen(ai.devnode, sizeof(ai.devnode))); } done: - close(fd); -} - -#endif - -void ALCossListFree(struct oss_device *list) -{ - struct oss_device *cur; - if(list == nullptr) - return; - - /* skip the first item "OSS Default" */ - cur = list->next; - list->next = nullptr; - - while(cur != nullptr) + if(fd >= 0) + close(fd); + fd = -1; + + const char *defdev{(type_flag==DSP_CAP_INPUT) ? DefaultCapture : DefaultPlayback}; + auto iter = std::find_if(devlist->cbegin(), devlist->cend(), + [defdev](const DevMap &entry) -> bool + { return entry.device_name == defdev; } + ); + if(iter == devlist->cend()) + devlist->insert(devlist->begin(), DevMap{DefaultName, defdev}); + else { - struct oss_device *next = cur->next; - free(cur); - cur = next; + DevMap entry{std::move(*iter)}; + devlist->erase(iter); + devlist->insert(devlist->begin(), std::move(entry)); } + devlist->shrink_to_fit(); } +#endif + int log2i(ALCuint x) { int y = 0; @@ -361,35 +369,29 @@ static int ALCplaybackOSS_mixerProc(void *ptr) static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) { - struct oss_device *dev = &oss_playback; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - if(!name || strcmp(name, dev->handle) == 0) - name = dev->handle; + const char *devname{DefaultPlayback}; + if(!name) + name = DefaultName; else { - if(!dev->next) - { - ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT); - dev = &oss_playback; - } - while(dev != nullptr) - { - if (strcmp(dev->handle, name) == 0) - break; - dev = dev->next; - } - if(dev == nullptr) - { - WARN("Could not find \"%s\" in device list\n", name); + if(PlaybackDevices.empty()) + ALCossListPopulate(&PlaybackDevices, DSP_CAP_OUTPUT); + + auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + [&name](const DevMap &entry) -> bool + { return entry.name == name; } + ); + if(iter == PlaybackDevices.cend()) return ALC_INVALID_VALUE; - } + devname = iter->device_name.c_str(); } - self->fd = open(dev->path, O_WRONLY); + self->fd = open(devname, O_WRONLY); if(self->fd == -1) { - ERR("Could not open %s: %s\n", dev->path, strerror(errno)); + ERR("Could not open %s: %s\n", devname, strerror(errno)); return ALC_INVALID_VALUE; } @@ -628,46 +630,32 @@ static int ALCcaptureOSS_recordProc(void *ptr) static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - struct oss_device *dev = &oss_capture; - int numFragmentsLogSize; - int log2FragmentSize; - unsigned int periods; - audio_buf_info info; - ALuint frameSize; - int numChannels; - int ossFormat; - int ossSpeed; - const char *err; - if(!name || strcmp(name, dev->handle) == 0) - name = dev->handle; + const char *devname{DefaultCapture}; + if(!name) + name = DefaultName; else { - if(!dev->next) - { - ALCossListPopulate(&oss_capture, DSP_CAP_INPUT); - dev = &oss_capture; - } - while(dev != nullptr) - { - if (strcmp(dev->handle, name) == 0) - break; - dev = dev->next; - } - if(dev == nullptr) - { - WARN("Could not find \"%s\" in device list\n", name); + if(CaptureDevices.empty()) + ALCossListPopulate(&CaptureDevices, DSP_CAP_INPUT); + + auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), + [&name](const DevMap &entry) -> bool + { return entry.name == name; } + ); + if(iter == CaptureDevices.cend()) return ALC_INVALID_VALUE; - } + devname = iter->device_name.c_str(); } - self->fd = open(dev->path, O_RDONLY); + self->fd = open(devname, O_RDONLY); if(self->fd == -1) { - ERR("Could not open %s: %s\n", dev->path, strerror(errno)); + ERR("Could not open %s: %s\n", devname, strerror(errno)); return ALC_INVALID_VALUE; } + int ossFormat{}; switch(device->FmtType) { case DevFmtByte: @@ -687,18 +675,19 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) return ALC_INVALID_VALUE; } - periods = 4; - numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - frameSize = numChannels * BytesFromDevFmt(device->FmtType); - ossSpeed = device->Frequency; - log2FragmentSize = log2i(device->UpdateSize * device->NumUpdates * - frameSize / periods); + int periods{4}; + int numChannels{ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder)}; + int frameSize{numChannels * BytesFromDevFmt(device->FmtType)}; + int ossSpeed{static_cast(device->Frequency)}; + int log2FragmentSize{log2i(device->UpdateSize * device->NumUpdates * + frameSize / periods)}; /* according to the OSS spec, 16 bytes are the minimum */ - if (log2FragmentSize < 4) - log2FragmentSize = 4; - numFragmentsLogSize = (periods << 16) | log2FragmentSize; + log2FragmentSize = std::max(log2FragmentSize, 4); + int numFragmentsLogSize{(periods << 16) | log2FragmentSize}; + audio_buf_info info; + const char *err; #define CHECKERR(func) if((func) < 0) { \ err = #func; \ goto err; \ @@ -810,16 +799,16 @@ ALCbackendFactory *ALCossBackendFactory_getFactory(void) ALCboolean ALCossBackendFactory_init(ALCossBackendFactory* UNUSED(self)) { - ConfigValueStr(nullptr, "oss", "device", &oss_playback.path); - ConfigValueStr(nullptr, "oss", "capture", &oss_capture.path); + ConfigValueStr(nullptr, "oss", "device", &DefaultPlayback); + ConfigValueStr(nullptr, "oss", "capture", &DefaultCapture); return ALC_TRUE; } -void ALCossBackendFactory_deinit(ALCossBackendFactory* UNUSED(self)) +void ALCossBackendFactory_deinit(ALCossBackendFactory* UNUSED(self)) { - ALCossListFree(&oss_playback); - ALCossListFree(&oss_capture); + PlaybackDevices.clear(); + CaptureDevices.clear(); } @@ -832,30 +821,32 @@ ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory* UNUSED(self), void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { - struct oss_device *cur = nullptr; + auto add_device = [outnames](const DevMap &entry) -> void + { +#ifdef HAVE_STAT + struct stat buf; + if(stat(entry.device_name.c_str(), &buf) == 0) +#endif + { + const char *name{entry.name.c_str()}; + alstr_append_range(outnames, name, name+entry.name.length()+1); + } + }; + switch(type) { case ALL_DEVICE_PROBE: - ALCossListFree(&oss_playback); - ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT); - cur = &oss_playback; + PlaybackDevices.clear(); + ALCossListPopulate(&PlaybackDevices, DSP_CAP_OUTPUT); + std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); break; case CAPTURE_DEVICE_PROBE: - ALCossListFree(&oss_capture); - ALCossListPopulate(&oss_capture, DSP_CAP_INPUT); - cur = &oss_capture; + CaptureDevices.clear(); + ALCossListPopulate(&CaptureDevices, DSP_CAP_INPUT); + std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); break; } - while(cur != nullptr) - { -#ifdef HAVE_STAT - struct stat buf; - if(stat(cur->path, &buf) == 0) -#endif - alstr_append_range(outnames, cur->handle, cur->handle+strlen(cur->handle)+1); - cur = cur->next; - } } ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -- cgit v1.2.3 From 1d2cc9017594046570b4b141eae71ea326250604 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 14 Nov 2018 20:49:08 -0800 Subject: Use C++ more in the OSS backend --- Alc/backends/oss.cpp | 105 ++++++++++++++++++++++++--------------------------- 1 file changed, 49 insertions(+), 56 deletions(-) diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 24609954..65212fba 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -33,6 +33,8 @@ #include #include +#include +#include #include #include #include @@ -41,7 +43,6 @@ #include "alu.h" #include "alconfig.h" #include "ringbuffer.h" -#include "threads.h" #include "compat.h" #include "backends/base.h" @@ -251,16 +252,15 @@ int log2i(ALCuint x) } // namespace struct ALCplaybackOSS final : public ALCbackend { - int fd; + int fd{-1}; - ALubyte *mix_data; - int data_size; + std::vector mix_data; - ATOMIC(ALenum) killNow; - althrd_t thread; + std::atomic killNow{AL_TRUE}; + std::thread thread; }; -static int ALCplaybackOSS_mixerProc(void *ptr); +static int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self); static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device); static void ALCplaybackOSS_Destruct(ALCplaybackOSS *self); @@ -282,9 +282,6 @@ static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device) new (self) ALCplaybackOSS{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCplaybackOSS, ALCbackend, self); - - self->fd = -1; - ATOMIC_INIT(&self->killNow, AL_FALSE); } static void ALCplaybackOSS_Destruct(ALCplaybackOSS *self) @@ -298,9 +295,8 @@ static void ALCplaybackOSS_Destruct(ALCplaybackOSS *self) } -static int ALCplaybackOSS_mixerProc(void *ptr) +static int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self) { - ALCplaybackOSS *self = static_cast(ptr); ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; struct timeval timeout; ALubyte *write_ptr; @@ -316,7 +312,7 @@ static int ALCplaybackOSS_mixerProc(void *ptr) frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); ALCplaybackOSS_lock(self); - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + while(!self->killNow.load(std::memory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { FD_ZERO(&wfds); @@ -341,10 +337,10 @@ static int ALCplaybackOSS_mixerProc(void *ptr) continue; } - write_ptr = self->mix_data; - to_write = self->data_size; + write_ptr = self->mix_data.data(); + to_write = self->mix_data.size(); aluMixData(device, write_ptr, to_write/frame_size); - while(to_write > 0 && !ATOMIC_LOAD_SEQ(&self->killNow)) + while(to_write > 0 && !self->killNow.load()) { wrote = write(self->fd, write_ptr, to_write); if(wrote < 0) @@ -486,48 +482,46 @@ static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - self->data_size = device->UpdateSize * FrameSizeFromDevFmt( - device->FmtChans, device->FmtType, device->AmbiOrder - ); - self->mix_data = static_cast(calloc(1, self->data_size)); + try { + self->mix_data.resize(device->UpdateSize * FrameSizeFromDevFmt( + device->FmtChans, device->FmtType, device->AmbiOrder + )); - ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE); - if(althrd_create(&self->thread, ALCplaybackOSS_mixerProc, self) != althrd_success) - { - free(self->mix_data); - self->mix_data = nullptr; - return ALC_FALSE; + self->killNow.store(AL_FALSE); + self->thread = std::thread(ALCplaybackOSS_mixerProc, self); + return ALC_TRUE; } - - return ALC_TRUE; + catch(std::exception& e) { + ERR("Could not create playback thread: %s\n", e.what()); + } + catch(...) { + } + return ALC_FALSE; } static void ALCplaybackOSS_stop(ALCplaybackOSS *self) { - int res; - - if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE)) + if(self->killNow.exchange(AL_TRUE) || !self->thread.joinable()) return; - althrd_join(self->thread, &res); + self->thread.join(); if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0) ERR("Error resetting device: %s\n", strerror(errno)); - free(self->mix_data); - self->mix_data = nullptr; + self->mix_data.clear(); } struct ALCcaptureOSS final : public ALCbackend { - int fd; + int fd{-1}; - ll_ringbuffer_t *ring; + ll_ringbuffer_t *ring{nullptr}; - ATOMIC(ALenum) killNow; - althrd_t thread; + std::atomic killNow{AL_TRUE}; + std::thread thread; }; -static int ALCcaptureOSS_recordProc(void *ptr); +static int ALCcaptureOSS_recordProc(ALCcaptureOSS *self); static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device); static void ALCcaptureOSS_Destruct(ALCcaptureOSS *self); @@ -549,10 +543,6 @@ static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device) new (self) ALCcaptureOSS{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCcaptureOSS, ALCbackend, self); - - self->fd = -1; - self->ring = nullptr; - ATOMIC_INIT(&self->killNow, AL_FALSE); } static void ALCcaptureOSS_Destruct(ALCcaptureOSS *self) @@ -568,9 +558,8 @@ static void ALCcaptureOSS_Destruct(ALCcaptureOSS *self) } -static int ALCcaptureOSS_recordProc(void *ptr) +static int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) { - ALCcaptureOSS *self = static_cast(ptr); ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; struct timeval timeout; int frame_size; @@ -583,10 +572,8 @@ static int ALCcaptureOSS_recordProc(void *ptr) frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - while(!ATOMIC_LOAD_SEQ(&self->killNow)) + while(!self->killNow.load()) { - ll_ringbuffer_data_t vec[2]; - FD_ZERO(&rfds); FD_SET(self->fd, &rfds); timeout.tv_sec = 1; @@ -607,6 +594,7 @@ static int ALCcaptureOSS_recordProc(void *ptr) continue; } + ll_ringbuffer_data_t vec[2]; ll_ringbuffer_get_write_vector(self->ring, vec); if(vec[0].len > 0) { @@ -741,20 +729,25 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self) { - ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE); - if(althrd_create(&self->thread, ALCcaptureOSS_recordProc, self) != althrd_success) - return ALC_FALSE; - return ALC_TRUE; + try { + self->killNow.store(AL_FALSE); + self->thread = std::thread(ALCcaptureOSS_recordProc, self); + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Could not create record thread: %s\n", e.what()); + } + catch(...) { + } + return ALC_FALSE; } static void ALCcaptureOSS_stop(ALCcaptureOSS *self) { - int res; - - if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE)) + if(self->killNow.exchange(AL_TRUE) || !self->thread.joinable()) return; - althrd_join(self->thread, &res); + self->thread.join(); if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0) ERR("Error resetting device: %s\n", strerror(errno)); -- cgit v1.2.3 From 27e7168ad41617d725553bb7234a0149fc711941 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 02:36:05 -0800 Subject: Only declare the device backend stuff with C++ --- Alc/backends/base.h | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/Alc/backends/base.h b/Alc/backends/base.h index bf60a744..75950344 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -24,16 +24,23 @@ inline ALuint64 GetDeviceClockTime(ALCdevice *device) device->Frequency); } +void ALCdevice_Lock(ALCdevice *device); +void ALCdevice_Unlock(ALCdevice *device); + +ClockLatency GetClockLatency(ALCdevice *device); + +#ifdef __cplusplus +} /* extern "C" */ struct ALCbackendVtable; -typedef struct ALCbackend { +struct ALCbackend { const struct ALCbackendVtable *vtbl; ALCdevice *mDevice; almtx_t mMutex; -} ALCbackend; +}; void ALCbackend_Construct(ALCbackend *self, ALCdevice *device); void ALCbackend_Destruct(ALCbackend *self); @@ -95,18 +102,18 @@ static const struct ALCbackendVtable T##_ALCbackend_vtable = { \ } -typedef enum ALCbackend_Type { +enum ALCbackend_Type { ALCbackend_Playback, ALCbackend_Capture, ALCbackend_Loopback -} ALCbackend_Type; +}; struct ALCbackendFactoryVtable; -typedef struct ALCbackendFactory { +struct ALCbackendFactory { const struct ALCbackendFactoryVtable *vtbl; -} ALCbackendFactory; +}; void ALCbackendFactory_deinit(ALCbackendFactory *self); @@ -155,14 +162,5 @@ ALCbackendFactory *ALCwaveBackendFactory_getFactory(void); ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void); ALCbackendFactory *ALCloopbackFactory_getFactory(void); - -void ALCdevice_Lock(ALCdevice *device); -void ALCdevice_Unlock(ALCdevice *device); - -ClockLatency GetClockLatency(ALCdevice *device); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - +#endif /* __cplusplus */ #endif /* AL_BACKENDS_BASE_H */ -- cgit v1.2.3 From 8f771a03877332f0dcbd6350b57c354a0c5254d3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 03:13:54 -0800 Subject: Convert alSource.c to C++ --- CMakeLists.txt | 2 +- OpenAL32/alSource.c | 3702 ------------------------------------------------ OpenAL32/alSource.cpp | 3707 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 3708 insertions(+), 3703 deletions(-) delete mode 100644 OpenAL32/alSource.c create mode 100644 OpenAL32/alSource.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5cd54ba9..6d3f6bfd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -829,7 +829,7 @@ SET(OPENAL_OBJS OpenAL32/Include/alListener.h OpenAL32/alListener.c OpenAL32/Include/alSource.h - OpenAL32/alSource.c + OpenAL32/alSource.cpp OpenAL32/alState.c OpenAL32/event.c OpenAL32/Include/sample_cvt.h diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c deleted file mode 100644 index 2eb69cb9..00000000 --- a/OpenAL32/alSource.c +++ /dev/null @@ -1,3702 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "alMain.h" -#include "alError.h" -#include "alSource.h" -#include "alBuffer.h" -#include "alFilter.h" -#include "alAuxEffectSlot.h" -#include "ringbuffer.h" - -#include "backends/base.h" - -#include "threads.h" -#include "almalloc.h" - - -static ALsource *AllocSource(ALCcontext *context); -static void FreeSource(ALCcontext *context, ALsource *source); -static void InitSourceParams(ALsource *Source, ALsizei num_sends); -static void DeinitSource(ALsource *source, ALsizei num_sends); -static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends, ALCcontext *context); -static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime); -static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime); -static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context); -static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac); -static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice); - -static inline void LockSourceList(ALCcontext *context) -{ almtx_lock(&context->SourceLock); } -static inline void UnlockSourceList(ALCcontext *context) -{ almtx_unlock(&context->SourceLock); } - -static inline ALsource *LookupSource(ALCcontext *context, ALuint id) -{ - SourceSubList *sublist; - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= VECTOR_SIZE(context->SourceList))) - return NULL; - sublist = &VECTOR_ELEM(context->SourceList, lidx); - if(UNLIKELY(sublist->FreeMask & (U64(1)<Sources + slidx; -} - -static inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) -{ - BufferSubList *sublist; - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= VECTOR_SIZE(device->BufferList))) - return NULL; - sublist = &VECTOR_ELEM(device->BufferList, lidx); - if(UNLIKELY(sublist->FreeMask & (U64(1)<Buffers + slidx; -} - -static inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) -{ - FilterSubList *sublist; - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= VECTOR_SIZE(device->FilterList))) - return NULL; - sublist = &VECTOR_ELEM(device->FilterList, lidx); - if(UNLIKELY(sublist->FreeMask & (U64(1)<Filters + slidx; -} - -static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) -{ - id--; - if(UNLIKELY(id >= VECTOR_SIZE(context->EffectSlotList))) - return NULL; - return VECTOR_ELEM(context->EffectSlotList, id); -} - - -typedef enum SourceProp { - srcPitch = AL_PITCH, - srcGain = AL_GAIN, - srcMinGain = AL_MIN_GAIN, - srcMaxGain = AL_MAX_GAIN, - srcMaxDistance = AL_MAX_DISTANCE, - srcRolloffFactor = AL_ROLLOFF_FACTOR, - srcDopplerFactor = AL_DOPPLER_FACTOR, - srcConeOuterGain = AL_CONE_OUTER_GAIN, - srcSecOffset = AL_SEC_OFFSET, - srcSampleOffset = AL_SAMPLE_OFFSET, - srcByteOffset = AL_BYTE_OFFSET, - srcConeInnerAngle = AL_CONE_INNER_ANGLE, - srcConeOuterAngle = AL_CONE_OUTER_ANGLE, - srcRefDistance = AL_REFERENCE_DISTANCE, - - srcPosition = AL_POSITION, - srcVelocity = AL_VELOCITY, - srcDirection = AL_DIRECTION, - - srcSourceRelative = AL_SOURCE_RELATIVE, - srcLooping = AL_LOOPING, - srcBuffer = AL_BUFFER, - srcSourceState = AL_SOURCE_STATE, - srcBuffersQueued = AL_BUFFERS_QUEUED, - srcBuffersProcessed = AL_BUFFERS_PROCESSED, - srcSourceType = AL_SOURCE_TYPE, - - /* ALC_EXT_EFX */ - srcConeOuterGainHF = AL_CONE_OUTER_GAINHF, - srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR, - srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR, - srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO, - srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, - srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, - srcDirectFilter = AL_DIRECT_FILTER, - srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER, - - /* AL_SOFT_direct_channels */ - srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT, - - /* AL_EXT_source_distance_model */ - srcDistanceModel = AL_DISTANCE_MODEL, - - /* AL_SOFT_source_latency */ - srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT, - srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT, - - /* AL_EXT_STEREO_ANGLES */ - srcAngles = AL_STEREO_ANGLES, - - /* AL_EXT_SOURCE_RADIUS */ - srcRadius = AL_SOURCE_RADIUS, - - /* AL_EXT_BFORMAT */ - srcOrientation = AL_ORIENTATION, - - /* AL_SOFT_source_resampler */ - srcResampler = AL_SOURCE_RESAMPLER_SOFT, - - /* AL_SOFT_source_spatialize */ - srcSpatialize = AL_SOURCE_SPATIALIZE_SOFT, - - /* ALC_SOFT_device_clock */ - srcSampleOffsetClockSOFT = AL_SAMPLE_OFFSET_CLOCK_SOFT, - srcSecOffsetClockSOFT = AL_SEC_OFFSET_CLOCK_SOFT, -} SourceProp; - -static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values); -static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values); -static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values); - -static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values); -static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values); -static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values); - -static inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) -{ - ALint idx = source->VoiceIdx; - if(idx >= 0 && idx < context->VoiceCount) - { - ALvoice *voice = context->Voices[idx]; - if(ATOMIC_LOAD(&voice->Source, almemory_order_acquire) == source) - return voice; - } - source->VoiceIdx = -1; - return NULL; -} - -/** - * Returns if the last known state for the source was playing or paused. Does - * not sync with the mixer voice. - */ -static inline bool IsPlayingOrPaused(ALsource *source) -{ return source->state == AL_PLAYING || source->state == AL_PAUSED; } - -/** - * Returns an updated source state using the matching voice's status (or lack - * thereof). - */ -static inline ALenum GetSourceState(ALsource *source, ALvoice *voice) -{ - if(!voice && source->state == AL_PLAYING) - source->state = AL_STOPPED; - return source->state; -} - -/** - * Returns if the source should specify an update, given the context's - * deferring state and the source's last known state. - */ -static inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context) -{ - return !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) && - IsPlayingOrPaused(source); -} - - -/** Can only be called while the mixer is locked! */ -static void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) -{ - AsyncEvent evt = ASYNC_EVENT(EventType_SourceStateChange); - ALbitfieldSOFT enabledevt; - - enabledevt = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); - if(!(enabledevt&EventType_SourceStateChange)) return; - - evt.u.user.type = AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT; - evt.u.user.id = id; - evt.u.user.param = state; - snprintf(evt.u.user.msg, sizeof(evt.u.user.msg), "Source ID %u state changed to %s", id, - (state==AL_INITIAL) ? "AL_INITIAL" : - (state==AL_PLAYING) ? "AL_PLAYING" : - (state==AL_PAUSED) ? "AL_PAUSED" : - (state==AL_STOPPED) ? "AL_STOPPED" : "" - ); - /* The mixer may have queued a state change that's not yet been processed, - * and we don't want state change messages to occur out of order, so send - * it through the async queue to ensure proper ordering. - */ - if(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) == 1) - alsem_post(&context->EventSem); -} - - -static ALint FloatValsByProp(ALenum prop) -{ - if(prop != (ALenum)((SourceProp)prop)) - return 0; - switch((SourceProp)prop) - { - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_REFERENCE_DISTANCE: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_SOURCE_RADIUS: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - return 1; - - case AL_STEREO_ANGLES: - return 2; - - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - return 3; - - case AL_ORIENTATION: - return 6; - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - - case AL_BUFFER: - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - break; /* i/i64 only */ - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; /* i64 only */ - } - return 0; -} -static ALint DoubleValsByProp(ALenum prop) -{ - if(prop != (ALenum)((SourceProp)prop)) - return 0; - switch((SourceProp)prop) - { - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_REFERENCE_DISTANCE: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_SOURCE_RADIUS: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - return 1; - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - case AL_STEREO_ANGLES: - return 2; - - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - return 3; - - case AL_ORIENTATION: - return 6; - - case AL_BUFFER: - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - break; /* i/i64 only */ - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; /* i64 only */ - } - return 0; -} - -static ALint IntValsByProp(ALenum prop) -{ - if(prop != (ALenum)((SourceProp)prop)) - return 0; - switch((SourceProp)prop) - { - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_REFERENCE_DISTANCE: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_BUFFER: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_DIRECT_FILTER: - case AL_SOURCE_RADIUS: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - return 1; - - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - case AL_AUXILIARY_SEND_FILTER: - return 3; - - case AL_ORIENTATION: - return 6; - - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; /* i64 only */ - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - case AL_STEREO_ANGLES: - break; /* Float/double only */ - } - return 0; -} -static ALint Int64ValsByProp(ALenum prop) -{ - if(prop != (ALenum)((SourceProp)prop)) - return 0; - switch((SourceProp)prop) - { - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_REFERENCE_DISTANCE: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_BUFFER: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_DIRECT_FILTER: - case AL_SOURCE_RADIUS: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - return 1; - - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - return 2; - - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - case AL_AUXILIARY_SEND_FILTER: - return 3; - - case AL_ORIENTATION: - return 6; - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - case AL_STEREO_ANGLES: - break; /* Float/double only */ - } - return 0; -} - - -#define CHECKVAL(x) do { \ - if(!(x)) \ - { \ - alSetError(Context, AL_INVALID_VALUE, "Value out of range"); \ - return AL_FALSE; \ - } \ -} while(0) - -#define DO_UPDATEPROPS() do { \ - ALvoice *voice; \ - if(SourceShouldUpdate(Source, Context) && \ - (voice=GetSourceVoice(Source, Context)) != NULL) \ - UpdateSourceProps(Source, voice, device->NumAuxSends, Context); \ - else \ - ATOMIC_STORE(&Source->PropsClean, AL_FALSE, almemory_order_release); \ -} while(0) - -static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values) -{ - ALCdevice *device = Context->Device; - ALint ival; - - switch(prop) - { - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - /* Query only */ - SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, - "Setting read-only source property 0x%04x", prop); - - case AL_PITCH: - CHECKVAL(*values >= 0.0f); - - Source->Pitch = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_CONE_INNER_ANGLE: - CHECKVAL(*values >= 0.0f && *values <= 360.0f); - - Source->InnerAngle = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_CONE_OUTER_ANGLE: - CHECKVAL(*values >= 0.0f && *values <= 360.0f); - - Source->OuterAngle = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_GAIN: - CHECKVAL(*values >= 0.0f); - - Source->Gain = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_MAX_DISTANCE: - CHECKVAL(*values >= 0.0f); - - Source->MaxDistance = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_ROLLOFF_FACTOR: - CHECKVAL(*values >= 0.0f); - - Source->RolloffFactor = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_REFERENCE_DISTANCE: - CHECKVAL(*values >= 0.0f); - - Source->RefDistance = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_MIN_GAIN: - CHECKVAL(*values >= 0.0f); - - Source->MinGain = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_MAX_GAIN: - CHECKVAL(*values >= 0.0f); - - Source->MaxGain = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_CONE_OUTER_GAIN: - CHECKVAL(*values >= 0.0f && *values <= 1.0f); - - Source->OuterGain = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_CONE_OUTER_GAINHF: - CHECKVAL(*values >= 0.0f && *values <= 1.0f); - - Source->OuterGainHF = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_AIR_ABSORPTION_FACTOR: - CHECKVAL(*values >= 0.0f && *values <= 10.0f); - - Source->AirAbsorptionFactor = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_ROOM_ROLLOFF_FACTOR: - CHECKVAL(*values >= 0.0f && *values <= 10.0f); - - Source->RoomRolloffFactor = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_DOPPLER_FACTOR: - CHECKVAL(*values >= 0.0f && *values <= 1.0f); - - Source->DopplerFactor = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - CHECKVAL(*values >= 0.0f); - - Source->OffsetType = prop; - Source->Offset = *values; - - if(IsPlayingOrPaused(Source)) - { - ALvoice *voice; - - ALCdevice_Lock(Context->Device); - /* Double-check that the source is still playing while we have - * the lock. - */ - voice = GetSourceVoice(Source, Context); - if(voice) - { - if(ApplyOffset(Source, voice) == AL_FALSE) - { - ALCdevice_Unlock(Context->Device); - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid offset"); - } - } - ALCdevice_Unlock(Context->Device); - } - return AL_TRUE; - - case AL_SOURCE_RADIUS: - CHECKVAL(*values >= 0.0f && isfinite(*values)); - - Source->Radius = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_STEREO_ANGLES: - CHECKVAL(isfinite(values[0]) && isfinite(values[1])); - - Source->StereoPan[0] = values[0]; - Source->StereoPan[1] = values[1]; - DO_UPDATEPROPS(); - return AL_TRUE; - - - case AL_POSITION: - CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2])); - - Source->Position[0] = values[0]; - Source->Position[1] = values[1]; - Source->Position[2] = values[2]; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_VELOCITY: - CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2])); - - Source->Velocity[0] = values[0]; - Source->Velocity[1] = values[1]; - Source->Velocity[2] = values[2]; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_DIRECTION: - CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2])); - - Source->Direction[0] = values[0]; - Source->Direction[1] = values[1]; - Source->Direction[2] = values[2]; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_ORIENTATION: - CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) && - isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5])); - - Source->Orientation[0][0] = values[0]; - Source->Orientation[0][1] = values[1]; - Source->Orientation[0][2] = values[2]; - Source->Orientation[1][0] = values[3]; - Source->Orientation[1][1] = values[4]; - Source->Orientation[1][2] = values[5]; - DO_UPDATEPROPS(); - return AL_TRUE; - - - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_SOURCE_TYPE: - case AL_DISTANCE_MODEL: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - ival = (ALint)values[0]; - return SetSourceiv(Source, Context, prop, &ival); - - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - ival = (ALint)((ALuint)values[0]); - return SetSourceiv(Source, Context, prop, &ival); - - case AL_BUFFER: - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; - } - - ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source float property 0x%04x", prop); -} - -static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values) -{ - ALCdevice *device = Context->Device; - ALbuffer *buffer = NULL; - ALfilter *filter = NULL; - ALeffectslot *slot = NULL; - ALbufferlistitem *oldlist; - ALfloat fvals[6]; - - switch(prop) - { - case AL_SOURCE_STATE: - case AL_SOURCE_TYPE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - /* Query only */ - SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, - "Setting read-only source property 0x%04x", prop); - - case AL_SOURCE_RELATIVE: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->HeadRelative = (ALboolean)*values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_LOOPING: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->Looping = (ALboolean)*values; - if(IsPlayingOrPaused(Source)) - { - ALvoice *voice = GetSourceVoice(Source, Context); - if(voice) - { - if(Source->Looping) - ATOMIC_STORE(&voice->loop_buffer, Source->queue, almemory_order_release); - else - ATOMIC_STORE(&voice->loop_buffer, NULL, almemory_order_release); - - /* If the source is playing, wait for the current mix to finish - * to ensure it isn't currently looping back or reaching the - * end. - */ - while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) - althrd_yield(); - } - } - return AL_TRUE; - - case AL_BUFFER: - LockBufferList(device); - if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL)) - { - UnlockBufferList(device); - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid buffer ID %u", - *values); - } - - if(buffer && buffer->MappedAccess != 0 && - !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) - { - UnlockBufferList(device); - SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, - "Setting non-persistently mapped buffer %u", buffer->id); - } - else - { - ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context)); - if(state == AL_PLAYING || state == AL_PAUSED) - { - UnlockBufferList(device); - SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, - "Setting buffer on playing or paused source %u", Source->id); - } - } - - oldlist = Source->queue; - if(buffer != NULL) - { - /* Add the selected buffer to a one-item queue */ - ALbufferlistitem *newlist = al_calloc(DEF_ALIGN, - FAM_SIZE(ALbufferlistitem, buffers, 1)); - ATOMIC_INIT(&newlist->next, NULL); - newlist->max_samples = buffer->SampleLen; - newlist->num_buffers = 1; - newlist->buffers[0] = buffer; - IncrementRef(&buffer->ref); - - /* Source is now Static */ - Source->SourceType = AL_STATIC; - Source->queue = newlist; - } - else - { - /* Source is now Undetermined */ - Source->SourceType = AL_UNDETERMINED; - Source->queue = NULL; - } - UnlockBufferList(device); - - /* Delete all elements in the previous queue */ - while(oldlist != NULL) - { - ALsizei i; - ALbufferlistitem *temp = oldlist; - oldlist = ATOMIC_LOAD(&temp->next, almemory_order_relaxed); - - for(i = 0;i < temp->num_buffers;i++) - { - if(temp->buffers[i]) - DecrementRef(&temp->buffers[i]->ref); - } - al_free(temp); - } - return AL_TRUE; - - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - CHECKVAL(*values >= 0); - - Source->OffsetType = prop; - Source->Offset = *values; - - if(IsPlayingOrPaused(Source)) - { - ALvoice *voice; - - ALCdevice_Lock(Context->Device); - voice = GetSourceVoice(Source, Context); - if(voice) - { - if(ApplyOffset(Source, voice) == AL_FALSE) - { - ALCdevice_Unlock(Context->Device); - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, - "Invalid source offset"); - } - } - ALCdevice_Unlock(Context->Device); - } - return AL_TRUE; - - case AL_DIRECT_FILTER: - LockFilterList(device); - if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL)) - { - UnlockFilterList(device); - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", - *values); - } - - if(!filter) - { - Source->Direct.Gain = 1.0f; - Source->Direct.GainHF = 1.0f; - Source->Direct.HFReference = LOWPASSFREQREF; - Source->Direct.GainLF = 1.0f; - Source->Direct.LFReference = HIGHPASSFREQREF; - } - else - { - Source->Direct.Gain = filter->Gain; - Source->Direct.GainHF = filter->GainHF; - Source->Direct.HFReference = filter->HFReference; - Source->Direct.GainLF = filter->GainLF; - Source->Direct.LFReference = filter->LFReference; - } - UnlockFilterList(device); - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_DIRECT_FILTER_GAINHF_AUTO: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->DryGainHFAuto = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->WetGainAuto = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->WetGainHFAuto = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_DIRECT_CHANNELS_SOFT: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->DirectChannels = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_DISTANCE_MODEL: - CHECKVAL(*values == AL_NONE || - *values == AL_INVERSE_DISTANCE || - *values == AL_INVERSE_DISTANCE_CLAMPED || - *values == AL_LINEAR_DISTANCE || - *values == AL_LINEAR_DISTANCE_CLAMPED || - *values == AL_EXPONENT_DISTANCE || - *values == AL_EXPONENT_DISTANCE_CLAMPED); - - Source->DistanceModel = *values; - if(Context->SourceDistanceModel) - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_SOURCE_RESAMPLER_SOFT: - CHECKVAL(*values >= 0 && *values <= ResamplerMax); - - Source->Resampler = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - case AL_SOURCE_SPATIALIZE_SOFT: - CHECKVAL(*values >= AL_FALSE && *values <= AL_AUTO_SOFT); - - Source->Spatialize = *values; - DO_UPDATEPROPS(); - return AL_TRUE; - - - case AL_AUXILIARY_SEND_FILTER: - LockEffectSlotList(Context); - if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL)) - { - UnlockEffectSlotList(Context); - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid effect ID %u", - values[0]); - } - if((ALuint)values[1] >= (ALuint)device->NumAuxSends) - { - UnlockEffectSlotList(Context); - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid send %u", values[1]); - } - LockFilterList(device); - if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)) - { - UnlockFilterList(device); - UnlockEffectSlotList(Context); - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", - values[2]); - } - - if(!filter) - { - /* Disable filter */ - Source->Send[values[1]].Gain = 1.0f; - Source->Send[values[1]].GainHF = 1.0f; - Source->Send[values[1]].HFReference = LOWPASSFREQREF; - Source->Send[values[1]].GainLF = 1.0f; - Source->Send[values[1]].LFReference = HIGHPASSFREQREF; - } - else - { - Source->Send[values[1]].Gain = filter->Gain; - Source->Send[values[1]].GainHF = filter->GainHF; - Source->Send[values[1]].HFReference = filter->HFReference; - Source->Send[values[1]].GainLF = filter->GainLF; - Source->Send[values[1]].LFReference = filter->LFReference; - } - UnlockFilterList(device); - - if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source)) - { - ALvoice *voice; - /* Add refcount on the new slot, and release the previous slot */ - if(slot) IncrementRef(&slot->ref); - if(Source->Send[values[1]].Slot) - DecrementRef(&Source->Send[values[1]].Slot->ref); - Source->Send[values[1]].Slot = slot; - - /* We must force an update if the auxiliary slot changed on an - * active source, in case the slot is about to be deleted. - */ - if((voice=GetSourceVoice(Source, Context)) != NULL) - UpdateSourceProps(Source, voice, device->NumAuxSends, Context); - else - ATOMIC_STORE(&Source->PropsClean, AL_FALSE, almemory_order_release); - } - else - { - if(slot) IncrementRef(&slot->ref); - if(Source->Send[values[1]].Slot) - DecrementRef(&Source->Send[values[1]].Slot->ref); - Source->Send[values[1]].Slot = slot; - DO_UPDATEPROPS(); - } - UnlockEffectSlotList(Context); - - return AL_TRUE; - - - /* 1x float */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_SOURCE_RADIUS: - fvals[0] = (ALfloat)*values; - return SetSourcefv(Source, Context, (int)prop, fvals); - - /* 3x float */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - fvals[0] = (ALfloat)values[0]; - fvals[1] = (ALfloat)values[1]; - fvals[2] = (ALfloat)values[2]; - return SetSourcefv(Source, Context, (int)prop, fvals); - - /* 6x float */ - case AL_ORIENTATION: - fvals[0] = (ALfloat)values[0]; - fvals[1] = (ALfloat)values[1]; - fvals[2] = (ALfloat)values[2]; - fvals[3] = (ALfloat)values[3]; - fvals[4] = (ALfloat)values[4]; - fvals[5] = (ALfloat)values[5]; - return SetSourcefv(Source, Context, (int)prop, fvals); - - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - case AL_STEREO_ANGLES: - break; - } - - ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x", - prop); -} - -static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values) -{ - ALfloat fvals[6]; - ALint ivals[3]; - - switch(prop) - { - case AL_SOURCE_TYPE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_STATE: - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - /* Query only */ - SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, - "Setting read-only source property 0x%04x", prop); - - /* 1x int */ - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - CHECKVAL(*values <= INT_MAX && *values >= INT_MIN); - - ivals[0] = (ALint)*values; - return SetSourceiv(Source, Context, (int)prop, ivals); - - /* 1x uint */ - case AL_BUFFER: - case AL_DIRECT_FILTER: - CHECKVAL(*values <= UINT_MAX && *values >= 0); - - ivals[0] = (ALuint)*values; - return SetSourceiv(Source, Context, (int)prop, ivals); - - /* 3x uint */ - case AL_AUXILIARY_SEND_FILTER: - CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 && - values[1] <= UINT_MAX && values[1] >= 0 && - values[2] <= UINT_MAX && values[2] >= 0); - - ivals[0] = (ALuint)values[0]; - ivals[1] = (ALuint)values[1]; - ivals[2] = (ALuint)values[2]; - return SetSourceiv(Source, Context, (int)prop, ivals); - - /* 1x float */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_SOURCE_RADIUS: - fvals[0] = (ALfloat)*values; - return SetSourcefv(Source, Context, (int)prop, fvals); - - /* 3x float */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - fvals[0] = (ALfloat)values[0]; - fvals[1] = (ALfloat)values[1]; - fvals[2] = (ALfloat)values[2]; - return SetSourcefv(Source, Context, (int)prop, fvals); - - /* 6x float */ - case AL_ORIENTATION: - fvals[0] = (ALfloat)values[0]; - fvals[1] = (ALfloat)values[1]; - fvals[2] = (ALfloat)values[2]; - fvals[3] = (ALfloat)values[3]; - fvals[4] = (ALfloat)values[4]; - fvals[5] = (ALfloat)values[5]; - return SetSourcefv(Source, Context, (int)prop, fvals); - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - case AL_STEREO_ANGLES: - break; - } - - ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x", - prop); -} - -#undef CHECKVAL - - -static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values) -{ - ALCdevice *device = Context->Device; - ClockLatency clocktime; - ALuint64 srcclock; - ALint ivals[3]; - ALboolean err; - - switch(prop) - { - case AL_GAIN: - *values = Source->Gain; - return AL_TRUE; - - case AL_PITCH: - *values = Source->Pitch; - return AL_TRUE; - - case AL_MAX_DISTANCE: - *values = Source->MaxDistance; - return AL_TRUE; - - case AL_ROLLOFF_FACTOR: - *values = Source->RolloffFactor; - return AL_TRUE; - - case AL_REFERENCE_DISTANCE: - *values = Source->RefDistance; - return AL_TRUE; - - case AL_CONE_INNER_ANGLE: - *values = Source->InnerAngle; - return AL_TRUE; - - case AL_CONE_OUTER_ANGLE: - *values = Source->OuterAngle; - return AL_TRUE; - - case AL_MIN_GAIN: - *values = Source->MinGain; - return AL_TRUE; - - case AL_MAX_GAIN: - *values = Source->MaxGain; - return AL_TRUE; - - case AL_CONE_OUTER_GAIN: - *values = Source->OuterGain; - return AL_TRUE; - - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - *values = GetSourceOffset(Source, prop, Context); - return AL_TRUE; - - case AL_CONE_OUTER_GAINHF: - *values = Source->OuterGainHF; - return AL_TRUE; - - case AL_AIR_ABSORPTION_FACTOR: - *values = Source->AirAbsorptionFactor; - return AL_TRUE; - - case AL_ROOM_ROLLOFF_FACTOR: - *values = Source->RoomRolloffFactor; - return AL_TRUE; - - case AL_DOPPLER_FACTOR: - *values = Source->DopplerFactor; - return AL_TRUE; - - case AL_SOURCE_RADIUS: - *values = Source->Radius; - return AL_TRUE; - - case AL_STEREO_ANGLES: - values[0] = Source->StereoPan[0]; - values[1] = Source->StereoPan[1]; - return AL_TRUE; - - case AL_SEC_OFFSET_LATENCY_SOFT: - /* Get the source offset with the clock time first. Then get the - * clock time with the device latency. Order is important. - */ - values[0] = GetSourceSecOffset(Source, Context, &srcclock); - almtx_lock(&device->BackendLock); - clocktime = GetClockLatency(device); - almtx_unlock(&device->BackendLock); - if(srcclock == (ALuint64)clocktime.ClockTime) - values[1] = (ALdouble)clocktime.Latency / 1000000000.0; - else - { - /* If the clock time incremented, reduce the latency by that - * much since it's that much closer to the source offset it got - * earlier. - */ - ALuint64 diff = clocktime.ClockTime - srcclock; - values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) / - 1000000000.0; - } - return AL_TRUE; - - case AL_SEC_OFFSET_CLOCK_SOFT: - values[0] = GetSourceSecOffset(Source, Context, &srcclock); - values[1] = srcclock / 1000000000.0; - return AL_TRUE; - - case AL_POSITION: - values[0] = Source->Position[0]; - values[1] = Source->Position[1]; - values[2] = Source->Position[2]; - return AL_TRUE; - - case AL_VELOCITY: - values[0] = Source->Velocity[0]; - values[1] = Source->Velocity[1]; - values[2] = Source->Velocity[2]; - return AL_TRUE; - - case AL_DIRECTION: - values[0] = Source->Direction[0]; - values[1] = Source->Direction[1]; - values[2] = Source->Direction[2]; - return AL_TRUE; - - case AL_ORIENTATION: - values[0] = Source->Orientation[0][0]; - values[1] = Source->Orientation[0][1]; - values[2] = Source->Orientation[0][2]; - values[3] = Source->Orientation[1][0]; - values[4] = Source->Orientation[1][1]; - values[5] = Source->Orientation[1][2]; - return AL_TRUE; - - /* 1x int */ - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE) - *values = (ALdouble)ivals[0]; - return err; - - case AL_BUFFER: - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; - } - - ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source double property 0x%04x", - prop); -} - -static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values) -{ - ALbufferlistitem *BufferList; - ALdouble dvals[6]; - ALboolean err; - - switch(prop) - { - case AL_SOURCE_RELATIVE: - *values = Source->HeadRelative; - return AL_TRUE; - - case AL_LOOPING: - *values = Source->Looping; - return AL_TRUE; - - case AL_BUFFER: - BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : NULL; - *values = (BufferList && BufferList->num_buffers >= 1 && BufferList->buffers[0]) ? - BufferList->buffers[0]->id : 0; - return AL_TRUE; - - case AL_SOURCE_STATE: - *values = GetSourceState(Source, GetSourceVoice(Source, Context)); - return AL_TRUE; - - case AL_BUFFERS_QUEUED: - if(!(BufferList=Source->queue)) - *values = 0; - else - { - ALsizei count = 0; - do { - count += BufferList->num_buffers; - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); - } while(BufferList != NULL); - *values = count; - } - return AL_TRUE; - - case AL_BUFFERS_PROCESSED: - if(Source->Looping || Source->SourceType != AL_STREAMING) - { - /* Buffers on a looping source are in a perpetual state of - * PENDING, so don't report any as PROCESSED */ - *values = 0; - } - else - { - const ALbufferlistitem *BufferList = Source->queue; - const ALbufferlistitem *Current = NULL; - ALsizei played = 0; - ALvoice *voice; - - if((voice=GetSourceVoice(Source, Context)) != NULL) - Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - else if(Source->state == AL_INITIAL) - Current = BufferList; - - while(BufferList && BufferList != Current) - { - played += BufferList->num_buffers; - BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, - almemory_order_relaxed); - } - *values = played; - } - return AL_TRUE; - - case AL_SOURCE_TYPE: - *values = Source->SourceType; - return AL_TRUE; - - case AL_DIRECT_FILTER_GAINHF_AUTO: - *values = Source->DryGainHFAuto; - return AL_TRUE; - - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - *values = Source->WetGainAuto; - return AL_TRUE; - - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - *values = Source->WetGainHFAuto; - return AL_TRUE; - - case AL_DIRECT_CHANNELS_SOFT: - *values = Source->DirectChannels; - return AL_TRUE; - - case AL_DISTANCE_MODEL: - *values = Source->DistanceModel; - return AL_TRUE; - - case AL_SOURCE_RESAMPLER_SOFT: - *values = Source->Resampler; - return AL_TRUE; - - case AL_SOURCE_SPATIALIZE_SOFT: - *values = Source->Spatialize; - return AL_TRUE; - - /* 1x float/double */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_DOPPLER_FACTOR: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_SOURCE_RADIUS: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - *values = (ALint)dvals[0]; - return err; - - /* 3x float/double */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - { - values[0] = (ALint)dvals[0]; - values[1] = (ALint)dvals[1]; - values[2] = (ALint)dvals[2]; - } - return err; - - /* 6x float/double */ - case AL_ORIENTATION: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - { - values[0] = (ALint)dvals[0]; - values[1] = (ALint)dvals[1]; - values[2] = (ALint)dvals[2]; - values[3] = (ALint)dvals[3]; - values[4] = (ALint)dvals[4]; - values[5] = (ALint)dvals[5]; - } - return err; - - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; /* i64 only */ - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - case AL_STEREO_ANGLES: - break; /* Float/double only */ - - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - break; /* ??? */ - } - - ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x", - prop); -} - -static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values) -{ - ALCdevice *device = Context->Device; - ClockLatency clocktime; - ALuint64 srcclock; - ALdouble dvals[6]; - ALint ivals[3]; - ALboolean err; - - switch(prop) - { - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - /* Get the source offset with the clock time first. Then get the - * clock time with the device latency. Order is important. - */ - values[0] = GetSourceSampleOffset(Source, Context, &srcclock); - almtx_lock(&device->BackendLock); - clocktime = GetClockLatency(device); - almtx_unlock(&device->BackendLock); - if(srcclock == (ALuint64)clocktime.ClockTime) - values[1] = clocktime.Latency; - else - { - /* If the clock time incremented, reduce the latency by that - * much since it's that much closer to the source offset it got - * earlier. - */ - ALuint64 diff = clocktime.ClockTime - srcclock; - values[1] = clocktime.Latency - minu64(clocktime.Latency, diff); - } - return AL_TRUE; - - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - values[0] = GetSourceSampleOffset(Source, Context, &srcclock); - values[1] = srcclock; - return AL_TRUE; - - /* 1x float/double */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_DOPPLER_FACTOR: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_SOURCE_RADIUS: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - *values = (ALint64)dvals[0]; - return err; - - /* 3x float/double */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - { - values[0] = (ALint64)dvals[0]; - values[1] = (ALint64)dvals[1]; - values[2] = (ALint64)dvals[2]; - } - return err; - - /* 6x float/double */ - case AL_ORIENTATION: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - { - values[0] = (ALint64)dvals[0]; - values[1] = (ALint64)dvals[1]; - values[2] = (ALint64)dvals[2]; - values[3] = (ALint64)dvals[3]; - values[4] = (ALint64)dvals[4]; - values[5] = (ALint64)dvals[5]; - } - return err; - - /* 1x int */ - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) - *values = ivals[0]; - return err; - - /* 1x uint */ - case AL_BUFFER: - case AL_DIRECT_FILTER: - if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) - *values = (ALuint)ivals[0]; - return err; - - /* 3x uint */ - case AL_AUXILIARY_SEND_FILTER: - if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) - { - values[0] = (ALuint)ivals[0]; - values[1] = (ALuint)ivals[1]; - values[2] = (ALuint)ivals[2]; - } - return err; - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - case AL_STEREO_ANGLES: - break; /* Float/double only */ - } - - ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x", - prop); -} - - -AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) -{ - ALCcontext *context; - ALsizei cur = 0; - - context = GetContextRef(); - if(!context) return; - - if(n < 0) - alSetError(context, AL_INVALID_VALUE, "Generating %d sources", n); - else for(cur = 0;cur < n;cur++) - { - ALsource *source = AllocSource(context); - if(!source) - { - alDeleteSources(cur, sources); - break; - } - sources[cur] = source->id; - } - - ALCcontext_DecRef(context); -} - - -AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) -{ - ALCcontext *context; - ALsource *Source; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - LockSourceList(context); - if(n < 0) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d sources", n); - - /* Check that all Sources are valid */ - for(i = 0;i < n;i++) - { - if(LookupSource(context, sources[i]) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); - } - for(i = 0;i < n;i++) - { - if((Source=LookupSource(context, sources[i])) != NULL) - FreeSource(context, Source); - } - -done: - UnlockSourceList(context); - ALCcontext_DecRef(context); -} - - -AL_API ALboolean AL_APIENTRY alIsSource(ALuint source) -{ - ALCcontext *context; - ALboolean ret; - - context = GetContextRef(); - if(!context) return AL_FALSE; - - LockSourceList(context); - ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE); - UnlockSourceList(context); - - ALCcontext_DecRef(context); - - return ret; -} - - -AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(FloatValsByProp(param) != 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid float property 0x%04x", param); - else - SetSourcefv(Source, Context, param, &value); - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(FloatValsByProp(param) != 3) - alSetError(Context, AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); - else - { - ALfloat fvals[3] = { value1, value2, value3 }; - SetSourcefv(Source, Context, param, fvals); - } - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(FloatValsByProp(param) < 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); - else - SetSourcefv(Source, Context, param, values); - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); -} - - -AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(DoubleValsByProp(param) != 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid double property 0x%04x", param); - else - { - ALfloat fval = (ALfloat)value; - SetSourcefv(Source, Context, param, &fval); - } - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(DoubleValsByProp(param) != 3) - alSetError(Context, AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); - else - { - ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 }; - SetSourcefv(Source, Context, param, fvals); - } - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values) -{ - ALCcontext *Context; - ALsource *Source; - ALint count; - - Context = GetContextRef(); - if(!Context) return; - - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if((count=DoubleValsByProp(param)) < 1 || count > 6) - alSetError(Context, AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); - else - { - ALfloat fvals[6]; - ALint i; - - for(i = 0;i < count;i++) - fvals[i] = (ALfloat)values[i]; - SetSourcefv(Source, Context, param, fvals); - } - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); -} - - -AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(IntValsByProp(param) != 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); - else - SetSourceiv(Source, Context, param, &value); - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); -} - -AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(IntValsByProp(param) != 3) - alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); - else - { - ALint ivals[3] = { value1, value2, value3 }; - SetSourceiv(Source, Context, param, ivals); - } - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); -} - -AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(IntValsByProp(param) < 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); - else - SetSourceiv(Source, Context, param, values); - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); -} - - -AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(Int64ValsByProp(param) != 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); - else - SetSourcei64v(Source, Context, param, &value); - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); -} - -AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(Int64ValsByProp(param) != 3) - alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); - else - { - ALint64SOFT i64vals[3] = { value1, value2, value3 }; - SetSourcei64v(Source, Context, param, i64vals); - } - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); -} - -AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(Int64ValsByProp(param) < 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); - else - SetSourcei64v(Source, Context, param, values); - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); -} - - -AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(FloatValsByProp(param) != 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid float property 0x%04x", param); - else - { - ALdouble dval; - if(GetSourcedv(Source, Context, param, &dval)) - *value = (ALfloat)dval; - } - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); -} - - -AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(FloatValsByProp(param) != 3) - alSetError(Context, AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); - else - { - ALdouble dvals[3]; - if(GetSourcedv(Source, Context, param, dvals)) - { - *value1 = (ALfloat)dvals[0]; - *value2 = (ALfloat)dvals[1]; - *value3 = (ALfloat)dvals[2]; - } - } - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); -} - - -AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values) -{ - ALCcontext *Context; - ALsource *Source; - ALint count; - - Context = GetContextRef(); - if(!Context) return; - - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if((count=FloatValsByProp(param)) < 1 && count > 6) - alSetError(Context, AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); - else - { - ALdouble dvals[6]; - if(GetSourcedv(Source, Context, param, dvals)) - { - ALint i; - for(i = 0;i < count;i++) - values[i] = (ALfloat)dvals[i]; - } - } - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); -} - - -AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(DoubleValsByProp(param) != 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid double property 0x%04x", param); - else - GetSourcedv(Source, Context, param, value); - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); -} - -AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(DoubleValsByProp(param) != 3) - alSetError(Context, AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); - else - { - ALdouble dvals[3]; - if(GetSourcedv(Source, Context, param, dvals)) - { - *value1 = dvals[0]; - *value2 = dvals[1]; - *value3 = dvals[2]; - } - } - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); -} - -AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(DoubleValsByProp(param) < 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); - else - GetSourcedv(Source, Context, param, values); - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); -} - - -AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(IntValsByProp(param) != 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); - else - GetSourceiv(Source, Context, param, value); - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); -} - - -AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(IntValsByProp(param) != 3) - alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); - else - { - ALint ivals[3]; - if(GetSourceiv(Source, Context, param, ivals)) - { - *value1 = ivals[0]; - *value2 = ivals[1]; - *value3 = ivals[2]; - } - } - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); -} - - -AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(IntValsByProp(param) < 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); - else - GetSourceiv(Source, Context, param, values); - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); -} - - -AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(Int64ValsByProp(param) != 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); - else - GetSourcei64v(Source, Context, param, value); - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); -} - -AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(Int64ValsByProp(param) != 3) - alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); - else - { - ALint64 i64vals[3]; - if(GetSourcei64v(Source, Context, param, i64vals)) - { - *value1 = i64vals[0]; - *value2 = i64vals[1]; - *value3 = i64vals[2]; - } - } - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); -} - -AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if(Int64ValsByProp(param) < 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); - else - GetSourcei64v(Source, Context, param, values); - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); -} - - -AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source) -{ - alSourcePlayv(1, &source); -} -AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) -{ - ALCcontext *context; - ALCdevice *device; - ALsource *source; - ALvoice *voice; - ALsizei i, j; - - context = GetContextRef(); - if(!context) return; - - LockSourceList(context); - if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Playing %d sources", n); - for(i = 0;i < n;i++) - { - if(!LookupSource(context, sources[i])) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); - } - - device = context->Device; - ALCdevice_Lock(device); - /* If the device is disconnected, go right to stopped. */ - if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) - { - /* TODO: Send state change event? */ - for(i = 0;i < n;i++) - { - source = LookupSource(context, sources[i]); - source->OffsetType = AL_NONE; - source->Offset = 0.0; - source->state = AL_STOPPED; - } - ALCdevice_Unlock(device); - goto done; - } - - while(n > context->MaxVoices-context->VoiceCount) - { - ALsizei newcount = context->MaxVoices << 1; - if(context->MaxVoices >= newcount) - { - ALCdevice_Unlock(device); - SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, - "Overflow increasing voice count %d -> %d", context->MaxVoices, newcount); - } - AllocateVoices(context, newcount, device->NumAuxSends); - } - - for(i = 0;i < n;i++) - { - ALbufferlistitem *BufferList; - bool start_fading = false; - ALint vidx = -1; - - source = LookupSource(context, sources[i]); - /* Check that there is a queue containing at least one valid, non zero - * length buffer. - */ - BufferList = source->queue; - while(BufferList && BufferList->max_samples == 0) - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); - - /* If there's nothing to play, go right to stopped. */ - if(UNLIKELY(!BufferList)) - { - /* NOTE: A source without any playable buffers should not have an - * ALvoice since it shouldn't be in a playing or paused state. So - * there's no need to look up its voice and clear the source. - */ - ALenum oldstate = GetSourceState(source, NULL); - source->OffsetType = AL_NONE; - source->Offset = 0.0; - if(oldstate != AL_STOPPED) - { - source->state = AL_STOPPED; - SendStateChangeEvent(context, source->id, AL_STOPPED); - } - continue; - } - - voice = GetSourceVoice(source, context); - switch(GetSourceState(source, voice)) - { - case AL_PLAYING: - assert(voice != NULL); - /* A source that's already playing is restarted from the beginning. */ - ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); - ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed); - ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release); - continue; - - case AL_PAUSED: - assert(voice != NULL); - /* A source that's paused simply resumes. */ - ATOMIC_STORE(&voice->Playing, true, almemory_order_release); - source->state = AL_PLAYING; - SendStateChangeEvent(context, source->id, AL_PLAYING); - continue; - - default: - break; - } - - /* Look for an unused voice to play this source with. */ - assert(voice == NULL); - for(j = 0;j < context->VoiceCount;j++) - { - if(ATOMIC_LOAD(&context->Voices[j]->Source, almemory_order_acquire) == NULL) - { - vidx = j; - break; - } - } - if(vidx == -1) - vidx = context->VoiceCount++; - voice = context->Voices[vidx]; - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - - ATOMIC_EXCHANGE(&source->PropsClean, AL_TRUE, almemory_order_acquire); - UpdateSourceProps(source, voice, device->NumAuxSends, context); - - /* A source that's not playing or paused has any offset applied when it - * starts playing. - */ - if(source->Looping) - ATOMIC_STORE(&voice->loop_buffer, source->queue, almemory_order_relaxed); - else - ATOMIC_STORE(&voice->loop_buffer, NULL, almemory_order_relaxed); - ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); - ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed); - ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed); - if(ApplyOffset(source, voice) != AL_FALSE) - start_fading = ATOMIC_LOAD(&voice->position, almemory_order_relaxed) != 0 || - ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) != 0 || - ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed) != BufferList; - - for(j = 0;j < BufferList->num_buffers;j++) - { - ALbuffer *buffer = BufferList->buffers[j]; - if(buffer) - { - voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels); - voice->SampleSize = BytesFromFmt(buffer->FmtType); - break; - } - } - - /* Clear previous samples. */ - memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples)); - - /* Clear the stepping value so the mixer knows not to mix this until - * the update gets applied. - */ - voice->Step = 0; - - voice->Flags = start_fading ? VOICE_IS_FADING : 0; - if(source->SourceType == AL_STATIC) voice->Flags |= VOICE_IS_STATIC; - memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])*voice->NumChannels); - for(j = 0;j < device->NumAuxSends;j++) - memset(voice->Send[j].Params, 0, sizeof(voice->Send[j].Params[0])*voice->NumChannels); - if(device->AvgSpeakerDist > 0.0f) - { - ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / - (device->AvgSpeakerDist * device->Frequency); - for(j = 0;j < voice->NumChannels;j++) - NfcFilterCreate(&voice->Direct.Params[j].NFCtrlFilter, 0.0f, w1); - } - - ATOMIC_STORE(&voice->Source, source, almemory_order_relaxed); - ATOMIC_STORE(&voice->Playing, true, almemory_order_release); - source->state = AL_PLAYING; - source->VoiceIdx = vidx; - - SendStateChangeEvent(context, source->id, AL_PLAYING); - } - ALCdevice_Unlock(device); - -done: - UnlockSourceList(context); - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source) -{ - alSourcePausev(1, &source); -} -AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) -{ - ALCcontext *context; - ALCdevice *device; - ALsource *source; - ALvoice *voice; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - LockSourceList(context); - if(n < 0) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Pausing %d sources", n); - for(i = 0;i < n;i++) - { - if(!LookupSource(context, sources[i])) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); - } - - device = context->Device; - ALCdevice_Lock(device); - for(i = 0;i < n;i++) - { - source = LookupSource(context, sources[i]); - if((voice=GetSourceVoice(source, context)) != NULL) - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - if(GetSourceState(source, voice) == AL_PLAYING) - { - source->state = AL_PAUSED; - SendStateChangeEvent(context, source->id, AL_PAUSED); - } - } - ALCdevice_Unlock(device); - -done: - UnlockSourceList(context); - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source) -{ - alSourceStopv(1, &source); -} -AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) -{ - ALCcontext *context; - ALCdevice *device; - ALsource *source; - ALvoice *voice; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - LockSourceList(context); - if(n < 0) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Stopping %d sources", n); - for(i = 0;i < n;i++) - { - if(!LookupSource(context, sources[i])) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); - } - - device = context->Device; - ALCdevice_Lock(device); - for(i = 0;i < n;i++) - { - ALenum oldstate; - source = LookupSource(context, sources[i]); - if((voice=GetSourceVoice(source, context)) != NULL) - { - ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - voice = NULL; - } - oldstate = GetSourceState(source, voice); - if(oldstate != AL_INITIAL && oldstate != AL_STOPPED) - { - source->state = AL_STOPPED; - SendStateChangeEvent(context, source->id, AL_STOPPED); - } - source->OffsetType = AL_NONE; - source->Offset = 0.0; - } - ALCdevice_Unlock(device); - -done: - UnlockSourceList(context); - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source) -{ - alSourceRewindv(1, &source); -} -AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) -{ - ALCcontext *context; - ALCdevice *device; - ALsource *source; - ALvoice *voice; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - LockSourceList(context); - if(n < 0) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Rewinding %d sources", n); - for(i = 0;i < n;i++) - { - if(!LookupSource(context, sources[i])) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); - } - - device = context->Device; - ALCdevice_Lock(device); - for(i = 0;i < n;i++) - { - source = LookupSource(context, sources[i]); - if((voice=GetSourceVoice(source, context)) != NULL) - { - ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - voice = NULL; - } - if(GetSourceState(source, voice) != AL_INITIAL) - { - source->state = AL_INITIAL; - SendStateChangeEvent(context, source->id, AL_INITIAL); - } - source->OffsetType = AL_NONE; - source->Offset = 0.0; - } - ALCdevice_Unlock(device); - -done: - UnlockSourceList(context); - ALCcontext_DecRef(context); -} - - -AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers) -{ - ALCdevice *device; - ALCcontext *context; - ALsource *source; - ALsizei i; - ALbufferlistitem *BufferListStart; - ALbufferlistitem *BufferList; - ALbuffer *BufferFmt = NULL; - - if(nb == 0) - return; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - - LockSourceList(context); - if(!(nb >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Queueing %d buffers", nb); - if((source=LookupSource(context, src)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src); - - if(source->SourceType == AL_STATIC) - { - /* Can't queue on a Static Source */ - SETERR_GOTO(context, AL_INVALID_OPERATION, done, "Queueing onto static source %u", src); - } - - /* Check for a valid Buffer, for its frequency and format */ - BufferList = source->queue; - while(BufferList) - { - for(i = 0;i < BufferList->num_buffers;i++) - { - if((BufferFmt=BufferList->buffers[i]) != NULL) - break; - } - if(BufferFmt) break; - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); - } - - LockBufferList(device); - BufferListStart = NULL; - BufferList = NULL; - for(i = 0;i < nb;i++) - { - ALbuffer *buffer = NULL; - if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer_error, "Queueing invalid buffer ID %u", - buffers[i]); - - if(!BufferListStart) - { - BufferListStart = al_calloc(DEF_ALIGN, - FAM_SIZE(ALbufferlistitem, buffers, 1)); - BufferList = BufferListStart; - } - else - { - ALbufferlistitem *item = al_calloc(DEF_ALIGN, - FAM_SIZE(ALbufferlistitem, buffers, 1)); - ATOMIC_STORE(&BufferList->next, item, almemory_order_relaxed); - BufferList = item; - } - ATOMIC_INIT(&BufferList->next, NULL); - BufferList->max_samples = buffer ? buffer->SampleLen : 0; - BufferList->num_buffers = 1; - BufferList->buffers[0] = buffer; - if(!buffer) continue; - - IncrementRef(&buffer->ref); - - if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) - SETERR_GOTO(context, AL_INVALID_OPERATION, buffer_error, - "Queueing non-persistently mapped buffer %u", buffer->id); - - if(BufferFmt == NULL) - BufferFmt = buffer; - else if(BufferFmt->Frequency != buffer->Frequency || - BufferFmt->FmtChannels != buffer->FmtChannels || - BufferFmt->OriginalType != buffer->OriginalType) - { - alSetError(context, AL_INVALID_OPERATION, "Queueing buffer with mismatched format"); - - buffer_error: - /* A buffer failed (invalid ID or format), so unlock and release - * each buffer we had. */ - while(BufferListStart) - { - ALbufferlistitem *next = ATOMIC_LOAD(&BufferListStart->next, - almemory_order_relaxed); - for(i = 0;i < BufferListStart->num_buffers;i++) - { - if((buffer=BufferListStart->buffers[i]) != NULL) - DecrementRef(&buffer->ref); - } - al_free(BufferListStart); - BufferListStart = next; - } - UnlockBufferList(device); - goto done; - } - } - /* All buffers good. */ - UnlockBufferList(device); - - /* Source is now streaming */ - source->SourceType = AL_STREAMING; - - if(!(BufferList=source->queue)) - source->queue = BufferListStart; - else - { - ALbufferlistitem *next; - while((next=ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed)) != NULL) - BufferList = next; - ATOMIC_STORE(&BufferList->next, BufferListStart, almemory_order_release); - } - -done: - UnlockSourceList(context); - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers) -{ - ALCdevice *device; - ALCcontext *context; - ALbufferlistitem *BufferListStart; - ALbufferlistitem *BufferList; - ALbuffer *BufferFmt = NULL; - ALsource *source; - ALsizei i; - - if(nb == 0) - return; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - - LockSourceList(context); - if(!(nb >= 0 && nb < 16)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Queueing %d buffer layers", nb); - if((source=LookupSource(context, src)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src); - - if(source->SourceType == AL_STATIC) - { - /* Can't queue on a Static Source */ - SETERR_GOTO(context, AL_INVALID_OPERATION, done, "Queueing onto static source %u", src); - } - - /* Check for a valid Buffer, for its frequency and format */ - BufferList = source->queue; - while(BufferList) - { - for(i = 0;i < BufferList->num_buffers;i++) - { - if((BufferFmt=BufferList->buffers[i]) != NULL) - break; - } - if(BufferFmt) break; - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); - } - - LockBufferList(device); - BufferListStart = al_calloc(DEF_ALIGN, FAM_SIZE(ALbufferlistitem, buffers, nb)); - BufferList = BufferListStart; - ATOMIC_INIT(&BufferList->next, NULL); - BufferList->max_samples = 0; - BufferList->num_buffers = 0; - for(i = 0;i < nb;i++) - { - ALbuffer *buffer = NULL; - if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer_error, "Queueing invalid buffer ID %u", - buffers[i]); - - BufferList->buffers[BufferList->num_buffers++] = buffer; - if(!buffer) continue; - - IncrementRef(&buffer->ref); - - BufferList->max_samples = maxi(BufferList->max_samples, buffer->SampleLen); - - if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) - SETERR_GOTO(context, AL_INVALID_OPERATION, buffer_error, - "Queueing non-persistently mapped buffer %u", buffer->id); - - if(BufferFmt == NULL) - BufferFmt = buffer; - else if(BufferFmt->Frequency != buffer->Frequency || - BufferFmt->FmtChannels != buffer->FmtChannels || - BufferFmt->OriginalType != buffer->OriginalType) - { - alSetError(context, AL_INVALID_OPERATION, "Queueing buffer with mismatched format"); - - buffer_error: - /* A buffer failed (invalid ID or format), so unlock and release - * each buffer we had. */ - while(BufferListStart) - { - ALbufferlistitem *next = ATOMIC_LOAD(&BufferListStart->next, - almemory_order_relaxed); - for(i = 0;i < BufferListStart->num_buffers;i++) - { - if((buffer=BufferListStart->buffers[i]) != NULL) - DecrementRef(&buffer->ref); - } - al_free(BufferListStart); - BufferListStart = next; - } - UnlockBufferList(device); - goto done; - } - } - /* All buffers good. */ - UnlockBufferList(device); - - /* Source is now streaming */ - source->SourceType = AL_STREAMING; - - if(!(BufferList=source->queue)) - source->queue = BufferListStart; - else - { - ALbufferlistitem *next; - while((next=ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed)) != NULL) - BufferList = next; - ATOMIC_STORE(&BufferList->next, BufferListStart, almemory_order_release); - } - -done: - UnlockSourceList(context); - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers) -{ - ALCcontext *context; - ALsource *source; - ALbufferlistitem *BufferList; - ALbufferlistitem *Current; - ALvoice *voice; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - LockSourceList(context); - if(!(nb >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing %d buffers", nb); - if((source=LookupSource(context, src)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src); - - /* Nothing to unqueue. */ - if(nb == 0) goto done; - - if(source->Looping) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing from looping source %u", src); - if(source->SourceType != AL_STREAMING) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing from a non-streaming source %u", - src); - - /* Make sure enough buffers have been processed to unqueue. */ - BufferList = source->queue; - Current = NULL; - if((voice=GetSourceVoice(source, context)) != NULL) - Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - else if(source->state == AL_INITIAL) - Current = BufferList; - if(BufferList == Current) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing pending buffers"); - - i = BufferList->num_buffers; - while(i < nb) - { - /* If the next bufferlist to check is NULL or is the current one, it's - * trying to unqueue pending buffers. - */ - ALbufferlistitem *next = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); - if(!next || next == Current) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing pending buffers"); - BufferList = next; - - i += BufferList->num_buffers; - } - - while(nb > 0) - { - ALbufferlistitem *head = source->queue; - ALbufferlistitem *next = ATOMIC_LOAD(&head->next, almemory_order_relaxed); - for(i = 0;i < head->num_buffers && nb > 0;i++,nb--) - { - ALbuffer *buffer = head->buffers[i]; - if(!buffer) - *(buffers++) = 0; - else - { - *(buffers++) = buffer->id; - DecrementRef(&buffer->ref); - } - } - if(i < head->num_buffers) - { - /* This head has some buffers left over, so move them to the front - * and update the sample and buffer count. - */ - ALsizei max_length = 0; - ALsizei j = 0; - while(i < head->num_buffers) - { - ALbuffer *buffer = head->buffers[i++]; - if(buffer) max_length = maxi(max_length, buffer->SampleLen); - head->buffers[j++] = buffer; - } - head->max_samples = max_length; - head->num_buffers = j; - break; - } - - /* Otherwise, free this item and set the source queue head to the next - * one. - */ - al_free(head); - source->queue = next; - } - -done: - UnlockSourceList(context); - ALCcontext_DecRef(context); -} - - -static void InitSourceParams(ALsource *Source, ALsizei num_sends) -{ - ALsizei i; - - Source->InnerAngle = 360.0f; - Source->OuterAngle = 360.0f; - Source->Pitch = 1.0f; - Source->Position[0] = 0.0f; - Source->Position[1] = 0.0f; - Source->Position[2] = 0.0f; - Source->Velocity[0] = 0.0f; - Source->Velocity[1] = 0.0f; - Source->Velocity[2] = 0.0f; - Source->Direction[0] = 0.0f; - Source->Direction[1] = 0.0f; - Source->Direction[2] = 0.0f; - Source->Orientation[0][0] = 0.0f; - Source->Orientation[0][1] = 0.0f; - Source->Orientation[0][2] = -1.0f; - Source->Orientation[1][0] = 0.0f; - Source->Orientation[1][1] = 1.0f; - Source->Orientation[1][2] = 0.0f; - Source->RefDistance = 1.0f; - Source->MaxDistance = FLT_MAX; - Source->RolloffFactor = 1.0f; - Source->Gain = 1.0f; - Source->MinGain = 0.0f; - Source->MaxGain = 1.0f; - Source->OuterGain = 0.0f; - Source->OuterGainHF = 1.0f; - - Source->DryGainHFAuto = AL_TRUE; - Source->WetGainAuto = AL_TRUE; - Source->WetGainHFAuto = AL_TRUE; - Source->AirAbsorptionFactor = 0.0f; - Source->RoomRolloffFactor = 0.0f; - Source->DopplerFactor = 1.0f; - Source->HeadRelative = AL_FALSE; - Source->Looping = AL_FALSE; - Source->DistanceModel = DefaultDistanceModel; - Source->Resampler = ResamplerDefault; - Source->DirectChannels = AL_FALSE; - Source->Spatialize = SpatializeAuto; - - Source->StereoPan[0] = DEG2RAD( 30.0f); - Source->StereoPan[1] = DEG2RAD(-30.0f); - - Source->Radius = 0.0f; - - Source->Direct.Gain = 1.0f; - Source->Direct.GainHF = 1.0f; - Source->Direct.HFReference = LOWPASSFREQREF; - Source->Direct.GainLF = 1.0f; - Source->Direct.LFReference = HIGHPASSFREQREF; - Source->Send = al_calloc(16, num_sends*sizeof(Source->Send[0])); - for(i = 0;i < num_sends;i++) - { - Source->Send[i].Slot = NULL; - Source->Send[i].Gain = 1.0f; - Source->Send[i].GainHF = 1.0f; - Source->Send[i].HFReference = LOWPASSFREQREF; - Source->Send[i].GainLF = 1.0f; - Source->Send[i].LFReference = HIGHPASSFREQREF; - } - - Source->Offset = 0.0; - Source->OffsetType = AL_NONE; - Source->SourceType = AL_UNDETERMINED; - Source->state = AL_INITIAL; - - Source->queue = NULL; - - ATOMIC_INIT(&Source->PropsClean, AL_TRUE); - - Source->VoiceIdx = -1; -} - -static void DeinitSource(ALsource *source, ALsizei num_sends) -{ - ALbufferlistitem *BufferList; - ALsizei i; - - BufferList = source->queue; - while(BufferList != NULL) - { - ALbufferlistitem *next = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); - for(i = 0;i < BufferList->num_buffers;i++) - { - if(BufferList->buffers[i] != NULL) - DecrementRef(&BufferList->buffers[i]->ref); - } - al_free(BufferList); - BufferList = next; - } - source->queue = NULL; - - if(source->Send) - { - for(i = 0;i < num_sends;i++) - { - if(source->Send[i].Slot) - DecrementRef(&source->Send[i].Slot->ref); - source->Send[i].Slot = NULL; - } - al_free(source->Send); - source->Send = NULL; - } -} - -static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends, ALCcontext *context) -{ - struct ALvoiceProps *props; - ALsizei i; - - /* Get an unused property container, or allocate a new one as needed. */ - props = ATOMIC_LOAD(&context->FreeVoiceProps, almemory_order_acquire); - if(!props) - props = al_calloc(16, FAM_SIZE(struct ALvoiceProps, Send, num_sends)); - else - { - struct ALvoiceProps *next; - do { - next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeVoiceProps, &props, next, - almemory_order_acq_rel, almemory_order_acquire) == 0); - } - - /* Copy in current property values. */ - props->Pitch = source->Pitch; - props->Gain = source->Gain; - props->OuterGain = source->OuterGain; - props->MinGain = source->MinGain; - props->MaxGain = source->MaxGain; - props->InnerAngle = source->InnerAngle; - props->OuterAngle = source->OuterAngle; - props->RefDistance = source->RefDistance; - props->MaxDistance = source->MaxDistance; - props->RolloffFactor = source->RolloffFactor; - for(i = 0;i < 3;i++) - props->Position[i] = source->Position[i]; - for(i = 0;i < 3;i++) - props->Velocity[i] = source->Velocity[i]; - for(i = 0;i < 3;i++) - props->Direction[i] = source->Direction[i]; - for(i = 0;i < 2;i++) - { - ALsizei j; - for(j = 0;j < 3;j++) - props->Orientation[i][j] = source->Orientation[i][j]; - } - props->HeadRelative = source->HeadRelative; - props->DistanceModel = source->DistanceModel; - props->Resampler = source->Resampler; - props->DirectChannels = source->DirectChannels; - props->SpatializeMode = source->Spatialize; - - props->DryGainHFAuto = source->DryGainHFAuto; - props->WetGainAuto = source->WetGainAuto; - props->WetGainHFAuto = source->WetGainHFAuto; - props->OuterGainHF = source->OuterGainHF; - - props->AirAbsorptionFactor = source->AirAbsorptionFactor; - props->RoomRolloffFactor = source->RoomRolloffFactor; - props->DopplerFactor = source->DopplerFactor; - - props->StereoPan[0] = source->StereoPan[0]; - props->StereoPan[1] = source->StereoPan[1]; - - props->Radius = source->Radius; - - props->Direct.Gain = source->Direct.Gain; - props->Direct.GainHF = source->Direct.GainHF; - props->Direct.HFReference = source->Direct.HFReference; - props->Direct.GainLF = source->Direct.GainLF; - props->Direct.LFReference = source->Direct.LFReference; - - for(i = 0;i < num_sends;i++) - { - props->Send[i].Slot = source->Send[i].Slot; - props->Send[i].Gain = source->Send[i].Gain; - props->Send[i].GainHF = source->Send[i].GainHF; - props->Send[i].HFReference = source->Send[i].HFReference; - props->Send[i].GainLF = source->Send[i].GainLF; - props->Send[i].LFReference = source->Send[i].LFReference; - } - - /* Set the new container for updating internal parameters. */ - props = ATOMIC_EXCHANGE_PTR(&voice->Update, props, almemory_order_acq_rel); - if(props) - { - /* If there was an unused update container, put it back in the - * freelist. - */ - ATOMIC_REPLACE_HEAD(struct ALvoiceProps*, &context->FreeVoiceProps, props); - } -} - -void UpdateAllSourceProps(ALCcontext *context) -{ - ALsizei num_sends = context->Device->NumAuxSends; - ALsizei pos; - - for(pos = 0;pos < context->VoiceCount;pos++) - { - ALvoice *voice = context->Voices[pos]; - ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire); - if(source && !ATOMIC_EXCHANGE(&source->PropsClean, AL_TRUE, almemory_order_acq_rel)) - UpdateSourceProps(source, voice, num_sends, context); - } -} - - -/* GetSourceSampleOffset - * - * Gets the current read offset for the given Source, in 32.32 fixed-point - * samples. The offset is relative to the start of the queue (not the start of - * the current buffer). - */ -static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime) -{ - ALCdevice *device = context->Device; - const ALbufferlistitem *Current; - ALuint64 readPos; - ALuint refcount; - ALvoice *voice; - - do { - Current = NULL; - readPos = 0; - while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) - althrd_yield(); - *clocktime = GetDeviceClockTime(device); - - voice = GetSourceVoice(Source, context); - if(voice) - { - Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - - readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << 32; - readPos |= (ALuint64)ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) << - (32-FRACTIONBITS); - } - ATOMIC_THREAD_FENCE(almemory_order_acquire); - } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); - - if(voice) - { - const ALbufferlistitem *BufferList = Source->queue; - while(BufferList && BufferList != Current) - { - readPos += (ALuint64)BufferList->max_samples << 32; - BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, - almemory_order_relaxed); - } - readPos = minu64(readPos, U64(0x7fffffffffffffff)); - } - - return (ALint64)readPos; -} - -/* GetSourceSecOffset - * - * Gets the current read offset for the given Source, in seconds. The offset is - * relative to the start of the queue (not the start of the current buffer). - */ -static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime) -{ - ALCdevice *device = context->Device; - const ALbufferlistitem *Current; - ALuint64 readPos; - ALuint refcount; - ALdouble offset; - ALvoice *voice; - - do { - Current = NULL; - readPos = 0; - while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) - althrd_yield(); - *clocktime = GetDeviceClockTime(device); - - voice = GetSourceVoice(Source, context); - if(voice) - { - Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - - readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << - FRACTIONBITS; - readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); - } - ATOMIC_THREAD_FENCE(almemory_order_acquire); - } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); - - offset = 0.0; - if(voice) - { - const ALbufferlistitem *BufferList = Source->queue; - const ALbuffer *BufferFmt = NULL; - while(BufferList && BufferList != Current) - { - ALsizei i = 0; - while(!BufferFmt && i < BufferList->num_buffers) - BufferFmt = BufferList->buffers[i++]; - readPos += (ALuint64)BufferList->max_samples << FRACTIONBITS; - BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, - almemory_order_relaxed); - } - - while(BufferList && !BufferFmt) - { - ALsizei i = 0; - while(!BufferFmt && i < BufferList->num_buffers) - BufferFmt = BufferList->buffers[i++]; - BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, - almemory_order_relaxed); - } - assert(BufferFmt != NULL); - - offset = (ALdouble)readPos / (ALdouble)FRACTIONONE / - (ALdouble)BufferFmt->Frequency; - } - - return offset; -} - -/* GetSourceOffset - * - * Gets the current read offset for the given Source, in the appropriate format - * (Bytes, Samples or Seconds). The offset is relative to the start of the - * queue (not the start of the current buffer). - */ -static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) -{ - ALCdevice *device = context->Device; - const ALbufferlistitem *Current; - ALuint readPos; - ALsizei readPosFrac; - ALuint refcount; - ALdouble offset; - ALvoice *voice; - - do { - Current = NULL; - readPos = readPosFrac = 0; - while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) - althrd_yield(); - voice = GetSourceVoice(Source, context); - if(voice) - { - Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - - readPos = ATOMIC_LOAD(&voice->position, almemory_order_relaxed); - readPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); - } - ATOMIC_THREAD_FENCE(almemory_order_acquire); - } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); - - offset = 0.0; - if(voice) - { - const ALbufferlistitem *BufferList = Source->queue; - const ALbuffer *BufferFmt = NULL; - ALboolean readFin = AL_FALSE; - ALuint totalBufferLen = 0; - - while(BufferList != NULL) - { - ALsizei i = 0; - while(!BufferFmt && i < BufferList->num_buffers) - BufferFmt = BufferList->buffers[i++]; - - readFin |= (BufferList == Current); - totalBufferLen += BufferList->max_samples; - if(!readFin) readPos += BufferList->max_samples; - - BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, - almemory_order_relaxed); - } - assert(BufferFmt != NULL); - - if(Source->Looping) - readPos %= totalBufferLen; - else - { - /* Wrap back to 0 */ - if(readPos >= totalBufferLen) - readPos = readPosFrac = 0; - } - - offset = 0.0; - switch(name) - { - case AL_SEC_OFFSET: - offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE) / BufferFmt->Frequency; - break; - - case AL_SAMPLE_OFFSET: - offset = readPos + (ALdouble)readPosFrac/FRACTIONONE; - break; - - case AL_BYTE_OFFSET: - if(BufferFmt->OriginalType == UserFmtIMA4) - { - ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; - ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels); - ALuint FrameBlockSize = BufferFmt->OriginalAlign; - - /* Round down to nearest ADPCM block */ - offset = (ALdouble)(readPos / FrameBlockSize * BlockSize); - } - else if(BufferFmt->OriginalType == UserFmtMSADPCM) - { - ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; - ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels); - ALuint FrameBlockSize = BufferFmt->OriginalAlign; - - /* Round down to nearest ADPCM block */ - offset = (ALdouble)(readPos / FrameBlockSize * BlockSize); - } - else - { - ALuint FrameSize = FrameSizeFromFmt(BufferFmt->FmtChannels, - BufferFmt->FmtType); - offset = (ALdouble)(readPos * FrameSize); - } - break; - } - } - - return offset; -} - - -/* ApplyOffset - * - * Apply the stored playback offset to the Source. This function will update - * the number of buffers "played" given the stored offset. - */ -static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) -{ - ALbufferlistitem *BufferList; - ALuint totalBufferLen; - ALuint offset = 0; - ALsizei frac = 0; - - /* Get sample frame offset */ - if(!GetSampleOffset(Source, &offset, &frac)) - return AL_FALSE; - - totalBufferLen = 0; - BufferList = Source->queue; - while(BufferList && totalBufferLen <= offset) - { - if((ALuint)BufferList->max_samples > offset-totalBufferLen) - { - /* Offset is in this buffer */ - ATOMIC_STORE(&voice->position, offset - totalBufferLen, almemory_order_relaxed); - ATOMIC_STORE(&voice->position_fraction, frac, almemory_order_relaxed); - ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_release); - return AL_TRUE; - } - totalBufferLen += BufferList->max_samples; - - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); - } - - /* Offset is out of range of the queue */ - return AL_FALSE; -} - - -/* GetSampleOffset - * - * Retrieves the sample offset into the Source's queue (from the Sample, Byte - * or Second offset supplied by the application). This takes into account the - * fact that the buffer format may have been modifed since. - */ -static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac) -{ - const ALbuffer *BufferFmt = NULL; - const ALbufferlistitem *BufferList; - ALdouble dbloff, dblfrac; - - /* Find the first valid Buffer in the Queue */ - BufferList = Source->queue; - while(BufferList) - { - ALsizei i; - for(i = 0;i < BufferList->num_buffers && !BufferFmt;i++) - BufferFmt = BufferList->buffers[i]; - if(BufferFmt) break; - BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, - almemory_order_relaxed); - } - if(!BufferFmt) - { - Source->OffsetType = AL_NONE; - Source->Offset = 0.0; - return AL_FALSE; - } - - switch(Source->OffsetType) - { - case AL_BYTE_OFFSET: - /* Determine the ByteOffset (and ensure it is block aligned) */ - *offset = (ALuint)Source->Offset; - if(BufferFmt->OriginalType == UserFmtIMA4) - { - ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; - *offset /= align * ChannelsFromFmt(BufferFmt->FmtChannels); - *offset *= BufferFmt->OriginalAlign; - } - else if(BufferFmt->OriginalType == UserFmtMSADPCM) - { - ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; - *offset /= align * ChannelsFromFmt(BufferFmt->FmtChannels); - *offset *= BufferFmt->OriginalAlign; - } - else - *offset /= FrameSizeFromFmt(BufferFmt->FmtChannels, BufferFmt->FmtType); - *frac = 0; - break; - - case AL_SAMPLE_OFFSET: - dblfrac = modf(Source->Offset, &dbloff); - *offset = (ALuint)mind(dbloff, UINT_MAX); - *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0); - break; - - case AL_SEC_OFFSET: - dblfrac = modf(Source->Offset*BufferFmt->Frequency, &dbloff); - *offset = (ALuint)mind(dbloff, UINT_MAX); - *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0); - break; - } - Source->OffsetType = AL_NONE; - Source->Offset = 0.0; - - return AL_TRUE; -} - - -static ALsource *AllocSource(ALCcontext *context) -{ - ALCdevice *device = context->Device; - SourceSubList *sublist, *subend; - ALsource *source = NULL; - ALsizei lidx = 0; - ALsizei slidx; - - almtx_lock(&context->SourceLock); - if(context->NumSources >= device->SourcesMax) - { - almtx_unlock(&context->SourceLock); - alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax); - return NULL; - } - sublist = VECTOR_BEGIN(context->SourceList); - subend = VECTOR_END(context->SourceList); - for(;sublist != subend;++sublist) - { - if(sublist->FreeMask) - { - slidx = CTZ64(sublist->FreeMask); - source = sublist->Sources + slidx; - break; - } - ++lidx; - } - if(UNLIKELY(!source)) - { - const SourceSubList empty_sublist = { 0, NULL }; - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ - if(UNLIKELY(VECTOR_SIZE(context->SourceList) >= 1<<25)) - { - almtx_unlock(&device->BufferLock); - alSetError(context, AL_OUT_OF_MEMORY, "Too many sources allocated"); - return NULL; - } - lidx = (ALsizei)VECTOR_SIZE(context->SourceList); - VECTOR_PUSH_BACK(context->SourceList, empty_sublist); - sublist = &VECTOR_BACK(context->SourceList); - sublist->FreeMask = ~U64(0); - sublist->Sources = al_calloc(16, sizeof(ALsource)*64); - if(UNLIKELY(!sublist->Sources)) - { - VECTOR_POP_BACK(context->SourceList); - almtx_unlock(&context->SourceLock); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate source batch"); - return NULL; - } - - slidx = 0; - source = sublist->Sources + slidx; - } - - memset(source, 0, sizeof(*source)); - InitSourceParams(source, device->NumAuxSends); - - /* Add 1 to avoid source ID 0. */ - source->id = ((lidx<<6) | slidx) + 1; - - context->NumSources++; - sublist->FreeMask &= ~(U64(1)<SourceLock); - - return source; -} - -static void FreeSource(ALCcontext *context, ALsource *source) -{ - ALCdevice *device = context->Device; - ALuint id = source->id - 1; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; - ALvoice *voice; - - ALCdevice_Lock(device); - if((voice=GetSourceVoice(source, context)) != NULL) - { - ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - } - ALCdevice_Unlock(device); - - DeinitSource(source, device->NumAuxSends); - memset(source, 0, sizeof(*source)); - - VECTOR_ELEM(context->SourceList, lidx).FreeMask |= U64(1) << slidx; - context->NumSources--; -} - -/* ReleaseALSources - * - * Destroys all sources in the source map. - */ -ALvoid ReleaseALSources(ALCcontext *context) -{ - ALCdevice *device = context->Device; - SourceSubList *sublist = VECTOR_BEGIN(context->SourceList); - SourceSubList *subend = VECTOR_END(context->SourceList); - size_t leftover = 0; - for(;sublist != subend;++sublist) - { - ALuint64 usemask = ~sublist->FreeMask; - while(usemask) - { - ALsizei idx = CTZ64(usemask); - ALsource *source = sublist->Sources + idx; - - DeinitSource(source, device->NumAuxSends); - memset(source, 0, sizeof(*source)); - ++leftover; - - usemask &= ~(U64(1) << idx); - } - sublist->FreeMask = ~usemask; - } - if(leftover > 0) - WARN("(%p) Deleted "SZFMT" Source%s\n", device, leftover, (leftover==1)?"":"s"); -} diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp new file mode 100644 index 00000000..158290ef --- /dev/null +++ b/OpenAL32/alSource.cpp @@ -0,0 +1,3707 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "alMain.h" +#include "alError.h" +#include "alSource.h" +#include "alBuffer.h" +#include "alFilter.h" +#include "alAuxEffectSlot.h" +#include "ringbuffer.h" + +#include "backends/base.h" + +#include "threads.h" +#include "almalloc.h" + + +static ALsource *AllocSource(ALCcontext *context); +static void FreeSource(ALCcontext *context, ALsource *source); +static void InitSourceParams(ALsource *Source, ALsizei num_sends); +static void DeinitSource(ALsource *source, ALsizei num_sends); +static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends, ALCcontext *context); +static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime); +static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime); +static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context); +static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac); +static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice); + +static inline void LockSourceList(ALCcontext *context) +{ almtx_lock(&context->SourceLock); } +static inline void UnlockSourceList(ALCcontext *context) +{ almtx_unlock(&context->SourceLock); } + +static inline ALsource *LookupSource(ALCcontext *context, ALuint id) +{ + SourceSubList *sublist; + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= VECTOR_SIZE(context->SourceList))) + return NULL; + sublist = &VECTOR_ELEM(context->SourceList, lidx); + if(UNLIKELY(sublist->FreeMask & (U64(1)<Sources + slidx; +} + +static inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) +{ + BufferSubList *sublist; + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= VECTOR_SIZE(device->BufferList))) + return NULL; + sublist = &VECTOR_ELEM(device->BufferList, lidx); + if(UNLIKELY(sublist->FreeMask & (U64(1)<Buffers + slidx; +} + +static inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) +{ + FilterSubList *sublist; + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= VECTOR_SIZE(device->FilterList))) + return NULL; + sublist = &VECTOR_ELEM(device->FilterList, lidx); + if(UNLIKELY(sublist->FreeMask & (U64(1)<Filters + slidx; +} + +static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) +{ + id--; + if(UNLIKELY(id >= VECTOR_SIZE(context->EffectSlotList))) + return NULL; + return VECTOR_ELEM(context->EffectSlotList, id); +} + + +typedef enum SourceProp { + srcPitch = AL_PITCH, + srcGain = AL_GAIN, + srcMinGain = AL_MIN_GAIN, + srcMaxGain = AL_MAX_GAIN, + srcMaxDistance = AL_MAX_DISTANCE, + srcRolloffFactor = AL_ROLLOFF_FACTOR, + srcDopplerFactor = AL_DOPPLER_FACTOR, + srcConeOuterGain = AL_CONE_OUTER_GAIN, + srcSecOffset = AL_SEC_OFFSET, + srcSampleOffset = AL_SAMPLE_OFFSET, + srcByteOffset = AL_BYTE_OFFSET, + srcConeInnerAngle = AL_CONE_INNER_ANGLE, + srcConeOuterAngle = AL_CONE_OUTER_ANGLE, + srcRefDistance = AL_REFERENCE_DISTANCE, + + srcPosition = AL_POSITION, + srcVelocity = AL_VELOCITY, + srcDirection = AL_DIRECTION, + + srcSourceRelative = AL_SOURCE_RELATIVE, + srcLooping = AL_LOOPING, + srcBuffer = AL_BUFFER, + srcSourceState = AL_SOURCE_STATE, + srcBuffersQueued = AL_BUFFERS_QUEUED, + srcBuffersProcessed = AL_BUFFERS_PROCESSED, + srcSourceType = AL_SOURCE_TYPE, + + /* ALC_EXT_EFX */ + srcConeOuterGainHF = AL_CONE_OUTER_GAINHF, + srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR, + srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR, + srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO, + srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, + srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, + srcDirectFilter = AL_DIRECT_FILTER, + srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER, + + /* AL_SOFT_direct_channels */ + srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT, + + /* AL_EXT_source_distance_model */ + srcDistanceModel = AL_DISTANCE_MODEL, + + /* AL_SOFT_source_latency */ + srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT, + srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT, + + /* AL_EXT_STEREO_ANGLES */ + srcAngles = AL_STEREO_ANGLES, + + /* AL_EXT_SOURCE_RADIUS */ + srcRadius = AL_SOURCE_RADIUS, + + /* AL_EXT_BFORMAT */ + srcOrientation = AL_ORIENTATION, + + /* AL_SOFT_source_resampler */ + srcResampler = AL_SOURCE_RESAMPLER_SOFT, + + /* AL_SOFT_source_spatialize */ + srcSpatialize = AL_SOURCE_SPATIALIZE_SOFT, + + /* ALC_SOFT_device_clock */ + srcSampleOffsetClockSOFT = AL_SAMPLE_OFFSET_CLOCK_SOFT, + srcSecOffsetClockSOFT = AL_SEC_OFFSET_CLOCK_SOFT, +} SourceProp; + +static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values); +static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values); +static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values); + +static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values); +static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values); +static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values); + +static inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) +{ + ALint idx = source->VoiceIdx; + if(idx >= 0 && idx < context->VoiceCount) + { + ALvoice *voice = context->Voices[idx]; + if(ATOMIC_LOAD(&voice->Source, almemory_order_acquire) == source) + return voice; + } + source->VoiceIdx = -1; + return NULL; +} + +/** + * Returns if the last known state for the source was playing or paused. Does + * not sync with the mixer voice. + */ +static inline bool IsPlayingOrPaused(ALsource *source) +{ return source->state == AL_PLAYING || source->state == AL_PAUSED; } + +/** + * Returns an updated source state using the matching voice's status (or lack + * thereof). + */ +static inline ALenum GetSourceState(ALsource *source, ALvoice *voice) +{ + if(!voice && source->state == AL_PLAYING) + source->state = AL_STOPPED; + return source->state; +} + +/** + * Returns if the source should specify an update, given the context's + * deferring state and the source's last known state. + */ +static inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context) +{ + return !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) && + IsPlayingOrPaused(source); +} + + +/** Can only be called while the mixer is locked! */ +static void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) +{ + AsyncEvent evt = ASYNC_EVENT(EventType_SourceStateChange); + ALbitfieldSOFT enabledevt; + + enabledevt = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); + if(!(enabledevt&EventType_SourceStateChange)) return; + + evt.u.user.type = AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT; + evt.u.user.id = id; + evt.u.user.param = state; + snprintf(evt.u.user.msg, sizeof(evt.u.user.msg), "Source ID %u state changed to %s", id, + (state==AL_INITIAL) ? "AL_INITIAL" : + (state==AL_PLAYING) ? "AL_PLAYING" : + (state==AL_PAUSED) ? "AL_PAUSED" : + (state==AL_STOPPED) ? "AL_STOPPED" : "" + ); + /* The mixer may have queued a state change that's not yet been processed, + * and we don't want state change messages to occur out of order, so send + * it through the async queue to ensure proper ordering. + */ + if(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) == 1) + alsem_post(&context->EventSem); +} + + +static ALint FloatValsByProp(ALenum prop) +{ + if(prop != (ALenum)((SourceProp)prop)) + return 0; + switch((SourceProp)prop) + { + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_SOURCE_RADIUS: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + return 1; + + case AL_STEREO_ANGLES: + return 2; + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + return 3; + + case AL_ORIENTATION: + return 6; + + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + break; /* Double only */ + + case AL_BUFFER: + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + break; /* i/i64 only */ + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; /* i64 only */ + } + return 0; +} +static ALint DoubleValsByProp(ALenum prop) +{ + if(prop != (ALenum)((SourceProp)prop)) + return 0; + switch((SourceProp)prop) + { + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_SOURCE_RADIUS: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + return 1; + + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + case AL_STEREO_ANGLES: + return 2; + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + return 3; + + case AL_ORIENTATION: + return 6; + + case AL_BUFFER: + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + break; /* i/i64 only */ + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; /* i64 only */ + } + return 0; +} + +static ALint IntValsByProp(ALenum prop) +{ + if(prop != (ALenum)((SourceProp)prop)) + return 0; + switch((SourceProp)prop) + { + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_BUFFER: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_DIRECT_FILTER: + case AL_SOURCE_RADIUS: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + return 1; + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + case AL_AUXILIARY_SEND_FILTER: + return 3; + + case AL_ORIENTATION: + return 6; + + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; /* i64 only */ + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + break; /* Double only */ + case AL_STEREO_ANGLES: + break; /* Float/double only */ + } + return 0; +} +static ALint Int64ValsByProp(ALenum prop) +{ + if(prop != (ALenum)((SourceProp)prop)) + return 0; + switch((SourceProp)prop) + { + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_BUFFER: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_DIRECT_FILTER: + case AL_SOURCE_RADIUS: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + return 1; + + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + return 2; + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + case AL_AUXILIARY_SEND_FILTER: + return 3; + + case AL_ORIENTATION: + return 6; + + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + break; /* Double only */ + case AL_STEREO_ANGLES: + break; /* Float/double only */ + } + return 0; +} + + +#define CHECKVAL(x) do { \ + if(!(x)) \ + { \ + alSetError(Context, AL_INVALID_VALUE, "Value out of range"); \ + return AL_FALSE; \ + } \ +} while(0) + +#define DO_UPDATEPROPS() do { \ + ALvoice *voice; \ + if(SourceShouldUpdate(Source, Context) && \ + (voice=GetSourceVoice(Source, Context)) != NULL) \ + UpdateSourceProps(Source, voice, device->NumAuxSends, Context); \ + else \ + ATOMIC_STORE(&Source->PropsClean, AL_FALSE, almemory_order_release); \ +} while(0) + +static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values) +{ + ALCdevice *device = Context->Device; + ALint ival; + + switch(prop) + { + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + /* Query only */ + SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, + "Setting read-only source property 0x%04x", prop); + + case AL_PITCH: + CHECKVAL(*values >= 0.0f); + + Source->Pitch = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_CONE_INNER_ANGLE: + CHECKVAL(*values >= 0.0f && *values <= 360.0f); + + Source->InnerAngle = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_CONE_OUTER_ANGLE: + CHECKVAL(*values >= 0.0f && *values <= 360.0f); + + Source->OuterAngle = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_GAIN: + CHECKVAL(*values >= 0.0f); + + Source->Gain = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_MAX_DISTANCE: + CHECKVAL(*values >= 0.0f); + + Source->MaxDistance = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_ROLLOFF_FACTOR: + CHECKVAL(*values >= 0.0f); + + Source->RolloffFactor = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_REFERENCE_DISTANCE: + CHECKVAL(*values >= 0.0f); + + Source->RefDistance = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_MIN_GAIN: + CHECKVAL(*values >= 0.0f); + + Source->MinGain = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_MAX_GAIN: + CHECKVAL(*values >= 0.0f); + + Source->MaxGain = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_CONE_OUTER_GAIN: + CHECKVAL(*values >= 0.0f && *values <= 1.0f); + + Source->OuterGain = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_CONE_OUTER_GAINHF: + CHECKVAL(*values >= 0.0f && *values <= 1.0f); + + Source->OuterGainHF = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_AIR_ABSORPTION_FACTOR: + CHECKVAL(*values >= 0.0f && *values <= 10.0f); + + Source->AirAbsorptionFactor = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_ROOM_ROLLOFF_FACTOR: + CHECKVAL(*values >= 0.0f && *values <= 10.0f); + + Source->RoomRolloffFactor = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_DOPPLER_FACTOR: + CHECKVAL(*values >= 0.0f && *values <= 1.0f); + + Source->DopplerFactor = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + CHECKVAL(*values >= 0.0f); + + Source->OffsetType = prop; + Source->Offset = *values; + + if(IsPlayingOrPaused(Source)) + { + ALvoice *voice; + + ALCdevice_Lock(Context->Device); + /* Double-check that the source is still playing while we have + * the lock. + */ + voice = GetSourceVoice(Source, Context); + if(voice) + { + if(ApplyOffset(Source, voice) == AL_FALSE) + { + ALCdevice_Unlock(Context->Device); + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid offset"); + } + } + ALCdevice_Unlock(Context->Device); + } + return AL_TRUE; + + case AL_SOURCE_RADIUS: + CHECKVAL(*values >= 0.0f && isfinite(*values)); + + Source->Radius = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_STEREO_ANGLES: + CHECKVAL(isfinite(values[0]) && isfinite(values[1])); + + Source->StereoPan[0] = values[0]; + Source->StereoPan[1] = values[1]; + DO_UPDATEPROPS(); + return AL_TRUE; + + + case AL_POSITION: + CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2])); + + Source->Position[0] = values[0]; + Source->Position[1] = values[1]; + Source->Position[2] = values[2]; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_VELOCITY: + CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2])); + + Source->Velocity[0] = values[0]; + Source->Velocity[1] = values[1]; + Source->Velocity[2] = values[2]; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_DIRECTION: + CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2])); + + Source->Direction[0] = values[0]; + Source->Direction[1] = values[1]; + Source->Direction[2] = values[2]; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_ORIENTATION: + CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) && + isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5])); + + Source->Orientation[0][0] = values[0]; + Source->Orientation[0][1] = values[1]; + Source->Orientation[0][2] = values[2]; + Source->Orientation[1][0] = values[3]; + Source->Orientation[1][1] = values[4]; + Source->Orientation[1][2] = values[5]; + DO_UPDATEPROPS(); + return AL_TRUE; + + + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_SOURCE_TYPE: + case AL_DISTANCE_MODEL: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + ival = (ALint)values[0]; + return SetSourceiv(Source, Context, prop, &ival); + + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + ival = (ALint)((ALuint)values[0]); + return SetSourceiv(Source, Context, prop, &ival); + + case AL_BUFFER: + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; + } + + ERR("Unexpected property: 0x%04x\n", prop); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source float property 0x%04x", prop); +} + +static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values) +{ + ALCdevice *device = Context->Device; + ALbuffer *buffer = NULL; + ALfilter *filter = NULL; + ALeffectslot *slot = NULL; + ALbufferlistitem *oldlist; + ALfloat fvals[6]; + + switch(prop) + { + case AL_SOURCE_STATE: + case AL_SOURCE_TYPE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + /* Query only */ + SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, + "Setting read-only source property 0x%04x", prop); + + case AL_SOURCE_RELATIVE: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->HeadRelative = (ALboolean)*values; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_LOOPING: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->Looping = (ALboolean)*values; + if(IsPlayingOrPaused(Source)) + { + ALvoice *voice = GetSourceVoice(Source, Context); + if(voice) + { + if(Source->Looping) + ATOMIC_STORE(&voice->loop_buffer, Source->queue, almemory_order_release); + else + ATOMIC_STORE(&voice->loop_buffer, static_cast(nullptr), + almemory_order_release); + + /* If the source is playing, wait for the current mix to finish + * to ensure it isn't currently looping back or reaching the + * end. + */ + while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) + althrd_yield(); + } + } + return AL_TRUE; + + case AL_BUFFER: + LockBufferList(device); + if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL)) + { + UnlockBufferList(device); + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid buffer ID %u", + *values); + } + + if(buffer && buffer->MappedAccess != 0 && + !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) + { + UnlockBufferList(device); + SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, + "Setting non-persistently mapped buffer %u", buffer->id); + } + else + { + ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context)); + if(state == AL_PLAYING || state == AL_PAUSED) + { + UnlockBufferList(device); + SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, + "Setting buffer on playing or paused source %u", Source->id); + } + } + + oldlist = Source->queue; + if(buffer != NULL) + { + /* Add the selected buffer to a one-item queue */ + ALbufferlistitem *newlist = static_cast(al_calloc(DEF_ALIGN, + FAM_SIZE(ALbufferlistitem, buffers, 1))); + ATOMIC_INIT(&newlist->next, static_cast(nullptr)); + newlist->max_samples = buffer->SampleLen; + newlist->num_buffers = 1; + newlist->buffers[0] = buffer; + IncrementRef(&buffer->ref); + + /* Source is now Static */ + Source->SourceType = AL_STATIC; + Source->queue = newlist; + } + else + { + /* Source is now Undetermined */ + Source->SourceType = AL_UNDETERMINED; + Source->queue = NULL; + } + UnlockBufferList(device); + + /* Delete all elements in the previous queue */ + while(oldlist != NULL) + { + ALsizei i; + ALbufferlistitem *temp = oldlist; + oldlist = ATOMIC_LOAD(&temp->next, almemory_order_relaxed); + + for(i = 0;i < temp->num_buffers;i++) + { + if(temp->buffers[i]) + DecrementRef(&temp->buffers[i]->ref); + } + al_free(temp); + } + return AL_TRUE; + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + CHECKVAL(*values >= 0); + + Source->OffsetType = prop; + Source->Offset = *values; + + if(IsPlayingOrPaused(Source)) + { + ALvoice *voice; + + ALCdevice_Lock(Context->Device); + voice = GetSourceVoice(Source, Context); + if(voice) + { + if(ApplyOffset(Source, voice) == AL_FALSE) + { + ALCdevice_Unlock(Context->Device); + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, + "Invalid source offset"); + } + } + ALCdevice_Unlock(Context->Device); + } + return AL_TRUE; + + case AL_DIRECT_FILTER: + LockFilterList(device); + if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL)) + { + UnlockFilterList(device); + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", + *values); + } + + if(!filter) + { + Source->Direct.Gain = 1.0f; + Source->Direct.GainHF = 1.0f; + Source->Direct.HFReference = LOWPASSFREQREF; + Source->Direct.GainLF = 1.0f; + Source->Direct.LFReference = HIGHPASSFREQREF; + } + else + { + Source->Direct.Gain = filter->Gain; + Source->Direct.GainHF = filter->GainHF; + Source->Direct.HFReference = filter->HFReference; + Source->Direct.GainLF = filter->GainLF; + Source->Direct.LFReference = filter->LFReference; + } + UnlockFilterList(device); + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_DIRECT_FILTER_GAINHF_AUTO: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->DryGainHFAuto = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->WetGainAuto = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->WetGainHFAuto = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_DIRECT_CHANNELS_SOFT: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->DirectChannels = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_DISTANCE_MODEL: + CHECKVAL(*values == AL_NONE || + *values == AL_INVERSE_DISTANCE || + *values == AL_INVERSE_DISTANCE_CLAMPED || + *values == AL_LINEAR_DISTANCE || + *values == AL_LINEAR_DISTANCE_CLAMPED || + *values == AL_EXPONENT_DISTANCE || + *values == AL_EXPONENT_DISTANCE_CLAMPED); + + Source->DistanceModel = static_cast(*values); + if(Context->SourceDistanceModel) + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_SOURCE_RESAMPLER_SOFT: + CHECKVAL(*values >= 0 && *values <= ResamplerMax); + + Source->Resampler = static_cast(*values); + DO_UPDATEPROPS(); + return AL_TRUE; + + case AL_SOURCE_SPATIALIZE_SOFT: + CHECKVAL(*values >= AL_FALSE && *values <= AL_AUTO_SOFT); + + Source->Spatialize = static_cast(*values); + DO_UPDATEPROPS(); + return AL_TRUE; + + + case AL_AUXILIARY_SEND_FILTER: + LockEffectSlotList(Context); + if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL)) + { + UnlockEffectSlotList(Context); + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid effect ID %u", + values[0]); + } + if((ALuint)values[1] >= (ALuint)device->NumAuxSends) + { + UnlockEffectSlotList(Context); + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid send %u", values[1]); + } + LockFilterList(device); + if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)) + { + UnlockFilterList(device); + UnlockEffectSlotList(Context); + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", + values[2]); + } + + if(!filter) + { + /* Disable filter */ + Source->Send[values[1]].Gain = 1.0f; + Source->Send[values[1]].GainHF = 1.0f; + Source->Send[values[1]].HFReference = LOWPASSFREQREF; + Source->Send[values[1]].GainLF = 1.0f; + Source->Send[values[1]].LFReference = HIGHPASSFREQREF; + } + else + { + Source->Send[values[1]].Gain = filter->Gain; + Source->Send[values[1]].GainHF = filter->GainHF; + Source->Send[values[1]].HFReference = filter->HFReference; + Source->Send[values[1]].GainLF = filter->GainLF; + Source->Send[values[1]].LFReference = filter->LFReference; + } + UnlockFilterList(device); + + if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source)) + { + ALvoice *voice; + /* Add refcount on the new slot, and release the previous slot */ + if(slot) IncrementRef(&slot->ref); + if(Source->Send[values[1]].Slot) + DecrementRef(&Source->Send[values[1]].Slot->ref); + Source->Send[values[1]].Slot = slot; + + /* We must force an update if the auxiliary slot changed on an + * active source, in case the slot is about to be deleted. + */ + if((voice=GetSourceVoice(Source, Context)) != NULL) + UpdateSourceProps(Source, voice, device->NumAuxSends, Context); + else + ATOMIC_STORE(&Source->PropsClean, AL_FALSE, almemory_order_release); + } + else + { + if(slot) IncrementRef(&slot->ref); + if(Source->Send[values[1]].Slot) + DecrementRef(&Source->Send[values[1]].Slot->ref); + Source->Send[values[1]].Slot = slot; + DO_UPDATEPROPS(); + } + UnlockEffectSlotList(Context); + + return AL_TRUE; + + + /* 1x float */ + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_REFERENCE_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_SOURCE_RADIUS: + fvals[0] = (ALfloat)*values; + return SetSourcefv(Source, Context, prop, fvals); + + /* 3x float */ + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + fvals[0] = (ALfloat)values[0]; + fvals[1] = (ALfloat)values[1]; + fvals[2] = (ALfloat)values[2]; + return SetSourcefv(Source, Context, prop, fvals); + + /* 6x float */ + case AL_ORIENTATION: + fvals[0] = (ALfloat)values[0]; + fvals[1] = (ALfloat)values[1]; + fvals[2] = (ALfloat)values[2]; + fvals[3] = (ALfloat)values[3]; + fvals[4] = (ALfloat)values[4]; + fvals[5] = (ALfloat)values[5]; + return SetSourcefv(Source, Context, prop, fvals); + + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + case AL_STEREO_ANGLES: + break; + } + + ERR("Unexpected property: 0x%04x\n", prop); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x", + prop); +} + +static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values) +{ + ALfloat fvals[6]; + ALint ivals[3]; + + switch(prop) + { + case AL_SOURCE_TYPE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_STATE: + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + /* Query only */ + SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, + "Setting read-only source property 0x%04x", prop); + + /* 1x int */ + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + CHECKVAL(*values <= INT_MAX && *values >= INT_MIN); + + ivals[0] = (ALint)*values; + return SetSourceiv(Source, Context, prop, ivals); + + /* 1x uint */ + case AL_BUFFER: + case AL_DIRECT_FILTER: + CHECKVAL(*values <= UINT_MAX && *values >= 0); + + ivals[0] = (ALuint)*values; + return SetSourceiv(Source, Context, prop, ivals); + + /* 3x uint */ + case AL_AUXILIARY_SEND_FILTER: + CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 && + values[1] <= UINT_MAX && values[1] >= 0 && + values[2] <= UINT_MAX && values[2] >= 0); + + ivals[0] = (ALuint)values[0]; + ivals[1] = (ALuint)values[1]; + ivals[2] = (ALuint)values[2]; + return SetSourceiv(Source, Context, prop, ivals); + + /* 1x float */ + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_REFERENCE_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_SOURCE_RADIUS: + fvals[0] = (ALfloat)*values; + return SetSourcefv(Source, Context, prop, fvals); + + /* 3x float */ + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + fvals[0] = (ALfloat)values[0]; + fvals[1] = (ALfloat)values[1]; + fvals[2] = (ALfloat)values[2]; + return SetSourcefv(Source, Context, prop, fvals); + + /* 6x float */ + case AL_ORIENTATION: + fvals[0] = (ALfloat)values[0]; + fvals[1] = (ALfloat)values[1]; + fvals[2] = (ALfloat)values[2]; + fvals[3] = (ALfloat)values[3]; + fvals[4] = (ALfloat)values[4]; + fvals[5] = (ALfloat)values[5]; + return SetSourcefv(Source, Context, prop, fvals); + + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + case AL_STEREO_ANGLES: + break; + } + + ERR("Unexpected property: 0x%04x\n", prop); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x", + prop); +} + +#undef CHECKVAL + + +static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values) +{ + ALCdevice *device = Context->Device; + ClockLatency clocktime; + ALuint64 srcclock; + ALint ivals[3]; + ALboolean err; + + switch(prop) + { + case AL_GAIN: + *values = Source->Gain; + return AL_TRUE; + + case AL_PITCH: + *values = Source->Pitch; + return AL_TRUE; + + case AL_MAX_DISTANCE: + *values = Source->MaxDistance; + return AL_TRUE; + + case AL_ROLLOFF_FACTOR: + *values = Source->RolloffFactor; + return AL_TRUE; + + case AL_REFERENCE_DISTANCE: + *values = Source->RefDistance; + return AL_TRUE; + + case AL_CONE_INNER_ANGLE: + *values = Source->InnerAngle; + return AL_TRUE; + + case AL_CONE_OUTER_ANGLE: + *values = Source->OuterAngle; + return AL_TRUE; + + case AL_MIN_GAIN: + *values = Source->MinGain; + return AL_TRUE; + + case AL_MAX_GAIN: + *values = Source->MaxGain; + return AL_TRUE; + + case AL_CONE_OUTER_GAIN: + *values = Source->OuterGain; + return AL_TRUE; + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + *values = GetSourceOffset(Source, prop, Context); + return AL_TRUE; + + case AL_CONE_OUTER_GAINHF: + *values = Source->OuterGainHF; + return AL_TRUE; + + case AL_AIR_ABSORPTION_FACTOR: + *values = Source->AirAbsorptionFactor; + return AL_TRUE; + + case AL_ROOM_ROLLOFF_FACTOR: + *values = Source->RoomRolloffFactor; + return AL_TRUE; + + case AL_DOPPLER_FACTOR: + *values = Source->DopplerFactor; + return AL_TRUE; + + case AL_SOURCE_RADIUS: + *values = Source->Radius; + return AL_TRUE; + + case AL_STEREO_ANGLES: + values[0] = Source->StereoPan[0]; + values[1] = Source->StereoPan[1]; + return AL_TRUE; + + case AL_SEC_OFFSET_LATENCY_SOFT: + /* Get the source offset with the clock time first. Then get the + * clock time with the device latency. Order is important. + */ + values[0] = GetSourceSecOffset(Source, Context, &srcclock); + almtx_lock(&device->BackendLock); + clocktime = GetClockLatency(device); + almtx_unlock(&device->BackendLock); + if(srcclock == (ALuint64)clocktime.ClockTime) + values[1] = (ALdouble)clocktime.Latency / 1000000000.0; + else + { + /* If the clock time incremented, reduce the latency by that + * much since it's that much closer to the source offset it got + * earlier. + */ + ALuint64 diff = clocktime.ClockTime - srcclock; + values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) / + 1000000000.0; + } + return AL_TRUE; + + case AL_SEC_OFFSET_CLOCK_SOFT: + values[0] = GetSourceSecOffset(Source, Context, &srcclock); + values[1] = srcclock / 1000000000.0; + return AL_TRUE; + + case AL_POSITION: + values[0] = Source->Position[0]; + values[1] = Source->Position[1]; + values[2] = Source->Position[2]; + return AL_TRUE; + + case AL_VELOCITY: + values[0] = Source->Velocity[0]; + values[1] = Source->Velocity[1]; + values[2] = Source->Velocity[2]; + return AL_TRUE; + + case AL_DIRECTION: + values[0] = Source->Direction[0]; + values[1] = Source->Direction[1]; + values[2] = Source->Direction[2]; + return AL_TRUE; + + case AL_ORIENTATION: + values[0] = Source->Orientation[0][0]; + values[1] = Source->Orientation[0][1]; + values[2] = Source->Orientation[0][2]; + values[3] = Source->Orientation[1][0]; + values[4] = Source->Orientation[1][1]; + values[5] = Source->Orientation[1][2]; + return AL_TRUE; + + /* 1x int */ + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) + *values = (ALdouble)ivals[0]; + return err; + + case AL_BUFFER: + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; + } + + ERR("Unexpected property: 0x%04x\n", prop); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source double property 0x%04x", + prop); +} + +static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values) +{ + ALbufferlistitem *BufferList; + ALdouble dvals[6]; + ALboolean err; + + switch(prop) + { + case AL_SOURCE_RELATIVE: + *values = Source->HeadRelative; + return AL_TRUE; + + case AL_LOOPING: + *values = Source->Looping; + return AL_TRUE; + + case AL_BUFFER: + BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : NULL; + *values = (BufferList && BufferList->num_buffers >= 1 && BufferList->buffers[0]) ? + BufferList->buffers[0]->id : 0; + return AL_TRUE; + + case AL_SOURCE_STATE: + *values = GetSourceState(Source, GetSourceVoice(Source, Context)); + return AL_TRUE; + + case AL_BUFFERS_QUEUED: + if(!(BufferList=Source->queue)) + *values = 0; + else + { + ALsizei count = 0; + do { + count += BufferList->num_buffers; + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + } while(BufferList != NULL); + *values = count; + } + return AL_TRUE; + + case AL_BUFFERS_PROCESSED: + if(Source->Looping || Source->SourceType != AL_STREAMING) + { + /* Buffers on a looping source are in a perpetual state of + * PENDING, so don't report any as PROCESSED */ + *values = 0; + } + else + { + const ALbufferlistitem *BufferList = Source->queue; + const ALbufferlistitem *Current = NULL; + ALsizei played = 0; + ALvoice *voice; + + if((voice=GetSourceVoice(Source, Context)) != NULL) + Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); + else if(Source->state == AL_INITIAL) + Current = BufferList; + + while(BufferList && BufferList != Current) + { + played += BufferList->num_buffers; + BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, + almemory_order_relaxed); + } + *values = played; + } + return AL_TRUE; + + case AL_SOURCE_TYPE: + *values = Source->SourceType; + return AL_TRUE; + + case AL_DIRECT_FILTER_GAINHF_AUTO: + *values = Source->DryGainHFAuto; + return AL_TRUE; + + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + *values = Source->WetGainAuto; + return AL_TRUE; + + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + *values = Source->WetGainHFAuto; + return AL_TRUE; + + case AL_DIRECT_CHANNELS_SOFT: + *values = Source->DirectChannels; + return AL_TRUE; + + case AL_DISTANCE_MODEL: + *values = Source->DistanceModel; + return AL_TRUE; + + case AL_SOURCE_RESAMPLER_SOFT: + *values = Source->Resampler; + return AL_TRUE; + + case AL_SOURCE_SPATIALIZE_SOFT: + *values = Source->Spatialize; + return AL_TRUE; + + /* 1x float/double */ + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_REFERENCE_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_DOPPLER_FACTOR: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_SOURCE_RADIUS: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + *values = (ALint)dvals[0]; + return err; + + /* 3x float/double */ + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + { + values[0] = (ALint)dvals[0]; + values[1] = (ALint)dvals[1]; + values[2] = (ALint)dvals[2]; + } + return err; + + /* 6x float/double */ + case AL_ORIENTATION: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + { + values[0] = (ALint)dvals[0]; + values[1] = (ALint)dvals[1]; + values[2] = (ALint)dvals[2]; + values[3] = (ALint)dvals[3]; + values[4] = (ALint)dvals[4]; + values[5] = (ALint)dvals[5]; + } + return err; + + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; /* i64 only */ + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + break; /* Double only */ + case AL_STEREO_ANGLES: + break; /* Float/double only */ + + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + break; /* ??? */ + } + + ERR("Unexpected property: 0x%04x\n", prop); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x", + prop); +} + +static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values) +{ + ALCdevice *device = Context->Device; + ClockLatency clocktime; + ALuint64 srcclock; + ALdouble dvals[6]; + ALint ivals[3]; + ALboolean err; + + switch(prop) + { + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + /* Get the source offset with the clock time first. Then get the + * clock time with the device latency. Order is important. + */ + values[0] = GetSourceSampleOffset(Source, Context, &srcclock); + almtx_lock(&device->BackendLock); + clocktime = GetClockLatency(device); + almtx_unlock(&device->BackendLock); + if(srcclock == (ALuint64)clocktime.ClockTime) + values[1] = clocktime.Latency; + else + { + /* If the clock time incremented, reduce the latency by that + * much since it's that much closer to the source offset it got + * earlier. + */ + ALuint64 diff = clocktime.ClockTime - srcclock; + values[1] = clocktime.Latency - minu64(clocktime.Latency, diff); + } + return AL_TRUE; + + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + values[0] = GetSourceSampleOffset(Source, Context, &srcclock); + values[1] = srcclock; + return AL_TRUE; + + /* 1x float/double */ + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_REFERENCE_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_DOPPLER_FACTOR: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_SOURCE_RADIUS: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + *values = (ALint64)dvals[0]; + return err; + + /* 3x float/double */ + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + { + values[0] = (ALint64)dvals[0]; + values[1] = (ALint64)dvals[1]; + values[2] = (ALint64)dvals[2]; + } + return err; + + /* 6x float/double */ + case AL_ORIENTATION: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + { + values[0] = (ALint64)dvals[0]; + values[1] = (ALint64)dvals[1]; + values[2] = (ALint64)dvals[2]; + values[3] = (ALint64)dvals[3]; + values[4] = (ALint64)dvals[4]; + values[5] = (ALint64)dvals[5]; + } + return err; + + /* 1x int */ + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) + *values = ivals[0]; + return err; + + /* 1x uint */ + case AL_BUFFER: + case AL_DIRECT_FILTER: + if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) + *values = (ALuint)ivals[0]; + return err; + + /* 3x uint */ + case AL_AUXILIARY_SEND_FILTER: + if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) + { + values[0] = (ALuint)ivals[0]; + values[1] = (ALuint)ivals[1]; + values[2] = (ALuint)ivals[2]; + } + return err; + + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + break; /* Double only */ + case AL_STEREO_ANGLES: + break; /* Float/double only */ + } + + ERR("Unexpected property: 0x%04x\n", prop); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x", + prop); +} + + +AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) +{ + ALCcontext *context; + ALsizei cur = 0; + + context = GetContextRef(); + if(!context) return; + + if(n < 0) + alSetError(context, AL_INVALID_VALUE, "Generating %d sources", n); + else for(cur = 0;cur < n;cur++) + { + ALsource *source = AllocSource(context); + if(!source) + { + alDeleteSources(cur, sources); + break; + } + sources[cur] = source->id; + } + + ALCcontext_DecRef(context); +} + + +AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) +{ + ALCcontext *context; + ALsource *Source; + ALsizei i; + + context = GetContextRef(); + if(!context) return; + + LockSourceList(context); + if(n < 0) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d sources", n); + + /* Check that all Sources are valid */ + for(i = 0;i < n;i++) + { + if(LookupSource(context, sources[i]) == NULL) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); + } + for(i = 0;i < n;i++) + { + if((Source=LookupSource(context, sources[i])) != NULL) + FreeSource(context, Source); + } + +done: + UnlockSourceList(context); + ALCcontext_DecRef(context); +} + + +AL_API ALboolean AL_APIENTRY alIsSource(ALuint source) +{ + ALCcontext *context; + ALboolean ret; + + context = GetContextRef(); + if(!context) return AL_FALSE; + + LockSourceList(context); + ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE); + UnlockSourceList(context); + + ALCcontext_DecRef(context); + + return ret; +} + + +AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + almtx_lock(&Context->PropLock); + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(FloatValsByProp(param) != 1) + alSetError(Context, AL_INVALID_ENUM, "Invalid float property 0x%04x", param); + else + SetSourcefv(Source, Context, static_cast(param), &value); + UnlockSourceList(Context); + almtx_unlock(&Context->PropLock); + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + almtx_lock(&Context->PropLock); + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(FloatValsByProp(param) != 3) + alSetError(Context, AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); + else + { + ALfloat fvals[3] = { value1, value2, value3 }; + SetSourcefv(Source, Context, static_cast(param), fvals); + } + UnlockSourceList(Context); + almtx_unlock(&Context->PropLock); + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + almtx_lock(&Context->PropLock); + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + else if(FloatValsByProp(param) < 1) + alSetError(Context, AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); + else + SetSourcefv(Source, Context, static_cast(param), values); + UnlockSourceList(Context); + almtx_unlock(&Context->PropLock); + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + almtx_lock(&Context->PropLock); + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(DoubleValsByProp(param) != 1) + alSetError(Context, AL_INVALID_ENUM, "Invalid double property 0x%04x", param); + else + { + ALfloat fval = (ALfloat)value; + SetSourcefv(Source, Context, static_cast(param), &fval); + } + UnlockSourceList(Context); + almtx_unlock(&Context->PropLock); + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + almtx_lock(&Context->PropLock); + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(DoubleValsByProp(param) != 3) + alSetError(Context, AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); + else + { + ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 }; + SetSourcefv(Source, Context, static_cast(param), fvals); + } + UnlockSourceList(Context); + almtx_unlock(&Context->PropLock); + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values) +{ + ALCcontext *Context; + ALsource *Source; + ALint count; + + Context = GetContextRef(); + if(!Context) return; + + almtx_lock(&Context->PropLock); + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + else if((count=DoubleValsByProp(param)) < 1 || count > 6) + alSetError(Context, AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); + else + { + ALfloat fvals[6]; + ALint i; + + for(i = 0;i < count;i++) + fvals[i] = (ALfloat)values[i]; + SetSourcefv(Source, Context, static_cast(param), fvals); + } + UnlockSourceList(Context); + almtx_unlock(&Context->PropLock); + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + almtx_lock(&Context->PropLock); + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(IntValsByProp(param) != 1) + alSetError(Context, AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); + else + SetSourceiv(Source, Context, static_cast(param), &value); + UnlockSourceList(Context); + almtx_unlock(&Context->PropLock); + + ALCcontext_DecRef(Context); +} + +AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + almtx_lock(&Context->PropLock); + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(IntValsByProp(param) != 3) + alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); + else + { + ALint ivals[3] = { value1, value2, value3 }; + SetSourceiv(Source, Context, static_cast(param), ivals); + } + UnlockSourceList(Context); + almtx_unlock(&Context->PropLock); + + ALCcontext_DecRef(Context); +} + +AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + almtx_lock(&Context->PropLock); + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + else if(IntValsByProp(param) < 1) + alSetError(Context, AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); + else + SetSourceiv(Source, Context, static_cast(param), values); + UnlockSourceList(Context); + almtx_unlock(&Context->PropLock); + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + almtx_lock(&Context->PropLock); + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(Int64ValsByProp(param) != 1) + alSetError(Context, AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); + else + SetSourcei64v(Source, Context, static_cast(param), &value); + UnlockSourceList(Context); + almtx_unlock(&Context->PropLock); + + ALCcontext_DecRef(Context); +} + +AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + almtx_lock(&Context->PropLock); + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(Int64ValsByProp(param) != 3) + alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); + else + { + ALint64SOFT i64vals[3] = { value1, value2, value3 }; + SetSourcei64v(Source, Context, static_cast(param), i64vals); + } + UnlockSourceList(Context); + almtx_unlock(&Context->PropLock); + + ALCcontext_DecRef(Context); +} + +AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + almtx_lock(&Context->PropLock); + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + else if(Int64ValsByProp(param) < 1) + alSetError(Context, AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); + else + SetSourcei64v(Source, Context, static_cast(param), values); + UnlockSourceList(Context); + almtx_unlock(&Context->PropLock); + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!value) + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + else if(FloatValsByProp(param) != 1) + alSetError(Context, AL_INVALID_ENUM, "Invalid float property 0x%04x", param); + else + { + ALdouble dval; + if(GetSourcedv(Source, Context, static_cast(param), &dval)) + *value = (ALfloat)dval; + } + UnlockSourceList(Context); + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!(value1 && value2 && value3)) + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + else if(FloatValsByProp(param) != 3) + alSetError(Context, AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); + else + { + ALdouble dvals[3]; + if(GetSourcedv(Source, Context, static_cast(param), dvals)) + { + *value1 = (ALfloat)dvals[0]; + *value2 = (ALfloat)dvals[1]; + *value3 = (ALfloat)dvals[2]; + } + } + UnlockSourceList(Context); + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values) +{ + ALCcontext *Context; + ALsource *Source; + ALint count; + + Context = GetContextRef(); + if(!Context) return; + + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + else if((count=FloatValsByProp(param)) < 1 && count > 6) + alSetError(Context, AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); + else + { + ALdouble dvals[6]; + if(GetSourcedv(Source, Context, static_cast(param), dvals)) + { + ALint i; + for(i = 0;i < count;i++) + values[i] = (ALfloat)dvals[i]; + } + } + UnlockSourceList(Context); + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!value) + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + else if(DoubleValsByProp(param) != 1) + alSetError(Context, AL_INVALID_ENUM, "Invalid double property 0x%04x", param); + else + GetSourcedv(Source, Context, static_cast(param), value); + UnlockSourceList(Context); + + ALCcontext_DecRef(Context); +} + +AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!(value1 && value2 && value3)) + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + else if(DoubleValsByProp(param) != 3) + alSetError(Context, AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); + else + { + ALdouble dvals[3]; + if(GetSourcedv(Source, Context, static_cast(param), dvals)) + { + *value1 = dvals[0]; + *value2 = dvals[1]; + *value3 = dvals[2]; + } + } + UnlockSourceList(Context); + + ALCcontext_DecRef(Context); +} + +AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + else if(DoubleValsByProp(param) < 1) + alSetError(Context, AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); + else + GetSourcedv(Source, Context, static_cast(param), values); + UnlockSourceList(Context); + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!value) + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + else if(IntValsByProp(param) != 1) + alSetError(Context, AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); + else + GetSourceiv(Source, Context, static_cast(param), value); + UnlockSourceList(Context); + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!(value1 && value2 && value3)) + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + else if(IntValsByProp(param) != 3) + alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); + else + { + ALint ivals[3]; + if(GetSourceiv(Source, Context, static_cast(param), ivals)) + { + *value1 = ivals[0]; + *value2 = ivals[1]; + *value3 = ivals[2]; + } + } + UnlockSourceList(Context); + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + else if(IntValsByProp(param) < 1) + alSetError(Context, AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); + else + GetSourceiv(Source, Context, static_cast(param), values); + UnlockSourceList(Context); + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!value) + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + else if(Int64ValsByProp(param) != 1) + alSetError(Context, AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); + else + GetSourcei64v(Source, Context, static_cast(param), value); + UnlockSourceList(Context); + + ALCcontext_DecRef(Context); +} + +AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!(value1 && value2 && value3)) + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + else if(Int64ValsByProp(param) != 3) + alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); + else + { + ALint64 i64vals[3]; + if(GetSourcei64v(Source, Context, static_cast(param), i64vals)) + { + *value1 = i64vals[0]; + *value2 = i64vals[1]; + *value3 = i64vals[2]; + } + } + UnlockSourceList(Context); + + ALCcontext_DecRef(Context); +} + +AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + LockSourceList(Context); + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + else if(Int64ValsByProp(param) < 1) + alSetError(Context, AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); + else + GetSourcei64v(Source, Context, static_cast(param), values); + UnlockSourceList(Context); + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source) +{ + alSourcePlayv(1, &source); +} +AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) +{ + ALCcontext *context; + ALCdevice *device; + ALsource *source; + ALvoice *voice; + ALsizei i, j; + + context = GetContextRef(); + if(!context) return; + + LockSourceList(context); + if(!(n >= 0)) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Playing %d sources", n); + for(i = 0;i < n;i++) + { + if(!LookupSource(context, sources[i])) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); + } + + device = context->Device; + ALCdevice_Lock(device); + /* If the device is disconnected, go right to stopped. */ + if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + { + /* TODO: Send state change event? */ + for(i = 0;i < n;i++) + { + source = LookupSource(context, sources[i]); + source->OffsetType = AL_NONE; + source->Offset = 0.0; + source->state = AL_STOPPED; + } + ALCdevice_Unlock(device); + goto done; + } + + while(n > context->MaxVoices-context->VoiceCount) + { + ALsizei newcount = context->MaxVoices << 1; + if(context->MaxVoices >= newcount) + { + ALCdevice_Unlock(device); + SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, + "Overflow increasing voice count %d -> %d", context->MaxVoices, newcount); + } + AllocateVoices(context, newcount, device->NumAuxSends); + } + + for(i = 0;i < n;i++) + { + ALbufferlistitem *BufferList; + bool start_fading = false; + ALint vidx = -1; + + source = LookupSource(context, sources[i]); + /* Check that there is a queue containing at least one valid, non zero + * length buffer. + */ + BufferList = source->queue; + while(BufferList && BufferList->max_samples == 0) + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + + /* If there's nothing to play, go right to stopped. */ + if(UNLIKELY(!BufferList)) + { + /* NOTE: A source without any playable buffers should not have an + * ALvoice since it shouldn't be in a playing or paused state. So + * there's no need to look up its voice and clear the source. + */ + ALenum oldstate = GetSourceState(source, NULL); + source->OffsetType = AL_NONE; + source->Offset = 0.0; + if(oldstate != AL_STOPPED) + { + source->state = AL_STOPPED; + SendStateChangeEvent(context, source->id, AL_STOPPED); + } + continue; + } + + voice = GetSourceVoice(source, context); + switch(GetSourceState(source, voice)) + { + case AL_PLAYING: + assert(voice != NULL); + /* A source that's already playing is restarted from the beginning. */ + ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); + ATOMIC_STORE(&voice->position, 0u, almemory_order_relaxed); + ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release); + continue; + + case AL_PAUSED: + assert(voice != NULL); + /* A source that's paused simply resumes. */ + ATOMIC_STORE(&voice->Playing, true, almemory_order_release); + source->state = AL_PLAYING; + SendStateChangeEvent(context, source->id, AL_PLAYING); + continue; + + default: + break; + } + + /* Look for an unused voice to play this source with. */ + assert(voice == NULL); + for(j = 0;j < context->VoiceCount;j++) + { + if(ATOMIC_LOAD(&context->Voices[j]->Source, almemory_order_acquire) == NULL) + { + vidx = j; + break; + } + } + if(vidx == -1) + vidx = context->VoiceCount++; + voice = context->Voices[vidx]; + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + + ATOMIC_EXCHANGE(&source->PropsClean, AL_TRUE, almemory_order_acquire); + UpdateSourceProps(source, voice, device->NumAuxSends, context); + + /* A source that's not playing or paused has any offset applied when it + * starts playing. + */ + if(source->Looping) + ATOMIC_STORE(&voice->loop_buffer, source->queue, almemory_order_relaxed); + else + ATOMIC_STORE(&voice->loop_buffer, static_cast(nullptr), + almemory_order_relaxed); + ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); + ATOMIC_STORE(&voice->position, 0u, almemory_order_relaxed); + ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed); + if(ApplyOffset(source, voice) != AL_FALSE) + start_fading = ATOMIC_LOAD(&voice->position, almemory_order_relaxed) != 0 || + ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) != 0 || + ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed) != BufferList; + + for(j = 0;j < BufferList->num_buffers;j++) + { + ALbuffer *buffer = BufferList->buffers[j]; + if(buffer) + { + voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels); + voice->SampleSize = BytesFromFmt(buffer->FmtType); + break; + } + } + + /* Clear previous samples. */ + memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples)); + + /* Clear the stepping value so the mixer knows not to mix this until + * the update gets applied. + */ + voice->Step = 0; + + voice->Flags = start_fading ? VOICE_IS_FADING : 0; + if(source->SourceType == AL_STATIC) voice->Flags |= VOICE_IS_STATIC; + memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])*voice->NumChannels); + for(j = 0;j < device->NumAuxSends;j++) + memset(voice->Send[j].Params, 0, sizeof(voice->Send[j].Params[0])*voice->NumChannels); + if(device->AvgSpeakerDist > 0.0f) + { + ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / + (device->AvgSpeakerDist * device->Frequency); + for(j = 0;j < voice->NumChannels;j++) + NfcFilterCreate(&voice->Direct.Params[j].NFCtrlFilter, 0.0f, w1); + } + + ATOMIC_STORE(&voice->Source, source, almemory_order_relaxed); + ATOMIC_STORE(&voice->Playing, true, almemory_order_release); + source->state = AL_PLAYING; + source->VoiceIdx = vidx; + + SendStateChangeEvent(context, source->id, AL_PLAYING); + } + ALCdevice_Unlock(device); + +done: + UnlockSourceList(context); + ALCcontext_DecRef(context); +} + +AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source) +{ + alSourcePausev(1, &source); +} +AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) +{ + ALCcontext *context; + ALCdevice *device; + ALsource *source; + ALvoice *voice; + ALsizei i; + + context = GetContextRef(); + if(!context) return; + + LockSourceList(context); + if(n < 0) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Pausing %d sources", n); + for(i = 0;i < n;i++) + { + if(!LookupSource(context, sources[i])) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); + } + + device = context->Device; + ALCdevice_Lock(device); + for(i = 0;i < n;i++) + { + source = LookupSource(context, sources[i]); + if((voice=GetSourceVoice(source, context)) != NULL) + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + if(GetSourceState(source, voice) == AL_PLAYING) + { + source->state = AL_PAUSED; + SendStateChangeEvent(context, source->id, AL_PAUSED); + } + } + ALCdevice_Unlock(device); + +done: + UnlockSourceList(context); + ALCcontext_DecRef(context); +} + +AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source) +{ + alSourceStopv(1, &source); +} +AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) +{ + ALCcontext *context; + ALCdevice *device; + ALsource *source; + ALvoice *voice; + ALsizei i; + + context = GetContextRef(); + if(!context) return; + + LockSourceList(context); + if(n < 0) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Stopping %d sources", n); + for(i = 0;i < n;i++) + { + if(!LookupSource(context, sources[i])) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); + } + + device = context->Device; + ALCdevice_Lock(device); + for(i = 0;i < n;i++) + { + ALenum oldstate; + source = LookupSource(context, sources[i]); + if((voice=GetSourceVoice(source, context)) != NULL) + { + ATOMIC_STORE(&voice->Source, static_cast(nullptr), almemory_order_relaxed); + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + voice = NULL; + } + oldstate = GetSourceState(source, voice); + if(oldstate != AL_INITIAL && oldstate != AL_STOPPED) + { + source->state = AL_STOPPED; + SendStateChangeEvent(context, source->id, AL_STOPPED); + } + source->OffsetType = AL_NONE; + source->Offset = 0.0; + } + ALCdevice_Unlock(device); + +done: + UnlockSourceList(context); + ALCcontext_DecRef(context); +} + +AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source) +{ + alSourceRewindv(1, &source); +} +AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) +{ + ALCcontext *context; + ALCdevice *device; + ALsource *source; + ALvoice *voice; + ALsizei i; + + context = GetContextRef(); + if(!context) return; + + LockSourceList(context); + if(n < 0) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Rewinding %d sources", n); + for(i = 0;i < n;i++) + { + if(!LookupSource(context, sources[i])) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); + } + + device = context->Device; + ALCdevice_Lock(device); + for(i = 0;i < n;i++) + { + source = LookupSource(context, sources[i]); + if((voice=GetSourceVoice(source, context)) != NULL) + { + ATOMIC_STORE(&voice->Source, static_cast(nullptr), almemory_order_relaxed); + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + voice = NULL; + } + if(GetSourceState(source, voice) != AL_INITIAL) + { + source->state = AL_INITIAL; + SendStateChangeEvent(context, source->id, AL_INITIAL); + } + source->OffsetType = AL_NONE; + source->Offset = 0.0; + } + ALCdevice_Unlock(device); + +done: + UnlockSourceList(context); + ALCcontext_DecRef(context); +} + + +AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers) +{ + ALCdevice *device; + ALCcontext *context; + ALsource *source; + ALsizei i; + ALbufferlistitem *BufferListStart; + ALbufferlistitem *BufferList; + ALbuffer *BufferFmt = NULL; + + if(nb == 0) + return; + + context = GetContextRef(); + if(!context) return; + + device = context->Device; + + LockSourceList(context); + if(!(nb >= 0)) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Queueing %d buffers", nb); + if((source=LookupSource(context, src)) == NULL) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src); + + if(source->SourceType == AL_STATIC) + { + /* Can't queue on a Static Source */ + SETERR_GOTO(context, AL_INVALID_OPERATION, done, "Queueing onto static source %u", src); + } + + /* Check for a valid Buffer, for its frequency and format */ + BufferList = source->queue; + while(BufferList) + { + for(i = 0;i < BufferList->num_buffers;i++) + { + if((BufferFmt=BufferList->buffers[i]) != NULL) + break; + } + if(BufferFmt) break; + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + } + + LockBufferList(device); + BufferListStart = NULL; + BufferList = NULL; + for(i = 0;i < nb;i++) + { + ALbuffer *buffer = NULL; + if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL) + SETERR_GOTO(context, AL_INVALID_NAME, buffer_error, "Queueing invalid buffer ID %u", + buffers[i]); + + if(!BufferListStart) + { + BufferListStart = static_cast(al_calloc(DEF_ALIGN, + FAM_SIZE(ALbufferlistitem, buffers, 1))); + BufferList = BufferListStart; + } + else + { + ALbufferlistitem *item = static_cast(al_calloc(DEF_ALIGN, + FAM_SIZE(ALbufferlistitem, buffers, 1))); + ATOMIC_STORE(&BufferList->next, item, almemory_order_relaxed); + BufferList = item; + } + ATOMIC_INIT(&BufferList->next, static_cast(nullptr)); + BufferList->max_samples = buffer ? buffer->SampleLen : 0; + BufferList->num_buffers = 1; + BufferList->buffers[0] = buffer; + if(!buffer) continue; + + IncrementRef(&buffer->ref); + + if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) + SETERR_GOTO(context, AL_INVALID_OPERATION, buffer_error, + "Queueing non-persistently mapped buffer %u", buffer->id); + + if(BufferFmt == NULL) + BufferFmt = buffer; + else if(BufferFmt->Frequency != buffer->Frequency || + BufferFmt->FmtChannels != buffer->FmtChannels || + BufferFmt->OriginalType != buffer->OriginalType) + { + alSetError(context, AL_INVALID_OPERATION, "Queueing buffer with mismatched format"); + + buffer_error: + /* A buffer failed (invalid ID or format), so unlock and release + * each buffer we had. */ + while(BufferListStart) + { + ALbufferlistitem *next = ATOMIC_LOAD(&BufferListStart->next, + almemory_order_relaxed); + for(i = 0;i < BufferListStart->num_buffers;i++) + { + if((buffer=BufferListStart->buffers[i]) != NULL) + DecrementRef(&buffer->ref); + } + al_free(BufferListStart); + BufferListStart = next; + } + UnlockBufferList(device); + goto done; + } + } + /* All buffers good. */ + UnlockBufferList(device); + + /* Source is now streaming */ + source->SourceType = AL_STREAMING; + + if(!(BufferList=source->queue)) + source->queue = BufferListStart; + else + { + ALbufferlistitem *next; + while((next=ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed)) != NULL) + BufferList = next; + ATOMIC_STORE(&BufferList->next, BufferListStart, almemory_order_release); + } + +done: + UnlockSourceList(context); + ALCcontext_DecRef(context); +} + +AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers) +{ + ALCdevice *device; + ALCcontext *context; + ALbufferlistitem *BufferListStart; + ALbufferlistitem *BufferList; + ALbuffer *BufferFmt = NULL; + ALsource *source; + ALsizei i; + + if(nb == 0) + return; + + context = GetContextRef(); + if(!context) return; + + device = context->Device; + + LockSourceList(context); + if(!(nb >= 0 && nb < 16)) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Queueing %d buffer layers", nb); + if((source=LookupSource(context, src)) == NULL) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src); + + if(source->SourceType == AL_STATIC) + { + /* Can't queue on a Static Source */ + SETERR_GOTO(context, AL_INVALID_OPERATION, done, "Queueing onto static source %u", src); + } + + /* Check for a valid Buffer, for its frequency and format */ + BufferList = source->queue; + while(BufferList) + { + for(i = 0;i < BufferList->num_buffers;i++) + { + if((BufferFmt=BufferList->buffers[i]) != NULL) + break; + } + if(BufferFmt) break; + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + } + + LockBufferList(device); + BufferListStart = static_cast(al_calloc(DEF_ALIGN, + FAM_SIZE(ALbufferlistitem, buffers, nb))); + BufferList = BufferListStart; + ATOMIC_INIT(&BufferList->next, static_cast(nullptr)); + BufferList->max_samples = 0; + BufferList->num_buffers = 0; + for(i = 0;i < nb;i++) + { + ALbuffer *buffer = NULL; + if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL) + SETERR_GOTO(context, AL_INVALID_NAME, buffer_error, "Queueing invalid buffer ID %u", + buffers[i]); + + BufferList->buffers[BufferList->num_buffers++] = buffer; + if(!buffer) continue; + + IncrementRef(&buffer->ref); + + BufferList->max_samples = maxi(BufferList->max_samples, buffer->SampleLen); + + if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) + SETERR_GOTO(context, AL_INVALID_OPERATION, buffer_error, + "Queueing non-persistently mapped buffer %u", buffer->id); + + if(BufferFmt == NULL) + BufferFmt = buffer; + else if(BufferFmt->Frequency != buffer->Frequency || + BufferFmt->FmtChannels != buffer->FmtChannels || + BufferFmt->OriginalType != buffer->OriginalType) + { + alSetError(context, AL_INVALID_OPERATION, "Queueing buffer with mismatched format"); + + buffer_error: + /* A buffer failed (invalid ID or format), so unlock and release + * each buffer we had. */ + while(BufferListStart) + { + ALbufferlistitem *next = ATOMIC_LOAD(&BufferListStart->next, + almemory_order_relaxed); + for(i = 0;i < BufferListStart->num_buffers;i++) + { + if((buffer=BufferListStart->buffers[i]) != NULL) + DecrementRef(&buffer->ref); + } + al_free(BufferListStart); + BufferListStart = next; + } + UnlockBufferList(device); + goto done; + } + } + /* All buffers good. */ + UnlockBufferList(device); + + /* Source is now streaming */ + source->SourceType = AL_STREAMING; + + if(!(BufferList=source->queue)) + source->queue = BufferListStart; + else + { + ALbufferlistitem *next; + while((next=ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed)) != NULL) + BufferList = next; + ATOMIC_STORE(&BufferList->next, BufferListStart, almemory_order_release); + } + +done: + UnlockSourceList(context); + ALCcontext_DecRef(context); +} + +AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers) +{ + ALCcontext *context; + ALsource *source; + ALbufferlistitem *BufferList; + ALbufferlistitem *Current; + ALvoice *voice; + ALsizei i; + + context = GetContextRef(); + if(!context) return; + + LockSourceList(context); + if(!(nb >= 0)) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing %d buffers", nb); + if((source=LookupSource(context, src)) == NULL) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src); + + /* Nothing to unqueue. */ + if(nb == 0) goto done; + + if(source->Looping) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing from looping source %u", src); + if(source->SourceType != AL_STREAMING) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing from a non-streaming source %u", + src); + + /* Make sure enough buffers have been processed to unqueue. */ + BufferList = source->queue; + Current = NULL; + if((voice=GetSourceVoice(source, context)) != NULL) + Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); + else if(source->state == AL_INITIAL) + Current = BufferList; + if(BufferList == Current) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing pending buffers"); + + i = BufferList->num_buffers; + while(i < nb) + { + /* If the next bufferlist to check is NULL or is the current one, it's + * trying to unqueue pending buffers. + */ + ALbufferlistitem *next = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + if(!next || next == Current) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing pending buffers"); + BufferList = next; + + i += BufferList->num_buffers; + } + + while(nb > 0) + { + ALbufferlistitem *head = source->queue; + ALbufferlistitem *next = ATOMIC_LOAD(&head->next, almemory_order_relaxed); + for(i = 0;i < head->num_buffers && nb > 0;i++,nb--) + { + ALbuffer *buffer = head->buffers[i]; + if(!buffer) + *(buffers++) = 0; + else + { + *(buffers++) = buffer->id; + DecrementRef(&buffer->ref); + } + } + if(i < head->num_buffers) + { + /* This head has some buffers left over, so move them to the front + * and update the sample and buffer count. + */ + ALsizei max_length = 0; + ALsizei j = 0; + while(i < head->num_buffers) + { + ALbuffer *buffer = head->buffers[i++]; + if(buffer) max_length = maxi(max_length, buffer->SampleLen); + head->buffers[j++] = buffer; + } + head->max_samples = max_length; + head->num_buffers = j; + break; + } + + /* Otherwise, free this item and set the source queue head to the next + * one. + */ + al_free(head); + source->queue = next; + } + +done: + UnlockSourceList(context); + ALCcontext_DecRef(context); +} + + +static void InitSourceParams(ALsource *Source, ALsizei num_sends) +{ + ALsizei i; + + Source->InnerAngle = 360.0f; + Source->OuterAngle = 360.0f; + Source->Pitch = 1.0f; + Source->Position[0] = 0.0f; + Source->Position[1] = 0.0f; + Source->Position[2] = 0.0f; + Source->Velocity[0] = 0.0f; + Source->Velocity[1] = 0.0f; + Source->Velocity[2] = 0.0f; + Source->Direction[0] = 0.0f; + Source->Direction[1] = 0.0f; + Source->Direction[2] = 0.0f; + Source->Orientation[0][0] = 0.0f; + Source->Orientation[0][1] = 0.0f; + Source->Orientation[0][2] = -1.0f; + Source->Orientation[1][0] = 0.0f; + Source->Orientation[1][1] = 1.0f; + Source->Orientation[1][2] = 0.0f; + Source->RefDistance = 1.0f; + Source->MaxDistance = FLT_MAX; + Source->RolloffFactor = 1.0f; + Source->Gain = 1.0f; + Source->MinGain = 0.0f; + Source->MaxGain = 1.0f; + Source->OuterGain = 0.0f; + Source->OuterGainHF = 1.0f; + + Source->DryGainHFAuto = AL_TRUE; + Source->WetGainAuto = AL_TRUE; + Source->WetGainHFAuto = AL_TRUE; + Source->AirAbsorptionFactor = 0.0f; + Source->RoomRolloffFactor = 0.0f; + Source->DopplerFactor = 1.0f; + Source->HeadRelative = AL_FALSE; + Source->Looping = AL_FALSE; + Source->DistanceModel = DefaultDistanceModel; + Source->Resampler = ResamplerDefault; + Source->DirectChannels = AL_FALSE; + Source->Spatialize = SpatializeAuto; + + Source->StereoPan[0] = DEG2RAD( 30.0f); + Source->StereoPan[1] = DEG2RAD(-30.0f); + + Source->Radius = 0.0f; + + Source->Direct.Gain = 1.0f; + Source->Direct.GainHF = 1.0f; + Source->Direct.HFReference = LOWPASSFREQREF; + Source->Direct.GainLF = 1.0f; + Source->Direct.LFReference = HIGHPASSFREQREF; + Source->Send = static_castSend)>(al_calloc(16, + num_sends*sizeof(Source->Send[0]))); + for(i = 0;i < num_sends;i++) + { + Source->Send[i].Slot = NULL; + Source->Send[i].Gain = 1.0f; + Source->Send[i].GainHF = 1.0f; + Source->Send[i].HFReference = LOWPASSFREQREF; + Source->Send[i].GainLF = 1.0f; + Source->Send[i].LFReference = HIGHPASSFREQREF; + } + + Source->Offset = 0.0; + Source->OffsetType = AL_NONE; + Source->SourceType = AL_UNDETERMINED; + Source->state = AL_INITIAL; + + Source->queue = NULL; + + ATOMIC_INIT(&Source->PropsClean, AL_TRUE); + + Source->VoiceIdx = -1; +} + +static void DeinitSource(ALsource *source, ALsizei num_sends) +{ + ALbufferlistitem *BufferList; + ALsizei i; + + BufferList = source->queue; + while(BufferList != NULL) + { + ALbufferlistitem *next = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + for(i = 0;i < BufferList->num_buffers;i++) + { + if(BufferList->buffers[i] != NULL) + DecrementRef(&BufferList->buffers[i]->ref); + } + al_free(BufferList); + BufferList = next; + } + source->queue = NULL; + + if(source->Send) + { + for(i = 0;i < num_sends;i++) + { + if(source->Send[i].Slot) + DecrementRef(&source->Send[i].Slot->ref); + source->Send[i].Slot = NULL; + } + al_free(source->Send); + source->Send = NULL; + } +} + +static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends, ALCcontext *context) +{ + struct ALvoiceProps *props; + ALsizei i; + + /* Get an unused property container, or allocate a new one as needed. */ + props = ATOMIC_LOAD(&context->FreeVoiceProps, almemory_order_acquire); + if(!props) + props = static_cast(al_calloc(16, + FAM_SIZE(struct ALvoiceProps, Send, num_sends))); + else + { + struct ALvoiceProps *next; + do { + next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); + } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeVoiceProps, &props, next, + almemory_order_acq_rel, almemory_order_acquire) == 0); + } + + /* Copy in current property values. */ + props->Pitch = source->Pitch; + props->Gain = source->Gain; + props->OuterGain = source->OuterGain; + props->MinGain = source->MinGain; + props->MaxGain = source->MaxGain; + props->InnerAngle = source->InnerAngle; + props->OuterAngle = source->OuterAngle; + props->RefDistance = source->RefDistance; + props->MaxDistance = source->MaxDistance; + props->RolloffFactor = source->RolloffFactor; + for(i = 0;i < 3;i++) + props->Position[i] = source->Position[i]; + for(i = 0;i < 3;i++) + props->Velocity[i] = source->Velocity[i]; + for(i = 0;i < 3;i++) + props->Direction[i] = source->Direction[i]; + for(i = 0;i < 2;i++) + { + ALsizei j; + for(j = 0;j < 3;j++) + props->Orientation[i][j] = source->Orientation[i][j]; + } + props->HeadRelative = source->HeadRelative; + props->DistanceModel = source->DistanceModel; + props->Resampler = source->Resampler; + props->DirectChannels = source->DirectChannels; + props->SpatializeMode = source->Spatialize; + + props->DryGainHFAuto = source->DryGainHFAuto; + props->WetGainAuto = source->WetGainAuto; + props->WetGainHFAuto = source->WetGainHFAuto; + props->OuterGainHF = source->OuterGainHF; + + props->AirAbsorptionFactor = source->AirAbsorptionFactor; + props->RoomRolloffFactor = source->RoomRolloffFactor; + props->DopplerFactor = source->DopplerFactor; + + props->StereoPan[0] = source->StereoPan[0]; + props->StereoPan[1] = source->StereoPan[1]; + + props->Radius = source->Radius; + + props->Direct.Gain = source->Direct.Gain; + props->Direct.GainHF = source->Direct.GainHF; + props->Direct.HFReference = source->Direct.HFReference; + props->Direct.GainLF = source->Direct.GainLF; + props->Direct.LFReference = source->Direct.LFReference; + + for(i = 0;i < num_sends;i++) + { + props->Send[i].Slot = source->Send[i].Slot; + props->Send[i].Gain = source->Send[i].Gain; + props->Send[i].GainHF = source->Send[i].GainHF; + props->Send[i].HFReference = source->Send[i].HFReference; + props->Send[i].GainLF = source->Send[i].GainLF; + props->Send[i].LFReference = source->Send[i].LFReference; + } + + /* Set the new container for updating internal parameters. */ + props = ATOMIC_EXCHANGE_PTR(&voice->Update, props, almemory_order_acq_rel); + if(props) + { + /* If there was an unused update container, put it back in the + * freelist. + */ + ATOMIC_REPLACE_HEAD(struct ALvoiceProps*, &context->FreeVoiceProps, props); + } +} + +void UpdateAllSourceProps(ALCcontext *context) +{ + ALsizei num_sends = context->Device->NumAuxSends; + ALsizei pos; + + for(pos = 0;pos < context->VoiceCount;pos++) + { + ALvoice *voice = context->Voices[pos]; + ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire); + if(source && !ATOMIC_EXCHANGE(&source->PropsClean, AL_TRUE, almemory_order_acq_rel)) + UpdateSourceProps(source, voice, num_sends, context); + } +} + + +/* GetSourceSampleOffset + * + * Gets the current read offset for the given Source, in 32.32 fixed-point + * samples. The offset is relative to the start of the queue (not the start of + * the current buffer). + */ +static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime) +{ + ALCdevice *device = context->Device; + const ALbufferlistitem *Current; + ALuint64 readPos; + ALuint refcount; + ALvoice *voice; + + do { + Current = NULL; + readPos = 0; + while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) + althrd_yield(); + *clocktime = GetDeviceClockTime(device); + + voice = GetSourceVoice(Source, context); + if(voice) + { + Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); + + readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << 32; + readPos |= (ALuint64)ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) << + (32-FRACTIONBITS); + } + ATOMIC_THREAD_FENCE(almemory_order_acquire); + } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); + + if(voice) + { + const ALbufferlistitem *BufferList = Source->queue; + while(BufferList && BufferList != Current) + { + readPos += (ALuint64)BufferList->max_samples << 32; + BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, + almemory_order_relaxed); + } + readPos = minu64(readPos, U64(0x7fffffffffffffff)); + } + + return (ALint64)readPos; +} + +/* GetSourceSecOffset + * + * Gets the current read offset for the given Source, in seconds. The offset is + * relative to the start of the queue (not the start of the current buffer). + */ +static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime) +{ + ALCdevice *device = context->Device; + const ALbufferlistitem *Current; + ALuint64 readPos; + ALuint refcount; + ALdouble offset; + ALvoice *voice; + + do { + Current = NULL; + readPos = 0; + while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) + althrd_yield(); + *clocktime = GetDeviceClockTime(device); + + voice = GetSourceVoice(Source, context); + if(voice) + { + Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); + + readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << + FRACTIONBITS; + readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); + } + ATOMIC_THREAD_FENCE(almemory_order_acquire); + } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); + + offset = 0.0; + if(voice) + { + const ALbufferlistitem *BufferList = Source->queue; + const ALbuffer *BufferFmt = NULL; + while(BufferList && BufferList != Current) + { + ALsizei i = 0; + while(!BufferFmt && i < BufferList->num_buffers) + BufferFmt = BufferList->buffers[i++]; + readPos += (ALuint64)BufferList->max_samples << FRACTIONBITS; + BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, + almemory_order_relaxed); + } + + while(BufferList && !BufferFmt) + { + ALsizei i = 0; + while(!BufferFmt && i < BufferList->num_buffers) + BufferFmt = BufferList->buffers[i++]; + BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, + almemory_order_relaxed); + } + assert(BufferFmt != NULL); + + offset = (ALdouble)readPos / (ALdouble)FRACTIONONE / + (ALdouble)BufferFmt->Frequency; + } + + return offset; +} + +/* GetSourceOffset + * + * Gets the current read offset for the given Source, in the appropriate format + * (Bytes, Samples or Seconds). The offset is relative to the start of the + * queue (not the start of the current buffer). + */ +static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) +{ + ALCdevice *device = context->Device; + const ALbufferlistitem *Current; + ALuint readPos; + ALsizei readPosFrac; + ALuint refcount; + ALdouble offset; + ALvoice *voice; + + do { + Current = NULL; + readPos = readPosFrac = 0; + while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) + althrd_yield(); + voice = GetSourceVoice(Source, context); + if(voice) + { + Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); + + readPos = ATOMIC_LOAD(&voice->position, almemory_order_relaxed); + readPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); + } + ATOMIC_THREAD_FENCE(almemory_order_acquire); + } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); + + offset = 0.0; + if(voice) + { + const ALbufferlistitem *BufferList = Source->queue; + const ALbuffer *BufferFmt = NULL; + ALboolean readFin = AL_FALSE; + ALuint totalBufferLen = 0; + + while(BufferList != NULL) + { + ALsizei i = 0; + while(!BufferFmt && i < BufferList->num_buffers) + BufferFmt = BufferList->buffers[i++]; + + readFin |= (BufferList == Current); + totalBufferLen += BufferList->max_samples; + if(!readFin) readPos += BufferList->max_samples; + + BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, + almemory_order_relaxed); + } + assert(BufferFmt != NULL); + + if(Source->Looping) + readPos %= totalBufferLen; + else + { + /* Wrap back to 0 */ + if(readPos >= totalBufferLen) + readPos = readPosFrac = 0; + } + + offset = 0.0; + switch(name) + { + case AL_SEC_OFFSET: + offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE) / BufferFmt->Frequency; + break; + + case AL_SAMPLE_OFFSET: + offset = readPos + (ALdouble)readPosFrac/FRACTIONONE; + break; + + case AL_BYTE_OFFSET: + if(BufferFmt->OriginalType == UserFmtIMA4) + { + ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; + ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels); + ALuint FrameBlockSize = BufferFmt->OriginalAlign; + + /* Round down to nearest ADPCM block */ + offset = (ALdouble)(readPos / FrameBlockSize * BlockSize); + } + else if(BufferFmt->OriginalType == UserFmtMSADPCM) + { + ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; + ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels); + ALuint FrameBlockSize = BufferFmt->OriginalAlign; + + /* Round down to nearest ADPCM block */ + offset = (ALdouble)(readPos / FrameBlockSize * BlockSize); + } + else + { + ALuint FrameSize = FrameSizeFromFmt(BufferFmt->FmtChannels, + BufferFmt->FmtType); + offset = (ALdouble)(readPos * FrameSize); + } + break; + } + } + + return offset; +} + + +/* ApplyOffset + * + * Apply the stored playback offset to the Source. This function will update + * the number of buffers "played" given the stored offset. + */ +static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) +{ + ALbufferlistitem *BufferList; + ALuint totalBufferLen; + ALuint offset = 0; + ALsizei frac = 0; + + /* Get sample frame offset */ + if(!GetSampleOffset(Source, &offset, &frac)) + return AL_FALSE; + + totalBufferLen = 0; + BufferList = Source->queue; + while(BufferList && totalBufferLen <= offset) + { + if((ALuint)BufferList->max_samples > offset-totalBufferLen) + { + /* Offset is in this buffer */ + ATOMIC_STORE(&voice->position, offset - totalBufferLen, almemory_order_relaxed); + ATOMIC_STORE(&voice->position_fraction, frac, almemory_order_relaxed); + ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_release); + return AL_TRUE; + } + totalBufferLen += BufferList->max_samples; + + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + } + + /* Offset is out of range of the queue */ + return AL_FALSE; +} + + +/* GetSampleOffset + * + * Retrieves the sample offset into the Source's queue (from the Sample, Byte + * or Second offset supplied by the application). This takes into account the + * fact that the buffer format may have been modifed since. + */ +static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac) +{ + const ALbuffer *BufferFmt = NULL; + const ALbufferlistitem *BufferList; + ALdouble dbloff, dblfrac; + + /* Find the first valid Buffer in the Queue */ + BufferList = Source->queue; + while(BufferList) + { + ALsizei i; + for(i = 0;i < BufferList->num_buffers && !BufferFmt;i++) + BufferFmt = BufferList->buffers[i]; + if(BufferFmt) break; + BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, + almemory_order_relaxed); + } + if(!BufferFmt) + { + Source->OffsetType = AL_NONE; + Source->Offset = 0.0; + return AL_FALSE; + } + + switch(Source->OffsetType) + { + case AL_BYTE_OFFSET: + /* Determine the ByteOffset (and ensure it is block aligned) */ + *offset = (ALuint)Source->Offset; + if(BufferFmt->OriginalType == UserFmtIMA4) + { + ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; + *offset /= align * ChannelsFromFmt(BufferFmt->FmtChannels); + *offset *= BufferFmt->OriginalAlign; + } + else if(BufferFmt->OriginalType == UserFmtMSADPCM) + { + ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; + *offset /= align * ChannelsFromFmt(BufferFmt->FmtChannels); + *offset *= BufferFmt->OriginalAlign; + } + else + *offset /= FrameSizeFromFmt(BufferFmt->FmtChannels, BufferFmt->FmtType); + *frac = 0; + break; + + case AL_SAMPLE_OFFSET: + dblfrac = modf(Source->Offset, &dbloff); + *offset = (ALuint)mind(dbloff, UINT_MAX); + *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0); + break; + + case AL_SEC_OFFSET: + dblfrac = modf(Source->Offset*BufferFmt->Frequency, &dbloff); + *offset = (ALuint)mind(dbloff, UINT_MAX); + *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0); + break; + } + Source->OffsetType = AL_NONE; + Source->Offset = 0.0; + + return AL_TRUE; +} + + +static ALsource *AllocSource(ALCcontext *context) +{ + ALCdevice *device = context->Device; + SourceSubList *sublist, *subend; + ALsource *source = NULL; + ALsizei lidx = 0; + ALsizei slidx; + + almtx_lock(&context->SourceLock); + if(context->NumSources >= device->SourcesMax) + { + almtx_unlock(&context->SourceLock); + alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax); + return NULL; + } + sublist = VECTOR_BEGIN(context->SourceList); + subend = VECTOR_END(context->SourceList); + for(;sublist != subend;++sublist) + { + if(sublist->FreeMask) + { + slidx = CTZ64(sublist->FreeMask); + source = sublist->Sources + slidx; + break; + } + ++lidx; + } + if(UNLIKELY(!source)) + { + const SourceSubList empty_sublist = { 0, NULL }; + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(VECTOR_SIZE(context->SourceList) >= 1<<25)) + { + almtx_unlock(&device->BufferLock); + alSetError(context, AL_OUT_OF_MEMORY, "Too many sources allocated"); + return NULL; + } + lidx = (ALsizei)VECTOR_SIZE(context->SourceList); + VECTOR_PUSH_BACK(context->SourceList, empty_sublist); + sublist = &VECTOR_BACK(context->SourceList); + sublist->FreeMask = ~U64(0); + sublist->Sources = static_cast(al_calloc(16, sizeof(ALsource)*64)); + if(UNLIKELY(!sublist->Sources)) + { + VECTOR_POP_BACK(context->SourceList); + almtx_unlock(&context->SourceLock); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate source batch"); + return NULL; + } + + slidx = 0; + source = sublist->Sources + slidx; + } + + memset(source, 0, sizeof(*source)); + InitSourceParams(source, device->NumAuxSends); + + /* Add 1 to avoid source ID 0. */ + source->id = ((lidx<<6) | slidx) + 1; + + context->NumSources++; + sublist->FreeMask &= ~(U64(1)<SourceLock); + + return source; +} + +static void FreeSource(ALCcontext *context, ALsource *source) +{ + ALCdevice *device = context->Device; + ALuint id = source->id - 1; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; + ALvoice *voice; + + ALCdevice_Lock(device); + if((voice=GetSourceVoice(source, context)) != NULL) + { + ATOMIC_STORE(&voice->Source, static_cast(nullptr), almemory_order_relaxed); + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + } + ALCdevice_Unlock(device); + + DeinitSource(source, device->NumAuxSends); + memset(source, 0, sizeof(*source)); + + VECTOR_ELEM(context->SourceList, lidx).FreeMask |= U64(1) << slidx; + context->NumSources--; +} + +/* ReleaseALSources + * + * Destroys all sources in the source map. + */ +ALvoid ReleaseALSources(ALCcontext *context) +{ + ALCdevice *device = context->Device; + SourceSubList *sublist = VECTOR_BEGIN(context->SourceList); + SourceSubList *subend = VECTOR_END(context->SourceList); + size_t leftover = 0; + for(;sublist != subend;++sublist) + { + ALuint64 usemask = ~sublist->FreeMask; + while(usemask) + { + ALsizei idx = CTZ64(usemask); + ALsource *source = sublist->Sources + idx; + + DeinitSource(source, device->NumAuxSends); + memset(source, 0, sizeof(*source)); + ++leftover; + + usemask &= ~(U64(1) << idx); + } + sublist->FreeMask = ~usemask; + } + if(leftover > 0) + WARN("(%p) Deleted " SZFMT " Source%s\n", device, leftover, (leftover==1)?"":"s"); +} -- cgit v1.2.3 From b7daddb564cfa551c9dcc983bdc0e6bc53cc67d3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 03:29:56 -0800 Subject: Try to clean up compat.h's macro block spaghetti a bit --- Alc/compat.h | 41 +++++++++++------------------------------ 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/Alc/compat.h b/Alc/compat.h index 31c84d48..18ba8da9 100644 --- a/Alc/compat.h +++ b/Alc/compat.h @@ -1,22 +1,13 @@ #ifndef AL_COMPAT_H #define AL_COMPAT_H -#include "alstring.h" - #ifdef __cplusplus -extern "C" { -#endif #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include -#define HAVE_DYNLOAD 1 - -#ifdef __cplusplus -} // extern "C" - #include #include #include @@ -210,18 +201,9 @@ public: } // namespace al -extern "C" { -#endif /* __cplusplus */ - -#else - -#if defined(HAVE_DLFCN_H) #define HAVE_DYNLOAD 1 -#endif - -#ifdef __cplusplus -} // extern "C" +#else /* _WIN32 */ #include @@ -232,24 +214,23 @@ using ifstream = std::ifstream; } // namespace al -extern "C" { -#endif /* __cplusplus */ - -#endif - -#ifdef HAVE_DYNLOAD -void *LoadLib(const char *name); -void CloseLib(void *handle); -void *GetSymbol(void *handle, const char *name); +#if defined(HAVE_DLFCN_H) +#define HAVE_DYNLOAD 1 #endif -#ifdef __cplusplus -} /* extern "C" */ +#endif /* _WIN32 */ #include struct PathNamePair { std::string path, fname; }; PathNamePair GetProcBinary(void); + +#ifdef HAVE_DYNLOAD +void *LoadLib(const char *name); +void CloseLib(void *handle); +void *GetSymbol(void *handle, const char *name); #endif +#endif /* __cplusplus */ + #endif /* AL_COMPAT_H */ -- cgit v1.2.3 From d4f64b9e29319f56f2ecab1291918a52ec8336f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 03:49:59 -0800 Subject: Use a C++ mutex with the device backend base --- Alc/backends/base.cpp | 21 +++++++++++++-------- Alc/backends/base.h | 14 +++++--------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/Alc/backends/base.cpp b/Alc/backends/base.cpp index 4a20518d..340ca7ac 100644 --- a/Alc/backends/base.cpp +++ b/Alc/backends/base.cpp @@ -26,14 +26,11 @@ ClockLatency GetClockLatency(ALCdevice *device) /* Base ALCbackend method implementations. */ void ALCbackend_Construct(ALCbackend *self, ALCdevice *device) { - int ret = almtx_init(&self->mMutex, almtx_recursive); - assert(ret == althrd_success); self->mDevice = device; } -void ALCbackend_Destruct(ALCbackend *self) +void ALCbackend_Destruct(ALCbackend* UNUSED(self)) { - almtx_destroy(&self->mMutex); } ALCboolean ALCbackend_reset(ALCbackend* UNUSED(self)) @@ -76,14 +73,22 @@ ClockLatency ALCbackend_getClockLatency(ALCbackend *self) void ALCbackend_lock(ALCbackend *self) { - int ret = almtx_lock(&self->mMutex); - assert(ret == althrd_success); + try { + self->mMutex.lock(); + } + catch(...) { + std::terminate(); + } } void ALCbackend_unlock(ALCbackend *self) { - int ret = almtx_unlock(&self->mMutex); - assert(ret == althrd_success); + try { + self->mMutex.unlock(); + } + catch(...) { + std::terminate(); + } } diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 75950344..f8b5f346 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -2,18 +2,16 @@ #define AL_BACKENDS_BASE_H #include "alMain.h" -#include "threads.h" #include "alstring.h" - #ifdef __cplusplus -extern "C" { -#endif -typedef struct ClockLatency { +#include + +struct ClockLatency { ALint64 ClockTime; ALint64 Latency; -} ClockLatency; +}; /* Helper to get the current clock time from the device's ClockBase, and * SamplesDone converted from the sample rate. @@ -29,8 +27,6 @@ void ALCdevice_Unlock(ALCdevice *device); ClockLatency GetClockLatency(ALCdevice *device); -#ifdef __cplusplus -} /* extern "C" */ struct ALCbackendVtable; @@ -39,7 +35,7 @@ struct ALCbackend { ALCdevice *mDevice; - almtx_t mMutex; + std::recursive_mutex mMutex; }; void ALCbackend_Construct(ALCbackend *self, ALCdevice *device); -- cgit v1.2.3 From 1971d0f5c6c94b250f4b3e29bdfa95c836f900bc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 04:24:33 -0800 Subject: Use std::string instead of al_string for enumerating --- Alc/alc.cpp | 35 ++++++++++++++--------------------- Alc/backends/alsa.cpp | 6 ++---- Alc/backends/base.h | 6 +++--- Alc/backends/coreaudio.cpp | 7 ++++--- Alc/backends/dsound.cpp | 8 +++----- Alc/backends/jack.cpp | 5 +++-- Alc/backends/loopback.cpp | 4 ++-- Alc/backends/null.cpp | 8 +++++--- Alc/backends/opensl.cpp | 5 +++-- Alc/backends/oss.cpp | 8 ++++---- Alc/backends/portaudio.cpp | 7 ++++--- Alc/backends/pulseaudio.cpp | 8 +++----- Alc/backends/qsa.cpp | 6 +++--- Alc/backends/sdl2.cpp | 12 +++++------- Alc/backends/sndio.cpp | 7 ++++--- Alc/backends/solaris.cpp | 6 +++--- Alc/backends/wasapi.cpp | 8 +++----- Alc/backends/wave.cpp | 7 ++++--- Alc/backends/winmm.cpp | 9 ++++----- 19 files changed, 76 insertions(+), 86 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 4f021a78..c90b97f6 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -707,8 +707,8 @@ constexpr ALCchar alcErrOutOfMemory[] = "Out of Memory"; /* Enumerated device names */ constexpr ALCchar alcDefaultName[] = "OpenAL Soft\0"; -al_string alcAllDevicesList; -al_string alcCaptureDeviceList; +std::string alcAllDevicesList; +std::string alcCaptureDeviceList; /* Default is always the first in the list */ std::string alcDefaultAllDevicesSpecifier; @@ -878,9 +878,6 @@ static void alc_init(void) LogFile = stderr; - AL_STRING_INIT(alcAllDevicesList); - AL_STRING_INIT(alcCaptureDeviceList); - str = getenv("__ALSOFT_HALF_ANGLE_CONES"); if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) ConeScale *= 0.5f; @@ -1173,8 +1170,8 @@ static void alc_initconfig(void) ************************************************/ static void alc_cleanup(void) { - AL_STRING_DEINIT(alcAllDevicesList); - AL_STRING_DEINIT(alcCaptureDeviceList); + alcAllDevicesList.clear(); + alcCaptureDeviceList.clear(); alcDefaultAllDevicesSpecifier.clear(); alcCaptureDefaultDeviceSpecifier.clear(); @@ -1232,12 +1229,12 @@ static void alc_deinit(void) /************************************************ * Device enumeration ************************************************/ -static void ProbeDevices(al_string *list, struct BackendInfo *backendinfo, enum DevProbe type) +static void ProbeDevices(std::string *list, struct BackendInfo *backendinfo, enum DevProbe type) { DO_INITCONFIG(); std::lock_guard _{ListLock}; - alstr_clear(list); + list->clear(); if(backendinfo->getFactory) { ALCbackendFactory *factory = backendinfo->getFactory(); @@ -3077,7 +3074,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para else { ProbeAllDevicesList(); - value = alstr_get_cstr(alcAllDevicesList); + value = alcAllDevicesList.c_str(); } break; @@ -3090,7 +3087,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para else { ProbeCaptureDeviceList(); - value = alstr_get_cstr(alcCaptureDeviceList); + value = alcCaptureDeviceList.c_str(); } break; @@ -3100,25 +3097,21 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para break; case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: - if(alstr_empty(alcAllDevicesList)) + if(alcAllDevicesList.empty()) ProbeAllDevicesList(); - VerifyDevice(&Device); - - alcDefaultAllDevicesSpecifier = alstr_get_cstr(alcAllDevicesList); + /* Copy first entry as default. */ + alcDefaultAllDevicesSpecifier = alcAllDevicesList.c_str(); value = alcDefaultAllDevicesSpecifier.c_str(); - if(Device) ALCdevice_DecRef(Device); break; case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: - if(alstr_empty(alcCaptureDeviceList)) + if(alcCaptureDeviceList.empty()) ProbeCaptureDeviceList(); - VerifyDevice(&Device); - - alcCaptureDefaultDeviceSpecifier = alstr_get_cstr(alcCaptureDeviceList); + /* Copy first entry as default. */ + alcCaptureDefaultDeviceSpecifier = alcCaptureDeviceList.c_str(); value = alcCaptureDefaultDeviceSpecifier.c_str(); - if(Device) ALCdevice_DecRef(Device); break; case ALC_EXTENSIONS: diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index 15308632..5a389eab 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -1327,16 +1327,14 @@ static ALCboolean ALCalsaBackendFactory_querySupport(ALCalsaBackendFactory* UNUS return ALC_FALSE; } -static void ALCalsaBackendFactory_probe(ALCalsaBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +static void ALCalsaBackendFactory_probe(ALCalsaBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) { auto add_device = [outnames](const DevMap &entry) -> void { - const char *name{entry.name.c_str()}; - size_t namelen{entry.name.length()}; /* +1 to also append the null char (to ensure a null-separated list and * double-null terminated list). */ - alstr_append_range(outnames, name, name + namelen+1); + outnames->append(entry.name.c_str(), entry.name.length()+1); }; switch(type) { diff --git a/Alc/backends/base.h b/Alc/backends/base.h index f8b5f346..360c2ffd 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -2,10 +2,10 @@ #define AL_BACKENDS_BASE_H #include "alMain.h" -#include "alstring.h" #ifdef __cplusplus +#include #include struct ClockLatency { @@ -119,7 +119,7 @@ struct ALCbackendFactoryVtable { ALCboolean (*const querySupport)(ALCbackendFactory *self, ALCbackend_Type type); - void (*const probe)(ALCbackendFactory *self, enum DevProbe type, al_string *outnames); + void (*const probe)(ALCbackendFactory *self, enum DevProbe type, std::string *outnames); ALCbackend* (*const createBackend)(ALCbackendFactory *self, ALCdevice *device, ALCbackend_Type type); }; @@ -128,7 +128,7 @@ struct ALCbackendFactoryVtable { DECLARE_THUNK(T, ALCbackendFactory, ALCboolean, init) \ DECLARE_THUNK(T, ALCbackendFactory, void, deinit) \ DECLARE_THUNK1(T, ALCbackendFactory, ALCboolean, querySupport, ALCbackend_Type) \ -DECLARE_THUNK2(T, ALCbackendFactory, void, probe, enum DevProbe, al_string*) \ +DECLARE_THUNK2(T, ALCbackendFactory, void, probe, enum DevProbe, std::string*) \ DECLARE_THUNK2(T, ALCbackendFactory, ALCbackend*, createBackend, ALCdevice*, ALCbackend_Type) \ \ static const struct ALCbackendFactoryVtable T##_ALCbackendFactory_vtable = { \ diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index 08cdeeaa..83ea4d5f 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -760,7 +760,7 @@ ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void); static ALCboolean ALCcoreAudioBackendFactory_init(ALCcoreAudioBackendFactory *self); static DECLARE_FORWARD(ALCcoreAudioBackendFactory, ALCbackendFactory, void, deinit) static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFactory *self, ALCbackend_Type type); -static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory *self, enum DevProbe type, al_string *outnames); +static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory *self, enum DevProbe type, std::string *outnames); static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCcoreAudioBackendFactory); @@ -788,13 +788,14 @@ static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFac return ALC_FALSE; } -static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) { switch(type) { case ALL_DEVICE_PROBE: case CAPTURE_DEVICE_PROBE: - alstr_append_range(outnames, ca_device, ca_device+sizeof(ca_device)); + /* Includes null char. */ + outnames->append(ca_device, sizeof(ca_device)); break; } } diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 10650175..50e956ea 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -951,7 +951,7 @@ 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, al_string *outnames); +static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory *self, enum DevProbe type, std::string *outnames); static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCdsoundBackendFactory); @@ -994,16 +994,14 @@ static ALCboolean ALCdsoundBackendFactory_querySupport(ALCdsoundBackendFactory* return ALC_FALSE; } -static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) { auto add_device = [outnames](const DevMap &entry) -> void { - const char *name{entry.name.c_str()}; - size_t namelen{entry.name.length()}; /* +1 to also append the null char (to ensure a null-separated list and * double-null terminated list). */ - alstr_append_range(outnames, name, name + namelen+1); + outnames->append(entry.name.c_str(), entry.name.length()+1); }; /* Initialize COM to prevent name truncation */ diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index db5e4a83..83f591fe 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -568,12 +568,13 @@ static ALCboolean ALCjackBackendFactory_querySupport(ALCjackBackendFactory* UNUS return ALC_FALSE; } -static void ALCjackBackendFactory_probe(ALCjackBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +static void ALCjackBackendFactory_probe(ALCjackBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) { switch(type) { case ALL_DEVICE_PROBE: - alstr_append_range(outnames, jackDevice, jackDevice+sizeof(jackDevice)); + /* Includes null char. */ + outnames->append(jackDevice, sizeof(jackDevice)); break; case CAPTURE_DEVICE_PROBE: diff --git a/Alc/backends/loopback.cpp b/Alc/backends/loopback.cpp index dd012ae5..3726463c 100644 --- a/Alc/backends/loopback.cpp +++ b/Alc/backends/loopback.cpp @@ -90,7 +90,7 @@ ALCbackendFactory *ALCloopbackFactory_getFactory(void); static ALCboolean ALCloopbackFactory_init(ALCloopbackFactory *self); static DECLARE_FORWARD(ALCloopbackFactory, ALCbackendFactory, void, deinit) static ALCboolean ALCloopbackFactory_querySupport(ALCloopbackFactory *self, ALCbackend_Type type); -static void ALCloopbackFactory_probe(ALCloopbackFactory *self, enum DevProbe type, al_string *outnames); +static void ALCloopbackFactory_probe(ALCloopbackFactory *self, enum DevProbe type, std::string *outnames); static ALCbackend* ALCloopbackFactory_createBackend(ALCloopbackFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCloopbackFactory); @@ -111,7 +111,7 @@ static ALCboolean ALCloopbackFactory_querySupport(ALCloopbackFactory* UNUSED(sel return ALC_FALSE; } -static void ALCloopbackFactory_probe(ALCloopbackFactory* UNUSED(self), enum DevProbe UNUSED(type), al_string* UNUSED(outnames)) +static void ALCloopbackFactory_probe(ALCloopbackFactory* UNUSED(self), enum DevProbe UNUSED(type), std::string* UNUSED(outnames)) { } diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index ccb1327f..c8523c88 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -185,7 +185,7 @@ ALCbackendFactory *ALCnullBackendFactory_getFactory(void); static ALCboolean ALCnullBackendFactory_init(ALCnullBackendFactory *self); static DECLARE_FORWARD(ALCnullBackendFactory, ALCbackendFactory, void, deinit) static ALCboolean ALCnullBackendFactory_querySupport(ALCnullBackendFactory *self, ALCbackend_Type type); -static void ALCnullBackendFactory_probe(ALCnullBackendFactory *self, enum DevProbe type, al_string *outnames); +static void ALCnullBackendFactory_probe(ALCnullBackendFactory *self, enum DevProbe type, std::string *outnames); static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCnullBackendFactory); @@ -214,13 +214,15 @@ static ALCboolean ALCnullBackendFactory_querySupport(ALCnullBackendFactory* UNUS return ALC_FALSE; } -static void ALCnullBackendFactory_probe(ALCnullBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +static void ALCnullBackendFactory_probe(ALCnullBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) { switch(type) { case ALL_DEVICE_PROBE: + /* Includes null char. */ + outnames->append(nullDevice, sizeof(nullDevice)); + break; case CAPTURE_DEVICE_PROBE: - alstr_append_range(outnames, nullDevice, nullDevice+sizeof(nullDevice)); break; } } diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index a8bb57eb..9d938ba4 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -1029,13 +1029,14 @@ static ALCboolean ALCopenslBackendFactory_querySupport(ALCopenslBackendFactory* return ALC_FALSE; } -static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) { switch(type) { case ALL_DEVICE_PROBE: case CAPTURE_DEVICE_PROBE: - alstr_append_range(outnames, opensl_device, opensl_device+sizeof(opensl_device)); + /* Includes null char. */ + outnames->append(opensl_device, sizeof(opensl_device)); break; } } diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 65212fba..618730b3 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -774,7 +774,7 @@ ALCbackendFactory *ALCossBackendFactory_getFactory(void); static ALCboolean ALCossBackendFactory_init(ALCossBackendFactory *self); static void ALCossBackendFactory_deinit(ALCossBackendFactory *self); static ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory *self, ALCbackend_Type type); -static void ALCossBackendFactory_probe(ALCossBackendFactory *self, enum DevProbe type, al_string *outnames); +static void ALCossBackendFactory_probe(ALCossBackendFactory *self, enum DevProbe type, std::string *outnames); static ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCossBackendFactory); @@ -812,7 +812,7 @@ ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory* UNUSED(self), return ALC_FALSE; } -void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) { auto add_device = [outnames](const DevMap &entry) -> void { @@ -821,8 +821,8 @@ void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProb if(stat(entry.device_name.c_str(), &buf) == 0) #endif { - const char *name{entry.name.c_str()}; - alstr_append_range(outnames, name, name+entry.name.length()+1); + /* Includes null char. */ + outnames->append(entry.name.c_str(), entry.name.length()+1); } }; diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index e1b1c265..03194c05 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -484,7 +484,7 @@ struct ALCportBackendFactory final : public ALCbackendFactory { static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory *self); static void ALCportBackendFactory_deinit(ALCportBackendFactory *self); static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory *self, ALCbackend_Type type); -static void ALCportBackendFactory_probe(ALCportBackendFactory *self, enum DevProbe type, al_string *outnames); +static void ALCportBackendFactory_probe(ALCportBackendFactory *self, enum DevProbe type, std::string *outnames); static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCportBackendFactory); @@ -521,13 +521,14 @@ static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory* UNUS return ALC_FALSE; } -static void ALCportBackendFactory_probe(ALCportBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +static void ALCportBackendFactory_probe(ALCportBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) { switch(type) { case ALL_DEVICE_PROBE: case CAPTURE_DEVICE_PROBE: - alstr_append_range(outnames, pa_device, pa_device+sizeof(pa_device)); + /* Includes null char. */ + outnames->append(pa_device, sizeof(pa_device)); break; } } diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 09b55229..37aee77c 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -1741,7 +1741,7 @@ struct PulseBackendFactory final : public ALCbackendFactory { static ALCboolean PulseBackendFactory_init(PulseBackendFactory *self); static void PulseBackendFactory_deinit(PulseBackendFactory *self); static ALCboolean PulseBackendFactory_querySupport(PulseBackendFactory *self, ALCbackend_Type type); -static void PulseBackendFactory_probe(PulseBackendFactory *self, enum DevProbe type, al_string *outnames); +static void PulseBackendFactory_probe(PulseBackendFactory *self, enum DevProbe type, std::string *outnames); static ALCbackend* PulseBackendFactory_createBackend(PulseBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(PulseBackendFactory); @@ -1810,16 +1810,14 @@ static ALCboolean PulseBackendFactory_querySupport(PulseBackendFactory* UNUSED(s return ALC_FALSE; } -static void PulseBackendFactory_probe(PulseBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +static void PulseBackendFactory_probe(PulseBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) { auto add_device = [outnames](const DevMap &entry) -> void { - const char *name{entry.name.c_str()}; - size_t namelen{entry.name.length()}; /* +1 to also append the null char (to ensure a null-separated list and * double-null terminated list). */ - alstr_append_range(outnames, name, name + namelen+1); + outnames->append(entry.name.c_str(), entry.name.length()+1); }; switch(type) { diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index b2890705..7afd3214 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -997,7 +997,7 @@ struct ALCqsaBackendFactory final : public ALCbackendFactory { static ALCboolean ALCqsaBackendFactory_init(ALCqsaBackendFactory* UNUSED(self)); static void ALCqsaBackendFactory_deinit(ALCqsaBackendFactory* UNUSED(self)); static ALCboolean ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory* UNUSED(self), ALCbackend_Type type); -static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames); +static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames); static ALCbackend* ALCqsaBackendFactory_createBackend(ALCqsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCqsaBackendFactory); @@ -1029,14 +1029,14 @@ static ALCboolean ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory* UNUSED return ALC_FALSE; } -static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) { switch (type) { #define APPEND_OUTNAME(e) do { \ const char *n_ = (e)->name; \ if(n_ && n_[0]) \ - alstr_append_range(outnames, n_, n_+strlen(n_)+1); \ + outnames->append(n_, strlen(n_)+1); \ } while(0) case ALL_DEVICE_PROBE: deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap); diff --git a/Alc/backends/sdl2.cpp b/Alc/backends/sdl2.cpp index cf81e1f0..82c350e1 100644 --- a/Alc/backends/sdl2.cpp +++ b/Alc/backends/sdl2.cpp @@ -222,7 +222,7 @@ ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void); static ALCboolean ALCsdl2BackendFactory_init(ALCsdl2BackendFactory *self); static void ALCsdl2BackendFactory_deinit(ALCsdl2BackendFactory *self); static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory *self, ALCbackend_Type type); -static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory *self, enum DevProbe type, al_string *outnames); +static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory *self, enum DevProbe type, std::string *outnames); static ALCbackend* ALCsdl2BackendFactory_createBackend(ALCsdl2BackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsdl2BackendFactory); @@ -257,23 +257,21 @@ static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory* UNUS return ALC_FALSE; } -static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) { if(type != ALL_DEVICE_PROBE) return; int num_devices{SDL_GetNumAudioDevices(SDL_FALSE)}; - alstr_append_range(outnames, defaultDeviceName, defaultDeviceName+sizeof(defaultDeviceName)); + /* Includes null char. */ + outnames->append(defaultDeviceName, sizeof(defaultDeviceName)); for(int i{0};i < num_devices;++i) { std::string name{DEVNAME_PREFIX}; name += SDL_GetAudioDeviceName(i, SDL_FALSE); if(!name.empty()) - { - const char *namestr{name.c_str()}; - alstr_append_range(outnames, namestr, namestr+name.length()+1); - } + outnames->append(name.c_str(), name.length()+1); } } diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index 818e107c..c97226a6 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -544,7 +544,7 @@ ALCbackendFactory *SndioBackendFactory_getFactory(void); static ALCboolean SndioBackendFactory_init(SndioBackendFactory *self); static DECLARE_FORWARD(SndioBackendFactory, ALCbackendFactory, void, deinit) static ALCboolean SndioBackendFactory_querySupport(SndioBackendFactory *self, ALCbackend_Type type); -static void SndioBackendFactory_probe(SndioBackendFactory *self, enum DevProbe type, al_string *outnames); +static void SndioBackendFactory_probe(SndioBackendFactory *self, enum DevProbe type, std::string *outnames); static ALCbackend* SndioBackendFactory_createBackend(SndioBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(SndioBackendFactory); @@ -571,13 +571,14 @@ static ALCboolean SndioBackendFactory_querySupport(SndioBackendFactory* UNUSED(s return ALC_FALSE; } -static void SndioBackendFactory_probe(SndioBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +static void SndioBackendFactory_probe(SndioBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) { switch(type) { case ALL_DEVICE_PROBE: case CAPTURE_DEVICE_PROBE: - alstr_append_range(outnames, sndio_device, sndio_device+sizeof(sndio_device)); + /* Includes null char. */ + outnames->append(sndio_device, sizeof(sndio_device)); break; } } diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index 953163fd..b63a85e8 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -301,7 +301,7 @@ ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void); static ALCboolean ALCsolarisBackendFactory_init(ALCsolarisBackendFactory *self); static DECLARE_FORWARD(ALCsolarisBackendFactory, ALCbackendFactory, void, deinit) static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory *self, ALCbackend_Type type); -static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory *self, enum DevProbe type, al_string *outnames); +static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory *self, enum DevProbe type, std::string *outnames); static ALCbackend* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsolarisBackendFactory); @@ -330,7 +330,7 @@ static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory return ALC_FALSE; } -static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) { switch(type) { @@ -340,7 +340,7 @@ static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory* UNUSED(self struct stat buf; if(stat(solaris_driver, &buf) == 0) #endif - alstr_append_range(outnames, solaris_device, solaris_device+sizeof(solaris_device)); + outnames->append(solaris_device, sizeof(solaris_device)); } break; diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 22edc09f..b55187ab 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -1824,7 +1824,7 @@ struct ALCwasapiBackendFactory final : public ALCbackendFactory { static ALCboolean ALCwasapiBackendFactory_init(ALCwasapiBackendFactory *self); static void ALCwasapiBackendFactory_deinit(ALCwasapiBackendFactory *self); static ALCboolean ALCwasapiBackendFactory_querySupport(ALCwasapiBackendFactory *self, ALCbackend_Type type); -static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory *self, enum DevProbe type, al_string *outnames); +static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory *self, enum DevProbe type, std::string *outnames); static ALCbackend* ALCwasapiBackendFactory_createBackend(ALCwasapiBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwasapiBackendFactory); @@ -1880,7 +1880,7 @@ static ALCboolean ALCwasapiBackendFactory_querySupport(ALCwasapiBackendFactory* return ALC_FALSE; } -static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) { ThreadRequest req{ nullptr, 0 }; @@ -1891,12 +1891,10 @@ static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory* UNUSED(self), { auto add_device = [outnames](const DevMap &entry) -> void { - const char *name{entry.name.c_str()}; - size_t namelen{entry.name.length()}; /* +1 to also append the null char (to ensure a null-separated list * and double-null terminated list). */ - alstr_append_range(outnames, name, name + namelen+1); + outnames->append(entry.name.c_str(), entry.name.length()+1); }; HRESULT hr = E_FAIL; if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, type)) diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index ea57ba65..48b3e911 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -396,7 +396,7 @@ ALCbackendFactory *ALCwaveBackendFactory_getFactory(void); static ALCboolean ALCwaveBackendFactory_init(ALCwaveBackendFactory *self); static DECLARE_FORWARD(ALCwaveBackendFactory, ALCbackendFactory, void, deinit) static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory *self, ALCbackend_Type type); -static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory *self, enum DevProbe type, al_string *outnames); +static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory *self, enum DevProbe type, std::string *outnames); static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwaveBackendFactory); @@ -419,12 +419,13 @@ static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory* UNUS return ALC_FALSE; } -static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) { switch(type) { case ALL_DEVICE_PROBE: - alstr_append_range(outnames, waveDevice, waveDevice+sizeof(waveDevice)); + /* Includes null char. */ + outnames->append(waveDevice, sizeof(waveDevice)); break; case CAPTURE_DEVICE_PROBE: break; diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 40a34b16..6e43ff79 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -672,7 +672,7 @@ struct ALCwinmmBackendFactory final : public ALCbackendFactory { static ALCboolean ALCwinmmBackendFactory_init(ALCwinmmBackendFactory *self); static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory *self); static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory *self, ALCbackend_Type type); -static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory *self, enum DevProbe type, al_string *outnames); +static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory *self, enum DevProbe type, std::string *outnames); static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwinmmBackendFactory); @@ -700,16 +700,15 @@ static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory* UN return ALC_FALSE; } -static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) +static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) { auto add_device = [outnames](const std::string &dname) -> void { - const char *name{dname.c_str()}; - size_t namelen{dname.length()}; /* +1 to also append the null char (to ensure a null-separated list and * double-null terminated list). */ - alstr_append_range(outnames, name, name + namelen+1); + if(!dname.empty()) + outnames->append(dname.c_str(), dname.length()+1); }; switch(type) { -- cgit v1.2.3 From 17161131e5f3309d6b2f27834102d3ca83b67afc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 04:28:47 -0800 Subject: Remove an unused extern inline --- Alc/inldefs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/Alc/inldefs.c b/Alc/inldefs.c index dd66da13..451c3bcc 100644 --- a/Alc/inldefs.c +++ b/Alc/inldefs.c @@ -30,8 +30,6 @@ extern inline void UnlockBufferList(ALCdevice *device); extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type); extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); -extern inline ALuint64 GetDeviceClockTime(ALCdevice *device); - extern inline void alstr_reset(al_string *str); extern inline size_t alstr_length(const_al_string str); -- cgit v1.2.3 From 08bee7cb586abe53ebd36d4d54160a12bf9d6dfa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 04:35:35 -0800 Subject: Search the right list for WASAPI name duplicates --- Alc/backends/wasapi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index b55187ab..64e7d43c 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -259,7 +259,7 @@ void add_device(IMMDevice *device, const WCHAR *devid, std::vector &list int count{1}; std::string newname{basename}; - while(checkName(PlaybackDevices, newname)) + while(checkName(list, newname)) { newname = basename; newname += " #"; -- cgit v1.2.3 From 9d9d626d99e2514c03a783140fa11076a4580607 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 05:33:02 -0800 Subject: Avoid some more uses of al_string --- Alc/backends/jack.cpp | 7 +++---- Alc/backends/pulseaudio.cpp | 2 +- Alc/helpers.cpp | 14 ++++++-------- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index 83f591fe..4aa6cd78 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -102,7 +102,7 @@ static ALCboolean jack_load(void) #ifdef HAVE_DYNLOAD if(!jack_handle) { - al_string missing_funcs = AL_STRING_INIT_STATIC(); + std::string missing_funcs; #ifdef _WIN32 #define JACKLIB "libjack.dll" @@ -121,7 +121,7 @@ static ALCboolean jack_load(void) p##f = reinterpret_cast(GetSymbol(jack_handle, #f)); \ if(p##f == nullptr) { \ error = ALC_TRUE; \ - alstr_append_cstr(&missing_funcs, "\n" #f); \ + missing_funcs += "\n" #f; \ } \ } while(0) JACK_FUNCS(LOAD_FUNC); @@ -133,11 +133,10 @@ static ALCboolean jack_load(void) if(error) { - WARN("Missing expected functions:%s\n", alstr_get_cstr(missing_funcs)); + WARN("Missing expected functions:%s\n", missing_funcs.c_str()); CloseLib(jack_handle); jack_handle = NULL; } - alstr_reset(&missing_funcs); } #endif diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 37aee77c..77719e3c 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -1877,7 +1877,7 @@ static ALCboolean PulseBackendFactory_querySupport(PulseBackendFactory* UNUSED(s return ALC_FALSE; } -static void PulseBackendFactory_probe(PulseBackendFactory* UNUSED(self), enum DevProbe UNUSED(type), al_string* UNUSED(outnames)) +static void PulseBackendFactory_probe(PulseBackendFactory* UNUSED(self), enum DevProbe UNUSED(type), std::string* UNUSED(outnames)) { } diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index 833be68e..468df505 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -210,7 +210,7 @@ void FillCPUCaps(int capfilter) ERR("Failed to open /proc/cpuinfo, cannot check for NEON support\n"); else { - al_string features = AL_STRING_INIT_STATIC(); + std::string features; char buf[256]; while(fgets(buf, sizeof(buf), file) != nullptr) @@ -218,21 +218,21 @@ void FillCPUCaps(int capfilter) if(strncmp(buf, "Features\t:", 10) != 0) continue; - alstr_copy_cstr(&features, buf+10); - while(VECTOR_BACK(features) != '\n') + features = buf+10; + while(features.back() != '\n') { if(fgets(buf, sizeof(buf), file) == nullptr) break; - alstr_append_cstr(&features, buf); + features += buf; } break; } fclose(file); file = nullptr; - if(!alstr_empty(features)) + if(!features.empty()) { - const char *str = alstr_get_cstr(features); + const char *str = features.c_str(); while(isspace(str[0])) ++str; TRACE("Got features string:%s\n", str); @@ -246,8 +246,6 @@ void FillCPUCaps(int capfilter) ++str; } } - - alstr_reset(&features); } #endif -- cgit v1.2.3 From ab9f8162b84870161948ddd27d29483206dd4e57 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 05:38:27 -0800 Subject: Pass a normal const char* to EnumerateHrtf --- Alc/alc.cpp | 4 ++-- Alc/hrtf.cpp | 8 ++++---- Alc/hrtf.h | 3 +-- Alc/panning.cpp | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index c90b97f6..dab2a70d 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1996,7 +1996,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(VECTOR_SIZE(device->HrtfList) == 0) { VECTOR_DEINIT(device->HrtfList); - device->HrtfList = EnumerateHrtf(device->DeviceName); + device->HrtfList = EnumerateHrtf(alstr_get_cstr(device->DeviceName)); } if(VECTOR_SIZE(device->HrtfList) > 0) { @@ -3448,7 +3448,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC case ALC_NUM_HRTF_SPECIFIERS_SOFT: almtx_lock(&device->BackendLock); FreeHrtfList(&device->HrtfList); - device->HrtfList = EnumerateHrtf(device->DeviceName); + device->HrtfList = EnumerateHrtf(alstr_get_cstr(device->DeviceName)); values[0] = (ALCint)VECTOR_SIZE(device->HrtfList); almtx_unlock(&device->BackendLock); return 1; diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 153b57b6..4bc1305d 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -1116,13 +1116,13 @@ ResData GetResource(int name) } // namespace -vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname) +vector_EnumeratedHrtf EnumerateHrtf(const char *devname) { vector_EnumeratedHrtf list{VECTOR_INIT_STATIC()}; bool usedefaults{true}; const char *pathlist{""}; - if(ConfigValueStr(alstr_get_cstr(devname), nullptr, "hrtf-paths", &pathlist)) + if(ConfigValueStr(devname, nullptr, "hrtf-paths", &pathlist)) { while(pathlist && *pathlist) { @@ -1154,7 +1154,7 @@ vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname) pathlist = next; } } - else if(ConfigValueExists(alstr_get_cstr(devname), nullptr, "hrtf_tables")) + else if(ConfigValueExists(devname, nullptr, "hrtf_tables")) ERR("The hrtf_tables option is deprecated, please use hrtf-paths instead.\n"); if(usedefaults) @@ -1172,7 +1172,7 @@ vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname) } const char *defaulthrtf{""}; - if(VECTOR_SIZE(list) > 1 && ConfigValueStr(alstr_get_cstr(devname), nullptr, "default-hrtf", &defaulthrtf)) + if(VECTOR_SIZE(list) > 1 && ConfigValueStr(devname, nullptr, "default-hrtf", &defaulthrtf)) { const EnumeratedHrtf *iter{}; /* Find the preferred HRTF and move it to the front of the list. */ diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 1cdfe568..71956691 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -5,7 +5,6 @@ #include "AL/alc.h" #include "alMain.h" -#include "alstring.h" #include "atomic.h" @@ -69,7 +68,7 @@ struct AngularPoint { void FreeHrtfs(void); -vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname); +vector_EnumeratedHrtf EnumerateHrtf(const char *devname); void FreeHrtfList(vector_EnumeratedHrtf *list); struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry); void Hrtf_IncRef(struct Hrtf *hrtf); diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 1d1eb7ef..6507cec5 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -1116,7 +1116,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(VECTOR_SIZE(device->HrtfList) == 0) { VECTOR_DEINIT(device->HrtfList); - device->HrtfList = EnumerateHrtf(device->DeviceName); + device->HrtfList = EnumerateHrtf(alstr_get_cstr(device->DeviceName)); } if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->HrtfList)) -- cgit v1.2.3 From 7b3a2085aac8eac47f9968f331d3991167793e85 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 06:23:01 -0800 Subject: Use a regular char* for the device's name --- Alc/alc.cpp | 35 ++++++++++++++++++----------------- Alc/backends/alsa.cpp | 10 ++++++---- Alc/backends/coreaudio.cpp | 6 ++++-- Alc/backends/dsound.cpp | 6 ++++-- Alc/backends/jack.cpp | 7 ++++--- Alc/backends/loopback.cpp | 3 ++- Alc/backends/null.cpp | 3 ++- Alc/backends/opensl.cpp | 6 ++++-- Alc/backends/oss.cpp | 6 ++++-- Alc/backends/portaudio.cpp | 6 ++++-- Alc/backends/pulseaudio.cpp | 16 ++++++++++------ Alc/backends/qsa.cpp | 6 ++++-- Alc/backends/sdl2.cpp | 3 ++- Alc/backends/sndio.cpp | 6 ++++-- Alc/backends/solaris.cpp | 3 ++- Alc/backends/wasapi.cpp | 22 ++++++++++++---------- Alc/backends/wave.cpp | 3 ++- Alc/backends/winmm.cpp | 6 ++++-- Alc/helpers.cpp | 9 +++++++++ Alc/hrtf.cpp | 12 ++---------- Alc/panning.cpp | 26 +++++++++----------------- OpenAL32/Include/alMain.h | 4 +++- 22 files changed, 115 insertions(+), 89 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index dab2a70d..159e3bc8 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1910,7 +1910,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } #undef TRACE_ATTR - ConfigValueUInt(alstr_get_cstr(device->DeviceName), nullptr, "frequency", &freq); + ConfigValueUInt(device->DeviceName, nullptr, "frequency", &freq); freq = maxu(freq, MIN_OUTPUT_RATE); device->UpdateSize = (ALuint64)device->UpdateSize * freq / @@ -1924,7 +1924,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(numMono > INT_MAX-numStereo) numMono = INT_MAX-numStereo; numMono += numStereo; - if(ConfigValueInt(alstr_get_cstr(device->DeviceName), nullptr, "sources", &numMono)) + if(ConfigValueInt(device->DeviceName, nullptr, "sources", &numMono)) { if(numMono <= 0) numMono = 256; @@ -1938,7 +1938,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->NumMonoSources = numMono; device->NumStereoSources = numStereo; - if(ConfigValueInt(alstr_get_cstr(device->DeviceName), nullptr, "sends", &new_sends)) + if(ConfigValueInt(device->DeviceName, nullptr, "sends", &new_sends)) new_sends = mini(numSends, clampi(new_sends, 0, MAX_SENDS)); else new_sends = numSends; @@ -1980,7 +1980,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(device->Type != Loopback) { const char *hrtf; - if(ConfigValueStr(alstr_get_cstr(device->DeviceName), nullptr, "hrtf", &hrtf)) + if(ConfigValueStr(device->DeviceName, nullptr, "hrtf", &hrtf)) { if(strcasecmp(hrtf, "true") == 0) hrtf_userreq = Hrtf_Enable; @@ -1996,7 +1996,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(VECTOR_SIZE(device->HrtfList) == 0) { VECTOR_DEINIT(device->HrtfList); - device->HrtfList = EnumerateHrtf(alstr_get_cstr(device->DeviceName)); + device->HrtfList = EnumerateHrtf(device->DeviceName); } if(VECTOR_SIZE(device->HrtfList) > 0) { @@ -2108,10 +2108,10 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->AuxiliaryEffectSlotMax, device->NumAuxSends); device->DitherDepth = 0.0f; - if(GetConfigValueBool(alstr_get_cstr(device->DeviceName), nullptr, "dither", 1)) + if(GetConfigValueBool(device->DeviceName, nullptr, "dither", 1)) { ALint depth = 0; - ConfigValueInt(alstr_get_cstr(device->DeviceName), nullptr, "dither-depth", &depth); + ConfigValueInt(device->DeviceName, nullptr, "dither-depth", &depth); if(depth <= 0) { switch(device->FmtType) @@ -2144,7 +2144,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->DitherDepth); device->LimiterState = gainLimiter; - if(ConfigValueBool(alstr_get_cstr(device->DeviceName), nullptr, "output-limiter", &val)) + if(ConfigValueBool(device->DeviceName, nullptr, "output-limiter", &val)) gainLimiter = val ? ALC_TRUE : ALC_FALSE; /* Valid values for gainLimiter are ALC_DONT_CARE_SOFT, ALC_TRUE, and @@ -2381,7 +2381,7 @@ static void InitDevice(ALCdevice *device, enum DeviceType type) device->RealOut.Buffer = nullptr; device->RealOut.NumChannels = 0; - AL_STRING_INIT(device->DeviceName); + device->DeviceName = nullptr; for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) { @@ -2486,7 +2486,8 @@ static ALCvoid FreeDevice(ALCdevice *device) device->ChannelDelay[i].Buffer = nullptr; } - AL_STRING_DEINIT(device->DeviceName); + al_free(device->DeviceName); + device->DeviceName = nullptr; al_free(device->Dry.Buffer); device->Dry.Buffer = nullptr; @@ -3068,7 +3069,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para case ALC_ALL_DEVICES_SPECIFIER: if(VerifyDevice(&Device)) { - value = alstr_get_cstr(Device->DeviceName); + value = Device->DeviceName; ALCdevice_DecRef(Device); } else @@ -3081,7 +3082,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para case ALC_CAPTURE_DEVICE_SPECIFIER: if(VerifyDevice(&Device)) { - value = alstr_get_cstr(Device->DeviceName); + value = Device->DeviceName; ALCdevice_DecRef(Device); } else @@ -3448,7 +3449,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC case ALC_NUM_HRTF_SPECIFIERS_SOFT: almtx_lock(&device->BackendLock); FreeHrtfList(&device->HrtfList); - device->HrtfList = EnumerateHrtf(alstr_get_cstr(device->DeviceName)); + device->HrtfList = EnumerateHrtf(device->DeviceName); values[0] = (ALCint)VECTOR_SIZE(device->HrtfList); almtx_unlock(&device->BackendLock); return 1; @@ -3810,7 +3811,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ALCdevice_IncRef(ALContext->Device); InitContext(ALContext); - if(ConfigValueFloat(alstr_get_cstr(device->DeviceName), nullptr, "volume-adjust", &valf)) + if(ConfigValueFloat(device->DeviceName, nullptr, "volume-adjust", &valf)) { if(!isfinite(valf)) ERR("volume-adjust must be finite: %f\n", valf); @@ -4131,7 +4132,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) return nullptr; } - if(ConfigValueStr(alstr_get_cstr(device->DeviceName), nullptr, "ambi-format", &fmt)) + if(ConfigValueStr(device->DeviceName, nullptr, "ambi-format", &fmt)) { if(strcasecmp(fmt, "fuma") == 0) { @@ -4159,7 +4160,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) } while(!DeviceList.compare_exchange_weak(head, device)); } - TRACE("Created device %p, \"%s\"\n", device, alstr_get_cstr(device->DeviceName)); + TRACE("Created device %p, \"%s\"\n", device, device->DeviceName); return device; } @@ -4295,7 +4296,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, } while(!DeviceList.compare_exchange_weak(head, device)); } - TRACE("Created device %p, \"%s\"\n", device, alstr_get_cstr(device->DeviceName)); + TRACE("Created device %p, \"%s\"\n", device, device->DeviceName); return device; } diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index 5a389eab..23e33e6b 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -684,7 +684,8 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name) snd_config_update_free_global(); ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - alstr_copy_cstr(&device->DeviceName, name); + al_free(device->DeviceName); + device->DeviceName = alstrdup(name); return ALC_NO_ERROR; } @@ -719,7 +720,7 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) break; } - bool allowmmap{!!GetConfigValueBool(alstr_get_cstr(device->DeviceName), "alsa", "mmap", 1)}; + bool allowmmap{!!GetConfigValueBool(device->DeviceName, "alsa", "mmap", 1)}; ALuint periods{device->NumUpdates}; ALuint periodLen{static_cast(device->UpdateSize * U64(1000000) / device->Frequency)}; ALuint bufferLen{periodLen * periods}; @@ -790,7 +791,7 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) } CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder))); /* set rate (implicitly constrains period/buffer parameters) */ - if(!GetConfigValueBool(alstr_get_cstr(device->DeviceName), "alsa", "allow-resampler", 0) || + if(!GetConfigValueBool(device->DeviceName, "alsa", "allow-resampler", 0) || !(device->Flags&DEVICE_FREQUENCY_REQUEST)) { if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0) @@ -1082,7 +1083,8 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) } } - alstr_copy_cstr(&device->DeviceName, name); + al_free(device->DeviceName); + device->DeviceName = alstrdup(name); return ALC_NO_ERROR; diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index 83ea4d5f..1a3f2ab1 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -143,7 +143,8 @@ static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCch return ALC_INVALID_VALUE; } - alstr_copy_cstr(&device->DeviceName, name); + al_free(device->DeviceName); + device->DeviceName = alstrdup(name); return ALC_NO_ERROR; } @@ -673,7 +674,8 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar ); if(!self->ring) goto error; - alstr_copy_cstr(&device->DeviceName, name); + al_free(device->DeviceName); + device->DeviceName = alstrdup(name); return ALC_NO_ERROR; diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 50e956ea..478bdf9a 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -396,7 +396,8 @@ static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *de return ALC_INVALID_VALUE; } - alstr_copy_cstr(&device->DeviceName, deviceName); + al_free(device->DeviceName); + device->DeviceName = alstrdup(deviceName); return ALC_NO_ERROR; } @@ -862,7 +863,8 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi self->BufferBytes = DSCBDescription.dwBufferBytes; SetDefaultWFXChannelOrder(device); - alstr_copy_cstr(&device->DeviceName, deviceName); + al_free(device->DeviceName); + device->DeviceName = alstrdup(deviceName); return ALC_NO_ERROR; } diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index 4aa6cd78..9db75537 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -224,7 +224,7 @@ static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg) device->NumUpdates = 2; bufsize = device->UpdateSize; - if(ConfigValueUInt(alstr_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize)) + if(ConfigValueUInt(device->DeviceName, "jack", "buffer-size", &bufsize)) bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize; @@ -368,7 +368,8 @@ static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name) jack_set_process_callback(self->Client, ALCjackPlayback_process, self); jack_set_buffer_size_callback(self->Client, ALCjackPlayback_bufferSizeNotify, self); - alstr_copy_cstr(&device->DeviceName, name); + al_free(device->DeviceName); + device->DeviceName = alstrdup(name); return ALC_NO_ERROR; } @@ -394,7 +395,7 @@ static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) device->NumUpdates = 2; bufsize = device->UpdateSize; - if(ConfigValueUInt(alstr_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize)) + if(ConfigValueUInt(device->DeviceName, "jack", "buffer-size", &bufsize)) bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize; diff --git a/Alc/backends/loopback.cpp b/Alc/backends/loopback.cpp index 3726463c..2eb4c935 100644 --- a/Alc/backends/loopback.cpp +++ b/Alc/backends/loopback.cpp @@ -62,7 +62,8 @@ static ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - alstr_copy_cstr(&device->DeviceName, name); + al_free(device->DeviceName); + device->DeviceName = alstrdup(name); return ALC_NO_ERROR; } diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index c8523c88..30d80b76 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -141,7 +141,8 @@ static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name) return ALC_INVALID_VALUE; device = STATIC_CAST(ALCbackend, self)->mDevice; - alstr_copy_cstr(&device->DeviceName, name); + al_free(device->DeviceName); + device->DeviceName = alstrdup(name); return ALC_NO_ERROR; } diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 9d938ba4..689c02af 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -375,7 +375,8 @@ static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *na return ALC_INVALID_VALUE; } - alstr_copy_cstr(&device->DeviceName, name); + al_free(device->DeviceName); + device->DeviceName = alstrdup(name); return ALC_NO_ERROR; } @@ -900,7 +901,8 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name return ALC_INVALID_VALUE; } - alstr_copy_cstr(&device->DeviceName, name); + al_free(device->DeviceName); + device->DeviceName = alstrdup(name); return ALC_NO_ERROR; } diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 618730b3..4f320b69 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -391,7 +391,8 @@ static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) return ALC_INVALID_VALUE; } - alstr_copy_cstr(&device->DeviceName, name); + al_free(device->DeviceName); + device->DeviceName = alstrdup(name); return ALC_NO_ERROR; } @@ -722,7 +723,8 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) return ALC_OUT_OF_MEMORY; } - alstr_copy_cstr(&device->DeviceName, name); + al_free(device->DeviceName); + device->DeviceName = alstrdup(name); return ALC_NO_ERROR; } diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index 03194c05..7b21669a 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -249,7 +249,8 @@ retry_open: return ALC_INVALID_VALUE; } - alstr_copy_cstr(&device->DeviceName, name); + al_free(device->DeviceName); + device->DeviceName = alstrdup(name); return ALC_NO_ERROR; @@ -440,7 +441,8 @@ static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) return ALC_INVALID_VALUE; } - alstr_copy_cstr(&device->DeviceName, name); + al_free(device->DeviceName); + device->DeviceName = alstrdup(name); return ALC_NO_ERROR; } diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 77719e3c..4569b91a 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -800,7 +800,8 @@ static void PulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const pa } ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; - alstr_copy_cstr(&device->DeviceName, info->description); + al_free(device->DeviceName); + device->DeviceName = alstrdup(info->description); } @@ -980,7 +981,8 @@ static ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) else { ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; - alstr_copy_cstr(&device->DeviceName, dev_name); + al_free(device->DeviceName); + device->DeviceName = alstrdup(dev_name); } return ALC_NO_ERROR; @@ -1011,7 +1013,7 @@ static ALCboolean PulsePlayback_reset(PulsePlayback *self) PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE}; if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 0)) flags |= PA_STREAM_DONT_MOVE; - if(GetConfigValueBool(alstr_get_cstr(device->DeviceName), "pulse", "fix-rate", 0) || + if(GetConfigValueBool(device->DeviceName, "pulse", "fix-rate", 0) || !(device->Flags&DEVICE_FREQUENCY_REQUEST)) flags |= PA_STREAM_FIX_RATE; @@ -1418,7 +1420,8 @@ static void PulseCapture_sourceNameCallback(pa_context *UNUSED(context), const p } ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; - alstr_copy_cstr(&device->DeviceName, info->description); + al_free(device->DeviceName); + device->DeviceName = alstrdup(info->description); } @@ -1490,7 +1493,8 @@ static ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) if(iter == CaptureDevices.cend()) return ALC_INVALID_VALUE; pulse_name = iter->device_name.c_str(); - alstr_copy_cstr(&device->DeviceName, iter->name.c_str()); + al_free(device->DeviceName); + device->DeviceName = alstrdup(iter->name.c_str()); } std::tie(self->loop, self->context) = pulse_open(PulseCapture_contextStateCallback, self); @@ -1593,7 +1597,7 @@ static ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) pa_stream_set_state_callback(self->stream, PulseCapture_streamStateCallback, self); self->device_name = pa_stream_get_device_name(self->stream); - if(alstr_empty(device->DeviceName)) + if(!device->DeviceName || device->DeviceName[0] == 0) { pa_operation *op{pa_context_get_source_info_by_name(self->context, self->device_name.c_str(), PulseCapture_sourceNameCallback, self diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index 7afd3214..3a99d71e 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -328,7 +328,8 @@ static ALCenum qsa_open_playback(PlaybackWrapper *self, const ALCchar* deviceNam return ALC_INVALID_DEVICE; } - alstr_copy_cstr(&device->DeviceName, deviceName); + al_free(device->DeviceName); + device->DeviceName = alstrdup(deviceName); self->ExtraData = data; return ALC_NO_ERROR; @@ -735,7 +736,8 @@ static ALCenum qsa_open_capture(CaptureWrapper *self, const ALCchar *deviceName) return ALC_INVALID_DEVICE; } - alstr_copy_cstr(&device->DeviceName, deviceName); + al_free(device->DeviceName); + device->DeviceName = alstrdup(deviceName); self->ExtraData = data; switch (device->FmtType) diff --git a/Alc/backends/sdl2.cpp b/Alc/backends/sdl2.cpp index 82c350e1..c918b57c 100644 --- a/Alc/backends/sdl2.cpp +++ b/Alc/backends/sdl2.cpp @@ -174,7 +174,8 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) self->FmtType = device->FmtType; self->UpdateSize = device->UpdateSize; - alstr_copy_cstr(&device->DeviceName, name ? name : defaultDeviceName); + al_free(device->DeviceName); + device->DeviceName = alstrdup(name ? name : defaultDeviceName); return ALC_NO_ERROR; } diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index c97226a6..f1e678cf 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -148,7 +148,8 @@ static ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name) return ALC_INVALID_VALUE; } - alstr_copy_cstr(&device->DeviceName, name); + al_free(device->DeviceName); + device->DeviceName = alstrdup(name); return ALC_NO_ERROR; } @@ -488,7 +489,8 @@ static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) SetDefaultChannelOrder(device); - alstr_copy_cstr(&device->DeviceName, name); + al_free(device->DeviceName); + device->DeviceName = alstrdup(name); return ALC_NO_ERROR; } diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index b63a85e8..20dda617 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -188,7 +188,8 @@ static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *na } device = STATIC_CAST(ALCbackend,self)->mDevice; - alstr_copy_cstr(&device->DeviceName, name); + al_free(device->DeviceName); + device->DeviceName = alstrdup(name); return ALC_NO_ERROR; } diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 64e7d43c..4fb0f317 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -719,7 +719,8 @@ static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *de { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; self->mDevId = iter->devid; - alstr_copy_range(&device->DeviceName, &*iter->name.cbegin(), &*iter->name.cend()); + al_free(device->DeviceName); + device->DeviceName = alstrdup(iter->name.c_str()); hr = S_OK; } } @@ -775,11 +776,11 @@ HRESULT ALCwasapiPlayback::openProxy() if(SUCCEEDED(hr)) { mClient = reinterpret_cast(ptr); - if(alstr_empty(device->DeviceName)) + if(!device->DeviceName || device->DeviceName[0] == 0) { - std::string devname; - std::tie(devname, std::ignore) = get_device_name_and_guid(mMMDev); - alstr_copy_range(&device->DeviceName, &*devname.cbegin(), &*devname.cend()); + std::string devname{get_device_name_and_guid(mMMDev).first}; + al_free(device->DeviceName); + device->DeviceName = alstrdup(devname.c_str()); } } @@ -1385,7 +1386,8 @@ static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *devi { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; self->mDevId = iter->devid; - alstr_copy_range(&device->DeviceName, &*iter->name.cbegin(), &*iter->name.cend()); + al_free(device->DeviceName); + device->DeviceName = alstrdup(iter->name.c_str()); hr = S_OK; } } @@ -1460,11 +1462,11 @@ HRESULT ALCwasapiCapture::openProxy() if(SUCCEEDED(hr)) { mClient = reinterpret_cast(ptr); - if(alstr_empty(device->DeviceName)) + if(!device->DeviceName || device->DeviceName[0] == 0) { - std::string devname; - std::tie(devname, std::ignore) = get_device_name_and_guid(mMMDev); - alstr_copy_range(&device->DeviceName, &*devname.cbegin(), &*devname.cend()); + std::string devname{get_device_name_and_guid(mMMDev).first}; + al_free(device->DeviceName); + device->DeviceName = alstrdup(devname.c_str()); } } diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index 48b3e911..ea4af146 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -242,7 +242,8 @@ static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name) } ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; - alstr_copy_cstr(&device->DeviceName, name); + al_free(device->DeviceName); + device->DeviceName = alstrdup(name); return ALC_NO_ERROR; } diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 6e43ff79..0c625e27 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -286,7 +286,8 @@ retry_open: return ALC_INVALID_VALUE; } - alstr_copy_cstr(&device->DeviceName, PlaybackDevices[DeviceID].c_str()); + al_free(device->DeviceName); + device->DeviceName = alstrdup(PlaybackDevices[DeviceID].c_str()); return ALC_NO_ERROR; } @@ -606,7 +607,8 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *device self->WaveBuffer[i].dwBufferLength = self->WaveBuffer[i-1].dwBufferLength; } - alstr_copy_cstr(&device->DeviceName, CaptureDevices[DeviceID].c_str()); + al_free(device->DeviceName); + device->DeviceName = alstrdup(CaptureDevices[DeviceID].c_str()); return ALC_NO_ERROR; } diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index 468df505..89f60380 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -729,6 +729,15 @@ void SetRTPriority(void) #endif +char *alstrdup(const char *str) +{ + const size_t len{strlen(str)}; + char *ret{static_cast(al_calloc(DEF_ALIGN, len+1))}; + memcpy(ret, str, len); + return ret; +} + + void alstr_clear(al_string *str) { if(!alstr_empty(*str)) diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 4bc1305d..783686d5 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -82,14 +82,6 @@ std::mutex LoadedHrtfLock; HrtfEntry *LoadedHrtfs{nullptr}; -char *alstrdup(const std::string &str) -{ - const size_t len{str.length()}; - char *ret{static_cast(al_calloc(DEF_ALIGN, len+1))}; - memcpy(ret, str.data(), len); - return ret; -} - class databuf final : public std::streambuf { int_type underflow() override { return traits_type::eof(); } @@ -1016,7 +1008,7 @@ void AddFileEntry(vector_EnumeratedHrtf *list, const std::string &filename) VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_NAME); #undef MATCH_NAME } while(iter != VECTOR_END(*list)); - EnumeratedHrtf entry{ alstrdup(newname), loaded_entry }; + EnumeratedHrtf entry{ alstrdup(newname.c_str()), loaded_entry }; TRACE("Adding file entry \"%s\"\n", entry.name); VECTOR_PUSH_BACK(*list, entry); @@ -1082,7 +1074,7 @@ void AddBuiltInEntry(vector_EnumeratedHrtf *list, const std::string &filename, A VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_NAME); #undef MATCH_NAME } while(iter != VECTOR_END(*list)); - EnumeratedHrtf entry{ alstrdup(newname), loaded_entry }; + EnumeratedHrtf entry{ alstrdup(newname.c_str()), loaded_entry }; TRACE("Adding built-in entry \"%s\"\n", entry.name); VECTOR_PUSH_BACK(*list, entry); diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 6507cec5..9bde25a0 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -63,14 +63,6 @@ constexpr ALsizei ACN2ACN[MAX_AMBI_COEFFS] = { 8, 9, 10, 11, 12, 13, 14, 15 }; -char *alstrdup(const char *str) -{ - const size_t len{strlen(str)}; - char *ret{static_cast(al_calloc(DEF_ALIGN, len+1))}; - memcpy(ret, str, len); - return ret; -} - } // namespace void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread, @@ -388,7 +380,7 @@ static const ChannelMap MonoCfg[1] = { static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, const ALsizei *RESTRICT chans_per_order) { - const char *devname = alstr_get_cstr(device->DeviceName); + const char *devname = device->DeviceName; ALsizei i; if(GetConfigValueBool(devname, "decoder", "nfc", 1) && ctrl_dist > 0.0f) @@ -408,7 +400,7 @@ static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei orde static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) { - const char *devname = alstr_get_cstr(device->DeviceName); + const char *devname = device->DeviceName; ALfloat maxdist = 0.0f; size_t total = 0; ALsizei i; @@ -521,7 +513,7 @@ static void InitPanning(ALCdevice *device) if(device->FmtChans == DevFmtAmbi3D) { - const char *devname = alstr_get_cstr(device->DeviceName); + const char *devname = device->DeviceName; const ALsizei *acnmap = (device->AmbiLayout == AmbiLayout_FuMa) ? FuMa2ACN : ACN2ACN; const ALfloat *n3dscale = (device->AmbiScale == AmbiNorm_FuMa) ? FuMa2N3DScale : (device->AmbiScale == AmbiNorm_SN3D) ? SN3D2N3DScale : @@ -975,7 +967,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(hrtf_appreq == Hrtf_Enable) device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; - devname = alstr_get_cstr(device->DeviceName); + devname = device->DeviceName; switch(device->FmtChans) { case DevFmtQuad: layout = "quad"; break; @@ -1081,7 +1073,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(device->Type != Loopback) { const char *mode; - if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "stereo-mode", &mode)) + if(ConfigValueStr(device->DeviceName, NULL, "stereo-mode", &mode)) { if(strcasecmp(mode, "headphones") == 0) headphones = true; @@ -1116,7 +1108,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(VECTOR_SIZE(device->HrtfList) == 0) { VECTOR_DEINIT(device->HrtfList); - device->HrtfList = EnumerateHrtf(alstr_get_cstr(device->DeviceName)); + device->HrtfList = EnumerateHrtf(device->DeviceName); } if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->HrtfList)) @@ -1152,7 +1144,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf old_hrtf = NULL; device->Render_Mode = HrtfRender; - if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "hrtf-mode", &mode)) + if(ConfigValueStr(device->DeviceName, NULL, "hrtf-mode", &mode)) { if(strcasecmp(mode, "full") == 0) device->Render_Mode = HrtfRender; @@ -1196,7 +1188,7 @@ no_hrtf: bs2blevel = ((headphones && hrtf_appreq != Hrtf_Disable) || (hrtf_appreq == Hrtf_Enable)) ? 5 : 0; if(device->Type != Loopback) - ConfigValueInt(alstr_get_cstr(device->DeviceName), NULL, "cf_level", &bs2blevel); + ConfigValueInt(device->DeviceName, NULL, "cf_level", &bs2blevel); if(bs2blevel > 0 && bs2blevel <= 6) { device->Bs2b = reinterpret_cast(al_calloc(16, sizeof(*device->Bs2b))); @@ -1208,7 +1200,7 @@ no_hrtf: TRACE("BS2B disabled\n"); - if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "stereo-encoding", &mode)) + if(ConfigValueStr(device->DeviceName, NULL, "stereo-encoding", &mode)) { if(strcasecmp(mode, "uhj") == 0) device->Render_Mode = NormalRender; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index b9ace4db..ee20d5be 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -634,7 +634,7 @@ struct ALCdevice_struct { ALCenum LimiterState; - al_string DeviceName; + char *DeviceName; ATOMIC(ALCenum) LastError; @@ -920,6 +920,8 @@ inline void UnlockEffectSlotList(ALCcontext *context) int EventThread(void *arg); +char *alstrdup(const char *str); + #ifdef __cplusplus } // extern "C" -- cgit v1.2.3 From 245b7ff0b41ebd43f3c1c53dd90ab0bf358e4c06 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 06:32:01 -0800 Subject: Remove the unused al_string API --- Alc/alc.cpp | 1 - Alc/alstring.h | 49 ----------------------- Alc/backends/wasapi.cpp | 1 - Alc/helpers.cpp | 99 ----------------------------------------------- Alc/inldefs.c | 7 ---- CMakeLists.txt | 1 - OpenAL32/Include/alMain.h | 1 - 7 files changed, 159 deletions(-) delete mode 100644 Alc/alstring.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 159e3bc8..6c4e970e 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -54,7 +54,6 @@ #include "cpu_caps.h" #include "compat.h" #include "threads.h" -#include "alstring.h" #include "almalloc.h" #include "backends/base.h" diff --git a/Alc/alstring.h b/Alc/alstring.h deleted file mode 100644 index f991310f..00000000 --- a/Alc/alstring.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef ALSTRING_H -#define ALSTRING_H - -#include - -#include "vector.h" - - -#ifdef __cplusplus -extern "C" { -#endif - -typedef char al_string_char_type; -TYPEDEF_VECTOR(al_string_char_type, al_string) -TYPEDEF_VECTOR(al_string, vector_al_string) - -inline void alstr_reset(al_string *str) -{ VECTOR_DEINIT(*str); } -#define AL_STRING_INIT(_x) do { (_x) = (al_string)NULL; } while(0) -#define AL_STRING_INIT_STATIC() ((al_string)NULL) -#define AL_STRING_DEINIT(_x) alstr_reset(&(_x)) - -inline size_t alstr_length(const_al_string str) -{ return VECTOR_SIZE(str); } - -inline ALboolean alstr_empty(const_al_string str) -{ return alstr_length(str) == 0; } - -inline const al_string_char_type *alstr_get_cstr(const_al_string str) -{ return str ? &VECTOR_FRONT(str) : ""; } - -void alstr_clear(al_string *str); - -int alstr_cmp(const_al_string str1, const_al_string str2); -int alstr_cmp_cstr(const_al_string str1, const al_string_char_type *str2); - -void alstr_copy(al_string *str, const_al_string from); -void alstr_copy_cstr(al_string *str, const al_string_char_type *from); -void alstr_copy_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to); - -void alstr_append_char(al_string *str, const al_string_char_type c); -void alstr_append_cstr(al_string *str, const al_string_char_type *from); -void alstr_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* ALSTRING_H */ diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 4fb0f317..b842b8ed 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -48,7 +48,6 @@ #include "alu.h" #include "ringbuffer.h" #include "compat.h" -#include "alstring.h" #include "converter.h" #include "backends/base.h" diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index 89f60380..d31101f7 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -120,7 +120,6 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x #include "fpu_modes.h" #include "uintmap.h" #include "vector.h" -#include "alstring.h" #include "compat.h" #include "threads.h" @@ -736,101 +735,3 @@ char *alstrdup(const char *str) memcpy(ret, str, len); return ret; } - - -void alstr_clear(al_string *str) -{ - if(!alstr_empty(*str)) - { - /* 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_RESIZE(*str, 0, 1); - VECTOR_ELEM(*str, 0) = 0; - } -} - -static inline int alstr_compare(const al_string_char_type *str1, size_t str1len, - const al_string_char_type *str2, size_t str2len) -{ - size_t complen = (str1len < str2len) ? str1len : str2len; - int ret = memcmp(str1, str2, complen); - if(ret == 0) - { - if(str1len > str2len) return 1; - if(str1len < str2len) return -1; - } - return ret; -} -int alstr_cmp(const_al_string str1, const_al_string str2) -{ - return alstr_compare(&VECTOR_FRONT(str1), alstr_length(str1), - &VECTOR_FRONT(str2), alstr_length(str2)); -} -int alstr_cmp_cstr(const_al_string str1, const al_string_char_type *str2) -{ - return alstr_compare(&VECTOR_FRONT(str1), alstr_length(str1), - str2, strlen(str2)); -} - -void alstr_copy(al_string *str, const_al_string from) -{ - size_t len = alstr_length(from); - VECTOR_RESIZE(*str, len, len+1); - for(size_t i{0};i < len;i++) - VECTOR_ELEM(*str, i) = VECTOR_ELEM(from, i); - VECTOR_ELEM(*str, len) = 0; -} - -void alstr_copy_cstr(al_string *str, const al_string_char_type *from) -{ - size_t len = strlen(from); - VECTOR_RESIZE(*str, len, len+1); - for(size_t i{0};i < len;i++) - VECTOR_ELEM(*str, i) = from[i]; - VECTOR_ELEM(*str, len) = 0; -} - -void alstr_copy_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to) -{ - size_t len = to - from; - VECTOR_RESIZE(*str, len, len+1); - for(size_t i{0};i < len;i++) - VECTOR_ELEM(*str, i) = from[i]; - VECTOR_ELEM(*str, len) = 0; -} - -void alstr_append_char(al_string *str, const al_string_char_type c) -{ - size_t len = alstr_length(*str); - VECTOR_RESIZE(*str, len+1, len+2); - VECTOR_BACK(*str) = c; - VECTOR_ELEM(*str, len+1) = 0; -} - -void alstr_append_cstr(al_string *str, const al_string_char_type *from) -{ - size_t len = strlen(from); - if(len != 0) - { - size_t base = alstr_length(*str); - VECTOR_RESIZE(*str, base+len, base+len+1); - for(size_t i{0};i < len;i++) - VECTOR_ELEM(*str, base+i) = from[i]; - VECTOR_ELEM(*str, base+len) = 0; - } -} - -void alstr_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to) -{ - size_t len = to - from; - if(len != 0) - { - size_t base = alstr_length(*str); - VECTOR_RESIZE(*str, base+len, base+len+1); - for(size_t i{0};i < len;i++) - VECTOR_ELEM(*str, base+i) = from[i]; - VECTOR_ELEM(*str, base+len) = 0; - } -} diff --git a/Alc/inldefs.c b/Alc/inldefs.c index 451c3bcc..dd1cff4a 100644 --- a/Alc/inldefs.c +++ b/Alc/inldefs.c @@ -7,7 +7,6 @@ #include "mixer/defs.h" #include "alBuffer.h" #include "alEffect.h" -#include "alstring.h" #include "backends/base.h" @@ -31,12 +30,6 @@ extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum User extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); -extern inline void alstr_reset(al_string *str); -extern inline size_t alstr_length(const_al_string str); -extern inline ALboolean alstr_empty(const_al_string str); -extern inline const al_string_char_type *alstr_get_cstr(const_al_string str); - - extern inline ALuint NextPowerOf2(ALuint value); extern inline size_t RoundUp(size_t value, size_t r); extern inline ALint fastf2i(ALfloat f); diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d3f6bfd..38858fa3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -868,7 +868,6 @@ SET(ALC_OBJS Alc/filters/splitter.cpp Alc/filters/splitter.h Alc/helpers.cpp - Alc/alstring.h Alc/compat.h Alc/cpu_caps.h Alc/fpu_modes.h diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index ee20d5be..53831ccf 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -27,7 +27,6 @@ #include "align.h" #include "atomic.h" #include "vector.h" -#include "alstring.h" #include "almalloc.h" #include "threads.h" -- cgit v1.2.3 From a3b644374b01437d69368ce6c144ab72948ef9f9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 06:48:00 -0800 Subject: Add a missing cast for MSVC --- OpenAL32/alSource.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 158290ef..93b0cd88 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -3229,7 +3229,8 @@ static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_send } /* Set the new container for updating internal parameters. */ - props = ATOMIC_EXCHANGE_PTR(&voice->Update, props, almemory_order_acq_rel); + props = static_cast(ATOMIC_EXCHANGE_PTR(&voice->Update, props, + almemory_order_acq_rel)); if(props) { /* If there was an unused update container, put it back in the -- cgit v1.2.3 From dc622b3182694793d0189acf402bda6bafdf589a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 06:48:52 -0800 Subject: Use std::isfinite from the cmath header --- Alc/alc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 6c4e970e..9fee3251 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -3812,7 +3812,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin if(ConfigValueFloat(device->DeviceName, nullptr, "volume-adjust", &valf)) { - if(!isfinite(valf)) + if(!std::isfinite(valf)) ERR("volume-adjust must be finite: %f\n", valf); else { -- cgit v1.2.3 From 7c933087718bd1b789f2638164bcf2f8698647cb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 17:53:05 -0800 Subject: Remove checks for functions that always exist They're part of C++11 and available on the testing systems. If some system has trouble, switching to proper C++ calls should fix it. --- Alc/backends/oss.cpp | 10 ---------- CMakeLists.txt | 38 -------------------------------------- OpenAL32/Include/alMain.h | 2 +- common/math_defs.h | 22 ---------------------- config.h.in | 12 ------------ 5 files changed, 1 insertion(+), 83 deletions(-) diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 4f320b69..9baa7346 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -114,16 +114,6 @@ void ALCossListPopulate(std::vector *devlist, int type) #else -#ifndef HAVE_STRNLEN -size_t my_strnlen(const char *str, size_t maxlen) -{ - const char *end = static_cast(memchr(str, 0, maxlen)); - if(!end) return maxlen; - return end - str; -} -#define strnlen my_strnlen -#endif - void ALCossListAppend(std::vector *list, const char *handle, size_t hlen, const char *path, size_t plen) { #ifdef ALC_OSS_DEVNODE_TRUC diff --git a/CMakeLists.txt b/CMakeLists.txt index 38858fa3..aa85e34b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -603,9 +603,6 @@ CHECK_SYMBOL_EXISTS(aligned_alloc stdlib.h HAVE_ALIGNED_ALLOC) CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN) CHECK_SYMBOL_EXISTS(_aligned_malloc malloc.h HAVE__ALIGNED_MALLOC) CHECK_SYMBOL_EXISTS(proc_pidpath libproc.h HAVE_PROC_PIDPATH) -CHECK_SYMBOL_EXISTS(lrintf math.h HAVE_LRINTF) -CHECK_SYMBOL_EXISTS(cbrtf math.h HAVE_CBRTF) -CHECK_SYMBOL_EXISTS(copysignf math.h HAVE_COPYSIGNF) IF(HAVE_FLOAT_H) CHECK_SYMBOL_EXISTS(_controlfp float.h HAVE__CONTROLFP) @@ -633,41 +630,6 @@ IF(NOT HAVE_STRNCASECMP) SET(CPP_DEFS ${CPP_DEFS} strncasecmp=_strnicmp) ENDIF() -CHECK_SYMBOL_EXISTS(strnlen string.h HAVE_STRNLEN) -CHECK_SYMBOL_EXISTS(snprintf stdio.h HAVE_SNPRINTF) -IF(NOT HAVE_SNPRINTF) - CHECK_FUNCTION_EXISTS(_snprintf HAVE__SNPRINTF) - IF(NOT HAVE__SNPRINTF) - MESSAGE(FATAL_ERROR "No snprintf function found, please report!") - ENDIF() - - SET(CPP_DEFS ${CPP_DEFS} snprintf=_snprintf) -ENDIF() - -CHECK_SYMBOL_EXISTS(isfinite math.h HAVE_ISFINITE) -IF(NOT HAVE_ISFINITE) - CHECK_FUNCTION_EXISTS(finite HAVE_FINITE) - IF(NOT HAVE_FINITE) - CHECK_FUNCTION_EXISTS(_finite HAVE__FINITE) - IF(NOT HAVE__FINITE) - MESSAGE(FATAL_ERROR "No isfinite function found, please report!") - ENDIF() - SET(CPP_DEFS ${CPP_DEFS} isfinite=_finite) - ELSE() - SET(CPP_DEFS ${CPP_DEFS} isfinite=finite) - ENDIF() -ENDIF() - -CHECK_SYMBOL_EXISTS(isnan math.h HAVE_ISNAN) -IF(NOT HAVE_ISNAN) - CHECK_FUNCTION_EXISTS(_isnan HAVE__ISNAN) - IF(NOT HAVE__ISNAN) - MESSAGE(FATAL_ERROR "No isnan function found, please report!") - ENDIF() - - SET(CPP_DEFS ${CPP_DEFS} isnan=_isnan) -ENDIF() - # Check if we have Windows headers SET(OLD_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 53831ccf..a79b6962 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -281,7 +281,7 @@ inline ALint fastf2i(ALfloat f) * libc call, while MSVC's implementation is horribly slow, so always fall * back to a normal integer conversion for them. */ -#elif defined(HAVE_LRINTF) && !defined(_MSC_VER) && !defined(__clang__) +#elif !defined(_MSC_VER) && !defined(__clang__) return lrintf(f); diff --git a/common/math_defs.h b/common/math_defs.h index 3e8dbe76..513570f0 100644 --- a/common/math_defs.h +++ b/common/math_defs.h @@ -32,28 +32,6 @@ static const union msvc_inf_hack { #define HUGE_VALF (msvc_inf_union.f) #endif -#ifndef HAVE_CBRTF -static inline float my_cbrtf(float f) -{ - return powf(f, 1.0f/3.0f); -} -#define cbrtf my_cbrtf -#endif - -#ifndef HAVE_COPYSIGNF -static inline float my_copysignf(float x, float y) -{ - union { - float f; - unsigned int u; - } ux = { x }, uy = { y }; - ux.u &= 0x7fffffffu; - ux.u |= (uy.u&0x80000000u); - return ux.f; -} -#define copysignf my_copysignf -#endif - #define DEG2RAD(x) ((float)(x) * (float)(M_PI/180.0)) #define RAD2DEG(x) ((float)(x) * (float)(180.0/M_PI)) diff --git a/config.h.in b/config.h.in index 7895dc88..5a85faea 100644 --- a/config.h.in +++ b/config.h.in @@ -89,18 +89,6 @@ /* Define if we have the stat function */ #cmakedefine HAVE_STAT -/* Define if we have the lrintf function */ -#cmakedefine HAVE_LRINTF - -/* Define if we have the cbrtf function */ -#cmakedefine HAVE_CBRTF - -/* Define if we have the copysignf function */ -#cmakedefine HAVE_COPYSIGNF - -/* Define if we have the strnlen function */ -#cmakedefine HAVE_STRNLEN - /* Define if we have the __int64 type */ #cmakedefine HAVE___INT64 -- cgit v1.2.3 From 49d8ac2537a03dd8d1a60fa4667dc6090da6bcc5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 19:15:14 -0800 Subject: Start a new backend factory API Using proper class inheritance. Be aware this breaks all backends except null (and loopback). They will be restored individually in due time. --- Alc/alc.cpp | 41 +++++++++-------------- Alc/backends/base.h | 14 +++++++- Alc/backends/null.cpp | 91 ++++++++++++++++++++------------------------------- Alc/backends/null.h | 20 +++++++++++ CMakeLists.txt | 1 + 5 files changed, 86 insertions(+), 81 deletions(-) create mode 100644 Alc/backends/null.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 9fee3251..04300d8a 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -57,6 +57,7 @@ #include "almalloc.h" #include "backends/base.h" +#include "backends/null.h" namespace { @@ -66,10 +67,11 @@ namespace { ************************************************/ struct BackendInfo { const char *name; - ALCbackendFactory* (*getFactory)(void); + BackendFactory& (*getFactory)(void); }; struct BackendInfo BackendList[] = { +#if 0 #ifdef HAVE_JACK { "jack", ALCjackBackendFactory_getFactory }, #endif @@ -117,6 +119,8 @@ struct BackendInfo BackendList[] = { #ifdef HAVE_WAVE { "wave", ALCwaveBackendFactory_getFactory }, #endif +#endif /* 0 */ + { "null", NullBackendFactory::getFactory }, }; ALsizei BackendListSize = COUNTOF(BackendList); #undef EmptyFuncs @@ -1099,23 +1103,22 @@ static void alc_initconfig(void) for(n = i = 0;i < BackendListSize && (!PlaybackBackend.name || !CaptureBackend.name);i++) { - ALCbackendFactory *factory; BackendList[n] = BackendList[i]; - factory = BackendList[n].getFactory(); - if(!V0(factory,init)()) + BackendFactory &factory = BackendList[n].getFactory(); + if(!factory.init()) { WARN("Failed to initialize backend \"%s\"\n", BackendList[n].name); continue; } TRACE("Initialized backend \"%s\"\n", BackendList[n].name); - if(!PlaybackBackend.name && V(factory,querySupport)(ALCbackend_Playback)) + if(!PlaybackBackend.name && factory.querySupport(ALCbackend_Playback)) { PlaybackBackend = BackendList[n]; TRACE("Added \"%s\" for playback\n", PlaybackBackend.name); } - if(!CaptureBackend.name && V(factory,querySupport)(ALCbackend_Capture)) + if(!CaptureBackend.name && factory.querySupport(ALCbackend_Capture)) { CaptureBackend = BackendList[n]; TRACE("Added \"%s\" for capture\n", CaptureBackend.name); @@ -1212,10 +1215,8 @@ static void alc_deinit(void) memset(&CaptureBackend, 0, sizeof(CaptureBackend)); for(i = 0;i < BackendListSize;i++) - { - ALCbackendFactory *factory = BackendList[i].getFactory(); - V0(factory,deinit)(); - } + BackendList[i].getFactory().deinit(); + { ALCbackendFactory *factory = ALCloopbackFactory_getFactory(); V0(factory,deinit)(); @@ -1235,10 +1236,7 @@ static void ProbeDevices(std::string *list, struct BackendInfo *backendinfo, enu std::lock_guard _{ListLock}; list->clear(); if(backendinfo->getFactory) - { - ALCbackendFactory *factory = backendinfo->getFactory(); - V(factory,probe)(type, list); - } + backendinfo->getFactory().probe(type, list); } static void ProbeAllDevicesList(void) { ProbeDevices(&alcAllDevicesList, &PlaybackBackend, ALL_DEVICE_PROBE); } @@ -3971,7 +3969,6 @@ ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *Context) */ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) { - ALCbackendFactory *factory; const ALCchar *fmt; ALCdevice *device; ALCenum err; @@ -4114,8 +4111,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->NumStereoSources = 1; device->NumMonoSources = device->SourcesMax - device->NumStereoSources; - factory = PlaybackBackend.getFactory(); - device->Backend = V(factory,createBackend)(device, ALCbackend_Playback); + device->Backend = PlaybackBackend.getFactory().createBackend(device, ALCbackend_Playback); if(!device->Backend) { FreeDevice(device); @@ -4219,7 +4215,6 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) ************************************************/ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei samples) { - ALCbackendFactory *factory; ALCdevice *device = nullptr; ALCenum err; @@ -4268,8 +4263,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, device->UpdateSize = samples; device->NumUpdates = 1; - factory = CaptureBackend.getFactory(); - device->Backend = V(factory,createBackend)(device, ALCbackend_Capture); + device->Backend = CaptureBackend.getFactory().createBackend(device, ALCbackend_Capture); if(!device->Backend) { FreeDevice(device); @@ -4409,9 +4403,6 @@ ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, */ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName) { - ALCbackendFactory *factory; - ALCdevice *device; - DO_INITCONFIG(); /* Make sure the device name, if specified, is us. */ @@ -4421,7 +4412,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN return nullptr; } - device = static_cast(al_calloc(16, sizeof(ALCdevice))); + ALCdevice *device{static_cast(al_calloc(16, sizeof(ALCdevice)))}; if(!device) { alcSetError(nullptr, ALC_OUT_OF_MEMORY); @@ -4461,7 +4452,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->NumStereoSources = 1; device->NumMonoSources = device->SourcesMax - device->NumStereoSources; - factory = ALCloopbackFactory_getFactory(); + ALCbackendFactory *factory = ALCloopbackFactory_getFactory(); device->Backend = V(factory,createBackend)(device, ALCbackend_Loopback); if(!device->Backend) { diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 360c2ffd..5f7deb62 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -153,10 +153,22 @@ ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void); ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void); ALCbackendFactory *ALCportBackendFactory_getFactory(void); ALCbackendFactory *ALCopenslBackendFactory_getFactory(void); -ALCbackendFactory *ALCnullBackendFactory_getFactory(void); ALCbackendFactory *ALCwaveBackendFactory_getFactory(void); ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void); ALCbackendFactory *ALCloopbackFactory_getFactory(void); + +struct BackendFactory { + virtual bool init() = 0; + virtual void deinit() { } + + virtual bool querySupport(ALCbackend_Type type) = 0; + + virtual void probe(enum DevProbe type, std::string *outnames) = 0; + + virtual ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) = 0; +}; + + #endif /* __cplusplus */ #endif /* AL_BACKENDS_BASE_H */ diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 30d80b76..d376ccdf 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -20,6 +20,8 @@ #include "config.h" +#include "backends/null.h" + #include #ifdef HAVE_WINDOWS_H #include @@ -32,8 +34,6 @@ #include "alu.h" #include "compat.h" -#include "backends/base.h" - namespace { @@ -43,32 +43,31 @@ using std::chrono::nanoseconds; constexpr ALCchar nullDevice[] = "No Output"; -} // namespace struct ALCnullBackend final : public ALCbackend { ATOMIC(int) killNow; std::thread thread; }; -static int ALCnullBackend_mixerProc(ALCnullBackend *self); - -static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device); -static void ALCnullBackend_Destruct(ALCnullBackend *self); -static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name); -static ALCboolean ALCnullBackend_reset(ALCnullBackend *self); -static ALCboolean ALCnullBackend_start(ALCnullBackend *self); -static void ALCnullBackend_stop(ALCnullBackend *self); -static DECLARE_FORWARD2(ALCnullBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCnullBackend, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCnullBackend, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, unlock) +int ALCnullBackend_mixerProc(ALCnullBackend *self); + +void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device); +void ALCnullBackend_Destruct(ALCnullBackend *self); +ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name); +ALCboolean ALCnullBackend_reset(ALCnullBackend *self); +ALCboolean ALCnullBackend_start(ALCnullBackend *self); +void ALCnullBackend_stop(ALCnullBackend *self); +DECLARE_FORWARD2(ALCnullBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +DECLARE_FORWARD(ALCnullBackend, ALCbackend, ALCuint, availableSamples) +DECLARE_FORWARD(ALCnullBackend, ALCbackend, ClockLatency, getClockLatency) +DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, lock) +DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCnullBackend) DEFINE_ALCBACKEND_VTABLE(ALCnullBackend); -static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device) +void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device) { new (self) ALCnullBackend{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); @@ -77,14 +76,14 @@ static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device) ATOMIC_INIT(&self->killNow, AL_TRUE); } -static void ALCnullBackend_Destruct(ALCnullBackend *self) +void ALCnullBackend_Destruct(ALCnullBackend *self) { ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCnullBackend(); } -static int ALCnullBackend_mixerProc(ALCnullBackend *self) +int ALCnullBackend_mixerProc(ALCnullBackend *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; const milliseconds restTime{device->UpdateSize*1000/device->Frequency / 2}; @@ -131,7 +130,7 @@ static int ALCnullBackend_mixerProc(ALCnullBackend *self) } -static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name) +ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name) { ALCdevice *device; @@ -147,13 +146,13 @@ static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name) return ALC_NO_ERROR; } -static ALCboolean ALCnullBackend_reset(ALCnullBackend *self) +ALCboolean ALCnullBackend_reset(ALCnullBackend *self) { SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice); return ALC_TRUE; } -static ALCboolean ALCnullBackend_start(ALCnullBackend *self) +ALCboolean ALCnullBackend_start(ALCnullBackend *self) { try { ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); @@ -168,7 +167,7 @@ static ALCboolean ALCnullBackend_start(ALCnullBackend *self) return ALC_FALSE; } -static void ALCnullBackend_stop(ALCnullBackend *self) +void ALCnullBackend_stop(ALCnullBackend *self) { if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel) || !self->thread.joinable()) @@ -176,46 +175,22 @@ static void ALCnullBackend_stop(ALCnullBackend *self) self->thread.join(); } - -struct ALCnullBackendFactory final : public ALCbackendFactory { - ALCnullBackendFactory() noexcept; -}; - -ALCbackendFactory *ALCnullBackendFactory_getFactory(void); - -static ALCboolean ALCnullBackendFactory_init(ALCnullBackendFactory *self); -static DECLARE_FORWARD(ALCnullBackendFactory, ALCbackendFactory, void, deinit) -static ALCboolean ALCnullBackendFactory_querySupport(ALCnullBackendFactory *self, ALCbackend_Type type); -static void ALCnullBackendFactory_probe(ALCnullBackendFactory *self, enum DevProbe type, std::string *outnames); -static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCnullBackendFactory); - -ALCnullBackendFactory::ALCnullBackendFactory() noexcept - : ALCbackendFactory{GET_VTABLE2(ALCnullBackendFactory, ALCbackendFactory)} -{ -} - - -ALCbackendFactory *ALCnullBackendFactory_getFactory(void) -{ - static ALCnullBackendFactory factory{}; - return STATIC_CAST(ALCbackendFactory, &factory); -} +} // namespace -static ALCboolean ALCnullBackendFactory_init(ALCnullBackendFactory* UNUSED(self)) +bool NullBackendFactory::init() { - return ALC_TRUE; + return true; } -static ALCboolean ALCnullBackendFactory_querySupport(ALCnullBackendFactory* UNUSED(self), ALCbackend_Type type) +bool NullBackendFactory::querySupport(ALCbackend_Type type) { if(type == ALCbackend_Playback) - return ALC_TRUE; - return ALC_FALSE; + return true; + return false; } -static void ALCnullBackendFactory_probe(ALCnullBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) +void NullBackendFactory::probe(enum DevProbe type, std::string *outnames) { switch(type) { @@ -228,7 +203,7 @@ static void ALCnullBackendFactory_probe(ALCnullBackendFactory* UNUSED(self), enu } } -static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +ALCbackend *NullBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) { @@ -240,3 +215,9 @@ static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory* UN return NULL; } + +BackendFactory &NullBackendFactory::getFactory() +{ + static NullBackendFactory factory{}; + return factory; +} diff --git a/Alc/backends/null.h b/Alc/backends/null.h new file mode 100644 index 00000000..e2adfc33 --- /dev/null +++ b/Alc/backends/null.h @@ -0,0 +1,20 @@ +#ifndef BACKENDS_NULL_H +#define BACKENDS_NULL_H + +#include "backends/base.h" + +struct NullBackendFactory final : public BackendFactory { +public: + bool init() override; + /*void deinit() override;*/ + + bool querySupport(ALCbackend_Type type) override; + + void probe(enum DevProbe type, std::string *outnames) override; + + ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_NULL_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index aa85e34b..d3718332 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -992,6 +992,7 @@ SET(ALC_OBJS ${ALC_OBJS} # Default backends, always available Alc/backends/loopback.cpp Alc/backends/null.cpp + Alc/backends/null.h ) # Check ALSA backend -- cgit v1.2.3 From 4311c609e48d954e8fde9b6c3bf8077cfac8efa0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 19:42:13 -0800 Subject: Update the loopback backend --- Alc/alc.cpp | 15 +++------ Alc/backends/base.h | 1 - Alc/backends/loopback.cpp | 79 ++++++++++++++++++++--------------------------- Alc/backends/loopback.h | 20 ++++++++++++ CMakeLists.txt | 1 + 5 files changed, 59 insertions(+), 57 deletions(-) create mode 100644 Alc/backends/loopback.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 04300d8a..0be0e575 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -58,6 +58,7 @@ #include "backends/base.h" #include "backends/null.h" +#include "backends/loopback.h" namespace { @@ -1127,10 +1128,7 @@ static void alc_initconfig(void) } BackendListSize = n; - { - ALCbackendFactory *factory = ALCloopbackFactory_getFactory(); - V0(factory,init)(); - } + LoopbackBackendFactory::getFactory().init(); if(!PlaybackBackend.name) WARN("No playback backend available!\n"); @@ -1217,10 +1215,7 @@ static void alc_deinit(void) for(i = 0;i < BackendListSize;i++) BackendList[i].getFactory().deinit(); - { - ALCbackendFactory *factory = ALCloopbackFactory_getFactory(); - V0(factory,deinit)(); - } + LoopbackBackendFactory::getFactory().deinit(); alc_deinit_safe(); } @@ -4452,8 +4447,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->NumStereoSources = 1; device->NumMonoSources = device->SourcesMax - device->NumStereoSources; - ALCbackendFactory *factory = ALCloopbackFactory_getFactory(); - device->Backend = V(factory,createBackend)(device, ALCbackend_Loopback); + device->Backend = LoopbackBackendFactory::getFactory().createBackend( + device, ALCbackend_Loopback); if(!device->Backend) { al_free(device); diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 5f7deb62..b87abb3f 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -155,7 +155,6 @@ ALCbackendFactory *ALCportBackendFactory_getFactory(void); ALCbackendFactory *ALCopenslBackendFactory_getFactory(void); ALCbackendFactory *ALCwaveBackendFactory_getFactory(void); ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void); -ALCbackendFactory *ALCloopbackFactory_getFactory(void); struct BackendFactory { diff --git a/Alc/backends/loopback.cpp b/Alc/backends/loopback.cpp index 2eb4c935..85c0a26e 100644 --- a/Alc/backends/loopback.cpp +++ b/Alc/backends/loopback.cpp @@ -20,45 +20,47 @@ #include "config.h" +#include "backends/loopback.h" + #include "alMain.h" #include "alu.h" -#include "backends/base.h" +namespace { struct ALCloopback final : public ALCbackend { }; -static void ALCloopback_Construct(ALCloopback *self, ALCdevice *device); -static void ALCloopback_Destruct(ALCloopback *self); -static ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name); -static ALCboolean ALCloopback_reset(ALCloopback *self); -static ALCboolean ALCloopback_start(ALCloopback *self); -static void ALCloopback_stop(ALCloopback *self); -static DECLARE_FORWARD2(ALCloopback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCloopback, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCloopback, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCloopback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCloopback, ALCbackend, void, unlock) +void ALCloopback_Construct(ALCloopback *self, ALCdevice *device); +void ALCloopback_Destruct(ALCloopback *self); +ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name); +ALCboolean ALCloopback_reset(ALCloopback *self); +ALCboolean ALCloopback_start(ALCloopback *self); +void ALCloopback_stop(ALCloopback *self); +DECLARE_FORWARD2(ALCloopback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +DECLARE_FORWARD(ALCloopback, ALCbackend, ALCuint, availableSamples) +DECLARE_FORWARD(ALCloopback, ALCbackend, ClockLatency, getClockLatency) +DECLARE_FORWARD(ALCloopback, ALCbackend, void, lock) +DECLARE_FORWARD(ALCloopback, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCloopback) DEFINE_ALCBACKEND_VTABLE(ALCloopback); -static void ALCloopback_Construct(ALCloopback *self, ALCdevice *device) +void ALCloopback_Construct(ALCloopback *self, ALCdevice *device) { new (self) ALCloopback{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCloopback, ALCbackend, self); } -static void ALCloopback_Destruct(ALCloopback *self) +void ALCloopback_Destruct(ALCloopback *self) { ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCloopback(); } -static ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name) +ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -67,70 +69,55 @@ static ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name) return ALC_NO_ERROR; } -static ALCboolean ALCloopback_reset(ALCloopback *self) +ALCboolean ALCloopback_reset(ALCloopback *self) { SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice); return ALC_TRUE; } -static ALCboolean ALCloopback_start(ALCloopback* UNUSED(self)) +ALCboolean ALCloopback_start(ALCloopback* UNUSED(self)) { return ALC_TRUE; } -static void ALCloopback_stop(ALCloopback* UNUSED(self)) +void ALCloopback_stop(ALCloopback* UNUSED(self)) { } - -struct ALCloopbackFactory final : public ALCbackendFactory { - ALCloopbackFactory() noexcept; -}; - -ALCbackendFactory *ALCloopbackFactory_getFactory(void); -static ALCboolean ALCloopbackFactory_init(ALCloopbackFactory *self); -static DECLARE_FORWARD(ALCloopbackFactory, ALCbackendFactory, void, deinit) -static ALCboolean ALCloopbackFactory_querySupport(ALCloopbackFactory *self, ALCbackend_Type type); -static void ALCloopbackFactory_probe(ALCloopbackFactory *self, enum DevProbe type, std::string *outnames); -static ALCbackend* ALCloopbackFactory_createBackend(ALCloopbackFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCloopbackFactory); - -ALCloopbackFactory::ALCloopbackFactory() noexcept - : ALCbackendFactory{GET_VTABLE2(ALCloopbackFactory, ALCbackendFactory)} -{ } +} // namespace -static ALCboolean ALCloopbackFactory_init(ALCloopbackFactory* UNUSED(self)) +bool LoopbackBackendFactory::init() { - return ALC_TRUE; + return true; } -static ALCboolean ALCloopbackFactory_querySupport(ALCloopbackFactory* UNUSED(self), ALCbackend_Type type) +bool LoopbackBackendFactory::querySupport(ALCbackend_Type type) { if(type == ALCbackend_Loopback) - return ALC_TRUE; - return ALC_FALSE; + return true; + return false; } -static void ALCloopbackFactory_probe(ALCloopbackFactory* UNUSED(self), enum DevProbe UNUSED(type), std::string* UNUSED(outnames)) +void LoopbackBackendFactory::probe(enum DevProbe, std::string*) { } -static ALCbackend* ALCloopbackFactory_createBackend(ALCloopbackFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +ALCbackend *LoopbackBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Loopback) { ALCloopback *backend; NEW_OBJ(backend, ALCloopback)(device); - if(!backend) return NULL; + if(!backend) return nullptr; return STATIC_CAST(ALCbackend, backend); } - return NULL; + return nullptr; } -ALCbackendFactory *ALCloopbackFactory_getFactory(void) +BackendFactory &LoopbackBackendFactory::getFactory() { - static ALCloopbackFactory factory{}; - return STATIC_CAST(ALCbackendFactory, &factory); + static LoopbackBackendFactory factory{}; + return factory; } diff --git a/Alc/backends/loopback.h b/Alc/backends/loopback.h new file mode 100644 index 00000000..68f33a5c --- /dev/null +++ b/Alc/backends/loopback.h @@ -0,0 +1,20 @@ +#ifndef BACKENDS_LOOPBACK_H +#define BACKENDS_LOOPBACK_H + +#include "backends/base.h" + +struct LoopbackBackendFactory final : public BackendFactory { +public: + bool init() override; + /*void deinit() override;*/ + + bool querySupport(ALCbackend_Type type) override; + + void probe(enum DevProbe type, std::string *outnames) override; + + ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_LOOPBACK_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index d3718332..06f280f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -991,6 +991,7 @@ SET(ALC_OBJS ${ALC_OBJS} Alc/backends/base.h # Default backends, always available Alc/backends/loopback.cpp + Alc/backends/loopback.h Alc/backends/null.cpp Alc/backends/null.h ) -- cgit v1.2.3 From e716c7b9889941463deff2d03a318d6be0162c9d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 19:55:56 -0800 Subject: Convert the PulseAudio backend factory --- Alc/alc.cpp | 37 ++----- Alc/backends/pulseaudio.cpp | 255 +++++++++++++++++++------------------------- Alc/backends/pulseaudio.h | 20 ++++ CMakeLists.txt | 2 +- 4 files changed, 135 insertions(+), 179 deletions(-) create mode 100644 Alc/backends/pulseaudio.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 0be0e575..4c73df06 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -59,6 +59,9 @@ #include "backends/base.h" #include "backends/null.h" #include "backends/loopback.h" +#ifdef HAVE_PULSEAUDIO +#include "backends/pulseaudio.h" +#endif namespace { @@ -72,55 +75,29 @@ struct BackendInfo { }; struct BackendInfo BackendList[] = { +#ifdef HAVE_PULSEAUDIO + { "pulse", PulseBackendFactory::getFactory }, +#endif #if 0 -#ifdef HAVE_JACK { "jack", ALCjackBackendFactory_getFactory }, -#endif -#ifdef HAVE_PULSEAUDIO { "pulse", ALCpulseBackendFactory_getFactory }, -#endif -#ifdef HAVE_ALSA { "alsa", ALCalsaBackendFactory_getFactory }, -#endif -#ifdef HAVE_COREAUDIO { "core", ALCcoreAudioBackendFactory_getFactory }, -#endif -#ifdef HAVE_SOLARIS { "solaris", ALCsolarisBackendFactory_getFactory }, -#endif -#ifdef HAVE_SNDIO { "sndio", SndioBackendFactory_getFactory }, -#endif -#ifdef HAVE_OSS { "oss", ALCossBackendFactory_getFactory }, -#endif -#ifdef HAVE_QSA { "qsa", ALCqsaBackendFactory_getFactory }, -#endif -#ifdef HAVE_WASAPI { "wasapi", ALCwasapiBackendFactory_getFactory }, -#endif -#ifdef HAVE_DSOUND { "dsound", ALCdsoundBackendFactory_getFactory }, -#endif -#ifdef HAVE_WINMM { "winmm", ALCwinmmBackendFactory_getFactory }, -#endif -#ifdef HAVE_PORTAUDIO { "port", ALCportBackendFactory_getFactory }, -#endif -#ifdef HAVE_OPENSL { "opensl", ALCopenslBackendFactory_getFactory }, -#endif -#ifdef HAVE_SDL2 { "sdl2", ALCsdl2BackendFactory_getFactory }, -#endif { "null", ALCnullBackendFactory_getFactory }, -#ifdef HAVE_WAVE { "wave", ALCwaveBackendFactory_getFactory }, -#endif #endif /* 0 */ + { "null", NullBackendFactory::getFactory }, }; ALsizei BackendListSize = COUNTOF(BackendList); diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 4569b91a..38623783 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -21,6 +21,8 @@ #include "config.h" +#include "backends/pulseaudio.h" + #include #include @@ -35,8 +37,6 @@ #include "alconfig.h" #include "compat.h" -#include "backends/base.h" - #include #if PA_API_VERSION == 12 @@ -522,8 +522,6 @@ bool checkName(const std::vector &list, const std::string &name) std::vector PlaybackDevices; std::vector CaptureDevices; -} // namespace - struct PulsePlayback final : public ALCbackend { std::string device_name; @@ -540,46 +538,46 @@ struct PulsePlayback final : public ALCbackend { std::thread thread; }; -static void PulsePlayback_deviceCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); -static void PulsePlayback_probeDevices(void); - -static void PulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata); -static void PulsePlayback_contextStateCallback(pa_context *context, void *pdata); -static void PulsePlayback_streamStateCallback(pa_stream *stream, void *pdata); -static void PulsePlayback_streamWriteCallback(pa_stream *p, size_t nbytes, void *userdata); -static void PulsePlayback_sinkInfoCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); -static void PulsePlayback_sinkNameCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); -static void PulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata); -static pa_stream *PulsePlayback_connectStream(const char *device_name, pa_threaded_mainloop *loop, - pa_context *context, pa_stream_flags_t flags, - pa_buffer_attr *attr, pa_sample_spec *spec, - pa_channel_map *chanmap); -static int PulsePlayback_mixerProc(PulsePlayback *self); - -static void PulsePlayback_Construct(PulsePlayback *self, ALCdevice *device); -static void PulsePlayback_Destruct(PulsePlayback *self); -static ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name); -static ALCboolean PulsePlayback_reset(PulsePlayback *self); -static ALCboolean PulsePlayback_start(PulsePlayback *self); -static void PulsePlayback_stop(PulsePlayback *self); -static DECLARE_FORWARD2(PulsePlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -static DECLARE_FORWARD(PulsePlayback, ALCbackend, ALCuint, availableSamples) -static ClockLatency PulsePlayback_getClockLatency(PulsePlayback *self); -static void PulsePlayback_lock(PulsePlayback *self); -static void PulsePlayback_unlock(PulsePlayback *self); +void PulsePlayback_deviceCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); +void PulsePlayback_probeDevices(void); + +void PulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata); +void PulsePlayback_contextStateCallback(pa_context *context, void *pdata); +void PulsePlayback_streamStateCallback(pa_stream *stream, void *pdata); +void PulsePlayback_streamWriteCallback(pa_stream *p, size_t nbytes, void *userdata); +void PulsePlayback_sinkInfoCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); +void PulsePlayback_sinkNameCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); +void PulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata); +pa_stream *PulsePlayback_connectStream(const char *device_name, pa_threaded_mainloop *loop, + pa_context *context, pa_stream_flags_t flags, + pa_buffer_attr *attr, pa_sample_spec *spec, + pa_channel_map *chanmap); +int PulsePlayback_mixerProc(PulsePlayback *self); + +void PulsePlayback_Construct(PulsePlayback *self, ALCdevice *device); +void PulsePlayback_Destruct(PulsePlayback *self); +ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name); +ALCboolean PulsePlayback_reset(PulsePlayback *self); +ALCboolean PulsePlayback_start(PulsePlayback *self); +void PulsePlayback_stop(PulsePlayback *self); +DECLARE_FORWARD2(PulsePlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) +DECLARE_FORWARD(PulsePlayback, ALCbackend, ALCuint, availableSamples) +ClockLatency PulsePlayback_getClockLatency(PulsePlayback *self); +void PulsePlayback_lock(PulsePlayback *self); +void PulsePlayback_unlock(PulsePlayback *self); DECLARE_DEFAULT_ALLOCATORS(PulsePlayback) DEFINE_ALCBACKEND_VTABLE(PulsePlayback); -static void PulsePlayback_Construct(PulsePlayback *self, ALCdevice *device) +void PulsePlayback_Construct(PulsePlayback *self, ALCdevice *device) { new (self) PulsePlayback(); ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(PulsePlayback, ALCbackend, self); } -static void PulsePlayback_Destruct(PulsePlayback *self) +void PulsePlayback_Destruct(PulsePlayback *self) { if(self->loop) { @@ -593,7 +591,7 @@ static void PulsePlayback_Destruct(PulsePlayback *self) } -static void PulsePlayback_deviceCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) +void PulsePlayback_deviceCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) { auto loop = reinterpret_cast(pdata); @@ -627,7 +625,7 @@ static void PulsePlayback_deviceCallback(pa_context *UNUSED(context), const pa_s TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str()); } -static void PulsePlayback_probeDevices(void) +void PulsePlayback_probeDevices(void) { PlaybackDevices.clear(); @@ -678,7 +676,7 @@ static void PulsePlayback_probeDevices(void) } -static void PulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata) +void PulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata) { auto self = reinterpret_cast(pdata); @@ -691,7 +689,7 @@ static void PulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata) */ } -static void PulsePlayback_contextStateCallback(pa_context *context, void *pdata) +void PulsePlayback_contextStateCallback(pa_context *context, void *pdata) { auto self = reinterpret_cast(pdata); if(pa_context_get_state(context) == PA_CONTEXT_FAILED) @@ -702,7 +700,7 @@ static void PulsePlayback_contextStateCallback(pa_context *context, void *pdata) pa_threaded_mainloop_signal(self->loop, 0); } -static void PulsePlayback_streamStateCallback(pa_stream *stream, void *pdata) +void PulsePlayback_streamStateCallback(pa_stream *stream, void *pdata) { auto self = reinterpret_cast(pdata); if(pa_stream_get_state(stream) == PA_STREAM_FAILED) @@ -713,13 +711,13 @@ static void PulsePlayback_streamStateCallback(pa_stream *stream, void *pdata) pa_threaded_mainloop_signal(self->loop, 0); } -static void PulsePlayback_streamWriteCallback(pa_stream* UNUSED(p), size_t UNUSED(nbytes), void *pdata) +void PulsePlayback_streamWriteCallback(pa_stream* UNUSED(p), size_t UNUSED(nbytes), void *pdata) { auto self = reinterpret_cast(pdata); pa_threaded_mainloop_signal(self->loop, 0); } -static void PulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) +void PulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) { struct ChannelMap { DevFmtChannels chans; @@ -789,7 +787,7 @@ static void PulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa device->FmtChans == DevFmtStereo); } -static void PulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) +void PulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) { auto self = reinterpret_cast(pdata); @@ -805,7 +803,7 @@ static void PulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const pa } -static void PulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata) +void PulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata) { auto self = reinterpret_cast(pdata); @@ -815,7 +813,7 @@ static void PulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata) } -static pa_stream *PulsePlayback_connectStream(const char *device_name, +pa_stream *PulsePlayback_connectStream(const char *device_name, pa_threaded_mainloop *loop, pa_context *context, pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, pa_channel_map *chanmap) @@ -863,7 +861,7 @@ static pa_stream *PulsePlayback_connectStream(const char *device_name, } -static int PulsePlayback_mixerProc(PulsePlayback *self) +int PulsePlayback_mixerProc(PulsePlayback *self) { ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; @@ -922,7 +920,7 @@ static int PulsePlayback_mixerProc(PulsePlayback *self) } -static ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) +ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) { const char *pulse_name{nullptr}; const char *dev_name{nullptr}; @@ -988,7 +986,7 @@ static ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) return ALC_NO_ERROR; } -static ALCboolean PulsePlayback_reset(PulsePlayback *self) +ALCboolean PulsePlayback_reset(PulsePlayback *self) { unique_palock palock{self->loop}; @@ -1153,7 +1151,7 @@ static ALCboolean PulsePlayback_reset(PulsePlayback *self) return ALC_TRUE; } -static ALCboolean PulsePlayback_start(PulsePlayback *self) +ALCboolean PulsePlayback_start(PulsePlayback *self) { try { self->killNow.store(AL_FALSE, std::memory_order_release); @@ -1169,7 +1167,7 @@ static ALCboolean PulsePlayback_start(PulsePlayback *self) return ALC_FALSE; } -static void PulsePlayback_stop(PulsePlayback *self) +void PulsePlayback_stop(PulsePlayback *self) { self->killNow.store(AL_TRUE, std::memory_order_release); if(!self->stream || !self->thread.joinable()) @@ -1193,7 +1191,7 @@ static void PulsePlayback_stop(PulsePlayback *self) } -static ClockLatency PulsePlayback_getClockLatency(PulsePlayback *self) +ClockLatency PulsePlayback_getClockLatency(PulsePlayback *self) { ClockLatency ret; pa_usec_t latency; @@ -1223,12 +1221,12 @@ static ClockLatency PulsePlayback_getClockLatency(PulsePlayback *self) } -static void PulsePlayback_lock(PulsePlayback *self) +void PulsePlayback_lock(PulsePlayback *self) { pa_threaded_mainloop_lock(self->loop); } -static void PulsePlayback_unlock(PulsePlayback *self) +void PulsePlayback_unlock(PulsePlayback *self) { pa_threaded_mainloop_unlock(self->loop); } @@ -1252,42 +1250,42 @@ struct PulseCapture final : public ALCbackend { pa_context *context{nullptr}; }; -static void PulseCapture_deviceCallback(pa_context *context, const pa_source_info *info, int eol, void *pdata); -static void PulseCapture_probeDevices(void); - -static void PulseCapture_contextStateCallback(pa_context *context, void *pdata); -static void PulseCapture_streamStateCallback(pa_stream *stream, void *pdata); -static void PulseCapture_sourceNameCallback(pa_context *context, const pa_source_info *info, int eol, void *pdata); -static void PulseCapture_streamMovedCallback(pa_stream *stream, void *pdata); -static pa_stream *PulseCapture_connectStream(const char *device_name, - pa_threaded_mainloop *loop, pa_context *context, - pa_stream_flags_t flags, pa_buffer_attr *attr, - pa_sample_spec *spec, pa_channel_map *chanmap); - -static void PulseCapture_Construct(PulseCapture *self, ALCdevice *device); -static void PulseCapture_Destruct(PulseCapture *self); -static ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name); -static DECLARE_FORWARD(PulseCapture, ALCbackend, ALCboolean, reset) -static ALCboolean PulseCapture_start(PulseCapture *self); -static void PulseCapture_stop(PulseCapture *self); -static ALCenum PulseCapture_captureSamples(PulseCapture *self, ALCvoid *buffer, ALCuint samples); -static ALCuint PulseCapture_availableSamples(PulseCapture *self); -static ClockLatency PulseCapture_getClockLatency(PulseCapture *self); -static void PulseCapture_lock(PulseCapture *self); -static void PulseCapture_unlock(PulseCapture *self); +void PulseCapture_deviceCallback(pa_context *context, const pa_source_info *info, int eol, void *pdata); +void PulseCapture_probeDevices(void); + +void PulseCapture_contextStateCallback(pa_context *context, void *pdata); +void PulseCapture_streamStateCallback(pa_stream *stream, void *pdata); +void PulseCapture_sourceNameCallback(pa_context *context, const pa_source_info *info, int eol, void *pdata); +void PulseCapture_streamMovedCallback(pa_stream *stream, void *pdata); +pa_stream *PulseCapture_connectStream(const char *device_name, + pa_threaded_mainloop *loop, pa_context *context, + pa_stream_flags_t flags, pa_buffer_attr *attr, + pa_sample_spec *spec, pa_channel_map *chanmap); + +void PulseCapture_Construct(PulseCapture *self, ALCdevice *device); +void PulseCapture_Destruct(PulseCapture *self); +ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name); +DECLARE_FORWARD(PulseCapture, ALCbackend, ALCboolean, reset) +ALCboolean PulseCapture_start(PulseCapture *self); +void PulseCapture_stop(PulseCapture *self); +ALCenum PulseCapture_captureSamples(PulseCapture *self, ALCvoid *buffer, ALCuint samples); +ALCuint PulseCapture_availableSamples(PulseCapture *self); +ClockLatency PulseCapture_getClockLatency(PulseCapture *self); +void PulseCapture_lock(PulseCapture *self); +void PulseCapture_unlock(PulseCapture *self); DECLARE_DEFAULT_ALLOCATORS(PulseCapture) DEFINE_ALCBACKEND_VTABLE(PulseCapture); -static void PulseCapture_Construct(PulseCapture *self, ALCdevice *device) +void PulseCapture_Construct(PulseCapture *self, ALCdevice *device) { new (self) PulseCapture(); ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(PulseCapture, ALCbackend, self); } -static void PulseCapture_Destruct(PulseCapture *self) +void PulseCapture_Destruct(PulseCapture *self) { if(self->loop) { @@ -1301,7 +1299,7 @@ static void PulseCapture_Destruct(PulseCapture *self) } -static void PulseCapture_deviceCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata) +void PulseCapture_deviceCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata) { auto loop = reinterpret_cast(pdata); @@ -1335,7 +1333,7 @@ static void PulseCapture_deviceCallback(pa_context *UNUSED(context), const pa_so TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str()); } -static void PulseCapture_probeDevices(void) +void PulseCapture_probeDevices(void) { CaptureDevices.clear(); @@ -1386,7 +1384,7 @@ static void PulseCapture_probeDevices(void) } -static void PulseCapture_contextStateCallback(pa_context *context, void *pdata) +void PulseCapture_contextStateCallback(pa_context *context, void *pdata) { auto self = reinterpret_cast(pdata); if(pa_context_get_state(context) == PA_CONTEXT_FAILED) @@ -1397,7 +1395,7 @@ static void PulseCapture_contextStateCallback(pa_context *context, void *pdata) pa_threaded_mainloop_signal(self->loop, 0); } -static void PulseCapture_streamStateCallback(pa_stream *stream, void *pdata) +void PulseCapture_streamStateCallback(pa_stream *stream, void *pdata) { auto self = reinterpret_cast(pdata); if(pa_stream_get_state(stream) == PA_STREAM_FAILED) @@ -1409,7 +1407,7 @@ static void PulseCapture_streamStateCallback(pa_stream *stream, void *pdata) } -static void PulseCapture_sourceNameCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata) +void PulseCapture_sourceNameCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata) { auto self = reinterpret_cast(pdata); @@ -1425,7 +1423,7 @@ static void PulseCapture_sourceNameCallback(pa_context *UNUSED(context), const p } -static void PulseCapture_streamMovedCallback(pa_stream *stream, void *pdata) +void PulseCapture_streamMovedCallback(pa_stream *stream, void *pdata) { auto self = reinterpret_cast(pdata); @@ -1435,7 +1433,7 @@ static void PulseCapture_streamMovedCallback(pa_stream *stream, void *pdata) } -static pa_stream *PulseCapture_connectStream(const char *device_name, +pa_stream *PulseCapture_connectStream(const char *device_name, pa_threaded_mainloop *loop, pa_context *context, pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, pa_channel_map *chanmap) @@ -1476,7 +1474,7 @@ static pa_stream *PulseCapture_connectStream(const char *device_name, } -static ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) +ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) { ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; const char *pulse_name{nullptr}; @@ -1608,7 +1606,7 @@ static ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) return ALC_NO_ERROR; } -static ALCboolean PulseCapture_start(PulseCapture *self) +ALCboolean PulseCapture_start(PulseCapture *self) { palock_guard _{self->loop}; pa_operation *op{pa_stream_cork(self->stream, 0, stream_success_callback, self->loop)}; @@ -1616,14 +1614,14 @@ static ALCboolean PulseCapture_start(PulseCapture *self) return ALC_TRUE; } -static void PulseCapture_stop(PulseCapture *self) +void PulseCapture_stop(PulseCapture *self) { palock_guard _{self->loop}; pa_operation *op{pa_stream_cork(self->stream, 1, stream_success_callback, self->loop)}; wait_for_operation(op, self->loop); } -static ALCenum PulseCapture_captureSamples(PulseCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum PulseCapture_captureSamples(PulseCapture *self, ALCvoid *buffer, ALCuint samples) { ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; ALCuint todo{samples * static_cast(pa_frame_size(&self->spec))}; @@ -1677,7 +1675,7 @@ static ALCenum PulseCapture_captureSamples(PulseCapture *self, ALCvoid *buffer, return ALC_NO_ERROR; } -static ALCuint PulseCapture_availableSamples(PulseCapture *self) +ALCuint PulseCapture_availableSamples(PulseCapture *self) { ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; size_t readable{self->cap_remain}; @@ -1701,7 +1699,7 @@ static ALCuint PulseCapture_availableSamples(PulseCapture *self) } -static ClockLatency PulseCapture_getClockLatency(PulseCapture *self) +ClockLatency PulseCapture_getClockLatency(PulseCapture *self) { ClockLatency ret; pa_usec_t latency; @@ -1726,38 +1724,22 @@ static ClockLatency PulseCapture_getClockLatency(PulseCapture *self) } -static void PulseCapture_lock(PulseCapture *self) +void PulseCapture_lock(PulseCapture *self) { pa_threaded_mainloop_lock(self->loop); } -static void PulseCapture_unlock(PulseCapture *self) +void PulseCapture_unlock(PulseCapture *self) { pa_threaded_mainloop_unlock(self->loop); } - -struct PulseBackendFactory final : public ALCbackendFactory { - PulseBackendFactory() noexcept; -}; -#define ALCPULSEBACKENDFACTORY_INITIALIZER GET_VTABLE2(PulseBackendFactory, ALCbackendFactory) - -static ALCboolean PulseBackendFactory_init(PulseBackendFactory *self); -static void PulseBackendFactory_deinit(PulseBackendFactory *self); -static ALCboolean PulseBackendFactory_querySupport(PulseBackendFactory *self, ALCbackend_Type type); -static void PulseBackendFactory_probe(PulseBackendFactory *self, enum DevProbe type, std::string *outnames); -static ALCbackend* PulseBackendFactory_createBackend(PulseBackendFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(PulseBackendFactory); - -PulseBackendFactory::PulseBackendFactory() noexcept - : ALCbackendFactory{ALCPULSEBACKENDFACTORY_INITIALIZER} -{ -} +} // namespace -static ALCboolean PulseBackendFactory_init(PulseBackendFactory* UNUSED(self)) +bool PulseBackendFactory::init() { - ALCboolean ret{ALC_FALSE}; + bool ret{false}; if(pulse_load()) { @@ -1772,7 +1754,7 @@ static ALCboolean PulseBackendFactory_init(PulseBackendFactory* UNUSED(self)) pa_context *context{connect_context(loop, AL_TRUE)}; if(context) { - ret = ALC_TRUE; + ret = true; /* Some libraries (Phonon, Qt) set some pulseaudio properties * through environment variables, which causes all streams in @@ -1795,7 +1777,7 @@ static ALCboolean PulseBackendFactory_init(PulseBackendFactory* UNUSED(self)) return ret; } -static void PulseBackendFactory_deinit(PulseBackendFactory* UNUSED(self)) +void PulseBackendFactory::deinit() { PlaybackDevices.clear(); CaptureDevices.clear(); @@ -1807,14 +1789,14 @@ static void PulseBackendFactory_deinit(PulseBackendFactory* UNUSED(self)) /* PulseAudio doesn't like being CloseLib'd sometimes */ } -static ALCboolean PulseBackendFactory_querySupport(PulseBackendFactory* UNUSED(self), ALCbackend_Type type) +bool PulseBackendFactory::querySupport(ALCbackend_Type type) { if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; + return true; + return false; } -static void PulseBackendFactory_probe(PulseBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) +void PulseBackendFactory::probe(enum DevProbe type, std::string *outnames) { auto add_device = [outnames](const DevMap &entry) -> void { @@ -1837,7 +1819,7 @@ static void PulseBackendFactory_probe(PulseBackendFactory* UNUSED(self), enum De } } -static ALCbackend* PulseBackendFactory_createBackend(PulseBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +ALCbackend *PulseBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) { @@ -1862,44 +1844,21 @@ static ALCbackend* PulseBackendFactory_createBackend(PulseBackendFactory* UNUSED #warning "Unsupported API version, backend will be unavailable!" -struct PulseBackendFactory final : public ALCbackendFactory { - PulseBackendFactory() noexcept; -}; -#define ALCPULSEBACKENDFACTORY_INITIALIZER GET_VTABLE2(PulseBackendFactory, ALCbackendFactory) - -static ALCboolean PulseBackendFactory_init(PulseBackendFactory* UNUSED(self)) -{ - return ALC_FALSE; -} +bool PulseBackendFactory::init() { return false; } -static void PulseBackendFactory_deinit(PulseBackendFactory* UNUSED(self)) -{ -} +void PulseBackendFactory::deinit() { } -static ALCboolean PulseBackendFactory_querySupport(PulseBackendFactory* UNUSED(self), ALCbackend_Type UNUSED(type)) -{ - return ALC_FALSE; -} - -static void PulseBackendFactory_probe(PulseBackendFactory* UNUSED(self), enum DevProbe UNUSED(type), std::string* UNUSED(outnames)) -{ -} - -static ALCbackend* PulseBackendFactory_createBackend(PulseBackendFactory* UNUSED(self), ALCdevice* UNUSED(device), ALCbackend_Type UNUSED(type)) -{ - return nullptr; -} +bool PulseBackendFactory::querySupport(ALCbackend_Type) { return false; } -DEFINE_ALCBACKENDFACTORY_VTABLE(PulseBackendFactory); +void PulseBackendFactory::probe(enum DevProbe, std::string*) { } -PulseBackendFactory::PulseBackendFactory() noexcept - : ALCbackendFactory{ALCPULSEBACKENDFACTORY_INITIALIZER} -{ } +ALCbackend *PulseBackendFactory::createBackend(ALCdevice*, ALCbackend_Type) +{ return nullptr; } #endif /* PA_API_VERSION == 12 */ -ALCbackendFactory *ALCpulseBackendFactory_getFactory(void) +BackendFactory &PulseBackendFactory::getFactory() { static PulseBackendFactory factory{}; - return STATIC_CAST(ALCbackendFactory, &factory); + return factory; } diff --git a/Alc/backends/pulseaudio.h b/Alc/backends/pulseaudio.h new file mode 100644 index 00000000..63b5bbbb --- /dev/null +++ b/Alc/backends/pulseaudio.h @@ -0,0 +1,20 @@ +#ifndef BACKENDS_PULSEAUDIO_H +#define BACKENDS_PULSEAUDIO_H + +#include "backends/base.h" + +class PulseBackendFactory final : public BackendFactory { +public: + bool init() override; + void deinit() override; + + bool querySupport(ALCbackend_Type type) override; + + void probe(enum DevProbe type, std::string *outnames) override; + + ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_PULSEAUDIO_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 06f280f1..7e88efe7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1167,7 +1167,7 @@ IF(PULSEAUDIO_FOUND) IF(ALSOFT_BACKEND_PULSEAUDIO) SET(HAVE_PULSEAUDIO 1) SET(BACKENDS "${BACKENDS} PulseAudio${IS_LINKED},") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/pulseaudio.cpp) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/pulseaudio.cpp Alc/backends/pulseaudio.h) ADD_BACKEND_LIBS(${PULSEAUDIO_LIBRARIES}) SET(INC_PATHS ${INC_PATHS} ${PULSEAUDIO_INCLUDE_DIRS}) ENDIF() -- cgit v1.2.3 From b1fb2e9e142e362ab78c961f8d1069f012b1ece3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 21:14:20 -0800 Subject: Convert the WASAPI backend factory --- Alc/alc.cpp | 6 +++ Alc/backends/base.h | 2 - Alc/backends/wasapi.cpp | 134 ++++++++++++++++++++---------------------------- Alc/backends/wasapi.h | 20 ++++++++ CMakeLists.txt | 2 +- 5 files changed, 82 insertions(+), 82 deletions(-) create mode 100644 Alc/backends/wasapi.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 4c73df06..52aab346 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -62,6 +62,9 @@ #ifdef HAVE_PULSEAUDIO #include "backends/pulseaudio.h" #endif +#ifdef HAVE_WASAPI +#include "backends/wasapi.h" +#endif namespace { @@ -78,6 +81,9 @@ struct BackendInfo BackendList[] = { #ifdef HAVE_PULSEAUDIO { "pulse", PulseBackendFactory::getFactory }, #endif +#ifdef HAVE_WASAPI + { "wasapi", WasapiBackendFactory::getFactory }, +#endif #if 0 { "jack", ALCjackBackendFactory_getFactory }, { "pulse", ALCpulseBackendFactory_getFactory }, diff --git a/Alc/backends/base.h b/Alc/backends/base.h index b87abb3f..a303f761 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -140,7 +140,6 @@ static const struct ALCbackendFactoryVtable T##_ALCbackendFactory_vtable = { \ } -ALCbackendFactory *ALCpulseBackendFactory_getFactory(void); ALCbackendFactory *ALCalsaBackendFactory_getFactory(void); ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void); ALCbackendFactory *ALCossBackendFactory_getFactory(void); @@ -148,7 +147,6 @@ ALCbackendFactory *ALCjackBackendFactory_getFactory(void); ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void); ALCbackendFactory *SndioBackendFactory_getFactory(void); ALCbackendFactory *ALCqsaBackendFactory_getFactory(void); -ALCbackendFactory *ALCwasapiBackendFactory_getFactory(void); ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void); ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void); ALCbackendFactory *ALCportBackendFactory_getFactory(void); diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index b842b8ed..4ebd6f25 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -20,6 +20,8 @@ #include "config.h" +#include "backends/wasapi.h" + #include #include #include @@ -50,8 +52,6 @@ #include "compat.h" #include "converter.h" -#include "backends/base.h" - /* Some headers seem to define these as macros for __uuidof, which is annoying * since some headers don't declare them at all. Hopefully the ifdef is enough @@ -153,7 +153,7 @@ struct ThreadRequest { #define WM_USER_Enumerate (WM_USER+5) #define WM_USER_Last (WM_USER+5) -static const char MessageStr[WM_USER_Last+1-WM_USER][20] = { +constexpr char MessageStr[WM_USER_Last+1-WM_USER][20] = { "Open Device", "Reset Device", "Start Device", @@ -489,8 +489,6 @@ DWORD CALLBACK WasapiProxy_messageHandler(void *ptr) return 0; } -} // namespace - struct ALCwasapiPlayback final : public ALCbackend, WasapiProxy { HRESULT openProxy() override; @@ -515,32 +513,32 @@ struct ALCwasapiPlayback final : public ALCbackend, WasapiProxy { std::thread mThread; }; -static int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self); - -static void ALCwasapiPlayback_Construct(ALCwasapiPlayback *self, ALCdevice *device); -static void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self); -static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *name); -static ALCboolean ALCwasapiPlayback_reset(ALCwasapiPlayback *self); -static ALCboolean ALCwasapiPlayback_start(ALCwasapiPlayback *self); -static void ALCwasapiPlayback_stop(ALCwasapiPlayback *self); -static DECLARE_FORWARD2(ALCwasapiPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -static DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, ALCuint, availableSamples) -static ClockLatency ALCwasapiPlayback_getClockLatency(ALCwasapiPlayback *self); -static DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, void, unlock) +int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self); + +void ALCwasapiPlayback_Construct(ALCwasapiPlayback *self, ALCdevice *device); +void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self); +ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *name); +ALCboolean ALCwasapiPlayback_reset(ALCwasapiPlayback *self); +ALCboolean ALCwasapiPlayback_start(ALCwasapiPlayback *self); +void ALCwasapiPlayback_stop(ALCwasapiPlayback *self); +DECLARE_FORWARD2(ALCwasapiPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) +DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, ALCuint, availableSamples) +ClockLatency ALCwasapiPlayback_getClockLatency(ALCwasapiPlayback *self); +DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, void, lock) +DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCwasapiPlayback) DEFINE_ALCBACKEND_VTABLE(ALCwasapiPlayback); -static void ALCwasapiPlayback_Construct(ALCwasapiPlayback *self, ALCdevice *device) +void ALCwasapiPlayback_Construct(ALCwasapiPlayback *self, ALCdevice *device) { new (self) ALCwasapiPlayback{}; SET_VTABLE2(ALCwasapiPlayback, ALCbackend, self); ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); } -static void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self) +void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self) { if(self->mMsgEvent) { @@ -565,7 +563,7 @@ static void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self) } -FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self) +FORCE_ALIGN int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self) { ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; IAudioClient *client{self->mClient}; @@ -637,7 +635,7 @@ FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self) } -static ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) +ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) { memset(out, 0, sizeof(*out)); if(in->wFormatTag == WAVE_FORMAT_EXTENSIBLE) @@ -676,7 +674,7 @@ static ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX * return ALC_TRUE; } -static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *deviceName) +ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *deviceName) { HRESULT hr = S_OK; @@ -805,7 +803,7 @@ void ALCwasapiPlayback::closeProxy() } -static ALCboolean ALCwasapiPlayback_reset(ALCwasapiPlayback *self) +ALCboolean ALCwasapiPlayback_reset(ALCwasapiPlayback *self) { ThreadRequest req{ self->mMsgEvent, 0 }; HRESULT hr{E_FAIL}; @@ -1076,7 +1074,7 @@ HRESULT ALCwasapiPlayback::resetProxy() } -static ALCboolean ALCwasapiPlayback_start(ALCwasapiPlayback *self) +ALCboolean ALCwasapiPlayback_start(ALCwasapiPlayback *self) { ThreadRequest req{ self->mMsgEvent, 0 }; HRESULT hr{E_FAIL}; @@ -1123,7 +1121,7 @@ HRESULT ALCwasapiPlayback::startProxy() } -static void ALCwasapiPlayback_stop(ALCwasapiPlayback *self) +void ALCwasapiPlayback_stop(ALCwasapiPlayback *self) { ThreadRequest req{ self->mMsgEvent, 0 }; auto proxy = static_cast(self); @@ -1145,7 +1143,7 @@ void ALCwasapiPlayback::stopProxy() } -static ClockLatency ALCwasapiPlayback_getClockLatency(ALCwasapiPlayback *self) +ClockLatency ALCwasapiPlayback_getClockLatency(ALCwasapiPlayback *self) { ClockLatency ret; @@ -1185,32 +1183,32 @@ struct ALCwasapiCapture final : public ALCbackend, WasapiProxy { std::thread mThread; }; -static int ALCwasapiCapture_recordProc(ALCwasapiCapture *self); - -static void ALCwasapiCapture_Construct(ALCwasapiCapture *self, ALCdevice *device); -static void ALCwasapiCapture_Destruct(ALCwasapiCapture *self); -static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *name); -static DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, ALCboolean, reset) -static ALCboolean ALCwasapiCapture_start(ALCwasapiCapture *self); -static void ALCwasapiCapture_stop(ALCwasapiCapture *self); -static ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, ALCuint samples); -static ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self); -static DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, void, unlock) +int ALCwasapiCapture_recordProc(ALCwasapiCapture *self); + +void ALCwasapiCapture_Construct(ALCwasapiCapture *self, ALCdevice *device); +void ALCwasapiCapture_Destruct(ALCwasapiCapture *self); +ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *name); +DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, ALCboolean, reset) +ALCboolean ALCwasapiCapture_start(ALCwasapiCapture *self); +void ALCwasapiCapture_stop(ALCwasapiCapture *self); +ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, ALCuint samples); +ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self); +DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, ClockLatency, getClockLatency) +DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, void, lock) +DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCwasapiCapture) DEFINE_ALCBACKEND_VTABLE(ALCwasapiCapture); -static void ALCwasapiCapture_Construct(ALCwasapiCapture *self, ALCdevice *device) +void ALCwasapiCapture_Construct(ALCwasapiCapture *self, ALCdevice *device) { new (self) ALCwasapiCapture{}; SET_VTABLE2(ALCwasapiCapture, ALCbackend, self); ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); } -static void ALCwasapiCapture_Destruct(ALCwasapiCapture *self) +void ALCwasapiCapture_Destruct(ALCwasapiCapture *self) { if(self->mMsgEvent) { @@ -1343,7 +1341,7 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) } -static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *deviceName) +ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *deviceName) { HRESULT hr{S_OK}; @@ -1730,7 +1728,7 @@ HRESULT ALCwasapiCapture::resetProxy() } -static ALCboolean ALCwasapiCapture_start(ALCwasapiCapture *self) +ALCboolean ALCwasapiCapture_start(ALCwasapiCapture *self) { ThreadRequest req{ self->mMsgEvent, 0 }; HRESULT hr{E_FAIL}; @@ -1780,7 +1778,7 @@ HRESULT ALCwasapiCapture::startProxy() } -static void ALCwasapiCapture_stop(ALCwasapiCapture *self) +void ALCwasapiCapture_stop(ALCwasapiCapture *self) { ThreadRequest req{ self->mMsgEvent, 0 }; auto proxy = static_cast(self); @@ -1803,12 +1801,12 @@ void ALCwasapiCapture::stopProxy() } -static ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self) +ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self) { return (ALuint)ll_ringbuffer_read_space(self->mRing); } -static ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, ALCuint samples) { if(ALCwasapiCapture_availableSamples(self) < samples) return ALC_INVALID_VALUE; @@ -1816,27 +1814,10 @@ static ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid * return ALC_NO_ERROR; } - -struct ALCwasapiBackendFactory final : public ALCbackendFactory { - ALCwasapiBackendFactory() noexcept; -}; -#define ALCWASAPIBACKENDFACTORY_INITIALIZER GET_VTABLE2(ALCwasapiBackendFactory, ALCbackendFactory) - -static ALCboolean ALCwasapiBackendFactory_init(ALCwasapiBackendFactory *self); -static void ALCwasapiBackendFactory_deinit(ALCwasapiBackendFactory *self); -static ALCboolean ALCwasapiBackendFactory_querySupport(ALCwasapiBackendFactory *self, ALCbackend_Type type); -static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory *self, enum DevProbe type, std::string *outnames); -static ALCbackend* ALCwasapiBackendFactory_createBackend(ALCwasapiBackendFactory *self, ALCdevice *device, ALCbackend_Type type); - -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwasapiBackendFactory); - -ALCwasapiBackendFactory::ALCwasapiBackendFactory() noexcept - : ALCbackendFactory{ALCWASAPIBACKENDFACTORY_INITIALIZER} -{ -} +} // namespace -static ALCboolean ALCwasapiBackendFactory_init(ALCwasapiBackendFactory* UNUSED(self)) +bool WasapiBackendFactory::init() { static HRESULT InitResult; @@ -1860,7 +1841,7 @@ static ALCboolean ALCwasapiBackendFactory_init(ALCwasapiBackendFactory* UNUSED(s return SUCCEEDED(InitResult) ? ALC_TRUE : ALC_FALSE; } -static void ALCwasapiBackendFactory_deinit(ALCwasapiBackendFactory* UNUSED(self)) +void WasapiBackendFactory::deinit() { PlaybackDevices.clear(); CaptureDevices.clear(); @@ -1874,14 +1855,10 @@ static void ALCwasapiBackendFactory_deinit(ALCwasapiBackendFactory* UNUSED(self) } } -static ALCboolean ALCwasapiBackendFactory_querySupport(ALCwasapiBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} +bool WasapiBackendFactory::querySupport(ALCbackend_Type type) +{ return (type == ALCbackend_Playback || type == ALCbackend_Capture); } -static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) +void WasapiBackendFactory::probe(enum DevProbe type, std::string *outnames) { ThreadRequest req{ nullptr, 0 }; @@ -1915,7 +1892,7 @@ static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory* UNUSED(self), } } -static ALCbackend* ALCwasapiBackendFactory_createBackend(ALCwasapiBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +ALCbackend *WasapiBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) { @@ -1935,9 +1912,8 @@ static ALCbackend* ALCwasapiBackendFactory_createBackend(ALCwasapiBackendFactory return nullptr; } - -ALCbackendFactory *ALCwasapiBackendFactory_getFactory(void) +BackendFactory &WasapiBackendFactory::getFactory() { - static ALCwasapiBackendFactory factory{}; - return STATIC_CAST(ALCbackendFactory, &factory); + static WasapiBackendFactory factory{}; + return factory; } diff --git a/Alc/backends/wasapi.h b/Alc/backends/wasapi.h new file mode 100644 index 00000000..2ee10ac8 --- /dev/null +++ b/Alc/backends/wasapi.h @@ -0,0 +1,20 @@ +#ifndef BACKENDS_WASAPI_H +#define BACKENDS_WASAPI_H + +#include "backends/base.h" + +struct WasapiBackendFactory final : public BackendFactory { +public: + bool init() override; + void deinit() override; + + bool querySupport(ALCbackend_Type type) override; + + void probe(enum DevProbe type, std::string *outnames) override; + + ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_WASAPI_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e88efe7..b8905764 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1125,7 +1125,7 @@ IF(HAVE_WINDOWS_H) IF(ALSOFT_BACKEND_WASAPI) SET(HAVE_WASAPI 1) SET(BACKENDS "${BACKENDS} WASAPI,") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/wasapi.cpp) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/wasapi.cpp Alc/backends/wasapi.h) ENDIF() ENDIF() -- cgit v1.2.3 From ead830814b95f137fa4d51ebf91b353a823f4e30 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 21:24:09 -0800 Subject: Convert the CoreAudio backend factory --- Alc/alc.cpp | 6 ++++++ Alc/backends/coreaudio.cpp | 52 ++++++++++++---------------------------------- Alc/backends/coreaudio.h | 20 ++++++++++++++++++ CMakeLists.txt | 2 +- 4 files changed, 40 insertions(+), 40 deletions(-) create mode 100644 Alc/backends/coreaudio.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 52aab346..d4e2dda5 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -65,6 +65,9 @@ #ifdef HAVE_WASAPI #include "backends/wasapi.h" #endif +#ifdef HAVE_COREAUDIO +#include "backends/coreaudio.h" +#endif namespace { @@ -84,6 +87,9 @@ struct BackendInfo BackendList[] = { #ifdef HAVE_WASAPI { "wasapi", WasapiBackendFactory::getFactory }, #endif +#ifdef HAVE_COREAUDIO + { "core", CoreAudioBackendFactory::getFactory }, +#endif #if 0 { "jack", ALCjackBackendFactory_getFactory }, { "pulse", ALCpulseBackendFactory_getFactory }, diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index 1a3f2ab1..62df982e 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -20,6 +20,8 @@ #include "config.h" +#include "backends/coreaudio.h" + #include #include #include @@ -32,8 +34,6 @@ #include #include -#include "backends/base.h" - static const ALCchar ca_device[] = "CoreAudio Default"; @@ -753,44 +753,18 @@ static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self) } -struct ALCcoreAudioBackendFactory final : public ALCbackendFactory { - ALCcoreAudioBackendFactory() noexcept; -}; - -ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void); - -static ALCboolean ALCcoreAudioBackendFactory_init(ALCcoreAudioBackendFactory *self); -static DECLARE_FORWARD(ALCcoreAudioBackendFactory, ALCbackendFactory, void, deinit) -static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFactory *self, ALCbackend_Type type); -static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory *self, enum DevProbe type, std::string *outnames); -static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCcoreAudioBackendFactory); - - -ALCcoreAudioBackendFactory::ALCcoreAudioBackendFactory() noexcept - : ALCbackendFactory{GET_VTABLE2(ALCcoreAudioBackendFactory, ALCbackendFactory)} -{ } - -ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void) +BackendFactory &CoreAudioBackendFactory::getFactory() { - static ALCcoreAudioBackendFactory factory{}; - return STATIC_CAST(ALCbackendFactory, &factory); + static CoreAudioBackendFactory factory{}; + return factory; } +bool CoreAudioBackendFactory::init() { return true; } -static ALCboolean ALCcoreAudioBackendFactory_init(ALCcoreAudioBackendFactory* UNUSED(self)) -{ - return ALC_TRUE; -} - -static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} +bool CoreAudioBackendFactory::querySupport(ALCbackend_Type type) +{ return (type == ALCbackend_Playback || ALCbackend_Capture); } -static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) +void CoreAudioBackendFactory::probe(enum DevProbe type, std::string *outnames) { switch(type) { @@ -802,22 +776,22 @@ static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory* UNUSED( } } -static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +ALCbackend *CoreAudioBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) { ALCcoreAudioPlayback *backend; NEW_OBJ(backend, ALCcoreAudioPlayback)(device); - if(!backend) return NULL; + if(!backend) return nullptr; return STATIC_CAST(ALCbackend, backend); } if(type == ALCbackend_Capture) { ALCcoreAudioCapture *backend; NEW_OBJ(backend, ALCcoreAudioCapture)(device); - if(!backend) return NULL; + if(!backend) return nullptr; return STATIC_CAST(ALCbackend, backend); } - return NULL; + return nullptr; } diff --git a/Alc/backends/coreaudio.h b/Alc/backends/coreaudio.h new file mode 100644 index 00000000..2926ee12 --- /dev/null +++ b/Alc/backends/coreaudio.h @@ -0,0 +1,20 @@ +#ifndef BACKENDS_COREAUDIO_H +#define BACKENDS_COREAUDIO_H + +#include "backends/base.h" + +struct CoreAudioBackendFactory final : public BackendFactory { +public: + bool init() override; + /*void deinit() override;*/ + + bool querySupport(ALCbackend_Type type) override; + + void probe(enum DevProbe type, std::string *outnames) override; + + ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_COREAUDIO_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index b8905764..1b2cab60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1203,7 +1203,7 @@ IF(COREAUDIO_FRAMEWORK) OPTION(ALSOFT_BACKEND_COREAUDIO "Enable CoreAudio backend" ON) IF(ALSOFT_BACKEND_COREAUDIO) SET(HAVE_COREAUDIO 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/coreaudio.cpp) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/coreaudio.cpp Alc/backends/coreaudio.h) SET(BACKENDS "${BACKENDS} CoreAudio,") SET(EXTRA_LIBS ${COREAUDIO_FRAMEWORK} ${EXTRA_LIBS}) SET(EXTRA_LIBS /System/Library/Frameworks/AudioUnit.framework ${EXTRA_LIBS}) -- cgit v1.2.3 From 9d43b548cc982d6ac90ccad82990f96622e74308 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 21:33:44 -0800 Subject: Convert the ALSA backend factory --- Alc/alc.cpp | 6 +++ Alc/backends/alsa.cpp | 127 +++++++++++++++++++++----------------------------- Alc/backends/alsa.h | 20 ++++++++ CMakeLists.txt | 2 +- 4 files changed, 80 insertions(+), 75 deletions(-) create mode 100644 Alc/backends/alsa.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index d4e2dda5..0e61385a 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -62,6 +62,9 @@ #ifdef HAVE_PULSEAUDIO #include "backends/pulseaudio.h" #endif +#ifdef HAVE_ALSA +#include "backends/alsa.h" +#endif #ifdef HAVE_WASAPI #include "backends/wasapi.h" #endif @@ -84,6 +87,9 @@ struct BackendInfo BackendList[] = { #ifdef HAVE_PULSEAUDIO { "pulse", PulseBackendFactory::getFactory }, #endif +#ifdef HAVE_ALSA + { "alsa", AlsaBackendFactory::getFactory }, +#endif #ifdef HAVE_WASAPI { "wasapi", WasapiBackendFactory::getFactory }, #endif diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index 23e33e6b..ee42842b 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -20,6 +20,8 @@ #include "config.h" +#include "backends/alsa.h" + #include #include #include @@ -36,8 +38,6 @@ #include "ringbuffer.h" #include "compat.h" -#include "backends/base.h" - #include @@ -421,8 +421,6 @@ int verify_state(snd_pcm_t *handle) return state; } -} // namespace - struct ALCplaybackAlsa final : public ALCbackend { snd_pcm_t *pcmHandle{nullptr}; @@ -433,26 +431,25 @@ struct ALCplaybackAlsa final : public ALCbackend { std::thread thread; }; -static int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self); -static int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self); - -static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device); -static void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self); -static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name); -static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self); -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 ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self); -static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, unlock) +int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self); +int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self); + +void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device); +void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self); +ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name); +ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self); +ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self); +void ALCplaybackAlsa_stop(ALCplaybackAlsa *self); +DECLARE_FORWARD2(ALCplaybackAlsa, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, ALCuint, availableSamples) +ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self); +DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, lock) +DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCplaybackAlsa) - DEFINE_ALCBACKEND_VTABLE(ALCplaybackAlsa); -static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device) +void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device) { new (self) ALCplaybackAlsa{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); @@ -470,7 +467,7 @@ void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self) } -static int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) +int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) { ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; @@ -557,7 +554,7 @@ static int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) return 0; } -static int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self) +int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self) { ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; @@ -650,7 +647,7 @@ static int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self) } -static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name) +ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name) { const char *driver{}; if(name) @@ -690,7 +687,7 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name) return ALC_NO_ERROR; } -static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) +ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) { ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; @@ -842,7 +839,7 @@ error: return ALC_FALSE; } -static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) +ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) { ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; int (*thread_func)(ALCplaybackAlsa*){}; @@ -895,7 +892,7 @@ error: return ALC_FALSE; } -static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self) +void ALCplaybackAlsa_stop(ALCplaybackAlsa *self) { if(self->killNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->thread.joinable()) return; @@ -905,7 +902,7 @@ static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self) self->buffer.clear(); } -static ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self) +ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self) { ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; ClockLatency ret; @@ -937,23 +934,23 @@ struct ALCcaptureAlsa final : public ALCbackend { snd_pcm_sframes_t last_avail{0}; }; -static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device); -static void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self); -static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name); -static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, ALCboolean, reset) -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 ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self); -static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, unlock) +void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device); +void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self); +ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name); +DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, ALCboolean, reset) +ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self); +void ALCcaptureAlsa_stop(ALCcaptureAlsa *self); +ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALCuint samples); +ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self); +ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self); +DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, lock) +DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCcaptureAlsa) DEFINE_ALCBACKEND_VTABLE(ALCcaptureAlsa); -static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device) +void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device) { new (self) ALCcaptureAlsa{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); @@ -974,7 +971,7 @@ void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self) } -static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) +ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; const char *driver{}; @@ -1101,7 +1098,7 @@ error2: return ALC_INVALID_VALUE; } -static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self) +ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self) { int err{snd_pcm_prepare(self->pcmHandle)}; if(err < 0) @@ -1123,7 +1120,7 @@ static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self) return ALC_TRUE; } -static void ALCcaptureAlsa_stop(ALCcaptureAlsa *self) +void ALCcaptureAlsa_stop(ALCcaptureAlsa *self) { /* OpenAL requires access to unread audio after stopping, but ALSA's * snd_pcm_drain is unreliable and snd_pcm_drop drops it. Capture what's @@ -1143,7 +1140,7 @@ static void ALCcaptureAlsa_stop(ALCcaptureAlsa *self) self->doCapture = false; } -static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALCuint samples) +ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALCuint samples) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -1207,7 +1204,7 @@ static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buff return ALC_NO_ERROR; } -static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) +ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -1278,7 +1275,7 @@ static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) return ll_ringbuffer_read_space(self->ring); } -static ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self) +ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self) { ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; ClockLatency ret; @@ -1298,19 +1295,13 @@ static ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self) return ret; } +} // namespace -struct ALCalsaBackendFactory final : public ALCbackendFactory { - ALCalsaBackendFactory() noexcept; -}; -static ALCboolean ALCalsaBackendFactory_init(ALCalsaBackendFactory* UNUSED(self)) -{ - if(!alsa_load()) - return ALC_FALSE; - return ALC_TRUE; -} +bool AlsaBackendFactory::init() +{ return !!alsa_load(); } -static void ALCalsaBackendFactory_deinit(ALCalsaBackendFactory* UNUSED(self)) +void AlsaBackendFactory::deinit() { PlaybackDevices.clear(); CaptureDevices.clear(); @@ -1322,14 +1313,10 @@ static void ALCalsaBackendFactory_deinit(ALCalsaBackendFactory* UNUSED(self)) #endif } -static ALCboolean ALCalsaBackendFactory_querySupport(ALCalsaBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} +bool AlsaBackendFactory::querySupport(ALCbackend_Type type) +{ return (type == ALCbackend_Playback || type == ALCbackend_Capture); } -static void ALCalsaBackendFactory_probe(ALCalsaBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) +void AlsaBackendFactory::probe(enum DevProbe type, std::string *outnames) { auto add_device = [outnames](const DevMap &entry) -> void { @@ -1352,7 +1339,7 @@ static void ALCalsaBackendFactory_probe(ALCalsaBackendFactory* UNUSED(self), enu } } -static ALCbackend* ALCalsaBackendFactory_createBackend(ALCalsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +ALCbackend *AlsaBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) { @@ -1372,16 +1359,8 @@ static ALCbackend* ALCalsaBackendFactory_createBackend(ALCalsaBackendFactory* UN return nullptr; } -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCalsaBackendFactory); - - -ALCalsaBackendFactory::ALCalsaBackendFactory() noexcept - : ALCbackendFactory{GET_VTABLE2(ALCalsaBackendFactory, ALCbackendFactory)} -{ -} - -ALCbackendFactory *ALCalsaBackendFactory_getFactory(void) +BackendFactory &AlsaBackendFactory::getFactory() { - static ALCalsaBackendFactory factory{}; - return STATIC_CAST(ALCbackendFactory, &factory); + static AlsaBackendFactory factory{}; + return factory; } diff --git a/Alc/backends/alsa.h b/Alc/backends/alsa.h new file mode 100644 index 00000000..3f772115 --- /dev/null +++ b/Alc/backends/alsa.h @@ -0,0 +1,20 @@ +#ifndef BACKENDS_ALSA_H +#define BACKENDS_ALSA_H + +#include "backends/base.h" + +struct AlsaBackendFactory final : public BackendFactory { +public: + bool init() override; + void deinit() override; + + bool querySupport(ALCbackend_Type type) override; + + void probe(enum DevProbe type, std::string *outnames) override; + + ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_ALSA_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b2cab60..66a2dbe5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1004,7 +1004,7 @@ IF(ALSA_FOUND) IF(ALSOFT_BACKEND_ALSA) SET(HAVE_ALSA 1) SET(BACKENDS "${BACKENDS} ALSA${IS_LINKED},") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/alsa.cpp) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/alsa.cpp Alc/backends/alsa.h) ADD_BACKEND_LIBS(${ALSA_LIBRARIES}) SET(INC_PATHS ${INC_PATHS} ${ALSA_INCLUDE_DIRS}) ENDIF() -- cgit v1.2.3 From cc113ce6aba8970cb9c111695c71400b2b8d39c3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 21:42:17 -0800 Subject: Convert the OpenSL backend factory --- Alc/alc.cpp | 6 ++++++ Alc/backends/opensl.cpp | 48 +++++++++++++----------------------------------- Alc/backends/opensl.h | 20 ++++++++++++++++++++ CMakeLists.txt | 2 +- 4 files changed, 40 insertions(+), 36 deletions(-) create mode 100644 Alc/backends/opensl.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 0e61385a..c27dd2a0 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -71,6 +71,9 @@ #ifdef HAVE_COREAUDIO #include "backends/coreaudio.h" #endif +#ifdef HAVE_OPENSL +#include "backends/opensl.h" +#endif namespace { @@ -96,6 +99,9 @@ struct BackendInfo BackendList[] = { #ifdef HAVE_COREAUDIO { "core", CoreAudioBackendFactory::getFactory }, #endif +#ifdef HAVE_OPENSL + { "opensl", OSLBackendFactory::getFactory }, +#endif #if 0 { "jack", ALCjackBackendFactory_getFactory }, { "pulse", ALCpulseBackendFactory_getFactory }, diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 689c02af..e8a575c8 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -21,6 +21,8 @@ #include "config.h" +#include "backends/opensl.h" + #include #include @@ -30,8 +32,6 @@ #include "threads.h" #include "compat.h" -#include "backends/base.h" - #include #include #include @@ -1011,27 +1011,12 @@ static ALCuint ALCopenslCapture_availableSamples(ALCopenslCapture *self) } -struct ALCopenslBackendFactory final : public ALCbackendFactory { - ALCopenslBackendFactory() noexcept; -}; +bool OSLBackendFactory::init() { return true; } -static ALCboolean ALCopenslBackendFactory_init(ALCopenslBackendFactory* UNUSED(self)) -{ - return ALC_TRUE; -} +bool OSLBackendFactory::querySupport(ALCbackend_Type type) +{ return (type == ALCbackend_Playback || type == ALCbackend_Capture); } -static void ALCopenslBackendFactory_deinit(ALCopenslBackendFactory* UNUSED(self)) -{ -} - -static ALCboolean ALCopenslBackendFactory_querySupport(ALCopenslBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} - -static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) +void OSLBackendFactory::probe(enum DevProbe type, std::string *outnames) { switch(type) { @@ -1043,35 +1028,28 @@ static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory* UNUSED(self), } } -static ALCbackend* ALCopenslBackendFactory_createBackend(ALCopenslBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +ALCbackend *OSLBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) { ALCopenslPlayback *backend; NEW_OBJ(backend, ALCopenslPlayback)(device); - if(!backend) return NULL; + if(!backend) return nullptr; return STATIC_CAST(ALCbackend, backend); } if(type == ALCbackend_Capture) { ALCopenslCapture *backend; NEW_OBJ(backend, ALCopenslCapture)(device); - if(!backend) return NULL; + if(!backend) return nullptr; return STATIC_CAST(ALCbackend, backend); } - return NULL; + return nullptr; } -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCopenslBackendFactory); - - -ALCopenslBackendFactory::ALCopenslBackendFactory() noexcept - : ALCbackendFactory{GET_VTABLE2(ALCopenslBackendFactory, ALCbackendFactory)} -{ } - -ALCbackendFactory *ALCopenslBackendFactory_getFactory(void) +BackendFactory &OSLBackendFactory::getFactory() { - static ALCopenslBackendFactory factory{}; - return STATIC_CAST(ALCbackendFactory, &factory); + static OSLBackendFactory factory{}; + return factory; } diff --git a/Alc/backends/opensl.h b/Alc/backends/opensl.h new file mode 100644 index 00000000..799d568f --- /dev/null +++ b/Alc/backends/opensl.h @@ -0,0 +1,20 @@ +#ifndef BACKENDS_OSL_H +#define BACKENDS_OSL_H + +#include "backends/base.h" + +struct OSLBackendFactory final : public BackendFactory { +public: + bool init() override; + /*void deinit() override;*/ + + bool querySupport(ALCbackend_Type type) override; + + void probe(enum DevProbe type, std::string *outnames) override; + + ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_OSL_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 66a2dbe5..6942fa46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1235,7 +1235,7 @@ IF(HAVE_SLES_OPENSLES_ANDROID_H) OPTION(ALSOFT_BACKEND_OPENSL "Enable OpenSL backend" ON) IF(ALSOFT_BACKEND_OPENSL) SET(HAVE_OPENSL 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/opensl.cpp) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/opensl.cpp Alc/backends/opensl.h) SET(BACKENDS "${BACKENDS} OpenSL,") SET(EXTRA_LIBS OpenSLES ${EXTRA_LIBS}) ENDIF() -- cgit v1.2.3 From d4928d4e7df0517313530db63503a56e8ab63caa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 21:53:14 -0800 Subject: Convert the Wave Writer backend factory --- Alc/alc.cpp | 9 +++-- Alc/backends/wave.cpp | 91 ++++++++++++++++++--------------------------------- Alc/backends/wave.h | 20 +++++++++++ CMakeLists.txt | 2 +- 4 files changed, 59 insertions(+), 63 deletions(-) create mode 100644 Alc/backends/wave.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index c27dd2a0..9319cfc3 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -74,6 +74,9 @@ #ifdef HAVE_OPENSL #include "backends/opensl.h" #endif +#ifdef HAVE_WAVE +#include "backends/wave.h" +#endif namespace { @@ -117,12 +120,12 @@ struct BackendInfo BackendList[] = { { "port", ALCportBackendFactory_getFactory }, { "opensl", ALCopenslBackendFactory_getFactory }, { "sdl2", ALCsdl2BackendFactory_getFactory }, - - { "null", ALCnullBackendFactory_getFactory }, - { "wave", ALCwaveBackendFactory_getFactory }, #endif /* 0 */ { "null", NullBackendFactory::getFactory }, +#ifdef HAVE_WAVE + { "wave", WaveBackendFactory::getFactory }, +#endif }; ALsizei BackendListSize = COUNTOF(BackendList); #undef EmptyFuncs diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index ea4af146..fb00ef32 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -20,6 +20,8 @@ #include "config.h" +#include "backends/wave.h" + #include #include #include @@ -34,8 +36,6 @@ #include "alconfig.h" #include "compat.h" -#include "backends/base.h" - namespace { @@ -77,8 +77,6 @@ void fwrite32le(ALuint val, FILE *f) fwrite(data, 1, 4, f); } -} // namespace - struct ALCwaveBackend final : public ALCbackend { FILE *mFile; @@ -90,25 +88,25 @@ struct ALCwaveBackend final : public ALCbackend { std::thread thread; }; -static int ALCwaveBackend_mixerProc(ALCwaveBackend *self); - -static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device); -static void ALCwaveBackend_Destruct(ALCwaveBackend *self); -static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name); -static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self); -static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self); -static void ALCwaveBackend_stop(ALCwaveBackend *self); -static DECLARE_FORWARD2(ALCwaveBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, unlock) +int ALCwaveBackend_mixerProc(ALCwaveBackend *self); + +void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device); +void ALCwaveBackend_Destruct(ALCwaveBackend *self); +ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name); +ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self); +ALCboolean ALCwaveBackend_start(ALCwaveBackend *self); +void ALCwaveBackend_stop(ALCwaveBackend *self); +DECLARE_FORWARD2(ALCwaveBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ALCuint, availableSamples) +DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ClockLatency, getClockLatency) +DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, lock) +DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCwaveBackend) DEFINE_ALCBACKEND_VTABLE(ALCwaveBackend); -static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device) +void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device) { new (self) ALCwaveBackend{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); @@ -120,7 +118,7 @@ static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device) ATOMIC_INIT(&self->killNow, AL_TRUE); } -static void ALCwaveBackend_Destruct(ALCwaveBackend *self) +void ALCwaveBackend_Destruct(ALCwaveBackend *self) { if(self->mFile) fclose(self->mFile); @@ -130,7 +128,7 @@ static void ALCwaveBackend_Destruct(ALCwaveBackend *self) self->~ALCwaveBackend(); } -static int ALCwaveBackend_mixerProc(ALCwaveBackend *self) +int ALCwaveBackend_mixerProc(ALCwaveBackend *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; const milliseconds restTime{device->UpdateSize*1000/device->Frequency / 2}; @@ -217,7 +215,7 @@ static int ALCwaveBackend_mixerProc(ALCwaveBackend *self) } -static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name) +ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name) { const char *fname{GetConfigValue(nullptr, "wave", "file", "")}; if(!fname[0]) return ALC_INVALID_VALUE; @@ -248,7 +246,7 @@ static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name) return ALC_NO_ERROR; } -static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) +ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; ALuint channels=0, bits=0, chanmask=0; @@ -353,7 +351,7 @@ static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) return ALC_TRUE; } -static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self) +ALCboolean ALCwaveBackend_start(ALCwaveBackend *self) { try { ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); @@ -368,7 +366,7 @@ static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self) return ALC_FALSE; } -static void ALCwaveBackend_stop(ALCwaveBackend *self) +void ALCwaveBackend_stop(ALCwaveBackend *self) { if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel) || !self->thread.joinable()) @@ -386,41 +384,16 @@ static void ALCwaveBackend_stop(ALCwaveBackend *self) } } - -struct ALCwaveBackendFactory final : public ALCbackendFactory { - ALCwaveBackendFactory() noexcept; -}; -#define ALCWAVEBACKENDFACTORY_INITIALIZER GET_VTABLE2(ALCwaveBackendFactory, ALCbackendFactory) - -ALCbackendFactory *ALCwaveBackendFactory_getFactory(void); - -static ALCboolean ALCwaveBackendFactory_init(ALCwaveBackendFactory *self); -static DECLARE_FORWARD(ALCwaveBackendFactory, ALCbackendFactory, void, deinit) -static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory *self, ALCbackend_Type type); -static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory *self, enum DevProbe type, std::string *outnames); -static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwaveBackendFactory); - - -ALCwaveBackendFactory::ALCwaveBackendFactory() noexcept - : ALCbackendFactory{ALCWAVEBACKENDFACTORY_INITIALIZER} -{ -} +} // namespace -static ALCboolean ALCwaveBackendFactory_init(ALCwaveBackendFactory* UNUSED(self)) -{ - return ALC_TRUE; -} +bool WaveBackendFactory::init() +{ return true; } -static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - return !!ConfigValueExists(nullptr, "wave", "file"); - return ALC_FALSE; -} +bool WaveBackendFactory::querySupport(ALCbackend_Type type) +{ return (type == ALCbackend_Playback); } -static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) +void WaveBackendFactory::probe(enum DevProbe type, std::string *outnames) { switch(type) { @@ -433,7 +406,7 @@ static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory* UNUSED(self), enu } } -static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +ALCbackend *WaveBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) { @@ -446,8 +419,8 @@ static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory* UN return nullptr; } -ALCbackendFactory *ALCwaveBackendFactory_getFactory(void) +BackendFactory &WaveBackendFactory::getFactory() { - static ALCwaveBackendFactory factory{}; - return STATIC_CAST(ALCbackendFactory, &factory); + static WaveBackendFactory factory{}; + return factory; } diff --git a/Alc/backends/wave.h b/Alc/backends/wave.h new file mode 100644 index 00000000..65bb5ecf --- /dev/null +++ b/Alc/backends/wave.h @@ -0,0 +1,20 @@ +#ifndef BACKENDS_WAVE_H +#define BACKENDS_WAVE_H + +#include "backends/base.h" + +struct WaveBackendFactory final : public BackendFactory { +public: + bool init() override; + /*void deinit() override;*/ + + bool querySupport(ALCbackend_Type type) override; + + void probe(enum DevProbe type, std::string *outnames) override; + + ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_WAVE_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 6942fa46..bd302de5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1267,7 +1267,7 @@ ENDIF() OPTION(ALSOFT_BACKEND_WAVE "Enable Wave Writer backend" ON) IF(ALSOFT_BACKEND_WAVE) SET(HAVE_WAVE 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/wave.cpp) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/wave.cpp Alc/backends/wave.h) SET(BACKENDS "${BACKENDS} WaveFile,") ENDIF() -- cgit v1.2.3 From 2a839e5762fa6bd4b0399e2f588ce0805e92b618 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 22:03:20 -0800 Subject: Convert the JACK backend factory --- Alc/alc.cpp | 11 +++++++---- Alc/backends/jack.cpp | 51 ++++++++++++++++++--------------------------------- Alc/backends/jack.h | 20 ++++++++++++++++++++ CMakeLists.txt | 2 +- 4 files changed, 46 insertions(+), 38 deletions(-) create mode 100644 Alc/backends/jack.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 9319cfc3..d83b545f 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -59,6 +59,9 @@ #include "backends/base.h" #include "backends/null.h" #include "backends/loopback.h" +#ifdef HAVE_JACK +#include "backends/jack.h" +#endif #ifdef HAVE_PULSEAUDIO #include "backends/pulseaudio.h" #endif @@ -90,6 +93,9 @@ struct BackendInfo { }; struct BackendInfo BackendList[] = { +#ifdef HAVE_JACK + { "jack", JackBackendFactory::getFactory }, +#endif #ifdef HAVE_PULSEAUDIO { "pulse", PulseBackendFactory::getFactory }, #endif @@ -105,11 +111,8 @@ struct BackendInfo BackendList[] = { #ifdef HAVE_OPENSL { "opensl", OSLBackendFactory::getFactory }, #endif + #if 0 - { "jack", ALCjackBackendFactory_getFactory }, - { "pulse", ALCpulseBackendFactory_getFactory }, - { "alsa", ALCalsaBackendFactory_getFactory }, - { "core", ALCcoreAudioBackendFactory_getFactory }, { "solaris", ALCsolarisBackendFactory_getFactory }, { "sndio", SndioBackendFactory_getFactory }, { "oss", ALCossBackendFactory_getFactory }, diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index 9db75537..ac57ffd5 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -20,6 +20,8 @@ #include "config.h" +#include "backends/jack.h" + #include #include #include @@ -31,8 +33,6 @@ #include "threads.h" #include "compat.h" -#include "backends/base.h" - #include #include @@ -520,18 +520,14 @@ static void jack_msg_handler(const char *message) WARN("%s\n", message); } -struct ALCjackBackendFactory final : public ALCbackendFactory { - ALCjackBackendFactory() noexcept; -}; - -static ALCboolean ALCjackBackendFactory_init(ALCjackBackendFactory* UNUSED(self)) +bool JackBackendFactory::init() { void (*old_error_cb)(const char*); jack_client_t *client; jack_status_t status; if(!jack_load()) - return ALC_FALSE; + return false; if(!GetConfigValueBool(NULL, "jack", "spawn-server", 0)) ClientOptions = static_cast(ClientOptions | JackNoStartServer); @@ -540,35 +536,31 @@ static ALCboolean ALCjackBackendFactory_init(ALCjackBackendFactory* UNUSED(self) jack_set_error_function(jack_msg_handler); client = jack_client_open("alsoft", ClientOptions, &status, NULL); jack_set_error_function(old_error_cb); - if(client == NULL) + if(!client) { WARN("jack_client_open() failed, 0x%02x\n", status); if((status&JackServerFailed) && !(ClientOptions&JackNoStartServer)) ERR("Unable to connect to JACK server\n"); - return ALC_FALSE; + return false; } jack_client_close(client); - return ALC_TRUE; + return true; } -static void ALCjackBackendFactory_deinit(ALCjackBackendFactory* UNUSED(self)) +void JackBackendFactory::deinit() { #ifdef HAVE_DYNLOAD if(jack_handle) CloseLib(jack_handle); - jack_handle = NULL; + jack_handle = nullptr; #endif } -static ALCboolean ALCjackBackendFactory_querySupport(ALCjackBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - return ALC_TRUE; - return ALC_FALSE; -} +bool JackBackendFactory::querySupport(ALCbackend_Type type) +{ return (type == ALCbackend_Playback); } -static void ALCjackBackendFactory_probe(ALCjackBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) +void JackBackendFactory::probe(enum DevProbe type, std::string *outnames) { switch(type) { @@ -582,28 +574,21 @@ static void ALCjackBackendFactory_probe(ALCjackBackendFactory* UNUSED(self), enu } } -static ALCbackend* ALCjackBackendFactory_createBackend(ALCjackBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +ALCbackend *JackBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) { ALCjackPlayback *backend; NEW_OBJ(backend, ALCjackPlayback)(device); - if(!backend) return NULL; + if(!backend) return nullptr; return STATIC_CAST(ALCbackend, backend); } - return NULL; + return nullptr; } -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCjackBackendFactory); - - -ALCjackBackendFactory::ALCjackBackendFactory() noexcept - : ALCbackendFactory{GET_VTABLE2(ALCjackBackendFactory, ALCbackendFactory)} -{ } - -ALCbackendFactory *ALCjackBackendFactory_getFactory(void) +BackendFactory &JackBackendFactory::getFactory() { - static ALCjackBackendFactory factory{}; - return STATIC_CAST(ALCbackendFactory, &factory); + static JackBackendFactory factory{}; + return factory; } diff --git a/Alc/backends/jack.h b/Alc/backends/jack.h new file mode 100644 index 00000000..8a6e3a22 --- /dev/null +++ b/Alc/backends/jack.h @@ -0,0 +1,20 @@ +#ifndef BACKENDS_JACK_H +#define BACKENDS_JACK_H + +#include "backends/base.h" + +struct JackBackendFactory final : public BackendFactory { +public: + bool init() override; + void deinit() override; + + bool querySupport(ALCbackend_Type type) override; + + void probe(enum DevProbe type, std::string *outnames) override; + + ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_JACK_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index bd302de5..d487d6d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1184,7 +1184,7 @@ IF(JACK_FOUND) IF(ALSOFT_BACKEND_JACK) SET(HAVE_JACK 1) SET(BACKENDS "${BACKENDS} JACK${IS_LINKED},") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/jack.cpp) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/jack.cpp Alc/backends/jack.h) ADD_BACKEND_LIBS(${JACK_LIBRARIES}) SET(INC_PATHS ${INC_PATHS} ${JACK_INCLUDE_DIRS}) ENDIF() -- cgit v1.2.3 From d73d01548d992f6f683f6685ff8f4767e8843ad9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 22:15:10 -0800 Subject: Convert the SDL2 backend factory --- Alc/alc.cpp | 8 ++++++-- Alc/backends/sdl2.cpp | 47 ++++++++++++----------------------------------- Alc/backends/sdl2.h | 20 ++++++++++++++++++++ CMakeLists.txt | 2 +- 4 files changed, 39 insertions(+), 38 deletions(-) create mode 100644 Alc/backends/sdl2.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index d83b545f..63f60e80 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -77,6 +77,9 @@ #ifdef HAVE_OPENSL #include "backends/opensl.h" #endif +#ifdef HAVE_SDL2 +#include "backends/sdl2.h" +#endif #ifdef HAVE_WAVE #include "backends/wave.h" #endif @@ -121,9 +124,10 @@ struct BackendInfo BackendList[] = { { "dsound", ALCdsoundBackendFactory_getFactory }, { "winmm", ALCwinmmBackendFactory_getFactory }, { "port", ALCportBackendFactory_getFactory }, - { "opensl", ALCopenslBackendFactory_getFactory }, - { "sdl2", ALCsdl2BackendFactory_getFactory }, #endif /* 0 */ +#ifdef HAVE_SDL2 + { "sdl2", SDL2BackendFactory::getFactory }, +#endif { "null", NullBackendFactory::getFactory }, #ifdef HAVE_WAVE diff --git a/Alc/backends/sdl2.cpp b/Alc/backends/sdl2.cpp index c918b57c..e1234c1b 100644 --- a/Alc/backends/sdl2.cpp +++ b/Alc/backends/sdl2.cpp @@ -20,6 +20,8 @@ #include "config.h" +#include "backends/sdl2.h" + #include #include @@ -30,8 +32,6 @@ #include "threads.h" #include "compat.h" -#include "backends/base.h" - #ifdef _WIN32 #define DEVNAME_PREFIX "OpenAL Soft on " @@ -214,51 +214,28 @@ static void ALCsdl2Backend_unlock(ALCsdl2Backend *self) } -struct ALCsdl2BackendFactory final : public ALCbackendFactory { - ALCsdl2BackendFactory() noexcept; -}; - -ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void); - -static ALCboolean ALCsdl2BackendFactory_init(ALCsdl2BackendFactory *self); -static void ALCsdl2BackendFactory_deinit(ALCsdl2BackendFactory *self); -static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory *self, ALCbackend_Type type); -static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory *self, enum DevProbe type, std::string *outnames); -static ALCbackend* ALCsdl2BackendFactory_createBackend(ALCsdl2BackendFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsdl2BackendFactory); - - -ALCsdl2BackendFactory::ALCsdl2BackendFactory() noexcept - : ALCbackendFactory{GET_VTABLE2(ALCsdl2BackendFactory, ALCbackendFactory)} -{ } - -ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void) +BackendFactory &SDL2BackendFactory::getFactory() { - static ALCsdl2BackendFactory factory{}; - return STATIC_CAST(ALCbackendFactory, &factory); + static SDL2BackendFactory factory{}; + return factory; } - -static ALCboolean ALCsdl2BackendFactory_init(ALCsdl2BackendFactory* UNUSED(self)) +bool SDL2BackendFactory::init() { - if(SDL_InitSubSystem(SDL_INIT_AUDIO) == 0) - return AL_TRUE; - return ALC_FALSE; + return (SDL_InitSubSystem(SDL_INIT_AUDIO) == 0); } -static void ALCsdl2BackendFactory_deinit(ALCsdl2BackendFactory* UNUSED(self)) +void SDL2BackendFactory::deinit() { SDL_QuitSubSystem(SDL_INIT_AUDIO); } -static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory* UNUSED(self), ALCbackend_Type type) +bool SDL2BackendFactory::querySupport(ALCbackend_Type type) { - if(type == ALCbackend_Playback) - return ALC_TRUE; - return ALC_FALSE; + return (type == ALCbackend_Playback); } -static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) +void SDL2BackendFactory::probe(enum DevProbe type, std::string *outnames) { if(type != ALL_DEVICE_PROBE) return; @@ -276,7 +253,7 @@ static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory* UNUSED(self), enu } } -static ALCbackend* ALCsdl2BackendFactory_createBackend(ALCsdl2BackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +ALCbackend *SDL2BackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) { diff --git a/Alc/backends/sdl2.h b/Alc/backends/sdl2.h new file mode 100644 index 00000000..7f383447 --- /dev/null +++ b/Alc/backends/sdl2.h @@ -0,0 +1,20 @@ +#ifndef BACKENDS_SDL2_H +#define BACKENDS_SDL2_H + +#include "backends/base.h" + +struct SDL2BackendFactory final : public BackendFactory { +public: + bool init() override; + void deinit() override; + + bool querySupport(ALCbackend_Type type) override; + + void probe(enum DevProbe type, std::string *outnames) override; + + ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_SDL2_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index d487d6d3..67f3ba82 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1253,7 +1253,7 @@ IF(SDL2_FOUND) OPTION(ALSOFT_BACKEND_SDL2 "Enable SDL2 backend" OFF) IF(ALSOFT_BACKEND_SDL2) SET(HAVE_SDL2 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/sdl2.cpp) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/sdl2.cpp Alc/backends/sdl2.h) SET(BACKENDS "${BACKENDS} SDL2,") SET(EXTRA_LIBS ${SDL2_LIBRARY} ${EXTRA_LIBS}) SET(INC_PATHS ${INC_PATHS} ${SDL2_INCLUDE_DIR}) -- cgit v1.2.3 From 271cfcf8e31d06dca259a436251b70f5ffa882be Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 22:23:29 -0800 Subject: Convert the Solaris backend factory --- Alc/alc.cpp | 8 ++++++-- Alc/backends/solaris.cpp | 45 +++++++++++---------------------------------- Alc/backends/solaris.h | 20 ++++++++++++++++++++ CMakeLists.txt | 2 +- 4 files changed, 38 insertions(+), 37 deletions(-) create mode 100644 Alc/backends/solaris.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 63f60e80..89385888 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -77,6 +77,9 @@ #ifdef HAVE_OPENSL #include "backends/opensl.h" #endif +#ifdef HAVE_SOLARIS +#include "backends/solaris.h" +#endif #ifdef HAVE_SDL2 #include "backends/sdl2.h" #endif @@ -114,13 +117,14 @@ struct BackendInfo BackendList[] = { #ifdef HAVE_OPENSL { "opensl", OSLBackendFactory::getFactory }, #endif +#ifdef HAVE_SOLARIS + { "solaris", SolarisBackendFactory::getFactory }, +#endif #if 0 - { "solaris", ALCsolarisBackendFactory_getFactory }, { "sndio", SndioBackendFactory_getFactory }, { "oss", ALCossBackendFactory_getFactory }, { "qsa", ALCqsaBackendFactory_getFactory }, - { "wasapi", ALCwasapiBackendFactory_getFactory }, { "dsound", ALCdsoundBackendFactory_getFactory }, { "winmm", ALCwinmmBackendFactory_getFactory }, { "port", ALCportBackendFactory_getFactory }, diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index 20dda617..029ef1a5 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -20,6 +20,8 @@ #include "config.h" +#include "backends/solaris.h" + #include #include #include @@ -38,8 +40,6 @@ #include "threads.h" #include "compat.h" -#include "backends/base.h" - #include @@ -293,45 +293,22 @@ static void ALCsolarisBackend_stop(ALCsolarisBackend *self) } -struct ALCsolarisBackendFactory final : public ALCbackendFactory { - ALCsolarisBackendFactory() noexcept; -}; - -ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void); - -static ALCboolean ALCsolarisBackendFactory_init(ALCsolarisBackendFactory *self); -static DECLARE_FORWARD(ALCsolarisBackendFactory, ALCbackendFactory, void, deinit) -static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory *self, ALCbackend_Type type); -static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory *self, enum DevProbe type, std::string *outnames); -static ALCbackend* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsolarisBackendFactory); - - -ALCsolarisBackendFactory::ALCsolarisBackendFactory() noexcept - : ALCbackendFactory{GET_VTABLE2(ALCsolarisBackendFactory, ALCbackendFactory)} -{ } - -ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void) +BackendFactory &SolarisBackendFactory::getFactory() { - static ALCsolarisBackendFactory factory{}; - return STATIC_CAST(ALCbackendFactory, &factory); + static SolarisBackendFactory factory{}; + return factory; } - -static ALCboolean ALCsolarisBackendFactory_init(ALCsolarisBackendFactory* UNUSED(self)) +bool SolarisBackendFactory::init() { ConfigValueStr(nullptr, "solaris", "device", &solaris_driver); - return ALC_TRUE; + return true; } -static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - return ALC_TRUE; - return ALC_FALSE; -} +bool SolarisBackendFactory::querySupport(ALCbackend_Type type) +{ return (type == ALCbackend_Playback); } -static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) +void SolarisBackendFactory::probe(enum DevProbe type, std::string *outnames) { switch(type) { @@ -350,7 +327,7 @@ static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory* UNUSED(self } } -ALCbackend* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +ALCbackend *SolarisBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) { diff --git a/Alc/backends/solaris.h b/Alc/backends/solaris.h new file mode 100644 index 00000000..dcb34570 --- /dev/null +++ b/Alc/backends/solaris.h @@ -0,0 +1,20 @@ +#ifndef BACKENDS_SOLARIS_H +#define BACKENDS_SOLARIS_H + +#include "backends/base.h" + +struct SolarisBackendFactory final : public BackendFactory { +public: + bool init() override; + /*void deinit() override;*/ + + bool querySupport(ALCbackend_Type type) override; + + void probe(enum DevProbe type, std::string *outnames) override; + + ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_SOLARIS_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 67f3ba82..551d30fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1040,7 +1040,7 @@ IF(AUDIOIO_FOUND) IF(ALSOFT_BACKEND_SOLARIS) SET(HAVE_SOLARIS 1) SET(BACKENDS "${BACKENDS} Solaris,") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/solaris.cpp) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/solaris.cpp Alc/backends/solaris.h) SET(INC_PATHS ${INC_PATHS} ${AUDIOIO_INCLUDE_DIRS}) ENDIF() ENDIF() -- cgit v1.2.3 From 7884cec02b62605cbc046f2311bf3f3b35e20777 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 22:36:49 -0800 Subject: Convert the SndIO backend factory --- Alc/alc.cpp | 7 ++++++- Alc/backends/sndio.cpp | 46 +++++++++++----------------------------------- Alc/backends/sndio.h | 20 ++++++++++++++++++++ CMakeLists.txt | 2 +- 4 files changed, 38 insertions(+), 37 deletions(-) create mode 100644 Alc/backends/sndio.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 89385888..8a16eb28 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -80,6 +80,9 @@ #ifdef HAVE_SOLARIS #include "backends/solaris.h" #endif +#ifdef HAVE_SNDIO +#include "backends/sndio.h" +#endif #ifdef HAVE_SDL2 #include "backends/sdl2.h" #endif @@ -120,9 +123,11 @@ struct BackendInfo BackendList[] = { #ifdef HAVE_SOLARIS { "solaris", SolarisBackendFactory::getFactory }, #endif +#ifdef HAVE_SNDIO + { "sndio", SndIOBackendFactory::getFactory }, +#endif #if 0 - { "sndio", SndioBackendFactory_getFactory }, { "oss", ALCossBackendFactory_getFactory }, { "qsa", ALCqsaBackendFactory_getFactory }, { "dsound", ALCdsoundBackendFactory_getFactory }, diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index f1e678cf..691bdcde 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -20,6 +20,8 @@ #include "config.h" +#include "backends/sndio.h" + #include #include #include @@ -29,8 +31,6 @@ #include "threads.h" #include "ringbuffer.h" -#include "backends/base.h" - #include @@ -537,43 +537,19 @@ static ALCuint SndioCapture_availableSamples(SndioCapture *self) } -struct SndioBackendFactory final : public ALCbackendFactory { - SndioBackendFactory() noexcept; -}; - -ALCbackendFactory *SndioBackendFactory_getFactory(void); - -static ALCboolean SndioBackendFactory_init(SndioBackendFactory *self); -static DECLARE_FORWARD(SndioBackendFactory, ALCbackendFactory, void, deinit) -static ALCboolean SndioBackendFactory_querySupport(SndioBackendFactory *self, ALCbackend_Type type); -static void SndioBackendFactory_probe(SndioBackendFactory *self, enum DevProbe type, std::string *outnames); -static ALCbackend* SndioBackendFactory_createBackend(SndioBackendFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(SndioBackendFactory); - -SndioBackendFactory::SndioBackendFactory() noexcept - : ALCbackendFactory{GET_VTABLE2(SndioBackendFactory, ALCbackendFactory)} -{ } - -ALCbackendFactory *SndioBackendFactory_getFactory(void) +BackendFactory &SndIOBackendFactory::getFactory() { - static SndioBackendFactory factory{}; - return STATIC_CAST(ALCbackendFactory, &factory); + static SndIOBackendFactory factory{}; + return factory; } -static ALCboolean SndioBackendFactory_init(SndioBackendFactory* UNUSED(self)) -{ - /* No dynamic loading */ - return ALC_TRUE; -} +bool SndIOBackendFactory::init() +{ return true; } -static ALCboolean SndioBackendFactory_querySupport(SndioBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} +bool SndIOBackendFactory::querySupport(ALCbackend_Type type) +{ return (type == ALCbackend_Playback || type == ALCbackend_Capture); } -static void SndioBackendFactory_probe(SndioBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) +void SndIOBackendFactory::probe(enum DevProbe type, std::string *outnames) { switch(type) { @@ -585,7 +561,7 @@ static void SndioBackendFactory_probe(SndioBackendFactory* UNUSED(self), enum De } } -static ALCbackend* SndioBackendFactory_createBackend(SndioBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +ALCbackend *SndIOBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) { diff --git a/Alc/backends/sndio.h b/Alc/backends/sndio.h new file mode 100644 index 00000000..38cd2767 --- /dev/null +++ b/Alc/backends/sndio.h @@ -0,0 +1,20 @@ +#ifndef BACKENDS_SNDIO_H +#define BACKENDS_SNDIO_H + +#include "backends/base.h" + +struct SndIOBackendFactory final : public BackendFactory { +public: + bool init() override; + /*void deinit() override;*/ + + bool querySupport(ALCbackend_Type type) override; + + void probe(enum DevProbe type, std::string *outnames) override; + + ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_SNDIO_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 551d30fe..6355752d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1056,7 +1056,7 @@ IF(SOUNDIO_FOUND) IF(ALSOFT_BACKEND_SNDIO) SET(HAVE_SNDIO 1) SET(BACKENDS "${BACKENDS} SndIO (linked),") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/sndio.cpp) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/sndio.cpp Alc/backends/sndio.h) SET(EXTRA_LIBS ${SOUNDIO_LIBRARIES} ${EXTRA_LIBS}) SET(INC_PATHS ${INC_PATHS} ${SOUNDIO_INCLUDE_DIRS}) ENDIF() -- cgit v1.2.3 From c78b42fb4e49a431e8c0b7b7ff8da0102e1aeb5d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 23:02:26 -0800 Subject: Convert the OSS backend factory --- Alc/alc.cpp | 7 ++- Alc/backends/oss.cpp | 131 +++++++++++++++++++++------------------------------ Alc/backends/oss.h | 20 ++++++++ CMakeLists.txt | 2 +- 4 files changed, 81 insertions(+), 79 deletions(-) create mode 100644 Alc/backends/oss.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 8a16eb28..78fa0d9c 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -83,6 +83,9 @@ #ifdef HAVE_SNDIO #include "backends/sndio.h" #endif +#ifdef HAVE_OSS +#include "backends/oss.h" +#endif #ifdef HAVE_SDL2 #include "backends/sdl2.h" #endif @@ -126,9 +129,11 @@ struct BackendInfo BackendList[] = { #ifdef HAVE_SNDIO { "sndio", SndIOBackendFactory::getFactory }, #endif +#ifdef HAVE_OSS + { "oss", OSSBackendFactory::getFactory }, +#endif #if 0 - { "oss", ALCossBackendFactory_getFactory }, { "qsa", ALCqsaBackendFactory_getFactory }, { "dsound", ALCdsoundBackendFactory_getFactory }, { "winmm", ALCwinmmBackendFactory_getFactory }, diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 9baa7346..cf95bcfe 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -20,6 +20,8 @@ #include "config.h" +#include "backends/oss.h" + #include #include #include @@ -45,8 +47,6 @@ #include "ringbuffer.h" #include "compat.h" -#include "backends/base.h" - #include /* @@ -239,7 +239,6 @@ int log2i(ALCuint x) return y; } -} // namespace struct ALCplaybackOSS final : public ALCbackend { int fd{-1}; @@ -250,31 +249,31 @@ struct ALCplaybackOSS final : public ALCbackend { std::thread thread; }; -static int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self); - -static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device); -static void ALCplaybackOSS_Destruct(ALCplaybackOSS *self); -static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name); -static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self); -static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self); -static void ALCplaybackOSS_stop(ALCplaybackOSS *self); -static DECLARE_FORWARD2(ALCplaybackOSS, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, unlock) +int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self); + +void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device); +void ALCplaybackOSS_Destruct(ALCplaybackOSS *self); +ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name); +ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self); +ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self); +void ALCplaybackOSS_stop(ALCplaybackOSS *self); +DECLARE_FORWARD2(ALCplaybackOSS, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) +DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ALCuint, availableSamples) +DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ClockLatency, getClockLatency) +DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, lock) +DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCplaybackOSS) DEFINE_ALCBACKEND_VTABLE(ALCplaybackOSS); -static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device) +void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device) { new (self) ALCplaybackOSS{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCplaybackOSS, ALCbackend, self); } -static void ALCplaybackOSS_Destruct(ALCplaybackOSS *self) +void ALCplaybackOSS_Destruct(ALCplaybackOSS *self) { if(self->fd != -1) close(self->fd); @@ -285,7 +284,7 @@ static void ALCplaybackOSS_Destruct(ALCplaybackOSS *self) } -static int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self) +int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; struct timeval timeout; @@ -353,7 +352,7 @@ static int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self) } -static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) +ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -387,7 +386,7 @@ static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) return ALC_NO_ERROR; } -static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) +ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; int numFragmentsLogSize; @@ -469,7 +468,7 @@ static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) return ALC_TRUE; } -static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self) +ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -490,7 +489,7 @@ static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self) return ALC_FALSE; } -static void ALCplaybackOSS_stop(ALCplaybackOSS *self) +void ALCplaybackOSS_stop(ALCplaybackOSS *self) { if(self->killNow.exchange(AL_TRUE) || !self->thread.joinable()) return; @@ -512,31 +511,31 @@ struct ALCcaptureOSS final : public ALCbackend { std::thread thread; }; -static int ALCcaptureOSS_recordProc(ALCcaptureOSS *self); - -static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device); -static void ALCcaptureOSS_Destruct(ALCcaptureOSS *self); -static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name); -static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ALCboolean, reset) -static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self); -static void ALCcaptureOSS_stop(ALCcaptureOSS *self); -static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples); -static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self); -static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, unlock) +int ALCcaptureOSS_recordProc(ALCcaptureOSS *self); + +void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device); +void ALCcaptureOSS_Destruct(ALCcaptureOSS *self); +ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name); +DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ALCboolean, reset) +ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self); +void ALCcaptureOSS_stop(ALCcaptureOSS *self); +ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples); +ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self); +DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ClockLatency, getClockLatency) +DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, lock) +DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCcaptureOSS) DEFINE_ALCBACKEND_VTABLE(ALCcaptureOSS); -static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device) +void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device) { new (self) ALCcaptureOSS{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCcaptureOSS, ALCbackend, self); } -static void ALCcaptureOSS_Destruct(ALCcaptureOSS *self) +void ALCcaptureOSS_Destruct(ALCcaptureOSS *self) { if(self->fd != -1) close(self->fd); @@ -549,7 +548,7 @@ static void ALCcaptureOSS_Destruct(ALCcaptureOSS *self) } -static int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) +int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; struct timeval timeout; @@ -606,7 +605,7 @@ static int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) } -static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) +ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -719,7 +718,7 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) return ALC_NO_ERROR; } -static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self) +ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self) { try { self->killNow.store(AL_FALSE); @@ -734,7 +733,7 @@ static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self) return ALC_FALSE; } -static void ALCcaptureOSS_stop(ALCcaptureOSS *self) +void ALCcaptureOSS_stop(ALCcaptureOSS *self) { if(self->killNow.exchange(AL_TRUE) || !self->thread.joinable()) return; @@ -745,66 +744,44 @@ static void ALCcaptureOSS_stop(ALCcaptureOSS *self) ERR("Error resetting device: %s\n", strerror(errno)); } -static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples) +ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples) { ll_ringbuffer_read(self->ring, static_cast(buffer), samples); return ALC_NO_ERROR; } -static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self) +ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self) { return ll_ringbuffer_read_space(self->ring); } +} // namespace -struct ALCossBackendFactory final : public ALCbackendFactory { - ALCossBackendFactory() noexcept; -}; - -ALCbackendFactory *ALCossBackendFactory_getFactory(void); - -static ALCboolean ALCossBackendFactory_init(ALCossBackendFactory *self); -static void ALCossBackendFactory_deinit(ALCossBackendFactory *self); -static ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory *self, ALCbackend_Type type); -static void ALCossBackendFactory_probe(ALCossBackendFactory *self, enum DevProbe type, std::string *outnames); -static ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCossBackendFactory); - - -ALCossBackendFactory::ALCossBackendFactory() noexcept - : ALCbackendFactory{GET_VTABLE2(ALCossBackendFactory, ALCbackendFactory)} -{ } -ALCbackendFactory *ALCossBackendFactory_getFactory(void) +BackendFactory &OSSBackendFactory::getFactory() { - static ALCossBackendFactory factory{}; - return STATIC_CAST(ALCbackendFactory, &factory); + static OSSBackendFactory factory{}; + return factory; } - -ALCboolean ALCossBackendFactory_init(ALCossBackendFactory* UNUSED(self)) +bool OSSBackendFactory::init() { ConfigValueStr(nullptr, "oss", "device", &DefaultPlayback); ConfigValueStr(nullptr, "oss", "capture", &DefaultCapture); - return ALC_TRUE; + return true; } -void ALCossBackendFactory_deinit(ALCossBackendFactory* UNUSED(self)) +void OSSBackendFactory::deinit() { PlaybackDevices.clear(); CaptureDevices.clear(); } +bool OSSBackendFactory::querySupport(ALCbackend_Type type) +{ return (type == ALCbackend_Playback || type == ALCbackend_Capture); } -ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} - -void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) +void OSSBackendFactory::probe(enum DevProbe type, std::string *outnames) { auto add_device = [outnames](const DevMap &entry) -> void { @@ -834,7 +811,7 @@ void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProb } } -ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +ALCbackend *OSSBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) { diff --git a/Alc/backends/oss.h b/Alc/backends/oss.h new file mode 100644 index 00000000..c3865d84 --- /dev/null +++ b/Alc/backends/oss.h @@ -0,0 +1,20 @@ +#ifndef BACKENDS_OSS_H +#define BACKENDS_OSS_H + +#include "backends/base.h" + +struct OSSBackendFactory final : public BackendFactory { +public: + bool init() override; + void deinit() override; + + bool querySupport(ALCbackend_Type type) override; + + void probe(enum DevProbe type, std::string *outnames) override; + + ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_OSS_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 6355752d..d4071a87 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1021,7 +1021,7 @@ IF(OSS_FOUND) IF(ALSOFT_BACKEND_OSS) SET(HAVE_OSS 1) SET(BACKENDS "${BACKENDS} OSS,") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/oss.cpp) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/oss.cpp Alc/backends/oss.h) IF(OSS_LIBRARIES) SET(EXTRA_LIBS ${OSS_LIBRARIES} ${EXTRA_LIBS}) ENDIF() -- cgit v1.2.3 From 5dc1956e18007fe910039487ef5d847bbb72ede0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 23:10:06 -0800 Subject: Convert the QSA backend factory --- Alc/alc.cpp | 7 ++++++- Alc/backends/qsa.cpp | 48 +++++++++++++----------------------------------- Alc/backends/qsa.h | 20 ++++++++++++++++++++ CMakeLists.txt | 2 +- 4 files changed, 40 insertions(+), 37 deletions(-) create mode 100644 Alc/backends/qsa.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 78fa0d9c..00442458 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -86,6 +86,9 @@ #ifdef HAVE_OSS #include "backends/oss.h" #endif +#ifdef HAVE_QSA +#include "backends/qsa.h" +#endif #ifdef HAVE_SDL2 #include "backends/sdl2.h" #endif @@ -132,9 +135,11 @@ struct BackendInfo BackendList[] = { #ifdef HAVE_OSS { "oss", OSSBackendFactory::getFactory }, #endif +#ifdef HAVE_QSA + { "qsa", QSABackendFactory::getFactory }, +#endif #if 0 - { "qsa", ALCqsaBackendFactory_getFactory }, { "dsound", ALCdsoundBackendFactory_getFactory }, { "winmm", ALCwinmmBackendFactory_getFactory }, { "port", ALCportBackendFactory_getFactory }, diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index 3a99d71e..da4e6b64 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -20,6 +20,8 @@ #include "config.h" +#include "backends/qsa.h" + #include #include #include @@ -33,8 +35,6 @@ #include "alu.h" #include "threads.h" -#include "backends/base.h" - namespace { @@ -163,8 +163,6 @@ void deviceList(int type, vector_DevMap *devmap) } } -} // namespace - /* Wrappers to use an old-style backend with the new interface. */ struct PlaybackWrapper final : public ALCbackend { @@ -991,29 +989,13 @@ static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self) return qsa_available_samples(self); } +} // namespace -struct ALCqsaBackendFactory final : public ALCbackendFactory { - ALCqsaBackendFactory() noexcept; -}; - -static ALCboolean ALCqsaBackendFactory_init(ALCqsaBackendFactory* UNUSED(self)); -static void ALCqsaBackendFactory_deinit(ALCqsaBackendFactory* UNUSED(self)); -static ALCboolean ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory* UNUSED(self), ALCbackend_Type type); -static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames); -static ALCbackend* ALCqsaBackendFactory_createBackend(ALCqsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCqsaBackendFactory); - -ALCqsaBackendFactory::ALCqsaBackendFactory() noexcept - : ALCbackendFactory{GET_VTABLE2(ALCqsaBackendFactory, ALCbackendFactory)} -{ } +bool QSABackendFactory::init() +{ return true; } -static ALCboolean ALCqsaBackendFactory_init(ALCqsaBackendFactory* UNUSED(self)) -{ - return ALC_TRUE; -} - -static void ALCqsaBackendFactory_deinit(ALCqsaBackendFactory* UNUSED(self)) +void QSABackendFactory::deinit() { #define FREE_NAME(iter) free((iter)->name) VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME); @@ -1024,14 +1006,10 @@ static void ALCqsaBackendFactory_deinit(ALCqsaBackendFactory* UNUSED(self)) #undef FREE_NAME } -static ALCboolean ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} +bool QSABackendFactory::querySupport(ALCbackend_Type type) +{ return (type == ALCbackend_Playback || type == ALCbackend_Capture); } -static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) +void QSABackendFactory::probe(enum DevProbe type, std::string *outnames) { switch (type) { @@ -1053,7 +1031,7 @@ static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum } } -static ALCbackend* ALCqsaBackendFactory_createBackend(ALCqsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +ALCbackend *QSABackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) { @@ -1073,8 +1051,8 @@ static ALCbackend* ALCqsaBackendFactory_createBackend(ALCqsaBackendFactory* UNUS return NULL; } -ALCbackendFactory *ALCqsaBackendFactory_getFactory(void) +BackendFactory &QSABackendFactory::getFactory() { - static ALCqsaBackendFactory factory{}; - return STATIC_CAST(ALCbackendFactory, &factory); + static QSABackendFactory factory{}; + return factory; } diff --git a/Alc/backends/qsa.h b/Alc/backends/qsa.h new file mode 100644 index 00000000..c4941392 --- /dev/null +++ b/Alc/backends/qsa.h @@ -0,0 +1,20 @@ +#ifndef BACKENDS_QSA_H +#define BACKENDS_QSA_H + +#include "backends/base.h" + +struct QSABackendFactory final : public BackendFactory { +public: + bool init() override; + void deinit() override; + + bool querySupport(ALCbackend_Type type) override; + + void probe(enum DevProbe type, std::string *outnames) override; + + ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_QSA_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index d4071a87..5d30bd6c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1073,7 +1073,7 @@ IF(QSA_FOUND) IF(ALSOFT_BACKEND_QSA) SET(HAVE_QSA 1) SET(BACKENDS "${BACKENDS} QSA (linked),") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/qsa.cpp) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/qsa.cpp Alc/backends/qsa.h) SET(EXTRA_LIBS ${QSA_LIBRARIES} ${EXTRA_LIBS}) SET(INC_PATHS ${INC_PATHS} ${QSA_INCLUDE_DIRS}) ENDIF() -- cgit v1.2.3 From 2ca6119e0eb6253a5a025739f99db2031dca8c2a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 23:32:28 -0800 Subject: Convert the DSound backend factory --- Alc/alc.cpp | 7 ++- Alc/backends/dsound.cpp | 154 ++++++++++++++++++++---------------------------- Alc/backends/dsound.h | 20 +++++++ CMakeLists.txt | 2 +- 4 files changed, 91 insertions(+), 92 deletions(-) create mode 100644 Alc/backends/dsound.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 00442458..c86d7260 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -89,6 +89,9 @@ #ifdef HAVE_QSA #include "backends/qsa.h" #endif +#ifdef HAVE_DSOUND +#include "backends/dsound.h" +#endif #ifdef HAVE_SDL2 #include "backends/sdl2.h" #endif @@ -138,9 +141,11 @@ struct BackendInfo BackendList[] = { #ifdef HAVE_QSA { "qsa", QSABackendFactory::getFactory }, #endif +#ifdef HAVE_DSOUND + { "dsound", DSoundBackendFactory::getFactory }, +#endif #if 0 - { "dsound", ALCdsoundBackendFactory_getFactory }, { "winmm", ALCwinmmBackendFactory_getFactory }, { "port", ALCportBackendFactory_getFactory }, #endif /* 0 */ diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 478bdf9a..34d7dc23 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -20,11 +20,12 @@ #include "config.h" +#include "backends/dsound.h" + #include #include #include -#include #include #include #ifndef _WAVEFORMATEXTENSIBLE_ @@ -43,7 +44,10 @@ #include "ringbuffer.h" #include "compat.h" -#include "backends/base.h" +/* MinGW-w64 needs this for some unknown reason now. */ +typedef const WAVEFORMATEX *LPCWAVEFORMATEX; +#include + #ifndef DSSPEAKER_5POINT1 # define DSSPEAKER_5POINT1 0x00000006 @@ -79,11 +83,11 @@ namespace { #ifdef HAVE_DYNLOAD -static void *ds_handle; -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); +void *ds_handle; +HRESULT (WINAPI *pDirectSoundCreate)(const GUID *pcGuidDevice, IDirectSound **ppDS, IUnknown *pUnkOuter); +HRESULT (WINAPI *pDirectSoundEnumerateW)(LPDSENUMCALLBACKW pDSEnumCallback, void *pContext); +HRESULT (WINAPI *pDirectSoundCaptureCreate)(const GUID *pcGuidDevice, IDirectSoundCapture **ppDSC, IUnknown *pUnkOuter); +HRESULT (WINAPI *pDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW pDSEnumCallback, void *pContext); #ifndef IN_IDE_PARSER #define DirectSoundCreate pDirectSoundCreate @@ -94,7 +98,7 @@ static HRESULT (WINAPI *pDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW pDSEnum #endif -static ALCboolean DSoundLoad(void) +bool DSoundLoad(void) { #ifdef HAVE_DYNLOAD if(!ds_handle) @@ -103,7 +107,7 @@ static ALCboolean DSoundLoad(void) if(!ds_handle) { ERR("Failed to load dsound.dll\n"); - return ALC_FALSE; + return false; } #define LOAD_FUNC(f) do { \ @@ -112,7 +116,7 @@ static ALCboolean DSoundLoad(void) { \ CloseLib(ds_handle); \ ds_handle = nullptr; \ - return ALC_FALSE; \ + return false; \ } \ } while(0) LOAD_FUNC(DirectSoundCreate); @@ -122,7 +126,7 @@ static ALCboolean DSoundLoad(void) #undef LOAD_FUNC } #endif - return ALC_TRUE; + return true; } @@ -179,8 +183,6 @@ BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR* UNUS return TRUE; } -} // namespace - struct ALCdsoundPlayback final : public ALCbackend { IDirectSound *DS{nullptr}; @@ -193,32 +195,32 @@ struct ALCdsoundPlayback final : public ALCbackend { std::thread thread; }; -static int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self); - -static void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device); -static void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self); -static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *name); -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, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, unlock) +int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self); + +void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device); +void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self); +ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *name); +ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self); +ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self); +void ALCdsoundPlayback_stop(ALCdsoundPlayback *self); +DECLARE_FORWARD2(ALCdsoundPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, ALCuint, availableSamples) +DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, ClockLatency, getClockLatency) +DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, lock) +DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCdsoundPlayback) DEFINE_ALCBACKEND_VTABLE(ALCdsoundPlayback); -static void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device) +void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device) { new (self) ALCdsoundPlayback{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCdsoundPlayback, ALCbackend, self); } -static void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self) +void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self) { if(self->Notifies) self->Notifies->Release(); @@ -242,7 +244,7 @@ static void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self) } -FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) +FORCE_ALIGN int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -348,7 +350,7 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) return 0; } -static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *deviceName) +ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *deviceName) { ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; @@ -402,7 +404,7 @@ static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *de return ALC_NO_ERROR; } -static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) +ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -623,7 +625,7 @@ retry_open: return ALC_TRUE; } -static ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self) +ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self) { try { self->killNow.store(AL_FALSE, std::memory_order_release); @@ -638,7 +640,7 @@ static ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self) return ALC_FALSE; } -static void ALCdsoundPlayback_stop(ALCdsoundPlayback *self) +void ALCdsoundPlayback_stop(ALCdsoundPlayback *self) { if(self->killNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->thread.joinable()) return; @@ -658,29 +660,28 @@ struct ALCdsoundCapture final : public ALCbackend { ll_ringbuffer_t *Ring{nullptr}; }; -static void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device); -static void ALCdsoundCapture_Destruct(ALCdsoundCapture *self); -static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *name); -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, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, void, unlock) +void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device); +void ALCdsoundCapture_Destruct(ALCdsoundCapture *self); +ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *name); +DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, ALCboolean, reset) +ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self); +void ALCdsoundCapture_stop(ALCdsoundCapture *self); +ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint samples); +ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self); +DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, ClockLatency, getClockLatency) +DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, void, lock) +DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCdsoundCapture) - DEFINE_ALCBACKEND_VTABLE(ALCdsoundCapture); -static void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device) +void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device) { new (self) ALCdsoundCapture{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCdsoundCapture, ALCbackend, self); } -static void ALCdsoundCapture_Destruct(ALCdsoundCapture *self) +void ALCdsoundCapture_Destruct(ALCdsoundCapture *self) { ll_ringbuffer_free(self->Ring); self->Ring = nullptr; @@ -701,7 +702,7 @@ static void ALCdsoundCapture_Destruct(ALCdsoundCapture *self) } -static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) +ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -869,7 +870,7 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi return ALC_NO_ERROR; } -static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self) +ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self) { HRESULT hr{self->DSCbuffer->Start(DSCBSTART_LOOPING)}; if(FAILED(hr)) @@ -883,7 +884,7 @@ static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self) return ALC_TRUE; } -static void ALCdsoundCapture_stop(ALCdsoundCapture *self) +void ALCdsoundCapture_stop(ALCdsoundCapture *self) { HRESULT hr{self->DSCbuffer->Stop()}; if(FAILED(hr)) @@ -894,13 +895,13 @@ static void ALCdsoundCapture_stop(ALCdsoundCapture *self) } } -static ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint samples) { ll_ringbuffer_read(self->Ring, reinterpret_cast(buffer), samples); return ALC_NO_ERROR; } -static ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) +ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -942,42 +943,19 @@ static ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) return ll_ringbuffer_read_space(self->Ring); } - -struct ALCdsoundBackendFactory final : public ALCbackendFactory { - ALCdsoundBackendFactory() noexcept; -}; -#define ALCDSOUNDBACKENDFACTORY_INITIALIZER GET_VTABLE2(ALCdsoundBackendFactory, ALCbackendFactory) - -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, std::string *outnames); -static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCdsoundBackendFactory); - - -ALCdsoundBackendFactory::ALCdsoundBackendFactory() noexcept - : ALCbackendFactory{ALCDSOUNDBACKENDFACTORY_INITIALIZER} -{ } +} // namespace -ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void) +BackendFactory &DSoundBackendFactory::getFactory() { - static ALCdsoundBackendFactory factory{}; - return STATIC_CAST(ALCbackendFactory, &factory); + static DSoundBackendFactory factory{}; + return factory; } +bool DSoundBackendFactory::init() +{ return DSoundLoad(); } -static ALCboolean ALCdsoundBackendFactory_init(ALCdsoundBackendFactory* UNUSED(self)) -{ - if(!DSoundLoad()) - return ALC_FALSE; - return ALC_TRUE; -} - -static void ALCdsoundBackendFactory_deinit(ALCdsoundBackendFactory* UNUSED(self)) +void DSoundBackendFactory::deinit() { PlaybackDevices.clear(); CaptureDevices.clear(); @@ -989,14 +967,10 @@ static void ALCdsoundBackendFactory_deinit(ALCdsoundBackendFactory* UNUSED(self) #endif } -static ALCboolean ALCdsoundBackendFactory_querySupport(ALCdsoundBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} +bool DSoundBackendFactory::querySupport(ALCbackend_Type type) +{ return (type == ALCbackend_Playback || type == ALCbackend_Capture); } -static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) +void DSoundBackendFactory::probe(enum DevProbe type, std::string *outnames) { auto add_device = [outnames](const DevMap &entry) -> void { @@ -1031,7 +1005,7 @@ static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory* UNUSED(self), CoUninitialize(); } -static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +ALCbackend *DSoundBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) { diff --git a/Alc/backends/dsound.h b/Alc/backends/dsound.h new file mode 100644 index 00000000..ebaa9c64 --- /dev/null +++ b/Alc/backends/dsound.h @@ -0,0 +1,20 @@ +#ifndef BACKENDS_DSOUND_H +#define BACKENDS_DSOUND_H + +#include "backends/base.h" + +struct DSoundBackendFactory final : public BackendFactory { +public: + bool init() override; + void deinit() override; + + bool querySupport(ALCbackend_Type type) override; + + void probe(enum DevProbe type, std::string *outnames) override; + + ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_DSOUND_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d30bd6c..94df6473 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1112,7 +1112,7 @@ IF(HAVE_WINDOWS_H) IF(ALSOFT_BACKEND_DSOUND) SET(HAVE_DSOUND 1) SET(BACKENDS "${BACKENDS} DirectSound${IS_LINKED},") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/dsound.cpp) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/dsound.cpp Alc/backends/dsound.h) ADD_BACKEND_LIBS(${DSOUND_LIBRARIES}) SET(INC_PATHS ${INC_PATHS} ${DSOUND_INCLUDE_DIRS}) ENDIF() -- cgit v1.2.3 From 78eb68a89ff3692924de0df53559b1d9ac5c4cb3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 23:41:09 -0800 Subject: Convert the WinMM backend factory --- Alc/alc.cpp | 8 ++- Alc/backends/winmm.cpp | 151 +++++++++++++++++++++---------------------------- Alc/backends/winmm.h | 20 +++++++ CMakeLists.txt | 2 +- 4 files changed, 91 insertions(+), 90 deletions(-) create mode 100644 Alc/backends/winmm.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index c86d7260..2a443b74 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -92,6 +92,9 @@ #ifdef HAVE_DSOUND #include "backends/dsound.h" #endif +#ifdef HAVE_WINMM +#include "backends/winmm.h" +#endif #ifdef HAVE_SDL2 #include "backends/sdl2.h" #endif @@ -144,9 +147,10 @@ struct BackendInfo BackendList[] = { #ifdef HAVE_DSOUND { "dsound", DSoundBackendFactory::getFactory }, #endif - +#ifdef HAVE_WINMM + { "winmm", WinMMBackendFactory::getFactory }, +#endif #if 0 - { "winmm", ALCwinmmBackendFactory_getFactory }, { "port", ALCportBackendFactory_getFactory }, #endif /* 0 */ #ifdef HAVE_SDL2 diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 0c625e27..0fb85f66 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -20,6 +20,8 @@ #include "config.h" +#include "backends/winmm.h" + #include #include #include @@ -40,8 +42,6 @@ #include "threads.h" #include "compat.h" -#include "backends/base.h" - #ifndef WAVE_FORMAT_IEEE_FLOAT #define WAVE_FORMAT_IEEE_FLOAT 0x0003 #endif @@ -119,7 +119,6 @@ void ProbeCaptureDevices(void) } } -} // namespace struct ALCwinmmPlayback final : public ALCbackend { std::atomic Writable{0u}; @@ -135,27 +134,27 @@ struct ALCwinmmPlayback final : public ALCbackend { std::thread thread; }; -static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device); -static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self); - -static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); -static int ALCwinmmPlayback_mixerProc(ALCwinmmPlayback *self); - -static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *name); -static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self); -static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self); -static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self); -static DECLARE_FORWARD2(ALCwinmmPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, unlock) +void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device); +void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self); + +void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); +int ALCwinmmPlayback_mixerProc(ALCwinmmPlayback *self); + +ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *name); +ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self); +ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self); +void ALCwinmmPlayback_stop(ALCwinmmPlayback *self); +DECLARE_FORWARD2(ALCwinmmPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) +DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ALCuint, availableSamples) +DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ClockLatency, getClockLatency) +DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, lock) +DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCwinmmPlayback) DEFINE_ALCBACKEND_VTABLE(ALCwinmmPlayback); -static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device) +void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device) { new (self) ALCwinmmPlayback{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); @@ -165,7 +164,7 @@ static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device std::fill(self->WaveBuffer.begin(), self->WaveBuffer.end(), WAVEHDR{}); } -static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self) +void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self) { if(self->OutHdl) waveOutClose(self->OutHdl); @@ -186,9 +185,9 @@ static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self) * Posts a message to 'ALCwinmmPlayback_mixerProc' everytime a WaveOut Buffer * is completed and returns to the application (for more data) */ -static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT UNUSED(device), UINT msg, - DWORD_PTR instance, DWORD_PTR UNUSED(param1), - DWORD_PTR UNUSED(param2)) +void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT UNUSED(device), UINT msg, + DWORD_PTR instance, DWORD_PTR UNUSED(param1), + DWORD_PTR UNUSED(param2)) { if(msg != WOM_DONE) return; @@ -198,7 +197,7 @@ static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT UNUSED(device), UINT alsem_post(&self->Sem); } -FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(ALCwinmmPlayback *self) +FORCE_ALIGN int ALCwinmmPlayback_mixerProc(ALCwinmmPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -235,7 +234,7 @@ FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(ALCwinmmPlayback *self) } -static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *deviceName) +ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *deviceName) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -291,7 +290,7 @@ retry_open: return ALC_NO_ERROR; } -static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self) +ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -361,7 +360,7 @@ static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self) return ALC_TRUE; } -static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self) +ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self) { try { std::for_each(self->WaveBuffer.begin(), self->WaveBuffer.end(), @@ -382,7 +381,7 @@ static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self) return ALC_FALSE; } -static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self) +void ALCwinmmPlayback_stop(ALCwinmmPlayback *self) { if(self->killNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->thread.joinable()) return; @@ -414,27 +413,27 @@ struct ALCwinmmCapture final : public ALCbackend { std::thread thread; }; -static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device); -static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self); - -static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); -static int ALCwinmmCapture_captureProc(ALCwinmmCapture *self); - -static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName); -static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ALCboolean, reset) -static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self); -static void ALCwinmmCapture_stop(ALCwinmmCapture *self); -static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples); -static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self); -static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, unlock) +void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device); +void ALCwinmmCapture_Destruct(ALCwinmmCapture *self); + +void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); +int ALCwinmmCapture_captureProc(ALCwinmmCapture *self); + +ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName); +DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ALCboolean, reset) +ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self); +void ALCwinmmCapture_stop(ALCwinmmCapture *self); +ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples); +ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self); +DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ClockLatency, getClockLatency) +DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, lock) +DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCwinmmCapture) DEFINE_ALCBACKEND_VTABLE(ALCwinmmCapture); -static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device) +void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device) { new (self) ALCwinmmCapture{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); @@ -444,7 +443,7 @@ static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device) std::fill(self->WaveBuffer.begin(), self->WaveBuffer.end(), WAVEHDR{}); } -static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self) +void ALCwinmmCapture_Destruct(ALCwinmmCapture *self) { // Close the Wave device if(self->InHdl) @@ -469,9 +468,9 @@ static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self) * Posts a message to 'ALCwinmmCapture_captureProc' everytime a WaveIn Buffer * is completed and returns to the application (with more data). */ -static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN UNUSED(device), UINT msg, - DWORD_PTR instance, DWORD_PTR UNUSED(param1), - DWORD_PTR UNUSED(param2)) +void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN UNUSED(device), UINT msg, + DWORD_PTR instance, DWORD_PTR UNUSED(param1), + DWORD_PTR UNUSED(param2)) { if(msg != WIM_DATA) return; @@ -481,7 +480,7 @@ static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN UNUSED(device), UINT msg alsem_post(&self->Sem); } -static int ALCwinmmCapture_captureProc(ALCwinmmCapture *self) +int ALCwinmmCapture_captureProc(ALCwinmmCapture *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -519,7 +518,7 @@ static int ALCwinmmCapture_captureProc(ALCwinmmCapture *self) } -static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName) +ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -612,7 +611,7 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *device return ALC_NO_ERROR; } -static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self) +ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self) { try { for(size_t i{0};i < self->WaveBuffer.size();++i) @@ -635,7 +634,7 @@ static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self) return ALC_FALSE; } -static void ALCwinmmCapture_stop(ALCwinmmCapture *self) +void ALCwinmmCapture_stop(ALCwinmmCapture *self) { waveInStop(self->InHdl); @@ -654,55 +653,33 @@ static void ALCwinmmCapture_stop(ALCwinmmCapture *self) self->Idx = 0; } -static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples) { ll_ringbuffer_read(self->Ring, static_cast(buffer), samples); return ALC_NO_ERROR; } -static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self) +ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self) { return (ALCuint)ll_ringbuffer_read_space(self->Ring); } - -struct ALCwinmmBackendFactory final : public ALCbackendFactory { - ALCwinmmBackendFactory() noexcept; -}; -#define ALCWINMMBACKENDFACTORY_INITIALIZER GET_VTABLE2(ALCwinmmBackendFactory, ALCbackendFactory) - -static ALCboolean ALCwinmmBackendFactory_init(ALCwinmmBackendFactory *self); -static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory *self); -static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory *self, ALCbackend_Type type); -static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory *self, enum DevProbe type, std::string *outnames); -static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory *self, ALCdevice *device, ALCbackend_Type type); - -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwinmmBackendFactory); - -ALCwinmmBackendFactory::ALCwinmmBackendFactory() noexcept - : ALCbackendFactory{ALCWINMMBACKENDFACTORY_INITIALIZER} -{ } +} // namespace -static ALCboolean ALCwinmmBackendFactory_init(ALCwinmmBackendFactory* UNUSED(self)) -{ - return ALC_TRUE; -} +bool WinMMBackendFactory::init() +{ return true; } -static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory* UNUSED(self)) +void WinMMBackendFactory::deinit() { PlaybackDevices.clear(); CaptureDevices.clear(); } -static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} +bool WinMMBackendFactory::querySupport(ALCbackend_Type type) +{ return (type == ALCbackend_Playback || type == ALCbackend_Capture); } -static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) +void WinMMBackendFactory::probe(enum DevProbe type, std::string *outnames) { auto add_device = [outnames](const std::string &dname) -> void { @@ -726,7 +703,7 @@ static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory* UNUSED(self), e } } -static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +ALCbackend *WinMMBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) { @@ -746,8 +723,8 @@ static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory* return nullptr; } -ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void) +BackendFactory &WinMMBackendFactory::getFactory() { - static ALCwinmmBackendFactory factory{}; - return STATIC_CAST(ALCbackendFactory, &factory); + static WinMMBackendFactory factory{}; + return factory; } diff --git a/Alc/backends/winmm.h b/Alc/backends/winmm.h new file mode 100644 index 00000000..b60dbc10 --- /dev/null +++ b/Alc/backends/winmm.h @@ -0,0 +1,20 @@ +#ifndef BACKENDS_WINMM_H +#define BACKENDS_WINMM_H + +#include "backends/base.h" + +struct WinMMBackendFactory final : public BackendFactory { +public: + bool init() override; + void deinit() override; + + bool querySupport(ALCbackend_Type type) override; + + void probe(enum DevProbe type, std::string *outnames) override; + + ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_WINMM_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 94df6473..f5f79390 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1099,7 +1099,7 @@ IF(HAVE_WINDOWS_H) IF(ALSOFT_BACKEND_WINMM) SET(HAVE_WINMM 1) SET(BACKENDS "${BACKENDS} WinMM,") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/winmm.cpp) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/winmm.cpp Alc/backends/winmm.h) SET(EXTRA_LIBS winmm ${EXTRA_LIBS}) ENDIF() ENDIF() -- cgit v1.2.3 From 7ef7477a139b5ca942d8a95ec24aeec331d4dd42 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 23:50:15 -0800 Subject: Convert the PortAudio backend factory --- Alc/alc.cpp | 10 ++-- Alc/backends/portaudio.cpp | 146 +++++++++++++++++++-------------------------- Alc/backends/portaudio.h | 20 +++++++ CMakeLists.txt | 2 +- 4 files changed, 90 insertions(+), 88 deletions(-) create mode 100644 Alc/backends/portaudio.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 2a443b74..5e984c65 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -95,6 +95,9 @@ #ifdef HAVE_WINMM #include "backends/winmm.h" #endif +#ifdef HAVE_PORTAUDIO +#include "backends/portaudio.h" +#endif #ifdef HAVE_SDL2 #include "backends/sdl2.h" #endif @@ -150,9 +153,9 @@ struct BackendInfo BackendList[] = { #ifdef HAVE_WINMM { "winmm", WinMMBackendFactory::getFactory }, #endif -#if 0 - { "port", ALCportBackendFactory_getFactory }, -#endif /* 0 */ +#ifdef HAVE_PORTAUDIO + { "port", PortBackendFactory::getFactory }, +#endif #ifdef HAVE_SDL2 { "sdl2", SDL2BackendFactory::getFactory }, #endif @@ -163,7 +166,6 @@ struct BackendInfo BackendList[] = { #endif }; ALsizei BackendListSize = COUNTOF(BackendList); -#undef EmptyFuncs struct BackendInfo PlaybackBackend; struct BackendInfo CaptureBackend; diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index 7b21669a..be5f30c4 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -20,6 +20,8 @@ #include "config.h" +#include "backends/portaudio.h" + #include #include #include @@ -30,17 +32,17 @@ #include "ringbuffer.h" #include "compat.h" -#include "backends/base.h" - #include -static const ALCchar pa_device[] = "PortAudio Default"; +namespace { + +constexpr ALCchar pa_device[] = "PortAudio Default"; #ifdef HAVE_DYNLOAD -static void *pa_handle; -#define MAKE_FUNC(x) static __typeof(x) * p##x +void *pa_handle; +#define MAKE_FUNC(x) decltype(x) * p##x MAKE_FUNC(Pa_Initialize); MAKE_FUNC(Pa_Terminate); MAKE_FUNC(Pa_GetErrorText); @@ -67,7 +69,7 @@ MAKE_FUNC(Pa_GetStreamInfo); #endif #endif -static ALCboolean pa_load(void) +bool pa_load(void) { PaError err; @@ -86,7 +88,7 @@ static ALCboolean pa_load(void) pa_handle = LoadLib(PALIB); if(!pa_handle) - return ALC_FALSE; + return false; #define LOAD_FUNC(f) do { \ p##f = reinterpret_cast(GetSymbol(pa_handle, #f)); \ @@ -94,7 +96,7 @@ static ALCboolean pa_load(void) { \ CloseLib(pa_handle); \ pa_handle = nullptr; \ - return ALC_FALSE; \ + return false; \ } \ } while(0) LOAD_FUNC(Pa_Initialize); @@ -114,17 +116,17 @@ static ALCboolean pa_load(void) ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err)); CloseLib(pa_handle); pa_handle = nullptr; - return ALC_FALSE; + return false; } } #else if((err=Pa_Initialize()) != paNoError) { ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err)); - return ALC_FALSE; + return false; } #endif - return ALC_TRUE; + return true; } @@ -134,27 +136,27 @@ struct ALCportPlayback final : public ALCbackend { ALuint update_size; }; -static int ALCportPlayback_WriteCallback(const void *inputBuffer, void *outputBuffer, +int ALCportPlayback_WriteCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags, void *userData); -static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device); -static void ALCportPlayback_Destruct(ALCportPlayback *self); -static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name); -static ALCboolean ALCportPlayback_reset(ALCportPlayback *self); -static ALCboolean ALCportPlayback_start(ALCportPlayback *self); -static void ALCportPlayback_stop(ALCportPlayback *self); -static DECLARE_FORWARD2(ALCportPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, unlock) +void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device); +void ALCportPlayback_Destruct(ALCportPlayback *self); +ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name); +ALCboolean ALCportPlayback_reset(ALCportPlayback *self); +ALCboolean ALCportPlayback_start(ALCportPlayback *self); +void ALCportPlayback_stop(ALCportPlayback *self); +DECLARE_FORWARD2(ALCportPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) +DECLARE_FORWARD(ALCportPlayback, ALCbackend, ALCuint, availableSamples) +DECLARE_FORWARD(ALCportPlayback, ALCbackend, ClockLatency, getClockLatency) +DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, lock) +DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCportPlayback) DEFINE_ALCBACKEND_VTABLE(ALCportPlayback); -static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device) +void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device) { new (self) ALCportPlayback{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); @@ -163,7 +165,7 @@ static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device) self->stream = nullptr; } -static void ALCportPlayback_Destruct(ALCportPlayback *self) +void ALCportPlayback_Destruct(ALCportPlayback *self) { PaError err = self->stream ? Pa_CloseStream(self->stream) : paNoError; if(err != paNoError) @@ -175,7 +177,7 @@ static void ALCportPlayback_Destruct(ALCportPlayback *self) } -static int ALCportPlayback_WriteCallback(const void *UNUSED(inputBuffer), void *outputBuffer, +int ALCportPlayback_WriteCallback(const void *UNUSED(inputBuffer), void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo), const PaStreamCallbackFlags UNUSED(statusFlags), void *userData) { @@ -188,7 +190,7 @@ static int ALCportPlayback_WriteCallback(const void *UNUSED(inputBuffer), void * } -static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name) +ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; PaError err; @@ -256,7 +258,7 @@ retry_open: } -static ALCboolean ALCportPlayback_reset(ALCportPlayback *self) +ALCboolean ALCportPlayback_reset(ALCportPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; const PaStreamInfo *streamInfo; @@ -295,7 +297,7 @@ static ALCboolean ALCportPlayback_reset(ALCportPlayback *self) return ALC_TRUE; } -static ALCboolean ALCportPlayback_start(ALCportPlayback *self) +ALCboolean ALCportPlayback_start(ALCportPlayback *self) { PaError err; @@ -309,7 +311,7 @@ static ALCboolean ALCportPlayback_start(ALCportPlayback *self) return ALC_TRUE; } -static void ALCportPlayback_stop(ALCportPlayback *self) +void ALCportPlayback_stop(ALCportPlayback *self) { PaError err = Pa_StopStream(self->stream); if(err != paNoError) @@ -324,27 +326,27 @@ struct ALCportCapture final : public ALCbackend { ll_ringbuffer_t *ring; }; -static int ALCportCapture_ReadCallback(const void *inputBuffer, void *outputBuffer, +int ALCportCapture_ReadCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags, void *userData); -static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device); -static void ALCportCapture_Destruct(ALCportCapture *self); -static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name); -static DECLARE_FORWARD(ALCportCapture, ALCbackend, ALCboolean, reset) -static ALCboolean ALCportCapture_start(ALCportCapture *self); -static void ALCportCapture_stop(ALCportCapture *self); -static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples); -static ALCuint ALCportCapture_availableSamples(ALCportCapture *self); -static DECLARE_FORWARD(ALCportCapture, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, unlock) +void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device); +void ALCportCapture_Destruct(ALCportCapture *self); +ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name); +DECLARE_FORWARD(ALCportCapture, ALCbackend, ALCboolean, reset) +ALCboolean ALCportCapture_start(ALCportCapture *self); +void ALCportCapture_stop(ALCportCapture *self); +ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples); +ALCuint ALCportCapture_availableSamples(ALCportCapture *self); +DECLARE_FORWARD(ALCportCapture, ALCbackend, ClockLatency, getClockLatency) +DECLARE_FORWARD(ALCportCapture, ALCbackend, void, lock) +DECLARE_FORWARD(ALCportCapture, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCportCapture) DEFINE_ALCBACKEND_VTABLE(ALCportCapture); -static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device) +void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device) { new (self) ALCportCapture{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); @@ -354,7 +356,7 @@ static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device) self->ring = nullptr; } -static void ALCportCapture_Destruct(ALCportCapture *self) +void ALCportCapture_Destruct(ALCportCapture *self) { PaError err = self->stream ? Pa_CloseStream(self->stream) : paNoError; if(err != paNoError) @@ -369,7 +371,7 @@ static void ALCportCapture_Destruct(ALCportCapture *self) } -static int ALCportCapture_ReadCallback(const void *inputBuffer, void *UNUSED(outputBuffer), +int ALCportCapture_ReadCallback(const void *inputBuffer, void *UNUSED(outputBuffer), unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo), const PaStreamCallbackFlags UNUSED(statusFlags), void *userData) { @@ -382,7 +384,7 @@ static int ALCportCapture_ReadCallback(const void *inputBuffer, void *UNUSED(out } -static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) +ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; ALuint samples, frame_size; @@ -448,7 +450,7 @@ static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) } -static ALCboolean ALCportCapture_start(ALCportCapture *self) +ALCboolean ALCportCapture_start(ALCportCapture *self) { PaError err = Pa_StartStream(self->stream); if(err != paNoError) @@ -459,7 +461,7 @@ static ALCboolean ALCportCapture_start(ALCportCapture *self) return ALC_TRUE; } -static void ALCportCapture_stop(ALCportCapture *self) +void ALCportCapture_stop(ALCportCapture *self) { PaError err = Pa_StopStream(self->stream); if(err != paNoError) @@ -467,42 +469,24 @@ static void ALCportCapture_stop(ALCportCapture *self) } -static ALCuint ALCportCapture_availableSamples(ALCportCapture *self) +ALCuint ALCportCapture_availableSamples(ALCportCapture *self) { return ll_ringbuffer_read_space(self->ring); } -static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples) { ll_ringbuffer_read(self->ring, static_cast(buffer), samples); return ALC_NO_ERROR; } - -struct ALCportBackendFactory final : public ALCbackendFactory { - ALCportBackendFactory() noexcept; -}; - -static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory *self); -static void ALCportBackendFactory_deinit(ALCportBackendFactory *self); -static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory *self, ALCbackend_Type type); -static void ALCportBackendFactory_probe(ALCportBackendFactory *self, enum DevProbe type, std::string *outnames); -static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCportBackendFactory); +} // namespace -ALCportBackendFactory::ALCportBackendFactory() noexcept - : ALCbackendFactory{GET_VTABLE2(ALCportBackendFactory, ALCbackendFactory)} -{ } +bool PortBackendFactory::init() +{ return pa_load(); } -static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory* UNUSED(self)) -{ - if(!pa_load()) - return ALC_FALSE; - return ALC_TRUE; -} - -static void ALCportBackendFactory_deinit(ALCportBackendFactory* UNUSED(self)) +void PortBackendFactory::deinit() { #ifdef HAVE_DYNLOAD if(pa_handle) @@ -516,14 +500,10 @@ static void ALCportBackendFactory_deinit(ALCportBackendFactory* UNUSED(self)) #endif } -static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} +bool PortBackendFactory::querySupport(ALCbackend_Type type) +{ return (type == ALCbackend_Playback || type == ALCbackend_Capture); } -static void ALCportBackendFactory_probe(ALCportBackendFactory* UNUSED(self), enum DevProbe type, std::string *outnames) +void PortBackendFactory::probe(enum DevProbe type, std::string *outnames) { switch(type) { @@ -535,7 +515,7 @@ static void ALCportBackendFactory_probe(ALCportBackendFactory* UNUSED(self), enu } } -static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +ALCbackend *PortBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) { @@ -555,8 +535,8 @@ static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory* UN return nullptr; } -ALCbackendFactory *ALCportBackendFactory_getFactory(void) +BackendFactory &PortBackendFactory::getFactory() { - static ALCportBackendFactory factory{}; - return STATIC_CAST(ALCbackendFactory, &factory); + static PortBackendFactory factory{}; + return factory; } diff --git a/Alc/backends/portaudio.h b/Alc/backends/portaudio.h new file mode 100644 index 00000000..598cd13d --- /dev/null +++ b/Alc/backends/portaudio.h @@ -0,0 +1,20 @@ +#ifndef BACKENDS_PORTAUDIO_H +#define BACKENDS_PORTAUDIO_H + +#include "backends/base.h" + +struct PortBackendFactory final : public BackendFactory { +public: + bool init() override; + void deinit() override; + + bool querySupport(ALCbackend_Type type) override; + + void probe(enum DevProbe type, std::string *outnames) override; + + ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_PORTAUDIO_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index f5f79390..54cf808a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1150,7 +1150,7 @@ IF(PORTAUDIO_FOUND) IF(ALSOFT_BACKEND_PORTAUDIO) SET(HAVE_PORTAUDIO 1) SET(BACKENDS "${BACKENDS} PortAudio${IS_LINKED},") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/portaudio.cpp) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/portaudio.cpp Alc/backends/portaudio.h) ADD_BACKEND_LIBS(${PORTAUDIO_LIBRARIES}) SET(INC_PATHS ${INC_PATHS} ${PORTAUDIO_INCLUDE_DIRS}) ENDIF() -- cgit v1.2.3 From a727978eb9ea6c5839e87b7de86665fd47c6dc7e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 23:55:23 -0800 Subject: Remove unused declarations and definitions --- Alc/backends/base.cpp | 6 ------ Alc/backends/base.h | 50 -------------------------------------------------- 2 files changed, 56 deletions(-) diff --git a/Alc/backends/base.cpp b/Alc/backends/base.cpp index 340ca7ac..61c2fe90 100644 --- a/Alc/backends/base.cpp +++ b/Alc/backends/base.cpp @@ -90,9 +90,3 @@ void ALCbackend_unlock(ALCbackend *self) std::terminate(); } } - - -/* Base ALCbackendFactory method implementations. */ -void ALCbackendFactory_deinit(ALCbackendFactory* UNUSED(self)) -{ -} diff --git a/Alc/backends/base.h b/Alc/backends/base.h index a303f761..50da6f38 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -105,56 +105,6 @@ enum ALCbackend_Type { }; -struct ALCbackendFactoryVtable; - -struct ALCbackendFactory { - const struct ALCbackendFactoryVtable *vtbl; -}; - -void ALCbackendFactory_deinit(ALCbackendFactory *self); - -struct ALCbackendFactoryVtable { - ALCboolean (*const init)(ALCbackendFactory *self); - void (*const deinit)(ALCbackendFactory *self); - - ALCboolean (*const querySupport)(ALCbackendFactory *self, ALCbackend_Type type); - - void (*const probe)(ALCbackendFactory *self, enum DevProbe type, std::string *outnames); - - ALCbackend* (*const createBackend)(ALCbackendFactory *self, ALCdevice *device, ALCbackend_Type type); -}; - -#define DEFINE_ALCBACKENDFACTORY_VTABLE(T) \ -DECLARE_THUNK(T, ALCbackendFactory, ALCboolean, init) \ -DECLARE_THUNK(T, ALCbackendFactory, void, deinit) \ -DECLARE_THUNK1(T, ALCbackendFactory, ALCboolean, querySupport, ALCbackend_Type) \ -DECLARE_THUNK2(T, ALCbackendFactory, void, probe, enum DevProbe, std::string*) \ -DECLARE_THUNK2(T, ALCbackendFactory, ALCbackend*, createBackend, ALCdevice*, ALCbackend_Type) \ - \ -static const struct ALCbackendFactoryVtable T##_ALCbackendFactory_vtable = { \ - T##_ALCbackendFactory_init, \ - T##_ALCbackendFactory_deinit, \ - T##_ALCbackendFactory_querySupport, \ - T##_ALCbackendFactory_probe, \ - T##_ALCbackendFactory_createBackend, \ -} - - -ALCbackendFactory *ALCalsaBackendFactory_getFactory(void); -ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void); -ALCbackendFactory *ALCossBackendFactory_getFactory(void); -ALCbackendFactory *ALCjackBackendFactory_getFactory(void); -ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void); -ALCbackendFactory *SndioBackendFactory_getFactory(void); -ALCbackendFactory *ALCqsaBackendFactory_getFactory(void); -ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void); -ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void); -ALCbackendFactory *ALCportBackendFactory_getFactory(void); -ALCbackendFactory *ALCopenslBackendFactory_getFactory(void); -ALCbackendFactory *ALCwaveBackendFactory_getFactory(void); -ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void); - - struct BackendFactory { virtual bool init() = 0; virtual void deinit() { } -- cgit v1.2.3 From 7a06a54af76a421dfe34d6ffa1759448c472da75 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Nov 2018 23:58:34 -0800 Subject: Simplify a couple checks --- Alc/backends/loopback.cpp | 13 +++---------- Alc/backends/null.cpp | 10 ++-------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/Alc/backends/loopback.cpp b/Alc/backends/loopback.cpp index 85c0a26e..843cb18e 100644 --- a/Alc/backends/loopback.cpp +++ b/Alc/backends/loopback.cpp @@ -88,20 +88,13 @@ void ALCloopback_stop(ALCloopback* UNUSED(self)) bool LoopbackBackendFactory::init() -{ - return true; -} +{ return true; } bool LoopbackBackendFactory::querySupport(ALCbackend_Type type) -{ - if(type == ALCbackend_Loopback) - return true; - return false; -} +{ return (type == ALCbackend_Loopback); } void LoopbackBackendFactory::probe(enum DevProbe, std::string*) -{ -} +{ } ALCbackend *LoopbackBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index d376ccdf..c9ba8de7 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -179,16 +179,10 @@ void ALCnullBackend_stop(ALCnullBackend *self) bool NullBackendFactory::init() -{ - return true; -} +{ return true; } bool NullBackendFactory::querySupport(ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - return true; - return false; -} +{ return (type == ALCbackend_Playback); } void NullBackendFactory::probe(enum DevProbe type, std::string *outnames) { -- cgit v1.2.3 From fc8191012a99d049dbd589f1a6366d778ff9c7e3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Nov 2018 00:06:54 -0800 Subject: Cleanup some syntax in alc.cpp --- Alc/alc.cpp | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 5e984c65..5706beb4 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -4005,10 +4005,6 @@ ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *Context) */ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) { - const ALCchar *fmt; - ALCdevice *device; - ALCenum err; - DO_INITCONFIG(); if(!PlaybackBackend.name) @@ -4029,7 +4025,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) )) deviceName = nullptr; - device = static_cast(al_calloc(16, sizeof(ALCdevice))); + auto device = static_cast(al_calloc(16, sizeof(ALCdevice))); if(!device) { alcSetError(nullptr, ALC_OUT_OF_MEMORY); @@ -4054,9 +4050,10 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->AuxiliaryEffectSlotMax = 64; device->NumAuxSends = DEFAULT_SENDS; + const ALCchar *fmt{}; if(ConfigValueStr(deviceName, nullptr, "channels", &fmt)) { - static const struct { + static constexpr struct { const char name[16]; enum DevFmtChannels chans; ALsizei order; @@ -4089,7 +4086,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) } if(ConfigValueStr(deviceName, nullptr, "sample-type", &fmt)) { - static const struct { + static constexpr struct { const char name[16]; enum DevFmtType type; } typelist[] = { @@ -4156,7 +4153,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) } // Find a playback device to open - if((err=V(device->Backend,open)(deviceName)) != ALC_NO_ERROR) + ALCenum err{V(device->Backend,open)(deviceName)}; + if(err != ALC_NO_ERROR) { FreeDevice(device); alcSetError(nullptr, err); @@ -4251,9 +4249,6 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) ************************************************/ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei samples) { - ALCdevice *device = nullptr; - ALCenum err; - DO_INITCONFIG(); if(!CaptureBackend.name) @@ -4271,7 +4266,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, if(deviceName && (!deviceName[0] || strcasecmp(deviceName, alcDefaultName) == 0 || strcasecmp(deviceName, "openal-soft") == 0)) deviceName = nullptr; - device = static_cast(al_calloc(16, sizeof(ALCdevice))); + auto device = static_cast(al_calloc(16, sizeof(ALCdevice))); if(!device) { alcSetError(nullptr, ALC_OUT_OF_MEMORY); @@ -4311,7 +4306,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), device->Frequency, device->UpdateSize, device->NumUpdates ); - if((err=V(device->Backend,open)(deviceName)) != ALC_NO_ERROR) + ALCenum err{V(device->Backend,open)(deviceName)}; + if(err != ALC_NO_ERROR) { FreeDevice(device); alcSetError(nullptr, err); @@ -4448,7 +4444,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN return nullptr; } - ALCdevice *device{static_cast(al_calloc(16, sizeof(ALCdevice)))}; + auto device = static_cast(al_calloc(16, sizeof(ALCdevice))); if(!device) { alcSetError(nullptr, ALC_OUT_OF_MEMORY); @@ -4517,7 +4513,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN */ ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type) { - ALCboolean ret = ALC_FALSE; + ALCboolean ret{ALC_FALSE}; if(!VerifyDevice(&device) || device->Type != Loopback) alcSetError(device, ALC_INVALID_DEVICE); @@ -4621,7 +4617,7 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) */ ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index) { - const ALCchar *str = nullptr; + const ALCchar *str{nullptr}; if(!VerifyDevice(&device) || device->Type == Capture) alcSetError(device, ALC_INVALID_DEVICE); @@ -4649,8 +4645,6 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum */ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs) { - ALCenum err; - std::unique_lock listlock{ListLock}; if(!VerifyDevice(&device) || device->Type == Capture || !ATOMIC_LOAD(&device->Connected, almemory_order_relaxed)) @@ -4663,7 +4657,7 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi almtx_lock(&device->BackendLock); listlock.unlock(); - err = UpdateDeviceParams(device, attribs); + ALCenum err{UpdateDeviceParams(device, attribs)}; almtx_unlock(&device->BackendLock); if(err != ALC_NO_ERROR) -- cgit v1.2.3 From 02eae1123f4bfdd239a9cc858378cc257e3331d3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Nov 2018 05:23:42 -0800 Subject: Use iterators instead of indexed loops --- Alc/alc.cpp | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 5706beb4..04792498 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include "alMain.h" #include "alSource.h" @@ -4053,7 +4054,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) const ALCchar *fmt{}; if(ConfigValueStr(deviceName, nullptr, "channels", &fmt)) { - static constexpr struct { + static constexpr struct ChannelMap { const char name[16]; enum DevFmtChannels chans; ALsizei order; @@ -4069,24 +4070,23 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) { "ambi2", DevFmtAmbi3D, 2 }, { "ambi3", DevFmtAmbi3D, 3 }, }; - size_t i; - for(i = 0;i < COUNTOF(chanlist);i++) + auto iter = std::find_if(std::begin(chanlist), std::end(chanlist), + [fmt](const ChannelMap &entry) -> bool + { return strcasecmp(entry.name, fmt) == 0; } + ); + if(iter == std::end(chanlist)) + ERR("Unsupported channels: %s\n", fmt); + else { - if(strcasecmp(chanlist[i].name, fmt) == 0) - { - device->FmtChans = chanlist[i].chans; - device->AmbiOrder = chanlist[i].order; - device->Flags |= DEVICE_CHANNELS_REQUEST; - break; - } + device->FmtChans = iter->chans; + device->AmbiOrder = iter->order; + device->Flags |= DEVICE_CHANNELS_REQUEST; } - if(i == COUNTOF(chanlist)) - ERR("Unsupported channels: %s\n", fmt); } if(ConfigValueStr(deviceName, nullptr, "sample-type", &fmt)) { - static constexpr struct { + static constexpr struct TypeMap { const char name[16]; enum DevFmtType type; } typelist[] = { @@ -4098,19 +4098,18 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) { "uint32", DevFmtUInt }, { "float32", DevFmtFloat }, }; - size_t i; - for(i = 0;i < COUNTOF(typelist);i++) + auto iter = std::find_if(std::begin(typelist), std::end(typelist), + [fmt](const TypeMap &entry) -> bool + { return strcasecmp(entry.name, fmt) == 0; } + ); + if(iter == std::end(typelist)) + ERR("Unsupported sample-type: %s\n", fmt); + else { - if(strcasecmp(typelist[i].name, fmt) == 0) - { - device->FmtType = typelist[i].type; - device->Flags |= DEVICE_SAMPLE_TYPE_REQUEST; - break; - } + device->FmtType = iter->type; + device->Flags |= DEVICE_SAMPLE_TYPE_REQUEST; } - if(i == COUNTOF(typelist)) - ERR("Unsupported sample-type: %s\n", fmt); } if(ConfigValueUInt(deviceName, nullptr, "frequency", &device->Frequency)) -- cgit v1.2.3 From 5cdd28c7365ae534c4ea381c135bfbeaa5dca6b7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Nov 2018 05:24:15 -0800 Subject: Convert sample_cvt.c to C++ --- CMakeLists.txt | 2 +- OpenAL32/sample_cvt.c | 276 ------------------------------------------------ OpenAL32/sample_cvt.cpp | 274 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 275 insertions(+), 277 deletions(-) delete mode 100644 OpenAL32/sample_cvt.c create mode 100644 OpenAL32/sample_cvt.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 54cf808a..d5066a69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -795,7 +795,7 @@ SET(OPENAL_OBJS OpenAL32/alState.c OpenAL32/event.c OpenAL32/Include/sample_cvt.h - OpenAL32/sample_cvt.c + OpenAL32/sample_cvt.cpp ) SET(ALC_OBJS Alc/alc.cpp diff --git a/OpenAL32/sample_cvt.c b/OpenAL32/sample_cvt.c deleted file mode 100644 index 4a85f74a..00000000 --- a/OpenAL32/sample_cvt.c +++ /dev/null @@ -1,276 +0,0 @@ - -#include "config.h" - -#include "sample_cvt.h" - -#include "AL/al.h" -#include "alu.h" -#include "alBuffer.h" - - -/* IMA ADPCM Stepsize table */ -static const int IMAStep_size[89] = { - 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, - 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, - 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, - 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, - 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, - 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, - 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493,10442, - 11487,12635,13899,15289,16818,18500,20350,22358,24633,27086,29794, - 32767 -}; - -/* IMA4 ADPCM Codeword decode table */ -static const int IMA4Codeword[16] = { - 1, 3, 5, 7, 9, 11, 13, 15, - -1,-3,-5,-7,-9,-11,-13,-15, -}; - -/* IMA4 ADPCM Step index adjust decode table */ -static const int IMA4Index_adjust[16] = { - -1,-1,-1,-1, 2, 4, 6, 8, - -1,-1,-1,-1, 2, 4, 6, 8 -}; - - -/* MSADPCM Adaption table */ -static const int MSADPCMAdaption[16] = { - 230, 230, 230, 230, 307, 409, 512, 614, - 768, 614, 512, 409, 307, 230, 230, 230 -}; - -/* MSADPCM Adaption Coefficient tables */ -static const int MSADPCMAdaptionCoeff[7][2] = { - { 256, 0 }, - { 512, -256 }, - { 0, 0 }, - { 192, 64 }, - { 240, 0 }, - { 460, -208 }, - { 392, -232 } -}; - - -/* A quick'n'dirty lookup table to decode a muLaw-encoded byte sample into a - * signed 16-bit sample */ -const ALshort muLawDecompressionTable[256] = { - -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956, - -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764, - -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412, - -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316, - -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, - -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, - -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, - -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, - -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, - -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, - -876, -844, -812, -780, -748, -716, -684, -652, - -620, -588, -556, -524, -492, -460, -428, -396, - -372, -356, -340, -324, -308, -292, -276, -260, - -244, -228, -212, -196, -180, -164, -148, -132, - -120, -112, -104, -96, -88, -80, -72, -64, - -56, -48, -40, -32, -24, -16, -8, 0, - 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, - 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, - 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, - 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, - 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, - 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, - 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, - 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, - 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, - 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, - 876, 844, 812, 780, 748, 716, 684, 652, - 620, 588, 556, 524, 492, 460, 428, 396, - 372, 356, 340, 324, 308, 292, 276, 260, - 244, 228, 212, 196, 180, 164, 148, 132, - 120, 112, 104, 96, 88, 80, 72, 64, - 56, 48, 40, 32, 24, 16, 8, 0 -}; - - -/* A quick'n'dirty lookup table to decode an aLaw-encoded byte sample into a - * signed 16-bit sample */ -const ALshort aLawDecompressionTable[256] = { - -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, - -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, - -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, - -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, - -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944, - -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136, - -11008,-10496,-12032,-11520, -8960, -8448, -9984, -9472, - -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568, - -344, -328, -376, -360, -280, -264, -312, -296, - -472, -456, -504, -488, -408, -392, -440, -424, - -88, -72, -120, -104, -24, -8, -56, -40, - -216, -200, -248, -232, -152, -136, -184, -168, - -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, - -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, - -688, -656, -752, -720, -560, -528, -624, -592, - -944, -912, -1008, -976, -816, -784, -880, -848, - 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, - 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, - 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, - 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, - 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, - 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, - 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, - 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, - 344, 328, 376, 360, 280, 264, 312, 296, - 472, 456, 504, 488, 408, 392, 440, 424, - 88, 72, 120, 104, 24, 8, 56, 40, - 216, 200, 248, 232, 152, 136, 184, 168, - 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, - 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, - 688, 656, 752, 720, 560, 528, 624, 592, - 944, 912, 1008, 976, 816, 784, 880, 848 -}; - - -static void DecodeIMA4Block(ALshort *dst, const ALubyte *src, ALint numchans, ALsizei align) -{ - ALint sample[MAX_INPUT_CHANNELS] = { 0 }; - ALint index[MAX_INPUT_CHANNELS] = { 0 }; - ALuint code[MAX_INPUT_CHANNELS] = { 0 }; - ALsizei c, i; - - for(c = 0;c < numchans;c++) - { - sample[c] = *(src++); - sample[c] |= *(src++) << 8; - sample[c] = (sample[c]^0x8000) - 32768; - index[c] = *(src++); - index[c] |= *(src++) << 8; - index[c] = (index[c]^0x8000) - 32768; - - index[c] = clampi(index[c], 0, 88); - - dst[c] = sample[c]; - } - - for(i = 1;i < align;i++) - { - if((i&7) == 1) - { - for(c = 0;c < numchans;c++) - { - code[c] = *(src++); - code[c] |= *(src++) << 8; - code[c] |= *(src++) << 16; - code[c] |= *(src++) << 24; - } - } - - for(c = 0;c < numchans;c++) - { - int nibble = code[c]&0xf; - code[c] >>= 4; - - sample[c] += IMA4Codeword[nibble] * IMAStep_size[index[c]] / 8; - sample[c] = clampi(sample[c], -32768, 32767); - - index[c] += IMA4Index_adjust[nibble]; - index[c] = clampi(index[c], 0, 88); - - *(dst++) = sample[c]; - } - } -} - -static void DecodeMSADPCMBlock(ALshort *dst, const ALubyte *src, ALint numchans, ALsizei align) -{ - ALubyte blockpred[MAX_INPUT_CHANNELS] = { 0 }; - ALint delta[MAX_INPUT_CHANNELS] = { 0 }; - ALshort samples[MAX_INPUT_CHANNELS][2] = { { 0, 0 } }; - ALint c, i; - - for(c = 0;c < numchans;c++) - { - blockpred[c] = *(src++); - blockpred[c] = minu(blockpred[c], 6); - } - for(c = 0;c < numchans;c++) - { - delta[c] = *(src++); - delta[c] |= *(src++) << 8; - delta[c] = (delta[c]^0x8000) - 32768; - } - for(c = 0;c < numchans;c++) - { - samples[c][0] = *(src++); - samples[c][0] |= *(src++) << 8; - samples[c][0] = (samples[c][0]^0x8000) - 32768; - } - for(c = 0;c < numchans;c++) - { - samples[c][1] = *(src++); - samples[c][1] |= *(src++) << 8; - samples[c][1] = (samples[c][1]^0x8000) - 0x8000; - } - - /* Second sample is written first. */ - for(c = 0;c < numchans;c++) - *(dst++) = samples[c][1]; - for(c = 0;c < numchans;c++) - *(dst++) = samples[c][0]; - - for(i = 2;i < align;i++) - { - for(c = 0;c < numchans;c++) - { - const ALint num = (i*numchans) + c; - ALint nibble, pred; - - /* Read the nibble (first is in the upper bits). */ - if(!(num&1)) - nibble = (*src>>4)&0x0f; - else - nibble = (*(src++))&0x0f; - - pred = (samples[c][0]*MSADPCMAdaptionCoeff[blockpred[c]][0] + - samples[c][1]*MSADPCMAdaptionCoeff[blockpred[c]][1]) / 256; - pred += ((nibble^0x08) - 0x08) * delta[c]; - pred = clampi(pred, -32768, 32767); - - samples[c][1] = samples[c][0]; - samples[c][0] = pred; - - delta[c] = (MSADPCMAdaption[nibble] * delta[c]) / 256; - delta[c] = maxi(16, delta[c]); - - *(dst++) = pred; - } - } -} - - -void Convert_ALshort_ALima4(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len, - ALsizei align) -{ - ALsizei byte_align = ((align-1)/2 + 4) * numchans; - ALsizei i; - - assert(align > 0 && (len%align) == 0); - for(i = 0;i < len;i += align) - { - DecodeIMA4Block(dst, src, numchans, align); - src += byte_align; - dst += align*numchans; - } -} - -void Convert_ALshort_ALmsadpcm(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len, - ALsizei align) -{ - ALsizei byte_align = ((align-2)/2 + 7) * numchans; - ALsizei i; - - assert(align > 1 && (len%align) == 0); - for(i = 0;i < len;i += align) - { - DecodeMSADPCMBlock(dst, src, numchans, align); - src += byte_align; - dst += align*numchans; - } -} diff --git a/OpenAL32/sample_cvt.cpp b/OpenAL32/sample_cvt.cpp new file mode 100644 index 00000000..6d6707f3 --- /dev/null +++ b/OpenAL32/sample_cvt.cpp @@ -0,0 +1,274 @@ + +#include "config.h" + +#include "sample_cvt.h" + +#include "AL/al.h" +#include "alu.h" +#include "alBuffer.h" + + +/* A quick'n'dirty lookup table to decode a muLaw-encoded byte sample into a + * signed 16-bit sample */ +const ALshort muLawDecompressionTable[256] = { + -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956, + -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764, + -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412, + -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316, + -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, + -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, + -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, + -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, + -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, + -876, -844, -812, -780, -748, -716, -684, -652, + -620, -588, -556, -524, -492, -460, -428, -396, + -372, -356, -340, -324, -308, -292, -276, -260, + -244, -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, -64, + -56, -48, -40, -32, -24, -16, -8, 0, + 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, + 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, + 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, + 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, + 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, + 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, + 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, + 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, + 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, + 876, 844, 812, 780, 748, 716, 684, 652, + 620, 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, 260, + 244, 228, 212, 196, 180, 164, 148, 132, + 120, 112, 104, 96, 88, 80, 72, 64, + 56, 48, 40, 32, 24, 16, 8, 0 +}; + +/* A quick'n'dirty lookup table to decode an aLaw-encoded byte sample into a + * signed 16-bit sample */ +const ALshort aLawDecompressionTable[256] = { + -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, + -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, + -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, + -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, + -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944, + -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136, + -11008,-10496,-12032,-11520, -8960, -8448, -9984, -9472, + -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568, + -344, -328, -376, -360, -280, -264, -312, -296, + -472, -456, -504, -488, -408, -392, -440, -424, + -88, -72, -120, -104, -24, -8, -56, -40, + -216, -200, -248, -232, -152, -136, -184, -168, + -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, + -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, -592, + -944, -912, -1008, -976, -816, -784, -880, -848, + 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, + 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, + 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, + 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, + 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, + 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, + 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, + 344, 328, 376, 360, 280, 264, 312, 296, + 472, 456, 504, 488, 408, 392, 440, 424, + 88, 72, 120, 104, 24, 8, 56, 40, + 216, 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, + 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, + 688, 656, 752, 720, 560, 528, 624, 592, + 944, 912, 1008, 976, 816, 784, 880, 848 +}; + +namespace { + +/* IMA ADPCM Stepsize table */ +constexpr int IMAStep_size[89] = { + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, + 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, + 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, + 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, + 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, + 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, + 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493,10442, + 11487,12635,13899,15289,16818,18500,20350,22358,24633,27086,29794, + 32767 +}; + +/* IMA4 ADPCM Codeword decode table */ +constexpr int IMA4Codeword[16] = { + 1, 3, 5, 7, 9, 11, 13, 15, + -1,-3,-5,-7,-9,-11,-13,-15, +}; + +/* IMA4 ADPCM Step index adjust decode table */ +constexpr int IMA4Index_adjust[16] = { + -1,-1,-1,-1, 2, 4, 6, 8, + -1,-1,-1,-1, 2, 4, 6, 8 +}; + + +/* MSADPCM Adaption table */ +constexpr int MSADPCMAdaption[16] = { + 230, 230, 230, 230, 307, 409, 512, 614, + 768, 614, 512, 409, 307, 230, 230, 230 +}; + +/* MSADPCM Adaption Coefficient tables */ +constexpr int MSADPCMAdaptionCoeff[7][2] = { + { 256, 0 }, + { 512, -256 }, + { 0, 0 }, + { 192, 64 }, + { 240, 0 }, + { 460, -208 }, + { 392, -232 } +}; + +void DecodeIMA4Block(ALshort *dst, const ALubyte *src, ALint numchans, ALsizei align) +{ + ALint sample[MAX_INPUT_CHANNELS]{}; + ALint index[MAX_INPUT_CHANNELS]{}; + ALuint code[MAX_INPUT_CHANNELS]{}; + + for(int c{0};c < numchans;c++) + { + sample[c] = *(src++); + sample[c] |= *(src++) << 8; + sample[c] = (sample[c]^0x8000) - 32768; + index[c] = *(src++); + index[c] |= *(src++) << 8; + index[c] = (index[c]^0x8000) - 32768; + + index[c] = clampi(index[c], 0, 88); + + dst[c] = sample[c]; + } + + for(int i{1};i < align;i++) + { + if((i&7) == 1) + { + for(int c{0};c < numchans;c++) + { + code[c] = *(src++); + code[c] |= *(src++) << 8; + code[c] |= *(src++) << 16; + code[c] |= *(src++) << 24; + } + } + + for(int c{0};c < numchans;c++) + { + int nibble = code[c]&0xf; + code[c] >>= 4; + + sample[c] += IMA4Codeword[nibble] * IMAStep_size[index[c]] / 8; + sample[c] = clampi(sample[c], -32768, 32767); + + index[c] += IMA4Index_adjust[nibble]; + index[c] = clampi(index[c], 0, 88); + + *(dst++) = sample[c]; + } + } +} + +void DecodeMSADPCMBlock(ALshort *dst, const ALubyte *src, ALint numchans, ALsizei align) +{ + ALubyte blockpred[MAX_INPUT_CHANNELS]{}; + ALint delta[MAX_INPUT_CHANNELS]{}; + ALshort samples[MAX_INPUT_CHANNELS][2]{}; + + for(int c{0};c < numchans;c++) + { + blockpred[c] = *(src++); + blockpred[c] = minu(blockpred[c], 6); + } + for(int c{0};c < numchans;c++) + { + delta[c] = *(src++); + delta[c] |= *(src++) << 8; + delta[c] = (delta[c]^0x8000) - 32768; + } + for(int c{0};c < numchans;c++) + { + samples[c][0] = *(src++); + samples[c][0] |= *(src++) << 8; + samples[c][0] = (samples[c][0]^0x8000) - 32768; + } + for(int c{0};c < numchans;c++) + { + samples[c][1] = *(src++); + samples[c][1] |= *(src++) << 8; + samples[c][1] = (samples[c][1]^0x8000) - 0x8000; + } + + /* Second sample is written first. */ + for(int c{0};c < numchans;c++) + *(dst++) = samples[c][1]; + for(int c{0};c < numchans;c++) + *(dst++) = samples[c][0]; + + for(int i{2};i < align;i++) + { + for(int c{0};c < numchans;c++) + { + const ALint num = (i*numchans) + c; + ALint nibble, pred; + + /* Read the nibble (first is in the upper bits). */ + if(!(num&1)) + nibble = (*src>>4)&0x0f; + else + nibble = (*(src++))&0x0f; + + pred = (samples[c][0]*MSADPCMAdaptionCoeff[blockpred[c]][0] + + samples[c][1]*MSADPCMAdaptionCoeff[blockpred[c]][1]) / 256; + pred += ((nibble^0x08) - 0x08) * delta[c]; + pred = clampi(pred, -32768, 32767); + + samples[c][1] = samples[c][0]; + samples[c][0] = pred; + + delta[c] = (MSADPCMAdaption[nibble] * delta[c]) / 256; + delta[c] = maxi(16, delta[c]); + + *(dst++) = pred; + } + } +} + +} // namespace + +void Convert_ALshort_ALima4(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len, + ALsizei align) +{ + ALsizei byte_align = ((align-1)/2 + 4) * numchans; + + assert(align > 0 && (len%align) == 0); + len /= align; + while(len--) + { + DecodeIMA4Block(dst, src, numchans, align); + src += byte_align; + dst += align*numchans; + } +} + +void Convert_ALshort_ALmsadpcm(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len, + ALsizei align) +{ + const ALsizei byte_align = ((align-2)/2 + 7) * numchans; + + assert(align > 1 && (len%align) == 0); + len /= align; + while(len--) + { + DecodeMSADPCMBlock(dst, src, numchans, align); + src += byte_align; + dst += align*numchans; + } +} -- cgit v1.2.3 From fedd5ebbea24883dc4767caf675778e2ca630d95 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Nov 2018 05:57:14 -0800 Subject: Convert event.c to C++ --- CMakeLists.txt | 2 +- OpenAL32/event.c | 127 ----------------------------------------------------- OpenAL32/event.cpp | 119 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 128 deletions(-) delete mode 100644 OpenAL32/event.c create mode 100644 OpenAL32/event.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d5066a69..0db47791 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -793,7 +793,7 @@ SET(OPENAL_OBJS OpenAL32/Include/alSource.h OpenAL32/alSource.cpp OpenAL32/alState.c - OpenAL32/event.c + OpenAL32/event.cpp OpenAL32/Include/sample_cvt.h OpenAL32/sample_cvt.cpp ) diff --git a/OpenAL32/event.c b/OpenAL32/event.c deleted file mode 100644 index 4c9c0be2..00000000 --- a/OpenAL32/event.c +++ /dev/null @@ -1,127 +0,0 @@ - -#include "config.h" - -#include "AL/alc.h" -#include "AL/al.h" -#include "AL/alext.h" -#include "alMain.h" -#include "alError.h" -#include "alAuxEffectSlot.h" -#include "ringbuffer.h" - - -int EventThread(void *arg) -{ - ALCcontext *context = arg; - bool quitnow = false; - - while(!quitnow) - { - ALbitfieldSOFT enabledevts; - AsyncEvent evt; - - if(ll_ringbuffer_read(context->AsyncEvents, (char*)&evt, 1) == 0) - { - alsem_wait(&context->EventSem); - continue; - } - - almtx_lock(&context->EventCbLock); - do { - quitnow = evt.EnumType == EventType_KillThread; - if(quitnow) break; - - if(evt.EnumType == EventType_ReleaseEffectState) - { - ALeffectState_DecRef(evt.u.EffectState); - continue; - } - - enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); - if(context->EventCb && (enabledevts&evt.EnumType) == evt.EnumType) - context->EventCb(evt.u.user.type, evt.u.user.id, evt.u.user.param, - (ALsizei)strlen(evt.u.user.msg), evt.u.user.msg, context->EventParam - ); - } while(ll_ringbuffer_read(context->AsyncEvents, (char*)&evt, 1) != 0); - almtx_unlock(&context->EventCbLock); - } - return 0; -} - -AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable) -{ - ALCcontext *context; - ALbitfieldSOFT enabledevts; - ALbitfieldSOFT flags = 0; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - if(count < 0) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Controlling %d events", count); - if(count == 0) goto done; - if(!types) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); - - for(i = 0;i < count;i++) - { - if(types[i] == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT) - flags |= EventType_BufferCompleted; - else if(types[i] == AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT) - flags |= EventType_SourceStateChange; - else if(types[i] == AL_EVENT_TYPE_ERROR_SOFT) - flags |= EventType_Error; - else if(types[i] == AL_EVENT_TYPE_PERFORMANCE_SOFT) - flags |= EventType_Performance; - else if(types[i] == AL_EVENT_TYPE_DEPRECATED_SOFT) - flags |= EventType_Deprecated; - else if(types[i] == AL_EVENT_TYPE_DISCONNECTED_SOFT) - flags |= EventType_Disconnected; - else - SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid event type 0x%04x", types[i]); - } - - if(enable) - { - enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); - while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->EnabledEvts, &enabledevts, enabledevts|flags, - almemory_order_acq_rel, almemory_order_acquire) == 0) - { - /* enabledevts is (re-)filled with the current value on failure, so - * just try again. - */ - } - } - else - { - enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); - while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->EnabledEvts, &enabledevts, enabledevts&~flags, - almemory_order_acq_rel, almemory_order_acquire) == 0) - { - } - /* Wait to ensure the event handler sees the changed flags before - * returning. - */ - almtx_lock(&context->EventCbLock); - almtx_unlock(&context->EventCbLock); - } - -done: - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam) -{ - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - almtx_lock(&context->PropLock); - almtx_lock(&context->EventCbLock); - context->EventCb = callback; - context->EventParam = userParam; - almtx_unlock(&context->EventCbLock); - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); -} diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp new file mode 100644 index 00000000..bc3e3178 --- /dev/null +++ b/OpenAL32/event.cpp @@ -0,0 +1,119 @@ + +#include "config.h" + +#include + +#include "AL/alc.h" +#include "AL/al.h" +#include "AL/alext.h" +#include "alMain.h" +#include "alError.h" +#include "alAuxEffectSlot.h" +#include "ringbuffer.h" +#include "threads.h" + + +int EventThread(void *arg) +{ + auto context = static_cast(arg); + + bool quitnow{false}; + while(LIKELY(!quitnow)) + { + AsyncEvent evt; + if(ll_ringbuffer_read(context->AsyncEvents, (char*)&evt, 1) == 0) + { + alsem_wait(&context->EventSem); + continue; + } + + std::lock_guard _{context->EventCbLock}; + do { + quitnow = evt.EnumType == EventType_KillThread; + if(UNLIKELY(quitnow)) break; + + if(evt.EnumType == EventType_ReleaseEffectState) + { + ALeffectState_DecRef(evt.u.EffectState); + continue; + } + + ALbitfieldSOFT enabledevts{ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire)}; + if(context->EventCb && (enabledevts&evt.EnumType) == evt.EnumType) + context->EventCb(evt.u.user.type, evt.u.user.id, evt.u.user.param, + (ALsizei)strlen(evt.u.user.msg), evt.u.user.msg, context->EventParam + ); + } while(ll_ringbuffer_read(context->AsyncEvents, (char*)&evt, 1) != 0); + } + return 0; +} + +AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(count < 0) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Controlling %d events", count); + if(count == 0) return; + if(!types) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "NULL pointer"); + + ALbitfieldSOFT flags{0}; + const ALenum *types_end = types+count; + auto bad_type = std::find_if_not(types, types_end, + [&flags](ALenum type) noexcept -> bool + { + if(type == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT) + flags |= EventType_BufferCompleted; + else if(type == AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT) + flags |= EventType_SourceStateChange; + else if(type == AL_EVENT_TYPE_ERROR_SOFT) + flags |= EventType_Error; + else if(type == AL_EVENT_TYPE_PERFORMANCE_SOFT) + flags |= EventType_Performance; + else if(type == AL_EVENT_TYPE_DEPRECATED_SOFT) + flags |= EventType_Deprecated; + else if(type == AL_EVENT_TYPE_DISCONNECTED_SOFT) + flags |= EventType_Disconnected; + else + return false; + return true; + } + ); + if(bad_type != types_end) + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, "Invalid event type 0x%04x", *bad_type); + + if(enable) + { + ALbitfieldSOFT enabledevts{ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)}; + while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->EnabledEvts, &enabledevts, enabledevts|flags, + almemory_order_acq_rel, almemory_order_acquire) == 0) + { + /* enabledevts is (re-)filled with the current value on failure, so + * just try again. + */ + } + } + else + { + ALbitfieldSOFT enabledevts{ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)}; + while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->EnabledEvts, &enabledevts, enabledevts&~flags, + almemory_order_acq_rel, almemory_order_acquire) == 0) + { + } + /* Wait to ensure the event handler sees the changed flags before + * returning. + */ + std::lock_guard{context->EventCbLock}; + } +} + +AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->EventCbLock}; + context->EventCb = callback; + context->EventParam = userParam; +} -- cgit v1.2.3 From 8be45fe8a5eb3ee5659983d3607524092fc54207 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Nov 2018 06:08:25 -0800 Subject: Convert alExtension.c to C++ --- CMakeLists.txt | 2 +- OpenAL32/alExtension.c | 87 ------------------------------------------------ OpenAL32/alExtension.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 88 deletions(-) delete mode 100644 OpenAL32/alExtension.c create mode 100644 OpenAL32/alExtension.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0db47791..c73e0d69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -785,7 +785,7 @@ SET(OPENAL_OBJS OpenAL32/alEffect.c OpenAL32/Include/alError.h OpenAL32/alError.c - OpenAL32/alExtension.c + OpenAL32/alExtension.cpp OpenAL32/Include/alFilter.h OpenAL32/alFilter.c OpenAL32/Include/alListener.h diff --git a/OpenAL32/alExtension.c b/OpenAL32/alExtension.c deleted file mode 100644 index f6378c70..00000000 --- a/OpenAL32/alExtension.c +++ /dev/null @@ -1,87 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include "alError.h" -#include "alMain.h" -#include "alFilter.h" -#include "alEffect.h" -#include "alAuxEffectSlot.h" -#include "alSource.h" -#include "alBuffer.h" -#include "AL/al.h" -#include "AL/alc.h" - - -AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName) -{ - ALboolean ret = AL_FALSE; - ALCcontext *context; - const char *ptr; - size_t len; - - context = GetContextRef(); - if(!context) return AL_FALSE; - - if(!extName) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); - - len = strlen(extName); - ptr = context->ExtensionList; - while(ptr && *ptr) - { - if(strncasecmp(ptr, extName, len) == 0 && - (ptr[len] == '\0' || isspace(ptr[len]))) - { - ret = AL_TRUE; - break; - } - if((ptr=strchr(ptr, ' ')) != NULL) - { - do { - ++ptr; - } while(isspace(*ptr)); - } - } - -done: - ALCcontext_DecRef(context); - return ret; -} - - -AL_API ALvoid* AL_APIENTRY alGetProcAddress(const ALchar *funcName) -{ - if(!funcName) - return NULL; - return alcGetProcAddress(NULL, funcName); -} - -AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *enumName) -{ - if(!enumName) - return (ALenum)0; - return alcGetEnumValue(NULL, enumName); -} diff --git a/OpenAL32/alExtension.cpp b/OpenAL32/alExtension.cpp new file mode 100644 index 00000000..bcc21f0f --- /dev/null +++ b/OpenAL32/alExtension.cpp @@ -0,0 +1,76 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include "alError.h" +#include "alMain.h" +#include "alFilter.h" +#include "alEffect.h" +#include "alAuxEffectSlot.h" +#include "alSource.h" +#include "alBuffer.h" +#include "AL/al.h" +#include "AL/alc.h" + + +AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return AL_FALSE; + + if(!extName) + SETERR_RETURN(context.get(), AL_INVALID_VALUE, AL_FALSE, "NULL pointer"); + + size_t len{strlen(extName)}; + const char *ptr{context->ExtensionList}; + while(ptr && *ptr) + { + if(strncasecmp(ptr, extName, len) == 0 && + (ptr[len] == '\0' || isspace(ptr[len]))) + return AL_TRUE; + + if((ptr=strchr(ptr, ' ')) != NULL) + { + do { + ++ptr; + } while(isspace(*ptr)); + } + } + + return AL_FALSE; +} + + +AL_API ALvoid* AL_APIENTRY alGetProcAddress(const ALchar *funcName) +{ + if(!funcName) return nullptr; + return alcGetProcAddress(nullptr, funcName); +} + +AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *enumName) +{ + if(!enumName) return (ALenum)0; + return alcGetEnumValue(nullptr, enumName); +} -- cgit v1.2.3 From 436db28a3f9f64a0348682a1e9888ef72d531153 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Nov 2018 06:24:24 -0800 Subject: Convert alError.c to C++ --- CMakeLists.txt | 2 +- OpenAL32/alError.c | 113 --------------------------------------------------- OpenAL32/alError.cpp | 104 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 114 deletions(-) delete mode 100644 OpenAL32/alError.c create mode 100644 OpenAL32/alError.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c73e0d69..bf925917 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -784,7 +784,7 @@ SET(OPENAL_OBJS OpenAL32/Include/alEffect.h OpenAL32/alEffect.c OpenAL32/Include/alError.h - OpenAL32/alError.c + OpenAL32/alError.cpp OpenAL32/alExtension.cpp OpenAL32/Include/alFilter.h OpenAL32/alFilter.c diff --git a/OpenAL32/alError.c b/OpenAL32/alError.c deleted file mode 100644 index b6208f77..00000000 --- a/OpenAL32/alError.c +++ /dev/null @@ -1,113 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2000 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#ifdef HAVE_WINDOWS_H -#define WIN32_LEAN_AND_MEAN -#include -#endif - -#include "alMain.h" -#include "AL/alc.h" -#include "alError.h" - -ALboolean TrapALError = AL_FALSE; - -void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) -{ - ALenum curerr = AL_NO_ERROR; - char message[1024] = { 0 }; - va_list args; - int msglen; - - va_start(args, msg); - msglen = vsnprintf(message, sizeof(message), msg, args); - va_end(args); - - if(msglen < 0 || (size_t)msglen >= sizeof(message)) - { - message[sizeof(message)-1] = 0; - msglen = (int)strlen(message); - } - if(msglen > 0) - msg = message; - else - { - msg = ""; - msglen = (int)strlen(msg); - } - - WARN("Error generated on context %p, code 0x%04x, \"%s\"\n", - context, errorCode, message); - if(TrapALError) - { -#ifdef _WIN32 - /* DebugBreak will cause an exception if there is no debugger */ - if(IsDebuggerPresent()) - DebugBreak(); -#elif defined(SIGTRAP) - raise(SIGTRAP); -#endif - } - - ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&context->LastError, &curerr, errorCode); - if((ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)&EventType_Error)) - { - ALbitfieldSOFT enabledevts; - almtx_lock(&context->EventCbLock); - enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); - if((enabledevts&EventType_Error) && context->EventCb) - (*context->EventCb)(AL_EVENT_TYPE_ERROR_SOFT, 0, errorCode, msglen, msg, - context->EventParam); - almtx_unlock(&context->EventCbLock); - } -} - -AL_API ALenum AL_APIENTRY alGetError(void) -{ - ALCcontext *context; - ALenum errorCode; - - context = GetContextRef(); - if(!context) - { - const ALenum deferror = AL_INVALID_OPERATION; - WARN("Querying error state on null context (implicitly 0x%04x)\n", deferror); - if(TrapALError) - { -#ifdef _WIN32 - if(IsDebuggerPresent()) - DebugBreak(); -#elif defined(SIGTRAP) - raise(SIGTRAP); -#endif - } - return deferror; - } - - errorCode = ATOMIC_EXCHANGE_SEQ(&context->LastError, AL_NO_ERROR); - - ALCcontext_DecRef(context); - return errorCode; -} diff --git a/OpenAL32/alError.cpp b/OpenAL32/alError.cpp new file mode 100644 index 00000000..cf56dd71 --- /dev/null +++ b/OpenAL32/alError.cpp @@ -0,0 +1,104 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2000 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#ifdef HAVE_WINDOWS_H +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include "alMain.h" +#include "AL/alc.h" +#include "alError.h" + +ALboolean TrapALError = AL_FALSE; + +void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) +{ + char message[1024]{}; + + va_list args; + va_start(args, msg); + int msglen{snprintf(message, sizeof(message), msg, args)}; + va_end(args); + + if(msglen < 0 || (size_t)msglen >= sizeof(message)) + { + message[sizeof(message)-1] = 0; + msglen = (int)strlen(message); + } + if(msglen > 0) + msg = message; + else + { + msg = ""; + msglen = (int)strlen(msg); + } + + WARN("Error generated on context %p, code 0x%04x, \"%s\"\n", + context, errorCode, message); + if(TrapALError) + { +#ifdef _WIN32 + /* DebugBreak will cause an exception if there is no debugger */ + if(IsDebuggerPresent()) + DebugBreak(); +#elif defined(SIGTRAP) + raise(SIGTRAP); +#endif + } + + ALenum curerr{AL_NO_ERROR}; + ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&context->LastError, &curerr, errorCode); + if((ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)&EventType_Error)) + { + std::lock_guard _{context->EventCbLock}; + ALbitfieldSOFT enabledevts{ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)}; + if((enabledevts&EventType_Error) && context->EventCb) + (*context->EventCb)(AL_EVENT_TYPE_ERROR_SOFT, 0, errorCode, msglen, msg, + context->EventParam); + } +} + +AL_API ALenum AL_APIENTRY alGetError(void) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) + { + constexpr ALenum deferror{AL_INVALID_OPERATION}; + WARN("Querying error state on null context (implicitly 0x%04x)\n", deferror); + if(TrapALError) + { +#ifdef _WIN32 + if(IsDebuggerPresent()) + DebugBreak(); +#elif defined(SIGTRAP) + raise(SIGTRAP); +#endif + } + return deferror; + } + + return ATOMIC_EXCHANGE_SEQ(&context->LastError, AL_NO_ERROR); +} -- cgit v1.2.3 From 165c162d01fa276945e60dc7030b1440973df95a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Nov 2018 06:45:24 -0800 Subject: Convert alState.c to C++ --- CMakeLists.txt | 2 +- OpenAL32/alState.c | 900 --------------------------------------------------- OpenAL32/alState.cpp | 818 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 819 insertions(+), 901 deletions(-) delete mode 100644 OpenAL32/alState.c create mode 100644 OpenAL32/alState.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index bf925917..1a840aab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -792,7 +792,7 @@ SET(OPENAL_OBJS OpenAL32/alListener.c OpenAL32/Include/alSource.h OpenAL32/alSource.cpp - OpenAL32/alState.c + OpenAL32/alState.cpp OpenAL32/event.cpp OpenAL32/Include/sample_cvt.h OpenAL32/sample_cvt.cpp diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c deleted file mode 100644 index 8be08435..00000000 --- a/OpenAL32/alState.c +++ /dev/null @@ -1,900 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2000 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "version.h" - -#include -#include "alMain.h" -#include "AL/alc.h" -#include "AL/al.h" -#include "AL/alext.h" -#include "alError.h" -#include "alListener.h" -#include "alSource.h" -#include "alAuxEffectSlot.h" - -#include "backends/base.h" - - -static const ALchar alVendor[] = "OpenAL Community"; -static const ALchar alVersion[] = "1.1 ALSOFT "ALSOFT_VERSION; -static const ALchar alRenderer[] = "OpenAL Soft"; - -// Error Messages -static const ALchar alNoError[] = "No Error"; -static const ALchar alErrInvalidName[] = "Invalid Name"; -static const ALchar alErrInvalidEnum[] = "Invalid Enum"; -static const ALchar alErrInvalidValue[] = "Invalid Value"; -static const ALchar alErrInvalidOp[] = "Invalid Operation"; -static const ALchar alErrOutOfMemory[] = "Out of Memory"; - -/* Resampler strings */ -static const ALchar alPointResampler[] = "Nearest"; -static const ALchar alLinearResampler[] = "Linear"; -static const ALchar alCubicResampler[] = "Cubic"; -static const ALchar alBSinc12Resampler[] = "11th order Sinc"; -static const ALchar alBSinc24Resampler[] = "23rd order Sinc"; - -/* WARNING: Non-standard export! Not part of any extension, or exposed in the - * alcFunctions list. - */ -AL_API const ALchar* AL_APIENTRY alsoft_get_version(void) -{ - const char *spoof = getenv("ALSOFT_SPOOF_VERSION"); - if(spoof && spoof[0] != '\0') return spoof; - return ALSOFT_VERSION; -} - -#define DO_UPDATEPROPS() do { \ - if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \ - UpdateContextProps(context); \ - else \ - ATOMIC_STORE(&context->PropsClean, AL_FALSE, almemory_order_release); \ -} while(0) - - -AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) -{ - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - almtx_lock(&context->PropLock); - switch(capability) - { - case AL_SOURCE_DISTANCE_MODEL: - context->SourceDistanceModel = AL_TRUE; - DO_UPDATEPROPS(); - break; - - default: - alSetError(context, AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability); - } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) -{ - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - almtx_lock(&context->PropLock); - switch(capability) - { - case AL_SOURCE_DISTANCE_MODEL: - context->SourceDistanceModel = AL_FALSE; - DO_UPDATEPROPS(); - break; - - default: - alSetError(context, AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability); - } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); -} - -AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability) -{ - ALCcontext *context; - ALboolean value=AL_FALSE; - - context = GetContextRef(); - if(!context) return AL_FALSE; - - almtx_lock(&context->PropLock); - switch(capability) - { - case AL_SOURCE_DISTANCE_MODEL: - value = context->SourceDistanceModel; - break; - - default: - alSetError(context, AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability); - } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); - return value; -} - -AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) -{ - ALCcontext *context; - ALboolean value=AL_FALSE; - - context = GetContextRef(); - if(!context) return AL_FALSE; - - almtx_lock(&context->PropLock); - switch(pname) - { - case AL_DOPPLER_FACTOR: - if(context->DopplerFactor != 0.0f) - value = AL_TRUE; - break; - - case AL_DOPPLER_VELOCITY: - if(context->DopplerVelocity != 0.0f) - value = AL_TRUE; - break; - - case AL_DISTANCE_MODEL: - if(context->DistanceModel == AL_INVERSE_DISTANCE_CLAMPED) - value = AL_TRUE; - break; - - case AL_SPEED_OF_SOUND: - if(context->SpeedOfSound != 0.0f) - value = AL_TRUE; - break; - - case AL_DEFERRED_UPDATES_SOFT: - if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - value = AL_TRUE; - break; - - case AL_GAIN_LIMIT_SOFT: - if(GAIN_MIX_MAX/context->GainBoost != 0.0f) - value = AL_TRUE; - break; - - case AL_NUM_RESAMPLERS_SOFT: - /* Always non-0. */ - value = AL_TRUE; - break; - - case AL_DEFAULT_RESAMPLER_SOFT: - value = ResamplerDefault ? AL_TRUE : AL_FALSE; - break; - - default: - alSetError(context, AL_INVALID_VALUE, "Invalid boolean property 0x%04x", pname); - } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); - return value; -} - -AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) -{ - ALCcontext *context; - ALdouble value = 0.0; - - context = GetContextRef(); - if(!context) return 0.0; - - almtx_lock(&context->PropLock); - switch(pname) - { - case AL_DOPPLER_FACTOR: - value = (ALdouble)context->DopplerFactor; - break; - - case AL_DOPPLER_VELOCITY: - value = (ALdouble)context->DopplerVelocity; - break; - - case AL_DISTANCE_MODEL: - value = (ALdouble)context->DistanceModel; - break; - - case AL_SPEED_OF_SOUND: - value = (ALdouble)context->SpeedOfSound; - break; - - case AL_DEFERRED_UPDATES_SOFT: - if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - value = (ALdouble)AL_TRUE; - break; - - case AL_GAIN_LIMIT_SOFT: - value = (ALdouble)GAIN_MIX_MAX/context->GainBoost; - break; - - case AL_NUM_RESAMPLERS_SOFT: - value = (ALdouble)(ResamplerMax + 1); - break; - - case AL_DEFAULT_RESAMPLER_SOFT: - value = (ALdouble)ResamplerDefault; - break; - - default: - alSetError(context, AL_INVALID_VALUE, "Invalid double property 0x%04x", pname); - } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); - return value; -} - -AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) -{ - ALCcontext *context; - ALfloat value = 0.0f; - - context = GetContextRef(); - if(!context) return 0.0f; - - almtx_lock(&context->PropLock); - switch(pname) - { - case AL_DOPPLER_FACTOR: - value = context->DopplerFactor; - break; - - case AL_DOPPLER_VELOCITY: - value = context->DopplerVelocity; - break; - - case AL_DISTANCE_MODEL: - value = (ALfloat)context->DistanceModel; - break; - - case AL_SPEED_OF_SOUND: - value = context->SpeedOfSound; - break; - - case AL_DEFERRED_UPDATES_SOFT: - if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - value = (ALfloat)AL_TRUE; - break; - - case AL_GAIN_LIMIT_SOFT: - value = GAIN_MIX_MAX/context->GainBoost; - break; - - case AL_NUM_RESAMPLERS_SOFT: - value = (ALfloat)(ResamplerMax + 1); - break; - - case AL_DEFAULT_RESAMPLER_SOFT: - value = (ALfloat)ResamplerDefault; - break; - - default: - alSetError(context, AL_INVALID_VALUE, "Invalid float property 0x%04x", pname); - } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); - return value; -} - -AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) -{ - ALCcontext *context; - ALint value = 0; - - context = GetContextRef(); - if(!context) return 0; - - almtx_lock(&context->PropLock); - switch(pname) - { - case AL_DOPPLER_FACTOR: - value = (ALint)context->DopplerFactor; - break; - - case AL_DOPPLER_VELOCITY: - value = (ALint)context->DopplerVelocity; - break; - - case AL_DISTANCE_MODEL: - value = (ALint)context->DistanceModel; - break; - - case AL_SPEED_OF_SOUND: - value = (ALint)context->SpeedOfSound; - break; - - case AL_DEFERRED_UPDATES_SOFT: - if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - value = (ALint)AL_TRUE; - break; - - case AL_GAIN_LIMIT_SOFT: - value = (ALint)(GAIN_MIX_MAX/context->GainBoost); - break; - - case AL_NUM_RESAMPLERS_SOFT: - value = ResamplerMax + 1; - break; - - case AL_DEFAULT_RESAMPLER_SOFT: - value = ResamplerDefault; - break; - - default: - alSetError(context, AL_INVALID_VALUE, "Invalid integer property 0x%04x", pname); - } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); - return value; -} - -AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) -{ - ALCcontext *context; - ALint64SOFT value = 0; - - context = GetContextRef(); - if(!context) return 0; - - almtx_lock(&context->PropLock); - switch(pname) - { - case AL_DOPPLER_FACTOR: - value = (ALint64SOFT)context->DopplerFactor; - break; - - case AL_DOPPLER_VELOCITY: - value = (ALint64SOFT)context->DopplerVelocity; - break; - - case AL_DISTANCE_MODEL: - value = (ALint64SOFT)context->DistanceModel; - break; - - case AL_SPEED_OF_SOUND: - value = (ALint64SOFT)context->SpeedOfSound; - break; - - case AL_DEFERRED_UPDATES_SOFT: - if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - value = (ALint64SOFT)AL_TRUE; - break; - - case AL_GAIN_LIMIT_SOFT: - value = (ALint64SOFT)(GAIN_MIX_MAX/context->GainBoost); - break; - - case AL_NUM_RESAMPLERS_SOFT: - value = (ALint64SOFT)(ResamplerMax + 1); - break; - - case AL_DEFAULT_RESAMPLER_SOFT: - value = (ALint64SOFT)ResamplerDefault; - break; - - default: - alSetError(context, AL_INVALID_VALUE, "Invalid integer64 property 0x%04x", pname); - } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); - return value; -} - -AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname) -{ - ALCcontext *context; - void *value = NULL; - - context = GetContextRef(); - if(!context) return NULL; - - almtx_lock(&context->PropLock); - switch(pname) - { - case AL_EVENT_CALLBACK_FUNCTION_SOFT: - value = context->EventCb; - break; - - case AL_EVENT_CALLBACK_USER_PARAM_SOFT: - value = context->EventParam; - break; - - default: - alSetError(context, AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname); - } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); - return value; -} - -AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values) -{ - ALCcontext *context; - - if(values) - { - switch(pname) - { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetBoolean(pname); - return; - } - } - - context = GetContextRef(); - if(!context) return; - - if(!values) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - switch(pname) - { - default: - alSetError(context, AL_INVALID_VALUE, "Invalid boolean-vector property 0x%04x", pname); - } - - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values) -{ - ALCcontext *context; - - if(values) - { - switch(pname) - { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetDouble(pname); - return; - } - } - - context = GetContextRef(); - if(!context) return; - - if(!values) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - switch(pname) - { - default: - alSetError(context, AL_INVALID_VALUE, "Invalid double-vector property 0x%04x", pname); - } - - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values) -{ - ALCcontext *context; - - if(values) - { - switch(pname) - { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetFloat(pname); - return; - } - } - - context = GetContextRef(); - if(!context) return; - - if(!values) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - switch(pname) - { - default: - alSetError(context, AL_INVALID_VALUE, "Invalid float-vector property 0x%04x", pname); - } - - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values) -{ - ALCcontext *context; - - if(values) - { - switch(pname) - { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetInteger(pname); - return; - } - } - - context = GetContextRef(); - if(!context) return; - - if(!values) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - switch(pname) - { - default: - alSetError(context, AL_INVALID_VALUE, "Invalid integer-vector property 0x%04x", pname); - } - - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values) -{ - ALCcontext *context; - - if(values) - { - switch(pname) - { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetInteger64SOFT(pname); - return; - } - } - - context = GetContextRef(); - if(!context) return; - - if(!values) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - switch(pname) - { - default: - alSetError(context, AL_INVALID_VALUE, "Invalid integer64-vector property 0x%04x", pname); - } - - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values) -{ - ALCcontext *context; - - if(values) - { - switch(pname) - { - case AL_EVENT_CALLBACK_FUNCTION_SOFT: - case AL_EVENT_CALLBACK_USER_PARAM_SOFT: - values[0] = alGetPointerSOFT(pname); - return; - } - } - - context = GetContextRef(); - if(!context) return; - - if(!values) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - switch(pname) - { - default: - alSetError(context, AL_INVALID_VALUE, "Invalid pointer-vector property 0x%04x", pname); - } - - ALCcontext_DecRef(context); -} - -AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname) -{ - const ALchar *value = NULL; - ALCcontext *context; - - context = GetContextRef(); - if(!context) return NULL; - - switch(pname) - { - case AL_VENDOR: - value = alVendor; - break; - - case AL_VERSION: - value = alVersion; - break; - - case AL_RENDERER: - value = alRenderer; - break; - - case AL_EXTENSIONS: - value = context->ExtensionList; - break; - - case AL_NO_ERROR: - value = alNoError; - break; - - case AL_INVALID_NAME: - value = alErrInvalidName; - break; - - case AL_INVALID_ENUM: - value = alErrInvalidEnum; - break; - - case AL_INVALID_VALUE: - value = alErrInvalidValue; - break; - - case AL_INVALID_OPERATION: - value = alErrInvalidOp; - break; - - case AL_OUT_OF_MEMORY: - value = alErrOutOfMemory; - break; - - default: - alSetError(context, AL_INVALID_VALUE, "Invalid string property 0x%04x", pname); - } - - ALCcontext_DecRef(context); - return value; -} - -AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value) -{ - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - if(!(value >= 0.0f && isfinite(value))) - alSetError(context, AL_INVALID_VALUE, "Doppler factor %f out of range", value); - else - { - almtx_lock(&context->PropLock); - context->DopplerFactor = value; - DO_UPDATEPROPS(); - almtx_unlock(&context->PropLock); - } - - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) -{ - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - if((ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)&EventType_Deprecated)) - { - static const ALCchar msg[] = - "alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound"; - const ALsizei msglen = (ALsizei)strlen(msg); - ALbitfieldSOFT enabledevts; - almtx_lock(&context->EventCbLock); - enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); - if((enabledevts&EventType_Deprecated) && context->EventCb) - (*context->EventCb)(AL_EVENT_TYPE_DEPRECATED_SOFT, 0, 0, msglen, msg, - context->EventParam); - almtx_unlock(&context->EventCbLock); - } - - if(!(value >= 0.0f && isfinite(value))) - alSetError(context, AL_INVALID_VALUE, "Doppler velocity %f out of range", value); - else - { - almtx_lock(&context->PropLock); - context->DopplerVelocity = value; - DO_UPDATEPROPS(); - almtx_unlock(&context->PropLock); - } - - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value) -{ - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - if(!(value > 0.0f && isfinite(value))) - alSetError(context, AL_INVALID_VALUE, "Speed of sound %f out of range", value); - else - { - almtx_lock(&context->PropLock); - context->SpeedOfSound = value; - DO_UPDATEPROPS(); - almtx_unlock(&context->PropLock); - } - - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value) -{ - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - if(!(value == AL_INVERSE_DISTANCE || value == AL_INVERSE_DISTANCE_CLAMPED || - value == AL_LINEAR_DISTANCE || value == AL_LINEAR_DISTANCE_CLAMPED || - value == AL_EXPONENT_DISTANCE || value == AL_EXPONENT_DISTANCE_CLAMPED || - value == AL_NONE)) - alSetError(context, AL_INVALID_VALUE, "Distance model 0x%04x out of range", value); - else - { - almtx_lock(&context->PropLock); - context->DistanceModel = value; - if(!context->SourceDistanceModel) - DO_UPDATEPROPS(); - almtx_unlock(&context->PropLock); - } - - ALCcontext_DecRef(context); -} - - -AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void) -{ - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - ALCcontext_DeferUpdates(context); - - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void) -{ - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - ALCcontext_ProcessUpdates(context); - - ALCcontext_DecRef(context); -} - - -AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index) -{ - const char *ResamplerNames[] = { - alPointResampler, alLinearResampler, - alCubicResampler, alBSinc12Resampler, - alBSinc24Resampler, - }; - const ALchar *value = NULL; - ALCcontext *context; - - static_assert(COUNTOF(ResamplerNames) == ResamplerMax+1, "Incorrect ResamplerNames list"); - - context = GetContextRef(); - if(!context) return NULL; - - switch(pname) - { - case AL_RESAMPLER_NAME_SOFT: - if(index < 0 || (size_t)index >= COUNTOF(ResamplerNames)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Resampler name index %d out of range", - index); - value = ResamplerNames[index]; - break; - - default: - alSetError(context, AL_INVALID_VALUE, "Invalid string indexed property"); - } - -done: - ALCcontext_DecRef(context); - return value; -} - - -void UpdateContextProps(ALCcontext *context) -{ - struct ALcontextProps *props; - - /* Get an unused proprty container, or allocate a new one as needed. */ - props = ATOMIC_LOAD(&context->FreeContextProps, almemory_order_acquire); - if(!props) - props = al_calloc(16, sizeof(*props)); - else - { - struct ALcontextProps *next; - do { - next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeContextProps, &props, next, - almemory_order_seq_cst, almemory_order_acquire) == 0); - } - - /* Copy in current property values. */ - props->MetersPerUnit = context->MetersPerUnit; - - props->DopplerFactor = context->DopplerFactor; - props->DopplerVelocity = context->DopplerVelocity; - props->SpeedOfSound = context->SpeedOfSound; - - props->SourceDistanceModel = context->SourceDistanceModel; - props->DistanceModel = context->DistanceModel; - - /* Set the new container for updating internal parameters. */ - props = ATOMIC_EXCHANGE_PTR(&context->Update, props, almemory_order_acq_rel); - if(props) - { - /* If there was an unused update container, put it back in the - * freelist. - */ - ATOMIC_REPLACE_HEAD(struct ALcontextProps*, &context->FreeContextProps, props); - } -} diff --git a/OpenAL32/alState.cpp b/OpenAL32/alState.cpp new file mode 100644 index 00000000..b15c710d --- /dev/null +++ b/OpenAL32/alState.cpp @@ -0,0 +1,818 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2000 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "version.h" + +#include +#include "alMain.h" +#include "AL/alc.h" +#include "AL/al.h" +#include "AL/alext.h" +#include "alError.h" +#include "alListener.h" +#include "alSource.h" +#include "alAuxEffectSlot.h" + +#include "backends/base.h" + + +namespace { + +constexpr ALchar alVendor[] = "OpenAL Community"; +constexpr ALchar alVersion[] = "1.1 ALSOFT " ALSOFT_VERSION; +constexpr ALchar alRenderer[] = "OpenAL Soft"; + +// Error Messages +constexpr ALchar alNoError[] = "No Error"; +constexpr ALchar alErrInvalidName[] = "Invalid Name"; +constexpr ALchar alErrInvalidEnum[] = "Invalid Enum"; +constexpr ALchar alErrInvalidValue[] = "Invalid Value"; +constexpr ALchar alErrInvalidOp[] = "Invalid Operation"; +constexpr ALchar alErrOutOfMemory[] = "Out of Memory"; + +/* Resampler strings */ +constexpr ALchar alPointResampler[] = "Nearest"; +constexpr ALchar alLinearResampler[] = "Linear"; +constexpr ALchar alCubicResampler[] = "Cubic"; +constexpr ALchar alBSinc12Resampler[] = "11th order Sinc"; +constexpr ALchar alBSinc24Resampler[] = "23rd order Sinc"; + +} // namespace + +/* WARNING: Non-standard export! Not part of any extension, or exposed in the + * alcFunctions list. + */ +extern "C" AL_API const ALchar* AL_APIENTRY alsoft_get_version(void) +{ + const char *spoof{getenv("ALSOFT_SPOOF_VERSION")}; + if(spoof && spoof[0] != '\0') return spoof; + return ALSOFT_VERSION; +} + +#define DO_UPDATEPROPS() do { \ + if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \ + UpdateContextProps(context.get()); \ + else \ + ATOMIC_STORE(&context->PropsClean, AL_FALSE, almemory_order_release); \ +} while(0) + + +AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + almtx_lock(&context->PropLock); + switch(capability) + { + case AL_SOURCE_DISTANCE_MODEL: + context->SourceDistanceModel = AL_TRUE; + DO_UPDATEPROPS(); + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability); + } + almtx_unlock(&context->PropLock); +} + +AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + almtx_lock(&context->PropLock); + switch(capability) + { + case AL_SOURCE_DISTANCE_MODEL: + context->SourceDistanceModel = AL_FALSE; + DO_UPDATEPROPS(); + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability); + } + almtx_unlock(&context->PropLock); +} + +AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return AL_FALSE; + + ALboolean value{AL_FALSE}; + almtx_lock(&context->PropLock); + switch(capability) + { + case AL_SOURCE_DISTANCE_MODEL: + value = context->SourceDistanceModel; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability); + } + almtx_unlock(&context->PropLock); + + return value; +} + +AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return AL_FALSE; + + ALboolean value{AL_FALSE}; + almtx_lock(&context->PropLock); + switch(pname) + { + case AL_DOPPLER_FACTOR: + if(context->DopplerFactor != 0.0f) + value = AL_TRUE; + break; + + case AL_DOPPLER_VELOCITY: + if(context->DopplerVelocity != 0.0f) + value = AL_TRUE; + break; + + case AL_DISTANCE_MODEL: + if(context->DistanceModel == AL_INVERSE_DISTANCE_CLAMPED) + value = AL_TRUE; + break; + + case AL_SPEED_OF_SOUND: + if(context->SpeedOfSound != 0.0f) + value = AL_TRUE; + break; + + case AL_DEFERRED_UPDATES_SOFT: + if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + value = AL_TRUE; + break; + + case AL_GAIN_LIMIT_SOFT: + if(GAIN_MIX_MAX/context->GainBoost != 0.0f) + value = AL_TRUE; + break; + + case AL_NUM_RESAMPLERS_SOFT: + /* Always non-0. */ + value = AL_TRUE; + break; + + case AL_DEFAULT_RESAMPLER_SOFT: + value = ResamplerDefault ? AL_TRUE : AL_FALSE; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid boolean property 0x%04x", pname); + } + almtx_unlock(&context->PropLock); + + return value; +} + +AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return 0.0; + + ALdouble value{0.0}; + almtx_lock(&context->PropLock); + switch(pname) + { + case AL_DOPPLER_FACTOR: + value = (ALdouble)context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + value = (ALdouble)context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + value = (ALdouble)context->DistanceModel; + break; + + case AL_SPEED_OF_SOUND: + value = (ALdouble)context->SpeedOfSound; + break; + + case AL_DEFERRED_UPDATES_SOFT: + if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + value = (ALdouble)AL_TRUE; + break; + + case AL_GAIN_LIMIT_SOFT: + value = (ALdouble)GAIN_MIX_MAX/context->GainBoost; + break; + + case AL_NUM_RESAMPLERS_SOFT: + value = (ALdouble)(ResamplerMax + 1); + break; + + case AL_DEFAULT_RESAMPLER_SOFT: + value = (ALdouble)ResamplerDefault; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid double property 0x%04x", pname); + } + almtx_unlock(&context->PropLock); + + return value; +} + +AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return 0.0f; + + ALfloat value{0.0f}; + almtx_lock(&context->PropLock); + switch(pname) + { + case AL_DOPPLER_FACTOR: + value = context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + value = context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + value = (ALfloat)context->DistanceModel; + break; + + case AL_SPEED_OF_SOUND: + value = context->SpeedOfSound; + break; + + case AL_DEFERRED_UPDATES_SOFT: + if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + value = (ALfloat)AL_TRUE; + break; + + case AL_GAIN_LIMIT_SOFT: + value = GAIN_MIX_MAX/context->GainBoost; + break; + + case AL_NUM_RESAMPLERS_SOFT: + value = (ALfloat)(ResamplerMax + 1); + break; + + case AL_DEFAULT_RESAMPLER_SOFT: + value = (ALfloat)ResamplerDefault; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid float property 0x%04x", pname); + } + almtx_unlock(&context->PropLock); + + return value; +} + +AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return 0; + + ALint value{0}; + almtx_lock(&context->PropLock); + switch(pname) + { + case AL_DOPPLER_FACTOR: + value = (ALint)context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + value = (ALint)context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + value = (ALint)context->DistanceModel; + break; + + case AL_SPEED_OF_SOUND: + value = (ALint)context->SpeedOfSound; + break; + + case AL_DEFERRED_UPDATES_SOFT: + if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + value = (ALint)AL_TRUE; + break; + + case AL_GAIN_LIMIT_SOFT: + value = (ALint)(GAIN_MIX_MAX/context->GainBoost); + break; + + case AL_NUM_RESAMPLERS_SOFT: + value = ResamplerMax + 1; + break; + + case AL_DEFAULT_RESAMPLER_SOFT: + value = ResamplerDefault; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer property 0x%04x", pname); + } + almtx_unlock(&context->PropLock); + + return value; +} + +extern "C" AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return 0; + + ALint64SOFT value{0}; + almtx_lock(&context->PropLock); + switch(pname) + { + case AL_DOPPLER_FACTOR: + value = (ALint64SOFT)context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + value = (ALint64SOFT)context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + value = (ALint64SOFT)context->DistanceModel; + break; + + case AL_SPEED_OF_SOUND: + value = (ALint64SOFT)context->SpeedOfSound; + break; + + case AL_DEFERRED_UPDATES_SOFT: + if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + value = (ALint64SOFT)AL_TRUE; + break; + + case AL_GAIN_LIMIT_SOFT: + value = (ALint64SOFT)(GAIN_MIX_MAX/context->GainBoost); + break; + + case AL_NUM_RESAMPLERS_SOFT: + value = (ALint64SOFT)(ResamplerMax + 1); + break; + + case AL_DEFAULT_RESAMPLER_SOFT: + value = (ALint64SOFT)ResamplerDefault; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer64 property 0x%04x", pname); + } + almtx_unlock(&context->PropLock); + + return value; +} + +AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return nullptr; + + void *value{nullptr}; + almtx_lock(&context->PropLock); + switch(pname) + { + case AL_EVENT_CALLBACK_FUNCTION_SOFT: + value = reinterpret_cast(context->EventCb); + break; + + case AL_EVENT_CALLBACK_USER_PARAM_SOFT: + value = context->EventParam; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname); + } + almtx_unlock(&context->PropLock); + + return value; +} + +AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values) +{ + if(values) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + case AL_DOPPLER_VELOCITY: + case AL_DISTANCE_MODEL: + case AL_SPEED_OF_SOUND: + case AL_DEFERRED_UPDATES_SOFT: + case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: + values[0] = alGetBoolean(pname); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(pname) + { + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid boolean-vector property 0x%04x", pname); + } +} + +AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values) +{ + if(values) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + case AL_DOPPLER_VELOCITY: + case AL_DISTANCE_MODEL: + case AL_SPEED_OF_SOUND: + case AL_DEFERRED_UPDATES_SOFT: + case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: + values[0] = alGetDouble(pname); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(pname) + { + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid double-vector property 0x%04x", pname); + } +} + +AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values) +{ + if(values) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + case AL_DOPPLER_VELOCITY: + case AL_DISTANCE_MODEL: + case AL_SPEED_OF_SOUND: + case AL_DEFERRED_UPDATES_SOFT: + case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: + values[0] = alGetFloat(pname); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(pname) + { + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid float-vector property 0x%04x", pname); + } +} + +AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values) +{ + if(values) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + case AL_DOPPLER_VELOCITY: + case AL_DISTANCE_MODEL: + case AL_SPEED_OF_SOUND: + case AL_DEFERRED_UPDATES_SOFT: + case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: + values[0] = alGetInteger(pname); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(pname) + { + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer-vector property 0x%04x", pname); + } +} + +extern "C" AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values) +{ + if(values) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + case AL_DOPPLER_VELOCITY: + case AL_DISTANCE_MODEL: + case AL_SPEED_OF_SOUND: + case AL_DEFERRED_UPDATES_SOFT: + case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: + values[0] = alGetInteger64SOFT(pname); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(pname) + { + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer64-vector property 0x%04x", pname); + } +} + +AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values) +{ + if(values) + { + switch(pname) + { + case AL_EVENT_CALLBACK_FUNCTION_SOFT: + case AL_EVENT_CALLBACK_USER_PARAM_SOFT: + values[0] = alGetPointerSOFT(pname); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(pname) + { + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid pointer-vector property 0x%04x", pname); + } +} + +AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return nullptr; + + const ALchar *value{nullptr}; + switch(pname) + { + case AL_VENDOR: + value = alVendor; + break; + + case AL_VERSION: + value = alVersion; + break; + + case AL_RENDERER: + value = alRenderer; + break; + + case AL_EXTENSIONS: + value = context->ExtensionList; + break; + + case AL_NO_ERROR: + value = alNoError; + break; + + case AL_INVALID_NAME: + value = alErrInvalidName; + break; + + case AL_INVALID_ENUM: + value = alErrInvalidEnum; + break; + + case AL_INVALID_VALUE: + value = alErrInvalidValue; + break; + + case AL_INVALID_OPERATION: + value = alErrInvalidOp; + break; + + case AL_OUT_OF_MEMORY: + value = alErrOutOfMemory; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid string property 0x%04x", pname); + } + return value; +} + +AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!(value >= 0.0f && isfinite(value))) + alSetError(context.get(), AL_INVALID_VALUE, "Doppler factor %f out of range", value); + else + { + almtx_lock(&context->PropLock); + context->DopplerFactor = value; + DO_UPDATEPROPS(); + almtx_unlock(&context->PropLock); + } +} + +AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if((ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)&EventType_Deprecated)) + { + static constexpr ALCchar msg[] = + "alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound"; + const ALsizei msglen = (ALsizei)strlen(msg); + ALbitfieldSOFT enabledevts; + almtx_lock(&context->EventCbLock); + enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); + if((enabledevts&EventType_Deprecated) && context->EventCb) + (*context->EventCb)(AL_EVENT_TYPE_DEPRECATED_SOFT, 0, 0, msglen, msg, + context->EventParam); + almtx_unlock(&context->EventCbLock); + } + + if(!(value >= 0.0f && isfinite(value))) + alSetError(context.get(), AL_INVALID_VALUE, "Doppler velocity %f out of range", value); + else + { + almtx_lock(&context->PropLock); + context->DopplerVelocity = value; + DO_UPDATEPROPS(); + almtx_unlock(&context->PropLock); + } +} + +AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!(value > 0.0f && isfinite(value))) + alSetError(context.get(), AL_INVALID_VALUE, "Speed of sound %f out of range", value); + else + { + almtx_lock(&context->PropLock); + context->SpeedOfSound = value; + DO_UPDATEPROPS(); + almtx_unlock(&context->PropLock); + } +} + +AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!(value == AL_INVERSE_DISTANCE || value == AL_INVERSE_DISTANCE_CLAMPED || + value == AL_LINEAR_DISTANCE || value == AL_LINEAR_DISTANCE_CLAMPED || + value == AL_EXPONENT_DISTANCE || value == AL_EXPONENT_DISTANCE_CLAMPED || + value == AL_NONE)) + alSetError(context.get(), AL_INVALID_VALUE, "Distance model 0x%04x out of range", value); + else + { + almtx_lock(&context->PropLock); + context->DistanceModel = static_cast(value); + if(!context->SourceDistanceModel) + DO_UPDATEPROPS(); + almtx_unlock(&context->PropLock); + } +} + + +AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCcontext_DeferUpdates(context.get()); +} + +AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCcontext_ProcessUpdates(context.get()); +} + + +AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index) +{ + const char *ResamplerNames[] = { + alPointResampler, alLinearResampler, + alCubicResampler, alBSinc12Resampler, + alBSinc24Resampler, + }; + static_assert(COUNTOF(ResamplerNames) == ResamplerMax+1, "Incorrect ResamplerNames list"); + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return nullptr; + + const ALchar *value{nullptr}; + switch(pname) + { + case AL_RESAMPLER_NAME_SOFT: + if(index < 0 || (size_t)index >= COUNTOF(ResamplerNames)) + alSetError(context.get(), AL_INVALID_VALUE, "Resampler name index %d out of range", + index); + else + value = ResamplerNames[index]; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid string indexed property"); + } + return value; +} + + +void UpdateContextProps(ALCcontext *context) +{ + /* Get an unused proprty container, or allocate a new one as needed. */ + struct ALcontextProps *props{ATOMIC_LOAD(&context->FreeContextProps, almemory_order_acquire)}; + if(!props) + props = static_cast(al_calloc(16, sizeof(*props))); + else + { + struct ALcontextProps *next; + do { + next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); + } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeContextProps, &props, next, + almemory_order_seq_cst, almemory_order_acquire) == 0); + } + + /* Copy in current property values. */ + props->MetersPerUnit = context->MetersPerUnit; + + props->DopplerFactor = context->DopplerFactor; + props->DopplerVelocity = context->DopplerVelocity; + props->SpeedOfSound = context->SpeedOfSound; + + props->SourceDistanceModel = context->SourceDistanceModel; + props->DistanceModel = context->DistanceModel; + + /* Set the new container for updating internal parameters. */ + props = static_cast(ATOMIC_EXCHANGE_PTR(&context->Update, props, + almemory_order_acq_rel)); + if(props) + { + /* If there was an unused update container, put it back in the + * freelist. + */ + ATOMIC_REPLACE_HEAD(struct ALcontextProps*, &context->FreeContextProps, props); + } +} -- cgit v1.2.3 From 50f36d39f7e62cd9c8701ef12515cf2b24204069 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Nov 2018 07:11:27 -0800 Subject: Use lock_guard instead of manual lock/unlock calls --- OpenAL32/alState.cpp | 45 +++++++++++++++------------------------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/OpenAL32/alState.cpp b/OpenAL32/alState.cpp index b15c710d..6750de1f 100644 --- a/OpenAL32/alState.cpp +++ b/OpenAL32/alState.cpp @@ -81,7 +81,7 @@ AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - almtx_lock(&context->PropLock); + std::lock_guard _{context->PropLock}; switch(capability) { case AL_SOURCE_DISTANCE_MODEL: @@ -92,7 +92,6 @@ AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) default: alSetError(context.get(), AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability); } - almtx_unlock(&context->PropLock); } AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) @@ -100,7 +99,7 @@ AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - almtx_lock(&context->PropLock); + std::lock_guard _{context->PropLock}; switch(capability) { case AL_SOURCE_DISTANCE_MODEL: @@ -111,7 +110,6 @@ AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) default: alSetError(context.get(), AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability); } - almtx_unlock(&context->PropLock); } AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability) @@ -119,8 +117,8 @@ AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return AL_FALSE; + std::lock_guard _{context->PropLock}; ALboolean value{AL_FALSE}; - almtx_lock(&context->PropLock); switch(capability) { case AL_SOURCE_DISTANCE_MODEL: @@ -130,7 +128,6 @@ AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability) default: alSetError(context.get(), AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability); } - almtx_unlock(&context->PropLock); return value; } @@ -140,8 +137,8 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return AL_FALSE; + std::lock_guard _{context->PropLock}; ALboolean value{AL_FALSE}; - almtx_lock(&context->PropLock); switch(pname) { case AL_DOPPLER_FACTOR: @@ -186,7 +183,6 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) default: alSetError(context.get(), AL_INVALID_VALUE, "Invalid boolean property 0x%04x", pname); } - almtx_unlock(&context->PropLock); return value; } @@ -196,8 +192,8 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return 0.0; + std::lock_guard _{context->PropLock}; ALdouble value{0.0}; - almtx_lock(&context->PropLock); switch(pname) { case AL_DOPPLER_FACTOR: @@ -236,7 +232,6 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) default: alSetError(context.get(), AL_INVALID_VALUE, "Invalid double property 0x%04x", pname); } - almtx_unlock(&context->PropLock); return value; } @@ -246,8 +241,8 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return 0.0f; + std::lock_guard _{context->PropLock}; ALfloat value{0.0f}; - almtx_lock(&context->PropLock); switch(pname) { case AL_DOPPLER_FACTOR: @@ -286,7 +281,6 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) default: alSetError(context.get(), AL_INVALID_VALUE, "Invalid float property 0x%04x", pname); } - almtx_unlock(&context->PropLock); return value; } @@ -296,8 +290,8 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return 0; + std::lock_guard _{context->PropLock}; ALint value{0}; - almtx_lock(&context->PropLock); switch(pname) { case AL_DOPPLER_FACTOR: @@ -336,7 +330,6 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) default: alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer property 0x%04x", pname); } - almtx_unlock(&context->PropLock); return value; } @@ -346,8 +339,8 @@ extern "C" AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return 0; + std::lock_guard _{context->PropLock}; ALint64SOFT value{0}; - almtx_lock(&context->PropLock); switch(pname) { case AL_DOPPLER_FACTOR: @@ -386,7 +379,6 @@ extern "C" AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) default: alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer64 property 0x%04x", pname); } - almtx_unlock(&context->PropLock); return value; } @@ -396,8 +388,8 @@ AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return nullptr; + std::lock_guard _{context->PropLock}; void *value{nullptr}; - almtx_lock(&context->PropLock); switch(pname) { case AL_EVENT_CALLBACK_FUNCTION_SOFT: @@ -411,7 +403,6 @@ AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname) default: alSetError(context.get(), AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname); } - almtx_unlock(&context->PropLock); return value; } @@ -659,10 +650,9 @@ AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value) alSetError(context.get(), AL_INVALID_VALUE, "Doppler factor %f out of range", value); else { - almtx_lock(&context->PropLock); + std::lock_guard _{context->PropLock}; context->DopplerFactor = value; DO_UPDATEPROPS(); - almtx_unlock(&context->PropLock); } } @@ -676,23 +666,20 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) static constexpr ALCchar msg[] = "alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound"; const ALsizei msglen = (ALsizei)strlen(msg); - ALbitfieldSOFT enabledevts; - almtx_lock(&context->EventCbLock); - enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); + std::lock_guard _{context->EventCbLock}; + ALbitfieldSOFT enabledevts{ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)}; if((enabledevts&EventType_Deprecated) && context->EventCb) (*context->EventCb)(AL_EVENT_TYPE_DEPRECATED_SOFT, 0, 0, msglen, msg, context->EventParam); - almtx_unlock(&context->EventCbLock); } if(!(value >= 0.0f && isfinite(value))) alSetError(context.get(), AL_INVALID_VALUE, "Doppler velocity %f out of range", value); else { - almtx_lock(&context->PropLock); + std::lock_guard _{context->PropLock}; context->DopplerVelocity = value; DO_UPDATEPROPS(); - almtx_unlock(&context->PropLock); } } @@ -705,10 +692,9 @@ AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value) alSetError(context.get(), AL_INVALID_VALUE, "Speed of sound %f out of range", value); else { - almtx_lock(&context->PropLock); + std::lock_guard _{context->PropLock}; context->SpeedOfSound = value; DO_UPDATEPROPS(); - almtx_unlock(&context->PropLock); } } @@ -724,11 +710,10 @@ AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value) alSetError(context.get(), AL_INVALID_VALUE, "Distance model 0x%04x out of range", value); else { - almtx_lock(&context->PropLock); + std::lock_guard _{context->PropLock}; context->DistanceModel = static_cast(value); if(!context->SourceDistanceModel) DO_UPDATEPROPS(); - almtx_unlock(&context->PropLock); } } -- cgit v1.2.3 From ce370be52b70f09cd87e8dff80f2dcd289203423 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Nov 2018 08:09:56 -0800 Subject: Remove some unneeded includes --- Alc/ALu.c | 2 -- Alc/backends/base.h | 4 ---- Alc/inldefs.c | 2 -- 3 files changed, 8 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 4d03fc0b..a9b5a009 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -46,8 +46,6 @@ #include "cpu_caps.h" #include "bsinc_inc.h" -#include "backends/base.h" - /* Cone scalar */ ALfloat ConeScale = 1.0f; diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 50da6f38..61b71a47 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -3,8 +3,6 @@ #include "alMain.h" -#ifdef __cplusplus - #include #include @@ -116,6 +114,4 @@ struct BackendFactory { virtual ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) = 0; }; - -#endif /* __cplusplus */ #endif /* AL_BACKENDS_BASE_H */ diff --git a/Alc/inldefs.c b/Alc/inldefs.c index dd1cff4a..025f2d27 100644 --- a/Alc/inldefs.c +++ b/Alc/inldefs.c @@ -8,8 +8,6 @@ #include "alBuffer.h" #include "alEffect.h" -#include "backends/base.h" - /* This is a place to dump inline function instantiations, to generate function * bodies for calls that can't be inlined. C++ does not have a way to do this * explicitly, so as long as there is C code calling inline functions, a body -- cgit v1.2.3 From 0e0fe15b989c8289748c50704c4b10036c1f79dd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Nov 2018 18:28:39 -0800 Subject: Convert alAuxEffectSlot.c to C++ --- CMakeLists.txt | 2 +- OpenAL32/alAuxEffectSlot.c | 799 ------------------------------------------ OpenAL32/alAuxEffectSlot.cpp | 802 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 803 insertions(+), 800 deletions(-) delete mode 100644 OpenAL32/alAuxEffectSlot.c create mode 100644 OpenAL32/alAuxEffectSlot.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a840aab..df190c60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -778,7 +778,7 @@ SET(OPENAL_OBJS OpenAL32/Include/alu.h OpenAL32/Include/alAuxEffectSlot.h - OpenAL32/alAuxEffectSlot.c + OpenAL32/alAuxEffectSlot.cpp OpenAL32/Include/alBuffer.h OpenAL32/alBuffer.cpp OpenAL32/Include/alEffect.h diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c deleted file mode 100644 index 297aa1b6..00000000 --- a/OpenAL32/alAuxEffectSlot.c +++ /dev/null @@ -1,799 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "alMain.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alListener.h" -#include "alSource.h" - -#include "fpu_modes.h" -#include "almalloc.h" - - -static void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context); -static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context); - -static const struct { - ALenum Type; - EffectStateFactory* (*GetFactory)(void); -} FactoryList[] = { - { AL_EFFECT_NULL, NullStateFactory_getFactory }, - { AL_EFFECT_EAXREVERB, ReverbStateFactory_getFactory }, - { AL_EFFECT_REVERB, ReverbStateFactory_getFactory }, - { AL_EFFECT_AUTOWAH, AutowahStateFactory_getFactory }, - { AL_EFFECT_CHORUS, ChorusStateFactory_getFactory }, - { AL_EFFECT_COMPRESSOR, CompressorStateFactory_getFactory }, - { AL_EFFECT_DISTORTION, DistortionStateFactory_getFactory }, - { AL_EFFECT_ECHO, EchoStateFactory_getFactory }, - { AL_EFFECT_EQUALIZER, EqualizerStateFactory_getFactory }, - { AL_EFFECT_FLANGER, FlangerStateFactory_getFactory }, - { AL_EFFECT_FREQUENCY_SHIFTER, FshifterStateFactory_getFactory }, - { AL_EFFECT_RING_MODULATOR, ModulatorStateFactory_getFactory }, - { AL_EFFECT_PITCH_SHIFTER, PshifterStateFactory_getFactory}, - { AL_EFFECT_DEDICATED_DIALOGUE, DedicatedStateFactory_getFactory }, - { AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedStateFactory_getFactory } -}; - -static inline EffectStateFactory *getFactoryByType(ALenum type) -{ - size_t i; - for(i = 0;i < COUNTOF(FactoryList);i++) - { - if(FactoryList[i].Type == type) - return FactoryList[i].GetFactory(); - } - return NULL; -} - -static void ALeffectState_IncRef(ALeffectState *state); - - -static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) -{ - id--; - if(UNLIKELY(id >= VECTOR_SIZE(context->EffectSlotList))) - return NULL; - return VECTOR_ELEM(context->EffectSlotList, id); -} - -static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) -{ - EffectSubList *sublist; - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= VECTOR_SIZE(device->EffectList))) - return NULL; - sublist = &VECTOR_ELEM(device->EffectList, lidx); - if(UNLIKELY(sublist->FreeMask & (U64(1)<Effects + slidx; -} - - -#define DO_UPDATEPROPS() do { \ - if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \ - UpdateEffectSlotProps(slot, context); \ - else \ - ATOMIC_STORE(&slot->PropsClean, AL_FALSE, almemory_order_release); \ -} while(0) - - -AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) -{ - ALCdevice *device; - ALCcontext *context; - ALsizei cur; - - context = GetContextRef(); - if(!context) return; - - if(n < 0) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d effect slots", n); - if(n == 0) goto done; - - LockEffectSlotList(context); - device = context->Device; - for(cur = 0;cur < n;cur++) - { - ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList); - ALeffectslotPtr *end = VECTOR_END(context->EffectSlotList); - ALeffectslot *slot = NULL; - ALenum err = AL_OUT_OF_MEMORY; - - for(;iter != end;iter++) - { - if(!*iter) - break; - } - if(iter == end) - { - if(device->AuxiliaryEffectSlotMax == VECTOR_SIZE(context->EffectSlotList)) - { - UnlockEffectSlotList(context); - alDeleteAuxiliaryEffectSlots(cur, effectslots); - SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, - "Exceeding %u auxiliary effect slot limit", device->AuxiliaryEffectSlotMax); - } - VECTOR_PUSH_BACK(context->EffectSlotList, NULL); - iter = &VECTOR_BACK(context->EffectSlotList); - } - slot = al_calloc(16, sizeof(ALeffectslot)); - if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR) - { - al_free(slot); - UnlockEffectSlotList(context); - - alDeleteAuxiliaryEffectSlots(cur, effectslots); - SETERR_GOTO(context, err, done, "Effect slot object allocation failed"); - } - aluInitEffectPanning(slot); - - slot->id = (iter - VECTOR_BEGIN(context->EffectSlotList)) + 1; - *iter = slot; - - effectslots[cur] = slot->id; - } - AddActiveEffectSlots(effectslots, n, context); - UnlockEffectSlotList(context); - -done: - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots) -{ - ALCcontext *context; - ALeffectslot *slot; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - LockEffectSlotList(context); - if(n < 0) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effect slots", n); - if(n == 0) goto done; - - for(i = 0;i < n;i++) - { - if((slot=LookupEffectSlot(context, effectslots[i])) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", - effectslots[i]); - if(ReadRef(&slot->ref) != 0) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Deleting in-use effect slot %u", - effectslots[i]); - } - - // All effectslots are valid - RemoveActiveEffectSlots(effectslots, n, context); - for(i = 0;i < n;i++) - { - if((slot=LookupEffectSlot(context, effectslots[i])) == NULL) - continue; - VECTOR_ELEM(context->EffectSlotList, effectslots[i]-1) = NULL; - - DeinitEffectSlot(slot); - - memset(slot, 0, sizeof(*slot)); - al_free(slot); - } - -done: - UnlockEffectSlotList(context); - ALCcontext_DecRef(context); -} - -AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot) -{ - ALCcontext *context; - ALboolean ret; - - context = GetContextRef(); - if(!context) return AL_FALSE; - - LockEffectSlotList(context); - ret = (LookupEffectSlot(context, effectslot) ? AL_TRUE : AL_FALSE); - UnlockEffectSlotList(context); - - ALCcontext_DecRef(context); - - return ret; -} - -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value) -{ - ALCdevice *device; - ALCcontext *context; - ALeffectslot *slot; - ALeffect *effect = NULL; - ALenum err; - - context = GetContextRef(); - if(!context) return; - - almtx_lock(&context->PropLock); - LockEffectSlotList(context); - if((slot=LookupEffectSlot(context, effectslot)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); - switch(param) - { - case AL_EFFECTSLOT_EFFECT: - device = context->Device; - - LockEffectList(device); - effect = (value ? LookupEffect(device, value) : NULL); - if(!(value == 0 || effect != NULL)) - { - UnlockEffectList(device); - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Invalid effect ID %u", value); - } - err = InitializeEffect(context, slot, effect); - UnlockEffectList(device); - - if(err != AL_NO_ERROR) - SETERR_GOTO(context, err, done, "Effect initialization failed"); - break; - - case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: - if(!(value == AL_TRUE || value == AL_FALSE)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, - "Effect slot auxiliary send auto out of range"); - slot->AuxSendAuto = value; - break; - - default: - SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid effect slot integer property 0x%04x", - param); - } - DO_UPDATEPROPS(); - -done: - UnlockEffectSlotList(context); - almtx_unlock(&context->PropLock); - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values) -{ - ALCcontext *context; - - switch(param) - { - case AL_EFFECTSLOT_EFFECT: - case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: - alAuxiliaryEffectSloti(effectslot, param, values[0]); - return; - } - - context = GetContextRef(); - if(!context) return; - - LockEffectSlotList(context); - if(LookupEffectSlot(context, effectslot) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer-vector property 0x%04x", - param); - } - -done: - UnlockEffectSlotList(context); - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value) -{ - ALCcontext *context; - ALeffectslot *slot; - - context = GetContextRef(); - if(!context) return; - - almtx_lock(&context->PropLock); - LockEffectSlotList(context); - if((slot=LookupEffectSlot(context, effectslot)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); - switch(param) - { - case AL_EFFECTSLOT_GAIN: - if(!(value >= 0.0f && value <= 1.0f)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Effect slot gain out of range"); - slot->Gain = value; - break; - - default: - SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid effect slot float property 0x%04x", - param); - } - DO_UPDATEPROPS(); - -done: - UnlockEffectSlotList(context); - almtx_unlock(&context->PropLock); - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values) -{ - ALCcontext *context; - - switch(param) - { - case AL_EFFECTSLOT_GAIN: - alAuxiliaryEffectSlotf(effectslot, param, values[0]); - return; - } - - context = GetContextRef(); - if(!context) return; - - LockEffectSlotList(context); - if(LookupEffectSlot(context, effectslot) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float-vector property 0x%04x", - param); - } - -done: - UnlockEffectSlotList(context); - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value) -{ - ALCcontext *context; - ALeffectslot *slot; - - context = GetContextRef(); - if(!context) return; - - LockEffectSlotList(context); - if((slot=LookupEffectSlot(context, effectslot)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); - switch(param) - { - case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: - *value = slot->AuxSendAuto; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer property 0x%04x", param); - } - -done: - UnlockEffectSlotList(context); - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values) -{ - ALCcontext *context; - - switch(param) - { - case AL_EFFECTSLOT_EFFECT: - case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: - alGetAuxiliaryEffectSloti(effectslot, param, values); - return; - } - - context = GetContextRef(); - if(!context) return; - - LockEffectSlotList(context); - if(LookupEffectSlot(context, effectslot) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer-vector property 0x%04x", - param); - } - -done: - UnlockEffectSlotList(context); - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value) -{ - ALCcontext *context; - ALeffectslot *slot; - - context = GetContextRef(); - if(!context) return; - - LockEffectSlotList(context); - if((slot=LookupEffectSlot(context, effectslot)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); - switch(param) - { - case AL_EFFECTSLOT_GAIN: - *value = slot->Gain; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float property 0x%04x", param); - } - -done: - UnlockEffectSlotList(context); - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values) -{ - ALCcontext *context; - - switch(param) - { - case AL_EFFECTSLOT_GAIN: - alGetAuxiliaryEffectSlotf(effectslot, param, values); - return; - } - - context = GetContextRef(); - if(!context) return; - - LockEffectSlotList(context); - if(LookupEffectSlot(context, effectslot) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float-vector property 0x%04x", - param); - } - -done: - UnlockEffectSlotList(context); - ALCcontext_DecRef(context); -} - - -ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect) -{ - ALCdevice *Device = Context->Device; - ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL); - struct ALeffectslotProps *props; - ALeffectState *State; - - if(newtype != EffectSlot->Effect.Type) - { - EffectStateFactory *factory; - - factory = getFactoryByType(newtype); - if(!factory) - { - ERR("Failed to find factory for effect type 0x%04x\n", newtype); - return AL_INVALID_ENUM; - } - State = EffectStateFactory_create(factory); - if(!State) return AL_OUT_OF_MEMORY; - - START_MIXER_MODE(); - almtx_lock(&Device->BackendLock); - State->OutBuffer = Device->Dry.Buffer; - State->OutChannels = Device->Dry.NumChannels; - if(V(State,deviceUpdate)(Device) == AL_FALSE) - { - almtx_unlock(&Device->BackendLock); - LEAVE_MIXER_MODE(); - ALeffectState_DecRef(State); - return AL_OUT_OF_MEMORY; - } - almtx_unlock(&Device->BackendLock); - END_MIXER_MODE(); - - if(!effect) - { - EffectSlot->Effect.Type = AL_EFFECT_NULL; - memset(&EffectSlot->Effect.Props, 0, sizeof(EffectSlot->Effect.Props)); - } - else - { - EffectSlot->Effect.Type = effect->type; - EffectSlot->Effect.Props = effect->Props; - } - - ALeffectState_DecRef(EffectSlot->Effect.State); - EffectSlot->Effect.State = State; - } - else if(effect) - EffectSlot->Effect.Props = effect->Props; - - /* Remove state references from old effect slot property updates. */ - props = ATOMIC_LOAD_SEQ(&Context->FreeEffectslotProps); - while(props) - { - if(props->State) - ALeffectState_DecRef(props->State); - props->State = NULL; - props = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - } - - return AL_NO_ERROR; -} - - -static void ALeffectState_IncRef(ALeffectState *state) -{ - uint ref; - ref = IncrementRef(&state->Ref); - TRACEREF("%p increasing refcount to %u\n", state, ref); -} - -void ALeffectState_DecRef(ALeffectState *state) -{ - uint ref; - ref = DecrementRef(&state->Ref); - TRACEREF("%p decreasing refcount to %u\n", state, ref); - if(ref == 0) DELETE_OBJ(state); -} - - -void ALeffectState_Construct(ALeffectState *state) -{ - InitRef(&state->Ref, 1); - - state->OutBuffer = NULL; - state->OutChannels = 0; -} - -void ALeffectState_Destruct(ALeffectState *UNUSED(state)) -{ -} - - -static void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) -{ - struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots, - almemory_order_acquire); - struct ALeffectslotArray *newarray = NULL; - ALsizei newcount = curarray->count + count; - ALCdevice *device = context->Device; - ALsizei i, j; - - /* Insert the new effect slots into the head of the array, followed by the - * existing ones. - */ - newarray = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, newcount)); - newarray->count = newcount; - for(i = 0;i < count;i++) - newarray->slot[i] = LookupEffectSlot(context, slotids[i]); - for(j = 0;i < newcount;) - newarray->slot[i++] = curarray->slot[j++]; - /* Remove any duplicates (first instance of each will be kept). */ - for(i = 1;i < newcount;i++) - { - for(j = i;j != 0;) - { - if(UNLIKELY(newarray->slot[i] == newarray->slot[--j])) - { - newcount--; - for(j = i;j < newcount;j++) - newarray->slot[j] = newarray->slot[j+1]; - i--; - break; - } - } - } - - /* Reallocate newarray if the new size ended up smaller from duplicate - * removal. - */ - if(UNLIKELY(newcount < newarray->count)) - { - struct ALeffectslotArray *tmpnewarray = al_calloc(DEF_ALIGN, - FAM_SIZE(struct ALeffectslotArray, slot, newcount)); - memcpy(tmpnewarray, newarray, FAM_SIZE(struct ALeffectslotArray, slot, newcount)); - al_free(newarray); - newarray = tmpnewarray; - newarray->count = newcount; - } - - curarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray, almemory_order_acq_rel); - while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) - althrd_yield(); - al_free(curarray); -} - -static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) -{ - struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots, - almemory_order_acquire); - struct ALeffectslotArray *newarray = NULL; - ALCdevice *device = context->Device; - ALsizei i, j; - - /* Don't shrink the allocated array size since we don't know how many (if - * any) of the effect slots to remove are in the array. - */ - newarray = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, curarray->count)); - newarray->count = 0; - for(i = 0;i < curarray->count;i++) - { - /* Insert this slot into the new array only if it's not one to remove. */ - ALeffectslot *slot = curarray->slot[i]; - for(j = count;j != 0;) - { - if(slot->id == slotids[--j]) - goto skip_ins; - } - newarray->slot[newarray->count++] = slot; - skip_ins: ; - } - - /* TODO: Could reallocate newarray now that we know it's needed size. */ - - curarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray, almemory_order_acq_rel); - while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) - althrd_yield(); - al_free(curarray); -} - - -ALenum InitEffectSlot(ALeffectslot *slot) -{ - EffectStateFactory *factory; - - slot->Effect.Type = AL_EFFECT_NULL; - - factory = getFactoryByType(AL_EFFECT_NULL); - slot->Effect.State = EffectStateFactory_create(factory); - if(!slot->Effect.State) return AL_OUT_OF_MEMORY; - - slot->Gain = 1.0; - slot->AuxSendAuto = AL_TRUE; - ATOMIC_INIT(&slot->PropsClean, AL_TRUE); - InitRef(&slot->ref, 0); - - ATOMIC_INIT(&slot->Update, NULL); - - slot->Params.Gain = 1.0f; - slot->Params.AuxSendAuto = AL_TRUE; - ALeffectState_IncRef(slot->Effect.State); - slot->Params.EffectState = slot->Effect.State; - slot->Params.RoomRolloff = 0.0f; - slot->Params.DecayTime = 0.0f; - slot->Params.DecayLFRatio = 0.0f; - slot->Params.DecayHFRatio = 0.0f; - slot->Params.DecayHFLimit = AL_FALSE; - slot->Params.AirAbsorptionGainHF = 1.0f; - - return AL_NO_ERROR; -} - -void DeinitEffectSlot(ALeffectslot *slot) -{ - struct ALeffectslotProps *props; - - props = ATOMIC_LOAD_SEQ(&slot->Update); - if(props) - { - if(props->State) ALeffectState_DecRef(props->State); - TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props); - al_free(props); - } - - ALeffectState_DecRef(slot->Effect.State); - if(slot->Params.EffectState) - ALeffectState_DecRef(slot->Params.EffectState); -} - -void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) -{ - struct ALeffectslotProps *props; - ALeffectState *oldstate; - - /* Get an unused property container, or allocate a new one as needed. */ - props = ATOMIC_LOAD(&context->FreeEffectslotProps, almemory_order_relaxed); - if(!props) - props = al_calloc(16, sizeof(*props)); - else - { - struct ALeffectslotProps *next; - do { - next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeEffectslotProps, &props, next, - almemory_order_seq_cst, almemory_order_acquire) == 0); - } - - /* Copy in current property values. */ - props->Gain = slot->Gain; - props->AuxSendAuto = slot->AuxSendAuto; - - props->Type = slot->Effect.Type; - props->Props = slot->Effect.Props; - /* Swap out any stale effect state object there may be in the container, to - * delete it. - */ - ALeffectState_IncRef(slot->Effect.State); - oldstate = props->State; - props->State = slot->Effect.State; - - /* Set the new container for updating internal parameters. */ - props = ATOMIC_EXCHANGE_PTR(&slot->Update, props, almemory_order_acq_rel); - if(props) - { - /* If there was an unused update container, put it back in the - * freelist. - */ - if(props->State) - ALeffectState_DecRef(props->State); - props->State = NULL; - ATOMIC_REPLACE_HEAD(struct ALeffectslotProps*, &context->FreeEffectslotProps, props); - } - - if(oldstate) - ALeffectState_DecRef(oldstate); -} - -void UpdateAllEffectSlotProps(ALCcontext *context) -{ - struct ALeffectslotArray *auxslots; - ALsizei i; - - LockEffectSlotList(context); - auxslots = ATOMIC_LOAD(&context->ActiveAuxSlots, almemory_order_acquire); - for(i = 0;i < auxslots->count;i++) - { - ALeffectslot *slot = auxslots->slot[i]; - if(!ATOMIC_EXCHANGE(&slot->PropsClean, AL_TRUE, almemory_order_acq_rel)) - UpdateEffectSlotProps(slot, context); - } - UnlockEffectSlotList(context); -} - -ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *context) -{ - ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList); - ALeffectslotPtr *end = VECTOR_END(context->EffectSlotList); - size_t leftover = 0; - - for(;iter != end;iter++) - { - ALeffectslot *slot = *iter; - if(!slot) continue; - *iter = NULL; - - DeinitEffectSlot(slot); - - memset(slot, 0, sizeof(*slot)); - al_free(slot); - ++leftover; - } - if(leftover > 0) - WARN("(%p) Deleted "SZFMT" AuxiliaryEffectSlot%s\n", context, leftover, (leftover==1)?"":"s"); -} diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp new file mode 100644 index 00000000..18bad2d4 --- /dev/null +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -0,0 +1,802 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "alMain.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alListener.h" +#include "alSource.h" + +#include "fpu_modes.h" +#include "almalloc.h" + + +static void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context); +static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context); + +static const struct { + ALenum Type; + EffectStateFactory* (*GetFactory)(void); +} FactoryList[] = { + { AL_EFFECT_NULL, NullStateFactory_getFactory }, + { AL_EFFECT_EAXREVERB, ReverbStateFactory_getFactory }, + { AL_EFFECT_REVERB, ReverbStateFactory_getFactory }, + { AL_EFFECT_AUTOWAH, AutowahStateFactory_getFactory }, + { AL_EFFECT_CHORUS, ChorusStateFactory_getFactory }, + { AL_EFFECT_COMPRESSOR, CompressorStateFactory_getFactory }, + { AL_EFFECT_DISTORTION, DistortionStateFactory_getFactory }, + { AL_EFFECT_ECHO, EchoStateFactory_getFactory }, + { AL_EFFECT_EQUALIZER, EqualizerStateFactory_getFactory }, + { AL_EFFECT_FLANGER, FlangerStateFactory_getFactory }, + { AL_EFFECT_FREQUENCY_SHIFTER, FshifterStateFactory_getFactory }, + { AL_EFFECT_RING_MODULATOR, ModulatorStateFactory_getFactory }, + { AL_EFFECT_PITCH_SHIFTER, PshifterStateFactory_getFactory}, + { AL_EFFECT_DEDICATED_DIALOGUE, DedicatedStateFactory_getFactory }, + { AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedStateFactory_getFactory } +}; + +static inline EffectStateFactory *getFactoryByType(ALenum type) +{ + size_t i; + for(i = 0;i < COUNTOF(FactoryList);i++) + { + if(FactoryList[i].Type == type) + return FactoryList[i].GetFactory(); + } + return nullptr; +} + +static void ALeffectState_IncRef(ALeffectState *state); + + +static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) +{ + id--; + if(UNLIKELY(id >= VECTOR_SIZE(context->EffectSlotList))) + return nullptr; + return VECTOR_ELEM(context->EffectSlotList, id); +} + +static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) +{ + EffectSubList *sublist; + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= VECTOR_SIZE(device->EffectList))) + return nullptr; + sublist = &VECTOR_ELEM(device->EffectList, lidx); + if(UNLIKELY(sublist->FreeMask & (U64(1)<Effects + slidx; +} + + +#define DO_UPDATEPROPS() do { \ + if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \ + UpdateEffectSlotProps(slot, context); \ + else \ + ATOMIC_STORE(&slot->PropsClean, AL_FALSE, almemory_order_release); \ +} while(0) + + +AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) +{ + ALCdevice *device; + ALCcontext *context; + ALsizei cur; + + context = GetContextRef(); + if(!context) return; + + if(n < 0) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d effect slots", n); + if(n == 0) goto done; + + LockEffectSlotList(context); + device = context->Device; + for(cur = 0;cur < n;cur++) + { + ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList); + ALeffectslotPtr *end = VECTOR_END(context->EffectSlotList); + ALeffectslot *slot = nullptr; + ALenum err = AL_OUT_OF_MEMORY; + + for(;iter != end;iter++) + { + if(!*iter) + break; + } + if(iter == end) + { + if(device->AuxiliaryEffectSlotMax == VECTOR_SIZE(context->EffectSlotList)) + { + UnlockEffectSlotList(context); + alDeleteAuxiliaryEffectSlots(cur, effectslots); + SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, + "Exceeding %u auxiliary effect slot limit", device->AuxiliaryEffectSlotMax); + } + VECTOR_PUSH_BACK(context->EffectSlotList, nullptr); + iter = &VECTOR_BACK(context->EffectSlotList); + } + slot = static_cast(al_calloc(16, sizeof(ALeffectslot))); + if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR) + { + al_free(slot); + UnlockEffectSlotList(context); + + alDeleteAuxiliaryEffectSlots(cur, effectslots); + SETERR_GOTO(context, err, done, "Effect slot object allocation failed"); + } + aluInitEffectPanning(slot); + + slot->id = (iter - VECTOR_BEGIN(context->EffectSlotList)) + 1; + *iter = slot; + + effectslots[cur] = slot->id; + } + AddActiveEffectSlots(effectslots, n, context); + UnlockEffectSlotList(context); + +done: + ALCcontext_DecRef(context); +} + +AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots) +{ + ALCcontext *context; + ALeffectslot *slot; + ALsizei i; + + context = GetContextRef(); + if(!context) return; + + LockEffectSlotList(context); + if(n < 0) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effect slots", n); + if(n == 0) goto done; + + for(i = 0;i < n;i++) + { + if((slot=LookupEffectSlot(context, effectslots[i])) == nullptr) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", + effectslots[i]); + if(ReadRef(&slot->ref) != 0) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Deleting in-use effect slot %u", + effectslots[i]); + } + + // All effectslots are valid + RemoveActiveEffectSlots(effectslots, n, context); + for(i = 0;i < n;i++) + { + if((slot=LookupEffectSlot(context, effectslots[i])) == nullptr) + continue; + VECTOR_ELEM(context->EffectSlotList, effectslots[i]-1) = nullptr; + + DeinitEffectSlot(slot); + + memset(slot, 0, sizeof(*slot)); + al_free(slot); + } + +done: + UnlockEffectSlotList(context); + ALCcontext_DecRef(context); +} + +AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot) +{ + ALCcontext *context; + ALboolean ret; + + context = GetContextRef(); + if(!context) return AL_FALSE; + + LockEffectSlotList(context); + ret = (LookupEffectSlot(context, effectslot) ? AL_TRUE : AL_FALSE); + UnlockEffectSlotList(context); + + ALCcontext_DecRef(context); + + return ret; +} + +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value) +{ + ALCdevice *device; + ALCcontext *context; + ALeffectslot *slot; + ALeffect *effect = nullptr; + ALenum err; + + context = GetContextRef(); + if(!context) return; + + almtx_lock(&context->PropLock); + LockEffectSlotList(context); + if((slot=LookupEffectSlot(context, effectslot)) == nullptr) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); + switch(param) + { + case AL_EFFECTSLOT_EFFECT: + device = context->Device; + + LockEffectList(device); + effect = (value ? LookupEffect(device, value) : nullptr); + if(!(value == 0 || effect != nullptr)) + { + UnlockEffectList(device); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Invalid effect ID %u", value); + } + err = InitializeEffect(context, slot, effect); + UnlockEffectList(device); + + if(err != AL_NO_ERROR) + SETERR_GOTO(context, err, done, "Effect initialization failed"); + break; + + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + if(!(value == AL_TRUE || value == AL_FALSE)) + SETERR_GOTO(context, AL_INVALID_VALUE, done, + "Effect slot auxiliary send auto out of range"); + slot->AuxSendAuto = value; + break; + + default: + SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid effect slot integer property 0x%04x", + param); + } + DO_UPDATEPROPS(); + +done: + UnlockEffectSlotList(context); + almtx_unlock(&context->PropLock); + ALCcontext_DecRef(context); +} + +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values) +{ + ALCcontext *context; + + switch(param) + { + case AL_EFFECTSLOT_EFFECT: + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + alAuxiliaryEffectSloti(effectslot, param, values[0]); + return; + } + + context = GetContextRef(); + if(!context) return; + + LockEffectSlotList(context); + if(LookupEffectSlot(context, effectslot) == nullptr) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer-vector property 0x%04x", + param); + } + +done: + UnlockEffectSlotList(context); + ALCcontext_DecRef(context); +} + +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value) +{ + ALCcontext *context; + ALeffectslot *slot; + + context = GetContextRef(); + if(!context) return; + + almtx_lock(&context->PropLock); + LockEffectSlotList(context); + if((slot=LookupEffectSlot(context, effectslot)) == nullptr) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); + switch(param) + { + case AL_EFFECTSLOT_GAIN: + if(!(value >= 0.0f && value <= 1.0f)) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Effect slot gain out of range"); + slot->Gain = value; + break; + + default: + SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid effect slot float property 0x%04x", + param); + } + DO_UPDATEPROPS(); + +done: + UnlockEffectSlotList(context); + almtx_unlock(&context->PropLock); + ALCcontext_DecRef(context); +} + +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values) +{ + ALCcontext *context; + + switch(param) + { + case AL_EFFECTSLOT_GAIN: + alAuxiliaryEffectSlotf(effectslot, param, values[0]); + return; + } + + context = GetContextRef(); + if(!context) return; + + LockEffectSlotList(context); + if(LookupEffectSlot(context, effectslot) == nullptr) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float-vector property 0x%04x", + param); + } + +done: + UnlockEffectSlotList(context); + ALCcontext_DecRef(context); +} + +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value) +{ + ALCcontext *context; + ALeffectslot *slot; + + context = GetContextRef(); + if(!context) return; + + LockEffectSlotList(context); + if((slot=LookupEffectSlot(context, effectslot)) == nullptr) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); + switch(param) + { + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + *value = slot->AuxSendAuto; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer property 0x%04x", param); + } + +done: + UnlockEffectSlotList(context); + ALCcontext_DecRef(context); +} + +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values) +{ + ALCcontext *context; + + switch(param) + { + case AL_EFFECTSLOT_EFFECT: + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + alGetAuxiliaryEffectSloti(effectslot, param, values); + return; + } + + context = GetContextRef(); + if(!context) return; + + LockEffectSlotList(context); + if(LookupEffectSlot(context, effectslot) == nullptr) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer-vector property 0x%04x", + param); + } + +done: + UnlockEffectSlotList(context); + ALCcontext_DecRef(context); +} + +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value) +{ + ALCcontext *context; + ALeffectslot *slot; + + context = GetContextRef(); + if(!context) return; + + LockEffectSlotList(context); + if((slot=LookupEffectSlot(context, effectslot)) == nullptr) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); + switch(param) + { + case AL_EFFECTSLOT_GAIN: + *value = slot->Gain; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float property 0x%04x", param); + } + +done: + UnlockEffectSlotList(context); + ALCcontext_DecRef(context); +} + +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values) +{ + ALCcontext *context; + + switch(param) + { + case AL_EFFECTSLOT_GAIN: + alGetAuxiliaryEffectSlotf(effectslot, param, values); + return; + } + + context = GetContextRef(); + if(!context) return; + + LockEffectSlotList(context); + if(LookupEffectSlot(context, effectslot) == nullptr) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float-vector property 0x%04x", + param); + } + +done: + UnlockEffectSlotList(context); + ALCcontext_DecRef(context); +} + + +ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect) +{ + ALCdevice *Device = Context->Device; + ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL); + struct ALeffectslotProps *props; + ALeffectState *State; + + if(newtype != EffectSlot->Effect.Type) + { + EffectStateFactory *factory; + + factory = getFactoryByType(newtype); + if(!factory) + { + ERR("Failed to find factory for effect type 0x%04x\n", newtype); + return AL_INVALID_ENUM; + } + State = EffectStateFactory_create(factory); + if(!State) return AL_OUT_OF_MEMORY; + + START_MIXER_MODE(); + almtx_lock(&Device->BackendLock); + State->OutBuffer = Device->Dry.Buffer; + State->OutChannels = Device->Dry.NumChannels; + if(V(State,deviceUpdate)(Device) == AL_FALSE) + { + almtx_unlock(&Device->BackendLock); + LEAVE_MIXER_MODE(); + ALeffectState_DecRef(State); + return AL_OUT_OF_MEMORY; + } + almtx_unlock(&Device->BackendLock); + END_MIXER_MODE(); + + if(!effect) + { + EffectSlot->Effect.Type = AL_EFFECT_NULL; + memset(&EffectSlot->Effect.Props, 0, sizeof(EffectSlot->Effect.Props)); + } + else + { + EffectSlot->Effect.Type = effect->type; + EffectSlot->Effect.Props = effect->Props; + } + + ALeffectState_DecRef(EffectSlot->Effect.State); + EffectSlot->Effect.State = State; + } + else if(effect) + EffectSlot->Effect.Props = effect->Props; + + /* Remove state references from old effect slot property updates. */ + props = ATOMIC_LOAD_SEQ(&Context->FreeEffectslotProps); + while(props) + { + if(props->State) + ALeffectState_DecRef(props->State); + props->State = nullptr; + props = ATOMIC_LOAD(&props->next, almemory_order_relaxed); + } + + return AL_NO_ERROR; +} + + +static void ALeffectState_IncRef(ALeffectState *state) +{ + uint ref; + ref = IncrementRef(&state->Ref); + TRACEREF("%p increasing refcount to %u\n", state, ref); +} + +void ALeffectState_DecRef(ALeffectState *state) +{ + uint ref; + ref = DecrementRef(&state->Ref); + TRACEREF("%p decreasing refcount to %u\n", state, ref); + if(ref == 0) DELETE_OBJ(state); +} + + +void ALeffectState_Construct(ALeffectState *state) +{ + InitRef(&state->Ref, 1); + + state->OutBuffer = nullptr; + state->OutChannels = 0; +} + +void ALeffectState_Destruct(ALeffectState *UNUSED(state)) +{ +} + + +static void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) +{ + struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots, + almemory_order_acquire); + struct ALeffectslotArray *newarray = nullptr; + ALsizei newcount = curarray->count + count; + ALCdevice *device = context->Device; + ALsizei i, j; + + /* Insert the new effect slots into the head of the array, followed by the + * existing ones. + */ + newarray = static_cast(al_calloc(DEF_ALIGN, + FAM_SIZE(struct ALeffectslotArray, slot, newcount))); + newarray->count = newcount; + for(i = 0;i < count;i++) + newarray->slot[i] = LookupEffectSlot(context, slotids[i]); + for(j = 0;i < newcount;) + newarray->slot[i++] = curarray->slot[j++]; + /* Remove any duplicates (first instance of each will be kept). */ + for(i = 1;i < newcount;i++) + { + for(j = i;j != 0;) + { + if(UNLIKELY(newarray->slot[i] == newarray->slot[--j])) + { + newcount--; + for(j = i;j < newcount;j++) + newarray->slot[j] = newarray->slot[j+1]; + i--; + break; + } + } + } + + /* Reallocate newarray if the new size ended up smaller from duplicate + * removal. + */ + if(UNLIKELY(newcount < newarray->count)) + { + struct ALeffectslotArray *tmp = static_cast(al_calloc(DEF_ALIGN, + FAM_SIZE(struct ALeffectslotArray, slot, newcount))); + memcpy(tmp, newarray, FAM_SIZE(struct ALeffectslotArray, slot, newcount)); + al_free(newarray); + newarray = tmp; + newarray->count = newcount; + } + + curarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray, almemory_order_acq_rel); + while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) + althrd_yield(); + al_free(curarray); +} + +static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) +{ + struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots, + almemory_order_acquire); + struct ALeffectslotArray *newarray = nullptr; + ALCdevice *device = context->Device; + ALsizei i, j; + + /* Don't shrink the allocated array size since we don't know how many (if + * any) of the effect slots to remove are in the array. + */ + newarray = static_cast(al_calloc(DEF_ALIGN, + FAM_SIZE(struct ALeffectslotArray, slot, curarray->count))); + newarray->count = 0; + for(i = 0;i < curarray->count;i++) + { + /* Insert this slot into the new array only if it's not one to remove. */ + ALeffectslot *slot = curarray->slot[i]; + for(j = count;j != 0;) + { + if(slot->id == slotids[--j]) + goto skip_ins; + } + newarray->slot[newarray->count++] = slot; + skip_ins: ; + } + + /* TODO: Could reallocate newarray now that we know it's needed size. */ + + curarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray, almemory_order_acq_rel); + while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) + althrd_yield(); + al_free(curarray); +} + + +ALenum InitEffectSlot(ALeffectslot *slot) +{ + EffectStateFactory *factory; + + slot->Effect.Type = AL_EFFECT_NULL; + + factory = getFactoryByType(AL_EFFECT_NULL); + slot->Effect.State = EffectStateFactory_create(factory); + if(!slot->Effect.State) return AL_OUT_OF_MEMORY; + + slot->Gain = 1.0; + slot->AuxSendAuto = AL_TRUE; + ATOMIC_INIT(&slot->PropsClean, AL_TRUE); + InitRef(&slot->ref, 0); + + ATOMIC_INIT(&slot->Update, static_cast(nullptr)); + + slot->Params.Gain = 1.0f; + slot->Params.AuxSendAuto = AL_TRUE; + ALeffectState_IncRef(slot->Effect.State); + slot->Params.EffectState = slot->Effect.State; + slot->Params.RoomRolloff = 0.0f; + slot->Params.DecayTime = 0.0f; + slot->Params.DecayLFRatio = 0.0f; + slot->Params.DecayHFRatio = 0.0f; + slot->Params.DecayHFLimit = AL_FALSE; + slot->Params.AirAbsorptionGainHF = 1.0f; + + return AL_NO_ERROR; +} + +void DeinitEffectSlot(ALeffectslot *slot) +{ + struct ALeffectslotProps *props; + + props = ATOMIC_LOAD_SEQ(&slot->Update); + if(props) + { + if(props->State) ALeffectState_DecRef(props->State); + TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props); + al_free(props); + } + + ALeffectState_DecRef(slot->Effect.State); + if(slot->Params.EffectState) + ALeffectState_DecRef(slot->Params.EffectState); +} + +void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) +{ + struct ALeffectslotProps *props; + ALeffectState *oldstate; + + /* Get an unused property container, or allocate a new one as needed. */ + props = ATOMIC_LOAD(&context->FreeEffectslotProps, almemory_order_relaxed); + if(!props) + props = static_cast(al_calloc(16, sizeof(*props))); + else + { + struct ALeffectslotProps *next; + do { + next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); + } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeEffectslotProps, &props, next, + almemory_order_seq_cst, almemory_order_acquire) == 0); + } + + /* Copy in current property values. */ + props->Gain = slot->Gain; + props->AuxSendAuto = slot->AuxSendAuto; + + props->Type = slot->Effect.Type; + props->Props = slot->Effect.Props; + /* Swap out any stale effect state object there may be in the container, to + * delete it. + */ + ALeffectState_IncRef(slot->Effect.State); + oldstate = props->State; + props->State = slot->Effect.State; + + /* Set the new container for updating internal parameters. */ + props = static_cast(ATOMIC_EXCHANGE_PTR(&slot->Update, props, + almemory_order_acq_rel)); + if(props) + { + /* If there was an unused update container, put it back in the + * freelist. + */ + if(props->State) + ALeffectState_DecRef(props->State); + props->State = nullptr; + ATOMIC_REPLACE_HEAD(struct ALeffectslotProps*, &context->FreeEffectslotProps, props); + } + + if(oldstate) + ALeffectState_DecRef(oldstate); +} + +void UpdateAllEffectSlotProps(ALCcontext *context) +{ + struct ALeffectslotArray *auxslots; + ALsizei i; + + LockEffectSlotList(context); + auxslots = ATOMIC_LOAD(&context->ActiveAuxSlots, almemory_order_acquire); + for(i = 0;i < auxslots->count;i++) + { + ALeffectslot *slot = auxslots->slot[i]; + if(!ATOMIC_EXCHANGE(&slot->PropsClean, AL_TRUE, almemory_order_acq_rel)) + UpdateEffectSlotProps(slot, context); + } + UnlockEffectSlotList(context); +} + +ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *context) +{ + ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList); + ALeffectslotPtr *end = VECTOR_END(context->EffectSlotList); + size_t leftover = 0; + + for(;iter != end;iter++) + { + ALeffectslot *slot = *iter; + if(!slot) continue; + *iter = nullptr; + + DeinitEffectSlot(slot); + + memset(slot, 0, sizeof(*slot)); + al_free(slot); + ++leftover; + } + if(leftover > 0) + WARN("(%p) Deleted " SZFMT " AuxiliaryEffectSlot%s\n", context, leftover, (leftover==1)?"":"s"); +} -- cgit v1.2.3 From a15a678da689681251312f19a30bc49e781e2c1d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Nov 2018 18:37:55 -0800 Subject: Convert alListener.c to C++ --- CMakeLists.txt | 2 +- OpenAL32/alListener.c | 502 ----------------------------------------------- OpenAL32/alListener.cpp | 503 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 504 insertions(+), 503 deletions(-) delete mode 100644 OpenAL32/alListener.c create mode 100644 OpenAL32/alListener.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index df190c60..30375389 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -789,7 +789,7 @@ SET(OPENAL_OBJS OpenAL32/Include/alFilter.h OpenAL32/alFilter.c OpenAL32/Include/alListener.h - OpenAL32/alListener.c + OpenAL32/alListener.cpp OpenAL32/Include/alSource.h OpenAL32/alSource.cpp OpenAL32/alState.cpp diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c deleted file mode 100644 index 700fa0af..00000000 --- a/OpenAL32/alListener.c +++ /dev/null @@ -1,502 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2000 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "alMain.h" -#include "alu.h" -#include "alError.h" -#include "alListener.h" -#include "alSource.h" - -#define DO_UPDATEPROPS() do { \ - if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \ - UpdateListenerProps(context); \ - else \ - ATOMIC_STORE(&listener->PropsClean, AL_FALSE, almemory_order_release);\ -} while(0) - - -AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) -{ - ALlistener *listener; - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - listener = context->Listener; - almtx_lock(&context->PropLock); - switch(param) - { - case AL_GAIN: - if(!(value >= 0.0f && isfinite(value))) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener gain out of range"); - listener->Gain = value; - DO_UPDATEPROPS(); - break; - - case AL_METERS_PER_UNIT: - if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener meters per unit out of range"); - context->MetersPerUnit = value; - if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - UpdateContextProps(context); - else - ATOMIC_STORE(&context->PropsClean, AL_FALSE, almemory_order_release); - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener float property"); - } - -done: - almtx_unlock(&context->PropLock); - ALCcontext_DecRef(context); -} - - -AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) -{ - ALlistener *listener; - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - listener = context->Listener; - almtx_lock(&context->PropLock); - switch(param) - { - case AL_POSITION: - if(!(isfinite(value1) && isfinite(value2) && isfinite(value3))) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener position out of range"); - listener->Position[0] = value1; - listener->Position[1] = value2; - listener->Position[2] = value3; - DO_UPDATEPROPS(); - break; - - case AL_VELOCITY: - if(!(isfinite(value1) && isfinite(value2) && isfinite(value3))) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener velocity out of range"); - listener->Velocity[0] = value1; - listener->Velocity[1] = value2; - listener->Velocity[2] = value3; - DO_UPDATEPROPS(); - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-float property"); - } - -done: - almtx_unlock(&context->PropLock); - ALCcontext_DecRef(context); -} - - -AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) -{ - ALlistener *listener; - ALCcontext *context; - - if(values) - { - switch(param) - { - case AL_GAIN: - case AL_METERS_PER_UNIT: - alListenerf(param, values[0]); - return; - - case AL_POSITION: - case AL_VELOCITY: - alListener3f(param, values[0], values[1], values[2]); - return; - } - } - - context = GetContextRef(); - if(!context) return; - - listener = context->Listener; - almtx_lock(&context->PropLock); - if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); - switch(param) - { - case AL_ORIENTATION: - if(!(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) && - isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]))) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener orientation out of range"); - /* AT then UP */ - listener->Forward[0] = values[0]; - listener->Forward[1] = values[1]; - listener->Forward[2] = values[2]; - listener->Up[0] = values[3]; - listener->Up[1] = values[4]; - listener->Up[2] = values[5]; - DO_UPDATEPROPS(); - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener float-vector property"); - } - -done: - almtx_unlock(&context->PropLock); - ALCcontext_DecRef(context); -} - - -AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value)) -{ - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - almtx_lock(&context->PropLock); - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener integer property"); - } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); -} - - -AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3) -{ - ALCcontext *context; - - switch(param) - { - case AL_POSITION: - case AL_VELOCITY: - alListener3f(param, (ALfloat)value1, (ALfloat)value2, (ALfloat)value3); - return; - } - - context = GetContextRef(); - if(!context) return; - - almtx_lock(&context->PropLock); - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-integer property"); - } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); -} - - -AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values) -{ - ALCcontext *context; - - if(values) - { - ALfloat fvals[6]; - switch(param) - { - case AL_POSITION: - case AL_VELOCITY: - alListener3f(param, (ALfloat)values[0], (ALfloat)values[1], (ALfloat)values[2]); - return; - - case AL_ORIENTATION: - fvals[0] = (ALfloat)values[0]; - fvals[1] = (ALfloat)values[1]; - fvals[2] = (ALfloat)values[2]; - fvals[3] = (ALfloat)values[3]; - fvals[4] = (ALfloat)values[4]; - fvals[5] = (ALfloat)values[5]; - alListenerfv(param, fvals); - return; - } - } - - context = GetContextRef(); - if(!context) return; - - almtx_lock(&context->PropLock); - if(!values) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener integer-vector property"); - } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); -} - - -AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) -{ - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - almtx_lock(&context->PropLock); - if(!value) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_GAIN: - *value = context->Listener->Gain; - break; - - case AL_METERS_PER_UNIT: - *value = context->MetersPerUnit; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener float property"); - } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); -} - - -AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) -{ - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - almtx_lock(&context->PropLock); - if(!value1 || !value2 || !value3) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_POSITION: - *value1 = context->Listener->Position[0]; - *value2 = context->Listener->Position[1]; - *value3 = context->Listener->Position[2]; - break; - - case AL_VELOCITY: - *value1 = context->Listener->Velocity[0]; - *value2 = context->Listener->Velocity[1]; - *value3 = context->Listener->Velocity[2]; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-float property"); - } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); -} - - -AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) -{ - ALCcontext *context; - - switch(param) - { - case AL_GAIN: - case AL_METERS_PER_UNIT: - alGetListenerf(param, values); - return; - - case AL_POSITION: - case AL_VELOCITY: - alGetListener3f(param, values+0, values+1, values+2); - return; - } - - context = GetContextRef(); - if(!context) return; - - almtx_lock(&context->PropLock); - if(!values) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_ORIENTATION: - // AT then UP - values[0] = context->Listener->Forward[0]; - values[1] = context->Listener->Forward[1]; - values[2] = context->Listener->Forward[2]; - values[3] = context->Listener->Up[0]; - values[4] = context->Listener->Up[1]; - values[5] = context->Listener->Up[2]; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener float-vector property"); - } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); -} - - -AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value) -{ - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - almtx_lock(&context->PropLock); - if(!value) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener integer property"); - } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); -} - - -AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3) -{ - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - almtx_lock(&context->PropLock); - if(!value1 || !value2 || !value3) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_POSITION: - *value1 = (ALint)context->Listener->Position[0]; - *value2 = (ALint)context->Listener->Position[1]; - *value3 = (ALint)context->Listener->Position[2]; - break; - - case AL_VELOCITY: - *value1 = (ALint)context->Listener->Velocity[0]; - *value2 = (ALint)context->Listener->Velocity[1]; - *value3 = (ALint)context->Listener->Velocity[2]; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-integer property"); - } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); -} - - -AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) -{ - ALCcontext *context; - - switch(param) - { - case AL_POSITION: - case AL_VELOCITY: - alGetListener3i(param, values+0, values+1, values+2); - return; - } - - context = GetContextRef(); - if(!context) return; - - almtx_lock(&context->PropLock); - if(!values) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_ORIENTATION: - // AT then UP - values[0] = (ALint)context->Listener->Forward[0]; - values[1] = (ALint)context->Listener->Forward[1]; - values[2] = (ALint)context->Listener->Forward[2]; - values[3] = (ALint)context->Listener->Up[0]; - values[4] = (ALint)context->Listener->Up[1]; - values[5] = (ALint)context->Listener->Up[2]; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener integer-vector property"); - } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); -} - - -void UpdateListenerProps(ALCcontext *context) -{ - ALlistener *listener = context->Listener; - struct ALlistenerProps *props; - - /* Get an unused proprty container, or allocate a new one as needed. */ - props = ATOMIC_LOAD(&context->FreeListenerProps, almemory_order_acquire); - if(!props) - props = al_calloc(16, sizeof(*props)); - else - { - struct ALlistenerProps *next; - do { - next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeListenerProps, &props, next, - almemory_order_seq_cst, almemory_order_acquire) == 0); - } - - /* Copy in current property values. */ - props->Position[0] = listener->Position[0]; - props->Position[1] = listener->Position[1]; - props->Position[2] = listener->Position[2]; - - props->Velocity[0] = listener->Velocity[0]; - props->Velocity[1] = listener->Velocity[1]; - props->Velocity[2] = listener->Velocity[2]; - - props->Forward[0] = listener->Forward[0]; - props->Forward[1] = listener->Forward[1]; - props->Forward[2] = listener->Forward[2]; - props->Up[0] = listener->Up[0]; - props->Up[1] = listener->Up[1]; - props->Up[2] = listener->Up[2]; - - props->Gain = listener->Gain; - - /* Set the new container for updating internal parameters. */ - props = ATOMIC_EXCHANGE_PTR(&listener->Update, props, almemory_order_acq_rel); - if(props) - { - /* If there was an unused update container, put it back in the - * freelist. - */ - ATOMIC_REPLACE_HEAD(struct ALlistenerProps*, &context->FreeListenerProps, props); - } -} diff --git a/OpenAL32/alListener.cpp b/OpenAL32/alListener.cpp new file mode 100644 index 00000000..809b0318 --- /dev/null +++ b/OpenAL32/alListener.cpp @@ -0,0 +1,503 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2000 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "alMain.h" +#include "alu.h" +#include "alError.h" +#include "alListener.h" +#include "alSource.h" + +#define DO_UPDATEPROPS() do { \ + if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \ + UpdateListenerProps(context); \ + else \ + ATOMIC_STORE(&listener->PropsClean, AL_FALSE, almemory_order_release);\ +} while(0) + + +AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) +{ + ALlistener *listener; + ALCcontext *context; + + context = GetContextRef(); + if(!context) return; + + listener = context->Listener; + almtx_lock(&context->PropLock); + switch(param) + { + case AL_GAIN: + if(!(value >= 0.0f && isfinite(value))) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener gain out of range"); + listener->Gain = value; + DO_UPDATEPROPS(); + break; + + case AL_METERS_PER_UNIT: + if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT)) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener meters per unit out of range"); + context->MetersPerUnit = value; + if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + UpdateContextProps(context); + else + ATOMIC_STORE(&context->PropsClean, AL_FALSE, almemory_order_release); + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid listener float property"); + } + +done: + almtx_unlock(&context->PropLock); + ALCcontext_DecRef(context); +} + + +AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) +{ + ALlistener *listener; + ALCcontext *context; + + context = GetContextRef(); + if(!context) return; + + listener = context->Listener; + almtx_lock(&context->PropLock); + switch(param) + { + case AL_POSITION: + if(!(isfinite(value1) && isfinite(value2) && isfinite(value3))) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener position out of range"); + listener->Position[0] = value1; + listener->Position[1] = value2; + listener->Position[2] = value3; + DO_UPDATEPROPS(); + break; + + case AL_VELOCITY: + if(!(isfinite(value1) && isfinite(value2) && isfinite(value3))) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener velocity out of range"); + listener->Velocity[0] = value1; + listener->Velocity[1] = value2; + listener->Velocity[2] = value3; + DO_UPDATEPROPS(); + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-float property"); + } + +done: + almtx_unlock(&context->PropLock); + ALCcontext_DecRef(context); +} + + +AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) +{ + ALlistener *listener; + ALCcontext *context; + + if(values) + { + switch(param) + { + case AL_GAIN: + case AL_METERS_PER_UNIT: + alListenerf(param, values[0]); + return; + + case AL_POSITION: + case AL_VELOCITY: + alListener3f(param, values[0], values[1], values[2]); + return; + } + } + + context = GetContextRef(); + if(!context) return; + + listener = context->Listener; + almtx_lock(&context->PropLock); + if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); + switch(param) + { + case AL_ORIENTATION: + if(!(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) && + isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]))) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener orientation out of range"); + /* AT then UP */ + listener->Forward[0] = values[0]; + listener->Forward[1] = values[1]; + listener->Forward[2] = values[2]; + listener->Up[0] = values[3]; + listener->Up[1] = values[4]; + listener->Up[2] = values[5]; + DO_UPDATEPROPS(); + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid listener float-vector property"); + } + +done: + almtx_unlock(&context->PropLock); + ALCcontext_DecRef(context); +} + + +AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value)) +{ + ALCcontext *context; + + context = GetContextRef(); + if(!context) return; + + almtx_lock(&context->PropLock); + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM, "Invalid listener integer property"); + } + almtx_unlock(&context->PropLock); + + ALCcontext_DecRef(context); +} + + +AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3) +{ + ALCcontext *context; + + switch(param) + { + case AL_POSITION: + case AL_VELOCITY: + alListener3f(param, (ALfloat)value1, (ALfloat)value2, (ALfloat)value3); + return; + } + + context = GetContextRef(); + if(!context) return; + + almtx_lock(&context->PropLock); + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-integer property"); + } + almtx_unlock(&context->PropLock); + + ALCcontext_DecRef(context); +} + + +AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values) +{ + ALCcontext *context; + + if(values) + { + ALfloat fvals[6]; + switch(param) + { + case AL_POSITION: + case AL_VELOCITY: + alListener3f(param, (ALfloat)values[0], (ALfloat)values[1], (ALfloat)values[2]); + return; + + case AL_ORIENTATION: + fvals[0] = (ALfloat)values[0]; + fvals[1] = (ALfloat)values[1]; + fvals[2] = (ALfloat)values[2]; + fvals[3] = (ALfloat)values[3]; + fvals[4] = (ALfloat)values[4]; + fvals[5] = (ALfloat)values[5]; + alListenerfv(param, fvals); + return; + } + } + + context = GetContextRef(); + if(!context) return; + + almtx_lock(&context->PropLock); + if(!values) + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM, "Invalid listener integer-vector property"); + } + almtx_unlock(&context->PropLock); + + ALCcontext_DecRef(context); +} + + +AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) +{ + ALCcontext *context; + + context = GetContextRef(); + if(!context) return; + + almtx_lock(&context->PropLock); + if(!value) + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_GAIN: + *value = context->Listener->Gain; + break; + + case AL_METERS_PER_UNIT: + *value = context->MetersPerUnit; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid listener float property"); + } + almtx_unlock(&context->PropLock); + + ALCcontext_DecRef(context); +} + + +AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) +{ + ALCcontext *context; + + context = GetContextRef(); + if(!context) return; + + almtx_lock(&context->PropLock); + if(!value1 || !value2 || !value3) + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_POSITION: + *value1 = context->Listener->Position[0]; + *value2 = context->Listener->Position[1]; + *value3 = context->Listener->Position[2]; + break; + + case AL_VELOCITY: + *value1 = context->Listener->Velocity[0]; + *value2 = context->Listener->Velocity[1]; + *value3 = context->Listener->Velocity[2]; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-float property"); + } + almtx_unlock(&context->PropLock); + + ALCcontext_DecRef(context); +} + + +AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) +{ + ALCcontext *context; + + switch(param) + { + case AL_GAIN: + case AL_METERS_PER_UNIT: + alGetListenerf(param, values); + return; + + case AL_POSITION: + case AL_VELOCITY: + alGetListener3f(param, values+0, values+1, values+2); + return; + } + + context = GetContextRef(); + if(!context) return; + + almtx_lock(&context->PropLock); + if(!values) + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_ORIENTATION: + // AT then UP + values[0] = context->Listener->Forward[0]; + values[1] = context->Listener->Forward[1]; + values[2] = context->Listener->Forward[2]; + values[3] = context->Listener->Up[0]; + values[4] = context->Listener->Up[1]; + values[5] = context->Listener->Up[2]; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid listener float-vector property"); + } + almtx_unlock(&context->PropLock); + + ALCcontext_DecRef(context); +} + + +AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value) +{ + ALCcontext *context; + + context = GetContextRef(); + if(!context) return; + + almtx_lock(&context->PropLock); + if(!value) + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM, "Invalid listener integer property"); + } + almtx_unlock(&context->PropLock); + + ALCcontext_DecRef(context); +} + + +AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3) +{ + ALCcontext *context; + + context = GetContextRef(); + if(!context) return; + + almtx_lock(&context->PropLock); + if(!value1 || !value2 || !value3) + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_POSITION: + *value1 = (ALint)context->Listener->Position[0]; + *value2 = (ALint)context->Listener->Position[1]; + *value3 = (ALint)context->Listener->Position[2]; + break; + + case AL_VELOCITY: + *value1 = (ALint)context->Listener->Velocity[0]; + *value2 = (ALint)context->Listener->Velocity[1]; + *value3 = (ALint)context->Listener->Velocity[2]; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-integer property"); + } + almtx_unlock(&context->PropLock); + + ALCcontext_DecRef(context); +} + + +AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) +{ + ALCcontext *context; + + switch(param) + { + case AL_POSITION: + case AL_VELOCITY: + alGetListener3i(param, values+0, values+1, values+2); + return; + } + + context = GetContextRef(); + if(!context) return; + + almtx_lock(&context->PropLock); + if(!values) + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_ORIENTATION: + // AT then UP + values[0] = (ALint)context->Listener->Forward[0]; + values[1] = (ALint)context->Listener->Forward[1]; + values[2] = (ALint)context->Listener->Forward[2]; + values[3] = (ALint)context->Listener->Up[0]; + values[4] = (ALint)context->Listener->Up[1]; + values[5] = (ALint)context->Listener->Up[2]; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid listener integer-vector property"); + } + almtx_unlock(&context->PropLock); + + ALCcontext_DecRef(context); +} + + +void UpdateListenerProps(ALCcontext *context) +{ + ALlistener *listener = context->Listener; + struct ALlistenerProps *props; + + /* Get an unused proprty container, or allocate a new one as needed. */ + props = ATOMIC_LOAD(&context->FreeListenerProps, almemory_order_acquire); + if(!props) + props = static_cast(al_calloc(16, sizeof(*props))); + else + { + struct ALlistenerProps *next; + do { + next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); + } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeListenerProps, &props, next, + almemory_order_seq_cst, almemory_order_acquire) == 0); + } + + /* Copy in current property values. */ + props->Position[0] = listener->Position[0]; + props->Position[1] = listener->Position[1]; + props->Position[2] = listener->Position[2]; + + props->Velocity[0] = listener->Velocity[0]; + props->Velocity[1] = listener->Velocity[1]; + props->Velocity[2] = listener->Velocity[2]; + + props->Forward[0] = listener->Forward[0]; + props->Forward[1] = listener->Forward[1]; + props->Forward[2] = listener->Forward[2]; + props->Up[0] = listener->Up[0]; + props->Up[1] = listener->Up[1]; + props->Up[2] = listener->Up[2]; + + props->Gain = listener->Gain; + + /* Set the new container for updating internal parameters. */ + props = static_cast(ATOMIC_EXCHANGE_PTR(&listener->Update, props, + almemory_order_acq_rel)); + if(props) + { + /* If there was an unused update container, put it back in the + * freelist. + */ + ATOMIC_REPLACE_HEAD(struct ALlistenerProps*, &context->FreeListenerProps, props); + } +} -- cgit v1.2.3 From 317acd6ae2f110c76fd1e019a3066c8c45b64921 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Nov 2018 18:44:43 -0800 Subject: Convert alEffect.c and alFilter.c to C++ --- CMakeLists.txt | 4 +- OpenAL32/alEffect.c | 815 -------------------------------------------------- OpenAL32/alEffect.cpp | 815 ++++++++++++++++++++++++++++++++++++++++++++++++++ OpenAL32/alFilter.c | 668 ----------------------------------------- OpenAL32/alFilter.cpp | 668 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1485 insertions(+), 1485 deletions(-) delete mode 100644 OpenAL32/alEffect.c create mode 100644 OpenAL32/alEffect.cpp delete mode 100644 OpenAL32/alFilter.c create mode 100644 OpenAL32/alFilter.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 30375389..509cc511 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -782,12 +782,12 @@ SET(OPENAL_OBJS OpenAL32/Include/alBuffer.h OpenAL32/alBuffer.cpp OpenAL32/Include/alEffect.h - OpenAL32/alEffect.c + OpenAL32/alEffect.cpp OpenAL32/Include/alError.h OpenAL32/alError.cpp OpenAL32/alExtension.cpp OpenAL32/Include/alFilter.h - OpenAL32/alFilter.c + OpenAL32/alFilter.cpp OpenAL32/Include/alListener.h OpenAL32/alListener.cpp OpenAL32/Include/alSource.h diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c deleted file mode 100644 index 67214957..00000000 --- a/OpenAL32/alEffect.c +++ /dev/null @@ -1,815 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "alMain.h" -#include "alEffect.h" -#include "alError.h" - - -const struct EffectList EffectList[EFFECTLIST_SIZE] = { - { "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB }, - { "reverb", REVERB_EFFECT, AL_EFFECT_REVERB }, - { "autowah", AUTOWAH_EFFECT, AL_EFFECT_AUTOWAH }, - { "chorus", CHORUS_EFFECT, AL_EFFECT_CHORUS }, - { "compressor", COMPRESSOR_EFFECT, AL_EFFECT_COMPRESSOR }, - { "distortion", DISTORTION_EFFECT, AL_EFFECT_DISTORTION }, - { "echo", ECHO_EFFECT, AL_EFFECT_ECHO }, - { "equalizer", EQUALIZER_EFFECT, AL_EFFECT_EQUALIZER }, - { "flanger", FLANGER_EFFECT, AL_EFFECT_FLANGER }, - { "fshifter", FSHIFTER_EFFECT, AL_EFFECT_FREQUENCY_SHIFTER }, - { "modulator", MODULATOR_EFFECT, AL_EFFECT_RING_MODULATOR }, - { "pshifter", PSHIFTER_EFFECT, AL_EFFECT_PITCH_SHIFTER }, - { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT }, - { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_DIALOGUE }, -}; - -ALboolean DisabledEffects[MAX_EFFECTS]; - -static ALeffect *AllocEffect(ALCcontext *context); -static void FreeEffect(ALCdevice *device, ALeffect *effect); -static void InitEffectParams(ALeffect *effect, ALenum type); - -static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) -{ - EffectSubList *sublist; - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= VECTOR_SIZE(device->EffectList))) - return NULL; - sublist = &VECTOR_ELEM(device->EffectList, lidx); - if(UNLIKELY(sublist->FreeMask & (U64(1)<Effects + slidx; -} - - -AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) -{ - ALCcontext *context; - ALsizei cur; - - context = GetContextRef(); - if(!context) return; - - if(n < 0) - alSetError(context, AL_INVALID_VALUE, "Generating %d effects", n); - else for(cur = 0;cur < n;cur++) - { - ALeffect *effect = AllocEffect(context); - if(!effect) - { - alDeleteEffects(cur, effects); - break; - } - effects[cur] = effect->id; - } - - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects) -{ - ALCdevice *device; - ALCcontext *context; - ALeffect *effect; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - LockEffectList(device); - if(n < 0) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effects", n); - for(i = 0;i < n;i++) - { - if(effects[i] && LookupEffect(device, effects[i]) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect ID %u", effects[i]); - } - for(i = 0;i < n;i++) - { - if((effect=LookupEffect(device, effects[i])) != NULL) - FreeEffect(device, effect); - } - -done: - UnlockEffectList(device); - ALCcontext_DecRef(context); -} - -AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect) -{ - ALCcontext *Context; - ALboolean result; - - Context = GetContextRef(); - if(!Context) return AL_FALSE; - - LockEffectList(Context->Device); - result = ((!effect || LookupEffect(Context->Device, effect)) ? - AL_TRUE : AL_FALSE); - UnlockEffectList(Context->Device); - - ALCcontext_DecRef(Context); - - return result; -} - -AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) -{ - ALCcontext *Context; - ALCdevice *Device; - ALeffect *ALEffect; - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockEffectList(Device); - if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - if(param == AL_EFFECT_TYPE) - { - ALboolean isOk = (value == AL_EFFECT_NULL); - ALint i; - for(i = 0;!isOk && i < EFFECTLIST_SIZE;i++) - { - if(value == EffectList[i].val && - !DisabledEffects[EffectList[i].type]) - isOk = AL_TRUE; - } - - if(isOk) - InitEffectParams(ALEffect, value); - else - alSetError(Context, AL_INVALID_VALUE, "Effect type 0x%04x not supported", value); - } - else - { - /* Call the appropriate handler */ - ALeffect_setParami(ALEffect, Context, param, value); - } - } - UnlockEffectList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *values) -{ - ALCcontext *Context; - ALCdevice *Device; - ALeffect *ALEffect; - - switch(param) - { - case AL_EFFECT_TYPE: - alEffecti(effect, param, values[0]); - return; - } - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockEffectList(Device); - if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - /* Call the appropriate handler */ - ALeffect_setParamiv(ALEffect, Context, param, values); - } - UnlockEffectList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value) -{ - ALCcontext *Context; - ALCdevice *Device; - ALeffect *ALEffect; - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockEffectList(Device); - if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - /* Call the appropriate handler */ - ALeffect_setParamf(ALEffect, Context, param, value); - } - UnlockEffectList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *values) -{ - ALCcontext *Context; - ALCdevice *Device; - ALeffect *ALEffect; - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockEffectList(Device); - if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - /* Call the appropriate handler */ - ALeffect_setParamfv(ALEffect, Context, param, values); - } - UnlockEffectList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value) -{ - ALCcontext *Context; - ALCdevice *Device; - ALeffect *ALEffect; - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockEffectList(Device); - if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - if(param == AL_EFFECT_TYPE) - *value = ALEffect->type; - else - { - /* Call the appropriate handler */ - ALeffect_getParami(ALEffect, Context, param, value); - } - } - UnlockEffectList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *values) -{ - ALCcontext *Context; - ALCdevice *Device; - ALeffect *ALEffect; - - switch(param) - { - case AL_EFFECT_TYPE: - alGetEffecti(effect, param, values); - return; - } - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockEffectList(Device); - if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - /* Call the appropriate handler */ - ALeffect_getParamiv(ALEffect, Context, param, values); - } - UnlockEffectList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *value) -{ - ALCcontext *Context; - ALCdevice *Device; - ALeffect *ALEffect; - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockEffectList(Device); - if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - /* Call the appropriate handler */ - ALeffect_getParamf(ALEffect, Context, param, value); - } - UnlockEffectList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *values) -{ - ALCcontext *Context; - ALCdevice *Device; - ALeffect *ALEffect; - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockEffectList(Device); - if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - /* Call the appropriate handler */ - ALeffect_getParamfv(ALEffect, Context, param, values); - } - UnlockEffectList(Device); - - ALCcontext_DecRef(Context); -} - - -void InitEffect(ALeffect *effect) -{ - InitEffectParams(effect, AL_EFFECT_NULL); -} - -static ALeffect *AllocEffect(ALCcontext *context) -{ - ALCdevice *device = context->Device; - EffectSubList *sublist, *subend; - ALeffect *effect = NULL; - ALsizei lidx = 0; - ALsizei slidx; - - almtx_lock(&device->EffectLock); - sublist = VECTOR_BEGIN(device->EffectList); - subend = VECTOR_END(device->EffectList); - for(;sublist != subend;++sublist) - { - if(sublist->FreeMask) - { - slidx = CTZ64(sublist->FreeMask); - effect = sublist->Effects + slidx; - break; - } - ++lidx; - } - if(UNLIKELY(!effect)) - { - const EffectSubList empty_sublist = { 0, NULL }; - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ - if(UNLIKELY(VECTOR_SIZE(device->EffectList) >= 1<<25)) - { - almtx_unlock(&device->EffectLock); - alSetError(context, AL_OUT_OF_MEMORY, "Too many effects allocated"); - return NULL; - } - lidx = (ALsizei)VECTOR_SIZE(device->EffectList); - VECTOR_PUSH_BACK(device->EffectList, empty_sublist); - sublist = &VECTOR_BACK(device->EffectList); - sublist->FreeMask = ~U64(0); - sublist->Effects = al_calloc(16, sizeof(ALeffect)*64); - if(UNLIKELY(!sublist->Effects)) - { - VECTOR_POP_BACK(device->EffectList); - almtx_unlock(&device->EffectLock); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect batch"); - return NULL; - } - - slidx = 0; - effect = sublist->Effects + slidx; - } - - memset(effect, 0, sizeof(*effect)); - InitEffectParams(effect, AL_EFFECT_NULL); - - /* Add 1 to avoid effect ID 0. */ - effect->id = ((lidx<<6) | slidx) + 1; - - sublist->FreeMask &= ~(U64(1)<EffectLock); - - return effect; -} - -static void FreeEffect(ALCdevice *device, ALeffect *effect) -{ - ALuint id = effect->id - 1; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; - - memset(effect, 0, sizeof(*effect)); - - VECTOR_ELEM(device->EffectList, lidx).FreeMask |= U64(1) << slidx; -} - -void ReleaseALEffects(ALCdevice *device) -{ - EffectSubList *sublist = VECTOR_BEGIN(device->EffectList); - EffectSubList *subend = VECTOR_END(device->EffectList); - size_t leftover = 0; - for(;sublist != subend;++sublist) - { - ALuint64 usemask = ~sublist->FreeMask; - while(usemask) - { - ALsizei idx = CTZ64(usemask); - ALeffect *effect = sublist->Effects + idx; - - memset(effect, 0, sizeof(*effect)); - ++leftover; - - usemask &= ~(U64(1) << idx); - } - sublist->FreeMask = ~usemask; - } - if(leftover > 0) - WARN("(%p) Deleted "SZFMT" Effect%s\n", device, leftover, (leftover==1)?"":"s"); -} - - -static void InitEffectParams(ALeffect *effect, ALenum type) -{ - switch(type) - { - case AL_EFFECT_EAXREVERB: - effect->Props.Reverb.Density = AL_EAXREVERB_DEFAULT_DENSITY; - effect->Props.Reverb.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION; - effect->Props.Reverb.Gain = AL_EAXREVERB_DEFAULT_GAIN; - effect->Props.Reverb.GainHF = AL_EAXREVERB_DEFAULT_GAINHF; - effect->Props.Reverb.GainLF = AL_EAXREVERB_DEFAULT_GAINLF; - effect->Props.Reverb.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME; - effect->Props.Reverb.DecayHFRatio = AL_EAXREVERB_DEFAULT_DECAY_HFRATIO; - effect->Props.Reverb.DecayLFRatio = AL_EAXREVERB_DEFAULT_DECAY_LFRATIO; - effect->Props.Reverb.ReflectionsGain = AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN; - effect->Props.Reverb.ReflectionsDelay = AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY; - effect->Props.Reverb.ReflectionsPan[0] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; - effect->Props.Reverb.ReflectionsPan[1] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; - effect->Props.Reverb.ReflectionsPan[2] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; - effect->Props.Reverb.LateReverbGain = AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN; - effect->Props.Reverb.LateReverbDelay = AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY; - effect->Props.Reverb.LateReverbPan[0] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; - effect->Props.Reverb.LateReverbPan[1] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; - effect->Props.Reverb.LateReverbPan[2] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; - effect->Props.Reverb.EchoTime = AL_EAXREVERB_DEFAULT_ECHO_TIME; - effect->Props.Reverb.EchoDepth = AL_EAXREVERB_DEFAULT_ECHO_DEPTH; - effect->Props.Reverb.ModulationTime = AL_EAXREVERB_DEFAULT_MODULATION_TIME; - effect->Props.Reverb.ModulationDepth = AL_EAXREVERB_DEFAULT_MODULATION_DEPTH; - effect->Props.Reverb.AirAbsorptionGainHF = AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF; - effect->Props.Reverb.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE; - effect->Props.Reverb.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE; - effect->Props.Reverb.RoomRolloffFactor = AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; - effect->Props.Reverb.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT; - effect->vtab = &ALeaxreverb_vtable; - break; - case AL_EFFECT_REVERB: - effect->Props.Reverb.Density = AL_REVERB_DEFAULT_DENSITY; - effect->Props.Reverb.Diffusion = AL_REVERB_DEFAULT_DIFFUSION; - effect->Props.Reverb.Gain = AL_REVERB_DEFAULT_GAIN; - effect->Props.Reverb.GainHF = AL_REVERB_DEFAULT_GAINHF; - effect->Props.Reverb.GainLF = 1.0f; - effect->Props.Reverb.DecayTime = AL_REVERB_DEFAULT_DECAY_TIME; - effect->Props.Reverb.DecayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO; - effect->Props.Reverb.DecayLFRatio = 1.0f; - effect->Props.Reverb.ReflectionsGain = AL_REVERB_DEFAULT_REFLECTIONS_GAIN; - effect->Props.Reverb.ReflectionsDelay = AL_REVERB_DEFAULT_REFLECTIONS_DELAY; - effect->Props.Reverb.ReflectionsPan[0] = 0.0f; - effect->Props.Reverb.ReflectionsPan[1] = 0.0f; - effect->Props.Reverb.ReflectionsPan[2] = 0.0f; - effect->Props.Reverb.LateReverbGain = AL_REVERB_DEFAULT_LATE_REVERB_GAIN; - effect->Props.Reverb.LateReverbDelay = AL_REVERB_DEFAULT_LATE_REVERB_DELAY; - effect->Props.Reverb.LateReverbPan[0] = 0.0f; - effect->Props.Reverb.LateReverbPan[1] = 0.0f; - effect->Props.Reverb.LateReverbPan[2] = 0.0f; - effect->Props.Reverb.EchoTime = 0.25f; - effect->Props.Reverb.EchoDepth = 0.0f; - effect->Props.Reverb.ModulationTime = 0.25f; - effect->Props.Reverb.ModulationDepth = 0.0f; - effect->Props.Reverb.AirAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF; - effect->Props.Reverb.HFReference = 5000.0f; - effect->Props.Reverb.LFReference = 250.0f; - effect->Props.Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; - effect->Props.Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT; - effect->vtab = &ALreverb_vtable; - break; - case AL_EFFECT_AUTOWAH: - effect->Props.Autowah.AttackTime = AL_AUTOWAH_DEFAULT_ATTACK_TIME; - effect->Props.Autowah.ReleaseTime = AL_AUTOWAH_DEFAULT_RELEASE_TIME; - effect->Props.Autowah.Resonance = AL_AUTOWAH_DEFAULT_RESONANCE; - effect->Props.Autowah.PeakGain = AL_AUTOWAH_DEFAULT_PEAK_GAIN; - effect->vtab = &ALautowah_vtable; - break; - case AL_EFFECT_CHORUS: - effect->Props.Chorus.Waveform = AL_CHORUS_DEFAULT_WAVEFORM; - effect->Props.Chorus.Phase = AL_CHORUS_DEFAULT_PHASE; - effect->Props.Chorus.Rate = AL_CHORUS_DEFAULT_RATE; - effect->Props.Chorus.Depth = AL_CHORUS_DEFAULT_DEPTH; - effect->Props.Chorus.Feedback = AL_CHORUS_DEFAULT_FEEDBACK; - effect->Props.Chorus.Delay = AL_CHORUS_DEFAULT_DELAY; - effect->vtab = &ALchorus_vtable; - break; - case AL_EFFECT_COMPRESSOR: - effect->Props.Compressor.OnOff = AL_COMPRESSOR_DEFAULT_ONOFF; - effect->vtab = &ALcompressor_vtable; - break; - case AL_EFFECT_DISTORTION: - effect->Props.Distortion.Edge = AL_DISTORTION_DEFAULT_EDGE; - effect->Props.Distortion.Gain = AL_DISTORTION_DEFAULT_GAIN; - effect->Props.Distortion.LowpassCutoff = AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF; - effect->Props.Distortion.EQCenter = AL_DISTORTION_DEFAULT_EQCENTER; - effect->Props.Distortion.EQBandwidth = AL_DISTORTION_DEFAULT_EQBANDWIDTH; - effect->vtab = &ALdistortion_vtable; - break; - case AL_EFFECT_ECHO: - effect->Props.Echo.Delay = AL_ECHO_DEFAULT_DELAY; - effect->Props.Echo.LRDelay = AL_ECHO_DEFAULT_LRDELAY; - effect->Props.Echo.Damping = AL_ECHO_DEFAULT_DAMPING; - effect->Props.Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK; - effect->Props.Echo.Spread = AL_ECHO_DEFAULT_SPREAD; - effect->vtab = &ALecho_vtable; - break; - case AL_EFFECT_EQUALIZER: - effect->Props.Equalizer.LowCutoff = AL_EQUALIZER_DEFAULT_LOW_CUTOFF; - effect->Props.Equalizer.LowGain = AL_EQUALIZER_DEFAULT_LOW_GAIN; - effect->Props.Equalizer.Mid1Center = AL_EQUALIZER_DEFAULT_MID1_CENTER; - effect->Props.Equalizer.Mid1Gain = AL_EQUALIZER_DEFAULT_MID1_GAIN; - effect->Props.Equalizer.Mid1Width = AL_EQUALIZER_DEFAULT_MID1_WIDTH; - effect->Props.Equalizer.Mid2Center = AL_EQUALIZER_DEFAULT_MID2_CENTER; - effect->Props.Equalizer.Mid2Gain = AL_EQUALIZER_DEFAULT_MID2_GAIN; - effect->Props.Equalizer.Mid2Width = AL_EQUALIZER_DEFAULT_MID2_WIDTH; - effect->Props.Equalizer.HighCutoff = AL_EQUALIZER_DEFAULT_HIGH_CUTOFF; - effect->Props.Equalizer.HighGain = AL_EQUALIZER_DEFAULT_HIGH_GAIN; - effect->vtab = &ALequalizer_vtable; - break; - case AL_EFFECT_FLANGER: - effect->Props.Chorus.Waveform = AL_FLANGER_DEFAULT_WAVEFORM; - effect->Props.Chorus.Phase = AL_FLANGER_DEFAULT_PHASE; - effect->Props.Chorus.Rate = AL_FLANGER_DEFAULT_RATE; - effect->Props.Chorus.Depth = AL_FLANGER_DEFAULT_DEPTH; - effect->Props.Chorus.Feedback = AL_FLANGER_DEFAULT_FEEDBACK; - effect->Props.Chorus.Delay = AL_FLANGER_DEFAULT_DELAY; - effect->vtab = &ALflanger_vtable; - break; - case AL_EFFECT_FREQUENCY_SHIFTER: - effect->Props.Fshifter.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY; - effect->Props.Fshifter.LeftDirection = AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION; - effect->Props.Fshifter.RightDirection = AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION; - effect->vtab = &ALfshifter_vtable; - break; - case AL_EFFECT_RING_MODULATOR: - effect->Props.Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY; - effect->Props.Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF; - effect->Props.Modulator.Waveform = AL_RING_MODULATOR_DEFAULT_WAVEFORM; - effect->vtab = &ALmodulator_vtable; - break; - case AL_EFFECT_PITCH_SHIFTER: - effect->Props.Pshifter.CoarseTune = AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE; - effect->Props.Pshifter.FineTune = AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE; - effect->vtab = &ALpshifter_vtable; - break; - case AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT: - case AL_EFFECT_DEDICATED_DIALOGUE: - effect->Props.Dedicated.Gain = 1.0f; - effect->vtab = &ALdedicated_vtable; - break; - default: - effect->vtab = &ALnull_vtable; - break; - } - effect->type = type; -} - - -#include "AL/efx-presets.h" - -#define DECL(x) { #x, EFX_REVERB_PRESET_##x } -static const struct { - const char name[32]; - EFXEAXREVERBPROPERTIES props; -} reverblist[] = { - DECL(GENERIC), - DECL(PADDEDCELL), - DECL(ROOM), - DECL(BATHROOM), - DECL(LIVINGROOM), - DECL(STONEROOM), - DECL(AUDITORIUM), - DECL(CONCERTHALL), - DECL(CAVE), - DECL(ARENA), - DECL(HANGAR), - DECL(CARPETEDHALLWAY), - DECL(HALLWAY), - DECL(STONECORRIDOR), - DECL(ALLEY), - DECL(FOREST), - DECL(CITY), - DECL(MOUNTAINS), - DECL(QUARRY), - DECL(PLAIN), - DECL(PARKINGLOT), - DECL(SEWERPIPE), - DECL(UNDERWATER), - DECL(DRUGGED), - DECL(DIZZY), - DECL(PSYCHOTIC), - - DECL(CASTLE_SMALLROOM), - DECL(CASTLE_SHORTPASSAGE), - DECL(CASTLE_MEDIUMROOM), - DECL(CASTLE_LARGEROOM), - DECL(CASTLE_LONGPASSAGE), - DECL(CASTLE_HALL), - DECL(CASTLE_CUPBOARD), - DECL(CASTLE_COURTYARD), - DECL(CASTLE_ALCOVE), - - DECL(FACTORY_SMALLROOM), - DECL(FACTORY_SHORTPASSAGE), - DECL(FACTORY_MEDIUMROOM), - DECL(FACTORY_LARGEROOM), - DECL(FACTORY_LONGPASSAGE), - DECL(FACTORY_HALL), - DECL(FACTORY_CUPBOARD), - DECL(FACTORY_COURTYARD), - DECL(FACTORY_ALCOVE), - - DECL(ICEPALACE_SMALLROOM), - DECL(ICEPALACE_SHORTPASSAGE), - DECL(ICEPALACE_MEDIUMROOM), - DECL(ICEPALACE_LARGEROOM), - DECL(ICEPALACE_LONGPASSAGE), - DECL(ICEPALACE_HALL), - DECL(ICEPALACE_CUPBOARD), - DECL(ICEPALACE_COURTYARD), - DECL(ICEPALACE_ALCOVE), - - DECL(SPACESTATION_SMALLROOM), - DECL(SPACESTATION_SHORTPASSAGE), - DECL(SPACESTATION_MEDIUMROOM), - DECL(SPACESTATION_LARGEROOM), - DECL(SPACESTATION_LONGPASSAGE), - DECL(SPACESTATION_HALL), - DECL(SPACESTATION_CUPBOARD), - DECL(SPACESTATION_ALCOVE), - - DECL(WOODEN_SMALLROOM), - DECL(WOODEN_SHORTPASSAGE), - DECL(WOODEN_MEDIUMROOM), - DECL(WOODEN_LARGEROOM), - DECL(WOODEN_LONGPASSAGE), - DECL(WOODEN_HALL), - DECL(WOODEN_CUPBOARD), - DECL(WOODEN_COURTYARD), - DECL(WOODEN_ALCOVE), - - DECL(SPORT_EMPTYSTADIUM), - DECL(SPORT_SQUASHCOURT), - DECL(SPORT_SMALLSWIMMINGPOOL), - DECL(SPORT_LARGESWIMMINGPOOL), - DECL(SPORT_GYMNASIUM), - DECL(SPORT_FULLSTADIUM), - DECL(SPORT_STADIUMTANNOY), - - DECL(PREFAB_WORKSHOP), - DECL(PREFAB_SCHOOLROOM), - DECL(PREFAB_PRACTISEROOM), - DECL(PREFAB_OUTHOUSE), - DECL(PREFAB_CARAVAN), - - DECL(DOME_TOMB), - DECL(PIPE_SMALL), - DECL(DOME_SAINTPAULS), - DECL(PIPE_LONGTHIN), - DECL(PIPE_LARGE), - DECL(PIPE_RESONANT), - - DECL(OUTDOORS_BACKYARD), - DECL(OUTDOORS_ROLLINGPLAINS), - DECL(OUTDOORS_DEEPCANYON), - DECL(OUTDOORS_CREEK), - DECL(OUTDOORS_VALLEY), - - DECL(MOOD_HEAVEN), - DECL(MOOD_HELL), - DECL(MOOD_MEMORY), - - DECL(DRIVING_COMMENTATOR), - DECL(DRIVING_PITGARAGE), - DECL(DRIVING_INCAR_RACER), - DECL(DRIVING_INCAR_SPORTS), - DECL(DRIVING_INCAR_LUXURY), - DECL(DRIVING_FULLGRANDSTAND), - DECL(DRIVING_EMPTYGRANDSTAND), - DECL(DRIVING_TUNNEL), - - DECL(CITY_STREETS), - DECL(CITY_SUBWAY), - DECL(CITY_MUSEUM), - DECL(CITY_LIBRARY), - DECL(CITY_UNDERPASS), - DECL(CITY_ABANDONED), - - DECL(DUSTYROOM), - DECL(CHAPEL), - DECL(SMALLWATERROOM), -}; -#undef DECL - -void LoadReverbPreset(const char *name, ALeffect *effect) -{ - size_t i; - - if(strcasecmp(name, "NONE") == 0) - { - InitEffectParams(effect, AL_EFFECT_NULL); - TRACE("Loading reverb '%s'\n", "NONE"); - return; - } - - if(!DisabledEffects[EAXREVERB_EFFECT]) - InitEffectParams(effect, AL_EFFECT_EAXREVERB); - else if(!DisabledEffects[REVERB_EFFECT]) - InitEffectParams(effect, AL_EFFECT_REVERB); - else - InitEffectParams(effect, AL_EFFECT_NULL); - for(i = 0;i < COUNTOF(reverblist);i++) - { - const EFXEAXREVERBPROPERTIES *props; - - if(strcasecmp(name, reverblist[i].name) != 0) - continue; - - TRACE("Loading reverb '%s'\n", reverblist[i].name); - props = &reverblist[i].props; - effect->Props.Reverb.Density = props->flDensity; - effect->Props.Reverb.Diffusion = props->flDiffusion; - effect->Props.Reverb.Gain = props->flGain; - effect->Props.Reverb.GainHF = props->flGainHF; - effect->Props.Reverb.GainLF = props->flGainLF; - effect->Props.Reverb.DecayTime = props->flDecayTime; - effect->Props.Reverb.DecayHFRatio = props->flDecayHFRatio; - effect->Props.Reverb.DecayLFRatio = props->flDecayLFRatio; - effect->Props.Reverb.ReflectionsGain = props->flReflectionsGain; - effect->Props.Reverb.ReflectionsDelay = props->flReflectionsDelay; - effect->Props.Reverb.ReflectionsPan[0] = props->flReflectionsPan[0]; - effect->Props.Reverb.ReflectionsPan[1] = props->flReflectionsPan[1]; - effect->Props.Reverb.ReflectionsPan[2] = props->flReflectionsPan[2]; - effect->Props.Reverb.LateReverbGain = props->flLateReverbGain; - effect->Props.Reverb.LateReverbDelay = props->flLateReverbDelay; - effect->Props.Reverb.LateReverbPan[0] = props->flLateReverbPan[0]; - effect->Props.Reverb.LateReverbPan[1] = props->flLateReverbPan[1]; - effect->Props.Reverb.LateReverbPan[2] = props->flLateReverbPan[2]; - effect->Props.Reverb.EchoTime = props->flEchoTime; - effect->Props.Reverb.EchoDepth = props->flEchoDepth; - effect->Props.Reverb.ModulationTime = props->flModulationTime; - effect->Props.Reverb.ModulationDepth = props->flModulationDepth; - effect->Props.Reverb.AirAbsorptionGainHF = props->flAirAbsorptionGainHF; - effect->Props.Reverb.HFReference = props->flHFReference; - effect->Props.Reverb.LFReference = props->flLFReference; - effect->Props.Reverb.RoomRolloffFactor = props->flRoomRolloffFactor; - effect->Props.Reverb.DecayHFLimit = props->iDecayHFLimit; - return; - } - - WARN("Reverb preset '%s' not found\n", name); -} diff --git a/OpenAL32/alEffect.cpp b/OpenAL32/alEffect.cpp new file mode 100644 index 00000000..b9a2623c --- /dev/null +++ b/OpenAL32/alEffect.cpp @@ -0,0 +1,815 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "alMain.h" +#include "alEffect.h" +#include "alError.h" + + +const struct EffectList EffectList[EFFECTLIST_SIZE] = { + { "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB }, + { "reverb", REVERB_EFFECT, AL_EFFECT_REVERB }, + { "autowah", AUTOWAH_EFFECT, AL_EFFECT_AUTOWAH }, + { "chorus", CHORUS_EFFECT, AL_EFFECT_CHORUS }, + { "compressor", COMPRESSOR_EFFECT, AL_EFFECT_COMPRESSOR }, + { "distortion", DISTORTION_EFFECT, AL_EFFECT_DISTORTION }, + { "echo", ECHO_EFFECT, AL_EFFECT_ECHO }, + { "equalizer", EQUALIZER_EFFECT, AL_EFFECT_EQUALIZER }, + { "flanger", FLANGER_EFFECT, AL_EFFECT_FLANGER }, + { "fshifter", FSHIFTER_EFFECT, AL_EFFECT_FREQUENCY_SHIFTER }, + { "modulator", MODULATOR_EFFECT, AL_EFFECT_RING_MODULATOR }, + { "pshifter", PSHIFTER_EFFECT, AL_EFFECT_PITCH_SHIFTER }, + { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT }, + { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_DIALOGUE }, +}; + +ALboolean DisabledEffects[MAX_EFFECTS]; + +static ALeffect *AllocEffect(ALCcontext *context); +static void FreeEffect(ALCdevice *device, ALeffect *effect); +static void InitEffectParams(ALeffect *effect, ALenum type); + +static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) +{ + EffectSubList *sublist; + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= VECTOR_SIZE(device->EffectList))) + return NULL; + sublist = &VECTOR_ELEM(device->EffectList, lidx); + if(UNLIKELY(sublist->FreeMask & (U64(1)<Effects + slidx; +} + + +AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) +{ + ALCcontext *context; + ALsizei cur; + + context = GetContextRef(); + if(!context) return; + + if(n < 0) + alSetError(context, AL_INVALID_VALUE, "Generating %d effects", n); + else for(cur = 0;cur < n;cur++) + { + ALeffect *effect = AllocEffect(context); + if(!effect) + { + alDeleteEffects(cur, effects); + break; + } + effects[cur] = effect->id; + } + + ALCcontext_DecRef(context); +} + +AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects) +{ + ALCdevice *device; + ALCcontext *context; + ALeffect *effect; + ALsizei i; + + context = GetContextRef(); + if(!context) return; + + device = context->Device; + LockEffectList(device); + if(n < 0) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effects", n); + for(i = 0;i < n;i++) + { + if(effects[i] && LookupEffect(device, effects[i]) == NULL) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect ID %u", effects[i]); + } + for(i = 0;i < n;i++) + { + if((effect=LookupEffect(device, effects[i])) != NULL) + FreeEffect(device, effect); + } + +done: + UnlockEffectList(device); + ALCcontext_DecRef(context); +} + +AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect) +{ + ALCcontext *Context; + ALboolean result; + + Context = GetContextRef(); + if(!Context) return AL_FALSE; + + LockEffectList(Context->Device); + result = ((!effect || LookupEffect(Context->Device, effect)) ? + AL_TRUE : AL_FALSE); + UnlockEffectList(Context->Device); + + ALCcontext_DecRef(Context); + + return result; +} + +AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + LockEffectList(Device); + if((ALEffect=LookupEffect(Device, effect)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + if(param == AL_EFFECT_TYPE) + { + ALboolean isOk = (value == AL_EFFECT_NULL); + ALint i; + for(i = 0;!isOk && i < EFFECTLIST_SIZE;i++) + { + if(value == EffectList[i].val && + !DisabledEffects[EffectList[i].type]) + isOk = AL_TRUE; + } + + if(isOk) + InitEffectParams(ALEffect, value); + else + alSetError(Context, AL_INVALID_VALUE, "Effect type 0x%04x not supported", value); + } + else + { + /* Call the appropriate handler */ + ALeffect_setParami(ALEffect, Context, param, value); + } + } + UnlockEffectList(Device); + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *values) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + switch(param) + { + case AL_EFFECT_TYPE: + alEffecti(effect, param, values[0]); + return; + } + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + LockEffectList(Device); + if((ALEffect=LookupEffect(Device, effect)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + /* Call the appropriate handler */ + ALeffect_setParamiv(ALEffect, Context, param, values); + } + UnlockEffectList(Device); + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + LockEffectList(Device); + if((ALEffect=LookupEffect(Device, effect)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + /* Call the appropriate handler */ + ALeffect_setParamf(ALEffect, Context, param, value); + } + UnlockEffectList(Device); + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *values) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + LockEffectList(Device); + if((ALEffect=LookupEffect(Device, effect)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + /* Call the appropriate handler */ + ALeffect_setParamfv(ALEffect, Context, param, values); + } + UnlockEffectList(Device); + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + LockEffectList(Device); + if((ALEffect=LookupEffect(Device, effect)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + if(param == AL_EFFECT_TYPE) + *value = ALEffect->type; + else + { + /* Call the appropriate handler */ + ALeffect_getParami(ALEffect, Context, param, value); + } + } + UnlockEffectList(Device); + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *values) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + switch(param) + { + case AL_EFFECT_TYPE: + alGetEffecti(effect, param, values); + return; + } + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + LockEffectList(Device); + if((ALEffect=LookupEffect(Device, effect)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + /* Call the appropriate handler */ + ALeffect_getParamiv(ALEffect, Context, param, values); + } + UnlockEffectList(Device); + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *value) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + LockEffectList(Device); + if((ALEffect=LookupEffect(Device, effect)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + /* Call the appropriate handler */ + ALeffect_getParamf(ALEffect, Context, param, value); + } + UnlockEffectList(Device); + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *values) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + LockEffectList(Device); + if((ALEffect=LookupEffect(Device, effect)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + /* Call the appropriate handler */ + ALeffect_getParamfv(ALEffect, Context, param, values); + } + UnlockEffectList(Device); + + ALCcontext_DecRef(Context); +} + + +void InitEffect(ALeffect *effect) +{ + InitEffectParams(effect, AL_EFFECT_NULL); +} + +static ALeffect *AllocEffect(ALCcontext *context) +{ + ALCdevice *device = context->Device; + EffectSubList *sublist, *subend; + ALeffect *effect = NULL; + ALsizei lidx = 0; + ALsizei slidx; + + almtx_lock(&device->EffectLock); + sublist = VECTOR_BEGIN(device->EffectList); + subend = VECTOR_END(device->EffectList); + for(;sublist != subend;++sublist) + { + if(sublist->FreeMask) + { + slidx = CTZ64(sublist->FreeMask); + effect = sublist->Effects + slidx; + break; + } + ++lidx; + } + if(UNLIKELY(!effect)) + { + const EffectSubList empty_sublist = { 0, NULL }; + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(VECTOR_SIZE(device->EffectList) >= 1<<25)) + { + almtx_unlock(&device->EffectLock); + alSetError(context, AL_OUT_OF_MEMORY, "Too many effects allocated"); + return NULL; + } + lidx = (ALsizei)VECTOR_SIZE(device->EffectList); + VECTOR_PUSH_BACK(device->EffectList, empty_sublist); + sublist = &VECTOR_BACK(device->EffectList); + sublist->FreeMask = ~U64(0); + sublist->Effects = static_cast(al_calloc(16, sizeof(ALeffect)*64)); + if(UNLIKELY(!sublist->Effects)) + { + VECTOR_POP_BACK(device->EffectList); + almtx_unlock(&device->EffectLock); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect batch"); + return NULL; + } + + slidx = 0; + effect = sublist->Effects + slidx; + } + + memset(effect, 0, sizeof(*effect)); + InitEffectParams(effect, AL_EFFECT_NULL); + + /* Add 1 to avoid effect ID 0. */ + effect->id = ((lidx<<6) | slidx) + 1; + + sublist->FreeMask &= ~(U64(1)<EffectLock); + + return effect; +} + +static void FreeEffect(ALCdevice *device, ALeffect *effect) +{ + ALuint id = effect->id - 1; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; + + memset(effect, 0, sizeof(*effect)); + + VECTOR_ELEM(device->EffectList, lidx).FreeMask |= U64(1) << slidx; +} + +void ReleaseALEffects(ALCdevice *device) +{ + EffectSubList *sublist = VECTOR_BEGIN(device->EffectList); + EffectSubList *subend = VECTOR_END(device->EffectList); + size_t leftover = 0; + for(;sublist != subend;++sublist) + { + ALuint64 usemask = ~sublist->FreeMask; + while(usemask) + { + ALsizei idx = CTZ64(usemask); + ALeffect *effect = sublist->Effects + idx; + + memset(effect, 0, sizeof(*effect)); + ++leftover; + + usemask &= ~(U64(1) << idx); + } + sublist->FreeMask = ~usemask; + } + if(leftover > 0) + WARN("(%p) Deleted " SZFMT " Effect%s\n", device, leftover, (leftover==1)?"":"s"); +} + + +static void InitEffectParams(ALeffect *effect, ALenum type) +{ + switch(type) + { + case AL_EFFECT_EAXREVERB: + effect->Props.Reverb.Density = AL_EAXREVERB_DEFAULT_DENSITY; + effect->Props.Reverb.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION; + effect->Props.Reverb.Gain = AL_EAXREVERB_DEFAULT_GAIN; + effect->Props.Reverb.GainHF = AL_EAXREVERB_DEFAULT_GAINHF; + effect->Props.Reverb.GainLF = AL_EAXREVERB_DEFAULT_GAINLF; + effect->Props.Reverb.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME; + effect->Props.Reverb.DecayHFRatio = AL_EAXREVERB_DEFAULT_DECAY_HFRATIO; + effect->Props.Reverb.DecayLFRatio = AL_EAXREVERB_DEFAULT_DECAY_LFRATIO; + effect->Props.Reverb.ReflectionsGain = AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN; + effect->Props.Reverb.ReflectionsDelay = AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY; + effect->Props.Reverb.ReflectionsPan[0] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; + effect->Props.Reverb.ReflectionsPan[1] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; + effect->Props.Reverb.ReflectionsPan[2] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; + effect->Props.Reverb.LateReverbGain = AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN; + effect->Props.Reverb.LateReverbDelay = AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY; + effect->Props.Reverb.LateReverbPan[0] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; + effect->Props.Reverb.LateReverbPan[1] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; + effect->Props.Reverb.LateReverbPan[2] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; + effect->Props.Reverb.EchoTime = AL_EAXREVERB_DEFAULT_ECHO_TIME; + effect->Props.Reverb.EchoDepth = AL_EAXREVERB_DEFAULT_ECHO_DEPTH; + effect->Props.Reverb.ModulationTime = AL_EAXREVERB_DEFAULT_MODULATION_TIME; + effect->Props.Reverb.ModulationDepth = AL_EAXREVERB_DEFAULT_MODULATION_DEPTH; + effect->Props.Reverb.AirAbsorptionGainHF = AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF; + effect->Props.Reverb.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE; + effect->Props.Reverb.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE; + effect->Props.Reverb.RoomRolloffFactor = AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; + effect->Props.Reverb.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT; + effect->vtab = &ALeaxreverb_vtable; + break; + case AL_EFFECT_REVERB: + effect->Props.Reverb.Density = AL_REVERB_DEFAULT_DENSITY; + effect->Props.Reverb.Diffusion = AL_REVERB_DEFAULT_DIFFUSION; + effect->Props.Reverb.Gain = AL_REVERB_DEFAULT_GAIN; + effect->Props.Reverb.GainHF = AL_REVERB_DEFAULT_GAINHF; + effect->Props.Reverb.GainLF = 1.0f; + effect->Props.Reverb.DecayTime = AL_REVERB_DEFAULT_DECAY_TIME; + effect->Props.Reverb.DecayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO; + effect->Props.Reverb.DecayLFRatio = 1.0f; + effect->Props.Reverb.ReflectionsGain = AL_REVERB_DEFAULT_REFLECTIONS_GAIN; + effect->Props.Reverb.ReflectionsDelay = AL_REVERB_DEFAULT_REFLECTIONS_DELAY; + effect->Props.Reverb.ReflectionsPan[0] = 0.0f; + effect->Props.Reverb.ReflectionsPan[1] = 0.0f; + effect->Props.Reverb.ReflectionsPan[2] = 0.0f; + effect->Props.Reverb.LateReverbGain = AL_REVERB_DEFAULT_LATE_REVERB_GAIN; + effect->Props.Reverb.LateReverbDelay = AL_REVERB_DEFAULT_LATE_REVERB_DELAY; + effect->Props.Reverb.LateReverbPan[0] = 0.0f; + effect->Props.Reverb.LateReverbPan[1] = 0.0f; + effect->Props.Reverb.LateReverbPan[2] = 0.0f; + effect->Props.Reverb.EchoTime = 0.25f; + effect->Props.Reverb.EchoDepth = 0.0f; + effect->Props.Reverb.ModulationTime = 0.25f; + effect->Props.Reverb.ModulationDepth = 0.0f; + effect->Props.Reverb.AirAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF; + effect->Props.Reverb.HFReference = 5000.0f; + effect->Props.Reverb.LFReference = 250.0f; + effect->Props.Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; + effect->Props.Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT; + effect->vtab = &ALreverb_vtable; + break; + case AL_EFFECT_AUTOWAH: + effect->Props.Autowah.AttackTime = AL_AUTOWAH_DEFAULT_ATTACK_TIME; + effect->Props.Autowah.ReleaseTime = AL_AUTOWAH_DEFAULT_RELEASE_TIME; + effect->Props.Autowah.Resonance = AL_AUTOWAH_DEFAULT_RESONANCE; + effect->Props.Autowah.PeakGain = AL_AUTOWAH_DEFAULT_PEAK_GAIN; + effect->vtab = &ALautowah_vtable; + break; + case AL_EFFECT_CHORUS: + effect->Props.Chorus.Waveform = AL_CHORUS_DEFAULT_WAVEFORM; + effect->Props.Chorus.Phase = AL_CHORUS_DEFAULT_PHASE; + effect->Props.Chorus.Rate = AL_CHORUS_DEFAULT_RATE; + effect->Props.Chorus.Depth = AL_CHORUS_DEFAULT_DEPTH; + effect->Props.Chorus.Feedback = AL_CHORUS_DEFAULT_FEEDBACK; + effect->Props.Chorus.Delay = AL_CHORUS_DEFAULT_DELAY; + effect->vtab = &ALchorus_vtable; + break; + case AL_EFFECT_COMPRESSOR: + effect->Props.Compressor.OnOff = AL_COMPRESSOR_DEFAULT_ONOFF; + effect->vtab = &ALcompressor_vtable; + break; + case AL_EFFECT_DISTORTION: + effect->Props.Distortion.Edge = AL_DISTORTION_DEFAULT_EDGE; + effect->Props.Distortion.Gain = AL_DISTORTION_DEFAULT_GAIN; + effect->Props.Distortion.LowpassCutoff = AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF; + effect->Props.Distortion.EQCenter = AL_DISTORTION_DEFAULT_EQCENTER; + effect->Props.Distortion.EQBandwidth = AL_DISTORTION_DEFAULT_EQBANDWIDTH; + effect->vtab = &ALdistortion_vtable; + break; + case AL_EFFECT_ECHO: + effect->Props.Echo.Delay = AL_ECHO_DEFAULT_DELAY; + effect->Props.Echo.LRDelay = AL_ECHO_DEFAULT_LRDELAY; + effect->Props.Echo.Damping = AL_ECHO_DEFAULT_DAMPING; + effect->Props.Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK; + effect->Props.Echo.Spread = AL_ECHO_DEFAULT_SPREAD; + effect->vtab = &ALecho_vtable; + break; + case AL_EFFECT_EQUALIZER: + effect->Props.Equalizer.LowCutoff = AL_EQUALIZER_DEFAULT_LOW_CUTOFF; + effect->Props.Equalizer.LowGain = AL_EQUALIZER_DEFAULT_LOW_GAIN; + effect->Props.Equalizer.Mid1Center = AL_EQUALIZER_DEFAULT_MID1_CENTER; + effect->Props.Equalizer.Mid1Gain = AL_EQUALIZER_DEFAULT_MID1_GAIN; + effect->Props.Equalizer.Mid1Width = AL_EQUALIZER_DEFAULT_MID1_WIDTH; + effect->Props.Equalizer.Mid2Center = AL_EQUALIZER_DEFAULT_MID2_CENTER; + effect->Props.Equalizer.Mid2Gain = AL_EQUALIZER_DEFAULT_MID2_GAIN; + effect->Props.Equalizer.Mid2Width = AL_EQUALIZER_DEFAULT_MID2_WIDTH; + effect->Props.Equalizer.HighCutoff = AL_EQUALIZER_DEFAULT_HIGH_CUTOFF; + effect->Props.Equalizer.HighGain = AL_EQUALIZER_DEFAULT_HIGH_GAIN; + effect->vtab = &ALequalizer_vtable; + break; + case AL_EFFECT_FLANGER: + effect->Props.Chorus.Waveform = AL_FLANGER_DEFAULT_WAVEFORM; + effect->Props.Chorus.Phase = AL_FLANGER_DEFAULT_PHASE; + effect->Props.Chorus.Rate = AL_FLANGER_DEFAULT_RATE; + effect->Props.Chorus.Depth = AL_FLANGER_DEFAULT_DEPTH; + effect->Props.Chorus.Feedback = AL_FLANGER_DEFAULT_FEEDBACK; + effect->Props.Chorus.Delay = AL_FLANGER_DEFAULT_DELAY; + effect->vtab = &ALflanger_vtable; + break; + case AL_EFFECT_FREQUENCY_SHIFTER: + effect->Props.Fshifter.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY; + effect->Props.Fshifter.LeftDirection = AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION; + effect->Props.Fshifter.RightDirection = AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION; + effect->vtab = &ALfshifter_vtable; + break; + case AL_EFFECT_RING_MODULATOR: + effect->Props.Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY; + effect->Props.Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF; + effect->Props.Modulator.Waveform = AL_RING_MODULATOR_DEFAULT_WAVEFORM; + effect->vtab = &ALmodulator_vtable; + break; + case AL_EFFECT_PITCH_SHIFTER: + effect->Props.Pshifter.CoarseTune = AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE; + effect->Props.Pshifter.FineTune = AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE; + effect->vtab = &ALpshifter_vtable; + break; + case AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT: + case AL_EFFECT_DEDICATED_DIALOGUE: + effect->Props.Dedicated.Gain = 1.0f; + effect->vtab = &ALdedicated_vtable; + break; + default: + effect->vtab = &ALnull_vtable; + break; + } + effect->type = type; +} + + +#include "AL/efx-presets.h" + +#define DECL(x) { #x, EFX_REVERB_PRESET_##x } +static const struct { + const char name[32]; + EFXEAXREVERBPROPERTIES props; +} reverblist[] = { + DECL(GENERIC), + DECL(PADDEDCELL), + DECL(ROOM), + DECL(BATHROOM), + DECL(LIVINGROOM), + DECL(STONEROOM), + DECL(AUDITORIUM), + DECL(CONCERTHALL), + DECL(CAVE), + DECL(ARENA), + DECL(HANGAR), + DECL(CARPETEDHALLWAY), + DECL(HALLWAY), + DECL(STONECORRIDOR), + DECL(ALLEY), + DECL(FOREST), + DECL(CITY), + DECL(MOUNTAINS), + DECL(QUARRY), + DECL(PLAIN), + DECL(PARKINGLOT), + DECL(SEWERPIPE), + DECL(UNDERWATER), + DECL(DRUGGED), + DECL(DIZZY), + DECL(PSYCHOTIC), + + DECL(CASTLE_SMALLROOM), + DECL(CASTLE_SHORTPASSAGE), + DECL(CASTLE_MEDIUMROOM), + DECL(CASTLE_LARGEROOM), + DECL(CASTLE_LONGPASSAGE), + DECL(CASTLE_HALL), + DECL(CASTLE_CUPBOARD), + DECL(CASTLE_COURTYARD), + DECL(CASTLE_ALCOVE), + + DECL(FACTORY_SMALLROOM), + DECL(FACTORY_SHORTPASSAGE), + DECL(FACTORY_MEDIUMROOM), + DECL(FACTORY_LARGEROOM), + DECL(FACTORY_LONGPASSAGE), + DECL(FACTORY_HALL), + DECL(FACTORY_CUPBOARD), + DECL(FACTORY_COURTYARD), + DECL(FACTORY_ALCOVE), + + DECL(ICEPALACE_SMALLROOM), + DECL(ICEPALACE_SHORTPASSAGE), + DECL(ICEPALACE_MEDIUMROOM), + DECL(ICEPALACE_LARGEROOM), + DECL(ICEPALACE_LONGPASSAGE), + DECL(ICEPALACE_HALL), + DECL(ICEPALACE_CUPBOARD), + DECL(ICEPALACE_COURTYARD), + DECL(ICEPALACE_ALCOVE), + + DECL(SPACESTATION_SMALLROOM), + DECL(SPACESTATION_SHORTPASSAGE), + DECL(SPACESTATION_MEDIUMROOM), + DECL(SPACESTATION_LARGEROOM), + DECL(SPACESTATION_LONGPASSAGE), + DECL(SPACESTATION_HALL), + DECL(SPACESTATION_CUPBOARD), + DECL(SPACESTATION_ALCOVE), + + DECL(WOODEN_SMALLROOM), + DECL(WOODEN_SHORTPASSAGE), + DECL(WOODEN_MEDIUMROOM), + DECL(WOODEN_LARGEROOM), + DECL(WOODEN_LONGPASSAGE), + DECL(WOODEN_HALL), + DECL(WOODEN_CUPBOARD), + DECL(WOODEN_COURTYARD), + DECL(WOODEN_ALCOVE), + + DECL(SPORT_EMPTYSTADIUM), + DECL(SPORT_SQUASHCOURT), + DECL(SPORT_SMALLSWIMMINGPOOL), + DECL(SPORT_LARGESWIMMINGPOOL), + DECL(SPORT_GYMNASIUM), + DECL(SPORT_FULLSTADIUM), + DECL(SPORT_STADIUMTANNOY), + + DECL(PREFAB_WORKSHOP), + DECL(PREFAB_SCHOOLROOM), + DECL(PREFAB_PRACTISEROOM), + DECL(PREFAB_OUTHOUSE), + DECL(PREFAB_CARAVAN), + + DECL(DOME_TOMB), + DECL(PIPE_SMALL), + DECL(DOME_SAINTPAULS), + DECL(PIPE_LONGTHIN), + DECL(PIPE_LARGE), + DECL(PIPE_RESONANT), + + DECL(OUTDOORS_BACKYARD), + DECL(OUTDOORS_ROLLINGPLAINS), + DECL(OUTDOORS_DEEPCANYON), + DECL(OUTDOORS_CREEK), + DECL(OUTDOORS_VALLEY), + + DECL(MOOD_HEAVEN), + DECL(MOOD_HELL), + DECL(MOOD_MEMORY), + + DECL(DRIVING_COMMENTATOR), + DECL(DRIVING_PITGARAGE), + DECL(DRIVING_INCAR_RACER), + DECL(DRIVING_INCAR_SPORTS), + DECL(DRIVING_INCAR_LUXURY), + DECL(DRIVING_FULLGRANDSTAND), + DECL(DRIVING_EMPTYGRANDSTAND), + DECL(DRIVING_TUNNEL), + + DECL(CITY_STREETS), + DECL(CITY_SUBWAY), + DECL(CITY_MUSEUM), + DECL(CITY_LIBRARY), + DECL(CITY_UNDERPASS), + DECL(CITY_ABANDONED), + + DECL(DUSTYROOM), + DECL(CHAPEL), + DECL(SMALLWATERROOM), +}; +#undef DECL + +void LoadReverbPreset(const char *name, ALeffect *effect) +{ + size_t i; + + if(strcasecmp(name, "NONE") == 0) + { + InitEffectParams(effect, AL_EFFECT_NULL); + TRACE("Loading reverb '%s'\n", "NONE"); + return; + } + + if(!DisabledEffects[EAXREVERB_EFFECT]) + InitEffectParams(effect, AL_EFFECT_EAXREVERB); + else if(!DisabledEffects[REVERB_EFFECT]) + InitEffectParams(effect, AL_EFFECT_REVERB); + else + InitEffectParams(effect, AL_EFFECT_NULL); + for(i = 0;i < COUNTOF(reverblist);i++) + { + const EFXEAXREVERBPROPERTIES *props; + + if(strcasecmp(name, reverblist[i].name) != 0) + continue; + + TRACE("Loading reverb '%s'\n", reverblist[i].name); + props = &reverblist[i].props; + effect->Props.Reverb.Density = props->flDensity; + effect->Props.Reverb.Diffusion = props->flDiffusion; + effect->Props.Reverb.Gain = props->flGain; + effect->Props.Reverb.GainHF = props->flGainHF; + effect->Props.Reverb.GainLF = props->flGainLF; + effect->Props.Reverb.DecayTime = props->flDecayTime; + effect->Props.Reverb.DecayHFRatio = props->flDecayHFRatio; + effect->Props.Reverb.DecayLFRatio = props->flDecayLFRatio; + effect->Props.Reverb.ReflectionsGain = props->flReflectionsGain; + effect->Props.Reverb.ReflectionsDelay = props->flReflectionsDelay; + effect->Props.Reverb.ReflectionsPan[0] = props->flReflectionsPan[0]; + effect->Props.Reverb.ReflectionsPan[1] = props->flReflectionsPan[1]; + effect->Props.Reverb.ReflectionsPan[2] = props->flReflectionsPan[2]; + effect->Props.Reverb.LateReverbGain = props->flLateReverbGain; + effect->Props.Reverb.LateReverbDelay = props->flLateReverbDelay; + effect->Props.Reverb.LateReverbPan[0] = props->flLateReverbPan[0]; + effect->Props.Reverb.LateReverbPan[1] = props->flLateReverbPan[1]; + effect->Props.Reverb.LateReverbPan[2] = props->flLateReverbPan[2]; + effect->Props.Reverb.EchoTime = props->flEchoTime; + effect->Props.Reverb.EchoDepth = props->flEchoDepth; + effect->Props.Reverb.ModulationTime = props->flModulationTime; + effect->Props.Reverb.ModulationDepth = props->flModulationDepth; + effect->Props.Reverb.AirAbsorptionGainHF = props->flAirAbsorptionGainHF; + effect->Props.Reverb.HFReference = props->flHFReference; + effect->Props.Reverb.LFReference = props->flLFReference; + effect->Props.Reverb.RoomRolloffFactor = props->flRoomRolloffFactor; + effect->Props.Reverb.DecayHFLimit = props->iDecayHFLimit; + return; + } + + WARN("Reverb preset '%s' not found\n", name); +} diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c deleted file mode 100644 index 3803fae6..00000000 --- a/OpenAL32/alFilter.c +++ /dev/null @@ -1,668 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include - -#include "alMain.h" -#include "alu.h" -#include "alFilter.h" -#include "alError.h" - - -#define FILTER_MIN_GAIN 0.0f -#define FILTER_MAX_GAIN 4.0f /* +12dB */ - -static ALfilter *AllocFilter(ALCcontext *context); -static void FreeFilter(ALCdevice *device, ALfilter *filter); -static void InitFilterParams(ALfilter *filter, ALenum type); - -static inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) -{ - FilterSubList *sublist; - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= VECTOR_SIZE(device->FilterList))) - return NULL; - sublist = &VECTOR_ELEM(device->FilterList, lidx); - if(UNLIKELY(sublist->FreeMask & (U64(1)<Filters + slidx; -} - - -AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) -{ - ALCcontext *context; - ALsizei cur = 0; - - context = GetContextRef(); - if(!context) return; - - if(n < 0) - alSetError(context, AL_INVALID_VALUE, "Generating %d filters", n); - else for(cur = 0;cur < n;cur++) - { - ALfilter *filter = AllocFilter(context); - if(!filter) - { - alDeleteFilters(cur, filters); - break; - } - - filters[cur] = filter->id; - } - - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) -{ - ALCdevice *device; - ALCcontext *context; - ALfilter *filter; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - LockFilterList(device); - if(n < 0) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d filters", n); - for(i = 0;i < n;i++) - { - if(filters[i] && LookupFilter(device, filters[i]) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid filter ID %u", filters[i]); - } - for(i = 0;i < n;i++) - { - if((filter=LookupFilter(device, filters[i])) != NULL) - FreeFilter(device, filter); - } - -done: - UnlockFilterList(device); - ALCcontext_DecRef(context); -} - -AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter) -{ - ALCcontext *Context; - ALboolean result; - - Context = GetContextRef(); - if(!Context) return AL_FALSE; - - LockFilterList(Context->Device); - result = ((!filter || LookupFilter(Context->Device, filter)) ? - AL_TRUE : AL_FALSE); - UnlockFilterList(Context->Device); - - ALCcontext_DecRef(Context); - - return result; -} - -AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) -{ - ALCcontext *Context; - ALCdevice *Device; - ALfilter *ALFilter; - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockFilterList(Device); - if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - if(param == AL_FILTER_TYPE) - { - if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS || - value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS) - InitFilterParams(ALFilter, value); - else - alSetError(Context, AL_INVALID_VALUE, "Invalid filter type 0x%04x", value); - } - else - { - /* Call the appropriate handler */ - ALfilter_setParami(ALFilter, Context, param, value); - } - } - UnlockFilterList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *values) -{ - ALCcontext *Context; - ALCdevice *Device; - ALfilter *ALFilter; - - switch(param) - { - case AL_FILTER_TYPE: - alFilteri(filter, param, values[0]); - return; - } - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockFilterList(Device); - if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_setParamiv(ALFilter, Context, param, values); - } - UnlockFilterList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value) -{ - ALCcontext *Context; - ALCdevice *Device; - ALfilter *ALFilter; - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockFilterList(Device); - if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_setParamf(ALFilter, Context, param, value); - } - UnlockFilterList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *values) -{ - ALCcontext *Context; - ALCdevice *Device; - ALfilter *ALFilter; - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockFilterList(Device); - if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_setParamfv(ALFilter, Context, param, values); - } - UnlockFilterList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value) -{ - ALCcontext *Context; - ALCdevice *Device; - ALfilter *ALFilter; - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockFilterList(Device); - if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - if(param == AL_FILTER_TYPE) - *value = ALFilter->type; - else - { - /* Call the appropriate handler */ - ALfilter_getParami(ALFilter, Context, param, value); - } - } - UnlockFilterList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *values) -{ - ALCcontext *Context; - ALCdevice *Device; - ALfilter *ALFilter; - - switch(param) - { - case AL_FILTER_TYPE: - alGetFilteri(filter, param, values); - return; - } - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockFilterList(Device); - if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_getParamiv(ALFilter, Context, param, values); - } - UnlockFilterList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *value) -{ - ALCcontext *Context; - ALCdevice *Device; - ALfilter *ALFilter; - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockFilterList(Device); - if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_getParamf(ALFilter, Context, param, value); - } - UnlockFilterList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *values) -{ - ALCcontext *Context; - ALCdevice *Device; - ALfilter *ALFilter; - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockFilterList(Device); - if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_getParamfv(ALFilter, Context, param, values); - } - UnlockFilterList(Device); - - ALCcontext_DecRef(Context); -} - - -static void ALlowpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } -static void ALlowpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } -static void ALlowpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_LOWPASS_GAIN: - if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gain %f out of range", val); - filter->Gain = val; - break; - - case AL_LOWPASS_GAINHF: - if(!(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gainhf %f out of range", val); - filter->GainHF = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param); - } -} -static void ALlowpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) -{ ALlowpass_setParamf(filter, context, param, vals[0]); } - -static void ALlowpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } -static void ALlowpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } -static void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_LOWPASS_GAIN: - *val = filter->Gain; - break; - - case AL_LOWPASS_GAINHF: - *val = filter->GainHF; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param); - } -} -static void ALlowpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) -{ ALlowpass_getParamf(filter, context, param, vals); } - -DEFINE_ALFILTER_VTABLE(ALlowpass); - - -static void ALhighpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } -static void ALhighpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } -static void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_HIGHPASS_GAIN: - if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gain out of range"); - filter->Gain = val; - break; - - case AL_HIGHPASS_GAINLF: - if(!(val >= AL_HIGHPASS_MIN_GAINLF && val <= AL_HIGHPASS_MAX_GAINLF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gainlf out of range"); - filter->GainLF = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param); - } -} -static void ALhighpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) -{ ALhighpass_setParamf(filter, context, param, vals[0]); } - -static void ALhighpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } -static void ALhighpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } -static void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_HIGHPASS_GAIN: - *val = filter->Gain; - break; - - case AL_HIGHPASS_GAINLF: - *val = filter->GainLF; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param); - } -} -static void ALhighpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) -{ ALhighpass_getParamf(filter, context, param, vals); } - -DEFINE_ALFILTER_VTABLE(ALhighpass); - - -static void ALbandpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } -static void ALbandpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } -static void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_BANDPASS_GAIN: - if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gain out of range"); - filter->Gain = val; - break; - - case AL_BANDPASS_GAINHF: - if(!(val >= AL_BANDPASS_MIN_GAINHF && val <= AL_BANDPASS_MAX_GAINHF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainhf out of range"); - filter->GainHF = val; - break; - - case AL_BANDPASS_GAINLF: - if(!(val >= AL_BANDPASS_MIN_GAINLF && val <= AL_BANDPASS_MAX_GAINLF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainlf out of range"); - filter->GainLF = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param); - } -} -static void ALbandpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) -{ ALbandpass_setParamf(filter, context, param, vals[0]); } - -static void ALbandpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } -static void ALbandpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } -static void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_BANDPASS_GAIN: - *val = filter->Gain; - break; - - case AL_BANDPASS_GAINHF: - *val = filter->GainHF; - break; - - case AL_BANDPASS_GAINLF: - *val = filter->GainLF; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param); - } -} -static void ALbandpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) -{ ALbandpass_getParamf(filter, context, param, vals); } - -DEFINE_ALFILTER_VTABLE(ALbandpass); - - -static void ALnullfilter_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -static void ALnullfilter_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -static void ALnullfilter_setParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -static void ALnullfilter_setParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALfloat *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } - -static void ALnullfilter_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -static void ALnullfilter_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -static void ALnullfilter_getParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat *UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -static void ALnullfilter_getParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } - -DEFINE_ALFILTER_VTABLE(ALnullfilter); - - -static ALfilter *AllocFilter(ALCcontext *context) -{ - ALCdevice *device = context->Device; - FilterSubList *sublist, *subend; - ALfilter *filter = NULL; - ALsizei lidx = 0; - ALsizei slidx; - - almtx_lock(&device->FilterLock); - sublist = VECTOR_BEGIN(device->FilterList); - subend = VECTOR_END(device->FilterList); - for(;sublist != subend;++sublist) - { - if(sublist->FreeMask) - { - slidx = CTZ64(sublist->FreeMask); - filter = sublist->Filters + slidx; - break; - } - ++lidx; - } - if(UNLIKELY(!filter)) - { - const FilterSubList empty_sublist = { 0, NULL }; - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ - if(UNLIKELY(VECTOR_SIZE(device->FilterList) >= 1<<25)) - { - almtx_unlock(&device->FilterLock); - alSetError(context, AL_OUT_OF_MEMORY, "Too many filters allocated"); - return NULL; - } - lidx = (ALsizei)VECTOR_SIZE(device->FilterList); - VECTOR_PUSH_BACK(device->FilterList, empty_sublist); - sublist = &VECTOR_BACK(device->FilterList); - sublist->FreeMask = ~U64(0); - sublist->Filters = al_calloc(16, sizeof(ALfilter)*64); - if(UNLIKELY(!sublist->Filters)) - { - VECTOR_POP_BACK(device->FilterList); - almtx_unlock(&device->FilterLock); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate filter batch"); - return NULL; - } - - slidx = 0; - filter = sublist->Filters + slidx; - } - - memset(filter, 0, sizeof(*filter)); - InitFilterParams(filter, AL_FILTER_NULL); - - /* Add 1 to avoid filter ID 0. */ - filter->id = ((lidx<<6) | slidx) + 1; - - sublist->FreeMask &= ~(U64(1)<FilterLock); - - return filter; -} - -static void FreeFilter(ALCdevice *device, ALfilter *filter) -{ - ALuint id = filter->id - 1; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; - - memset(filter, 0, sizeof(*filter)); - - VECTOR_ELEM(device->FilterList, lidx).FreeMask |= U64(1) << slidx; -} - -void ReleaseALFilters(ALCdevice *device) -{ - FilterSubList *sublist = VECTOR_BEGIN(device->FilterList); - FilterSubList *subend = VECTOR_END(device->FilterList); - size_t leftover = 0; - for(;sublist != subend;++sublist) - { - ALuint64 usemask = ~sublist->FreeMask; - while(usemask) - { - ALsizei idx = CTZ64(usemask); - ALfilter *filter = sublist->Filters + idx; - - memset(filter, 0, sizeof(*filter)); - ++leftover; - - usemask &= ~(U64(1) << idx); - } - sublist->FreeMask = ~usemask; - } - if(leftover > 0) - WARN("(%p) Deleted "SZFMT" Filter%s\n", device, leftover, (leftover==1)?"":"s"); -} - - -static void InitFilterParams(ALfilter *filter, ALenum type) -{ - if(type == AL_FILTER_LOWPASS) - { - filter->Gain = AL_LOWPASS_DEFAULT_GAIN; - filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF; - filter->HFReference = LOWPASSFREQREF; - filter->GainLF = 1.0f; - filter->LFReference = HIGHPASSFREQREF; - filter->vtab = &ALlowpass_vtable; - } - else if(type == AL_FILTER_HIGHPASS) - { - filter->Gain = AL_HIGHPASS_DEFAULT_GAIN; - filter->GainHF = 1.0f; - filter->HFReference = LOWPASSFREQREF; - filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF; - filter->LFReference = HIGHPASSFREQREF; - filter->vtab = &ALhighpass_vtable; - } - else if(type == AL_FILTER_BANDPASS) - { - filter->Gain = AL_BANDPASS_DEFAULT_GAIN; - filter->GainHF = AL_BANDPASS_DEFAULT_GAINHF; - filter->HFReference = LOWPASSFREQREF; - filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF; - filter->LFReference = HIGHPASSFREQREF; - filter->vtab = &ALbandpass_vtable; - } - else - { - filter->Gain = 1.0f; - filter->GainHF = 1.0f; - filter->HFReference = LOWPASSFREQREF; - filter->GainLF = 1.0f; - filter->LFReference = HIGHPASSFREQREF; - filter->vtab = &ALnullfilter_vtable; - } - filter->type = type; -} diff --git a/OpenAL32/alFilter.cpp b/OpenAL32/alFilter.cpp new file mode 100644 index 00000000..a85c5dde --- /dev/null +++ b/OpenAL32/alFilter.cpp @@ -0,0 +1,668 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include + +#include "alMain.h" +#include "alu.h" +#include "alFilter.h" +#include "alError.h" + + +#define FILTER_MIN_GAIN 0.0f +#define FILTER_MAX_GAIN 4.0f /* +12dB */ + +static ALfilter *AllocFilter(ALCcontext *context); +static void FreeFilter(ALCdevice *device, ALfilter *filter); +static void InitFilterParams(ALfilter *filter, ALenum type); + +static inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) +{ + FilterSubList *sublist; + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= VECTOR_SIZE(device->FilterList))) + return NULL; + sublist = &VECTOR_ELEM(device->FilterList, lidx); + if(UNLIKELY(sublist->FreeMask & (U64(1)<Filters + slidx; +} + + +AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) +{ + ALCcontext *context; + ALsizei cur = 0; + + context = GetContextRef(); + if(!context) return; + + if(n < 0) + alSetError(context, AL_INVALID_VALUE, "Generating %d filters", n); + else for(cur = 0;cur < n;cur++) + { + ALfilter *filter = AllocFilter(context); + if(!filter) + { + alDeleteFilters(cur, filters); + break; + } + + filters[cur] = filter->id; + } + + ALCcontext_DecRef(context); +} + +AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) +{ + ALCdevice *device; + ALCcontext *context; + ALfilter *filter; + ALsizei i; + + context = GetContextRef(); + if(!context) return; + + device = context->Device; + LockFilterList(device); + if(n < 0) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d filters", n); + for(i = 0;i < n;i++) + { + if(filters[i] && LookupFilter(device, filters[i]) == NULL) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid filter ID %u", filters[i]); + } + for(i = 0;i < n;i++) + { + if((filter=LookupFilter(device, filters[i])) != NULL) + FreeFilter(device, filter); + } + +done: + UnlockFilterList(device); + ALCcontext_DecRef(context); +} + +AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter) +{ + ALCcontext *Context; + ALboolean result; + + Context = GetContextRef(); + if(!Context) return AL_FALSE; + + LockFilterList(Context->Device); + result = ((!filter || LookupFilter(Context->Device, filter)) ? + AL_TRUE : AL_FALSE); + UnlockFilterList(Context->Device); + + ALCcontext_DecRef(Context); + + return result; +} + +AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) +{ + ALCcontext *Context; + ALCdevice *Device; + ALfilter *ALFilter; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + LockFilterList(Device); + if((ALFilter=LookupFilter(Device, filter)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + if(param == AL_FILTER_TYPE) + { + if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS || + value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS) + InitFilterParams(ALFilter, value); + else + alSetError(Context, AL_INVALID_VALUE, "Invalid filter type 0x%04x", value); + } + else + { + /* Call the appropriate handler */ + ALfilter_setParami(ALFilter, Context, param, value); + } + } + UnlockFilterList(Device); + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *values) +{ + ALCcontext *Context; + ALCdevice *Device; + ALfilter *ALFilter; + + switch(param) + { + case AL_FILTER_TYPE: + alFilteri(filter, param, values[0]); + return; + } + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + LockFilterList(Device); + if((ALFilter=LookupFilter(Device, filter)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_setParamiv(ALFilter, Context, param, values); + } + UnlockFilterList(Device); + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value) +{ + ALCcontext *Context; + ALCdevice *Device; + ALfilter *ALFilter; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + LockFilterList(Device); + if((ALFilter=LookupFilter(Device, filter)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_setParamf(ALFilter, Context, param, value); + } + UnlockFilterList(Device); + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *values) +{ + ALCcontext *Context; + ALCdevice *Device; + ALfilter *ALFilter; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + LockFilterList(Device); + if((ALFilter=LookupFilter(Device, filter)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_setParamfv(ALFilter, Context, param, values); + } + UnlockFilterList(Device); + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value) +{ + ALCcontext *Context; + ALCdevice *Device; + ALfilter *ALFilter; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + LockFilterList(Device); + if((ALFilter=LookupFilter(Device, filter)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + if(param == AL_FILTER_TYPE) + *value = ALFilter->type; + else + { + /* Call the appropriate handler */ + ALfilter_getParami(ALFilter, Context, param, value); + } + } + UnlockFilterList(Device); + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *values) +{ + ALCcontext *Context; + ALCdevice *Device; + ALfilter *ALFilter; + + switch(param) + { + case AL_FILTER_TYPE: + alGetFilteri(filter, param, values); + return; + } + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + LockFilterList(Device); + if((ALFilter=LookupFilter(Device, filter)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_getParamiv(ALFilter, Context, param, values); + } + UnlockFilterList(Device); + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *value) +{ + ALCcontext *Context; + ALCdevice *Device; + ALfilter *ALFilter; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + LockFilterList(Device); + if((ALFilter=LookupFilter(Device, filter)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_getParamf(ALFilter, Context, param, value); + } + UnlockFilterList(Device); + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *values) +{ + ALCcontext *Context; + ALCdevice *Device; + ALfilter *ALFilter; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + LockFilterList(Device); + if((ALFilter=LookupFilter(Device, filter)) == NULL) + alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_getParamfv(ALFilter, Context, param, values); + } + UnlockFilterList(Device); + + ALCcontext_DecRef(Context); +} + + +static void ALlowpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } +static void ALlowpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } +static void ALlowpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_LOWPASS_GAIN: + if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gain %f out of range", val); + filter->Gain = val; + break; + + case AL_LOWPASS_GAINHF: + if(!(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gainhf %f out of range", val); + filter->GainHF = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param); + } +} +static void ALlowpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALlowpass_setParamf(filter, context, param, vals[0]); } + +static void ALlowpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } +static void ALlowpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } +static void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_LOWPASS_GAIN: + *val = filter->Gain; + break; + + case AL_LOWPASS_GAINHF: + *val = filter->GainHF; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param); + } +} +static void ALlowpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALlowpass_getParamf(filter, context, param, vals); } + +DEFINE_ALFILTER_VTABLE(ALlowpass); + + +static void ALhighpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } +static void ALhighpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } +static void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_HIGHPASS_GAIN: + if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gain out of range"); + filter->Gain = val; + break; + + case AL_HIGHPASS_GAINLF: + if(!(val >= AL_HIGHPASS_MIN_GAINLF && val <= AL_HIGHPASS_MAX_GAINLF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gainlf out of range"); + filter->GainLF = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param); + } +} +static void ALhighpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALhighpass_setParamf(filter, context, param, vals[0]); } + +static void ALhighpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } +static void ALhighpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } +static void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_HIGHPASS_GAIN: + *val = filter->Gain; + break; + + case AL_HIGHPASS_GAINLF: + *val = filter->GainLF; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param); + } +} +static void ALhighpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALhighpass_getParamf(filter, context, param, vals); } + +DEFINE_ALFILTER_VTABLE(ALhighpass); + + +static void ALbandpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } +static void ALbandpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } +static void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_BANDPASS_GAIN: + if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gain out of range"); + filter->Gain = val; + break; + + case AL_BANDPASS_GAINHF: + if(!(val >= AL_BANDPASS_MIN_GAINHF && val <= AL_BANDPASS_MAX_GAINHF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainhf out of range"); + filter->GainHF = val; + break; + + case AL_BANDPASS_GAINLF: + if(!(val >= AL_BANDPASS_MIN_GAINLF && val <= AL_BANDPASS_MAX_GAINLF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainlf out of range"); + filter->GainLF = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param); + } +} +static void ALbandpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALbandpass_setParamf(filter, context, param, vals[0]); } + +static void ALbandpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } +static void ALbandpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } +static void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_BANDPASS_GAIN: + *val = filter->Gain; + break; + + case AL_BANDPASS_GAINHF: + *val = filter->GainHF; + break; + + case AL_BANDPASS_GAINLF: + *val = filter->GainLF; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param); + } +} +static void ALbandpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALbandpass_getParamf(filter, context, param, vals); } + +DEFINE_ALFILTER_VTABLE(ALbandpass); + + +static void ALnullfilter_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +static void ALnullfilter_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +static void ALnullfilter_setParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +static void ALnullfilter_setParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALfloat *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } + +static void ALnullfilter_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +static void ALnullfilter_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +static void ALnullfilter_getParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +static void ALnullfilter_getParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } + +DEFINE_ALFILTER_VTABLE(ALnullfilter); + + +static ALfilter *AllocFilter(ALCcontext *context) +{ + ALCdevice *device = context->Device; + FilterSubList *sublist, *subend; + ALfilter *filter = NULL; + ALsizei lidx = 0; + ALsizei slidx; + + almtx_lock(&device->FilterLock); + sublist = VECTOR_BEGIN(device->FilterList); + subend = VECTOR_END(device->FilterList); + for(;sublist != subend;++sublist) + { + if(sublist->FreeMask) + { + slidx = CTZ64(sublist->FreeMask); + filter = sublist->Filters + slidx; + break; + } + ++lidx; + } + if(UNLIKELY(!filter)) + { + const FilterSubList empty_sublist = { 0, NULL }; + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(VECTOR_SIZE(device->FilterList) >= 1<<25)) + { + almtx_unlock(&device->FilterLock); + alSetError(context, AL_OUT_OF_MEMORY, "Too many filters allocated"); + return NULL; + } + lidx = (ALsizei)VECTOR_SIZE(device->FilterList); + VECTOR_PUSH_BACK(device->FilterList, empty_sublist); + sublist = &VECTOR_BACK(device->FilterList); + sublist->FreeMask = ~U64(0); + sublist->Filters = static_cast(al_calloc(16, sizeof(ALfilter)*64)); + if(UNLIKELY(!sublist->Filters)) + { + VECTOR_POP_BACK(device->FilterList); + almtx_unlock(&device->FilterLock); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate filter batch"); + return NULL; + } + + slidx = 0; + filter = sublist->Filters + slidx; + } + + memset(filter, 0, sizeof(*filter)); + InitFilterParams(filter, AL_FILTER_NULL); + + /* Add 1 to avoid filter ID 0. */ + filter->id = ((lidx<<6) | slidx) + 1; + + sublist->FreeMask &= ~(U64(1)<FilterLock); + + return filter; +} + +static void FreeFilter(ALCdevice *device, ALfilter *filter) +{ + ALuint id = filter->id - 1; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; + + memset(filter, 0, sizeof(*filter)); + + VECTOR_ELEM(device->FilterList, lidx).FreeMask |= U64(1) << slidx; +} + +void ReleaseALFilters(ALCdevice *device) +{ + FilterSubList *sublist = VECTOR_BEGIN(device->FilterList); + FilterSubList *subend = VECTOR_END(device->FilterList); + size_t leftover = 0; + for(;sublist != subend;++sublist) + { + ALuint64 usemask = ~sublist->FreeMask; + while(usemask) + { + ALsizei idx = CTZ64(usemask); + ALfilter *filter = sublist->Filters + idx; + + memset(filter, 0, sizeof(*filter)); + ++leftover; + + usemask &= ~(U64(1) << idx); + } + sublist->FreeMask = ~usemask; + } + if(leftover > 0) + WARN("(%p) Deleted " SZFMT " Filter%s\n", device, leftover, (leftover==1)?"":"s"); +} + + +static void InitFilterParams(ALfilter *filter, ALenum type) +{ + if(type == AL_FILTER_LOWPASS) + { + filter->Gain = AL_LOWPASS_DEFAULT_GAIN; + filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF; + filter->HFReference = LOWPASSFREQREF; + filter->GainLF = 1.0f; + filter->LFReference = HIGHPASSFREQREF; + filter->vtab = &ALlowpass_vtable; + } + else if(type == AL_FILTER_HIGHPASS) + { + filter->Gain = AL_HIGHPASS_DEFAULT_GAIN; + filter->GainHF = 1.0f; + filter->HFReference = LOWPASSFREQREF; + filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF; + filter->LFReference = HIGHPASSFREQREF; + filter->vtab = &ALhighpass_vtable; + } + else if(type == AL_FILTER_BANDPASS) + { + filter->Gain = AL_BANDPASS_DEFAULT_GAIN; + filter->GainHF = AL_BANDPASS_DEFAULT_GAINHF; + filter->HFReference = LOWPASSFREQREF; + filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF; + filter->LFReference = HIGHPASSFREQREF; + filter->vtab = &ALbandpass_vtable; + } + else + { + filter->Gain = 1.0f; + filter->GainHF = 1.0f; + filter->HFReference = LOWPASSFREQREF; + filter->GainLF = 1.0f; + filter->LFReference = HIGHPASSFREQREF; + filter->vtab = &ALnullfilter_vtable; + } + filter->type = type; +} -- cgit v1.2.3 From 53373a43b8984aea6a7e2107b264d208c00a5f53 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Nov 2018 20:32:19 -0800 Subject: Convert ALu.c to C++ Required changes to bsincgen to generate C++-friendly structures. --- Alc/ALu.c | 1879 ---------------------------------------------- Alc/alu.cpp | 1884 +++++++++++++++++++++++++++++++++++++++++++++++ Alc/filters/defs.h | 8 + Alc/mixer/defs.h | 8 + Alc/mixvoice.c | 2 +- CMakeLists.txt | 2 +- OpenAL32/Include/alu.h | 6 +- native-tools/bsincgen.c | 72 +- 8 files changed, 1941 insertions(+), 1920 deletions(-) delete mode 100644 Alc/ALu.c create mode 100644 Alc/alu.cpp diff --git a/Alc/ALu.c b/Alc/ALu.c deleted file mode 100644 index a9b5a009..00000000 --- a/Alc/ALu.c +++ /dev/null @@ -1,1879 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "alMain.h" -#include "alSource.h" -#include "alBuffer.h" -#include "alListener.h" -#include "alAuxEffectSlot.h" -#include "alu.h" -#include "bs2b.h" -#include "hrtf.h" -#include "mastering.h" -#include "uhjfilter.h" -#include "bformatdec.h" -#include "static_assert.h" -#include "ringbuffer.h" -#include "filters/splitter.h" - -#include "mixer/defs.h" -#include "fpu_modes.h" -#include "cpu_caps.h" -#include "bsinc_inc.h" - - -/* Cone scalar */ -ALfloat ConeScale = 1.0f; - -/* Localized Z scalar for mono sources */ -ALfloat ZScale = 1.0f; - -/* Force default speed of sound for distance-related reverb decay. */ -ALboolean OverrideReverbSpeedOfSound = AL_FALSE; - -const aluMatrixf IdentityMatrixf = {{ - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 1.0f }, -}}; - - -static void ClearArray(ALfloat f[MAX_OUTPUT_CHANNELS]) -{ - size_t i; - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - f[i] = 0.0f; -} - -struct ChanMap { - enum Channel channel; - ALfloat angle; - ALfloat elevation; -}; - -static HrtfDirectMixerFunc MixDirectHrtf = MixDirectHrtf_C; - - -void DeinitVoice(ALvoice *voice) -{ - al_free(ATOMIC_EXCHANGE_PTR_SEQ(&voice->Update, NULL)); -} - - -static inline HrtfDirectMixerFunc SelectHrtfMixer(void) -{ -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return MixDirectHrtf_Neon; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return MixDirectHrtf_SSE; -#endif - - return MixDirectHrtf_C; -} - - -/* This RNG method was created based on the math found in opusdec. It's quick, - * and starting with a seed value of 22222, is suitable for generating - * whitenoise. - */ -static inline ALuint dither_rng(ALuint *seed) -{ - *seed = (*seed * 96314165) + 907633515; - return *seed; -} - - -static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector) -{ - outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1]; - outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2]; - outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0]; -} - -static inline ALfloat aluDotproduct(const aluVector *vec1, const aluVector *vec2) -{ - return vec1->v[0]*vec2->v[0] + vec1->v[1]*vec2->v[1] + vec1->v[2]*vec2->v[2]; -} - -static ALfloat aluNormalize(ALfloat *vec) -{ - ALfloat length = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); - if(length > FLT_EPSILON) - { - ALfloat inv_length = 1.0f/length; - vec[0] *= inv_length; - vec[1] *= inv_length; - vec[2] *= inv_length; - return length; - } - vec[0] = vec[1] = vec[2] = 0.0f; - return 0.0f; -} - -static void aluMatrixfFloat3(ALfloat *vec, ALfloat w, const aluMatrixf *mtx) -{ - ALfloat v[4] = { vec[0], vec[1], vec[2], w }; - - vec[0] = v[0]*mtx->m[0][0] + v[1]*mtx->m[1][0] + v[2]*mtx->m[2][0] + v[3]*mtx->m[3][0]; - vec[1] = v[0]*mtx->m[0][1] + v[1]*mtx->m[1][1] + v[2]*mtx->m[2][1] + v[3]*mtx->m[3][1]; - vec[2] = v[0]*mtx->m[0][2] + v[1]*mtx->m[1][2] + v[2]*mtx->m[2][2] + v[3]*mtx->m[3][2]; -} - -static aluVector aluMatrixfVector(const aluMatrixf *mtx, const aluVector *vec) -{ - aluVector v; - v.v[0] = vec->v[0]*mtx->m[0][0] + vec->v[1]*mtx->m[1][0] + vec->v[2]*mtx->m[2][0] + vec->v[3]*mtx->m[3][0]; - v.v[1] = vec->v[0]*mtx->m[0][1] + vec->v[1]*mtx->m[1][1] + vec->v[2]*mtx->m[2][1] + vec->v[3]*mtx->m[3][1]; - v.v[2] = vec->v[0]*mtx->m[0][2] + vec->v[1]*mtx->m[1][2] + vec->v[2]*mtx->m[2][2] + vec->v[3]*mtx->m[3][2]; - v.v[3] = vec->v[0]*mtx->m[0][3] + vec->v[1]*mtx->m[1][3] + vec->v[2]*mtx->m[2][3] + vec->v[3]*mtx->m[3][3]; - return v; -} - - -void aluInit(void) -{ - MixDirectHrtf = SelectHrtfMixer(); -} - - -static void SendSourceStoppedEvent(ALCcontext *context, ALuint id) -{ - AsyncEvent evt = ASYNC_EVENT(EventType_SourceStateChange); - ALbitfieldSOFT enabledevt; - size_t strpos; - ALuint scale; - - enabledevt = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); - if(!(enabledevt&EventType_SourceStateChange)) return; - - evt.u.user.type = AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT; - evt.u.user.id = id; - evt.u.user.param = AL_STOPPED; - - /* Normally snprintf would be used, but this is called from the mixer and - * that function's not real-time safe, so we have to construct it manually. - */ - strcpy(evt.u.user.msg, "Source ID "); strpos = 10; - scale = 1000000000; - while(scale > 0 && scale > id) - scale /= 10; - while(scale > 0) - { - evt.u.user.msg[strpos++] = '0' + ((id/scale)%10); - scale /= 10; - } - strcpy(evt.u.user.msg+strpos, " state changed to AL_STOPPED"); - - if(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) == 1) - alsem_post(&context->EventSem); -} - - -static void ProcessHrtf(ALCdevice *device, ALsizei SamplesToDo) -{ - DirectHrtfState *state; - int lidx, ridx; - ALsizei c; - - if(device->AmbiUp) - ambiup_process(device->AmbiUp, - device->Dry.Buffer, device->Dry.NumChannels, device->FOAOut.Buffer, - SamplesToDo - ); - - lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); - ridx = GetChannelIdxByName(&device->RealOut, FrontRight); - assert(lidx != -1 && ridx != -1); - - state = device->Hrtf; - for(c = 0;c < device->Dry.NumChannels;c++) - { - MixDirectHrtf(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], - device->Dry.Buffer[c], state->Offset, state->IrSize, - state->Chan[c].Coeffs, state->Chan[c].Values, SamplesToDo - ); - } - state->Offset += SamplesToDo; -} - -static void ProcessAmbiDec(ALCdevice *device, ALsizei SamplesToDo) -{ - if(device->Dry.Buffer != device->FOAOut.Buffer) - bformatdec_upSample(device->AmbiDecoder, - device->Dry.Buffer, device->FOAOut.Buffer, device->FOAOut.NumChannels, - SamplesToDo - ); - bformatdec_process(device->AmbiDecoder, - device->RealOut.Buffer, device->RealOut.NumChannels, device->Dry.Buffer, - SamplesToDo - ); -} - -static void ProcessAmbiUp(ALCdevice *device, ALsizei SamplesToDo) -{ - ambiup_process(device->AmbiUp, - device->RealOut.Buffer, device->RealOut.NumChannels, device->FOAOut.Buffer, - SamplesToDo - ); -} - -static void ProcessUhj(ALCdevice *device, ALsizei SamplesToDo) -{ - int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); - int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); - assert(lidx != -1 && ridx != -1); - - /* Encode to stereo-compatible 2-channel UHJ output. */ - EncodeUhj2(device->Uhj_Encoder, - device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], - device->Dry.Buffer, SamplesToDo - ); -} - -static void ProcessBs2b(ALCdevice *device, ALsizei SamplesToDo) -{ - int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); - int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); - assert(lidx != -1 && ridx != -1); - - /* Apply binaural/crossfeed filter */ - bs2b_cross_feed(device->Bs2b, device->RealOut.Buffer[lidx], - device->RealOut.Buffer[ridx], SamplesToDo); -} - -void aluSelectPostProcess(ALCdevice *device) -{ - if(device->HrtfHandle) - device->PostProcess = ProcessHrtf; - else if(device->AmbiDecoder) - device->PostProcess = ProcessAmbiDec; - else if(device->AmbiUp) - device->PostProcess = ProcessAmbiUp; - else if(device->Uhj_Encoder) - device->PostProcess = ProcessUhj; - else if(device->Bs2b) - device->PostProcess = ProcessBs2b; - else - device->PostProcess = NULL; -} - - -/* Prepares the interpolator for a given rate (determined by increment). - * - * With a bit of work, and a trade of memory for CPU cost, this could be - * modified for use with an interpolated increment for buttery-smooth pitch - * changes. - */ -void BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *table) -{ - ALfloat sf = 0.0f; - ALsizei si = BSINC_SCALE_COUNT-1; - - if(increment > FRACTIONONE) - { - sf = (ALfloat)FRACTIONONE / increment; - sf = maxf(0.0f, (BSINC_SCALE_COUNT-1) * (sf-table->scaleBase) * table->scaleRange); - si = float2int(sf); - /* The interpolation factor is fit to this diagonally-symmetric curve - * to reduce the transition ripple caused by interpolating different - * scales of the sinc function. - */ - sf = 1.0f - cosf(asinf(sf - si)); - } - - state->sf = sf; - state->m = table->m[si]; - state->l = (state->m/2) - 1; - state->filter = table->Tab + table->filterOffset[si]; -} - - -static bool CalcContextParams(ALCcontext *Context) -{ - ALlistener *Listener = Context->Listener; - struct ALcontextProps *props; - - props = ATOMIC_EXCHANGE_PTR(&Context->Update, NULL, almemory_order_acq_rel); - if(!props) return false; - - Listener->Params.MetersPerUnit = props->MetersPerUnit; - - Listener->Params.DopplerFactor = props->DopplerFactor; - Listener->Params.SpeedOfSound = props->SpeedOfSound * props->DopplerVelocity; - if(!OverrideReverbSpeedOfSound) - Listener->Params.ReverbSpeedOfSound = Listener->Params.SpeedOfSound * - Listener->Params.MetersPerUnit; - - Listener->Params.SourceDistanceModel = props->SourceDistanceModel; - Listener->Params.DistanceModel = props->DistanceModel; - - ATOMIC_REPLACE_HEAD(struct ALcontextProps*, &Context->FreeContextProps, props); - return true; -} - -static bool CalcListenerParams(ALCcontext *Context) -{ - ALlistener *Listener = Context->Listener; - ALfloat N[3], V[3], U[3], P[3]; - struct ALlistenerProps *props; - aluVector vel; - - props = ATOMIC_EXCHANGE_PTR(&Listener->Update, NULL, almemory_order_acq_rel); - if(!props) return false; - - /* AT then UP */ - N[0] = props->Forward[0]; - N[1] = props->Forward[1]; - N[2] = props->Forward[2]; - aluNormalize(N); - V[0] = props->Up[0]; - V[1] = props->Up[1]; - V[2] = props->Up[2]; - aluNormalize(V); - /* Build and normalize right-vector */ - aluCrossproduct(N, V, U); - aluNormalize(U); - - aluMatrixfSet(&Listener->Params.Matrix, - U[0], V[0], -N[0], 0.0, - U[1], V[1], -N[1], 0.0, - U[2], V[2], -N[2], 0.0, - 0.0, 0.0, 0.0, 1.0 - ); - - P[0] = props->Position[0]; - P[1] = props->Position[1]; - P[2] = props->Position[2]; - aluMatrixfFloat3(P, 1.0, &Listener->Params.Matrix); - aluMatrixfSetRow(&Listener->Params.Matrix, 3, -P[0], -P[1], -P[2], 1.0f); - - aluVectorSet(&vel, props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f); - Listener->Params.Velocity = aluMatrixfVector(&Listener->Params.Matrix, &vel); - - Listener->Params.Gain = props->Gain * Context->GainBoost; - - ATOMIC_REPLACE_HEAD(struct ALlistenerProps*, &Context->FreeListenerProps, props); - return true; -} - -static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) -{ - struct ALeffectslotProps *props; - ALeffectState *state; - - props = ATOMIC_EXCHANGE_PTR(&slot->Update, NULL, almemory_order_acq_rel); - if(!props && !force) return false; - - if(props) - { - slot->Params.Gain = props->Gain; - slot->Params.AuxSendAuto = props->AuxSendAuto; - slot->Params.EffectType = props->Type; - slot->Params.EffectProps = props->Props; - if(IsReverbEffect(props->Type)) - { - slot->Params.RoomRolloff = props->Props.Reverb.RoomRolloffFactor; - slot->Params.DecayTime = props->Props.Reverb.DecayTime; - slot->Params.DecayLFRatio = props->Props.Reverb.DecayLFRatio; - slot->Params.DecayHFRatio = props->Props.Reverb.DecayHFRatio; - slot->Params.DecayHFLimit = props->Props.Reverb.DecayHFLimit; - slot->Params.AirAbsorptionGainHF = props->Props.Reverb.AirAbsorptionGainHF; - } - else - { - slot->Params.RoomRolloff = 0.0f; - slot->Params.DecayTime = 0.0f; - slot->Params.DecayLFRatio = 0.0f; - slot->Params.DecayHFRatio = 0.0f; - slot->Params.DecayHFLimit = AL_FALSE; - slot->Params.AirAbsorptionGainHF = 1.0f; - } - - state = props->State; - - if(state == slot->Params.EffectState) - { - /* If the effect state is the same as current, we can decrement its - * count safely to remove it from the update object (it can't reach - * 0 refs since the current params also hold a reference). - */ - DecrementRef(&state->Ref); - props->State = NULL; - } - else - { - /* Otherwise, replace it and send off the old one with a release - * event. - */ - AsyncEvent evt = ASYNC_EVENT(EventType_ReleaseEffectState); - evt.u.EffectState = slot->Params.EffectState; - - slot->Params.EffectState = state; - props->State = NULL; - - if(LIKELY(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) != 0)) - alsem_post(&context->EventSem); - else - { - /* If writing the event failed, the queue was probably full. - * Store the old state in the property object where it can - * eventually be cleaned up sometime later (not ideal, but - * better than blocking or leaking). - */ - props->State = evt.u.EffectState; - } - } - - ATOMIC_REPLACE_HEAD(struct ALeffectslotProps*, &context->FreeEffectslotProps, props); - } - else - state = slot->Params.EffectState; - - V(state,update)(context, slot, &slot->Params.EffectProps); - return true; -} - - -static const struct ChanMap MonoMap[1] = { - { FrontCenter, 0.0f, 0.0f } -}, RearMap[2] = { - { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) }, - { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) } -}, QuadMap[4] = { - { FrontLeft, DEG2RAD( -45.0f), DEG2RAD(0.0f) }, - { FrontRight, DEG2RAD( 45.0f), DEG2RAD(0.0f) }, - { BackLeft, DEG2RAD(-135.0f), DEG2RAD(0.0f) }, - { BackRight, DEG2RAD( 135.0f), DEG2RAD(0.0f) } -}, X51Map[6] = { - { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) }, - { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, - { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, - { LFE, 0.0f, 0.0f }, - { SideLeft, DEG2RAD(-110.0f), DEG2RAD(0.0f) }, - { SideRight, DEG2RAD( 110.0f), DEG2RAD(0.0f) } -}, X61Map[7] = { - { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, - { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, - { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, - { LFE, 0.0f, 0.0f }, - { BackCenter, DEG2RAD(180.0f), DEG2RAD(0.0f) }, - { SideLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) }, - { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } -}, X71Map[8] = { - { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) }, - { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, - { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, - { LFE, 0.0f, 0.0f }, - { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) }, - { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) }, - { SideLeft, DEG2RAD( -90.0f), DEG2RAD(0.0f) }, - { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } -}; - -static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev, - const ALfloat Distance, const ALfloat Spread, - const ALfloat DryGain, const ALfloat DryGainHF, - const ALfloat DryGainLF, const ALfloat *WetGain, - const ALfloat *WetGainLF, const ALfloat *WetGainHF, - ALeffectslot **SendSlots, const ALbuffer *Buffer, - const struct ALvoiceProps *props, const ALlistener *Listener, - const ALCdevice *Device) -{ - struct ChanMap StereoMap[2] = { - { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, - { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) } - }; - bool DirectChannels = props->DirectChannels; - const ALsizei NumSends = Device->NumAuxSends; - const ALuint Frequency = Device->Frequency; - const struct ChanMap *chans = NULL; - ALsizei num_channels = 0; - bool isbformat = false; - ALfloat downmix_gain = 1.0f; - ALsizei c, i; - - switch(Buffer->FmtChannels) - { - case FmtMono: - chans = MonoMap; - num_channels = 1; - /* Mono buffers are never played direct. */ - DirectChannels = false; - break; - - case FmtStereo: - /* Convert counter-clockwise to clockwise. */ - StereoMap[0].angle = -props->StereoPan[0]; - StereoMap[1].angle = -props->StereoPan[1]; - - chans = StereoMap; - num_channels = 2; - downmix_gain = 1.0f / 2.0f; - break; - - case FmtRear: - chans = RearMap; - num_channels = 2; - downmix_gain = 1.0f / 2.0f; - break; - - case FmtQuad: - chans = QuadMap; - num_channels = 4; - downmix_gain = 1.0f / 4.0f; - break; - - case FmtX51: - chans = X51Map; - num_channels = 6; - /* NOTE: Excludes LFE. */ - downmix_gain = 1.0f / 5.0f; - break; - - case FmtX61: - chans = X61Map; - num_channels = 7; - /* NOTE: Excludes LFE. */ - downmix_gain = 1.0f / 6.0f; - break; - - case FmtX71: - chans = X71Map; - num_channels = 8; - /* NOTE: Excludes LFE. */ - downmix_gain = 1.0f / 7.0f; - break; - - case FmtBFormat2D: - num_channels = 3; - isbformat = true; - DirectChannels = false; - break; - - case FmtBFormat3D: - num_channels = 4; - isbformat = true; - DirectChannels = false; - break; - } - - for(c = 0;c < num_channels;c++) - { - memset(&voice->Direct.Params[c].Hrtf.Target, 0, - sizeof(voice->Direct.Params[c].Hrtf.Target)); - ClearArray(voice->Direct.Params[c].Gains.Target); - } - for(i = 0;i < NumSends;i++) - { - for(c = 0;c < num_channels;c++) - ClearArray(voice->Send[i].Params[c].Gains.Target); - } - - voice->Flags &= ~(VOICE_HAS_HRTF | VOICE_HAS_NFC); - if(isbformat) - { - /* Special handling for B-Format sources. */ - - if(Distance > FLT_EPSILON) - { - /* Panning a B-Format sound toward some direction is easy. Just pan - * the first (W) channel as a normal mono sound and silence the - * others. - */ - ALfloat coeffs[MAX_AMBI_COEFFS]; - - if(Device->AvgSpeakerDist > 0.0f) - { - ALfloat mdist = Distance * Listener->Params.MetersPerUnit; - ALfloat w0 = SPEEDOFSOUNDMETRESPERSEC / - (mdist * (ALfloat)Device->Frequency); - ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / - (Device->AvgSpeakerDist * (ALfloat)Device->Frequency); - /* Clamp w0 for really close distances, to prevent excessive - * bass. - */ - w0 = minf(w0, w1*4.0f); - - /* Only need to adjust the first channel of a B-Format source. */ - NfcFilterAdjust(&voice->Direct.Params[0].NFCtrlFilter, w0); - - for(i = 0;i < MAX_AMBI_ORDER+1;i++) - voice->Direct.ChannelsPerOrder[i] = Device->NumChannelsPerOrder[i]; - voice->Flags |= VOICE_HAS_NFC; - } - - /* A scalar of 1.5 for plain stereo results in +/-60 degrees being - * moved to +/-90 degrees for direct right and left speaker - * responses. - */ - CalcAngleCoeffs((Device->Render_Mode==StereoPair) ? ScaleAzimuthFront(Azi, 1.5f) : Azi, - Elev, Spread, coeffs); - - /* NOTE: W needs to be scaled by sqrt(2) due to FuMa normalization. */ - ComputePanGains(&Device->Dry, coeffs, DryGain*SQRTF_2, - voice->Direct.Params[0].Gains.Target); - for(i = 0;i < NumSends;i++) - { - const ALeffectslot *Slot = SendSlots[i]; - if(Slot) - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, - WetGain[i]*SQRTF_2, voice->Send[i].Params[0].Gains.Target - ); - } - } - else - { - /* Local B-Format sources have their XYZ channels rotated according - * to the orientation. - */ - ALfloat N[3], V[3], U[3]; - aluMatrixf matrix; - - if(Device->AvgSpeakerDist > 0.0f) - { - /* NOTE: The NFCtrlFilters were created with a w0 of 0, which - * is what we want for FOA input. The first channel may have - * been previously re-adjusted if panned, so reset it. - */ - NfcFilterAdjust(&voice->Direct.Params[0].NFCtrlFilter, 0.0f); - - voice->Direct.ChannelsPerOrder[0] = 1; - voice->Direct.ChannelsPerOrder[1] = mini(voice->Direct.Channels-1, 3); - for(i = 2;i < MAX_AMBI_ORDER+1;i++) - voice->Direct.ChannelsPerOrder[i] = 0; - voice->Flags |= VOICE_HAS_NFC; - } - - /* AT then UP */ - N[0] = props->Orientation[0][0]; - N[1] = props->Orientation[0][1]; - N[2] = props->Orientation[0][2]; - aluNormalize(N); - V[0] = props->Orientation[1][0]; - V[1] = props->Orientation[1][1]; - V[2] = props->Orientation[1][2]; - aluNormalize(V); - if(!props->HeadRelative) - { - const aluMatrixf *lmatrix = &Listener->Params.Matrix; - aluMatrixfFloat3(N, 0.0f, lmatrix); - aluMatrixfFloat3(V, 0.0f, lmatrix); - } - /* Build and normalize right-vector */ - aluCrossproduct(N, V, U); - aluNormalize(U); - - /* Build a rotate + conversion matrix (FuMa -> ACN+N3D). NOTE: This - * matrix is transposed, for the inputs to align on the rows and - * outputs on the columns. - */ - aluMatrixfSet(&matrix, - // ACN0 ACN1 ACN2 ACN3 - SQRTF_2, 0.0f, 0.0f, 0.0f, // Ambi W - 0.0f, -N[0]*SQRTF_3, N[1]*SQRTF_3, -N[2]*SQRTF_3, // Ambi X - 0.0f, U[0]*SQRTF_3, -U[1]*SQRTF_3, U[2]*SQRTF_3, // Ambi Y - 0.0f, -V[0]*SQRTF_3, V[1]*SQRTF_3, -V[2]*SQRTF_3 // Ambi Z - ); - - voice->Direct.Buffer = Device->FOAOut.Buffer; - voice->Direct.Channels = Device->FOAOut.NumChannels; - for(c = 0;c < num_channels;c++) - ComputePanGains(&Device->FOAOut, matrix.m[c], DryGain, - voice->Direct.Params[c].Gains.Target); - for(i = 0;i < NumSends;i++) - { - const ALeffectslot *Slot = SendSlots[i]; - if(Slot) - { - for(c = 0;c < num_channels;c++) - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, - matrix.m[c], WetGain[i], voice->Send[i].Params[c].Gains.Target - ); - } - } - } - } - else if(DirectChannels) - { - /* Direct source channels always play local. Skip the virtual channels - * and write inputs to the matching real outputs. - */ - voice->Direct.Buffer = Device->RealOut.Buffer; - voice->Direct.Channels = Device->RealOut.NumChannels; - - for(c = 0;c < num_channels;c++) - { - int idx = GetChannelIdxByName(&Device->RealOut, chans[c].channel); - if(idx != -1) voice->Direct.Params[c].Gains.Target[idx] = DryGain; - } - - /* Auxiliary sends still use normal channel panning since they mix to - * B-Format, which can't channel-match. - */ - for(c = 0;c < num_channels;c++) - { - ALfloat coeffs[MAX_AMBI_COEFFS]; - CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); - - for(i = 0;i < NumSends;i++) - { - const ALeffectslot *Slot = SendSlots[i]; - if(Slot) - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, - coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target - ); - } - } - } - else if(Device->Render_Mode == HrtfRender) - { - /* Full HRTF rendering. Skip the virtual channels and render to the - * real outputs. - */ - voice->Direct.Buffer = Device->RealOut.Buffer; - voice->Direct.Channels = Device->RealOut.NumChannels; - - if(Distance > FLT_EPSILON) - { - ALfloat coeffs[MAX_AMBI_COEFFS]; - - /* Get the HRIR coefficients and delays just once, for the given - * source direction. - */ - GetHrtfCoeffs(Device->HrtfHandle, Elev, Azi, Spread, - voice->Direct.Params[0].Hrtf.Target.Coeffs, - voice->Direct.Params[0].Hrtf.Target.Delay); - voice->Direct.Params[0].Hrtf.Target.Gain = DryGain * downmix_gain; - - /* Remaining channels use the same results as the first. */ - for(c = 1;c < num_channels;c++) - { - /* Skip LFE */ - if(chans[c].channel != LFE) - voice->Direct.Params[c].Hrtf.Target = voice->Direct.Params[0].Hrtf.Target; - } - - /* Calculate the directional coefficients once, which apply to all - * input channels of the source sends. - */ - CalcAngleCoeffs(Azi, Elev, Spread, coeffs); - - for(i = 0;i < NumSends;i++) - { - const ALeffectslot *Slot = SendSlots[i]; - if(Slot) - for(c = 0;c < num_channels;c++) - { - /* Skip LFE */ - if(chans[c].channel != LFE) - ComputePanningGainsBF(Slot->ChanMap, - Slot->NumChannels, coeffs, WetGain[i] * downmix_gain, - voice->Send[i].Params[c].Gains.Target - ); - } - } - } - else - { - /* Local sources on HRTF play with each channel panned to its - * relative location around the listener, providing "virtual - * speaker" responses. - */ - for(c = 0;c < num_channels;c++) - { - ALfloat coeffs[MAX_AMBI_COEFFS]; - - if(chans[c].channel == LFE) - { - /* Skip LFE */ - continue; - } - - /* Get the HRIR coefficients and delays for this channel - * position. - */ - GetHrtfCoeffs(Device->HrtfHandle, - chans[c].elevation, chans[c].angle, Spread, - voice->Direct.Params[c].Hrtf.Target.Coeffs, - voice->Direct.Params[c].Hrtf.Target.Delay - ); - voice->Direct.Params[c].Hrtf.Target.Gain = DryGain; - - /* Normal panning for auxiliary sends. */ - CalcAngleCoeffs(chans[c].angle, chans[c].elevation, Spread, coeffs); - - for(i = 0;i < NumSends;i++) - { - const ALeffectslot *Slot = SendSlots[i]; - if(Slot) - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, - coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target - ); - } - } - } - - voice->Flags |= VOICE_HAS_HRTF; - } - else - { - /* Non-HRTF rendering. Use normal panning to the output. */ - - if(Distance > FLT_EPSILON) - { - ALfloat coeffs[MAX_AMBI_COEFFS]; - ALfloat w0 = 0.0f; - - /* Calculate NFC filter coefficient if needed. */ - if(Device->AvgSpeakerDist > 0.0f) - { - ALfloat mdist = Distance * Listener->Params.MetersPerUnit; - ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / - (Device->AvgSpeakerDist * (ALfloat)Device->Frequency); - w0 = SPEEDOFSOUNDMETRESPERSEC / - (mdist * (ALfloat)Device->Frequency); - /* Clamp w0 for really close distances, to prevent excessive - * bass. - */ - w0 = minf(w0, w1*4.0f); - - /* Adjust NFC filters. */ - for(c = 0;c < num_channels;c++) - NfcFilterAdjust(&voice->Direct.Params[c].NFCtrlFilter, w0); - - for(i = 0;i < MAX_AMBI_ORDER+1;i++) - voice->Direct.ChannelsPerOrder[i] = Device->NumChannelsPerOrder[i]; - voice->Flags |= VOICE_HAS_NFC; - } - - /* Calculate the directional coefficients once, which apply to all - * input channels. - */ - CalcAngleCoeffs((Device->Render_Mode==StereoPair) ? ScaleAzimuthFront(Azi, 1.5f) : Azi, - Elev, Spread, coeffs); - - for(c = 0;c < num_channels;c++) - { - /* Special-case LFE */ - if(chans[c].channel == LFE) - { - if(Device->Dry.Buffer == Device->RealOut.Buffer) - { - int idx = GetChannelIdxByName(&Device->RealOut, chans[c].channel); - if(idx != -1) voice->Direct.Params[c].Gains.Target[idx] = DryGain; - } - continue; - } - - ComputePanGains(&Device->Dry, coeffs, DryGain * downmix_gain, - voice->Direct.Params[c].Gains.Target); - } - - for(i = 0;i < NumSends;i++) - { - const ALeffectslot *Slot = SendSlots[i]; - if(Slot) - for(c = 0;c < num_channels;c++) - { - /* Skip LFE */ - if(chans[c].channel != LFE) - ComputePanningGainsBF(Slot->ChanMap, - Slot->NumChannels, coeffs, WetGain[i] * downmix_gain, - voice->Send[i].Params[c].Gains.Target - ); - } - } - } - else - { - ALfloat w0 = 0.0f; - - if(Device->AvgSpeakerDist > 0.0f) - { - /* If the source distance is 0, set w0 to w1 to act as a pass- - * through. We still want to pass the signal through the - * filters so they keep an appropriate history, in case the - * source moves away from the listener. - */ - w0 = SPEEDOFSOUNDMETRESPERSEC / - (Device->AvgSpeakerDist * (ALfloat)Device->Frequency); - - for(c = 0;c < num_channels;c++) - NfcFilterAdjust(&voice->Direct.Params[c].NFCtrlFilter, w0); - - for(i = 0;i < MAX_AMBI_ORDER+1;i++) - voice->Direct.ChannelsPerOrder[i] = Device->NumChannelsPerOrder[i]; - voice->Flags |= VOICE_HAS_NFC; - } - - for(c = 0;c < num_channels;c++) - { - ALfloat coeffs[MAX_AMBI_COEFFS]; - - /* Special-case LFE */ - if(chans[c].channel == LFE) - { - if(Device->Dry.Buffer == Device->RealOut.Buffer) - { - int idx = GetChannelIdxByName(&Device->RealOut, chans[c].channel); - if(idx != -1) voice->Direct.Params[c].Gains.Target[idx] = DryGain; - } - continue; - } - - CalcAngleCoeffs( - (Device->Render_Mode==StereoPair) ? ScaleAzimuthFront(chans[c].angle, 3.0f) - : chans[c].angle, - chans[c].elevation, Spread, coeffs - ); - - ComputePanGains(&Device->Dry, coeffs, DryGain, - voice->Direct.Params[c].Gains.Target); - for(i = 0;i < NumSends;i++) - { - const ALeffectslot *Slot = SendSlots[i]; - if(Slot) - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, - coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target - ); - } - } - } - } - - { - ALfloat hfScale = props->Direct.HFReference / Frequency; - ALfloat lfScale = props->Direct.LFReference / Frequency; - ALfloat gainHF = maxf(DryGainHF, 0.001f); /* Limit -60dB */ - ALfloat gainLF = maxf(DryGainLF, 0.001f); - - voice->Direct.FilterType = AF_None; - if(gainHF != 1.0f) voice->Direct.FilterType |= AF_LowPass; - if(gainLF != 1.0f) voice->Direct.FilterType |= AF_HighPass; - BiquadFilter_setParams( - &voice->Direct.Params[0].LowPass, BiquadType_HighShelf, - gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) - ); - BiquadFilter_setParams( - &voice->Direct.Params[0].HighPass, BiquadType_LowShelf, - gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) - ); - for(c = 1;c < num_channels;c++) - { - BiquadFilter_copyParams(&voice->Direct.Params[c].LowPass, - &voice->Direct.Params[0].LowPass); - BiquadFilter_copyParams(&voice->Direct.Params[c].HighPass, - &voice->Direct.Params[0].HighPass); - } - } - for(i = 0;i < NumSends;i++) - { - ALfloat hfScale = props->Send[i].HFReference / Frequency; - ALfloat lfScale = props->Send[i].LFReference / Frequency; - ALfloat gainHF = maxf(WetGainHF[i], 0.001f); - ALfloat gainLF = maxf(WetGainLF[i], 0.001f); - - voice->Send[i].FilterType = AF_None; - if(gainHF != 1.0f) voice->Send[i].FilterType |= AF_LowPass; - if(gainLF != 1.0f) voice->Send[i].FilterType |= AF_HighPass; - BiquadFilter_setParams( - &voice->Send[i].Params[0].LowPass, BiquadType_HighShelf, - gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) - ); - BiquadFilter_setParams( - &voice->Send[i].Params[0].HighPass, BiquadType_LowShelf, - gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) - ); - for(c = 1;c < num_channels;c++) - { - BiquadFilter_copyParams(&voice->Send[i].Params[c].LowPass, - &voice->Send[i].Params[0].LowPass); - BiquadFilter_copyParams(&voice->Send[i].Params[c].HighPass, - &voice->Send[i].Params[0].HighPass); - } - } -} - -static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) -{ - const ALCdevice *Device = ALContext->Device; - const ALlistener *Listener = ALContext->Listener; - ALfloat DryGain, DryGainHF, DryGainLF; - ALfloat WetGain[MAX_SENDS]; - ALfloat WetGainHF[MAX_SENDS]; - ALfloat WetGainLF[MAX_SENDS]; - ALeffectslot *SendSlots[MAX_SENDS]; - ALfloat Pitch; - ALsizei i; - - voice->Direct.Buffer = Device->Dry.Buffer; - voice->Direct.Channels = Device->Dry.NumChannels; - for(i = 0;i < Device->NumAuxSends;i++) - { - SendSlots[i] = props->Send[i].Slot; - if(!SendSlots[i] && i == 0) - SendSlots[i] = ALContext->DefaultSlot; - if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) - { - SendSlots[i] = NULL; - voice->Send[i].Buffer = NULL; - voice->Send[i].Channels = 0; - } - else - { - voice->Send[i].Buffer = SendSlots[i]->WetBuffer; - voice->Send[i].Channels = SendSlots[i]->NumChannels; - } - } - - /* Calculate the stepping value */ - Pitch = (ALfloat)ALBuffer->Frequency/(ALfloat)Device->Frequency * props->Pitch; - if(Pitch > (ALfloat)MAX_PITCH) - voice->Step = MAX_PITCH<Step = maxi(fastf2i(Pitch * FRACTIONONE), 1); - if(props->Resampler == BSinc24Resampler) - BsincPrepare(voice->Step, &voice->ResampleState.bsinc, &bsinc24); - else if(props->Resampler == BSinc12Resampler) - BsincPrepare(voice->Step, &voice->ResampleState.bsinc, &bsinc12); - voice->Resampler = SelectResampler(props->Resampler); - - /* Calculate gains */ - DryGain = clampf(props->Gain, props->MinGain, props->MaxGain); - DryGain *= props->Direct.Gain * Listener->Params.Gain; - DryGain = minf(DryGain, GAIN_MIX_MAX); - DryGainHF = props->Direct.GainHF; - DryGainLF = props->Direct.GainLF; - for(i = 0;i < Device->NumAuxSends;i++) - { - WetGain[i] = clampf(props->Gain, props->MinGain, props->MaxGain); - WetGain[i] *= props->Send[i].Gain * Listener->Params.Gain; - WetGain[i] = minf(WetGain[i], GAIN_MIX_MAX); - WetGainHF[i] = props->Send[i].GainHF; - WetGainLF[i] = props->Send[i].GainLF; - } - - CalcPanningAndFilters(voice, 0.0f, 0.0f, 0.0f, 0.0f, DryGain, DryGainHF, DryGainLF, WetGain, - WetGainLF, WetGainHF, SendSlots, ALBuffer, props, Listener, Device); -} - -static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) -{ - const ALCdevice *Device = ALContext->Device; - const ALlistener *Listener = ALContext->Listener; - const ALsizei NumSends = Device->NumAuxSends; - aluVector Position, Velocity, Direction, SourceToListener; - ALfloat Distance, ClampedDist, DopplerFactor; - ALeffectslot *SendSlots[MAX_SENDS]; - ALfloat RoomRolloff[MAX_SENDS]; - ALfloat DecayDistance[MAX_SENDS]; - ALfloat DecayLFDistance[MAX_SENDS]; - ALfloat DecayHFDistance[MAX_SENDS]; - ALfloat DryGain, DryGainHF, DryGainLF; - ALfloat WetGain[MAX_SENDS]; - ALfloat WetGainHF[MAX_SENDS]; - ALfloat WetGainLF[MAX_SENDS]; - bool directional; - ALfloat ev, az; - ALfloat spread; - ALfloat Pitch; - ALint i; - - /* Set mixing buffers and get send parameters. */ - voice->Direct.Buffer = Device->Dry.Buffer; - voice->Direct.Channels = Device->Dry.NumChannels; - for(i = 0;i < NumSends;i++) - { - SendSlots[i] = props->Send[i].Slot; - if(!SendSlots[i] && i == 0) - SendSlots[i] = ALContext->DefaultSlot; - if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) - { - SendSlots[i] = NULL; - RoomRolloff[i] = 0.0f; - DecayDistance[i] = 0.0f; - DecayLFDistance[i] = 0.0f; - DecayHFDistance[i] = 0.0f; - } - else if(SendSlots[i]->Params.AuxSendAuto) - { - RoomRolloff[i] = SendSlots[i]->Params.RoomRolloff + props->RoomRolloffFactor; - /* Calculate the distances to where this effect's decay reaches - * -60dB. - */ - DecayDistance[i] = SendSlots[i]->Params.DecayTime * - Listener->Params.ReverbSpeedOfSound; - DecayLFDistance[i] = DecayDistance[i] * SendSlots[i]->Params.DecayLFRatio; - DecayHFDistance[i] = DecayDistance[i] * SendSlots[i]->Params.DecayHFRatio; - if(SendSlots[i]->Params.DecayHFLimit) - { - ALfloat airAbsorption = SendSlots[i]->Params.AirAbsorptionGainHF; - if(airAbsorption < 1.0f) - { - /* Calculate the distance to where this effect's air - * absorption reaches -60dB, and limit the effect's HF - * decay distance (so it doesn't take any longer to decay - * than the air would allow). - */ - ALfloat absorb_dist = log10f(REVERB_DECAY_GAIN) / log10f(airAbsorption); - DecayHFDistance[i] = minf(absorb_dist, DecayHFDistance[i]); - } - } - } - else - { - /* If the slot's auxiliary send auto is off, the data sent to the - * effect slot is the same as the dry path, sans filter effects */ - RoomRolloff[i] = props->RolloffFactor; - DecayDistance[i] = 0.0f; - DecayLFDistance[i] = 0.0f; - DecayHFDistance[i] = 0.0f; - } - - if(!SendSlots[i]) - { - voice->Send[i].Buffer = NULL; - voice->Send[i].Channels = 0; - } - else - { - voice->Send[i].Buffer = SendSlots[i]->WetBuffer; - voice->Send[i].Channels = SendSlots[i]->NumChannels; - } - } - - /* Transform source to listener space (convert to head relative) */ - aluVectorSet(&Position, props->Position[0], props->Position[1], props->Position[2], 1.0f); - aluVectorSet(&Direction, props->Direction[0], props->Direction[1], props->Direction[2], 0.0f); - aluVectorSet(&Velocity, props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f); - if(props->HeadRelative == AL_FALSE) - { - const aluMatrixf *Matrix = &Listener->Params.Matrix; - /* Transform source vectors */ - Position = aluMatrixfVector(Matrix, &Position); - Velocity = aluMatrixfVector(Matrix, &Velocity); - Direction = aluMatrixfVector(Matrix, &Direction); - } - else - { - const aluVector *lvelocity = &Listener->Params.Velocity; - /* Offset the source velocity to be relative of the listener velocity */ - Velocity.v[0] += lvelocity->v[0]; - Velocity.v[1] += lvelocity->v[1]; - Velocity.v[2] += lvelocity->v[2]; - } - - directional = aluNormalize(Direction.v) > 0.0f; - SourceToListener.v[0] = -Position.v[0]; - SourceToListener.v[1] = -Position.v[1]; - SourceToListener.v[2] = -Position.v[2]; - SourceToListener.v[3] = 0.0f; - Distance = aluNormalize(SourceToListener.v); - - /* Initial source gain */ - DryGain = props->Gain; - DryGainHF = 1.0f; - DryGainLF = 1.0f; - for(i = 0;i < NumSends;i++) - { - WetGain[i] = props->Gain; - WetGainHF[i] = 1.0f; - WetGainLF[i] = 1.0f; - } - - /* Calculate distance attenuation */ - ClampedDist = Distance; - - switch(Listener->Params.SourceDistanceModel ? - props->DistanceModel : Listener->Params.DistanceModel) - { - case InverseDistanceClamped: - ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); - if(props->MaxDistance < props->RefDistance) - break; - /*fall-through*/ - case InverseDistance: - if(!(props->RefDistance > 0.0f)) - ClampedDist = props->RefDistance; - else - { - ALfloat dist = lerp(props->RefDistance, ClampedDist, props->RolloffFactor); - if(dist > 0.0f) DryGain *= props->RefDistance / dist; - for(i = 0;i < NumSends;i++) - { - dist = lerp(props->RefDistance, ClampedDist, RoomRolloff[i]); - if(dist > 0.0f) WetGain[i] *= props->RefDistance / dist; - } - } - break; - - case LinearDistanceClamped: - ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); - if(props->MaxDistance < props->RefDistance) - break; - /*fall-through*/ - case LinearDistance: - if(!(props->MaxDistance != props->RefDistance)) - ClampedDist = props->RefDistance; - else - { - ALfloat attn = props->RolloffFactor * (ClampedDist-props->RefDistance) / - (props->MaxDistance-props->RefDistance); - DryGain *= maxf(1.0f - attn, 0.0f); - for(i = 0;i < NumSends;i++) - { - attn = RoomRolloff[i] * (ClampedDist-props->RefDistance) / - (props->MaxDistance-props->RefDistance); - WetGain[i] *= maxf(1.0f - attn, 0.0f); - } - } - break; - - case ExponentDistanceClamped: - ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); - if(props->MaxDistance < props->RefDistance) - break; - /*fall-through*/ - case ExponentDistance: - if(!(ClampedDist > 0.0f && props->RefDistance > 0.0f)) - ClampedDist = props->RefDistance; - else - { - DryGain *= powf(ClampedDist/props->RefDistance, -props->RolloffFactor); - for(i = 0;i < NumSends;i++) - WetGain[i] *= powf(ClampedDist/props->RefDistance, -RoomRolloff[i]); - } - break; - - case DisableDistance: - ClampedDist = props->RefDistance; - break; - } - - /* Calculate directional soundcones */ - if(directional && props->InnerAngle < 360.0f) - { - ALfloat ConeVolume; - ALfloat ConeHF; - ALfloat Angle; - - Angle = acosf(aluDotproduct(&Direction, &SourceToListener)); - Angle = RAD2DEG(Angle * ConeScale * 2.0f); - if(!(Angle > props->InnerAngle)) - { - ConeVolume = 1.0f; - ConeHF = 1.0f; - } - else if(Angle < props->OuterAngle) - { - ALfloat scale = ( Angle-props->InnerAngle) / - (props->OuterAngle-props->InnerAngle); - ConeVolume = lerp(1.0f, props->OuterGain, scale); - ConeHF = lerp(1.0f, props->OuterGainHF, scale); - } - else - { - ConeVolume = props->OuterGain; - ConeHF = props->OuterGainHF; - } - - DryGain *= ConeVolume; - if(props->DryGainHFAuto) - DryGainHF *= ConeHF; - if(props->WetGainAuto) - { - for(i = 0;i < NumSends;i++) - WetGain[i] *= ConeVolume; - } - if(props->WetGainHFAuto) - { - for(i = 0;i < NumSends;i++) - WetGainHF[i] *= ConeHF; - } - } - - /* Apply gain and frequency filters */ - DryGain = clampf(DryGain, props->MinGain, props->MaxGain); - DryGain = minf(DryGain*props->Direct.Gain*Listener->Params.Gain, GAIN_MIX_MAX); - DryGainHF *= props->Direct.GainHF; - DryGainLF *= props->Direct.GainLF; - for(i = 0;i < NumSends;i++) - { - WetGain[i] = clampf(WetGain[i], props->MinGain, props->MaxGain); - WetGain[i] = minf(WetGain[i]*props->Send[i].Gain*Listener->Params.Gain, GAIN_MIX_MAX); - WetGainHF[i] *= props->Send[i].GainHF; - WetGainLF[i] *= props->Send[i].GainLF; - } - - /* Distance-based air absorption and initial send decay. */ - if(ClampedDist > props->RefDistance && props->RolloffFactor > 0.0f) - { - ALfloat meters_base = (ClampedDist-props->RefDistance) * props->RolloffFactor * - Listener->Params.MetersPerUnit; - if(props->AirAbsorptionFactor > 0.0f) - { - ALfloat hfattn = powf(AIRABSORBGAINHF, meters_base * props->AirAbsorptionFactor); - DryGainHF *= hfattn; - for(i = 0;i < NumSends;i++) - WetGainHF[i] *= hfattn; - } - - if(props->WetGainAuto) - { - /* Apply a decay-time transformation to the wet path, based on the - * source distance in meters. The initial decay of the reverb - * effect is calculated and applied to the wet path. - */ - for(i = 0;i < NumSends;i++) - { - ALfloat gain, gainhf, gainlf; - - if(!(DecayDistance[i] > 0.0f)) - continue; - - gain = powf(REVERB_DECAY_GAIN, meters_base/DecayDistance[i]); - WetGain[i] *= gain; - /* Yes, the wet path's air absorption is applied with - * WetGainAuto on, rather than WetGainHFAuto. - */ - if(gain > 0.0f) - { - gainhf = powf(REVERB_DECAY_GAIN, meters_base/DecayHFDistance[i]); - WetGainHF[i] *= minf(gainhf / gain, 1.0f); - gainlf = powf(REVERB_DECAY_GAIN, meters_base/DecayLFDistance[i]); - WetGainLF[i] *= minf(gainlf / gain, 1.0f); - } - } - } - } - - - /* Initial source pitch */ - Pitch = props->Pitch; - - /* Calculate velocity-based doppler effect */ - DopplerFactor = props->DopplerFactor * Listener->Params.DopplerFactor; - if(DopplerFactor > 0.0f) - { - const aluVector *lvelocity = &Listener->Params.Velocity; - const ALfloat SpeedOfSound = Listener->Params.SpeedOfSound; - ALfloat vss, vls; - - vss = aluDotproduct(&Velocity, &SourceToListener) * DopplerFactor; - vls = aluDotproduct(lvelocity, &SourceToListener) * DopplerFactor; - - if(!(vls < SpeedOfSound)) - { - /* Listener moving away from the source at the speed of sound. - * Sound waves can't catch it. - */ - Pitch = 0.0f; - } - else if(!(vss < SpeedOfSound)) - { - /* Source moving toward the listener at the speed of sound. Sound - * waves bunch up to extreme frequencies. - */ - Pitch = HUGE_VALF; - } - else - { - /* Source and listener movement is nominal. Calculate the proper - * doppler shift. - */ - Pitch *= (SpeedOfSound-vls) / (SpeedOfSound-vss); - } - } - - /* Adjust pitch based on the buffer and output frequencies, and calculate - * fixed-point stepping value. - */ - Pitch *= (ALfloat)ALBuffer->Frequency/(ALfloat)Device->Frequency; - if(Pitch > (ALfloat)MAX_PITCH) - voice->Step = MAX_PITCH<Step = maxi(fastf2i(Pitch * FRACTIONONE), 1); - if(props->Resampler == BSinc24Resampler) - BsincPrepare(voice->Step, &voice->ResampleState.bsinc, &bsinc24); - else if(props->Resampler == BSinc12Resampler) - BsincPrepare(voice->Step, &voice->ResampleState.bsinc, &bsinc12); - voice->Resampler = SelectResampler(props->Resampler); - - if(Distance > 0.0f) - { - /* Clamp Y, in case rounding errors caused it to end up outside of - * -1...+1. - */ - ev = asinf(clampf(-SourceToListener.v[1], -1.0f, 1.0f)); - /* Double negation on Z cancels out; negate once for changing source- - * to-listener to listener-to-source, and again for right-handed coords - * with -Z in front. - */ - az = atan2f(-SourceToListener.v[0], SourceToListener.v[2]*ZScale); - } - else - ev = az = 0.0f; - - if(props->Radius > Distance) - spread = F_TAU - Distance/props->Radius*F_PI; - else if(Distance > 0.0f) - spread = asinf(props->Radius / Distance) * 2.0f; - else - spread = 0.0f; - - CalcPanningAndFilters(voice, az, ev, Distance, spread, DryGain, DryGainHF, DryGainLF, WetGain, - WetGainLF, WetGainHF, SendSlots, ALBuffer, props, Listener, Device); -} - -static void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) -{ - ALbufferlistitem *BufferListItem; - struct ALvoiceProps *props; - - props = ATOMIC_EXCHANGE_PTR(&voice->Update, NULL, almemory_order_acq_rel); - if(!props && !force) return; - - if(props) - { - memcpy(voice->Props, props, - FAM_SIZE(struct ALvoiceProps, Send, context->Device->NumAuxSends) - ); - - ATOMIC_REPLACE_HEAD(struct ALvoiceProps*, &context->FreeVoiceProps, props); - } - props = voice->Props; - - BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - while(BufferListItem != NULL) - { - const ALbuffer *buffer = NULL; - ALsizei i = 0; - while(!buffer && i < BufferListItem->num_buffers) - buffer = BufferListItem->buffers[i]; - if(LIKELY(buffer)) - { - if(props->SpatializeMode == SpatializeOn || - (props->SpatializeMode == SpatializeAuto && buffer->FmtChannels == FmtMono)) - CalcAttnSourceParams(voice, props, buffer, context); - else - CalcNonAttnSourceParams(voice, props, buffer, context); - break; - } - BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_acquire); - } -} - - -static void ProcessParamUpdates(ALCcontext *ctx, const struct ALeffectslotArray *slots) -{ - ALvoice **voice, **voice_end; - ALsource *source; - ALsizei i; - - IncrementRef(&ctx->UpdateCount); - if(!ATOMIC_LOAD(&ctx->HoldUpdates, almemory_order_acquire)) - { - bool cforce = CalcContextParams(ctx); - bool force = CalcListenerParams(ctx) | cforce; - for(i = 0;i < slots->count;i++) - force |= CalcEffectSlotParams(slots->slot[i], ctx, cforce); - - voice = ctx->Voices; - voice_end = voice + ctx->VoiceCount; - for(;voice != voice_end;++voice) - { - source = ATOMIC_LOAD(&(*voice)->Source, almemory_order_acquire); - if(source) CalcSourceParams(*voice, ctx, force); - } - } - IncrementRef(&ctx->UpdateCount); -} - - -static void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*RESTRICT Buffer)[BUFFERSIZE], - int lidx, int ridx, int cidx, ALsizei SamplesToDo, - ALsizei NumChannels) -{ - ALfloat (*RESTRICT lsplit)[BUFFERSIZE] = ASSUME_ALIGNED(Stablizer->LSplit, 16); - ALfloat (*RESTRICT rsplit)[BUFFERSIZE] = ASSUME_ALIGNED(Stablizer->RSplit, 16); - ALsizei i; - - /* Apply an all-pass to all channels, except the front-left and front- - * right, so they maintain the same relative phase. - */ - for(i = 0;i < NumChannels;i++) - { - if(i == lidx || i == ridx) - continue; - splitterap_process(&Stablizer->APFilter[i], Buffer[i], SamplesToDo); - } - - bandsplit_process(&Stablizer->LFilter, lsplit[1], lsplit[0], Buffer[lidx], SamplesToDo); - bandsplit_process(&Stablizer->RFilter, rsplit[1], rsplit[0], Buffer[ridx], SamplesToDo); - - for(i = 0;i < SamplesToDo;i++) - { - ALfloat lfsum, hfsum; - ALfloat m, s, c; - - lfsum = lsplit[0][i] + rsplit[0][i]; - hfsum = lsplit[1][i] + rsplit[1][i]; - s = lsplit[0][i] + lsplit[1][i] - rsplit[0][i] - rsplit[1][i]; - - /* This pans the separate low- and high-frequency sums between being on - * the center channel and the left/right channels. The low-frequency - * sum is 1/3rd toward center (2/3rds on left/right) and the high- - * frequency sum is 1/4th toward center (3/4ths on left/right). These - * values can be tweaked. - */ - m = lfsum*cosf(1.0f/3.0f * F_PI_2) + hfsum*cosf(1.0f/4.0f * F_PI_2); - c = lfsum*sinf(1.0f/3.0f * F_PI_2) + hfsum*sinf(1.0f/4.0f * F_PI_2); - - /* The generated center channel signal adds to the existing signal, - * while the modified left and right channels replace. - */ - Buffer[lidx][i] = (m + s) * 0.5f; - Buffer[ridx][i] = (m - s) * 0.5f; - Buffer[cidx][i] += c * 0.5f; - } -} - -static void ApplyDistanceComp(ALfloat (*RESTRICT Samples)[BUFFERSIZE], DistanceComp *distcomp, - ALfloat *RESTRICT Values, ALsizei SamplesToDo, ALsizei numchans) -{ - ALsizei i, c; - - Values = ASSUME_ALIGNED(Values, 16); - for(c = 0;c < numchans;c++) - { - ALfloat *RESTRICT inout = ASSUME_ALIGNED(Samples[c], 16); - const ALfloat gain = distcomp[c].Gain; - const ALsizei base = distcomp[c].Length; - ALfloat *RESTRICT distbuf = ASSUME_ALIGNED(distcomp[c].Buffer, 16); - - if(base == 0) - { - if(gain < 1.0f) - { - for(i = 0;i < SamplesToDo;i++) - inout[i] *= gain; - } - continue; - } - - if(LIKELY(SamplesToDo >= base)) - { - for(i = 0;i < base;i++) - Values[i] = distbuf[i]; - for(;i < SamplesToDo;i++) - Values[i] = inout[i-base]; - memcpy(distbuf, &inout[SamplesToDo-base], base*sizeof(ALfloat)); - } - else - { - for(i = 0;i < SamplesToDo;i++) - Values[i] = distbuf[i]; - memmove(distbuf, distbuf+SamplesToDo, (base-SamplesToDo)*sizeof(ALfloat)); - memcpy(distbuf+base-SamplesToDo, inout, SamplesToDo*sizeof(ALfloat)); - } - for(i = 0;i < SamplesToDo;i++) - inout[i] = Values[i]*gain; - } -} - -static void ApplyDither(ALfloat (*RESTRICT Samples)[BUFFERSIZE], ALuint *dither_seed, - const ALfloat quant_scale, const ALsizei SamplesToDo, - const ALsizei numchans) -{ - const ALfloat invscale = 1.0f / quant_scale; - ALuint seed = *dither_seed; - ALsizei c, i; - - ASSUME(numchans > 0); - ASSUME(SamplesToDo > 0); - - /* Dithering. Step 1, generate whitenoise (uniform distribution of random - * values between -1 and +1). Step 2 is to add the noise to the samples, - * before rounding and after scaling up to the desired quantization depth. - */ - for(c = 0;c < numchans;c++) - { - ALfloat *RESTRICT samples = Samples[c]; - for(i = 0;i < SamplesToDo;i++) - { - ALfloat val = samples[i] * quant_scale; - ALuint rng0 = dither_rng(&seed); - ALuint rng1 = dither_rng(&seed); - val += (ALfloat)(rng0*(1.0/UINT_MAX) - rng1*(1.0/UINT_MAX)); - samples[i] = fast_roundf(val) * invscale; - } - } - *dither_seed = seed; -} - - -static inline ALfloat Conv_ALfloat(ALfloat val) -{ return val; } -static inline ALint Conv_ALint(ALfloat val) -{ - /* Floats have a 23-bit mantissa. There is an implied 1 bit in the mantissa - * along with the sign bit, giving 25 bits total, so [-16777216, +16777216] - * is the max value a normalized float can be scaled to before losing - * precision. - */ - return fastf2i(clampf(val*16777216.0f, -16777216.0f, 16777215.0f))<<7; -} -static inline ALshort Conv_ALshort(ALfloat val) -{ return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); } -static inline ALbyte Conv_ALbyte(ALfloat val) -{ return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); } - -/* Define unsigned output variations. */ -#define DECL_TEMPLATE(T, func, O) \ -static inline T Conv_##T(ALfloat val) { return func(val)+O; } - -DECL_TEMPLATE(ALubyte, Conv_ALbyte, 128) -DECL_TEMPLATE(ALushort, Conv_ALshort, 32768) -DECL_TEMPLATE(ALuint, Conv_ALint, 2147483648u) - -#undef DECL_TEMPLATE - -#define DECL_TEMPLATE(T, A) \ -static void Write##A(const ALfloat (*RESTRICT InBuffer)[BUFFERSIZE], \ - ALvoid *OutBuffer, ALsizei Offset, ALsizei SamplesToDo, \ - ALsizei numchans) \ -{ \ - ALsizei i, j; \ - \ - ASSUME(numchans > 0); \ - ASSUME(SamplesToDo > 0); \ - \ - for(j = 0;j < numchans;j++) \ - { \ - const ALfloat *RESTRICT in = ASSUME_ALIGNED(InBuffer[j], 16); \ - T *RESTRICT out = (T*)OutBuffer + Offset*numchans + j; \ - \ - for(i = 0;i < SamplesToDo;i++) \ - out[i*numchans] = Conv_##T(in[i]); \ - } \ -} - -DECL_TEMPLATE(ALfloat, F32) -DECL_TEMPLATE(ALuint, UI32) -DECL_TEMPLATE(ALint, I32) -DECL_TEMPLATE(ALushort, UI16) -DECL_TEMPLATE(ALshort, I16) -DECL_TEMPLATE(ALubyte, UI8) -DECL_TEMPLATE(ALbyte, I8) - -#undef DECL_TEMPLATE - - -void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) -{ - ALsizei SamplesToDo; - ALsizei SamplesDone; - ALCcontext *ctx; - ALsizei i, c; - - START_MIXER_MODE(); - for(SamplesDone = 0;SamplesDone < NumSamples;) - { - SamplesToDo = mini(NumSamples-SamplesDone, BUFFERSIZE); - for(c = 0;c < device->Dry.NumChannels;c++) - memset(device->Dry.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); - if(device->Dry.Buffer != device->FOAOut.Buffer) - for(c = 0;c < device->FOAOut.NumChannels;c++) - memset(device->FOAOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); - if(device->Dry.Buffer != device->RealOut.Buffer) - for(c = 0;c < device->RealOut.NumChannels;c++) - memset(device->RealOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); - - IncrementRef(&device->MixCount); - - ctx = ATOMIC_LOAD(&device->ContextList, almemory_order_acquire); - while(ctx) - { - const struct ALeffectslotArray *auxslots; - - auxslots = ATOMIC_LOAD(&ctx->ActiveAuxSlots, almemory_order_acquire); - ProcessParamUpdates(ctx, auxslots); - - for(i = 0;i < auxslots->count;i++) - { - ALeffectslot *slot = auxslots->slot[i]; - for(c = 0;c < slot->NumChannels;c++) - memset(slot->WetBuffer[c], 0, SamplesToDo*sizeof(ALfloat)); - } - - /* source processing */ - for(i = 0;i < ctx->VoiceCount;i++) - { - ALvoice *voice = ctx->Voices[i]; - ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire); - if(source && ATOMIC_LOAD(&voice->Playing, almemory_order_relaxed) && - voice->Step > 0) - { - if(!MixSource(voice, source->id, ctx, SamplesToDo)) - { - ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - SendSourceStoppedEvent(ctx, source->id); - } - } - } - - /* effect slot processing */ - for(i = 0;i < auxslots->count;i++) - { - const ALeffectslot *slot = auxslots->slot[i]; - ALeffectState *state = slot->Params.EffectState; - V(state,process)(SamplesToDo, slot->WetBuffer, state->OutBuffer, - state->OutChannels); - } - - ctx = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed); - } - - /* Increment the clock time. Every second's worth of samples is - * converted and added to clock base so that large sample counts don't - * overflow during conversion. This also guarantees an exact, stable - * conversion. */ - device->SamplesDone += SamplesToDo; - device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES; - device->SamplesDone %= device->Frequency; - IncrementRef(&device->MixCount); - - /* Apply post-process for finalizing the Dry mix to the RealOut - * (Ambisonic decode, UHJ encode, etc). - */ - if(LIKELY(device->PostProcess)) - device->PostProcess(device, SamplesToDo); - - if(device->Stablizer) - { - int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); - int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); - int cidx = GetChannelIdxByName(&device->RealOut, FrontCenter); - assert(lidx >= 0 && ridx >= 0 && cidx >= 0); - - ApplyStablizer(device->Stablizer, device->RealOut.Buffer, lidx, ridx, cidx, - SamplesToDo, device->RealOut.NumChannels); - } - - ApplyDistanceComp(device->RealOut.Buffer, device->ChannelDelay, device->TempBuffer[0], - SamplesToDo, device->RealOut.NumChannels); - - if(device->Limiter) - ApplyCompression(device->Limiter, SamplesToDo, device->RealOut.Buffer); - - if(device->DitherDepth > 0.0f) - ApplyDither(device->RealOut.Buffer, &device->DitherSeed, device->DitherDepth, - SamplesToDo, device->RealOut.NumChannels); - - if(LIKELY(OutBuffer)) - { - ALfloat (*Buffer)[BUFFERSIZE] = device->RealOut.Buffer; - ALsizei Channels = device->RealOut.NumChannels; - - switch(device->FmtType) - { -#define HANDLE_WRITE(T, S) case T: \ - Write##S(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); break; - HANDLE_WRITE(DevFmtByte, I8) - HANDLE_WRITE(DevFmtUByte, UI8) - HANDLE_WRITE(DevFmtShort, I16) - HANDLE_WRITE(DevFmtUShort, UI16) - HANDLE_WRITE(DevFmtInt, I32) - HANDLE_WRITE(DevFmtUInt, UI32) - HANDLE_WRITE(DevFmtFloat, F32) -#undef HANDLE_WRITE - } - } - - SamplesDone += SamplesToDo; - } - END_MIXER_MODE(); -} - - -void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) -{ - AsyncEvent evt = ASYNC_EVENT(EventType_Disconnected); - ALCcontext *ctx; - va_list args; - int msglen; - - if(!ATOMIC_EXCHANGE(&device->Connected, AL_FALSE, almemory_order_acq_rel)) - return; - - evt.u.user.type = AL_EVENT_TYPE_DISCONNECTED_SOFT; - evt.u.user.id = 0; - evt.u.user.param = 0; - - va_start(args, msg); - msglen = vsnprintf(evt.u.user.msg, sizeof(evt.u.user.msg), msg, args); - va_end(args); - - if(msglen < 0 || (size_t)msglen >= sizeof(evt.u.user.msg)) - evt.u.user.msg[sizeof(evt.u.user.msg)-1] = 0; - - ctx = ATOMIC_LOAD_SEQ(&device->ContextList); - while(ctx) - { - ALbitfieldSOFT enabledevt = ATOMIC_LOAD(&ctx->EnabledEvts, almemory_order_acquire); - ALsizei i; - - if((enabledevt&EventType_Disconnected) && - ll_ringbuffer_write(ctx->AsyncEvents, (const char*)&evt, 1) == 1) - alsem_post(&ctx->EventSem); - - for(i = 0;i < ctx->VoiceCount;i++) - { - ALvoice *voice = ctx->Voices[i]; - ALsource *source; - - source = ATOMIC_EXCHANGE_PTR(&voice->Source, NULL, almemory_order_relaxed); - if(source && ATOMIC_LOAD(&voice->Playing, almemory_order_relaxed)) - { - /* If the source's voice was playing, it's now effectively - * stopped (the source state will be updated the next time it's - * checked). - */ - SendSourceStoppedEvent(ctx, source->id); - } - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - } - - ctx = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed); - } -} diff --git a/Alc/alu.cpp b/Alc/alu.cpp new file mode 100644 index 00000000..df857b80 --- /dev/null +++ b/Alc/alu.cpp @@ -0,0 +1,1884 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "alMain.h" +#include "alSource.h" +#include "alBuffer.h" +#include "alListener.h" +#include "alAuxEffectSlot.h" +#include "alu.h" +#include "bs2b.h" +#include "hrtf.h" +#include "mastering.h" +#include "uhjfilter.h" +#include "bformatdec.h" +#include "static_assert.h" +#include "ringbuffer.h" +#include "filters/splitter.h" + +#include "mixer/defs.h" +#include "fpu_modes.h" +#include "cpu_caps.h" +#include "bsinc_inc.h" + + +/* Cone scalar */ +ALfloat ConeScale = 1.0f; + +/* Localized Z scalar for mono sources */ +ALfloat ZScale = 1.0f; + +/* Force default speed of sound for distance-related reverb decay. */ +ALboolean OverrideReverbSpeedOfSound = AL_FALSE; + +const aluMatrixf IdentityMatrixf = {{ + { 1.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 1.0f }, +}}; + + +static void ClearArray(ALfloat f[MAX_OUTPUT_CHANNELS]) +{ + size_t i; + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + f[i] = 0.0f; +} + +struct ChanMap { + enum Channel channel; + ALfloat angle; + ALfloat elevation; +}; + +static HrtfDirectMixerFunc MixDirectHrtf = MixDirectHrtf_C; + + +void DeinitVoice(ALvoice *voice) +{ + al_free(ATOMIC_EXCHANGE_PTR_SEQ(&voice->Update, static_cast(nullptr))); +} + + +static inline HrtfDirectMixerFunc SelectHrtfMixer(void) +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return MixDirectHrtf_Neon; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixDirectHrtf_SSE; +#endif + + return MixDirectHrtf_C; +} + + +/* This RNG method was created based on the math found in opusdec. It's quick, + * and starting with a seed value of 22222, is suitable for generating + * whitenoise. + */ +static inline ALuint dither_rng(ALuint *seed) +{ + *seed = (*seed * 96314165) + 907633515; + return *seed; +} + + +static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector) +{ + outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1]; + outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2]; + outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0]; +} + +static inline ALfloat aluDotproduct(const aluVector *vec1, const aluVector *vec2) +{ + return vec1->v[0]*vec2->v[0] + vec1->v[1]*vec2->v[1] + vec1->v[2]*vec2->v[2]; +} + +static ALfloat aluNormalize(ALfloat *vec) +{ + ALfloat length = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); + if(length > FLT_EPSILON) + { + ALfloat inv_length = 1.0f/length; + vec[0] *= inv_length; + vec[1] *= inv_length; + vec[2] *= inv_length; + return length; + } + vec[0] = vec[1] = vec[2] = 0.0f; + return 0.0f; +} + +static void aluMatrixfFloat3(ALfloat *vec, ALfloat w, const aluMatrixf *mtx) +{ + ALfloat v[4] = { vec[0], vec[1], vec[2], w }; + + vec[0] = v[0]*mtx->m[0][0] + v[1]*mtx->m[1][0] + v[2]*mtx->m[2][0] + v[3]*mtx->m[3][0]; + vec[1] = v[0]*mtx->m[0][1] + v[1]*mtx->m[1][1] + v[2]*mtx->m[2][1] + v[3]*mtx->m[3][1]; + vec[2] = v[0]*mtx->m[0][2] + v[1]*mtx->m[1][2] + v[2]*mtx->m[2][2] + v[3]*mtx->m[3][2]; +} + +static aluVector aluMatrixfVector(const aluMatrixf *mtx, const aluVector *vec) +{ + aluVector v; + v.v[0] = vec->v[0]*mtx->m[0][0] + vec->v[1]*mtx->m[1][0] + vec->v[2]*mtx->m[2][0] + vec->v[3]*mtx->m[3][0]; + v.v[1] = vec->v[0]*mtx->m[0][1] + vec->v[1]*mtx->m[1][1] + vec->v[2]*mtx->m[2][1] + vec->v[3]*mtx->m[3][1]; + v.v[2] = vec->v[0]*mtx->m[0][2] + vec->v[1]*mtx->m[1][2] + vec->v[2]*mtx->m[2][2] + vec->v[3]*mtx->m[3][2]; + v.v[3] = vec->v[0]*mtx->m[0][3] + vec->v[1]*mtx->m[1][3] + vec->v[2]*mtx->m[2][3] + vec->v[3]*mtx->m[3][3]; + return v; +} + + +void aluInit(void) +{ + MixDirectHrtf = SelectHrtfMixer(); +} + + +static void SendSourceStoppedEvent(ALCcontext *context, ALuint id) +{ + AsyncEvent evt = ASYNC_EVENT(EventType_SourceStateChange); + ALbitfieldSOFT enabledevt; + size_t strpos; + ALuint scale; + + enabledevt = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); + if(!(enabledevt&EventType_SourceStateChange)) return; + + evt.u.user.type = AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT; + evt.u.user.id = id; + evt.u.user.param = AL_STOPPED; + + /* Normally snprintf would be used, but this is called from the mixer and + * that function's not real-time safe, so we have to construct it manually. + */ + strcpy(evt.u.user.msg, "Source ID "); strpos = 10; + scale = 1000000000; + while(scale > 0 && scale > id) + scale /= 10; + while(scale > 0) + { + evt.u.user.msg[strpos++] = '0' + ((id/scale)%10); + scale /= 10; + } + strcpy(evt.u.user.msg+strpos, " state changed to AL_STOPPED"); + + if(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) == 1) + alsem_post(&context->EventSem); +} + + +static void ProcessHrtf(ALCdevice *device, ALsizei SamplesToDo) +{ + DirectHrtfState *state; + int lidx, ridx; + ALsizei c; + + if(device->AmbiUp) + ambiup_process(device->AmbiUp, + device->Dry.Buffer, device->Dry.NumChannels, device->FOAOut.Buffer, + SamplesToDo + ); + + lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); + ridx = GetChannelIdxByName(&device->RealOut, FrontRight); + assert(lidx != -1 && ridx != -1); + + state = device->Hrtf; + for(c = 0;c < device->Dry.NumChannels;c++) + { + MixDirectHrtf(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], + device->Dry.Buffer[c], state->Offset, state->IrSize, + state->Chan[c].Coeffs, state->Chan[c].Values, SamplesToDo + ); + } + state->Offset += SamplesToDo; +} + +static void ProcessAmbiDec(ALCdevice *device, ALsizei SamplesToDo) +{ + if(device->Dry.Buffer != device->FOAOut.Buffer) + bformatdec_upSample(device->AmbiDecoder, + device->Dry.Buffer, device->FOAOut.Buffer, device->FOAOut.NumChannels, + SamplesToDo + ); + bformatdec_process(device->AmbiDecoder, + device->RealOut.Buffer, device->RealOut.NumChannels, device->Dry.Buffer, + SamplesToDo + ); +} + +static void ProcessAmbiUp(ALCdevice *device, ALsizei SamplesToDo) +{ + ambiup_process(device->AmbiUp, + device->RealOut.Buffer, device->RealOut.NumChannels, device->FOAOut.Buffer, + SamplesToDo + ); +} + +static void ProcessUhj(ALCdevice *device, ALsizei SamplesToDo) +{ + int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); + int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); + assert(lidx != -1 && ridx != -1); + + /* Encode to stereo-compatible 2-channel UHJ output. */ + EncodeUhj2(device->Uhj_Encoder, + device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], + device->Dry.Buffer, SamplesToDo + ); +} + +static void ProcessBs2b(ALCdevice *device, ALsizei SamplesToDo) +{ + int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); + int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); + assert(lidx != -1 && ridx != -1); + + /* Apply binaural/crossfeed filter */ + bs2b_cross_feed(device->Bs2b, device->RealOut.Buffer[lidx], + device->RealOut.Buffer[ridx], SamplesToDo); +} + +void aluSelectPostProcess(ALCdevice *device) +{ + if(device->HrtfHandle) + device->PostProcess = ProcessHrtf; + else if(device->AmbiDecoder) + device->PostProcess = ProcessAmbiDec; + else if(device->AmbiUp) + device->PostProcess = ProcessAmbiUp; + else if(device->Uhj_Encoder) + device->PostProcess = ProcessUhj; + else if(device->Bs2b) + device->PostProcess = ProcessBs2b; + else + device->PostProcess = NULL; +} + + +/* Prepares the interpolator for a given rate (determined by increment). + * + * With a bit of work, and a trade of memory for CPU cost, this could be + * modified for use with an interpolated increment for buttery-smooth pitch + * changes. + */ +void BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *table) +{ + ALfloat sf = 0.0f; + ALsizei si = BSINC_SCALE_COUNT-1; + + if(increment > FRACTIONONE) + { + sf = (ALfloat)FRACTIONONE / increment; + sf = maxf(0.0f, (BSINC_SCALE_COUNT-1) * (sf-table->scaleBase) * table->scaleRange); + si = float2int(sf); + /* The interpolation factor is fit to this diagonally-symmetric curve + * to reduce the transition ripple caused by interpolating different + * scales of the sinc function. + */ + sf = 1.0f - cosf(asinf(sf - si)); + } + + state->sf = sf; + state->m = table->m[si]; + state->l = (state->m/2) - 1; + state->filter = table->Tab + table->filterOffset[si]; +} + + +static bool CalcContextParams(ALCcontext *Context) +{ + ALlistener *Listener = Context->Listener; + struct ALcontextProps *props; + + props = static_cast(ATOMIC_EXCHANGE_PTR(&Context->Update, + static_cast(nullptr), almemory_order_acq_rel)); + if(!props) return false; + + Listener->Params.MetersPerUnit = props->MetersPerUnit; + + Listener->Params.DopplerFactor = props->DopplerFactor; + Listener->Params.SpeedOfSound = props->SpeedOfSound * props->DopplerVelocity; + if(!OverrideReverbSpeedOfSound) + Listener->Params.ReverbSpeedOfSound = Listener->Params.SpeedOfSound * + Listener->Params.MetersPerUnit; + + Listener->Params.SourceDistanceModel = props->SourceDistanceModel; + Listener->Params.DistanceModel = props->DistanceModel; + + ATOMIC_REPLACE_HEAD(struct ALcontextProps*, &Context->FreeContextProps, props); + return true; +} + +static bool CalcListenerParams(ALCcontext *Context) +{ + ALlistener *Listener = Context->Listener; + ALfloat N[3], V[3], U[3], P[3]; + struct ALlistenerProps *props; + aluVector vel; + + props = static_cast(ATOMIC_EXCHANGE_PTR(&Listener->Update, + static_cast(nullptr), almemory_order_acq_rel)); + if(!props) return false; + + /* AT then UP */ + N[0] = props->Forward[0]; + N[1] = props->Forward[1]; + N[2] = props->Forward[2]; + aluNormalize(N); + V[0] = props->Up[0]; + V[1] = props->Up[1]; + V[2] = props->Up[2]; + aluNormalize(V); + /* Build and normalize right-vector */ + aluCrossproduct(N, V, U); + aluNormalize(U); + + aluMatrixfSet(&Listener->Params.Matrix, + U[0], V[0], -N[0], 0.0, + U[1], V[1], -N[1], 0.0, + U[2], V[2], -N[2], 0.0, + 0.0, 0.0, 0.0, 1.0 + ); + + P[0] = props->Position[0]; + P[1] = props->Position[1]; + P[2] = props->Position[2]; + aluMatrixfFloat3(P, 1.0, &Listener->Params.Matrix); + aluMatrixfSetRow(&Listener->Params.Matrix, 3, -P[0], -P[1], -P[2], 1.0f); + + aluVectorSet(&vel, props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f); + Listener->Params.Velocity = aluMatrixfVector(&Listener->Params.Matrix, &vel); + + Listener->Params.Gain = props->Gain * Context->GainBoost; + + ATOMIC_REPLACE_HEAD(struct ALlistenerProps*, &Context->FreeListenerProps, props); + return true; +} + +static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) +{ + struct ALeffectslotProps *props; + ALeffectState *state; + + props = static_cast(ATOMIC_EXCHANGE_PTR(&slot->Update, + static_cast(nullptr), almemory_order_acq_rel)); + if(!props && !force) return false; + + if(props) + { + slot->Params.Gain = props->Gain; + slot->Params.AuxSendAuto = props->AuxSendAuto; + slot->Params.EffectType = props->Type; + slot->Params.EffectProps = props->Props; + if(IsReverbEffect(props->Type)) + { + slot->Params.RoomRolloff = props->Props.Reverb.RoomRolloffFactor; + slot->Params.DecayTime = props->Props.Reverb.DecayTime; + slot->Params.DecayLFRatio = props->Props.Reverb.DecayLFRatio; + slot->Params.DecayHFRatio = props->Props.Reverb.DecayHFRatio; + slot->Params.DecayHFLimit = props->Props.Reverb.DecayHFLimit; + slot->Params.AirAbsorptionGainHF = props->Props.Reverb.AirAbsorptionGainHF; + } + else + { + slot->Params.RoomRolloff = 0.0f; + slot->Params.DecayTime = 0.0f; + slot->Params.DecayLFRatio = 0.0f; + slot->Params.DecayHFRatio = 0.0f; + slot->Params.DecayHFLimit = AL_FALSE; + slot->Params.AirAbsorptionGainHF = 1.0f; + } + + state = props->State; + + if(state == slot->Params.EffectState) + { + /* If the effect state is the same as current, we can decrement its + * count safely to remove it from the update object (it can't reach + * 0 refs since the current params also hold a reference). + */ + DecrementRef(&state->Ref); + props->State = NULL; + } + else + { + /* Otherwise, replace it and send off the old one with a release + * event. + */ + AsyncEvent evt = ASYNC_EVENT(EventType_ReleaseEffectState); + evt.u.EffectState = slot->Params.EffectState; + + slot->Params.EffectState = state; + props->State = NULL; + + if(LIKELY(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) != 0)) + alsem_post(&context->EventSem); + else + { + /* If writing the event failed, the queue was probably full. + * Store the old state in the property object where it can + * eventually be cleaned up sometime later (not ideal, but + * better than blocking or leaking). + */ + props->State = evt.u.EffectState; + } + } + + ATOMIC_REPLACE_HEAD(struct ALeffectslotProps*, &context->FreeEffectslotProps, props); + } + else + state = slot->Params.EffectState; + + V(state,update)(context, slot, &slot->Params.EffectProps); + return true; +} + + +static const struct ChanMap MonoMap[1] = { + { FrontCenter, 0.0f, 0.0f } +}, RearMap[2] = { + { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) }, + { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) } +}, QuadMap[4] = { + { FrontLeft, DEG2RAD( -45.0f), DEG2RAD(0.0f) }, + { FrontRight, DEG2RAD( 45.0f), DEG2RAD(0.0f) }, + { BackLeft, DEG2RAD(-135.0f), DEG2RAD(0.0f) }, + { BackRight, DEG2RAD( 135.0f), DEG2RAD(0.0f) } +}, X51Map[6] = { + { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) }, + { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, + { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, + { LFE, 0.0f, 0.0f }, + { SideLeft, DEG2RAD(-110.0f), DEG2RAD(0.0f) }, + { SideRight, DEG2RAD( 110.0f), DEG2RAD(0.0f) } +}, X61Map[7] = { + { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, + { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, + { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, + { LFE, 0.0f, 0.0f }, + { BackCenter, DEG2RAD(180.0f), DEG2RAD(0.0f) }, + { SideLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) }, + { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } +}, X71Map[8] = { + { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) }, + { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, + { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, + { LFE, 0.0f, 0.0f }, + { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) }, + { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) }, + { SideLeft, DEG2RAD( -90.0f), DEG2RAD(0.0f) }, + { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } +}; + +static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev, + const ALfloat Distance, const ALfloat Spread, + const ALfloat DryGain, const ALfloat DryGainHF, + const ALfloat DryGainLF, const ALfloat *WetGain, + const ALfloat *WetGainLF, const ALfloat *WetGainHF, + ALeffectslot **SendSlots, const ALbuffer *Buffer, + const struct ALvoiceProps *props, const ALlistener *Listener, + const ALCdevice *Device) +{ + struct ChanMap StereoMap[2] = { + { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, + { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) } + }; + bool DirectChannels = props->DirectChannels; + const ALsizei NumSends = Device->NumAuxSends; + const ALuint Frequency = Device->Frequency; + const struct ChanMap *chans = NULL; + ALsizei num_channels = 0; + bool isbformat = false; + ALfloat downmix_gain = 1.0f; + ALsizei c, i; + + switch(Buffer->FmtChannels) + { + case FmtMono: + chans = MonoMap; + num_channels = 1; + /* Mono buffers are never played direct. */ + DirectChannels = false; + break; + + case FmtStereo: + /* Convert counter-clockwise to clockwise. */ + StereoMap[0].angle = -props->StereoPan[0]; + StereoMap[1].angle = -props->StereoPan[1]; + + chans = StereoMap; + num_channels = 2; + downmix_gain = 1.0f / 2.0f; + break; + + case FmtRear: + chans = RearMap; + num_channels = 2; + downmix_gain = 1.0f / 2.0f; + break; + + case FmtQuad: + chans = QuadMap; + num_channels = 4; + downmix_gain = 1.0f / 4.0f; + break; + + case FmtX51: + chans = X51Map; + num_channels = 6; + /* NOTE: Excludes LFE. */ + downmix_gain = 1.0f / 5.0f; + break; + + case FmtX61: + chans = X61Map; + num_channels = 7; + /* NOTE: Excludes LFE. */ + downmix_gain = 1.0f / 6.0f; + break; + + case FmtX71: + chans = X71Map; + num_channels = 8; + /* NOTE: Excludes LFE. */ + downmix_gain = 1.0f / 7.0f; + break; + + case FmtBFormat2D: + num_channels = 3; + isbformat = true; + DirectChannels = false; + break; + + case FmtBFormat3D: + num_channels = 4; + isbformat = true; + DirectChannels = false; + break; + } + + for(c = 0;c < num_channels;c++) + { + memset(&voice->Direct.Params[c].Hrtf.Target, 0, + sizeof(voice->Direct.Params[c].Hrtf.Target)); + ClearArray(voice->Direct.Params[c].Gains.Target); + } + for(i = 0;i < NumSends;i++) + { + for(c = 0;c < num_channels;c++) + ClearArray(voice->Send[i].Params[c].Gains.Target); + } + + voice->Flags &= ~(VOICE_HAS_HRTF | VOICE_HAS_NFC); + if(isbformat) + { + /* Special handling for B-Format sources. */ + + if(Distance > FLT_EPSILON) + { + /* Panning a B-Format sound toward some direction is easy. Just pan + * the first (W) channel as a normal mono sound and silence the + * others. + */ + ALfloat coeffs[MAX_AMBI_COEFFS]; + + if(Device->AvgSpeakerDist > 0.0f) + { + ALfloat mdist = Distance * Listener->Params.MetersPerUnit; + ALfloat w0 = SPEEDOFSOUNDMETRESPERSEC / + (mdist * (ALfloat)Device->Frequency); + ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / + (Device->AvgSpeakerDist * (ALfloat)Device->Frequency); + /* Clamp w0 for really close distances, to prevent excessive + * bass. + */ + w0 = minf(w0, w1*4.0f); + + /* Only need to adjust the first channel of a B-Format source. */ + NfcFilterAdjust(&voice->Direct.Params[0].NFCtrlFilter, w0); + + for(i = 0;i < MAX_AMBI_ORDER+1;i++) + voice->Direct.ChannelsPerOrder[i] = Device->NumChannelsPerOrder[i]; + voice->Flags |= VOICE_HAS_NFC; + } + + /* A scalar of 1.5 for plain stereo results in +/-60 degrees being + * moved to +/-90 degrees for direct right and left speaker + * responses. + */ + CalcAngleCoeffs((Device->Render_Mode==StereoPair) ? ScaleAzimuthFront(Azi, 1.5f) : Azi, + Elev, Spread, coeffs); + + /* NOTE: W needs to be scaled by sqrt(2) due to FuMa normalization. */ + ComputePanGains(&Device->Dry, coeffs, DryGain*SQRTF_2, + voice->Direct.Params[0].Gains.Target); + for(i = 0;i < NumSends;i++) + { + const ALeffectslot *Slot = SendSlots[i]; + if(Slot) + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, + WetGain[i]*SQRTF_2, voice->Send[i].Params[0].Gains.Target + ); + } + } + else + { + /* Local B-Format sources have their XYZ channels rotated according + * to the orientation. + */ + ALfloat N[3], V[3], U[3]; + aluMatrixf matrix; + + if(Device->AvgSpeakerDist > 0.0f) + { + /* NOTE: The NFCtrlFilters were created with a w0 of 0, which + * is what we want for FOA input. The first channel may have + * been previously re-adjusted if panned, so reset it. + */ + NfcFilterAdjust(&voice->Direct.Params[0].NFCtrlFilter, 0.0f); + + voice->Direct.ChannelsPerOrder[0] = 1; + voice->Direct.ChannelsPerOrder[1] = mini(voice->Direct.Channels-1, 3); + for(i = 2;i < MAX_AMBI_ORDER+1;i++) + voice->Direct.ChannelsPerOrder[i] = 0; + voice->Flags |= VOICE_HAS_NFC; + } + + /* AT then UP */ + N[0] = props->Orientation[0][0]; + N[1] = props->Orientation[0][1]; + N[2] = props->Orientation[0][2]; + aluNormalize(N); + V[0] = props->Orientation[1][0]; + V[1] = props->Orientation[1][1]; + V[2] = props->Orientation[1][2]; + aluNormalize(V); + if(!props->HeadRelative) + { + const aluMatrixf *lmatrix = &Listener->Params.Matrix; + aluMatrixfFloat3(N, 0.0f, lmatrix); + aluMatrixfFloat3(V, 0.0f, lmatrix); + } + /* Build and normalize right-vector */ + aluCrossproduct(N, V, U); + aluNormalize(U); + + /* Build a rotate + conversion matrix (FuMa -> ACN+N3D). NOTE: This + * matrix is transposed, for the inputs to align on the rows and + * outputs on the columns. + */ + aluMatrixfSet(&matrix, + // ACN0 ACN1 ACN2 ACN3 + SQRTF_2, 0.0f, 0.0f, 0.0f, // Ambi W + 0.0f, -N[0]*SQRTF_3, N[1]*SQRTF_3, -N[2]*SQRTF_3, // Ambi X + 0.0f, U[0]*SQRTF_3, -U[1]*SQRTF_3, U[2]*SQRTF_3, // Ambi Y + 0.0f, -V[0]*SQRTF_3, V[1]*SQRTF_3, -V[2]*SQRTF_3 // Ambi Z + ); + + voice->Direct.Buffer = Device->FOAOut.Buffer; + voice->Direct.Channels = Device->FOAOut.NumChannels; + for(c = 0;c < num_channels;c++) + ComputePanGains(&Device->FOAOut, matrix.m[c], DryGain, + voice->Direct.Params[c].Gains.Target); + for(i = 0;i < NumSends;i++) + { + const ALeffectslot *Slot = SendSlots[i]; + if(Slot) + { + for(c = 0;c < num_channels;c++) + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, + matrix.m[c], WetGain[i], voice->Send[i].Params[c].Gains.Target + ); + } + } + } + } + else if(DirectChannels) + { + /* Direct source channels always play local. Skip the virtual channels + * and write inputs to the matching real outputs. + */ + voice->Direct.Buffer = Device->RealOut.Buffer; + voice->Direct.Channels = Device->RealOut.NumChannels; + + for(c = 0;c < num_channels;c++) + { + int idx = GetChannelIdxByName(&Device->RealOut, chans[c].channel); + if(idx != -1) voice->Direct.Params[c].Gains.Target[idx] = DryGain; + } + + /* Auxiliary sends still use normal channel panning since they mix to + * B-Format, which can't channel-match. + */ + for(c = 0;c < num_channels;c++) + { + ALfloat coeffs[MAX_AMBI_COEFFS]; + CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); + + for(i = 0;i < NumSends;i++) + { + const ALeffectslot *Slot = SendSlots[i]; + if(Slot) + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, + coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target + ); + } + } + } + else if(Device->Render_Mode == HrtfRender) + { + /* Full HRTF rendering. Skip the virtual channels and render to the + * real outputs. + */ + voice->Direct.Buffer = Device->RealOut.Buffer; + voice->Direct.Channels = Device->RealOut.NumChannels; + + if(Distance > FLT_EPSILON) + { + ALfloat coeffs[MAX_AMBI_COEFFS]; + + /* Get the HRIR coefficients and delays just once, for the given + * source direction. + */ + GetHrtfCoeffs(Device->HrtfHandle, Elev, Azi, Spread, + voice->Direct.Params[0].Hrtf.Target.Coeffs, + voice->Direct.Params[0].Hrtf.Target.Delay); + voice->Direct.Params[0].Hrtf.Target.Gain = DryGain * downmix_gain; + + /* Remaining channels use the same results as the first. */ + for(c = 1;c < num_channels;c++) + { + /* Skip LFE */ + if(chans[c].channel != LFE) + voice->Direct.Params[c].Hrtf.Target = voice->Direct.Params[0].Hrtf.Target; + } + + /* Calculate the directional coefficients once, which apply to all + * input channels of the source sends. + */ + CalcAngleCoeffs(Azi, Elev, Spread, coeffs); + + for(i = 0;i < NumSends;i++) + { + const ALeffectslot *Slot = SendSlots[i]; + if(Slot) + for(c = 0;c < num_channels;c++) + { + /* Skip LFE */ + if(chans[c].channel != LFE) + ComputePanningGainsBF(Slot->ChanMap, + Slot->NumChannels, coeffs, WetGain[i] * downmix_gain, + voice->Send[i].Params[c].Gains.Target + ); + } + } + } + else + { + /* Local sources on HRTF play with each channel panned to its + * relative location around the listener, providing "virtual + * speaker" responses. + */ + for(c = 0;c < num_channels;c++) + { + ALfloat coeffs[MAX_AMBI_COEFFS]; + + if(chans[c].channel == LFE) + { + /* Skip LFE */ + continue; + } + + /* Get the HRIR coefficients and delays for this channel + * position. + */ + GetHrtfCoeffs(Device->HrtfHandle, + chans[c].elevation, chans[c].angle, Spread, + voice->Direct.Params[c].Hrtf.Target.Coeffs, + voice->Direct.Params[c].Hrtf.Target.Delay + ); + voice->Direct.Params[c].Hrtf.Target.Gain = DryGain; + + /* Normal panning for auxiliary sends. */ + CalcAngleCoeffs(chans[c].angle, chans[c].elevation, Spread, coeffs); + + for(i = 0;i < NumSends;i++) + { + const ALeffectslot *Slot = SendSlots[i]; + if(Slot) + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, + coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target + ); + } + } + } + + voice->Flags |= VOICE_HAS_HRTF; + } + else + { + /* Non-HRTF rendering. Use normal panning to the output. */ + + if(Distance > FLT_EPSILON) + { + ALfloat coeffs[MAX_AMBI_COEFFS]; + ALfloat w0 = 0.0f; + + /* Calculate NFC filter coefficient if needed. */ + if(Device->AvgSpeakerDist > 0.0f) + { + ALfloat mdist = Distance * Listener->Params.MetersPerUnit; + ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / + (Device->AvgSpeakerDist * (ALfloat)Device->Frequency); + w0 = SPEEDOFSOUNDMETRESPERSEC / + (mdist * (ALfloat)Device->Frequency); + /* Clamp w0 for really close distances, to prevent excessive + * bass. + */ + w0 = minf(w0, w1*4.0f); + + /* Adjust NFC filters. */ + for(c = 0;c < num_channels;c++) + NfcFilterAdjust(&voice->Direct.Params[c].NFCtrlFilter, w0); + + for(i = 0;i < MAX_AMBI_ORDER+1;i++) + voice->Direct.ChannelsPerOrder[i] = Device->NumChannelsPerOrder[i]; + voice->Flags |= VOICE_HAS_NFC; + } + + /* Calculate the directional coefficients once, which apply to all + * input channels. + */ + CalcAngleCoeffs((Device->Render_Mode==StereoPair) ? ScaleAzimuthFront(Azi, 1.5f) : Azi, + Elev, Spread, coeffs); + + for(c = 0;c < num_channels;c++) + { + /* Special-case LFE */ + if(chans[c].channel == LFE) + { + if(Device->Dry.Buffer == Device->RealOut.Buffer) + { + int idx = GetChannelIdxByName(&Device->RealOut, chans[c].channel); + if(idx != -1) voice->Direct.Params[c].Gains.Target[idx] = DryGain; + } + continue; + } + + ComputePanGains(&Device->Dry, coeffs, DryGain * downmix_gain, + voice->Direct.Params[c].Gains.Target); + } + + for(i = 0;i < NumSends;i++) + { + const ALeffectslot *Slot = SendSlots[i]; + if(Slot) + for(c = 0;c < num_channels;c++) + { + /* Skip LFE */ + if(chans[c].channel != LFE) + ComputePanningGainsBF(Slot->ChanMap, + Slot->NumChannels, coeffs, WetGain[i] * downmix_gain, + voice->Send[i].Params[c].Gains.Target + ); + } + } + } + else + { + ALfloat w0 = 0.0f; + + if(Device->AvgSpeakerDist > 0.0f) + { + /* If the source distance is 0, set w0 to w1 to act as a pass- + * through. We still want to pass the signal through the + * filters so they keep an appropriate history, in case the + * source moves away from the listener. + */ + w0 = SPEEDOFSOUNDMETRESPERSEC / + (Device->AvgSpeakerDist * (ALfloat)Device->Frequency); + + for(c = 0;c < num_channels;c++) + NfcFilterAdjust(&voice->Direct.Params[c].NFCtrlFilter, w0); + + for(i = 0;i < MAX_AMBI_ORDER+1;i++) + voice->Direct.ChannelsPerOrder[i] = Device->NumChannelsPerOrder[i]; + voice->Flags |= VOICE_HAS_NFC; + } + + for(c = 0;c < num_channels;c++) + { + ALfloat coeffs[MAX_AMBI_COEFFS]; + + /* Special-case LFE */ + if(chans[c].channel == LFE) + { + if(Device->Dry.Buffer == Device->RealOut.Buffer) + { + int idx = GetChannelIdxByName(&Device->RealOut, chans[c].channel); + if(idx != -1) voice->Direct.Params[c].Gains.Target[idx] = DryGain; + } + continue; + } + + CalcAngleCoeffs( + (Device->Render_Mode==StereoPair) ? ScaleAzimuthFront(chans[c].angle, 3.0f) + : chans[c].angle, + chans[c].elevation, Spread, coeffs + ); + + ComputePanGains(&Device->Dry, coeffs, DryGain, + voice->Direct.Params[c].Gains.Target); + for(i = 0;i < NumSends;i++) + { + const ALeffectslot *Slot = SendSlots[i]; + if(Slot) + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, + coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target + ); + } + } + } + } + + { + ALfloat hfScale = props->Direct.HFReference / Frequency; + ALfloat lfScale = props->Direct.LFReference / Frequency; + ALfloat gainHF = maxf(DryGainHF, 0.001f); /* Limit -60dB */ + ALfloat gainLF = maxf(DryGainLF, 0.001f); + + voice->Direct.FilterType = AF_None; + if(gainHF != 1.0f) voice->Direct.FilterType |= AF_LowPass; + if(gainLF != 1.0f) voice->Direct.FilterType |= AF_HighPass; + BiquadFilter_setParams( + &voice->Direct.Params[0].LowPass, BiquadType_HighShelf, + gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) + ); + BiquadFilter_setParams( + &voice->Direct.Params[0].HighPass, BiquadType_LowShelf, + gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) + ); + for(c = 1;c < num_channels;c++) + { + BiquadFilter_copyParams(&voice->Direct.Params[c].LowPass, + &voice->Direct.Params[0].LowPass); + BiquadFilter_copyParams(&voice->Direct.Params[c].HighPass, + &voice->Direct.Params[0].HighPass); + } + } + for(i = 0;i < NumSends;i++) + { + ALfloat hfScale = props->Send[i].HFReference / Frequency; + ALfloat lfScale = props->Send[i].LFReference / Frequency; + ALfloat gainHF = maxf(WetGainHF[i], 0.001f); + ALfloat gainLF = maxf(WetGainLF[i], 0.001f); + + voice->Send[i].FilterType = AF_None; + if(gainHF != 1.0f) voice->Send[i].FilterType |= AF_LowPass; + if(gainLF != 1.0f) voice->Send[i].FilterType |= AF_HighPass; + BiquadFilter_setParams( + &voice->Send[i].Params[0].LowPass, BiquadType_HighShelf, + gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) + ); + BiquadFilter_setParams( + &voice->Send[i].Params[0].HighPass, BiquadType_LowShelf, + gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) + ); + for(c = 1;c < num_channels;c++) + { + BiquadFilter_copyParams(&voice->Send[i].Params[c].LowPass, + &voice->Send[i].Params[0].LowPass); + BiquadFilter_copyParams(&voice->Send[i].Params[c].HighPass, + &voice->Send[i].Params[0].HighPass); + } + } +} + +static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) +{ + const ALCdevice *Device = ALContext->Device; + const ALlistener *Listener = ALContext->Listener; + ALfloat DryGain, DryGainHF, DryGainLF; + ALfloat WetGain[MAX_SENDS]; + ALfloat WetGainHF[MAX_SENDS]; + ALfloat WetGainLF[MAX_SENDS]; + ALeffectslot *SendSlots[MAX_SENDS]; + ALfloat Pitch; + ALsizei i; + + voice->Direct.Buffer = Device->Dry.Buffer; + voice->Direct.Channels = Device->Dry.NumChannels; + for(i = 0;i < Device->NumAuxSends;i++) + { + SendSlots[i] = props->Send[i].Slot; + if(!SendSlots[i] && i == 0) + SendSlots[i] = ALContext->DefaultSlot; + if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) + { + SendSlots[i] = NULL; + voice->Send[i].Buffer = NULL; + voice->Send[i].Channels = 0; + } + else + { + voice->Send[i].Buffer = SendSlots[i]->WetBuffer; + voice->Send[i].Channels = SendSlots[i]->NumChannels; + } + } + + /* Calculate the stepping value */ + Pitch = (ALfloat)ALBuffer->Frequency/(ALfloat)Device->Frequency * props->Pitch; + if(Pitch > (ALfloat)MAX_PITCH) + voice->Step = MAX_PITCH<Step = maxi(fastf2i(Pitch * FRACTIONONE), 1); + if(props->Resampler == BSinc24Resampler) + BsincPrepare(voice->Step, &voice->ResampleState.bsinc, &bsinc24); + else if(props->Resampler == BSinc12Resampler) + BsincPrepare(voice->Step, &voice->ResampleState.bsinc, &bsinc12); + voice->Resampler = SelectResampler(props->Resampler); + + /* Calculate gains */ + DryGain = clampf(props->Gain, props->MinGain, props->MaxGain); + DryGain *= props->Direct.Gain * Listener->Params.Gain; + DryGain = minf(DryGain, GAIN_MIX_MAX); + DryGainHF = props->Direct.GainHF; + DryGainLF = props->Direct.GainLF; + for(i = 0;i < Device->NumAuxSends;i++) + { + WetGain[i] = clampf(props->Gain, props->MinGain, props->MaxGain); + WetGain[i] *= props->Send[i].Gain * Listener->Params.Gain; + WetGain[i] = minf(WetGain[i], GAIN_MIX_MAX); + WetGainHF[i] = props->Send[i].GainHF; + WetGainLF[i] = props->Send[i].GainLF; + } + + CalcPanningAndFilters(voice, 0.0f, 0.0f, 0.0f, 0.0f, DryGain, DryGainHF, DryGainLF, WetGain, + WetGainLF, WetGainHF, SendSlots, ALBuffer, props, Listener, Device); +} + +static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) +{ + const ALCdevice *Device = ALContext->Device; + const ALlistener *Listener = ALContext->Listener; + const ALsizei NumSends = Device->NumAuxSends; + aluVector Position, Velocity, Direction, SourceToListener; + ALfloat Distance, ClampedDist, DopplerFactor; + ALeffectslot *SendSlots[MAX_SENDS]; + ALfloat RoomRolloff[MAX_SENDS]; + ALfloat DecayDistance[MAX_SENDS]; + ALfloat DecayLFDistance[MAX_SENDS]; + ALfloat DecayHFDistance[MAX_SENDS]; + ALfloat DryGain, DryGainHF, DryGainLF; + ALfloat WetGain[MAX_SENDS]; + ALfloat WetGainHF[MAX_SENDS]; + ALfloat WetGainLF[MAX_SENDS]; + bool directional; + ALfloat ev, az; + ALfloat spread; + ALfloat Pitch; + ALint i; + + /* Set mixing buffers and get send parameters. */ + voice->Direct.Buffer = Device->Dry.Buffer; + voice->Direct.Channels = Device->Dry.NumChannels; + for(i = 0;i < NumSends;i++) + { + SendSlots[i] = props->Send[i].Slot; + if(!SendSlots[i] && i == 0) + SendSlots[i] = ALContext->DefaultSlot; + if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) + { + SendSlots[i] = NULL; + RoomRolloff[i] = 0.0f; + DecayDistance[i] = 0.0f; + DecayLFDistance[i] = 0.0f; + DecayHFDistance[i] = 0.0f; + } + else if(SendSlots[i]->Params.AuxSendAuto) + { + RoomRolloff[i] = SendSlots[i]->Params.RoomRolloff + props->RoomRolloffFactor; + /* Calculate the distances to where this effect's decay reaches + * -60dB. + */ + DecayDistance[i] = SendSlots[i]->Params.DecayTime * + Listener->Params.ReverbSpeedOfSound; + DecayLFDistance[i] = DecayDistance[i] * SendSlots[i]->Params.DecayLFRatio; + DecayHFDistance[i] = DecayDistance[i] * SendSlots[i]->Params.DecayHFRatio; + if(SendSlots[i]->Params.DecayHFLimit) + { + ALfloat airAbsorption = SendSlots[i]->Params.AirAbsorptionGainHF; + if(airAbsorption < 1.0f) + { + /* Calculate the distance to where this effect's air + * absorption reaches -60dB, and limit the effect's HF + * decay distance (so it doesn't take any longer to decay + * than the air would allow). + */ + ALfloat absorb_dist = log10f(REVERB_DECAY_GAIN) / log10f(airAbsorption); + DecayHFDistance[i] = minf(absorb_dist, DecayHFDistance[i]); + } + } + } + else + { + /* If the slot's auxiliary send auto is off, the data sent to the + * effect slot is the same as the dry path, sans filter effects */ + RoomRolloff[i] = props->RolloffFactor; + DecayDistance[i] = 0.0f; + DecayLFDistance[i] = 0.0f; + DecayHFDistance[i] = 0.0f; + } + + if(!SendSlots[i]) + { + voice->Send[i].Buffer = NULL; + voice->Send[i].Channels = 0; + } + else + { + voice->Send[i].Buffer = SendSlots[i]->WetBuffer; + voice->Send[i].Channels = SendSlots[i]->NumChannels; + } + } + + /* Transform source to listener space (convert to head relative) */ + aluVectorSet(&Position, props->Position[0], props->Position[1], props->Position[2], 1.0f); + aluVectorSet(&Direction, props->Direction[0], props->Direction[1], props->Direction[2], 0.0f); + aluVectorSet(&Velocity, props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f); + if(props->HeadRelative == AL_FALSE) + { + const aluMatrixf *Matrix = &Listener->Params.Matrix; + /* Transform source vectors */ + Position = aluMatrixfVector(Matrix, &Position); + Velocity = aluMatrixfVector(Matrix, &Velocity); + Direction = aluMatrixfVector(Matrix, &Direction); + } + else + { + const aluVector *lvelocity = &Listener->Params.Velocity; + /* Offset the source velocity to be relative of the listener velocity */ + Velocity.v[0] += lvelocity->v[0]; + Velocity.v[1] += lvelocity->v[1]; + Velocity.v[2] += lvelocity->v[2]; + } + + directional = aluNormalize(Direction.v) > 0.0f; + SourceToListener.v[0] = -Position.v[0]; + SourceToListener.v[1] = -Position.v[1]; + SourceToListener.v[2] = -Position.v[2]; + SourceToListener.v[3] = 0.0f; + Distance = aluNormalize(SourceToListener.v); + + /* Initial source gain */ + DryGain = props->Gain; + DryGainHF = 1.0f; + DryGainLF = 1.0f; + for(i = 0;i < NumSends;i++) + { + WetGain[i] = props->Gain; + WetGainHF[i] = 1.0f; + WetGainLF[i] = 1.0f; + } + + /* Calculate distance attenuation */ + ClampedDist = Distance; + + switch(Listener->Params.SourceDistanceModel ? + props->DistanceModel : Listener->Params.DistanceModel) + { + case InverseDistanceClamped: + ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); + if(props->MaxDistance < props->RefDistance) + break; + /*fall-through*/ + case InverseDistance: + if(!(props->RefDistance > 0.0f)) + ClampedDist = props->RefDistance; + else + { + ALfloat dist = lerp(props->RefDistance, ClampedDist, props->RolloffFactor); + if(dist > 0.0f) DryGain *= props->RefDistance / dist; + for(i = 0;i < NumSends;i++) + { + dist = lerp(props->RefDistance, ClampedDist, RoomRolloff[i]); + if(dist > 0.0f) WetGain[i] *= props->RefDistance / dist; + } + } + break; + + case LinearDistanceClamped: + ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); + if(props->MaxDistance < props->RefDistance) + break; + /*fall-through*/ + case LinearDistance: + if(!(props->MaxDistance != props->RefDistance)) + ClampedDist = props->RefDistance; + else + { + ALfloat attn = props->RolloffFactor * (ClampedDist-props->RefDistance) / + (props->MaxDistance-props->RefDistance); + DryGain *= maxf(1.0f - attn, 0.0f); + for(i = 0;i < NumSends;i++) + { + attn = RoomRolloff[i] * (ClampedDist-props->RefDistance) / + (props->MaxDistance-props->RefDistance); + WetGain[i] *= maxf(1.0f - attn, 0.0f); + } + } + break; + + case ExponentDistanceClamped: + ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); + if(props->MaxDistance < props->RefDistance) + break; + /*fall-through*/ + case ExponentDistance: + if(!(ClampedDist > 0.0f && props->RefDistance > 0.0f)) + ClampedDist = props->RefDistance; + else + { + DryGain *= powf(ClampedDist/props->RefDistance, -props->RolloffFactor); + for(i = 0;i < NumSends;i++) + WetGain[i] *= powf(ClampedDist/props->RefDistance, -RoomRolloff[i]); + } + break; + + case DisableDistance: + ClampedDist = props->RefDistance; + break; + } + + /* Calculate directional soundcones */ + if(directional && props->InnerAngle < 360.0f) + { + ALfloat ConeVolume; + ALfloat ConeHF; + ALfloat Angle; + + Angle = acosf(aluDotproduct(&Direction, &SourceToListener)); + Angle = RAD2DEG(Angle * ConeScale * 2.0f); + if(!(Angle > props->InnerAngle)) + { + ConeVolume = 1.0f; + ConeHF = 1.0f; + } + else if(Angle < props->OuterAngle) + { + ALfloat scale = ( Angle-props->InnerAngle) / + (props->OuterAngle-props->InnerAngle); + ConeVolume = lerp(1.0f, props->OuterGain, scale); + ConeHF = lerp(1.0f, props->OuterGainHF, scale); + } + else + { + ConeVolume = props->OuterGain; + ConeHF = props->OuterGainHF; + } + + DryGain *= ConeVolume; + if(props->DryGainHFAuto) + DryGainHF *= ConeHF; + if(props->WetGainAuto) + { + for(i = 0;i < NumSends;i++) + WetGain[i] *= ConeVolume; + } + if(props->WetGainHFAuto) + { + for(i = 0;i < NumSends;i++) + WetGainHF[i] *= ConeHF; + } + } + + /* Apply gain and frequency filters */ + DryGain = clampf(DryGain, props->MinGain, props->MaxGain); + DryGain = minf(DryGain*props->Direct.Gain*Listener->Params.Gain, GAIN_MIX_MAX); + DryGainHF *= props->Direct.GainHF; + DryGainLF *= props->Direct.GainLF; + for(i = 0;i < NumSends;i++) + { + WetGain[i] = clampf(WetGain[i], props->MinGain, props->MaxGain); + WetGain[i] = minf(WetGain[i]*props->Send[i].Gain*Listener->Params.Gain, GAIN_MIX_MAX); + WetGainHF[i] *= props->Send[i].GainHF; + WetGainLF[i] *= props->Send[i].GainLF; + } + + /* Distance-based air absorption and initial send decay. */ + if(ClampedDist > props->RefDistance && props->RolloffFactor > 0.0f) + { + ALfloat meters_base = (ClampedDist-props->RefDistance) * props->RolloffFactor * + Listener->Params.MetersPerUnit; + if(props->AirAbsorptionFactor > 0.0f) + { + ALfloat hfattn = powf(AIRABSORBGAINHF, meters_base * props->AirAbsorptionFactor); + DryGainHF *= hfattn; + for(i = 0;i < NumSends;i++) + WetGainHF[i] *= hfattn; + } + + if(props->WetGainAuto) + { + /* Apply a decay-time transformation to the wet path, based on the + * source distance in meters. The initial decay of the reverb + * effect is calculated and applied to the wet path. + */ + for(i = 0;i < NumSends;i++) + { + ALfloat gain, gainhf, gainlf; + + if(!(DecayDistance[i] > 0.0f)) + continue; + + gain = powf(REVERB_DECAY_GAIN, meters_base/DecayDistance[i]); + WetGain[i] *= gain; + /* Yes, the wet path's air absorption is applied with + * WetGainAuto on, rather than WetGainHFAuto. + */ + if(gain > 0.0f) + { + gainhf = powf(REVERB_DECAY_GAIN, meters_base/DecayHFDistance[i]); + WetGainHF[i] *= minf(gainhf / gain, 1.0f); + gainlf = powf(REVERB_DECAY_GAIN, meters_base/DecayLFDistance[i]); + WetGainLF[i] *= minf(gainlf / gain, 1.0f); + } + } + } + } + + + /* Initial source pitch */ + Pitch = props->Pitch; + + /* Calculate velocity-based doppler effect */ + DopplerFactor = props->DopplerFactor * Listener->Params.DopplerFactor; + if(DopplerFactor > 0.0f) + { + const aluVector *lvelocity = &Listener->Params.Velocity; + const ALfloat SpeedOfSound = Listener->Params.SpeedOfSound; + ALfloat vss, vls; + + vss = aluDotproduct(&Velocity, &SourceToListener) * DopplerFactor; + vls = aluDotproduct(lvelocity, &SourceToListener) * DopplerFactor; + + if(!(vls < SpeedOfSound)) + { + /* Listener moving away from the source at the speed of sound. + * Sound waves can't catch it. + */ + Pitch = 0.0f; + } + else if(!(vss < SpeedOfSound)) + { + /* Source moving toward the listener at the speed of sound. Sound + * waves bunch up to extreme frequencies. + */ + Pitch = HUGE_VALF; + } + else + { + /* Source and listener movement is nominal. Calculate the proper + * doppler shift. + */ + Pitch *= (SpeedOfSound-vls) / (SpeedOfSound-vss); + } + } + + /* Adjust pitch based on the buffer and output frequencies, and calculate + * fixed-point stepping value. + */ + Pitch *= (ALfloat)ALBuffer->Frequency/(ALfloat)Device->Frequency; + if(Pitch > (ALfloat)MAX_PITCH) + voice->Step = MAX_PITCH<Step = maxi(fastf2i(Pitch * FRACTIONONE), 1); + if(props->Resampler == BSinc24Resampler) + BsincPrepare(voice->Step, &voice->ResampleState.bsinc, &bsinc24); + else if(props->Resampler == BSinc12Resampler) + BsincPrepare(voice->Step, &voice->ResampleState.bsinc, &bsinc12); + voice->Resampler = SelectResampler(props->Resampler); + + if(Distance > 0.0f) + { + /* Clamp Y, in case rounding errors caused it to end up outside of + * -1...+1. + */ + ev = asinf(clampf(-SourceToListener.v[1], -1.0f, 1.0f)); + /* Double negation on Z cancels out; negate once for changing source- + * to-listener to listener-to-source, and again for right-handed coords + * with -Z in front. + */ + az = atan2f(-SourceToListener.v[0], SourceToListener.v[2]*ZScale); + } + else + ev = az = 0.0f; + + if(props->Radius > Distance) + spread = F_TAU - Distance/props->Radius*F_PI; + else if(Distance > 0.0f) + spread = asinf(props->Radius / Distance) * 2.0f; + else + spread = 0.0f; + + CalcPanningAndFilters(voice, az, ev, Distance, spread, DryGain, DryGainHF, DryGainLF, WetGain, + WetGainLF, WetGainHF, SendSlots, ALBuffer, props, Listener, Device); +} + +static void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) +{ + ALbufferlistitem *BufferListItem; + struct ALvoiceProps *props; + + props = static_cast(ATOMIC_EXCHANGE_PTR(&voice->Update, + static_cast(nullptr), almemory_order_acq_rel)); + if(!props && !force) return; + + if(props) + { + memcpy(voice->Props, props, + FAM_SIZE(struct ALvoiceProps, Send, context->Device->NumAuxSends) + ); + + ATOMIC_REPLACE_HEAD(struct ALvoiceProps*, &context->FreeVoiceProps, props); + } + props = voice->Props; + + BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); + while(BufferListItem != NULL) + { + const ALbuffer *buffer = NULL; + ALsizei i = 0; + while(!buffer && i < BufferListItem->num_buffers) + buffer = BufferListItem->buffers[i]; + if(LIKELY(buffer)) + { + if(props->SpatializeMode == SpatializeOn || + (props->SpatializeMode == SpatializeAuto && buffer->FmtChannels == FmtMono)) + CalcAttnSourceParams(voice, props, buffer, context); + else + CalcNonAttnSourceParams(voice, props, buffer, context); + break; + } + BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_acquire); + } +} + + +static void ProcessParamUpdates(ALCcontext *ctx, const struct ALeffectslotArray *slots) +{ + ALvoice **voice, **voice_end; + ALsource *source; + ALsizei i; + + IncrementRef(&ctx->UpdateCount); + if(!ATOMIC_LOAD(&ctx->HoldUpdates, almemory_order_acquire)) + { + bool cforce = CalcContextParams(ctx); + bool force = CalcListenerParams(ctx) | cforce; + for(i = 0;i < slots->count;i++) + force |= CalcEffectSlotParams(slots->slot[i], ctx, cforce); + + voice = ctx->Voices; + voice_end = voice + ctx->VoiceCount; + for(;voice != voice_end;++voice) + { + source = ATOMIC_LOAD(&(*voice)->Source, almemory_order_acquire); + if(source) CalcSourceParams(*voice, ctx, force); + } + } + IncrementRef(&ctx->UpdateCount); +} + + +static void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*RESTRICT Buffer)[BUFFERSIZE], + int lidx, int ridx, int cidx, ALsizei SamplesToDo, + ALsizei NumChannels) +{ + ALfloat (*RESTRICT lsplit)[BUFFERSIZE] = Stablizer->LSplit; + ALfloat (*RESTRICT rsplit)[BUFFERSIZE] = Stablizer->RSplit; + ALsizei i; + + /* Apply an all-pass to all channels, except the front-left and front- + * right, so they maintain the same relative phase. + */ + for(i = 0;i < NumChannels;i++) + { + if(i == lidx || i == ridx) + continue; + splitterap_process(&Stablizer->APFilter[i], Buffer[i], SamplesToDo); + } + + bandsplit_process(&Stablizer->LFilter, lsplit[1], lsplit[0], Buffer[lidx], SamplesToDo); + bandsplit_process(&Stablizer->RFilter, rsplit[1], rsplit[0], Buffer[ridx], SamplesToDo); + + for(i = 0;i < SamplesToDo;i++) + { + ALfloat lfsum, hfsum; + ALfloat m, s, c; + + lfsum = lsplit[0][i] + rsplit[0][i]; + hfsum = lsplit[1][i] + rsplit[1][i]; + s = lsplit[0][i] + lsplit[1][i] - rsplit[0][i] - rsplit[1][i]; + + /* This pans the separate low- and high-frequency sums between being on + * the center channel and the left/right channels. The low-frequency + * sum is 1/3rd toward center (2/3rds on left/right) and the high- + * frequency sum is 1/4th toward center (3/4ths on left/right). These + * values can be tweaked. + */ + m = lfsum*cosf(1.0f/3.0f * F_PI_2) + hfsum*cosf(1.0f/4.0f * F_PI_2); + c = lfsum*sinf(1.0f/3.0f * F_PI_2) + hfsum*sinf(1.0f/4.0f * F_PI_2); + + /* The generated center channel signal adds to the existing signal, + * while the modified left and right channels replace. + */ + Buffer[lidx][i] = (m + s) * 0.5f; + Buffer[ridx][i] = (m - s) * 0.5f; + Buffer[cidx][i] += c * 0.5f; + } +} + +static void ApplyDistanceComp(ALfloat (*RESTRICT Samples)[BUFFERSIZE], DistanceComp *distcomp, + ALfloat *RESTRICT Values, ALsizei SamplesToDo, ALsizei numchans) +{ + ALsizei i, c; + + for(c = 0;c < numchans;c++) + { + ALfloat *RESTRICT inout = Samples[c]; + const ALfloat gain = distcomp[c].Gain; + const ALsizei base = distcomp[c].Length; + ALfloat *RESTRICT distbuf = distcomp[c].Buffer; + + if(base == 0) + { + if(gain < 1.0f) + { + for(i = 0;i < SamplesToDo;i++) + inout[i] *= gain; + } + continue; + } + + if(LIKELY(SamplesToDo >= base)) + { + for(i = 0;i < base;i++) + Values[i] = distbuf[i]; + for(;i < SamplesToDo;i++) + Values[i] = inout[i-base]; + memcpy(distbuf, &inout[SamplesToDo-base], base*sizeof(ALfloat)); + } + else + { + for(i = 0;i < SamplesToDo;i++) + Values[i] = distbuf[i]; + memmove(distbuf, distbuf+SamplesToDo, (base-SamplesToDo)*sizeof(ALfloat)); + memcpy(distbuf+base-SamplesToDo, inout, SamplesToDo*sizeof(ALfloat)); + } + for(i = 0;i < SamplesToDo;i++) + inout[i] = Values[i]*gain; + } +} + +static void ApplyDither(ALfloat (*RESTRICT Samples)[BUFFERSIZE], ALuint *dither_seed, + const ALfloat quant_scale, const ALsizei SamplesToDo, + const ALsizei numchans) +{ + const ALfloat invscale = 1.0f / quant_scale; + ALuint seed = *dither_seed; + ALsizei c, i; + + ASSUME(numchans > 0); + ASSUME(SamplesToDo > 0); + + /* Dithering. Step 1, generate whitenoise (uniform distribution of random + * values between -1 and +1). Step 2 is to add the noise to the samples, + * before rounding and after scaling up to the desired quantization depth. + */ + for(c = 0;c < numchans;c++) + { + ALfloat *RESTRICT samples = Samples[c]; + for(i = 0;i < SamplesToDo;i++) + { + ALfloat val = samples[i] * quant_scale; + ALuint rng0 = dither_rng(&seed); + ALuint rng1 = dither_rng(&seed); + val += (ALfloat)(rng0*(1.0/UINT_MAX) - rng1*(1.0/UINT_MAX)); + samples[i] = fast_roundf(val) * invscale; + } + } + *dither_seed = seed; +} + + +static inline ALfloat Conv_ALfloat(ALfloat val) +{ return val; } +static inline ALint Conv_ALint(ALfloat val) +{ + /* Floats have a 23-bit mantissa. There is an implied 1 bit in the mantissa + * along with the sign bit, giving 25 bits total, so [-16777216, +16777216] + * is the max value a normalized float can be scaled to before losing + * precision. + */ + return fastf2i(clampf(val*16777216.0f, -16777216.0f, 16777215.0f))<<7; +} +static inline ALshort Conv_ALshort(ALfloat val) +{ return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); } +static inline ALbyte Conv_ALbyte(ALfloat val) +{ return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); } + +/* Define unsigned output variations. */ +#define DECL_TEMPLATE(T, func, O) \ +static inline T Conv_##T(ALfloat val) { return func(val)+O; } + +DECL_TEMPLATE(ALubyte, Conv_ALbyte, 128) +DECL_TEMPLATE(ALushort, Conv_ALshort, 32768) +DECL_TEMPLATE(ALuint, Conv_ALint, 2147483648u) + +#undef DECL_TEMPLATE + +#define DECL_TEMPLATE(T, A) \ +static void Write##A(const ALfloat (*RESTRICT InBuffer)[BUFFERSIZE], \ + ALvoid *OutBuffer, ALsizei Offset, ALsizei SamplesToDo, \ + ALsizei numchans) \ +{ \ + ALsizei i, j; \ + \ + ASSUME(numchans > 0); \ + ASSUME(SamplesToDo > 0); \ + \ + for(j = 0;j < numchans;j++) \ + { \ + const ALfloat *RESTRICT in = InBuffer[j]; \ + T *RESTRICT out = (T*)OutBuffer + Offset*numchans + j; \ + \ + for(i = 0;i < SamplesToDo;i++) \ + out[i*numchans] = Conv_##T(in[i]); \ + } \ +} + +DECL_TEMPLATE(ALfloat, F32) +DECL_TEMPLATE(ALuint, UI32) +DECL_TEMPLATE(ALint, I32) +DECL_TEMPLATE(ALushort, UI16) +DECL_TEMPLATE(ALshort, I16) +DECL_TEMPLATE(ALubyte, UI8) +DECL_TEMPLATE(ALbyte, I8) + +#undef DECL_TEMPLATE + + +void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) +{ + ALsizei SamplesToDo; + ALsizei SamplesDone; + ALCcontext *ctx; + ALsizei i, c; + + START_MIXER_MODE(); + for(SamplesDone = 0;SamplesDone < NumSamples;) + { + SamplesToDo = mini(NumSamples-SamplesDone, BUFFERSIZE); + for(c = 0;c < device->Dry.NumChannels;c++) + memset(device->Dry.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); + if(device->Dry.Buffer != device->FOAOut.Buffer) + for(c = 0;c < device->FOAOut.NumChannels;c++) + memset(device->FOAOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); + if(device->Dry.Buffer != device->RealOut.Buffer) + for(c = 0;c < device->RealOut.NumChannels;c++) + memset(device->RealOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); + + IncrementRef(&device->MixCount); + + ctx = ATOMIC_LOAD(&device->ContextList, almemory_order_acquire); + while(ctx) + { + const struct ALeffectslotArray *auxslots; + + auxslots = ATOMIC_LOAD(&ctx->ActiveAuxSlots, almemory_order_acquire); + ProcessParamUpdates(ctx, auxslots); + + for(i = 0;i < auxslots->count;i++) + { + ALeffectslot *slot = auxslots->slot[i]; + for(c = 0;c < slot->NumChannels;c++) + memset(slot->WetBuffer[c], 0, SamplesToDo*sizeof(ALfloat)); + } + + /* source processing */ + for(i = 0;i < ctx->VoiceCount;i++) + { + ALvoice *voice = ctx->Voices[i]; + ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire); + if(source && ATOMIC_LOAD(&voice->Playing, almemory_order_relaxed) && + voice->Step > 0) + { + if(!MixSource(voice, source->id, ctx, SamplesToDo)) + { + ATOMIC_STORE(&voice->Source, static_cast(nullptr), + almemory_order_relaxed); + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + SendSourceStoppedEvent(ctx, source->id); + } + } + } + + /* effect slot processing */ + for(i = 0;i < auxslots->count;i++) + { + const ALeffectslot *slot = auxslots->slot[i]; + ALeffectState *state = slot->Params.EffectState; + V(state,process)(SamplesToDo, slot->WetBuffer, state->OutBuffer, + state->OutChannels); + } + + ctx = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed); + } + + /* Increment the clock time. Every second's worth of samples is + * converted and added to clock base so that large sample counts don't + * overflow during conversion. This also guarantees an exact, stable + * conversion. */ + device->SamplesDone += SamplesToDo; + device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES; + device->SamplesDone %= device->Frequency; + IncrementRef(&device->MixCount); + + /* Apply post-process for finalizing the Dry mix to the RealOut + * (Ambisonic decode, UHJ encode, etc). + */ + if(LIKELY(device->PostProcess)) + device->PostProcess(device, SamplesToDo); + + if(device->Stablizer) + { + int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); + int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); + int cidx = GetChannelIdxByName(&device->RealOut, FrontCenter); + assert(lidx >= 0 && ridx >= 0 && cidx >= 0); + + ApplyStablizer(device->Stablizer, device->RealOut.Buffer, lidx, ridx, cidx, + SamplesToDo, device->RealOut.NumChannels); + } + + ApplyDistanceComp(device->RealOut.Buffer, device->ChannelDelay, device->TempBuffer[0], + SamplesToDo, device->RealOut.NumChannels); + + if(device->Limiter) + ApplyCompression(device->Limiter, SamplesToDo, device->RealOut.Buffer); + + if(device->DitherDepth > 0.0f) + ApplyDither(device->RealOut.Buffer, &device->DitherSeed, device->DitherDepth, + SamplesToDo, device->RealOut.NumChannels); + + if(LIKELY(OutBuffer)) + { + ALfloat (*Buffer)[BUFFERSIZE] = device->RealOut.Buffer; + ALsizei Channels = device->RealOut.NumChannels; + + switch(device->FmtType) + { +#define HANDLE_WRITE(T, S) case T: \ + Write##S(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); break; + HANDLE_WRITE(DevFmtByte, I8) + HANDLE_WRITE(DevFmtUByte, UI8) + HANDLE_WRITE(DevFmtShort, I16) + HANDLE_WRITE(DevFmtUShort, UI16) + HANDLE_WRITE(DevFmtInt, I32) + HANDLE_WRITE(DevFmtUInt, UI32) + HANDLE_WRITE(DevFmtFloat, F32) +#undef HANDLE_WRITE + } + } + + SamplesDone += SamplesToDo; + } + END_MIXER_MODE(); +} + + +void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) +{ + AsyncEvent evt = ASYNC_EVENT(EventType_Disconnected); + ALCcontext *ctx; + va_list args; + int msglen; + + if(!ATOMIC_EXCHANGE(&device->Connected, AL_FALSE, almemory_order_acq_rel)) + return; + + evt.u.user.type = AL_EVENT_TYPE_DISCONNECTED_SOFT; + evt.u.user.id = 0; + evt.u.user.param = 0; + + va_start(args, msg); + msglen = vsnprintf(evt.u.user.msg, sizeof(evt.u.user.msg), msg, args); + va_end(args); + + if(msglen < 0 || (size_t)msglen >= sizeof(evt.u.user.msg)) + evt.u.user.msg[sizeof(evt.u.user.msg)-1] = 0; + + ctx = ATOMIC_LOAD_SEQ(&device->ContextList); + while(ctx) + { + ALbitfieldSOFT enabledevt = ATOMIC_LOAD(&ctx->EnabledEvts, almemory_order_acquire); + ALsizei i; + + if((enabledevt&EventType_Disconnected) && + ll_ringbuffer_write(ctx->AsyncEvents, (const char*)&evt, 1) == 1) + alsem_post(&ctx->EventSem); + + for(i = 0;i < ctx->VoiceCount;i++) + { + ALvoice *voice = ctx->Voices[i]; + ALsource *source; + + source = static_cast(ATOMIC_EXCHANGE_PTR(&voice->Source, + static_cast(nullptr), almemory_order_relaxed)); + if(source && ATOMIC_LOAD(&voice->Playing, almemory_order_relaxed)) + { + /* If the source's voice was playing, it's now effectively + * stopped (the source state will be updated the next time it's + * checked). + */ + SendSourceStoppedEvent(ctx, source->id); + } + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + } + + ctx = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed); + } +} diff --git a/Alc/filters/defs.h b/Alc/filters/defs.h index beb4ab3e..58b7cc0a 100644 --- a/Alc/filters/defs.h +++ b/Alc/filters/defs.h @@ -4,6 +4,10 @@ #include "AL/al.h" #include "math_defs.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Filters implementation is based on the "Cookbook formulae for audio * EQ biquad filter coefficients" by Robert Bristow-Johnson * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt @@ -109,4 +113,8 @@ inline void BiquadFilter_passthru(BiquadFilter *filter, ALsizei numsamples) } } +#ifdef __cplusplus +} // extern "C" +#endif + #endif /* ALC_FILTER_H */ diff --git a/Alc/mixer/defs.h b/Alc/mixer/defs.h index acb8a8c2..46f70982 100644 --- a/Alc/mixer/defs.h +++ b/Alc/mixer/defs.h @@ -6,6 +6,10 @@ #include "alMain.h" #include "alu.h" +#ifdef __cplusplus +extern "C" { +#endif + struct MixGains; struct MixHrtfParams; @@ -116,4 +120,8 @@ const ALfloat *Resample_bsinc_Neon(const InterpState *state, const ALfloat *REST ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen); +#ifdef __cplusplus +} // extern "C" +#endif + #endif /* MIXER_DEFS_H */ diff --git a/Alc/mixvoice.c b/Alc/mixvoice.c index ffbcdb25..9a774786 100644 --- a/Alc/mixvoice.c +++ b/Alc/mixvoice.c @@ -261,7 +261,7 @@ static void LoadSamples(ALfloat *RESTRICT dst, const ALvoid *RESTRICT src, ALint static const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, ALfloat *RESTRICT dst, const ALfloat *RESTRICT src, - ALsizei numsamples, enum ActiveFilters type) + ALsizei numsamples, int type) { ALsizei i; switch(type) diff --git a/CMakeLists.txt b/CMakeLists.txt index 509cc511..1b925889 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -799,7 +799,7 @@ SET(OPENAL_OBJS ) SET(ALC_OBJS Alc/alc.cpp - Alc/ALu.c + Alc/alu.cpp Alc/alconfig.cpp Alc/alconfig.h Alc/bs2b.c diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 03c388b4..2dbd3107 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -136,7 +136,7 @@ inline void aluMatrixfSet(aluMatrixf *matrix, ALfloat m00, ALfloat m01, ALfloat } -enum ActiveFilters { +enum { AF_None = 0, AF_LowPass = 1, AF_HighPass = 2, @@ -285,7 +285,7 @@ typedef struct ALvoice { InterpState ResampleState; struct { - enum ActiveFilters FilterType; + int FilterType; DirectParams Params[MAX_INPUT_CHANNELS]; ALfloat (*Buffer)[BUFFERSIZE]; @@ -294,7 +294,7 @@ typedef struct ALvoice { } Direct; struct { - enum ActiveFilters FilterType; + int FilterType; SendParams Params[MAX_INPUT_CHANNELS]; ALfloat (*Buffer)[BUFFERSIZE]; diff --git a/native-tools/bsincgen.c b/native-tools/bsincgen.c index 72bd8183..4e85135b 100644 --- a/native-tools/bsincgen.c +++ b/native-tools/bsincgen.c @@ -249,6 +249,11 @@ static void BsiGenerateTables(FILE *output, const char *tabname, const double re for(si = 0; si < BSINC_SCALE_COUNT; si++) mt[si] = (mt[si]+3) & ~3; + // Calculate the table size. + i = 0; + for(si = 0; si < BSINC_SCALE_COUNT; si++) + i += 4 * BSINC_PHASE_COUNT * mt[si]; + fprintf(output, "/* This %d%s order filter has a rejection of -%.0fdB, yielding a transition width\n" " * of ~%.3f (normalized frequency). Order increases when downsampling to a\n" @@ -256,12 +261,36 @@ static void BsiGenerateTables(FILE *output, const char *tabname, const double re " * width) suffers to reduce the CPU cost. The bandlimiting will cut all sound\n" " * after downsampling by ~%.2f octaves.\n" " */\n" -"const BSincTable %s = {\n", +"alignas(16) constexpr float %s_tab[%d] = {\n", order, (((order%100)/10) == 1) ? "th" : ((order%10) == 1) ? "st" : ((order%10) == 2) ? "nd" : ((order%10) == 3) ? "rd" : "th", - rejection, width, log2(1.0/scaleBase), tabname); + rejection, width, log2(1.0/scaleBase), tabname, i); + for(si = 0; si < BSINC_SCALE_COUNT; si++) + { + const int m = mt[si]; + const int o = num_points_min - (m / 2); + + for(pi = 0; pi < BSINC_PHASE_COUNT; pi++) + { + fprintf(output, " /* %2d,%2d (%d) */", si, pi, m); + fprintf(output, "\n "); + for(i = 0; i < m; i++) + fprintf(output, " %+14.9ef,", filter[si][pi][o + i]); + fprintf(output, "\n "); + for(i = 0; i < m; i++) + fprintf(output, " %+14.9ef,", scDeltas[si][pi][o + i]); + fprintf(output, "\n "); + for(i = 0; i < m; i++) + fprintf(output, " %+14.9ef,", phDeltas[si][pi][o + i]); + fprintf(output, "\n "); + for(i = 0; i < m; i++) + fprintf(output, " %+14.9ef,", spDeltas[si][pi][o + i]); + fprintf(output, "\n"); + } + } + fprintf(output, "};\nconstexpr BSincTable %s = {\n", tabname); /* The scaleBase is calculated from the Kaiser window transition width. It represents the absolute limit to the filter before it fully cuts @@ -286,37 +315,8 @@ static void BsiGenerateTables(FILE *output, const char *tabname, const double re } fprintf(output, " },\n"); - - // Calculate the table size. - i = 0; - for(si = 0; si < BSINC_SCALE_COUNT; si++) - i += 4 * BSINC_PHASE_COUNT * mt[si]; - - fprintf(output, "\n /* Tab (%d entries) */ {\n", i); - for(si = 0; si < BSINC_SCALE_COUNT; si++) - { - const int m = mt[si]; - const int o = num_points_min - (m / 2); - - for(pi = 0; pi < BSINC_PHASE_COUNT; pi++) - { - fprintf(output, " /* %2d,%2d (%d) */", si, pi, m); - fprintf(output, "\n "); - for(i = 0; i < m; i++) - fprintf(output, " %+14.9ef,", filter[si][pi][o + i]); - fprintf(output, "\n "); - for(i = 0; i < m; i++) - fprintf(output, " %+14.9ef,", scDeltas[si][pi][o + i]); - fprintf(output, "\n "); - for(i = 0; i < m; i++) - fprintf(output, " %+14.9ef,", phDeltas[si][pi][o + i]); - fprintf(output, "\n "); - for(i = 0; i < m; i++) - fprintf(output, " %+14.9ef,", spDeltas[si][pi][o + i]); - fprintf(output, "\n"); - } - } - fprintf(output, " }\n};\n\n"); + fprintf(output, " %s_tab\n", tabname); + fprintf(output, "};\n\n"); } @@ -348,12 +348,12 @@ int main(int argc, char *argv[]) "static_assert(BSINC_SCALE_COUNT == %d, \"Unexpected BSINC_SCALE_COUNT value!\");\n" "static_assert(BSINC_PHASE_COUNT == %d, \"Unexpected BSINC_PHASE_COUNT value!\");\n" "static_assert(FRACTIONONE == %d, \"Unexpected FRACTIONONE value!\");\n\n" -"typedef struct BSincTable {\n" +"struct BSincTable {\n" " const float scaleBase, scaleRange;\n" " const int m[BSINC_SCALE_COUNT];\n" " const int filterOffset[BSINC_SCALE_COUNT];\n" -" alignas(16) const float Tab[];\n" -"} BSincTable;\n\n", BSINC_SCALE_COUNT, BSINC_PHASE_COUNT, FRACTIONONE); +" const float *Tab;\n" +"};\n\n", BSINC_SCALE_COUNT, BSINC_PHASE_COUNT, FRACTIONONE); /* A 23rd order filter with a -60dB drop at nyquist. */ BsiGenerateTables(output, "bsinc24", 60.0, 23); /* An 11th order filter with a -40dB drop at nyquist. */ -- cgit v1.2.3 From a68d0b68d74a9f3fa65096fdfddc5a04fa118dfa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Nov 2018 20:46:50 -0800 Subject: Convert mixvoice.c to C++ --- Alc/mixvoice.c | 759 ------------------------------------------------------ Alc/mixvoice.cpp | 761 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 762 insertions(+), 760 deletions(-) delete mode 100644 Alc/mixvoice.c create mode 100644 Alc/mixvoice.cpp diff --git a/Alc/mixvoice.c b/Alc/mixvoice.c deleted file mode 100644 index 9a774786..00000000 --- a/Alc/mixvoice.c +++ /dev/null @@ -1,759 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "alMain.h" -#include "AL/al.h" -#include "AL/alc.h" -#include "alSource.h" -#include "alBuffer.h" -#include "alListener.h" -#include "alAuxEffectSlot.h" -#include "sample_cvt.h" -#include "alu.h" -#include "alconfig.h" -#include "ringbuffer.h" - -#include "cpu_caps.h" -#include "mixer/defs.h" - - -static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, - "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!"); - -/* BSinc24 requires up to 23 extra samples before the current position, and 24 after. */ -static_assert(MAX_RESAMPLE_PADDING >= 24, "MAX_RESAMPLE_PADDING must be at least 24!"); - - -enum Resampler ResamplerDefault = LinearResampler; - -MixerFunc MixSamples = Mix_C; -RowMixerFunc MixRowSamples = MixRow_C; -static HrtfMixerFunc MixHrtfSamples = MixHrtf_C; -static HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_C; - -static MixerFunc SelectMixer(void) -{ -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return Mix_Neon; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return Mix_SSE; -#endif - return Mix_C; -} - -static RowMixerFunc SelectRowMixer(void) -{ -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return MixRow_Neon; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return MixRow_SSE; -#endif - return MixRow_C; -} - -static inline HrtfMixerFunc SelectHrtfMixer(void) -{ -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return MixHrtf_Neon; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return MixHrtf_SSE; -#endif - return MixHrtf_C; -} - -static inline HrtfMixerBlendFunc SelectHrtfBlendMixer(void) -{ -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return MixHrtfBlend_Neon; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return MixHrtfBlend_SSE; -#endif - return MixHrtfBlend_C; -} - -ResamplerFunc SelectResampler(enum Resampler resampler) -{ - switch(resampler) - { - case PointResampler: - return Resample_point_C; - case LinearResampler: -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return Resample_lerp_Neon; -#endif -#ifdef HAVE_SSE4_1 - if((CPUCapFlags&CPU_CAP_SSE4_1)) - return Resample_lerp_SSE41; -#endif -#ifdef HAVE_SSE2 - if((CPUCapFlags&CPU_CAP_SSE2)) - return Resample_lerp_SSE2; -#endif - return Resample_lerp_C; - case FIR4Resampler: - return Resample_cubic_C; - case BSinc12Resampler: - case BSinc24Resampler: -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return Resample_bsinc_Neon; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return Resample_bsinc_SSE; -#endif - return Resample_bsinc_C; - } - - return Resample_point_C; -} - - -void aluInitMixer(void) -{ - const char *str; - - if(ConfigValueStr(NULL, NULL, "resampler", &str)) - { - if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0) - ResamplerDefault = PointResampler; - else if(strcasecmp(str, "linear") == 0) - ResamplerDefault = LinearResampler; - else if(strcasecmp(str, "cubic") == 0) - ResamplerDefault = FIR4Resampler; - else if(strcasecmp(str, "bsinc12") == 0) - ResamplerDefault = BSinc12Resampler; - else if(strcasecmp(str, "bsinc24") == 0) - ResamplerDefault = BSinc24Resampler; - else if(strcasecmp(str, "bsinc") == 0) - { - WARN("Resampler option \"%s\" is deprecated, using bsinc12\n", str); - ResamplerDefault = BSinc12Resampler; - } - else if(strcasecmp(str, "sinc4") == 0 || strcasecmp(str, "sinc8") == 0) - { - WARN("Resampler option \"%s\" is deprecated, using cubic\n", str); - ResamplerDefault = FIR4Resampler; - } - else - { - char *end; - long n = strtol(str, &end, 0); - if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == FIR4Resampler)) - ResamplerDefault = n; - else - WARN("Invalid resampler: %s\n", str); - } - } - - MixHrtfBlendSamples = SelectHrtfBlendMixer(); - MixHrtfSamples = SelectHrtfMixer(); - MixSamples = SelectMixer(); - MixRowSamples = SelectRowMixer(); -} - - -static void SendAsyncEvent(ALCcontext *context, ALuint enumtype, ALenum type, - ALuint objid, ALuint param, const char *msg) -{ - AsyncEvent evt = ASYNC_EVENT(enumtype); - evt.u.user.type = type; - evt.u.user.id = objid; - evt.u.user.param = param; - strcpy(evt.u.user.msg, msg); - if(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) == 1) - alsem_post(&context->EventSem); -} - - -static inline ALfloat Sample_ALubyte(ALubyte val) -{ return (val-128) * (1.0f/128.0f); } - -static inline ALfloat Sample_ALshort(ALshort val) -{ return val * (1.0f/32768.0f); } - -static inline ALfloat Sample_ALfloat(ALfloat val) -{ return val; } - -static inline ALfloat Sample_ALdouble(ALdouble val) -{ return (ALfloat)val; } - -typedef ALubyte ALmulaw; -static inline ALfloat Sample_ALmulaw(ALmulaw val) -{ return muLawDecompressionTable[val] * (1.0f/32768.0f); } - -typedef ALubyte ALalaw; -static inline ALfloat Sample_ALalaw(ALalaw val) -{ return aLawDecompressionTable[val] * (1.0f/32768.0f); } - -#define DECL_TEMPLATE(T) \ -static inline void Load_##T(ALfloat *RESTRICT dst, const T *RESTRICT src, \ - ALint srcstep, ALsizei samples) \ -{ \ - ALsizei i; \ - for(i = 0;i < samples;i++) \ - dst[i] += Sample_##T(src[i*srcstep]); \ -} - -DECL_TEMPLATE(ALubyte) -DECL_TEMPLATE(ALshort) -DECL_TEMPLATE(ALfloat) -DECL_TEMPLATE(ALdouble) -DECL_TEMPLATE(ALmulaw) -DECL_TEMPLATE(ALalaw) - -#undef DECL_TEMPLATE - -static void LoadSamples(ALfloat *RESTRICT dst, const ALvoid *RESTRICT src, ALint srcstep, - enum FmtType srctype, ALsizei samples) -{ -#define HANDLE_FMT(ET, ST) case ET: Load_##ST(dst, src, srcstep, samples); break - switch(srctype) - { - HANDLE_FMT(FmtUByte, ALubyte); - HANDLE_FMT(FmtShort, ALshort); - HANDLE_FMT(FmtFloat, ALfloat); - HANDLE_FMT(FmtDouble, ALdouble); - HANDLE_FMT(FmtMulaw, ALmulaw); - HANDLE_FMT(FmtAlaw, ALalaw); - } -#undef HANDLE_FMT -} - - -static const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, - ALfloat *RESTRICT dst, const ALfloat *RESTRICT src, - ALsizei numsamples, int type) -{ - ALsizei i; - switch(type) - { - case AF_None: - BiquadFilter_passthru(lpfilter, numsamples); - BiquadFilter_passthru(hpfilter, numsamples); - break; - - case AF_LowPass: - BiquadFilter_process(lpfilter, dst, src, numsamples); - BiquadFilter_passthru(hpfilter, numsamples); - return dst; - case AF_HighPass: - BiquadFilter_passthru(lpfilter, numsamples); - BiquadFilter_process(hpfilter, dst, src, numsamples); - return dst; - - case AF_BandPass: - for(i = 0;i < numsamples;) - { - ALfloat temp[256]; - ALsizei todo = mini(256, numsamples-i); - - BiquadFilter_process(lpfilter, temp, src+i, todo); - BiquadFilter_process(hpfilter, dst+i, temp, todo); - i += todo; - } - return dst; - } - return src; -} - - -/* This function uses these device temp buffers. */ -#define SOURCE_DATA_BUF 0 -#define RESAMPLED_BUF 1 -#define FILTERED_BUF 2 -#define NFC_DATA_BUF 3 -ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo) -{ - ALCdevice *Device = Context->Device; - ALbufferlistitem *BufferListItem; - ALbufferlistitem *BufferLoopItem; - ALsizei NumChannels, SampleSize; - ALbitfieldSOFT enabledevt; - ALsizei buffers_done = 0; - ResamplerFunc Resample; - ALsizei DataPosInt; - ALsizei DataPosFrac; - ALint64 DataSize64; - ALint increment; - ALsizei Counter; - ALsizei OutPos; - ALsizei IrSize; - bool isplaying; - bool firstpass; - bool isstatic; - ALsizei chan; - ALsizei send; - - /* Get source info */ - isplaying = true; /* Will only be called while playing. */ - isstatic = !!(voice->Flags&VOICE_IS_STATIC); - DataPosInt = ATOMIC_LOAD(&voice->position, almemory_order_acquire); - DataPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); - BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - BufferLoopItem = ATOMIC_LOAD(&voice->loop_buffer, almemory_order_relaxed); - NumChannels = voice->NumChannels; - SampleSize = voice->SampleSize; - increment = voice->Step; - - IrSize = (Device->HrtfHandle ? Device->HrtfHandle->irSize : 0); - - Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ? - Resample_copy_C : voice->Resampler); - - Counter = (voice->Flags&VOICE_IS_FADING) ? SamplesToDo : 0; - firstpass = true; - OutPos = 0; - - do { - ALsizei SrcBufferSize, DstBufferSize; - - /* Figure out how many buffer samples will be needed */ - DataSize64 = SamplesToDo-OutPos; - DataSize64 *= increment; - DataSize64 += DataPosFrac+FRACTIONMASK; - DataSize64 >>= FRACTIONBITS; - DataSize64 += MAX_RESAMPLE_PADDING*2; - SrcBufferSize = (ALsizei)mini64(DataSize64, BUFFERSIZE); - - /* Figure out how many samples we can actually mix from this. */ - DataSize64 = SrcBufferSize; - DataSize64 -= MAX_RESAMPLE_PADDING*2; - DataSize64 <<= FRACTIONBITS; - DataSize64 -= DataPosFrac; - DstBufferSize = (ALsizei)mini64((DataSize64+(increment-1)) / increment, - SamplesToDo - OutPos); - - /* Some mixers like having a multiple of 4, so try to give that unless - * this is the last update. */ - if(DstBufferSize < SamplesToDo-OutPos) - DstBufferSize &= ~3; - - /* It's impossible to have a buffer list item with no entries. */ - assert(BufferListItem->num_buffers > 0); - - for(chan = 0;chan < NumChannels;chan++) - { - const ALfloat *ResampledData; - ALfloat *SrcData = Device->TempBuffer[SOURCE_DATA_BUF]; - ALsizei FilledAmt; - - /* Load the previous samples into the source data first, and clear the rest. */ - memcpy(SrcData, voice->PrevSamples[chan], MAX_RESAMPLE_PADDING*sizeof(ALfloat)); - memset(SrcData+MAX_RESAMPLE_PADDING, 0, (BUFFERSIZE-MAX_RESAMPLE_PADDING)* - sizeof(ALfloat)); - FilledAmt = MAX_RESAMPLE_PADDING; - - if(isstatic) - { - /* TODO: For static sources, loop points are taken from the - * first buffer (should be adjusted by any buffer offset, to - * possibly be added later). - */ - const ALbuffer *Buffer0 = BufferListItem->buffers[0]; - const ALsizei LoopStart = Buffer0->LoopStart; - const ALsizei LoopEnd = Buffer0->LoopEnd; - const ALsizei LoopSize = LoopEnd - LoopStart; - - /* If current pos is beyond the loop range, do not loop */ - if(!BufferLoopItem || DataPosInt >= LoopEnd) - { - ALsizei SizeToDo = SrcBufferSize - FilledAmt; - ALsizei CompLen = 0; - ALsizei i; - - BufferLoopItem = NULL; - - for(i = 0;i < BufferListItem->num_buffers;i++) - { - const ALbuffer *buffer = BufferListItem->buffers[i]; - const ALubyte *Data = buffer->data; - ALsizei DataSize; - - if(DataPosInt >= buffer->SampleLen) - continue; - - /* Load what's left to play from the buffer */ - DataSize = mini(SizeToDo, buffer->SampleLen - DataPosInt); - CompLen = maxi(CompLen, DataSize); - - LoadSamples(&SrcData[FilledAmt], - &Data[(DataPosInt*NumChannels + chan)*SampleSize], - NumChannels, buffer->FmtType, DataSize - ); - } - FilledAmt += CompLen; - } - else - { - ALsizei SizeToDo = mini(SrcBufferSize - FilledAmt, LoopEnd - DataPosInt); - ALsizei CompLen = 0; - ALsizei i; - - for(i = 0;i < BufferListItem->num_buffers;i++) - { - const ALbuffer *buffer = BufferListItem->buffers[i]; - const ALubyte *Data = buffer->data; - ALsizei DataSize; - - if(DataPosInt >= buffer->SampleLen) - continue; - - /* Load what's left of this loop iteration */ - DataSize = mini(SizeToDo, buffer->SampleLen - DataPosInt); - CompLen = maxi(CompLen, DataSize); - - LoadSamples(&SrcData[FilledAmt], - &Data[(DataPosInt*NumChannels + chan)*SampleSize], - NumChannels, buffer->FmtType, DataSize - ); - } - FilledAmt += CompLen; - - while(SrcBufferSize > FilledAmt) - { - const ALsizei SizeToDo = mini(SrcBufferSize - FilledAmt, LoopSize); - - CompLen = 0; - for(i = 0;i < BufferListItem->num_buffers;i++) - { - const ALbuffer *buffer = BufferListItem->buffers[i]; - const ALubyte *Data = buffer->data; - ALsizei DataSize; - - if(LoopStart >= buffer->SampleLen) - continue; - - DataSize = mini(SizeToDo, buffer->SampleLen - LoopStart); - CompLen = maxi(CompLen, DataSize); - - LoadSamples(&SrcData[FilledAmt], - &Data[(LoopStart*NumChannels + chan)*SampleSize], - NumChannels, buffer->FmtType, DataSize - ); - } - FilledAmt += CompLen; - } - } - } - else - { - /* Crawl the buffer queue to fill in the temp buffer */ - ALbufferlistitem *tmpiter = BufferListItem; - ALsizei pos = DataPosInt; - - while(tmpiter && SrcBufferSize > FilledAmt) - { - ALsizei SizeToDo = SrcBufferSize - FilledAmt; - ALsizei CompLen = 0; - ALsizei i; - - for(i = 0;i < tmpiter->num_buffers;i++) - { - const ALbuffer *ALBuffer = tmpiter->buffers[i]; - ALsizei DataSize = ALBuffer ? ALBuffer->SampleLen : 0; - - if(DataSize > pos) - { - const ALubyte *Data = ALBuffer->data; - Data += (pos*NumChannels + chan)*SampleSize; - - DataSize = mini(SizeToDo, DataSize - pos); - CompLen = maxi(CompLen, DataSize); - - LoadSamples(&SrcData[FilledAmt], Data, NumChannels, - ALBuffer->FmtType, DataSize); - } - } - if(UNLIKELY(!CompLen)) - pos -= tmpiter->max_samples; - else - { - FilledAmt += CompLen; - if(SrcBufferSize <= FilledAmt) - break; - pos = 0; - } - tmpiter = ATOMIC_LOAD(&tmpiter->next, almemory_order_acquire); - if(!tmpiter) tmpiter = BufferLoopItem; - } - } - - /* Store the last source samples used for next time. */ - memcpy(voice->PrevSamples[chan], - &SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS], - MAX_RESAMPLE_PADDING*sizeof(ALfloat) - ); - - /* Now resample, then filter and mix to the appropriate outputs. */ - ResampledData = Resample(&voice->ResampleState, - &SrcData[MAX_RESAMPLE_PADDING], DataPosFrac, increment, - Device->TempBuffer[RESAMPLED_BUF], DstBufferSize - ); - { - DirectParams *parms = &voice->Direct.Params[chan]; - const ALfloat *samples; - - samples = DoFilters( - &parms->LowPass, &parms->HighPass, Device->TempBuffer[FILTERED_BUF], - ResampledData, DstBufferSize, voice->Direct.FilterType - ); - if(!(voice->Flags&VOICE_HAS_HRTF)) - { - if(!Counter) - memcpy(parms->Gains.Current, parms->Gains.Target, - sizeof(parms->Gains.Current)); - if(!(voice->Flags&VOICE_HAS_NFC)) - MixSamples(samples, voice->Direct.Channels, voice->Direct.Buffer, - parms->Gains.Current, parms->Gains.Target, Counter, OutPos, - DstBufferSize - ); - else - { - ALfloat *nfcsamples = Device->TempBuffer[NFC_DATA_BUF]; - ALsizei chanoffset = 0; - - MixSamples(samples, - voice->Direct.ChannelsPerOrder[0], voice->Direct.Buffer, - parms->Gains.Current, parms->Gains.Target, Counter, OutPos, - DstBufferSize - ); - chanoffset += voice->Direct.ChannelsPerOrder[0]; -#define APPLY_NFC_MIX(order) \ - if(voice->Direct.ChannelsPerOrder[order] > 0) \ - { \ - NfcFilterProcess##order(&parms->NFCtrlFilter, nfcsamples, samples, \ - DstBufferSize); \ - MixSamples(nfcsamples, voice->Direct.ChannelsPerOrder[order], \ - voice->Direct.Buffer+chanoffset, parms->Gains.Current+chanoffset, \ - parms->Gains.Target+chanoffset, Counter, OutPos, DstBufferSize \ - ); \ - chanoffset += voice->Direct.ChannelsPerOrder[order]; \ - } - APPLY_NFC_MIX(1) - APPLY_NFC_MIX(2) - APPLY_NFC_MIX(3) -#undef APPLY_NFC_MIX - } - } - else - { - MixHrtfParams hrtfparams; - ALsizei fademix = 0; - int lidx, ridx; - - lidx = GetChannelIdxByName(&Device->RealOut, FrontLeft); - ridx = GetChannelIdxByName(&Device->RealOut, FrontRight); - assert(lidx != -1 && ridx != -1); - - if(!Counter) - { - /* No fading, just overwrite the old HRTF params. */ - parms->Hrtf.Old = parms->Hrtf.Target; - } - else if(!(parms->Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD)) - { - /* The old HRTF params are silent, so overwrite the old - * coefficients with the new, and reset the old gain to - * 0. The future mix will then fade from silence. - */ - parms->Hrtf.Old = parms->Hrtf.Target; - parms->Hrtf.Old.Gain = 0.0f; - } - else if(firstpass) - { - ALfloat gain; - - /* Fade between the coefficients over 128 samples. */ - fademix = mini(DstBufferSize, 128); - - /* The new coefficients need to fade in completely - * since they're replacing the old ones. To keep the - * gain fading consistent, interpolate between the old - * and new target gains given how much of the fade time - * this mix handles. - */ - gain = lerp(parms->Hrtf.Old.Gain, parms->Hrtf.Target.Gain, - minf(1.0f, (ALfloat)fademix/Counter)); - hrtfparams.Coeffs = parms->Hrtf.Target.Coeffs; - hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; - hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; - hrtfparams.Gain = 0.0f; - hrtfparams.GainStep = gain / (ALfloat)fademix; - - MixHrtfBlendSamples( - voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], - samples, voice->Offset, OutPos, IrSize, &parms->Hrtf.Old, - &hrtfparams, &parms->Hrtf.State, fademix - ); - /* Update the old parameters with the result. */ - parms->Hrtf.Old = parms->Hrtf.Target; - if(fademix < Counter) - parms->Hrtf.Old.Gain = hrtfparams.Gain; - } - - if(fademix < DstBufferSize) - { - ALsizei todo = DstBufferSize - fademix; - ALfloat gain = parms->Hrtf.Target.Gain; - - /* Interpolate the target gain if the gain fading lasts - * longer than this mix. - */ - if(Counter > DstBufferSize) - gain = lerp(parms->Hrtf.Old.Gain, gain, - (ALfloat)todo/(Counter-fademix)); - - hrtfparams.Coeffs = parms->Hrtf.Target.Coeffs; - hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; - hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; - hrtfparams.Gain = parms->Hrtf.Old.Gain; - hrtfparams.GainStep = (gain - parms->Hrtf.Old.Gain) / (ALfloat)todo; - MixHrtfSamples( - voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], - samples+fademix, voice->Offset+fademix, OutPos+fademix, IrSize, - &hrtfparams, &parms->Hrtf.State, todo - ); - /* Store the interpolated gain or the final target gain - * depending if the fade is done. - */ - if(DstBufferSize < Counter) - parms->Hrtf.Old.Gain = gain; - else - parms->Hrtf.Old.Gain = parms->Hrtf.Target.Gain; - } - } - } - - for(send = 0;send < Device->NumAuxSends;send++) - { - SendParams *parms = &voice->Send[send].Params[chan]; - const ALfloat *samples; - - if(!voice->Send[send].Buffer) - continue; - - samples = DoFilters( - &parms->LowPass, &parms->HighPass, Device->TempBuffer[FILTERED_BUF], - ResampledData, DstBufferSize, voice->Send[send].FilterType - ); - - if(!Counter) - memcpy(parms->Gains.Current, parms->Gains.Target, - sizeof(parms->Gains.Current)); - MixSamples(samples, voice->Send[send].Channels, voice->Send[send].Buffer, - parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize - ); - } - } - /* Update positions */ - DataPosFrac += increment*DstBufferSize; - DataPosInt += DataPosFrac>>FRACTIONBITS; - DataPosFrac &= FRACTIONMASK; - - OutPos += DstBufferSize; - voice->Offset += DstBufferSize; - Counter = maxi(DstBufferSize, Counter) - DstBufferSize; - firstpass = false; - - if(isstatic) - { - if(BufferLoopItem) - { - /* Handle looping static source */ - const ALbuffer *Buffer = BufferListItem->buffers[0]; - ALsizei LoopStart = Buffer->LoopStart; - ALsizei LoopEnd = Buffer->LoopEnd; - if(DataPosInt >= LoopEnd) - { - assert(LoopEnd > LoopStart); - DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart; - } - } - else - { - /* Handle non-looping static source */ - if(DataPosInt >= BufferListItem->max_samples) - { - isplaying = false; - BufferListItem = NULL; - DataPosInt = 0; - DataPosFrac = 0; - break; - } - } - } - else while(1) - { - /* Handle streaming source */ - if(BufferListItem->max_samples > DataPosInt) - break; - - DataPosInt -= BufferListItem->max_samples; - - buffers_done += BufferListItem->num_buffers; - BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_relaxed); - if(!BufferListItem && !(BufferListItem=BufferLoopItem)) - { - isplaying = false; - DataPosInt = 0; - DataPosFrac = 0; - break; - } - } - } while(isplaying && OutPos < SamplesToDo); - - voice->Flags |= VOICE_IS_FADING; - - /* Update source info */ - ATOMIC_STORE(&voice->position, DataPosInt, almemory_order_relaxed); - ATOMIC_STORE(&voice->position_fraction, DataPosFrac, almemory_order_relaxed); - ATOMIC_STORE(&voice->current_buffer, BufferListItem, almemory_order_release); - - /* Send any events now, after the position/buffer info was updated. */ - enabledevt = ATOMIC_LOAD(&Context->EnabledEvts, almemory_order_acquire); - if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) - SendAsyncEvent(Context, EventType_BufferCompleted, - AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, SourceID, buffers_done, "Buffer completed" - ); - - return isplaying; -} diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp new file mode 100644 index 00000000..03d51dd6 --- /dev/null +++ b/Alc/mixvoice.cpp @@ -0,0 +1,761 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "alMain.h" +#include "AL/al.h" +#include "AL/alc.h" +#include "alSource.h" +#include "alBuffer.h" +#include "alListener.h" +#include "alAuxEffectSlot.h" +#include "sample_cvt.h" +#include "alu.h" +#include "alconfig.h" +#include "ringbuffer.h" + +#include "cpu_caps.h" +#include "mixer/defs.h" + + +static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, + "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!"); + +/* BSinc24 requires up to 23 extra samples before the current position, and 24 after. */ +static_assert(MAX_RESAMPLE_PADDING >= 24, "MAX_RESAMPLE_PADDING must be at least 24!"); + + +enum Resampler ResamplerDefault = LinearResampler; + +MixerFunc MixSamples = Mix_C; +RowMixerFunc MixRowSamples = MixRow_C; +static HrtfMixerFunc MixHrtfSamples = MixHrtf_C; +static HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_C; + +static MixerFunc SelectMixer(void) +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return Mix_Neon; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return Mix_SSE; +#endif + return Mix_C; +} + +static RowMixerFunc SelectRowMixer(void) +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return MixRow_Neon; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixRow_SSE; +#endif + return MixRow_C; +} + +static inline HrtfMixerFunc SelectHrtfMixer(void) +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return MixHrtf_Neon; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixHrtf_SSE; +#endif + return MixHrtf_C; +} + +static inline HrtfMixerBlendFunc SelectHrtfBlendMixer(void) +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return MixHrtfBlend_Neon; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixHrtfBlend_SSE; +#endif + return MixHrtfBlend_C; +} + +ResamplerFunc SelectResampler(enum Resampler resampler) +{ + switch(resampler) + { + case PointResampler: + return Resample_point_C; + case LinearResampler: +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return Resample_lerp_Neon; +#endif +#ifdef HAVE_SSE4_1 + if((CPUCapFlags&CPU_CAP_SSE4_1)) + return Resample_lerp_SSE41; +#endif +#ifdef HAVE_SSE2 + if((CPUCapFlags&CPU_CAP_SSE2)) + return Resample_lerp_SSE2; +#endif + return Resample_lerp_C; + case FIR4Resampler: + return Resample_cubic_C; + case BSinc12Resampler: + case BSinc24Resampler: +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return Resample_bsinc_Neon; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return Resample_bsinc_SSE; +#endif + return Resample_bsinc_C; + } + + return Resample_point_C; +} + + +void aluInitMixer(void) +{ + const char *str; + + if(ConfigValueStr(NULL, NULL, "resampler", &str)) + { + if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0) + ResamplerDefault = PointResampler; + else if(strcasecmp(str, "linear") == 0) + ResamplerDefault = LinearResampler; + else if(strcasecmp(str, "cubic") == 0) + ResamplerDefault = FIR4Resampler; + else if(strcasecmp(str, "bsinc12") == 0) + ResamplerDefault = BSinc12Resampler; + else if(strcasecmp(str, "bsinc24") == 0) + ResamplerDefault = BSinc24Resampler; + else if(strcasecmp(str, "bsinc") == 0) + { + WARN("Resampler option \"%s\" is deprecated, using bsinc12\n", str); + ResamplerDefault = BSinc12Resampler; + } + else if(strcasecmp(str, "sinc4") == 0 || strcasecmp(str, "sinc8") == 0) + { + WARN("Resampler option \"%s\" is deprecated, using cubic\n", str); + ResamplerDefault = FIR4Resampler; + } + else + { + char *end; + long n = strtol(str, &end, 0); + if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == FIR4Resampler)) + ResamplerDefault = static_cast(n); + else + WARN("Invalid resampler: %s\n", str); + } + } + + MixHrtfBlendSamples = SelectHrtfBlendMixer(); + MixHrtfSamples = SelectHrtfMixer(); + MixSamples = SelectMixer(); + MixRowSamples = SelectRowMixer(); +} + + +static void SendAsyncEvent(ALCcontext *context, ALuint enumtype, ALenum type, + ALuint objid, ALuint param, const char *msg) +{ + AsyncEvent evt = ASYNC_EVENT(enumtype); + evt.u.user.type = type; + evt.u.user.id = objid; + evt.u.user.param = param; + strcpy(evt.u.user.msg, msg); + if(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) == 1) + alsem_post(&context->EventSem); +} + + +static inline ALfloat Sample_ALubyte(ALubyte val) +{ return (val-128) * (1.0f/128.0f); } + +static inline ALfloat Sample_ALshort(ALshort val) +{ return val * (1.0f/32768.0f); } + +static inline ALfloat Sample_ALfloat(ALfloat val) +{ return val; } + +static inline ALfloat Sample_ALdouble(ALdouble val) +{ return (ALfloat)val; } + +typedef ALubyte ALmulaw; +static inline ALfloat Sample_ALmulaw(ALmulaw val) +{ return muLawDecompressionTable[val] * (1.0f/32768.0f); } + +typedef ALubyte ALalaw; +static inline ALfloat Sample_ALalaw(ALalaw val) +{ return aLawDecompressionTable[val] * (1.0f/32768.0f); } + +#define DECL_TEMPLATE(T) \ +static inline void Load_##T(ALfloat *RESTRICT dst, const T *RESTRICT src, \ + ALint srcstep, ALsizei samples) \ +{ \ + ALsizei i; \ + for(i = 0;i < samples;i++) \ + dst[i] += Sample_##T(src[i*srcstep]); \ +} + +DECL_TEMPLATE(ALubyte) +DECL_TEMPLATE(ALshort) +DECL_TEMPLATE(ALfloat) +DECL_TEMPLATE(ALdouble) +DECL_TEMPLATE(ALmulaw) +DECL_TEMPLATE(ALalaw) + +#undef DECL_TEMPLATE + +static void LoadSamples(ALfloat *RESTRICT dst, const ALvoid *RESTRICT src, ALint srcstep, + enum FmtType srctype, ALsizei samples) +{ +#define HANDLE_FMT(ET, ST) \ + case ET: Load_##ST(dst, static_cast(src), srcstep, samples); \ + break + switch(srctype) + { + HANDLE_FMT(FmtUByte, ALubyte); + HANDLE_FMT(FmtShort, ALshort); + HANDLE_FMT(FmtFloat, ALfloat); + HANDLE_FMT(FmtDouble, ALdouble); + HANDLE_FMT(FmtMulaw, ALmulaw); + HANDLE_FMT(FmtAlaw, ALalaw); + } +#undef HANDLE_FMT +} + + +static const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, + ALfloat *RESTRICT dst, const ALfloat *RESTRICT src, + ALsizei numsamples, int type) +{ + ALsizei i; + switch(type) + { + case AF_None: + BiquadFilter_passthru(lpfilter, numsamples); + BiquadFilter_passthru(hpfilter, numsamples); + break; + + case AF_LowPass: + BiquadFilter_process(lpfilter, dst, src, numsamples); + BiquadFilter_passthru(hpfilter, numsamples); + return dst; + case AF_HighPass: + BiquadFilter_passthru(lpfilter, numsamples); + BiquadFilter_process(hpfilter, dst, src, numsamples); + return dst; + + case AF_BandPass: + for(i = 0;i < numsamples;) + { + ALfloat temp[256]; + ALsizei todo = mini(256, numsamples-i); + + BiquadFilter_process(lpfilter, temp, src+i, todo); + BiquadFilter_process(hpfilter, dst+i, temp, todo); + i += todo; + } + return dst; + } + return src; +} + + +/* This function uses these device temp buffers. */ +#define SOURCE_DATA_BUF 0 +#define RESAMPLED_BUF 1 +#define FILTERED_BUF 2 +#define NFC_DATA_BUF 3 +ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo) +{ + ALCdevice *Device = Context->Device; + ALbufferlistitem *BufferListItem; + ALbufferlistitem *BufferLoopItem; + ALsizei NumChannels, SampleSize; + ALbitfieldSOFT enabledevt; + ALsizei buffers_done = 0; + ResamplerFunc Resample; + ALsizei DataPosInt; + ALsizei DataPosFrac; + ALint64 DataSize64; + ALint increment; + ALsizei Counter; + ALsizei OutPos; + ALsizei IrSize; + bool isplaying; + bool firstpass; + bool isstatic; + ALsizei chan; + ALsizei send; + + /* Get source info */ + isplaying = true; /* Will only be called while playing. */ + isstatic = !!(voice->Flags&VOICE_IS_STATIC); + DataPosInt = ATOMIC_LOAD(&voice->position, almemory_order_acquire); + DataPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); + BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); + BufferLoopItem = ATOMIC_LOAD(&voice->loop_buffer, almemory_order_relaxed); + NumChannels = voice->NumChannels; + SampleSize = voice->SampleSize; + increment = voice->Step; + + IrSize = (Device->HrtfHandle ? Device->HrtfHandle->irSize : 0); + + Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ? + Resample_copy_C : voice->Resampler); + + Counter = (voice->Flags&VOICE_IS_FADING) ? SamplesToDo : 0; + firstpass = true; + OutPos = 0; + + do { + ALsizei SrcBufferSize, DstBufferSize; + + /* Figure out how many buffer samples will be needed */ + DataSize64 = SamplesToDo-OutPos; + DataSize64 *= increment; + DataSize64 += DataPosFrac+FRACTIONMASK; + DataSize64 >>= FRACTIONBITS; + DataSize64 += MAX_RESAMPLE_PADDING*2; + SrcBufferSize = (ALsizei)mini64(DataSize64, BUFFERSIZE); + + /* Figure out how many samples we can actually mix from this. */ + DataSize64 = SrcBufferSize; + DataSize64 -= MAX_RESAMPLE_PADDING*2; + DataSize64 <<= FRACTIONBITS; + DataSize64 -= DataPosFrac; + DstBufferSize = (ALsizei)mini64((DataSize64+(increment-1)) / increment, + SamplesToDo - OutPos); + + /* Some mixers like having a multiple of 4, so try to give that unless + * this is the last update. */ + if(DstBufferSize < SamplesToDo-OutPos) + DstBufferSize &= ~3; + + /* It's impossible to have a buffer list item with no entries. */ + assert(BufferListItem->num_buffers > 0); + + for(chan = 0;chan < NumChannels;chan++) + { + const ALfloat *ResampledData; + ALfloat *SrcData = Device->TempBuffer[SOURCE_DATA_BUF]; + ALsizei FilledAmt; + + /* Load the previous samples into the source data first, and clear the rest. */ + memcpy(SrcData, voice->PrevSamples[chan], MAX_RESAMPLE_PADDING*sizeof(ALfloat)); + memset(SrcData+MAX_RESAMPLE_PADDING, 0, (BUFFERSIZE-MAX_RESAMPLE_PADDING)* + sizeof(ALfloat)); + FilledAmt = MAX_RESAMPLE_PADDING; + + if(isstatic) + { + /* TODO: For static sources, loop points are taken from the + * first buffer (should be adjusted by any buffer offset, to + * possibly be added later). + */ + const ALbuffer *Buffer0 = BufferListItem->buffers[0]; + const ALsizei LoopStart = Buffer0->LoopStart; + const ALsizei LoopEnd = Buffer0->LoopEnd; + const ALsizei LoopSize = LoopEnd - LoopStart; + + /* If current pos is beyond the loop range, do not loop */ + if(!BufferLoopItem || DataPosInt >= LoopEnd) + { + ALsizei SizeToDo = SrcBufferSize - FilledAmt; + ALsizei CompLen = 0; + ALsizei i; + + BufferLoopItem = NULL; + + for(i = 0;i < BufferListItem->num_buffers;i++) + { + const ALbuffer *buffer = BufferListItem->buffers[i]; + const ALubyte *Data = static_cast(buffer->data); + ALsizei DataSize; + + if(DataPosInt >= buffer->SampleLen) + continue; + + /* Load what's left to play from the buffer */ + DataSize = mini(SizeToDo, buffer->SampleLen - DataPosInt); + CompLen = maxi(CompLen, DataSize); + + LoadSamples(&SrcData[FilledAmt], + &Data[(DataPosInt*NumChannels + chan)*SampleSize], + NumChannels, buffer->FmtType, DataSize + ); + } + FilledAmt += CompLen; + } + else + { + ALsizei SizeToDo = mini(SrcBufferSize - FilledAmt, LoopEnd - DataPosInt); + ALsizei CompLen = 0; + ALsizei i; + + for(i = 0;i < BufferListItem->num_buffers;i++) + { + const ALbuffer *buffer = BufferListItem->buffers[i]; + const ALubyte *Data = static_cast(buffer->data); + ALsizei DataSize; + + if(DataPosInt >= buffer->SampleLen) + continue; + + /* Load what's left of this loop iteration */ + DataSize = mini(SizeToDo, buffer->SampleLen - DataPosInt); + CompLen = maxi(CompLen, DataSize); + + LoadSamples(&SrcData[FilledAmt], + &Data[(DataPosInt*NumChannels + chan)*SampleSize], + NumChannels, buffer->FmtType, DataSize + ); + } + FilledAmt += CompLen; + + while(SrcBufferSize > FilledAmt) + { + const ALsizei SizeToDo = mini(SrcBufferSize - FilledAmt, LoopSize); + + CompLen = 0; + for(i = 0;i < BufferListItem->num_buffers;i++) + { + const ALbuffer *buffer = BufferListItem->buffers[i]; + const ALubyte *Data = static_cast(buffer->data); + ALsizei DataSize; + + if(LoopStart >= buffer->SampleLen) + continue; + + DataSize = mini(SizeToDo, buffer->SampleLen - LoopStart); + CompLen = maxi(CompLen, DataSize); + + LoadSamples(&SrcData[FilledAmt], + &Data[(LoopStart*NumChannels + chan)*SampleSize], + NumChannels, buffer->FmtType, DataSize + ); + } + FilledAmt += CompLen; + } + } + } + else + { + /* Crawl the buffer queue to fill in the temp buffer */ + ALbufferlistitem *tmpiter = BufferListItem; + ALsizei pos = DataPosInt; + + while(tmpiter && SrcBufferSize > FilledAmt) + { + ALsizei SizeToDo = SrcBufferSize - FilledAmt; + ALsizei CompLen = 0; + ALsizei i; + + for(i = 0;i < tmpiter->num_buffers;i++) + { + const ALbuffer *ALBuffer = tmpiter->buffers[i]; + ALsizei DataSize = ALBuffer ? ALBuffer->SampleLen : 0; + + if(DataSize > pos) + { + const ALubyte *Data = static_cast(ALBuffer->data); + Data += (pos*NumChannels + chan)*SampleSize; + + DataSize = mini(SizeToDo, DataSize - pos); + CompLen = maxi(CompLen, DataSize); + + LoadSamples(&SrcData[FilledAmt], Data, NumChannels, + ALBuffer->FmtType, DataSize); + } + } + if(UNLIKELY(!CompLen)) + pos -= tmpiter->max_samples; + else + { + FilledAmt += CompLen; + if(SrcBufferSize <= FilledAmt) + break; + pos = 0; + } + tmpiter = ATOMIC_LOAD(&tmpiter->next, almemory_order_acquire); + if(!tmpiter) tmpiter = BufferLoopItem; + } + } + + /* Store the last source samples used for next time. */ + memcpy(voice->PrevSamples[chan], + &SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS], + MAX_RESAMPLE_PADDING*sizeof(ALfloat) + ); + + /* Now resample, then filter and mix to the appropriate outputs. */ + ResampledData = Resample(&voice->ResampleState, + &SrcData[MAX_RESAMPLE_PADDING], DataPosFrac, increment, + Device->TempBuffer[RESAMPLED_BUF], DstBufferSize + ); + { + DirectParams *parms = &voice->Direct.Params[chan]; + const ALfloat *samples; + + samples = DoFilters( + &parms->LowPass, &parms->HighPass, Device->TempBuffer[FILTERED_BUF], + ResampledData, DstBufferSize, voice->Direct.FilterType + ); + if(!(voice->Flags&VOICE_HAS_HRTF)) + { + if(!Counter) + memcpy(parms->Gains.Current, parms->Gains.Target, + sizeof(parms->Gains.Current)); + if(!(voice->Flags&VOICE_HAS_NFC)) + MixSamples(samples, voice->Direct.Channels, voice->Direct.Buffer, + parms->Gains.Current, parms->Gains.Target, Counter, OutPos, + DstBufferSize + ); + else + { + ALfloat *nfcsamples = Device->TempBuffer[NFC_DATA_BUF]; + ALsizei chanoffset = 0; + + MixSamples(samples, + voice->Direct.ChannelsPerOrder[0], voice->Direct.Buffer, + parms->Gains.Current, parms->Gains.Target, Counter, OutPos, + DstBufferSize + ); + chanoffset += voice->Direct.ChannelsPerOrder[0]; +#define APPLY_NFC_MIX(order) \ + if(voice->Direct.ChannelsPerOrder[order] > 0) \ + { \ + NfcFilterProcess##order(&parms->NFCtrlFilter, nfcsamples, samples, \ + DstBufferSize); \ + MixSamples(nfcsamples, voice->Direct.ChannelsPerOrder[order], \ + voice->Direct.Buffer+chanoffset, parms->Gains.Current+chanoffset, \ + parms->Gains.Target+chanoffset, Counter, OutPos, DstBufferSize \ + ); \ + chanoffset += voice->Direct.ChannelsPerOrder[order]; \ + } + APPLY_NFC_MIX(1) + APPLY_NFC_MIX(2) + APPLY_NFC_MIX(3) +#undef APPLY_NFC_MIX + } + } + else + { + MixHrtfParams hrtfparams; + ALsizei fademix = 0; + int lidx, ridx; + + lidx = GetChannelIdxByName(&Device->RealOut, FrontLeft); + ridx = GetChannelIdxByName(&Device->RealOut, FrontRight); + assert(lidx != -1 && ridx != -1); + + if(!Counter) + { + /* No fading, just overwrite the old HRTF params. */ + parms->Hrtf.Old = parms->Hrtf.Target; + } + else if(!(parms->Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD)) + { + /* The old HRTF params are silent, so overwrite the old + * coefficients with the new, and reset the old gain to + * 0. The future mix will then fade from silence. + */ + parms->Hrtf.Old = parms->Hrtf.Target; + parms->Hrtf.Old.Gain = 0.0f; + } + else if(firstpass) + { + ALfloat gain; + + /* Fade between the coefficients over 128 samples. */ + fademix = mini(DstBufferSize, 128); + + /* The new coefficients need to fade in completely + * since they're replacing the old ones. To keep the + * gain fading consistent, interpolate between the old + * and new target gains given how much of the fade time + * this mix handles. + */ + gain = lerp(parms->Hrtf.Old.Gain, parms->Hrtf.Target.Gain, + minf(1.0f, (ALfloat)fademix/Counter)); + hrtfparams.Coeffs = parms->Hrtf.Target.Coeffs; + hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; + hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; + hrtfparams.Gain = 0.0f; + hrtfparams.GainStep = gain / (ALfloat)fademix; + + MixHrtfBlendSamples( + voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], + samples, voice->Offset, OutPos, IrSize, &parms->Hrtf.Old, + &hrtfparams, &parms->Hrtf.State, fademix + ); + /* Update the old parameters with the result. */ + parms->Hrtf.Old = parms->Hrtf.Target; + if(fademix < Counter) + parms->Hrtf.Old.Gain = hrtfparams.Gain; + } + + if(fademix < DstBufferSize) + { + ALsizei todo = DstBufferSize - fademix; + ALfloat gain = parms->Hrtf.Target.Gain; + + /* Interpolate the target gain if the gain fading lasts + * longer than this mix. + */ + if(Counter > DstBufferSize) + gain = lerp(parms->Hrtf.Old.Gain, gain, + (ALfloat)todo/(Counter-fademix)); + + hrtfparams.Coeffs = parms->Hrtf.Target.Coeffs; + hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; + hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; + hrtfparams.Gain = parms->Hrtf.Old.Gain; + hrtfparams.GainStep = (gain - parms->Hrtf.Old.Gain) / (ALfloat)todo; + MixHrtfSamples( + voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], + samples+fademix, voice->Offset+fademix, OutPos+fademix, IrSize, + &hrtfparams, &parms->Hrtf.State, todo + ); + /* Store the interpolated gain or the final target gain + * depending if the fade is done. + */ + if(DstBufferSize < Counter) + parms->Hrtf.Old.Gain = gain; + else + parms->Hrtf.Old.Gain = parms->Hrtf.Target.Gain; + } + } + } + + for(send = 0;send < Device->NumAuxSends;send++) + { + SendParams *parms = &voice->Send[send].Params[chan]; + const ALfloat *samples; + + if(!voice->Send[send].Buffer) + continue; + + samples = DoFilters( + &parms->LowPass, &parms->HighPass, Device->TempBuffer[FILTERED_BUF], + ResampledData, DstBufferSize, voice->Send[send].FilterType + ); + + if(!Counter) + memcpy(parms->Gains.Current, parms->Gains.Target, + sizeof(parms->Gains.Current)); + MixSamples(samples, voice->Send[send].Channels, voice->Send[send].Buffer, + parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize + ); + } + } + /* Update positions */ + DataPosFrac += increment*DstBufferSize; + DataPosInt += DataPosFrac>>FRACTIONBITS; + DataPosFrac &= FRACTIONMASK; + + OutPos += DstBufferSize; + voice->Offset += DstBufferSize; + Counter = maxi(DstBufferSize, Counter) - DstBufferSize; + firstpass = false; + + if(isstatic) + { + if(BufferLoopItem) + { + /* Handle looping static source */ + const ALbuffer *Buffer = BufferListItem->buffers[0]; + ALsizei LoopStart = Buffer->LoopStart; + ALsizei LoopEnd = Buffer->LoopEnd; + if(DataPosInt >= LoopEnd) + { + assert(LoopEnd > LoopStart); + DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart; + } + } + else + { + /* Handle non-looping static source */ + if(DataPosInt >= BufferListItem->max_samples) + { + isplaying = false; + BufferListItem = NULL; + DataPosInt = 0; + DataPosFrac = 0; + break; + } + } + } + else while(1) + { + /* Handle streaming source */ + if(BufferListItem->max_samples > DataPosInt) + break; + + DataPosInt -= BufferListItem->max_samples; + + buffers_done += BufferListItem->num_buffers; + BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_relaxed); + if(!BufferListItem && !(BufferListItem=BufferLoopItem)) + { + isplaying = false; + DataPosInt = 0; + DataPosFrac = 0; + break; + } + } + } while(isplaying && OutPos < SamplesToDo); + + voice->Flags |= VOICE_IS_FADING; + + /* Update source info */ + ATOMIC_STORE(&voice->position, static_cast(DataPosInt), almemory_order_relaxed); + ATOMIC_STORE(&voice->position_fraction, DataPosFrac, almemory_order_relaxed); + ATOMIC_STORE(&voice->current_buffer, BufferListItem, almemory_order_release); + + /* Send any events now, after the position/buffer info was updated. */ + enabledevt = ATOMIC_LOAD(&Context->EnabledEvts, almemory_order_acquire); + if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) + SendAsyncEvent(Context, EventType_BufferCompleted, + AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, SourceID, buffers_done, "Buffer completed" + ); + + return isplaying; +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b925889..429a6639 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -845,7 +845,7 @@ SET(ALC_OBJS Alc/bformatdec.h Alc/panning.cpp Alc/polymorphism.h - Alc/mixvoice.c + Alc/mixvoice.cpp Alc/mixer/defs.h Alc/mixer/mixer_c.c ) -- cgit v1.2.3 From 8410e71a34fc286579573ab55dc94be83c48e55b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Nov 2018 21:31:52 -0800 Subject: Convert the reverb effect to C++ --- Alc/effects/reverb.c | 2090 ----------------------------------------------- Alc/effects/reverb.cpp | 2094 ++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 2095 insertions(+), 2091 deletions(-) delete mode 100644 Alc/effects/reverb.c create mode 100644 Alc/effects/reverb.cpp diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c deleted file mode 100644 index ad4aae5c..00000000 --- a/Alc/effects/reverb.c +++ /dev/null @@ -1,2090 +0,0 @@ -/** - * Ambisonic reverb engine for the OpenAL cross platform audio library - * Copyright (C) 2008-2017 by Chris Robinson and Christopher Fitzgerald. - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include "alMain.h" -#include "alu.h" -#include "alAuxEffectSlot.h" -#include "alListener.h" -#include "alError.h" -#include "filters/defs.h" - -/* This is a user config option for modifying the overall output of the reverb - * effect. - */ -ALfloat ReverbBoost = 1.0f; - -/* This is the maximum number of samples processed for each inner loop - * iteration. */ -#define MAX_UPDATE_SAMPLES 256 - -/* The number of samples used for cross-faded delay lines. This can be used - * to balance the compensation for abrupt line changes and attenuation due to - * minimally lengthed recursive lines. Try to keep this below the device - * update size. - */ -#define FADE_SAMPLES 128 - -/* The number of spatialized lines or channels to process. Four channels allows - * for a 3D A-Format response. NOTE: This can't be changed without taking care - * of the conversion matrices, and a few places where the length arrays are - * assumed to have 4 elements. - */ -#define NUM_LINES 4 - - -/* The B-Format to A-Format conversion matrix. The arrangement of rows is - * deliberately chosen to align the resulting lines to their spatial opposites - * (0:above front left <-> 3:above back right, 1:below front right <-> 2:below - * back left). It's not quite opposite, since the A-Format results in a - * tetrahedron, but it's close enough. Should the model be extended to 8-lines - * in the future, true opposites can be used. - */ -static const aluMatrixf B2A = {{ - { 0.288675134595f, 0.288675134595f, 0.288675134595f, 0.288675134595f }, - { 0.288675134595f, -0.288675134595f, -0.288675134595f, 0.288675134595f }, - { 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f }, - { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f } -}}; - -/* Converts A-Format to B-Format. */ -static const aluMatrixf A2B = {{ - { 0.866025403785f, 0.866025403785f, 0.866025403785f, 0.866025403785f }, - { 0.866025403785f, -0.866025403785f, 0.866025403785f, -0.866025403785f }, - { 0.866025403785f, -0.866025403785f, -0.866025403785f, 0.866025403785f }, - { 0.866025403785f, 0.866025403785f, -0.866025403785f, -0.866025403785f } -}}; - -static const ALfloat FadeStep = 1.0f / FADE_SAMPLES; - -/* The all-pass and delay lines have a variable length dependent on the - * effect's density parameter, which helps alter the perceived environment - * size. The size-to-density conversion is a cubed scale: - * - * density = min(1.0, pow(size, 3.0) / DENSITY_SCALE); - * - * The line lengths scale linearly with room size, so the inverse density - * conversion is needed, taking the cube root of the re-scaled density to - * calculate the line length multiplier: - * - * length_mult = max(5.0, cbrtf(density*DENSITY_SCALE)); - * - * The density scale below will result in a max line multiplier of 50, for an - * effective size range of 5m to 50m. - */ -static const ALfloat DENSITY_SCALE = 125000.0f; - -/* All delay line lengths are specified in seconds. - * - * To approximate early reflections, we break them up into primary (those - * arriving from the same direction as the source) and secondary (those - * arriving from the opposite direction). - * - * The early taps decorrelate the 4-channel signal to approximate an average - * room response for the primary reflections after the initial early delay. - * - * Given an average room dimension (d_a) and the speed of sound (c) we can - * calculate the average reflection delay (r_a) regardless of listener and - * source positions as: - * - * r_a = d_a / c - * c = 343.3 - * - * This can extended to finding the average difference (r_d) between the - * maximum (r_1) and minimum (r_0) reflection delays: - * - * r_0 = 2 / 3 r_a - * = r_a - r_d / 2 - * = r_d - * r_1 = 4 / 3 r_a - * = r_a + r_d / 2 - * = 2 r_d - * r_d = 2 / 3 r_a - * = r_1 - r_0 - * - * As can be determined by integrating the 1D model with a source (s) and - * listener (l) positioned across the dimension of length (d_a): - * - * r_d = int_(l=0)^d_a (int_(s=0)^d_a |2 d_a - 2 (l + s)| ds) dl / c - * - * The initial taps (T_(i=0)^N) are then specified by taking a power series - * that ranges between r_0 and half of r_1 less r_0: - * - * R_i = 2^(i / (2 N - 1)) r_d - * = r_0 + (2^(i / (2 N - 1)) - 1) r_d - * = r_0 + T_i - * T_i = R_i - r_0 - * = (2^(i / (2 N - 1)) - 1) r_d - * - * Assuming an average of 1m, we get the following taps: - */ -static const ALfloat EARLY_TAP_LENGTHS[NUM_LINES] = -{ - 0.0000000e+0f, 2.0213520e-4f, 4.2531060e-4f, 6.7171600e-4f -}; - -/* The early all-pass filter lengths are based on the early tap lengths: - * - * A_i = R_i / a - * - * Where a is the approximate maximum all-pass cycle limit (20). - */ -static const ALfloat EARLY_ALLPASS_LENGTHS[NUM_LINES] = -{ - 9.7096800e-5f, 1.0720356e-4f, 1.1836234e-4f, 1.3068260e-4f -}; - -/* The early delay lines are used to transform the primary reflections into - * the secondary reflections. The A-format is arranged in such a way that - * the channels/lines are spatially opposite: - * - * C_i is opposite C_(N-i-1) - * - * The delays of the two opposing reflections (R_i and O_i) from a source - * anywhere along a particular dimension always sum to twice its full delay: - * - * 2 r_a = R_i + O_i - * - * With that in mind we can determine the delay between the two reflections - * and thus specify our early line lengths (L_(i=0)^N) using: - * - * O_i = 2 r_a - R_(N-i-1) - * L_i = O_i - R_(N-i-1) - * = 2 (r_a - R_(N-i-1)) - * = 2 (r_a - T_(N-i-1) - r_0) - * = 2 r_a (1 - (2 / 3) 2^((N - i - 1) / (2 N - 1))) - * - * Using an average dimension of 1m, we get: - */ -static const ALfloat EARLY_LINE_LENGTHS[NUM_LINES] = -{ - 5.9850400e-4f, 1.0913150e-3f, 1.5376658e-3f, 1.9419362e-3f -}; - -/* The late all-pass filter lengths are based on the late line lengths: - * - * A_i = (5 / 3) L_i / r_1 - */ -static const ALfloat LATE_ALLPASS_LENGTHS[NUM_LINES] = -{ - 1.6182800e-4f, 2.0389060e-4f, 2.8159360e-4f, 3.2365600e-4f -}; - -/* The late lines are used to approximate the decaying cycle of recursive - * late reflections. - * - * Splitting the lines in half, we start with the shortest reflection paths - * (L_(i=0)^(N/2)): - * - * L_i = 2^(i / (N - 1)) r_d - * - * Then for the opposite (longest) reflection paths (L_(i=N/2)^N): - * - * L_i = 2 r_a - L_(i-N/2) - * = 2 r_a - 2^((i - N / 2) / (N - 1)) r_d - * - * For our 1m average room, we get: - */ -static const ALfloat LATE_LINE_LENGTHS[NUM_LINES] = -{ - 1.9419362e-3f, 2.4466860e-3f, 3.3791220e-3f, 3.8838720e-3f -}; - - -typedef struct DelayLineI { - /* The delay lines use interleaved samples, with the lengths being powers - * of 2 to allow the use of bit-masking instead of a modulus for wrapping. - */ - ALsizei Mask; - ALfloat (*Line)[NUM_LINES]; -} DelayLineI; - -typedef struct VecAllpass { - DelayLineI Delay; - ALfloat Coeff; - ALsizei Offset[NUM_LINES][2]; -} VecAllpass; - -typedef struct T60Filter { - /* Two filters are used to adjust the signal. One to control the low - * frequencies, and one to control the high frequencies. - */ - ALfloat MidGain[2]; - BiquadFilter HFFilter, LFFilter; -} T60Filter; - -typedef struct EarlyReflections { - /* A Gerzon vector all-pass filter is used to simulate initial diffusion. - * The spread from this filter also helps smooth out the reverb tail. - */ - VecAllpass VecAp; - - /* An echo line is used to complete the second half of the early - * reflections. - */ - DelayLineI Delay; - ALsizei Offset[NUM_LINES][2]; - ALfloat Coeff[NUM_LINES][2]; - - /* The gain for each output channel based on 3D panning. */ - ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; - ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; -} EarlyReflections; - -typedef struct LateReverb { - /* A recursive delay line is used fill in the reverb tail. */ - DelayLineI Delay; - ALsizei Offset[NUM_LINES][2]; - - /* Attenuation to compensate for the modal density and decay rate of the - * late lines. - */ - ALfloat DensityGain[2]; - - /* T60 decay filters are used to simulate absorption. */ - T60Filter T60[NUM_LINES]; - - /* A Gerzon vector all-pass filter is used to simulate diffusion. */ - VecAllpass VecAp; - - /* The gain for each output channel based on 3D panning. */ - ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; - ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; -} LateReverb; - -typedef struct ReverbState { - DERIVE_FROM_TYPE(ALeffectState); - - /* All delay lines are allocated as a single buffer to reduce memory - * fragmentation and management code. - */ - ALfloat *SampleBuffer; - ALuint TotalSamples; - - struct { - /* Calculated parameters which indicate if cross-fading is needed after - * an update. - */ - ALfloat Density, Diffusion; - ALfloat DecayTime, HFDecayTime, LFDecayTime; - ALfloat HFReference, LFReference; - } Params; - - /* Master effect filters */ - struct { - BiquadFilter Lp; - BiquadFilter Hp; - } Filter[NUM_LINES]; - - /* Core delay line (early reflections and late reverb tap from this). */ - DelayLineI Delay; - - /* Tap points for early reflection delay. */ - ALsizei EarlyDelayTap[NUM_LINES][2]; - ALfloat EarlyDelayCoeff[NUM_LINES][2]; - - /* Tap points for late reverb feed and delay. */ - ALsizei LateFeedTap; - ALsizei LateDelayTap[NUM_LINES][2]; - - /* Coefficients for the all-pass and line scattering matrices. */ - ALfloat MixX; - ALfloat MixY; - - EarlyReflections Early; - - LateReverb Late; - - /* Indicates the cross-fade point for delay line reads [0,FADE_SAMPLES]. */ - ALsizei FadeCount; - - /* Maximum number of samples to process at once. */ - ALsizei MaxUpdate[2]; - - /* The current write offset for all delay lines. */ - ALsizei Offset; - - /* Temporary storage used when processing. */ - alignas(16) ALfloat TempSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; - alignas(16) ALfloat MixSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; -} ReverbState; - -static ALvoid ReverbState_Destruct(ReverbState *State); -static ALboolean ReverbState_deviceUpdate(ReverbState *State, ALCdevice *Device); -static ALvoid ReverbState_update(ReverbState *State, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props); -static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ReverbState) - -DEFINE_ALEFFECTSTATE_VTABLE(ReverbState); - -static void ReverbState_Construct(ReverbState *state) -{ - ALsizei i, j; - - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ReverbState, ALeffectState, state); - - state->TotalSamples = 0; - state->SampleBuffer = NULL; - - state->Params.Density = AL_EAXREVERB_DEFAULT_DENSITY; - state->Params.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION; - state->Params.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME; - state->Params.HFDecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME*AL_EAXREVERB_DEFAULT_DECAY_HFRATIO; - state->Params.LFDecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME*AL_EAXREVERB_DEFAULT_DECAY_LFRATIO; - state->Params.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE; - state->Params.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE; - - for(i = 0;i < NUM_LINES;i++) - { - BiquadFilter_clear(&state->Filter[i].Lp); - BiquadFilter_clear(&state->Filter[i].Hp); - } - - state->Delay.Mask = 0; - state->Delay.Line = NULL; - - for(i = 0;i < NUM_LINES;i++) - { - state->EarlyDelayTap[i][0] = 0; - state->EarlyDelayTap[i][1] = 0; - state->EarlyDelayCoeff[i][0] = 0.0f; - state->EarlyDelayCoeff[i][1] = 0.0f; - } - - state->LateFeedTap = 0; - - for(i = 0;i < NUM_LINES;i++) - { - state->LateDelayTap[i][0] = 0; - state->LateDelayTap[i][1] = 0; - } - - state->MixX = 0.0f; - state->MixY = 0.0f; - - state->Early.VecAp.Delay.Mask = 0; - state->Early.VecAp.Delay.Line = NULL; - state->Early.VecAp.Coeff = 0.0f; - state->Early.Delay.Mask = 0; - state->Early.Delay.Line = NULL; - for(i = 0;i < NUM_LINES;i++) - { - state->Early.VecAp.Offset[i][0] = 0; - state->Early.VecAp.Offset[i][1] = 0; - state->Early.Offset[i][0] = 0; - state->Early.Offset[i][1] = 0; - state->Early.Coeff[i][0] = 0.0f; - state->Early.Coeff[i][1] = 0.0f; - } - - state->Late.DensityGain[0] = 0.0f; - state->Late.DensityGain[1] = 0.0f; - state->Late.Delay.Mask = 0; - state->Late.Delay.Line = NULL; - state->Late.VecAp.Delay.Mask = 0; - state->Late.VecAp.Delay.Line = NULL; - state->Late.VecAp.Coeff = 0.0f; - for(i = 0;i < NUM_LINES;i++) - { - state->Late.Offset[i][0] = 0; - state->Late.Offset[i][1] = 0; - - state->Late.VecAp.Offset[i][0] = 0; - state->Late.VecAp.Offset[i][1] = 0; - - state->Late.T60[i].MidGain[0] = 0.0f; - state->Late.T60[i].MidGain[1] = 0.0f; - BiquadFilter_clear(&state->Late.T60[i].HFFilter); - BiquadFilter_clear(&state->Late.T60[i].LFFilter); - } - - for(i = 0;i < NUM_LINES;i++) - { - for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - { - state->Early.CurrentGain[i][j] = 0.0f; - state->Early.PanGain[i][j] = 0.0f; - state->Late.CurrentGain[i][j] = 0.0f; - state->Late.PanGain[i][j] = 0.0f; - } - } - - state->FadeCount = 0; - state->MaxUpdate[0] = MAX_UPDATE_SAMPLES; - state->MaxUpdate[1] = MAX_UPDATE_SAMPLES; - state->Offset = 0; -} - -static ALvoid ReverbState_Destruct(ReverbState *State) -{ - al_free(State->SampleBuffer); - State->SampleBuffer = NULL; - - ALeffectState_Destruct(STATIC_CAST(ALeffectState,State)); -} - -/************************************** - * Device Update * - **************************************/ - -static inline ALfloat CalcDelayLengthMult(ALfloat density) -{ - return maxf(5.0f, cbrtf(density*DENSITY_SCALE)); -} - -/* Given the allocated sample buffer, this function updates each delay line - * offset. - */ -static inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLineI *Delay) -{ - union { - ALfloat *f; - ALfloat (*f4)[NUM_LINES]; - } u; - u.f = &sampleBuffer[(ptrdiff_t)Delay->Line * NUM_LINES]; - Delay->Line = u.f4; -} - -/* Calculate the length of a delay line and store its mask and offset. */ -static ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const ALuint frequency, - const ALuint extra, DelayLineI *Delay) -{ - ALuint samples; - - /* All line lengths are powers of 2, calculated from their lengths in - * seconds, rounded up. - */ - samples = float2int(ceilf(length*frequency)); - samples = NextPowerOf2(samples + extra); - - /* All lines share a single sample buffer. */ - Delay->Mask = samples - 1; - Delay->Line = (ALfloat(*)[NUM_LINES])offset; - - /* Return the sample count for accumulation. */ - return samples; -} - -/* Calculates the delay line metrics and allocates the shared sample buffer - * for all lines given the sample rate (frequency). If an allocation failure - * occurs, it returns AL_FALSE. - */ -static ALboolean AllocLines(const ALuint frequency, ReverbState *State) -{ - ALuint totalSamples, i; - ALfloat multiplier, length; - - /* All delay line lengths are calculated to accomodate the full range of - * lengths given their respective paramters. - */ - totalSamples = 0; - - /* Multiplier for the maximum density value, i.e. density=1, which is - * actually the least density... - */ - multiplier = CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY); - - /* The main delay length includes the maximum early reflection delay, the - * largest early tap width, the maximum late reverb delay, and the - * largest late tap width. Finally, it must also be extended by the - * update size (MAX_UPDATE_SAMPLES) for block processing. - */ - length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier + - AL_EAXREVERB_MAX_LATE_REVERB_DELAY + - (LATE_LINE_LENGTHS[NUM_LINES-1] - LATE_LINE_LENGTHS[0])*0.25f*multiplier; - totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES, - &State->Delay); - - /* The early vector all-pass line. */ - length = EARLY_ALLPASS_LENGTHS[NUM_LINES-1] * multiplier; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, - &State->Early.VecAp.Delay); - - /* The early reflection line. */ - length = EARLY_LINE_LENGTHS[NUM_LINES-1] * multiplier; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, - &State->Early.Delay); - - /* The late vector all-pass line. */ - length = LATE_ALLPASS_LENGTHS[NUM_LINES-1] * multiplier; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, - &State->Late.VecAp.Delay); - - /* The late delay lines are calculated from the largest maximum density - * line length. - */ - length = LATE_LINE_LENGTHS[NUM_LINES-1] * multiplier; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, - &State->Late.Delay); - - if(totalSamples != State->TotalSamples) - { - ALfloat *newBuffer; - - TRACE("New reverb buffer length: %ux4 samples\n", totalSamples); - newBuffer = al_calloc(16, sizeof(ALfloat[NUM_LINES]) * totalSamples); - if(!newBuffer) return AL_FALSE; - - al_free(State->SampleBuffer); - State->SampleBuffer = newBuffer; - State->TotalSamples = totalSamples; - } - - /* Update all delays to reflect the new sample buffer. */ - RealizeLineOffset(State->SampleBuffer, &State->Delay); - RealizeLineOffset(State->SampleBuffer, &State->Early.VecAp.Delay); - RealizeLineOffset(State->SampleBuffer, &State->Early.Delay); - RealizeLineOffset(State->SampleBuffer, &State->Late.VecAp.Delay); - RealizeLineOffset(State->SampleBuffer, &State->Late.Delay); - - /* Clear the sample buffer. */ - for(i = 0;i < State->TotalSamples;i++) - State->SampleBuffer[i] = 0.0f; - - return AL_TRUE; -} - -static ALboolean ReverbState_deviceUpdate(ReverbState *State, ALCdevice *Device) -{ - ALuint frequency = Device->Frequency; - ALfloat multiplier; - ALsizei i, j; - - /* Allocate the delay lines. */ - if(!AllocLines(frequency, State)) - return AL_FALSE; - - multiplier = CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY); - - /* The late feed taps are set a fixed position past the latest delay tap. */ - State->LateFeedTap = float2int((AL_EAXREVERB_MAX_REFLECTIONS_DELAY + - EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier) * - frequency); - - /* Clear filters and gain coefficients since the delay lines were all just - * cleared (if not reallocated). - */ - for(i = 0;i < NUM_LINES;i++) - { - BiquadFilter_clear(&State->Filter[i].Lp); - BiquadFilter_clear(&State->Filter[i].Hp); - } - - for(i = 0;i < NUM_LINES;i++) - { - State->EarlyDelayCoeff[i][0] = 0.0f; - State->EarlyDelayCoeff[i][1] = 0.0f; - } - - for(i = 0;i < NUM_LINES;i++) - { - State->Early.Coeff[i][0] = 0.0f; - State->Early.Coeff[i][1] = 0.0f; - } - - State->Late.DensityGain[0] = 0.0f; - State->Late.DensityGain[1] = 0.0f; - for(i = 0;i < NUM_LINES;i++) - { - State->Late.T60[i].MidGain[0] = 0.0f; - State->Late.T60[i].MidGain[1] = 0.0f; - BiquadFilter_clear(&State->Late.T60[i].HFFilter); - BiquadFilter_clear(&State->Late.T60[i].LFFilter); - } - - for(i = 0;i < NUM_LINES;i++) - { - for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - { - State->Early.CurrentGain[i][j] = 0.0f; - State->Early.PanGain[i][j] = 0.0f; - State->Late.CurrentGain[i][j] = 0.0f; - State->Late.PanGain[i][j] = 0.0f; - } - } - - /* Reset counters and offset base. */ - State->FadeCount = 0; - State->MaxUpdate[0] = MAX_UPDATE_SAMPLES; - State->MaxUpdate[1] = MAX_UPDATE_SAMPLES; - State->Offset = 0; - - return AL_TRUE; -} - -/************************************** - * Effect Update * - **************************************/ - -/* Calculate a decay coefficient given the length of each cycle and the time - * until the decay reaches -60 dB. - */ -static inline ALfloat CalcDecayCoeff(const ALfloat length, const ALfloat decayTime) -{ - return powf(REVERB_DECAY_GAIN, length/decayTime); -} - -/* Calculate a decay length from a coefficient and the time until the decay - * reaches -60 dB. - */ -static inline ALfloat CalcDecayLength(const ALfloat coeff, const ALfloat decayTime) -{ - return log10f(coeff) * decayTime / log10f(REVERB_DECAY_GAIN); -} - -/* Calculate an attenuation to be applied to the input of any echo models to - * compensate for modal density and decay time. - */ -static inline ALfloat CalcDensityGain(const ALfloat a) -{ - /* The energy of a signal can be obtained by finding the area under the - * squared signal. This takes the form of Sum(x_n^2), where x is the - * amplitude for the sample n. - * - * Decaying feedback matches exponential decay of the form Sum(a^n), - * where a is the attenuation coefficient, and n is the sample. The area - * under this decay curve can be calculated as: 1 / (1 - a). - * - * Modifying the above equation to find the area under the squared curve - * (for energy) yields: 1 / (1 - a^2). Input attenuation can then be - * calculated by inverting the square root of this approximation, - * yielding: 1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2). - */ - return sqrtf(1.0f - a*a); -} - -/* Calculate the scattering matrix coefficients given a diffusion factor. */ -static inline ALvoid CalcMatrixCoeffs(const ALfloat diffusion, ALfloat *x, ALfloat *y) -{ - ALfloat n, t; - - /* The matrix is of order 4, so n is sqrt(4 - 1). */ - n = sqrtf(3.0f); - t = diffusion * atanf(n); - - /* Calculate the first mixing matrix coefficient. */ - *x = cosf(t); - /* Calculate the second mixing matrix coefficient. */ - *y = sinf(t) / n; -} - -/* Calculate the limited HF ratio for use with the late reverb low-pass - * filters. - */ -static ALfloat CalcLimitedHfRatio(const ALfloat hfRatio, const ALfloat airAbsorptionGainHF, - const ALfloat decayTime, const ALfloat SpeedOfSound) -{ - ALfloat limitRatio; - - /* Find the attenuation due to air absorption in dB (converting delay - * time to meters using the speed of sound). Then reversing the decay - * equation, solve for HF ratio. The delay length is cancelled out of - * the equation, so it can be calculated once for all lines. - */ - limitRatio = 1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) * SpeedOfSound); - - /* Using the limit calculated above, apply the upper bound to the HF ratio. - */ - return minf(limitRatio, hfRatio); -} - - -/* Calculates the 3-band T60 damping coefficients for a particular delay line - * of specified length, using a combination of two shelf filter sections given - * decay times for each band split at two reference frequencies. - */ -static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime, - const ALfloat mfDecayTime, const ALfloat hfDecayTime, - const ALfloat lf0norm, const ALfloat hf0norm, - T60Filter *filter) -{ - ALfloat lfGain = CalcDecayCoeff(length, lfDecayTime); - ALfloat mfGain = CalcDecayCoeff(length, mfDecayTime); - ALfloat hfGain = CalcDecayCoeff(length, hfDecayTime); - - filter->MidGain[1] = mfGain; - BiquadFilter_setParams(&filter->LFFilter, BiquadType_LowShelf, lfGain/mfGain, lf0norm, - calc_rcpQ_from_slope(lfGain/mfGain, 1.0f)); - BiquadFilter_setParams(&filter->HFFilter, BiquadType_HighShelf, hfGain/mfGain, hf0norm, - calc_rcpQ_from_slope(hfGain/mfGain, 1.0f)); -} - -/* Update the offsets for the main effect delay line. */ -static ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, const ALfloat density, const ALfloat decayTime, const ALuint frequency, ReverbState *State) -{ - ALfloat multiplier, length; - ALuint i; - - multiplier = CalcDelayLengthMult(density); - - /* Early reflection taps are decorrelated by means of an average room - * reflection approximation described above the definition of the taps. - * This approximation is linear and so the above density multiplier can - * be applied to adjust the width of the taps. A single-band decay - * coefficient is applied to simulate initial attenuation and absorption. - * - * Late reverb taps are based on the late line lengths to allow a zero- - * delay path and offsets that would continue the propagation naturally - * into the late lines. - */ - for(i = 0;i < NUM_LINES;i++) - { - length = earlyDelay + EARLY_TAP_LENGTHS[i]*multiplier; - State->EarlyDelayTap[i][1] = float2int(length * frequency); - - length = EARLY_TAP_LENGTHS[i]*multiplier; - State->EarlyDelayCoeff[i][1] = CalcDecayCoeff(length, decayTime); - - length = lateDelay + (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS[0])*0.25f*multiplier; - State->LateDelayTap[i][1] = State->LateFeedTap + float2int(length * frequency); - } -} - -/* Update the early reflection line lengths and gain coefficients. */ -static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat diffusion, const ALfloat decayTime, const ALuint frequency, EarlyReflections *Early) -{ - ALfloat multiplier, length; - ALsizei i; - - multiplier = CalcDelayLengthMult(density); - - /* Calculate the all-pass feed-back/forward coefficient. */ - Early->VecAp.Coeff = sqrtf(0.5f) * powf(diffusion, 2.0f); - - for(i = 0;i < NUM_LINES;i++) - { - /* Calculate the length (in seconds) of each all-pass line. */ - length = EARLY_ALLPASS_LENGTHS[i] * multiplier; - - /* Calculate the delay offset for each all-pass line. */ - Early->VecAp.Offset[i][1] = float2int(length * frequency); - - /* Calculate the length (in seconds) of each delay line. */ - length = EARLY_LINE_LENGTHS[i] * multiplier; - - /* Calculate the delay offset for each delay line. */ - Early->Offset[i][1] = float2int(length * frequency); - - /* Calculate the gain (coefficient) for each line. */ - Early->Coeff[i][1] = CalcDecayCoeff(length, decayTime); - } -} - -/* Update the late reverb line lengths and T60 coefficients. */ -static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lf0norm, const ALfloat hf0norm, const ALuint frequency, LateReverb *Late) -{ - /* Scaling factor to convert the normalized reference frequencies from - * representing 0...freq to 0...max_reference. - */ - const ALfloat norm_weight_factor = (ALfloat)frequency / AL_EAXREVERB_MAX_HFREFERENCE; - ALfloat multiplier, length, bandWeights[3]; - ALsizei i; - - /* To compensate for changes in modal density and decay time of the late - * reverb signal, the input is attenuated based on the maximal energy of - * the outgoing signal. This approximation is used to keep the apparent - * energy of the signal equal for all ranges of density and decay time. - * - * The average length of the delay lines is used to calculate the - * attenuation coefficient. - */ - multiplier = CalcDelayLengthMult(density); - length = (LATE_LINE_LENGTHS[0] + LATE_LINE_LENGTHS[1] + - LATE_LINE_LENGTHS[2] + LATE_LINE_LENGTHS[3]) / 4.0f * multiplier; - length += (LATE_ALLPASS_LENGTHS[0] + LATE_ALLPASS_LENGTHS[1] + - LATE_ALLPASS_LENGTHS[2] + LATE_ALLPASS_LENGTHS[3]) / 4.0f * multiplier; - /* The density gain calculation uses an average decay time weighted by - * approximate bandwidth. This attempts to compensate for losses of energy - * that reduce decay time due to scattering into highly attenuated bands. - */ - bandWeights[0] = lf0norm*norm_weight_factor; - bandWeights[1] = hf0norm*norm_weight_factor - lf0norm*norm_weight_factor; - bandWeights[2] = 1.0f - hf0norm*norm_weight_factor; - Late->DensityGain[1] = CalcDensityGain( - CalcDecayCoeff(length, - bandWeights[0]*lfDecayTime + bandWeights[1]*mfDecayTime + bandWeights[2]*hfDecayTime - ) - ); - - /* Calculate the all-pass feed-back/forward coefficient. */ - Late->VecAp.Coeff = sqrtf(0.5f) * powf(diffusion, 2.0f); - - for(i = 0;i < NUM_LINES;i++) - { - /* Calculate the length (in seconds) of each all-pass line. */ - length = LATE_ALLPASS_LENGTHS[i] * multiplier; - - /* Calculate the delay offset for each all-pass line. */ - Late->VecAp.Offset[i][1] = float2int(length * frequency); - - /* Calculate the length (in seconds) of each delay line. */ - length = LATE_LINE_LENGTHS[i] * multiplier; - - /* Calculate the delay offset for each delay line. */ - Late->Offset[i][1] = float2int(length*frequency + 0.5f); - - /* Approximate the absorption that the vector all-pass would exhibit - * given the current diffusion so we don't have to process a full T60 - * filter for each of its four lines. - */ - length += lerp(LATE_ALLPASS_LENGTHS[i], - (LATE_ALLPASS_LENGTHS[0] + LATE_ALLPASS_LENGTHS[1] + - LATE_ALLPASS_LENGTHS[2] + LATE_ALLPASS_LENGTHS[3]) / 4.0f, - diffusion) * multiplier; - - /* Calculate the T60 damping coefficients for each line. */ - CalcT60DampingCoeffs(length, lfDecayTime, mfDecayTime, hfDecayTime, - lf0norm, hf0norm, &Late->T60[i]); - } -} - -/* Creates a transform matrix given a reverb vector. The vector pans the reverb - * reflections toward the given direction, using its magnitude (up to 1) as a - * focal strength. This function results in a B-Format transformation matrix - * that spatially focuses the signal in the desired direction. - */ -static aluMatrixf GetTransformFromVector(const ALfloat *vec) -{ - aluMatrixf focus; - ALfloat norm[3]; - ALfloat mag; - - /* Normalize the panning vector according to the N3D scale, which has an - * extra sqrt(3) term on the directional components. Converting from OpenAL - * to B-Format also requires negating X (ACN 1) and Z (ACN 3). Note however - * that the reverb panning vectors use left-handed coordinates, unlike the - * rest of OpenAL which use right-handed. This is fixed by negating Z, - * which cancels out with the B-Format Z negation. - */ - mag = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); - if(mag > 1.0f) - { - norm[0] = vec[0] / mag * -SQRTF_3; - norm[1] = vec[1] / mag * SQRTF_3; - norm[2] = vec[2] / mag * SQRTF_3; - mag = 1.0f; - } - else - { - /* If the magnitude is less than or equal to 1, just apply the sqrt(3) - * term. There's no need to renormalize the magnitude since it would - * just be reapplied in the matrix. - */ - norm[0] = vec[0] * -SQRTF_3; - norm[1] = vec[1] * SQRTF_3; - norm[2] = vec[2] * SQRTF_3; - } - - aluMatrixfSet(&focus, - 1.0f, 0.0f, 0.0f, 0.0f, - norm[0], 1.0f-mag, 0.0f, 0.0f, - norm[1], 0.0f, 1.0f-mag, 0.0f, - norm[2], 0.0f, 0.0f, 1.0f-mag - ); - - return focus; -} - -/* Update the early and late 3D panning gains. */ -static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, const ALfloat earlyGain, const ALfloat lateGain, ReverbState *State) -{ - aluMatrixf transform, rot; - ALsizei i; - - STATIC_CAST(ALeffectState,State)->OutBuffer = Device->FOAOut.Buffer; - STATIC_CAST(ALeffectState,State)->OutChannels = Device->FOAOut.NumChannels; - - /* Note: _res is transposed. */ -#define MATRIX_MULT(_res, _m1, _m2) do { \ - int row, col; \ - for(col = 0;col < 4;col++) \ - { \ - for(row = 0;row < 4;row++) \ - _res.m[col][row] = _m1.m[row][0]*_m2.m[0][col] + _m1.m[row][1]*_m2.m[1][col] + \ - _m1.m[row][2]*_m2.m[2][col] + _m1.m[row][3]*_m2.m[3][col]; \ - } \ -} while(0) - /* Create a matrix that first converts A-Format to B-Format, then - * transforms the B-Format signal according to the panning vector. - */ - rot = GetTransformFromVector(ReflectionsPan); - MATRIX_MULT(transform, rot, A2B); - memset(&State->Early.PanGain, 0, sizeof(State->Early.PanGain)); - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&Device->FOAOut, transform.m[i], earlyGain, - State->Early.PanGain[i]); - - rot = GetTransformFromVector(LateReverbPan); - MATRIX_MULT(transform, rot, A2B); - memset(&State->Late.PanGain, 0, sizeof(State->Late.PanGain)); - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&Device->FOAOut, transform.m[i], lateGain, - State->Late.PanGain[i]); -#undef MATRIX_MULT -} - -static void ReverbState_update(ReverbState *State, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) -{ - const ALCdevice *Device = Context->Device; - const ALlistener *Listener = Context->Listener; - ALuint frequency = Device->Frequency; - ALfloat lf0norm, hf0norm, hfRatio; - ALfloat lfDecayTime, hfDecayTime; - ALfloat gain, gainlf, gainhf; - ALsizei i; - - /* Calculate the master filters */ - hf0norm = minf(props->Reverb.HFReference / frequency, 0.49f); - /* Restrict the filter gains from going below -60dB to keep the filter from - * killing most of the signal. - */ - gainhf = maxf(props->Reverb.GainHF, 0.001f); - BiquadFilter_setParams(&State->Filter[0].Lp, BiquadType_HighShelf, gainhf, hf0norm, - calc_rcpQ_from_slope(gainhf, 1.0f)); - lf0norm = minf(props->Reverb.LFReference / frequency, 0.49f); - gainlf = maxf(props->Reverb.GainLF, 0.001f); - BiquadFilter_setParams(&State->Filter[0].Hp, BiquadType_LowShelf, gainlf, lf0norm, - calc_rcpQ_from_slope(gainlf, 1.0f)); - for(i = 1;i < NUM_LINES;i++) - { - BiquadFilter_copyParams(&State->Filter[i].Lp, &State->Filter[0].Lp); - BiquadFilter_copyParams(&State->Filter[i].Hp, &State->Filter[0].Hp); - } - - /* Update the main effect delay and associated taps. */ - UpdateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay, - props->Reverb.Density, props->Reverb.DecayTime, frequency, - State); - - /* Update the early lines. */ - UpdateEarlyLines(props->Reverb.Density, props->Reverb.Diffusion, - props->Reverb.DecayTime, frequency, &State->Early); - - /* Get the mixing matrix coefficients. */ - CalcMatrixCoeffs(props->Reverb.Diffusion, &State->MixX, &State->MixY); - - /* If the HF limit parameter is flagged, calculate an appropriate limit - * based on the air absorption parameter. - */ - hfRatio = props->Reverb.DecayHFRatio; - if(props->Reverb.DecayHFLimit && props->Reverb.AirAbsorptionGainHF < 1.0f) - hfRatio = CalcLimitedHfRatio(hfRatio, props->Reverb.AirAbsorptionGainHF, - props->Reverb.DecayTime, Listener->Params.ReverbSpeedOfSound - ); - - /* Calculate the LF/HF decay times. */ - lfDecayTime = clampf(props->Reverb.DecayTime * props->Reverb.DecayLFRatio, - AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME); - hfDecayTime = clampf(props->Reverb.DecayTime * hfRatio, - AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME); - - /* Update the late lines. */ - UpdateLateLines(props->Reverb.Density, props->Reverb.Diffusion, - lfDecayTime, props->Reverb.DecayTime, hfDecayTime, lf0norm, hf0norm, - frequency, &State->Late - ); - - /* Update early and late 3D panning. */ - gain = props->Reverb.Gain * Slot->Params.Gain * ReverbBoost; - Update3DPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, - props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain, - State); - - /* Calculate the max update size from the smallest relevant delay. */ - State->MaxUpdate[1] = mini(MAX_UPDATE_SAMPLES, - mini(State->Early.Offset[0][1], State->Late.Offset[0][1]) - ); - - /* Determine if delay-line cross-fading is required. Density is essentially - * a master control for the feedback delays, so changes the offsets of many - * delay lines. - */ - if(State->Params.Density != props->Reverb.Density || - /* Diffusion and decay times influences the decay rate (gain) of the - * late reverb T60 filter. - */ - State->Params.Diffusion != props->Reverb.Diffusion || - State->Params.DecayTime != props->Reverb.DecayTime || - State->Params.HFDecayTime != hfDecayTime || - State->Params.LFDecayTime != lfDecayTime || - /* HF/LF References control the weighting used to calculate the density - * gain. - */ - State->Params.HFReference != props->Reverb.HFReference || - State->Params.LFReference != props->Reverb.LFReference) - State->FadeCount = 0; - State->Params.Density = props->Reverb.Density; - State->Params.Diffusion = props->Reverb.Diffusion; - State->Params.DecayTime = props->Reverb.DecayTime; - State->Params.HFDecayTime = hfDecayTime; - State->Params.LFDecayTime = lfDecayTime; - State->Params.HFReference = props->Reverb.HFReference; - State->Params.LFReference = props->Reverb.LFReference; -} - - -/************************************** - * Effect Processing * - **************************************/ - -/* Basic delay line input/output routines. */ -static inline ALfloat DelayLineOut(const DelayLineI *Delay, const ALsizei offset, const ALsizei c) -{ - return Delay->Line[offset&Delay->Mask][c]; -} - -/* Cross-faded delay line output routine. Instead of interpolating the - * offsets, this interpolates (cross-fades) the outputs at each offset. - */ -static inline ALfloat FadedDelayLineOut(const DelayLineI *Delay, const ALsizei off0, - const ALsizei off1, const ALsizei c, - const ALfloat sc0, const ALfloat sc1) -{ - return Delay->Line[off0&Delay->Mask][c]*sc0 + - Delay->Line[off1&Delay->Mask][c]*sc1; -} - - -static inline void DelayLineIn(const DelayLineI *Delay, ALsizei offset, const ALsizei c, - const ALfloat *RESTRICT in, ALsizei count) -{ - ALsizei i; - for(i = 0;i < count;i++) - Delay->Line[(offset++)&Delay->Mask][c] = *(in++); -} - -/* Applies a scattering matrix to the 4-line (vector) input. This is used - * for both the below vector all-pass model and to perform modal feed-back - * delay network (FDN) mixing. - * - * The matrix is derived from a skew-symmetric matrix to form a 4D rotation - * matrix with a single unitary rotational parameter: - * - * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2 - * [ -a, d, c, -b ] - * [ -b, -c, d, a ] - * [ -c, b, -a, d ] - * - * The rotation is constructed from the effect's diffusion parameter, - * yielding: - * - * 1 = x^2 + 3 y^2 - * - * Where a, b, and c are the coefficient y with differing signs, and d is the - * coefficient x. The final matrix is thus: - * - * [ x, y, -y, y ] n = sqrt(matrix_order - 1) - * [ -y, x, y, y ] t = diffusion_parameter * atan(n) - * [ y, -y, x, y ] x = cos(t) - * [ -y, -y, -y, x ] y = sin(t) / n - * - * Any square orthogonal matrix with an order that is a power of two will - * work (where ^T is transpose, ^-1 is inverse): - * - * M^T = M^-1 - * - * Using that knowledge, finding an appropriate matrix can be accomplished - * naively by searching all combinations of: - * - * M = D + S - S^T - * - * Where D is a diagonal matrix (of x), and S is a triangular matrix (of y) - * whose combination of signs are being iterated. - */ -static inline void VectorPartialScatter(ALfloat *RESTRICT out, const ALfloat *RESTRICT in, - const ALfloat xCoeff, const ALfloat yCoeff) -{ - out[0] = xCoeff*in[0] + yCoeff*( in[1] + -in[2] + in[3]); - out[1] = xCoeff*in[1] + yCoeff*(-in[0] + in[2] + in[3]); - out[2] = xCoeff*in[2] + yCoeff*( in[0] + -in[1] + in[3]); - out[3] = xCoeff*in[3] + yCoeff*(-in[0] + -in[1] + -in[2] ); -} -#define VectorScatterDelayIn(delay, o, in, xcoeff, ycoeff) \ - VectorPartialScatter((delay)->Line[(o)&(delay)->Mask], in, xcoeff, ycoeff) - -/* Utilizes the above, but reverses the input channels. */ -static inline void VectorScatterRevDelayIn(const DelayLineI *Delay, ALint offset, - const ALfloat xCoeff, const ALfloat yCoeff, - const ALfloat (*RESTRICT in)[MAX_UPDATE_SAMPLES], - const ALsizei count) -{ - const DelayLineI delay = *Delay; - ALsizei i, j; - - for(i = 0;i < count;++i) - { - ALfloat f[NUM_LINES]; - for(j = 0;j < NUM_LINES;j++) - f[NUM_LINES-1-j] = in[j][i]; - - VectorScatterDelayIn(&delay, offset++, f, xCoeff, yCoeff); - } -} - -/* This applies a Gerzon multiple-in/multiple-out (MIMO) vector all-pass - * filter to the 4-line input. - * - * It works by vectorizing a regular all-pass filter and replacing the delay - * element with a scattering matrix (like the one above) and a diagonal - * matrix of delay elements. - * - * Two static specializations are used for transitional (cross-faded) delay - * line processing and non-transitional processing. - */ -static void VectorAllpass_Unfaded(ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES], ALsizei offset, - const ALfloat xCoeff, const ALfloat yCoeff, ALsizei todo, - VecAllpass *Vap) -{ - const DelayLineI delay = Vap->Delay; - const ALfloat feedCoeff = Vap->Coeff; - ALsizei vap_offset[NUM_LINES]; - ALsizei i, j; - - ASSUME(todo > 0); - - for(j = 0;j < NUM_LINES;j++) - vap_offset[j] = offset-Vap->Offset[j][0]; - for(i = 0;i < todo;i++) - { - ALfloat f[NUM_LINES]; - - for(j = 0;j < NUM_LINES;j++) - { - ALfloat input = samples[j][i]; - ALfloat out = DelayLineOut(&delay, vap_offset[j]++, j) - feedCoeff*input; - f[j] = input + feedCoeff*out; - - samples[j][i] = out; - } - - VectorScatterDelayIn(&delay, offset, f, xCoeff, yCoeff); - ++offset; - } -} -static void VectorAllpass_Faded(ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES], ALsizei offset, - const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, - ALsizei todo, VecAllpass *Vap) -{ - const DelayLineI delay = Vap->Delay; - const ALfloat feedCoeff = Vap->Coeff; - ALsizei vap_offset[NUM_LINES][2]; - ALsizei i, j; - - ASSUME(todo > 0); - - fade *= 1.0f/FADE_SAMPLES; - for(j = 0;j < NUM_LINES;j++) - { - vap_offset[j][0] = offset-Vap->Offset[j][0]; - vap_offset[j][1] = offset-Vap->Offset[j][1]; - } - for(i = 0;i < todo;i++) - { - ALfloat f[NUM_LINES]; - - for(j = 0;j < NUM_LINES;j++) - { - ALfloat input = samples[j][i]; - ALfloat out = - FadedDelayLineOut(&delay, vap_offset[j][0]++, vap_offset[j][1]++, j, - 1.0f-fade, fade - ) - feedCoeff*input; - f[j] = input + feedCoeff*out; - - samples[j][i] = out; - } - fade += FadeStep; - - VectorScatterDelayIn(&delay, offset, f, xCoeff, yCoeff); - ++offset; - } -} - -/* This generates early reflections. - * - * This is done by obtaining the primary reflections (those arriving from the - * same direction as the source) from the main delay line. These are - * attenuated and all-pass filtered (based on the diffusion parameter). - * - * The early lines are then fed in reverse (according to the approximately - * opposite spatial location of the A-Format lines) to create the secondary - * reflections (those arriving from the opposite direction as the source). - * - * The early response is then completed by combining the primary reflections - * with the delayed and attenuated output from the early lines. - * - * Finally, the early response is reversed, scattered (based on diffusion), - * and fed into the late reverb section of the main delay line. - * - * Two static specializations are used for transitional (cross-faded) delay - * line processing and non-transitional processing. - */ -static void EarlyReflection_Unfaded(ReverbState *State, ALsizei offset, const ALsizei todo, - ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) -{ - ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; - const DelayLineI early_delay = State->Early.Delay; - const DelayLineI main_delay = State->Delay; - const ALfloat mixX = State->MixX; - const ALfloat mixY = State->MixY; - ALsizei late_feed_tap; - ALsizei i, j; - - ASSUME(todo > 0); - - /* First, load decorrelated samples from the main delay line as the primary - * reflections. - */ - for(j = 0;j < NUM_LINES;j++) - { - ALsizei early_delay_tap = offset - State->EarlyDelayTap[j][0]; - ALfloat coeff = State->EarlyDelayCoeff[j][0]; - for(i = 0;i < todo;i++) - temps[j][i] = DelayLineOut(&main_delay, early_delay_tap++, j) * coeff; - } - - /* Apply a vector all-pass, to help color the initial reflections based on - * the diffusion strength. - */ - VectorAllpass_Unfaded(temps, offset, mixX, mixY, todo, &State->Early.VecAp); - - /* Apply a delay and bounce to generate secondary reflections, combine with - * the primary reflections and write out the result for mixing. - */ - for(j = 0;j < NUM_LINES;j++) - { - ALint early_feedb_tap = offset - State->Early.Offset[j][0]; - ALfloat early_feedb_coeff = State->Early.Coeff[j][0]; - - for(i = 0;i < todo;i++) - out[j][i] = DelayLineOut(&early_delay, early_feedb_tap++, j)*early_feedb_coeff + - temps[j][i]; - } - for(j = 0;j < NUM_LINES;j++) - DelayLineIn(&early_delay, offset, NUM_LINES-1-j, temps[j], todo); - - /* Also write the result back to the main delay line for the late reverb - * stage to pick up at the appropriate time, appplying a scatter and - * bounce to improve the initial diffusion in the late reverb. - */ - late_feed_tap = offset - State->LateFeedTap; - VectorScatterRevDelayIn(&main_delay, late_feed_tap, mixX, mixY, out, todo); -} -static void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsizei todo, - const ALfloat fade, ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) -{ - ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; - const DelayLineI early_delay = State->Early.Delay; - const DelayLineI main_delay = State->Delay; - const ALfloat mixX = State->MixX; - const ALfloat mixY = State->MixY; - ALsizei late_feed_tap; - ALsizei i, j; - - ASSUME(todo > 0); - - for(j = 0;j < NUM_LINES;j++) - { - ALsizei early_delay_tap0 = offset - State->EarlyDelayTap[j][0]; - ALsizei early_delay_tap1 = offset - State->EarlyDelayTap[j][1]; - ALfloat oldCoeff = State->EarlyDelayCoeff[j][0]; - ALfloat oldCoeffStep = -oldCoeff / FADE_SAMPLES; - ALfloat newCoeffStep = State->EarlyDelayCoeff[j][1] / FADE_SAMPLES; - ALfloat fadeCount = fade; - - for(i = 0;i < todo;i++) - { - const ALfloat fade0 = oldCoeff + oldCoeffStep*fadeCount; - const ALfloat fade1 = newCoeffStep*fadeCount; - temps[j][i] = FadedDelayLineOut(&main_delay, - early_delay_tap0++, early_delay_tap1++, j, fade0, fade1 - ); - fadeCount += 1.0f; - } - } - - VectorAllpass_Faded(temps, offset, mixX, mixY, fade, todo, &State->Early.VecAp); - - for(j = 0;j < NUM_LINES;j++) - { - ALint feedb_tap0 = offset - State->Early.Offset[j][0]; - ALint feedb_tap1 = offset - State->Early.Offset[j][1]; - ALfloat feedb_oldCoeff = State->Early.Coeff[j][0]; - ALfloat feedb_oldCoeffStep = -feedb_oldCoeff / FADE_SAMPLES; - ALfloat feedb_newCoeffStep = State->Early.Coeff[j][1] / FADE_SAMPLES; - ALfloat fadeCount = fade; - - for(i = 0;i < todo;i++) - { - const ALfloat fade0 = feedb_oldCoeff + feedb_oldCoeffStep*fadeCount; - const ALfloat fade1 = feedb_newCoeffStep*fadeCount; - out[j][i] = FadedDelayLineOut(&early_delay, - feedb_tap0++, feedb_tap1++, j, fade0, fade1 - ) + temps[j][i]; - fadeCount += 1.0f; - } - } - for(j = 0;j < NUM_LINES;j++) - DelayLineIn(&early_delay, offset, NUM_LINES-1-j, temps[j], todo); - - late_feed_tap = offset - State->LateFeedTap; - VectorScatterRevDelayIn(&main_delay, late_feed_tap, mixX, mixY, out, todo); -} - -/* Applies the two T60 damping filter sections. */ -static inline void LateT60Filter(ALfloat *RESTRICT samples, const ALsizei todo, T60Filter *filter) -{ - ALfloat temp[MAX_UPDATE_SAMPLES]; - BiquadFilter_process(&filter->HFFilter, temp, samples, todo); - BiquadFilter_process(&filter->LFFilter, samples, temp, todo); -} - -/* This generates the reverb tail using a modified feed-back delay network - * (FDN). - * - * Results from the early reflections are mixed with the output from the late - * delay lines. - * - * The late response is then completed by T60 and all-pass filtering the mix. - * - * Finally, the lines are reversed (so they feed their opposite directions) - * and scattered with the FDN matrix before re-feeding the delay lines. - * - * Two variations are made, one for for transitional (cross-faded) delay line - * processing and one for non-transitional processing. - */ -static void LateReverb_Unfaded(ReverbState *State, ALsizei offset, const ALsizei todo, - ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) -{ - ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; - const DelayLineI late_delay = State->Late.Delay; - const DelayLineI main_delay = State->Delay; - const ALfloat mixX = State->MixX; - const ALfloat mixY = State->MixY; - ALsizei i, j; - - ASSUME(todo > 0); - - /* First, load decorrelated samples from the main and feedback delay lines. - * Filter the signal to apply its frequency-dependent decay. - */ - for(j = 0;j < NUM_LINES;j++) - { - ALsizei late_delay_tap = offset - State->LateDelayTap[j][0]; - ALsizei late_feedb_tap = offset - State->Late.Offset[j][0]; - ALfloat midGain = State->Late.T60[j].MidGain[0]; - const ALfloat densityGain = State->Late.DensityGain[0] * midGain; - for(i = 0;i < todo;i++) - temps[j][i] = DelayLineOut(&main_delay, late_delay_tap++, j)*densityGain + - DelayLineOut(&late_delay, late_feedb_tap++, j)*midGain; - LateT60Filter(temps[j], todo, &State->Late.T60[j]); - } - - /* Apply a vector all-pass to improve micro-surface diffusion, and write - * out the results for mixing. - */ - VectorAllpass_Unfaded(temps, offset, mixX, mixY, todo, &State->Late.VecAp); - - for(j = 0;j < NUM_LINES;j++) - memcpy(out[j], temps[j], todo*sizeof(ALfloat)); - - /* Finally, scatter and bounce the results to refeed the feedback buffer. */ - VectorScatterRevDelayIn(&late_delay, offset, mixX, mixY, out, todo); -} -static void LateReverb_Faded(ReverbState *State, ALsizei offset, const ALsizei todo, - const ALfloat fade, ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) -{ - ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; - const DelayLineI late_delay = State->Late.Delay; - const DelayLineI main_delay = State->Delay; - const ALfloat mixX = State->MixX; - const ALfloat mixY = State->MixY; - ALsizei i, j; - - ASSUME(todo > 0); - - for(j = 0;j < NUM_LINES;j++) - { - const ALfloat oldMidGain = State->Late.T60[j].MidGain[0]; - const ALfloat midGain = State->Late.T60[j].MidGain[1]; - const ALfloat oldMidStep = -oldMidGain / FADE_SAMPLES; - const ALfloat midStep = midGain / FADE_SAMPLES; - const ALfloat oldDensityGain = State->Late.DensityGain[0] * oldMidGain; - const ALfloat densityGain = State->Late.DensityGain[1] * midGain; - const ALfloat oldDensityStep = -oldDensityGain / FADE_SAMPLES; - const ALfloat densityStep = densityGain / FADE_SAMPLES; - ALsizei late_delay_tap0 = offset - State->LateDelayTap[j][0]; - ALsizei late_delay_tap1 = offset - State->LateDelayTap[j][1]; - ALsizei late_feedb_tap0 = offset - State->Late.Offset[j][0]; - ALsizei late_feedb_tap1 = offset - State->Late.Offset[j][1]; - ALfloat fadeCount = fade; - - for(i = 0;i < todo;i++) - { - const ALfloat fade0 = oldDensityGain + oldDensityStep*fadeCount; - const ALfloat fade1 = densityStep*fadeCount; - const ALfloat gfade0 = oldMidGain + oldMidStep*fadeCount; - const ALfloat gfade1 = midStep*fadeCount; - temps[j][i] = - FadedDelayLineOut(&main_delay, late_delay_tap0++, late_delay_tap1++, j, - fade0, fade1) + - FadedDelayLineOut(&late_delay, late_feedb_tap0++, late_feedb_tap1++, j, - gfade0, gfade1); - fadeCount += 1.0f; - } - LateT60Filter(temps[j], todo, &State->Late.T60[j]); - } - - VectorAllpass_Faded(temps, offset, mixX, mixY, fade, todo, &State->Late.VecAp); - - for(j = 0;j < NUM_LINES;j++) - memcpy(out[j], temps[j], todo*sizeof(ALfloat)); - - VectorScatterRevDelayIn(&late_delay, offset, mixX, mixY, temps, todo); -} - -static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) -{ - ALfloat (*RESTRICT afmt)[MAX_UPDATE_SAMPLES] = State->TempSamples; - ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES] = State->MixSamples; - ALsizei fadeCount = State->FadeCount; - ALsizei offset = State->Offset; - ALsizei base, c; - - /* Process reverb for these samples. */ - for(base = 0;base < SamplesToDo;) - { - ALsizei todo = SamplesToDo - base; - /* If cross-fading, don't do more samples than there are to fade. */ - if(FADE_SAMPLES-fadeCount > 0) - { - todo = mini(todo, FADE_SAMPLES-fadeCount); - todo = mini(todo, State->MaxUpdate[0]); - } - todo = mini(todo, State->MaxUpdate[1]); - /* If this is not the final update, ensure the update size is a - * multiple of 4 for the SIMD mixers. - */ - if(todo < SamplesToDo-base) - todo &= ~3; - - /* Convert B-Format to A-Format for processing. */ - memset(afmt, 0, sizeof(*afmt)*NUM_LINES); - for(c = 0;c < NUM_LINES;c++) - MixRowSamples(afmt[c], B2A.m[c], - SamplesIn, MAX_EFFECT_CHANNELS, base, todo - ); - - /* Process the samples for reverb. */ - for(c = 0;c < NUM_LINES;c++) - { - /* Band-pass the incoming samples. */ - BiquadFilter_process(&State->Filter[c].Lp, samples[0], afmt[c], todo); - BiquadFilter_process(&State->Filter[c].Hp, samples[1], samples[0], todo); - - /* Feed the initial delay line. */ - DelayLineIn(&State->Delay, offset, c, samples[1], todo); - } - - if(UNLIKELY(fadeCount < FADE_SAMPLES)) - { - ALfloat fade = (ALfloat)fadeCount; - - /* Generate early reflections. */ - EarlyReflection_Faded(State, offset, todo, fade, samples); - /* Mix the A-Format results to output, implicitly converting back - * to B-Format. - */ - for(c = 0;c < NUM_LINES;c++) - MixSamples(samples[c], NumChannels, SamplesOut, - State->Early.CurrentGain[c], State->Early.PanGain[c], - SamplesToDo-base, base, todo - ); - - /* Generate and mix late reverb. */ - LateReverb_Faded(State, offset, todo, fade, samples); - for(c = 0;c < NUM_LINES;c++) - MixSamples(samples[c], NumChannels, SamplesOut, - State->Late.CurrentGain[c], State->Late.PanGain[c], - SamplesToDo-base, base, todo - ); - - /* Step fading forward. */ - fadeCount += todo; - if(LIKELY(fadeCount >= FADE_SAMPLES)) - { - /* Update the cross-fading delay line taps. */ - fadeCount = FADE_SAMPLES; - for(c = 0;c < NUM_LINES;c++) - { - State->EarlyDelayTap[c][0] = State->EarlyDelayTap[c][1]; - State->EarlyDelayCoeff[c][0] = State->EarlyDelayCoeff[c][1]; - State->Early.VecAp.Offset[c][0] = State->Early.VecAp.Offset[c][1]; - State->Early.Offset[c][0] = State->Early.Offset[c][1]; - State->Early.Coeff[c][0] = State->Early.Coeff[c][1]; - State->LateDelayTap[c][0] = State->LateDelayTap[c][1]; - State->Late.VecAp.Offset[c][0] = State->Late.VecAp.Offset[c][1]; - State->Late.Offset[c][0] = State->Late.Offset[c][1]; - State->Late.T60[c].MidGain[0] = State->Late.T60[c].MidGain[1]; - } - State->Late.DensityGain[0] = State->Late.DensityGain[1]; - State->MaxUpdate[0] = State->MaxUpdate[1]; - } - } - else - { - /* Generate and mix early reflections. */ - EarlyReflection_Unfaded(State, offset, todo, samples); - for(c = 0;c < NUM_LINES;c++) - MixSamples(samples[c], NumChannels, SamplesOut, - State->Early.CurrentGain[c], State->Early.PanGain[c], - SamplesToDo-base, base, todo - ); - - /* Generate and mix late reverb. */ - LateReverb_Unfaded(State, offset, todo, samples); - for(c = 0;c < NUM_LINES;c++) - MixSamples(samples[c], NumChannels, SamplesOut, - State->Late.CurrentGain[c], State->Late.PanGain[c], - SamplesToDo-base, base, todo - ); - } - - /* Step all delays forward. */ - offset += todo; - - base += todo; - } - State->Offset = offset; - State->FadeCount = fadeCount; -} - - -typedef struct ReverbStateFactory { - DERIVE_FROM_TYPE(EffectStateFactory); -} ReverbStateFactory; - -static ALeffectState *ReverbStateFactory_create(ReverbStateFactory* UNUSED(factory)) -{ - ReverbState *state; - - NEW_OBJ0(state, ReverbState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(ReverbStateFactory); - -EffectStateFactory *ReverbStateFactory_getFactory(void) -{ - static ReverbStateFactory ReverbFactory = { { GET_VTABLE2(ReverbStateFactory, EffectStateFactory) } }; - - return STATIC_CAST(EffectStateFactory, &ReverbFactory); -} - - -void ALeaxreverb_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_EAXREVERB_DECAY_HFLIMIT: - if(!(val >= AL_EAXREVERB_MIN_DECAY_HFLIMIT && val <= AL_EAXREVERB_MAX_DECAY_HFLIMIT)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay hflimit out of range"); - props->Reverb.DecayHFLimit = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb integer property 0x%04x", - param); - } -} -void ALeaxreverb_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ ALeaxreverb_setParami(effect, context, param, vals[0]); } -void ALeaxreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_EAXREVERB_DENSITY: - if(!(val >= AL_EAXREVERB_MIN_DENSITY && val <= AL_EAXREVERB_MAX_DENSITY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb density out of range"); - props->Reverb.Density = val; - break; - - case AL_EAXREVERB_DIFFUSION: - if(!(val >= AL_EAXREVERB_MIN_DIFFUSION && val <= AL_EAXREVERB_MAX_DIFFUSION)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb diffusion out of range"); - props->Reverb.Diffusion = val; - break; - - case AL_EAXREVERB_GAIN: - if(!(val >= AL_EAXREVERB_MIN_GAIN && val <= AL_EAXREVERB_MAX_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb gain out of range"); - props->Reverb.Gain = val; - break; - - case AL_EAXREVERB_GAINHF: - if(!(val >= AL_EAXREVERB_MIN_GAINHF && val <= AL_EAXREVERB_MAX_GAINHF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb gainhf out of range"); - props->Reverb.GainHF = val; - break; - - case AL_EAXREVERB_GAINLF: - if(!(val >= AL_EAXREVERB_MIN_GAINLF && val <= AL_EAXREVERB_MAX_GAINLF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb gainlf out of range"); - props->Reverb.GainLF = val; - break; - - case AL_EAXREVERB_DECAY_TIME: - if(!(val >= AL_EAXREVERB_MIN_DECAY_TIME && val <= AL_EAXREVERB_MAX_DECAY_TIME)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay time out of range"); - props->Reverb.DecayTime = val; - break; - - case AL_EAXREVERB_DECAY_HFRATIO: - if(!(val >= AL_EAXREVERB_MIN_DECAY_HFRATIO && val <= AL_EAXREVERB_MAX_DECAY_HFRATIO)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay hfratio out of range"); - props->Reverb.DecayHFRatio = val; - break; - - case AL_EAXREVERB_DECAY_LFRATIO: - if(!(val >= AL_EAXREVERB_MIN_DECAY_LFRATIO && val <= AL_EAXREVERB_MAX_DECAY_LFRATIO)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay lfratio out of range"); - props->Reverb.DecayLFRatio = val; - break; - - case AL_EAXREVERB_REFLECTIONS_GAIN: - if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_GAIN && val <= AL_EAXREVERB_MAX_REFLECTIONS_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb reflections gain out of range"); - props->Reverb.ReflectionsGain = val; - break; - - case AL_EAXREVERB_REFLECTIONS_DELAY: - if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_DELAY && val <= AL_EAXREVERB_MAX_REFLECTIONS_DELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb reflections delay out of range"); - props->Reverb.ReflectionsDelay = val; - break; - - case AL_EAXREVERB_LATE_REVERB_GAIN: - if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_GAIN && val <= AL_EAXREVERB_MAX_LATE_REVERB_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb late reverb gain out of range"); - props->Reverb.LateReverbGain = val; - break; - - case AL_EAXREVERB_LATE_REVERB_DELAY: - if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_DELAY && val <= AL_EAXREVERB_MAX_LATE_REVERB_DELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb late reverb delay out of range"); - props->Reverb.LateReverbDelay = val; - break; - - case AL_EAXREVERB_AIR_ABSORPTION_GAINHF: - if(!(val >= AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb air absorption gainhf out of range"); - props->Reverb.AirAbsorptionGainHF = val; - break; - - case AL_EAXREVERB_ECHO_TIME: - if(!(val >= AL_EAXREVERB_MIN_ECHO_TIME && val <= AL_EAXREVERB_MAX_ECHO_TIME)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb echo time out of range"); - props->Reverb.EchoTime = val; - break; - - case AL_EAXREVERB_ECHO_DEPTH: - if(!(val >= AL_EAXREVERB_MIN_ECHO_DEPTH && val <= AL_EAXREVERB_MAX_ECHO_DEPTH)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb echo depth out of range"); - props->Reverb.EchoDepth = val; - break; - - case AL_EAXREVERB_MODULATION_TIME: - if(!(val >= AL_EAXREVERB_MIN_MODULATION_TIME && val <= AL_EAXREVERB_MAX_MODULATION_TIME)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb modulation time out of range"); - props->Reverb.ModulationTime = val; - break; - - case AL_EAXREVERB_MODULATION_DEPTH: - if(!(val >= AL_EAXREVERB_MIN_MODULATION_DEPTH && val <= AL_EAXREVERB_MAX_MODULATION_DEPTH)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb modulation depth out of range"); - props->Reverb.ModulationDepth = val; - break; - - case AL_EAXREVERB_HFREFERENCE: - if(!(val >= AL_EAXREVERB_MIN_HFREFERENCE && val <= AL_EAXREVERB_MAX_HFREFERENCE)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb hfreference out of range"); - props->Reverb.HFReference = val; - break; - - case AL_EAXREVERB_LFREFERENCE: - if(!(val >= AL_EAXREVERB_MIN_LFREFERENCE && val <= AL_EAXREVERB_MAX_LFREFERENCE)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb lfreference out of range"); - props->Reverb.LFReference = val; - break; - - case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR: - if(!(val >= AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb room rolloff factor out of range"); - props->Reverb.RoomRolloffFactor = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", - param); - } -} -void ALeaxreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_EAXREVERB_REFLECTIONS_PAN: - if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2]))) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb reflections pan out of range"); - props->Reverb.ReflectionsPan[0] = vals[0]; - props->Reverb.ReflectionsPan[1] = vals[1]; - props->Reverb.ReflectionsPan[2] = vals[2]; - break; - case AL_EAXREVERB_LATE_REVERB_PAN: - if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2]))) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb late reverb pan out of range"); - props->Reverb.LateReverbPan[0] = vals[0]; - props->Reverb.LateReverbPan[1] = vals[1]; - props->Reverb.LateReverbPan[2] = vals[2]; - break; - - default: - ALeaxreverb_setParamf(effect, context, param, vals[0]); - break; - } -} - -void ALeaxreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_EAXREVERB_DECAY_HFLIMIT: - *val = props->Reverb.DecayHFLimit; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb integer property 0x%04x", - param); - } -} -void ALeaxreverb_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ ALeaxreverb_getParami(effect, context, param, vals); } -void ALeaxreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_EAXREVERB_DENSITY: - *val = props->Reverb.Density; - break; - - case AL_EAXREVERB_DIFFUSION: - *val = props->Reverb.Diffusion; - break; - - case AL_EAXREVERB_GAIN: - *val = props->Reverb.Gain; - break; - - case AL_EAXREVERB_GAINHF: - *val = props->Reverb.GainHF; - break; - - case AL_EAXREVERB_GAINLF: - *val = props->Reverb.GainLF; - break; - - case AL_EAXREVERB_DECAY_TIME: - *val = props->Reverb.DecayTime; - break; - - case AL_EAXREVERB_DECAY_HFRATIO: - *val = props->Reverb.DecayHFRatio; - break; - - case AL_EAXREVERB_DECAY_LFRATIO: - *val = props->Reverb.DecayLFRatio; - break; - - case AL_EAXREVERB_REFLECTIONS_GAIN: - *val = props->Reverb.ReflectionsGain; - break; - - case AL_EAXREVERB_REFLECTIONS_DELAY: - *val = props->Reverb.ReflectionsDelay; - break; - - case AL_EAXREVERB_LATE_REVERB_GAIN: - *val = props->Reverb.LateReverbGain; - break; - - case AL_EAXREVERB_LATE_REVERB_DELAY: - *val = props->Reverb.LateReverbDelay; - break; - - case AL_EAXREVERB_AIR_ABSORPTION_GAINHF: - *val = props->Reverb.AirAbsorptionGainHF; - break; - - case AL_EAXREVERB_ECHO_TIME: - *val = props->Reverb.EchoTime; - break; - - case AL_EAXREVERB_ECHO_DEPTH: - *val = props->Reverb.EchoDepth; - break; - - case AL_EAXREVERB_MODULATION_TIME: - *val = props->Reverb.ModulationTime; - break; - - case AL_EAXREVERB_MODULATION_DEPTH: - *val = props->Reverb.ModulationDepth; - break; - - case AL_EAXREVERB_HFREFERENCE: - *val = props->Reverb.HFReference; - break; - - case AL_EAXREVERB_LFREFERENCE: - *val = props->Reverb.LFReference; - break; - - case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR: - *val = props->Reverb.RoomRolloffFactor; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", - param); - } -} -void ALeaxreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_EAXREVERB_REFLECTIONS_PAN: - vals[0] = props->Reverb.ReflectionsPan[0]; - vals[1] = props->Reverb.ReflectionsPan[1]; - vals[2] = props->Reverb.ReflectionsPan[2]; - break; - case AL_EAXREVERB_LATE_REVERB_PAN: - vals[0] = props->Reverb.LateReverbPan[0]; - vals[1] = props->Reverb.LateReverbPan[1]; - vals[2] = props->Reverb.LateReverbPan[2]; - break; - - default: - ALeaxreverb_getParamf(effect, context, param, vals); - break; - } -} - -DEFINE_ALEFFECT_VTABLE(ALeaxreverb); - -void ALreverb_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_REVERB_DECAY_HFLIMIT: - if(!(val >= AL_REVERB_MIN_DECAY_HFLIMIT && val <= AL_REVERB_MAX_DECAY_HFLIMIT)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb decay hflimit out of range"); - props->Reverb.DecayHFLimit = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid reverb integer property 0x%04x", param); - } -} -void ALreverb_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ ALreverb_setParami(effect, context, param, vals[0]); } -void ALreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_REVERB_DENSITY: - if(!(val >= AL_REVERB_MIN_DENSITY && val <= AL_REVERB_MAX_DENSITY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb density out of range"); - props->Reverb.Density = val; - break; - - case AL_REVERB_DIFFUSION: - if(!(val >= AL_REVERB_MIN_DIFFUSION && val <= AL_REVERB_MAX_DIFFUSION)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb diffusion out of range"); - props->Reverb.Diffusion = val; - break; - - case AL_REVERB_GAIN: - if(!(val >= AL_REVERB_MIN_GAIN && val <= AL_REVERB_MAX_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb gain out of range"); - props->Reverb.Gain = val; - break; - - case AL_REVERB_GAINHF: - if(!(val >= AL_REVERB_MIN_GAINHF && val <= AL_REVERB_MAX_GAINHF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb gainhf out of range"); - props->Reverb.GainHF = val; - break; - - case AL_REVERB_DECAY_TIME: - if(!(val >= AL_REVERB_MIN_DECAY_TIME && val <= AL_REVERB_MAX_DECAY_TIME)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb decay time out of range"); - props->Reverb.DecayTime = val; - break; - - case AL_REVERB_DECAY_HFRATIO: - if(!(val >= AL_REVERB_MIN_DECAY_HFRATIO && val <= AL_REVERB_MAX_DECAY_HFRATIO)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb decay hfratio out of range"); - props->Reverb.DecayHFRatio = val; - break; - - case AL_REVERB_REFLECTIONS_GAIN: - if(!(val >= AL_REVERB_MIN_REFLECTIONS_GAIN && val <= AL_REVERB_MAX_REFLECTIONS_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb reflections gain out of range"); - props->Reverb.ReflectionsGain = val; - break; - - case AL_REVERB_REFLECTIONS_DELAY: - if(!(val >= AL_REVERB_MIN_REFLECTIONS_DELAY && val <= AL_REVERB_MAX_REFLECTIONS_DELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb reflections delay out of range"); - props->Reverb.ReflectionsDelay = val; - break; - - case AL_REVERB_LATE_REVERB_GAIN: - if(!(val >= AL_REVERB_MIN_LATE_REVERB_GAIN && val <= AL_REVERB_MAX_LATE_REVERB_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb late reverb gain out of range"); - props->Reverb.LateReverbGain = val; - break; - - case AL_REVERB_LATE_REVERB_DELAY: - if(!(val >= AL_REVERB_MIN_LATE_REVERB_DELAY && val <= AL_REVERB_MAX_LATE_REVERB_DELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb late reverb delay out of range"); - props->Reverb.LateReverbDelay = val; - break; - - case AL_REVERB_AIR_ABSORPTION_GAINHF: - if(!(val >= AL_REVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_REVERB_MAX_AIR_ABSORPTION_GAINHF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb air absorption gainhf out of range"); - props->Reverb.AirAbsorptionGainHF = val; - break; - - case AL_REVERB_ROOM_ROLLOFF_FACTOR: - if(!(val >= AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb room rolloff factor out of range"); - props->Reverb.RoomRolloffFactor = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid reverb float property 0x%04x", param); - } -} -void ALreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ ALreverb_setParamf(effect, context, param, vals[0]); } - -void ALreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_REVERB_DECAY_HFLIMIT: - *val = props->Reverb.DecayHFLimit; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid reverb integer property 0x%04x", param); - } -} -void ALreverb_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ ALreverb_getParami(effect, context, param, vals); } -void ALreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_REVERB_DENSITY: - *val = props->Reverb.Density; - break; - - case AL_REVERB_DIFFUSION: - *val = props->Reverb.Diffusion; - break; - - case AL_REVERB_GAIN: - *val = props->Reverb.Gain; - break; - - case AL_REVERB_GAINHF: - *val = props->Reverb.GainHF; - break; - - case AL_REVERB_DECAY_TIME: - *val = props->Reverb.DecayTime; - break; - - case AL_REVERB_DECAY_HFRATIO: - *val = props->Reverb.DecayHFRatio; - break; - - case AL_REVERB_REFLECTIONS_GAIN: - *val = props->Reverb.ReflectionsGain; - break; - - case AL_REVERB_REFLECTIONS_DELAY: - *val = props->Reverb.ReflectionsDelay; - break; - - case AL_REVERB_LATE_REVERB_GAIN: - *val = props->Reverb.LateReverbGain; - break; - - case AL_REVERB_LATE_REVERB_DELAY: - *val = props->Reverb.LateReverbDelay; - break; - - case AL_REVERB_AIR_ABSORPTION_GAINHF: - *val = props->Reverb.AirAbsorptionGainHF; - break; - - case AL_REVERB_ROOM_ROLLOFF_FACTOR: - *val = props->Reverb.RoomRolloffFactor; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid reverb float property 0x%04x", param); - } -} -void ALreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ ALreverb_getParamf(effect, context, param, vals); } - -DEFINE_ALEFFECT_VTABLE(ALreverb); diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp new file mode 100644 index 00000000..5cfc0012 --- /dev/null +++ b/Alc/effects/reverb.cpp @@ -0,0 +1,2094 @@ +/** + * Ambisonic reverb engine for the OpenAL cross platform audio library + * Copyright (C) 2008-2017 by Chris Robinson and Christopher Fitzgerald. + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include "alMain.h" +#include "alu.h" +#include "alAuxEffectSlot.h" +#include "alListener.h" +#include "alError.h" +#include "filters/defs.h" + +/* This is a user config option for modifying the overall output of the reverb + * effect. + */ +ALfloat ReverbBoost = 1.0f; + +/* This is the maximum number of samples processed for each inner loop + * iteration. */ +#define MAX_UPDATE_SAMPLES 256 + +/* The number of samples used for cross-faded delay lines. This can be used + * to balance the compensation for abrupt line changes and attenuation due to + * minimally lengthed recursive lines. Try to keep this below the device + * update size. + */ +#define FADE_SAMPLES 128 + +/* The number of spatialized lines or channels to process. Four channels allows + * for a 3D A-Format response. NOTE: This can't be changed without taking care + * of the conversion matrices, and a few places where the length arrays are + * assumed to have 4 elements. + */ +#define NUM_LINES 4 + + +/* The B-Format to A-Format conversion matrix. The arrangement of rows is + * deliberately chosen to align the resulting lines to their spatial opposites + * (0:above front left <-> 3:above back right, 1:below front right <-> 2:below + * back left). It's not quite opposite, since the A-Format results in a + * tetrahedron, but it's close enough. Should the model be extended to 8-lines + * in the future, true opposites can be used. + */ +static const aluMatrixf B2A = {{ + { 0.288675134595f, 0.288675134595f, 0.288675134595f, 0.288675134595f }, + { 0.288675134595f, -0.288675134595f, -0.288675134595f, 0.288675134595f }, + { 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f }, + { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f } +}}; + +/* Converts A-Format to B-Format. */ +static const aluMatrixf A2B = {{ + { 0.866025403785f, 0.866025403785f, 0.866025403785f, 0.866025403785f }, + { 0.866025403785f, -0.866025403785f, 0.866025403785f, -0.866025403785f }, + { 0.866025403785f, -0.866025403785f, -0.866025403785f, 0.866025403785f }, + { 0.866025403785f, 0.866025403785f, -0.866025403785f, -0.866025403785f } +}}; + +static const ALfloat FadeStep = 1.0f / FADE_SAMPLES; + +/* The all-pass and delay lines have a variable length dependent on the + * effect's density parameter, which helps alter the perceived environment + * size. The size-to-density conversion is a cubed scale: + * + * density = min(1.0, pow(size, 3.0) / DENSITY_SCALE); + * + * The line lengths scale linearly with room size, so the inverse density + * conversion is needed, taking the cube root of the re-scaled density to + * calculate the line length multiplier: + * + * length_mult = max(5.0, cbrtf(density*DENSITY_SCALE)); + * + * The density scale below will result in a max line multiplier of 50, for an + * effective size range of 5m to 50m. + */ +static const ALfloat DENSITY_SCALE = 125000.0f; + +/* All delay line lengths are specified in seconds. + * + * To approximate early reflections, we break them up into primary (those + * arriving from the same direction as the source) and secondary (those + * arriving from the opposite direction). + * + * The early taps decorrelate the 4-channel signal to approximate an average + * room response for the primary reflections after the initial early delay. + * + * Given an average room dimension (d_a) and the speed of sound (c) we can + * calculate the average reflection delay (r_a) regardless of listener and + * source positions as: + * + * r_a = d_a / c + * c = 343.3 + * + * This can extended to finding the average difference (r_d) between the + * maximum (r_1) and minimum (r_0) reflection delays: + * + * r_0 = 2 / 3 r_a + * = r_a - r_d / 2 + * = r_d + * r_1 = 4 / 3 r_a + * = r_a + r_d / 2 + * = 2 r_d + * r_d = 2 / 3 r_a + * = r_1 - r_0 + * + * As can be determined by integrating the 1D model with a source (s) and + * listener (l) positioned across the dimension of length (d_a): + * + * r_d = int_(l=0)^d_a (int_(s=0)^d_a |2 d_a - 2 (l + s)| ds) dl / c + * + * The initial taps (T_(i=0)^N) are then specified by taking a power series + * that ranges between r_0 and half of r_1 less r_0: + * + * R_i = 2^(i / (2 N - 1)) r_d + * = r_0 + (2^(i / (2 N - 1)) - 1) r_d + * = r_0 + T_i + * T_i = R_i - r_0 + * = (2^(i / (2 N - 1)) - 1) r_d + * + * Assuming an average of 1m, we get the following taps: + */ +static const ALfloat EARLY_TAP_LENGTHS[NUM_LINES] = +{ + 0.0000000e+0f, 2.0213520e-4f, 4.2531060e-4f, 6.7171600e-4f +}; + +/* The early all-pass filter lengths are based on the early tap lengths: + * + * A_i = R_i / a + * + * Where a is the approximate maximum all-pass cycle limit (20). + */ +static const ALfloat EARLY_ALLPASS_LENGTHS[NUM_LINES] = +{ + 9.7096800e-5f, 1.0720356e-4f, 1.1836234e-4f, 1.3068260e-4f +}; + +/* The early delay lines are used to transform the primary reflections into + * the secondary reflections. The A-format is arranged in such a way that + * the channels/lines are spatially opposite: + * + * C_i is opposite C_(N-i-1) + * + * The delays of the two opposing reflections (R_i and O_i) from a source + * anywhere along a particular dimension always sum to twice its full delay: + * + * 2 r_a = R_i + O_i + * + * With that in mind we can determine the delay between the two reflections + * and thus specify our early line lengths (L_(i=0)^N) using: + * + * O_i = 2 r_a - R_(N-i-1) + * L_i = O_i - R_(N-i-1) + * = 2 (r_a - R_(N-i-1)) + * = 2 (r_a - T_(N-i-1) - r_0) + * = 2 r_a (1 - (2 / 3) 2^((N - i - 1) / (2 N - 1))) + * + * Using an average dimension of 1m, we get: + */ +static const ALfloat EARLY_LINE_LENGTHS[NUM_LINES] = +{ + 5.9850400e-4f, 1.0913150e-3f, 1.5376658e-3f, 1.9419362e-3f +}; + +/* The late all-pass filter lengths are based on the late line lengths: + * + * A_i = (5 / 3) L_i / r_1 + */ +static const ALfloat LATE_ALLPASS_LENGTHS[NUM_LINES] = +{ + 1.6182800e-4f, 2.0389060e-4f, 2.8159360e-4f, 3.2365600e-4f +}; + +/* The late lines are used to approximate the decaying cycle of recursive + * late reflections. + * + * Splitting the lines in half, we start with the shortest reflection paths + * (L_(i=0)^(N/2)): + * + * L_i = 2^(i / (N - 1)) r_d + * + * Then for the opposite (longest) reflection paths (L_(i=N/2)^N): + * + * L_i = 2 r_a - L_(i-N/2) + * = 2 r_a - 2^((i - N / 2) / (N - 1)) r_d + * + * For our 1m average room, we get: + */ +static const ALfloat LATE_LINE_LENGTHS[NUM_LINES] = +{ + 1.9419362e-3f, 2.4466860e-3f, 3.3791220e-3f, 3.8838720e-3f +}; + + +typedef struct DelayLineI { + /* The delay lines use interleaved samples, with the lengths being powers + * of 2 to allow the use of bit-masking instead of a modulus for wrapping. + */ + ALsizei Mask; + ALfloat (*Line)[NUM_LINES]; +} DelayLineI; + +typedef struct VecAllpass { + DelayLineI Delay; + ALfloat Coeff; + ALsizei Offset[NUM_LINES][2]; +} VecAllpass; + +typedef struct T60Filter { + /* Two filters are used to adjust the signal. One to control the low + * frequencies, and one to control the high frequencies. + */ + ALfloat MidGain[2]; + BiquadFilter HFFilter, LFFilter; +} T60Filter; + +typedef struct EarlyReflections { + /* A Gerzon vector all-pass filter is used to simulate initial diffusion. + * The spread from this filter also helps smooth out the reverb tail. + */ + VecAllpass VecAp; + + /* An echo line is used to complete the second half of the early + * reflections. + */ + DelayLineI Delay; + ALsizei Offset[NUM_LINES][2]; + ALfloat Coeff[NUM_LINES][2]; + + /* The gain for each output channel based on 3D panning. */ + ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; + ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; +} EarlyReflections; + +typedef struct LateReverb { + /* A recursive delay line is used fill in the reverb tail. */ + DelayLineI Delay; + ALsizei Offset[NUM_LINES][2]; + + /* Attenuation to compensate for the modal density and decay rate of the + * late lines. + */ + ALfloat DensityGain[2]; + + /* T60 decay filters are used to simulate absorption. */ + T60Filter T60[NUM_LINES]; + + /* A Gerzon vector all-pass filter is used to simulate diffusion. */ + VecAllpass VecAp; + + /* The gain for each output channel based on 3D panning. */ + ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; + ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; +} LateReverb; + +struct ReverbState final : public ALeffectState { + /* All delay lines are allocated as a single buffer to reduce memory + * fragmentation and management code. + */ + ALfloat *SampleBuffer; + ALuint TotalSamples; + + struct { + /* Calculated parameters which indicate if cross-fading is needed after + * an update. + */ + ALfloat Density, Diffusion; + ALfloat DecayTime, HFDecayTime, LFDecayTime; + ALfloat HFReference, LFReference; + } Params; + + /* Master effect filters */ + struct { + BiquadFilter Lp; + BiquadFilter Hp; + } Filter[NUM_LINES]; + + /* Core delay line (early reflections and late reverb tap from this). */ + DelayLineI Delay; + + /* Tap points for early reflection delay. */ + ALsizei EarlyDelayTap[NUM_LINES][2]; + ALfloat EarlyDelayCoeff[NUM_LINES][2]; + + /* Tap points for late reverb feed and delay. */ + ALsizei LateFeedTap; + ALsizei LateDelayTap[NUM_LINES][2]; + + /* Coefficients for the all-pass and line scattering matrices. */ + ALfloat MixX; + ALfloat MixY; + + EarlyReflections Early; + + LateReverb Late; + + /* Indicates the cross-fade point for delay line reads [0,FADE_SAMPLES]. */ + ALsizei FadeCount; + + /* Maximum number of samples to process at once. */ + ALsizei MaxUpdate[2]; + + /* The current write offset for all delay lines. */ + ALsizei Offset; + + /* Temporary storage used when processing. */ + alignas(16) ALfloat TempSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; + alignas(16) ALfloat MixSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; +}; + +static ALvoid ReverbState_Destruct(ReverbState *State); +static ALboolean ReverbState_deviceUpdate(ReverbState *State, ALCdevice *Device); +static ALvoid ReverbState_update(ReverbState *State, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props); +static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ReverbState) + +DEFINE_ALEFFECTSTATE_VTABLE(ReverbState); + +static void ReverbState_Construct(ReverbState *state) +{ + new (state) ReverbState{}; + + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ReverbState, ALeffectState, state); + + state->TotalSamples = 0; + state->SampleBuffer = NULL; + + state->Params.Density = AL_EAXREVERB_DEFAULT_DENSITY; + state->Params.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION; + state->Params.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME; + state->Params.HFDecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME*AL_EAXREVERB_DEFAULT_DECAY_HFRATIO; + state->Params.LFDecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME*AL_EAXREVERB_DEFAULT_DECAY_LFRATIO; + state->Params.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE; + state->Params.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE; + + for(ALsizei i{0};i < NUM_LINES;i++) + { + BiquadFilter_clear(&state->Filter[i].Lp); + BiquadFilter_clear(&state->Filter[i].Hp); + } + + state->Delay.Mask = 0; + state->Delay.Line = NULL; + + for(ALsizei i{0};i < NUM_LINES;i++) + { + state->EarlyDelayTap[i][0] = 0; + state->EarlyDelayTap[i][1] = 0; + state->EarlyDelayCoeff[i][0] = 0.0f; + state->EarlyDelayCoeff[i][1] = 0.0f; + } + + state->LateFeedTap = 0; + + for(ALsizei i{0};i < NUM_LINES;i++) + { + state->LateDelayTap[i][0] = 0; + state->LateDelayTap[i][1] = 0; + } + + state->MixX = 0.0f; + state->MixY = 0.0f; + + state->Early.VecAp.Delay.Mask = 0; + state->Early.VecAp.Delay.Line = NULL; + state->Early.VecAp.Coeff = 0.0f; + state->Early.Delay.Mask = 0; + state->Early.Delay.Line = NULL; + for(ALsizei i{0};i < NUM_LINES;i++) + { + state->Early.VecAp.Offset[i][0] = 0; + state->Early.VecAp.Offset[i][1] = 0; + state->Early.Offset[i][0] = 0; + state->Early.Offset[i][1] = 0; + state->Early.Coeff[i][0] = 0.0f; + state->Early.Coeff[i][1] = 0.0f; + } + + state->Late.DensityGain[0] = 0.0f; + state->Late.DensityGain[1] = 0.0f; + state->Late.Delay.Mask = 0; + state->Late.Delay.Line = NULL; + state->Late.VecAp.Delay.Mask = 0; + state->Late.VecAp.Delay.Line = NULL; + state->Late.VecAp.Coeff = 0.0f; + for(ALsizei i{0};i < NUM_LINES;i++) + { + state->Late.Offset[i][0] = 0; + state->Late.Offset[i][1] = 0; + + state->Late.VecAp.Offset[i][0] = 0; + state->Late.VecAp.Offset[i][1] = 0; + + state->Late.T60[i].MidGain[0] = 0.0f; + state->Late.T60[i].MidGain[1] = 0.0f; + BiquadFilter_clear(&state->Late.T60[i].HFFilter); + BiquadFilter_clear(&state->Late.T60[i].LFFilter); + } + + for(ALsizei i{0};i < NUM_LINES;i++) + { + for(ALsizei j{0};j < MAX_OUTPUT_CHANNELS;j++) + { + state->Early.CurrentGain[i][j] = 0.0f; + state->Early.PanGain[i][j] = 0.0f; + state->Late.CurrentGain[i][j] = 0.0f; + state->Late.PanGain[i][j] = 0.0f; + } + } + + state->FadeCount = 0; + state->MaxUpdate[0] = MAX_UPDATE_SAMPLES; + state->MaxUpdate[1] = MAX_UPDATE_SAMPLES; + state->Offset = 0; +} + +static ALvoid ReverbState_Destruct(ReverbState *State) +{ + al_free(State->SampleBuffer); + State->SampleBuffer = NULL; + + ALeffectState_Destruct(STATIC_CAST(ALeffectState,State)); + State->~ReverbState(); +} + +/************************************** + * Device Update * + **************************************/ + +static inline ALfloat CalcDelayLengthMult(ALfloat density) +{ + return maxf(5.0f, cbrtf(density*DENSITY_SCALE)); +} + +/* Given the allocated sample buffer, this function updates each delay line + * offset. + */ +static inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLineI *Delay) +{ + union { + ALfloat *f; + ALfloat (*f4)[NUM_LINES]; + } u; + u.f = &sampleBuffer[(ptrdiff_t)Delay->Line * NUM_LINES]; + Delay->Line = u.f4; +} + +/* Calculate the length of a delay line and store its mask and offset. */ +static ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const ALuint frequency, + const ALuint extra, DelayLineI *Delay) +{ + ALuint samples; + + /* All line lengths are powers of 2, calculated from their lengths in + * seconds, rounded up. + */ + samples = float2int(ceilf(length*frequency)); + samples = NextPowerOf2(samples + extra); + + /* All lines share a single sample buffer. */ + Delay->Mask = samples - 1; + Delay->Line = (ALfloat(*)[NUM_LINES])offset; + + /* Return the sample count for accumulation. */ + return samples; +} + +/* Calculates the delay line metrics and allocates the shared sample buffer + * for all lines given the sample rate (frequency). If an allocation failure + * occurs, it returns AL_FALSE. + */ +static ALboolean AllocLines(const ALuint frequency, ReverbState *State) +{ + ALuint totalSamples, i; + ALfloat multiplier, length; + + /* All delay line lengths are calculated to accomodate the full range of + * lengths given their respective paramters. + */ + totalSamples = 0; + + /* Multiplier for the maximum density value, i.e. density=1, which is + * actually the least density... + */ + multiplier = CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY); + + /* The main delay length includes the maximum early reflection delay, the + * largest early tap width, the maximum late reverb delay, and the + * largest late tap width. Finally, it must also be extended by the + * update size (MAX_UPDATE_SAMPLES) for block processing. + */ + length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier + + AL_EAXREVERB_MAX_LATE_REVERB_DELAY + + (LATE_LINE_LENGTHS[NUM_LINES-1] - LATE_LINE_LENGTHS[0])*0.25f*multiplier; + totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES, + &State->Delay); + + /* The early vector all-pass line. */ + length = EARLY_ALLPASS_LENGTHS[NUM_LINES-1] * multiplier; + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, + &State->Early.VecAp.Delay); + + /* The early reflection line. */ + length = EARLY_LINE_LENGTHS[NUM_LINES-1] * multiplier; + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, + &State->Early.Delay); + + /* The late vector all-pass line. */ + length = LATE_ALLPASS_LENGTHS[NUM_LINES-1] * multiplier; + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, + &State->Late.VecAp.Delay); + + /* The late delay lines are calculated from the largest maximum density + * line length. + */ + length = LATE_LINE_LENGTHS[NUM_LINES-1] * multiplier; + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, + &State->Late.Delay); + + if(totalSamples != State->TotalSamples) + { + ALfloat *newBuffer; + + TRACE("New reverb buffer length: %ux4 samples\n", totalSamples); + newBuffer = static_cast(al_calloc(16, + sizeof(ALfloat[NUM_LINES]) * totalSamples)); + if(!newBuffer) return AL_FALSE; + + al_free(State->SampleBuffer); + State->SampleBuffer = newBuffer; + State->TotalSamples = totalSamples; + } + + /* Update all delays to reflect the new sample buffer. */ + RealizeLineOffset(State->SampleBuffer, &State->Delay); + RealizeLineOffset(State->SampleBuffer, &State->Early.VecAp.Delay); + RealizeLineOffset(State->SampleBuffer, &State->Early.Delay); + RealizeLineOffset(State->SampleBuffer, &State->Late.VecAp.Delay); + RealizeLineOffset(State->SampleBuffer, &State->Late.Delay); + + /* Clear the sample buffer. */ + for(i = 0;i < State->TotalSamples;i++) + State->SampleBuffer[i] = 0.0f; + + return AL_TRUE; +} + +static ALboolean ReverbState_deviceUpdate(ReverbState *State, ALCdevice *Device) +{ + ALuint frequency = Device->Frequency; + ALfloat multiplier; + ALsizei i, j; + + /* Allocate the delay lines. */ + if(!AllocLines(frequency, State)) + return AL_FALSE; + + multiplier = CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY); + + /* The late feed taps are set a fixed position past the latest delay tap. */ + State->LateFeedTap = float2int((AL_EAXREVERB_MAX_REFLECTIONS_DELAY + + EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier) * + frequency); + + /* Clear filters and gain coefficients since the delay lines were all just + * cleared (if not reallocated). + */ + for(i = 0;i < NUM_LINES;i++) + { + BiquadFilter_clear(&State->Filter[i].Lp); + BiquadFilter_clear(&State->Filter[i].Hp); + } + + for(i = 0;i < NUM_LINES;i++) + { + State->EarlyDelayCoeff[i][0] = 0.0f; + State->EarlyDelayCoeff[i][1] = 0.0f; + } + + for(i = 0;i < NUM_LINES;i++) + { + State->Early.Coeff[i][0] = 0.0f; + State->Early.Coeff[i][1] = 0.0f; + } + + State->Late.DensityGain[0] = 0.0f; + State->Late.DensityGain[1] = 0.0f; + for(i = 0;i < NUM_LINES;i++) + { + State->Late.T60[i].MidGain[0] = 0.0f; + State->Late.T60[i].MidGain[1] = 0.0f; + BiquadFilter_clear(&State->Late.T60[i].HFFilter); + BiquadFilter_clear(&State->Late.T60[i].LFFilter); + } + + for(i = 0;i < NUM_LINES;i++) + { + for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) + { + State->Early.CurrentGain[i][j] = 0.0f; + State->Early.PanGain[i][j] = 0.0f; + State->Late.CurrentGain[i][j] = 0.0f; + State->Late.PanGain[i][j] = 0.0f; + } + } + + /* Reset counters and offset base. */ + State->FadeCount = 0; + State->MaxUpdate[0] = MAX_UPDATE_SAMPLES; + State->MaxUpdate[1] = MAX_UPDATE_SAMPLES; + State->Offset = 0; + + return AL_TRUE; +} + +/************************************** + * Effect Update * + **************************************/ + +/* Calculate a decay coefficient given the length of each cycle and the time + * until the decay reaches -60 dB. + */ +static inline ALfloat CalcDecayCoeff(const ALfloat length, const ALfloat decayTime) +{ + return powf(REVERB_DECAY_GAIN, length/decayTime); +} + +/* Calculate a decay length from a coefficient and the time until the decay + * reaches -60 dB. + */ +static inline ALfloat CalcDecayLength(const ALfloat coeff, const ALfloat decayTime) +{ + return log10f(coeff) * decayTime / log10f(REVERB_DECAY_GAIN); +} + +/* Calculate an attenuation to be applied to the input of any echo models to + * compensate for modal density and decay time. + */ +static inline ALfloat CalcDensityGain(const ALfloat a) +{ + /* The energy of a signal can be obtained by finding the area under the + * squared signal. This takes the form of Sum(x_n^2), where x is the + * amplitude for the sample n. + * + * Decaying feedback matches exponential decay of the form Sum(a^n), + * where a is the attenuation coefficient, and n is the sample. The area + * under this decay curve can be calculated as: 1 / (1 - a). + * + * Modifying the above equation to find the area under the squared curve + * (for energy) yields: 1 / (1 - a^2). Input attenuation can then be + * calculated by inverting the square root of this approximation, + * yielding: 1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2). + */ + return sqrtf(1.0f - a*a); +} + +/* Calculate the scattering matrix coefficients given a diffusion factor. */ +static inline ALvoid CalcMatrixCoeffs(const ALfloat diffusion, ALfloat *x, ALfloat *y) +{ + ALfloat n, t; + + /* The matrix is of order 4, so n is sqrt(4 - 1). */ + n = sqrtf(3.0f); + t = diffusion * atanf(n); + + /* Calculate the first mixing matrix coefficient. */ + *x = cosf(t); + /* Calculate the second mixing matrix coefficient. */ + *y = sinf(t) / n; +} + +/* Calculate the limited HF ratio for use with the late reverb low-pass + * filters. + */ +static ALfloat CalcLimitedHfRatio(const ALfloat hfRatio, const ALfloat airAbsorptionGainHF, + const ALfloat decayTime, const ALfloat SpeedOfSound) +{ + ALfloat limitRatio; + + /* Find the attenuation due to air absorption in dB (converting delay + * time to meters using the speed of sound). Then reversing the decay + * equation, solve for HF ratio. The delay length is cancelled out of + * the equation, so it can be calculated once for all lines. + */ + limitRatio = 1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) * SpeedOfSound); + + /* Using the limit calculated above, apply the upper bound to the HF ratio. + */ + return minf(limitRatio, hfRatio); +} + + +/* Calculates the 3-band T60 damping coefficients for a particular delay line + * of specified length, using a combination of two shelf filter sections given + * decay times for each band split at two reference frequencies. + */ +static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime, + const ALfloat mfDecayTime, const ALfloat hfDecayTime, + const ALfloat lf0norm, const ALfloat hf0norm, + T60Filter *filter) +{ + ALfloat lfGain = CalcDecayCoeff(length, lfDecayTime); + ALfloat mfGain = CalcDecayCoeff(length, mfDecayTime); + ALfloat hfGain = CalcDecayCoeff(length, hfDecayTime); + + filter->MidGain[1] = mfGain; + BiquadFilter_setParams(&filter->LFFilter, BiquadType_LowShelf, lfGain/mfGain, lf0norm, + calc_rcpQ_from_slope(lfGain/mfGain, 1.0f)); + BiquadFilter_setParams(&filter->HFFilter, BiquadType_HighShelf, hfGain/mfGain, hf0norm, + calc_rcpQ_from_slope(hfGain/mfGain, 1.0f)); +} + +/* Update the offsets for the main effect delay line. */ +static ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, const ALfloat density, const ALfloat decayTime, const ALuint frequency, ReverbState *State) +{ + ALfloat multiplier, length; + ALuint i; + + multiplier = CalcDelayLengthMult(density); + + /* Early reflection taps are decorrelated by means of an average room + * reflection approximation described above the definition of the taps. + * This approximation is linear and so the above density multiplier can + * be applied to adjust the width of the taps. A single-band decay + * coefficient is applied to simulate initial attenuation and absorption. + * + * Late reverb taps are based on the late line lengths to allow a zero- + * delay path and offsets that would continue the propagation naturally + * into the late lines. + */ + for(i = 0;i < NUM_LINES;i++) + { + length = earlyDelay + EARLY_TAP_LENGTHS[i]*multiplier; + State->EarlyDelayTap[i][1] = float2int(length * frequency); + + length = EARLY_TAP_LENGTHS[i]*multiplier; + State->EarlyDelayCoeff[i][1] = CalcDecayCoeff(length, decayTime); + + length = lateDelay + (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS[0])*0.25f*multiplier; + State->LateDelayTap[i][1] = State->LateFeedTap + float2int(length * frequency); + } +} + +/* Update the early reflection line lengths and gain coefficients. */ +static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat diffusion, const ALfloat decayTime, const ALuint frequency, EarlyReflections *Early) +{ + ALfloat multiplier, length; + ALsizei i; + + multiplier = CalcDelayLengthMult(density); + + /* Calculate the all-pass feed-back/forward coefficient. */ + Early->VecAp.Coeff = sqrtf(0.5f) * powf(diffusion, 2.0f); + + for(i = 0;i < NUM_LINES;i++) + { + /* Calculate the length (in seconds) of each all-pass line. */ + length = EARLY_ALLPASS_LENGTHS[i] * multiplier; + + /* Calculate the delay offset for each all-pass line. */ + Early->VecAp.Offset[i][1] = float2int(length * frequency); + + /* Calculate the length (in seconds) of each delay line. */ + length = EARLY_LINE_LENGTHS[i] * multiplier; + + /* Calculate the delay offset for each delay line. */ + Early->Offset[i][1] = float2int(length * frequency); + + /* Calculate the gain (coefficient) for each line. */ + Early->Coeff[i][1] = CalcDecayCoeff(length, decayTime); + } +} + +/* Update the late reverb line lengths and T60 coefficients. */ +static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lf0norm, const ALfloat hf0norm, const ALuint frequency, LateReverb *Late) +{ + /* Scaling factor to convert the normalized reference frequencies from + * representing 0...freq to 0...max_reference. + */ + const ALfloat norm_weight_factor = (ALfloat)frequency / AL_EAXREVERB_MAX_HFREFERENCE; + ALfloat multiplier, length, bandWeights[3]; + ALsizei i; + + /* To compensate for changes in modal density and decay time of the late + * reverb signal, the input is attenuated based on the maximal energy of + * the outgoing signal. This approximation is used to keep the apparent + * energy of the signal equal for all ranges of density and decay time. + * + * The average length of the delay lines is used to calculate the + * attenuation coefficient. + */ + multiplier = CalcDelayLengthMult(density); + length = (LATE_LINE_LENGTHS[0] + LATE_LINE_LENGTHS[1] + + LATE_LINE_LENGTHS[2] + LATE_LINE_LENGTHS[3]) / 4.0f * multiplier; + length += (LATE_ALLPASS_LENGTHS[0] + LATE_ALLPASS_LENGTHS[1] + + LATE_ALLPASS_LENGTHS[2] + LATE_ALLPASS_LENGTHS[3]) / 4.0f * multiplier; + /* The density gain calculation uses an average decay time weighted by + * approximate bandwidth. This attempts to compensate for losses of energy + * that reduce decay time due to scattering into highly attenuated bands. + */ + bandWeights[0] = lf0norm*norm_weight_factor; + bandWeights[1] = hf0norm*norm_weight_factor - lf0norm*norm_weight_factor; + bandWeights[2] = 1.0f - hf0norm*norm_weight_factor; + Late->DensityGain[1] = CalcDensityGain( + CalcDecayCoeff(length, + bandWeights[0]*lfDecayTime + bandWeights[1]*mfDecayTime + bandWeights[2]*hfDecayTime + ) + ); + + /* Calculate the all-pass feed-back/forward coefficient. */ + Late->VecAp.Coeff = sqrtf(0.5f) * powf(diffusion, 2.0f); + + for(i = 0;i < NUM_LINES;i++) + { + /* Calculate the length (in seconds) of each all-pass line. */ + length = LATE_ALLPASS_LENGTHS[i] * multiplier; + + /* Calculate the delay offset for each all-pass line. */ + Late->VecAp.Offset[i][1] = float2int(length * frequency); + + /* Calculate the length (in seconds) of each delay line. */ + length = LATE_LINE_LENGTHS[i] * multiplier; + + /* Calculate the delay offset for each delay line. */ + Late->Offset[i][1] = float2int(length*frequency + 0.5f); + + /* Approximate the absorption that the vector all-pass would exhibit + * given the current diffusion so we don't have to process a full T60 + * filter for each of its four lines. + */ + length += lerp(LATE_ALLPASS_LENGTHS[i], + (LATE_ALLPASS_LENGTHS[0] + LATE_ALLPASS_LENGTHS[1] + + LATE_ALLPASS_LENGTHS[2] + LATE_ALLPASS_LENGTHS[3]) / 4.0f, + diffusion) * multiplier; + + /* Calculate the T60 damping coefficients for each line. */ + CalcT60DampingCoeffs(length, lfDecayTime, mfDecayTime, hfDecayTime, + lf0norm, hf0norm, &Late->T60[i]); + } +} + +/* Creates a transform matrix given a reverb vector. The vector pans the reverb + * reflections toward the given direction, using its magnitude (up to 1) as a + * focal strength. This function results in a B-Format transformation matrix + * that spatially focuses the signal in the desired direction. + */ +static aluMatrixf GetTransformFromVector(const ALfloat *vec) +{ + aluMatrixf focus; + ALfloat norm[3]; + ALfloat mag; + + /* Normalize the panning vector according to the N3D scale, which has an + * extra sqrt(3) term on the directional components. Converting from OpenAL + * to B-Format also requires negating X (ACN 1) and Z (ACN 3). Note however + * that the reverb panning vectors use left-handed coordinates, unlike the + * rest of OpenAL which use right-handed. This is fixed by negating Z, + * which cancels out with the B-Format Z negation. + */ + mag = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); + if(mag > 1.0f) + { + norm[0] = vec[0] / mag * -SQRTF_3; + norm[1] = vec[1] / mag * SQRTF_3; + norm[2] = vec[2] / mag * SQRTF_3; + mag = 1.0f; + } + else + { + /* If the magnitude is less than or equal to 1, just apply the sqrt(3) + * term. There's no need to renormalize the magnitude since it would + * just be reapplied in the matrix. + */ + norm[0] = vec[0] * -SQRTF_3; + norm[1] = vec[1] * SQRTF_3; + norm[2] = vec[2] * SQRTF_3; + } + + aluMatrixfSet(&focus, + 1.0f, 0.0f, 0.0f, 0.0f, + norm[0], 1.0f-mag, 0.0f, 0.0f, + norm[1], 0.0f, 1.0f-mag, 0.0f, + norm[2], 0.0f, 0.0f, 1.0f-mag + ); + + return focus; +} + +/* Update the early and late 3D panning gains. */ +static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, const ALfloat earlyGain, const ALfloat lateGain, ReverbState *State) +{ + aluMatrixf transform, rot; + ALsizei i; + + STATIC_CAST(ALeffectState,State)->OutBuffer = Device->FOAOut.Buffer; + STATIC_CAST(ALeffectState,State)->OutChannels = Device->FOAOut.NumChannels; + + /* Note: _res is transposed. */ +#define MATRIX_MULT(_res, _m1, _m2) do { \ + int row, col; \ + for(col = 0;col < 4;col++) \ + { \ + for(row = 0;row < 4;row++) \ + _res.m[col][row] = _m1.m[row][0]*_m2.m[0][col] + _m1.m[row][1]*_m2.m[1][col] + \ + _m1.m[row][2]*_m2.m[2][col] + _m1.m[row][3]*_m2.m[3][col]; \ + } \ +} while(0) + /* Create a matrix that first converts A-Format to B-Format, then + * transforms the B-Format signal according to the panning vector. + */ + rot = GetTransformFromVector(ReflectionsPan); + MATRIX_MULT(transform, rot, A2B); + memset(&State->Early.PanGain, 0, sizeof(State->Early.PanGain)); + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(&Device->FOAOut, transform.m[i], earlyGain, + State->Early.PanGain[i]); + + rot = GetTransformFromVector(LateReverbPan); + MATRIX_MULT(transform, rot, A2B); + memset(&State->Late.PanGain, 0, sizeof(State->Late.PanGain)); + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(&Device->FOAOut, transform.m[i], lateGain, + State->Late.PanGain[i]); +#undef MATRIX_MULT +} + +static void ReverbState_update(ReverbState *State, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) +{ + const ALCdevice *Device = Context->Device; + const ALlistener *Listener = Context->Listener; + ALuint frequency = Device->Frequency; + ALfloat lf0norm, hf0norm, hfRatio; + ALfloat lfDecayTime, hfDecayTime; + ALfloat gain, gainlf, gainhf; + ALsizei i; + + /* Calculate the master filters */ + hf0norm = minf(props->Reverb.HFReference / frequency, 0.49f); + /* Restrict the filter gains from going below -60dB to keep the filter from + * killing most of the signal. + */ + gainhf = maxf(props->Reverb.GainHF, 0.001f); + BiquadFilter_setParams(&State->Filter[0].Lp, BiquadType_HighShelf, gainhf, hf0norm, + calc_rcpQ_from_slope(gainhf, 1.0f)); + lf0norm = minf(props->Reverb.LFReference / frequency, 0.49f); + gainlf = maxf(props->Reverb.GainLF, 0.001f); + BiquadFilter_setParams(&State->Filter[0].Hp, BiquadType_LowShelf, gainlf, lf0norm, + calc_rcpQ_from_slope(gainlf, 1.0f)); + for(i = 1;i < NUM_LINES;i++) + { + BiquadFilter_copyParams(&State->Filter[i].Lp, &State->Filter[0].Lp); + BiquadFilter_copyParams(&State->Filter[i].Hp, &State->Filter[0].Hp); + } + + /* Update the main effect delay and associated taps. */ + UpdateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay, + props->Reverb.Density, props->Reverb.DecayTime, frequency, + State); + + /* Update the early lines. */ + UpdateEarlyLines(props->Reverb.Density, props->Reverb.Diffusion, + props->Reverb.DecayTime, frequency, &State->Early); + + /* Get the mixing matrix coefficients. */ + CalcMatrixCoeffs(props->Reverb.Diffusion, &State->MixX, &State->MixY); + + /* If the HF limit parameter is flagged, calculate an appropriate limit + * based on the air absorption parameter. + */ + hfRatio = props->Reverb.DecayHFRatio; + if(props->Reverb.DecayHFLimit && props->Reverb.AirAbsorptionGainHF < 1.0f) + hfRatio = CalcLimitedHfRatio(hfRatio, props->Reverb.AirAbsorptionGainHF, + props->Reverb.DecayTime, Listener->Params.ReverbSpeedOfSound + ); + + /* Calculate the LF/HF decay times. */ + lfDecayTime = clampf(props->Reverb.DecayTime * props->Reverb.DecayLFRatio, + AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME); + hfDecayTime = clampf(props->Reverb.DecayTime * hfRatio, + AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME); + + /* Update the late lines. */ + UpdateLateLines(props->Reverb.Density, props->Reverb.Diffusion, + lfDecayTime, props->Reverb.DecayTime, hfDecayTime, lf0norm, hf0norm, + frequency, &State->Late + ); + + /* Update early and late 3D panning. */ + gain = props->Reverb.Gain * Slot->Params.Gain * ReverbBoost; + Update3DPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, + props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain, + State); + + /* Calculate the max update size from the smallest relevant delay. */ + State->MaxUpdate[1] = mini(MAX_UPDATE_SAMPLES, + mini(State->Early.Offset[0][1], State->Late.Offset[0][1]) + ); + + /* Determine if delay-line cross-fading is required. Density is essentially + * a master control for the feedback delays, so changes the offsets of many + * delay lines. + */ + if(State->Params.Density != props->Reverb.Density || + /* Diffusion and decay times influences the decay rate (gain) of the + * late reverb T60 filter. + */ + State->Params.Diffusion != props->Reverb.Diffusion || + State->Params.DecayTime != props->Reverb.DecayTime || + State->Params.HFDecayTime != hfDecayTime || + State->Params.LFDecayTime != lfDecayTime || + /* HF/LF References control the weighting used to calculate the density + * gain. + */ + State->Params.HFReference != props->Reverb.HFReference || + State->Params.LFReference != props->Reverb.LFReference) + State->FadeCount = 0; + State->Params.Density = props->Reverb.Density; + State->Params.Diffusion = props->Reverb.Diffusion; + State->Params.DecayTime = props->Reverb.DecayTime; + State->Params.HFDecayTime = hfDecayTime; + State->Params.LFDecayTime = lfDecayTime; + State->Params.HFReference = props->Reverb.HFReference; + State->Params.LFReference = props->Reverb.LFReference; +} + + +/************************************** + * Effect Processing * + **************************************/ + +/* Basic delay line input/output routines. */ +static inline ALfloat DelayLineOut(const DelayLineI *Delay, const ALsizei offset, const ALsizei c) +{ + return Delay->Line[offset&Delay->Mask][c]; +} + +/* Cross-faded delay line output routine. Instead of interpolating the + * offsets, this interpolates (cross-fades) the outputs at each offset. + */ +static inline ALfloat FadedDelayLineOut(const DelayLineI *Delay, const ALsizei off0, + const ALsizei off1, const ALsizei c, + const ALfloat sc0, const ALfloat sc1) +{ + return Delay->Line[off0&Delay->Mask][c]*sc0 + + Delay->Line[off1&Delay->Mask][c]*sc1; +} + + +static inline void DelayLineIn(const DelayLineI *Delay, ALsizei offset, const ALsizei c, + const ALfloat *RESTRICT in, ALsizei count) +{ + ALsizei i; + for(i = 0;i < count;i++) + Delay->Line[(offset++)&Delay->Mask][c] = *(in++); +} + +/* Applies a scattering matrix to the 4-line (vector) input. This is used + * for both the below vector all-pass model and to perform modal feed-back + * delay network (FDN) mixing. + * + * The matrix is derived from a skew-symmetric matrix to form a 4D rotation + * matrix with a single unitary rotational parameter: + * + * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2 + * [ -a, d, c, -b ] + * [ -b, -c, d, a ] + * [ -c, b, -a, d ] + * + * The rotation is constructed from the effect's diffusion parameter, + * yielding: + * + * 1 = x^2 + 3 y^2 + * + * Where a, b, and c are the coefficient y with differing signs, and d is the + * coefficient x. The final matrix is thus: + * + * [ x, y, -y, y ] n = sqrt(matrix_order - 1) + * [ -y, x, y, y ] t = diffusion_parameter * atan(n) + * [ y, -y, x, y ] x = cos(t) + * [ -y, -y, -y, x ] y = sin(t) / n + * + * Any square orthogonal matrix with an order that is a power of two will + * work (where ^T is transpose, ^-1 is inverse): + * + * M^T = M^-1 + * + * Using that knowledge, finding an appropriate matrix can be accomplished + * naively by searching all combinations of: + * + * M = D + S - S^T + * + * Where D is a diagonal matrix (of x), and S is a triangular matrix (of y) + * whose combination of signs are being iterated. + */ +static inline void VectorPartialScatter(ALfloat *RESTRICT out, const ALfloat *RESTRICT in, + const ALfloat xCoeff, const ALfloat yCoeff) +{ + out[0] = xCoeff*in[0] + yCoeff*( in[1] + -in[2] + in[3]); + out[1] = xCoeff*in[1] + yCoeff*(-in[0] + in[2] + in[3]); + out[2] = xCoeff*in[2] + yCoeff*( in[0] + -in[1] + in[3]); + out[3] = xCoeff*in[3] + yCoeff*(-in[0] + -in[1] + -in[2] ); +} +#define VectorScatterDelayIn(delay, o, in, xcoeff, ycoeff) \ + VectorPartialScatter((delay)->Line[(o)&(delay)->Mask], in, xcoeff, ycoeff) + +/* Utilizes the above, but reverses the input channels. */ +static inline void VectorScatterRevDelayIn(const DelayLineI *Delay, ALint offset, + const ALfloat xCoeff, const ALfloat yCoeff, + const ALfloat (*RESTRICT in)[MAX_UPDATE_SAMPLES], + const ALsizei count) +{ + const DelayLineI delay = *Delay; + ALsizei i, j; + + for(i = 0;i < count;++i) + { + ALfloat f[NUM_LINES]; + for(j = 0;j < NUM_LINES;j++) + f[NUM_LINES-1-j] = in[j][i]; + + VectorScatterDelayIn(&delay, offset++, f, xCoeff, yCoeff); + } +} + +/* This applies a Gerzon multiple-in/multiple-out (MIMO) vector all-pass + * filter to the 4-line input. + * + * It works by vectorizing a regular all-pass filter and replacing the delay + * element with a scattering matrix (like the one above) and a diagonal + * matrix of delay elements. + * + * Two static specializations are used for transitional (cross-faded) delay + * line processing and non-transitional processing. + */ +static void VectorAllpass_Unfaded(ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES], ALsizei offset, + const ALfloat xCoeff, const ALfloat yCoeff, ALsizei todo, + VecAllpass *Vap) +{ + const DelayLineI delay = Vap->Delay; + const ALfloat feedCoeff = Vap->Coeff; + ALsizei vap_offset[NUM_LINES]; + ALsizei i, j; + + ASSUME(todo > 0); + + for(j = 0;j < NUM_LINES;j++) + vap_offset[j] = offset-Vap->Offset[j][0]; + for(i = 0;i < todo;i++) + { + ALfloat f[NUM_LINES]; + + for(j = 0;j < NUM_LINES;j++) + { + ALfloat input = samples[j][i]; + ALfloat out = DelayLineOut(&delay, vap_offset[j]++, j) - feedCoeff*input; + f[j] = input + feedCoeff*out; + + samples[j][i] = out; + } + + VectorScatterDelayIn(&delay, offset, f, xCoeff, yCoeff); + ++offset; + } +} +static void VectorAllpass_Faded(ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES], ALsizei offset, + const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, + ALsizei todo, VecAllpass *Vap) +{ + const DelayLineI delay = Vap->Delay; + const ALfloat feedCoeff = Vap->Coeff; + ALsizei vap_offset[NUM_LINES][2]; + ALsizei i, j; + + ASSUME(todo > 0); + + fade *= 1.0f/FADE_SAMPLES; + for(j = 0;j < NUM_LINES;j++) + { + vap_offset[j][0] = offset-Vap->Offset[j][0]; + vap_offset[j][1] = offset-Vap->Offset[j][1]; + } + for(i = 0;i < todo;i++) + { + ALfloat f[NUM_LINES]; + + for(j = 0;j < NUM_LINES;j++) + { + ALfloat input = samples[j][i]; + ALfloat out = + FadedDelayLineOut(&delay, vap_offset[j][0]++, vap_offset[j][1]++, j, + 1.0f-fade, fade + ) - feedCoeff*input; + f[j] = input + feedCoeff*out; + + samples[j][i] = out; + } + fade += FadeStep; + + VectorScatterDelayIn(&delay, offset, f, xCoeff, yCoeff); + ++offset; + } +} + +/* This generates early reflections. + * + * This is done by obtaining the primary reflections (those arriving from the + * same direction as the source) from the main delay line. These are + * attenuated and all-pass filtered (based on the diffusion parameter). + * + * The early lines are then fed in reverse (according to the approximately + * opposite spatial location of the A-Format lines) to create the secondary + * reflections (those arriving from the opposite direction as the source). + * + * The early response is then completed by combining the primary reflections + * with the delayed and attenuated output from the early lines. + * + * Finally, the early response is reversed, scattered (based on diffusion), + * and fed into the late reverb section of the main delay line. + * + * Two static specializations are used for transitional (cross-faded) delay + * line processing and non-transitional processing. + */ +static void EarlyReflection_Unfaded(ReverbState *State, ALsizei offset, const ALsizei todo, + ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) +{ + ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; + const DelayLineI early_delay = State->Early.Delay; + const DelayLineI main_delay = State->Delay; + const ALfloat mixX = State->MixX; + const ALfloat mixY = State->MixY; + ALsizei late_feed_tap; + ALsizei i, j; + + ASSUME(todo > 0); + + /* First, load decorrelated samples from the main delay line as the primary + * reflections. + */ + for(j = 0;j < NUM_LINES;j++) + { + ALsizei early_delay_tap = offset - State->EarlyDelayTap[j][0]; + ALfloat coeff = State->EarlyDelayCoeff[j][0]; + for(i = 0;i < todo;i++) + temps[j][i] = DelayLineOut(&main_delay, early_delay_tap++, j) * coeff; + } + + /* Apply a vector all-pass, to help color the initial reflections based on + * the diffusion strength. + */ + VectorAllpass_Unfaded(temps, offset, mixX, mixY, todo, &State->Early.VecAp); + + /* Apply a delay and bounce to generate secondary reflections, combine with + * the primary reflections and write out the result for mixing. + */ + for(j = 0;j < NUM_LINES;j++) + { + ALint early_feedb_tap = offset - State->Early.Offset[j][0]; + ALfloat early_feedb_coeff = State->Early.Coeff[j][0]; + + for(i = 0;i < todo;i++) + out[j][i] = DelayLineOut(&early_delay, early_feedb_tap++, j)*early_feedb_coeff + + temps[j][i]; + } + for(j = 0;j < NUM_LINES;j++) + DelayLineIn(&early_delay, offset, NUM_LINES-1-j, temps[j], todo); + + /* Also write the result back to the main delay line for the late reverb + * stage to pick up at the appropriate time, appplying a scatter and + * bounce to improve the initial diffusion in the late reverb. + */ + late_feed_tap = offset - State->LateFeedTap; + VectorScatterRevDelayIn(&main_delay, late_feed_tap, mixX, mixY, out, todo); +} +static void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsizei todo, + const ALfloat fade, ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) +{ + ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; + const DelayLineI early_delay = State->Early.Delay; + const DelayLineI main_delay = State->Delay; + const ALfloat mixX = State->MixX; + const ALfloat mixY = State->MixY; + ALsizei late_feed_tap; + ALsizei i, j; + + ASSUME(todo > 0); + + for(j = 0;j < NUM_LINES;j++) + { + ALsizei early_delay_tap0 = offset - State->EarlyDelayTap[j][0]; + ALsizei early_delay_tap1 = offset - State->EarlyDelayTap[j][1]; + ALfloat oldCoeff = State->EarlyDelayCoeff[j][0]; + ALfloat oldCoeffStep = -oldCoeff / FADE_SAMPLES; + ALfloat newCoeffStep = State->EarlyDelayCoeff[j][1] / FADE_SAMPLES; + ALfloat fadeCount = fade; + + for(i = 0;i < todo;i++) + { + const ALfloat fade0 = oldCoeff + oldCoeffStep*fadeCount; + const ALfloat fade1 = newCoeffStep*fadeCount; + temps[j][i] = FadedDelayLineOut(&main_delay, + early_delay_tap0++, early_delay_tap1++, j, fade0, fade1 + ); + fadeCount += 1.0f; + } + } + + VectorAllpass_Faded(temps, offset, mixX, mixY, fade, todo, &State->Early.VecAp); + + for(j = 0;j < NUM_LINES;j++) + { + ALint feedb_tap0 = offset - State->Early.Offset[j][0]; + ALint feedb_tap1 = offset - State->Early.Offset[j][1]; + ALfloat feedb_oldCoeff = State->Early.Coeff[j][0]; + ALfloat feedb_oldCoeffStep = -feedb_oldCoeff / FADE_SAMPLES; + ALfloat feedb_newCoeffStep = State->Early.Coeff[j][1] / FADE_SAMPLES; + ALfloat fadeCount = fade; + + for(i = 0;i < todo;i++) + { + const ALfloat fade0 = feedb_oldCoeff + feedb_oldCoeffStep*fadeCount; + const ALfloat fade1 = feedb_newCoeffStep*fadeCount; + out[j][i] = FadedDelayLineOut(&early_delay, + feedb_tap0++, feedb_tap1++, j, fade0, fade1 + ) + temps[j][i]; + fadeCount += 1.0f; + } + } + for(j = 0;j < NUM_LINES;j++) + DelayLineIn(&early_delay, offset, NUM_LINES-1-j, temps[j], todo); + + late_feed_tap = offset - State->LateFeedTap; + VectorScatterRevDelayIn(&main_delay, late_feed_tap, mixX, mixY, out, todo); +} + +/* Applies the two T60 damping filter sections. */ +static inline void LateT60Filter(ALfloat *RESTRICT samples, const ALsizei todo, T60Filter *filter) +{ + ALfloat temp[MAX_UPDATE_SAMPLES]; + BiquadFilter_process(&filter->HFFilter, temp, samples, todo); + BiquadFilter_process(&filter->LFFilter, samples, temp, todo); +} + +/* This generates the reverb tail using a modified feed-back delay network + * (FDN). + * + * Results from the early reflections are mixed with the output from the late + * delay lines. + * + * The late response is then completed by T60 and all-pass filtering the mix. + * + * Finally, the lines are reversed (so they feed their opposite directions) + * and scattered with the FDN matrix before re-feeding the delay lines. + * + * Two variations are made, one for for transitional (cross-faded) delay line + * processing and one for non-transitional processing. + */ +static void LateReverb_Unfaded(ReverbState *State, ALsizei offset, const ALsizei todo, + ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) +{ + ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; + const DelayLineI late_delay = State->Late.Delay; + const DelayLineI main_delay = State->Delay; + const ALfloat mixX = State->MixX; + const ALfloat mixY = State->MixY; + ALsizei i, j; + + ASSUME(todo > 0); + + /* First, load decorrelated samples from the main and feedback delay lines. + * Filter the signal to apply its frequency-dependent decay. + */ + for(j = 0;j < NUM_LINES;j++) + { + ALsizei late_delay_tap = offset - State->LateDelayTap[j][0]; + ALsizei late_feedb_tap = offset - State->Late.Offset[j][0]; + ALfloat midGain = State->Late.T60[j].MidGain[0]; + const ALfloat densityGain = State->Late.DensityGain[0] * midGain; + for(i = 0;i < todo;i++) + temps[j][i] = DelayLineOut(&main_delay, late_delay_tap++, j)*densityGain + + DelayLineOut(&late_delay, late_feedb_tap++, j)*midGain; + LateT60Filter(temps[j], todo, &State->Late.T60[j]); + } + + /* Apply a vector all-pass to improve micro-surface diffusion, and write + * out the results for mixing. + */ + VectorAllpass_Unfaded(temps, offset, mixX, mixY, todo, &State->Late.VecAp); + + for(j = 0;j < NUM_LINES;j++) + memcpy(out[j], temps[j], todo*sizeof(ALfloat)); + + /* Finally, scatter and bounce the results to refeed the feedback buffer. */ + VectorScatterRevDelayIn(&late_delay, offset, mixX, mixY, out, todo); +} +static void LateReverb_Faded(ReverbState *State, ALsizei offset, const ALsizei todo, + const ALfloat fade, ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) +{ + ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; + const DelayLineI late_delay = State->Late.Delay; + const DelayLineI main_delay = State->Delay; + const ALfloat mixX = State->MixX; + const ALfloat mixY = State->MixY; + ALsizei i, j; + + ASSUME(todo > 0); + + for(j = 0;j < NUM_LINES;j++) + { + const ALfloat oldMidGain = State->Late.T60[j].MidGain[0]; + const ALfloat midGain = State->Late.T60[j].MidGain[1]; + const ALfloat oldMidStep = -oldMidGain / FADE_SAMPLES; + const ALfloat midStep = midGain / FADE_SAMPLES; + const ALfloat oldDensityGain = State->Late.DensityGain[0] * oldMidGain; + const ALfloat densityGain = State->Late.DensityGain[1] * midGain; + const ALfloat oldDensityStep = -oldDensityGain / FADE_SAMPLES; + const ALfloat densityStep = densityGain / FADE_SAMPLES; + ALsizei late_delay_tap0 = offset - State->LateDelayTap[j][0]; + ALsizei late_delay_tap1 = offset - State->LateDelayTap[j][1]; + ALsizei late_feedb_tap0 = offset - State->Late.Offset[j][0]; + ALsizei late_feedb_tap1 = offset - State->Late.Offset[j][1]; + ALfloat fadeCount = fade; + + for(i = 0;i < todo;i++) + { + const ALfloat fade0 = oldDensityGain + oldDensityStep*fadeCount; + const ALfloat fade1 = densityStep*fadeCount; + const ALfloat gfade0 = oldMidGain + oldMidStep*fadeCount; + const ALfloat gfade1 = midStep*fadeCount; + temps[j][i] = + FadedDelayLineOut(&main_delay, late_delay_tap0++, late_delay_tap1++, j, + fade0, fade1) + + FadedDelayLineOut(&late_delay, late_feedb_tap0++, late_feedb_tap1++, j, + gfade0, gfade1); + fadeCount += 1.0f; + } + LateT60Filter(temps[j], todo, &State->Late.T60[j]); + } + + VectorAllpass_Faded(temps, offset, mixX, mixY, fade, todo, &State->Late.VecAp); + + for(j = 0;j < NUM_LINES;j++) + memcpy(out[j], temps[j], todo*sizeof(ALfloat)); + + VectorScatterRevDelayIn(&late_delay, offset, mixX, mixY, temps, todo); +} + +static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +{ + ALfloat (*RESTRICT afmt)[MAX_UPDATE_SAMPLES] = State->TempSamples; + ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES] = State->MixSamples; + ALsizei fadeCount = State->FadeCount; + ALsizei offset = State->Offset; + ALsizei base, c; + + /* Process reverb for these samples. */ + for(base = 0;base < SamplesToDo;) + { + ALsizei todo = SamplesToDo - base; + /* If cross-fading, don't do more samples than there are to fade. */ + if(FADE_SAMPLES-fadeCount > 0) + { + todo = mini(todo, FADE_SAMPLES-fadeCount); + todo = mini(todo, State->MaxUpdate[0]); + } + todo = mini(todo, State->MaxUpdate[1]); + /* If this is not the final update, ensure the update size is a + * multiple of 4 for the SIMD mixers. + */ + if(todo < SamplesToDo-base) + todo &= ~3; + + /* Convert B-Format to A-Format for processing. */ + memset(afmt, 0, sizeof(*afmt)*NUM_LINES); + for(c = 0;c < NUM_LINES;c++) + MixRowSamples(afmt[c], B2A.m[c], + SamplesIn, MAX_EFFECT_CHANNELS, base, todo + ); + + /* Process the samples for reverb. */ + for(c = 0;c < NUM_LINES;c++) + { + /* Band-pass the incoming samples. */ + BiquadFilter_process(&State->Filter[c].Lp, samples[0], afmt[c], todo); + BiquadFilter_process(&State->Filter[c].Hp, samples[1], samples[0], todo); + + /* Feed the initial delay line. */ + DelayLineIn(&State->Delay, offset, c, samples[1], todo); + } + + if(UNLIKELY(fadeCount < FADE_SAMPLES)) + { + ALfloat fade = (ALfloat)fadeCount; + + /* Generate early reflections. */ + EarlyReflection_Faded(State, offset, todo, fade, samples); + /* Mix the A-Format results to output, implicitly converting back + * to B-Format. + */ + for(c = 0;c < NUM_LINES;c++) + MixSamples(samples[c], NumChannels, SamplesOut, + State->Early.CurrentGain[c], State->Early.PanGain[c], + SamplesToDo-base, base, todo + ); + + /* Generate and mix late reverb. */ + LateReverb_Faded(State, offset, todo, fade, samples); + for(c = 0;c < NUM_LINES;c++) + MixSamples(samples[c], NumChannels, SamplesOut, + State->Late.CurrentGain[c], State->Late.PanGain[c], + SamplesToDo-base, base, todo + ); + + /* Step fading forward. */ + fadeCount += todo; + if(LIKELY(fadeCount >= FADE_SAMPLES)) + { + /* Update the cross-fading delay line taps. */ + fadeCount = FADE_SAMPLES; + for(c = 0;c < NUM_LINES;c++) + { + State->EarlyDelayTap[c][0] = State->EarlyDelayTap[c][1]; + State->EarlyDelayCoeff[c][0] = State->EarlyDelayCoeff[c][1]; + State->Early.VecAp.Offset[c][0] = State->Early.VecAp.Offset[c][1]; + State->Early.Offset[c][0] = State->Early.Offset[c][1]; + State->Early.Coeff[c][0] = State->Early.Coeff[c][1]; + State->LateDelayTap[c][0] = State->LateDelayTap[c][1]; + State->Late.VecAp.Offset[c][0] = State->Late.VecAp.Offset[c][1]; + State->Late.Offset[c][0] = State->Late.Offset[c][1]; + State->Late.T60[c].MidGain[0] = State->Late.T60[c].MidGain[1]; + } + State->Late.DensityGain[0] = State->Late.DensityGain[1]; + State->MaxUpdate[0] = State->MaxUpdate[1]; + } + } + else + { + /* Generate and mix early reflections. */ + EarlyReflection_Unfaded(State, offset, todo, samples); + for(c = 0;c < NUM_LINES;c++) + MixSamples(samples[c], NumChannels, SamplesOut, + State->Early.CurrentGain[c], State->Early.PanGain[c], + SamplesToDo-base, base, todo + ); + + /* Generate and mix late reverb. */ + LateReverb_Unfaded(State, offset, todo, samples); + for(c = 0;c < NUM_LINES;c++) + MixSamples(samples[c], NumChannels, SamplesOut, + State->Late.CurrentGain[c], State->Late.PanGain[c], + SamplesToDo-base, base, todo + ); + } + + /* Step all delays forward. */ + offset += todo; + + base += todo; + } + State->Offset = offset; + State->FadeCount = fadeCount; +} + + +struct ReverbStateFactory final : public EffectStateFactory { + ReverbStateFactory() noexcept; +}; + +static ALeffectState *ReverbStateFactory_create(ReverbStateFactory* UNUSED(factory)) +{ + ReverbState *state; + + NEW_OBJ0(state, ReverbState)(); + if(!state) return NULL; + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_EFFECTSTATEFACTORY_VTABLE(ReverbStateFactory); + +ReverbStateFactory::ReverbStateFactory() noexcept + : EffectStateFactory{GET_VTABLE2(ReverbStateFactory, EffectStateFactory)} +{ +} + +EffectStateFactory *ReverbStateFactory_getFactory(void) +{ + static ReverbStateFactory ReverbFactory{}; + return STATIC_CAST(EffectStateFactory, &ReverbFactory); +} + + +void ALeaxreverb_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_EAXREVERB_DECAY_HFLIMIT: + if(!(val >= AL_EAXREVERB_MIN_DECAY_HFLIMIT && val <= AL_EAXREVERB_MAX_DECAY_HFLIMIT)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay hflimit out of range"); + props->Reverb.DecayHFLimit = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb integer property 0x%04x", + param); + } +} +void ALeaxreverb_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ ALeaxreverb_setParami(effect, context, param, vals[0]); } +void ALeaxreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_EAXREVERB_DENSITY: + if(!(val >= AL_EAXREVERB_MIN_DENSITY && val <= AL_EAXREVERB_MAX_DENSITY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb density out of range"); + props->Reverb.Density = val; + break; + + case AL_EAXREVERB_DIFFUSION: + if(!(val >= AL_EAXREVERB_MIN_DIFFUSION && val <= AL_EAXREVERB_MAX_DIFFUSION)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb diffusion out of range"); + props->Reverb.Diffusion = val; + break; + + case AL_EAXREVERB_GAIN: + if(!(val >= AL_EAXREVERB_MIN_GAIN && val <= AL_EAXREVERB_MAX_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb gain out of range"); + props->Reverb.Gain = val; + break; + + case AL_EAXREVERB_GAINHF: + if(!(val >= AL_EAXREVERB_MIN_GAINHF && val <= AL_EAXREVERB_MAX_GAINHF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb gainhf out of range"); + props->Reverb.GainHF = val; + break; + + case AL_EAXREVERB_GAINLF: + if(!(val >= AL_EAXREVERB_MIN_GAINLF && val <= AL_EAXREVERB_MAX_GAINLF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb gainlf out of range"); + props->Reverb.GainLF = val; + break; + + case AL_EAXREVERB_DECAY_TIME: + if(!(val >= AL_EAXREVERB_MIN_DECAY_TIME && val <= AL_EAXREVERB_MAX_DECAY_TIME)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay time out of range"); + props->Reverb.DecayTime = val; + break; + + case AL_EAXREVERB_DECAY_HFRATIO: + if(!(val >= AL_EAXREVERB_MIN_DECAY_HFRATIO && val <= AL_EAXREVERB_MAX_DECAY_HFRATIO)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay hfratio out of range"); + props->Reverb.DecayHFRatio = val; + break; + + case AL_EAXREVERB_DECAY_LFRATIO: + if(!(val >= AL_EAXREVERB_MIN_DECAY_LFRATIO && val <= AL_EAXREVERB_MAX_DECAY_LFRATIO)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay lfratio out of range"); + props->Reverb.DecayLFRatio = val; + break; + + case AL_EAXREVERB_REFLECTIONS_GAIN: + if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_GAIN && val <= AL_EAXREVERB_MAX_REFLECTIONS_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb reflections gain out of range"); + props->Reverb.ReflectionsGain = val; + break; + + case AL_EAXREVERB_REFLECTIONS_DELAY: + if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_DELAY && val <= AL_EAXREVERB_MAX_REFLECTIONS_DELAY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb reflections delay out of range"); + props->Reverb.ReflectionsDelay = val; + break; + + case AL_EAXREVERB_LATE_REVERB_GAIN: + if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_GAIN && val <= AL_EAXREVERB_MAX_LATE_REVERB_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb late reverb gain out of range"); + props->Reverb.LateReverbGain = val; + break; + + case AL_EAXREVERB_LATE_REVERB_DELAY: + if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_DELAY && val <= AL_EAXREVERB_MAX_LATE_REVERB_DELAY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb late reverb delay out of range"); + props->Reverb.LateReverbDelay = val; + break; + + case AL_EAXREVERB_AIR_ABSORPTION_GAINHF: + if(!(val >= AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb air absorption gainhf out of range"); + props->Reverb.AirAbsorptionGainHF = val; + break; + + case AL_EAXREVERB_ECHO_TIME: + if(!(val >= AL_EAXREVERB_MIN_ECHO_TIME && val <= AL_EAXREVERB_MAX_ECHO_TIME)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb echo time out of range"); + props->Reverb.EchoTime = val; + break; + + case AL_EAXREVERB_ECHO_DEPTH: + if(!(val >= AL_EAXREVERB_MIN_ECHO_DEPTH && val <= AL_EAXREVERB_MAX_ECHO_DEPTH)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb echo depth out of range"); + props->Reverb.EchoDepth = val; + break; + + case AL_EAXREVERB_MODULATION_TIME: + if(!(val >= AL_EAXREVERB_MIN_MODULATION_TIME && val <= AL_EAXREVERB_MAX_MODULATION_TIME)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb modulation time out of range"); + props->Reverb.ModulationTime = val; + break; + + case AL_EAXREVERB_MODULATION_DEPTH: + if(!(val >= AL_EAXREVERB_MIN_MODULATION_DEPTH && val <= AL_EAXREVERB_MAX_MODULATION_DEPTH)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb modulation depth out of range"); + props->Reverb.ModulationDepth = val; + break; + + case AL_EAXREVERB_HFREFERENCE: + if(!(val >= AL_EAXREVERB_MIN_HFREFERENCE && val <= AL_EAXREVERB_MAX_HFREFERENCE)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb hfreference out of range"); + props->Reverb.HFReference = val; + break; + + case AL_EAXREVERB_LFREFERENCE: + if(!(val >= AL_EAXREVERB_MIN_LFREFERENCE && val <= AL_EAXREVERB_MAX_LFREFERENCE)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb lfreference out of range"); + props->Reverb.LFReference = val; + break; + + case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR: + if(!(val >= AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb room rolloff factor out of range"); + props->Reverb.RoomRolloffFactor = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", + param); + } +} +void ALeaxreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_EAXREVERB_REFLECTIONS_PAN: + if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2]))) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb reflections pan out of range"); + props->Reverb.ReflectionsPan[0] = vals[0]; + props->Reverb.ReflectionsPan[1] = vals[1]; + props->Reverb.ReflectionsPan[2] = vals[2]; + break; + case AL_EAXREVERB_LATE_REVERB_PAN: + if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2]))) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb late reverb pan out of range"); + props->Reverb.LateReverbPan[0] = vals[0]; + props->Reverb.LateReverbPan[1] = vals[1]; + props->Reverb.LateReverbPan[2] = vals[2]; + break; + + default: + ALeaxreverb_setParamf(effect, context, param, vals[0]); + break; + } +} + +void ALeaxreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_EAXREVERB_DECAY_HFLIMIT: + *val = props->Reverb.DecayHFLimit; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb integer property 0x%04x", + param); + } +} +void ALeaxreverb_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ ALeaxreverb_getParami(effect, context, param, vals); } +void ALeaxreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_EAXREVERB_DENSITY: + *val = props->Reverb.Density; + break; + + case AL_EAXREVERB_DIFFUSION: + *val = props->Reverb.Diffusion; + break; + + case AL_EAXREVERB_GAIN: + *val = props->Reverb.Gain; + break; + + case AL_EAXREVERB_GAINHF: + *val = props->Reverb.GainHF; + break; + + case AL_EAXREVERB_GAINLF: + *val = props->Reverb.GainLF; + break; + + case AL_EAXREVERB_DECAY_TIME: + *val = props->Reverb.DecayTime; + break; + + case AL_EAXREVERB_DECAY_HFRATIO: + *val = props->Reverb.DecayHFRatio; + break; + + case AL_EAXREVERB_DECAY_LFRATIO: + *val = props->Reverb.DecayLFRatio; + break; + + case AL_EAXREVERB_REFLECTIONS_GAIN: + *val = props->Reverb.ReflectionsGain; + break; + + case AL_EAXREVERB_REFLECTIONS_DELAY: + *val = props->Reverb.ReflectionsDelay; + break; + + case AL_EAXREVERB_LATE_REVERB_GAIN: + *val = props->Reverb.LateReverbGain; + break; + + case AL_EAXREVERB_LATE_REVERB_DELAY: + *val = props->Reverb.LateReverbDelay; + break; + + case AL_EAXREVERB_AIR_ABSORPTION_GAINHF: + *val = props->Reverb.AirAbsorptionGainHF; + break; + + case AL_EAXREVERB_ECHO_TIME: + *val = props->Reverb.EchoTime; + break; + + case AL_EAXREVERB_ECHO_DEPTH: + *val = props->Reverb.EchoDepth; + break; + + case AL_EAXREVERB_MODULATION_TIME: + *val = props->Reverb.ModulationTime; + break; + + case AL_EAXREVERB_MODULATION_DEPTH: + *val = props->Reverb.ModulationDepth; + break; + + case AL_EAXREVERB_HFREFERENCE: + *val = props->Reverb.HFReference; + break; + + case AL_EAXREVERB_LFREFERENCE: + *val = props->Reverb.LFReference; + break; + + case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR: + *val = props->Reverb.RoomRolloffFactor; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", + param); + } +} +void ALeaxreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_EAXREVERB_REFLECTIONS_PAN: + vals[0] = props->Reverb.ReflectionsPan[0]; + vals[1] = props->Reverb.ReflectionsPan[1]; + vals[2] = props->Reverb.ReflectionsPan[2]; + break; + case AL_EAXREVERB_LATE_REVERB_PAN: + vals[0] = props->Reverb.LateReverbPan[0]; + vals[1] = props->Reverb.LateReverbPan[1]; + vals[2] = props->Reverb.LateReverbPan[2]; + break; + + default: + ALeaxreverb_getParamf(effect, context, param, vals); + break; + } +} + +DEFINE_ALEFFECT_VTABLE(ALeaxreverb); + +void ALreverb_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_REVERB_DECAY_HFLIMIT: + if(!(val >= AL_REVERB_MIN_DECAY_HFLIMIT && val <= AL_REVERB_MAX_DECAY_HFLIMIT)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb decay hflimit out of range"); + props->Reverb.DecayHFLimit = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid reverb integer property 0x%04x", param); + } +} +void ALreverb_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ ALreverb_setParami(effect, context, param, vals[0]); } +void ALreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_REVERB_DENSITY: + if(!(val >= AL_REVERB_MIN_DENSITY && val <= AL_REVERB_MAX_DENSITY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb density out of range"); + props->Reverb.Density = val; + break; + + case AL_REVERB_DIFFUSION: + if(!(val >= AL_REVERB_MIN_DIFFUSION && val <= AL_REVERB_MAX_DIFFUSION)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb diffusion out of range"); + props->Reverb.Diffusion = val; + break; + + case AL_REVERB_GAIN: + if(!(val >= AL_REVERB_MIN_GAIN && val <= AL_REVERB_MAX_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb gain out of range"); + props->Reverb.Gain = val; + break; + + case AL_REVERB_GAINHF: + if(!(val >= AL_REVERB_MIN_GAINHF && val <= AL_REVERB_MAX_GAINHF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb gainhf out of range"); + props->Reverb.GainHF = val; + break; + + case AL_REVERB_DECAY_TIME: + if(!(val >= AL_REVERB_MIN_DECAY_TIME && val <= AL_REVERB_MAX_DECAY_TIME)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb decay time out of range"); + props->Reverb.DecayTime = val; + break; + + case AL_REVERB_DECAY_HFRATIO: + if(!(val >= AL_REVERB_MIN_DECAY_HFRATIO && val <= AL_REVERB_MAX_DECAY_HFRATIO)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb decay hfratio out of range"); + props->Reverb.DecayHFRatio = val; + break; + + case AL_REVERB_REFLECTIONS_GAIN: + if(!(val >= AL_REVERB_MIN_REFLECTIONS_GAIN && val <= AL_REVERB_MAX_REFLECTIONS_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb reflections gain out of range"); + props->Reverb.ReflectionsGain = val; + break; + + case AL_REVERB_REFLECTIONS_DELAY: + if(!(val >= AL_REVERB_MIN_REFLECTIONS_DELAY && val <= AL_REVERB_MAX_REFLECTIONS_DELAY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb reflections delay out of range"); + props->Reverb.ReflectionsDelay = val; + break; + + case AL_REVERB_LATE_REVERB_GAIN: + if(!(val >= AL_REVERB_MIN_LATE_REVERB_GAIN && val <= AL_REVERB_MAX_LATE_REVERB_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb late reverb gain out of range"); + props->Reverb.LateReverbGain = val; + break; + + case AL_REVERB_LATE_REVERB_DELAY: + if(!(val >= AL_REVERB_MIN_LATE_REVERB_DELAY && val <= AL_REVERB_MAX_LATE_REVERB_DELAY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb late reverb delay out of range"); + props->Reverb.LateReverbDelay = val; + break; + + case AL_REVERB_AIR_ABSORPTION_GAINHF: + if(!(val >= AL_REVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_REVERB_MAX_AIR_ABSORPTION_GAINHF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb air absorption gainhf out of range"); + props->Reverb.AirAbsorptionGainHF = val; + break; + + case AL_REVERB_ROOM_ROLLOFF_FACTOR: + if(!(val >= AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb room rolloff factor out of range"); + props->Reverb.RoomRolloffFactor = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid reverb float property 0x%04x", param); + } +} +void ALreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALreverb_setParamf(effect, context, param, vals[0]); } + +void ALreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_REVERB_DECAY_HFLIMIT: + *val = props->Reverb.DecayHFLimit; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid reverb integer property 0x%04x", param); + } +} +void ALreverb_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ ALreverb_getParami(effect, context, param, vals); } +void ALreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_REVERB_DENSITY: + *val = props->Reverb.Density; + break; + + case AL_REVERB_DIFFUSION: + *val = props->Reverb.Diffusion; + break; + + case AL_REVERB_GAIN: + *val = props->Reverb.Gain; + break; + + case AL_REVERB_GAINHF: + *val = props->Reverb.GainHF; + break; + + case AL_REVERB_DECAY_TIME: + *val = props->Reverb.DecayTime; + break; + + case AL_REVERB_DECAY_HFRATIO: + *val = props->Reverb.DecayHFRatio; + break; + + case AL_REVERB_REFLECTIONS_GAIN: + *val = props->Reverb.ReflectionsGain; + break; + + case AL_REVERB_REFLECTIONS_DELAY: + *val = props->Reverb.ReflectionsDelay; + break; + + case AL_REVERB_LATE_REVERB_GAIN: + *val = props->Reverb.LateReverbGain; + break; + + case AL_REVERB_LATE_REVERB_DELAY: + *val = props->Reverb.LateReverbDelay; + break; + + case AL_REVERB_AIR_ABSORPTION_GAINHF: + *val = props->Reverb.AirAbsorptionGainHF; + break; + + case AL_REVERB_ROOM_ROLLOFF_FACTOR: + *val = props->Reverb.RoomRolloffFactor; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid reverb float property 0x%04x", param); + } +} +void ALreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALreverb_getParamf(effect, context, param, vals); } + +DEFINE_ALEFFECT_VTABLE(ALreverb); diff --git a/CMakeLists.txt b/CMakeLists.txt index 429a6639..7a349762 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -822,7 +822,7 @@ SET(ALC_OBJS Alc/effects/modulator.c Alc/effects/null.c Alc/effects/pshifter.c - Alc/effects/reverb.c + Alc/effects/reverb.cpp Alc/filters/defs.h Alc/filters/filter.c Alc/filters/nfc.c -- cgit v1.2.3 From ee8e6733e1bddb7ca9ed5b93a1407b7113a44e6e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Nov 2018 21:55:11 -0800 Subject: Avoid using C-style TLS --- Alc/alc.cpp | 50 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 04792498..05112e28 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -795,7 +795,22 @@ constexpr ALchar alExtList[] = std::atomic LastNullDeviceError{ALC_NO_ERROR}; /* Thread-local current context */ -altss_t LocalContext; +std::atomic ThreadCtxProc{nullptr}; +thread_local class ThreadCtx { + ALCcontext *ctx{nullptr}; + +public: + ~ThreadCtx() + { + auto destruct = ThreadCtxProc.load(); + if(destruct && ctx) + destruct(ctx); + ctx = nullptr; + } + + ALCcontext *get() const noexcept { return ctx; } + void set(ALCcontext *ctx_) noexcept { ctx = ctx_; } +} LocalContext; /* Process-wide current context */ std::atomic GlobalContext{nullptr}; @@ -916,15 +931,12 @@ static void alc_deinit(void) __attribute__((destructor)); #error "No global initialization available on this platform!" #endif -static void ReleaseThreadCtx(void *ptr); +static void ReleaseThreadCtx(ALCcontext *ctx); static void alc_init(void) { - const char *str; - int ret; - LogFile = stderr; - str = getenv("__ALSOFT_HALF_ANGLE_CONES"); + const char *str{getenv("__ALSOFT_HALF_ANGLE_CONES")}; if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) ConeScale *= 0.5f; @@ -936,8 +948,7 @@ static void alc_init(void) if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) OverrideReverbSpeedOfSound = AL_TRUE; - ret = altss_create(&LocalContext, ReleaseThreadCtx); - assert(ret == althrd_success); + ThreadCtxProc = ReleaseThreadCtx; } static void alc_initconfig(void) @@ -1236,7 +1247,7 @@ static void alc_deinit_safe(void) FreeHrtfs(); FreeALConfig(); - altss_delete(LocalContext); + ThreadCtxProc = nullptr; if(LogFile != stderr) fclose(LogFile); @@ -2802,10 +2813,10 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) ALCcontext *origctx, *newhead; bool ret = true; - if(altss_get(LocalContext) == context) + if(LocalContext.get() == context) { WARN("%p released while current on thread\n", context); - altss_set(LocalContext, nullptr); + LocalContext.set(nullptr); ALCcontext_DecRef(context); } @@ -2858,9 +2869,8 @@ void ALCcontext_DecRef(ALCcontext *context) if(ref == 0) FreeContext(context); } -static void ReleaseThreadCtx(void *ptr) +static void ReleaseThreadCtx(ALCcontext *context) { - ALCcontext *context = static_cast(ptr); uint ref = DecrementRef(&context->ref); TRACEREF("%p decreasing refcount to %u\n", context, ref); ERR("Context %p current for thread being destroyed, possible leak!\n", context); @@ -2901,7 +2911,7 @@ static ALCboolean VerifyContext(ALCcontext **context) */ ALCcontext *GetContextRef(void) { - ALCcontext *context{static_cast(altss_get(LocalContext))}; + ALCcontext *context{LocalContext.get()}; if(context) ALCcontext_IncRef(context); else @@ -3920,7 +3930,7 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) */ ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) { - ALCcontext *Context{static_cast(altss_get(LocalContext))}; + ALCcontext *Context{LocalContext.get()}; if(!Context) Context = GlobalContext.load(); return Context; } @@ -3931,7 +3941,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) */ ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) { - return static_cast(altss_get(LocalContext)); + return LocalContext.get(); } @@ -3952,9 +3962,9 @@ ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) context = GlobalContext.exchange(context); if(context) ALCcontext_DecRef(context); - if((context=static_cast(altss_get(LocalContext))) != nullptr) + if((context=LocalContext.get()) != nullptr) { - altss_set(LocalContext, nullptr); + LocalContext.set(nullptr); ALCcontext_DecRef(context); } @@ -3974,8 +3984,8 @@ ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) return ALC_FALSE; } /* context's reference count is already incremented */ - ALCcontext *old{static_cast(altss_get(LocalContext))}; - altss_set(LocalContext, context); + ALCcontext *old{LocalContext.get()}; + LocalContext.set(context); if(old) ALCcontext_DecRef(old); return ALC_TRUE; -- cgit v1.2.3 From de8d8b5216650467661040b6b47ea649cf898c01 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Nov 2018 22:12:35 -0800 Subject: Remove unused altss types and methods --- Alc/alc.cpp | 4 ---- common/threads.c | 62 -------------------------------------------------------- common/threads.h | 35 -------------------------------- 3 files changed, 101 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 05112e28..4ce66eaf 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -886,10 +886,6 @@ BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD reason, LPVOID lpReserved) alc_init(); break; - case DLL_THREAD_DETACH: - althrd_thread_detach(); - break; - case DLL_PROCESS_DETACH: if(!lpReserved) alc_deinit(); diff --git a/common/threads.c b/common/threads.c index 16604267..4cdb329d 100644 --- a/common/threads.c +++ b/common/threads.c @@ -38,9 +38,6 @@ extern inline int almtx_lock(almtx_t *mtx); extern inline int almtx_unlock(almtx_t *mtx); extern inline int almtx_trylock(almtx_t *mtx); -extern inline void *altss_get(altss_t tss_id); -extern inline int altss_set(altss_t tss_id, void *val); - #ifndef UNUSED #if defined(__cplusplus) @@ -72,13 +69,6 @@ extern inline int altss_set(altss_t tss_id, void *val); */ static UIntMap ThrdIdHandle = UINTMAP_STATIC_INITIALIZE; -/* An associative map of uint:void* pairs. The key is the TLS index (given by - * TlsAlloc), and the value is the altss_dtor_t callback. When a thread exits, - * we iterate over the TLS indices for their thread-local value and call the - * destructor function with it if they're both not NULL. - */ -static UIntMap TlsDestructors = UINTMAP_STATIC_INITIALIZE; - void althrd_setname(althrd_t thr, const char *name) { @@ -228,25 +218,6 @@ int alsem_trywait(alsem_t *sem) } -int altss_create(altss_t *tss_id, altss_dtor_t callback) -{ - DWORD key = TlsAlloc(); - if(key == TLS_OUT_OF_INDEXES) - return althrd_error; - - *tss_id = key; - if(callback != NULL) - InsertUIntMapEntry(&TlsDestructors, key, callback); - return althrd_success; -} - -void altss_delete(altss_t tss_id) -{ - RemoveUIntMapKey(&TlsDestructors, tss_id); - TlsFree(tss_id); -} - - void alcall_once(alonce_flag *once, void (*callback)(void)) { LONG ret; @@ -261,25 +232,6 @@ void alcall_once(alonce_flag *once, void (*callback)(void)) void althrd_deinit(void) { ResetUIntMap(&ThrdIdHandle); - ResetUIntMap(&TlsDestructors); -} - -void althrd_thread_detach(void) -{ - ALsizei i; - - LockUIntMapRead(&TlsDestructors); - for(i = 0;i < TlsDestructors.size;i++) - { - void *ptr = altss_get(TlsDestructors.keys[i]); - altss_dtor_t callback = (altss_dtor_t)TlsDestructors.values[i]; - if(ptr) - { - if(callback) callback(ptr); - altss_set(TlsDestructors.keys[i], NULL); - } - } - UnlockUIntMapRead(&TlsDestructors); } #else @@ -295,7 +247,6 @@ void althrd_thread_detach(void) extern inline void alcall_once(alonce_flag *once, void (*callback)(void)); extern inline void althrd_deinit(void); -extern inline void althrd_thread_detach(void); void althrd_setname(althrd_t thr, const char *name) { @@ -511,17 +462,4 @@ int alsem_trywait(alsem_t *sem) #endif /* __APPLE__ */ - -int altss_create(altss_t *tss_id, altss_dtor_t callback) -{ - if(pthread_key_create(tss_id, callback) != 0) - return althrd_error; - return althrd_success; -} - -void altss_delete(altss_t tss_id) -{ - pthread_key_delete(tss_id); -} - #endif diff --git a/common/threads.h b/common/threads.h index 2cc65557..2d1c228d 100644 --- a/common/threads.h +++ b/common/threads.h @@ -31,7 +31,6 @@ enum { }; typedef int (*althrd_start_t)(void*); -typedef void (*altss_dtor_t)(void*); #ifdef _WIN32 @@ -42,7 +41,6 @@ typedef void (*altss_dtor_t)(void*); typedef DWORD althrd_t; typedef CRITICAL_SECTION almtx_t; typedef HANDLE alsem_t; -typedef DWORD altss_t; typedef LONG alonce_flag; #define AL_ONCE_FLAG_INIT 0 @@ -50,8 +48,6 @@ typedef LONG alonce_flag; void alcall_once(alonce_flag *once, void (*callback)(void)); void althrd_deinit(void); -void althrd_thread_detach(void); - inline althrd_t althrd_current(void) { @@ -96,19 +92,6 @@ inline int almtx_trylock(almtx_t *mtx) return althrd_success; } - -inline void *altss_get(altss_t tss_id) -{ - return TlsGetValue(tss_id); -} - -inline int altss_set(altss_t tss_id, void *val) -{ - if(TlsSetValue(tss_id, val) == 0) - return althrd_error; - return althrd_success; -} - #else #include @@ -128,7 +111,6 @@ typedef dispatch_semaphore_t alsem_t; #else /* !__APPLE__ */ typedef sem_t alsem_t; #endif /* __APPLE__ */ -typedef pthread_key_t altss_t; typedef pthread_once_t alonce_flag; #define AL_ONCE_FLAG_INIT PTHREAD_ONCE_INIT @@ -181,19 +163,6 @@ inline int almtx_trylock(almtx_t *mtx) } -inline void *altss_get(altss_t tss_id) -{ - return pthread_getspecific(tss_id); -} - -inline int altss_set(altss_t tss_id, void *val) -{ - if(pthread_setspecific(tss_id, val) != 0) - return althrd_error; - return althrd_success; -} - - inline void alcall_once(alonce_flag *once, void (*callback)(void)) { pthread_once(once, callback); @@ -201,7 +170,6 @@ inline void alcall_once(alonce_flag *once, void (*callback)(void)) inline void althrd_deinit(void) { } -inline void althrd_thread_detach(void) { } #endif @@ -220,9 +188,6 @@ int alsem_post(alsem_t *sem); int alsem_wait(alsem_t *sem); int alsem_trywait(alsem_t *sem); -int altss_create(altss_t *tss_id, altss_dtor_t callback); -void altss_delete(altss_t tss_id); - #ifdef __cplusplus } // extern "C" -- cgit v1.2.3 From 1bd40d94345ac263887b9a83c765ee46dc701799 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Nov 2018 22:41:04 -0800 Subject: Put a lambda in the call_once call This optimizes better and avoids a visible symbol (templating to an anonymous lambda type will generate a unique anonymous instantiation, making inlining more likely, whereas passing a general function pointer/reference type will likely use or generate a publically available instance). --- Alc/alc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 4ce66eaf..65023fe1 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1211,7 +1211,7 @@ static void alc_initconfig(void) if((str && str[0]) || ConfigValueStr(nullptr, nullptr, "default-reverb", &str)) LoadReverbPreset(str, &DefaultEffect); } -#define DO_INITCONFIG() std::call_once(alc_config_once, alc_initconfig) +#define DO_INITCONFIG() std::call_once(alc_config_once, [](){alc_initconfig();}) /************************************************ -- cgit v1.2.3 From 3bbfd0c0996e1db310cc2b72cffaf310a2adf6fb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Nov 2018 23:01:40 -0800 Subject: Fix compilation with MSVC --- OpenAL32/alAuxEffectSlot.cpp | 6 ++++-- native-tools/bsincgen.c | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index 18bad2d4..0ebcd3c9 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -624,7 +624,8 @@ static void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontex newarray->count = newcount; } - curarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray, almemory_order_acq_rel); + curarray = static_cast(ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, + newarray, almemory_order_acq_rel)); while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) althrd_yield(); al_free(curarray); @@ -659,7 +660,8 @@ static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcon /* TODO: Could reallocate newarray now that we know it's needed size. */ - curarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray, almemory_order_acq_rel); + curarray = static_cast(ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, + newarray, almemory_order_acq_rel)); while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) althrd_yield(); al_free(curarray); diff --git a/native-tools/bsincgen.c b/native-tools/bsincgen.c index 4e85135b..89f9f378 100644 --- a/native-tools/bsincgen.c +++ b/native-tools/bsincgen.c @@ -261,7 +261,7 @@ static void BsiGenerateTables(FILE *output, const char *tabname, const double re " * width) suffers to reduce the CPU cost. The bandlimiting will cut all sound\n" " * after downsampling by ~%.2f octaves.\n" " */\n" -"alignas(16) constexpr float %s_tab[%d] = {\n", +"alignas(16) static constexpr float %s_tab[%d] = {\n", order, (((order%100)/10) == 1) ? "th" : ((order%10) == 1) ? "st" : ((order%10) == 2) ? "nd" : @@ -290,7 +290,7 @@ static void BsiGenerateTables(FILE *output, const char *tabname, const double re fprintf(output, "\n"); } } - fprintf(output, "};\nconstexpr BSincTable %s = {\n", tabname); + fprintf(output, "};\nconst BSincTable %s = {\n", tabname); /* The scaleBase is calculated from the Kaiser window transition width. It represents the absolute limit to the filter before it fully cuts -- cgit v1.2.3 From f1731af282b3c54d2b19dedd72beb584cbda5220 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 01:29:35 -0800 Subject: Remove unneeded declarations and definitions --- common/alcomplex.c | 36 +++++++++++++++++++++++++++++++++--- common/alcomplex.h | 33 --------------------------------- common/threads.c | 5 ----- common/threads.h | 29 ----------------------------- 4 files changed, 33 insertions(+), 70 deletions(-) diff --git a/common/alcomplex.c b/common/alcomplex.c index d4045aeb..851f4105 100644 --- a/common/alcomplex.c +++ b/common/alcomplex.c @@ -5,9 +5,39 @@ #include "math_defs.h" -extern inline ALcomplex complex_add(ALcomplex a, ALcomplex b); -extern inline ALcomplex complex_sub(ALcomplex a, ALcomplex b); -extern inline ALcomplex complex_mult(ALcomplex a, ALcomplex b); +/** Addition of two complex numbers. */ +static inline ALcomplex complex_add(ALcomplex a, ALcomplex b) +{ + ALcomplex result; + + result.Real = a.Real + b.Real; + result.Imag = a.Imag + b.Imag; + + return result; +} + +/** Subtraction of two complex numbers. */ +static inline ALcomplex complex_sub(ALcomplex a, ALcomplex b) +{ + ALcomplex result; + + result.Real = a.Real - b.Real; + result.Imag = a.Imag - b.Imag; + + return result; +} + +/** Multiplication of two complex numbers. */ +static inline ALcomplex complex_mult(ALcomplex a, ALcomplex b) +{ + ALcomplex result; + + result.Real = a.Real*b.Real - a.Imag*b.Imag; + result.Imag = a.Imag*b.Real + a.Real*b.Imag; + + return result; +} + void complex_fft(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign) { diff --git a/common/alcomplex.h b/common/alcomplex.h index 2418ce78..0070ac13 100644 --- a/common/alcomplex.h +++ b/common/alcomplex.h @@ -13,39 +13,6 @@ typedef struct ALcomplex { ALdouble Imag; } ALcomplex; -/** Addition of two complex numbers. */ -inline ALcomplex complex_add(ALcomplex a, ALcomplex b) -{ - ALcomplex result; - - result.Real = a.Real + b.Real; - result.Imag = a.Imag + b.Imag; - - return result; -} - -/** Subtraction of two complex numbers. */ -inline ALcomplex complex_sub(ALcomplex a, ALcomplex b) -{ - ALcomplex result; - - result.Real = a.Real - b.Real; - result.Imag = a.Imag - b.Imag; - - return result; -} - -/** Multiplication of two complex numbers. */ -inline ALcomplex complex_mult(ALcomplex a, ALcomplex b) -{ - ALcomplex result; - - result.Real = a.Real*b.Real - a.Imag*b.Imag; - result.Imag = a.Imag*b.Real + a.Real*b.Imag; - - return result; -} - /** * Iterative implementation of 2-radix FFT (In-place algorithm). Sign = -1 is * FFT and 1 is iFFT (inverse). Fills FFTBuffer[0...FFTSize-1] with the diff --git a/common/threads.c b/common/threads.c index 4cdb329d..1ecec365 100644 --- a/common/threads.c +++ b/common/threads.c @@ -31,13 +31,8 @@ extern inline althrd_t althrd_current(void); extern inline int althrd_equal(althrd_t thr0, althrd_t thr1); -extern inline void althrd_exit(int res); extern inline void althrd_yield(void); -extern inline int almtx_lock(almtx_t *mtx); -extern inline int almtx_unlock(almtx_t *mtx); -extern inline int almtx_trylock(almtx_t *mtx); - #ifndef UNUSED #if defined(__cplusplus) diff --git a/common/threads.h b/common/threads.h index 2d1c228d..ae033931 100644 --- a/common/threads.h +++ b/common/threads.h @@ -59,11 +59,6 @@ inline int althrd_equal(althrd_t thr0, althrd_t thr1) return thr0 == thr1; } -inline void althrd_exit(int res) -{ - ExitThread(res); -} - inline void althrd_yield(void) { SwitchToThread(); @@ -84,14 +79,6 @@ inline int almtx_unlock(almtx_t *mtx) return althrd_success; } -inline int almtx_trylock(almtx_t *mtx) -{ - if(!mtx) return althrd_error; - if(!TryEnterCriticalSection(mtx)) - return althrd_busy; - return althrd_success; -} - #else #include @@ -126,11 +113,6 @@ inline int althrd_equal(althrd_t thr0, althrd_t thr1) return pthread_equal(thr0, thr1); } -inline void althrd_exit(int res) -{ - pthread_exit((void*)(intptr_t)res); -} - inline void althrd_yield(void) { sched_yield(); @@ -151,17 +133,6 @@ inline int almtx_unlock(almtx_t *mtx) return althrd_success; } -inline int almtx_trylock(almtx_t *mtx) -{ - int ret = pthread_mutex_trylock(mtx); - switch(ret) - { - case 0: return althrd_success; - case EBUSY: return althrd_busy; - } - return althrd_error; -} - inline void alcall_once(alonce_flag *once, void (*callback)(void)) { -- cgit v1.2.3 From 557048afa2d06d68c5a5f7f0584dbace67d02ef6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 01:36:47 -0800 Subject: Convert pshifter.c to C++ --- Alc/effects/pshifter.c | 441 ---------------------------------------------- Alc/effects/pshifter.cpp | 446 +++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 447 insertions(+), 442 deletions(-) delete mode 100644 Alc/effects/pshifter.c create mode 100644 Alc/effects/pshifter.cpp diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c deleted file mode 100644 index 35168eab..00000000 --- a/Alc/effects/pshifter.c +++ /dev/null @@ -1,441 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2018 by Raul Herraiz. - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" -#include "filters/defs.h" - -#include "alcomplex.h" - - -#define STFT_SIZE 1024 -#define STFT_HALF_SIZE (STFT_SIZE>>1) -#define OVERSAMP (1<<2) - -#define STFT_STEP (STFT_SIZE / OVERSAMP) -#define FIFO_LATENCY (STFT_STEP * (OVERSAMP-1)) - - -typedef struct ALphasor { - ALdouble Amplitude; - ALdouble Phase; -} ALphasor; - -typedef struct ALFrequencyDomain { - ALdouble Amplitude; - ALdouble Frequency; -} ALfrequencyDomain; - - -typedef struct ALpshifterState { - DERIVE_FROM_TYPE(ALeffectState); - - /* Effect parameters */ - ALsizei count; - ALsizei PitchShiftI; - ALfloat PitchShift; - ALfloat FreqPerBin; - - /*Effects buffers*/ - ALfloat InFIFO[STFT_SIZE]; - ALfloat OutFIFO[STFT_STEP]; - ALdouble LastPhase[STFT_HALF_SIZE+1]; - ALdouble SumPhase[STFT_HALF_SIZE+1]; - ALdouble OutputAccum[STFT_SIZE]; - - ALcomplex FFTbuffer[STFT_SIZE]; - - ALfrequencyDomain Analysis_buffer[STFT_HALF_SIZE+1]; - ALfrequencyDomain Syntesis_buffer[STFT_HALF_SIZE+1]; - - alignas(16) ALfloat BufferOut[BUFFERSIZE]; - - /* Effect gains for each output channel */ - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; -} ALpshifterState; - -static ALvoid ALpshifterState_Destruct(ALpshifterState *state); -static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device); -static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALpshifterState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALpshifterState); - - -/* Define a Hann window, used to filter the STFT input and output. */ -alignas(16) static ALdouble HannWindow[STFT_SIZE]; - -static void InitHannWindow(void) -{ - ALsizei i; - - /* Create lookup table of the Hann window for the desired size, i.e. STFT_SIZE */ - for(i = 0;i < STFT_SIZE>>1;i++) - { - ALdouble val = sin(M_PI * (ALdouble)i / (ALdouble)(STFT_SIZE-1)); - HannWindow[i] = HannWindow[STFT_SIZE-1-i] = val * val; - } -} -static alonce_flag HannInitOnce = AL_ONCE_FLAG_INIT; - - -static inline ALint double2int(ALdouble d) -{ -#if ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) && \ - !defined(__SSE2_MATH__)) || (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP < 2) - ALint sign, shift; - ALint64 mant; - union { - ALdouble d; - ALint64 i64; - } conv; - - conv.d = d; - sign = (conv.i64>>63) | 1; - shift = ((conv.i64>>52)&0x7ff) - (1023+52); - - /* Over/underflow */ - if(UNLIKELY(shift >= 63 || shift < -52)) - return 0; - - mant = (conv.i64&I64(0xfffffffffffff)) | I64(0x10000000000000); - if(LIKELY(shift < 0)) - return (ALint)(mant >> -shift) * sign; - return (ALint)(mant << shift) * sign; - -#else - - return (ALint)d; -#endif -} - - -/* Converts ALcomplex to ALphasor */ -static inline ALphasor rect2polar(ALcomplex number) -{ - ALphasor polar; - - polar.Amplitude = sqrt(number.Real*number.Real + number.Imag*number.Imag); - polar.Phase = atan2(number.Imag, number.Real); - - return polar; -} - -/* Converts ALphasor to ALcomplex */ -static inline ALcomplex polar2rect(ALphasor number) -{ - ALcomplex cartesian; - - cartesian.Real = number.Amplitude * cos(number.Phase); - cartesian.Imag = number.Amplitude * sin(number.Phase); - - return cartesian; -} - - -static void ALpshifterState_Construct(ALpshifterState *state) -{ - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALpshifterState, ALeffectState, state); - - alcall_once(&HannInitOnce, InitHannWindow); -} - -static ALvoid ALpshifterState_Destruct(ALpshifterState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); -} - -static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device) -{ - /* (Re-)initializing parameters and clear the buffers. */ - state->count = FIFO_LATENCY; - state->PitchShiftI = FRACTIONONE; - state->PitchShift = 1.0f; - state->FreqPerBin = device->Frequency / (ALfloat)STFT_SIZE; - - memset(state->InFIFO, 0, sizeof(state->InFIFO)); - memset(state->OutFIFO, 0, sizeof(state->OutFIFO)); - memset(state->FFTbuffer, 0, sizeof(state->FFTbuffer)); - memset(state->LastPhase, 0, sizeof(state->LastPhase)); - memset(state->SumPhase, 0, sizeof(state->SumPhase)); - memset(state->OutputAccum, 0, sizeof(state->OutputAccum)); - memset(state->Analysis_buffer, 0, sizeof(state->Analysis_buffer)); - memset(state->Syntesis_buffer, 0, sizeof(state->Syntesis_buffer)); - - memset(state->CurrentGains, 0, sizeof(state->CurrentGains)); - memset(state->TargetGains, 0, sizeof(state->TargetGains)); - - return AL_TRUE; -} - -static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) -{ - const ALCdevice *device = context->Device; - ALfloat coeffs[MAX_AMBI_COEFFS]; - float pitch; - - pitch = powf(2.0f, - (ALfloat)(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f - ); - state->PitchShiftI = fastf2i(pitch*FRACTIONONE); - state->PitchShift = state->PitchShiftI * (1.0f/FRACTIONONE); - - CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); -} - -static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) -{ - /* Pitch shifter engine based on the work of Stephan Bernsee. - * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/ - */ - - static const ALdouble expected = M_PI*2.0 / OVERSAMP; - const ALdouble freq_per_bin = state->FreqPerBin; - ALfloat *RESTRICT bufferOut = state->BufferOut; - ALsizei count = state->count; - ALsizei i, j, k; - - for(i = 0;i < SamplesToDo;) - { - do { - /* Fill FIFO buffer with samples data */ - state->InFIFO[count] = SamplesIn[0][i]; - bufferOut[i] = state->OutFIFO[count - FIFO_LATENCY]; - - count++; - } while(++i < SamplesToDo && count < STFT_SIZE); - - /* Check whether FIFO buffer is filled */ - if(count < STFT_SIZE) break; - count = FIFO_LATENCY; - - /* Real signal windowing and store in FFTbuffer */ - for(k = 0;k < STFT_SIZE;k++) - { - state->FFTbuffer[k].Real = state->InFIFO[k] * HannWindow[k]; - state->FFTbuffer[k].Imag = 0.0; - } - - /* ANALYSIS */ - /* Apply FFT to FFTbuffer data */ - complex_fft(state->FFTbuffer, STFT_SIZE, -1.0); - - /* Analyze the obtained data. Since the real FFT is symmetric, only - * STFT_HALF_SIZE+1 samples are needed. - */ - for(k = 0;k < STFT_HALF_SIZE+1;k++) - { - ALphasor component; - ALdouble tmp; - ALint qpd; - - /* Compute amplitude and phase */ - component = rect2polar(state->FFTbuffer[k]); - - /* Compute phase difference and subtract expected phase difference */ - tmp = (component.Phase - state->LastPhase[k]) - k*expected; - - /* Map delta phase into +/- Pi interval */ - qpd = double2int(tmp / M_PI); - tmp -= M_PI * (qpd + (qpd%2)); - - /* Get deviation from bin frequency from the +/- Pi interval */ - tmp /= expected; - - /* Compute the k-th partials' true frequency, twice the amplitude - * for maintain the gain (because half of bins are used) and store - * amplitude and true frequency in analysis buffer. - */ - state->Analysis_buffer[k].Amplitude = 2.0 * component.Amplitude; - state->Analysis_buffer[k].Frequency = (k + tmp) * freq_per_bin; - - /* Store actual phase[k] for the calculations in the next frame*/ - state->LastPhase[k] = component.Phase; - } - - /* PROCESSING */ - /* pitch shifting */ - for(k = 0;k < STFT_HALF_SIZE+1;k++) - { - state->Syntesis_buffer[k].Amplitude = 0.0; - state->Syntesis_buffer[k].Frequency = 0.0; - } - - for(k = 0;k < STFT_HALF_SIZE+1;k++) - { - j = (k*state->PitchShiftI) >> FRACTIONBITS; - if(j >= STFT_HALF_SIZE+1) break; - - state->Syntesis_buffer[j].Amplitude += state->Analysis_buffer[k].Amplitude; - state->Syntesis_buffer[j].Frequency = state->Analysis_buffer[k].Frequency * - state->PitchShift; - } - - /* SYNTHESIS */ - /* Synthesis the processing data */ - for(k = 0;k < STFT_HALF_SIZE+1;k++) - { - ALphasor component; - ALdouble tmp; - - /* Compute bin deviation from scaled freq */ - tmp = state->Syntesis_buffer[k].Frequency/freq_per_bin - k; - - /* Calculate actual delta phase and accumulate it to get bin phase */ - state->SumPhase[k] += (k + tmp) * expected; - - component.Amplitude = state->Syntesis_buffer[k].Amplitude; - component.Phase = state->SumPhase[k]; - - /* Compute phasor component to cartesian complex number and storage it into FFTbuffer*/ - state->FFTbuffer[k] = polar2rect(component); - } - /* zero negative frequencies for recontruct a real signal */ - for(k = STFT_HALF_SIZE+1;k < STFT_SIZE;k++) - { - state->FFTbuffer[k].Real = 0.0; - state->FFTbuffer[k].Imag = 0.0; - } - - /* Apply iFFT to buffer data */ - complex_fft(state->FFTbuffer, STFT_SIZE, 1.0); - - /* Windowing and add to output */ - for(k = 0;k < STFT_SIZE;k++) - state->OutputAccum[k] += HannWindow[k] * state->FFTbuffer[k].Real / - (0.5 * STFT_HALF_SIZE * OVERSAMP); - - /* Shift accumulator, input & output FIFO */ - for(k = 0;k < STFT_STEP;k++) state->OutFIFO[k] = (ALfloat)state->OutputAccum[k]; - for(j = 0;k < STFT_SIZE;k++,j++) state->OutputAccum[j] = state->OutputAccum[k]; - for(;j < STFT_SIZE;j++) state->OutputAccum[j] = 0.0; - for(k = 0;k < FIFO_LATENCY;k++) - state->InFIFO[k] = state->InFIFO[k+STFT_STEP]; - } - state->count = count; - - /* Now, mix the processed sound data to the output. */ - MixSamples(bufferOut, NumChannels, SamplesOut, state->CurrentGains, state->TargetGains, - maxi(SamplesToDo, 512), 0, SamplesToDo); -} - -typedef struct PshifterStateFactory { - DERIVE_FROM_TYPE(EffectStateFactory); -} PshifterStateFactory; - -static ALeffectState *PshifterStateFactory_create(PshifterStateFactory *UNUSED(factory)) -{ - ALpshifterState *state; - - NEW_OBJ0(state, ALpshifterState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(PshifterStateFactory); - -EffectStateFactory *PshifterStateFactory_getFactory(void) -{ - static PshifterStateFactory PshifterFactory = { { GET_VTABLE2(PshifterStateFactory, EffectStateFactory) } }; - - return STATIC_CAST(EffectStateFactory, &PshifterFactory); -} - - -void ALpshifter_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat UNUSED(val)) -{ - alSetError( context, AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param ); -} - -void ALpshifter_setParamfv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALfloat *UNUSED(vals)) -{ - alSetError( context, AL_INVALID_ENUM, "Invalid pitch shifter float-vector property 0x%04x", param ); -} - -void ALpshifter_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_PITCH_SHIFTER_COARSE_TUNE: - if(!(val >= AL_PITCH_SHIFTER_MIN_COARSE_TUNE && val <= AL_PITCH_SHIFTER_MAX_COARSE_TUNE)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Pitch shifter coarse tune out of range"); - props->Pshifter.CoarseTune = val; - break; - - case AL_PITCH_SHIFTER_FINE_TUNE: - if(!(val >= AL_PITCH_SHIFTER_MIN_FINE_TUNE && val <= AL_PITCH_SHIFTER_MAX_FINE_TUNE)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Pitch shifter fine tune out of range"); - props->Pshifter.FineTune = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x", param); - } -} -void ALpshifter_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - ALpshifter_setParami(effect, context, param, vals[0]); -} - -void ALpshifter_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_PITCH_SHIFTER_COARSE_TUNE: - *val = (ALint)props->Pshifter.CoarseTune; - break; - case AL_PITCH_SHIFTER_FINE_TUNE: - *val = (ALint)props->Pshifter.FineTune; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x", param); - } -} -void ALpshifter_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - ALpshifter_getParami(effect, context, param, vals); -} - -void ALpshifter_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat *UNUSED(val)) -{ - alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param); -} - -void ALpshifter_getParamfv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat *UNUSED(vals)) -{ - alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float vector-property 0x%04x", param); -} - -DEFINE_ALEFFECT_VTABLE(ALpshifter); diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp new file mode 100644 index 00000000..d3a399ff --- /dev/null +++ b/Alc/effects/pshifter.cpp @@ -0,0 +1,446 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2018 by Raul Herraiz. + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" +#include "filters/defs.h" + +#include "alcomplex.h" + + +#define STFT_SIZE 1024 +#define STFT_HALF_SIZE (STFT_SIZE>>1) +#define OVERSAMP (1<<2) + +#define STFT_STEP (STFT_SIZE / OVERSAMP) +#define FIFO_LATENCY (STFT_STEP * (OVERSAMP-1)) + + +typedef struct ALphasor { + ALdouble Amplitude; + ALdouble Phase; +} ALphasor; + +typedef struct ALFrequencyDomain { + ALdouble Amplitude; + ALdouble Frequency; +} ALfrequencyDomain; + + +struct ALpshifterState final : public ALeffectState { + /* Effect parameters */ + ALsizei count; + ALsizei PitchShiftI; + ALfloat PitchShift; + ALfloat FreqPerBin; + + /*Effects buffers*/ + ALfloat InFIFO[STFT_SIZE]; + ALfloat OutFIFO[STFT_STEP]; + ALdouble LastPhase[STFT_HALF_SIZE+1]; + ALdouble SumPhase[STFT_HALF_SIZE+1]; + ALdouble OutputAccum[STFT_SIZE]; + + ALcomplex FFTbuffer[STFT_SIZE]; + + ALfrequencyDomain Analysis_buffer[STFT_HALF_SIZE+1]; + ALfrequencyDomain Syntesis_buffer[STFT_HALF_SIZE+1]; + + alignas(16) ALfloat BufferOut[BUFFERSIZE]; + + /* Effect gains for each output channel */ + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; +}; + +static ALvoid ALpshifterState_Destruct(ALpshifterState *state); +static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device); +static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALpshifterState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALpshifterState); + + +/* Define a Hann window, used to filter the STFT input and output. */ +alignas(16) static ALdouble HannWindow[STFT_SIZE]; + +static void InitHannWindow(void) +{ + ALsizei i; + + /* Create lookup table of the Hann window for the desired size, i.e. STFT_SIZE */ + for(i = 0;i < STFT_SIZE>>1;i++) + { + ALdouble val = sin(M_PI * (ALdouble)i / (ALdouble)(STFT_SIZE-1)); + HannWindow[i] = HannWindow[STFT_SIZE-1-i] = val * val; + } +} +static alonce_flag HannInitOnce = AL_ONCE_FLAG_INIT; + + +static inline ALint double2int(ALdouble d) +{ +#if ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) && \ + !defined(__SSE2_MATH__)) || (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP < 2) + ALint sign, shift; + ALint64 mant; + union { + ALdouble d; + ALint64 i64; + } conv; + + conv.d = d; + sign = (conv.i64>>63) | 1; + shift = ((conv.i64>>52)&0x7ff) - (1023+52); + + /* Over/underflow */ + if(UNLIKELY(shift >= 63 || shift < -52)) + return 0; + + mant = (conv.i64&I64(0xfffffffffffff)) | I64(0x10000000000000); + if(LIKELY(shift < 0)) + return (ALint)(mant >> -shift) * sign; + return (ALint)(mant << shift) * sign; + +#else + + return (ALint)d; +#endif +} + + +/* Converts ALcomplex to ALphasor */ +static inline ALphasor rect2polar(ALcomplex number) +{ + ALphasor polar; + + polar.Amplitude = sqrt(number.Real*number.Real + number.Imag*number.Imag); + polar.Phase = atan2(number.Imag, number.Real); + + return polar; +} + +/* Converts ALphasor to ALcomplex */ +static inline ALcomplex polar2rect(ALphasor number) +{ + ALcomplex cartesian; + + cartesian.Real = number.Amplitude * cos(number.Phase); + cartesian.Imag = number.Amplitude * sin(number.Phase); + + return cartesian; +} + + +static void ALpshifterState_Construct(ALpshifterState *state) +{ + new (state) ALpshifterState{}; + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALpshifterState, ALeffectState, state); + + alcall_once(&HannInitOnce, InitHannWindow); +} + +static ALvoid ALpshifterState_Destruct(ALpshifterState *state) +{ + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); + state->~ALpshifterState(); +} + +static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device) +{ + /* (Re-)initializing parameters and clear the buffers. */ + state->count = FIFO_LATENCY; + state->PitchShiftI = FRACTIONONE; + state->PitchShift = 1.0f; + state->FreqPerBin = device->Frequency / (ALfloat)STFT_SIZE; + + memset(state->InFIFO, 0, sizeof(state->InFIFO)); + memset(state->OutFIFO, 0, sizeof(state->OutFIFO)); + memset(state->FFTbuffer, 0, sizeof(state->FFTbuffer)); + memset(state->LastPhase, 0, sizeof(state->LastPhase)); + memset(state->SumPhase, 0, sizeof(state->SumPhase)); + memset(state->OutputAccum, 0, sizeof(state->OutputAccum)); + memset(state->Analysis_buffer, 0, sizeof(state->Analysis_buffer)); + memset(state->Syntesis_buffer, 0, sizeof(state->Syntesis_buffer)); + + memset(state->CurrentGains, 0, sizeof(state->CurrentGains)); + memset(state->TargetGains, 0, sizeof(state->TargetGains)); + + return AL_TRUE; +} + +static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +{ + const ALCdevice *device = context->Device; + ALfloat coeffs[MAX_AMBI_COEFFS]; + float pitch; + + pitch = powf(2.0f, + (ALfloat)(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f + ); + state->PitchShiftI = fastf2i(pitch*FRACTIONONE); + state->PitchShift = state->PitchShiftI * (1.0f/FRACTIONONE); + + CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); +} + +static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +{ + /* Pitch shifter engine based on the work of Stephan Bernsee. + * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/ + */ + + static const ALdouble expected = M_PI*2.0 / OVERSAMP; + const ALdouble freq_per_bin = state->FreqPerBin; + ALfloat *RESTRICT bufferOut = state->BufferOut; + ALsizei count = state->count; + ALsizei i, j, k; + + for(i = 0;i < SamplesToDo;) + { + do { + /* Fill FIFO buffer with samples data */ + state->InFIFO[count] = SamplesIn[0][i]; + bufferOut[i] = state->OutFIFO[count - FIFO_LATENCY]; + + count++; + } while(++i < SamplesToDo && count < STFT_SIZE); + + /* Check whether FIFO buffer is filled */ + if(count < STFT_SIZE) break; + count = FIFO_LATENCY; + + /* Real signal windowing and store in FFTbuffer */ + for(k = 0;k < STFT_SIZE;k++) + { + state->FFTbuffer[k].Real = state->InFIFO[k] * HannWindow[k]; + state->FFTbuffer[k].Imag = 0.0; + } + + /* ANALYSIS */ + /* Apply FFT to FFTbuffer data */ + complex_fft(state->FFTbuffer, STFT_SIZE, -1.0); + + /* Analyze the obtained data. Since the real FFT is symmetric, only + * STFT_HALF_SIZE+1 samples are needed. + */ + for(k = 0;k < STFT_HALF_SIZE+1;k++) + { + ALphasor component; + ALdouble tmp; + ALint qpd; + + /* Compute amplitude and phase */ + component = rect2polar(state->FFTbuffer[k]); + + /* Compute phase difference and subtract expected phase difference */ + tmp = (component.Phase - state->LastPhase[k]) - k*expected; + + /* Map delta phase into +/- Pi interval */ + qpd = double2int(tmp / M_PI); + tmp -= M_PI * (qpd + (qpd%2)); + + /* Get deviation from bin frequency from the +/- Pi interval */ + tmp /= expected; + + /* Compute the k-th partials' true frequency, twice the amplitude + * for maintain the gain (because half of bins are used) and store + * amplitude and true frequency in analysis buffer. + */ + state->Analysis_buffer[k].Amplitude = 2.0 * component.Amplitude; + state->Analysis_buffer[k].Frequency = (k + tmp) * freq_per_bin; + + /* Store actual phase[k] for the calculations in the next frame*/ + state->LastPhase[k] = component.Phase; + } + + /* PROCESSING */ + /* pitch shifting */ + for(k = 0;k < STFT_HALF_SIZE+1;k++) + { + state->Syntesis_buffer[k].Amplitude = 0.0; + state->Syntesis_buffer[k].Frequency = 0.0; + } + + for(k = 0;k < STFT_HALF_SIZE+1;k++) + { + j = (k*state->PitchShiftI) >> FRACTIONBITS; + if(j >= STFT_HALF_SIZE+1) break; + + state->Syntesis_buffer[j].Amplitude += state->Analysis_buffer[k].Amplitude; + state->Syntesis_buffer[j].Frequency = state->Analysis_buffer[k].Frequency * + state->PitchShift; + } + + /* SYNTHESIS */ + /* Synthesis the processing data */ + for(k = 0;k < STFT_HALF_SIZE+1;k++) + { + ALphasor component; + ALdouble tmp; + + /* Compute bin deviation from scaled freq */ + tmp = state->Syntesis_buffer[k].Frequency/freq_per_bin - k; + + /* Calculate actual delta phase and accumulate it to get bin phase */ + state->SumPhase[k] += (k + tmp) * expected; + + component.Amplitude = state->Syntesis_buffer[k].Amplitude; + component.Phase = state->SumPhase[k]; + + /* Compute phasor component to cartesian complex number and storage it into FFTbuffer*/ + state->FFTbuffer[k] = polar2rect(component); + } + /* zero negative frequencies for recontruct a real signal */ + for(k = STFT_HALF_SIZE+1;k < STFT_SIZE;k++) + { + state->FFTbuffer[k].Real = 0.0; + state->FFTbuffer[k].Imag = 0.0; + } + + /* Apply iFFT to buffer data */ + complex_fft(state->FFTbuffer, STFT_SIZE, 1.0); + + /* Windowing and add to output */ + for(k = 0;k < STFT_SIZE;k++) + state->OutputAccum[k] += HannWindow[k] * state->FFTbuffer[k].Real / + (0.5 * STFT_HALF_SIZE * OVERSAMP); + + /* Shift accumulator, input & output FIFO */ + for(k = 0;k < STFT_STEP;k++) state->OutFIFO[k] = (ALfloat)state->OutputAccum[k]; + for(j = 0;k < STFT_SIZE;k++,j++) state->OutputAccum[j] = state->OutputAccum[k]; + for(;j < STFT_SIZE;j++) state->OutputAccum[j] = 0.0; + for(k = 0;k < FIFO_LATENCY;k++) + state->InFIFO[k] = state->InFIFO[k+STFT_STEP]; + } + state->count = count; + + /* Now, mix the processed sound data to the output. */ + MixSamples(bufferOut, NumChannels, SamplesOut, state->CurrentGains, state->TargetGains, + maxi(SamplesToDo, 512), 0, SamplesToDo); +} + +struct PshifterStateFactory final : public EffectStateFactory { + PshifterStateFactory() noexcept; +}; + +static ALeffectState *PshifterStateFactory_create(PshifterStateFactory *UNUSED(factory)) +{ + ALpshifterState *state; + + NEW_OBJ0(state, ALpshifterState)(); + if(!state) return NULL; + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_EFFECTSTATEFACTORY_VTABLE(PshifterStateFactory); + + +PshifterStateFactory::PshifterStateFactory() noexcept + : EffectStateFactory{GET_VTABLE2(PshifterStateFactory, EffectStateFactory)} +{ +} + +EffectStateFactory *PshifterStateFactory_getFactory(void) +{ + static PshifterStateFactory PshifterFactory{}; + return STATIC_CAST(EffectStateFactory, &PshifterFactory); +} + + +void ALpshifter_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat UNUSED(val)) +{ + alSetError( context, AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param ); +} + +void ALpshifter_setParamfv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALfloat *UNUSED(vals)) +{ + alSetError( context, AL_INVALID_ENUM, "Invalid pitch shifter float-vector property 0x%04x", param ); +} + +void ALpshifter_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_PITCH_SHIFTER_COARSE_TUNE: + if(!(val >= AL_PITCH_SHIFTER_MIN_COARSE_TUNE && val <= AL_PITCH_SHIFTER_MAX_COARSE_TUNE)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Pitch shifter coarse tune out of range"); + props->Pshifter.CoarseTune = val; + break; + + case AL_PITCH_SHIFTER_FINE_TUNE: + if(!(val >= AL_PITCH_SHIFTER_MIN_FINE_TUNE && val <= AL_PITCH_SHIFTER_MAX_FINE_TUNE)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Pitch shifter fine tune out of range"); + props->Pshifter.FineTune = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x", param); + } +} +void ALpshifter_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + ALpshifter_setParami(effect, context, param, vals[0]); +} + +void ALpshifter_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_PITCH_SHIFTER_COARSE_TUNE: + *val = (ALint)props->Pshifter.CoarseTune; + break; + case AL_PITCH_SHIFTER_FINE_TUNE: + *val = (ALint)props->Pshifter.FineTune; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x", param); + } +} +void ALpshifter_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + ALpshifter_getParami(effect, context, param, vals); +} + +void ALpshifter_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat *UNUSED(val)) +{ + alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param); +} + +void ALpshifter_getParamfv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat *UNUSED(vals)) +{ + alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float vector-property 0x%04x", param); +} + +DEFINE_ALEFFECT_VTABLE(ALpshifter); diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a349762..2da22d3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -821,7 +821,7 @@ SET(ALC_OBJS Alc/effects/fshifter.c Alc/effects/modulator.c Alc/effects/null.c - Alc/effects/pshifter.c + Alc/effects/pshifter.cpp Alc/effects/reverb.cpp Alc/filters/defs.h Alc/filters/filter.c -- cgit v1.2.3 From a7d3c24b511be49d8d0917d5030a0f378af8da87 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 01:49:26 -0800 Subject: Convert null.c to C++ --- Alc/effects/null.c | 179 ------------------------------------------------- Alc/effects/null.cpp | 186 +++++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 187 insertions(+), 180 deletions(-) delete mode 100644 Alc/effects/null.c create mode 100644 Alc/effects/null.cpp diff --git a/Alc/effects/null.c b/Alc/effects/null.c deleted file mode 100644 index 82ea5d26..00000000 --- a/Alc/effects/null.c +++ /dev/null @@ -1,179 +0,0 @@ -#include "config.h" - -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "alMain.h" -#include "alAuxEffectSlot.h" -#include "alError.h" - - -typedef struct ALnullState { - DERIVE_FROM_TYPE(ALeffectState); -} ALnullState; - -/* Forward-declare "virtual" functions to define the vtable with. */ -static ALvoid ALnullState_Destruct(ALnullState *state); -static ALboolean ALnullState_deviceUpdate(ALnullState *state, ALCdevice *device); -static ALvoid ALnullState_update(ALnullState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALnullState_process(ALnullState *state, ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei mumChannels); -static void *ALnullState_New(size_t size); -static void ALnullState_Delete(void *ptr); - -/* Define the ALeffectState vtable for this type. */ -DEFINE_ALEFFECTSTATE_VTABLE(ALnullState); - - -/* This constructs the effect state. It's called when the object is first - * created. Make sure to call the parent Construct function first, and set the - * vtable! - */ -static void ALnullState_Construct(ALnullState *state) -{ - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALnullState, ALeffectState, state); -} - -/* This destructs (not free!) the effect state. It's called only when the - * effect slot is no longer used. Make sure to call the parent Destruct - * function before returning! - */ -static ALvoid ALnullState_Destruct(ALnullState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); -} - -/* This updates the device-dependant effect state. This is called on - * initialization and any time the device parameters (eg. playback frequency, - * format) have been changed. - */ -static ALboolean ALnullState_deviceUpdate(ALnullState* UNUSED(state), ALCdevice* UNUSED(device)) -{ - return AL_TRUE; -} - -/* This updates the effect state. This is called any time the effect is - * (re)loaded into a slot. - */ -static ALvoid ALnullState_update(ALnullState* UNUSED(state), const ALCcontext* UNUSED(context), const ALeffectslot* UNUSED(slot), const ALeffectProps* UNUSED(props)) -{ -} - -/* This processes the effect state, for the given number of samples from the - * input to the output buffer. The result should be added to the output buffer, - * not replace it. - */ -static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALsizei UNUSED(samplesToDo), const ALfloatBUFFERSIZE*RESTRICT UNUSED(samplesIn), ALfloatBUFFERSIZE*RESTRICT UNUSED(samplesOut), ALsizei UNUSED(numChannels)) -{ -} - -/* This allocates memory to store the object, before it gets constructed. - * DECLARE_DEFAULT_ALLOCATORS can be used to declare a default method. - */ -static void *ALnullState_New(size_t size) -{ - return al_calloc(16, size); -} - -/* This frees the memory used by the object, after it has been destructed. - * DECLARE_DEFAULT_ALLOCATORS can be used to declare a default method. - */ -static void ALnullState_Delete(void *ptr) -{ - al_free(ptr); -} - - -typedef struct NullStateFactory { - DERIVE_FROM_TYPE(EffectStateFactory); -} NullStateFactory; - -/* Creates ALeffectState objects of the appropriate type. */ -ALeffectState *NullStateFactory_create(NullStateFactory *UNUSED(factory)) -{ - ALnullState *state; - - NEW_OBJ0(state, ALnullState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -/* Define the EffectStateFactory vtable for this type. */ -DEFINE_EFFECTSTATEFACTORY_VTABLE(NullStateFactory); - -EffectStateFactory *NullStateFactory_getFactory(void) -{ - static NullStateFactory NullFactory = { { GET_VTABLE2(NullStateFactory, EffectStateFactory) } }; - return STATIC_CAST(EffectStateFactory, &NullFactory); -} - - -void ALnull_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val)) -{ - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x", param); - } -} -void ALnull_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint* UNUSED(vals)) -{ - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer-vector property 0x%04x", param); - } -} -void ALnull_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat UNUSED(val)) -{ - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid null effect float property 0x%04x", param); - } -} -void ALnull_setParamfv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALfloat* UNUSED(vals)) -{ - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid null effect float-vector property 0x%04x", param); - } -} - -void ALnull_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint* UNUSED(val)) -{ - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x", param); - } -} -void ALnull_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint* UNUSED(vals)) -{ - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer-vector property 0x%04x", param); - } -} -void ALnull_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat* UNUSED(val)) -{ - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid null effect float property 0x%04x", param); - } -} -void ALnull_getParamfv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat* UNUSED(vals)) -{ - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid null effect float-vector property 0x%04x", param); - } -} - -DEFINE_ALEFFECT_VTABLE(ALnull); diff --git a/Alc/effects/null.cpp b/Alc/effects/null.cpp new file mode 100644 index 00000000..377593ab --- /dev/null +++ b/Alc/effects/null.cpp @@ -0,0 +1,186 @@ +#include "config.h" + +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "alMain.h" +#include "alAuxEffectSlot.h" +#include "alError.h" + + +struct ALnullState final : public ALeffectState { +}; + +/* Forward-declare "virtual" functions to define the vtable with. */ +static ALvoid ALnullState_Destruct(ALnullState *state); +static ALboolean ALnullState_deviceUpdate(ALnullState *state, ALCdevice *device); +static ALvoid ALnullState_update(ALnullState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALnullState_process(ALnullState *state, ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei mumChannels); +static void *ALnullState_New(size_t size); +static void ALnullState_Delete(void *ptr); + +/* Define the ALeffectState vtable for this type. */ +DEFINE_ALEFFECTSTATE_VTABLE(ALnullState); + + +/* This constructs the effect state. It's called when the object is first + * created. Make sure to call the parent Construct function first, and set the + * vtable! + */ +static void ALnullState_Construct(ALnullState *state) +{ + new (state) ALnullState{}; + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALnullState, ALeffectState, state); +} + +/* This destructs (not free!) the effect state. It's called only when the + * effect slot is no longer used. Make sure to call the parent Destruct + * function before returning! + */ +static ALvoid ALnullState_Destruct(ALnullState *state) +{ + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); + state->~ALnullState(); +} + +/* This updates the device-dependant effect state. This is called on + * initialization and any time the device parameters (eg. playback frequency, + * format) have been changed. + */ +static ALboolean ALnullState_deviceUpdate(ALnullState* UNUSED(state), ALCdevice* UNUSED(device)) +{ + return AL_TRUE; +} + +/* This updates the effect state. This is called any time the effect is + * (re)loaded into a slot. + */ +static ALvoid ALnullState_update(ALnullState* UNUSED(state), const ALCcontext* UNUSED(context), const ALeffectslot* UNUSED(slot), const ALeffectProps* UNUSED(props)) +{ +} + +/* This processes the effect state, for the given number of samples from the + * input to the output buffer. The result should be added to the output buffer, + * not replace it. + */ +static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALsizei UNUSED(samplesToDo), const ALfloatBUFFERSIZE*RESTRICT UNUSED(samplesIn), ALfloatBUFFERSIZE*RESTRICT UNUSED(samplesOut), ALsizei UNUSED(numChannels)) +{ +} + +/* This allocates memory to store the object, before it gets constructed. + * DECLARE_DEFAULT_ALLOCATORS can be used to declare a default method. + */ +static void *ALnullState_New(size_t size) +{ + return al_calloc(16, size); +} + +/* This frees the memory used by the object, after it has been destructed. + * DECLARE_DEFAULT_ALLOCATORS can be used to declare a default method. + */ +static void ALnullState_Delete(void *ptr) +{ + al_free(ptr); +} + + +struct NullStateFactory final : public EffectStateFactory { + NullStateFactory() noexcept; +}; + +/* Creates ALeffectState objects of the appropriate type. */ +ALeffectState *NullStateFactory_create(NullStateFactory *UNUSED(factory)) +{ + ALnullState *state; + + NEW_OBJ0(state, ALnullState)(); + if(!state) return NULL; + + return STATIC_CAST(ALeffectState, state); +} + +/* Define the EffectStateFactory vtable for this type. */ +DEFINE_EFFECTSTATEFACTORY_VTABLE(NullStateFactory); + +NullStateFactory::NullStateFactory() noexcept + : EffectStateFactory{GET_VTABLE2(NullStateFactory, EffectStateFactory)} +{ +} + + +EffectStateFactory *NullStateFactory_getFactory(void) +{ + static NullStateFactory NullFactory{}; + return STATIC_CAST(EffectStateFactory, &NullFactory); +} + + +void ALnull_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val)) +{ + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x", param); + } +} +void ALnull_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint* UNUSED(vals)) +{ + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer-vector property 0x%04x", param); + } +} +void ALnull_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat UNUSED(val)) +{ + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM, "Invalid null effect float property 0x%04x", param); + } +} +void ALnull_setParamfv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALfloat* UNUSED(vals)) +{ + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM, "Invalid null effect float-vector property 0x%04x", param); + } +} + +void ALnull_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint* UNUSED(val)) +{ + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x", param); + } +} +void ALnull_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint* UNUSED(vals)) +{ + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer-vector property 0x%04x", param); + } +} +void ALnull_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat* UNUSED(val)) +{ + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM, "Invalid null effect float property 0x%04x", param); + } +} +void ALnull_getParamfv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat* UNUSED(vals)) +{ + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM, "Invalid null effect float-vector property 0x%04x", param); + } +} + +DEFINE_ALEFFECT_VTABLE(ALnull); diff --git a/CMakeLists.txt b/CMakeLists.txt index 2da22d3a..d5b1d005 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -820,7 +820,7 @@ SET(ALC_OBJS Alc/effects/equalizer.c Alc/effects/fshifter.c Alc/effects/modulator.c - Alc/effects/null.c + Alc/effects/null.cpp Alc/effects/pshifter.cpp Alc/effects/reverb.cpp Alc/filters/defs.h -- cgit v1.2.3 From aa66ed0ea54b282f7b547ebecfa716927aa02cd1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 01:53:39 -0800 Subject: Convert modulator.c to C++ --- Alc/effects/modulator.c | 307 --------------------------------------------- Alc/effects/modulator.cpp | 310 ++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 311 insertions(+), 308 deletions(-) delete mode 100644 Alc/effects/modulator.c create mode 100644 Alc/effects/modulator.cpp diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c deleted file mode 100644 index 87799dd7..00000000 --- a/Alc/effects/modulator.c +++ /dev/null @@ -1,307 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2009 by Chris Robinson. - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" -#include "filters/defs.h" - - -#define MAX_UPDATE_SAMPLES 128 - -typedef struct ALmodulatorState { - DERIVE_FROM_TYPE(ALeffectState); - - void (*GetSamples)(ALfloat*RESTRICT, ALsizei, const ALsizei, ALsizei); - - ALsizei index; - ALsizei step; - - struct { - BiquadFilter Filter; - - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; - } Chans[MAX_EFFECT_CHANNELS]; -} ALmodulatorState; - -static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state); -static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevice *device); -static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALmodulatorState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState); - - -#define WAVEFORM_FRACBITS 24 -#define WAVEFORM_FRACONE (1<>(WAVEFORM_FRACBITS-2))&2) - 1); -} - -static inline ALfloat One(ALsizei UNUSED(index)) -{ - return 1.0f; -} - -#define DECL_TEMPLATE(func) \ -static void Modulate##func(ALfloat *RESTRICT dst, ALsizei index, \ - const ALsizei step, ALsizei todo) \ -{ \ - ALsizei i; \ - for(i = 0;i < todo;i++) \ - { \ - index += step; \ - index &= WAVEFORM_FRACMASK; \ - dst[i] = func(index); \ - } \ -} - -DECL_TEMPLATE(Sin) -DECL_TEMPLATE(Saw) -DECL_TEMPLATE(Square) -DECL_TEMPLATE(One) - -#undef DECL_TEMPLATE - - -static void ALmodulatorState_Construct(ALmodulatorState *state) -{ - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALmodulatorState, ALeffectState, state); - - state->index = 0; - state->step = 1; -} - -static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); -} - -static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevice *UNUSED(device)) -{ - ALsizei i, j; - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - { - BiquadFilter_clear(&state->Chans[i].Filter); - for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - state->Chans[i].CurrentGains[j] = 0.0f; - } - return AL_TRUE; -} - -static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) -{ - const ALCdevice *device = context->Device; - ALfloat f0norm; - ALsizei i; - - state->step = fastf2i(props->Modulator.Frequency / (ALfloat)device->Frequency * - WAVEFORM_FRACONE); - state->step = clampi(state->step, 0, WAVEFORM_FRACONE-1); - - if(state->step == 0) - state->GetSamples = ModulateOne; - else if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) - state->GetSamples = ModulateSin; - else if(props->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) - state->GetSamples = ModulateSaw; - else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/ - state->GetSamples = ModulateSquare; - - f0norm = props->Modulator.HighPassCutoff / (ALfloat)device->Frequency; - f0norm = clampf(f0norm, 1.0f/512.0f, 0.49f); - /* Bandwidth value is constant in octaves. */ - BiquadFilter_setParams(&state->Chans[0].Filter, BiquadType_HighPass, 1.0f, - f0norm, calc_rcpQ_from_bandwidth(f0norm, 0.75f)); - for(i = 1;i < MAX_EFFECT_CHANNELS;i++) - BiquadFilter_copyParams(&state->Chans[i].Filter, &state->Chans[0].Filter); - - STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; - STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain, - state->Chans[i].TargetGains); -} - -static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) -{ - const ALsizei step = state->step; - ALsizei base; - - for(base = 0;base < SamplesToDo;) - { - alignas(16) ALfloat modsamples[MAX_UPDATE_SAMPLES]; - ALsizei td = mini(MAX_UPDATE_SAMPLES, SamplesToDo-base); - ALsizei c, i; - - state->GetSamples(modsamples, state->index, step, td); - state->index += (step*td) & WAVEFORM_FRACMASK; - state->index &= WAVEFORM_FRACMASK; - - for(c = 0;c < MAX_EFFECT_CHANNELS;c++) - { - alignas(16) ALfloat temps[MAX_UPDATE_SAMPLES]; - - BiquadFilter_process(&state->Chans[c].Filter, temps, &SamplesIn[c][base], td); - for(i = 0;i < td;i++) - temps[i] *= modsamples[i]; - - MixSamples(temps, NumChannels, SamplesOut, state->Chans[c].CurrentGains, - state->Chans[c].TargetGains, SamplesToDo-base, base, td); - } - - base += td; - } -} - - -typedef struct ModulatorStateFactory { - DERIVE_FROM_TYPE(EffectStateFactory); -} ModulatorStateFactory; - -static ALeffectState *ModulatorStateFactory_create(ModulatorStateFactory *UNUSED(factory)) -{ - ALmodulatorState *state; - - NEW_OBJ0(state, ALmodulatorState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(ModulatorStateFactory); - -EffectStateFactory *ModulatorStateFactory_getFactory(void) -{ - static ModulatorStateFactory ModulatorFactory = { { GET_VTABLE2(ModulatorStateFactory, EffectStateFactory) } }; - - return STATIC_CAST(EffectStateFactory, &ModulatorFactory); -} - - -void ALmodulator_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_RING_MODULATOR_FREQUENCY: - if(!(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Modulator frequency out of range"); - props->Modulator.Frequency = val; - break; - - case AL_RING_MODULATOR_HIGHPASS_CUTOFF: - if(!(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Modulator high-pass cutoff out of range"); - props->Modulator.HighPassCutoff = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param); - } -} -void ALmodulator_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ ALmodulator_setParamf(effect, context, param, vals[0]); } -void ALmodulator_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_RING_MODULATOR_FREQUENCY: - case AL_RING_MODULATOR_HIGHPASS_CUTOFF: - ALmodulator_setParamf(effect, context, param, (ALfloat)val); - break; - - case AL_RING_MODULATOR_WAVEFORM: - if(!(val >= AL_RING_MODULATOR_MIN_WAVEFORM && val <= AL_RING_MODULATOR_MAX_WAVEFORM)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid modulator waveform"); - props->Modulator.Waveform = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x", param); - } -} -void ALmodulator_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ ALmodulator_setParami(effect, context, param, vals[0]); } - -void ALmodulator_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_RING_MODULATOR_FREQUENCY: - *val = (ALint)props->Modulator.Frequency; - break; - case AL_RING_MODULATOR_HIGHPASS_CUTOFF: - *val = (ALint)props->Modulator.HighPassCutoff; - break; - case AL_RING_MODULATOR_WAVEFORM: - *val = props->Modulator.Waveform; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x", param); - } -} -void ALmodulator_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ ALmodulator_getParami(effect, context, param, vals); } -void ALmodulator_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_RING_MODULATOR_FREQUENCY: - *val = props->Modulator.Frequency; - break; - case AL_RING_MODULATOR_HIGHPASS_CUTOFF: - *val = props->Modulator.HighPassCutoff; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param); - } -} -void ALmodulator_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ ALmodulator_getParamf(effect, context, param, vals); } - -DEFINE_ALEFFECT_VTABLE(ALmodulator); diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp new file mode 100644 index 00000000..19513add --- /dev/null +++ b/Alc/effects/modulator.cpp @@ -0,0 +1,310 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2009 by Chris Robinson. + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" +#include "filters/defs.h" + + +#define MAX_UPDATE_SAMPLES 128 + +struct ALmodulatorState final : public ALeffectState { + void (*GetSamples)(ALfloat*RESTRICT, ALsizei, const ALsizei, ALsizei); + + ALsizei index; + ALsizei step; + + struct { + BiquadFilter Filter; + + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; + } Chans[MAX_EFFECT_CHANNELS]; +}; + +static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state); +static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevice *device); +static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALmodulatorState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState); + + +#define WAVEFORM_FRACBITS 24 +#define WAVEFORM_FRACONE (1<>(WAVEFORM_FRACBITS-2))&2) - 1); +} + +static inline ALfloat One(ALsizei UNUSED(index)) +{ + return 1.0f; +} + +#define DECL_TEMPLATE(func) \ +static void Modulate##func(ALfloat *RESTRICT dst, ALsizei index, \ + const ALsizei step, ALsizei todo) \ +{ \ + ALsizei i; \ + for(i = 0;i < todo;i++) \ + { \ + index += step; \ + index &= WAVEFORM_FRACMASK; \ + dst[i] = func(index); \ + } \ +} + +DECL_TEMPLATE(Sin) +DECL_TEMPLATE(Saw) +DECL_TEMPLATE(Square) +DECL_TEMPLATE(One) + +#undef DECL_TEMPLATE + + +static void ALmodulatorState_Construct(ALmodulatorState *state) +{ + new (state) ALmodulatorState{}; + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALmodulatorState, ALeffectState, state); + + state->index = 0; + state->step = 1; +} + +static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state) +{ + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); + state->~ALmodulatorState(); +} + +static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevice *UNUSED(device)) +{ + ALsizei i, j; + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + { + BiquadFilter_clear(&state->Chans[i].Filter); + for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) + state->Chans[i].CurrentGains[j] = 0.0f; + } + return AL_TRUE; +} + +static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +{ + const ALCdevice *device = context->Device; + ALfloat f0norm; + ALsizei i; + + state->step = fastf2i(props->Modulator.Frequency / (ALfloat)device->Frequency * + WAVEFORM_FRACONE); + state->step = clampi(state->step, 0, WAVEFORM_FRACONE-1); + + if(state->step == 0) + state->GetSamples = ModulateOne; + else if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) + state->GetSamples = ModulateSin; + else if(props->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) + state->GetSamples = ModulateSaw; + else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/ + state->GetSamples = ModulateSquare; + + f0norm = props->Modulator.HighPassCutoff / (ALfloat)device->Frequency; + f0norm = clampf(f0norm, 1.0f/512.0f, 0.49f); + /* Bandwidth value is constant in octaves. */ + BiquadFilter_setParams(&state->Chans[0].Filter, BiquadType_HighPass, 1.0f, + f0norm, calc_rcpQ_from_bandwidth(f0norm, 0.75f)); + for(i = 1;i < MAX_EFFECT_CHANNELS;i++) + BiquadFilter_copyParams(&state->Chans[i].Filter, &state->Chans[0].Filter); + + STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; + STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain, + state->Chans[i].TargetGains); +} + +static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +{ + const ALsizei step = state->step; + ALsizei base; + + for(base = 0;base < SamplesToDo;) + { + alignas(16) ALfloat modsamples[MAX_UPDATE_SAMPLES]; + ALsizei td = mini(MAX_UPDATE_SAMPLES, SamplesToDo-base); + ALsizei c, i; + + state->GetSamples(modsamples, state->index, step, td); + state->index += (step*td) & WAVEFORM_FRACMASK; + state->index &= WAVEFORM_FRACMASK; + + for(c = 0;c < MAX_EFFECT_CHANNELS;c++) + { + alignas(16) ALfloat temps[MAX_UPDATE_SAMPLES]; + + BiquadFilter_process(&state->Chans[c].Filter, temps, &SamplesIn[c][base], td); + for(i = 0;i < td;i++) + temps[i] *= modsamples[i]; + + MixSamples(temps, NumChannels, SamplesOut, state->Chans[c].CurrentGains, + state->Chans[c].TargetGains, SamplesToDo-base, base, td); + } + + base += td; + } +} + + +struct ModulatorStateFactory final : public EffectStateFactory { + ModulatorStateFactory() noexcept; +}; + +static ALeffectState *ModulatorStateFactory_create(ModulatorStateFactory *UNUSED(factory)) +{ + ALmodulatorState *state; + + NEW_OBJ0(state, ALmodulatorState)(); + if(!state) return NULL; + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_EFFECTSTATEFACTORY_VTABLE(ModulatorStateFactory); + +ModulatorStateFactory::ModulatorStateFactory() noexcept + : EffectStateFactory{GET_VTABLE2(ModulatorStateFactory, EffectStateFactory)} +{ } + +EffectStateFactory *ModulatorStateFactory_getFactory(void) +{ + static ModulatorStateFactory ModulatorFactory{}; + return STATIC_CAST(EffectStateFactory, &ModulatorFactory); +} + + +void ALmodulator_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + if(!(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Modulator frequency out of range"); + props->Modulator.Frequency = val; + break; + + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + if(!(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Modulator high-pass cutoff out of range"); + props->Modulator.HighPassCutoff = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param); + } +} +void ALmodulator_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALmodulator_setParamf(effect, context, param, vals[0]); } +void ALmodulator_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + ALmodulator_setParamf(effect, context, param, (ALfloat)val); + break; + + case AL_RING_MODULATOR_WAVEFORM: + if(!(val >= AL_RING_MODULATOR_MIN_WAVEFORM && val <= AL_RING_MODULATOR_MAX_WAVEFORM)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid modulator waveform"); + props->Modulator.Waveform = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x", param); + } +} +void ALmodulator_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ ALmodulator_setParami(effect, context, param, vals[0]); } + +void ALmodulator_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + *val = (ALint)props->Modulator.Frequency; + break; + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + *val = (ALint)props->Modulator.HighPassCutoff; + break; + case AL_RING_MODULATOR_WAVEFORM: + *val = props->Modulator.Waveform; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x", param); + } +} +void ALmodulator_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ ALmodulator_getParami(effect, context, param, vals); } +void ALmodulator_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + *val = props->Modulator.Frequency; + break; + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + *val = props->Modulator.HighPassCutoff; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param); + } +} +void ALmodulator_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALmodulator_getParamf(effect, context, param, vals); } + +DEFINE_ALEFFECT_VTABLE(ALmodulator); diff --git a/CMakeLists.txt b/CMakeLists.txt index d5b1d005..9bc240d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -819,7 +819,7 @@ SET(ALC_OBJS Alc/effects/echo.c Alc/effects/equalizer.c Alc/effects/fshifter.c - Alc/effects/modulator.c + Alc/effects/modulator.cpp Alc/effects/null.cpp Alc/effects/pshifter.cpp Alc/effects/reverb.cpp -- cgit v1.2.3 From b69b3bd89f1e6a605cf3089860b7f193c9e9f744 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 01:58:38 -0800 Subject: Convert fshifter.c to C++ --- Alc/effects/fshifter.c | 329 ---------------------------------------------- Alc/effects/fshifter.cpp | 333 +++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 334 insertions(+), 330 deletions(-) delete mode 100644 Alc/effects/fshifter.c create mode 100644 Alc/effects/fshifter.cpp diff --git a/Alc/effects/fshifter.c b/Alc/effects/fshifter.c deleted file mode 100644 index 6ada7dfa..00000000 --- a/Alc/effects/fshifter.c +++ /dev/null @@ -1,329 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2018 by Raul Herraiz. - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" -#include "filters/defs.h" - -#include "alcomplex.h" - -#define HIL_SIZE 1024 -#define OVERSAMP (1<<2) - -#define HIL_STEP (HIL_SIZE / OVERSAMP) -#define FIFO_LATENCY (HIL_STEP * (OVERSAMP-1)) - - -typedef struct ALfshifterState { - DERIVE_FROM_TYPE(ALeffectState); - - /* Effect parameters */ - ALsizei count; - ALsizei PhaseStep; - ALsizei Phase; - ALdouble ld_sign; - - /*Effects buffers*/ - ALfloat InFIFO[HIL_SIZE]; - ALcomplex OutFIFO[HIL_SIZE]; - ALcomplex OutputAccum[HIL_SIZE]; - ALcomplex Analytic[HIL_SIZE]; - ALcomplex Outdata[BUFFERSIZE]; - - alignas(16) ALfloat BufferOut[BUFFERSIZE]; - - /* Effect gains for each output channel */ - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; -} ALfshifterState; - -static ALvoid ALfshifterState_Destruct(ALfshifterState *state); -static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *device); -static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALfshifterState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALfshifterState); - -/* Define a Hann window, used to filter the HIL input and output. */ -alignas(16) static ALdouble HannWindow[HIL_SIZE]; - -static void InitHannWindow(void) -{ - ALsizei i; - - /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */ - for(i = 0;i < HIL_SIZE>>1;i++) - { - ALdouble val = sin(M_PI * (ALdouble)i / (ALdouble)(HIL_SIZE-1)); - HannWindow[i] = HannWindow[HIL_SIZE-1-i] = val * val; - } -} - -static alonce_flag HannInitOnce = AL_ONCE_FLAG_INIT; - -static void ALfshifterState_Construct(ALfshifterState *state) -{ - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALfshifterState, ALeffectState, state); - - alcall_once(&HannInitOnce, InitHannWindow); -} - -static ALvoid ALfshifterState_Destruct(ALfshifterState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); -} - -static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *UNUSED(device)) -{ - /* (Re-)initializing parameters and clear the buffers. */ - state->count = FIFO_LATENCY; - state->PhaseStep = 0; - state->Phase = 0; - state->ld_sign = 1.0; - - memset(state->InFIFO, 0, sizeof(state->InFIFO)); - memset(state->OutFIFO, 0, sizeof(state->OutFIFO)); - memset(state->OutputAccum, 0, sizeof(state->OutputAccum)); - memset(state->Analytic, 0, sizeof(state->Analytic)); - - memset(state->CurrentGains, 0, sizeof(state->CurrentGains)); - memset(state->TargetGains, 0, sizeof(state->TargetGains)); - - return AL_TRUE; -} - -static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) -{ - const ALCdevice *device = context->Device; - ALfloat coeffs[MAX_AMBI_COEFFS]; - ALfloat step; - - step = props->Fshifter.Frequency / (ALfloat)device->Frequency; - state->PhaseStep = fastf2i(minf(step, 0.5f) * FRACTIONONE); - - switch(props->Fshifter.LeftDirection) - { - case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: - state->ld_sign = -1.0; - break; - - case AL_FREQUENCY_SHIFTER_DIRECTION_UP: - state->ld_sign = 1.0; - break; - - case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: - state->Phase = 0; - state->PhaseStep = 0; - break; - } - - CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); -} - -static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) -{ - static const ALcomplex complex_zero = { 0.0, 0.0 }; - ALfloat *RESTRICT BufferOut = state->BufferOut; - ALsizei j, k, base; - - for(base = 0;base < SamplesToDo;) - { - ALsizei todo = mini(HIL_SIZE-state->count, SamplesToDo-base); - - ASSUME(todo > 0); - - /* Fill FIFO buffer with samples data */ - k = state->count; - for(j = 0;j < todo;j++,k++) - { - state->InFIFO[k] = SamplesIn[0][base+j]; - state->Outdata[base+j] = state->OutFIFO[k-FIFO_LATENCY]; - } - state->count += todo; - base += todo; - - /* Check whether FIFO buffer is filled */ - if(state->count < HIL_SIZE) continue; - - state->count = FIFO_LATENCY; - - /* Real signal windowing and store in Analytic buffer */ - for(k = 0;k < HIL_SIZE;k++) - { - state->Analytic[k].Real = state->InFIFO[k] * HannWindow[k]; - state->Analytic[k].Imag = 0.0; - } - - /* Processing signal by Discrete Hilbert Transform (analytical signal). */ - complex_hilbert(state->Analytic, HIL_SIZE); - - /* Windowing and add to output accumulator */ - for(k = 0;k < HIL_SIZE;k++) - { - state->OutputAccum[k].Real += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Real; - state->OutputAccum[k].Imag += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Imag; - } - - /* Shift accumulator, input & output FIFO */ - for(k = 0;k < HIL_STEP;k++) state->OutFIFO[k] = state->OutputAccum[k]; - for(j = 0;k < HIL_SIZE;k++,j++) state->OutputAccum[j] = state->OutputAccum[k]; - for(;j < HIL_SIZE;j++) state->OutputAccum[j] = complex_zero; - for(k = 0;k < FIFO_LATENCY;k++) - state->InFIFO[k] = state->InFIFO[k+HIL_STEP]; - } - - /* Process frequency shifter using the analytic signal obtained. */ - for(k = 0;k < SamplesToDo;k++) - { - ALdouble phase = state->Phase * ((1.0/FRACTIONONE) * 2.0*M_PI); - BufferOut[k] = (ALfloat)(state->Outdata[k].Real*cos(phase) + - state->Outdata[k].Imag*sin(phase)*state->ld_sign); - - state->Phase += state->PhaseStep; - state->Phase &= FRACTIONMASK; - } - - /* Now, mix the processed sound data to the output. */ - MixSamples(BufferOut, NumChannels, SamplesOut, state->CurrentGains, state->TargetGains, - maxi(SamplesToDo, 512), 0, SamplesToDo); -} - -typedef struct FshifterStateFactory { - DERIVE_FROM_TYPE(EffectStateFactory); -} FshifterStateFactory; - -static ALeffectState *FshifterStateFactory_create(FshifterStateFactory *UNUSED(factory)) -{ - ALfshifterState *state; - - NEW_OBJ0(state, ALfshifterState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(FshifterStateFactory); - -EffectStateFactory *FshifterStateFactory_getFactory(void) -{ - static FshifterStateFactory FshifterFactory = { { GET_VTABLE2(FshifterStateFactory, EffectStateFactory) } }; - - return STATIC_CAST(EffectStateFactory, &FshifterFactory); -} - -void ALfshifter_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_FREQUENCY_SHIFTER_FREQUENCY: - if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter frequency out of range"); - props->Fshifter.Frequency = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); - } -} - -void ALfshifter_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - ALfshifter_setParamf(effect, context, param, vals[0]); -} - -void ALfshifter_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: - if(!(val >= AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter left direction out of range"); - props->Fshifter.LeftDirection = val; - break; - - case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: - if(!(val >= AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter right direction out of range"); - props->Fshifter.RightDirection = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); - } -} -void ALfshifter_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - ALfshifter_setParami(effect, context, param, vals[0]); -} - -void ALfshifter_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: - *val = props->Fshifter.LeftDirection; - break; - case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: - *val = props->Fshifter.RightDirection; - break; - default: - alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); - } -} -void ALfshifter_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - ALfshifter_getParami(effect, context, param, vals); -} - -void ALfshifter_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_FREQUENCY_SHIFTER_FREQUENCY: - *val = props->Fshifter.Frequency; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); - } - -} - -void ALfshifter_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - ALfshifter_getParamf(effect, context, param, vals); -} - -DEFINE_ALEFFECT_VTABLE(ALfshifter); diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp new file mode 100644 index 00000000..610a2463 --- /dev/null +++ b/Alc/effects/fshifter.cpp @@ -0,0 +1,333 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2018 by Raul Herraiz. + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" +#include "filters/defs.h" + +#include "alcomplex.h" + +#define HIL_SIZE 1024 +#define OVERSAMP (1<<2) + +#define HIL_STEP (HIL_SIZE / OVERSAMP) +#define FIFO_LATENCY (HIL_STEP * (OVERSAMP-1)) + + +struct ALfshifterState final : public ALeffectState { + /* Effect parameters */ + ALsizei count; + ALsizei PhaseStep; + ALsizei Phase; + ALdouble ld_sign; + + /*Effects buffers*/ + ALfloat InFIFO[HIL_SIZE]; + ALcomplex OutFIFO[HIL_SIZE]; + ALcomplex OutputAccum[HIL_SIZE]; + ALcomplex Analytic[HIL_SIZE]; + ALcomplex Outdata[BUFFERSIZE]; + + alignas(16) ALfloat BufferOut[BUFFERSIZE]; + + /* Effect gains for each output channel */ + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; +}; + +static ALvoid ALfshifterState_Destruct(ALfshifterState *state); +static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *device); +static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALfshifterState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALfshifterState); + +/* Define a Hann window, used to filter the HIL input and output. */ +alignas(16) static ALdouble HannWindow[HIL_SIZE]; + +static void InitHannWindow(void) +{ + ALsizei i; + + /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */ + for(i = 0;i < HIL_SIZE>>1;i++) + { + ALdouble val = sin(M_PI * (ALdouble)i / (ALdouble)(HIL_SIZE-1)); + HannWindow[i] = HannWindow[HIL_SIZE-1-i] = val * val; + } +} + +static alonce_flag HannInitOnce = AL_ONCE_FLAG_INIT; + +static void ALfshifterState_Construct(ALfshifterState *state) +{ + new (state) ALfshifterState{}; + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALfshifterState, ALeffectState, state); + + alcall_once(&HannInitOnce, InitHannWindow); +} + +static ALvoid ALfshifterState_Destruct(ALfshifterState *state) +{ + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); + state->~ALfshifterState(); +} + +static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *UNUSED(device)) +{ + /* (Re-)initializing parameters and clear the buffers. */ + state->count = FIFO_LATENCY; + state->PhaseStep = 0; + state->Phase = 0; + state->ld_sign = 1.0; + + memset(state->InFIFO, 0, sizeof(state->InFIFO)); + memset(state->OutFIFO, 0, sizeof(state->OutFIFO)); + memset(state->OutputAccum, 0, sizeof(state->OutputAccum)); + memset(state->Analytic, 0, sizeof(state->Analytic)); + + memset(state->CurrentGains, 0, sizeof(state->CurrentGains)); + memset(state->TargetGains, 0, sizeof(state->TargetGains)); + + return AL_TRUE; +} + +static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +{ + const ALCdevice *device = context->Device; + ALfloat coeffs[MAX_AMBI_COEFFS]; + ALfloat step; + + step = props->Fshifter.Frequency / (ALfloat)device->Frequency; + state->PhaseStep = fastf2i(minf(step, 0.5f) * FRACTIONONE); + + switch(props->Fshifter.LeftDirection) + { + case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: + state->ld_sign = -1.0; + break; + + case AL_FREQUENCY_SHIFTER_DIRECTION_UP: + state->ld_sign = 1.0; + break; + + case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: + state->Phase = 0; + state->PhaseStep = 0; + break; + } + + CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); +} + +static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +{ + static const ALcomplex complex_zero = { 0.0, 0.0 }; + ALfloat *RESTRICT BufferOut = state->BufferOut; + ALsizei j, k, base; + + for(base = 0;base < SamplesToDo;) + { + ALsizei todo = mini(HIL_SIZE-state->count, SamplesToDo-base); + + ASSUME(todo > 0); + + /* Fill FIFO buffer with samples data */ + k = state->count; + for(j = 0;j < todo;j++,k++) + { + state->InFIFO[k] = SamplesIn[0][base+j]; + state->Outdata[base+j] = state->OutFIFO[k-FIFO_LATENCY]; + } + state->count += todo; + base += todo; + + /* Check whether FIFO buffer is filled */ + if(state->count < HIL_SIZE) continue; + + state->count = FIFO_LATENCY; + + /* Real signal windowing and store in Analytic buffer */ + for(k = 0;k < HIL_SIZE;k++) + { + state->Analytic[k].Real = state->InFIFO[k] * HannWindow[k]; + state->Analytic[k].Imag = 0.0; + } + + /* Processing signal by Discrete Hilbert Transform (analytical signal). */ + complex_hilbert(state->Analytic, HIL_SIZE); + + /* Windowing and add to output accumulator */ + for(k = 0;k < HIL_SIZE;k++) + { + state->OutputAccum[k].Real += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Real; + state->OutputAccum[k].Imag += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Imag; + } + + /* Shift accumulator, input & output FIFO */ + for(k = 0;k < HIL_STEP;k++) state->OutFIFO[k] = state->OutputAccum[k]; + for(j = 0;k < HIL_SIZE;k++,j++) state->OutputAccum[j] = state->OutputAccum[k]; + for(;j < HIL_SIZE;j++) state->OutputAccum[j] = complex_zero; + for(k = 0;k < FIFO_LATENCY;k++) + state->InFIFO[k] = state->InFIFO[k+HIL_STEP]; + } + + /* Process frequency shifter using the analytic signal obtained. */ + for(k = 0;k < SamplesToDo;k++) + { + ALdouble phase = state->Phase * ((1.0/FRACTIONONE) * 2.0*M_PI); + BufferOut[k] = (ALfloat)(state->Outdata[k].Real*cos(phase) + + state->Outdata[k].Imag*sin(phase)*state->ld_sign); + + state->Phase += state->PhaseStep; + state->Phase &= FRACTIONMASK; + } + + /* Now, mix the processed sound data to the output. */ + MixSamples(BufferOut, NumChannels, SamplesOut, state->CurrentGains, state->TargetGains, + maxi(SamplesToDo, 512), 0, SamplesToDo); +} + +struct FshifterStateFactory final : public EffectStateFactory { + FshifterStateFactory() noexcept; +}; + +static ALeffectState *FshifterStateFactory_create(FshifterStateFactory *UNUSED(factory)) +{ + ALfshifterState *state; + + NEW_OBJ0(state, ALfshifterState)(); + if(!state) return NULL; + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_EFFECTSTATEFACTORY_VTABLE(FshifterStateFactory); + +FshifterStateFactory::FshifterStateFactory() noexcept + : EffectStateFactory{GET_VTABLE2(FshifterStateFactory, EffectStateFactory)} +{ +} + +EffectStateFactory *FshifterStateFactory_getFactory(void) +{ + static FshifterStateFactory FshifterFactory{}; + return STATIC_CAST(EffectStateFactory, &FshifterFactory); +} + +void ALfshifter_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FREQUENCY_SHIFTER_FREQUENCY: + if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter frequency out of range"); + props->Fshifter.Frequency = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); + } +} + +void ALfshifter_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + ALfshifter_setParamf(effect, context, param, vals[0]); +} + +void ALfshifter_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: + if(!(val >= AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter left direction out of range"); + props->Fshifter.LeftDirection = val; + break; + + case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: + if(!(val >= AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter right direction out of range"); + props->Fshifter.RightDirection = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); + } +} +void ALfshifter_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + ALfshifter_setParami(effect, context, param, vals[0]); +} + +void ALfshifter_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: + *val = props->Fshifter.LeftDirection; + break; + case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: + *val = props->Fshifter.RightDirection; + break; + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); + } +} +void ALfshifter_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + ALfshifter_getParami(effect, context, param, vals); +} + +void ALfshifter_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FREQUENCY_SHIFTER_FREQUENCY: + *val = props->Fshifter.Frequency; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); + } + +} + +void ALfshifter_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + ALfshifter_getParamf(effect, context, param, vals); +} + +DEFINE_ALEFFECT_VTABLE(ALfshifter); diff --git a/CMakeLists.txt b/CMakeLists.txt index 9bc240d4..51fe1e87 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -818,7 +818,7 @@ SET(ALC_OBJS Alc/effects/distortion.c Alc/effects/echo.c Alc/effects/equalizer.c - Alc/effects/fshifter.c + Alc/effects/fshifter.cpp Alc/effects/modulator.cpp Alc/effects/null.cpp Alc/effects/pshifter.cpp -- cgit v1.2.3 From b485cbe53a4bd5c3aab1b584c1752be8bc5cb894 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 02:30:41 -0800 Subject: Make the Hann windows const --- Alc/effects/fshifter.cpp | 60 +++++++++--------- Alc/effects/pshifter.cpp | 161 +++++++++++++++++++++++------------------------ 2 files changed, 110 insertions(+), 111 deletions(-) diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp index 610a2463..23291ccd 100644 --- a/Alc/effects/fshifter.cpp +++ b/Alc/effects/fshifter.cpp @@ -20,8 +20,8 @@ #include "config.h" -#include -#include +#include +#include #include "alMain.h" #include "alAuxEffectSlot.h" @@ -31,12 +31,29 @@ #include "alcomplex.h" +namespace { + #define HIL_SIZE 1024 #define OVERSAMP (1<<2) #define HIL_STEP (HIL_SIZE / OVERSAMP) #define FIFO_LATENCY (HIL_STEP * (OVERSAMP-1)) +/* Define a Hann window, used to filter the HIL input and output. */ +/* Making this constexpr seems to require C++14. */ +std::array InitHannWindow(void) +{ + std::array ret; + /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */ + for(ALsizei i{0};i < HIL_SIZE>>1;i++) + { + ALdouble val = std::sin(M_PI * (ALdouble)i / (ALdouble)(HIL_SIZE-1)); + ret[i] = ret[HIL_SIZE-1-i] = val * val; + } + return ret; +} +alignas(16) const std::array HannWindow = InitHannWindow(); + struct ALfshifterState final : public ALeffectState { /* Effect parameters */ @@ -59,47 +76,28 @@ struct ALfshifterState final : public ALeffectState { ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; }; -static ALvoid ALfshifterState_Destruct(ALfshifterState *state); -static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *device); -static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +ALvoid ALfshifterState_Destruct(ALfshifterState *state); +ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *device); +ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); +ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALfshifterState) DEFINE_ALEFFECTSTATE_VTABLE(ALfshifterState); -/* Define a Hann window, used to filter the HIL input and output. */ -alignas(16) static ALdouble HannWindow[HIL_SIZE]; - -static void InitHannWindow(void) -{ - ALsizei i; - - /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */ - for(i = 0;i < HIL_SIZE>>1;i++) - { - ALdouble val = sin(M_PI * (ALdouble)i / (ALdouble)(HIL_SIZE-1)); - HannWindow[i] = HannWindow[HIL_SIZE-1-i] = val * val; - } -} - -static alonce_flag HannInitOnce = AL_ONCE_FLAG_INIT; - -static void ALfshifterState_Construct(ALfshifterState *state) +void ALfshifterState_Construct(ALfshifterState *state) { new (state) ALfshifterState{}; ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); SET_VTABLE2(ALfshifterState, ALeffectState, state); - - alcall_once(&HannInitOnce, InitHannWindow); } -static ALvoid ALfshifterState_Destruct(ALfshifterState *state) +ALvoid ALfshifterState_Destruct(ALfshifterState *state) { ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); state->~ALfshifterState(); } -static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *UNUSED(device)) +ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *UNUSED(device)) { /* (Re-)initializing parameters and clear the buffers. */ state->count = FIFO_LATENCY; @@ -118,7 +116,7 @@ static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice return AL_TRUE; } -static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) { const ALCdevice *device = context->Device; ALfloat coeffs[MAX_AMBI_COEFFS]; @@ -147,7 +145,7 @@ static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *c ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); } -static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { static const ALcomplex complex_zero = { 0.0, 0.0 }; ALfloat *RESTRICT BufferOut = state->BufferOut; @@ -215,6 +213,8 @@ static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToD maxi(SamplesToDo, 512), 0, SamplesToDo); } +} // namespace + struct FshifterStateFactory final : public EffectStateFactory { FshifterStateFactory() noexcept; }; diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp index d3a399ff..410eb982 100644 --- a/Alc/effects/pshifter.cpp +++ b/Alc/effects/pshifter.cpp @@ -20,8 +20,8 @@ #include "config.h" -#include -#include +#include +#include #include "alMain.h" #include "alAuxEffectSlot.h" @@ -32,6 +32,8 @@ #include "alcomplex.h" +namespace { + #define STFT_SIZE 1024 #define STFT_HALF_SIZE (STFT_SIZE>>1) #define OVERSAMP (1<<2) @@ -39,71 +41,7 @@ #define STFT_STEP (STFT_SIZE / OVERSAMP) #define FIFO_LATENCY (STFT_STEP * (OVERSAMP-1)) - -typedef struct ALphasor { - ALdouble Amplitude; - ALdouble Phase; -} ALphasor; - -typedef struct ALFrequencyDomain { - ALdouble Amplitude; - ALdouble Frequency; -} ALfrequencyDomain; - - -struct ALpshifterState final : public ALeffectState { - /* Effect parameters */ - ALsizei count; - ALsizei PitchShiftI; - ALfloat PitchShift; - ALfloat FreqPerBin; - - /*Effects buffers*/ - ALfloat InFIFO[STFT_SIZE]; - ALfloat OutFIFO[STFT_STEP]; - ALdouble LastPhase[STFT_HALF_SIZE+1]; - ALdouble SumPhase[STFT_HALF_SIZE+1]; - ALdouble OutputAccum[STFT_SIZE]; - - ALcomplex FFTbuffer[STFT_SIZE]; - - ALfrequencyDomain Analysis_buffer[STFT_HALF_SIZE+1]; - ALfrequencyDomain Syntesis_buffer[STFT_HALF_SIZE+1]; - - alignas(16) ALfloat BufferOut[BUFFERSIZE]; - - /* Effect gains for each output channel */ - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; -}; - -static ALvoid ALpshifterState_Destruct(ALpshifterState *state); -static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device); -static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALpshifterState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALpshifterState); - - -/* Define a Hann window, used to filter the STFT input and output. */ -alignas(16) static ALdouble HannWindow[STFT_SIZE]; - -static void InitHannWindow(void) -{ - ALsizei i; - - /* Create lookup table of the Hann window for the desired size, i.e. STFT_SIZE */ - for(i = 0;i < STFT_SIZE>>1;i++) - { - ALdouble val = sin(M_PI * (ALdouble)i / (ALdouble)(STFT_SIZE-1)); - HannWindow[i] = HannWindow[STFT_SIZE-1-i] = val * val; - } -} -static alonce_flag HannInitOnce = AL_ONCE_FLAG_INIT; - - -static inline ALint double2int(ALdouble d) +inline ALint double2int(ALdouble d) { #if ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) && \ !defined(__SSE2_MATH__)) || (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP < 2) @@ -133,46 +71,105 @@ static inline ALint double2int(ALdouble d) #endif } +/* Define a Hann window, used to filter the STFT input and output. */ +/* Making this constexpr seems to require C++14. */ +std::array InitHannWindow(void) +{ + std::array ret; + /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */ + for(ALsizei i{0};i < STFT_SIZE>>1;i++) + { + ALdouble val = std::sin(M_PI * (ALdouble)i / (ALdouble)(STFT_SIZE-1)); + ret[i] = ret[STFT_SIZE-1-i] = val * val; + } + return ret; +} +alignas(16) const std::array HannWindow = InitHannWindow(); + + +struct ALphasor { + ALdouble Amplitude; + ALdouble Phase; +}; + +struct ALfrequencyDomain { + ALdouble Amplitude; + ALdouble Frequency; +}; + /* Converts ALcomplex to ALphasor */ -static inline ALphasor rect2polar(ALcomplex number) +inline ALphasor rect2polar(ALcomplex number) { ALphasor polar; - polar.Amplitude = sqrt(number.Real*number.Real + number.Imag*number.Imag); - polar.Phase = atan2(number.Imag, number.Real); + polar.Amplitude = std::sqrt(number.Real*number.Real + number.Imag*number.Imag); + polar.Phase = std::atan2(number.Imag, number.Real); return polar; } /* Converts ALphasor to ALcomplex */ -static inline ALcomplex polar2rect(ALphasor number) +inline ALcomplex polar2rect(ALphasor number) { ALcomplex cartesian; - cartesian.Real = number.Amplitude * cos(number.Phase); - cartesian.Imag = number.Amplitude * sin(number.Phase); + cartesian.Real = number.Amplitude * std::cos(number.Phase); + cartesian.Imag = number.Amplitude * std::sin(number.Phase); return cartesian; } -static void ALpshifterState_Construct(ALpshifterState *state) + +struct ALpshifterState final : public ALeffectState { + /* Effect parameters */ + ALsizei count; + ALsizei PitchShiftI; + ALfloat PitchShift; + ALfloat FreqPerBin; + + /*Effects buffers*/ + ALfloat InFIFO[STFT_SIZE]; + ALfloat OutFIFO[STFT_STEP]; + ALdouble LastPhase[STFT_HALF_SIZE+1]; + ALdouble SumPhase[STFT_HALF_SIZE+1]; + ALdouble OutputAccum[STFT_SIZE]; + + ALcomplex FFTbuffer[STFT_SIZE]; + + ALfrequencyDomain Analysis_buffer[STFT_HALF_SIZE+1]; + ALfrequencyDomain Syntesis_buffer[STFT_HALF_SIZE+1]; + + alignas(16) ALfloat BufferOut[BUFFERSIZE]; + + /* Effect gains for each output channel */ + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; +}; + +static ALvoid ALpshifterState_Destruct(ALpshifterState *state); +static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device); +static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALpshifterState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALpshifterState); + +void ALpshifterState_Construct(ALpshifterState *state) { new (state) ALpshifterState{}; ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); SET_VTABLE2(ALpshifterState, ALeffectState, state); - - alcall_once(&HannInitOnce, InitHannWindow); } -static ALvoid ALpshifterState_Destruct(ALpshifterState *state) +ALvoid ALpshifterState_Destruct(ALpshifterState *state) { ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); state->~ALpshifterState(); } -static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device) +ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device) { /* (Re-)initializing parameters and clear the buffers. */ state->count = FIFO_LATENCY; @@ -195,13 +192,13 @@ static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice return AL_TRUE; } -static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) { const ALCdevice *device = context->Device; ALfloat coeffs[MAX_AMBI_COEFFS]; float pitch; - pitch = powf(2.0f, + pitch = std::pow(2.0f, (ALfloat)(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f ); state->PitchShiftI = fastf2i(pitch*FRACTIONONE); @@ -211,7 +208,7 @@ static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *c ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); } -static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { /* Pitch shifter engine based on the work of Stephan Bernsee. * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/ @@ -347,6 +344,8 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD maxi(SamplesToDo, 512), 0, SamplesToDo); } +} // namespace + struct PshifterStateFactory final : public EffectStateFactory { PshifterStateFactory() noexcept; }; -- cgit v1.2.3 From 09943683b5872943cd1f9211ef2a77922906b906 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 02:41:21 -0800 Subject: Remove some more unused stuff --- common/threads.c | 18 +++--------------- common/threads.h | 18 +----------------- 2 files changed, 4 insertions(+), 32 deletions(-) diff --git a/common/threads.c b/common/threads.c index 1ecec365..b0f90bc5 100644 --- a/common/threads.c +++ b/common/threads.c @@ -213,17 +213,6 @@ int alsem_trywait(alsem_t *sem) } -void alcall_once(alonce_flag *once, void (*callback)(void)) -{ - LONG ret; - while((ret=InterlockedExchange(once, 1)) == 1) - althrd_yield(); - if(ret == 0) - (*callback)(); - InterlockedExchange(once, 2); -} - - void althrd_deinit(void) { ResetUIntMap(&ThrdIdHandle); @@ -239,10 +228,6 @@ void althrd_deinit(void) #endif -extern inline void alcall_once(alonce_flag *once, void (*callback)(void)); - -extern inline void althrd_deinit(void); - void althrd_setname(althrd_t thr, const char *name) { #if defined(HAVE_PTHREAD_SETNAME_NP) @@ -457,4 +442,7 @@ int alsem_trywait(alsem_t *sem) #endif /* __APPLE__ */ +void althrd_deinit(void) +{ } + #endif diff --git a/common/threads.h b/common/threads.h index ae033931..9abb22f2 100644 --- a/common/threads.h +++ b/common/threads.h @@ -37,15 +37,10 @@ typedef int (*althrd_start_t)(void*); #define WIN32_LEAN_AND_MEAN #include - typedef DWORD althrd_t; typedef CRITICAL_SECTION almtx_t; typedef HANDLE alsem_t; -typedef LONG alonce_flag; - -#define AL_ONCE_FLAG_INIT 0 -void alcall_once(alonce_flag *once, void (*callback)(void)); void althrd_deinit(void); @@ -90,7 +85,6 @@ inline int almtx_unlock(almtx_t *mtx) #include #endif /* __APPLE__ */ - typedef pthread_t althrd_t; typedef pthread_mutex_t almtx_t; #ifdef __APPLE__ @@ -98,10 +92,9 @@ typedef dispatch_semaphore_t alsem_t; #else /* !__APPLE__ */ typedef sem_t alsem_t; #endif /* __APPLE__ */ -typedef pthread_once_t alonce_flag; -#define AL_ONCE_FLAG_INIT PTHREAD_ONCE_INIT +void althrd_deinit(void); inline althrd_t althrd_current(void) { @@ -133,15 +126,6 @@ inline int almtx_unlock(almtx_t *mtx) return althrd_success; } - -inline void alcall_once(alonce_flag *once, void (*callback)(void)) -{ - pthread_once(once, callback); -} - - -inline void althrd_deinit(void) { } - #endif -- cgit v1.2.3 From ccdaca80c910047e16f710d44f640a6d6f86a195 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 04:14:57 -0800 Subject: Use standard complex types instead of custom --- Alc/effects/fshifter.cpp | 41 ++++++++-------- Alc/effects/pshifter.cpp | 101 +++++++++++++++++---------------------- CMakeLists.txt | 2 +- common/alcomplex.c | 122 ----------------------------------------------- common/alcomplex.cpp | 76 +++++++++++++++++++++++++++++ common/alcomplex.h | 20 ++------ 6 files changed, 145 insertions(+), 217 deletions(-) delete mode 100644 common/alcomplex.c create mode 100644 common/alcomplex.cpp diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp index 23291ccd..e0dced3a 100644 --- a/Alc/effects/fshifter.cpp +++ b/Alc/effects/fshifter.cpp @@ -22,6 +22,8 @@ #include #include +#include +#include #include "alMain.h" #include "alAuxEffectSlot.h" @@ -33,6 +35,8 @@ namespace { +using complex_d = std::complex; + #define HIL_SIZE 1024 #define OVERSAMP (1<<2) @@ -64,10 +68,10 @@ struct ALfshifterState final : public ALeffectState { /*Effects buffers*/ ALfloat InFIFO[HIL_SIZE]; - ALcomplex OutFIFO[HIL_SIZE]; - ALcomplex OutputAccum[HIL_SIZE]; - ALcomplex Analytic[HIL_SIZE]; - ALcomplex Outdata[BUFFERSIZE]; + complex_d OutFIFO[HIL_SIZE]; + complex_d OutputAccum[HIL_SIZE]; + complex_d Analytic[HIL_SIZE]; + complex_d Outdata[BUFFERSIZE]; alignas(16) ALfloat BufferOut[BUFFERSIZE]; @@ -105,13 +109,13 @@ ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *UNUSED state->Phase = 0; state->ld_sign = 1.0; - memset(state->InFIFO, 0, sizeof(state->InFIFO)); - memset(state->OutFIFO, 0, sizeof(state->OutFIFO)); - memset(state->OutputAccum, 0, sizeof(state->OutputAccum)); - memset(state->Analytic, 0, sizeof(state->Analytic)); + std::fill(std::begin(state->InFIFO), std::end(state->InFIFO), 0.0f); + std::fill(std::begin(state->OutFIFO), std::end(state->OutFIFO), complex_d{}); + std::fill(std::begin(state->OutputAccum), std::end(state->OutputAccum), complex_d{}); + std::fill(std::begin(state->Analytic), std::end(state->Analytic), complex_d{}); - memset(state->CurrentGains, 0, sizeof(state->CurrentGains)); - memset(state->TargetGains, 0, sizeof(state->TargetGains)); + std::fill(std::begin(state->CurrentGains), std::end(state->CurrentGains), 0.0f); + std::fill(std::begin(state->TargetGains), std::end(state->TargetGains), 0.0f); return AL_TRUE; } @@ -147,7 +151,7 @@ ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - static const ALcomplex complex_zero = { 0.0, 0.0 }; + static const complex_d complex_zero{0.0, 0.0}; ALfloat *RESTRICT BufferOut = state->BufferOut; ALsizei j, k, base; @@ -175,8 +179,8 @@ ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, cons /* Real signal windowing and store in Analytic buffer */ for(k = 0;k < HIL_SIZE;k++) { - state->Analytic[k].Real = state->InFIFO[k] * HannWindow[k]; - state->Analytic[k].Imag = 0.0; + state->Analytic[k].real(state->InFIFO[k] * HannWindow[k]); + state->Analytic[k].imag(0.0); } /* Processing signal by Discrete Hilbert Transform (analytical signal). */ @@ -184,10 +188,7 @@ ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, cons /* Windowing and add to output accumulator */ for(k = 0;k < HIL_SIZE;k++) - { - state->OutputAccum[k].Real += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Real; - state->OutputAccum[k].Imag += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Imag; - } + state->OutputAccum[k] += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k]; /* Shift accumulator, input & output FIFO */ for(k = 0;k < HIL_STEP;k++) state->OutFIFO[k] = state->OutputAccum[k]; @@ -200,9 +201,9 @@ ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, cons /* Process frequency shifter using the analytic signal obtained. */ for(k = 0;k < SamplesToDo;k++) { - ALdouble phase = state->Phase * ((1.0/FRACTIONONE) * 2.0*M_PI); - BufferOut[k] = (ALfloat)(state->Outdata[k].Real*cos(phase) + - state->Outdata[k].Imag*sin(phase)*state->ld_sign); + double phase = state->Phase * ((1.0/FRACTIONONE) * 2.0*M_PI); + BufferOut[k] = (float)(state->Outdata[k].real()*std::cos(phase) + + state->Outdata[k].imag()*std::sin(phase)*state->ld_sign); state->Phase += state->PhaseStep; state->Phase &= FRACTIONMASK; diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp index 410eb982..f1a80254 100644 --- a/Alc/effects/pshifter.cpp +++ b/Alc/effects/pshifter.cpp @@ -22,6 +22,8 @@ #include #include +#include +#include #include "alMain.h" #include "alAuxEffectSlot.h" @@ -34,6 +36,8 @@ namespace { +using complex_d = std::complex; + #define STFT_SIZE 1024 #define STFT_HALF_SIZE (STFT_SIZE>>1) #define OVERSAMP (1<<2) @@ -41,7 +45,7 @@ namespace { #define STFT_STEP (STFT_SIZE / OVERSAMP) #define FIFO_LATENCY (STFT_STEP * (OVERSAMP-1)) -inline ALint double2int(ALdouble d) +inline int double2int(double d) { #if ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) && \ !defined(__SSE2_MATH__)) || (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP < 2) @@ -98,28 +102,18 @@ struct ALfrequencyDomain { }; -/* Converts ALcomplex to ALphasor */ -inline ALphasor rect2polar(ALcomplex number) +/* Converts complex to ALphasor */ +inline ALphasor rect2polar(const complex_d &number) { ALphasor polar; - - polar.Amplitude = std::sqrt(number.Real*number.Real + number.Imag*number.Imag); - polar.Phase = std::atan2(number.Imag, number.Real); - + polar.Amplitude = std::abs(number); + polar.Phase = std::arg(number); return polar; } -/* Converts ALphasor to ALcomplex */ -inline ALcomplex polar2rect(ALphasor number) -{ - ALcomplex cartesian; - - cartesian.Real = number.Amplitude * std::cos(number.Phase); - cartesian.Imag = number.Amplitude * std::sin(number.Phase); - - return cartesian; -} - +/* Converts ALphasor to complex */ +inline complex_d polar2rect(const ALphasor &number) +{ return std::polar(number.Amplitude, number.Phase); } struct ALpshifterState final : public ALeffectState { @@ -136,7 +130,7 @@ struct ALpshifterState final : public ALeffectState { ALdouble SumPhase[STFT_HALF_SIZE+1]; ALdouble OutputAccum[STFT_SIZE]; - ALcomplex FFTbuffer[STFT_SIZE]; + complex_d FFTbuffer[STFT_SIZE]; ALfrequencyDomain Analysis_buffer[STFT_HALF_SIZE+1]; ALfrequencyDomain Syntesis_buffer[STFT_HALF_SIZE+1]; @@ -177,17 +171,17 @@ ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device state->PitchShift = 1.0f; state->FreqPerBin = device->Frequency / (ALfloat)STFT_SIZE; - memset(state->InFIFO, 0, sizeof(state->InFIFO)); - memset(state->OutFIFO, 0, sizeof(state->OutFIFO)); - memset(state->FFTbuffer, 0, sizeof(state->FFTbuffer)); - memset(state->LastPhase, 0, sizeof(state->LastPhase)); - memset(state->SumPhase, 0, sizeof(state->SumPhase)); - memset(state->OutputAccum, 0, sizeof(state->OutputAccum)); - memset(state->Analysis_buffer, 0, sizeof(state->Analysis_buffer)); - memset(state->Syntesis_buffer, 0, sizeof(state->Syntesis_buffer)); + std::fill(std::begin(state->InFIFO), std::end(state->InFIFO), 0.0f); + std::fill(std::begin(state->OutFIFO), std::end(state->OutFIFO), 0.0f); + std::fill(std::begin(state->LastPhase), std::end(state->LastPhase), 0.0); + std::fill(std::begin(state->SumPhase), std::end(state->SumPhase), 0.0); + std::fill(std::begin(state->OutputAccum), std::end(state->OutputAccum), 0.0); + std::fill(std::begin(state->FFTbuffer), std::end(state->FFTbuffer), complex_d{}); + std::fill(std::begin(state->Analysis_buffer), std::end(state->Analysis_buffer), ALfrequencyDomain{}); + std::fill(std::begin(state->Syntesis_buffer), std::end(state->Syntesis_buffer), ALfrequencyDomain{}); - memset(state->CurrentGains, 0, sizeof(state->CurrentGains)); - memset(state->TargetGains, 0, sizeof(state->TargetGains)); + std::fill(std::begin(state->CurrentGains), std::end(state->CurrentGains), 0.0f); + std::fill(std::begin(state->TargetGains), std::end(state->TargetGains), 0.0f); return AL_TRUE; } @@ -214,13 +208,12 @@ ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, cons * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/ */ - static const ALdouble expected = M_PI*2.0 / OVERSAMP; - const ALdouble freq_per_bin = state->FreqPerBin; - ALfloat *RESTRICT bufferOut = state->BufferOut; - ALsizei count = state->count; - ALsizei i, j, k; + static constexpr ALdouble expected{M_PI*2.0 / OVERSAMP}; + const ALdouble freq_per_bin{state->FreqPerBin}; + ALfloat *RESTRICT bufferOut{state->BufferOut}; + ALsizei count{state->count}; - for(i = 0;i < SamplesToDo;) + for(ALsizei i{0};i < SamplesToDo;) { do { /* Fill FIFO buffer with samples data */ @@ -235,10 +228,10 @@ ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, cons count = FIFO_LATENCY; /* Real signal windowing and store in FFTbuffer */ - for(k = 0;k < STFT_SIZE;k++) + for(ALsizei k{0};k < STFT_SIZE;k++) { - state->FFTbuffer[k].Real = state->InFIFO[k] * HannWindow[k]; - state->FFTbuffer[k].Imag = 0.0; + state->FFTbuffer[k].real(state->InFIFO[k] * HannWindow[k]); + state->FFTbuffer[k].imag(0.0); } /* ANALYSIS */ @@ -248,20 +241,16 @@ ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, cons /* Analyze the obtained data. Since the real FFT is symmetric, only * STFT_HALF_SIZE+1 samples are needed. */ - for(k = 0;k < STFT_HALF_SIZE+1;k++) + for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) { - ALphasor component; - ALdouble tmp; - ALint qpd; - /* Compute amplitude and phase */ - component = rect2polar(state->FFTbuffer[k]); + ALphasor component{rect2polar(state->FFTbuffer[k])}; /* Compute phase difference and subtract expected phase difference */ - tmp = (component.Phase - state->LastPhase[k]) - k*expected; + double tmp{(component.Phase - state->LastPhase[k]) - k*expected}; /* Map delta phase into +/- Pi interval */ - qpd = double2int(tmp / M_PI); + int qpd{double2int(tmp / M_PI)}; tmp -= M_PI * (qpd + (qpd%2)); /* Get deviation from bin frequency from the +/- Pi interval */ @@ -280,15 +269,15 @@ ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, cons /* PROCESSING */ /* pitch shifting */ - for(k = 0;k < STFT_HALF_SIZE+1;k++) + for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) { state->Syntesis_buffer[k].Amplitude = 0.0; state->Syntesis_buffer[k].Frequency = 0.0; } - for(k = 0;k < STFT_HALF_SIZE+1;k++) + for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) { - j = (k*state->PitchShiftI) >> FRACTIONBITS; + ALsizei j{(k*state->PitchShiftI) >> FRACTIONBITS}; if(j >= STFT_HALF_SIZE+1) break; state->Syntesis_buffer[j].Amplitude += state->Analysis_buffer[k].Amplitude; @@ -298,7 +287,7 @@ ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, cons /* SYNTHESIS */ /* Synthesis the processing data */ - for(k = 0;k < STFT_HALF_SIZE+1;k++) + for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) { ALphasor component; ALdouble tmp; @@ -316,21 +305,19 @@ ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, cons state->FFTbuffer[k] = polar2rect(component); } /* zero negative frequencies for recontruct a real signal */ - for(k = STFT_HALF_SIZE+1;k < STFT_SIZE;k++) - { - state->FFTbuffer[k].Real = 0.0; - state->FFTbuffer[k].Imag = 0.0; - } + for(ALsizei k{STFT_HALF_SIZE+1};k < STFT_SIZE;k++) + state->FFTbuffer[k] = complex_d{}; /* Apply iFFT to buffer data */ complex_fft(state->FFTbuffer, STFT_SIZE, 1.0); /* Windowing and add to output */ - for(k = 0;k < STFT_SIZE;k++) - state->OutputAccum[k] += HannWindow[k] * state->FFTbuffer[k].Real / + for(ALsizei k{0};k < STFT_SIZE;k++) + state->OutputAccum[k] += HannWindow[k] * state->FFTbuffer[k].real() / (0.5 * STFT_HALF_SIZE * OVERSAMP); /* Shift accumulator, input & output FIFO */ + ALsizei j, k; for(k = 0;k < STFT_STEP;k++) state->OutFIFO[k] = (ALfloat)state->OutputAccum[k]; for(j = 0;k < STFT_SIZE;k++,j++) state->OutputAccum[j] = state->OutputAccum[k]; for(;j < STFT_SIZE;j++) state->OutputAccum[j] = 0.0; diff --git a/CMakeLists.txt b/CMakeLists.txt index 51fe1e87..768856df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -755,7 +755,7 @@ ENDIF() SET(COMMON_OBJS - common/alcomplex.c + common/alcomplex.cpp common/alcomplex.h common/align.h common/almalloc.c diff --git a/common/alcomplex.c b/common/alcomplex.c deleted file mode 100644 index 851f4105..00000000 --- a/common/alcomplex.c +++ /dev/null @@ -1,122 +0,0 @@ - -#include "config.h" - -#include "alcomplex.h" -#include "math_defs.h" - - -/** Addition of two complex numbers. */ -static inline ALcomplex complex_add(ALcomplex a, ALcomplex b) -{ - ALcomplex result; - - result.Real = a.Real + b.Real; - result.Imag = a.Imag + b.Imag; - - return result; -} - -/** Subtraction of two complex numbers. */ -static inline ALcomplex complex_sub(ALcomplex a, ALcomplex b) -{ - ALcomplex result; - - result.Real = a.Real - b.Real; - result.Imag = a.Imag - b.Imag; - - return result; -} - -/** Multiplication of two complex numbers. */ -static inline ALcomplex complex_mult(ALcomplex a, ALcomplex b) -{ - ALcomplex result; - - result.Real = a.Real*b.Real - a.Imag*b.Imag; - result.Imag = a.Imag*b.Real + a.Real*b.Imag; - - return result; -} - - -void complex_fft(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign) -{ - ALsizei i, j, k, mask, step, step2; - ALcomplex temp, u, w; - ALdouble arg; - - /* Bit-reversal permutation applied to a sequence of FFTSize items */ - for(i = 1;i < FFTSize-1;i++) - { - for(mask = 0x1, j = 0;mask < FFTSize;mask <<= 1) - { - if((i&mask) != 0) - j++; - j <<= 1; - } - j >>= 1; - - if(i < j) - { - temp = FFTBuffer[i]; - FFTBuffer[i] = FFTBuffer[j]; - FFTBuffer[j] = temp; - } - } - - /* Iterative form of Danielson–Lanczos lemma */ - for(i = 1, step = 2;i < FFTSize;i<<=1, step<<=1) - { - step2 = step >> 1; - arg = M_PI / step2; - - w.Real = cos(arg); - w.Imag = sin(arg) * Sign; - - u.Real = 1.0; - u.Imag = 0.0; - - for(j = 0;j < step2;j++) - { - for(k = j;k < FFTSize;k+=step) - { - temp = complex_mult(FFTBuffer[k+step2], u); - FFTBuffer[k+step2] = complex_sub(FFTBuffer[k], temp); - FFTBuffer[k] = complex_add(FFTBuffer[k], temp); - } - - u = complex_mult(u, w); - } - } -} - -void complex_hilbert(ALcomplex *Buffer, ALsizei size) -{ - const ALdouble inverse_size = 1.0/(ALdouble)size; - ALsizei todo, i; - - for(i = 0;i < size;i++) - Buffer[i].Imag = 0.0; - - complex_fft(Buffer, size, 1.0); - - todo = size >> 1; - Buffer[0].Real *= inverse_size; - Buffer[0].Imag *= inverse_size; - for(i = 1;i < todo;i++) - { - Buffer[i].Real *= 2.0*inverse_size; - Buffer[i].Imag *= 2.0*inverse_size; - } - Buffer[i].Real *= inverse_size; - Buffer[i].Imag *= inverse_size; - i++; - - for(;i < size;i++) - { - Buffer[i].Real = 0.0; - Buffer[i].Imag = 0.0; - } - - complex_fft(Buffer, size, -1.0); -} diff --git a/common/alcomplex.cpp b/common/alcomplex.cpp new file mode 100644 index 00000000..de2d1be9 --- /dev/null +++ b/common/alcomplex.cpp @@ -0,0 +1,76 @@ + +#include "config.h" + +#include "alcomplex.h" + +#include + +namespace { + +constexpr double Pi{3.141592653589793238462643383279502884}; + +} // namespace + +void complex_fft(std::complex *FFTBuffer, int FFTSize, double Sign) +{ + /* Bit-reversal permutation applied to a sequence of FFTSize items */ + for(int i{1};i < FFTSize-1;i++) + { + int j{0}; + for(int mask{1};mask < FFTSize;mask <<= 1) + { + if((i&mask) != 0) + j++; + j <<= 1; + } + j >>= 1; + + if(i < j) + std::swap(FFTBuffer[i], FFTBuffer[j]); + } + + /* Iterative form of Danielson–Lanczos lemma */ + int step{2}; + for(int i{1};i < FFTSize;i<<=1, step<<=1) + { + int step2{step >> 1}; + double arg{Pi / step2}; + + std::complex w{std::cos(arg), std::sin(arg)*Sign}; + std::complex u{1.0, 0.0}; + for(int j{0};j < step2;j++) + { + for(int k{j};k < FFTSize;k+=step) + { + std::complex temp{FFTBuffer[k+step2] * u}; + FFTBuffer[k+step2] = FFTBuffer[k] - temp; + FFTBuffer[k] += temp; + } + + u *= w; + } + } +} + +void complex_hilbert(std::complex *Buffer, int size) +{ + const double inverse_size = 1.0/(double)size; + + for(int i{0};i < size;i++) + Buffer[i].imag(0.0); + + complex_fft(Buffer, size, 1.0); + + int todo{size>>1}; + int i{0}; + + Buffer[i++] *= inverse_size; + while(i < todo) + Buffer[i++] *= 2.0*inverse_size; + Buffer[i++] *= inverse_size; + + for(;i < size;i++) + Buffer[i] = std::complex{}; + + complex_fft(Buffer, size, -1.0); +} diff --git a/common/alcomplex.h b/common/alcomplex.h index 0070ac13..554886c4 100644 --- a/common/alcomplex.h +++ b/common/alcomplex.h @@ -1,17 +1,7 @@ #ifndef ALCOMPLEX_H #define ALCOMPLEX_H -#include "AL/al.h" - - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct ALcomplex { - ALdouble Real; - ALdouble Imag; -} ALcomplex; +#include /** * Iterative implementation of 2-radix FFT (In-place algorithm). Sign = -1 is @@ -20,7 +10,7 @@ typedef struct ALcomplex { * FFTBuffer[0...FFTSize-1]. FFTBuffer is an array of complex numbers, FFTSize * MUST BE power of two. */ -void complex_fft(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign); +void complex_fft(std::complex *FFTBuffer, int FFTSize, double Sign); /** * Calculate the complex helical sequence (discrete-time analytical signal) of @@ -29,10 +19,6 @@ void complex_fft(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign); * Buffer[0...size-1]. Buffer is an array of complex numbers, size MUST BE * power of two. */ -void complex_hilbert(ALcomplex *Buffer, ALsizei size); - -#ifdef __cplusplus -} // extern "C" -#endif +void complex_hilbert(std::complex *Buffer, int size); #endif /* ALCOMPLEX_H */ -- cgit v1.2.3 From 1fae8c16a8c0634ffa44b4a2e25f3be4899ea7e2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 05:31:29 -0800 Subject: Convert threads.c to C++ Also vastly simplify and remove related code. --- CMakeLists.txt | 5 +- OpenAL32/Include/alBuffer.h | 1 - common/rwlock.c | 59 ------ common/rwlock.h | 32 ---- common/threads.c | 448 -------------------------------------------- common/threads.cpp | 442 +++++++++++++++++++++++++++++++++++++++++++ common/uintmap.c | 182 ------------------ common/uintmap.h | 62 +++--- 8 files changed, 471 insertions(+), 760 deletions(-) delete mode 100644 common/rwlock.c delete mode 100644 common/rwlock.h delete mode 100644 common/threads.c create mode 100644 common/threads.cpp delete mode 100644 common/uintmap.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 768856df..79530117 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -764,12 +764,9 @@ SET(COMMON_OBJS common/atomic.h common/bool.h common/math_defs.h - common/rwlock.c - common/rwlock.h common/static_assert.h - common/threads.c + common/threads.cpp common/threads.h - common/uintmap.c common/uintmap.h ) SET(OPENAL_OBJS diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index fbe3e6e5..f264caa5 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -7,7 +7,6 @@ #include "inprogext.h" #include "atomic.h" -#include "rwlock.h" #ifdef __cplusplus extern "C" { diff --git a/common/rwlock.c b/common/rwlock.c deleted file mode 100644 index 44237282..00000000 --- a/common/rwlock.c +++ /dev/null @@ -1,59 +0,0 @@ - -#include "config.h" - -#include "rwlock.h" - -#include "bool.h" -#include "atomic.h" -#include "threads.h" - - -/* A simple spinlock. Yield the thread while the given integer is set by - * another. Could probably be improved... */ -#define LOCK(l) do { \ - while(ATOMIC_EXCHANGE(&(l), 1, almemory_order_acq_rel) == true) \ - althrd_yield(); \ -} while(0) -#define UNLOCK(l) ATOMIC_STORE(&(l), 0, almemory_order_release) - - -void RWLockInit(RWLock *lock) -{ - InitRef(&lock->read_count, 0); - InitRef(&lock->write_count, 0); - ATOMIC_INIT(&lock->read_lock, 0); - ATOMIC_INIT(&lock->read_entry_lock, 0); - ATOMIC_INIT(&lock->write_lock, 0); -} - -void ReadLock(RWLock *lock) -{ - LOCK(lock->read_entry_lock); - LOCK(lock->read_lock); - /* NOTE: ATOMIC_ADD returns the *old* value! */ - if(ATOMIC_ADD(&lock->read_count, 1, almemory_order_acq_rel) == 0) - LOCK(lock->write_lock); - UNLOCK(lock->read_lock); - UNLOCK(lock->read_entry_lock); -} - -void ReadUnlock(RWLock *lock) -{ - /* NOTE: ATOMIC_SUB returns the *old* value! */ - if(ATOMIC_SUB(&lock->read_count, 1, almemory_order_acq_rel) == 1) - UNLOCK(lock->write_lock); -} - -void WriteLock(RWLock *lock) -{ - if(ATOMIC_ADD(&lock->write_count, 1, almemory_order_acq_rel) == 0) - LOCK(lock->read_lock); - LOCK(lock->write_lock); -} - -void WriteUnlock(RWLock *lock) -{ - UNLOCK(lock->write_lock); - if(ATOMIC_SUB(&lock->write_count, 1, almemory_order_acq_rel) == 1) - UNLOCK(lock->read_lock); -} diff --git a/common/rwlock.h b/common/rwlock.h deleted file mode 100644 index fee1b070..00000000 --- a/common/rwlock.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef AL_RWLOCK_H -#define AL_RWLOCK_H - -#include "bool.h" -#include "atomic.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - RefCount read_count; - RefCount write_count; - ATOMIC(int) read_lock; - ATOMIC(int) read_entry_lock; - ATOMIC(int) write_lock; -} RWLock; -#define RWLOCK_STATIC_INITIALIZE { ATOMIC_INIT_STATIC(0), ATOMIC_INIT_STATIC(0), \ - ATOMIC_INIT_STATIC(0), ATOMIC_INIT_STATIC(0), \ - ATOMIC_INIT_STATIC(0) } - -void RWLockInit(RWLock *lock); -void ReadLock(RWLock *lock); -void ReadUnlock(RWLock *lock); -void WriteLock(RWLock *lock); -void WriteUnlock(RWLock *lock); - -#ifdef __cplusplus -} -#endif - -#endif /* AL_RWLOCK_H */ diff --git a/common/threads.c b/common/threads.c deleted file mode 100644 index b0f90bc5..00000000 --- a/common/threads.c +++ /dev/null @@ -1,448 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "threads.h" - -#include -#include -#include - -#include "uintmap.h" - - -extern inline althrd_t althrd_current(void); -extern inline int althrd_equal(althrd_t thr0, althrd_t thr1); -extern inline void althrd_yield(void); - - -#ifndef UNUSED -#if defined(__cplusplus) -#define UNUSED(x) -#elif defined(__GNUC__) -#define UNUSED(x) UNUSED_##x __attribute__((unused)) -#elif defined(__LCLINT__) -#define UNUSED(x) /*@unused@*/ x -#else -#define UNUSED(x) x -#endif -#endif - - -#define THREAD_STACK_SIZE (2*1024*1024) /* 2MB */ - -#ifdef _WIN32 - -#define WIN32_LEAN_AND_MEAN -#include -#include - - -/* An associative map of uint:void* pairs. The key is the unique Thread ID and - * the value is the thread HANDLE. The thread ID is passed around as the - * althrd_t since there is only one ID per thread, whereas a thread may be - * referenced by multiple different HANDLEs. This map allows retrieving the - * original handle which is needed to join the thread and get its return value. - */ -static UIntMap ThrdIdHandle = UINTMAP_STATIC_INITIALIZE; - - -void althrd_setname(althrd_t thr, const char *name) -{ -#if defined(_MSC_VER) -#define MS_VC_EXCEPTION 0x406D1388 -#pragma pack(push,8) - 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; -#pragma pack(pop) - info.dwType = 0x1000; - info.szName = name; - info.dwThreadID = thr; - info.dwFlags = 0; - - __try { - RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); - } - __except(EXCEPTION_CONTINUE_EXECUTION) { - } -#undef MS_VC_EXCEPTION -#else - (void)thr; - (void)name; -#endif -} - - -typedef struct thread_cntr { - althrd_start_t func; - void *arg; -} thread_cntr; - -static DWORD WINAPI althrd_starter(void *arg) -{ - thread_cntr cntr; - memcpy(&cntr, arg, sizeof(cntr)); - free(arg); - - return (DWORD)((*cntr.func)(cntr.arg)); -} - - -int althrd_create(althrd_t *thr, althrd_start_t func, void *arg) -{ - thread_cntr *cntr; - DWORD thrid; - HANDLE hdl; - - cntr = malloc(sizeof(*cntr)); - if(!cntr) return althrd_nomem; - - cntr->func = func; - cntr->arg = arg; - - hdl = CreateThread(NULL, THREAD_STACK_SIZE, althrd_starter, cntr, 0, &thrid); - if(!hdl) - { - free(cntr); - return althrd_error; - } - InsertUIntMapEntry(&ThrdIdHandle, thrid, hdl); - - *thr = thrid; - return althrd_success; -} - -int althrd_detach(althrd_t thr) -{ - HANDLE hdl = RemoveUIntMapKey(&ThrdIdHandle, thr); - if(!hdl) return althrd_error; - - CloseHandle(hdl); - return althrd_success; -} - -int althrd_join(althrd_t thr, int *res) -{ - DWORD code; - - HANDLE hdl = RemoveUIntMapKey(&ThrdIdHandle, thr); - if(!hdl) return althrd_error; - - WaitForSingleObject(hdl, INFINITE); - GetExitCodeThread(hdl, &code); - CloseHandle(hdl); - - if(res != NULL) - *res = (int)code; - return althrd_success; -} - - -int almtx_init(almtx_t *mtx, int type) -{ - if(!mtx) return althrd_error; - - type &= ~almtx_recursive; - if(type != almtx_plain) - return althrd_error; - - InitializeCriticalSection(mtx); - return althrd_success; -} - -void almtx_destroy(almtx_t *mtx) -{ - DeleteCriticalSection(mtx); -} - - -int alsem_init(alsem_t *sem, unsigned int initial) -{ - *sem = CreateSemaphore(NULL, initial, INT_MAX, NULL); - if(*sem != NULL) return althrd_success; - return althrd_error; -} - -void alsem_destroy(alsem_t *sem) -{ - CloseHandle(*sem); -} - -int alsem_post(alsem_t *sem) -{ - DWORD ret = ReleaseSemaphore(*sem, 1, NULL); - if(ret) return althrd_success; - return althrd_error; -} - -int alsem_wait(alsem_t *sem) -{ - DWORD ret = WaitForSingleObject(*sem, INFINITE); - if(ret == WAIT_OBJECT_0) return althrd_success; - return althrd_error; -} - -int alsem_trywait(alsem_t *sem) -{ - DWORD ret = WaitForSingleObject(*sem, 0); - if(ret == WAIT_OBJECT_0) return althrd_success; - if(ret == WAIT_TIMEOUT) return althrd_busy; - return althrd_error; -} - - -void althrd_deinit(void) -{ - ResetUIntMap(&ThrdIdHandle); -} - -#else - -#include -#include -#include -#ifdef HAVE_PTHREAD_NP_H -#include -#endif - - -void althrd_setname(althrd_t thr, const char *name) -{ -#if defined(HAVE_PTHREAD_SETNAME_NP) -#if defined(PTHREAD_SETNAME_NP_ONE_PARAM) - if(althrd_equal(thr, althrd_current())) - pthread_setname_np(name); -#elif defined(PTHREAD_SETNAME_NP_THREE_PARAMS) - pthread_setname_np(thr, "%s", (void*)name); -#else - pthread_setname_np(thr, name); -#endif -#elif defined(HAVE_PTHREAD_SET_NAME_NP) - pthread_set_name_np(thr, name); -#else - (void)thr; - (void)name; -#endif -} - - -typedef struct thread_cntr { - althrd_start_t func; - void *arg; -} thread_cntr; - -static void *althrd_starter(void *arg) -{ - thread_cntr cntr; - memcpy(&cntr, arg, sizeof(cntr)); - free(arg); - - return (void*)(intptr_t)((*cntr.func)(cntr.arg)); -} - - -int althrd_create(althrd_t *thr, althrd_start_t func, void *arg) -{ - thread_cntr *cntr; - pthread_attr_t attr; - size_t stackmult = 1; - int err; - - cntr = malloc(sizeof(*cntr)); - if(!cntr) return althrd_nomem; - - if(pthread_attr_init(&attr) != 0) - { - free(cntr); - return althrd_error; - } -retry_stacksize: - if(pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE*stackmult) != 0) - { - pthread_attr_destroy(&attr); - free(cntr); - return althrd_error; - } - - cntr->func = func; - cntr->arg = arg; - if((err=pthread_create(thr, &attr, althrd_starter, cntr)) == 0) - { - pthread_attr_destroy(&attr); - return althrd_success; - } - - if(err == EINVAL) - { - /* If an invalid stack size, try increasing it (limit x4, 8MB). */ - if(stackmult < 4) - { - stackmult *= 2; - goto retry_stacksize; - } - /* If still nothing, try defaults and hope they're good enough. */ - if(pthread_create(thr, NULL, althrd_starter, cntr) == 0) - { - pthread_attr_destroy(&attr); - return althrd_success; - } - } - pthread_attr_destroy(&attr); - free(cntr); - return althrd_error; -} - -int althrd_detach(althrd_t thr) -{ - if(pthread_detach(thr) != 0) - return althrd_error; - return althrd_success; -} - -int althrd_join(althrd_t thr, int *res) -{ - void *code; - - if(pthread_join(thr, &code) != 0) - return althrd_error; - if(res != NULL) - *res = (int)(intptr_t)code; - return althrd_success; -} - - -int almtx_init(almtx_t *mtx, int type) -{ - int ret; - - if(!mtx) return althrd_error; - if((type&~almtx_recursive) != 0) - return althrd_error; - - if(type == almtx_plain) - ret = pthread_mutex_init(mtx, NULL); - else - { - pthread_mutexattr_t attr; - - ret = pthread_mutexattr_init(&attr); - if(ret) return althrd_error; - - if(type == almtx_recursive) - { - ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); -#ifdef HAVE_PTHREAD_MUTEXATTR_SETKIND_NP - if(ret != 0) - ret = pthread_mutexattr_setkind_np(&attr, PTHREAD_MUTEX_RECURSIVE); -#endif - } - else - ret = 1; - if(ret == 0) - ret = pthread_mutex_init(mtx, &attr); - pthread_mutexattr_destroy(&attr); - } - return ret ? althrd_error : althrd_success; -} - -void almtx_destroy(almtx_t *mtx) -{ - pthread_mutex_destroy(mtx); -} - - -#ifdef __APPLE__ - -int alsem_init(alsem_t *sem, unsigned int initial) -{ - *sem = dispatch_semaphore_create(initial); - return *sem ? althrd_success : althrd_error; -} - -void alsem_destroy(alsem_t *sem) -{ - dispatch_release(*sem); -} - -int alsem_post(alsem_t *sem) -{ - dispatch_semaphore_signal(*sem); - return althrd_success; -} - -int alsem_wait(alsem_t *sem) -{ - dispatch_semaphore_wait(*sem, DISPATCH_TIME_FOREVER); - return althrd_success; -} - -int alsem_trywait(alsem_t *sem) -{ - long value = dispatch_semaphore_wait(*sem, DISPATCH_TIME_NOW); - return value == 0 ? althrd_success : althrd_busy; -} - -#else /* !__APPLE__ */ - -int alsem_init(alsem_t *sem, unsigned int initial) -{ - if(sem_init(sem, 0, initial) == 0) - return althrd_success; - return althrd_error; -} - -void alsem_destroy(alsem_t *sem) -{ - sem_destroy(sem); -} - -int alsem_post(alsem_t *sem) -{ - if(sem_post(sem) == 0) - return althrd_success; - return althrd_error; -} - -int alsem_wait(alsem_t *sem) -{ - if(sem_wait(sem) == 0) return althrd_success; - if(errno == EINTR) return -2; - return althrd_error; -} - -int alsem_trywait(alsem_t *sem) -{ - if(sem_trywait(sem) == 0) return althrd_success; - if(errno == EWOULDBLOCK) return althrd_busy; - if(errno == EINTR) return -2; - return althrd_error; -} - -#endif /* __APPLE__ */ - -void althrd_deinit(void) -{ } - -#endif diff --git a/common/threads.cpp b/common/threads.cpp new file mode 100644 index 00000000..48f62274 --- /dev/null +++ b/common/threads.cpp @@ -0,0 +1,442 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "threads.h" + +#include +#include +#include + +#include "uintmap.h" + + +#ifndef UNUSED +#if defined(__cplusplus) +#define UNUSED(x) +#elif defined(__GNUC__) +#define UNUSED(x) UNUSED_##x __attribute__((unused)) +#elif defined(__LCLINT__) +#define UNUSED(x) /*@unused@*/ x +#else +#define UNUSED(x) x +#endif +#endif + + +#define THREAD_STACK_SIZE (2*1024*1024) /* 2MB */ + +#ifdef _WIN32 + +#define WIN32_LEAN_AND_MEAN +#include +#include + + +/* An associative map of uint:void* pairs. The key is the unique Thread ID and + * the value is the thread HANDLE. The thread ID is passed around as the + * althrd_t since there is only one ID per thread, whereas a thread may be + * referenced by multiple different HANDLEs. This map allows retrieving the + * original handle which is needed to join the thread and get its return value. + */ +static ThrSafeMap ThrdIdHandle{}; + + +void althrd_setname(althrd_t thr, const char *name) +{ +#if defined(_MSC_VER) +#define MS_VC_EXCEPTION 0x406D1388 +#pragma pack(push,8) + 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; +#pragma pack(pop) + info.dwType = 0x1000; + info.szName = name; + info.dwThreadID = thr; + info.dwFlags = 0; + + __try { + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); + } + __except(EXCEPTION_CONTINUE_EXECUTION) { + } +#undef MS_VC_EXCEPTION +#else + (void)thr; + (void)name; +#endif +} + + +typedef struct thread_cntr { + althrd_start_t func; + void *arg; +} thread_cntr; + +static DWORD WINAPI althrd_starter(void *arg) +{ + thread_cntr cntr; + memcpy(&cntr, arg, sizeof(cntr)); + free(arg); + + return (DWORD)((*cntr.func)(cntr.arg)); +} + + +int althrd_create(althrd_t *thr, althrd_start_t func, void *arg) +{ + thread_cntr *cntr; + DWORD thrid; + HANDLE hdl; + + cntr = static_cast(malloc(sizeof(*cntr))); + if(!cntr) return althrd_nomem; + + cntr->func = func; + cntr->arg = arg; + + hdl = CreateThread(NULL, THREAD_STACK_SIZE, althrd_starter, cntr, 0, &thrid); + if(!hdl) + { + free(cntr); + return althrd_error; + } + ThrdIdHandle.InsertEntry(thrid, hdl); + + *thr = thrid; + return althrd_success; +} + +int althrd_detach(althrd_t thr) +{ + HANDLE hdl = ThrdIdHandle.RemoveKey(thr); + if(!hdl) return althrd_error; + + CloseHandle(hdl); + return althrd_success; +} + +int althrd_join(althrd_t thr, int *res) +{ + DWORD code; + + HANDLE hdl = ThrdIdHandle.RemoveKey(thr); + if(!hdl) return althrd_error; + + WaitForSingleObject(hdl, INFINITE); + GetExitCodeThread(hdl, &code); + CloseHandle(hdl); + + if(res != NULL) + *res = (int)code; + return althrd_success; +} + + +int almtx_init(almtx_t *mtx, int type) +{ + if(!mtx) return althrd_error; + + type &= ~almtx_recursive; + if(type != almtx_plain) + return althrd_error; + + InitializeCriticalSection(mtx); + return althrd_success; +} + +void almtx_destroy(almtx_t *mtx) +{ + DeleteCriticalSection(mtx); +} + + +int alsem_init(alsem_t *sem, unsigned int initial) +{ + *sem = CreateSemaphore(NULL, initial, INT_MAX, NULL); + if(*sem != NULL) return althrd_success; + return althrd_error; +} + +void alsem_destroy(alsem_t *sem) +{ + CloseHandle(*sem); +} + +int alsem_post(alsem_t *sem) +{ + DWORD ret = ReleaseSemaphore(*sem, 1, NULL); + if(ret) return althrd_success; + return althrd_error; +} + +int alsem_wait(alsem_t *sem) +{ + DWORD ret = WaitForSingleObject(*sem, INFINITE); + if(ret == WAIT_OBJECT_0) return althrd_success; + return althrd_error; +} + +int alsem_trywait(alsem_t *sem) +{ + DWORD ret = WaitForSingleObject(*sem, 0); + if(ret == WAIT_OBJECT_0) return althrd_success; + if(ret == WAIT_TIMEOUT) return althrd_busy; + return althrd_error; +} + + +void althrd_deinit(void) +{ +} + +#else + +#include +#include +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif + + +void althrd_setname(althrd_t thr, const char *name) +{ +#if defined(HAVE_PTHREAD_SETNAME_NP) +#if defined(PTHREAD_SETNAME_NP_ONE_PARAM) + if(althrd_equal(thr, althrd_current())) + pthread_setname_np(name); +#elif defined(PTHREAD_SETNAME_NP_THREE_PARAMS) + pthread_setname_np(thr, "%s", (void*)name); +#else + pthread_setname_np(thr, name); +#endif +#elif defined(HAVE_PTHREAD_SET_NAME_NP) + pthread_set_name_np(thr, name); +#else + (void)thr; + (void)name; +#endif +} + + +typedef struct thread_cntr { + althrd_start_t func; + void *arg; +} thread_cntr; + +static void *althrd_starter(void *arg) +{ + thread_cntr cntr; + memcpy(&cntr, arg, sizeof(cntr)); + free(arg); + + return (void*)(intptr_t)((*cntr.func)(cntr.arg)); +} + + +int althrd_create(althrd_t *thr, althrd_start_t func, void *arg) +{ + thread_cntr *cntr; + pthread_attr_t attr; + size_t stackmult = 1; + int err; + + cntr = static_cast(malloc(sizeof(*cntr))); + if(!cntr) return althrd_nomem; + + if(pthread_attr_init(&attr) != 0) + { + free(cntr); + return althrd_error; + } +retry_stacksize: + if(pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE*stackmult) != 0) + { + pthread_attr_destroy(&attr); + free(cntr); + return althrd_error; + } + + cntr->func = func; + cntr->arg = arg; + if((err=pthread_create(thr, &attr, althrd_starter, cntr)) == 0) + { + pthread_attr_destroy(&attr); + return althrd_success; + } + + if(err == EINVAL) + { + /* If an invalid stack size, try increasing it (limit x4, 8MB). */ + if(stackmult < 4) + { + stackmult *= 2; + goto retry_stacksize; + } + /* If still nothing, try defaults and hope they're good enough. */ + if(pthread_create(thr, NULL, althrd_starter, cntr) == 0) + { + pthread_attr_destroy(&attr); + return althrd_success; + } + } + pthread_attr_destroy(&attr); + free(cntr); + return althrd_error; +} + +int althrd_detach(althrd_t thr) +{ + if(pthread_detach(thr) != 0) + return althrd_error; + return althrd_success; +} + +int althrd_join(althrd_t thr, int *res) +{ + void *code; + + if(pthread_join(thr, &code) != 0) + return althrd_error; + if(res != NULL) + *res = (int)(intptr_t)code; + return althrd_success; +} + + +int almtx_init(almtx_t *mtx, int type) +{ + int ret; + + if(!mtx) return althrd_error; + if((type&~almtx_recursive) != 0) + return althrd_error; + + if(type == almtx_plain) + ret = pthread_mutex_init(mtx, NULL); + else + { + pthread_mutexattr_t attr; + + ret = pthread_mutexattr_init(&attr); + if(ret) return althrd_error; + + if(type == almtx_recursive) + { + ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); +#ifdef HAVE_PTHREAD_MUTEXATTR_SETKIND_NP + if(ret != 0) + ret = pthread_mutexattr_setkind_np(&attr, PTHREAD_MUTEX_RECURSIVE); +#endif + } + else + ret = 1; + if(ret == 0) + ret = pthread_mutex_init(mtx, &attr); + pthread_mutexattr_destroy(&attr); + } + return ret ? althrd_error : althrd_success; +} + +void almtx_destroy(almtx_t *mtx) +{ + pthread_mutex_destroy(mtx); +} + + +#ifdef __APPLE__ + +int alsem_init(alsem_t *sem, unsigned int initial) +{ + *sem = dispatch_semaphore_create(initial); + return *sem ? althrd_success : althrd_error; +} + +void alsem_destroy(alsem_t *sem) +{ + dispatch_release(*sem); +} + +int alsem_post(alsem_t *sem) +{ + dispatch_semaphore_signal(*sem); + return althrd_success; +} + +int alsem_wait(alsem_t *sem) +{ + dispatch_semaphore_wait(*sem, DISPATCH_TIME_FOREVER); + return althrd_success; +} + +int alsem_trywait(alsem_t *sem) +{ + long value = dispatch_semaphore_wait(*sem, DISPATCH_TIME_NOW); + return value == 0 ? althrd_success : althrd_busy; +} + +#else /* !__APPLE__ */ + +int alsem_init(alsem_t *sem, unsigned int initial) +{ + if(sem_init(sem, 0, initial) == 0) + return althrd_success; + return althrd_error; +} + +void alsem_destroy(alsem_t *sem) +{ + sem_destroy(sem); +} + +int alsem_post(alsem_t *sem) +{ + if(sem_post(sem) == 0) + return althrd_success; + return althrd_error; +} + +int alsem_wait(alsem_t *sem) +{ + if(sem_wait(sem) == 0) return althrd_success; + if(errno == EINTR) return -2; + return althrd_error; +} + +int alsem_trywait(alsem_t *sem) +{ + if(sem_trywait(sem) == 0) return althrd_success; + if(errno == EWOULDBLOCK) return althrd_busy; + if(errno == EINTR) return -2; + return althrd_error; +} + +#endif /* __APPLE__ */ + +void althrd_deinit(void) +{ } + +#endif diff --git a/common/uintmap.c b/common/uintmap.c deleted file mode 100644 index 3654779c..00000000 --- a/common/uintmap.c +++ /dev/null @@ -1,182 +0,0 @@ - -#include "config.h" - -#include "uintmap.h" - -#include -#include - -#include "almalloc.h" - - -extern inline void LockUIntMapRead(UIntMap *map); -extern inline void UnlockUIntMapRead(UIntMap *map); -extern inline void LockUIntMapWrite(UIntMap *map); -extern inline void UnlockUIntMapWrite(UIntMap *map); - - -void InitUIntMap(UIntMap *map, ALsizei limit) -{ - map->keys = NULL; - map->values = NULL; - map->size = 0; - map->capacity = 0; - map->limit = limit; - RWLockInit(&map->lock); -} - -void ResetUIntMap(UIntMap *map) -{ - WriteLock(&map->lock); - al_free(map->keys); - map->keys = NULL; - map->values = NULL; - map->size = 0; - map->capacity = 0; - WriteUnlock(&map->lock); -} - -ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value) -{ - ALsizei pos = 0; - - WriteLock(&map->lock); - if(map->size > 0) - { - ALsizei count = map->size; - do { - ALsizei step = count>>1; - ALsizei i = pos+step; - if(map->keys[i] >= key) - count = step; - else - { - pos = i+1; - count -= step+1; - } - } while(count > 0); - } - - if(pos == map->size || map->keys[pos] != key) - { - if(map->size >= map->limit) - { - WriteUnlock(&map->lock); - return AL_OUT_OF_MEMORY; - } - - if(map->size == map->capacity) - { - ALuint *keys = NULL; - ALvoid **values; - ALsizei newcap, keylen; - - newcap = (map->capacity ? (map->capacity<<1) : 4); - if(map->limit > 0 && newcap > map->limit) - newcap = map->limit; - if(newcap > map->capacity) - { - /* Round the memory size for keys up to a multiple of the - * pointer size. - */ - keylen = newcap * sizeof(map->keys[0]); - keylen += sizeof(map->values[0]) - 1; - keylen -= keylen%sizeof(map->values[0]); - - keys = al_malloc(16, keylen + newcap*sizeof(map->values[0])); - } - if(!keys) - { - WriteUnlock(&map->lock); - return AL_OUT_OF_MEMORY; - } - values = (ALvoid**)((ALbyte*)keys + keylen); - - if(map->keys) - { - memcpy(keys, map->keys, map->size*sizeof(map->keys[0])); - memcpy(values, map->values, map->size*sizeof(map->values[0])); - } - al_free(map->keys); - map->keys = keys; - map->values = values; - map->capacity = newcap; - } - - if(pos < map->size) - { - memmove(&map->keys[pos+1], &map->keys[pos], - (map->size-pos)*sizeof(map->keys[0])); - memmove(&map->values[pos+1], &map->values[pos], - (map->size-pos)*sizeof(map->values[0])); - } - map->size++; - } - map->keys[pos] = key; - map->values[pos] = value; - WriteUnlock(&map->lock); - - return AL_NO_ERROR; -} - -ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key) -{ - ALvoid *ptr = NULL; - WriteLock(&map->lock); - if(map->size > 0) - { - ALsizei pos = 0; - ALsizei count = map->size; - do { - ALsizei step = count>>1; - ALsizei i = pos+step; - if(map->keys[i] >= key) - count = step; - else - { - pos = i+1; - count -= step+1; - } - } while(count > 0); - if(pos < map->size && map->keys[pos] == key) - { - ptr = map->values[pos]; - if(pos < map->size-1) - { - memmove(&map->keys[pos], &map->keys[pos+1], - (map->size-1-pos)*sizeof(map->keys[0])); - memmove(&map->values[pos], &map->values[pos+1], - (map->size-1-pos)*sizeof(map->values[0])); - } - map->size--; - } - } - WriteUnlock(&map->lock); - return ptr; -} - -ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key) -{ - ALvoid *ptr = NULL; - ReadLock(&map->lock); - if(map->size > 0) - { - ALsizei pos = 0; - ALsizei count = map->size; - do { - ALsizei step = count>>1; - ALsizei i = pos+step; - if(map->keys[i] >= key) - count = step; - else - { - pos = i+1; - count -= step+1; - } - } while(count > 0); - if(pos < map->size && map->keys[pos] == key) - ptr = map->values[pos]; - } - ReadUnlock(&map->lock); - return ptr; -} diff --git a/common/uintmap.h b/common/uintmap.h index 32868653..0646d2b5 100644 --- a/common/uintmap.h +++ b/common/uintmap.h @@ -1,41 +1,35 @@ #ifndef AL_UINTMAP_H #define AL_UINTMAP_H -#include +#include +#include #include "AL/al.h" -#include "rwlock.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct UIntMap { - ALuint *keys; - /* Shares memory with keys. */ - ALvoid **values; - - ALsizei size; - ALsizei capacity; - ALsizei limit; - RWLock lock; -} UIntMap; -#define UINTMAP_STATIC_INITIALIZE_N(_n) { NULL, NULL, 0, 0, (_n), RWLOCK_STATIC_INITIALIZE } -#define UINTMAP_STATIC_INITIALIZE UINTMAP_STATIC_INITIALIZE_N(INT_MAX) - -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); } - -#ifdef __cplusplus -} -#endif + +template +class ThrSafeMap { + std::unordered_map mValues; + std::mutex mLock; + +public: + void InsertEntry(T0 key, T1 value) noexcept + { + std::lock_guard _{mLock}; + mValues[key] = value; + } + + T1 RemoveKey(T0 key) noexcept + { + T1 retval{}; + + std::lock_guard _{mLock}; + auto iter = mValues.find(key); + if(iter != mValues.end()) + retval = iter->second; + mValues.erase(iter); + + return retval; + } +}; #endif /* AL_UINTMAP_H */ -- cgit v1.2.3 From 7b537c795bd174b4b02418a37b377b4da5cfe266 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 06:07:04 -0800 Subject: Don't pass the current thread to althrd_setname --- Alc/alc.cpp | 2 -- Alc/backends/alsa.cpp | 4 ++-- Alc/backends/dsound.cpp | 2 +- Alc/backends/jack.cpp | 2 +- Alc/backends/null.cpp | 2 +- Alc/backends/opensl.cpp | 2 +- Alc/backends/oss.cpp | 4 ++-- Alc/backends/pulseaudio.cpp | 2 +- Alc/backends/qsa.cpp | 2 +- Alc/backends/sndio.cpp | 4 ++-- Alc/backends/solaris.cpp | 2 +- Alc/backends/wasapi.cpp | 4 ++-- Alc/backends/wave.cpp | 2 +- Alc/backends/winmm.cpp | 4 ++-- common/threads.cpp | 25 +++++++------------------ common/threads.h | 26 +------------------------- 16 files changed, 26 insertions(+), 63 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 65023fe1..c719eaa9 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1248,8 +1248,6 @@ static void alc_deinit_safe(void) if(LogFile != stderr) fclose(LogFile); LogFile = nullptr; - - althrd_deinit(); } static void alc_deinit(void) diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index ee42842b..d02d5d20 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -472,7 +472,7 @@ int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); + althrd_setname(MIXER_THREAD_NAME); snd_pcm_uframes_t update_size{device->UpdateSize}; snd_pcm_uframes_t num_updates{device->NumUpdates}; @@ -559,7 +559,7 @@ int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self) ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); + althrd_setname(MIXER_THREAD_NAME); snd_pcm_uframes_t update_size{device->UpdateSize}; snd_pcm_uframes_t num_updates{device->NumUpdates}; diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 34d7dc23..a52bb17c 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -249,7 +249,7 @@ FORCE_ALIGN int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); + althrd_setname(MIXER_THREAD_NAME); IDirectSoundBuffer *const Buffer{self->Buffer}; diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index ac57ffd5..97254582 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -306,7 +306,7 @@ static int ALCjackPlayback_mixerProc(void *arg) ll_ringbuffer_data_t data[2]; SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); + althrd_setname(MIXER_THREAD_NAME); ALCjackPlayback_lock(self); while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index c9ba8de7..7c27e22c 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -89,7 +89,7 @@ int ALCnullBackend_mixerProc(ALCnullBackend *self) const milliseconds restTime{device->UpdateSize*1000/device->Frequency / 2}; SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); + althrd_setname(MIXER_THREAD_NAME); ALint64 done{0}; auto start = std::chrono::steady_clock::now(); diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index e8a575c8..1c85c9d5 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -244,7 +244,7 @@ static int ALCopenslPlayback_mixerProc(void *arg) SLresult result; SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); + althrd_setname(MIXER_THREAD_NAME); result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index cf95bcfe..ebe4b15a 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -296,7 +296,7 @@ int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self) int sret; SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); + althrd_setname(MIXER_THREAD_NAME); frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); @@ -558,7 +558,7 @@ int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) int sret; SetRTPriority(); - althrd_setname(althrd_current(), RECORD_THREAD_NAME); + althrd_setname(RECORD_THREAD_NAME); frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 38623783..df2eb656 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -866,7 +866,7 @@ int PulsePlayback_mixerProc(PulsePlayback *self) ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); + althrd_setname(MIXER_THREAD_NAME); unique_palock palock{self->loop}; size_t frame_size{pa_frame_size(&self->spec)}; diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index da4e6b64..f710f080 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -198,7 +198,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) int sret; SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); + althrd_setname(MIXER_THREAD_NAME); /* Increase default 10 priority to 11 to avoid jerky sound */ SchedGet(0, 0, ¶m); diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index 691bdcde..654c2975 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -98,7 +98,7 @@ static int SndioPlayback_mixerProc(void *ptr) size_t wrote; SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); + althrd_setname(MIXER_THREAD_NAME); frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); @@ -340,7 +340,7 @@ static int SndioCapture_recordProc(void* ptr) ALsizei frameSize; SetRTPriority(); - althrd_setname(althrd_current(), RECORD_THREAD_NAME); + althrd_setname(RECORD_THREAD_NAME); frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index 029ef1a5..008f3446 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -115,7 +115,7 @@ static int ALCsolarisBackend_mixerProc(void *ptr) int sret; SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); + althrd_setname(MIXER_THREAD_NAME); frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 4ebd6f25..7f52bafe 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -580,7 +580,7 @@ FORCE_ALIGN int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self) } SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); + althrd_setname(MIXER_THREAD_NAME); ALuint update_size{device->UpdateSize}; UINT32 buffer_len{update_size * device->NumUpdates}; @@ -1251,7 +1251,7 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) return 1; } - althrd_setname(althrd_current(), RECORD_THREAD_NAME); + althrd_setname(RECORD_THREAD_NAME); std::vector samples; while(!self->mKillNow.load(std::memory_order_relaxed)) diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index fb00ef32..58e0efd5 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -133,7 +133,7 @@ int ALCwaveBackend_mixerProc(ALCwaveBackend *self) ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; const milliseconds restTime{device->UpdateSize*1000/device->Frequency / 2}; - althrd_setname(althrd_current(), MIXER_THREAD_NAME); + althrd_setname(MIXER_THREAD_NAME); ALsizei frameSize{FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder)}; diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 0fb85f66..1d0a8ecc 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -202,7 +202,7 @@ FORCE_ALIGN int ALCwinmmPlayback_mixerProc(ALCwinmmPlayback *self) ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); + althrd_setname(MIXER_THREAD_NAME); ALCwinmmPlayback_lock(self); while(!self->killNow.load(std::memory_order_acquire) && @@ -484,7 +484,7 @@ int ALCwinmmCapture_captureProc(ALCwinmmCapture *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - althrd_setname(althrd_current(), RECORD_THREAD_NAME); + althrd_setname(RECORD_THREAD_NAME); ALCwinmmCapture_lock(self); while(!self->killNow.load(std::memory_order_acquire) && diff --git a/common/threads.cpp b/common/threads.cpp index 48f62274..7d44c012 100644 --- a/common/threads.cpp +++ b/common/threads.cpp @@ -60,7 +60,7 @@ static ThrSafeMap ThrdIdHandle{}; -void althrd_setname(althrd_t thr, const char *name) +void althrd_setname(const char *name) { #if defined(_MSC_VER) #define MS_VC_EXCEPTION 0x406D1388 @@ -74,7 +74,7 @@ void althrd_setname(althrd_t thr, const char *name) #pragma pack(pop) info.dwType = 0x1000; info.szName = name; - info.dwThreadID = thr; + info.dwThreadID = -1; info.dwFlags = 0; __try { @@ -84,7 +84,6 @@ void althrd_setname(althrd_t thr, const char *name) } #undef MS_VC_EXCEPTION #else - (void)thr; (void)name; #endif } @@ -207,11 +206,6 @@ int alsem_trywait(alsem_t *sem) return althrd_error; } - -void althrd_deinit(void) -{ -} - #else #include @@ -222,21 +216,19 @@ void althrd_deinit(void) #endif -void althrd_setname(althrd_t thr, const char *name) +void althrd_setname(const char *name) { #if defined(HAVE_PTHREAD_SETNAME_NP) #if defined(PTHREAD_SETNAME_NP_ONE_PARAM) - if(althrd_equal(thr, althrd_current())) - pthread_setname_np(name); + pthread_setname_np(name); #elif defined(PTHREAD_SETNAME_NP_THREE_PARAMS) - pthread_setname_np(thr, "%s", (void*)name); + pthread_setname_np(pthread_self(), "%s", (void*)name); #else - pthread_setname_np(thr, name); + pthread_setname_np(pthread_self(), name); #endif #elif defined(HAVE_PTHREAD_SET_NAME_NP) - pthread_set_name_np(thr, name); + pthread_set_name_np(pthread_self(), name); #else - (void)thr; (void)name; #endif } @@ -436,7 +428,4 @@ int alsem_trywait(alsem_t *sem) #endif /* __APPLE__ */ -void althrd_deinit(void) -{ } - #endif diff --git a/common/threads.h b/common/threads.h index 9abb22f2..0b53c38f 100644 --- a/common/threads.h +++ b/common/threads.h @@ -42,18 +42,6 @@ typedef CRITICAL_SECTION almtx_t; typedef HANDLE alsem_t; -void althrd_deinit(void); - -inline althrd_t althrd_current(void) -{ - return GetCurrentThreadId(); -} - -inline int althrd_equal(althrd_t thr0, althrd_t thr1) -{ - return thr0 == thr1; -} - inline void althrd_yield(void) { SwitchToThread(); @@ -94,18 +82,6 @@ typedef sem_t alsem_t; #endif /* __APPLE__ */ -void althrd_deinit(void); - -inline althrd_t althrd_current(void) -{ - return pthread_self(); -} - -inline int althrd_equal(althrd_t thr0, althrd_t thr1) -{ - return pthread_equal(thr0, thr1); -} - inline void althrd_yield(void) { sched_yield(); @@ -132,7 +108,7 @@ inline int almtx_unlock(almtx_t *mtx) int althrd_create(althrd_t *thr, althrd_start_t func, void *arg); int althrd_detach(althrd_t thr); int althrd_join(althrd_t thr, int *res); -void althrd_setname(althrd_t thr, const char *name); +void althrd_setname(const char *name); int almtx_init(almtx_t *mtx, int type); void almtx_destroy(almtx_t *mtx); -- cgit v1.2.3 From ad34855a2bb9312d3f21ff3fdca20bca767b9224 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 06:11:55 -0800 Subject: Add a couple missing includes --- Alc/effects/fshifter.cpp | 1 + Alc/effects/pshifter.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp index e0dced3a..304e281f 100644 --- a/Alc/effects/fshifter.cpp +++ b/Alc/effects/fshifter.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp index f1a80254..f0cdf53e 100644 --- a/Alc/effects/pshifter.cpp +++ b/Alc/effects/pshifter.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include -- cgit v1.2.3 From 93d96ced9cef7200b04dbfec51325a3c9c55af19 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 06:53:20 -0800 Subject: Convert the dedicated, distortion, echo, and equalizer to C++ --- Alc/effects/dedicated.c | 184 ----------------------- Alc/effects/dedicated.cpp | 187 +++++++++++++++++++++++ Alc/effects/distortion.c | 286 ------------------------------------ Alc/effects/distortion.cpp | 289 ++++++++++++++++++++++++++++++++++++ Alc/effects/echo.c | 310 -------------------------------------- Alc/effects/echo.cpp | 314 +++++++++++++++++++++++++++++++++++++++ Alc/effects/equalizer.c | 355 -------------------------------------------- Alc/effects/equalizer.cpp | 359 +++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 8 +- 9 files changed, 1153 insertions(+), 1139 deletions(-) delete mode 100644 Alc/effects/dedicated.c create mode 100644 Alc/effects/dedicated.cpp delete mode 100644 Alc/effects/distortion.c create mode 100644 Alc/effects/distortion.cpp delete mode 100644 Alc/effects/echo.c create mode 100644 Alc/effects/echo.cpp delete mode 100644 Alc/effects/equalizer.c create mode 100644 Alc/effects/equalizer.cpp diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c deleted file mode 100644 index 59c13b77..00000000 --- a/Alc/effects/dedicated.c +++ /dev/null @@ -1,184 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2011 by Chris Robinson. - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include - -#include "alMain.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" -#include "filters/defs.h" - - -typedef struct ALdedicatedState { - DERIVE_FROM_TYPE(ALeffectState); - - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; -} ALdedicatedState; - -static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state); -static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *state, ALCdevice *device); -static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALdedicatedState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALdedicatedState); - - -static void ALdedicatedState_Construct(ALdedicatedState *state) -{ - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALdedicatedState, ALeffectState, state); -} - -static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); -} - -static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *state, ALCdevice *UNUSED(device)) -{ - ALsizei i; - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - state->CurrentGains[i] = 0.0f; - return AL_TRUE; -} - -static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) -{ - const ALCdevice *device = context->Device; - ALfloat Gain; - ALsizei i; - - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - state->TargetGains[i] = 0.0f; - - Gain = slot->Params.Gain * props->Dedicated.Gain; - if(slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) - { - int idx; - if((idx=GetChannelIdxByName(&device->RealOut, LFE)) != -1) - { - STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer; - STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels; - state->TargetGains[idx] = Gain; - } - } - else if(slot->Params.EffectType == AL_EFFECT_DEDICATED_DIALOGUE) - { - int idx; - /* Dialog goes to the front-center speaker if it exists, otherwise it - * plays from the front-center location. */ - if((idx=GetChannelIdxByName(&device->RealOut, FrontCenter)) != -1) - { - STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer; - STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels; - state->TargetGains[idx] = Gain; - } - else - { - ALfloat coeffs[MAX_AMBI_COEFFS]; - CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - - STATIC_CAST(ALeffectState,state)->OutBuffer = device->Dry.Buffer; - STATIC_CAST(ALeffectState,state)->OutChannels = device->Dry.NumChannels; - ComputePanGains(&device->Dry, coeffs, Gain, state->TargetGains); - } - } -} - -static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) -{ - MixSamples(SamplesIn[0], NumChannels, SamplesOut, state->CurrentGains, - state->TargetGains, SamplesToDo, 0, SamplesToDo); -} - - -typedef struct DedicatedStateFactory { - DERIVE_FROM_TYPE(EffectStateFactory); -} DedicatedStateFactory; - -ALeffectState *DedicatedStateFactory_create(DedicatedStateFactory *UNUSED(factory)) -{ - ALdedicatedState *state; - - NEW_OBJ0(state, ALdedicatedState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(DedicatedStateFactory); - - -EffectStateFactory *DedicatedStateFactory_getFactory(void) -{ - static DedicatedStateFactory DedicatedFactory = { { GET_VTABLE2(DedicatedStateFactory, EffectStateFactory) } }; - - return STATIC_CAST(EffectStateFactory, &DedicatedFactory); -} - - -void ALdedicated_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param); } -void ALdedicated_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x", param); } -void ALdedicated_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_DEDICATED_GAIN: - if(!(val >= 0.0f && isfinite(val))) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Dedicated gain out of range"); - props->Dedicated.Gain = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param); - } -} -void ALdedicated_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ ALdedicated_setParamf(effect, context, param, vals[0]); } - -void ALdedicated_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param); } -void ALdedicated_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x", param); } -void ALdedicated_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_DEDICATED_GAIN: - *val = props->Dedicated.Gain; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param); - } -} -void ALdedicated_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ ALdedicated_getParamf(effect, context, param, vals); } - -DEFINE_ALEFFECT_VTABLE(ALdedicated); diff --git a/Alc/effects/dedicated.cpp b/Alc/effects/dedicated.cpp new file mode 100644 index 00000000..dd250e64 --- /dev/null +++ b/Alc/effects/dedicated.cpp @@ -0,0 +1,187 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2011 by Chris Robinson. + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include + +#include "alMain.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" +#include "filters/defs.h" + + +struct ALdedicatedState final : public ALeffectState { + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; +}; + +static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state); +static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *state, ALCdevice *device); +static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALdedicatedState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALdedicatedState); + + +static void ALdedicatedState_Construct(ALdedicatedState *state) +{ + new (state) ALdedicatedState{}; + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALdedicatedState, ALeffectState, state); +} + +static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state) +{ + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); + state->~ALdedicatedState(); +} + +static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *state, ALCdevice *UNUSED(device)) +{ + ALsizei i; + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + state->CurrentGains[i] = 0.0f; + return AL_TRUE; +} + +static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +{ + const ALCdevice *device = context->Device; + ALfloat Gain; + ALsizei i; + + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + state->TargetGains[i] = 0.0f; + + Gain = slot->Params.Gain * props->Dedicated.Gain; + if(slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) + { + int idx; + if((idx=GetChannelIdxByName(&device->RealOut, LFE)) != -1) + { + STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer; + STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels; + state->TargetGains[idx] = Gain; + } + } + else if(slot->Params.EffectType == AL_EFFECT_DEDICATED_DIALOGUE) + { + int idx; + /* Dialog goes to the front-center speaker if it exists, otherwise it + * plays from the front-center location. */ + if((idx=GetChannelIdxByName(&device->RealOut, FrontCenter)) != -1) + { + STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer; + STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels; + state->TargetGains[idx] = Gain; + } + else + { + ALfloat coeffs[MAX_AMBI_COEFFS]; + CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); + + STATIC_CAST(ALeffectState,state)->OutBuffer = device->Dry.Buffer; + STATIC_CAST(ALeffectState,state)->OutChannels = device->Dry.NumChannels; + ComputePanGains(&device->Dry, coeffs, Gain, state->TargetGains); + } + } +} + +static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +{ + MixSamples(SamplesIn[0], NumChannels, SamplesOut, state->CurrentGains, + state->TargetGains, SamplesToDo, 0, SamplesToDo); +} + + +struct DedicatedStateFactory final : public EffectStateFactory { + DedicatedStateFactory() noexcept; +}; + +ALeffectState *DedicatedStateFactory_create(DedicatedStateFactory *UNUSED(factory)) +{ + ALdedicatedState *state; + + NEW_OBJ0(state, ALdedicatedState)(); + if(!state) return NULL; + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_EFFECTSTATEFACTORY_VTABLE(DedicatedStateFactory); + +DedicatedStateFactory::DedicatedStateFactory() noexcept + : EffectStateFactory{GET_VTABLE2(DedicatedStateFactory, EffectStateFactory)} +{ +} + +EffectStateFactory *DedicatedStateFactory_getFactory(void) +{ + static DedicatedStateFactory DedicatedFactory{}; + return STATIC_CAST(EffectStateFactory, &DedicatedFactory); +} + + +void ALdedicated_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param); } +void ALdedicated_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x", param); } +void ALdedicated_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_DEDICATED_GAIN: + if(!(val >= 0.0f && isfinite(val))) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Dedicated gain out of range"); + props->Dedicated.Gain = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param); + } +} +void ALdedicated_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALdedicated_setParamf(effect, context, param, vals[0]); } + +void ALdedicated_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param); } +void ALdedicated_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x", param); } +void ALdedicated_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_DEDICATED_GAIN: + *val = props->Dedicated.Gain; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param); + } +} +void ALdedicated_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALdedicated_getParamf(effect, context, param, vals); } + +DEFINE_ALEFFECT_VTABLE(ALdedicated); diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c deleted file mode 100644 index f2a70bff..00000000 --- a/Alc/effects/distortion.c +++ /dev/null @@ -1,286 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2013 by Mike Gorchak - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" -#include "filters/defs.h" - - -typedef struct ALdistortionState { - DERIVE_FROM_TYPE(ALeffectState); - - /* Effect gains for each channel */ - ALfloat Gain[MAX_OUTPUT_CHANNELS]; - - /* Effect parameters */ - BiquadFilter lowpass; - BiquadFilter bandpass; - ALfloat attenuation; - ALfloat edge_coeff; - - ALfloat Buffer[2][BUFFERSIZE]; -} ALdistortionState; - -static ALvoid ALdistortionState_Destruct(ALdistortionState *state); -static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *device); -static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALdistortionState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALdistortionState); - - -static void ALdistortionState_Construct(ALdistortionState *state) -{ - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALdistortionState, ALeffectState, state); -} - -static ALvoid ALdistortionState_Destruct(ALdistortionState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); -} - -static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *UNUSED(device)) -{ - BiquadFilter_clear(&state->lowpass); - BiquadFilter_clear(&state->bandpass); - return AL_TRUE; -} - -static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) -{ - const ALCdevice *device = context->Device; - ALfloat frequency = (ALfloat)device->Frequency; - ALfloat coeffs[MAX_AMBI_COEFFS]; - ALfloat bandwidth; - ALfloat cutoff; - ALfloat edge; - - /* Store waveshaper edge settings. */ - edge = sinf(props->Distortion.Edge * (F_PI_2)); - edge = minf(edge, 0.99f); - state->edge_coeff = 2.0f * edge / (1.0f-edge); - - cutoff = props->Distortion.LowpassCutoff; - /* Bandwidth value is constant in octaves. */ - bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f); - /* Multiply sampling frequency by the amount of oversampling done during - * processing. - */ - BiquadFilter_setParams(&state->lowpass, BiquadType_LowPass, 1.0f, - cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) - ); - - cutoff = props->Distortion.EQCenter; - /* Convert bandwidth in Hz to octaves. */ - bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f); - BiquadFilter_setParams(&state->bandpass, BiquadType_BandPass, 1.0f, - cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) - ); - - CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain*props->Distortion.Gain, state->Gain); -} - -static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) -{ - ALfloat (*RESTRICT buffer)[BUFFERSIZE] = state->Buffer; - const ALfloat fc = state->edge_coeff; - ALsizei base; - ALsizei i, k; - - for(base = 0;base < SamplesToDo;) - { - /* Perform 4x oversampling to avoid aliasing. Oversampling greatly - * improves distortion quality and allows to implement lowpass and - * bandpass filters using high frequencies, at which classic IIR - * filters became unstable. - */ - ALsizei todo = mini(BUFFERSIZE, (SamplesToDo-base) * 4); - - /* Fill oversample buffer using zero stuffing. Multiply the sample by - * the amount of oversampling to maintain the signal's power. - */ - for(i = 0;i < todo;i++) - buffer[0][i] = !(i&3) ? SamplesIn[0][(i>>2)+base] * 4.0f : 0.0f; - - /* First step, do lowpass filtering of original signal. Additionally - * perform buffer interpolation and lowpass cutoff for oversampling - * (which is fortunately first step of distortion). So combine three - * operations into the one. - */ - BiquadFilter_process(&state->lowpass, buffer[1], buffer[0], todo); - - /* Second step, do distortion using waveshaper function to emulate - * signal processing during tube overdriving. Three steps of - * waveshaping are intended to modify waveform without boost/clipping/ - * attenuation process. - */ - for(i = 0;i < todo;i++) - { - ALfloat smp = buffer[1][i]; - - smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)); - smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)) * -1.0f; - smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)); - - buffer[0][i] = smp; - } - - /* Third step, do bandpass filtering of distorted signal. */ - BiquadFilter_process(&state->bandpass, buffer[1], buffer[0], todo); - - todo >>= 2; - for(k = 0;k < NumChannels;k++) - { - /* Fourth step, final, do attenuation and perform decimation, - * storing only one sample out of four. - */ - ALfloat gain = state->Gain[k]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - for(i = 0;i < todo;i++) - SamplesOut[k][base+i] += gain * buffer[1][i*4]; - } - - base += todo; - } -} - - -typedef struct DistortionStateFactory { - DERIVE_FROM_TYPE(EffectStateFactory); -} DistortionStateFactory; - -static ALeffectState *DistortionStateFactory_create(DistortionStateFactory *UNUSED(factory)) -{ - ALdistortionState *state; - - NEW_OBJ0(state, ALdistortionState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(DistortionStateFactory); - - -EffectStateFactory *DistortionStateFactory_getFactory(void) -{ - static DistortionStateFactory DistortionFactory = { { GET_VTABLE2(DistortionStateFactory, EffectStateFactory) } }; - - return STATIC_CAST(EffectStateFactory, &DistortionFactory); -} - - -void ALdistortion_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param); } -void ALdistortion_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x", param); } -void ALdistortion_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_DISTORTION_EDGE: - if(!(val >= AL_DISTORTION_MIN_EDGE && val <= AL_DISTORTION_MAX_EDGE)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion edge out of range"); - props->Distortion.Edge = val; - break; - - case AL_DISTORTION_GAIN: - if(!(val >= AL_DISTORTION_MIN_GAIN && val <= AL_DISTORTION_MAX_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion gain out of range"); - props->Distortion.Gain = val; - break; - - case AL_DISTORTION_LOWPASS_CUTOFF: - if(!(val >= AL_DISTORTION_MIN_LOWPASS_CUTOFF && val <= AL_DISTORTION_MAX_LOWPASS_CUTOFF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion low-pass cutoff out of range"); - props->Distortion.LowpassCutoff = val; - break; - - case AL_DISTORTION_EQCENTER: - if(!(val >= AL_DISTORTION_MIN_EQCENTER && val <= AL_DISTORTION_MAX_EQCENTER)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion EQ center out of range"); - props->Distortion.EQCenter = val; - break; - - case AL_DISTORTION_EQBANDWIDTH: - if(!(val >= AL_DISTORTION_MIN_EQBANDWIDTH && val <= AL_DISTORTION_MAX_EQBANDWIDTH)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion EQ bandwidth out of range"); - props->Distortion.EQBandwidth = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", - param); - } -} -void ALdistortion_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ ALdistortion_setParamf(effect, context, param, vals[0]); } - -void ALdistortion_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param); } -void ALdistortion_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x", param); } -void ALdistortion_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_DISTORTION_EDGE: - *val = props->Distortion.Edge; - break; - - case AL_DISTORTION_GAIN: - *val = props->Distortion.Gain; - break; - - case AL_DISTORTION_LOWPASS_CUTOFF: - *val = props->Distortion.LowpassCutoff; - break; - - case AL_DISTORTION_EQCENTER: - *val = props->Distortion.EQCenter; - break; - - case AL_DISTORTION_EQBANDWIDTH: - *val = props->Distortion.EQBandwidth; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", - param); - } -} -void ALdistortion_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ ALdistortion_getParamf(effect, context, param, vals); } - -DEFINE_ALEFFECT_VTABLE(ALdistortion); diff --git a/Alc/effects/distortion.cpp b/Alc/effects/distortion.cpp new file mode 100644 index 00000000..75629d9c --- /dev/null +++ b/Alc/effects/distortion.cpp @@ -0,0 +1,289 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2013 by Mike Gorchak + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" +#include "filters/defs.h" + + +struct ALdistortionState final : public ALeffectState { + /* Effect gains for each channel */ + ALfloat Gain[MAX_OUTPUT_CHANNELS]; + + /* Effect parameters */ + BiquadFilter lowpass; + BiquadFilter bandpass; + ALfloat attenuation; + ALfloat edge_coeff; + + ALfloat Buffer[2][BUFFERSIZE]; +}; + +static ALvoid ALdistortionState_Destruct(ALdistortionState *state); +static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *device); +static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALdistortionState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALdistortionState); + + +static void ALdistortionState_Construct(ALdistortionState *state) +{ + new (state) ALdistortionState{}; + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALdistortionState, ALeffectState, state); +} + +static ALvoid ALdistortionState_Destruct(ALdistortionState *state) +{ + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); + state->~ALdistortionState(); +} + +static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *UNUSED(device)) +{ + BiquadFilter_clear(&state->lowpass); + BiquadFilter_clear(&state->bandpass); + return AL_TRUE; +} + +static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +{ + const ALCdevice *device = context->Device; + ALfloat frequency = (ALfloat)device->Frequency; + ALfloat coeffs[MAX_AMBI_COEFFS]; + ALfloat bandwidth; + ALfloat cutoff; + ALfloat edge; + + /* Store waveshaper edge settings. */ + edge = sinf(props->Distortion.Edge * (F_PI_2)); + edge = minf(edge, 0.99f); + state->edge_coeff = 2.0f * edge / (1.0f-edge); + + cutoff = props->Distortion.LowpassCutoff; + /* Bandwidth value is constant in octaves. */ + bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f); + /* Multiply sampling frequency by the amount of oversampling done during + * processing. + */ + BiquadFilter_setParams(&state->lowpass, BiquadType_LowPass, 1.0f, + cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) + ); + + cutoff = props->Distortion.EQCenter; + /* Convert bandwidth in Hz to octaves. */ + bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f); + BiquadFilter_setParams(&state->bandpass, BiquadType_BandPass, 1.0f, + cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) + ); + + CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain*props->Distortion.Gain, state->Gain); +} + +static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +{ + ALfloat (*RESTRICT buffer)[BUFFERSIZE] = state->Buffer; + const ALfloat fc = state->edge_coeff; + ALsizei base; + ALsizei i, k; + + for(base = 0;base < SamplesToDo;) + { + /* Perform 4x oversampling to avoid aliasing. Oversampling greatly + * improves distortion quality and allows to implement lowpass and + * bandpass filters using high frequencies, at which classic IIR + * filters became unstable. + */ + ALsizei todo = mini(BUFFERSIZE, (SamplesToDo-base) * 4); + + /* Fill oversample buffer using zero stuffing. Multiply the sample by + * the amount of oversampling to maintain the signal's power. + */ + for(i = 0;i < todo;i++) + buffer[0][i] = !(i&3) ? SamplesIn[0][(i>>2)+base] * 4.0f : 0.0f; + + /* First step, do lowpass filtering of original signal. Additionally + * perform buffer interpolation and lowpass cutoff for oversampling + * (which is fortunately first step of distortion). So combine three + * operations into the one. + */ + BiquadFilter_process(&state->lowpass, buffer[1], buffer[0], todo); + + /* Second step, do distortion using waveshaper function to emulate + * signal processing during tube overdriving. Three steps of + * waveshaping are intended to modify waveform without boost/clipping/ + * attenuation process. + */ + for(i = 0;i < todo;i++) + { + ALfloat smp = buffer[1][i]; + + smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)); + smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)) * -1.0f; + smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)); + + buffer[0][i] = smp; + } + + /* Third step, do bandpass filtering of distorted signal. */ + BiquadFilter_process(&state->bandpass, buffer[1], buffer[0], todo); + + todo >>= 2; + for(k = 0;k < NumChannels;k++) + { + /* Fourth step, final, do attenuation and perform decimation, + * storing only one sample out of four. + */ + ALfloat gain = state->Gain[k]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + for(i = 0;i < todo;i++) + SamplesOut[k][base+i] += gain * buffer[1][i*4]; + } + + base += todo; + } +} + + +struct DistortionStateFactory final : public EffectStateFactory { + DistortionStateFactory() noexcept; +}; + +static ALeffectState *DistortionStateFactory_create(DistortionStateFactory *UNUSED(factory)) +{ + ALdistortionState *state; + + NEW_OBJ0(state, ALdistortionState)(); + if(!state) return NULL; + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_EFFECTSTATEFACTORY_VTABLE(DistortionStateFactory); + +DistortionStateFactory::DistortionStateFactory() noexcept + : EffectStateFactory{GET_VTABLE2(DistortionStateFactory, EffectStateFactory)} +{ +} + +EffectStateFactory *DistortionStateFactory_getFactory(void) +{ + static DistortionStateFactory DistortionFactory{}; + return STATIC_CAST(EffectStateFactory, &DistortionFactory); +} + + +void ALdistortion_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param); } +void ALdistortion_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x", param); } +void ALdistortion_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_DISTORTION_EDGE: + if(!(val >= AL_DISTORTION_MIN_EDGE && val <= AL_DISTORTION_MAX_EDGE)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion edge out of range"); + props->Distortion.Edge = val; + break; + + case AL_DISTORTION_GAIN: + if(!(val >= AL_DISTORTION_MIN_GAIN && val <= AL_DISTORTION_MAX_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion gain out of range"); + props->Distortion.Gain = val; + break; + + case AL_DISTORTION_LOWPASS_CUTOFF: + if(!(val >= AL_DISTORTION_MIN_LOWPASS_CUTOFF && val <= AL_DISTORTION_MAX_LOWPASS_CUTOFF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion low-pass cutoff out of range"); + props->Distortion.LowpassCutoff = val; + break; + + case AL_DISTORTION_EQCENTER: + if(!(val >= AL_DISTORTION_MIN_EQCENTER && val <= AL_DISTORTION_MAX_EQCENTER)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion EQ center out of range"); + props->Distortion.EQCenter = val; + break; + + case AL_DISTORTION_EQBANDWIDTH: + if(!(val >= AL_DISTORTION_MIN_EQBANDWIDTH && val <= AL_DISTORTION_MAX_EQBANDWIDTH)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion EQ bandwidth out of range"); + props->Distortion.EQBandwidth = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", + param); + } +} +void ALdistortion_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALdistortion_setParamf(effect, context, param, vals[0]); } + +void ALdistortion_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param); } +void ALdistortion_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x", param); } +void ALdistortion_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_DISTORTION_EDGE: + *val = props->Distortion.Edge; + break; + + case AL_DISTORTION_GAIN: + *val = props->Distortion.Gain; + break; + + case AL_DISTORTION_LOWPASS_CUTOFF: + *val = props->Distortion.LowpassCutoff; + break; + + case AL_DISTORTION_EQCENTER: + *val = props->Distortion.EQCenter; + break; + + case AL_DISTORTION_EQBANDWIDTH: + *val = props->Distortion.EQBandwidth; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", + param); + } +} +void ALdistortion_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALdistortion_getParamf(effect, context, param, vals); } + +DEFINE_ALEFFECT_VTABLE(ALdistortion); diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c deleted file mode 100644 index 5c323986..00000000 --- a/Alc/effects/echo.c +++ /dev/null @@ -1,310 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2009 by Chris Robinson. - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alFilter.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" -#include "filters/defs.h" - - -typedef struct ALechoState { - DERIVE_FROM_TYPE(ALeffectState); - - ALfloat *SampleBuffer; - ALsizei BufferLength; - - // The echo is two tap. The delay is the number of samples from before the - // current offset - struct { - ALsizei delay; - } Tap[2]; - ALsizei Offset; - - /* The panning gains for the two taps */ - struct { - ALfloat Current[MAX_OUTPUT_CHANNELS]; - ALfloat Target[MAX_OUTPUT_CHANNELS]; - } Gains[2]; - - ALfloat FeedGain; - - BiquadFilter Filter; -} ALechoState; - -static ALvoid ALechoState_Destruct(ALechoState *state); -static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device); -static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALechoState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALechoState); - - -static void ALechoState_Construct(ALechoState *state) -{ - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALechoState, ALeffectState, state); - - state->BufferLength = 0; - state->SampleBuffer = NULL; - - state->Tap[0].delay = 0; - state->Tap[1].delay = 0; - state->Offset = 0; - - BiquadFilter_clear(&state->Filter); -} - -static ALvoid ALechoState_Destruct(ALechoState *state) -{ - al_free(state->SampleBuffer); - state->SampleBuffer = NULL; - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); -} - -static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device) -{ - ALsizei maxlen; - - // Use the next power of 2 for the buffer length, so the tap offsets can be - // wrapped using a mask instead of a modulo - maxlen = float2int(AL_ECHO_MAX_DELAY*Device->Frequency + 0.5f) + - float2int(AL_ECHO_MAX_LRDELAY*Device->Frequency + 0.5f); - maxlen = NextPowerOf2(maxlen); - if(maxlen <= 0) return AL_FALSE; - - if(maxlen != state->BufferLength) - { - void *temp = al_calloc(16, maxlen * sizeof(ALfloat)); - if(!temp) return AL_FALSE; - - al_free(state->SampleBuffer); - state->SampleBuffer = temp; - state->BufferLength = maxlen; - } - - memset(state->SampleBuffer, 0, state->BufferLength*sizeof(ALfloat)); - memset(state->Gains, 0, sizeof(state->Gains)); - - return AL_TRUE; -} - -static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) -{ - const ALCdevice *device = context->Device; - ALuint frequency = device->Frequency; - ALfloat coeffs[MAX_AMBI_COEFFS]; - ALfloat gainhf, lrpan, spread; - - state->Tap[0].delay = maxi(float2int(props->Echo.Delay*frequency + 0.5f), 1); - state->Tap[1].delay = float2int(props->Echo.LRDelay*frequency + 0.5f); - state->Tap[1].delay += state->Tap[0].delay; - - spread = props->Echo.Spread; - if(spread < 0.0f) lrpan = -1.0f; - else lrpan = 1.0f; - /* Convert echo spread (where 0 = omni, +/-1 = directional) to coverage - * spread (where 0 = point, tau = omni). - */ - spread = asinf(1.0f - fabsf(spread))*4.0f; - - state->FeedGain = props->Echo.Feedback; - - gainhf = maxf(1.0f - props->Echo.Damping, 0.0625f); /* Limit -24dB */ - BiquadFilter_setParams(&state->Filter, BiquadType_HighShelf, - gainhf, LOWPASSFREQREF/frequency, calc_rcpQ_from_slope(gainhf, 1.0f) - ); - - /* First tap panning */ - CalcAngleCoeffs(-F_PI_2*lrpan, 0.0f, spread, coeffs); - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->Gains[0].Target); - - /* Second tap panning */ - CalcAngleCoeffs( F_PI_2*lrpan, 0.0f, spread, coeffs); - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->Gains[1].Target); -} - -static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) -{ - const ALsizei mask = state->BufferLength-1; - const ALsizei tap1 = state->Tap[0].delay; - const ALsizei tap2 = state->Tap[1].delay; - ALfloat *RESTRICT delaybuf = state->SampleBuffer; - ALsizei offset = state->Offset; - ALfloat z1, z2, in, out; - ALsizei base; - ALsizei c, i; - - z1 = state->Filter.z1; - z2 = state->Filter.z2; - for(base = 0;base < SamplesToDo;) - { - alignas(16) ALfloat temps[2][128]; - ALsizei td = mini(128, SamplesToDo-base); - - for(i = 0;i < td;i++) - { - /* Feed the delay buffer's input first. */ - delaybuf[offset&mask] = SamplesIn[0][i+base]; - - /* First tap */ - temps[0][i] = delaybuf[(offset-tap1) & mask]; - /* Second tap */ - temps[1][i] = delaybuf[(offset-tap2) & mask]; - - /* Apply damping to the second tap, then add it to the buffer with - * feedback attenuation. - */ - in = temps[1][i]; - out = in*state->Filter.b0 + z1; - z1 = in*state->Filter.b1 - out*state->Filter.a1 + z2; - z2 = in*state->Filter.b2 - out*state->Filter.a2; - - delaybuf[offset&mask] += out * state->FeedGain; - offset++; - } - - for(c = 0;c < 2;c++) - MixSamples(temps[c], NumChannels, SamplesOut, state->Gains[c].Current, - state->Gains[c].Target, SamplesToDo-base, base, td); - - base += td; - } - state->Filter.z1 = z1; - state->Filter.z2 = z2; - - state->Offset = offset; -} - - -typedef struct EchoStateFactory { - DERIVE_FROM_TYPE(EffectStateFactory); -} EchoStateFactory; - -ALeffectState *EchoStateFactory_create(EchoStateFactory *UNUSED(factory)) -{ - ALechoState *state; - - NEW_OBJ0(state, ALechoState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(EchoStateFactory); - -EffectStateFactory *EchoStateFactory_getFactory(void) -{ - static EchoStateFactory EchoFactory = { { GET_VTABLE2(EchoStateFactory, EffectStateFactory) } }; - - return STATIC_CAST(EffectStateFactory, &EchoFactory); -} - - -void ALecho_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param); } -void ALecho_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param); } -void ALecho_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_ECHO_DELAY: - if(!(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo delay out of range"); - props->Echo.Delay = val; - break; - - case AL_ECHO_LRDELAY: - if(!(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo LR delay out of range"); - props->Echo.LRDelay = val; - break; - - case AL_ECHO_DAMPING: - if(!(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo damping out of range"); - props->Echo.Damping = val; - break; - - case AL_ECHO_FEEDBACK: - if(!(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo feedback out of range"); - props->Echo.Feedback = val; - break; - - case AL_ECHO_SPREAD: - if(!(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo spread out of range"); - props->Echo.Spread = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param); - } -} -void ALecho_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ ALecho_setParamf(effect, context, param, vals[0]); } - -void ALecho_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param); } -void ALecho_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param); } -void ALecho_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_ECHO_DELAY: - *val = props->Echo.Delay; - break; - - case AL_ECHO_LRDELAY: - *val = props->Echo.LRDelay; - break; - - case AL_ECHO_DAMPING: - *val = props->Echo.Damping; - break; - - case AL_ECHO_FEEDBACK: - *val = props->Echo.Feedback; - break; - - case AL_ECHO_SPREAD: - *val = props->Echo.Spread; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param); - } -} -void ALecho_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ ALecho_getParamf(effect, context, param, vals); } - -DEFINE_ALEFFECT_VTABLE(ALecho); diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp new file mode 100644 index 00000000..f987e582 --- /dev/null +++ b/Alc/effects/echo.cpp @@ -0,0 +1,314 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2009 by Chris Robinson. + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alFilter.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" +#include "filters/defs.h" + + +struct ALechoState final : public ALeffectState { + ALfloat *SampleBuffer; + ALsizei BufferLength; + + // The echo is two tap. The delay is the number of samples from before the + // current offset + struct { + ALsizei delay; + } Tap[2]; + ALsizei Offset; + + /* The panning gains for the two taps */ + struct { + ALfloat Current[MAX_OUTPUT_CHANNELS]; + ALfloat Target[MAX_OUTPUT_CHANNELS]; + } Gains[2]; + + ALfloat FeedGain; + + BiquadFilter Filter; +}; + +static ALvoid ALechoState_Destruct(ALechoState *state); +static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device); +static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALechoState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALechoState); + + +static void ALechoState_Construct(ALechoState *state) +{ + new (state) ALechoState{}; + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALechoState, ALeffectState, state); + + state->BufferLength = 0; + state->SampleBuffer = NULL; + + state->Tap[0].delay = 0; + state->Tap[1].delay = 0; + state->Offset = 0; + + BiquadFilter_clear(&state->Filter); +} + +static ALvoid ALechoState_Destruct(ALechoState *state) +{ + al_free(state->SampleBuffer); + state->SampleBuffer = NULL; + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); + state->~ALechoState(); +} + +static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device) +{ + ALsizei maxlen; + + // Use the next power of 2 for the buffer length, so the tap offsets can be + // wrapped using a mask instead of a modulo + maxlen = float2int(AL_ECHO_MAX_DELAY*Device->Frequency + 0.5f) + + float2int(AL_ECHO_MAX_LRDELAY*Device->Frequency + 0.5f); + maxlen = NextPowerOf2(maxlen); + if(maxlen <= 0) return AL_FALSE; + + if(maxlen != state->BufferLength) + { + void *temp = al_calloc(16, maxlen * sizeof(ALfloat)); + if(!temp) return AL_FALSE; + + al_free(state->SampleBuffer); + state->SampleBuffer = static_cast(temp); + state->BufferLength = maxlen; + } + + memset(state->SampleBuffer, 0, state->BufferLength*sizeof(ALfloat)); + memset(state->Gains, 0, sizeof(state->Gains)); + + return AL_TRUE; +} + +static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +{ + const ALCdevice *device = context->Device; + ALuint frequency = device->Frequency; + ALfloat coeffs[MAX_AMBI_COEFFS]; + ALfloat gainhf, lrpan, spread; + + state->Tap[0].delay = maxi(float2int(props->Echo.Delay*frequency + 0.5f), 1); + state->Tap[1].delay = float2int(props->Echo.LRDelay*frequency + 0.5f); + state->Tap[1].delay += state->Tap[0].delay; + + spread = props->Echo.Spread; + if(spread < 0.0f) lrpan = -1.0f; + else lrpan = 1.0f; + /* Convert echo spread (where 0 = omni, +/-1 = directional) to coverage + * spread (where 0 = point, tau = omni). + */ + spread = asinf(1.0f - fabsf(spread))*4.0f; + + state->FeedGain = props->Echo.Feedback; + + gainhf = maxf(1.0f - props->Echo.Damping, 0.0625f); /* Limit -24dB */ + BiquadFilter_setParams(&state->Filter, BiquadType_HighShelf, + gainhf, LOWPASSFREQREF/frequency, calc_rcpQ_from_slope(gainhf, 1.0f) + ); + + /* First tap panning */ + CalcAngleCoeffs(-F_PI_2*lrpan, 0.0f, spread, coeffs); + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->Gains[0].Target); + + /* Second tap panning */ + CalcAngleCoeffs( F_PI_2*lrpan, 0.0f, spread, coeffs); + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->Gains[1].Target); +} + +static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +{ + const ALsizei mask = state->BufferLength-1; + const ALsizei tap1 = state->Tap[0].delay; + const ALsizei tap2 = state->Tap[1].delay; + ALfloat *RESTRICT delaybuf = state->SampleBuffer; + ALsizei offset = state->Offset; + ALfloat z1, z2, in, out; + ALsizei base; + ALsizei c, i; + + z1 = state->Filter.z1; + z2 = state->Filter.z2; + for(base = 0;base < SamplesToDo;) + { + alignas(16) ALfloat temps[2][128]; + ALsizei td = mini(128, SamplesToDo-base); + + for(i = 0;i < td;i++) + { + /* Feed the delay buffer's input first. */ + delaybuf[offset&mask] = SamplesIn[0][i+base]; + + /* First tap */ + temps[0][i] = delaybuf[(offset-tap1) & mask]; + /* Second tap */ + temps[1][i] = delaybuf[(offset-tap2) & mask]; + + /* Apply damping to the second tap, then add it to the buffer with + * feedback attenuation. + */ + in = temps[1][i]; + out = in*state->Filter.b0 + z1; + z1 = in*state->Filter.b1 - out*state->Filter.a1 + z2; + z2 = in*state->Filter.b2 - out*state->Filter.a2; + + delaybuf[offset&mask] += out * state->FeedGain; + offset++; + } + + for(c = 0;c < 2;c++) + MixSamples(temps[c], NumChannels, SamplesOut, state->Gains[c].Current, + state->Gains[c].Target, SamplesToDo-base, base, td); + + base += td; + } + state->Filter.z1 = z1; + state->Filter.z2 = z2; + + state->Offset = offset; +} + + +struct EchoStateFactory final : public EffectStateFactory { + EchoStateFactory() noexcept; +}; + +ALeffectState *EchoStateFactory_create(EchoStateFactory *UNUSED(factory)) +{ + ALechoState *state; + + NEW_OBJ0(state, ALechoState)(); + if(!state) return NULL; + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_EFFECTSTATEFACTORY_VTABLE(EchoStateFactory); + +EchoStateFactory::EchoStateFactory() noexcept + : EffectStateFactory{GET_VTABLE2(EchoStateFactory, EffectStateFactory)} +{ +} + +EffectStateFactory *EchoStateFactory_getFactory(void) +{ + static EchoStateFactory EchoFactory{}; + return STATIC_CAST(EffectStateFactory, &EchoFactory); +} + + +void ALecho_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param); } +void ALecho_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param); } +void ALecho_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_ECHO_DELAY: + if(!(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo delay out of range"); + props->Echo.Delay = val; + break; + + case AL_ECHO_LRDELAY: + if(!(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo LR delay out of range"); + props->Echo.LRDelay = val; + break; + + case AL_ECHO_DAMPING: + if(!(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo damping out of range"); + props->Echo.Damping = val; + break; + + case AL_ECHO_FEEDBACK: + if(!(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo feedback out of range"); + props->Echo.Feedback = val; + break; + + case AL_ECHO_SPREAD: + if(!(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo spread out of range"); + props->Echo.Spread = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param); + } +} +void ALecho_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALecho_setParamf(effect, context, param, vals[0]); } + +void ALecho_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param); } +void ALecho_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param); } +void ALecho_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_ECHO_DELAY: + *val = props->Echo.Delay; + break; + + case AL_ECHO_LRDELAY: + *val = props->Echo.LRDelay; + break; + + case AL_ECHO_DAMPING: + *val = props->Echo.Damping; + break; + + case AL_ECHO_FEEDBACK: + *val = props->Echo.Feedback; + break; + + case AL_ECHO_SPREAD: + *val = props->Echo.Spread; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param); + } +} +void ALecho_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALecho_getParamf(effect, context, param, vals); } + +DEFINE_ALEFFECT_VTABLE(ALecho); diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c deleted file mode 100644 index c62f8e80..00000000 --- a/Alc/effects/equalizer.c +++ /dev/null @@ -1,355 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2013 by Mike Gorchak - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" -#include "filters/defs.h" - - -/* The document "Effects Extension Guide.pdf" says that low and high * - * frequencies are cutoff frequencies. This is not fully correct, they * - * are corner frequencies for low and high shelf filters. If they were * - * just cutoff frequencies, there would be no need in cutoff frequency * - * gains, which are present. Documentation for "Creative Proteus X2" * - * software describes 4-band equalizer functionality in a much better * - * way. This equalizer seems to be a predecessor of OpenAL 4-band * - * equalizer. With low and high shelf filters we are able to cutoff * - * frequencies below and/or above corner frequencies using attenuation * - * gains (below 1.0) and amplify all low and/or high frequencies using * - * gains above 1.0. * - * * - * Low-shelf Low Mid Band High Mid Band High-shelf * - * corner center center corner * - * frequency frequency frequency frequency * - * 50Hz..800Hz 200Hz..3000Hz 1000Hz..8000Hz 4000Hz..16000Hz * - * * - * | | | | * - * | | | | * - * B -----+ /--+--\ /--+--\ +----- * - * O |\ | | | | | | /| * - * O | \ - | - - | - / | * - * S + | \ | | | | | | / | * - * T | | | | | | | | | | * - * ---------+---------------+------------------+---------------+-------- * - * C | | | | | | | | | | * - * U - | / | | | | | | \ | * - * T | / - | - - | - \ | * - * O |/ | | | | | | \| * - * F -----+ \--+--/ \--+--/ +----- * - * F | | | | * - * | | | | * - * * - * Gains vary from 0.126 up to 7.943, which means from -18dB attenuation * - * up to +18dB amplification. Band width varies from 0.01 up to 1.0 in * - * octaves for two mid bands. * - * * - * Implementation is based on the "Cookbook formulae for audio EQ biquad * - * filter coefficients" by Robert Bristow-Johnson * - * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */ - - -typedef struct ALequalizerState { - DERIVE_FROM_TYPE(ALeffectState); - - struct { - /* Effect parameters */ - BiquadFilter filter[4]; - - /* Effect gains for each channel */ - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; - } Chans[MAX_EFFECT_CHANNELS]; - - ALfloat SampleBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE]; -} ALequalizerState; - -static ALvoid ALequalizerState_Destruct(ALequalizerState *state); -static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevice *device); -static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALequalizerState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALequalizerState); - - -static void ALequalizerState_Construct(ALequalizerState *state) -{ - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALequalizerState, ALeffectState, state); -} - -static ALvoid ALequalizerState_Destruct(ALequalizerState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); -} - -static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevice *UNUSED(device)) -{ - ALsizei i, j; - - for(i = 0; i < MAX_EFFECT_CHANNELS;i++) - { - for(j = 0;j < 4;j++) - BiquadFilter_clear(&state->Chans[i].filter[j]); - for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - state->Chans[i].CurrentGains[j] = 0.0f; - } - return AL_TRUE; -} - -static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) -{ - const ALCdevice *device = context->Device; - ALfloat frequency = (ALfloat)device->Frequency; - ALfloat gain, f0norm; - ALuint i; - - /* Calculate coefficients for the each type of filter. Note that the shelf - * filters' gain is for the reference frequency, which is the centerpoint - * of the transition band. - */ - gain = maxf(sqrtf(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */ - f0norm = props->Equalizer.LowCutoff/frequency; - BiquadFilter_setParams(&state->Chans[0].filter[0], BiquadType_LowShelf, - gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f) - ); - - gain = maxf(props->Equalizer.Mid1Gain, 0.0625f); - f0norm = props->Equalizer.Mid1Center/frequency; - BiquadFilter_setParams(&state->Chans[0].filter[1], BiquadType_Peaking, - gain, f0norm, calc_rcpQ_from_bandwidth( - f0norm, props->Equalizer.Mid1Width - ) - ); - - gain = maxf(props->Equalizer.Mid2Gain, 0.0625f); - f0norm = props->Equalizer.Mid2Center/frequency; - BiquadFilter_setParams(&state->Chans[0].filter[2], BiquadType_Peaking, - gain, f0norm, calc_rcpQ_from_bandwidth( - f0norm, props->Equalizer.Mid2Width - ) - ); - - gain = maxf(sqrtf(props->Equalizer.HighGain), 0.0625f); - f0norm = props->Equalizer.HighCutoff/frequency; - BiquadFilter_setParams(&state->Chans[0].filter[3], BiquadType_HighShelf, - gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f) - ); - - /* Copy the filter coefficients for the other input channels. */ - for(i = 1;i < MAX_EFFECT_CHANNELS;i++) - { - BiquadFilter_copyParams(&state->Chans[i].filter[0], &state->Chans[0].filter[0]); - BiquadFilter_copyParams(&state->Chans[i].filter[1], &state->Chans[0].filter[1]); - BiquadFilter_copyParams(&state->Chans[i].filter[2], &state->Chans[0].filter[2]); - BiquadFilter_copyParams(&state->Chans[i].filter[3], &state->Chans[0].filter[3]); - } - - STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; - STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain, - state->Chans[i].TargetGains); -} - -static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) -{ - ALfloat (*RESTRICT temps)[BUFFERSIZE] = state->SampleBuffer; - ALsizei c; - - for(c = 0;c < MAX_EFFECT_CHANNELS;c++) - { - BiquadFilter_process(&state->Chans[c].filter[0], temps[0], SamplesIn[c], SamplesToDo); - BiquadFilter_process(&state->Chans[c].filter[1], temps[1], temps[0], SamplesToDo); - BiquadFilter_process(&state->Chans[c].filter[2], temps[2], temps[1], SamplesToDo); - BiquadFilter_process(&state->Chans[c].filter[3], temps[3], temps[2], SamplesToDo); - - MixSamples(temps[3], NumChannels, SamplesOut, - state->Chans[c].CurrentGains, state->Chans[c].TargetGains, - SamplesToDo, 0, SamplesToDo - ); - } -} - - -typedef struct EqualizerStateFactory { - DERIVE_FROM_TYPE(EffectStateFactory); -} EqualizerStateFactory; - -ALeffectState *EqualizerStateFactory_create(EqualizerStateFactory *UNUSED(factory)) -{ - ALequalizerState *state; - - NEW_OBJ0(state, ALequalizerState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(EqualizerStateFactory); - -EffectStateFactory *EqualizerStateFactory_getFactory(void) -{ - static EqualizerStateFactory EqualizerFactory = { { GET_VTABLE2(EqualizerStateFactory, EffectStateFactory) } }; - - return STATIC_CAST(EffectStateFactory, &EqualizerFactory); -} - - -void ALequalizer_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param); } -void ALequalizer_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x", param); } -void ALequalizer_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_EQUALIZER_LOW_GAIN: - if(!(val >= AL_EQUALIZER_MIN_LOW_GAIN && val <= AL_EQUALIZER_MAX_LOW_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer low-band gain out of range"); - props->Equalizer.LowGain = val; - break; - - case AL_EQUALIZER_LOW_CUTOFF: - if(!(val >= AL_EQUALIZER_MIN_LOW_CUTOFF && val <= AL_EQUALIZER_MAX_LOW_CUTOFF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer low-band cutoff out of range"); - props->Equalizer.LowCutoff = val; - break; - - case AL_EQUALIZER_MID1_GAIN: - if(!(val >= AL_EQUALIZER_MIN_MID1_GAIN && val <= AL_EQUALIZER_MAX_MID1_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band gain out of range"); - props->Equalizer.Mid1Gain = val; - break; - - case AL_EQUALIZER_MID1_CENTER: - if(!(val >= AL_EQUALIZER_MIN_MID1_CENTER && val <= AL_EQUALIZER_MAX_MID1_CENTER)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band center out of range"); - props->Equalizer.Mid1Center = val; - break; - - case AL_EQUALIZER_MID1_WIDTH: - if(!(val >= AL_EQUALIZER_MIN_MID1_WIDTH && val <= AL_EQUALIZER_MAX_MID1_WIDTH)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band width out of range"); - props->Equalizer.Mid1Width = val; - break; - - case AL_EQUALIZER_MID2_GAIN: - if(!(val >= AL_EQUALIZER_MIN_MID2_GAIN && val <= AL_EQUALIZER_MAX_MID2_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band gain out of range"); - props->Equalizer.Mid2Gain = val; - break; - - case AL_EQUALIZER_MID2_CENTER: - if(!(val >= AL_EQUALIZER_MIN_MID2_CENTER && val <= AL_EQUALIZER_MAX_MID2_CENTER)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band center out of range"); - props->Equalizer.Mid2Center = val; - break; - - case AL_EQUALIZER_MID2_WIDTH: - if(!(val >= AL_EQUALIZER_MIN_MID2_WIDTH && val <= AL_EQUALIZER_MAX_MID2_WIDTH)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band width out of range"); - props->Equalizer.Mid2Width = val; - break; - - case AL_EQUALIZER_HIGH_GAIN: - if(!(val >= AL_EQUALIZER_MIN_HIGH_GAIN && val <= AL_EQUALIZER_MAX_HIGH_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer high-band gain out of range"); - props->Equalizer.HighGain = val; - break; - - case AL_EQUALIZER_HIGH_CUTOFF: - if(!(val >= AL_EQUALIZER_MIN_HIGH_CUTOFF && val <= AL_EQUALIZER_MAX_HIGH_CUTOFF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer high-band cutoff out of range"); - props->Equalizer.HighCutoff = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param); - } -} -void ALequalizer_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ ALequalizer_setParamf(effect, context, param, vals[0]); } - -void ALequalizer_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param); } -void ALequalizer_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x", param); } -void ALequalizer_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_EQUALIZER_LOW_GAIN: - *val = props->Equalizer.LowGain; - break; - - case AL_EQUALIZER_LOW_CUTOFF: - *val = props->Equalizer.LowCutoff; - break; - - case AL_EQUALIZER_MID1_GAIN: - *val = props->Equalizer.Mid1Gain; - break; - - case AL_EQUALIZER_MID1_CENTER: - *val = props->Equalizer.Mid1Center; - break; - - case AL_EQUALIZER_MID1_WIDTH: - *val = props->Equalizer.Mid1Width; - break; - - case AL_EQUALIZER_MID2_GAIN: - *val = props->Equalizer.Mid2Gain; - break; - - case AL_EQUALIZER_MID2_CENTER: - *val = props->Equalizer.Mid2Center; - break; - - case AL_EQUALIZER_MID2_WIDTH: - *val = props->Equalizer.Mid2Width; - break; - - case AL_EQUALIZER_HIGH_GAIN: - *val = props->Equalizer.HighGain; - break; - - case AL_EQUALIZER_HIGH_CUTOFF: - *val = props->Equalizer.HighCutoff; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param); - } -} -void ALequalizer_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ ALequalizer_getParamf(effect, context, param, vals); } - -DEFINE_ALEFFECT_VTABLE(ALequalizer); diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp new file mode 100644 index 00000000..8388a123 --- /dev/null +++ b/Alc/effects/equalizer.cpp @@ -0,0 +1,359 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2013 by Mike Gorchak + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" +#include "filters/defs.h" + + +/* The document "Effects Extension Guide.pdf" says that low and high * + * frequencies are cutoff frequencies. This is not fully correct, they * + * are corner frequencies for low and high shelf filters. If they were * + * just cutoff frequencies, there would be no need in cutoff frequency * + * gains, which are present. Documentation for "Creative Proteus X2" * + * software describes 4-band equalizer functionality in a much better * + * way. This equalizer seems to be a predecessor of OpenAL 4-band * + * equalizer. With low and high shelf filters we are able to cutoff * + * frequencies below and/or above corner frequencies using attenuation * + * gains (below 1.0) and amplify all low and/or high frequencies using * + * gains above 1.0. * + * * + * Low-shelf Low Mid Band High Mid Band High-shelf * + * corner center center corner * + * frequency frequency frequency frequency * + * 50Hz..800Hz 200Hz..3000Hz 1000Hz..8000Hz 4000Hz..16000Hz * + * * + * | | | | * + * | | | | * + * B -----+ /--+--\ /--+--\ +----- * + * O |\ | | | | | | /| * + * O | \ - | - - | - / | * + * S + | \ | | | | | | / | * + * T | | | | | | | | | | * + * ---------+---------------+------------------+---------------+-------- * + * C | | | | | | | | | | * + * U - | / | | | | | | \ | * + * T | / - | - - | - \ | * + * O |/ | | | | | | \| * + * F -----+ \--+--/ \--+--/ +----- * + * F | | | | * + * | | | | * + * * + * Gains vary from 0.126 up to 7.943, which means from -18dB attenuation * + * up to +18dB amplification. Band width varies from 0.01 up to 1.0 in * + * octaves for two mid bands. * + * * + * Implementation is based on the "Cookbook formulae for audio EQ biquad * + * filter coefficients" by Robert Bristow-Johnson * + * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */ + + +struct ALequalizerState final : public ALeffectState { + struct { + /* Effect parameters */ + BiquadFilter filter[4]; + + /* Effect gains for each channel */ + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; + } Chans[MAX_EFFECT_CHANNELS]; + + ALfloat SampleBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE]; +}; + +static ALvoid ALequalizerState_Destruct(ALequalizerState *state); +static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevice *device); +static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALequalizerState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALequalizerState); + + +static void ALequalizerState_Construct(ALequalizerState *state) +{ + new (state) ALequalizerState{}; + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALequalizerState, ALeffectState, state); +} + +static ALvoid ALequalizerState_Destruct(ALequalizerState *state) +{ + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); + state->~ALequalizerState(); +} + +static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevice *UNUSED(device)) +{ + ALsizei i, j; + + for(i = 0; i < MAX_EFFECT_CHANNELS;i++) + { + for(j = 0;j < 4;j++) + BiquadFilter_clear(&state->Chans[i].filter[j]); + for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) + state->Chans[i].CurrentGains[j] = 0.0f; + } + return AL_TRUE; +} + +static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +{ + const ALCdevice *device = context->Device; + ALfloat frequency = (ALfloat)device->Frequency; + ALfloat gain, f0norm; + ALuint i; + + /* Calculate coefficients for the each type of filter. Note that the shelf + * filters' gain is for the reference frequency, which is the centerpoint + * of the transition band. + */ + gain = maxf(sqrtf(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */ + f0norm = props->Equalizer.LowCutoff/frequency; + BiquadFilter_setParams(&state->Chans[0].filter[0], BiquadType_LowShelf, + gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f) + ); + + gain = maxf(props->Equalizer.Mid1Gain, 0.0625f); + f0norm = props->Equalizer.Mid1Center/frequency; + BiquadFilter_setParams(&state->Chans[0].filter[1], BiquadType_Peaking, + gain, f0norm, calc_rcpQ_from_bandwidth( + f0norm, props->Equalizer.Mid1Width + ) + ); + + gain = maxf(props->Equalizer.Mid2Gain, 0.0625f); + f0norm = props->Equalizer.Mid2Center/frequency; + BiquadFilter_setParams(&state->Chans[0].filter[2], BiquadType_Peaking, + gain, f0norm, calc_rcpQ_from_bandwidth( + f0norm, props->Equalizer.Mid2Width + ) + ); + + gain = maxf(sqrtf(props->Equalizer.HighGain), 0.0625f); + f0norm = props->Equalizer.HighCutoff/frequency; + BiquadFilter_setParams(&state->Chans[0].filter[3], BiquadType_HighShelf, + gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f) + ); + + /* Copy the filter coefficients for the other input channels. */ + for(i = 1;i < MAX_EFFECT_CHANNELS;i++) + { + BiquadFilter_copyParams(&state->Chans[i].filter[0], &state->Chans[0].filter[0]); + BiquadFilter_copyParams(&state->Chans[i].filter[1], &state->Chans[0].filter[1]); + BiquadFilter_copyParams(&state->Chans[i].filter[2], &state->Chans[0].filter[2]); + BiquadFilter_copyParams(&state->Chans[i].filter[3], &state->Chans[0].filter[3]); + } + + STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; + STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain, + state->Chans[i].TargetGains); +} + +static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +{ + ALfloat (*RESTRICT temps)[BUFFERSIZE] = state->SampleBuffer; + ALsizei c; + + for(c = 0;c < MAX_EFFECT_CHANNELS;c++) + { + BiquadFilter_process(&state->Chans[c].filter[0], temps[0], SamplesIn[c], SamplesToDo); + BiquadFilter_process(&state->Chans[c].filter[1], temps[1], temps[0], SamplesToDo); + BiquadFilter_process(&state->Chans[c].filter[2], temps[2], temps[1], SamplesToDo); + BiquadFilter_process(&state->Chans[c].filter[3], temps[3], temps[2], SamplesToDo); + + MixSamples(temps[3], NumChannels, SamplesOut, + state->Chans[c].CurrentGains, state->Chans[c].TargetGains, + SamplesToDo, 0, SamplesToDo + ); + } +} + + +struct EqualizerStateFactory final : public EffectStateFactory { + EqualizerStateFactory() noexcept; +}; + +ALeffectState *EqualizerStateFactory_create(EqualizerStateFactory *UNUSED(factory)) +{ + ALequalizerState *state; + + NEW_OBJ0(state, ALequalizerState)(); + if(!state) return NULL; + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_EFFECTSTATEFACTORY_VTABLE(EqualizerStateFactory); + +EqualizerStateFactory::EqualizerStateFactory() noexcept + : EffectStateFactory{GET_VTABLE2(EqualizerStateFactory, EffectStateFactory)} +{ +} + +EffectStateFactory *EqualizerStateFactory_getFactory(void) +{ + static EqualizerStateFactory EqualizerFactory{}; + return STATIC_CAST(EffectStateFactory, &EqualizerFactory); +} + + +void ALequalizer_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param); } +void ALequalizer_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x", param); } +void ALequalizer_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_EQUALIZER_LOW_GAIN: + if(!(val >= AL_EQUALIZER_MIN_LOW_GAIN && val <= AL_EQUALIZER_MAX_LOW_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer low-band gain out of range"); + props->Equalizer.LowGain = val; + break; + + case AL_EQUALIZER_LOW_CUTOFF: + if(!(val >= AL_EQUALIZER_MIN_LOW_CUTOFF && val <= AL_EQUALIZER_MAX_LOW_CUTOFF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer low-band cutoff out of range"); + props->Equalizer.LowCutoff = val; + break; + + case AL_EQUALIZER_MID1_GAIN: + if(!(val >= AL_EQUALIZER_MIN_MID1_GAIN && val <= AL_EQUALIZER_MAX_MID1_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band gain out of range"); + props->Equalizer.Mid1Gain = val; + break; + + case AL_EQUALIZER_MID1_CENTER: + if(!(val >= AL_EQUALIZER_MIN_MID1_CENTER && val <= AL_EQUALIZER_MAX_MID1_CENTER)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band center out of range"); + props->Equalizer.Mid1Center = val; + break; + + case AL_EQUALIZER_MID1_WIDTH: + if(!(val >= AL_EQUALIZER_MIN_MID1_WIDTH && val <= AL_EQUALIZER_MAX_MID1_WIDTH)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band width out of range"); + props->Equalizer.Mid1Width = val; + break; + + case AL_EQUALIZER_MID2_GAIN: + if(!(val >= AL_EQUALIZER_MIN_MID2_GAIN && val <= AL_EQUALIZER_MAX_MID2_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band gain out of range"); + props->Equalizer.Mid2Gain = val; + break; + + case AL_EQUALIZER_MID2_CENTER: + if(!(val >= AL_EQUALIZER_MIN_MID2_CENTER && val <= AL_EQUALIZER_MAX_MID2_CENTER)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band center out of range"); + props->Equalizer.Mid2Center = val; + break; + + case AL_EQUALIZER_MID2_WIDTH: + if(!(val >= AL_EQUALIZER_MIN_MID2_WIDTH && val <= AL_EQUALIZER_MAX_MID2_WIDTH)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band width out of range"); + props->Equalizer.Mid2Width = val; + break; + + case AL_EQUALIZER_HIGH_GAIN: + if(!(val >= AL_EQUALIZER_MIN_HIGH_GAIN && val <= AL_EQUALIZER_MAX_HIGH_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer high-band gain out of range"); + props->Equalizer.HighGain = val; + break; + + case AL_EQUALIZER_HIGH_CUTOFF: + if(!(val >= AL_EQUALIZER_MIN_HIGH_CUTOFF && val <= AL_EQUALIZER_MAX_HIGH_CUTOFF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer high-band cutoff out of range"); + props->Equalizer.HighCutoff = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param); + } +} +void ALequalizer_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALequalizer_setParamf(effect, context, param, vals[0]); } + +void ALequalizer_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param); } +void ALequalizer_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x", param); } +void ALequalizer_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_EQUALIZER_LOW_GAIN: + *val = props->Equalizer.LowGain; + break; + + case AL_EQUALIZER_LOW_CUTOFF: + *val = props->Equalizer.LowCutoff; + break; + + case AL_EQUALIZER_MID1_GAIN: + *val = props->Equalizer.Mid1Gain; + break; + + case AL_EQUALIZER_MID1_CENTER: + *val = props->Equalizer.Mid1Center; + break; + + case AL_EQUALIZER_MID1_WIDTH: + *val = props->Equalizer.Mid1Width; + break; + + case AL_EQUALIZER_MID2_GAIN: + *val = props->Equalizer.Mid2Gain; + break; + + case AL_EQUALIZER_MID2_CENTER: + *val = props->Equalizer.Mid2Center; + break; + + case AL_EQUALIZER_MID2_WIDTH: + *val = props->Equalizer.Mid2Width; + break; + + case AL_EQUALIZER_HIGH_GAIN: + *val = props->Equalizer.HighGain; + break; + + case AL_EQUALIZER_HIGH_CUTOFF: + *val = props->Equalizer.HighCutoff; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param); + } +} +void ALequalizer_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALequalizer_getParamf(effect, context, param, vals); } + +DEFINE_ALEFFECT_VTABLE(ALequalizer); diff --git a/CMakeLists.txt b/CMakeLists.txt index 79530117..79d28e23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -811,10 +811,10 @@ SET(ALC_OBJS Alc/effects/autowah.c Alc/effects/chorus.c Alc/effects/compressor.c - Alc/effects/dedicated.c - Alc/effects/distortion.c - Alc/effects/echo.c - Alc/effects/equalizer.c + Alc/effects/dedicated.cpp + Alc/effects/distortion.cpp + Alc/effects/echo.cpp + Alc/effects/equalizer.cpp Alc/effects/fshifter.cpp Alc/effects/modulator.cpp Alc/effects/null.cpp -- cgit v1.2.3 From 13478126cb7d41e8f6efebf020fb5a387c303f2d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 07:08:41 -0800 Subject: Convert the remaining effects to C++ --- Alc/effects/autowah.c | 321 -------------------------- Alc/effects/autowah.cpp | 326 ++++++++++++++++++++++++++ Alc/effects/chorus.c | 555 -------------------------------------------- Alc/effects/chorus.cpp | 561 +++++++++++++++++++++++++++++++++++++++++++++ Alc/effects/compressor.c | 243 -------------------- Alc/effects/compressor.cpp | 247 ++++++++++++++++++++ CMakeLists.txt | 6 +- 7 files changed, 1137 insertions(+), 1122 deletions(-) delete mode 100644 Alc/effects/autowah.c create mode 100644 Alc/effects/autowah.cpp delete mode 100644 Alc/effects/chorus.c create mode 100644 Alc/effects/chorus.cpp delete mode 100644 Alc/effects/compressor.c create mode 100644 Alc/effects/compressor.cpp diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c deleted file mode 100644 index f65f1be6..00000000 --- a/Alc/effects/autowah.c +++ /dev/null @@ -1,321 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2018 by Raul Herraiz. - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" -#include "filters/defs.h" - -#define MIN_FREQ 20.0f -#define MAX_FREQ 2500.0f -#define Q_FACTOR 5.0f - -typedef struct ALautowahState { - DERIVE_FROM_TYPE(ALeffectState); - - /* Effect parameters */ - ALfloat AttackRate; - ALfloat ReleaseRate; - ALfloat ResonanceGain; - ALfloat PeakGain; - ALfloat FreqMinNorm; - ALfloat BandwidthNorm; - ALfloat env_delay; - - /* Filter components derived from the envelope. */ - struct { - ALfloat cos_w0; - ALfloat alpha; - } Env[BUFFERSIZE]; - - struct { - /* Effect filters' history. */ - struct { - ALfloat z1, z2; - } Filter; - - /* Effect gains for each output channel */ - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; - } Chans[MAX_EFFECT_CHANNELS]; - - /* Effects buffers */ - alignas(16) ALfloat BufferOut[BUFFERSIZE]; -} ALautowahState; - -static ALvoid ALautowahState_Destruct(ALautowahState *state); -static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *device); -static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALautowahState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALautowahState); - -static void ALautowahState_Construct(ALautowahState *state) -{ - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALautowahState, ALeffectState, state); -} - -static ALvoid ALautowahState_Destruct(ALautowahState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); -} - -static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *UNUSED(device)) -{ - /* (Re-)initializing parameters and clear the buffers. */ - ALsizei i, j; - - state->AttackRate = 1.0f; - state->ReleaseRate = 1.0f; - state->ResonanceGain = 10.0f; - state->PeakGain = 4.5f; - state->FreqMinNorm = 4.5e-4f; - state->BandwidthNorm = 0.05f; - state->env_delay = 0.0f; - - memset(state->Env, 0, sizeof(state->Env)); - - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - { - for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - state->Chans[i].CurrentGains[j] = 0.0f; - state->Chans[i].Filter.z1 = 0.0f; - state->Chans[i].Filter.z2 = 0.0f; - } - - return AL_TRUE; -} - -static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) -{ - const ALCdevice *device = context->Device; - ALfloat ReleaseTime; - ALsizei i; - - ReleaseTime = clampf(props->Autowah.ReleaseTime, 0.001f, 1.0f); - - state->AttackRate = expf(-1.0f / (props->Autowah.AttackTime*device->Frequency)); - state->ReleaseRate = expf(-1.0f / (ReleaseTime*device->Frequency)); - /* 0-20dB Resonance Peak gain */ - state->ResonanceGain = sqrtf(log10f(props->Autowah.Resonance)*10.0f / 3.0f); - state->PeakGain = 1.0f - log10f(props->Autowah.PeakGain/AL_AUTOWAH_MAX_PEAK_GAIN); - state->FreqMinNorm = MIN_FREQ / device->Frequency; - state->BandwidthNorm = (MAX_FREQ-MIN_FREQ) / device->Frequency; - - STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; - STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain, - state->Chans[i].TargetGains); -} - -static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) -{ - const ALfloat attack_rate = state->AttackRate; - const ALfloat release_rate = state->ReleaseRate; - const ALfloat res_gain = state->ResonanceGain; - const ALfloat peak_gain = state->PeakGain; - const ALfloat freq_min = state->FreqMinNorm; - const ALfloat bandwidth = state->BandwidthNorm; - ALfloat env_delay; - ALsizei c, i; - - env_delay = state->env_delay; - for(i = 0;i < SamplesToDo;i++) - { - ALfloat w0, sample, a; - - /* Envelope follower described on the book: Audio Effects, Theory, - * Implementation and Application. - */ - sample = peak_gain * fabsf(SamplesIn[0][i]); - a = (sample > env_delay) ? attack_rate : release_rate; - env_delay = lerp(sample, env_delay, a); - - /* Calculate the cos and alpha components for this sample's filter. */ - w0 = minf((bandwidth*env_delay + freq_min), 0.46f) * F_TAU; - state->Env[i].cos_w0 = cosf(w0); - state->Env[i].alpha = sinf(w0)/(2.0f * Q_FACTOR); - } - state->env_delay = env_delay; - - for(c = 0;c < MAX_EFFECT_CHANNELS; c++) - { - /* This effectively inlines BiquadFilter_setParams for a peaking - * filter and BiquadFilter_processC. The alpha and cosine components - * for the filter coefficients were previously calculated with the - * envelope. Because the filter changes for each sample, the - * coefficients are transient and don't need to be held. - */ - ALfloat z1 = state->Chans[c].Filter.z1; - ALfloat z2 = state->Chans[c].Filter.z2; - - for(i = 0;i < SamplesToDo;i++) - { - const ALfloat alpha = state->Env[i].alpha; - const ALfloat cos_w0 = state->Env[i].cos_w0; - ALfloat input, output; - ALfloat a[3], b[3]; - - b[0] = 1.0f + alpha*res_gain; - b[1] = -2.0f * cos_w0; - b[2] = 1.0f - alpha*res_gain; - a[0] = 1.0f + alpha/res_gain; - a[1] = -2.0f * cos_w0; - a[2] = 1.0f - alpha/res_gain; - - input = SamplesIn[c][i]; - output = input*(b[0]/a[0]) + z1; - z1 = input*(b[1]/a[0]) - output*(a[1]/a[0]) + z2; - z2 = input*(b[2]/a[0]) - output*(a[2]/a[0]); - state->BufferOut[i] = output; - } - state->Chans[c].Filter.z1 = z1; - state->Chans[c].Filter.z2 = z2; - - /* Now, mix the processed sound data to the output. */ - MixSamples(state->BufferOut, NumChannels, SamplesOut, state->Chans[c].CurrentGains, - state->Chans[c].TargetGains, SamplesToDo, 0, SamplesToDo); - } -} - -typedef struct AutowahStateFactory { - DERIVE_FROM_TYPE(EffectStateFactory); -} AutowahStateFactory; - -static ALeffectState *AutowahStateFactory_create(AutowahStateFactory *UNUSED(factory)) -{ - ALautowahState *state; - - NEW_OBJ0(state, ALautowahState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(AutowahStateFactory); - -EffectStateFactory *AutowahStateFactory_getFactory(void) -{ - static AutowahStateFactory AutowahFactory = { { GET_VTABLE2(AutowahStateFactory, EffectStateFactory) } }; - - return STATIC_CAST(EffectStateFactory, &AutowahFactory); -} - -void ALautowah_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_AUTOWAH_ATTACK_TIME: - if(!(val >= AL_AUTOWAH_MIN_ATTACK_TIME && val <= AL_AUTOWAH_MAX_ATTACK_TIME)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Autowah attack time out of range"); - props->Autowah.AttackTime = val; - break; - - case AL_AUTOWAH_RELEASE_TIME: - if(!(val >= AL_AUTOWAH_MIN_RELEASE_TIME && val <= AL_AUTOWAH_MAX_RELEASE_TIME)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Autowah release time out of range"); - props->Autowah.ReleaseTime = val; - break; - - case AL_AUTOWAH_RESONANCE: - if(!(val >= AL_AUTOWAH_MIN_RESONANCE && val <= AL_AUTOWAH_MAX_RESONANCE)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Autowah resonance out of range"); - props->Autowah.Resonance = val; - break; - - case AL_AUTOWAH_PEAK_GAIN: - if(!(val >= AL_AUTOWAH_MIN_PEAK_GAIN && val <= AL_AUTOWAH_MAX_PEAK_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Autowah peak gain out of range"); - props->Autowah.PeakGain = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param); - } -} - -void ALautowah_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - ALautowah_setParamf(effect, context, param, vals[0]); -} - -void ALautowah_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val)) -{ - alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param); -} - -void ALautowah_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) -{ - alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x", param); -} - -void ALautowah_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(val)) -{ - alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param); -} -void ALautowah_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) -{ - alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x", param); -} - -void ALautowah_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_AUTOWAH_ATTACK_TIME: - *val = props->Autowah.AttackTime; - break; - - case AL_AUTOWAH_RELEASE_TIME: - *val = props->Autowah.ReleaseTime; - break; - - case AL_AUTOWAH_RESONANCE: - *val = props->Autowah.Resonance; - break; - - case AL_AUTOWAH_PEAK_GAIN: - *val = props->Autowah.PeakGain; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param); - } - -} - -void ALautowah_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - ALautowah_getParamf(effect, context, param, vals); -} - -DEFINE_ALEFFECT_VTABLE(ALautowah); diff --git a/Alc/effects/autowah.cpp b/Alc/effects/autowah.cpp new file mode 100644 index 00000000..b4ef8f3c --- /dev/null +++ b/Alc/effects/autowah.cpp @@ -0,0 +1,326 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2018 by Raul Herraiz. + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" +#include "filters/defs.h" + +#define MIN_FREQ 20.0f +#define MAX_FREQ 2500.0f +#define Q_FACTOR 5.0f + +struct ALautowahState final : public ALeffectState { + /* Effect parameters */ + ALfloat AttackRate; + ALfloat ReleaseRate; + ALfloat ResonanceGain; + ALfloat PeakGain; + ALfloat FreqMinNorm; + ALfloat BandwidthNorm; + ALfloat env_delay; + + /* Filter components derived from the envelope. */ + struct { + ALfloat cos_w0; + ALfloat alpha; + } Env[BUFFERSIZE]; + + struct { + /* Effect filters' history. */ + struct { + ALfloat z1, z2; + } Filter; + + /* Effect gains for each output channel */ + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; + } Chans[MAX_EFFECT_CHANNELS]; + + /* Effects buffers */ + alignas(16) ALfloat BufferOut[BUFFERSIZE]; +}; + +static ALvoid ALautowahState_Destruct(ALautowahState *state); +static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *device); +static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALautowahState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALautowahState); + +static void ALautowahState_Construct(ALautowahState *state) +{ + new (state) ALautowahState{}; + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALautowahState, ALeffectState, state); +} + +static ALvoid ALautowahState_Destruct(ALautowahState *state) +{ + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); + state->~ALautowahState(); +} + +static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *UNUSED(device)) +{ + /* (Re-)initializing parameters and clear the buffers. */ + ALsizei i, j; + + state->AttackRate = 1.0f; + state->ReleaseRate = 1.0f; + state->ResonanceGain = 10.0f; + state->PeakGain = 4.5f; + state->FreqMinNorm = 4.5e-4f; + state->BandwidthNorm = 0.05f; + state->env_delay = 0.0f; + + memset(state->Env, 0, sizeof(state->Env)); + + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + { + for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) + state->Chans[i].CurrentGains[j] = 0.0f; + state->Chans[i].Filter.z1 = 0.0f; + state->Chans[i].Filter.z2 = 0.0f; + } + + return AL_TRUE; +} + +static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +{ + const ALCdevice *device = context->Device; + ALfloat ReleaseTime; + ALsizei i; + + ReleaseTime = clampf(props->Autowah.ReleaseTime, 0.001f, 1.0f); + + state->AttackRate = expf(-1.0f / (props->Autowah.AttackTime*device->Frequency)); + state->ReleaseRate = expf(-1.0f / (ReleaseTime*device->Frequency)); + /* 0-20dB Resonance Peak gain */ + state->ResonanceGain = sqrtf(log10f(props->Autowah.Resonance)*10.0f / 3.0f); + state->PeakGain = 1.0f - log10f(props->Autowah.PeakGain/AL_AUTOWAH_MAX_PEAK_GAIN); + state->FreqMinNorm = MIN_FREQ / device->Frequency; + state->BandwidthNorm = (MAX_FREQ-MIN_FREQ) / device->Frequency; + + STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; + STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain, + state->Chans[i].TargetGains); +} + +static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +{ + const ALfloat attack_rate = state->AttackRate; + const ALfloat release_rate = state->ReleaseRate; + const ALfloat res_gain = state->ResonanceGain; + const ALfloat peak_gain = state->PeakGain; + const ALfloat freq_min = state->FreqMinNorm; + const ALfloat bandwidth = state->BandwidthNorm; + ALfloat env_delay; + ALsizei c, i; + + env_delay = state->env_delay; + for(i = 0;i < SamplesToDo;i++) + { + ALfloat w0, sample, a; + + /* Envelope follower described on the book: Audio Effects, Theory, + * Implementation and Application. + */ + sample = peak_gain * fabsf(SamplesIn[0][i]); + a = (sample > env_delay) ? attack_rate : release_rate; + env_delay = lerp(sample, env_delay, a); + + /* Calculate the cos and alpha components for this sample's filter. */ + w0 = minf((bandwidth*env_delay + freq_min), 0.46f) * F_TAU; + state->Env[i].cos_w0 = cosf(w0); + state->Env[i].alpha = sinf(w0)/(2.0f * Q_FACTOR); + } + state->env_delay = env_delay; + + for(c = 0;c < MAX_EFFECT_CHANNELS; c++) + { + /* This effectively inlines BiquadFilter_setParams for a peaking + * filter and BiquadFilter_processC. The alpha and cosine components + * for the filter coefficients were previously calculated with the + * envelope. Because the filter changes for each sample, the + * coefficients are transient and don't need to be held. + */ + ALfloat z1 = state->Chans[c].Filter.z1; + ALfloat z2 = state->Chans[c].Filter.z2; + + for(i = 0;i < SamplesToDo;i++) + { + const ALfloat alpha = state->Env[i].alpha; + const ALfloat cos_w0 = state->Env[i].cos_w0; + ALfloat input, output; + ALfloat a[3], b[3]; + + b[0] = 1.0f + alpha*res_gain; + b[1] = -2.0f * cos_w0; + b[2] = 1.0f - alpha*res_gain; + a[0] = 1.0f + alpha/res_gain; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha/res_gain; + + input = SamplesIn[c][i]; + output = input*(b[0]/a[0]) + z1; + z1 = input*(b[1]/a[0]) - output*(a[1]/a[0]) + z2; + z2 = input*(b[2]/a[0]) - output*(a[2]/a[0]); + state->BufferOut[i] = output; + } + state->Chans[c].Filter.z1 = z1; + state->Chans[c].Filter.z2 = z2; + + /* Now, mix the processed sound data to the output. */ + MixSamples(state->BufferOut, NumChannels, SamplesOut, state->Chans[c].CurrentGains, + state->Chans[c].TargetGains, SamplesToDo, 0, SamplesToDo); + } +} + +struct AutowahStateFactory final : public EffectStateFactory { + AutowahStateFactory() noexcept; +}; + +static ALeffectState *AutowahStateFactory_create(AutowahStateFactory *UNUSED(factory)) +{ + ALautowahState *state; + + NEW_OBJ0(state, ALautowahState)(); + if(!state) return NULL; + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_EFFECTSTATEFACTORY_VTABLE(AutowahStateFactory); + +AutowahStateFactory::AutowahStateFactory() noexcept + : EffectStateFactory{GET_VTABLE2(AutowahStateFactory, EffectStateFactory)} +{ +} + +EffectStateFactory *AutowahStateFactory_getFactory(void) +{ + static AutowahStateFactory AutowahFactory{}; + + return STATIC_CAST(EffectStateFactory, &AutowahFactory); +} + +void ALautowah_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_AUTOWAH_ATTACK_TIME: + if(!(val >= AL_AUTOWAH_MIN_ATTACK_TIME && val <= AL_AUTOWAH_MAX_ATTACK_TIME)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Autowah attack time out of range"); + props->Autowah.AttackTime = val; + break; + + case AL_AUTOWAH_RELEASE_TIME: + if(!(val >= AL_AUTOWAH_MIN_RELEASE_TIME && val <= AL_AUTOWAH_MAX_RELEASE_TIME)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Autowah release time out of range"); + props->Autowah.ReleaseTime = val; + break; + + case AL_AUTOWAH_RESONANCE: + if(!(val >= AL_AUTOWAH_MIN_RESONANCE && val <= AL_AUTOWAH_MAX_RESONANCE)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Autowah resonance out of range"); + props->Autowah.Resonance = val; + break; + + case AL_AUTOWAH_PEAK_GAIN: + if(!(val >= AL_AUTOWAH_MIN_PEAK_GAIN && val <= AL_AUTOWAH_MAX_PEAK_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Autowah peak gain out of range"); + props->Autowah.PeakGain = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param); + } +} + +void ALautowah_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + ALautowah_setParamf(effect, context, param, vals[0]); +} + +void ALautowah_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val)) +{ + alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param); +} + +void ALautowah_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +{ + alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x", param); +} + +void ALautowah_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +{ + alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param); +} +void ALautowah_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +{ + alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x", param); +} + +void ALautowah_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_AUTOWAH_ATTACK_TIME: + *val = props->Autowah.AttackTime; + break; + + case AL_AUTOWAH_RELEASE_TIME: + *val = props->Autowah.ReleaseTime; + break; + + case AL_AUTOWAH_RESONANCE: + *val = props->Autowah.Resonance; + break; + + case AL_AUTOWAH_PEAK_GAIN: + *val = props->Autowah.PeakGain; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param); + } + +} + +void ALautowah_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + ALautowah_getParamf(effect, context, param, vals); +} + +DEFINE_ALEFFECT_VTABLE(ALautowah); diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c deleted file mode 100644 index 725189b3..00000000 --- a/Alc/effects/chorus.c +++ /dev/null @@ -1,555 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2013 by Mike Gorchak - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" -#include "filters/defs.h" - - -static_assert(AL_CHORUS_WAVEFORM_SINUSOID == AL_FLANGER_WAVEFORM_SINUSOID, "Chorus/Flanger waveform value mismatch"); -static_assert(AL_CHORUS_WAVEFORM_TRIANGLE == AL_FLANGER_WAVEFORM_TRIANGLE, "Chorus/Flanger waveform value mismatch"); - -enum WaveForm { - WF_Sinusoid, - WF_Triangle -}; - -typedef struct ALchorusState { - DERIVE_FROM_TYPE(ALeffectState); - - ALfloat *SampleBuffer; - ALsizei BufferLength; - ALsizei offset; - - ALsizei lfo_offset; - ALsizei lfo_range; - ALfloat lfo_scale; - ALint lfo_disp; - - /* Gains for left and right sides */ - struct { - ALfloat Current[MAX_OUTPUT_CHANNELS]; - ALfloat Target[MAX_OUTPUT_CHANNELS]; - } Gains[2]; - - /* effect parameters */ - enum WaveForm waveform; - ALint delay; - ALfloat depth; - ALfloat feedback; -} ALchorusState; - -static ALvoid ALchorusState_Destruct(ALchorusState *state); -static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device); -static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props); -static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALchorusState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALchorusState); - - -static void ALchorusState_Construct(ALchorusState *state) -{ - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALchorusState, ALeffectState, state); - - state->BufferLength = 0; - state->SampleBuffer = NULL; - state->offset = 0; - state->lfo_offset = 0; - state->lfo_range = 1; - state->waveform = WF_Triangle; -} - -static ALvoid ALchorusState_Destruct(ALchorusState *state) -{ - al_free(state->SampleBuffer); - state->SampleBuffer = NULL; - - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); -} - -static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device) -{ - const ALfloat max_delay = maxf(AL_CHORUS_MAX_DELAY, AL_FLANGER_MAX_DELAY); - ALsizei maxlen; - - maxlen = NextPowerOf2(float2int(max_delay*2.0f*Device->Frequency) + 1u); - if(maxlen <= 0) return AL_FALSE; - - if(maxlen != state->BufferLength) - { - void *temp = al_calloc(16, maxlen * sizeof(ALfloat)); - if(!temp) return AL_FALSE; - - al_free(state->SampleBuffer); - state->SampleBuffer = temp; - - state->BufferLength = maxlen; - } - - memset(state->SampleBuffer, 0, state->BufferLength*sizeof(ALfloat)); - memset(state->Gains, 0, sizeof(state->Gains)); - - return AL_TRUE; -} - -static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) -{ - const ALsizei mindelay = MAX_RESAMPLE_PADDING << FRACTIONBITS; - const ALCdevice *device = Context->Device; - ALfloat frequency = (ALfloat)device->Frequency; - ALfloat coeffs[MAX_AMBI_COEFFS]; - ALfloat rate; - ALint phase; - - switch(props->Chorus.Waveform) - { - case AL_CHORUS_WAVEFORM_TRIANGLE: - state->waveform = WF_Triangle; - break; - case AL_CHORUS_WAVEFORM_SINUSOID: - state->waveform = WF_Sinusoid; - break; - } - - /* The LFO depth is scaled to be relative to the sample delay. Clamp the - * delay and depth to allow enough padding for resampling. - */ - state->delay = maxi(float2int(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f), - mindelay); - state->depth = minf(props->Chorus.Depth * state->delay, - (ALfloat)(state->delay - mindelay)); - - state->feedback = props->Chorus.Feedback; - - /* Gains for left and right sides */ - CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, state->Gains[0].Target); - CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, state->Gains[1].Target); - - phase = props->Chorus.Phase; - rate = props->Chorus.Rate; - if(!(rate > 0.0f)) - { - state->lfo_offset = 0; - state->lfo_range = 1; - state->lfo_scale = 0.0f; - state->lfo_disp = 0; - } - else - { - /* Calculate LFO coefficient (number of samples per cycle). Limit the - * max range to avoid overflow when calculating the displacement. - */ - ALsizei lfo_range = float2int(minf(frequency/rate + 0.5f, (ALfloat)(INT_MAX/360 - 180))); - - state->lfo_offset = float2int((ALfloat)state->lfo_offset/state->lfo_range* - lfo_range + 0.5f) % lfo_range; - state->lfo_range = lfo_range; - switch(state->waveform) - { - case WF_Triangle: - state->lfo_scale = 4.0f / state->lfo_range; - break; - case WF_Sinusoid: - state->lfo_scale = F_TAU / state->lfo_range; - break; - } - - /* Calculate lfo phase displacement */ - if(phase < 0) phase = 360 + phase; - state->lfo_disp = (state->lfo_range*phase + 180) / 360; - } -} - -static void GetTriangleDelays(ALint *RESTRICT delays, ALsizei offset, const ALsizei lfo_range, - const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, - const ALsizei todo) -{ - ALsizei i; - for(i = 0;i < todo;i++) - { - delays[i] = fastf2i((1.0f - fabsf(2.0f - lfo_scale*offset)) * depth) + delay; - offset = (offset+1)%lfo_range; - } -} - -static void GetSinusoidDelays(ALint *RESTRICT delays, ALsizei offset, const ALsizei lfo_range, - const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, - const ALsizei todo) -{ - ALsizei i; - for(i = 0;i < todo;i++) - { - delays[i] = fastf2i(sinf(lfo_scale*offset) * depth) + delay; - offset = (offset+1)%lfo_range; - } -} - - -static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) -{ - const ALsizei bufmask = state->BufferLength-1; - const ALfloat feedback = state->feedback; - const ALsizei avgdelay = (state->delay + (FRACTIONONE>>1)) >> FRACTIONBITS; - ALfloat *RESTRICT delaybuf = state->SampleBuffer; - ALsizei offset = state->offset; - ALsizei i, c; - ALsizei base; - - for(base = 0;base < SamplesToDo;) - { - const ALsizei todo = mini(256, SamplesToDo-base); - ALint moddelays[2][256]; - alignas(16) ALfloat temps[2][256]; - - if(state->waveform == WF_Sinusoid) - { - GetSinusoidDelays(moddelays[0], state->lfo_offset, state->lfo_range, state->lfo_scale, - state->depth, state->delay, todo); - GetSinusoidDelays(moddelays[1], (state->lfo_offset+state->lfo_disp)%state->lfo_range, - state->lfo_range, state->lfo_scale, state->depth, state->delay, - todo); - } - else /*if(state->waveform == WF_Triangle)*/ - { - GetTriangleDelays(moddelays[0], state->lfo_offset, state->lfo_range, state->lfo_scale, - state->depth, state->delay, todo); - GetTriangleDelays(moddelays[1], (state->lfo_offset+state->lfo_disp)%state->lfo_range, - state->lfo_range, state->lfo_scale, state->depth, state->delay, - todo); - } - state->lfo_offset = (state->lfo_offset+todo) % state->lfo_range; - - for(i = 0;i < todo;i++) - { - ALint delay; - ALfloat mu; - - // Feed the buffer's input first (necessary for delays < 1). - delaybuf[offset&bufmask] = SamplesIn[0][base+i]; - - // Tap for the left output. - delay = offset - (moddelays[0][i]>>FRACTIONBITS); - mu = (moddelays[0][i]&FRACTIONMASK) * (1.0f/FRACTIONONE); - temps[0][i] = cubic(delaybuf[(delay+1) & bufmask], delaybuf[(delay ) & bufmask], - delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask], - mu); - - // Tap for the right output. - delay = offset - (moddelays[1][i]>>FRACTIONBITS); - mu = (moddelays[1][i]&FRACTIONMASK) * (1.0f/FRACTIONONE); - temps[1][i] = cubic(delaybuf[(delay+1) & bufmask], delaybuf[(delay ) & bufmask], - delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask], - mu); - - // Accumulate feedback from the average delay of the taps. - delaybuf[offset&bufmask] += delaybuf[(offset-avgdelay) & bufmask] * feedback; - offset++; - } - - for(c = 0;c < 2;c++) - MixSamples(temps[c], NumChannels, SamplesOut, state->Gains[c].Current, - state->Gains[c].Target, SamplesToDo-base, base, todo); - - base += todo; - } - - state->offset = offset; -} - - -typedef struct ChorusStateFactory { - DERIVE_FROM_TYPE(EffectStateFactory); -} ChorusStateFactory; - -static ALeffectState *ChorusStateFactory_create(ChorusStateFactory *UNUSED(factory)) -{ - ALchorusState *state; - - NEW_OBJ0(state, ALchorusState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(ChorusStateFactory); - - -EffectStateFactory *ChorusStateFactory_getFactory(void) -{ - static ChorusStateFactory ChorusFactory = { { GET_VTABLE2(ChorusStateFactory, EffectStateFactory) } }; - - return STATIC_CAST(EffectStateFactory, &ChorusFactory); -} - - -void ALchorus_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_CHORUS_WAVEFORM: - if(!(val >= AL_CHORUS_MIN_WAVEFORM && val <= AL_CHORUS_MAX_WAVEFORM)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid chorus waveform"); - props->Chorus.Waveform = val; - break; - - case AL_CHORUS_PHASE: - if(!(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus phase out of range"); - props->Chorus.Phase = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param); - } -} -void ALchorus_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ ALchorus_setParami(effect, context, param, vals[0]); } -void ALchorus_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_CHORUS_RATE: - if(!(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus rate out of range"); - props->Chorus.Rate = val; - break; - - case AL_CHORUS_DEPTH: - if(!(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus depth out of range"); - props->Chorus.Depth = val; - break; - - case AL_CHORUS_FEEDBACK: - if(!(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus feedback out of range"); - props->Chorus.Feedback = val; - break; - - case AL_CHORUS_DELAY: - if(!(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus delay out of range"); - props->Chorus.Delay = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param); - } -} -void ALchorus_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ ALchorus_setParamf(effect, context, param, vals[0]); } - -void ALchorus_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_CHORUS_WAVEFORM: - *val = props->Chorus.Waveform; - break; - - case AL_CHORUS_PHASE: - *val = props->Chorus.Phase; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param); - } -} -void ALchorus_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ ALchorus_getParami(effect, context, param, vals); } -void ALchorus_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_CHORUS_RATE: - *val = props->Chorus.Rate; - break; - - case AL_CHORUS_DEPTH: - *val = props->Chorus.Depth; - break; - - case AL_CHORUS_FEEDBACK: - *val = props->Chorus.Feedback; - break; - - case AL_CHORUS_DELAY: - *val = props->Chorus.Delay; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param); - } -} -void ALchorus_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ ALchorus_getParamf(effect, context, param, vals); } - -DEFINE_ALEFFECT_VTABLE(ALchorus); - - -/* Flanger is basically a chorus with a really short delay. They can both use - * the same processing functions, so piggyback flanger on the chorus functions. - */ -typedef struct FlangerStateFactory { - DERIVE_FROM_TYPE(EffectStateFactory); -} FlangerStateFactory; - -ALeffectState *FlangerStateFactory_create(FlangerStateFactory *UNUSED(factory)) -{ - ALchorusState *state; - - NEW_OBJ0(state, ALchorusState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(FlangerStateFactory); - -EffectStateFactory *FlangerStateFactory_getFactory(void) -{ - static FlangerStateFactory FlangerFactory = { { GET_VTABLE2(FlangerStateFactory, EffectStateFactory) } }; - - return STATIC_CAST(EffectStateFactory, &FlangerFactory); -} - - -void ALflanger_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_FLANGER_WAVEFORM: - if(!(val >= AL_FLANGER_MIN_WAVEFORM && val <= AL_FLANGER_MAX_WAVEFORM)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid flanger waveform"); - props->Chorus.Waveform = val; - break; - - case AL_FLANGER_PHASE: - if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger phase out of range"); - props->Chorus.Phase = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param); - } -} -void ALflanger_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ ALflanger_setParami(effect, context, param, vals[0]); } -void ALflanger_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_FLANGER_RATE: - if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger rate out of range"); - props->Chorus.Rate = val; - break; - - case AL_FLANGER_DEPTH: - if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger depth out of range"); - props->Chorus.Depth = val; - break; - - case AL_FLANGER_FEEDBACK: - if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger feedback out of range"); - props->Chorus.Feedback = val; - break; - - case AL_FLANGER_DELAY: - if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger delay out of range"); - props->Chorus.Delay = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param); - } -} -void ALflanger_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ ALflanger_setParamf(effect, context, param, vals[0]); } - -void ALflanger_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_FLANGER_WAVEFORM: - *val = props->Chorus.Waveform; - break; - - case AL_FLANGER_PHASE: - *val = props->Chorus.Phase; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param); - } -} -void ALflanger_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ ALflanger_getParami(effect, context, param, vals); } -void ALflanger_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_FLANGER_RATE: - *val = props->Chorus.Rate; - break; - - case AL_FLANGER_DEPTH: - *val = props->Chorus.Depth; - break; - - case AL_FLANGER_FEEDBACK: - *val = props->Chorus.Feedback; - break; - - case AL_FLANGER_DELAY: - *val = props->Chorus.Delay; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param); - } -} -void ALflanger_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ ALflanger_getParamf(effect, context, param, vals); } - -DEFINE_ALEFFECT_VTABLE(ALflanger); diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp new file mode 100644 index 00000000..b658098e --- /dev/null +++ b/Alc/effects/chorus.cpp @@ -0,0 +1,561 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2013 by Mike Gorchak + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" +#include "filters/defs.h" + + +static_assert(AL_CHORUS_WAVEFORM_SINUSOID == AL_FLANGER_WAVEFORM_SINUSOID, "Chorus/Flanger waveform value mismatch"); +static_assert(AL_CHORUS_WAVEFORM_TRIANGLE == AL_FLANGER_WAVEFORM_TRIANGLE, "Chorus/Flanger waveform value mismatch"); + +enum WaveForm { + WF_Sinusoid, + WF_Triangle +}; + +struct ALchorusState final : public ALeffectState { + ALfloat *SampleBuffer; + ALsizei BufferLength; + ALsizei offset; + + ALsizei lfo_offset; + ALsizei lfo_range; + ALfloat lfo_scale; + ALint lfo_disp; + + /* Gains for left and right sides */ + struct { + ALfloat Current[MAX_OUTPUT_CHANNELS]; + ALfloat Target[MAX_OUTPUT_CHANNELS]; + } Gains[2]; + + /* effect parameters */ + enum WaveForm waveform; + ALint delay; + ALfloat depth; + ALfloat feedback; +}; + +static ALvoid ALchorusState_Destruct(ALchorusState *state); +static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device); +static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props); +static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALchorusState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALchorusState); + + +static void ALchorusState_Construct(ALchorusState *state) +{ + new (state) ALchorusState{}; + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALchorusState, ALeffectState, state); + + state->BufferLength = 0; + state->SampleBuffer = NULL; + state->offset = 0; + state->lfo_offset = 0; + state->lfo_range = 1; + state->waveform = WF_Triangle; +} + +static ALvoid ALchorusState_Destruct(ALchorusState *state) +{ + al_free(state->SampleBuffer); + state->SampleBuffer = NULL; + + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); + state->~ALchorusState(); +} + +static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device) +{ + const ALfloat max_delay = maxf(AL_CHORUS_MAX_DELAY, AL_FLANGER_MAX_DELAY); + ALsizei maxlen; + + maxlen = NextPowerOf2(float2int(max_delay*2.0f*Device->Frequency) + 1u); + if(maxlen <= 0) return AL_FALSE; + + if(maxlen != state->BufferLength) + { + void *temp = al_calloc(16, maxlen * sizeof(ALfloat)); + if(!temp) return AL_FALSE; + + al_free(state->SampleBuffer); + state->SampleBuffer = static_cast(temp); + state->BufferLength = maxlen; + } + + memset(state->SampleBuffer, 0, state->BufferLength*sizeof(ALfloat)); + memset(state->Gains, 0, sizeof(state->Gains)); + + return AL_TRUE; +} + +static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) +{ + const ALsizei mindelay = MAX_RESAMPLE_PADDING << FRACTIONBITS; + const ALCdevice *device = Context->Device; + ALfloat frequency = (ALfloat)device->Frequency; + ALfloat coeffs[MAX_AMBI_COEFFS]; + ALfloat rate; + ALint phase; + + switch(props->Chorus.Waveform) + { + case AL_CHORUS_WAVEFORM_TRIANGLE: + state->waveform = WF_Triangle; + break; + case AL_CHORUS_WAVEFORM_SINUSOID: + state->waveform = WF_Sinusoid; + break; + } + + /* The LFO depth is scaled to be relative to the sample delay. Clamp the + * delay and depth to allow enough padding for resampling. + */ + state->delay = maxi(float2int(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f), + mindelay); + state->depth = minf(props->Chorus.Depth * state->delay, + (ALfloat)(state->delay - mindelay)); + + state->feedback = props->Chorus.Feedback; + + /* Gains for left and right sides */ + CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs); + ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, state->Gains[0].Target); + CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs); + ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, state->Gains[1].Target); + + phase = props->Chorus.Phase; + rate = props->Chorus.Rate; + if(!(rate > 0.0f)) + { + state->lfo_offset = 0; + state->lfo_range = 1; + state->lfo_scale = 0.0f; + state->lfo_disp = 0; + } + else + { + /* Calculate LFO coefficient (number of samples per cycle). Limit the + * max range to avoid overflow when calculating the displacement. + */ + ALsizei lfo_range = float2int(minf(frequency/rate + 0.5f, (ALfloat)(INT_MAX/360 - 180))); + + state->lfo_offset = float2int((ALfloat)state->lfo_offset/state->lfo_range* + lfo_range + 0.5f) % lfo_range; + state->lfo_range = lfo_range; + switch(state->waveform) + { + case WF_Triangle: + state->lfo_scale = 4.0f / state->lfo_range; + break; + case WF_Sinusoid: + state->lfo_scale = F_TAU / state->lfo_range; + break; + } + + /* Calculate lfo phase displacement */ + if(phase < 0) phase = 360 + phase; + state->lfo_disp = (state->lfo_range*phase + 180) / 360; + } +} + +static void GetTriangleDelays(ALint *RESTRICT delays, ALsizei offset, const ALsizei lfo_range, + const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, + const ALsizei todo) +{ + ALsizei i; + for(i = 0;i < todo;i++) + { + delays[i] = fastf2i((1.0f - fabsf(2.0f - lfo_scale*offset)) * depth) + delay; + offset = (offset+1)%lfo_range; + } +} + +static void GetSinusoidDelays(ALint *RESTRICT delays, ALsizei offset, const ALsizei lfo_range, + const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, + const ALsizei todo) +{ + ALsizei i; + for(i = 0;i < todo;i++) + { + delays[i] = fastf2i(sinf(lfo_scale*offset) * depth) + delay; + offset = (offset+1)%lfo_range; + } +} + + +static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +{ + const ALsizei bufmask = state->BufferLength-1; + const ALfloat feedback = state->feedback; + const ALsizei avgdelay = (state->delay + (FRACTIONONE>>1)) >> FRACTIONBITS; + ALfloat *RESTRICT delaybuf = state->SampleBuffer; + ALsizei offset = state->offset; + ALsizei i, c; + ALsizei base; + + for(base = 0;base < SamplesToDo;) + { + const ALsizei todo = mini(256, SamplesToDo-base); + ALint moddelays[2][256]; + alignas(16) ALfloat temps[2][256]; + + if(state->waveform == WF_Sinusoid) + { + GetSinusoidDelays(moddelays[0], state->lfo_offset, state->lfo_range, state->lfo_scale, + state->depth, state->delay, todo); + GetSinusoidDelays(moddelays[1], (state->lfo_offset+state->lfo_disp)%state->lfo_range, + state->lfo_range, state->lfo_scale, state->depth, state->delay, + todo); + } + else /*if(state->waveform == WF_Triangle)*/ + { + GetTriangleDelays(moddelays[0], state->lfo_offset, state->lfo_range, state->lfo_scale, + state->depth, state->delay, todo); + GetTriangleDelays(moddelays[1], (state->lfo_offset+state->lfo_disp)%state->lfo_range, + state->lfo_range, state->lfo_scale, state->depth, state->delay, + todo); + } + state->lfo_offset = (state->lfo_offset+todo) % state->lfo_range; + + for(i = 0;i < todo;i++) + { + ALint delay; + ALfloat mu; + + // Feed the buffer's input first (necessary for delays < 1). + delaybuf[offset&bufmask] = SamplesIn[0][base+i]; + + // Tap for the left output. + delay = offset - (moddelays[0][i]>>FRACTIONBITS); + mu = (moddelays[0][i]&FRACTIONMASK) * (1.0f/FRACTIONONE); + temps[0][i] = cubic(delaybuf[(delay+1) & bufmask], delaybuf[(delay ) & bufmask], + delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask], + mu); + + // Tap for the right output. + delay = offset - (moddelays[1][i]>>FRACTIONBITS); + mu = (moddelays[1][i]&FRACTIONMASK) * (1.0f/FRACTIONONE); + temps[1][i] = cubic(delaybuf[(delay+1) & bufmask], delaybuf[(delay ) & bufmask], + delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask], + mu); + + // Accumulate feedback from the average delay of the taps. + delaybuf[offset&bufmask] += delaybuf[(offset-avgdelay) & bufmask] * feedback; + offset++; + } + + for(c = 0;c < 2;c++) + MixSamples(temps[c], NumChannels, SamplesOut, state->Gains[c].Current, + state->Gains[c].Target, SamplesToDo-base, base, todo); + + base += todo; + } + + state->offset = offset; +} + + +struct ChorusStateFactory final : public EffectStateFactory { + ChorusStateFactory() noexcept; +}; + +static ALeffectState *ChorusStateFactory_create(ChorusStateFactory *UNUSED(factory)) +{ + ALchorusState *state; + + NEW_OBJ0(state, ALchorusState)(); + if(!state) return NULL; + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_EFFECTSTATEFACTORY_VTABLE(ChorusStateFactory); + +ChorusStateFactory::ChorusStateFactory() noexcept + : EffectStateFactory{GET_VTABLE2(ChorusStateFactory, EffectStateFactory)} +{ +} + +EffectStateFactory *ChorusStateFactory_getFactory(void) +{ + static ChorusStateFactory ChorusFactory{}; + return STATIC_CAST(EffectStateFactory, &ChorusFactory); +} + + +void ALchorus_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_CHORUS_WAVEFORM: + if(!(val >= AL_CHORUS_MIN_WAVEFORM && val <= AL_CHORUS_MAX_WAVEFORM)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid chorus waveform"); + props->Chorus.Waveform = val; + break; + + case AL_CHORUS_PHASE: + if(!(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus phase out of range"); + props->Chorus.Phase = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param); + } +} +void ALchorus_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ ALchorus_setParami(effect, context, param, vals[0]); } +void ALchorus_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_CHORUS_RATE: + if(!(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus rate out of range"); + props->Chorus.Rate = val; + break; + + case AL_CHORUS_DEPTH: + if(!(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus depth out of range"); + props->Chorus.Depth = val; + break; + + case AL_CHORUS_FEEDBACK: + if(!(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus feedback out of range"); + props->Chorus.Feedback = val; + break; + + case AL_CHORUS_DELAY: + if(!(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus delay out of range"); + props->Chorus.Delay = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param); + } +} +void ALchorus_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALchorus_setParamf(effect, context, param, vals[0]); } + +void ALchorus_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_CHORUS_WAVEFORM: + *val = props->Chorus.Waveform; + break; + + case AL_CHORUS_PHASE: + *val = props->Chorus.Phase; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param); + } +} +void ALchorus_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ ALchorus_getParami(effect, context, param, vals); } +void ALchorus_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_CHORUS_RATE: + *val = props->Chorus.Rate; + break; + + case AL_CHORUS_DEPTH: + *val = props->Chorus.Depth; + break; + + case AL_CHORUS_FEEDBACK: + *val = props->Chorus.Feedback; + break; + + case AL_CHORUS_DELAY: + *val = props->Chorus.Delay; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param); + } +} +void ALchorus_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALchorus_getParamf(effect, context, param, vals); } + +DEFINE_ALEFFECT_VTABLE(ALchorus); + + +/* Flanger is basically a chorus with a really short delay. They can both use + * the same processing functions, so piggyback flanger on the chorus functions. + */ +struct FlangerStateFactory final : public EffectStateFactory { + FlangerStateFactory() noexcept; +}; + +ALeffectState *FlangerStateFactory_create(FlangerStateFactory *UNUSED(factory)) +{ + ALchorusState *state; + + NEW_OBJ0(state, ALchorusState)(); + if(!state) return NULL; + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_EFFECTSTATEFACTORY_VTABLE(FlangerStateFactory); + +FlangerStateFactory::FlangerStateFactory() noexcept + : EffectStateFactory{GET_VTABLE2(FlangerStateFactory, EffectStateFactory)} +{ +} + +EffectStateFactory *FlangerStateFactory_getFactory(void) +{ + static FlangerStateFactory FlangerFactory{}; + return STATIC_CAST(EffectStateFactory, &FlangerFactory); +} + + +void ALflanger_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FLANGER_WAVEFORM: + if(!(val >= AL_FLANGER_MIN_WAVEFORM && val <= AL_FLANGER_MAX_WAVEFORM)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid flanger waveform"); + props->Chorus.Waveform = val; + break; + + case AL_FLANGER_PHASE: + if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger phase out of range"); + props->Chorus.Phase = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param); + } +} +void ALflanger_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ ALflanger_setParami(effect, context, param, vals[0]); } +void ALflanger_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FLANGER_RATE: + if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger rate out of range"); + props->Chorus.Rate = val; + break; + + case AL_FLANGER_DEPTH: + if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger depth out of range"); + props->Chorus.Depth = val; + break; + + case AL_FLANGER_FEEDBACK: + if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger feedback out of range"); + props->Chorus.Feedback = val; + break; + + case AL_FLANGER_DELAY: + if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger delay out of range"); + props->Chorus.Delay = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param); + } +} +void ALflanger_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALflanger_setParamf(effect, context, param, vals[0]); } + +void ALflanger_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FLANGER_WAVEFORM: + *val = props->Chorus.Waveform; + break; + + case AL_FLANGER_PHASE: + *val = props->Chorus.Phase; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param); + } +} +void ALflanger_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ ALflanger_getParami(effect, context, param, vals); } +void ALflanger_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FLANGER_RATE: + *val = props->Chorus.Rate; + break; + + case AL_FLANGER_DEPTH: + *val = props->Chorus.Depth; + break; + + case AL_FLANGER_FEEDBACK: + *val = props->Chorus.Feedback; + break; + + case AL_FLANGER_DELAY: + *val = props->Chorus.Delay; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param); + } +} +void ALflanger_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALflanger_getParamf(effect, context, param, vals); } + +DEFINE_ALEFFECT_VTABLE(ALflanger); diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c deleted file mode 100644 index d9b9f1e0..00000000 --- a/Alc/effects/compressor.c +++ /dev/null @@ -1,243 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2013 by Anis A. Hireche - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include - -#include "config.h" -#include "alError.h" -#include "alMain.h" -#include "alAuxEffectSlot.h" -#include "alu.h" - - -#define AMP_ENVELOPE_MIN 0.5f -#define AMP_ENVELOPE_MAX 2.0f - -#define ATTACK_TIME 0.1f /* 100ms to rise from min to max */ -#define RELEASE_TIME 0.2f /* 200ms to drop from max to min */ - - -typedef struct ALcompressorState { - DERIVE_FROM_TYPE(ALeffectState); - - /* Effect gains for each channel */ - ALfloat Gain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS]; - - /* Effect parameters */ - ALboolean Enabled; - ALfloat AttackMult; - ALfloat ReleaseMult; - ALfloat EnvFollower; -} ALcompressorState; - -static ALvoid ALcompressorState_Destruct(ALcompressorState *state); -static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device); -static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALcompressorState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALcompressorState); - - -static void ALcompressorState_Construct(ALcompressorState *state) -{ - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALcompressorState, ALeffectState, state); - - state->Enabled = AL_TRUE; - state->AttackMult = 1.0f; - state->ReleaseMult = 1.0f; - state->EnvFollower = 1.0f; -} - -static ALvoid ALcompressorState_Destruct(ALcompressorState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); -} - -static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device) -{ - /* Number of samples to do a full attack and release (non-integer sample - * counts are okay). - */ - const ALfloat attackCount = (ALfloat)device->Frequency * ATTACK_TIME; - const ALfloat releaseCount = (ALfloat)device->Frequency * RELEASE_TIME; - - /* Calculate per-sample multipliers to attack and release at the desired - * rates. - */ - state->AttackMult = powf(AMP_ENVELOPE_MAX/AMP_ENVELOPE_MIN, 1.0f/attackCount); - state->ReleaseMult = powf(AMP_ENVELOPE_MIN/AMP_ENVELOPE_MAX, 1.0f/releaseCount); - - return AL_TRUE; -} - -static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) -{ - const ALCdevice *device = context->Device; - ALuint i; - - state->Enabled = props->Compressor.OnOff; - - STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; - STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; - for(i = 0;i < 4;i++) - ComputePanGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain, state->Gain[i]); -} - -static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) -{ - ALsizei i, j, k; - ALsizei base; - - for(base = 0;base < SamplesToDo;) - { - ALfloat gains[256]; - ALsizei td = mini(256, SamplesToDo-base); - ALfloat env = state->EnvFollower; - - /* Generate the per-sample gains from the signal envelope. */ - if(state->Enabled) - { - for(i = 0;i < td;++i) - { - /* Clamp the absolute amplitude to the defined envelope limits, - * then attack or release the envelope to reach it. - */ - ALfloat amplitude = clampf(fabsf(SamplesIn[0][base+i]), - AMP_ENVELOPE_MIN, AMP_ENVELOPE_MAX); - if(amplitude > env) - env = minf(env*state->AttackMult, amplitude); - else if(amplitude < env) - env = maxf(env*state->ReleaseMult, amplitude); - - /* Apply the reciprocal of the envelope to normalize the volume - * (compress the dynamic range). - */ - gains[i] = 1.0f / env; - } - } - else - { - /* Same as above, except the amplitude is forced to 1. This helps - * ensure smooth gain changes when the compressor is turned on and - * off. - */ - for(i = 0;i < td;++i) - { - ALfloat amplitude = 1.0f; - if(amplitude > env) - env = minf(env*state->AttackMult, amplitude); - else if(amplitude < env) - env = maxf(env*state->ReleaseMult, amplitude); - - gains[i] = 1.0f / env; - } - } - state->EnvFollower = env; - - /* Now compress the signal amplitude to output. */ - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - { - for(k = 0;k < NumChannels;k++) - { - ALfloat gain = state->Gain[j][k]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - for(i = 0;i < td;i++) - SamplesOut[k][base+i] += SamplesIn[j][base+i] * gains[i] * gain; - } - } - - base += td; - } -} - - -typedef struct CompressorStateFactory { - DERIVE_FROM_TYPE(EffectStateFactory); -} CompressorStateFactory; - -static ALeffectState *CompressorStateFactory_create(CompressorStateFactory *UNUSED(factory)) -{ - ALcompressorState *state; - - NEW_OBJ0(state, ALcompressorState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(CompressorStateFactory); - -EffectStateFactory *CompressorStateFactory_getFactory(void) -{ - static CompressorStateFactory CompressorFactory = { { GET_VTABLE2(CompressorStateFactory, EffectStateFactory) } }; - - return STATIC_CAST(EffectStateFactory, &CompressorFactory); -} - - -void ALcompressor_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_COMPRESSOR_ONOFF: - if(!(val >= AL_COMPRESSOR_MIN_ONOFF && val <= AL_COMPRESSOR_MAX_ONOFF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Compressor state out of range"); - props->Compressor.OnOff = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid compressor integer property 0x%04x", - param); - } -} -void ALcompressor_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ ALcompressor_setParami(effect, context, param, vals[0]); } -void ALcompressor_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param); } -void ALcompressor_setParamfv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALfloat *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float-vector property 0x%04x", param); } - -void ALcompressor_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_COMPRESSOR_ONOFF: - *val = props->Compressor.OnOff; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid compressor integer property 0x%04x", - param); - } -} -void ALcompressor_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ ALcompressor_getParami(effect, context, param, vals); } -void ALcompressor_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat *UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param); } -void ALcompressor_getParamfv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float-vector property 0x%04x", param); } - -DEFINE_ALEFFECT_VTABLE(ALcompressor); diff --git a/Alc/effects/compressor.cpp b/Alc/effects/compressor.cpp new file mode 100644 index 00000000..0a307a5f --- /dev/null +++ b/Alc/effects/compressor.cpp @@ -0,0 +1,247 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2013 by Anis A. Hireche + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include + +#include "config.h" +#include "alError.h" +#include "alMain.h" +#include "alAuxEffectSlot.h" +#include "alu.h" + + +#define AMP_ENVELOPE_MIN 0.5f +#define AMP_ENVELOPE_MAX 2.0f + +#define ATTACK_TIME 0.1f /* 100ms to rise from min to max */ +#define RELEASE_TIME 0.2f /* 200ms to drop from max to min */ + + +struct ALcompressorState final : public ALeffectState { + /* Effect gains for each channel */ + ALfloat Gain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS]; + + /* Effect parameters */ + ALboolean Enabled; + ALfloat AttackMult; + ALfloat ReleaseMult; + ALfloat EnvFollower; +}; + +static ALvoid ALcompressorState_Destruct(ALcompressorState *state); +static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device); +static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALcompressorState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALcompressorState); + + +static void ALcompressorState_Construct(ALcompressorState *state) +{ + new (state) ALcompressorState{}; + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALcompressorState, ALeffectState, state); + + state->Enabled = AL_TRUE; + state->AttackMult = 1.0f; + state->ReleaseMult = 1.0f; + state->EnvFollower = 1.0f; +} + +static ALvoid ALcompressorState_Destruct(ALcompressorState *state) +{ + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); + state->~ALcompressorState(); +} + +static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device) +{ + /* Number of samples to do a full attack and release (non-integer sample + * counts are okay). + */ + const ALfloat attackCount = (ALfloat)device->Frequency * ATTACK_TIME; + const ALfloat releaseCount = (ALfloat)device->Frequency * RELEASE_TIME; + + /* Calculate per-sample multipliers to attack and release at the desired + * rates. + */ + state->AttackMult = powf(AMP_ENVELOPE_MAX/AMP_ENVELOPE_MIN, 1.0f/attackCount); + state->ReleaseMult = powf(AMP_ENVELOPE_MIN/AMP_ENVELOPE_MAX, 1.0f/releaseCount); + + return AL_TRUE; +} + +static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +{ + const ALCdevice *device = context->Device; + ALuint i; + + state->Enabled = props->Compressor.OnOff; + + STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; + STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; + for(i = 0;i < 4;i++) + ComputePanGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain, state->Gain[i]); +} + +static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +{ + ALsizei i, j, k; + ALsizei base; + + for(base = 0;base < SamplesToDo;) + { + ALfloat gains[256]; + ALsizei td = mini(256, SamplesToDo-base); + ALfloat env = state->EnvFollower; + + /* Generate the per-sample gains from the signal envelope. */ + if(state->Enabled) + { + for(i = 0;i < td;++i) + { + /* Clamp the absolute amplitude to the defined envelope limits, + * then attack or release the envelope to reach it. + */ + ALfloat amplitude = clampf(fabsf(SamplesIn[0][base+i]), + AMP_ENVELOPE_MIN, AMP_ENVELOPE_MAX); + if(amplitude > env) + env = minf(env*state->AttackMult, amplitude); + else if(amplitude < env) + env = maxf(env*state->ReleaseMult, amplitude); + + /* Apply the reciprocal of the envelope to normalize the volume + * (compress the dynamic range). + */ + gains[i] = 1.0f / env; + } + } + else + { + /* Same as above, except the amplitude is forced to 1. This helps + * ensure smooth gain changes when the compressor is turned on and + * off. + */ + for(i = 0;i < td;++i) + { + ALfloat amplitude = 1.0f; + if(amplitude > env) + env = minf(env*state->AttackMult, amplitude); + else if(amplitude < env) + env = maxf(env*state->ReleaseMult, amplitude); + + gains[i] = 1.0f / env; + } + } + state->EnvFollower = env; + + /* Now compress the signal amplitude to output. */ + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + { + for(k = 0;k < NumChannels;k++) + { + ALfloat gain = state->Gain[j][k]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + for(i = 0;i < td;i++) + SamplesOut[k][base+i] += SamplesIn[j][base+i] * gains[i] * gain; + } + } + + base += td; + } +} + + +struct CompressorStateFactory final : public EffectStateFactory { + CompressorStateFactory() noexcept; +}; + +static ALeffectState *CompressorStateFactory_create(CompressorStateFactory *UNUSED(factory)) +{ + ALcompressorState *state; + + NEW_OBJ0(state, ALcompressorState)(); + if(!state) return NULL; + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_EFFECTSTATEFACTORY_VTABLE(CompressorStateFactory); + +CompressorStateFactory::CompressorStateFactory() noexcept + : EffectStateFactory{GET_VTABLE2(CompressorStateFactory, EffectStateFactory)} +{ +} + +EffectStateFactory *CompressorStateFactory_getFactory(void) +{ + static CompressorStateFactory CompressorFactory{}; + return STATIC_CAST(EffectStateFactory, &CompressorFactory); +} + + +void ALcompressor_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_COMPRESSOR_ONOFF: + if(!(val >= AL_COMPRESSOR_MIN_ONOFF && val <= AL_COMPRESSOR_MAX_ONOFF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Compressor state out of range"); + props->Compressor.OnOff = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid compressor integer property 0x%04x", + param); + } +} +void ALcompressor_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ ALcompressor_setParami(effect, context, param, vals[0]); } +void ALcompressor_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param); } +void ALcompressor_setParamfv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALfloat *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float-vector property 0x%04x", param); } + +void ALcompressor_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_COMPRESSOR_ONOFF: + *val = props->Compressor.OnOff; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid compressor integer property 0x%04x", + param); + } +} +void ALcompressor_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ ALcompressor_getParami(effect, context, param, vals); } +void ALcompressor_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param); } +void ALcompressor_getParamfv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float-vector property 0x%04x", param); } + +DEFINE_ALEFFECT_VTABLE(ALcompressor); diff --git a/CMakeLists.txt b/CMakeLists.txt index 79d28e23..64a40d95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -808,9 +808,9 @@ SET(ALC_OBJS Alc/mastering.h Alc/ringbuffer.c Alc/ringbuffer.h - Alc/effects/autowah.c - Alc/effects/chorus.c - Alc/effects/compressor.c + Alc/effects/autowah.cpp + Alc/effects/chorus.cpp + Alc/effects/compressor.cpp Alc/effects/dedicated.cpp Alc/effects/distortion.cpp Alc/effects/echo.cpp -- cgit v1.2.3 From 6e6a0240580c3a474a199be45ba0748add860d3b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 07:35:11 -0800 Subject: Convert converter.c to C++ --- Alc/converter.c | 468 ----------------------------------------------------- Alc/converter.cpp | 469 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ Alc/converter.h | 16 +- CMakeLists.txt | 2 +- 4 files changed, 474 insertions(+), 481 deletions(-) delete mode 100644 Alc/converter.c create mode 100644 Alc/converter.cpp diff --git a/Alc/converter.c b/Alc/converter.c deleted file mode 100644 index 5080f302..00000000 --- a/Alc/converter.c +++ /dev/null @@ -1,468 +0,0 @@ - -#include "config.h" - -#include "converter.h" - -#include "fpu_modes.h" -#include "mixer/defs.h" - - -SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, ALsizei numchans, ALsizei srcRate, ALsizei dstRate) -{ - SampleConverter *converter; - ALsizei step; - - if(numchans <= 0 || srcRate <= 0 || dstRate <= 0) - return NULL; - - converter = al_calloc(16, FAM_SIZE(SampleConverter, Chan, numchans)); - converter->mSrcType = srcType; - converter->mDstType = dstType; - converter->mNumChannels = numchans; - converter->mSrcTypeSize = BytesFromDevFmt(srcType); - converter->mDstTypeSize = BytesFromDevFmt(dstType); - - converter->mSrcPrepCount = 0; - converter->mFracOffset = 0; - - /* Have to set the mixer FPU mode since that's what the resampler code expects. */ - START_MIXER_MODE(); - step = (ALsizei)mind(((ALdouble)srcRate/dstRate*FRACTIONONE) + 0.5, - MAX_PITCH * FRACTIONONE); - converter->mIncrement = maxi(step, 1); - if(converter->mIncrement == FRACTIONONE) - converter->mResample = Resample_copy_C; - else - { - /* TODO: Allow other resamplers. */ - BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc12); - converter->mResample = SelectResampler(BSinc12Resampler); - } - END_MIXER_MODE(); - - return converter; -} - -void DestroySampleConverter(SampleConverter **converter) -{ - if(converter) - { - al_free(*converter); - *converter = NULL; - } -} - - -static inline ALfloat Sample_ALbyte(ALbyte val) -{ return val * (1.0f/128.0f); } -static inline ALfloat Sample_ALubyte(ALubyte val) -{ return Sample_ALbyte((ALint)val - 128); } - -static inline ALfloat Sample_ALshort(ALshort val) -{ return val * (1.0f/32768.0f); } -static inline ALfloat Sample_ALushort(ALushort val) -{ return Sample_ALshort((ALint)val - 32768); } - -static inline ALfloat Sample_ALint(ALint val) -{ return (val>>7) * (1.0f/16777216.0f); } -static inline ALfloat Sample_ALuint(ALuint val) -{ return Sample_ALint(val - INT_MAX - 1); } - -static inline ALfloat Sample_ALfloat(ALfloat val) -{ return val; } - -#define DECL_TEMPLATE(T) \ -static inline void Load_##T(ALfloat *RESTRICT dst, const T *RESTRICT src, \ - ALint srcstep, ALsizei samples) \ -{ \ - ALsizei i; \ - for(i = 0;i < samples;i++) \ - dst[i] = Sample_##T(src[i*srcstep]); \ -} - -DECL_TEMPLATE(ALbyte) -DECL_TEMPLATE(ALubyte) -DECL_TEMPLATE(ALshort) -DECL_TEMPLATE(ALushort) -DECL_TEMPLATE(ALint) -DECL_TEMPLATE(ALuint) -DECL_TEMPLATE(ALfloat) - -#undef DECL_TEMPLATE - -static void LoadSamples(ALfloat *dst, const ALvoid *src, ALint srcstep, enum DevFmtType srctype, ALsizei samples) -{ - switch(srctype) - { - case DevFmtByte: - Load_ALbyte(dst, src, srcstep, samples); - break; - case DevFmtUByte: - Load_ALubyte(dst, src, srcstep, samples); - break; - case DevFmtShort: - Load_ALshort(dst, src, srcstep, samples); - break; - case DevFmtUShort: - Load_ALushort(dst, src, srcstep, samples); - break; - case DevFmtInt: - Load_ALint(dst, src, srcstep, samples); - break; - case DevFmtUInt: - Load_ALuint(dst, src, srcstep, samples); - break; - case DevFmtFloat: - Load_ALfloat(dst, src, srcstep, samples); - break; - } -} - - -static inline ALbyte ALbyte_Sample(ALfloat val) -{ return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); } -static inline ALubyte ALubyte_Sample(ALfloat val) -{ return ALbyte_Sample(val)+128; } - -static inline ALshort ALshort_Sample(ALfloat val) -{ return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); } -static inline ALushort ALushort_Sample(ALfloat val) -{ return ALshort_Sample(val)+32768; } - -static inline ALint ALint_Sample(ALfloat val) -{ return fastf2i(clampf(val*16777216.0f, -16777216.0f, 16777215.0f)) << 7; } -static inline ALuint ALuint_Sample(ALfloat val) -{ return ALint_Sample(val)+INT_MAX+1; } - -static inline ALfloat ALfloat_Sample(ALfloat val) -{ return val; } - -#define DECL_TEMPLATE(T) \ -static inline void Store_##T(T *RESTRICT dst, const ALfloat *RESTRICT src, \ - ALint dststep, ALsizei samples) \ -{ \ - ALsizei i; \ - for(i = 0;i < samples;i++) \ - dst[i*dststep] = T##_Sample(src[i]); \ -} - -DECL_TEMPLATE(ALbyte) -DECL_TEMPLATE(ALubyte) -DECL_TEMPLATE(ALshort) -DECL_TEMPLATE(ALushort) -DECL_TEMPLATE(ALint) -DECL_TEMPLATE(ALuint) -DECL_TEMPLATE(ALfloat) - -#undef DECL_TEMPLATE - -static void StoreSamples(ALvoid *dst, const ALfloat *src, ALint dststep, enum DevFmtType dsttype, ALsizei samples) -{ - switch(dsttype) - { - case DevFmtByte: - Store_ALbyte(dst, src, dststep, samples); - break; - case DevFmtUByte: - Store_ALubyte(dst, src, dststep, samples); - break; - case DevFmtShort: - Store_ALshort(dst, src, dststep, samples); - break; - case DevFmtUShort: - Store_ALushort(dst, src, dststep, samples); - break; - case DevFmtInt: - Store_ALint(dst, src, dststep, samples); - break; - case DevFmtUInt: - Store_ALuint(dst, src, dststep, samples); - break; - case DevFmtFloat: - Store_ALfloat(dst, src, dststep, samples); - break; - } -} - - -ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframes) -{ - ALint prepcount = converter->mSrcPrepCount; - ALsizei increment = converter->mIncrement; - ALsizei DataPosFrac = converter->mFracOffset; - ALuint64 DataSize64; - - if(prepcount < 0) - { - /* Negative prepcount means we need to skip that many input samples. */ - if(-prepcount >= srcframes) - return 0; - srcframes += prepcount; - prepcount = 0; - } - - if(srcframes < 1) - { - /* No output samples if there's no input samples. */ - return 0; - } - - if(prepcount < MAX_RESAMPLE_PADDING*2 && - MAX_RESAMPLE_PADDING*2 - prepcount >= srcframes) - { - /* Not enough input samples to generate an output sample. */ - return 0; - } - - DataSize64 = prepcount; - DataSize64 += srcframes; - DataSize64 -= MAX_RESAMPLE_PADDING*2; - DataSize64 <<= FRACTIONBITS; - DataSize64 -= DataPosFrac; - - /* If we have a full prep, we can generate at least one sample. */ - return (ALsizei)clampu64((DataSize64 + increment-1)/increment, 1, BUFFERSIZE); -} - - -ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes) -{ - const ALsizei SrcFrameSize = converter->mNumChannels * converter->mSrcTypeSize; - const ALsizei DstFrameSize = converter->mNumChannels * converter->mDstTypeSize; - const ALsizei increment = converter->mIncrement; - ALsizei pos = 0; - - START_MIXER_MODE(); - while(pos < dstframes && *srcframes > 0) - { - ALfloat *RESTRICT SrcData = ASSUME_ALIGNED(converter->mSrcSamples, 16); - ALfloat *RESTRICT DstData = ASSUME_ALIGNED(converter->mDstSamples, 16); - ALint prepcount = converter->mSrcPrepCount; - ALsizei DataPosFrac = converter->mFracOffset; - ALuint64 DataSize64; - ALsizei DstSize; - ALint toread; - ALsizei chan; - - if(prepcount < 0) - { - /* Negative prepcount means we need to skip that many input samples. */ - if(-prepcount >= *srcframes) - { - converter->mSrcPrepCount = prepcount + *srcframes; - *srcframes = 0; - break; - } - *src = (const ALbyte*)*src + SrcFrameSize*-prepcount; - *srcframes += prepcount; - converter->mSrcPrepCount = 0; - continue; - } - toread = mini(*srcframes, BUFFERSIZE - MAX_RESAMPLE_PADDING*2); - - if(prepcount < MAX_RESAMPLE_PADDING*2 && - MAX_RESAMPLE_PADDING*2 - prepcount >= toread) - { - /* Not enough input samples to generate an output sample. Store - * what we're given for later. - */ - for(chan = 0;chan < converter->mNumChannels;chan++) - LoadSamples(&converter->Chan[chan].mPrevSamples[prepcount], - (const ALbyte*)*src + converter->mSrcTypeSize*chan, - converter->mNumChannels, converter->mSrcType, toread - ); - - converter->mSrcPrepCount = prepcount + toread; - *srcframes = 0; - break; - } - - DataSize64 = prepcount; - DataSize64 += toread; - DataSize64 -= MAX_RESAMPLE_PADDING*2; - DataSize64 <<= FRACTIONBITS; - DataSize64 -= DataPosFrac; - - /* If we have a full prep, we can generate at least one sample. */ - DstSize = (ALsizei)clampu64((DataSize64 + increment-1)/increment, 1, BUFFERSIZE); - DstSize = mini(DstSize, dstframes-pos); - - for(chan = 0;chan < converter->mNumChannels;chan++) - { - const ALbyte *SrcSamples = (const ALbyte*)*src + converter->mSrcTypeSize*chan; - ALbyte *DstSamples = (ALbyte*)dst + converter->mDstTypeSize*chan; - const ALfloat *ResampledData; - ALsizei SrcDataEnd; - - /* Load the previous samples into the source data first, then the - * new samples from the input buffer. - */ - memcpy(SrcData, converter->Chan[chan].mPrevSamples, - prepcount*sizeof(ALfloat)); - LoadSamples(SrcData + prepcount, SrcSamples, - converter->mNumChannels, converter->mSrcType, toread - ); - - /* Store as many prep samples for next time as possible, given the - * number of output samples being generated. - */ - SrcDataEnd = (DataPosFrac + increment*DstSize)>>FRACTIONBITS; - if(SrcDataEnd >= prepcount+toread) - memset(converter->Chan[chan].mPrevSamples, 0, - sizeof(converter->Chan[chan].mPrevSamples)); - else - { - size_t len = mini(MAX_RESAMPLE_PADDING*2, prepcount+toread-SrcDataEnd); - memcpy(converter->Chan[chan].mPrevSamples, &SrcData[SrcDataEnd], - len*sizeof(ALfloat)); - memset(converter->Chan[chan].mPrevSamples+len, 0, - sizeof(converter->Chan[chan].mPrevSamples) - len*sizeof(ALfloat)); - } - - /* Now resample, and store the result in the output buffer. */ - ResampledData = converter->mResample(&converter->mState, - SrcData+MAX_RESAMPLE_PADDING, DataPosFrac, increment, - DstData, DstSize - ); - - StoreSamples(DstSamples, ResampledData, converter->mNumChannels, - converter->mDstType, DstSize); - } - - /* Update the number of prep samples still available, as well as the - * fractional offset. - */ - DataPosFrac += increment*DstSize; - converter->mSrcPrepCount = mini(prepcount + toread - (DataPosFrac>>FRACTIONBITS), - MAX_RESAMPLE_PADDING*2); - converter->mFracOffset = DataPosFrac & FRACTIONMASK; - - /* Update the src and dst pointers in case there's still more to do. */ - *src = (const ALbyte*)*src + SrcFrameSize*(DataPosFrac>>FRACTIONBITS); - *srcframes -= mini(*srcframes, (DataPosFrac>>FRACTIONBITS)); - - dst = (ALbyte*)dst + DstFrameSize*DstSize; - pos += DstSize; - } - END_MIXER_MODE(); - - return pos; -} - - -ChannelConverter *CreateChannelConverter(enum DevFmtType srcType, enum DevFmtChannels srcChans, enum DevFmtChannels dstChans) -{ - ChannelConverter *converter; - - if(srcChans != dstChans && !((srcChans == DevFmtMono && dstChans == DevFmtStereo) || - (srcChans == DevFmtStereo && dstChans == DevFmtMono))) - return NULL; - - converter = al_calloc(DEF_ALIGN, sizeof(*converter)); - converter->mSrcType = srcType; - converter->mSrcChans = srcChans; - converter->mDstChans = dstChans; - - return converter; -} - -void DestroyChannelConverter(ChannelConverter **converter) -{ - if(converter) - { - al_free(*converter); - *converter = NULL; - } -} - - -#define DECL_TEMPLATE(T) \ -static void Mono2Stereo##T(ALfloat *RESTRICT dst, const T *src, ALsizei frames)\ -{ \ - ALsizei i; \ - for(i = 0;i < frames;i++) \ - dst[i*2 + 1] = dst[i*2 + 0] = Sample_##T(src[i]) * 0.707106781187f; \ -} \ - \ -static void Stereo2Mono##T(ALfloat *RESTRICT dst, const T *src, ALsizei frames)\ -{ \ - ALsizei i; \ - for(i = 0;i < frames;i++) \ - dst[i] = (Sample_##T(src[i*2 + 0])+Sample_##T(src[i*2 + 1])) * \ - 0.707106781187f; \ -} - -DECL_TEMPLATE(ALbyte) -DECL_TEMPLATE(ALubyte) -DECL_TEMPLATE(ALshort) -DECL_TEMPLATE(ALushort) -DECL_TEMPLATE(ALint) -DECL_TEMPLATE(ALuint) -DECL_TEMPLATE(ALfloat) - -#undef DECL_TEMPLATE - -void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALfloat *dst, ALsizei frames) -{ - if(converter->mSrcChans == converter->mDstChans) - { - LoadSamples(dst, src, 1, converter->mSrcType, - frames*ChannelsFromDevFmt(converter->mSrcChans, 0)); - return; - } - - if(converter->mSrcChans == DevFmtStereo && converter->mDstChans == DevFmtMono) - { - switch(converter->mSrcType) - { - case DevFmtByte: - Stereo2MonoALbyte(dst, src, frames); - break; - case DevFmtUByte: - Stereo2MonoALubyte(dst, src, frames); - break; - case DevFmtShort: - Stereo2MonoALshort(dst, src, frames); - break; - case DevFmtUShort: - Stereo2MonoALushort(dst, src, frames); - break; - case DevFmtInt: - Stereo2MonoALint(dst, src, frames); - break; - case DevFmtUInt: - Stereo2MonoALuint(dst, src, frames); - break; - case DevFmtFloat: - Stereo2MonoALfloat(dst, src, frames); - break; - } - } - else /*if(converter->mSrcChans == DevFmtMono && converter->mDstChans == DevFmtStereo)*/ - { - switch(converter->mSrcType) - { - case DevFmtByte: - Mono2StereoALbyte(dst, src, frames); - break; - case DevFmtUByte: - Mono2StereoALubyte(dst, src, frames); - break; - case DevFmtShort: - Mono2StereoALshort(dst, src, frames); - break; - case DevFmtUShort: - Mono2StereoALushort(dst, src, frames); - break; - case DevFmtInt: - Mono2StereoALint(dst, src, frames); - break; - case DevFmtUInt: - Mono2StereoALuint(dst, src, frames); - break; - case DevFmtFloat: - Mono2StereoALfloat(dst, src, frames); - break; - } - } -} diff --git a/Alc/converter.cpp b/Alc/converter.cpp new file mode 100644 index 00000000..5858c370 --- /dev/null +++ b/Alc/converter.cpp @@ -0,0 +1,469 @@ + +#include "config.h" + +#include "converter.h" + +#include "fpu_modes.h" +#include "mixer/defs.h" + + +SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, ALsizei numchans, ALsizei srcRate, ALsizei dstRate) +{ + SampleConverter *converter; + ALsizei step; + + if(numchans <= 0 || srcRate <= 0 || dstRate <= 0) + return NULL; + + converter = static_cast(al_calloc(16, + FAM_SIZE(SampleConverter, Chan, numchans))); + converter->mSrcType = srcType; + converter->mDstType = dstType; + converter->mNumChannels = numchans; + converter->mSrcTypeSize = BytesFromDevFmt(srcType); + converter->mDstTypeSize = BytesFromDevFmt(dstType); + + converter->mSrcPrepCount = 0; + converter->mFracOffset = 0; + + /* Have to set the mixer FPU mode since that's what the resampler code expects. */ + START_MIXER_MODE(); + step = (ALsizei)mind(((ALdouble)srcRate/dstRate*FRACTIONONE) + 0.5, + MAX_PITCH * FRACTIONONE); + converter->mIncrement = maxi(step, 1); + if(converter->mIncrement == FRACTIONONE) + converter->mResample = Resample_copy_C; + else + { + /* TODO: Allow other resamplers. */ + BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc12); + converter->mResample = SelectResampler(BSinc12Resampler); + } + END_MIXER_MODE(); + + return converter; +} + +void DestroySampleConverter(SampleConverter **converter) +{ + if(converter) + { + al_free(*converter); + *converter = NULL; + } +} + + +static inline ALfloat Sample_ALbyte(ALbyte val) +{ return val * (1.0f/128.0f); } +static inline ALfloat Sample_ALubyte(ALubyte val) +{ return Sample_ALbyte((ALint)val - 128); } + +static inline ALfloat Sample_ALshort(ALshort val) +{ return val * (1.0f/32768.0f); } +static inline ALfloat Sample_ALushort(ALushort val) +{ return Sample_ALshort((ALint)val - 32768); } + +static inline ALfloat Sample_ALint(ALint val) +{ return (val>>7) * (1.0f/16777216.0f); } +static inline ALfloat Sample_ALuint(ALuint val) +{ return Sample_ALint(val - INT_MAX - 1); } + +static inline ALfloat Sample_ALfloat(ALfloat val) +{ return val; } + +#define DECL_TEMPLATE(T) \ +static inline void Load_##T(ALfloat *RESTRICT dst, const T *RESTRICT src, \ + ALint srcstep, ALsizei samples) \ +{ \ + ALsizei i; \ + for(i = 0;i < samples;i++) \ + dst[i] = Sample_##T(src[i*srcstep]); \ +} + +DECL_TEMPLATE(ALbyte) +DECL_TEMPLATE(ALubyte) +DECL_TEMPLATE(ALshort) +DECL_TEMPLATE(ALushort) +DECL_TEMPLATE(ALint) +DECL_TEMPLATE(ALuint) +DECL_TEMPLATE(ALfloat) + +#undef DECL_TEMPLATE + +static void LoadSamples(ALfloat *dst, const ALvoid *src, ALint srcstep, enum DevFmtType srctype, ALsizei samples) +{ + switch(srctype) + { + case DevFmtByte: + Load_ALbyte(dst, static_cast(src), srcstep, samples); + break; + case DevFmtUByte: + Load_ALubyte(dst, static_cast(src), srcstep, samples); + break; + case DevFmtShort: + Load_ALshort(dst, static_cast(src), srcstep, samples); + break; + case DevFmtUShort: + Load_ALushort(dst, static_cast(src), srcstep, samples); + break; + case DevFmtInt: + Load_ALint(dst, static_cast(src), srcstep, samples); + break; + case DevFmtUInt: + Load_ALuint(dst, static_cast(src), srcstep, samples); + break; + case DevFmtFloat: + Load_ALfloat(dst, static_cast(src), srcstep, samples); + break; + } +} + + +static inline ALbyte ALbyte_Sample(ALfloat val) +{ return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); } +static inline ALubyte ALubyte_Sample(ALfloat val) +{ return ALbyte_Sample(val)+128; } + +static inline ALshort ALshort_Sample(ALfloat val) +{ return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); } +static inline ALushort ALushort_Sample(ALfloat val) +{ return ALshort_Sample(val)+32768; } + +static inline ALint ALint_Sample(ALfloat val) +{ return fastf2i(clampf(val*16777216.0f, -16777216.0f, 16777215.0f)) << 7; } +static inline ALuint ALuint_Sample(ALfloat val) +{ return ALint_Sample(val)+INT_MAX+1; } + +static inline ALfloat ALfloat_Sample(ALfloat val) +{ return val; } + +#define DECL_TEMPLATE(T) \ +static inline void Store_##T(T *RESTRICT dst, const ALfloat *RESTRICT src, \ + ALint dststep, ALsizei samples) \ +{ \ + ALsizei i; \ + for(i = 0;i < samples;i++) \ + dst[i*dststep] = T##_Sample(src[i]); \ +} + +DECL_TEMPLATE(ALbyte) +DECL_TEMPLATE(ALubyte) +DECL_TEMPLATE(ALshort) +DECL_TEMPLATE(ALushort) +DECL_TEMPLATE(ALint) +DECL_TEMPLATE(ALuint) +DECL_TEMPLATE(ALfloat) + +#undef DECL_TEMPLATE + +static void StoreSamples(ALvoid *dst, const ALfloat *src, ALint dststep, enum DevFmtType dsttype, ALsizei samples) +{ + switch(dsttype) + { + case DevFmtByte: + Store_ALbyte(static_cast(dst), src, dststep, samples); + break; + case DevFmtUByte: + Store_ALubyte(static_cast(dst), src, dststep, samples); + break; + case DevFmtShort: + Store_ALshort(static_cast(dst), src, dststep, samples); + break; + case DevFmtUShort: + Store_ALushort(static_cast(dst), src, dststep, samples); + break; + case DevFmtInt: + Store_ALint(static_cast(dst), src, dststep, samples); + break; + case DevFmtUInt: + Store_ALuint(static_cast(dst), src, dststep, samples); + break; + case DevFmtFloat: + Store_ALfloat(static_cast(dst), src, dststep, samples); + break; + } +} + + +ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframes) +{ + ALint prepcount = converter->mSrcPrepCount; + ALsizei increment = converter->mIncrement; + ALsizei DataPosFrac = converter->mFracOffset; + ALuint64 DataSize64; + + if(prepcount < 0) + { + /* Negative prepcount means we need to skip that many input samples. */ + if(-prepcount >= srcframes) + return 0; + srcframes += prepcount; + prepcount = 0; + } + + if(srcframes < 1) + { + /* No output samples if there's no input samples. */ + return 0; + } + + if(prepcount < MAX_RESAMPLE_PADDING*2 && + MAX_RESAMPLE_PADDING*2 - prepcount >= srcframes) + { + /* Not enough input samples to generate an output sample. */ + return 0; + } + + DataSize64 = prepcount; + DataSize64 += srcframes; + DataSize64 -= MAX_RESAMPLE_PADDING*2; + DataSize64 <<= FRACTIONBITS; + DataSize64 -= DataPosFrac; + + /* If we have a full prep, we can generate at least one sample. */ + return (ALsizei)clampu64((DataSize64 + increment-1)/increment, 1, BUFFERSIZE); +} + + +ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes) +{ + const ALsizei SrcFrameSize = converter->mNumChannels * converter->mSrcTypeSize; + const ALsizei DstFrameSize = converter->mNumChannels * converter->mDstTypeSize; + const ALsizei increment = converter->mIncrement; + ALsizei pos = 0; + + START_MIXER_MODE(); + while(pos < dstframes && *srcframes > 0) + { + ALfloat *RESTRICT SrcData = converter->mSrcSamples; + ALfloat *RESTRICT DstData = converter->mDstSamples; + ALint prepcount = converter->mSrcPrepCount; + ALsizei DataPosFrac = converter->mFracOffset; + ALuint64 DataSize64; + ALsizei DstSize; + ALint toread; + ALsizei chan; + + if(prepcount < 0) + { + /* Negative prepcount means we need to skip that many input samples. */ + if(-prepcount >= *srcframes) + { + converter->mSrcPrepCount = prepcount + *srcframes; + *srcframes = 0; + break; + } + *src = (const ALbyte*)*src + SrcFrameSize*-prepcount; + *srcframes += prepcount; + converter->mSrcPrepCount = 0; + continue; + } + toread = mini(*srcframes, BUFFERSIZE - MAX_RESAMPLE_PADDING*2); + + if(prepcount < MAX_RESAMPLE_PADDING*2 && + MAX_RESAMPLE_PADDING*2 - prepcount >= toread) + { + /* Not enough input samples to generate an output sample. Store + * what we're given for later. + */ + for(chan = 0;chan < converter->mNumChannels;chan++) + LoadSamples(&converter->Chan[chan].mPrevSamples[prepcount], + (const ALbyte*)*src + converter->mSrcTypeSize*chan, + converter->mNumChannels, converter->mSrcType, toread + ); + + converter->mSrcPrepCount = prepcount + toread; + *srcframes = 0; + break; + } + + DataSize64 = prepcount; + DataSize64 += toread; + DataSize64 -= MAX_RESAMPLE_PADDING*2; + DataSize64 <<= FRACTIONBITS; + DataSize64 -= DataPosFrac; + + /* If we have a full prep, we can generate at least one sample. */ + DstSize = (ALsizei)clampu64((DataSize64 + increment-1)/increment, 1, BUFFERSIZE); + DstSize = mini(DstSize, dstframes-pos); + + for(chan = 0;chan < converter->mNumChannels;chan++) + { + const ALbyte *SrcSamples = (const ALbyte*)*src + converter->mSrcTypeSize*chan; + ALbyte *DstSamples = (ALbyte*)dst + converter->mDstTypeSize*chan; + const ALfloat *ResampledData; + ALsizei SrcDataEnd; + + /* Load the previous samples into the source data first, then the + * new samples from the input buffer. + */ + memcpy(SrcData, converter->Chan[chan].mPrevSamples, + prepcount*sizeof(ALfloat)); + LoadSamples(SrcData + prepcount, SrcSamples, + converter->mNumChannels, converter->mSrcType, toread + ); + + /* Store as many prep samples for next time as possible, given the + * number of output samples being generated. + */ + SrcDataEnd = (DataPosFrac + increment*DstSize)>>FRACTIONBITS; + if(SrcDataEnd >= prepcount+toread) + memset(converter->Chan[chan].mPrevSamples, 0, + sizeof(converter->Chan[chan].mPrevSamples)); + else + { + size_t len = mini(MAX_RESAMPLE_PADDING*2, prepcount+toread-SrcDataEnd); + memcpy(converter->Chan[chan].mPrevSamples, &SrcData[SrcDataEnd], + len*sizeof(ALfloat)); + memset(converter->Chan[chan].mPrevSamples+len, 0, + sizeof(converter->Chan[chan].mPrevSamples) - len*sizeof(ALfloat)); + } + + /* Now resample, and store the result in the output buffer. */ + ResampledData = converter->mResample(&converter->mState, + SrcData+MAX_RESAMPLE_PADDING, DataPosFrac, increment, + DstData, DstSize + ); + + StoreSamples(DstSamples, ResampledData, converter->mNumChannels, + converter->mDstType, DstSize); + } + + /* Update the number of prep samples still available, as well as the + * fractional offset. + */ + DataPosFrac += increment*DstSize; + converter->mSrcPrepCount = mini(prepcount + toread - (DataPosFrac>>FRACTIONBITS), + MAX_RESAMPLE_PADDING*2); + converter->mFracOffset = DataPosFrac & FRACTIONMASK; + + /* Update the src and dst pointers in case there's still more to do. */ + *src = (const ALbyte*)*src + SrcFrameSize*(DataPosFrac>>FRACTIONBITS); + *srcframes -= mini(*srcframes, (DataPosFrac>>FRACTIONBITS)); + + dst = (ALbyte*)dst + DstFrameSize*DstSize; + pos += DstSize; + } + END_MIXER_MODE(); + + return pos; +} + + +ChannelConverter *CreateChannelConverter(enum DevFmtType srcType, enum DevFmtChannels srcChans, enum DevFmtChannels dstChans) +{ + ChannelConverter *converter; + + if(srcChans != dstChans && !((srcChans == DevFmtMono && dstChans == DevFmtStereo) || + (srcChans == DevFmtStereo && dstChans == DevFmtMono))) + return NULL; + + converter = static_cast(al_calloc(DEF_ALIGN, sizeof(*converter))); + converter->mSrcType = srcType; + converter->mSrcChans = srcChans; + converter->mDstChans = dstChans; + + return converter; +} + +void DestroyChannelConverter(ChannelConverter **converter) +{ + if(converter) + { + al_free(*converter); + *converter = NULL; + } +} + + +#define DECL_TEMPLATE(T) \ +static void Mono2Stereo##T(ALfloat *RESTRICT dst, const T *src, ALsizei frames)\ +{ \ + ALsizei i; \ + for(i = 0;i < frames;i++) \ + dst[i*2 + 1] = dst[i*2 + 0] = Sample_##T(src[i]) * 0.707106781187f; \ +} \ + \ +static void Stereo2Mono##T(ALfloat *RESTRICT dst, const T *src, ALsizei frames)\ +{ \ + ALsizei i; \ + for(i = 0;i < frames;i++) \ + dst[i] = (Sample_##T(src[i*2 + 0])+Sample_##T(src[i*2 + 1])) * \ + 0.707106781187f; \ +} + +DECL_TEMPLATE(ALbyte) +DECL_TEMPLATE(ALubyte) +DECL_TEMPLATE(ALshort) +DECL_TEMPLATE(ALushort) +DECL_TEMPLATE(ALint) +DECL_TEMPLATE(ALuint) +DECL_TEMPLATE(ALfloat) + +#undef DECL_TEMPLATE + +void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALfloat *dst, ALsizei frames) +{ + if(converter->mSrcChans == converter->mDstChans) + { + LoadSamples(dst, src, 1, converter->mSrcType, + frames*ChannelsFromDevFmt(converter->mSrcChans, 0)); + return; + } + + if(converter->mSrcChans == DevFmtStereo && converter->mDstChans == DevFmtMono) + { + switch(converter->mSrcType) + { + case DevFmtByte: + Stereo2MonoALbyte(dst, static_cast(src), frames); + break; + case DevFmtUByte: + Stereo2MonoALubyte(dst, static_cast(src), frames); + break; + case DevFmtShort: + Stereo2MonoALshort(dst, static_cast(src), frames); + break; + case DevFmtUShort: + Stereo2MonoALushort(dst, static_cast(src), frames); + break; + case DevFmtInt: + Stereo2MonoALint(dst, static_cast(src), frames); + break; + case DevFmtUInt: + Stereo2MonoALuint(dst, static_cast(src), frames); + break; + case DevFmtFloat: + Stereo2MonoALfloat(dst, static_cast(src), frames); + break; + } + } + else /*if(converter->mSrcChans == DevFmtMono && converter->mDstChans == DevFmtStereo)*/ + { + switch(converter->mSrcType) + { + case DevFmtByte: + Mono2StereoALbyte(dst, static_cast(src), frames); + break; + case DevFmtUByte: + Mono2StereoALubyte(dst, static_cast(src), frames); + break; + case DevFmtShort: + Mono2StereoALshort(dst, static_cast(src), frames); + break; + case DevFmtUShort: + Mono2StereoALushort(dst, static_cast(src), frames); + break; + case DevFmtInt: + Mono2StereoALint(dst, static_cast(src), frames); + break; + case DevFmtUInt: + Mono2StereoALuint(dst, static_cast(src), frames); + break; + case DevFmtFloat: + Mono2StereoALfloat(dst, static_cast(src), frames); + break; + } + } +} diff --git a/Alc/converter.h b/Alc/converter.h index 3f0c6304..78cbdf64 100644 --- a/Alc/converter.h +++ b/Alc/converter.h @@ -4,11 +4,7 @@ #include "alMain.h" #include "alu.h" -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct SampleConverter { +struct SampleConverter { enum DevFmtType mSrcType; enum DevFmtType mDstType; ALsizei mNumChannels; @@ -28,7 +24,7 @@ typedef struct SampleConverter { struct { alignas(16) ALfloat mPrevSamples[MAX_RESAMPLE_PADDING*2]; } Chan[]; -} SampleConverter; +}; SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, ALsizei numchans, ALsizei srcRate, ALsizei dstRate); void DestroySampleConverter(SampleConverter **converter); @@ -37,19 +33,15 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframes); -typedef struct ChannelConverter { +struct ChannelConverter { enum DevFmtType mSrcType; enum DevFmtChannels mSrcChans; enum DevFmtChannels mDstChans; -} ChannelConverter; +}; ChannelConverter *CreateChannelConverter(enum DevFmtType srcType, enum DevFmtChannels srcChans, enum DevFmtChannels dstChans); void DestroyChannelConverter(ChannelConverter **converter); void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALfloat *dst, ALsizei frames); -#ifdef __cplusplus -} -#endif - #endif /* CONVERTER_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 64a40d95..917ec303 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -800,7 +800,7 @@ SET(ALC_OBJS Alc/alconfig.cpp Alc/alconfig.h Alc/bs2b.c - Alc/converter.c + Alc/converter.cpp Alc/converter.h Alc/inldefs.c Alc/inprogext.h -- cgit v1.2.3 From ff4219e54e2a444f0ccf4033091931d2908af91e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 07:40:10 -0800 Subject: Convert mastering.c to C++ --- Alc/mastering.c | 543 ------------------------------------------------------ Alc/mastering.cpp | 543 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 544 insertions(+), 544 deletions(-) delete mode 100644 Alc/mastering.c create mode 100644 Alc/mastering.cpp diff --git a/Alc/mastering.c b/Alc/mastering.c deleted file mode 100644 index 5ccf3a9e..00000000 --- a/Alc/mastering.c +++ /dev/null @@ -1,543 +0,0 @@ -#include "config.h" - -#include - -#include "mastering.h" -#include "alu.h" -#include "almalloc.h" -#include "static_assert.h" -#include "math_defs.h" - - -/* Early MSVC lacks round/roundf */ -#if defined(_MSC_VER) && _MSC_VER < 1800 -static double round(double val) -{ - if(val < 0.0) - return ceil(val-0.5); - return floor(val+0.5); -} -#define roundf(f) ((float)round((float)(f))) -#endif - - -/* These structures assume BUFFERSIZE is a power of 2. */ -static_assert((BUFFERSIZE & (BUFFERSIZE-1)) == 0, "BUFFERSIZE is not a power of 2"); - -typedef struct SlidingHold { - ALfloat Values[BUFFERSIZE]; - ALsizei Expiries[BUFFERSIZE]; - ALsizei LowerIndex; - ALsizei UpperIndex; - ALsizei Length; -} SlidingHold; - -/* General topology and basic automation was based on the following paper: - * - * D. Giannoulis, M. Massberg and J. D. Reiss, - * "Parameter Automation in a Dynamic Range Compressor," - * Journal of the Audio Engineering Society, v61 (10), Oct. 2013 - * - * Available (along with supplemental reading) at: - * - * http://c4dm.eecs.qmul.ac.uk/audioengineering/compressors/ - */ -typedef struct Compressor { - ALsizei NumChans; - ALuint SampleRate; - - struct { - ALuint Knee : 1; - ALuint Attack : 1; - ALuint Release : 1; - ALuint PostGain : 1; - ALuint Declip : 1; - } Auto; - - ALsizei LookAhead; - - ALfloat PreGain; - ALfloat PostGain; - - ALfloat Threshold; - ALfloat Slope; - ALfloat Knee; - - ALfloat Attack; - ALfloat Release; - - alignas(16) ALfloat SideChain[2*BUFFERSIZE]; - alignas(16) ALfloat CrestFactor[BUFFERSIZE]; - - SlidingHold *Hold; - ALfloat (*Delay)[BUFFERSIZE]; - ALsizei DelayIndex; - - ALfloat CrestCoeff; - ALfloat GainEstimate; - ALfloat AdaptCoeff; - - ALfloat LastPeakSq; - ALfloat LastRmsSq; - ALfloat LastRelease; - ALfloat LastAttack; - ALfloat LastGainDev; -} Compressor; - - -/* This sliding hold follows the input level with an instant attack and a - * fixed duration hold before an instant release to the next highest level. - * It is a sliding window maximum (descending maxima) implementation based on - * Richard Harter's ascending minima algorithm available at: - * - * http://www.richardhartersworld.com/cri/2001/slidingmin.html - */ -static ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALfloat in) -{ - const ALsizei mask = BUFFERSIZE - 1; - const ALsizei length = Hold->Length; - ALfloat *RESTRICT values = Hold->Values; - ALsizei *RESTRICT expiries = Hold->Expiries; - ALsizei lowerIndex = Hold->LowerIndex; - ALsizei upperIndex = Hold->UpperIndex; - - if(i >= expiries[upperIndex]) - upperIndex = (upperIndex + 1) & mask; - - if(in >= values[upperIndex]) - { - values[upperIndex] = in; - expiries[upperIndex] = i + length; - lowerIndex = upperIndex; - } - else - { - do { - do { - if(!(in >= values[lowerIndex])) - goto found_place; - } while(lowerIndex--); - lowerIndex = mask; - } while(1); - found_place: - - lowerIndex = (lowerIndex + 1) & mask; - values[lowerIndex] = in; - expiries[lowerIndex] = i + length; - } - - Hold->LowerIndex = lowerIndex; - Hold->UpperIndex = upperIndex; - - return values[upperIndex]; -} - -static void ShiftSlidingHold(SlidingHold *Hold, const ALsizei n) -{ - const ALsizei lowerIndex = Hold->LowerIndex; - ALsizei *RESTRICT expiries = Hold->Expiries; - ALsizei i = Hold->UpperIndex; - - if(lowerIndex < i) - { - for(;i < BUFFERSIZE;i++) - expiries[i] -= n; - i = 0; - } - for(;i < lowerIndex;i++) - expiries[i] -= n; - - expiries[i] -= n; -} - -/* Multichannel compression is linked via the absolute maximum of all - * channels. - */ -static void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]) -{ - const ALsizei index = Comp->LookAhead; - const ALsizei numChans = Comp->NumChans; - ALfloat *RESTRICT sideChain = Comp->SideChain; - ALsizei c, i; - - ASSUME(SamplesToDo > 0); - ASSUME(numChans > 0); - - for(i = 0;i < SamplesToDo;i++) - sideChain[index + i] = 0.0f; - - for(c = 0;c < numChans;c++) - { - ALsizei offset = index; - for(i = 0;i < SamplesToDo;i++) - { - sideChain[offset] = maxf(sideChain[offset], fabsf(OutBuffer[c][i])); - ++offset; - } - } -} - -/* This calculates the squared crest factor of the control signal for the - * basic automation of the attack/release times. As suggested by the paper, - * it uses an instantaneous squared peak detector and a squared RMS detector - * both with 200ms release times. - */ -static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo) -{ - const ALfloat a_crest = Comp->CrestCoeff; - const ALsizei index = Comp->LookAhead; - const ALfloat *RESTRICT sideChain = Comp->SideChain; - ALfloat *RESTRICT crestFactor = Comp->CrestFactor; - ALfloat y2_peak = Comp->LastPeakSq; - ALfloat y2_rms = Comp->LastRmsSq; - ALsizei i; - - ASSUME(SamplesToDo > 0); - - for(i = 0;i < SamplesToDo;i++) - { - ALfloat x_abs = sideChain[index + i]; - ALfloat x2 = maxf(0.000001f, x_abs * x_abs); - - y2_peak = maxf(x2, lerp(x2, y2_peak, a_crest)); - y2_rms = lerp(x2, y2_rms, a_crest); - crestFactor[i] = y2_peak / y2_rms; - } - - Comp->LastPeakSq = y2_peak; - Comp->LastRmsSq = y2_rms; -} - -/* The side-chain starts with a simple peak detector (based on the absolute - * value of the incoming signal) and performs most of its operations in the - * log domain. - */ -static void PeakDetector(Compressor *Comp, const ALsizei SamplesToDo) -{ - const ALsizei index = Comp->LookAhead; - ALfloat *RESTRICT sideChain = Comp->SideChain; - ALsizei i; - - ASSUME(SamplesToDo > 0); - - for(i = 0;i < SamplesToDo;i++) - { - const ALuint offset = index + i; - const ALfloat x_abs = sideChain[offset]; - - sideChain[offset] = logf(maxf(0.000001f, x_abs)); - } -} - -/* An optional hold can be used to extend the peak detector so it can more - * solidly detect fast transients. This is best used when operating as a - * limiter. - */ -static void PeakHoldDetector(Compressor *Comp, const ALsizei SamplesToDo) -{ - const ALsizei index = Comp->LookAhead; - ALfloat *RESTRICT sideChain = Comp->SideChain; - SlidingHold *hold = Comp->Hold; - ALsizei i; - - ASSUME(SamplesToDo > 0); - - for(i = 0;i < SamplesToDo;i++) - { - const ALsizei offset = index + i; - const ALfloat x_abs = sideChain[offset]; - const ALfloat x_G = logf(maxf(0.000001f, x_abs)); - - sideChain[offset] = UpdateSlidingHold(hold, i, x_G); - } - - ShiftSlidingHold(hold, SamplesToDo); -} - -/* This is the heart of the feed-forward compressor. It operates in the log - * domain (to better match human hearing) and can apply some basic automation - * to knee width, attack/release times, make-up/post gain, and clipping - * reduction. - */ -static void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) -{ - const bool autoKnee = Comp->Auto.Knee; - const bool autoAttack = Comp->Auto.Attack; - const bool autoRelease = Comp->Auto.Release; - const bool autoPostGain = Comp->Auto.PostGain; - const bool autoDeclip = Comp->Auto.Declip; - const ALsizei lookAhead = Comp->LookAhead; - const ALfloat threshold = Comp->Threshold; - const ALfloat slope = Comp->Slope; - const ALfloat attack = Comp->Attack; - const ALfloat release = Comp->Release; - const ALfloat c_est = Comp->GainEstimate; - const ALfloat a_adp = Comp->AdaptCoeff; - const ALfloat *RESTRICT crestFactor = Comp->CrestFactor; - ALfloat *RESTRICT sideChain = Comp->SideChain; - ALfloat postGain = Comp->PostGain; - ALfloat knee = Comp->Knee; - ALfloat t_att = attack; - ALfloat t_rel = release - attack; - ALfloat a_att = expf(-1.0f / t_att); - ALfloat a_rel = expf(-1.0f / t_rel); - ALfloat y_1 = Comp->LastRelease; - ALfloat y_L = Comp->LastAttack; - ALfloat c_dev = Comp->LastGainDev; - ALsizei i; - - ASSUME(SamplesToDo > 0); - - for(i = 0;i < SamplesToDo;i++) - { - const ALfloat y2_crest = crestFactor[i]; - const ALfloat x_G = sideChain[lookAhead + i]; - const ALfloat x_over = x_G - threshold; - ALfloat knee_h; - ALfloat y_G; - ALfloat x_L; - - if(autoKnee) - knee = maxf(0.0f, 2.5f * (c_dev + c_est)); - knee_h = 0.5f * knee; - - /* This is the gain computer. It applies a static compression curve - * to the control signal. - */ - if(x_over <= -knee_h) - y_G = 0.0f; - else if(fabsf(x_over) < knee_h) - y_G = (x_over + knee_h) * (x_over + knee_h) / (2.0f * knee); - else - y_G = x_over; - - x_L = -slope * y_G; - - if(autoAttack) - { - t_att = 2.0f * attack / y2_crest; - a_att = expf(-1.0f / t_att); - } - - if(autoRelease) - { - t_rel = 2.0f * release / y2_crest - t_att; - a_rel = expf(-1.0f / t_rel); - } - - /* Gain smoothing (ballistics) is done via a smooth decoupled peak - * detector. The attack time is subtracted from the release time - * above to compensate for the chained operating mode. - */ - y_1 = maxf(x_L, lerp(x_L, y_1, a_rel)); - y_L = lerp(y_1, y_L, a_att); - - /* Knee width and make-up gain automation make use of a smoothed - * measurement of deviation between the control signal and estimate. - * The estimate is also used to bias the measurement to hot-start its - * average. - */ - c_dev = lerp(-y_L - c_est, c_dev, a_adp); - - if(autoPostGain) - { - /* Clipping reduction is only viable when make-up gain is being - * automated. It modifies the deviation to further attenuate the - * control signal when clipping is detected. The adaptation - * time is sufficiently long enough to suppress further clipping - * at the same output level. - */ - if(autoDeclip) - c_dev = maxf(c_dev, sideChain[i] - y_L - threshold - c_est); - - postGain = -(c_dev + c_est); - } - - sideChain[i] = expf(postGain - y_L); - } - - Comp->LastRelease = y_1; - Comp->LastAttack = y_L; - Comp->LastGainDev = c_dev; -} - -/* Combined with the hold time, a look-ahead delay can improve handling of - * fast transients by allowing the envelope time to converge prior to - * reaching the offending impulse. This is best used when operating as a - * limiter. - */ -static void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]) -{ - const ALsizei mask = BUFFERSIZE - 1; - const ALsizei numChans = Comp->NumChans; - const ALsizei indexIn = Comp->DelayIndex; - const ALsizei indexOut = Comp->DelayIndex - Comp->LookAhead; - ALfloat (*RESTRICT delay)[BUFFERSIZE] = Comp->Delay; - ALsizei c, i; - - ASSUME(SamplesToDo > 0); - ASSUME(numChans > 0); - - for(c = 0;c < numChans;c++) - { - for(i = 0;i < SamplesToDo;i++) - { - ALfloat sig = OutBuffer[c][i]; - - OutBuffer[c][i] = delay[c][(indexOut + i) & mask]; - delay[c][(indexIn + i) & mask] = sig; - } - } - - Comp->DelayIndex = (indexIn + SamplesToDo) & mask; -} - -/* The compressor is initialized with the following settings: - * - * NumChans - Number of channels to process. - * SampleRate - Sample rate to process. - * AutoKnee - Whether to automate the knee width parameter. - * AutoAttack - Whether to automate the attack time parameter. - * AutoRelease - Whether to automate the release time parameter. - * AutoPostGain - Whether to automate the make-up (post) gain parameter. - * AutoDeclip - Whether to automate clipping reduction. Ignored when - * not automating make-up gain. - * LookAheadTime - Look-ahead time (in seconds). - * HoldTime - Peak hold-time (in seconds). - * PreGainDb - Gain applied before detection (in dB). - * PostGainDb - Make-up gain applied after compression (in dB). - * ThresholdDb - Triggering threshold (in dB). - * Ratio - Compression ratio (x:1). Set to INFINITY for true - * limiting. Ignored when automating knee width. - * KneeDb - Knee width (in dB). Ignored when automating knee - * width. - * AttackTimeMin - Attack time (in seconds). Acts as a maximum when - * automating attack time. - * ReleaseTimeMin - Release time (in seconds). Acts as a maximum when - * automating release time. - */ -Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, - const ALboolean AutoKnee, const ALboolean AutoAttack, - const ALboolean AutoRelease, const ALboolean AutoPostGain, - const ALboolean AutoDeclip, const ALfloat LookAheadTime, - const ALfloat HoldTime, const ALfloat PreGainDb, - const ALfloat PostGainDb, const ALfloat ThresholdDb, - const ALfloat Ratio, const ALfloat KneeDb, - const ALfloat AttackTime, const ALfloat ReleaseTime) -{ - Compressor *Comp; - ALsizei lookAhead; - ALsizei hold; - size_t size; - - lookAhead = (ALsizei)clampf(roundf(LookAheadTime*SampleRate), 0.0f, BUFFERSIZE-1); - hold = (ALsizei)clampf(roundf(HoldTime*SampleRate), 0.0f, BUFFERSIZE-1); - /* The sliding hold implementation doesn't handle a length of 1. A 1-sample - * hold is useless anyway, it would only ever give back what was just given - * to it. - */ - if(hold == 1) - hold = 0; - - size = sizeof(*Comp); - if(lookAhead > 0) - { - size += sizeof(*Comp->Delay) * NumChans; - if(hold > 0) - size += sizeof(*Comp->Hold); - } - - Comp = al_calloc(16, size); - Comp->NumChans = NumChans; - Comp->SampleRate = SampleRate; - Comp->Auto.Knee = AutoKnee; - Comp->Auto.Attack = AutoAttack; - Comp->Auto.Release = AutoRelease; - Comp->Auto.PostGain = AutoPostGain; - Comp->Auto.Declip = AutoPostGain && AutoDeclip; - Comp->LookAhead = lookAhead; - Comp->PreGain = powf(10.0f, PreGainDb / 20.0f); - Comp->PostGain = PostGainDb * logf(10.0f) / 20.0f; - Comp->Threshold = ThresholdDb * logf(10.0f) / 20.0f; - Comp->Slope = 1.0f / maxf(1.0f, Ratio) - 1.0f; - Comp->Knee = maxf(0.0f, KneeDb * logf(10.0f) / 20.0f); - Comp->Attack = maxf(1.0f, AttackTime * SampleRate); - Comp->Release = maxf(1.0f, ReleaseTime * SampleRate); - - /* Knee width automation actually treats the compressor as a limiter. By - * varying the knee width, it can effectively be seen as applying - * compression over a wide range of ratios. - */ - if(AutoKnee) - Comp->Slope = -1.0f; - - if(lookAhead > 0) - { - if(hold > 0) - { - Comp->Hold = (SlidingHold*)(Comp + 1); - Comp->Hold->Values[0] = -HUGE_VALF; - Comp->Hold->Expiries[0] = hold; - Comp->Hold->Length = hold; - Comp->Delay = (ALfloat(*)[BUFFERSIZE])(Comp->Hold + 1); - } - else - { - Comp->Delay = (ALfloat(*)[BUFFERSIZE])(Comp + 1); - } - } - - Comp->CrestCoeff = expf(-1.0f / (0.200f * SampleRate)); // 200ms - Comp->GainEstimate = Comp->Threshold * -0.5f * Comp->Slope; - Comp->AdaptCoeff = expf(-1.0f / (2.0f * SampleRate)); // 2s - - return Comp; -} - -void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]) -{ - const ALsizei numChans = Comp->NumChans; - const ALfloat preGain = Comp->PreGain; - ALfloat *RESTRICT sideChain; - ALsizei c, i; - - ASSUME(SamplesToDo > 0); - ASSUME(numChans > 0); - - if(preGain != 1.0f) - { - for(c = 0;c < numChans;c++) - { - for(i = 0;i < SamplesToDo;i++) - OutBuffer[c][i] *= preGain; - } - } - - LinkChannels(Comp, SamplesToDo, OutBuffer); - - if(Comp->Auto.Attack || Comp->Auto.Release) - CrestDetector(Comp, SamplesToDo); - - if(Comp->Hold) - PeakHoldDetector(Comp, SamplesToDo); - else - PeakDetector(Comp, SamplesToDo); - - GainCompressor(Comp, SamplesToDo); - - if(Comp->Delay) - SignalDelay(Comp, SamplesToDo, OutBuffer); - - sideChain = Comp->SideChain; - for(c = 0;c < numChans;c++) - { - for(i = 0;i < SamplesToDo;i++) - OutBuffer[c][i] *= sideChain[i]; - } - - memmove(sideChain, sideChain+SamplesToDo, Comp->LookAhead*sizeof(ALfloat)); -} - - -ALsizei GetCompressorLookAhead(const Compressor *Comp) -{ return Comp->LookAhead; } diff --git a/Alc/mastering.cpp b/Alc/mastering.cpp new file mode 100644 index 00000000..001aada1 --- /dev/null +++ b/Alc/mastering.cpp @@ -0,0 +1,543 @@ +#include "config.h" + +#include + +#include "mastering.h" +#include "alu.h" +#include "almalloc.h" +#include "static_assert.h" +#include "math_defs.h" + + +/* Early MSVC lacks round/roundf */ +#if defined(_MSC_VER) && _MSC_VER < 1800 +static double round(double val) +{ + if(val < 0.0) + return ceil(val-0.5); + return floor(val+0.5); +} +#define roundf(f) ((float)round((float)(f))) +#endif + + +/* These structures assume BUFFERSIZE is a power of 2. */ +static_assert((BUFFERSIZE & (BUFFERSIZE-1)) == 0, "BUFFERSIZE is not a power of 2"); + +typedef struct SlidingHold { + ALfloat Values[BUFFERSIZE]; + ALsizei Expiries[BUFFERSIZE]; + ALsizei LowerIndex; + ALsizei UpperIndex; + ALsizei Length; +} SlidingHold; + +/* General topology and basic automation was based on the following paper: + * + * D. Giannoulis, M. Massberg and J. D. Reiss, + * "Parameter Automation in a Dynamic Range Compressor," + * Journal of the Audio Engineering Society, v61 (10), Oct. 2013 + * + * Available (along with supplemental reading) at: + * + * http://c4dm.eecs.qmul.ac.uk/audioengineering/compressors/ + */ +typedef struct Compressor { + ALsizei NumChans; + ALuint SampleRate; + + struct { + ALuint Knee : 1; + ALuint Attack : 1; + ALuint Release : 1; + ALuint PostGain : 1; + ALuint Declip : 1; + } Auto; + + ALsizei LookAhead; + + ALfloat PreGain; + ALfloat PostGain; + + ALfloat Threshold; + ALfloat Slope; + ALfloat Knee; + + ALfloat Attack; + ALfloat Release; + + alignas(16) ALfloat SideChain[2*BUFFERSIZE]; + alignas(16) ALfloat CrestFactor[BUFFERSIZE]; + + SlidingHold *Hold; + ALfloat (*Delay)[BUFFERSIZE]; + ALsizei DelayIndex; + + ALfloat CrestCoeff; + ALfloat GainEstimate; + ALfloat AdaptCoeff; + + ALfloat LastPeakSq; + ALfloat LastRmsSq; + ALfloat LastRelease; + ALfloat LastAttack; + ALfloat LastGainDev; +} Compressor; + + +/* This sliding hold follows the input level with an instant attack and a + * fixed duration hold before an instant release to the next highest level. + * It is a sliding window maximum (descending maxima) implementation based on + * Richard Harter's ascending minima algorithm available at: + * + * http://www.richardhartersworld.com/cri/2001/slidingmin.html + */ +static ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALfloat in) +{ + const ALsizei mask = BUFFERSIZE - 1; + const ALsizei length = Hold->Length; + ALfloat *RESTRICT values = Hold->Values; + ALsizei *RESTRICT expiries = Hold->Expiries; + ALsizei lowerIndex = Hold->LowerIndex; + ALsizei upperIndex = Hold->UpperIndex; + + if(i >= expiries[upperIndex]) + upperIndex = (upperIndex + 1) & mask; + + if(in >= values[upperIndex]) + { + values[upperIndex] = in; + expiries[upperIndex] = i + length; + lowerIndex = upperIndex; + } + else + { + do { + do { + if(!(in >= values[lowerIndex])) + goto found_place; + } while(lowerIndex--); + lowerIndex = mask; + } while(1); + found_place: + + lowerIndex = (lowerIndex + 1) & mask; + values[lowerIndex] = in; + expiries[lowerIndex] = i + length; + } + + Hold->LowerIndex = lowerIndex; + Hold->UpperIndex = upperIndex; + + return values[upperIndex]; +} + +static void ShiftSlidingHold(SlidingHold *Hold, const ALsizei n) +{ + const ALsizei lowerIndex = Hold->LowerIndex; + ALsizei *RESTRICT expiries = Hold->Expiries; + ALsizei i = Hold->UpperIndex; + + if(lowerIndex < i) + { + for(;i < BUFFERSIZE;i++) + expiries[i] -= n; + i = 0; + } + for(;i < lowerIndex;i++) + expiries[i] -= n; + + expiries[i] -= n; +} + +/* Multichannel compression is linked via the absolute maximum of all + * channels. + */ +static void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]) +{ + const ALsizei index = Comp->LookAhead; + const ALsizei numChans = Comp->NumChans; + ALfloat *RESTRICT sideChain = Comp->SideChain; + ALsizei c, i; + + ASSUME(SamplesToDo > 0); + ASSUME(numChans > 0); + + for(i = 0;i < SamplesToDo;i++) + sideChain[index + i] = 0.0f; + + for(c = 0;c < numChans;c++) + { + ALsizei offset = index; + for(i = 0;i < SamplesToDo;i++) + { + sideChain[offset] = maxf(sideChain[offset], fabsf(OutBuffer[c][i])); + ++offset; + } + } +} + +/* This calculates the squared crest factor of the control signal for the + * basic automation of the attack/release times. As suggested by the paper, + * it uses an instantaneous squared peak detector and a squared RMS detector + * both with 200ms release times. + */ +static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo) +{ + const ALfloat a_crest = Comp->CrestCoeff; + const ALsizei index = Comp->LookAhead; + const ALfloat *RESTRICT sideChain = Comp->SideChain; + ALfloat *RESTRICT crestFactor = Comp->CrestFactor; + ALfloat y2_peak = Comp->LastPeakSq; + ALfloat y2_rms = Comp->LastRmsSq; + ALsizei i; + + ASSUME(SamplesToDo > 0); + + for(i = 0;i < SamplesToDo;i++) + { + ALfloat x_abs = sideChain[index + i]; + ALfloat x2 = maxf(0.000001f, x_abs * x_abs); + + y2_peak = maxf(x2, lerp(x2, y2_peak, a_crest)); + y2_rms = lerp(x2, y2_rms, a_crest); + crestFactor[i] = y2_peak / y2_rms; + } + + Comp->LastPeakSq = y2_peak; + Comp->LastRmsSq = y2_rms; +} + +/* The side-chain starts with a simple peak detector (based on the absolute + * value of the incoming signal) and performs most of its operations in the + * log domain. + */ +static void PeakDetector(Compressor *Comp, const ALsizei SamplesToDo) +{ + const ALsizei index = Comp->LookAhead; + ALfloat *RESTRICT sideChain = Comp->SideChain; + ALsizei i; + + ASSUME(SamplesToDo > 0); + + for(i = 0;i < SamplesToDo;i++) + { + const ALuint offset = index + i; + const ALfloat x_abs = sideChain[offset]; + + sideChain[offset] = logf(maxf(0.000001f, x_abs)); + } +} + +/* An optional hold can be used to extend the peak detector so it can more + * solidly detect fast transients. This is best used when operating as a + * limiter. + */ +static void PeakHoldDetector(Compressor *Comp, const ALsizei SamplesToDo) +{ + const ALsizei index = Comp->LookAhead; + ALfloat *RESTRICT sideChain = Comp->SideChain; + SlidingHold *hold = Comp->Hold; + ALsizei i; + + ASSUME(SamplesToDo > 0); + + for(i = 0;i < SamplesToDo;i++) + { + const ALsizei offset = index + i; + const ALfloat x_abs = sideChain[offset]; + const ALfloat x_G = logf(maxf(0.000001f, x_abs)); + + sideChain[offset] = UpdateSlidingHold(hold, i, x_G); + } + + ShiftSlidingHold(hold, SamplesToDo); +} + +/* This is the heart of the feed-forward compressor. It operates in the log + * domain (to better match human hearing) and can apply some basic automation + * to knee width, attack/release times, make-up/post gain, and clipping + * reduction. + */ +static void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) +{ + const bool autoKnee = Comp->Auto.Knee; + const bool autoAttack = Comp->Auto.Attack; + const bool autoRelease = Comp->Auto.Release; + const bool autoPostGain = Comp->Auto.PostGain; + const bool autoDeclip = Comp->Auto.Declip; + const ALsizei lookAhead = Comp->LookAhead; + const ALfloat threshold = Comp->Threshold; + const ALfloat slope = Comp->Slope; + const ALfloat attack = Comp->Attack; + const ALfloat release = Comp->Release; + const ALfloat c_est = Comp->GainEstimate; + const ALfloat a_adp = Comp->AdaptCoeff; + const ALfloat *RESTRICT crestFactor = Comp->CrestFactor; + ALfloat *RESTRICT sideChain = Comp->SideChain; + ALfloat postGain = Comp->PostGain; + ALfloat knee = Comp->Knee; + ALfloat t_att = attack; + ALfloat t_rel = release - attack; + ALfloat a_att = expf(-1.0f / t_att); + ALfloat a_rel = expf(-1.0f / t_rel); + ALfloat y_1 = Comp->LastRelease; + ALfloat y_L = Comp->LastAttack; + ALfloat c_dev = Comp->LastGainDev; + ALsizei i; + + ASSUME(SamplesToDo > 0); + + for(i = 0;i < SamplesToDo;i++) + { + const ALfloat y2_crest = crestFactor[i]; + const ALfloat x_G = sideChain[lookAhead + i]; + const ALfloat x_over = x_G - threshold; + ALfloat knee_h; + ALfloat y_G; + ALfloat x_L; + + if(autoKnee) + knee = maxf(0.0f, 2.5f * (c_dev + c_est)); + knee_h = 0.5f * knee; + + /* This is the gain computer. It applies a static compression curve + * to the control signal. + */ + if(x_over <= -knee_h) + y_G = 0.0f; + else if(fabsf(x_over) < knee_h) + y_G = (x_over + knee_h) * (x_over + knee_h) / (2.0f * knee); + else + y_G = x_over; + + x_L = -slope * y_G; + + if(autoAttack) + { + t_att = 2.0f * attack / y2_crest; + a_att = expf(-1.0f / t_att); + } + + if(autoRelease) + { + t_rel = 2.0f * release / y2_crest - t_att; + a_rel = expf(-1.0f / t_rel); + } + + /* Gain smoothing (ballistics) is done via a smooth decoupled peak + * detector. The attack time is subtracted from the release time + * above to compensate for the chained operating mode. + */ + y_1 = maxf(x_L, lerp(x_L, y_1, a_rel)); + y_L = lerp(y_1, y_L, a_att); + + /* Knee width and make-up gain automation make use of a smoothed + * measurement of deviation between the control signal and estimate. + * The estimate is also used to bias the measurement to hot-start its + * average. + */ + c_dev = lerp(-y_L - c_est, c_dev, a_adp); + + if(autoPostGain) + { + /* Clipping reduction is only viable when make-up gain is being + * automated. It modifies the deviation to further attenuate the + * control signal when clipping is detected. The adaptation + * time is sufficiently long enough to suppress further clipping + * at the same output level. + */ + if(autoDeclip) + c_dev = maxf(c_dev, sideChain[i] - y_L - threshold - c_est); + + postGain = -(c_dev + c_est); + } + + sideChain[i] = expf(postGain - y_L); + } + + Comp->LastRelease = y_1; + Comp->LastAttack = y_L; + Comp->LastGainDev = c_dev; +} + +/* Combined with the hold time, a look-ahead delay can improve handling of + * fast transients by allowing the envelope time to converge prior to + * reaching the offending impulse. This is best used when operating as a + * limiter. + */ +static void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]) +{ + const ALsizei mask = BUFFERSIZE - 1; + const ALsizei numChans = Comp->NumChans; + const ALsizei indexIn = Comp->DelayIndex; + const ALsizei indexOut = Comp->DelayIndex - Comp->LookAhead; + ALfloat (*RESTRICT delay)[BUFFERSIZE] = Comp->Delay; + ALsizei c, i; + + ASSUME(SamplesToDo > 0); + ASSUME(numChans > 0); + + for(c = 0;c < numChans;c++) + { + for(i = 0;i < SamplesToDo;i++) + { + ALfloat sig = OutBuffer[c][i]; + + OutBuffer[c][i] = delay[c][(indexOut + i) & mask]; + delay[c][(indexIn + i) & mask] = sig; + } + } + + Comp->DelayIndex = (indexIn + SamplesToDo) & mask; +} + +/* The compressor is initialized with the following settings: + * + * NumChans - Number of channels to process. + * SampleRate - Sample rate to process. + * AutoKnee - Whether to automate the knee width parameter. + * AutoAttack - Whether to automate the attack time parameter. + * AutoRelease - Whether to automate the release time parameter. + * AutoPostGain - Whether to automate the make-up (post) gain parameter. + * AutoDeclip - Whether to automate clipping reduction. Ignored when + * not automating make-up gain. + * LookAheadTime - Look-ahead time (in seconds). + * HoldTime - Peak hold-time (in seconds). + * PreGainDb - Gain applied before detection (in dB). + * PostGainDb - Make-up gain applied after compression (in dB). + * ThresholdDb - Triggering threshold (in dB). + * Ratio - Compression ratio (x:1). Set to INFINITY for true + * limiting. Ignored when automating knee width. + * KneeDb - Knee width (in dB). Ignored when automating knee + * width. + * AttackTimeMin - Attack time (in seconds). Acts as a maximum when + * automating attack time. + * ReleaseTimeMin - Release time (in seconds). Acts as a maximum when + * automating release time. + */ +Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, + const ALboolean AutoKnee, const ALboolean AutoAttack, + const ALboolean AutoRelease, const ALboolean AutoPostGain, + const ALboolean AutoDeclip, const ALfloat LookAheadTime, + const ALfloat HoldTime, const ALfloat PreGainDb, + const ALfloat PostGainDb, const ALfloat ThresholdDb, + const ALfloat Ratio, const ALfloat KneeDb, + const ALfloat AttackTime, const ALfloat ReleaseTime) +{ + Compressor *Comp; + ALsizei lookAhead; + ALsizei hold; + size_t size; + + lookAhead = (ALsizei)clampf(roundf(LookAheadTime*SampleRate), 0.0f, BUFFERSIZE-1); + hold = (ALsizei)clampf(roundf(HoldTime*SampleRate), 0.0f, BUFFERSIZE-1); + /* The sliding hold implementation doesn't handle a length of 1. A 1-sample + * hold is useless anyway, it would only ever give back what was just given + * to it. + */ + if(hold == 1) + hold = 0; + + size = sizeof(*Comp); + if(lookAhead > 0) + { + size += sizeof(*Comp->Delay) * NumChans; + if(hold > 0) + size += sizeof(*Comp->Hold); + } + + Comp = static_cast(al_calloc(16, size)); + Comp->NumChans = NumChans; + Comp->SampleRate = SampleRate; + Comp->Auto.Knee = AutoKnee; + Comp->Auto.Attack = AutoAttack; + Comp->Auto.Release = AutoRelease; + Comp->Auto.PostGain = AutoPostGain; + Comp->Auto.Declip = AutoPostGain && AutoDeclip; + Comp->LookAhead = lookAhead; + Comp->PreGain = powf(10.0f, PreGainDb / 20.0f); + Comp->PostGain = PostGainDb * logf(10.0f) / 20.0f; + Comp->Threshold = ThresholdDb * logf(10.0f) / 20.0f; + Comp->Slope = 1.0f / maxf(1.0f, Ratio) - 1.0f; + Comp->Knee = maxf(0.0f, KneeDb * logf(10.0f) / 20.0f); + Comp->Attack = maxf(1.0f, AttackTime * SampleRate); + Comp->Release = maxf(1.0f, ReleaseTime * SampleRate); + + /* Knee width automation actually treats the compressor as a limiter. By + * varying the knee width, it can effectively be seen as applying + * compression over a wide range of ratios. + */ + if(AutoKnee) + Comp->Slope = -1.0f; + + if(lookAhead > 0) + { + if(hold > 0) + { + Comp->Hold = (SlidingHold*)(Comp + 1); + Comp->Hold->Values[0] = -HUGE_VALF; + Comp->Hold->Expiries[0] = hold; + Comp->Hold->Length = hold; + Comp->Delay = (ALfloat(*)[BUFFERSIZE])(Comp->Hold + 1); + } + else + { + Comp->Delay = (ALfloat(*)[BUFFERSIZE])(Comp + 1); + } + } + + Comp->CrestCoeff = expf(-1.0f / (0.200f * SampleRate)); // 200ms + Comp->GainEstimate = Comp->Threshold * -0.5f * Comp->Slope; + Comp->AdaptCoeff = expf(-1.0f / (2.0f * SampleRate)); // 2s + + return Comp; +} + +void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]) +{ + const ALsizei numChans = Comp->NumChans; + const ALfloat preGain = Comp->PreGain; + ALfloat *RESTRICT sideChain; + ALsizei c, i; + + ASSUME(SamplesToDo > 0); + ASSUME(numChans > 0); + + if(preGain != 1.0f) + { + for(c = 0;c < numChans;c++) + { + for(i = 0;i < SamplesToDo;i++) + OutBuffer[c][i] *= preGain; + } + } + + LinkChannels(Comp, SamplesToDo, OutBuffer); + + if(Comp->Auto.Attack || Comp->Auto.Release) + CrestDetector(Comp, SamplesToDo); + + if(Comp->Hold) + PeakHoldDetector(Comp, SamplesToDo); + else + PeakDetector(Comp, SamplesToDo); + + GainCompressor(Comp, SamplesToDo); + + if(Comp->Delay) + SignalDelay(Comp, SamplesToDo, OutBuffer); + + sideChain = Comp->SideChain; + for(c = 0;c < numChans;c++) + { + for(i = 0;i < SamplesToDo;i++) + OutBuffer[c][i] *= sideChain[i]; + } + + memmove(sideChain, sideChain+SamplesToDo, Comp->LookAhead*sizeof(ALfloat)); +} + + +ALsizei GetCompressorLookAhead(const Compressor *Comp) +{ return Comp->LookAhead; } diff --git a/CMakeLists.txt b/CMakeLists.txt index 917ec303..84a99d2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -804,7 +804,7 @@ SET(ALC_OBJS Alc/converter.h Alc/inldefs.c Alc/inprogext.h - Alc/mastering.c + Alc/mastering.cpp Alc/mastering.h Alc/ringbuffer.c Alc/ringbuffer.h -- cgit v1.2.3 From 057b1411f980d480cca76fb64c817f5b3e127f80 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 07:45:10 -0800 Subject: Convert ringbuffer.c to C++ --- Alc/ringbuffer.c | 295 ----------------------------------------------------- Alc/ringbuffer.cpp | 295 +++++++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 296 insertions(+), 296 deletions(-) delete mode 100644 Alc/ringbuffer.c create mode 100644 Alc/ringbuffer.cpp diff --git a/Alc/ringbuffer.c b/Alc/ringbuffer.c deleted file mode 100644 index 6c419cf8..00000000 --- a/Alc/ringbuffer.c +++ /dev/null @@ -1,295 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include "ringbuffer.h" -#include "align.h" -#include "atomic.h" -#include "threads.h" -#include "almalloc.h" -#include "compat.h" - - -/* NOTE: This lockless ringbuffer implementation is copied from JACK, extended - * to include an element size. Consequently, parameters and return values for a - * size or count is in 'elements', not bytes. Additionally, it only supports - * single-consumer/single-provider operation. */ -struct ll_ringbuffer { - ATOMIC(size_t) write_ptr; - ATOMIC(size_t) read_ptr; - size_t size; - size_t size_mask; - size_t elem_size; - - alignas(16) char buf[]; -}; - -ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes) -{ - ll_ringbuffer_t *rb; - size_t power_of_two = 0; - - if(sz > 0) - { - power_of_two = sz; - power_of_two |= power_of_two>>1; - power_of_two |= power_of_two>>2; - power_of_two |= power_of_two>>4; - power_of_two |= power_of_two>>8; - power_of_two |= power_of_two>>16; -#if SIZE_MAX > UINT_MAX - power_of_two |= power_of_two>>32; -#endif - } - power_of_two++; - if(power_of_two < sz) return NULL; - - rb = al_malloc(16, sizeof(*rb) + power_of_two*elem_sz); - if(!rb) return NULL; - - ATOMIC_INIT(&rb->write_ptr, 0); - ATOMIC_INIT(&rb->read_ptr, 0); - rb->size = limit_writes ? sz : power_of_two; - rb->size_mask = power_of_two - 1; - rb->elem_size = elem_sz; - return rb; -} - -void ll_ringbuffer_free(ll_ringbuffer_t *rb) -{ - al_free(rb); -} - -void ll_ringbuffer_reset(ll_ringbuffer_t *rb) -{ - ATOMIC_STORE(&rb->write_ptr, 0, almemory_order_release); - ATOMIC_STORE(&rb->read_ptr, 0, almemory_order_release); - memset(rb->buf, 0, (rb->size_mask+1)*rb->elem_size); -} - - -size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb) -{ - size_t w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); - size_t r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); - return (w-r) & rb->size_mask; -} - -size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb) -{ - size_t w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); - size_t r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); - w = (r-w-1) & rb->size_mask; - return (w > rb->size) ? rb->size : w; -} - - -size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt) -{ - size_t read_ptr; - size_t free_cnt; - size_t cnt2; - size_t to_read; - size_t n1, n2; - - free_cnt = ll_ringbuffer_read_space(rb); - if(free_cnt == 0) return 0; - - to_read = (cnt > free_cnt) ? free_cnt : cnt; - read_ptr = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask; - - cnt2 = read_ptr + to_read; - if(cnt2 > rb->size_mask+1) - { - n1 = rb->size_mask+1 - read_ptr; - n2 = cnt2 & rb->size_mask; - } - else - { - n1 = to_read; - n2 = 0; - } - - memcpy(dest, &rb->buf[read_ptr*rb->elem_size], n1*rb->elem_size); - read_ptr += n1; - if(n2) - { - memcpy(dest + n1*rb->elem_size, &rb->buf[(read_ptr&rb->size_mask)*rb->elem_size], - n2*rb->elem_size); - read_ptr += n2; - } - ATOMIC_STORE(&rb->read_ptr, read_ptr, almemory_order_release); - return to_read; -} - -size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt) -{ - size_t free_cnt; - size_t cnt2; - size_t to_read; - size_t n1, n2; - size_t read_ptr; - - free_cnt = ll_ringbuffer_read_space(rb); - if(free_cnt == 0) return 0; - - to_read = (cnt > free_cnt) ? free_cnt : cnt; - read_ptr = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask; - - cnt2 = read_ptr + to_read; - if(cnt2 > rb->size_mask+1) - { - n1 = rb->size_mask+1 - read_ptr; - n2 = cnt2 & rb->size_mask; - } - else - { - n1 = to_read; - n2 = 0; - } - - memcpy(dest, &rb->buf[read_ptr*rb->elem_size], n1*rb->elem_size); - if(n2) - { - read_ptr += n1; - memcpy(dest + n1*rb->elem_size, &rb->buf[(read_ptr&rb->size_mask)*rb->elem_size], - n2*rb->elem_size); - } - return to_read; -} - -size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt) -{ - size_t write_ptr; - size_t free_cnt; - size_t cnt2; - size_t to_write; - size_t n1, n2; - - free_cnt = ll_ringbuffer_write_space(rb); - if(free_cnt == 0) return 0; - - to_write = (cnt > free_cnt) ? free_cnt : cnt; - write_ptr = ATOMIC_LOAD(&rb->write_ptr, almemory_order_relaxed) & rb->size_mask; - - cnt2 = write_ptr + to_write; - if(cnt2 > rb->size_mask+1) - { - n1 = rb->size_mask+1 - write_ptr; - n2 = cnt2 & rb->size_mask; - } - else - { - n1 = to_write; - n2 = 0; - } - - memcpy(&rb->buf[write_ptr*rb->elem_size], src, n1*rb->elem_size); - write_ptr += n1; - if(n2) - { - memcpy(&rb->buf[(write_ptr&rb->size_mask)*rb->elem_size], src + n1*rb->elem_size, - n2*rb->elem_size); - write_ptr += n2; - } - ATOMIC_STORE(&rb->write_ptr, write_ptr, almemory_order_release); - return to_write; -} - - -void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt) -{ - ATOMIC_ADD(&rb->read_ptr, cnt, almemory_order_acq_rel); -} - -void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt) -{ - ATOMIC_ADD(&rb->write_ptr, cnt, almemory_order_acq_rel); -} - - -void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t vec[2]) -{ - size_t free_cnt; - size_t cnt2; - size_t w, r; - - w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); - r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); - w &= rb->size_mask; - r &= rb->size_mask; - free_cnt = (w-r) & rb->size_mask; - - cnt2 = r + free_cnt; - if(cnt2 > rb->size_mask+1) - { - /* Two part vector: the rest of the buffer after the current write ptr, - * plus some from the start of the buffer. */ - vec[0].buf = (char*)&rb->buf[r*rb->elem_size]; - vec[0].len = rb->size_mask+1 - r; - vec[1].buf = (char*)rb->buf; - vec[1].len = cnt2 & rb->size_mask; - } - else - { - /* Single part vector: just the rest of the buffer */ - vec[0].buf = (char*)&rb->buf[r*rb->elem_size]; - vec[0].len = free_cnt; - vec[1].buf = NULL; - vec[1].len = 0; - } -} - -void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t vec[2]) -{ - size_t free_cnt; - size_t cnt2; - size_t w, r; - - w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); - r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); - w &= rb->size_mask; - r &= rb->size_mask; - free_cnt = (r-w-1) & rb->size_mask; - if(free_cnt > rb->size) free_cnt = rb->size; - - cnt2 = w + free_cnt; - if(cnt2 > rb->size_mask+1) - { - /* Two part vector: the rest of the buffer after the current write ptr, - * plus some from the start of the buffer. */ - vec[0].buf = (char*)&rb->buf[w*rb->elem_size]; - vec[0].len = rb->size_mask+1 - w; - vec[1].buf = (char*)rb->buf; - vec[1].len = cnt2 & rb->size_mask; - } - else - { - vec[0].buf = (char*)&rb->buf[w*rb->elem_size]; - vec[0].len = free_cnt; - vec[1].buf = NULL; - vec[1].len = 0; - } -} diff --git a/Alc/ringbuffer.cpp b/Alc/ringbuffer.cpp new file mode 100644 index 00000000..72267bd0 --- /dev/null +++ b/Alc/ringbuffer.cpp @@ -0,0 +1,295 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include "ringbuffer.h" +#include "align.h" +#include "atomic.h" +#include "threads.h" +#include "almalloc.h" +#include "compat.h" + + +/* NOTE: This lockless ringbuffer implementation is copied from JACK, extended + * to include an element size. Consequently, parameters and return values for a + * size or count is in 'elements', not bytes. Additionally, it only supports + * single-consumer/single-provider operation. */ +struct ll_ringbuffer { + ATOMIC(size_t) write_ptr; + ATOMIC(size_t) read_ptr; + size_t size; + size_t size_mask; + size_t elem_size; + + alignas(16) char buf[]; +}; + +ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes) +{ + ll_ringbuffer_t *rb; + size_t power_of_two = 0; + + if(sz > 0) + { + power_of_two = sz; + power_of_two |= power_of_two>>1; + power_of_two |= power_of_two>>2; + power_of_two |= power_of_two>>4; + power_of_two |= power_of_two>>8; + power_of_two |= power_of_two>>16; +#if SIZE_MAX > UINT_MAX + power_of_two |= power_of_two>>32; +#endif + } + power_of_two++; + if(power_of_two < sz) return NULL; + + rb = static_cast(al_malloc(16, sizeof(*rb) + power_of_two*elem_sz)); + if(!rb) return NULL; + + ATOMIC_INIT(&rb->write_ptr, static_cast(0)); + ATOMIC_INIT(&rb->read_ptr, static_cast(0)); + rb->size = limit_writes ? sz : power_of_two; + rb->size_mask = power_of_two - 1; + rb->elem_size = elem_sz; + return rb; +} + +void ll_ringbuffer_free(ll_ringbuffer_t *rb) +{ + al_free(rb); +} + +void ll_ringbuffer_reset(ll_ringbuffer_t *rb) +{ + ATOMIC_STORE(&rb->write_ptr, static_cast(0), almemory_order_release); + ATOMIC_STORE(&rb->read_ptr, static_cast(0), almemory_order_release); + memset(rb->buf, 0, (rb->size_mask+1)*rb->elem_size); +} + + +size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb) +{ + size_t w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); + size_t r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); + return (w-r) & rb->size_mask; +} + +size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb) +{ + size_t w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); + size_t r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); + w = (r-w-1) & rb->size_mask; + return (w > rb->size) ? rb->size : w; +} + + +size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt) +{ + size_t read_ptr; + size_t free_cnt; + size_t cnt2; + size_t to_read; + size_t n1, n2; + + free_cnt = ll_ringbuffer_read_space(rb); + if(free_cnt == 0) return 0; + + to_read = (cnt > free_cnt) ? free_cnt : cnt; + read_ptr = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask; + + cnt2 = read_ptr + to_read; + if(cnt2 > rb->size_mask+1) + { + n1 = rb->size_mask+1 - read_ptr; + n2 = cnt2 & rb->size_mask; + } + else + { + n1 = to_read; + n2 = 0; + } + + memcpy(dest, &rb->buf[read_ptr*rb->elem_size], n1*rb->elem_size); + read_ptr += n1; + if(n2) + { + memcpy(dest + n1*rb->elem_size, &rb->buf[(read_ptr&rb->size_mask)*rb->elem_size], + n2*rb->elem_size); + read_ptr += n2; + } + ATOMIC_STORE(&rb->read_ptr, read_ptr, almemory_order_release); + return to_read; +} + +size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt) +{ + size_t free_cnt; + size_t cnt2; + size_t to_read; + size_t n1, n2; + size_t read_ptr; + + free_cnt = ll_ringbuffer_read_space(rb); + if(free_cnt == 0) return 0; + + to_read = (cnt > free_cnt) ? free_cnt : cnt; + read_ptr = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask; + + cnt2 = read_ptr + to_read; + if(cnt2 > rb->size_mask+1) + { + n1 = rb->size_mask+1 - read_ptr; + n2 = cnt2 & rb->size_mask; + } + else + { + n1 = to_read; + n2 = 0; + } + + memcpy(dest, &rb->buf[read_ptr*rb->elem_size], n1*rb->elem_size); + if(n2) + { + read_ptr += n1; + memcpy(dest + n1*rb->elem_size, &rb->buf[(read_ptr&rb->size_mask)*rb->elem_size], + n2*rb->elem_size); + } + return to_read; +} + +size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt) +{ + size_t write_ptr; + size_t free_cnt; + size_t cnt2; + size_t to_write; + size_t n1, n2; + + free_cnt = ll_ringbuffer_write_space(rb); + if(free_cnt == 0) return 0; + + to_write = (cnt > free_cnt) ? free_cnt : cnt; + write_ptr = ATOMIC_LOAD(&rb->write_ptr, almemory_order_relaxed) & rb->size_mask; + + cnt2 = write_ptr + to_write; + if(cnt2 > rb->size_mask+1) + { + n1 = rb->size_mask+1 - write_ptr; + n2 = cnt2 & rb->size_mask; + } + else + { + n1 = to_write; + n2 = 0; + } + + memcpy(&rb->buf[write_ptr*rb->elem_size], src, n1*rb->elem_size); + write_ptr += n1; + if(n2) + { + memcpy(&rb->buf[(write_ptr&rb->size_mask)*rb->elem_size], src + n1*rb->elem_size, + n2*rb->elem_size); + write_ptr += n2; + } + ATOMIC_STORE(&rb->write_ptr, write_ptr, almemory_order_release); + return to_write; +} + + +void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt) +{ + ATOMIC_ADD(&rb->read_ptr, cnt, almemory_order_acq_rel); +} + +void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt) +{ + ATOMIC_ADD(&rb->write_ptr, cnt, almemory_order_acq_rel); +} + + +void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t vec[2]) +{ + size_t free_cnt; + size_t cnt2; + size_t w, r; + + w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); + r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); + w &= rb->size_mask; + r &= rb->size_mask; + free_cnt = (w-r) & rb->size_mask; + + cnt2 = r + free_cnt; + if(cnt2 > rb->size_mask+1) + { + /* Two part vector: the rest of the buffer after the current write ptr, + * plus some from the start of the buffer. */ + vec[0].buf = (char*)&rb->buf[r*rb->elem_size]; + vec[0].len = rb->size_mask+1 - r; + vec[1].buf = (char*)rb->buf; + vec[1].len = cnt2 & rb->size_mask; + } + else + { + /* Single part vector: just the rest of the buffer */ + vec[0].buf = (char*)&rb->buf[r*rb->elem_size]; + vec[0].len = free_cnt; + vec[1].buf = NULL; + vec[1].len = 0; + } +} + +void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t vec[2]) +{ + size_t free_cnt; + size_t cnt2; + size_t w, r; + + w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); + r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); + w &= rb->size_mask; + r &= rb->size_mask; + free_cnt = (r-w-1) & rb->size_mask; + if(free_cnt > rb->size) free_cnt = rb->size; + + cnt2 = w + free_cnt; + if(cnt2 > rb->size_mask+1) + { + /* Two part vector: the rest of the buffer after the current write ptr, + * plus some from the start of the buffer. */ + vec[0].buf = (char*)&rb->buf[w*rb->elem_size]; + vec[0].len = rb->size_mask+1 - w; + vec[1].buf = (char*)rb->buf; + vec[1].len = cnt2 & rb->size_mask; + } + else + { + vec[0].buf = (char*)&rb->buf[w*rb->elem_size]; + vec[0].len = free_cnt; + vec[1].buf = NULL; + vec[1].len = 0; + } +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 84a99d2e..19dc0439 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -806,7 +806,7 @@ SET(ALC_OBJS Alc/inprogext.h Alc/mastering.cpp Alc/mastering.h - Alc/ringbuffer.c + Alc/ringbuffer.cpp Alc/ringbuffer.h Alc/effects/autowah.cpp Alc/effects/chorus.cpp -- cgit v1.2.3 From ed5d222eed4b8b464961f53c465ac4d02d5f1980 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 07:50:46 -0800 Subject: Remove the old unused bsincgen.c --- utils/bsincgen.c | 404 ------------------------------------------------------- 1 file changed, 404 deletions(-) delete mode 100644 utils/bsincgen.c diff --git a/utils/bsincgen.c b/utils/bsincgen.c deleted file mode 100644 index 03421da9..00000000 --- a/utils/bsincgen.c +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Sinc interpolator coefficient and delta generator for the OpenAL Soft - * cross platform audio library. - * - * Copyright (C) 2015 by Christopher Fitzgerald. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Or visit: http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html - * - * -------------------------------------------------------------------------- - * - * This is a modified version of the bandlimited windowed sinc interpolator - * algorithm presented here: - * - * Smith, J.O. "Windowed Sinc Interpolation", in - * Physical Audio Signal Processing, - * https://ccrma.stanford.edu/~jos/pasp/Windowed_Sinc_Interpolation.html, - * online book, - * accessed October 2012. - */ - -#define _UNICODE -#include -#include -#include -#include - -#include "win_main_utf8.h" - - -#ifndef M_PI -#define M_PI (3.14159265358979323846) -#endif - -#if defined(__ANDROID__) && !(defined(_ISOC99_SOURCE) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L)) -#define log2(x) (log(x) / log(2.0)) -#endif - -// The number of distinct scale and phase intervals within the filter table. -// Must be the same as in alu.h! -#define BSINC_SCALE_COUNT (16) -#define BSINC_PHASE_COUNT (16) - -/* 48 points includes the doubling for downsampling, so the maximum number of - * base sample points is 24, which is 23rd order. - */ -#define BSINC_POINTS_MAX (48) - -static double MinDouble(double a, double b) -{ return (a <= b) ? a : b; } - -static double MaxDouble(double a, double b) -{ return (a >= b) ? a : b; } - -/* NOTE: This is the normalized (instead of just sin(x)/x) cardinal sine - * function. - * 2 f_t sinc(2 f_t x) - * f_t -- normalized transition frequency (0.5 is nyquist) - * x -- sample index (-N to N) - */ -static double Sinc(const double x) -{ - if(fabs(x) < 1e-15) - return 1.0; - return sin(M_PI * x) / (M_PI * x); -} - -static double BesselI_0(const double x) -{ - double term, sum, last_sum, x2, y; - int i; - - term = 1.0; - sum = 1.0; - x2 = x / 2.0; - i = 1; - - do { - y = x2 / i; - i++; - last_sum = sum; - term *= y * y; - sum += term; - } while(sum != last_sum); - - return sum; -} - -/* NOTE: k is assumed normalized (-1 to 1) - * beta is equivalent to 2 alpha - */ -static double Kaiser(const double b, const double k) -{ - if(!(k >= -1.0 && k <= 1.0)) - return 0.0; - return BesselI_0(b * sqrt(1.0 - k*k)) / BesselI_0(b); -} - -/* Calculates the (normalized frequency) transition width of the Kaiser window. - * Rejection is in dB. - */ -static double CalcKaiserWidth(const double rejection, const int order) -{ - double w_t = 2.0 * M_PI; - - if(rejection > 21.0) - return (rejection - 7.95) / (order * 2.285 * w_t); - /* This enforces a minimum rejection of just above 21.18dB */ - return 5.79 / (order * w_t); -} - -static double CalcKaiserBeta(const double rejection) -{ - if(rejection > 50.0) - return 0.1102 * (rejection - 8.7); - else if(rejection >= 21.0) - return (0.5842 * pow(rejection - 21.0, 0.4)) + - (0.07886 * (rejection - 21.0)); - return 0.0; -} - -/* Generates the coefficient, delta, and index tables required by the bsinc resampler */ -static void BsiGenerateTables(FILE *output, const char *tabname, const double rejection, const int order) -{ - static double filter[BSINC_SCALE_COUNT][BSINC_PHASE_COUNT + 1][BSINC_POINTS_MAX]; - static double scDeltas[BSINC_SCALE_COUNT][BSINC_PHASE_COUNT ][BSINC_POINTS_MAX]; - static double phDeltas[BSINC_SCALE_COUNT][BSINC_PHASE_COUNT + 1][BSINC_POINTS_MAX]; - static double spDeltas[BSINC_SCALE_COUNT][BSINC_PHASE_COUNT ][BSINC_POINTS_MAX]; - static int mt[BSINC_SCALE_COUNT]; - static double at[BSINC_SCALE_COUNT]; - const int num_points_min = order + 1; - double width, beta, scaleBase, scaleRange; - int si, pi, i; - - memset(filter, 0, sizeof(filter)); - memset(scDeltas, 0, sizeof(scDeltas)); - memset(phDeltas, 0, sizeof(phDeltas)); - memset(spDeltas, 0, sizeof(spDeltas)); - - /* Calculate windowing parameters. The width describes the transition - band, but it may vary due to the linear interpolation between scales - of the filter. - */ - width = CalcKaiserWidth(rejection, order); - beta = CalcKaiserBeta(rejection); - scaleBase = width / 2.0; - scaleRange = 1.0 - scaleBase; - - // Determine filter scaling. - for(si = 0; si < BSINC_SCALE_COUNT; si++) - { - const double scale = scaleBase + (scaleRange * si / (BSINC_SCALE_COUNT - 1)); - const double a = MinDouble(floor(num_points_min / (2.0 * scale)), num_points_min); - const int m = 2 * (int)a; - - mt[si] = m; - at[si] = a; - } - - /* Calculate the Kaiser-windowed Sinc filter coefficients for each scale - and phase. - */ - for(si = 0; si < BSINC_SCALE_COUNT; si++) - { - const int m = mt[si]; - const int o = num_points_min - (m / 2); - const int l = (m / 2) - 1; - const double a = at[si]; - const double scale = scaleBase + (scaleRange * si / (BSINC_SCALE_COUNT - 1)); - const double cutoff = (0.5 * scale) - (scaleBase * MaxDouble(0.5, scale)); - - for(pi = 0; pi <= BSINC_PHASE_COUNT; pi++) - { - const double phase = l + ((double)pi / BSINC_PHASE_COUNT); - - for(i = 0; i < m; i++) - { - const double x = i - phase; - filter[si][pi][o + i] = Kaiser(beta, x / a) * 2.0 * cutoff * Sinc(2.0 * cutoff * x); - } - } - } - - /* Linear interpolation between scales is simplified by pre-calculating - the delta (b - a) in: x = a + f (b - a) - - Given a difference in points between scales, the destination points - will be 0, thus: x = a + f (-a) - */ - for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++) - { - const int m = mt[si]; - const int o = num_points_min - (m / 2); - - for(pi = 0; pi < BSINC_PHASE_COUNT; pi++) - { - for(i = 0; i < m; i++) - scDeltas[si][pi][o + i] = filter[si + 1][pi][o + i] - filter[si][pi][o + i]; - } - } - - // Linear interpolation between phases is also simplified. - for(si = 0; si < BSINC_SCALE_COUNT; si++) - { - const int m = mt[si]; - const int o = num_points_min - (m / 2); - - for(pi = 0; pi < BSINC_PHASE_COUNT; pi++) - { - for(i = 0; i < m; i++) - phDeltas[si][pi][o + i] = filter[si][pi + 1][o + i] - filter[si][pi][o + i]; - } - } - - /* This last simplification is done to complete the bilinear equation for - the combination of scale and phase. - */ - for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++) - { - const int m = mt[si]; - const int o = num_points_min - (m / 2); - - for(pi = 0; pi < BSINC_PHASE_COUNT; pi++) - { - for(i = 0; i < m; i++) - spDeltas[si][pi][o + i] = phDeltas[si + 1][pi][o + i] - phDeltas[si][pi][o + i]; - } - } - - // Make sure the number of points is a multiple of 4 (for SIMD). - for(si = 0; si < BSINC_SCALE_COUNT; si++) - mt[si] = (mt[si]+3) & ~3; - - fprintf(output, -"/* This %d%s order filter has a rejection of -%.0fdB, yielding a transition width\n" -" * of ~%.3f (normalized frequency). Order increases when downsampling to a\n" -" * limit of one octave, after which the quality of the filter (transition\n" -" * width) suffers to reduce the CPU cost. The bandlimiting will cut all sound\n" -" * after downsampling by ~%.2f octaves.\n" -" */\n" -"const BSincTable %s = {\n", - order, (((order%100)/10) == 1) ? "th" : - ((order%10) == 1) ? "st" : - ((order%10) == 2) ? "nd" : - ((order%10) == 3) ? "rd" : "th", - rejection, width, log2(1.0/scaleBase), tabname); - - /* The scaleBase is calculated from the Kaiser window transition width. - It represents the absolute limit to the filter before it fully cuts - the signal. The limit in octaves can be calculated by taking the - base-2 logarithm of its inverse: log_2(1 / scaleBase) - */ - fprintf(output, " /* scaleBase */ %.9ef, /* scaleRange */ %.9ef,\n", scaleBase, 1.0 / scaleRange); - - fprintf(output, " /* m */ {"); - fprintf(output, " %d", mt[0]); - for(si = 1; si < BSINC_SCALE_COUNT; si++) - fprintf(output, ", %d", mt[si]); - fprintf(output, " },\n"); - - fprintf(output, " /* filterOffset */ {"); - fprintf(output, " %d", 0); - i = mt[0]*4*BSINC_PHASE_COUNT; - for(si = 1; si < BSINC_SCALE_COUNT; si++) - { - fprintf(output, ", %d", i); - i += mt[si]*4*BSINC_PHASE_COUNT; - } - - fprintf(output, " },\n"); - - // Calculate the table size. - i = 0; - for(si = 0; si < BSINC_SCALE_COUNT; si++) - i += 4 * BSINC_PHASE_COUNT * mt[si]; - - fprintf(output, "\n /* Tab (%d entries) */ {\n", i); - for(si = 0; si < BSINC_SCALE_COUNT; si++) - { - const int m = mt[si]; - const int o = num_points_min - (m / 2); - - for(pi = 0; pi < BSINC_PHASE_COUNT; pi++) - { - fprintf(output, " /* %2d,%2d (%d) */", si, pi, m); - fprintf(output, "\n "); - for(i = 0; i < m; i++) - fprintf(output, " %+14.9ef,", filter[si][pi][o + i]); - fprintf(output, "\n "); - for(i = 0; i < m; i++) - fprintf(output, " %+14.9ef,", scDeltas[si][pi][o + i]); - fprintf(output, "\n "); - for(i = 0; i < m; i++) - fprintf(output, " %+14.9ef,", phDeltas[si][pi][o + i]); - fprintf(output, "\n "); - for(i = 0; i < m; i++) - fprintf(output, " %+14.9ef,", spDeltas[si][pi][o + i]); - fprintf(output, "\n"); - } - } - fprintf(output, " }\n};\n\n"); -} - - -/* These methods generate a much simplified 4-point sinc interpolator using a - * Kaiser window. This is much simpler to process at run-time, but has notably - * more aliasing noise. - */ - -/* Same as in alu.h! */ -#define FRACTIONBITS (12) -#define FRACTIONONE (1< 2) - { - fprintf(stderr, "Usage: %s [output file]\n", argv[0]); - return 1; - } - - if(argc == 2) - { - output = fopen(argv[1], "wb"); - if(!output) - { - fprintf(stderr, "Failed to open %s for writing\n", argv[1]); - return 1; - } - } - else - output = stdout; - - fprintf(output, "/* Generated by bsincgen, do not edit! */\n\n" -"static_assert(BSINC_SCALE_COUNT == %d, \"Unexpected BSINC_SCALE_COUNT value!\");\n" -"static_assert(BSINC_PHASE_COUNT == %d, \"Unexpected BSINC_PHASE_COUNT value!\");\n" -"static_assert(FRACTIONONE == %d, \"Unexpected FRACTIONONE value!\");\n\n" -"typedef struct BSincTable {\n" -" const float scaleBase, scaleRange;\n" -" const int m[BSINC_SCALE_COUNT];\n" -" const int filterOffset[BSINC_SCALE_COUNT];\n" -" alignas(16) const float Tab[];\n" -"} BSincTable;\n\n", BSINC_SCALE_COUNT, BSINC_PHASE_COUNT, FRACTIONONE); - /* A 23rd order filter with a -60dB drop at nyquist. */ - BsiGenerateTables(output, "bsinc24", 60.0, 23); - /* An 11th order filter with a -60dB drop at nyquist. */ - BsiGenerateTables(output, "bsinc12", 60.0, 11); - Sinc4GenerateTables(output, 60.0); - - if(output != stdout) - fclose(output); - output = NULL; - - return 0; -} -- cgit v1.2.3 From e5442db803b5ecac2bbbe45073e01de32431c0a5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 17:22:32 -0800 Subject: Convert the filters to C++ --- Alc/filters/filter.c | 123 -------------- Alc/filters/filter.cpp | 123 ++++++++++++++ Alc/filters/nfc.c | 426 ------------------------------------------------- Alc/filters/nfc.cpp | 426 +++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 4 +- 5 files changed, 551 insertions(+), 551 deletions(-) delete mode 100644 Alc/filters/filter.c create mode 100644 Alc/filters/filter.cpp delete mode 100644 Alc/filters/nfc.c create mode 100644 Alc/filters/nfc.cpp diff --git a/Alc/filters/filter.c b/Alc/filters/filter.c deleted file mode 100644 index 838a9a5d..00000000 --- a/Alc/filters/filter.c +++ /dev/null @@ -1,123 +0,0 @@ - -#include "config.h" - -#include "AL/alc.h" -#include "AL/al.h" - -#include "alMain.h" -#include "defs.h" - - -void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ) -{ - ALfloat alpha, sqrtgain_alpha_2; - ALfloat w0, sin_w0, cos_w0; - ALfloat a[3] = { 1.0f, 0.0f, 0.0f }; - ALfloat b[3] = { 1.0f, 0.0f, 0.0f }; - - // Limit gain to -100dB - assert(gain > 0.00001f); - - w0 = F_TAU * f0norm; - sin_w0 = sinf(w0); - cos_w0 = cosf(w0); - alpha = sin_w0/2.0f * rcpQ; - - /* Calculate filter coefficients depending on filter type */ - switch(type) - { - case BiquadType_HighShelf: - sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha; - b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); - b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 ); - b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); - a[0] = (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; - a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 ); - a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; - break; - case BiquadType_LowShelf: - sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha; - b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); - b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 ); - b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); - a[0] = (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; - a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 ); - a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; - break; - case BiquadType_Peaking: - gain = sqrtf(gain); - b[0] = 1.0f + alpha * gain; - b[1] = -2.0f * cos_w0; - b[2] = 1.0f - alpha * gain; - a[0] = 1.0f + alpha / gain; - a[1] = -2.0f * cos_w0; - a[2] = 1.0f - alpha / gain; - break; - - case BiquadType_LowPass: - b[0] = (1.0f - cos_w0) / 2.0f; - b[1] = 1.0f - cos_w0; - b[2] = (1.0f - cos_w0) / 2.0f; - a[0] = 1.0f + alpha; - a[1] = -2.0f * cos_w0; - a[2] = 1.0f - alpha; - break; - case BiquadType_HighPass: - b[0] = (1.0f + cos_w0) / 2.0f; - b[1] = -(1.0f + cos_w0); - b[2] = (1.0f + cos_w0) / 2.0f; - a[0] = 1.0f + alpha; - a[1] = -2.0f * cos_w0; - a[2] = 1.0f - alpha; - break; - case BiquadType_BandPass: - b[0] = alpha; - b[1] = 0; - b[2] = -alpha; - a[0] = 1.0f + alpha; - a[1] = -2.0f * cos_w0; - a[2] = 1.0f - alpha; - break; - } - - filter->a1 = a[1] / a[0]; - filter->a2 = a[2] / a[0]; - filter->b0 = b[0] / a[0]; - filter->b1 = b[1] / a[0]; - filter->b2 = b[2] / a[0]; -} - - -void BiquadFilter_processC(BiquadFilter *filter, ALfloat *RESTRICT dst, const ALfloat *RESTRICT src, ALsizei numsamples) -{ - const ALfloat a1 = filter->a1; - const ALfloat a2 = filter->a2; - const ALfloat b0 = filter->b0; - const ALfloat b1 = filter->b1; - const ALfloat b2 = filter->b2; - ALfloat z1 = filter->z1; - ALfloat z2 = filter->z2; - ALsizei i; - - ASSUME(numsamples > 0); - - /* Processing loop is Transposed Direct Form II. This requires less storage - * compared to Direct Form I (only two delay components, instead of a four- - * sample history; the last two inputs and outputs), and works better for - * floating-point which favors summing similarly-sized values while being - * less bothered by overflow. - * - * See: http://www.earlevel.com/main/2003/02/28/biquads/ - */ - for(i = 0;i < numsamples;i++) - { - ALfloat input = src[i]; - ALfloat output = input*b0 + z1; - z1 = input*b1 - output*a1 + z2; - z2 = input*b2 - output*a2; - dst[i] = output; - } - - filter->z1 = z1; - filter->z2 = z2; -} diff --git a/Alc/filters/filter.cpp b/Alc/filters/filter.cpp new file mode 100644 index 00000000..838a9a5d --- /dev/null +++ b/Alc/filters/filter.cpp @@ -0,0 +1,123 @@ + +#include "config.h" + +#include "AL/alc.h" +#include "AL/al.h" + +#include "alMain.h" +#include "defs.h" + + +void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ) +{ + ALfloat alpha, sqrtgain_alpha_2; + ALfloat w0, sin_w0, cos_w0; + ALfloat a[3] = { 1.0f, 0.0f, 0.0f }; + ALfloat b[3] = { 1.0f, 0.0f, 0.0f }; + + // Limit gain to -100dB + assert(gain > 0.00001f); + + w0 = F_TAU * f0norm; + sin_w0 = sinf(w0); + cos_w0 = cosf(w0); + alpha = sin_w0/2.0f * rcpQ; + + /* Calculate filter coefficients depending on filter type */ + switch(type) + { + case BiquadType_HighShelf: + sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha; + b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); + b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 ); + b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); + a[0] = (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; + a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 ); + a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; + break; + case BiquadType_LowShelf: + sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha; + b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); + b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 ); + b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); + a[0] = (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; + a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 ); + a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; + break; + case BiquadType_Peaking: + gain = sqrtf(gain); + b[0] = 1.0f + alpha * gain; + b[1] = -2.0f * cos_w0; + b[2] = 1.0f - alpha * gain; + a[0] = 1.0f + alpha / gain; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha / gain; + break; + + case BiquadType_LowPass: + b[0] = (1.0f - cos_w0) / 2.0f; + b[1] = 1.0f - cos_w0; + b[2] = (1.0f - cos_w0) / 2.0f; + a[0] = 1.0f + alpha; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha; + break; + case BiquadType_HighPass: + b[0] = (1.0f + cos_w0) / 2.0f; + b[1] = -(1.0f + cos_w0); + b[2] = (1.0f + cos_w0) / 2.0f; + a[0] = 1.0f + alpha; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha; + break; + case BiquadType_BandPass: + b[0] = alpha; + b[1] = 0; + b[2] = -alpha; + a[0] = 1.0f + alpha; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha; + break; + } + + filter->a1 = a[1] / a[0]; + filter->a2 = a[2] / a[0]; + filter->b0 = b[0] / a[0]; + filter->b1 = b[1] / a[0]; + filter->b2 = b[2] / a[0]; +} + + +void BiquadFilter_processC(BiquadFilter *filter, ALfloat *RESTRICT dst, const ALfloat *RESTRICT src, ALsizei numsamples) +{ + const ALfloat a1 = filter->a1; + const ALfloat a2 = filter->a2; + const ALfloat b0 = filter->b0; + const ALfloat b1 = filter->b1; + const ALfloat b2 = filter->b2; + ALfloat z1 = filter->z1; + ALfloat z2 = filter->z2; + ALsizei i; + + ASSUME(numsamples > 0); + + /* Processing loop is Transposed Direct Form II. This requires less storage + * compared to Direct Form I (only two delay components, instead of a four- + * sample history; the last two inputs and outputs), and works better for + * floating-point which favors summing similarly-sized values while being + * less bothered by overflow. + * + * See: http://www.earlevel.com/main/2003/02/28/biquads/ + */ + for(i = 0;i < numsamples;i++) + { + ALfloat input = src[i]; + ALfloat output = input*b0 + z1; + z1 = input*b1 - output*a1 + z2; + z2 = input*b2 - output*a2; + dst[i] = output; + } + + filter->z1 = z1; + filter->z2 = z2; +} diff --git a/Alc/filters/nfc.c b/Alc/filters/nfc.c deleted file mode 100644 index 8d61bb37..00000000 --- a/Alc/filters/nfc.c +++ /dev/null @@ -1,426 +0,0 @@ - -#include "config.h" - -#include "nfc.h" -#include "alMain.h" - -#include - - -/* Near-field control filters are the basis for handling the near-field effect. - * The near-field effect is a bass-boost present in the directional components - * of a recorded signal, created as a result of the wavefront curvature (itself - * a function of sound distance). Proper reproduction dictates this be - * compensated for using a bass-cut given the playback speaker distance, to - * avoid excessive bass in the playback. - * - * For real-time rendered audio, emulating the near-field effect based on the - * sound source's distance, and subsequently compensating for it at output - * based on the speaker distances, can create a more realistic perception of - * sound distance beyond a simple 1/r attenuation. - * - * These filters do just that. Each one applies a low-shelf filter, created as - * the combination of a bass-boost for a given sound source distance (near- - * field emulation) along with a bass-cut for a given control/speaker distance - * (near-field compensation). - * - * Note that it is necessary to apply a cut along with the boost, since the - * boost alone is unstable in higher-order ambisonics as it causes an infinite - * DC gain (even first-order ambisonics requires there to be no DC offset for - * the boost to work). Consequently, ambisonics requires a control parameter to - * be used to avoid an unstable boost-only filter. NFC-HOA defines this control - * as a reference delay, calculated with: - * - * reference_delay = control_distance / speed_of_sound - * - * This means w0 (for input) or w1 (for output) should be set to: - * - * wN = 1 / (reference_delay * sample_rate) - * - * when dealing with NFC-HOA content. For FOA input content, which does not - * specify a reference_delay variable, w0 should be set to 0 to apply only - * near-field compensation for output. It's important that w1 be a finite, - * positive, non-0 value or else the bass-boost will become unstable again. - * Also, w0 should not be too large compared to w1, to avoid excessively loud - * low frequencies. - */ - -static const float B[4][3] = { - { 0.0f }, - { 1.0f }, - { 3.0f, 3.0f }, - { 3.6778f, 6.4595f, 2.3222f }, - /*{ 4.2076f, 11.4877f, 5.7924f, 9.1401f }*/ -}; - -static void NfcFilterCreate1(struct NfcFilter1 *nfc, const float w0, const float w1) -{ - float b_00, g_0; - float r; - - nfc->base_gain = 1.0f; - nfc->gain = 1.0f; - - /* Calculate bass-boost coefficients. */ - r = 0.5f * w0; - b_00 = B[1][0] * r; - g_0 = 1.0f + b_00; - - nfc->gain *= g_0; - nfc->b1 = 2.0f * b_00 / g_0; - - /* Calculate bass-cut coefficients. */ - r = 0.5f * w1; - b_00 = B[1][0] * r; - g_0 = 1.0f + b_00; - - nfc->base_gain /= g_0; - nfc->gain /= g_0; - nfc->a1 = 2.0f * b_00 / g_0; -} - -static void NfcFilterAdjust1(struct NfcFilter1 *nfc, const float w0) -{ - float b_00, g_0; - float r; - - r = 0.5f * w0; - b_00 = B[1][0] * r; - g_0 = 1.0f + b_00; - - nfc->gain = nfc->base_gain * g_0; - nfc->b1 = 2.0f * b_00 / g_0; -} - - -static void NfcFilterCreate2(struct NfcFilter2 *nfc, const float w0, const float w1) -{ - float b_10, b_11, g_1; - float r; - - nfc->base_gain = 1.0f; - nfc->gain = 1.0f; - - /* Calculate bass-boost coefficients. */ - r = 0.5f * w0; - b_10 = B[2][0] * r; - b_11 = B[2][1] * r * r; - g_1 = 1.0f + b_10 + b_11; - - nfc->gain *= g_1; - nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; - nfc->b2 = 4.0f * b_11 / g_1; - - /* Calculate bass-cut coefficients. */ - r = 0.5f * w1; - b_10 = B[2][0] * r; - b_11 = B[2][1] * r * r; - g_1 = 1.0f + b_10 + b_11; - - nfc->base_gain /= g_1; - nfc->gain /= g_1; - nfc->a1 = (2.0f*b_10 + 4.0f*b_11) / g_1; - nfc->a2 = 4.0f * b_11 / g_1; -} - -static void NfcFilterAdjust2(struct NfcFilter2 *nfc, const float w0) -{ - float b_10, b_11, g_1; - float r; - - r = 0.5f * w0; - b_10 = B[2][0] * r; - b_11 = B[2][1] * r * r; - g_1 = 1.0f + b_10 + b_11; - - nfc->gain = nfc->base_gain * g_1; - nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; - nfc->b2 = 4.0f * b_11 / g_1; -} - - -static void NfcFilterCreate3(struct NfcFilter3 *nfc, const float w0, const float w1) -{ - float b_10, b_11, g_1; - float b_00, g_0; - float r; - - nfc->base_gain = 1.0f; - nfc->gain = 1.0f; - - /* Calculate bass-boost coefficients. */ - r = 0.5f * w0; - b_10 = B[3][0] * r; - b_11 = B[3][1] * r * r; - g_1 = 1.0f + b_10 + b_11; - - nfc->gain *= g_1; - nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; - nfc->b2 = 4.0f * b_11 / g_1; - - b_00 = B[3][2] * r; - g_0 = 1.0f + b_00; - - nfc->gain *= g_0; - nfc->b3 = 2.0f * b_00 / g_0; - - /* Calculate bass-cut coefficients. */ - r = 0.5f * w1; - b_10 = B[3][0] * r; - b_11 = B[3][1] * r * r; - g_1 = 1.0f + b_10 + b_11; - - nfc->base_gain /= g_1; - nfc->gain /= g_1; - nfc->a1 = (2.0f*b_10 + 4.0f*b_11) / g_1; - nfc->a2 = 4.0f * b_11 / g_1; - - b_00 = B[3][2] * r; - g_0 = 1.0f + b_00; - - nfc->base_gain /= g_0; - nfc->gain /= g_0; - nfc->a3 = 2.0f * b_00 / g_0; -} - -static void NfcFilterAdjust3(struct NfcFilter3 *nfc, const float w0) -{ - float b_10, b_11, g_1; - float b_00, g_0; - float r; - - r = 0.5f * w0; - b_10 = B[3][0] * r; - b_11 = B[3][1] * r * r; - g_1 = 1.0f + b_10 + b_11; - - nfc->gain = nfc->base_gain * g_1; - nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; - nfc->b2 = 4.0f * b_11 / g_1; - - b_00 = B[3][2] * r; - g_0 = 1.0f + b_00; - - nfc->gain *= g_0; - nfc->b3 = 2.0f * b_00 / g_0; -} - - -void NfcFilterCreate(NfcFilter *nfc, const float w0, const float w1) -{ - memset(nfc, 0, sizeof(*nfc)); - NfcFilterCreate1(&nfc->first, w0, w1); - NfcFilterCreate2(&nfc->second, w0, w1); - NfcFilterCreate3(&nfc->third, w0, w1); -} - -void NfcFilterAdjust(NfcFilter *nfc, const float w0) -{ - NfcFilterAdjust1(&nfc->first, w0); - NfcFilterAdjust2(&nfc->second, w0); - NfcFilterAdjust3(&nfc->third, w0); -} - - -void NfcFilterProcess1(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRICT src, const int count) -{ - const float gain = nfc->first.gain; - const float b1 = nfc->first.b1; - const float a1 = nfc->first.a1; - float z1 = nfc->first.z[0]; - int i; - - ASSUME(count > 0); - - for(i = 0;i < count;i++) - { - float y = src[i]*gain - a1*z1; - float out = y + b1*z1; - z1 += y; - - dst[i] = out; - } - nfc->first.z[0] = z1; -} - -void NfcFilterProcess2(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRICT src, const int count) -{ - const float gain = nfc->second.gain; - const float b1 = nfc->second.b1; - const float b2 = nfc->second.b2; - const float a1 = nfc->second.a1; - const float a2 = nfc->second.a2; - float z1 = nfc->second.z[0]; - float z2 = nfc->second.z[1]; - int i; - - ASSUME(count > 0); - - for(i = 0;i < count;i++) - { - float y = src[i]*gain - a1*z1 - a2*z2; - float out = y + b1*z1 + b2*z2; - z2 += z1; - z1 += y; - - dst[i] = out; - } - nfc->second.z[0] = z1; - nfc->second.z[1] = z2; -} - -void NfcFilterProcess3(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRICT src, const int count) -{ - const float gain = nfc->third.gain; - const float b1 = nfc->third.b1; - const float b2 = nfc->third.b2; - const float b3 = nfc->third.b3; - const float a1 = nfc->third.a1; - const float a2 = nfc->third.a2; - const float a3 = nfc->third.a3; - float z1 = nfc->third.z[0]; - float z2 = nfc->third.z[1]; - float z3 = nfc->third.z[2]; - int i; - - ASSUME(count > 0); - - for(i = 0;i < count;i++) - { - float y = src[i]*gain - a1*z1 - a2*z2; - float out = y + b1*z1 + b2*z2; - z2 += z1; - z1 += y; - - y = out - a3*z3; - out = y + b3*z3; - z3 += y; - - dst[i] = out; - } - nfc->third.z[0] = z1; - nfc->third.z[1] = z2; - nfc->third.z[2] = z3; -} - -#if 0 /* Original methods the above are derived from. */ -static void NfcFilterCreate(NfcFilter *nfc, const ALsizei order, const float src_dist, const float ctl_dist, const float rate) -{ - static const float B[4][5] = { - { }, - { 1.0f }, - { 3.0f, 3.0f }, - { 3.6778f, 6.4595f, 2.3222f }, - { 4.2076f, 11.4877f, 5.7924f, 9.1401f } - }; - float w0 = SPEEDOFSOUNDMETRESPERSEC / (src_dist * rate); - float w1 = SPEEDOFSOUNDMETRESPERSEC / (ctl_dist * rate); - ALsizei i; - float r; - - nfc->g = 1.0f; - nfc->coeffs[0] = 1.0f; - - /* NOTE: Slight adjustment from the literature to raise the center - * frequency a bit (0.5 -> 1.0). - */ - r = 1.0f * w0; - for(i = 0; i < (order-1);i += 2) - { - float b_10 = B[order][i ] * r; - float b_11 = B[order][i+1] * r * r; - float g_1 = 1.0f + b_10 + b_11; - - nfc->b[i] = b_10; - nfc->b[i + 1] = b_11; - nfc->coeffs[0] *= g_1; - nfc->coeffs[i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[i+2] = (4.0f * b_11) / g_1; - } - if(i < order) - { - float b_00 = B[order][i] * r; - float g_0 = 1.0f + b_00; - - nfc->b[i] = b_00; - nfc->coeffs[0] *= g_0; - nfc->coeffs[i+1] = (2.0f * b_00) / g_0; - } - - r = 1.0f * w1; - for(i = 0;i < (order-1);i += 2) - { - float b_10 = B[order][i ] * r; - float b_11 = B[order][i+1] * r * r; - float g_1 = 1.0f + b_10 + b_11; - - nfc->g /= g_1; - nfc->coeffs[0] /= g_1; - nfc->coeffs[order+i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[order+i+2] = (4.0f * b_11) / g_1; - } - if(i < order) - { - float b_00 = B[order][i] * r; - float g_0 = 1.0f + b_00; - - nfc->g /= g_0; - nfc->coeffs[0] /= g_0; - nfc->coeffs[order+i+1] = (2.0f * b_00) / g_0; - } - - for(i = 0; i < MAX_AMBI_ORDER; i++) - nfc->history[i] = 0.0f; -} - -static void NfcFilterAdjust(NfcFilter *nfc, const float distance) -{ - int i; - - nfc->coeffs[0] = nfc->g; - - for(i = 0;i < (nfc->order-1);i += 2) - { - float b_10 = nfc->b[i] / distance; - float b_11 = nfc->b[i+1] / (distance * distance); - float g_1 = 1.0f + b_10 + b_11; - - nfc->coeffs[0] *= g_1; - nfc->coeffs[i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[i+2] = (4.0f * b_11) / g_1; - } - if(i < nfc->order) - { - float b_00 = nfc->b[i] / distance; - float g_0 = 1.0f + b_00; - - nfc->coeffs[0] *= g_0; - nfc->coeffs[i+1] = (2.0f * b_00) / g_0; - } -} - -static float NfcFilterProcess(const float in, NfcFilter *nfc) -{ - int i; - float out = in * nfc->coeffs[0]; - - for(i = 0;i < (nfc->order-1);i += 2) - { - float y = out - (nfc->coeffs[nfc->order+i+1] * nfc->history[i]) - - (nfc->coeffs[nfc->order+i+2] * nfc->history[i+1]) + 1.0e-30f; - out = y + (nfc->coeffs[i+1]*nfc->history[i]) + (nfc->coeffs[i+2]*nfc->history[i+1]); - - nfc->history[i+1] += nfc->history[i]; - nfc->history[i] += y; - } - if(i < nfc->order) - { - float y = out - (nfc->coeffs[nfc->order+i+1] * nfc->history[i]) + 1.0e-30f; - - out = y + (nfc->coeffs[i+1] * nfc->history[i]); - nfc->history[i] += y; - } - - return out; -} -#endif diff --git a/Alc/filters/nfc.cpp b/Alc/filters/nfc.cpp new file mode 100644 index 00000000..8d61bb37 --- /dev/null +++ b/Alc/filters/nfc.cpp @@ -0,0 +1,426 @@ + +#include "config.h" + +#include "nfc.h" +#include "alMain.h" + +#include + + +/* Near-field control filters are the basis for handling the near-field effect. + * The near-field effect is a bass-boost present in the directional components + * of a recorded signal, created as a result of the wavefront curvature (itself + * a function of sound distance). Proper reproduction dictates this be + * compensated for using a bass-cut given the playback speaker distance, to + * avoid excessive bass in the playback. + * + * For real-time rendered audio, emulating the near-field effect based on the + * sound source's distance, and subsequently compensating for it at output + * based on the speaker distances, can create a more realistic perception of + * sound distance beyond a simple 1/r attenuation. + * + * These filters do just that. Each one applies a low-shelf filter, created as + * the combination of a bass-boost for a given sound source distance (near- + * field emulation) along with a bass-cut for a given control/speaker distance + * (near-field compensation). + * + * Note that it is necessary to apply a cut along with the boost, since the + * boost alone is unstable in higher-order ambisonics as it causes an infinite + * DC gain (even first-order ambisonics requires there to be no DC offset for + * the boost to work). Consequently, ambisonics requires a control parameter to + * be used to avoid an unstable boost-only filter. NFC-HOA defines this control + * as a reference delay, calculated with: + * + * reference_delay = control_distance / speed_of_sound + * + * This means w0 (for input) or w1 (for output) should be set to: + * + * wN = 1 / (reference_delay * sample_rate) + * + * when dealing with NFC-HOA content. For FOA input content, which does not + * specify a reference_delay variable, w0 should be set to 0 to apply only + * near-field compensation for output. It's important that w1 be a finite, + * positive, non-0 value or else the bass-boost will become unstable again. + * Also, w0 should not be too large compared to w1, to avoid excessively loud + * low frequencies. + */ + +static const float B[4][3] = { + { 0.0f }, + { 1.0f }, + { 3.0f, 3.0f }, + { 3.6778f, 6.4595f, 2.3222f }, + /*{ 4.2076f, 11.4877f, 5.7924f, 9.1401f }*/ +}; + +static void NfcFilterCreate1(struct NfcFilter1 *nfc, const float w0, const float w1) +{ + float b_00, g_0; + float r; + + nfc->base_gain = 1.0f; + nfc->gain = 1.0f; + + /* Calculate bass-boost coefficients. */ + r = 0.5f * w0; + b_00 = B[1][0] * r; + g_0 = 1.0f + b_00; + + nfc->gain *= g_0; + nfc->b1 = 2.0f * b_00 / g_0; + + /* Calculate bass-cut coefficients. */ + r = 0.5f * w1; + b_00 = B[1][0] * r; + g_0 = 1.0f + b_00; + + nfc->base_gain /= g_0; + nfc->gain /= g_0; + nfc->a1 = 2.0f * b_00 / g_0; +} + +static void NfcFilterAdjust1(struct NfcFilter1 *nfc, const float w0) +{ + float b_00, g_0; + float r; + + r = 0.5f * w0; + b_00 = B[1][0] * r; + g_0 = 1.0f + b_00; + + nfc->gain = nfc->base_gain * g_0; + nfc->b1 = 2.0f * b_00 / g_0; +} + + +static void NfcFilterCreate2(struct NfcFilter2 *nfc, const float w0, const float w1) +{ + float b_10, b_11, g_1; + float r; + + nfc->base_gain = 1.0f; + nfc->gain = 1.0f; + + /* Calculate bass-boost coefficients. */ + r = 0.5f * w0; + b_10 = B[2][0] * r; + b_11 = B[2][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc->gain *= g_1; + nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc->b2 = 4.0f * b_11 / g_1; + + /* Calculate bass-cut coefficients. */ + r = 0.5f * w1; + b_10 = B[2][0] * r; + b_11 = B[2][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc->base_gain /= g_1; + nfc->gain /= g_1; + nfc->a1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc->a2 = 4.0f * b_11 / g_1; +} + +static void NfcFilterAdjust2(struct NfcFilter2 *nfc, const float w0) +{ + float b_10, b_11, g_1; + float r; + + r = 0.5f * w0; + b_10 = B[2][0] * r; + b_11 = B[2][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc->gain = nfc->base_gain * g_1; + nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc->b2 = 4.0f * b_11 / g_1; +} + + +static void NfcFilterCreate3(struct NfcFilter3 *nfc, const float w0, const float w1) +{ + float b_10, b_11, g_1; + float b_00, g_0; + float r; + + nfc->base_gain = 1.0f; + nfc->gain = 1.0f; + + /* Calculate bass-boost coefficients. */ + r = 0.5f * w0; + b_10 = B[3][0] * r; + b_11 = B[3][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc->gain *= g_1; + nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc->b2 = 4.0f * b_11 / g_1; + + b_00 = B[3][2] * r; + g_0 = 1.0f + b_00; + + nfc->gain *= g_0; + nfc->b3 = 2.0f * b_00 / g_0; + + /* Calculate bass-cut coefficients. */ + r = 0.5f * w1; + b_10 = B[3][0] * r; + b_11 = B[3][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc->base_gain /= g_1; + nfc->gain /= g_1; + nfc->a1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc->a2 = 4.0f * b_11 / g_1; + + b_00 = B[3][2] * r; + g_0 = 1.0f + b_00; + + nfc->base_gain /= g_0; + nfc->gain /= g_0; + nfc->a3 = 2.0f * b_00 / g_0; +} + +static void NfcFilterAdjust3(struct NfcFilter3 *nfc, const float w0) +{ + float b_10, b_11, g_1; + float b_00, g_0; + float r; + + r = 0.5f * w0; + b_10 = B[3][0] * r; + b_11 = B[3][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc->gain = nfc->base_gain * g_1; + nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc->b2 = 4.0f * b_11 / g_1; + + b_00 = B[3][2] * r; + g_0 = 1.0f + b_00; + + nfc->gain *= g_0; + nfc->b3 = 2.0f * b_00 / g_0; +} + + +void NfcFilterCreate(NfcFilter *nfc, const float w0, const float w1) +{ + memset(nfc, 0, sizeof(*nfc)); + NfcFilterCreate1(&nfc->first, w0, w1); + NfcFilterCreate2(&nfc->second, w0, w1); + NfcFilterCreate3(&nfc->third, w0, w1); +} + +void NfcFilterAdjust(NfcFilter *nfc, const float w0) +{ + NfcFilterAdjust1(&nfc->first, w0); + NfcFilterAdjust2(&nfc->second, w0); + NfcFilterAdjust3(&nfc->third, w0); +} + + +void NfcFilterProcess1(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRICT src, const int count) +{ + const float gain = nfc->first.gain; + const float b1 = nfc->first.b1; + const float a1 = nfc->first.a1; + float z1 = nfc->first.z[0]; + int i; + + ASSUME(count > 0); + + for(i = 0;i < count;i++) + { + float y = src[i]*gain - a1*z1; + float out = y + b1*z1; + z1 += y; + + dst[i] = out; + } + nfc->first.z[0] = z1; +} + +void NfcFilterProcess2(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRICT src, const int count) +{ + const float gain = nfc->second.gain; + const float b1 = nfc->second.b1; + const float b2 = nfc->second.b2; + const float a1 = nfc->second.a1; + const float a2 = nfc->second.a2; + float z1 = nfc->second.z[0]; + float z2 = nfc->second.z[1]; + int i; + + ASSUME(count > 0); + + for(i = 0;i < count;i++) + { + float y = src[i]*gain - a1*z1 - a2*z2; + float out = y + b1*z1 + b2*z2; + z2 += z1; + z1 += y; + + dst[i] = out; + } + nfc->second.z[0] = z1; + nfc->second.z[1] = z2; +} + +void NfcFilterProcess3(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRICT src, const int count) +{ + const float gain = nfc->third.gain; + const float b1 = nfc->third.b1; + const float b2 = nfc->third.b2; + const float b3 = nfc->third.b3; + const float a1 = nfc->third.a1; + const float a2 = nfc->third.a2; + const float a3 = nfc->third.a3; + float z1 = nfc->third.z[0]; + float z2 = nfc->third.z[1]; + float z3 = nfc->third.z[2]; + int i; + + ASSUME(count > 0); + + for(i = 0;i < count;i++) + { + float y = src[i]*gain - a1*z1 - a2*z2; + float out = y + b1*z1 + b2*z2; + z2 += z1; + z1 += y; + + y = out - a3*z3; + out = y + b3*z3; + z3 += y; + + dst[i] = out; + } + nfc->third.z[0] = z1; + nfc->third.z[1] = z2; + nfc->third.z[2] = z3; +} + +#if 0 /* Original methods the above are derived from. */ +static void NfcFilterCreate(NfcFilter *nfc, const ALsizei order, const float src_dist, const float ctl_dist, const float rate) +{ + static const float B[4][5] = { + { }, + { 1.0f }, + { 3.0f, 3.0f }, + { 3.6778f, 6.4595f, 2.3222f }, + { 4.2076f, 11.4877f, 5.7924f, 9.1401f } + }; + float w0 = SPEEDOFSOUNDMETRESPERSEC / (src_dist * rate); + float w1 = SPEEDOFSOUNDMETRESPERSEC / (ctl_dist * rate); + ALsizei i; + float r; + + nfc->g = 1.0f; + nfc->coeffs[0] = 1.0f; + + /* NOTE: Slight adjustment from the literature to raise the center + * frequency a bit (0.5 -> 1.0). + */ + r = 1.0f * w0; + for(i = 0; i < (order-1);i += 2) + { + float b_10 = B[order][i ] * r; + float b_11 = B[order][i+1] * r * r; + float g_1 = 1.0f + b_10 + b_11; + + nfc->b[i] = b_10; + nfc->b[i + 1] = b_11; + nfc->coeffs[0] *= g_1; + nfc->coeffs[i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[i+2] = (4.0f * b_11) / g_1; + } + if(i < order) + { + float b_00 = B[order][i] * r; + float g_0 = 1.0f + b_00; + + nfc->b[i] = b_00; + nfc->coeffs[0] *= g_0; + nfc->coeffs[i+1] = (2.0f * b_00) / g_0; + } + + r = 1.0f * w1; + for(i = 0;i < (order-1);i += 2) + { + float b_10 = B[order][i ] * r; + float b_11 = B[order][i+1] * r * r; + float g_1 = 1.0f + b_10 + b_11; + + nfc->g /= g_1; + nfc->coeffs[0] /= g_1; + nfc->coeffs[order+i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[order+i+2] = (4.0f * b_11) / g_1; + } + if(i < order) + { + float b_00 = B[order][i] * r; + float g_0 = 1.0f + b_00; + + nfc->g /= g_0; + nfc->coeffs[0] /= g_0; + nfc->coeffs[order+i+1] = (2.0f * b_00) / g_0; + } + + for(i = 0; i < MAX_AMBI_ORDER; i++) + nfc->history[i] = 0.0f; +} + +static void NfcFilterAdjust(NfcFilter *nfc, const float distance) +{ + int i; + + nfc->coeffs[0] = nfc->g; + + for(i = 0;i < (nfc->order-1);i += 2) + { + float b_10 = nfc->b[i] / distance; + float b_11 = nfc->b[i+1] / (distance * distance); + float g_1 = 1.0f + b_10 + b_11; + + nfc->coeffs[0] *= g_1; + nfc->coeffs[i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[i+2] = (4.0f * b_11) / g_1; + } + if(i < nfc->order) + { + float b_00 = nfc->b[i] / distance; + float g_0 = 1.0f + b_00; + + nfc->coeffs[0] *= g_0; + nfc->coeffs[i+1] = (2.0f * b_00) / g_0; + } +} + +static float NfcFilterProcess(const float in, NfcFilter *nfc) +{ + int i; + float out = in * nfc->coeffs[0]; + + for(i = 0;i < (nfc->order-1);i += 2) + { + float y = out - (nfc->coeffs[nfc->order+i+1] * nfc->history[i]) - + (nfc->coeffs[nfc->order+i+2] * nfc->history[i+1]) + 1.0e-30f; + out = y + (nfc->coeffs[i+1]*nfc->history[i]) + (nfc->coeffs[i+2]*nfc->history[i+1]); + + nfc->history[i+1] += nfc->history[i]; + nfc->history[i] += y; + } + if(i < nfc->order) + { + float y = out - (nfc->coeffs[nfc->order+i+1] * nfc->history[i]) + 1.0e-30f; + + out = y + (nfc->coeffs[i+1] * nfc->history[i]); + nfc->history[i] += y; + } + + return out; +} +#endif diff --git a/CMakeLists.txt b/CMakeLists.txt index 19dc0439..cca21465 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -821,8 +821,8 @@ SET(ALC_OBJS Alc/effects/pshifter.cpp Alc/effects/reverb.cpp Alc/filters/defs.h - Alc/filters/filter.c - Alc/filters/nfc.c + Alc/filters/filter.cpp + Alc/filters/nfc.cpp Alc/filters/nfc.h Alc/filters/splitter.cpp Alc/filters/splitter.h -- cgit v1.2.3 From 2d4ff77410d4fe647950c4e06dbe1c5536235796 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 17:32:32 -0800 Subject: Remove ASSUME_ALIGNED It's become a liability with C++ since it returns void* instead of the input pointer type, and it doesn't seem to help optimizations anyway (auto- vectorization still produces unaligned loads and stores). --- Alc/mixer/hrtf_inc.c | 6 +++--- Alc/mixer/mixer_c.c | 8 ++++---- Alc/mixer/mixer_neon.c | 13 +++++-------- Alc/mixer/mixer_sse.c | 10 ++++------ CMakeLists.txt | 13 ------------- config.h.in | 3 --- 6 files changed, 16 insertions(+), 37 deletions(-) diff --git a/Alc/mixer/hrtf_inc.c b/Alc/mixer/hrtf_inc.c index 21840abd..1f70242d 100644 --- a/Alc/mixer/hrtf_inc.c +++ b/Alc/mixer/hrtf_inc.c @@ -20,7 +20,7 @@ void MixHrtf(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALsizei IrSize, MixHrtfParams *hrtfparams, HrtfState *hrtfstate, ALsizei BufferSize) { - const ALfloat (*Coeffs)[2] = ASSUME_ALIGNED(hrtfparams->Coeffs, 16); + const ALfloat (*Coeffs)[2] = hrtfparams->Coeffs; const ALsizei Delay[2] = { hrtfparams->Delay[0], hrtfparams->Delay[1] }; const ALfloat gainstep = hrtfparams->GainStep; const ALfloat gain = hrtfparams->Gain; @@ -60,11 +60,11 @@ void MixHrtfBlend(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, MixHrtfParams *newparams, HrtfState *hrtfstate, ALsizei BufferSize) { - const ALfloat (*OldCoeffs)[2] = ASSUME_ALIGNED(oldparams->Coeffs, 16); + const ALfloat (*OldCoeffs)[2] = oldparams->Coeffs; const ALsizei OldDelay[2] = { oldparams->Delay[0], oldparams->Delay[1] }; const ALfloat oldGain = oldparams->Gain; const ALfloat oldGainStep = -oldGain / (ALfloat)BufferSize; - const ALfloat (*NewCoeffs)[2] = ASSUME_ALIGNED(newparams->Coeffs, 16); + const ALfloat (*NewCoeffs)[2] = newparams->Coeffs; const ALsizei NewDelay[2] = { newparams->Delay[0], newparams->Delay[1] }; const ALfloat newGain = newparams->Gain; const ALfloat newGainStep = newparams->GainStep; diff --git a/Alc/mixer/mixer_c.c b/Alc/mixer/mixer_c.c index ea864dbc..dce6daec 100644 --- a/Alc/mixer/mixer_c.c +++ b/Alc/mixer/mixer_c.c @@ -29,10 +29,10 @@ static inline ALfloat do_bsinc(const InterpState *state, const ALfloat *RESTRICT pf = (frac & ((1<bsinc.filter + state->bsinc.m*pi*4, 16); - scd = ASSUME_ALIGNED(fil + state->bsinc.m, 16); - phd = ASSUME_ALIGNED(scd + state->bsinc.m, 16); - spd = ASSUME_ALIGNED(phd + state->bsinc.m, 16); + fil = state->bsinc.filter + state->bsinc.m*pi*4; + scd = fil + state->bsinc.m; + phd = scd + state->bsinc.m; + spd = phd + state->bsinc.m; // Apply the scale and phase interpolated filter. r = 0.0f; diff --git a/Alc/mixer/mixer_neon.c b/Alc/mixer/mixer_neon.c index a035abc7..9bc76987 100644 --- a/Alc/mixer/mixer_neon.c +++ b/Alc/mixer/mixer_neon.c @@ -91,10 +91,10 @@ const ALfloat *Resample_bsinc_Neon(const InterpState *state, #undef FRAC_PHASE_BITDIFF offset = m*pi*4; - fil = ASSUME_ALIGNED(filter + offset, 16); offset += m; - scd = ASSUME_ALIGNED(filter + offset, 16); offset += m; - phd = ASSUME_ALIGNED(filter + offset, 16); offset += m; - spd = ASSUME_ALIGNED(filter + offset, 16); + fil = (const float32x4_t*)(filter + offset); offset += m; + scd = (const float32x4_t*)(filter + offset); offset += m; + phd = (const float32x4_t*)(filter + offset); offset += m; + spd = (const float32x4_t*)(filter + offset); // Apply the scale and phase interpolated filter. r4 = vdupq_n_f32(0.0f); @@ -140,8 +140,7 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], leftright2 = vset_lane_f32(right, leftright2, 1); leftright4 = vcombine_f32(leftright2, leftright2); } - Values = ASSUME_ALIGNED(Values, 16); - Coeffs = ASSUME_ALIGNED(Coeffs, 16); + for(c = 0;c < IrSize;c += 2) { const ALsizei o0 = (Offset+c)&HRIR_MASK; @@ -172,8 +171,6 @@ void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*RESTRICT OutBuffe ASSUME(OutChans > 0); ASSUME(BufferSize > 0); - data = ASSUME_ALIGNED(data, 16); - OutBuffer = ASSUME_ALIGNED(OutBuffer, 16); for(c = 0;c < OutChans;c++) { diff --git a/Alc/mixer/mixer_sse.c b/Alc/mixer/mixer_sse.c index 34055001..d9ad2ed3 100644 --- a/Alc/mixer/mixer_sse.c +++ b/Alc/mixer/mixer_sse.c @@ -37,10 +37,10 @@ const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *RESTR #undef FRAC_PHASE_BITDIFF offset = m*pi*4; - fil = (const __m128*)ASSUME_ALIGNED(filter + offset, 16); offset += m; - scd = (const __m128*)ASSUME_ALIGNED(filter + offset, 16); offset += m; - phd = (const __m128*)ASSUME_ALIGNED(filter + offset, 16); offset += m; - spd = (const __m128*)ASSUME_ALIGNED(filter + offset, 16); + fil = (const __m128*)(filter + offset); offset += m; + scd = (const __m128*)(filter + offset); offset += m; + phd = (const __m128*)(filter + offset); offset += m; + spd = (const __m128*)(filter + offset); // Apply the scale and phase interpolated filter. r4 = _mm_setzero_ps(); @@ -85,8 +85,6 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], __m128 coeffs; ALsizei i; - Values = ASSUME_ALIGNED(Values, 16); - Coeffs = ASSUME_ALIGNED(Coeffs, 16); if((Offset&1)) { const ALsizei o0 = Offset&HRIR_MASK; diff --git a/CMakeLists.txt b/CMakeLists.txt index cca21465..d4c48fcd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -445,19 +445,6 @@ ELSE() SET(CMAKE_REQUIRED_FLAGS "${OLD_REQUIRED_FLAGS}") ENDIF() -CHECK_C_SOURCE_COMPILES(" -int main() -{ - float *ptr; - ptr = __builtin_assume_aligned(ptr, 16); - return 0; -}" HAVE___BUILTIN_ASSUME_ALIGNED) -IF(HAVE___BUILTIN_ASSUME_ALIGNED) - SET(ASSUME_ALIGNED_DECL "__builtin_assume_aligned(x, y)") -ELSE() - SET(ASSUME_ALIGNED_DECL "(x)") -ENDIF() - SET(SSE_SWITCH "") SET(SSE2_SWITCH "") SET(SSE3_SWITCH "") diff --git a/config.h.in b/config.h.in index 5a85faea..9714810c 100644 --- a/config.h.in +++ b/config.h.in @@ -5,9 +5,6 @@ /* Define any available alignment declaration */ #define ALIGN(x) ${ALIGN_DECL} -/* Define a built-in call indicating an aligned data pointer */ -#define ASSUME_ALIGNED(x, y) ${ASSUME_ALIGNED_DECL} - /* Define a restrict macro for non-aliased pointers */ #define RESTRICT ${RESTRICT_DECL} -- cgit v1.2.3 From 7f69dbb51744d3f499d70e33904e1ea1d8d0e452 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 17:49:55 -0800 Subject: Convert the mixers to C++ --- Alc/mixer/hrtf_inc.c | 128 --------------------- Alc/mixer/hrtf_inc.cpp | 128 +++++++++++++++++++++ Alc/mixer/mixer_c.c | 169 ---------------------------- Alc/mixer/mixer_c.cpp | 169 ++++++++++++++++++++++++++++ Alc/mixer/mixer_neon.c | 280 ---------------------------------------------- Alc/mixer/mixer_neon.cpp | 280 ++++++++++++++++++++++++++++++++++++++++++++++ Alc/mixer/mixer_sse.c | 248 ---------------------------------------- Alc/mixer/mixer_sse.cpp | 248 ++++++++++++++++++++++++++++++++++++++++ Alc/mixer/mixer_sse2.c | 84 -------------- Alc/mixer/mixer_sse2.cpp | 84 ++++++++++++++ Alc/mixer/mixer_sse3.c | 0 Alc/mixer/mixer_sse3.cpp | 0 Alc/mixer/mixer_sse41.c | 85 -------------- Alc/mixer/mixer_sse41.cpp | 85 ++++++++++++++ CMakeLists.txt | 22 ++-- 15 files changed, 1005 insertions(+), 1005 deletions(-) delete mode 100644 Alc/mixer/hrtf_inc.c create mode 100644 Alc/mixer/hrtf_inc.cpp delete mode 100644 Alc/mixer/mixer_c.c create mode 100644 Alc/mixer/mixer_c.cpp delete mode 100644 Alc/mixer/mixer_neon.c create mode 100644 Alc/mixer/mixer_neon.cpp delete mode 100644 Alc/mixer/mixer_sse.c create mode 100644 Alc/mixer/mixer_sse.cpp delete mode 100644 Alc/mixer/mixer_sse2.c create mode 100644 Alc/mixer/mixer_sse2.cpp delete mode 100644 Alc/mixer/mixer_sse3.c create mode 100644 Alc/mixer/mixer_sse3.cpp delete mode 100644 Alc/mixer/mixer_sse41.c create mode 100644 Alc/mixer/mixer_sse41.cpp diff --git a/Alc/mixer/hrtf_inc.c b/Alc/mixer/hrtf_inc.c deleted file mode 100644 index 1f70242d..00000000 --- a/Alc/mixer/hrtf_inc.c +++ /dev/null @@ -1,128 +0,0 @@ -#include "config.h" - -#include "alMain.h" -#include "alSource.h" - -#include "hrtf.h" -#include "align.h" -#include "alu.h" -#include "defs.h" - - -static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], - const ALsizei irSize, - const ALfloat (*RESTRICT Coeffs)[2], - ALfloat left, ALfloat right); - - -void MixHrtf(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, MixHrtfParams *hrtfparams, HrtfState *hrtfstate, - ALsizei BufferSize) -{ - const ALfloat (*Coeffs)[2] = hrtfparams->Coeffs; - const ALsizei Delay[2] = { hrtfparams->Delay[0], hrtfparams->Delay[1] }; - const ALfloat gainstep = hrtfparams->GainStep; - const ALfloat gain = hrtfparams->Gain; - ALfloat g, stepcount = 0.0f; - ALfloat left, right; - ALsizei i; - - ASSUME(IrSize >= 4); - ASSUME(BufferSize > 0); - - LeftOut += OutPos; - RightOut += OutPos; - for(i = 0;i < BufferSize;i++) - { - hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++); - - g = gain + gainstep*stepcount; - left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK]*g; - right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK]*g; - - hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f; - hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f; - - ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right); - *(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0]; - *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1]; - - stepcount += 1.0f; - Offset++; - } - hrtfparams->Gain = gain + gainstep*stepcount; -} - -void MixHrtfBlend(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, const HrtfParams *oldparams, - MixHrtfParams *newparams, HrtfState *hrtfstate, - ALsizei BufferSize) -{ - const ALfloat (*OldCoeffs)[2] = oldparams->Coeffs; - const ALsizei OldDelay[2] = { oldparams->Delay[0], oldparams->Delay[1] }; - const ALfloat oldGain = oldparams->Gain; - const ALfloat oldGainStep = -oldGain / (ALfloat)BufferSize; - const ALfloat (*NewCoeffs)[2] = newparams->Coeffs; - const ALsizei NewDelay[2] = { newparams->Delay[0], newparams->Delay[1] }; - const ALfloat newGain = newparams->Gain; - const ALfloat newGainStep = newparams->GainStep; - ALfloat g, stepcount = 0.0f; - ALfloat left, right; - ALsizei i; - - ASSUME(IrSize >= 4); - ASSUME(BufferSize > 0); - - LeftOut += OutPos; - RightOut += OutPos; - for(i = 0;i < BufferSize;i++) - { - hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f; - hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f; - - hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++); - - g = oldGain + oldGainStep*stepcount; - left = hrtfstate->History[(Offset-OldDelay[0])&HRTF_HISTORY_MASK]*g; - right = hrtfstate->History[(Offset-OldDelay[1])&HRTF_HISTORY_MASK]*g; - ApplyCoeffs(Offset, hrtfstate->Values, IrSize, OldCoeffs, left, right); - - g = newGain + newGainStep*stepcount; - left = hrtfstate->History[(Offset-NewDelay[0])&HRTF_HISTORY_MASK]*g; - right = hrtfstate->History[(Offset-NewDelay[1])&HRTF_HISTORY_MASK]*g; - ApplyCoeffs(Offset, hrtfstate->Values, IrSize, NewCoeffs, left, right); - - *(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0]; - *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1]; - - stepcount += 1.0f; - Offset++; - } - newparams->Gain = newGain + newGainStep*stepcount; -} - -void MixDirectHrtf(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - const ALfloat (*RESTRICT Coeffs)[2], ALfloat (*RESTRICT Values)[2], - ALsizei BufferSize) -{ - ALfloat insample; - ALsizei i; - - ASSUME(IrSize >= 4); - ASSUME(BufferSize > 0); - - for(i = 0;i < BufferSize;i++) - { - Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; - Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; - Offset++; - - insample = *(data++); - ApplyCoeffs(Offset, Values, IrSize, Coeffs, insample, insample); - *(LeftOut++) += Values[Offset&HRIR_MASK][0]; - *(RightOut++) += Values[Offset&HRIR_MASK][1]; - } -} diff --git a/Alc/mixer/hrtf_inc.cpp b/Alc/mixer/hrtf_inc.cpp new file mode 100644 index 00000000..1f70242d --- /dev/null +++ b/Alc/mixer/hrtf_inc.cpp @@ -0,0 +1,128 @@ +#include "config.h" + +#include "alMain.h" +#include "alSource.h" + +#include "hrtf.h" +#include "align.h" +#include "alu.h" +#include "defs.h" + + +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], + const ALsizei irSize, + const ALfloat (*RESTRICT Coeffs)[2], + ALfloat left, ALfloat right); + + +void MixHrtf(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, MixHrtfParams *hrtfparams, HrtfState *hrtfstate, + ALsizei BufferSize) +{ + const ALfloat (*Coeffs)[2] = hrtfparams->Coeffs; + const ALsizei Delay[2] = { hrtfparams->Delay[0], hrtfparams->Delay[1] }; + const ALfloat gainstep = hrtfparams->GainStep; + const ALfloat gain = hrtfparams->Gain; + ALfloat g, stepcount = 0.0f; + ALfloat left, right; + ALsizei i; + + ASSUME(IrSize >= 4); + ASSUME(BufferSize > 0); + + LeftOut += OutPos; + RightOut += OutPos; + for(i = 0;i < BufferSize;i++) + { + hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++); + + g = gain + gainstep*stepcount; + left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK]*g; + right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK]*g; + + hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f; + hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f; + + ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right); + *(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0]; + *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1]; + + stepcount += 1.0f; + Offset++; + } + hrtfparams->Gain = gain + gainstep*stepcount; +} + +void MixHrtfBlend(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, const HrtfParams *oldparams, + MixHrtfParams *newparams, HrtfState *hrtfstate, + ALsizei BufferSize) +{ + const ALfloat (*OldCoeffs)[2] = oldparams->Coeffs; + const ALsizei OldDelay[2] = { oldparams->Delay[0], oldparams->Delay[1] }; + const ALfloat oldGain = oldparams->Gain; + const ALfloat oldGainStep = -oldGain / (ALfloat)BufferSize; + const ALfloat (*NewCoeffs)[2] = newparams->Coeffs; + const ALsizei NewDelay[2] = { newparams->Delay[0], newparams->Delay[1] }; + const ALfloat newGain = newparams->Gain; + const ALfloat newGainStep = newparams->GainStep; + ALfloat g, stepcount = 0.0f; + ALfloat left, right; + ALsizei i; + + ASSUME(IrSize >= 4); + ASSUME(BufferSize > 0); + + LeftOut += OutPos; + RightOut += OutPos; + for(i = 0;i < BufferSize;i++) + { + hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f; + hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f; + + hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++); + + g = oldGain + oldGainStep*stepcount; + left = hrtfstate->History[(Offset-OldDelay[0])&HRTF_HISTORY_MASK]*g; + right = hrtfstate->History[(Offset-OldDelay[1])&HRTF_HISTORY_MASK]*g; + ApplyCoeffs(Offset, hrtfstate->Values, IrSize, OldCoeffs, left, right); + + g = newGain + newGainStep*stepcount; + left = hrtfstate->History[(Offset-NewDelay[0])&HRTF_HISTORY_MASK]*g; + right = hrtfstate->History[(Offset-NewDelay[1])&HRTF_HISTORY_MASK]*g; + ApplyCoeffs(Offset, hrtfstate->Values, IrSize, NewCoeffs, left, right); + + *(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0]; + *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1]; + + stepcount += 1.0f; + Offset++; + } + newparams->Gain = newGain + newGainStep*stepcount; +} + +void MixDirectHrtf(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, + const ALfloat *data, ALsizei Offset, const ALsizei IrSize, + const ALfloat (*RESTRICT Coeffs)[2], ALfloat (*RESTRICT Values)[2], + ALsizei BufferSize) +{ + ALfloat insample; + ALsizei i; + + ASSUME(IrSize >= 4); + ASSUME(BufferSize > 0); + + for(i = 0;i < BufferSize;i++) + { + Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; + Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; + Offset++; + + insample = *(data++); + ApplyCoeffs(Offset, Values, IrSize, Coeffs, insample, insample); + *(LeftOut++) += Values[Offset&HRIR_MASK][0]; + *(RightOut++) += Values[Offset&HRIR_MASK][1]; + } +} diff --git a/Alc/mixer/mixer_c.c b/Alc/mixer/mixer_c.c deleted file mode 100644 index dce6daec..00000000 --- a/Alc/mixer/mixer_c.c +++ /dev/null @@ -1,169 +0,0 @@ -#include "config.h" - -#include - -#include "alMain.h" -#include "alu.h" -#include "alSource.h" -#include "alAuxEffectSlot.h" -#include "defs.h" - - -static inline ALfloat do_point(const InterpState* UNUSED(state), const ALfloat *RESTRICT vals, ALsizei UNUSED(frac)) -{ return vals[0]; } -static inline ALfloat do_lerp(const InterpState* UNUSED(state), const ALfloat *RESTRICT vals, ALsizei frac) -{ return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); } -static inline ALfloat do_cubic(const InterpState* UNUSED(state), const ALfloat *RESTRICT vals, ALsizei frac) -{ return cubic(vals[0], vals[1], vals[2], vals[3], frac * (1.0f/FRACTIONONE)); } -static inline ALfloat do_bsinc(const InterpState *state, const ALfloat *RESTRICT vals, ALsizei frac) -{ - const ALfloat *fil, *scd, *phd, *spd; - ALsizei j_f, pi; - ALfloat pf, r; - - ASSUME(state->bsinc.m > 0); - - // Calculate the phase index and factor. -#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) - pi = frac >> FRAC_PHASE_BITDIFF; - pf = (frac & ((1<bsinc.filter + state->bsinc.m*pi*4; - scd = fil + state->bsinc.m; - phd = scd + state->bsinc.m; - spd = phd + state->bsinc.m; - - // Apply the scale and phase interpolated filter. - r = 0.0f; - for(j_f = 0;j_f < state->bsinc.m;j_f++) - r += (fil[j_f] + state->bsinc.sf*scd[j_f] + pf*(phd[j_f] + state->bsinc.sf*spd[j_f])) * vals[j_f]; - return r; -} - -const ALfloat *Resample_copy_C(const InterpState* UNUSED(state), - const ALfloat *RESTRICT src, ALsizei UNUSED(frac), ALint UNUSED(increment), - ALfloat *RESTRICT dst, ALsizei numsamples) -{ -#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(Tag, Sampler, O) \ -const ALfloat *Resample_##Tag##_C(const InterpState *state, \ - const ALfloat *RESTRICT src, ALsizei frac, ALint increment, \ - ALfloat *RESTRICT dst, ALsizei numsamples) \ -{ \ - const InterpState istate = *state; \ - ALsizei i; \ - \ - ASSUME(numsamples > 0); \ - \ - src -= O; \ - for(i = 0;i < numsamples;i++) \ - { \ - dst[i] = Sampler(&istate, src, frac); \ - \ - frac += increment; \ - src += frac>>FRACTIONBITS; \ - frac &= FRACTIONMASK; \ - } \ - return dst; \ -} - -DECL_TEMPLATE(point, do_point, 0) -DECL_TEMPLATE(lerp, do_lerp, 0) -DECL_TEMPLATE(cubic, do_cubic, 1) -DECL_TEMPLATE(bsinc, do_bsinc, istate.bsinc.l) - -#undef DECL_TEMPLATE - - -static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], - const ALsizei IrSize, - const ALfloat (*RESTRICT Coeffs)[2], - ALfloat left, ALfloat right) -{ - ALsizei c; - for(c = 0;c < IrSize;c++) - { - const ALsizei off = (Offset+c)&HRIR_MASK; - Values[off][0] += Coeffs[c][0] * left; - Values[off][1] += Coeffs[c][1] * right; - } -} - -#define MixHrtf MixHrtf_C -#define MixHrtfBlend MixHrtfBlend_C -#define MixDirectHrtf MixDirectHrtf_C -#include "hrtf_inc.c" - - -void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], - ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, - ALsizei BufferSize) -{ - const ALfloat delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; - ALsizei c; - - ASSUME(OutChans > 0); - ASSUME(BufferSize > 0); - - for(c = 0;c < OutChans;c++) - { - ALsizei pos = 0; - ALfloat gain = CurrentGains[c]; - const ALfloat diff = TargetGains[c] - gain; - - if(fabsf(diff) > FLT_EPSILON) - { - ALsizei minsize = mini(BufferSize, Counter); - const ALfloat step = diff * delta; - ALfloat step_count = 0.0f; - for(;pos < minsize;pos++) - { - OutBuffer[c][OutPos+pos] += data[pos] * (gain + step*step_count); - step_count += 1.0f; - } - if(pos == Counter) - gain = TargetGains[c]; - else - gain += step*step_count; - CurrentGains[c] = gain; - } - - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - for(;pos < BufferSize;pos++) - OutBuffer[c][OutPos+pos] += data[pos]*gain; - } -} - -/* Basically the inverse of the above. Rather than one input going to multiple - * outputs (each with its own gain), it's multiple inputs (each with its own - * gain) going to one output. This applies one row (vs one column) of a matrix - * transform. And as the matrices are more or less static once set up, no - * stepping is necessary. - */ -void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*RESTRICT data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) -{ - ALsizei c, i; - - ASSUME(InChans > 0); - ASSUME(BufferSize > 0); - - for(c = 0;c < InChans;c++) - { - const ALfloat gain = Gains[c]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - for(i = 0;i < BufferSize;i++) - OutBuffer[i] += data[c][InPos+i] * gain; - } -} diff --git a/Alc/mixer/mixer_c.cpp b/Alc/mixer/mixer_c.cpp new file mode 100644 index 00000000..06e3ae22 --- /dev/null +++ b/Alc/mixer/mixer_c.cpp @@ -0,0 +1,169 @@ +#include "config.h" + +#include + +#include "alMain.h" +#include "alu.h" +#include "alSource.h" +#include "alAuxEffectSlot.h" +#include "defs.h" + + +static inline ALfloat do_point(const InterpState* UNUSED(state), const ALfloat *RESTRICT vals, ALsizei UNUSED(frac)) +{ return vals[0]; } +static inline ALfloat do_lerp(const InterpState* UNUSED(state), const ALfloat *RESTRICT vals, ALsizei frac) +{ return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); } +static inline ALfloat do_cubic(const InterpState* UNUSED(state), const ALfloat *RESTRICT vals, ALsizei frac) +{ return cubic(vals[0], vals[1], vals[2], vals[3], frac * (1.0f/FRACTIONONE)); } +static inline ALfloat do_bsinc(const InterpState *state, const ALfloat *RESTRICT vals, ALsizei frac) +{ + const ALfloat *fil, *scd, *phd, *spd; + ALsizei j_f, pi; + ALfloat pf, r; + + ASSUME(state->bsinc.m > 0); + + // Calculate the phase index and factor. +#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) + pi = frac >> FRAC_PHASE_BITDIFF; + pf = (frac & ((1<bsinc.filter + state->bsinc.m*pi*4; + scd = fil + state->bsinc.m; + phd = scd + state->bsinc.m; + spd = phd + state->bsinc.m; + + // Apply the scale and phase interpolated filter. + r = 0.0f; + for(j_f = 0;j_f < state->bsinc.m;j_f++) + r += (fil[j_f] + state->bsinc.sf*scd[j_f] + pf*(phd[j_f] + state->bsinc.sf*spd[j_f])) * vals[j_f]; + return r; +} + +const ALfloat *Resample_copy_C(const InterpState* UNUSED(state), + const ALfloat *RESTRICT src, ALsizei UNUSED(frac), ALint UNUSED(increment), + ALfloat *RESTRICT dst, ALsizei numsamples) +{ +#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(Tag, Sampler, O) \ +const ALfloat *Resample_##Tag##_C(const InterpState *state, \ + const ALfloat *RESTRICT src, ALsizei frac, ALint increment, \ + ALfloat *RESTRICT dst, ALsizei numsamples) \ +{ \ + const InterpState istate = *state; \ + ALsizei i; \ + \ + ASSUME(numsamples > 0); \ + \ + src -= O; \ + for(i = 0;i < numsamples;i++) \ + { \ + dst[i] = Sampler(&istate, src, frac); \ + \ + frac += increment; \ + src += frac>>FRACTIONBITS; \ + frac &= FRACTIONMASK; \ + } \ + return dst; \ +} + +DECL_TEMPLATE(point, do_point, 0) +DECL_TEMPLATE(lerp, do_lerp, 0) +DECL_TEMPLATE(cubic, do_cubic, 1) +DECL_TEMPLATE(bsinc, do_bsinc, istate.bsinc.l) + +#undef DECL_TEMPLATE + + +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], + const ALsizei IrSize, + const ALfloat (*RESTRICT Coeffs)[2], + ALfloat left, ALfloat right) +{ + ALsizei c; + for(c = 0;c < IrSize;c++) + { + const ALsizei off = (Offset+c)&HRIR_MASK; + Values[off][0] += Coeffs[c][0] * left; + Values[off][1] += Coeffs[c][1] * right; + } +} + +#define MixHrtf MixHrtf_C +#define MixHrtfBlend MixHrtfBlend_C +#define MixDirectHrtf MixDirectHrtf_C +#include "hrtf_inc.cpp" + + +void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], + ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, + ALsizei BufferSize) +{ + const ALfloat delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; + ALsizei c; + + ASSUME(OutChans > 0); + ASSUME(BufferSize > 0); + + for(c = 0;c < OutChans;c++) + { + ALsizei pos = 0; + ALfloat gain = CurrentGains[c]; + const ALfloat diff = TargetGains[c] - gain; + + if(fabsf(diff) > FLT_EPSILON) + { + ALsizei minsize = mini(BufferSize, Counter); + const ALfloat step = diff * delta; + ALfloat step_count = 0.0f; + for(;pos < minsize;pos++) + { + OutBuffer[c][OutPos+pos] += data[pos] * (gain + step*step_count); + step_count += 1.0f; + } + if(pos == Counter) + gain = TargetGains[c]; + else + gain += step*step_count; + CurrentGains[c] = gain; + } + + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + for(;pos < BufferSize;pos++) + OutBuffer[c][OutPos+pos] += data[pos]*gain; + } +} + +/* Basically the inverse of the above. Rather than one input going to multiple + * outputs (each with its own gain), it's multiple inputs (each with its own + * gain) going to one output. This applies one row (vs one column) of a matrix + * transform. And as the matrices are more or less static once set up, no + * stepping is necessary. + */ +void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*RESTRICT data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) +{ + ALsizei c, i; + + ASSUME(InChans > 0); + ASSUME(BufferSize > 0); + + for(c = 0;c < InChans;c++) + { + const ALfloat gain = Gains[c]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + for(i = 0;i < BufferSize;i++) + OutBuffer[i] += data[c][InPos+i] * gain; + } +} diff --git a/Alc/mixer/mixer_neon.c b/Alc/mixer/mixer_neon.c deleted file mode 100644 index 9bc76987..00000000 --- a/Alc/mixer/mixer_neon.c +++ /dev/null @@ -1,280 +0,0 @@ -#include "config.h" - -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "alMain.h" -#include "alu.h" -#include "hrtf.h" -#include "defs.h" - - -const ALfloat *Resample_lerp_Neon(const InterpState* UNUSED(state), - const ALfloat *RESTRICT src, ALsizei frac, ALint increment, - ALfloat *RESTRICT dst, ALsizei numsamples) -{ - const int32x4_t increment4 = vdupq_n_s32(increment*4); - const float32x4_t fracOne4 = vdupq_n_f32(1.0f/FRACTIONONE); - const int32x4_t fracMask4 = vdupq_n_s32(FRACTIONMASK); - alignas(16) ALsizei pos_[4], frac_[4]; - int32x4_t pos4, frac4; - ALsizei todo, pos, i; - - ASSUME(numsamples > 0); - - InitiatePositionArrays(frac, increment, frac_, pos_, 4); - frac4 = vld1q_s32(frac_); - pos4 = vld1q_s32(pos_); - - todo = numsamples & ~3; - for(i = 0;i < todo;i += 4) - { - const int pos0 = vgetq_lane_s32(pos4, 0); - const int pos1 = vgetq_lane_s32(pos4, 1); - const int pos2 = vgetq_lane_s32(pos4, 2); - const int pos3 = vgetq_lane_s32(pos4, 3); - const float32x4_t val1 = (float32x4_t){src[pos0], src[pos1], src[pos2], src[pos3]}; - const float32x4_t val2 = (float32x4_t){src[pos0+1], src[pos1+1], src[pos2+1], src[pos3+1]}; - - /* val1 + (val2-val1)*mu */ - const float32x4_t r0 = vsubq_f32(val2, val1); - const float32x4_t mu = vmulq_f32(vcvtq_f32_s32(frac4), fracOne4); - const float32x4_t out = vmlaq_f32(val1, mu, r0); - - vst1q_f32(&dst[i], out); - - frac4 = vaddq_s32(frac4, increment4); - pos4 = vaddq_s32(pos4, vshrq_n_s32(frac4, FRACTIONBITS)); - frac4 = vandq_s32(frac4, fracMask4); - } - - /* NOTE: These four elements represent the position *after* the last four - * samples, so the lowest element is the next position to resample. - */ - pos = vgetq_lane_s32(pos4, 0); - frac = vgetq_lane_s32(frac4, 0); - - 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; -} - -const ALfloat *Resample_bsinc_Neon(const InterpState *state, - const ALfloat *RESTRICT src, ALsizei frac, ALint increment, - ALfloat *RESTRICT dst, ALsizei dstlen) -{ - const ALfloat *const filter = state->bsinc.filter; - const float32x4_t sf4 = vdupq_n_f32(state->bsinc.sf); - const ALsizei m = state->bsinc.m; - const float32x4_t *fil, *scd, *phd, *spd; - ALsizei pi, i, j, offset; - float32x4_t r4; - ALfloat pf; - - ASSUME(m > 0); - ASSUME(dstlen > 0); - - src -= state->bsinc.l; - for(i = 0;i < dstlen;i++) - { - // Calculate the phase index and factor. -#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) - pi = frac >> FRAC_PHASE_BITDIFF; - pf = (frac & ((1<> 2; - const float32x4_t pf4 = vdupq_n_f32(pf); - - ASSUME(count > 0); - - for(j = 0;j < count;j++) - { - /* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */ - const float32x4_t f4 = vmlaq_f32( - vmlaq_f32(fil[j], sf4, scd[j]), - pf4, vmlaq_f32(phd[j], sf4, spd[j]) - ); - /* r += f*src */ - r4 = vmlaq_f32(r4, f4, vld1q_f32(&src[j*4])); - } - } - r4 = vaddq_f32(r4, vcombine_f32(vrev64_f32(vget_high_f32(r4)), - vrev64_f32(vget_low_f32(r4)))); - dst[i] = vget_lane_f32(vadd_f32(vget_low_f32(r4), vget_high_f32(r4)), 0); - - frac += increment; - src += frac>>FRACTIONBITS; - frac &= FRACTIONMASK; - } - return dst; -} - - -static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], - const ALsizei IrSize, - const ALfloat (*RESTRICT Coeffs)[2], - ALfloat left, ALfloat right) -{ - ALsizei 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) - { - const ALsizei o0 = (Offset+c)&HRIR_MASK; - const ALsizei 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]); - - vals = vmlaq_f32(vals, coefs, leftright4); - - vst1_f32((float32_t*)&Values[o0][0], vget_low_f32(vals)); - vst1_f32((float32_t*)&Values[o1][0], vget_high_f32(vals)); - } -} - -#define MixHrtf MixHrtf_Neon -#define MixHrtfBlend MixHrtfBlend_Neon -#define MixDirectHrtf MixDirectHrtf_Neon -#include "hrtf_inc.c" - - -void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], - ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, - ALsizei BufferSize) -{ - const ALfloat delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; - ALsizei c; - - ASSUME(OutChans > 0); - ASSUME(BufferSize > 0); - - for(c = 0;c < OutChans;c++) - { - ALsizei pos = 0; - ALfloat gain = CurrentGains[c]; - const ALfloat diff = TargetGains[c] - gain; - - if(fabsf(diff) > FLT_EPSILON) - { - ALsizei minsize = mini(BufferSize, Counter); - const ALfloat step = diff * delta; - ALfloat step_count = 0.0f; - /* Mix with applying gain steps in aligned multiples of 4. */ - if(LIKELY(minsize > 3)) - { - const float32x4_t four4 = vdupq_n_f32(4.0f); - const float32x4_t step4 = vdupq_n_f32(step); - const float32x4_t gain4 = vdupq_n_f32(gain); - float32x4_t step_count4 = vsetq_lane_f32(0.0f, - vsetq_lane_f32(1.0f, - vsetq_lane_f32(2.0f, - vsetq_lane_f32(3.0f, vdupq_n_f32(0.0f), 3), - 2), 1), 0 - ); - ALsizei todo = minsize >> 2; - - do { - const float32x4_t val4 = vld1q_f32(&data[pos]); - float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]); - dry4 = vmlaq_f32(dry4, val4, vmlaq_f32(gain4, step4, step_count4)); - step_count4 = vaddq_f32(step_count4, four4); - vst1q_f32(&OutBuffer[c][OutPos+pos], dry4); - pos += 4; - } while(--todo); - /* NOTE: step_count4 now represents the next four counts after - * the last four mixed samples, so the lowest element - * represents the next step count to apply. - */ - step_count = vgetq_lane_f32(step_count4, 0); - } - /* Mix with applying left over gain steps that aren't aligned multiples of 4. */ - for(;pos < minsize;pos++) - { - OutBuffer[c][OutPos+pos] += data[pos]*(gain + step*step_count); - step_count += 1.0f; - } - if(pos == Counter) - gain = TargetGains[c]; - else - gain += step*step_count; - CurrentGains[c] = gain; - - /* Mix until pos is aligned with 4 or the mix is done. */ - minsize = mini(BufferSize, (pos+3)&~3); - for(;pos < minsize;pos++) - OutBuffer[c][OutPos+pos] += data[pos]*gain; - } - - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - if(LIKELY(BufferSize-pos > 3)) - { - ALsizei todo = (BufferSize-pos) >> 2; - const float32x4_t gain4 = vdupq_n_f32(gain); - do { - const float32x4_t val4 = vld1q_f32(&data[pos]); - float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]); - dry4 = vmlaq_f32(dry4, val4, gain4); - vst1q_f32(&OutBuffer[c][OutPos+pos], dry4); - pos += 4; - } while(--todo); - } - for(;pos < BufferSize;pos++) - OutBuffer[c][OutPos+pos] += data[pos]*gain; - } -} - -void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*RESTRICT data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) -{ - ALsizei c; - - ASSUME(InChans > 0); - ASSUME(BufferSize > 0); - - for(c = 0;c < InChans;c++) - { - ALsizei pos = 0; - const ALfloat gain = Gains[c]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - if(LIKELY(BufferSize > 3)) - { - ALsizei todo = BufferSize >> 2; - float32x4_t gain4 = vdupq_n_f32(gain); - do { - const float32x4_t val4 = vld1q_f32(&data[c][InPos+pos]); - float32x4_t dry4 = vld1q_f32(&OutBuffer[pos]); - dry4 = vmlaq_f32(dry4, val4, gain4); - vst1q_f32(&OutBuffer[pos], dry4); - pos += 4; - } while(--todo); - } - for(;pos < BufferSize;pos++) - OutBuffer[pos] += data[c][InPos+pos]*gain; - } -} diff --git a/Alc/mixer/mixer_neon.cpp b/Alc/mixer/mixer_neon.cpp new file mode 100644 index 00000000..b1f219e4 --- /dev/null +++ b/Alc/mixer/mixer_neon.cpp @@ -0,0 +1,280 @@ +#include "config.h" + +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "alMain.h" +#include "alu.h" +#include "hrtf.h" +#include "defs.h" + + +const ALfloat *Resample_lerp_Neon(const InterpState* UNUSED(state), + const ALfloat *RESTRICT src, ALsizei frac, ALint increment, + ALfloat *RESTRICT dst, ALsizei numsamples) +{ + const int32x4_t increment4 = vdupq_n_s32(increment*4); + const float32x4_t fracOne4 = vdupq_n_f32(1.0f/FRACTIONONE); + const int32x4_t fracMask4 = vdupq_n_s32(FRACTIONMASK); + alignas(16) ALsizei pos_[4], frac_[4]; + int32x4_t pos4, frac4; + ALsizei todo, pos, i; + + ASSUME(numsamples > 0); + + InitiatePositionArrays(frac, increment, frac_, pos_, 4); + frac4 = vld1q_s32(frac_); + pos4 = vld1q_s32(pos_); + + todo = numsamples & ~3; + for(i = 0;i < todo;i += 4) + { + const int pos0 = vgetq_lane_s32(pos4, 0); + const int pos1 = vgetq_lane_s32(pos4, 1); + const int pos2 = vgetq_lane_s32(pos4, 2); + const int pos3 = vgetq_lane_s32(pos4, 3); + const float32x4_t val1 = (float32x4_t){src[pos0], src[pos1], src[pos2], src[pos3]}; + const float32x4_t val2 = (float32x4_t){src[pos0+1], src[pos1+1], src[pos2+1], src[pos3+1]}; + + /* val1 + (val2-val1)*mu */ + const float32x4_t r0 = vsubq_f32(val2, val1); + const float32x4_t mu = vmulq_f32(vcvtq_f32_s32(frac4), fracOne4); + const float32x4_t out = vmlaq_f32(val1, mu, r0); + + vst1q_f32(&dst[i], out); + + frac4 = vaddq_s32(frac4, increment4); + pos4 = vaddq_s32(pos4, vshrq_n_s32(frac4, FRACTIONBITS)); + frac4 = vandq_s32(frac4, fracMask4); + } + + /* NOTE: These four elements represent the position *after* the last four + * samples, so the lowest element is the next position to resample. + */ + pos = vgetq_lane_s32(pos4, 0); + frac = vgetq_lane_s32(frac4, 0); + + 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; +} + +const ALfloat *Resample_bsinc_Neon(const InterpState *state, + const ALfloat *RESTRICT src, ALsizei frac, ALint increment, + ALfloat *RESTRICT dst, ALsizei dstlen) +{ + const ALfloat *const filter = state->bsinc.filter; + const float32x4_t sf4 = vdupq_n_f32(state->bsinc.sf); + const ALsizei m = state->bsinc.m; + const float32x4_t *fil, *scd, *phd, *spd; + ALsizei pi, i, j, offset; + float32x4_t r4; + ALfloat pf; + + ASSUME(m > 0); + ASSUME(dstlen > 0); + + src -= state->bsinc.l; + for(i = 0;i < dstlen;i++) + { + // Calculate the phase index and factor. +#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) + pi = frac >> FRAC_PHASE_BITDIFF; + pf = (frac & ((1<> 2; + const float32x4_t pf4 = vdupq_n_f32(pf); + + ASSUME(count > 0); + + for(j = 0;j < count;j++) + { + /* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */ + const float32x4_t f4 = vmlaq_f32( + vmlaq_f32(fil[j], sf4, scd[j]), + pf4, vmlaq_f32(phd[j], sf4, spd[j]) + ); + /* r += f*src */ + r4 = vmlaq_f32(r4, f4, vld1q_f32(&src[j*4])); + } + } + r4 = vaddq_f32(r4, vcombine_f32(vrev64_f32(vget_high_f32(r4)), + vrev64_f32(vget_low_f32(r4)))); + dst[i] = vget_lane_f32(vadd_f32(vget_low_f32(r4), vget_high_f32(r4)), 0); + + frac += increment; + src += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } + return dst; +} + + +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], + const ALsizei IrSize, + const ALfloat (*RESTRICT Coeffs)[2], + ALfloat left, ALfloat right) +{ + ALsizei 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) + { + const ALsizei o0 = (Offset+c)&HRIR_MASK; + const ALsizei 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]); + + vals = vmlaq_f32(vals, coefs, leftright4); + + vst1_f32((float32_t*)&Values[o0][0], vget_low_f32(vals)); + vst1_f32((float32_t*)&Values[o1][0], vget_high_f32(vals)); + } +} + +#define MixHrtf MixHrtf_Neon +#define MixHrtfBlend MixHrtfBlend_Neon +#define MixDirectHrtf MixDirectHrtf_Neon +#include "hrtf_inc.cpp" + + +void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], + ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, + ALsizei BufferSize) +{ + const ALfloat delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; + ALsizei c; + + ASSUME(OutChans > 0); + ASSUME(BufferSize > 0); + + for(c = 0;c < OutChans;c++) + { + ALsizei pos = 0; + ALfloat gain = CurrentGains[c]; + const ALfloat diff = TargetGains[c] - gain; + + if(fabsf(diff) > FLT_EPSILON) + { + ALsizei minsize = mini(BufferSize, Counter); + const ALfloat step = diff * delta; + ALfloat step_count = 0.0f; + /* Mix with applying gain steps in aligned multiples of 4. */ + if(LIKELY(minsize > 3)) + { + const float32x4_t four4 = vdupq_n_f32(4.0f); + const float32x4_t step4 = vdupq_n_f32(step); + const float32x4_t gain4 = vdupq_n_f32(gain); + float32x4_t step_count4 = vsetq_lane_f32(0.0f, + vsetq_lane_f32(1.0f, + vsetq_lane_f32(2.0f, + vsetq_lane_f32(3.0f, vdupq_n_f32(0.0f), 3), + 2), 1), 0 + ); + ALsizei todo = minsize >> 2; + + do { + const float32x4_t val4 = vld1q_f32(&data[pos]); + float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]); + dry4 = vmlaq_f32(dry4, val4, vmlaq_f32(gain4, step4, step_count4)); + step_count4 = vaddq_f32(step_count4, four4); + vst1q_f32(&OutBuffer[c][OutPos+pos], dry4); + pos += 4; + } while(--todo); + /* NOTE: step_count4 now represents the next four counts after + * the last four mixed samples, so the lowest element + * represents the next step count to apply. + */ + step_count = vgetq_lane_f32(step_count4, 0); + } + /* Mix with applying left over gain steps that aren't aligned multiples of 4. */ + for(;pos < minsize;pos++) + { + OutBuffer[c][OutPos+pos] += data[pos]*(gain + step*step_count); + step_count += 1.0f; + } + if(pos == Counter) + gain = TargetGains[c]; + else + gain += step*step_count; + CurrentGains[c] = gain; + + /* Mix until pos is aligned with 4 or the mix is done. */ + minsize = mini(BufferSize, (pos+3)&~3); + for(;pos < minsize;pos++) + OutBuffer[c][OutPos+pos] += data[pos]*gain; + } + + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + if(LIKELY(BufferSize-pos > 3)) + { + ALsizei todo = (BufferSize-pos) >> 2; + const float32x4_t gain4 = vdupq_n_f32(gain); + do { + const float32x4_t val4 = vld1q_f32(&data[pos]); + float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]); + dry4 = vmlaq_f32(dry4, val4, gain4); + vst1q_f32(&OutBuffer[c][OutPos+pos], dry4); + pos += 4; + } while(--todo); + } + for(;pos < BufferSize;pos++) + OutBuffer[c][OutPos+pos] += data[pos]*gain; + } +} + +void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*RESTRICT data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) +{ + ALsizei c; + + ASSUME(InChans > 0); + ASSUME(BufferSize > 0); + + for(c = 0;c < InChans;c++) + { + ALsizei pos = 0; + const ALfloat gain = Gains[c]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + if(LIKELY(BufferSize > 3)) + { + ALsizei todo = BufferSize >> 2; + float32x4_t gain4 = vdupq_n_f32(gain); + do { + const float32x4_t val4 = vld1q_f32(&data[c][InPos+pos]); + float32x4_t dry4 = vld1q_f32(&OutBuffer[pos]); + dry4 = vmlaq_f32(dry4, val4, gain4); + vst1q_f32(&OutBuffer[pos], dry4); + pos += 4; + } while(--todo); + } + for(;pos < BufferSize;pos++) + OutBuffer[pos] += data[c][InPos+pos]*gain; + } +} diff --git a/Alc/mixer/mixer_sse.c b/Alc/mixer/mixer_sse.c deleted file mode 100644 index d9ad2ed3..00000000 --- a/Alc/mixer/mixer_sse.c +++ /dev/null @@ -1,248 +0,0 @@ -#include "config.h" - -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "alMain.h" -#include "alu.h" - -#include "alSource.h" -#include "alAuxEffectSlot.h" -#include "defs.h" - - -const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, - ALsizei dstlen) -{ - const ALfloat *const filter = state->bsinc.filter; - const __m128 sf4 = _mm_set1_ps(state->bsinc.sf); - const ALsizei m = state->bsinc.m; - const __m128 *fil, *scd, *phd, *spd; - ALsizei pi, i, j, offset; - ALfloat pf; - __m128 r4; - - ASSUME(m > 0); - ASSUME(dstlen > 0); - - src -= state->bsinc.l; - for(i = 0;i < dstlen;i++) - { - // Calculate the phase index and factor. -#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) - pi = frac >> FRAC_PHASE_BITDIFF; - pf = (frac & ((1<> 2; - const __m128 pf4 = _mm_set1_ps(pf); - - ASSUME(count > 0); - -#define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z)) - for(j = 0;j < count;j++) - { - /* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */ - const __m128 f4 = MLA4( - MLA4(fil[j], sf4, scd[j]), - pf4, MLA4(phd[j], sf4, spd[j]) - ); - /* r += f*src */ - r4 = MLA4(r4, f4, _mm_loadu_ps(&src[j*4])); - } -#undef MLA4 - } - r4 = _mm_add_ps(r4, _mm_shuffle_ps(r4, r4, _MM_SHUFFLE(0, 1, 2, 3))); - r4 = _mm_add_ps(r4, _mm_movehl_ps(r4, r4)); - dst[i] = _mm_cvtss_f32(r4); - - frac += increment; - src += frac>>FRACTIONBITS; - frac &= FRACTIONMASK; - } - return dst; -} - - -static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], - const ALsizei IrSize, - const ALfloat (*RESTRICT Coeffs)[2], - ALfloat left, ALfloat right) -{ - const __m128 lrlr = _mm_setr_ps(left, right, left, right); - __m128 vals = _mm_setzero_ps(); - __m128 coeffs; - ALsizei i; - - if((Offset&1)) - { - const ALsizei o0 = Offset&HRIR_MASK; - const ALsizei o1 = (Offset+IrSize-1)&HRIR_MASK; - __m128 imp0, imp1; - - coeffs = _mm_load_ps(&Coeffs[0][0]); - vals = _mm_loadl_pi(vals, (__m64*)&Values[o0][0]); - imp0 = _mm_mul_ps(lrlr, coeffs); - vals = _mm_add_ps(imp0, vals); - _mm_storel_pi((__m64*)&Values[o0][0], vals); - for(i = 1;i < IrSize-1;i += 2) - { - const ALsizei o2 = (Offset+i)&HRIR_MASK; - - coeffs = _mm_load_ps(&Coeffs[i+1][0]); - vals = _mm_load_ps(&Values[o2][0]); - imp1 = _mm_mul_ps(lrlr, coeffs); - imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2)); - vals = _mm_add_ps(imp0, vals); - _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 ALsizei o = (Offset + i)&HRIR_MASK; - - coeffs = _mm_load_ps(&Coeffs[i][0]); - vals = _mm_load_ps(&Values[o][0]); - vals = _mm_add_ps(vals, _mm_mul_ps(lrlr, coeffs)); - _mm_store_ps(&Values[o][0], vals); - } - } -} - -#define MixHrtf MixHrtf_SSE -#define MixHrtfBlend MixHrtfBlend_SSE -#define MixDirectHrtf MixDirectHrtf_SSE -#include "hrtf_inc.c" - - -void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], - ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, - ALsizei BufferSize) -{ - const ALfloat delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; - ALsizei c; - - ASSUME(OutChans > 0); - ASSUME(BufferSize > 0); - - for(c = 0;c < OutChans;c++) - { - ALsizei pos = 0; - ALfloat gain = CurrentGains[c]; - const ALfloat diff = TargetGains[c] - gain; - - if(fabsf(diff) > FLT_EPSILON) - { - ALsizei minsize = mini(BufferSize, Counter); - const ALfloat step = diff * delta; - ALfloat step_count = 0.0f; - /* Mix with applying gain steps in aligned multiples of 4. */ - if(LIKELY(minsize > 3)) - { - const __m128 four4 = _mm_set1_ps(4.0f); - const __m128 step4 = _mm_set1_ps(step); - const __m128 gain4 = _mm_set1_ps(gain); - __m128 step_count4 = _mm_setr_ps(0.0f, 1.0f, 2.0f, 3.0f); - ALsizei todo = minsize >> 2; - do { - const __m128 val4 = _mm_load_ps(&data[pos]); - __m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]); -#define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z)) - /* dry += val * (gain + step*step_count) */ - dry4 = MLA4(dry4, val4, MLA4(gain4, step4, step_count4)); -#undef MLA4 - _mm_store_ps(&OutBuffer[c][OutPos+pos], dry4); - step_count4 = _mm_add_ps(step_count4, four4); - pos += 4; - } while(--todo); - /* NOTE: step_count4 now represents the next four counts after - * the last four mixed samples, so the lowest element - * represents the next step count to apply. - */ - step_count = _mm_cvtss_f32(step_count4); - } - /* Mix with applying left over gain steps that aren't aligned multiples of 4. */ - for(;pos < minsize;pos++) - { - OutBuffer[c][OutPos+pos] += data[pos]*(gain + step*step_count); - step_count += 1.0f; - } - if(pos == Counter) - gain = TargetGains[c]; - else - gain += step*step_count; - CurrentGains[c] = gain; - - /* Mix until pos is aligned with 4 or the mix is done. */ - minsize = mini(BufferSize, (pos+3)&~3); - for(;pos < minsize;pos++) - OutBuffer[c][OutPos+pos] += data[pos]*gain; - } - - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - if(LIKELY(BufferSize-pos > 3)) - { - ALsizei todo = (BufferSize-pos) >> 2; - const __m128 gain4 = _mm_set1_ps(gain); - 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, gain4)); - _mm_store_ps(&OutBuffer[c][OutPos+pos], dry4); - pos += 4; - } while(--todo); - } - for(;pos < BufferSize;pos++) - OutBuffer[c][OutPos+pos] += data[pos]*gain; - } -} - -void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*RESTRICT data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) -{ - ALsizei c; - - ASSUME(InChans > 0); - ASSUME(BufferSize > 0); - - for(c = 0;c < InChans;c++) - { - ALsizei pos = 0; - const ALfloat gain = Gains[c]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - if(LIKELY(BufferSize > 3)) - { - ALsizei todo = BufferSize >> 2; - const __m128 gain4 = _mm_set1_ps(gain); - do { - const __m128 val4 = _mm_load_ps(&data[c][InPos+pos]); - __m128 dry4 = _mm_load_ps(&OutBuffer[pos]); - dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); - _mm_store_ps(&OutBuffer[pos], dry4); - pos += 4; - } while(--todo); - } - for(;pos < BufferSize;pos++) - OutBuffer[pos] += data[c][InPos+pos]*gain; - } -} diff --git a/Alc/mixer/mixer_sse.cpp b/Alc/mixer/mixer_sse.cpp new file mode 100644 index 00000000..8492a1c8 --- /dev/null +++ b/Alc/mixer/mixer_sse.cpp @@ -0,0 +1,248 @@ +#include "config.h" + +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "alMain.h" +#include "alu.h" + +#include "alSource.h" +#include "alAuxEffectSlot.h" +#include "defs.h" + + +const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, + ALsizei dstlen) +{ + const ALfloat *const filter = state->bsinc.filter; + const __m128 sf4 = _mm_set1_ps(state->bsinc.sf); + const ALsizei m = state->bsinc.m; + const __m128 *fil, *scd, *phd, *spd; + ALsizei pi, i, j, offset; + ALfloat pf; + __m128 r4; + + ASSUME(m > 0); + ASSUME(dstlen > 0); + + src -= state->bsinc.l; + for(i = 0;i < dstlen;i++) + { + // Calculate the phase index and factor. +#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) + pi = frac >> FRAC_PHASE_BITDIFF; + pf = (frac & ((1<> 2; + const __m128 pf4 = _mm_set1_ps(pf); + + ASSUME(count > 0); + +#define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z)) + for(j = 0;j < count;j++) + { + /* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */ + const __m128 f4 = MLA4( + MLA4(fil[j], sf4, scd[j]), + pf4, MLA4(phd[j], sf4, spd[j]) + ); + /* r += f*src */ + r4 = MLA4(r4, f4, _mm_loadu_ps(&src[j*4])); + } +#undef MLA4 + } + r4 = _mm_add_ps(r4, _mm_shuffle_ps(r4, r4, _MM_SHUFFLE(0, 1, 2, 3))); + r4 = _mm_add_ps(r4, _mm_movehl_ps(r4, r4)); + dst[i] = _mm_cvtss_f32(r4); + + frac += increment; + src += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } + return dst; +} + + +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], + const ALsizei IrSize, + const ALfloat (*RESTRICT Coeffs)[2], + ALfloat left, ALfloat right) +{ + const __m128 lrlr = _mm_setr_ps(left, right, left, right); + __m128 vals = _mm_setzero_ps(); + __m128 coeffs; + ALsizei i; + + if((Offset&1)) + { + const ALsizei o0 = Offset&HRIR_MASK; + const ALsizei o1 = (Offset+IrSize-1)&HRIR_MASK; + __m128 imp0, imp1; + + coeffs = _mm_load_ps(&Coeffs[0][0]); + vals = _mm_loadl_pi(vals, (__m64*)&Values[o0][0]); + imp0 = _mm_mul_ps(lrlr, coeffs); + vals = _mm_add_ps(imp0, vals); + _mm_storel_pi((__m64*)&Values[o0][0], vals); + for(i = 1;i < IrSize-1;i += 2) + { + const ALsizei o2 = (Offset+i)&HRIR_MASK; + + coeffs = _mm_load_ps(&Coeffs[i+1][0]); + vals = _mm_load_ps(&Values[o2][0]); + imp1 = _mm_mul_ps(lrlr, coeffs); + imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2)); + vals = _mm_add_ps(imp0, vals); + _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 ALsizei o = (Offset + i)&HRIR_MASK; + + coeffs = _mm_load_ps(&Coeffs[i][0]); + vals = _mm_load_ps(&Values[o][0]); + vals = _mm_add_ps(vals, _mm_mul_ps(lrlr, coeffs)); + _mm_store_ps(&Values[o][0], vals); + } + } +} + +#define MixHrtf MixHrtf_SSE +#define MixHrtfBlend MixHrtfBlend_SSE +#define MixDirectHrtf MixDirectHrtf_SSE +#include "hrtf_inc.cpp" + + +void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], + ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, + ALsizei BufferSize) +{ + const ALfloat delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; + ALsizei c; + + ASSUME(OutChans > 0); + ASSUME(BufferSize > 0); + + for(c = 0;c < OutChans;c++) + { + ALsizei pos = 0; + ALfloat gain = CurrentGains[c]; + const ALfloat diff = TargetGains[c] - gain; + + if(fabsf(diff) > FLT_EPSILON) + { + ALsizei minsize = mini(BufferSize, Counter); + const ALfloat step = diff * delta; + ALfloat step_count = 0.0f; + /* Mix with applying gain steps in aligned multiples of 4. */ + if(LIKELY(minsize > 3)) + { + const __m128 four4 = _mm_set1_ps(4.0f); + const __m128 step4 = _mm_set1_ps(step); + const __m128 gain4 = _mm_set1_ps(gain); + __m128 step_count4 = _mm_setr_ps(0.0f, 1.0f, 2.0f, 3.0f); + ALsizei todo = minsize >> 2; + do { + const __m128 val4 = _mm_load_ps(&data[pos]); + __m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]); +#define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z)) + /* dry += val * (gain + step*step_count) */ + dry4 = MLA4(dry4, val4, MLA4(gain4, step4, step_count4)); +#undef MLA4 + _mm_store_ps(&OutBuffer[c][OutPos+pos], dry4); + step_count4 = _mm_add_ps(step_count4, four4); + pos += 4; + } while(--todo); + /* NOTE: step_count4 now represents the next four counts after + * the last four mixed samples, so the lowest element + * represents the next step count to apply. + */ + step_count = _mm_cvtss_f32(step_count4); + } + /* Mix with applying left over gain steps that aren't aligned multiples of 4. */ + for(;pos < minsize;pos++) + { + OutBuffer[c][OutPos+pos] += data[pos]*(gain + step*step_count); + step_count += 1.0f; + } + if(pos == Counter) + gain = TargetGains[c]; + else + gain += step*step_count; + CurrentGains[c] = gain; + + /* Mix until pos is aligned with 4 or the mix is done. */ + minsize = mini(BufferSize, (pos+3)&~3); + for(;pos < minsize;pos++) + OutBuffer[c][OutPos+pos] += data[pos]*gain; + } + + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + if(LIKELY(BufferSize-pos > 3)) + { + ALsizei todo = (BufferSize-pos) >> 2; + const __m128 gain4 = _mm_set1_ps(gain); + 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, gain4)); + _mm_store_ps(&OutBuffer[c][OutPos+pos], dry4); + pos += 4; + } while(--todo); + } + for(;pos < BufferSize;pos++) + OutBuffer[c][OutPos+pos] += data[pos]*gain; + } +} + +void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*RESTRICT data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) +{ + ALsizei c; + + ASSUME(InChans > 0); + ASSUME(BufferSize > 0); + + for(c = 0;c < InChans;c++) + { + ALsizei pos = 0; + const ALfloat gain = Gains[c]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + if(LIKELY(BufferSize > 3)) + { + ALsizei todo = BufferSize >> 2; + const __m128 gain4 = _mm_set1_ps(gain); + do { + const __m128 val4 = _mm_load_ps(&data[c][InPos+pos]); + __m128 dry4 = _mm_load_ps(&OutBuffer[pos]); + dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); + _mm_store_ps(&OutBuffer[pos], dry4); + pos += 4; + } while(--todo); + } + for(;pos < BufferSize;pos++) + OutBuffer[pos] += data[c][InPos+pos]*gain; + } +} diff --git a/Alc/mixer/mixer_sse2.c b/Alc/mixer/mixer_sse2.c deleted file mode 100644 index 2432342f..00000000 --- a/Alc/mixer/mixer_sse2.c +++ /dev/null @@ -1,84 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2014 by Timothy Arceri . - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alu.h" -#include "defs.h" - - -const ALfloat *Resample_lerp_SSE2(const InterpState* UNUSED(state), - const ALfloat *RESTRICT src, ALsizei frac, ALint increment, - ALfloat *RESTRICT dst, ALsizei 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) ALsizei pos_[4], frac_[4]; - __m128i frac4, pos4; - ALsizei todo, pos, i; - - ASSUME(numsamples > 0); - - InitiatePositionArrays(frac, increment, frac_, pos_, 4); - frac4 = _mm_setr_epi32(frac_[0], frac_[1], frac_[2], frac_[3]); - pos4 = _mm_setr_epi32(pos_[0], pos_[1], pos_[2], pos_[3]); - - todo = numsamples & ~3; - for(i = 0;i < todo;i += 4) - { - const int pos0 = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(0, 0, 0, 0))); - const int pos1 = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(1, 1, 1, 1))); - const int pos2 = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(2, 2, 2, 2))); - const int pos3 = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(3, 3, 3, 3))); - const __m128 val1 = _mm_setr_ps(src[pos0 ], src[pos1 ], src[pos2 ], src[pos3 ]); - const __m128 val2 = _mm_setr_ps(src[pos0+1], src[pos1+1], src[pos2+1], src[pos3+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); - } - - /* NOTE: These four elements represent the position *after* the last four - * samples, so the lowest element is the next position to resample. - */ - pos = _mm_cvtsi128_si32(pos4); - 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/mixer_sse2.cpp b/Alc/mixer/mixer_sse2.cpp new file mode 100644 index 00000000..2432342f --- /dev/null +++ b/Alc/mixer/mixer_sse2.cpp @@ -0,0 +1,84 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2014 by Timothy Arceri . + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alu.h" +#include "defs.h" + + +const ALfloat *Resample_lerp_SSE2(const InterpState* UNUSED(state), + const ALfloat *RESTRICT src, ALsizei frac, ALint increment, + ALfloat *RESTRICT dst, ALsizei 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) ALsizei pos_[4], frac_[4]; + __m128i frac4, pos4; + ALsizei todo, pos, i; + + ASSUME(numsamples > 0); + + InitiatePositionArrays(frac, increment, frac_, pos_, 4); + frac4 = _mm_setr_epi32(frac_[0], frac_[1], frac_[2], frac_[3]); + pos4 = _mm_setr_epi32(pos_[0], pos_[1], pos_[2], pos_[3]); + + todo = numsamples & ~3; + for(i = 0;i < todo;i += 4) + { + const int pos0 = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(0, 0, 0, 0))); + const int pos1 = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(1, 1, 1, 1))); + const int pos2 = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(2, 2, 2, 2))); + const int pos3 = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(3, 3, 3, 3))); + const __m128 val1 = _mm_setr_ps(src[pos0 ], src[pos1 ], src[pos2 ], src[pos3 ]); + const __m128 val2 = _mm_setr_ps(src[pos0+1], src[pos1+1], src[pos2+1], src[pos3+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); + } + + /* NOTE: These four elements represent the position *after* the last four + * samples, so the lowest element is the next position to resample. + */ + pos = _mm_cvtsi128_si32(pos4); + 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/mixer_sse3.c b/Alc/mixer/mixer_sse3.c deleted file mode 100644 index e69de29b..00000000 diff --git a/Alc/mixer/mixer_sse3.cpp b/Alc/mixer/mixer_sse3.cpp new file mode 100644 index 00000000..e69de29b diff --git a/Alc/mixer/mixer_sse41.c b/Alc/mixer/mixer_sse41.c deleted file mode 100644 index 34b405f8..00000000 --- a/Alc/mixer/mixer_sse41.c +++ /dev/null @@ -1,85 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2014 by Timothy Arceri . - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include "alu.h" -#include "defs.h" - - -const ALfloat *Resample_lerp_SSE41(const InterpState* UNUSED(state), - const ALfloat *RESTRICT src, ALsizei frac, ALint increment, - ALfloat *RESTRICT dst, ALsizei 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) ALsizei pos_[4], frac_[4]; - __m128i frac4, pos4; - ALsizei todo, pos, i; - - ASSUME(numsamples > 0); - - InitiatePositionArrays(frac, increment, frac_, pos_, 4); - frac4 = _mm_setr_epi32(frac_[0], frac_[1], frac_[2], frac_[3]); - pos4 = _mm_setr_epi32(pos_[0], pos_[1], pos_[2], pos_[3]); - - todo = numsamples & ~3; - for(i = 0;i < todo;i += 4) - { - const int pos0 = _mm_extract_epi32(pos4, 0); - const int pos1 = _mm_extract_epi32(pos4, 1); - const int pos2 = _mm_extract_epi32(pos4, 2); - const int pos3 = _mm_extract_epi32(pos4, 3); - const __m128 val1 = _mm_setr_ps(src[pos0 ], src[pos1 ], src[pos2 ], src[pos3 ]); - const __m128 val2 = _mm_setr_ps(src[pos0+1], src[pos1+1], src[pos2+1], src[pos3+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); - } - - /* NOTE: These four elements represent the position *after* the last four - * samples, so the lowest element is the next position to resample. - */ - pos = _mm_cvtsi128_si32(pos4); - 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/mixer_sse41.cpp b/Alc/mixer/mixer_sse41.cpp new file mode 100644 index 00000000..34b405f8 --- /dev/null +++ b/Alc/mixer/mixer_sse41.cpp @@ -0,0 +1,85 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2014 by Timothy Arceri . + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include "alu.h" +#include "defs.h" + + +const ALfloat *Resample_lerp_SSE41(const InterpState* UNUSED(state), + const ALfloat *RESTRICT src, ALsizei frac, ALint increment, + ALfloat *RESTRICT dst, ALsizei 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) ALsizei pos_[4], frac_[4]; + __m128i frac4, pos4; + ALsizei todo, pos, i; + + ASSUME(numsamples > 0); + + InitiatePositionArrays(frac, increment, frac_, pos_, 4); + frac4 = _mm_setr_epi32(frac_[0], frac_[1], frac_[2], frac_[3]); + pos4 = _mm_setr_epi32(pos_[0], pos_[1], pos_[2], pos_[3]); + + todo = numsamples & ~3; + for(i = 0;i < todo;i += 4) + { + const int pos0 = _mm_extract_epi32(pos4, 0); + const int pos1 = _mm_extract_epi32(pos4, 1); + const int pos2 = _mm_extract_epi32(pos4, 2); + const int pos3 = _mm_extract_epi32(pos4, 3); + const __m128 val1 = _mm_setr_ps(src[pos0 ], src[pos1 ], src[pos2 ], src[pos3 ]); + const __m128 val2 = _mm_setr_ps(src[pos0+1], src[pos1+1], src[pos2+1], src[pos3+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); + } + + /* NOTE: These four elements represent the position *after* the last four + * samples, so the lowest element is the next position to resample. + */ + pos = _mm_cvtsi128_si32(pos4); + 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/CMakeLists.txt b/CMakeLists.txt index d4c48fcd..2b3fef2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -831,7 +831,7 @@ SET(ALC_OBJS Alc/polymorphism.h Alc/mixvoice.cpp Alc/mixer/defs.h - Alc/mixer/mixer_c.c + Alc/mixer/mixer_c.cpp ) @@ -865,9 +865,9 @@ IF(HAVE_XMMINTRIN_H) IF(ALSOFT_CPUEXT_SSE) IF(ALIGN_DECL OR HAVE_C11_ALIGNAS) SET(HAVE_SSE 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse.cpp) IF(SSE_SWITCH) - SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse.c PROPERTIES + SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse.cpp PROPERTIES COMPILE_FLAGS "${SSE_SWITCH}") ENDIF() SET(CPU_EXTS "${CPU_EXTS}, SSE") @@ -885,9 +885,9 @@ IF(HAVE_EMMINTRIN_H) IF(HAVE_SSE AND ALSOFT_CPUEXT_SSE2) IF(ALIGN_DECL OR HAVE_C11_ALIGNAS) SET(HAVE_SSE2 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse2.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse2.cpp) IF(SSE2_SWITCH) - SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse2.c PROPERTIES + SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse2.cpp PROPERTIES COMPILE_FLAGS "${SSE2_SWITCH}") ENDIF() SET(CPU_EXTS "${CPU_EXTS}, SSE2") @@ -905,9 +905,9 @@ IF(HAVE_EMMINTRIN_H) IF(HAVE_SSE2 AND ALSOFT_CPUEXT_SSE3) IF(ALIGN_DECL OR HAVE_C11_ALIGNAS) SET(HAVE_SSE3 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse3.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse3.cpp) IF(SSE2_SWITCH) - SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse3.c PROPERTIES + SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse3.cpp PROPERTIES COMPILE_FLAGS "${SSE3_SWITCH}") ENDIF() SET(CPU_EXTS "${CPU_EXTS}, SSE3") @@ -925,9 +925,9 @@ IF(HAVE_SMMINTRIN_H) IF(HAVE_SSE2 AND ALSOFT_CPUEXT_SSE4_1) IF(ALIGN_DECL OR HAVE_C11_ALIGNAS) SET(HAVE_SSE4_1 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse41.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse41.cpp) IF(SSE4_1_SWITCH) - SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse41.c PROPERTIES + SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse41.cpp PROPERTIES COMPILE_FLAGS "${SSE4_1_SWITCH}") ENDIF() SET(CPU_EXTS "${CPU_EXTS}, SSE4.1") @@ -945,9 +945,9 @@ IF(HAVE_ARM_NEON_H) OPTION(ALSOFT_CPUEXT_NEON "Enable ARM Neon support" ON) IF(ALSOFT_CPUEXT_NEON) SET(HAVE_NEON 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_neon.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_neon.cpp) IF(FPU_NEON_SWITCH) - SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_neon.c PROPERTIES + SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_neon.cpp PROPERTIES COMPILE_FLAGS "${FPU_NEON_SWITCH}") ENDIF() SET(CPU_EXTS "${CPU_EXTS}, Neon") -- cgit v1.2.3 From 9992cef9159cbee8d97fdc43733d370877129ddc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 17:52:23 -0800 Subject: Remove now unneeded inldefs.c All code using inline functions is now C++, so will generate callable functions as-needed. --- Alc/inldefs.c | 111 --------------------------------------------------------- CMakeLists.txt | 1 - 2 files changed, 112 deletions(-) delete mode 100644 Alc/inldefs.c diff --git a/Alc/inldefs.c b/Alc/inldefs.c deleted file mode 100644 index 025f2d27..00000000 --- a/Alc/inldefs.c +++ /dev/null @@ -1,111 +0,0 @@ - -#include "config.h" - -#include "alMain.h" -#include "alu.h" -#include "filters/defs.h" -#include "mixer/defs.h" -#include "alBuffer.h" -#include "alEffect.h" - -/* This is a place to dump inline function instantiations, to generate function - * bodies for calls that can't be inlined. C++ does not have a way to do this - * explicitly, so as long as there is C code calling inline functions, a body - * must be explicitly instantiated in case of non-inlined calls. - * - * This just makes it easier to keep track of everything, while things are - * converted to C++. - */ - -extern inline ALsizei FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type, ALsizei ambiorder); - -extern inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS], enum Channel chan); -extern inline ALint GetChannelIdxByName(const RealMixParams *real, enum Channel chan); - -extern inline void LockBufferList(ALCdevice *device); -extern inline void UnlockBufferList(ALCdevice *device); -extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type); -extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); - - -extern inline ALuint NextPowerOf2(ALuint value); -extern inline size_t RoundUp(size_t value, size_t r); -extern inline ALint fastf2i(ALfloat f); -extern inline int float2int(float f); -extern inline float fast_roundf(float f); -#ifndef __GNUC__ -#if defined(HAVE_BITSCANFORWARD64_INTRINSIC) -extern inline int msvc64_ctz64(ALuint64 v); -#elif defined(HAVE_BITSCANFORWARD_INTRINSIC) -extern inline int msvc_ctz64(ALuint64 v); -#else -extern inline int fallback_popcnt64(ALuint64 v); -extern inline int fallback_ctz64(ALuint64 value); -#endif -#endif - -extern inline ALfloat minf(ALfloat a, ALfloat b); -extern inline ALfloat maxf(ALfloat a, ALfloat b); -extern inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max); - -extern inline ALdouble mind(ALdouble a, ALdouble b); -extern inline ALdouble maxd(ALdouble a, ALdouble b); -extern inline ALdouble clampd(ALdouble val, ALdouble min, ALdouble max); - -extern inline ALuint minu(ALuint a, ALuint b); -extern inline ALuint maxu(ALuint a, ALuint b); -extern inline ALuint clampu(ALuint val, ALuint min, ALuint max); - -extern inline ALint mini(ALint a, ALint b); -extern inline ALint maxi(ALint a, ALint b); -extern inline ALint clampi(ALint val, ALint min, ALint max); - -extern inline ALint64 mini64(ALint64 a, ALint64 b); -extern inline ALint64 maxi64(ALint64 a, ALint64 b); -extern inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max); - -extern inline ALuint64 minu64(ALuint64 a, ALuint64 b); -extern inline ALuint64 maxu64(ALuint64 a, ALuint64 b); -extern inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max); - -extern inline size_t minz(size_t a, size_t b); -extern inline size_t maxz(size_t a, size_t b); -extern inline size_t clampz(size_t val, size_t min, size_t max); - -extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu); -extern inline ALfloat cubic(ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat mu); - -extern inline void aluVectorSet(aluVector *vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w); - -extern inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row, - ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3); -extern inline void aluMatrixfSet(aluMatrixf *matrix, - ALfloat m00, ALfloat m01, ALfloat m02, ALfloat m03, - ALfloat m10, ALfloat m11, ALfloat m12, ALfloat m13, - ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23, - ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33); - -extern inline void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); -extern inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); -extern inline float ScaleAzimuthFront(float azimuth, float scale); -extern inline void ComputePanGains(const MixParams *dry, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); - -extern inline void BiquadFilter_clear(BiquadFilter *filter); -extern inline void BiquadFilter_copyParams(BiquadFilter *RESTRICT dst, const BiquadFilter *RESTRICT src); -extern inline void BiquadFilter_passthru(BiquadFilter *filter, ALsizei numsamples); -extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope); -extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth); - - -extern inline void LockFilterList(ALCdevice *device); -extern inline void UnlockFilterList(ALCdevice *device); - -extern inline void LockEffectList(ALCdevice *device); -extern inline void UnlockEffectList(ALCdevice *device); -extern inline ALboolean IsReverbEffect(ALenum type); - -extern inline void LockEffectSlotList(ALCcontext *context); -extern inline void UnlockEffectSlotList(ALCcontext *context); - - -extern inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *RESTRICT frac_arr, ALsizei *RESTRICT pos_arr, ALsizei size); diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b3fef2a..f1b1e18f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -789,7 +789,6 @@ SET(ALC_OBJS Alc/bs2b.c Alc/converter.cpp Alc/converter.h - Alc/inldefs.c Alc/inprogext.h Alc/mastering.cpp Alc/mastering.h -- cgit v1.2.3 From 1468dee831c6d2d2b05d4fb29de062c72ea3a324 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 18:54:10 -0800 Subject: Convert bs2b.c to C++ --- Alc/bs2b.c | 187 -------------------------------------------------------- Alc/bs2b.cpp | 188 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 3 files changed, 189 insertions(+), 188 deletions(-) delete mode 100644 Alc/bs2b.c create mode 100644 Alc/bs2b.cpp diff --git a/Alc/bs2b.c b/Alc/bs2b.c deleted file mode 100644 index e0ce3249..00000000 --- a/Alc/bs2b.c +++ /dev/null @@ -1,187 +0,0 @@ -/*- - * Copyright (c) 2005 Boris Mikhaylov - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "config.h" - -#include -#include - -#include "bs2b.h" -#include "alu.h" - - -/* Set up all data. */ -static void init(struct bs2b *bs2b) -{ - float Fc_lo, Fc_hi; - float G_lo, G_hi; - float x, g; - - switch(bs2b->level) - { - case BS2B_LOW_CLEVEL: /* Low crossfeed level */ - Fc_lo = 360.0f; - Fc_hi = 501.0f; - G_lo = 0.398107170553497f; - G_hi = 0.205671765275719f; - break; - - case BS2B_MIDDLE_CLEVEL: /* Middle crossfeed level */ - Fc_lo = 500.0f; - Fc_hi = 711.0f; - G_lo = 0.459726988530872f; - G_hi = 0.228208484414988f; - break; - - case BS2B_HIGH_CLEVEL: /* High crossfeed level (virtual speakers are closer to itself) */ - Fc_lo = 700.0f; - Fc_hi = 1021.0f; - G_lo = 0.530884444230988f; - G_hi = 0.250105790667544f; - break; - - case BS2B_LOW_ECLEVEL: /* Low easy crossfeed level */ - Fc_lo = 360.0f; - Fc_hi = 494.0f; - G_lo = 0.316227766016838f; - G_hi = 0.168236228897329f; - break; - - case BS2B_MIDDLE_ECLEVEL: /* Middle easy crossfeed level */ - Fc_lo = 500.0f; - Fc_hi = 689.0f; - G_lo = 0.354813389233575f; - G_hi = 0.187169483835901f; - break; - - default: /* High easy crossfeed level */ - bs2b->level = BS2B_HIGH_ECLEVEL; - - Fc_lo = 700.0f; - Fc_hi = 975.0f; - G_lo = 0.398107170553497f; - G_hi = 0.205671765275719f; - break; - } /* switch */ - - g = 1.0f / (1.0f - G_hi + G_lo); - - /* $fc = $Fc / $s; - * $d = 1 / 2 / pi / $fc; - * $x = exp(-1 / $d); - */ - x = expf(-2.0f * F_PI * Fc_lo / bs2b->srate); - bs2b->b1_lo = x; - bs2b->a0_lo = G_lo * (1.0f - x) * g; - - x = expf(-2.0f * F_PI * Fc_hi / bs2b->srate); - bs2b->b1_hi = x; - bs2b->a0_hi = (1.0f - G_hi * (1.0f - x)) * g; - bs2b->a1_hi = -x * g; -} /* init */ - - -/* Exported functions. - * See descriptions in "bs2b.h" - */ - -void bs2b_set_params(struct bs2b *bs2b, int level, int srate) -{ - if(srate <= 0) srate = 1; - - bs2b->level = level; - bs2b->srate = srate; - init(bs2b); -} /* bs2b_set_params */ - -int bs2b_get_level(struct bs2b *bs2b) -{ - return bs2b->level; -} /* bs2b_get_level */ - -int bs2b_get_srate(struct bs2b *bs2b) -{ - return bs2b->srate; -} /* bs2b_get_srate */ - -void bs2b_clear(struct bs2b *bs2b) -{ - memset(&bs2b->last_sample, 0, sizeof(bs2b->last_sample)); -} /* bs2b_clear */ - -void bs2b_cross_feed(struct bs2b *bs2b, float *RESTRICT Left, float *RESTRICT Right, int SamplesToDo) -{ - float lsamples[128][2]; - float rsamples[128][2]; - int base; - - for(base = 0;base < SamplesToDo;) - { - int todo = mini(128, SamplesToDo-base); - int i; - - /* Process left input */ - lsamples[0][0] = bs2b->a0_lo*Left[0] + - bs2b->b1_lo*bs2b->last_sample[0].lo; - lsamples[0][1] = bs2b->a0_hi*Left[0] + - bs2b->a1_hi*bs2b->last_sample[0].asis + - bs2b->b1_hi*bs2b->last_sample[0].hi; - for(i = 1;i < todo;i++) - { - lsamples[i][0] = bs2b->a0_lo*Left[i] + - bs2b->b1_lo*lsamples[i-1][0]; - lsamples[i][1] = bs2b->a0_hi*Left[i] + - bs2b->a1_hi*Left[i-1] + - bs2b->b1_hi*lsamples[i-1][1]; - } - bs2b->last_sample[0].asis = Left[i-1]; - bs2b->last_sample[0].lo = lsamples[i-1][0]; - bs2b->last_sample[0].hi = lsamples[i-1][1]; - - /* Process right input */ - rsamples[0][0] = bs2b->a0_lo*Right[0] + - bs2b->b1_lo*bs2b->last_sample[1].lo; - rsamples[0][1] = bs2b->a0_hi*Right[0] + - bs2b->a1_hi*bs2b->last_sample[1].asis + - bs2b->b1_hi*bs2b->last_sample[1].hi; - for(i = 1;i < todo;i++) - { - rsamples[i][0] = bs2b->a0_lo*Right[i] + - bs2b->b1_lo*rsamples[i-1][0]; - rsamples[i][1] = bs2b->a0_hi*Right[i] + - bs2b->a1_hi*Right[i-1] + - bs2b->b1_hi*rsamples[i-1][1]; - } - bs2b->last_sample[1].asis = Right[i-1]; - bs2b->last_sample[1].lo = rsamples[i-1][0]; - bs2b->last_sample[1].hi = rsamples[i-1][1]; - - /* Crossfeed */ - for(i = 0;i < todo;i++) - *(Left++) = lsamples[i][1] + rsamples[i][0]; - for(i = 0;i < todo;i++) - *(Right++) = rsamples[i][1] + lsamples[i][0]; - - base += todo; - } -} /* bs2b_cross_feed */ diff --git a/Alc/bs2b.cpp b/Alc/bs2b.cpp new file mode 100644 index 00000000..1307e5c1 --- /dev/null +++ b/Alc/bs2b.cpp @@ -0,0 +1,188 @@ +/*- + * Copyright (c) 2005 Boris Mikhaylov + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include +#include +#include + +#include "bs2b.h" +#include "math_defs.h" + + +/* Set up all data. */ +static void init(struct bs2b *bs2b) +{ + float Fc_lo, Fc_hi; + float G_lo, G_hi; + float x, g; + + switch(bs2b->level) + { + case BS2B_LOW_CLEVEL: /* Low crossfeed level */ + Fc_lo = 360.0f; + Fc_hi = 501.0f; + G_lo = 0.398107170553497f; + G_hi = 0.205671765275719f; + break; + + case BS2B_MIDDLE_CLEVEL: /* Middle crossfeed level */ + Fc_lo = 500.0f; + Fc_hi = 711.0f; + G_lo = 0.459726988530872f; + G_hi = 0.228208484414988f; + break; + + case BS2B_HIGH_CLEVEL: /* High crossfeed level (virtual speakers are closer to itself) */ + Fc_lo = 700.0f; + Fc_hi = 1021.0f; + G_lo = 0.530884444230988f; + G_hi = 0.250105790667544f; + break; + + case BS2B_LOW_ECLEVEL: /* Low easy crossfeed level */ + Fc_lo = 360.0f; + Fc_hi = 494.0f; + G_lo = 0.316227766016838f; + G_hi = 0.168236228897329f; + break; + + case BS2B_MIDDLE_ECLEVEL: /* Middle easy crossfeed level */ + Fc_lo = 500.0f; + Fc_hi = 689.0f; + G_lo = 0.354813389233575f; + G_hi = 0.187169483835901f; + break; + + default: /* High easy crossfeed level */ + bs2b->level = BS2B_HIGH_ECLEVEL; + + Fc_lo = 700.0f; + Fc_hi = 975.0f; + G_lo = 0.398107170553497f; + G_hi = 0.205671765275719f; + break; + } /* switch */ + + g = 1.0f / (1.0f - G_hi + G_lo); + + /* $fc = $Fc / $s; + * $d = 1 / 2 / pi / $fc; + * $x = exp(-1 / $d); + */ + x = std::exp(-2.0f * F_PI * Fc_lo / bs2b->srate); + bs2b->b1_lo = x; + bs2b->a0_lo = G_lo * (1.0f - x) * g; + + x = std::exp(-2.0f * F_PI * Fc_hi / bs2b->srate); + bs2b->b1_hi = x; + bs2b->a0_hi = (1.0f - G_hi * (1.0f - x)) * g; + bs2b->a1_hi = -x * g; +} /* init */ + + +/* Exported functions. + * See descriptions in "bs2b.h" + */ + +void bs2b_set_params(struct bs2b *bs2b, int level, int srate) +{ + if(srate <= 0) srate = 1; + + bs2b->level = level; + bs2b->srate = srate; + init(bs2b); +} /* bs2b_set_params */ + +int bs2b_get_level(struct bs2b *bs2b) +{ + return bs2b->level; +} /* bs2b_get_level */ + +int bs2b_get_srate(struct bs2b *bs2b) +{ + return bs2b->srate; +} /* bs2b_get_srate */ + +void bs2b_clear(struct bs2b *bs2b) +{ + std::memset(&bs2b->last_sample, 0, sizeof(bs2b->last_sample)); +} /* bs2b_clear */ + +void bs2b_cross_feed(struct bs2b *bs2b, float *RESTRICT Left, float *RESTRICT Right, int SamplesToDo) +{ + float lsamples[128][2]; + float rsamples[128][2]; + int base; + + for(base = 0;base < SamplesToDo;) + { + int todo = std::min(128, SamplesToDo-base); + int i; + + /* Process left input */ + lsamples[0][0] = bs2b->a0_lo*Left[0] + + bs2b->b1_lo*bs2b->last_sample[0].lo; + lsamples[0][1] = bs2b->a0_hi*Left[0] + + bs2b->a1_hi*bs2b->last_sample[0].asis + + bs2b->b1_hi*bs2b->last_sample[0].hi; + for(i = 1;i < todo;i++) + { + lsamples[i][0] = bs2b->a0_lo*Left[i] + + bs2b->b1_lo*lsamples[i-1][0]; + lsamples[i][1] = bs2b->a0_hi*Left[i] + + bs2b->a1_hi*Left[i-1] + + bs2b->b1_hi*lsamples[i-1][1]; + } + bs2b->last_sample[0].asis = Left[i-1]; + bs2b->last_sample[0].lo = lsamples[i-1][0]; + bs2b->last_sample[0].hi = lsamples[i-1][1]; + + /* Process right input */ + rsamples[0][0] = bs2b->a0_lo*Right[0] + + bs2b->b1_lo*bs2b->last_sample[1].lo; + rsamples[0][1] = bs2b->a0_hi*Right[0] + + bs2b->a1_hi*bs2b->last_sample[1].asis + + bs2b->b1_hi*bs2b->last_sample[1].hi; + for(i = 1;i < todo;i++) + { + rsamples[i][0] = bs2b->a0_lo*Right[i] + + bs2b->b1_lo*rsamples[i-1][0]; + rsamples[i][1] = bs2b->a0_hi*Right[i] + + bs2b->a1_hi*Right[i-1] + + bs2b->b1_hi*rsamples[i-1][1]; + } + bs2b->last_sample[1].asis = Right[i-1]; + bs2b->last_sample[1].lo = rsamples[i-1][0]; + bs2b->last_sample[1].hi = rsamples[i-1][1]; + + /* Crossfeed */ + for(i = 0;i < todo;i++) + *(Left++) = lsamples[i][1] + rsamples[i][0]; + for(i = 0;i < todo;i++) + *(Right++) = rsamples[i][1] + lsamples[i][0]; + + base += todo; + } +} /* bs2b_cross_feed */ diff --git a/CMakeLists.txt b/CMakeLists.txt index f1b1e18f..89357900 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -786,7 +786,7 @@ SET(ALC_OBJS Alc/alu.cpp Alc/alconfig.cpp Alc/alconfig.h - Alc/bs2b.c + Alc/bs2b.cpp Alc/converter.cpp Alc/converter.h Alc/inprogext.h -- cgit v1.2.3 From 8c69fb046c9a3b983f360a71614512e0e0e5aeac Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 18:56:00 -0800 Subject: Always use C++11 atomics --- CMakeLists.txt | 1 - common/atomic.c | 10 -- common/atomic.h | 338 +------------------------------------------------------- 3 files changed, 2 insertions(+), 347 deletions(-) delete mode 100644 common/atomic.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 89357900..ebb8ec19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -747,7 +747,6 @@ SET(COMMON_OBJS common/align.h common/almalloc.c common/almalloc.h - common/atomic.c common/atomic.h common/bool.h common/math_defs.h diff --git a/common/atomic.c b/common/atomic.c deleted file mode 100644 index 7a8fe6d8..00000000 --- a/common/atomic.c +++ /dev/null @@ -1,10 +0,0 @@ - -#include "config.h" - -#include "atomic.h" - - -extern inline void InitRef(RefCount *ptr, uint value); -extern inline uint ReadRef(RefCount *ptr); -extern inline uint IncrementRef(RefCount *ptr); -extern inline uint DecrementRef(RefCount *ptr); diff --git a/common/atomic.h b/common/atomic.h index 2c81f62f..4976149a 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -1,6 +1,8 @@ #ifndef AL_ATOMIC_H #define AL_ATOMIC_H +#include + #include "static_assert.h" #include "bool.h" @@ -17,23 +19,6 @@ #define CONST_CAST(T, V) ((T)(V)) #endif -#ifdef HAVE_C11_ATOMIC -#ifdef __cplusplus -/* C++11 doesn't support compatibility with C11 atomics. So instead, make C++11 - * atomic declarations global to emulate C11. There's no standard guarantee of - * ABI compatibility, but it's desired behavior that mostly works. See: - * - * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0943r1.html - * - * Any alignment issues arising from this can be fixed with explicit alignas() - * specifiers on affected variables. - * - * Only do this when C11 atomics are supported in C, since MSVC and pre-C11 - * compilers may use something else that is significantly different in C - * despite supporting C++11 atomics. - */ -#include - #define _Atomic(T) std::atomic using std::memory_order; using std::memory_order_relaxed; @@ -53,19 +38,6 @@ using std::atomic_compare_exchange_strong_explicit; using std::atomic_compare_exchange_weak_explicit; using std::atomic_thread_fence; -#else - -#include -#endif /* __cplusplus */ -#endif /* HAVE_C11_ATOMIC */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Atomics using C11 */ -#ifdef HAVE_C11_ATOMIC - #define almemory_order memory_order #define almemory_order_relaxed memory_order_relaxed #define almemory_order_consume memory_order_consume @@ -91,299 +63,6 @@ extern "C" { #define ATOMIC_THREAD_FENCE atomic_thread_fence -/* Atomics using GCC intrinsics */ -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && !defined(__QNXNTO__) - -enum almemory_order { - almemory_order_relaxed, - almemory_order_consume, - almemory_order_acquire, - almemory_order_release, - almemory_order_acq_rel, - almemory_order_seq_cst -}; - -#define ATOMIC(T) struct { T volatile value; } - -#define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0) -#define ATOMIC_INIT_STATIC(_newval) {(_newval)} - -#define ATOMIC_LOAD(_val, _MO) __extension__({ \ - __typeof((_val)->value) _r = (_val)->value; \ - __asm__ __volatile__("" ::: "memory"); \ - _r; \ -}) -#define ATOMIC_STORE(_val, _newval, _MO) do { \ - __asm__ __volatile__("" ::: "memory"); \ - (_val)->value = (_newval); \ -} while(0) - -#define ATOMIC_ADD(_val, _incr, _MO) __sync_fetch_and_add(&(_val)->value, (_incr)) -#define ATOMIC_SUB(_val, _decr, _MO) __sync_fetch_and_sub(&(_val)->value, (_decr)) - -#define ATOMIC_EXCHANGE(_val, _newval, _MO) __extension__({ \ - __asm__ __volatile__("" ::: "memory"); \ - __sync_lock_test_and_set(&(_val)->value, (_newval)); \ -}) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _oldval, _newval, _MO1, _MO2) __extension__({ \ - __typeof(*(_oldval)) _o = *(_oldval); \ - *(_oldval) = __sync_val_compare_and_swap(&(_val)->value, _o, (_newval)); \ - *(_oldval) == _o; \ -}) - - -#define ATOMIC_THREAD_FENCE(order) do { \ - enum { must_be_constant = (order) }; \ - const int _o = must_be_constant; \ - if(_o > almemory_order_relaxed) \ - __asm__ __volatile__("" ::: "memory"); \ -} while(0) - -/* Atomics using x86/x86-64 GCC inline assembly */ -#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - -#define WRAP_ADD(S, ret, dest, incr) __asm__ __volatile__( \ - "lock; xadd" S " %0,(%1)" \ - : "=r" (ret) \ - : "r" (dest), "0" (incr) \ - : "memory" \ -) -#define WRAP_SUB(S, ret, dest, decr) __asm__ __volatile__( \ - "lock; xadd" S " %0,(%1)" \ - : "=r" (ret) \ - : "r" (dest), "0" (-(decr)) \ - : "memory" \ -) - -#define WRAP_XCHG(S, ret, dest, newval) __asm__ __volatile__( \ - "lock; xchg" S " %0,(%1)" \ - : "=r" (ret) \ - : "r" (dest), "0" (newval) \ - : "memory" \ -) -#define WRAP_CMPXCHG(S, ret, dest, oldval, newval) __asm__ __volatile__( \ - "lock; cmpxchg" S " %2,(%1)" \ - : "=a" (ret) \ - : "r" (dest), "r" (newval), "0" (oldval) \ - : "memory" \ -) - - -enum almemory_order { - almemory_order_relaxed, - almemory_order_consume, - almemory_order_acquire, - almemory_order_release, - almemory_order_acq_rel, - almemory_order_seq_cst -}; - -#define ATOMIC(T) struct { T volatile value; } - -#define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0) -#define ATOMIC_INIT_STATIC(_newval) {(_newval)} - -#define ATOMIC_LOAD(_val, _MO) __extension__({ \ - __typeof((_val)->value) _r = (_val)->value; \ - __asm__ __volatile__("" ::: "memory"); \ - _r; \ -}) -#define ATOMIC_STORE(_val, _newval, _MO) do { \ - __asm__ __volatile__("" ::: "memory"); \ - (_val)->value = (_newval); \ -} while(0) - -#define ATOMIC_ADD(_val, _incr, _MO) __extension__({ \ - static_assert(sizeof((_val)->value)==4 || sizeof((_val)->value)==8, "Unsupported size!"); \ - __typeof((_val)->value) _r; \ - if(sizeof((_val)->value) == 4) WRAP_ADD("l", _r, &(_val)->value, _incr); \ - else if(sizeof((_val)->value) == 8) WRAP_ADD("q", _r, &(_val)->value, _incr); \ - _r; \ -}) -#define ATOMIC_SUB(_val, _decr, _MO) __extension__({ \ - static_assert(sizeof((_val)->value)==4 || sizeof((_val)->value)==8, "Unsupported size!"); \ - __typeof((_val)->value) _r; \ - if(sizeof((_val)->value) == 4) WRAP_SUB("l", _r, &(_val)->value, _decr); \ - else if(sizeof((_val)->value) == 8) WRAP_SUB("q", _r, &(_val)->value, _decr); \ - _r; \ -}) - -#define ATOMIC_EXCHANGE(_val, _newval, _MO) __extension__({ \ - __typeof((_val)->value) _r; \ - if(sizeof((_val)->value) == 4) WRAP_XCHG("l", _r, &(_val)->value, (_newval)); \ - else if(sizeof((_val)->value) == 8) WRAP_XCHG("q", _r, &(_val)->value, (_newval)); \ - _r; \ -}) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _oldval, _newval, _MO1, _MO2) __extension__({ \ - __typeof(*(_oldval)) _old = *(_oldval); \ - if(sizeof((_val)->value) == 4) WRAP_CMPXCHG("l", *(_oldval), &(_val)->value, _old, (_newval)); \ - else if(sizeof((_val)->value) == 8) WRAP_CMPXCHG("q", *(_oldval), &(_val)->value, _old, (_newval)); \ - *(_oldval) == _old; \ -}) - -#define ATOMIC_EXCHANGE_PTR(_val, _newval, _MO) __extension__({ \ - void *_r; \ - if(sizeof(void*) == 4) WRAP_XCHG("l", _r, &(_val)->value, (_newval)); \ - else if(sizeof(void*) == 8) WRAP_XCHG("q", _r, &(_val)->value, (_newval));\ - _r; \ -}) -#define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG(_val, _oldval, _newval, _MO1, _MO2) __extension__({ \ - void *_old = *(_oldval); \ - if(sizeof(void*) == 4) WRAP_CMPXCHG("l", *(_oldval), &(_val)->value, _old, (_newval)); \ - else if(sizeof(void*) == 8) WRAP_CMPXCHG("q", *(_oldval), &(_val)->value, _old, (_newval)); \ - *(_oldval) == _old; \ -}) - -#define ATOMIC_THREAD_FENCE(order) do { \ - enum { must_be_constant = (order) }; \ - const int _o = must_be_constant; \ - if(_o > almemory_order_relaxed) \ - __asm__ __volatile__("" ::: "memory"); \ -} while(0) - -/* Atomics using Windows methods */ -#elif defined(_WIN32) - -#define WIN32_LEAN_AND_MEAN -#include - -/* NOTE: This mess is *extremely* touchy. It lacks quite a bit of safety - * checking due to the lack of multi-statement expressions, typeof(), and C99 - * compound literals. It is incapable of properly exchanging floats, which get - * casted to LONG/int, and could cast away potential warnings. - * - * Unfortunately, it's the only semi-safe way that doesn't rely on C99 (because - * MSVC). - */ - -inline LONG AtomicAdd32(volatile LONG *dest, LONG incr) -{ - return InterlockedExchangeAdd(dest, incr); -} -inline LONGLONG AtomicAdd64(volatile LONGLONG *dest, LONGLONG incr) -{ - return InterlockedExchangeAdd64(dest, incr); -} -inline LONG AtomicSub32(volatile LONG *dest, LONG decr) -{ - return InterlockedExchangeAdd(dest, -decr); -} -inline LONGLONG AtomicSub64(volatile LONGLONG *dest, LONGLONG decr) -{ - return InterlockedExchangeAdd64(dest, -decr); -} - -inline LONG AtomicSwap32(volatile LONG *dest, LONG newval) -{ - return InterlockedExchange(dest, newval); -} -inline LONGLONG AtomicSwap64(volatile LONGLONG *dest, LONGLONG newval) -{ - return InterlockedExchange64(dest, newval); -} -inline void *AtomicSwapPtr(void *volatile *dest, void *newval) -{ - return InterlockedExchangePointer(dest, newval); -} - -inline bool CompareAndSwap32(volatile LONG *dest, LONG newval, LONG *oldval) -{ - LONG old = *oldval; - *oldval = InterlockedCompareExchange(dest, newval, *oldval); - return old == *oldval; -} -inline bool CompareAndSwap64(volatile LONGLONG *dest, LONGLONG newval, LONGLONG *oldval) -{ - LONGLONG old = *oldval; - *oldval = InterlockedCompareExchange64(dest, newval, *oldval); - return old == *oldval; -} -inline bool CompareAndSwapPtr(void *volatile *dest, void *newval, void **oldval) -{ - void *old = *oldval; - *oldval = InterlockedCompareExchangePointer(dest, newval, *oldval); - return old == *oldval; -} - -#define WRAP_ADDSUB(T, _func, _ptr, _amnt) _func((T volatile*)(_ptr), (_amnt)) -#define WRAP_XCHG(T, _func, _ptr, _newval) _func((T volatile*)(_ptr), (_newval)) -#define WRAP_CMPXCHG(T, _func, _ptr, _newval, _oldval) _func((T volatile*)(_ptr), (_newval), (T*)(_oldval)) - - -enum almemory_order { - almemory_order_relaxed, - almemory_order_consume, - almemory_order_acquire, - almemory_order_release, - almemory_order_acq_rel, - almemory_order_seq_cst -}; - -#define ATOMIC(T) struct { T volatile value; } - -#define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0) -#define ATOMIC_INIT_STATIC(_newval) {(_newval)} - -#define ATOMIC_LOAD(_val, _MO) ((_val)->value) -#define ATOMIC_STORE(_val, _newval, _MO) do { \ - (_val)->value = (_newval); \ -} while(0) - -int _al_invalid_atomic_size(); /* not defined */ -void *_al_invalid_atomic_ptr_size(); /* not defined */ - -#define ATOMIC_ADD(_val, _incr, _MO) \ - ((sizeof((_val)->value)==4) ? WRAP_ADDSUB(LONG, AtomicAdd32, &(_val)->value, (_incr)) : \ - (sizeof((_val)->value)==8) ? WRAP_ADDSUB(LONGLONG, AtomicAdd64, &(_val)->value, (_incr)) : \ - _al_invalid_atomic_size()) -#define ATOMIC_SUB(_val, _decr, _MO) \ - ((sizeof((_val)->value)==4) ? WRAP_ADDSUB(LONG, AtomicSub32, &(_val)->value, (_decr)) : \ - (sizeof((_val)->value)==8) ? WRAP_ADDSUB(LONGLONG, AtomicSub64, &(_val)->value, (_decr)) : \ - _al_invalid_atomic_size()) - -#define ATOMIC_EXCHANGE(_val, _newval, _MO) \ - ((sizeof((_val)->value)==4) ? WRAP_XCHG(LONG, AtomicSwap32, &(_val)->value, (_newval)) : \ - (sizeof((_val)->value)==8) ? WRAP_XCHG(LONGLONG, AtomicSwap64, &(_val)->value, (_newval)) : \ - (LONG)_al_invalid_atomic_size()) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _oldval, _newval, _MO1, _MO2) \ - ((sizeof((_val)->value)==4) ? WRAP_CMPXCHG(LONG, CompareAndSwap32, &(_val)->value, (_newval), (_oldval)) : \ - (sizeof((_val)->value)==8) ? WRAP_CMPXCHG(LONGLONG, CompareAndSwap64, &(_val)->value, (_newval), (_oldval)) : \ - (bool)_al_invalid_atomic_size()) - -#define ATOMIC_EXCHANGE_PTR(_val, _newval, _MO) \ - ((sizeof((_val)->value)==sizeof(void*)) ? AtomicSwapPtr((void*volatile*)&(_val)->value, (_newval)) : \ - _al_invalid_atomic_ptr_size()) -#define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG(_val, _oldval, _newval, _MO1, _MO2)\ - ((sizeof((_val)->value)==sizeof(void*)) ? CompareAndSwapPtr((void*volatile*)&(_val)->value, (_newval), (void**)(_oldval)) : \ - (bool)_al_invalid_atomic_size()) - -#define ATOMIC_THREAD_FENCE(order) do { \ - enum { must_be_constant = (order) }; \ - const int _o = must_be_constant; \ - if(_o > almemory_order_relaxed) \ - _ReadWriteBarrier(); \ -} while(0) - -#else - -#error "No atomic functions available on this platform!" - -#define ATOMIC(T) T - -#define ATOMIC_INIT(_val, _newval) ((void)0) -#define ATOMIC_INIT_STATIC(_newval) (0) - -#define ATOMIC_LOAD(...) (0) -#define ATOMIC_STORE(...) ((void)0) - -#define ATOMIC_ADD(...) (0) -#define ATOMIC_SUB(...) (0) - -#define ATOMIC_EXCHANGE(...) (0) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(...) (0) - -#define ATOMIC_THREAD_FENCE(...) ((void)0) -#endif /* If no PTR xchg variants are provided, the normal ones can handle it. */ #ifndef ATOMIC_EXCHANGE_PTR @@ -392,15 +71,6 @@ void *_al_invalid_atomic_ptr_size(); /* not defined */ #define ATOMIC_COMPARE_EXCHANGE_PTR_WEAK ATOMIC_COMPARE_EXCHANGE_WEAK #endif -/* If no weak cmpxchg is provided (not all systems will have one), substitute a - * strong cmpxchg. */ -#ifndef ATOMIC_COMPARE_EXCHANGE_WEAK -#define ATOMIC_COMPARE_EXCHANGE_WEAK ATOMIC_COMPARE_EXCHANGE_STRONG -#endif -#ifndef ATOMIC_COMPARE_EXCHANGE_PTR_WEAK -#define ATOMIC_COMPARE_EXCHANGE_PTR_WEAK ATOMIC_COMPARE_EXCHANGE_PTR_STRONG -#endif - #define ATOMIC_LOAD_SEQ(_val) ATOMIC_LOAD(_val, almemory_order_seq_cst) #define ATOMIC_STORE_SEQ(_val, _newval) ATOMIC_STORE(_val, _newval, almemory_order_seq_cst) @@ -446,8 +116,4 @@ inline uint DecrementRef(RefCount *ptr) almemory_order_acq_rel, almemory_order_acquire) == 0); \ } while(0) -#ifdef __cplusplus -} -#endif - #endif /* AL_ATOMIC_H */ -- cgit v1.2.3 From 1ac41d3ea03aed456a94187bf8e0381eeb4168e6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 19:01:10 -0800 Subject: Convert almalloc.c to C++ --- CMakeLists.txt | 2 +- common/almalloc.c | 110 ---------------------------------------------------- common/almalloc.cpp | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 111 deletions(-) delete mode 100644 common/almalloc.c create mode 100644 common/almalloc.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ebb8ec19..3e4c6d4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -745,7 +745,7 @@ SET(COMMON_OBJS common/alcomplex.cpp common/alcomplex.h common/align.h - common/almalloc.c + common/almalloc.cpp common/almalloc.h common/atomic.h common/bool.h diff --git a/common/almalloc.c b/common/almalloc.c deleted file mode 100644 index 0d982ca1..00000000 --- a/common/almalloc.c +++ /dev/null @@ -1,110 +0,0 @@ - -#include "config.h" - -#include "almalloc.h" - -#include -#include -#ifdef HAVE_MALLOC_H -#include -#endif -#ifdef HAVE_WINDOWS_H -#include -#else -#include -#endif - - -#ifdef __GNUC__ -#define LIKELY(x) __builtin_expect(!!(x), !0) -#define UNLIKELY(x) __builtin_expect(!!(x), 0) -#else -#define LIKELY(x) (!!(x)) -#define UNLIKELY(x) (!!(x)) -#endif - - -void *al_malloc(size_t alignment, size_t size) -{ -#if defined(HAVE_ALIGNED_ALLOC) - size = (size+(alignment-1))&~(alignment-1); - return aligned_alloc(alignment, size); -#elif defined(HAVE_POSIX_MEMALIGN) - void *ret; - if(posix_memalign(&ret, alignment, size) == 0) - return ret; - return NULL; -#elif defined(HAVE__ALIGNED_MALLOC) - return _aligned_malloc(size, alignment); -#else - char *ret = malloc(size+alignment); - if(ret != NULL) - { - *(ret++) = 0x00; - while(((ptrdiff_t)ret&(alignment-1)) != 0) - *(ret++) = 0x55; - } - return ret; -#endif -} - -void *al_calloc(size_t alignment, size_t size) -{ - void *ret = al_malloc(alignment, size); - if(ret) memset(ret, 0, size); - return ret; -} - -void al_free(void *ptr) -{ -#if defined(HAVE_ALIGNED_ALLOC) || defined(HAVE_POSIX_MEMALIGN) - free(ptr); -#elif defined(HAVE__ALIGNED_MALLOC) - _aligned_free(ptr); -#else - if(ptr != NULL) - { - char *finder = ptr; - do { - --finder; - } while(*finder == 0x55); - free(finder); - } -#endif -} - -size_t al_get_page_size(void) -{ - static size_t psize = 0; - if(UNLIKELY(!psize)) - { -#ifdef HAVE_SYSCONF -#if defined(_SC_PAGESIZE) - if(!psize) psize = sysconf(_SC_PAGESIZE); -#elif defined(_SC_PAGE_SIZE) - if(!psize) psize = sysconf(_SC_PAGE_SIZE); -#endif -#endif /* HAVE_SYSCONF */ -#ifdef _WIN32 - if(!psize) - { - SYSTEM_INFO sysinfo; - memset(&sysinfo, 0, sizeof(sysinfo)); - - GetSystemInfo(&sysinfo); - psize = sysinfo.dwPageSize; - } -#endif - if(!psize) psize = DEF_ALIGN; - } - return psize; -} - -int al_is_sane_alignment_allocator(void) -{ -#if defined(HAVE_ALIGNED_ALLOC) || defined(HAVE_POSIX_MEMALIGN) || defined(HAVE__ALIGNED_MALLOC) - return 1; -#else - return 0; -#endif -} diff --git a/common/almalloc.cpp b/common/almalloc.cpp new file mode 100644 index 00000000..1b90d1c0 --- /dev/null +++ b/common/almalloc.cpp @@ -0,0 +1,110 @@ + +#include "config.h" + +#include "almalloc.h" + +#include +#include +#ifdef HAVE_MALLOC_H +#include +#endif +#ifdef HAVE_WINDOWS_H +#include +#else +#include +#endif + + +#ifdef __GNUC__ +#define LIKELY(x) __builtin_expect(!!(x), !0) +#define UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define LIKELY(x) (!!(x)) +#define UNLIKELY(x) (!!(x)) +#endif + + +void *al_malloc(size_t alignment, size_t size) +{ +#if defined(HAVE_ALIGNED_ALLOC) + size = (size+(alignment-1))&~(alignment-1); + return aligned_alloc(alignment, size); +#elif defined(HAVE_POSIX_MEMALIGN) + void *ret; + if(posix_memalign(&ret, alignment, size) == 0) + return ret; + return NULL; +#elif defined(HAVE__ALIGNED_MALLOC) + return _aligned_malloc(size, alignment); +#else + char *ret = static_cast(malloc(size+alignment)); + if(ret != NULL) + { + *(ret++) = 0x00; + while(((ptrdiff_t)ret&(alignment-1)) != 0) + *(ret++) = 0x55; + } + return ret; +#endif +} + +void *al_calloc(size_t alignment, size_t size) +{ + void *ret = al_malloc(alignment, size); + if(ret) memset(ret, 0, size); + return ret; +} + +void al_free(void *ptr) +{ +#if defined(HAVE_ALIGNED_ALLOC) || defined(HAVE_POSIX_MEMALIGN) + free(ptr); +#elif defined(HAVE__ALIGNED_MALLOC) + _aligned_free(ptr); +#else + if(ptr != NULL) + { + char *finder = static_cast(ptr); + do { + --finder; + } while(*finder == 0x55); + free(finder); + } +#endif +} + +size_t al_get_page_size(void) +{ + static size_t psize = 0; + if(UNLIKELY(!psize)) + { +#ifdef HAVE_SYSCONF +#if defined(_SC_PAGESIZE) + if(!psize) psize = sysconf(_SC_PAGESIZE); +#elif defined(_SC_PAGE_SIZE) + if(!psize) psize = sysconf(_SC_PAGE_SIZE); +#endif +#endif /* HAVE_SYSCONF */ +#ifdef _WIN32 + if(!psize) + { + SYSTEM_INFO sysinfo; + memset(&sysinfo, 0, sizeof(sysinfo)); + + GetSystemInfo(&sysinfo); + psize = sysinfo.dwPageSize; + } +#endif + if(!psize) psize = DEF_ALIGN; + } + return psize; +} + +int al_is_sane_alignment_allocator(void) +{ +#if defined(HAVE_ALIGNED_ALLOC) || defined(HAVE_POSIX_MEMALIGN) || defined(HAVE__ALIGNED_MALLOC) + return 1; +#else + return 0; +#endif +} -- cgit v1.2.3 From d10301c209a1194741d442a44cc4c0d819803144 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 19:52:54 -0800 Subject: Remove unused headers and checks --- Alc/alconfig.cpp | 1 - Alc/alu.cpp | 1 - Alc/bformatdec.cpp | 1 - Alc/mastering.cpp | 1 - Alc/mixer/hrtf_inc.cpp | 1 - Alc/panning.cpp | 1 - Alc/ringbuffer.cpp | 1 - CMakeLists.txt | 100 +++++++++---------------------------- OpenAL32/Include/alAuxEffectSlot.h | 1 - OpenAL32/Include/alMain.h | 2 - OpenAL32/Include/alSource.h | 1 - OpenAL32/Include/alu.h | 1 - common/align.h | 18 ------- common/atomic.h | 3 -- common/bool.h | 18 ------- common/static_assert.h | 21 -------- config.h.in | 18 ------- 17 files changed, 24 insertions(+), 166 deletions(-) delete mode 100644 common/align.h delete mode 100644 common/bool.h delete mode 100644 common/static_assert.h diff --git a/Alc/alconfig.cpp b/Alc/alconfig.cpp index 5198f830..73ea0458 100644 --- a/Alc/alconfig.cpp +++ b/Alc/alconfig.cpp @@ -46,7 +46,6 @@ #include "alMain.h" #include "alconfig.h" #include "compat.h" -#include "bool.h" namespace { diff --git a/Alc/alu.cpp b/Alc/alu.cpp index df857b80..3075f1ec 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -37,7 +37,6 @@ #include "mastering.h" #include "uhjfilter.h" #include "bformatdec.h" -#include "static_assert.h" #include "ringbuffer.h" #include "filters/splitter.h" diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 7d1e36ff..afa25461 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -9,7 +9,6 @@ #include "filters/splitter.h" #include "alu.h" -#include "bool.h" #include "threads.h" #include "almalloc.h" diff --git a/Alc/mastering.cpp b/Alc/mastering.cpp index 001aada1..131a0330 100644 --- a/Alc/mastering.cpp +++ b/Alc/mastering.cpp @@ -5,7 +5,6 @@ #include "mastering.h" #include "alu.h" #include "almalloc.h" -#include "static_assert.h" #include "math_defs.h" diff --git a/Alc/mixer/hrtf_inc.cpp b/Alc/mixer/hrtf_inc.cpp index 1f70242d..22715abc 100644 --- a/Alc/mixer/hrtf_inc.cpp +++ b/Alc/mixer/hrtf_inc.cpp @@ -4,7 +4,6 @@ #include "alSource.h" #include "hrtf.h" -#include "align.h" #include "alu.h" #include "defs.h" diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 9bde25a0..a60b4d4d 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -30,7 +30,6 @@ #include "alAuxEffectSlot.h" #include "alu.h" #include "alconfig.h" -#include "bool.h" #include "ambdec.h" #include "bformatdec.h" #include "filters/splitter.h" diff --git a/Alc/ringbuffer.cpp b/Alc/ringbuffer.cpp index 72267bd0..9d20db6c 100644 --- a/Alc/ringbuffer.cpp +++ b/Alc/ringbuffer.cpp @@ -25,7 +25,6 @@ #include #include "ringbuffer.h" -#include "align.h" #include "atomic.h" #include "threads.h" #include "almalloc.h" diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e4c6d4b..2a9fdee6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -235,45 +235,6 @@ IF(HAVE_LIBLOG) SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} log) ENDIF() -# Check if we have C99 bool -CHECK_C_SOURCE_COMPILES( -"int main(int argc, char *argv[]) - { - volatile _Bool ret; - ret = (argc > 1) ? 1 : 0; - return ret ? -1 : 0; - }" -HAVE_C99_BOOL) - -# Check if we have C11 static_assert -CHECK_C_SOURCE_COMPILES( -"int main() - { - _Static_assert(sizeof(int) == sizeof(int), \"What\"); - return 0; - }" -HAVE_C11_STATIC_ASSERT) - -# Check if we have C11 alignas -CHECK_C_SOURCE_COMPILES( -"_Alignas(16) int foo; - int main() - { - return 0; - }" -HAVE_C11_ALIGNAS) - -# Check if we have C11 _Atomic -CHECK_C_SOURCE_COMPILES( -"#include - int _Atomic foo = ATOMIC_VAR_INIT(0); - int main() - { - atomic_fetch_add(&foo, 2); - return 0; - }" -HAVE_C11_ATOMIC) - # Add definitions, compiler switches, etc. INCLUDE_DIRECTORIES("${OpenAL_SOURCE_DIR}/include" "${OpenAL_SOURCE_DIR}/common" "${OpenAL_BINARY_DIR}") @@ -517,8 +478,6 @@ ENDIF() CHECK_C_SOURCE_COMPILES("int foo(const char *str, ...) __attribute__((format(printf, 1, 2))); int main() {return 0;}" HAVE_GCC_FORMAT) -CHECK_INCLUDE_FILE(stdbool.h HAVE_STDBOOL_H) -CHECK_INCLUDE_FILE(stdalign.h HAVE_STDALIGN_H) CHECK_INCLUDE_FILE(malloc.h HAVE_MALLOC_H) CHECK_INCLUDE_FILE(dirent.h HAVE_DIRENT_H) CHECK_INCLUDE_FILE(strings.h HAVE_STRINGS_H) @@ -744,13 +703,10 @@ ENDIF() SET(COMMON_OBJS common/alcomplex.cpp common/alcomplex.h - common/align.h common/almalloc.cpp common/almalloc.h common/atomic.h - common/bool.h common/math_defs.h - common/static_assert.h common/threads.cpp common/threads.h common/uintmap.h @@ -861,15 +817,13 @@ CHECK_INCLUDE_FILE(xmmintrin.h HAVE_XMMINTRIN_H "${SSE_SWITCH}") IF(HAVE_XMMINTRIN_H) OPTION(ALSOFT_CPUEXT_SSE "Enable SSE support" ON) IF(ALSOFT_CPUEXT_SSE) - IF(ALIGN_DECL OR HAVE_C11_ALIGNAS) - SET(HAVE_SSE 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse.cpp) - IF(SSE_SWITCH) - SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse.cpp PROPERTIES - COMPILE_FLAGS "${SSE_SWITCH}") - ENDIF() - SET(CPU_EXTS "${CPU_EXTS}, SSE") + SET(HAVE_SSE 1) + SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse.cpp) + IF(SSE_SWITCH) + SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse.cpp PROPERTIES + COMPILE_FLAGS "${SSE_SWITCH}") ENDIF() + SET(CPU_EXTS "${CPU_EXTS}, SSE") ENDIF() ENDIF() IF(ALSOFT_REQUIRE_SSE AND NOT HAVE_SSE) @@ -881,15 +835,13 @@ CHECK_INCLUDE_FILE(emmintrin.h HAVE_EMMINTRIN_H "${SSE2_SWITCH}") IF(HAVE_EMMINTRIN_H) OPTION(ALSOFT_CPUEXT_SSE2 "Enable SSE2 support" ON) IF(HAVE_SSE AND ALSOFT_CPUEXT_SSE2) - IF(ALIGN_DECL OR HAVE_C11_ALIGNAS) - SET(HAVE_SSE2 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse2.cpp) - IF(SSE2_SWITCH) - SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse2.cpp PROPERTIES - COMPILE_FLAGS "${SSE2_SWITCH}") - ENDIF() - SET(CPU_EXTS "${CPU_EXTS}, SSE2") + SET(HAVE_SSE2 1) + SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse2.cpp) + IF(SSE2_SWITCH) + SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse2.cpp PROPERTIES + COMPILE_FLAGS "${SSE2_SWITCH}") ENDIF() + SET(CPU_EXTS "${CPU_EXTS}, SSE2") ENDIF() ENDIF() IF(ALSOFT_REQUIRE_SSE2 AND NOT HAVE_SSE2) @@ -901,15 +853,13 @@ CHECK_INCLUDE_FILE(pmmintrin.h HAVE_PMMINTRIN_H "${SSE3_SWITCH}") IF(HAVE_EMMINTRIN_H) OPTION(ALSOFT_CPUEXT_SSE3 "Enable SSE3 support" ON) IF(HAVE_SSE2 AND ALSOFT_CPUEXT_SSE3) - IF(ALIGN_DECL OR HAVE_C11_ALIGNAS) - SET(HAVE_SSE3 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse3.cpp) - IF(SSE2_SWITCH) - SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse3.cpp PROPERTIES - COMPILE_FLAGS "${SSE3_SWITCH}") - ENDIF() - SET(CPU_EXTS "${CPU_EXTS}, SSE3") + SET(HAVE_SSE3 1) + SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse3.cpp) + IF(SSE2_SWITCH) + SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse3.cpp PROPERTIES + COMPILE_FLAGS "${SSE3_SWITCH}") ENDIF() + SET(CPU_EXTS "${CPU_EXTS}, SSE3") ENDIF() ENDIF() IF(ALSOFT_REQUIRE_SSE3 AND NOT HAVE_SSE3) @@ -921,15 +871,13 @@ CHECK_INCLUDE_FILE(smmintrin.h HAVE_SMMINTRIN_H "${SSE4_1_SWITCH}") IF(HAVE_SMMINTRIN_H) OPTION(ALSOFT_CPUEXT_SSE4_1 "Enable SSE4.1 support" ON) IF(HAVE_SSE2 AND ALSOFT_CPUEXT_SSE4_1) - IF(ALIGN_DECL OR HAVE_C11_ALIGNAS) - SET(HAVE_SSE4_1 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse41.cpp) - IF(SSE4_1_SWITCH) - SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse41.cpp PROPERTIES - COMPILE_FLAGS "${SSE4_1_SWITCH}") - ENDIF() - SET(CPU_EXTS "${CPU_EXTS}, SSE4.1") + SET(HAVE_SSE4_1 1) + SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse41.cpp) + IF(SSE4_1_SWITCH) + SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse41.cpp PROPERTIES + COMPILE_FLAGS "${SSE4_1_SWITCH}") ENDIF() + SET(CPU_EXTS "${CPU_EXTS}, SSE4.1") ENDIF() ENDIF() IF(ALSOFT_REQUIRE_SSE4_1 AND NOT HAVE_SSE4_1) diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 16de9a79..99060b74 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -5,7 +5,6 @@ #include "alEffect.h" #include "atomic.h" -#include "align.h" #ifdef __cplusplus extern "C" { diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index a79b6962..75cd0576 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -23,8 +23,6 @@ #include "inprogext.h" #include "logging.h" #include "polymorphism.h" -#include "static_assert.h" -#include "align.h" #include "atomic.h" #include "vector.h" #include "almalloc.h" diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index f7749de3..53313fdd 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -1,7 +1,6 @@ #ifndef _AL_SOURCE_H_ #define _AL_SOURCE_H_ -#include "bool.h" #include "alMain.h" #include "alu.h" #include "hrtf.h" diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 2dbd3107..78ec502d 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -14,7 +14,6 @@ #include "alBuffer.h" #include "hrtf.h" -#include "align.h" #include "math_defs.h" #include "filters/defs.h" #include "filters/nfc.h" diff --git a/common/align.h b/common/align.h deleted file mode 100644 index 53a5806a..00000000 --- a/common/align.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef AL_ALIGN_H -#define AL_ALIGN_H - -#if defined(HAVE_STDALIGN_H) && defined(HAVE_C11_ALIGNAS) -#include -#endif - -#if !defined(alignas) && !defined(__cplusplus) -#if defined(HAVE_C11_ALIGNAS) -#define alignas _Alignas -#else -/* NOTE: Our custom ALIGN macro can't take a type name like alignas can. For - * maximum compatibility, only provide constant integer values to alignas. */ -#define alignas(_x) ALIGN(_x) -#endif -#endif - -#endif /* AL_ALIGN_H */ diff --git a/common/atomic.h b/common/atomic.h index 4976149a..5838f8da 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -3,9 +3,6 @@ #include -#include "static_assert.h" -#include "bool.h" - #ifdef __GNUC__ /* This helps cast away the const-ness of a pointer without accidentally * changing the pointer type. This is necessary due to Clang's inability to use diff --git a/common/bool.h b/common/bool.h deleted file mode 100644 index eb1d9174..00000000 --- a/common/bool.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef AL_BOOL_H -#define AL_BOOL_H - -#ifdef HAVE_STDBOOL_H -#include -#endif - -#if !defined(bool) && !defined(__cplusplus) -#ifdef HAVE_C99_BOOL -#define bool _Bool -#else -#define bool int -#endif -#define false 0 -#define true 1 -#endif - -#endif /* AL_BOOL_H */ diff --git a/common/static_assert.h b/common/static_assert.h deleted file mode 100644 index 3a554fb5..00000000 --- a/common/static_assert.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef AL_STATIC_ASSERT_H -#define AL_STATIC_ASSERT_H - -#include - - -#if !defined(static_assert) && !defined(__cplusplus) -#ifdef HAVE_C11_STATIC_ASSERT -#define static_assert _Static_assert -#else -#define CTASTR2(_pre,_post) _pre##_post -#define CTASTR(_pre,_post) CTASTR2(_pre,_post) -#if defined(__COUNTER__) -#define static_assert(_cond, _msg) typedef struct { int CTASTR(static_assert_failed_at_line_,__LINE__) : !!(_cond); } CTASTR(static_assertion_,__COUNTER__) -#else -#define static_assert(_cond, _msg) struct { int CTASTR(static_assert_failed_at_line_,__LINE__) : !!(_cond); } -#endif -#endif -#endif - -#endif /* AL_STATIC_ASSERT_H */ diff --git a/config.h.in b/config.h.in index 9714810c..6c83b7f5 100644 --- a/config.h.in +++ b/config.h.in @@ -95,18 +95,6 @@ /* Define to the size of a long long int type */ #cmakedefine SIZEOF_LONG_LONG ${SIZEOF_LONG_LONG} -/* Define if we have C99 _Bool support */ -#cmakedefine HAVE_C99_BOOL - -/* Define if we have C11 _Static_assert support */ -#cmakedefine HAVE_C11_STATIC_ASSERT - -/* Define if we have C11 _Alignas support */ -#cmakedefine HAVE_C11_ALIGNAS - -/* Define if we have C11 _Atomic support */ -#cmakedefine HAVE_C11_ATOMIC - /* Define if we have GCC's destructor attribute */ #cmakedefine HAVE_GCC_DESTRUCTOR @@ -116,12 +104,6 @@ /* Define if we have stdint.h */ #cmakedefine HAVE_STDINT_H -/* Define if we have stdbool.h */ -#cmakedefine HAVE_STDBOOL_H - -/* Define if we have stdalign.h */ -#cmakedefine HAVE_STDALIGN_H - /* Define if we have windows.h */ #cmakedefine HAVE_WINDOWS_H -- cgit v1.2.3 From 20e62aa959f922a408312a4ed8c365e9e976510d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 20:39:45 -0800 Subject: Avoid an explicit static_cast to bool --- OpenAL32/Include/alMain.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 75cd0576..d06aeaf2 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -952,7 +952,7 @@ public: return *this; } - operator bool() const noexcept { return static_cast(mCtx); } + operator bool() const noexcept { return mCtx; } ALCcontext* operator->() noexcept { return mCtx; } ALCcontext* get() noexcept { return mCtx; } -- cgit v1.2.3 From 8f6e0f97ec5543de8ae49f12046b5c893565778e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 21:48:54 -0800 Subject: Try to clear up an MSVC warning --- OpenAL32/Include/alMain.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index d06aeaf2..b5c86dc6 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -952,7 +952,7 @@ public: return *this; } - operator bool() const noexcept { return mCtx; } + operator bool() const noexcept { return mCtx != nullptr; } ALCcontext* operator->() noexcept { return mCtx; } ALCcontext* get() noexcept { return mCtx; } -- cgit v1.2.3 From fa3c34268dd7d9bc380ecd19aedb28924d29b295 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 23:02:27 -0800 Subject: Move the ALCcontext definition to its own header --- Alc/alc.cpp | 3 +- Alc/alcontext.h | 180 ++++++++++++++++++++++++++++++++++++++++++ Alc/alu.cpp | 15 ++-- Alc/effects/autowah.cpp | 1 + Alc/effects/chorus.cpp | 1 + Alc/effects/compressor.cpp | 8 +- Alc/effects/dedicated.cpp | 2 +- Alc/effects/distortion.cpp | 1 + Alc/effects/echo.cpp | 1 + Alc/effects/equalizer.cpp | 1 + Alc/effects/fshifter.cpp | 2 +- Alc/effects/modulator.cpp | 1 + Alc/effects/null.cpp | 2 + Alc/effects/pshifter.cpp | 2 +- Alc/effects/reverb.cpp | 1 + Alc/mixvoice.cpp | 4 +- CMakeLists.txt | 1 + OpenAL32/Include/alListener.h | 11 --- OpenAL32/Include/alMain.h | 146 ---------------------------------- OpenAL32/Include/alu.h | 4 +- OpenAL32/alAuxEffectSlot.cpp | 2 + OpenAL32/alBuffer.cpp | 1 + OpenAL32/alEffect.cpp | 2 + OpenAL32/alError.cpp | 2 +- OpenAL32/alExtension.cpp | 10 +-- OpenAL32/alFilter.cpp | 1 + OpenAL32/alListener.cpp | 1 + OpenAL32/alSource.cpp | 6 +- OpenAL32/alState.cpp | 11 +-- OpenAL32/event.cpp | 2 + 30 files changed, 234 insertions(+), 191 deletions(-) create mode 100644 Alc/alcontext.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index c719eaa9..ec9a0adf 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -37,6 +37,7 @@ #include #include "alMain.h" +#include "alcontext.h" #include "alSource.h" #include "alListener.h" #include "alSource.h" @@ -2633,7 +2634,7 @@ static ALvoid InitContext(ALCcontext *Context) ATOMIC_INIT(&Context->ActiveAuxSlots, auxslots); //Set globals - Context->DistanceModel = DefaultDistanceModel; + Context->DistanceModel = DistanceModel::Default; Context->SourceDistanceModel = AL_FALSE; Context->DopplerFactor = 1.0f; Context->DopplerVelocity = 1.0f; diff --git a/Alc/alcontext.h b/Alc/alcontext.h new file mode 100644 index 00000000..9ef2db3b --- /dev/null +++ b/Alc/alcontext.h @@ -0,0 +1,180 @@ +#ifndef ALCONTEXT_H +#define ALCONTEXT_H + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" +#include "inprogext.h" + +#include "atomic.h" +#include "vector.h" +#include "threads.h" + + +struct ALlistener; +struct ALsource; +struct ALeffectslot; +struct ALcontextProps; +struct ALlistenerProps; +struct ALvoiceProps; +struct ALeffectslotProps; +struct ALvoice; +struct ALeffectslotArray; +struct ll_ringbuffer; + +enum class DistanceModel { + InverseClamped = AL_INVERSE_DISTANCE_CLAMPED, + LinearClamped = AL_LINEAR_DISTANCE_CLAMPED, + ExponentClamped = AL_EXPONENT_DISTANCE_CLAMPED, + Inverse = AL_INVERSE_DISTANCE, + Linear = AL_LINEAR_DISTANCE, + Exponent = AL_EXPONENT_DISTANCE, + Disable = AL_NONE, + + Default = InverseClamped +}; + +struct SourceSubList { + uint64_t FreeMask; + ALsource *Sources; /* 64 */ +}; +TYPEDEF_VECTOR(SourceSubList, vector_SourceSubList) + +/* Effect slots are rather large, and apps aren't likely to have more than one + * or two (let alone 64), so hold them individually. + */ +using ALeffectslotPtr = struct ALeffectslot*; +TYPEDEF_VECTOR(ALeffectslotPtr, vector_ALeffectslotPtr) + +struct ALCcontext_struct { + RefCount ref; + + ALlistener *Listener; + + vector_SourceSubList SourceList; + ALuint NumSources; + almtx_t SourceLock; + + vector_ALeffectslotPtr EffectSlotList; + almtx_t EffectSlotLock; + + ATOMIC(ALenum) LastError; + + enum DistanceModel DistanceModel; + ALboolean SourceDistanceModel; + + ALfloat DopplerFactor; + ALfloat DopplerVelocity; + ALfloat SpeedOfSound; + ALfloat MetersPerUnit; + + ATOMIC(ALenum) PropsClean; + ATOMIC(ALenum) DeferUpdates; + + almtx_t PropLock; + + /* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit + * indicates if updates are currently happening). + */ + RefCount UpdateCount; + ATOMIC(ALenum) HoldUpdates; + + ALfloat GainBoost; + + ATOMIC(ALcontextProps*) Update; + + /* Linked lists of unused property containers, free to use for future + * updates. + */ + ATOMIC(ALcontextProps*) FreeContextProps; + ATOMIC(ALlistenerProps*) FreeListenerProps; + ATOMIC(ALvoiceProps*) FreeVoiceProps; + ATOMIC(ALeffectslotProps*) FreeEffectslotProps; + + ALvoice **Voices; + ALsizei VoiceCount; + ALsizei MaxVoices; + + ATOMIC(ALeffectslotArray*) ActiveAuxSlots; + + althrd_t EventThread; + alsem_t EventSem; + ll_ringbuffer *AsyncEvents; + ATOMIC(ALbitfieldSOFT) EnabledEvts; + almtx_t EventCbLock; + ALEVENTPROCSOFT EventCb; + void *EventParam; + + /* Default effect slot */ + ALeffectslot *DefaultSlot; + + ALCdevice *Device; + const ALCchar *ExtensionList; + + ATOMIC(ALCcontext*) next; + + /* Memory space used by the listener (and possibly default effect slot) */ + alignas(16) ALCbyte _listener_mem[]; +}; + +ALCcontext *GetContextRef(void); +void ALCcontext_DecRef(ALCcontext *context); + +void UpdateContextProps(ALCcontext *context); + +void ALCcontext_DeferUpdates(ALCcontext *context); +void ALCcontext_ProcessUpdates(ALCcontext *context); + +inline void LockEffectSlotList(ALCcontext *context) +{ almtx_lock(&context->EffectSlotLock); } +inline void UnlockEffectSlotList(ALCcontext *context) +{ almtx_unlock(&context->EffectSlotLock); } + + +/* Simple RAII context reference. Takes the reference of the provided + * ALCcontext, and decrements it when leaving scope. Movable (transfer + * reference) but not copyable (no new references). + */ +class ContextRef { + ALCcontext *mCtx{nullptr}; + + void release() noexcept + { + if(mCtx) + ALCcontext_DecRef(mCtx); + mCtx = nullptr; + } + +public: + ContextRef() noexcept = default; + explicit ContextRef(ALCcontext *ctx) noexcept : mCtx(ctx) { } + ~ContextRef() { release(); } + + ContextRef& operator=(const ContextRef&) = delete; + ContextRef& operator=(ContextRef&& rhs) noexcept + { + release(); + mCtx = rhs.mCtx; + rhs.mCtx = nullptr; + return *this; + } + + operator bool() const noexcept { return mCtx != nullptr; } + + ALCcontext* operator->() noexcept { return mCtx; } + ALCcontext* get() noexcept { return mCtx; } +}; + + +struct ALcontextProps { + ALfloat DopplerFactor; + ALfloat DopplerVelocity; + ALfloat SpeedOfSound; + ALboolean SourceDistanceModel; + enum DistanceModel DistanceModel; + ALfloat MetersPerUnit; + + ATOMIC(struct ALcontextProps*) next; +}; + +#endif /* ALCONTEXT_H */ diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 3075f1ec..1895b777 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -27,6 +27,7 @@ #include #include "alMain.h" +#include "alcontext.h" #include "alSource.h" #include "alBuffer.h" #include "alListener.h" @@ -1218,12 +1219,12 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop switch(Listener->Params.SourceDistanceModel ? props->DistanceModel : Listener->Params.DistanceModel) { - case InverseDistanceClamped: + case DistanceModel::InverseClamped: ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); if(props->MaxDistance < props->RefDistance) break; /*fall-through*/ - case InverseDistance: + case DistanceModel::Inverse: if(!(props->RefDistance > 0.0f)) ClampedDist = props->RefDistance; else @@ -1238,12 +1239,12 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop } break; - case LinearDistanceClamped: + case DistanceModel::LinearClamped: ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); if(props->MaxDistance < props->RefDistance) break; /*fall-through*/ - case LinearDistance: + case DistanceModel::Linear: if(!(props->MaxDistance != props->RefDistance)) ClampedDist = props->RefDistance; else @@ -1260,12 +1261,12 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop } break; - case ExponentDistanceClamped: + case DistanceModel::ExponentClamped: ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); if(props->MaxDistance < props->RefDistance) break; /*fall-through*/ - case ExponentDistance: + case DistanceModel::Exponent: if(!(ClampedDist > 0.0f && props->RefDistance > 0.0f)) ClampedDist = props->RefDistance; else @@ -1276,7 +1277,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop } break; - case DisableDistance: + case DistanceModel::Disable: ClampedDist = props->RefDistance; break; } diff --git a/Alc/effects/autowah.cpp b/Alc/effects/autowah.cpp index b4ef8f3c..e2f07b6f 100644 --- a/Alc/effects/autowah.cpp +++ b/Alc/effects/autowah.cpp @@ -24,6 +24,7 @@ #include #include "alMain.h" +#include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp index b658098e..411ba6a5 100644 --- a/Alc/effects/chorus.cpp +++ b/Alc/effects/chorus.cpp @@ -24,6 +24,7 @@ #include #include "alMain.h" +#include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" diff --git a/Alc/effects/compressor.cpp b/Alc/effects/compressor.cpp index 0a307a5f..5603deea 100644 --- a/Alc/effects/compressor.cpp +++ b/Alc/effects/compressor.cpp @@ -18,13 +18,15 @@ * Or go to http://www.gnu.org/copyleft/lgpl.html */ +#include "config.h" + #include -#include "config.h" -#include "alError.h" #include "alMain.h" -#include "alAuxEffectSlot.h" +#include "alcontext.h" #include "alu.h" +#include "alAuxEffectSlot.h" +#include "alError.h" #define AMP_ENVELOPE_MIN 0.5f diff --git a/Alc/effects/dedicated.cpp b/Alc/effects/dedicated.cpp index dd250e64..705f7d41 100644 --- a/Alc/effects/dedicated.cpp +++ b/Alc/effects/dedicated.cpp @@ -23,10 +23,10 @@ #include #include "alMain.h" +#include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" -#include "filters/defs.h" struct ALdedicatedState final : public ALeffectState { diff --git a/Alc/effects/distortion.cpp b/Alc/effects/distortion.cpp index 75629d9c..7dd15981 100644 --- a/Alc/effects/distortion.cpp +++ b/Alc/effects/distortion.cpp @@ -24,6 +24,7 @@ #include #include "alMain.h" +#include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index f987e582..492da6f6 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -24,6 +24,7 @@ #include #include "alMain.h" +#include "alcontext.h" #include "alFilter.h" #include "alAuxEffectSlot.h" #include "alError.h" diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index 8388a123..48c6d1e2 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -24,6 +24,7 @@ #include #include "alMain.h" +#include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp index 304e281f..f112c4c7 100644 --- a/Alc/effects/fshifter.cpp +++ b/Alc/effects/fshifter.cpp @@ -27,10 +27,10 @@ #include #include "alMain.h" +#include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" -#include "filters/defs.h" #include "alcomplex.h" diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index 19513add..7e8f8ce4 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -24,6 +24,7 @@ #include #include "alMain.h" +#include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" diff --git a/Alc/effects/null.cpp b/Alc/effects/null.cpp index 377593ab..0d85d505 100644 --- a/Alc/effects/null.cpp +++ b/Alc/effects/null.cpp @@ -4,7 +4,9 @@ #include "AL/al.h" #include "AL/alc.h" + #include "alMain.h" +#include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp index f0cdf53e..1199a19d 100644 --- a/Alc/effects/pshifter.cpp +++ b/Alc/effects/pshifter.cpp @@ -27,10 +27,10 @@ #include #include "alMain.h" +#include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" -#include "filters/defs.h" #include "alcomplex.h" diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 5cfc0012..fe9cc9f7 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -25,6 +25,7 @@ #include #include "alMain.h" +#include "alcontext.h" #include "alu.h" #include "alAuxEffectSlot.h" #include "alListener.h" diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 03d51dd6..f89b6efa 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -26,9 +26,11 @@ #include #include -#include "alMain.h" #include "AL/al.h" #include "AL/alc.h" + +#include "alMain.h" +#include "alcontext.h" #include "alSource.h" #include "alBuffer.h" #include "alListener.h" diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a9fdee6..e81dc403 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -741,6 +741,7 @@ SET(ALC_OBJS Alc/alu.cpp Alc/alconfig.cpp Alc/alconfig.h + Alc/alcontext.h Alc/bs2b.cpp Alc/converter.cpp Alc/converter.h diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h index 9efadf47..33dea4f3 100644 --- a/OpenAL32/Include/alListener.h +++ b/OpenAL32/Include/alListener.h @@ -8,17 +8,6 @@ extern "C" { #endif -struct ALcontextProps { - ALfloat DopplerFactor; - ALfloat DopplerVelocity; - ALfloat SpeedOfSound; - ALboolean SourceDistanceModel; - enum DistanceModel DistanceModel; - ALfloat MetersPerUnit; - - ATOMIC(struct ALcontextProps*) next; -}; - struct ALlistenerProps { ALfloat Position[3]; ALfloat Velocity[3]; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index b5c86dc6..0e6e4cd9 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -204,7 +204,6 @@ static const union { #endif -struct ll_ringbuffer; struct Hrtf; struct HrtfEntry; struct DirectHrtfState; @@ -214,11 +213,6 @@ struct ALCbackend; struct ALbuffer; struct ALeffect; struct ALfilter; -struct ALsource; -struct ALcontextProps; -struct ALlistenerProps; -struct ALvoiceProps; -struct ALeffectslotProps; #define DEFAULT_OUTPUT_RATE (44100) @@ -380,18 +374,6 @@ enum DevProbe { }; -enum DistanceModel { - InverseDistanceClamped = AL_INVERSE_DISTANCE_CLAMPED, - LinearDistanceClamped = AL_LINEAR_DISTANCE_CLAMPED, - ExponentDistanceClamped = AL_EXPONENT_DISTANCE_CLAMPED, - InverseDistance = AL_INVERSE_DISTANCE, - LinearDistance = AL_LINEAR_DISTANCE, - ExponentDistance = AL_EXPONENT_DISTANCE, - DisableDistance = AL_NONE, - - DefaultDistanceModel = InverseDistanceClamped -}; - enum Channel { FrontLeft = 0, FrontRight, @@ -552,18 +534,6 @@ typedef struct FilterSubList { } FilterSubList; TYPEDEF_VECTOR(FilterSubList, vector_FilterSubList) -typedef struct SourceSubList { - ALuint64 FreeMask; - struct ALsource *Sources; /* 64 */ -} SourceSubList; -TYPEDEF_VECTOR(SourceSubList, vector_SourceSubList) - -/* Effect slots are rather large, and apps aren't likely to have more than one - * or two (let alone 64), so hold them individually. - */ -typedef struct ALeffectslot *ALeffectslotPtr; -TYPEDEF_VECTOR(ALeffectslotPtr, vector_ALeffectslotPtr) - typedef struct EnumeratedHrtf { char *name; @@ -790,83 +760,6 @@ typedef struct AsyncEvent { } AsyncEvent; #define ASYNC_EVENT(t) { t, { 0 } } -struct ALCcontext_struct { - RefCount ref; - - struct ALlistener *Listener; - - vector_SourceSubList SourceList; - ALuint NumSources; - almtx_t SourceLock; - - vector_ALeffectslotPtr EffectSlotList; - almtx_t EffectSlotLock; - - ATOMIC(ALenum) LastError; - - enum DistanceModel DistanceModel; - ALboolean SourceDistanceModel; - - ALfloat DopplerFactor; - ALfloat DopplerVelocity; - ALfloat SpeedOfSound; - ALfloat MetersPerUnit; - - ATOMIC(ALenum) PropsClean; - ATOMIC(ALenum) DeferUpdates; - - almtx_t PropLock; - - /* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit - * indicates if updates are currently happening). - */ - RefCount UpdateCount; - ATOMIC(ALenum) HoldUpdates; - - ALfloat GainBoost; - - ATOMIC(struct ALcontextProps*) Update; - - /* Linked lists of unused property containers, free to use for future - * updates. - */ - ATOMIC(struct ALcontextProps*) FreeContextProps; - ATOMIC(struct ALlistenerProps*) FreeListenerProps; - ATOMIC(struct ALvoiceProps*) FreeVoiceProps; - ATOMIC(struct ALeffectslotProps*) FreeEffectslotProps; - - struct ALvoice **Voices; - ALsizei VoiceCount; - ALsizei MaxVoices; - - ATOMIC(struct ALeffectslotArray*) ActiveAuxSlots; - - althrd_t EventThread; - alsem_t EventSem; - struct ll_ringbuffer *AsyncEvents; - ATOMIC(ALbitfieldSOFT) EnabledEvts; - almtx_t EventCbLock; - ALEVENTPROCSOFT EventCb; - void *EventParam; - - /* Default effect slot */ - struct ALeffectslot *DefaultSlot; - - ALCdevice *Device; - const ALCchar *ExtensionList; - - ATOMIC(ALCcontext*) next; - - /* Memory space used by the listener (and possibly default effect slot) */ - alignas(16) ALCbyte _listener_mem[]; -}; - -ALCcontext *GetContextRef(void); - -void ALCcontext_DecRef(ALCcontext *context); - -void ALCcontext_DeferUpdates(ALCcontext *context); -void ALCcontext_ProcessUpdates(ALCcontext *context); void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends); @@ -909,11 +802,6 @@ inline void UnlockEffectList(ALCdevice *device) { almtx_unlock(&device->EffectLo inline void LockFilterList(ALCdevice *device) { almtx_lock(&device->FilterLock); } inline void UnlockFilterList(ALCdevice *device) { almtx_unlock(&device->FilterLock); } -inline void LockEffectSlotList(ALCcontext *context) -{ almtx_lock(&context->EffectSlotLock); } -inline void UnlockEffectSlotList(ALCcontext *context) -{ almtx_unlock(&context->EffectSlotLock); } - int EventThread(void *arg); @@ -923,40 +811,6 @@ char *alstrdup(const char *str); } // extern "C" std::vector SearchDataFiles(const char *match, const char *subdir); - -/* Simple RAII context reference. Takes the reference of the provided - * ALCcontext, and decrements it when leaving scope. Movable (transfer - * reference) but not copyable (no new references). - */ -class ContextRef { - ALCcontext *mCtx{nullptr}; - - void release() noexcept - { - if(mCtx) - ALCcontext_DecRef(mCtx); - mCtx = nullptr; - } - -public: - ContextRef() noexcept = default; - explicit ContextRef(ALCcontext *ctx) noexcept : mCtx(ctx) { } - ~ContextRef() { release(); } - - ContextRef& operator=(const ContextRef&) = delete; - ContextRef& operator=(ContextRef&& rhs) noexcept - { - release(); - mCtx = rhs.mCtx; - rhs.mCtx = nullptr; - return *this; - } - - operator bool() const noexcept { return mCtx != nullptr; } - - ALCcontext* operator->() noexcept { return mCtx; } - ALCcontext* get() noexcept { return mCtx; } -}; #endif #endif diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 78ec502d..7031df70 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -19,6 +19,8 @@ #include "filters/nfc.h" +enum class DistanceModel; + #define MAX_PITCH (255) /* Maximum number of samples to pad on either end of a buffer for resampling. @@ -517,8 +519,6 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples); /* Caller must lock the device, and the mixer must not be running. */ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) DECL_FORMAT(printf, 2, 3); -void UpdateContextProps(ALCcontext *context); - extern MixerFunc MixSamples; extern RowMixerFunc MixRowSamples; diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index 0ebcd3c9..bcf5c967 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -25,7 +25,9 @@ #include "AL/al.h" #include "AL/alc.h" + #include "alMain.h" +#include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" #include "alListener.h" diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index c04b8664..27e3ddd1 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -34,6 +34,7 @@ #include #include "alMain.h" +#include "alcontext.h" #include "alu.h" #include "alError.h" #include "alBuffer.h" diff --git a/OpenAL32/alEffect.cpp b/OpenAL32/alEffect.cpp index b9a2623c..4f25b5f4 100644 --- a/OpenAL32/alEffect.cpp +++ b/OpenAL32/alEffect.cpp @@ -26,7 +26,9 @@ #include "AL/al.h" #include "AL/alc.h" + #include "alMain.h" +#include "alcontext.h" #include "alEffect.h" #include "alError.h" diff --git a/OpenAL32/alError.cpp b/OpenAL32/alError.cpp index cf56dd71..6d8ca882 100644 --- a/OpenAL32/alError.cpp +++ b/OpenAL32/alError.cpp @@ -29,7 +29,7 @@ #endif #include "alMain.h" -#include "AL/alc.h" +#include "alcontext.h" #include "alError.h" ALboolean TrapALError = AL_FALSE; diff --git a/OpenAL32/alExtension.cpp b/OpenAL32/alExtension.cpp index bcc21f0f..fff12e01 100644 --- a/OpenAL32/alExtension.cpp +++ b/OpenAL32/alExtension.cpp @@ -24,16 +24,12 @@ #include #include -#include "alError.h" -#include "alMain.h" -#include "alFilter.h" -#include "alEffect.h" -#include "alAuxEffectSlot.h" -#include "alSource.h" -#include "alBuffer.h" #include "AL/al.h" #include "AL/alc.h" +#include "alMain.h" +#include "alcontext.h" +#include "alError.h" AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName) { diff --git a/OpenAL32/alFilter.cpp b/OpenAL32/alFilter.cpp index a85c5dde..3c78cebf 100644 --- a/OpenAL32/alFilter.cpp +++ b/OpenAL32/alFilter.cpp @@ -23,6 +23,7 @@ #include #include "alMain.h" +#include "alcontext.h" #include "alu.h" #include "alFilter.h" #include "alError.h" diff --git a/OpenAL32/alListener.cpp b/OpenAL32/alListener.cpp index 809b0318..f2fdf3c1 100644 --- a/OpenAL32/alListener.cpp +++ b/OpenAL32/alListener.cpp @@ -21,6 +21,7 @@ #include "config.h" #include "alMain.h" +#include "alcontext.h" #include "alu.h" #include "alError.h" #include "alListener.h" diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 93b0cd88..f3996cbf 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -27,7 +27,9 @@ #include "AL/al.h" #include "AL/alc.h" + #include "alMain.h" +#include "alcontext.h" #include "alError.h" #include "alSource.h" #include "alBuffer.h" @@ -1465,7 +1467,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_DISTANCE_MODEL: - *values = Source->DistanceModel; + *values = static_cast(Source->DistanceModel); return AL_TRUE; case AL_SOURCE_RESAMPLER_SOFT: @@ -3079,7 +3081,7 @@ static void InitSourceParams(ALsource *Source, ALsizei num_sends) Source->DopplerFactor = 1.0f; Source->HeadRelative = AL_FALSE; Source->Looping = AL_FALSE; - Source->DistanceModel = DefaultDistanceModel; + Source->DistanceModel = DistanceModel::Default; Source->Resampler = ResamplerDefault; Source->DirectChannels = AL_FALSE; Source->Spatialize = SpatializeAuto; diff --git a/OpenAL32/alState.cpp b/OpenAL32/alState.cpp index 6750de1f..c550d2b5 100644 --- a/OpenAL32/alState.cpp +++ b/OpenAL32/alState.cpp @@ -23,14 +23,11 @@ #include "version.h" #include + #include "alMain.h" -#include "AL/alc.h" -#include "AL/al.h" -#include "AL/alext.h" +#include "alcontext.h" +#include "alu.h" #include "alError.h" -#include "alListener.h" -#include "alSource.h" -#include "alAuxEffectSlot.h" #include "backends/base.h" @@ -152,7 +149,7 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) break; case AL_DISTANCE_MODEL: - if(context->DistanceModel == AL_INVERSE_DISTANCE_CLAMPED) + if(context->DistanceModel == DistanceModel::Default) value = AL_TRUE; break; diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index bc3e3178..67a10645 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -6,7 +6,9 @@ #include "AL/alc.h" #include "AL/al.h" #include "AL/alext.h" + #include "alMain.h" +#include "alcontext.h" #include "alError.h" #include "alAuxEffectSlot.h" #include "ringbuffer.h" -- cgit v1.2.3 From e79d9bdd1a6aa6d6d9852bf5a380a8cd01cbc315 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 23:21:37 -0800 Subject: Move the vector and matrix declarations to a separate header --- Alc/alc.cpp | 2 +- Alc/alu.cpp | 7 ------- Alc/effects/autowah.cpp | 3 ++- Alc/effects/compressor.cpp | 4 +++- Alc/effects/equalizer.cpp | 3 ++- Alc/effects/modulator.cpp | 3 ++- Alc/effects/reverb.cpp | 1 + CMakeLists.txt | 2 ++ OpenAL32/Include/alListener.h | 23 ++++++++++------------ OpenAL32/Include/alu.h | 39 ------------------------------------ common/vecmat.cpp | 12 +++++++++++ common/vecmat.h | 46 +++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 81 insertions(+), 64 deletions(-) create mode 100644 common/vecmat.cpp create mode 100644 common/vecmat.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index ec9a0adf..daa0818d 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2658,7 +2658,7 @@ static ALvoid InitContext(ALCcontext *Context) Context->ExtensionList = alExtList; - listener->Params.Matrix = IdentityMatrixf; + listener->Params.Matrix = aluMatrixf::Identity; aluVectorSet(&listener->Params.Velocity, 0.0f, 0.0f, 0.0f, 0.0f); listener->Params.Gain = listener->Gain; listener->Params.MetersPerUnit = Context->MetersPerUnit; diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 1895b777..2a6dcfe0 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -56,13 +56,6 @@ ALfloat ZScale = 1.0f; /* Force default speed of sound for distance-related reverb decay. */ ALboolean OverrideReverbSpeedOfSound = AL_FALSE; -const aluMatrixf IdentityMatrixf = {{ - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 1.0f }, -}}; - static void ClearArray(ALfloat f[MAX_OUTPUT_CHANNELS]) { diff --git a/Alc/effects/autowah.cpp b/Alc/effects/autowah.cpp index e2f07b6f..a8e4fe6e 100644 --- a/Alc/effects/autowah.cpp +++ b/Alc/effects/autowah.cpp @@ -29,6 +29,7 @@ #include "alError.h" #include "alu.h" #include "filters/defs.h" +#include "vecmat.h" #define MIN_FREQ 20.0f #define MAX_FREQ 2500.0f @@ -131,7 +132,7 @@ static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *con STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain, + ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain, state->Chans[i].TargetGains); } diff --git a/Alc/effects/compressor.cpp b/Alc/effects/compressor.cpp index 5603deea..464e98ec 100644 --- a/Alc/effects/compressor.cpp +++ b/Alc/effects/compressor.cpp @@ -27,6 +27,7 @@ #include "alu.h" #include "alAuxEffectSlot.h" #include "alError.h" +#include "vecmat.h" #define AMP_ENVELOPE_MIN 0.5f @@ -101,7 +102,8 @@ static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCcontex STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < 4;i++) - ComputePanGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain, state->Gain[i]); + ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain, + state->Gain[i]); } static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index 48c6d1e2..e8d50fad 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -29,6 +29,7 @@ #include "alError.h" #include "alu.h" #include "filters/defs.h" +#include "vecmat.h" /* The document "Effects Extension Guide.pdf" says that low and high * @@ -173,7 +174,7 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain, + ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain, state->Chans[i].TargetGains); } diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index 7e8f8ce4..9790af79 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -29,6 +29,7 @@ #include "alError.h" #include "alu.h" #include "filters/defs.h" +#include "vecmat.h" #define MAX_UPDATE_SAMPLES 128 @@ -159,7 +160,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain, + ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain, state->Chans[i].TargetGains); } diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index fe9cc9f7..ebb9b7da 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -31,6 +31,7 @@ #include "alListener.h" #include "alError.h" #include "filters/defs.h" +#include "vecmat.h" /* This is a user config option for modifying the overall output of the reverb * effect. diff --git a/CMakeLists.txt b/CMakeLists.txt index e81dc403..476b241f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -710,6 +710,8 @@ SET(COMMON_OBJS common/threads.cpp common/threads.h common/uintmap.h + common/vecmat.cpp + common/vecmat.h ) SET(OPENAL_OBJS OpenAL32/Include/bs2b.h diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h index 33dea4f3..ec6ee509 100644 --- a/OpenAL32/Include/alListener.h +++ b/OpenAL32/Include/alListener.h @@ -1,12 +1,13 @@ #ifndef _AL_LISTENER_H_ #define _AL_LISTENER_H_ -#include "alMain.h" -#include "alu.h" +#include "AL/alc.h" +#include "AL/al.h" +#include "AL/alext.h" + +#include "atomic.h" +#include "vecmat.h" -#ifdef __cplusplus -extern "C" { -#endif struct ALlistenerProps { ALfloat Position[3]; @@ -15,10 +16,10 @@ struct ALlistenerProps { ALfloat Up[3]; ALfloat Gain; - ATOMIC(struct ALlistenerProps*) next; + ATOMIC(ALlistenerProps*) next; }; -typedef struct ALlistener { +struct ALlistener { alignas(16) ALfloat Position[3]; ALfloat Velocity[3]; ALfloat Forward[3]; @@ -29,7 +30,7 @@ typedef struct ALlistener { /* Pointer to the most recent property values that are awaiting an update. */ - ATOMIC(struct ALlistenerProps*) Update; + ATOMIC(ALlistenerProps*) Update; struct { aluMatrixf Matrix; @@ -45,12 +46,8 @@ typedef struct ALlistener { ALboolean SourceDistanceModel; enum DistanceModel DistanceModel; } Params; -} ALlistener; +}; void UpdateListenerProps(ALCcontext *context); -#ifdef __cplusplus -} -#endif - #endif diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 7031df70..d309c2a7 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -98,45 +98,6 @@ extern const struct BSincTable bsinc12; extern const struct BSincTable bsinc24; -typedef union aluVector { - alignas(16) ALfloat v[4]; -} aluVector; - -inline void aluVectorSet(aluVector *vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w) -{ - vector->v[0] = x; - vector->v[1] = y; - vector->v[2] = z; - vector->v[3] = w; -} - - -typedef union aluMatrixf { - alignas(16) ALfloat m[4][4]; -} aluMatrixf; -extern const aluMatrixf IdentityMatrixf; - -inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row, - ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3) -{ - matrix->m[row][0] = m0; - matrix->m[row][1] = m1; - matrix->m[row][2] = m2; - matrix->m[row][3] = m3; -} - -inline void aluMatrixfSet(aluMatrixf *matrix, ALfloat m00, ALfloat m01, ALfloat m02, ALfloat m03, - ALfloat m10, ALfloat m11, ALfloat m12, ALfloat m13, - ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23, - ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33) -{ - aluMatrixfSetRow(matrix, 0, m00, m01, m02, m03); - aluMatrixfSetRow(matrix, 1, m10, m11, m12, m13); - aluMatrixfSetRow(matrix, 2, m20, m21, m22, m23); - aluMatrixfSetRow(matrix, 3, m30, m31, m32, m33); -} - - enum { AF_None = 0, AF_LowPass = 1, diff --git a/common/vecmat.cpp b/common/vecmat.cpp new file mode 100644 index 00000000..ccb9ad9f --- /dev/null +++ b/common/vecmat.cpp @@ -0,0 +1,12 @@ + +#include "config.h" + +#include "vecmat.h" + + +const aluMatrixf aluMatrixf::Identity{{ + { 1.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 1.0f }, +}}; diff --git a/common/vecmat.h b/common/vecmat.h new file mode 100644 index 00000000..0a60cb9e --- /dev/null +++ b/common/vecmat.h @@ -0,0 +1,46 @@ +#ifndef COMMON_VECMAT_H +#define COMMON_VECMAT_H + +#include "AL/al.h" + + +struct aluVector { + alignas(16) ALfloat v[4]; +}; + +inline void aluVectorSet(aluVector *vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w) +{ + vector->v[0] = x; + vector->v[1] = y; + vector->v[2] = z; + vector->v[3] = w; +} + + +struct aluMatrixf { + alignas(16) ALfloat m[4][4]; + + static const aluMatrixf Identity; +}; + +inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row, + ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3) +{ + matrix->m[row][0] = m0; + matrix->m[row][1] = m1; + matrix->m[row][2] = m2; + matrix->m[row][3] = m3; +} + +inline void aluMatrixfSet(aluMatrixf *matrix, ALfloat m00, ALfloat m01, ALfloat m02, ALfloat m03, + ALfloat m10, ALfloat m11, ALfloat m12, ALfloat m13, + ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23, + ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33) +{ + aluMatrixfSetRow(matrix, 0, m00, m01, m02, m03); + aluMatrixfSetRow(matrix, 1, m10, m11, m12, m13); + aluMatrixfSetRow(matrix, 2, m20, m21, m22, m23); + aluMatrixfSetRow(matrix, 3, m30, m31, m32, m33); +} + +#endif /* COMMON_VECMAT_H */ -- cgit v1.2.3 From 38d6df9c1d10ac74af3454c67147dd21bb0a7bb8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Nov 2018 23:41:11 -0800 Subject: Store the listener directly in the context --- Alc/alc.cpp | 68 +++++++++++++++++++++---------------------- Alc/alcontext.h | 8 ++--- Alc/alu.cpp | 68 +++++++++++++++++++++---------------------- Alc/effects/reverb.cpp | 4 +-- OpenAL32/Include/alListener.h | 2 ++ OpenAL32/alListener.cpp | 58 ++++++++++++++++++------------------ 6 files changed, 104 insertions(+), 104 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index daa0818d..7b55f120 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1623,7 +1623,7 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) if(!ATOMIC_EXCHANGE(&context->PropsClean, AL_TRUE, almemory_order_acq_rel)) UpdateContextProps(context); - if(!ATOMIC_EXCHANGE(&context->Listener->PropsClean, AL_TRUE, almemory_order_acq_rel)) + if(!ATOMIC_EXCHANGE(&context->Listener.PropsClean, AL_TRUE, almemory_order_acq_rel)) UpdateListenerProps(context); UpdateAllEffectSlotProps(context); UpdateAllSourceProps(context); @@ -2368,7 +2368,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ATOMIC_STORE(&context->PropsClean, AL_TRUE, almemory_order_release); UpdateContextProps(context); - ATOMIC_STORE(&context->Listener->PropsClean, AL_TRUE, almemory_order_release); + ATOMIC_STORE(&context->Listener.PropsClean, AL_TRUE, almemory_order_release); UpdateListenerProps(context); UpdateAllSourceProps(context); almtx_unlock(&context->PropLock); @@ -2585,26 +2585,26 @@ static ALCboolean VerifyDevice(ALCdevice **device) */ static ALvoid InitContext(ALCcontext *Context) { - ALlistener *listener = Context->Listener; + ALlistener &listener = Context->Listener; struct ALeffectslotArray *auxslots; //Initialise listener - listener->Gain = 1.0f; - listener->Position[0] = 0.0f; - listener->Position[1] = 0.0f; - listener->Position[2] = 0.0f; - listener->Velocity[0] = 0.0f; - listener->Velocity[1] = 0.0f; - listener->Velocity[2] = 0.0f; - listener->Forward[0] = 0.0f; - listener->Forward[1] = 0.0f; - listener->Forward[2] = -1.0f; - listener->Up[0] = 0.0f; - listener->Up[1] = 1.0f; - listener->Up[2] = 0.0f; - ATOMIC_INIT(&listener->PropsClean, AL_TRUE); - - ATOMIC_INIT(&listener->Update, static_cast(nullptr)); + listener.Gain = 1.0f; + listener.Position[0] = 0.0f; + listener.Position[1] = 0.0f; + listener.Position[2] = 0.0f; + listener.Velocity[0] = 0.0f; + listener.Velocity[1] = 0.0f; + listener.Velocity[2] = 0.0f; + listener.Forward[0] = 0.0f; + listener.Forward[1] = 0.0f; + listener.Forward[2] = -1.0f; + listener.Up[0] = 0.0f; + listener.Up[1] = 1.0f; + listener.Up[2] = 0.0f; + ATOMIC_INIT(&listener.PropsClean, AL_TRUE); + + ATOMIC_INIT(&listener.Update, static_cast(nullptr)); //Validate Context InitRef(&Context->UpdateCount, 0); @@ -2658,16 +2658,16 @@ static ALvoid InitContext(ALCcontext *Context) Context->ExtensionList = alExtList; - listener->Params.Matrix = aluMatrixf::Identity; - aluVectorSet(&listener->Params.Velocity, 0.0f, 0.0f, 0.0f, 0.0f); - listener->Params.Gain = listener->Gain; - listener->Params.MetersPerUnit = Context->MetersPerUnit; - listener->Params.DopplerFactor = Context->DopplerFactor; - listener->Params.SpeedOfSound = Context->SpeedOfSound * Context->DopplerVelocity; - listener->Params.ReverbSpeedOfSound = listener->Params.SpeedOfSound * - listener->Params.MetersPerUnit; - listener->Params.SourceDistanceModel = Context->SourceDistanceModel; - listener->Params.DistanceModel = Context->DistanceModel; + listener.Params.Matrix = aluMatrixf::Identity; + aluVectorSet(&listener.Params.Velocity, 0.0f, 0.0f, 0.0f, 0.0f); + listener.Params.Gain = listener.Gain; + listener.Params.MetersPerUnit = Context->MetersPerUnit; + listener.Params.DopplerFactor = Context->DopplerFactor; + listener.Params.SpeedOfSound = Context->SpeedOfSound * Context->DopplerVelocity; + listener.Params.ReverbSpeedOfSound = listener.Params.SpeedOfSound * + listener.Params.MetersPerUnit; + listener.Params.SourceDistanceModel = Context->SourceDistanceModel; + listener.Params.DistanceModel = Context->DistanceModel; Context->AsyncEvents = ll_ringbuffer_create(63, sizeof(AsyncEvent), false); @@ -2683,7 +2683,7 @@ static ALvoid InitContext(ALCcontext *Context) */ static void FreeContext(ALCcontext *context) { - ALlistener *listener = context->Listener; + ALlistener &listener = context->Listener; struct ALeffectslotProps *eprops; struct ALlistenerProps *lprops; struct ALcontextProps *cprops; @@ -2764,7 +2764,7 @@ static void FreeContext(ALCcontext *context) context->VoiceCount = 0; context->MaxVoices = 0; - if((lprops=ATOMIC_LOAD(&listener->Update, almemory_order_acquire)) != nullptr) + if((lprops=ATOMIC_LOAD(&listener.Update, almemory_order_acquire)) != nullptr) { TRACE("Freed unapplied listener update %p\n", lprops); al_free(lprops); @@ -3806,7 +3806,6 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin } InitRef(&ALContext->ref, 1); - ALContext->Listener = (ALlistener*)ALContext->_listener_mem; ALContext->DefaultSlot = nullptr; ALContext->Voices = nullptr; @@ -3835,9 +3834,10 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin } AllocateVoices(ALContext, 256, device->NumAuxSends); - if(DefaultEffect.type != AL_EFFECT_NULL && device->Type == Playback) + // FIXME: Reenable after the default effect slot is handled again + if(0 && DefaultEffect.type != AL_EFFECT_NULL && device->Type == Playback) { - ALContext->DefaultSlot = (ALeffectslot*)(ALContext->_listener_mem + sizeof(ALlistener)); + ALContext->DefaultSlot = nullptr; if(InitEffectSlot(ALContext->DefaultSlot) == AL_NO_ERROR) aluInitEffectPanning(ALContext->DefaultSlot); else diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 9ef2db3b..16a5e909 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -10,8 +10,9 @@ #include "vector.h" #include "threads.h" +#include "alListener.h" + -struct ALlistener; struct ALsource; struct ALeffectslot; struct ALcontextProps; @@ -49,8 +50,6 @@ TYPEDEF_VECTOR(ALeffectslotPtr, vector_ALeffectslotPtr) struct ALCcontext_struct { RefCount ref; - ALlistener *Listener; - vector_SourceSubList SourceList; ALuint NumSources; almtx_t SourceLock; @@ -113,8 +112,7 @@ struct ALCcontext_struct { ATOMIC(ALCcontext*) next; - /* Memory space used by the listener (and possibly default effect slot) */ - alignas(16) ALCbyte _listener_mem[]; + ALlistener Listener; }; ALCcontext *GetContextRef(void); diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 2a6dcfe0..91d9e758 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -312,23 +312,23 @@ void BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *t static bool CalcContextParams(ALCcontext *Context) { - ALlistener *Listener = Context->Listener; + ALlistener &Listener = Context->Listener; struct ALcontextProps *props; props = static_cast(ATOMIC_EXCHANGE_PTR(&Context->Update, static_cast(nullptr), almemory_order_acq_rel)); if(!props) return false; - Listener->Params.MetersPerUnit = props->MetersPerUnit; + Listener.Params.MetersPerUnit = props->MetersPerUnit; - Listener->Params.DopplerFactor = props->DopplerFactor; - Listener->Params.SpeedOfSound = props->SpeedOfSound * props->DopplerVelocity; + Listener.Params.DopplerFactor = props->DopplerFactor; + Listener.Params.SpeedOfSound = props->SpeedOfSound * props->DopplerVelocity; if(!OverrideReverbSpeedOfSound) - Listener->Params.ReverbSpeedOfSound = Listener->Params.SpeedOfSound * - Listener->Params.MetersPerUnit; + Listener.Params.ReverbSpeedOfSound = Listener.Params.SpeedOfSound * + Listener.Params.MetersPerUnit; - Listener->Params.SourceDistanceModel = props->SourceDistanceModel; - Listener->Params.DistanceModel = props->DistanceModel; + Listener.Params.SourceDistanceModel = props->SourceDistanceModel; + Listener.Params.DistanceModel = props->DistanceModel; ATOMIC_REPLACE_HEAD(struct ALcontextProps*, &Context->FreeContextProps, props); return true; @@ -336,12 +336,12 @@ static bool CalcContextParams(ALCcontext *Context) static bool CalcListenerParams(ALCcontext *Context) { - ALlistener *Listener = Context->Listener; + ALlistener &Listener = Context->Listener; ALfloat N[3], V[3], U[3], P[3]; struct ALlistenerProps *props; aluVector vel; - props = static_cast(ATOMIC_EXCHANGE_PTR(&Listener->Update, + props = static_cast(ATOMIC_EXCHANGE_PTR(&Listener.Update, static_cast(nullptr), almemory_order_acq_rel)); if(!props) return false; @@ -358,7 +358,7 @@ static bool CalcListenerParams(ALCcontext *Context) aluCrossproduct(N, V, U); aluNormalize(U); - aluMatrixfSet(&Listener->Params.Matrix, + aluMatrixfSet(&Listener.Params.Matrix, U[0], V[0], -N[0], 0.0, U[1], V[1], -N[1], 0.0, U[2], V[2], -N[2], 0.0, @@ -368,13 +368,13 @@ static bool CalcListenerParams(ALCcontext *Context) P[0] = props->Position[0]; P[1] = props->Position[1]; P[2] = props->Position[2]; - aluMatrixfFloat3(P, 1.0, &Listener->Params.Matrix); - aluMatrixfSetRow(&Listener->Params.Matrix, 3, -P[0], -P[1], -P[2], 1.0f); + aluMatrixfFloat3(P, 1.0, &Listener.Params.Matrix); + aluMatrixfSetRow(&Listener.Params.Matrix, 3, -P[0], -P[1], -P[2], 1.0f); aluVectorSet(&vel, props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f); - Listener->Params.Velocity = aluMatrixfVector(&Listener->Params.Matrix, &vel); + Listener.Params.Velocity = aluMatrixfVector(&Listener.Params.Matrix, &vel); - Listener->Params.Gain = props->Gain * Context->GainBoost; + Listener.Params.Gain = props->Gain * Context->GainBoost; ATOMIC_REPLACE_HEAD(struct ALlistenerProps*, &Context->FreeListenerProps, props); return true; @@ -501,7 +501,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo const ALfloat DryGainLF, const ALfloat *WetGain, const ALfloat *WetGainLF, const ALfloat *WetGainHF, ALeffectslot **SendSlots, const ALbuffer *Buffer, - const struct ALvoiceProps *props, const ALlistener *Listener, + const struct ALvoiceProps *props, const ALlistener &Listener, const ALCdevice *Device) { struct ChanMap StereoMap[2] = { @@ -609,7 +609,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo if(Device->AvgSpeakerDist > 0.0f) { - ALfloat mdist = Distance * Listener->Params.MetersPerUnit; + ALfloat mdist = Distance * Listener.Params.MetersPerUnit; ALfloat w0 = SPEEDOFSOUNDMETRESPERSEC / (mdist * (ALfloat)Device->Frequency); ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / @@ -680,7 +680,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo aluNormalize(V); if(!props->HeadRelative) { - const aluMatrixf *lmatrix = &Listener->Params.Matrix; + const aluMatrixf *lmatrix = &Listener.Params.Matrix; aluMatrixfFloat3(N, 0.0f, lmatrix); aluMatrixfFloat3(V, 0.0f, lmatrix); } @@ -852,7 +852,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo /* Calculate NFC filter coefficient if needed. */ if(Device->AvgSpeakerDist > 0.0f) { - ALfloat mdist = Distance * Listener->Params.MetersPerUnit; + ALfloat mdist = Distance * Listener.Params.MetersPerUnit; ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / (Device->AvgSpeakerDist * (ALfloat)Device->Frequency); w0 = SPEEDOFSOUNDMETRESPERSEC / @@ -1022,7 +1022,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { const ALCdevice *Device = ALContext->Device; - const ALlistener *Listener = ALContext->Listener; + const ALlistener &Listener = ALContext->Listener; ALfloat DryGain, DryGainHF, DryGainLF; ALfloat WetGain[MAX_SENDS]; ALfloat WetGainHF[MAX_SENDS]; @@ -1065,14 +1065,14 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *p /* Calculate gains */ DryGain = clampf(props->Gain, props->MinGain, props->MaxGain); - DryGain *= props->Direct.Gain * Listener->Params.Gain; + DryGain *= props->Direct.Gain * Listener.Params.Gain; DryGain = minf(DryGain, GAIN_MIX_MAX); DryGainHF = props->Direct.GainHF; DryGainLF = props->Direct.GainLF; for(i = 0;i < Device->NumAuxSends;i++) { WetGain[i] = clampf(props->Gain, props->MinGain, props->MaxGain); - WetGain[i] *= props->Send[i].Gain * Listener->Params.Gain; + WetGain[i] *= props->Send[i].Gain * Listener.Params.Gain; WetGain[i] = minf(WetGain[i], GAIN_MIX_MAX); WetGainHF[i] = props->Send[i].GainHF; WetGainLF[i] = props->Send[i].GainLF; @@ -1085,7 +1085,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *p static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { const ALCdevice *Device = ALContext->Device; - const ALlistener *Listener = ALContext->Listener; + const ALlistener &Listener = ALContext->Listener; const ALsizei NumSends = Device->NumAuxSends; aluVector Position, Velocity, Direction, SourceToListener; ALfloat Distance, ClampedDist, DopplerFactor; @@ -1127,7 +1127,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop * -60dB. */ DecayDistance[i] = SendSlots[i]->Params.DecayTime * - Listener->Params.ReverbSpeedOfSound; + Listener.Params.ReverbSpeedOfSound; DecayLFDistance[i] = DecayDistance[i] * SendSlots[i]->Params.DecayLFRatio; DecayHFDistance[i] = DecayDistance[i] * SendSlots[i]->Params.DecayHFRatio; if(SendSlots[i]->Params.DecayHFLimit) @@ -1173,7 +1173,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop aluVectorSet(&Velocity, props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f); if(props->HeadRelative == AL_FALSE) { - const aluMatrixf *Matrix = &Listener->Params.Matrix; + const aluMatrixf *Matrix = &Listener.Params.Matrix; /* Transform source vectors */ Position = aluMatrixfVector(Matrix, &Position); Velocity = aluMatrixfVector(Matrix, &Velocity); @@ -1181,7 +1181,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop } else { - const aluVector *lvelocity = &Listener->Params.Velocity; + const aluVector *lvelocity = &Listener.Params.Velocity; /* Offset the source velocity to be relative of the listener velocity */ Velocity.v[0] += lvelocity->v[0]; Velocity.v[1] += lvelocity->v[1]; @@ -1209,8 +1209,8 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop /* Calculate distance attenuation */ ClampedDist = Distance; - switch(Listener->Params.SourceDistanceModel ? - props->DistanceModel : Listener->Params.DistanceModel) + switch(Listener.Params.SourceDistanceModel ? + props->DistanceModel : Listener.Params.DistanceModel) { case DistanceModel::InverseClamped: ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); @@ -1319,13 +1319,13 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop /* Apply gain and frequency filters */ DryGain = clampf(DryGain, props->MinGain, props->MaxGain); - DryGain = minf(DryGain*props->Direct.Gain*Listener->Params.Gain, GAIN_MIX_MAX); + DryGain = minf(DryGain*props->Direct.Gain*Listener.Params.Gain, GAIN_MIX_MAX); DryGainHF *= props->Direct.GainHF; DryGainLF *= props->Direct.GainLF; for(i = 0;i < NumSends;i++) { WetGain[i] = clampf(WetGain[i], props->MinGain, props->MaxGain); - WetGain[i] = minf(WetGain[i]*props->Send[i].Gain*Listener->Params.Gain, GAIN_MIX_MAX); + WetGain[i] = minf(WetGain[i]*props->Send[i].Gain*Listener.Params.Gain, GAIN_MIX_MAX); WetGainHF[i] *= props->Send[i].GainHF; WetGainLF[i] *= props->Send[i].GainLF; } @@ -1334,7 +1334,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop if(ClampedDist > props->RefDistance && props->RolloffFactor > 0.0f) { ALfloat meters_base = (ClampedDist-props->RefDistance) * props->RolloffFactor * - Listener->Params.MetersPerUnit; + Listener.Params.MetersPerUnit; if(props->AirAbsorptionFactor > 0.0f) { ALfloat hfattn = powf(AIRABSORBGAINHF, meters_base * props->AirAbsorptionFactor); @@ -1377,11 +1377,11 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop Pitch = props->Pitch; /* Calculate velocity-based doppler effect */ - DopplerFactor = props->DopplerFactor * Listener->Params.DopplerFactor; + DopplerFactor = props->DopplerFactor * Listener.Params.DopplerFactor; if(DopplerFactor > 0.0f) { - const aluVector *lvelocity = &Listener->Params.Velocity; - const ALfloat SpeedOfSound = Listener->Params.SpeedOfSound; + const aluVector *lvelocity = &Listener.Params.Velocity; + const ALfloat SpeedOfSound = Listener.Params.SpeedOfSound; ALfloat vss, vls; vss = aluDotproduct(&Velocity, &SourceToListener) * DopplerFactor; diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index ebb9b7da..702a8cdd 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -951,7 +951,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection static void ReverbState_update(ReverbState *State, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) { const ALCdevice *Device = Context->Device; - const ALlistener *Listener = Context->Listener; + const ALlistener &Listener = Context->Listener; ALuint frequency = Device->Frequency; ALfloat lf0norm, hf0norm, hfRatio; ALfloat lfDecayTime, hfDecayTime; @@ -994,7 +994,7 @@ static void ReverbState_update(ReverbState *State, const ALCcontext *Context, co hfRatio = props->Reverb.DecayHFRatio; if(props->Reverb.DecayHFLimit && props->Reverb.AirAbsorptionGainHF < 1.0f) hfRatio = CalcLimitedHfRatio(hfRatio, props->Reverb.AirAbsorptionGainHF, - props->Reverb.DecayTime, Listener->Params.ReverbSpeedOfSound + props->Reverb.DecayTime, Listener.Params.ReverbSpeedOfSound ); /* Calculate the LF/HF decay times. */ diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h index ec6ee509..096a747e 100644 --- a/OpenAL32/Include/alListener.h +++ b/OpenAL32/Include/alListener.h @@ -8,6 +8,8 @@ #include "atomic.h" #include "vecmat.h" +enum class DistanceModel; + struct ALlistenerProps { ALfloat Position[3]; diff --git a/OpenAL32/alListener.cpp b/OpenAL32/alListener.cpp index f2fdf3c1..1be5bf48 100644 --- a/OpenAL32/alListener.cpp +++ b/OpenAL32/alListener.cpp @@ -43,7 +43,7 @@ AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) context = GetContextRef(); if(!context) return; - listener = context->Listener; + listener = &context->Listener; almtx_lock(&context->PropLock); switch(param) { @@ -82,7 +82,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val context = GetContextRef(); if(!context) return; - listener = context->Listener; + listener = &context->Listener; almtx_lock(&context->PropLock); switch(param) { @@ -138,7 +138,7 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) context = GetContextRef(); if(!context) return; - listener = context->Listener; + listener = &context->Listener; almtx_lock(&context->PropLock); if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); switch(param) @@ -269,7 +269,7 @@ AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) else switch(param) { case AL_GAIN: - *value = context->Listener->Gain; + *value = context->Listener.Gain; break; case AL_METERS_PER_UNIT: @@ -298,15 +298,15 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat else switch(param) { case AL_POSITION: - *value1 = context->Listener->Position[0]; - *value2 = context->Listener->Position[1]; - *value3 = context->Listener->Position[2]; + *value1 = context->Listener.Position[0]; + *value2 = context->Listener.Position[1]; + *value3 = context->Listener.Position[2]; break; case AL_VELOCITY: - *value1 = context->Listener->Velocity[0]; - *value2 = context->Listener->Velocity[1]; - *value3 = context->Listener->Velocity[2]; + *value1 = context->Listener.Velocity[0]; + *value2 = context->Listener.Velocity[1]; + *value3 = context->Listener.Velocity[2]; break; default: @@ -345,12 +345,12 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) { case AL_ORIENTATION: // AT then UP - values[0] = context->Listener->Forward[0]; - values[1] = context->Listener->Forward[1]; - values[2] = context->Listener->Forward[2]; - values[3] = context->Listener->Up[0]; - values[4] = context->Listener->Up[1]; - values[5] = context->Listener->Up[2]; + values[0] = context->Listener.Forward[0]; + values[1] = context->Listener.Forward[1]; + values[2] = context->Listener.Forward[2]; + values[3] = context->Listener.Up[0]; + values[4] = context->Listener.Up[1]; + values[5] = context->Listener.Up[2]; break; default: @@ -396,15 +396,15 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu else switch(param) { case AL_POSITION: - *value1 = (ALint)context->Listener->Position[0]; - *value2 = (ALint)context->Listener->Position[1]; - *value3 = (ALint)context->Listener->Position[2]; + *value1 = (ALint)context->Listener.Position[0]; + *value2 = (ALint)context->Listener.Position[1]; + *value3 = (ALint)context->Listener.Position[2]; break; case AL_VELOCITY: - *value1 = (ALint)context->Listener->Velocity[0]; - *value2 = (ALint)context->Listener->Velocity[1]; - *value3 = (ALint)context->Listener->Velocity[2]; + *value1 = (ALint)context->Listener.Velocity[0]; + *value2 = (ALint)context->Listener.Velocity[1]; + *value3 = (ALint)context->Listener.Velocity[2]; break; default: @@ -438,12 +438,12 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) { case AL_ORIENTATION: // AT then UP - values[0] = (ALint)context->Listener->Forward[0]; - values[1] = (ALint)context->Listener->Forward[1]; - values[2] = (ALint)context->Listener->Forward[2]; - values[3] = (ALint)context->Listener->Up[0]; - values[4] = (ALint)context->Listener->Up[1]; - values[5] = (ALint)context->Listener->Up[2]; + values[0] = (ALint)context->Listener.Forward[0]; + values[1] = (ALint)context->Listener.Forward[1]; + values[2] = (ALint)context->Listener.Forward[2]; + values[3] = (ALint)context->Listener.Up[0]; + values[4] = (ALint)context->Listener.Up[1]; + values[5] = (ALint)context->Listener.Up[2]; break; default: @@ -457,7 +457,7 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) void UpdateListenerProps(ALCcontext *context) { - ALlistener *listener = context->Listener; + ALlistener *listener{&context->Listener}; struct ALlistenerProps *props; /* Get an unused proprty container, or allocate a new one as needed. */ -- cgit v1.2.3 From d7cc9b912b71b17d6cd1bb9726673b79a4c0173a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 00:38:31 -0800 Subject: Use new/delete for ALCcontext objects --- Alc/alc.cpp | 18 ++---------------- Alc/alcontext.h | 3 +++ Alc/bformatdec.cpp | 6 ++---- common/almalloc.cpp | 6 +++--- common/almalloc.h | 23 ++++++++++++----------- 5 files changed, 22 insertions(+), 34 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 7b55f120..1d6d55e0 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2791,9 +2791,7 @@ static void FreeContext(ALCcontext *context) ALCdevice_DecRef(context->Device); context->Device = nullptr; - //Invalidate context - memset(context, 0, sizeof(ALCcontext)); - al_free(context); + delete context; } /* ReleaseContext @@ -3791,19 +3789,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ATOMIC_STORE_SEQ(&device->LastError, ALC_NO_ERROR); - if(device->Type == Playback && DefaultEffect.type != AL_EFFECT_NULL) - ALContext = static_cast(al_calloc(16, - sizeof(ALCcontext)+sizeof(ALlistener)+sizeof(ALeffectslot))); - else - ALContext = static_cast(al_calloc(16, sizeof(ALCcontext)+sizeof(ALlistener))); - if(!ALContext) - { - almtx_unlock(&device->BackendLock); - - alcSetError(device, ALC_OUT_OF_MEMORY); - ALCdevice_DecRef(device); - return nullptr; - } + ALContext = new ALCcontext{}; InitRef(&ALContext->ref, 1); ALContext->DefaultSlot = nullptr; diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 16a5e909..f04607a9 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -9,6 +9,7 @@ #include "atomic.h" #include "vector.h" #include "threads.h" +#include "almalloc.h" #include "alListener.h" @@ -113,6 +114,8 @@ struct ALCcontext_struct { ATOMIC(ALCcontext*) next; ALlistener Listener; + + DEF_NEWDEL(ALCcontext) }; ALCcontext *GetContextRef(void); diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index afa25461..6202d7c1 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -164,8 +164,7 @@ struct BFormatDec { ALsizei NumChannels; ALboolean DualBand; - void *operator new(size_t size) { return al_malloc(alignof(BFormatDec), size); } - void operator delete(void *block) { al_free(block); } + DEF_NEWDEL(BFormatDec) }; BFormatDec *bformatdec_alloc() @@ -437,8 +436,7 @@ struct AmbiUpsampler { ALfloat Gains[4][MAX_OUTPUT_CHANNELS][NUM_BANDS]; - void *operator new(size_t size) { return al_malloc(alignof(AmbiUpsampler), size); } - void operator delete(void *block) { al_free(block); } + DEF_NEWDEL(AmbiUpsampler) }; AmbiUpsampler *ambiup_alloc() diff --git a/common/almalloc.cpp b/common/almalloc.cpp index 1b90d1c0..6dcb6cfc 100644 --- a/common/almalloc.cpp +++ b/common/almalloc.cpp @@ -55,7 +55,7 @@ void *al_calloc(size_t alignment, size_t size) return ret; } -void al_free(void *ptr) +void al_free(void *ptr) noexcept { #if defined(HAVE_ALIGNED_ALLOC) || defined(HAVE_POSIX_MEMALIGN) free(ptr); @@ -73,7 +73,7 @@ void al_free(void *ptr) #endif } -size_t al_get_page_size(void) +size_t al_get_page_size(void) noexcept { static size_t psize = 0; if(UNLIKELY(!psize)) @@ -100,7 +100,7 @@ size_t al_get_page_size(void) return psize; } -int al_is_sane_alignment_allocator(void) +int al_is_sane_alignment_allocator(void) noexcept { #if defined(HAVE_ALIGNED_ALLOC) || defined(HAVE_POSIX_MEMALIGN) || defined(HAVE__ALIGNED_MALLOC) return 1; diff --git a/common/almalloc.h b/common/almalloc.h index a4297cf5..ad48db8b 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -3,28 +3,29 @@ #include -#ifdef __cplusplus -extern "C" { -#endif - /* Minimum alignment required by posix_memalign. */ #define DEF_ALIGN sizeof(void*) void *al_malloc(size_t alignment, size_t size); void *al_calloc(size_t alignment, size_t size); -void al_free(void *ptr); +void al_free(void *ptr) noexcept; -size_t al_get_page_size(void); +size_t al_get_page_size(void) noexcept; /** * Returns non-0 if the allocation function has direct alignment handling. * Otherwise, the standard malloc is used with an over-allocation and pointer * offset strategy. */ -int al_is_sane_alignment_allocator(void); - -#ifdef __cplusplus -} -#endif +int al_is_sane_alignment_allocator(void) noexcept; + +#define DEF_NEWDEL(T) \ + void *operator new(size_t size) \ + { \ + void *ret = al_malloc(alignof(T), size); \ + if(!ret) throw std::bad_alloc(); \ + return ret; \ + } \ + void operator delete(void *block) noexcept { al_free(block); } #endif /* AL_MALLOC_H */ -- cgit v1.2.3 From 4dc8f44d00c435924e5918fb8e06f926ecc4035b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 01:33:26 -0800 Subject: Move the alignment-aware allocator and vector to headers --- Alc/bformatdec.cpp | 33 +------------------------ Alc/vector.h | 71 ++++++++++++++++-------------------------------------- common/almalloc.h | 38 +++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 82 deletions(-) diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 6202d7c1..f36cf08b 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -104,37 +104,6 @@ ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn) } #define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a)) - -template -class aligned_allocator : public std::allocator { -public: - using size_type = size_t; - using pointer = T*; - using const_pointer = const T*; - - template - struct rebind { - using other = aligned_allocator; - }; - - pointer allocate(size_type n, const void* = nullptr) - { return reinterpret_cast(al_malloc(alignment, n*sizeof(T))); } - - void deallocate(pointer p, size_type) - { al_free(p); } - - aligned_allocator() : std::allocator() { } - aligned_allocator(const aligned_allocator &a) : std::allocator(a) { } - template - aligned_allocator(const aligned_allocator &a) - : std::allocator(a) - { } - ~aligned_allocator() { } -}; - -template -using aligned_vector = std::vector>; - } // namespace @@ -149,7 +118,7 @@ struct BFormatDec { BandSplitter XOver[MAX_AMBI_COEFFS]; - aligned_vector, 16> Samples; + al::vector, 16> Samples; /* These two alias into Samples */ std::array *SamplesHF; std::array *SamplesLF; diff --git a/Alc/vector.h b/Alc/vector.h index a7be99d0..99713e2f 100644 --- a/Alc/vector.h +++ b/Alc/vector.h @@ -1,65 +1,32 @@ #ifndef AL_VECTOR_H #define AL_VECTOR_H -#include - -#include +#include +#include #include "almalloc.h" #define TYPEDEF_VECTOR(T, N) typedef struct { \ - size_t Capacity; \ - size_t Size; \ + std::size_t Capacity; \ + std::size_t Size; \ T Data[]; \ } _##N; \ typedef _##N* N; \ typedef const _##N* const_##N; #define VECTOR(T) struct { \ - size_t Capacity; \ - size_t Size; \ + std::size_t Capacity; \ + std::size_t Size; \ T Data[]; \ }* -#define VECTOR_INIT(_x) do { (_x) = NULL; } while(0) -#define VECTOR_INIT_STATIC() NULL -#define VECTOR_DEINIT(_x) do { al_free((_x)); (_x) = NULL; } while(0) - -#ifndef __cplusplus -#define VECTOR_RESIZE(_x, _s, _c) do { \ - size_t _size = (_s); \ - size_t _cap = (_c); \ - if(_size > _cap) \ - _cap = _size; \ - \ - if(!(_x) && _cap == 0) \ - break; \ - \ - if(((_x) ? (_x)->Capacity : 0) < _cap) \ - { \ - ptrdiff_t data_offset = (_x) ? (char*)((_x)->Data) - (char*)(_x) : \ - sizeof(*(_x)); \ - size_t old_size = ((_x) ? (_x)->Size : 0); \ - void *temp; \ - \ - temp = al_calloc(16, data_offset + sizeof((_x)->Data[0])*_cap); \ - assert(temp != NULL); \ - if((_x)) \ - memcpy(((char*)temp)+data_offset, (_x)->Data, \ - sizeof((_x)->Data[0])*old_size); \ - \ - al_free((_x)); \ - (_x) = temp; \ - (_x)->Capacity = _cap; \ - } \ - (_x)->Size = _size; \ -} while(0) \ - -#else +#define VECTOR_INIT(_x) do { (_x) = nullptr; } while(0) +#define VECTOR_INIT_STATIC() nullptr +#define VECTOR_DEINIT(_x) do { al_free((_x)); (_x) = nullptr; } while(0) template -inline void do_vector_resize(T *&vec, size_t size, size_t cap) +inline void do_vector_resize(T *&vec, std::size_t size, std::size_t cap) { if(size > cap) cap = size; @@ -71,12 +38,9 @@ inline void do_vector_resize(T *&vec, size_t size, size_t cap) { ptrdiff_t data_offset = vec ? (char*)(vec->Data) - (char*)(vec) : sizeof(*vec); size_t old_size = (vec ? vec->Size : 0); - T *temp; - temp = reinterpret_cast(al_calloc(16, data_offset + sizeof(vec->Data[0])*cap)); - assert(temp != nullptr); - if(vec) - memcpy(temp->Data, vec->Data, sizeof(vec->Data[0])*old_size); + auto temp = static_cast(al_calloc(16, data_offset + sizeof(vec->Data[0])*cap)); + if(vec) std::memcpy(temp->Data, vec->Data, sizeof(vec->Data[0])*old_size); al_free(vec); vec = temp; @@ -85,7 +49,6 @@ inline void do_vector_resize(T *&vec, size_t size, size_t cap) vec->Size = size; } #define VECTOR_RESIZE(_x, _s, _c) do_vector_resize(_x, _s, _c) -#endif // __cplusplus #define VECTOR_CAPACITY(_x) ((_x) ? (_x)->Capacity : 0) #define VECTOR_SIZE(_x) ((_x) ? (_x)->Size : 0) @@ -94,7 +57,7 @@ inline void do_vector_resize(T *&vec, size_t size, size_t cap) #define VECTOR_END(_x) ((_x) ? (_x)->Data + (_x)->Size : NULL) #define VECTOR_PUSH_BACK(_x, _obj) do { \ - size_t _pbsize = VECTOR_SIZE(_x)+1; \ + std::size_t _pbsize = VECTOR_SIZE(_x)+1; \ VECTOR_RESIZE(_x, _pbsize, _pbsize); \ (_x)->Data[(_x)->Size-1] = (_obj); \ } while(0) @@ -123,4 +86,12 @@ inline void do_vector_resize(T *&vec, size_t size, size_t cap) (_i) = _iter; \ } while(0) + +namespace al { + +template +using vector = std::vector>; + +} // namespace al + #endif /* AL_VECTOR_H */ diff --git a/common/almalloc.h b/common/almalloc.h index ad48db8b..ccaa6a98 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -3,6 +3,9 @@ #include +#include +#include + /* Minimum alignment required by posix_memalign. */ #define DEF_ALIGN sizeof(void*) @@ -28,4 +31,39 @@ int al_is_sane_alignment_allocator(void) noexcept; } \ void operator delete(void *block) noexcept { al_free(block); } +namespace al { + +template +struct allocator : public std::allocator { + using size_type = size_t; + using pointer = T*; + using const_pointer = const T*; + + template + struct rebind { + using other = allocator; + }; + + pointer allocate(size_type n, const void* = nullptr) + { + if(n > std::numeric_limits::max() / sizeof(T)) + throw std::bad_alloc(); + + void *ret{al_malloc(alignment, n*sizeof(T))}; + if(!ret) throw std::bad_alloc(); + return static_cast(ret); + } + + void deallocate(pointer p, size_type) + { al_free(p); } + + allocator() : std::allocator() { } + allocator(const allocator &a) : std::allocator(a) { } + template + allocator(const allocator &a) : std::allocator(a) + { } +}; + +} // namespace al + #endif /* AL_MALLOC_H */ -- cgit v1.2.3 From 7b95712f38e9bc1848ab954fbaa9c393600bdb28 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 02:15:31 -0800 Subject: Use a proper vector for the source sublists --- Alc/alc.cpp | 19 ++++++------- Alc/alcontext.h | 7 ++--- OpenAL32/alSource.cpp | 79 +++++++++++++++++++++++---------------------------- 3 files changed, 47 insertions(+), 58 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 1d6d55e0..dcf35c63 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2254,7 +2254,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) context = ATOMIC_LOAD_SEQ(&device->ContextList); while(context) { - SourceSubList *sublist, *subend; struct ALvoiceProps *vprops; ALsizei pos; @@ -2288,15 +2287,13 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) almtx_unlock(&context->EffectSlotLock); almtx_lock(&context->SourceLock); - sublist = VECTOR_BEGIN(context->SourceList); - subend = VECTOR_END(context->SourceList); - for(;sublist != subend;++sublist) + for(auto &sublist : context->SourceList) { - ALuint64 usemask = ~sublist->FreeMask; + uint64_t usemask = ~sublist.FreeMask; while(usemask) { ALsizei idx = CTZ64(usemask); - ALsource *source = sublist->Sources + idx; + ALsource *source = sublist.Sources + idx; usemask &= ~(U64(1) << idx); @@ -2612,7 +2609,6 @@ static ALvoid InitContext(ALCcontext *Context) Context->GainBoost = 1.0f; almtx_init(&Context->PropLock, almtx_plain); ATOMIC_INIT(&Context->LastError, AL_NO_ERROR); - VECTOR_INIT(Context->SourceList); Context->NumSources = 0; almtx_init(&Context->SourceLock, almtx_plain); VECTOR_INIT(Context->EffectSlotList); @@ -2720,10 +2716,11 @@ static void FreeContext(ALCcontext *context) static_cast(nullptr), almemory_order_relaxed)); ReleaseALSources(context); -#define FREE_SOURCESUBLIST(x) al_free((x)->Sources) - VECTOR_FOR_EACH(SourceSubList, context->SourceList, FREE_SOURCESUBLIST); -#undef FREE_SOURCESUBLIST - VECTOR_DEINIT(context->SourceList); + std::for_each(context->SourceList.begin(), context->SourceList.end(), + [](const SourceSubList &entry) noexcept -> void + { al_free(entry.Sources); } + ); + context->SourceList.clear(); context->NumSources = 0; almtx_destroy(&context->SourceLock); diff --git a/Alc/alcontext.h b/Alc/alcontext.h index f04607a9..a4e397be 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -37,10 +37,9 @@ enum class DistanceModel { }; struct SourceSubList { - uint64_t FreeMask; - ALsource *Sources; /* 64 */ + uint64_t FreeMask{0u}; + ALsource *Sources{nullptr}; /* 64 */ }; -TYPEDEF_VECTOR(SourceSubList, vector_SourceSubList) /* Effect slots are rather large, and apps aren't likely to have more than one * or two (let alone 64), so hold them individually. @@ -51,7 +50,7 @@ TYPEDEF_VECTOR(ALeffectslotPtr, vector_ALeffectslotPtr) struct ALCcontext_struct { RefCount ref; - vector_SourceSubList SourceList; + al::vector SourceList; ALuint NumSources; almtx_t SourceLock; diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index f3996cbf..e1c65cd8 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -25,6 +25,8 @@ #include #include +#include + #include "AL/al.h" #include "AL/alc.h" @@ -61,16 +63,15 @@ static inline void UnlockSourceList(ALCcontext *context) static inline ALsource *LookupSource(ALCcontext *context, ALuint id) { - SourceSubList *sublist; ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; - if(UNLIKELY(lidx >= VECTOR_SIZE(context->SourceList))) - return NULL; - sublist = &VECTOR_ELEM(context->SourceList, lidx); - if(UNLIKELY(sublist->FreeMask & (U64(1)<Sources + slidx; + if(UNLIKELY(lidx >= context->SourceList.size())) + return nullptr; + SourceSubList &sublist{context->SourceList[lidx]}; + if(UNLIKELY(sublist.FreeMask & (U64(1)<Device; - SourceSubList *sublist, *subend; - ALsource *source = NULL; - ALsizei lidx = 0; - ALsizei slidx; - + ALCdevice *device{context->Device}; almtx_lock(&context->SourceLock); if(context->NumSources >= device->SourcesMax) { almtx_unlock(&context->SourceLock); alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax); - return NULL; + return nullptr; } - sublist = VECTOR_BEGIN(context->SourceList); - subend = VECTOR_END(context->SourceList); - for(;sublist != subend;++sublist) + auto sublist = std::find_if(context->SourceList.begin(), context->SourceList.end(), + [](const SourceSubList &entry) -> bool + { return entry.FreeMask != 0; } + ); + ALsizei lidx = std::distance(context->SourceList.begin(), sublist); + ALsource *source; + ALsizei slidx; + if(LIKELY(sublist != context->SourceList.end())) { - if(sublist->FreeMask) - { - slidx = CTZ64(sublist->FreeMask); - source = sublist->Sources + slidx; - break; - } - ++lidx; + slidx = CTZ64(sublist->FreeMask); + source = sublist->Sources + slidx; } - if(UNLIKELY(!source)) + else { - const SourceSubList empty_sublist = { 0, NULL }; /* Don't allocate so many list entries that the 32-bit ID could * overflow... */ - if(UNLIKELY(VECTOR_SIZE(context->SourceList) >= 1<<25)) + if(UNLIKELY(context->SourceList.size() >= 1<<25)) { almtx_unlock(&device->BufferLock); alSetError(context, AL_OUT_OF_MEMORY, "Too many sources allocated"); - return NULL; + return nullptr; } - lidx = (ALsizei)VECTOR_SIZE(context->SourceList); - VECTOR_PUSH_BACK(context->SourceList, empty_sublist); - sublist = &VECTOR_BACK(context->SourceList); + context->SourceList.emplace_back(); + sublist = context->SourceList.end() - 1; + sublist->FreeMask = ~U64(0); sublist->Sources = static_cast(al_calloc(16, sizeof(ALsource)*64)); if(UNLIKELY(!sublist->Sources)) { - VECTOR_POP_BACK(context->SourceList); + context->SourceList.pop_back(); almtx_unlock(&context->SourceLock); alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate source batch"); - return NULL; + return nullptr; } slidx = 0; source = sublist->Sources + slidx; } - memset(source, 0, sizeof(*source)); + source = new (source) ALsource{}; InitSourceParams(source, device->NumAuxSends); /* Add 1 to avoid source ID 0. */ @@ -3673,9 +3668,9 @@ static void FreeSource(ALCcontext *context, ALsource *source) ALCdevice_Unlock(device); DeinitSource(source, device->NumAuxSends); - memset(source, 0, sizeof(*source)); + source->~ALsource(); - VECTOR_ELEM(context->SourceList, lidx).FreeMask |= U64(1) << slidx; + context->SourceList[lidx].FreeMask |= U64(1) << slidx; context->NumSources--; } @@ -3686,24 +3681,22 @@ static void FreeSource(ALCcontext *context, ALsource *source) ALvoid ReleaseALSources(ALCcontext *context) { ALCdevice *device = context->Device; - SourceSubList *sublist = VECTOR_BEGIN(context->SourceList); - SourceSubList *subend = VECTOR_END(context->SourceList); size_t leftover = 0; - for(;sublist != subend;++sublist) + for(auto &sublist : context->SourceList) { - ALuint64 usemask = ~sublist->FreeMask; + ALuint64 usemask = ~sublist.FreeMask; while(usemask) { ALsizei idx = CTZ64(usemask); - ALsource *source = sublist->Sources + idx; + ALsource *source = sublist.Sources + idx; DeinitSource(source, device->NumAuxSends); - memset(source, 0, sizeof(*source)); + source->~ALsource(); ++leftover; usemask &= ~(U64(1) << idx); } - sublist->FreeMask = ~usemask; + sublist.FreeMask = ~usemask; } if(leftover > 0) WARN("(%p) Deleted " SZFMT " Source%s\n", device, leftover, (leftover==1)?"":"s"); -- cgit v1.2.3 From 3eededf5d64e197b1c1ed4be883efd0309ca00e0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 02:39:27 -0800 Subject: Use a normal vector for auxiliary effect slots --- Alc/alc.cpp | 9 ++------ Alc/alcontext.h | 2 +- OpenAL32/alAuxEffectSlot.cpp | 53 +++++++++++++++++++++----------------------- OpenAL32/alSource.cpp | 8 +++---- 4 files changed, 32 insertions(+), 40 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index dcf35c63..66c19b86 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2272,9 +2272,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) almtx_lock(&context->PropLock); almtx_lock(&context->EffectSlotLock); - for(pos = 0;pos < (ALsizei)VECTOR_SIZE(context->EffectSlotList);pos++) + for(auto &slot : context->EffectSlotList) { - ALeffectslot *slot = VECTOR_ELEM(context->EffectSlotList, pos); ALeffectState *state = slot->Effect.State; state->OutBuffer = device->Dry.Buffer; @@ -2611,7 +2610,6 @@ static ALvoid InitContext(ALCcontext *Context) ATOMIC_INIT(&Context->LastError, AL_NO_ERROR); Context->NumSources = 0; almtx_init(&Context->SourceLock, almtx_plain); - VECTOR_INIT(Context->EffectSlotList); almtx_init(&Context->EffectSlotLock, almtx_plain); if(Context->DefaultSlot) @@ -2737,10 +2735,7 @@ static void FreeContext(ALCcontext *context) TRACE("Freed " SZFMT " AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s"); ReleaseALAuxiliaryEffectSlots(context); -#define FREE_EFFECTSLOTPTR(x) al_free(*(x)) - VECTOR_FOR_EACH(ALeffectslotPtr, context->EffectSlotList, FREE_EFFECTSLOTPTR); -#undef FREE_EFFECTSLOTPTR - VECTOR_DEINIT(context->EffectSlotList); + context->EffectSlotList.clear(); almtx_destroy(&context->EffectSlotLock); count = 0; diff --git a/Alc/alcontext.h b/Alc/alcontext.h index a4e397be..d0a2dc51 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -54,7 +54,7 @@ struct ALCcontext_struct { ALuint NumSources; almtx_t SourceLock; - vector_ALeffectslotPtr EffectSlotList; + al::vector EffectSlotList; almtx_t EffectSlotLock; ATOMIC(ALenum) LastError; diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index bcf5c967..119bb038 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -23,6 +23,8 @@ #include #include +#include + #include "AL/al.h" #include "AL/alc.h" @@ -77,10 +79,10 @@ static void ALeffectState_IncRef(ALeffectState *state); static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) { - id--; - if(UNLIKELY(id >= VECTOR_SIZE(context->EffectSlotList))) + --id; + if(UNLIKELY(id >= context->EffectSlotList.size())) return nullptr; - return VECTOR_ELEM(context->EffectSlotList, id); + return context->EffectSlotList[id]; } static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) @@ -123,31 +125,29 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo device = context->Device; for(cur = 0;cur < n;cur++) { - ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList); - ALeffectslotPtr *end = VECTOR_END(context->EffectSlotList); - ALeffectslot *slot = nullptr; - ALenum err = AL_OUT_OF_MEMORY; - - for(;iter != end;iter++) + auto iter = std::find_if(context->EffectSlotList.begin(), context->EffectSlotList.end(), + [](const ALeffectslotPtr &entry) noexcept -> bool + { return !entry; } + ); + if(iter == context->EffectSlotList.end()) { - if(!*iter) - break; - } - if(iter == end) - { - if(device->AuxiliaryEffectSlotMax == VECTOR_SIZE(context->EffectSlotList)) + if(device->AuxiliaryEffectSlotMax == context->EffectSlotList.size()) { UnlockEffectSlotList(context); alDeleteAuxiliaryEffectSlots(cur, effectslots); SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, "Exceeding %u auxiliary effect slot limit", device->AuxiliaryEffectSlotMax); } - VECTOR_PUSH_BACK(context->EffectSlotList, nullptr); - iter = &VECTOR_BACK(context->EffectSlotList); + context->EffectSlotList.emplace_back(nullptr); + iter = context->EffectSlotList.end() - 1; } - slot = static_cast(al_calloc(16, sizeof(ALeffectslot))); + + ALenum err{AL_OUT_OF_MEMORY}; + auto slot = static_cast(al_calloc(16, sizeof(ALeffectslot))); + if(slot) slot = new (slot) ALeffectslot{}; if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR) { + slot->~ALeffectslot(); al_free(slot); UnlockEffectSlotList(context); @@ -156,7 +156,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo } aluInitEffectPanning(slot); - slot->id = (iter - VECTOR_BEGIN(context->EffectSlotList)) + 1; + slot->id = std::distance(context->EffectSlotList.begin(), iter) + 1; *iter = slot; effectslots[cur] = slot->id; @@ -198,11 +198,11 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * { if((slot=LookupEffectSlot(context, effectslots[i])) == nullptr) continue; - VECTOR_ELEM(context->EffectSlotList, effectslots[i]-1) = nullptr; + context->EffectSlotList[effectslots[i]-1] = nullptr; DeinitEffectSlot(slot); - memset(slot, 0, sizeof(*slot)); + slot->~ALeffectslot(); al_free(slot); } @@ -785,19 +785,16 @@ void UpdateAllEffectSlotProps(ALCcontext *context) ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *context) { - ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList); - ALeffectslotPtr *end = VECTOR_END(context->EffectSlotList); size_t leftover = 0; - - for(;iter != end;iter++) + for(auto &entry : context->EffectSlotList) { - ALeffectslot *slot = *iter; + ALeffectslot *slot = entry; if(!slot) continue; - *iter = nullptr; + entry = nullptr; DeinitEffectSlot(slot); - memset(slot, 0, sizeof(*slot)); + slot->~ALeffectslot(); al_free(slot); ++leftover; } diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index e1c65cd8..e3fd4557 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -104,10 +104,10 @@ static inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) { - id--; - if(UNLIKELY(id >= VECTOR_SIZE(context->EffectSlotList))) - return NULL; - return VECTOR_ELEM(context->EffectSlotList, id); + --id; + if(UNLIKELY(id >= context->EffectSlotList.size())) + return nullptr; + return context->EffectSlotList[id]; } -- cgit v1.2.3 From 310770c53125691135210d76128b5c76ea5a777a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 02:52:46 -0800 Subject: Add and use new/delete operators to ALeffectslot --- Alc/alc.cpp | 7 ++++--- OpenAL32/Include/alAuxEffectSlot.h | 7 +++++-- OpenAL32/alAuxEffectSlot.cpp | 17 ++++++----------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 66c19b86..6aec72d0 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2707,6 +2707,7 @@ static void FreeContext(ALCcontext *context) if(context->DefaultSlot) { DeinitEffectSlot(context->DefaultSlot); + delete context->DefaultSlot; context->DefaultSlot = nullptr; } @@ -3812,14 +3813,14 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin } AllocateVoices(ALContext, 256, device->NumAuxSends); - // FIXME: Reenable after the default effect slot is handled again - if(0 && DefaultEffect.type != AL_EFFECT_NULL && device->Type == Playback) + if(DefaultEffect.type != AL_EFFECT_NULL && device->Type == Playback) { - ALContext->DefaultSlot = nullptr; + ALContext->DefaultSlot = new ALeffectslot{}; if(InitEffectSlot(ALContext->DefaultSlot) == AL_NO_ERROR) aluInitEffectPanning(ALContext->DefaultSlot); else { + delete ALContext->DefaultSlot; ALContext->DefaultSlot = nullptr; ERR("Failed to initialize the default effect slot\n"); } diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 99060b74..38900695 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -4,6 +4,7 @@ #include "alMain.h" #include "alEffect.h" +#include "almalloc.h" #include "atomic.h" #ifdef __cplusplus @@ -99,7 +100,7 @@ struct ALeffectslotProps { }; -typedef struct ALeffectslot { +struct ALeffectslot { ALfloat Gain; ALboolean AuxSendAuto; @@ -148,7 +149,9 @@ typedef struct ALeffectslot { * output (FOAOut). */ alignas(16) ALfloat WetBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE]; -} ALeffectslot; + + DEF_NEWDEL(ALeffectslot) +}; ALenum InitEffectSlot(ALeffectslot *slot); void DeinitEffectSlot(ALeffectslot *slot); diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index 119bb038..e67571a2 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -142,13 +142,11 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo iter = context->EffectSlotList.end() - 1; } - ALenum err{AL_OUT_OF_MEMORY}; - auto slot = static_cast(al_calloc(16, sizeof(ALeffectslot))); - if(slot) slot = new (slot) ALeffectslot{}; - if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR) + auto slot = new ALeffectslot{}; + ALenum err{InitEffectSlot(slot)}; + if(err != AL_NO_ERROR) { - slot->~ALeffectslot(); - al_free(slot); + delete slot; UnlockEffectSlotList(context); alDeleteAuxiliaryEffectSlots(cur, effectslots); @@ -201,9 +199,7 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * context->EffectSlotList[effectslots[i]-1] = nullptr; DeinitEffectSlot(slot); - - slot->~ALeffectslot(); - al_free(slot); + delete slot; } done: @@ -793,9 +789,8 @@ ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *context) entry = nullptr; DeinitEffectSlot(slot); + delete slot; - slot->~ALeffectslot(); - al_free(slot); ++leftover; } if(leftover > 0) -- cgit v1.2.3 From bf30eb0391b84e81353139354d2ec665942847f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 03:25:32 -0800 Subject: Use std::isfinite instead of the global isfinite --- OpenAL32/alSource.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index e3fd4557..72ac3391 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -22,9 +22,9 @@ #include #include -#include #include +#include #include #include "AL/al.h" @@ -666,14 +666,14 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_SOURCE_RADIUS: - CHECKVAL(*values >= 0.0f && isfinite(*values)); + CHECKVAL(*values >= 0.0f && std::isfinite(*values)); Source->Radius = *values; DO_UPDATEPROPS(); return AL_TRUE; case AL_STEREO_ANGLES: - CHECKVAL(isfinite(values[0]) && isfinite(values[1])); + CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1])); Source->StereoPan[0] = values[0]; Source->StereoPan[1] = values[1]; @@ -682,7 +682,7 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_POSITION: - CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2])); + CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); Source->Position[0] = values[0]; Source->Position[1] = values[1]; @@ -691,7 +691,7 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_VELOCITY: - CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2])); + CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); Source->Velocity[0] = values[0]; Source->Velocity[1] = values[1]; @@ -700,7 +700,7 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_DIRECTION: - CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2])); + CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); Source->Direction[0] = values[0]; Source->Direction[1] = values[1]; @@ -709,8 +709,8 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_ORIENTATION: - CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) && - isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5])); + CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) && + std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5])); Source->Orientation[0][0] = values[0]; Source->Orientation[0][1] = values[1]; -- cgit v1.2.3 From 7433cb5f4cb0515dd6e314978f579ae91e2c63c4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 03:39:32 -0800 Subject: Avoid naming a struct member the same as an enum type --- Alc/alc.cpp | 4 ++-- Alc/alcontext.h | 4 ++-- Alc/alu.cpp | 4 ++-- OpenAL32/Include/alListener.h | 2 +- OpenAL32/Include/alSource.h | 2 +- OpenAL32/Include/alu.h | 2 +- OpenAL32/alSource.cpp | 8 ++++---- OpenAL32/alState.cpp | 14 +++++++------- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 6aec72d0..ec836bfa 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2628,7 +2628,7 @@ static ALvoid InitContext(ALCcontext *Context) ATOMIC_INIT(&Context->ActiveAuxSlots, auxslots); //Set globals - Context->DistanceModel = DistanceModel::Default; + Context->mDistanceModel = DistanceModel::Default; Context->SourceDistanceModel = AL_FALSE; Context->DopplerFactor = 1.0f; Context->DopplerVelocity = 1.0f; @@ -2661,7 +2661,7 @@ static ALvoid InitContext(ALCcontext *Context) listener.Params.ReverbSpeedOfSound = listener.Params.SpeedOfSound * listener.Params.MetersPerUnit; listener.Params.SourceDistanceModel = Context->SourceDistanceModel; - listener.Params.DistanceModel = Context->DistanceModel; + listener.Params.mDistanceModel = Context->mDistanceModel; Context->AsyncEvents = ll_ringbuffer_create(63, sizeof(AsyncEvent), false); diff --git a/Alc/alcontext.h b/Alc/alcontext.h index d0a2dc51..26da4464 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -59,7 +59,7 @@ struct ALCcontext_struct { ATOMIC(ALenum) LastError; - enum DistanceModel DistanceModel; + DistanceModel mDistanceModel; ALboolean SourceDistanceModel; ALfloat DopplerFactor; @@ -171,7 +171,7 @@ struct ALcontextProps { ALfloat DopplerVelocity; ALfloat SpeedOfSound; ALboolean SourceDistanceModel; - enum DistanceModel DistanceModel; + DistanceModel mDistanceModel; ALfloat MetersPerUnit; ATOMIC(struct ALcontextProps*) next; diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 91d9e758..92aa2bc4 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -328,7 +328,7 @@ static bool CalcContextParams(ALCcontext *Context) Listener.Params.MetersPerUnit; Listener.Params.SourceDistanceModel = props->SourceDistanceModel; - Listener.Params.DistanceModel = props->DistanceModel; + Listener.Params.mDistanceModel = props->mDistanceModel; ATOMIC_REPLACE_HEAD(struct ALcontextProps*, &Context->FreeContextProps, props); return true; @@ -1210,7 +1210,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop ClampedDist = Distance; switch(Listener.Params.SourceDistanceModel ? - props->DistanceModel : Listener.Params.DistanceModel) + props->mDistanceModel : Listener.Params.mDistanceModel) { case DistanceModel::InverseClamped: ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h index 096a747e..e14527d9 100644 --- a/OpenAL32/Include/alListener.h +++ b/OpenAL32/Include/alListener.h @@ -46,7 +46,7 @@ struct ALlistener { ALfloat ReverbSpeedOfSound; /* in meters per sec! */ ALboolean SourceDistanceModel; - enum DistanceModel DistanceModel; + DistanceModel mDistanceModel; } Params; }; diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 53313fdd..3d7d733e 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -43,7 +43,7 @@ typedef struct ALsource { ALfloat Orientation[2][3]; ALboolean HeadRelative; ALboolean Looping; - enum DistanceModel DistanceModel; + DistanceModel mDistanceModel; enum Resampler Resampler; ALboolean DirectChannels; enum SpatializeMode Spatialize; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index d309c2a7..d086bcc7 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -161,7 +161,7 @@ struct ALvoiceProps { ALfloat Direction[3]; ALfloat Orientation[2][3]; ALboolean HeadRelative; - enum DistanceModel DistanceModel; + DistanceModel mDistanceModel; enum Resampler Resampler; ALboolean DirectChannels; enum SpatializeMode SpatializeMode; diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 72ac3391..7f54767a 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -964,7 +964,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p *values == AL_EXPONENT_DISTANCE || *values == AL_EXPONENT_DISTANCE_CLAMPED); - Source->DistanceModel = static_cast(*values); + Source->mDistanceModel = static_cast(*values); if(Context->SourceDistanceModel) DO_UPDATEPROPS(); return AL_TRUE; @@ -1468,7 +1468,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_DISTANCE_MODEL: - *values = static_cast(Source->DistanceModel); + *values = static_cast(Source->mDistanceModel); return AL_TRUE; case AL_SOURCE_RESAMPLER_SOFT: @@ -3082,7 +3082,7 @@ static void InitSourceParams(ALsource *Source, ALsizei num_sends) Source->DopplerFactor = 1.0f; Source->HeadRelative = AL_FALSE; Source->Looping = AL_FALSE; - Source->DistanceModel = DistanceModel::Default; + Source->mDistanceModel = DistanceModel::Default; Source->Resampler = ResamplerDefault; Source->DirectChannels = AL_FALSE; Source->Spatialize = SpatializeAuto; @@ -3196,7 +3196,7 @@ static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_send props->Orientation[i][j] = source->Orientation[i][j]; } props->HeadRelative = source->HeadRelative; - props->DistanceModel = source->DistanceModel; + props->mDistanceModel = source->mDistanceModel; props->Resampler = source->Resampler; props->DirectChannels = source->DirectChannels; props->SpatializeMode = source->Spatialize; diff --git a/OpenAL32/alState.cpp b/OpenAL32/alState.cpp index c550d2b5..8ff2c2c3 100644 --- a/OpenAL32/alState.cpp +++ b/OpenAL32/alState.cpp @@ -149,7 +149,7 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) break; case AL_DISTANCE_MODEL: - if(context->DistanceModel == DistanceModel::Default) + if(context->mDistanceModel == DistanceModel::Default) value = AL_TRUE; break; @@ -202,7 +202,7 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) break; case AL_DISTANCE_MODEL: - value = (ALdouble)context->DistanceModel; + value = (ALdouble)context->mDistanceModel; break; case AL_SPEED_OF_SOUND: @@ -251,7 +251,7 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) break; case AL_DISTANCE_MODEL: - value = (ALfloat)context->DistanceModel; + value = (ALfloat)context->mDistanceModel; break; case AL_SPEED_OF_SOUND: @@ -300,7 +300,7 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) break; case AL_DISTANCE_MODEL: - value = (ALint)context->DistanceModel; + value = (ALint)context->mDistanceModel; break; case AL_SPEED_OF_SOUND: @@ -349,7 +349,7 @@ extern "C" AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) break; case AL_DISTANCE_MODEL: - value = (ALint64SOFT)context->DistanceModel; + value = (ALint64SOFT)context->mDistanceModel; break; case AL_SPEED_OF_SOUND: @@ -708,7 +708,7 @@ AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value) else { std::lock_guard _{context->PropLock}; - context->DistanceModel = static_cast(value); + context->mDistanceModel = static_cast(value); if(!context->SourceDistanceModel) DO_UPDATEPROPS(); } @@ -785,7 +785,7 @@ void UpdateContextProps(ALCcontext *context) props->SpeedOfSound = context->SpeedOfSound; props->SourceDistanceModel = context->SourceDistanceModel; - props->DistanceModel = context->DistanceModel; + props->mDistanceModel = context->mDistanceModel; /* Set the new container for updating internal parameters. */ props = static_cast(ATOMIC_EXCHANGE_PTR(&context->Update, props, -- cgit v1.2.3 From f48be9d73b4472570d28bf381d84e40cf65694c8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 03:59:39 -0800 Subject: Remove the pointer-specific atomic exchange macros --- Alc/alc.cpp | 22 +++++++++++----------- Alc/alu.cpp | 24 +++++++++++------------- OpenAL32/alAuxEffectSlot.cpp | 11 ++++------- OpenAL32/alListener.cpp | 5 ++--- OpenAL32/alSource.cpp | 5 ++--- OpenAL32/alState.cpp | 5 ++--- common/atomic.h | 16 +--------------- 7 files changed, 33 insertions(+), 55 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index ec836bfa..bf665cfe 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2331,8 +2331,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) * auxiliary sends is changing. Active sources will have updates * respecified in UpdateAllSourceProps. */ - vprops = static_cast(ATOMIC_EXCHANGE_PTR(&context->FreeVoiceProps, - static_cast(nullptr), almemory_order_acq_rel)); + vprops = ATOMIC_EXCHANGE(&context->FreeVoiceProps, static_cast(nullptr), + almemory_order_acq_rel); while(vprops) { struct ALvoiceProps *next = ATOMIC_LOAD(&vprops->next, almemory_order_relaxed); @@ -2345,8 +2345,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { ALvoice *voice = context->Voices[pos]; - al_free(ATOMIC_EXCHANGE_PTR(&voice->Update, static_cast(nullptr), - almemory_order_acq_rel)); + al_free(ATOMIC_EXCHANGE(&voice->Update, static_cast(nullptr), + almemory_order_acq_rel)); if(ATOMIC_LOAD(&voice->Source, almemory_order_acquire) == nullptr) continue; @@ -2711,7 +2711,7 @@ static void FreeContext(ALCcontext *context) context->DefaultSlot = nullptr; } - al_free(ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, + al_free(ATOMIC_EXCHANGE(&context->ActiveAuxSlots, static_cast(nullptr), almemory_order_relaxed)); ReleaseALSources(context); @@ -2813,7 +2813,7 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) V0(device->Backend,lock)(); origctx = context; newhead = ATOMIC_LOAD(&context->next, almemory_order_relaxed); - if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&device->ContextList, &origctx, newhead)) + if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&device->ContextList, &origctx, newhead)) { ALCcontext *list; do { @@ -2822,7 +2822,7 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) */ list = origctx; origctx = context; - } while(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&list->next, &origctx, newhead)); + } while(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&list->next, &origctx, newhead)); } else ret = !!newhead; @@ -3848,8 +3848,8 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ALCcontext *head = ATOMIC_LOAD_SEQ(&device->ContextList); do { ATOMIC_STORE(&ALContext->next, head, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK_SEQ(&device->ContextList, &head, - ALContext) == 0); + } while(ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(&device->ContextList, &head, + ALContext) == 0); } almtx_unlock(&device->BackendLock); @@ -4204,7 +4204,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) do { list = origdev; origdev = device; - } while(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&list->next, &origdev, nextdev)); + } while(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&list->next, &origdev, nextdev)); } listlock.unlock(); @@ -4332,7 +4332,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) do { list = origdev; origdev = device; - } while(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&list->next, &origdev, nextdev)); + } while(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&list->next, &origdev, nextdev)); } listlock.unlock(); diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 92aa2bc4..9a02d4b6 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -75,7 +75,7 @@ static HrtfDirectMixerFunc MixDirectHrtf = MixDirectHrtf_C; void DeinitVoice(ALvoice *voice) { - al_free(ATOMIC_EXCHANGE_PTR_SEQ(&voice->Update, static_cast(nullptr))); + al_free(ATOMIC_EXCHANGE_SEQ(&voice->Update, static_cast(nullptr))); } @@ -315,8 +315,8 @@ static bool CalcContextParams(ALCcontext *Context) ALlistener &Listener = Context->Listener; struct ALcontextProps *props; - props = static_cast(ATOMIC_EXCHANGE_PTR(&Context->Update, - static_cast(nullptr), almemory_order_acq_rel)); + props = ATOMIC_EXCHANGE(&Context->Update, static_cast(nullptr), + almemory_order_acq_rel); if(!props) return false; Listener.Params.MetersPerUnit = props->MetersPerUnit; @@ -341,8 +341,8 @@ static bool CalcListenerParams(ALCcontext *Context) struct ALlistenerProps *props; aluVector vel; - props = static_cast(ATOMIC_EXCHANGE_PTR(&Listener.Update, - static_cast(nullptr), almemory_order_acq_rel)); + props = ATOMIC_EXCHANGE(&Listener.Update, static_cast(nullptr), + almemory_order_acq_rel); if(!props) return false; /* AT then UP */ @@ -385,8 +385,8 @@ static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool f struct ALeffectslotProps *props; ALeffectState *state; - props = static_cast(ATOMIC_EXCHANGE_PTR(&slot->Update, - static_cast(nullptr), almemory_order_acq_rel)); + props = ATOMIC_EXCHANGE(&slot->Update, static_cast(nullptr), + almemory_order_acq_rel); if(!props && !force) return false; if(props) @@ -1455,8 +1455,8 @@ static void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) ALbufferlistitem *BufferListItem; struct ALvoiceProps *props; - props = static_cast(ATOMIC_EXCHANGE_PTR(&voice->Update, - static_cast(nullptr), almemory_order_acq_rel)); + props = ATOMIC_EXCHANGE(&voice->Update, static_cast(nullptr), + almemory_order_acq_rel); if(!props && !force) return; if(props) @@ -1857,10 +1857,8 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) for(i = 0;i < ctx->VoiceCount;i++) { ALvoice *voice = ctx->Voices[i]; - ALsource *source; - - source = static_cast(ATOMIC_EXCHANGE_PTR(&voice->Source, - static_cast(nullptr), almemory_order_relaxed)); + ALsource *source = ATOMIC_EXCHANGE(&voice->Source, static_cast(nullptr), + almemory_order_relaxed); if(source && ATOMIC_LOAD(&voice->Playing, almemory_order_relaxed)) { /* If the source's voice was playing, it's now effectively diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index e67571a2..ceb5cf39 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -622,8 +622,7 @@ static void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontex newarray->count = newcount; } - curarray = static_cast(ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, - newarray, almemory_order_acq_rel)); + curarray = ATOMIC_EXCHANGE(&context->ActiveAuxSlots, newarray, almemory_order_acq_rel); while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) althrd_yield(); al_free(curarray); @@ -658,8 +657,7 @@ static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcon /* TODO: Could reallocate newarray now that we know it's needed size. */ - curarray = static_cast(ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, - newarray, almemory_order_acq_rel)); + curarray = ATOMIC_EXCHANGE(&context->ActiveAuxSlots, newarray, almemory_order_acq_rel); while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) althrd_yield(); al_free(curarray); @@ -728,7 +726,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) struct ALeffectslotProps *next; do { next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeEffectslotProps, &props, next, + } while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->FreeEffectslotProps, &props, next, almemory_order_seq_cst, almemory_order_acquire) == 0); } @@ -746,8 +744,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) props->State = slot->Effect.State; /* Set the new container for updating internal parameters. */ - props = static_cast(ATOMIC_EXCHANGE_PTR(&slot->Update, props, - almemory_order_acq_rel)); + props = ATOMIC_EXCHANGE(&slot->Update, props, almemory_order_acq_rel); if(props) { /* If there was an unused update container, put it back in the diff --git a/OpenAL32/alListener.cpp b/OpenAL32/alListener.cpp index 1be5bf48..05fd7a21 100644 --- a/OpenAL32/alListener.cpp +++ b/OpenAL32/alListener.cpp @@ -469,7 +469,7 @@ void UpdateListenerProps(ALCcontext *context) struct ALlistenerProps *next; do { next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeListenerProps, &props, next, + } while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->FreeListenerProps, &props, next, almemory_order_seq_cst, almemory_order_acquire) == 0); } @@ -492,8 +492,7 @@ void UpdateListenerProps(ALCcontext *context) props->Gain = listener->Gain; /* Set the new container for updating internal parameters. */ - props = static_cast(ATOMIC_EXCHANGE_PTR(&listener->Update, props, - almemory_order_acq_rel)); + props = ATOMIC_EXCHANGE(&listener->Update, props, almemory_order_acq_rel); if(props) { /* If there was an unused update container, put it back in the diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 7f54767a..8b08728a 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -3168,7 +3168,7 @@ static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_send struct ALvoiceProps *next; do { next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeVoiceProps, &props, next, + } while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->FreeVoiceProps, &props, next, almemory_order_acq_rel, almemory_order_acquire) == 0); } @@ -3232,8 +3232,7 @@ static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_send } /* Set the new container for updating internal parameters. */ - props = static_cast(ATOMIC_EXCHANGE_PTR(&voice->Update, props, - almemory_order_acq_rel)); + props = ATOMIC_EXCHANGE(&voice->Update, props, almemory_order_acq_rel); if(props) { /* If there was an unused update container, put it back in the diff --git a/OpenAL32/alState.cpp b/OpenAL32/alState.cpp index 8ff2c2c3..85789c5e 100644 --- a/OpenAL32/alState.cpp +++ b/OpenAL32/alState.cpp @@ -773,7 +773,7 @@ void UpdateContextProps(ALCcontext *context) struct ALcontextProps *next; do { next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeContextProps, &props, next, + } while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->FreeContextProps, &props, next, almemory_order_seq_cst, almemory_order_acquire) == 0); } @@ -788,8 +788,7 @@ void UpdateContextProps(ALCcontext *context) props->mDistanceModel = context->mDistanceModel; /* Set the new container for updating internal parameters. */ - props = static_cast(ATOMIC_EXCHANGE_PTR(&context->Update, props, - almemory_order_acq_rel)); + props = ATOMIC_EXCHANGE(&context->Update, props, almemory_order_acq_rel); if(props) { /* If there was an unused update container, put it back in the diff --git a/common/atomic.h b/common/atomic.h index 5838f8da..dbb75d29 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -61,14 +61,6 @@ using std::atomic_thread_fence; #define ATOMIC_THREAD_FENCE atomic_thread_fence -/* If no PTR xchg variants are provided, the normal ones can handle it. */ -#ifndef ATOMIC_EXCHANGE_PTR -#define ATOMIC_EXCHANGE_PTR ATOMIC_EXCHANGE -#define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG ATOMIC_COMPARE_EXCHANGE_STRONG -#define ATOMIC_COMPARE_EXCHANGE_PTR_WEAK ATOMIC_COMPARE_EXCHANGE_WEAK -#endif - - #define ATOMIC_LOAD_SEQ(_val) ATOMIC_LOAD(_val, almemory_order_seq_cst) #define ATOMIC_STORE_SEQ(_val, _newval) ATOMIC_STORE(_val, _newval, almemory_order_seq_cst) @@ -81,12 +73,6 @@ using std::atomic_thread_fence; #define ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(_val, _oldval, _newval) \ ATOMIC_COMPARE_EXCHANGE_WEAK(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) -#define ATOMIC_EXCHANGE_PTR_SEQ(_val, _newval) ATOMIC_EXCHANGE_PTR(_val, _newval, almemory_order_seq_cst) -#define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(_val, _oldval, _newval) \ - ATOMIC_COMPARE_EXCHANGE_PTR_STRONG(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) -#define ATOMIC_COMPARE_EXCHANGE_PTR_WEAK_SEQ(_val, _oldval, _newval) \ - ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) - typedef unsigned int uint; typedef ATOMIC(uint) RefCount; @@ -109,7 +95,7 @@ inline uint DecrementRef(RefCount *ptr) T _first = ATOMIC_LOAD(_head, almemory_order_acquire); \ do { \ ATOMIC_STORE(&(_entry)->next, _first, almemory_order_relaxed); \ - } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(_head, &_first, _entry, \ + } while(ATOMIC_COMPARE_EXCHANGE_WEAK(_head, &_first, _entry, \ almemory_order_acq_rel, almemory_order_acquire) == 0); \ } while(0) -- cgit v1.2.3 From 0851dc12b4f21483b6f9002db4718ded99cbeb57 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 04:26:28 -0800 Subject: Remove an unused typedef --- Alc/alcontext.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 26da4464..2cdb0cf7 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -45,7 +45,6 @@ struct SourceSubList { * or two (let alone 64), so hold them individually. */ using ALeffectslotPtr = struct ALeffectslot*; -TYPEDEF_VECTOR(ALeffectslotPtr, vector_ALeffectslotPtr) struct ALCcontext_struct { RefCount ref; -- cgit v1.2.3 From de13f30e286358d8e4f41e457421e4ec9776e3f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 05:38:03 -0800 Subject: Improve audio underrun recordery in alffplay Now it has a better idea to skip samples during refill instead of after restarting. --- examples/alffplay.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 27520a6d..f02fb16b 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -992,6 +992,18 @@ int AudioState::handler() */ alSourceRewind(mSource); alSourcei(mSource, AL_BUFFER, 0); + if(alcGetInteger64vSOFT) + { + /* Also update the device start time with the current device + * clock, so the decoder knows we're running behind. + */ + int64_t devtime{}; + alcGetInteger64vSOFT(alcGetContextsDevice(alcGetCurrentContext()), + ALC_DEVICE_CLOCK_SOFT, 1, &devtime); + auto device_time = nanoseconds{devtime}; + + mDeviceStartTime = device_time - mCurrentPts; + } continue; } -- cgit v1.2.3 From ad82a70a655f3b1172a2b1c49b3eea2feb699c16 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 05:40:00 -0800 Subject: Use cleaner constructor/destructor calls for ALCcontext Note that the actual type name is ALCcontext_struct, because of how it's defined in AL/alc.h (ALCcontext is just an alias to struct ALCcontext_struct). --- Alc/alc.cpp | 111 +++++++++++++++++------------------------- Alc/alcontext.h | 70 ++++++++++++++------------ OpenAL32/Include/alListener.h | 14 +++--- 3 files changed, 90 insertions(+), 105 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index bf665cfe..2ab2df8e 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2670,64 +2670,55 @@ static ALvoid InitContext(ALCcontext *Context) } -/* FreeContext +/* ALCcontext_struct::~ALCcontext_struct() * * Cleans up the context, and destroys any remaining objects the app failed to * delete. Called once there's no more references on the context. */ -static void FreeContext(ALCcontext *context) +ALCcontext_struct::~ALCcontext_struct() { - ALlistener &listener = context->Listener; - struct ALeffectslotProps *eprops; - struct ALlistenerProps *lprops; - struct ALcontextProps *cprops; - struct ALvoiceProps *vprops; - size_t count; - ALsizei i; - - TRACE("%p\n", context); + TRACE("%p\n", this); - if((cprops=ATOMIC_LOAD(&context->Update, almemory_order_acquire)) != nullptr) + struct ALcontextProps *cprops{Update.load(std::memory_order_relaxed)}; + if(cprops) { TRACE("Freed unapplied context update %p\n", cprops); al_free(cprops); } - - count = 0; - cprops = ATOMIC_LOAD(&context->FreeContextProps, almemory_order_acquire); + size_t count{0}; + cprops = FreeContextProps.load(std::memory_order_acquire); while(cprops) { - struct ALcontextProps *next = ATOMIC_LOAD(&cprops->next, almemory_order_acquire); + struct ALcontextProps *next{cprops->next.load(std::memory_order_relaxed)}; al_free(cprops); cprops = next; ++count; } TRACE("Freed " SZFMT " context property object%s\n", count, (count==1)?"":"s"); - if(context->DefaultSlot) + if(DefaultSlot) { - DeinitEffectSlot(context->DefaultSlot); - delete context->DefaultSlot; - context->DefaultSlot = nullptr; + DeinitEffectSlot(DefaultSlot); + delete DefaultSlot; + DefaultSlot = nullptr; } - al_free(ATOMIC_EXCHANGE(&context->ActiveAuxSlots, - static_cast(nullptr), almemory_order_relaxed)); + al_free(ActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed)); - ReleaseALSources(context); - std::for_each(context->SourceList.begin(), context->SourceList.end(), + ReleaseALSources(this); + std::for_each(SourceList.begin(), SourceList.end(), [](const SourceSubList &entry) noexcept -> void { al_free(entry.Sources); } ); - context->SourceList.clear(); - context->NumSources = 0; - almtx_destroy(&context->SourceLock); + SourceList.clear(); + NumSources = 0; + almtx_destroy(&SourceLock); count = 0; - eprops = ATOMIC_LOAD(&context->FreeEffectslotProps, almemory_order_relaxed); + struct ALeffectslotProps *eprops{FreeEffectslotProps.load(std::memory_order_acquire)}; while(eprops) { - struct ALeffectslotProps *next = ATOMIC_LOAD(&eprops->next, almemory_order_relaxed); + struct ALeffectslotProps *next{eprops->next.load(std::memory_order_relaxed)}; if(eprops->State) ALeffectState_DecRef(eprops->State); al_free(eprops); eprops = next; @@ -2735,56 +2726,54 @@ static void FreeContext(ALCcontext *context) } TRACE("Freed " SZFMT " AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s"); - ReleaseALAuxiliaryEffectSlots(context); - context->EffectSlotList.clear(); - almtx_destroy(&context->EffectSlotLock); + ReleaseALAuxiliaryEffectSlots(this); + EffectSlotList.clear(); + almtx_destroy(&EffectSlotLock); count = 0; - vprops = ATOMIC_LOAD(&context->FreeVoiceProps, almemory_order_relaxed); + struct ALvoiceProps *vprops{FreeVoiceProps.load(std::memory_order_acquire)}; while(vprops) { - struct ALvoiceProps *next = ATOMIC_LOAD(&vprops->next, almemory_order_relaxed); + struct ALvoiceProps *next{vprops->next.load(std::memory_order_relaxed)}; al_free(vprops); vprops = next; ++count; } TRACE("Freed " SZFMT " voice property object%s\n", count, (count==1)?"":"s"); - for(i = 0;i < context->VoiceCount;i++) - DeinitVoice(context->Voices[i]); - al_free(context->Voices); - context->Voices = nullptr; - context->VoiceCount = 0; - context->MaxVoices = 0; + for(ALsizei i{0};i < VoiceCount;i++) + DeinitVoice(Voices[i]); + al_free(Voices); + Voices = nullptr; + VoiceCount = 0; + MaxVoices = 0; - if((lprops=ATOMIC_LOAD(&listener.Update, almemory_order_acquire)) != nullptr) + struct ALlistenerProps *lprops{Listener.Update.load(std::memory_order_relaxed)}; + if(lprops) { TRACE("Freed unapplied listener update %p\n", lprops); al_free(lprops); } count = 0; - lprops = ATOMIC_LOAD(&context->FreeListenerProps, almemory_order_acquire); + lprops = FreeListenerProps.load(std::memory_order_acquire); while(lprops) { - struct ALlistenerProps *next = ATOMIC_LOAD(&lprops->next, almemory_order_acquire); + struct ALlistenerProps *next{lprops->next.load(std::memory_order_relaxed)}; al_free(lprops); lprops = next; ++count; } TRACE("Freed " SZFMT " listener property object%s\n", count, (count==1)?"":"s"); - almtx_destroy(&context->EventCbLock); - alsem_destroy(&context->EventSem); + almtx_destroy(&EventCbLock); + alsem_destroy(&EventSem); - ll_ringbuffer_free(context->AsyncEvents); - context->AsyncEvents = nullptr; + ll_ringbuffer_free(AsyncEvents); + AsyncEvents = nullptr; - almtx_destroy(&context->PropLock); + almtx_destroy(&PropLock); - ALCdevice_DecRef(context->Device); - context->Device = nullptr; - - delete context; + ALCdevice_DecRef(Device); } /* ReleaseContext @@ -2852,7 +2841,7 @@ void ALCcontext_DecRef(ALCcontext *context) { uint ref = DecrementRef(&context->ref); TRACEREF("%p decreasing refcount to %u\n", context, ref); - if(ref == 0) FreeContext(context); + if(ref == 0) delete context; } static void ReleaseThreadCtx(ALCcontext *context) @@ -3782,23 +3771,14 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ATOMIC_STORE_SEQ(&device->LastError, ALC_NO_ERROR); - ALContext = new ALCcontext{}; - - InitRef(&ALContext->ref, 1); - ALContext->DefaultSlot = nullptr; - - ALContext->Voices = nullptr; - ALContext->VoiceCount = 0; - ALContext->MaxVoices = 0; - ATOMIC_INIT(&ALContext->ActiveAuxSlots, static_cast(nullptr)); - ALContext->Device = device; - ATOMIC_INIT(&ALContext->next, static_cast(nullptr)); + ALContext = new ALCcontext{device}; + ALCdevice_IncRef(ALContext->Device); if((err=UpdateDeviceParams(device, attrList)) != ALC_NO_ERROR) { almtx_unlock(&device->BackendLock); - al_free(ALContext); + delete ALContext; ALContext = nullptr; alcSetError(device, err); @@ -3826,7 +3806,6 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin } } - ALCdevice_IncRef(ALContext->Device); InitContext(ALContext); if(ConfigValueFloat(device->DeviceName, nullptr, "volume-adjust", &valf)) diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 2cdb0cf7..6a7ac376 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -47,71 +47,77 @@ struct SourceSubList { using ALeffectslotPtr = struct ALeffectslot*; struct ALCcontext_struct { - RefCount ref; + RefCount ref{1u}; al::vector SourceList; - ALuint NumSources; + ALuint NumSources{0}; almtx_t SourceLock; al::vector EffectSlotList; almtx_t EffectSlotLock; - ATOMIC(ALenum) LastError; + ATOMIC(ALenum) LastError{AL_NO_ERROR}; - DistanceModel mDistanceModel; - ALboolean SourceDistanceModel; + DistanceModel mDistanceModel{DistanceModel::Default}; + ALboolean SourceDistanceModel{AL_FALSE}; - ALfloat DopplerFactor; - ALfloat DopplerVelocity; - ALfloat SpeedOfSound; - ALfloat MetersPerUnit; + ALfloat DopplerFactor{1.0f}; + ALfloat DopplerVelocity{1.0f}; + ALfloat SpeedOfSound{}; + ALfloat MetersPerUnit{1.0f}; - ATOMIC(ALenum) PropsClean; - ATOMIC(ALenum) DeferUpdates; + ATOMIC(ALenum) PropsClean{AL_TRUE}; + ATOMIC(ALenum) DeferUpdates{AL_FALSE}; almtx_t PropLock; /* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit * indicates if updates are currently happening). */ - RefCount UpdateCount; - ATOMIC(ALenum) HoldUpdates; + RefCount UpdateCount{0u}; + ATOMIC(ALenum) HoldUpdates{AL_FALSE}; - ALfloat GainBoost; + ALfloat GainBoost{1.0f}; - ATOMIC(ALcontextProps*) Update; + ATOMIC(ALcontextProps*) Update{nullptr}; /* Linked lists of unused property containers, free to use for future * updates. */ - ATOMIC(ALcontextProps*) FreeContextProps; - ATOMIC(ALlistenerProps*) FreeListenerProps; - ATOMIC(ALvoiceProps*) FreeVoiceProps; - ATOMIC(ALeffectslotProps*) FreeEffectslotProps; + ATOMIC(ALcontextProps*) FreeContextProps{nullptr}; + ATOMIC(ALlistenerProps*) FreeListenerProps{nullptr}; + ATOMIC(ALvoiceProps*) FreeVoiceProps{nullptr}; + ATOMIC(ALeffectslotProps*) FreeEffectslotProps{nullptr}; - ALvoice **Voices; - ALsizei VoiceCount; - ALsizei MaxVoices; + ALvoice **Voices{nullptr}; + ALsizei VoiceCount{0}; + ALsizei MaxVoices{0}; - ATOMIC(ALeffectslotArray*) ActiveAuxSlots; + ATOMIC(ALeffectslotArray*) ActiveAuxSlots{nullptr}; althrd_t EventThread; alsem_t EventSem; - ll_ringbuffer *AsyncEvents; - ATOMIC(ALbitfieldSOFT) EnabledEvts; + ll_ringbuffer *AsyncEvents{nullptr}; + ATOMIC(ALbitfieldSOFT) EnabledEvts{0u}; almtx_t EventCbLock; - ALEVENTPROCSOFT EventCb; - void *EventParam; + ALEVENTPROCSOFT EventCb{}; + void *EventParam{nullptr}; /* Default effect slot */ - ALeffectslot *DefaultSlot; + ALeffectslot *DefaultSlot{nullptr}; + + ALCdevice *const Device; + const ALCchar *ExtensionList{nullptr}; + + ATOMIC(ALCcontext*) next{nullptr}; - ALCdevice *Device; - const ALCchar *ExtensionList; + ALlistener Listener{}; - ATOMIC(ALCcontext*) next; - ALlistener Listener; + ALCcontext_struct(ALCdevice *device) : Device{device} { } + ALCcontext_struct(const ALCcontext_struct&) = delete; + ALCcontext_struct& operator=(const ALCcontext_struct&) = delete; + ~ALCcontext_struct(); DEF_NEWDEL(ALCcontext) }; diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h index e14527d9..1e0a8265 100644 --- a/OpenAL32/Include/alListener.h +++ b/OpenAL32/Include/alListener.h @@ -22,17 +22,17 @@ struct ALlistenerProps { }; struct ALlistener { - alignas(16) ALfloat Position[3]; - ALfloat Velocity[3]; - ALfloat Forward[3]; - ALfloat Up[3]; - ALfloat Gain; + ALfloat Position[3]{0.0f, 0.0f, 0.0f}; + ALfloat Velocity[3]{0.0f, 0.0f, 0.0f}; + ALfloat Forward[3]{0.0f, 0.0f, -1.0f}; + ALfloat Up[3]{0.0f, 1.0f, 0.0f}; + ALfloat Gain{1.0f}; - ATOMIC(ALenum) PropsClean; + ATOMIC(ALenum) PropsClean{AL_TRUE}; /* Pointer to the most recent property values that are awaiting an update. */ - ATOMIC(ALlistenerProps*) Update; + ATOMIC(ALlistenerProps*) Update{nullptr}; struct { aluMatrixf Matrix; -- cgit v1.2.3 From e194d896de6cbeec2a06041dc73ba1a0ff0d992e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 06:15:02 -0800 Subject: Use constructors/destructors for ALeffectslot --- Alc/alc.cpp | 41 ++---------------------------- OpenAL32/Include/alAuxEffectSlot.h | 52 ++++++++++++++++++++------------------ OpenAL32/alAuxEffectSlot.cpp | 43 +++++++------------------------ 3 files changed, 39 insertions(+), 97 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 2ab2df8e..8cc8fb2d 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2584,31 +2584,8 @@ static ALvoid InitContext(ALCcontext *Context) ALlistener &listener = Context->Listener; struct ALeffectslotArray *auxslots; - //Initialise listener - listener.Gain = 1.0f; - listener.Position[0] = 0.0f; - listener.Position[1] = 0.0f; - listener.Position[2] = 0.0f; - listener.Velocity[0] = 0.0f; - listener.Velocity[1] = 0.0f; - listener.Velocity[2] = 0.0f; - listener.Forward[0] = 0.0f; - listener.Forward[1] = 0.0f; - listener.Forward[2] = -1.0f; - listener.Up[0] = 0.0f; - listener.Up[1] = 1.0f; - listener.Up[2] = 0.0f; - ATOMIC_INIT(&listener.PropsClean, AL_TRUE); - - ATOMIC_INIT(&listener.Update, static_cast(nullptr)); - //Validate Context - InitRef(&Context->UpdateCount, 0); - ATOMIC_INIT(&Context->HoldUpdates, AL_FALSE); - Context->GainBoost = 1.0f; almtx_init(&Context->PropLock, almtx_plain); - ATOMIC_INIT(&Context->LastError, AL_NO_ERROR); - Context->NumSources = 0; almtx_init(&Context->SourceLock, almtx_plain); almtx_init(&Context->EffectSlotLock, almtx_plain); @@ -2637,17 +2614,7 @@ static ALvoid InitContext(ALCcontext *Context) ATOMIC_INIT(&Context->PropsClean, AL_TRUE); ATOMIC_INIT(&Context->DeferUpdates, AL_FALSE); alsem_init(&Context->EventSem, 0); - Context->AsyncEvents = nullptr; - ATOMIC_INIT(&Context->EnabledEvts, 0u); almtx_init(&Context->EventCbLock, almtx_plain); - Context->EventCb = nullptr; - Context->EventParam = nullptr; - - ATOMIC_INIT(&Context->Update, static_cast(nullptr)); - ATOMIC_INIT(&Context->FreeContextProps, static_cast(nullptr)); - ATOMIC_INIT(&Context->FreeListenerProps, static_cast(nullptr)); - ATOMIC_INIT(&Context->FreeVoiceProps, static_cast(nullptr)); - ATOMIC_INIT(&Context->FreeEffectslotProps, static_cast(nullptr)); Context->ExtensionList = alExtList; @@ -2696,12 +2663,8 @@ ALCcontext_struct::~ALCcontext_struct() } TRACE("Freed " SZFMT " context property object%s\n", count, (count==1)?"":"s"); - if(DefaultSlot) - { - DeinitEffectSlot(DefaultSlot); - delete DefaultSlot; - DefaultSlot = nullptr; - } + delete DefaultSlot; + DefaultSlot = nullptr; al_free(ActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed)); diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 38900695..815ae77e 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -101,42 +101,42 @@ struct ALeffectslotProps { struct ALeffectslot { - ALfloat Gain; - ALboolean AuxSendAuto; + ALfloat Gain{1.0f}; + ALboolean AuxSendAuto{AL_TRUE}; struct { - ALenum Type; - ALeffectProps Props; + ALenum Type{AL_EFFECT_NULL}; + ALeffectProps Props{}; - ALeffectState *State; + ALeffectState *State{nullptr}; } Effect; - ATOMIC(ALenum) PropsClean; + ATOMIC(ALenum) PropsClean{AL_TRUE}; - RefCount ref; + RefCount ref{0u}; - ATOMIC(struct ALeffectslotProps*) Update; + ATOMIC(struct ALeffectslotProps*) Update{nullptr}; struct { - ALfloat Gain; - ALboolean AuxSendAuto; - - ALenum EffectType; - ALeffectProps EffectProps; - ALeffectState *EffectState; - - ALfloat RoomRolloff; /* Added to the source's room rolloff, not multiplied. */ - ALfloat DecayTime; - ALfloat DecayLFRatio; - ALfloat DecayHFRatio; - ALboolean DecayHFLimit; - ALfloat AirAbsorptionGainHF; + ALfloat Gain{1.0f}; + ALboolean AuxSendAuto{AL_TRUE}; + + ALenum EffectType{AL_EFFECT_NULL}; + ALeffectProps EffectProps{}; + ALeffectState *EffectState{nullptr}; + + ALfloat RoomRolloff{0.0f}; /* Added to the source's room rolloff, not multiplied. */ + ALfloat DecayTime{0.0f}; + ALfloat DecayLFRatio{0.0f}; + ALfloat DecayHFRatio{0.0f}; + ALboolean DecayHFLimit{AL_FALSE}; + ALfloat AirAbsorptionGainHF{1.0f}; } Params; /* Self ID */ - ALuint id; + ALuint id{}; - ALsizei NumChannels; + ALsizei NumChannels{}; BFChannelConfig ChanMap[MAX_EFFECT_CHANNELS]; /* Wet buffer configuration is ACN channel order with N3D scaling: * * Channel 0 is the unattenuated mono signal. @@ -150,11 +150,15 @@ struct ALeffectslot { */ alignas(16) ALfloat WetBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE]; + ALeffectslot() = default; + ALeffectslot(const ALeffectslot&) = delete; + ALeffectslot& operator=(const ALeffectslot&) = delete; + ~ALeffectslot(); + DEF_NEWDEL(ALeffectslot) }; ALenum InitEffectSlot(ALeffectslot *slot); -void DeinitEffectSlot(ALeffectslot *slot); void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context); void UpdateAllEffectSlotProps(ALCcontext *context); ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context); diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index ceb5cf39..6a0cc34c 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -198,7 +198,6 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * continue; context->EffectSlotList[effectslots[i]-1] = nullptr; - DeinitEffectSlot(slot); delete slot; } @@ -666,40 +665,18 @@ static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcon ALenum InitEffectSlot(ALeffectslot *slot) { - EffectStateFactory *factory; - - slot->Effect.Type = AL_EFFECT_NULL; - - factory = getFactoryByType(AL_EFFECT_NULL); + EffectStateFactory *factory{getFactoryByType(slot->Effect.Type)}; slot->Effect.State = EffectStateFactory_create(factory); if(!slot->Effect.State) return AL_OUT_OF_MEMORY; - slot->Gain = 1.0; - slot->AuxSendAuto = AL_TRUE; - ATOMIC_INIT(&slot->PropsClean, AL_TRUE); - InitRef(&slot->ref, 0); - - ATOMIC_INIT(&slot->Update, static_cast(nullptr)); - - slot->Params.Gain = 1.0f; - slot->Params.AuxSendAuto = AL_TRUE; ALeffectState_IncRef(slot->Effect.State); slot->Params.EffectState = slot->Effect.State; - slot->Params.RoomRolloff = 0.0f; - slot->Params.DecayTime = 0.0f; - slot->Params.DecayLFRatio = 0.0f; - slot->Params.DecayHFRatio = 0.0f; - slot->Params.DecayHFLimit = AL_FALSE; - slot->Params.AirAbsorptionGainHF = 1.0f; - return AL_NO_ERROR; } -void DeinitEffectSlot(ALeffectslot *slot) +ALeffectslot::~ALeffectslot() { - struct ALeffectslotProps *props; - - props = ATOMIC_LOAD_SEQ(&slot->Update); + struct ALeffectslotProps *props{Update.load()}; if(props) { if(props->State) ALeffectState_DecRef(props->State); @@ -707,9 +684,10 @@ void DeinitEffectSlot(ALeffectslot *slot) al_free(props); } - ALeffectState_DecRef(slot->Effect.State); - if(slot->Params.EffectState) - ALeffectState_DecRef(slot->Params.EffectState); + if(Effect.State) + ALeffectState_DecRef(Effect.State); + if(Params.EffectState) + ALeffectState_DecRef(Params.EffectState); } void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) @@ -781,13 +759,10 @@ ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *context) size_t leftover = 0; for(auto &entry : context->EffectSlotList) { - ALeffectslot *slot = entry; - if(!slot) continue; + if(!entry) continue; + delete entry; entry = nullptr; - DeinitEffectSlot(slot); - delete slot; - ++leftover; } if(leftover > 0) -- cgit v1.2.3 From 5bbddff2f33dfc1a25b150202f8c49c4661e8115 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 06:46:50 -0800 Subject: Separate class and variable definitions --- Alc/alc.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 8cc8fb2d..15f191ff 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -797,7 +797,7 @@ std::atomic LastNullDeviceError{ALC_NO_ERROR}; /* Thread-local current context */ std::atomic ThreadCtxProc{nullptr}; -thread_local class ThreadCtx { +class ThreadCtx { ALCcontext *ctx{nullptr}; public: @@ -811,7 +811,8 @@ public: ALCcontext *get() const noexcept { return ctx; } void set(ALCcontext *ctx_) noexcept { ctx = ctx_; } -} LocalContext; +}; +thread_local ThreadCtx LocalContext; /* Process-wide current context */ std::atomic GlobalContext{nullptr}; -- cgit v1.2.3 From 1bc88ed751504b1dce4ceab97cdb2c5b40eced82 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 07:00:43 -0800 Subject: Avoid a fixed-size string buffer --- Alc/alc.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 15f191ff..3a4905b1 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -980,14 +980,15 @@ static void alc_initconfig(void) TRACE("Initializing library v%s-%s %s\n", ALSOFT_VERSION, ALSOFT_GIT_COMMIT_HASH, ALSOFT_GIT_BRANCH); { - char buf[1024] = ""; - int len = 0; - + std::string names; if(BackendListSize > 0) - len += snprintf(buf, sizeof(buf), "%s", BackendList[0].name); + names += BackendList[0].name; for(i = 1;i < BackendListSize;i++) - len += snprintf(buf+len, sizeof(buf)-len, ", %s", BackendList[i].name); - TRACE("Supported backends: %s\n", buf); + { + names += ", "; + names += BackendList[i].name; + } + TRACE("Supported backends: %s\n", names.c_str()); } ReadALConfig(); -- cgit v1.2.3 From 336b7b77999fec857093c82c050c96b8ead3cb97 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 07:33:42 -0800 Subject: Use constructors/destructors with ALCdevice As with ALCcontext, this is really ALCdevice_struct because of the way it's declared in the public header. --- Alc/alc.cpp | 219 +++++++++++++++------------------------------- OpenAL32/Include/alMain.h | 145 +++++++++++++++--------------- 2 files changed, 142 insertions(+), 222 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 3a4905b1..640e60b7 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2388,154 +2388,101 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } -static void InitDevice(ALCdevice *device, enum DeviceType type) +ALCdevice_struct::ALCdevice_struct(DeviceType type) + : Type{type} { - ALsizei i; - - InitRef(&device->ref, 1); - ATOMIC_INIT(&device->Connected, ALC_TRUE); - device->Type = type; - ATOMIC_INIT(&device->LastError, ALC_NO_ERROR); - - device->Flags = 0; - device->Render_Mode = NormalRender; - device->AvgSpeakerDist = 0.0f; - device->LimiterState = ALC_DONT_CARE_SOFT; - - ATOMIC_INIT(&device->ContextList, static_cast(nullptr)); - - device->ClockBase = 0; - device->SamplesDone = 0; - device->FixedLatency = 0; - - device->SourcesMax = 0; - device->AuxiliaryEffectSlotMax = 0; - device->NumAuxSends = 0; - - device->Dry.Buffer = nullptr; - device->Dry.NumChannels = 0; - device->FOAOut.Buffer = nullptr; - device->FOAOut.NumChannels = 0; - device->RealOut.Buffer = nullptr; - device->RealOut.NumChannels = 0; - - device->DeviceName = nullptr; + VECTOR_INIT(HrtfList); - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - { - device->ChannelDelay[i].Gain = 1.0f; - device->ChannelDelay[i].Length = 0; - device->ChannelDelay[i].Buffer = nullptr; - } - - device->HrtfName = nullptr; - VECTOR_INIT(device->HrtfList); - device->HrtfHandle = nullptr; - device->Hrtf = nullptr; - device->Bs2b = nullptr; - device->Uhj_Encoder = nullptr; - device->AmbiDecoder = nullptr; - device->AmbiUp = nullptr; - device->Stablizer = nullptr; - device->Limiter = nullptr; + VECTOR_INIT(BufferList); + almtx_init(&BufferLock, almtx_plain); - VECTOR_INIT(device->BufferList); - almtx_init(&device->BufferLock, almtx_plain); + VECTOR_INIT(EffectList); + almtx_init(&EffectLock, almtx_plain); - VECTOR_INIT(device->EffectList); - almtx_init(&device->EffectLock, almtx_plain); + VECTOR_INIT(FilterList); + almtx_init(&FilterLock, almtx_plain); - VECTOR_INIT(device->FilterList); - almtx_init(&device->FilterLock, almtx_plain); - - almtx_init(&device->BackendLock, almtx_plain); - device->Backend = nullptr; - - ATOMIC_INIT(&device->next, static_cast(nullptr)); + almtx_init(&BackendLock, almtx_plain); } -/* FreeDevice +/* ALCdevice_struct::~ALCdevice_struct * * Frees the device structure, and destroys any objects the app failed to * delete. Called once there's no more references on the device. */ -static ALCvoid FreeDevice(ALCdevice *device) +ALCdevice_struct::~ALCdevice_struct() { - ALsizei i; - - TRACE("%p\n", device); + TRACE("%p\n", this); - if(device->Backend) - DELETE_OBJ(device->Backend); - device->Backend = nullptr; + if(Backend) + DELETE_OBJ(Backend); + Backend = nullptr; - almtx_destroy(&device->BackendLock); + almtx_destroy(&BackendLock); - ReleaseALBuffers(device); + ReleaseALBuffers(this); #define FREE_BUFFERSUBLIST(x) al_free((x)->Buffers) - VECTOR_FOR_EACH(BufferSubList, device->BufferList, FREE_BUFFERSUBLIST); + VECTOR_FOR_EACH(BufferSubList, BufferList, FREE_BUFFERSUBLIST); #undef FREE_BUFFERSUBLIST - VECTOR_DEINIT(device->BufferList); - almtx_destroy(&device->BufferLock); + VECTOR_DEINIT(BufferList); + almtx_destroy(&BufferLock); - ReleaseALEffects(device); + ReleaseALEffects(this); #define FREE_EFFECTSUBLIST(x) al_free((x)->Effects) - VECTOR_FOR_EACH(EffectSubList, device->EffectList, FREE_EFFECTSUBLIST); + VECTOR_FOR_EACH(EffectSubList, EffectList, FREE_EFFECTSUBLIST); #undef FREE_EFFECTSUBLIST - VECTOR_DEINIT(device->EffectList); - almtx_destroy(&device->EffectLock); + VECTOR_DEINIT(EffectList); + almtx_destroy(&EffectLock); - ReleaseALFilters(device); + ReleaseALFilters(this); #define FREE_FILTERSUBLIST(x) al_free((x)->Filters) - VECTOR_FOR_EACH(FilterSubList, device->FilterList, FREE_FILTERSUBLIST); + VECTOR_FOR_EACH(FilterSubList, FilterList, FREE_FILTERSUBLIST); #undef FREE_FILTERSUBLIST - VECTOR_DEINIT(device->FilterList); - almtx_destroy(&device->FilterLock); - - al_free(device->HrtfName); - device->HrtfName = nullptr; - FreeHrtfList(&device->HrtfList); - if(device->HrtfHandle) - Hrtf_DecRef(device->HrtfHandle); - device->HrtfHandle = nullptr; - al_free(device->Hrtf); - device->Hrtf = nullptr; + VECTOR_DEINIT(FilterList); + almtx_destroy(&FilterLock); - al_free(device->Bs2b); - device->Bs2b = nullptr; + al_free(HrtfName); + HrtfName = nullptr; + FreeHrtfList(&HrtfList); + if(HrtfHandle) + Hrtf_DecRef(HrtfHandle); + HrtfHandle = nullptr; + al_free(Hrtf); + Hrtf = nullptr; - al_free(device->Uhj_Encoder); - device->Uhj_Encoder = nullptr; + al_free(Bs2b); + Bs2b = nullptr; - bformatdec_free(&device->AmbiDecoder); - ambiup_free(&device->AmbiUp); + al_free(Uhj_Encoder); + Uhj_Encoder = nullptr; - al_free(device->Stablizer); - device->Stablizer = nullptr; + bformatdec_free(&AmbiDecoder); + ambiup_free(&AmbiUp); - al_free(device->Limiter); - device->Limiter = nullptr; + al_free(Stablizer); + Stablizer = nullptr; - al_free(device->ChannelDelay[0].Buffer); - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + al_free(Limiter); + Limiter = nullptr; + + al_free(ChannelDelay[0].Buffer); + for(ALsizei i{0};i < MAX_OUTPUT_CHANNELS;i++) { - device->ChannelDelay[i].Gain = 1.0f; - device->ChannelDelay[i].Length = 0; - device->ChannelDelay[i].Buffer = nullptr; + ChannelDelay[i].Gain = 1.0f; + ChannelDelay[i].Length = 0; + ChannelDelay[i].Buffer = nullptr; } - al_free(device->DeviceName); - device->DeviceName = nullptr; - - al_free(device->Dry.Buffer); - device->Dry.Buffer = nullptr; - device->Dry.NumChannels = 0; - device->FOAOut.Buffer = nullptr; - device->FOAOut.NumChannels = 0; - device->RealOut.Buffer = nullptr; - device->RealOut.NumChannels = 0; + al_free(DeviceName); + DeviceName = nullptr; - al_free(device); + al_free(Dry.Buffer); + Dry.Buffer = nullptr; + Dry.NumChannels = 0; + FOAOut.Buffer = nullptr; + FOAOut.NumChannels = 0; + RealOut.Buffer = nullptr; + RealOut.NumChannels = 0; } @@ -2551,7 +2498,7 @@ void ALCdevice_DecRef(ALCdevice *device) uint ref; ref = DecrementRef(&device->ref); TRACEREF("%p decreasing refcount to %u\n", device, ref); - if(ref == 0) FreeDevice(device); + if(ref == 0) delete device; } /* VerifyDevice @@ -3954,15 +3901,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) )) deviceName = nullptr; - auto device = static_cast(al_calloc(16, sizeof(ALCdevice))); - if(!device) - { - alcSetError(nullptr, ALC_OUT_OF_MEMORY); - return nullptr; - } - - //Validate device - InitDevice(device, Playback); + auto device = new ALCdevice{Playback}; //Set output format device->FmtChans = DevFmtChannelsDefault; @@ -4074,7 +4013,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->Backend = PlaybackBackend.getFactory().createBackend(device, ALCbackend_Playback); if(!device->Backend) { - FreeDevice(device); + delete device; alcSetError(nullptr, ALC_OUT_OF_MEMORY); return nullptr; } @@ -4083,7 +4022,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) ALCenum err{V(device->Backend,open)(deviceName)}; if(err != ALC_NO_ERROR) { - FreeDevice(device); + delete device; alcSetError(nullptr, err); return nullptr; } @@ -4193,22 +4132,14 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, if(deviceName && (!deviceName[0] || strcasecmp(deviceName, alcDefaultName) == 0 || strcasecmp(deviceName, "openal-soft") == 0)) deviceName = nullptr; - auto device = static_cast(al_calloc(16, sizeof(ALCdevice))); - if(!device) - { - alcSetError(nullptr, ALC_OUT_OF_MEMORY); - return nullptr; - } - - //Validate device - InitDevice(device, Capture); + auto device = new ALCdevice{Capture}; device->Frequency = frequency; device->Flags |= DEVICE_FREQUENCY_REQUEST; if(DecomposeDevFormat(format, &device->FmtChans, &device->FmtType) == AL_FALSE) { - FreeDevice(device); + delete device; alcSetError(nullptr, ALC_INVALID_ENUM); return nullptr; } @@ -4224,7 +4155,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, device->Backend = CaptureBackend.getFactory().createBackend(device, ALCbackend_Capture); if(!device->Backend) { - FreeDevice(device); + delete device; alcSetError(nullptr, ALC_OUT_OF_MEMORY); return nullptr; } @@ -4236,7 +4167,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCenum err{V(device->Backend,open)(deviceName)}; if(err != ALC_NO_ERROR) { - FreeDevice(device); + delete device; alcSetError(nullptr, err); return nullptr; } @@ -4371,15 +4302,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN return nullptr; } - auto device = static_cast(al_calloc(16, sizeof(ALCdevice))); - if(!device) - { - alcSetError(nullptr, ALC_OUT_OF_MEMORY); - return nullptr; - } - - //Validate device - InitDevice(device, Loopback); + auto device = new ALCdevice{Loopback}; device->SourcesMax = 256; device->AuxiliaryEffectSlotMax = 64; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 0e6e4cd9..ef44fb00 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -16,6 +16,9 @@ #include #endif +#include +#include + #include "AL/al.h" #include "AL/alc.h" #include "AL/alext.h" @@ -29,14 +32,10 @@ #include "threads.h" -#ifndef __cplusplus -#define COUNTOF(x) (sizeof(x) / sizeof(0[x])) -#else template constexpr inline size_t countof(const T(&)[N]) noexcept { return N; } #define COUNTOF countof -#endif #if defined(_WIN64) #define SZFMT "%I64u" @@ -104,13 +103,6 @@ constexpr inline size_t countof(const T(&)[N]) noexcept #define FAM_SIZE(T, M, N) (offsetof(T, M) + sizeof(((T*)NULL)->M[0])*(N)) -#ifdef __cplusplus -#include -#include - -extern "C" { -#endif - typedef ALint64SOFT ALint64; typedef ALuint64SOFT ALuint64; @@ -547,9 +539,9 @@ TYPEDEF_VECTOR(EnumeratedHrtf, vector_EnumeratedHrtf) #define MAX_DELAY_LENGTH 1024 typedef struct DistanceComp { - ALfloat Gain; - ALsizei Length; /* Valid range is [0...MAX_DELAY_LENGTH). */ - ALfloat *Buffer; + ALfloat Gain{1.0f}; + ALsizei Length{0}; /* Valid range is [0...MAX_DELAY_LENGTH). */ + ALfloat *Buffer{nullptr}; } DistanceComp; /* Size for temporary storage of buffer data, in ALfloats. Larger values need @@ -560,109 +552,109 @@ typedef struct DistanceComp { #define BUFFERSIZE 2048 typedef struct MixParams { - AmbiConfig Ambi; + AmbiConfig Ambi{}; /* Number of coefficients in each Ambi.Coeffs to mix together (4 for first- * order, 9 for second-order, etc). If the count is 0, Ambi.Map is used * instead to map each output to a coefficient index. */ - ALsizei CoeffCount; + ALsizei CoeffCount{0}; - ALfloat (*Buffer)[BUFFERSIZE]; - ALsizei NumChannels; + ALfloat (*Buffer)[BUFFERSIZE]{nullptr}; + ALsizei NumChannels{0}; } MixParams; typedef struct RealMixParams { - enum Channel ChannelName[MAX_OUTPUT_CHANNELS]; + enum Channel ChannelName[MAX_OUTPUT_CHANNELS]{}; - ALfloat (*Buffer)[BUFFERSIZE]; - ALsizei NumChannels; + ALfloat (*Buffer)[BUFFERSIZE]{nullptr}; + ALsizei NumChannels{0}; } RealMixParams; typedef void (*POSTPROCESS)(ALCdevice *device, ALsizei SamplesToDo); struct ALCdevice_struct { - RefCount ref; - - ATOMIC(ALenum) Connected; - enum DeviceType Type; - - ALuint Frequency; - ALuint UpdateSize; - ALuint NumUpdates; - enum DevFmtChannels FmtChans; - enum DevFmtType FmtType; - ALboolean IsHeadphones; - ALsizei AmbiOrder; + RefCount ref{0u}; + + ATOMIC(ALenum) Connected{AL_TRUE}; + DeviceType Type{}; + + ALuint Frequency{}; + ALuint UpdateSize{}; + ALuint NumUpdates{}; + DevFmtChannels FmtChans{}; + DevFmtType FmtType{}; + ALboolean IsHeadphones{}; + ALsizei AmbiOrder{}; /* For DevFmtAmbi* output only, specifies the channel order and * normalization. */ - enum AmbiLayout AmbiLayout; - enum AmbiNorm AmbiScale; + AmbiLayout AmbiLayout{}; + AmbiNorm AmbiScale{}; - ALCenum LimiterState; + ALCenum LimiterState{ALC_DONT_CARE_SOFT}; - char *DeviceName; + char *DeviceName{nullptr}; - ATOMIC(ALCenum) LastError; + ATOMIC(ALCenum) LastError{ALC_NO_ERROR}; // Maximum number of sources that can be created - ALuint SourcesMax; + ALuint SourcesMax{}; // Maximum number of slots that can be created - ALuint AuxiliaryEffectSlotMax; + ALuint AuxiliaryEffectSlotMax{}; - ALCuint NumMonoSources; - ALCuint NumStereoSources; - ALsizei NumAuxSends; + ALCuint NumMonoSources{}; + ALCuint NumStereoSources{}; + ALsizei NumAuxSends{}; // Map of Buffers for this device - vector_BufferSubList BufferList; + vector_BufferSubList BufferList{}; almtx_t BufferLock; // Map of Effects for this device - vector_EffectSubList EffectList; + vector_EffectSubList EffectList{}; almtx_t EffectLock; // Map of Filters for this device - vector_FilterSubList FilterList; + vector_FilterSubList FilterList{}; almtx_t FilterLock; - POSTPROCESS PostProcess; + POSTPROCESS PostProcess{}; /* HRTF state and info */ - struct DirectHrtfState *Hrtf; - char *HrtfName; - struct Hrtf *HrtfHandle; - vector_EnumeratedHrtf HrtfList; - ALCenum HrtfStatus; + struct DirectHrtfState *Hrtf{nullptr}; + char *HrtfName{nullptr}; + struct Hrtf *HrtfHandle{nullptr}; + vector_EnumeratedHrtf HrtfList{}; + ALCenum HrtfStatus{ALC_FALSE}; /* UHJ encoder state */ - struct Uhj2Encoder *Uhj_Encoder; + struct Uhj2Encoder *Uhj_Encoder{nullptr}; /* High quality Ambisonic decoder */ - struct BFormatDec *AmbiDecoder; + struct BFormatDec *AmbiDecoder{nullptr}; /* Stereo-to-binaural filter */ - struct bs2b *Bs2b; + struct bs2b *Bs2b{nullptr}; /* First-order ambisonic upsampler for higher-order output */ - struct AmbiUpsampler *AmbiUp; + struct AmbiUpsampler *AmbiUp{nullptr}; /* Rendering mode. */ - enum RenderMode Render_Mode; + RenderMode Render_Mode{NormalRender}; // Device flags - ALuint Flags; + ALuint Flags{0u}; - ALuint64 ClockBase; - ALuint SamplesDone; - ALuint FixedLatency; + ALuint64 ClockBase{0u}; + ALuint SamplesDone{0u}; + ALuint FixedLatency{0u}; /* Temp storage used for mixer processing. */ alignas(16) ALfloat TempBuffer[4][BUFFERSIZE]; /* The "dry" path corresponds to the main output. */ MixParams Dry; - ALsizei NumChannelsPerOrder[MAX_AMBI_ORDER+1]; + ALsizei NumChannelsPerOrder[MAX_AMBI_ORDER+1]{}; /* First-order ambisonics output, to be upsampled to the dry buffer if different. */ MixParams FOAOut; @@ -672,36 +664,44 @@ struct ALCdevice_struct { */ RealMixParams RealOut; - struct FrontStablizer *Stablizer; + struct FrontStablizer *Stablizer{nullptr}; - struct Compressor *Limiter; + struct Compressor *Limiter{nullptr}; /* The average speaker distance as determined by the ambdec configuration * (or alternatively, by the NFC-HOA reference delay). Only used for NFC. */ - ALfloat AvgSpeakerDist; + ALfloat AvgSpeakerDist{0.0f}; /* Delay buffers used to compensate for speaker distances. */ DistanceComp ChannelDelay[MAX_OUTPUT_CHANNELS]; /* Dithering control. */ - ALfloat DitherDepth; - ALuint DitherSeed; + ALfloat DitherDepth{0.0f}; + ALuint DitherSeed{0u}; /* Running count of the mixer invocations, in 31.1 fixed point. This * actually increments *twice* when mixing, first at the start and then at * the end, so the bottom bit indicates if the device is currently mixing * and the upper bits indicates how many mixes have been done. */ - RefCount MixCount; + RefCount MixCount{0u}; // Contexts created on this device - ATOMIC(ALCcontext*) ContextList; + ATOMIC(ALCcontext*) ContextList{nullptr}; almtx_t BackendLock; - struct ALCbackend *Backend; + struct ALCbackend *Backend{nullptr}; + + ATOMIC(ALCdevice*) next{nullptr}; - ATOMIC(ALCdevice*) next; + + ALCdevice_struct(DeviceType type); + ALCdevice_struct(const ALCdevice_struct&) = delete; + ALCdevice_struct& operator=(const ALCdevice_struct&) = delete; + ~ALCdevice_struct(); + + DEF_NEWDEL(ALCdevice) }; // Frequency was requested by the app or config file @@ -807,10 +807,7 @@ int EventThread(void *arg); char *alstrdup(const char *str); -#ifdef __cplusplus -} // extern "C" std::vector SearchDataFiles(const char *match, const char *subdir); -#endif #endif -- cgit v1.2.3 From 8b8f01e25d31e7874acb5af7e0c3c7c801497410 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 08:01:50 -0800 Subject: Avoid more cases of an enum variable and type name clash --- Alc/alc.cpp | 58 ++++++++++++++++++++++----------------------- Alc/backends/alsa.cpp | 10 ++++---- Alc/backends/coreaudio.cpp | 4 ++-- Alc/backends/dsound.cpp | 8 +++---- Alc/backends/jack.cpp | 6 ++--- Alc/backends/opensl.cpp | 12 +++++----- Alc/backends/oss.cpp | 14 +++++------ Alc/backends/portaudio.cpp | 4 ++-- Alc/backends/pulseaudio.cpp | 4 ++-- Alc/backends/qsa.cpp | 16 ++++++------- Alc/backends/sdl2.cpp | 4 ++-- Alc/backends/sndio.cpp | 10 ++++---- Alc/backends/solaris.cpp | 8 +++---- Alc/backends/wasapi.cpp | 6 ++--- Alc/backends/wave.cpp | 12 +++++----- Alc/backends/winmm.cpp | 4 ++-- Alc/panning.cpp | 28 +++++++++++----------- OpenAL32/Include/alMain.h | 6 ++--- 18 files changed, 107 insertions(+), 107 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 640e60b7..c7caaf19 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1523,13 +1523,13 @@ void SetDefaultWFXChannelOrder(ALCdevice *device) break; case DevFmtAmbi3D: device->RealOut.ChannelName[0] = Aux0; - if(device->AmbiOrder > 0) + if(device->mAmbiOrder > 0) { device->RealOut.ChannelName[1] = Aux1; device->RealOut.ChannelName[2] = Aux2; device->RealOut.ChannelName[3] = Aux3; } - if(device->AmbiOrder > 1) + if(device->mAmbiOrder > 1) { device->RealOut.ChannelName[4] = Aux4; device->RealOut.ChannelName[5] = Aux5; @@ -1537,7 +1537,7 @@ void SetDefaultWFXChannelOrder(ALCdevice *device) device->RealOut.ChannelName[7] = Aux7; device->RealOut.ChannelName[8] = Aux8; } - if(device->AmbiOrder > 2) + if(device->mAmbiOrder > 2) { device->RealOut.ChannelName[9] = Aux9; device->RealOut.ChannelName[10] = Aux10; @@ -1847,9 +1847,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->FmtType = static_cast(stype); if(schans == ALC_BFORMAT3D_SOFT) { - device->AmbiOrder = aorder; - device->AmbiLayout = static_cast(alayout); - device->AmbiScale = static_cast(ascale); + device->mAmbiOrder = aorder; + device->mAmbiLayout = static_cast(alayout); + device->mAmbiScale = static_cast(ascale); } if(numMono > INT_MAX-numStereo) @@ -3227,13 +3227,13 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC if(device->FmtChans == DevFmtAmbi3D) { values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; - values[i++] = device->AmbiLayout; + values[i++] = device->mAmbiLayout; values[i++] = ALC_AMBISONIC_SCALING_SOFT; - values[i++] = device->AmbiScale; + values[i++] = device->mAmbiScale; values[i++] = ALC_AMBISONIC_ORDER_SOFT; - values[i++] = device->AmbiOrder; + values[i++] = device->mAmbiOrder; } values[i++] = ALC_FORMAT_CHANNELS_SOFT; @@ -3332,7 +3332,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC alcSetError(device, ALC_INVALID_DEVICE); return 0; } - values[0] = device->AmbiLayout; + values[0] = device->mAmbiLayout; return 1; case ALC_AMBISONIC_SCALING_SOFT: @@ -3341,7 +3341,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC alcSetError(device, ALC_INVALID_DEVICE); return 0; } - values[0] = device->AmbiScale; + values[0] = device->mAmbiScale; return 1; case ALC_AMBISONIC_ORDER_SOFT: @@ -3350,7 +3350,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC alcSetError(device, ALC_INVALID_DEVICE); return 0; } - values[0] = device->AmbiOrder; + values[0] = device->mAmbiOrder; return 1; case ALC_MONO_SOURCES: @@ -3464,13 +3464,13 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, if(device->FmtChans == DevFmtAmbi3D) { values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; - values[i++] = device->AmbiLayout; + values[i++] = device->mAmbiLayout; values[i++] = ALC_AMBISONIC_SCALING_SOFT; - values[i++] = device->AmbiScale; + values[i++] = device->mAmbiScale; values[i++] = ALC_AMBISONIC_ORDER_SOFT; - values[i++] = device->AmbiOrder; + values[i++] = device->mAmbiOrder; } values[i++] = ALC_FORMAT_CHANNELS_SOFT; @@ -3908,8 +3908,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->FmtType = DevFmtTypeDefault; device->Frequency = DEFAULT_OUTPUT_RATE; device->IsHeadphones = AL_FALSE; - device->AmbiLayout = AmbiLayout_Default; - device->AmbiScale = AmbiNorm_Default; + device->mAmbiLayout = AmbiLayout_Default; + device->mAmbiScale = AmbiNorm_Default; device->LimiterState = ALC_TRUE; device->NumUpdates = 3; device->UpdateSize = 1024; @@ -3947,7 +3947,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) else { device->FmtChans = iter->chans; - device->AmbiOrder = iter->order; + device->mAmbiOrder = iter->order; device->Flags |= DEVICE_CHANNELS_REQUEST; } } @@ -4031,18 +4031,18 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) { if(strcasecmp(fmt, "fuma") == 0) { - device->AmbiLayout = AmbiLayout_FuMa; - device->AmbiScale = AmbiNorm_FuMa; + device->mAmbiLayout = AmbiLayout_FuMa; + device->mAmbiScale = AmbiNorm_FuMa; } else if(strcasecmp(fmt, "acn+sn3d") == 0) { - device->AmbiLayout = AmbiLayout_ACN; - device->AmbiScale = AmbiNorm_SN3D; + device->mAmbiLayout = AmbiLayout_ACN; + device->mAmbiScale = AmbiNorm_SN3D; } else if(strcasecmp(fmt, "acn+n3d") == 0) { - device->AmbiLayout = AmbiLayout_ACN; - device->AmbiScale = AmbiNorm_N3D; + device->mAmbiLayout = AmbiLayout_ACN; + device->mAmbiScale = AmbiNorm_N3D; } else ERR("Unsupported ambi-format: %s\n", fmt); @@ -4145,9 +4145,9 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, } device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_SAMPLE_TYPE_REQUEST; device->IsHeadphones = AL_FALSE; - device->AmbiOrder = 0; - device->AmbiLayout = AmbiLayout_Default; - device->AmbiScale = AmbiNorm_Default; + device->mAmbiOrder = 0; + device->mAmbiLayout = AmbiLayout_Default; + device->mAmbiScale = AmbiNorm_Default; device->UpdateSize = samples; device->NumUpdates = 1; @@ -4316,8 +4316,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->FmtChans = DevFmtChannelsDefault; device->FmtType = DevFmtTypeDefault; device->IsHeadphones = AL_FALSE; - device->AmbiLayout = AmbiLayout_Default; - device->AmbiScale = AmbiNorm_Default; + device->mAmbiLayout = AmbiLayout_Default; + device->mAmbiScale = AmbiNorm_Default; ConfigValueUInt(nullptr, nullptr, "sources", &device->SourcesMax); if(device->SourcesMax == 0) device->SourcesMax = 256; diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index d02d5d20..bcc13a66 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -766,7 +766,7 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) } CHECK(snd_pcm_hw_params_set_format(self->pcmHandle, hp, format)); /* test and set channels (implicitly sets frame bits) */ - if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder)) < 0) + if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder)) < 0) { static const enum DevFmtChannels channellist[] = { DevFmtStereo, @@ -781,12 +781,12 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(chan, 0)) >= 0) { device->FmtChans = chan; - device->AmbiOrder = 0; + device->mAmbiOrder = 0; break; } } } - CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder))); + CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder))); /* set rate (implicitly constrains period/buffer parameters) */ if(!GetConfigValueBool(device->DeviceName, "alsa", "allow-resampler", 0) || !(device->Flags&DEVICE_FREQUENCY_REQUEST)) @@ -1046,7 +1046,7 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) /* set format (implicitly sets sample bits) */ CHECK(snd_pcm_hw_params_set_format(self->pcmHandle, hp, format)); /* set channels (implicitly sets frame bits) */ - CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder))); + CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder))); /* set rate (implicitly constrains period/buffer parameters) */ CHECK(snd_pcm_hw_params_set_rate(self->pcmHandle, hp, device->Frequency, 0)); /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ @@ -1070,7 +1070,7 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) { self->ring = ll_ringbuffer_create( device->UpdateSize*device->NumUpdates, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder), false ); if(!self->ring) diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index 62df982e..a7d5445e 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -272,7 +272,7 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) } /* setup callback */ - self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); input.inputProc = ALCcoreAudioPlayback_MixerProc; input.inputProcRefCon = self; @@ -624,7 +624,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar // save requested format description for later use self->format = requestedFormat; - self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); // Use intermediate format for sample rate conversion (outputFormat) // Set sample rate to the same as hardware for resampling later diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index a52bb17c..b642dfea 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -265,7 +265,7 @@ FORCE_ALIGN int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) return 1; } - ALsizei FrameSize{FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder)}; + ALsizei FrameSize{FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder)}; DWORD FragSize{device->UpdateSize * FrameSize}; bool Playing{false}; @@ -523,7 +523,7 @@ ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) retry_open: hr = S_OK; OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; - OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); OutputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8; OutputType.Format.nSamplesPerSec = device->Frequency; @@ -807,7 +807,7 @@ ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) } InputType.Format.wFormatTag = WAVE_FORMAT_PCM; - InputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + InputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); InputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8; InputType.Format.nSamplesPerSec = device->Frequency; @@ -908,7 +908,7 @@ ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) return ll_ringbuffer_read_space(self->Ring); - ALsizei FrameSize{FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder)}; + ALsizei FrameSize{FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder)}; DWORD BufferBytes{self->BufferBytes}; DWORD LastCursor{self->Cursor}; diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index 97254582..ed404a19 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -232,7 +232,7 @@ static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg) ll_ringbuffer_free(self->Ring); self->Ring = ll_ringbuffer_create(bufsize, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder), true ); if(!self->Ring) @@ -402,7 +402,7 @@ static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) /* Force 32-bit float output. */ device->FmtType = DevFmtFloat; - numchans = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + numchans = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); for(i = 0;i < numchans;i++) { char name[64]; @@ -432,7 +432,7 @@ static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) ll_ringbuffer_free(self->Ring); self->Ring = ll_ringbuffer_create(bufsize, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder), true ); if(!self->Ring) diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 1c85c9d5..e292dfe4 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -481,7 +481,7 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) device->FmtType = DevFmtShort; SetDefaultWFXChannelOrder(device); - self->mFrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + self->mFrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; @@ -490,7 +490,7 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) #ifdef SL_DATAFORMAT_PCM_EX SLDataFormat_PCM_EX format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM_EX; - format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); format_pcm.sampleRate = device->Frequency * 1000; format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; format_pcm.containerSize = format_pcm.bitsPerSample; @@ -501,7 +501,7 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) #else SLDataFormat_PCM format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); format_pcm.samplesPerSec = device->Frequency * 1000; format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; format_pcm.containerSize = format_pcm.bitsPerSample; @@ -780,7 +780,7 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name device->UpdateSize = update_len; device->NumUpdates = (length+update_len-1) / update_len; - self->mFrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + self->mFrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); } loc_dev.locatorType = SL_DATALOCATOR_IODEVICE; loc_dev.deviceType = SL_IODEVICE_AUDIOINPUT; @@ -796,7 +796,7 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name #ifdef SL_DATAFORMAT_PCM_EX SLDataFormat_PCM_EX format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM_EX; - format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); format_pcm.sampleRate = device->Frequency * 1000; format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; format_pcm.containerSize = format_pcm.bitsPerSample; @@ -807,7 +807,7 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name #else SLDataFormat_PCM format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); format_pcm.samplesPerSec = device->Frequency * 1000; format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; format_pcm.containerSize = format_pcm.bitsPerSample; diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index ebe4b15a..38d1c40d 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -298,7 +298,7 @@ int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self) SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); ALCplaybackOSS_lock(self); while(!self->killNow.load(std::memory_order_acquire) && @@ -419,7 +419,7 @@ ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) } periods = device->NumUpdates; - numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + numChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); ossSpeed = device->Frequency; frameSize = numChannels * BytesFromDevFmt(device->FmtType); /* According to the OSS spec, 16 bytes (log2(16)) is the minimum. */ @@ -445,7 +445,7 @@ ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) } #undef CHECKERR - if((int)ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != numChannels) + if((int)ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder) != numChannels) { ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); return ALC_FALSE; @@ -474,7 +474,7 @@ ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self) try { self->mix_data.resize(device->UpdateSize * FrameSizeFromDevFmt( - device->FmtChans, device->FmtType, device->AmbiOrder + device->FmtChans, device->FmtType, device->mAmbiOrder )); self->killNow.store(AL_FALSE); @@ -560,7 +560,7 @@ int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) SetRTPriority(); althrd_setname(RECORD_THREAD_NAME); - frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); while(!self->killNow.load()) { @@ -654,7 +654,7 @@ ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) } int periods{4}; - int numChannels{ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder)}; + int numChannels{ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder)}; int frameSize{numChannels * BytesFromDevFmt(device->FmtType)}; int ossSpeed{static_cast(device->Frequency)}; int log2FragmentSize{log2i(device->UpdateSize * device->NumUpdates * @@ -685,7 +685,7 @@ ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) } #undef CHECKERR - if((int)ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != numChannels) + if((int)ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder) != numChannels) { ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); close(self->fd); diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index be5f30c4..f8506baa 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -397,7 +397,7 @@ ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) samples = device->UpdateSize * device->NumUpdates; samples = maxu(samples, 100 * device->Frequency / 1000); - frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); self->ring = ll_ringbuffer_create(samples, frame_size, false); if(self->ring == nullptr) return ALC_INVALID_VALUE; @@ -431,7 +431,7 @@ ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); return ALC_INVALID_VALUE; } - self->params.channelCount = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + self->params.channelCount = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); err = Pa_OpenStream(&self->stream, &self->params, nullptr, device->Frequency, paFramesPerBufferUnspecified, paNoFlag, diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index df2eb656..bf98c757 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -1040,7 +1040,7 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) break; } self->spec.rate = device->Frequency; - self->spec.channels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + self->spec.channels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); if(pa_sample_spec_valid(&self->spec) == 0) { @@ -1557,7 +1557,7 @@ ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) } self->spec.rate = device->Frequency; - self->spec.channels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + self->spec.channels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); if(pa_sample_spec_valid(&self->spec) == 0) { diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index f710f080..e171fb92 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -206,7 +206,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) SchedSet(0, 0, SCHED_NOCHANGE, ¶m); const ALint frame_size = FrameSizeFromDevFmt( - device->FmtChans, device->FmtType, device->AmbiOrder + device->FmtChans, device->FmtType, device->mAmbiOrder ); PlaybackWrapper_lock(self); @@ -394,13 +394,13 @@ static ALCboolean qsa_reset_playback(PlaybackWrapper *self) data->cparams.stop_mode=SND_PCM_STOP_STOP; data->cparams.buf.block.frag_size=device->UpdateSize * - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); data->cparams.buf.block.frags_max=device->NumUpdates; data->cparams.buf.block.frags_min=device->NumUpdates; data->cparams.format.interleave=1; data->cparams.format.rate=device->Frequency; - data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); data->cparams.format.format=format; if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0) @@ -584,7 +584,7 @@ static ALCboolean qsa_reset_playback(PlaybackWrapper *self) SetDefaultChannelOrder(device); device->UpdateSize=data->csetup.buf.block.frag_size/ - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); device->NumUpdates=data->csetup.buf.block.frags; data->size=data->csetup.buf.block.frag_size; @@ -776,13 +776,13 @@ static ALCenum qsa_open_capture(CaptureWrapper *self, const ALCchar *deviceName) data->cparams.stop_mode=SND_PCM_STOP_STOP; data->cparams.buf.block.frag_size=device->UpdateSize* - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); data->cparams.buf.block.frags_max=device->NumUpdates; data->cparams.buf.block.frags_min=device->NumUpdates; data->cparams.format.interleave=1; data->cparams.format.rate=device->Frequency; - data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); data->cparams.format.format=format; if(snd_pcm_plugin_params(data->pcmHandle, &data->cparams) < 0) @@ -840,7 +840,7 @@ static ALCuint qsa_available_samples(CaptureWrapper *self) ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; qsa_data *data = self->ExtraData; snd_pcm_channel_status_t status; - ALint frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + ALint frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); ALint free_size; int rstatus; @@ -877,7 +877,7 @@ static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuin int selectret; struct timeval timeout; int bytes_read; - ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); ALint len=samples*frame_size; int rstatus; diff --git a/Alc/backends/sdl2.cpp b/Alc/backends/sdl2.cpp index e1234c1b..2ef7d852 100644 --- a/Alc/backends/sdl2.cpp +++ b/Alc/backends/sdl2.cpp @@ -73,7 +73,7 @@ static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device) SET_VTABLE2(ALCsdl2Backend, ALCbackend, self); self->deviceID = 0; - self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); self->Frequency = device->Frequency; self->FmtChans = device->FmtChans; self->FmtType = device->FmtType; @@ -168,7 +168,7 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) device->UpdateSize = have.samples; device->NumUpdates = 2; /* SDL always (tries to) use two periods. */ - self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); self->Frequency = device->Frequency; self->FmtChans = device->FmtChans; self->FmtType = device->FmtType; diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index 654c2975..be6cd2e3 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -100,7 +100,7 @@ static int SndioPlayback_mixerProc(void *ptr) SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) @@ -244,7 +244,7 @@ static ALCboolean SndioPlayback_start(SndioPlayback *self) ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; self->data_size = device->UpdateSize * FrameSizeFromDevFmt( - device->FmtChans, device->FmtType, device->AmbiOrder + device->FmtChans, device->FmtType, device->mAmbiOrder ); al_free(self->mix_data); self->mix_data = al_calloc(16, self->data_size); @@ -342,7 +342,7 @@ static int SndioCapture_recordProc(void* ptr) SetRTPriority(); althrd_setname(RECORD_THREAD_NAME); - frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) @@ -442,7 +442,7 @@ static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) par.bits = par.bps * 8; par.le = SIO_LE_NATIVE; par.msb = SIO_LE_NATIVE ? 0 : 1; - par.rchan = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + par.rchan = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); par.rate = device->Frequency; par.appbufsz = maxu(device->UpdateSize*device->NumUpdates, (device->Frequency+9)/10); @@ -470,7 +470,7 @@ static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) (device->FmtType == DevFmtUShort && par.bits == 16 && par.sig == 0) || (device->FmtType == DevFmtInt && par.bits == 32 && par.sig != 0) || (device->FmtType == DevFmtUInt && par.bits == 32 && par.sig == 0)) || - ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != (ALsizei)par.rchan || + ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder) != (ALsizei)par.rchan || device->Frequency != par.rate) { ERR("Failed to set format %s %s %uhz, got %c%u %u-channel %uhz instead\n", diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index 008f3446..d306a0c5 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -117,7 +117,7 @@ static int ALCsolarisBackend_mixerProc(void *ptr) SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); ALCsolarisBackend_lock(self); while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && @@ -207,7 +207,7 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) if(device->FmtChans != DevFmtMono) device->FmtChans = DevFmtStereo; - numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + numChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); info.play.channels = numChannels; switch(device->FmtType) @@ -241,7 +241,7 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) return ALC_FALSE; } - if(ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != (ALsizei)info.play.channels) + if(ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder) != (ALsizei)info.play.channels) { ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(device->FmtChans), info.play.channels); return ALC_FALSE; @@ -264,7 +264,7 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) free(self->mix_data); self->data_size = device->UpdateSize * FrameSizeFromDevFmt( - device->FmtChans, device->FmtType, device->AmbiOrder + device->FmtChans, device->FmtType, device->mAmbiOrder ); self->mix_data = static_cast(calloc(1, self->data_size)); diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 7f52bafe..76d5f1ef 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -1306,7 +1306,7 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) else { ALuint framesize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, - device->AmbiOrder); + device->mAmbiOrder); size_t len1 = minz(data[0].len, numsamples); size_t len2 = minz(data[1].len, numsamples-len1); @@ -1674,7 +1674,7 @@ HRESULT ALCwasapiCapture::resetProxy() if(device->Frequency != OutputType.Format.nSamplesPerSec || device->FmtType != srcType) { mSampleConv = CreateSampleConverter( - srcType, device->FmtType, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder), + srcType, device->FmtType, ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder), OutputType.Format.nSamplesPerSec, device->Frequency ); if(!mSampleConv) @@ -1708,7 +1708,7 @@ HRESULT ALCwasapiCapture::resetProxy() buffer_len = maxu(device->UpdateSize*device->NumUpdates, buffer_len); ll_ringbuffer_free(mRing); mRing = ll_ringbuffer_create(buffer_len, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder), false ); if(!mRing) diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index 58e0efd5..af1fd768 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -135,7 +135,7 @@ int ALCwaveBackend_mixerProc(ALCwaveBackend *self) althrd_setname(MIXER_THREAD_NAME); - ALsizei frameSize{FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder)}; + ALsizei frameSize{FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder)}; ALint64 done{0}; auto start = std::chrono::steady_clock::now(); @@ -259,7 +259,7 @@ ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) if(GetConfigValueBool(nullptr, "wave", "bformat", 0)) { device->FmtChans = DevFmtAmbi3D; - device->AmbiOrder = 1; + device->mAmbiOrder = 1; } switch(device->FmtType) @@ -290,14 +290,14 @@ ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break; case DevFmtAmbi3D: /* .amb output requires FuMa */ - device->AmbiLayout = AmbiLayout_FuMa; - device->AmbiScale = AmbiNorm_FuMa; + device->mAmbiLayout = AmbiLayout_FuMa; + device->mAmbiScale = AmbiNorm_FuMa; isbformat = 1; chanmask = 0; break; } bits = BytesFromDevFmt(device->FmtType) * 8; - channels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + channels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); fputs("RIFF", self->mFile); fwrite32le(0xFFFFFFFF, self->mFile); // 'RIFF' header len; filled in at close @@ -344,7 +344,7 @@ ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) SetDefaultWFXChannelOrder(device); ALuint bufsize{FrameSizeFromDevFmt( - device->FmtChans, device->FmtType, device->AmbiOrder + device->FmtChans, device->FmtType, device->mAmbiOrder ) * device->UpdateSize}; self->mBuffer.resize(bufsize); diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 1d0a8ecc..8b97daab 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -341,7 +341,7 @@ ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self) SetDefaultWFXChannelOrder(device); ALuint BufferSize{device->UpdateSize * - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder)}; + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder)}; al_free(self->WaveBuffer[0].lpData); self->WaveBuffer[0] = WAVEHDR{}; @@ -564,7 +564,7 @@ ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName) memset(&self->Format, 0, sizeof(WAVEFORMATEX)); self->Format.wFormatTag = (device->FmtType == DevFmtFloat) ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM; - self->Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + self->Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); self->Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; self->Format.nBlockAlign = self->Format.wBitsPerSample * self->Format.nChannels / 8; diff --git a/Alc/panning.cpp b/Alc/panning.cpp index a60b4d4d..0d62e086 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -513,15 +513,15 @@ static void InitPanning(ALCdevice *device) if(device->FmtChans == DevFmtAmbi3D) { const char *devname = device->DeviceName; - const ALsizei *acnmap = (device->AmbiLayout == AmbiLayout_FuMa) ? FuMa2ACN : ACN2ACN; - const ALfloat *n3dscale = (device->AmbiScale == AmbiNorm_FuMa) ? FuMa2N3DScale : - (device->AmbiScale == AmbiNorm_SN3D) ? SN3D2N3DScale : - /*(device->AmbiScale == AmbiNorm_N3D) ?*/ N3D2N3DScale; + const ALsizei *acnmap = (device->mAmbiLayout == AmbiLayout_FuMa) ? FuMa2ACN : ACN2ACN; + const ALfloat *n3dscale = (device->mAmbiScale == AmbiNorm_FuMa) ? FuMa2N3DScale : + (device->mAmbiScale == AmbiNorm_SN3D) ? SN3D2N3DScale : + /*(device->mAmbiScale == AmbiNorm_N3D) ?*/ N3D2N3DScale; ALfloat nfc_delay = 0.0f; - count = (device->AmbiOrder == 3) ? 16 : - (device->AmbiOrder == 2) ? 9 : - (device->AmbiOrder == 1) ? 4 : 1; + count = (device->mAmbiOrder == 3) ? 16 : + (device->mAmbiOrder == 2) ? 9 : + (device->mAmbiOrder == 1) ? 4 : 1; for(i = 0;i < count;i++) { ALsizei acn = acnmap[i]; @@ -531,7 +531,7 @@ static void InitPanning(ALCdevice *device) device->Dry.CoeffCount = 0; device->Dry.NumChannels = count; - if(device->AmbiOrder < 2) + if(device->mAmbiOrder < 2) { device->FOAOut.Ambi = device->Dry.Ambi; device->FOAOut.CoeffCount = device->Dry.CoeffCount; @@ -553,7 +553,7 @@ static void InitPanning(ALCdevice *device) device->FOAOut.CoeffCount = 0; device->FOAOut.NumChannels = 4; - if(device->AmbiOrder >= 3) + if(device->mAmbiOrder >= 3) { w_scale = W_SCALE_3H3P; xyz_scale = XYZ_SCALE_3H3P; @@ -573,7 +573,7 @@ static void InitPanning(ALCdevice *device) }; nfc_delay = clampf(nfc_delay, 0.001f, 1000.0f); InitNearFieldCtrl(device, nfc_delay * SPEEDOFSOUNDMETRESPERSEC, - device->AmbiOrder, chans_per_order); + device->mAmbiOrder, chans_per_order); } } else @@ -759,7 +759,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz device->FOAOut.NumChannels = count; } - device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); avg_dist = 0.0f; for(i = 0;i < conf->NumSpeakers;i++) @@ -889,7 +889,7 @@ static void InitHrtfPanning(ALCdevice *device) device->FOAOut.NumChannels = 0; } - device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); BuildBFormatHrtf(device->HrtfHandle, device->Hrtf, device->Dry.NumChannels, AmbiPoints, AmbiMatrix, COUNTOF(AmbiPoints), @@ -918,7 +918,7 @@ static void InitUhjPanning(ALCdevice *device) device->FOAOut.CoeffCount = device->Dry.CoeffCount; device->FOAOut.NumChannels = 0; - device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); } void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq) @@ -1009,7 +1009,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf else { bformatdec_free(&device->AmbiDecoder); - if(device->FmtChans != DevFmtAmbi3D || device->AmbiOrder < 2) + if(device->FmtChans != DevFmtAmbi3D || device->mAmbiOrder < 2) ambiup_free(&device->AmbiUp); else { diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index ef44fb00..95753cc4 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -584,12 +584,12 @@ struct ALCdevice_struct { DevFmtChannels FmtChans{}; DevFmtType FmtType{}; ALboolean IsHeadphones{}; - ALsizei AmbiOrder{}; + ALsizei mAmbiOrder{}; /* For DevFmtAmbi* output only, specifies the channel order and * normalization. */ - AmbiLayout AmbiLayout{}; - AmbiNorm AmbiScale{}; + AmbiLayout mAmbiLayout{}; + AmbiNorm mAmbiScale{}; ALCenum LimiterState{ALC_DONT_CARE_SOFT}; -- cgit v1.2.3 From aef52be4324740bdd23c29ce3aef1027357f9694 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 08:03:22 -0800 Subject: Fix a float constant type --- Alc/alc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index c7caaf19..86150794 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2182,7 +2182,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(!(device->DitherDepth > 0.0f)) TRACE("Dithering disabled\n"); else - TRACE("Dithering enabled (%d-bit, %g)\n", float2int(std::log2(device->DitherDepth)+0.5)+1, + TRACE("Dithering enabled (%d-bit, %g)\n", float2int(std::log2(device->DitherDepth)+0.5f)+1, device->DitherDepth); device->LimiterState = gainLimiter; -- cgit v1.2.3 From ef7995cfd086dd1b32d85bf214b66da37e6550c5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 08:14:23 -0800 Subject: Fix the initial device refcount --- OpenAL32/Include/alMain.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 95753cc4..e31d0146 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -573,7 +573,7 @@ typedef struct RealMixParams { typedef void (*POSTPROCESS)(ALCdevice *device, ALsizei SamplesToDo); struct ALCdevice_struct { - RefCount ref{0u}; + RefCount ref{1u}; ATOMIC(ALenum) Connected{AL_TRUE}; DeviceType Type{}; -- cgit v1.2.3 From b10e7d08c34bc6d46aaf61ef2a0183e7841b75f3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 18:04:27 -0800 Subject: Use a std::thread for the event thread --- Alc/alc.cpp | 9 ++------- Alc/alcontext.h | 4 +++- OpenAL32/Include/alMain.h | 3 ++- OpenAL32/event.cpp | 27 ++++++++++++++++++++++++--- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 86150794..5de72b4c 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2581,8 +2581,7 @@ static ALvoid InitContext(ALCcontext *Context) Context->AsyncEvents = ll_ringbuffer_create(63, sizeof(AsyncEvent), false); - if(althrd_create(&Context->EventThread, EventThread, Context) != althrd_success) - ERR("Failed to start event thread! Expect problems.\n"); + StartEventThrd(Context); } @@ -2696,7 +2695,6 @@ ALCcontext_struct::~ALCcontext_struct() */ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) { - static const AsyncEvent kill_evt = ASYNC_EVENT(EventType_KillThread); ALCcontext *origctx, *newhead; bool ret = true; @@ -2734,10 +2732,7 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) * this, although waiting for a non-odd mix count would work too. */ - while(ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1) == 0) - althrd_yield(); - alsem_post(&context->EventSem); - althrd_join(context->EventThread, nullptr); + StopEventThrd(context); ALCcontext_DecRef(context); return ret; diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 6a7ac376..5eec2e96 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -1,6 +1,8 @@ #ifndef ALCONTEXT_H #define ALCONTEXT_H +#include + #include "AL/al.h" #include "AL/alc.h" #include "AL/alext.h" @@ -95,7 +97,7 @@ struct ALCcontext_struct { ATOMIC(ALeffectslotArray*) ActiveAuxSlots{nullptr}; - althrd_t EventThread; + std::thread EventThread; alsem_t EventSem; ll_ringbuffer *AsyncEvents{nullptr}; ATOMIC(ALbitfieldSOFT) EnabledEvts{0u}; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index e31d0146..a81d3f3d 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -803,7 +803,8 @@ inline void LockFilterList(ALCdevice *device) { almtx_lock(&device->FilterLock); inline void UnlockFilterList(ALCdevice *device) { almtx_unlock(&device->FilterLock); } -int EventThread(void *arg); +void StartEventThrd(ALCcontext *ctx); +void StopEventThrd(ALCcontext *ctx); char *alstrdup(const char *str); diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index 67a10645..e4b5eee0 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -15,10 +15,8 @@ #include "threads.h" -int EventThread(void *arg) +static int EventThread(ALCcontext *context) { - auto context = static_cast(arg); - bool quitnow{false}; while(LIKELY(!quitnow)) { @@ -50,6 +48,29 @@ int EventThread(void *arg) return 0; } +void StartEventThrd(ALCcontext *ctx) +{ + try { + ctx->EventThread = std::thread(EventThread, ctx); + } + catch(std::exception& e) { + ERR("Failed to start event thread: %s\n", e.what()); + } + catch(...) { + ERR("Failed to start event thread! Expect problems.\n"); + } +} + +void StopEventThrd(ALCcontext *ctx) +{ + static constexpr AsyncEvent kill_evt = ASYNC_EVENT(EventType_KillThread); + while(ll_ringbuffer_write(ctx->AsyncEvents, (const char*)&kill_evt, 1) == 0) + althrd_yield(); + alsem_post(&ctx->EventSem); + if(ctx->EventThread.joinable()) + ctx->EventThread.join(); +} + AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable) { ContextRef context{GetContextRef()}; -- cgit v1.2.3 From bafcba7194c36eaf4fa1cb09b000170f8a138055 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 18:45:45 -0800 Subject: Use a std::string for the device name --- Alc/alc.cpp | 33 +++++++++++++++------------------ Alc/backends/alsa.cpp | 10 ++++------ Alc/backends/coreaudio.cpp | 7 ++----- Alc/backends/dsound.cpp | 8 ++------ Alc/backends/jack.cpp | 8 +++----- Alc/backends/loopback.cpp | 3 +-- Alc/backends/null.cpp | 3 +-- Alc/backends/opensl.cpp | 8 ++------ Alc/backends/oss.cpp | 8 ++------ Alc/backends/portaudio.cpp | 8 ++------ Alc/backends/pulseaudio.cpp | 16 ++++++---------- Alc/backends/qsa.cpp | 6 ++---- Alc/backends/sdl2.cpp | 4 +--- Alc/backends/sndio.cpp | 8 ++------ Alc/backends/solaris.cpp | 3 +-- Alc/backends/wasapi.cpp | 22 ++++++---------------- Alc/backends/wave.cpp | 3 +-- Alc/backends/winmm.cpp | 6 ++---- Alc/panning.cpp | 18 +++++++++--------- OpenAL32/Include/alMain.h | 2 +- 20 files changed, 65 insertions(+), 119 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 5de72b4c..e2f562a1 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1952,7 +1952,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } #undef TRACE_ATTR - ConfigValueUInt(device->DeviceName, nullptr, "frequency", &freq); + ConfigValueUInt(device->DeviceName.c_str(), nullptr, "frequency", &freq); freq = maxu(freq, MIN_OUTPUT_RATE); device->UpdateSize = (ALuint64)device->UpdateSize * freq / @@ -1966,7 +1966,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(numMono > INT_MAX-numStereo) numMono = INT_MAX-numStereo; numMono += numStereo; - if(ConfigValueInt(device->DeviceName, nullptr, "sources", &numMono)) + if(ConfigValueInt(device->DeviceName.c_str(), nullptr, "sources", &numMono)) { if(numMono <= 0) numMono = 256; @@ -1980,7 +1980,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->NumMonoSources = numMono; device->NumStereoSources = numStereo; - if(ConfigValueInt(device->DeviceName, nullptr, "sends", &new_sends)) + if(ConfigValueInt(device->DeviceName.c_str(), nullptr, "sends", &new_sends)) new_sends = mini(numSends, clampi(new_sends, 0, MAX_SENDS)); else new_sends = numSends; @@ -2022,7 +2022,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(device->Type != Loopback) { const char *hrtf; - if(ConfigValueStr(device->DeviceName, nullptr, "hrtf", &hrtf)) + if(ConfigValueStr(device->DeviceName.c_str(), nullptr, "hrtf", &hrtf)) { if(strcasecmp(hrtf, "true") == 0) hrtf_userreq = Hrtf_Enable; @@ -2038,7 +2038,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(VECTOR_SIZE(device->HrtfList) == 0) { VECTOR_DEINIT(device->HrtfList); - device->HrtfList = EnumerateHrtf(device->DeviceName); + device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); } if(VECTOR_SIZE(device->HrtfList) > 0) { @@ -2150,10 +2150,10 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->AuxiliaryEffectSlotMax, device->NumAuxSends); device->DitherDepth = 0.0f; - if(GetConfigValueBool(device->DeviceName, nullptr, "dither", 1)) + if(GetConfigValueBool(device->DeviceName.c_str(), nullptr, "dither", 1)) { ALint depth = 0; - ConfigValueInt(device->DeviceName, nullptr, "dither-depth", &depth); + ConfigValueInt(device->DeviceName.c_str(), nullptr, "dither-depth", &depth); if(depth <= 0) { switch(device->FmtType) @@ -2186,7 +2186,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->DitherDepth); device->LimiterState = gainLimiter; - if(ConfigValueBool(device->DeviceName, nullptr, "output-limiter", &val)) + if(ConfigValueBool(device->DeviceName.c_str(), nullptr, "output-limiter", &val)) gainLimiter = val ? ALC_TRUE : ALC_FALSE; /* Valid values for gainLimiter are ALC_DONT_CARE_SOFT, ALC_TRUE, and @@ -2473,9 +2473,6 @@ ALCdevice_struct::~ALCdevice_struct() ChannelDelay[i].Buffer = nullptr; } - al_free(DeviceName); - DeviceName = nullptr; - al_free(Dry.Buffer); Dry.Buffer = nullptr; Dry.NumChannels = 0; @@ -2995,7 +2992,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para case ALC_ALL_DEVICES_SPECIFIER: if(VerifyDevice(&Device)) { - value = Device->DeviceName; + value = Device->DeviceName.c_str(); ALCdevice_DecRef(Device); } else @@ -3008,7 +3005,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para case ALC_CAPTURE_DEVICE_SPECIFIER: if(VerifyDevice(&Device)) { - value = Device->DeviceName; + value = Device->DeviceName.c_str(); ALCdevice_DecRef(Device); } else @@ -3375,7 +3372,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC case ALC_NUM_HRTF_SPECIFIERS_SOFT: almtx_lock(&device->BackendLock); FreeHrtfList(&device->HrtfList); - device->HrtfList = EnumerateHrtf(device->DeviceName); + device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); values[0] = (ALCint)VECTOR_SIZE(device->HrtfList); almtx_unlock(&device->BackendLock); return 1; @@ -3715,7 +3712,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin InitContext(ALContext); - if(ConfigValueFloat(device->DeviceName, nullptr, "volume-adjust", &valf)) + if(ConfigValueFloat(device->DeviceName.c_str(), nullptr, "volume-adjust", &valf)) { if(!std::isfinite(valf)) ERR("volume-adjust must be finite: %f\n", valf); @@ -4022,7 +4019,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) return nullptr; } - if(ConfigValueStr(device->DeviceName, nullptr, "ambi-format", &fmt)) + if(ConfigValueStr(device->DeviceName.c_str(), nullptr, "ambi-format", &fmt)) { if(strcasecmp(fmt, "fuma") == 0) { @@ -4050,7 +4047,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) } while(!DeviceList.compare_exchange_weak(head, device)); } - TRACE("Created device %p, \"%s\"\n", device, device->DeviceName); + TRACE("Created device %p, \"%s\"\n", device, device->DeviceName.c_str()); return device; } @@ -4174,7 +4171,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, } while(!DeviceList.compare_exchange_weak(head, device)); } - TRACE("Created device %p, \"%s\"\n", device, device->DeviceName); + TRACE("Created device %p, \"%s\"\n", device, device->DeviceName.c_str()); return device; } diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index bcc13a66..b3adfafa 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -681,8 +681,7 @@ ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name) snd_config_update_free_global(); ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - al_free(device->DeviceName); - device->DeviceName = alstrdup(name); + device->DeviceName = name; return ALC_NO_ERROR; } @@ -717,7 +716,7 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) break; } - bool allowmmap{!!GetConfigValueBool(device->DeviceName, "alsa", "mmap", 1)}; + bool allowmmap{!!GetConfigValueBool(device->DeviceName.c_str(), "alsa", "mmap", 1)}; ALuint periods{device->NumUpdates}; ALuint periodLen{static_cast(device->UpdateSize * U64(1000000) / device->Frequency)}; ALuint bufferLen{periodLen * periods}; @@ -788,7 +787,7 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) } CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder))); /* set rate (implicitly constrains period/buffer parameters) */ - if(!GetConfigValueBool(device->DeviceName, "alsa", "allow-resampler", 0) || + if(!GetConfigValueBool(device->DeviceName.c_str(), "alsa", "allow-resampler", 0) || !(device->Flags&DEVICE_FREQUENCY_REQUEST)) { if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0) @@ -1080,8 +1079,7 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) } } - al_free(device->DeviceName); - device->DeviceName = alstrdup(name); + device->DeviceName = name; return ALC_NO_ERROR; diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index a7d5445e..158331f1 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -143,8 +143,7 @@ static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCch return ALC_INVALID_VALUE; } - al_free(device->DeviceName); - device->DeviceName = alstrdup(name); + device->DeviceName = name; return ALC_NO_ERROR; } @@ -674,9 +673,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar ); if(!self->ring) goto error; - al_free(device->DeviceName); - device->DeviceName = alstrdup(name); - + device->DeviceName = name; return ALC_NO_ERROR; error: diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index b642dfea..6a8b0754 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -398,9 +398,7 @@ ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *deviceNam return ALC_INVALID_VALUE; } - al_free(device->DeviceName); - device->DeviceName = alstrdup(deviceName); - + device->DeviceName = deviceName; return ALC_NO_ERROR; } @@ -864,9 +862,7 @@ ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) self->BufferBytes = DSCBDescription.dwBufferBytes; SetDefaultWFXChannelOrder(device); - al_free(device->DeviceName); - device->DeviceName = alstrdup(deviceName); - + device->DeviceName = deviceName; return ALC_NO_ERROR; } diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index ed404a19..c72958e7 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -224,7 +224,7 @@ static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg) device->NumUpdates = 2; bufsize = device->UpdateSize; - if(ConfigValueUInt(device->DeviceName, "jack", "buffer-size", &bufsize)) + if(ConfigValueUInt(device->DeviceName.c_str(), "jack", "buffer-size", &bufsize)) bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize; @@ -368,9 +368,7 @@ static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name) jack_set_process_callback(self->Client, ALCjackPlayback_process, self); jack_set_buffer_size_callback(self->Client, ALCjackPlayback_bufferSizeNotify, self); - al_free(device->DeviceName); - device->DeviceName = alstrdup(name); - + device->DeviceName = name; return ALC_NO_ERROR; } @@ -395,7 +393,7 @@ static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) device->NumUpdates = 2; bufsize = device->UpdateSize; - if(ConfigValueUInt(device->DeviceName, "jack", "buffer-size", &bufsize)) + if(ConfigValueUInt(device->DeviceName.c_str(), "jack", "buffer-size", &bufsize)) bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize; diff --git a/Alc/backends/loopback.cpp b/Alc/backends/loopback.cpp index 843cb18e..5a6e14b5 100644 --- a/Alc/backends/loopback.cpp +++ b/Alc/backends/loopback.cpp @@ -64,8 +64,7 @@ ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - al_free(device->DeviceName); - device->DeviceName = alstrdup(name); + device->DeviceName = name; return ALC_NO_ERROR; } diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 7c27e22c..255aa01f 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -140,8 +140,7 @@ ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name) return ALC_INVALID_VALUE; device = STATIC_CAST(ALCbackend, self)->mDevice; - al_free(device->DeviceName); - device->DeviceName = alstrdup(name); + device->DeviceName = name; return ALC_NO_ERROR; } diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index e292dfe4..d0b1a7b1 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -375,9 +375,7 @@ static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *na return ALC_INVALID_VALUE; } - al_free(device->DeviceName); - device->DeviceName = alstrdup(name); - + device->DeviceName = name; return ALC_NO_ERROR; } @@ -901,9 +899,7 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name return ALC_INVALID_VALUE; } - al_free(device->DeviceName); - device->DeviceName = alstrdup(name); - + device->DeviceName = name; return ALC_NO_ERROR; } diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 38d1c40d..32ee1022 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -380,9 +380,7 @@ ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) return ALC_INVALID_VALUE; } - al_free(device->DeviceName); - device->DeviceName = alstrdup(name); - + device->DeviceName = name; return ALC_NO_ERROR; } @@ -712,9 +710,7 @@ ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) return ALC_OUT_OF_MEMORY; } - al_free(device->DeviceName); - device->DeviceName = alstrdup(name); - + device->DeviceName = name; return ALC_NO_ERROR; } diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index f8506baa..1a74250e 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -251,9 +251,7 @@ retry_open: return ALC_INVALID_VALUE; } - al_free(device->DeviceName); - device->DeviceName = alstrdup(name); - + device->DeviceName = name; return ALC_NO_ERROR; } @@ -443,9 +441,7 @@ ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) return ALC_INVALID_VALUE; } - al_free(device->DeviceName); - device->DeviceName = alstrdup(name); - + device->DeviceName = name; return ALC_NO_ERROR; } diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index bf98c757..d0c1c229 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -798,8 +798,7 @@ void PulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const pa_sink_i } ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; - al_free(device->DeviceName); - device->DeviceName = alstrdup(info->description); + device->DeviceName = info->description; } @@ -979,8 +978,7 @@ ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) else { ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; - al_free(device->DeviceName); - device->DeviceName = alstrdup(dev_name); + device->DeviceName = dev_name; } return ALC_NO_ERROR; @@ -1011,7 +1009,7 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE}; if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 0)) flags |= PA_STREAM_DONT_MOVE; - if(GetConfigValueBool(device->DeviceName, "pulse", "fix-rate", 0) || + if(GetConfigValueBool(device->DeviceName.c_str(), "pulse", "fix-rate", 0) || !(device->Flags&DEVICE_FREQUENCY_REQUEST)) flags |= PA_STREAM_FIX_RATE; @@ -1418,8 +1416,7 @@ void PulseCapture_sourceNameCallback(pa_context *UNUSED(context), const pa_sourc } ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; - al_free(device->DeviceName); - device->DeviceName = alstrdup(info->description); + device->DeviceName = info->description; } @@ -1491,8 +1488,7 @@ ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) if(iter == CaptureDevices.cend()) return ALC_INVALID_VALUE; pulse_name = iter->device_name.c_str(); - al_free(device->DeviceName); - device->DeviceName = alstrdup(iter->name.c_str()); + device->DeviceName = iter->name; } std::tie(self->loop, self->context) = pulse_open(PulseCapture_contextStateCallback, self); @@ -1595,7 +1591,7 @@ ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) pa_stream_set_state_callback(self->stream, PulseCapture_streamStateCallback, self); self->device_name = pa_stream_get_device_name(self->stream); - if(!device->DeviceName || device->DeviceName[0] == 0) + if(device->DeviceName.empty()) { pa_operation *op{pa_context_get_source_info_by_name(self->context, self->device_name.c_str(), PulseCapture_sourceNameCallback, self diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index e171fb92..6db480d9 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -326,8 +326,7 @@ static ALCenum qsa_open_playback(PlaybackWrapper *self, const ALCchar* deviceNam return ALC_INVALID_DEVICE; } - al_free(device->DeviceName); - device->DeviceName = alstrdup(deviceName); + device->DeviceName = deviceName; self->ExtraData = data; return ALC_NO_ERROR; @@ -734,8 +733,7 @@ static ALCenum qsa_open_capture(CaptureWrapper *self, const ALCchar *deviceName) return ALC_INVALID_DEVICE; } - al_free(device->DeviceName); - device->DeviceName = alstrdup(deviceName); + device->DeviceName = deviceName; self->ExtraData = data; switch (device->FmtType) diff --git a/Alc/backends/sdl2.cpp b/Alc/backends/sdl2.cpp index 2ef7d852..d643faa3 100644 --- a/Alc/backends/sdl2.cpp +++ b/Alc/backends/sdl2.cpp @@ -174,9 +174,7 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) self->FmtType = device->FmtType; self->UpdateSize = device->UpdateSize; - al_free(device->DeviceName); - device->DeviceName = alstrdup(name ? name : defaultDeviceName); - + device->DeviceName = name ? name : defaultDeviceName; return ALC_NO_ERROR; } diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index be6cd2e3..958bc2ff 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -148,9 +148,7 @@ static ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name) return ALC_INVALID_VALUE; } - al_free(device->DeviceName); - device->DeviceName = alstrdup(name); - + device->DeviceName = name; return ALC_NO_ERROR; } @@ -489,9 +487,7 @@ static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) SetDefaultChannelOrder(device); - al_free(device->DeviceName); - device->DeviceName = alstrdup(name); - + device->DeviceName = name; return ALC_NO_ERROR; } diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index d306a0c5..86120491 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -188,8 +188,7 @@ static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *na } device = STATIC_CAST(ALCbackend,self)->mDevice; - al_free(device->DeviceName); - device->DeviceName = alstrdup(name); + device->DeviceName = name; return ALC_NO_ERROR; } diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 76d5f1ef..751c56d8 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -716,8 +716,7 @@ ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *deviceNam { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; self->mDevId = iter->devid; - al_free(device->DeviceName); - device->DeviceName = alstrdup(iter->name.c_str()); + device->DeviceName = iter->name; hr = S_OK; } } @@ -773,12 +772,8 @@ HRESULT ALCwasapiPlayback::openProxy() if(SUCCEEDED(hr)) { mClient = reinterpret_cast(ptr); - if(!device->DeviceName || device->DeviceName[0] == 0) - { - std::string devname{get_device_name_and_guid(mMMDev).first}; - al_free(device->DeviceName); - device->DeviceName = alstrdup(devname.c_str()); - } + if(device->DeviceName.empty()) + device->DeviceName = get_device_name_and_guid(mMMDev).first; } if(FAILED(hr)) @@ -1383,8 +1378,7 @@ ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *deviceName) { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; self->mDevId = iter->devid; - al_free(device->DeviceName); - device->DeviceName = alstrdup(iter->name.c_str()); + device->DeviceName = iter->name; hr = S_OK; } } @@ -1459,12 +1453,8 @@ HRESULT ALCwasapiCapture::openProxy() if(SUCCEEDED(hr)) { mClient = reinterpret_cast(ptr); - if(!device->DeviceName || device->DeviceName[0] == 0) - { - std::string devname{get_device_name_and_guid(mMMDev).first}; - al_free(device->DeviceName); - device->DeviceName = alstrdup(devname.c_str()); - } + if(device->DeviceName.empty()) + device->DeviceName = get_device_name_and_guid(mMMDev).first; } if(FAILED(hr)) diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index af1fd768..3f8d8c97 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -240,8 +240,7 @@ ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name) } ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; - al_free(device->DeviceName); - device->DeviceName = alstrdup(name); + device->DeviceName = name; return ALC_NO_ERROR; } diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 8b97daab..9da3e4c3 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -285,8 +285,7 @@ retry_open: return ALC_INVALID_VALUE; } - al_free(device->DeviceName); - device->DeviceName = alstrdup(PlaybackDevices[DeviceID].c_str()); + device->DeviceName = PlaybackDevices[DeviceID]; return ALC_NO_ERROR; } @@ -606,8 +605,7 @@ ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName) self->WaveBuffer[i].dwBufferLength = self->WaveBuffer[i-1].dwBufferLength; } - al_free(device->DeviceName); - device->DeviceName = alstrdup(CaptureDevices[DeviceID].c_str()); + device->DeviceName = CaptureDevices[DeviceID]; return ALC_NO_ERROR; } diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 0d62e086..020d8237 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -379,7 +379,7 @@ static const ChannelMap MonoCfg[1] = { static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, const ALsizei *RESTRICT chans_per_order) { - const char *devname = device->DeviceName; + const char *devname = device->DeviceName.c_str(); ALsizei i; if(GetConfigValueBool(devname, "decoder", "nfc", 1) && ctrl_dist > 0.0f) @@ -399,7 +399,7 @@ static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei orde static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) { - const char *devname = device->DeviceName; + const char *devname = device->DeviceName.c_str(); ALfloat maxdist = 0.0f; size_t total = 0; ALsizei i; @@ -512,7 +512,7 @@ static void InitPanning(ALCdevice *device) if(device->FmtChans == DevFmtAmbi3D) { - const char *devname = device->DeviceName; + const char *devname = device->DeviceName.c_str(); const ALsizei *acnmap = (device->mAmbiLayout == AmbiLayout_FuMa) ? FuMa2ACN : ACN2ACN; const ALfloat *n3dscale = (device->mAmbiScale == AmbiNorm_FuMa) ? FuMa2N3DScale : (device->mAmbiScale == AmbiNorm_SN3D) ? SN3D2N3DScale : @@ -966,7 +966,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(hrtf_appreq == Hrtf_Enable) device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; - devname = device->DeviceName; + devname = device->DeviceName.c_str(); switch(device->FmtChans) { case DevFmtQuad: layout = "quad"; break; @@ -1072,7 +1072,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(device->Type != Loopback) { const char *mode; - if(ConfigValueStr(device->DeviceName, NULL, "stereo-mode", &mode)) + if(ConfigValueStr(device->DeviceName.c_str(), NULL, "stereo-mode", &mode)) { if(strcasecmp(mode, "headphones") == 0) headphones = true; @@ -1107,7 +1107,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(VECTOR_SIZE(device->HrtfList) == 0) { VECTOR_DEINIT(device->HrtfList); - device->HrtfList = EnumerateHrtf(device->DeviceName); + device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); } if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->HrtfList)) @@ -1143,7 +1143,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf old_hrtf = NULL; device->Render_Mode = HrtfRender; - if(ConfigValueStr(device->DeviceName, NULL, "hrtf-mode", &mode)) + if(ConfigValueStr(device->DeviceName.c_str(), NULL, "hrtf-mode", &mode)) { if(strcasecmp(mode, "full") == 0) device->Render_Mode = HrtfRender; @@ -1187,7 +1187,7 @@ no_hrtf: bs2blevel = ((headphones && hrtf_appreq != Hrtf_Disable) || (hrtf_appreq == Hrtf_Enable)) ? 5 : 0; if(device->Type != Loopback) - ConfigValueInt(device->DeviceName, NULL, "cf_level", &bs2blevel); + ConfigValueInt(device->DeviceName.c_str(), NULL, "cf_level", &bs2blevel); if(bs2blevel > 0 && bs2blevel <= 6) { device->Bs2b = reinterpret_cast(al_calloc(16, sizeof(*device->Bs2b))); @@ -1199,7 +1199,7 @@ no_hrtf: TRACE("BS2B disabled\n"); - if(ConfigValueStr(device->DeviceName, NULL, "stereo-encoding", &mode)) + if(ConfigValueStr(device->DeviceName.c_str(), NULL, "stereo-encoding", &mode)) { if(strcasecmp(mode, "uhj") == 0) device->Render_Mode = NormalRender; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index a81d3f3d..66a7cfa3 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -593,7 +593,7 @@ struct ALCdevice_struct { ALCenum LimiterState{ALC_DONT_CARE_SOFT}; - char *DeviceName{nullptr}; + std::string DeviceName; ATOMIC(ALCenum) LastError{ALC_NO_ERROR}; -- cgit v1.2.3 From 2c06ec709324b7aebdb71961a428362cfcafa68f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 19:19:35 -0800 Subject: Use a regular vector for the enumerated HRTF list --- Alc/alc.cpp | 25 ++++----- Alc/hrtf.cpp | 135 ++++++++++++++++++++++------------------------ Alc/hrtf.h | 13 ++--- Alc/panning.cpp | 21 ++++---- OpenAL32/Include/alMain.h | 3 +- 5 files changed, 86 insertions(+), 111 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index e2f562a1..bb51f6f0 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2035,17 +2035,14 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(hrtf_userreq == Hrtf_Enable || (hrtf_userreq != Hrtf_Disable && hrtf_appreq == Hrtf_Enable)) { struct Hrtf *hrtf = nullptr; - if(VECTOR_SIZE(device->HrtfList) == 0) - { - VECTOR_DEINIT(device->HrtfList); + if(device->HrtfList.empty()) device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); - } - if(VECTOR_SIZE(device->HrtfList) > 0) + if(!device->HrtfList.empty()) { - if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->HrtfList)) - hrtf = GetLoadedHrtf(VECTOR_ELEM(device->HrtfList, hrtf_id).hrtf); + if(hrtf_id >= 0 && (size_t)hrtf_id < device->HrtfList.size()) + hrtf = GetLoadedHrtf(device->HrtfList[hrtf_id].hrtf); else - hrtf = GetLoadedHrtf(VECTOR_ELEM(device->HrtfList, 0).hrtf); + hrtf = GetLoadedHrtf(device->HrtfList.front().hrtf); } if(hrtf) @@ -2391,8 +2388,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ALCdevice_struct::ALCdevice_struct(DeviceType type) : Type{type} { - VECTOR_INIT(HrtfList); - VECTOR_INIT(BufferList); almtx_init(&BufferLock, almtx_plain); @@ -2443,7 +2438,7 @@ ALCdevice_struct::~ALCdevice_struct() al_free(HrtfName); HrtfName = nullptr; - FreeHrtfList(&HrtfList); + FreeHrtfList(HrtfList); if(HrtfHandle) Hrtf_DecRef(HrtfHandle); HrtfHandle = nullptr; @@ -3371,9 +3366,9 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC case ALC_NUM_HRTF_SPECIFIERS_SOFT: almtx_lock(&device->BackendLock); - FreeHrtfList(&device->HrtfList); + FreeHrtfList(device->HrtfList); device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); - values[0] = (ALCint)VECTOR_SIZE(device->HrtfList); + values[0] = (ALCint)device->HrtfList.size(); almtx_unlock(&device->BackendLock); return 1; @@ -4466,8 +4461,8 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum else switch(paramName) { case ALC_HRTF_SPECIFIER_SOFT: - if(index >= 0 && (size_t)index < VECTOR_SIZE(device->HrtfList)) - str = VECTOR_ELEM(device->HrtfList, index).name; + if(index >= 0 && (size_t)index < device->HrtfList.size()) + str = device->HrtfList[index].name; else alcSetError(device, ALC_INVALID_VALUE); break; diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 783686d5..1305c347 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -944,7 +944,15 @@ struct Hrtf *LoadHrtf02(std::istream &data, const char *filename) } -void AddFileEntry(vector_EnumeratedHrtf *list, const std::string &filename) +static bool checkName(al::vector &list, const std::string &name) +{ + return std::find_if(list.cbegin(), list.cend(), + [&name](const EnumeratedHrtf &entry) + { return name == entry.name; } + ) != list.cend(); +} + +void AddFileEntry(al::vector &list, const std::string &filename) { /* Check if this file has already been loaded globally. */ HrtfEntry *loaded_entry{LoadedHrtfs}; @@ -952,12 +960,12 @@ void AddFileEntry(vector_EnumeratedHrtf *list, const std::string &filename) { if(filename == loaded_entry->filename) { - const EnumeratedHrtf *iter; /* Check if this entry has already been added to the list. */ -#define MATCH_ENTRY(i) (loaded_entry == (i)->hrtf) - VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_ENTRY); -#undef MATCH_ENTRY - if(iter != VECTOR_END(*list)) + auto iter = std::find_if(list.cbegin(), list.cend(), + [loaded_entry](const EnumeratedHrtf &entry) -> bool + { return loaded_entry == entry.hrtf; } + ); + if(iter != list.cend()) { TRACE("Skipping duplicate file entry %s\n", filename.c_str()); return; @@ -989,46 +997,38 @@ void AddFileEntry(vector_EnumeratedHrtf *list, const std::string &filename) size_t extpos{filename.find_last_of('.')}; if(extpos <= namepos) extpos = std::string::npos; - const EnumeratedHrtf *iter{}; - std::string newname; - int i{0}; - do { - if(extpos == std::string::npos) - newname = filename.substr(namepos); - else - newname = filename.substr(namepos, extpos-namepos); - if(i != 0) - { - newname += " #"; - newname += std::to_string(i+1); - } - ++i; - -#define MATCH_NAME(i) (newname == (i)->name) - VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_NAME); -#undef MATCH_NAME - } while(iter != VECTOR_END(*list)); - EnumeratedHrtf entry{ alstrdup(newname.c_str()), loaded_entry }; + const std::string basename{(extpos == std::string::npos) ? + filename.substr(namepos) : filename.substr(namepos, extpos-namepos)}; + std::string newname{basename}; + int count{1}; + while(checkName(list, newname)) + { + newname = basename; + newname += " #"; + newname += std::to_string(++count); + } + list.push_back(EnumeratedHrtf{alstrdup(newname.c_str()), loaded_entry}); + const EnumeratedHrtf &entry = list.back(); TRACE("Adding file entry \"%s\"\n", entry.name); - VECTOR_PUSH_BACK(*list, entry); } /* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer * for input instead of opening the given filename. */ -void AddBuiltInEntry(vector_EnumeratedHrtf *list, const std::string &filename, ALuint residx) +void AddBuiltInEntry(al::vector &list, const std::string &filename, ALuint residx) { HrtfEntry *loaded_entry{LoadedHrtfs}; while(loaded_entry) { if(filename == loaded_entry->filename) { - const EnumeratedHrtf *iter{}; -#define MATCH_ENTRY(i) (loaded_entry == (i)->hrtf) - VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_ENTRY); -#undef MATCH_ENTRY - if(iter != VECTOR_END(*list)) + /* Check if this entry has already been added to the list. */ + auto iter = std::find_if(list.cbegin(), list.cend(), + [loaded_entry](const EnumeratedHrtf &entry) -> bool + { return loaded_entry == entry.hrtf; } + ); + if(iter != list.cend()) { TRACE("Skipping duplicate file entry %s\n", filename.c_str()); return; @@ -1058,26 +1058,18 @@ void AddBuiltInEntry(vector_EnumeratedHrtf *list, const std::string &filename, A /* TODO: Get a human-readable name from the HRTF data (possibly coming in a * format update). */ - const EnumeratedHrtf *iter{}; - std::string newname; - int i{0}; - do { + std::string newname{filename}; + int count{1}; + while(checkName(list, newname)) + { newname = filename; - if(i != 0) - { - newname += " #"; - newname += std::to_string(i+1); - } - ++i; - -#define MATCH_NAME(i) (newname == (i)->name) - VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_NAME); -#undef MATCH_NAME - } while(iter != VECTOR_END(*list)); - EnumeratedHrtf entry{ alstrdup(newname.c_str()), loaded_entry }; + newname += " #"; + newname += std::to_string(++count); + } + list.push_back(EnumeratedHrtf{alstrdup(newname.c_str()), loaded_entry}); + const EnumeratedHrtf &entry = list.back(); TRACE("Adding built-in entry \"%s\"\n", entry.name); - VECTOR_PUSH_BACK(*list, entry); } @@ -1108,9 +1100,9 @@ ResData GetResource(int name) } // namespace -vector_EnumeratedHrtf EnumerateHrtf(const char *devname) +al::vector EnumerateHrtf(const char *devname) { - vector_EnumeratedHrtf list{VECTOR_INIT_STATIC()}; + al::vector list; bool usedefaults{true}; const char *pathlist{""}; @@ -1140,7 +1132,7 @@ vector_EnumeratedHrtf EnumerateHrtf(const char *devname) { const std::string pname{pathlist, end}; for(const auto &fname : SearchDataFiles(".mhr", pname.c_str())) - AddFileEntry(&list, fname); + AddFileEntry(list, fname); } pathlist = next; @@ -1152,45 +1144,44 @@ vector_EnumeratedHrtf EnumerateHrtf(const char *devname) if(usedefaults) { for(const auto &fname : SearchDataFiles(".mhr", "openal/hrtf")) - AddFileEntry(&list, fname); + AddFileEntry(list, fname); ResData res{GetResource(IDR_DEFAULT_44100_MHR)}; if(res.data != nullptr && res.size > 0) - AddBuiltInEntry(&list, "Built-In 44100hz", IDR_DEFAULT_44100_MHR); + AddBuiltInEntry(list, "Built-In 44100hz", IDR_DEFAULT_44100_MHR); res = GetResource(IDR_DEFAULT_48000_MHR); if(res.data != nullptr && res.size > 0) - AddBuiltInEntry(&list, "Built-In 48000hz", IDR_DEFAULT_48000_MHR); + AddBuiltInEntry(list, "Built-In 48000hz", IDR_DEFAULT_48000_MHR); } const char *defaulthrtf{""}; - if(VECTOR_SIZE(list) > 1 && ConfigValueStr(devname, nullptr, "default-hrtf", &defaulthrtf)) + if(!list.empty() && ConfigValueStr(devname, nullptr, "default-hrtf", &defaulthrtf)) { - const EnumeratedHrtf *iter{}; - /* Find the preferred HRTF and move it to the front of the list. */ -#define FIND_ENTRY(i) (strcmp((i)->name, defaulthrtf) == 0) - VECTOR_FIND_IF(iter, const EnumeratedHrtf, list, FIND_ENTRY); -#undef FIND_ENTRY - if(iter == VECTOR_END(list)) + auto iter = std::find_if(list.begin(), list.end(), + [defaulthrtf](const EnumeratedHrtf &entry) -> bool + { return strcmp(entry.name, defaulthrtf) == 0; } + ); + if(iter == list.end()) WARN("Failed to find default HRTF \"%s\"\n", defaulthrtf); - else if(iter != VECTOR_BEGIN(list)) + else if(iter != list.begin()) { EnumeratedHrtf entry{*iter}; - memmove(&VECTOR_ELEM(list,1), &VECTOR_ELEM(list,0), - (iter-VECTOR_BEGIN(list))*sizeof(EnumeratedHrtf)); - VECTOR_ELEM(list,0) = entry; + list.erase(iter); + list.insert(list.begin(), entry); } } return list; } -void FreeHrtfList(vector_EnumeratedHrtf *list) +void FreeHrtfList(al::vector &list) { -#define CLEAR_ENTRY(i) al_free((i)->name) - VECTOR_FOR_EACH(EnumeratedHrtf, *list, CLEAR_ENTRY); - VECTOR_DEINIT(*list); -#undef CLEAR_ENTRY + std::for_each(list.begin(), list.end(), + [](EnumeratedHrtf &entry) noexcept -> void + { al_free(entry.name); } + ); + list.clear(); } struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry) diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 71956691..a36e9738 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -6,12 +6,9 @@ #include "alMain.h" #include "atomic.h" +#include "vector.h" -#ifdef __cplusplus -extern "C" { -#endif - #define HRTF_HISTORY_BITS (6) #define HRTF_HISTORY_LENGTH (1< EnumerateHrtf(const char *devname); +void FreeHrtfList(al::vector &list); struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry); void Hrtf_IncRef(struct Hrtf *hrtf); void Hrtf_DecRef(struct Hrtf *hrtf); @@ -84,8 +81,4 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, */ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const struct AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_COEFFS], ALsizei AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain); -#ifdef __cplusplus -} // extern "C" -#endif - #endif /* ALC_HRTF_H */ diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 020d8237..d5c8bbdf 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -1104,33 +1104,30 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf device->HrtfStatus = ALC_HRTF_REQUIRED_SOFT; } - if(VECTOR_SIZE(device->HrtfList) == 0) - { - VECTOR_DEINIT(device->HrtfList); + if(device->HrtfList.empty()) device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); - } - if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->HrtfList)) + if(hrtf_id >= 0 && (size_t)hrtf_id < device->HrtfList.size()) { - const EnumeratedHrtf *entry = &VECTOR_ELEM(device->HrtfList, hrtf_id); - struct Hrtf *hrtf = GetLoadedHrtf(entry->hrtf); + const EnumeratedHrtf &entry = device->HrtfList[hrtf_id]; + struct Hrtf *hrtf = GetLoadedHrtf(entry.hrtf); if(hrtf && hrtf->sampleRate == device->Frequency) { device->HrtfHandle = hrtf; - device->HrtfName = alstrdup(entry->name); + device->HrtfName = alstrdup(entry.name); } else if(hrtf) Hrtf_DecRef(hrtf); } - for(i = 0;!device->HrtfHandle && i < VECTOR_SIZE(device->HrtfList);i++) + for(i = 0;!device->HrtfHandle && i < device->HrtfList.size();i++) { - const EnumeratedHrtf *entry = &VECTOR_ELEM(device->HrtfList, i); - struct Hrtf *hrtf = GetLoadedHrtf(entry->hrtf); + const EnumeratedHrtf &entry = device->HrtfList[i]; + struct Hrtf *hrtf = GetLoadedHrtf(entry.hrtf); if(hrtf && hrtf->sampleRate == device->Frequency) { device->HrtfHandle = hrtf; - device->HrtfName = alstrdup(entry->name); + device->HrtfName = alstrdup(entry.name); } else if(hrtf) Hrtf_DecRef(hrtf); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 66a7cfa3..11f9d7de 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -532,7 +532,6 @@ typedef struct EnumeratedHrtf { struct HrtfEntry *hrtf; } EnumeratedHrtf; -TYPEDEF_VECTOR(EnumeratedHrtf, vector_EnumeratedHrtf) /* Maximum delay in samples for speaker distance compensation. */ @@ -624,7 +623,7 @@ struct ALCdevice_struct { struct DirectHrtfState *Hrtf{nullptr}; char *HrtfName{nullptr}; struct Hrtf *HrtfHandle{nullptr}; - vector_EnumeratedHrtf HrtfList{}; + al::vector HrtfList; ALCenum HrtfStatus{ALC_FALSE}; /* UHJ encoder state */ -- cgit v1.2.3 From 140c139852de0bde537de0314e30239832f309f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 19:28:01 -0800 Subject: Use a standard string for the device's HRTF name --- Alc/alc.cpp | 4 +--- Alc/panning.cpp | 9 ++++----- OpenAL32/Include/alMain.h | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index bb51f6f0..805ba70c 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2436,8 +2436,6 @@ ALCdevice_struct::~ALCdevice_struct() VECTOR_DEINIT(FilterList); almtx_destroy(&FilterLock); - al_free(HrtfName); - HrtfName = nullptr; FreeHrtfList(HrtfList); if(HrtfHandle) Hrtf_DecRef(HrtfHandle); @@ -3049,7 +3047,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para else { almtx_lock(&Device->BackendLock); - value = ((Device->HrtfHandle && Device->HrtfName) ? Device->HrtfName : ""); + value = (Device->HrtfHandle ? Device->HrtfName.c_str() : ""); almtx_unlock(&Device->BackendLock); ALCdevice_DecRef(Device); } diff --git a/Alc/panning.cpp b/Alc/panning.cpp index d5c8bbdf..aface673 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -933,8 +933,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf al_free(device->Hrtf); device->Hrtf = NULL; device->HrtfHandle = NULL; - al_free(device->HrtfName); - device->HrtfName = NULL; + device->HrtfName.clear(); device->Render_Mode = NormalRender; memset(&device->Dry.Ambi, 0, sizeof(device->Dry.Ambi)); @@ -1114,7 +1113,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(hrtf && hrtf->sampleRate == device->Frequency) { device->HrtfHandle = hrtf; - device->HrtfName = alstrdup(entry.name); + device->HrtfName = entry.name; } else if(hrtf) Hrtf_DecRef(hrtf); @@ -1127,7 +1126,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(hrtf && hrtf->sampleRate == device->Frequency) { device->HrtfHandle = hrtf; - device->HrtfName = alstrdup(entry.name); + device->HrtfName = entry.name; } else if(hrtf) Hrtf_DecRef(hrtf); @@ -1164,7 +1163,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf } TRACE("%s HRTF rendering enabled, using \"%s\"\n", - ((device->Render_Mode == HrtfRender) ? "Full" : "Basic"), device->HrtfName + ((device->Render_Mode == HrtfRender) ? "Full" : "Basic"), device->HrtfName.c_str() ); InitHrtfPanning(device); return; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 11f9d7de..57ecd925 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -621,7 +621,7 @@ struct ALCdevice_struct { /* HRTF state and info */ struct DirectHrtfState *Hrtf{nullptr}; - char *HrtfName{nullptr}; + std::string HrtfName; struct Hrtf *HrtfHandle{nullptr}; al::vector HrtfList; ALCenum HrtfStatus{ALC_FALSE}; -- cgit v1.2.3 From e23796aabe21a065b3fde34e8023a60a4bcb7dc5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 21:18:19 -0800 Subject: Use a standard string for the enumerated HRTF names --- Alc/alc.cpp | 6 +++--- Alc/helpers.cpp | 9 --------- Alc/hrtf.cpp | 19 +++++-------------- Alc/hrtf.h | 1 - OpenAL32/Include/alMain.h | 4 +--- 5 files changed, 9 insertions(+), 30 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 805ba70c..f4a64199 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2436,7 +2436,7 @@ ALCdevice_struct::~ALCdevice_struct() VECTOR_DEINIT(FilterList); almtx_destroy(&FilterLock); - FreeHrtfList(HrtfList); + HrtfList.clear(); if(HrtfHandle) Hrtf_DecRef(HrtfHandle); HrtfHandle = nullptr; @@ -3364,7 +3364,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC case ALC_NUM_HRTF_SPECIFIERS_SOFT: almtx_lock(&device->BackendLock); - FreeHrtfList(device->HrtfList); + device->HrtfList.clear(); device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); values[0] = (ALCint)device->HrtfList.size(); almtx_unlock(&device->BackendLock); @@ -4460,7 +4460,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum { case ALC_HRTF_SPECIFIER_SOFT: if(index >= 0 && (size_t)index < device->HrtfList.size()) - str = device->HrtfList[index].name; + str = device->HrtfList[index].name.c_str(); else alcSetError(device, ALC_INVALID_VALUE); break; diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index d31101f7..a78e3d83 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -726,12 +726,3 @@ void SetRTPriority(void) } #endif - - -char *alstrdup(const char *str) -{ - const size_t len{strlen(str)}; - char *ret{static_cast(al_calloc(DEF_ALIGN, len+1))}; - memcpy(ret, str, len); - return ret; -} diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 1305c347..89b80074 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -1007,10 +1007,10 @@ void AddFileEntry(al::vector &list, const std::string &filename) newname += " #"; newname += std::to_string(++count); } - list.push_back(EnumeratedHrtf{alstrdup(newname.c_str()), loaded_entry}); + list.emplace_back(EnumeratedHrtf{newname, loaded_entry}); const EnumeratedHrtf &entry = list.back(); - TRACE("Adding file entry \"%s\"\n", entry.name); + TRACE("Adding file entry \"%s\"\n", entry.name.c_str()); } /* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer @@ -1066,10 +1066,10 @@ void AddBuiltInEntry(al::vector &list, const std::string &filena newname += " #"; newname += std::to_string(++count); } - list.push_back(EnumeratedHrtf{alstrdup(newname.c_str()), loaded_entry}); + list.emplace_back(EnumeratedHrtf{newname, loaded_entry}); const EnumeratedHrtf &entry = list.back(); - TRACE("Adding built-in entry \"%s\"\n", entry.name); + TRACE("Adding built-in entry \"%s\"\n", entry.name.c_str()); } @@ -1160,7 +1160,7 @@ al::vector EnumerateHrtf(const char *devname) { auto iter = std::find_if(list.begin(), list.end(), [defaulthrtf](const EnumeratedHrtf &entry) -> bool - { return strcmp(entry.name, defaulthrtf) == 0; } + { return entry.name == defaulthrtf; } ); if(iter == list.end()) WARN("Failed to find default HRTF \"%s\"\n", defaulthrtf); @@ -1175,15 +1175,6 @@ al::vector EnumerateHrtf(const char *devname) return list; } -void FreeHrtfList(al::vector &list) -{ - std::for_each(list.begin(), list.end(), - [](EnumeratedHrtf &entry) noexcept -> void - { al_free(entry.name); } - ); - list.clear(); -} - struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry) { std::lock_guard _{LoadedHrtfLock}; diff --git a/Alc/hrtf.h b/Alc/hrtf.h index a36e9738..a74df749 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -66,7 +66,6 @@ struct AngularPoint { void FreeHrtfs(void); al::vector EnumerateHrtf(const char *devname); -void FreeHrtfList(al::vector &list); struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry); void Hrtf_IncRef(struct Hrtf *hrtf); void Hrtf_DecRef(struct Hrtf *hrtf); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 57ecd925..e0d1462b 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -528,7 +528,7 @@ TYPEDEF_VECTOR(FilterSubList, vector_FilterSubList) typedef struct EnumeratedHrtf { - char *name; + std::string name; struct HrtfEntry *hrtf; } EnumeratedHrtf; @@ -805,8 +805,6 @@ inline void UnlockFilterList(ALCdevice *device) { almtx_unlock(&device->FilterLo void StartEventThrd(ALCcontext *ctx); void StopEventThrd(ALCcontext *ctx); -char *alstrdup(const char *str); - std::vector SearchDataFiles(const char *match, const char *subdir); -- cgit v1.2.3 From becbaab2dc4cf39fc3c0f64f352a76aee6d8e26c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 22:14:44 -0800 Subject: Remove some unnecessary static specifiers --- Alc/hrtf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 89b80074..0393da65 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -639,7 +639,7 @@ struct Hrtf *LoadHrtf00(std::istream &data, const char *filename) &reinterpret_cast(delays[0]), filename); } -static struct Hrtf *LoadHrtf01(std::istream &data, const char *filename) +struct Hrtf *LoadHrtf01(std::istream &data, const char *filename) { ALuint rate{GetLE_ALuint(data)}; ALushort irSize{GetLE_ALubyte(data)}; @@ -944,7 +944,7 @@ struct Hrtf *LoadHrtf02(std::istream &data, const char *filename) } -static bool checkName(al::vector &list, const std::string &name) +bool checkName(al::vector &list, const std::string &name) { return std::find_if(list.cbegin(), list.cend(), [&name](const EnumeratedHrtf &entry) -- cgit v1.2.3 From 81aed2ea01904c73156ade21faa5f12806685f72 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 22:31:51 -0800 Subject: Use a normal vector for buffer sublists --- Alc/alc.cpp | 10 ++++---- OpenAL32/Include/alMain.h | 7 +++--- OpenAL32/alBuffer.cpp | 63 ++++++++++++++++++++++------------------------- OpenAL32/alSource.cpp | 13 +++++----- 4 files changed, 44 insertions(+), 49 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index f4a64199..ae9a6e92 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2388,7 +2388,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ALCdevice_struct::ALCdevice_struct(DeviceType type) : Type{type} { - VECTOR_INIT(BufferList); almtx_init(&BufferLock, almtx_plain); VECTOR_INIT(EffectList); @@ -2416,10 +2415,11 @@ ALCdevice_struct::~ALCdevice_struct() almtx_destroy(&BackendLock); ReleaseALBuffers(this); -#define FREE_BUFFERSUBLIST(x) al_free((x)->Buffers) - VECTOR_FOR_EACH(BufferSubList, BufferList, FREE_BUFFERSUBLIST); -#undef FREE_BUFFERSUBLIST - VECTOR_DEINIT(BufferList); + std::for_each(BufferList.begin(), BufferList.end(), + [](BufferSubList &entry) noexcept -> void + { al_free(entry.Buffers); } + ); + BufferList.clear(); almtx_destroy(&BufferLock); ReleaseALEffects(this); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index e0d1462b..38c0471b 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -509,10 +509,9 @@ typedef union AmbiConfig { typedef struct BufferSubList { - ALuint64 FreeMask; - struct ALbuffer *Buffers; /* 64 */ + ALuint64 FreeMask{0u}; + struct ALbuffer *Buffers{nullptr}; /* 64 */ } BufferSubList; -TYPEDEF_VECTOR(BufferSubList, vector_BufferSubList) typedef struct EffectSubList { ALuint64 FreeMask; @@ -606,7 +605,7 @@ struct ALCdevice_struct { ALsizei NumAuxSends{}; // Map of Buffers for this device - vector_BufferSubList BufferList{}; + al::vector BufferList; almtx_t BufferLock; // Map of Effects for this device diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index 27e3ddd1..cd173193 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -55,40 +55,37 @@ ALbuffer *AllocBuffer(ALCcontext *context) ALCdevice *device = context->Device; std::unique_lock buflock{device->BufferLock}; + auto sublist = std::find_if(device->BufferList.begin(), device->BufferList.end(), + [](const BufferSubList &entry) noexcept -> bool + { return entry.FreeMask != 0; } + ); + + auto lidx = std::distance(device->BufferList.begin(), sublist); ALbuffer *buffer{nullptr}; - ALsizei lidx{0}, slidx{0}; - BufferSubList *sublist{VECTOR_BEGIN(device->BufferList)}; - BufferSubList *subend{VECTOR_END(device->BufferList)}; - for(;sublist != subend;++sublist) + ALsizei slidx{0}; + if(LIKELY(sublist != device->BufferList.end())) { - if(sublist->FreeMask) - { - slidx = CTZ64(sublist->FreeMask); - buffer = sublist->Buffers + slidx; - break; - } - ++lidx; + slidx = CTZ64(sublist->FreeMask); + buffer = sublist->Buffers + slidx; } - if(UNLIKELY(!buffer)) + else { - static constexpr BufferSubList empty_sublist{ 0, nullptr }; /* Don't allocate so many list entries that the 32-bit ID could * overflow... */ - if(UNLIKELY(VECTOR_SIZE(device->BufferList) >= 1<<25)) + if(UNLIKELY(device->BufferList.size() >= 1<<25)) { buflock.unlock(); alSetError(context, AL_OUT_OF_MEMORY, "Too many buffers allocated"); return nullptr; } - lidx = (ALsizei)VECTOR_SIZE(device->BufferList); - VECTOR_PUSH_BACK(device->BufferList, empty_sublist); - sublist = &VECTOR_BACK(device->BufferList); + device->BufferList.emplace_back(); + sublist = device->BufferList.end() - 1; sublist->FreeMask = ~U64(0); sublist->Buffers = reinterpret_cast(al_calloc(16, sizeof(ALbuffer)*64)); if(UNLIKELY(!sublist->Buffers)) { - VECTOR_POP_BACK(device->BufferList); + device->BufferList.pop_back(); buflock.unlock(); alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate buffer batch"); return nullptr; @@ -98,8 +95,7 @@ ALbuffer *AllocBuffer(ALCcontext *context) buffer = sublist->Buffers + slidx; } - memset(buffer, 0, sizeof(*buffer)); - + buffer = new (buffer) ALbuffer{}; /* Add 1 to avoid buffer ID 0. */ buffer->id = ((lidx<<6) | slidx) + 1; @@ -115,9 +111,10 @@ void FreeBuffer(ALCdevice *device, ALbuffer *buffer) ALsizei slidx = id & 0x3f; al_free(buffer->data); - memset(buffer, 0, sizeof(*buffer)); + buffer->data = nullptr; + buffer->~ALbuffer(); - VECTOR_ELEM(device->BufferList, lidx).FreeMask |= U64(1) << slidx; + device->BufferList[lidx].FreeMask |= U64(1) << slidx; } inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) @@ -125,12 +122,12 @@ inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; - if(UNLIKELY(lidx >= VECTOR_SIZE(device->BufferList))) + if(UNLIKELY(lidx >= device->BufferList.size())) return nullptr; - BufferSubList *sublist{&VECTOR_ELEM(device->BufferList, lidx)}; - if(UNLIKELY(sublist->FreeMask & (U64(1)<BufferList[lidx]; + if(UNLIKELY(sublist.FreeMask & (U64(1)<Buffers + slidx; + return sublist.Buffers + slidx; } @@ -1187,24 +1184,24 @@ ALsizei ChannelsFromFmt(FmtChannels chans) */ ALvoid ReleaseALBuffers(ALCdevice *device) { - BufferSubList *sublist = VECTOR_BEGIN(device->BufferList); - BufferSubList *subend = VECTOR_END(device->BufferList); size_t leftover = 0; - for(;sublist != subend;++sublist) + for(auto &sublist : device->BufferList) { - ALuint64 usemask = ~sublist->FreeMask; + ALuint64 usemask = ~sublist.FreeMask; while(usemask) { ALsizei idx = CTZ64(usemask); - ALbuffer *buffer = sublist->Buffers + idx; + ALbuffer *buffer = sublist.Buffers + idx; al_free(buffer->data); - memset(buffer, 0, sizeof(*buffer)); + buffer->data = nullptr; + buffer->~ALbuffer(); + ++leftover; usemask &= ~(U64(1) << idx); } - sublist->FreeMask = ~usemask; + sublist.FreeMask = ~usemask; } if(leftover > 0) WARN("(%p) Deleted " SZFMT " Buffer%s\n", device, leftover, (leftover==1)?"":"s"); diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 8b08728a..33aedb09 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -76,16 +76,15 @@ static inline ALsource *LookupSource(ALCcontext *context, ALuint id) static inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) { - BufferSubList *sublist; ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; - if(UNLIKELY(lidx >= VECTOR_SIZE(device->BufferList))) - return NULL; - sublist = &VECTOR_ELEM(device->BufferList, lidx); - if(UNLIKELY(sublist->FreeMask & (U64(1)<Buffers + slidx; + if(UNLIKELY(lidx >= device->BufferList.size())) + return nullptr; + BufferSubList &sublist = device->BufferList[lidx]; + if(UNLIKELY(sublist.FreeMask & (U64(1)< Date: Sun, 18 Nov 2018 22:45:55 -0800 Subject: Use a normal vector for effect sublists --- Alc/alc.cpp | 10 +++--- OpenAL32/Include/alMain.h | 7 ++--- OpenAL32/alAuxEffectSlot.cpp | 9 +++--- OpenAL32/alEffect.cpp | 72 ++++++++++++++++++++------------------------ 4 files changed, 45 insertions(+), 53 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index ae9a6e92..56e500d4 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2390,7 +2390,6 @@ ALCdevice_struct::ALCdevice_struct(DeviceType type) { almtx_init(&BufferLock, almtx_plain); - VECTOR_INIT(EffectList); almtx_init(&EffectLock, almtx_plain); VECTOR_INIT(FilterList); @@ -2423,10 +2422,11 @@ ALCdevice_struct::~ALCdevice_struct() almtx_destroy(&BufferLock); ReleaseALEffects(this); -#define FREE_EFFECTSUBLIST(x) al_free((x)->Effects) - VECTOR_FOR_EACH(EffectSubList, EffectList, FREE_EFFECTSUBLIST); -#undef FREE_EFFECTSUBLIST - VECTOR_DEINIT(EffectList); + std::for_each(EffectList.begin(), EffectList.end(), + [](EffectSubList &entry) noexcept -> void + { al_free(entry.Effects); } + ); + EffectList.clear(); almtx_destroy(&EffectLock); ReleaseALFilters(this); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 38c0471b..8a85f141 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -514,10 +514,9 @@ typedef struct BufferSubList { } BufferSubList; typedef struct EffectSubList { - ALuint64 FreeMask; - struct ALeffect *Effects; /* 64 */ + ALuint64 FreeMask{0u}; + struct ALeffect *Effects{nullptr}; /* 64 */ } EffectSubList; -TYPEDEF_VECTOR(EffectSubList, vector_EffectSubList) typedef struct FilterSubList { ALuint64 FreeMask; @@ -609,7 +608,7 @@ struct ALCdevice_struct { almtx_t BufferLock; // Map of Effects for this device - vector_EffectSubList EffectList{}; + al::vector EffectList; almtx_t EffectLock; // Map of Filters for this device diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index 6a0cc34c..fc4b4d1b 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -87,16 +87,15 @@ static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) { - EffectSubList *sublist; ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; - if(UNLIKELY(lidx >= VECTOR_SIZE(device->EffectList))) + if(UNLIKELY(lidx >= device->EffectList.size())) return nullptr; - sublist = &VECTOR_ELEM(device->EffectList, lidx); - if(UNLIKELY(sublist->FreeMask & (U64(1)<EffectList[lidx]; + if(UNLIKELY(sublist.FreeMask & (U64(1)<Effects + slidx; + return sublist.Effects + slidx; } diff --git a/OpenAL32/alEffect.cpp b/OpenAL32/alEffect.cpp index 4f25b5f4..54cfad67 100644 --- a/OpenAL32/alEffect.cpp +++ b/OpenAL32/alEffect.cpp @@ -24,6 +24,8 @@ #include #include +#include + #include "AL/al.h" #include "AL/alc.h" @@ -58,16 +60,15 @@ static void InitEffectParams(ALeffect *effect, ALenum type); static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) { - EffectSubList *sublist; ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; - if(UNLIKELY(lidx >= VECTOR_SIZE(device->EffectList))) - return NULL; - sublist = &VECTOR_ELEM(device->EffectList, lidx); - if(UNLIKELY(sublist->FreeMask & (U64(1)<Effects + slidx; + if(UNLIKELY(lidx >= device->EffectList.size())) + return nullptr; + EffectSubList &sublist = device->EffectList[lidx]; + if(UNLIKELY(sublist.FreeMask & (U64(1)<Device; - EffectSubList *sublist, *subend; - ALeffect *effect = NULL; - ALsizei lidx = 0; - ALsizei slidx; - almtx_lock(&device->EffectLock); - sublist = VECTOR_BEGIN(device->EffectList); - subend = VECTOR_END(device->EffectList); - for(;sublist != subend;++sublist) + + auto sublist = std::find_if(device->EffectList.begin(), device->EffectList.end(), + [](const EffectSubList &entry) noexcept -> bool + { return entry.FreeMask != 0; } + ); + + auto lidx = std::distance(device->EffectList.begin(), sublist); + ALeffect *effect{nullptr}; + ALsizei slidx{0}; + if(LIKELY(sublist != device->EffectList.end())) { - if(sublist->FreeMask) - { - slidx = CTZ64(sublist->FreeMask); - effect = sublist->Effects + slidx; - break; - } - ++lidx; + slidx = CTZ64(sublist->FreeMask); + effect = sublist->Effects + slidx; } - if(UNLIKELY(!effect)) + else { - const EffectSubList empty_sublist = { 0, NULL }; /* Don't allocate so many list entries that the 32-bit ID could * overflow... */ - if(UNLIKELY(VECTOR_SIZE(device->EffectList) >= 1<<25)) + if(UNLIKELY(device->EffectList.size() >= 1<<25)) { almtx_unlock(&device->EffectLock); alSetError(context, AL_OUT_OF_MEMORY, "Too many effects allocated"); return NULL; } - lidx = (ALsizei)VECTOR_SIZE(device->EffectList); - VECTOR_PUSH_BACK(device->EffectList, empty_sublist); - sublist = &VECTOR_BACK(device->EffectList); + device->EffectList.emplace_back(); + sublist = device->EffectList.end() - 1; sublist->FreeMask = ~U64(0); sublist->Effects = static_cast(al_calloc(16, sizeof(ALeffect)*64)); if(UNLIKELY(!sublist->Effects)) { - VECTOR_POP_BACK(device->EffectList); + device->EffectList.pop_back(); almtx_unlock(&device->EffectLock); alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect batch"); return NULL; @@ -421,7 +417,7 @@ static ALeffect *AllocEffect(ALCcontext *context) effect = sublist->Effects + slidx; } - memset(effect, 0, sizeof(*effect)); + effect = new (effect) ALeffect{}; InitEffectParams(effect, AL_EFFECT_NULL); /* Add 1 to avoid effect ID 0. */ @@ -439,30 +435,28 @@ static void FreeEffect(ALCdevice *device, ALeffect *effect) ALsizei lidx = id >> 6; ALsizei slidx = id & 0x3f; - memset(effect, 0, sizeof(*effect)); + effect->~ALeffect(); - VECTOR_ELEM(device->EffectList, lidx).FreeMask |= U64(1) << slidx; + device->EffectList[lidx].FreeMask |= U64(1) << slidx; } void ReleaseALEffects(ALCdevice *device) { - EffectSubList *sublist = VECTOR_BEGIN(device->EffectList); - EffectSubList *subend = VECTOR_END(device->EffectList); size_t leftover = 0; - for(;sublist != subend;++sublist) + for(auto &sublist : device->EffectList) { - ALuint64 usemask = ~sublist->FreeMask; + ALuint64 usemask = ~sublist.FreeMask; while(usemask) { ALsizei idx = CTZ64(usemask); - ALeffect *effect = sublist->Effects + idx; + ALeffect *effect = sublist.Effects + idx; - memset(effect, 0, sizeof(*effect)); + effect->~ALeffect(); ++leftover; usemask &= ~(U64(1) << idx); } - sublist->FreeMask = ~usemask; + sublist.FreeMask = ~usemask; } if(leftover > 0) WARN("(%p) Deleted " SZFMT " Effect%s\n", device, leftover, (leftover==1)?"":"s"); -- cgit v1.2.3 From e0d0faaa634b5e3f14f0a3c477aba4dbf78683fb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 23:02:31 -0800 Subject: Use a normal vector for filter sublists --- Alc/alc.cpp | 12 ++++---- OpenAL32/Include/alMain.h | 7 ++--- OpenAL32/alFilter.cpp | 72 ++++++++++++++++++++++------------------------- OpenAL32/alSource.cpp | 13 ++++----- 4 files changed, 47 insertions(+), 57 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 56e500d4..24783510 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2389,10 +2389,7 @@ ALCdevice_struct::ALCdevice_struct(DeviceType type) : Type{type} { almtx_init(&BufferLock, almtx_plain); - almtx_init(&EffectLock, almtx_plain); - - VECTOR_INIT(FilterList); almtx_init(&FilterLock, almtx_plain); almtx_init(&BackendLock, almtx_plain); @@ -2430,10 +2427,11 @@ ALCdevice_struct::~ALCdevice_struct() almtx_destroy(&EffectLock); ReleaseALFilters(this); -#define FREE_FILTERSUBLIST(x) al_free((x)->Filters) - VECTOR_FOR_EACH(FilterSubList, FilterList, FREE_FILTERSUBLIST); -#undef FREE_FILTERSUBLIST - VECTOR_DEINIT(FilterList); + std::for_each(FilterList.begin(), FilterList.end(), + [](FilterSubList &entry) noexcept -> void + { al_free(entry.Filters); } + ); + FilterList.clear(); almtx_destroy(&FilterLock); HrtfList.clear(); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 8a85f141..226d39a9 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -519,10 +519,9 @@ typedef struct EffectSubList { } EffectSubList; typedef struct FilterSubList { - ALuint64 FreeMask; - struct ALfilter *Filters; /* 64 */ + ALuint64 FreeMask{0u}; + struct ALfilter *Filters{nullptr}; /* 64 */ } FilterSubList; -TYPEDEF_VECTOR(FilterSubList, vector_FilterSubList) typedef struct EnumeratedHrtf { @@ -612,7 +611,7 @@ struct ALCdevice_struct { almtx_t EffectLock; // Map of Filters for this device - vector_FilterSubList FilterList{}; + al::vector FilterList; almtx_t FilterLock; POSTPROCESS PostProcess{}; diff --git a/OpenAL32/alFilter.cpp b/OpenAL32/alFilter.cpp index 3c78cebf..b22729a2 100644 --- a/OpenAL32/alFilter.cpp +++ b/OpenAL32/alFilter.cpp @@ -22,6 +22,8 @@ #include +#include + #include "alMain.h" #include "alcontext.h" #include "alu.h" @@ -38,16 +40,15 @@ static void InitFilterParams(ALfilter *filter, ALenum type); static inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) { - FilterSubList *sublist; ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; - if(UNLIKELY(lidx >= VECTOR_SIZE(device->FilterList))) - return NULL; - sublist = &VECTOR_ELEM(device->FilterList, lidx); - if(UNLIKELY(sublist->FreeMask & (U64(1)<Filters + slidx; + if(UNLIKELY(lidx >= device->FilterList.size())) + return nullptr; + FilterSubList &sublist = device->FilterList[lidx]; + if(UNLIKELY(sublist.FreeMask & (U64(1)<Device; - FilterSubList *sublist, *subend; - ALfilter *filter = NULL; - ALsizei lidx = 0; - ALsizei slidx; - almtx_lock(&device->FilterLock); - sublist = VECTOR_BEGIN(device->FilterList); - subend = VECTOR_END(device->FilterList); - for(;sublist != subend;++sublist) + + auto sublist = std::find_if(device->FilterList.begin(), device->FilterList.end(), + [](const FilterSubList &entry) noexcept -> bool + { return entry.FreeMask != 0; } + ); + + auto lidx = std::distance(device->FilterList.begin(), sublist); + ALfilter *filter{nullptr}; + ALsizei slidx{0}; + if(LIKELY(sublist != device->FilterList.end())) { - if(sublist->FreeMask) - { - slidx = CTZ64(sublist->FreeMask); - filter = sublist->Filters + slidx; - break; - } - ++lidx; + slidx = CTZ64(sublist->FreeMask); + filter = sublist->Filters + slidx; } - if(UNLIKELY(!filter)) + else { - const FilterSubList empty_sublist = { 0, NULL }; /* Don't allocate so many list entries that the 32-bit ID could * overflow... */ - if(UNLIKELY(VECTOR_SIZE(device->FilterList) >= 1<<25)) + if(UNLIKELY(device->FilterList.size() >= 1<<25)) { almtx_unlock(&device->FilterLock); alSetError(context, AL_OUT_OF_MEMORY, "Too many filters allocated"); return NULL; } - lidx = (ALsizei)VECTOR_SIZE(device->FilterList); - VECTOR_PUSH_BACK(device->FilterList, empty_sublist); - sublist = &VECTOR_BACK(device->FilterList); + device->FilterList.emplace_back(); + sublist = device->FilterList.end() - 1; sublist->FreeMask = ~U64(0); sublist->Filters = static_cast(al_calloc(16, sizeof(ALfilter)*64)); if(UNLIKELY(!sublist->Filters)) { - VECTOR_POP_BACK(device->FilterList); + device->FilterList.pop_back(); almtx_unlock(&device->FilterLock); alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate filter batch"); return NULL; @@ -579,7 +575,7 @@ static ALfilter *AllocFilter(ALCcontext *context) filter = sublist->Filters + slidx; } - memset(filter, 0, sizeof(*filter)); + filter = new (filter) ALfilter{}; InitFilterParams(filter, AL_FILTER_NULL); /* Add 1 to avoid filter ID 0. */ @@ -597,30 +593,28 @@ static void FreeFilter(ALCdevice *device, ALfilter *filter) ALsizei lidx = id >> 6; ALsizei slidx = id & 0x3f; - memset(filter, 0, sizeof(*filter)); + filter->~ALfilter(); - VECTOR_ELEM(device->FilterList, lidx).FreeMask |= U64(1) << slidx; + device->FilterList[lidx].FreeMask |= U64(1) << slidx; } void ReleaseALFilters(ALCdevice *device) { - FilterSubList *sublist = VECTOR_BEGIN(device->FilterList); - FilterSubList *subend = VECTOR_END(device->FilterList); size_t leftover = 0; - for(;sublist != subend;++sublist) + for(auto &sublist : device->FilterList) { - ALuint64 usemask = ~sublist->FreeMask; + ALuint64 usemask = ~sublist.FreeMask; while(usemask) { ALsizei idx = CTZ64(usemask); - ALfilter *filter = sublist->Filters + idx; + ALfilter *filter = sublist.Filters + idx; - memset(filter, 0, sizeof(*filter)); + filter->~ALfilter(); ++leftover; usemask &= ~(U64(1) << idx); } - sublist->FreeMask = ~usemask; + sublist.FreeMask = ~usemask; } if(leftover > 0) WARN("(%p) Deleted " SZFMT " Filter%s\n", device, leftover, (leftover==1)?"":"s"); diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 33aedb09..2fe81320 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -89,16 +89,15 @@ static inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) static inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) { - FilterSubList *sublist; ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; - if(UNLIKELY(lidx >= VECTOR_SIZE(device->FilterList))) - return NULL; - sublist = &VECTOR_ELEM(device->FilterList, lidx); - if(UNLIKELY(sublist->FreeMask & (U64(1)<Filters + slidx; + if(UNLIKELY(lidx >= device->FilterList.size())) + return nullptr; + FilterSubList &sublist = device->FilterList[lidx]; + if(UNLIKELY(sublist.FreeMask & (U64(1)< Date: Sun, 18 Nov 2018 23:23:12 -0800 Subject: Use a normal vector in the QSA backend --- Alc/backends/qsa.cpp | 87 +++++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 42 deletions(-) diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index 6db480d9..9803d77d 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -27,14 +27,17 @@ #include #include #include -#include -#include -#include + +#include #include "alMain.h" #include "alu.h" #include "threads.h" +#include +#include +#include + namespace { @@ -57,10 +60,9 @@ struct DevMap { int card; int dev; }; -TYPEDEF_VECTOR(DevMap, vector_DevMap) -vector_DevMap DeviceNameMap; -vector_DevMap CaptureNameMap; +al::vector DeviceNameMap; +al::vector CaptureNameMap; constexpr ALCchar qsaDevice[] = "QSA Default"; @@ -108,7 +110,7 @@ constexpr struct { {0}, }; -void deviceList(int type, vector_DevMap *devmap) +void deviceList(int type, al::vector *devmap) { snd_ctl_t* handle; snd_pcm_info_t pcminfo; @@ -121,15 +123,16 @@ void deviceList(int type, vector_DevMap *devmap) if(max_cards < 0) return; -#define FREE_NAME(iter) free((iter)->name) - VECTOR_FOR_EACH(DevMap, *devmap, FREE_NAME); -#undef FREE_NAME - VECTOR_RESIZE(*devmap, 0, max_cards+1); + std::for_each(devmap->begin(), devmap->end(), + [](const DevMap &entry) -> void + { free(entry.name); } + ); + devmap->clear(); entry.name = strdup(qsaDevice); entry.card = 0; entry.dev = 0; - VECTOR_PUSH_BACK(*devmap, entry); + devmap->push_back(entry); for(card = 0;card < max_cards;card++) { @@ -155,7 +158,7 @@ void deviceList(int type, vector_DevMap *devmap) entry.card = card; entry.dev = dev; - VECTOR_PUSH_BACK(*devmap, entry); + devmap->push_back(entry); TRACE("Got device \"%s\", card %d, dev %d\n", name, card, dev); } } @@ -295,15 +298,14 @@ static ALCenum qsa_open_playback(PlaybackWrapper *self, const ALCchar* deviceNam status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_PLAYBACK); else { - const DevMap *iter; - - if(VECTOR_SIZE(DeviceNameMap) == 0) + if(DeviceNameMap.empty()) deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap); -#define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0) - VECTOR_FIND_IF(iter, const DevMap, DeviceNameMap, MATCH_DEVNAME); -#undef MATCH_DEVNAME - if(iter == VECTOR_END(DeviceNameMap)) + auto iter = std::find_if(DeviceNameMap.begin(), DeviceNameMap.end(), + [deviceName](const DevMap &entry) -> bool + { return entry.name && strcmp(deviceName, entry.name) == 0; } + ); + if(iter == DeviceNameMap.cend()) { free(data); return ALC_INVALID_DEVICE; @@ -702,15 +704,14 @@ static ALCenum qsa_open_capture(CaptureWrapper *self, const ALCchar *deviceName) status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_CAPTURE); else { - const DevMap *iter; - - if(VECTOR_SIZE(CaptureNameMap) == 0) + if(CaptureNameMap.empty()) deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap); -#define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0) - VECTOR_FIND_IF(iter, const DevMap, CaptureNameMap, MATCH_DEVNAME); -#undef MATCH_DEVNAME - if(iter == VECTOR_END(CaptureNameMap)) + auto iter = std::find_if(CaptureNameMap.cbegin(), CaptureNameMap.cend(), + [deviceName](const DevMap &entry) -> bool + { return entry.name && strcmp(deviceName, entry.name) == 0; } + ); + if(iter == CaptureNameMap.cend()) { free(data); return ALC_INVALID_DEVICE; @@ -995,13 +996,15 @@ bool QSABackendFactory::init() void QSABackendFactory::deinit() { -#define FREE_NAME(iter) free((iter)->name) - VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME); - VECTOR_DEINIT(DeviceNameMap); + std::for_each(DeviceNameMap.begin(), DeviceNameMap.end(), + [](DevMap &entry) -> void { free(entry.name); } + ); + DeviceNameMap.clear(); - VECTOR_FOR_EACH(DevMap, CaptureNameMap, FREE_NAME); - VECTOR_DEINIT(CaptureNameMap); -#undef FREE_NAME + std::for_each(CaptureNameMap.begin(), CaptureNameMap.end(), + [](DevMap &entry) -> void { free(entry.name); } + ); + CaptureNameMap.clear(); } bool QSABackendFactory::querySupport(ALCbackend_Type type) @@ -1009,23 +1012,23 @@ bool QSABackendFactory::querySupport(ALCbackend_Type type) void QSABackendFactory::probe(enum DevProbe type, std::string *outnames) { + auto add_device = [outnames](const DevMap &entry) -> void + { + const char *n = entry.name; + if(n && n[0]) + outnames->append(n, strlen(n)+1); + }; + switch (type) { -#define APPEND_OUTNAME(e) do { \ - const char *n_ = (e)->name; \ - if(n_ && n_[0]) \ - outnames->append(n_, strlen(n_)+1); \ -} while(0) case ALL_DEVICE_PROBE: deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap); - VECTOR_FOR_EACH(const DevMap, DeviceNameMap, APPEND_OUTNAME); + std::for_each(DeviceNameMap.cbegin(), DeviceNameMap.cend(), add_device); break; - case CAPTURE_DEVICE_PROBE: deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap); - VECTOR_FOR_EACH(const DevMap, CaptureNameMap, APPEND_OUTNAME); + std::for_each(CaptureNameMap.cbegin(), CaptureNameMap.cend(), add_device); break; -#undef APPEND_OUTNAME } } -- cgit v1.2.3 From 190de1452e647aa9d45099d782d20473cba1284c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Nov 2018 23:37:56 -0800 Subject: Remove the unused vector macros --- Alc/vector.h | 82 ------------------------------------------------------------ 1 file changed, 82 deletions(-) diff --git a/Alc/vector.h b/Alc/vector.h index 99713e2f..a7df54f4 100644 --- a/Alc/vector.h +++ b/Alc/vector.h @@ -1,92 +1,10 @@ #ifndef AL_VECTOR_H #define AL_VECTOR_H -#include #include #include "almalloc.h" - -#define TYPEDEF_VECTOR(T, N) typedef struct { \ - std::size_t Capacity; \ - std::size_t Size; \ - T Data[]; \ -} _##N; \ -typedef _##N* N; \ -typedef const _##N* const_##N; - -#define VECTOR(T) struct { \ - std::size_t Capacity; \ - std::size_t Size; \ - T Data[]; \ -}* - -#define VECTOR_INIT(_x) do { (_x) = nullptr; } while(0) -#define VECTOR_INIT_STATIC() nullptr -#define VECTOR_DEINIT(_x) do { al_free((_x)); (_x) = nullptr; } while(0) - -template -inline void do_vector_resize(T *&vec, std::size_t size, std::size_t cap) -{ - if(size > cap) - cap = size; - - if(!vec && cap == 0) - return; - - if((vec ? vec->Capacity : 0) < cap) - { - ptrdiff_t data_offset = vec ? (char*)(vec->Data) - (char*)(vec) : sizeof(*vec); - size_t old_size = (vec ? vec->Size : 0); - - auto temp = static_cast(al_calloc(16, data_offset + sizeof(vec->Data[0])*cap)); - if(vec) std::memcpy(temp->Data, vec->Data, sizeof(vec->Data[0])*old_size); - - al_free(vec); - vec = temp; - vec->Capacity = cap; - } - vec->Size = size; -} -#define VECTOR_RESIZE(_x, _s, _c) do_vector_resize(_x, _s, _c) - -#define VECTOR_CAPACITY(_x) ((_x) ? (_x)->Capacity : 0) -#define VECTOR_SIZE(_x) ((_x) ? (_x)->Size : 0) - -#define VECTOR_BEGIN(_x) ((_x) ? (_x)->Data + 0 : NULL) -#define VECTOR_END(_x) ((_x) ? (_x)->Data + (_x)->Size : NULL) - -#define VECTOR_PUSH_BACK(_x, _obj) do { \ - std::size_t _pbsize = VECTOR_SIZE(_x)+1; \ - VECTOR_RESIZE(_x, _pbsize, _pbsize); \ - (_x)->Data[(_x)->Size-1] = (_obj); \ -} while(0) -#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_BEGIN((_x)); \ - _t *_end = VECTOR_END((_x)); \ - for(;_iter != _end;++_iter) \ - _f(_iter); \ -} while(0) - -#define VECTOR_FIND_IF(_i, _t, _x, _f) do { \ - _t *_iter = VECTOR_BEGIN((_x)); \ - _t *_end = VECTOR_END((_x)); \ - for(;_iter != _end;++_iter) \ - { \ - if(_f(_iter)) \ - break; \ - } \ - (_i) = _iter; \ -} while(0) - - namespace al { template -- cgit v1.2.3 From 6e114a7a70c90d575e5978c5bcac95307bec0140 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 01:20:03 -0800 Subject: Replace ATOMIC_REPLACE_HEAD with an inline function --- Alc/alu.cpp | 8 ++++---- OpenAL32/alAuxEffectSlot.cpp | 2 +- OpenAL32/alListener.cpp | 2 +- OpenAL32/alSource.cpp | 2 +- OpenAL32/alState.cpp | 2 +- common/atomic.h | 16 +++++++++------- 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 9a02d4b6..e26f5f57 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -330,7 +330,7 @@ static bool CalcContextParams(ALCcontext *Context) Listener.Params.SourceDistanceModel = props->SourceDistanceModel; Listener.Params.mDistanceModel = props->mDistanceModel; - ATOMIC_REPLACE_HEAD(struct ALcontextProps*, &Context->FreeContextProps, props); + AtomicReplaceHead(Context->FreeContextProps, props); return true; } @@ -376,7 +376,7 @@ static bool CalcListenerParams(ALCcontext *Context) Listener.Params.Gain = props->Gain * Context->GainBoost; - ATOMIC_REPLACE_HEAD(struct ALlistenerProps*, &Context->FreeListenerProps, props); + AtomicReplaceHead(Context->FreeListenerProps, props); return true; } @@ -449,7 +449,7 @@ static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool f } } - ATOMIC_REPLACE_HEAD(struct ALeffectslotProps*, &context->FreeEffectslotProps, props); + AtomicReplaceHead(context->FreeEffectslotProps, props); } else state = slot->Params.EffectState; @@ -1465,7 +1465,7 @@ static void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) FAM_SIZE(struct ALvoiceProps, Send, context->Device->NumAuxSends) ); - ATOMIC_REPLACE_HEAD(struct ALvoiceProps*, &context->FreeVoiceProps, props); + AtomicReplaceHead(context->FreeVoiceProps, props); } props = voice->Props; diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index fc4b4d1b..037c99dd 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -730,7 +730,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) if(props->State) ALeffectState_DecRef(props->State); props->State = nullptr; - ATOMIC_REPLACE_HEAD(struct ALeffectslotProps*, &context->FreeEffectslotProps, props); + AtomicReplaceHead(context->FreeEffectslotProps, props); } if(oldstate) diff --git a/OpenAL32/alListener.cpp b/OpenAL32/alListener.cpp index 05fd7a21..574f897c 100644 --- a/OpenAL32/alListener.cpp +++ b/OpenAL32/alListener.cpp @@ -498,6 +498,6 @@ void UpdateListenerProps(ALCcontext *context) /* If there was an unused update container, put it back in the * freelist. */ - ATOMIC_REPLACE_HEAD(struct ALlistenerProps*, &context->FreeListenerProps, props); + AtomicReplaceHead(context->FreeListenerProps, props); } } diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 2fe81320..ac220a2e 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -3236,7 +3236,7 @@ static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_send /* If there was an unused update container, put it back in the * freelist. */ - ATOMIC_REPLACE_HEAD(struct ALvoiceProps*, &context->FreeVoiceProps, props); + AtomicReplaceHead(context->FreeVoiceProps, props); } } diff --git a/OpenAL32/alState.cpp b/OpenAL32/alState.cpp index 85789c5e..836853bb 100644 --- a/OpenAL32/alState.cpp +++ b/OpenAL32/alState.cpp @@ -794,6 +794,6 @@ void UpdateContextProps(ALCcontext *context) /* If there was an unused update container, put it back in the * freelist. */ - ATOMIC_REPLACE_HEAD(struct ALcontextProps*, &context->FreeContextProps, props); + AtomicReplaceHead(context->FreeContextProps, props); } } diff --git a/common/atomic.h b/common/atomic.h index dbb75d29..5e46436f 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -91,12 +91,14 @@ inline uint DecrementRef(RefCount *ptr) * changing the head without giving this a chance to actually swap in the new * one (practically impossible with this little code, but...). */ -#define ATOMIC_REPLACE_HEAD(T, _head, _entry) do { \ - T _first = ATOMIC_LOAD(_head, almemory_order_acquire); \ - do { \ - ATOMIC_STORE(&(_entry)->next, _first, almemory_order_relaxed); \ - } while(ATOMIC_COMPARE_EXCHANGE_WEAK(_head, &_first, _entry, \ - almemory_order_acq_rel, almemory_order_acquire) == 0); \ -} while(0) +template +inline void AtomicReplaceHead(std::atomic &head, T newhead) +{ + T first_ = head.load(std::memory_order_acquire); + do { + newhead->next.store(first_, std::memory_order_relaxed); + } while(!head.compare_exchange_weak(first_, newhead, + std::memory_order_acq_rel, std::memory_order_acquire)); +} #endif /* AL_ATOMIC_H */ -- cgit v1.2.3 From c5142530d675885415c9168869eb6c125ce10876 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 02:17:06 -0800 Subject: Simplify the RefCount type --- Alc/alc.cpp | 12 +++++------- Alc/hrtf.cpp | 4 ++-- OpenAL32/alAuxEffectSlot.cpp | 6 ++---- common/atomic.h | 17 ++++++++--------- 4 files changed, 17 insertions(+), 22 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 24783510..6bb632f7 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2476,15 +2476,13 @@ ALCdevice_struct::~ALCdevice_struct() void ALCdevice_IncRef(ALCdevice *device) { - uint ref; - ref = IncrementRef(&device->ref); + auto ref = IncrementRef(&device->ref); TRACEREF("%p increasing refcount to %u\n", device, ref); } void ALCdevice_DecRef(ALCdevice *device) { - uint ref; - ref = DecrementRef(&device->ref); + auto ref = DecrementRef(&device->ref); TRACEREF("%p decreasing refcount to %u\n", device, ref); if(ref == 0) delete device; } @@ -2728,20 +2726,20 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) static void ALCcontext_IncRef(ALCcontext *context) { - uint ref = IncrementRef(&context->ref); + auto ref = IncrementRef(&context->ref); TRACEREF("%p increasing refcount to %u\n", context, ref); } void ALCcontext_DecRef(ALCcontext *context) { - uint ref = DecrementRef(&context->ref); + auto ref = DecrementRef(&context->ref); TRACEREF("%p decreasing refcount to %u\n", context, ref); if(ref == 0) delete context; } static void ReleaseThreadCtx(ALCcontext *context) { - uint ref = DecrementRef(&context->ref); + auto ref = DecrementRef(&context->ref); TRACEREF("%p decreasing refcount to %u\n", context, ref); ERR("Context %p current for thread being destroyed, possible leak!\n", context); } diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 0393da65..034d5a49 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -1257,13 +1257,13 @@ struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry) void Hrtf_IncRef(struct Hrtf *hrtf) { - uint ref = IncrementRef(&hrtf->ref); + auto ref = IncrementRef(&hrtf->ref); TRACEREF("%p increasing refcount to %u\n", hrtf, ref); } void Hrtf_DecRef(struct Hrtf *hrtf) { - uint ref = DecrementRef(&hrtf->ref); + auto ref = DecrementRef(&hrtf->ref); TRACEREF("%p decreasing refcount to %u\n", hrtf, ref); if(ref == 0) { diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index 037c99dd..9c11720e 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -545,15 +545,13 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect static void ALeffectState_IncRef(ALeffectState *state) { - uint ref; - ref = IncrementRef(&state->Ref); + auto ref = IncrementRef(&state->Ref); TRACEREF("%p increasing refcount to %u\n", state, ref); } void ALeffectState_DecRef(ALeffectState *state) { - uint ref; - ref = DecrementRef(&state->Ref); + auto ref = DecrementRef(&state->Ref); TRACEREF("%p decreasing refcount to %u\n", state, ref); if(ref == 0) DELETE_OBJ(state); } diff --git a/common/atomic.h b/common/atomic.h index 5e46436f..d1557ffb 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -74,17 +74,16 @@ using std::atomic_thread_fence; ATOMIC_COMPARE_EXCHANGE_WEAK(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) -typedef unsigned int uint; -typedef ATOMIC(uint) RefCount; +using RefCount = std::atomic; -inline void InitRef(RefCount *ptr, uint value) +inline void InitRef(RefCount *ptr, unsigned int value) { ATOMIC_INIT(ptr, value); } -inline uint ReadRef(RefCount *ptr) -{ return ATOMIC_LOAD(ptr, almemory_order_acquire); } -inline uint IncrementRef(RefCount *ptr) -{ return ATOMIC_ADD(ptr, 1u, almemory_order_acq_rel)+1; } -inline uint DecrementRef(RefCount *ptr) -{ return ATOMIC_SUB(ptr, 1u, almemory_order_acq_rel)-1; } +inline unsigned int ReadRef(RefCount *ptr) +{ return ptr->load(std::memory_order_acquire); } +inline unsigned int IncrementRef(RefCount *ptr) +{ return ptr->fetch_add(1u, std::memory_order_acq_rel)+1u; } +inline unsigned int DecrementRef(RefCount *ptr) +{ return ptr->fetch_sub(1u, std::memory_order_acq_rel)-1u; } /* WARNING: A livelock is theoretically possible if another thread keeps -- cgit v1.2.3 From e24435ef58b2f28555e6397f502f41f36524dac9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 03:21:58 -0800 Subject: Remove the atomic exchange macros --- Alc/alc.cpp | 29 +++++++++++++---------------- Alc/alu.cpp | 23 +++++++++-------------- Alc/backends/jack.cpp | 2 +- Alc/backends/null.cpp | 3 +-- Alc/backends/opensl.cpp | 2 +- Alc/backends/qsa.cpp | 2 +- Alc/backends/sndio.cpp | 4 ++-- Alc/backends/solaris.cpp | 2 +- Alc/backends/wave.cpp | 3 +-- OpenAL32/alAuxEffectSlot.cpp | 18 +++++++++--------- OpenAL32/alError.cpp | 8 ++++---- OpenAL32/alListener.cpp | 10 +++++----- OpenAL32/alSource.cpp | 16 ++++++++-------- OpenAL32/alState.cpp | 10 +++++----- OpenAL32/event.cpp | 12 ++++++------ common/atomic.h | 10 ---------- 16 files changed, 67 insertions(+), 87 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 6bb632f7..879dba00 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1614,7 +1614,7 @@ void ALCcontext_DeferUpdates(ALCcontext *context) void ALCcontext_ProcessUpdates(ALCcontext *context) { almtx_lock(&context->PropLock); - if(ATOMIC_EXCHANGE_SEQ(&context->DeferUpdates, AL_FALSE)) + if(context->DeferUpdates.exchange(AL_FALSE)) { /* Tell the mixer to stop applying updates, then wait for any active * updating to finish, before providing updates. @@ -1623,9 +1623,9 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) while((ATOMIC_LOAD(&context->UpdateCount, almemory_order_acquire)&1) != 0) althrd_yield(); - if(!ATOMIC_EXCHANGE(&context->PropsClean, AL_TRUE, almemory_order_acq_rel)) + if(!context->PropsClean.exchange(AL_TRUE, std::memory_order_acq_rel)) UpdateContextProps(context); - if(!ATOMIC_EXCHANGE(&context->Listener.PropsClean, AL_TRUE, almemory_order_acq_rel)) + if(!context->Listener.PropsClean.exchange(AL_TRUE, std::memory_order_acq_rel)) UpdateListenerProps(context); UpdateAllEffectSlotProps(context); UpdateAllSourceProps(context); @@ -2330,11 +2330,10 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) * auxiliary sends is changing. Active sources will have updates * respecified in UpdateAllSourceProps. */ - vprops = ATOMIC_EXCHANGE(&context->FreeVoiceProps, static_cast(nullptr), - almemory_order_acq_rel); + vprops = context->FreeVoiceProps.exchange(nullptr, std::memory_order_acq_rel); while(vprops) { - struct ALvoiceProps *next = ATOMIC_LOAD(&vprops->next, almemory_order_relaxed); + struct ALvoiceProps *next = vprops->next.load(std::memory_order_relaxed); al_free(vprops); vprops = next; } @@ -2344,10 +2343,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { ALvoice *voice = context->Voices[pos]; - al_free(ATOMIC_EXCHANGE(&voice->Update, static_cast(nullptr), - almemory_order_acq_rel)); + al_free(voice->Update.exchange(nullptr, std::memory_order_acq_rel)); - if(ATOMIC_LOAD(&voice->Source, almemory_order_acquire) == nullptr) + if(voice->Source.load(std::memory_order_acquire) == nullptr) continue; if(device->AvgSpeakerDist > 0.0f) @@ -2698,7 +2696,7 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) V0(device->Backend,lock)(); origctx = context; newhead = ATOMIC_LOAD(&context->next, almemory_order_relaxed); - if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&device->ContextList, &origctx, newhead)) + if(!device->ContextList.compare_exchange_strong(origctx, newhead)) { ALCcontext *list; do { @@ -2707,7 +2705,7 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) */ list = origctx; origctx = context; - } while(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&list->next, &origctx, newhead)); + } while(!list->next.compare_exchange_strong(origctx, newhead)); } else ret = !!newhead; @@ -2893,7 +2891,7 @@ ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) if(VerifyDevice(&device)) { - errorCode = ATOMIC_EXCHANGE_SEQ(&device->LastError, ALC_NO_ERROR); + errorCode = device->LastError.exchange(ALC_NO_ERROR); ALCdevice_DecRef(device); } else @@ -3720,8 +3718,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ALCcontext *head = ATOMIC_LOAD_SEQ(&device->ContextList); do { ATOMIC_STORE(&ALContext->next, head, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(&device->ContextList, &head, - ALContext) == 0); + } while(!device->ContextList.compare_exchange_weak(head, ALContext)); } almtx_unlock(&device->BackendLock); @@ -4068,7 +4065,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) do { list = origdev; origdev = device; - } while(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&list->next, &origdev, nextdev)); + } while(!list->next.compare_exchange_strong(origdev, nextdev)); } listlock.unlock(); @@ -4188,7 +4185,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) do { list = origdev; origdev = device; - } while(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&list->next, &origdev, nextdev)); + } while(!list->next.compare_exchange_strong(origdev, nextdev)); } listlock.unlock(); diff --git a/Alc/alu.cpp b/Alc/alu.cpp index e26f5f57..f9a53139 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -75,7 +75,7 @@ static HrtfDirectMixerFunc MixDirectHrtf = MixDirectHrtf_C; void DeinitVoice(ALvoice *voice) { - al_free(ATOMIC_EXCHANGE_SEQ(&voice->Update, static_cast(nullptr))); + al_free(voice->Update.exchange(nullptr)); } @@ -315,8 +315,7 @@ static bool CalcContextParams(ALCcontext *Context) ALlistener &Listener = Context->Listener; struct ALcontextProps *props; - props = ATOMIC_EXCHANGE(&Context->Update, static_cast(nullptr), - almemory_order_acq_rel); + props = Context->Update.exchange(nullptr, std::memory_order_acq_rel); if(!props) return false; Listener.Params.MetersPerUnit = props->MetersPerUnit; @@ -341,8 +340,7 @@ static bool CalcListenerParams(ALCcontext *Context) struct ALlistenerProps *props; aluVector vel; - props = ATOMIC_EXCHANGE(&Listener.Update, static_cast(nullptr), - almemory_order_acq_rel); + props = Listener.Update.exchange(nullptr, std::memory_order_acq_rel); if(!props) return false; /* AT then UP */ @@ -385,8 +383,7 @@ static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool f struct ALeffectslotProps *props; ALeffectState *state; - props = ATOMIC_EXCHANGE(&slot->Update, static_cast(nullptr), - almemory_order_acq_rel); + props = slot->Update.exchange(nullptr, std::memory_order_acq_rel); if(!props && !force) return false; if(props) @@ -1455,8 +1452,7 @@ static void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) ALbufferlistitem *BufferListItem; struct ALvoiceProps *props; - props = ATOMIC_EXCHANGE(&voice->Update, static_cast(nullptr), - almemory_order_acq_rel); + props = voice->Update.exchange(nullptr, std::memory_order_acq_rel); if(!props && !force) return; if(props) @@ -1830,7 +1826,7 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) va_list args; int msglen; - if(!ATOMIC_EXCHANGE(&device->Connected, AL_FALSE, almemory_order_acq_rel)) + if(!device->Connected.exchange(AL_FALSE, std::memory_order_acq_rel)) return; evt.u.user.type = AL_EVENT_TYPE_DISCONNECTED_SOFT; @@ -1857,9 +1853,8 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) for(i = 0;i < ctx->VoiceCount;i++) { ALvoice *voice = ctx->Voices[i]; - ALsource *source = ATOMIC_EXCHANGE(&voice->Source, static_cast(nullptr), - almemory_order_relaxed); - if(source && ATOMIC_LOAD(&voice->Playing, almemory_order_relaxed)) + ALsource *source = voice->Source.exchange(nullptr, std::memory_order_relaxed); + if(source && voice->Playing.load(std::memory_order_relaxed)) { /* If the source's voice was playing, it's now effectively * stopped (the source state will be updated the next time it's @@ -1867,7 +1862,7 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) */ SendSourceStoppedEvent(ctx, source->id); } - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + voice->Playing.store(false, std::memory_order_release); } ctx = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed); diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index c72958e7..924e1926 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -488,7 +488,7 @@ static void ALCjackPlayback_stop(ALCjackPlayback *self) { int res; - if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) + if(self->killNow.exchange(AL_TRUE, std::memory_order_acq_rel)) return; alsem_post(&self->Sem); diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 255aa01f..47ebd0ae 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -168,8 +168,7 @@ ALCboolean ALCnullBackend_start(ALCnullBackend *self) void ALCnullBackend_stop(ALCnullBackend *self) { - if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel) || - !self->thread.joinable()) + if(self->killNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->thread.joinable()) return; self->thread.join(); } diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index d0b1a7b1..0eb194e0 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -610,7 +610,7 @@ static void ALCopenslPlayback_stop(ALCopenslPlayback *self) SLresult result; int res; - if(ATOMIC_EXCHANGE_SEQ(&self->mKillNow, AL_TRUE)) + if(self->mKillNow.exchange(AL_TRUE)) return; alsem_post(&self->mSem); diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index 9803d77d..09082357 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -614,7 +614,7 @@ static void qsa_stop_playback(PlaybackWrapper *self) qsa_data *data = self->ExtraData; int res; - if(ATOMIC_EXCHANGE(&data->killNow, AL_TRUE, almemory_order_acq_rel)) + if(data->killNow.exchange(AL_TRUE, std::memory_order_acq_rel)) return; althrd_join(data->thread, &res); } diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index 958bc2ff..cc5eacbe 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -267,7 +267,7 @@ static void SndioPlayback_stop(SndioPlayback *self) { int res; - if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) + if(self->killNow.exchange(AL_TRUE, std::memory_order_acq_rel)) return; althrd_join(self->thread, &res); @@ -513,7 +513,7 @@ static void SndioCapture_stop(SndioCapture *self) { int res; - if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) + if(self->killNow.exchange(AL_TRUE, std::memory_order_acq_rel)) return; althrd_join(self->thread, &res); diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index 86120491..c757e5e1 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -282,7 +282,7 @@ static void ALCsolarisBackend_stop(ALCsolarisBackend *self) { int res; - if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE)) + if(self->killNow.exchange(AL_TRUE)) return; althrd_join(self->thread, &res); diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index 3f8d8c97..83af40a8 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -367,8 +367,7 @@ ALCboolean ALCwaveBackend_start(ALCwaveBackend *self) void ALCwaveBackend_stop(ALCwaveBackend *self) { - if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel) || - !self->thread.joinable()) + if(self->killNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->thread.joinable()) return; self->thread.join(); diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index 9c11720e..ff0f7eaa 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -618,7 +618,7 @@ static void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontex newarray->count = newcount; } - curarray = ATOMIC_EXCHANGE(&context->ActiveAuxSlots, newarray, almemory_order_acq_rel); + curarray = context->ActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) althrd_yield(); al_free(curarray); @@ -653,7 +653,7 @@ static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcon /* TODO: Could reallocate newarray now that we know it's needed size. */ - curarray = ATOMIC_EXCHANGE(&context->ActiveAuxSlots, newarray, almemory_order_acq_rel); + curarray = context->ActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) althrd_yield(); al_free(curarray); @@ -693,16 +693,16 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) ALeffectState *oldstate; /* Get an unused property container, or allocate a new one as needed. */ - props = ATOMIC_LOAD(&context->FreeEffectslotProps, almemory_order_relaxed); + props = context->FreeEffectslotProps.load(std::memory_order_relaxed); if(!props) props = static_cast(al_calloc(16, sizeof(*props))); else { struct ALeffectslotProps *next; do { - next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->FreeEffectslotProps, &props, next, - almemory_order_seq_cst, almemory_order_acquire) == 0); + next = props->next.load(std::memory_order_relaxed); + } while(context->FreeEffectslotProps.compare_exchange_weak(props, next, + std::memory_order_seq_cst, std::memory_order_acquire) == 0); } /* Copy in current property values. */ @@ -719,7 +719,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) props->State = slot->Effect.State; /* Set the new container for updating internal parameters. */ - props = ATOMIC_EXCHANGE(&slot->Update, props, almemory_order_acq_rel); + props = slot->Update.exchange(props, std::memory_order_acq_rel); if(props) { /* If there was an unused update container, put it back in the @@ -741,11 +741,11 @@ void UpdateAllEffectSlotProps(ALCcontext *context) ALsizei i; LockEffectSlotList(context); - auxslots = ATOMIC_LOAD(&context->ActiveAuxSlots, almemory_order_acquire); + auxslots = context->ActiveAuxSlots.load(std::memory_order_acquire); for(i = 0;i < auxslots->count;i++) { ALeffectslot *slot = auxslots->slot[i]; - if(!ATOMIC_EXCHANGE(&slot->PropsClean, AL_TRUE, almemory_order_acq_rel)) + if(!slot->PropsClean.exchange(AL_TRUE, std::memory_order_acq_rel)) UpdateEffectSlotProps(slot, context); } UnlockEffectSlotList(context); diff --git a/OpenAL32/alError.cpp b/OpenAL32/alError.cpp index 6d8ca882..16c89273 100644 --- a/OpenAL32/alError.cpp +++ b/OpenAL32/alError.cpp @@ -70,11 +70,11 @@ void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) } ALenum curerr{AL_NO_ERROR}; - ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&context->LastError, &curerr, errorCode); - if((ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)&EventType_Error)) + context->LastError.compare_exchange_strong(curerr, errorCode); + if((context->EnabledEvts.load(std::memory_order_relaxed)&EventType_Error)) { std::lock_guard _{context->EventCbLock}; - ALbitfieldSOFT enabledevts{ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)}; + ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; if((enabledevts&EventType_Error) && context->EventCb) (*context->EventCb)(AL_EVENT_TYPE_ERROR_SOFT, 0, errorCode, msglen, msg, context->EventParam); @@ -100,5 +100,5 @@ AL_API ALenum AL_APIENTRY alGetError(void) return deferror; } - return ATOMIC_EXCHANGE_SEQ(&context->LastError, AL_NO_ERROR); + return context->LastError.exchange(AL_NO_ERROR); } diff --git a/OpenAL32/alListener.cpp b/OpenAL32/alListener.cpp index 574f897c..bf1ac3f9 100644 --- a/OpenAL32/alListener.cpp +++ b/OpenAL32/alListener.cpp @@ -461,16 +461,16 @@ void UpdateListenerProps(ALCcontext *context) struct ALlistenerProps *props; /* Get an unused proprty container, or allocate a new one as needed. */ - props = ATOMIC_LOAD(&context->FreeListenerProps, almemory_order_acquire); + props = context->FreeListenerProps.load(std::memory_order_acquire); if(!props) props = static_cast(al_calloc(16, sizeof(*props))); else { struct ALlistenerProps *next; do { - next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->FreeListenerProps, &props, next, - almemory_order_seq_cst, almemory_order_acquire) == 0); + next = props->next.load(std::memory_order_relaxed); + } while(context->FreeListenerProps.compare_exchange_weak(props, next, + std::memory_order_seq_cst, std::memory_order_acquire) == 0); } /* Copy in current property values. */ @@ -492,7 +492,7 @@ void UpdateListenerProps(ALCcontext *context) props->Gain = listener->Gain; /* Set the new container for updating internal parameters. */ - props = ATOMIC_EXCHANGE(&listener->Update, props, almemory_order_acq_rel); + props = listener->Update.exchange(props, std::memory_order_acq_rel); if(props) { /* If there was an unused update container, put it back in the diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index ac220a2e..ea83d578 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -2488,9 +2488,9 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) if(vidx == -1) vidx = context->VoiceCount++; voice = context->Voices[vidx]; - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + voice->Playing.store(false, std::memory_order_release); - ATOMIC_EXCHANGE(&source->PropsClean, AL_TRUE, almemory_order_acquire); + source->PropsClean.exchange(AL_TRUE, std::memory_order_acquire); UpdateSourceProps(source, voice, device->NumAuxSends, context); /* A source that's not playing or paused has any offset applied when it @@ -3157,7 +3157,7 @@ static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_send ALsizei i; /* Get an unused property container, or allocate a new one as needed. */ - props = ATOMIC_LOAD(&context->FreeVoiceProps, almemory_order_acquire); + props = context->FreeVoiceProps.load(std::memory_order_acquire); if(!props) props = static_cast(al_calloc(16, FAM_SIZE(struct ALvoiceProps, Send, num_sends))); @@ -3165,9 +3165,9 @@ static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_send { struct ALvoiceProps *next; do { - next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->FreeVoiceProps, &props, next, - almemory_order_acq_rel, almemory_order_acquire) == 0); + next = props->next.load(std::memory_order_relaxed); + } while(context->FreeVoiceProps.compare_exchange_weak(props, next, + std::memory_order_acq_rel, std::memory_order_acquire) == 0); } /* Copy in current property values. */ @@ -3230,7 +3230,7 @@ static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_send } /* Set the new container for updating internal parameters. */ - props = ATOMIC_EXCHANGE(&voice->Update, props, almemory_order_acq_rel); + props = voice->Update.exchange(props, std::memory_order_acq_rel); if(props) { /* If there was an unused update container, put it back in the @@ -3249,7 +3249,7 @@ void UpdateAllSourceProps(ALCcontext *context) { ALvoice *voice = context->Voices[pos]; ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire); - if(source && !ATOMIC_EXCHANGE(&source->PropsClean, AL_TRUE, almemory_order_acq_rel)) + if(source && !source->PropsClean.exchange(AL_TRUE, std::memory_order_acq_rel)) UpdateSourceProps(source, voice, num_sends, context); } } diff --git a/OpenAL32/alState.cpp b/OpenAL32/alState.cpp index 836853bb..a3c3cc1f 100644 --- a/OpenAL32/alState.cpp +++ b/OpenAL32/alState.cpp @@ -765,16 +765,16 @@ AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index) void UpdateContextProps(ALCcontext *context) { /* Get an unused proprty container, or allocate a new one as needed. */ - struct ALcontextProps *props{ATOMIC_LOAD(&context->FreeContextProps, almemory_order_acquire)}; + struct ALcontextProps *props{context->FreeContextProps.load(std::memory_order_acquire)}; if(!props) props = static_cast(al_calloc(16, sizeof(*props))); else { struct ALcontextProps *next; do { - next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->FreeContextProps, &props, next, - almemory_order_seq_cst, almemory_order_acquire) == 0); + next = props->next.load(std::memory_order_relaxed); + } while(context->FreeContextProps.compare_exchange_weak(props, next, + std::memory_order_seq_cst, std::memory_order_acquire) == 0); } /* Copy in current property values. */ @@ -788,7 +788,7 @@ void UpdateContextProps(ALCcontext *context) props->mDistanceModel = context->mDistanceModel; /* Set the new container for updating internal parameters. */ - props = ATOMIC_EXCHANGE(&context->Update, props, almemory_order_acq_rel); + props = context->Update.exchange(props, std::memory_order_acq_rel); if(props) { /* If there was an unused update container, put it back in the diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index e4b5eee0..fcbcba66 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -107,9 +107,9 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A if(enable) { - ALbitfieldSOFT enabledevts{ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)}; - while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->EnabledEvts, &enabledevts, enabledevts|flags, - almemory_order_acq_rel, almemory_order_acquire) == 0) + ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; + while(context->EnabledEvts.compare_exchange_weak(enabledevts, enabledevts|flags, + std::memory_order_acq_rel, std::memory_order_acquire) == 0) { /* enabledevts is (re-)filled with the current value on failure, so * just try again. @@ -118,9 +118,9 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A } else { - ALbitfieldSOFT enabledevts{ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)}; - while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->EnabledEvts, &enabledevts, enabledevts&~flags, - almemory_order_acq_rel, almemory_order_acquire) == 0) + ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; + while(context->EnabledEvts.compare_exchange_weak(enabledevts, enabledevts&~flags, + std::memory_order_acq_rel, std::memory_order_acquire) == 0) { } /* Wait to ensure the event handler sees the changed flags before diff --git a/common/atomic.h b/common/atomic.h index d1557ffb..e58a363c 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -54,10 +54,6 @@ using std::atomic_thread_fence; #define ATOMIC_ADD atomic_fetch_add_explicit #define ATOMIC_SUB atomic_fetch_sub_explicit -#define ATOMIC_EXCHANGE atomic_exchange_explicit -#define ATOMIC_COMPARE_EXCHANGE_STRONG atomic_compare_exchange_strong_explicit -#define ATOMIC_COMPARE_EXCHANGE_WEAK atomic_compare_exchange_weak_explicit - #define ATOMIC_THREAD_FENCE atomic_thread_fence @@ -67,12 +63,6 @@ using std::atomic_thread_fence; #define ATOMIC_ADD_SEQ(_val, _incr) ATOMIC_ADD(_val, _incr, almemory_order_seq_cst) #define ATOMIC_SUB_SEQ(_val, _decr) ATOMIC_SUB(_val, _decr, almemory_order_seq_cst) -#define ATOMIC_EXCHANGE_SEQ(_val, _newval) ATOMIC_EXCHANGE(_val, _newval, almemory_order_seq_cst) -#define ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(_val, _oldval, _newval) \ - ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) -#define ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(_val, _oldval, _newval) \ - ATOMIC_COMPARE_EXCHANGE_WEAK(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) - using RefCount = std::atomic; -- cgit v1.2.3 From e6c2c1f3b6795444a3719e26f203240511c6d464 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 03:32:16 -0800 Subject: Remove unnecessary using statements --- common/atomic.h | 51 ++++++++++++++++----------------------------------- 1 file changed, 16 insertions(+), 35 deletions(-) diff --git a/common/atomic.h b/common/atomic.h index e58a363c..d25f3122 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -16,45 +16,26 @@ #define CONST_CAST(T, V) ((T)(V)) #endif -#define _Atomic(T) std::atomic -using std::memory_order; -using std::memory_order_relaxed; -using std::memory_order_consume; -using std::memory_order_acquire; -using std::memory_order_release; -using std::memory_order_acq_rel; -using std::memory_order_seq_cst; - -using std::atomic_init; -using std::atomic_load_explicit; -using std::atomic_store_explicit; -using std::atomic_fetch_add_explicit; -using std::atomic_fetch_sub_explicit; -using std::atomic_exchange_explicit; -using std::atomic_compare_exchange_strong_explicit; -using std::atomic_compare_exchange_weak_explicit; -using std::atomic_thread_fence; - -#define almemory_order memory_order -#define almemory_order_relaxed memory_order_relaxed -#define almemory_order_consume memory_order_consume -#define almemory_order_acquire memory_order_acquire -#define almemory_order_release memory_order_release -#define almemory_order_acq_rel memory_order_acq_rel -#define almemory_order_seq_cst memory_order_seq_cst - -#define ATOMIC(T) _Atomic(T) - -#define ATOMIC_INIT atomic_init +#define almemory_order std::memory_order +#define almemory_order_relaxed std::memory_order_relaxed +#define almemory_order_consume std::memory_order_consume +#define almemory_order_acquire std::memory_order_acquire +#define almemory_order_release std::memory_order_release +#define almemory_order_acq_rel std::memory_order_acq_rel +#define almemory_order_seq_cst std::memory_order_seq_cst + +#define ATOMIC(T) std::atomic + +#define ATOMIC_INIT std::atomic_init #define ATOMIC_INIT_STATIC ATOMIC_VAR_INIT -#define ATOMIC_LOAD atomic_load_explicit -#define ATOMIC_STORE atomic_store_explicit +#define ATOMIC_LOAD std::atomic_load_explicit +#define ATOMIC_STORE std::atomic_store_explicit -#define ATOMIC_ADD atomic_fetch_add_explicit -#define ATOMIC_SUB atomic_fetch_sub_explicit +#define ATOMIC_ADD std::atomic_fetch_add_explicit +#define ATOMIC_SUB std::atomic_fetch_sub_explicit -#define ATOMIC_THREAD_FENCE atomic_thread_fence +#define ATOMIC_THREAD_FENCE std::atomic_thread_fence #define ATOMIC_LOAD_SEQ(_val) ATOMIC_LOAD(_val, almemory_order_seq_cst) -- cgit v1.2.3 From c01743fe5df8ba4778950176ea38d95c65f25309 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 03:53:31 -0800 Subject: Remove the CONST_CAST hack --- Alc/ringbuffer.cpp | 56 +++++++++++++++++++++++++-------------------------- OpenAL32/alSource.cpp | 18 ++++++----------- common/atomic.h | 12 ----------- 3 files changed, 33 insertions(+), 53 deletions(-) diff --git a/Alc/ringbuffer.cpp b/Alc/ringbuffer.cpp index 9d20db6c..4fa52468 100644 --- a/Alc/ringbuffer.cpp +++ b/Alc/ringbuffer.cpp @@ -36,8 +36,8 @@ * size or count is in 'elements', not bytes. Additionally, it only supports * single-consumer/single-provider operation. */ struct ll_ringbuffer { - ATOMIC(size_t) write_ptr; - ATOMIC(size_t) read_ptr; + std::atomic write_ptr; + std::atomic read_ptr; size_t size; size_t size_mask; size_t elem_size; @@ -83,23 +83,23 @@ void ll_ringbuffer_free(ll_ringbuffer_t *rb) void ll_ringbuffer_reset(ll_ringbuffer_t *rb) { - ATOMIC_STORE(&rb->write_ptr, static_cast(0), almemory_order_release); - ATOMIC_STORE(&rb->read_ptr, static_cast(0), almemory_order_release); + rb->write_ptr.store(0, std::memory_order_release); + rb->read_ptr.store(0, std::memory_order_release); memset(rb->buf, 0, (rb->size_mask+1)*rb->elem_size); } size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb) { - size_t w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); - size_t r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); + size_t w = rb->write_ptr.load(std::memory_order_acquire); + size_t r = rb->read_ptr.load(std::memory_order_acquire); return (w-r) & rb->size_mask; } size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb) { - size_t w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); - size_t r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); + size_t w = rb->write_ptr.load(std::memory_order_acquire); + size_t r = rb->read_ptr.load(std::memory_order_acquire); w = (r-w-1) & rb->size_mask; return (w > rb->size) ? rb->size : w; } @@ -117,7 +117,7 @@ size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt) if(free_cnt == 0) return 0; to_read = (cnt > free_cnt) ? free_cnt : cnt; - read_ptr = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask; + read_ptr = rb->read_ptr.load(std::memory_order_relaxed) & rb->size_mask; cnt2 = read_ptr + to_read; if(cnt2 > rb->size_mask+1) @@ -139,7 +139,7 @@ size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt) n2*rb->elem_size); read_ptr += n2; } - ATOMIC_STORE(&rb->read_ptr, read_ptr, almemory_order_release); + rb->read_ptr.store(read_ptr, std::memory_order_release); return to_read; } @@ -155,7 +155,7 @@ size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt) if(free_cnt == 0) return 0; to_read = (cnt > free_cnt) ? free_cnt : cnt; - read_ptr = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask; + read_ptr = rb->read_ptr.load(std::memory_order_relaxed) & rb->size_mask; cnt2 = read_ptr + to_read; if(cnt2 > rb->size_mask+1) @@ -191,7 +191,7 @@ size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt) if(free_cnt == 0) return 0; to_write = (cnt > free_cnt) ? free_cnt : cnt; - write_ptr = ATOMIC_LOAD(&rb->write_ptr, almemory_order_relaxed) & rb->size_mask; + write_ptr = rb->write_ptr.load(std::memory_order_relaxed) & rb->size_mask; cnt2 = write_ptr + to_write; if(cnt2 > rb->size_mask+1) @@ -213,19 +213,19 @@ size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt) n2*rb->elem_size); write_ptr += n2; } - ATOMIC_STORE(&rb->write_ptr, write_ptr, almemory_order_release); + rb->write_ptr.store(write_ptr, std::memory_order_release); return to_write; } void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt) { - ATOMIC_ADD(&rb->read_ptr, cnt, almemory_order_acq_rel); + rb->read_ptr.fetch_add(cnt, std::memory_order_acq_rel); } void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt) { - ATOMIC_ADD(&rb->write_ptr, cnt, almemory_order_acq_rel); + rb->write_ptr.fetch_add(cnt, std::memory_order_acq_rel); } @@ -233,10 +233,9 @@ void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data { size_t free_cnt; size_t cnt2; - size_t w, r; - w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); - r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); + size_t w = rb->write_ptr.load(std::memory_order_acquire); + size_t r = rb->read_ptr.load(std::memory_order_acquire); w &= rb->size_mask; r &= rb->size_mask; free_cnt = (w-r) & rb->size_mask; @@ -246,17 +245,17 @@ void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data { /* Two part vector: the rest of the buffer after the current write ptr, * plus some from the start of the buffer. */ - vec[0].buf = (char*)&rb->buf[r*rb->elem_size]; + vec[0].buf = const_cast(&rb->buf[r*rb->elem_size]); vec[0].len = rb->size_mask+1 - r; - vec[1].buf = (char*)rb->buf; + vec[1].buf = const_cast(rb->buf); vec[1].len = cnt2 & rb->size_mask; } else { /* Single part vector: just the rest of the buffer */ - vec[0].buf = (char*)&rb->buf[r*rb->elem_size]; + vec[0].buf = const_cast(&rb->buf[r*rb->elem_size]); vec[0].len = free_cnt; - vec[1].buf = NULL; + vec[1].buf = nullptr; vec[1].len = 0; } } @@ -265,10 +264,9 @@ void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_dat { size_t free_cnt; size_t cnt2; - size_t w, r; - w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); - r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); + size_t w = rb->write_ptr.load(std::memory_order_acquire); + size_t r = rb->read_ptr.load(std::memory_order_acquire); w &= rb->size_mask; r &= rb->size_mask; free_cnt = (r-w-1) & rb->size_mask; @@ -279,16 +277,16 @@ void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_dat { /* Two part vector: the rest of the buffer after the current write ptr, * plus some from the start of the buffer. */ - vec[0].buf = (char*)&rb->buf[w*rb->elem_size]; + vec[0].buf = const_cast(&rb->buf[w*rb->elem_size]); vec[0].len = rb->size_mask+1 - w; - vec[1].buf = (char*)rb->buf; + vec[1].buf = const_cast(rb->buf); vec[1].len = cnt2 & rb->size_mask; } else { - vec[0].buf = (char*)&rb->buf[w*rb->elem_size]; + vec[0].buf = const_cast(&rb->buf[w*rb->elem_size]); vec[0].len = free_cnt; - vec[1].buf = NULL; + vec[1].buf = nullptr; vec[1].len = 0; } } diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index ea83d578..539a5f4f 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -1438,8 +1438,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p while(BufferList && BufferList != Current) { played += BufferList->num_buffers; - BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, - almemory_order_relaxed); + BufferList = BufferList->next.load(std::memory_order_relaxed); } *values = played; } @@ -3294,8 +3293,7 @@ static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALui while(BufferList && BufferList != Current) { readPos += (ALuint64)BufferList->max_samples << 32; - BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, - almemory_order_relaxed); + BufferList = BufferList->next.load(std::memory_order_relaxed); } readPos = minu64(readPos, U64(0x7fffffffffffffff)); } @@ -3347,8 +3345,7 @@ static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint while(!BufferFmt && i < BufferList->num_buffers) BufferFmt = BufferList->buffers[i++]; readPos += (ALuint64)BufferList->max_samples << FRACTIONBITS; - BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, - almemory_order_relaxed); + BufferList = BufferList->next.load(std::memory_order_relaxed); } while(BufferList && !BufferFmt) @@ -3356,8 +3353,7 @@ static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint ALsizei i = 0; while(!BufferFmt && i < BufferList->num_buffers) BufferFmt = BufferList->buffers[i++]; - BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, - almemory_order_relaxed); + BufferList = BufferList->next.load(std::memory_order_relaxed); } assert(BufferFmt != NULL); @@ -3418,8 +3414,7 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *conte totalBufferLen += BufferList->max_samples; if(!readFin) readPos += BufferList->max_samples; - BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, - almemory_order_relaxed); + BufferList = BufferList->next.load(std::memory_order_relaxed); } assert(BufferFmt != NULL); @@ -3534,8 +3529,7 @@ static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac for(i = 0;i < BufferList->num_buffers && !BufferFmt;i++) BufferFmt = BufferList->buffers[i]; if(BufferFmt) break; - BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, - almemory_order_relaxed); + BufferList = BufferList->next.load(std::memory_order_relaxed); } if(!BufferFmt) { diff --git a/common/atomic.h b/common/atomic.h index d25f3122..b25bd4dd 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -3,18 +3,6 @@ #include -#ifdef __GNUC__ -/* This helps cast away the const-ness of a pointer without accidentally - * changing the pointer type. This is necessary due to Clang's inability to use - * atomic_load on a const _Atomic variable. - */ -#define CONST_CAST(T, V) __extension__({ \ - const T _tmp = (V); \ - (T)_tmp; \ -}) -#else -#define CONST_CAST(T, V) ((T)(V)) -#endif #define almemory_order std::memory_order #define almemory_order_relaxed std::memory_order_relaxed -- cgit v1.2.3 From a14f39ea06a458e6b3b70e0428264967847da7f4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 04:11:21 -0800 Subject: Make ll_ringbuffer_write/read take void*/const void* --- Alc/alu.cpp | 6 +++--- Alc/backends/coreaudio.cpp | 5 ++--- Alc/backends/dsound.cpp | 8 +++----- Alc/backends/portaudio.cpp | 4 ++-- Alc/backends/winmm.cpp | 2 +- Alc/mixvoice.cpp | 2 +- Alc/ringbuffer.cpp | 15 +++++++++------ Alc/ringbuffer.h | 6 +++--- OpenAL32/alSource.cpp | 2 +- OpenAL32/event.cpp | 6 +++--- 10 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index f9a53139..b4b34e5f 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -186,7 +186,7 @@ static void SendSourceStoppedEvent(ALCcontext *context, ALuint id) } strcpy(evt.u.user.msg+strpos, " state changed to AL_STOPPED"); - if(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) == 1) + if(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) == 1) alsem_post(&context->EventSem); } @@ -433,7 +433,7 @@ static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool f slot->Params.EffectState = state; props->State = NULL; - if(LIKELY(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) != 0)) + if(LIKELY(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) != 0)) alsem_post(&context->EventSem); else { @@ -1847,7 +1847,7 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) ALsizei i; if((enabledevt&EventType_Disconnected) && - ll_ringbuffer_write(ctx->AsyncEvents, (const char*)&evt, 1) == 1) + ll_ringbuffer_write(ctx->AsyncEvents, &evt, 1) == 1) alsem_post(&ctx->EventSem); for(i = 0;i < ctx->VoiceCount;i++) diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index 158331f1..ff02a706 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -420,8 +420,7 @@ static OSStatus ALCcoreAudioCapture_RecordProc(void *inRefCon, return err; } - ll_ringbuffer_write(self->ring, static_cast(self->bufferList->mBuffers[0].mData), - inNumberFrames); + ll_ringbuffer_write(self->ring, self->bufferList->mBuffers[0].mData, inNumberFrames); return noErr; } @@ -433,7 +432,7 @@ static OSStatus ALCcoreAudioCapture_ConvertCallback(AudioConverterRef UNUSED(inA ALCcoreAudioCapture *self = reinterpret_cast(inUserData); // Read from the ring buffer and store temporarily in a large buffer - ll_ringbuffer_read(self->ring, static_cast(self->resampleBuffer), *ioNumberDataPackets); + ll_ringbuffer_read(self->ring, self->resampleBuffer, *ioNumberDataPackets); // Set the input data ioData->mNumberBuffers = 1; diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 6a8b0754..085dab90 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -893,7 +893,7 @@ void ALCdsoundCapture_stop(ALCdsoundCapture *self) ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint samples) { - ll_ringbuffer_read(self->Ring, reinterpret_cast(buffer), samples); + ll_ringbuffer_read(self->Ring, buffer, samples); return ALC_NO_ERROR; } @@ -921,11 +921,9 @@ ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) } if(SUCCEEDED(hr)) { - ll_ringbuffer_write(self->Ring, reinterpret_cast(ReadPtr1), - ReadCnt1/FrameSize); + ll_ringbuffer_write(self->Ring, ReadPtr1, ReadCnt1/FrameSize); if(ReadPtr2 != nullptr) - ll_ringbuffer_write(self->Ring, reinterpret_cast(ReadPtr2), - ReadCnt2/FrameSize); + ll_ringbuffer_write(self->Ring, ReadPtr2, ReadCnt2/FrameSize); hr = self->DSCbuffer->Unlock(ReadPtr1, ReadCnt1, ReadPtr2, ReadCnt2); self->Cursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes; } diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index 1a74250e..1c87f2c8 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -377,7 +377,7 @@ int ALCportCapture_ReadCallback(const void *inputBuffer, void *UNUSED(outputBuff size_t writable = ll_ringbuffer_write_space(self->ring); if(framesPerBuffer > writable) framesPerBuffer = writable; - ll_ringbuffer_write(self->ring, static_cast(inputBuffer), framesPerBuffer); + ll_ringbuffer_write(self->ring, inputBuffer, framesPerBuffer); return 0; } @@ -472,7 +472,7 @@ ALCuint ALCportCapture_availableSamples(ALCportCapture *self) ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples) { - ll_ringbuffer_read(self->ring, static_cast(buffer), samples); + ll_ringbuffer_read(self->ring, buffer, samples); return ALC_NO_ERROR; } diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 9da3e4c3..f17b5d1f 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -653,7 +653,7 @@ void ALCwinmmCapture_stop(ALCwinmmCapture *self) ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples) { - ll_ringbuffer_read(self->Ring, static_cast(buffer), samples); + ll_ringbuffer_read(self->Ring, buffer, samples); return ALC_NO_ERROR; } diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index f89b6efa..c83fb8a7 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -201,7 +201,7 @@ static void SendAsyncEvent(ALCcontext *context, ALuint enumtype, ALenum type, evt.u.user.id = objid; evt.u.user.param = param; strcpy(evt.u.user.msg, msg); - if(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) == 1) + if(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) == 1) alsem_post(&context->EventSem); } diff --git a/Alc/ringbuffer.cpp b/Alc/ringbuffer.cpp index 4fa52468..4d40ec93 100644 --- a/Alc/ringbuffer.cpp +++ b/Alc/ringbuffer.cpp @@ -105,7 +105,7 @@ size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb) } -size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt) +size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, void *dest, size_t cnt) { size_t read_ptr; size_t free_cnt; @@ -135,7 +135,8 @@ size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt) read_ptr += n1; if(n2) { - memcpy(dest + n1*rb->elem_size, &rb->buf[(read_ptr&rb->size_mask)*rb->elem_size], + memcpy(static_cast(dest) + n1*rb->elem_size, + &rb->buf[(read_ptr&rb->size_mask)*rb->elem_size], n2*rb->elem_size); read_ptr += n2; } @@ -143,7 +144,7 @@ size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt) return to_read; } -size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt) +size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, void *dest, size_t cnt) { size_t free_cnt; size_t cnt2; @@ -173,13 +174,14 @@ size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt) if(n2) { read_ptr += n1; - memcpy(dest + n1*rb->elem_size, &rb->buf[(read_ptr&rb->size_mask)*rb->elem_size], + memcpy(static_cast(dest) + n1*rb->elem_size, + &rb->buf[(read_ptr&rb->size_mask)*rb->elem_size], n2*rb->elem_size); } return to_read; } -size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt) +size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const void *src, size_t cnt) { size_t write_ptr; size_t free_cnt; @@ -209,7 +211,8 @@ size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt) write_ptr += n1; if(n2) { - memcpy(&rb->buf[(write_ptr&rb->size_mask)*rb->elem_size], src + n1*rb->elem_size, + memcpy(&rb->buf[(write_ptr&rb->size_mask)*rb->elem_size], + static_cast(src) + n1*rb->elem_size, n2*rb->elem_size); write_ptr += n2; } diff --git a/Alc/ringbuffer.h b/Alc/ringbuffer.h index 0d05ec84..521d96cb 100644 --- a/Alc/ringbuffer.h +++ b/Alc/ringbuffer.h @@ -48,12 +48,12 @@ size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb); * The copying data reader. Copy at most `cnt' elements from `rb' to `dest'. * Returns the actual number of elements copied. */ -size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt); +size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, void *dest, size_t cnt); /** * The copying data reader w/o read pointer advance. Copy at most `cnt' * elements from `rb' to `dest'. Returns the actual number of elements copied. */ -size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt); +size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, void *dest, size_t cnt); /** Advance the read pointer `cnt' places. */ void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt); @@ -66,7 +66,7 @@ size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb); * The copying data writer. Copy at most `cnt' elements to `rb' from `src'. * Returns the actual number of elements copied. */ -size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt); +size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const void *src, size_t cnt); /** Advance the write pointer `cnt' places. */ void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt); diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 539a5f4f..39f70ab5 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -249,7 +249,7 @@ static void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) * and we don't want state change messages to occur out of order, so send * it through the async queue to ensure proper ordering. */ - if(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) == 1) + if(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) == 1) alsem_post(&context->EventSem); } diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index fcbcba66..1dc2745f 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -21,7 +21,7 @@ static int EventThread(ALCcontext *context) while(LIKELY(!quitnow)) { AsyncEvent evt; - if(ll_ringbuffer_read(context->AsyncEvents, (char*)&evt, 1) == 0) + if(ll_ringbuffer_read(context->AsyncEvents, &evt, 1) == 0) { alsem_wait(&context->EventSem); continue; @@ -43,7 +43,7 @@ static int EventThread(ALCcontext *context) context->EventCb(evt.u.user.type, evt.u.user.id, evt.u.user.param, (ALsizei)strlen(evt.u.user.msg), evt.u.user.msg, context->EventParam ); - } while(ll_ringbuffer_read(context->AsyncEvents, (char*)&evt, 1) != 0); + } while(ll_ringbuffer_read(context->AsyncEvents, &evt, 1) != 0); } return 0; } @@ -64,7 +64,7 @@ void StartEventThrd(ALCcontext *ctx) void StopEventThrd(ALCcontext *ctx) { static constexpr AsyncEvent kill_evt = ASYNC_EVENT(EventType_KillThread); - while(ll_ringbuffer_write(ctx->AsyncEvents, (const char*)&kill_evt, 1) == 0) + while(ll_ringbuffer_write(ctx->AsyncEvents, &kill_evt, 1) == 0) althrd_yield(); alsem_post(&ctx->EventSem); if(ctx->EventThread.joinable()) -- cgit v1.2.3 From ad5f9d9b22f8860f0c6ca06004c134182dda95df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 04:46:49 -0800 Subject: Return the ringbuffer data pointers as a pair --- Alc/backends/alsa.cpp | 9 ++++----- Alc/backends/jack.cpp | 26 ++++++++++++-------------- Alc/backends/opensl.cpp | 38 +++++++++++++++++--------------------- Alc/backends/oss.cpp | 7 +++---- Alc/backends/sndio.cpp | 19 +++++++++---------- Alc/backends/wasapi.cpp | 19 ++++++++++--------- Alc/ringbuffer.cpp | 42 ++++++++++++++++++++++++------------------ Alc/ringbuffer.h | 34 ++++++++++++++++------------------ 8 files changed, 95 insertions(+), 99 deletions(-) diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index b3adfafa..e1e861db 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -1237,12 +1237,11 @@ ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) while(avail > 0) { - ll_ringbuffer_data_t vec[2]; - ll_ringbuffer_get_write_vector(self->ring, vec); - if(vec[0].len == 0) break; + auto vec = ll_ringbuffer_get_write_vector(self->ring); + if(vec.first.len == 0) break; - snd_pcm_sframes_t amt{std::min(vec[0].len, avail)}; - amt = snd_pcm_readi(self->pcmHandle, vec[0].buf, amt); + snd_pcm_sframes_t amt{std::min(vec.first.len, avail)}; + amt = snd_pcm_readi(self->pcmHandle, vec.first.buf, amt); if(amt < 0) { ERR("read error: %s\n", snd_strerror(amt)); diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index 924e1926..93dbaf13 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -249,33 +249,32 @@ static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) { ALCjackPlayback *self = static_cast(arg); jack_default_audio_sample_t *out[MAX_OUTPUT_CHANNELS]; - ll_ringbuffer_data_t data[2]; - jack_nframes_t total = 0; + jack_nframes_t total{0}; jack_nframes_t todo; ALsizei i, c, numchans; - ll_ringbuffer_get_read_vector(self->Ring, data); + auto data = ll_ringbuffer_get_read_vector(self->Ring); for(c = 0;c < MAX_OUTPUT_CHANNELS && self->Port[c];c++) out[c] = static_cast(jack_port_get_buffer(self->Port[c], numframes)); numchans = c; - todo = minu(numframes, data[0].len); + todo = minu(numframes, data.first.len); for(c = 0;c < numchans;c++) { - const ALfloat *RESTRICT in = ((ALfloat*)data[0].buf) + c; + const ALfloat *RESTRICT in = ((ALfloat*)data.first.buf) + c; for(i = 0;(jack_nframes_t)i < todo;i++) out[c][i] = in[i*numchans]; out[c] += todo; } total += todo; - todo = minu(numframes-total, data[1].len); + todo = minu(numframes-total, data.second.len); if(todo > 0) { for(c = 0;c < numchans;c++) { - const ALfloat *RESTRICT in = ((ALfloat*)data[1].buf) + c; + const ALfloat *RESTRICT in = ((ALfloat*)data.second.buf) + c; for(i = 0;(jack_nframes_t)i < todo;i++) out[c][i] = in[i*numchans]; out[c] += todo; @@ -303,7 +302,6 @@ static int ALCjackPlayback_mixerProc(void *arg) { ALCjackPlayback *self = static_cast(arg); ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - ll_ringbuffer_data_t data[2]; SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); @@ -322,16 +320,16 @@ static int ALCjackPlayback_mixerProc(void *arg) continue; } - ll_ringbuffer_get_write_vector(self->Ring, data); - todo = data[0].len + data[1].len; + auto data = ll_ringbuffer_get_write_vector(self->Ring); + todo = data.first.len + data.second.len; todo -= todo%device->UpdateSize; - len1 = minu(data[0].len, todo); - len2 = minu(data[1].len, todo-len1); + len1 = minu(data.first.len, todo); + len2 = minu(data.second.len, todo-len1); - aluMixData(device, data[0].buf, len1); + aluMixData(device, data.first.buf, len1); if(len2 > 0) - aluMixData(device, data[1].buf, len2); + aluMixData(device, data.second.buf, len2); ll_ringbuffer_write_advance(self->Ring, todo); } ALCjackPlayback_unlock(self); diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 0eb194e0..a53c0759 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -239,7 +239,6 @@ static int ALCopenslPlayback_mixerProc(void *arg) ALCopenslPlayback *self = static_cast(arg); ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; SLAndroidSimpleBufferQueueItf bufferQueue; - ll_ringbuffer_data_t data[2]; SLPlayItf player; SLresult result; @@ -291,13 +290,12 @@ static int ALCopenslPlayback_mixerProc(void *arg) } } - ll_ringbuffer_get_write_vector(self->mRing, data); + auto data = ll_ringbuffer_get_write_vector(self->mRing); + aluMixData(device, data.first.buf, data.first.len*device->UpdateSize); + if(data.second.len > 0) + aluMixData(device, data.second.buf, data.second.len*device->UpdateSize); - aluMixData(device, data[0].buf, data[0].len*device->UpdateSize); - if(data[1].len > 0) - aluMixData(device, data[1].buf, data[1].len*device->UpdateSize); - - todo = data[0].len+data[1].len; + todo = data.first.len+data.second.len; ll_ringbuffer_write_advance(self->mRing, todo); for(size_t i = 0;i < todo;i++) @@ -869,18 +867,17 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name if(SL_RESULT_SUCCESS == result) { ALsizei chunk_size = device->UpdateSize * self->mFrameSize; - ll_ringbuffer_data_t data[2]; size_t i; - ll_ringbuffer_get_write_vector(self->mRing, data); - for(i = 0;i < data[0].len && SL_RESULT_SUCCESS == result;i++) + auto data = ll_ringbuffer_get_write_vector(self->mRing); + for(i = 0;i < data.first.len && SL_RESULT_SUCCESS == result;i++) { - result = VCALL(bufferQueue,Enqueue)(data[0].buf + chunk_size*i, chunk_size); + result = VCALL(bufferQueue,Enqueue)(data.first.buf + chunk_size*i, chunk_size); PRINTERR(result, "bufferQueue->Enqueue"); } - for(i = 0;i < data[1].len && SL_RESULT_SUCCESS == result;i++) + for(i = 0;i < data.second.len && SL_RESULT_SUCCESS == result;i++) { - result = VCALL(bufferQueue,Enqueue)(data[1].buf + chunk_size*i, chunk_size); + result = VCALL(bufferQueue,Enqueue)(data.second.buf + chunk_size*i, chunk_size); PRINTERR(result, "bufferQueue->Enqueue"); } } @@ -949,7 +946,6 @@ static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid * ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; ALsizei chunk_size = device->UpdateSize * self->mFrameSize; SLAndroidSimpleBufferQueueItf bufferQueue; - ll_ringbuffer_data_t data[2]; SLresult result; ALCuint i; @@ -960,12 +956,12 @@ static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid * /* Read the desired samples from the ring buffer then advance its read * pointer. */ - ll_ringbuffer_get_read_vector(self->mRing, data); + auto data = ll_ringbuffer_get_read_vector(self->mRing); for(i = 0;i < samples;) { ALCuint rem = minu(samples - i, device->UpdateSize - self->mSplOffset); memcpy((ALCbyte*)buffer + i*self->mFrameSize, - data[0].buf + self->mSplOffset*self->mFrameSize, + data.first.buf + self->mSplOffset*self->mFrameSize, rem * self->mFrameSize); self->mSplOffset += rem; @@ -975,15 +971,15 @@ static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid * self->mSplOffset = 0; ll_ringbuffer_read_advance(self->mRing, 1); - result = VCALL(bufferQueue,Enqueue)(data[0].buf, chunk_size); + result = VCALL(bufferQueue,Enqueue)(data.first.buf, chunk_size); PRINTERR(result, "bufferQueue->Enqueue"); if(SL_RESULT_SUCCESS != result) break; - data[0].len--; - if(!data[0].len) - data[0] = data[1]; + data.first.len--; + if(!data.first.len) + data.first = data.second; else - data[0].buf += chunk_size; + data.first.buf += chunk_size; } i += rem; diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 32ee1022..3985cd27 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -582,11 +582,10 @@ int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) continue; } - ll_ringbuffer_data_t vec[2]; - ll_ringbuffer_get_write_vector(self->ring, vec); - if(vec[0].len > 0) + auto vec = ll_ringbuffer_get_write_vector(self->ring); + if(vec.first.len > 0) { - amt = read(self->fd, vec[0].buf, vec[0].len*frame_size); + amt = read(self->fd, vec.first.buf, vec.first.len*frame_size); if(amt < 0) { ERR("read failed: %s\n", strerror(errno)); diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index cc5eacbe..2a20fb61 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -345,11 +345,10 @@ static int SndioCapture_recordProc(void* ptr) while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { - ll_ringbuffer_data_t data[2]; size_t total, todo; - ll_ringbuffer_get_write_vector(self->ring, data); - todo = data[0].len + data[1].len; + auto data = ll_ringbuffer_get_write_vector(self->ring); + todo = data.first.len + data.second.len; if(todo == 0) { static char junk[4096]; @@ -358,17 +357,17 @@ static int SndioCapture_recordProc(void* ptr) } total = 0; - data[0].len *= frameSize; - data[1].len *= frameSize; + data.first.len *= frameSize; + data.second.len *= frameSize; todo = minz(todo, device->UpdateSize) * frameSize; while(total < todo) { size_t got; - if(!data[0].len) - data[0] = data[1]; + if(!data.first.len) + data.first = data.second; - got = sio_read(self->sndHandle, data[0].buf, minz(todo-total, data[0].len)); + got = sio_read(self->sndHandle, data.first.buf, minz(todo-total, data.first.len)); if(!got) { SndioCapture_lock(self); @@ -377,8 +376,8 @@ static int SndioCapture_recordProc(void* ptr) break; } - data[0].buf += got; - data[0].len -= got; + data.first.buf += got; + data.first.len -= got; total += got; } ll_ringbuffer_write_advance(self->ring, total / frameSize); diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 751c56d8..e531a9ae 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -1275,8 +1275,7 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) rdata = reinterpret_cast(samples.data()); } - ll_ringbuffer_data_t data[2]; - ll_ringbuffer_get_write_vector(self->mRing, data); + auto data = ll_ringbuffer_get_write_vector(self->mRing); size_t dstframes; if(self->mSampleConv) @@ -1285,16 +1284,18 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) ALsizei srcframes = numsamples; dstframes = SampleConverterInput(self->mSampleConv, - &srcdata, &srcframes, data[0].buf, (ALsizei)minz(data[0].len, INT_MAX) + &srcdata, &srcframes, data.first.buf, + (ALsizei)minz(data.first.len, INT_MAX) ); - if(srcframes > 0 && dstframes == data[0].len && data[1].len > 0) + if(srcframes > 0 && dstframes == data.first.len && data.second.len > 0) { /* If some source samples remain, all of the first dest * block was filled, and there's space in the second * dest block, do another run for the second block. */ dstframes += SampleConverterInput(self->mSampleConv, - &srcdata, &srcframes, data[1].buf, (ALsizei)minz(data[1].len, INT_MAX) + &srcdata, &srcframes, data.second.buf, + (ALsizei)minz(data.second.len, INT_MAX) ); } } @@ -1302,12 +1303,12 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) { ALuint framesize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); - size_t len1 = minz(data[0].len, numsamples); - size_t len2 = minz(data[1].len, numsamples-len1); + size_t len1 = minz(data.first.len, numsamples); + size_t len2 = minz(data.second.len, numsamples-len1); - memcpy(data[0].buf, rdata, len1*framesize); + memcpy(data.first.buf, rdata, len1*framesize); if(len2 > 0) - memcpy(data[1].buf, rdata+len1*framesize, len2*framesize); + memcpy(data.second.buf, rdata+len1*framesize, len2*framesize); dstframes = len1 + len2; } diff --git a/Alc/ringbuffer.cpp b/Alc/ringbuffer.cpp index 4d40ec93..e5f0f554 100644 --- a/Alc/ringbuffer.cpp +++ b/Alc/ringbuffer.cpp @@ -232,8 +232,9 @@ void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt) } -void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t vec[2]) +ll_ringbuffer_data_pair ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb) { + ll_ringbuffer_data_pair ret; size_t free_cnt; size_t cnt2; @@ -248,23 +249,26 @@ void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data { /* Two part vector: the rest of the buffer after the current write ptr, * plus some from the start of the buffer. */ - vec[0].buf = const_cast(&rb->buf[r*rb->elem_size]); - vec[0].len = rb->size_mask+1 - r; - vec[1].buf = const_cast(rb->buf); - vec[1].len = cnt2 & rb->size_mask; + ret.first.buf = const_cast(&rb->buf[r*rb->elem_size]); + ret.first.len = rb->size_mask+1 - r; + ret.second.buf = const_cast(rb->buf); + ret.second.len = cnt2 & rb->size_mask; } else { /* Single part vector: just the rest of the buffer */ - vec[0].buf = const_cast(&rb->buf[r*rb->elem_size]); - vec[0].len = free_cnt; - vec[1].buf = nullptr; - vec[1].len = 0; + ret.first.buf = const_cast(&rb->buf[r*rb->elem_size]); + ret.first.len = free_cnt; + ret.second.buf = nullptr; + ret.second.len = 0; } + + return ret; } -void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t vec[2]) +ll_ringbuffer_data_pair ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb) { + ll_ringbuffer_data_pair ret; size_t free_cnt; size_t cnt2; @@ -280,16 +284,18 @@ void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_dat { /* Two part vector: the rest of the buffer after the current write ptr, * plus some from the start of the buffer. */ - vec[0].buf = const_cast(&rb->buf[w*rb->elem_size]); - vec[0].len = rb->size_mask+1 - w; - vec[1].buf = const_cast(rb->buf); - vec[1].len = cnt2 & rb->size_mask; + ret.first.buf = const_cast(&rb->buf[w*rb->elem_size]); + ret.first.len = rb->size_mask+1 - w; + ret.second.buf = const_cast(rb->buf); + ret.second.len = cnt2 & rb->size_mask; } else { - vec[0].buf = const_cast(&rb->buf[w*rb->elem_size]); - vec[0].len = free_cnt; - vec[1].buf = nullptr; - vec[1].len = 0; + ret.first.buf = const_cast(&rb->buf[w*rb->elem_size]); + ret.first.len = free_cnt; + ret.second.buf = nullptr; + ret.second.len = 0; } + + return ret; } diff --git a/Alc/ringbuffer.h b/Alc/ringbuffer.h index 521d96cb..b516ab57 100644 --- a/Alc/ringbuffer.h +++ b/Alc/ringbuffer.h @@ -3,16 +3,18 @@ #include +#include -#ifdef __cplusplus -extern "C" { -#endif -typedef struct ll_ringbuffer ll_ringbuffer_t; -typedef struct ll_ringbuffer_data { +struct ll_ringbuffer; +using ll_ringbuffer_t = struct ll_ringbuffer; + +struct ll_ringbuffer_data { char *buf; size_t len; -} ll_ringbuffer_data_t; +}; +using ll_ringbuffer_data_pair = std::pair; +using ll_ringbuffer_data_t = struct ll_ringbuffer_data; /** @@ -27,17 +29,17 @@ void ll_ringbuffer_free(ll_ringbuffer_t *rb); void ll_ringbuffer_reset(ll_ringbuffer_t *rb); /** - * The non-copying data reader. `vec' is an array of two places. Set the values - * at `vec' to hold the current readable data at `rb'. If the readable data is - * in one segment the second segment has zero length. + * The non-copying data reader. Returns two ringbuffer data pointers that hold + * the current readable data at `rb'. If the readable data is in one segment + * the second segment has zero length. */ -void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t vec[2]); +ll_ringbuffer_data_pair ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb); /** - * The non-copying data writer. `vec' is an array of two places. Set the values - * at `vec' to hold the current writeable data at `rb'. If the writeable data - * is in one segment the second segment has zero length. + * The non-copying data writer. Returns two ringbuffer data pointers that hold + * the current writeable data at `rb'. If the writeable data is in one segment + * the second segment has zero length. */ -void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t vec[2]); +ll_ringbuffer_data_pair ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb); /** * Return the number of elements available for reading. This is the number of @@ -70,8 +72,4 @@ size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const void *src, size_t cnt); /** Advance the write pointer `cnt' places. */ void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt); -#ifdef __cplusplus -} /* extern "C" */ -#endif - #endif /* RINGBUFFER_H */ -- cgit v1.2.3 From ac2a420351a2489fc347689968767a15f863ec77 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 05:04:17 -0800 Subject: Remove the ATOMIC_THREAD_FENCE macro --- Alc/backends/base.cpp | 6 +++--- OpenAL32/alBuffer.cpp | 2 +- OpenAL32/alSource.cpp | 6 +++--- common/atomic.h | 3 --- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/Alc/backends/base.cpp b/Alc/backends/base.cpp index 61c2fe90..f3a4c60e 100644 --- a/Alc/backends/base.cpp +++ b/Alc/backends/base.cpp @@ -55,11 +55,11 @@ ClockLatency ALCbackend_getClockLatency(ALCbackend *self) ClockLatency ret; do { - while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) + while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) althrd_yield(); ret.ClockTime = GetDeviceClockTime(device); - ATOMIC_THREAD_FENCE(almemory_order_acquire); - } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); + std::atomic_thread_fence(std::memory_order_acquire); + } while(refcount != device->MixCount.load(std::memory_order_relaxed)); /* NOTE: The device will generally have about all but one periods filled at * any given time during playback. Without a more accurate measurement from diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index cd173193..b08518ba 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -656,7 +656,7 @@ AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, A * asynchronously. Currently we just say the app shouldn't write where * OpenAL's reading, and hope for the best... */ - ATOMIC_THREAD_FENCE(almemory_order_seq_cst); + std::atomic_thread_fence(std::memory_order_seq_cst); } } diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 39f70ab5..2585039f 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -3284,7 +3284,7 @@ static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALui readPos |= (ALuint64)ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) << (32-FRACTIONBITS); } - ATOMIC_THREAD_FENCE(almemory_order_acquire); + std::atomic_thread_fence(std::memory_order_acquire); } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); if(voice) @@ -3331,7 +3331,7 @@ static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint FRACTIONBITS; readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); } - ATOMIC_THREAD_FENCE(almemory_order_acquire); + std::atomic_thread_fence(std::memory_order_acquire); } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); offset = 0.0; @@ -3393,7 +3393,7 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *conte readPos = ATOMIC_LOAD(&voice->position, almemory_order_relaxed); readPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); } - ATOMIC_THREAD_FENCE(almemory_order_acquire); + std::atomic_thread_fence(std::memory_order_acquire); } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); offset = 0.0; diff --git a/common/atomic.h b/common/atomic.h index b25bd4dd..87560e3d 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -15,7 +15,6 @@ #define ATOMIC(T) std::atomic #define ATOMIC_INIT std::atomic_init -#define ATOMIC_INIT_STATIC ATOMIC_VAR_INIT #define ATOMIC_LOAD std::atomic_load_explicit #define ATOMIC_STORE std::atomic_store_explicit @@ -23,8 +22,6 @@ #define ATOMIC_ADD std::atomic_fetch_add_explicit #define ATOMIC_SUB std::atomic_fetch_sub_explicit -#define ATOMIC_THREAD_FENCE std::atomic_thread_fence - #define ATOMIC_LOAD_SEQ(_val) ATOMIC_LOAD(_val, almemory_order_seq_cst) #define ATOMIC_STORE_SEQ(_val, _newval) ATOMIC_STORE(_val, _newval, almemory_order_seq_cst) -- cgit v1.2.3 From f766437569da417cc9048cb789764c8c29cce8b0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 05:07:09 -0800 Subject: Fix a couple incorrect uses of ringbuffer pointer data --- Alc/backends/opensl.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index a53c0759..2c516021 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -300,14 +300,15 @@ static int ALCopenslPlayback_mixerProc(void *arg) for(size_t i = 0;i < todo;i++) { - if(!data[0].len) + if(!data.first.len) { - data[0] = data[1]; - data[1].buf = NULL; - data[1].len = 0; + data.first = data.second; + data.second.buf = nullptr; + data.second.len = 0; } - result = VCALL(bufferQueue,Enqueue)(data[0].buf, device->UpdateSize*self->mFrameSize); + result = VCALL(bufferQueue,Enqueue)(data.first.buf, + device->UpdateSize*self->mFrameSize); PRINTERR(result, "bufferQueue->Enqueue"); if(SL_RESULT_SUCCESS != result) { @@ -315,8 +316,8 @@ static int ALCopenslPlayback_mixerProc(void *arg) break; } - data[0].len--; - data[0].buf += device->UpdateSize*self->mFrameSize; + data.first.len--; + data.first.buf += device->UpdateSize*self->mFrameSize; } } ALCopenslPlayback_unlock(self); -- cgit v1.2.3 From f0cc34a60e65b7120a8d2d2bd5f76aebb3352685 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 06:22:09 -0800 Subject: Use a vector to handle mixing buffer storage --- Alc/alc.cpp | 27 ++++++++------------------- OpenAL32/Include/alMain.h | 3 +++ 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 879dba00..6e68d130 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1704,7 +1704,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ALCsizei hrtf_id = -1; ALCcontext *context; ALCuint oldFreq; - size_t size; ALCsizei i; int val; @@ -2002,13 +2001,14 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->ChannelDelay[i].Buffer = nullptr; } - al_free(device->Dry.Buffer); device->Dry.Buffer = nullptr; device->Dry.NumChannels = 0; device->FOAOut.Buffer = nullptr; device->FOAOut.NumChannels = 0; device->RealOut.Buffer = nullptr; device->RealOut.NumChannels = 0; + device->MixBuffer.clear(); + device->MixBuffer.shrink_to_fit(); UpdateClockBase(device); device->FixedLatency = 0; @@ -2113,17 +2113,14 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->FOAOut.NumChannels, device->RealOut.NumChannels); /* Allocate extra channels for any post-filter output. */ - size = (device->Dry.NumChannels + device->FOAOut.NumChannels + - device->RealOut.NumChannels)*sizeof(device->Dry.Buffer[0]); + ALsizei num_chans{device->Dry.NumChannels + device->FOAOut.NumChannels + + device->RealOut.NumChannels}; - TRACE("Allocating " SZFMT " channels, " SZFMT " bytes\n", size/sizeof(device->Dry.Buffer[0]), size); - device->Dry.Buffer = static_cast(al_calloc(16, size)); - if(!device->Dry.Buffer) - { - ERR("Failed to allocate " SZFMT " bytes for mix buffer\n", size); - return ALC_INVALID_DEVICE; - } + TRACE("Allocating %d channels, " SZFMT " bytes\n", num_chans, + num_chans*sizeof(device->MixBuffer[0])); + device->MixBuffer.resize(num_chans); + device->Dry.Buffer = &reinterpret_cast(device->MixBuffer[0]); if(device->RealOut.NumChannels != 0) device->RealOut.Buffer = device->Dry.Buffer + device->Dry.NumChannels + device->FOAOut.NumChannels; @@ -2461,14 +2458,6 @@ ALCdevice_struct::~ALCdevice_struct() ChannelDelay[i].Length = 0; ChannelDelay[i].Buffer = nullptr; } - - al_free(Dry.Buffer); - Dry.Buffer = nullptr; - Dry.NumChannels = 0; - FOAOut.Buffer = nullptr; - FOAOut.NumChannels = 0; - RealOut.Buffer = nullptr; - RealOut.NumChannels = 0; } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 226d39a9..53cebc1f 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -648,6 +648,9 @@ struct ALCdevice_struct { /* Temp storage used for mixer processing. */ alignas(16) ALfloat TempBuffer[4][BUFFERSIZE]; + /* Mixing buffer used by the Dry mix, FOAOut, and Real out. */ + al::vector, 16> MixBuffer; + /* The "dry" path corresponds to the main output. */ MixParams Dry; ALsizei NumChannelsPerOrder[MAX_AMBI_ORDER+1]{}; -- cgit v1.2.3 From c5c537cc5f5cb466cdf6679c9af9768301e32cc3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 06:43:37 -0800 Subject: Use proper inheritence for EffectStateFactory --- Alc/effects/autowah.cpp | 20 +++++--------------- Alc/effects/chorus.cpp | 36 ++++++++---------------------------- Alc/effects/compressor.cpp | 18 ++++-------------- Alc/effects/dedicated.cpp | 18 ++++-------------- Alc/effects/distortion.cpp | 18 ++++-------------- Alc/effects/echo.cpp | 18 ++++-------------- Alc/effects/equalizer.cpp | 18 ++++-------------- Alc/effects/fshifter.cpp | 19 +++++-------------- Alc/effects/modulator.cpp | 17 ++++------------- Alc/effects/null.cpp | 20 ++++---------------- Alc/effects/pshifter.cpp | 19 ++++--------------- Alc/effects/reverb.cpp | 18 ++++-------------- OpenAL32/Include/alAuxEffectSlot.h | 25 +++---------------------- OpenAL32/alAuxEffectSlot.cpp | 8 +++----- 14 files changed, 60 insertions(+), 212 deletions(-) diff --git a/Alc/effects/autowah.cpp b/Alc/effects/autowah.cpp index a8e4fe6e..eb2696fe 100644 --- a/Alc/effects/autowah.cpp +++ b/Alc/effects/autowah.cpp @@ -207,33 +207,23 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, } struct AutowahStateFactory final : public EffectStateFactory { - AutowahStateFactory() noexcept; + ALeffectState *create() override; }; -static ALeffectState *AutowahStateFactory_create(AutowahStateFactory *UNUSED(factory)) +ALeffectState *AutowahStateFactory::create() { ALautowahState *state; - NEW_OBJ0(state, ALautowahState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(AutowahStateFactory); - -AutowahStateFactory::AutowahStateFactory() noexcept - : EffectStateFactory{GET_VTABLE2(AutowahStateFactory, EffectStateFactory)} -{ + return state; } EffectStateFactory *AutowahStateFactory_getFactory(void) { static AutowahStateFactory AutowahFactory{}; - - return STATIC_CAST(EffectStateFactory, &AutowahFactory); + return &AutowahFactory; } + void ALautowah_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) { ALeffectProps *props = &effect->Props; diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp index 411ba6a5..62691887 100644 --- a/Alc/effects/chorus.cpp +++ b/Alc/effects/chorus.cpp @@ -286,30 +286,20 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, c struct ChorusStateFactory final : public EffectStateFactory { - ChorusStateFactory() noexcept; + ALeffectState *create() override; }; -static ALeffectState *ChorusStateFactory_create(ChorusStateFactory *UNUSED(factory)) +ALeffectState *ChorusStateFactory::create() { ALchorusState *state; - NEW_OBJ0(state, ALchorusState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(ChorusStateFactory); - -ChorusStateFactory::ChorusStateFactory() noexcept - : EffectStateFactory{GET_VTABLE2(ChorusStateFactory, EffectStateFactory)} -{ + return state; } EffectStateFactory *ChorusStateFactory_getFactory(void) { static ChorusStateFactory ChorusFactory{}; - return STATIC_CAST(EffectStateFactory, &ChorusFactory); + return &ChorusFactory; } @@ -426,30 +416,20 @@ DEFINE_ALEFFECT_VTABLE(ALchorus); * the same processing functions, so piggyback flanger on the chorus functions. */ struct FlangerStateFactory final : public EffectStateFactory { - FlangerStateFactory() noexcept; + ALeffectState *create() override; }; -ALeffectState *FlangerStateFactory_create(FlangerStateFactory *UNUSED(factory)) +ALeffectState *FlangerStateFactory::create() { ALchorusState *state; - NEW_OBJ0(state, ALchorusState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(FlangerStateFactory); - -FlangerStateFactory::FlangerStateFactory() noexcept - : EffectStateFactory{GET_VTABLE2(FlangerStateFactory, EffectStateFactory)} -{ + return state; } EffectStateFactory *FlangerStateFactory_getFactory(void) { static FlangerStateFactory FlangerFactory{}; - return STATIC_CAST(EffectStateFactory, &FlangerFactory); + return &FlangerFactory; } diff --git a/Alc/effects/compressor.cpp b/Alc/effects/compressor.cpp index 464e98ec..cd6c72db 100644 --- a/Alc/effects/compressor.cpp +++ b/Alc/effects/compressor.cpp @@ -177,30 +177,20 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei Sample struct CompressorStateFactory final : public EffectStateFactory { - CompressorStateFactory() noexcept; + ALeffectState *create() override; }; -static ALeffectState *CompressorStateFactory_create(CompressorStateFactory *UNUSED(factory)) +ALeffectState *CompressorStateFactory::create() { ALcompressorState *state; - NEW_OBJ0(state, ALcompressorState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(CompressorStateFactory); - -CompressorStateFactory::CompressorStateFactory() noexcept - : EffectStateFactory{GET_VTABLE2(CompressorStateFactory, EffectStateFactory)} -{ + return state; } EffectStateFactory *CompressorStateFactory_getFactory(void) { static CompressorStateFactory CompressorFactory{}; - return STATIC_CAST(EffectStateFactory, &CompressorFactory); + return &CompressorFactory; } diff --git a/Alc/effects/dedicated.cpp b/Alc/effects/dedicated.cpp index 705f7d41..59f31b52 100644 --- a/Alc/effects/dedicated.cpp +++ b/Alc/effects/dedicated.cpp @@ -115,30 +115,20 @@ static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesT struct DedicatedStateFactory final : public EffectStateFactory { - DedicatedStateFactory() noexcept; + ALeffectState *create() override; }; -ALeffectState *DedicatedStateFactory_create(DedicatedStateFactory *UNUSED(factory)) +ALeffectState *DedicatedStateFactory::create() { ALdedicatedState *state; - NEW_OBJ0(state, ALdedicatedState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(DedicatedStateFactory); - -DedicatedStateFactory::DedicatedStateFactory() noexcept - : EffectStateFactory{GET_VTABLE2(DedicatedStateFactory, EffectStateFactory)} -{ + return state; } EffectStateFactory *DedicatedStateFactory_getFactory(void) { static DedicatedStateFactory DedicatedFactory{}; - return STATIC_CAST(EffectStateFactory, &DedicatedFactory); + return &DedicatedFactory; } diff --git a/Alc/effects/distortion.cpp b/Alc/effects/distortion.cpp index 7dd15981..31f07de3 100644 --- a/Alc/effects/distortion.cpp +++ b/Alc/effects/distortion.cpp @@ -176,30 +176,20 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei Sample struct DistortionStateFactory final : public EffectStateFactory { - DistortionStateFactory() noexcept; + ALeffectState *create() override; }; -static ALeffectState *DistortionStateFactory_create(DistortionStateFactory *UNUSED(factory)) +ALeffectState *DistortionStateFactory::create() { ALdistortionState *state; - NEW_OBJ0(state, ALdistortionState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(DistortionStateFactory); - -DistortionStateFactory::DistortionStateFactory() noexcept - : EffectStateFactory{GET_VTABLE2(DistortionStateFactory, EffectStateFactory)} -{ + return state; } EffectStateFactory *DistortionStateFactory_getFactory(void) { static DistortionStateFactory DistortionFactory{}; - return STATIC_CAST(EffectStateFactory, &DistortionFactory); + return &DistortionFactory; } diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index 492da6f6..47d21e6c 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -203,30 +203,20 @@ static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const struct EchoStateFactory final : public EffectStateFactory { - EchoStateFactory() noexcept; + ALeffectState *create() override; }; -ALeffectState *EchoStateFactory_create(EchoStateFactory *UNUSED(factory)) +ALeffectState *EchoStateFactory::create() { ALechoState *state; - NEW_OBJ0(state, ALechoState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(EchoStateFactory); - -EchoStateFactory::EchoStateFactory() noexcept - : EffectStateFactory{GET_VTABLE2(EchoStateFactory, EffectStateFactory)} -{ + return state; } EffectStateFactory *EchoStateFactory_getFactory(void) { static EchoStateFactory EchoFactory{}; - return STATIC_CAST(EffectStateFactory, &EchoFactory); + return &EchoFactory; } diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index e8d50fad..17eee5b4 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -199,30 +199,20 @@ static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesT struct EqualizerStateFactory final : public EffectStateFactory { - EqualizerStateFactory() noexcept; + ALeffectState *create() override; }; -ALeffectState *EqualizerStateFactory_create(EqualizerStateFactory *UNUSED(factory)) +ALeffectState *EqualizerStateFactory::create() { ALequalizerState *state; - NEW_OBJ0(state, ALequalizerState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(EqualizerStateFactory); - -EqualizerStateFactory::EqualizerStateFactory() noexcept - : EffectStateFactory{GET_VTABLE2(EqualizerStateFactory, EffectStateFactory)} -{ + return state; } EffectStateFactory *EqualizerStateFactory_getFactory(void) { static EqualizerStateFactory EqualizerFactory{}; - return STATIC_CAST(EffectStateFactory, &EqualizerFactory); + return &EqualizerFactory; } diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp index f112c4c7..7775fafb 100644 --- a/Alc/effects/fshifter.cpp +++ b/Alc/effects/fshifter.cpp @@ -218,32 +218,23 @@ ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, cons } // namespace struct FshifterStateFactory final : public EffectStateFactory { - FshifterStateFactory() noexcept; + ALeffectState *create() override; }; -static ALeffectState *FshifterStateFactory_create(FshifterStateFactory *UNUSED(factory)) +ALeffectState *FshifterStateFactory::create() { ALfshifterState *state; - NEW_OBJ0(state, ALfshifterState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(FshifterStateFactory); - -FshifterStateFactory::FshifterStateFactory() noexcept - : EffectStateFactory{GET_VTABLE2(FshifterStateFactory, EffectStateFactory)} -{ + return state; } EffectStateFactory *FshifterStateFactory_getFactory(void) { static FshifterStateFactory FshifterFactory{}; - return STATIC_CAST(EffectStateFactory, &FshifterFactory); + return &FshifterFactory; } + void ALfshifter_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) { ALeffectProps *props = &effect->Props; diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index 9790af79..e96859f7 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -197,29 +197,20 @@ static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesT struct ModulatorStateFactory final : public EffectStateFactory { - ModulatorStateFactory() noexcept; + ALeffectState *create() override; }; -static ALeffectState *ModulatorStateFactory_create(ModulatorStateFactory *UNUSED(factory)) +ALeffectState *ModulatorStateFactory::create() { ALmodulatorState *state; - NEW_OBJ0(state, ALmodulatorState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); + return state; } -DEFINE_EFFECTSTATEFACTORY_VTABLE(ModulatorStateFactory); - -ModulatorStateFactory::ModulatorStateFactory() noexcept - : EffectStateFactory{GET_VTABLE2(ModulatorStateFactory, EffectStateFactory)} -{ } - EffectStateFactory *ModulatorStateFactory_getFactory(void) { static ModulatorStateFactory ModulatorFactory{}; - return STATIC_CAST(EffectStateFactory, &ModulatorFactory); + return &ModulatorFactory; } diff --git a/Alc/effects/null.cpp b/Alc/effects/null.cpp index 0d85d505..f5641e20 100644 --- a/Alc/effects/null.cpp +++ b/Alc/effects/null.cpp @@ -89,33 +89,21 @@ static void ALnullState_Delete(void *ptr) struct NullStateFactory final : public EffectStateFactory { - NullStateFactory() noexcept; + ALeffectState *create() override; }; /* Creates ALeffectState objects of the appropriate type. */ -ALeffectState *NullStateFactory_create(NullStateFactory *UNUSED(factory)) +ALeffectState *NullStateFactory::create() { ALnullState *state; - NEW_OBJ0(state, ALnullState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); + return state; } -/* Define the EffectStateFactory vtable for this type. */ -DEFINE_EFFECTSTATEFACTORY_VTABLE(NullStateFactory); - -NullStateFactory::NullStateFactory() noexcept - : EffectStateFactory{GET_VTABLE2(NullStateFactory, EffectStateFactory)} -{ -} - - EffectStateFactory *NullStateFactory_getFactory(void) { static NullStateFactory NullFactory{}; - return STATIC_CAST(EffectStateFactory, &NullFactory); + return &NullFactory; } diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp index 1199a19d..217b021e 100644 --- a/Alc/effects/pshifter.cpp +++ b/Alc/effects/pshifter.cpp @@ -335,31 +335,20 @@ ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, cons } // namespace struct PshifterStateFactory final : public EffectStateFactory { - PshifterStateFactory() noexcept; + ALeffectState *create() override; }; -static ALeffectState *PshifterStateFactory_create(PshifterStateFactory *UNUSED(factory)) +ALeffectState *PshifterStateFactory::create() { ALpshifterState *state; - NEW_OBJ0(state, ALpshifterState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(PshifterStateFactory); - - -PshifterStateFactory::PshifterStateFactory() noexcept - : EffectStateFactory{GET_VTABLE2(PshifterStateFactory, EffectStateFactory)} -{ + return state; } EffectStateFactory *PshifterStateFactory_getFactory(void) { static PshifterStateFactory PshifterFactory{}; - return STATIC_CAST(EffectStateFactory, &PshifterFactory); + return &PshifterFactory; } diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 702a8cdd..d486e8b4 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -1586,30 +1586,20 @@ static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const struct ReverbStateFactory final : public EffectStateFactory { - ReverbStateFactory() noexcept; + ALeffectState *create() override; }; -static ALeffectState *ReverbStateFactory_create(ReverbStateFactory* UNUSED(factory)) +ALeffectState *ReverbStateFactory::create() { ReverbState *state; - NEW_OBJ0(state, ReverbState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(ReverbStateFactory); - -ReverbStateFactory::ReverbStateFactory() noexcept - : EffectStateFactory{GET_VTABLE2(ReverbStateFactory, EffectStateFactory)} -{ + return state; } EffectStateFactory *ReverbStateFactory_getFactory(void) { static ReverbStateFactory ReverbFactory{}; - return STATIC_CAST(EffectStateFactory, &ReverbFactory); + return &ReverbFactory; } diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 815ae77e..d3d4e704 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -7,9 +7,6 @@ #include "almalloc.h" #include "atomic.h" -#ifdef __cplusplus -extern "C" { -#endif struct ALeffectStateVtable; struct ALeffectslot; @@ -59,23 +56,11 @@ static const struct ALeffectStateVtable T##_ALeffectState_vtable = { \ } -struct EffectStateFactoryVtable; - -typedef struct EffectStateFactory { - const struct EffectStateFactoryVtable *vtab; -} EffectStateFactory; +struct EffectStateFactory { + virtual ~EffectStateFactory() { } -struct EffectStateFactoryVtable { - ALeffectState *(*const create)(EffectStateFactory *factory); + virtual ALeffectState *create() = 0; }; -#define EffectStateFactory_create(x) ((x)->vtab->create((x))) - -#define DEFINE_EFFECTSTATEFACTORY_VTABLE(T) \ -DECLARE_THUNK(T, EffectStateFactory, ALeffectState*, create) \ - \ -static const struct EffectStateFactoryVtable T##_EffectStateFactory_vtable = { \ - T##_EffectStateFactory_create, \ -} #define MAX_EFFECT_CHANNELS (4) @@ -184,8 +169,4 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect void ALeffectState_DecRef(ALeffectState *state); -#ifdef __cplusplus -} -#endif - #endif diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index ff0f7eaa..4e25d3ee 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -487,15 +487,13 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect if(newtype != EffectSlot->Effect.Type) { - EffectStateFactory *factory; - - factory = getFactoryByType(newtype); + EffectStateFactory *factory = getFactoryByType(newtype); if(!factory) { ERR("Failed to find factory for effect type 0x%04x\n", newtype); return AL_INVALID_ENUM; } - State = EffectStateFactory_create(factory); + State = factory->create(); if(!State) return AL_OUT_OF_MEMORY; START_MIXER_MODE(); @@ -663,7 +661,7 @@ static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcon ALenum InitEffectSlot(ALeffectslot *slot) { EffectStateFactory *factory{getFactoryByType(slot->Effect.Type)}; - slot->Effect.State = EffectStateFactory_create(factory); + slot->Effect.State = factory->create(); if(!slot->Effect.State) return AL_OUT_OF_MEMORY; ALeffectState_IncRef(slot->Effect.State); -- cgit v1.2.3 From f51f6703d8058e25981bfbfe2190b106f700be6d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 06:50:37 -0800 Subject: Add a missing include --- OpenAL32/Include/alMain.h | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 53cebc1f..64297592 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -16,6 +16,7 @@ #include #endif +#include #include #include -- cgit v1.2.3 From 07386e79de93988faccc98166a036b6234ff9fe1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 09:06:17 -0800 Subject: Fix up the struct member names in the autowah effect --- Alc/effects/autowah.cpp | 112 +++++++++++++++++++++++++----------------------- 1 file changed, 58 insertions(+), 54 deletions(-) diff --git a/Alc/effects/autowah.cpp b/Alc/effects/autowah.cpp index eb2696fe..4cf79998 100644 --- a/Alc/effects/autowah.cpp +++ b/Alc/effects/autowah.cpp @@ -23,6 +23,8 @@ #include #include +#include + #include "alMain.h" #include "alcontext.h" #include "alAuxEffectSlot.h" @@ -37,19 +39,19 @@ struct ALautowahState final : public ALeffectState { /* Effect parameters */ - ALfloat AttackRate; - ALfloat ReleaseRate; - ALfloat ResonanceGain; - ALfloat PeakGain; - ALfloat FreqMinNorm; - ALfloat BandwidthNorm; - ALfloat env_delay; + ALfloat mAttackRate; + ALfloat mReleaseRate; + ALfloat mResonanceGain; + ALfloat mPeakGain; + ALfloat mFreqMinNorm; + ALfloat mBandwidthNorm; + ALfloat mEnvDelay; /* Filter components derived from the envelope. */ struct { ALfloat cos_w0; ALfloat alpha; - } Env[BUFFERSIZE]; + } mEnv[BUFFERSIZE]; struct { /* Effect filters' history. */ @@ -60,10 +62,10 @@ struct ALautowahState final : public ALeffectState { /* Effect gains for each output channel */ ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; - } Chans[MAX_EFFECT_CHANNELS]; + } mChans[MAX_EFFECT_CHANNELS]; /* Effects buffers */ - alignas(16) ALfloat BufferOut[BUFFERSIZE]; + alignas(16) ALfloat mBufferOut[BUFFERSIZE]; }; static ALvoid ALautowahState_Destruct(ALautowahState *state); @@ -77,37 +79,39 @@ DEFINE_ALEFFECTSTATE_VTABLE(ALautowahState); static void ALautowahState_Construct(ALautowahState *state) { new (state) ALautowahState{}; - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + ALeffectState_Construct(state); SET_VTABLE2(ALautowahState, ALeffectState, state); } static ALvoid ALautowahState_Destruct(ALautowahState *state) { - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); + ALeffectState_Destruct(state); state->~ALautowahState(); } static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *UNUSED(device)) { /* (Re-)initializing parameters and clear the buffers. */ - ALsizei i, j; - state->AttackRate = 1.0f; - state->ReleaseRate = 1.0f; - state->ResonanceGain = 10.0f; - state->PeakGain = 4.5f; - state->FreqMinNorm = 4.5e-4f; - state->BandwidthNorm = 0.05f; - state->env_delay = 0.0f; + state->mAttackRate = 1.0f; + state->mReleaseRate = 1.0f; + state->mResonanceGain = 10.0f; + state->mPeakGain = 4.5f; + state->mFreqMinNorm = 4.5e-4f; + state->mBandwidthNorm = 0.05f; + state->mEnvDelay = 0.0f; - memset(state->Env, 0, sizeof(state->Env)); + for(auto &e : state->mEnv) + { + e.cos_w0 = 0.0f; + e.alpha = 0.0f; + } - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + for(auto &chan : state->mChans) { - for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - state->Chans[i].CurrentGains[j] = 0.0f; - state->Chans[i].Filter.z1 = 0.0f; - state->Chans[i].Filter.z2 = 0.0f; + std::fill(std::begin(chan.CurrentGains), std::end(chan.CurrentGains), 0.0f); + chan.Filter.z1 = 0.0f; + chan.Filter.z2 = 0.0f; } return AL_TRUE; @@ -121,33 +125,33 @@ static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *con ReleaseTime = clampf(props->Autowah.ReleaseTime, 0.001f, 1.0f); - state->AttackRate = expf(-1.0f / (props->Autowah.AttackTime*device->Frequency)); - state->ReleaseRate = expf(-1.0f / (ReleaseTime*device->Frequency)); + state->mAttackRate = expf(-1.0f / (props->Autowah.AttackTime*device->Frequency)); + state->mReleaseRate = expf(-1.0f / (ReleaseTime*device->Frequency)); /* 0-20dB Resonance Peak gain */ - state->ResonanceGain = sqrtf(log10f(props->Autowah.Resonance)*10.0f / 3.0f); - state->PeakGain = 1.0f - log10f(props->Autowah.PeakGain/AL_AUTOWAH_MAX_PEAK_GAIN); - state->FreqMinNorm = MIN_FREQ / device->Frequency; - state->BandwidthNorm = (MAX_FREQ-MIN_FREQ) / device->Frequency; + state->mResonanceGain = sqrtf(log10f(props->Autowah.Resonance)*10.0f / 3.0f); + state->mPeakGain = 1.0f - log10f(props->Autowah.PeakGain/AL_AUTOWAH_MAX_PEAK_GAIN); + state->mFreqMinNorm = MIN_FREQ / device->Frequency; + state->mBandwidthNorm = (MAX_FREQ-MIN_FREQ) / device->Frequency; - STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; - STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; + state->OutBuffer = device->FOAOut.Buffer; + state->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain, - state->Chans[i].TargetGains); + state->mChans[i].TargetGains); } static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - const ALfloat attack_rate = state->AttackRate; - const ALfloat release_rate = state->ReleaseRate; - const ALfloat res_gain = state->ResonanceGain; - const ALfloat peak_gain = state->PeakGain; - const ALfloat freq_min = state->FreqMinNorm; - const ALfloat bandwidth = state->BandwidthNorm; + const ALfloat attack_rate = state->mAttackRate; + const ALfloat release_rate = state->mReleaseRate; + const ALfloat res_gain = state->mResonanceGain; + const ALfloat peak_gain = state->mPeakGain; + const ALfloat freq_min = state->mFreqMinNorm; + const ALfloat bandwidth = state->mBandwidthNorm; ALfloat env_delay; ALsizei c, i; - env_delay = state->env_delay; + env_delay = state->mEnvDelay; for(i = 0;i < SamplesToDo;i++) { ALfloat w0, sample, a; @@ -161,10 +165,10 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, /* Calculate the cos and alpha components for this sample's filter. */ w0 = minf((bandwidth*env_delay + freq_min), 0.46f) * F_TAU; - state->Env[i].cos_w0 = cosf(w0); - state->Env[i].alpha = sinf(w0)/(2.0f * Q_FACTOR); + state->mEnv[i].cos_w0 = cosf(w0); + state->mEnv[i].alpha = sinf(w0)/(2.0f * Q_FACTOR); } - state->env_delay = env_delay; + state->mEnvDelay = env_delay; for(c = 0;c < MAX_EFFECT_CHANNELS; c++) { @@ -174,13 +178,13 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, * envelope. Because the filter changes for each sample, the * coefficients are transient and don't need to be held. */ - ALfloat z1 = state->Chans[c].Filter.z1; - ALfloat z2 = state->Chans[c].Filter.z2; + ALfloat z1 = state->mChans[c].Filter.z1; + ALfloat z2 = state->mChans[c].Filter.z2; for(i = 0;i < SamplesToDo;i++) { - const ALfloat alpha = state->Env[i].alpha; - const ALfloat cos_w0 = state->Env[i].cos_w0; + const ALfloat alpha = state->mEnv[i].alpha; + const ALfloat cos_w0 = state->mEnv[i].cos_w0; ALfloat input, output; ALfloat a[3], b[3]; @@ -195,14 +199,14 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, output = input*(b[0]/a[0]) + z1; z1 = input*(b[1]/a[0]) - output*(a[1]/a[0]) + z2; z2 = input*(b[2]/a[0]) - output*(a[2]/a[0]); - state->BufferOut[i] = output; + state->mBufferOut[i] = output; } - state->Chans[c].Filter.z1 = z1; - state->Chans[c].Filter.z2 = z2; + state->mChans[c].Filter.z1 = z1; + state->mChans[c].Filter.z2 = z2; /* Now, mix the processed sound data to the output. */ - MixSamples(state->BufferOut, NumChannels, SamplesOut, state->Chans[c].CurrentGains, - state->Chans[c].TargetGains, SamplesToDo, 0, SamplesToDo); + MixSamples(state->mBufferOut, NumChannels, SamplesOut, state->mChans[c].CurrentGains, + state->mChans[c].TargetGains, SamplesToDo, 0, SamplesToDo); } } -- cgit v1.2.3 From 387a34ca002bdc25cc31fb8514c0fa2e44af6e1b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 09:10:36 -0800 Subject: Clean up the biquad filter a bit --- Alc/alu.cpp | 8 ++++---- Alc/effects/distortion.cpp | 4 ++-- Alc/effects/echo.cpp | 2 +- Alc/effects/equalizer.cpp | 8 ++++---- Alc/effects/modulator.cpp | 2 +- Alc/effects/reverb.cpp | 8 ++++---- Alc/filters/defs.h | 43 ++++++++++++++++++++----------------------- Alc/filters/filter.cpp | 24 +++++++++++++----------- 8 files changed, 49 insertions(+), 50 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index b4b34e5f..e30f6a2e 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -973,11 +973,11 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo if(gainHF != 1.0f) voice->Direct.FilterType |= AF_LowPass; if(gainLF != 1.0f) voice->Direct.FilterType |= AF_HighPass; BiquadFilter_setParams( - &voice->Direct.Params[0].LowPass, BiquadType_HighShelf, + &voice->Direct.Params[0].LowPass, BiquadType::HighShelf, gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) ); BiquadFilter_setParams( - &voice->Direct.Params[0].HighPass, BiquadType_LowShelf, + &voice->Direct.Params[0].HighPass, BiquadType::LowShelf, gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) ); for(c = 1;c < num_channels;c++) @@ -999,11 +999,11 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo if(gainHF != 1.0f) voice->Send[i].FilterType |= AF_LowPass; if(gainLF != 1.0f) voice->Send[i].FilterType |= AF_HighPass; BiquadFilter_setParams( - &voice->Send[i].Params[0].LowPass, BiquadType_HighShelf, + &voice->Send[i].Params[0].LowPass, BiquadType::HighShelf, gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) ); BiquadFilter_setParams( - &voice->Send[i].Params[0].HighPass, BiquadType_LowShelf, + &voice->Send[i].Params[0].HighPass, BiquadType::LowShelf, gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) ); for(c = 1;c < num_channels;c++) diff --git a/Alc/effects/distortion.cpp b/Alc/effects/distortion.cpp index 31f07de3..69603db9 100644 --- a/Alc/effects/distortion.cpp +++ b/Alc/effects/distortion.cpp @@ -93,14 +93,14 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontex /* Multiply sampling frequency by the amount of oversampling done during * processing. */ - BiquadFilter_setParams(&state->lowpass, BiquadType_LowPass, 1.0f, + BiquadFilter_setParams(&state->lowpass, BiquadType::LowPass, 1.0f, cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); cutoff = props->Distortion.EQCenter; /* Convert bandwidth in Hz to octaves. */ bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f); - BiquadFilter_setParams(&state->bandpass, BiquadType_BandPass, 1.0f, + BiquadFilter_setParams(&state->bandpass, BiquadType::BandPass, 1.0f, cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index 47d21e6c..946c07b4 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -136,7 +136,7 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, state->FeedGain = props->Echo.Feedback; gainhf = maxf(1.0f - props->Echo.Damping, 0.0625f); /* Limit -24dB */ - BiquadFilter_setParams(&state->Filter, BiquadType_HighShelf, + BiquadFilter_setParams(&state->Filter, BiquadType::HighShelf, gainhf, LOWPASSFREQREF/frequency, calc_rcpQ_from_slope(gainhf, 1.0f) ); diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index 17eee5b4..ad101a7e 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -136,13 +136,13 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext */ gain = maxf(sqrtf(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */ f0norm = props->Equalizer.LowCutoff/frequency; - BiquadFilter_setParams(&state->Chans[0].filter[0], BiquadType_LowShelf, + BiquadFilter_setParams(&state->Chans[0].filter[0], BiquadType::LowShelf, gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f) ); gain = maxf(props->Equalizer.Mid1Gain, 0.0625f); f0norm = props->Equalizer.Mid1Center/frequency; - BiquadFilter_setParams(&state->Chans[0].filter[1], BiquadType_Peaking, + BiquadFilter_setParams(&state->Chans[0].filter[1], BiquadType::Peaking, gain, f0norm, calc_rcpQ_from_bandwidth( f0norm, props->Equalizer.Mid1Width ) @@ -150,7 +150,7 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext gain = maxf(props->Equalizer.Mid2Gain, 0.0625f); f0norm = props->Equalizer.Mid2Center/frequency; - BiquadFilter_setParams(&state->Chans[0].filter[2], BiquadType_Peaking, + BiquadFilter_setParams(&state->Chans[0].filter[2], BiquadType::Peaking, gain, f0norm, calc_rcpQ_from_bandwidth( f0norm, props->Equalizer.Mid2Width ) @@ -158,7 +158,7 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext gain = maxf(sqrtf(props->Equalizer.HighGain), 0.0625f); f0norm = props->Equalizer.HighCutoff/frequency; - BiquadFilter_setParams(&state->Chans[0].filter[3], BiquadType_HighShelf, + BiquadFilter_setParams(&state->Chans[0].filter[3], BiquadType::HighShelf, gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f) ); diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index e96859f7..b7ee97d9 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -152,7 +152,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext f0norm = props->Modulator.HighPassCutoff / (ALfloat)device->Frequency; f0norm = clampf(f0norm, 1.0f/512.0f, 0.49f); /* Bandwidth value is constant in octaves. */ - BiquadFilter_setParams(&state->Chans[0].Filter, BiquadType_HighPass, 1.0f, + BiquadFilter_setParams(&state->Chans[0].Filter, BiquadType::HighPass, 1.0f, f0norm, calc_rcpQ_from_bandwidth(f0norm, 0.75f)); for(i = 1;i < MAX_EFFECT_CHANNELS;i++) BiquadFilter_copyParams(&state->Chans[i].Filter, &state->Chans[0].Filter); diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index d486e8b4..68c76337 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -728,9 +728,9 @@ static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime ALfloat hfGain = CalcDecayCoeff(length, hfDecayTime); filter->MidGain[1] = mfGain; - BiquadFilter_setParams(&filter->LFFilter, BiquadType_LowShelf, lfGain/mfGain, lf0norm, + BiquadFilter_setParams(&filter->LFFilter, BiquadType::LowShelf, lfGain/mfGain, lf0norm, calc_rcpQ_from_slope(lfGain/mfGain, 1.0f)); - BiquadFilter_setParams(&filter->HFFilter, BiquadType_HighShelf, hfGain/mfGain, hf0norm, + BiquadFilter_setParams(&filter->HFFilter, BiquadType::HighShelf, hfGain/mfGain, hf0norm, calc_rcpQ_from_slope(hfGain/mfGain, 1.0f)); } @@ -964,11 +964,11 @@ static void ReverbState_update(ReverbState *State, const ALCcontext *Context, co * killing most of the signal. */ gainhf = maxf(props->Reverb.GainHF, 0.001f); - BiquadFilter_setParams(&State->Filter[0].Lp, BiquadType_HighShelf, gainhf, hf0norm, + BiquadFilter_setParams(&State->Filter[0].Lp, BiquadType::HighShelf, gainhf, hf0norm, calc_rcpQ_from_slope(gainhf, 1.0f)); lf0norm = minf(props->Reverb.LFReference / frequency, 0.49f); gainlf = maxf(props->Reverb.GainLF, 0.001f); - BiquadFilter_setParams(&State->Filter[0].Hp, BiquadType_LowShelf, gainlf, lf0norm, + BiquadFilter_setParams(&State->Filter[0].Hp, BiquadType::LowShelf, gainlf, lf0norm, calc_rcpQ_from_slope(gainlf, 1.0f)); for(i = 1;i < NUM_LINES;i++) { diff --git a/Alc/filters/defs.h b/Alc/filters/defs.h index 58b7cc0a..19514b62 100644 --- a/Alc/filters/defs.h +++ b/Alc/filters/defs.h @@ -1,12 +1,11 @@ #ifndef ALC_FILTER_H #define ALC_FILTER_H +#include + #include "AL/al.h" #include "math_defs.h" -#ifdef __cplusplus -extern "C" { -#endif /* Filters implementation is based on the "Cookbook formulae for audio * EQ biquad filter coefficients" by Robert Bristow-Johnson @@ -18,28 +17,30 @@ extern "C" { * the square root of the desired linear gain (or halve the dB gain). */ -typedef enum BiquadType { +enum class BiquadType { /** EFX-style low-pass filter, specifying a gain and reference frequency. */ - BiquadType_HighShelf, + HighShelf, /** EFX-style high-pass filter, specifying a gain and reference frequency. */ - BiquadType_LowShelf, + LowShelf, /** Peaking filter, specifying a gain and reference frequency. */ - BiquadType_Peaking, + Peaking, /** Low-pass cut-off filter, specifying a cut-off frequency. */ - BiquadType_LowPass, + LowPass, /** High-pass cut-off filter, specifying a cut-off frequency. */ - BiquadType_HighPass, + HighPass, /** Band-pass filter, specifying a center frequency. */ - BiquadType_BandPass, -} BiquadType; + BandPass, +}; -typedef struct BiquadFilter { - ALfloat z1, z2; /* Last two delayed components for direct form II. */ - ALfloat b0, b1, b2; /* Transfer function coefficients "b" (numerator) */ - ALfloat a1, a2; /* Transfer function coefficients "a" (denominator; a0 is - * pre-applied). */ -} BiquadFilter; +struct BiquadFilter { + /* Last two delayed components for direct form II. */ + ALfloat z1{0.0f}, z2{0.0f}; + /* Transfer function coefficients "b" (numerator) */ + ALfloat b0{1.0f}, b1{0.0f}, b2{0.0f}; + /* Transfer function coefficients "a" (denominator; a0 is pre-applied). */ + ALfloat a1{0.0f}, a2{0.0f}; +}; /* Currently only a C-based filter process method is implemented. */ #define BiquadFilter_process BiquadFilter_processC @@ -51,7 +52,7 @@ typedef struct BiquadFilter { */ inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope) { - return sqrtf((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f); + return std::sqrt((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f); } /** * Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the normalized @@ -62,7 +63,7 @@ inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope) inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth) { ALfloat w0 = F_TAU * f0norm; - return 2.0f*sinhf(logf(2.0f)/2.0f*bandwidth*w0/sinf(w0)); + return 2.0f*std::sinh(std::log(2.0f)/2.0f*bandwidth*w0/std::sin(w0)); } inline void BiquadFilter_clear(BiquadFilter *filter) @@ -113,8 +114,4 @@ inline void BiquadFilter_passthru(BiquadFilter *filter, ALsizei numsamples) } } -#ifdef __cplusplus -} // extern "C" -#endif - #endif /* ALC_FILTER_H */ diff --git a/Alc/filters/filter.cpp b/Alc/filters/filter.cpp index 838a9a5d..6099cf13 100644 --- a/Alc/filters/filter.cpp +++ b/Alc/filters/filter.cpp @@ -1,6 +1,8 @@ #include "config.h" +#include + #include "AL/alc.h" #include "AL/al.h" @@ -19,15 +21,15 @@ void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, assert(gain > 0.00001f); w0 = F_TAU * f0norm; - sin_w0 = sinf(w0); - cos_w0 = cosf(w0); + sin_w0 = std::sin(w0); + cos_w0 = std::cos(w0); alpha = sin_w0/2.0f * rcpQ; /* Calculate filter coefficients depending on filter type */ switch(type) { - case BiquadType_HighShelf: - sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha; + case BiquadType::HighShelf: + sqrtgain_alpha_2 = 2.0f * std::sqrt(gain) * alpha; b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 ); b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); @@ -35,8 +37,8 @@ void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 ); a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; break; - case BiquadType_LowShelf: - sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha; + case BiquadType::LowShelf: + sqrtgain_alpha_2 = 2.0f * std::sqrt(gain) * alpha; b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 ); b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); @@ -44,8 +46,8 @@ void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 ); a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; break; - case BiquadType_Peaking: - gain = sqrtf(gain); + case BiquadType::Peaking: + gain = std::sqrt(gain); b[0] = 1.0f + alpha * gain; b[1] = -2.0f * cos_w0; b[2] = 1.0f - alpha * gain; @@ -54,7 +56,7 @@ void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, a[2] = 1.0f - alpha / gain; break; - case BiquadType_LowPass: + case BiquadType::LowPass: b[0] = (1.0f - cos_w0) / 2.0f; b[1] = 1.0f - cos_w0; b[2] = (1.0f - cos_w0) / 2.0f; @@ -62,7 +64,7 @@ void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, a[1] = -2.0f * cos_w0; a[2] = 1.0f - alpha; break; - case BiquadType_HighPass: + case BiquadType::HighPass: b[0] = (1.0f + cos_w0) / 2.0f; b[1] = -(1.0f + cos_w0); b[2] = (1.0f + cos_w0) / 2.0f; @@ -70,7 +72,7 @@ void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, a[1] = -2.0f * cos_w0; a[2] = 1.0f - alpha; break; - case BiquadType_BandPass: + case BiquadType::BandPass: b[0] = alpha; b[1] = 0; b[2] = -alpha; -- cgit v1.2.3 From 55637ff1fc9a2d815e46bafcae3430c43e1b1eee Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 09:29:22 -0800 Subject: Rename reverb struct members --- Alc/effects/reverb.cpp | 448 ++++++++++++++++++++++++------------------------- 1 file changed, 224 insertions(+), 224 deletions(-) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 68c76337..4fef38d1 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -280,8 +280,8 @@ struct ReverbState final : public ALeffectState { /* All delay lines are allocated as a single buffer to reduce memory * fragmentation and management code. */ - ALfloat *SampleBuffer; - ALuint TotalSamples; + ALfloat *mSampleBuffer; + ALuint mTotalSamples; struct { /* Calculated parameters which indicate if cross-fading is needed after @@ -290,45 +290,45 @@ struct ReverbState final : public ALeffectState { ALfloat Density, Diffusion; ALfloat DecayTime, HFDecayTime, LFDecayTime; ALfloat HFReference, LFReference; - } Params; + } mParams; /* Master effect filters */ struct { BiquadFilter Lp; BiquadFilter Hp; - } Filter[NUM_LINES]; + } mFilter[NUM_LINES]; /* Core delay line (early reflections and late reverb tap from this). */ - DelayLineI Delay; + DelayLineI mDelay; /* Tap points for early reflection delay. */ - ALsizei EarlyDelayTap[NUM_LINES][2]; - ALfloat EarlyDelayCoeff[NUM_LINES][2]; + ALsizei mEarlyDelayTap[NUM_LINES][2]; + ALfloat mEarlyDelayCoeff[NUM_LINES][2]; /* Tap points for late reverb feed and delay. */ - ALsizei LateFeedTap; - ALsizei LateDelayTap[NUM_LINES][2]; + ALsizei mLateFeedTap; + ALsizei mLateDelayTap[NUM_LINES][2]; /* Coefficients for the all-pass and line scattering matrices. */ - ALfloat MixX; - ALfloat MixY; + ALfloat mMixX; + ALfloat mMixY; - EarlyReflections Early; + EarlyReflections mEarly; - LateReverb Late; + LateReverb mLate; /* Indicates the cross-fade point for delay line reads [0,FADE_SAMPLES]. */ - ALsizei FadeCount; + ALsizei mFadeCount; /* Maximum number of samples to process at once. */ - ALsizei MaxUpdate[2]; + ALsizei mMaxUpdate[2]; /* The current write offset for all delay lines. */ - ALsizei Offset; + ALsizei mOffset; /* Temporary storage used when processing. */ - alignas(16) ALfloat TempSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; - alignas(16) ALfloat MixSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; + alignas(16) ALfloat mTempSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; + alignas(16) ALfloat mMixBuffer[NUM_LINES][MAX_UPDATE_SAMPLES]; }; static ALvoid ReverbState_Destruct(ReverbState *State); @@ -346,102 +346,102 @@ static void ReverbState_Construct(ReverbState *state) ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); SET_VTABLE2(ReverbState, ALeffectState, state); - state->TotalSamples = 0; - state->SampleBuffer = NULL; + state->mTotalSamples = 0; + state->mSampleBuffer = NULL; - state->Params.Density = AL_EAXREVERB_DEFAULT_DENSITY; - state->Params.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION; - state->Params.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME; - state->Params.HFDecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME*AL_EAXREVERB_DEFAULT_DECAY_HFRATIO; - state->Params.LFDecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME*AL_EAXREVERB_DEFAULT_DECAY_LFRATIO; - state->Params.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE; - state->Params.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE; + state->mParams.Density = AL_EAXREVERB_DEFAULT_DENSITY; + state->mParams.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION; + state->mParams.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME; + state->mParams.HFDecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME*AL_EAXREVERB_DEFAULT_DECAY_HFRATIO; + state->mParams.LFDecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME*AL_EAXREVERB_DEFAULT_DECAY_LFRATIO; + state->mParams.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE; + state->mParams.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE; for(ALsizei i{0};i < NUM_LINES;i++) { - BiquadFilter_clear(&state->Filter[i].Lp); - BiquadFilter_clear(&state->Filter[i].Hp); + BiquadFilter_clear(&state->mFilter[i].Lp); + BiquadFilter_clear(&state->mFilter[i].Hp); } - state->Delay.Mask = 0; - state->Delay.Line = NULL; + state->mDelay.Mask = 0; + state->mDelay.Line = NULL; for(ALsizei i{0};i < NUM_LINES;i++) { - state->EarlyDelayTap[i][0] = 0; - state->EarlyDelayTap[i][1] = 0; - state->EarlyDelayCoeff[i][0] = 0.0f; - state->EarlyDelayCoeff[i][1] = 0.0f; + state->mEarlyDelayTap[i][0] = 0; + state->mEarlyDelayTap[i][1] = 0; + state->mEarlyDelayCoeff[i][0] = 0.0f; + state->mEarlyDelayCoeff[i][1] = 0.0f; } - state->LateFeedTap = 0; + state->mLateFeedTap = 0; for(ALsizei i{0};i < NUM_LINES;i++) { - state->LateDelayTap[i][0] = 0; - state->LateDelayTap[i][1] = 0; + state->mLateDelayTap[i][0] = 0; + state->mLateDelayTap[i][1] = 0; } - state->MixX = 0.0f; - state->MixY = 0.0f; + state->mMixX = 0.0f; + state->mMixY = 0.0f; - state->Early.VecAp.Delay.Mask = 0; - state->Early.VecAp.Delay.Line = NULL; - state->Early.VecAp.Coeff = 0.0f; - state->Early.Delay.Mask = 0; - state->Early.Delay.Line = NULL; + state->mEarly.VecAp.Delay.Mask = 0; + state->mEarly.VecAp.Delay.Line = NULL; + state->mEarly.VecAp.Coeff = 0.0f; + state->mEarly.Delay.Mask = 0; + state->mEarly.Delay.Line = NULL; for(ALsizei i{0};i < NUM_LINES;i++) { - state->Early.VecAp.Offset[i][0] = 0; - state->Early.VecAp.Offset[i][1] = 0; - state->Early.Offset[i][0] = 0; - state->Early.Offset[i][1] = 0; - state->Early.Coeff[i][0] = 0.0f; - state->Early.Coeff[i][1] = 0.0f; + state->mEarly.VecAp.Offset[i][0] = 0; + state->mEarly.VecAp.Offset[i][1] = 0; + state->mEarly.Offset[i][0] = 0; + state->mEarly.Offset[i][1] = 0; + state->mEarly.Coeff[i][0] = 0.0f; + state->mEarly.Coeff[i][1] = 0.0f; } - state->Late.DensityGain[0] = 0.0f; - state->Late.DensityGain[1] = 0.0f; - state->Late.Delay.Mask = 0; - state->Late.Delay.Line = NULL; - state->Late.VecAp.Delay.Mask = 0; - state->Late.VecAp.Delay.Line = NULL; - state->Late.VecAp.Coeff = 0.0f; + state->mLate.DensityGain[0] = 0.0f; + state->mLate.DensityGain[1] = 0.0f; + state->mLate.Delay.Mask = 0; + state->mLate.Delay.Line = NULL; + state->mLate.VecAp.Delay.Mask = 0; + state->mLate.VecAp.Delay.Line = NULL; + state->mLate.VecAp.Coeff = 0.0f; for(ALsizei i{0};i < NUM_LINES;i++) { - state->Late.Offset[i][0] = 0; - state->Late.Offset[i][1] = 0; + state->mLate.Offset[i][0] = 0; + state->mLate.Offset[i][1] = 0; - state->Late.VecAp.Offset[i][0] = 0; - state->Late.VecAp.Offset[i][1] = 0; + state->mLate.VecAp.Offset[i][0] = 0; + state->mLate.VecAp.Offset[i][1] = 0; - state->Late.T60[i].MidGain[0] = 0.0f; - state->Late.T60[i].MidGain[1] = 0.0f; - BiquadFilter_clear(&state->Late.T60[i].HFFilter); - BiquadFilter_clear(&state->Late.T60[i].LFFilter); + state->mLate.T60[i].MidGain[0] = 0.0f; + state->mLate.T60[i].MidGain[1] = 0.0f; + BiquadFilter_clear(&state->mLate.T60[i].HFFilter); + BiquadFilter_clear(&state->mLate.T60[i].LFFilter); } for(ALsizei i{0};i < NUM_LINES;i++) { for(ALsizei j{0};j < MAX_OUTPUT_CHANNELS;j++) { - state->Early.CurrentGain[i][j] = 0.0f; - state->Early.PanGain[i][j] = 0.0f; - state->Late.CurrentGain[i][j] = 0.0f; - state->Late.PanGain[i][j] = 0.0f; + state->mEarly.CurrentGain[i][j] = 0.0f; + state->mEarly.PanGain[i][j] = 0.0f; + state->mLate.CurrentGain[i][j] = 0.0f; + state->mLate.PanGain[i][j] = 0.0f; } } - state->FadeCount = 0; - state->MaxUpdate[0] = MAX_UPDATE_SAMPLES; - state->MaxUpdate[1] = MAX_UPDATE_SAMPLES; - state->Offset = 0; + state->mFadeCount = 0; + state->mMaxUpdate[0] = MAX_UPDATE_SAMPLES; + state->mMaxUpdate[1] = MAX_UPDATE_SAMPLES; + state->mOffset = 0; } static ALvoid ReverbState_Destruct(ReverbState *State) { - al_free(State->SampleBuffer); - State->SampleBuffer = NULL; + al_free(State->mSampleBuffer); + State->mSampleBuffer = NULL; ALeffectState_Destruct(STATIC_CAST(ALeffectState,State)); State->~ReverbState(); @@ -517,31 +517,31 @@ static ALboolean AllocLines(const ALuint frequency, ReverbState *State) AL_EAXREVERB_MAX_LATE_REVERB_DELAY + (LATE_LINE_LENGTHS[NUM_LINES-1] - LATE_LINE_LENGTHS[0])*0.25f*multiplier; totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES, - &State->Delay); + &State->mDelay); /* The early vector all-pass line. */ length = EARLY_ALLPASS_LENGTHS[NUM_LINES-1] * multiplier; totalSamples += CalcLineLength(length, totalSamples, frequency, 0, - &State->Early.VecAp.Delay); + &State->mEarly.VecAp.Delay); /* The early reflection line. */ length = EARLY_LINE_LENGTHS[NUM_LINES-1] * multiplier; totalSamples += CalcLineLength(length, totalSamples, frequency, 0, - &State->Early.Delay); + &State->mEarly.Delay); /* The late vector all-pass line. */ length = LATE_ALLPASS_LENGTHS[NUM_LINES-1] * multiplier; totalSamples += CalcLineLength(length, totalSamples, frequency, 0, - &State->Late.VecAp.Delay); + &State->mLate.VecAp.Delay); /* The late delay lines are calculated from the largest maximum density * line length. */ length = LATE_LINE_LENGTHS[NUM_LINES-1] * multiplier; totalSamples += CalcLineLength(length, totalSamples, frequency, 0, - &State->Late.Delay); + &State->mLate.Delay); - if(totalSamples != State->TotalSamples) + if(totalSamples != State->mTotalSamples) { ALfloat *newBuffer; @@ -550,21 +550,21 @@ static ALboolean AllocLines(const ALuint frequency, ReverbState *State) sizeof(ALfloat[NUM_LINES]) * totalSamples)); if(!newBuffer) return AL_FALSE; - al_free(State->SampleBuffer); - State->SampleBuffer = newBuffer; - State->TotalSamples = totalSamples; + al_free(State->mSampleBuffer); + State->mSampleBuffer = newBuffer; + State->mTotalSamples = totalSamples; } /* Update all delays to reflect the new sample buffer. */ - RealizeLineOffset(State->SampleBuffer, &State->Delay); - RealizeLineOffset(State->SampleBuffer, &State->Early.VecAp.Delay); - RealizeLineOffset(State->SampleBuffer, &State->Early.Delay); - RealizeLineOffset(State->SampleBuffer, &State->Late.VecAp.Delay); - RealizeLineOffset(State->SampleBuffer, &State->Late.Delay); + RealizeLineOffset(State->mSampleBuffer, &State->mDelay); + RealizeLineOffset(State->mSampleBuffer, &State->mEarly.VecAp.Delay); + RealizeLineOffset(State->mSampleBuffer, &State->mEarly.Delay); + RealizeLineOffset(State->mSampleBuffer, &State->mLate.VecAp.Delay); + RealizeLineOffset(State->mSampleBuffer, &State->mLate.Delay); /* Clear the sample buffer. */ - for(i = 0;i < State->TotalSamples;i++) - State->SampleBuffer[i] = 0.0f; + for(i = 0;i < State->mTotalSamples;i++) + State->mSampleBuffer[i] = 0.0f; return AL_TRUE; } @@ -582,57 +582,57 @@ static ALboolean ReverbState_deviceUpdate(ReverbState *State, ALCdevice *Device) multiplier = CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY); /* The late feed taps are set a fixed position past the latest delay tap. */ - State->LateFeedTap = float2int((AL_EAXREVERB_MAX_REFLECTIONS_DELAY + - EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier) * - frequency); + State->mLateFeedTap = float2int((AL_EAXREVERB_MAX_REFLECTIONS_DELAY + + EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier) * + frequency); /* Clear filters and gain coefficients since the delay lines were all just * cleared (if not reallocated). */ for(i = 0;i < NUM_LINES;i++) { - BiquadFilter_clear(&State->Filter[i].Lp); - BiquadFilter_clear(&State->Filter[i].Hp); + BiquadFilter_clear(&State->mFilter[i].Lp); + BiquadFilter_clear(&State->mFilter[i].Hp); } for(i = 0;i < NUM_LINES;i++) { - State->EarlyDelayCoeff[i][0] = 0.0f; - State->EarlyDelayCoeff[i][1] = 0.0f; + State->mEarlyDelayCoeff[i][0] = 0.0f; + State->mEarlyDelayCoeff[i][1] = 0.0f; } for(i = 0;i < NUM_LINES;i++) { - State->Early.Coeff[i][0] = 0.0f; - State->Early.Coeff[i][1] = 0.0f; + State->mEarly.Coeff[i][0] = 0.0f; + State->mEarly.Coeff[i][1] = 0.0f; } - State->Late.DensityGain[0] = 0.0f; - State->Late.DensityGain[1] = 0.0f; + State->mLate.DensityGain[0] = 0.0f; + State->mLate.DensityGain[1] = 0.0f; for(i = 0;i < NUM_LINES;i++) { - State->Late.T60[i].MidGain[0] = 0.0f; - State->Late.T60[i].MidGain[1] = 0.0f; - BiquadFilter_clear(&State->Late.T60[i].HFFilter); - BiquadFilter_clear(&State->Late.T60[i].LFFilter); + State->mLate.T60[i].MidGain[0] = 0.0f; + State->mLate.T60[i].MidGain[1] = 0.0f; + BiquadFilter_clear(&State->mLate.T60[i].HFFilter); + BiquadFilter_clear(&State->mLate.T60[i].LFFilter); } for(i = 0;i < NUM_LINES;i++) { for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) { - State->Early.CurrentGain[i][j] = 0.0f; - State->Early.PanGain[i][j] = 0.0f; - State->Late.CurrentGain[i][j] = 0.0f; - State->Late.PanGain[i][j] = 0.0f; + State->mEarly.CurrentGain[i][j] = 0.0f; + State->mEarly.PanGain[i][j] = 0.0f; + State->mLate.CurrentGain[i][j] = 0.0f; + State->mLate.PanGain[i][j] = 0.0f; } } /* Reset counters and offset base. */ - State->FadeCount = 0; - State->MaxUpdate[0] = MAX_UPDATE_SAMPLES; - State->MaxUpdate[1] = MAX_UPDATE_SAMPLES; - State->Offset = 0; + State->mFadeCount = 0; + State->mMaxUpdate[0] = MAX_UPDATE_SAMPLES; + State->mMaxUpdate[1] = MAX_UPDATE_SAMPLES; + State->mOffset = 0; return AL_TRUE; } @@ -755,13 +755,13 @@ static ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, for(i = 0;i < NUM_LINES;i++) { length = earlyDelay + EARLY_TAP_LENGTHS[i]*multiplier; - State->EarlyDelayTap[i][1] = float2int(length * frequency); + State->mEarlyDelayTap[i][1] = float2int(length * frequency); length = EARLY_TAP_LENGTHS[i]*multiplier; - State->EarlyDelayCoeff[i][1] = CalcDecayCoeff(length, decayTime); + State->mEarlyDelayCoeff[i][1] = CalcDecayCoeff(length, decayTime); length = lateDelay + (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS[0])*0.25f*multiplier; - State->LateDelayTap[i][1] = State->LateFeedTap + float2int(length * frequency); + State->mLateDelayTap[i][1] = State->mLateFeedTap + float2int(length * frequency); } } @@ -934,17 +934,17 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection */ rot = GetTransformFromVector(ReflectionsPan); MATRIX_MULT(transform, rot, A2B); - memset(&State->Early.PanGain, 0, sizeof(State->Early.PanGain)); + memset(&State->mEarly.PanGain, 0, sizeof(State->mEarly.PanGain)); for(i = 0;i < MAX_EFFECT_CHANNELS;i++) ComputePanGains(&Device->FOAOut, transform.m[i], earlyGain, - State->Early.PanGain[i]); + State->mEarly.PanGain[i]); rot = GetTransformFromVector(LateReverbPan); MATRIX_MULT(transform, rot, A2B); - memset(&State->Late.PanGain, 0, sizeof(State->Late.PanGain)); + memset(&State->mLate.PanGain, 0, sizeof(State->mLate.PanGain)); for(i = 0;i < MAX_EFFECT_CHANNELS;i++) ComputePanGains(&Device->FOAOut, transform.m[i], lateGain, - State->Late.PanGain[i]); + State->mLate.PanGain[i]); #undef MATRIX_MULT } @@ -964,16 +964,16 @@ static void ReverbState_update(ReverbState *State, const ALCcontext *Context, co * killing most of the signal. */ gainhf = maxf(props->Reverb.GainHF, 0.001f); - BiquadFilter_setParams(&State->Filter[0].Lp, BiquadType::HighShelf, gainhf, hf0norm, + BiquadFilter_setParams(&State->mFilter[0].Lp, BiquadType::HighShelf, gainhf, hf0norm, calc_rcpQ_from_slope(gainhf, 1.0f)); lf0norm = minf(props->Reverb.LFReference / frequency, 0.49f); gainlf = maxf(props->Reverb.GainLF, 0.001f); - BiquadFilter_setParams(&State->Filter[0].Hp, BiquadType::LowShelf, gainlf, lf0norm, + BiquadFilter_setParams(&State->mFilter[0].Hp, BiquadType::LowShelf, gainlf, lf0norm, calc_rcpQ_from_slope(gainlf, 1.0f)); for(i = 1;i < NUM_LINES;i++) { - BiquadFilter_copyParams(&State->Filter[i].Lp, &State->Filter[0].Lp); - BiquadFilter_copyParams(&State->Filter[i].Hp, &State->Filter[0].Hp); + BiquadFilter_copyParams(&State->mFilter[i].Lp, &State->mFilter[0].Lp); + BiquadFilter_copyParams(&State->mFilter[i].Hp, &State->mFilter[0].Hp); } /* Update the main effect delay and associated taps. */ @@ -983,10 +983,10 @@ static void ReverbState_update(ReverbState *State, const ALCcontext *Context, co /* Update the early lines. */ UpdateEarlyLines(props->Reverb.Density, props->Reverb.Diffusion, - props->Reverb.DecayTime, frequency, &State->Early); + props->Reverb.DecayTime, frequency, &State->mEarly); /* Get the mixing matrix coefficients. */ - CalcMatrixCoeffs(props->Reverb.Diffusion, &State->MixX, &State->MixY); + CalcMatrixCoeffs(props->Reverb.Diffusion, &State->mMixX, &State->mMixY); /* If the HF limit parameter is flagged, calculate an appropriate limit * based on the air absorption parameter. @@ -1006,7 +1006,7 @@ static void ReverbState_update(ReverbState *State, const ALCcontext *Context, co /* Update the late lines. */ UpdateLateLines(props->Reverb.Density, props->Reverb.Diffusion, lfDecayTime, props->Reverb.DecayTime, hfDecayTime, lf0norm, hf0norm, - frequency, &State->Late + frequency, &State->mLate ); /* Update early and late 3D panning. */ @@ -1016,35 +1016,35 @@ static void ReverbState_update(ReverbState *State, const ALCcontext *Context, co State); /* Calculate the max update size from the smallest relevant delay. */ - State->MaxUpdate[1] = mini(MAX_UPDATE_SAMPLES, - mini(State->Early.Offset[0][1], State->Late.Offset[0][1]) + State->mMaxUpdate[1] = mini(MAX_UPDATE_SAMPLES, + mini(State->mEarly.Offset[0][1], State->mLate.Offset[0][1]) ); /* Determine if delay-line cross-fading is required. Density is essentially * a master control for the feedback delays, so changes the offsets of many * delay lines. */ - if(State->Params.Density != props->Reverb.Density || + if(State->mParams.Density != props->Reverb.Density || /* Diffusion and decay times influences the decay rate (gain) of the * late reverb T60 filter. */ - State->Params.Diffusion != props->Reverb.Diffusion || - State->Params.DecayTime != props->Reverb.DecayTime || - State->Params.HFDecayTime != hfDecayTime || - State->Params.LFDecayTime != lfDecayTime || + State->mParams.Diffusion != props->Reverb.Diffusion || + State->mParams.DecayTime != props->Reverb.DecayTime || + State->mParams.HFDecayTime != hfDecayTime || + State->mParams.LFDecayTime != lfDecayTime || /* HF/LF References control the weighting used to calculate the density * gain. */ - State->Params.HFReference != props->Reverb.HFReference || - State->Params.LFReference != props->Reverb.LFReference) - State->FadeCount = 0; - State->Params.Density = props->Reverb.Density; - State->Params.Diffusion = props->Reverb.Diffusion; - State->Params.DecayTime = props->Reverb.DecayTime; - State->Params.HFDecayTime = hfDecayTime; - State->Params.LFDecayTime = lfDecayTime; - State->Params.HFReference = props->Reverb.HFReference; - State->Params.LFReference = props->Reverb.LFReference; + State->mParams.HFReference != props->Reverb.HFReference || + State->mParams.LFReference != props->Reverb.LFReference) + State->mFadeCount = 0; + State->mParams.Density = props->Reverb.Density; + State->mParams.Diffusion = props->Reverb.Diffusion; + State->mParams.DecayTime = props->Reverb.DecayTime; + State->mParams.HFDecayTime = hfDecayTime; + State->mParams.LFDecayTime = lfDecayTime; + State->mParams.HFReference = props->Reverb.HFReference; + State->mParams.LFReference = props->Reverb.LFReference; } @@ -1247,11 +1247,11 @@ static void VectorAllpass_Faded(ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES], static void EarlyReflection_Unfaded(ReverbState *State, ALsizei offset, const ALsizei todo, ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) { - ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; - const DelayLineI early_delay = State->Early.Delay; - const DelayLineI main_delay = State->Delay; - const ALfloat mixX = State->MixX; - const ALfloat mixY = State->MixY; + ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->mTempSamples; + const DelayLineI early_delay = State->mEarly.Delay; + const DelayLineI main_delay = State->mDelay; + const ALfloat mixX = State->mMixX; + const ALfloat mixY = State->mMixY; ALsizei late_feed_tap; ALsizei i, j; @@ -1262,8 +1262,8 @@ static void EarlyReflection_Unfaded(ReverbState *State, ALsizei offset, const AL */ for(j = 0;j < NUM_LINES;j++) { - ALsizei early_delay_tap = offset - State->EarlyDelayTap[j][0]; - ALfloat coeff = State->EarlyDelayCoeff[j][0]; + ALsizei early_delay_tap = offset - State->mEarlyDelayTap[j][0]; + ALfloat coeff = State->mEarlyDelayCoeff[j][0]; for(i = 0;i < todo;i++) temps[j][i] = DelayLineOut(&main_delay, early_delay_tap++, j) * coeff; } @@ -1271,15 +1271,15 @@ static void EarlyReflection_Unfaded(ReverbState *State, ALsizei offset, const AL /* Apply a vector all-pass, to help color the initial reflections based on * the diffusion strength. */ - VectorAllpass_Unfaded(temps, offset, mixX, mixY, todo, &State->Early.VecAp); + VectorAllpass_Unfaded(temps, offset, mixX, mixY, todo, &State->mEarly.VecAp); /* Apply a delay and bounce to generate secondary reflections, combine with * the primary reflections and write out the result for mixing. */ for(j = 0;j < NUM_LINES;j++) { - ALint early_feedb_tap = offset - State->Early.Offset[j][0]; - ALfloat early_feedb_coeff = State->Early.Coeff[j][0]; + ALint early_feedb_tap = offset - State->mEarly.Offset[j][0]; + ALfloat early_feedb_coeff = State->mEarly.Coeff[j][0]; for(i = 0;i < todo;i++) out[j][i] = DelayLineOut(&early_delay, early_feedb_tap++, j)*early_feedb_coeff + @@ -1292,17 +1292,17 @@ static void EarlyReflection_Unfaded(ReverbState *State, ALsizei offset, const AL * stage to pick up at the appropriate time, appplying a scatter and * bounce to improve the initial diffusion in the late reverb. */ - late_feed_tap = offset - State->LateFeedTap; + late_feed_tap = offset - State->mLateFeedTap; VectorScatterRevDelayIn(&main_delay, late_feed_tap, mixX, mixY, out, todo); } static void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsizei todo, const ALfloat fade, ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) { - ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; - const DelayLineI early_delay = State->Early.Delay; - const DelayLineI main_delay = State->Delay; - const ALfloat mixX = State->MixX; - const ALfloat mixY = State->MixY; + ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->mTempSamples; + const DelayLineI early_delay = State->mEarly.Delay; + const DelayLineI main_delay = State->mDelay; + const ALfloat mixX = State->mMixX; + const ALfloat mixY = State->mMixY; ALsizei late_feed_tap; ALsizei i, j; @@ -1310,11 +1310,11 @@ static void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsi for(j = 0;j < NUM_LINES;j++) { - ALsizei early_delay_tap0 = offset - State->EarlyDelayTap[j][0]; - ALsizei early_delay_tap1 = offset - State->EarlyDelayTap[j][1]; - ALfloat oldCoeff = State->EarlyDelayCoeff[j][0]; + ALsizei early_delay_tap0 = offset - State->mEarlyDelayTap[j][0]; + ALsizei early_delay_tap1 = offset - State->mEarlyDelayTap[j][1]; + ALfloat oldCoeff = State->mEarlyDelayCoeff[j][0]; ALfloat oldCoeffStep = -oldCoeff / FADE_SAMPLES; - ALfloat newCoeffStep = State->EarlyDelayCoeff[j][1] / FADE_SAMPLES; + ALfloat newCoeffStep = State->mEarlyDelayCoeff[j][1] / FADE_SAMPLES; ALfloat fadeCount = fade; for(i = 0;i < todo;i++) @@ -1328,15 +1328,15 @@ static void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsi } } - VectorAllpass_Faded(temps, offset, mixX, mixY, fade, todo, &State->Early.VecAp); + VectorAllpass_Faded(temps, offset, mixX, mixY, fade, todo, &State->mEarly.VecAp); for(j = 0;j < NUM_LINES;j++) { - ALint feedb_tap0 = offset - State->Early.Offset[j][0]; - ALint feedb_tap1 = offset - State->Early.Offset[j][1]; - ALfloat feedb_oldCoeff = State->Early.Coeff[j][0]; + ALint feedb_tap0 = offset - State->mEarly.Offset[j][0]; + ALint feedb_tap1 = offset - State->mEarly.Offset[j][1]; + ALfloat feedb_oldCoeff = State->mEarly.Coeff[j][0]; ALfloat feedb_oldCoeffStep = -feedb_oldCoeff / FADE_SAMPLES; - ALfloat feedb_newCoeffStep = State->Early.Coeff[j][1] / FADE_SAMPLES; + ALfloat feedb_newCoeffStep = State->mEarly.Coeff[j][1] / FADE_SAMPLES; ALfloat fadeCount = fade; for(i = 0;i < todo;i++) @@ -1352,7 +1352,7 @@ static void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsi for(j = 0;j < NUM_LINES;j++) DelayLineIn(&early_delay, offset, NUM_LINES-1-j, temps[j], todo); - late_feed_tap = offset - State->LateFeedTap; + late_feed_tap = offset - State->mLateFeedTap; VectorScatterRevDelayIn(&main_delay, late_feed_tap, mixX, mixY, out, todo); } @@ -1381,11 +1381,11 @@ static inline void LateT60Filter(ALfloat *RESTRICT samples, const ALsizei todo, static void LateReverb_Unfaded(ReverbState *State, ALsizei offset, const ALsizei todo, ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) { - ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; - const DelayLineI late_delay = State->Late.Delay; - const DelayLineI main_delay = State->Delay; - const ALfloat mixX = State->MixX; - const ALfloat mixY = State->MixY; + ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->mTempSamples; + const DelayLineI late_delay = State->mLate.Delay; + const DelayLineI main_delay = State->mDelay; + const ALfloat mixX = State->mMixX; + const ALfloat mixY = State->mMixY; ALsizei i, j; ASSUME(todo > 0); @@ -1395,20 +1395,20 @@ static void LateReverb_Unfaded(ReverbState *State, ALsizei offset, const ALsizei */ for(j = 0;j < NUM_LINES;j++) { - ALsizei late_delay_tap = offset - State->LateDelayTap[j][0]; - ALsizei late_feedb_tap = offset - State->Late.Offset[j][0]; - ALfloat midGain = State->Late.T60[j].MidGain[0]; - const ALfloat densityGain = State->Late.DensityGain[0] * midGain; + ALsizei late_delay_tap = offset - State->mLateDelayTap[j][0]; + ALsizei late_feedb_tap = offset - State->mLate.Offset[j][0]; + ALfloat midGain = State->mLate.T60[j].MidGain[0]; + const ALfloat densityGain = State->mLate.DensityGain[0] * midGain; for(i = 0;i < todo;i++) temps[j][i] = DelayLineOut(&main_delay, late_delay_tap++, j)*densityGain + DelayLineOut(&late_delay, late_feedb_tap++, j)*midGain; - LateT60Filter(temps[j], todo, &State->Late.T60[j]); + LateT60Filter(temps[j], todo, &State->mLate.T60[j]); } /* Apply a vector all-pass to improve micro-surface diffusion, and write * out the results for mixing. */ - VectorAllpass_Unfaded(temps, offset, mixX, mixY, todo, &State->Late.VecAp); + VectorAllpass_Unfaded(temps, offset, mixX, mixY, todo, &State->mLate.VecAp); for(j = 0;j < NUM_LINES;j++) memcpy(out[j], temps[j], todo*sizeof(ALfloat)); @@ -1419,29 +1419,29 @@ static void LateReverb_Unfaded(ReverbState *State, ALsizei offset, const ALsizei static void LateReverb_Faded(ReverbState *State, ALsizei offset, const ALsizei todo, const ALfloat fade, ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) { - ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; - const DelayLineI late_delay = State->Late.Delay; - const DelayLineI main_delay = State->Delay; - const ALfloat mixX = State->MixX; - const ALfloat mixY = State->MixY; + ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->mTempSamples; + const DelayLineI late_delay = State->mLate.Delay; + const DelayLineI main_delay = State->mDelay; + const ALfloat mixX = State->mMixX; + const ALfloat mixY = State->mMixY; ALsizei i, j; ASSUME(todo > 0); for(j = 0;j < NUM_LINES;j++) { - const ALfloat oldMidGain = State->Late.T60[j].MidGain[0]; - const ALfloat midGain = State->Late.T60[j].MidGain[1]; + const ALfloat oldMidGain = State->mLate.T60[j].MidGain[0]; + const ALfloat midGain = State->mLate.T60[j].MidGain[1]; const ALfloat oldMidStep = -oldMidGain / FADE_SAMPLES; const ALfloat midStep = midGain / FADE_SAMPLES; - const ALfloat oldDensityGain = State->Late.DensityGain[0] * oldMidGain; - const ALfloat densityGain = State->Late.DensityGain[1] * midGain; + const ALfloat oldDensityGain = State->mLate.DensityGain[0] * oldMidGain; + const ALfloat densityGain = State->mLate.DensityGain[1] * midGain; const ALfloat oldDensityStep = -oldDensityGain / FADE_SAMPLES; const ALfloat densityStep = densityGain / FADE_SAMPLES; - ALsizei late_delay_tap0 = offset - State->LateDelayTap[j][0]; - ALsizei late_delay_tap1 = offset - State->LateDelayTap[j][1]; - ALsizei late_feedb_tap0 = offset - State->Late.Offset[j][0]; - ALsizei late_feedb_tap1 = offset - State->Late.Offset[j][1]; + ALsizei late_delay_tap0 = offset - State->mLateDelayTap[j][0]; + ALsizei late_delay_tap1 = offset - State->mLateDelayTap[j][1]; + ALsizei late_feedb_tap0 = offset - State->mLate.Offset[j][0]; + ALsizei late_feedb_tap1 = offset - State->mLate.Offset[j][1]; ALfloat fadeCount = fade; for(i = 0;i < todo;i++) @@ -1457,10 +1457,10 @@ static void LateReverb_Faded(ReverbState *State, ALsizei offset, const ALsizei t gfade0, gfade1); fadeCount += 1.0f; } - LateT60Filter(temps[j], todo, &State->Late.T60[j]); + LateT60Filter(temps[j], todo, &State->mLate.T60[j]); } - VectorAllpass_Faded(temps, offset, mixX, mixY, fade, todo, &State->Late.VecAp); + VectorAllpass_Faded(temps, offset, mixX, mixY, fade, todo, &State->mLate.VecAp); for(j = 0;j < NUM_LINES;j++) memcpy(out[j], temps[j], todo*sizeof(ALfloat)); @@ -1470,10 +1470,10 @@ static void LateReverb_Faded(ReverbState *State, ALsizei offset, const ALsizei t static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALfloat (*RESTRICT afmt)[MAX_UPDATE_SAMPLES] = State->TempSamples; - ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES] = State->MixSamples; - ALsizei fadeCount = State->FadeCount; - ALsizei offset = State->Offset; + ALfloat (*RESTRICT afmt)[MAX_UPDATE_SAMPLES] = State->mTempSamples; + ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES] = State->mMixBuffer; + ALsizei fadeCount = State->mFadeCount; + ALsizei offset = State->mOffset; ALsizei base, c; /* Process reverb for these samples. */ @@ -1484,9 +1484,9 @@ static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const if(FADE_SAMPLES-fadeCount > 0) { todo = mini(todo, FADE_SAMPLES-fadeCount); - todo = mini(todo, State->MaxUpdate[0]); + todo = mini(todo, State->mMaxUpdate[0]); } - todo = mini(todo, State->MaxUpdate[1]); + todo = mini(todo, State->mMaxUpdate[1]); /* If this is not the final update, ensure the update size is a * multiple of 4 for the SIMD mixers. */ @@ -1504,11 +1504,11 @@ static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const for(c = 0;c < NUM_LINES;c++) { /* Band-pass the incoming samples. */ - BiquadFilter_process(&State->Filter[c].Lp, samples[0], afmt[c], todo); - BiquadFilter_process(&State->Filter[c].Hp, samples[1], samples[0], todo); + BiquadFilter_process(&State->mFilter[c].Lp, samples[0], afmt[c], todo); + BiquadFilter_process(&State->mFilter[c].Hp, samples[1], samples[0], todo); /* Feed the initial delay line. */ - DelayLineIn(&State->Delay, offset, c, samples[1], todo); + DelayLineIn(&State->mDelay, offset, c, samples[1], todo); } if(UNLIKELY(fadeCount < FADE_SAMPLES)) @@ -1522,7 +1522,7 @@ static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const */ for(c = 0;c < NUM_LINES;c++) MixSamples(samples[c], NumChannels, SamplesOut, - State->Early.CurrentGain[c], State->Early.PanGain[c], + State->mEarly.CurrentGain[c], State->mEarly.PanGain[c], SamplesToDo-base, base, todo ); @@ -1530,7 +1530,7 @@ static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const LateReverb_Faded(State, offset, todo, fade, samples); for(c = 0;c < NUM_LINES;c++) MixSamples(samples[c], NumChannels, SamplesOut, - State->Late.CurrentGain[c], State->Late.PanGain[c], + State->mLate.CurrentGain[c], State->mLate.PanGain[c], SamplesToDo-base, base, todo ); @@ -1542,18 +1542,18 @@ static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const fadeCount = FADE_SAMPLES; for(c = 0;c < NUM_LINES;c++) { - State->EarlyDelayTap[c][0] = State->EarlyDelayTap[c][1]; - State->EarlyDelayCoeff[c][0] = State->EarlyDelayCoeff[c][1]; - State->Early.VecAp.Offset[c][0] = State->Early.VecAp.Offset[c][1]; - State->Early.Offset[c][0] = State->Early.Offset[c][1]; - State->Early.Coeff[c][0] = State->Early.Coeff[c][1]; - State->LateDelayTap[c][0] = State->LateDelayTap[c][1]; - State->Late.VecAp.Offset[c][0] = State->Late.VecAp.Offset[c][1]; - State->Late.Offset[c][0] = State->Late.Offset[c][1]; - State->Late.T60[c].MidGain[0] = State->Late.T60[c].MidGain[1]; + State->mEarlyDelayTap[c][0] = State->mEarlyDelayTap[c][1]; + State->mEarlyDelayCoeff[c][0] = State->mEarlyDelayCoeff[c][1]; + State->mEarly.VecAp.Offset[c][0] = State->mEarly.VecAp.Offset[c][1]; + State->mEarly.Offset[c][0] = State->mEarly.Offset[c][1]; + State->mEarly.Coeff[c][0] = State->mEarly.Coeff[c][1]; + State->mLateDelayTap[c][0] = State->mLateDelayTap[c][1]; + State->mLate.VecAp.Offset[c][0] = State->mLate.VecAp.Offset[c][1]; + State->mLate.Offset[c][0] = State->mLate.Offset[c][1]; + State->mLate.T60[c].MidGain[0] = State->mLate.T60[c].MidGain[1]; } - State->Late.DensityGain[0] = State->Late.DensityGain[1]; - State->MaxUpdate[0] = State->MaxUpdate[1]; + State->mLate.DensityGain[0] = State->mLate.DensityGain[1]; + State->mMaxUpdate[0] = State->mMaxUpdate[1]; } } else @@ -1562,7 +1562,7 @@ static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const EarlyReflection_Unfaded(State, offset, todo, samples); for(c = 0;c < NUM_LINES;c++) MixSamples(samples[c], NumChannels, SamplesOut, - State->Early.CurrentGain[c], State->Early.PanGain[c], + State->mEarly.CurrentGain[c], State->mEarly.PanGain[c], SamplesToDo-base, base, todo ); @@ -1570,7 +1570,7 @@ static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const LateReverb_Unfaded(State, offset, todo, samples); for(c = 0;c < NUM_LINES;c++) MixSamples(samples[c], NumChannels, SamplesOut, - State->Late.CurrentGain[c], State->Late.PanGain[c], + State->mLate.CurrentGain[c], State->mLate.PanGain[c], SamplesToDo-base, base, todo ); } @@ -1580,8 +1580,8 @@ static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const base += todo; } - State->Offset = offset; - State->FadeCount = fadeCount; + State->mOffset = offset; + State->mFadeCount = fadeCount; } -- cgit v1.2.3 From ddfed7187fad7c55ebb5eadb67108914ce22a57f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 09:36:59 -0800 Subject: Use a regular vector for the reverb sample buffer --- Alc/effects/reverb.cpp | 56 ++++++++++++++++++-------------------------------- 1 file changed, 20 insertions(+), 36 deletions(-) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 4fef38d1..64676ed2 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -24,6 +24,8 @@ #include #include +#include + #include "alMain.h" #include "alcontext.h" #include "alu.h" @@ -31,6 +33,7 @@ #include "alListener.h" #include "alError.h" #include "filters/defs.h" +#include "vector.h" #include "vecmat.h" /* This is a user config option for modifying the overall output of the reverb @@ -280,8 +283,7 @@ struct ReverbState final : public ALeffectState { /* All delay lines are allocated as a single buffer to reduce memory * fragmentation and management code. */ - ALfloat *mSampleBuffer; - ALuint mTotalSamples; + al::vector mSampleBuffer; struct { /* Calculated parameters which indicate if cross-fading is needed after @@ -346,9 +348,6 @@ static void ReverbState_Construct(ReverbState *state) ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); SET_VTABLE2(ReverbState, ALeffectState, state); - state->mTotalSamples = 0; - state->mSampleBuffer = NULL; - state->mParams.Density = AL_EAXREVERB_DEFAULT_DENSITY; state->mParams.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION; state->mParams.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME; @@ -440,9 +439,6 @@ static void ReverbState_Construct(ReverbState *state) static ALvoid ReverbState_Destruct(ReverbState *State) { - al_free(State->mSampleBuffer); - State->mSampleBuffer = NULL; - ALeffectState_Destruct(STATIC_CAST(ALeffectState,State)); State->~ReverbState(); } @@ -495,27 +491,24 @@ static ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const */ static ALboolean AllocLines(const ALuint frequency, ReverbState *State) { - ALuint totalSamples, i; - ALfloat multiplier, length; - /* All delay line lengths are calculated to accomodate the full range of * lengths given their respective paramters. */ - totalSamples = 0; + ALuint totalSamples{0u}; /* Multiplier for the maximum density value, i.e. density=1, which is * actually the least density... */ - multiplier = CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY); + ALfloat multiplier{CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY)}; /* The main delay length includes the maximum early reflection delay, the * largest early tap width, the maximum late reverb delay, and the * largest late tap width. Finally, it must also be extended by the * update size (MAX_UPDATE_SAMPLES) for block processing. */ - length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier + - AL_EAXREVERB_MAX_LATE_REVERB_DELAY + - (LATE_LINE_LENGTHS[NUM_LINES-1] - LATE_LINE_LENGTHS[0])*0.25f*multiplier; + ALfloat length{AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier + + AL_EAXREVERB_MAX_LATE_REVERB_DELAY + + (LATE_LINE_LENGTHS[NUM_LINES-1] - LATE_LINE_LENGTHS[0])*0.25f*multiplier}; totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES, &State->mDelay); @@ -541,30 +534,21 @@ static ALboolean AllocLines(const ALuint frequency, ReverbState *State) totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &State->mLate.Delay); - if(totalSamples != State->mTotalSamples) + if(totalSamples != State->mSampleBuffer.size()) { - ALfloat *newBuffer; - - TRACE("New reverb buffer length: %ux4 samples\n", totalSamples); - newBuffer = static_cast(al_calloc(16, - sizeof(ALfloat[NUM_LINES]) * totalSamples)); - if(!newBuffer) return AL_FALSE; - - al_free(State->mSampleBuffer); - State->mSampleBuffer = newBuffer; - State->mTotalSamples = totalSamples; + State->mSampleBuffer.resize(sizeof(ALfloat[NUM_LINES]) * totalSamples); + State->mSampleBuffer.shrink_to_fit(); } - /* Update all delays to reflect the new sample buffer. */ - RealizeLineOffset(State->mSampleBuffer, &State->mDelay); - RealizeLineOffset(State->mSampleBuffer, &State->mEarly.VecAp.Delay); - RealizeLineOffset(State->mSampleBuffer, &State->mEarly.Delay); - RealizeLineOffset(State->mSampleBuffer, &State->mLate.VecAp.Delay); - RealizeLineOffset(State->mSampleBuffer, &State->mLate.Delay); - /* Clear the sample buffer. */ - for(i = 0;i < State->mTotalSamples;i++) - State->mSampleBuffer[i] = 0.0f; + std::fill(State->mSampleBuffer.begin(), State->mSampleBuffer.end(), 0.0f); + + /* Update all delays to reflect the new sample buffer. */ + RealizeLineOffset(State->mSampleBuffer.data(), &State->mDelay); + RealizeLineOffset(State->mSampleBuffer.data(), &State->mEarly.VecAp.Delay); + RealizeLineOffset(State->mSampleBuffer.data(), &State->mEarly.Delay); + RealizeLineOffset(State->mSampleBuffer.data(), &State->mLate.VecAp.Delay); + RealizeLineOffset(State->mSampleBuffer.data(), &State->mLate.Delay); return AL_TRUE; } -- cgit v1.2.3 From 3ae1c78d1ac07cd22727296488a399c48597fd15 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 09:51:29 -0800 Subject: Use std::isfinite instead of isfinite --- Alc/effects/dedicated.cpp | 3 ++- Alc/effects/reverb.cpp | 5 +++-- OpenAL32/alListener.cpp | 12 +++++++----- OpenAL32/alState.cpp | 7 ++++--- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/Alc/effects/dedicated.cpp b/Alc/effects/dedicated.cpp index 59f31b52..f91458b3 100644 --- a/Alc/effects/dedicated.cpp +++ b/Alc/effects/dedicated.cpp @@ -21,6 +21,7 @@ #include "config.h" #include +#include #include "alMain.h" #include "alcontext.h" @@ -142,7 +143,7 @@ void ALdedicated_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, switch(param) { case AL_DEDICATED_GAIN: - if(!(val >= 0.0f && isfinite(val))) + if(!(val >= 0.0f && std::isfinite(val))) SETERR_RETURN(context, AL_INVALID_VALUE,, "Dedicated gain out of range"); props->Dedicated.Gain = val; break; diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 64676ed2..8b63e473 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include "alMain.h" @@ -1741,14 +1742,14 @@ void ALeaxreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, switch(param) { case AL_EAXREVERB_REFLECTIONS_PAN: - if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2]))) + if(!(std::isfinite(vals[0]) && std::isfinite(vals[1]) && std::isfinite(vals[2]))) SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb reflections pan out of range"); props->Reverb.ReflectionsPan[0] = vals[0]; props->Reverb.ReflectionsPan[1] = vals[1]; props->Reverb.ReflectionsPan[2] = vals[2]; break; case AL_EAXREVERB_LATE_REVERB_PAN: - if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2]))) + if(!(std::isfinite(vals[0]) && std::isfinite(vals[1]) && std::isfinite(vals[2]))) SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb late reverb pan out of range"); props->Reverb.LateReverbPan[0] = vals[0]; props->Reverb.LateReverbPan[1] = vals[1]; diff --git a/OpenAL32/alListener.cpp b/OpenAL32/alListener.cpp index bf1ac3f9..d60f5254 100644 --- a/OpenAL32/alListener.cpp +++ b/OpenAL32/alListener.cpp @@ -20,6 +20,8 @@ #include "config.h" +#include + #include "alMain.h" #include "alcontext.h" #include "alu.h" @@ -48,7 +50,7 @@ AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) switch(param) { case AL_GAIN: - if(!(value >= 0.0f && isfinite(value))) + if(!(value >= 0.0f && std::isfinite(value))) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener gain out of range"); listener->Gain = value; DO_UPDATEPROPS(); @@ -87,7 +89,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val switch(param) { case AL_POSITION: - if(!(isfinite(value1) && isfinite(value2) && isfinite(value3))) + if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3))) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener position out of range"); listener->Position[0] = value1; listener->Position[1] = value2; @@ -96,7 +98,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val break; case AL_VELOCITY: - if(!(isfinite(value1) && isfinite(value2) && isfinite(value3))) + if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3))) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener velocity out of range"); listener->Velocity[0] = value1; listener->Velocity[1] = value2; @@ -144,8 +146,8 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) switch(param) { case AL_ORIENTATION: - if(!(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) && - isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]))) + if(!(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) && + std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5]))) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener orientation out of range"); /* AT then UP */ listener->Forward[0] = values[0]; diff --git a/OpenAL32/alState.cpp b/OpenAL32/alState.cpp index a3c3cc1f..e3e8856f 100644 --- a/OpenAL32/alState.cpp +++ b/OpenAL32/alState.cpp @@ -23,6 +23,7 @@ #include "version.h" #include +#include #include "alMain.h" #include "alcontext.h" @@ -643,7 +644,7 @@ AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - if(!(value >= 0.0f && isfinite(value))) + if(!(value >= 0.0f && std::isfinite(value))) alSetError(context.get(), AL_INVALID_VALUE, "Doppler factor %f out of range", value); else { @@ -670,7 +671,7 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) context->EventParam); } - if(!(value >= 0.0f && isfinite(value))) + if(!(value >= 0.0f && std::isfinite(value))) alSetError(context.get(), AL_INVALID_VALUE, "Doppler velocity %f out of range", value); else { @@ -685,7 +686,7 @@ AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - if(!(value > 0.0f && isfinite(value))) + if(!(value > 0.0f && std::isfinite(value))) alSetError(context.get(), AL_INVALID_VALUE, "Speed of sound %f out of range", value); else { -- cgit v1.2.3 From ba33f6a7a475b4e4ae6f71a6a41726e418212ab3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 18:51:01 -0800 Subject: Clean up the chorus/flanger struct members --- Alc/effects/chorus.cpp | 131 ++++++++++++++++++++++++------------------------- 1 file changed, 65 insertions(+), 66 deletions(-) diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp index 62691887..8fa26e5a 100644 --- a/Alc/effects/chorus.cpp +++ b/Alc/effects/chorus.cpp @@ -23,6 +23,8 @@ #include #include +#include + #include "alMain.h" #include "alcontext.h" #include "alAuxEffectSlot.h" @@ -40,26 +42,26 @@ enum WaveForm { }; struct ALchorusState final : public ALeffectState { - ALfloat *SampleBuffer; - ALsizei BufferLength; - ALsizei offset; + ALfloat *mSampleBuffer{nullptr}; + ALsizei mBufferLength{0}; + ALsizei mOffset{0}; - ALsizei lfo_offset; - ALsizei lfo_range; - ALfloat lfo_scale; - ALint lfo_disp; + ALsizei mLfoOffset{0}; + ALsizei mLfoRange{1}; + ALfloat mLfoScale{0.0f}; + ALint mLfoDisp{0}; /* Gains for left and right sides */ struct { - ALfloat Current[MAX_OUTPUT_CHANNELS]; - ALfloat Target[MAX_OUTPUT_CHANNELS]; - } Gains[2]; + ALfloat Current[MAX_OUTPUT_CHANNELS]{}; + ALfloat Target[MAX_OUTPUT_CHANNELS]{}; + } mGains[2]; /* effect parameters */ - enum WaveForm waveform; - ALint delay; - ALfloat depth; - ALfloat feedback; + WaveForm mWaveform{}; + ALint mDelay{0}; + ALfloat mDepth{0.0f}; + ALfloat mFeedback{0.0f}; }; static ALvoid ALchorusState_Destruct(ALchorusState *state); @@ -76,19 +78,12 @@ static void ALchorusState_Construct(ALchorusState *state) new (state) ALchorusState{}; ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); SET_VTABLE2(ALchorusState, ALeffectState, state); - - state->BufferLength = 0; - state->SampleBuffer = NULL; - state->offset = 0; - state->lfo_offset = 0; - state->lfo_range = 1; - state->waveform = WF_Triangle; } static ALvoid ALchorusState_Destruct(ALchorusState *state) { - al_free(state->SampleBuffer); - state->SampleBuffer = NULL; + al_free(state->mSampleBuffer); + state->mSampleBuffer = NULL; ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); state->~ALchorusState(); @@ -102,18 +97,22 @@ static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Dev maxlen = NextPowerOf2(float2int(max_delay*2.0f*Device->Frequency) + 1u); if(maxlen <= 0) return AL_FALSE; - if(maxlen != state->BufferLength) + if(maxlen != state->mBufferLength) { void *temp = al_calloc(16, maxlen * sizeof(ALfloat)); if(!temp) return AL_FALSE; - al_free(state->SampleBuffer); - state->SampleBuffer = static_cast(temp); - state->BufferLength = maxlen; + al_free(state->mSampleBuffer); + state->mSampleBuffer = static_cast(temp); + state->mBufferLength = maxlen; } - memset(state->SampleBuffer, 0, state->BufferLength*sizeof(ALfloat)); - memset(state->Gains, 0, sizeof(state->Gains)); + std::fill_n(state->mSampleBuffer, state->mBufferLength, 0.0f); + for(auto &e : state->mGains) + { + std::fill(std::begin(e.Current), std::end(e.Current), 0.0f); + std::fill(std::begin(e.Target), std::end(e.Target), 0.0f); + } return AL_TRUE; } @@ -130,37 +129,37 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Conte switch(props->Chorus.Waveform) { case AL_CHORUS_WAVEFORM_TRIANGLE: - state->waveform = WF_Triangle; + state->mWaveform = WF_Triangle; break; case AL_CHORUS_WAVEFORM_SINUSOID: - state->waveform = WF_Sinusoid; + state->mWaveform = WF_Sinusoid; break; } /* The LFO depth is scaled to be relative to the sample delay. Clamp the * delay and depth to allow enough padding for resampling. */ - state->delay = maxi(float2int(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f), - mindelay); - state->depth = minf(props->Chorus.Depth * state->delay, - (ALfloat)(state->delay - mindelay)); + state->mDelay = maxi(float2int(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f), + mindelay); + state->mDepth = minf(props->Chorus.Depth * state->mDelay, + (ALfloat)(state->mDelay - mindelay)); - state->feedback = props->Chorus.Feedback; + state->mFeedback = props->Chorus.Feedback; /* Gains for left and right sides */ CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, state->Gains[0].Target); + ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, state->mGains[0].Target); CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, state->Gains[1].Target); + ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, state->mGains[1].Target); phase = props->Chorus.Phase; rate = props->Chorus.Rate; if(!(rate > 0.0f)) { - state->lfo_offset = 0; - state->lfo_range = 1; - state->lfo_scale = 0.0f; - state->lfo_disp = 0; + state->mLfoOffset = 0; + state->mLfoRange = 1; + state->mLfoScale = 0.0f; + state->mLfoDisp = 0; } else { @@ -169,22 +168,22 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Conte */ ALsizei lfo_range = float2int(minf(frequency/rate + 0.5f, (ALfloat)(INT_MAX/360 - 180))); - state->lfo_offset = float2int((ALfloat)state->lfo_offset/state->lfo_range* + state->mLfoOffset = float2int((ALfloat)state->mLfoOffset/state->mLfoRange* lfo_range + 0.5f) % lfo_range; - state->lfo_range = lfo_range; - switch(state->waveform) + state->mLfoRange = lfo_range; + switch(state->mWaveform) { case WF_Triangle: - state->lfo_scale = 4.0f / state->lfo_range; + state->mLfoScale = 4.0f / state->mLfoRange; break; case WF_Sinusoid: - state->lfo_scale = F_TAU / state->lfo_range; + state->mLfoScale = F_TAU / state->mLfoRange; break; } /* Calculate lfo phase displacement */ if(phase < 0) phase = 360 + phase; - state->lfo_disp = (state->lfo_range*phase + 180) / 360; + state->mLfoDisp = (state->mLfoRange*phase + 180) / 360; } } @@ -215,11 +214,11 @@ static void GetSinusoidDelays(ALint *RESTRICT delays, ALsizei offset, const ALsi static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - const ALsizei bufmask = state->BufferLength-1; - const ALfloat feedback = state->feedback; - const ALsizei avgdelay = (state->delay + (FRACTIONONE>>1)) >> FRACTIONBITS; - ALfloat *RESTRICT delaybuf = state->SampleBuffer; - ALsizei offset = state->offset; + const ALsizei bufmask = state->mBufferLength-1; + const ALfloat feedback = state->mFeedback; + const ALsizei avgdelay = (state->mDelay + (FRACTIONONE>>1)) >> FRACTIONBITS; + ALfloat *RESTRICT delaybuf = state->mSampleBuffer; + ALsizei offset = state->mOffset; ALsizei i, c; ALsizei base; @@ -229,23 +228,23 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, c ALint moddelays[2][256]; alignas(16) ALfloat temps[2][256]; - if(state->waveform == WF_Sinusoid) + if(state->mWaveform == WF_Sinusoid) { - GetSinusoidDelays(moddelays[0], state->lfo_offset, state->lfo_range, state->lfo_scale, - state->depth, state->delay, todo); - GetSinusoidDelays(moddelays[1], (state->lfo_offset+state->lfo_disp)%state->lfo_range, - state->lfo_range, state->lfo_scale, state->depth, state->delay, + GetSinusoidDelays(moddelays[0], state->mLfoOffset, state->mLfoRange, state->mLfoScale, + state->mDepth, state->mDelay, todo); + GetSinusoidDelays(moddelays[1], (state->mLfoOffset+state->mLfoDisp)%state->mLfoRange, + state->mLfoRange, state->mLfoScale, state->mDepth, state->mDelay, todo); } else /*if(state->waveform == WF_Triangle)*/ { - GetTriangleDelays(moddelays[0], state->lfo_offset, state->lfo_range, state->lfo_scale, - state->depth, state->delay, todo); - GetTriangleDelays(moddelays[1], (state->lfo_offset+state->lfo_disp)%state->lfo_range, - state->lfo_range, state->lfo_scale, state->depth, state->delay, + GetTriangleDelays(moddelays[0], state->mLfoOffset, state->mLfoRange, state->mLfoScale, + state->mDepth, state->mDelay, todo); + GetTriangleDelays(moddelays[1], (state->mLfoOffset+state->mLfoDisp)%state->mLfoRange, + state->mLfoRange, state->mLfoScale, state->mDepth, state->mDelay, todo); } - state->lfo_offset = (state->lfo_offset+todo) % state->lfo_range; + state->mLfoOffset = (state->mLfoOffset+todo) % state->mLfoRange; for(i = 0;i < todo;i++) { @@ -275,13 +274,13 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, c } for(c = 0;c < 2;c++) - MixSamples(temps[c], NumChannels, SamplesOut, state->Gains[c].Current, - state->Gains[c].Target, SamplesToDo-base, base, todo); + MixSamples(temps[c], NumChannels, SamplesOut, state->mGains[c].Current, + state->mGains[c].Target, SamplesToDo-base, base, todo); base += todo; } - state->offset = offset; + state->mOffset = offset; } -- cgit v1.2.3 From 4810def6137c7bc865cfd87346a515ca1bc3a646 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 19:08:30 -0800 Subject: Use a normal vector for the chorus sample buffer --- Alc/effects/chorus.cpp | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp index 8fa26e5a..d859d630 100644 --- a/Alc/effects/chorus.cpp +++ b/Alc/effects/chorus.cpp @@ -31,6 +31,7 @@ #include "alError.h" #include "alu.h" #include "filters/defs.h" +#include "vector.h" static_assert(AL_CHORUS_WAVEFORM_SINUSOID == AL_FLANGER_WAVEFORM_SINUSOID, "Chorus/Flanger waveform value mismatch"); @@ -42,8 +43,7 @@ enum WaveForm { }; struct ALchorusState final : public ALeffectState { - ALfloat *mSampleBuffer{nullptr}; - ALsizei mBufferLength{0}; + al::vector mSampleBuffer; ALsizei mOffset{0}; ALsizei mLfoOffset{0}; @@ -82,9 +82,6 @@ static void ALchorusState_Construct(ALchorusState *state) static ALvoid ALchorusState_Destruct(ALchorusState *state) { - al_free(state->mSampleBuffer); - state->mSampleBuffer = NULL; - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); state->~ALchorusState(); } @@ -92,22 +89,18 @@ static ALvoid ALchorusState_Destruct(ALchorusState *state) static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device) { const ALfloat max_delay = maxf(AL_CHORUS_MAX_DELAY, AL_FLANGER_MAX_DELAY); - ALsizei maxlen; + size_t maxlen; maxlen = NextPowerOf2(float2int(max_delay*2.0f*Device->Frequency) + 1u); if(maxlen <= 0) return AL_FALSE; - if(maxlen != state->mBufferLength) + if(maxlen != state->mSampleBuffer.size()) { - void *temp = al_calloc(16, maxlen * sizeof(ALfloat)); - if(!temp) return AL_FALSE; - - al_free(state->mSampleBuffer); - state->mSampleBuffer = static_cast(temp); - state->mBufferLength = maxlen; + state->mSampleBuffer.resize(maxlen); + state->mSampleBuffer.shrink_to_fit(); } - std::fill_n(state->mSampleBuffer, state->mBufferLength, 0.0f); + std::fill(state->mSampleBuffer.begin(), state->mSampleBuffer.end(), 0.0f); for(auto &e : state->mGains) { std::fill(std::begin(e.Current), std::end(e.Current), 0.0f); @@ -214,10 +207,10 @@ static void GetSinusoidDelays(ALint *RESTRICT delays, ALsizei offset, const ALsi static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - const ALsizei bufmask = state->mBufferLength-1; + const ALsizei bufmask = state->mSampleBuffer.size()-1; const ALfloat feedback = state->mFeedback; const ALsizei avgdelay = (state->mDelay + (FRACTIONONE>>1)) >> FRACTIONBITS; - ALfloat *RESTRICT delaybuf = state->mSampleBuffer; + ALfloat *RESTRICT delaybuf = state->mSampleBuffer.data(); ALsizei offset = state->mOffset; ALsizei i, c; ALsizei base; -- cgit v1.2.3 From 7f3584ec4cef13e3e7b9159c90b0d43246d08a42 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 19:13:44 -0800 Subject: Fix the reverb buffer size calculation --- Alc/effects/reverb.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 8b63e473..229cd316 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -535,9 +535,10 @@ static ALboolean AllocLines(const ALuint frequency, ReverbState *State) totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &State->mLate.Delay); + totalSamples *= NUM_LINES; if(totalSamples != State->mSampleBuffer.size()) { - State->mSampleBuffer.resize(sizeof(ALfloat[NUM_LINES]) * totalSamples); + State->mSampleBuffer.resize(totalSamples); State->mSampleBuffer.shrink_to_fit(); } -- cgit v1.2.3 From a346380e2b69885edd0902f1164415484af9c2fe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 19:57:30 -0800 Subject: Clean up more effects' struct members --- Alc/effects/compressor.cpp | 43 +++++++++----------- Alc/effects/dedicated.cpp | 39 +++++++++---------- Alc/effects/distortion.cpp | 32 +++++++-------- Alc/effects/echo.cpp | 97 ++++++++++++++++++++++------------------------ 4 files changed, 100 insertions(+), 111 deletions(-) diff --git a/Alc/effects/compressor.cpp b/Alc/effects/compressor.cpp index cd6c72db..be91dd6c 100644 --- a/Alc/effects/compressor.cpp +++ b/Alc/effects/compressor.cpp @@ -39,13 +39,13 @@ struct ALcompressorState final : public ALeffectState { /* Effect gains for each channel */ - ALfloat Gain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS]; + ALfloat mGain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS]{}; /* Effect parameters */ - ALboolean Enabled; - ALfloat AttackMult; - ALfloat ReleaseMult; - ALfloat EnvFollower; + ALboolean mEnabled{AL_TRUE}; + ALfloat mAttackMult{1.0f}; + ALfloat mReleaseMult{1.0f}; + ALfloat mEnvFollower{1.0f}; }; static ALvoid ALcompressorState_Destruct(ALcompressorState *state); @@ -62,11 +62,6 @@ static void ALcompressorState_Construct(ALcompressorState *state) new (state) ALcompressorState{}; ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); SET_VTABLE2(ALcompressorState, ALeffectState, state); - - state->Enabled = AL_TRUE; - state->AttackMult = 1.0f; - state->ReleaseMult = 1.0f; - state->EnvFollower = 1.0f; } static ALvoid ALcompressorState_Destruct(ALcompressorState *state) @@ -86,8 +81,8 @@ static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdev /* Calculate per-sample multipliers to attack and release at the desired * rates. */ - state->AttackMult = powf(AMP_ENVELOPE_MAX/AMP_ENVELOPE_MIN, 1.0f/attackCount); - state->ReleaseMult = powf(AMP_ENVELOPE_MIN/AMP_ENVELOPE_MAX, 1.0f/releaseCount); + state->mAttackMult = powf(AMP_ENVELOPE_MAX/AMP_ENVELOPE_MIN, 1.0f/attackCount); + state->mReleaseMult = powf(AMP_ENVELOPE_MIN/AMP_ENVELOPE_MAX, 1.0f/releaseCount); return AL_TRUE; } @@ -97,13 +92,13 @@ static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCcontex const ALCdevice *device = context->Device; ALuint i; - state->Enabled = props->Compressor.OnOff; + state->mEnabled = props->Compressor.OnOff; - STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; - STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; + state->OutBuffer = device->FOAOut.Buffer; + state->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < 4;i++) ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain, - state->Gain[i]); + state->mGain[i]); } static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) @@ -115,10 +110,10 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei Sample { ALfloat gains[256]; ALsizei td = mini(256, SamplesToDo-base); - ALfloat env = state->EnvFollower; + ALfloat env = state->mEnvFollower; /* Generate the per-sample gains from the signal envelope. */ - if(state->Enabled) + if(state->mEnabled) { for(i = 0;i < td;++i) { @@ -128,9 +123,9 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei Sample ALfloat amplitude = clampf(fabsf(SamplesIn[0][base+i]), AMP_ENVELOPE_MIN, AMP_ENVELOPE_MAX); if(amplitude > env) - env = minf(env*state->AttackMult, amplitude); + env = minf(env*state->mAttackMult, amplitude); else if(amplitude < env) - env = maxf(env*state->ReleaseMult, amplitude); + env = maxf(env*state->mReleaseMult, amplitude); /* Apply the reciprocal of the envelope to normalize the volume * (compress the dynamic range). @@ -148,21 +143,21 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei Sample { ALfloat amplitude = 1.0f; if(amplitude > env) - env = minf(env*state->AttackMult, amplitude); + env = minf(env*state->mAttackMult, amplitude); else if(amplitude < env) - env = maxf(env*state->ReleaseMult, amplitude); + env = maxf(env*state->mReleaseMult, amplitude); gains[i] = 1.0f / env; } } - state->EnvFollower = env; + state->mEnvFollower = env; /* Now compress the signal amplitude to output. */ for(j = 0;j < MAX_EFFECT_CHANNELS;j++) { for(k = 0;k < NumChannels;k++) { - ALfloat gain = state->Gain[j][k]; + ALfloat gain = state->mGain[j][k]; if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; diff --git a/Alc/effects/dedicated.cpp b/Alc/effects/dedicated.cpp index f91458b3..8a59fd4b 100644 --- a/Alc/effects/dedicated.cpp +++ b/Alc/effects/dedicated.cpp @@ -22,6 +22,7 @@ #include #include +#include #include "alMain.h" #include "alcontext.h" @@ -31,8 +32,8 @@ struct ALdedicatedState final : public ALeffectState { - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; + ALfloat mCurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat mTargetGains[MAX_OUTPUT_CHANNELS]; }; static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state); @@ -59,9 +60,7 @@ static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state) static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *state, ALCdevice *UNUSED(device)) { - ALsizei i; - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - state->CurrentGains[i] = 0.0f; + std::fill(std::begin(state->mCurrentGains), std::end(state->mCurrentGains), 0.0f); return AL_TRUE; } @@ -69,10 +68,8 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext { const ALCdevice *device = context->Device; ALfloat Gain; - ALsizei i; - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - state->TargetGains[i] = 0.0f; + std::fill(std::begin(state->mTargetGains), std::end(state->mTargetGains), 0.0f); Gain = slot->Params.Gain * props->Dedicated.Gain; if(slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) @@ -80,38 +77,38 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext int idx; if((idx=GetChannelIdxByName(&device->RealOut, LFE)) != -1) { - STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer; - STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels; - state->TargetGains[idx] = Gain; + state->OutBuffer = device->RealOut.Buffer; + state->OutChannels = device->RealOut.NumChannels; + state->mTargetGains[idx] = Gain; } } else if(slot->Params.EffectType == AL_EFFECT_DEDICATED_DIALOGUE) { - int idx; /* Dialog goes to the front-center speaker if it exists, otherwise it * plays from the front-center location. */ - if((idx=GetChannelIdxByName(&device->RealOut, FrontCenter)) != -1) + int idx{GetChannelIdxByName(&device->RealOut, FrontCenter)}; + if(idx != -1) { - STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer; - STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels; - state->TargetGains[idx] = Gain; + state->OutBuffer = device->RealOut.Buffer; + state->OutChannels = device->RealOut.NumChannels; + state->mTargetGains[idx] = Gain; } else { ALfloat coeffs[MAX_AMBI_COEFFS]; CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - STATIC_CAST(ALeffectState,state)->OutBuffer = device->Dry.Buffer; - STATIC_CAST(ALeffectState,state)->OutChannels = device->Dry.NumChannels; - ComputePanGains(&device->Dry, coeffs, Gain, state->TargetGains); + state->OutBuffer = device->Dry.Buffer; + state->OutChannels = device->Dry.NumChannels; + ComputePanGains(&device->Dry, coeffs, Gain, state->mTargetGains); } } } static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - MixSamples(SamplesIn[0], NumChannels, SamplesOut, state->CurrentGains, - state->TargetGains, SamplesToDo, 0, SamplesToDo); + MixSamples(SamplesIn[0], NumChannels, SamplesOut, state->mCurrentGains, + state->mTargetGains, SamplesToDo, 0, SamplesToDo); } diff --git a/Alc/effects/distortion.cpp b/Alc/effects/distortion.cpp index 69603db9..48acfa56 100644 --- a/Alc/effects/distortion.cpp +++ b/Alc/effects/distortion.cpp @@ -33,15 +33,15 @@ struct ALdistortionState final : public ALeffectState { /* Effect gains for each channel */ - ALfloat Gain[MAX_OUTPUT_CHANNELS]; + ALfloat mGain[MAX_OUTPUT_CHANNELS]{}; /* Effect parameters */ - BiquadFilter lowpass; - BiquadFilter bandpass; - ALfloat attenuation; - ALfloat edge_coeff; + BiquadFilter mLowpass; + BiquadFilter mBandpass; + ALfloat mAttenuation{}; + ALfloat mEdgeCoeff{}; - ALfloat Buffer[2][BUFFERSIZE]; + ALfloat Buffer[2][BUFFERSIZE]{}; }; static ALvoid ALdistortionState_Destruct(ALdistortionState *state); @@ -68,8 +68,8 @@ static ALvoid ALdistortionState_Destruct(ALdistortionState *state) static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *UNUSED(device)) { - BiquadFilter_clear(&state->lowpass); - BiquadFilter_clear(&state->bandpass); + BiquadFilter_clear(&state->mLowpass); + BiquadFilter_clear(&state->mBandpass); return AL_TRUE; } @@ -85,7 +85,7 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontex /* Store waveshaper edge settings. */ edge = sinf(props->Distortion.Edge * (F_PI_2)); edge = minf(edge, 0.99f); - state->edge_coeff = 2.0f * edge / (1.0f-edge); + state->mEdgeCoeff = 2.0f * edge / (1.0f-edge); cutoff = props->Distortion.LowpassCutoff; /* Bandwidth value is constant in octaves. */ @@ -93,25 +93,25 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontex /* Multiply sampling frequency by the amount of oversampling done during * processing. */ - BiquadFilter_setParams(&state->lowpass, BiquadType::LowPass, 1.0f, + BiquadFilter_setParams(&state->mLowpass, BiquadType::LowPass, 1.0f, cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); cutoff = props->Distortion.EQCenter; /* Convert bandwidth in Hz to octaves. */ bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f); - BiquadFilter_setParams(&state->bandpass, BiquadType::BandPass, 1.0f, + BiquadFilter_setParams(&state->mBandpass, BiquadType::BandPass, 1.0f, cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain*props->Distortion.Gain, state->Gain); + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain*props->Distortion.Gain, state->mGain); } static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { ALfloat (*RESTRICT buffer)[BUFFERSIZE] = state->Buffer; - const ALfloat fc = state->edge_coeff; + const ALfloat fc = state->mEdgeCoeff; ALsizei base; ALsizei i, k; @@ -135,7 +135,7 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei Sample * (which is fortunately first step of distortion). So combine three * operations into the one. */ - BiquadFilter_process(&state->lowpass, buffer[1], buffer[0], todo); + BiquadFilter_process(&state->mLowpass, buffer[1], buffer[0], todo); /* Second step, do distortion using waveshaper function to emulate * signal processing during tube overdriving. Three steps of @@ -154,7 +154,7 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei Sample } /* Third step, do bandpass filtering of distorted signal. */ - BiquadFilter_process(&state->bandpass, buffer[1], buffer[0], todo); + BiquadFilter_process(&state->mBandpass, buffer[1], buffer[0], todo); todo >>= 2; for(k = 0;k < NumChannels;k++) @@ -162,7 +162,7 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei Sample /* Fourth step, final, do attenuation and perform decimation, * storing only one sample out of four. */ - ALfloat gain = state->Gain[k]; + ALfloat gain = state->mGain[k]; if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index 946c07b4..2de6a44d 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -23,6 +23,8 @@ #include #include +#include + #include "alMain.h" #include "alcontext.h" #include "alFilter.h" @@ -33,25 +35,25 @@ struct ALechoState final : public ALeffectState { - ALfloat *SampleBuffer; - ALsizei BufferLength; + ALfloat *mSampleBuffer{nullptr}; + ALsizei mBufferLength{0}; // The echo is two tap. The delay is the number of samples from before the // current offset struct { - ALsizei delay; - } Tap[2]; - ALsizei Offset; + ALsizei delay{0}; + } mTap[2]; + ALsizei mOffset{0}; /* The panning gains for the two taps */ struct { - ALfloat Current[MAX_OUTPUT_CHANNELS]; - ALfloat Target[MAX_OUTPUT_CHANNELS]; - } Gains[2]; + ALfloat Current[MAX_OUTPUT_CHANNELS]{}; + ALfloat Target[MAX_OUTPUT_CHANNELS]{}; + } mGains[2]; - ALfloat FeedGain; + ALfloat mFeedGain{0.0f}; - BiquadFilter Filter; + BiquadFilter mFilter; }; static ALvoid ALechoState_Destruct(ALechoState *state); @@ -68,21 +70,12 @@ static void ALechoState_Construct(ALechoState *state) new (state) ALechoState{}; ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); SET_VTABLE2(ALechoState, ALeffectState, state); - - state->BufferLength = 0; - state->SampleBuffer = NULL; - - state->Tap[0].delay = 0; - state->Tap[1].delay = 0; - state->Offset = 0; - - BiquadFilter_clear(&state->Filter); } static ALvoid ALechoState_Destruct(ALechoState *state) { - al_free(state->SampleBuffer); - state->SampleBuffer = NULL; + al_free(state->mSampleBuffer); + state->mSampleBuffer = NULL; ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); state->~ALechoState(); } @@ -98,18 +91,22 @@ static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device) maxlen = NextPowerOf2(maxlen); if(maxlen <= 0) return AL_FALSE; - if(maxlen != state->BufferLength) + if(maxlen != state->mBufferLength) { void *temp = al_calloc(16, maxlen * sizeof(ALfloat)); if(!temp) return AL_FALSE; - al_free(state->SampleBuffer); - state->SampleBuffer = static_cast(temp); - state->BufferLength = maxlen; + al_free(state->mSampleBuffer); + state->mSampleBuffer = static_cast(temp); + state->mBufferLength = maxlen; } - memset(state->SampleBuffer, 0, state->BufferLength*sizeof(ALfloat)); - memset(state->Gains, 0, sizeof(state->Gains)); + std::fill_n(state->mSampleBuffer, state->mBufferLength, 0.0f); + for(auto &e : state->mGains) + { + std::fill(std::begin(e.Current), std::end(e.Current), 0.0f); + std::fill(std::begin(e.Target), std::end(e.Target), 0.0f); + } return AL_TRUE; } @@ -121,9 +118,9 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, ALfloat coeffs[MAX_AMBI_COEFFS]; ALfloat gainhf, lrpan, spread; - state->Tap[0].delay = maxi(float2int(props->Echo.Delay*frequency + 0.5f), 1); - state->Tap[1].delay = float2int(props->Echo.LRDelay*frequency + 0.5f); - state->Tap[1].delay += state->Tap[0].delay; + state->mTap[0].delay = maxi(float2int(props->Echo.Delay*frequency + 0.5f), 1); + state->mTap[1].delay = float2int(props->Echo.LRDelay*frequency + 0.5f); + state->mTap[1].delay += state->mTap[0].delay; spread = props->Echo.Spread; if(spread < 0.0f) lrpan = -1.0f; @@ -133,35 +130,35 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, */ spread = asinf(1.0f - fabsf(spread))*4.0f; - state->FeedGain = props->Echo.Feedback; + state->mFeedGain = props->Echo.Feedback; gainhf = maxf(1.0f - props->Echo.Damping, 0.0625f); /* Limit -24dB */ - BiquadFilter_setParams(&state->Filter, BiquadType::HighShelf, + BiquadFilter_setParams(&state->mFilter, BiquadType::HighShelf, gainhf, LOWPASSFREQREF/frequency, calc_rcpQ_from_slope(gainhf, 1.0f) ); /* First tap panning */ CalcAngleCoeffs(-F_PI_2*lrpan, 0.0f, spread, coeffs); - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->Gains[0].Target); + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->mGains[0].Target); /* Second tap panning */ CalcAngleCoeffs( F_PI_2*lrpan, 0.0f, spread, coeffs); - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->Gains[1].Target); + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->mGains[1].Target); } static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - const ALsizei mask = state->BufferLength-1; - const ALsizei tap1 = state->Tap[0].delay; - const ALsizei tap2 = state->Tap[1].delay; - ALfloat *RESTRICT delaybuf = state->SampleBuffer; - ALsizei offset = state->Offset; + const ALsizei mask = state->mBufferLength-1; + const ALsizei tap1 = state->mTap[0].delay; + const ALsizei tap2 = state->mTap[1].delay; + ALfloat *RESTRICT delaybuf = state->mSampleBuffer; + ALsizei offset = state->mOffset; ALfloat z1, z2, in, out; ALsizei base; ALsizei c, i; - z1 = state->Filter.z1; - z2 = state->Filter.z2; + z1 = state->mFilter.z1; + z2 = state->mFilter.z2; for(base = 0;base < SamplesToDo;) { alignas(16) ALfloat temps[2][128]; @@ -181,24 +178,24 @@ static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const * feedback attenuation. */ in = temps[1][i]; - out = in*state->Filter.b0 + z1; - z1 = in*state->Filter.b1 - out*state->Filter.a1 + z2; - z2 = in*state->Filter.b2 - out*state->Filter.a2; + out = in*state->mFilter.b0 + z1; + z1 = in*state->mFilter.b1 - out*state->mFilter.a1 + z2; + z2 = in*state->mFilter.b2 - out*state->mFilter.a2; - delaybuf[offset&mask] += out * state->FeedGain; + delaybuf[offset&mask] += out * state->mFeedGain; offset++; } for(c = 0;c < 2;c++) - MixSamples(temps[c], NumChannels, SamplesOut, state->Gains[c].Current, - state->Gains[c].Target, SamplesToDo-base, base, td); + MixSamples(temps[c], NumChannels, SamplesOut, state->mGains[c].Current, + state->mGains[c].Target, SamplesToDo-base, base, td); base += td; } - state->Filter.z1 = z1; - state->Filter.z2 = z2; + state->mFilter.z1 = z1; + state->mFilter.z2 = z2; - state->Offset = offset; + state->mOffset = offset; } -- cgit v1.2.3 From 67da3850cbf43dd6c40b41e905b446bec975663c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 20:15:40 -0800 Subject: Use a normal vector for the echo buffer --- Alc/effects/echo.cpp | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index 2de6a44d..a72b242c 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -32,11 +32,11 @@ #include "alError.h" #include "alu.h" #include "filters/defs.h" +#include "vector.h" struct ALechoState final : public ALeffectState { - ALfloat *mSampleBuffer{nullptr}; - ALsizei mBufferLength{0}; + al::vector mSampleBuffer; // The echo is two tap. The delay is the number of samples from before the // current offset @@ -74,15 +74,13 @@ static void ALechoState_Construct(ALechoState *state) static ALvoid ALechoState_Destruct(ALechoState *state) { - al_free(state->mSampleBuffer); - state->mSampleBuffer = NULL; ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); state->~ALechoState(); } static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device) { - ALsizei maxlen; + ALuint maxlen; // Use the next power of 2 for the buffer length, so the tap offsets can be // wrapped using a mask instead of a modulo @@ -91,17 +89,13 @@ static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device) maxlen = NextPowerOf2(maxlen); if(maxlen <= 0) return AL_FALSE; - if(maxlen != state->mBufferLength) + if(maxlen != state->mSampleBuffer.size()) { - void *temp = al_calloc(16, maxlen * sizeof(ALfloat)); - if(!temp) return AL_FALSE; - - al_free(state->mSampleBuffer); - state->mSampleBuffer = static_cast(temp); - state->mBufferLength = maxlen; + state->mSampleBuffer.resize(maxlen); + state->mSampleBuffer.shrink_to_fit(); } - std::fill_n(state->mSampleBuffer, state->mBufferLength, 0.0f); + std::fill(state->mSampleBuffer.begin(), state->mSampleBuffer.end(), 0.0f); for(auto &e : state->mGains) { std::fill(std::begin(e.Current), std::end(e.Current), 0.0f); @@ -148,10 +142,10 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - const ALsizei mask = state->mBufferLength-1; + const ALsizei mask = state->mSampleBuffer.size()-1; const ALsizei tap1 = state->mTap[0].delay; const ALsizei tap2 = state->mTap[1].delay; - ALfloat *RESTRICT delaybuf = state->mSampleBuffer; + ALfloat *RESTRICT delaybuf = state->mSampleBuffer.data(); ALsizei offset = state->mOffset; ALfloat z1, z2, in, out; ALsizei base; -- cgit v1.2.3 From 6ac84c7a5f6d267522bdc872802c8940dcd2adec Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 21:04:50 -0800 Subject: Clean up the remaining effect struct member names --- Alc/effects/equalizer.cpp | 57 +++++++++---------- Alc/effects/fshifter.cpp | 108 ++++++++++++++++++------------------ Alc/effects/modulator.cpp | 68 +++++++++++------------ Alc/effects/pshifter.cpp | 138 +++++++++++++++++++++++----------------------- 4 files changed, 184 insertions(+), 187 deletions(-) diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index ad101a7e..814b43a4 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -23,6 +23,8 @@ #include #include +#include + #include "alMain.h" #include "alcontext.h" #include "alAuxEffectSlot.h" @@ -80,11 +82,11 @@ struct ALequalizerState final : public ALeffectState { BiquadFilter filter[4]; /* Effect gains for each channel */ - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; - } Chans[MAX_EFFECT_CHANNELS]; + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]{}; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]{}; + } mChans[MAX_EFFECT_CHANNELS]; - ALfloat SampleBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE]; + ALfloat mSampleBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE]{}; }; static ALvoid ALequalizerState_Destruct(ALequalizerState *state); @@ -111,14 +113,13 @@ static ALvoid ALequalizerState_Destruct(ALequalizerState *state) static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevice *UNUSED(device)) { - ALsizei i, j; - - for(i = 0; i < MAX_EFFECT_CHANNELS;i++) + for(auto &e : state->mChans) { - for(j = 0;j < 4;j++) - BiquadFilter_clear(&state->Chans[i].filter[j]); - for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - state->Chans[i].CurrentGains[j] = 0.0f; + std::for_each(std::begin(e.filter), std::end(e.filter), + [](BiquadFilter &f) -> void + { BiquadFilter_clear(&f); } + ); + std::fill(std::begin(e.CurrentGains), std::end(e.CurrentGains), 0.0f); } return AL_TRUE; } @@ -136,13 +137,13 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext */ gain = maxf(sqrtf(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */ f0norm = props->Equalizer.LowCutoff/frequency; - BiquadFilter_setParams(&state->Chans[0].filter[0], BiquadType::LowShelf, + BiquadFilter_setParams(&state->mChans[0].filter[0], BiquadType::LowShelf, gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f) ); gain = maxf(props->Equalizer.Mid1Gain, 0.0625f); f0norm = props->Equalizer.Mid1Center/frequency; - BiquadFilter_setParams(&state->Chans[0].filter[1], BiquadType::Peaking, + BiquadFilter_setParams(&state->mChans[0].filter[1], BiquadType::Peaking, gain, f0norm, calc_rcpQ_from_bandwidth( f0norm, props->Equalizer.Mid1Width ) @@ -150,7 +151,7 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext gain = maxf(props->Equalizer.Mid2Gain, 0.0625f); f0norm = props->Equalizer.Mid2Center/frequency; - BiquadFilter_setParams(&state->Chans[0].filter[2], BiquadType::Peaking, + BiquadFilter_setParams(&state->mChans[0].filter[2], BiquadType::Peaking, gain, f0norm, calc_rcpQ_from_bandwidth( f0norm, props->Equalizer.Mid2Width ) @@ -158,40 +159,40 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext gain = maxf(sqrtf(props->Equalizer.HighGain), 0.0625f); f0norm = props->Equalizer.HighCutoff/frequency; - BiquadFilter_setParams(&state->Chans[0].filter[3], BiquadType::HighShelf, + BiquadFilter_setParams(&state->mChans[0].filter[3], BiquadType::HighShelf, gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f) ); /* Copy the filter coefficients for the other input channels. */ for(i = 1;i < MAX_EFFECT_CHANNELS;i++) { - BiquadFilter_copyParams(&state->Chans[i].filter[0], &state->Chans[0].filter[0]); - BiquadFilter_copyParams(&state->Chans[i].filter[1], &state->Chans[0].filter[1]); - BiquadFilter_copyParams(&state->Chans[i].filter[2], &state->Chans[0].filter[2]); - BiquadFilter_copyParams(&state->Chans[i].filter[3], &state->Chans[0].filter[3]); + BiquadFilter_copyParams(&state->mChans[i].filter[0], &state->mChans[0].filter[0]); + BiquadFilter_copyParams(&state->mChans[i].filter[1], &state->mChans[0].filter[1]); + BiquadFilter_copyParams(&state->mChans[i].filter[2], &state->mChans[0].filter[2]); + BiquadFilter_copyParams(&state->mChans[i].filter[3], &state->mChans[0].filter[3]); } - STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; - STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; + state->OutBuffer = device->FOAOut.Buffer; + state->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain, - state->Chans[i].TargetGains); + state->mChans[i].TargetGains); } static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALfloat (*RESTRICT temps)[BUFFERSIZE] = state->SampleBuffer; + ALfloat (*RESTRICT temps)[BUFFERSIZE] = state->mSampleBuffer; ALsizei c; for(c = 0;c < MAX_EFFECT_CHANNELS;c++) { - BiquadFilter_process(&state->Chans[c].filter[0], temps[0], SamplesIn[c], SamplesToDo); - BiquadFilter_process(&state->Chans[c].filter[1], temps[1], temps[0], SamplesToDo); - BiquadFilter_process(&state->Chans[c].filter[2], temps[2], temps[1], SamplesToDo); - BiquadFilter_process(&state->Chans[c].filter[3], temps[3], temps[2], SamplesToDo); + BiquadFilter_process(&state->mChans[c].filter[0], temps[0], SamplesIn[c], SamplesToDo); + BiquadFilter_process(&state->mChans[c].filter[1], temps[1], temps[0], SamplesToDo); + BiquadFilter_process(&state->mChans[c].filter[2], temps[2], temps[1], SamplesToDo); + BiquadFilter_process(&state->mChans[c].filter[3], temps[3], temps[2], SamplesToDo); MixSamples(temps[3], NumChannels, SamplesOut, - state->Chans[c].CurrentGains, state->Chans[c].TargetGains, + state->mChans[c].CurrentGains, state->mChans[c].TargetGains, SamplesToDo, 0, SamplesToDo ); } diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp index 7775fafb..b4d073da 100644 --- a/Alc/effects/fshifter.cpp +++ b/Alc/effects/fshifter.cpp @@ -62,23 +62,23 @@ alignas(16) const std::array HannWindow = InitHannWindow(); struct ALfshifterState final : public ALeffectState { /* Effect parameters */ - ALsizei count; - ALsizei PhaseStep; - ALsizei Phase; - ALdouble ld_sign; + ALsizei mCount{}; + ALsizei mPhaseStep{}; + ALsizei mPhase{}; + ALdouble mLdSign{}; /*Effects buffers*/ - ALfloat InFIFO[HIL_SIZE]; - complex_d OutFIFO[HIL_SIZE]; - complex_d OutputAccum[HIL_SIZE]; - complex_d Analytic[HIL_SIZE]; - complex_d Outdata[BUFFERSIZE]; + ALfloat mInFIFO[HIL_SIZE]{}; + complex_d mOutFIFO[HIL_SIZE]{}; + complex_d mOutputAccum[HIL_SIZE]{}; + complex_d mAnalytic[HIL_SIZE]{}; + complex_d mOutdata[BUFFERSIZE]{}; - alignas(16) ALfloat BufferOut[BUFFERSIZE]; + alignas(16) ALfloat mBufferOut[BUFFERSIZE]{}; /* Effect gains for each output channel */ - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; + ALfloat mCurrentGains[MAX_OUTPUT_CHANNELS]{}; + ALfloat mTargetGains[MAX_OUTPUT_CHANNELS]{}; }; ALvoid ALfshifterState_Destruct(ALfshifterState *state); @@ -105,113 +105,111 @@ ALvoid ALfshifterState_Destruct(ALfshifterState *state) ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *UNUSED(device)) { /* (Re-)initializing parameters and clear the buffers. */ - state->count = FIFO_LATENCY; - state->PhaseStep = 0; - state->Phase = 0; - state->ld_sign = 1.0; + state->mCount = FIFO_LATENCY; + state->mPhaseStep = 0; + state->mPhase = 0; + state->mLdSign = 1.0; - std::fill(std::begin(state->InFIFO), std::end(state->InFIFO), 0.0f); - std::fill(std::begin(state->OutFIFO), std::end(state->OutFIFO), complex_d{}); - std::fill(std::begin(state->OutputAccum), std::end(state->OutputAccum), complex_d{}); - std::fill(std::begin(state->Analytic), std::end(state->Analytic), complex_d{}); + std::fill(std::begin(state->mInFIFO), std::end(state->mInFIFO), 0.0f); + std::fill(std::begin(state->mOutFIFO), std::end(state->mOutFIFO), complex_d{}); + std::fill(std::begin(state->mOutputAccum), std::end(state->mOutputAccum), complex_d{}); + std::fill(std::begin(state->mAnalytic), std::end(state->mAnalytic), complex_d{}); - std::fill(std::begin(state->CurrentGains), std::end(state->CurrentGains), 0.0f); - std::fill(std::begin(state->TargetGains), std::end(state->TargetGains), 0.0f); + std::fill(std::begin(state->mCurrentGains), std::end(state->mCurrentGains), 0.0f); + std::fill(std::begin(state->mTargetGains), std::end(state->mTargetGains), 0.0f); return AL_TRUE; } ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) { - const ALCdevice *device = context->Device; - ALfloat coeffs[MAX_AMBI_COEFFS]; - ALfloat step; + const ALCdevice *device{context->Device}; - step = props->Fshifter.Frequency / (ALfloat)device->Frequency; - state->PhaseStep = fastf2i(minf(step, 0.5f) * FRACTIONONE); + ALfloat step{props->Fshifter.Frequency / (ALfloat)device->Frequency}; + state->mPhaseStep = fastf2i(minf(step, 0.5f) * FRACTIONONE); switch(props->Fshifter.LeftDirection) { case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: - state->ld_sign = -1.0; + state->mLdSign = -1.0; break; case AL_FREQUENCY_SHIFTER_DIRECTION_UP: - state->ld_sign = 1.0; + state->mLdSign = 1.0; break; case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: - state->Phase = 0; - state->PhaseStep = 0; + state->mPhase = 0; + state->mPhaseStep = 0; break; } + ALfloat coeffs[MAX_AMBI_COEFFS]; CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->mTargetGains); } ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { static const complex_d complex_zero{0.0, 0.0}; - ALfloat *RESTRICT BufferOut = state->BufferOut; + ALfloat *RESTRICT BufferOut = state->mBufferOut; ALsizei j, k, base; for(base = 0;base < SamplesToDo;) { - ALsizei todo = mini(HIL_SIZE-state->count, SamplesToDo-base); + ALsizei todo = mini(HIL_SIZE-state->mCount, SamplesToDo-base); ASSUME(todo > 0); /* Fill FIFO buffer with samples data */ - k = state->count; + k = state->mCount; for(j = 0;j < todo;j++,k++) { - state->InFIFO[k] = SamplesIn[0][base+j]; - state->Outdata[base+j] = state->OutFIFO[k-FIFO_LATENCY]; + state->mInFIFO[k] = SamplesIn[0][base+j]; + state->mOutdata[base+j] = state->mOutFIFO[k-FIFO_LATENCY]; } - state->count += todo; + state->mCount += todo; base += todo; /* Check whether FIFO buffer is filled */ - if(state->count < HIL_SIZE) continue; - - state->count = FIFO_LATENCY; + if(state->mCount < HIL_SIZE) continue; + state->mCount = FIFO_LATENCY; /* Real signal windowing and store in Analytic buffer */ for(k = 0;k < HIL_SIZE;k++) { - state->Analytic[k].real(state->InFIFO[k] * HannWindow[k]); - state->Analytic[k].imag(0.0); + state->mAnalytic[k].real(state->mInFIFO[k] * HannWindow[k]); + state->mAnalytic[k].imag(0.0); } /* Processing signal by Discrete Hilbert Transform (analytical signal). */ - complex_hilbert(state->Analytic, HIL_SIZE); + complex_hilbert(state->mAnalytic, HIL_SIZE); /* Windowing and add to output accumulator */ for(k = 0;k < HIL_SIZE;k++) - state->OutputAccum[k] += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k]; + state->mOutputAccum[k] += 2.0/OVERSAMP*HannWindow[k]*state->mAnalytic[k]; /* Shift accumulator, input & output FIFO */ - for(k = 0;k < HIL_STEP;k++) state->OutFIFO[k] = state->OutputAccum[k]; - for(j = 0;k < HIL_SIZE;k++,j++) state->OutputAccum[j] = state->OutputAccum[k]; - for(;j < HIL_SIZE;j++) state->OutputAccum[j] = complex_zero; + for(k = 0;k < HIL_STEP;k++) state->mOutFIFO[k] = state->mOutputAccum[k]; + for(j = 0;k < HIL_SIZE;k++,j++) state->mOutputAccum[j] = state->mOutputAccum[k]; + for(;j < HIL_SIZE;j++) state->mOutputAccum[j] = complex_zero; for(k = 0;k < FIFO_LATENCY;k++) - state->InFIFO[k] = state->InFIFO[k+HIL_STEP]; + state->mInFIFO[k] = state->mInFIFO[k+HIL_STEP]; } /* Process frequency shifter using the analytic signal obtained. */ for(k = 0;k < SamplesToDo;k++) { - double phase = state->Phase * ((1.0/FRACTIONONE) * 2.0*M_PI); - BufferOut[k] = (float)(state->Outdata[k].real()*std::cos(phase) + - state->Outdata[k].imag()*std::sin(phase)*state->ld_sign); + double phase = state->mPhase * ((1.0/FRACTIONONE) * 2.0*M_PI); + BufferOut[k] = (float)(state->mOutdata[k].real()*std::cos(phase) + + state->mOutdata[k].imag()*std::sin(phase)*state->mLdSign); - state->Phase += state->PhaseStep; - state->Phase &= FRACTIONMASK; + state->mPhase += state->mPhaseStep; + state->mPhase &= FRACTIONMASK; } /* Now, mix the processed sound data to the output. */ - MixSamples(BufferOut, NumChannels, SamplesOut, state->CurrentGains, state->TargetGains, + MixSamples(BufferOut, NumChannels, SamplesOut, state->mCurrentGains, state->mTargetGains, maxi(SamplesToDo, 512), 0, SamplesToDo); } diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index b7ee97d9..0062a779 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -23,6 +23,9 @@ #include #include +#include +#include + #include "alMain.h" #include "alcontext.h" #include "alAuxEffectSlot.h" @@ -35,17 +38,17 @@ #define MAX_UPDATE_SAMPLES 128 struct ALmodulatorState final : public ALeffectState { - void (*GetSamples)(ALfloat*RESTRICT, ALsizei, const ALsizei, ALsizei); + void (*mGetSamples)(ALfloat*RESTRICT, ALsizei, const ALsizei, ALsizei){}; - ALsizei index; - ALsizei step; + ALsizei mIndex{0}; + ALsizei mStep{1}; struct { BiquadFilter Filter; - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; - } Chans[MAX_EFFECT_CHANNELS]; + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]{}; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]{}; + } mChans[MAX_EFFECT_CHANNELS]; }; static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state); @@ -63,7 +66,7 @@ DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState); static inline ALfloat Sin(ALsizei index) { - return sinf((ALfloat)index * (F_TAU / WAVEFORM_FRACONE)); + return std::sin((ALfloat)index * (F_TAU / (ALfloat)WAVEFORM_FRACONE)); } static inline ALfloat Saw(ALsizei index) @@ -107,9 +110,6 @@ static void ALmodulatorState_Construct(ALmodulatorState *state) new (state) ALmodulatorState{}; ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); SET_VTABLE2(ALmodulatorState, ALeffectState, state); - - state->index = 0; - state->step = 1; } static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state) @@ -120,12 +120,10 @@ static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state) static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevice *UNUSED(device)) { - ALsizei i, j; - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + for(auto &e : state->mChans) { - BiquadFilter_clear(&state->Chans[i].Filter); - for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - state->Chans[i].CurrentGains[j] = 0.0f; + BiquadFilter_clear(&e.Filter); + std::fill(std::begin(e.CurrentGains), std::end(e.CurrentGains), 0.0f); } return AL_TRUE; } @@ -136,37 +134,37 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext ALfloat f0norm; ALsizei i; - state->step = fastf2i(props->Modulator.Frequency / (ALfloat)device->Frequency * - WAVEFORM_FRACONE); - state->step = clampi(state->step, 0, WAVEFORM_FRACONE-1); + state->mStep = fastf2i(props->Modulator.Frequency / (ALfloat)device->Frequency * + WAVEFORM_FRACONE); + state->mStep = clampi(state->mStep, 0, WAVEFORM_FRACONE-1); - if(state->step == 0) - state->GetSamples = ModulateOne; + if(state->mStep == 0) + state->mGetSamples = ModulateOne; else if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) - state->GetSamples = ModulateSin; + state->mGetSamples = ModulateSin; else if(props->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) - state->GetSamples = ModulateSaw; + state->mGetSamples = ModulateSaw; else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/ - state->GetSamples = ModulateSquare; + state->mGetSamples = ModulateSquare; f0norm = props->Modulator.HighPassCutoff / (ALfloat)device->Frequency; f0norm = clampf(f0norm, 1.0f/512.0f, 0.49f); /* Bandwidth value is constant in octaves. */ - BiquadFilter_setParams(&state->Chans[0].Filter, BiquadType::HighPass, 1.0f, + BiquadFilter_setParams(&state->mChans[0].Filter, BiquadType::HighPass, 1.0f, f0norm, calc_rcpQ_from_bandwidth(f0norm, 0.75f)); for(i = 1;i < MAX_EFFECT_CHANNELS;i++) - BiquadFilter_copyParams(&state->Chans[i].Filter, &state->Chans[0].Filter); + BiquadFilter_copyParams(&state->mChans[i].Filter, &state->mChans[0].Filter); - STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; - STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; + state->OutBuffer = device->FOAOut.Buffer; + state->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain, - state->Chans[i].TargetGains); + state->mChans[i].TargetGains); } static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - const ALsizei step = state->step; + const ALsizei step = state->mStep; ALsizei base; for(base = 0;base < SamplesToDo;) @@ -175,20 +173,20 @@ static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesT ALsizei td = mini(MAX_UPDATE_SAMPLES, SamplesToDo-base); ALsizei c, i; - state->GetSamples(modsamples, state->index, step, td); - state->index += (step*td) & WAVEFORM_FRACMASK; - state->index &= WAVEFORM_FRACMASK; + state->mGetSamples(modsamples, state->mIndex, step, td); + state->mIndex += (step*td) & WAVEFORM_FRACMASK; + state->mIndex &= WAVEFORM_FRACMASK; for(c = 0;c < MAX_EFFECT_CHANNELS;c++) { alignas(16) ALfloat temps[MAX_UPDATE_SAMPLES]; - BiquadFilter_process(&state->Chans[c].Filter, temps, &SamplesIn[c][base], td); + BiquadFilter_process(&state->mChans[c].Filter, temps, &SamplesIn[c][base], td); for(i = 0;i < td;i++) temps[i] *= modsamples[i]; - MixSamples(temps, NumChannels, SamplesOut, state->Chans[c].CurrentGains, - state->Chans[c].TargetGains, SamplesToDo-base, base, td); + MixSamples(temps, NumChannels, SamplesOut, state->mChans[c].CurrentGains, + state->mChans[c].TargetGains, SamplesToDo-base, base, td); } base += td; diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp index 217b021e..ec473678 100644 --- a/Alc/effects/pshifter.cpp +++ b/Alc/effects/pshifter.cpp @@ -119,28 +119,28 @@ inline complex_d polar2rect(const ALphasor &number) struct ALpshifterState final : public ALeffectState { /* Effect parameters */ - ALsizei count; - ALsizei PitchShiftI; - ALfloat PitchShift; - ALfloat FreqPerBin; + ALsizei mCount; + ALsizei mPitchShiftI; + ALfloat mPitchShift; + ALfloat mFreqPerBin; - /*Effects buffers*/ - ALfloat InFIFO[STFT_SIZE]; - ALfloat OutFIFO[STFT_STEP]; - ALdouble LastPhase[STFT_HALF_SIZE+1]; - ALdouble SumPhase[STFT_HALF_SIZE+1]; - ALdouble OutputAccum[STFT_SIZE]; + /* Effects buffers */ + ALfloat mInFIFO[STFT_SIZE]; + ALfloat mOutFIFO[STFT_STEP]; + ALdouble mLastPhase[STFT_HALF_SIZE+1]; + ALdouble mSumPhase[STFT_HALF_SIZE+1]; + ALdouble mOutputAccum[STFT_SIZE]; - complex_d FFTbuffer[STFT_SIZE]; + complex_d mFFTbuffer[STFT_SIZE]; - ALfrequencyDomain Analysis_buffer[STFT_HALF_SIZE+1]; - ALfrequencyDomain Syntesis_buffer[STFT_HALF_SIZE+1]; + ALfrequencyDomain mAnalysis_buffer[STFT_HALF_SIZE+1]; + ALfrequencyDomain mSyntesis_buffer[STFT_HALF_SIZE+1]; - alignas(16) ALfloat BufferOut[BUFFERSIZE]; + alignas(16) ALfloat mBufferOut[BUFFERSIZE]; /* Effect gains for each output channel */ - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; + ALfloat mCurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat mTargetGains[MAX_OUTPUT_CHANNELS]; }; static ALvoid ALpshifterState_Destruct(ALpshifterState *state); @@ -167,22 +167,22 @@ ALvoid ALpshifterState_Destruct(ALpshifterState *state) ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device) { /* (Re-)initializing parameters and clear the buffers. */ - state->count = FIFO_LATENCY; - state->PitchShiftI = FRACTIONONE; - state->PitchShift = 1.0f; - state->FreqPerBin = device->Frequency / (ALfloat)STFT_SIZE; - - std::fill(std::begin(state->InFIFO), std::end(state->InFIFO), 0.0f); - std::fill(std::begin(state->OutFIFO), std::end(state->OutFIFO), 0.0f); - std::fill(std::begin(state->LastPhase), std::end(state->LastPhase), 0.0); - std::fill(std::begin(state->SumPhase), std::end(state->SumPhase), 0.0); - std::fill(std::begin(state->OutputAccum), std::end(state->OutputAccum), 0.0); - std::fill(std::begin(state->FFTbuffer), std::end(state->FFTbuffer), complex_d{}); - std::fill(std::begin(state->Analysis_buffer), std::end(state->Analysis_buffer), ALfrequencyDomain{}); - std::fill(std::begin(state->Syntesis_buffer), std::end(state->Syntesis_buffer), ALfrequencyDomain{}); - - std::fill(std::begin(state->CurrentGains), std::end(state->CurrentGains), 0.0f); - std::fill(std::begin(state->TargetGains), std::end(state->TargetGains), 0.0f); + state->mCount = FIFO_LATENCY; + state->mPitchShiftI = FRACTIONONE; + state->mPitchShift = 1.0f; + state->mFreqPerBin = device->Frequency / (ALfloat)STFT_SIZE; + + std::fill(std::begin(state->mInFIFO), std::end(state->mInFIFO), 0.0f); + std::fill(std::begin(state->mOutFIFO), std::end(state->mOutFIFO), 0.0f); + std::fill(std::begin(state->mLastPhase), std::end(state->mLastPhase), 0.0); + std::fill(std::begin(state->mSumPhase), std::end(state->mSumPhase), 0.0); + std::fill(std::begin(state->mOutputAccum), std::end(state->mOutputAccum), 0.0); + std::fill(std::begin(state->mFFTbuffer), std::end(state->mFFTbuffer), complex_d{}); + std::fill(std::begin(state->mAnalysis_buffer), std::end(state->mAnalysis_buffer), ALfrequencyDomain{}); + std::fill(std::begin(state->mSyntesis_buffer), std::end(state->mSyntesis_buffer), ALfrequencyDomain{}); + + std::fill(std::begin(state->mCurrentGains), std::end(state->mCurrentGains), 0.0f); + std::fill(std::begin(state->mTargetGains), std::end(state->mTargetGains), 0.0f); return AL_TRUE; } @@ -196,11 +196,11 @@ ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, pitch = std::pow(2.0f, (ALfloat)(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f ); - state->PitchShiftI = fastf2i(pitch*FRACTIONONE); - state->PitchShift = state->PitchShiftI * (1.0f/FRACTIONONE); + state->mPitchShiftI = fastf2i(pitch*FRACTIONONE); + state->mPitchShift = state->mPitchShiftI * (1.0f/FRACTIONONE); CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->mTargetGains); } ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) @@ -210,16 +210,16 @@ ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, cons */ static constexpr ALdouble expected{M_PI*2.0 / OVERSAMP}; - const ALdouble freq_per_bin{state->FreqPerBin}; - ALfloat *RESTRICT bufferOut{state->BufferOut}; - ALsizei count{state->count}; + const ALdouble freq_per_bin{state->mFreqPerBin}; + ALfloat *RESTRICT bufferOut{state->mBufferOut}; + ALsizei count{state->mCount}; for(ALsizei i{0};i < SamplesToDo;) { do { /* Fill FIFO buffer with samples data */ - state->InFIFO[count] = SamplesIn[0][i]; - bufferOut[i] = state->OutFIFO[count - FIFO_LATENCY]; + state->mInFIFO[count] = SamplesIn[0][i]; + bufferOut[i] = state->mOutFIFO[count - FIFO_LATENCY]; count++; } while(++i < SamplesToDo && count < STFT_SIZE); @@ -231,13 +231,13 @@ ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, cons /* Real signal windowing and store in FFTbuffer */ for(ALsizei k{0};k < STFT_SIZE;k++) { - state->FFTbuffer[k].real(state->InFIFO[k] * HannWindow[k]); - state->FFTbuffer[k].imag(0.0); + state->mFFTbuffer[k].real(state->mInFIFO[k] * HannWindow[k]); + state->mFFTbuffer[k].imag(0.0); } /* ANALYSIS */ /* Apply FFT to FFTbuffer data */ - complex_fft(state->FFTbuffer, STFT_SIZE, -1.0); + complex_fft(state->mFFTbuffer, STFT_SIZE, -1.0); /* Analyze the obtained data. Since the real FFT is symmetric, only * STFT_HALF_SIZE+1 samples are needed. @@ -245,10 +245,10 @@ ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, cons for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) { /* Compute amplitude and phase */ - ALphasor component{rect2polar(state->FFTbuffer[k])}; + ALphasor component{rect2polar(state->mFFTbuffer[k])}; /* Compute phase difference and subtract expected phase difference */ - double tmp{(component.Phase - state->LastPhase[k]) - k*expected}; + double tmp{(component.Phase - state->mLastPhase[k]) - k*expected}; /* Map delta phase into +/- Pi interval */ int qpd{double2int(tmp / M_PI)}; @@ -261,29 +261,29 @@ ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, cons * for maintain the gain (because half of bins are used) and store * amplitude and true frequency in analysis buffer. */ - state->Analysis_buffer[k].Amplitude = 2.0 * component.Amplitude; - state->Analysis_buffer[k].Frequency = (k + tmp) * freq_per_bin; + state->mAnalysis_buffer[k].Amplitude = 2.0 * component.Amplitude; + state->mAnalysis_buffer[k].Frequency = (k + tmp) * freq_per_bin; /* Store actual phase[k] for the calculations in the next frame*/ - state->LastPhase[k] = component.Phase; + state->mLastPhase[k] = component.Phase; } /* PROCESSING */ /* pitch shifting */ for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) { - state->Syntesis_buffer[k].Amplitude = 0.0; - state->Syntesis_buffer[k].Frequency = 0.0; + state->mSyntesis_buffer[k].Amplitude = 0.0; + state->mSyntesis_buffer[k].Frequency = 0.0; } for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) { - ALsizei j{(k*state->PitchShiftI) >> FRACTIONBITS}; + ALsizei j{(k*state->mPitchShiftI) >> FRACTIONBITS}; if(j >= STFT_HALF_SIZE+1) break; - state->Syntesis_buffer[j].Amplitude += state->Analysis_buffer[k].Amplitude; - state->Syntesis_buffer[j].Frequency = state->Analysis_buffer[k].Frequency * - state->PitchShift; + state->mSyntesis_buffer[j].Amplitude += state->mAnalysis_buffer[k].Amplitude; + state->mSyntesis_buffer[j].Frequency = state->mAnalysis_buffer[k].Frequency * + state->mPitchShift; } /* SYNTHESIS */ @@ -294,41 +294,41 @@ ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, cons ALdouble tmp; /* Compute bin deviation from scaled freq */ - tmp = state->Syntesis_buffer[k].Frequency/freq_per_bin - k; + tmp = state->mSyntesis_buffer[k].Frequency/freq_per_bin - k; /* Calculate actual delta phase and accumulate it to get bin phase */ - state->SumPhase[k] += (k + tmp) * expected; + state->mSumPhase[k] += (k + tmp) * expected; - component.Amplitude = state->Syntesis_buffer[k].Amplitude; - component.Phase = state->SumPhase[k]; + component.Amplitude = state->mSyntesis_buffer[k].Amplitude; + component.Phase = state->mSumPhase[k]; /* Compute phasor component to cartesian complex number and storage it into FFTbuffer*/ - state->FFTbuffer[k] = polar2rect(component); + state->mFFTbuffer[k] = polar2rect(component); } /* zero negative frequencies for recontruct a real signal */ for(ALsizei k{STFT_HALF_SIZE+1};k < STFT_SIZE;k++) - state->FFTbuffer[k] = complex_d{}; + state->mFFTbuffer[k] = complex_d{}; /* Apply iFFT to buffer data */ - complex_fft(state->FFTbuffer, STFT_SIZE, 1.0); + complex_fft(state->mFFTbuffer, STFT_SIZE, 1.0); /* Windowing and add to output */ for(ALsizei k{0};k < STFT_SIZE;k++) - state->OutputAccum[k] += HannWindow[k] * state->FFTbuffer[k].real() / - (0.5 * STFT_HALF_SIZE * OVERSAMP); + state->mOutputAccum[k] += HannWindow[k] * state->mFFTbuffer[k].real() / + (0.5 * STFT_HALF_SIZE * OVERSAMP); /* Shift accumulator, input & output FIFO */ ALsizei j, k; - for(k = 0;k < STFT_STEP;k++) state->OutFIFO[k] = (ALfloat)state->OutputAccum[k]; - for(j = 0;k < STFT_SIZE;k++,j++) state->OutputAccum[j] = state->OutputAccum[k]; - for(;j < STFT_SIZE;j++) state->OutputAccum[j] = 0.0; + for(k = 0;k < STFT_STEP;k++) state->mOutFIFO[k] = (ALfloat)state->mOutputAccum[k]; + for(j = 0;k < STFT_SIZE;k++,j++) state->mOutputAccum[j] = state->mOutputAccum[k]; + for(;j < STFT_SIZE;j++) state->mOutputAccum[j] = 0.0; for(k = 0;k < FIFO_LATENCY;k++) - state->InFIFO[k] = state->InFIFO[k+STFT_STEP]; + state->mInFIFO[k] = state->mInFIFO[k+STFT_STEP]; } - state->count = count; + state->mCount = count; /* Now, mix the processed sound data to the output. */ - MixSamples(bufferOut, NumChannels, SamplesOut, state->CurrentGains, state->TargetGains, + MixSamples(bufferOut, NumChannels, SamplesOut, state->mCurrentGains, state->mTargetGains, maxi(SamplesToDo, 512), 0, SamplesToDo); } -- cgit v1.2.3 From 8472a9d916eae13771455c2b527c1148aa71d8fb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 22:34:26 -0800 Subject: Use proper inheritence for the effect state objects --- Alc/alc.cpp | 18 +-- Alc/alu.cpp | 18 +-- Alc/effects/autowah.cpp | 116 ++++++-------- Alc/effects/chorus.cpp | 135 +++++++--------- Alc/effects/compressor.cpp | 75 ++++----- Alc/effects/dedicated.cpp | 69 +++----- Alc/effects/distortion.cpp | 67 +++----- Alc/effects/echo.cpp | 99 +++++------- Alc/effects/equalizer.cpp | 93 ++++------- Alc/effects/fshifter.cpp | 118 ++++++-------- Alc/effects/modulator.cpp | 85 ++++------ Alc/effects/null.cpp | 69 +++----- Alc/effects/pshifter.cpp | 147 ++++++++--------- Alc/effects/reverb.cpp | 316 ++++++++++++++++++------------------- OpenAL32/Include/alAuxEffectSlot.h | 59 ++----- OpenAL32/Include/alMain.h | 3 +- OpenAL32/alAuxEffectSlot.cpp | 59 +++---- OpenAL32/event.cpp | 2 +- 18 files changed, 626 insertions(+), 922 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 6e68d130..56a581fd 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2256,11 +2256,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(context->DefaultSlot) { ALeffectslot *slot = context->DefaultSlot; - ALeffectState *state = slot->Effect.State; + EffectState *state = slot->Effect.State; - state->OutBuffer = device->Dry.Buffer; - state->OutChannels = device->Dry.NumChannels; - if(V(state,deviceUpdate)(device) == AL_FALSE) + state->mOutBuffer = device->Dry.Buffer; + state->mOutChannels = device->Dry.NumChannels; + if(state->deviceUpdate(device) == AL_FALSE) update_failed = AL_TRUE; else UpdateEffectSlotProps(slot, context); @@ -2270,11 +2270,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) almtx_lock(&context->EffectSlotLock); for(auto &slot : context->EffectSlotList) { - ALeffectState *state = slot->Effect.State; + EffectState *state = slot->Effect.State; - state->OutBuffer = device->Dry.Buffer; - state->OutChannels = device->Dry.NumChannels; - if(V(state,deviceUpdate)(device) == AL_FALSE) + state->mOutBuffer = device->Dry.Buffer; + state->mOutChannels = device->Dry.NumChannels; + if(state->deviceUpdate(device) == AL_FALSE) update_failed = AL_TRUE; else UpdateEffectSlotProps(slot, context); @@ -2603,7 +2603,7 @@ ALCcontext_struct::~ALCcontext_struct() while(eprops) { struct ALeffectslotProps *next{eprops->next.load(std::memory_order_relaxed)}; - if(eprops->State) ALeffectState_DecRef(eprops->State); + if(eprops->State) eprops->State->DecRef(); al_free(eprops); eprops = next; ++count; diff --git a/Alc/alu.cpp b/Alc/alu.cpp index e30f6a2e..6a2f0c01 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -381,7 +381,7 @@ static bool CalcListenerParams(ALCcontext *Context) static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) { struct ALeffectslotProps *props; - ALeffectState *state; + EffectState *state; props = slot->Update.exchange(nullptr, std::memory_order_acq_rel); if(!props && !force) return false; @@ -419,8 +419,8 @@ static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool f * count safely to remove it from the update object (it can't reach * 0 refs since the current params also hold a reference). */ - DecrementRef(&state->Ref); - props->State = NULL; + DecrementRef(&state->mRef); + props->State = nullptr; } else { @@ -428,7 +428,7 @@ static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool f * event. */ AsyncEvent evt = ASYNC_EVENT(EventType_ReleaseEffectState); - evt.u.EffectState = slot->Params.EffectState; + evt.u.mEffectState = slot->Params.EffectState; slot->Params.EffectState = state; props->State = NULL; @@ -442,7 +442,7 @@ static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool f * eventually be cleaned up sometime later (not ideal, but * better than blocking or leaking). */ - props->State = evt.u.EffectState; + props->State = evt.u.mEffectState; } } @@ -451,7 +451,7 @@ static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool f else state = slot->Params.EffectState; - V(state,update)(context, slot, &slot->Params.EffectProps); + state->update(context, slot, &slot->Params.EffectProps); return true; } @@ -1749,9 +1749,9 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) for(i = 0;i < auxslots->count;i++) { const ALeffectslot *slot = auxslots->slot[i]; - ALeffectState *state = slot->Params.EffectState; - V(state,process)(SamplesToDo, slot->WetBuffer, state->OutBuffer, - state->OutChannels); + EffectState *state = slot->Params.EffectState; + state->process(SamplesToDo, slot->WetBuffer, state->mOutBuffer, + state->mOutChannels); } ctx = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed); diff --git a/Alc/effects/autowah.cpp b/Alc/effects/autowah.cpp index 4cf79998..8e789652 100644 --- a/Alc/effects/autowah.cpp +++ b/Alc/effects/autowah.cpp @@ -37,7 +37,7 @@ #define MAX_FREQ 2500.0f #define Q_FACTOR 5.0f -struct ALautowahState final : public ALeffectState { +struct ALautowahState final : public EffectState { /* Effect parameters */ ALfloat mAttackRate; ALfloat mReleaseRate; @@ -66,48 +66,34 @@ struct ALautowahState final : public ALeffectState { /* Effects buffers */ alignas(16) ALfloat mBufferOut[BUFFERSIZE]; -}; -static ALvoid ALautowahState_Destruct(ALautowahState *state); -static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *device); -static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALautowahState) -DEFINE_ALEFFECTSTATE_VTABLE(ALautowahState); + ALboolean deviceUpdate(ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; -static void ALautowahState_Construct(ALautowahState *state) -{ - new (state) ALautowahState{}; - ALeffectState_Construct(state); - SET_VTABLE2(ALautowahState, ALeffectState, state); -} - -static ALvoid ALautowahState_Destruct(ALautowahState *state) -{ - ALeffectState_Destruct(state); - state->~ALautowahState(); -} + DEF_NEWDEL(ALautowahState) +}; -static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *UNUSED(device)) +ALboolean ALautowahState::deviceUpdate(ALCdevice *UNUSED(device)) { /* (Re-)initializing parameters and clear the buffers. */ - state->mAttackRate = 1.0f; - state->mReleaseRate = 1.0f; - state->mResonanceGain = 10.0f; - state->mPeakGain = 4.5f; - state->mFreqMinNorm = 4.5e-4f; - state->mBandwidthNorm = 0.05f; - state->mEnvDelay = 0.0f; + mAttackRate = 1.0f; + mReleaseRate = 1.0f; + mResonanceGain = 10.0f; + mPeakGain = 4.5f; + mFreqMinNorm = 4.5e-4f; + mBandwidthNorm = 0.05f; + mEnvDelay = 0.0f; - for(auto &e : state->mEnv) + for(auto &e : mEnv) { e.cos_w0 = 0.0f; e.alpha = 0.0f; } - for(auto &chan : state->mChans) + for(auto &chan : mChans) { std::fill(std::begin(chan.CurrentGains), std::end(chan.CurrentGains), 0.0f); chan.Filter.z1 = 0.0f; @@ -117,7 +103,7 @@ static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *U return AL_TRUE; } -static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) { const ALCdevice *device = context->Device; ALfloat ReleaseTime; @@ -125,33 +111,33 @@ static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *con ReleaseTime = clampf(props->Autowah.ReleaseTime, 0.001f, 1.0f); - state->mAttackRate = expf(-1.0f / (props->Autowah.AttackTime*device->Frequency)); - state->mReleaseRate = expf(-1.0f / (ReleaseTime*device->Frequency)); + mAttackRate = expf(-1.0f / (props->Autowah.AttackTime*device->Frequency)); + mReleaseRate = expf(-1.0f / (ReleaseTime*device->Frequency)); /* 0-20dB Resonance Peak gain */ - state->mResonanceGain = sqrtf(log10f(props->Autowah.Resonance)*10.0f / 3.0f); - state->mPeakGain = 1.0f - log10f(props->Autowah.PeakGain/AL_AUTOWAH_MAX_PEAK_GAIN); - state->mFreqMinNorm = MIN_FREQ / device->Frequency; - state->mBandwidthNorm = (MAX_FREQ-MIN_FREQ) / device->Frequency; + mResonanceGain = sqrtf(log10f(props->Autowah.Resonance)*10.0f / 3.0f); + mPeakGain = 1.0f - log10f(props->Autowah.PeakGain/AL_AUTOWAH_MAX_PEAK_GAIN); + mFreqMinNorm = MIN_FREQ / device->Frequency; + mBandwidthNorm = (MAX_FREQ-MIN_FREQ) / device->Frequency; - state->OutBuffer = device->FOAOut.Buffer; - state->OutChannels = device->FOAOut.NumChannels; + mOutBuffer = device->FOAOut.Buffer; + mOutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain, - state->mChans[i].TargetGains); + mChans[i].TargetGains); } -static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +void ALautowahState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - const ALfloat attack_rate = state->mAttackRate; - const ALfloat release_rate = state->mReleaseRate; - const ALfloat res_gain = state->mResonanceGain; - const ALfloat peak_gain = state->mPeakGain; - const ALfloat freq_min = state->mFreqMinNorm; - const ALfloat bandwidth = state->mBandwidthNorm; + const ALfloat attack_rate = mAttackRate; + const ALfloat release_rate = mReleaseRate; + const ALfloat res_gain = mResonanceGain; + const ALfloat peak_gain = mPeakGain; + const ALfloat freq_min = mFreqMinNorm; + const ALfloat bandwidth = mBandwidthNorm; ALfloat env_delay; ALsizei c, i; - env_delay = state->mEnvDelay; + env_delay = mEnvDelay; for(i = 0;i < SamplesToDo;i++) { ALfloat w0, sample, a; @@ -165,10 +151,10 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, /* Calculate the cos and alpha components for this sample's filter. */ w0 = minf((bandwidth*env_delay + freq_min), 0.46f) * F_TAU; - state->mEnv[i].cos_w0 = cosf(w0); - state->mEnv[i].alpha = sinf(w0)/(2.0f * Q_FACTOR); + mEnv[i].cos_w0 = cosf(w0); + mEnv[i].alpha = sinf(w0)/(2.0f * Q_FACTOR); } - state->mEnvDelay = env_delay; + mEnvDelay = env_delay; for(c = 0;c < MAX_EFFECT_CHANNELS; c++) { @@ -178,13 +164,13 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, * envelope. Because the filter changes for each sample, the * coefficients are transient and don't need to be held. */ - ALfloat z1 = state->mChans[c].Filter.z1; - ALfloat z2 = state->mChans[c].Filter.z2; + ALfloat z1 = mChans[c].Filter.z1; + ALfloat z2 = mChans[c].Filter.z2; for(i = 0;i < SamplesToDo;i++) { - const ALfloat alpha = state->mEnv[i].alpha; - const ALfloat cos_w0 = state->mEnv[i].cos_w0; + const ALfloat alpha = mEnv[i].alpha; + const ALfloat cos_w0 = mEnv[i].cos_w0; ALfloat input, output; ALfloat a[3], b[3]; @@ -199,27 +185,23 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, output = input*(b[0]/a[0]) + z1; z1 = input*(b[1]/a[0]) - output*(a[1]/a[0]) + z2; z2 = input*(b[2]/a[0]) - output*(a[2]/a[0]); - state->mBufferOut[i] = output; + mBufferOut[i] = output; } - state->mChans[c].Filter.z1 = z1; - state->mChans[c].Filter.z2 = z2; + mChans[c].Filter.z1 = z1; + mChans[c].Filter.z2 = z2; /* Now, mix the processed sound data to the output. */ - MixSamples(state->mBufferOut, NumChannels, SamplesOut, state->mChans[c].CurrentGains, - state->mChans[c].TargetGains, SamplesToDo, 0, SamplesToDo); + MixSamples(mBufferOut, NumChannels, SamplesOut, mChans[c].CurrentGains, + mChans[c].TargetGains, SamplesToDo, 0, SamplesToDo); } } struct AutowahStateFactory final : public EffectStateFactory { - ALeffectState *create() override; + EffectState *create() override; }; -ALeffectState *AutowahStateFactory::create() -{ - ALautowahState *state; - NEW_OBJ0(state, ALautowahState)(); - return state; -} +EffectState *AutowahStateFactory::create() +{ return new ALautowahState{}; } EffectStateFactory *AutowahStateFactory_getFactory(void) { diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp index d859d630..ee0b64e5 100644 --- a/Alc/effects/chorus.cpp +++ b/Alc/effects/chorus.cpp @@ -42,7 +42,7 @@ enum WaveForm { WF_Triangle }; -struct ALchorusState final : public ALeffectState { +struct ALchorusState final : public EffectState { al::vector mSampleBuffer; ALsizei mOffset{0}; @@ -62,31 +62,16 @@ struct ALchorusState final : public ALeffectState { ALint mDelay{0}; ALfloat mDepth{0.0f}; ALfloat mFeedback{0.0f}; -}; - -static ALvoid ALchorusState_Destruct(ALchorusState *state); -static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device); -static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props); -static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALchorusState) -DEFINE_ALEFFECTSTATE_VTABLE(ALchorusState); + ALboolean deviceUpdate(ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; -static void ALchorusState_Construct(ALchorusState *state) -{ - new (state) ALchorusState{}; - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALchorusState, ALeffectState, state); -} - -static ALvoid ALchorusState_Destruct(ALchorusState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); - state->~ALchorusState(); -} + DEF_NEWDEL(ALchorusState) +}; -static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device) +ALboolean ALchorusState::deviceUpdate(ALCdevice *Device) { const ALfloat max_delay = maxf(AL_CHORUS_MAX_DELAY, AL_FLANGER_MAX_DELAY); size_t maxlen; @@ -94,14 +79,14 @@ static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Dev maxlen = NextPowerOf2(float2int(max_delay*2.0f*Device->Frequency) + 1u); if(maxlen <= 0) return AL_FALSE; - if(maxlen != state->mSampleBuffer.size()) + if(maxlen != mSampleBuffer.size()) { - state->mSampleBuffer.resize(maxlen); - state->mSampleBuffer.shrink_to_fit(); + mSampleBuffer.resize(maxlen); + mSampleBuffer.shrink_to_fit(); } - std::fill(state->mSampleBuffer.begin(), state->mSampleBuffer.end(), 0.0f); - for(auto &e : state->mGains) + std::fill(mSampleBuffer.begin(), mSampleBuffer.end(), 0.0f); + for(auto &e : mGains) { std::fill(std::begin(e.Current), std::end(e.Current), 0.0f); std::fill(std::begin(e.Target), std::end(e.Target), 0.0f); @@ -110,7 +95,7 @@ static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Dev return AL_TRUE; } -static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) +void ALchorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) { const ALsizei mindelay = MAX_RESAMPLE_PADDING << FRACTIONBITS; const ALCdevice *device = Context->Device; @@ -122,37 +107,35 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Conte switch(props->Chorus.Waveform) { case AL_CHORUS_WAVEFORM_TRIANGLE: - state->mWaveform = WF_Triangle; + mWaveform = WF_Triangle; break; case AL_CHORUS_WAVEFORM_SINUSOID: - state->mWaveform = WF_Sinusoid; + mWaveform = WF_Sinusoid; break; } /* The LFO depth is scaled to be relative to the sample delay. Clamp the * delay and depth to allow enough padding for resampling. */ - state->mDelay = maxi(float2int(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f), - mindelay); - state->mDepth = minf(props->Chorus.Depth * state->mDelay, - (ALfloat)(state->mDelay - mindelay)); + mDelay = maxi(float2int(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f), mindelay); + mDepth = minf(props->Chorus.Depth * mDelay, (ALfloat)(mDelay - mindelay)); - state->mFeedback = props->Chorus.Feedback; + mFeedback = props->Chorus.Feedback; /* Gains for left and right sides */ CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, state->mGains[0].Target); + ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, mGains[0].Target); CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, state->mGains[1].Target); + ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, mGains[1].Target); phase = props->Chorus.Phase; rate = props->Chorus.Rate; if(!(rate > 0.0f)) { - state->mLfoOffset = 0; - state->mLfoRange = 1; - state->mLfoScale = 0.0f; - state->mLfoDisp = 0; + mLfoOffset = 0; + mLfoRange = 1; + mLfoScale = 0.0f; + mLfoDisp = 0; } else { @@ -161,22 +144,21 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Conte */ ALsizei lfo_range = float2int(minf(frequency/rate + 0.5f, (ALfloat)(INT_MAX/360 - 180))); - state->mLfoOffset = float2int((ALfloat)state->mLfoOffset/state->mLfoRange* - lfo_range + 0.5f) % lfo_range; - state->mLfoRange = lfo_range; - switch(state->mWaveform) + mLfoOffset = float2int((ALfloat)mLfoOffset/mLfoRange*lfo_range + 0.5f) % lfo_range; + mLfoRange = lfo_range; + switch(mWaveform) { case WF_Triangle: - state->mLfoScale = 4.0f / state->mLfoRange; + mLfoScale = 4.0f / mLfoRange; break; case WF_Sinusoid: - state->mLfoScale = F_TAU / state->mLfoRange; + mLfoScale = F_TAU / mLfoRange; break; } /* Calculate lfo phase displacement */ if(phase < 0) phase = 360 + phase; - state->mLfoDisp = (state->mLfoRange*phase + 180) / 360; + mLfoDisp = (mLfoRange*phase + 180) / 360; } } @@ -204,14 +186,13 @@ static void GetSinusoidDelays(ALint *RESTRICT delays, ALsizei offset, const ALsi } } - -static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +void ALchorusState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - const ALsizei bufmask = state->mSampleBuffer.size()-1; - const ALfloat feedback = state->mFeedback; - const ALsizei avgdelay = (state->mDelay + (FRACTIONONE>>1)) >> FRACTIONBITS; - ALfloat *RESTRICT delaybuf = state->mSampleBuffer.data(); - ALsizei offset = state->mOffset; + const ALsizei bufmask = mSampleBuffer.size()-1; + const ALfloat feedback = mFeedback; + const ALsizei avgdelay = (mDelay + (FRACTIONONE>>1)) >> FRACTIONBITS; + ALfloat *RESTRICT delaybuf = mSampleBuffer.data(); + ALsizei offset = mOffset; ALsizei i, c; ALsizei base; @@ -221,23 +202,21 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, c ALint moddelays[2][256]; alignas(16) ALfloat temps[2][256]; - if(state->mWaveform == WF_Sinusoid) + if(mWaveform == WF_Sinusoid) { - GetSinusoidDelays(moddelays[0], state->mLfoOffset, state->mLfoRange, state->mLfoScale, - state->mDepth, state->mDelay, todo); - GetSinusoidDelays(moddelays[1], (state->mLfoOffset+state->mLfoDisp)%state->mLfoRange, - state->mLfoRange, state->mLfoScale, state->mDepth, state->mDelay, + GetSinusoidDelays(moddelays[0], mLfoOffset, mLfoRange, mLfoScale, mDepth, mDelay, todo); + GetSinusoidDelays(moddelays[1], (mLfoOffset+mLfoDisp)%mLfoRange, mLfoRange, mLfoScale, + mDepth, mDelay, todo); } else /*if(state->waveform == WF_Triangle)*/ { - GetTriangleDelays(moddelays[0], state->mLfoOffset, state->mLfoRange, state->mLfoScale, - state->mDepth, state->mDelay, todo); - GetTriangleDelays(moddelays[1], (state->mLfoOffset+state->mLfoDisp)%state->mLfoRange, - state->mLfoRange, state->mLfoScale, state->mDepth, state->mDelay, + GetTriangleDelays(moddelays[0], mLfoOffset, mLfoRange, mLfoScale, mDepth, mDelay, todo); + GetTriangleDelays(moddelays[1], (mLfoOffset+mLfoDisp)%mLfoRange, mLfoRange, mLfoScale, + mDepth, mDelay, todo); } - state->mLfoOffset = (state->mLfoOffset+todo) % state->mLfoRange; + mLfoOffset = (mLfoOffset+todo) % mLfoRange; for(i = 0;i < todo;i++) { @@ -267,26 +246,22 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, c } for(c = 0;c < 2;c++) - MixSamples(temps[c], NumChannels, SamplesOut, state->mGains[c].Current, - state->mGains[c].Target, SamplesToDo-base, base, todo); + MixSamples(temps[c], NumChannels, SamplesOut, mGains[c].Current, + mGains[c].Target, SamplesToDo-base, base, todo); base += todo; } - state->mOffset = offset; + mOffset = offset; } struct ChorusStateFactory final : public EffectStateFactory { - ALeffectState *create() override; + EffectState *create() override; }; -ALeffectState *ChorusStateFactory::create() -{ - ALchorusState *state; - NEW_OBJ0(state, ALchorusState)(); - return state; -} +EffectState *ChorusStateFactory::create() +{ return new ALchorusState{}; } EffectStateFactory *ChorusStateFactory_getFactory(void) { @@ -408,15 +383,11 @@ DEFINE_ALEFFECT_VTABLE(ALchorus); * the same processing functions, so piggyback flanger on the chorus functions. */ struct FlangerStateFactory final : public EffectStateFactory { - ALeffectState *create() override; + EffectState *create() override; }; -ALeffectState *FlangerStateFactory::create() -{ - ALchorusState *state; - NEW_OBJ0(state, ALchorusState)(); - return state; -} +EffectState *FlangerStateFactory::create() +{ return new ALchorusState{}; } EffectStateFactory *FlangerStateFactory_getFactory(void) { diff --git a/Alc/effects/compressor.cpp b/Alc/effects/compressor.cpp index be91dd6c..c8bdef15 100644 --- a/Alc/effects/compressor.cpp +++ b/Alc/effects/compressor.cpp @@ -37,7 +37,7 @@ #define RELEASE_TIME 0.2f /* 200ms to drop from max to min */ -struct ALcompressorState final : public ALeffectState { +struct ALcompressorState final : public EffectState { /* Effect gains for each channel */ ALfloat mGain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS]{}; @@ -46,31 +46,16 @@ struct ALcompressorState final : public ALeffectState { ALfloat mAttackMult{1.0f}; ALfloat mReleaseMult{1.0f}; ALfloat mEnvFollower{1.0f}; -}; - -static ALvoid ALcompressorState_Destruct(ALcompressorState *state); -static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device); -static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALcompressorState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALcompressorState); -static void ALcompressorState_Construct(ALcompressorState *state) -{ - new (state) ALcompressorState{}; - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALcompressorState, ALeffectState, state); -} + ALboolean deviceUpdate(ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; -static ALvoid ALcompressorState_Destruct(ALcompressorState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); - state->~ALcompressorState(); -} + DEF_NEWDEL(ALcompressorState) +}; -static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device) +ALboolean ALcompressorState::deviceUpdate(ALCdevice *device) { /* Number of samples to do a full attack and release (non-integer sample * counts are okay). @@ -81,27 +66,25 @@ static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdev /* Calculate per-sample multipliers to attack and release at the desired * rates. */ - state->mAttackMult = powf(AMP_ENVELOPE_MAX/AMP_ENVELOPE_MIN, 1.0f/attackCount); - state->mReleaseMult = powf(AMP_ENVELOPE_MIN/AMP_ENVELOPE_MAX, 1.0f/releaseCount); + mAttackMult = powf(AMP_ENVELOPE_MAX/AMP_ENVELOPE_MIN, 1.0f/attackCount); + mReleaseMult = powf(AMP_ENVELOPE_MIN/AMP_ENVELOPE_MAX, 1.0f/releaseCount); return AL_TRUE; } -static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +void ALcompressorState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) { const ALCdevice *device = context->Device; - ALuint i; - state->mEnabled = props->Compressor.OnOff; + mEnabled = props->Compressor.OnOff; - state->OutBuffer = device->FOAOut.Buffer; - state->OutChannels = device->FOAOut.NumChannels; - for(i = 0;i < 4;i++) - ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain, - state->mGain[i]); + mOutBuffer = device->FOAOut.Buffer; + mOutChannels = device->FOAOut.NumChannels; + for(ALsizei i{0};i < 4;i++) + ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain, mGain[i]); } -static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +void ALcompressorState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { ALsizei i, j, k; ALsizei base; @@ -110,10 +93,10 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei Sample { ALfloat gains[256]; ALsizei td = mini(256, SamplesToDo-base); - ALfloat env = state->mEnvFollower; + ALfloat env = mEnvFollower; /* Generate the per-sample gains from the signal envelope. */ - if(state->mEnabled) + if(mEnabled) { for(i = 0;i < td;++i) { @@ -123,9 +106,9 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei Sample ALfloat amplitude = clampf(fabsf(SamplesIn[0][base+i]), AMP_ENVELOPE_MIN, AMP_ENVELOPE_MAX); if(amplitude > env) - env = minf(env*state->mAttackMult, amplitude); + env = minf(env*mAttackMult, amplitude); else if(amplitude < env) - env = maxf(env*state->mReleaseMult, amplitude); + env = maxf(env*mReleaseMult, amplitude); /* Apply the reciprocal of the envelope to normalize the volume * (compress the dynamic range). @@ -143,21 +126,21 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei Sample { ALfloat amplitude = 1.0f; if(amplitude > env) - env = minf(env*state->mAttackMult, amplitude); + env = minf(env*mAttackMult, amplitude); else if(amplitude < env) - env = maxf(env*state->mReleaseMult, amplitude); + env = maxf(env*mReleaseMult, amplitude); gains[i] = 1.0f / env; } } - state->mEnvFollower = env; + mEnvFollower = env; /* Now compress the signal amplitude to output. */ for(j = 0;j < MAX_EFFECT_CHANNELS;j++) { for(k = 0;k < NumChannels;k++) { - ALfloat gain = state->mGain[j][k]; + ALfloat gain = mGain[j][k]; if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; @@ -172,15 +155,11 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei Sample struct CompressorStateFactory final : public EffectStateFactory { - ALeffectState *create() override; + EffectState *create() override; }; -ALeffectState *CompressorStateFactory::create() -{ - ALcompressorState *state; - NEW_OBJ0(state, ALcompressorState)(); - return state; -} +EffectState *CompressorStateFactory::create() +{ return new ALcompressorState{}; } EffectStateFactory *CompressorStateFactory_getFactory(void) { diff --git a/Alc/effects/dedicated.cpp b/Alc/effects/dedicated.cpp index 8a59fd4b..491b57ec 100644 --- a/Alc/effects/dedicated.cpp +++ b/Alc/effects/dedicated.cpp @@ -31,45 +31,30 @@ #include "alu.h" -struct ALdedicatedState final : public ALeffectState { +struct ALdedicatedState final : public EffectState { ALfloat mCurrentGains[MAX_OUTPUT_CHANNELS]; ALfloat mTargetGains[MAX_OUTPUT_CHANNELS]; -}; - -static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state); -static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *state, ALCdevice *device); -static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALdedicatedState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALdedicatedState); -static void ALdedicatedState_Construct(ALdedicatedState *state) -{ - new (state) ALdedicatedState{}; - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALdedicatedState, ALeffectState, state); -} + ALboolean deviceUpdate(ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; -static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); - state->~ALdedicatedState(); -} + DEF_NEWDEL(ALdedicatedState) +}; -static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *state, ALCdevice *UNUSED(device)) +ALboolean ALdedicatedState::deviceUpdate(ALCdevice *UNUSED(device)) { - std::fill(std::begin(state->mCurrentGains), std::end(state->mCurrentGains), 0.0f); + std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f); return AL_TRUE; } -static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +void ALdedicatedState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) { const ALCdevice *device = context->Device; ALfloat Gain; - std::fill(std::begin(state->mTargetGains), std::end(state->mTargetGains), 0.0f); + std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f); Gain = slot->Params.Gain * props->Dedicated.Gain; if(slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) @@ -77,9 +62,9 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext int idx; if((idx=GetChannelIdxByName(&device->RealOut, LFE)) != -1) { - state->OutBuffer = device->RealOut.Buffer; - state->OutChannels = device->RealOut.NumChannels; - state->mTargetGains[idx] = Gain; + mOutBuffer = device->RealOut.Buffer; + mOutChannels = device->RealOut.NumChannels; + mTargetGains[idx] = Gain; } } else if(slot->Params.EffectType == AL_EFFECT_DEDICATED_DIALOGUE) @@ -89,39 +74,35 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext int idx{GetChannelIdxByName(&device->RealOut, FrontCenter)}; if(idx != -1) { - state->OutBuffer = device->RealOut.Buffer; - state->OutChannels = device->RealOut.NumChannels; - state->mTargetGains[idx] = Gain; + mOutBuffer = device->RealOut.Buffer; + mOutChannels = device->RealOut.NumChannels; + mTargetGains[idx] = Gain; } else { ALfloat coeffs[MAX_AMBI_COEFFS]; CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - state->OutBuffer = device->Dry.Buffer; - state->OutChannels = device->Dry.NumChannels; - ComputePanGains(&device->Dry, coeffs, Gain, state->mTargetGains); + mOutBuffer = device->Dry.Buffer; + mOutChannels = device->Dry.NumChannels; + ComputePanGains(&device->Dry, coeffs, Gain, mTargetGains); } } } -static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +void ALdedicatedState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - MixSamples(SamplesIn[0], NumChannels, SamplesOut, state->mCurrentGains, - state->mTargetGains, SamplesToDo, 0, SamplesToDo); + MixSamples(SamplesIn[0], NumChannels, SamplesOut, mCurrentGains, + mTargetGains, SamplesToDo, 0, SamplesToDo); } struct DedicatedStateFactory final : public EffectStateFactory { - ALeffectState *create() override; + EffectState *create() override; }; -ALeffectState *DedicatedStateFactory::create() -{ - ALdedicatedState *state; - NEW_OBJ0(state, ALdedicatedState)(); - return state; -} +EffectState *DedicatedStateFactory::create() +{ return new ALdedicatedState{}; } EffectStateFactory *DedicatedStateFactory_getFactory(void) { diff --git a/Alc/effects/distortion.cpp b/Alc/effects/distortion.cpp index 48acfa56..a2681e3d 100644 --- a/Alc/effects/distortion.cpp +++ b/Alc/effects/distortion.cpp @@ -31,7 +31,7 @@ #include "filters/defs.h" -struct ALdistortionState final : public ALeffectState { +struct ALdistortionState final : public EffectState { /* Effect gains for each channel */ ALfloat mGain[MAX_OUTPUT_CHANNELS]{}; @@ -41,39 +41,24 @@ struct ALdistortionState final : public ALeffectState { ALfloat mAttenuation{}; ALfloat mEdgeCoeff{}; - ALfloat Buffer[2][BUFFERSIZE]{}; -}; - -static ALvoid ALdistortionState_Destruct(ALdistortionState *state); -static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *device); -static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALdistortionState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALdistortionState); + ALfloat mBuffer[2][BUFFERSIZE]{}; -static void ALdistortionState_Construct(ALdistortionState *state) -{ - new (state) ALdistortionState{}; - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALdistortionState, ALeffectState, state); -} + ALboolean deviceUpdate(ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; -static ALvoid ALdistortionState_Destruct(ALdistortionState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); - state->~ALdistortionState(); -} + DEF_NEWDEL(ALdistortionState) +}; -static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *UNUSED(device)) +ALboolean ALdistortionState::deviceUpdate(ALCdevice *UNUSED(device)) { - BiquadFilter_clear(&state->mLowpass); - BiquadFilter_clear(&state->mBandpass); + BiquadFilter_clear(&mLowpass); + BiquadFilter_clear(&mBandpass); return AL_TRUE; } -static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +void ALdistortionState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) { const ALCdevice *device = context->Device; ALfloat frequency = (ALfloat)device->Frequency; @@ -85,7 +70,7 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontex /* Store waveshaper edge settings. */ edge = sinf(props->Distortion.Edge * (F_PI_2)); edge = minf(edge, 0.99f); - state->mEdgeCoeff = 2.0f * edge / (1.0f-edge); + mEdgeCoeff = 2.0f * edge / (1.0f-edge); cutoff = props->Distortion.LowpassCutoff; /* Bandwidth value is constant in octaves. */ @@ -93,25 +78,25 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontex /* Multiply sampling frequency by the amount of oversampling done during * processing. */ - BiquadFilter_setParams(&state->mLowpass, BiquadType::LowPass, 1.0f, + BiquadFilter_setParams(&mLowpass, BiquadType::LowPass, 1.0f, cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); cutoff = props->Distortion.EQCenter; /* Convert bandwidth in Hz to octaves. */ bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f); - BiquadFilter_setParams(&state->mBandpass, BiquadType::BandPass, 1.0f, + BiquadFilter_setParams(&mBandpass, BiquadType::BandPass, 1.0f, cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain*props->Distortion.Gain, state->mGain); + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain*props->Distortion.Gain, mGain); } -static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +void ALdistortionState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALfloat (*RESTRICT buffer)[BUFFERSIZE] = state->Buffer; - const ALfloat fc = state->mEdgeCoeff; + ALfloat (*RESTRICT buffer)[BUFFERSIZE] = mBuffer; + const ALfloat fc = mEdgeCoeff; ALsizei base; ALsizei i, k; @@ -135,7 +120,7 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei Sample * (which is fortunately first step of distortion). So combine three * operations into the one. */ - BiquadFilter_process(&state->mLowpass, buffer[1], buffer[0], todo); + BiquadFilter_process(&mLowpass, buffer[1], buffer[0], todo); /* Second step, do distortion using waveshaper function to emulate * signal processing during tube overdriving. Three steps of @@ -154,7 +139,7 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei Sample } /* Third step, do bandpass filtering of distorted signal. */ - BiquadFilter_process(&state->mBandpass, buffer[1], buffer[0], todo); + BiquadFilter_process(&mBandpass, buffer[1], buffer[0], todo); todo >>= 2; for(k = 0;k < NumChannels;k++) @@ -162,7 +147,7 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei Sample /* Fourth step, final, do attenuation and perform decimation, * storing only one sample out of four. */ - ALfloat gain = state->mGain[k]; + ALfloat gain = mGain[k]; if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; @@ -176,15 +161,11 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei Sample struct DistortionStateFactory final : public EffectStateFactory { - ALeffectState *create() override; + EffectState *create() override; }; -ALeffectState *DistortionStateFactory::create() -{ - ALdistortionState *state; - NEW_OBJ0(state, ALdistortionState)(); - return state; -} +EffectState *DistortionStateFactory::create() +{ return new ALdistortionState{}; } EffectStateFactory *DistortionStateFactory_getFactory(void) { diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index a72b242c..58728b50 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -35,7 +35,7 @@ #include "vector.h" -struct ALechoState final : public ALeffectState { +struct ALechoState final : public EffectState { al::vector mSampleBuffer; // The echo is two tap. The delay is the number of samples from before the @@ -54,31 +54,16 @@ struct ALechoState final : public ALeffectState { ALfloat mFeedGain{0.0f}; BiquadFilter mFilter; -}; - -static ALvoid ALechoState_Destruct(ALechoState *state); -static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device); -static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALechoState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALechoState); -static void ALechoState_Construct(ALechoState *state) -{ - new (state) ALechoState{}; - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALechoState, ALeffectState, state); -} + ALboolean deviceUpdate(ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; -static ALvoid ALechoState_Destruct(ALechoState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); - state->~ALechoState(); -} + DEF_NEWDEL(ALechoState) +}; -static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device) +ALboolean ALechoState::deviceUpdate(ALCdevice *Device) { ALuint maxlen; @@ -89,14 +74,14 @@ static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device) maxlen = NextPowerOf2(maxlen); if(maxlen <= 0) return AL_FALSE; - if(maxlen != state->mSampleBuffer.size()) + if(maxlen != mSampleBuffer.size()) { - state->mSampleBuffer.resize(maxlen); - state->mSampleBuffer.shrink_to_fit(); + mSampleBuffer.resize(maxlen); + mSampleBuffer.shrink_to_fit(); } - std::fill(state->mSampleBuffer.begin(), state->mSampleBuffer.end(), 0.0f); - for(auto &e : state->mGains) + std::fill(mSampleBuffer.begin(), mSampleBuffer.end(), 0.0f); + for(auto &e : mGains) { std::fill(std::begin(e.Current), std::end(e.Current), 0.0f); std::fill(std::begin(e.Target), std::end(e.Target), 0.0f); @@ -105,16 +90,16 @@ static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device) return AL_TRUE; } -static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +void ALechoState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) { const ALCdevice *device = context->Device; ALuint frequency = device->Frequency; ALfloat coeffs[MAX_AMBI_COEFFS]; ALfloat gainhf, lrpan, spread; - state->mTap[0].delay = maxi(float2int(props->Echo.Delay*frequency + 0.5f), 1); - state->mTap[1].delay = float2int(props->Echo.LRDelay*frequency + 0.5f); - state->mTap[1].delay += state->mTap[0].delay; + mTap[0].delay = maxi(float2int(props->Echo.Delay*frequency + 0.5f), 1); + mTap[1].delay = float2int(props->Echo.LRDelay*frequency + 0.5f); + mTap[1].delay += mTap[0].delay; spread = props->Echo.Spread; if(spread < 0.0f) lrpan = -1.0f; @@ -124,35 +109,35 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, */ spread = asinf(1.0f - fabsf(spread))*4.0f; - state->mFeedGain = props->Echo.Feedback; + mFeedGain = props->Echo.Feedback; gainhf = maxf(1.0f - props->Echo.Damping, 0.0625f); /* Limit -24dB */ - BiquadFilter_setParams(&state->mFilter, BiquadType::HighShelf, + BiquadFilter_setParams(&mFilter, BiquadType::HighShelf, gainhf, LOWPASSFREQREF/frequency, calc_rcpQ_from_slope(gainhf, 1.0f) ); /* First tap panning */ CalcAngleCoeffs(-F_PI_2*lrpan, 0.0f, spread, coeffs); - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->mGains[0].Target); + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, mGains[0].Target); /* Second tap panning */ CalcAngleCoeffs( F_PI_2*lrpan, 0.0f, spread, coeffs); - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->mGains[1].Target); + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, mGains[1].Target); } -static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +void ALechoState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - const ALsizei mask = state->mSampleBuffer.size()-1; - const ALsizei tap1 = state->mTap[0].delay; - const ALsizei tap2 = state->mTap[1].delay; - ALfloat *RESTRICT delaybuf = state->mSampleBuffer.data(); - ALsizei offset = state->mOffset; + const ALsizei mask = mSampleBuffer.size()-1; + const ALsizei tap1 = mTap[0].delay; + const ALsizei tap2 = mTap[1].delay; + ALfloat *RESTRICT delaybuf = mSampleBuffer.data(); + ALsizei offset = mOffset; ALfloat z1, z2, in, out; ALsizei base; ALsizei c, i; - z1 = state->mFilter.z1; - z2 = state->mFilter.z2; + z1 = mFilter.z1; + z2 = mFilter.z2; for(base = 0;base < SamplesToDo;) { alignas(16) ALfloat temps[2][128]; @@ -172,37 +157,33 @@ static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const * feedback attenuation. */ in = temps[1][i]; - out = in*state->mFilter.b0 + z1; - z1 = in*state->mFilter.b1 - out*state->mFilter.a1 + z2; - z2 = in*state->mFilter.b2 - out*state->mFilter.a2; + out = in*mFilter.b0 + z1; + z1 = in*mFilter.b1 - out*mFilter.a1 + z2; + z2 = in*mFilter.b2 - out*mFilter.a2; - delaybuf[offset&mask] += out * state->mFeedGain; + delaybuf[offset&mask] += out * mFeedGain; offset++; } for(c = 0;c < 2;c++) - MixSamples(temps[c], NumChannels, SamplesOut, state->mGains[c].Current, - state->mGains[c].Target, SamplesToDo-base, base, td); + MixSamples(temps[c], NumChannels, SamplesOut, mGains[c].Current, + mGains[c].Target, SamplesToDo-base, base, td); base += td; } - state->mFilter.z1 = z1; - state->mFilter.z2 = z2; + mFilter.z1 = z1; + mFilter.z2 = z2; - state->mOffset = offset; + mOffset = offset; } struct EchoStateFactory final : public EffectStateFactory { - ALeffectState *create() override; + EffectState *create() override; }; -ALeffectState *EchoStateFactory::create() -{ - ALechoState *state; - NEW_OBJ0(state, ALechoState)(); - return state; -} +EffectState *EchoStateFactory::create() +{ return new ALechoState{}; } EffectStateFactory *EchoStateFactory_getFactory(void) { diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index 814b43a4..6329ede2 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -76,7 +76,7 @@ * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */ -struct ALequalizerState final : public ALeffectState { +struct ALequalizerState final : public EffectState { struct { /* Effect parameters */ BiquadFilter filter[4]; @@ -87,33 +87,18 @@ struct ALequalizerState final : public ALeffectState { } mChans[MAX_EFFECT_CHANNELS]; ALfloat mSampleBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE]{}; -}; - -static ALvoid ALequalizerState_Destruct(ALequalizerState *state); -static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevice *device); -static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALequalizerState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALequalizerState); -static void ALequalizerState_Construct(ALequalizerState *state) -{ - new (state) ALequalizerState{}; - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALequalizerState, ALeffectState, state); -} + ALboolean deviceUpdate(ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; -static ALvoid ALequalizerState_Destruct(ALequalizerState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); - state->~ALequalizerState(); -} + DEF_NEWDEL(ALequalizerState) +}; -static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevice *UNUSED(device)) +ALboolean ALequalizerState::deviceUpdate(ALCdevice *UNUSED(device)) { - for(auto &e : state->mChans) + for(auto &e : mChans) { std::for_each(std::begin(e.filter), std::end(e.filter), [](BiquadFilter &f) -> void @@ -124,7 +109,7 @@ static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevic return AL_TRUE; } -static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +void ALequalizerState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) { const ALCdevice *device = context->Device; ALfloat frequency = (ALfloat)device->Frequency; @@ -137,78 +122,68 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext */ gain = maxf(sqrtf(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */ f0norm = props->Equalizer.LowCutoff/frequency; - BiquadFilter_setParams(&state->mChans[0].filter[0], BiquadType::LowShelf, + BiquadFilter_setParams(&mChans[0].filter[0], BiquadType::LowShelf, gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f) ); gain = maxf(props->Equalizer.Mid1Gain, 0.0625f); f0norm = props->Equalizer.Mid1Center/frequency; - BiquadFilter_setParams(&state->mChans[0].filter[1], BiquadType::Peaking, - gain, f0norm, calc_rcpQ_from_bandwidth( - f0norm, props->Equalizer.Mid1Width - ) + BiquadFilter_setParams(&mChans[0].filter[1], BiquadType::Peaking, + gain, f0norm, calc_rcpQ_from_bandwidth(f0norm, props->Equalizer.Mid1Width) ); gain = maxf(props->Equalizer.Mid2Gain, 0.0625f); f0norm = props->Equalizer.Mid2Center/frequency; - BiquadFilter_setParams(&state->mChans[0].filter[2], BiquadType::Peaking, - gain, f0norm, calc_rcpQ_from_bandwidth( - f0norm, props->Equalizer.Mid2Width - ) + BiquadFilter_setParams(&mChans[0].filter[2], BiquadType::Peaking, + gain, f0norm, calc_rcpQ_from_bandwidth(f0norm, props->Equalizer.Mid2Width) ); gain = maxf(sqrtf(props->Equalizer.HighGain), 0.0625f); f0norm = props->Equalizer.HighCutoff/frequency; - BiquadFilter_setParams(&state->mChans[0].filter[3], BiquadType::HighShelf, + BiquadFilter_setParams(&mChans[0].filter[3], BiquadType::HighShelf, gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f) ); /* Copy the filter coefficients for the other input channels. */ for(i = 1;i < MAX_EFFECT_CHANNELS;i++) { - BiquadFilter_copyParams(&state->mChans[i].filter[0], &state->mChans[0].filter[0]); - BiquadFilter_copyParams(&state->mChans[i].filter[1], &state->mChans[0].filter[1]); - BiquadFilter_copyParams(&state->mChans[i].filter[2], &state->mChans[0].filter[2]); - BiquadFilter_copyParams(&state->mChans[i].filter[3], &state->mChans[0].filter[3]); + BiquadFilter_copyParams(&mChans[i].filter[0], &mChans[0].filter[0]); + BiquadFilter_copyParams(&mChans[i].filter[1], &mChans[0].filter[1]); + BiquadFilter_copyParams(&mChans[i].filter[2], &mChans[0].filter[2]); + BiquadFilter_copyParams(&mChans[i].filter[3], &mChans[0].filter[3]); } - state->OutBuffer = device->FOAOut.Buffer; - state->OutChannels = device->FOAOut.NumChannels; + mOutBuffer = device->FOAOut.Buffer; + mOutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain, - state->mChans[i].TargetGains); + mChans[i].TargetGains); } -static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +void ALequalizerState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALfloat (*RESTRICT temps)[BUFFERSIZE] = state->mSampleBuffer; + ALfloat (*RESTRICT temps)[BUFFERSIZE] = mSampleBuffer; ALsizei c; for(c = 0;c < MAX_EFFECT_CHANNELS;c++) { - BiquadFilter_process(&state->mChans[c].filter[0], temps[0], SamplesIn[c], SamplesToDo); - BiquadFilter_process(&state->mChans[c].filter[1], temps[1], temps[0], SamplesToDo); - BiquadFilter_process(&state->mChans[c].filter[2], temps[2], temps[1], SamplesToDo); - BiquadFilter_process(&state->mChans[c].filter[3], temps[3], temps[2], SamplesToDo); - - MixSamples(temps[3], NumChannels, SamplesOut, - state->mChans[c].CurrentGains, state->mChans[c].TargetGains, - SamplesToDo, 0, SamplesToDo - ); + BiquadFilter_process(&mChans[c].filter[0], temps[0], SamplesIn[c], SamplesToDo); + BiquadFilter_process(&mChans[c].filter[1], temps[1], temps[0], SamplesToDo); + BiquadFilter_process(&mChans[c].filter[2], temps[2], temps[1], SamplesToDo); + BiquadFilter_process(&mChans[c].filter[3], temps[3], temps[2], SamplesToDo); + + MixSamples(temps[3], NumChannels, SamplesOut, mChans[c].CurrentGains, + mChans[c].TargetGains, SamplesToDo, 0, SamplesToDo); } } struct EqualizerStateFactory final : public EffectStateFactory { - ALeffectState *create() override; + EffectState *create() override; }; -ALeffectState *EqualizerStateFactory::create() -{ - ALequalizerState *state; - NEW_OBJ0(state, ALequalizerState)(); - return state; -} +EffectState *EqualizerStateFactory::create() +{ return new ALequalizerState{}; } EffectStateFactory *EqualizerStateFactory_getFactory(void) { diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp index b4d073da..38fb5492 100644 --- a/Alc/effects/fshifter.cpp +++ b/Alc/effects/fshifter.cpp @@ -60,7 +60,7 @@ std::array InitHannWindow(void) alignas(16) const std::array HannWindow = InitHannWindow(); -struct ALfshifterState final : public ALeffectState { +struct ALfshifterState final : public EffectState { /* Effect parameters */ ALsizei mCount{}; ALsizei mPhaseStep{}; @@ -79,152 +79,134 @@ struct ALfshifterState final : public ALeffectState { /* Effect gains for each output channel */ ALfloat mCurrentGains[MAX_OUTPUT_CHANNELS]{}; ALfloat mTargetGains[MAX_OUTPUT_CHANNELS]{}; -}; -ALvoid ALfshifterState_Destruct(ALfshifterState *state); -ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *device); -ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALfshifterState) -DEFINE_ALEFFECTSTATE_VTABLE(ALfshifterState); + ALboolean deviceUpdate(ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; -void ALfshifterState_Construct(ALfshifterState *state) -{ - new (state) ALfshifterState{}; - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALfshifterState, ALeffectState, state); -} - -ALvoid ALfshifterState_Destruct(ALfshifterState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); - state->~ALfshifterState(); -} + DEF_NEWDEL(ALfshifterState) +}; -ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *UNUSED(device)) +ALboolean ALfshifterState::deviceUpdate(ALCdevice *UNUSED(device)) { /* (Re-)initializing parameters and clear the buffers. */ - state->mCount = FIFO_LATENCY; - state->mPhaseStep = 0; - state->mPhase = 0; - state->mLdSign = 1.0; + mCount = FIFO_LATENCY; + mPhaseStep = 0; + mPhase = 0; + mLdSign = 1.0; - std::fill(std::begin(state->mInFIFO), std::end(state->mInFIFO), 0.0f); - std::fill(std::begin(state->mOutFIFO), std::end(state->mOutFIFO), complex_d{}); - std::fill(std::begin(state->mOutputAccum), std::end(state->mOutputAccum), complex_d{}); - std::fill(std::begin(state->mAnalytic), std::end(state->mAnalytic), complex_d{}); + std::fill(std::begin(mInFIFO), std::end(mInFIFO), 0.0f); + std::fill(std::begin(mOutFIFO), std::end(mOutFIFO), complex_d{}); + std::fill(std::begin(mOutputAccum), std::end(mOutputAccum), complex_d{}); + std::fill(std::begin(mAnalytic), std::end(mAnalytic), complex_d{}); - std::fill(std::begin(state->mCurrentGains), std::end(state->mCurrentGains), 0.0f); - std::fill(std::begin(state->mTargetGains), std::end(state->mTargetGains), 0.0f); + std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f); + std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f); return AL_TRUE; } -ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +void ALfshifterState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) { const ALCdevice *device{context->Device}; ALfloat step{props->Fshifter.Frequency / (ALfloat)device->Frequency}; - state->mPhaseStep = fastf2i(minf(step, 0.5f) * FRACTIONONE); + mPhaseStep = fastf2i(minf(step, 0.5f) * FRACTIONONE); switch(props->Fshifter.LeftDirection) { case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: - state->mLdSign = -1.0; + mLdSign = -1.0; break; case AL_FREQUENCY_SHIFTER_DIRECTION_UP: - state->mLdSign = 1.0; + mLdSign = 1.0; break; case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: - state->mPhase = 0; - state->mPhaseStep = 0; + mPhase = 0; + mPhaseStep = 0; break; } ALfloat coeffs[MAX_AMBI_COEFFS]; CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->mTargetGains); + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, mTargetGains); } -ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +void ALfshifterState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { static const complex_d complex_zero{0.0, 0.0}; - ALfloat *RESTRICT BufferOut = state->mBufferOut; + ALfloat *RESTRICT BufferOut = mBufferOut; ALsizei j, k, base; for(base = 0;base < SamplesToDo;) { - ALsizei todo = mini(HIL_SIZE-state->mCount, SamplesToDo-base); + ALsizei todo = mini(HIL_SIZE-mCount, SamplesToDo-base); ASSUME(todo > 0); /* Fill FIFO buffer with samples data */ - k = state->mCount; + k = mCount; for(j = 0;j < todo;j++,k++) { - state->mInFIFO[k] = SamplesIn[0][base+j]; - state->mOutdata[base+j] = state->mOutFIFO[k-FIFO_LATENCY]; + mInFIFO[k] = SamplesIn[0][base+j]; + mOutdata[base+j] = mOutFIFO[k-FIFO_LATENCY]; } - state->mCount += todo; + mCount += todo; base += todo; /* Check whether FIFO buffer is filled */ - if(state->mCount < HIL_SIZE) continue; - state->mCount = FIFO_LATENCY; + if(mCount < HIL_SIZE) continue; + mCount = FIFO_LATENCY; /* Real signal windowing and store in Analytic buffer */ for(k = 0;k < HIL_SIZE;k++) { - state->mAnalytic[k].real(state->mInFIFO[k] * HannWindow[k]); - state->mAnalytic[k].imag(0.0); + mAnalytic[k].real(mInFIFO[k] * HannWindow[k]); + mAnalytic[k].imag(0.0); } /* Processing signal by Discrete Hilbert Transform (analytical signal). */ - complex_hilbert(state->mAnalytic, HIL_SIZE); + complex_hilbert(mAnalytic, HIL_SIZE); /* Windowing and add to output accumulator */ for(k = 0;k < HIL_SIZE;k++) - state->mOutputAccum[k] += 2.0/OVERSAMP*HannWindow[k]*state->mAnalytic[k]; + mOutputAccum[k] += 2.0/OVERSAMP*HannWindow[k]*mAnalytic[k]; /* Shift accumulator, input & output FIFO */ - for(k = 0;k < HIL_STEP;k++) state->mOutFIFO[k] = state->mOutputAccum[k]; - for(j = 0;k < HIL_SIZE;k++,j++) state->mOutputAccum[j] = state->mOutputAccum[k]; - for(;j < HIL_SIZE;j++) state->mOutputAccum[j] = complex_zero; + for(k = 0;k < HIL_STEP;k++) mOutFIFO[k] = mOutputAccum[k]; + for(j = 0;k < HIL_SIZE;k++,j++) mOutputAccum[j] = mOutputAccum[k]; + for(;j < HIL_SIZE;j++) mOutputAccum[j] = complex_zero; for(k = 0;k < FIFO_LATENCY;k++) - state->mInFIFO[k] = state->mInFIFO[k+HIL_STEP]; + mInFIFO[k] = mInFIFO[k+HIL_STEP]; } /* Process frequency shifter using the analytic signal obtained. */ for(k = 0;k < SamplesToDo;k++) { - double phase = state->mPhase * ((1.0/FRACTIONONE) * 2.0*M_PI); - BufferOut[k] = (float)(state->mOutdata[k].real()*std::cos(phase) + - state->mOutdata[k].imag()*std::sin(phase)*state->mLdSign); + double phase = mPhase * ((1.0/FRACTIONONE) * 2.0*M_PI); + BufferOut[k] = (float)(mOutdata[k].real()*std::cos(phase) + + mOutdata[k].imag()*std::sin(phase)*mLdSign); - state->mPhase += state->mPhaseStep; - state->mPhase &= FRACTIONMASK; + mPhase += mPhaseStep; + mPhase &= FRACTIONMASK; } /* Now, mix the processed sound data to the output. */ - MixSamples(BufferOut, NumChannels, SamplesOut, state->mCurrentGains, state->mTargetGains, + MixSamples(BufferOut, NumChannels, SamplesOut, mCurrentGains, mTargetGains, maxi(SamplesToDo, 512), 0, SamplesToDo); } } // namespace struct FshifterStateFactory final : public EffectStateFactory { - ALeffectState *create() override; + EffectState *create() override; }; -ALeffectState *FshifterStateFactory::create() -{ - ALfshifterState *state; - NEW_OBJ0(state, ALfshifterState)(); - return state; -} +EffectState *FshifterStateFactory::create() +{ return new ALfshifterState{}; } EffectStateFactory *FshifterStateFactory_getFactory(void) { diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index 0062a779..f714f94f 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -37,7 +37,7 @@ #define MAX_UPDATE_SAMPLES 128 -struct ALmodulatorState final : public ALeffectState { +struct ALmodulatorState final : public EffectState { void (*mGetSamples)(ALfloat*RESTRICT, ALsizei, const ALsizei, ALsizei){}; ALsizei mIndex{0}; @@ -49,15 +49,14 @@ struct ALmodulatorState final : public ALeffectState { ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]{}; ALfloat TargetGains[MAX_OUTPUT_CHANNELS]{}; } mChans[MAX_EFFECT_CHANNELS]; -}; -static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state); -static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevice *device); -static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALmodulatorState) -DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState); + ALboolean deviceUpdate(ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; + + DEF_NEWDEL(ALmodulatorState) +}; #define WAVEFORM_FRACBITS 24 @@ -105,22 +104,9 @@ DECL_TEMPLATE(One) #undef DECL_TEMPLATE -static void ALmodulatorState_Construct(ALmodulatorState *state) -{ - new (state) ALmodulatorState{}; - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALmodulatorState, ALeffectState, state); -} - -static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state) +ALboolean ALmodulatorState::deviceUpdate(ALCdevice *UNUSED(device)) { - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); - state->~ALmodulatorState(); -} - -static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevice *UNUSED(device)) -{ - for(auto &e : state->mChans) + for(auto &e : mChans) { BiquadFilter_clear(&e.Filter); std::fill(std::begin(e.CurrentGains), std::end(e.CurrentGains), 0.0f); @@ -128,43 +114,42 @@ static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevic return AL_TRUE; } -static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +void ALmodulatorState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) { const ALCdevice *device = context->Device; ALfloat f0norm; ALsizei i; - state->mStep = fastf2i(props->Modulator.Frequency / (ALfloat)device->Frequency * - WAVEFORM_FRACONE); - state->mStep = clampi(state->mStep, 0, WAVEFORM_FRACONE-1); + mStep = fastf2i(props->Modulator.Frequency / (ALfloat)device->Frequency * WAVEFORM_FRACONE); + mStep = clampi(mStep, 0, WAVEFORM_FRACONE-1); - if(state->mStep == 0) - state->mGetSamples = ModulateOne; + if(mStep == 0) + mGetSamples = ModulateOne; else if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) - state->mGetSamples = ModulateSin; + mGetSamples = ModulateSin; else if(props->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) - state->mGetSamples = ModulateSaw; + mGetSamples = ModulateSaw; else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/ - state->mGetSamples = ModulateSquare; + mGetSamples = ModulateSquare; f0norm = props->Modulator.HighPassCutoff / (ALfloat)device->Frequency; f0norm = clampf(f0norm, 1.0f/512.0f, 0.49f); /* Bandwidth value is constant in octaves. */ - BiquadFilter_setParams(&state->mChans[0].Filter, BiquadType::HighPass, 1.0f, + BiquadFilter_setParams(&mChans[0].Filter, BiquadType::HighPass, 1.0f, f0norm, calc_rcpQ_from_bandwidth(f0norm, 0.75f)); for(i = 1;i < MAX_EFFECT_CHANNELS;i++) - BiquadFilter_copyParams(&state->mChans[i].Filter, &state->mChans[0].Filter); + BiquadFilter_copyParams(&mChans[i].Filter, &mChans[0].Filter); - state->OutBuffer = device->FOAOut.Buffer; - state->OutChannels = device->FOAOut.NumChannels; + mOutBuffer = device->FOAOut.Buffer; + mOutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain, - state->mChans[i].TargetGains); + mChans[i].TargetGains); } -static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +void ALmodulatorState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - const ALsizei step = state->mStep; + const ALsizei step = mStep; ALsizei base; for(base = 0;base < SamplesToDo;) @@ -173,20 +158,20 @@ static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesT ALsizei td = mini(MAX_UPDATE_SAMPLES, SamplesToDo-base); ALsizei c, i; - state->mGetSamples(modsamples, state->mIndex, step, td); - state->mIndex += (step*td) & WAVEFORM_FRACMASK; - state->mIndex &= WAVEFORM_FRACMASK; + mGetSamples(modsamples, mIndex, step, td); + mIndex += (step*td) & WAVEFORM_FRACMASK; + mIndex &= WAVEFORM_FRACMASK; for(c = 0;c < MAX_EFFECT_CHANNELS;c++) { alignas(16) ALfloat temps[MAX_UPDATE_SAMPLES]; - BiquadFilter_process(&state->mChans[c].Filter, temps, &SamplesIn[c][base], td); + BiquadFilter_process(&mChans[c].Filter, temps, &SamplesIn[c][base], td); for(i = 0;i < td;i++) temps[i] *= modsamples[i]; - MixSamples(temps, NumChannels, SamplesOut, state->mChans[c].CurrentGains, - state->mChans[c].TargetGains, SamplesToDo-base, base, td); + MixSamples(temps, NumChannels, SamplesOut, mChans[c].CurrentGains, + mChans[c].TargetGains, SamplesToDo-base, base, td); } base += td; @@ -195,15 +180,11 @@ static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesT struct ModulatorStateFactory final : public EffectStateFactory { - ALeffectState *create() override; + EffectState *create() override; }; -ALeffectState *ModulatorStateFactory::create() -{ - ALmodulatorState *state; - NEW_OBJ0(state, ALmodulatorState)(); - return state; -} +EffectState *ModulatorStateFactory::create() +{ return new ALmodulatorState{}; } EffectStateFactory *ModulatorStateFactory_getFactory(void) { diff --git a/Alc/effects/null.cpp b/Alc/effects/null.cpp index f5641e20..d28a6889 100644 --- a/Alc/effects/null.cpp +++ b/Alc/effects/null.cpp @@ -11,47 +11,36 @@ #include "alError.h" -struct ALnullState final : public ALeffectState { -}; - -/* Forward-declare "virtual" functions to define the vtable with. */ -static ALvoid ALnullState_Destruct(ALnullState *state); -static ALboolean ALnullState_deviceUpdate(ALnullState *state, ALCdevice *device); -static ALvoid ALnullState_update(ALnullState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALnullState_process(ALnullState *state, ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei mumChannels); -static void *ALnullState_New(size_t size); -static void ALnullState_Delete(void *ptr); +struct ALnullState final : public EffectState { + ALnullState(); + ~ALnullState() override; -/* Define the ALeffectState vtable for this type. */ -DEFINE_ALEFFECTSTATE_VTABLE(ALnullState); + ALboolean deviceUpdate(ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; + DEF_NEWDEL(ALnullState) +}; /* This constructs the effect state. It's called when the object is first - * created. Make sure to call the parent Construct function first, and set the - * vtable! + * created. */ -static void ALnullState_Construct(ALnullState *state) +ALnullState::ALnullState() { - new (state) ALnullState{}; - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALnullState, ALeffectState, state); } -/* This destructs (not free!) the effect state. It's called only when the - * effect slot is no longer used. Make sure to call the parent Destruct - * function before returning! +/* This destructs the effect state. It's called only when the effect slot is no + * longer used prior to being freed. */ -static ALvoid ALnullState_Destruct(ALnullState *state) +ALnullState::~ALnullState() { - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); - state->~ALnullState(); } /* This updates the device-dependant effect state. This is called on * initialization and any time the device parameters (eg. playback frequency, * format) have been changed. */ -static ALboolean ALnullState_deviceUpdate(ALnullState* UNUSED(state), ALCdevice* UNUSED(device)) +ALboolean ALnullState::deviceUpdate(ALCdevice* UNUSED(device)) { return AL_TRUE; } @@ -59,7 +48,7 @@ static ALboolean ALnullState_deviceUpdate(ALnullState* UNUSED(state), ALCdevice* /* This updates the effect state. This is called any time the effect is * (re)loaded into a slot. */ -static ALvoid ALnullState_update(ALnullState* UNUSED(state), const ALCcontext* UNUSED(context), const ALeffectslot* UNUSED(slot), const ALeffectProps* UNUSED(props)) +void ALnullState::update(const ALCcontext* UNUSED(context), const ALeffectslot* UNUSED(slot), const ALeffectProps* UNUSED(props)) { } @@ -67,38 +56,18 @@ static ALvoid ALnullState_update(ALnullState* UNUSED(state), const ALCcontext* U * input to the output buffer. The result should be added to the output buffer, * not replace it. */ -static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALsizei UNUSED(samplesToDo), const ALfloatBUFFERSIZE*RESTRICT UNUSED(samplesIn), ALfloatBUFFERSIZE*RESTRICT UNUSED(samplesOut), ALsizei UNUSED(numChannels)) +void ALnullState::process(ALsizei UNUSED(samplesToDo), const ALfloat (*RESTRICT UNUSED(samplesIn))[BUFFERSIZE], ALfloat (*RESTRICT UNUSED(samplesOut))[BUFFERSIZE], ALsizei UNUSED(numChannels)) { } -/* This allocates memory to store the object, before it gets constructed. - * DECLARE_DEFAULT_ALLOCATORS can be used to declare a default method. - */ -static void *ALnullState_New(size_t size) -{ - return al_calloc(16, size); -} - -/* This frees the memory used by the object, after it has been destructed. - * DECLARE_DEFAULT_ALLOCATORS can be used to declare a default method. - */ -static void ALnullState_Delete(void *ptr) -{ - al_free(ptr); -} - struct NullStateFactory final : public EffectStateFactory { - ALeffectState *create() override; + EffectState *create() override; }; /* Creates ALeffectState objects of the appropriate type. */ -ALeffectState *NullStateFactory::create() -{ - ALnullState *state; - NEW_OBJ0(state, ALnullState)(); - return state; -} +EffectState *NullStateFactory::create() +{ return new ALnullState{}; } EffectStateFactory *NullStateFactory_getFactory(void) { diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp index ec473678..3c375499 100644 --- a/Alc/effects/pshifter.cpp +++ b/Alc/effects/pshifter.cpp @@ -117,7 +117,7 @@ inline complex_d polar2rect(const ALphasor &number) { return std::polar(number.Amplitude, number.Phase); } -struct ALpshifterState final : public ALeffectState { +struct ALpshifterState final : public EffectState { /* Effect parameters */ ALsizei mCount; ALsizei mPitchShiftI; @@ -141,53 +141,39 @@ struct ALpshifterState final : public ALeffectState { /* Effect gains for each output channel */ ALfloat mCurrentGains[MAX_OUTPUT_CHANNELS]; ALfloat mTargetGains[MAX_OUTPUT_CHANNELS]; -}; -static ALvoid ALpshifterState_Destruct(ALpshifterState *state); -static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device); -static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALpshifterState) -DEFINE_ALEFFECTSTATE_VTABLE(ALpshifterState); + ALboolean deviceUpdate(ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; -void ALpshifterState_Construct(ALpshifterState *state) -{ - new (state) ALpshifterState{}; - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALpshifterState, ALeffectState, state); -} - -ALvoid ALpshifterState_Destruct(ALpshifterState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); - state->~ALpshifterState(); -} + DEF_NEWDEL(ALpshifterState) +}; -ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device) +ALboolean ALpshifterState::deviceUpdate(ALCdevice *device) { /* (Re-)initializing parameters and clear the buffers. */ - state->mCount = FIFO_LATENCY; - state->mPitchShiftI = FRACTIONONE; - state->mPitchShift = 1.0f; - state->mFreqPerBin = device->Frequency / (ALfloat)STFT_SIZE; - - std::fill(std::begin(state->mInFIFO), std::end(state->mInFIFO), 0.0f); - std::fill(std::begin(state->mOutFIFO), std::end(state->mOutFIFO), 0.0f); - std::fill(std::begin(state->mLastPhase), std::end(state->mLastPhase), 0.0); - std::fill(std::begin(state->mSumPhase), std::end(state->mSumPhase), 0.0); - std::fill(std::begin(state->mOutputAccum), std::end(state->mOutputAccum), 0.0); - std::fill(std::begin(state->mFFTbuffer), std::end(state->mFFTbuffer), complex_d{}); - std::fill(std::begin(state->mAnalysis_buffer), std::end(state->mAnalysis_buffer), ALfrequencyDomain{}); - std::fill(std::begin(state->mSyntesis_buffer), std::end(state->mSyntesis_buffer), ALfrequencyDomain{}); - - std::fill(std::begin(state->mCurrentGains), std::end(state->mCurrentGains), 0.0f); - std::fill(std::begin(state->mTargetGains), std::end(state->mTargetGains), 0.0f); + mCount = FIFO_LATENCY; + mPitchShiftI = FRACTIONONE; + mPitchShift = 1.0f; + mFreqPerBin = device->Frequency / (ALfloat)STFT_SIZE; + + std::fill(std::begin(mInFIFO), std::end(mInFIFO), 0.0f); + std::fill(std::begin(mOutFIFO), std::end(mOutFIFO), 0.0f); + std::fill(std::begin(mLastPhase), std::end(mLastPhase), 0.0); + std::fill(std::begin(mSumPhase), std::end(mSumPhase), 0.0); + std::fill(std::begin(mOutputAccum), std::end(mOutputAccum), 0.0); + std::fill(std::begin(mFFTbuffer), std::end(mFFTbuffer), complex_d{}); + std::fill(std::begin(mAnalysis_buffer), std::end(mAnalysis_buffer), ALfrequencyDomain{}); + std::fill(std::begin(mSyntesis_buffer), std::end(mSyntesis_buffer), ALfrequencyDomain{}); + + std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f); + std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f); return AL_TRUE; } -ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +void ALpshifterState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) { const ALCdevice *device = context->Device; ALfloat coeffs[MAX_AMBI_COEFFS]; @@ -196,30 +182,30 @@ ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, pitch = std::pow(2.0f, (ALfloat)(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f ); - state->mPitchShiftI = fastf2i(pitch*FRACTIONONE); - state->mPitchShift = state->mPitchShiftI * (1.0f/FRACTIONONE); + mPitchShiftI = fastf2i(pitch*FRACTIONONE); + mPitchShift = mPitchShiftI * (1.0f/FRACTIONONE); CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->mTargetGains); + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, mTargetGains); } -ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +void ALpshifterState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { /* Pitch shifter engine based on the work of Stephan Bernsee. * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/ */ static constexpr ALdouble expected{M_PI*2.0 / OVERSAMP}; - const ALdouble freq_per_bin{state->mFreqPerBin}; - ALfloat *RESTRICT bufferOut{state->mBufferOut}; - ALsizei count{state->mCount}; + const ALdouble freq_per_bin{mFreqPerBin}; + ALfloat *RESTRICT bufferOut{mBufferOut}; + ALsizei count{mCount}; for(ALsizei i{0};i < SamplesToDo;) { do { /* Fill FIFO buffer with samples data */ - state->mInFIFO[count] = SamplesIn[0][i]; - bufferOut[i] = state->mOutFIFO[count - FIFO_LATENCY]; + mInFIFO[count] = SamplesIn[0][i]; + bufferOut[i] = mOutFIFO[count - FIFO_LATENCY]; count++; } while(++i < SamplesToDo && count < STFT_SIZE); @@ -231,13 +217,13 @@ ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, cons /* Real signal windowing and store in FFTbuffer */ for(ALsizei k{0};k < STFT_SIZE;k++) { - state->mFFTbuffer[k].real(state->mInFIFO[k] * HannWindow[k]); - state->mFFTbuffer[k].imag(0.0); + mFFTbuffer[k].real(mInFIFO[k] * HannWindow[k]); + mFFTbuffer[k].imag(0.0); } /* ANALYSIS */ /* Apply FFT to FFTbuffer data */ - complex_fft(state->mFFTbuffer, STFT_SIZE, -1.0); + complex_fft(mFFTbuffer, STFT_SIZE, -1.0); /* Analyze the obtained data. Since the real FFT is symmetric, only * STFT_HALF_SIZE+1 samples are needed. @@ -245,10 +231,10 @@ ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, cons for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) { /* Compute amplitude and phase */ - ALphasor component{rect2polar(state->mFFTbuffer[k])}; + ALphasor component{rect2polar(mFFTbuffer[k])}; /* Compute phase difference and subtract expected phase difference */ - double tmp{(component.Phase - state->mLastPhase[k]) - k*expected}; + double tmp{(component.Phase - mLastPhase[k]) - k*expected}; /* Map delta phase into +/- Pi interval */ int qpd{double2int(tmp / M_PI)}; @@ -261,29 +247,28 @@ ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, cons * for maintain the gain (because half of bins are used) and store * amplitude and true frequency in analysis buffer. */ - state->mAnalysis_buffer[k].Amplitude = 2.0 * component.Amplitude; - state->mAnalysis_buffer[k].Frequency = (k + tmp) * freq_per_bin; + mAnalysis_buffer[k].Amplitude = 2.0 * component.Amplitude; + mAnalysis_buffer[k].Frequency = (k + tmp) * freq_per_bin; /* Store actual phase[k] for the calculations in the next frame*/ - state->mLastPhase[k] = component.Phase; + mLastPhase[k] = component.Phase; } /* PROCESSING */ /* pitch shifting */ for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) { - state->mSyntesis_buffer[k].Amplitude = 0.0; - state->mSyntesis_buffer[k].Frequency = 0.0; + mSyntesis_buffer[k].Amplitude = 0.0; + mSyntesis_buffer[k].Frequency = 0.0; } for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) { - ALsizei j{(k*state->mPitchShiftI) >> FRACTIONBITS}; + ALsizei j{(k*mPitchShiftI) >> FRACTIONBITS}; if(j >= STFT_HALF_SIZE+1) break; - state->mSyntesis_buffer[j].Amplitude += state->mAnalysis_buffer[k].Amplitude; - state->mSyntesis_buffer[j].Frequency = state->mAnalysis_buffer[k].Frequency * - state->mPitchShift; + mSyntesis_buffer[j].Amplitude += mAnalysis_buffer[k].Amplitude; + mSyntesis_buffer[j].Frequency = mAnalysis_buffer[k].Frequency * mPitchShift; } /* SYNTHESIS */ @@ -294,56 +279,52 @@ ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, cons ALdouble tmp; /* Compute bin deviation from scaled freq */ - tmp = state->mSyntesis_buffer[k].Frequency/freq_per_bin - k; + tmp = mSyntesis_buffer[k].Frequency/freq_per_bin - k; /* Calculate actual delta phase and accumulate it to get bin phase */ - state->mSumPhase[k] += (k + tmp) * expected; + mSumPhase[k] += (k + tmp) * expected; - component.Amplitude = state->mSyntesis_buffer[k].Amplitude; - component.Phase = state->mSumPhase[k]; + component.Amplitude = mSyntesis_buffer[k].Amplitude; + component.Phase = mSumPhase[k]; /* Compute phasor component to cartesian complex number and storage it into FFTbuffer*/ - state->mFFTbuffer[k] = polar2rect(component); + mFFTbuffer[k] = polar2rect(component); } /* zero negative frequencies for recontruct a real signal */ for(ALsizei k{STFT_HALF_SIZE+1};k < STFT_SIZE;k++) - state->mFFTbuffer[k] = complex_d{}; + mFFTbuffer[k] = complex_d{}; /* Apply iFFT to buffer data */ - complex_fft(state->mFFTbuffer, STFT_SIZE, 1.0); + complex_fft(mFFTbuffer, STFT_SIZE, 1.0); /* Windowing and add to output */ for(ALsizei k{0};k < STFT_SIZE;k++) - state->mOutputAccum[k] += HannWindow[k] * state->mFFTbuffer[k].real() / - (0.5 * STFT_HALF_SIZE * OVERSAMP); + mOutputAccum[k] += HannWindow[k] * mFFTbuffer[k].real() / + (0.5 * STFT_HALF_SIZE * OVERSAMP); /* Shift accumulator, input & output FIFO */ ALsizei j, k; - for(k = 0;k < STFT_STEP;k++) state->mOutFIFO[k] = (ALfloat)state->mOutputAccum[k]; - for(j = 0;k < STFT_SIZE;k++,j++) state->mOutputAccum[j] = state->mOutputAccum[k]; - for(;j < STFT_SIZE;j++) state->mOutputAccum[j] = 0.0; + for(k = 0;k < STFT_STEP;k++) mOutFIFO[k] = (ALfloat)mOutputAccum[k]; + for(j = 0;k < STFT_SIZE;k++,j++) mOutputAccum[j] = mOutputAccum[k]; + for(;j < STFT_SIZE;j++) mOutputAccum[j] = 0.0; for(k = 0;k < FIFO_LATENCY;k++) - state->mInFIFO[k] = state->mInFIFO[k+STFT_STEP]; + mInFIFO[k] = mInFIFO[k+STFT_STEP]; } - state->mCount = count; + mCount = count; /* Now, mix the processed sound data to the output. */ - MixSamples(bufferOut, NumChannels, SamplesOut, state->mCurrentGains, state->mTargetGains, + MixSamples(bufferOut, NumChannels, SamplesOut, mCurrentGains, mTargetGains, maxi(SamplesToDo, 512), 0, SamplesToDo); } } // namespace struct PshifterStateFactory final : public EffectStateFactory { - ALeffectState *create() override; + EffectState *create() override; }; -ALeffectState *PshifterStateFactory::create() -{ - ALpshifterState *state; - NEW_OBJ0(state, ALpshifterState)(); - return state; -} +EffectState *PshifterStateFactory::create() +{ return new ALpshifterState{}; } EffectStateFactory *PshifterStateFactory_getFactory(void) { diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 229cd316..91d2d0d6 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -280,7 +280,7 @@ typedef struct LateReverb { ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; } LateReverb; -struct ReverbState final : public ALeffectState { +struct ReverbState final : public EffectState { /* All delay lines are allocated as a single buffer to reduce memory * fragmentation and management code. */ @@ -332,116 +332,106 @@ struct ReverbState final : public ALeffectState { /* Temporary storage used when processing. */ alignas(16) ALfloat mTempSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; alignas(16) ALfloat mMixBuffer[NUM_LINES][MAX_UPDATE_SAMPLES]; -}; -static ALvoid ReverbState_Destruct(ReverbState *State); -static ALboolean ReverbState_deviceUpdate(ReverbState *State, ALCdevice *Device); -static ALvoid ReverbState_update(ReverbState *State, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props); -static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ReverbState) -DEFINE_ALEFFECTSTATE_VTABLE(ReverbState); + ReverbState(); -static void ReverbState_Construct(ReverbState *state) -{ - new (state) ReverbState{}; + ALboolean deviceUpdate(ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ReverbState, ALeffectState, state); + DEF_NEWDEL(ReverbState) +}; - state->mParams.Density = AL_EAXREVERB_DEFAULT_DENSITY; - state->mParams.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION; - state->mParams.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME; - state->mParams.HFDecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME*AL_EAXREVERB_DEFAULT_DECAY_HFRATIO; - state->mParams.LFDecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME*AL_EAXREVERB_DEFAULT_DECAY_LFRATIO; - state->mParams.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE; - state->mParams.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE; +ReverbState::ReverbState() +{ + mParams.Density = AL_EAXREVERB_DEFAULT_DENSITY; + mParams.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION; + mParams.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME; + mParams.HFDecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME*AL_EAXREVERB_DEFAULT_DECAY_HFRATIO; + mParams.LFDecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME*AL_EAXREVERB_DEFAULT_DECAY_LFRATIO; + mParams.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE; + mParams.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE; for(ALsizei i{0};i < NUM_LINES;i++) { - BiquadFilter_clear(&state->mFilter[i].Lp); - BiquadFilter_clear(&state->mFilter[i].Hp); + BiquadFilter_clear(&mFilter[i].Lp); + BiquadFilter_clear(&mFilter[i].Hp); } - state->mDelay.Mask = 0; - state->mDelay.Line = NULL; + mDelay.Mask = 0; + mDelay.Line = NULL; for(ALsizei i{0};i < NUM_LINES;i++) { - state->mEarlyDelayTap[i][0] = 0; - state->mEarlyDelayTap[i][1] = 0; - state->mEarlyDelayCoeff[i][0] = 0.0f; - state->mEarlyDelayCoeff[i][1] = 0.0f; + mEarlyDelayTap[i][0] = 0; + mEarlyDelayTap[i][1] = 0; + mEarlyDelayCoeff[i][0] = 0.0f; + mEarlyDelayCoeff[i][1] = 0.0f; } - state->mLateFeedTap = 0; + mLateFeedTap = 0; for(ALsizei i{0};i < NUM_LINES;i++) { - state->mLateDelayTap[i][0] = 0; - state->mLateDelayTap[i][1] = 0; + mLateDelayTap[i][0] = 0; + mLateDelayTap[i][1] = 0; } - state->mMixX = 0.0f; - state->mMixY = 0.0f; + mMixX = 0.0f; + mMixY = 0.0f; - state->mEarly.VecAp.Delay.Mask = 0; - state->mEarly.VecAp.Delay.Line = NULL; - state->mEarly.VecAp.Coeff = 0.0f; - state->mEarly.Delay.Mask = 0; - state->mEarly.Delay.Line = NULL; + mEarly.VecAp.Delay.Mask = 0; + mEarly.VecAp.Delay.Line = NULL; + mEarly.VecAp.Coeff = 0.0f; + mEarly.Delay.Mask = 0; + mEarly.Delay.Line = NULL; for(ALsizei i{0};i < NUM_LINES;i++) { - state->mEarly.VecAp.Offset[i][0] = 0; - state->mEarly.VecAp.Offset[i][1] = 0; - state->mEarly.Offset[i][0] = 0; - state->mEarly.Offset[i][1] = 0; - state->mEarly.Coeff[i][0] = 0.0f; - state->mEarly.Coeff[i][1] = 0.0f; + mEarly.VecAp.Offset[i][0] = 0; + mEarly.VecAp.Offset[i][1] = 0; + mEarly.Offset[i][0] = 0; + mEarly.Offset[i][1] = 0; + mEarly.Coeff[i][0] = 0.0f; + mEarly.Coeff[i][1] = 0.0f; } - state->mLate.DensityGain[0] = 0.0f; - state->mLate.DensityGain[1] = 0.0f; - state->mLate.Delay.Mask = 0; - state->mLate.Delay.Line = NULL; - state->mLate.VecAp.Delay.Mask = 0; - state->mLate.VecAp.Delay.Line = NULL; - state->mLate.VecAp.Coeff = 0.0f; + mLate.DensityGain[0] = 0.0f; + mLate.DensityGain[1] = 0.0f; + mLate.Delay.Mask = 0; + mLate.Delay.Line = NULL; + mLate.VecAp.Delay.Mask = 0; + mLate.VecAp.Delay.Line = NULL; + mLate.VecAp.Coeff = 0.0f; for(ALsizei i{0};i < NUM_LINES;i++) { - state->mLate.Offset[i][0] = 0; - state->mLate.Offset[i][1] = 0; + mLate.Offset[i][0] = 0; + mLate.Offset[i][1] = 0; - state->mLate.VecAp.Offset[i][0] = 0; - state->mLate.VecAp.Offset[i][1] = 0; + mLate.VecAp.Offset[i][0] = 0; + mLate.VecAp.Offset[i][1] = 0; - state->mLate.T60[i].MidGain[0] = 0.0f; - state->mLate.T60[i].MidGain[1] = 0.0f; - BiquadFilter_clear(&state->mLate.T60[i].HFFilter); - BiquadFilter_clear(&state->mLate.T60[i].LFFilter); + mLate.T60[i].MidGain[0] = 0.0f; + mLate.T60[i].MidGain[1] = 0.0f; + BiquadFilter_clear(&mLate.T60[i].HFFilter); + BiquadFilter_clear(&mLate.T60[i].LFFilter); } for(ALsizei i{0};i < NUM_LINES;i++) { for(ALsizei j{0};j < MAX_OUTPUT_CHANNELS;j++) { - state->mEarly.CurrentGain[i][j] = 0.0f; - state->mEarly.PanGain[i][j] = 0.0f; - state->mLate.CurrentGain[i][j] = 0.0f; - state->mLate.PanGain[i][j] = 0.0f; + mEarly.CurrentGain[i][j] = 0.0f; + mEarly.PanGain[i][j] = 0.0f; + mLate.CurrentGain[i][j] = 0.0f; + mLate.PanGain[i][j] = 0.0f; } } - state->mFadeCount = 0; - state->mMaxUpdate[0] = MAX_UPDATE_SAMPLES; - state->mMaxUpdate[1] = MAX_UPDATE_SAMPLES; - state->mOffset = 0; -} - -static ALvoid ReverbState_Destruct(ReverbState *State) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,State)); - State->~ReverbState(); + mFadeCount = 0; + mMaxUpdate[0] = MAX_UPDATE_SAMPLES; + mMaxUpdate[1] = MAX_UPDATE_SAMPLES; + mOffset = 0; } /************************************** @@ -555,70 +545,70 @@ static ALboolean AllocLines(const ALuint frequency, ReverbState *State) return AL_TRUE; } -static ALboolean ReverbState_deviceUpdate(ReverbState *State, ALCdevice *Device) +ALboolean ReverbState::deviceUpdate(ALCdevice *Device) { ALuint frequency = Device->Frequency; ALfloat multiplier; ALsizei i, j; /* Allocate the delay lines. */ - if(!AllocLines(frequency, State)) + if(!AllocLines(frequency, this)) return AL_FALSE; multiplier = CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY); /* The late feed taps are set a fixed position past the latest delay tap. */ - State->mLateFeedTap = float2int((AL_EAXREVERB_MAX_REFLECTIONS_DELAY + - EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier) * - frequency); + mLateFeedTap = float2int((AL_EAXREVERB_MAX_REFLECTIONS_DELAY + + EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier) * + frequency); /* Clear filters and gain coefficients since the delay lines were all just * cleared (if not reallocated). */ for(i = 0;i < NUM_LINES;i++) { - BiquadFilter_clear(&State->mFilter[i].Lp); - BiquadFilter_clear(&State->mFilter[i].Hp); + BiquadFilter_clear(&mFilter[i].Lp); + BiquadFilter_clear(&mFilter[i].Hp); } for(i = 0;i < NUM_LINES;i++) { - State->mEarlyDelayCoeff[i][0] = 0.0f; - State->mEarlyDelayCoeff[i][1] = 0.0f; + mEarlyDelayCoeff[i][0] = 0.0f; + mEarlyDelayCoeff[i][1] = 0.0f; } for(i = 0;i < NUM_LINES;i++) { - State->mEarly.Coeff[i][0] = 0.0f; - State->mEarly.Coeff[i][1] = 0.0f; + mEarly.Coeff[i][0] = 0.0f; + mEarly.Coeff[i][1] = 0.0f; } - State->mLate.DensityGain[0] = 0.0f; - State->mLate.DensityGain[1] = 0.0f; + mLate.DensityGain[0] = 0.0f; + mLate.DensityGain[1] = 0.0f; for(i = 0;i < NUM_LINES;i++) { - State->mLate.T60[i].MidGain[0] = 0.0f; - State->mLate.T60[i].MidGain[1] = 0.0f; - BiquadFilter_clear(&State->mLate.T60[i].HFFilter); - BiquadFilter_clear(&State->mLate.T60[i].LFFilter); + mLate.T60[i].MidGain[0] = 0.0f; + mLate.T60[i].MidGain[1] = 0.0f; + BiquadFilter_clear(&mLate.T60[i].HFFilter); + BiquadFilter_clear(&mLate.T60[i].LFFilter); } for(i = 0;i < NUM_LINES;i++) { for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) { - State->mEarly.CurrentGain[i][j] = 0.0f; - State->mEarly.PanGain[i][j] = 0.0f; - State->mLate.CurrentGain[i][j] = 0.0f; - State->mLate.PanGain[i][j] = 0.0f; + mEarly.CurrentGain[i][j] = 0.0f; + mEarly.PanGain[i][j] = 0.0f; + mLate.CurrentGain[i][j] = 0.0f; + mLate.PanGain[i][j] = 0.0f; } } /* Reset counters and offset base. */ - State->mFadeCount = 0; - State->mMaxUpdate[0] = MAX_UPDATE_SAMPLES; - State->mMaxUpdate[1] = MAX_UPDATE_SAMPLES; - State->mOffset = 0; + mFadeCount = 0; + mMaxUpdate[0] = MAX_UPDATE_SAMPLES; + mMaxUpdate[1] = MAX_UPDATE_SAMPLES; + mOffset = 0; return AL_TRUE; } @@ -902,8 +892,8 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection aluMatrixf transform, rot; ALsizei i; - STATIC_CAST(ALeffectState,State)->OutBuffer = Device->FOAOut.Buffer; - STATIC_CAST(ALeffectState,State)->OutChannels = Device->FOAOut.NumChannels; + State->mOutBuffer = Device->FOAOut.Buffer; + State->mOutChannels = Device->FOAOut.NumChannels; /* Note: _res is transposed. */ #define MATRIX_MULT(_res, _m1, _m2) do { \ @@ -934,7 +924,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection #undef MATRIX_MULT } -static void ReverbState_update(ReverbState *State, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) +void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) { const ALCdevice *Device = Context->Device; const ALlistener &Listener = Context->Listener; @@ -950,29 +940,29 @@ static void ReverbState_update(ReverbState *State, const ALCcontext *Context, co * killing most of the signal. */ gainhf = maxf(props->Reverb.GainHF, 0.001f); - BiquadFilter_setParams(&State->mFilter[0].Lp, BiquadType::HighShelf, gainhf, hf0norm, + BiquadFilter_setParams(&mFilter[0].Lp, BiquadType::HighShelf, gainhf, hf0norm, calc_rcpQ_from_slope(gainhf, 1.0f)); lf0norm = minf(props->Reverb.LFReference / frequency, 0.49f); gainlf = maxf(props->Reverb.GainLF, 0.001f); - BiquadFilter_setParams(&State->mFilter[0].Hp, BiquadType::LowShelf, gainlf, lf0norm, + BiquadFilter_setParams(&mFilter[0].Hp, BiquadType::LowShelf, gainlf, lf0norm, calc_rcpQ_from_slope(gainlf, 1.0f)); for(i = 1;i < NUM_LINES;i++) { - BiquadFilter_copyParams(&State->mFilter[i].Lp, &State->mFilter[0].Lp); - BiquadFilter_copyParams(&State->mFilter[i].Hp, &State->mFilter[0].Hp); + BiquadFilter_copyParams(&mFilter[i].Lp, &mFilter[0].Lp); + BiquadFilter_copyParams(&mFilter[i].Hp, &mFilter[0].Hp); } /* Update the main effect delay and associated taps. */ UpdateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay, props->Reverb.Density, props->Reverb.DecayTime, frequency, - State); + this); /* Update the early lines. */ UpdateEarlyLines(props->Reverb.Density, props->Reverb.Diffusion, - props->Reverb.DecayTime, frequency, &State->mEarly); + props->Reverb.DecayTime, frequency, &mEarly); /* Get the mixing matrix coefficients. */ - CalcMatrixCoeffs(props->Reverb.Diffusion, &State->mMixX, &State->mMixY); + CalcMatrixCoeffs(props->Reverb.Diffusion, &mMixX, &mMixY); /* If the HF limit parameter is flagged, calculate an appropriate limit * based on the air absorption parameter. @@ -992,45 +982,43 @@ static void ReverbState_update(ReverbState *State, const ALCcontext *Context, co /* Update the late lines. */ UpdateLateLines(props->Reverb.Density, props->Reverb.Diffusion, lfDecayTime, props->Reverb.DecayTime, hfDecayTime, lf0norm, hf0norm, - frequency, &State->mLate + frequency, &mLate ); /* Update early and late 3D panning. */ gain = props->Reverb.Gain * Slot->Params.Gain * ReverbBoost; Update3DPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain, - State); + this); /* Calculate the max update size from the smallest relevant delay. */ - State->mMaxUpdate[1] = mini(MAX_UPDATE_SAMPLES, - mini(State->mEarly.Offset[0][1], State->mLate.Offset[0][1]) - ); + mMaxUpdate[1] = mini(MAX_UPDATE_SAMPLES, mini(mEarly.Offset[0][1], mLate.Offset[0][1])); /* Determine if delay-line cross-fading is required. Density is essentially * a master control for the feedback delays, so changes the offsets of many * delay lines. */ - if(State->mParams.Density != props->Reverb.Density || + if(mParams.Density != props->Reverb.Density || /* Diffusion and decay times influences the decay rate (gain) of the * late reverb T60 filter. */ - State->mParams.Diffusion != props->Reverb.Diffusion || - State->mParams.DecayTime != props->Reverb.DecayTime || - State->mParams.HFDecayTime != hfDecayTime || - State->mParams.LFDecayTime != lfDecayTime || + mParams.Diffusion != props->Reverb.Diffusion || + mParams.DecayTime != props->Reverb.DecayTime || + mParams.HFDecayTime != hfDecayTime || + mParams.LFDecayTime != lfDecayTime || /* HF/LF References control the weighting used to calculate the density * gain. */ - State->mParams.HFReference != props->Reverb.HFReference || - State->mParams.LFReference != props->Reverb.LFReference) - State->mFadeCount = 0; - State->mParams.Density = props->Reverb.Density; - State->mParams.Diffusion = props->Reverb.Diffusion; - State->mParams.DecayTime = props->Reverb.DecayTime; - State->mParams.HFDecayTime = hfDecayTime; - State->mParams.LFDecayTime = lfDecayTime; - State->mParams.HFReference = props->Reverb.HFReference; - State->mParams.LFReference = props->Reverb.LFReference; + mParams.HFReference != props->Reverb.HFReference || + mParams.LFReference != props->Reverb.LFReference) + mFadeCount = 0; + mParams.Density = props->Reverb.Density; + mParams.Diffusion = props->Reverb.Diffusion; + mParams.DecayTime = props->Reverb.DecayTime; + mParams.HFDecayTime = hfDecayTime; + mParams.LFDecayTime = lfDecayTime; + mParams.HFReference = props->Reverb.HFReference; + mParams.LFReference = props->Reverb.LFReference; } @@ -1454,12 +1442,12 @@ static void LateReverb_Faded(ReverbState *State, ALsizei offset, const ALsizei t VectorScatterRevDelayIn(&late_delay, offset, mixX, mixY, temps, todo); } -static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +void ReverbState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALfloat (*RESTRICT afmt)[MAX_UPDATE_SAMPLES] = State->mTempSamples; - ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES] = State->mMixBuffer; - ALsizei fadeCount = State->mFadeCount; - ALsizei offset = State->mOffset; + ALfloat (*RESTRICT afmt)[MAX_UPDATE_SAMPLES] = mTempSamples; + ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES] = mMixBuffer; + ALsizei fadeCount = mFadeCount; + ALsizei offset = mOffset; ALsizei base, c; /* Process reverb for these samples. */ @@ -1470,9 +1458,9 @@ static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const if(FADE_SAMPLES-fadeCount > 0) { todo = mini(todo, FADE_SAMPLES-fadeCount); - todo = mini(todo, State->mMaxUpdate[0]); + todo = mini(todo, mMaxUpdate[0]); } - todo = mini(todo, State->mMaxUpdate[1]); + todo = mini(todo, mMaxUpdate[1]); /* If this is not the final update, ensure the update size is a * multiple of 4 for the SIMD mixers. */ @@ -1490,11 +1478,11 @@ static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const for(c = 0;c < NUM_LINES;c++) { /* Band-pass the incoming samples. */ - BiquadFilter_process(&State->mFilter[c].Lp, samples[0], afmt[c], todo); - BiquadFilter_process(&State->mFilter[c].Hp, samples[1], samples[0], todo); + BiquadFilter_process(&mFilter[c].Lp, samples[0], afmt[c], todo); + BiquadFilter_process(&mFilter[c].Hp, samples[1], samples[0], todo); /* Feed the initial delay line. */ - DelayLineIn(&State->mDelay, offset, c, samples[1], todo); + DelayLineIn(&mDelay, offset, c, samples[1], todo); } if(UNLIKELY(fadeCount < FADE_SAMPLES)) @@ -1502,21 +1490,21 @@ static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const ALfloat fade = (ALfloat)fadeCount; /* Generate early reflections. */ - EarlyReflection_Faded(State, offset, todo, fade, samples); + EarlyReflection_Faded(this, offset, todo, fade, samples); /* Mix the A-Format results to output, implicitly converting back * to B-Format. */ for(c = 0;c < NUM_LINES;c++) MixSamples(samples[c], NumChannels, SamplesOut, - State->mEarly.CurrentGain[c], State->mEarly.PanGain[c], + mEarly.CurrentGain[c], mEarly.PanGain[c], SamplesToDo-base, base, todo ); /* Generate and mix late reverb. */ - LateReverb_Faded(State, offset, todo, fade, samples); + LateReverb_Faded(this, offset, todo, fade, samples); for(c = 0;c < NUM_LINES;c++) MixSamples(samples[c], NumChannels, SamplesOut, - State->mLate.CurrentGain[c], State->mLate.PanGain[c], + mLate.CurrentGain[c], mLate.PanGain[c], SamplesToDo-base, base, todo ); @@ -1528,35 +1516,35 @@ static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const fadeCount = FADE_SAMPLES; for(c = 0;c < NUM_LINES;c++) { - State->mEarlyDelayTap[c][0] = State->mEarlyDelayTap[c][1]; - State->mEarlyDelayCoeff[c][0] = State->mEarlyDelayCoeff[c][1]; - State->mEarly.VecAp.Offset[c][0] = State->mEarly.VecAp.Offset[c][1]; - State->mEarly.Offset[c][0] = State->mEarly.Offset[c][1]; - State->mEarly.Coeff[c][0] = State->mEarly.Coeff[c][1]; - State->mLateDelayTap[c][0] = State->mLateDelayTap[c][1]; - State->mLate.VecAp.Offset[c][0] = State->mLate.VecAp.Offset[c][1]; - State->mLate.Offset[c][0] = State->mLate.Offset[c][1]; - State->mLate.T60[c].MidGain[0] = State->mLate.T60[c].MidGain[1]; + mEarlyDelayTap[c][0] = mEarlyDelayTap[c][1]; + mEarlyDelayCoeff[c][0] = mEarlyDelayCoeff[c][1]; + mEarly.VecAp.Offset[c][0] = mEarly.VecAp.Offset[c][1]; + mEarly.Offset[c][0] = mEarly.Offset[c][1]; + mEarly.Coeff[c][0] = mEarly.Coeff[c][1]; + mLateDelayTap[c][0] = mLateDelayTap[c][1]; + mLate.VecAp.Offset[c][0] = mLate.VecAp.Offset[c][1]; + mLate.Offset[c][0] = mLate.Offset[c][1]; + mLate.T60[c].MidGain[0] = mLate.T60[c].MidGain[1]; } - State->mLate.DensityGain[0] = State->mLate.DensityGain[1]; - State->mMaxUpdate[0] = State->mMaxUpdate[1]; + mLate.DensityGain[0] = mLate.DensityGain[1]; + mMaxUpdate[0] = mMaxUpdate[1]; } } else { /* Generate and mix early reflections. */ - EarlyReflection_Unfaded(State, offset, todo, samples); + EarlyReflection_Unfaded(this, offset, todo, samples); for(c = 0;c < NUM_LINES;c++) MixSamples(samples[c], NumChannels, SamplesOut, - State->mEarly.CurrentGain[c], State->mEarly.PanGain[c], + mEarly.CurrentGain[c], mEarly.PanGain[c], SamplesToDo-base, base, todo ); /* Generate and mix late reverb. */ - LateReverb_Unfaded(State, offset, todo, samples); + LateReverb_Unfaded(this, offset, todo, samples); for(c = 0;c < NUM_LINES;c++) MixSamples(samples[c], NumChannels, SamplesOut, - State->mLate.CurrentGain[c], State->mLate.PanGain[c], + mLate.CurrentGain[c], mLate.PanGain[c], SamplesToDo-base, base, todo ); } @@ -1566,21 +1554,17 @@ static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const base += todo; } - State->mOffset = offset; - State->mFadeCount = fadeCount; + mOffset = offset; + mFadeCount = fadeCount; } struct ReverbStateFactory final : public EffectStateFactory { - ALeffectState *create() override; + EffectState *create() override; }; -ALeffectState *ReverbStateFactory::create() -{ - ReverbState *state; - NEW_OBJ0(state, ReverbState)(); - return state; -} +EffectState *ReverbStateFactory::create() +{ return new ReverbState{}; } EffectStateFactory *ReverbStateFactory_getFactory(void) { diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index d3d4e704..ca2cb663 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -8,58 +8,31 @@ #include "atomic.h" -struct ALeffectStateVtable; struct ALeffectslot; -typedef struct ALeffectState { - RefCount Ref; - const struct ALeffectStateVtable *vtbl; - ALfloat (*OutBuffer)[BUFFERSIZE]; - ALsizei OutChannels; -} ALeffectState; +struct EffectState { + RefCount mRef{1u}; -void ALeffectState_Construct(ALeffectState *state); -void ALeffectState_Destruct(ALeffectState *state); + ALfloat (*mOutBuffer)[BUFFERSIZE]{nullptr}; + ALsizei mOutChannels{0}; -struct ALeffectStateVtable { - void (*const Destruct)(ALeffectState *state); - ALboolean (*const deviceUpdate)(ALeffectState *state, ALCdevice *device); - void (*const update)(ALeffectState *state, const ALCcontext *context, const struct ALeffectslot *slot, const union ALeffectProps *props); - void (*const process)(ALeffectState *state, ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels); + virtual ~EffectState() = default; - void (*const Delete)(void *ptr); -}; + virtual ALboolean deviceUpdate(ALCdevice *device) = 0; + virtual void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) = 0; + virtual void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) = 0; -/* Small hack to use a pointer-to-array types as a normal argument type. - * Shouldn't be used directly. - */ -typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE]; - -#define DEFINE_ALEFFECTSTATE_VTABLE(T) \ -DECLARE_THUNK(T, ALeffectState, void, Destruct) \ -DECLARE_THUNK1(T, ALeffectState, ALboolean, deviceUpdate, ALCdevice*) \ -DECLARE_THUNK3(T, ALeffectState, void, update, const ALCcontext*, const ALeffectslot*, const ALeffectProps*) \ -DECLARE_THUNK4(T, ALeffectState, void, process, ALsizei, const ALfloatBUFFERSIZE*RESTRICT, ALfloatBUFFERSIZE*RESTRICT, ALsizei) \ -static void T##_ALeffectState_Delete(void *ptr) \ -{ return T##_Delete(STATIC_UPCAST(T, ALeffectState, (ALeffectState*)ptr)); } \ - \ -static const struct ALeffectStateVtable T##_ALeffectState_vtable = { \ - T##_ALeffectState_Destruct, \ - \ - T##_ALeffectState_deviceUpdate, \ - T##_ALeffectState_update, \ - T##_ALeffectState_process, \ - \ - T##_ALeffectState_Delete, \ -} + void IncRef() noexcept; + void DecRef() noexcept; +}; struct EffectStateFactory { virtual ~EffectStateFactory() { } - virtual ALeffectState *create() = 0; + virtual EffectState *create() = 0; }; @@ -79,7 +52,7 @@ struct ALeffectslotProps { ALenum Type; ALeffectProps Props; - ALeffectState *State; + EffectState *State; ATOMIC(struct ALeffectslotProps*) next; }; @@ -93,7 +66,7 @@ struct ALeffectslot { ALenum Type{AL_EFFECT_NULL}; ALeffectProps Props{}; - ALeffectState *State{nullptr}; + EffectState *State{nullptr}; } Effect; ATOMIC(ALenum) PropsClean{AL_TRUE}; @@ -108,7 +81,7 @@ struct ALeffectslot { ALenum EffectType{AL_EFFECT_NULL}; ALeffectProps EffectProps{}; - ALeffectState *EffectState{nullptr}; + EffectState *EffectState{nullptr}; ALfloat RoomRolloff{0.0f}; /* Added to the source's room rolloff, not multiplied. */ ALfloat DecayTime{0.0f}; @@ -167,6 +140,4 @@ EffectStateFactory *DedicatedStateFactory_getFactory(void); ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect); -void ALeffectState_DecRef(ALeffectState *state); - #endif diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 64297592..8f08d94a 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -206,6 +206,7 @@ struct ALCbackend; struct ALbuffer; struct ALeffect; struct ALfilter; +struct EffectState; #define DEFAULT_OUTPUT_RATE (44100) @@ -755,7 +756,7 @@ typedef struct AsyncEvent { ALuint param; ALchar msg[1008]; } user; - struct ALeffectState *EffectState; + EffectState *mEffectState; } u; } AsyncEvent; #define ASYNC_EVENT(t) { t, { 0 } } diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index 4e25d3ee..cab9e43d 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -74,8 +74,6 @@ static inline EffectStateFactory *getFactoryByType(ALenum type) return nullptr; } -static void ALeffectState_IncRef(ALeffectState *state); - static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) { @@ -483,7 +481,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect ALCdevice *Device = Context->Device; ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL); struct ALeffectslotProps *props; - ALeffectState *State; + EffectState *State; if(newtype != EffectSlot->Effect.Type) { @@ -498,13 +496,13 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect START_MIXER_MODE(); almtx_lock(&Device->BackendLock); - State->OutBuffer = Device->Dry.Buffer; - State->OutChannels = Device->Dry.NumChannels; - if(V(State,deviceUpdate)(Device) == AL_FALSE) + State->mOutBuffer = Device->Dry.Buffer; + State->mOutChannels = Device->Dry.NumChannels; + if(State->deviceUpdate(Device) == AL_FALSE) { almtx_unlock(&Device->BackendLock); LEAVE_MIXER_MODE(); - ALeffectState_DecRef(State); + State->DecRef(); return AL_OUT_OF_MEMORY; } almtx_unlock(&Device->BackendLock); @@ -521,7 +519,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect EffectSlot->Effect.Props = effect->Props; } - ALeffectState_DecRef(EffectSlot->Effect.State); + EffectSlot->Effect.State->DecRef(); EffectSlot->Effect.State = State; } else if(effect) @@ -532,7 +530,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect while(props) { if(props->State) - ALeffectState_DecRef(props->State); + props->State->DecRef(); props->State = nullptr; props = ATOMIC_LOAD(&props->next, almemory_order_relaxed); } @@ -541,30 +539,17 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect } -static void ALeffectState_IncRef(ALeffectState *state) +void EffectState::IncRef() noexcept { - auto ref = IncrementRef(&state->Ref); - TRACEREF("%p increasing refcount to %u\n", state, ref); -} - -void ALeffectState_DecRef(ALeffectState *state) -{ - auto ref = DecrementRef(&state->Ref); - TRACEREF("%p decreasing refcount to %u\n", state, ref); - if(ref == 0) DELETE_OBJ(state); -} - - -void ALeffectState_Construct(ALeffectState *state) -{ - InitRef(&state->Ref, 1); - - state->OutBuffer = nullptr; - state->OutChannels = 0; + auto ref = IncrementRef(&mRef); + TRACEREF("%p increasing refcount to %u\n", this, ref); } -void ALeffectState_Destruct(ALeffectState *UNUSED(state)) +void EffectState::DecRef() noexcept { + auto ref = DecrementRef(&mRef); + TRACEREF("%p decreasing refcount to %u\n", this, ref); + if(ref == 0) delete this; } @@ -664,7 +649,7 @@ ALenum InitEffectSlot(ALeffectslot *slot) slot->Effect.State = factory->create(); if(!slot->Effect.State) return AL_OUT_OF_MEMORY; - ALeffectState_IncRef(slot->Effect.State); + slot->Effect.State->IncRef(); slot->Params.EffectState = slot->Effect.State; return AL_NO_ERROR; } @@ -674,21 +659,21 @@ ALeffectslot::~ALeffectslot() struct ALeffectslotProps *props{Update.load()}; if(props) { - if(props->State) ALeffectState_DecRef(props->State); + if(props->State) props->State->DecRef(); TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props); al_free(props); } if(Effect.State) - ALeffectState_DecRef(Effect.State); + Effect.State->DecRef(); if(Params.EffectState) - ALeffectState_DecRef(Params.EffectState); + Params.EffectState->DecRef(); } void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) { struct ALeffectslotProps *props; - ALeffectState *oldstate; + EffectState *oldstate; /* Get an unused property container, or allocate a new one as needed. */ props = context->FreeEffectslotProps.load(std::memory_order_relaxed); @@ -712,7 +697,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) /* Swap out any stale effect state object there may be in the container, to * delete it. */ - ALeffectState_IncRef(slot->Effect.State); + slot->Effect.State->IncRef(); oldstate = props->State; props->State = slot->Effect.State; @@ -724,13 +709,13 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) * freelist. */ if(props->State) - ALeffectState_DecRef(props->State); + props->State->DecRef(); props->State = nullptr; AtomicReplaceHead(context->FreeEffectslotProps, props); } if(oldstate) - ALeffectState_DecRef(oldstate); + oldstate->DecRef(); } void UpdateAllEffectSlotProps(ALCcontext *context) diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index 1dc2745f..d6fa01fb 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -34,7 +34,7 @@ static int EventThread(ALCcontext *context) if(evt.EnumType == EventType_ReleaseEffectState) { - ALeffectState_DecRef(evt.u.EffectState); + evt.u.mEffectState->DecRef(); continue; } -- cgit v1.2.3 From 8995306203f022cb5042f490044373f09caac177 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 22:43:28 -0800 Subject: Use proper templating for the modulator's Modulate function --- Alc/effects/modulator.cpp | 75 +++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 42 deletions(-) diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index f714f94f..ac71e444 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -37,28 +37,6 @@ #define MAX_UPDATE_SAMPLES 128 -struct ALmodulatorState final : public EffectState { - void (*mGetSamples)(ALfloat*RESTRICT, ALsizei, const ALsizei, ALsizei){}; - - ALsizei mIndex{0}; - ALsizei mStep{1}; - - struct { - BiquadFilter Filter; - - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]{}; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]{}; - } mChans[MAX_EFFECT_CHANNELS]; - - - ALboolean deviceUpdate(ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; - void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; - - DEF_NEWDEL(ALmodulatorState) -}; - - #define WAVEFORM_FRACBITS 24 #define WAVEFORM_FRACONE (1< +static void Modulate(ALfloat *RESTRICT dst, ALsizei index, const ALsizei step, ALsizei todo) +{ + ALsizei i; + for(i = 0;i < todo;i++) + { + index += step; + index &= WAVEFORM_FRACMASK; + dst[i] = func(index); + } } -DECL_TEMPLATE(Sin) -DECL_TEMPLATE(Saw) -DECL_TEMPLATE(Square) -DECL_TEMPLATE(One) -#undef DECL_TEMPLATE +struct ALmodulatorState final : public EffectState { + void (*mGetSamples)(ALfloat*RESTRICT, ALsizei, const ALsizei, ALsizei){}; + + ALsizei mIndex{0}; + ALsizei mStep{1}; + + struct { + BiquadFilter Filter; + + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]{}; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]{}; + } mChans[MAX_EFFECT_CHANNELS]; + + ALboolean deviceUpdate(ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; + + DEF_NEWDEL(ALmodulatorState) +}; ALboolean ALmodulatorState::deviceUpdate(ALCdevice *UNUSED(device)) { @@ -124,13 +115,13 @@ void ALmodulatorState::update(const ALCcontext *context, const ALeffectslot *slo mStep = clampi(mStep, 0, WAVEFORM_FRACONE-1); if(mStep == 0) - mGetSamples = ModulateOne; + mGetSamples = Modulate; else if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) - mGetSamples = ModulateSin; + mGetSamples = Modulate; else if(props->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) - mGetSamples = ModulateSaw; + mGetSamples = Modulate; else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/ - mGetSamples = ModulateSquare; + mGetSamples = Modulate; f0norm = props->Modulator.HighPassCutoff / (ALfloat)device->Frequency; f0norm = clampf(f0norm, 1.0f/512.0f, 0.49f); -- cgit v1.2.3 From 288dbbe8864ac2ede7031138f73a20de4da6ca31 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 22:48:56 -0800 Subject: Use default initialization for the reverb effect state --- Alc/effects/reverb.cpp | 151 ++++++++++--------------------------------------- 1 file changed, 31 insertions(+), 120 deletions(-) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 91d2d0d6..bf2e9a6f 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -223,21 +223,21 @@ typedef struct DelayLineI { /* The delay lines use interleaved samples, with the lengths being powers * of 2 to allow the use of bit-masking instead of a modulus for wrapping. */ - ALsizei Mask; - ALfloat (*Line)[NUM_LINES]; + ALsizei Mask{0}; + ALfloat (*Line)[NUM_LINES]{nullptr}; } DelayLineI; typedef struct VecAllpass { DelayLineI Delay; - ALfloat Coeff; - ALsizei Offset[NUM_LINES][2]; + ALfloat Coeff{0.0f}; + ALsizei Offset[NUM_LINES][2]{}; } VecAllpass; typedef struct T60Filter { /* Two filters are used to adjust the signal. One to control the low * frequencies, and one to control the high frequencies. */ - ALfloat MidGain[2]; + ALfloat MidGain[2]{0.0f, 0.0f}; BiquadFilter HFFilter, LFFilter; } T60Filter; @@ -251,23 +251,23 @@ typedef struct EarlyReflections { * reflections. */ DelayLineI Delay; - ALsizei Offset[NUM_LINES][2]; - ALfloat Coeff[NUM_LINES][2]; + ALsizei Offset[NUM_LINES][2]{}; + ALfloat Coeff[NUM_LINES][2]{}; /* The gain for each output channel based on 3D panning. */ - ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; - ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; + ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]{}; + ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]{}; } EarlyReflections; typedef struct LateReverb { /* A recursive delay line is used fill in the reverb tail. */ DelayLineI Delay; - ALsizei Offset[NUM_LINES][2]; + ALsizei Offset[NUM_LINES][2]{}; /* Attenuation to compensate for the modal density and decay rate of the * late lines. */ - ALfloat DensityGain[2]; + ALfloat DensityGain[2]{0.0f, 0.0f}; /* T60 decay filters are used to simulate absorption. */ T60Filter T60[NUM_LINES]; @@ -276,8 +276,8 @@ typedef struct LateReverb { VecAllpass VecAp; /* The gain for each output channel based on 3D panning. */ - ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; - ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; + ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]{}; + ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]{}; } LateReverb; struct ReverbState final : public EffectState { @@ -290,9 +290,13 @@ struct ReverbState final : public EffectState { /* Calculated parameters which indicate if cross-fading is needed after * an update. */ - ALfloat Density, Diffusion; - ALfloat DecayTime, HFDecayTime, LFDecayTime; - ALfloat HFReference, LFReference; + ALfloat Density{AL_EAXREVERB_DEFAULT_DENSITY}; + ALfloat Diffusion{AL_EAXREVERB_DEFAULT_DIFFUSION}; + ALfloat DecayTime{AL_EAXREVERB_DEFAULT_DECAY_TIME}; + ALfloat HFDecayTime{AL_EAXREVERB_DEFAULT_DECAY_HFRATIO * AL_EAXREVERB_DEFAULT_DECAY_TIME}; + ALfloat LFDecayTime{AL_EAXREVERB_DEFAULT_DECAY_LFRATIO * AL_EAXREVERB_DEFAULT_DECAY_TIME}; + ALfloat HFReference{AL_EAXREVERB_DEFAULT_HFREFERENCE}; + ALfloat LFReference{AL_EAXREVERB_DEFAULT_LFREFERENCE}; } mParams; /* Master effect filters */ @@ -305,37 +309,35 @@ struct ReverbState final : public EffectState { DelayLineI mDelay; /* Tap points for early reflection delay. */ - ALsizei mEarlyDelayTap[NUM_LINES][2]; - ALfloat mEarlyDelayCoeff[NUM_LINES][2]; + ALsizei mEarlyDelayTap[NUM_LINES][2]{}; + ALfloat mEarlyDelayCoeff[NUM_LINES][2]{}; /* Tap points for late reverb feed and delay. */ - ALsizei mLateFeedTap; - ALsizei mLateDelayTap[NUM_LINES][2]; + ALsizei mLateFeedTap{}; + ALsizei mLateDelayTap[NUM_LINES][2]{}; /* Coefficients for the all-pass and line scattering matrices. */ - ALfloat mMixX; - ALfloat mMixY; + ALfloat mMixX{0.0f}; + ALfloat mMixY{0.0f}; EarlyReflections mEarly; LateReverb mLate; /* Indicates the cross-fade point for delay line reads [0,FADE_SAMPLES]. */ - ALsizei mFadeCount; + ALsizei mFadeCount{0}; /* Maximum number of samples to process at once. */ - ALsizei mMaxUpdate[2]; + ALsizei mMaxUpdate[2]{MAX_UPDATE_SAMPLES, MAX_UPDATE_SAMPLES}; /* The current write offset for all delay lines. */ - ALsizei mOffset; + ALsizei mOffset{0}; /* Temporary storage used when processing. */ - alignas(16) ALfloat mTempSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; - alignas(16) ALfloat mMixBuffer[NUM_LINES][MAX_UPDATE_SAMPLES]; + alignas(16) ALfloat mTempSamples[NUM_LINES][MAX_UPDATE_SAMPLES]{}; + alignas(16) ALfloat mMixBuffer[NUM_LINES][MAX_UPDATE_SAMPLES]{}; - ReverbState(); - ALboolean deviceUpdate(ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; @@ -343,97 +345,6 @@ struct ReverbState final : public EffectState { DEF_NEWDEL(ReverbState) }; -ReverbState::ReverbState() -{ - mParams.Density = AL_EAXREVERB_DEFAULT_DENSITY; - mParams.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION; - mParams.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME; - mParams.HFDecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME*AL_EAXREVERB_DEFAULT_DECAY_HFRATIO; - mParams.LFDecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME*AL_EAXREVERB_DEFAULT_DECAY_LFRATIO; - mParams.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE; - mParams.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE; - - for(ALsizei i{0};i < NUM_LINES;i++) - { - BiquadFilter_clear(&mFilter[i].Lp); - BiquadFilter_clear(&mFilter[i].Hp); - } - - mDelay.Mask = 0; - mDelay.Line = NULL; - - for(ALsizei i{0};i < NUM_LINES;i++) - { - mEarlyDelayTap[i][0] = 0; - mEarlyDelayTap[i][1] = 0; - mEarlyDelayCoeff[i][0] = 0.0f; - mEarlyDelayCoeff[i][1] = 0.0f; - } - - mLateFeedTap = 0; - - for(ALsizei i{0};i < NUM_LINES;i++) - { - mLateDelayTap[i][0] = 0; - mLateDelayTap[i][1] = 0; - } - - mMixX = 0.0f; - mMixY = 0.0f; - - mEarly.VecAp.Delay.Mask = 0; - mEarly.VecAp.Delay.Line = NULL; - mEarly.VecAp.Coeff = 0.0f; - mEarly.Delay.Mask = 0; - mEarly.Delay.Line = NULL; - for(ALsizei i{0};i < NUM_LINES;i++) - { - mEarly.VecAp.Offset[i][0] = 0; - mEarly.VecAp.Offset[i][1] = 0; - mEarly.Offset[i][0] = 0; - mEarly.Offset[i][1] = 0; - mEarly.Coeff[i][0] = 0.0f; - mEarly.Coeff[i][1] = 0.0f; - } - - mLate.DensityGain[0] = 0.0f; - mLate.DensityGain[1] = 0.0f; - mLate.Delay.Mask = 0; - mLate.Delay.Line = NULL; - mLate.VecAp.Delay.Mask = 0; - mLate.VecAp.Delay.Line = NULL; - mLate.VecAp.Coeff = 0.0f; - for(ALsizei i{0};i < NUM_LINES;i++) - { - mLate.Offset[i][0] = 0; - mLate.Offset[i][1] = 0; - - mLate.VecAp.Offset[i][0] = 0; - mLate.VecAp.Offset[i][1] = 0; - - mLate.T60[i].MidGain[0] = 0.0f; - mLate.T60[i].MidGain[1] = 0.0f; - BiquadFilter_clear(&mLate.T60[i].HFFilter); - BiquadFilter_clear(&mLate.T60[i].LFFilter); - } - - for(ALsizei i{0};i < NUM_LINES;i++) - { - for(ALsizei j{0};j < MAX_OUTPUT_CHANNELS;j++) - { - mEarly.CurrentGain[i][j] = 0.0f; - mEarly.PanGain[i][j] = 0.0f; - mLate.CurrentGain[i][j] = 0.0f; - mLate.PanGain[i][j] = 0.0f; - } - } - - mFadeCount = 0; - mMaxUpdate[0] = MAX_UPDATE_SAMPLES; - mMaxUpdate[1] = MAX_UPDATE_SAMPLES; - mOffset = 0; -} - /************************************** * Device Update * **************************************/ -- cgit v1.2.3 From eb2937de8419dddc73952feef5119e6a6be2a93d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Nov 2018 23:48:45 -0800 Subject: Avoid another case of a variable named the same as a type --- Alc/alu.cpp | 10 +++++----- OpenAL32/Include/alAuxEffectSlot.h | 2 +- OpenAL32/alAuxEffectSlot.cpp | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 6a2f0c01..3150ec4f 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -413,7 +413,7 @@ static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool f state = props->State; - if(state == slot->Params.EffectState) + if(state == slot->Params.mEffectState) { /* If the effect state is the same as current, we can decrement its * count safely to remove it from the update object (it can't reach @@ -428,9 +428,9 @@ static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool f * event. */ AsyncEvent evt = ASYNC_EVENT(EventType_ReleaseEffectState); - evt.u.mEffectState = slot->Params.EffectState; + evt.u.mEffectState = slot->Params.mEffectState; - slot->Params.EffectState = state; + slot->Params.mEffectState = state; props->State = NULL; if(LIKELY(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) != 0)) @@ -449,7 +449,7 @@ static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool f AtomicReplaceHead(context->FreeEffectslotProps, props); } else - state = slot->Params.EffectState; + state = slot->Params.mEffectState; state->update(context, slot, &slot->Params.EffectProps); return true; @@ -1749,7 +1749,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) for(i = 0;i < auxslots->count;i++) { const ALeffectslot *slot = auxslots->slot[i]; - EffectState *state = slot->Params.EffectState; + EffectState *state = slot->Params.mEffectState; state->process(SamplesToDo, slot->WetBuffer, state->mOutBuffer, state->mOutChannels); } diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index ca2cb663..6e315e8f 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -81,7 +81,7 @@ struct ALeffectslot { ALenum EffectType{AL_EFFECT_NULL}; ALeffectProps EffectProps{}; - EffectState *EffectState{nullptr}; + EffectState *mEffectState{nullptr}; ALfloat RoomRolloff{0.0f}; /* Added to the source's room rolloff, not multiplied. */ ALfloat DecayTime{0.0f}; diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index cab9e43d..d4608bf1 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -650,7 +650,7 @@ ALenum InitEffectSlot(ALeffectslot *slot) if(!slot->Effect.State) return AL_OUT_OF_MEMORY; slot->Effect.State->IncRef(); - slot->Params.EffectState = slot->Effect.State; + slot->Params.mEffectState = slot->Effect.State; return AL_NO_ERROR; } @@ -666,8 +666,8 @@ ALeffectslot::~ALeffectslot() if(Effect.State) Effect.State->DecRef(); - if(Params.EffectState) - Params.EffectState->DecRef(); + if(Params.mEffectState) + Params.mEffectState->DecRef(); } void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) -- cgit v1.2.3 From 5881cd2183ac4aa954cae1daabf093f006eb0aa3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Nov 2018 02:01:03 -0800 Subject: Add compile-time traits for DevFmtType enum values --- OpenAL32/Include/alMain.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 8f08d94a..0770ee89 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -437,6 +437,26 @@ enum DevFmtChannels { }; #define MAX_OUTPUT_CHANNELS (16) +/* DevFmtType traits, providing the type, etc given a DevFmtType. */ +template +struct DevFmtTypeTraits { }; + +template<> +struct DevFmtTypeTraits { using Type = ALbyte; }; +template<> +struct DevFmtTypeTraits { using Type = ALubyte; }; +template<> +struct DevFmtTypeTraits { using Type = ALshort; }; +template<> +struct DevFmtTypeTraits { using Type = ALushort; }; +template<> +struct DevFmtTypeTraits { using Type = ALint; }; +template<> +struct DevFmtTypeTraits { using Type = ALuint; }; +template<> +struct DevFmtTypeTraits { using Type = ALfloat; }; + + ALsizei BytesFromDevFmt(enum DevFmtType type); ALsizei ChannelsFromDevFmt(enum DevFmtChannels chans, ALsizei ambiorder); inline ALsizei FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type, ALsizei ambiorder) -- cgit v1.2.3 From 457d48487277375a6441228b2d297f0c000e9349 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Nov 2018 02:12:04 -0800 Subject: Use C++ templates instead of macro-defined variations --- Alc/alu.cpp | 349 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 175 insertions(+), 174 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 3150ec4f..cc48a4bf 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -57,7 +57,9 @@ ALfloat ZScale = 1.0f; ALboolean OverrideReverbSpeedOfSound = AL_FALSE; -static void ClearArray(ALfloat f[MAX_OUTPUT_CHANNELS]) +namespace { + +void ClearArray(ALfloat f[MAX_OUTPUT_CHANNELS]) { size_t i; for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) @@ -70,16 +72,10 @@ struct ChanMap { ALfloat elevation; }; -static HrtfDirectMixerFunc MixDirectHrtf = MixDirectHrtf_C; - - -void DeinitVoice(ALvoice *voice) -{ - al_free(voice->Update.exchange(nullptr)); -} +HrtfDirectMixerFunc MixDirectHrtf = MixDirectHrtf_C; -static inline HrtfDirectMixerFunc SelectHrtfMixer(void) +inline HrtfDirectMixerFunc SelectHrtfMixer(void) { #ifdef HAVE_NEON if((CPUCapFlags&CPU_CAP_NEON)) @@ -93,64 +89,7 @@ static inline HrtfDirectMixerFunc SelectHrtfMixer(void) return MixDirectHrtf_C; } - -/* This RNG method was created based on the math found in opusdec. It's quick, - * and starting with a seed value of 22222, is suitable for generating - * whitenoise. - */ -static inline ALuint dither_rng(ALuint *seed) -{ - *seed = (*seed * 96314165) + 907633515; - return *seed; -} - - -static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector) -{ - outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1]; - outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2]; - outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0]; -} - -static inline ALfloat aluDotproduct(const aluVector *vec1, const aluVector *vec2) -{ - return vec1->v[0]*vec2->v[0] + vec1->v[1]*vec2->v[1] + vec1->v[2]*vec2->v[2]; -} - -static ALfloat aluNormalize(ALfloat *vec) -{ - ALfloat length = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); - if(length > FLT_EPSILON) - { - ALfloat inv_length = 1.0f/length; - vec[0] *= inv_length; - vec[1] *= inv_length; - vec[2] *= inv_length; - return length; - } - vec[0] = vec[1] = vec[2] = 0.0f; - return 0.0f; -} - -static void aluMatrixfFloat3(ALfloat *vec, ALfloat w, const aluMatrixf *mtx) -{ - ALfloat v[4] = { vec[0], vec[1], vec[2], w }; - - vec[0] = v[0]*mtx->m[0][0] + v[1]*mtx->m[1][0] + v[2]*mtx->m[2][0] + v[3]*mtx->m[3][0]; - vec[1] = v[0]*mtx->m[0][1] + v[1]*mtx->m[1][1] + v[2]*mtx->m[2][1] + v[3]*mtx->m[3][1]; - vec[2] = v[0]*mtx->m[0][2] + v[1]*mtx->m[1][2] + v[2]*mtx->m[2][2] + v[3]*mtx->m[3][2]; -} - -static aluVector aluMatrixfVector(const aluMatrixf *mtx, const aluVector *vec) -{ - aluVector v; - v.v[0] = vec->v[0]*mtx->m[0][0] + vec->v[1]*mtx->m[1][0] + vec->v[2]*mtx->m[2][0] + vec->v[3]*mtx->m[3][0]; - v.v[1] = vec->v[0]*mtx->m[0][1] + vec->v[1]*mtx->m[1][1] + vec->v[2]*mtx->m[2][1] + vec->v[3]*mtx->m[3][1]; - v.v[2] = vec->v[0]*mtx->m[0][2] + vec->v[1]*mtx->m[1][2] + vec->v[2]*mtx->m[2][2] + vec->v[3]*mtx->m[3][2]; - v.v[3] = vec->v[0]*mtx->m[0][3] + vec->v[1]*mtx->m[1][3] + vec->v[2]*mtx->m[2][3] + vec->v[3]*mtx->m[3][3]; - return v; -} - +} // namespace void aluInit(void) { @@ -158,40 +97,15 @@ void aluInit(void) } -static void SendSourceStoppedEvent(ALCcontext *context, ALuint id) +void DeinitVoice(ALvoice *voice) { - AsyncEvent evt = ASYNC_EVENT(EventType_SourceStateChange); - ALbitfieldSOFT enabledevt; - size_t strpos; - ALuint scale; - - enabledevt = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); - if(!(enabledevt&EventType_SourceStateChange)) return; - - evt.u.user.type = AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT; - evt.u.user.id = id; - evt.u.user.param = AL_STOPPED; - - /* Normally snprintf would be used, but this is called from the mixer and - * that function's not real-time safe, so we have to construct it manually. - */ - strcpy(evt.u.user.msg, "Source ID "); strpos = 10; - scale = 1000000000; - while(scale > 0 && scale > id) - scale /= 10; - while(scale > 0) - { - evt.u.user.msg[strpos++] = '0' + ((id/scale)%10); - scale /= 10; - } - strcpy(evt.u.user.msg+strpos, " state changed to AL_STOPPED"); - - if(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) == 1) - alsem_post(&context->EventSem); + al_free(voice->Update.exchange(nullptr)); } -static void ProcessHrtf(ALCdevice *device, ALsizei SamplesToDo) +namespace { + +void ProcessHrtf(ALCdevice *device, ALsizei SamplesToDo) { DirectHrtfState *state; int lidx, ridx; @@ -218,7 +132,7 @@ static void ProcessHrtf(ALCdevice *device, ALsizei SamplesToDo) state->Offset += SamplesToDo; } -static void ProcessAmbiDec(ALCdevice *device, ALsizei SamplesToDo) +void ProcessAmbiDec(ALCdevice *device, ALsizei SamplesToDo) { if(device->Dry.Buffer != device->FOAOut.Buffer) bformatdec_upSample(device->AmbiDecoder, @@ -231,7 +145,7 @@ static void ProcessAmbiDec(ALCdevice *device, ALsizei SamplesToDo) ); } -static void ProcessAmbiUp(ALCdevice *device, ALsizei SamplesToDo) +void ProcessAmbiUp(ALCdevice *device, ALsizei SamplesToDo) { ambiup_process(device->AmbiUp, device->RealOut.Buffer, device->RealOut.NumChannels, device->FOAOut.Buffer, @@ -239,7 +153,7 @@ static void ProcessAmbiUp(ALCdevice *device, ALsizei SamplesToDo) ); } -static void ProcessUhj(ALCdevice *device, ALsizei SamplesToDo) +void ProcessUhj(ALCdevice *device, ALsizei SamplesToDo) { int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); @@ -252,7 +166,7 @@ static void ProcessUhj(ALCdevice *device, ALsizei SamplesToDo) ); } -static void ProcessBs2b(ALCdevice *device, ALsizei SamplesToDo) +void ProcessBs2b(ALCdevice *device, ALsizei SamplesToDo) { int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); @@ -263,6 +177,8 @@ static void ProcessBs2b(ALCdevice *device, ALsizei SamplesToDo) device->RealOut.Buffer[ridx], SamplesToDo); } +} // namespace + void aluSelectPostProcess(ALCdevice *device) { if(device->HrtfHandle) @@ -310,7 +226,100 @@ void BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *t } -static bool CalcContextParams(ALCcontext *Context) +namespace { + +/* This RNG method was created based on the math found in opusdec. It's quick, + * and starting with a seed value of 22222, is suitable for generating + * whitenoise. + */ +inline ALuint dither_rng(ALuint *seed) +{ + *seed = (*seed * 96314165) + 907633515; + return *seed; +} + + +inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector) +{ + outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1]; + outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2]; + outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0]; +} + +inline ALfloat aluDotproduct(const aluVector *vec1, const aluVector *vec2) +{ + return vec1->v[0]*vec2->v[0] + vec1->v[1]*vec2->v[1] + vec1->v[2]*vec2->v[2]; +} + +ALfloat aluNormalize(ALfloat *vec) +{ + ALfloat length = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); + if(length > FLT_EPSILON) + { + ALfloat inv_length = 1.0f/length; + vec[0] *= inv_length; + vec[1] *= inv_length; + vec[2] *= inv_length; + return length; + } + vec[0] = vec[1] = vec[2] = 0.0f; + return 0.0f; +} + +void aluMatrixfFloat3(ALfloat *vec, ALfloat w, const aluMatrixf *mtx) +{ + ALfloat v[4] = { vec[0], vec[1], vec[2], w }; + + vec[0] = v[0]*mtx->m[0][0] + v[1]*mtx->m[1][0] + v[2]*mtx->m[2][0] + v[3]*mtx->m[3][0]; + vec[1] = v[0]*mtx->m[0][1] + v[1]*mtx->m[1][1] + v[2]*mtx->m[2][1] + v[3]*mtx->m[3][1]; + vec[2] = v[0]*mtx->m[0][2] + v[1]*mtx->m[1][2] + v[2]*mtx->m[2][2] + v[3]*mtx->m[3][2]; +} + +aluVector aluMatrixfVector(const aluMatrixf *mtx, const aluVector *vec) +{ + aluVector v; + v.v[0] = vec->v[0]*mtx->m[0][0] + vec->v[1]*mtx->m[1][0] + vec->v[2]*mtx->m[2][0] + vec->v[3]*mtx->m[3][0]; + v.v[1] = vec->v[0]*mtx->m[0][1] + vec->v[1]*mtx->m[1][1] + vec->v[2]*mtx->m[2][1] + vec->v[3]*mtx->m[3][1]; + v.v[2] = vec->v[0]*mtx->m[0][2] + vec->v[1]*mtx->m[1][2] + vec->v[2]*mtx->m[2][2] + vec->v[3]*mtx->m[3][2]; + v.v[3] = vec->v[0]*mtx->m[0][3] + vec->v[1]*mtx->m[1][3] + vec->v[2]*mtx->m[2][3] + vec->v[3]*mtx->m[3][3]; + return v; +} + + +void SendSourceStoppedEvent(ALCcontext *context, ALuint id) +{ + AsyncEvent evt = ASYNC_EVENT(EventType_SourceStateChange); + ALbitfieldSOFT enabledevt; + size_t strpos; + ALuint scale; + + enabledevt = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); + if(!(enabledevt&EventType_SourceStateChange)) return; + + evt.u.user.type = AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT; + evt.u.user.id = id; + evt.u.user.param = AL_STOPPED; + + /* Normally snprintf would be used, but this is called from the mixer and + * that function's not real-time safe, so we have to construct it manually. + */ + strcpy(evt.u.user.msg, "Source ID "); strpos = 10; + scale = 1000000000; + while(scale > 0 && scale > id) + scale /= 10; + while(scale > 0) + { + evt.u.user.msg[strpos++] = '0' + ((id/scale)%10); + scale /= 10; + } + strcpy(evt.u.user.msg+strpos, " state changed to AL_STOPPED"); + + if(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) == 1) + alsem_post(&context->EventSem); +} + + +bool CalcContextParams(ALCcontext *Context) { ALlistener &Listener = Context->Listener; struct ALcontextProps *props; @@ -333,7 +342,7 @@ static bool CalcContextParams(ALCcontext *Context) return true; } -static bool CalcListenerParams(ALCcontext *Context) +bool CalcListenerParams(ALCcontext *Context) { ALlistener &Listener = Context->Listener; ALfloat N[3], V[3], U[3], P[3]; @@ -378,7 +387,7 @@ static bool CalcListenerParams(ALCcontext *Context) return true; } -static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) +bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) { struct ALeffectslotProps *props; EffectState *state; @@ -456,7 +465,7 @@ static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool f } -static const struct ChanMap MonoMap[1] = { +constexpr struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f, 0.0f } }, RearMap[2] = { { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) }, @@ -492,14 +501,14 @@ static const struct ChanMap MonoMap[1] = { { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } }; -static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev, - const ALfloat Distance, const ALfloat Spread, - const ALfloat DryGain, const ALfloat DryGainHF, - const ALfloat DryGainLF, const ALfloat *WetGain, - const ALfloat *WetGainLF, const ALfloat *WetGainHF, - ALeffectslot **SendSlots, const ALbuffer *Buffer, - const struct ALvoiceProps *props, const ALlistener &Listener, - const ALCdevice *Device) +void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev, + const ALfloat Distance, const ALfloat Spread, + const ALfloat DryGain, const ALfloat DryGainHF, + const ALfloat DryGainLF, const ALfloat *WetGain, + const ALfloat *WetGainLF, const ALfloat *WetGainHF, + ALeffectslot **SendSlots, const ALbuffer *Buffer, + const struct ALvoiceProps *props, const ALlistener &Listener, + const ALCdevice *Device) { struct ChanMap StereoMap[2] = { { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, @@ -1016,7 +1025,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo } } -static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) +void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { const ALCdevice *Device = ALContext->Device; const ALlistener &Listener = ALContext->Listener; @@ -1079,7 +1088,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *p WetGainLF, WetGainHF, SendSlots, ALBuffer, props, Listener, Device); } -static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) +void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { const ALCdevice *Device = ALContext->Device; const ALlistener &Listener = ALContext->Listener; @@ -1447,7 +1456,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop WetGainLF, WetGainHF, SendSlots, ALBuffer, props, Listener, Device); } -static void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) +void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) { ALbufferlistitem *BufferListItem; struct ALvoiceProps *props; @@ -1486,7 +1495,7 @@ static void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) } -static void ProcessParamUpdates(ALCcontext *ctx, const struct ALeffectslotArray *slots) +void ProcessParamUpdates(ALCcontext *ctx, const struct ALeffectslotArray *slots) { ALvoice **voice, **voice_end; ALsource *source; @@ -1512,9 +1521,8 @@ static void ProcessParamUpdates(ALCcontext *ctx, const struct ALeffectslotArray } -static void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*RESTRICT Buffer)[BUFFERSIZE], - int lidx, int ridx, int cidx, ALsizei SamplesToDo, - ALsizei NumChannels) +void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*RESTRICT Buffer)[BUFFERSIZE], + int lidx, int ridx, int cidx, ALsizei SamplesToDo, ALsizei NumChannels) { ALfloat (*RESTRICT lsplit)[BUFFERSIZE] = Stablizer->LSplit; ALfloat (*RESTRICT rsplit)[BUFFERSIZE] = Stablizer->RSplit; @@ -1560,8 +1568,8 @@ static void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*RESTRICT Buffer) } } -static void ApplyDistanceComp(ALfloat (*RESTRICT Samples)[BUFFERSIZE], DistanceComp *distcomp, - ALfloat *RESTRICT Values, ALsizei SamplesToDo, ALsizei numchans) +void ApplyDistanceComp(ALfloat (*RESTRICT Samples)[BUFFERSIZE], DistanceComp *distcomp, + ALfloat *RESTRICT Values, ALsizei SamplesToDo, ALsizei numchans) { ALsizei i, c; @@ -1602,9 +1610,8 @@ static void ApplyDistanceComp(ALfloat (*RESTRICT Samples)[BUFFERSIZE], DistanceC } } -static void ApplyDither(ALfloat (*RESTRICT Samples)[BUFFERSIZE], ALuint *dither_seed, - const ALfloat quant_scale, const ALsizei SamplesToDo, - const ALsizei numchans) +void ApplyDither(ALfloat (*RESTRICT Samples)[BUFFERSIZE], ALuint *dither_seed, + const ALfloat quant_scale, const ALsizei SamplesToDo, const ALsizei numchans) { const ALfloat invscale = 1.0f / quant_scale; ALuint seed = *dither_seed; @@ -1633,9 +1640,15 @@ static void ApplyDither(ALfloat (*RESTRICT Samples)[BUFFERSIZE], ALuint *dither_ } -static inline ALfloat Conv_ALfloat(ALfloat val) +/* Base template left undefined. Should be marked =delete, but Clang 3.8.1 + * chokes on that given the inline specializations. + */ +template +inline T SampleConv(ALfloat); + +template<> inline ALfloat SampleConv(ALfloat val) { return val; } -static inline ALint Conv_ALint(ALfloat val) +template<> inline ALint SampleConv(ALfloat val) { /* Floats have a 23-bit mantissa. There is an implied 1 bit in the mantissa * along with the sign bit, giving 25 bits total, so [-16777216, +16777216] @@ -1644,51 +1657,39 @@ static inline ALint Conv_ALint(ALfloat val) */ return fastf2i(clampf(val*16777216.0f, -16777216.0f, 16777215.0f))<<7; } -static inline ALshort Conv_ALshort(ALfloat val) +template<> inline ALshort SampleConv(ALfloat val) { return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); } -static inline ALbyte Conv_ALbyte(ALfloat val) +template<> inline ALbyte SampleConv(ALfloat val) { return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); } /* Define unsigned output variations. */ -#define DECL_TEMPLATE(T, func, O) \ -static inline T Conv_##T(ALfloat val) { return func(val)+O; } - -DECL_TEMPLATE(ALubyte, Conv_ALbyte, 128) -DECL_TEMPLATE(ALushort, Conv_ALshort, 32768) -DECL_TEMPLATE(ALuint, Conv_ALint, 2147483648u) - -#undef DECL_TEMPLATE - -#define DECL_TEMPLATE(T, A) \ -static void Write##A(const ALfloat (*RESTRICT InBuffer)[BUFFERSIZE], \ - ALvoid *OutBuffer, ALsizei Offset, ALsizei SamplesToDo, \ - ALsizei numchans) \ -{ \ - ALsizei i, j; \ - \ - ASSUME(numchans > 0); \ - ASSUME(SamplesToDo > 0); \ - \ - for(j = 0;j < numchans;j++) \ - { \ - const ALfloat *RESTRICT in = InBuffer[j]; \ - T *RESTRICT out = (T*)OutBuffer + Offset*numchans + j; \ - \ - for(i = 0;i < SamplesToDo;i++) \ - out[i*numchans] = Conv_##T(in[i]); \ - } \ -} +template<> inline ALuint SampleConv(ALfloat val) +{ return SampleConv(val) + 2147483648u; } +template<> inline ALushort SampleConv(ALfloat val) +{ return SampleConv(val) + 32768; } +template<> inline ALubyte SampleConv(ALfloat val) +{ return SampleConv(val) + 128; } + +template +void Write(const ALfloat (*RESTRICT InBuffer)[BUFFERSIZE], ALvoid *OutBuffer, + ALsizei Offset, ALsizei SamplesToDo, ALsizei numchans) +{ + using SampleType = typename DevFmtTypeTraits::Type; -DECL_TEMPLATE(ALfloat, F32) -DECL_TEMPLATE(ALuint, UI32) -DECL_TEMPLATE(ALint, I32) -DECL_TEMPLATE(ALushort, UI16) -DECL_TEMPLATE(ALshort, I16) -DECL_TEMPLATE(ALubyte, UI8) -DECL_TEMPLATE(ALbyte, I8) + ASSUME(numchans > 0); + ASSUME(SamplesToDo > 0); + + for(ALsizei j{0};j < numchans;j++) + { + const ALfloat *RESTRICT in = InBuffer[j]; + SampleType *RESTRICT out = static_cast(OutBuffer) + Offset*numchans + j; -#undef DECL_TEMPLATE + for(ALsizei i{0};i < SamplesToDo;i++) + out[i*numchans] = SampleConv(in[i]); + } +} +} // namespace void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) { @@ -1800,15 +1801,15 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) switch(device->FmtType) { -#define HANDLE_WRITE(T, S) case T: \ - Write##S(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); break; - HANDLE_WRITE(DevFmtByte, I8) - HANDLE_WRITE(DevFmtUByte, UI8) - HANDLE_WRITE(DevFmtShort, I16) - HANDLE_WRITE(DevFmtUShort, UI16) - HANDLE_WRITE(DevFmtInt, I32) - HANDLE_WRITE(DevFmtUInt, UI32) - HANDLE_WRITE(DevFmtFloat, F32) +#define HANDLE_WRITE(T) case T: \ + Write(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); break; + HANDLE_WRITE(DevFmtByte) + HANDLE_WRITE(DevFmtUByte) + HANDLE_WRITE(DevFmtShort) + HANDLE_WRITE(DevFmtUShort) + HANDLE_WRITE(DevFmtInt) + HANDLE_WRITE(DevFmtUInt) + HANDLE_WRITE(DevFmtFloat) #undef HANDLE_WRITE } } -- cgit v1.2.3 From 16d0e79db7a5e99a9859cfaacb718dfae862cb2a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Nov 2018 02:42:49 -0800 Subject: Add compile-time traits for FmtType enum values --- OpenAL32/Include/alBuffer.h | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index f264caa5..a99c06fc 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -8,9 +8,6 @@ #include "inprogext.h" #include "atomic.h" -#ifdef __cplusplus -extern "C" { -#endif /* User formats */ enum UserFmtType { @@ -65,6 +62,24 @@ enum FmtChannels { }; #define MAX_INPUT_CHANNELS (8) +/* DevFmtType traits, providing the type, etc given a DevFmtType. */ +template +struct FmtTypeTraits { }; + +template<> +struct FmtTypeTraits { using Type = ALubyte; }; +template<> +struct FmtTypeTraits { using Type = ALshort; }; +template<> +struct FmtTypeTraits { using Type = ALfloat; }; +template<> +struct FmtTypeTraits { using Type = ALdouble; }; +template<> +struct FmtTypeTraits { using Type = ALubyte; }; +template<> +struct FmtTypeTraits { using Type = ALubyte; }; + + ALsizei BytesFromFmt(enum FmtType type); ALsizei ChannelsFromFmt(enum FmtChannels chans); inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type) @@ -107,8 +122,4 @@ typedef struct ALbuffer { ALvoid ReleaseALBuffers(ALCdevice *device); -#ifdef __cplusplus -} -#endif - #endif -- cgit v1.2.3 From c7472f8642454830caf69bc163b0cfac61603d15 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Nov 2018 02:59:02 -0800 Subject: Use C++ templates instead of macro definitions more --- Alc/mixvoice.cpp | 75 +++++++++++++++++++++++++------------------------------- 1 file changed, 34 insertions(+), 41 deletions(-) diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index c83fb8a7..50c9c735 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -193,6 +193,8 @@ void aluInitMixer(void) } +namespace { + static void SendAsyncEvent(ALCcontext *context, ALuint enumtype, ALenum type, ALuint objid, ALuint param, const char *msg) { @@ -206,66 +208,56 @@ static void SendAsyncEvent(ALCcontext *context, ALuint enumtype, ALenum type, } -static inline ALfloat Sample_ALubyte(ALubyte val) -{ return (val-128) * (1.0f/128.0f); } +/* Base template left undefined. Should be marked =delete, but Clang 3.8.1 + * chokes on that given the inline specializations. + */ +template +inline ALfloat LoadSample(typename FmtTypeTraits::Type val); -static inline ALfloat Sample_ALshort(ALshort val) +template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) +{ return (val-128) * (1.0f/128.0f); } +template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) { return val * (1.0f/32768.0f); } - -static inline ALfloat Sample_ALfloat(ALfloat val) +template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) { return val; } - -static inline ALfloat Sample_ALdouble(ALdouble val) +template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) { return (ALfloat)val; } - -typedef ALubyte ALmulaw; -static inline ALfloat Sample_ALmulaw(ALmulaw val) +template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) { return muLawDecompressionTable[val] * (1.0f/32768.0f); } - -typedef ALubyte ALalaw; -static inline ALfloat Sample_ALalaw(ALalaw val) +template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) { return aLawDecompressionTable[val] * (1.0f/32768.0f); } -#define DECL_TEMPLATE(T) \ -static inline void Load_##T(ALfloat *RESTRICT dst, const T *RESTRICT src, \ - ALint srcstep, ALsizei samples) \ -{ \ - ALsizei i; \ - for(i = 0;i < samples;i++) \ - dst[i] += Sample_##T(src[i*srcstep]); \ -} - -DECL_TEMPLATE(ALubyte) -DECL_TEMPLATE(ALshort) -DECL_TEMPLATE(ALfloat) -DECL_TEMPLATE(ALdouble) -DECL_TEMPLATE(ALmulaw) -DECL_TEMPLATE(ALalaw) +template +inline void LoadSampleArray(ALfloat *RESTRICT dst, const void *src, ALint srcstep, ALsizei samples) +{ + using SampleType = typename FmtTypeTraits::Type; -#undef DECL_TEMPLATE + const SampleType *ssrc = static_cast(src); + for(ALsizei i{0};i < samples;i++) + dst[i] += LoadSample(ssrc[i*srcstep]); +} static void LoadSamples(ALfloat *RESTRICT dst, const ALvoid *RESTRICT src, ALint srcstep, enum FmtType srctype, ALsizei samples) { -#define HANDLE_FMT(ET, ST) \ - case ET: Load_##ST(dst, static_cast(src), srcstep, samples); \ - break +#define HANDLE_FMT(T) \ + case T: LoadSampleArray(dst, src, srcstep, samples); break switch(srctype) { - HANDLE_FMT(FmtUByte, ALubyte); - HANDLE_FMT(FmtShort, ALshort); - HANDLE_FMT(FmtFloat, ALfloat); - HANDLE_FMT(FmtDouble, ALdouble); - HANDLE_FMT(FmtMulaw, ALmulaw); - HANDLE_FMT(FmtAlaw, ALalaw); + HANDLE_FMT(FmtUByte); + HANDLE_FMT(FmtShort); + HANDLE_FMT(FmtFloat); + HANDLE_FMT(FmtDouble); + HANDLE_FMT(FmtMulaw); + HANDLE_FMT(FmtAlaw); } #undef HANDLE_FMT } -static const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, - ALfloat *RESTRICT dst, const ALfloat *RESTRICT src, - ALsizei numsamples, int type) +const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, + ALfloat *RESTRICT dst, const ALfloat *RESTRICT src, + ALsizei numsamples, int type) { ALsizei i; switch(type) @@ -299,6 +291,7 @@ static const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, return src; } +} // namespace /* This function uses these device temp buffers. */ #define SOURCE_DATA_BUF 0 -- cgit v1.2.3 From 66fdd027d027058792d56da741a7660d8646c9df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Nov 2018 03:35:41 -0800 Subject: Use more C++ templates instead of DECL_TEMPLATE tricks --- Alc/converter.cpp | 347 +++++++++++++++++++++++------------------------------- 1 file changed, 145 insertions(+), 202 deletions(-) diff --git a/Alc/converter.cpp b/Alc/converter.cpp index 5858c370..d64bc328 100644 --- a/Alc/converter.cpp +++ b/Alc/converter.cpp @@ -7,6 +7,133 @@ #include "mixer/defs.h" +namespace { + +/* Base template left undefined. Should be marked =delete, but Clang 3.8.1 + * chokes on that given the inline specializations. + */ +template +inline ALfloat LoadSample(typename DevFmtTypeTraits::Type val); + +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) +{ return val * (1.0f/128.0f); } +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) +{ return val * (1.0f/32768.0f); } +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) +{ return (val>>7) * (1.0f/16777216.0f); } +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) +{ return val; } + +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) +{ return LoadSample(val - 128); } +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) +{ return LoadSample(val - 32768); } +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) +{ return LoadSample(val - 2147483648u); } + + +template +inline void LoadSampleArray(ALfloat *RESTRICT dst, const void *src, ALint srcstep, ALsizei samples) +{ + using SampleType = typename DevFmtTypeTraits::Type; + + const SampleType *ssrc = static_cast(src); + for(ALsizei i{0};i < samples;i++) + dst[i] = LoadSample(ssrc[i*srcstep]); +} + +void LoadSamples(ALfloat *dst, const ALvoid *src, ALint srcstep, enum DevFmtType srctype, + ALsizei samples) +{ +#define HANDLE_FMT(T) \ + case T: LoadSampleArray(dst, src, srcstep, samples); break + switch(srctype) + { + HANDLE_FMT(DevFmtByte); + HANDLE_FMT(DevFmtUByte); + HANDLE_FMT(DevFmtShort); + HANDLE_FMT(DevFmtUShort); + HANDLE_FMT(DevFmtInt); + HANDLE_FMT(DevFmtUInt); + HANDLE_FMT(DevFmtFloat); + } +#undef HANDLE_FMT +} + + +template +inline typename DevFmtTypeTraits::Type StoreSample(ALfloat); + +template<> inline ALfloat StoreSample(ALfloat val) +{ return val; } +template<> inline ALint StoreSample(ALfloat val) +{ return fastf2i(clampf(val*16777216.0f, -16777216.0f, 16777215.0f))<<7; } +template<> inline ALshort StoreSample(ALfloat val) +{ return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); } +template<> inline ALbyte StoreSample(ALfloat val) +{ return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); } + +/* Define unsigned output variations. */ +template<> inline ALuint StoreSample(ALfloat val) +{ return StoreSample(val) + 2147483648u; } +template<> inline ALushort StoreSample(ALfloat val) +{ return StoreSample(val) + 32768; } +template<> inline ALubyte StoreSample(ALfloat val) +{ return StoreSample(val) + 128; } + +template +inline void StoreSampleArray(void *dst, const ALfloat *RESTRICT src, ALint dststep, + ALsizei samples) +{ + using SampleType = typename DevFmtTypeTraits::Type; + + SampleType *sdst = static_cast(dst); + for(ALsizei i{0};i < samples;i++) + sdst[i*dststep] = StoreSample(src[i]); +} + + +void StoreSamples(ALvoid *dst, const ALfloat *src, ALint dststep, enum DevFmtType dsttype, ALsizei samples) +{ +#define HANDLE_FMT(T) \ + case T: StoreSampleArray(dst, src, dststep, samples); break + switch(dsttype) + { + HANDLE_FMT(DevFmtByte); + HANDLE_FMT(DevFmtUByte); + HANDLE_FMT(DevFmtShort); + HANDLE_FMT(DevFmtUShort); + HANDLE_FMT(DevFmtInt); + HANDLE_FMT(DevFmtUInt); + HANDLE_FMT(DevFmtFloat); + } +#undef HANDLE_FMT +} + + +template +void Mono2Stereo(ALfloat *RESTRICT dst, const void *src, ALsizei frames) +{ + using SampleType = typename DevFmtTypeTraits::Type; + + const SampleType *ssrc = static_cast(src); + for(ALsizei i{0};i < frames;i++) + dst[i*2 + 1] = dst[i*2 + 0] = LoadSample(ssrc[i]) * 0.707106781187f; +} + +template +void Stereo2Mono(ALfloat *RESTRICT dst, const void *src, ALsizei frames) +{ + using SampleType = typename DevFmtTypeTraits::Type; + + const SampleType *ssrc = static_cast(src); + for(ALsizei i{0};i < frames;i++) + dst[i] = (LoadSample(ssrc[i*2 + 0])+LoadSample(ssrc[i*2 + 1])) * + 0.707106781187f; +} + +} // namespace + SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, ALsizei numchans, ALsizei srcRate, ALsizei dstRate) { SampleConverter *converter; @@ -54,138 +181,6 @@ void DestroySampleConverter(SampleConverter **converter) } -static inline ALfloat Sample_ALbyte(ALbyte val) -{ return val * (1.0f/128.0f); } -static inline ALfloat Sample_ALubyte(ALubyte val) -{ return Sample_ALbyte((ALint)val - 128); } - -static inline ALfloat Sample_ALshort(ALshort val) -{ return val * (1.0f/32768.0f); } -static inline ALfloat Sample_ALushort(ALushort val) -{ return Sample_ALshort((ALint)val - 32768); } - -static inline ALfloat Sample_ALint(ALint val) -{ return (val>>7) * (1.0f/16777216.0f); } -static inline ALfloat Sample_ALuint(ALuint val) -{ return Sample_ALint(val - INT_MAX - 1); } - -static inline ALfloat Sample_ALfloat(ALfloat val) -{ return val; } - -#define DECL_TEMPLATE(T) \ -static inline void Load_##T(ALfloat *RESTRICT dst, const T *RESTRICT src, \ - ALint srcstep, ALsizei samples) \ -{ \ - ALsizei i; \ - for(i = 0;i < samples;i++) \ - dst[i] = Sample_##T(src[i*srcstep]); \ -} - -DECL_TEMPLATE(ALbyte) -DECL_TEMPLATE(ALubyte) -DECL_TEMPLATE(ALshort) -DECL_TEMPLATE(ALushort) -DECL_TEMPLATE(ALint) -DECL_TEMPLATE(ALuint) -DECL_TEMPLATE(ALfloat) - -#undef DECL_TEMPLATE - -static void LoadSamples(ALfloat *dst, const ALvoid *src, ALint srcstep, enum DevFmtType srctype, ALsizei samples) -{ - switch(srctype) - { - case DevFmtByte: - Load_ALbyte(dst, static_cast(src), srcstep, samples); - break; - case DevFmtUByte: - Load_ALubyte(dst, static_cast(src), srcstep, samples); - break; - case DevFmtShort: - Load_ALshort(dst, static_cast(src), srcstep, samples); - break; - case DevFmtUShort: - Load_ALushort(dst, static_cast(src), srcstep, samples); - break; - case DevFmtInt: - Load_ALint(dst, static_cast(src), srcstep, samples); - break; - case DevFmtUInt: - Load_ALuint(dst, static_cast(src), srcstep, samples); - break; - case DevFmtFloat: - Load_ALfloat(dst, static_cast(src), srcstep, samples); - break; - } -} - - -static inline ALbyte ALbyte_Sample(ALfloat val) -{ return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); } -static inline ALubyte ALubyte_Sample(ALfloat val) -{ return ALbyte_Sample(val)+128; } - -static inline ALshort ALshort_Sample(ALfloat val) -{ return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); } -static inline ALushort ALushort_Sample(ALfloat val) -{ return ALshort_Sample(val)+32768; } - -static inline ALint ALint_Sample(ALfloat val) -{ return fastf2i(clampf(val*16777216.0f, -16777216.0f, 16777215.0f)) << 7; } -static inline ALuint ALuint_Sample(ALfloat val) -{ return ALint_Sample(val)+INT_MAX+1; } - -static inline ALfloat ALfloat_Sample(ALfloat val) -{ return val; } - -#define DECL_TEMPLATE(T) \ -static inline void Store_##T(T *RESTRICT dst, const ALfloat *RESTRICT src, \ - ALint dststep, ALsizei samples) \ -{ \ - ALsizei i; \ - for(i = 0;i < samples;i++) \ - dst[i*dststep] = T##_Sample(src[i]); \ -} - -DECL_TEMPLATE(ALbyte) -DECL_TEMPLATE(ALubyte) -DECL_TEMPLATE(ALshort) -DECL_TEMPLATE(ALushort) -DECL_TEMPLATE(ALint) -DECL_TEMPLATE(ALuint) -DECL_TEMPLATE(ALfloat) - -#undef DECL_TEMPLATE - -static void StoreSamples(ALvoid *dst, const ALfloat *src, ALint dststep, enum DevFmtType dsttype, ALsizei samples) -{ - switch(dsttype) - { - case DevFmtByte: - Store_ALbyte(static_cast(dst), src, dststep, samples); - break; - case DevFmtUByte: - Store_ALubyte(static_cast(dst), src, dststep, samples); - break; - case DevFmtShort: - Store_ALshort(static_cast(dst), src, dststep, samples); - break; - case DevFmtUShort: - Store_ALushort(static_cast(dst), src, dststep, samples); - break; - case DevFmtInt: - Store_ALint(static_cast(dst), src, dststep, samples); - break; - case DevFmtUInt: - Store_ALuint(static_cast(dst), src, dststep, samples); - break; - case DevFmtFloat: - Store_ALfloat(static_cast(dst), src, dststep, samples); - break; - } -} - - ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframes) { ALint prepcount = converter->mSrcPrepCount; @@ -225,7 +220,6 @@ ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframe return (ALsizei)clampu64((DataSize64 + increment-1)/increment, 1, BUFFERSIZE); } - ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes) { const ALsizei SrcFrameSize = converter->mNumChannels * converter->mSrcTypeSize; @@ -376,33 +370,6 @@ void DestroyChannelConverter(ChannelConverter **converter) } } - -#define DECL_TEMPLATE(T) \ -static void Mono2Stereo##T(ALfloat *RESTRICT dst, const T *src, ALsizei frames)\ -{ \ - ALsizei i; \ - for(i = 0;i < frames;i++) \ - dst[i*2 + 1] = dst[i*2 + 0] = Sample_##T(src[i]) * 0.707106781187f; \ -} \ - \ -static void Stereo2Mono##T(ALfloat *RESTRICT dst, const T *src, ALsizei frames)\ -{ \ - ALsizei i; \ - for(i = 0;i < frames;i++) \ - dst[i] = (Sample_##T(src[i*2 + 0])+Sample_##T(src[i*2 + 1])) * \ - 0.707106781187f; \ -} - -DECL_TEMPLATE(ALbyte) -DECL_TEMPLATE(ALubyte) -DECL_TEMPLATE(ALshort) -DECL_TEMPLATE(ALushort) -DECL_TEMPLATE(ALint) -DECL_TEMPLATE(ALuint) -DECL_TEMPLATE(ALfloat) - -#undef DECL_TEMPLATE - void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALfloat *dst, ALsizei frames) { if(converter->mSrcChans == converter->mDstChans) @@ -416,54 +383,30 @@ void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALflo { switch(converter->mSrcType) { - case DevFmtByte: - Stereo2MonoALbyte(dst, static_cast(src), frames); - break; - case DevFmtUByte: - Stereo2MonoALubyte(dst, static_cast(src), frames); - break; - case DevFmtShort: - Stereo2MonoALshort(dst, static_cast(src), frames); - break; - case DevFmtUShort: - Stereo2MonoALushort(dst, static_cast(src), frames); - break; - case DevFmtInt: - Stereo2MonoALint(dst, static_cast(src), frames); - break; - case DevFmtUInt: - Stereo2MonoALuint(dst, static_cast(src), frames); - break; - case DevFmtFloat: - Stereo2MonoALfloat(dst, static_cast(src), frames); - break; +#define HANDLE_FMT(T) case T: Stereo2Mono(dst, src, frames); break + HANDLE_FMT(DevFmtByte); + HANDLE_FMT(DevFmtUByte); + HANDLE_FMT(DevFmtShort); + HANDLE_FMT(DevFmtUShort); + HANDLE_FMT(DevFmtInt); + HANDLE_FMT(DevFmtUInt); + HANDLE_FMT(DevFmtFloat); +#undef HANDLE_FMT } } else /*if(converter->mSrcChans == DevFmtMono && converter->mDstChans == DevFmtStereo)*/ { switch(converter->mSrcType) { - case DevFmtByte: - Mono2StereoALbyte(dst, static_cast(src), frames); - break; - case DevFmtUByte: - Mono2StereoALubyte(dst, static_cast(src), frames); - break; - case DevFmtShort: - Mono2StereoALshort(dst, static_cast(src), frames); - break; - case DevFmtUShort: - Mono2StereoALushort(dst, static_cast(src), frames); - break; - case DevFmtInt: - Mono2StereoALint(dst, static_cast(src), frames); - break; - case DevFmtUInt: - Mono2StereoALuint(dst, static_cast(src), frames); - break; - case DevFmtFloat: - Mono2StereoALfloat(dst, static_cast(src), frames); - break; +#define HANDLE_FMT(T) case T: Mono2Stereo(dst, src, frames); break + HANDLE_FMT(DevFmtByte); + HANDLE_FMT(DevFmtUByte); + HANDLE_FMT(DevFmtShort); + HANDLE_FMT(DevFmtUShort); + HANDLE_FMT(DevFmtInt); + HANDLE_FMT(DevFmtUInt); + HANDLE_FMT(DevFmtFloat); +#undef HANDLE_FMT } } } -- cgit v1.2.3 From 1df42c4a0f988c2736e9d2d2929d0f23ad2538be Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Nov 2018 05:01:08 -0800 Subject: Use a unique_ptr for the default effect slot --- Alc/alc.cpp | 24 +++++++++++++----------- Alc/alcontext.h | 5 +++-- Alc/alu.cpp | 4 ++-- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 56a581fd..3247e14c 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2255,7 +2255,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(context->DefaultSlot) { - ALeffectslot *slot = context->DefaultSlot; + ALeffectslot *slot = context->DefaultSlot.get(); EffectState *state = slot->Effect.State; state->mOutBuffer = device->Dry.Buffer; @@ -2497,6 +2497,11 @@ static ALCboolean VerifyDevice(ALCdevice **device) } +ALCcontext_struct::ALCcontext_struct(ALCdevice *device) + : Device{device} +{ +} + /* InitContext * * Initializes context fields @@ -2516,7 +2521,7 @@ static ALvoid InitContext(ALCcontext *Context) auxslots = static_cast(al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, 1))); auxslots->count = 1; - auxslots->slot[0] = Context->DefaultSlot; + auxslots->slot[0] = Context->DefaultSlot.get(); } else { @@ -2584,10 +2589,8 @@ ALCcontext_struct::~ALCcontext_struct() } TRACE("Freed " SZFMT " context property object%s\n", count, (count==1)?"":"s"); - delete DefaultSlot; - DefaultSlot = nullptr; - al_free(ActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed)); + DefaultSlot = nullptr; ReleaseALSources(this); std::for_each(SourceList.begin(), SourceList.end(), @@ -3675,12 +3678,11 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin if(DefaultEffect.type != AL_EFFECT_NULL && device->Type == Playback) { - ALContext->DefaultSlot = new ALeffectslot{}; - if(InitEffectSlot(ALContext->DefaultSlot) == AL_NO_ERROR) - aluInitEffectPanning(ALContext->DefaultSlot); + ALContext->DefaultSlot.reset(new ALeffectslot{}); + if(InitEffectSlot(ALContext->DefaultSlot.get()) == AL_NO_ERROR) + aluInitEffectPanning(ALContext->DefaultSlot.get()); else { - delete ALContext->DefaultSlot; ALContext->DefaultSlot = nullptr; ERR("Failed to initialize the default effect slot\n"); } @@ -3713,8 +3715,8 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin if(ALContext->DefaultSlot) { - if(InitializeEffect(ALContext, ALContext->DefaultSlot, &DefaultEffect) == AL_NO_ERROR) - UpdateEffectSlotProps(ALContext->DefaultSlot, ALContext); + if(InitializeEffect(ALContext, ALContext->DefaultSlot.get(), &DefaultEffect) == AL_NO_ERROR) + UpdateEffectSlotProps(ALContext->DefaultSlot.get(), ALContext); else ERR("Failed to initialize the default effect\n"); } diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 5eec2e96..f174f324 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -1,6 +1,7 @@ #ifndef ALCONTEXT_H #define ALCONTEXT_H +#include #include #include "AL/al.h" @@ -106,7 +107,7 @@ struct ALCcontext_struct { void *EventParam{nullptr}; /* Default effect slot */ - ALeffectslot *DefaultSlot{nullptr}; + std::unique_ptr DefaultSlot; ALCdevice *const Device; const ALCchar *ExtensionList{nullptr}; @@ -116,7 +117,7 @@ struct ALCcontext_struct { ALlistener Listener{}; - ALCcontext_struct(ALCdevice *device) : Device{device} { } + ALCcontext_struct(ALCdevice *device); ALCcontext_struct(const ALCcontext_struct&) = delete; ALCcontext_struct& operator=(const ALCcontext_struct&) = delete; ~ALCcontext_struct(); diff --git a/Alc/alu.cpp b/Alc/alu.cpp index cc48a4bf..68387f7b 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1043,7 +1043,7 @@ void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, c { SendSlots[i] = props->Send[i].Slot; if(!SendSlots[i] && i == 0) - SendSlots[i] = ALContext->DefaultSlot; + SendSlots[i] = ALContext->DefaultSlot.get(); if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) { SendSlots[i] = NULL; @@ -1117,7 +1117,7 @@ void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, cons { SendSlots[i] = props->Send[i].Slot; if(!SendSlots[i] && i == 0) - SendSlots[i] = ALContext->DefaultSlot; + SendSlots[i] = ALContext->DefaultSlot.get(); if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) { SendSlots[i] = NULL; -- cgit v1.2.3 From 29558c091b55e54770869deb13483fa0b8e35e12 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Nov 2018 09:47:49 -0800 Subject: Use C++ more in alAuxEffectSlot.cpp --- OpenAL32/alAuxEffectSlot.cpp | 628 +++++++++++++++++++------------------------ 1 file changed, 279 insertions(+), 349 deletions(-) diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index d4608bf1..cce3e5d8 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -39,12 +39,110 @@ #include "almalloc.h" -static void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context); -static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context); +namespace { -static const struct { +inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept +{ + --id; + if(UNLIKELY(id >= context->EffectSlotList.size())) + return nullptr; + return context->EffectSlotList[id]; +} + +inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) noexcept +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= device->EffectList.size())) + return nullptr; + EffectSubList &sublist = device->EffectList[lidx]; + if(UNLIKELY(sublist.FreeMask & (U64(1)<ActiveAuxSlots.load(std::memory_order_acquire)}; + ALsizei newcount{curarray->count + count}; + + /* Insert the new effect slots into the head of the array, followed by the + * existing ones. + */ + auto newarray = static_cast(al_calloc(DEF_ALIGN, + FAM_SIZE(ALeffectslotArray, slot, newcount))); + newarray->count = newcount; + auto slotiter = std::transform(slotids, slotids+count, newarray->slot, + [context](ALuint id) noexcept -> ALeffectslot* + { return LookupEffectSlot(context, id); } + ); + std::copy_n(curarray->slot, curarray->count, slotiter); + + /* Remove any duplicates (first instance of each will be kept). */ + ALeffectslot **last = newarray->slot + newarray->count; + for(ALeffectslot **start=newarray->slot+1;;) + { + last = std::remove(start, last, *(start-1)); + if(start == last) break; + ++start; + } + newcount = std::distance(newarray->slot, last); + + /* Reallocate newarray if the new size ended up smaller from duplicate + * removal. + */ + if(UNLIKELY(newcount < newarray->count)) + { + curarray = newarray; + newarray = static_cast(al_calloc(DEF_ALIGN, + FAM_SIZE(ALeffectslotArray, slot, newcount))); + newarray->count = newcount; + std::copy_n(curarray->slot, newcount, newarray->slot); + al_free(curarray); + curarray = nullptr; + } + + curarray = context->ActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); + ALCdevice *device{context->Device}; + while((device->MixCount.load(std::memory_order_acquire)&1)) + althrd_yield(); + al_free(curarray); +} + +void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) +{ + if(count < 1) return; + ALeffectslotArray *curarray{context->ActiveAuxSlots.load(std::memory_order_acquire)}; + + /* Don't shrink the allocated array size since we don't know how many (if + * any) of the effect slots to remove are in the array. + */ + auto newarray = static_cast(al_calloc(DEF_ALIGN, + FAM_SIZE(ALeffectslotArray, slot, curarray->count))); + + /* Copy each element in curarray to newarray whose ID is not in slotids. */ + const ALuint *slotids_end{slotids + count}; + auto slotiter = std::copy_if(curarray->slot, curarray->slot+curarray->count, newarray->slot, + [slotids, slotids_end](const ALeffectslot *slot) -> bool + { return std::find(slotids, slotids_end, slot->id) == slotids_end; } + ); + newarray->count = std::distance(newarray->slot, slotiter); + + /* TODO: Could reallocate newarray now that we know it's needed size. */ + + curarray = context->ActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); + ALCdevice *device{context->Device}; + while((device->MixCount.load(std::memory_order_acquire)&1)) + althrd_yield(); + al_free(curarray); +} + +constexpr struct FactoryItem { ALenum Type; - EffectStateFactory* (*GetFactory)(void); + EffectStateFactory* (&GetFactory)(void); } FactoryList[] = { { AL_EFFECT_NULL, NullStateFactory_getFactory }, { AL_EFFECT_EAXREVERB, ReverbStateFactory_getFactory }, @@ -63,64 +161,37 @@ static const struct { { AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedStateFactory_getFactory } }; -static inline EffectStateFactory *getFactoryByType(ALenum type) -{ - size_t i; - for(i = 0;i < COUNTOF(FactoryList);i++) - { - if(FactoryList[i].Type == type) - return FactoryList[i].GetFactory(); - } - return nullptr; -} - - -static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) -{ - --id; - if(UNLIKELY(id >= context->EffectSlotList.size())) - return nullptr; - return context->EffectSlotList[id]; -} - -static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) +inline EffectStateFactory *getFactoryByType(ALenum type) { - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= device->EffectList.size())) - return nullptr; - EffectSubList &sublist = device->EffectList[lidx]; - if(UNLIKELY(sublist.FreeMask & (U64(1)< bool + { return item.Type == type; } + ); + return (iter != std::end(FactoryList)) ? iter->GetFactory() : nullptr; } #define DO_UPDATEPROPS() do { \ - if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \ - UpdateEffectSlotProps(slot, context); \ + if(!context->DeferUpdates.load(std::memory_order_acquire)) \ + UpdateEffectSlotProps(slot, context.get()); \ else \ - ATOMIC_STORE(&slot->PropsClean, AL_FALSE, almemory_order_release); \ + slot->PropsClean.store(AL_FALSE, std::memory_order_release); \ } while(0) +} // namespace AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) { - ALCdevice *device; - ALCcontext *context; - ALsizei cur; - - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; if(n < 0) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d effect slots", n); - if(n == 0) goto done; + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Generating %d effect slots", n); + if(n == 0) return; - LockEffectSlotList(context); - device = context->Device; - for(cur = 0;cur < n;cur++) + std::unique_lock slotlock{context->EffectSlotLock}; + ALCdevice *device{context->Device}; + for(ALsizei cur{0};cur < n;cur++) { auto iter = std::find_if(context->EffectSlotList.begin(), context->EffectSlotList.end(), [](const ALeffectslotPtr &entry) noexcept -> bool @@ -128,12 +199,13 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo ); if(iter == context->EffectSlotList.end()) { - if(device->AuxiliaryEffectSlotMax == context->EffectSlotList.size()) + if(UNLIKELY(device->AuxiliaryEffectSlotMax == context->EffectSlotList.size())) { - UnlockEffectSlotList(context); + slotlock.unlock(); alDeleteAuxiliaryEffectSlots(cur, effectslots); - SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, + alSetError(context.get(), AL_OUT_OF_MEMORY, "Exceeding %u auxiliary effect slot limit", device->AuxiliaryEffectSlotMax); + return; } context->EffectSlotList.emplace_back(nullptr); iter = context->EffectSlotList.end() - 1; @@ -144,10 +216,11 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo if(err != AL_NO_ERROR) { delete slot; - UnlockEffectSlotList(context); + slotlock.unlock(); alDeleteAuxiliaryEffectSlots(cur, effectslots); - SETERR_GOTO(context, err, done, "Effect slot object allocation failed"); + alSetError(context.get(), err, "Effect slot object allocation failed"); + return; } aluInitEffectPanning(slot); @@ -156,127 +229,113 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo effectslots[cur] = slot->id; } - AddActiveEffectSlots(effectslots, n, context); - UnlockEffectSlotList(context); - -done: - ALCcontext_DecRef(context); + AddActiveEffectSlots(effectslots, n, context.get()); } AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots) { - ALCcontext *context; - ALeffectslot *slot; - ALsizei i; - - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - LockEffectSlotList(context); if(n < 0) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effect slots", n); - if(n == 0) goto done; + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Deleting %d effect slots", n); + if(n == 0) return; - for(i = 0;i < n;i++) - { - if((slot=LookupEffectSlot(context, effectslots[i])) == nullptr) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", - effectslots[i]); - if(ReadRef(&slot->ref) != 0) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Deleting in-use effect slot %u", - effectslots[i]); - } - - // All effectslots are valid - RemoveActiveEffectSlots(effectslots, n, context); - for(i = 0;i < n;i++) - { - if((slot=LookupEffectSlot(context, effectslots[i])) == nullptr) - continue; - context->EffectSlotList[effectslots[i]-1] = nullptr; + std::lock_guard _{context->EffectSlotLock}; + auto effectslots_end = effectslots + n; + auto bad_slot = std::find_if(effectslots, effectslots_end, + [&context](ALuint id) -> bool + { + ALeffectslot *slot{LookupEffectSlot(context.get(), id)}; + if(!slot) + { + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect slot ID %u", id); + return true; + } + if(ReadRef(&slot->ref) != 0) + { + alSetError(context.get(), AL_INVALID_NAME, "Deleting in-use effect slot %u", id); + return true; + } + return false; + } + ); + if(bad_slot != effectslots_end) + return; - delete slot; - } + // All effectslots are valid, remove and delete them + RemoveActiveEffectSlots(effectslots, n, context.get()); + std::for_each(effectslots, effectslots_end, + [&context](ALuint id) -> void + { + ALeffectslot *slot{LookupEffectSlot(context.get(), id)}; + if(!slot) return; -done: - UnlockEffectSlotList(context); - ALCcontext_DecRef(context); + context->EffectSlotList[id-1] = nullptr; + delete slot; + } + ); } AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot) { - ALCcontext *context; - ALboolean ret; - - context = GetContextRef(); - if(!context) return AL_FALSE; - - LockEffectSlotList(context); - ret = (LookupEffectSlot(context, effectslot) ? AL_TRUE : AL_FALSE); - UnlockEffectSlotList(context); - - ALCcontext_DecRef(context); - - return ret; + ContextRef context{GetContextRef()}; + if(LIKELY(context)) + { + std::lock_guard _{context->EffectSlotLock}; + if(LookupEffectSlot(context.get(), effectslot) != nullptr) + return AL_TRUE; + } + return AL_FALSE; } AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value) { - ALCdevice *device; - ALCcontext *context; - ALeffectslot *slot; - ALeffect *effect = nullptr; - ALenum err; - - context = GetContextRef(); - if(!context) return; - - almtx_lock(&context->PropLock); - LockEffectSlotList(context); - if((slot=LookupEffectSlot(context, effectslot)) == nullptr) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + + ALCdevice *device{}; + ALenum err{}; switch(param) { case AL_EFFECTSLOT_EFFECT: device = context->Device; - LockEffectList(device); - effect = (value ? LookupEffect(device, value) : nullptr); - if(!(value == 0 || effect != nullptr)) - { - UnlockEffectList(device); - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Invalid effect ID %u", value); + { std::lock_guard ___{device->EffectLock}; + ALeffect *effect{value ? LookupEffect(device, value) : nullptr}; + if(!(value == 0 || effect != nullptr)) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Invalid effect ID %u", value); + err = InitializeEffect(context.get(), slot, effect); } - err = InitializeEffect(context, slot, effect); - UnlockEffectList(device); - if(err != AL_NO_ERROR) - SETERR_GOTO(context, err, done, "Effect initialization failed"); + { + alSetError(context.get(), err, "Effect initialization failed"); + return; + } break; case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: if(!(value == AL_TRUE || value == AL_FALSE)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, - "Effect slot auxiliary send auto out of range"); + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, + "Effect slot auxiliary send auto out of range"); slot->AuxSendAuto = value; break; default: - SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid effect slot integer property 0x%04x", - param); + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot integer property 0x%04x", param); } DO_UPDATEPROPS(); - -done: - UnlockEffectSlotList(context); - almtx_unlock(&context->PropLock); - ALCcontext_DecRef(context); } AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values) { - ALCcontext *context; - switch(param) { case AL_EFFECTSLOT_EFFECT: @@ -285,60 +344,50 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum para return; } - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard __{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - LockEffectSlotList(context); - if(LookupEffectSlot(context, effectslot) == nullptr) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) { default: - alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer-vector property 0x%04x", - param); + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot integer-vector property 0x%04x", param); } - -done: - UnlockEffectSlotList(context); - ALCcontext_DecRef(context); } AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value) { - ALCcontext *context; - ALeffectslot *slot; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - almtx_lock(&context->PropLock); - LockEffectSlotList(context); - if((slot=LookupEffectSlot(context, effectslot)) == nullptr) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) { case AL_EFFECTSLOT_GAIN: if(!(value >= 0.0f && value <= 1.0f)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Effect slot gain out of range"); + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Effect slot gain out of range"); slot->Gain = value; break; default: - SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid effect slot float property 0x%04x", - param); + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, "Invalid effect slot float property 0x%04x", + param); } DO_UPDATEPROPS(); - -done: - UnlockEffectSlotList(context); - almtx_unlock(&context->PropLock); - ALCcontext_DecRef(context); } AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values) { - ALCcontext *context; - switch(param) { case AL_EFFECTSLOT_GAIN: @@ -346,35 +395,32 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum para return; } - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - LockEffectSlotList(context); - if(LookupEffectSlot(context, effectslot) == nullptr) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) { default: - alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float-vector property 0x%04x", - param); + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot float-vector property 0x%04x", param); } - -done: - UnlockEffectSlotList(context); - ALCcontext_DecRef(context); } AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value) { - ALCcontext *context; - ALeffectslot *slot; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; + std::lock_guard __{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - LockEffectSlotList(context); - if((slot=LookupEffectSlot(context, effectslot)) == nullptr) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) { case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: @@ -382,18 +428,13 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum pa break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer property 0x%04x", param); + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot integer property 0x%04x", param); } - -done: - UnlockEffectSlotList(context); - ALCcontext_DecRef(context); } AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values) { - ALCcontext *context; - switch(param) { case AL_EFFECTSLOT_EFFECT: @@ -402,35 +443,32 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum p return; } - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - LockEffectSlotList(context); - if(LookupEffectSlot(context, effectslot) == nullptr) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) { default: - alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer-vector property 0x%04x", - param); + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot integer-vector property 0x%04x", param); } - -done: - UnlockEffectSlotList(context); - ALCcontext_DecRef(context); } AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value) { - ALCcontext *context; - ALeffectslot *slot; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; + std::lock_guard _{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - LockEffectSlotList(context); - if((slot=LookupEffectSlot(context, effectslot)) == nullptr) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) { case AL_EFFECTSLOT_GAIN: @@ -438,18 +476,13 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum pa break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float property 0x%04x", param); + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot float property 0x%04x", param); } - -done: - UnlockEffectSlotList(context); - ALCcontext_DecRef(context); } AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values) { - ALCcontext *context; - switch(param) { case AL_EFFECTSLOT_GAIN: @@ -457,56 +490,50 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum p return; } - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - LockEffectSlotList(context); - if(LookupEffectSlot(context, effectslot) == nullptr) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) { default: - alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float-vector property 0x%04x", - param); + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot float-vector property 0x%04x", param); } - -done: - UnlockEffectSlotList(context); - ALCcontext_DecRef(context); } ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect) { - ALCdevice *Device = Context->Device; - ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL); - struct ALeffectslotProps *props; - EffectState *State; - + ALenum newtype{effect ? effect->type : AL_EFFECT_NULL}; if(newtype != EffectSlot->Effect.Type) { - EffectStateFactory *factory = getFactoryByType(newtype); + EffectStateFactory *factory{getFactoryByType(newtype)}; if(!factory) { ERR("Failed to find factory for effect type 0x%04x\n", newtype); return AL_INVALID_ENUM; } - State = factory->create(); + EffectState *State{factory->create()}; if(!State) return AL_OUT_OF_MEMORY; - START_MIXER_MODE(); - almtx_lock(&Device->BackendLock); - State->mOutBuffer = Device->Dry.Buffer; - State->mOutChannels = Device->Dry.NumChannels; - if(State->deviceUpdate(Device) == AL_FALSE) - { - almtx_unlock(&Device->BackendLock); - LEAVE_MIXER_MODE(); - State->DecRef(); - return AL_OUT_OF_MEMORY; - } - almtx_unlock(&Device->BackendLock); - END_MIXER_MODE(); + START_MIXER_MODE(); { + ALCdevice *Device{Context->Device}; + std::unique_lock backlock{Device->BackendLock}; + State->mOutBuffer = Device->Dry.Buffer; + State->mOutChannels = Device->Dry.NumChannels; + if(State->deviceUpdate(Device) == AL_FALSE) + { + backlock.unlock(); + LEAVE_MIXER_MODE(); + State->DecRef(); + return AL_OUT_OF_MEMORY; + } + } END_MIXER_MODE(); if(!effect) { @@ -526,7 +553,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect EffectSlot->Effect.Props = effect->Props; /* Remove state references from old effect slot property updates. */ - props = ATOMIC_LOAD_SEQ(&Context->FreeEffectslotProps); + ALeffectslotProps *props{Context->FreeEffectslotProps.load()}; while(props) { if(props->State) @@ -553,96 +580,6 @@ void EffectState::DecRef() noexcept } -static void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) -{ - struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots, - almemory_order_acquire); - struct ALeffectslotArray *newarray = nullptr; - ALsizei newcount = curarray->count + count; - ALCdevice *device = context->Device; - ALsizei i, j; - - /* Insert the new effect slots into the head of the array, followed by the - * existing ones. - */ - newarray = static_cast(al_calloc(DEF_ALIGN, - FAM_SIZE(struct ALeffectslotArray, slot, newcount))); - newarray->count = newcount; - for(i = 0;i < count;i++) - newarray->slot[i] = LookupEffectSlot(context, slotids[i]); - for(j = 0;i < newcount;) - newarray->slot[i++] = curarray->slot[j++]; - /* Remove any duplicates (first instance of each will be kept). */ - for(i = 1;i < newcount;i++) - { - for(j = i;j != 0;) - { - if(UNLIKELY(newarray->slot[i] == newarray->slot[--j])) - { - newcount--; - for(j = i;j < newcount;j++) - newarray->slot[j] = newarray->slot[j+1]; - i--; - break; - } - } - } - - /* Reallocate newarray if the new size ended up smaller from duplicate - * removal. - */ - if(UNLIKELY(newcount < newarray->count)) - { - struct ALeffectslotArray *tmp = static_cast(al_calloc(DEF_ALIGN, - FAM_SIZE(struct ALeffectslotArray, slot, newcount))); - memcpy(tmp, newarray, FAM_SIZE(struct ALeffectslotArray, slot, newcount)); - al_free(newarray); - newarray = tmp; - newarray->count = newcount; - } - - curarray = context->ActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); - while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) - althrd_yield(); - al_free(curarray); -} - -static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) -{ - struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots, - almemory_order_acquire); - struct ALeffectslotArray *newarray = nullptr; - ALCdevice *device = context->Device; - ALsizei i, j; - - /* Don't shrink the allocated array size since we don't know how many (if - * any) of the effect slots to remove are in the array. - */ - newarray = static_cast(al_calloc(DEF_ALIGN, - FAM_SIZE(struct ALeffectslotArray, slot, curarray->count))); - newarray->count = 0; - for(i = 0;i < curarray->count;i++) - { - /* Insert this slot into the new array only if it's not one to remove. */ - ALeffectslot *slot = curarray->slot[i]; - for(j = count;j != 0;) - { - if(slot->id == slotids[--j]) - goto skip_ins; - } - newarray->slot[newarray->count++] = slot; - skip_ins: ; - } - - /* TODO: Could reallocate newarray now that we know it's needed size. */ - - curarray = context->ActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); - while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) - althrd_yield(); - al_free(curarray); -} - - ALenum InitEffectSlot(ALeffectslot *slot) { EffectStateFactory *factory{getFactoryByType(slot->Effect.Type)}; @@ -672,11 +609,8 @@ ALeffectslot::~ALeffectslot() void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) { - struct ALeffectslotProps *props; - EffectState *oldstate; - /* Get an unused property container, or allocate a new one as needed. */ - props = context->FreeEffectslotProps.load(std::memory_order_relaxed); + ALeffectslotProps *props{context->FreeEffectslotProps.load(std::memory_order_relaxed)}; if(!props) props = static_cast(al_calloc(16, sizeof(*props))); else @@ -697,8 +631,8 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) /* Swap out any stale effect state object there may be in the container, to * delete it. */ + EffectState *oldstate{props->State}; slot->Effect.State->IncRef(); - oldstate = props->State; props->State = slot->Effect.State; /* Set the new container for updating internal parameters. */ @@ -720,18 +654,14 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) void UpdateAllEffectSlotProps(ALCcontext *context) { - struct ALeffectslotArray *auxslots; - ALsizei i; - - LockEffectSlotList(context); - auxslots = context->ActiveAuxSlots.load(std::memory_order_acquire); - for(i = 0;i < auxslots->count;i++) + std::lock_guard _{context->EffectSlotLock}; + ALeffectslotArray *auxslots{context->ActiveAuxSlots.load(std::memory_order_acquire)}; + for(ALsizei i{0};i < auxslots->count;i++) { ALeffectslot *slot = auxslots->slot[i]; if(!slot->PropsClean.exchange(AL_TRUE, std::memory_order_acq_rel)) UpdateEffectSlotProps(slot, context); } - UnlockEffectSlotList(context); } ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *context) -- cgit v1.2.3 From 1e31ac469e129ccd5cde5fb890b31fa8b6815a9b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Nov 2018 10:01:20 -0800 Subject: Store effect slots as unique_ptrs --- Alc/alc.cpp | 2 +- Alc/alcontext.h | 2 +- OpenAL32/alAuxEffectSlot.cpp | 37 +++++++++++++++---------------------- OpenAL32/alSource.cpp | 2 +- 4 files changed, 18 insertions(+), 25 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 3247e14c..10a1511e 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2277,7 +2277,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(state->deviceUpdate(device) == AL_FALSE) update_failed = AL_TRUE; else - UpdateEffectSlotProps(slot, context); + UpdateEffectSlotProps(slot.get(), context); } almtx_unlock(&context->EffectSlotLock); diff --git a/Alc/alcontext.h b/Alc/alcontext.h index f174f324..424f1447 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -47,7 +47,7 @@ struct SourceSubList { /* Effect slots are rather large, and apps aren't likely to have more than one * or two (let alone 64), so hold them individually. */ -using ALeffectslotPtr = struct ALeffectslot*; +using ALeffectslotPtr = std::unique_ptr; struct ALCcontext_struct { RefCount ref{1u}; diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index cce3e5d8..ea1765bb 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -46,7 +46,7 @@ inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept --id; if(UNLIKELY(id >= context->EffectSlotList.size())) return nullptr; - return context->EffectSlotList[id]; + return context->EffectSlotList[id].get(); } inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) noexcept @@ -211,23 +211,22 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo iter = context->EffectSlotList.end() - 1; } - auto slot = new ALeffectslot{}; - ALenum err{InitEffectSlot(slot)}; + *iter = std::unique_ptr(new ALeffectslot{}); + ALenum err{InitEffectSlot(iter->get())}; if(err != AL_NO_ERROR) { - delete slot; + *iter = nullptr; slotlock.unlock(); alDeleteAuxiliaryEffectSlots(cur, effectslots); alSetError(context.get(), err, "Effect slot object allocation failed"); return; } - aluInitEffectPanning(slot); + aluInitEffectPanning(iter->get()); - slot->id = std::distance(context->EffectSlotList.begin(), iter) + 1; - *iter = slot; - - effectslots[cur] = slot->id; + ALuint id = std::distance(context->EffectSlotList.begin(), iter) + 1; + (*iter)->id = id; + effectslots[cur] = id; } AddActiveEffectSlots(effectslots, n, context.get()); } @@ -266,14 +265,8 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * // All effectslots are valid, remove and delete them RemoveActiveEffectSlots(effectslots, n, context.get()); std::for_each(effectslots, effectslots_end, - [&context](ALuint id) -> void - { - ALeffectslot *slot{LookupEffectSlot(context.get(), id)}; - if(!slot) return; - - context->EffectSlotList[id-1] = nullptr; - delete slot; - } + [&context](ALuint id) noexcept -> void + { context->EffectSlotList[id-1] = nullptr; } ); } @@ -669,11 +662,11 @@ ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *context) size_t leftover = 0; for(auto &entry : context->EffectSlotList) { - if(!entry) continue; - delete entry; - entry = nullptr; - - ++leftover; + if(entry) + { + entry = nullptr; + ++leftover; + } } if(leftover > 0) WARN("(%p) Deleted " SZFMT " AuxiliaryEffectSlot%s\n", context, leftover, (leftover==1)?"":"s"); diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 2585039f..2c452918 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -105,7 +105,7 @@ static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) --id; if(UNLIKELY(id >= context->EffectSlotList.size())) return nullptr; - return context->EffectSlotList[id]; + return context->EffectSlotList[id].get(); } -- cgit v1.2.3 From 191ea90de3994f9e98377ea9318c4c7b6885179c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Nov 2018 10:45:01 -0800 Subject: Use atomic_flags and atomics where appropriate --- Alc/alc.cpp | 16 +++++++--------- Alc/alcontext.h | 4 ++-- OpenAL32/Include/alAuxEffectSlot.h | 2 +- OpenAL32/Include/alListener.h | 2 +- OpenAL32/Include/alSource.h | 2 +- OpenAL32/alAuxEffectSlot.cpp | 4 ++-- OpenAL32/alListener.cpp | 8 ++++---- OpenAL32/alSource.cpp | 12 +++++------- OpenAL32/alState.cpp | 14 +++++++------- 9 files changed, 30 insertions(+), 34 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 10a1511e..00148246 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1604,7 +1604,7 @@ void SetDefaultChannelOrder(ALCdevice *device) */ void ALCcontext_DeferUpdates(ALCcontext *context) { - ATOMIC_STORE_SEQ(&context->DeferUpdates, AL_TRUE); + context->DeferUpdates.store(true); } /* ALCcontext_ProcessUpdates @@ -1614,7 +1614,7 @@ void ALCcontext_DeferUpdates(ALCcontext *context) void ALCcontext_ProcessUpdates(ALCcontext *context) { almtx_lock(&context->PropLock); - if(context->DeferUpdates.exchange(AL_FALSE)) + if(context->DeferUpdates.exchange(false)) { /* Tell the mixer to stop applying updates, then wait for any active * updating to finish, before providing updates. @@ -1623,9 +1623,9 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) while((ATOMIC_LOAD(&context->UpdateCount, almemory_order_acquire)&1) != 0) althrd_yield(); - if(!context->PropsClean.exchange(AL_TRUE, std::memory_order_acq_rel)) + if(!context->PropsClean.test_and_set(std::memory_order_acq_rel)) UpdateContextProps(context); - if(!context->Listener.PropsClean.exchange(AL_TRUE, std::memory_order_acq_rel)) + if(!context->Listener.PropsClean.test_and_set(std::memory_order_acq_rel)) UpdateListenerProps(context); UpdateAllEffectSlotProps(context); UpdateAllSourceProps(context); @@ -2319,7 +2319,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } } - ATOMIC_STORE(&source->PropsClean, AL_FALSE, almemory_order_release); + source->PropsClean.clear(std::memory_order_release); } } @@ -2356,9 +2356,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } almtx_unlock(&context->SourceLock); - ATOMIC_STORE(&context->PropsClean, AL_TRUE, almemory_order_release); + context->PropsClean.test_and_set(std::memory_order_release); UpdateContextProps(context); - ATOMIC_STORE(&context->Listener.PropsClean, AL_TRUE, almemory_order_release); + context->Listener.PropsClean.test_and_set(std::memory_order_release); UpdateListenerProps(context); UpdateAllSourceProps(context); almtx_unlock(&context->PropLock); @@ -2538,8 +2538,6 @@ static ALvoid InitContext(ALCcontext *Context) Context->DopplerVelocity = 1.0f; Context->SpeedOfSound = SPEEDOFSOUNDMETRESPERSEC; Context->MetersPerUnit = AL_DEFAULT_METERS_PER_UNIT; - ATOMIC_INIT(&Context->PropsClean, AL_TRUE); - ATOMIC_INIT(&Context->DeferUpdates, AL_FALSE); alsem_init(&Context->EventSem, 0); almtx_init(&Context->EventCbLock, almtx_plain); diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 424f1447..ce715bc2 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -69,8 +69,8 @@ struct ALCcontext_struct { ALfloat SpeedOfSound{}; ALfloat MetersPerUnit{1.0f}; - ATOMIC(ALenum) PropsClean{AL_TRUE}; - ATOMIC(ALenum) DeferUpdates{AL_FALSE}; + std::atomic_flag PropsClean{true}; + std::atomic DeferUpdates{false}; almtx_t PropLock; diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 6e315e8f..dd44b436 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -69,7 +69,7 @@ struct ALeffectslot { EffectState *State{nullptr}; } Effect; - ATOMIC(ALenum) PropsClean{AL_TRUE}; + std::atomic_flag PropsClean{true}; RefCount ref{0u}; diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h index 1e0a8265..6b1dcda9 100644 --- a/OpenAL32/Include/alListener.h +++ b/OpenAL32/Include/alListener.h @@ -28,7 +28,7 @@ struct ALlistener { ALfloat Up[3]{0.0f, 1.0f, 0.0f}; ALfloat Gain{1.0f}; - ATOMIC(ALenum) PropsClean{AL_TRUE}; + std::atomic_flag PropsClean{true}; /* Pointer to the most recent property values that are awaiting an update. */ diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 3d7d733e..9ad5577d 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -97,7 +97,7 @@ typedef struct ALsource { /** Source Buffer Queue head. */ ALbufferlistitem *queue; - ATOMIC(ALenum) PropsClean; + std::atomic_flag PropsClean{true}; /* Index into the context's Voices array. Lazily updated, only checked and * reset when looking up the voice. diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index ea1765bb..df2c2a43 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -175,7 +175,7 @@ inline EffectStateFactory *getFactoryByType(ALenum type) if(!context->DeferUpdates.load(std::memory_order_acquire)) \ UpdateEffectSlotProps(slot, context.get()); \ else \ - slot->PropsClean.store(AL_FALSE, std::memory_order_release); \ + slot->PropsClean.clear(std::memory_order_release); \ } while(0) } // namespace @@ -652,7 +652,7 @@ void UpdateAllEffectSlotProps(ALCcontext *context) for(ALsizei i{0};i < auxslots->count;i++) { ALeffectslot *slot = auxslots->slot[i]; - if(!slot->PropsClean.exchange(AL_TRUE, std::memory_order_acq_rel)) + if(!slot->PropsClean.test_and_set(std::memory_order_acq_rel)) UpdateEffectSlotProps(slot, context); } } diff --git a/OpenAL32/alListener.cpp b/OpenAL32/alListener.cpp index d60f5254..bd004368 100644 --- a/OpenAL32/alListener.cpp +++ b/OpenAL32/alListener.cpp @@ -30,10 +30,10 @@ #include "alSource.h" #define DO_UPDATEPROPS() do { \ - if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \ + if(!context->DeferUpdates.load(std::memory_order_acquire)) \ UpdateListenerProps(context); \ else \ - ATOMIC_STORE(&listener->PropsClean, AL_FALSE, almemory_order_release);\ + listener->PropsClean.clear(std::memory_order_release); \ } while(0) @@ -60,10 +60,10 @@ AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT)) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener meters per unit out of range"); context->MetersPerUnit = value; - if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + if(!context->DeferUpdates.load(std::memory_order_acquire)) UpdateContextProps(context); else - ATOMIC_STORE(&context->PropsClean, AL_FALSE, almemory_order_release); + context->PropsClean.clear(std::memory_order_release); break; default: diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 2c452918..c487d877 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -222,7 +222,7 @@ static inline ALenum GetSourceState(ALsource *source, ALvoice *voice) */ static inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context) { - return !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) && + return !context->DeferUpdates.load(std::memory_order_acquire) && IsPlayingOrPaused(source); } @@ -520,7 +520,7 @@ static ALint Int64ValsByProp(ALenum prop) (voice=GetSourceVoice(Source, Context)) != NULL) \ UpdateSourceProps(Source, voice, device->NumAuxSends, Context); \ else \ - ATOMIC_STORE(&Source->PropsClean, AL_FALSE, almemory_order_release); \ + Source->PropsClean.clear(std::memory_order_release); \ } while(0) static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values) @@ -1038,7 +1038,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p if((voice=GetSourceVoice(Source, Context)) != NULL) UpdateSourceProps(Source, voice, device->NumAuxSends, Context); else - ATOMIC_STORE(&Source->PropsClean, AL_FALSE, almemory_order_release); + Source->PropsClean.clear(std::memory_order_release); } else { @@ -2489,7 +2489,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) voice = context->Voices[vidx]; voice->Playing.store(false, std::memory_order_release); - source->PropsClean.exchange(AL_TRUE, std::memory_order_acquire); + source->PropsClean.test_and_set(std::memory_order_acquire); UpdateSourceProps(source, voice, device->NumAuxSends, context); /* A source that's not playing or paused has any offset applied when it @@ -3113,8 +3113,6 @@ static void InitSourceParams(ALsource *Source, ALsizei num_sends) Source->queue = NULL; - ATOMIC_INIT(&Source->PropsClean, AL_TRUE); - Source->VoiceIdx = -1; } @@ -3248,7 +3246,7 @@ void UpdateAllSourceProps(ALCcontext *context) { ALvoice *voice = context->Voices[pos]; ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire); - if(source && !source->PropsClean.exchange(AL_TRUE, std::memory_order_acq_rel)) + if(source && !source->PropsClean.test_and_set(std::memory_order_acq_rel)) UpdateSourceProps(source, voice, num_sends, context); } } diff --git a/OpenAL32/alState.cpp b/OpenAL32/alState.cpp index e3e8856f..2901baa2 100644 --- a/OpenAL32/alState.cpp +++ b/OpenAL32/alState.cpp @@ -67,10 +67,10 @@ extern "C" AL_API const ALchar* AL_APIENTRY alsoft_get_version(void) } #define DO_UPDATEPROPS() do { \ - if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \ + if(!context->DeferUpdates.load(std::memory_order_acquire)) \ UpdateContextProps(context.get()); \ else \ - ATOMIC_STORE(&context->PropsClean, AL_FALSE, almemory_order_release); \ + context->PropsClean.clear(std::memory_order_release); \ } while(0) @@ -160,7 +160,7 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) break; case AL_DEFERRED_UPDATES_SOFT: - if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + if(context->DeferUpdates.load(std::memory_order_acquire)) value = AL_TRUE; break; @@ -211,7 +211,7 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) break; case AL_DEFERRED_UPDATES_SOFT: - if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + if(context->DeferUpdates.load(std::memory_order_acquire)) value = (ALdouble)AL_TRUE; break; @@ -260,7 +260,7 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) break; case AL_DEFERRED_UPDATES_SOFT: - if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + if(context->DeferUpdates.load(std::memory_order_acquire)) value = (ALfloat)AL_TRUE; break; @@ -309,7 +309,7 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) break; case AL_DEFERRED_UPDATES_SOFT: - if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + if(context->DeferUpdates.load(std::memory_order_acquire)) value = (ALint)AL_TRUE; break; @@ -358,7 +358,7 @@ extern "C" AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) break; case AL_DEFERRED_UPDATES_SOFT: - if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + if(context->DeferUpdates.load(std::memory_order_acquire)) value = (ALint64SOFT)AL_TRUE; break; -- cgit v1.2.3 From f9e969a3391e1c0622e35ceaf5dc541b7f149c5d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Nov 2018 10:55:57 -0800 Subject: Use a standard mutex for the event callback lock --- Alc/alc.cpp | 2 -- Alc/alcontext.h | 4 +++- OpenAL32/alError.cpp | 2 +- OpenAL32/alState.cpp | 4 ++-- OpenAL32/event.cpp | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 00148246..65e77b0d 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2539,7 +2539,6 @@ static ALvoid InitContext(ALCcontext *Context) Context->SpeedOfSound = SPEEDOFSOUNDMETRESPERSEC; Context->MetersPerUnit = AL_DEFAULT_METERS_PER_UNIT; alsem_init(&Context->EventSem, 0); - almtx_init(&Context->EventCbLock, almtx_plain); Context->ExtensionList = alExtList; @@ -2650,7 +2649,6 @@ ALCcontext_struct::~ALCcontext_struct() } TRACE("Freed " SZFMT " listener property object%s\n", count, (count==1)?"":"s"); - almtx_destroy(&EventCbLock); alsem_destroy(&EventSem); ll_ringbuffer_free(AsyncEvents); diff --git a/Alc/alcontext.h b/Alc/alcontext.h index ce715bc2..4a056597 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -1,6 +1,8 @@ #ifndef ALCONTEXT_H #define ALCONTEXT_H +#include +#include #include #include @@ -102,7 +104,7 @@ struct ALCcontext_struct { alsem_t EventSem; ll_ringbuffer *AsyncEvents{nullptr}; ATOMIC(ALbitfieldSOFT) EnabledEvts{0u}; - almtx_t EventCbLock; + std::mutex EventCbLock; ALEVENTPROCSOFT EventCb{}; void *EventParam{nullptr}; diff --git a/OpenAL32/alError.cpp b/OpenAL32/alError.cpp index 16c89273..39c666d2 100644 --- a/OpenAL32/alError.cpp +++ b/OpenAL32/alError.cpp @@ -73,7 +73,7 @@ void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) context->LastError.compare_exchange_strong(curerr, errorCode); if((context->EnabledEvts.load(std::memory_order_relaxed)&EventType_Error)) { - std::lock_guard _{context->EventCbLock}; + std::lock_guard _{context->EventCbLock}; ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; if((enabledevts&EventType_Error) && context->EventCb) (*context->EventCb)(AL_EVENT_TYPE_ERROR_SOFT, 0, errorCode, msglen, msg, diff --git a/OpenAL32/alState.cpp b/OpenAL32/alState.cpp index 2901baa2..95a4fd92 100644 --- a/OpenAL32/alState.cpp +++ b/OpenAL32/alState.cpp @@ -664,8 +664,8 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) static constexpr ALCchar msg[] = "alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound"; const ALsizei msglen = (ALsizei)strlen(msg); - std::lock_guard _{context->EventCbLock}; - ALbitfieldSOFT enabledevts{ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)}; + std::lock_guard _{context->EventCbLock}; + ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; if((enabledevts&EventType_Deprecated) && context->EventCb) (*context->EventCb)(AL_EVENT_TYPE_DEPRECATED_SOFT, 0, 0, msglen, msg, context->EventParam); diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index d6fa01fb..a2c98928 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -27,7 +27,7 @@ static int EventThread(ALCcontext *context) continue; } - std::lock_guard _{context->EventCbLock}; + std::lock_guard _{context->EventCbLock}; do { quitnow = evt.EnumType == EventType_KillThread; if(UNLIKELY(quitnow)) break; @@ -126,7 +126,7 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A /* Wait to ensure the event handler sees the changed flags before * returning. */ - std::lock_guard{context->EventCbLock}; + std::lock_guard{context->EventCbLock}; } } @@ -136,7 +136,7 @@ AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *user if(UNLIKELY(!context)) return; std::lock_guard _{context->PropLock}; - std::lock_guard __{context->EventCbLock}; + std::lock_guard __{context->EventCbLock}; context->EventCb = callback; context->EventParam = userParam; } -- cgit v1.2.3 From a111254c26cb1c926dda8730a20790bcc5f78ef1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Nov 2018 11:17:54 -0800 Subject: Use C++ more in alListener.cpp --- OpenAL32/alListener.cpp | 316 +++++++++++++++++++----------------------------- 1 file changed, 127 insertions(+), 189 deletions(-) diff --git a/OpenAL32/alListener.cpp b/OpenAL32/alListener.cpp index bd004368..2d3482bf 100644 --- a/OpenAL32/alListener.cpp +++ b/OpenAL32/alListener.cpp @@ -31,96 +31,80 @@ #define DO_UPDATEPROPS() do { \ if(!context->DeferUpdates.load(std::memory_order_acquire)) \ - UpdateListenerProps(context); \ + UpdateListenerProps(context.get()); \ else \ - listener->PropsClean.clear(std::memory_order_release); \ + listener.PropsClean.clear(std::memory_order_release); \ } while(0) AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) { - ALlistener *listener; - ALCcontext *context; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; - - listener = &context->Listener; - almtx_lock(&context->PropLock); + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; switch(param) { case AL_GAIN: if(!(value >= 0.0f && std::isfinite(value))) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener gain out of range"); - listener->Gain = value; + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener gain out of range"); + listener.Gain = value; DO_UPDATEPROPS(); break; case AL_METERS_PER_UNIT: if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener meters per unit out of range"); + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, + "Listener meters per unit out of range"); context->MetersPerUnit = value; if(!context->DeferUpdates.load(std::memory_order_acquire)) - UpdateContextProps(context); + UpdateContextProps(context.get()); else context->PropsClean.clear(std::memory_order_release); break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener float property"); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float property"); } - -done: - almtx_unlock(&context->PropLock); - ALCcontext_DecRef(context); } AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) { - ALlistener *listener; - ALCcontext *context; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; - - listener = &context->Listener; - almtx_lock(&context->PropLock); + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; switch(param) { case AL_POSITION: if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3))) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener position out of range"); - listener->Position[0] = value1; - listener->Position[1] = value2; - listener->Position[2] = value3; + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener position out of range"); + listener.Position[0] = value1; + listener.Position[1] = value2; + listener.Position[2] = value3; DO_UPDATEPROPS(); break; case AL_VELOCITY: if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3))) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener velocity out of range"); - listener->Velocity[0] = value1; - listener->Velocity[1] = value2; - listener->Velocity[2] = value3; + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener velocity out of range"); + listener.Velocity[0] = value1; + listener.Velocity[1] = value2; + listener.Velocity[2] = value3; DO_UPDATEPROPS(); break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-float property"); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-float property"); } - -done: - almtx_unlock(&context->PropLock); - ALCcontext_DecRef(context); } AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) { - ALlistener *listener; - ALCcontext *context; - if(values) { switch(param) @@ -137,61 +121,50 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) } } - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - listener = &context->Listener; - almtx_lock(&context->PropLock); - if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; + if(!values) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "NULL pointer"); switch(param) { case AL_ORIENTATION: if(!(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) && std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5]))) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener orientation out of range"); + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener orientation out of range"); /* AT then UP */ - listener->Forward[0] = values[0]; - listener->Forward[1] = values[1]; - listener->Forward[2] = values[2]; - listener->Up[0] = values[3]; - listener->Up[1] = values[4]; - listener->Up[2] = values[5]; + listener.Forward[0] = values[0]; + listener.Forward[1] = values[1]; + listener.Forward[2] = values[2]; + listener.Up[0] = values[3]; + listener.Up[1] = values[4]; + listener.Up[2] = values[5]; DO_UPDATEPROPS(); break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener float-vector property"); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float-vector property"); } - -done: - almtx_unlock(&context->PropLock); - ALCcontext_DecRef(context); } AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value)) { - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - almtx_lock(&context->PropLock); + std::lock_guard _{context->PropLock}; switch(param) { default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener integer property"); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer property"); } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); } AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3) { - ALCcontext *context; - switch(param) { case AL_POSITION: @@ -200,25 +173,20 @@ AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, A return; } - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - almtx_lock(&context->PropLock); + std::lock_guard _{context->PropLock}; switch(param) { default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-integer property"); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-integer property"); } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); } AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values) { - ALCcontext *context; - if(values) { ALfloat fvals[6]; @@ -241,37 +209,33 @@ AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values) } } - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - almtx_lock(&context->PropLock); + std::lock_guard _{context->PropLock}; if(!values) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) { default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener integer-vector property"); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer-vector property"); } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); } AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) { - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - almtx_lock(&context->PropLock); + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; if(!value) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_GAIN: - *value = context->Listener.Gain; + *value = listener.Gain; break; case AL_METERS_PER_UNIT: @@ -279,51 +243,42 @@ AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener float property"); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float property"); } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); } AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) { - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - almtx_lock(&context->PropLock); + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; if(!value1 || !value2 || !value3) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_POSITION: - *value1 = context->Listener.Position[0]; - *value2 = context->Listener.Position[1]; - *value3 = context->Listener.Position[2]; + *value1 = listener.Position[0]; + *value2 = listener.Position[1]; + *value3 = listener.Position[2]; break; case AL_VELOCITY: - *value1 = context->Listener.Velocity[0]; - *value2 = context->Listener.Velocity[1]; - *value3 = context->Listener.Velocity[2]; + *value1 = listener.Velocity[0]; + *value2 = listener.Velocity[1]; + *value3 = listener.Velocity[2]; break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-float property"); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-float property"); } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); } AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) { - ALCcontext *context; - switch(param) { case AL_GAIN: @@ -337,91 +292,78 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) return; } - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - almtx_lock(&context->PropLock); + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; if(!values) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_ORIENTATION: // AT then UP - values[0] = context->Listener.Forward[0]; - values[1] = context->Listener.Forward[1]; - values[2] = context->Listener.Forward[2]; - values[3] = context->Listener.Up[0]; - values[4] = context->Listener.Up[1]; - values[5] = context->Listener.Up[2]; + values[0] = listener.Forward[0]; + values[1] = listener.Forward[1]; + values[2] = listener.Forward[2]; + values[3] = listener.Up[0]; + values[4] = listener.Up[1]; + values[5] = listener.Up[2]; break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener float-vector property"); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float-vector property"); } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); } AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value) { - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - almtx_lock(&context->PropLock); + std::lock_guard _{context->PropLock}; if(!value) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) { default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener integer property"); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer property"); } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); } AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3) { - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - almtx_lock(&context->PropLock); + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; if(!value1 || !value2 || !value3) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_POSITION: - *value1 = (ALint)context->Listener.Position[0]; - *value2 = (ALint)context->Listener.Position[1]; - *value3 = (ALint)context->Listener.Position[2]; + *value1 = (ALint)listener.Position[0]; + *value2 = (ALint)listener.Position[1]; + *value3 = (ALint)listener.Position[2]; break; case AL_VELOCITY: - *value1 = (ALint)context->Listener.Velocity[0]; - *value2 = (ALint)context->Listener.Velocity[1]; - *value3 = (ALint)context->Listener.Velocity[2]; + *value1 = (ALint)listener.Velocity[0]; + *value2 = (ALint)listener.Velocity[1]; + *value3 = (ALint)listener.Velocity[2]; break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-integer property"); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-integer property"); } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); } AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) { - ALCcontext *context; - switch(param) { case AL_POSITION: @@ -430,40 +372,35 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) return; } - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - almtx_lock(&context->PropLock); + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; if(!values) - alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_ORIENTATION: // AT then UP - values[0] = (ALint)context->Listener.Forward[0]; - values[1] = (ALint)context->Listener.Forward[1]; - values[2] = (ALint)context->Listener.Forward[2]; - values[3] = (ALint)context->Listener.Up[0]; - values[4] = (ALint)context->Listener.Up[1]; - values[5] = (ALint)context->Listener.Up[2]; + values[0] = (ALint)listener.Forward[0]; + values[1] = (ALint)listener.Forward[1]; + values[2] = (ALint)listener.Forward[2]; + values[3] = (ALint)listener.Up[0]; + values[4] = (ALint)listener.Up[1]; + values[5] = (ALint)listener.Up[2]; break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid listener integer-vector property"); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer-vector property"); } - almtx_unlock(&context->PropLock); - - ALCcontext_DecRef(context); } void UpdateListenerProps(ALCcontext *context) { - ALlistener *listener{&context->Listener}; - struct ALlistenerProps *props; - /* Get an unused proprty container, or allocate a new one as needed. */ - props = context->FreeListenerProps.load(std::memory_order_acquire); + ALlistenerProps *props{context->FreeListenerProps.load(std::memory_order_acquire)}; if(!props) props = static_cast(al_calloc(16, sizeof(*props))); else @@ -476,25 +413,26 @@ void UpdateListenerProps(ALCcontext *context) } /* Copy in current property values. */ - props->Position[0] = listener->Position[0]; - props->Position[1] = listener->Position[1]; - props->Position[2] = listener->Position[2]; + ALlistener &listener = context->Listener; + props->Position[0] = listener.Position[0]; + props->Position[1] = listener.Position[1]; + props->Position[2] = listener.Position[2]; - props->Velocity[0] = listener->Velocity[0]; - props->Velocity[1] = listener->Velocity[1]; - props->Velocity[2] = listener->Velocity[2]; + props->Velocity[0] = listener.Velocity[0]; + props->Velocity[1] = listener.Velocity[1]; + props->Velocity[2] = listener.Velocity[2]; - props->Forward[0] = listener->Forward[0]; - props->Forward[1] = listener->Forward[1]; - props->Forward[2] = listener->Forward[2]; - props->Up[0] = listener->Up[0]; - props->Up[1] = listener->Up[1]; - props->Up[2] = listener->Up[2]; + props->Forward[0] = listener.Forward[0]; + props->Forward[1] = listener.Forward[1]; + props->Forward[2] = listener.Forward[2]; + props->Up[0] = listener.Up[0]; + props->Up[1] = listener.Up[1]; + props->Up[2] = listener.Up[2]; - props->Gain = listener->Gain; + props->Gain = listener.Gain; /* Set the new container for updating internal parameters. */ - props = listener->Update.exchange(props, std::memory_order_acq_rel); + props = listener.Update.exchange(props, std::memory_order_acq_rel); if(props) { /* If there was an unused update container, put it back in the -- cgit v1.2.3 From f3e01ae9d4f4028f36652ae1e81bbe5bf33389bb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Nov 2018 12:25:15 -0800 Subject: Use a normal vector for the source send properties --- Alc/alc.cpp | 9 +- OpenAL32/Include/alSource.h | 13 ++- OpenAL32/alSource.cpp | 233 ++++++++++++++++++++------------------------ 3 files changed, 118 insertions(+), 137 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 65e77b0d..d15b6e00 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2294,20 +2294,15 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(old_sends != device->NumAuxSends) { - ALvoid *sends = al_calloc(16, device->NumAuxSends*sizeof(source->Send[0])); ALsizei s; - - memcpy(sends, source->Send, - mini(device->NumAuxSends, old_sends)*sizeof(source->Send[0]) - ); for(s = device->NumAuxSends;s < old_sends;s++) { if(source->Send[s].Slot) DecrementRef(&source->Send[s].Slot->ref); source->Send[s].Slot = nullptr; } - al_free(source->Send); - source->Send = static_castSend)>(sends); + source->Send.resize(device->NumAuxSends); + source->Send.shrink_to_fit(); for(s = old_sends;s < device->NumAuxSends;s++) { source->Send[s].Slot = nullptr; diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 9ad5577d..4e111250 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -4,6 +4,7 @@ #include "alMain.h" #include "alu.h" #include "hrtf.h" +#include "almalloc.h" #include "atomic.h" #define MAX_SENDS 16 @@ -72,14 +73,15 @@ typedef struct ALsource { ALfloat GainLF; ALfloat LFReference; } Direct; - struct { + struct SendData { struct ALeffectslot *Slot; ALfloat Gain; ALfloat GainHF; ALfloat HFReference; ALfloat GainLF; ALfloat LFReference; - } *Send; + }; + al::vector Send; /** * Last user-specified offset, and the offset type (bytes, samples, or @@ -106,6 +108,13 @@ typedef struct ALsource { /** Self ID */ ALuint id; + + + ALsource(ALsizei num_sends); + ~ALsource(); + + ALsource(const ALsource&) = delete; + ALsource& operator=(const ALsource&) = delete; } ALsource; void UpdateAllSourceProps(ALCcontext *context); diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index c487d877..56895e77 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -47,9 +47,7 @@ static ALsource *AllocSource(ALCcontext *context); static void FreeSource(ALCcontext *context, ALsource *source); -static void InitSourceParams(ALsource *Source, ALsizei num_sends); -static void DeinitSource(ALsource *source, ALsizei num_sends); -static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends, ALCcontext *context); +static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALCcontext *context); static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime); static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime); static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context); @@ -518,14 +516,13 @@ static ALint Int64ValsByProp(ALenum prop) ALvoice *voice; \ if(SourceShouldUpdate(Source, Context) && \ (voice=GetSourceVoice(Source, Context)) != NULL) \ - UpdateSourceProps(Source, voice, device->NumAuxSends, Context); \ + UpdateSourceProps(Source, voice, Context); \ else \ Source->PropsClean.clear(std::memory_order_release); \ } while(0) static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values) { - ALCdevice *device = Context->Device; ALint ival; switch(prop) @@ -1036,7 +1033,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p * active source, in case the slot is about to be deleted. */ if((voice=GetSourceVoice(Source, Context)) != NULL) - UpdateSourceProps(Source, voice, device->NumAuxSends, Context); + UpdateSourceProps(Source, voice, Context); else Source->PropsClean.clear(std::memory_order_release); } @@ -2490,7 +2487,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) voice->Playing.store(false, std::memory_order_release); source->PropsClean.test_and_set(std::memory_order_acquire); - UpdateSourceProps(source, voice, device->NumAuxSends, context); + UpdateSourceProps(source, voice, context); /* A source that's not playing or paused has any offset applied when it * starts playing. @@ -3040,124 +3037,112 @@ done: } -static void InitSourceParams(ALsource *Source, ALsizei num_sends) -{ - ALsizei i; - - Source->InnerAngle = 360.0f; - Source->OuterAngle = 360.0f; - Source->Pitch = 1.0f; - Source->Position[0] = 0.0f; - Source->Position[1] = 0.0f; - Source->Position[2] = 0.0f; - Source->Velocity[0] = 0.0f; - Source->Velocity[1] = 0.0f; - Source->Velocity[2] = 0.0f; - Source->Direction[0] = 0.0f; - Source->Direction[1] = 0.0f; - Source->Direction[2] = 0.0f; - Source->Orientation[0][0] = 0.0f; - Source->Orientation[0][1] = 0.0f; - Source->Orientation[0][2] = -1.0f; - Source->Orientation[1][0] = 0.0f; - Source->Orientation[1][1] = 1.0f; - Source->Orientation[1][2] = 0.0f; - Source->RefDistance = 1.0f; - Source->MaxDistance = FLT_MAX; - Source->RolloffFactor = 1.0f; - Source->Gain = 1.0f; - Source->MinGain = 0.0f; - Source->MaxGain = 1.0f; - Source->OuterGain = 0.0f; - Source->OuterGainHF = 1.0f; - - Source->DryGainHFAuto = AL_TRUE; - Source->WetGainAuto = AL_TRUE; - Source->WetGainHFAuto = AL_TRUE; - Source->AirAbsorptionFactor = 0.0f; - Source->RoomRolloffFactor = 0.0f; - Source->DopplerFactor = 1.0f; - Source->HeadRelative = AL_FALSE; - Source->Looping = AL_FALSE; - Source->mDistanceModel = DistanceModel::Default; - Source->Resampler = ResamplerDefault; - Source->DirectChannels = AL_FALSE; - Source->Spatialize = SpatializeAuto; - - Source->StereoPan[0] = DEG2RAD( 30.0f); - Source->StereoPan[1] = DEG2RAD(-30.0f); - - Source->Radius = 0.0f; - - Source->Direct.Gain = 1.0f; - Source->Direct.GainHF = 1.0f; - Source->Direct.HFReference = LOWPASSFREQREF; - Source->Direct.GainLF = 1.0f; - Source->Direct.LFReference = HIGHPASSFREQREF; - Source->Send = static_castSend)>(al_calloc(16, - num_sends*sizeof(Source->Send[0]))); - for(i = 0;i < num_sends;i++) - { - Source->Send[i].Slot = NULL; - Source->Send[i].Gain = 1.0f; - Source->Send[i].GainHF = 1.0f; - Source->Send[i].HFReference = LOWPASSFREQREF; - Source->Send[i].GainLF = 1.0f; - Source->Send[i].LFReference = HIGHPASSFREQREF; - } - - Source->Offset = 0.0; - Source->OffsetType = AL_NONE; - Source->SourceType = AL_UNDETERMINED; - Source->state = AL_INITIAL; - - Source->queue = NULL; - - Source->VoiceIdx = -1; -} - -static void DeinitSource(ALsource *source, ALsizei num_sends) -{ - ALbufferlistitem *BufferList; - ALsizei i; - - BufferList = source->queue; +ALsource::ALsource(ALsizei num_sends) +{ + InnerAngle = 360.0f; + OuterAngle = 360.0f; + Pitch = 1.0f; + Position[0] = 0.0f; + Position[1] = 0.0f; + Position[2] = 0.0f; + Velocity[0] = 0.0f; + Velocity[1] = 0.0f; + Velocity[2] = 0.0f; + Direction[0] = 0.0f; + Direction[1] = 0.0f; + Direction[2] = 0.0f; + Orientation[0][0] = 0.0f; + Orientation[0][1] = 0.0f; + Orientation[0][2] = -1.0f; + Orientation[1][0] = 0.0f; + Orientation[1][1] = 1.0f; + Orientation[1][2] = 0.0f; + RefDistance = 1.0f; + MaxDistance = FLT_MAX; + RolloffFactor = 1.0f; + Gain = 1.0f; + MinGain = 0.0f; + MaxGain = 1.0f; + OuterGain = 0.0f; + OuterGainHF = 1.0f; + + DryGainHFAuto = AL_TRUE; + WetGainAuto = AL_TRUE; + WetGainHFAuto = AL_TRUE; + AirAbsorptionFactor = 0.0f; + RoomRolloffFactor = 0.0f; + DopplerFactor = 1.0f; + HeadRelative = AL_FALSE; + Looping = AL_FALSE; + mDistanceModel = DistanceModel::Default; + Resampler = ResamplerDefault; + DirectChannels = AL_FALSE; + Spatialize = SpatializeAuto; + + StereoPan[0] = DEG2RAD( 30.0f); + StereoPan[1] = DEG2RAD(-30.0f); + + Radius = 0.0f; + + Direct.Gain = 1.0f; + Direct.GainHF = 1.0f; + Direct.HFReference = LOWPASSFREQREF; + Direct.GainLF = 1.0f; + Direct.LFReference = HIGHPASSFREQREF; + Send.resize(num_sends); + for(auto &send : Send) + { + send.Slot = nullptr; + send.Gain = 1.0f; + send.GainHF = 1.0f; + send.HFReference = LOWPASSFREQREF; + send.GainLF = 1.0f; + send.LFReference = HIGHPASSFREQREF; + } + + Offset = 0.0; + OffsetType = AL_NONE; + SourceType = AL_UNDETERMINED; + state = AL_INITIAL; + + queue = NULL; + + VoiceIdx = -1; +} + +ALsource::~ALsource() +{ + ALbufferlistitem *BufferList{queue}; while(BufferList != NULL) { - ALbufferlistitem *next = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); - for(i = 0;i < BufferList->num_buffers;i++) + ALbufferlistitem *next = BufferList->next.load(std::memory_order_relaxed); + for(ALsizei i{0};i < BufferList->num_buffers;i++) { - if(BufferList->buffers[i] != NULL) + if(BufferList->buffers[i]) DecrementRef(&BufferList->buffers[i]->ref); } al_free(BufferList); BufferList = next; } - source->queue = NULL; + queue = nullptr; - if(source->Send) - { - for(i = 0;i < num_sends;i++) + std::for_each(Send.begin(), Send.end(), + [](ALsource::SendData &send) -> void { - if(source->Send[i].Slot) - DecrementRef(&source->Send[i].Slot->ref); - source->Send[i].Slot = NULL; + if(send.Slot) + DecrementRef(&send.Slot->ref); + send.Slot = nullptr; } - al_free(source->Send); - source->Send = NULL; - } + ); } -static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends, ALCcontext *context) +static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALCcontext *context) { - struct ALvoiceProps *props; - ALsizei i; - /* Get an unused property container, or allocate a new one as needed. */ - props = context->FreeVoiceProps.load(std::memory_order_acquire); + ALvoiceProps *props{context->FreeVoiceProps.load(std::memory_order_acquire)}; if(!props) props = static_cast(al_calloc(16, - FAM_SIZE(struct ALvoiceProps, Send, num_sends))); + FAM_SIZE(struct ALvoiceProps, Send, source->Send.size()))); else { struct ALvoiceProps *next; @@ -3178,16 +3163,15 @@ static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_send props->RefDistance = source->RefDistance; props->MaxDistance = source->MaxDistance; props->RolloffFactor = source->RolloffFactor; - for(i = 0;i < 3;i++) + for(ALsizei i{0};i < 3;i++) props->Position[i] = source->Position[i]; - for(i = 0;i < 3;i++) + for(ALsizei i{0};i < 3;i++) props->Velocity[i] = source->Velocity[i]; - for(i = 0;i < 3;i++) + for(ALsizei i{0};i < 3;i++) props->Direction[i] = source->Direction[i]; - for(i = 0;i < 2;i++) + for(ALsizei i{0};i < 2;i++) { - ALsizei j; - for(j = 0;j < 3;j++) + for(ALsizei j{0};j < 3;j++) props->Orientation[i][j] = source->Orientation[i][j]; } props->HeadRelative = source->HeadRelative; @@ -3216,7 +3200,7 @@ static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_send props->Direct.GainLF = source->Direct.GainLF; props->Direct.LFReference = source->Direct.LFReference; - for(i = 0;i < num_sends;i++) + for(size_t i{0u};i < source->Send.size();i++) { props->Send[i].Slot = source->Send[i].Slot; props->Send[i].Gain = source->Send[i].Gain; @@ -3239,15 +3223,12 @@ static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_send void UpdateAllSourceProps(ALCcontext *context) { - ALsizei num_sends = context->Device->NumAuxSends; - ALsizei pos; - - for(pos = 0;pos < context->VoiceCount;pos++) + for(ALsizei i{0};i < context->VoiceCount;++i) { - ALvoice *voice = context->Voices[pos]; - ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire); + ALvoice *voice = context->Voices[i]; + ALsource *source = voice->Source.load(std::memory_order_acquire); if(source && !source->PropsClean.test_and_set(std::memory_order_acq_rel)) - UpdateSourceProps(source, voice, num_sends, context); + UpdateSourceProps(source, voice, context); } } @@ -3627,8 +3608,7 @@ static ALsource *AllocSource(ALCcontext *context) source = sublist->Sources + slidx; } - source = new (source) ALsource{}; - InitSourceParams(source, device->NumAuxSends); + source = new (source) ALsource{device->NumAuxSends}; /* Add 1 to avoid source ID 0. */ source->id = ((lidx<<6) | slidx) + 1; @@ -3656,7 +3636,6 @@ static void FreeSource(ALCcontext *context, ALsource *source) } ALCdevice_Unlock(device); - DeinitSource(source, device->NumAuxSends); source->~ALsource(); context->SourceList[lidx].FreeMask |= U64(1) << slidx; @@ -3669,7 +3648,6 @@ static void FreeSource(ALCcontext *context, ALsource *source) */ ALvoid ReleaseALSources(ALCcontext *context) { - ALCdevice *device = context->Device; size_t leftover = 0; for(auto &sublist : context->SourceList) { @@ -3679,7 +3657,6 @@ ALvoid ReleaseALSources(ALCcontext *context) ALsizei idx = CTZ64(usemask); ALsource *source = sublist.Sources + idx; - DeinitSource(source, device->NumAuxSends); source->~ALsource(); ++leftover; @@ -3688,5 +3665,5 @@ ALvoid ReleaseALSources(ALCcontext *context) sublist.FreeMask = ~usemask; } if(leftover > 0) - WARN("(%p) Deleted " SZFMT " Source%s\n", device, leftover, (leftover==1)?"":"s"); + WARN("(%p) Deleted " SZFMT " Source%s\n", context, leftover, (leftover==1)?"":"s"); } -- cgit v1.2.3 From dc8ef8264a458282ebad15a6a1b4027cc139cc59 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Nov 2018 12:32:42 -0800 Subject: Try to improve alffplay underrun device time adjustment --- examples/alffplay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index f02fb16b..771e5ded 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -1002,7 +1002,7 @@ int AudioState::handler() ALC_DEVICE_CLOCK_SOFT, 1, &devtime); auto device_time = nanoseconds{devtime}; - mDeviceStartTime = device_time - mCurrentPts; + mDeviceStartTime = device_time - mCurrentPts + AudioBufferTotalTime; } continue; } -- cgit v1.2.3 From d64d64d4a5d62a90b861ab104fd3b787bfd7256a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Nov 2018 22:47:24 -0800 Subject: Use an enum class for AmbiLayout/Norm settings --- Alc/alc.cpp | 40 +++++++++++++++------------------------- Alc/backends/wave.cpp | 4 ++-- Alc/panning.cpp | 8 ++++---- OpenAL32/Include/alMain.h | 26 +++++++++++++------------- 4 files changed, 34 insertions(+), 44 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index d15b6e00..af81dd55 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1847,8 +1847,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(schans == ALC_BFORMAT3D_SOFT) { device->mAmbiOrder = aorder; - device->mAmbiLayout = static_cast(alayout); - device->mAmbiScale = static_cast(ascale); + device->mAmbiLayout = static_cast(alayout); + device->mAmbiScale = static_cast(ascale); } if(numMono > INT_MAX-numStereo) @@ -3189,10 +3189,10 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC if(device->FmtChans == DevFmtAmbi3D) { values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; - values[i++] = device->mAmbiLayout; + values[i++] = static_cast(device->mAmbiLayout); values[i++] = ALC_AMBISONIC_SCALING_SOFT; - values[i++] = device->mAmbiScale; + values[i++] = static_cast(device->mAmbiScale); values[i++] = ALC_AMBISONIC_ORDER_SOFT; values[i++] = device->mAmbiOrder; @@ -3294,7 +3294,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC alcSetError(device, ALC_INVALID_DEVICE); return 0; } - values[0] = device->mAmbiLayout; + values[0] = static_cast(device->mAmbiLayout); return 1; case ALC_AMBISONIC_SCALING_SOFT: @@ -3303,7 +3303,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC alcSetError(device, ALC_INVALID_DEVICE); return 0; } - values[0] = device->mAmbiScale; + values[0] = static_cast(device->mAmbiScale); return 1; case ALC_AMBISONIC_ORDER_SOFT: @@ -3426,10 +3426,10 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, if(device->FmtChans == DevFmtAmbi3D) { values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; - values[i++] = device->mAmbiLayout; + values[i++] = static_cast(device->mAmbiLayout); values[i++] = ALC_AMBISONIC_SCALING_SOFT; - values[i++] = device->mAmbiScale; + values[i++] = static_cast(device->mAmbiScale); values[i++] = ALC_AMBISONIC_ORDER_SOFT; values[i++] = device->mAmbiOrder; @@ -3867,9 +3867,6 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->FmtChans = DevFmtChannelsDefault; device->FmtType = DevFmtTypeDefault; device->Frequency = DEFAULT_OUTPUT_RATE; - device->IsHeadphones = AL_FALSE; - device->mAmbiLayout = AmbiLayout_Default; - device->mAmbiScale = AmbiNorm_Default; device->LimiterState = ALC_TRUE; device->NumUpdates = 3; device->UpdateSize = 1024; @@ -3991,18 +3988,18 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) { if(strcasecmp(fmt, "fuma") == 0) { - device->mAmbiLayout = AmbiLayout_FuMa; - device->mAmbiScale = AmbiNorm_FuMa; + device->mAmbiLayout = AmbiLayout::FuMa; + device->mAmbiScale = AmbiNorm::FuMa; } else if(strcasecmp(fmt, "acn+sn3d") == 0) { - device->mAmbiLayout = AmbiLayout_ACN; - device->mAmbiScale = AmbiNorm_SN3D; + device->mAmbiLayout = AmbiLayout::ACN; + device->mAmbiScale = AmbiNorm::SN3D; } else if(strcasecmp(fmt, "acn+n3d") == 0) { - device->mAmbiLayout = AmbiLayout_ACN; - device->mAmbiScale = AmbiNorm_N3D; + device->mAmbiLayout = AmbiLayout::ACN; + device->mAmbiScale = AmbiNorm::N3D; } else ERR("Unsupported ambi-format: %s\n", fmt); @@ -4011,7 +4008,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) { ALCdevice *head{DeviceList.load()}; do { - ATOMIC_STORE(&device->next, head, almemory_order_relaxed); + device->next.store(head, std::memory_order_relaxed); } while(!DeviceList.compare_exchange_weak(head, device)); } @@ -4104,10 +4101,6 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, return nullptr; } device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_SAMPLE_TYPE_REQUEST; - device->IsHeadphones = AL_FALSE; - device->mAmbiOrder = 0; - device->mAmbiLayout = AmbiLayout_Default; - device->mAmbiScale = AmbiNorm_Default; device->UpdateSize = samples; device->NumUpdates = 1; @@ -4275,9 +4268,6 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->Frequency = DEFAULT_OUTPUT_RATE; device->FmtChans = DevFmtChannelsDefault; device->FmtType = DevFmtTypeDefault; - device->IsHeadphones = AL_FALSE; - device->mAmbiLayout = AmbiLayout_Default; - device->mAmbiScale = AmbiNorm_Default; ConfigValueUInt(nullptr, nullptr, "sources", &device->SourcesMax); if(device->SourcesMax == 0) device->SourcesMax = 256; diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index 83af40a8..d1356338 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -289,8 +289,8 @@ ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break; case DevFmtAmbi3D: /* .amb output requires FuMa */ - device->mAmbiLayout = AmbiLayout_FuMa; - device->mAmbiScale = AmbiNorm_FuMa; + device->mAmbiLayout = AmbiLayout::FuMa; + device->mAmbiScale = AmbiNorm::FuMa; isbformat = 1; chanmask = 0; break; diff --git a/Alc/panning.cpp b/Alc/panning.cpp index aface673..806486a3 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -513,10 +513,10 @@ static void InitPanning(ALCdevice *device) if(device->FmtChans == DevFmtAmbi3D) { const char *devname = device->DeviceName.c_str(); - const ALsizei *acnmap = (device->mAmbiLayout == AmbiLayout_FuMa) ? FuMa2ACN : ACN2ACN; - const ALfloat *n3dscale = (device->mAmbiScale == AmbiNorm_FuMa) ? FuMa2N3DScale : - (device->mAmbiScale == AmbiNorm_SN3D) ? SN3D2N3DScale : - /*(device->mAmbiScale == AmbiNorm_N3D) ?*/ N3D2N3DScale; + const ALsizei *acnmap = (device->mAmbiLayout == AmbiLayout::FuMa) ? FuMa2ACN : ACN2ACN; + const ALfloat *n3dscale = (device->mAmbiScale == AmbiNorm::FuMa) ? FuMa2N3DScale : + (device->mAmbiScale == AmbiNorm::SN3D) ? SN3D2N3DScale : + /*(device->mAmbiScale == AmbiNorm::N3D) ?*/ N3D2N3DScale; ALfloat nfc_delay = 0.0f; count = (device->mAmbiOrder == 3) ? 16 : diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 0770ee89..c7bdcc2a 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -464,19 +464,19 @@ inline ALsizei FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType ty return ChannelsFromDevFmt(chans, ambiorder) * BytesFromDevFmt(type); } -enum AmbiLayout { - AmbiLayout_FuMa = ALC_FUMA_SOFT, /* FuMa channel order */ - AmbiLayout_ACN = ALC_ACN_SOFT, /* ACN channel order */ +enum class AmbiLayout { + FuMa = ALC_FUMA_SOFT, /* FuMa channel order */ + ACN = ALC_ACN_SOFT, /* ACN channel order */ - AmbiLayout_Default = AmbiLayout_ACN + Default = ACN }; -enum AmbiNorm { - AmbiNorm_FuMa = ALC_FUMA_SOFT, /* FuMa normalization */ - AmbiNorm_SN3D = ALC_SN3D_SOFT, /* SN3D normalization */ - AmbiNorm_N3D = ALC_N3D_SOFT, /* N3D normalization */ +enum class AmbiNorm { + FuMa = ALC_FUMA_SOFT, /* FuMa normalization */ + SN3D = ALC_SN3D_SOFT, /* SN3D normalization */ + N3D = ALC_N3D_SOFT, /* N3D normalization */ - AmbiNorm_Default = AmbiNorm_SN3D + Default = SN3D }; @@ -601,13 +601,13 @@ struct ALCdevice_struct { ALuint NumUpdates{}; DevFmtChannels FmtChans{}; DevFmtType FmtType{}; - ALboolean IsHeadphones{}; - ALsizei mAmbiOrder{}; + ALboolean IsHeadphones{AL_FALSE}; + ALsizei mAmbiOrder{0}; /* For DevFmtAmbi* output only, specifies the channel order and * normalization. */ - AmbiLayout mAmbiLayout{}; - AmbiNorm mAmbiScale{}; + AmbiLayout mAmbiLayout{AmbiLayout::Default}; + AmbiNorm mAmbiScale{AmbiNorm::Default}; ALCenum LimiterState{ALC_DONT_CARE_SOFT}; -- cgit v1.2.3 From ed06169569193a081b97b7b37cd1a1d3579f5636 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Nov 2018 23:42:21 -0800 Subject: Use RAII locks with the BackendLock --- Alc/alc.cpp | 270 +++++++++++++++++++++++--------------------------- OpenAL32/alSource.cpp | 12 +-- 2 files changed, 131 insertions(+), 151 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index af81dd55..4527ce85 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -3023,9 +3023,9 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para alcSetError(nullptr, ALC_INVALID_DEVICE); else { - almtx_lock(&Device->BackendLock); - value = (Device->HrtfHandle ? Device->HrtfName.c_str() : ""); - almtx_unlock(&Device->BackendLock); + { std::lock_guard _{Device->BackendLock}; + value = (Device->HrtfHandle ? Device->HrtfName.c_str() : ""); + } ALCdevice_DecRef(Device); } break; @@ -3104,25 +3104,22 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_ALL_ATTRIBUTES: + i = 0; if(size < NumAttrsForDevice(device)) - { alcSetError(device, ALC_INVALID_VALUE); - return 0; + else + { + std::lock_guard _{device->BackendLock}; + values[i++] = ALC_MAJOR_VERSION; + values[i++] = alcMajorVersion; + values[i++] = ALC_MINOR_VERSION; + values[i++] = alcMinorVersion; + values[i++] = ALC_CAPTURE_SAMPLES; + values[i++] = V0(device->Backend,availableSamples)(); + values[i++] = ALC_CONNECTED; + values[i++] = ATOMIC_LOAD(&device->Connected, almemory_order_relaxed); + values[i++] = 0; } - - i = 0; - almtx_lock(&device->BackendLock); - values[i++] = ALC_MAJOR_VERSION; - values[i++] = alcMajorVersion; - values[i++] = ALC_MINOR_VERSION; - values[i++] = alcMinorVersion; - values[i++] = ALC_CAPTURE_SAMPLES; - values[i++] = V0(device->Backend,availableSamples)(); - values[i++] = ALC_CONNECTED; - values[i++] = ATOMIC_LOAD(&device->Connected, almemory_order_relaxed); - almtx_unlock(&device->BackendLock); - - values[i++] = 0; return i; case ALC_MAJOR_VERSION: @@ -3133,13 +3130,13 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_CAPTURE_SAMPLES: - almtx_lock(&device->BackendLock); - values[0] = V0(device->Backend,availableSamples)(); - almtx_unlock(&device->BackendLock); + { std::lock_guard _{device->BackendLock}; + values[0] = V0(device->Backend,availableSamples)(); + } return 1; case ALC_CONNECTED: - values[0] = ATOMIC_LOAD(&device->Connected, almemory_order_acquire); + values[0] = device->Connected.load(std::memory_order_acquire); return 1; default: @@ -3157,77 +3154,75 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_ALL_ATTRIBUTES: + i = 0; if(size < NumAttrsForDevice(device)) - { alcSetError(device, ALC_INVALID_VALUE); - return 0; - } - - i = 0; - almtx_lock(&device->BackendLock); - values[i++] = ALC_MAJOR_VERSION; - values[i++] = alcMajorVersion; - values[i++] = ALC_MINOR_VERSION; - values[i++] = alcMinorVersion; - values[i++] = ALC_EFX_MAJOR_VERSION; - values[i++] = alcEFXMajorVersion; - values[i++] = ALC_EFX_MINOR_VERSION; - values[i++] = alcEFXMinorVersion; - - values[i++] = ALC_FREQUENCY; - values[i++] = device->Frequency; - if(device->Type != Loopback) - { - values[i++] = ALC_REFRESH; - values[i++] = device->Frequency / device->UpdateSize; - - values[i++] = ALC_SYNC; - values[i++] = ALC_FALSE; - } else { - if(device->FmtChans == DevFmtAmbi3D) + std::lock_guard _{device->BackendLock}; + values[i++] = ALC_MAJOR_VERSION; + values[i++] = alcMajorVersion; + values[i++] = ALC_MINOR_VERSION; + values[i++] = alcMinorVersion; + values[i++] = ALC_EFX_MAJOR_VERSION; + values[i++] = alcEFXMajorVersion; + values[i++] = ALC_EFX_MINOR_VERSION; + values[i++] = alcEFXMinorVersion; + + values[i++] = ALC_FREQUENCY; + values[i++] = device->Frequency; + if(device->Type != Loopback) { - values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; - values[i++] = static_cast(device->mAmbiLayout); - - values[i++] = ALC_AMBISONIC_SCALING_SOFT; - values[i++] = static_cast(device->mAmbiScale); + values[i++] = ALC_REFRESH; + values[i++] = device->Frequency / device->UpdateSize; - values[i++] = ALC_AMBISONIC_ORDER_SOFT; - values[i++] = device->mAmbiOrder; + values[i++] = ALC_SYNC; + values[i++] = ALC_FALSE; } + else + { + if(device->FmtChans == DevFmtAmbi3D) + { + values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; + values[i++] = static_cast(device->mAmbiLayout); - values[i++] = ALC_FORMAT_CHANNELS_SOFT; - values[i++] = device->FmtChans; + values[i++] = ALC_AMBISONIC_SCALING_SOFT; + values[i++] = static_cast(device->mAmbiScale); - values[i++] = ALC_FORMAT_TYPE_SOFT; - values[i++] = device->FmtType; - } + values[i++] = ALC_AMBISONIC_ORDER_SOFT; + values[i++] = device->mAmbiOrder; + } + + values[i++] = ALC_FORMAT_CHANNELS_SOFT; + values[i++] = device->FmtChans; + + values[i++] = ALC_FORMAT_TYPE_SOFT; + values[i++] = device->FmtType; + } - values[i++] = ALC_MONO_SOURCES; - values[i++] = device->NumMonoSources; + values[i++] = ALC_MONO_SOURCES; + values[i++] = device->NumMonoSources; - values[i++] = ALC_STEREO_SOURCES; - values[i++] = device->NumStereoSources; + values[i++] = ALC_STEREO_SOURCES; + values[i++] = device->NumStereoSources; - values[i++] = ALC_MAX_AUXILIARY_SENDS; - values[i++] = device->NumAuxSends; + values[i++] = ALC_MAX_AUXILIARY_SENDS; + values[i++] = device->NumAuxSends; - values[i++] = ALC_HRTF_SOFT; - values[i++] = (device->HrtfHandle ? ALC_TRUE : ALC_FALSE); + values[i++] = ALC_HRTF_SOFT; + values[i++] = (device->HrtfHandle ? ALC_TRUE : ALC_FALSE); - values[i++] = ALC_HRTF_STATUS_SOFT; - values[i++] = device->HrtfStatus; + values[i++] = ALC_HRTF_STATUS_SOFT; + values[i++] = device->HrtfStatus; - values[i++] = ALC_OUTPUT_LIMITER_SOFT; - values[i++] = device->Limiter ? ALC_TRUE : ALC_FALSE; + values[i++] = ALC_OUTPUT_LIMITER_SOFT; + values[i++] = device->Limiter ? ALC_TRUE : ALC_FALSE; - values[i++] = ALC_MAX_AMBISONIC_ORDER_SOFT; - values[i++] = MAX_AMBI_ORDER; - almtx_unlock(&device->BackendLock); + values[i++] = ALC_MAX_AMBISONIC_ORDER_SOFT; + values[i++] = MAX_AMBI_ORDER; - values[i++] = 0; + values[i++] = 0; + } return i; case ALC_MAJOR_VERSION: @@ -3256,9 +3251,9 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC alcSetError(device, ALC_INVALID_DEVICE); return 0; } - almtx_lock(&device->BackendLock); - values[0] = device->Frequency / device->UpdateSize; - almtx_unlock(&device->BackendLock); + { std::lock_guard _{device->BackendLock}; + values[0] = device->Frequency / device->UpdateSize; + } return 1; case ALC_SYNC: @@ -3328,7 +3323,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_CONNECTED: - values[0] = ATOMIC_LOAD(&device->Connected, almemory_order_acquire); + values[0] = device->Connected.load(std::memory_order_acquire); return 1; case ALC_HRTF_SOFT: @@ -3340,11 +3335,11 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_NUM_HRTF_SPECIFIERS_SOFT: - almtx_lock(&device->BackendLock); - device->HrtfList.clear(); - device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); - values[0] = (ALCint)device->HrtfList.size(); - almtx_unlock(&device->BackendLock); + { std::lock_guard _{device->BackendLock}; + device->HrtfList.clear(); + device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); + values[0] = (ALCint)device->HrtfList.size(); + } return 1; case ALC_OUTPUT_LIMITER_SOFT: @@ -3378,8 +3373,6 @@ ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsi ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALCsizei size, ALCint64SOFT *values) { - ALsizei i; - VerifyDevice(&device); if(size <= 0 || values == nullptr) alcSetError(device, ALC_INVALID_VALUE); @@ -3387,16 +3380,10 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, { std::vector ivals(size); size = GetIntegerv(device, pname, size, ivals.data()); - for(i = 0;i < size;i++) - values[i] = ivals[i]; + std::copy(ivals.begin(), ivals.begin()+size, values); } else /* render device */ { - ClockLatency clock; - ALuint64 basecount; - ALuint samplecount; - ALuint refcount; - switch(pname) { case ALC_ATTRIBUTES_SIZE: @@ -3408,8 +3395,8 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, alcSetError(device, ALC_INVALID_VALUE); else { - i = 0; - almtx_lock(&device->BackendLock); + ALsizei i{0}; + std::lock_guard _{device->BackendLock}; values[i++] = ALC_FREQUENCY; values[i++] = device->Frequency; @@ -3460,35 +3447,37 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, values[i++] = ALC_OUTPUT_LIMITER_SOFT; values[i++] = device->Limiter ? ALC_TRUE : ALC_FALSE; - clock = GetClockLatency(device); + ClockLatency clock{GetClockLatency(device)}; values[i++] = ALC_DEVICE_CLOCK_SOFT; values[i++] = clock.ClockTime; values[i++] = ALC_DEVICE_LATENCY_SOFT; values[i++] = clock.Latency; - almtx_unlock(&device->BackendLock); values[i++] = 0; } break; case ALC_DEVICE_CLOCK_SOFT: - almtx_lock(&device->BackendLock); - do { - while(((refcount=ReadRef(&device->MixCount))&1) != 0) - althrd_yield(); - basecount = device->ClockBase; - samplecount = device->SamplesDone; - } while(refcount != ReadRef(&device->MixCount)); - *values = basecount + (samplecount*DEVICE_CLOCK_RES/device->Frequency); - almtx_unlock(&device->BackendLock); + { std::lock_guard _{device->BackendLock}; + ALuint64 basecount; + ALuint samplecount; + ALuint refcount; + do { + while(((refcount=ReadRef(&device->MixCount))&1) != 0) + althrd_yield(); + basecount = device->ClockBase; + samplecount = device->SamplesDone; + } while(refcount != ReadRef(&device->MixCount)); + *values = basecount + (samplecount*DEVICE_CLOCK_RES/device->Frequency); + } break; case ALC_DEVICE_LATENCY_SOFT: - almtx_lock(&device->BackendLock); - clock = GetClockLatency(device); - almtx_unlock(&device->BackendLock); - *values = clock.Latency; + { std::lock_guard _{device->BackendLock}; + ClockLatency clock{GetClockLatency(device)}; + *values = clock.Latency; + } break; case ALC_DEVICE_CLOCK_LATENCY_SOFT: @@ -3496,9 +3485,8 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, alcSetError(device, ALC_INVALID_VALUE); else { - almtx_lock(&device->BackendLock); - clock = GetClockLatency(device); - almtx_unlock(&device->BackendLock); + std::lock_guard _{device->BackendLock}; + ClockLatency clock{GetClockLatency(device)}; values[0] = clock.ClockTime; values[1] = clock.Latency; } @@ -3507,8 +3495,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, default: std::vector ivals(size); size = GetIntegerv(device, pname, size, ivals.data()); - for(i = 0;i < size;i++) - values[i] = ivals[i]; + std::copy(ivals.begin(), ivals.begin()+size, values); break; } } @@ -3640,7 +3627,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin if(device) ALCdevice_DecRef(device); return nullptr; } - almtx_lock(&device->BackendLock); + std::unique_lock backlock{device->BackendLock}; listlock.unlock(); ATOMIC_STORE_SEQ(&device->LastError, ALC_NO_ERROR); @@ -3650,7 +3637,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin if((err=UpdateDeviceParams(device, attrList)) != ALC_NO_ERROR) { - almtx_unlock(&device->BackendLock); + backlock.unlock(); delete ALContext; ALContext = nullptr; @@ -3702,7 +3689,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ATOMIC_STORE(&ALContext->next, head, almemory_order_relaxed); } while(!device->ContextList.compare_exchange_weak(head, ALContext)); } - almtx_unlock(&device->BackendLock); + backlock.unlock(); if(ALContext->DefaultSlot) { @@ -3735,13 +3722,12 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) ALCdevice* Device{context->Device}; if(Device) { - almtx_lock(&Device->BackendLock); + std::lock_guard _{Device->BackendLock}; if(!ReleaseContext(context, Device)) { V0(Device->Backend,stop)(); Device->Flags &= ~DEVICE_RUNNING; } - almtx_unlock(&Device->BackendLock); } listlock.unlock(); @@ -4034,7 +4020,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) alcSetError(iter, ALC_INVALID_DEVICE); return ALC_FALSE; } - almtx_lock(&device->BackendLock); + std::unique_lock backlock{device->BackendLock}; ALCdevice *origdev{device}; ALCdevice *nextdev{ATOMIC_LOAD(&device->next, almemory_order_relaxed)}; @@ -4059,7 +4045,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) if((device->Flags&DEVICE_RUNNING)) V0(device->Backend,stop)(); device->Flags &= ~DEVICE_RUNNING; - almtx_unlock(&device->BackendLock); + backlock.unlock(); ALCdevice_DecRef(device); @@ -4164,11 +4150,11 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) } listlock.unlock(); - almtx_lock(&device->BackendLock); - if((device->Flags&DEVICE_RUNNING)) - V0(device->Backend,stop)(); - device->Flags &= ~DEVICE_RUNNING; - almtx_unlock(&device->BackendLock); + { std::lock_guard _{device->BackendLock}; + if((device->Flags&DEVICE_RUNNING)) + V0(device->Backend,stop)(); + device->Flags &= ~DEVICE_RUNNING; + } ALCdevice_DecRef(device); @@ -4181,7 +4167,7 @@ ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) alcSetError(device, ALC_INVALID_DEVICE); else { - almtx_lock(&device->BackendLock); + std::lock_guard _{device->BackendLock}; if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) alcSetError(device, ALC_INVALID_DEVICE); else if(!(device->Flags&DEVICE_RUNNING)) @@ -4194,7 +4180,6 @@ ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) alcSetError(device, ALC_INVALID_DEVICE); } } - almtx_unlock(&device->BackendLock); } if(device) ALCdevice_DecRef(device); @@ -4206,11 +4191,10 @@ ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) alcSetError(device, ALC_INVALID_DEVICE); else { - almtx_lock(&device->BackendLock); + std::lock_guard _{device->BackendLock}; if((device->Flags&DEVICE_RUNNING)) V0(device->Backend,stop)(); device->Flags &= ~DEVICE_RUNNING; - almtx_unlock(&device->BackendLock); } if(device) ALCdevice_DecRef(device); @@ -4223,12 +4207,10 @@ ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, else { ALCenum err = ALC_INVALID_VALUE; - - almtx_lock(&device->BackendLock); - if(samples >= 0 && V0(device->Backend,availableSamples)() >= (ALCuint)samples) - err = V(device->Backend,captureSamples)(buffer, samples); - almtx_unlock(&device->BackendLock); - + { std::lock_guard _{device->BackendLock}; + if(samples >= 0 && V0(device->Backend,availableSamples)() >= (ALCuint)samples) + err = V(device->Backend,captureSamples)(buffer, samples); + } if(err != ALC_NO_ERROR) alcSetError(device, err); } @@ -4364,12 +4346,11 @@ ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device) alcSetError(device, ALC_INVALID_DEVICE); else { - almtx_lock(&device->BackendLock); + std::lock_guard _{device->BackendLock}; if((device->Flags&DEVICE_RUNNING)) V0(device->Backend,stop)(); device->Flags &= ~DEVICE_RUNNING; device->Flags |= DEVICE_PAUSED; - almtx_unlock(&device->BackendLock); } if(device) ALCdevice_DecRef(device); } @@ -4384,7 +4365,7 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) alcSetError(device, ALC_INVALID_DEVICE); else { - almtx_lock(&device->BackendLock); + std::lock_guard _{device->BackendLock}; if((device->Flags&DEVICE_PAUSED)) { device->Flags &= ~DEVICE_PAUSED; @@ -4401,7 +4382,6 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) } } } - almtx_unlock(&device->BackendLock); } if(device) ALCdevice_DecRef(device); } @@ -4454,11 +4434,11 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi if(device) ALCdevice_DecRef(device); return ALC_FALSE; } - almtx_lock(&device->BackendLock); + std::unique_lock backlock{device->BackendLock}; listlock.unlock(); ALCenum err{UpdateDeviceParams(device, attribs)}; - almtx_unlock(&device->BackendLock); + backlock.unlock(); if(err != ALC_NO_ERROR) { diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 56895e77..783a9d82 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -1293,9 +1293,9 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p * clock time with the device latency. Order is important. */ values[0] = GetSourceSecOffset(Source, Context, &srcclock); - almtx_lock(&device->BackendLock); - clocktime = GetClockLatency(device); - almtx_unlock(&device->BackendLock); + { std::lock_guard _{device->BackendLock}; + clocktime = GetClockLatency(device); + } if(srcclock == (ALuint64)clocktime.ClockTime) values[1] = (ALdouble)clocktime.Latency / 1000000000.0; else @@ -1556,9 +1556,9 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp * clock time with the device latency. Order is important. */ values[0] = GetSourceSampleOffset(Source, Context, &srcclock); - almtx_lock(&device->BackendLock); - clocktime = GetClockLatency(device); - almtx_unlock(&device->BackendLock); + { std::lock_guard _{device->BackendLock}; + clocktime = GetClockLatency(device); + } if(srcclock == (ALuint64)clocktime.ClockTime) values[1] = clocktime.Latency; else -- cgit v1.2.3 From 8ec25da12ec41b1277c9f68390bd5ab29bbcbc52 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Nov 2018 00:40:41 -0800 Subject: Rename a method to be clearer about its behavior --- Alc/alcontext.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 4a056597..1d66ffc6 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -148,7 +148,7 @@ inline void UnlockEffectSlotList(ALCcontext *context) class ContextRef { ALCcontext *mCtx{nullptr}; - void release() noexcept + void reset() noexcept { if(mCtx) ALCcontext_DecRef(mCtx); @@ -158,12 +158,12 @@ class ContextRef { public: ContextRef() noexcept = default; explicit ContextRef(ALCcontext *ctx) noexcept : mCtx(ctx) { } - ~ContextRef() { release(); } + ~ContextRef() { reset(); } ContextRef& operator=(const ContextRef&) = delete; ContextRef& operator=(ContextRef&& rhs) noexcept { - release(); + reset(); mCtx = rhs.mCtx; rhs.mCtx = nullptr; return *this; -- cgit v1.2.3 From 4c64fa1e4e11f39f7b6634e24dee13bb7434927c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Nov 2018 02:02:53 -0800 Subject: Make VerifyContext return a context reference --- Alc/alc.cpp | 97 ++++++++++++++++++++++++++++++--------------------------- Alc/alcontext.h | 9 ++++++ 2 files changed, 60 insertions(+), 46 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 4527ce85..fa909091 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2727,29 +2727,28 @@ static void ReleaseThreadCtx(ALCcontext *context) /* VerifyContext * - * Checks that the given context is valid, and increments its reference count. + * Checks if the given context is valid, returning a new reference to it if so. */ -static ALCboolean VerifyContext(ALCcontext **context) +static ContextRef VerifyContext(ALCcontext *context) { std::lock_guard _{ListLock}; ALCdevice *dev{DeviceList.load()}; while(dev) { - ALCcontext *ctx = ATOMIC_LOAD(&dev->ContextList, almemory_order_acquire); + ALCcontext *ctx = dev->ContextList.load(std::memory_order_acquire); while(ctx) { - if(ctx == *context) + if(ctx == context) { ALCcontext_IncRef(ctx); - return ALC_TRUE; + return ContextRef{ctx}; } - ctx = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed); + ctx = ctx->next.load(std::memory_order_relaxed); } - dev = ATOMIC_LOAD(&dev->next, almemory_order_relaxed); + dev = dev->next.load(std::memory_order_relaxed); } - *context = nullptr; - return ALC_FALSE; + return ContextRef{}; } @@ -2893,13 +2892,11 @@ ALC_API ALCvoid ALC_APIENTRY alcSuspendContext(ALCcontext *context) if(!SuspendDefers) return; - if(!VerifyContext(&context)) + ContextRef ctx{VerifyContext(context)}; + if(!ctx) alcSetError(nullptr, ALC_INVALID_CONTEXT); else - { - ALCcontext_DeferUpdates(context); - ALCcontext_DecRef(context); - } + ALCcontext_DeferUpdates(ctx.get()); } /* alcProcessContext @@ -2911,13 +2908,11 @@ ALC_API ALCvoid ALC_APIENTRY alcProcessContext(ALCcontext *context) if(!SuspendDefers) return; - if(!VerifyContext(&context)) + ContextRef ctx{VerifyContext(context)}; + if(!ctx) alcSetError(nullptr, ALC_INVALID_CONTEXT); else - { - ALCcontext_ProcessUpdates(context); - ALCcontext_DecRef(context); - } + ALCcontext_ProcessUpdates(ctx.get()); } @@ -3712,26 +3707,25 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) { std::unique_lock listlock{ListLock}; - if(!VerifyContext(&context)) + ContextRef ctx{VerifyContext(context)}; + if(!ctx) { listlock.unlock(); alcSetError(nullptr, ALC_INVALID_CONTEXT); return; } - ALCdevice* Device{context->Device}; + ALCdevice* Device{ctx->Device}; if(Device) { std::lock_guard _{Device->BackendLock}; - if(!ReleaseContext(context, Device)) + if(!ReleaseContext(ctx.get(), Device)) { V0(Device->Backend,stop)(); Device->Flags &= ~DEVICE_RUNNING; } } listlock.unlock(); - - ALCcontext_DecRef(context); } @@ -3764,20 +3758,29 @@ ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) { /* context must be valid or nullptr */ - if(context && !VerifyContext(&context)) + ContextRef ctx; + if(context) { - alcSetError(nullptr, ALC_INVALID_CONTEXT); - return ALC_FALSE; + ctx = VerifyContext(context); + if(!ctx) + { + alcSetError(nullptr, ALC_INVALID_CONTEXT); + return ALC_FALSE; + } } - /* context's reference count is already incremented */ - context = GlobalContext.exchange(context); - if(context) ALCcontext_DecRef(context); + /* Release this reference (if any) to store it in the GlobalContext + * pointer. Take ownership of the reference (if any) that was previously + * stored there. + */ + ctx = ContextRef{GlobalContext.exchange(ctx.release())}; - if((context=LocalContext.get()) != nullptr) - { - LocalContext.set(nullptr); - ALCcontext_DecRef(context); - } + /* Reset (decrement) the previous global reference by replacing it with the + * thread-local context. Take ownership of the thread-local context + * reference (if any), clearing the storage to null. + */ + ctx = ContextRef{LocalContext.get()}; + if(ctx) LocalContext.set(nullptr); + /* Reset (decrement) the previous thread-local reference. */ return ALC_TRUE; } @@ -3789,15 +3792,19 @@ ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) { /* context must be valid or nullptr */ - if(context && !VerifyContext(&context)) + ContextRef ctx; + if(context) { - alcSetError(nullptr, ALC_INVALID_CONTEXT); - return ALC_FALSE; + ctx = VerifyContext(context); + if(!ctx) + { + alcSetError(nullptr, ALC_INVALID_CONTEXT); + return ALC_FALSE; + } } /* context's reference count is already incremented */ - ALCcontext *old{LocalContext.get()}; - LocalContext.set(context); - if(old) ALCcontext_DecRef(old); + ContextRef old{LocalContext.get()}; + LocalContext.set(ctx.release()); return ALC_TRUE; } @@ -3809,15 +3816,13 @@ ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) */ ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *Context) { - if(!VerifyContext(&Context)) + ContextRef ctx{VerifyContext(Context)}; + if(!ctx) { alcSetError(nullptr, ALC_INVALID_CONTEXT); return nullptr; } - ALCdevice *Device{Context->Device}; - ALCcontext_DecRef(Context); - - return Device; + return ctx->Device; } diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 1d66ffc6..26616f18 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -157,6 +157,8 @@ class ContextRef { public: ContextRef() noexcept = default; + ContextRef(ContextRef&& rhs) noexcept : mCtx{rhs.mCtx} + { rhs.mCtx = nullptr; } explicit ContextRef(ALCcontext *ctx) noexcept : mCtx(ctx) { } ~ContextRef() { reset(); } @@ -173,6 +175,13 @@ public: ALCcontext* operator->() noexcept { return mCtx; } ALCcontext* get() noexcept { return mCtx; } + + ALCcontext* release() noexcept + { + ALCcontext *ret{mCtx}; + mCtx = nullptr; + return ret; + } }; -- cgit v1.2.3 From 757c42c74bb1f88dfc6f24200382a0ea741fccac Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Nov 2018 05:06:31 -0800 Subject: Use a normal vector for the distance buffer storage --- Alc/alc.cpp | 16 ++-------------- Alc/alu.cpp | 37 ++++++++++++++++++------------------- Alc/panning.cpp | 11 +++-------- OpenAL32/Include/alMain.h | 35 +++++++++++++++++++++++++++++------ 4 files changed, 52 insertions(+), 47 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index fa909091..fa7b9f44 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1994,12 +1994,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) al_free(device->Bs2b); device->Bs2b = nullptr; - al_free(device->ChannelDelay[0].Buffer); - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - { - device->ChannelDelay[i].Length = 0; - device->ChannelDelay[i].Buffer = nullptr; - } + device->ChannelDelay.clear(); + device->ChannelDelay.shrink_to_fit(); device->Dry.Buffer = nullptr; device->Dry.NumChannels = 0; @@ -2445,14 +2441,6 @@ ALCdevice_struct::~ALCdevice_struct() al_free(Limiter); Limiter = nullptr; - - al_free(ChannelDelay[0].Buffer); - for(ALsizei i{0};i < MAX_OUTPUT_CHANNELS;i++) - { - ChannelDelay[i].Gain = 1.0f; - ChannelDelay[i].Length = 0; - ChannelDelay[i].Buffer = nullptr; - } } diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 68387f7b..faa011a2 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -26,6 +26,8 @@ #include #include +#include + #include "alMain.h" #include "alcontext.h" #include "alSource.h" @@ -1568,12 +1570,10 @@ void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*RESTRICT Buffer)[BUFFER } } -void ApplyDistanceComp(ALfloat (*RESTRICT Samples)[BUFFERSIZE], DistanceComp *distcomp, +void ApplyDistanceComp(ALfloat (*RESTRICT Samples)[BUFFERSIZE], const DistanceComp &distcomp, ALfloat *RESTRICT Values, ALsizei SamplesToDo, ALsizei numchans) { - ALsizei i, c; - - for(c = 0;c < numchans;c++) + for(ALsizei c{0};c < numchans;c++) { ALfloat *RESTRICT inout = Samples[c]; const ALfloat gain = distcomp[c].Gain; @@ -1583,30 +1583,29 @@ void ApplyDistanceComp(ALfloat (*RESTRICT Samples)[BUFFERSIZE], DistanceComp *di if(base == 0) { if(gain < 1.0f) - { - for(i = 0;i < SamplesToDo;i++) - inout[i] *= gain; - } + std::for_each(inout, inout+SamplesToDo, + [gain](ALfloat &in) noexcept -> void + { in *= gain; } + ); continue; } if(LIKELY(SamplesToDo >= base)) { - for(i = 0;i < base;i++) - Values[i] = distbuf[i]; - for(;i < SamplesToDo;i++) - Values[i] = inout[i-base]; - memcpy(distbuf, &inout[SamplesToDo-base], base*sizeof(ALfloat)); + auto out = std::copy_n(distbuf, base, Values); + std::copy_n(inout, SamplesToDo-base, out); + std::copy_n(inout+SamplesToDo-base, base, distbuf); } else { - for(i = 0;i < SamplesToDo;i++) - Values[i] = distbuf[i]; - memmove(distbuf, distbuf+SamplesToDo, (base-SamplesToDo)*sizeof(ALfloat)); - memcpy(distbuf+base-SamplesToDo, inout, SamplesToDo*sizeof(ALfloat)); + std::copy_n(distbuf, SamplesToDo, Values); + auto out = std::copy(distbuf+SamplesToDo, distbuf+base, distbuf); + std::copy_n(inout, SamplesToDo, out); } - for(i = 0;i < SamplesToDo;i++) - inout[i] = Values[i]*gain; + std::transform(Values, Values+SamplesToDo, inout, + [gain](ALfloat in) noexcept -> ALfloat + { return in * gain; } + ); } } diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 806486a3..f538e347 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -445,8 +445,8 @@ static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const AL if(total > 0) { - device->ChannelDelay[0].Buffer = reinterpret_cast( - al_calloc(16, total * sizeof(ALfloat))); + device->ChannelDelay.resize(total); + device->ChannelDelay[0].Buffer = device->ChannelDelay.data(); for(i = 1;i < MAX_OUTPUT_CHANNELS;i++) { size_t len = RoundUp(device->ChannelDelay[i-1].Length, 4); @@ -943,12 +943,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf device->NumChannelsPerOrder[i] = 0; device->AvgSpeakerDist = 0.0f; - memset(device->ChannelDelay, 0, sizeof(device->ChannelDelay)); - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - { - device->ChannelDelay[i].Gain = 1.0f; - device->ChannelDelay[i].Length = 0; - } + device->ChannelDelay.clear(); al_free(device->Stablizer); device->Stablizer = NULL; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index c7bdcc2a..e6ad849e 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -556,11 +556,34 @@ typedef struct EnumeratedHrtf { /* Maximum delay in samples for speaker distance compensation. */ #define MAX_DELAY_LENGTH 1024 -typedef struct DistanceComp { - ALfloat Gain{1.0f}; - ALsizei Length{0}; /* Valid range is [0...MAX_DELAY_LENGTH). */ - ALfloat *Buffer{nullptr}; -} DistanceComp; +class DistanceComp { + struct DistData { + ALfloat Gain{1.0f}; + ALsizei Length{0}; /* Valid range is [0...MAX_DELAY_LENGTH). */ + ALfloat *Buffer{nullptr}; + } mChannel[MAX_OUTPUT_CHANNELS]; + al::vector mSamples; + +public: + void resize(size_t amt) { mSamples.resize(amt); } + void shrink_to_fit() { mSamples.shrink_to_fit(); } + void clear() noexcept + { + for(auto &chan : mChannel) + { + chan.Gain = 1.0f; + chan.Length = 0; + chan.Buffer = nullptr; + } + mSamples.clear(); + } + + ALfloat *data() noexcept { return mSamples.data(); } + const ALfloat *data() const noexcept { return mSamples.data(); } + + DistData& operator[](size_t o) noexcept { return mChannel[o]; } + const DistData& operator[](size_t o) const noexcept { return mChannel[o]; } +}; /* Size for temporary storage of buffer data, in ALfloats. Larger values need * more memory, while smaller values may need more iterations. The value needs @@ -695,7 +718,7 @@ struct ALCdevice_struct { ALfloat AvgSpeakerDist{0.0f}; /* Delay buffers used to compensate for speaker distances. */ - DistanceComp ChannelDelay[MAX_OUTPUT_CHANNELS]; + DistanceComp ChannelDelay; /* Dithering control. */ ALfloat DitherDepth{0.0f}; -- cgit v1.2.3 From 75213ee6f951355906bd1744a2936bb764f23e40 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Nov 2018 05:35:47 -0800 Subject: Always use RAII with EffectSlotLock --- Alc/alc.cpp | 4 ++-- Alc/alcontext.h | 5 ----- OpenAL32/alSource.cpp | 10 +++++----- common/threads.h | 5 +++-- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index fa7b9f44..28c9bc6f 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2263,7 +2263,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } almtx_lock(&context->PropLock); - almtx_lock(&context->EffectSlotLock); + std::unique_lock slotlock{context->EffectSlotLock}; for(auto &slot : context->EffectSlotList) { EffectState *state = slot->Effect.State; @@ -2275,7 +2275,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) else UpdateEffectSlotProps(slot.get(), context); } - almtx_unlock(&context->EffectSlotLock); + slotlock.unlock(); almtx_lock(&context->SourceLock); for(auto &sublist : context->SourceList) diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 26616f18..c9cfa985 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -135,11 +135,6 @@ void UpdateContextProps(ALCcontext *context); void ALCcontext_DeferUpdates(ALCcontext *context); void ALCcontext_ProcessUpdates(ALCcontext *context); -inline void LockEffectSlotList(ALCcontext *context) -{ almtx_lock(&context->EffectSlotLock); } -inline void UnlockEffectSlotList(ALCcontext *context) -{ almtx_unlock(&context->EffectSlotLock); } - /* Simple RAII context reference. Takes the reference of the provided * ALCcontext, and decrements it when leaving scope. Movable (transfer diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 783a9d82..3a7bc4f0 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -755,6 +755,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p ALfilter *filter = NULL; ALeffectslot *slot = NULL; ALbufferlistitem *oldlist; + std::unique_lock slotlock; ALfloat fvals[6]; switch(prop) @@ -980,23 +981,23 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_AUXILIARY_SEND_FILTER: - LockEffectSlotList(Context); + slotlock = std::unique_lock{Context->EffectSlotLock}; if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL)) { - UnlockEffectSlotList(Context); + slotlock.unlock(); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid effect ID %u", values[0]); } if((ALuint)values[1] >= (ALuint)device->NumAuxSends) { - UnlockEffectSlotList(Context); + slotlock.unlock(); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid send %u", values[1]); } LockFilterList(device); if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)) { UnlockFilterList(device); - UnlockEffectSlotList(Context); + slotlock.unlock(); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", values[2]); } @@ -1045,7 +1046,6 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->Send[values[1]].Slot = slot; DO_UPDATEPROPS(); } - UnlockEffectSlotList(Context); return AL_TRUE; diff --git a/common/threads.h b/common/threads.h index 0b53c38f..8fd1093d 100644 --- a/common/threads.h +++ b/common/threads.h @@ -137,7 +137,7 @@ public: using mutex_type = almtx_t; explicit lock_guard(almtx_t &mtx) : mMtx(mtx) { almtx_lock(&mMtx); } - lock_guard(almtx_t &mtx, std::adopt_lock_t) : mMtx(mtx) { } + lock_guard(almtx_t &mtx, std::adopt_lock_t) noexcept : mMtx(mtx) { } ~lock_guard() { almtx_unlock(&mMtx); } lock_guard(const lock_guard&) = delete; @@ -152,8 +152,9 @@ class unique_lock { public: using mutex_type = almtx_t; + unique_lock() noexcept = default; explicit unique_lock(almtx_t &mtx) : mMtx(&mtx) { almtx_lock(mMtx); mLocked = true; } - unique_lock(unique_lock&& rhs) : mMtx(rhs.mMtx), mLocked(rhs.mLocked) + unique_lock(unique_lock&& rhs) noexcept : mMtx(rhs.mMtx), mLocked(rhs.mLocked) { rhs.mMtx = nullptr; rhs.mLocked = false; } ~unique_lock() { if(mLocked) almtx_unlock(mMtx); } -- cgit v1.2.3 From de4bb7aca10e6f206b82385b78312fdd86301a62 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Nov 2018 06:41:49 -0800 Subject: Replace a couple more almtx_lock/unlock calls --- Alc/alc.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 28c9bc6f..1979f33b 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1613,7 +1613,7 @@ void ALCcontext_DeferUpdates(ALCcontext *context) */ void ALCcontext_ProcessUpdates(ALCcontext *context) { - almtx_lock(&context->PropLock); + std::lock_guard _{context->PropLock}; if(context->DeferUpdates.exchange(false)) { /* Tell the mixer to stop applying updates, then wait for any active @@ -1635,7 +1635,6 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) */ ATOMIC_STORE_SEQ(&context->HoldUpdates, AL_FALSE); } - almtx_unlock(&context->PropLock); } @@ -2262,7 +2261,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) UpdateEffectSlotProps(slot, context); } - almtx_lock(&context->PropLock); + std::unique_lock proplock{context->PropLock}; std::unique_lock slotlock{context->EffectSlotLock}; for(auto &slot : context->EffectSlotList) { @@ -2277,7 +2276,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } slotlock.unlock(); - almtx_lock(&context->SourceLock); + std::unique_lock srclock{context->SourceLock}; for(auto &sublist : context->SourceList) { uint64_t usemask = ~sublist.FreeMask; @@ -2345,14 +2344,13 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) NfcFilterCreate(&voice->Direct.Params[i].NFCtrlFilter, 0.0f, w1); } } - almtx_unlock(&context->SourceLock); + srclock.unlock(); context->PropsClean.test_and_set(std::memory_order_release); UpdateContextProps(context); context->Listener.PropsClean.test_and_set(std::memory_order_release); UpdateListenerProps(context); UpdateAllSourceProps(context); - almtx_unlock(&context->PropLock); context = ATOMIC_LOAD(&context->next, almemory_order_relaxed); } -- cgit v1.2.3 From 8f43f737ba5f0ed32a37498f6787c34257a3f796 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Nov 2018 07:52:17 -0800 Subject: Avoid using ATOMIC macros --- Alc/alc.cpp | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 1979f33b..5c46b950 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1233,7 +1233,7 @@ static void alc_cleanup(void) ALCuint num = 0; do { num++; - dev = ATOMIC_LOAD(&dev->next, almemory_order_relaxed); + dev = dev->next.load(std::memory_order_relaxed); } while(dev != nullptr); ERR("%u device%s not closed\n", num, (num>1)?"s":""); } @@ -1619,8 +1619,8 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) /* Tell the mixer to stop applying updates, then wait for any active * updating to finish, before providing updates. */ - ATOMIC_STORE_SEQ(&context->HoldUpdates, AL_TRUE); - while((ATOMIC_LOAD(&context->UpdateCount, almemory_order_acquire)&1) != 0) + context->HoldUpdates.store(AL_TRUE); + while((context->UpdateCount.load(std::memory_order_acquire)&1) != 0) althrd_yield(); if(!context->PropsClean.test_and_set(std::memory_order_acq_rel)) @@ -1633,7 +1633,7 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) /* Now with all updates declared, let the mixer continue applying them * so they all happen at once. */ - ATOMIC_STORE_SEQ(&context->HoldUpdates, AL_FALSE); + context->HoldUpdates.store(AL_FALSE); } } @@ -1657,7 +1657,7 @@ static void alcSetError(ALCdevice *device, ALCenum errorCode) } if(device) - ATOMIC_STORE_SEQ(&device->LastError, errorCode); + device->LastError.store(errorCode); else LastNullDeviceError.store(errorCode); } @@ -2242,7 +2242,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) */ update_failed = AL_FALSE; START_MIXER_MODE(); - context = ATOMIC_LOAD_SEQ(&device->ContextList); + context = device->ContextList.load(); while(context) { struct ALvoiceProps *vprops; @@ -2352,7 +2352,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) UpdateListenerProps(context); UpdateAllSourceProps(context); - context = ATOMIC_LOAD(&context->next, almemory_order_relaxed); + context = context->next.load(std::memory_order_relaxed); } END_MIXER_MODE(); if(update_failed) @@ -2470,7 +2470,7 @@ static ALCboolean VerifyDevice(ALCdevice **device) ALCdevice_IncRef(tmpDevice); return ALC_TRUE; } - tmpDevice = ATOMIC_LOAD(&tmpDevice->next, almemory_order_relaxed); + tmpDevice = tmpDevice->next.load(std::memory_order_relaxed); } *device = nullptr; @@ -2664,7 +2664,7 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) V0(device->Backend,lock)(); origctx = context; - newhead = ATOMIC_LOAD(&context->next, almemory_order_relaxed); + newhead = context->next.load(std::memory_order_relaxed); if(!device->ContextList.compare_exchange_strong(origctx, newhead)) { ALCcontext *list; @@ -3098,7 +3098,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC values[i++] = ALC_CAPTURE_SAMPLES; values[i++] = V0(device->Backend,availableSamples)(); values[i++] = ALC_CONNECTED; - values[i++] = ATOMIC_LOAD(&device->Connected, almemory_order_relaxed); + values[i++] = device->Connected.load(std::memory_order_relaxed); values[i++] = 0; } return i; @@ -3601,7 +3601,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin */ std::unique_lock listlock{ListLock}; if(!VerifyDevice(&device) || device->Type == Capture || - !ATOMIC_LOAD(&device->Connected, almemory_order_relaxed)) + !device->Connected.load(std::memory_order_relaxed)) { listlock.unlock(); alcSetError(device, ALC_INVALID_DEVICE); @@ -3611,7 +3611,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin std::unique_lock backlock{device->BackendLock}; listlock.unlock(); - ATOMIC_STORE_SEQ(&device->LastError, ALC_NO_ERROR); + device->LastError.store(ALC_NO_ERROR); ALContext = new ALCcontext{device}; ALCdevice_IncRef(ALContext->Device); @@ -3665,9 +3665,9 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin UpdateListenerProps(ALContext); { - ALCcontext *head = ATOMIC_LOAD_SEQ(&device->ContextList); + ALCcontext *head = device->ContextList.load(); do { - ATOMIC_STORE(&ALContext->next, head, almemory_order_relaxed); + ALContext->next.store(head, std::memory_order_relaxed); } while(!device->ContextList.compare_exchange_weak(head, ALContext)); } backlock.unlock(); @@ -4004,7 +4004,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) do { if(iter == device) break; - iter = ATOMIC_LOAD(&iter->next, almemory_order_relaxed); + iter = iter->next.load(std::memory_order_relaxed); } while(iter != nullptr); if(!iter || iter->Type == Capture) { @@ -4014,7 +4014,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) std::unique_lock backlock{device->BackendLock}; ALCdevice *origdev{device}; - ALCdevice *nextdev{ATOMIC_LOAD(&device->next, almemory_order_relaxed)}; + ALCdevice *nextdev{device->next.load(std::memory_order_relaxed)}; if(!DeviceList.compare_exchange_strong(origdev, nextdev)) { ALCdevice *list; @@ -4025,10 +4025,10 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) } listlock.unlock(); - ALCcontext *ctx{ATOMIC_LOAD_SEQ(&device->ContextList)}; + ALCcontext *ctx{device->ContextList.load()}; while(ctx != nullptr) { - ALCcontext *next = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed); + ALCcontext *next = ctx->next.load(std::memory_order_relaxed); WARN("Releasing context %p\n", ctx); ReleaseContext(ctx, device); ctx = next; @@ -4105,7 +4105,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, { ALCdevice *head{DeviceList.load()}; do { - ATOMIC_STORE(&device->next, head, almemory_order_relaxed); + device->next.store(head, std::memory_order_relaxed); } while(!DeviceList.compare_exchange_weak(head, device)); } @@ -4121,7 +4121,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) do { if(iter == device) break; - iter = ATOMIC_LOAD(&iter->next, almemory_order_relaxed); + iter = iter->next.load(std::memory_order_relaxed); } while(iter != nullptr); if(!iter || iter->Type != Capture) { @@ -4130,7 +4130,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) } ALCdevice *origdev{device}; - ALCdevice *nextdev{ATOMIC_LOAD(&device->next, almemory_order_relaxed)}; + ALCdevice *nextdev{device->next.load(std::memory_order_relaxed)}; if(!DeviceList.compare_exchange_strong(origdev, nextdev)) { ALCdevice *list; @@ -4159,7 +4159,7 @@ ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) else { std::lock_guard _{device->BackendLock}; - if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + if(!device->Connected.load(std::memory_order_acquire)) alcSetError(device, ALC_INVALID_DEVICE); else if(!(device->Flags&DEVICE_RUNNING)) { @@ -4272,7 +4272,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN { ALCdevice *head{DeviceList.load()}; do { - ATOMIC_STORE(&device->next, head, almemory_order_relaxed); + device->next.store(head, std::memory_order_relaxed); } while(!DeviceList.compare_exchange_weak(head, device)); } @@ -4360,7 +4360,7 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) if((device->Flags&DEVICE_PAUSED)) { device->Flags &= ~DEVICE_PAUSED; - if(ATOMIC_LOAD_SEQ(&device->ContextList) != nullptr) + if(device->ContextList.load() != nullptr) { if(V0(device->Backend,start)() != ALC_FALSE) device->Flags |= DEVICE_RUNNING; @@ -4418,7 +4418,7 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi { std::unique_lock listlock{ListLock}; if(!VerifyDevice(&device) || device->Type == Capture || - !ATOMIC_LOAD(&device->Connected, almemory_order_relaxed)) + !device->Connected.load(std::memory_order_relaxed)) { listlock.unlock(); alcSetError(device, ALC_INVALID_DEVICE); -- cgit v1.2.3 From 9f2a77f78801da760df582900ec862fff6438a09 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Nov 2018 09:07:02 -0800 Subject: Use RAII when handling the mixer's FPU state --- Alc/alc.cpp | 4 ++-- Alc/alu.cpp | 3 +-- Alc/converter.cpp | 6 ++---- Alc/fpu_modes.h | 44 ++++++++++++++------------------------------ Alc/helpers.cpp | 25 +++++++++++++++---------- OpenAL32/alAuxEffectSlot.cpp | 26 +++++++++++++------------- 6 files changed, 47 insertions(+), 61 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 5c46b950..d9fa549a 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2241,7 +2241,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) * allocated with the appropriate size. */ update_failed = AL_FALSE; - START_MIXER_MODE(); + FPUCtl mixer_mode{}; context = device->ContextList.load(); while(context) { @@ -2354,7 +2354,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) context = context->next.load(std::memory_order_relaxed); } - END_MIXER_MODE(); + mixer_mode.leave(); if(update_failed) return ALC_INVALID_DEVICE; diff --git a/Alc/alu.cpp b/Alc/alu.cpp index faa011a2..b3ffd24b 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1697,7 +1697,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) ALCcontext *ctx; ALsizei i, c; - START_MIXER_MODE(); + FPUCtl mixer_mode{}; for(SamplesDone = 0;SamplesDone < NumSamples;) { SamplesToDo = mini(NumSamples-SamplesDone, BUFFERSIZE); @@ -1815,7 +1815,6 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) SamplesDone += SamplesToDo; } - END_MIXER_MODE(); } diff --git a/Alc/converter.cpp b/Alc/converter.cpp index d64bc328..72015db0 100644 --- a/Alc/converter.cpp +++ b/Alc/converter.cpp @@ -154,7 +154,7 @@ SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType converter->mFracOffset = 0; /* Have to set the mixer FPU mode since that's what the resampler code expects. */ - START_MIXER_MODE(); + FPUCtl mixer_mode{}; step = (ALsizei)mind(((ALdouble)srcRate/dstRate*FRACTIONONE) + 0.5, MAX_PITCH * FRACTIONONE); converter->mIncrement = maxi(step, 1); @@ -166,7 +166,6 @@ SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc12); converter->mResample = SelectResampler(BSinc12Resampler); } - END_MIXER_MODE(); return converter; } @@ -227,7 +226,7 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs const ALsizei increment = converter->mIncrement; ALsizei pos = 0; - START_MIXER_MODE(); + FPUCtl mixer_mode{}; while(pos < dstframes && *srcframes > 0) { ALfloat *RESTRICT SrcData = converter->mSrcSamples; @@ -339,7 +338,6 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs dst = (ALbyte*)dst + DstFrameSize*DstSize; pos += DstSize; } - END_MIXER_MODE(); return pos; } diff --git a/Alc/fpu_modes.h b/Alc/fpu_modes.h index e8858ad9..1afd6618 100644 --- a/Alc/fpu_modes.h +++ b/Alc/fpu_modes.h @@ -1,41 +1,25 @@ #ifndef FPU_MODES_H #define FPU_MODES_H -#ifdef HAVE_FENV_H -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct FPUCtl { +class FPUCtl { #if defined(__GNUC__) && defined(HAVE_SSE) - unsigned int sse_state; + unsigned int sse_state{}; #elif defined(HAVE___CONTROL87_2) - unsigned int state; - unsigned int sse_state; + unsigned int state{}; + unsigned int sse_state{}; #elif defined(HAVE__CONTROLFP) - unsigned int state; + unsigned int state{}; #endif -} FPUCtl; -void SetMixerFPUMode(FPUCtl *ctl); -void RestoreFPUMode(const FPUCtl *ctl); + bool in_mode{}; -#ifdef __GNUC__ -/* Use an alternate macro set with GCC to avoid accidental continue or break - * statements within the mixer mode. - */ -#define START_MIXER_MODE() __extension__({ FPUCtl _oldMode; SetMixerFPUMode(&_oldMode) -#define END_MIXER_MODE() RestoreFPUMode(&_oldMode); }) -#else -#define START_MIXER_MODE() do { FPUCtl _oldMode; SetMixerFPUMode(&_oldMode) -#define END_MIXER_MODE() RestoreFPUMode(&_oldMode); } while(0) -#endif -#define LEAVE_MIXER_MODE() RestoreFPUMode(&_oldMode) +public: + FPUCtl() noexcept; + ~FPUCtl() { leave(); } -#ifdef __cplusplus -} // extern "C" -#endif + FPUCtl(const FPUCtl&) = delete; + FPUCtl& operator=(const FPUCtl&) = delete; + + void leave() noexcept; +}; #endif /* FPU_MODES_H */ diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index a78e3d83..658c7d09 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -260,13 +260,13 @@ void FillCPUCaps(int capfilter) } -void SetMixerFPUMode(FPUCtl *ctl) +FPUCtl::FPUCtl() noexcept { #if defined(__GNUC__) && defined(HAVE_SSE) if((CPUCapFlags&CPU_CAP_SSE)) { - __asm__ __volatile__("stmxcsr %0" : "=m" (*&ctl->sse_state)); - unsigned int sseState = ctl->sse_state; + __asm__ __volatile__("stmxcsr %0" : "=m" (*&this->sse_state)); + unsigned int sseState = this->sse_state; sseState |= 0x8000; /* set flush-to-zero */ if((CPUCapFlags&CPU_CAP_SSE2)) sseState |= 0x0040; /* set denormals-are-zero */ @@ -275,32 +275,37 @@ void SetMixerFPUMode(FPUCtl *ctl) #elif defined(HAVE___CONTROL87_2) - __control87_2(0, 0, &ctl->state, &ctl->sse_state); + __control87_2(0, 0, &this->state, &this->sse_state); _control87(_DN_FLUSH, _MCW_DN); #elif defined(HAVE__CONTROLFP) - ctl->state = _controlfp(0, 0); + this->state = _controlfp(0, 0); _controlfp(_DN_FLUSH, _MCW_DN); #endif + + this->in_mode = true; } -void RestoreFPUMode(const FPUCtl *ctl) +void FPUCtl::leave() noexcept { + if(!this->in_mode) return; + #if defined(__GNUC__) && defined(HAVE_SSE) if((CPUCapFlags&CPU_CAP_SSE)) - __asm__ __volatile__("ldmxcsr %0" : : "m" (*&ctl->sse_state)); + __asm__ __volatile__("ldmxcsr %0" : : "m" (*&this->sse_state)); #elif defined(HAVE___CONTROL87_2) unsigned int mode; - __control87_2(ctl->state, _MCW_DN, &mode, nullptr); - __control87_2(ctl->sse_state, _MCW_DN, nullptr, &mode); + __control87_2(this->state, _MCW_DN, &mode, nullptr); + __control87_2(this->sse_state, _MCW_DN, nullptr, &mode); #elif defined(HAVE__CONTROLFP) - _controlfp(ctl->state, _MCW_DN); + _controlfp(this->state, _MCW_DN); #endif + this->in_mode = false; } diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index df2c2a43..60c44f49 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -514,19 +514,19 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect EffectState *State{factory->create()}; if(!State) return AL_OUT_OF_MEMORY; - START_MIXER_MODE(); { - ALCdevice *Device{Context->Device}; - std::unique_lock backlock{Device->BackendLock}; - State->mOutBuffer = Device->Dry.Buffer; - State->mOutChannels = Device->Dry.NumChannels; - if(State->deviceUpdate(Device) == AL_FALSE) - { - backlock.unlock(); - LEAVE_MIXER_MODE(); - State->DecRef(); - return AL_OUT_OF_MEMORY; - } - } END_MIXER_MODE(); + FPUCtl mixer_mode{}; + ALCdevice *Device{Context->Device}; + std::unique_lock backlock{Device->BackendLock}; + State->mOutBuffer = Device->Dry.Buffer; + State->mOutChannels = Device->Dry.NumChannels; + if(State->deviceUpdate(Device) == AL_FALSE) + { + backlock.unlock(); + mixer_mode.leave(); + State->DecRef(); + return AL_OUT_OF_MEMORY; + } + mixer_mode.leave(); if(!effect) { -- cgit v1.2.3 From d20522166ec8adf856a5ba4c99ee45ea733ca8b4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Nov 2018 11:11:25 -0800 Subject: Use RAII more in alSource.cpp --- OpenAL32/alSource.cpp | 1108 ++++++++++++++++++++----------------------------- 1 file changed, 457 insertions(+), 651 deletions(-) diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 3a7bc4f0..0739f677 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -54,11 +54,6 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *conte static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac); static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice); -static inline void LockSourceList(ALCcontext *context) -{ almtx_lock(&context->SourceLock); } -static inline void UnlockSourceList(ALCcontext *context) -{ almtx_unlock(&context->SourceLock); } - static inline ALsource *LookupSource(ALCcontext *context, ALuint id) { ALuint lidx = (id-1) >> 6; @@ -1675,691 +1670,572 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) { - ALCcontext *context; - ALsizei cur = 0; - - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; if(n < 0) - alSetError(context, AL_INVALID_VALUE, "Generating %d sources", n); - else for(cur = 0;cur < n;cur++) + alSetError(context.get(), AL_INVALID_VALUE, "Generating %d sources", n); + else if(n == 1) { - ALsource *source = AllocSource(context); - if(!source) - { - alDeleteSources(cur, sources); - break; - } - sources[cur] = source->id; + ALsource *source = AllocSource(context.get()); + if(source) sources[0] = source->id; + } + else + { + al::vector tempids(n); + auto alloc_end = std::find_if_not(tempids.begin(), tempids.end(), + [&context](ALuint &id) -> bool + { + ALsource *source = AllocSource(context.get()); + if(!source) return false; + id = source->id; + return true; + } + ); + if(alloc_end != tempids.end()) + alDeleteSources(std::distance(tempids.begin(), alloc_end), tempids.data()); + else + std::copy(tempids.cbegin(), tempids.cend(), sources); } - - ALCcontext_DecRef(context); } AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) { - ALCcontext *context; - ALsource *Source; - ALsizei i; - - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - LockSourceList(context); if(n < 0) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d sources", n); + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Deleting %d sources", n); + + std::lock_guard _{context->SourceLock}; /* Check that all Sources are valid */ - for(i = 0;i < n;i++) - { - if(LookupSource(context, sources[i]) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); - } - for(i = 0;i < n;i++) + const ALuint *sources_end = sources + n; + auto invsrc = std::find_if_not(sources, sources_end, + [&context](ALuint sid) -> bool + { + if(!LookupSource(context.get(), sid)) + { + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", sid); + return false; + } + return true; + } + ); + if(LIKELY(invsrc == sources_end)) { - if((Source=LookupSource(context, sources[i])) != NULL) - FreeSource(context, Source); + /* All good. Delete source IDs. */ + std::for_each(sources, sources_end, + [&context](ALuint sid) -> void + { + ALsource *src = LookupSource(context.get(), sid); + if(src) FreeSource(context.get(), src); + } + ); } - -done: - UnlockSourceList(context); - ALCcontext_DecRef(context); } AL_API ALboolean AL_APIENTRY alIsSource(ALuint source) { - ALCcontext *context; - ALboolean ret; - - context = GetContextRef(); - if(!context) return AL_FALSE; - - LockSourceList(context); - ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE); - UnlockSourceList(context); - - ALCcontext_DecRef(context); - - return ret; + ContextRef context{GetContextRef()}; + if(LIKELY(context)) + { + std::lock_guard _{context->SourceLock}; + if(LookupSource(context.get(), source) != nullptr) + return AL_TRUE; + } + return AL_FALSE; } AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) { - ALCcontext *Context; - ALsource *Source; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Context = GetContextRef(); - if(!Context) return; - - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(FloatValsByProp(param) != 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid float property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid float property 0x%04x", param); else - SetSourcefv(Source, Context, static_cast(param), &value); - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); + SetSourcefv(Source, context.get(), static_cast(param), &value); } AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) { - ALCcontext *Context; - ALsource *Source; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Context = GetContextRef(); - if(!Context) return; - - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(FloatValsByProp(param) != 3) - alSetError(Context, AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); else { ALfloat fvals[3] = { value1, value2, value3 }; - SetSourcefv(Source, Context, static_cast(param), fvals); + SetSourcefv(Source, context.get(), static_cast(param), fvals); } - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); } AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values) { - ALCcontext *Context; - ALsource *Source; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Context = GetContextRef(); - if(!Context) return; - - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else if(FloatValsByProp(param) < 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); else - SetSourcefv(Source, Context, static_cast(param), values); - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); + SetSourcefv(Source, context.get(), static_cast(param), values); } AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value) { - ALCcontext *Context; - ALsource *Source; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Context = GetContextRef(); - if(!Context) return; - - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(DoubleValsByProp(param) != 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid double property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid double property 0x%04x", param); else { ALfloat fval = (ALfloat)value; - SetSourcefv(Source, Context, static_cast(param), &fval); + SetSourcefv(Source, context.get(), static_cast(param), &fval); } - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); } AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3) { - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(DoubleValsByProp(param) != 3) - alSetError(Context, AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); else { ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 }; - SetSourcefv(Source, Context, static_cast(param), fvals); + SetSourcefv(Source, context.get(), static_cast(param), fvals); } - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); } AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values) { - ALCcontext *Context; - ALsource *Source; - ALint count; - - Context = GetContextRef(); - if(!Context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if((count=DoubleValsByProp(param)) < 1 || count > 6) - alSetError(Context, AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else { - ALfloat fvals[6]; - ALint i; + ALint count{DoubleValsByProp(param)}; + if(count < 1 || count > 6) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); + else + { + ALfloat fvals[6]; + ALint i; - for(i = 0;i < count;i++) - fvals[i] = (ALfloat)values[i]; - SetSourcefv(Source, Context, static_cast(param), fvals); + for(i = 0;i < count;i++) + fvals[i] = (ALfloat)values[i]; + SetSourcefv(Source, context.get(), static_cast(param), fvals); + } } - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); } AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) { - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(IntValsByProp(param) != 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); else - SetSourceiv(Source, Context, static_cast(param), &value); - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); + SetSourceiv(Source, context.get(), static_cast(param), &value); } AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3) { - ALCcontext *Context; - ALsource *Source; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Context = GetContextRef(); - if(!Context) return; - - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(IntValsByProp(param) != 3) - alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); else { ALint ivals[3] = { value1, value2, value3 }; - SetSourceiv(Source, Context, static_cast(param), ivals); + SetSourceiv(Source, context.get(), static_cast(param), ivals); } - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); } AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values) { - ALCcontext *Context; - ALsource *Source; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Context = GetContextRef(); - if(!Context) return; - - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else if(IntValsByProp(param) < 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); else - SetSourceiv(Source, Context, static_cast(param), values); - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); + SetSourceiv(Source, context.get(), static_cast(param), values); } AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value) { - ALCcontext *Context; - ALsource *Source; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Context = GetContextRef(); - if(!Context) return; - - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(Int64ValsByProp(param) != 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); else - SetSourcei64v(Source, Context, static_cast(param), &value); - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); + SetSourcei64v(Source, context.get(), static_cast(param), &value); } AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3) { - ALCcontext *Context; - ALsource *Source; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Context = GetContextRef(); - if(!Context) return; - - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(Int64ValsByProp(param) != 3) - alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); else { ALint64SOFT i64vals[3] = { value1, value2, value3 }; - SetSourcei64v(Source, Context, static_cast(param), i64vals); + SetSourcei64v(Source, context.get(), static_cast(param), i64vals); } - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); } AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values) { - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - almtx_lock(&Context->PropLock); - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else if(Int64ValsByProp(param) < 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); else - SetSourcei64v(Source, Context, static_cast(param), values); - UnlockSourceList(Context); - almtx_unlock(&Context->PropLock); - - ALCcontext_DecRef(Context); + SetSourcei64v(Source, context.get(), static_cast(param), values); } AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value) { - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else if(FloatValsByProp(param) != 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid float property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid float property 0x%04x", param); else { ALdouble dval; - if(GetSourcedv(Source, Context, static_cast(param), &dval)) + if(GetSourcedv(Source, context.get(), static_cast(param), &dval)) *value = (ALfloat)dval; } - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); } AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) { - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else if(FloatValsByProp(param) != 3) - alSetError(Context, AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); else { ALdouble dvals[3]; - if(GetSourcedv(Source, Context, static_cast(param), dvals)) + if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) { *value1 = (ALfloat)dvals[0]; *value2 = (ALfloat)dvals[1]; *value3 = (ALfloat)dvals[2]; } } - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); } AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values) { - ALCcontext *Context; - ALsource *Source; - ALint count; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Context = GetContextRef(); - if(!Context) return; - - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); - else if((count=FloatValsByProp(param)) < 1 && count > 6) - alSetError(Context, AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else { - ALdouble dvals[6]; - if(GetSourcedv(Source, Context, static_cast(param), dvals)) + ALint count{FloatValsByProp(param)}; + if(count < 1 && count > 6) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); + else { - ALint i; - for(i = 0;i < count;i++) - values[i] = (ALfloat)dvals[i]; + ALdouble dvals[6]; + if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) + { + for(ALint i{0};i < count;i++) + values[i] = (ALfloat)dvals[i]; + } } } - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); } AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value) { - ALCcontext *Context; - ALsource *Source; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Context = GetContextRef(); - if(!Context) return; - - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else if(DoubleValsByProp(param) != 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid double property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid double property 0x%04x", param); else - GetSourcedv(Source, Context, static_cast(param), value); - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); + GetSourcedv(Source, context.get(), static_cast(param), value); } AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3) { - ALCcontext *Context; - ALsource *Source; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Context = GetContextRef(); - if(!Context) return; - - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else if(DoubleValsByProp(param) != 3) - alSetError(Context, AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); else { ALdouble dvals[3]; - if(GetSourcedv(Source, Context, static_cast(param), dvals)) + if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) { *value1 = dvals[0]; *value2 = dvals[1]; *value3 = dvals[2]; } } - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); } AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values) { - ALCcontext *Context; - ALsource *Source; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Context = GetContextRef(); - if(!Context) return; - - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else if(DoubleValsByProp(param) < 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); else - GetSourcedv(Source, Context, static_cast(param), values); - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); + GetSourcedv(Source, context.get(), static_cast(param), values); } AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value) { - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else if(IntValsByProp(param) != 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); else - GetSourceiv(Source, Context, static_cast(param), value); - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); + GetSourceiv(Source, context.get(), static_cast(param), value); } AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3) { - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else if(IntValsByProp(param) != 3) - alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); else { ALint ivals[3]; - if(GetSourceiv(Source, Context, static_cast(param), ivals)) + if(GetSourceiv(Source, context.get(), static_cast(param), ivals)) { *value1 = ivals[0]; *value2 = ivals[1]; *value3 = ivals[2]; } } - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); } AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values) { - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else if(IntValsByProp(param) < 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); else - GetSourceiv(Source, Context, static_cast(param), values); - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); + GetSourceiv(Source, context.get(), static_cast(param), values); } AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value) { - ALCcontext *Context; - ALsource *Source; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Context = GetContextRef(); - if(!Context) return; - - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else if(Int64ValsByProp(param) != 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); else - GetSourcei64v(Source, Context, static_cast(param), value); - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); + GetSourcei64v(Source, context.get(), static_cast(param), value); } AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3) { - ALCcontext *Context; - ALsource *Source; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Context = GetContextRef(); - if(!Context) return; - - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else if(Int64ValsByProp(param) != 3) - alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); else { ALint64 i64vals[3]; - if(GetSourcei64v(Source, Context, static_cast(param), i64vals)) + if(GetSourcei64v(Source, context.get(), static_cast(param), i64vals)) { *value1 = i64vals[0]; *value2 = i64vals[1]; *value3 = i64vals[2]; } } - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); } AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values) { - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - LockSourceList(Context); - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else if(Int64ValsByProp(param) < 1) - alSetError(Context, AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); else - GetSourcei64v(Source, Context, static_cast(param), values); - UnlockSourceList(Context); - - ALCcontext_DecRef(Context); + GetSourcei64v(Source, context.get(), static_cast(param), values); } @@ -2369,39 +2245,35 @@ AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source) } AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) { - ALCcontext *context; - ALCdevice *device; - ALsource *source; - ALvoice *voice; - ALsizei i, j; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; + if(n < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Playing %d sources", n); + if(n == 0) return; - LockSourceList(context); - if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Playing %d sources", n); - for(i = 0;i < n;i++) + std::lock_guard _{context->SourceLock}; + for(ALsizei i{0};i < n;i++) { - if(!LookupSource(context, sources[i])) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); + if(!LookupSource(context.get(), sources[i])) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } - device = context->Device; + ALCdevice *device{context->Device}; ALCdevice_Lock(device); /* If the device is disconnected, go right to stopped. */ if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { /* TODO: Send state change event? */ - for(i = 0;i < n;i++) + for(ALsizei i{0};i < n;i++) { - source = LookupSource(context, sources[i]); + ALsource *source{LookupSource(context.get(), sources[i])}; source->OffsetType = AL_NONE; source->Offset = 0.0; source->state = AL_STOPPED; } ALCdevice_Unlock(device); - goto done; + return; } while(n > context->MaxVoices-context->VoiceCount) @@ -2410,23 +2282,19 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) if(context->MaxVoices >= newcount) { ALCdevice_Unlock(device); - SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, - "Overflow increasing voice count %d -> %d", context->MaxVoices, newcount); + SETERR_RETURN(context.get(), AL_OUT_OF_MEMORY,, + "Overflow increasing voice count %d -> %d", context->MaxVoices, newcount); } - AllocateVoices(context, newcount, device->NumAuxSends); + AllocateVoices(context.get(), newcount, device->NumAuxSends); } - for(i = 0;i < n;i++) + for(ALsizei i{0};i < n;i++) { - ALbufferlistitem *BufferList; - bool start_fading = false; - ALint vidx = -1; - - source = LookupSource(context, sources[i]); + ALsource *source{LookupSource(context.get(), sources[i])}; /* Check that there is a queue containing at least one valid, non zero * length buffer. */ - BufferList = source->queue; + ALbufferlistitem *BufferList{source->queue}; while(BufferList && BufferList->max_samples == 0) BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); @@ -2443,12 +2311,12 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) if(oldstate != AL_STOPPED) { source->state = AL_STOPPED; - SendStateChangeEvent(context, source->id, AL_STOPPED); + SendStateChangeEvent(context.get(), source->id, AL_STOPPED); } continue; } - voice = GetSourceVoice(source, context); + ALvoice *voice{GetSourceVoice(source, context.get())}; switch(GetSourceState(source, voice)) { case AL_PLAYING: @@ -2464,7 +2332,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) /* A source that's paused simply resumes. */ ATOMIC_STORE(&voice->Playing, true, almemory_order_release); source->state = AL_PLAYING; - SendStateChangeEvent(context, source->id, AL_PLAYING); + SendStateChangeEvent(context.get(), source->id, AL_PLAYING); continue; default: @@ -2473,7 +2341,8 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) /* Look for an unused voice to play this source with. */ assert(voice == NULL); - for(j = 0;j < context->VoiceCount;j++) + ALint vidx{-1}; + for(ALsizei j{0};j < context->VoiceCount;j++) { if(ATOMIC_LOAD(&context->Voices[j]->Source, almemory_order_acquire) == NULL) { @@ -2487,7 +2356,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) voice->Playing.store(false, std::memory_order_release); source->PropsClean.test_and_set(std::memory_order_acquire); - UpdateSourceProps(source, voice, context); + UpdateSourceProps(source, voice, context.get()); /* A source that's not playing or paused has any offset applied when it * starts playing. @@ -2500,12 +2369,13 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); ATOMIC_STORE(&voice->position, 0u, almemory_order_relaxed); ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed); + bool start_fading{false}; if(ApplyOffset(source, voice) != AL_FALSE) start_fading = ATOMIC_LOAD(&voice->position, almemory_order_relaxed) != 0 || ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) != 0 || ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed) != BufferList; - for(j = 0;j < BufferList->num_buffers;j++) + for(ALsizei j{0};j < BufferList->num_buffers;j++) { ALbuffer *buffer = BufferList->buffers[j]; if(buffer) @@ -2527,13 +2397,13 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) voice->Flags = start_fading ? VOICE_IS_FADING : 0; if(source->SourceType == AL_STATIC) voice->Flags |= VOICE_IS_STATIC; memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])*voice->NumChannels); - for(j = 0;j < device->NumAuxSends;j++) + for(ALsizei j{0};j < device->NumAuxSends;j++) memset(voice->Send[j].Params, 0, sizeof(voice->Send[j].Params[0])*voice->NumChannels); if(device->AvgSpeakerDist > 0.0f) { ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / (device->AvgSpeakerDist * device->Frequency); - for(j = 0;j < voice->NumChannels;j++) + for(ALsizei j{0};j < voice->NumChannels;j++) NfcFilterCreate(&voice->Direct.Params[j].NFCtrlFilter, 0.0f, w1); } @@ -2542,13 +2412,9 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) source->state = AL_PLAYING; source->VoiceIdx = vidx; - SendStateChangeEvent(context, source->id, AL_PLAYING); + SendStateChangeEvent(context.get(), source->id, AL_PLAYING); } ALCdevice_Unlock(device); - -done: - UnlockSourceList(context); - ALCcontext_DecRef(context); } AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source) @@ -2557,42 +2423,33 @@ AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source) } AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) { - ALCcontext *context; - ALCdevice *device; - ALsource *source; - ALvoice *voice; - ALsizei i; - - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - LockSourceList(context); if(n < 0) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Pausing %d sources", n); - for(i = 0;i < n;i++) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Pausing %d sources", n); + if(n == 0) return; + + for(ALsizei i{0};i < n;i++) { - if(!LookupSource(context, sources[i])) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); + if(!LookupSource(context.get(), sources[i])) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } - device = context->Device; + ALCdevice *device{context->Device}; ALCdevice_Lock(device); - for(i = 0;i < n;i++) + for(ALsizei i{0};i < n;i++) { - source = LookupSource(context, sources[i]); - if((voice=GetSourceVoice(source, context)) != NULL) - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + ALsource *source{LookupSource(context.get(), sources[i])}; + ALvoice *voice{GetSourceVoice(source, context.get())}; + if(!voice) voice->Playing.store(false, std::memory_order_release); if(GetSourceState(source, voice) == AL_PLAYING) { source->state = AL_PAUSED; - SendStateChangeEvent(context, source->id, AL_PAUSED); + SendStateChangeEvent(context.get(), source->id, AL_PAUSED); } } ALCdevice_Unlock(device); - -done: - UnlockSourceList(context); - ALCcontext_DecRef(context); } AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source) @@ -2601,50 +2458,41 @@ AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source) } AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) { - ALCcontext *context; - ALCdevice *device; - ALsource *source; - ALvoice *voice; - ALsizei i; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; - - LockSourceList(context); if(n < 0) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Stopping %d sources", n); - for(i = 0;i < n;i++) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Stopping %d sources", n); + if(n == 0) return; + + for(ALsizei i{0};i < n;i++) { - if(!LookupSource(context, sources[i])) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); + if(!LookupSource(context.get(), sources[i])) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } - device = context->Device; + ALCdevice *device{context->Device}; ALCdevice_Lock(device); - for(i = 0;i < n;i++) + for(ALsizei i{0};i < n;i++) { - ALenum oldstate; - source = LookupSource(context, sources[i]); - if((voice=GetSourceVoice(source, context)) != NULL) + ALsource *source{LookupSource(context.get(), sources[i])}; + ALvoice *voice{GetSourceVoice(source, context.get())}; + if(voice != nullptr) { - ATOMIC_STORE(&voice->Source, static_cast(nullptr), almemory_order_relaxed); - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - voice = NULL; + voice->Source.store(nullptr, std::memory_order_relaxed); + voice->Playing.store(false, std::memory_order_release); + voice = nullptr; } - oldstate = GetSourceState(source, voice); + ALenum oldstate{GetSourceState(source, voice)}; if(oldstate != AL_INITIAL && oldstate != AL_STOPPED) { source->state = AL_STOPPED; - SendStateChangeEvent(context, source->id, AL_STOPPED); + SendStateChangeEvent(context.get(), source->id, AL_STOPPED); } source->OffsetType = AL_NONE; source->Offset = 0.0; } ALCdevice_Unlock(device); - -done: - UnlockSourceList(context); - ALCcontext_DecRef(context); } AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source) @@ -2653,103 +2501,87 @@ AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source) } AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) { - ALCcontext *context; - ALCdevice *device; - ALsource *source; - ALvoice *voice; - ALsizei i; - - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - LockSourceList(context); if(n < 0) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Rewinding %d sources", n); - for(i = 0;i < n;i++) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Rewinding %d sources", n); + if(n == 0) return; + + for(ALsizei i{0};i < n;i++) { - if(!LookupSource(context, sources[i])) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); + if(!LookupSource(context.get(), sources[i])) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } - device = context->Device; + ALCdevice *device{context->Device}; ALCdevice_Lock(device); - for(i = 0;i < n;i++) + for(ALsizei i{0};i < n;i++) { - source = LookupSource(context, sources[i]); - if((voice=GetSourceVoice(source, context)) != NULL) + ALsource *source{LookupSource(context.get(), sources[i])}; + ALvoice *voice{GetSourceVoice(source, context.get())}; + if(voice != nullptr) { - ATOMIC_STORE(&voice->Source, static_cast(nullptr), almemory_order_relaxed); - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - voice = NULL; + voice->Source.store(nullptr, std::memory_order_relaxed); + voice->Playing.store(false, std::memory_order_release); + voice = nullptr; } if(GetSourceState(source, voice) != AL_INITIAL) { source->state = AL_INITIAL; - SendStateChangeEvent(context, source->id, AL_INITIAL); + SendStateChangeEvent(context.get(), source->id, AL_INITIAL); } source->OffsetType = AL_NONE; source->Offset = 0.0; } ALCdevice_Unlock(device); - -done: - UnlockSourceList(context); - ALCcontext_DecRef(context); } AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers) { - ALCdevice *device; - ALCcontext *context; - ALsource *source; - ALsizei i; - ALbufferlistitem *BufferListStart; - ALbufferlistitem *BufferList; - ALbuffer *BufferFmt = NULL; - - if(nb == 0) - return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; + if(nb < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffers", nb); + if(nb == 0) return; - device = context->Device; - - LockSourceList(context); - if(!(nb >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Queueing %d buffers", nb); - if((source=LookupSource(context, src)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src); + std::lock_guard _{context->SourceLock}; + ALsource *source{LookupSource(context.get(),src)}; + if(!source) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); if(source->SourceType == AL_STATIC) { /* Can't queue on a Static Source */ - SETERR_GOTO(context, AL_INVALID_OPERATION, done, "Queueing onto static source %u", src); + SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src); } /* Check for a valid Buffer, for its frequency and format */ - BufferList = source->queue; + ALCdevice *device{context->Device}; + ALbuffer *BufferFmt{nullptr}; + ALbufferlistitem *BufferList{source->queue}; while(BufferList) { - for(i = 0;i < BufferList->num_buffers;i++) + for(ALsizei i{0};i < BufferList->num_buffers;i++) { - if((BufferFmt=BufferList->buffers[i]) != NULL) + if((BufferFmt=BufferList->buffers[i]) != nullptr) break; } if(BufferFmt) break; - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + BufferList = BufferList->next.load(std::memory_order_relaxed); } - LockBufferList(device); - BufferListStart = NULL; - BufferList = NULL; - for(i = 0;i < nb;i++) + std::unique_lock buflock{device->BufferLock}; + ALbufferlistitem *BufferListStart{nullptr}; + BufferList = nullptr; + for(ALsizei i{0};i < nb;i++) { - ALbuffer *buffer = NULL; + ALbuffer *buffer{nullptr}; if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer_error, "Queueing invalid buffer ID %u", - buffers[i]); + SETERR_GOTO(context.get(), AL_INVALID_NAME, buffer_error, + "Queueing invalid buffer ID %u", buffers[i]); if(!BufferListStart) { @@ -2759,9 +2591,9 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu } else { - ALbufferlistitem *item = static_cast(al_calloc(DEF_ALIGN, + auto item = static_cast(al_calloc(DEF_ALIGN, FAM_SIZE(ALbufferlistitem, buffers, 1))); - ATOMIC_STORE(&BufferList->next, item, almemory_order_relaxed); + BufferList->next.store(item, std::memory_order_relaxed); BufferList = item; } ATOMIC_INIT(&BufferList->next, static_cast(nullptr)); @@ -2773,7 +2605,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu IncrementRef(&buffer->ref); if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) - SETERR_GOTO(context, AL_INVALID_OPERATION, buffer_error, + SETERR_GOTO(context.get(), AL_INVALID_OPERATION, buffer_error, "Queueing non-persistently mapped buffer %u", buffer->id); if(BufferFmt == NULL) @@ -2782,15 +2614,15 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu BufferFmt->FmtChannels != buffer->FmtChannels || BufferFmt->OriginalType != buffer->OriginalType) { - alSetError(context, AL_INVALID_OPERATION, "Queueing buffer with mismatched format"); + alSetError(context.get(), AL_INVALID_OPERATION, + "Queueing buffer with mismatched format"); buffer_error: /* A buffer failed (invalid ID or format), so unlock and release * each buffer we had. */ while(BufferListStart) { - ALbufferlistitem *next = ATOMIC_LOAD(&BufferListStart->next, - almemory_order_relaxed); + ALbufferlistitem *next = BufferListStart->next.load(std::memory_order_relaxed); for(i = 0;i < BufferListStart->num_buffers;i++) { if((buffer=BufferListStart->buffers[i]) != NULL) @@ -2799,12 +2631,11 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu al_free(BufferListStart); BufferListStart = next; } - UnlockBufferList(device); - goto done; + return; } } /* All buffers good. */ - UnlockBufferList(device); + buflock.unlock(); /* Source is now streaming */ source->SourceType = AL_STREAMING; @@ -2814,72 +2645,61 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu else { ALbufferlistitem *next; - while((next=ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed)) != NULL) + while((next=BufferList->next.load(std::memory_order_relaxed)) != nullptr) BufferList = next; - ATOMIC_STORE(&BufferList->next, BufferListStart, almemory_order_release); + BufferList->next.store(BufferListStart, std::memory_order_release); } - -done: - UnlockSourceList(context); - ALCcontext_DecRef(context); } AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers) { - ALCdevice *device; - ALCcontext *context; - ALbufferlistitem *BufferListStart; - ALbufferlistitem *BufferList; - ALbuffer *BufferFmt = NULL; - ALsource *source; - ALsizei i; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - if(nb == 0) - return; + if(nb < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffer layers", nb); + if(nb == 0) return; - context = GetContextRef(); - if(!context) return; - - device = context->Device; - - LockSourceList(context); - if(!(nb >= 0 && nb < 16)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Queueing %d buffer layers", nb); - if((source=LookupSource(context, src)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src); + std::lock_guard _{context->SourceLock}; + ALsource *source{LookupSource(context.get(),src)}; + if(!source) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); if(source->SourceType == AL_STATIC) { /* Can't queue on a Static Source */ - SETERR_GOTO(context, AL_INVALID_OPERATION, done, "Queueing onto static source %u", src); + SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src); } /* Check for a valid Buffer, for its frequency and format */ - BufferList = source->queue; + ALCdevice *device{context->Device}; + ALbuffer *BufferFmt{nullptr}; + ALbufferlistitem *BufferList{source->queue}; while(BufferList) { - for(i = 0;i < BufferList->num_buffers;i++) + for(ALsizei i{0};i < BufferList->num_buffers;i++) { - if((BufferFmt=BufferList->buffers[i]) != NULL) + if((BufferFmt=BufferList->buffers[i]) != nullptr) break; } if(BufferFmt) break; - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + BufferList = BufferList->next.load(std::memory_order_relaxed); } - LockBufferList(device); - BufferListStart = static_cast(al_calloc(DEF_ALIGN, + std::unique_lock buflock{device->BufferLock}; + auto BufferListStart = static_cast(al_calloc(DEF_ALIGN, FAM_SIZE(ALbufferlistitem, buffers, nb))); BufferList = BufferListStart; ATOMIC_INIT(&BufferList->next, static_cast(nullptr)); BufferList->max_samples = 0; BufferList->num_buffers = 0; - for(i = 0;i < nb;i++) + + for(ALsizei i{0};i < nb;i++) { - ALbuffer *buffer = NULL; - if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer_error, "Queueing invalid buffer ID %u", - buffers[i]); + ALbuffer *buffer{nullptr}; + if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr) + SETERR_GOTO(context.get(), AL_INVALID_NAME, buffer_error, + "Queueing invalid buffer ID %u", buffers[i]); BufferList->buffers[BufferList->num_buffers++] = buffer; if(!buffer) continue; @@ -2889,7 +2709,7 @@ AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, co BufferList->max_samples = maxi(BufferList->max_samples, buffer->SampleLen); if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) - SETERR_GOTO(context, AL_INVALID_OPERATION, buffer_error, + SETERR_GOTO(context.get(), AL_INVALID_OPERATION, buffer_error, "Queueing non-persistently mapped buffer %u", buffer->id); if(BufferFmt == NULL) @@ -2898,7 +2718,8 @@ AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, co BufferFmt->FmtChannels != buffer->FmtChannels || BufferFmt->OriginalType != buffer->OriginalType) { - alSetError(context, AL_INVALID_OPERATION, "Queueing buffer with mismatched format"); + alSetError(context.get(), AL_INVALID_OPERATION, + "Queueing buffer with mismatched format"); buffer_error: /* A buffer failed (invalid ID or format), so unlock and release @@ -2915,12 +2736,11 @@ AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, co al_free(BufferListStart); BufferListStart = next; } - UnlockBufferList(device); - goto done; + return; } } /* All buffers good. */ - UnlockBufferList(device); + buflock.unlock(); /* Source is now streaming */ source->SourceType = AL_STREAMING; @@ -2934,58 +2754,48 @@ AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, co BufferList = next; ATOMIC_STORE(&BufferList->next, BufferListStart, almemory_order_release); } - -done: - UnlockSourceList(context); - ALCcontext_DecRef(context); } AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers) { - ALCcontext *context; - ALsource *source; - ALbufferlistitem *BufferList; - ALbufferlistitem *Current; - ALvoice *voice; - ALsizei i; - - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - LockSourceList(context); - if(!(nb >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing %d buffers", nb); - if((source=LookupSource(context, src)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src); + if(nb < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing %d buffers", nb); + if(nb == 0) return; - /* Nothing to unqueue. */ - if(nb == 0) goto done; + std::lock_guard _{context->SourceLock}; + ALsource *source{LookupSource(context.get(),src)}; + if(!source) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); if(source->Looping) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing from looping source %u", src); + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing from looping source %u", src); if(source->SourceType != AL_STREAMING) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing from a non-streaming source %u", - src); + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, + "Unqueueing from a non-streaming source %u", src); /* Make sure enough buffers have been processed to unqueue. */ - BufferList = source->queue; - Current = NULL; - if((voice=GetSourceVoice(source, context)) != NULL) - Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); + ALbufferlistitem *BufferList{source->queue}; + ALvoice *voice{GetSourceVoice(source, context.get())}; + ALbufferlistitem *Current{nullptr}; + if(voice) + Current = voice->current_buffer.load(std::memory_order_relaxed); else if(source->state == AL_INITIAL) Current = BufferList; if(BufferList == Current) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing pending buffers"); + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing pending buffers"); - i = BufferList->num_buffers; + ALsizei i{BufferList->num_buffers}; while(i < nb) { /* If the next bufferlist to check is NULL or is the current one, it's * trying to unqueue pending buffers. */ - ALbufferlistitem *next = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + ALbufferlistitem *next = BufferList->next.load(std::memory_order_relaxed); if(!next || next == Current) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing pending buffers"); + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing pending buffers"); BufferList = next; i += BufferList->num_buffers; @@ -2994,7 +2804,7 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint while(nb > 0) { ALbufferlistitem *head = source->queue; - ALbufferlistitem *next = ATOMIC_LOAD(&head->next, almemory_order_relaxed); + ALbufferlistitem *next = head->next.load(std::memory_order_relaxed); for(i = 0;i < head->num_buffers && nb > 0;i++,nb--) { ALbuffer *buffer = head->buffers[i]; @@ -3030,10 +2840,6 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint al_free(head); source->queue = next; } - -done: - UnlockSourceList(context); - ALCcontext_DecRef(context); } -- cgit v1.2.3 From dfcc98afbf574205e11826753f0a2c2abc7b922e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Nov 2018 11:51:34 -0800 Subject: Fix deleting the same buffer ID multiple times in one call --- OpenAL32/alBuffer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index b08518ba..196dcd22 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -502,7 +502,10 @@ AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) /* All good. Delete non-0 buffer IDs. */ std::for_each(buffers, buffers_end, [device](ALuint bid) -> void - { if(bid) FreeBuffer(device, LookupBuffer(device, bid)); } + { + ALbuffer *buffer{bid ? LookupBuffer(device, bid) : nullptr}; + if(buffer) FreeBuffer(device, buffer); + } ); } } -- cgit v1.2.3 From eefc379a239820a0711683455f5fadb20c8dbaf9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Nov 2018 15:31:32 -0800 Subject: Use a unique_ptr for Uhj2Encoder --- Alc/alc.cpp | 5 +---- Alc/alu.cpp | 2 +- Alc/panning.cpp | 2 +- Alc/uhjfilter.h | 22 +++++++++------------- OpenAL32/Include/alMain.h | 3 ++- 5 files changed, 14 insertions(+), 20 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index d9fa549a..2ad6c887 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -48,6 +48,7 @@ #include "alError.h" #include "mastering.h" #include "bformatdec.h" +#include "uhjfilter.h" #include "alu.h" #include "alconfig.h" #include "ringbuffer.h" @@ -1987,7 +1988,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if((device->Flags&DEVICE_RUNNING)) return ALC_NO_ERROR; - al_free(device->Uhj_Encoder); device->Uhj_Encoder = nullptr; al_free(device->Bs2b); @@ -2428,9 +2428,6 @@ ALCdevice_struct::~ALCdevice_struct() al_free(Bs2b); Bs2b = nullptr; - al_free(Uhj_Encoder); - Uhj_Encoder = nullptr; - bformatdec_free(&AmbiDecoder); ambiup_free(&AmbiUp); diff --git a/Alc/alu.cpp b/Alc/alu.cpp index b3ffd24b..a87be0b6 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -162,7 +162,7 @@ void ProcessUhj(ALCdevice *device, ALsizei SamplesToDo) assert(lidx != -1 && ridx != -1); /* Encode to stereo-compatible 2-channel UHJ output. */ - EncodeUhj2(device->Uhj_Encoder, + EncodeUhj2(device->Uhj_Encoder.get(), device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], device->Dry.Buffer, SamplesToDo ); diff --git a/Alc/panning.cpp b/Alc/panning.cpp index f538e347..c167c227 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -1199,7 +1199,7 @@ no_hrtf: } if(device->Render_Mode == NormalRender) { - device->Uhj_Encoder = reinterpret_cast(al_calloc(16, sizeof(Uhj2Encoder))); + device->Uhj_Encoder.reset(new Uhj2Encoder{}); TRACE("UHJ enabled\n"); InitUhjPanning(device); return; diff --git a/Alc/uhjfilter.h b/Alc/uhjfilter.h index 211425ed..c6335af3 100644 --- a/Alc/uhjfilter.h +++ b/Alc/uhjfilter.h @@ -4,14 +4,12 @@ #include "AL/al.h" #include "alMain.h" +#include "almalloc.h" -#ifdef __cplusplus -extern "C" { -#endif -typedef struct AllPassState { - ALfloat z[2]; -} AllPassState; +struct AllPassState { + ALfloat z[2]{0.0f, 0.0f}; +}; /* Encoding 2-channel UHJ from B-Format is done as: * @@ -38,20 +36,18 @@ typedef struct AllPassState { * other inputs. */ -typedef struct Uhj2Encoder { +struct Uhj2Encoder { AllPassState Filter1_Y[4]; AllPassState Filter2_WX[4]; AllPassState Filter1_WX[4]; - ALfloat LastY, LastWX; -} Uhj2Encoder; + ALfloat LastY{0.0f}, LastWX{0.0f}; + + DEF_NEWDEL(Uhj2Encoder) +}; /* Encodes a 2-channel UHJ (stereo-compatible) signal from a B-Format input * signal. The input must use FuMa channel ordering and scaling. */ void EncodeUhj2(Uhj2Encoder *enc, ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo); -#ifdef __cplusplus -} // extern "C" -#endif - #endif /* UHJFILTER_H */ diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index e6ad849e..06ccd574 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -207,6 +207,7 @@ struct ALbuffer; struct ALeffect; struct ALfilter; struct EffectState; +struct Uhj2Encoder; #define DEFAULT_OUTPUT_RATE (44100) @@ -669,7 +670,7 @@ struct ALCdevice_struct { ALCenum HrtfStatus{ALC_FALSE}; /* UHJ encoder state */ - struct Uhj2Encoder *Uhj_Encoder{nullptr}; + std::unique_ptr Uhj_Encoder; /* High quality Ambisonic decoder */ struct BFormatDec *AmbiDecoder{nullptr}; -- cgit v1.2.3 From cc3e2a838f245770af3d773e8d2c461b9912e392 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Nov 2018 16:46:52 -0800 Subject: Use a unique_ptr for the Compressor --- Alc/alc.cpp | 11 +---- Alc/alu.cpp | 2 +- Alc/mastering.cpp | 104 ++++++++++++++-------------------------------- Alc/mastering.h | 68 ++++++++++++++++++++++++++---- OpenAL32/Include/alMain.h | 2 +- 5 files changed, 95 insertions(+), 92 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 2ad6c887..b942064f 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2221,16 +2221,12 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(device->DitherDepth > 0.0f) thrshld -= 1.0f / device->DitherDepth; - al_free(device->Limiter); - device->Limiter = CreateDeviceLimiter(device, std::log10(thrshld) * 20.0f); - device->FixedLatency += (ALuint)(GetCompressorLookAhead(device->Limiter) * + device->Limiter.reset(CreateDeviceLimiter(device, std::log10(thrshld) * 20.0f)); + device->FixedLatency += (ALuint)(GetCompressorLookAhead(device->Limiter.get()) * DEVICE_CLOCK_RES / device->Frequency); } else - { - al_free(device->Limiter); device->Limiter = nullptr; - } TRACE("Output limiter %s\n", device->Limiter ? "enabled" : "disabled"); aluSelectPostProcess(device); @@ -2433,9 +2429,6 @@ ALCdevice_struct::~ALCdevice_struct() al_free(Stablizer); Stablizer = nullptr; - - al_free(Limiter); - Limiter = nullptr; } diff --git a/Alc/alu.cpp b/Alc/alu.cpp index a87be0b6..4d3ad9b2 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1787,7 +1787,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) SamplesToDo, device->RealOut.NumChannels); if(device->Limiter) - ApplyCompression(device->Limiter, SamplesToDo, device->RealOut.Buffer); + ApplyCompression(device->Limiter.get(), SamplesToDo, device->RealOut.Buffer); if(device->DitherDepth > 0.0f) ApplyDither(device->RealOut.Buffer, &device->DitherSeed, device->DitherDepth, diff --git a/Alc/mastering.cpp b/Alc/mastering.cpp index 131a0330..bf999709 100644 --- a/Alc/mastering.cpp +++ b/Alc/mastering.cpp @@ -2,6 +2,8 @@ #include +#include + #include "mastering.h" #include "alu.h" #include "almalloc.h" @@ -23,65 +25,13 @@ static double round(double val) /* These structures assume BUFFERSIZE is a power of 2. */ static_assert((BUFFERSIZE & (BUFFERSIZE-1)) == 0, "BUFFERSIZE is not a power of 2"); -typedef struct SlidingHold { +struct SlidingHold { ALfloat Values[BUFFERSIZE]; ALsizei Expiries[BUFFERSIZE]; ALsizei LowerIndex; ALsizei UpperIndex; ALsizei Length; -} SlidingHold; - -/* General topology and basic automation was based on the following paper: - * - * D. Giannoulis, M. Massberg and J. D. Reiss, - * "Parameter Automation in a Dynamic Range Compressor," - * Journal of the Audio Engineering Society, v61 (10), Oct. 2013 - * - * Available (along with supplemental reading) at: - * - * http://c4dm.eecs.qmul.ac.uk/audioengineering/compressors/ - */ -typedef struct Compressor { - ALsizei NumChans; - ALuint SampleRate; - - struct { - ALuint Knee : 1; - ALuint Attack : 1; - ALuint Release : 1; - ALuint PostGain : 1; - ALuint Declip : 1; - } Auto; - - ALsizei LookAhead; - - ALfloat PreGain; - ALfloat PostGain; - - ALfloat Threshold; - ALfloat Slope; - ALfloat Knee; - - ALfloat Attack; - ALfloat Release; - - alignas(16) ALfloat SideChain[2*BUFFERSIZE]; - alignas(16) ALfloat CrestFactor[BUFFERSIZE]; - - SlidingHold *Hold; - ALfloat (*Delay)[BUFFERSIZE]; - ALsizei DelayIndex; - - ALfloat CrestCoeff; - ALfloat GainEstimate; - ALfloat AdaptCoeff; - - ALfloat LastPeakSq; - ALfloat LastRmsSq; - ALfloat LastRelease; - ALfloat LastAttack; - ALfloat LastGainDev; -} Compressor; +}; /* This sliding hold follows the input level with an instant attack and a @@ -446,7 +396,7 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, size += sizeof(*Comp->Hold); } - Comp = static_cast(al_calloc(16, size)); + Comp = new (al_calloc(16, size)) Compressor{}; Comp->NumChans = NumChans; Comp->SampleRate = SampleRate; Comp->Auto.Knee = AutoKnee; @@ -474,7 +424,7 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, { if(hold > 0) { - Comp->Hold = (SlidingHold*)(Comp + 1); + Comp->Hold = new ((void*)(Comp + 1)) SlidingHold{}; Comp->Hold->Values[0] = -HUGE_VALF; Comp->Hold->Expiries[0] = hold; Comp->Hold->Length = hold; @@ -495,21 +445,23 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]) { - const ALsizei numChans = Comp->NumChans; - const ALfloat preGain = Comp->PreGain; - ALfloat *RESTRICT sideChain; - ALsizei c, i; + const ALsizei numChans{Comp->NumChans}; ASSUME(SamplesToDo > 0); ASSUME(numChans > 0); + const ALfloat preGain{Comp->PreGain}; if(preGain != 1.0f) { - for(c = 0;c < numChans;c++) - { - for(i = 0;i < SamplesToDo;i++) - OutBuffer[c][i] *= preGain; - } + std::for_each(OutBuffer, OutBuffer+numChans, + [SamplesToDo, preGain](ALfloat *buffer) noexcept -> void + { + std::for_each(buffer, buffer+SamplesToDo, + [preGain](ALfloat &samp) noexcept -> void + { samp *= preGain; } + ); + } + ); } LinkChannels(Comp, SamplesToDo, OutBuffer); @@ -527,14 +479,22 @@ void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RES if(Comp->Delay) SignalDelay(Comp, SamplesToDo, OutBuffer); - sideChain = Comp->SideChain; - for(c = 0;c < numChans;c++) - { - for(i = 0;i < SamplesToDo;i++) - OutBuffer[c][i] *= sideChain[i]; - } + ALfloat *RESTRICT sideChain{Comp->SideChain}; + std::for_each(OutBuffer, OutBuffer+numChans, + [SamplesToDo, sideChain](ALfloat *buffer) noexcept -> void + { + /* Mark the sideChain "input-1 type" as restrict, so the compiler + * can vectorize this loop (otherwise it assumes a write to + * buffer[n] can change sideChain[n+1]). + */ + std::transform(sideChain, sideChain+SamplesToDo, buffer, buffer, + [](const ALfloat gain, const ALfloat samp) noexcept -> ALfloat + { return samp * gain; } + ); + } + ); - memmove(sideChain, sideChain+SamplesToDo, Comp->LookAhead*sizeof(ALfloat)); + std::copy(sideChain+SamplesToDo, sideChain+SamplesToDo+Comp->LookAhead, sideChain); } diff --git a/Alc/mastering.h b/Alc/mastering.h index 7738a4aa..a6cf58ed 100644 --- a/Alc/mastering.h +++ b/Alc/mastering.h @@ -3,14 +3,68 @@ #include "AL/al.h" +#include "almalloc.h" /* For BUFFERSIZE. */ #include "alMain.h" -#ifdef __cplusplus -extern "C" { -#endif -struct Compressor; +struct SlidingHold; + +/* General topology and basic automation was based on the following paper: + * + * D. Giannoulis, M. Massberg and J. D. Reiss, + * "Parameter Automation in a Dynamic Range Compressor," + * Journal of the Audio Engineering Society, v61 (10), Oct. 2013 + * + * Available (along with supplemental reading) at: + * + * http://c4dm.eecs.qmul.ac.uk/audioengineering/compressors/ + */ +struct Compressor { + ALsizei NumChans; + ALuint SampleRate; + + struct { + ALuint Knee : 1; + ALuint Attack : 1; + ALuint Release : 1; + ALuint PostGain : 1; + ALuint Declip : 1; + } Auto; + + ALsizei LookAhead; + + ALfloat PreGain; + ALfloat PostGain; + + ALfloat Threshold; + ALfloat Slope; + ALfloat Knee; + + ALfloat Attack; + ALfloat Release; + + alignas(16) ALfloat SideChain[2*BUFFERSIZE]; + alignas(16) ALfloat CrestFactor[BUFFERSIZE]; + + SlidingHold *Hold; + ALfloat (*Delay)[BUFFERSIZE]; + ALsizei DelayIndex; + + ALfloat CrestCoeff; + ALfloat GainEstimate; + ALfloat AdaptCoeff; + + ALfloat LastPeakSq; + ALfloat LastRmsSq; + ALfloat LastRelease; + ALfloat LastAttack; + ALfloat LastGainDev; + + void *operator new(size_t size) = delete; + void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } + void operator delete(void *block) noexcept { al_free(block); } +}; /* The compressor is initialized with the following settings: * @@ -36,7 +90,7 @@ struct Compressor; * ReleaseTimeMin - Release time (in seconds). Acts as a maximum when * automating release time. */ -struct Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, +Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, const ALboolean AutoKnee, const ALboolean AutoAttack, const ALboolean AutoRelease, const ALboolean AutoPostGain, const ALboolean AutoDeclip, const ALfloat LookAheadTime, @@ -50,8 +104,4 @@ void ApplyCompression(struct Compressor *Comp, const ALsizei SamplesToDo, ALsizei GetCompressorLookAhead(const struct Compressor *Comp); -#ifdef __cplusplus -} // extern "C" -#endif - #endif /* MASTERING_H */ diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 06ccd574..41465c1d 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -711,7 +711,7 @@ struct ALCdevice_struct { struct FrontStablizer *Stablizer{nullptr}; - struct Compressor *Limiter{nullptr}; + std::unique_ptr Limiter; /* The average speaker distance as determined by the ambdec configuration * (or alternatively, by the NFC-HOA reference delay). Only used for NFC. -- cgit v1.2.3 From 671ed1abf8cc246c6e2b5f9ae3bac132fb9af519 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Nov 2018 04:53:29 -0800 Subject: Use a unique_ptr for the FrontStablizer --- Alc/alc.cpp | 4 +--- Alc/alu.cpp | 2 +- Alc/filters/splitter.h | 32 ++++++++++++++------------------ Alc/panning.cpp | 12 +++++------- OpenAL32/Include/alMain.h | 2 +- 5 files changed, 22 insertions(+), 30 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index b942064f..9e4d1ac9 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -52,6 +52,7 @@ #include "alu.h" #include "alconfig.h" #include "ringbuffer.h" +#include "filters/splitter.h" #include "fpu_modes.h" #include "cpu_caps.h" @@ -2426,9 +2427,6 @@ ALCdevice_struct::~ALCdevice_struct() bformatdec_free(&AmbiDecoder); ambiup_free(&AmbiUp); - - al_free(Stablizer); - Stablizer = nullptr; } diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 4d3ad9b2..da9d10f2 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1779,7 +1779,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) int cidx = GetChannelIdxByName(&device->RealOut, FrontCenter); assert(lidx >= 0 && ridx >= 0 && cidx >= 0); - ApplyStablizer(device->Stablizer, device->RealOut.Buffer, lidx, ridx, cidx, + ApplyStablizer(device->Stablizer.get(), device->RealOut.Buffer, lidx, ridx, cidx, SamplesToDo, device->RealOut.NumChannels); } diff --git a/Alc/filters/splitter.h b/Alc/filters/splitter.h index a996917c..13f4cd55 100644 --- a/Alc/filters/splitter.h +++ b/Alc/filters/splitter.h @@ -2,18 +2,16 @@ #define FILTER_SPLITTER_H #include "alMain.h" +#include "almalloc.h" -#ifdef __cplusplus -extern "C" { -#endif /* Band splitter. Splits a signal into two phase-matching frequency bands. */ -typedef struct BandSplitter { - ALfloat coeff; - ALfloat lp_z1; - ALfloat lp_z2; - ALfloat hp_z1; -} BandSplitter; +struct BandSplitter { + ALfloat coeff{0.0f}; + ALfloat lp_z1{0.0f}; + ALfloat lp_z2{0.0f}; + ALfloat hp_z1{0.0f}; +}; void bandsplit_init(BandSplitter *splitter, ALfloat f0norm); void bandsplit_clear(BandSplitter *splitter); @@ -23,25 +21,23 @@ void bandsplit_process(BandSplitter *splitter, ALfloat *RESTRICT hpout, ALfloat /* The all-pass portion of the band splitter. Applies the same phase shift * without splitting the signal. */ -typedef struct SplitterAllpass { - ALfloat coeff; - ALfloat z1; -} SplitterAllpass; +struct SplitterAllpass { + ALfloat coeff{0.0f}; + ALfloat z1{0.0f}; +}; void splitterap_init(SplitterAllpass *splitter, ALfloat f0norm); void splitterap_clear(SplitterAllpass *splitter); void splitterap_process(SplitterAllpass *splitter, ALfloat *RESTRICT samples, ALsizei count); -typedef struct FrontStablizer { +struct FrontStablizer { SplitterAllpass APFilter[MAX_OUTPUT_CHANNELS]; BandSplitter LFilter, RFilter; alignas(16) ALfloat LSplit[2][BUFFERSIZE]; alignas(16) ALfloat RSplit[2][BUFFERSIZE]; -} FrontStablizer; -#ifdef __cplusplus -} // extern "C" -#endif + DEF_NEWDEL(FrontStablizer) +}; #endif /* FILTER_SPLITTER_H */ diff --git a/Alc/panning.cpp b/Alc/panning.cpp index c167c227..4ffdf969 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -931,8 +931,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf size_t i; al_free(device->Hrtf); - device->Hrtf = NULL; - device->HrtfHandle = NULL; + device->Hrtf = nullptr; + device->HrtfHandle = nullptr; device->HrtfName.clear(); device->Render_Mode = NormalRender; @@ -945,8 +945,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf device->AvgSpeakerDist = 0.0f; device->ChannelDelay.clear(); - al_free(device->Stablizer); - device->Stablizer = NULL; + device->Stablizer = nullptr; if(device->FmtChans != DevFmtStereo) { @@ -1035,8 +1034,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf * higher). */ ALfloat scale = (ALfloat)(5000.0 / device->Frequency); - FrontStablizer *stablizer = reinterpret_cast( - al_calloc(16, sizeof(*stablizer))); + std::unique_ptr stablizer{new FrontStablizer{}}; bandsplit_init(&stablizer->LFilter, scale); stablizer->RFilter = stablizer->LFilter; @@ -1046,7 +1044,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf for(i = 1;i < (size_t)device->RealOut.NumChannels;i++) stablizer->APFilter[i] = stablizer->APFilter[0]; - device->Stablizer = stablizer; + device->Stablizer = std::move(stablizer); } break; case DevFmtMono: diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 41465c1d..c57d87ba 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -709,7 +709,7 @@ struct ALCdevice_struct { */ RealMixParams RealOut; - struct FrontStablizer *Stablizer{nullptr}; + std::unique_ptr Stablizer; std::unique_ptr Limiter; -- cgit v1.2.3 From b3b42201828bb737c55c20bd46af10b40d10ef85 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Nov 2018 05:37:35 -0800 Subject: Use unique_ptr for BFormatDec and AmbiUpsampler --- Alc/alc.cpp | 3 -- Alc/alu.cpp | 8 +++--- Alc/bformatdec.cpp | 70 +++-------------------------------------------- Alc/bformatdec.h | 67 +++++++++++++++++++++++++++++++++------------ Alc/panning.cpp | 29 +++++++++----------- OpenAL32/Include/alMain.h | 6 ++-- 6 files changed, 74 insertions(+), 109 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 9e4d1ac9..d96f6df0 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2424,9 +2424,6 @@ ALCdevice_struct::~ALCdevice_struct() al_free(Bs2b); Bs2b = nullptr; - - bformatdec_free(&AmbiDecoder); - ambiup_free(&AmbiUp); } diff --git a/Alc/alu.cpp b/Alc/alu.cpp index da9d10f2..9372da85 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -114,7 +114,7 @@ void ProcessHrtf(ALCdevice *device, ALsizei SamplesToDo) ALsizei c; if(device->AmbiUp) - ambiup_process(device->AmbiUp, + ambiup_process(device->AmbiUp.get(), device->Dry.Buffer, device->Dry.NumChannels, device->FOAOut.Buffer, SamplesToDo ); @@ -137,11 +137,11 @@ void ProcessHrtf(ALCdevice *device, ALsizei SamplesToDo) void ProcessAmbiDec(ALCdevice *device, ALsizei SamplesToDo) { if(device->Dry.Buffer != device->FOAOut.Buffer) - bformatdec_upSample(device->AmbiDecoder, + bformatdec_upSample(device->AmbiDecoder.get(), device->Dry.Buffer, device->FOAOut.Buffer, device->FOAOut.NumChannels, SamplesToDo ); - bformatdec_process(device->AmbiDecoder, + bformatdec_process(device->AmbiDecoder.get(), device->RealOut.Buffer, device->RealOut.NumChannels, device->Dry.Buffer, SamplesToDo ); @@ -149,7 +149,7 @@ void ProcessAmbiDec(ALCdevice *device, ALsizei SamplesToDo) void ProcessAmbiUp(ALCdevice *device, ALsizei SamplesToDo) { - ambiup_process(device->AmbiUp, + ambiup_process(device->AmbiUp.get(), device->RealOut.Buffer, device->RealOut.NumChannels, device->FOAOut.Buffer, SamplesToDo ); diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index f36cf08b..f82d2d9c 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -62,7 +62,8 @@ namespace { #define HF_BAND 0 #define LF_BAND 1 -#define NUM_BANDS 2 +static_assert(BFormatDec::NumBands == 2, "Unexpected BFormatDec::NumBands"); +static_assert(AmbiUpsampler::NumBands == 2, "Unexpected AmbiUpsampler::NumBands"); /* These points are in AL coordinates! */ constexpr ALfloat Ambi3DPoints[8][3] = { @@ -107,47 +108,6 @@ ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn) } // namespace -/* NOTE: BandSplitter filters are unused with single-band decoding */ -struct BFormatDec { - ALuint Enabled; /* Bitfield of enabled channels. */ - - union { - alignas(16) ALfloat Dual[MAX_OUTPUT_CHANNELS][NUM_BANDS][MAX_AMBI_COEFFS]; - alignas(16) ALfloat Single[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; - } Matrix; - - BandSplitter XOver[MAX_AMBI_COEFFS]; - - al::vector, 16> Samples; - /* These two alias into Samples */ - std::array *SamplesHF; - std::array *SamplesLF; - - alignas(16) ALfloat ChannelMix[BUFFERSIZE]; - - struct { - BandSplitter XOver; - ALfloat Gains[NUM_BANDS]; - } UpSampler[4]; - - ALsizei NumChannels; - ALboolean DualBand; - - DEF_NEWDEL(BFormatDec) -}; - -BFormatDec *bformatdec_alloc() -{ return new BFormatDec{}; } - -void bformatdec_free(BFormatDec **dec) -{ - if(dec && *dec) - { - delete *dec; - *dec = nullptr; - } -} - void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS]) { static constexpr ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = { @@ -392,34 +352,12 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[B /* Now write each band to the output. */ MixRowSamples(OutBuffer[i], dec->UpSampler[i].Gains, &reinterpret_cast(dec->Samples[0]), - NUM_BANDS, 0, SamplesToDo + BFormatDec::NumBands, 0, SamplesToDo ); } } -struct AmbiUpsampler { - alignas(16) ALfloat Samples[NUM_BANDS][BUFFERSIZE]; - - BandSplitter XOver[4]; - - ALfloat Gains[4][MAX_OUTPUT_CHANNELS][NUM_BANDS]; - - DEF_NEWDEL(AmbiUpsampler) -}; - -AmbiUpsampler *ambiup_alloc() -{ return new AmbiUpsampler{}; } - -void ambiup_free(struct AmbiUpsampler **ambiup) -{ - if(ambiup) - { - delete *ambiup; - *ambiup = nullptr; - } -} - void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat w_scale, ALfloat xyz_scale) { ALfloat ratio; @@ -488,7 +426,7 @@ void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*RESTRICT OutBuffer)[ for(j = 0;j < OutChannels;j++) MixRowSamples(OutBuffer[j], ambiup->Gains[i][j], - ambiup->Samples, NUM_BANDS, 0, SamplesToDo + ambiup->Samples, AmbiUpsampler::NumBands, 0, SamplesToDo ); } } diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 964a89f9..0d3fe611 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -2,10 +2,12 @@ #define BFORMATDEC_H #include "alMain.h" +#include "filters/splitter.h" +#include "almalloc.h" + + +struct AmbDecConf; -#ifdef __cplusplus -extern "C" { -#endif /* These are the necessary scales for first-order HF responses to play over * higher-order 2D (non-periphonic) decoders. @@ -32,33 +34,62 @@ extern const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS]; extern const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS]; -struct AmbDecConf; -struct BFormatDec; -struct AmbiUpsampler; +struct BFormatDec { + static constexpr size_t NumBands{2}; + + ALuint Enabled; /* Bitfield of enabled channels. */ + + union { + alignas(16) ALfloat Dual[MAX_OUTPUT_CHANNELS][NumBands][MAX_AMBI_COEFFS]; + alignas(16) ALfloat Single[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; + } Matrix; + + /* NOTE: BandSplitter filters are unused with single-band decoding */ + BandSplitter XOver[MAX_AMBI_COEFFS]; + al::vector, 16> Samples; + /* These two alias into Samples */ + std::array *SamplesHF; + std::array *SamplesLF; -struct BFormatDec *bformatdec_alloc(); -void bformatdec_free(struct BFormatDec **dec); -void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS]); + alignas(16) ALfloat ChannelMix[BUFFERSIZE]; + + struct { + BandSplitter XOver; + ALfloat Gains[NumBands]; + } UpSampler[4]; + + ALsizei NumChannels; + ALboolean DualBand; + + DEF_NEWDEL(BFormatDec) +}; + +void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS]); /* Decodes the ambisonic input to the given output channels. */ -void bformatdec_process(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo); +void bformatdec_process(BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo); /* Up-samples a first-order input to the decoder's configuration. */ -void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo); +void bformatdec_upSample(BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo); /* Stand-alone first-order upsampler. Kept here because it shares some stuff * with bformatdec. Assumes a periphonic (4-channel) input mix! */ -struct AmbiUpsampler *ambiup_alloc(); -void ambiup_free(struct AmbiUpsampler **ambiup); -void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat w_scale, ALfloat xyz_scale); +struct AmbiUpsampler { + static constexpr size_t NumBands{2}; + + alignas(16) ALfloat Samples[NumBands][BUFFERSIZE]; + + BandSplitter XOver[4]; + + ALfloat Gains[4][MAX_OUTPUT_CHANNELS][NumBands]; -void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo); + DEF_NEWDEL(AmbiUpsampler) +}; -#ifdef __cplusplus -} // extern "C" -#endif +void ambiup_reset(AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat w_scale, ALfloat xyz_scale); +void ambiup_process(AmbiUpsampler *ambiup, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo); #endif /* BFORMATDEC_H */ diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 4ffdf969..e9a410e1 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -563,7 +563,7 @@ static void InitPanning(ALCdevice *device) w_scale = W_SCALE_2H2P; xyz_scale = XYZ_SCALE_2H2P; } - ambiup_reset(device->AmbiUp, device, w_scale, xyz_scale); + ambiup_reset(device->AmbiUp.get(), device, w_scale, xyz_scale); } if(ConfigValueFloat(devname, "decoder", "nfc-ref-delay", &nfc_delay) && nfc_delay > 0.0f) @@ -725,7 +725,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz (conf->ChanMask > 0xf) ? (conf->ChanMask > 0x1ff) ? "third" : "second" : "first", (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? " periphonic" : "" ); - bformatdec_reset(device->AmbiDecoder, conf, count, device->Frequency, speakermap); + bformatdec_reset(device->AmbiDecoder.get(), conf, count, device->Frequency, speakermap); if(conf->ChanMask <= 0xf) { @@ -879,7 +879,7 @@ static void InitHrtfPanning(ALCdevice *device) device->FOAOut.CoeffCount = 0; device->FOAOut.NumChannels = 4; - ambiup_reset(device->AmbiUp, device, AmbiOrderHFGainFOA[0] / AmbiOrderHFGain[0], + ambiup_reset(device->AmbiUp.get(), device, AmbiOrderHFGainFOA[0] / AmbiOrderHFGain[0], AmbiOrderHFGainFOA[1] / AmbiOrderHFGain[1]); } else @@ -995,20 +995,17 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(pconf && GetConfigValueBool(devname, "decoder", "hq-mode", 0)) { - ambiup_free(&device->AmbiUp); + device->AmbiUp = nullptr; if(!device->AmbiDecoder) - device->AmbiDecoder = bformatdec_alloc(); + device->AmbiDecoder.reset(new BFormatDec{}); } else { - bformatdec_free(&device->AmbiDecoder); + device->AmbiDecoder = nullptr; if(device->FmtChans != DevFmtAmbi3D || device->mAmbiOrder < 2) - ambiup_free(&device->AmbiUp); - else - { - if(!device->AmbiUp) - device->AmbiUp = ambiup_alloc(); - } + device->AmbiUp = nullptr; + else if(!device->AmbiUp) + device->AmbiUp.reset(new AmbiUpsampler{}); } if(!pconf) @@ -1058,7 +1055,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf return; } - bformatdec_free(&device->AmbiDecoder); + device->AmbiDecoder = nullptr; headphones = device->IsHeadphones; if(device->Type != Loopback) @@ -1147,12 +1144,12 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf /* Don't bother with HOA when using full HRTF rendering. Nothing * needs it, and it eases the CPU/memory load. */ - ambiup_free(&device->AmbiUp); + device->AmbiUp = nullptr; } else { if(!device->AmbiUp) - device->AmbiUp = ambiup_alloc(); + device->AmbiUp.reset(new AmbiUpsampler{}); } TRACE("%s HRTF rendering enabled, using \"%s\"\n", @@ -1171,7 +1168,7 @@ no_hrtf: device->Render_Mode = StereoPair; - ambiup_free(&device->AmbiUp); + device->AmbiUp = nullptr; bs2blevel = ((headphones && hrtf_appreq != Hrtf_Disable) || (hrtf_appreq == Hrtf_Enable)) ? 5 : 0; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index c57d87ba..de602d35 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -208,6 +208,8 @@ struct ALeffect; struct ALfilter; struct EffectState; struct Uhj2Encoder; +struct BFormatDec; +struct AmbiUpsampler; #define DEFAULT_OUTPUT_RATE (44100) @@ -673,13 +675,13 @@ struct ALCdevice_struct { std::unique_ptr Uhj_Encoder; /* High quality Ambisonic decoder */ - struct BFormatDec *AmbiDecoder{nullptr}; + std::unique_ptr AmbiDecoder; /* Stereo-to-binaural filter */ struct bs2b *Bs2b{nullptr}; /* First-order ambisonic upsampler for higher-order output */ - struct AmbiUpsampler *AmbiUp{nullptr}; + std::unique_ptr AmbiUp; /* Rendering mode. */ RenderMode Render_Mode{NormalRender}; -- cgit v1.2.3 From 9d73e03aaa6d51d6b787b0d576760f782fc3394f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Nov 2018 06:49:37 -0800 Subject: Use unique_ptr for bs2b --- Alc/alc.cpp | 6 +----- Alc/alu.cpp | 2 +- Alc/panning.cpp | 6 +++--- OpenAL32/Include/alMain.h | 3 ++- OpenAL32/Include/bs2b.h | 22 +++++++++------------- 5 files changed, 16 insertions(+), 23 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index d96f6df0..4c724fd6 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -53,6 +53,7 @@ #include "alconfig.h" #include "ringbuffer.h" #include "filters/splitter.h" +#include "bs2b.h" #include "fpu_modes.h" #include "cpu_caps.h" @@ -1990,8 +1991,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) return ALC_NO_ERROR; device->Uhj_Encoder = nullptr; - - al_free(device->Bs2b); device->Bs2b = nullptr; device->ChannelDelay.clear(); @@ -2421,9 +2420,6 @@ ALCdevice_struct::~ALCdevice_struct() HrtfHandle = nullptr; al_free(Hrtf); Hrtf = nullptr; - - al_free(Bs2b); - Bs2b = nullptr; } diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 9372da85..a8f2f402 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -175,7 +175,7 @@ void ProcessBs2b(ALCdevice *device, ALsizei SamplesToDo) assert(lidx != -1 && ridx != -1); /* Apply binaural/crossfeed filter */ - bs2b_cross_feed(device->Bs2b, device->RealOut.Buffer[lidx], + bs2b_cross_feed(device->Bs2b.get(), device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], SamplesToDo); } diff --git a/Alc/panning.cpp b/Alc/panning.cpp index e9a410e1..29c708f6 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -1163,7 +1163,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf no_hrtf: if(old_hrtf) Hrtf_DecRef(old_hrtf); - old_hrtf = NULL; + old_hrtf = nullptr; TRACE("HRTF disabled\n"); device->Render_Mode = StereoPair; @@ -1176,8 +1176,8 @@ no_hrtf: ConfigValueInt(device->DeviceName.c_str(), NULL, "cf_level", &bs2blevel); if(bs2blevel > 0 && bs2blevel <= 6) { - device->Bs2b = reinterpret_cast(al_calloc(16, sizeof(*device->Bs2b))); - bs2b_set_params(device->Bs2b, bs2blevel, device->Frequency); + device->Bs2b.reset(new bs2b{}); + bs2b_set_params(device->Bs2b.get(), bs2blevel, device->Frequency); TRACE("BS2B enabled\n"); InitPanning(device); return; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index de602d35..3fdd4e02 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -210,6 +210,7 @@ struct EffectState; struct Uhj2Encoder; struct BFormatDec; struct AmbiUpsampler; +struct bs2b; #define DEFAULT_OUTPUT_RATE (44100) @@ -678,7 +679,7 @@ struct ALCdevice_struct { std::unique_ptr AmbiDecoder; /* Stereo-to-binaural filter */ - struct bs2b *Bs2b{nullptr}; + std::unique_ptr Bs2b; /* First-order ambisonic upsampler for higher-order output */ std::unique_ptr AmbiUp; diff --git a/OpenAL32/Include/bs2b.h b/OpenAL32/Include/bs2b.h index 13cdf9a6..e235e765 100644 --- a/OpenAL32/Include/bs2b.h +++ b/OpenAL32/Include/bs2b.h @@ -24,6 +24,8 @@ #ifndef BS2B_H #define BS2B_H +#include "almalloc.h" + /* Number of crossfeed levels */ #define BS2B_CLEVELS 3 @@ -42,10 +44,6 @@ /* Default sample rate (Hz) */ #define BS2B_DEFAULT_SRATE 44100 -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - struct bs2b { int level; /* Crossfeed level */ int srate; /* Sample rate (Hz) */ @@ -67,6 +65,8 @@ struct bs2b { float lo; float hi; } last_sample[2]; + + DEF_NEWDEL(bs2b) }; /* Clear buffers and set new coefficients with new crossfeed level and sample @@ -74,21 +74,17 @@ struct bs2b { * level - crossfeed level of *LEVEL values. * srate - sample rate by Hz. */ -void bs2b_set_params(struct bs2b *bs2b, int level, int srate); +void bs2b_set_params(bs2b *bs2b, int level, int srate); /* Return current crossfeed level value */ -int bs2b_get_level(struct bs2b *bs2b); +int bs2b_get_level(bs2b *bs2b); /* Return current sample rate value */ -int bs2b_get_srate(struct bs2b *bs2b); +int bs2b_get_srate(bs2b *bs2b); /* Clear buffer */ -void bs2b_clear(struct bs2b *bs2b); - -void bs2b_cross_feed(struct bs2b *bs2b, float *RESTRICT Left, float *RESTRICT Right, int SamplesToDo); +void bs2b_clear(bs2b *bs2b); -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ +void bs2b_cross_feed(bs2b *bs2b, float *RESTRICT Left, float *RESTRICT Right, int SamplesToDo); #endif /* BS2B_H */ -- cgit v1.2.3 From ab6db9a589ac5ad8daa498e9fedb4de66cbb1948 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Nov 2018 06:59:32 -0800 Subject: Clean up some unnecessary specifiers --- Alc/alc.cpp | 4 ++-- Alc/alu.cpp | 12 ++++-------- Alc/hrtf.h | 12 ++++++------ Alc/panning.cpp | 8 ++++---- OpenAL32/Include/alMain.h | 6 +++--- 5 files changed, 19 insertions(+), 23 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 4c724fd6..10b4c007 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2418,8 +2418,8 @@ ALCdevice_struct::~ALCdevice_struct() if(HrtfHandle) Hrtf_DecRef(HrtfHandle); HrtfHandle = nullptr; - al_free(Hrtf); - Hrtf = nullptr; + al_free(mHrtfState); + mHrtfState = nullptr; } diff --git a/Alc/alu.cpp b/Alc/alu.cpp index a8f2f402..c67e8705 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -109,22 +109,18 @@ namespace { void ProcessHrtf(ALCdevice *device, ALsizei SamplesToDo) { - DirectHrtfState *state; - int lidx, ridx; - ALsizei c; - if(device->AmbiUp) ambiup_process(device->AmbiUp.get(), device->Dry.Buffer, device->Dry.NumChannels, device->FOAOut.Buffer, SamplesToDo ); - lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); - ridx = GetChannelIdxByName(&device->RealOut, FrontRight); + int lidx{GetChannelIdxByName(&device->RealOut, FrontLeft)}; + int ridx{GetChannelIdxByName(&device->RealOut, FrontRight)}; assert(lidx != -1 && ridx != -1); - state = device->Hrtf; - for(c = 0;c < device->Dry.NumChannels;c++) + DirectHrtfState *state{device->mHrtfState}; + for(ALsizei c{0};c < device->Dry.NumChannels;c++) { MixDirectHrtf(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], device->Dry.Buffer[c], state->Offset, state->IrSize, diff --git a/Alc/hrtf.h b/Alc/hrtf.h index a74df749..d73faca7 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -36,18 +36,18 @@ struct Hrtf { }; -typedef struct HrtfState { +struct HrtfState { alignas(16) ALfloat History[HRTF_HISTORY_LENGTH]; alignas(16) ALfloat Values[HRIR_LENGTH][2]; -} HrtfState; +}; -typedef struct HrtfParams { +struct HrtfParams { alignas(16) ALfloat Coeffs[HRIR_LENGTH][2]; ALsizei Delay[2]; ALfloat Gain; -} HrtfParams; +}; -typedef struct DirectHrtfState { +struct DirectHrtfState { /* HRTF filter state for dry buffer content */ ALsizei Offset; ALsizei IrSize; @@ -55,7 +55,7 @@ typedef struct DirectHrtfState { alignas(16) ALfloat Values[HRIR_LENGTH][2]; alignas(16) ALfloat Coeffs[HRIR_LENGTH][2]; } Chan[]; -} DirectHrtfState; +}; struct AngularPoint { ALfloat Elev; diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 29c708f6..e0677600 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -857,7 +857,7 @@ static void InitHrtfPanning(ALCdevice *device) count = COUNTOF(IndexMap); } - device->Hrtf = reinterpret_cast( + device->mHrtfState = reinterpret_cast( al_calloc(16, FAM_SIZE(DirectHrtfState, Chan, count))); for(i = 0;i < count;i++) @@ -892,7 +892,7 @@ static void InitHrtfPanning(ALCdevice *device) device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); BuildBFormatHrtf(device->HrtfHandle, - device->Hrtf, device->Dry.NumChannels, AmbiPoints, AmbiMatrix, COUNTOF(AmbiPoints), + device->mHrtfState, device->Dry.NumChannels, AmbiPoints, AmbiMatrix, COUNTOF(AmbiPoints), AmbiOrderHFGain ); @@ -930,8 +930,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf int bs2blevel; size_t i; - al_free(device->Hrtf); - device->Hrtf = nullptr; + al_free(device->mHrtfState); + device->mHrtfState = nullptr; device->HrtfHandle = nullptr; device->HrtfName.clear(); device->Render_Mode = NormalRender; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 3fdd4e02..3a8e28fc 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -666,9 +666,9 @@ struct ALCdevice_struct { POSTPROCESS PostProcess{}; /* HRTF state and info */ - struct DirectHrtfState *Hrtf{nullptr}; + DirectHrtfState *mHrtfState{nullptr}; std::string HrtfName; - struct Hrtf *HrtfHandle{nullptr}; + Hrtf *HrtfHandle{nullptr}; al::vector HrtfList; ALCenum HrtfStatus{ALC_FALSE}; @@ -739,7 +739,7 @@ struct ALCdevice_struct { ATOMIC(ALCcontext*) ContextList{nullptr}; almtx_t BackendLock; - struct ALCbackend *Backend{nullptr}; + ALCbackend *Backend{nullptr}; ATOMIC(ALCdevice*) next{nullptr}; -- cgit v1.2.3 From ba8c865513d33019962a02e00ab496365de17abf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Nov 2018 07:06:42 -0800 Subject: Add and use a macro to define placement-new-only allocators This is for structs that utilize over-allocation, either flexible array members, or which store optional additional objects in the same allocation block. --- Alc/mastering.h | 4 +--- common/almalloc.h | 4 ++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Alc/mastering.h b/Alc/mastering.h index a6cf58ed..14111130 100644 --- a/Alc/mastering.h +++ b/Alc/mastering.h @@ -61,9 +61,7 @@ struct Compressor { ALfloat LastAttack; ALfloat LastGainDev; - void *operator new(size_t size) = delete; - void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } - void operator delete(void *block) noexcept { al_free(block); } + DEF_PLACE_NEWDEL() }; /* The compressor is initialized with the following settings: diff --git a/common/almalloc.h b/common/almalloc.h index ccaa6a98..d9b285fe 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -31,6 +31,10 @@ int al_is_sane_alignment_allocator(void) noexcept; } \ void operator delete(void *block) noexcept { al_free(block); } +#define DEF_PLACE_NEWDEL() \ + void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } \ + void operator delete(void *block) noexcept { al_free(block); } + namespace al { template -- cgit v1.2.3 From 9c155a57fb37e3869f16e2f6502ee7d95d7d6a75 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Nov 2018 07:54:29 -0800 Subject: Use unique_ptr for DirectHrtfState --- Alc/alc.cpp | 2 -- Alc/alu.cpp | 2 +- Alc/hrtf.h | 3 +++ Alc/panning.cpp | 9 ++++----- OpenAL32/Include/alMain.h | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 10b4c007..42856dbf 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2418,8 +2418,6 @@ ALCdevice_struct::~ALCdevice_struct() if(HrtfHandle) Hrtf_DecRef(HrtfHandle); HrtfHandle = nullptr; - al_free(mHrtfState); - mHrtfState = nullptr; } diff --git a/Alc/alu.cpp b/Alc/alu.cpp index c67e8705..fc386908 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -119,7 +119,7 @@ void ProcessHrtf(ALCdevice *device, ALsizei SamplesToDo) int ridx{GetChannelIdxByName(&device->RealOut, FrontRight)}; assert(lidx != -1 && ridx != -1); - DirectHrtfState *state{device->mHrtfState}; + DirectHrtfState *state{device->mHrtfState.get()}; for(ALsizei c{0};c < device->Dry.NumChannels;c++) { MixDirectHrtf(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], diff --git a/Alc/hrtf.h b/Alc/hrtf.h index d73faca7..1409ffa8 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -7,6 +7,7 @@ #include "alMain.h" #include "atomic.h" #include "vector.h" +#include "almalloc.h" #define HRTF_HISTORY_BITS (6) @@ -55,6 +56,8 @@ struct DirectHrtfState { alignas(16) ALfloat Values[HRIR_LENGTH][2]; alignas(16) ALfloat Coeffs[HRIR_LENGTH][2]; } Chan[]; + + DEF_PLACE_NEWDEL() }; struct AngularPoint { diff --git a/Alc/panning.cpp b/Alc/panning.cpp index e0677600..a67234ec 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -857,8 +857,8 @@ static void InitHrtfPanning(ALCdevice *device) count = COUNTOF(IndexMap); } - device->mHrtfState = reinterpret_cast( - al_calloc(16, FAM_SIZE(DirectHrtfState, Chan, count))); + device->mHrtfState.reset( + new (al_calloc(16, FAM_SIZE(DirectHrtfState, Chan, count))) DirectHrtfState{}); for(i = 0;i < count;i++) { @@ -892,8 +892,8 @@ static void InitHrtfPanning(ALCdevice *device) device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); BuildBFormatHrtf(device->HrtfHandle, - device->mHrtfState, device->Dry.NumChannels, AmbiPoints, AmbiMatrix, COUNTOF(AmbiPoints), - AmbiOrderHFGain + device->mHrtfState.get(), device->Dry.NumChannels, AmbiPoints, AmbiMatrix, + COUNTOF(AmbiPoints), AmbiOrderHFGain ); InitNearFieldCtrl(device, device->HrtfHandle->distance, device->AmbiUp ? 2 : 1, @@ -930,7 +930,6 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf int bs2blevel; size_t i; - al_free(device->mHrtfState); device->mHrtfState = nullptr; device->HrtfHandle = nullptr; device->HrtfName.clear(); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 3a8e28fc..744e3609 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -666,7 +666,7 @@ struct ALCdevice_struct { POSTPROCESS PostProcess{}; /* HRTF state and info */ - DirectHrtfState *mHrtfState{nullptr}; + std::unique_ptr mHrtfState; std::string HrtfName; Hrtf *HrtfHandle{nullptr}; al::vector HrtfList; -- cgit v1.2.3 From cc938c34b2142c1215584c7f0c49458b9c5ee13a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Nov 2018 08:08:46 -0800 Subject: Clean up the Chorus a little --- Alc/effects/chorus.cpp | 117 ++++++++++++++++++++++--------------------------- 1 file changed, 53 insertions(+), 64 deletions(-) diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp index ee0b64e5..95f47d36 100644 --- a/Alc/effects/chorus.cpp +++ b/Alc/effects/chorus.cpp @@ -20,9 +20,9 @@ #include "config.h" -#include #include +#include #include #include "alMain.h" @@ -34,15 +34,41 @@ #include "vector.h" +namespace { + static_assert(AL_CHORUS_WAVEFORM_SINUSOID == AL_FLANGER_WAVEFORM_SINUSOID, "Chorus/Flanger waveform value mismatch"); static_assert(AL_CHORUS_WAVEFORM_TRIANGLE == AL_FLANGER_WAVEFORM_TRIANGLE, "Chorus/Flanger waveform value mismatch"); -enum WaveForm { - WF_Sinusoid, - WF_Triangle +enum class WaveForm { + Sinusoid, + Triangle }; -struct ALchorusState final : public EffectState { +void GetTriangleDelays(ALint *delays, ALsizei offset, ALsizei lfo_range, ALfloat lfo_scale, + ALfloat depth, ALsizei delay, ALsizei todo) +{ + std::generate_n(delays, todo, + [&offset,lfo_range,lfo_scale,depth,delay]() -> ALint + { + offset = (offset+1)%lfo_range; + return fastf2i((1.0f - std::abs(2.0f - lfo_scale*offset)) * depth) + delay; + } + ); +} + +void GetSinusoidDelays(ALint *delays, ALsizei offset, ALsizei lfo_range, ALfloat lfo_scale, + ALfloat depth, ALsizei delay, ALsizei todo) +{ + std::generate_n(delays, todo, + [&offset,lfo_range,lfo_scale,depth,delay]() -> ALint + { + offset = (offset+1)%lfo_range; + return fastf2i(std::sin(lfo_scale*offset) * depth) + delay; + } + ); +} + +struct ChorusState final : public EffectState { al::vector mSampleBuffer; ALsizei mOffset{0}; @@ -68,10 +94,10 @@ struct ALchorusState final : public EffectState { void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; - DEF_NEWDEL(ALchorusState) + DEF_NEWDEL(ChorusState) }; -ALboolean ALchorusState::deviceUpdate(ALCdevice *Device) +ALboolean ChorusState::deviceUpdate(ALCdevice *Device) { const ALfloat max_delay = maxf(AL_CHORUS_MAX_DELAY, AL_FLANGER_MAX_DELAY); size_t maxlen; @@ -95,41 +121,38 @@ ALboolean ALchorusState::deviceUpdate(ALCdevice *Device) return AL_TRUE; } -void ALchorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) +void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) { - const ALsizei mindelay = MAX_RESAMPLE_PADDING << FRACTIONBITS; - const ALCdevice *device = Context->Device; - ALfloat frequency = (ALfloat)device->Frequency; - ALfloat coeffs[MAX_AMBI_COEFFS]; - ALfloat rate; - ALint phase; + static constexpr ALsizei mindelay = MAX_RESAMPLE_PADDING << FRACTIONBITS; switch(props->Chorus.Waveform) { case AL_CHORUS_WAVEFORM_TRIANGLE: - mWaveform = WF_Triangle; + mWaveform = WaveForm::Triangle; break; case AL_CHORUS_WAVEFORM_SINUSOID: - mWaveform = WF_Sinusoid; + mWaveform = WaveForm::Sinusoid; break; } /* The LFO depth is scaled to be relative to the sample delay. Clamp the * delay and depth to allow enough padding for resampling. */ + const ALCdevice *device{Context->Device}; + auto frequency = static_cast(device->Frequency); mDelay = maxi(float2int(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f), mindelay); mDepth = minf(props->Chorus.Depth * mDelay, (ALfloat)(mDelay - mindelay)); mFeedback = props->Chorus.Feedback; /* Gains for left and right sides */ + ALfloat coeffs[MAX_AMBI_COEFFS]; CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs); ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, mGains[0].Target); CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs); ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, mGains[1].Target); - phase = props->Chorus.Phase; - rate = props->Chorus.Rate; + ALfloat rate{props->Chorus.Rate}; if(!(rate > 0.0f)) { mLfoOffset = 0; @@ -148,45 +171,22 @@ void ALchorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, mLfoRange = lfo_range; switch(mWaveform) { - case WF_Triangle: + case WaveForm::Triangle: mLfoScale = 4.0f / mLfoRange; break; - case WF_Sinusoid: + case WaveForm::Sinusoid: mLfoScale = F_TAU / mLfoRange; break; } /* Calculate lfo phase displacement */ + ALint phase{props->Chorus.Phase}; if(phase < 0) phase = 360 + phase; mLfoDisp = (mLfoRange*phase + 180) / 360; } } -static void GetTriangleDelays(ALint *RESTRICT delays, ALsizei offset, const ALsizei lfo_range, - const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, - const ALsizei todo) -{ - ALsizei i; - for(i = 0;i < todo;i++) - { - delays[i] = fastf2i((1.0f - fabsf(2.0f - lfo_scale*offset)) * depth) + delay; - offset = (offset+1)%lfo_range; - } -} - -static void GetSinusoidDelays(ALint *RESTRICT delays, ALsizei offset, const ALsizei lfo_range, - const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, - const ALsizei todo) -{ - ALsizei i; - for(i = 0;i < todo;i++) - { - delays[i] = fastf2i(sinf(lfo_scale*offset) * depth) + delay; - offset = (offset+1)%lfo_range; - } -} - -void ALchorusState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +void ChorusState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { const ALsizei bufmask = mSampleBuffer.size()-1; const ALfloat feedback = mFeedback; @@ -202,14 +202,14 @@ void ALchorusState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT Sample ALint moddelays[2][256]; alignas(16) ALfloat temps[2][256]; - if(mWaveform == WF_Sinusoid) + if(mWaveform == WaveForm::Sinusoid) { GetSinusoidDelays(moddelays[0], mLfoOffset, mLfoRange, mLfoScale, mDepth, mDelay, todo); GetSinusoidDelays(moddelays[1], (mLfoOffset+mLfoDisp)%mLfoRange, mLfoRange, mLfoScale, mDepth, mDelay, todo); } - else /*if(state->waveform == WF_Triangle)*/ + else /*if(mWaveform == WaveForm::Triangle)*/ { GetTriangleDelays(moddelays[0], mLfoOffset, mLfoRange, mLfoScale, mDepth, mDelay, todo); @@ -220,15 +220,12 @@ void ALchorusState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT Sample for(i = 0;i < todo;i++) { - ALint delay; - ALfloat mu; - // Feed the buffer's input first (necessary for delays < 1). delaybuf[offset&bufmask] = SamplesIn[0][base+i]; // Tap for the left output. - delay = offset - (moddelays[0][i]>>FRACTIONBITS); - mu = (moddelays[0][i]&FRACTIONMASK) * (1.0f/FRACTIONONE); + ALint delay{offset - (moddelays[0][i]>>FRACTIONBITS)}; + ALfloat mu{(moddelays[0][i]&FRACTIONMASK) * (1.0f/FRACTIONONE)}; temps[0][i] = cubic(delaybuf[(delay+1) & bufmask], delaybuf[(delay ) & bufmask], delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask], mu); @@ -261,7 +258,9 @@ struct ChorusStateFactory final : public EffectStateFactory { }; EffectState *ChorusStateFactory::create() -{ return new ALchorusState{}; } +{ return new ChorusState{}; } + +} // namespace EffectStateFactory *ChorusStateFactory_getFactory(void) { @@ -382,18 +381,8 @@ DEFINE_ALEFFECT_VTABLE(ALchorus); /* Flanger is basically a chorus with a really short delay. They can both use * the same processing functions, so piggyback flanger on the chorus functions. */ -struct FlangerStateFactory final : public EffectStateFactory { - EffectState *create() override; -}; - -EffectState *FlangerStateFactory::create() -{ return new ALchorusState{}; } - EffectStateFactory *FlangerStateFactory_getFactory(void) -{ - static FlangerStateFactory FlangerFactory{}; - return &FlangerFactory; -} +{ return ChorusStateFactory_getFactory(); } void ALflanger_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -- cgit v1.2.3 From bb9d8db73c3536ccea5fbb928ae27810f7f63e0e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Nov 2018 12:02:02 -0800 Subject: Clean up alSource.cpp some --- OpenAL32/alSource.cpp | 3892 ++++++++++++++++++++++++------------------------- 1 file changed, 1926 insertions(+), 1966 deletions(-) diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 0739f677..382875d5 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include "AL/al.h" @@ -45,188 +46,648 @@ #include "almalloc.h" -static ALsource *AllocSource(ALCcontext *context); -static void FreeSource(ALCcontext *context, ALsource *source); -static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALCcontext *context); -static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime); -static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime); -static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context); -static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac); -static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice); +namespace { -static inline ALsource *LookupSource(ALCcontext *context, ALuint id) +inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) { - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= context->SourceList.size())) - return nullptr; - SourceSubList &sublist{context->SourceList[lidx]}; - if(UNLIKELY(sublist.FreeMask & (U64(1)<VoiceIdx}; + if(idx >= 0 && idx < context->VoiceCount) + { + ALvoice *voice{context->Voices[idx]}; + if(voice->Source.load(std::memory_order_acquire) == source) + return voice; + } + source->VoiceIdx = -1; + return nullptr; } -static inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) +void UpdateSourceProps(ALsource *source, ALvoice *voice, ALCcontext *context) { - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= device->BufferList.size())) - return nullptr; - BufferSubList &sublist = device->BufferList[lidx]; - if(UNLIKELY(sublist.FreeMask & (U64(1)<FreeVoiceProps.load(std::memory_order_acquire)}; + if(!props) + props = static_cast(al_calloc(16, + FAM_SIZE(ALvoiceProps, Send, source->Send.size())) + ); + else + { + ALvoiceProps *next; + do { + next = props->next.load(std::memory_order_relaxed); + } while(context->FreeVoiceProps.compare_exchange_weak(props, next, + std::memory_order_acq_rel, std::memory_order_acquire) == 0); + } -static inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) -{ - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; + /* Copy in current property values. */ + props->Pitch = source->Pitch; + props->Gain = source->Gain; + props->OuterGain = source->OuterGain; + props->MinGain = source->MinGain; + props->MaxGain = source->MaxGain; + props->InnerAngle = source->InnerAngle; + props->OuterAngle = source->OuterAngle; + props->RefDistance = source->RefDistance; + props->MaxDistance = source->MaxDistance; + props->RolloffFactor = source->RolloffFactor; + std::copy_n(source->Position, 3, props->Position); + std::copy_n(source->Velocity, 3, props->Velocity); + std::copy_n(source->Direction, 3, props->Direction); + for(ALsizei i{0};i < 2;i++) + std::copy_n(source->Orientation[i], 3, props->Orientation[i]); + props->HeadRelative = source->HeadRelative; + props->mDistanceModel = source->mDistanceModel; + props->Resampler = source->Resampler; + props->DirectChannels = source->DirectChannels; + props->SpatializeMode = source->Spatialize; - if(UNLIKELY(lidx >= device->FilterList.size())) - return nullptr; - FilterSubList &sublist = device->FilterList[lidx]; - if(UNLIKELY(sublist.FreeMask & (U64(1)<DryGainHFAuto = source->DryGainHFAuto; + props->WetGainAuto = source->WetGainAuto; + props->WetGainHFAuto = source->WetGainHFAuto; + props->OuterGainHF = source->OuterGainHF; -static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) -{ - --id; - if(UNLIKELY(id >= context->EffectSlotList.size())) - return nullptr; - return context->EffectSlotList[id].get(); -} + props->AirAbsorptionFactor = source->AirAbsorptionFactor; + props->RoomRolloffFactor = source->RoomRolloffFactor; + props->DopplerFactor = source->DopplerFactor; + std::copy_n(source->StereoPan, 2, props->StereoPan); -typedef enum SourceProp { - srcPitch = AL_PITCH, - srcGain = AL_GAIN, - srcMinGain = AL_MIN_GAIN, - srcMaxGain = AL_MAX_GAIN, - srcMaxDistance = AL_MAX_DISTANCE, - srcRolloffFactor = AL_ROLLOFF_FACTOR, - srcDopplerFactor = AL_DOPPLER_FACTOR, - srcConeOuterGain = AL_CONE_OUTER_GAIN, - srcSecOffset = AL_SEC_OFFSET, - srcSampleOffset = AL_SAMPLE_OFFSET, - srcByteOffset = AL_BYTE_OFFSET, - srcConeInnerAngle = AL_CONE_INNER_ANGLE, - srcConeOuterAngle = AL_CONE_OUTER_ANGLE, - srcRefDistance = AL_REFERENCE_DISTANCE, + props->Radius = source->Radius; - srcPosition = AL_POSITION, - srcVelocity = AL_VELOCITY, - srcDirection = AL_DIRECTION, + props->Direct.Gain = source->Direct.Gain; + props->Direct.GainHF = source->Direct.GainHF; + props->Direct.HFReference = source->Direct.HFReference; + props->Direct.GainLF = source->Direct.GainLF; + props->Direct.LFReference = source->Direct.LFReference; - srcSourceRelative = AL_SOURCE_RELATIVE, - srcLooping = AL_LOOPING, - srcBuffer = AL_BUFFER, - srcSourceState = AL_SOURCE_STATE, - srcBuffersQueued = AL_BUFFERS_QUEUED, - srcBuffersProcessed = AL_BUFFERS_PROCESSED, - srcSourceType = AL_SOURCE_TYPE, + for(size_t i{0u};i < source->Send.size();i++) + { + props->Send[i].Slot = source->Send[i].Slot; + props->Send[i].Gain = source->Send[i].Gain; + props->Send[i].GainHF = source->Send[i].GainHF; + props->Send[i].HFReference = source->Send[i].HFReference; + props->Send[i].GainLF = source->Send[i].GainLF; + props->Send[i].LFReference = source->Send[i].LFReference; + } - /* ALC_EXT_EFX */ - srcConeOuterGainHF = AL_CONE_OUTER_GAINHF, - srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR, - srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR, - srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO, - srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, - srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, - srcDirectFilter = AL_DIRECT_FILTER, - srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER, + /* Set the new container for updating internal parameters. */ + props = voice->Update.exchange(props, std::memory_order_acq_rel); + if(props) + { + /* If there was an unused update container, put it back in the + * freelist. + */ + AtomicReplaceHead(context->FreeVoiceProps, props); + } +} - /* AL_SOFT_direct_channels */ - srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT, - /* AL_EXT_source_distance_model */ - srcDistanceModel = AL_DISTANCE_MODEL, +/* GetSourceSampleOffset + * + * Gets the current read offset for the given Source, in 32.32 fixed-point + * samples. The offset is relative to the start of the queue (not the start of + * the current buffer). + */ +ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime) +{ + ALCdevice *device{context->Device}; + const ALbufferlistitem *Current; + ALuint64 readPos; + ALuint refcount; + ALvoice *voice; - /* AL_SOFT_source_latency */ - srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT, - srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT, + do { + Current = nullptr; + readPos = 0; + while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) + althrd_yield(); + *clocktime = GetDeviceClockTime(device); - /* AL_EXT_STEREO_ANGLES */ - srcAngles = AL_STEREO_ANGLES, + voice = GetSourceVoice(Source, context); + if(voice) + { + Current = voice->current_buffer.load(std::memory_order_relaxed); - /* AL_EXT_SOURCE_RADIUS */ - srcRadius = AL_SOURCE_RADIUS, + readPos = (ALuint64)voice->position.load(std::memory_order_relaxed) << 32; + readPos |= (ALuint64)voice->position_fraction.load(std::memory_order_relaxed) << + (32-FRACTIONBITS); + } + std::atomic_thread_fence(std::memory_order_acquire); + } while(refcount != device->MixCount.load(std::memory_order_relaxed)); - /* AL_EXT_BFORMAT */ - srcOrientation = AL_ORIENTATION, + if(voice) + { + const ALbufferlistitem *BufferList{Source->queue}; + while(BufferList && BufferList != Current) + { + readPos += (ALuint64)BufferList->max_samples << 32; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + readPos = minu64(readPos, U64(0x7fffffffffffffff)); + } - /* AL_SOFT_source_resampler */ - srcResampler = AL_SOURCE_RESAMPLER_SOFT, + return (ALint64)readPos; +} - /* AL_SOFT_source_spatialize */ - srcSpatialize = AL_SOURCE_SPATIALIZE_SOFT, +/* GetSourceSecOffset + * + * Gets the current read offset for the given Source, in seconds. The offset is + * relative to the start of the queue (not the start of the current buffer). + */ +ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime) +{ + ALCdevice *device{context->Device}; + const ALbufferlistitem *Current; + ALuint64 readPos; + ALuint refcount; + ALvoice *voice; - /* ALC_SOFT_device_clock */ - srcSampleOffsetClockSOFT = AL_SAMPLE_OFFSET_CLOCK_SOFT, - srcSecOffsetClockSOFT = AL_SEC_OFFSET_CLOCK_SOFT, -} SourceProp; + do { + Current = nullptr; + readPos = 0; + while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) + althrd_yield(); + *clocktime = GetDeviceClockTime(device); -static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values); -static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values); -static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values); + voice = GetSourceVoice(Source, context); + if(voice) + { + Current = voice->current_buffer.load(std::memory_order_relaxed); -static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values); -static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values); -static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values); + readPos = (ALuint64)voice->position.load(std::memory_order_relaxed) << FRACTIONBITS; + readPos |= voice->position_fraction.load(std::memory_order_relaxed); + } + std::atomic_thread_fence(std::memory_order_acquire); + } while(refcount != device->MixCount.load(std::memory_order_relaxed)); -static inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) -{ - ALint idx = source->VoiceIdx; - if(idx >= 0 && idx < context->VoiceCount) + ALdouble offset{0.0}; + if(voice) { - ALvoice *voice = context->Voices[idx]; - if(ATOMIC_LOAD(&voice->Source, almemory_order_acquire) == source) - return voice; - } - source->VoiceIdx = -1; - return NULL; -} + const ALbufferlistitem *BufferList{Source->queue}; + const ALbuffer *BufferFmt{nullptr}; + while(BufferList && BufferList != Current) + { + for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i) + BufferFmt = BufferList->buffers[i]; + readPos += (ALuint64)BufferList->max_samples << FRACTIONBITS; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } -/** - * Returns if the last known state for the source was playing or paused. Does - * not sync with the mixer voice. - */ -static inline bool IsPlayingOrPaused(ALsource *source) -{ return source->state == AL_PLAYING || source->state == AL_PAUSED; } + while(BufferList && !BufferFmt) + { + for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i) + BufferFmt = BufferList->buffers[i]; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + assert(BufferFmt != nullptr); -/** - * Returns an updated source state using the matching voice's status (or lack - * thereof). - */ -static inline ALenum GetSourceState(ALsource *source, ALvoice *voice) -{ - if(!voice && source->state == AL_PLAYING) - source->state = AL_STOPPED; - return source->state; -} + offset = (ALdouble)readPos / (ALdouble)FRACTIONONE / + (ALdouble)BufferFmt->Frequency; + } -/** - * Returns if the source should specify an update, given the context's - * deferring state and the source's last known state. - */ -static inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context) -{ - return !context->DeferUpdates.load(std::memory_order_acquire) && - IsPlayingOrPaused(source); + return offset; } - -/** Can only be called while the mixer is locked! */ -static void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) +/* GetSourceOffset + * + * Gets the current read offset for the given Source, in the appropriate format + * (Bytes, Samples or Seconds). The offset is relative to the start of the + * queue (not the start of the current buffer). + */ +ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) +{ + ALCdevice *device{context->Device}; + const ALbufferlistitem *Current; + ALuint readPos; + ALsizei readPosFrac; + ALuint refcount; + ALvoice *voice; + + do { + Current = nullptr; + readPos = readPosFrac = 0; + while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) + althrd_yield(); + voice = GetSourceVoice(Source, context); + if(voice) + { + Current = voice->current_buffer.load(std::memory_order_relaxed); + + readPos = voice->position.load(std::memory_order_relaxed); + readPosFrac = voice->position_fraction.load(std::memory_order_relaxed); + } + std::atomic_thread_fence(std::memory_order_acquire); + } while(refcount != device->MixCount.load(std::memory_order_relaxed)); + + ALdouble offset{0.0}; + if(voice) + { + const ALbufferlistitem *BufferList{Source->queue}; + const ALbuffer *BufferFmt{nullptr}; + ALboolean readFin{AL_FALSE}; + ALuint totalBufferLen{0u}; + + while(BufferList) + { + for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i) + BufferFmt = BufferList->buffers[i]; + + readFin |= (BufferList == Current); + totalBufferLen += BufferList->max_samples; + if(!readFin) readPos += BufferList->max_samples; + + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + assert(BufferFmt != nullptr); + + if(Source->Looping) + readPos %= totalBufferLen; + else + { + /* Wrap back to 0 */ + if(readPos >= totalBufferLen) + readPos = readPosFrac = 0; + } + + offset = 0.0; + switch(name) + { + case AL_SEC_OFFSET: + offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE) / BufferFmt->Frequency; + break; + + case AL_SAMPLE_OFFSET: + offset = readPos + (ALdouble)readPosFrac/FRACTIONONE; + break; + + case AL_BYTE_OFFSET: + if(BufferFmt->OriginalType == UserFmtIMA4) + { + ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; + ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels); + ALuint FrameBlockSize = BufferFmt->OriginalAlign; + + /* Round down to nearest ADPCM block */ + offset = (ALdouble)(readPos / FrameBlockSize * BlockSize); + } + else if(BufferFmt->OriginalType == UserFmtMSADPCM) + { + ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; + ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels); + ALuint FrameBlockSize = BufferFmt->OriginalAlign; + + /* Round down to nearest ADPCM block */ + offset = (ALdouble)(readPos / FrameBlockSize * BlockSize); + } + else + { + ALuint FrameSize = FrameSizeFromFmt(BufferFmt->FmtChannels, + BufferFmt->FmtType); + offset = (ALdouble)(readPos * FrameSize); + } + break; + } + } + + return offset; +} + + +/* GetSampleOffset + * + * Retrieves the sample offset into the Source's queue (from the Sample, Byte + * or Second offset supplied by the application). This takes into account the + * fact that the buffer format may have been modifed since. + */ +ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac) +{ + const ALbuffer *BufferFmt{nullptr}; + const ALbufferlistitem *BufferList; + + /* Find the first valid Buffer in the Queue */ + BufferList = Source->queue; + while(BufferList) + { + for(ALsizei i{0};i < BufferList->num_buffers && !BufferFmt;i++) + BufferFmt = BufferList->buffers[i]; + if(BufferFmt) break; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + if(!BufferFmt) + { + Source->OffsetType = AL_NONE; + Source->Offset = 0.0; + return AL_FALSE; + } + + ALdouble dbloff, dblfrac; + switch(Source->OffsetType) + { + case AL_BYTE_OFFSET: + /* Determine the ByteOffset (and ensure it is block aligned) */ + *offset = (ALuint)Source->Offset; + if(BufferFmt->OriginalType == UserFmtIMA4) + { + ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; + *offset /= align * ChannelsFromFmt(BufferFmt->FmtChannels); + *offset *= BufferFmt->OriginalAlign; + } + else if(BufferFmt->OriginalType == UserFmtMSADPCM) + { + ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; + *offset /= align * ChannelsFromFmt(BufferFmt->FmtChannels); + *offset *= BufferFmt->OriginalAlign; + } + else + *offset /= FrameSizeFromFmt(BufferFmt->FmtChannels, BufferFmt->FmtType); + *frac = 0; + break; + + case AL_SAMPLE_OFFSET: + dblfrac = modf(Source->Offset, &dbloff); + *offset = (ALuint)mind(dbloff, std::numeric_limits::max()); + *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0); + break; + + case AL_SEC_OFFSET: + dblfrac = modf(Source->Offset*BufferFmt->Frequency, &dbloff); + *offset = (ALuint)mind(dbloff, std::numeric_limits::max()); + *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0); + break; + } + Source->OffsetType = AL_NONE; + Source->Offset = 0.0; + + return AL_TRUE; +} + +/* ApplyOffset + * + * Apply the stored playback offset to the Source. This function will update + * the number of buffers "played" given the stored offset. + */ +ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) +{ + /* Get sample frame offset */ + ALuint offset{0u}; + ALsizei frac{0}; + if(!GetSampleOffset(Source, &offset, &frac)) + return AL_FALSE; + + ALuint totalBufferLen{0u}; + ALbufferlistitem *BufferList{Source->queue}; + while(BufferList && totalBufferLen <= offset) + { + if((ALuint)BufferList->max_samples > offset-totalBufferLen) + { + /* Offset is in this buffer */ + voice->position.store(offset - totalBufferLen, std::memory_order_relaxed); + voice->position_fraction.store(frac, std::memory_order_relaxed); + voice->current_buffer.store(BufferList, std::memory_order_release); + return AL_TRUE; + } + totalBufferLen += BufferList->max_samples; + + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + + /* Offset is out of range of the queue */ + return AL_FALSE; +} + + +ALsource *AllocSource(ALCcontext *context) +{ + ALCdevice *device{context->Device}; + std::lock_guard _{context->SourceLock}; + if(context->NumSources >= device->SourcesMax) + { + alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax); + return nullptr; + } + auto sublist = std::find_if(context->SourceList.begin(), context->SourceList.end(), + [](const SourceSubList &entry) -> bool + { return entry.FreeMask != 0; } + ); + ALsizei lidx = std::distance(context->SourceList.begin(), sublist); + ALsource *source; + ALsizei slidx; + if(LIKELY(sublist != context->SourceList.end())) + { + slidx = CTZ64(sublist->FreeMask); + source = sublist->Sources + slidx; + } + else + { + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(context->SourceList.size() >= 1<<25)) + { + alSetError(context, AL_OUT_OF_MEMORY, "Too many sources allocated"); + return nullptr; + } + context->SourceList.emplace_back(); + sublist = context->SourceList.end() - 1; + + sublist->FreeMask = ~U64(0); + sublist->Sources = static_cast(al_calloc(16, sizeof(ALsource)*64)); + if(UNLIKELY(!sublist->Sources)) + { + context->SourceList.pop_back(); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate source batch"); + return nullptr; + } + + slidx = 0; + source = sublist->Sources + slidx; + } + + source = new (source) ALsource{device->NumAuxSends}; + + /* Add 1 to avoid source ID 0. */ + source->id = ((lidx<<6) | slidx) + 1; + + context->NumSources += 1; + sublist->FreeMask &= ~(U64(1)<id - 1; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; + + ALCdevice *device{context->Device}; + ALCdevice_Lock(device); + ALvoice *voice{GetSourceVoice(source, context)}; + if(voice) + { + voice->Source.store(nullptr, std::memory_order_relaxed); + voice->Playing.store(false, std::memory_order_release); + } + ALCdevice_Unlock(device); + + source->~ALsource(); + + context->SourceList[lidx].FreeMask |= U64(1) << slidx; + context->NumSources--; +} + + +inline ALsource *LookupSource(ALCcontext *context, ALuint id) noexcept +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= context->SourceList.size())) + return nullptr; + SourceSubList &sublist{context->SourceList[lidx]}; + if(UNLIKELY(sublist.FreeMask & (U64(1)<> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= device->BufferList.size())) + return nullptr; + BufferSubList &sublist = device->BufferList[lidx]; + if(UNLIKELY(sublist.FreeMask & (U64(1)<> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= device->FilterList.size())) + return nullptr; + FilterSubList &sublist = device->FilterList[lidx]; + if(UNLIKELY(sublist.FreeMask & (U64(1)<= context->EffectSlotList.size())) + return nullptr; + return context->EffectSlotList[id].get(); +} + + +enum SourceProp { + srcPitch = AL_PITCH, + srcGain = AL_GAIN, + srcMinGain = AL_MIN_GAIN, + srcMaxGain = AL_MAX_GAIN, + srcMaxDistance = AL_MAX_DISTANCE, + srcRolloffFactor = AL_ROLLOFF_FACTOR, + srcDopplerFactor = AL_DOPPLER_FACTOR, + srcConeOuterGain = AL_CONE_OUTER_GAIN, + srcSecOffset = AL_SEC_OFFSET, + srcSampleOffset = AL_SAMPLE_OFFSET, + srcByteOffset = AL_BYTE_OFFSET, + srcConeInnerAngle = AL_CONE_INNER_ANGLE, + srcConeOuterAngle = AL_CONE_OUTER_ANGLE, + srcRefDistance = AL_REFERENCE_DISTANCE, + + srcPosition = AL_POSITION, + srcVelocity = AL_VELOCITY, + srcDirection = AL_DIRECTION, + + srcSourceRelative = AL_SOURCE_RELATIVE, + srcLooping = AL_LOOPING, + srcBuffer = AL_BUFFER, + srcSourceState = AL_SOURCE_STATE, + srcBuffersQueued = AL_BUFFERS_QUEUED, + srcBuffersProcessed = AL_BUFFERS_PROCESSED, + srcSourceType = AL_SOURCE_TYPE, + + /* ALC_EXT_EFX */ + srcConeOuterGainHF = AL_CONE_OUTER_GAINHF, + srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR, + srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR, + srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO, + srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, + srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, + srcDirectFilter = AL_DIRECT_FILTER, + srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER, + + /* AL_SOFT_direct_channels */ + srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT, + + /* AL_EXT_source_distance_model */ + srcDistanceModel = AL_DISTANCE_MODEL, + + /* AL_SOFT_source_latency */ + srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT, + srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT, + + /* AL_EXT_STEREO_ANGLES */ + srcAngles = AL_STEREO_ANGLES, + + /* AL_EXT_SOURCE_RADIUS */ + srcRadius = AL_SOURCE_RADIUS, + + /* AL_EXT_BFORMAT */ + srcOrientation = AL_ORIENTATION, + + /* AL_SOFT_source_resampler */ + srcResampler = AL_SOURCE_RESAMPLER_SOFT, + + /* AL_SOFT_source_spatialize */ + srcSpatialize = AL_SOURCE_SPATIALIZE_SOFT, + + /* ALC_SOFT_device_clock */ + srcSampleOffsetClockSOFT = AL_SAMPLE_OFFSET_CLOCK_SOFT, + srcSecOffsetClockSOFT = AL_SEC_OFFSET_CLOCK_SOFT, +}; + +/** + * Returns if the last known state for the source was playing or paused. Does + * not sync with the mixer voice. + */ +inline bool IsPlayingOrPaused(ALsource *source) +{ return source->state == AL_PLAYING || source->state == AL_PAUSED; } + +/** + * Returns an updated source state using the matching voice's status (or lack + * thereof). + */ +inline ALenum GetSourceState(ALsource *source, ALvoice *voice) +{ + if(!voice && source->state == AL_PLAYING) + source->state = AL_STOPPED; + return source->state; +} + +/** + * Returns if the source should specify an update, given the context's + * deferring state and the source's last known state. + */ +inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context) +{ + return !context->DeferUpdates.load(std::memory_order_acquire) && + IsPlayingOrPaused(source); +} + + +/** Can only be called while the mixer is locked! */ +void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) { AsyncEvent evt = ASYNC_EVENT(EventType_SourceStateChange); ALbitfieldSOFT enabledevt; - enabledevt = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); + enabledevt = context->EnabledEvts.load(std::memory_order_acquire); if(!(enabledevt&EventType_SourceStateChange)) return; evt.u.user.type = AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT; @@ -247,7 +708,7 @@ static void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) } -static ALint FloatValsByProp(ALenum prop) +ALint FloatValsByProp(ALenum prop) { if(prop != (ALenum)((SourceProp)prop)) return 0; @@ -311,7 +772,7 @@ static ALint FloatValsByProp(ALenum prop) } return 0; } -static ALint DoubleValsByProp(ALenum prop) +ALint DoubleValsByProp(ALenum prop) { if(prop != (ALenum)((SourceProp)prop)) return 0; @@ -374,7 +835,7 @@ static ALint DoubleValsByProp(ALenum prop) return 0; } -static ALint IntValsByProp(ALenum prop) +ALint IntValsByProp(ALenum prop) { if(prop != (ALenum)((SourceProp)prop)) return 0; @@ -435,7 +896,7 @@ static ALint IntValsByProp(ALenum prop) } return 0; } -static ALint Int64ValsByProp(ALenum prop) +ALint Int64ValsByProp(ALenum prop) { if(prop != (ALenum)((SourceProp)prop)) return 0; @@ -499,6 +960,10 @@ static ALint Int64ValsByProp(ALenum prop) } +ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values); +ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values); +ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values); + #define CHECKVAL(x) do { \ if(!(x)) \ { \ @@ -510,13 +975,13 @@ static ALint Int64ValsByProp(ALenum prop) #define DO_UPDATEPROPS() do { \ ALvoice *voice; \ if(SourceShouldUpdate(Source, Context) && \ - (voice=GetSourceVoice(Source, Context)) != NULL) \ + (voice=GetSourceVoice(Source, Context)) != nullptr) \ UpdateSourceProps(Source, voice, Context); \ else \ Source->PropsClean.clear(std::memory_order_release); \ } while(0) -static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values) +ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values) { ALint ival; @@ -743,14 +1208,15 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source float property 0x%04x", prop); } -static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values) +ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values) { - ALCdevice *device = Context->Device; - ALbuffer *buffer = NULL; - ALfilter *filter = NULL; - ALeffectslot *slot = NULL; - ALbufferlistitem *oldlist; + ALCdevice *device{Context->Device}; + ALbuffer *buffer{nullptr}; + ALfilter *filter{nullptr}; + ALeffectslot *slot{nullptr}; + ALbufferlistitem *oldlist{nullptr}; std::unique_lock slotlock; + std::unique_lock buflock; ALfloat fvals[6]; switch(prop) @@ -776,57 +1242,47 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->Looping = (ALboolean)*values; if(IsPlayingOrPaused(Source)) { - ALvoice *voice = GetSourceVoice(Source, Context); + ALvoice *voice{GetSourceVoice(Source, Context)}; if(voice) { if(Source->Looping) - ATOMIC_STORE(&voice->loop_buffer, Source->queue, almemory_order_release); + voice->loop_buffer.store(Source->queue, std::memory_order_release); else - ATOMIC_STORE(&voice->loop_buffer, static_cast(nullptr), - almemory_order_release); + voice->loop_buffer.store(nullptr, std::memory_order_release); /* If the source is playing, wait for the current mix to finish * to ensure it isn't currently looping back or reaching the * end. */ - while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) + while((device->MixCount.load(std::memory_order_acquire)&1)) althrd_yield(); } } return AL_TRUE; case AL_BUFFER: - LockBufferList(device); - if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL)) - { - UnlockBufferList(device); + buflock = std::unique_lock{device->BufferLock}; + if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != nullptr)) SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid buffer ID %u", *values); - } if(buffer && buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) - { - UnlockBufferList(device); SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, "Setting non-persistently mapped buffer %u", buffer->id); - } else { ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context)); if(state == AL_PLAYING || state == AL_PAUSED) - { - UnlockBufferList(device); SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, "Setting buffer on playing or paused source %u", Source->id); - } } oldlist = Source->queue; - if(buffer != NULL) + if(buffer != nullptr) { /* Add the selected buffer to a one-item queue */ - ALbufferlistitem *newlist = static_cast(al_calloc(DEF_ALIGN, + auto newlist = static_cast(al_calloc(DEF_ALIGN, FAM_SIZE(ALbufferlistitem, buffers, 1))); ATOMIC_INIT(&newlist->next, static_cast(nullptr)); newlist->max_samples = buffer->SampleLen; @@ -842,18 +1298,17 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p { /* Source is now Undetermined */ Source->SourceType = AL_UNDETERMINED; - Source->queue = NULL; + Source->queue = nullptr; } - UnlockBufferList(device); + buflock.unlock(); /* Delete all elements in the previous queue */ - while(oldlist != NULL) + while(oldlist != nullptr) { - ALsizei i; - ALbufferlistitem *temp = oldlist; - oldlist = ATOMIC_LOAD(&temp->next, almemory_order_relaxed); + ALbufferlistitem *temp{oldlist}; + oldlist = temp->next.load(std::memory_order_relaxed); - for(i = 0;i < temp->num_buffers;i++) + for(ALsizei i{0};i < temp->num_buffers;i++) { if(temp->buffers[i]) DecrementRef(&temp->buffers[i]->ref); @@ -872,10 +1327,8 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p if(IsPlayingOrPaused(Source)) { - ALvoice *voice; - ALCdevice_Lock(Context->Device); - voice = GetSourceVoice(Source, Context); + ALvoice *voice{GetSourceVoice(Source, Context)}; if(voice) { if(ApplyOffset(Source, voice) == AL_FALSE) @@ -891,7 +1344,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_DIRECT_FILTER: LockFilterList(device); - if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL)) + if(!(*values == 0 || (filter=LookupFilter(device, *values)) != nullptr)) { UnlockFilterList(device); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", @@ -977,22 +1430,15 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_AUXILIARY_SEND_FILTER: slotlock = std::unique_lock{Context->EffectSlotLock}; - if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL)) - { - slotlock.unlock(); + if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != nullptr)) SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid effect ID %u", values[0]); - } if((ALuint)values[1] >= (ALuint)device->NumAuxSends) - { - slotlock.unlock(); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid send %u", values[1]); - } LockFilterList(device); - if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)) + if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != nullptr)) { UnlockFilterList(device); - slotlock.unlock(); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", values[2]); } @@ -1018,7 +1464,6 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source)) { - ALvoice *voice; /* Add refcount on the new slot, and release the previous slot */ if(slot) IncrementRef(&slot->ref); if(Source->Send[values[1]].Slot) @@ -1028,10 +1473,9 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p /* We must force an update if the auxiliary slot changed on an * active source, in case the slot is about to be deleted. */ - if((voice=GetSourceVoice(Source, Context)) != NULL) - UpdateSourceProps(Source, voice, Context); - else - Source->PropsClean.clear(std::memory_order_release); + ALvoice *voice{GetSourceVoice(Source, Context)}; + if(voice) UpdateSourceProps(Source, voice, Context); + else Source->PropsClean.clear(std::memory_order_release); } else { @@ -1096,7 +1540,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p prop); } -static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values) +ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values) { ALfloat fvals[6]; ALint ivals[3]; @@ -1202,9 +1646,13 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp #undef CHECKVAL -static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values) +ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values); +ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values); +ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values); + +ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values) { - ALCdevice *device = Context->Device; + ALCdevice *device{Context->Device}; ClockLatency clocktime; ALuint64 srcclock; ALint ivals[3]; @@ -1282,280 +1730,17 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p values[0] = Source->StereoPan[0]; values[1] = Source->StereoPan[1]; return AL_TRUE; - - case AL_SEC_OFFSET_LATENCY_SOFT: - /* Get the source offset with the clock time first. Then get the - * clock time with the device latency. Order is important. - */ - values[0] = GetSourceSecOffset(Source, Context, &srcclock); - { std::lock_guard _{device->BackendLock}; - clocktime = GetClockLatency(device); - } - if(srcclock == (ALuint64)clocktime.ClockTime) - values[1] = (ALdouble)clocktime.Latency / 1000000000.0; - else - { - /* If the clock time incremented, reduce the latency by that - * much since it's that much closer to the source offset it got - * earlier. - */ - ALuint64 diff = clocktime.ClockTime - srcclock; - values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) / - 1000000000.0; - } - return AL_TRUE; - - case AL_SEC_OFFSET_CLOCK_SOFT: - values[0] = GetSourceSecOffset(Source, Context, &srcclock); - values[1] = srcclock / 1000000000.0; - return AL_TRUE; - - case AL_POSITION: - values[0] = Source->Position[0]; - values[1] = Source->Position[1]; - values[2] = Source->Position[2]; - return AL_TRUE; - - case AL_VELOCITY: - values[0] = Source->Velocity[0]; - values[1] = Source->Velocity[1]; - values[2] = Source->Velocity[2]; - return AL_TRUE; - - case AL_DIRECTION: - values[0] = Source->Direction[0]; - values[1] = Source->Direction[1]; - values[2] = Source->Direction[2]; - return AL_TRUE; - - case AL_ORIENTATION: - values[0] = Source->Orientation[0][0]; - values[1] = Source->Orientation[0][1]; - values[2] = Source->Orientation[0][2]; - values[3] = Source->Orientation[1][0]; - values[4] = Source->Orientation[1][1]; - values[5] = Source->Orientation[1][2]; - return AL_TRUE; - - /* 1x int */ - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) - *values = (ALdouble)ivals[0]; - return err; - - case AL_BUFFER: - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; - } - - ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source double property 0x%04x", - prop); -} - -static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values) -{ - ALbufferlistitem *BufferList; - ALdouble dvals[6]; - ALboolean err; - - switch(prop) - { - case AL_SOURCE_RELATIVE: - *values = Source->HeadRelative; - return AL_TRUE; - - case AL_LOOPING: - *values = Source->Looping; - return AL_TRUE; - - case AL_BUFFER: - BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : NULL; - *values = (BufferList && BufferList->num_buffers >= 1 && BufferList->buffers[0]) ? - BufferList->buffers[0]->id : 0; - return AL_TRUE; - - case AL_SOURCE_STATE: - *values = GetSourceState(Source, GetSourceVoice(Source, Context)); - return AL_TRUE; - - case AL_BUFFERS_QUEUED: - if(!(BufferList=Source->queue)) - *values = 0; - else - { - ALsizei count = 0; - do { - count += BufferList->num_buffers; - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); - } while(BufferList != NULL); - *values = count; - } - return AL_TRUE; - - case AL_BUFFERS_PROCESSED: - if(Source->Looping || Source->SourceType != AL_STREAMING) - { - /* Buffers on a looping source are in a perpetual state of - * PENDING, so don't report any as PROCESSED */ - *values = 0; - } - else - { - const ALbufferlistitem *BufferList = Source->queue; - const ALbufferlistitem *Current = NULL; - ALsizei played = 0; - ALvoice *voice; - - if((voice=GetSourceVoice(Source, Context)) != NULL) - Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - else if(Source->state == AL_INITIAL) - Current = BufferList; - - while(BufferList && BufferList != Current) - { - played += BufferList->num_buffers; - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - *values = played; - } - return AL_TRUE; - - case AL_SOURCE_TYPE: - *values = Source->SourceType; - return AL_TRUE; - - case AL_DIRECT_FILTER_GAINHF_AUTO: - *values = Source->DryGainHFAuto; - return AL_TRUE; - - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - *values = Source->WetGainAuto; - return AL_TRUE; - - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - *values = Source->WetGainHFAuto; - return AL_TRUE; - - case AL_DIRECT_CHANNELS_SOFT: - *values = Source->DirectChannels; - return AL_TRUE; - - case AL_DISTANCE_MODEL: - *values = static_cast(Source->mDistanceModel); - return AL_TRUE; - - case AL_SOURCE_RESAMPLER_SOFT: - *values = Source->Resampler; - return AL_TRUE; - - case AL_SOURCE_SPATIALIZE_SOFT: - *values = Source->Spatialize; - return AL_TRUE; - - /* 1x float/double */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_DOPPLER_FACTOR: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_SOURCE_RADIUS: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - *values = (ALint)dvals[0]; - return err; - - /* 3x float/double */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - { - values[0] = (ALint)dvals[0]; - values[1] = (ALint)dvals[1]; - values[2] = (ALint)dvals[2]; - } - return err; - - /* 6x float/double */ - case AL_ORIENTATION: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - { - values[0] = (ALint)dvals[0]; - values[1] = (ALint)dvals[1]; - values[2] = (ALint)dvals[2]; - values[3] = (ALint)dvals[3]; - values[4] = (ALint)dvals[4]; - values[5] = (ALint)dvals[5]; - } - return err; - - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; /* i64 only */ - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - case AL_STEREO_ANGLES: - break; /* Float/double only */ - - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - break; /* ??? */ - } - - ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x", - prop); -} - -static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values) -{ - ALCdevice *device = Context->Device; - ClockLatency clocktime; - ALuint64 srcclock; - ALdouble dvals[6]; - ALint ivals[3]; - ALboolean err; - - switch(prop) - { - case AL_SAMPLE_OFFSET_LATENCY_SOFT: + + case AL_SEC_OFFSET_LATENCY_SOFT: /* Get the source offset with the clock time first. Then get the * clock time with the device latency. Order is important. */ - values[0] = GetSourceSampleOffset(Source, Context, &srcclock); + values[0] = GetSourceSecOffset(Source, Context, &srcclock); { std::lock_guard _{device->BackendLock}; clocktime = GetClockLatency(device); } if(srcclock == (ALuint64)clocktime.ClockTime) - values[1] = clocktime.Latency; + values[1] = (ALdouble)clocktime.Latency / 1000000000.0; else { /* If the clock time incremented, reduce the latency by that @@ -1563,62 +1748,42 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp * earlier. */ ALuint64 diff = clocktime.ClockTime - srcclock; - values[1] = clocktime.Latency - minu64(clocktime.Latency, diff); + values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) / + 1000000000.0; } return AL_TRUE; - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - values[0] = GetSourceSampleOffset(Source, Context, &srcclock); - values[1] = srcclock; + case AL_SEC_OFFSET_CLOCK_SOFT: + values[0] = GetSourceSecOffset(Source, Context, &srcclock); + values[1] = srcclock / 1000000000.0; return AL_TRUE; - /* 1x float/double */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_DOPPLER_FACTOR: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_SOURCE_RADIUS: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - *values = (ALint64)dvals[0]; - return err; - - /* 3x float/double */ case AL_POSITION: + values[0] = Source->Position[0]; + values[1] = Source->Position[1]; + values[2] = Source->Position[2]; + return AL_TRUE; + case AL_VELOCITY: + values[0] = Source->Velocity[0]; + values[1] = Source->Velocity[1]; + values[2] = Source->Velocity[2]; + return AL_TRUE; + case AL_DIRECTION: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - { - values[0] = (ALint64)dvals[0]; - values[1] = (ALint64)dvals[1]; - values[2] = (ALint64)dvals[2]; - } - return err; + values[0] = Source->Direction[0]; + values[1] = Source->Direction[1]; + values[2] = Source->Direction[2]; + return AL_TRUE; - /* 6x float/double */ case AL_ORIENTATION: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - { - values[0] = (ALint64)dvals[0]; - values[1] = (ALint64)dvals[1]; - values[2] = (ALint64)dvals[2]; - values[3] = (ALint64)dvals[3]; - values[4] = (ALint64)dvals[4]; - values[5] = (ALint64)dvals[5]; - } - return err; + values[0] = Source->Orientation[0][0]; + values[1] = Source->Orientation[0][1]; + values[2] = Source->Orientation[0][2]; + values[3] = Source->Orientation[1][0]; + values[4] = Source->Orientation[1][1]; + values[5] = Source->Orientation[1][2]; + return AL_TRUE; /* 1x int */ case AL_SOURCE_RELATIVE: @@ -1635,1817 +1800,1612 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp case AL_SOURCE_RESAMPLER_SOFT: case AL_SOURCE_SPATIALIZE_SOFT: if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) - *values = ivals[0]; + *values = (ALdouble)ivals[0]; return err; - /* 1x uint */ case AL_BUFFER: case AL_DIRECT_FILTER: - if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) - *values = (ALuint)ivals[0]; - return err; - - /* 3x uint */ case AL_AUXILIARY_SEND_FILTER: - if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) - { - values[0] = (ALuint)ivals[0]; - values[1] = (ALuint)ivals[1]; - values[2] = (ALuint)ivals[2]; - } - return err; - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - case AL_STEREO_ANGLES: - break; /* Float/double only */ + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; } ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x", + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source double property 0x%04x", prop); } - -AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) +ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values) { - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + ALbufferlistitem *BufferList; + ALdouble dvals[6]; + ALboolean err; - if(n < 0) - alSetError(context.get(), AL_INVALID_VALUE, "Generating %d sources", n); - else if(n == 1) - { - ALsource *source = AllocSource(context.get()); - if(source) sources[0] = source->id; - } - else + switch(prop) { - al::vector tempids(n); - auto alloc_end = std::find_if_not(tempids.begin(), tempids.end(), - [&context](ALuint &id) -> bool - { - ALsource *source = AllocSource(context.get()); - if(!source) return false; - id = source->id; - return true; - } - ); - if(alloc_end != tempids.end()) - alDeleteSources(std::distance(tempids.begin(), alloc_end), tempids.data()); - else - std::copy(tempids.cbegin(), tempids.cend(), sources); - } -} - + case AL_SOURCE_RELATIVE: + *values = Source->HeadRelative; + return AL_TRUE; -AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + case AL_LOOPING: + *values = Source->Looping; + return AL_TRUE; - if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Deleting %d sources", n); + case AL_BUFFER: + BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : nullptr; + *values = (BufferList && BufferList->num_buffers >= 1 && BufferList->buffers[0]) ? + BufferList->buffers[0]->id : 0; + return AL_TRUE; - std::lock_guard _{context->SourceLock}; + case AL_SOURCE_STATE: + *values = GetSourceState(Source, GetSourceVoice(Source, Context)); + return AL_TRUE; - /* Check that all Sources are valid */ - const ALuint *sources_end = sources + n; - auto invsrc = std::find_if_not(sources, sources_end, - [&context](ALuint sid) -> bool - { - if(!LookupSource(context.get(), sid)) + case AL_BUFFERS_QUEUED: + if(!(BufferList=Source->queue)) + *values = 0; + else { - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", sid); - return false; + ALsizei count = 0; + do { + count += BufferList->num_buffers; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } while(BufferList != nullptr); + *values = count; } - return true; - } - ); - if(LIKELY(invsrc == sources_end)) - { - /* All good. Delete source IDs. */ - std::for_each(sources, sources_end, - [&context](ALuint sid) -> void + return AL_TRUE; + + case AL_BUFFERS_PROCESSED: + if(Source->Looping || Source->SourceType != AL_STREAMING) { - ALsource *src = LookupSource(context.get(), sid); - if(src) FreeSource(context.get(), src); + /* Buffers on a looping source are in a perpetual state of + * PENDING, so don't report any as PROCESSED */ + *values = 0; } - ); - } -} + else + { + const ALbufferlistitem *BufferList{Source->queue}; + const ALbufferlistitem *Current{nullptr}; + ALsizei played{0}; + ALvoice *voice{GetSourceVoice(Source, Context)}; + if(voice != nullptr) + Current = voice->current_buffer.load(std::memory_order_relaxed); + else if(Source->state == AL_INITIAL) + Current = BufferList; -AL_API ALboolean AL_APIENTRY alIsSource(ALuint source) -{ - ContextRef context{GetContextRef()}; - if(LIKELY(context)) - { - std::lock_guard _{context->SourceLock}; - if(LookupSource(context.get(), source) != nullptr) + while(BufferList && BufferList != Current) + { + played += BufferList->num_buffers; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + *values = played; + } return AL_TRUE; - } - return AL_FALSE; -} - - -AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(FloatValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid float property 0x%04x", param); - else - SetSourcefv(Source, context.get(), static_cast(param), &value); -} - -AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(FloatValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); - else - { - ALfloat fvals[3] = { value1, value2, value3 }; - SetSourcefv(Source, context.get(), static_cast(param), fvals); - } -} -AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values) -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + case AL_SOURCE_TYPE: + *values = Source->SourceType; + return AL_TRUE; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(FloatValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); - else - SetSourcefv(Source, context.get(), static_cast(param), values); -} + case AL_DIRECT_FILTER_GAINHF_AUTO: + *values = Source->DryGainHFAuto; + return AL_TRUE; + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + *values = Source->WetGainAuto; + return AL_TRUE; -AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value) -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + *values = Source->WetGainHFAuto; + return AL_TRUE; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(DoubleValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid double property 0x%04x", param); - else - { - ALfloat fval = (ALfloat)value; - SetSourcefv(Source, context.get(), static_cast(param), &fval); - } -} + case AL_DIRECT_CHANNELS_SOFT: + *values = Source->DirectChannels; + return AL_TRUE; -AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3) -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + case AL_DISTANCE_MODEL: + *values = static_cast(Source->mDistanceModel); + return AL_TRUE; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(DoubleValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); - else - { - ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 }; - SetSourcefv(Source, context.get(), static_cast(param), fvals); - } -} + case AL_SOURCE_RESAMPLER_SOFT: + *values = Source->Resampler; + return AL_TRUE; -AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values) -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + case AL_SOURCE_SPATIALIZE_SOFT: + *values = Source->Spatialize; + return AL_TRUE; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else - { - ALint count{DoubleValsByProp(param)}; - if(count < 1 || count > 6) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); - else - { - ALfloat fvals[6]; - ALint i; + /* 1x float/double */ + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_REFERENCE_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_DOPPLER_FACTOR: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_SOURCE_RADIUS: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + *values = (ALint)dvals[0]; + return err; - for(i = 0;i < count;i++) - fvals[i] = (ALfloat)values[i]; - SetSourcefv(Source, context.get(), static_cast(param), fvals); - } - } -} + /* 3x float/double */ + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + { + values[0] = (ALint)dvals[0]; + values[1] = (ALint)dvals[1]; + values[2] = (ALint)dvals[2]; + } + return err; + + /* 6x float/double */ + case AL_ORIENTATION: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + { + values[0] = (ALint)dvals[0]; + values[1] = (ALint)dvals[1]; + values[2] = (ALint)dvals[2]; + values[3] = (ALint)dvals[3]; + values[4] = (ALint)dvals[4]; + values[5] = (ALint)dvals[5]; + } + return err; + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; /* i64 only */ + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + break; /* Double only */ + case AL_STEREO_ANGLES: + break; /* Float/double only */ -AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + break; /* ??? */ + } - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(IntValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); - else - SetSourceiv(Source, context.get(), static_cast(param), &value); + ERR("Unexpected property: 0x%04x\n", prop); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x", + prop); } -AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3) +ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values) { - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + ALCdevice *device = Context->Device; + ClockLatency clocktime; + ALuint64 srcclock; + ALdouble dvals[6]; + ALint ivals[3]; + ALboolean err; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(IntValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); - else + switch(prop) { - ALint ivals[3] = { value1, value2, value3 }; - SetSourceiv(Source, context.get(), static_cast(param), ivals); - } -} + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + /* Get the source offset with the clock time first. Then get the + * clock time with the device latency. Order is important. + */ + values[0] = GetSourceSampleOffset(Source, Context, &srcclock); + { std::lock_guard _{device->BackendLock}; + clocktime = GetClockLatency(device); + } + if(srcclock == (ALuint64)clocktime.ClockTime) + values[1] = clocktime.Latency; + else + { + /* If the clock time incremented, reduce the latency by that + * much since it's that much closer to the source offset it got + * earlier. + */ + ALuint64 diff{clocktime.ClockTime - srcclock}; + values[1] = clocktime.Latency - minu64(clocktime.Latency, diff); + } + return AL_TRUE; -AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values) -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + values[0] = GetSourceSampleOffset(Source, Context, &srcclock); + values[1] = srcclock; + return AL_TRUE; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(IntValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); - else - SetSourceiv(Source, context.get(), static_cast(param), values); -} + /* 1x float/double */ + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_REFERENCE_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_DOPPLER_FACTOR: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_SOURCE_RADIUS: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + *values = (ALint64)dvals[0]; + return err; + + /* 3x float/double */ + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + { + values[0] = (ALint64)dvals[0]; + values[1] = (ALint64)dvals[1]; + values[2] = (ALint64)dvals[2]; + } + return err; + /* 6x float/double */ + case AL_ORIENTATION: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + { + values[0] = (ALint64)dvals[0]; + values[1] = (ALint64)dvals[1]; + values[2] = (ALint64)dvals[2]; + values[3] = (ALint64)dvals[3]; + values[4] = (ALint64)dvals[4]; + values[5] = (ALint64)dvals[5]; + } + return err; -AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value) -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + /* 1x int */ + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) + *values = ivals[0]; + return err; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(Int64ValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); - else - SetSourcei64v(Source, context.get(), static_cast(param), &value); -} + /* 1x uint */ + case AL_BUFFER: + case AL_DIRECT_FILTER: + if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) + *values = (ALuint)ivals[0]; + return err; -AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3) -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + /* 3x uint */ + case AL_AUXILIARY_SEND_FILTER: + if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) + { + values[0] = (ALuint)ivals[0]; + values[1] = (ALuint)ivals[1]; + values[2] = (ALuint)ivals[2]; + } + return err; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(Int64ValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); - else - { - ALint64SOFT i64vals[3] = { value1, value2, value3 }; - SetSourcei64v(Source, context.get(), static_cast(param), i64vals); + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + break; /* Double only */ + case AL_STEREO_ANGLES: + break; /* Float/double only */ } -} - -AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values) -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(Int64ValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); - else - SetSourcei64v(Source, context.get(), static_cast(param), values); + ERR("Unexpected property: 0x%04x\n", prop); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x", + prop); } +} // namespace -AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value) +AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) { ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(FloatValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid float property 0x%04x", param); - else + if(n < 0) + alSetError(context.get(), AL_INVALID_VALUE, "Generating %d sources", n); + else if(n == 1) { - ALdouble dval; - if(GetSourcedv(Source, context.get(), static_cast(param), &dval)) - *value = (ALfloat)dval; + ALsource *source = AllocSource(context.get()); + if(source) sources[0] = source->id; } -} - - -AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(FloatValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); else { - ALdouble dvals[3]; - if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) - { - *value1 = (ALfloat)dvals[0]; - *value2 = (ALfloat)dvals[1]; - *value3 = (ALfloat)dvals[2]; - } + al::vector tempids(n); + auto alloc_end = std::find_if_not(tempids.begin(), tempids.end(), + [&context](ALuint &id) -> bool + { + ALsource *source{AllocSource(context.get())}; + if(!source) return false; + id = source->id; + return true; + } + ); + if(alloc_end != tempids.end()) + alDeleteSources(std::distance(tempids.begin(), alloc_end), tempids.data()); + else + std::copy(tempids.cbegin(), tempids.cend(), sources); } } -AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values) +AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) { ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; + if(n < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Deleting %d sources", n); + std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else - { - ALint count{FloatValsByProp(param)}; - if(count < 1 && count > 6) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); - else + + /* Check that all Sources are valid */ + const ALuint *sources_end = sources + n; + auto invsrc = std::find_if_not(sources, sources_end, + [&context](ALuint sid) -> bool { - ALdouble dvals[6]; - if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) + if(!LookupSource(context.get(), sid)) { - for(ALint i{0};i < count;i++) - values[i] = (ALfloat)dvals[i]; + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", sid); + return false; } + return true; } + ); + if(LIKELY(invsrc == sources_end)) + { + /* All good. Delete source IDs. */ + std::for_each(sources, sources_end, + [&context](ALuint sid) -> void + { + ALsource *src{LookupSource(context.get(), sid)}; + if(src) FreeSource(context.get(), src); + } + ); } } -AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value) -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(DoubleValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid double property 0x%04x", param); - else - GetSourcedv(Source, context.get(), static_cast(param), value); -} - -AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3) +AL_API ALboolean AL_APIENTRY alIsSource(ALuint source) { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(DoubleValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); - else + if(LIKELY(context)) { - ALdouble dvals[3]; - if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) - { - *value1 = dvals[0]; - *value2 = dvals[1]; - *value3 = dvals[2]; - } + std::lock_guard _{context->SourceLock}; + if(LookupSource(context.get(), source) != nullptr) + return AL_TRUE; } -} - -AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values) -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(DoubleValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); - else - GetSourcedv(Source, context.get(), static_cast(param), values); + return AL_FALSE; } -AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value) +AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) { ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(IntValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); + else if(FloatValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid float property 0x%04x", param); else - GetSourceiv(Source, context.get(), static_cast(param), value); + SetSourcefv(Source, context.get(), static_cast(param), &value); } - -AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3) +AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) { ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(IntValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); + else if(FloatValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); else { - ALint ivals[3]; - if(GetSourceiv(Source, context.get(), static_cast(param), ivals)) - { - *value1 = ivals[0]; - *value2 = ivals[1]; - *value3 = ivals[2]; - } + ALfloat fvals[3] = { value1, value2, value3 }; + SetSourcefv(Source, context.get(), static_cast(param), fvals); } } - -AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values) +AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values) { ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(IntValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); + else if(FloatValsByProp(param) < 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); else - GetSourceiv(Source, context.get(), static_cast(param), values); + SetSourcefv(Source, context.get(), static_cast(param), values); } -AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value) +AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value) { ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(Int64ValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); + else if(DoubleValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid double property 0x%04x", param); else - GetSourcei64v(Source, context.get(), static_cast(param), value); + { + ALfloat fval = (ALfloat)value; + SetSourcefv(Source, context.get(), static_cast(param), &fval); + } } -AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3) +AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3) { ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(Int64ValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); + else if(DoubleValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); else { - ALint64 i64vals[3]; - if(GetSourcei64v(Source, context.get(), static_cast(param), i64vals)) - { - *value1 = i64vals[0]; - *value2 = i64vals[1]; - *value3 = i64vals[2]; - } + ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 }; + SetSourcefv(Source, context.get(), static_cast(param), fvals); } } -AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values) +AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values) { ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(Int64ValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); else - GetSourcei64v(Source, context.get(), static_cast(param), values); -} - - -AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source) -{ - alSourcePlayv(1, &source); -} -AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Playing %d sources", n); - if(n == 0) return; - - std::lock_guard _{context->SourceLock}; - for(ALsizei i{0};i < n;i++) - { - if(!LookupSource(context.get(), sources[i])) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); - } - - ALCdevice *device{context->Device}; - ALCdevice_Lock(device); - /* If the device is disconnected, go right to stopped. */ - if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) - { - /* TODO: Send state change event? */ - for(ALsizei i{0};i < n;i++) - { - ALsource *source{LookupSource(context.get(), sources[i])}; - source->OffsetType = AL_NONE; - source->Offset = 0.0; - source->state = AL_STOPPED; - } - ALCdevice_Unlock(device); - return; - } - - while(n > context->MaxVoices-context->VoiceCount) - { - ALsizei newcount = context->MaxVoices << 1; - if(context->MaxVoices >= newcount) - { - ALCdevice_Unlock(device); - SETERR_RETURN(context.get(), AL_OUT_OF_MEMORY,, - "Overflow increasing voice count %d -> %d", context->MaxVoices, newcount); - } - AllocateVoices(context.get(), newcount, device->NumAuxSends); - } - - for(ALsizei i{0};i < n;i++) - { - ALsource *source{LookupSource(context.get(), sources[i])}; - /* Check that there is a queue containing at least one valid, non zero - * length buffer. - */ - ALbufferlistitem *BufferList{source->queue}; - while(BufferList && BufferList->max_samples == 0) - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); - - /* If there's nothing to play, go right to stopped. */ - if(UNLIKELY(!BufferList)) - { - /* NOTE: A source without any playable buffers should not have an - * ALvoice since it shouldn't be in a playing or paused state. So - * there's no need to look up its voice and clear the source. - */ - ALenum oldstate = GetSourceState(source, NULL); - source->OffsetType = AL_NONE; - source->Offset = 0.0; - if(oldstate != AL_STOPPED) - { - source->state = AL_STOPPED; - SendStateChangeEvent(context.get(), source->id, AL_STOPPED); - } - continue; - } - - ALvoice *voice{GetSourceVoice(source, context.get())}; - switch(GetSourceState(source, voice)) - { - case AL_PLAYING: - assert(voice != NULL); - /* A source that's already playing is restarted from the beginning. */ - ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); - ATOMIC_STORE(&voice->position, 0u, almemory_order_relaxed); - ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release); - continue; - - case AL_PAUSED: - assert(voice != NULL); - /* A source that's paused simply resumes. */ - ATOMIC_STORE(&voice->Playing, true, almemory_order_release); - source->state = AL_PLAYING; - SendStateChangeEvent(context.get(), source->id, AL_PLAYING); - continue; - - default: - break; - } - - /* Look for an unused voice to play this source with. */ - assert(voice == NULL); - ALint vidx{-1}; - for(ALsizei j{0};j < context->VoiceCount;j++) - { - if(ATOMIC_LOAD(&context->Voices[j]->Source, almemory_order_acquire) == NULL) - { - vidx = j; - break; - } - } - if(vidx == -1) - vidx = context->VoiceCount++; - voice = context->Voices[vidx]; - voice->Playing.store(false, std::memory_order_release); - - source->PropsClean.test_and_set(std::memory_order_acquire); - UpdateSourceProps(source, voice, context.get()); - - /* A source that's not playing or paused has any offset applied when it - * starts playing. - */ - if(source->Looping) - ATOMIC_STORE(&voice->loop_buffer, source->queue, almemory_order_relaxed); - else - ATOMIC_STORE(&voice->loop_buffer, static_cast(nullptr), - almemory_order_relaxed); - ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); - ATOMIC_STORE(&voice->position, 0u, almemory_order_relaxed); - ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed); - bool start_fading{false}; - if(ApplyOffset(source, voice) != AL_FALSE) - start_fading = ATOMIC_LOAD(&voice->position, almemory_order_relaxed) != 0 || - ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) != 0 || - ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed) != BufferList; - - for(ALsizei j{0};j < BufferList->num_buffers;j++) - { - ALbuffer *buffer = BufferList->buffers[j]; - if(buffer) - { - voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels); - voice->SampleSize = BytesFromFmt(buffer->FmtType); - break; - } - } - - /* Clear previous samples. */ - memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples)); - - /* Clear the stepping value so the mixer knows not to mix this until - * the update gets applied. - */ - voice->Step = 0; - - voice->Flags = start_fading ? VOICE_IS_FADING : 0; - if(source->SourceType == AL_STATIC) voice->Flags |= VOICE_IS_STATIC; - memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])*voice->NumChannels); - for(ALsizei j{0};j < device->NumAuxSends;j++) - memset(voice->Send[j].Params, 0, sizeof(voice->Send[j].Params[0])*voice->NumChannels); - if(device->AvgSpeakerDist > 0.0f) - { - ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / - (device->AvgSpeakerDist * device->Frequency); - for(ALsizei j{0};j < voice->NumChannels;j++) - NfcFilterCreate(&voice->Direct.Params[j].NFCtrlFilter, 0.0f, w1); - } - - ATOMIC_STORE(&voice->Source, source, almemory_order_relaxed); - ATOMIC_STORE(&voice->Playing, true, almemory_order_release); - source->state = AL_PLAYING; - source->VoiceIdx = vidx; + { + ALint count{DoubleValsByProp(param)}; + if(count < 1 || count > 6) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); + else + { + ALfloat fvals[6]; + ALint i; - SendStateChangeEvent(context.get(), source->id, AL_PLAYING); + for(i = 0;i < count;i++) + fvals[i] = (ALfloat)values[i]; + SetSourcefv(Source, context.get(), static_cast(param), fvals); + } } - ALCdevice_Unlock(device); } -AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source) -{ - alSourcePausev(1, &source); -} -AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) + +AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) { ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Pausing %d sources", n); - if(n == 0) return; + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(IntValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); + else + SetSourceiv(Source, context.get(), static_cast(param), &value); +} - for(ALsizei i{0};i < n;i++) - { - if(!LookupSource(context.get(), sources[i])) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); - } +AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - ALCdevice *device{context->Device}; - ALCdevice_Lock(device); - for(ALsizei i{0};i < n;i++) + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(IntValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); + else { - ALsource *source{LookupSource(context.get(), sources[i])}; - ALvoice *voice{GetSourceVoice(source, context.get())}; - if(!voice) voice->Playing.store(false, std::memory_order_release); - if(GetSourceState(source, voice) == AL_PLAYING) - { - source->state = AL_PAUSED; - SendStateChangeEvent(context.get(), source->id, AL_PAUSED); - } + ALint ivals[3] = { value1, value2, value3 }; + SetSourceiv(Source, context.get(), static_cast(param), ivals); } - ALCdevice_Unlock(device); } -AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source) +AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values) { - alSourceStopv(1, &source); + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(IntValsByProp(param) < 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); + else + SetSourceiv(Source, context.get(), static_cast(param), values); } -AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) + + +AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value) { ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Stopping %d sources", n); - if(n == 0) return; + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(Int64ValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); + else + SetSourcei64v(Source, context.get(), static_cast(param), &value); +} - for(ALsizei i{0};i < n;i++) - { - if(!LookupSource(context.get(), sources[i])) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); - } +AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - ALCdevice *device{context->Device}; - ALCdevice_Lock(device); - for(ALsizei i{0};i < n;i++) + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(Int64ValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); + else { - ALsource *source{LookupSource(context.get(), sources[i])}; - ALvoice *voice{GetSourceVoice(source, context.get())}; - if(voice != nullptr) - { - voice->Source.store(nullptr, std::memory_order_relaxed); - voice->Playing.store(false, std::memory_order_release); - voice = nullptr; - } - ALenum oldstate{GetSourceState(source, voice)}; - if(oldstate != AL_INITIAL && oldstate != AL_STOPPED) - { - source->state = AL_STOPPED; - SendStateChangeEvent(context.get(), source->id, AL_STOPPED); - } - source->OffsetType = AL_NONE; - source->Offset = 0.0; + ALint64SOFT i64vals[3] = { value1, value2, value3 }; + SetSourcei64v(Source, context.get(), static_cast(param), i64vals); } - ALCdevice_Unlock(device); } -AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source) -{ - alSourceRewindv(1, &source); -} -AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) +AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values) { ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Rewinding %d sources", n); - if(n == 0) return; - - for(ALsizei i{0};i < n;i++) - { - if(!LookupSource(context.get(), sources[i])) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); - } - - ALCdevice *device{context->Device}; - ALCdevice_Lock(device); - for(ALsizei i{0};i < n;i++) - { - ALsource *source{LookupSource(context.get(), sources[i])}; - ALvoice *voice{GetSourceVoice(source, context.get())}; - if(voice != nullptr) - { - voice->Source.store(nullptr, std::memory_order_relaxed); - voice->Playing.store(false, std::memory_order_release); - voice = nullptr; - } - if(GetSourceState(source, voice) != AL_INITIAL) - { - source->state = AL_INITIAL; - SendStateChangeEvent(context.get(), source->id, AL_INITIAL); - } - source->OffsetType = AL_NONE; - source->Offset = 0.0; - } - ALCdevice_Unlock(device); + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(Int64ValsByProp(param) < 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); + else + SetSourcei64v(Source, context.get(), static_cast(param), values); } -AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers) +AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value) { ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - if(nb < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffers", nb); - if(nb == 0) return; - std::lock_guard _{context->SourceLock}; - ALsource *source{LookupSource(context.get(),src)}; - if(!source) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); - - if(source->SourceType == AL_STATIC) + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!value) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(FloatValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid float property 0x%04x", param); + else { - /* Can't queue on a Static Source */ - SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src); + ALdouble dval; + if(GetSourcedv(Source, context.get(), static_cast(param), &dval)) + *value = (ALfloat)dval; } +} - /* Check for a valid Buffer, for its frequency and format */ - ALCdevice *device{context->Device}; - ALbuffer *BufferFmt{nullptr}; - ALbufferlistitem *BufferList{source->queue}; - while(BufferList) - { - for(ALsizei i{0};i < BufferList->num_buffers;i++) - { - if((BufferFmt=BufferList->buffers[i]) != nullptr) - break; - } - if(BufferFmt) break; - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - std::unique_lock buflock{device->BufferLock}; - ALbufferlistitem *BufferListStart{nullptr}; - BufferList = nullptr; - for(ALsizei i{0};i < nb;i++) - { - ALbuffer *buffer{nullptr}; - if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL) - SETERR_GOTO(context.get(), AL_INVALID_NAME, buffer_error, - "Queueing invalid buffer ID %u", buffers[i]); +AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - if(!BufferListStart) - { - BufferListStart = static_cast(al_calloc(DEF_ALIGN, - FAM_SIZE(ALbufferlistitem, buffers, 1))); - BufferList = BufferListStart; - } - else - { - auto item = static_cast(al_calloc(DEF_ALIGN, - FAM_SIZE(ALbufferlistitem, buffers, 1))); - BufferList->next.store(item, std::memory_order_relaxed); - BufferList = item; + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!(value1 && value2 && value3)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(FloatValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); + else + { + ALdouble dvals[3]; + if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) + { + *value1 = (ALfloat)dvals[0]; + *value2 = (ALfloat)dvals[1]; + *value3 = (ALfloat)dvals[2]; } - ATOMIC_INIT(&BufferList->next, static_cast(nullptr)); - BufferList->max_samples = buffer ? buffer->SampleLen : 0; - BufferList->num_buffers = 1; - BufferList->buffers[0] = buffer; - if(!buffer) continue; + } +} - IncrementRef(&buffer->ref); - if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) - SETERR_GOTO(context.get(), AL_INVALID_OPERATION, buffer_error, - "Queueing non-persistently mapped buffer %u", buffer->id); +AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - if(BufferFmt == NULL) - BufferFmt = buffer; - else if(BufferFmt->Frequency != buffer->Frequency || - BufferFmt->FmtChannels != buffer->FmtChannels || - BufferFmt->OriginalType != buffer->OriginalType) + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else + { + ALint count{FloatValsByProp(param)}; + if(count < 1 && count > 6) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); + else { - alSetError(context.get(), AL_INVALID_OPERATION, - "Queueing buffer with mismatched format"); - - buffer_error: - /* A buffer failed (invalid ID or format), so unlock and release - * each buffer we had. */ - while(BufferListStart) + ALdouble dvals[6]; + if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) { - ALbufferlistitem *next = BufferListStart->next.load(std::memory_order_relaxed); - for(i = 0;i < BufferListStart->num_buffers;i++) - { - if((buffer=BufferListStart->buffers[i]) != NULL) - DecrementRef(&buffer->ref); - } - al_free(BufferListStart); - BufferListStart = next; + for(ALint i{0};i < count;i++) + values[i] = (ALfloat)dvals[i]; } - return; } } - /* All buffers good. */ - buflock.unlock(); +} - /* Source is now streaming */ - source->SourceType = AL_STREAMING; - if(!(BufferList=source->queue)) - source->queue = BufferListStart; +AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!value) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(DoubleValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid double property 0x%04x", param); + else + GetSourcedv(Source, context.get(), static_cast(param), value); +} + +AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!(value1 && value2 && value3)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(DoubleValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); else { - ALbufferlistitem *next; - while((next=BufferList->next.load(std::memory_order_relaxed)) != nullptr) - BufferList = next; - BufferList->next.store(BufferListStart, std::memory_order_release); + ALdouble dvals[3]; + if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) + { + *value1 = dvals[0]; + *value2 = dvals[1]; + *value3 = dvals[2]; + } } } -AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers) +AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values) { ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - if(nb < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffer layers", nb); - if(nb == 0) return; + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(DoubleValsByProp(param) < 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); + else + GetSourcedv(Source, context.get(), static_cast(param), values); +} + + +AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; std::lock_guard _{context->SourceLock}; - ALsource *source{LookupSource(context.get(),src)}; - if(!source) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!value) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(IntValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); + else + GetSourceiv(Source, context.get(), static_cast(param), value); +} - if(source->SourceType == AL_STATIC) - { - /* Can't queue on a Static Source */ - SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src); - } - /* Check for a valid Buffer, for its frequency and format */ - ALCdevice *device{context->Device}; - ALbuffer *BufferFmt{nullptr}; - ALbufferlistitem *BufferList{source->queue}; - while(BufferList) +AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!(value1 && value2 && value3)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(IntValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); + else { - for(ALsizei i{0};i < BufferList->num_buffers;i++) + ALint ivals[3]; + if(GetSourceiv(Source, context.get(), static_cast(param), ivals)) { - if((BufferFmt=BufferList->buffers[i]) != nullptr) - break; + *value1 = ivals[0]; + *value2 = ivals[1]; + *value3 = ivals[2]; } - if(BufferFmt) break; - BufferList = BufferList->next.load(std::memory_order_relaxed); } +} - std::unique_lock buflock{device->BufferLock}; - auto BufferListStart = static_cast(al_calloc(DEF_ALIGN, - FAM_SIZE(ALbufferlistitem, buffers, nb))); - BufferList = BufferListStart; - ATOMIC_INIT(&BufferList->next, static_cast(nullptr)); - BufferList->max_samples = 0; - BufferList->num_buffers = 0; - - for(ALsizei i{0};i < nb;i++) - { - ALbuffer *buffer{nullptr}; - if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr) - SETERR_GOTO(context.get(), AL_INVALID_NAME, buffer_error, - "Queueing invalid buffer ID %u", buffers[i]); - - BufferList->buffers[BufferList->num_buffers++] = buffer; - if(!buffer) continue; - IncrementRef(&buffer->ref); +AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - BufferList->max_samples = maxi(BufferList->max_samples, buffer->SampleLen); + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(IntValsByProp(param) < 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); + else + GetSourceiv(Source, context.get(), static_cast(param), values); +} - if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) - SETERR_GOTO(context.get(), AL_INVALID_OPERATION, buffer_error, - "Queueing non-persistently mapped buffer %u", buffer->id); - if(BufferFmt == NULL) - BufferFmt = buffer; - else if(BufferFmt->Frequency != buffer->Frequency || - BufferFmt->FmtChannels != buffer->FmtChannels || - BufferFmt->OriginalType != buffer->OriginalType) - { - alSetError(context.get(), AL_INVALID_OPERATION, - "Queueing buffer with mismatched format"); +AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - buffer_error: - /* A buffer failed (invalid ID or format), so unlock and release - * each buffer we had. */ - while(BufferListStart) - { - ALbufferlistitem *next = ATOMIC_LOAD(&BufferListStart->next, - almemory_order_relaxed); - for(i = 0;i < BufferListStart->num_buffers;i++) - { - if((buffer=BufferListStart->buffers[i]) != NULL) - DecrementRef(&buffer->ref); - } - al_free(BufferListStart); - BufferListStart = next; - } - return; - } - } - /* All buffers good. */ - buflock.unlock(); + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!value) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(Int64ValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); + else + GetSourcei64v(Source, context.get(), static_cast(param), value); +} - /* Source is now streaming */ - source->SourceType = AL_STREAMING; +AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - if(!(BufferList=source->queue)) - source->queue = BufferListStart; + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!(value1 && value2 && value3)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(Int64ValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); else { - ALbufferlistitem *next; - while((next=ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed)) != NULL) - BufferList = next; - ATOMIC_STORE(&BufferList->next, BufferListStart, almemory_order_release); + ALint64 i64vals[3]; + if(GetSourcei64v(Source, context.get(), static_cast(param), i64vals)) + { + *value1 = i64vals[0]; + *value2 = i64vals[1]; + *value3 = i64vals[2]; + } } } -AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers) +AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values) { ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - if(nb < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing %d buffers", nb); - if(nb == 0) return; - std::lock_guard _{context->SourceLock}; - ALsource *source{LookupSource(context.get(),src)}; - if(!source) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(Int64ValsByProp(param) < 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); + else + GetSourcei64v(Source, context.get(), static_cast(param), values); +} - if(source->Looping) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing from looping source %u", src); - if(source->SourceType != AL_STREAMING) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, - "Unqueueing from a non-streaming source %u", src); - /* Make sure enough buffers have been processed to unqueue. */ - ALbufferlistitem *BufferList{source->queue}; - ALvoice *voice{GetSourceVoice(source, context.get())}; - ALbufferlistitem *Current{nullptr}; - if(voice) - Current = voice->current_buffer.load(std::memory_order_relaxed); - else if(source->state == AL_INITIAL) - Current = BufferList; - if(BufferList == Current) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing pending buffers"); +AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source) +{ + alSourcePlayv(1, &source); +} +AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - ALsizei i{BufferList->num_buffers}; - while(i < nb) + if(n < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Playing %d sources", n); + if(n == 0) return; + + std::lock_guard _{context->SourceLock}; + for(ALsizei i{0};i < n;i++) { - /* If the next bufferlist to check is NULL or is the current one, it's - * trying to unqueue pending buffers. - */ - ALbufferlistitem *next = BufferList->next.load(std::memory_order_relaxed); - if(!next || next == Current) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing pending buffers"); - BufferList = next; + if(!LookupSource(context.get(), sources[i])) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); + } - i += BufferList->num_buffers; + ALCdevice *device{context->Device}; + ALCdevice_Lock(device); + /* If the device is disconnected, go right to stopped. */ + if(!device->Connected.load(std::memory_order_acquire)) + { + /* TODO: Send state change event? */ + for(ALsizei i{0};i < n;i++) + { + ALsource *source{LookupSource(context.get(), sources[i])}; + source->OffsetType = AL_NONE; + source->Offset = 0.0; + source->state = AL_STOPPED; + } + ALCdevice_Unlock(device); + return; } - while(nb > 0) + while(n > context->MaxVoices-context->VoiceCount) { - ALbufferlistitem *head = source->queue; - ALbufferlistitem *next = head->next.load(std::memory_order_relaxed); - for(i = 0;i < head->num_buffers && nb > 0;i++,nb--) + ALsizei newcount = context->MaxVoices << 1; + if(context->MaxVoices >= newcount) { - ALbuffer *buffer = head->buffers[i]; - if(!buffer) - *(buffers++) = 0; - else - { - *(buffers++) = buffer->id; - DecrementRef(&buffer->ref); - } + ALCdevice_Unlock(device); + SETERR_RETURN(context.get(), AL_OUT_OF_MEMORY,, + "Overflow increasing voice count %d -> %d", context->MaxVoices, newcount); } - if(i < head->num_buffers) + AllocateVoices(context.get(), newcount, device->NumAuxSends); + } + + for(ALsizei i{0};i < n;i++) + { + ALsource *source{LookupSource(context.get(), sources[i])}; + /* Check that there is a queue containing at least one valid, non zero + * length buffer. + */ + ALbufferlistitem *BufferList{source->queue}; + while(BufferList && BufferList->max_samples == 0) + BufferList = BufferList->next.load(std::memory_order_relaxed); + + /* If there's nothing to play, go right to stopped. */ + if(UNLIKELY(!BufferList)) { - /* This head has some buffers left over, so move them to the front - * and update the sample and buffer count. + /* NOTE: A source without any playable buffers should not have an + * ALvoice since it shouldn't be in a playing or paused state. So + * there's no need to look up its voice and clear the source. */ - ALsizei max_length = 0; - ALsizei j = 0; - while(i < head->num_buffers) + ALenum oldstate{GetSourceState(source, nullptr)}; + source->OffsetType = AL_NONE; + source->Offset = 0.0; + if(oldstate != AL_STOPPED) { - ALbuffer *buffer = head->buffers[i++]; - if(buffer) max_length = maxi(max_length, buffer->SampleLen); - head->buffers[j++] = buffer; + source->state = AL_STOPPED; + SendStateChangeEvent(context.get(), source->id, AL_STOPPED); } - head->max_samples = max_length; - head->num_buffers = j; - break; + continue; } - /* Otherwise, free this item and set the source queue head to the next - * one. - */ - al_free(head); - source->queue = next; - } -} + ALvoice *voice{GetSourceVoice(source, context.get())}; + switch(GetSourceState(source, voice)) + { + case AL_PLAYING: + assert(voice != nullptr); + /* A source that's already playing is restarted from the beginning. */ + voice->current_buffer.store(BufferList, std::memory_order_relaxed); + voice->position.store(0u, std::memory_order_relaxed); + voice->position_fraction.store(0, std::memory_order_release); + continue; + case AL_PAUSED: + assert(voice != nullptr); + /* A source that's paused simply resumes. */ + voice->Playing.store(true, std::memory_order_release); + source->state = AL_PLAYING; + SendStateChangeEvent(context.get(), source->id, AL_PLAYING); + continue; -ALsource::ALsource(ALsizei num_sends) -{ - InnerAngle = 360.0f; - OuterAngle = 360.0f; - Pitch = 1.0f; - Position[0] = 0.0f; - Position[1] = 0.0f; - Position[2] = 0.0f; - Velocity[0] = 0.0f; - Velocity[1] = 0.0f; - Velocity[2] = 0.0f; - Direction[0] = 0.0f; - Direction[1] = 0.0f; - Direction[2] = 0.0f; - Orientation[0][0] = 0.0f; - Orientation[0][1] = 0.0f; - Orientation[0][2] = -1.0f; - Orientation[1][0] = 0.0f; - Orientation[1][1] = 1.0f; - Orientation[1][2] = 0.0f; - RefDistance = 1.0f; - MaxDistance = FLT_MAX; - RolloffFactor = 1.0f; - Gain = 1.0f; - MinGain = 0.0f; - MaxGain = 1.0f; - OuterGain = 0.0f; - OuterGainHF = 1.0f; + default: + break; + } - DryGainHFAuto = AL_TRUE; - WetGainAuto = AL_TRUE; - WetGainHFAuto = AL_TRUE; - AirAbsorptionFactor = 0.0f; - RoomRolloffFactor = 0.0f; - DopplerFactor = 1.0f; - HeadRelative = AL_FALSE; - Looping = AL_FALSE; - mDistanceModel = DistanceModel::Default; - Resampler = ResamplerDefault; - DirectChannels = AL_FALSE; - Spatialize = SpatializeAuto; + /* Look for an unused voice to play this source with. */ + assert(voice == nullptr); + ALint vidx{-1}; + for(ALsizei j{0};j < context->VoiceCount;j++) + { + if(context->Voices[j]->Source.load(std::memory_order_acquire) == nullptr) + { + vidx = j; + break; + } + } + if(vidx == -1) + vidx = context->VoiceCount++; + voice = context->Voices[vidx]; + voice->Playing.store(false, std::memory_order_release); - StereoPan[0] = DEG2RAD( 30.0f); - StereoPan[1] = DEG2RAD(-30.0f); + source->PropsClean.test_and_set(std::memory_order_acquire); + UpdateSourceProps(source, voice, context.get()); - Radius = 0.0f; + /* A source that's not playing or paused has any offset applied when it + * starts playing. + */ + if(source->Looping) + voice->loop_buffer.store(source->queue, std::memory_order_relaxed); + else + voice->loop_buffer.store(nullptr, std::memory_order_relaxed); + voice->current_buffer.store(BufferList, std::memory_order_relaxed); + voice->position.store(0u, std::memory_order_relaxed); + voice->position_fraction.store(0, std::memory_order_relaxed); + bool start_fading{false}; + if(ApplyOffset(source, voice) != AL_FALSE) + start_fading = voice->position.load(std::memory_order_relaxed) != 0 || + voice->position_fraction.load(std::memory_order_relaxed) != 0 || + voice->current_buffer.load(std::memory_order_relaxed) != BufferList; - Direct.Gain = 1.0f; - Direct.GainHF = 1.0f; - Direct.HFReference = LOWPASSFREQREF; - Direct.GainLF = 1.0f; - Direct.LFReference = HIGHPASSFREQREF; - Send.resize(num_sends); - for(auto &send : Send) - { - send.Slot = nullptr; - send.Gain = 1.0f; - send.GainHF = 1.0f; - send.HFReference = LOWPASSFREQREF; - send.GainLF = 1.0f; - send.LFReference = HIGHPASSFREQREF; - } + for(ALsizei j{0};j < BufferList->num_buffers;j++) + { + ALbuffer *buffer = BufferList->buffers[j]; + if(buffer) + { + voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels); + voice->SampleSize = BytesFromFmt(buffer->FmtType); + break; + } + } - Offset = 0.0; - OffsetType = AL_NONE; - SourceType = AL_UNDETERMINED; - state = AL_INITIAL; + /* Clear previous samples. */ + memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples)); + + /* Clear the stepping value so the mixer knows not to mix this until + * the update gets applied. + */ + voice->Step = 0; - queue = NULL; + voice->Flags = start_fading ? VOICE_IS_FADING : 0; + if(source->SourceType == AL_STATIC) voice->Flags |= VOICE_IS_STATIC; + memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])*voice->NumChannels); + for(ALsizei j{0};j < device->NumAuxSends;j++) + memset(voice->Send[j].Params, 0, sizeof(voice->Send[j].Params[0])*voice->NumChannels); + if(device->AvgSpeakerDist > 0.0f) + { + ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / + (device->AvgSpeakerDist * device->Frequency); + for(ALsizei j{0};j < voice->NumChannels;j++) + NfcFilterCreate(&voice->Direct.Params[j].NFCtrlFilter, 0.0f, w1); + } - VoiceIdx = -1; + voice->Source.store(source, std::memory_order_relaxed); + voice->Playing.store(true, std::memory_order_release); + source->state = AL_PLAYING; + source->VoiceIdx = vidx; + + SendStateChangeEvent(context.get(), source->id, AL_PLAYING); + } + ALCdevice_Unlock(device); } -ALsource::~ALsource() +AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source) { - ALbufferlistitem *BufferList{queue}; - while(BufferList != NULL) + alSourcePausev(1, &source); +} +AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(n < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Pausing %d sources", n); + if(n == 0) return; + + for(ALsizei i{0};i < n;i++) { - ALbufferlistitem *next = BufferList->next.load(std::memory_order_relaxed); - for(ALsizei i{0};i < BufferList->num_buffers;i++) - { - if(BufferList->buffers[i]) - DecrementRef(&BufferList->buffers[i]->ref); - } - al_free(BufferList); - BufferList = next; + if(!LookupSource(context.get(), sources[i])) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } - queue = nullptr; - std::for_each(Send.begin(), Send.end(), - [](ALsource::SendData &send) -> void + ALCdevice *device{context->Device}; + ALCdevice_Lock(device); + for(ALsizei i{0};i < n;i++) + { + ALsource *source{LookupSource(context.get(), sources[i])}; + ALvoice *voice{GetSourceVoice(source, context.get())}; + if(!voice) voice->Playing.store(false, std::memory_order_release); + if(GetSourceState(source, voice) == AL_PLAYING) { - if(send.Slot) - DecrementRef(&send.Slot->ref); - send.Slot = nullptr; + source->state = AL_PAUSED; + SendStateChangeEvent(context.get(), source->id, AL_PAUSED); } - ); + } + ALCdevice_Unlock(device); } -static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALCcontext *context) +AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source) { - /* Get an unused property container, or allocate a new one as needed. */ - ALvoiceProps *props{context->FreeVoiceProps.load(std::memory_order_acquire)}; - if(!props) - props = static_cast(al_calloc(16, - FAM_SIZE(struct ALvoiceProps, Send, source->Send.size()))); - else + alSourceStopv(1, &source); +} +AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(n < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Stopping %d sources", n); + if(n == 0) return; + + for(ALsizei i{0};i < n;i++) { - struct ALvoiceProps *next; - do { - next = props->next.load(std::memory_order_relaxed); - } while(context->FreeVoiceProps.compare_exchange_weak(props, next, - std::memory_order_acq_rel, std::memory_order_acquire) == 0); + if(!LookupSource(context.get(), sources[i])) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } - /* Copy in current property values. */ - props->Pitch = source->Pitch; - props->Gain = source->Gain; - props->OuterGain = source->OuterGain; - props->MinGain = source->MinGain; - props->MaxGain = source->MaxGain; - props->InnerAngle = source->InnerAngle; - props->OuterAngle = source->OuterAngle; - props->RefDistance = source->RefDistance; - props->MaxDistance = source->MaxDistance; - props->RolloffFactor = source->RolloffFactor; - for(ALsizei i{0};i < 3;i++) - props->Position[i] = source->Position[i]; - for(ALsizei i{0};i < 3;i++) - props->Velocity[i] = source->Velocity[i]; - for(ALsizei i{0};i < 3;i++) - props->Direction[i] = source->Direction[i]; - for(ALsizei i{0};i < 2;i++) + ALCdevice *device{context->Device}; + ALCdevice_Lock(device); + for(ALsizei i{0};i < n;i++) { - for(ALsizei j{0};j < 3;j++) - props->Orientation[i][j] = source->Orientation[i][j]; + ALsource *source{LookupSource(context.get(), sources[i])}; + ALvoice *voice{GetSourceVoice(source, context.get())}; + if(voice != nullptr) + { + voice->Source.store(nullptr, std::memory_order_relaxed); + voice->Playing.store(false, std::memory_order_release); + voice = nullptr; + } + ALenum oldstate{GetSourceState(source, voice)}; + if(oldstate != AL_INITIAL && oldstate != AL_STOPPED) + { + source->state = AL_STOPPED; + SendStateChangeEvent(context.get(), source->id, AL_STOPPED); + } + source->OffsetType = AL_NONE; + source->Offset = 0.0; } - props->HeadRelative = source->HeadRelative; - props->mDistanceModel = source->mDistanceModel; - props->Resampler = source->Resampler; - props->DirectChannels = source->DirectChannels; - props->SpatializeMode = source->Spatialize; - - props->DryGainHFAuto = source->DryGainHFAuto; - props->WetGainAuto = source->WetGainAuto; - props->WetGainHFAuto = source->WetGainHFAuto; - props->OuterGainHF = source->OuterGainHF; - - props->AirAbsorptionFactor = source->AirAbsorptionFactor; - props->RoomRolloffFactor = source->RoomRolloffFactor; - props->DopplerFactor = source->DopplerFactor; - - props->StereoPan[0] = source->StereoPan[0]; - props->StereoPan[1] = source->StereoPan[1]; + ALCdevice_Unlock(device); +} - props->Radius = source->Radius; +AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source) +{ + alSourceRewindv(1, &source); +} +AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - props->Direct.Gain = source->Direct.Gain; - props->Direct.GainHF = source->Direct.GainHF; - props->Direct.HFReference = source->Direct.HFReference; - props->Direct.GainLF = source->Direct.GainLF; - props->Direct.LFReference = source->Direct.LFReference; + if(n < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Rewinding %d sources", n); + if(n == 0) return; - for(size_t i{0u};i < source->Send.size();i++) + for(ALsizei i{0};i < n;i++) { - props->Send[i].Slot = source->Send[i].Slot; - props->Send[i].Gain = source->Send[i].Gain; - props->Send[i].GainHF = source->Send[i].GainHF; - props->Send[i].HFReference = source->Send[i].HFReference; - props->Send[i].GainLF = source->Send[i].GainLF; - props->Send[i].LFReference = source->Send[i].LFReference; + if(!LookupSource(context.get(), sources[i])) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } - /* Set the new container for updating internal parameters. */ - props = voice->Update.exchange(props, std::memory_order_acq_rel); - if(props) + ALCdevice *device{context->Device}; + ALCdevice_Lock(device); + for(ALsizei i{0};i < n;i++) { - /* If there was an unused update container, put it back in the - * freelist. - */ - AtomicReplaceHead(context->FreeVoiceProps, props); + ALsource *source{LookupSource(context.get(), sources[i])}; + ALvoice *voice{GetSourceVoice(source, context.get())}; + if(voice != nullptr) + { + voice->Source.store(nullptr, std::memory_order_relaxed); + voice->Playing.store(false, std::memory_order_release); + voice = nullptr; + } + if(GetSourceState(source, voice) != AL_INITIAL) + { + source->state = AL_INITIAL; + SendStateChangeEvent(context.get(), source->id, AL_INITIAL); + } + source->OffsetType = AL_NONE; + source->Offset = 0.0; } + ALCdevice_Unlock(device); } -void UpdateAllSourceProps(ALCcontext *context) + +AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers) { - for(ALsizei i{0};i < context->VoiceCount;++i) + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(nb < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffers", nb); + if(nb == 0) return; + + std::lock_guard _{context->SourceLock}; + ALsource *source{LookupSource(context.get(),src)}; + if(!source) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); + + /* Can't queue on a Static Source */ + if(source->SourceType == AL_STATIC) + SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src); + + /* Check for a valid Buffer, for its frequency and format */ + ALCdevice *device{context->Device}; + ALbuffer *BufferFmt{nullptr}; + ALbufferlistitem *BufferList{source->queue}; + while(BufferList) { - ALvoice *voice = context->Voices[i]; - ALsource *source = voice->Source.load(std::memory_order_acquire); - if(source && !source->PropsClean.test_and_set(std::memory_order_acq_rel)) - UpdateSourceProps(source, voice, context); + for(ALsizei i{0};i < BufferList->num_buffers;i++) + { + if((BufferFmt=BufferList->buffers[i]) != nullptr) + break; + } + if(BufferFmt) break; + BufferList = BufferList->next.load(std::memory_order_relaxed); } -} + std::unique_lock buflock{device->BufferLock}; + ALbufferlistitem *BufferListStart{nullptr}; + BufferList = nullptr; + for(ALsizei i{0};i < nb;i++) + { + ALbuffer *buffer{nullptr}; + if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr) + { + alSetError(context.get(), AL_INVALID_NAME, "Queueing invalid buffer ID %u", + buffers[i]); + goto buffer_error; + } -/* GetSourceSampleOffset - * - * Gets the current read offset for the given Source, in 32.32 fixed-point - * samples. The offset is relative to the start of the queue (not the start of - * the current buffer). - */ -static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime) -{ - ALCdevice *device = context->Device; - const ALbufferlistitem *Current; - ALuint64 readPos; - ALuint refcount; - ALvoice *voice; + if(!BufferListStart) + { + BufferListStart = static_cast(al_calloc(DEF_ALIGN, + FAM_SIZE(ALbufferlistitem, buffers, 1))); + BufferList = BufferListStart; + } + else + { + auto item = static_cast(al_calloc(DEF_ALIGN, + FAM_SIZE(ALbufferlistitem, buffers, 1))); + BufferList->next.store(item, std::memory_order_relaxed); + BufferList = item; + } + ATOMIC_INIT(&BufferList->next, static_cast(nullptr)); + BufferList->max_samples = buffer ? buffer->SampleLen : 0; + BufferList->num_buffers = 1; + BufferList->buffers[0] = buffer; + if(!buffer) continue; - do { - Current = NULL; - readPos = 0; - while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) - althrd_yield(); - *clocktime = GetDeviceClockTime(device); + IncrementRef(&buffer->ref); - voice = GetSourceVoice(Source, context); - if(voice) + if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) { - Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - - readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << 32; - readPos |= (ALuint64)ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) << - (32-FRACTIONBITS); + alSetError(context.get(), AL_INVALID_OPERATION, + "Queueing non-persistently mapped buffer %u", buffer->id); + goto buffer_error; } - std::atomic_thread_fence(std::memory_order_acquire); - } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); - if(voice) - { - const ALbufferlistitem *BufferList = Source->queue; - while(BufferList && BufferList != Current) + if(BufferFmt == nullptr) + BufferFmt = buffer; + else if(BufferFmt->Frequency != buffer->Frequency || + BufferFmt->FmtChannels != buffer->FmtChannels || + BufferFmt->OriginalType != buffer->OriginalType) { - readPos += (ALuint64)BufferList->max_samples << 32; - BufferList = BufferList->next.load(std::memory_order_relaxed); + alSetError(context.get(), AL_INVALID_OPERATION, + "Queueing buffer with mismatched format"); + + buffer_error: + /* A buffer failed (invalid ID or format), so unlock and release + * each buffer we had. */ + while(BufferListStart) + { + ALbufferlistitem *next = BufferListStart->next.load(std::memory_order_relaxed); + for(i = 0;i < BufferListStart->num_buffers;i++) + { + if((buffer=BufferListStart->buffers[i]) != nullptr) + DecrementRef(&buffer->ref); + } + al_free(BufferListStart); + BufferListStart = next; + } + return; } - readPos = minu64(readPos, U64(0x7fffffffffffffff)); } + /* All buffers good. */ + buflock.unlock(); - return (ALint64)readPos; + /* Source is now streaming */ + source->SourceType = AL_STREAMING; + + if(!(BufferList=source->queue)) + source->queue = BufferListStart; + else + { + ALbufferlistitem *next; + while((next=BufferList->next.load(std::memory_order_relaxed)) != nullptr) + BufferList = next; + BufferList->next.store(BufferListStart, std::memory_order_release); + } } -/* GetSourceSecOffset - * - * Gets the current read offset for the given Source, in seconds. The offset is - * relative to the start of the queue (not the start of the current buffer). - */ -static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime) +AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers) { - ALCdevice *device = context->Device; - const ALbufferlistitem *Current; - ALuint64 readPos; - ALuint refcount; - ALdouble offset; - ALvoice *voice; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - do { - Current = NULL; - readPos = 0; - while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) - althrd_yield(); - *clocktime = GetDeviceClockTime(device); + if(nb < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffer layers", nb); + if(nb == 0) return; - voice = GetSourceVoice(Source, context); - if(voice) - { - Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); + std::lock_guard _{context->SourceLock}; + ALsource *source{LookupSource(context.get(),src)}; + if(!source) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); - readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << - FRACTIONBITS; - readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); - } - std::atomic_thread_fence(std::memory_order_acquire); - } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); + /* Can't queue on a Static Source */ + if(source->SourceType == AL_STATIC) + SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src); - offset = 0.0; - if(voice) + /* Check for a valid Buffer, for its frequency and format */ + ALCdevice *device{context->Device}; + ALbuffer *BufferFmt{nullptr}; + ALbufferlistitem *BufferList{source->queue}; + while(BufferList) { - const ALbufferlistitem *BufferList = Source->queue; - const ALbuffer *BufferFmt = NULL; - while(BufferList && BufferList != Current) - { - ALsizei i = 0; - while(!BufferFmt && i < BufferList->num_buffers) - BufferFmt = BufferList->buffers[i++]; - readPos += (ALuint64)BufferList->max_samples << FRACTIONBITS; - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - - while(BufferList && !BufferFmt) + for(ALsizei i{0};i < BufferList->num_buffers;i++) { - ALsizei i = 0; - while(!BufferFmt && i < BufferList->num_buffers) - BufferFmt = BufferList->buffers[i++]; - BufferList = BufferList->next.load(std::memory_order_relaxed); + if((BufferFmt=BufferList->buffers[i]) != nullptr) + break; } - assert(BufferFmt != NULL); - - offset = (ALdouble)readPos / (ALdouble)FRACTIONONE / - (ALdouble)BufferFmt->Frequency; + if(BufferFmt) break; + BufferList = BufferList->next.load(std::memory_order_relaxed); } - return offset; -} - -/* GetSourceOffset - * - * Gets the current read offset for the given Source, in the appropriate format - * (Bytes, Samples or Seconds). The offset is relative to the start of the - * queue (not the start of the current buffer). - */ -static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) -{ - ALCdevice *device = context->Device; - const ALbufferlistitem *Current; - ALuint readPos; - ALsizei readPosFrac; - ALuint refcount; - ALdouble offset; - ALvoice *voice; + std::unique_lock buflock{device->BufferLock}; + auto BufferListStart = static_cast(al_calloc(DEF_ALIGN, + FAM_SIZE(ALbufferlistitem, buffers, nb))); + BufferList = BufferListStart; + ATOMIC_INIT(&BufferList->next, static_cast(nullptr)); + BufferList->max_samples = 0; + BufferList->num_buffers = 0; - do { - Current = NULL; - readPos = readPosFrac = 0; - while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) - althrd_yield(); - voice = GetSourceVoice(Source, context); - if(voice) + for(ALsizei i{0};i < nb;i++) + { + ALbuffer *buffer{nullptr}; + if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr) { - Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - - readPos = ATOMIC_LOAD(&voice->position, almemory_order_relaxed); - readPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); + alSetError(context.get(), AL_INVALID_NAME, "Queueing invalid buffer ID %u", + buffers[i]); + goto buffer_error; } - std::atomic_thread_fence(std::memory_order_acquire); - } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); - - offset = 0.0; - if(voice) - { - const ALbufferlistitem *BufferList = Source->queue; - const ALbuffer *BufferFmt = NULL; - ALboolean readFin = AL_FALSE; - ALuint totalBufferLen = 0; - while(BufferList != NULL) - { - ALsizei i = 0; - while(!BufferFmt && i < BufferList->num_buffers) - BufferFmt = BufferList->buffers[i++]; + BufferList->buffers[BufferList->num_buffers++] = buffer; + if(!buffer) continue; - readFin |= (BufferList == Current); - totalBufferLen += BufferList->max_samples; - if(!readFin) readPos += BufferList->max_samples; + IncrementRef(&buffer->ref); - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - assert(BufferFmt != NULL); + BufferList->max_samples = maxi(BufferList->max_samples, buffer->SampleLen); - if(Source->Looping) - readPos %= totalBufferLen; - else + if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) { - /* Wrap back to 0 */ - if(readPos >= totalBufferLen) - readPos = readPosFrac = 0; + alSetError(context.get(), AL_INVALID_OPERATION, + "Queueing non-persistently mapped buffer %u", buffer->id); + goto buffer_error; } - offset = 0.0; - switch(name) + if(BufferFmt == nullptr) + BufferFmt = buffer; + else if(BufferFmt->Frequency != buffer->Frequency || + BufferFmt->FmtChannels != buffer->FmtChannels || + BufferFmt->OriginalType != buffer->OriginalType) { - case AL_SEC_OFFSET: - offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE) / BufferFmt->Frequency; - break; - - case AL_SAMPLE_OFFSET: - offset = readPos + (ALdouble)readPosFrac/FRACTIONONE; - break; - - case AL_BYTE_OFFSET: - if(BufferFmt->OriginalType == UserFmtIMA4) - { - ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; - ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels); - ALuint FrameBlockSize = BufferFmt->OriginalAlign; - - /* Round down to nearest ADPCM block */ - offset = (ALdouble)(readPos / FrameBlockSize * BlockSize); - } - else if(BufferFmt->OriginalType == UserFmtMSADPCM) - { - ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; - ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels); - ALuint FrameBlockSize = BufferFmt->OriginalAlign; + alSetError(context.get(), AL_INVALID_OPERATION, + "Queueing buffer with mismatched format"); - /* Round down to nearest ADPCM block */ - offset = (ALdouble)(readPos / FrameBlockSize * BlockSize); - } - else + buffer_error: + /* A buffer failed (invalid ID or format), so unlock and release + * each buffer we had. */ + while(BufferListStart) + { + ALbufferlistitem *next{BufferListStart->next.load(std::memory_order_relaxed)}; + for(i = 0;i < BufferListStart->num_buffers;i++) { - ALuint FrameSize = FrameSizeFromFmt(BufferFmt->FmtChannels, - BufferFmt->FmtType); - offset = (ALdouble)(readPos * FrameSize); + if((buffer=BufferListStart->buffers[i]) != nullptr) + DecrementRef(&buffer->ref); } - break; + al_free(BufferListStart); + BufferListStart = next; + } + return; } } + /* All buffers good. */ + buflock.unlock(); - return offset; + /* Source is now streaming */ + source->SourceType = AL_STREAMING; + + if(!(BufferList=source->queue)) + source->queue = BufferListStart; + else + { + ALbufferlistitem *next; + while((next=BufferList->next.load(std::memory_order_relaxed)) != nullptr) + BufferList = next; + BufferList->next.store(BufferListStart, std::memory_order_release); + } } +AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(nb < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing %d buffers", nb); + if(nb == 0) return; + + std::lock_guard _{context->SourceLock}; + ALsource *source{LookupSource(context.get(),src)}; + if(!source) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); + + if(source->Looping) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing from looping source %u", src); + if(source->SourceType != AL_STREAMING) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, + "Unqueueing from a non-streaming source %u", src); + + /* Make sure enough buffers have been processed to unqueue. */ + ALbufferlistitem *BufferList{source->queue}; + ALvoice *voice{GetSourceVoice(source, context.get())}; + ALbufferlistitem *Current{nullptr}; + if(voice) + Current = voice->current_buffer.load(std::memory_order_relaxed); + else if(source->state == AL_INITIAL) + Current = BufferList; + if(BufferList == Current) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing pending buffers"); -/* ApplyOffset - * - * Apply the stored playback offset to the Source. This function will update - * the number of buffers "played" given the stored offset. - */ -static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) -{ - ALbufferlistitem *BufferList; - ALuint totalBufferLen; - ALuint offset = 0; - ALsizei frac = 0; + ALsizei i{BufferList->num_buffers}; + while(i < nb) + { + /* If the next bufferlist to check is NULL or is the current one, it's + * trying to unqueue pending buffers. + */ + ALbufferlistitem *next{BufferList->next.load(std::memory_order_relaxed)}; + if(!next || next == Current) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing pending buffers"); + BufferList = next; - /* Get sample frame offset */ - if(!GetSampleOffset(Source, &offset, &frac)) - return AL_FALSE; + i += BufferList->num_buffers; + } - totalBufferLen = 0; - BufferList = Source->queue; - while(BufferList && totalBufferLen <= offset) + while(nb > 0) { - if((ALuint)BufferList->max_samples > offset-totalBufferLen) + ALbufferlistitem *head{source->queue}; + ALbufferlistitem *next{head->next.load(std::memory_order_relaxed)}; + for(i = 0;i < head->num_buffers && nb > 0;i++,nb--) { - /* Offset is in this buffer */ - ATOMIC_STORE(&voice->position, offset - totalBufferLen, almemory_order_relaxed); - ATOMIC_STORE(&voice->position_fraction, frac, almemory_order_relaxed); - ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_release); - return AL_TRUE; + ALbuffer *buffer{head->buffers[i]}; + if(!buffer) + *(buffers++) = 0; + else + { + *(buffers++) = buffer->id; + DecrementRef(&buffer->ref); + } + } + if(i < head->num_buffers) + { + /* This head has some buffers left over, so move them to the front + * and update the sample and buffer count. + */ + ALsizei max_length{0}; + ALsizei j{0}; + while(i < head->num_buffers) + { + ALbuffer *buffer{head->buffers[i++]}; + if(buffer) max_length = maxi(max_length, buffer->SampleLen); + head->buffers[j++] = buffer; + } + head->max_samples = max_length; + head->num_buffers = j; + break; } - totalBufferLen += BufferList->max_samples; - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + /* Otherwise, free this item and set the source queue head to the next + * one. + */ + al_free(head); + source->queue = next; } - - /* Offset is out of range of the queue */ - return AL_FALSE; } -/* GetSampleOffset - * - * Retrieves the sample offset into the Source's queue (from the Sample, Byte - * or Second offset supplied by the application). This takes into account the - * fact that the buffer format may have been modifed since. - */ -static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac) +ALsource::ALsource(ALsizei num_sends) { - const ALbuffer *BufferFmt = NULL; - const ALbufferlistitem *BufferList; - ALdouble dbloff, dblfrac; + InnerAngle = 360.0f; + OuterAngle = 360.0f; + Pitch = 1.0f; + Position[0] = 0.0f; + Position[1] = 0.0f; + Position[2] = 0.0f; + Velocity[0] = 0.0f; + Velocity[1] = 0.0f; + Velocity[2] = 0.0f; + Direction[0] = 0.0f; + Direction[1] = 0.0f; + Direction[2] = 0.0f; + Orientation[0][0] = 0.0f; + Orientation[0][1] = 0.0f; + Orientation[0][2] = -1.0f; + Orientation[1][0] = 0.0f; + Orientation[1][1] = 1.0f; + Orientation[1][2] = 0.0f; + RefDistance = 1.0f; + MaxDistance = FLT_MAX; + RolloffFactor = 1.0f; + Gain = 1.0f; + MinGain = 0.0f; + MaxGain = 1.0f; + OuterGain = 0.0f; + OuterGainHF = 1.0f; - /* Find the first valid Buffer in the Queue */ - BufferList = Source->queue; - while(BufferList) - { - ALsizei i; - for(i = 0;i < BufferList->num_buffers && !BufferFmt;i++) - BufferFmt = BufferList->buffers[i]; - if(BufferFmt) break; - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - if(!BufferFmt) - { - Source->OffsetType = AL_NONE; - Source->Offset = 0.0; - return AL_FALSE; - } + DryGainHFAuto = AL_TRUE; + WetGainAuto = AL_TRUE; + WetGainHFAuto = AL_TRUE; + AirAbsorptionFactor = 0.0f; + RoomRolloffFactor = 0.0f; + DopplerFactor = 1.0f; + HeadRelative = AL_FALSE; + Looping = AL_FALSE; + mDistanceModel = DistanceModel::Default; + Resampler = ResamplerDefault; + DirectChannels = AL_FALSE; + Spatialize = SpatializeAuto; - switch(Source->OffsetType) - { - case AL_BYTE_OFFSET: - /* Determine the ByteOffset (and ensure it is block aligned) */ - *offset = (ALuint)Source->Offset; - if(BufferFmt->OriginalType == UserFmtIMA4) - { - ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; - *offset /= align * ChannelsFromFmt(BufferFmt->FmtChannels); - *offset *= BufferFmt->OriginalAlign; - } - else if(BufferFmt->OriginalType == UserFmtMSADPCM) - { - ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; - *offset /= align * ChannelsFromFmt(BufferFmt->FmtChannels); - *offset *= BufferFmt->OriginalAlign; - } - else - *offset /= FrameSizeFromFmt(BufferFmt->FmtChannels, BufferFmt->FmtType); - *frac = 0; - break; + StereoPan[0] = DEG2RAD( 30.0f); + StereoPan[1] = DEG2RAD(-30.0f); - case AL_SAMPLE_OFFSET: - dblfrac = modf(Source->Offset, &dbloff); - *offset = (ALuint)mind(dbloff, UINT_MAX); - *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0); - break; + Radius = 0.0f; - case AL_SEC_OFFSET: - dblfrac = modf(Source->Offset*BufferFmt->Frequency, &dbloff); - *offset = (ALuint)mind(dbloff, UINT_MAX); - *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0); - break; + Direct.Gain = 1.0f; + Direct.GainHF = 1.0f; + Direct.HFReference = LOWPASSFREQREF; + Direct.GainLF = 1.0f; + Direct.LFReference = HIGHPASSFREQREF; + Send.resize(num_sends); + for(auto &send : Send) + { + send.Slot = nullptr; + send.Gain = 1.0f; + send.GainHF = 1.0f; + send.HFReference = LOWPASSFREQREF; + send.GainLF = 1.0f; + send.LFReference = HIGHPASSFREQREF; } - Source->OffsetType = AL_NONE; - Source->Offset = 0.0; - return AL_TRUE; -} + Offset = 0.0; + OffsetType = AL_NONE; + SourceType = AL_UNDETERMINED; + state = AL_INITIAL; + + queue = nullptr; + VoiceIdx = -1; +} -static ALsource *AllocSource(ALCcontext *context) +ALsource::~ALsource() { - ALCdevice *device{context->Device}; - almtx_lock(&context->SourceLock); - if(context->NumSources >= device->SourcesMax) - { - almtx_unlock(&context->SourceLock); - alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax); - return nullptr; - } - auto sublist = std::find_if(context->SourceList.begin(), context->SourceList.end(), - [](const SourceSubList &entry) -> bool - { return entry.FreeMask != 0; } - ); - ALsizei lidx = std::distance(context->SourceList.begin(), sublist); - ALsource *source; - ALsizei slidx; - if(LIKELY(sublist != context->SourceList.end())) - { - slidx = CTZ64(sublist->FreeMask); - source = sublist->Sources + slidx; - } - else + ALbufferlistitem *BufferList{queue}; + while(BufferList != nullptr) { - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ - if(UNLIKELY(context->SourceList.size() >= 1<<25)) + ALbufferlistitem *next{BufferList->next.load(std::memory_order_relaxed)}; + for(ALsizei i{0};i < BufferList->num_buffers;i++) { - almtx_unlock(&device->BufferLock); - alSetError(context, AL_OUT_OF_MEMORY, "Too many sources allocated"); - return nullptr; + if(BufferList->buffers[i]) + DecrementRef(&BufferList->buffers[i]->ref); } - context->SourceList.emplace_back(); - sublist = context->SourceList.end() - 1; + al_free(BufferList); + BufferList = next; + } + queue = nullptr; - sublist->FreeMask = ~U64(0); - sublist->Sources = static_cast(al_calloc(16, sizeof(ALsource)*64)); - if(UNLIKELY(!sublist->Sources)) + std::for_each(Send.begin(), Send.end(), + [](ALsource::SendData &send) -> void { - context->SourceList.pop_back(); - almtx_unlock(&context->SourceLock); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate source batch"); - return nullptr; + if(send.Slot) + DecrementRef(&send.Slot->ref); + send.Slot = nullptr; } - - slidx = 0; - source = sublist->Sources + slidx; - } - - source = new (source) ALsource{device->NumAuxSends}; - - /* Add 1 to avoid source ID 0. */ - source->id = ((lidx<<6) | slidx) + 1; - - context->NumSources++; - sublist->FreeMask &= ~(U64(1)<SourceLock); - - return source; + ); } -static void FreeSource(ALCcontext *context, ALsource *source) +void UpdateAllSourceProps(ALCcontext *context) { - ALCdevice *device = context->Device; - ALuint id = source->id - 1; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; - ALvoice *voice; - - ALCdevice_Lock(device); - if((voice=GetSourceVoice(source, context)) != NULL) + for(ALsizei i{0};i < context->VoiceCount;++i) { - ATOMIC_STORE(&voice->Source, static_cast(nullptr), almemory_order_relaxed); - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + ALvoice *voice{context->Voices[i]}; + ALsource *source{voice->Source.load(std::memory_order_acquire)}; + if(source && !source->PropsClean.test_and_set(std::memory_order_acq_rel)) + UpdateSourceProps(source, voice, context); } - ALCdevice_Unlock(device); - - source->~ALsource(); - - context->SourceList[lidx].FreeMask |= U64(1) << slidx; - context->NumSources--; } /* ReleaseALSources @@ -3460,8 +3420,8 @@ ALvoid ReleaseALSources(ALCcontext *context) ALuint64 usemask = ~sublist.FreeMask; while(usemask) { - ALsizei idx = CTZ64(usemask); - ALsource *source = sublist.Sources + idx; + ALsizei idx{CTZ64(usemask)}; + ALsource *source{sublist.Sources + idx}; source->~ALsource(); ++leftover; -- cgit v1.2.3 From 84f0f74d0794b38d1b1bb0021090d50f2648e0ce Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Nov 2018 12:53:16 -0800 Subject: Use standard types for the device clock times --- Alc/alc.cpp | 22 +++++++++++++++------- Alc/alu.cpp | 2 +- Alc/backends/base.cpp | 2 +- Alc/backends/base.h | 11 +++++++++-- OpenAL32/Include/alMain.h | 5 +++-- 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 42856dbf..a5238aa5 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1682,8 +1682,13 @@ static struct Compressor *CreateDeviceLimiter(const ALCdevice *device, const ALf */ static inline void UpdateClockBase(ALCdevice *device) { + using std::chrono::seconds; + using std::chrono::nanoseconds; + using std::chrono::duration_cast; + IncrementRef(&device->MixCount); - device->ClockBase += device->SamplesDone * DEVICE_CLOCK_RES / device->Frequency; + device->ClockBase += duration_cast(seconds{device->SamplesDone}) / + device->Frequency; device->SamplesDone = 0; IncrementRef(&device->MixCount); } @@ -2006,7 +2011,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->MixBuffer.shrink_to_fit(); UpdateClockBase(device); - device->FixedLatency = 0; + device->FixedLatency = std::chrono::nanoseconds::zero(); device->DitherSeed = DITHER_RNG_SEED; @@ -2222,8 +2227,10 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) thrshld -= 1.0f / device->DitherDepth; device->Limiter.reset(CreateDeviceLimiter(device, std::log10(thrshld) * 20.0f)); - device->FixedLatency += (ALuint)(GetCompressorLookAhead(device->Limiter.get()) * - DEVICE_CLOCK_RES / device->Frequency); + /* Convert the lookahead from samples to nanosamples to nanoseconds. */ + device->FixedLatency += std::chrono::duration_cast( + std::chrono::seconds(GetCompressorLookAhead(device->Limiter.get())) + ) / device->Frequency; } else device->Limiter = nullptr; @@ -2231,7 +2238,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) aluSelectPostProcess(device); - TRACE("Fixed device latency: %uns\n", device->FixedLatency); + TRACE("Fixed device latency: %ldns\n", (long)device->FixedLatency.count()); /* Need to delay returning failure until replacement Send arrays have been * allocated with the appropriate size. @@ -3420,7 +3427,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, case ALC_DEVICE_CLOCK_SOFT: { std::lock_guard _{device->BackendLock}; - ALuint64 basecount; + std::chrono::nanoseconds basecount; ALuint samplecount; ALuint refcount; do { @@ -3429,7 +3436,8 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, basecount = device->ClockBase; samplecount = device->SamplesDone; } while(refcount != ReadRef(&device->MixCount)); - *values = basecount + (samplecount*DEVICE_CLOCK_RES/device->Frequency); + *values = (basecount + std::chrono::duration_cast( + std::chrono::seconds{samplecount}) / device->Frequency).count(); } break; diff --git a/Alc/alu.cpp b/Alc/alu.cpp index fc386908..6587ab39 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1758,7 +1758,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) * overflow during conversion. This also guarantees an exact, stable * conversion. */ device->SamplesDone += SamplesToDo; - device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES; + device->ClockBase += std::chrono::seconds{device->SamplesDone / device->Frequency}; device->SamplesDone %= device->Frequency; IncrementRef(&device->MixCount); diff --git a/Alc/backends/base.cpp b/Alc/backends/base.cpp index f3a4c60e..1839d353 100644 --- a/Alc/backends/base.cpp +++ b/Alc/backends/base.cpp @@ -18,7 +18,7 @@ void ALCdevice_Unlock(ALCdevice *device) ClockLatency GetClockLatency(ALCdevice *device) { ClockLatency ret = V0(device->Backend,getClockLatency)(); - ret.Latency += device->FixedLatency; + ret.Latency += device->FixedLatency.count(); return ret; } diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 61b71a47..db2127ef 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -7,6 +7,9 @@ #include struct ClockLatency { + /* FIXME: These should be nanoseconds. Will require changing backends that + * provide this info. + */ ALint64 ClockTime; ALint64 Latency; }; @@ -16,8 +19,12 @@ struct ClockLatency { */ inline ALuint64 GetDeviceClockTime(ALCdevice *device) { - return device->ClockBase + (device->SamplesDone * DEVICE_CLOCK_RES / - device->Frequency); + using std::chrono::seconds; + using std::chrono::nanoseconds; + using std::chrono::duration_cast; + + auto ns = duration_cast(seconds{device->SamplesDone}) / device->Frequency; + return (device->ClockBase + ns).count(); } void ALCdevice_Lock(ALCdevice *device); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 744e3609..036d4ec3 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -19,6 +19,7 @@ #include #include #include +#include #include "AL/al.h" #include "AL/alc.h" @@ -690,9 +691,9 @@ struct ALCdevice_struct { // Device flags ALuint Flags{0u}; - ALuint64 ClockBase{0u}; ALuint SamplesDone{0u}; - ALuint FixedLatency{0u}; + std::chrono::nanoseconds ClockBase{0}; + std::chrono::nanoseconds FixedLatency{0}; /* Temp storage used for mixer processing. */ alignas(16) ALfloat TempBuffer[4][BUFFERSIZE]; -- cgit v1.2.3 From d26b5d94677a7091d95972cbfd4337fb36a5e622 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Nov 2018 14:32:48 -0800 Subject: Use proper time types for the device clock time and latency --- Alc/alc.cpp | 10 +++++----- Alc/backends/alsa.cpp | 6 ++++-- Alc/backends/base.cpp | 6 +++--- Alc/backends/base.h | 12 +++++------- Alc/backends/jack.cpp | 4 ++-- Alc/backends/opensl.cpp | 4 ++-- Alc/backends/pulseaudio.cpp | 4 ++-- Alc/backends/wasapi.cpp | 4 ++-- OpenAL32/alSource.cpp | 28 ++++++++++++++-------------- 9 files changed, 39 insertions(+), 39 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index a5238aa5..a8ea1c53 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -3416,10 +3416,10 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ClockLatency clock{GetClockLatency(device)}; values[i++] = ALC_DEVICE_CLOCK_SOFT; - values[i++] = clock.ClockTime; + values[i++] = clock.ClockTime.count(); values[i++] = ALC_DEVICE_LATENCY_SOFT; - values[i++] = clock.Latency; + values[i++] = clock.Latency.count(); values[i++] = 0; } @@ -3444,7 +3444,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, case ALC_DEVICE_LATENCY_SOFT: { std::lock_guard _{device->BackendLock}; ClockLatency clock{GetClockLatency(device)}; - *values = clock.Latency; + *values = clock.Latency.count(); } break; @@ -3455,8 +3455,8 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, { std::lock_guard _{device->BackendLock}; ClockLatency clock{GetClockLatency(device)}; - values[0] = clock.ClockTime; - values[1] = clock.Latency; + values[0] = clock.ClockTime.count(); + values[1] = clock.Latency.count(); } break; diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index e1e861db..35c1f834 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -915,7 +915,8 @@ ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self) ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); delay = 0; } - ret.Latency = std::max(0, delay) * DEVICE_CLOCK_RES / device->Frequency; + ret.Latency = std::chrono::seconds{std::max(0, delay)}; + ret.Latency /= device->Frequency; ALCplaybackAlsa_unlock(self); return ret; @@ -1286,7 +1287,8 @@ ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self) ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); delay = 0; } - ret.Latency = std::max(0, delay) * DEVICE_CLOCK_RES / device->Frequency; + ret.Latency = std::chrono::seconds{std::max(0, delay)}; + ret.Latency /= device->Frequency; ALCcaptureAlsa_unlock(self); return ret; diff --git a/Alc/backends/base.cpp b/Alc/backends/base.cpp index 1839d353..e4c7588c 100644 --- a/Alc/backends/base.cpp +++ b/Alc/backends/base.cpp @@ -18,7 +18,7 @@ void ALCdevice_Unlock(ALCdevice *device) ClockLatency GetClockLatency(ALCdevice *device) { ClockLatency ret = V0(device->Backend,getClockLatency)(); - ret.Latency += device->FixedLatency.count(); + ret.Latency += device->FixedLatency; return ret; } @@ -65,8 +65,8 @@ ClockLatency ALCbackend_getClockLatency(ALCbackend *self) * any given time during playback. Without a more accurate measurement from * the output, this is an okay approximation. */ - ret.Latency = device->UpdateSize * DEVICE_CLOCK_RES / device->Frequency * - maxu(device->NumUpdates-1, 1); + ret.Latency = std::chrono::seconds{device->UpdateSize*maxi(device->NumUpdates-1, 0)}; + ret.Latency /= device->Frequency; return ret; } diff --git a/Alc/backends/base.h b/Alc/backends/base.h index db2127ef..f4de5176 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -3,28 +3,26 @@ #include "alMain.h" +#include #include #include struct ClockLatency { - /* FIXME: These should be nanoseconds. Will require changing backends that - * provide this info. - */ - ALint64 ClockTime; - ALint64 Latency; + std::chrono::nanoseconds ClockTime; + std::chrono::nanoseconds Latency; }; /* Helper to get the current clock time from the device's ClockBase, and * SamplesDone converted from the sample rate. */ -inline ALuint64 GetDeviceClockTime(ALCdevice *device) +inline std::chrono::nanoseconds GetDeviceClockTime(ALCdevice *device) { using std::chrono::seconds; using std::chrono::nanoseconds; using std::chrono::duration_cast; auto ns = duration_cast(seconds{device->SamplesDone}) / device->Frequency; - return (device->ClockBase + ns).count(); + return device->ClockBase + ns; } void ALCdevice_Lock(ALCdevice *device); diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index 93dbaf13..cd02388d 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -503,8 +503,8 @@ static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self) ALCjackPlayback_lock(self); ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = ll_ringbuffer_read_space(self->Ring) * DEVICE_CLOCK_RES / - device->Frequency; + ret.Latency = std::chrono::seconds{ll_ringbuffer_read_space(self->Ring)}; + ret.Latency /= device->Frequency; ALCjackPlayback_unlock(self); return ret; diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 2c516021..f7ad1595 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -654,8 +654,8 @@ static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self) ALCopenslPlayback_lock(self); ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = ll_ringbuffer_read_space(self->mRing)*device->UpdateSize * - DEVICE_CLOCK_RES / device->Frequency; + ret.Latency = std::chrono::seconds{ll_ringbuffer_read_space(self->mRing)*device->UpdateSize}; + ret.Latency /= device->Frequency; ALCopenslPlayback_unlock(self); return ret; diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index d0c1c229..9563cdd4 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -1213,7 +1213,7 @@ ClockLatency PulsePlayback_getClockLatency(PulsePlayback *self) } else if(UNLIKELY(neg)) latency = 0; - ret.Latency = (ALint64)minu64(latency, U64(0x7fffffffffffffff)/1000) * 1000; + ret.Latency = std::chrono::microseconds{latency}; return ret; } @@ -1714,7 +1714,7 @@ ClockLatency PulseCapture_getClockLatency(PulseCapture *self) } else if(UNLIKELY(neg)) latency = 0; - ret.Latency = (ALint64)minu64(latency, U64(0x7fffffffffffffff)/1000) * 1000; + ret.Latency = std::chrono::microseconds{latency}; return ret; } diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index e531a9ae..52f324f7 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -1145,8 +1145,8 @@ ClockLatency ALCwasapiPlayback_getClockLatency(ALCwasapiPlayback *self) ALCwasapiPlayback_lock(self); ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = self->mPadding.load(std::memory_order_relaxed) * DEVICE_CLOCK_RES / - device->Frequency; + ret.Latency = std::chrono::seconds{self->mPadding.load(std::memory_order_relaxed)}; + ret.Latency /= device->Frequency; ALCwasapiPlayback_unlock(self); return ret; diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 382875d5..df2de67c 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -147,7 +147,7 @@ void UpdateSourceProps(ALsource *source, ALvoice *voice, ALCcontext *context) * samples. The offset is relative to the start of the queue (not the start of * the current buffer). */ -ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime) +ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, std::chrono::nanoseconds *clocktime) { ALCdevice *device{context->Device}; const ALbufferlistitem *Current; @@ -193,7 +193,7 @@ ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *c * Gets the current read offset for the given Source, in seconds. The offset is * relative to the start of the queue (not the start of the current buffer). */ -ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime) +ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, std::chrono::nanoseconds *clocktime) { ALCdevice *device{context->Device}; const ALbufferlistitem *Current; @@ -1654,7 +1654,7 @@ ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL { ALCdevice *device{Context->Device}; ClockLatency clocktime; - ALuint64 srcclock; + std::chrono::nanoseconds srcclock; ALint ivals[3]; ALboolean err; @@ -1739,23 +1739,23 @@ ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL { std::lock_guard _{device->BackendLock}; clocktime = GetClockLatency(device); } - if(srcclock == (ALuint64)clocktime.ClockTime) - values[1] = (ALdouble)clocktime.Latency / 1000000000.0; + if(srcclock == clocktime.ClockTime) + values[1] = (ALdouble)clocktime.Latency.count() / 1000000000.0; else { /* If the clock time incremented, reduce the latency by that * much since it's that much closer to the source offset it got * earlier. */ - ALuint64 diff = clocktime.ClockTime - srcclock; - values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) / + std::chrono::nanoseconds diff = clocktime.ClockTime - srcclock; + values[1] = (ALdouble)(clocktime.Latency - std::min(clocktime.Latency, diff)).count() / 1000000000.0; } return AL_TRUE; case AL_SEC_OFFSET_CLOCK_SOFT: values[0] = GetSourceSecOffset(Source, Context, &srcclock); - values[1] = srcclock / 1000000000.0; + values[1] = srcclock.count() / 1000000000.0; return AL_TRUE; case AL_POSITION: @@ -1987,7 +1987,7 @@ ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, { ALCdevice *device = Context->Device; ClockLatency clocktime; - ALuint64 srcclock; + std::chrono::nanoseconds srcclock; ALdouble dvals[6]; ALint ivals[3]; ALboolean err; @@ -2002,22 +2002,22 @@ ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, { std::lock_guard _{device->BackendLock}; clocktime = GetClockLatency(device); } - if(srcclock == (ALuint64)clocktime.ClockTime) - values[1] = clocktime.Latency; + if(srcclock == clocktime.ClockTime) + values[1] = clocktime.Latency.count(); else { /* If the clock time incremented, reduce the latency by that * much since it's that much closer to the source offset it got * earlier. */ - ALuint64 diff{clocktime.ClockTime - srcclock}; - values[1] = clocktime.Latency - minu64(clocktime.Latency, diff); + auto diff = clocktime.ClockTime - srcclock; + values[1] = (clocktime.Latency - std::min(clocktime.Latency, diff)).count(); } return AL_TRUE; case AL_SAMPLE_OFFSET_CLOCK_SOFT: values[0] = GetSourceSampleOffset(Source, Context, &srcclock); - values[1] = srcclock; + values[1] = srcclock.count(); return AL_TRUE; /* 1x float/double */ -- cgit v1.2.3 From 30ee6e1b3f3e859b10816234149795219c9108f9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Nov 2018 14:36:37 -0800 Subject: Make a DirectHrtfState constructor to try appeasing MSVC --- Alc/hrtf.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 1409ffa8..cbec2fc7 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -50,13 +50,15 @@ struct HrtfParams { struct DirectHrtfState { /* HRTF filter state for dry buffer content */ - ALsizei Offset; - ALsizei IrSize; + ALsizei Offset{0}; + ALsizei IrSize{0}; struct { alignas(16) ALfloat Values[HRIR_LENGTH][2]; alignas(16) ALfloat Coeffs[HRIR_LENGTH][2]; } Chan[]; + DirectHrtfState() noexcept { } + DEF_PLACE_NEWDEL() }; -- cgit v1.2.3 From 976e49711b47d6c742995986e976275badb5c9f0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Nov 2018 19:47:41 -0800 Subject: Add noexcept to a bunch of inline functions --- OpenAL32/Include/alMain.h | 10 +++++----- OpenAL32/Include/alu.h | 46 +++++++++++++++++++++++----------------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 036d4ec3..efec58a0 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -219,7 +219,7 @@ struct bs2b; /* Find the next power-of-2 for non-power-of-2 numbers. */ -inline ALuint NextPowerOf2(ALuint value) +inline ALuint NextPowerOf2(ALuint value) noexcept { if(value > 0) { @@ -234,7 +234,7 @@ inline ALuint NextPowerOf2(ALuint value) } /** Round up a value to the next multiple. */ -inline size_t RoundUp(size_t value, size_t r) +inline size_t RoundUp(size_t value, size_t r) noexcept { value += r-1; return value - (value%r); @@ -245,7 +245,7 @@ inline size_t RoundUp(size_t value, size_t r) * change it on its own threads. On some systems, a truncating conversion may * always be the fastest method. */ -inline ALint fastf2i(ALfloat f) +inline ALint fastf2i(ALfloat f) noexcept { #if defined(HAVE_INTRIN_H) && ((defined(_M_IX86_FP) && (_M_IX86_FP > 0)) || defined(_M_X64)) return _mm_cvt_ss2si(_mm_set1_ps(f)); @@ -283,7 +283,7 @@ inline ALint fastf2i(ALfloat f) } /* Converts float-to-int using standard behavior (truncation). */ -inline int float2int(float f) +inline int float2int(float f) noexcept { #if ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) && \ !defined(__SSE_MATH__)) || (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP == 0) @@ -316,7 +316,7 @@ inline int float2int(float f) * rounding mode. This is essentially an inlined version of rintf, although * makes fewer promises (e.g. -0 or -0.25 rounded to 0 may result in +0). */ -inline float fast_roundf(float f) +inline float fast_roundf(float f) noexcept { #if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) && \ !defined(__SSE_MATH__) diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index d086bcc7..eb71290a 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -304,61 +304,61 @@ typedef void (*HrtfDirectMixerFunc)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT #define FRACTIONMASK (FRACTIONONE-1) -inline ALfloat minf(ALfloat a, ALfloat b) +inline ALfloat minf(ALfloat a, ALfloat b) noexcept { return ((a > b) ? b : a); } -inline ALfloat maxf(ALfloat a, ALfloat b) +inline ALfloat maxf(ALfloat a, ALfloat b) noexcept { return ((a > b) ? a : b); } -inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max) +inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max) noexcept { return minf(max, maxf(min, val)); } -inline ALdouble mind(ALdouble a, ALdouble b) +inline ALdouble mind(ALdouble a, ALdouble b) noexcept { return ((a > b) ? b : a); } -inline ALdouble maxd(ALdouble a, ALdouble b) +inline ALdouble maxd(ALdouble a, ALdouble b) noexcept { return ((a > b) ? a : b); } -inline ALdouble clampd(ALdouble val, ALdouble min, ALdouble max) +inline ALdouble clampd(ALdouble val, ALdouble min, ALdouble max) noexcept { return mind(max, maxd(min, val)); } -inline ALuint minu(ALuint a, ALuint b) +inline ALuint minu(ALuint a, ALuint b) noexcept { return ((a > b) ? b : a); } -inline ALuint maxu(ALuint a, ALuint b) +inline ALuint maxu(ALuint a, ALuint b) noexcept { return ((a > b) ? a : b); } -inline ALuint clampu(ALuint val, ALuint min, ALuint max) +inline ALuint clampu(ALuint val, ALuint min, ALuint max) noexcept { return minu(max, maxu(min, val)); } -inline ALint mini(ALint a, ALint b) +inline ALint mini(ALint a, ALint b) noexcept { return ((a > b) ? b : a); } -inline ALint maxi(ALint a, ALint b) +inline ALint maxi(ALint a, ALint b) noexcept { return ((a > b) ? a : b); } -inline ALint clampi(ALint val, ALint min, ALint max) +inline ALint clampi(ALint val, ALint min, ALint max) noexcept { return mini(max, maxi(min, val)); } -inline ALint64 mini64(ALint64 a, ALint64 b) +inline ALint64 mini64(ALint64 a, ALint64 b) noexcept { return ((a > b) ? b : a); } -inline ALint64 maxi64(ALint64 a, ALint64 b) +inline ALint64 maxi64(ALint64 a, ALint64 b) noexcept { return ((a > b) ? a : b); } -inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max) +inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max) noexcept { return mini64(max, maxi64(min, val)); } -inline ALuint64 minu64(ALuint64 a, ALuint64 b) +inline ALuint64 minu64(ALuint64 a, ALuint64 b) noexcept { return ((a > b) ? b : a); } -inline ALuint64 maxu64(ALuint64 a, ALuint64 b) +inline ALuint64 maxu64(ALuint64 a, ALuint64 b) noexcept { return ((a > b) ? a : b); } -inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max) +inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max) noexcept { return minu64(max, maxu64(min, val)); } -inline size_t minz(size_t a, size_t b) +inline size_t minz(size_t a, size_t b) noexcept { return ((a > b) ? b : a); } -inline size_t maxz(size_t a, size_t b) +inline size_t maxz(size_t a, size_t b) noexcept { return ((a > b) ? a : b); } -inline size_t clampz(size_t val, size_t min, size_t max) +inline size_t clampz(size_t val, size_t min, size_t max) noexcept { return minz(max, maxz(min, val)); } -inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu) +inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu) noexcept { return val1 + (val2-val1)*mu; } -inline ALfloat cubic(ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat mu) +inline ALfloat cubic(ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat mu) noexcept { ALfloat mu2 = mu*mu, mu3 = mu2*mu; ALfloat a0 = -0.5f*mu3 + mu2 + -0.5f*mu; -- cgit v1.2.3 From 438e626993fe86831b666a42b5f90731d5c26aeb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Nov 2018 22:53:22 -0800 Subject: Avoid a couple explicit loops --- Alc/panning.cpp | 37 ++++++++++++++++++------------------- OpenAL32/Include/alMain.h | 13 +++++-------- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index a67234ec..7b5a6674 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -219,32 +219,31 @@ static inline const char *GetLabelFromChannel(enum Channel channel) } -typedef struct ChannelMap { - enum Channel ChanName; +struct ChannelMap { + Channel ChanName; ChannelConfig Config; -} ChannelMap; +}; -static void SetChannelMap(const enum Channel devchans[MAX_OUTPUT_CHANNELS], +static void SetChannelMap(const Channel (&devchans)[MAX_OUTPUT_CHANNELS], ChannelConfig *ambicoeffs, const ChannelMap *chanmap, ALsizei count, ALsizei *outcount) { - ALsizei maxchans = 0; - ALsizei i, j; - - for(i = 0;i < count;i++) - { - ALint idx = GetChannelIndex(devchans, chanmap[i].ChanName); - if(idx < 0) + ALsizei maxchans{0}; + std::for_each(chanmap, chanmap+count, + [&maxchans,&devchans,ambicoeffs](const ChannelMap &channel) -> void { - ERR("Failed to find %s channel in device\n", - GetLabelFromChannel(chanmap[i].ChanName)); - continue; - } + ALint idx = GetChannelIndex(devchans, channel.ChanName); + if(idx < 0) + { + ERR("Failed to find %s channel in device\n", + GetLabelFromChannel(channel.ChanName)); + return; + } - maxchans = maxi(maxchans, idx+1); - for(j = 0;j < MAX_AMBI_COEFFS;j++) - ambicoeffs[idx][j] = chanmap[i].Config[j]; - } + maxchans = maxi(maxchans, idx+1); + std::copy_n(channel.Config, MAX_AMBI_COEFFS, ambicoeffs[idx]); + } + ); *outcount = mini(maxchans, MAX_OUTPUT_CHANNELS); } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index efec58a0..1a2f7d8d 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -20,6 +20,7 @@ #include #include #include +#include #include "AL/al.h" #include "AL/alc.h" @@ -822,15 +823,11 @@ void SetDefaultWFXChannelOrder(ALCdevice *device); const ALCchar *DevFmtTypeString(enum DevFmtType type); const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans); -inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS], enum Channel chan) +inline ALint GetChannelIndex(const enum Channel (&names)[MAX_OUTPUT_CHANNELS], enum Channel chan) { - ALint i; - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - { - if(names[i] == chan) - return i; - } - return -1; + auto iter = std::find(std::begin(names), std::end(names), chan); + if(iter == std::end(names)) return -1; + return std::distance(names, iter); } /** * GetChannelIdxByName -- cgit v1.2.3 From fb94cdcfd3bf032d2c8783d931a78e188ac55e15 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 23 Nov 2018 13:12:48 -0800 Subject: Restructure and clean up alu.cpp a bit --- Alc/alu.cpp | 317 +++++++++++++++++++++++++++++++----------------------------- 1 file changed, 166 insertions(+), 151 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 6587ab39..71823bf7 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -230,7 +230,7 @@ namespace { * and starting with a seed value of 22222, is suitable for generating * whitenoise. */ -inline ALuint dither_rng(ALuint *seed) +inline ALuint dither_rng(ALuint *seed) noexcept { *seed = (*seed * 96314165) + 907633515; return *seed; @@ -291,7 +291,7 @@ void SendSourceStoppedEvent(ALCcontext *context, ALuint id) size_t strpos; ALuint scale; - enabledevt = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); + enabledevt = context->EnabledEvts.load(std::memory_order_acquire); if(!(enabledevt&EventType_SourceStateChange)) return; evt.u.user.type = AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT; @@ -1456,10 +1456,7 @@ void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, cons void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) { - ALbufferlistitem *BufferListItem; - struct ALvoiceProps *props; - - props = voice->Update.exchange(nullptr, std::memory_order_acq_rel); + ALvoiceProps *props{voice->Update.exchange(nullptr, std::memory_order_acq_rel)}; if(!props && !force) return; if(props) @@ -1472,52 +1469,98 @@ void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) } props = voice->Props; - BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - while(BufferListItem != NULL) + ALbufferlistitem *BufferListItem{voice->current_buffer.load(std::memory_order_relaxed)}; + while(BufferListItem) { - const ALbuffer *buffer = NULL; - ALsizei i = 0; - while(!buffer && i < BufferListItem->num_buffers) - buffer = BufferListItem->buffers[i]; - if(LIKELY(buffer)) + auto buffers_end = BufferListItem->buffers+BufferListItem->num_buffers; + auto buffer = std::find_if(BufferListItem->buffers, buffers_end, + [](const ALbuffer *buffer) noexcept -> bool + { return buffer != nullptr; } + ); + if(LIKELY(buffer != buffers_end)) { if(props->SpatializeMode == SpatializeOn || - (props->SpatializeMode == SpatializeAuto && buffer->FmtChannels == FmtMono)) - CalcAttnSourceParams(voice, props, buffer, context); + (props->SpatializeMode == SpatializeAuto && (*buffer)->FmtChannels == FmtMono)) + CalcAttnSourceParams(voice, props, *buffer, context); else - CalcNonAttnSourceParams(voice, props, buffer, context); + CalcNonAttnSourceParams(voice, props, *buffer, context); break; } - BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_acquire); + BufferListItem = BufferListItem->next.load(std::memory_order_acquire); } } -void ProcessParamUpdates(ALCcontext *ctx, const struct ALeffectslotArray *slots) +void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray *slots) { - ALvoice **voice, **voice_end; - ALsource *source; - ALsizei i; - IncrementRef(&ctx->UpdateCount); - if(!ATOMIC_LOAD(&ctx->HoldUpdates, almemory_order_acquire)) + if(LIKELY(!ctx->HoldUpdates.load(std::memory_order_acquire))) { bool cforce = CalcContextParams(ctx); bool force = CalcListenerParams(ctx) | cforce; - for(i = 0;i < slots->count;i++) - force |= CalcEffectSlotParams(slots->slot[i], ctx, cforce); + std::for_each(slots->slot, slots->slot+slots->count, + [ctx,cforce,&force](ALeffectslot *slot) -> void + { force |= CalcEffectSlotParams(slot, ctx, cforce); } + ); - voice = ctx->Voices; - voice_end = voice + ctx->VoiceCount; - for(;voice != voice_end;++voice) - { - source = ATOMIC_LOAD(&(*voice)->Source, almemory_order_acquire); - if(source) CalcSourceParams(*voice, ctx, force); - } + std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount, + [ctx,force](ALvoice *voice) -> void + { + ALsource *source{voice->Source.load(std::memory_order_acquire)}; + if(source) CalcSourceParams(voice, ctx, force); + } + ); } IncrementRef(&ctx->UpdateCount); } +void ProcessContext(ALCcontext *ctx, ALsizei SamplesToDo) +{ + const ALeffectslotArray *auxslots{ctx->ActiveAuxSlots.load(std::memory_order_acquire)}; + + /* Process pending propery updates for objects on the context. */ + ProcessParamUpdates(ctx, auxslots); + + /* Clear auxiliary effect slot mixing buffers. */ + std::for_each(auxslots->slot, auxslots->slot+auxslots->count, + [SamplesToDo](ALeffectslot *slot) -> void + { + std::for_each(slot->WetBuffer, slot->WetBuffer+slot->NumChannels, + [SamplesToDo](ALfloat *buffer) -> void + { std::fill_n(buffer, SamplesToDo, 0.0f); } + ); + } + ); + + /* Process voices that have a playing source. */ + std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount, + [SamplesToDo,ctx](ALvoice *voice) -> void + { + ALsource *source{voice->Source.load(std::memory_order_acquire)}; + if(!source) return; + if(!voice->Playing.load(std::memory_order_relaxed) || voice->Step < 1) + return; + + if(!MixSource(voice, source->id, ctx, SamplesToDo)) + { + voice->Source.store(nullptr, std::memory_order_relaxed); + voice->Playing.store(false, std::memory_order_release); + SendSourceStoppedEvent(ctx, source->id); + } + } + ); + + /* Process effects. */ + std::for_each(auxslots->slot, auxslots->slot+auxslots->count, + [SamplesToDo](const ALeffectslot *slot) -> void + { + EffectState *state{slot->Params.mEffectState}; + state->process(SamplesToDo, slot->WetBuffer, state->mOutBuffer, + state->mOutChannels); + } + ); +} + void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*RESTRICT Buffer)[BUFFERSIZE], int lidx, int ridx, int cidx, ALsizei SamplesToDo, ALsizei NumChannels) @@ -1598,7 +1641,7 @@ void ApplyDistanceComp(ALfloat (*RESTRICT Samples)[BUFFERSIZE], const DistanceCo auto out = std::copy(distbuf+SamplesToDo, distbuf+base, distbuf); std::copy_n(inout, SamplesToDo, out); } - std::transform(Values, Values+SamplesToDo, inout, + std::transform(Values, Values+SamplesToDo, inout, [gain](ALfloat in) noexcept -> ALfloat { return in * gain; } ); @@ -1608,29 +1651,29 @@ void ApplyDistanceComp(ALfloat (*RESTRICT Samples)[BUFFERSIZE], const DistanceCo void ApplyDither(ALfloat (*RESTRICT Samples)[BUFFERSIZE], ALuint *dither_seed, const ALfloat quant_scale, const ALsizei SamplesToDo, const ALsizei numchans) { - const ALfloat invscale = 1.0f / quant_scale; - ALuint seed = *dither_seed; - ALsizei c, i; - ASSUME(numchans > 0); - ASSUME(SamplesToDo > 0); - /* Dithering. Step 1, generate whitenoise (uniform distribution of random - * values between -1 and +1). Step 2 is to add the noise to the samples, - * before rounding and after scaling up to the desired quantization depth. + /* Dithering. Generate whitenoise (uniform distribution of random values + * between -1 and +1) and add it to the sample values, after scaling up to + * the desired quantization depth amd before rounding. */ - for(c = 0;c < numchans;c++) + const ALfloat invscale = 1.0f / quant_scale; + ALuint seed = *dither_seed; + auto dither_channel = [&seed,invscale,quant_scale,SamplesToDo](ALfloat *buffer) -> void { - ALfloat *RESTRICT samples = Samples[c]; - for(i = 0;i < SamplesToDo;i++) - { - ALfloat val = samples[i] * quant_scale; - ALuint rng0 = dither_rng(&seed); - ALuint rng1 = dither_rng(&seed); - val += (ALfloat)(rng0*(1.0/UINT_MAX) - rng1*(1.0/UINT_MAX)); - samples[i] = fast_roundf(val) * invscale; - } - } + ASSUME(SamplesToDo > 0); + std::transform(buffer, buffer+SamplesToDo, buffer, + [&seed,invscale,quant_scale](ALfloat sample) noexcept -> ALfloat + { + ALfloat val = sample * quant_scale; + ALuint rng0 = dither_rng(&seed); + ALuint rng1 = dither_rng(&seed); + val += (ALfloat)(rng0*(1.0/UINT_MAX) - rng1*(1.0/UINT_MAX)); + return fast_roundf(val) * invscale; + } + ); + }; + std::for_each(Samples, Samples+numchans, dither_channel); *dither_seed = seed; } @@ -1639,11 +1682,11 @@ void ApplyDither(ALfloat (*RESTRICT Samples)[BUFFERSIZE], ALuint *dither_seed, * chokes on that given the inline specializations. */ template -inline T SampleConv(ALfloat); +inline T SampleConv(ALfloat) noexcept; -template<> inline ALfloat SampleConv(ALfloat val) +template<> inline ALfloat SampleConv(ALfloat val) noexcept { return val; } -template<> inline ALint SampleConv(ALfloat val) +template<> inline ALint SampleConv(ALfloat val) noexcept { /* Floats have a 23-bit mantissa. There is an implied 1 bit in the mantissa * along with the sign bit, giving 25 bits total, so [-16777216, +16777216] @@ -1652,17 +1695,17 @@ template<> inline ALint SampleConv(ALfloat val) */ return fastf2i(clampf(val*16777216.0f, -16777216.0f, 16777215.0f))<<7; } -template<> inline ALshort SampleConv(ALfloat val) +template<> inline ALshort SampleConv(ALfloat val) noexcept { return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); } -template<> inline ALbyte SampleConv(ALfloat val) +template<> inline ALbyte SampleConv(ALfloat val) noexcept { return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); } /* Define unsigned output variations. */ -template<> inline ALuint SampleConv(ALfloat val) +template<> inline ALuint SampleConv(ALfloat val) noexcept { return SampleConv(val) + 2147483648u; } -template<> inline ALushort SampleConv(ALfloat val) +template<> inline ALushort SampleConv(ALfloat val) noexcept { return SampleConv(val) + 32768; } -template<> inline ALubyte SampleConv(ALfloat val) +template<> inline ALubyte SampleConv(ALfloat val) noexcept { return SampleConv(val) + 128; } template @@ -1672,102 +1715,70 @@ void Write(const ALfloat (*RESTRICT InBuffer)[BUFFERSIZE], ALvoid *OutBuffer, using SampleType = typename DevFmtTypeTraits::Type; ASSUME(numchans > 0); - ASSUME(SamplesToDo > 0); - - for(ALsizei j{0};j < numchans;j++) + SampleType *outbase = static_cast(OutBuffer) + Offset*numchans; + auto conv_channel = [&outbase,SamplesToDo,numchans](const ALfloat *inbuf) -> void { - const ALfloat *RESTRICT in = InBuffer[j]; - SampleType *RESTRICT out = static_cast(OutBuffer) + Offset*numchans + j; - - for(ALsizei i{0};i < SamplesToDo;i++) - out[i*numchans] = SampleConv(in[i]); - } + ASSUME(SamplesToDo > 0); + SampleType *out{outbase++}; + std::for_each(inbuf, inbuf+SamplesToDo, + [numchans,&out](const ALfloat s) noexcept -> void + { + *out = SampleConv(s); + out += numchans; + } + ); + }; + std::for_each(InBuffer, InBuffer+numchans, conv_channel); } } // namespace void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) { - ALsizei SamplesToDo; - ALsizei SamplesDone; - ALCcontext *ctx; - ALsizei i, c; - FPUCtl mixer_mode{}; - for(SamplesDone = 0;SamplesDone < NumSamples;) + for(ALsizei SamplesDone{0};SamplesDone < NumSamples;) { - SamplesToDo = mini(NumSamples-SamplesDone, BUFFERSIZE); - for(c = 0;c < device->Dry.NumChannels;c++) - memset(device->Dry.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); - if(device->Dry.Buffer != device->FOAOut.Buffer) - for(c = 0;c < device->FOAOut.NumChannels;c++) - memset(device->FOAOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); - if(device->Dry.Buffer != device->RealOut.Buffer) - for(c = 0;c < device->RealOut.NumChannels;c++) - memset(device->RealOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); + const ALsizei SamplesToDo{mini(NumSamples-SamplesDone, BUFFERSIZE)}; + + /* Clear main mixing buffers. */ + std::for_each(device->MixBuffer.begin(), device->MixBuffer.end(), + [SamplesToDo](std::array &buffer) -> void + { std::fill_n(buffer.begin(), SamplesToDo, 0.0f); } + ); + /* Increment the mix count at the start (lsb should now be 1). */ IncrementRef(&device->MixCount); - ctx = ATOMIC_LOAD(&device->ContextList, almemory_order_acquire); + /* For each context on this device, process and mix its sources and + * effects. + */ + ALCcontext *ctx{device->ContextList.load(std::memory_order_acquire)}; while(ctx) { - const struct ALeffectslotArray *auxslots; - - auxslots = ATOMIC_LOAD(&ctx->ActiveAuxSlots, almemory_order_acquire); - ProcessParamUpdates(ctx, auxslots); - - for(i = 0;i < auxslots->count;i++) - { - ALeffectslot *slot = auxslots->slot[i]; - for(c = 0;c < slot->NumChannels;c++) - memset(slot->WetBuffer[c], 0, SamplesToDo*sizeof(ALfloat)); - } + ProcessContext(ctx, SamplesToDo); - /* source processing */ - for(i = 0;i < ctx->VoiceCount;i++) - { - ALvoice *voice = ctx->Voices[i]; - ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire); - if(source && ATOMIC_LOAD(&voice->Playing, almemory_order_relaxed) && - voice->Step > 0) - { - if(!MixSource(voice, source->id, ctx, SamplesToDo)) - { - ATOMIC_STORE(&voice->Source, static_cast(nullptr), - almemory_order_relaxed); - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - SendSourceStoppedEvent(ctx, source->id); - } - } - } - - /* effect slot processing */ - for(i = 0;i < auxslots->count;i++) - { - const ALeffectslot *slot = auxslots->slot[i]; - EffectState *state = slot->Params.mEffectState; - state->process(SamplesToDo, slot->WetBuffer, state->mOutBuffer, - state->mOutChannels); - } - - ctx = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed); + ctx = ctx->next.load(std::memory_order_relaxed); } /* Increment the clock time. Every second's worth of samples is * converted and added to clock base so that large sample counts don't - * overflow during conversion. This also guarantees an exact, stable - * conversion. */ + * overflow during conversion. This also guarantees a stable + * conversion. + */ device->SamplesDone += SamplesToDo; device->ClockBase += std::chrono::seconds{device->SamplesDone / device->Frequency}; device->SamplesDone %= device->Frequency; + + /* Increment the mix count at the end (lsb should now be 0). */ IncrementRef(&device->MixCount); - /* Apply post-process for finalizing the Dry mix to the RealOut - * (Ambisonic decode, UHJ encode, etc). + /* Apply any needed post-process for finalizing the Dry mix to the + * RealOut (Ambisonic decode, UHJ encode, etc). */ if(LIKELY(device->PostProcess)) device->PostProcess(device, SamplesToDo); + /* Apply front image stablization for surround sound, if applicable. */ if(device->Stablizer) { int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); @@ -1779,12 +1790,17 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) SamplesToDo, device->RealOut.NumChannels); } + /* Apply delays and attenuation for mismatched speaker distances. */ ApplyDistanceComp(device->RealOut.Buffer, device->ChannelDelay, device->TempBuffer[0], SamplesToDo, device->RealOut.NumChannels); + /* Apply compression, limiting final sample amplitude, if desired. */ if(device->Limiter) ApplyCompression(device->Limiter.get(), SamplesToDo, device->RealOut.Buffer); + /* Apply dithering. The compressor should have left enough headroom for + * the dither noise to not saturate. + */ if(device->DitherDepth > 0.0f) ApplyDither(device->RealOut.Buffer, &device->DitherSeed, device->DitherDepth, SamplesToDo, device->RealOut.NumChannels); @@ -1794,6 +1810,9 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) ALfloat (*Buffer)[BUFFERSIZE] = device->RealOut.Buffer; ALsizei Channels = device->RealOut.NumChannels; + /* Finally, interleave and convert samples, writing to the device's + * output buffer. + */ switch(device->FmtType) { #define HANDLE_WRITE(T) case T: \ @@ -1816,50 +1835,46 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) { - AsyncEvent evt = ASYNC_EVENT(EventType_Disconnected); - ALCcontext *ctx; - va_list args; - int msglen; - if(!device->Connected.exchange(AL_FALSE, std::memory_order_acq_rel)) return; + AsyncEvent evt = ASYNC_EVENT(EventType_Disconnected); evt.u.user.type = AL_EVENT_TYPE_DISCONNECTED_SOFT; evt.u.user.id = 0; evt.u.user.param = 0; + va_list args; va_start(args, msg); - msglen = vsnprintf(evt.u.user.msg, sizeof(evt.u.user.msg), msg, args); + int msglen{vsnprintf(evt.u.user.msg, sizeof(evt.u.user.msg), msg, args)}; va_end(args); if(msglen < 0 || (size_t)msglen >= sizeof(evt.u.user.msg)) evt.u.user.msg[sizeof(evt.u.user.msg)-1] = 0; - ctx = ATOMIC_LOAD_SEQ(&device->ContextList); + ALCcontext *ctx{device->ContextList.load()}; while(ctx) { - ALbitfieldSOFT enabledevt = ATOMIC_LOAD(&ctx->EnabledEvts, almemory_order_acquire); - ALsizei i; - + ALbitfieldSOFT enabledevt = ctx->EnabledEvts.load(std::memory_order_acquire); if((enabledevt&EventType_Disconnected) && ll_ringbuffer_write(ctx->AsyncEvents, &evt, 1) == 1) alsem_post(&ctx->EventSem); - for(i = 0;i < ctx->VoiceCount;i++) - { - ALvoice *voice = ctx->Voices[i]; - ALsource *source = voice->Source.exchange(nullptr, std::memory_order_relaxed); - if(source && voice->Playing.load(std::memory_order_relaxed)) + std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount, + [ctx](ALvoice *voice) -> void { - /* If the source's voice was playing, it's now effectively - * stopped (the source state will be updated the next time it's - * checked). - */ - SendSourceStoppedEvent(ctx, source->id); + ALsource *source{voice->Source.exchange(nullptr, std::memory_order_relaxed)}; + if(source && voice->Playing.load(std::memory_order_relaxed)) + { + /* If the source's voice was playing, it's now effectively + * stopped (the source state will be updated the next time + * it's checked). + */ + SendSourceStoppedEvent(ctx, source->id); + } + voice->Playing.store(false, std::memory_order_release); } - voice->Playing.store(false, std::memory_order_release); - } + ); - ctx = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed); + ctx = ctx->next.load(std::memory_order_relaxed); } } -- cgit v1.2.3 From 73528c9f550c7df6b1e0f2b54e61c02bf7eac00a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 23 Nov 2018 14:42:02 -0800 Subject: Fix an incorrect check --- OpenAL32/alSource.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index df2de67c..30629c29 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -2890,7 +2890,7 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) { ALsource *source{LookupSource(context.get(), sources[i])}; ALvoice *voice{GetSourceVoice(source, context.get())}; - if(!voice) voice->Playing.store(false, std::memory_order_release); + if(voice) voice->Playing.store(false, std::memory_order_release); if(GetSourceState(source, voice) == AL_PLAYING) { source->state = AL_PAUSED; -- cgit v1.2.3 From df057d41181b8acc83cb8f64a7dc118b771f9198 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 23 Nov 2018 16:16:31 -0800 Subject: Make the context VoiceCount atomic --- Alc/alc.cpp | 98 ++++++++++++++++++++++++--------------------------- Alc/alcontext.h | 2 +- Alc/alu.cpp | 6 ++-- OpenAL32/alSource.cpp | 59 +++++++++++++++---------------- 4 files changed, 79 insertions(+), 86 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index a8ea1c53..9fcf028a 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1711,7 +1711,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ALCsizei hrtf_id = -1; ALCcontext *context; ALCuint oldFreq; - ALCsizei i; int val; // Check for attributes @@ -2248,9 +2247,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) context = device->ContextList.load(); while(context) { - struct ALvoiceProps *vprops; - ALsizei pos; - if(context->DefaultSlot) { ALeffectslot *slot = context->DefaultSlot.get(); @@ -2320,7 +2316,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) * auxiliary sends is changing. Active sources will have updates * respecified in UpdateAllSourceProps. */ - vprops = context->FreeVoiceProps.exchange(nullptr, std::memory_order_acq_rel); + ALvoiceProps *vprops{context->FreeVoiceProps.exchange(nullptr, std::memory_order_acq_rel)}; while(vprops) { struct ALvoiceProps *next = vprops->next.load(std::memory_order_relaxed); @@ -2329,24 +2325,27 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } AllocateVoices(context, context->MaxVoices, old_sends); - for(pos = 0;pos < context->VoiceCount;pos++) - { - ALvoice *voice = context->Voices[pos]; - - al_free(voice->Update.exchange(nullptr, std::memory_order_acq_rel)); + auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed); + std::for_each(context->Voices, voices_end, + [device](ALvoice *voice) -> void + { + al_free(voice->Update.exchange(nullptr, std::memory_order_acq_rel)); - if(voice->Source.load(std::memory_order_acquire) == nullptr) - continue; + if(voice->Source.load(std::memory_order_acquire) == nullptr) + return; - if(device->AvgSpeakerDist > 0.0f) - { - /* Reinitialize the NFC filters for new parameters. */ - ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / - (device->AvgSpeakerDist * device->Frequency); - for(i = 0;i < voice->NumChannels;i++) - NfcFilterCreate(&voice->Direct.Params[i].NFCtrlFilter, 0.0f, w1); + if(device->AvgSpeakerDist > 0.0f) + { + /* Reinitialize the NFC filters for new parameters. */ + ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / + (device->AvgSpeakerDist * device->Frequency); + std::for_each(voice->Direct.Params, voice->Direct.Params+voice->NumChannels, + [w1](DirectParams ¶ms) -> void + { NfcFilterCreate(¶ms.NFCtrlFilter, 0.0f, w1); } + ); + } } - } + ); srclock.unlock(); context->PropsClean.test_and_set(std::memory_order_release); @@ -2592,11 +2591,12 @@ ALCcontext_struct::~ALCcontext_struct() } TRACE("Freed " SZFMT " voice property object%s\n", count, (count==1)?"":"s"); - for(ALsizei i{0};i < VoiceCount;i++) - DeinitVoice(Voices[i]); + std::for_each(Voices, Voices + VoiceCount.load(std::memory_order_relaxed), + [](ALvoice *voice) -> void { DeinitVoice(voice); } + ); al_free(Voices); Voices = nullptr; - VoiceCount = 0; + VoiceCount.store(0, std::memory_order_relaxed); MaxVoices = 0; struct ALlistenerProps *lprops{Listener.Update.load(std::memory_order_relaxed)}; @@ -2747,15 +2747,8 @@ ALCcontext *GetContextRef(void) void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) { - ALCdevice *device = context->Device; - ALsizei num_sends = device->NumAuxSends; - struct ALvoiceProps *props; - size_t sizeof_props; - size_t sizeof_voice; - ALvoice **voices; - ALvoice *voice; - ALsizei v = 0; - size_t size; + ALCdevice *device{context->Device}; + ALsizei num_sends{device->NumAuxSends}; if(num_voices == context->MaxVoices && num_sends == old_sends) return; @@ -2764,53 +2757,54 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) * property set (including the dynamically-sized Send[] array) in one * chunk. */ - sizeof_voice = RoundUp(FAM_SIZE(ALvoice, Send, num_sends), 16); - sizeof_props = RoundUp(FAM_SIZE(struct ALvoiceProps, Send, num_sends), 16); - size = sizeof(ALvoice*) + sizeof_voice + sizeof_props; + size_t sizeof_voice{RoundUp(FAM_SIZE(ALvoice, Send, num_sends), 16)}; + size_t sizeof_props{RoundUp(FAM_SIZE(struct ALvoiceProps, Send, num_sends), 16)}; + size_t size{sizeof(ALvoice*) + sizeof_voice + sizeof_props}; - voices = static_cast(al_calloc(16, RoundUp(size*num_voices, 16))); + auto voices = static_cast(al_calloc(16, RoundUp(size*num_voices, 16))); /* The voice and property objects are stored interleaved since they're * paired together. */ - voice = (ALvoice*)((char*)voices + RoundUp(num_voices*sizeof(ALvoice*), 16)); - props = (struct ALvoiceProps*)((char*)voice + sizeof_voice); + auto voice = reinterpret_cast((char*)voices + RoundUp(num_voices*sizeof(ALvoice*), 16)); + auto props = reinterpret_cast((char*)voice + sizeof_voice); + ALsizei v{0}; if(context->Voices) { - const ALsizei v_count = mini(context->VoiceCount, num_voices); + const ALsizei v_count = mini(context->VoiceCount.load(std::memory_order_relaxed), + num_voices); const ALsizei s_count = mini(old_sends, num_sends); for(;v < v_count;v++) { - ALvoice *old_voice = context->Voices[v]; - ALsizei i; + ALvoice *old_voice{context->Voices[v]}; /* Copy the old voice data and source property set to the new * storage. */ memcpy(voice, old_voice, sizeof(*voice)); - for(i = 0;i < s_count;i++) - voice->Send[i] = old_voice->Send[i]; + std::copy_n(old_voice->Send, s_count, voice->Send); memcpy(props, old_voice->Props, sizeof(*props)); - for(i = 0;i < s_count;i++) - props->Send[i] = old_voice->Props->Send[i]; + std::copy_n(old_voice->Props->Send, s_count, props->Send); /* Set this voice's property set pointer and voice reference. */ voice->Props = props; voices[v] = voice; /* Increment pointers to the next storage space. */ - voice = (ALvoice*)((char*)props + sizeof_props); - props = (struct ALvoiceProps*)((char*)voice + sizeof_voice); + voice = reinterpret_cast((char*)props + sizeof_props); + props = reinterpret_cast((char*)voice + sizeof_voice); } /* Deinit any left over voices that weren't copied over to the new * array. NOTE: If this does anything, v equals num_voices and * num_voices is less than VoiceCount, so the following loop won't do * anything. */ - for(;v < context->VoiceCount;v++) - DeinitVoice(context->Voices[v]); + auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed); + std::for_each(context->Voices + v, voices_end, + [](ALvoice *voice) -> void { DeinitVoice(voice); } + ); } /* Finish setting the voices' property set pointers and references. */ for(;v < num_voices;v++) @@ -2820,14 +2814,14 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) voice->Props = props; voices[v] = voice; - voice = (ALvoice*)((char*)props + sizeof_props); - props = (struct ALvoiceProps*)((char*)voice + sizeof_voice); + voice = reinterpret_cast((char*)props + sizeof_props); + props = reinterpret_cast((char*)voice + sizeof_voice); } al_free(context->Voices); context->Voices = voices; context->MaxVoices = num_voices; - context->VoiceCount = mini(context->VoiceCount, num_voices); + context->VoiceCount = mini(context->VoiceCount.load(std::memory_order_relaxed), num_voices); } diff --git a/Alc/alcontext.h b/Alc/alcontext.h index c9cfa985..9845b686 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -95,7 +95,7 @@ struct ALCcontext_struct { ATOMIC(ALeffectslotProps*) FreeEffectslotProps{nullptr}; ALvoice **Voices{nullptr}; - ALsizei VoiceCount{0}; + std::atomic VoiceCount{0}; ALsizei MaxVoices{0}; ATOMIC(ALeffectslotArray*) ActiveAuxSlots{nullptr}; diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 71823bf7..5036ae24 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1503,7 +1503,7 @@ void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray *slots) { force |= CalcEffectSlotParams(slot, ctx, cforce); } ); - std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount, + std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire), [ctx,force](ALvoice *voice) -> void { ALsource *source{voice->Source.load(std::memory_order_acquire)}; @@ -1533,7 +1533,7 @@ void ProcessContext(ALCcontext *ctx, ALsizei SamplesToDo) ); /* Process voices that have a playing source. */ - std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount, + std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire), [SamplesToDo,ctx](ALvoice *voice) -> void { ALsource *source{voice->Source.load(std::memory_order_acquire)}; @@ -1859,7 +1859,7 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) ll_ringbuffer_write(ctx->AsyncEvents, &evt, 1) == 1) alsem_post(&ctx->EventSem); - std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount, + std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire), [ctx](ALvoice *voice) -> void { ALsource *source{voice->Source.exchange(nullptr, std::memory_order_relaxed)}; diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 30629c29..8ee94600 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -51,7 +51,7 @@ namespace { inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) { ALint idx{source->VoiceIdx}; - if(idx >= 0 && idx < context->VoiceCount) + if(idx >= 0 && idx < context->VoiceCount.load(std::memory_order_relaxed)) { ALvoice *voice{context->Voices[idx]}; if(voice->Source.load(std::memory_order_acquire) == source) @@ -2725,7 +2725,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) return; } - while(n > context->MaxVoices-context->VoiceCount) + while(n > context->MaxVoices-context->VoiceCount.load(std::memory_order_relaxed)) { ALsizei newcount = context->MaxVoices << 1; if(context->MaxVoices >= newcount) @@ -2790,19 +2790,15 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) /* Look for an unused voice to play this source with. */ assert(voice == nullptr); - ALint vidx{-1}; - for(ALsizei j{0};j < context->VoiceCount;j++) - { - if(context->Voices[j]->Source.load(std::memory_order_acquire) == nullptr) - { - vidx = j; - break; - } - } - if(vidx == -1) - vidx = context->VoiceCount++; - voice = context->Voices[vidx]; + auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed); + auto voice_iter = std::find_if(context->Voices, voices_end, + [](const ALvoice *voice) noexcept -> bool + { return voice->Source.load(std::memory_order_relaxed) == nullptr; } + ); + auto vidx = static_cast(std::distance(context->Voices, voice_iter)); + voice = *voice_iter; voice->Playing.store(false, std::memory_order_release); + if(voice_iter == voices_end) context->VoiceCount.fetch_add(1, std::memory_order_acq_rel); source->PropsClean.test_and_set(std::memory_order_acquire); UpdateSourceProps(source, voice, context.get()); @@ -2823,19 +2819,20 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) voice->position_fraction.load(std::memory_order_relaxed) != 0 || voice->current_buffer.load(std::memory_order_relaxed) != BufferList; - for(ALsizei j{0};j < BufferList->num_buffers;j++) + auto buffers_end = BufferList->buffers + BufferList->num_buffers; + auto buffer = std::find_if(BufferList->buffers, buffers_end, + [](const ALbuffer *buffer) noexcept -> bool + { return buffer != nullptr; } + ); + if(buffer != buffers_end) { - ALbuffer *buffer = BufferList->buffers[j]; - if(buffer) - { - voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels); - voice->SampleSize = BytesFromFmt(buffer->FmtType); - break; - } + voice->NumChannels = ChannelsFromFmt((*buffer)->FmtChannels); + voice->SampleSize = BytesFromFmt((*buffer)->FmtType); } /* Clear previous samples. */ - memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples)); + for(auto &samples : voice->PrevSamples) + std::fill(std::begin(samples), std::end(samples), 0.0f); /* Clear the stepping value so the mixer knows not to mix this until * the update gets applied. @@ -3399,13 +3396,15 @@ ALsource::~ALsource() void UpdateAllSourceProps(ALCcontext *context) { - for(ALsizei i{0};i < context->VoiceCount;++i) - { - ALvoice *voice{context->Voices[i]}; - ALsource *source{voice->Source.load(std::memory_order_acquire)}; - if(source && !source->PropsClean.test_and_set(std::memory_order_acq_rel)) - UpdateSourceProps(source, voice, context); - } + auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed); + std::for_each(context->Voices, voices_end, + [context](ALvoice *voice) -> void + { + ALsource *source{voice->Source.load(std::memory_order_acquire)}; + if(source && !source->PropsClean.test_and_set(std::memory_order_acq_rel)) + UpdateSourceProps(source, voice, context); + } + ); } /* ReleaseALSources -- cgit v1.2.3 From a7c556f814fdb5c638a969a2ca4e309e0927c615 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 23 Nov 2018 17:54:12 -0800 Subject: Use RAII for device references --- Alc/alc.cpp | 468 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 232 insertions(+), 236 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 9fcf028a..a53269cd 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2427,39 +2427,82 @@ ALCdevice_struct::~ALCdevice_struct() } -void ALCdevice_IncRef(ALCdevice *device) +static void ALCdevice_IncRef(ALCdevice *device) { auto ref = IncrementRef(&device->ref); TRACEREF("%p increasing refcount to %u\n", device, ref); } -void ALCdevice_DecRef(ALCdevice *device) +static void ALCdevice_DecRef(ALCdevice *device) { auto ref = DecrementRef(&device->ref); TRACEREF("%p decreasing refcount to %u\n", device, ref); if(ref == 0) delete device; } +/* Simple RAII device reference. Takes the reference of the provided ALCdevice, + * and decrements it when leaving scope. Movable (transfer reference) but not + * copyable (no new references). + */ +class DeviceRef { + ALCdevice *mDev{nullptr}; + + void reset() noexcept + { + if(mDev) + ALCdevice_DecRef(mDev); + mDev = nullptr; + } + +public: + DeviceRef() noexcept = default; + DeviceRef(DeviceRef&& rhs) noexcept : mDev{rhs.mDev} + { rhs.mDev = nullptr; } + explicit DeviceRef(ALCdevice *dev) noexcept : mDev(dev) { } + ~DeviceRef() { reset(); } + + DeviceRef& operator=(const DeviceRef&) = delete; + DeviceRef& operator=(DeviceRef&& rhs) noexcept + { + reset(); + mDev = rhs.mDev; + rhs.mDev = nullptr; + return *this; + } + + operator bool() const noexcept { return mDev != nullptr; } + + ALCdevice* operator->() noexcept { return mDev; } + ALCdevice* get() noexcept { return mDev; } + + ALCdevice* release() noexcept + { + ALCdevice *ret{mDev}; + mDev = nullptr; + return ret; + } +}; + + /* VerifyDevice * - * Checks if the device handle is valid, and increments its ref count if so. + * Checks if the device handle is valid, and returns a new reference if so. */ -static ALCboolean VerifyDevice(ALCdevice **device) +static DeviceRef VerifyDevice(ALCdevice *device) { std::lock_guard _{ListLock}; ALCdevice *tmpDevice{DeviceList.load()}; while(tmpDevice) { - if(tmpDevice == *device) + if(tmpDevice == device) { ALCdevice_IncRef(tmpDevice); - return ALC_TRUE; + return DeviceRef{tmpDevice}; } tmpDevice = tmpDevice->next.load(std::memory_order_relaxed); } - *device = nullptr; - return ALC_FALSE; + return DeviceRef{}; } @@ -2832,20 +2875,12 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) /* alcGetError * * Return last ALC generated error code for the given device -*/ + */ ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) { - ALCenum errorCode; - - if(VerifyDevice(&device)) - { - errorCode = device->LastError.exchange(ALC_NO_ERROR); - ALCdevice_DecRef(device); - } - else - errorCode = LastNullDeviceError.exchange(ALC_NO_ERROR); - - return errorCode; + DeviceRef dev{VerifyDevice(device)}; + if(dev) return dev->LastError.exchange(ALC_NO_ERROR); + return LastNullDeviceError.exchange(ALC_NO_ERROR); } @@ -2889,6 +2924,7 @@ ALC_API ALCvoid ALC_APIENTRY alcProcessContext(ALCcontext *context) ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum param) { const ALCchar *value = nullptr; + DeviceRef dev; switch(param) { @@ -2921,11 +2957,9 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para break; case ALC_ALL_DEVICES_SPECIFIER: - if(VerifyDevice(&Device)) - { - value = Device->DeviceName.c_str(); - ALCdevice_DecRef(Device); - } + dev = VerifyDevice(Device); + if(dev) + value = dev->DeviceName.c_str(); else { ProbeAllDevicesList(); @@ -2934,11 +2968,9 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para break; case ALC_CAPTURE_DEVICE_SPECIFIER: - if(VerifyDevice(&Device)) - { - value = Device->DeviceName.c_str(); - ALCdevice_DecRef(Device); - } + dev = VerifyDevice(Device); + if(dev) + value = dev->DeviceName.c_str(); else { ProbeCaptureDeviceList(); @@ -2970,31 +3002,25 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para break; case ALC_EXTENSIONS: - if(!VerifyDevice(&Device)) - value = alcNoDeviceExtList; - else - { - value = alcExtensionList; - ALCdevice_DecRef(Device); - } + dev = VerifyDevice(Device); + if(dev) value = alcExtensionList; + else value = alcNoDeviceExtList; break; case ALC_HRTF_SPECIFIER_SOFT: - if(!VerifyDevice(&Device)) + dev = VerifyDevice(Device); + if(!dev) alcSetError(nullptr, ALC_INVALID_DEVICE); else { - { std::lock_guard _{Device->BackendLock}; - value = (Device->HrtfHandle ? Device->HrtfName.c_str() : ""); - } - ALCdevice_DecRef(Device); + std::lock_guard _{dev->BackendLock}; + value = (dev->HrtfHandle ? dev->HrtfName.c_str() : ""); } break; default: - VerifyDevice(&Device); - alcSetError(Device, ALC_INVALID_ENUM); - if(Device) ALCdevice_DecRef(Device); + dev = VerifyDevice(Device); + alcSetError(dev.get(), ALC_INVALID_ENUM); break; } @@ -3324,23 +3350,22 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC */ ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) { - VerifyDevice(&device); + DeviceRef dev{VerifyDevice(device)}; if(size <= 0 || values == nullptr) - alcSetError(device, ALC_INVALID_VALUE); + alcSetError(dev.get(), ALC_INVALID_VALUE); else - GetIntegerv(device, param, size, values); - if(device) ALCdevice_DecRef(device); + GetIntegerv(dev.get(), param, size, values); } ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALCsizei size, ALCint64SOFT *values) { - VerifyDevice(&device); + DeviceRef dev{VerifyDevice(device)}; if(size <= 0 || values == nullptr) - alcSetError(device, ALC_INVALID_VALUE); - else if(!device || device->Type == Capture) + alcSetError(dev.get(), ALC_INVALID_VALUE); + else if(!dev || dev->Type == Capture) { std::vector ivals(size); - size = GetIntegerv(device, pname, size, ivals.data()); + size = GetIntegerv(dev.get(), pname, size, ivals.data()); std::copy(ivals.begin(), ivals.begin()+size, values); } else /* render device */ @@ -3348,67 +3373,67 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, switch(pname) { case ALC_ATTRIBUTES_SIZE: - *values = NumAttrsForDevice(device)+4; + *values = NumAttrsForDevice(dev.get())+4; break; case ALC_ALL_ATTRIBUTES: - if(size < NumAttrsForDevice(device)+4) - alcSetError(device, ALC_INVALID_VALUE); + if(size < NumAttrsForDevice(dev.get())+4) + alcSetError(dev.get(), ALC_INVALID_VALUE); else { ALsizei i{0}; - std::lock_guard _{device->BackendLock}; + std::lock_guard _{dev->BackendLock}; values[i++] = ALC_FREQUENCY; - values[i++] = device->Frequency; + values[i++] = dev->Frequency; - if(device->Type != Loopback) + if(dev->Type != Loopback) { values[i++] = ALC_REFRESH; - values[i++] = device->Frequency / device->UpdateSize; + values[i++] = dev->Frequency / dev->UpdateSize; values[i++] = ALC_SYNC; values[i++] = ALC_FALSE; } else { - if(device->FmtChans == DevFmtAmbi3D) + if(dev->FmtChans == DevFmtAmbi3D) { values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; - values[i++] = static_cast(device->mAmbiLayout); + values[i++] = static_cast(dev->mAmbiLayout); values[i++] = ALC_AMBISONIC_SCALING_SOFT; - values[i++] = static_cast(device->mAmbiScale); + values[i++] = static_cast(dev->mAmbiScale); values[i++] = ALC_AMBISONIC_ORDER_SOFT; - values[i++] = device->mAmbiOrder; + values[i++] = dev->mAmbiOrder; } values[i++] = ALC_FORMAT_CHANNELS_SOFT; - values[i++] = device->FmtChans; + values[i++] = dev->FmtChans; values[i++] = ALC_FORMAT_TYPE_SOFT; - values[i++] = device->FmtType; + values[i++] = dev->FmtType; } values[i++] = ALC_MONO_SOURCES; - values[i++] = device->NumMonoSources; + values[i++] = dev->NumMonoSources; values[i++] = ALC_STEREO_SOURCES; - values[i++] = device->NumStereoSources; + values[i++] = dev->NumStereoSources; values[i++] = ALC_MAX_AUXILIARY_SENDS; - values[i++] = device->NumAuxSends; + values[i++] = dev->NumAuxSends; values[i++] = ALC_HRTF_SOFT; - values[i++] = (device->HrtfHandle ? ALC_TRUE : ALC_FALSE); + values[i++] = (dev->HrtfHandle ? ALC_TRUE : ALC_FALSE); values[i++] = ALC_HRTF_STATUS_SOFT; - values[i++] = device->HrtfStatus; + values[i++] = dev->HrtfStatus; values[i++] = ALC_OUTPUT_LIMITER_SOFT; - values[i++] = device->Limiter ? ALC_TRUE : ALC_FALSE; + values[i++] = dev->Limiter ? ALC_TRUE : ALC_FALSE; - ClockLatency clock{GetClockLatency(device)}; + ClockLatency clock{GetClockLatency(dev.get())}; values[i++] = ALC_DEVICE_CLOCK_SOFT; values[i++] = clock.ClockTime.count(); @@ -3420,35 +3445,39 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, break; case ALC_DEVICE_CLOCK_SOFT: - { std::lock_guard _{device->BackendLock}; - std::chrono::nanoseconds basecount; + { std::lock_guard _{dev->BackendLock}; + using std::chrono::seconds; + using std::chrono::nanoseconds; + using std::chrono::duration_cast; + + nanoseconds basecount; ALuint samplecount; ALuint refcount; do { - while(((refcount=ReadRef(&device->MixCount))&1) != 0) + while(((refcount=ReadRef(&dev->MixCount))&1) != 0) althrd_yield(); - basecount = device->ClockBase; - samplecount = device->SamplesDone; - } while(refcount != ReadRef(&device->MixCount)); - *values = (basecount + std::chrono::duration_cast( - std::chrono::seconds{samplecount}) / device->Frequency).count(); + basecount = dev->ClockBase; + samplecount = dev->SamplesDone; + } while(refcount != ReadRef(&dev->MixCount)); + *values = (duration_cast(seconds{samplecount})/dev->Frequency + + basecount).count(); } break; case ALC_DEVICE_LATENCY_SOFT: - { std::lock_guard _{device->BackendLock}; - ClockLatency clock{GetClockLatency(device)}; + { std::lock_guard _{dev->BackendLock}; + ClockLatency clock{GetClockLatency(dev.get())}; *values = clock.Latency.count(); } break; case ALC_DEVICE_CLOCK_LATENCY_SOFT: if(size < 2) - alcSetError(device, ALC_INVALID_VALUE); + alcSetError(dev.get(), ALC_INVALID_VALUE); else { - std::lock_guard _{device->BackendLock}; - ClockLatency clock{GetClockLatency(device)}; + std::lock_guard _{dev->BackendLock}; + ClockLatency clock{GetClockLatency(dev.get())}; values[0] = clock.ClockTime.count(); values[1] = clock.Latency.count(); } @@ -3456,13 +3485,11 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, default: std::vector ivals(size); - size = GetIntegerv(device, pname, size, ivals.data()); + size = GetIntegerv(dev.get(), pname, size, ivals.data()); std::copy(ivals.begin(), ivals.begin()+size, values); break; } } - if(device) - ALCdevice_DecRef(device); } @@ -3472,24 +3499,19 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, */ ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extName) { - ALCboolean bResult = ALC_FALSE; - - VerifyDevice(&device); - + DeviceRef dev{VerifyDevice(device)}; if(!extName) - alcSetError(device, ALC_INVALID_VALUE); + alcSetError(dev.get(), ALC_INVALID_VALUE); else { size_t len = strlen(extName); - const char *ptr = (device ? alcExtensionList : alcNoDeviceExtList); + const char *ptr = (dev ? alcExtensionList : alcNoDeviceExtList); while(ptr && *ptr) { if(strncasecmp(ptr, extName, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len]))) - { - bResult = ALC_TRUE; - break; - } + return ALC_TRUE; + if((ptr=strchr(ptr, ' ')) != nullptr) { do { @@ -3498,9 +3520,7 @@ ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const A } } } - if(device) - ALCdevice_DecRef(device); - return bResult; + return ALC_FALSE; } @@ -3510,13 +3530,10 @@ ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const A */ ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcName) { - ALCvoid *ptr = nullptr; - if(!funcName) { - VerifyDevice(&device); - alcSetError(device, ALC_INVALID_VALUE); - if(device) ALCdevice_DecRef(device); + DeviceRef dev{VerifyDevice(device)}; + alcSetError(dev.get(), ALC_INVALID_VALUE); } else { @@ -3524,14 +3541,11 @@ ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar for(i = 0;i < COUNTOF(alcFunctions);i++) { if(strcmp(alcFunctions[i].funcName, funcName) == 0) - { - ptr = alcFunctions[i].address; - break; - } + return alcFunctions[i].address; } } - return ptr; + return nullptr; } @@ -3541,13 +3555,10 @@ ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar */ ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumName) { - ALCenum val = 0; - if(!enumName) { - VerifyDevice(&device); - alcSetError(device, ALC_INVALID_VALUE); - if(device) ALCdevice_DecRef(device); + DeviceRef dev{VerifyDevice(device)}; + alcSetError(dev.get(), ALC_INVALID_VALUE); } else { @@ -3555,14 +3566,11 @@ ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *e for(i = 0;i < COUNTOF(alcEnumerations);i++) { if(strcmp(alcEnumerations[i].enumName, enumName) == 0) - { - val = alcEnumerations[i].value; - break; - } + return alcEnumerations[i].value; } } - return val; + return 0; } @@ -3581,42 +3589,40 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin * properly cleaned up after being made. */ std::unique_lock listlock{ListLock}; - if(!VerifyDevice(&device) || device->Type == Capture || - !device->Connected.load(std::memory_order_relaxed)) + DeviceRef dev{VerifyDevice(device)}; + if(!dev || dev->Type == Capture || !dev->Connected.load(std::memory_order_relaxed)) { listlock.unlock(); - alcSetError(device, ALC_INVALID_DEVICE); - if(device) ALCdevice_DecRef(device); + alcSetError(dev.get(), ALC_INVALID_DEVICE); return nullptr; } - std::unique_lock backlock{device->BackendLock}; + std::unique_lock backlock{dev->BackendLock}; listlock.unlock(); - device->LastError.store(ALC_NO_ERROR); + dev->LastError.store(ALC_NO_ERROR); - ALContext = new ALCcontext{device}; + ALContext = new ALCcontext{dev.get()}; ALCdevice_IncRef(ALContext->Device); - if((err=UpdateDeviceParams(device, attrList)) != ALC_NO_ERROR) + if((err=UpdateDeviceParams(dev.get(), attrList)) != ALC_NO_ERROR) { backlock.unlock(); delete ALContext; ALContext = nullptr; - alcSetError(device, err); + alcSetError(dev.get(), err); if(err == ALC_INVALID_DEVICE) { - V0(device->Backend,lock)(); - aluHandleDisconnect(device, "Device update failure"); - V0(device->Backend,unlock)(); + V0(dev->Backend,lock)(); + aluHandleDisconnect(dev.get(), "Device update failure"); + V0(dev->Backend,unlock)(); } - ALCdevice_DecRef(device); return nullptr; } - AllocateVoices(ALContext, 256, device->NumAuxSends); + AllocateVoices(ALContext, 256, dev->NumAuxSends); - if(DefaultEffect.type != AL_EFFECT_NULL && device->Type == Playback) + if(DefaultEffect.type != AL_EFFECT_NULL && dev->Type == Playback) { ALContext->DefaultSlot.reset(new ALeffectslot{}); if(InitEffectSlot(ALContext->DefaultSlot.get()) == AL_NO_ERROR) @@ -3630,7 +3636,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin InitContext(ALContext); - if(ConfigValueFloat(device->DeviceName.c_str(), nullptr, "volume-adjust", &valf)) + if(ConfigValueFloat(dev->DeviceName.c_str(), nullptr, "volume-adjust", &valf)) { if(!std::isfinite(valf)) ERR("volume-adjust must be finite: %f\n", valf); @@ -3646,10 +3652,10 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin UpdateListenerProps(ALContext); { - ALCcontext *head = device->ContextList.load(); + ALCcontext *head = dev->ContextList.load(); do { ALContext->next.store(head, std::memory_order_relaxed); - } while(!device->ContextList.compare_exchange_weak(head, ALContext)); + } while(!dev->ContextList.compare_exchange_weak(head, ALContext)); } backlock.unlock(); @@ -3661,8 +3667,6 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ERR("Failed to initialize the default effect\n"); } - ALCdevice_DecRef(device); - TRACE("Created context %p\n", ALContext); return ALContext; } @@ -4135,58 +4139,58 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) { - if(!VerifyDevice(&device) || device->Type != Capture) - alcSetError(device, ALC_INVALID_DEVICE); - else + DeviceRef dev{VerifyDevice(device)}; + if(!dev || dev->Type != Capture) + { + alcSetError(dev.get(), ALC_INVALID_DEVICE); + return; + } + + std::lock_guard _{dev->BackendLock}; + if(!dev->Connected.load(std::memory_order_acquire)) + alcSetError(dev.get(), ALC_INVALID_DEVICE); + else if(!(dev->Flags&DEVICE_RUNNING)) { - std::lock_guard _{device->BackendLock}; - if(!device->Connected.load(std::memory_order_acquire)) - alcSetError(device, ALC_INVALID_DEVICE); - else if(!(device->Flags&DEVICE_RUNNING)) + if(V0(dev->Backend,start)()) + dev->Flags |= DEVICE_RUNNING; + else { - if(V0(device->Backend,start)()) - device->Flags |= DEVICE_RUNNING; - else - { - aluHandleDisconnect(device, "Device start failure"); - alcSetError(device, ALC_INVALID_DEVICE); - } + aluHandleDisconnect(dev.get(), "Device start failure"); + alcSetError(dev.get(), ALC_INVALID_DEVICE); } } - - if(device) ALCdevice_DecRef(device); } ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) { - if(!VerifyDevice(&device) || device->Type != Capture) - alcSetError(device, ALC_INVALID_DEVICE); + DeviceRef dev{VerifyDevice(device)}; + if(!dev || dev->Type != Capture) + alcSetError(dev.get(), ALC_INVALID_DEVICE); else { - std::lock_guard _{device->BackendLock}; - if((device->Flags&DEVICE_RUNNING)) - V0(device->Backend,stop)(); - device->Flags &= ~DEVICE_RUNNING; + std::lock_guard _{dev->BackendLock}; + if((dev->Flags&DEVICE_RUNNING)) + V0(dev->Backend,stop)(); + dev->Flags &= ~DEVICE_RUNNING; } - - if(device) ALCdevice_DecRef(device); } ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) { - if(!VerifyDevice(&device) || device->Type != Capture) - alcSetError(device, ALC_INVALID_DEVICE); - else + DeviceRef dev{VerifyDevice(device)}; + if(!dev || dev->Type != Capture) { - ALCenum err = ALC_INVALID_VALUE; - { std::lock_guard _{device->BackendLock}; - if(samples >= 0 && V0(device->Backend,availableSamples)() >= (ALCuint)samples) - err = V(device->Backend,captureSamples)(buffer, samples); - } - if(err != ALC_NO_ERROR) - alcSetError(device, err); + alcSetError(dev.get(), ALC_INVALID_DEVICE); + return; } - if(device) ALCdevice_DecRef(device); + + ALCenum err{ALC_INVALID_VALUE}; + { std::lock_guard _{dev->BackendLock}; + if(samples >= 0 && V0(dev->Backend,availableSamples)() >= (ALCuint)samples) + err = V(dev->Backend,captureSamples)(buffer, samples); + } + if(err != ALC_NO_ERROR) + alcSetError(dev.get(), err); } @@ -4267,20 +4271,18 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN */ ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type) { - ALCboolean ret{ALC_FALSE}; - - if(!VerifyDevice(&device) || device->Type != Loopback) - alcSetError(device, ALC_INVALID_DEVICE); + DeviceRef dev{VerifyDevice(device)}; + if(!dev || dev->Type != Loopback) + alcSetError(dev.get(), ALC_INVALID_DEVICE); else if(freq <= 0) - alcSetError(device, ALC_INVALID_VALUE); + alcSetError(dev.get(), ALC_INVALID_VALUE); else { if(IsValidALCType(type) && IsValidALCChannels(channels) && freq >= MIN_OUTPUT_RATE) - ret = ALC_TRUE; + return ALC_TRUE; } - if(device) ALCdevice_DecRef(device); - return ret; + return ALC_FALSE; } /* alcRenderSamplesSOFT @@ -4290,17 +4292,17 @@ ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device */ FORCE_ALIGN ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) { - if(!VerifyDevice(&device) || device->Type != Loopback) - alcSetError(device, ALC_INVALID_DEVICE); + DeviceRef dev{VerifyDevice(device)}; + if(!dev || dev->Type != Loopback) + alcSetError(dev.get(), ALC_INVALID_DEVICE); else if(samples < 0 || (samples > 0 && buffer == nullptr)) - alcSetError(device, ALC_INVALID_VALUE); + alcSetError(dev.get(), ALC_INVALID_VALUE); else { - V0(device->Backend,lock)(); - aluMixData(device, buffer, samples); - V0(device->Backend,unlock)(); + V0(dev->Backend,lock)(); + aluMixData(dev.get(), buffer, samples); + V0(dev->Backend,unlock)(); } - if(device) ALCdevice_DecRef(device); } @@ -4314,17 +4316,17 @@ FORCE_ALIGN ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, AL */ ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device) { - if(!VerifyDevice(&device) || device->Type != Playback) - alcSetError(device, ALC_INVALID_DEVICE); + DeviceRef dev{VerifyDevice(device)}; + if(!dev || dev->Type != Playback) + alcSetError(dev.get(), ALC_INVALID_DEVICE); else { - std::lock_guard _{device->BackendLock}; - if((device->Flags&DEVICE_RUNNING)) - V0(device->Backend,stop)(); - device->Flags &= ~DEVICE_RUNNING; - device->Flags |= DEVICE_PAUSED; + std::lock_guard _{dev->BackendLock}; + if((dev->Flags&DEVICE_RUNNING)) + V0(dev->Backend,stop)(); + dev->Flags &= ~DEVICE_RUNNING; + dev->Flags |= DEVICE_PAUSED; } - if(device) ALCdevice_DecRef(device); } /* alcDeviceResumeSOFT @@ -4333,29 +4335,29 @@ ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device) */ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) { - if(!VerifyDevice(&device) || device->Type != Playback) - alcSetError(device, ALC_INVALID_DEVICE); + DeviceRef dev{VerifyDevice(device)}; + if(!dev || dev->Type != Playback) + alcSetError(dev.get(), ALC_INVALID_DEVICE); else { - std::lock_guard _{device->BackendLock}; - if((device->Flags&DEVICE_PAUSED)) + std::lock_guard _{dev->BackendLock}; + if((dev->Flags&DEVICE_PAUSED)) { - device->Flags &= ~DEVICE_PAUSED; - if(device->ContextList.load() != nullptr) + dev->Flags &= ~DEVICE_PAUSED; + if(dev->ContextList.load() != nullptr) { - if(V0(device->Backend,start)() != ALC_FALSE) - device->Flags |= DEVICE_RUNNING; + if(V0(dev->Backend,start)() != ALC_FALSE) + dev->Flags |= DEVICE_RUNNING; else { - V0(device->Backend,lock)(); - aluHandleDisconnect(device, "Device start failure"); - V0(device->Backend,unlock)(); - alcSetError(device, ALC_INVALID_DEVICE); + V0(dev->Backend,lock)(); + aluHandleDisconnect(dev.get(), "Device start failure"); + V0(dev->Backend,unlock)(); + alcSetError(dev.get(), ALC_INVALID_DEVICE); } } } } - if(device) ALCdevice_DecRef(device); } @@ -4369,26 +4371,23 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) */ ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index) { - const ALCchar *str{nullptr}; - - if(!VerifyDevice(&device) || device->Type == Capture) - alcSetError(device, ALC_INVALID_DEVICE); + DeviceRef dev{VerifyDevice(device)}; + if(!dev || dev->Type == Capture) + alcSetError(dev.get(), ALC_INVALID_DEVICE); else switch(paramName) { case ALC_HRTF_SPECIFIER_SOFT: - if(index >= 0 && (size_t)index < device->HrtfList.size()) - str = device->HrtfList[index].name.c_str(); - else - alcSetError(device, ALC_INVALID_VALUE); + if(index >= 0 && (size_t)index < dev->HrtfList.size()) + return dev->HrtfList[index].name.c_str(); + alcSetError(dev.get(), ALC_INVALID_VALUE); break; default: - alcSetError(device, ALC_INVALID_ENUM); + alcSetError(dev.get(), ALC_INVALID_ENUM); break; } - if(device) ALCdevice_DecRef(device); - return str; + return nullptr; } /* alcResetDeviceSOFT @@ -4398,33 +4397,30 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs) { std::unique_lock listlock{ListLock}; - if(!VerifyDevice(&device) || device->Type == Capture || - !device->Connected.load(std::memory_order_relaxed)) + DeviceRef dev{VerifyDevice(device)}; + if(!dev || dev->Type == Capture || !dev->Connected.load(std::memory_order_relaxed)) { listlock.unlock(); - alcSetError(device, ALC_INVALID_DEVICE); - if(device) ALCdevice_DecRef(device); + alcSetError(dev.get(), ALC_INVALID_DEVICE); return ALC_FALSE; } - std::unique_lock backlock{device->BackendLock}; + std::unique_lock backlock{dev->BackendLock}; listlock.unlock(); - ALCenum err{UpdateDeviceParams(device, attribs)}; + ALCenum err{UpdateDeviceParams(dev.get(), attribs)}; backlock.unlock(); if(err != ALC_NO_ERROR) { - alcSetError(device, err); + alcSetError(dev.get(), err); if(err == ALC_INVALID_DEVICE) { - V0(device->Backend,lock)(); - aluHandleDisconnect(device, "Device start failure"); - V0(device->Backend,unlock)(); + V0(dev->Backend,lock)(); + aluHandleDisconnect(dev.get(), "Device start failure"); + V0(dev->Backend,unlock)(); } - ALCdevice_DecRef(device); return ALC_FALSE; } - ALCdevice_DecRef(device); return ALC_TRUE; } -- cgit v1.2.3 From 48154c94d7db164b2c587c1c1cca413f782102d9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 23 Nov 2018 20:16:34 -0800 Subject: Use a unique_ptr while opening a device --- Alc/alc.cpp | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index a53269cd..46b371ef 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -3823,7 +3823,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) )) deviceName = nullptr; - auto device = new ALCdevice{Playback}; + std::unique_ptr device{new ALCdevice{Playback}}; //Set output format device->FmtChans = DevFmtChannelsDefault; @@ -3929,10 +3929,11 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->NumStereoSources = 1; device->NumMonoSources = device->SourcesMax - device->NumStereoSources; - device->Backend = PlaybackBackend.getFactory().createBackend(device, ALCbackend_Playback); + device->Backend = PlaybackBackend.getFactory().createBackend( + device.get(), ALCbackend_Playback); if(!device->Backend) { - delete device; + device = nullptr; alcSetError(nullptr, ALC_OUT_OF_MEMORY); return nullptr; } @@ -3941,7 +3942,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) ALCenum err{V(device->Backend,open)(deviceName)}; if(err != ALC_NO_ERROR) { - delete device; + device = nullptr; alcSetError(nullptr, err); return nullptr; } @@ -3971,11 +3972,11 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) ALCdevice *head{DeviceList.load()}; do { device->next.store(head, std::memory_order_relaxed); - } while(!DeviceList.compare_exchange_weak(head, device)); + } while(!DeviceList.compare_exchange_weak(head, device.get())); } - TRACE("Created device %p, \"%s\"\n", device, device->DeviceName.c_str()); - return device; + TRACE("Created device %p, \"%s\"\n", device.get(), device->DeviceName.c_str()); + return device.release(); } /* alcCloseDevice @@ -4051,14 +4052,14 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, if(deviceName && (!deviceName[0] || strcasecmp(deviceName, alcDefaultName) == 0 || strcasecmp(deviceName, "openal-soft") == 0)) deviceName = nullptr; - auto device = new ALCdevice{Capture}; + std::unique_ptr device{new ALCdevice{Capture}}; device->Frequency = frequency; device->Flags |= DEVICE_FREQUENCY_REQUEST; if(DecomposeDevFormat(format, &device->FmtChans, &device->FmtType) == AL_FALSE) { - delete device; + device = nullptr; alcSetError(nullptr, ALC_INVALID_ENUM); return nullptr; } @@ -4067,10 +4068,10 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, device->UpdateSize = samples; device->NumUpdates = 1; - device->Backend = CaptureBackend.getFactory().createBackend(device, ALCbackend_Capture); + device->Backend = CaptureBackend.getFactory().createBackend(device.get(), ALCbackend_Capture); if(!device->Backend) { - delete device; + device = nullptr; alcSetError(nullptr, ALC_OUT_OF_MEMORY); return nullptr; } @@ -4082,7 +4083,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCenum err{V(device->Backend,open)(deviceName)}; if(err != ALC_NO_ERROR) { - delete device; + device = nullptr; alcSetError(nullptr, err); return nullptr; } @@ -4091,11 +4092,11 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCdevice *head{DeviceList.load()}; do { device->next.store(head, std::memory_order_relaxed); - } while(!DeviceList.compare_exchange_weak(head, device)); + } while(!DeviceList.compare_exchange_weak(head, device.get())); } - TRACE("Created device %p, \"%s\"\n", device, device->DeviceName.c_str()); - return device; + TRACE("Created device %p, \"%s\"\n", device.get(), device->DeviceName.c_str()); + return device.release(); } ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) @@ -4213,7 +4214,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN return nullptr; } - auto device = new ALCdevice{Loopback}; + std::unique_ptr device{new ALCdevice{Loopback}}; device->SourcesMax = 256; device->AuxiliaryEffectSlotMax = 64; @@ -4243,10 +4244,10 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->NumMonoSources = device->SourcesMax - device->NumStereoSources; device->Backend = LoopbackBackendFactory::getFactory().createBackend( - device, ALCbackend_Loopback); + device.get(), ALCbackend_Loopback); if(!device->Backend) { - al_free(device); + device = nullptr; alcSetError(nullptr, ALC_OUT_OF_MEMORY); return nullptr; } @@ -4258,11 +4259,11 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN ALCdevice *head{DeviceList.load()}; do { device->next.store(head, std::memory_order_relaxed); - } while(!DeviceList.compare_exchange_weak(head, device)); + } while(!DeviceList.compare_exchange_weak(head, device.get())); } - TRACE("Created device %p\n", device); - return device; + TRACE("Created device %p\n", device.get()); + return device.release(); } /* alcIsRenderFormatSupportedSOFT -- cgit v1.2.3 From 505e535655cb12af9a0d4dc8b2cae9a0db03e34e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 24 Nov 2018 09:40:13 -0800 Subject: Use RAII more with alFilter.cpp --- OpenAL32/alFilter.cpp | 746 ++++++++++++++++++++++++-------------------------- 1 file changed, 364 insertions(+), 382 deletions(-) diff --git a/OpenAL32/alFilter.cpp b/OpenAL32/alFilter.cpp index b22729a2..62ceba97 100644 --- a/OpenAL32/alFilter.cpp +++ b/OpenAL32/alFilter.cpp @@ -31,320 +31,16 @@ #include "alError.h" +namespace { + #define FILTER_MIN_GAIN 0.0f #define FILTER_MAX_GAIN 4.0f /* +12dB */ -static ALfilter *AllocFilter(ALCcontext *context); -static void FreeFilter(ALCdevice *device, ALfilter *filter); -static void InitFilterParams(ALfilter *filter, ALenum type); - -static inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) -{ - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= device->FilterList.size())) - return nullptr; - FilterSubList &sublist = device->FilterList[lidx]; - if(UNLIKELY(sublist.FreeMask & (U64(1)<id; - } - - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) -{ - ALCdevice *device; - ALCcontext *context; - ALfilter *filter; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - LockFilterList(device); - if(n < 0) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d filters", n); - for(i = 0;i < n;i++) - { - if(filters[i] && LookupFilter(device, filters[i]) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid filter ID %u", filters[i]); - } - for(i = 0;i < n;i++) - { - if((filter=LookupFilter(device, filters[i])) != NULL) - FreeFilter(device, filter); - } - -done: - UnlockFilterList(device); - ALCcontext_DecRef(context); -} - -AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter) -{ - ALCcontext *Context; - ALboolean result; - - Context = GetContextRef(); - if(!Context) return AL_FALSE; - - LockFilterList(Context->Device); - result = ((!filter || LookupFilter(Context->Device, filter)) ? - AL_TRUE : AL_FALSE); - UnlockFilterList(Context->Device); - - ALCcontext_DecRef(Context); - - return result; -} - -AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) -{ - ALCcontext *Context; - ALCdevice *Device; - ALfilter *ALFilter; - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockFilterList(Device); - if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - if(param == AL_FILTER_TYPE) - { - if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS || - value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS) - InitFilterParams(ALFilter, value); - else - alSetError(Context, AL_INVALID_VALUE, "Invalid filter type 0x%04x", value); - } - else - { - /* Call the appropriate handler */ - ALfilter_setParami(ALFilter, Context, param, value); - } - } - UnlockFilterList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *values) -{ - ALCcontext *Context; - ALCdevice *Device; - ALfilter *ALFilter; - - switch(param) - { - case AL_FILTER_TYPE: - alFilteri(filter, param, values[0]); - return; - } - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockFilterList(Device); - if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_setParamiv(ALFilter, Context, param, values); - } - UnlockFilterList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value) -{ - ALCcontext *Context; - ALCdevice *Device; - ALfilter *ALFilter; - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockFilterList(Device); - if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_setParamf(ALFilter, Context, param, value); - } - UnlockFilterList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *values) -{ - ALCcontext *Context; - ALCdevice *Device; - ALfilter *ALFilter; - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockFilterList(Device); - if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_setParamfv(ALFilter, Context, param, values); - } - UnlockFilterList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value) -{ - ALCcontext *Context; - ALCdevice *Device; - ALfilter *ALFilter; - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockFilterList(Device); - if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - if(param == AL_FILTER_TYPE) - *value = ALFilter->type; - else - { - /* Call the appropriate handler */ - ALfilter_getParami(ALFilter, Context, param, value); - } - } - UnlockFilterList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *values) -{ - ALCcontext *Context; - ALCdevice *Device; - ALfilter *ALFilter; - - switch(param) - { - case AL_FILTER_TYPE: - alGetFilteri(filter, param, values); - return; - } - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockFilterList(Device); - if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_getParamiv(ALFilter, Context, param, values); - } - UnlockFilterList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *value) -{ - ALCcontext *Context; - ALCdevice *Device; - ALfilter *ALFilter; - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockFilterList(Device); - if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_getParamf(ALFilter, Context, param, value); - } - UnlockFilterList(Device); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *values) -{ - ALCcontext *Context; - ALCdevice *Device; - ALfilter *ALFilter; - - Context = GetContextRef(); - if(!Context) return; - - Device = Context->Device; - LockFilterList(Device); - if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_getParamfv(ALFilter, Context, param, values); - } - UnlockFilterList(Device); - - ALCcontext_DecRef(Context); -} - - -static void ALlowpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) +void ALlowpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) { alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } -static void ALlowpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +void ALlowpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) { alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } -static void ALlowpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) +void ALlowpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) { switch(param) { @@ -364,14 +60,14 @@ static void ALlowpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum pa alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param); } } -static void ALlowpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) +void ALlowpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) { ALlowpass_setParamf(filter, context, param, vals[0]); } -static void ALlowpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +void ALlowpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) { alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } -static void ALlowpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +void ALlowpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) { alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } -static void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) +void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) { @@ -387,17 +83,17 @@ static void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum pa alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param); } } -static void ALlowpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) +void ALlowpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) { ALlowpass_getParamf(filter, context, param, vals); } DEFINE_ALFILTER_VTABLE(ALlowpass); -static void ALhighpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) +void ALhighpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) { alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } -static void ALhighpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +void ALhighpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) { alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } -static void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) +void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) { switch(param) { @@ -417,14 +113,14 @@ static void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum p alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param); } } -static void ALhighpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) +void ALhighpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) { ALhighpass_setParamf(filter, context, param, vals[0]); } -static void ALhighpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +void ALhighpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) { alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } -static void ALhighpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +void ALhighpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) { alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } -static void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) +void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) { @@ -440,17 +136,17 @@ static void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum p alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param); } } -static void ALhighpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) +void ALhighpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) { ALhighpass_getParamf(filter, context, param, vals); } DEFINE_ALFILTER_VTABLE(ALhighpass); -static void ALbandpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) +void ALbandpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) { alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } -static void ALbandpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +void ALbandpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) { alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } -static void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) +void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) { switch(param) { @@ -476,14 +172,14 @@ static void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum p alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param); } } -static void ALbandpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) +void ALbandpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) { ALbandpass_setParamf(filter, context, param, vals[0]); } -static void ALbandpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +void ALbandpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) { alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } -static void ALbandpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +void ALbandpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) { alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } -static void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) +void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) { @@ -503,34 +199,75 @@ static void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum p alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param); } } -static void ALbandpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) +void ALbandpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) { ALbandpass_getParamf(filter, context, param, vals); } DEFINE_ALFILTER_VTABLE(ALbandpass); -static void ALnullfilter_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) +void ALnullfilter_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -static void ALnullfilter_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +void ALnullfilter_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -static void ALnullfilter_setParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat UNUSED(val)) +void ALnullfilter_setParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat UNUSED(val)) { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -static void ALnullfilter_setParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALfloat *UNUSED(vals)) +void ALnullfilter_setParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALfloat *UNUSED(vals)) { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -static void ALnullfilter_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +void ALnullfilter_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -static void ALnullfilter_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +void ALnullfilter_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -static void ALnullfilter_getParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat *UNUSED(val)) +void ALnullfilter_getParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat *UNUSED(val)) { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -static void ALnullfilter_getParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat *UNUSED(vals)) +void ALnullfilter_getParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat *UNUSED(vals)) { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } DEFINE_ALFILTER_VTABLE(ALnullfilter); -static ALfilter *AllocFilter(ALCcontext *context) +void InitFilterParams(ALfilter *filter, ALenum type) +{ + if(type == AL_FILTER_LOWPASS) + { + filter->Gain = AL_LOWPASS_DEFAULT_GAIN; + filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF; + filter->HFReference = LOWPASSFREQREF; + filter->GainLF = 1.0f; + filter->LFReference = HIGHPASSFREQREF; + filter->vtab = &ALlowpass_vtable; + } + else if(type == AL_FILTER_HIGHPASS) + { + filter->Gain = AL_HIGHPASS_DEFAULT_GAIN; + filter->GainHF = 1.0f; + filter->HFReference = LOWPASSFREQREF; + filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF; + filter->LFReference = HIGHPASSFREQREF; + filter->vtab = &ALhighpass_vtable; + } + else if(type == AL_FILTER_BANDPASS) + { + filter->Gain = AL_BANDPASS_DEFAULT_GAIN; + filter->GainHF = AL_BANDPASS_DEFAULT_GAINHF; + filter->HFReference = LOWPASSFREQREF; + filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF; + filter->LFReference = HIGHPASSFREQREF; + filter->vtab = &ALbandpass_vtable; + } + else + { + filter->Gain = 1.0f; + filter->GainHF = 1.0f; + filter->HFReference = LOWPASSFREQREF; + filter->GainLF = 1.0f; + filter->LFReference = HIGHPASSFREQREF; + filter->vtab = &ALnullfilter_vtable; + } + filter->type = type; +} + +ALfilter *AllocFilter(ALCcontext *context) { ALCdevice *device = context->Device; almtx_lock(&device->FilterLock); @@ -587,7 +324,7 @@ static ALfilter *AllocFilter(ALCcontext *context) return filter; } -static void FreeFilter(ALCdevice *device, ALfilter *filter) +void FreeFilter(ALCdevice *device, ALfilter *filter) { ALuint id = filter->id - 1; ALsizei lidx = id >> 6; @@ -598,66 +335,311 @@ static void FreeFilter(ALCdevice *device, ALfilter *filter) device->FilterList[lidx].FreeMask |= U64(1) << slidx; } -void ReleaseALFilters(ALCdevice *device) + +inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) { - size_t leftover = 0; - for(auto &sublist : device->FilterList) + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= device->FilterList.size())) + return nullptr; + FilterSubList &sublist = device->FilterList[lidx]; + if(UNLIKELY(sublist.FreeMask & (U64(1)<id; + } + else if(n > 1) + { + /* Store the allocated buffer IDs in a separate local list, to avoid + * modifying the user storage in case of failure. + */ + std::vector ids; + ids.reserve(n); + do { + ALfilter *filter = AllocFilter(context.get()); + if(!filter) + { + alDeleteFilters(ids.size(), ids.data()); + return; + } + + ids.emplace_back(filter->id); + } while(--n); + std::copy(ids.begin(), ids.end(), filters); + } +} + +AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(UNLIKELY(n < 0)) + { + alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d filters", n); + return; + } + if(UNLIKELY(n == 0)) + return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + /* First try to find any buffers that are invalid or in-use. */ + const ALuint *filters_end = filters + n; + auto invflt = std::find_if(filters, filters_end, + [device, &context](ALuint fid) -> bool { - ALsizei idx = CTZ64(usemask); - ALfilter *filter = sublist.Filters + idx; + if(!fid) return false; + ALfilter *filter{LookupFilter(device, fid)}; + if(UNLIKELY(!filter)) + { + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", fid); + return true; + } + return false; + } + ); + if(LIKELY(invflt == filters_end)) + { + /* All good. Delete non-0 buffer IDs. */ + std::for_each(filters, filters_end, + [device](ALuint fid) -> void + { + ALfilter *filter{fid ? LookupFilter(device, fid) : nullptr}; + if(filter) FreeFilter(device, filter); + } + ); + } +} - filter->~ALfilter(); - ++leftover; +AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter) +{ + ContextRef context{GetContextRef()}; + if(LIKELY(context)) + { + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + if(!filter || LookupFilter(device, filter)) + return AL_TRUE; + } + return AL_FALSE; +} - usemask &= ~(U64(1) << idx); + +AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + if(param == AL_FILTER_TYPE) + { + if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS || + value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS) + InitFilterParams(alfilt, value); + else + alSetError(context.get(), AL_INVALID_VALUE, "Invalid filter type 0x%04x", value); + } + else + { + /* Call the appropriate handler */ + ALfilter_setParami(alfilt, context.get(), param, value); } - sublist.FreeMask = ~usemask; } - if(leftover > 0) - WARN("(%p) Deleted " SZFMT " Filter%s\n", device, leftover, (leftover==1)?"":"s"); } +AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *values) +{ + switch(param) + { + case AL_FILTER_TYPE: + alFilteri(filter, param, values[0]); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; -static void InitFilterParams(ALfilter *filter, ALenum type) + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_setParamiv(alfilt, context.get(), param, values); + } +} + +AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value) { - if(type == AL_FILTER_LOWPASS) + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else { - filter->Gain = AL_LOWPASS_DEFAULT_GAIN; - filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF; - filter->HFReference = LOWPASSFREQREF; - filter->GainLF = 1.0f; - filter->LFReference = HIGHPASSFREQREF; - filter->vtab = &ALlowpass_vtable; + /* Call the appropriate handler */ + ALfilter_setParamf(alfilt, context.get(), param, value); } - else if(type == AL_FILTER_HIGHPASS) +} + +AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *values) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else { - filter->Gain = AL_HIGHPASS_DEFAULT_GAIN; - filter->GainHF = 1.0f; - filter->HFReference = LOWPASSFREQREF; - filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF; - filter->LFReference = HIGHPASSFREQREF; - filter->vtab = &ALhighpass_vtable; + /* Call the appropriate handler */ + ALfilter_setParamfv(alfilt, context.get(), param, values); } - else if(type == AL_FILTER_BANDPASS) +} + +AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else { - filter->Gain = AL_BANDPASS_DEFAULT_GAIN; - filter->GainHF = AL_BANDPASS_DEFAULT_GAINHF; - filter->HFReference = LOWPASSFREQREF; - filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF; - filter->LFReference = HIGHPASSFREQREF; - filter->vtab = &ALbandpass_vtable; + if(param == AL_FILTER_TYPE) + *value = alfilt->type; + else + { + /* Call the appropriate handler */ + ALfilter_getParami(alfilt, context.get(), param, value); + } } +} + +AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *values) +{ + switch(param) + { + case AL_FILTER_TYPE: + alGetFilteri(filter, param, values); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); else { - filter->Gain = 1.0f; - filter->GainHF = 1.0f; - filter->HFReference = LOWPASSFREQREF; - filter->GainLF = 1.0f; - filter->LFReference = HIGHPASSFREQREF; - filter->vtab = &ALnullfilter_vtable; + /* Call the appropriate handler */ + ALfilter_getParamiv(alfilt, context.get(), param, values); } - filter->type = type; +} + +AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *value) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_getParamf(alfilt, context.get(), param, value); + } +} + +AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *values) +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_getParamfv(alfilt, context.get(), param, values); + } +} + + +void ReleaseALFilters(ALCdevice *device) +{ + size_t leftover = 0; + for(auto &sublist : device->FilterList) + { + ALuint64 usemask = ~sublist.FreeMask; + while(usemask) + { + ALsizei idx = CTZ64(usemask); + ALfilter *filter = sublist.Filters + idx; + + filter->~ALfilter(); + ++leftover; + + usemask &= ~(U64(1) << idx); + } + sublist.FreeMask = ~usemask; + } + if(leftover > 0) + WARN("(%p) Deleted " SZFMT " Filter%s\n", device, leftover, (leftover==1)?"":"s"); } -- cgit v1.2.3 From b508a760c88e8af6e852561dd7cf50edd7c601b9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 24 Nov 2018 10:07:48 -0800 Subject: Use a normal vector to store buffer data --- Alc/mixvoice.cpp | 8 ++++---- OpenAL32/Include/alBuffer.h | 43 ++++++++++++++++++++++--------------------- OpenAL32/alBuffer.cpp | 30 +++++++++++------------------- 3 files changed, 37 insertions(+), 44 deletions(-) diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 50c9c735..9620b214 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -402,7 +402,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize for(i = 0;i < BufferListItem->num_buffers;i++) { const ALbuffer *buffer = BufferListItem->buffers[i]; - const ALubyte *Data = static_cast(buffer->data); + const ALbyte *Data = buffer->mData.data(); ALsizei DataSize; if(DataPosInt >= buffer->SampleLen) @@ -428,7 +428,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize for(i = 0;i < BufferListItem->num_buffers;i++) { const ALbuffer *buffer = BufferListItem->buffers[i]; - const ALubyte *Data = static_cast(buffer->data); + const ALbyte *Data = buffer->mData.data(); ALsizei DataSize; if(DataPosInt >= buffer->SampleLen) @@ -453,7 +453,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize for(i = 0;i < BufferListItem->num_buffers;i++) { const ALbuffer *buffer = BufferListItem->buffers[i]; - const ALubyte *Data = static_cast(buffer->data); + const ALbyte *Data = buffer->mData.data(); ALsizei DataSize; if(LoopStart >= buffer->SampleLen) @@ -490,7 +490,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize if(DataSize > pos) { - const ALubyte *Data = static_cast(ALBuffer->data); + const ALbyte *Data = ALBuffer->mData.data(); Data += (pos*NumChannels + chan)*SampleSize; DataSize = mini(SizeToDo, DataSize - pos); diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index a99c06fc..54c17670 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -7,6 +7,7 @@ #include "inprogext.h" #include "atomic.h" +#include "vector.h" /* User formats */ @@ -88,37 +89,37 @@ inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type) } -typedef struct ALbuffer { - ALvoid *data; +struct ALbuffer { + al::vector mData; - ALsizei Frequency; - ALbitfieldSOFT Access; - ALsizei SampleLen; + ALsizei Frequency{0}; + ALbitfieldSOFT Access{0u}; + ALsizei SampleLen{0}; - enum FmtChannels FmtChannels; - enum FmtType FmtType; - ALsizei BytesAlloc; + enum FmtChannels FmtChannels{}; + enum FmtType FmtType{}; + ALsizei BytesAlloc{0}; - enum UserFmtType OriginalType; - ALsizei OriginalSize; - ALsizei OriginalAlign; + enum UserFmtType OriginalType{}; + ALsizei OriginalSize{0}; + ALsizei OriginalAlign{0}; - ALsizei LoopStart; - ALsizei LoopEnd; + ALsizei LoopStart{0}; + ALsizei LoopEnd{0}; - ATOMIC(ALsizei) UnpackAlign; - ATOMIC(ALsizei) PackAlign; + std::atomic UnpackAlign{0}; + std::atomic PackAlign{0}; - ALbitfieldSOFT MappedAccess; - ALsizei MappedOffset; - ALsizei MappedSize; + ALbitfieldSOFT MappedAccess{0u}; + ALsizei MappedOffset{0}; + ALsizei MappedSize{0}; /* Number of times buffer was attached to a source (deletion can only occur when 0) */ - RefCount ref; + RefCount ref{0u}; /* Self ID */ - ALuint id; -} ALbuffer; + ALuint id{0}; +}; ALvoid ReleaseALBuffers(ALCdevice *device); diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index 196dcd22..0580b33a 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -110,8 +110,6 @@ void FreeBuffer(ALCdevice *device, ALbuffer *buffer) ALsizei lidx = id >> 6; ALsizei slidx = id & 0x3f; - al_free(buffer->data); - buffer->data = nullptr; buffer->~ALbuffer(); device->BufferList[lidx].FreeMask |= U64(1) << slidx; @@ -290,41 +288,37 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U newsize = (newsize+15) & ~0xf; if(newsize != ALBuf->BytesAlloc) { - void *temp{al_malloc(16, (size_t)newsize)}; - if(UNLIKELY(!temp && newsize)) - SETERR_RETURN(context, AL_OUT_OF_MEMORY,, "Failed to allocate %d bytes of storage", - newsize); + al::vector newdata(newsize); if((access&AL_PRESERVE_DATA_BIT_SOFT)) { ALsizei tocopy{std::min(newsize, ALBuf->BytesAlloc)}; - if(tocopy > 0) memcpy(temp, ALBuf->data, tocopy); + std::copy_n(ALBuf->mData.begin(), tocopy, newdata.begin()); } - al_free(ALBuf->data); - ALBuf->data = temp; + ALBuf->mData = std::move(newdata); ALBuf->BytesAlloc = newsize; } if(SrcType == UserFmtIMA4) { assert(DstType == FmtShort); - if(data != nullptr && ALBuf->data != nullptr) - Convert_ALshort_ALima4(static_cast(ALBuf->data), + if(data != nullptr && !ALBuf->mData.empty()) + Convert_ALshort_ALima4(reinterpret_cast(ALBuf->mData.data()), static_cast(data), NumChannels, frames, align); ALBuf->OriginalAlign = align; } else if(SrcType == UserFmtMSADPCM) { assert(DstType == FmtShort); - if(data != nullptr && ALBuf->data != nullptr) - Convert_ALshort_ALmsadpcm(static_cast(ALBuf->data), + if(data != nullptr && !ALBuf->mData.empty()) + Convert_ALshort_ALmsadpcm(reinterpret_cast(ALBuf->mData.data()), static_cast(data), NumChannels, frames, align); ALBuf->OriginalAlign = align; } else { assert((long)SrcType == (long)DstType); - if(data != nullptr && ALBuf->data != nullptr) - memcpy(ALBuf->data, data, frames*FrameSize); + if(data != nullptr && !ALBuf->mData.empty()) + std::copy_n(static_cast(data), frames*FrameSize, ALBuf->mData.begin()); ALBuf->OriginalAlign = 1; } ALBuf->OriginalSize = size; @@ -601,7 +595,7 @@ AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei offset, length, buffer); else { - void *retval = (ALbyte*)albuf->data + offset; + void *retval = albuf->mData.data() + offset; albuf->MappedAccess = access; albuf->MappedOffset = offset; albuf->MappedSize = length; @@ -730,7 +724,7 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons offset = offset/byte_align * align * frame_size; length = length/byte_align * align; - void *dst = static_cast(albuf->data) + offset; + void *dst = albuf->mData.data() + offset; if(srctype == UserFmtIMA4 && albuf->FmtType == FmtShort) Convert_ALshort_ALima4(static_cast(dst), static_cast(data), num_chans, length, align); @@ -1196,8 +1190,6 @@ ALvoid ReleaseALBuffers(ALCdevice *device) ALsizei idx = CTZ64(usemask); ALbuffer *buffer = sublist.Buffers + idx; - al_free(buffer->data); - buffer->data = nullptr; buffer->~ALbuffer(); ++leftover; -- cgit v1.2.3 From d83cff02e5ac6f35231df6ce6a1e61ee21a6a41c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 24 Nov 2018 11:41:50 -0800 Subject: Ensure an enum is the appropriate size/type --- OpenAL32/alSource.cpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 8ee94600..0955d1e9 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -584,7 +584,7 @@ inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept } -enum SourceProp { +enum SourceProp : ALenum { srcPitch = AL_PITCH, srcGain = AL_GAIN, srcMinGain = AL_MIN_GAIN, @@ -710,9 +710,7 @@ void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) ALint FloatValsByProp(ALenum prop) { - if(prop != (ALenum)((SourceProp)prop)) - return 0; - switch((SourceProp)prop) + switch(static_cast(prop)) { case AL_PITCH: case AL_GAIN: @@ -774,9 +772,7 @@ ALint FloatValsByProp(ALenum prop) } ALint DoubleValsByProp(ALenum prop) { - if(prop != (ALenum)((SourceProp)prop)) - return 0; - switch((SourceProp)prop) + switch(static_cast(prop)) { case AL_PITCH: case AL_GAIN: @@ -837,9 +833,7 @@ ALint DoubleValsByProp(ALenum prop) ALint IntValsByProp(ALenum prop) { - if(prop != (ALenum)((SourceProp)prop)) - return 0; - switch((SourceProp)prop) + switch(static_cast(prop)) { case AL_PITCH: case AL_GAIN: @@ -898,9 +892,7 @@ ALint IntValsByProp(ALenum prop) } ALint Int64ValsByProp(ALenum prop) { - if(prop != (ALenum)((SourceProp)prop)) - return 0; - switch((SourceProp)prop) + switch(static_cast(prop)) { case AL_PITCH: case AL_GAIN: -- cgit v1.2.3 From 6a84a2ca614f368791dd9e03139f47601bff42c7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 24 Nov 2018 12:09:37 -0800 Subject: Fix a couple comments --- OpenAL32/alFilter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenAL32/alFilter.cpp b/OpenAL32/alFilter.cpp index 62ceba97..bda03fae 100644 --- a/OpenAL32/alFilter.cpp +++ b/OpenAL32/alFilter.cpp @@ -405,7 +405,7 @@ AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) ALCdevice *device{context->Device}; std::lock_guard _{device->FilterLock}; - /* First try to find any buffers that are invalid or in-use. */ + /* First try to find any filters that are invalid. */ const ALuint *filters_end = filters + n; auto invflt = std::find_if(filters, filters_end, [device, &context](ALuint fid) -> bool @@ -422,7 +422,7 @@ AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) ); if(LIKELY(invflt == filters_end)) { - /* All good. Delete non-0 buffer IDs. */ + /* All good. Delete non-0 filter IDs. */ std::for_each(filters, filters_end, [device](ALuint fid) -> void { -- cgit v1.2.3 From 62d38b1187ac3cf64f3e78531a9720279f877e23 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 24 Nov 2018 13:23:27 -0800 Subject: Use RAII in alEffect.cpp --- OpenAL32/Include/alEffect.h | 69 ++-- OpenAL32/alEffect.cpp | 755 +++++++++++++++++++++----------------------- 2 files changed, 398 insertions(+), 426 deletions(-) diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index 7b849c0c..38540cfc 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -3,9 +3,6 @@ #include "alMain.h" -#ifdef __cplusplus -extern "C" { -#endif struct ALeffect; @@ -36,43 +33,43 @@ struct EffectList { ALenum val; }; #define EFFECTLIST_SIZE 14 -extern const struct EffectList EffectList[EFFECTLIST_SIZE]; +extern const EffectList EffectList[EFFECTLIST_SIZE]; struct ALeffectVtable { - void (*const setParami)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALint val); - void (*const setParamiv)(struct ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals); - void (*const setParamf)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val); - void (*const setParamfv)(struct ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals); - - void (*const getParami)(const struct ALeffect *effect, ALCcontext *context, ALenum param, ALint *val); - void (*const getParamiv)(const struct ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals); - void (*const getParamf)(const struct ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val); - void (*const getParamfv)(const struct ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals); + void (*const setParami)(ALeffect *effect, ALCcontext *context, ALenum param, ALint val); + void (*const setParamiv)(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals); + void (*const setParamf)(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val); + void (*const setParamfv)(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals); + + void (*const getParami)(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val); + void (*const getParamiv)(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals); + void (*const getParamf)(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val); + void (*const getParamfv)(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals); }; #define DEFINE_ALEFFECT_VTABLE(T) \ -const struct ALeffectVtable T##_vtable = { \ +const ALeffectVtable T##_vtable = { \ T##_setParami, T##_setParamiv, \ T##_setParamf, T##_setParamfv, \ T##_getParami, T##_getParamiv, \ T##_getParamf, T##_getParamfv, \ } -extern const struct ALeffectVtable ALeaxreverb_vtable; -extern const struct ALeffectVtable ALreverb_vtable; -extern const struct ALeffectVtable ALautowah_vtable; -extern const struct ALeffectVtable ALchorus_vtable; -extern const struct ALeffectVtable ALcompressor_vtable; -extern const struct ALeffectVtable ALdistortion_vtable; -extern const struct ALeffectVtable ALecho_vtable; -extern const struct ALeffectVtable ALequalizer_vtable; -extern const struct ALeffectVtable ALflanger_vtable; -extern const struct ALeffectVtable ALfshifter_vtable; -extern const struct ALeffectVtable ALmodulator_vtable; -extern const struct ALeffectVtable ALnull_vtable; -extern const struct ALeffectVtable ALpshifter_vtable; -extern const struct ALeffectVtable ALdedicated_vtable; +extern const ALeffectVtable ALeaxreverb_vtable; +extern const ALeffectVtable ALreverb_vtable; +extern const ALeffectVtable ALautowah_vtable; +extern const ALeffectVtable ALchorus_vtable; +extern const ALeffectVtable ALcompressor_vtable; +extern const ALeffectVtable ALdistortion_vtable; +extern const ALeffectVtable ALecho_vtable; +extern const ALeffectVtable ALequalizer_vtable; +extern const ALeffectVtable ALflanger_vtable; +extern const ALeffectVtable ALfshifter_vtable; +extern const ALeffectVtable ALmodulator_vtable; +extern const ALeffectVtable ALnull_vtable; +extern const ALeffectVtable ALpshifter_vtable; +extern const ALeffectVtable ALdedicated_vtable; typedef union ALeffectProps { @@ -178,17 +175,17 @@ typedef union ALeffectProps { } Dedicated; } ALeffectProps; -typedef struct ALeffect { +struct ALeffect { // Effect type (AL_EFFECT_NULL, ...) - ALenum type; + ALenum type{AL_EFFECT_NULL}; - ALeffectProps Props; + ALeffectProps Props{}; - const struct ALeffectVtable *vtab; + const ALeffectVtable *vtab{nullptr}; /* Self ID */ - ALuint id; -} ALeffect; + ALuint id{0u}; +}; #define ALeffect_setParami(o, c, p, v) ((o)->vtab->setParami(o, c, p, v)) #define ALeffect_setParamf(o, c, p, v) ((o)->vtab->setParamf(o, c, p, v)) #define ALeffect_setParamiv(o, c, p, v) ((o)->vtab->setParamiv(o, c, p, v)) @@ -206,8 +203,4 @@ void ReleaseALEffects(ALCdevice *device); void LoadReverbPreset(const char *name, ALeffect *effect); -#ifdef __cplusplus -} -#endif - #endif diff --git a/OpenAL32/alEffect.cpp b/OpenAL32/alEffect.cpp index 54cfad67..e25e2007 100644 --- a/OpenAL32/alEffect.cpp +++ b/OpenAL32/alEffect.cpp @@ -54,11 +54,228 @@ const struct EffectList EffectList[EFFECTLIST_SIZE] = { ALboolean DisabledEffects[MAX_EFFECTS]; -static ALeffect *AllocEffect(ALCcontext *context); -static void FreeEffect(ALCdevice *device, ALeffect *effect); -static void InitEffectParams(ALeffect *effect, ALenum type); +namespace { -static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) +void InitEffectParams(ALeffect *effect, ALenum type) +{ + switch(type) + { + case AL_EFFECT_EAXREVERB: + effect->Props.Reverb.Density = AL_EAXREVERB_DEFAULT_DENSITY; + effect->Props.Reverb.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION; + effect->Props.Reverb.Gain = AL_EAXREVERB_DEFAULT_GAIN; + effect->Props.Reverb.GainHF = AL_EAXREVERB_DEFAULT_GAINHF; + effect->Props.Reverb.GainLF = AL_EAXREVERB_DEFAULT_GAINLF; + effect->Props.Reverb.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME; + effect->Props.Reverb.DecayHFRatio = AL_EAXREVERB_DEFAULT_DECAY_HFRATIO; + effect->Props.Reverb.DecayLFRatio = AL_EAXREVERB_DEFAULT_DECAY_LFRATIO; + effect->Props.Reverb.ReflectionsGain = AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN; + effect->Props.Reverb.ReflectionsDelay = AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY; + effect->Props.Reverb.ReflectionsPan[0] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; + effect->Props.Reverb.ReflectionsPan[1] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; + effect->Props.Reverb.ReflectionsPan[2] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; + effect->Props.Reverb.LateReverbGain = AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN; + effect->Props.Reverb.LateReverbDelay = AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY; + effect->Props.Reverb.LateReverbPan[0] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; + effect->Props.Reverb.LateReverbPan[1] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; + effect->Props.Reverb.LateReverbPan[2] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; + effect->Props.Reverb.EchoTime = AL_EAXREVERB_DEFAULT_ECHO_TIME; + effect->Props.Reverb.EchoDepth = AL_EAXREVERB_DEFAULT_ECHO_DEPTH; + effect->Props.Reverb.ModulationTime = AL_EAXREVERB_DEFAULT_MODULATION_TIME; + effect->Props.Reverb.ModulationDepth = AL_EAXREVERB_DEFAULT_MODULATION_DEPTH; + effect->Props.Reverb.AirAbsorptionGainHF = AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF; + effect->Props.Reverb.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE; + effect->Props.Reverb.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE; + effect->Props.Reverb.RoomRolloffFactor = AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; + effect->Props.Reverb.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT; + effect->vtab = &ALeaxreverb_vtable; + break; + case AL_EFFECT_REVERB: + effect->Props.Reverb.Density = AL_REVERB_DEFAULT_DENSITY; + effect->Props.Reverb.Diffusion = AL_REVERB_DEFAULT_DIFFUSION; + effect->Props.Reverb.Gain = AL_REVERB_DEFAULT_GAIN; + effect->Props.Reverb.GainHF = AL_REVERB_DEFAULT_GAINHF; + effect->Props.Reverb.GainLF = 1.0f; + effect->Props.Reverb.DecayTime = AL_REVERB_DEFAULT_DECAY_TIME; + effect->Props.Reverb.DecayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO; + effect->Props.Reverb.DecayLFRatio = 1.0f; + effect->Props.Reverb.ReflectionsGain = AL_REVERB_DEFAULT_REFLECTIONS_GAIN; + effect->Props.Reverb.ReflectionsDelay = AL_REVERB_DEFAULT_REFLECTIONS_DELAY; + effect->Props.Reverb.ReflectionsPan[0] = 0.0f; + effect->Props.Reverb.ReflectionsPan[1] = 0.0f; + effect->Props.Reverb.ReflectionsPan[2] = 0.0f; + effect->Props.Reverb.LateReverbGain = AL_REVERB_DEFAULT_LATE_REVERB_GAIN; + effect->Props.Reverb.LateReverbDelay = AL_REVERB_DEFAULT_LATE_REVERB_DELAY; + effect->Props.Reverb.LateReverbPan[0] = 0.0f; + effect->Props.Reverb.LateReverbPan[1] = 0.0f; + effect->Props.Reverb.LateReverbPan[2] = 0.0f; + effect->Props.Reverb.EchoTime = 0.25f; + effect->Props.Reverb.EchoDepth = 0.0f; + effect->Props.Reverb.ModulationTime = 0.25f; + effect->Props.Reverb.ModulationDepth = 0.0f; + effect->Props.Reverb.AirAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF; + effect->Props.Reverb.HFReference = 5000.0f; + effect->Props.Reverb.LFReference = 250.0f; + effect->Props.Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; + effect->Props.Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT; + effect->vtab = &ALreverb_vtable; + break; + case AL_EFFECT_AUTOWAH: + effect->Props.Autowah.AttackTime = AL_AUTOWAH_DEFAULT_ATTACK_TIME; + effect->Props.Autowah.ReleaseTime = AL_AUTOWAH_DEFAULT_RELEASE_TIME; + effect->Props.Autowah.Resonance = AL_AUTOWAH_DEFAULT_RESONANCE; + effect->Props.Autowah.PeakGain = AL_AUTOWAH_DEFAULT_PEAK_GAIN; + effect->vtab = &ALautowah_vtable; + break; + case AL_EFFECT_CHORUS: + effect->Props.Chorus.Waveform = AL_CHORUS_DEFAULT_WAVEFORM; + effect->Props.Chorus.Phase = AL_CHORUS_DEFAULT_PHASE; + effect->Props.Chorus.Rate = AL_CHORUS_DEFAULT_RATE; + effect->Props.Chorus.Depth = AL_CHORUS_DEFAULT_DEPTH; + effect->Props.Chorus.Feedback = AL_CHORUS_DEFAULT_FEEDBACK; + effect->Props.Chorus.Delay = AL_CHORUS_DEFAULT_DELAY; + effect->vtab = &ALchorus_vtable; + break; + case AL_EFFECT_COMPRESSOR: + effect->Props.Compressor.OnOff = AL_COMPRESSOR_DEFAULT_ONOFF; + effect->vtab = &ALcompressor_vtable; + break; + case AL_EFFECT_DISTORTION: + effect->Props.Distortion.Edge = AL_DISTORTION_DEFAULT_EDGE; + effect->Props.Distortion.Gain = AL_DISTORTION_DEFAULT_GAIN; + effect->Props.Distortion.LowpassCutoff = AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF; + effect->Props.Distortion.EQCenter = AL_DISTORTION_DEFAULT_EQCENTER; + effect->Props.Distortion.EQBandwidth = AL_DISTORTION_DEFAULT_EQBANDWIDTH; + effect->vtab = &ALdistortion_vtable; + break; + case AL_EFFECT_ECHO: + effect->Props.Echo.Delay = AL_ECHO_DEFAULT_DELAY; + effect->Props.Echo.LRDelay = AL_ECHO_DEFAULT_LRDELAY; + effect->Props.Echo.Damping = AL_ECHO_DEFAULT_DAMPING; + effect->Props.Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK; + effect->Props.Echo.Spread = AL_ECHO_DEFAULT_SPREAD; + effect->vtab = &ALecho_vtable; + break; + case AL_EFFECT_EQUALIZER: + effect->Props.Equalizer.LowCutoff = AL_EQUALIZER_DEFAULT_LOW_CUTOFF; + effect->Props.Equalizer.LowGain = AL_EQUALIZER_DEFAULT_LOW_GAIN; + effect->Props.Equalizer.Mid1Center = AL_EQUALIZER_DEFAULT_MID1_CENTER; + effect->Props.Equalizer.Mid1Gain = AL_EQUALIZER_DEFAULT_MID1_GAIN; + effect->Props.Equalizer.Mid1Width = AL_EQUALIZER_DEFAULT_MID1_WIDTH; + effect->Props.Equalizer.Mid2Center = AL_EQUALIZER_DEFAULT_MID2_CENTER; + effect->Props.Equalizer.Mid2Gain = AL_EQUALIZER_DEFAULT_MID2_GAIN; + effect->Props.Equalizer.Mid2Width = AL_EQUALIZER_DEFAULT_MID2_WIDTH; + effect->Props.Equalizer.HighCutoff = AL_EQUALIZER_DEFAULT_HIGH_CUTOFF; + effect->Props.Equalizer.HighGain = AL_EQUALIZER_DEFAULT_HIGH_GAIN; + effect->vtab = &ALequalizer_vtable; + break; + case AL_EFFECT_FLANGER: + effect->Props.Chorus.Waveform = AL_FLANGER_DEFAULT_WAVEFORM; + effect->Props.Chorus.Phase = AL_FLANGER_DEFAULT_PHASE; + effect->Props.Chorus.Rate = AL_FLANGER_DEFAULT_RATE; + effect->Props.Chorus.Depth = AL_FLANGER_DEFAULT_DEPTH; + effect->Props.Chorus.Feedback = AL_FLANGER_DEFAULT_FEEDBACK; + effect->Props.Chorus.Delay = AL_FLANGER_DEFAULT_DELAY; + effect->vtab = &ALflanger_vtable; + break; + case AL_EFFECT_FREQUENCY_SHIFTER: + effect->Props.Fshifter.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY; + effect->Props.Fshifter.LeftDirection = AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION; + effect->Props.Fshifter.RightDirection = AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION; + effect->vtab = &ALfshifter_vtable; + break; + case AL_EFFECT_RING_MODULATOR: + effect->Props.Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY; + effect->Props.Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF; + effect->Props.Modulator.Waveform = AL_RING_MODULATOR_DEFAULT_WAVEFORM; + effect->vtab = &ALmodulator_vtable; + break; + case AL_EFFECT_PITCH_SHIFTER: + effect->Props.Pshifter.CoarseTune = AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE; + effect->Props.Pshifter.FineTune = AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE; + effect->vtab = &ALpshifter_vtable; + break; + case AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT: + case AL_EFFECT_DEDICATED_DIALOGUE: + effect->Props.Dedicated.Gain = 1.0f; + effect->vtab = &ALdedicated_vtable; + break; + default: + effect->vtab = &ALnull_vtable; + break; + } + effect->type = type; +} + +ALeffect *AllocEffect(ALCcontext *context) +{ + ALCdevice *device = context->Device; + almtx_lock(&device->EffectLock); + + auto sublist = std::find_if(device->EffectList.begin(), device->EffectList.end(), + [](const EffectSubList &entry) noexcept -> bool + { return entry.FreeMask != 0; } + ); + + auto lidx = std::distance(device->EffectList.begin(), sublist); + ALeffect *effect{nullptr}; + ALsizei slidx{0}; + if(LIKELY(sublist != device->EffectList.end())) + { + slidx = CTZ64(sublist->FreeMask); + effect = sublist->Effects + slidx; + } + else + { + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(device->EffectList.size() >= 1<<25)) + { + almtx_unlock(&device->EffectLock); + alSetError(context, AL_OUT_OF_MEMORY, "Too many effects allocated"); + return NULL; + } + device->EffectList.emplace_back(); + sublist = device->EffectList.end() - 1; + sublist->FreeMask = ~U64(0); + sublist->Effects = static_cast(al_calloc(16, sizeof(ALeffect)*64)); + if(UNLIKELY(!sublist->Effects)) + { + device->EffectList.pop_back(); + almtx_unlock(&device->EffectLock); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect batch"); + return NULL; + } + + slidx = 0; + effect = sublist->Effects + slidx; + } + + effect = new (effect) ALeffect{}; + InitEffectParams(effect, AL_EFFECT_NULL); + + /* Add 1 to avoid effect ID 0. */ + effect->id = ((lidx<<6) | slidx) + 1; + + sublist->FreeMask &= ~(U64(1)<EffectLock); + + return effect; +} + +void FreeEffect(ALCdevice *device, ALeffect *effect) +{ + ALuint id = effect->id - 1; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; + + effect->~ALeffect(); + + device->EffectList[lidx].FreeMask |= U64(1) << slidx; +} + +inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) { ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; @@ -71,127 +288,140 @@ static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) return sublist.Effects + slidx; } +} // namespace AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) { - ALCcontext *context; - ALsizei cur; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; + if(UNLIKELY(n < 0)) + { + alSetError(context.get(), AL_INVALID_VALUE, "Generating %d effects", n); + return; + } - if(n < 0) - alSetError(context, AL_INVALID_VALUE, "Generating %d effects", n); - else for(cur = 0;cur < n;cur++) + if(LIKELY(n == 1)) { - ALeffect *effect = AllocEffect(context); - if(!effect) - { - alDeleteEffects(cur, effects); - break; - } - effects[cur] = effect->id; + /* Special handling for the easy and normal case. */ + ALeffect *effect = AllocEffect(context.get()); + if(effect) effects[0] = effect->id; } + else if(n > 1) + { + /* Store the allocated buffer IDs in a separate local list, to avoid + * modifying the user storage in case of failure. + */ + std::vector ids; + ids.reserve(n); + do { + ALeffect *effect = AllocEffect(context.get()); + if(!effect) + { + alDeleteEffects(ids.size(), ids.data()); + return; + } - ALCcontext_DecRef(context); + ids.emplace_back(effect->id); + } while(--n); + std::copy(ids.begin(), ids.end(), effects); + } } AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects) { - ALCdevice *device; - ALCcontext *context; - ALeffect *effect; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - LockEffectList(device); - if(n < 0) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effects", n); - for(i = 0;i < n;i++) + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(UNLIKELY(n < 0)) { - if(effects[i] && LookupEffect(device, effects[i]) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect ID %u", effects[i]); + alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d effects", n); + return; } - for(i = 0;i < n;i++) + if(UNLIKELY(n == 0)) + return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + + /* First try to find any effects that are invalid. */ + const ALuint *effects_end = effects + n; + auto inveffect = std::find_if(effects, effects_end, + [device, &context](ALuint eid) -> bool + { + if(!eid) return false; + ALeffect *effect{LookupEffect(device, eid)}; + if(UNLIKELY(!effect)) + { + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", eid); + return true; + } + return false; + } + ); + if(LIKELY(inveffect == effects_end)) { - if((effect=LookupEffect(device, effects[i])) != NULL) - FreeEffect(device, effect); + /* All good. Delete non-0 effect IDs. */ + std::for_each(effects, effects_end, + [device](ALuint eid) -> void + { + ALeffect *effect{eid ? LookupEffect(device, eid) : nullptr}; + if(effect) FreeEffect(device, effect); + } + ); } - -done: - UnlockEffectList(device); - ALCcontext_DecRef(context); } AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect) { - ALCcontext *Context; - ALboolean result; - - Context = GetContextRef(); - if(!Context) return AL_FALSE; - - LockEffectList(Context->Device); - result = ((!effect || LookupEffect(Context->Device, effect)) ? - AL_TRUE : AL_FALSE); - UnlockEffectList(Context->Device); - - ALCcontext_DecRef(Context); - - return result; + ContextRef context{GetContextRef()}; + if(LIKELY(context)) + { + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + if(!effect || LookupEffect(device, effect)) + return AL_TRUE; + } + return AL_FALSE; } AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) { - ALCcontext *Context; - ALCdevice *Device; - ALeffect *ALEffect; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Context = GetContextRef(); - if(!Context) return; + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; - Device = Context->Device; - LockEffectList(Device); - if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); + ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); else { if(param == AL_EFFECT_TYPE) { ALboolean isOk = (value == AL_EFFECT_NULL); - ALint i; - for(i = 0;!isOk && i < EFFECTLIST_SIZE;i++) + for(ALsizei i{0};!isOk && i < EFFECTLIST_SIZE;i++) { - if(value == EffectList[i].val && - !DisabledEffects[EffectList[i].type]) + if(value == EffectList[i].val && !DisabledEffects[EffectList[i].type]) isOk = AL_TRUE; } if(isOk) - InitEffectParams(ALEffect, value); + InitEffectParams(aleffect, value); else - alSetError(Context, AL_INVALID_VALUE, "Effect type 0x%04x not supported", value); + alSetError(context.get(), AL_INVALID_VALUE, "Effect type 0x%04x not supported", value); } else { /* Call the appropriate handler */ - ALeffect_setParami(ALEffect, Context, param, value); + ALeffect_setParami(aleffect, context.get(), param, value); } } - UnlockEffectList(Device); - - ALCcontext_DecRef(Context); } AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *values) { - ALCcontext *Context; - ALCdevice *Device; - ALeffect *ALEffect; - switch(param) { case AL_EFFECT_TYPE: @@ -199,103 +429,83 @@ AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *v return; } - Context = GetContextRef(); - if(!Context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Device = Context->Device; - LockEffectList(Device); - if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + + ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); else { /* Call the appropriate handler */ - ALeffect_setParamiv(ALEffect, Context, param, values); + ALeffect_setParamiv(aleffect, context.get(), param, values); } - UnlockEffectList(Device); - - ALCcontext_DecRef(Context); } AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value) { - ALCcontext *Context; - ALCdevice *Device; - ALeffect *ALEffect; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Context = GetContextRef(); - if(!Context) return; + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; - Device = Context->Device; - LockEffectList(Device); - if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); + ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); else { /* Call the appropriate handler */ - ALeffect_setParamf(ALEffect, Context, param, value); + ALeffect_setParamf(aleffect, context.get(), param, value); } - UnlockEffectList(Device); - - ALCcontext_DecRef(Context); } AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *values) { - ALCcontext *Context; - ALCdevice *Device; - ALeffect *ALEffect; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Context = GetContextRef(); - if(!Context) return; + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; - Device = Context->Device; - LockEffectList(Device); - if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); + ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); else { /* Call the appropriate handler */ - ALeffect_setParamfv(ALEffect, Context, param, values); + ALeffect_setParamfv(aleffect, context.get(), param, values); } - UnlockEffectList(Device); - - ALCcontext_DecRef(Context); } AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value) { - ALCcontext *Context; - ALCdevice *Device; - ALeffect *ALEffect; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Context = GetContextRef(); - if(!Context) return; + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; - Device = Context->Device; - LockEffectList(Device); - if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); + const ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); else { if(param == AL_EFFECT_TYPE) - *value = ALEffect->type; + *value = aleffect->type; else { /* Call the appropriate handler */ - ALeffect_getParami(ALEffect, Context, param, value); + ALeffect_getParami(aleffect, context.get(), param, value); } } - UnlockEffectList(Device); - - ALCcontext_DecRef(Context); } AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *values) { - ALCcontext *Context; - ALCdevice *Device; - ALeffect *ALEffect; - switch(param) { case AL_EFFECT_TYPE: @@ -303,67 +513,56 @@ AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *valu return; } - Context = GetContextRef(); - if(!Context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; - Device = Context->Device; - LockEffectList(Device); - if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); + const ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); else { /* Call the appropriate handler */ - ALeffect_getParamiv(ALEffect, Context, param, values); + ALeffect_getParamiv(aleffect, context.get(), param, values); } - UnlockEffectList(Device); - - ALCcontext_DecRef(Context); } AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *value) { - ALCcontext *Context; - ALCdevice *Device; - ALeffect *ALEffect; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Context = GetContextRef(); - if(!Context) return; + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; - Device = Context->Device; - LockEffectList(Device); - if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); + const ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); else { /* Call the appropriate handler */ - ALeffect_getParamf(ALEffect, Context, param, value); + ALeffect_getParamf(aleffect, context.get(), param, value); } - UnlockEffectList(Device); - - ALCcontext_DecRef(Context); } AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *values) { - ALCcontext *Context; - ALCdevice *Device; - ALeffect *ALEffect; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - Context = GetContextRef(); - if(!Context) return; + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; - Device = Context->Device; - LockEffectList(Device); - if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); + const ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); else { /* Call the appropriate handler */ - ALeffect_getParamfv(ALEffect, Context, param, values); + ALeffect_getParamfv(aleffect, context.get(), param, values); } - UnlockEffectList(Device); - - ALCcontext_DecRef(Context); } @@ -372,74 +571,6 @@ void InitEffect(ALeffect *effect) InitEffectParams(effect, AL_EFFECT_NULL); } -static ALeffect *AllocEffect(ALCcontext *context) -{ - ALCdevice *device = context->Device; - almtx_lock(&device->EffectLock); - - auto sublist = std::find_if(device->EffectList.begin(), device->EffectList.end(), - [](const EffectSubList &entry) noexcept -> bool - { return entry.FreeMask != 0; } - ); - - auto lidx = std::distance(device->EffectList.begin(), sublist); - ALeffect *effect{nullptr}; - ALsizei slidx{0}; - if(LIKELY(sublist != device->EffectList.end())) - { - slidx = CTZ64(sublist->FreeMask); - effect = sublist->Effects + slidx; - } - else - { - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ - if(UNLIKELY(device->EffectList.size() >= 1<<25)) - { - almtx_unlock(&device->EffectLock); - alSetError(context, AL_OUT_OF_MEMORY, "Too many effects allocated"); - return NULL; - } - device->EffectList.emplace_back(); - sublist = device->EffectList.end() - 1; - sublist->FreeMask = ~U64(0); - sublist->Effects = static_cast(al_calloc(16, sizeof(ALeffect)*64)); - if(UNLIKELY(!sublist->Effects)) - { - device->EffectList.pop_back(); - almtx_unlock(&device->EffectLock); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect batch"); - return NULL; - } - - slidx = 0; - effect = sublist->Effects + slidx; - } - - effect = new (effect) ALeffect{}; - InitEffectParams(effect, AL_EFFECT_NULL); - - /* Add 1 to avoid effect ID 0. */ - effect->id = ((lidx<<6) | slidx) + 1; - - sublist->FreeMask &= ~(U64(1)<EffectLock); - - return effect; -} - -static void FreeEffect(ALCdevice *device, ALeffect *effect) -{ - ALuint id = effect->id - 1; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; - - effect->~ALeffect(); - - device->EffectList[lidx].FreeMask |= U64(1) << slidx; -} - void ReleaseALEffects(ALCdevice *device) { size_t leftover = 0; @@ -463,158 +594,6 @@ void ReleaseALEffects(ALCdevice *device) } -static void InitEffectParams(ALeffect *effect, ALenum type) -{ - switch(type) - { - case AL_EFFECT_EAXREVERB: - effect->Props.Reverb.Density = AL_EAXREVERB_DEFAULT_DENSITY; - effect->Props.Reverb.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION; - effect->Props.Reverb.Gain = AL_EAXREVERB_DEFAULT_GAIN; - effect->Props.Reverb.GainHF = AL_EAXREVERB_DEFAULT_GAINHF; - effect->Props.Reverb.GainLF = AL_EAXREVERB_DEFAULT_GAINLF; - effect->Props.Reverb.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME; - effect->Props.Reverb.DecayHFRatio = AL_EAXREVERB_DEFAULT_DECAY_HFRATIO; - effect->Props.Reverb.DecayLFRatio = AL_EAXREVERB_DEFAULT_DECAY_LFRATIO; - effect->Props.Reverb.ReflectionsGain = AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN; - effect->Props.Reverb.ReflectionsDelay = AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY; - effect->Props.Reverb.ReflectionsPan[0] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; - effect->Props.Reverb.ReflectionsPan[1] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; - effect->Props.Reverb.ReflectionsPan[2] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; - effect->Props.Reverb.LateReverbGain = AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN; - effect->Props.Reverb.LateReverbDelay = AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY; - effect->Props.Reverb.LateReverbPan[0] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; - effect->Props.Reverb.LateReverbPan[1] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; - effect->Props.Reverb.LateReverbPan[2] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; - effect->Props.Reverb.EchoTime = AL_EAXREVERB_DEFAULT_ECHO_TIME; - effect->Props.Reverb.EchoDepth = AL_EAXREVERB_DEFAULT_ECHO_DEPTH; - effect->Props.Reverb.ModulationTime = AL_EAXREVERB_DEFAULT_MODULATION_TIME; - effect->Props.Reverb.ModulationDepth = AL_EAXREVERB_DEFAULT_MODULATION_DEPTH; - effect->Props.Reverb.AirAbsorptionGainHF = AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF; - effect->Props.Reverb.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE; - effect->Props.Reverb.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE; - effect->Props.Reverb.RoomRolloffFactor = AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; - effect->Props.Reverb.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT; - effect->vtab = &ALeaxreverb_vtable; - break; - case AL_EFFECT_REVERB: - effect->Props.Reverb.Density = AL_REVERB_DEFAULT_DENSITY; - effect->Props.Reverb.Diffusion = AL_REVERB_DEFAULT_DIFFUSION; - effect->Props.Reverb.Gain = AL_REVERB_DEFAULT_GAIN; - effect->Props.Reverb.GainHF = AL_REVERB_DEFAULT_GAINHF; - effect->Props.Reverb.GainLF = 1.0f; - effect->Props.Reverb.DecayTime = AL_REVERB_DEFAULT_DECAY_TIME; - effect->Props.Reverb.DecayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO; - effect->Props.Reverb.DecayLFRatio = 1.0f; - effect->Props.Reverb.ReflectionsGain = AL_REVERB_DEFAULT_REFLECTIONS_GAIN; - effect->Props.Reverb.ReflectionsDelay = AL_REVERB_DEFAULT_REFLECTIONS_DELAY; - effect->Props.Reverb.ReflectionsPan[0] = 0.0f; - effect->Props.Reverb.ReflectionsPan[1] = 0.0f; - effect->Props.Reverb.ReflectionsPan[2] = 0.0f; - effect->Props.Reverb.LateReverbGain = AL_REVERB_DEFAULT_LATE_REVERB_GAIN; - effect->Props.Reverb.LateReverbDelay = AL_REVERB_DEFAULT_LATE_REVERB_DELAY; - effect->Props.Reverb.LateReverbPan[0] = 0.0f; - effect->Props.Reverb.LateReverbPan[1] = 0.0f; - effect->Props.Reverb.LateReverbPan[2] = 0.0f; - effect->Props.Reverb.EchoTime = 0.25f; - effect->Props.Reverb.EchoDepth = 0.0f; - effect->Props.Reverb.ModulationTime = 0.25f; - effect->Props.Reverb.ModulationDepth = 0.0f; - effect->Props.Reverb.AirAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF; - effect->Props.Reverb.HFReference = 5000.0f; - effect->Props.Reverb.LFReference = 250.0f; - effect->Props.Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; - effect->Props.Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT; - effect->vtab = &ALreverb_vtable; - break; - case AL_EFFECT_AUTOWAH: - effect->Props.Autowah.AttackTime = AL_AUTOWAH_DEFAULT_ATTACK_TIME; - effect->Props.Autowah.ReleaseTime = AL_AUTOWAH_DEFAULT_RELEASE_TIME; - effect->Props.Autowah.Resonance = AL_AUTOWAH_DEFAULT_RESONANCE; - effect->Props.Autowah.PeakGain = AL_AUTOWAH_DEFAULT_PEAK_GAIN; - effect->vtab = &ALautowah_vtable; - break; - case AL_EFFECT_CHORUS: - effect->Props.Chorus.Waveform = AL_CHORUS_DEFAULT_WAVEFORM; - effect->Props.Chorus.Phase = AL_CHORUS_DEFAULT_PHASE; - effect->Props.Chorus.Rate = AL_CHORUS_DEFAULT_RATE; - effect->Props.Chorus.Depth = AL_CHORUS_DEFAULT_DEPTH; - effect->Props.Chorus.Feedback = AL_CHORUS_DEFAULT_FEEDBACK; - effect->Props.Chorus.Delay = AL_CHORUS_DEFAULT_DELAY; - effect->vtab = &ALchorus_vtable; - break; - case AL_EFFECT_COMPRESSOR: - effect->Props.Compressor.OnOff = AL_COMPRESSOR_DEFAULT_ONOFF; - effect->vtab = &ALcompressor_vtable; - break; - case AL_EFFECT_DISTORTION: - effect->Props.Distortion.Edge = AL_DISTORTION_DEFAULT_EDGE; - effect->Props.Distortion.Gain = AL_DISTORTION_DEFAULT_GAIN; - effect->Props.Distortion.LowpassCutoff = AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF; - effect->Props.Distortion.EQCenter = AL_DISTORTION_DEFAULT_EQCENTER; - effect->Props.Distortion.EQBandwidth = AL_DISTORTION_DEFAULT_EQBANDWIDTH; - effect->vtab = &ALdistortion_vtable; - break; - case AL_EFFECT_ECHO: - effect->Props.Echo.Delay = AL_ECHO_DEFAULT_DELAY; - effect->Props.Echo.LRDelay = AL_ECHO_DEFAULT_LRDELAY; - effect->Props.Echo.Damping = AL_ECHO_DEFAULT_DAMPING; - effect->Props.Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK; - effect->Props.Echo.Spread = AL_ECHO_DEFAULT_SPREAD; - effect->vtab = &ALecho_vtable; - break; - case AL_EFFECT_EQUALIZER: - effect->Props.Equalizer.LowCutoff = AL_EQUALIZER_DEFAULT_LOW_CUTOFF; - effect->Props.Equalizer.LowGain = AL_EQUALIZER_DEFAULT_LOW_GAIN; - effect->Props.Equalizer.Mid1Center = AL_EQUALIZER_DEFAULT_MID1_CENTER; - effect->Props.Equalizer.Mid1Gain = AL_EQUALIZER_DEFAULT_MID1_GAIN; - effect->Props.Equalizer.Mid1Width = AL_EQUALIZER_DEFAULT_MID1_WIDTH; - effect->Props.Equalizer.Mid2Center = AL_EQUALIZER_DEFAULT_MID2_CENTER; - effect->Props.Equalizer.Mid2Gain = AL_EQUALIZER_DEFAULT_MID2_GAIN; - effect->Props.Equalizer.Mid2Width = AL_EQUALIZER_DEFAULT_MID2_WIDTH; - effect->Props.Equalizer.HighCutoff = AL_EQUALIZER_DEFAULT_HIGH_CUTOFF; - effect->Props.Equalizer.HighGain = AL_EQUALIZER_DEFAULT_HIGH_GAIN; - effect->vtab = &ALequalizer_vtable; - break; - case AL_EFFECT_FLANGER: - effect->Props.Chorus.Waveform = AL_FLANGER_DEFAULT_WAVEFORM; - effect->Props.Chorus.Phase = AL_FLANGER_DEFAULT_PHASE; - effect->Props.Chorus.Rate = AL_FLANGER_DEFAULT_RATE; - effect->Props.Chorus.Depth = AL_FLANGER_DEFAULT_DEPTH; - effect->Props.Chorus.Feedback = AL_FLANGER_DEFAULT_FEEDBACK; - effect->Props.Chorus.Delay = AL_FLANGER_DEFAULT_DELAY; - effect->vtab = &ALflanger_vtable; - break; - case AL_EFFECT_FREQUENCY_SHIFTER: - effect->Props.Fshifter.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY; - effect->Props.Fshifter.LeftDirection = AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION; - effect->Props.Fshifter.RightDirection = AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION; - effect->vtab = &ALfshifter_vtable; - break; - case AL_EFFECT_RING_MODULATOR: - effect->Props.Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY; - effect->Props.Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF; - effect->Props.Modulator.Waveform = AL_RING_MODULATOR_DEFAULT_WAVEFORM; - effect->vtab = &ALmodulator_vtable; - break; - case AL_EFFECT_PITCH_SHIFTER: - effect->Props.Pshifter.CoarseTune = AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE; - effect->Props.Pshifter.FineTune = AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE; - effect->vtab = &ALpshifter_vtable; - break; - case AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT: - case AL_EFFECT_DEDICATED_DIALOGUE: - effect->Props.Dedicated.Gain = 1.0f; - effect->vtab = &ALdedicated_vtable; - break; - default: - effect->vtab = &ALnull_vtable; - break; - } - effect->type = type; -} - - #include "AL/efx-presets.h" #define DECL(x) { #x, EFX_REVERB_PRESET_##x } -- cgit v1.2.3 From bd8db0d27b50644dad97aa74f8f207d30d6b9490 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 24 Nov 2018 14:07:32 -0800 Subject: Make GetContextRef return a ContextRef --- Alc/alc.cpp | 8 +++----- Alc/alcontext.h | 3 ++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 46b371ef..40bf25b4 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2769,10 +2769,9 @@ static ContextRef VerifyContext(ALCcontext *context) /* GetContextRef * - * Returns the currently active context for this thread, and adds a reference - * without locking it. + * Returns a new reference to the currently active context for this thread. */ -ALCcontext *GetContextRef(void) +ContextRef GetContextRef(void) { ALCcontext *context{LocalContext.get()}; if(context) @@ -2783,8 +2782,7 @@ ALCcontext *GetContextRef(void) context = GlobalContext.load(std::memory_order_acquire); if(context) ALCcontext_IncRef(context); } - - return context; + return ContextRef{context}; } diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 9845b686..c9bdddc7 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -127,7 +127,6 @@ struct ALCcontext_struct { DEF_NEWDEL(ALCcontext) }; -ALCcontext *GetContextRef(void); void ALCcontext_DecRef(ALCcontext *context); void UpdateContextProps(ALCcontext *context); @@ -179,6 +178,8 @@ public: } }; +ContextRef GetContextRef(void); + struct ALcontextProps { ALfloat DopplerFactor; -- cgit v1.2.3 From 16a60dc371254ba4936f4f5c13c32d060b9911ac Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 24 Nov 2018 15:30:28 -0800 Subject: Avoid an extraneous boolean --- Alc/mixvoice.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 9620b214..c902c66a 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -315,7 +315,6 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize ALsizei OutPos; ALsizei IrSize; bool isplaying; - bool firstpass; bool isstatic; ALsizei chan; ALsizei send; @@ -337,7 +336,6 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize Resample_copy_C : voice->Resampler); Counter = (voice->Flags&VOICE_IS_FADING) ? SamplesToDo : 0; - firstpass = true; OutPos = 0; do { @@ -595,11 +593,9 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize parms->Hrtf.Old = parms->Hrtf.Target; parms->Hrtf.Old.Gain = 0.0f; } - else if(firstpass) + else if(OutPos == 0) { - ALfloat gain; - - /* Fade between the coefficients over 128 samples. */ + /* First mixing pass, fade between the coefficients. */ fademix = mini(DstBufferSize, 128); /* The new coefficients need to fade in completely @@ -608,8 +604,8 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize * and new target gains given how much of the fade time * this mix handles. */ - gain = lerp(parms->Hrtf.Old.Gain, parms->Hrtf.Target.Gain, - minf(1.0f, (ALfloat)fademix/Counter)); + ALfloat gain{lerp(parms->Hrtf.Old.Gain, parms->Hrtf.Target.Gain, + minf(1.0f, (ALfloat)fademix/Counter))}; hrtfparams.Coeffs = parms->Hrtf.Target.Coeffs; hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; @@ -689,7 +685,6 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize OutPos += DstBufferSize; voice->Offset += DstBufferSize; Counter = maxi(DstBufferSize, Counter) - DstBufferSize; - firstpass = false; if(isstatic) { -- cgit v1.2.3 From 9e10f632c7a5d66b0f896753e197970eec3ab7cf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 24 Nov 2018 16:58:49 -0800 Subject: Replace remaining uses of std::vector with al::vector Which uses a custom allocator that uses our allocation functions. --- Alc/alc.cpp | 4 ++-- Alc/alconfig.cpp | 2 +- Alc/backends/alsa.cpp | 14 +++++++------- Alc/backends/dsound.cpp | 8 ++++---- Alc/backends/oss.cpp | 14 +++++++------- Alc/backends/pulseaudio.cpp | 6 +++--- Alc/backends/wasapi.cpp | 12 ++++++------ Alc/backends/wave.cpp | 2 +- Alc/backends/winmm.cpp | 6 +++--- Alc/helpers.cpp | 18 +++++++++--------- Alc/hrtf.cpp | 28 ++++++++++++++-------------- OpenAL32/Include/alMain.h | 2 +- OpenAL32/alBuffer.cpp | 2 +- OpenAL32/alEffect.cpp | 2 +- OpenAL32/alFilter.cpp | 2 +- 15 files changed, 61 insertions(+), 61 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 40bf25b4..434e4660 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -3362,7 +3362,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, alcSetError(dev.get(), ALC_INVALID_VALUE); else if(!dev || dev->Type == Capture) { - std::vector ivals(size); + al::vector ivals(size); size = GetIntegerv(dev.get(), pname, size, ivals.data()); std::copy(ivals.begin(), ivals.begin()+size, values); } @@ -3482,7 +3482,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, break; default: - std::vector ivals(size); + al::vector ivals(size); size = GetIntegerv(dev.get(), pname, size, ivals.data()); std::copy(ivals.begin(), ivals.begin()+size, values); break; diff --git a/Alc/alconfig.cpp b/Alc/alconfig.cpp index 73ea0458..a6304ce7 100644 --- a/Alc/alconfig.cpp +++ b/Alc/alconfig.cpp @@ -59,7 +59,7 @@ struct ConfigEntry { : key{std::forward(key_)}, value{std::forward(val_)} { } }; -std::vector ConfOpts; +al::vector ConfOpts; std::string &lstrip(std::string &line) diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index 35c1f834..1a048fc7 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -253,8 +253,8 @@ struct DevMap { { } }; -std::vector PlaybackDevices; -std::vector CaptureDevices; +al::vector PlaybackDevices; +al::vector CaptureDevices; const char *prefix_name(snd_pcm_stream_t stream) @@ -263,9 +263,9 @@ const char *prefix_name(snd_pcm_stream_t stream) return (stream==SND_PCM_STREAM_PLAYBACK) ? "device-prefix" : "capture-prefix"; } -std::vector probe_devices(snd_pcm_stream_t stream) +al::vector probe_devices(snd_pcm_stream_t stream) { - std::vector devlist; + al::vector devlist; snd_ctl_card_info_t *info; snd_ctl_card_info_malloc(&info); @@ -425,7 +425,7 @@ int verify_state(snd_pcm_t *handle) struct ALCplaybackAlsa final : public ALCbackend { snd_pcm_t *pcmHandle{nullptr}; - std::vector buffer; + al::vector buffer; std::atomic killNow{AL_TRUE}; std::thread thread; @@ -926,7 +926,7 @@ ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self) struct ALCcaptureAlsa final : public ALCbackend { snd_pcm_t *pcmHandle{nullptr}; - std::vector buffer; + al::vector buffer; bool doCapture{false}; ll_ringbuffer_t *ring{nullptr}; @@ -1129,7 +1129,7 @@ void ALCcaptureAlsa_stop(ALCcaptureAlsa *self) { /* The ring buffer implicitly captures when checking availability. * Direct access needs to explicitly capture it into temp storage. */ - std::vector temp(snd_pcm_frames_to_bytes(self->pcmHandle, avail)); + al::vector temp(snd_pcm_frames_to_bytes(self->pcmHandle, avail)); ALCcaptureAlsa_captureSamples(self, temp.data(), avail); self->buffer = std::move(temp); } diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 085dab90..4f1186ee 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -142,10 +142,10 @@ struct DevMap { { } }; -std::vector PlaybackDevices; -std::vector CaptureDevices; +al::vector PlaybackDevices; +al::vector CaptureDevices; -bool checkName(const std::vector &list, const std::string &name) +bool checkName(const al::vector &list, const std::string &name) { return std::find_if(list.cbegin(), list.cend(), [&name](const DevMap &entry) -> bool @@ -158,7 +158,7 @@ BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR* UNUS if(!guid) return TRUE; - auto& devices = *reinterpret_cast*>(data); + auto& devices = *reinterpret_cast*>(data); const std::string basename{DEVNAME_HEAD + wstr_to_utf8(desc)}; int count{1}; diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 3985cd27..7b8d234a 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -91,7 +91,7 @@ struct DevMap { { } }; -bool checkName(const std::vector &list, const std::string &name) +bool checkName(const al::vector &list, const std::string &name) { return std::find_if(list.cbegin(), list.cend(), [&name](const DevMap &entry) -> bool @@ -99,22 +99,22 @@ bool checkName(const std::vector &list, const std::string &name) ) != list.cend(); } -std::vector PlaybackDevices; -std::vector CaptureDevices; +al::vector PlaybackDevices; +al::vector CaptureDevices; #ifdef ALC_OSS_COMPAT #define DSP_CAP_OUTPUT 0x00020000 #define DSP_CAP_INPUT 0x00010000 -void ALCossListPopulate(std::vector *devlist, int type) +void ALCossListPopulate(al::vector *devlist, int type) { devlist->emplace_back(DefaultName, (type==DSP_CAP_INPUT) ? DefaultCapture : DefaultPlayback); } #else -void ALCossListAppend(std::vector *list, const char *handle, size_t hlen, const char *path, size_t plen) +void ALCossListAppend(al::vector *list, const char *handle, size_t hlen, const char *path, size_t plen) { #ifdef ALC_OSS_DEVNODE_TRUC for(size_t i{0};i < plen;i++) @@ -160,7 +160,7 @@ void ALCossListAppend(std::vector *list, const char *handle, size_t hlen TRACE("Got device \"%s\", \"%s\"\n", entry.name.c_str(), entry.device_name.c_str()); } -void ALCossListPopulate(std::vector *devlist, int type_flag) +void ALCossListPopulate(al::vector *devlist, int type_flag) { int fd{open("/dev/mixer", O_RDONLY)}; if(fd < 0) @@ -243,7 +243,7 @@ int log2i(ALCuint x) struct ALCplaybackOSS final : public ALCbackend { int fd{-1}; - std::vector mix_data; + al::vector mix_data; std::atomic killNow{AL_TRUE}; std::thread thread; diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 9563cdd4..c64c3ed7 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -511,7 +511,7 @@ struct DevMap { { } }; -bool checkName(const std::vector &list, const std::string &name) +bool checkName(const al::vector &list, const std::string &name) { return std::find_if(list.cbegin(), list.cend(), [&name](const DevMap &entry) -> bool @@ -519,8 +519,8 @@ bool checkName(const std::vector &list, const std::string &name) ) != list.cend(); } -std::vector PlaybackDevices; -std::vector CaptureDevices; +al::vector PlaybackDevices; +al::vector CaptureDevices; struct PulsePlayback final : public ALCbackend { diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 52f324f7..3d6c3e8c 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -123,7 +123,7 @@ struct DevMap { { } }; -bool checkName(const std::vector &list, const std::string &name) +bool checkName(const al::vector &list, const std::string &name) { return std::find_if(list.cbegin(), list.cend(), [&name](const DevMap &entry) -> bool @@ -131,8 +131,8 @@ bool checkName(const std::vector &list, const std::string &name) ) != list.cend(); } -std::vector PlaybackDevices; -std::vector CaptureDevices; +al::vector PlaybackDevices; +al::vector CaptureDevices; HANDLE ThreadHdl; @@ -251,7 +251,7 @@ void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfactor) } -void add_device(IMMDevice *device, const WCHAR *devid, std::vector &list) +void add_device(IMMDevice *device, const WCHAR *devid, al::vector &list) { std::string basename, guidstr; std::tie(basename, guidstr) = get_device_name_and_guid(device); @@ -285,7 +285,7 @@ WCHAR *get_device_id(IMMDevice *device) return devid; } -HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, std::vector &list) +HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, al::vector &list) { IMMDeviceCollection *coll; HRESULT hr = devenum->EnumAudioEndpoints(flowdir, DEVICE_STATE_ACTIVE, &coll); @@ -1248,7 +1248,7 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) althrd_setname(RECORD_THREAD_NAME); - std::vector samples; + al::vector samples; while(!self->mKillNow.load(std::memory_order_relaxed)) { UINT32 avail; diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index d1356338..d9219336 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -82,7 +82,7 @@ struct ALCwaveBackend final : public ALCbackend { FILE *mFile; long mDataStart; - std::vector mBuffer; + al::vector mBuffer; ATOMIC(ALenum) killNow; std::thread thread; diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index f17b5d1f..f1aee5b3 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -51,10 +51,10 @@ namespace { #define DEVNAME_HEAD "OpenAL Soft on " -std::vector PlaybackDevices; -std::vector CaptureDevices; +al::vector PlaybackDevices; +al::vector CaptureDevices; -bool checkName(const std::vector &list, const std::string &name) +bool checkName(const al::vector &list, const std::string &name) { return std::find(list.cbegin(), list.cend(), name) != list.cend(); } void ProbePlaybackDevices(void) diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index 658c7d09..d06a4807 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -315,7 +315,7 @@ PathNamePair GetProcBinary() { PathNamePair ret; - std::vector fullpath(256); + al::vector fullpath(256); DWORD len; while((len=GetModuleFileNameW(nullptr, fullpath.data(), fullpath.size())) == fullpath.size()) fullpath.resize(fullpath.size() << 1); @@ -379,7 +379,7 @@ void al_print(const char *type, const char *func, const char *fmt, ...) static inline int is_slash(int c) { return (c == '\\' || c == '/'); } -static void DirectorySearch(const char *path, const char *ext, std::vector *const results) +static void DirectorySearch(const char *path, const char *ext, al::vector *const results) { std::string pathstr{path}; pathstr += "\\*"; @@ -406,13 +406,13 @@ static void DirectorySearch(const char *path, const char *ext, std::vector SearchDataFiles(const char *ext, const char *subdir) +al::vector SearchDataFiles(const char *ext, const char *subdir) { static std::mutex search_lock; std::lock_guard _{search_lock}; /* If the path is absolute, use it directly. */ - std::vector results; + al::vector results; if(isalpha(subdir[0]) && subdir[1] == ':' && is_slash(subdir[2])) { std::string path{subdir}; @@ -481,7 +481,7 @@ void SetRTPriority(void) PathNamePair GetProcBinary() { PathNamePair ret; - std::vector pathname; + al::vector pathname; #ifdef __FreeBSD__ size_t pathlen; @@ -598,7 +598,7 @@ void al_print(const char *type, const char *func, const char *fmt, ...) } -static void DirectorySearch(const char *path, const char *ext, std::vector *const results) +static void DirectorySearch(const char *path, const char *ext, al::vector *const results) { TRACE("Searching %s for *%s\n", path, ext); DIR *dir{opendir(path)}; @@ -632,12 +632,12 @@ static void DirectorySearch(const char *path, const char *ext, std::vector SearchDataFiles(const char *ext, const char *subdir) +al::vector SearchDataFiles(const char *ext, const char *subdir) { static std::mutex search_lock; std::lock_guard _{search_lock}; - std::vector results; + al::vector results; if(subdir[0] == '/') { DirectorySearch(subdir, ext, &results); @@ -650,7 +650,7 @@ std::vector SearchDataFiles(const char *ext, const char *subdir) DirectorySearch(str, ext, &results); else { - std::vector cwdbuf(256); + al::vector cwdbuf(256); while(!getcwd(cwdbuf.data(), cwdbuf.size())) { if(errno != ERANGE) diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 034d5a49..19919717 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -281,7 +281,7 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N #define NUM_BANDS 2 ALsizei min_delay{HRTF_HISTORY_LENGTH}; ALsizei max_delay{0}; - std::vector idx(AmbiCount); + al::vector idx(AmbiCount); for(ALsizei c{0};c < AmbiCount;c++) { ALuint evidx, azidx; @@ -305,7 +305,7 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N max_delay = maxi(max_delay, maxi(Hrtf->delays[idx[c]][0], Hrtf->delays[idx[c]][1])); } - std::vector,HRIR_LENGTH>> tmpres(NumChannels); + al::vector,HRIR_LENGTH>> tmpres(NumChannels); ALfloat temps[3][HRIR_LENGTH]{}; BandSplitter splitter; @@ -549,7 +549,7 @@ struct Hrtf *LoadHrtf00(std::istream &data, const char *filename) if(failed) return nullptr; - std::vector evOffset(evCount); + al::vector evOffset(evCount); for(auto &val : evOffset) val = GetLE_ALushort(data); if(!data || data.eof()) @@ -575,7 +575,7 @@ struct Hrtf *LoadHrtf00(std::istream &data, const char *filename) if(failed) return nullptr; - std::vector azCount(evCount); + al::vector azCount(evCount); for(ALsizei i{1};i < evCount;i++) { azCount[i-1] = evOffset[i] - evOffset[i-1]; @@ -596,8 +596,8 @@ struct Hrtf *LoadHrtf00(std::istream &data, const char *filename) if(failed) return nullptr; - std::vector> coeffs(irSize*irCount); - std::vector> delays(irCount); + al::vector> coeffs(irSize*irCount); + al::vector> delays(irCount); for(auto &val : coeffs) val[0] = GetLE_ALshort(data) / 32768.0f; for(auto &val : delays) @@ -666,7 +666,7 @@ struct Hrtf *LoadHrtf01(std::istream &data, const char *filename) if(failed) return nullptr; - std::vector azCount(evCount); + al::vector azCount(evCount); data.read(reinterpret_cast(azCount.data()), evCount); if(!data || data.eof() || data.gcount() < evCount) { @@ -685,7 +685,7 @@ struct Hrtf *LoadHrtf01(std::istream &data, const char *filename) if(failed) return nullptr; - std::vector evOffset(evCount); + al::vector evOffset(evCount); evOffset[0] = 0; ALushort irCount{azCount[0]}; for(ALsizei i{1};i < evCount;i++) @@ -694,8 +694,8 @@ struct Hrtf *LoadHrtf01(std::istream &data, const char *filename) irCount += azCount[i]; } - std::vector> coeffs(irSize*irCount); - std::vector> delays(irCount); + al::vector> coeffs(irSize*irCount); + al::vector> delays(irCount); for(auto &val : coeffs) val[0] = GetLE_ALshort(data) / 32768.0f; for(auto &val : delays) @@ -785,7 +785,7 @@ struct Hrtf *LoadHrtf02(std::istream &data, const char *filename) ALushort distance{}; ALubyte evCount{}; - std::vector azCount; + al::vector azCount; for(ALsizei i{0};i < fdCount;i++) { distance = GetLE_ALushort(data); @@ -832,7 +832,7 @@ struct Hrtf *LoadHrtf02(std::istream &data, const char *filename) return nullptr; } - std::vector evOffset(evCount); + al::vector evOffset(evCount); evOffset[0] = 0; ALushort irCount{azCount[0]}; for(ALsizei i{1};i < evCount;++i) @@ -841,8 +841,8 @@ struct Hrtf *LoadHrtf02(std::istream &data, const char *filename) irCount += azCount[i]; } - std::vector> coeffs(irSize*irCount); - std::vector> delays(irCount); + al::vector> coeffs(irSize*irCount); + al::vector> delays(irCount); if(channelType == CHANTYPE_LEFTONLY) { if(sampleType == SAMPLETYPE_S16) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 1a2f7d8d..21aa1e89 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -853,6 +853,6 @@ void StartEventThrd(ALCcontext *ctx); void StopEventThrd(ALCcontext *ctx); -std::vector SearchDataFiles(const char *match, const char *subdir); +al::vector SearchDataFiles(const char *match, const char *subdir); #endif diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index 0580b33a..5c40a27e 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -439,7 +439,7 @@ AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) /* Store the allocated buffer IDs in a separate local list, to avoid * modifying the user storage in case of failure. */ - std::vector ids; + al::vector ids; ids.reserve(n); do { ALbuffer *buffer = AllocBuffer(context.get()); diff --git a/OpenAL32/alEffect.cpp b/OpenAL32/alEffect.cpp index e25e2007..2bc60e24 100644 --- a/OpenAL32/alEffect.cpp +++ b/OpenAL32/alEffect.cpp @@ -312,7 +312,7 @@ AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) /* Store the allocated buffer IDs in a separate local list, to avoid * modifying the user storage in case of failure. */ - std::vector ids; + al::vector ids; ids.reserve(n); do { ALeffect *effect = AllocEffect(context.get()); diff --git a/OpenAL32/alFilter.cpp b/OpenAL32/alFilter.cpp index bda03fae..5b15e7e0 100644 --- a/OpenAL32/alFilter.cpp +++ b/OpenAL32/alFilter.cpp @@ -373,7 +373,7 @@ AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) /* Store the allocated buffer IDs in a separate local list, to avoid * modifying the user storage in case of failure. */ - std::vector ids; + al::vector ids; ids.reserve(n); do { ALfilter *filter = AllocFilter(context.get()); -- cgit v1.2.3 From 377325e794c77f5372a8fc7991eac85809e60e64 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 24 Nov 2018 19:16:21 -0800 Subject: Use C++ methods a bit more --- Alc/alc.cpp | 14 ++++++-------- Alc/mixvoice.cpp | 21 ++++++++------------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 434e4660..ec7af970 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -3535,11 +3535,10 @@ ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar } else { - size_t i = 0; - for(i = 0;i < COUNTOF(alcFunctions);i++) + for(const auto &func : alcFunctions) { - if(strcmp(alcFunctions[i].funcName, funcName) == 0) - return alcFunctions[i].address; + if(strcmp(func.funcName, funcName) == 0) + return func.address; } } @@ -3560,11 +3559,10 @@ ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *e } else { - size_t i = 0; - for(i = 0;i < COUNTOF(alcEnumerations);i++) + for(const auto &enm : alcEnumerations) { - if(strcmp(alcEnumerations[i].enumName, enumName) == 0) - return alcEnumerations[i].value; + if(strcmp(enm.enumName, enumName) == 0) + return enm.value; } } diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index c902c66a..6cd170f9 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -367,15 +367,12 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize for(chan = 0;chan < NumChannels;chan++) { - const ALfloat *ResampledData; - ALfloat *SrcData = Device->TempBuffer[SOURCE_DATA_BUF]; - ALsizei FilledAmt; + ALfloat *SrcData{Device->TempBuffer[SOURCE_DATA_BUF]}; /* Load the previous samples into the source data first, and clear the rest. */ - memcpy(SrcData, voice->PrevSamples[chan], MAX_RESAMPLE_PADDING*sizeof(ALfloat)); - memset(SrcData+MAX_RESAMPLE_PADDING, 0, (BUFFERSIZE-MAX_RESAMPLE_PADDING)* - sizeof(ALfloat)); - FilledAmt = MAX_RESAMPLE_PADDING; + std::copy_n(voice->PrevSamples[chan], MAX_RESAMPLE_PADDING, SrcData); + std::fill_n(SrcData+MAX_RESAMPLE_PADDING, BUFFERSIZE-MAX_RESAMPLE_PADDING, 0.0f); + ALsizei FilledAmt{MAX_RESAMPLE_PADDING}; if(isstatic) { @@ -513,16 +510,14 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize } /* Store the last source samples used for next time. */ - memcpy(voice->PrevSamples[chan], - &SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS], - MAX_RESAMPLE_PADDING*sizeof(ALfloat) - ); + std::copy_n(&SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS], + MAX_RESAMPLE_PADDING, voice->PrevSamples[chan]); /* Now resample, then filter and mix to the appropriate outputs. */ - ResampledData = Resample(&voice->ResampleState, + const ALfloat *ResampledData{Resample(&voice->ResampleState, &SrcData[MAX_RESAMPLE_PADDING], DataPosFrac, increment, Device->TempBuffer[RESAMPLED_BUF], DstBufferSize - ); + )}; { DirectParams *parms = &voice->Direct.Params[chan]; const ALfloat *samples; -- cgit v1.2.3 From 71660df5e50bf44784c8bd06d80af96eb3a5a479 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 24 Nov 2018 19:54:30 -0800 Subject: Move bs2b.h to a more appropriate place --- Alc/bs2b.h | 90 +++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- OpenAL32/Include/bs2b.h | 90 ------------------------------------------------- 3 files changed, 91 insertions(+), 91 deletions(-) create mode 100644 Alc/bs2b.h delete mode 100644 OpenAL32/Include/bs2b.h diff --git a/Alc/bs2b.h b/Alc/bs2b.h new file mode 100644 index 00000000..e235e765 --- /dev/null +++ b/Alc/bs2b.h @@ -0,0 +1,90 @@ +/*- + * Copyright (c) 2005 Boris Mikhaylov + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef BS2B_H +#define BS2B_H + +#include "almalloc.h" + +/* Number of crossfeed levels */ +#define BS2B_CLEVELS 3 + +/* Normal crossfeed levels */ +#define BS2B_HIGH_CLEVEL 3 +#define BS2B_MIDDLE_CLEVEL 2 +#define BS2B_LOW_CLEVEL 1 + +/* Easy crossfeed levels */ +#define BS2B_HIGH_ECLEVEL BS2B_HIGH_CLEVEL + BS2B_CLEVELS +#define BS2B_MIDDLE_ECLEVEL BS2B_MIDDLE_CLEVEL + BS2B_CLEVELS +#define BS2B_LOW_ECLEVEL BS2B_LOW_CLEVEL + BS2B_CLEVELS + +/* Default crossfeed levels */ +#define BS2B_DEFAULT_CLEVEL BS2B_HIGH_ECLEVEL +/* Default sample rate (Hz) */ +#define BS2B_DEFAULT_SRATE 44100 + +struct bs2b { + int level; /* Crossfeed level */ + int srate; /* Sample rate (Hz) */ + + /* Lowpass IIR filter coefficients */ + float a0_lo; + float b1_lo; + + /* Highboost IIR filter coefficients */ + float a0_hi; + float a1_hi; + float b1_hi; + + /* Buffer of last filtered sample. + * [0] - first channel, [1] - second channel + */ + struct t_last_sample { + float asis; + float lo; + float hi; + } last_sample[2]; + + DEF_NEWDEL(bs2b) +}; + +/* Clear buffers and set new coefficients with new crossfeed level and sample + * rate values. + * level - crossfeed level of *LEVEL values. + * srate - sample rate by Hz. + */ +void bs2b_set_params(bs2b *bs2b, int level, int srate); + +/* Return current crossfeed level value */ +int bs2b_get_level(bs2b *bs2b); + +/* Return current sample rate value */ +int bs2b_get_srate(bs2b *bs2b); + +/* Clear buffer */ +void bs2b_clear(bs2b *bs2b); + +void bs2b_cross_feed(bs2b *bs2b, float *RESTRICT Left, float *RESTRICT Right, int SamplesToDo); + +#endif /* BS2B_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 476b241f..6bbbc561 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -714,7 +714,6 @@ SET(COMMON_OBJS common/vecmat.h ) SET(OPENAL_OBJS - OpenAL32/Include/bs2b.h OpenAL32/Include/alMain.h OpenAL32/Include/alu.h @@ -745,6 +744,7 @@ SET(ALC_OBJS Alc/alconfig.h Alc/alcontext.h Alc/bs2b.cpp + Alc/bs2b.h Alc/converter.cpp Alc/converter.h Alc/inprogext.h diff --git a/OpenAL32/Include/bs2b.h b/OpenAL32/Include/bs2b.h deleted file mode 100644 index e235e765..00000000 --- a/OpenAL32/Include/bs2b.h +++ /dev/null @@ -1,90 +0,0 @@ -/*- - * Copyright (c) 2005 Boris Mikhaylov - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef BS2B_H -#define BS2B_H - -#include "almalloc.h" - -/* Number of crossfeed levels */ -#define BS2B_CLEVELS 3 - -/* Normal crossfeed levels */ -#define BS2B_HIGH_CLEVEL 3 -#define BS2B_MIDDLE_CLEVEL 2 -#define BS2B_LOW_CLEVEL 1 - -/* Easy crossfeed levels */ -#define BS2B_HIGH_ECLEVEL BS2B_HIGH_CLEVEL + BS2B_CLEVELS -#define BS2B_MIDDLE_ECLEVEL BS2B_MIDDLE_CLEVEL + BS2B_CLEVELS -#define BS2B_LOW_ECLEVEL BS2B_LOW_CLEVEL + BS2B_CLEVELS - -/* Default crossfeed levels */ -#define BS2B_DEFAULT_CLEVEL BS2B_HIGH_ECLEVEL -/* Default sample rate (Hz) */ -#define BS2B_DEFAULT_SRATE 44100 - -struct bs2b { - int level; /* Crossfeed level */ - int srate; /* Sample rate (Hz) */ - - /* Lowpass IIR filter coefficients */ - float a0_lo; - float b1_lo; - - /* Highboost IIR filter coefficients */ - float a0_hi; - float a1_hi; - float b1_hi; - - /* Buffer of last filtered sample. - * [0] - first channel, [1] - second channel - */ - struct t_last_sample { - float asis; - float lo; - float hi; - } last_sample[2]; - - DEF_NEWDEL(bs2b) -}; - -/* Clear buffers and set new coefficients with new crossfeed level and sample - * rate values. - * level - crossfeed level of *LEVEL values. - * srate - sample rate by Hz. - */ -void bs2b_set_params(bs2b *bs2b, int level, int srate); - -/* Return current crossfeed level value */ -int bs2b_get_level(bs2b *bs2b); - -/* Return current sample rate value */ -int bs2b_get_srate(bs2b *bs2b); - -/* Clear buffer */ -void bs2b_clear(bs2b *bs2b); - -void bs2b_cross_feed(bs2b *bs2b, float *RESTRICT Left, float *RESTRICT Right, int SamplesToDo); - -#endif /* BS2B_H */ -- cgit v1.2.3 From f5f2cdaaf334a1481d063cdf03893bfad1768475 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 24 Nov 2018 21:16:53 -0800 Subject: Add a POPCNT64 macro To count the number of 1/on bits in a 64-bit value --- OpenAL32/Include/alMain.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 21aa1e89..5adabb18 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -135,13 +135,21 @@ typedef ALuint64SOFT ALuint64; #ifdef __GNUC__ #if SIZEOF_LONG == 8 +#define POPCNT64 __builtin_popcountl #define CTZ64 __builtin_ctzl #else +#define POPCNT64 __builtin_popcountll #define CTZ64 __builtin_ctzll #endif #elif defined(HAVE_BITSCANFORWARD64_INTRINSIC) +inline int msvc64_popcnt64(ALuint64 v) +{ + return __popcnt64(v); +} +#define POPCNT64 msvc64_popcnt64 + inline int msvc64_ctz64(ALuint64 v) { unsigned long idx = 64; @@ -152,6 +160,12 @@ inline int msvc64_ctz64(ALuint64 v) #elif defined(HAVE_BITSCANFORWARD_INTRINSIC) +inline int msvc_popcnt64(ALuint64 v) +{ + return __popcnt((ALuint)v) + __popcnt((ALuint)(v>>32)); +} +#define POPCNT64 msvc_popcnt64 + inline int msvc_ctz64(ALuint64 v) { unsigned long idx = 64; @@ -180,6 +194,7 @@ inline int fallback_popcnt64(ALuint64 v) v = (v + (v >> 4)) & U64(0x0f0f0f0f0f0f0f0f); return (int)((v * U64(0x0101010101010101)) >> 56); } +#define POPCNT64 fallback_popcnt64 inline int fallback_ctz64(ALuint64 value) { -- cgit v1.2.3 From 7c0605f09eabb55cd3f1b85474b31bfae584cde9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 25 Nov 2018 07:40:15 -0800 Subject: Properly initialize the sublists' freemask --- Alc/alcontext.h | 2 +- OpenAL32/Include/alMain.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/alcontext.h b/Alc/alcontext.h index c9bdddc7..b1bbd1af 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -42,7 +42,7 @@ enum class DistanceModel { }; struct SourceSubList { - uint64_t FreeMask{0u}; + uint64_t FreeMask{~uint64_t{}}; ALsource *Sources{nullptr}; /* 64 */ }; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 5adabb18..5ff1e064 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -552,17 +552,17 @@ typedef union AmbiConfig { typedef struct BufferSubList { - ALuint64 FreeMask{0u}; + ALuint64 FreeMask{~ALuint64{}}; struct ALbuffer *Buffers{nullptr}; /* 64 */ } BufferSubList; typedef struct EffectSubList { - ALuint64 FreeMask{0u}; + ALuint64 FreeMask{~ALuint64{}}; struct ALeffect *Effects{nullptr}; /* 64 */ } EffectSubList; typedef struct FilterSubList { - ALuint64 FreeMask{0u}; + ALuint64 FreeMask{~ALuint64{}}; struct ALfilter *Filters{nullptr}; /* 64 */ } FilterSubList; -- cgit v1.2.3 From bf4518fe5cbe708b3d6b44855f05b58008a48cc8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 25 Nov 2018 08:42:43 -0800 Subject: Atuomatically clean up sources with its sublist's destruction --- Alc/alc.cpp | 10 +++++----- Alc/alcontext.h | 10 ++++++++++ OpenAL32/Include/alSource.h | 2 -- OpenAL32/alSource.cpp | 29 ++++++++++------------------- 4 files changed, 25 insertions(+), 26 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index ec7af970..9919d011 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2598,11 +2598,11 @@ ALCcontext_struct::~ALCcontext_struct() al_free(ActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed)); DefaultSlot = nullptr; - ReleaseALSources(this); - std::for_each(SourceList.begin(), SourceList.end(), - [](const SourceSubList &entry) noexcept -> void - { al_free(entry.Sources); } - ); + count = 0; + for(auto &sublist : SourceList) + count += POPCNT64(~sublist.FreeMask); + if(count > 0) + WARN(SZFMT " Source%s not deleted\n", count, (count==1)?"":"s"); SourceList.clear(); NumSources = 0; almtx_destroy(&SourceLock); diff --git a/Alc/alcontext.h b/Alc/alcontext.h index b1bbd1af..c6824d78 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -44,6 +44,16 @@ enum class DistanceModel { struct SourceSubList { uint64_t FreeMask{~uint64_t{}}; ALsource *Sources{nullptr}; /* 64 */ + + SourceSubList() noexcept = default; + SourceSubList(const SourceSubList&) = delete; + SourceSubList(SourceSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Sources{rhs.Sources} + { rhs.FreeMask = ~uint64_t{}; rhs.Sources = nullptr; } + ~SourceSubList(); + + SourceSubList& operator=(const SourceSubList&) = delete; + SourceSubList& operator=(SourceSubList&& rhs) noexcept + { std::swap(FreeMask, rhs.FreeMask); std::swap(Sources, rhs.Sources); return *this; } }; /* Effect slots are rather large, and apps aren't likely to have more than one diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 4e111250..05ccdadf 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -119,8 +119,6 @@ typedef struct ALsource { void UpdateAllSourceProps(ALCcontext *context); -ALvoid ReleaseALSources(ALCcontext *Context); - #ifdef __cplusplus } #endif diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 0955d1e9..8b461982 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -3399,28 +3399,19 @@ void UpdateAllSourceProps(ALCcontext *context) ); } -/* ReleaseALSources - * - * Destroys all sources in the source map. - */ -ALvoid ReleaseALSources(ALCcontext *context) +SourceSubList::~SourceSubList() { - size_t leftover = 0; - for(auto &sublist : context->SourceList) + ALuint64 usemask = ~FreeMask; + while(usemask) { - ALuint64 usemask = ~sublist.FreeMask; - while(usemask) - { - ALsizei idx{CTZ64(usemask)}; - ALsource *source{sublist.Sources + idx}; + ALsizei idx{CTZ64(usemask)}; + ALsource *source{Sources + idx}; - source->~ALsource(); - ++leftover; + source->~ALsource(); - usemask &= ~(U64(1) << idx); - } - sublist.FreeMask = ~usemask; + usemask &= ~(U64(1) << idx); } - if(leftover > 0) - WARN("(%p) Deleted " SZFMT " Source%s\n", context, leftover, (leftover==1)?"":"s"); + FreeMask = ~usemask; + al_free(Sources); + Sources = nullptr; } -- cgit v1.2.3 From ec9736035226539d267659d2e6eba2e06c2507ca Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 25 Nov 2018 09:23:01 -0800 Subject: Avoid a separate function to clean up effect slots --- Alc/alc.cpp | 6 +++++- OpenAL32/Include/alAuxEffectSlot.h | 1 - OpenAL32/alAuxEffectSlot.cpp | 15 --------------- 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 9919d011..5fae13b3 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2619,7 +2619,11 @@ ALCcontext_struct::~ALCcontext_struct() } TRACE("Freed " SZFMT " AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s"); - ReleaseALAuxiliaryEffectSlots(this); + count = 0; + for(auto &slot : EffectSlotList) + count += slot ? 1 : 0; + if(count > 0) + WARN(SZFMT " AuxiliaryEffectSlot%s not deleted\n", count, (count==1)?"":"s"); EffectSlotList.clear(); almtx_destroy(&EffectSlotLock); diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index dd44b436..dfb57140 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -119,7 +119,6 @@ struct ALeffectslot { ALenum InitEffectSlot(ALeffectslot *slot); void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context); void UpdateAllEffectSlotProps(ALCcontext *context); -ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context); EffectStateFactory *NullStateFactory_getFactory(void); diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index 60c44f49..e7991ff0 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -656,18 +656,3 @@ void UpdateAllEffectSlotProps(ALCcontext *context) UpdateEffectSlotProps(slot, context); } } - -ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *context) -{ - size_t leftover = 0; - for(auto &entry : context->EffectSlotList) - { - if(entry) - { - entry = nullptr; - ++leftover; - } - } - if(leftover > 0) - WARN("(%p) Deleted " SZFMT " AuxiliaryEffectSlot%s\n", context, leftover, (leftover==1)?"":"s"); -} -- cgit v1.2.3 From adcdb8ce64e76a7e772b05fe3be8ce633d29aa90 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 25 Nov 2018 09:27:50 -0800 Subject: Fix an incorrect function call --- OpenAL32/alError.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/alError.cpp b/OpenAL32/alError.cpp index 39c666d2..303fbeac 100644 --- a/OpenAL32/alError.cpp +++ b/OpenAL32/alError.cpp @@ -40,7 +40,7 @@ void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) va_list args; va_start(args, msg); - int msglen{snprintf(message, sizeof(message), msg, args)}; + int msglen{vsnprintf(message, sizeof(message), msg, args)}; va_end(args); if(msglen < 0 || (size_t)msglen >= sizeof(message)) -- cgit v1.2.3 From ad2639248a8825cb2dbd0416ebacd840000fd9f0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 25 Nov 2018 10:50:42 -0800 Subject: Avoid another DECL_TEMPLATE macro --- Alc/mixer/mixer_c.cpp | 79 ++++++++++++++++++++++++++++------------------- Alc/mixer/mixer_neon.cpp | 4 +++ Alc/mixer/mixer_sse.cpp | 2 ++ Alc/mixer/mixer_sse2.cpp | 2 ++ Alc/mixer/mixer_sse41.cpp | 2 ++ 5 files changed, 58 insertions(+), 31 deletions(-) diff --git a/Alc/mixer/mixer_c.cpp b/Alc/mixer/mixer_c.cpp index 06e3ae22..99d3e343 100644 --- a/Alc/mixer/mixer_c.cpp +++ b/Alc/mixer/mixer_c.cpp @@ -9,13 +9,13 @@ #include "defs.h" -static inline ALfloat do_point(const InterpState* UNUSED(state), const ALfloat *RESTRICT vals, ALsizei UNUSED(frac)) +static inline ALfloat do_point(const InterpState*, const ALfloat *RESTRICT vals, ALsizei) noexcept { return vals[0]; } -static inline ALfloat do_lerp(const InterpState* UNUSED(state), const ALfloat *RESTRICT vals, ALsizei frac) +static inline ALfloat do_lerp(const InterpState*, const ALfloat *RESTRICT vals, ALsizei frac) noexcept { return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); } -static inline ALfloat do_cubic(const InterpState* UNUSED(state), const ALfloat *RESTRICT vals, ALsizei frac) +static inline ALfloat do_cubic(const InterpState*, const ALfloat *RESTRICT vals, ALsizei frac) noexcept { return cubic(vals[0], vals[1], vals[2], vals[3], frac * (1.0f/FRACTIONONE)); } -static inline ALfloat do_bsinc(const InterpState *state, const ALfloat *RESTRICT vals, ALsizei frac) +static inline ALfloat do_bsinc(const InterpState *state, const ALfloat *RESTRICT vals, ALsizei frac) noexcept { const ALfloat *fil, *scd, *phd, *spd; ALsizei j_f, pi; @@ -45,43 +45,60 @@ const ALfloat *Resample_copy_C(const InterpState* UNUSED(state), const ALfloat *RESTRICT src, ALsizei UNUSED(frac), ALint UNUSED(increment), ALfloat *RESTRICT dst, ALsizei numsamples) { + ASSUME(numsamples > 0); #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)); + std::copy_n(src, numsamples, dst); return dst; } -#define DECL_TEMPLATE(Tag, Sampler, O) \ -const ALfloat *Resample_##Tag##_C(const InterpState *state, \ - const ALfloat *RESTRICT src, ALsizei frac, ALint increment, \ - ALfloat *RESTRICT dst, ALsizei numsamples) \ -{ \ - const InterpState istate = *state; \ - ALsizei i; \ - \ - ASSUME(numsamples > 0); \ - \ - src -= O; \ - for(i = 0;i < numsamples;i++) \ - { \ - dst[i] = Sampler(&istate, src, frac); \ - \ - frac += increment; \ - src += frac>>FRACTIONBITS; \ - frac &= FRACTIONMASK; \ - } \ - return dst; \ -} +template +static const ALfloat *DoResample(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, + ALsizei numsamples) +{ + ASSUME(numsamples > 0); + ASSUME(increment > 0); + ASSUME(frac >= 0); + + const InterpState istate = *state; + std::generate_n(dst, numsamples, + [&src,&frac,istate,increment]() noexcept -> ALfloat + { + ALfloat ret{Sampler(&istate, src, frac)}; -DECL_TEMPLATE(point, do_point, 0) -DECL_TEMPLATE(lerp, do_lerp, 0) -DECL_TEMPLATE(cubic, do_cubic, 1) -DECL_TEMPLATE(bsinc, do_bsinc, istate.bsinc.l) + frac += increment; + src += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + + return ret; + } + ); + return dst; +} -#undef DECL_TEMPLATE +const ALfloat *Resample_point_C(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, + ALsizei numsamples) +{ return DoResample(state, src, frac, increment, dst, numsamples); } + +const ALfloat *Resample_lerp_C(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, + ALsizei numsamples) +{ return DoResample(state, src, frac, increment, dst, numsamples); } + +const ALfloat *Resample_cubic_C(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, + ALsizei numsamples) +{ return DoResample(state, src-1, frac, increment, dst, numsamples); } + +const ALfloat *Resample_bsinc_C(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, + ALsizei numsamples) +{ return DoResample(state, src-state->bsinc.l, frac, increment, dst, numsamples); } static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], diff --git a/Alc/mixer/mixer_neon.cpp b/Alc/mixer/mixer_neon.cpp index b1f219e4..f7fe57d1 100644 --- a/Alc/mixer/mixer_neon.cpp +++ b/Alc/mixer/mixer_neon.cpp @@ -22,6 +22,8 @@ const ALfloat *Resample_lerp_Neon(const InterpState* UNUSED(state), ALsizei todo, pos, i; ASSUME(numsamples > 0); + ASSUME(increment > 0); + ASSUME(frac >= 0); InitiatePositionArrays(frac, increment, frac_, pos_, 4); frac4 = vld1q_s32(frac_); @@ -80,6 +82,8 @@ const ALfloat *Resample_bsinc_Neon(const InterpState *state, ASSUME(m > 0); ASSUME(dstlen > 0); + ASSUME(increment > 0); + ASSUME(frac >= 0); src -= state->bsinc.l; for(i = 0;i < dstlen;i++) diff --git a/Alc/mixer/mixer_sse.cpp b/Alc/mixer/mixer_sse.cpp index 8492a1c8..000196ca 100644 --- a/Alc/mixer/mixer_sse.cpp +++ b/Alc/mixer/mixer_sse.cpp @@ -26,6 +26,8 @@ const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *RESTR ASSUME(m > 0); ASSUME(dstlen > 0); + ASSUME(increment > 0); + ASSUME(frac >= 0); src -= state->bsinc.l; for(i = 0;i < dstlen;i++) diff --git a/Alc/mixer/mixer_sse2.cpp b/Alc/mixer/mixer_sse2.cpp index 2432342f..26fe26ba 100644 --- a/Alc/mixer/mixer_sse2.cpp +++ b/Alc/mixer/mixer_sse2.cpp @@ -39,6 +39,8 @@ const ALfloat *Resample_lerp_SSE2(const InterpState* UNUSED(state), ALsizei todo, pos, i; ASSUME(numsamples > 0); + ASSUME(increment > 0); + ASSUME(frac >= 0); InitiatePositionArrays(frac, increment, frac_, pos_, 4); frac4 = _mm_setr_epi32(frac_[0], frac_[1], frac_[2], frac_[3]); diff --git a/Alc/mixer/mixer_sse41.cpp b/Alc/mixer/mixer_sse41.cpp index 34b405f8..cfda905b 100644 --- a/Alc/mixer/mixer_sse41.cpp +++ b/Alc/mixer/mixer_sse41.cpp @@ -40,6 +40,8 @@ const ALfloat *Resample_lerp_SSE41(const InterpState* UNUSED(state), ALsizei todo, pos, i; ASSUME(numsamples > 0); + ASSUME(increment > 0); + ASSUME(frac >= 0); InitiatePositionArrays(frac, increment, frac_, pos_, 4); frac4 = _mm_setr_epi32(frac_[0], frac_[1], frac_[2], frac_[3]); -- cgit v1.2.3 From 05845b53e889c2104a5436ff5418c5e2ba5dcbf3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 25 Nov 2018 13:19:01 -0800 Subject: Clean up MixSource --- Alc/mixvoice.cpp | 197 ++++++++++++++++++++++++++----------------------------- 1 file changed, 93 insertions(+), 104 deletions(-) diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 6cd170f9..5a1a1d4d 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -300,62 +300,51 @@ const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, #define NFC_DATA_BUF 3 ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo) { - ALCdevice *Device = Context->Device; - ALbufferlistitem *BufferListItem; - ALbufferlistitem *BufferLoopItem; - ALsizei NumChannels, SampleSize; - ALbitfieldSOFT enabledevt; - ALsizei buffers_done = 0; - ResamplerFunc Resample; - ALsizei DataPosInt; - ALsizei DataPosFrac; - ALint64 DataSize64; - ALint increment; - ALsizei Counter; - ALsizei OutPos; - ALsizei IrSize; - bool isplaying; - bool isstatic; - ALsizei chan; - ALsizei send; + ASSUME(SamplesToDo > 0); /* Get source info */ - isplaying = true; /* Will only be called while playing. */ - isstatic = !!(voice->Flags&VOICE_IS_STATIC); - DataPosInt = ATOMIC_LOAD(&voice->position, almemory_order_acquire); - DataPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); - BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - BufferLoopItem = ATOMIC_LOAD(&voice->loop_buffer, almemory_order_relaxed); - NumChannels = voice->NumChannels; - SampleSize = voice->SampleSize; - increment = voice->Step; - - IrSize = (Device->HrtfHandle ? Device->HrtfHandle->irSize : 0); - - Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ? - Resample_copy_C : voice->Resampler); - - Counter = (voice->Flags&VOICE_IS_FADING) ? SamplesToDo : 0; - OutPos = 0; + bool isplaying{true}; /* Will only be called while playing. */ + bool isstatic{(voice->Flags&VOICE_IS_STATIC) != 0}; + ALsizei DataPosInt{(ALsizei)voice->position.load(std::memory_order_acquire)}; + ALsizei DataPosFrac{voice->position_fraction.load(std::memory_order_relaxed)}; + ALbufferlistitem *BufferListItem{voice->current_buffer.load(std::memory_order_relaxed)}; + ALbufferlistitem *BufferLoopItem{voice->loop_buffer.load(std::memory_order_relaxed)}; + ALsizei NumChannels{voice->NumChannels}; + ALsizei SampleSize{voice->SampleSize}; + ALint increment{voice->Step}; + + ASSUME(DataPosInt >= 0); + ASSUME(DataPosFrac >= 0); + ASSUME(NumChannels > 0); + ASSUME(SampleSize > 0); + ASSUME(increment > 0); + + ALCdevice *Device{Context->Device}; + ALsizei IrSize{Device->HrtfHandle ? Device->HrtfHandle->irSize : 0}; + + ResamplerFunc Resample{(increment == FRACTIONONE && DataPosFrac == 0) ? + Resample_copy_C : voice->Resampler}; + + ALsizei Counter{(voice->Flags&VOICE_IS_FADING) ? SamplesToDo : 0}; + ALsizei buffers_done{0}; + ALsizei OutPos{0}; do { - ALsizei SrcBufferSize, DstBufferSize; - /* Figure out how many buffer samples will be needed */ - DataSize64 = SamplesToDo-OutPos; + ALint64 DataSize64{SamplesToDo - OutPos}; DataSize64 *= increment; DataSize64 += DataPosFrac+FRACTIONMASK; DataSize64 >>= FRACTIONBITS; DataSize64 += MAX_RESAMPLE_PADDING*2; - SrcBufferSize = (ALsizei)mini64(DataSize64, BUFFERSIZE); + ALsizei SrcBufferSize{(ALsizei)mini64(DataSize64, BUFFERSIZE)}; /* Figure out how many samples we can actually mix from this. */ DataSize64 = SrcBufferSize; DataSize64 -= MAX_RESAMPLE_PADDING*2; DataSize64 <<= FRACTIONBITS; DataSize64 -= DataPosFrac; - DstBufferSize = (ALsizei)mini64((DataSize64+(increment-1)) / increment, - SamplesToDo - OutPos); + ALsizei DstBufferSize{(ALsizei)mini64((DataSize64+(increment-1)) / increment, + SamplesToDo - OutPos)}; /* Some mixers like having a multiple of 4, so try to give that unless * this is the last update. */ @@ -365,7 +354,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize /* It's impossible to have a buffer list item with no entries. */ assert(BufferListItem->num_buffers > 0); - for(chan = 0;chan < NumChannels;chan++) + for(ALsizei chan{0};chan < NumChannels;chan++) { ALfloat *SrcData{Device->TempBuffer[SOURCE_DATA_BUF]}; @@ -380,21 +369,21 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize * first buffer (should be adjusted by any buffer offset, to * possibly be added later). */ - const ALbuffer *Buffer0 = BufferListItem->buffers[0]; - const ALsizei LoopStart = Buffer0->LoopStart; - const ALsizei LoopEnd = Buffer0->LoopEnd; - const ALsizei LoopSize = LoopEnd - LoopStart; + const ALbuffer *Buffer0{BufferListItem->buffers[0]}; + const ALsizei LoopStart{Buffer0->LoopStart}; + const ALsizei LoopEnd{Buffer0->LoopEnd}; + ASSUME(LoopStart >= 0); + ASSUME(LoopEnd > LoopStart); /* If current pos is beyond the loop range, do not loop */ if(!BufferLoopItem || DataPosInt >= LoopEnd) { ALsizei SizeToDo = SrcBufferSize - FilledAmt; - ALsizei CompLen = 0; - ALsizei i; - BufferLoopItem = NULL; + BufferLoopItem = nullptr; - for(i = 0;i < BufferListItem->num_buffers;i++) + ALsizei CompLen{0}; + for(ALsizei i{0};i < BufferListItem->num_buffers;i++) { const ALbuffer *buffer = BufferListItem->buffers[i]; const ALbyte *Data = buffer->mData.data(); @@ -416,11 +405,11 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize } else { + const ALsizei LoopSize{LoopEnd - LoopStart}; ALsizei SizeToDo = mini(SrcBufferSize - FilledAmt, LoopEnd - DataPosInt); - ALsizei CompLen = 0; - ALsizei i; - for(i = 0;i < BufferListItem->num_buffers;i++) + ALsizei CompLen{0}; + for(ALsizei i{0};i < BufferListItem->num_buffers;i++) { const ALbuffer *buffer = BufferListItem->buffers[i]; const ALbyte *Data = buffer->mData.data(); @@ -445,7 +434,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize const ALsizei SizeToDo = mini(SrcBufferSize - FilledAmt, LoopSize); CompLen = 0; - for(i = 0;i < BufferListItem->num_buffers;i++) + for(ALsizei i{0};i < BufferListItem->num_buffers;i++) { const ALbuffer *buffer = BufferListItem->buffers[i]; const ALbyte *Data = buffer->mData.data(); @@ -469,42 +458,43 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize else { /* Crawl the buffer queue to fill in the temp buffer */ - ALbufferlistitem *tmpiter = BufferListItem; - ALsizei pos = DataPosInt; + ALbufferlistitem *tmpiter{BufferListItem}; + ALsizei pos{DataPosInt}; while(tmpiter && SrcBufferSize > FilledAmt) { - ALsizei SizeToDo = SrcBufferSize - FilledAmt; - ALsizei CompLen = 0; - ALsizei i; + if(pos >= tmpiter->max_samples) + { + pos -= tmpiter->max_samples; + tmpiter = tmpiter->next.load(std::memory_order_acquire); + if(!tmpiter) tmpiter = BufferLoopItem; + continue; + } - for(i = 0;i < tmpiter->num_buffers;i++) + const ALsizei SizeToDo{SrcBufferSize - FilledAmt}; + ALsizei CompLen{0}; + for(ALsizei i{0};i < tmpiter->num_buffers;i++) { - const ALbuffer *ALBuffer = tmpiter->buffers[i]; - ALsizei DataSize = ALBuffer ? ALBuffer->SampleLen : 0; + const ALbuffer *ALBuffer{tmpiter->buffers[i]}; + ALsizei DataSize{ALBuffer ? ALBuffer->SampleLen : 0}; - if(DataSize > pos) - { - const ALbyte *Data = ALBuffer->mData.data(); - Data += (pos*NumChannels + chan)*SampleSize; + if(pos >= DataSize) + continue; - DataSize = mini(SizeToDo, DataSize - pos); - CompLen = maxi(CompLen, DataSize); + const ALbyte *Data{ALBuffer->mData.data()}; + Data += (pos*NumChannels + chan)*SampleSize; - LoadSamples(&SrcData[FilledAmt], Data, NumChannels, - ALBuffer->FmtType, DataSize); - } - } - if(UNLIKELY(!CompLen)) - pos -= tmpiter->max_samples; - else - { - FilledAmt += CompLen; - if(SrcBufferSize <= FilledAmt) - break; - pos = 0; + DataSize = mini(SizeToDo, DataSize - pos); + CompLen = maxi(CompLen, DataSize); + + LoadSamples(&SrcData[FilledAmt], Data, NumChannels, + ALBuffer->FmtType, DataSize); } - tmpiter = ATOMIC_LOAD(&tmpiter->next, almemory_order_acquire); + FilledAmt += CompLen; + if(SrcBufferSize <= FilledAmt) + break; + pos = 0; + tmpiter = tmpiter->next.load(std::memory_order_acquire); if(!tmpiter) tmpiter = BufferLoopItem; } } @@ -519,18 +509,18 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize Device->TempBuffer[RESAMPLED_BUF], DstBufferSize )}; { - DirectParams *parms = &voice->Direct.Params[chan]; - const ALfloat *samples; + DirectParams *parms{&voice->Direct.Params[chan]}; + const ALfloat *samples{DoFilters(&parms->LowPass, &parms->HighPass, + Device->TempBuffer[FILTERED_BUF], ResampledData, DstBufferSize, + voice->Direct.FilterType + )}; - samples = DoFilters( - &parms->LowPass, &parms->HighPass, Device->TempBuffer[FILTERED_BUF], - ResampledData, DstBufferSize, voice->Direct.FilterType - ); if(!(voice->Flags&VOICE_HAS_HRTF)) { if(!Counter) - memcpy(parms->Gains.Current, parms->Gains.Target, - sizeof(parms->Gains.Current)); + std::copy(std::begin(parms->Gains.Target), std::end(parms->Gains.Target), + std::begin(parms->Gains.Current)); + if(!(voice->Flags&VOICE_HAS_NFC)) MixSamples(samples, voice->Direct.Channels, voice->Direct.Buffer, parms->Gains.Current, parms->Gains.Target, Counter, OutPos, @@ -651,22 +641,21 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize } } - for(send = 0;send < Device->NumAuxSends;send++) + for(ALsizei send{0};send < Device->NumAuxSends;send++) { SendParams *parms = &voice->Send[send].Params[chan]; - const ALfloat *samples; if(!voice->Send[send].Buffer) continue; - samples = DoFilters( - &parms->LowPass, &parms->HighPass, Device->TempBuffer[FILTERED_BUF], - ResampledData, DstBufferSize, voice->Send[send].FilterType - ); + const ALfloat *samples{DoFilters(&parms->LowPass, &parms->HighPass, + Device->TempBuffer[FILTERED_BUF], ResampledData, DstBufferSize, + voice->Send[send].FilterType + )}; if(!Counter) - memcpy(parms->Gains.Current, parms->Gains.Target, - sizeof(parms->Gains.Current)); + std::copy(std::begin(parms->Gains.Target), std::end(parms->Gains.Target), + std::begin(parms->Gains.Current)); MixSamples(samples, voice->Send[send].Channels, voice->Send[send].Buffer, parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize ); @@ -686,9 +675,9 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize if(BufferLoopItem) { /* Handle looping static source */ - const ALbuffer *Buffer = BufferListItem->buffers[0]; - ALsizei LoopStart = Buffer->LoopStart; - ALsizei LoopEnd = Buffer->LoopEnd; + const ALbuffer *Buffer{BufferListItem->buffers[0]}; + ALsizei LoopStart{Buffer->LoopStart}; + ALsizei LoopEnd{Buffer->LoopEnd}; if(DataPosInt >= LoopEnd) { assert(LoopEnd > LoopStart); @@ -731,12 +720,12 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize voice->Flags |= VOICE_IS_FADING; /* Update source info */ - ATOMIC_STORE(&voice->position, static_cast(DataPosInt), almemory_order_relaxed); - ATOMIC_STORE(&voice->position_fraction, DataPosFrac, almemory_order_relaxed); - ATOMIC_STORE(&voice->current_buffer, BufferListItem, almemory_order_release); + voice->position.store(DataPosInt, std::memory_order_relaxed); + voice->position_fraction.store(DataPosFrac, std::memory_order_relaxed); + voice->current_buffer.store(BufferListItem, std::memory_order_release); /* Send any events now, after the position/buffer info was updated. */ - enabledevt = ATOMIC_LOAD(&Context->EnabledEvts, almemory_order_acquire); + ALbitfieldSOFT enabledevt{Context->EnabledEvts.load(std::memory_order_acquire)}; if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) SendAsyncEvent(Context, EventType_BufferCompleted, AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, SourceID, buffers_done, "Buffer completed" -- cgit v1.2.3 From 8ae07ad1ae2d957f65ba54fdcd19649eceeb0e3d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 25 Nov 2018 15:30:32 -0800 Subject: Automatically clean up buffers with ther sublist --- Alc/alc.cpp | 10 +++++----- OpenAL32/Include/alBuffer.h | 2 -- OpenAL32/Include/alMain.h | 16 +++++++++++++--- OpenAL32/alBuffer.cpp | 32 +++++++++----------------------- OpenAL32/alSource.cpp | 5 +---- 5 files changed, 28 insertions(+), 37 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 5fae13b3..34279269 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2396,11 +2396,11 @@ ALCdevice_struct::~ALCdevice_struct() almtx_destroy(&BackendLock); - ReleaseALBuffers(this); - std::for_each(BufferList.begin(), BufferList.end(), - [](BufferSubList &entry) noexcept -> void - { al_free(entry.Buffers); } - ); + size_t count{0u}; + for(auto &sublist : BufferList) + count += POPCNT64(~sublist.FreeMask); + if(count > 0) + WARN(SZFMT " Buffer%s not deleted\n", count, (count==1)?"":"s"); BufferList.clear(); almtx_destroy(&BufferLock); diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 54c17670..691c7e22 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -121,6 +121,4 @@ struct ALbuffer { ALuint id{0}; }; -ALvoid ReleaseALBuffers(ALCdevice *device); - #endif diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 5ff1e064..eae3ea99 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -551,10 +551,20 @@ typedef union AmbiConfig { } AmbiConfig; -typedef struct BufferSubList { - ALuint64 FreeMask{~ALuint64{}}; +struct BufferSubList { + uint64_t FreeMask{~uint64_t{}}; struct ALbuffer *Buffers{nullptr}; /* 64 */ -} BufferSubList; + + BufferSubList() noexcept = default; + BufferSubList(const BufferSubList&) = delete; + BufferSubList(BufferSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Buffers{rhs.Buffers} + { rhs.FreeMask = ~uint64_t{}; rhs.Buffers = nullptr; } + ~BufferSubList(); + + BufferSubList& operator=(const BufferSubList&) = delete; + BufferSubList& operator=(BufferSubList&& rhs) noexcept + { std::swap(FreeMask, rhs.FreeMask); std::swap(Buffers, rhs.Buffers); return *this; } +}; typedef struct EffectSubList { ALuint64 FreeMask{~ALuint64{}}; diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index 5c40a27e..3716ac28 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -1174,30 +1174,16 @@ ALsizei ChannelsFromFmt(FmtChannels chans) } -/* - * ReleaseALBuffers() - * - * INTERNAL: Called to destroy any buffers that still exist on the device - */ -ALvoid ReleaseALBuffers(ALCdevice *device) +BufferSubList::~BufferSubList() { - size_t leftover = 0; - for(auto &sublist : device->BufferList) + ALuint64 usemask = ~FreeMask; + while(usemask) { - ALuint64 usemask = ~sublist.FreeMask; - while(usemask) - { - ALsizei idx = CTZ64(usemask); - ALbuffer *buffer = sublist.Buffers + idx; - - buffer->~ALbuffer(); - - ++leftover; - - usemask &= ~(U64(1) << idx); - } - sublist.FreeMask = ~usemask; + ALsizei idx{CTZ64(usemask)}; + Buffers[idx].~ALbuffer(); + usemask &= ~(U64(1) << idx); } - if(leftover > 0) - WARN("(%p) Deleted " SZFMT " Buffer%s\n", device, leftover, (leftover==1)?"":"s"); + FreeMask = ~usemask; + al_free(Buffers); + Buffers = nullptr; } diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 8b461982..12a8a04a 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -3405,10 +3405,7 @@ SourceSubList::~SourceSubList() while(usemask) { ALsizei idx{CTZ64(usemask)}; - ALsource *source{Sources + idx}; - - source->~ALsource(); - + Sources[idx].~ALsource(); usemask &= ~(U64(1) << idx); } FreeMask = ~usemask; -- cgit v1.2.3 From 127ec026e7dd0722bd5fbc193a85cb28a95925f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 25 Nov 2018 16:13:07 -0800 Subject: Automatically clean up filters and effects with their sublists --- Alc/alc.cpp | 20 ++++++++++---------- OpenAL32/Include/alEffect.h | 1 - OpenAL32/Include/alFilter.h | 9 --------- OpenAL32/Include/alMain.h | 32 ++++++++++++++++++++++++++------ OpenAL32/alEffect.cpp | 26 +++++++++----------------- OpenAL32/alFilter.cpp | 26 +++++++++----------------- 6 files changed, 54 insertions(+), 60 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 34279269..56bfb875 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2404,19 +2404,19 @@ ALCdevice_struct::~ALCdevice_struct() BufferList.clear(); almtx_destroy(&BufferLock); - ReleaseALEffects(this); - std::for_each(EffectList.begin(), EffectList.end(), - [](EffectSubList &entry) noexcept -> void - { al_free(entry.Effects); } - ); + count = 0; + for(auto &sublist : EffectList) + count += POPCNT64(~sublist.FreeMask); + if(count > 0) + WARN(SZFMT " Effect%s not deleted\n", count, (count==1)?"":"s"); EffectList.clear(); almtx_destroy(&EffectLock); - ReleaseALFilters(this); - std::for_each(FilterList.begin(), FilterList.end(), - [](FilterSubList &entry) noexcept -> void - { al_free(entry.Filters); } - ); + count = 0; + for(auto &sublist : FilterList) + count += POPCNT64(~sublist.FreeMask); + if(count > 0) + WARN(SZFMT " Filter%s not deleted\n", count, (count==1)?"":"s"); FilterList.clear(); almtx_destroy(&FilterLock); diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index 38540cfc..441a8e97 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -199,7 +199,6 @@ inline ALboolean IsReverbEffect(ALenum type) { return type == AL_EFFECT_REVERB || type == AL_EFFECT_EAXREVERB; } void InitEffect(ALeffect *effect); -void ReleaseALEffects(ALCdevice *device); void LoadReverbPreset(const char *name, ALeffect *effect); diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h index 2634d5e8..feca54e3 100644 --- a/OpenAL32/Include/alFilter.h +++ b/OpenAL32/Include/alFilter.h @@ -4,9 +4,6 @@ #include "AL/alc.h" #include "AL/al.h" -#ifdef __cplusplus -extern "C" { -#endif #define LOWPASSFREQREF (5000.0f) #define HIGHPASSFREQREF (250.0f) @@ -58,10 +55,4 @@ typedef struct ALfilter { #define ALfilter_getParamiv(o, c, p, v) ((o)->vtab->getParamiv(o, c, p, v)) #define ALfilter_getParamfv(o, c, p, v) ((o)->vtab->getParamfv(o, c, p, v)) -void ReleaseALFilters(ALCdevice *device); - -#ifdef __cplusplus -} -#endif - #endif diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index eae3ea99..c08f9a09 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -566,15 +566,35 @@ struct BufferSubList { { std::swap(FreeMask, rhs.FreeMask); std::swap(Buffers, rhs.Buffers); return *this; } }; -typedef struct EffectSubList { - ALuint64 FreeMask{~ALuint64{}}; +struct EffectSubList { + uint64_t FreeMask{~uint64_t{}}; struct ALeffect *Effects{nullptr}; /* 64 */ -} EffectSubList; -typedef struct FilterSubList { - ALuint64 FreeMask{~ALuint64{}}; + EffectSubList() noexcept = default; + EffectSubList(const EffectSubList&) = delete; + EffectSubList(EffectSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Effects{rhs.Effects} + { rhs.FreeMask = ~uint64_t{}; rhs.Effects = nullptr; } + ~EffectSubList(); + + EffectSubList& operator=(const EffectSubList&) = delete; + EffectSubList& operator=(EffectSubList&& rhs) noexcept + { std::swap(FreeMask, rhs.FreeMask); std::swap(Effects, rhs.Effects); return *this; } +}; + +struct FilterSubList { + uint64_t FreeMask{~uint64_t{}}; struct ALfilter *Filters{nullptr}; /* 64 */ -} FilterSubList; + + FilterSubList() noexcept = default; + FilterSubList(const FilterSubList&) = delete; + FilterSubList(FilterSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Filters{rhs.Filters} + { rhs.FreeMask = ~uint64_t{}; rhs.Filters = nullptr; } + ~FilterSubList(); + + FilterSubList& operator=(const FilterSubList&) = delete; + FilterSubList& operator=(FilterSubList&& rhs) noexcept + { std::swap(FreeMask, rhs.FreeMask); std::swap(Filters, rhs.Filters); return *this; } +}; typedef struct EnumeratedHrtf { diff --git a/OpenAL32/alEffect.cpp b/OpenAL32/alEffect.cpp index 2bc60e24..7f479c83 100644 --- a/OpenAL32/alEffect.cpp +++ b/OpenAL32/alEffect.cpp @@ -571,26 +571,18 @@ void InitEffect(ALeffect *effect) InitEffectParams(effect, AL_EFFECT_NULL); } -void ReleaseALEffects(ALCdevice *device) +EffectSubList::~EffectSubList() { - size_t leftover = 0; - for(auto &sublist : device->EffectList) + ALuint64 usemask = ~FreeMask; + while(usemask) { - ALuint64 usemask = ~sublist.FreeMask; - while(usemask) - { - ALsizei idx = CTZ64(usemask); - ALeffect *effect = sublist.Effects + idx; - - effect->~ALeffect(); - ++leftover; - - usemask &= ~(U64(1) << idx); - } - sublist.FreeMask = ~usemask; + ALsizei idx = CTZ64(usemask); + Effects[idx].~ALeffect(); + usemask &= ~(U64(1) << idx); } - if(leftover > 0) - WARN("(%p) Deleted " SZFMT " Effect%s\n", device, leftover, (leftover==1)?"":"s"); + FreeMask = ~usemask; + al_free(Effects); + Effects = nullptr; } diff --git a/OpenAL32/alFilter.cpp b/OpenAL32/alFilter.cpp index 5b15e7e0..390432cb 100644 --- a/OpenAL32/alFilter.cpp +++ b/OpenAL32/alFilter.cpp @@ -622,24 +622,16 @@ AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *va } -void ReleaseALFilters(ALCdevice *device) +FilterSubList::~FilterSubList() { - size_t leftover = 0; - for(auto &sublist : device->FilterList) + ALuint64 usemask = ~FreeMask; + while(usemask) { - ALuint64 usemask = ~sublist.FreeMask; - while(usemask) - { - ALsizei idx = CTZ64(usemask); - ALfilter *filter = sublist.Filters + idx; - - filter->~ALfilter(); - ++leftover; - - usemask &= ~(U64(1) << idx); - } - sublist.FreeMask = ~usemask; + ALsizei idx = CTZ64(usemask); + Filters[idx].~ALfilter(); + usemask &= ~(U64(1) << idx); } - if(leftover > 0) - WARN("(%p) Deleted " SZFMT " Filter%s\n", device, leftover, (leftover==1)?"":"s"); + FreeMask = ~usemask; + al_free(Filters); + Filters = nullptr; } -- cgit v1.2.3 From 5b2b96b24598636e35f1fe7ecf868b09571065d6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 25 Nov 2018 17:51:39 -0800 Subject: Don't explicitly clear vector objects in the destructor --- Alc/alc.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 56bfb875..a3c6b5bd 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2390,37 +2390,33 @@ ALCdevice_struct::~ALCdevice_struct() { TRACE("%p\n", this); - if(Backend) - DELETE_OBJ(Backend); + DELETE_OBJ(Backend); Backend = nullptr; - almtx_destroy(&BackendLock); - size_t count{0u}; for(auto &sublist : BufferList) count += POPCNT64(~sublist.FreeMask); if(count > 0) WARN(SZFMT " Buffer%s not deleted\n", count, (count==1)?"":"s"); - BufferList.clear(); - almtx_destroy(&BufferLock); count = 0; for(auto &sublist : EffectList) count += POPCNT64(~sublist.FreeMask); if(count > 0) WARN(SZFMT " Effect%s not deleted\n", count, (count==1)?"":"s"); - EffectList.clear(); - almtx_destroy(&EffectLock); count = 0; for(auto &sublist : FilterList) count += POPCNT64(~sublist.FreeMask); if(count > 0) WARN(SZFMT " Filter%s not deleted\n", count, (count==1)?"":"s"); - FilterList.clear(); + + almtx_destroy(&BackendLock); + + almtx_destroy(&BufferLock); + almtx_destroy(&EffectLock); almtx_destroy(&FilterLock); - HrtfList.clear(); if(HrtfHandle) Hrtf_DecRef(HrtfHandle); HrtfHandle = nullptr; -- cgit v1.2.3 From a6923790fac739f0b98db6c06bc93543b9707556 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 14:31:54 -0800 Subject: Avoid using ATOMIC_INIT --- Alc/alc.cpp | 4 ++-- Alc/backends/jack.cpp | 15 ++++----------- Alc/backends/null.cpp | 4 +--- Alc/backends/opensl.cpp | 44 ++++++++++++-------------------------------- Alc/backends/qsa.cpp | 2 +- Alc/backends/sndio.cpp | 22 +++++++--------------- Alc/backends/solaris.cpp | 12 ++++-------- Alc/backends/wave.cpp | 11 +++-------- Alc/ringbuffer.cpp | 23 +++++++++++------------ OpenAL32/alSource.cpp | 6 +++--- common/atomic.h | 4 +--- 11 files changed, 49 insertions(+), 98 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index a3c6b5bd..ea72757c 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2534,7 +2534,7 @@ static ALvoid InitContext(ALCcontext *Context) sizeof(struct ALeffectslotArray))); auxslots->count = 0; } - ATOMIC_INIT(&Context->ActiveAuxSlots, auxslots); + Context->ActiveAuxSlots.store(auxslots, std::memory_order_relaxed); //Set globals Context->mDistanceModel = DistanceModel::Default; @@ -2850,7 +2850,7 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) /* Finish setting the voices' property set pointers and references. */ for(;v < num_voices;v++) { - ATOMIC_INIT(&voice->Update, static_cast(nullptr)); + voice->Update.store(nullptr, std::memory_order_relaxed); voice->Props = props; voices[v] = voice; diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index cd02388d..d0687939 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -145,13 +145,13 @@ static ALCboolean jack_load(void) struct ALCjackPlayback final : public ALCbackend { - jack_client_t *Client; - jack_port_t *Port[MAX_OUTPUT_CHANNELS]; + jack_client_t *Client{nullptr}; + jack_port_t *Port[MAX_OUTPUT_CHANNELS]{}; - ll_ringbuffer_t *Ring; + ll_ringbuffer_t *Ring{nullptr}; alsem_t Sem; - ATOMIC(ALenum) killNow; + ATOMIC(ALenum) killNow{AL_TRUE}; althrd_t thread; }; @@ -183,13 +183,6 @@ static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device) SET_VTABLE2(ALCjackPlayback, ALCbackend, self); alsem_init(&self->Sem, 0); - - self->Client = NULL; - for(ALsizei i{0};i < MAX_OUTPUT_CHANNELS;i++) - self->Port[i] = NULL; - self->Ring = NULL; - - ATOMIC_INIT(&self->killNow, AL_TRUE); } static void ALCjackPlayback_Destruct(ALCjackPlayback *self) diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 47ebd0ae..7c7f5e5e 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -45,7 +45,7 @@ constexpr ALCchar nullDevice[] = "No Output"; struct ALCnullBackend final : public ALCbackend { - ATOMIC(int) killNow; + ATOMIC(int) killNow{AL_TRUE}; std::thread thread; }; @@ -72,8 +72,6 @@ void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device) new (self) ALCnullBackend{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCnullBackend, ALCbackend, self); - - ATOMIC_INIT(&self->killNow, AL_TRUE); } void ALCnullBackend_Destruct(ALCnullBackend *self) diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index f7ad1595..5b80ea65 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -134,21 +134,21 @@ static const char *res_str(SLresult result) struct ALCopenslPlayback final : public ALCbackend { /* engine interfaces */ - SLObjectItf mEngineObj; - SLEngineItf mEngine; + SLObjectItf mEngineObj{nullptr}; + SLEngineItf mEngine{nullptr}; /* output mix interfaces */ - SLObjectItf mOutputMix; + SLObjectItf mOutputMix{nullptr}; /* buffer queue player interfaces */ - SLObjectItf mBufferQueueObj; + SLObjectItf mBufferQueueObj{nullptr}; - ll_ringbuffer_t *mRing; + ll_ringbuffer_t *mRing{nullptr}; alsem_t mSem; - ALsizei mFrameSize; + ALsizei mFrameSize{0}; - ATOMIC(ALenum) mKillNow; + ATOMIC(ALenum) mKillNow{AL_TRUE}; althrd_t mThread; }; @@ -177,17 +177,7 @@ static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *devi ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCopenslPlayback, ALCbackend, self); - self->mEngineObj = NULL; - self->mEngine = NULL; - self->mOutputMix = NULL; - self->mBufferQueueObj = NULL; - - self->mRing = NULL; alsem_init(&self->mSem, 0); - - self->mFrameSize = 0; - - ATOMIC_INIT(&self->mKillNow, AL_FALSE); } static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self) @@ -664,16 +654,16 @@ static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self) struct ALCopenslCapture final : public ALCbackend { /* engine interfaces */ - SLObjectItf mEngineObj; + SLObjectItf mEngineObj{nullptr}; SLEngineItf mEngine; /* recording interfaces */ - SLObjectItf mRecordObj; + SLObjectItf mRecordObj{nullptr}; - ll_ringbuffer_t *mRing; - ALCuint mSplOffset; + ll_ringbuffer_t *mRing{nullptr}; + ALCuint mSplOffset{0u}; - ALsizei mFrameSize; + ALsizei mFrameSize{0}; }; static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf bq, void *context); @@ -698,16 +688,6 @@ static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device new (self) ALCopenslCapture{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCopenslCapture, ALCbackend, self); - - self->mEngineObj = NULL; - self->mEngine = NULL; - - self->mRecordObj = NULL; - - self->mRing = NULL; - self->mSplOffset = 0; - - self->mFrameSize = 0; } static void ALCopenslCapture_Destruct(ALCopenslCapture *self) diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index 09082357..a6d1e0ea 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -289,7 +289,7 @@ static ALCenum qsa_open_playback(PlaybackWrapper *self, const ALCchar* deviceNam data = (qsa_data*)calloc(1, sizeof(qsa_data)); if(data == NULL) return ALC_OUT_OF_MEMORY; - ATOMIC_INIT(&data->killNow, AL_TRUE); + data->killNow.store(AL_TRUE, std::memory_order_relaxed); if(!deviceName) deviceName = qsaDevice; diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index 2a20fb61..de5f74e4 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -38,12 +38,12 @@ static const ALCchar sndio_device[] = "SndIO Default"; struct SndioPlayback final : public ALCbackend { - struct sio_hdl *sndHandle; + struct sio_hdl *sndHandle{nullptr}; - ALvoid *mix_data; - ALsizei data_size; + ALvoid *mix_data{nullptr}; + ALsizei data_size{0}; - ATOMIC(int) killNow; + ATOMIC(int) killNow{AL_TRUE}; althrd_t thread; }; @@ -70,10 +70,6 @@ static void SndioPlayback_Construct(SndioPlayback *self, ALCdevice *device) new (self) SndioPlayback{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(SndioPlayback, ALCbackend, self); - - self->sndHandle = nullptr; - self->mix_data = nullptr; - ATOMIC_INIT(&self->killNow, AL_TRUE); } static void SndioPlayback_Destruct(SndioPlayback *self) @@ -280,11 +276,11 @@ static void SndioPlayback_stop(SndioPlayback *self) struct SndioCapture final : public ALCbackend { - struct sio_hdl *sndHandle; + struct sio_hdl *sndHandle{nullptr}; - ll_ringbuffer_t *ring; + ll_ringbuffer_t *ring{nullptr}; - ATOMIC(int) killNow; + ATOMIC(int) killNow{AL_TRUE}; althrd_t thread; }; @@ -311,10 +307,6 @@ static void SndioCapture_Construct(SndioCapture *self, ALCdevice *device) new (self) SndioCapture{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(SndioCapture, ALCbackend, self); - - self->sndHandle = nullptr; - self->ring = nullptr; - ATOMIC_INIT(&self->killNow, AL_TRUE); } static void SndioCapture_Destruct(SndioCapture *self) diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index c757e5e1..93de4384 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -44,12 +44,12 @@ struct ALCsolarisBackend final : public ALCbackend { - int fd; + int fd{-1}; - ALubyte *mix_data; - int data_size; + ALubyte *mix_data{nullptr}; + int data_size{0}; - ATOMIC(ALenum) killNow; + ATOMIC(ALenum) killNow{AL_TRUE}; althrd_t thread; }; @@ -81,10 +81,6 @@ static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *devi new (self) ALCsolarisBackend{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCsolarisBackend, ALCbackend, self); - - self->fd = -1; - self->mix_data = nullptr; - ATOMIC_INIT(&self->killNow, AL_FALSE); } static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self) diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index d9219336..bb37d979 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -79,12 +79,12 @@ void fwrite32le(ALuint val, FILE *f) struct ALCwaveBackend final : public ALCbackend { - FILE *mFile; - long mDataStart; + FILE *mFile{nullptr}; + long mDataStart{-1}; al::vector mBuffer; - ATOMIC(ALenum) killNow; + ATOMIC(ALenum) killNow{AL_TRUE}; std::thread thread; }; @@ -111,11 +111,6 @@ void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device) new (self) ALCwaveBackend{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCwaveBackend, ALCbackend, self); - - self->mFile = nullptr; - self->mDataStart = -1; - - ATOMIC_INIT(&self->killNow, AL_TRUE); } void ALCwaveBackend_Destruct(ALCwaveBackend *self) diff --git a/Alc/ringbuffer.cpp b/Alc/ringbuffer.cpp index e5f0f554..db44f8ae 100644 --- a/Alc/ringbuffer.cpp +++ b/Alc/ringbuffer.cpp @@ -36,13 +36,15 @@ * size or count is in 'elements', not bytes. Additionally, it only supports * single-consumer/single-provider operation. */ struct ll_ringbuffer { - std::atomic write_ptr; - std::atomic read_ptr; - size_t size; - size_t size_mask; - size_t elem_size; + std::atomic write_ptr{0u}; + std::atomic read_ptr{0u}; + size_t size{0u}; + size_t size_mask{0u}; + size_t elem_size{0u}; alignas(16) char buf[]; + + DEF_PLACE_NEWDEL() }; ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes) @@ -65,11 +67,8 @@ ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_write power_of_two++; if(power_of_two < sz) return NULL; - rb = static_cast(al_malloc(16, sizeof(*rb) + power_of_two*elem_sz)); - if(!rb) return NULL; + rb = new (al_malloc(16, sizeof(*rb) + power_of_two*elem_sz)) ll_ringbuffer{}; - ATOMIC_INIT(&rb->write_ptr, static_cast(0)); - ATOMIC_INIT(&rb->read_ptr, static_cast(0)); rb->size = limit_writes ? sz : power_of_two; rb->size_mask = power_of_two - 1; rb->elem_size = elem_sz; @@ -78,13 +77,13 @@ ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_write void ll_ringbuffer_free(ll_ringbuffer_t *rb) { - al_free(rb); + delete rb; } void ll_ringbuffer_reset(ll_ringbuffer_t *rb) { - rb->write_ptr.store(0, std::memory_order_release); - rb->read_ptr.store(0, std::memory_order_release); + rb->write_ptr.store(0, std::memory_order_relaxed); + rb->read_ptr.store(0, std::memory_order_relaxed); memset(rb->buf, 0, (rb->size_mask+1)*rb->elem_size); } diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 12a8a04a..e58d6314 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -1276,7 +1276,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co /* Add the selected buffer to a one-item queue */ auto newlist = static_cast(al_calloc(DEF_ALIGN, FAM_SIZE(ALbufferlistitem, buffers, 1))); - ATOMIC_INIT(&newlist->next, static_cast(nullptr)); + newlist->next.store(nullptr, std::memory_order_relaxed); newlist->max_samples = buffer->SampleLen; newlist->num_buffers = 1; newlist->buffers[0] = buffer; @@ -3034,7 +3034,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu BufferList->next.store(item, std::memory_order_relaxed); BufferList = item; } - ATOMIC_INIT(&BufferList->next, static_cast(nullptr)); + BufferList->next.store(nullptr, std::memory_order_relaxed); BufferList->max_samples = buffer ? buffer->SampleLen : 0; BufferList->num_buffers = 1; BufferList->buffers[0] = buffer; @@ -3129,7 +3129,7 @@ AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, co auto BufferListStart = static_cast(al_calloc(DEF_ALIGN, FAM_SIZE(ALbufferlistitem, buffers, nb))); BufferList = BufferListStart; - ATOMIC_INIT(&BufferList->next, static_cast(nullptr)); + BufferList->next.store(nullptr, std::memory_order_relaxed); BufferList->max_samples = 0; BufferList->num_buffers = 0; diff --git a/common/atomic.h b/common/atomic.h index 87560e3d..eaae8fb8 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -14,8 +14,6 @@ #define ATOMIC(T) std::atomic -#define ATOMIC_INIT std::atomic_init - #define ATOMIC_LOAD std::atomic_load_explicit #define ATOMIC_STORE std::atomic_store_explicit @@ -33,7 +31,7 @@ using RefCount = std::atomic; inline void InitRef(RefCount *ptr, unsigned int value) -{ ATOMIC_INIT(ptr, value); } +{ ptr->store(value, std::memory_order_relaxed); } inline unsigned int ReadRef(RefCount *ptr) { return ptr->load(std::memory_order_acquire); } inline unsigned int IncrementRef(RefCount *ptr) -- cgit v1.2.3 From 053599b2435844eddcc084414ab9dd1c5ad7ec23 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 14:48:26 -0800 Subject: Avoid using the ATOMIC() macro --- Alc/alcontext.h | 22 +++++++++++----------- Alc/backends/jack.cpp | 2 +- Alc/backends/null.cpp | 2 +- Alc/backends/opensl.cpp | 2 +- Alc/backends/qsa.cpp | 2 +- Alc/backends/sndio.cpp | 4 ++-- Alc/backends/solaris.cpp | 2 +- Alc/backends/wave.cpp | 2 +- OpenAL32/Include/alAuxEffectSlot.h | 4 ++-- OpenAL32/Include/alListener.h | 4 ++-- OpenAL32/Include/alMain.h | 8 ++++---- OpenAL32/Include/alSource.h | 2 +- OpenAL32/Include/alu.h | 18 +++++++++--------- common/atomic.h | 2 -- 14 files changed, 37 insertions(+), 39 deletions(-) diff --git a/Alc/alcontext.h b/Alc/alcontext.h index c6824d78..056d9003 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -71,7 +71,7 @@ struct ALCcontext_struct { al::vector EffectSlotList; almtx_t EffectSlotLock; - ATOMIC(ALenum) LastError{AL_NO_ERROR}; + std::atomic LastError{AL_NO_ERROR}; DistanceModel mDistanceModel{DistanceModel::Default}; ALboolean SourceDistanceModel{AL_FALSE}; @@ -90,30 +90,30 @@ struct ALCcontext_struct { * indicates if updates are currently happening). */ RefCount UpdateCount{0u}; - ATOMIC(ALenum) HoldUpdates{AL_FALSE}; + std::atomic HoldUpdates{AL_FALSE}; ALfloat GainBoost{1.0f}; - ATOMIC(ALcontextProps*) Update{nullptr}; + std::atomic Update{nullptr}; /* Linked lists of unused property containers, free to use for future * updates. */ - ATOMIC(ALcontextProps*) FreeContextProps{nullptr}; - ATOMIC(ALlistenerProps*) FreeListenerProps{nullptr}; - ATOMIC(ALvoiceProps*) FreeVoiceProps{nullptr}; - ATOMIC(ALeffectslotProps*) FreeEffectslotProps{nullptr}; + std::atomic FreeContextProps{nullptr}; + std::atomic FreeListenerProps{nullptr}; + std::atomic FreeVoiceProps{nullptr}; + std::atomic FreeEffectslotProps{nullptr}; ALvoice **Voices{nullptr}; std::atomic VoiceCount{0}; ALsizei MaxVoices{0}; - ATOMIC(ALeffectslotArray*) ActiveAuxSlots{nullptr}; + std::atomic ActiveAuxSlots{nullptr}; std::thread EventThread; alsem_t EventSem; ll_ringbuffer *AsyncEvents{nullptr}; - ATOMIC(ALbitfieldSOFT) EnabledEvts{0u}; + std::atomic EnabledEvts{0u}; std::mutex EventCbLock; ALEVENTPROCSOFT EventCb{}; void *EventParam{nullptr}; @@ -124,7 +124,7 @@ struct ALCcontext_struct { ALCdevice *const Device; const ALCchar *ExtensionList{nullptr}; - ATOMIC(ALCcontext*) next{nullptr}; + std::atomic next{nullptr}; ALlistener Listener{}; @@ -199,7 +199,7 @@ struct ALcontextProps { DistanceModel mDistanceModel; ALfloat MetersPerUnit; - ATOMIC(struct ALcontextProps*) next; + std::atomic next; }; #endif /* ALCONTEXT_H */ diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index d0687939..72a27c44 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -151,7 +151,7 @@ struct ALCjackPlayback final : public ALCbackend { ll_ringbuffer_t *Ring{nullptr}; alsem_t Sem; - ATOMIC(ALenum) killNow{AL_TRUE}; + std::atomic killNow{AL_TRUE}; althrd_t thread; }; diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 7c7f5e5e..440da5e8 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -45,7 +45,7 @@ constexpr ALCchar nullDevice[] = "No Output"; struct ALCnullBackend final : public ALCbackend { - ATOMIC(int) killNow{AL_TRUE}; + std::atomic killNow{AL_TRUE}; std::thread thread; }; diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 5b80ea65..2a87e19b 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -148,7 +148,7 @@ struct ALCopenslPlayback final : public ALCbackend { ALsizei mFrameSize{0}; - ATOMIC(ALenum) mKillNow{AL_TRUE}; + std::atomic mKillNow{AL_TRUE}; althrd_t mThread; }; diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index a6d1e0ea..66f3e601 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -51,7 +51,7 @@ struct qsa_data { ALvoid* buffer; ALsizei size; - ATOMIC(ALenum) killNow; + std::atomic killNow; althrd_t thread; }; diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index de5f74e4..5e7b48af 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -43,7 +43,7 @@ struct SndioPlayback final : public ALCbackend { ALvoid *mix_data{nullptr}; ALsizei data_size{0}; - ATOMIC(int) killNow{AL_TRUE}; + std::atomic killNow{AL_TRUE}; althrd_t thread; }; @@ -280,7 +280,7 @@ struct SndioCapture final : public ALCbackend { ll_ringbuffer_t *ring{nullptr}; - ATOMIC(int) killNow{AL_TRUE}; + std::atomic killNow{AL_TRUE}; althrd_t thread; }; diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index 93de4384..2d26fb6a 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -49,7 +49,7 @@ struct ALCsolarisBackend final : public ALCbackend { ALubyte *mix_data{nullptr}; int data_size{0}; - ATOMIC(ALenum) killNow{AL_TRUE}; + std::atomic killNow{AL_TRUE}; althrd_t thread; }; diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index bb37d979..ec5e787b 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -84,7 +84,7 @@ struct ALCwaveBackend final : public ALCbackend { al::vector mBuffer; - ATOMIC(ALenum) killNow{AL_TRUE}; + std::atomic killNow{AL_TRUE}; std::thread thread; }; diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index dfb57140..586fc507 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -54,7 +54,7 @@ struct ALeffectslotProps { EffectState *State; - ATOMIC(struct ALeffectslotProps*) next; + std::atomic next; }; @@ -73,7 +73,7 @@ struct ALeffectslot { RefCount ref{0u}; - ATOMIC(struct ALeffectslotProps*) Update{nullptr}; + std::atomic Update{nullptr}; struct { ALfloat Gain{1.0f}; diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h index 6b1dcda9..f3a39dfa 100644 --- a/OpenAL32/Include/alListener.h +++ b/OpenAL32/Include/alListener.h @@ -18,7 +18,7 @@ struct ALlistenerProps { ALfloat Up[3]; ALfloat Gain; - ATOMIC(ALlistenerProps*) next; + std::atomic next; }; struct ALlistener { @@ -32,7 +32,7 @@ struct ALlistener { /* Pointer to the most recent property values that are awaiting an update. */ - ATOMIC(ALlistenerProps*) Update{nullptr}; + std::atomic Update{nullptr}; struct { aluMatrixf Matrix; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index c08f9a09..297ff06f 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -667,7 +667,7 @@ typedef void (*POSTPROCESS)(ALCdevice *device, ALsizei SamplesToDo); struct ALCdevice_struct { RefCount ref{1u}; - ATOMIC(ALenum) Connected{AL_TRUE}; + std::atomic Connected{AL_TRUE}; DeviceType Type{}; ALuint Frequency{}; @@ -687,7 +687,7 @@ struct ALCdevice_struct { std::string DeviceName; - ATOMIC(ALCenum) LastError{ALC_NO_ERROR}; + std::atomic LastError{ALC_NO_ERROR}; // Maximum number of sources that can be created ALuint SourcesMax{}; @@ -783,12 +783,12 @@ struct ALCdevice_struct { RefCount MixCount{0u}; // Contexts created on this device - ATOMIC(ALCcontext*) ContextList{nullptr}; + std::atomic ContextList{nullptr}; almtx_t BackendLock; ALCbackend *Backend{nullptr}; - ATOMIC(ALCdevice*) next{nullptr}; + std::atomic next{nullptr}; ALCdevice_struct(DeviceType type); diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 05ccdadf..2cbc5ddc 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -19,7 +19,7 @@ struct ALsource; typedef struct ALbufferlistitem { - ATOMIC(struct ALbufferlistitem*) next; + std::atomic next; ALsizei max_samples; ALsizei num_buffers; struct ALbuffer *buffers[]; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index eb71290a..d51000c8 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -144,7 +144,7 @@ typedef struct SendParams { struct ALvoiceProps { - ATOMIC(struct ALvoiceProps*) next; + std::atomic next; ALfloat Pitch; ALfloat Gain; @@ -203,28 +203,28 @@ struct ALvoiceProps { #define VOICE_HAS_NFC (1<<3) typedef struct ALvoice { - struct ALvoiceProps *Props; + ALvoiceProps *Props; - ATOMIC(struct ALvoiceProps*) Update; + std::atomic Update; - ATOMIC(struct ALsource*) Source; - ATOMIC(bool) Playing; + std::atomic Source; + std::atomic Playing; /** * Source offset in samples, relative to the currently playing buffer, NOT * the whole queue, and the fractional (fixed-point) offset to the next * sample. */ - ATOMIC(ALuint) position; - ATOMIC(ALsizei) position_fraction; + std::atomic position; + std::atomic position_fraction; /* Current buffer queue item being played. */ - ATOMIC(struct ALbufferlistitem*) current_buffer; + std::atomic current_buffer; /* Buffer queue item to loop to at end of queue (will be NULL for non- * looping voices). */ - ATOMIC(struct ALbufferlistitem*) loop_buffer; + std::atomic loop_buffer; /** * Number of channels and bytes-per-sample for the attached source's diff --git a/common/atomic.h b/common/atomic.h index eaae8fb8..15c34953 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -12,8 +12,6 @@ #define almemory_order_acq_rel std::memory_order_acq_rel #define almemory_order_seq_cst std::memory_order_seq_cst -#define ATOMIC(T) std::atomic - #define ATOMIC_LOAD std::atomic_load_explicit #define ATOMIC_STORE std::atomic_store_explicit -- cgit v1.2.3 From 04cbdbd5695bb8547966cc850ad854b0640ef7b0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 14:53:20 -0800 Subject: Remove some unused macros --- common/atomic.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/common/atomic.h b/common/atomic.h index 15c34953..2b512653 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -15,16 +15,9 @@ #define ATOMIC_LOAD std::atomic_load_explicit #define ATOMIC_STORE std::atomic_store_explicit -#define ATOMIC_ADD std::atomic_fetch_add_explicit -#define ATOMIC_SUB std::atomic_fetch_sub_explicit - - #define ATOMIC_LOAD_SEQ(_val) ATOMIC_LOAD(_val, almemory_order_seq_cst) #define ATOMIC_STORE_SEQ(_val, _newval) ATOMIC_STORE(_val, _newval, almemory_order_seq_cst) -#define ATOMIC_ADD_SEQ(_val, _incr) ATOMIC_ADD(_val, _incr, almemory_order_seq_cst) -#define ATOMIC_SUB_SEQ(_val, _decr) ATOMIC_SUB(_val, _decr, almemory_order_seq_cst) - using RefCount = std::atomic; -- cgit v1.2.3 From 04c2802a82e3db8a49b197037ca2e5b2ab74fe8e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 17:31:04 -0800 Subject: Rename some struct members --- Alc/backends/alsa.cpp | 252 ++++++++++++++++++++++---------------------- Alc/backends/coreaudio.cpp | 184 ++++++++++++++++---------------- Alc/backends/dsound.cpp | 14 +-- Alc/backends/jack.cpp | 8 +- Alc/backends/null.cpp | 14 +-- Alc/backends/oss.cpp | 58 +++++----- Alc/backends/portaudio.cpp | 129 +++++++++++------------ Alc/backends/pulseaudio.cpp | 18 ++-- Alc/backends/qsa.cpp | 12 +-- Alc/backends/sndio.cpp | 18 ++-- Alc/backends/solaris.cpp | 10 +- Alc/backends/wave.cpp | 14 +-- Alc/backends/winmm.cpp | 30 +++--- 13 files changed, 378 insertions(+), 383 deletions(-) diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index 1a048fc7..20ffc559 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -423,12 +423,12 @@ int verify_state(snd_pcm_t *handle) struct ALCplaybackAlsa final : public ALCbackend { - snd_pcm_t *pcmHandle{nullptr}; + snd_pcm_t *PcmHandle{nullptr}; - al::vector buffer; + al::vector Buffer; - std::atomic killNow{AL_TRUE}; - std::thread thread; + std::atomic mKillNow{AL_TRUE}; + std::thread mThread; }; int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self); @@ -458,9 +458,9 @@ void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device) void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self) { - if(self->pcmHandle) - snd_pcm_close(self->pcmHandle); - self->pcmHandle = nullptr; + if(self->PcmHandle) + snd_pcm_close(self->PcmHandle); + self->PcmHandle = nullptr; ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCplaybackAlsa(); @@ -476,9 +476,9 @@ int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) snd_pcm_uframes_t update_size{device->UpdateSize}; snd_pcm_uframes_t num_updates{device->NumUpdates}; - while(!self->killNow.load(std::memory_order_acquire)) + while(!self->mKillNow.load(std::memory_order_acquire)) { - int state{verify_state(self->pcmHandle)}; + int state{verify_state(self->PcmHandle)}; if(state < 0) { ERR("Invalid state detected: %s\n", snd_strerror(state)); @@ -488,7 +488,7 @@ int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) break; } - snd_pcm_sframes_t avail{snd_pcm_avail_update(self->pcmHandle)}; + snd_pcm_sframes_t avail{snd_pcm_avail_update(self->PcmHandle)}; if(avail < 0) { ERR("available update failed: %s\n", snd_strerror(avail)); @@ -498,7 +498,7 @@ int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) if((snd_pcm_uframes_t)avail > update_size*(num_updates+1)) { WARN("available samples exceeds the buffer size\n"); - snd_pcm_reset(self->pcmHandle); + snd_pcm_reset(self->PcmHandle); continue; } @@ -507,14 +507,14 @@ int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) { if(state != SND_PCM_STATE_RUNNING) { - int err{snd_pcm_start(self->pcmHandle)}; + int err{snd_pcm_start(self->PcmHandle)}; if(err < 0) { ERR("start failed: %s\n", snd_strerror(err)); continue; } } - if(snd_pcm_wait(self->pcmHandle, 1000) == 0) + if(snd_pcm_wait(self->PcmHandle, 1000) == 0) ERR("Wait timeout... buffer size too low?\n"); continue; } @@ -528,7 +528,7 @@ int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) const snd_pcm_channel_area_t *areas{}; snd_pcm_uframes_t offset{}; - int err{snd_pcm_mmap_begin(self->pcmHandle, &areas, &offset, &frames)}; + int err{snd_pcm_mmap_begin(self->PcmHandle, &areas, &offset, &frames)}; if(err < 0) { ERR("mmap begin error: %s\n", snd_strerror(err)); @@ -538,7 +538,7 @@ int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) char *WritePtr{(char*)areas->addr + (offset * areas->step / 8)}; aluMixData(device, WritePtr, frames); - snd_pcm_sframes_t commitres{snd_pcm_mmap_commit(self->pcmHandle, offset, frames)}; + snd_pcm_sframes_t commitres{snd_pcm_mmap_commit(self->PcmHandle, offset, frames)}; if(commitres < 0 || (commitres-frames) != 0) { ERR("mmap commit error: %s\n", @@ -563,9 +563,9 @@ int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self) snd_pcm_uframes_t update_size{device->UpdateSize}; snd_pcm_uframes_t num_updates{device->NumUpdates}; - while(!self->killNow.load(std::memory_order_acquire)) + while(!self->mKillNow.load(std::memory_order_acquire)) { - int state{verify_state(self->pcmHandle)}; + int state{verify_state(self->PcmHandle)}; if(state < 0) { ERR("Invalid state detected: %s\n", snd_strerror(state)); @@ -575,7 +575,7 @@ int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self) break; } - snd_pcm_sframes_t avail{snd_pcm_avail_update(self->pcmHandle)}; + snd_pcm_sframes_t avail{snd_pcm_avail_update(self->PcmHandle)}; if(avail < 0) { ERR("available update failed: %s\n", snd_strerror(avail)); @@ -585,7 +585,7 @@ int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self) if((snd_pcm_uframes_t)avail > update_size*num_updates) { WARN("available samples exceeds the buffer size\n"); - snd_pcm_reset(self->pcmHandle); + snd_pcm_reset(self->PcmHandle); continue; } @@ -593,25 +593,25 @@ int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self) { if(state != SND_PCM_STATE_RUNNING) { - int err{snd_pcm_start(self->pcmHandle)}; + int err{snd_pcm_start(self->PcmHandle)}; if(err < 0) { ERR("start failed: %s\n", snd_strerror(err)); continue; } } - if(snd_pcm_wait(self->pcmHandle, 1000) == 0) + if(snd_pcm_wait(self->PcmHandle, 1000) == 0) ERR("Wait timeout... buffer size too low?\n"); continue; } ALCplaybackAlsa_lock(self); - char *WritePtr{self->buffer.data()}; - avail = snd_pcm_bytes_to_frames(self->pcmHandle, self->buffer.size()); + char *WritePtr{self->Buffer.data()}; + avail = snd_pcm_bytes_to_frames(self->PcmHandle, self->Buffer.size()); aluMixData(device, WritePtr, avail); while(avail > 0) { - int ret = snd_pcm_writei(self->pcmHandle, WritePtr, avail); + int ret = snd_pcm_writei(self->PcmHandle, WritePtr, avail); switch (ret) { case -EAGAIN: @@ -621,21 +621,21 @@ int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self) #endif case -EPIPE: case -EINTR: - ret = snd_pcm_recover(self->pcmHandle, ret, 1); + ret = snd_pcm_recover(self->PcmHandle, ret, 1); if(ret < 0) avail = 0; break; default: if (ret >= 0) { - WritePtr += snd_pcm_frames_to_bytes(self->pcmHandle, ret); + WritePtr += snd_pcm_frames_to_bytes(self->PcmHandle, ret); avail -= ret; } break; } if (ret < 0) { - ret = snd_pcm_prepare(self->pcmHandle); + ret = snd_pcm_prepare(self->PcmHandle); if(ret < 0) break; } @@ -670,7 +670,7 @@ ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name) } TRACE("Opening device \"%s\"\n", driver); - int err{snd_pcm_open(&self->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)}; + int err{snd_pcm_open(&self->PcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)}; if(err < 0) { ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(err)); @@ -730,15 +730,15 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) int dir, err; snd_pcm_hw_params_malloc(&hp); #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error - CHECK(snd_pcm_hw_params_any(self->pcmHandle, hp)); + CHECK(snd_pcm_hw_params_any(self->PcmHandle, hp)); /* set interleaved access */ - if(!allowmmap || snd_pcm_hw_params_set_access(self->pcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) + if(!allowmmap || snd_pcm_hw_params_set_access(self->PcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) { /* No mmap */ - CHECK(snd_pcm_hw_params_set_access(self->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); + CHECK(snd_pcm_hw_params_set_access(self->PcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); } /* test and set format (implicitly sets sample bits) */ - if(snd_pcm_hw_params_test_format(self->pcmHandle, hp, format) < 0) + if(snd_pcm_hw_params_test_format(self->PcmHandle, hp, format) < 0) { static const struct { snd_pcm_format_t format; @@ -756,16 +756,16 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) for(const auto &fmt : formatlist) { format = fmt.format; - if(snd_pcm_hw_params_test_format(self->pcmHandle, hp, format) >= 0) + if(snd_pcm_hw_params_test_format(self->PcmHandle, hp, format) >= 0) { device->FmtType = fmt.fmttype; break; } } } - CHECK(snd_pcm_hw_params_set_format(self->pcmHandle, hp, format)); + CHECK(snd_pcm_hw_params_set_format(self->PcmHandle, hp, format)); /* test and set channels (implicitly sets frame bits) */ - if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder)) < 0) + if(snd_pcm_hw_params_test_channels(self->PcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder)) < 0) { static const enum DevFmtChannels channellist[] = { DevFmtStereo, @@ -777,7 +777,7 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) for(const auto &chan : channellist) { - if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(chan, 0)) >= 0) + if(snd_pcm_hw_params_test_channels(self->PcmHandle, hp, ChannelsFromDevFmt(chan, 0)) >= 0) { device->FmtChans = chan; device->mAmbiOrder = 0; @@ -785,25 +785,25 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) } } } - CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder))); + CHECK(snd_pcm_hw_params_set_channels(self->PcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder))); /* set rate (implicitly constrains period/buffer parameters) */ if(!GetConfigValueBool(device->DeviceName.c_str(), "alsa", "allow-resampler", 0) || !(device->Flags&DEVICE_FREQUENCY_REQUEST)) { - if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0) + if(snd_pcm_hw_params_set_rate_resample(self->PcmHandle, hp, 0) < 0) ERR("Failed to disable ALSA resampler\n"); } - else if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 1) < 0) + else if(snd_pcm_hw_params_set_rate_resample(self->PcmHandle, hp, 1) < 0) ERR("Failed to enable ALSA resampler\n"); - CHECK(snd_pcm_hw_params_set_rate_near(self->pcmHandle, hp, &rate, nullptr)); + CHECK(snd_pcm_hw_params_set_rate_near(self->PcmHandle, hp, &rate, nullptr)); /* set buffer time (implicitly constrains period/buffer parameters) */ - if((err=snd_pcm_hw_params_set_buffer_time_near(self->pcmHandle, hp, &bufferLen, nullptr)) < 0) + if((err=snd_pcm_hw_params_set_buffer_time_near(self->PcmHandle, hp, &bufferLen, nullptr)) < 0) ERR("snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err)); /* set period time (implicitly sets buffer size/bytes/time and period size/bytes) */ - if((err=snd_pcm_hw_params_set_period_time_near(self->pcmHandle, hp, &periodLen, nullptr)) < 0) + if((err=snd_pcm_hw_params_set_period_time_near(self->PcmHandle, hp, &periodLen, nullptr)) < 0) ERR("snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err)); /* install and prepare hardware configuration */ - CHECK(snd_pcm_hw_params(self->pcmHandle, hp)); + CHECK(snd_pcm_hw_params(self->PcmHandle, hp)); /* retrieve configuration info */ CHECK(snd_pcm_hw_params_get_access(hp, &access)); @@ -815,10 +815,10 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) hp = nullptr; snd_pcm_sw_params_malloc(&sp); - CHECK(snd_pcm_sw_params_current(self->pcmHandle, sp)); - CHECK(snd_pcm_sw_params_set_avail_min(self->pcmHandle, sp, periodSizeInFrames)); - CHECK(snd_pcm_sw_params_set_stop_threshold(self->pcmHandle, sp, periodSizeInFrames*periods)); - CHECK(snd_pcm_sw_params(self->pcmHandle, sp)); + CHECK(snd_pcm_sw_params_current(self->PcmHandle, sp)); + CHECK(snd_pcm_sw_params_set_avail_min(self->PcmHandle, sp, periodSizeInFrames)); + CHECK(snd_pcm_sw_params_set_stop_threshold(self->PcmHandle, sp, periodSizeInFrames*periods)); + CHECK(snd_pcm_sw_params(self->PcmHandle, sp)); #undef CHECK snd_pcm_sw_params_free(sp); sp = nullptr; @@ -849,7 +849,7 @@ ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) snd_pcm_hw_params_malloc(&hp); #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error - CHECK(snd_pcm_hw_params_current(self->pcmHandle, hp)); + CHECK(snd_pcm_hw_params_current(self->PcmHandle, hp)); /* retrieve configuration info */ CHECK(snd_pcm_hw_params_get_access(hp, &access)); #undef CHECK @@ -858,23 +858,23 @@ ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) if(access == SND_PCM_ACCESS_RW_INTERLEAVED) { - self->buffer.resize(snd_pcm_frames_to_bytes(self->pcmHandle, device->UpdateSize)); + self->Buffer.resize(snd_pcm_frames_to_bytes(self->PcmHandle, device->UpdateSize)); thread_func = ALCplaybackAlsa_mixerNoMMapProc; } else { - err = snd_pcm_prepare(self->pcmHandle); + err = snd_pcm_prepare(self->PcmHandle); if(err < 0) { - ERR("snd_pcm_prepare(data->pcmHandle) failed: %s\n", snd_strerror(err)); + ERR("snd_pcm_prepare(data->PcmHandle) failed: %s\n", snd_strerror(err)); return ALC_FALSE; } thread_func = ALCplaybackAlsa_mixerProc; } try { - self->killNow.store(AL_FALSE, std::memory_order_release); - self->thread = std::thread(thread_func, self); + self->mKillNow.store(AL_FALSE, std::memory_order_release); + self->mThread = std::thread(thread_func, self); return ALC_TRUE; } catch(std::exception& e) { @@ -882,7 +882,7 @@ ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) } catch(...) { } - self->buffer.clear(); + self->Buffer.clear(); return ALC_FALSE; error: @@ -893,12 +893,12 @@ error: void ALCplaybackAlsa_stop(ALCplaybackAlsa *self) { - if(self->killNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->thread.joinable()) + if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->mThread.joinable()) return; - self->thread.join(); + self->mThread.join(); - self->buffer.clear(); + self->Buffer.clear(); } ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self) @@ -909,7 +909,7 @@ ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self) ALCplaybackAlsa_lock(self); ret.ClockTime = GetDeviceClockTime(device); snd_pcm_sframes_t delay{}; - int err{snd_pcm_delay(self->pcmHandle, &delay)}; + int err{snd_pcm_delay(self->PcmHandle, &delay)}; if(err < 0) { ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); @@ -924,14 +924,14 @@ ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self) struct ALCcaptureAlsa final : public ALCbackend { - snd_pcm_t *pcmHandle{nullptr}; + snd_pcm_t *PcmHandle{nullptr}; - al::vector buffer; + al::vector Buffer; - bool doCapture{false}; - ll_ringbuffer_t *ring{nullptr}; + bool DoCapture{false}; + ll_ringbuffer_t *Ring{nullptr}; - snd_pcm_sframes_t last_avail{0}; + snd_pcm_sframes_t mLastAvail{0}; }; void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device); @@ -959,12 +959,12 @@ void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device) void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self) { - if(self->pcmHandle) - snd_pcm_close(self->pcmHandle); - self->pcmHandle = nullptr; + if(self->PcmHandle) + snd_pcm_close(self->PcmHandle); + self->PcmHandle = nullptr; - ll_ringbuffer_free(self->ring); - self->ring = nullptr; + ll_ringbuffer_free(self->Ring); + self->Ring = nullptr; ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCcaptureAlsa(); @@ -995,7 +995,7 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) } TRACE("Opening device \"%s\"\n", driver); - int err{snd_pcm_open(&self->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)}; + int err{snd_pcm_open(&self->PcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)}; if(err < 0) { ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err)); @@ -1040,26 +1040,26 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) snd_pcm_hw_params_t *hp{}; snd_pcm_hw_params_malloc(&hp); #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error - CHECK(snd_pcm_hw_params_any(self->pcmHandle, hp)); + CHECK(snd_pcm_hw_params_any(self->PcmHandle, hp)); /* set interleaved access */ - CHECK(snd_pcm_hw_params_set_access(self->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); + CHECK(snd_pcm_hw_params_set_access(self->PcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); /* set format (implicitly sets sample bits) */ - CHECK(snd_pcm_hw_params_set_format(self->pcmHandle, hp, format)); + CHECK(snd_pcm_hw_params_set_format(self->PcmHandle, hp, format)); /* set channels (implicitly sets frame bits) */ - CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder))); + CHECK(snd_pcm_hw_params_set_channels(self->PcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder))); /* set rate (implicitly constrains period/buffer parameters) */ - CHECK(snd_pcm_hw_params_set_rate(self->pcmHandle, hp, device->Frequency, 0)); + CHECK(snd_pcm_hw_params_set_rate(self->PcmHandle, hp, device->Frequency, 0)); /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ - if(snd_pcm_hw_params_set_buffer_size_min(self->pcmHandle, hp, &bufferSizeInFrames) < 0) + if(snd_pcm_hw_params_set_buffer_size_min(self->PcmHandle, hp, &bufferSizeInFrames) < 0) { TRACE("Buffer too large, using intermediate ring buffer\n"); needring = true; - CHECK(snd_pcm_hw_params_set_buffer_size_near(self->pcmHandle, hp, &bufferSizeInFrames)); + CHECK(snd_pcm_hw_params_set_buffer_size_near(self->PcmHandle, hp, &bufferSizeInFrames)); } /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ - CHECK(snd_pcm_hw_params_set_period_size_near(self->pcmHandle, hp, &periodSizeInFrames, nullptr)); + CHECK(snd_pcm_hw_params_set_period_size_near(self->PcmHandle, hp, &periodSizeInFrames, nullptr)); /* install and prepare hardware configuration */ - CHECK(snd_pcm_hw_params(self->pcmHandle, hp)); + CHECK(snd_pcm_hw_params(self->PcmHandle, hp)); /* retrieve configuration info */ CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, nullptr)); #undef CHECK @@ -1068,12 +1068,12 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) if(needring) { - self->ring = ll_ringbuffer_create( + self->Ring = ll_ringbuffer_create( device->UpdateSize*device->NumUpdates, FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder), false ); - if(!self->ring) + if(!self->Ring) { ERR("ring buffer create failed\n"); goto error2; @@ -1089,22 +1089,22 @@ error: if(hp) snd_pcm_hw_params_free(hp); error2: - ll_ringbuffer_free(self->ring); - self->ring = nullptr; - snd_pcm_close(self->pcmHandle); - self->pcmHandle = nullptr; + ll_ringbuffer_free(self->Ring); + self->Ring = nullptr; + snd_pcm_close(self->PcmHandle); + self->PcmHandle = nullptr; return ALC_INVALID_VALUE; } ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self) { - int err{snd_pcm_prepare(self->pcmHandle)}; + int err{snd_pcm_prepare(self->PcmHandle)}; if(err < 0) ERR("prepare failed: %s\n", snd_strerror(err)); else { - err = snd_pcm_start(self->pcmHandle); + err = snd_pcm_start(self->PcmHandle); if(err < 0) ERR("start failed: %s\n", snd_strerror(err)); } @@ -1115,7 +1115,7 @@ ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self) return ALC_FALSE; } - self->doCapture = true; + self->DoCapture = true; return ALC_TRUE; } @@ -1125,60 +1125,60 @@ void ALCcaptureAlsa_stop(ALCcaptureAlsa *self) * snd_pcm_drain is unreliable and snd_pcm_drop drops it. Capture what's * available now so it'll be available later after the drop. */ ALCuint avail{ALCcaptureAlsa_availableSamples(self)}; - if(!self->ring && avail > 0) + if(!self->Ring && avail > 0) { /* The ring buffer implicitly captures when checking availability. * Direct access needs to explicitly capture it into temp storage. */ - al::vector temp(snd_pcm_frames_to_bytes(self->pcmHandle, avail)); + al::vector temp(snd_pcm_frames_to_bytes(self->PcmHandle, avail)); ALCcaptureAlsa_captureSamples(self, temp.data(), avail); - self->buffer = std::move(temp); + self->Buffer = std::move(temp); } - int err{snd_pcm_drop(self->pcmHandle)}; + int err{snd_pcm_drop(self->PcmHandle)}; if(err < 0) ERR("drop failed: %s\n", snd_strerror(err)); - self->doCapture = false; + self->DoCapture = false; } ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALCuint samples) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - if(self->ring) + if(self->Ring) { - ll_ringbuffer_read(self->ring, static_cast(buffer), samples); + ll_ringbuffer_read(self->Ring, static_cast(buffer), samples); return ALC_NO_ERROR; } - self->last_avail -= samples; + self->mLastAvail -= samples; while(ATOMIC_LOAD(&device->Connected, almemory_order_acquire) && samples > 0) { snd_pcm_sframes_t amt{0}; - if(!self->buffer.empty()) + if(!self->Buffer.empty()) { /* First get any data stored from the last stop */ - amt = snd_pcm_bytes_to_frames(self->pcmHandle, self->buffer.size()); + amt = snd_pcm_bytes_to_frames(self->PcmHandle, self->Buffer.size()); if((snd_pcm_uframes_t)amt > samples) amt = samples; - amt = snd_pcm_frames_to_bytes(self->pcmHandle, amt); - memcpy(buffer, self->buffer.data(), amt); + amt = snd_pcm_frames_to_bytes(self->PcmHandle, amt); + memcpy(buffer, self->Buffer.data(), amt); - self->buffer.erase(self->buffer.begin(), self->buffer.begin()+amt); - amt = snd_pcm_bytes_to_frames(self->pcmHandle, amt); + self->Buffer.erase(self->Buffer.begin(), self->Buffer.begin()+amt); + amt = snd_pcm_bytes_to_frames(self->PcmHandle, amt); } - else if(self->doCapture) - amt = snd_pcm_readi(self->pcmHandle, buffer, samples); + else if(self->DoCapture) + amt = snd_pcm_readi(self->PcmHandle, buffer, samples); if(amt < 0) { ERR("read error: %s\n", snd_strerror(amt)); if(amt == -EAGAIN) continue; - if((amt=snd_pcm_recover(self->pcmHandle, amt, 1)) >= 0) + if((amt=snd_pcm_recover(self->PcmHandle, amt, 1)) >= 0) { - amt = snd_pcm_start(self->pcmHandle); + amt = snd_pcm_start(self->PcmHandle); if(amt >= 0) - amt = snd_pcm_avail_update(self->pcmHandle); + amt = snd_pcm_avail_update(self->PcmHandle); } if(amt < 0) { @@ -1198,7 +1198,7 @@ ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALC } if(samples > 0) memset(buffer, ((device->FmtType == DevFmtUByte) ? 0x80 : 0), - snd_pcm_frames_to_bytes(self->pcmHandle, samples)); + snd_pcm_frames_to_bytes(self->PcmHandle, samples)); return ALC_NO_ERROR; } @@ -1208,18 +1208,18 @@ ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; snd_pcm_sframes_t avail{0}; - if(ATOMIC_LOAD(&device->Connected, almemory_order_acquire) && self->doCapture) - avail = snd_pcm_avail_update(self->pcmHandle); + if(ATOMIC_LOAD(&device->Connected, almemory_order_acquire) && self->DoCapture) + avail = snd_pcm_avail_update(self->PcmHandle); if(avail < 0) { ERR("avail update failed: %s\n", snd_strerror(avail)); - if((avail=snd_pcm_recover(self->pcmHandle, avail, 1)) >= 0) + if((avail=snd_pcm_recover(self->PcmHandle, avail, 1)) >= 0) { - if(self->doCapture) - avail = snd_pcm_start(self->pcmHandle); + if(self->DoCapture) + avail = snd_pcm_start(self->PcmHandle); if(avail >= 0) - avail = snd_pcm_avail_update(self->pcmHandle); + avail = snd_pcm_avail_update(self->PcmHandle); } if(avail < 0) { @@ -1228,33 +1228,33 @@ ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) } } - if(!self->ring) + if(!self->Ring) { if(avail < 0) avail = 0; - avail += snd_pcm_bytes_to_frames(self->pcmHandle, self->buffer.size()); - if(avail > self->last_avail) self->last_avail = avail; - return self->last_avail; + avail += snd_pcm_bytes_to_frames(self->PcmHandle, self->Buffer.size()); + if(avail > self->mLastAvail) self->mLastAvail = avail; + return self->mLastAvail; } while(avail > 0) { - auto vec = ll_ringbuffer_get_write_vector(self->ring); + auto vec = ll_ringbuffer_get_write_vector(self->Ring); if(vec.first.len == 0) break; snd_pcm_sframes_t amt{std::min(vec.first.len, avail)}; - amt = snd_pcm_readi(self->pcmHandle, vec.first.buf, amt); + amt = snd_pcm_readi(self->PcmHandle, vec.first.buf, amt); if(amt < 0) { ERR("read error: %s\n", snd_strerror(amt)); if(amt == -EAGAIN) continue; - if((amt=snd_pcm_recover(self->pcmHandle, amt, 1)) >= 0) + if((amt=snd_pcm_recover(self->PcmHandle, amt, 1)) >= 0) { - if(self->doCapture) - amt = snd_pcm_start(self->pcmHandle); + if(self->DoCapture) + amt = snd_pcm_start(self->PcmHandle); if(amt >= 0) - amt = snd_pcm_avail_update(self->pcmHandle); + amt = snd_pcm_avail_update(self->PcmHandle); } if(amt < 0) { @@ -1266,11 +1266,11 @@ ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) continue; } - ll_ringbuffer_write_advance(self->ring, amt); + ll_ringbuffer_write_advance(self->Ring, amt); avail -= amt; } - return ll_ringbuffer_read_space(self->ring); + return ll_ringbuffer_read_space(self->Ring); } ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self) @@ -1281,7 +1281,7 @@ ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self) ALCcaptureAlsa_lock(self); ret.ClockTime = GetDeviceClockTime(device); snd_pcm_sframes_t delay{}; - int err{snd_pcm_delay(self->pcmHandle, &delay)}; + int err{snd_pcm_delay(self->PcmHandle, &delay)}; if(err < 0) { ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index ff02a706..f5574965 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -39,10 +39,10 @@ static const ALCchar ca_device[] = "CoreAudio Default"; struct ALCcoreAudioPlayback final : public ALCbackend { - AudioUnit audioUnit; + AudioUnit AudioUnit; - ALuint frameSize; - AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD + ALuint FrameSize; + AudioStreamBasicDescription Format; // This is the OpenAL format as a CoreAudio ASBD }; static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device); @@ -67,14 +67,14 @@ static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCcoreAudioPlayback, ALCbackend, self); - self->frameSize = 0; - memset(&self->format, 0, sizeof(self->format)); + self->FrameSize = 0; + memset(&self->Format, 0, sizeof(self->Format)); } static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self) { - AudioUnitUninitialize(self->audioUnit); - AudioComponentInstanceDispose(self->audioUnit); + AudioUnitUninitialize(self->AudioUnit); + AudioComponentInstanceDispose(self->AudioUnit); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCcoreAudioPlayback(); @@ -90,7 +90,7 @@ static OSStatus ALCcoreAudioPlayback_MixerProc(void *inRefCon, ALCcoreAudioPlayback_lock(self); aluMixData(device, ioData->mBuffers[0].mData, - ioData->mBuffers[0].mDataByteSize / self->frameSize); + ioData->mBuffers[0].mDataByteSize / self->FrameSize); ALCcoreAudioPlayback_unlock(self); return noErr; @@ -127,7 +127,7 @@ static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCch return ALC_INVALID_VALUE; } - err = AudioComponentInstanceNew(comp, &self->audioUnit); + err = AudioComponentInstanceNew(comp, &self->AudioUnit); if(err != noErr) { ERR("AudioComponentInstanceNew failed\n"); @@ -135,11 +135,11 @@ static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCch } /* init and start the default audio unit... */ - err = AudioUnitInitialize(self->audioUnit); + err = AudioUnitInitialize(self->AudioUnit); if(err != noErr) { ERR("AudioUnitInitialize failed\n"); - AudioComponentInstanceDispose(self->audioUnit); + AudioComponentInstanceDispose(self->AudioUnit); return ALC_INVALID_VALUE; } @@ -155,13 +155,13 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) OSStatus err; UInt32 size; - err = AudioUnitUninitialize(self->audioUnit); + err = AudioUnitUninitialize(self->AudioUnit); if(err != noErr) ERR("-- AudioUnitUninitialize failed.\n"); /* retrieve default output unit's properties (output side) */ size = sizeof(AudioStreamBasicDescription); - err = AudioUnitGetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, &size); + err = AudioUnitGetProperty(self->AudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, &size); if(err != noErr || size != sizeof(AudioStreamBasicDescription)) { ERR("AudioUnitGetProperty failed\n"); @@ -179,7 +179,7 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) #endif /* set default output unit's input side to match output side */ - err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, size); + err = AudioUnitSetProperty(self->AudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, size); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -263,7 +263,7 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) streamFormat.mFormatFlags |= kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsPacked; - err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription)); + err = AudioUnitSetProperty(self->AudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -271,11 +271,11 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) } /* setup callback */ - self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); + self->FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); input.inputProc = ALCcoreAudioPlayback_MixerProc; input.inputProcRefCon = self; - err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct)); + err = AudioUnitSetProperty(self->AudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -283,7 +283,7 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) } /* init the default audio unit... */ - err = AudioUnitInitialize(self->audioUnit); + err = AudioUnitInitialize(self->AudioUnit); if(err != noErr) { ERR("AudioUnitInitialize failed\n"); @@ -295,7 +295,7 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self) { - OSStatus err = AudioOutputUnitStart(self->audioUnit); + OSStatus err = AudioOutputUnitStart(self->AudioUnit); if(err != noErr) { ERR("AudioOutputUnitStart failed\n"); @@ -307,24 +307,24 @@ static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self) static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self) { - OSStatus err = AudioOutputUnitStop(self->audioUnit); + OSStatus err = AudioOutputUnitStop(self->AudioUnit); if(err != noErr) ERR("AudioOutputUnitStop failed\n"); } struct ALCcoreAudioCapture final : public ALCbackend { - AudioUnit audioUnit; + AudioUnit AudioUnit; - ALuint frameSize; - ALdouble sampleRateRatio; // Ratio of hardware sample rate / requested sample rate - AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD + ALuint FrameSize; + ALdouble SampleRateRatio; // Ratio of hardware sample rate / requested sample rate + AudioStreamBasicDescription Format; // This is the OpenAL format as a CoreAudio ASBD - AudioConverterRef audioConverter; // Sample rate converter if needed - AudioBufferList *bufferList; // Buffer for data coming from the input device - ALCvoid *resampleBuffer; // Buffer for returned RingBuffer data when resampling + AudioConverterRef AudioConverter; // Sample rate converter if needed + AudioBufferList *BufferList; // Buffer for data coming from the input device + ALCvoid *ResampleBuffer; // Buffer for returned RingBuffer data when resampling - ll_ringbuffer_t *ring; + ll_ringbuffer_t *Ring; }; static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device); @@ -372,31 +372,31 @@ static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice * ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCcoreAudioCapture, ALCbackend, self); - self->audioUnit = 0; - self->audioConverter = NULL; - self->bufferList = NULL; - self->resampleBuffer = NULL; - self->ring = NULL; + self->AudioUnit = 0; + self->AudioConverter = NULL; + self->BufferList = NULL; + self->ResampleBuffer = NULL; + self->Ring = NULL; } static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self) { - ll_ringbuffer_free(self->ring); - self->ring = NULL; + ll_ringbuffer_free(self->Ring); + self->Ring = NULL; - free(self->resampleBuffer); - self->resampleBuffer = NULL; + free(self->ResampleBuffer); + self->ResampleBuffer = NULL; - destroy_buffer_list(self->bufferList); - self->bufferList = NULL; + destroy_buffer_list(self->BufferList); + self->BufferList = NULL; - if(self->audioConverter) - AudioConverterDispose(self->audioConverter); - self->audioConverter = NULL; + if(self->AudioConverter) + AudioConverterDispose(self->AudioConverter); + self->AudioConverter = NULL; - if(self->audioUnit) - AudioComponentInstanceDispose(self->audioUnit); - self->audioUnit = 0; + if(self->AudioUnit) + AudioComponentInstanceDispose(self->AudioUnit); + self->AudioUnit = 0; ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCcoreAudioCapture(); @@ -412,15 +412,15 @@ static OSStatus ALCcoreAudioCapture_RecordProc(void *inRefCon, AudioUnitRenderActionFlags flags = 0; OSStatus err; - // fill the bufferList with data from the input device - err = AudioUnitRender(self->audioUnit, &flags, inTimeStamp, 1, inNumberFrames, self->bufferList); + // fill the BufferList with data from the input device + err = AudioUnitRender(self->AudioUnit, &flags, inTimeStamp, 1, inNumberFrames, self->BufferList); if(err != noErr) { ERR("AudioUnitRender error: %d\n", err); return err; } - ll_ringbuffer_write(self->ring, self->bufferList->mBuffers[0].mData, inNumberFrames); + ll_ringbuffer_write(self->Ring, self->BufferList->mBuffers[0].mData, inNumberFrames); return noErr; } @@ -432,13 +432,13 @@ static OSStatus ALCcoreAudioCapture_ConvertCallback(AudioConverterRef UNUSED(inA ALCcoreAudioCapture *self = reinterpret_cast(inUserData); // Read from the ring buffer and store temporarily in a large buffer - ll_ringbuffer_read(self->ring, self->resampleBuffer, *ioNumberDataPackets); + ll_ringbuffer_read(self->Ring, self->ResampleBuffer, *ioNumberDataPackets); // Set the input data ioData->mNumberBuffers = 1; - ioData->mBuffers[0].mNumberChannels = self->format.mChannelsPerFrame; - ioData->mBuffers[0].mData = self->resampleBuffer; - ioData->mBuffers[0].mDataByteSize = (*ioNumberDataPackets) * self->format.mBytesPerFrame; + ioData->mBuffers[0].mNumberChannels = self->Format.mChannelsPerFrame; + ioData->mBuffers[0].mData = self->ResampleBuffer; + ioData->mBuffers[0].mDataByteSize = (*ioNumberDataPackets) * self->Format.mBytesPerFrame; return noErr; } @@ -483,7 +483,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } // Open the component - err = AudioComponentInstanceNew(comp, &self->audioUnit); + err = AudioComponentInstanceNew(comp, &self->AudioUnit); if(err != noErr) { ERR("AudioComponentInstanceNew failed\n"); @@ -492,7 +492,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar // Turn off AudioUnit output enableIO = 0; - err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint)); + err = AudioUnitSetProperty(self->AudioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -501,7 +501,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar // Turn on AudioUnit input enableIO = 1; - err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint)); + err = AudioUnitSetProperty(self->AudioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -531,7 +531,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } // Track the input device - err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID)); + err = AudioUnitSetProperty(self->AudioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -544,7 +544,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar input.inputProc = ALCcoreAudioCapture_RecordProc; input.inputProcRefCon = self; - err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct)); + err = AudioUnitSetProperty(self->AudioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -552,7 +552,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } // Initialize the device - err = AudioUnitInitialize(self->audioUnit); + err = AudioUnitInitialize(self->AudioUnit); if(err != noErr) { ERR("AudioUnitInitialize failed\n"); @@ -561,7 +561,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar // Get the hardware format propertySize = sizeof(AudioStreamBasicDescription); - err = AudioUnitGetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize); + err = AudioUnitGetProperty(self->AudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize); if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription)) { ERR("AudioUnitGetProperty failed\n"); @@ -621,8 +621,8 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar requestedFormat.mFramesPerPacket = 1; // save requested format description for later use - self->format = requestedFormat; - self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); + self->Format = requestedFormat; + self->FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); // Use intermediate format for sample rate conversion (outputFormat) // Set sample rate to the same as hardware for resampling later @@ -630,11 +630,11 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar outputFormat.mSampleRate = hardwareFormat.mSampleRate; // Determine sample rate ratio for resampling - self->sampleRateRatio = outputFormat.mSampleRate / device->Frequency; + self->SampleRateRatio = outputFormat.mSampleRate / device->Frequency; // The output format should be the requested format, but using the hardware sample rate // This is because the AudioUnit will automatically scale other properties, except for sample rate - err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat)); + err = AudioUnitSetProperty(self->AudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -642,8 +642,8 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } // Set the AudioUnit output format frame count - outputFrameCount = device->UpdateSize * self->sampleRateRatio; - err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount)); + outputFrameCount = device->UpdateSize * self->SampleRateRatio; + err = AudioUnitSetProperty(self->AudioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount)); if(err != noErr) { ERR("AudioUnitSetProperty failed: %d\n", err); @@ -651,7 +651,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } // Set up sample converter - err = AudioConverterNew(&outputFormat, &requestedFormat, &self->audioConverter); + err = AudioConverterNew(&outputFormat, &requestedFormat, &self->AudioConverter); if(err != noErr) { ERR("AudioConverterNew failed: %d\n", err); @@ -659,36 +659,36 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } // Create a buffer for use in the resample callback - self->resampleBuffer = malloc(device->UpdateSize * self->frameSize * self->sampleRateRatio); + self->ResampleBuffer = malloc(device->UpdateSize * self->FrameSize * self->SampleRateRatio); // Allocate buffer for the AudioUnit output - self->bufferList = allocate_buffer_list(outputFormat.mChannelsPerFrame, device->UpdateSize * self->frameSize * self->sampleRateRatio); - if(self->bufferList == NULL) + self->BufferList = allocate_buffer_list(outputFormat.mChannelsPerFrame, device->UpdateSize * self->FrameSize * self->SampleRateRatio); + if(self->BufferList == NULL) goto error; - self->ring = ll_ringbuffer_create( - (size_t)ceil(device->UpdateSize*self->sampleRateRatio*device->NumUpdates), - self->frameSize, false + self->Ring = ll_ringbuffer_create( + (size_t)ceil(device->UpdateSize*self->SampleRateRatio*device->NumUpdates), + self->FrameSize, false ); - if(!self->ring) goto error; + if(!self->Ring) goto error; device->DeviceName = name; return ALC_NO_ERROR; error: - ll_ringbuffer_free(self->ring); - self->ring = NULL; - free(self->resampleBuffer); - self->resampleBuffer = NULL; - destroy_buffer_list(self->bufferList); - self->bufferList = NULL; - - if(self->audioConverter) - AudioConverterDispose(self->audioConverter); - self->audioConverter = NULL; - if(self->audioUnit) - AudioComponentInstanceDispose(self->audioUnit); - self->audioUnit = 0; + ll_ringbuffer_free(self->Ring); + self->Ring = NULL; + free(self->ResampleBuffer); + self->ResampleBuffer = NULL; + destroy_buffer_list(self->BufferList); + self->BufferList = NULL; + + if(self->AudioConverter) + AudioConverterDispose(self->AudioConverter); + self->AudioConverter = NULL; + if(self->AudioUnit) + AudioComponentInstanceDispose(self->AudioUnit); + self->AudioUnit = 0; return ALC_INVALID_VALUE; } @@ -696,7 +696,7 @@ error: static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self) { - OSStatus err = AudioOutputUnitStart(self->audioUnit); + OSStatus err = AudioOutputUnitStart(self->AudioUnit); if(err != noErr) { ERR("AudioOutputUnitStart failed\n"); @@ -707,7 +707,7 @@ static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self) static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self) { - OSStatus err = AudioOutputUnitStop(self->audioUnit); + OSStatus err = AudioOutputUnitStop(self->AudioUnit); if(err != noErr) ERR("AudioOutputUnitStop failed\n"); } @@ -726,13 +726,13 @@ static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALC // Point the resampling buffer to the capture buffer audiobuf.list.mNumberBuffers = 1; - audiobuf.list.mBuffers[0].mNumberChannels = self->format.mChannelsPerFrame; - audiobuf.list.mBuffers[0].mDataByteSize = samples * self->frameSize; + audiobuf.list.mBuffers[0].mNumberChannels = self->Format.mChannelsPerFrame; + audiobuf.list.mBuffers[0].mDataByteSize = samples * self->FrameSize; audiobuf.list.mBuffers[0].mData = buffer; // Resample into another AudioBufferList frameCount = samples; - err = AudioConverterFillComplexBuffer(self->audioConverter, + err = AudioConverterFillComplexBuffer(self->AudioConverter, ALCcoreAudioCapture_ConvertCallback, self, &frameCount, &audiobuf.list, NULL ); if(err != noErr) @@ -745,7 +745,7 @@ static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALC static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self) { - return ll_ringbuffer_read_space(self->ring) / self->sampleRateRatio; + return ll_ringbuffer_read_space(self->Ring) / self->SampleRateRatio; } diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 4f1186ee..3bce5cad 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -191,8 +191,8 @@ struct ALCdsoundPlayback final : public ALCbackend { IDirectSoundNotify *Notifies{nullptr}; HANDLE NotifyEvent{nullptr}; - std::atomic killNow{AL_TRUE}; - std::thread thread; + std::atomic mKillNow{AL_TRUE}; + std::thread mThread; }; int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self); @@ -271,7 +271,7 @@ FORCE_ALIGN int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) bool Playing{false}; DWORD LastCursor{0u}; Buffer->GetCurrentPosition(&LastCursor, nullptr); - while(!self->killNow.load(std::memory_order_acquire) && + while(!self->mKillNow.load(std::memory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { // Get current play cursor @@ -626,8 +626,8 @@ retry_open: ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self) { try { - self->killNow.store(AL_FALSE, std::memory_order_release); - self->thread = std::thread(ALCdsoundPlayback_mixerProc, self); + self->mKillNow.store(AL_FALSE, std::memory_order_release); + self->mThread = std::thread(ALCdsoundPlayback_mixerProc, self); return ALC_TRUE; } catch(std::exception& e) { @@ -640,10 +640,10 @@ ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self) void ALCdsoundPlayback_stop(ALCdsoundPlayback *self) { - if(self->killNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->thread.joinable()) + if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->mThread.joinable()) return; - self->thread.join(); + self->mThread.join(); self->Buffer->Stop(); } diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index 72a27c44..daa15219 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -151,7 +151,7 @@ struct ALCjackPlayback final : public ALCbackend { ll_ringbuffer_t *Ring{nullptr}; alsem_t Sem; - std::atomic killNow{AL_TRUE}; + std::atomic mKillNow{AL_TRUE}; althrd_t thread; }; @@ -300,7 +300,7 @@ static int ALCjackPlayback_mixerProc(void *arg) althrd_setname(MIXER_THREAD_NAME); ALCjackPlayback_lock(self); - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + while(!self->mKillNow.load(std::memory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { ALuint todo, len1, len2; @@ -465,7 +465,7 @@ static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self) } jack_free(ports); - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); + self->mKillNow.store(AL_FALSE, std::memory_order_release); if(althrd_create(&self->thread, ALCjackPlayback_mixerProc, self) != althrd_success) { jack_deactivate(self->Client); @@ -479,7 +479,7 @@ static void ALCjackPlayback_stop(ALCjackPlayback *self) { int res; - if(self->killNow.exchange(AL_TRUE, std::memory_order_acq_rel)) + if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel)) return; alsem_post(&self->Sem); diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 440da5e8..631c23d3 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -45,8 +45,8 @@ constexpr ALCchar nullDevice[] = "No Output"; struct ALCnullBackend final : public ALCbackend { - std::atomic killNow{AL_TRUE}; - std::thread thread; + std::atomic mKillNow{AL_TRUE}; + std::thread mThread; }; int ALCnullBackend_mixerProc(ALCnullBackend *self); @@ -91,7 +91,7 @@ int ALCnullBackend_mixerProc(ALCnullBackend *self) ALint64 done{0}; auto start = std::chrono::steady_clock::now(); - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + while(!self->mKillNow.load(std::memory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { auto now = std::chrono::steady_clock::now(); @@ -152,8 +152,8 @@ ALCboolean ALCnullBackend_reset(ALCnullBackend *self) ALCboolean ALCnullBackend_start(ALCnullBackend *self) { try { - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); - self->thread = std::thread(ALCnullBackend_mixerProc, self); + self->mKillNow.store(AL_FALSE, std::memory_order_release); + self->mThread = std::thread(ALCnullBackend_mixerProc, self); return ALC_TRUE; } catch(std::exception& e) { @@ -166,9 +166,9 @@ ALCboolean ALCnullBackend_start(ALCnullBackend *self) void ALCnullBackend_stop(ALCnullBackend *self) { - if(self->killNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->thread.joinable()) + if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->mThread.joinable()) return; - self->thread.join(); + self->mThread.join(); } } // namespace diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 7b8d234a..58a4dbad 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -243,10 +243,10 @@ int log2i(ALCuint x) struct ALCplaybackOSS final : public ALCbackend { int fd{-1}; - al::vector mix_data; + al::vector mMixData; - std::atomic killNow{AL_TRUE}; - std::thread thread; + std::atomic mKillNow{AL_TRUE}; + std::thread mThread; }; int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self); @@ -301,7 +301,7 @@ int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self) frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); ALCplaybackOSS_lock(self); - while(!self->killNow.load(std::memory_order_acquire) && + while(!self->mKillNow.load(std::memory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { FD_ZERO(&wfds); @@ -326,10 +326,10 @@ int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self) continue; } - write_ptr = self->mix_data.data(); - to_write = self->mix_data.size(); + write_ptr = self->mMixData.data(); + to_write = self->mMixData.size(); aluMixData(device, write_ptr, to_write/frame_size); - while(to_write > 0 && !self->killNow.load()) + while(to_write > 0 && !self->mKillNow.load()) { wrote = write(self->fd, write_ptr, to_write); if(wrote < 0) @@ -471,12 +471,12 @@ ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self) ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; try { - self->mix_data.resize(device->UpdateSize * FrameSizeFromDevFmt( + self->mMixData.resize(device->UpdateSize * FrameSizeFromDevFmt( device->FmtChans, device->FmtType, device->mAmbiOrder )); - self->killNow.store(AL_FALSE); - self->thread = std::thread(ALCplaybackOSS_mixerProc, self); + self->mKillNow.store(AL_FALSE); + self->mThread = std::thread(ALCplaybackOSS_mixerProc, self); return ALC_TRUE; } catch(std::exception& e) { @@ -489,24 +489,24 @@ ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self) void ALCplaybackOSS_stop(ALCplaybackOSS *self) { - if(self->killNow.exchange(AL_TRUE) || !self->thread.joinable()) + if(self->mKillNow.exchange(AL_TRUE) || !self->mThread.joinable()) return; - self->thread.join(); + self->mThread.join(); if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0) ERR("Error resetting device: %s\n", strerror(errno)); - self->mix_data.clear(); + self->mMixData.clear(); } struct ALCcaptureOSS final : public ALCbackend { int fd{-1}; - ll_ringbuffer_t *ring{nullptr}; + ll_ringbuffer_t *mRing{nullptr}; - std::atomic killNow{AL_TRUE}; - std::thread thread; + std::atomic mKillNow{AL_TRUE}; + std::thread mThread; }; int ALCcaptureOSS_recordProc(ALCcaptureOSS *self); @@ -539,8 +539,8 @@ void ALCcaptureOSS_Destruct(ALCcaptureOSS *self) close(self->fd); self->fd = -1; - ll_ringbuffer_free(self->ring); - self->ring = nullptr; + ll_ringbuffer_free(self->mRing); + self->mRing = nullptr; ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCcaptureOSS(); } @@ -560,7 +560,7 @@ int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); - while(!self->killNow.load()) + while(!self->mKillNow.load()) { FD_ZERO(&rfds); FD_SET(self->fd, &rfds); @@ -582,7 +582,7 @@ int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) continue; } - auto vec = ll_ringbuffer_get_write_vector(self->ring); + auto vec = ll_ringbuffer_get_write_vector(self->mRing); if(vec.first.len > 0) { amt = read(self->fd, vec.first.buf, vec.first.len*frame_size); @@ -594,7 +594,7 @@ int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) ALCcaptureOSS_unlock(self); break; } - ll_ringbuffer_write_advance(self->ring, amt/frame_size); + ll_ringbuffer_write_advance(self->mRing, amt/frame_size); } } @@ -700,8 +700,8 @@ ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) return ALC_INVALID_VALUE; } - self->ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, frameSize, false); - if(!self->ring) + self->mRing = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, frameSize, false); + if(!self->mRing) { ERR("Ring buffer create failed\n"); close(self->fd); @@ -716,8 +716,8 @@ ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self) { try { - self->killNow.store(AL_FALSE); - self->thread = std::thread(ALCcaptureOSS_recordProc, self); + self->mKillNow.store(AL_FALSE); + self->mThread = std::thread(ALCcaptureOSS_recordProc, self); return ALC_TRUE; } catch(std::exception& e) { @@ -730,10 +730,10 @@ ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self) void ALCcaptureOSS_stop(ALCcaptureOSS *self) { - if(self->killNow.exchange(AL_TRUE) || !self->thread.joinable()) + if(self->mKillNow.exchange(AL_TRUE) || !self->mThread.joinable()) return; - self->thread.join(); + self->mThread.join(); if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0) ERR("Error resetting device: %s\n", strerror(errno)); @@ -741,13 +741,13 @@ void ALCcaptureOSS_stop(ALCcaptureOSS *self) ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples) { - ll_ringbuffer_read(self->ring, static_cast(buffer), samples); + ll_ringbuffer_read(self->mRing, static_cast(buffer), samples); return ALC_NO_ERROR; } ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self) { - return ll_ringbuffer_read_space(self->ring); + return ll_ringbuffer_read_space(self->mRing); } } // namespace diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index 1c87f2c8..8b8c7fef 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -131,9 +131,9 @@ bool pa_load(void) struct ALCportPlayback final : public ALCbackend { - PaStream *stream; - PaStreamParameters params; - ALuint update_size; + PaStream *Stream{nullptr}; + PaStreamParameters Params; + ALuint UpdateSize{0u}; }; int ALCportPlayback_WriteCallback(const void *inputBuffer, void *outputBuffer, @@ -161,16 +161,14 @@ void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device) new (self) ALCportPlayback{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCportPlayback, ALCbackend, self); - - self->stream = nullptr; } void ALCportPlayback_Destruct(ALCportPlayback *self) { - PaError err = self->stream ? Pa_CloseStream(self->stream) : paNoError; + PaError err = self->Stream ? Pa_CloseStream(self->Stream) : paNoError; if(err != paNoError) ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); - self->stream = nullptr; + self->Stream = nullptr; ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCportPlayback(); @@ -200,51 +198,51 @@ ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name) else if(strcmp(name, pa_device) != 0) return ALC_INVALID_VALUE; - self->update_size = device->UpdateSize; + self->UpdateSize = device->UpdateSize; - self->params.device = -1; - if(!ConfigValueInt(nullptr, "port", "device", &self->params.device) || - self->params.device < 0) - self->params.device = Pa_GetDefaultOutputDevice(); - self->params.suggestedLatency = (device->UpdateSize*device->NumUpdates) / + self->Params.device = -1; + if(!ConfigValueInt(nullptr, "port", "device", &self->Params.device) || + self->Params.device < 0) + self->Params.device = Pa_GetDefaultOutputDevice(); + self->Params.suggestedLatency = (device->UpdateSize*device->NumUpdates) / (float)device->Frequency; - self->params.hostApiSpecificStreamInfo = nullptr; + self->Params.hostApiSpecificStreamInfo = nullptr; - self->params.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2); + self->Params.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2); switch(device->FmtType) { case DevFmtByte: - self->params.sampleFormat = paInt8; + self->Params.sampleFormat = paInt8; break; case DevFmtUByte: - self->params.sampleFormat = paUInt8; + self->Params.sampleFormat = paUInt8; break; case DevFmtUShort: /* fall-through */ case DevFmtShort: - self->params.sampleFormat = paInt16; + self->Params.sampleFormat = paInt16; break; case DevFmtUInt: /* fall-through */ case DevFmtInt: - self->params.sampleFormat = paInt32; + self->Params.sampleFormat = paInt32; break; case DevFmtFloat: - self->params.sampleFormat = paFloat32; + self->Params.sampleFormat = paFloat32; break; } retry_open: - err = Pa_OpenStream(&self->stream, nullptr, &self->params, + err = Pa_OpenStream(&self->Stream, nullptr, &self->Params, device->Frequency, device->UpdateSize, paNoFlag, ALCportPlayback_WriteCallback, self ); if(err != paNoError) { - if(self->params.sampleFormat == paFloat32) + if(self->Params.sampleFormat == paFloat32) { - self->params.sampleFormat = paInt16; + self->Params.sampleFormat = paInt16; goto retry_open; } ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); @@ -261,33 +259,33 @@ ALCboolean ALCportPlayback_reset(ALCportPlayback *self) ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; const PaStreamInfo *streamInfo; - streamInfo = Pa_GetStreamInfo(self->stream); + streamInfo = Pa_GetStreamInfo(self->Stream); device->Frequency = streamInfo->sampleRate; - device->UpdateSize = self->update_size; + device->UpdateSize = self->UpdateSize; - if(self->params.sampleFormat == paInt8) + if(self->Params.sampleFormat == paInt8) device->FmtType = DevFmtByte; - else if(self->params.sampleFormat == paUInt8) + else if(self->Params.sampleFormat == paUInt8) device->FmtType = DevFmtUByte; - else if(self->params.sampleFormat == paInt16) + else if(self->Params.sampleFormat == paInt16) device->FmtType = DevFmtShort; - else if(self->params.sampleFormat == paInt32) + else if(self->Params.sampleFormat == paInt32) device->FmtType = DevFmtInt; - else if(self->params.sampleFormat == paFloat32) + else if(self->Params.sampleFormat == paFloat32) device->FmtType = DevFmtFloat; else { - ERR("Unexpected sample format: 0x%lx\n", self->params.sampleFormat); + ERR("Unexpected sample format: 0x%lx\n", self->Params.sampleFormat); return ALC_FALSE; } - if(self->params.channelCount == 2) + if(self->Params.channelCount == 2) device->FmtChans = DevFmtStereo; - else if(self->params.channelCount == 1) + else if(self->Params.channelCount == 1) device->FmtChans = DevFmtMono; else { - ERR("Unexpected channel count: %u\n", self->params.channelCount); + ERR("Unexpected channel count: %u\n", self->Params.channelCount); return ALC_FALSE; } SetDefaultChannelOrder(device); @@ -299,7 +297,7 @@ ALCboolean ALCportPlayback_start(ALCportPlayback *self) { PaError err; - err = Pa_StartStream(self->stream); + err = Pa_StartStream(self->Stream); if(err != paNoError) { ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err)); @@ -311,17 +309,17 @@ ALCboolean ALCportPlayback_start(ALCportPlayback *self) void ALCportPlayback_stop(ALCportPlayback *self) { - PaError err = Pa_StopStream(self->stream); + PaError err = Pa_StopStream(self->Stream); if(err != paNoError) ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); } struct ALCportCapture final : public ALCbackend { - PaStream *stream; - PaStreamParameters params; + PaStream *Stream{nullptr}; + PaStreamParameters Params; - ll_ringbuffer_t *ring; + ll_ringbuffer_t *Ring{nullptr}; }; int ALCportCapture_ReadCallback(const void *inputBuffer, void *outputBuffer, @@ -349,20 +347,17 @@ void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device) new (self) ALCportCapture{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCportCapture, ALCbackend, self); - - self->stream = nullptr; - self->ring = nullptr; } void ALCportCapture_Destruct(ALCportCapture *self) { - PaError err = self->stream ? Pa_CloseStream(self->stream) : paNoError; + PaError err = self->Stream ? Pa_CloseStream(self->Stream) : paNoError; if(err != paNoError) ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); - self->stream = nullptr; + self->Stream = nullptr; - ll_ringbuffer_free(self->ring); - self->ring = nullptr; + ll_ringbuffer_free(self->Ring); + self->Ring = nullptr; ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCportCapture(); @@ -374,10 +369,10 @@ int ALCportCapture_ReadCallback(const void *inputBuffer, void *UNUSED(outputBuff const PaStreamCallbackFlags UNUSED(statusFlags), void *userData) { ALCportCapture *self = static_cast(userData); - size_t writable = ll_ringbuffer_write_space(self->ring); + size_t writable = ll_ringbuffer_write_space(self->Ring); if(framesPerBuffer > writable) framesPerBuffer = writable; - ll_ringbuffer_write(self->ring, inputBuffer, framesPerBuffer); + ll_ringbuffer_write(self->Ring, inputBuffer, framesPerBuffer); return 0; } @@ -397,41 +392,41 @@ ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) samples = maxu(samples, 100 * device->Frequency / 1000); frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); - self->ring = ll_ringbuffer_create(samples, frame_size, false); - if(self->ring == nullptr) return ALC_INVALID_VALUE; + self->Ring = ll_ringbuffer_create(samples, frame_size, false); + if(self->Ring == nullptr) return ALC_INVALID_VALUE; - self->params.device = -1; - if(!ConfigValueInt(nullptr, "port", "capture", &self->params.device) || - self->params.device < 0) - self->params.device = Pa_GetDefaultInputDevice(); - self->params.suggestedLatency = 0.0f; - self->params.hostApiSpecificStreamInfo = nullptr; + self->Params.device = -1; + if(!ConfigValueInt(nullptr, "port", "capture", &self->Params.device) || + self->Params.device < 0) + self->Params.device = Pa_GetDefaultInputDevice(); + self->Params.suggestedLatency = 0.0f; + self->Params.hostApiSpecificStreamInfo = nullptr; switch(device->FmtType) { case DevFmtByte: - self->params.sampleFormat = paInt8; + self->Params.sampleFormat = paInt8; break; case DevFmtUByte: - self->params.sampleFormat = paUInt8; + self->Params.sampleFormat = paUInt8; break; case DevFmtShort: - self->params.sampleFormat = paInt16; + self->Params.sampleFormat = paInt16; break; case DevFmtInt: - self->params.sampleFormat = paInt32; + self->Params.sampleFormat = paInt32; break; case DevFmtFloat: - self->params.sampleFormat = paFloat32; + self->Params.sampleFormat = paFloat32; break; case DevFmtUInt: case DevFmtUShort: ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); return ALC_INVALID_VALUE; } - self->params.channelCount = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); + self->Params.channelCount = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); - err = Pa_OpenStream(&self->stream, &self->params, nullptr, + err = Pa_OpenStream(&self->Stream, &self->Params, nullptr, device->Frequency, paFramesPerBufferUnspecified, paNoFlag, ALCportCapture_ReadCallback, self ); @@ -448,7 +443,7 @@ ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) ALCboolean ALCportCapture_start(ALCportCapture *self) { - PaError err = Pa_StartStream(self->stream); + PaError err = Pa_StartStream(self->Stream); if(err != paNoError) { ERR("Error starting stream: %s\n", Pa_GetErrorText(err)); @@ -459,7 +454,7 @@ ALCboolean ALCportCapture_start(ALCportCapture *self) void ALCportCapture_stop(ALCportCapture *self) { - PaError err = Pa_StopStream(self->stream); + PaError err = Pa_StopStream(self->Stream); if(err != paNoError) ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); } @@ -467,12 +462,12 @@ void ALCportCapture_stop(ALCportCapture *self) ALCuint ALCportCapture_availableSamples(ALCportCapture *self) { - return ll_ringbuffer_read_space(self->ring); + return ll_ringbuffer_read_space(self->Ring); } ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples) { - ll_ringbuffer_read(self->ring, buffer, samples); + ll_ringbuffer_read(self->Ring, buffer, samples); return ALC_NO_ERROR; } diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index c64c3ed7..560656c5 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -534,8 +534,8 @@ struct PulsePlayback final : public ALCbackend { pa_stream *stream{nullptr}; pa_context *context{nullptr}; - std::atomic killNow{ALC_TRUE}; - std::thread thread; + std::atomic mKillNow{ALC_TRUE}; + std::thread mThread; }; void PulsePlayback_deviceCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); @@ -870,7 +870,7 @@ int PulsePlayback_mixerProc(PulsePlayback *self) unique_palock palock{self->loop}; size_t frame_size{pa_frame_size(&self->spec)}; - while(!self->killNow.load(std::memory_order_acquire) && + while(!self->mKillNow.load(std::memory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { ssize_t len{static_cast(pa_stream_writable_size(self->stream))}; @@ -1152,8 +1152,8 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) ALCboolean PulsePlayback_start(PulsePlayback *self) { try { - self->killNow.store(AL_FALSE, std::memory_order_release); - self->thread = std::thread(PulsePlayback_mixerProc, self); + self->mKillNow.store(AL_FALSE, std::memory_order_release); + self->mThread = std::thread(PulsePlayback_mixerProc, self); return ALC_TRUE; } catch(std::exception& e) { @@ -1167,20 +1167,20 @@ ALCboolean PulsePlayback_start(PulsePlayback *self) void PulsePlayback_stop(PulsePlayback *self) { - self->killNow.store(AL_TRUE, std::memory_order_release); - if(!self->stream || !self->thread.joinable()) + self->mKillNow.store(AL_TRUE, std::memory_order_release); + if(!self->stream || !self->mThread.joinable()) return; /* Signal the main loop in case PulseAudio isn't sending us audio requests * (e.g. if the device is suspended). We need to lock the mainloop in case - * the mixer is between checking the killNow flag but before waiting for + * the mixer is between checking the mKillNow flag but before waiting for * the signal. */ unique_palock palock{self->loop}; palock.unlock(); pa_threaded_mainloop_signal(self->loop, 0); - self->thread.join(); + self->mThread.join(); palock.lock(); diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index 66f3e601..3fa72472 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -51,7 +51,7 @@ struct qsa_data { ALvoid* buffer; ALsizei size; - std::atomic killNow; + std::atomic mKillNow; althrd_t thread; }; @@ -213,7 +213,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) ); PlaybackWrapper_lock(self); - while(!ATOMIC_LOAD(&data->killNow, almemory_order_acquire)) + while(!data->mKillNow.load(std::memory_order_acquire)) { FD_ZERO(&wfds); FD_SET(data->audio_fd, &wfds); @@ -239,7 +239,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) len = data->size; write_ptr = static_cast(data->buffer); aluMixData(device, write_ptr, len/frame_size); - while(len>0 && !ATOMIC_LOAD(&data->killNow, almemory_order_acquire)) + while(len>0 && !data->mKillNow.load(std::memory_order_acquire)) { int wrote = snd_pcm_plugin_write(data->pcmHandle, write_ptr, len); if(wrote <= 0) @@ -289,7 +289,7 @@ static ALCenum qsa_open_playback(PlaybackWrapper *self, const ALCchar* deviceNam data = (qsa_data*)calloc(1, sizeof(qsa_data)); if(data == NULL) return ALC_OUT_OF_MEMORY; - data->killNow.store(AL_TRUE, std::memory_order_relaxed); + data->mKillNow.store(AL_TRUE, std::memory_order_relaxed); if(!deviceName) deviceName = qsaDevice; @@ -602,7 +602,7 @@ static ALCboolean qsa_start_playback(PlaybackWrapper *self) { qsa_data *data = self->ExtraData; - ATOMIC_STORE(&data->killNow, AL_FALSE, almemory_order_release); + data->mKillNow.store(AL_FALSE, std::memory_order_release); if(althrd_create(&data->thread, qsa_proc_playback, self) != althrd_success) return ALC_FALSE; @@ -614,7 +614,7 @@ static void qsa_stop_playback(PlaybackWrapper *self) qsa_data *data = self->ExtraData; int res; - if(data->killNow.exchange(AL_TRUE, std::memory_order_acq_rel)) + if(data->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel)) return; althrd_join(data->thread, &res); } diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index 5e7b48af..d7340f4a 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -43,7 +43,7 @@ struct SndioPlayback final : public ALCbackend { ALvoid *mix_data{nullptr}; ALsizei data_size{0}; - std::atomic killNow{AL_TRUE}; + std::atomic mKillNow{AL_TRUE}; althrd_t thread; }; @@ -98,7 +98,7 @@ static int SndioPlayback_mixerProc(void *ptr) frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + while(!self->mKillNow.load(std::memory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { ALsizei len = self->data_size; @@ -107,7 +107,7 @@ static int SndioPlayback_mixerProc(void *ptr) SndioPlayback_lock(self); aluMixData(device, WritePtr, len/frameSize); SndioPlayback_unlock(self); - while(len > 0 && !ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) + while(len > 0 && !self->mKillNow.load(std::memory_order_acquire)) { wrote = sio_write(self->sndHandle, WritePtr, len); if(wrote == 0) @@ -249,7 +249,7 @@ static ALCboolean SndioPlayback_start(SndioPlayback *self) return ALC_FALSE; } - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); + self->mKillNow.store(AL_FALSE, std::memory_order_release); if(althrd_create(&self->thread, SndioPlayback_mixerProc, self) != althrd_success) { sio_stop(self->sndHandle); @@ -263,7 +263,7 @@ static void SndioPlayback_stop(SndioPlayback *self) { int res; - if(self->killNow.exchange(AL_TRUE, std::memory_order_acq_rel)) + if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel)) return; althrd_join(self->thread, &res); @@ -280,7 +280,7 @@ struct SndioCapture final : public ALCbackend { ll_ringbuffer_t *ring{nullptr}; - std::atomic killNow{AL_TRUE}; + std::atomic mKillNow{AL_TRUE}; althrd_t thread; }; @@ -334,7 +334,7 @@ static int SndioCapture_recordProc(void* ptr) frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + while(!self->mKillNow.load(std::memory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { size_t total, todo; @@ -490,7 +490,7 @@ static ALCboolean SndioCapture_start(SndioCapture *self) return ALC_FALSE; } - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); + self->mKillNow.store(AL_FALSE, std::memory_order_release); if(althrd_create(&self->thread, SndioCapture_recordProc, self) != althrd_success) { sio_stop(self->sndHandle); @@ -504,7 +504,7 @@ static void SndioCapture_stop(SndioCapture *self) { int res; - if(self->killNow.exchange(AL_TRUE, std::memory_order_acq_rel)) + if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel)) return; althrd_join(self->thread, &res); diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index 2d26fb6a..cd3f615f 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -49,7 +49,7 @@ struct ALCsolarisBackend final : public ALCbackend { ALubyte *mix_data{nullptr}; int data_size{0}; - std::atomic killNow{AL_TRUE}; + std::atomic mKillNow{AL_TRUE}; althrd_t thread; }; @@ -116,7 +116,7 @@ static int ALCsolarisBackend_mixerProc(void *ptr) frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); ALCsolarisBackend_lock(self); - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + while(!self->mKillNow.load(std::memory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { FD_ZERO(&wfds); @@ -144,7 +144,7 @@ static int ALCsolarisBackend_mixerProc(void *ptr) write_ptr = self->mix_data; to_write = self->data_size; aluMixData(device, write_ptr, to_write/frame_size); - while(to_write > 0 && !ATOMIC_LOAD_SEQ(&self->killNow)) + while(to_write > 0 && !self->mKillNow.load()) { wrote = write(self->fd, write_ptr, to_write); if(wrote < 0) @@ -268,7 +268,7 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self) { - ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE); + self->mKillNow.store(AL_FALSE); if(althrd_create(&self->thread, ALCsolarisBackend_mixerProc, self) != althrd_success) return ALC_FALSE; return ALC_TRUE; @@ -278,7 +278,7 @@ static void ALCsolarisBackend_stop(ALCsolarisBackend *self) { int res; - if(self->killNow.exchange(AL_TRUE)) + if(self->mKillNow.exchange(AL_TRUE)) return; althrd_join(self->thread, &res); diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index ec5e787b..2475aa9f 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -84,8 +84,8 @@ struct ALCwaveBackend final : public ALCbackend { al::vector mBuffer; - std::atomic killNow{AL_TRUE}; - std::thread thread; + std::atomic mKillNow{AL_TRUE}; + std::thread mThread; }; int ALCwaveBackend_mixerProc(ALCwaveBackend *self); @@ -134,7 +134,7 @@ int ALCwaveBackend_mixerProc(ALCwaveBackend *self) ALint64 done{0}; auto start = std::chrono::steady_clock::now(); - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + while(!self->mKillNow.load(std::memory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { auto now = std::chrono::steady_clock::now(); @@ -348,8 +348,8 @@ ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) ALCboolean ALCwaveBackend_start(ALCwaveBackend *self) { try { - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); - self->thread = std::thread(ALCwaveBackend_mixerProc, self); + self->mKillNow.store(AL_FALSE, std::memory_order_release); + self->mThread = std::thread(ALCwaveBackend_mixerProc, self); return ALC_TRUE; } catch(std::exception& e) { @@ -362,9 +362,9 @@ ALCboolean ALCwaveBackend_start(ALCwaveBackend *self) void ALCwaveBackend_stop(ALCwaveBackend *self) { - if(self->killNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->thread.joinable()) + if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->mThread.joinable()) return; - self->thread.join(); + self->mThread.join(); long size{ftell(self->mFile)}; if(size > 0) diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index f1aee5b3..b4651b4c 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -130,8 +130,8 @@ struct ALCwinmmPlayback final : public ALCbackend { WAVEFORMATEX Format{}; - std::atomic killNow{AL_TRUE}; - std::thread thread; + std::atomic mKillNow{AL_TRUE}; + std::thread mThread; }; void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device); @@ -205,7 +205,7 @@ FORCE_ALIGN int ALCwinmmPlayback_mixerProc(ALCwinmmPlayback *self) althrd_setname(MIXER_THREAD_NAME); ALCwinmmPlayback_lock(self); - while(!self->killNow.load(std::memory_order_acquire) && + while(!self->mKillNow.load(std::memory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { ALsizei todo = self->Writable.load(std::memory_order_acquire); @@ -368,8 +368,8 @@ ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self) ); self->Writable.store(self->WaveBuffer.size(), std::memory_order_release); - self->killNow.store(AL_FALSE, std::memory_order_release); - self->thread = std::thread(ALCwinmmPlayback_mixerProc, self); + self->mKillNow.store(AL_FALSE, std::memory_order_release); + self->mThread = std::thread(ALCwinmmPlayback_mixerProc, self); return ALC_TRUE; } catch(std::exception& e) { @@ -382,9 +382,9 @@ ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self) void ALCwinmmPlayback_stop(ALCwinmmPlayback *self) { - if(self->killNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->thread.joinable()) + if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->mThread.joinable()) return; - self->thread.join(); + self->mThread.join(); while(self->Writable.load(std::memory_order_acquire) < self->WaveBuffer.size()) alsem_wait(&self->Sem); @@ -408,8 +408,8 @@ struct ALCwinmmCapture final : public ALCbackend { WAVEFORMATEX Format{}; - std::atomic killNow{AL_TRUE}; - std::thread thread; + std::atomic mKillNow{AL_TRUE}; + std::thread mThread; }; void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device); @@ -486,7 +486,7 @@ int ALCwinmmCapture_captureProc(ALCwinmmCapture *self) althrd_setname(RECORD_THREAD_NAME); ALCwinmmCapture_lock(self); - while(!self->killNow.load(std::memory_order_acquire) && + while(!self->mKillNow.load(std::memory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { ALsizei todo = self->Readable.load(std::memory_order_acquire); @@ -618,8 +618,8 @@ ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self) waveInAddBuffer(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); } - self->killNow.store(AL_FALSE, std::memory_order_release); - self->thread = std::thread(ALCwinmmCapture_captureProc, self); + self->mKillNow.store(AL_FALSE, std::memory_order_release); + self->mThread = std::thread(ALCwinmmCapture_captureProc, self); waveInStart(self->InHdl); return ALC_TRUE; @@ -636,11 +636,11 @@ void ALCwinmmCapture_stop(ALCwinmmCapture *self) { waveInStop(self->InHdl); - self->killNow.store(AL_TRUE, std::memory_order_release); - if(self->thread.joinable()) + self->mKillNow.store(AL_TRUE, std::memory_order_release); + if(self->mThread.joinable()) { alsem_post(&self->Sem); - self->thread.join(); + self->mThread.join(); } waveInReset(self->InHdl); -- cgit v1.2.3 From 1a9edd4e35ff15bef8662313a9982f62732f5055 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 17:53:56 -0800 Subject: Use a unique_ptr for the QSA backend data --- Alc/backends/qsa.cpp | 81 ++++++++++++++++++---------------------------------- 1 file changed, 28 insertions(+), 53 deletions(-) diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index 3fa72472..b40b5b6b 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include "alMain.h" @@ -42,16 +43,16 @@ namespace { struct qsa_data { - snd_pcm_t* pcmHandle; - int audio_fd; + snd_pcm_t* pcmHandle{nullptr}; + int audio_fd{-1}; - snd_pcm_channel_setup_t csetup; - snd_pcm_channel_params_t cparams; + snd_pcm_channel_setup_t csetup{}; + snd_pcm_channel_params_t cparams{}; - ALvoid* buffer; - ALsizei size; + ALvoid* buffer{nullptr}; + ALsizei size{0}; - std::atomic mKillNow; + std::atomic mKillNow{AL_TRUE}; althrd_t thread; }; @@ -169,7 +170,7 @@ void deviceList(int type, al::vector *devmap) /* Wrappers to use an old-style backend with the new interface. */ struct PlaybackWrapper final : public ALCbackend { - qsa_data *ExtraData; + std::unique_ptr ExtraData; }; static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device); @@ -282,13 +283,10 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) static ALCenum qsa_open_playback(PlaybackWrapper *self, const ALCchar* deviceName) { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - qsa_data *data; int card, dev; int status; - data = (qsa_data*)calloc(1, sizeof(qsa_data)); - if(data == NULL) - return ALC_OUT_OF_MEMORY; + std::unique_ptr data{new qsa_data{}}; data->mKillNow.store(AL_TRUE, std::memory_order_relaxed); if(!deviceName) @@ -306,37 +304,30 @@ static ALCenum qsa_open_playback(PlaybackWrapper *self, const ALCchar* deviceNam { return entry.name && strcmp(deviceName, entry.name) == 0; } ); if(iter == DeviceNameMap.cend()) - { - free(data); return ALC_INVALID_DEVICE; - } status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_PLAYBACK); } if(status < 0) - { - free(data); return ALC_INVALID_DEVICE; - } data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK); if(data->audio_fd < 0) { snd_pcm_close(data->pcmHandle); - free(data); return ALC_INVALID_DEVICE; } device->DeviceName = deviceName; - self->ExtraData = data; + self->ExtraData = std::move(data); return ALC_NO_ERROR; } static void qsa_close_playback(PlaybackWrapper *self) { - qsa_data *data = self->ExtraData; + qsa_data *data = self->ExtraData.get(); if (data->buffer!=NULL) { @@ -345,15 +336,14 @@ static void qsa_close_playback(PlaybackWrapper *self) } snd_pcm_close(data->pcmHandle); - free(data); - self->ExtraData = NULL; + self->ExtraData = nullptr; } static ALCboolean qsa_reset_playback(PlaybackWrapper *self) { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - qsa_data *data = self->ExtraData; + qsa_data *data = self->ExtraData.get(); int32_t format=-1; switch(device->FmtType) @@ -600,7 +590,7 @@ static ALCboolean qsa_reset_playback(PlaybackWrapper *self) static ALCboolean qsa_start_playback(PlaybackWrapper *self) { - qsa_data *data = self->ExtraData; + qsa_data *data = self->ExtraData.get(); data->mKillNow.store(AL_FALSE, std::memory_order_release); if(althrd_create(&data->thread, qsa_proc_playback, self) != althrd_success) @@ -611,7 +601,7 @@ static ALCboolean qsa_start_playback(PlaybackWrapper *self) static void qsa_stop_playback(PlaybackWrapper *self) { - qsa_data *data = self->ExtraData; + qsa_data *data = self->ExtraData.get(); int res; if(data->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel)) @@ -665,7 +655,7 @@ static void PlaybackWrapper_stop(PlaybackWrapper *self) /***********/ struct CaptureWrapper final : public ALCbackend { - qsa_data *ExtraData; + std::unique_ptr ExtraData; }; static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device); @@ -686,16 +676,11 @@ DEFINE_ALCBACKEND_VTABLE(CaptureWrapper); static ALCenum qsa_open_capture(CaptureWrapper *self, const ALCchar *deviceName) { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - qsa_data *data; int card, dev; int format=-1; int status; - data=(qsa_data*)calloc(1, sizeof(qsa_data)); - if (data==NULL) - { - return ALC_OUT_OF_MEMORY; - } + std::unique_ptr data{new qsa_data{}}; if(!deviceName) deviceName = qsaDevice; @@ -712,30 +697,22 @@ static ALCenum qsa_open_capture(CaptureWrapper *self, const ALCchar *deviceName) { return entry.name && strcmp(deviceName, entry.name) == 0; } ); if(iter == CaptureNameMap.cend()) - { - free(data); return ALC_INVALID_DEVICE; - } status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_CAPTURE); } if(status < 0) - { - free(data); return ALC_INVALID_DEVICE; - } data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE); if(data->audio_fd < 0) { snd_pcm_close(data->pcmHandle); - free(data); return ALC_INVALID_DEVICE; } device->DeviceName = deviceName; - self->ExtraData = data; switch (device->FmtType) { @@ -787,28 +764,28 @@ static ALCenum qsa_open_capture(CaptureWrapper *self, const ALCchar *deviceName) if(snd_pcm_plugin_params(data->pcmHandle, &data->cparams) < 0) { snd_pcm_close(data->pcmHandle); - free(data); - return ALC_INVALID_VALUE; } + self->ExtraData = std::move(data); + return ALC_NO_ERROR; } static void qsa_close_capture(CaptureWrapper *self) { - qsa_data *data = self->ExtraData; + qsa_data *data = self->ExtraData.get(); - if (data->pcmHandle!=NULL) + if (data->pcmHandle!=nullptr) snd_pcm_close(data->pcmHandle); + data->pcmHandle = nullptr - free(data); - self->ExtraData = NULL; + self->ExtraData = nullptr; } static void qsa_start_capture(CaptureWrapper *self) { - qsa_data *data = self->ExtraData; + qsa_data *data = self->ExtraData.get(); int rstatus; if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0) @@ -830,14 +807,14 @@ static void qsa_start_capture(CaptureWrapper *self) static void qsa_stop_capture(CaptureWrapper *self) { - qsa_data *data = self->ExtraData; + qsa_data *data = self->ExtraData.get(); snd_pcm_capture_flush(data->pcmHandle); } static ALCuint qsa_available_samples(CaptureWrapper *self) { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - qsa_data *data = self->ExtraData; + qsa_data *data = self->ExtraData.get(); snd_pcm_channel_status_t status; ALint frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); ALint free_size; @@ -869,7 +846,7 @@ static ALCuint qsa_available_samples(CaptureWrapper *self) static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuint samples) { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - qsa_data *data = self->ExtraData; + qsa_data *data = self->ExtraData.get(); char* read_ptr; snd_pcm_channel_status_t status; fd_set rfds; @@ -949,8 +926,6 @@ static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device) new (self) CaptureWrapper{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(CaptureWrapper, ALCbackend, self); - - self->ExtraData = NULL; } static void CaptureWrapper_Destruct(CaptureWrapper *self) -- cgit v1.2.3 From 461ef4196ed78a2803325fbda45a035ed5e6cf71 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 18:07:52 -0800 Subject: Avoid using ATOMIC_LOAD on ALCdevice::Connected --- Alc/backends/alsa.cpp | 4 ++-- Alc/backends/dsound.cpp | 4 ++-- Alc/backends/jack.cpp | 2 +- Alc/backends/null.cpp | 2 +- Alc/backends/opensl.cpp | 5 ++--- Alc/backends/oss.cpp | 2 +- Alc/backends/pulseaudio.cpp | 4 ++-- Alc/backends/sndio.cpp | 4 ++-- Alc/backends/solaris.cpp | 2 +- Alc/backends/wave.cpp | 2 +- Alc/backends/winmm.cpp | 4 ++-- 11 files changed, 17 insertions(+), 18 deletions(-) diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index 20ffc559..629038b8 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -1150,7 +1150,7 @@ ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALC } self->mLastAvail -= samples; - while(ATOMIC_LOAD(&device->Connected, almemory_order_acquire) && samples > 0) + while(device->Connected.load(std::memory_order_acquire) && samples > 0) { snd_pcm_sframes_t amt{0}; @@ -1208,7 +1208,7 @@ ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; snd_pcm_sframes_t avail{0}; - if(ATOMIC_LOAD(&device->Connected, almemory_order_acquire) && self->DoCapture) + if(device->Connected.load(std::memory_order_acquire) && self->DoCapture) avail = snd_pcm_avail_update(self->PcmHandle); if(avail < 0) { diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 3bce5cad..2bb6048a 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -272,7 +272,7 @@ FORCE_ALIGN int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) DWORD LastCursor{0u}; Buffer->GetCurrentPosition(&LastCursor, nullptr); while(!self->mKillNow.load(std::memory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + device->Connected.load(std::memory_order_acquire)) { // Get current play cursor DWORD PlayCursor; @@ -901,7 +901,7 @@ ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + if(!device->Connected.load(std::memory_order_acquire)) return ll_ringbuffer_read_space(self->Ring); ALsizei FrameSize{FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder)}; diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index daa15219..fc385f7b 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -301,7 +301,7 @@ static int ALCjackPlayback_mixerProc(void *arg) ALCjackPlayback_lock(self); while(!self->mKillNow.load(std::memory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + device->Connected.load(std::memory_order_acquire)) { ALuint todo, len1, len2; diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 631c23d3..969193b8 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -92,7 +92,7 @@ int ALCnullBackend_mixerProc(ALCnullBackend *self) ALint64 done{0}; auto start = std::chrono::steady_clock::now(); while(!self->mKillNow.load(std::memory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + device->Connected.load(std::memory_order_acquire)) { auto now = std::chrono::steady_clock::now(); diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 2a87e19b..d59ef5f3 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -248,9 +248,8 @@ static int ALCopenslPlayback_mixerProc(void *arg) if(SL_RESULT_SUCCESS != result) aluHandleDisconnect(device, "Failed to get playback buffer: 0x%08x", result); - while(SL_RESULT_SUCCESS == result && - !ATOMIC_LOAD(&self->mKillNow, almemory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + while(SL_RESULT_SUCCESS == result && !self->mKillNow.load(std::memory_order_acquire) && + device->Connected.load(std::memory_order_acquire)) { size_t todo; diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 58a4dbad..5e8100fb 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -302,7 +302,7 @@ int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self) ALCplaybackOSS_lock(self); while(!self->mKillNow.load(std::memory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + device->Connected.load(std::memory_order_acquire)) { FD_ZERO(&wfds); FD_SET(self->fd, &wfds); diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 560656c5..51b7c0a9 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -871,7 +871,7 @@ int PulsePlayback_mixerProc(PulsePlayback *self) size_t frame_size{pa_frame_size(&self->spec)}; while(!self->mKillNow.load(std::memory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + device->Connected.load(std::memory_order_acquire)) { ssize_t len{static_cast(pa_stream_writable_size(self->stream))}; if(UNLIKELY(len < 0)) @@ -1676,7 +1676,7 @@ ALCuint PulseCapture_availableSamples(PulseCapture *self) ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; size_t readable{self->cap_remain}; - if(ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + if(device->Connected.load(std::memory_order_acquire)) { palock_guard _{self->loop}; size_t got{pa_stream_readable_size(self->stream)}; diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index d7340f4a..2a999bd4 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -99,7 +99,7 @@ static int SndioPlayback_mixerProc(void *ptr) frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); while(!self->mKillNow.load(std::memory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + device->Connected.load(std::memory_order_acquire)) { ALsizei len = self->data_size; ALubyte *WritePtr = static_cast(self->mix_data); @@ -335,7 +335,7 @@ static int SndioCapture_recordProc(void* ptr) frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); while(!self->mKillNow.load(std::memory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + device->Connected.load(std::memory_order_acquire)) { size_t total, todo; diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index cd3f615f..0ca7a4ec 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -117,7 +117,7 @@ static int ALCsolarisBackend_mixerProc(void *ptr) ALCsolarisBackend_lock(self); while(!self->mKillNow.load(std::memory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + device->Connected.load(std::memory_order_acquire)) { FD_ZERO(&wfds); FD_SET(self->fd, &wfds); diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index 2475aa9f..25245a1b 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -135,7 +135,7 @@ int ALCwaveBackend_mixerProc(ALCwaveBackend *self) ALint64 done{0}; auto start = std::chrono::steady_clock::now(); while(!self->mKillNow.load(std::memory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + device->Connected.load(std::memory_order_acquire)) { auto now = std::chrono::steady_clock::now(); diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index b4651b4c..2524ecc1 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -206,7 +206,7 @@ FORCE_ALIGN int ALCwinmmPlayback_mixerProc(ALCwinmmPlayback *self) ALCwinmmPlayback_lock(self); while(!self->mKillNow.load(std::memory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + device->Connected.load(std::memory_order_acquire)) { ALsizei todo = self->Writable.load(std::memory_order_acquire); if(todo < 1) @@ -487,7 +487,7 @@ int ALCwinmmCapture_captureProc(ALCwinmmCapture *self) ALCwinmmCapture_lock(self); while(!self->mKillNow.load(std::memory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + device->Connected.load(std::memory_order_acquire)) { ALsizei todo = self->Readable.load(std::memory_order_acquire); if(todo < 1) -- cgit v1.2.3 From df3dcc879f6c037efcb1285f08d70c76cd570bee Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 18:19:58 -0800 Subject: Get rid of the last ATOMIC macro uses --- Alc/backends/opensl.cpp | 2 +- Alc/mixvoice.cpp | 2 +- OpenAL32/alAuxEffectSlot.cpp | 2 +- OpenAL32/alBuffer.cpp | 12 ++++++------ OpenAL32/alState.cpp | 2 +- OpenAL32/event.cpp | 2 +- common/atomic.h | 15 --------------- 7 files changed, 11 insertions(+), 26 deletions(-) diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index d59ef5f3..9e8e5031 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -580,7 +580,7 @@ static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self) if(SL_RESULT_SUCCESS != result) return ALC_FALSE; - ATOMIC_STORE_SEQ(&self->mKillNow, AL_FALSE); + self->mKillNow.store(AL_FALSE); if(althrd_create(&self->mThread, ALCopenslPlayback_mixerProc, self) != althrd_success) { ERR("Failed to start mixer thread\n"); diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 5a1a1d4d..86de61ee 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -706,7 +706,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize DataPosInt -= BufferListItem->max_samples; buffers_done += BufferListItem->num_buffers; - BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_relaxed); + BufferListItem = BufferListItem->next.load(std::memory_order_relaxed); if(!BufferListItem && !(BufferListItem=BufferLoopItem)) { isplaying = false; diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index e7991ff0..cf39292b 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -552,7 +552,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect if(props->State) props->State->DecRef(); props->State = nullptr; - props = ATOMIC_LOAD(&props->next, almemory_order_relaxed); + props = props->next.load(std::memory_order_relaxed); } return AL_NO_ERROR; diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index 3716ac28..1b50f075 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -235,7 +235,7 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U NameFromUserFmtType(SrcType)); } - ALsizei unpackalign{ATOMIC_LOAD_SEQ(&ALBuf->UnpackAlign)}; + ALsizei unpackalign{ALBuf->UnpackAlign.load()}; ALsizei align{SanitizeAlignment(SrcType, unpackalign)}; if(UNLIKELY(align < 1)) SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid unpack alignment %d for %s samples", @@ -682,7 +682,7 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons return; } - ALsizei unpack_align{ATOMIC_LOAD_SEQ(&albuf->UnpackAlign)}; + ALsizei unpack_align{albuf->UnpackAlign.load()}; ALsizei align{SanitizeAlignment(srctype, unpack_align)}; if(UNLIKELY(align < 1)) alSetError(context.get(), AL_INVALID_VALUE, "Invalid unpack alignment %d", unpack_align); @@ -854,14 +854,14 @@ AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) if(UNLIKELY(value < 0)) alSetError(context.get(), AL_INVALID_VALUE, "Invalid unpack block alignment %d", value); else - ATOMIC_STORE_SEQ(&albuf->UnpackAlign, value); + albuf->UnpackAlign.store(value); break; case AL_PACK_BLOCK_ALIGNMENT_SOFT: if(UNLIKELY(value < 0)) alSetError(context.get(), AL_INVALID_VALUE, "Invalid pack block alignment %d", value); else - ATOMIC_STORE_SEQ(&albuf->PackAlign, value); + albuf->PackAlign.store(value); break; default: @@ -1036,11 +1036,11 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value break; case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: - *value = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign); + *value = albuf->UnpackAlign.load(); break; case AL_PACK_BLOCK_ALIGNMENT_SOFT: - *value = ATOMIC_LOAD_SEQ(&albuf->PackAlign); + *value = albuf->PackAlign.load(); break; default: diff --git a/OpenAL32/alState.cpp b/OpenAL32/alState.cpp index 95a4fd92..e2cd96d6 100644 --- a/OpenAL32/alState.cpp +++ b/OpenAL32/alState.cpp @@ -659,7 +659,7 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - if((ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)&EventType_Deprecated)) + if((context->EnabledEvts.load(std::memory_order_relaxed)&EventType_Deprecated)) { static constexpr ALCchar msg[] = "alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound"; diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index a2c98928..0491c7c6 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -38,7 +38,7 @@ static int EventThread(ALCcontext *context) continue; } - ALbitfieldSOFT enabledevts{ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire)}; + ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_acquire)}; if(context->EventCb && (enabledevts&evt.EnumType) == evt.EnumType) context->EventCb(evt.u.user.type, evt.u.user.id, evt.u.user.param, (ALsizei)strlen(evt.u.user.msg), evt.u.user.msg, context->EventParam diff --git a/common/atomic.h b/common/atomic.h index 2b512653..e34f35bb 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -4,21 +4,6 @@ #include -#define almemory_order std::memory_order -#define almemory_order_relaxed std::memory_order_relaxed -#define almemory_order_consume std::memory_order_consume -#define almemory_order_acquire std::memory_order_acquire -#define almemory_order_release std::memory_order_release -#define almemory_order_acq_rel std::memory_order_acq_rel -#define almemory_order_seq_cst std::memory_order_seq_cst - -#define ATOMIC_LOAD std::atomic_load_explicit -#define ATOMIC_STORE std::atomic_store_explicit - -#define ATOMIC_LOAD_SEQ(_val) ATOMIC_LOAD(_val, almemory_order_seq_cst) -#define ATOMIC_STORE_SEQ(_val, _newval) ATOMIC_STORE(_val, _newval, almemory_order_seq_cst) - - using RefCount = std::atomic; inline void InitRef(RefCount *ptr, unsigned int value) -- cgit v1.2.3 From 75b39cafc8b747a0f468382a9e4a64793a231b98 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 18:25:29 -0800 Subject: Get rid of some unnecessary functions --- OpenAL32/Include/alMain.h | 10 ---------- OpenAL32/alSource.cpp | 16 ++++++---------- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 297ff06f..cb2181da 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -884,16 +884,6 @@ inline ALint GetChannelIdxByName(const RealMixParams *real, enum Channel chan) { return GetChannelIndex(real->ChannelName, chan); } -inline void LockBufferList(ALCdevice *device) { almtx_lock(&device->BufferLock); } -inline void UnlockBufferList(ALCdevice *device) { almtx_unlock(&device->BufferLock); } - -inline void LockEffectList(ALCdevice *device) { almtx_lock(&device->EffectLock); } -inline void UnlockEffectList(ALCdevice *device) { almtx_unlock(&device->EffectLock); } - -inline void LockFilterList(ALCdevice *device) { almtx_lock(&device->FilterLock); } -inline void UnlockFilterList(ALCdevice *device) { almtx_unlock(&device->FilterLock); } - - void StartEventThrd(ALCcontext *ctx); void StopEventThrd(ALCcontext *ctx); diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index e58d6314..37805376 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -1208,6 +1208,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co ALeffectslot *slot{nullptr}; ALbufferlistitem *oldlist{nullptr}; std::unique_lock slotlock; + std::unique_lock filtlock; std::unique_lock buflock; ALfloat fvals[6]; @@ -1335,13 +1336,10 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co return AL_TRUE; case AL_DIRECT_FILTER: - LockFilterList(device); + filtlock = std::unique_lock{device->FilterLock}; if(!(*values == 0 || (filter=LookupFilter(device, *values)) != nullptr)) - { - UnlockFilterList(device); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", *values); - } if(!filter) { @@ -1359,7 +1357,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co Source->Direct.GainLF = filter->GainLF; Source->Direct.LFReference = filter->LFReference; } - UnlockFilterList(device); + filtlock.unlock(); DO_UPDATEPROPS(); return AL_TRUE; @@ -1427,13 +1425,11 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co values[0]); if((ALuint)values[1] >= (ALuint)device->NumAuxSends) SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid send %u", values[1]); - LockFilterList(device); + + filtlock = std::unique_lock{device->FilterLock}; if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != nullptr)) - { - UnlockFilterList(device); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", values[2]); - } if(!filter) { @@ -1452,7 +1448,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co Source->Send[values[1]].GainLF = filter->GainLF; Source->Send[values[1]].LFReference = filter->LFReference; } - UnlockFilterList(device); + filtlock.unlock(); if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source)) { -- cgit v1.2.3 From 05390fa8276ae5e5d1929766cb0cc14818a45669 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 19:01:14 -0800 Subject: Add a missing std::begin --- OpenAL32/Include/alMain.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index cb2181da..d809406d 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -872,7 +872,7 @@ inline ALint GetChannelIndex(const enum Channel (&names)[MAX_OUTPUT_CHANNELS], e { auto iter = std::find(std::begin(names), std::end(names), chan); if(iter == std::end(names)) return -1; - return std::distance(names, iter); + return std::distance(std::begin(names), iter); } /** * GetChannelIdxByName -- cgit v1.2.3 From ecab90802a62266687cf8aeaa61dc2811ce191e7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 20:06:22 -0800 Subject: Replace some uses of althrd_t with std::thread --- Alc/backends/jack.cpp | 33 ++++++++++++++++++--------------- Alc/backends/opensl.cpp | 31 +++++++++++++++++-------------- 2 files changed, 35 insertions(+), 29 deletions(-) diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index fc385f7b..0862f685 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -26,6 +26,8 @@ #include #include +#include + #include "alMain.h" #include "alu.h" #include "alconfig.h" @@ -152,13 +154,13 @@ struct ALCjackPlayback final : public ALCbackend { alsem_t Sem; std::atomic mKillNow{AL_TRUE}; - althrd_t thread; + std::thread mThread; }; static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg); static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg); -static int ALCjackPlayback_mixerProc(void *arg); +static int ALCjackPlayback_mixerProc(ALCjackPlayback *self); static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device); static void ALCjackPlayback_Destruct(ALCjackPlayback *self); @@ -291,9 +293,8 @@ static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) return 0; } -static int ALCjackPlayback_mixerProc(void *arg) +static int ALCjackPlayback_mixerProc(ALCjackPlayback *self) { - ALCjackPlayback *self = static_cast(arg); ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; SetRTPriority(); @@ -465,25 +466,27 @@ static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self) } jack_free(ports); - self->mKillNow.store(AL_FALSE, std::memory_order_release); - if(althrd_create(&self->thread, ALCjackPlayback_mixerProc, self) != althrd_success) - { - jack_deactivate(self->Client); - return ALC_FALSE; + try { + self->mKillNow.store(AL_FALSE, std::memory_order_release); + self->mThread = std::thread(ALCjackPlayback_mixerProc, self); + return ALC_TRUE; } - - return ALC_TRUE; + catch(std::exception& e) { + ERR("Could not create playback thread: %s\n", e.what()); + } + catch(...) { + } + jack_deactivate(self->Client); + return ALC_FALSE; } static void ALCjackPlayback_stop(ALCjackPlayback *self) { - int res; - - if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel)) + if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->mThread.joinable()) return; alsem_post(&self->Sem); - althrd_join(self->thread, &res); + self->mThread.join(); jack_deactivate(self->Client); } diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 9e8e5031..8cea36f3 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -26,6 +26,8 @@ #include #include +#include + #include "alMain.h" #include "alu.h" #include "ringbuffer.h" @@ -149,11 +151,11 @@ struct ALCopenslPlayback final : public ALCbackend { ALsizei mFrameSize{0}; std::atomic mKillNow{AL_TRUE}; - althrd_t mThread; + std::thread mThread; }; static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf bq, void *context); -static int ALCopenslPlayback_mixerProc(void *arg); +static int ALCopenslPlayback_mixerProc(ALCopenslPlayback *self); static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *device); static void ALCopenslPlayback_Destruct(ALCopenslPlayback *self); @@ -224,9 +226,8 @@ static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), } -static int ALCopenslPlayback_mixerProc(void *arg) +static int ALCopenslPlayback_mixerProc(ALCopenslPlayback *self) { - ALCopenslPlayback *self = static_cast(arg); ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; SLAndroidSimpleBufferQueueItf bufferQueue; SLPlayItf player; @@ -580,14 +581,17 @@ static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self) if(SL_RESULT_SUCCESS != result) return ALC_FALSE; - self->mKillNow.store(AL_FALSE); - if(althrd_create(&self->mThread, ALCopenslPlayback_mixerProc, self) != althrd_success) - { - ERR("Failed to start mixer thread\n"); - return ALC_FALSE; + try { + self->mKillNow.store(AL_FALSE); + self->mThread = std::thread(ALCopenslPlayback_mixerProc, self); + return ALC_TRUE; } - - return ALC_TRUE; + catch(std::exception& e) { + ERR("Could not create playback thread: %s\n", e.what()); + } + catch(...) { + } + return ALC_FALSE; } @@ -596,13 +600,12 @@ static void ALCopenslPlayback_stop(ALCopenslPlayback *self) SLAndroidSimpleBufferQueueItf bufferQueue; SLPlayItf player; SLresult result; - int res; - if(self->mKillNow.exchange(AL_TRUE)) + if(self->mKillNow.exchange(AL_TRUE) || !self->mThread.joinable()) return; alsem_post(&self->mSem); - althrd_join(self->mThread, &res); + self->mThread.join(); result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player); PRINTERR(result, "bufferQueue->GetInterface"); -- cgit v1.2.3 From bf9db1fe3d611137448c0eb99978c8906531ffc1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 20:34:16 -0800 Subject: Remove althrd_t from Windows --- Alc/helpers.cpp | 1 - CMakeLists.txt | 1 - common/threads.cpp | 76 ------------------------------------------------------ common/threads.h | 11 ++++---- common/uintmap.h | 35 ------------------------- 5 files changed, 5 insertions(+), 119 deletions(-) delete mode 100644 common/uintmap.h diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index d06a4807..8a2a851d 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -118,7 +118,6 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x #include "alu.h" #include "cpu_caps.h" #include "fpu_modes.h" -#include "uintmap.h" #include "vector.h" #include "compat.h" #include "threads.h" diff --git a/CMakeLists.txt b/CMakeLists.txt index 6bbbc561..26476a67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -709,7 +709,6 @@ SET(COMMON_OBJS common/math_defs.h common/threads.cpp common/threads.h - common/uintmap.h common/vecmat.cpp common/vecmat.h ) diff --git a/common/threads.cpp b/common/threads.cpp index 7d44c012..86fbb7b5 100644 --- a/common/threads.cpp +++ b/common/threads.cpp @@ -26,8 +26,6 @@ #include #include -#include "uintmap.h" - #ifndef UNUSED #if defined(__cplusplus) @@ -51,15 +49,6 @@ #include -/* An associative map of uint:void* pairs. The key is the unique Thread ID and - * the value is the thread HANDLE. The thread ID is passed around as the - * althrd_t since there is only one ID per thread, whereas a thread may be - * referenced by multiple different HANDLEs. This map allows retrieving the - * original handle which is needed to join the thread and get its return value. - */ -static ThrSafeMap ThrdIdHandle{}; - - void althrd_setname(const char *name) { #if defined(_MSC_VER) @@ -89,71 +78,6 @@ void althrd_setname(const char *name) } -typedef struct thread_cntr { - althrd_start_t func; - void *arg; -} thread_cntr; - -static DWORD WINAPI althrd_starter(void *arg) -{ - thread_cntr cntr; - memcpy(&cntr, arg, sizeof(cntr)); - free(arg); - - return (DWORD)((*cntr.func)(cntr.arg)); -} - - -int althrd_create(althrd_t *thr, althrd_start_t func, void *arg) -{ - thread_cntr *cntr; - DWORD thrid; - HANDLE hdl; - - cntr = static_cast(malloc(sizeof(*cntr))); - if(!cntr) return althrd_nomem; - - cntr->func = func; - cntr->arg = arg; - - hdl = CreateThread(NULL, THREAD_STACK_SIZE, althrd_starter, cntr, 0, &thrid); - if(!hdl) - { - free(cntr); - return althrd_error; - } - ThrdIdHandle.InsertEntry(thrid, hdl); - - *thr = thrid; - return althrd_success; -} - -int althrd_detach(althrd_t thr) -{ - HANDLE hdl = ThrdIdHandle.RemoveKey(thr); - if(!hdl) return althrd_error; - - CloseHandle(hdl); - return althrd_success; -} - -int althrd_join(althrd_t thr, int *res) -{ - DWORD code; - - HANDLE hdl = ThrdIdHandle.RemoveKey(thr); - if(!hdl) return althrd_error; - - WaitForSingleObject(hdl, INFINITE); - GetExitCodeThread(hdl, &code); - CloseHandle(hdl); - - if(res != NULL) - *res = (int)code; - return althrd_success; -} - - int almtx_init(almtx_t *mtx, int type) { if(!mtx) return althrd_error; diff --git a/common/threads.h b/common/threads.h index 8fd1093d..a5f6ce45 100644 --- a/common/threads.h +++ b/common/threads.h @@ -30,14 +30,11 @@ enum { almtx_recursive = 1, }; -typedef int (*althrd_start_t)(void*); - #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include -typedef DWORD althrd_t; typedef CRITICAL_SECTION almtx_t; typedef HANDLE alsem_t; @@ -81,6 +78,8 @@ typedef dispatch_semaphore_t alsem_t; typedef sem_t alsem_t; #endif /* __APPLE__ */ +typedef int (*althrd_start_t)(void*); + inline void althrd_yield(void) { @@ -102,12 +101,12 @@ inline int almtx_unlock(almtx_t *mtx) return althrd_success; } -#endif - - int althrd_create(althrd_t *thr, althrd_start_t func, void *arg); int althrd_detach(althrd_t thr); int althrd_join(althrd_t thr, int *res); + +#endif + void althrd_setname(const char *name); int almtx_init(almtx_t *mtx, int type); diff --git a/common/uintmap.h b/common/uintmap.h deleted file mode 100644 index 0646d2b5..00000000 --- a/common/uintmap.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef AL_UINTMAP_H -#define AL_UINTMAP_H - -#include -#include - -#include "AL/al.h" - -template -class ThrSafeMap { - std::unordered_map mValues; - std::mutex mLock; - -public: - void InsertEntry(T0 key, T1 value) noexcept - { - std::lock_guard _{mLock}; - mValues[key] = value; - } - - T1 RemoveKey(T0 key) noexcept - { - T1 retval{}; - - std::lock_guard _{mLock}; - auto iter = mValues.find(key); - if(iter != mValues.end()) - retval = iter->second; - mValues.erase(iter); - - return retval; - } -}; - -#endif /* AL_UINTMAP_H */ -- cgit v1.2.3 From 9ac76c0a7ff12ae2c3456481e95e65b46c33d4e5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 20:55:00 -0800 Subject: Simplify some binary search lookups --- router/router.cpp | 96 ++++++++++++++++--------------------------------------- 1 file changed, 27 insertions(+), 69 deletions(-) diff --git a/router/router.cpp b/router/router.cpp index 66bf5dd3..5b976e95 100644 --- a/router/router.cpp +++ b/router/router.cpp @@ -7,6 +7,8 @@ #include #include +#include + #include "AL/alc.h" #include "AL/al.h" #include "almalloc.h" @@ -362,46 +364,28 @@ PtrIntMap::~PtrIntMap() ALenum PtrIntMap::insert(ALvoid *key, ALint value) { - ALsizei pos = 0; - std::lock_guard maplock{mLock}; - if(mSize > 0) - { - ALsizei count = mSize; - do { - ALsizei step = count>>1; - ALsizei i = pos+step; - if(mKeys[i] >= key) - count = step; - else - { - pos = i+1; - count -= step+1; - } - } while(count > 0); - } + auto iter = std::lower_bound(mKeys, mKeys+mSize, key); + auto pos = static_cast(std::distance(mKeys, iter)); if(pos == mSize || mKeys[pos] != key) { if(mSize == mCapacity) { - ALvoid **newkeys = nullptr; - ALint *newvalues; - ALsizei newcap; - - newcap = (mCapacity ? (mCapacity<<1) : 4); + ALvoid **newkeys{nullptr}; + ALsizei newcap{mCapacity ? (mCapacity<<1) : 4}; if(newcap > mCapacity) - newkeys = reinterpret_cast( + newkeys = static_cast( al_calloc(16, (sizeof(mKeys[0])+sizeof(mValues[0]))*newcap) ); if(!newkeys) return AL_OUT_OF_MEMORY; - newvalues = (ALint*)&newkeys[newcap]; + auto newvalues = reinterpret_cast(&newkeys[newcap]); if(mKeys) { - memcpy(newkeys, mKeys, mSize*sizeof(mKeys[0])); - memcpy(newvalues, mValues, mSize*sizeof(mValues[0])); + std::copy_n(mKeys, mSize, newkeys); + std::copy_n(mValues, mSize, newvalues); } al_free(mKeys); mKeys = newkeys; @@ -411,8 +395,8 @@ ALenum PtrIntMap::insert(ALvoid *key, ALint value) if(pos < mSize) { - memmove(&mKeys[pos+1], &mKeys[pos], (mSize-pos)*sizeof(mKeys[0])); - memmove(&mValues[pos+1], &mValues[pos], (mSize-pos)*sizeof(mValues[0])); + std::copy_backward(mKeys+pos, mKeys+mSize, mKeys+mSize+1); + std::copy_backward(mValues+pos, mValues+mSize, mValues+mSize+1); } mSize++; } @@ -427,57 +411,31 @@ ALint PtrIntMap::removeByKey(ALvoid *key) ALint ret = -1; std::lock_guard maplock{mLock}; - if(mSize > 0) + auto iter = std::lower_bound(mKeys, mKeys+mSize, key); + auto pos = static_cast(std::distance(mKeys, iter)); + if(pos < mSize && mKeys[pos] == key) { - ALsizei pos = 0; - ALsizei count = mSize; - do { - ALsizei step = count>>1; - ALsizei i = pos+step; - if(mKeys[i] >= key) - count = step; - else - { - pos = i+1; - count -= step+1; - } - } while(count > 0); - if(pos < mSize && mKeys[pos] == key) + ret = mValues[pos]; + if(pos+1 < mSize) { - ret = mValues[pos]; - if(pos < mSize-1) - { - memmove(&mKeys[pos], &mKeys[pos+1], (mSize-1-pos)*sizeof(mKeys[0])); - memmove(&mValues[pos], &mValues[pos+1], (mSize-1-pos)*sizeof(mValues[0])); - } - mSize--; + std::copy(mKeys+pos+1, mKeys+mSize, mKeys+pos); + std::copy(mValues+pos+1, mValues+mSize, mValues+pos); } + mSize--; } + return ret; } -ALint PtrIntMap::lookupByKey(ALvoid* key) +ALint PtrIntMap::lookupByKey(ALvoid *key) { ALint ret = -1; std::lock_guard maplock{mLock}; - if(mSize > 0) - { - ALsizei pos = 0; - ALsizei count = mSize; - do { - ALsizei step = count>>1; - ALsizei i = pos+step; - if(mKeys[i] >= key) - count = step; - else - { - pos = i+1; - count -= step+1; - } - } while(count > 0); - if(pos < mSize && mKeys[pos] == key) - ret = mValues[pos]; - } + auto iter = std::lower_bound(mKeys, mKeys+mSize, key); + auto pos = static_cast(std::distance(mKeys, iter)); + if(pos < mSize && mKeys[pos] == key) + ret = mValues[pos]; + return ret; } -- cgit v1.2.3 From 9070426ece40e6620d839c9010474bd753935d1d Mon Sep 17 00:00:00 2001 From: wangwenx190 <2546789017@qq.com> Date: Tue, 27 Nov 2018 13:18:30 +0800 Subject: Update FindWindowsSDK.cmake Support latest Win10 SDK. --- cmake/FindWindowsSDK.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmake/FindWindowsSDK.cmake b/cmake/FindWindowsSDK.cmake index e136b897..4b0e2340 100644 --- a/cmake/FindWindowsSDK.cmake +++ b/cmake/FindWindowsSDK.cmake @@ -73,6 +73,10 @@ macro(_winsdk_announce) endmacro() set(_winsdk_win10vers + 10.0.17763.0 # Windows 10 Version 1809 + 10.0.17134.0 # Windows 10 Version 1803 (April 2018 Update) + 10.0.16299.0 # Windows 10 Version 1709 (Fall Creators Update) + 10.0.15063.0 # Windows 10 Version 1703 (Creators Update) 10.0.14393.0 # Redstone aka Win10 1607 "Anniversary Update" 10.0.10586.0 # TH2 aka Win10 1511 10.0.10240.0 # Win10 RTM -- cgit v1.2.3 From 00ad4a2f5d67b54ec932a8c33f5af2a90b32b46b Mon Sep 17 00:00:00 2001 From: wangwenx190 <2546789017@qq.com> Date: Tue, 27 Nov 2018 13:20:04 +0800 Subject: Update FindWindowsSDK.cmake --- cmake/FindWindowsSDK.cmake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/FindWindowsSDK.cmake b/cmake/FindWindowsSDK.cmake index 4b0e2340..007c9b17 100644 --- a/cmake/FindWindowsSDK.cmake +++ b/cmake/FindWindowsSDK.cmake @@ -73,10 +73,10 @@ macro(_winsdk_announce) endmacro() set(_winsdk_win10vers - 10.0.17763.0 # Windows 10 Version 1809 - 10.0.17134.0 # Windows 10 Version 1803 (April 2018 Update) - 10.0.16299.0 # Windows 10 Version 1709 (Fall Creators Update) - 10.0.15063.0 # Windows 10 Version 1703 (Creators Update) + 10.0.17763.0 # Windows 10 Version 1809 + 10.0.17134.0 # Windows 10 Version 1803 (April 2018 Update) + 10.0.16299.0 # Windows 10 Version 1709 (Fall Creators Update) + 10.0.15063.0 # Windows 10 Version 1703 (Creators Update) 10.0.14393.0 # Redstone aka Win10 1607 "Anniversary Update" 10.0.10586.0 # TH2 aka Win10 1511 10.0.10240.0 # Win10 RTM -- cgit v1.2.3 From b108d0acfd062756da69074242e24ea7b2856b8a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 21:19:20 -0800 Subject: Remove the last remaining uses of althrd_t --- Alc/backends/qsa.cpp | 24 +++++++++----- Alc/backends/sndio.cpp | 64 +++++++++++++++++++----------------- Alc/backends/solaris.cpp | 30 ++++++++++------- common/threads.cpp | 85 ------------------------------------------------ common/threads.h | 7 ---- 5 files changed, 67 insertions(+), 143 deletions(-) diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index b40b5b6b..3d09a744 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -53,7 +54,7 @@ struct qsa_data { ALsizei size{0}; std::atomic mKillNow{AL_TRUE}; - althrd_t thread; + std::thread mThread; }; struct DevMap { @@ -592,21 +593,26 @@ static ALCboolean qsa_start_playback(PlaybackWrapper *self) { qsa_data *data = self->ExtraData.get(); - data->mKillNow.store(AL_FALSE, std::memory_order_release); - if(althrd_create(&data->thread, qsa_proc_playback, self) != althrd_success) - return ALC_FALSE; - - return ALC_TRUE; + try { + data->mKillNow.store(AL_FALSE, std::memory_order_release); + data->mThread = std::thread(qsa_proc_playback, self); + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Could not create playback thread: %s\n", e.what()); + } + catch(...) { + } + return ALC_FALSE; } static void qsa_stop_playback(PlaybackWrapper *self) { qsa_data *data = self->ExtraData.get(); - int res; - if(data->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel)) + if(data->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !data->mThread.joinable()) return; - althrd_join(data->thread, &res); + data->mThread.join(); } diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index 2a999bd4..1dabe5ca 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -26,6 +26,8 @@ #include #include +#include + #include "alMain.h" #include "alu.h" #include "threads.h" @@ -44,10 +46,10 @@ struct SndioPlayback final : public ALCbackend { ALsizei data_size{0}; std::atomic mKillNow{AL_TRUE}; - althrd_t thread; + std::thread mThread; }; -static int SndioPlayback_mixerProc(void *ptr); +static int SndioPlayback_mixerProc(SndioPlayback *self); static void SndioPlayback_Construct(SndioPlayback *self, ALCdevice *device); static void SndioPlayback_Destruct(SndioPlayback *self); @@ -86,9 +88,8 @@ static void SndioPlayback_Destruct(SndioPlayback *self) } -static int SndioPlayback_mixerProc(void *ptr) +static int SndioPlayback_mixerProc(SndioPlayback *self) { - SndioPlayback *self = static_cast(ptr); ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; ALsizei frameSize; size_t wrote; @@ -249,23 +250,25 @@ static ALCboolean SndioPlayback_start(SndioPlayback *self) return ALC_FALSE; } - self->mKillNow.store(AL_FALSE, std::memory_order_release); - if(althrd_create(&self->thread, SndioPlayback_mixerProc, self) != althrd_success) - { - sio_stop(self->sndHandle); - return ALC_FALSE; + try { + self->mKillNow.store(AL_FALSE, std::memory_order_release); + self->mThread = std::thread(SndioPlayback_mixerProc, self); + return ALC_TRUE; } - - return ALC_TRUE; + catch(std::exception& e) { + ERR("Could not create playback thread: %s\n", e.what()); + } + catch(...) { + } + sio_stop(self->sndHandle); + return ALC_FALSE; } static void SndioPlayback_stop(SndioPlayback *self) { - int res; - - if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel)) + if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->mThread.joinable()) return; - althrd_join(self->thread, &res); + self->mThread.join(); if(!sio_stop(self->sndHandle)) ERR("Error stopping device\n"); @@ -281,10 +284,10 @@ struct SndioCapture final : public ALCbackend { ll_ringbuffer_t *ring{nullptr}; std::atomic mKillNow{AL_TRUE}; - althrd_t thread; + std::thread mThread; }; -static int SndioCapture_recordProc(void *ptr); +static int SndioCapture_recordProc(SndioCapture *self); static void SndioCapture_Construct(SndioCapture *self, ALCdevice *device); static void SndioCapture_Destruct(SndioCapture *self); @@ -323,9 +326,8 @@ static void SndioCapture_Destruct(SndioCapture *self) } -static int SndioCapture_recordProc(void* ptr) +static int SndioCapture_recordProc(SndioCapture *self) { - SndioCapture *self = static_cast(ptr); ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; ALsizei frameSize; @@ -490,23 +492,25 @@ static ALCboolean SndioCapture_start(SndioCapture *self) return ALC_FALSE; } - self->mKillNow.store(AL_FALSE, std::memory_order_release); - if(althrd_create(&self->thread, SndioCapture_recordProc, self) != althrd_success) - { - sio_stop(self->sndHandle); - return ALC_FALSE; + try { + self->mKillNow.store(AL_FALSE, std::memory_order_release); + self->mThread = std::thread(SndioCapture_recordProc, self); + return ALC_TRUE; } - - return ALC_TRUE; + catch(std::exception& e) { + ERR("Could not create record thread: %s\n", e.what()); + } + catch(...) { + } + sio_stop(self->sndHandle); + return ALC_FALSE; } static void SndioCapture_stop(SndioCapture *self) { - int res; - - if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel)) + if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->mThread.joinable()) return; - althrd_join(self->thread, &res); + self->mThread.join(); if(!sio_stop(self->sndHandle)) ERR("Error stopping device\n"); diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index 0ca7a4ec..941ca015 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -34,6 +34,8 @@ #include #include +#include + #include "alMain.h" #include "alu.h" #include "alconfig.h" @@ -50,10 +52,10 @@ struct ALCsolarisBackend final : public ALCbackend { int data_size{0}; std::atomic mKillNow{AL_TRUE}; - althrd_t thread; + std::thread mThread; }; -static int ALCsolarisBackend_mixerProc(void *ptr); +static int ALCsolarisBackend_mixerProc(ALCsolarisBackend *self); static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *device); static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self); @@ -98,9 +100,8 @@ static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self) } -static int ALCsolarisBackend_mixerProc(void *ptr) +static int ALCsolarisBackend_mixerProc(ALCsolarisBackend *self) { - ALCsolarisBackend *self = static_cast(ptr); ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; struct timeval timeout; ALubyte *write_ptr; @@ -268,20 +269,25 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self) { - self->mKillNow.store(AL_FALSE); - if(althrd_create(&self->thread, ALCsolarisBackend_mixerProc, self) != althrd_success) - return ALC_FALSE; - return ALC_TRUE; + try { + self->mKillNow.store(AL_FALSE); + self->mThread = std::thread(ALCsolarisBackend_mixerProc, self); + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Could not create playback thread: %s\n", e.what()); + } + catch(...) { + } + return ALC_FALSE; } static void ALCsolarisBackend_stop(ALCsolarisBackend *self) { - int res; - - if(self->mKillNow.exchange(AL_TRUE)) + if(self->mKillNow.exchange(AL_TRUE) || !self->mThread.joinable()) return; - althrd_join(self->thread, &res); + self->mThread.join(); if(ioctl(self->fd, AUDIO_DRAIN) < 0) ERR("Error draining device: %s\n", strerror(errno)); diff --git a/common/threads.cpp b/common/threads.cpp index 86fbb7b5..489e5f5b 100644 --- a/common/threads.cpp +++ b/common/threads.cpp @@ -158,91 +158,6 @@ void althrd_setname(const char *name) } -typedef struct thread_cntr { - althrd_start_t func; - void *arg; -} thread_cntr; - -static void *althrd_starter(void *arg) -{ - thread_cntr cntr; - memcpy(&cntr, arg, sizeof(cntr)); - free(arg); - - return (void*)(intptr_t)((*cntr.func)(cntr.arg)); -} - - -int althrd_create(althrd_t *thr, althrd_start_t func, void *arg) -{ - thread_cntr *cntr; - pthread_attr_t attr; - size_t stackmult = 1; - int err; - - cntr = static_cast(malloc(sizeof(*cntr))); - if(!cntr) return althrd_nomem; - - if(pthread_attr_init(&attr) != 0) - { - free(cntr); - return althrd_error; - } -retry_stacksize: - if(pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE*stackmult) != 0) - { - pthread_attr_destroy(&attr); - free(cntr); - return althrd_error; - } - - cntr->func = func; - cntr->arg = arg; - if((err=pthread_create(thr, &attr, althrd_starter, cntr)) == 0) - { - pthread_attr_destroy(&attr); - return althrd_success; - } - - if(err == EINVAL) - { - /* If an invalid stack size, try increasing it (limit x4, 8MB). */ - if(stackmult < 4) - { - stackmult *= 2; - goto retry_stacksize; - } - /* If still nothing, try defaults and hope they're good enough. */ - if(pthread_create(thr, NULL, althrd_starter, cntr) == 0) - { - pthread_attr_destroy(&attr); - return althrd_success; - } - } - pthread_attr_destroy(&attr); - free(cntr); - return althrd_error; -} - -int althrd_detach(althrd_t thr) -{ - if(pthread_detach(thr) != 0) - return althrd_error; - return althrd_success; -} - -int althrd_join(althrd_t thr, int *res) -{ - void *code; - - if(pthread_join(thr, &code) != 0) - return althrd_error; - if(res != NULL) - *res = (int)(intptr_t)code; - return althrd_success; -} - - int almtx_init(almtx_t *mtx, int type) { int ret; diff --git a/common/threads.h b/common/threads.h index a5f6ce45..53b56147 100644 --- a/common/threads.h +++ b/common/threads.h @@ -70,7 +70,6 @@ inline int almtx_unlock(almtx_t *mtx) #include #endif /* __APPLE__ */ -typedef pthread_t althrd_t; typedef pthread_mutex_t almtx_t; #ifdef __APPLE__ typedef dispatch_semaphore_t alsem_t; @@ -78,8 +77,6 @@ typedef dispatch_semaphore_t alsem_t; typedef sem_t alsem_t; #endif /* __APPLE__ */ -typedef int (*althrd_start_t)(void*); - inline void althrd_yield(void) { @@ -101,10 +98,6 @@ inline int almtx_unlock(almtx_t *mtx) return althrd_success; } -int althrd_create(althrd_t *thr, althrd_start_t func, void *arg); -int althrd_detach(althrd_t thr); -int althrd_join(althrd_t thr, int *res); - #endif void althrd_setname(const char *name); -- cgit v1.2.3 From d8b9230ee4770095b0848aa38752e19d0090dd6a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 21:29:11 -0800 Subject: Use a standard mutex for the backend lock --- Alc/alc.cpp | 44 ++++++++++++++++++++------------------------ OpenAL32/Include/alMain.h | 2 +- OpenAL32/alAuxEffectSlot.cpp | 2 +- OpenAL32/alSource.cpp | 4 ++-- 4 files changed, 24 insertions(+), 28 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index ea72757c..485ab88e 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2377,8 +2377,6 @@ ALCdevice_struct::ALCdevice_struct(DeviceType type) almtx_init(&BufferLock, almtx_plain); almtx_init(&EffectLock, almtx_plain); almtx_init(&FilterLock, almtx_plain); - - almtx_init(&BackendLock, almtx_plain); } /* ALCdevice_struct::~ALCdevice_struct @@ -2411,8 +2409,6 @@ ALCdevice_struct::~ALCdevice_struct() if(count > 0) WARN(SZFMT " Filter%s not deleted\n", count, (count==1)?"":"s"); - almtx_destroy(&BackendLock); - almtx_destroy(&BufferLock); almtx_destroy(&EffectLock); almtx_destroy(&FilterLock); @@ -3011,7 +3007,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para alcSetError(nullptr, ALC_INVALID_DEVICE); else { - std::lock_guard _{dev->BackendLock}; + std::lock_guard _{dev->BackendLock}; value = (dev->HrtfHandle ? dev->HrtfName.c_str() : ""); } break; @@ -3094,7 +3090,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC alcSetError(device, ALC_INVALID_VALUE); else { - std::lock_guard _{device->BackendLock}; + std::lock_guard _{device->BackendLock}; values[i++] = ALC_MAJOR_VERSION; values[i++] = alcMajorVersion; values[i++] = ALC_MINOR_VERSION; @@ -3115,7 +3111,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_CAPTURE_SAMPLES: - { std::lock_guard _{device->BackendLock}; + { std::lock_guard _{device->BackendLock}; values[0] = V0(device->Backend,availableSamples)(); } return 1; @@ -3144,7 +3140,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC alcSetError(device, ALC_INVALID_VALUE); else { - std::lock_guard _{device->BackendLock}; + std::lock_guard _{device->BackendLock}; values[i++] = ALC_MAJOR_VERSION; values[i++] = alcMajorVersion; values[i++] = ALC_MINOR_VERSION; @@ -3236,7 +3232,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC alcSetError(device, ALC_INVALID_DEVICE); return 0; } - { std::lock_guard _{device->BackendLock}; + { std::lock_guard _{device->BackendLock}; values[0] = device->Frequency / device->UpdateSize; } return 1; @@ -3320,7 +3316,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_NUM_HRTF_SPECIFIERS_SOFT: - { std::lock_guard _{device->BackendLock}; + { std::lock_guard _{device->BackendLock}; device->HrtfList.clear(); device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); values[0] = (ALCint)device->HrtfList.size(); @@ -3380,7 +3376,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, else { ALsizei i{0}; - std::lock_guard _{dev->BackendLock}; + std::lock_guard _{dev->BackendLock}; values[i++] = ALC_FREQUENCY; values[i++] = dev->Frequency; @@ -3443,7 +3439,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, break; case ALC_DEVICE_CLOCK_SOFT: - { std::lock_guard _{dev->BackendLock}; + { std::lock_guard _{dev->BackendLock}; using std::chrono::seconds; using std::chrono::nanoseconds; using std::chrono::duration_cast; @@ -3463,7 +3459,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, break; case ALC_DEVICE_LATENCY_SOFT: - { std::lock_guard _{dev->BackendLock}; + { std::lock_guard _{dev->BackendLock}; ClockLatency clock{GetClockLatency(dev.get())}; *values = clock.Latency.count(); } @@ -3474,7 +3470,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, alcSetError(dev.get(), ALC_INVALID_VALUE); else { - std::lock_guard _{dev->BackendLock}; + std::lock_guard _{dev->BackendLock}; ClockLatency clock{GetClockLatency(dev.get())}; values[0] = clock.ClockTime.count(); values[1] = clock.Latency.count(); @@ -3592,7 +3588,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin alcSetError(dev.get(), ALC_INVALID_DEVICE); return nullptr; } - std::unique_lock backlock{dev->BackendLock}; + std::unique_lock backlock{dev->BackendLock}; listlock.unlock(); dev->LastError.store(ALC_NO_ERROR); @@ -3685,7 +3681,7 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) ALCdevice* Device{ctx->Device}; if(Device) { - std::lock_guard _{Device->BackendLock}; + std::lock_guard _{Device->BackendLock}; if(!ReleaseContext(ctx.get(), Device)) { V0(Device->Backend,stop)(); @@ -3993,7 +3989,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) alcSetError(iter, ALC_INVALID_DEVICE); return ALC_FALSE; } - std::unique_lock backlock{device->BackendLock}; + std::unique_lock backlock{device->BackendLock}; ALCdevice *origdev{device}; ALCdevice *nextdev{device->next.load(std::memory_order_relaxed)}; @@ -4123,7 +4119,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) } listlock.unlock(); - { std::lock_guard _{device->BackendLock}; + { std::lock_guard _{device->BackendLock}; if((device->Flags&DEVICE_RUNNING)) V0(device->Backend,stop)(); device->Flags &= ~DEVICE_RUNNING; @@ -4143,7 +4139,7 @@ ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) return; } - std::lock_guard _{dev->BackendLock}; + std::lock_guard _{dev->BackendLock}; if(!dev->Connected.load(std::memory_order_acquire)) alcSetError(dev.get(), ALC_INVALID_DEVICE); else if(!(dev->Flags&DEVICE_RUNNING)) @@ -4165,7 +4161,7 @@ ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) alcSetError(dev.get(), ALC_INVALID_DEVICE); else { - std::lock_guard _{dev->BackendLock}; + std::lock_guard _{dev->BackendLock}; if((dev->Flags&DEVICE_RUNNING)) V0(dev->Backend,stop)(); dev->Flags &= ~DEVICE_RUNNING; @@ -4182,7 +4178,7 @@ ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, } ALCenum err{ALC_INVALID_VALUE}; - { std::lock_guard _{dev->BackendLock}; + { std::lock_guard _{dev->BackendLock}; if(samples >= 0 && V0(dev->Backend,availableSamples)() >= (ALCuint)samples) err = V(dev->Backend,captureSamples)(buffer, samples); } @@ -4318,7 +4314,7 @@ ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device) alcSetError(dev.get(), ALC_INVALID_DEVICE); else { - std::lock_guard _{dev->BackendLock}; + std::lock_guard _{dev->BackendLock}; if((dev->Flags&DEVICE_RUNNING)) V0(dev->Backend,stop)(); dev->Flags &= ~DEVICE_RUNNING; @@ -4337,7 +4333,7 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) alcSetError(dev.get(), ALC_INVALID_DEVICE); else { - std::lock_guard _{dev->BackendLock}; + std::lock_guard _{dev->BackendLock}; if((dev->Flags&DEVICE_PAUSED)) { dev->Flags &= ~DEVICE_PAUSED; @@ -4401,7 +4397,7 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi alcSetError(dev.get(), ALC_INVALID_DEVICE); return ALC_FALSE; } - std::unique_lock backlock{dev->BackendLock}; + std::unique_lock backlock{dev->BackendLock}; listlock.unlock(); ALCenum err{UpdateDeviceParams(dev.get(), attribs)}; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index d809406d..3643dd77 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -785,7 +785,7 @@ struct ALCdevice_struct { // Contexts created on this device std::atomic ContextList{nullptr}; - almtx_t BackendLock; + std::mutex BackendLock; ALCbackend *Backend{nullptr}; std::atomic next{nullptr}; diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index cf39292b..43e99584 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -516,7 +516,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect FPUCtl mixer_mode{}; ALCdevice *Device{Context->Device}; - std::unique_lock backlock{Device->BackendLock}; + std::unique_lock backlock{Device->BackendLock}; State->mOutBuffer = Device->Dry.Buffer; State->mOutChannels = Device->Dry.NumChannels; if(State->deviceUpdate(Device) == AL_FALSE) diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 37805376..0515074c 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -1724,7 +1724,7 @@ ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL * clock time with the device latency. Order is important. */ values[0] = GetSourceSecOffset(Source, Context, &srcclock); - { std::lock_guard _{device->BackendLock}; + { std::lock_guard _{device->BackendLock}; clocktime = GetClockLatency(device); } if(srcclock == clocktime.ClockTime) @@ -1987,7 +1987,7 @@ ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, * clock time with the device latency. Order is important. */ values[0] = GetSourceSampleOffset(Source, Context, &srcclock); - { std::lock_guard _{device->BackendLock}; + { std::lock_guard _{device->BackendLock}; clocktime = GetClockLatency(device); } if(srcclock == clocktime.ClockTime) -- cgit v1.2.3 From 2e73c2ca929b6cea23195270fe144f9ad3ae5c27 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 21:37:58 -0800 Subject: Use a standard mutex for the proplock --- Alc/alc.cpp | 7 ++----- Alc/alcontext.h | 2 +- OpenAL32/alAuxEffectSlot.cpp | 4 ++-- OpenAL32/alListener.cpp | 24 ++++++++++++------------ OpenAL32/alSource.cpp | 24 ++++++++++++------------ OpenAL32/alState.cpp | 26 +++++++++++++------------- OpenAL32/event.cpp | 2 +- 7 files changed, 43 insertions(+), 46 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 485ab88e..d6331862 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1616,7 +1616,7 @@ void ALCcontext_DeferUpdates(ALCcontext *context) */ void ALCcontext_ProcessUpdates(ALCcontext *context) { - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; if(context->DeferUpdates.exchange(false)) { /* Tell the mixer to stop applying updates, then wait for any active @@ -2260,7 +2260,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) UpdateEffectSlotProps(slot, context); } - std::unique_lock proplock{context->PropLock}; + std::unique_lock proplock{context->PropLock}; std::unique_lock slotlock{context->EffectSlotLock}; for(auto &slot : context->EffectSlotList) { @@ -2513,7 +2513,6 @@ static ALvoid InitContext(ALCcontext *Context) struct ALeffectslotArray *auxslots; //Validate Context - almtx_init(&Context->PropLock, almtx_plain); almtx_init(&Context->SourceLock, almtx_plain); almtx_init(&Context->EffectSlotLock, almtx_plain); @@ -2660,8 +2659,6 @@ ALCcontext_struct::~ALCcontext_struct() ll_ringbuffer_free(AsyncEvents); AsyncEvents = nullptr; - almtx_destroy(&PropLock); - ALCdevice_DecRef(Device); } diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 056d9003..0b285bfb 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -84,7 +84,7 @@ struct ALCcontext_struct { std::atomic_flag PropsClean{true}; std::atomic DeferUpdates{false}; - almtx_t PropLock; + std::mutex PropLock; /* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit * indicates if updates are currently happening). diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index 43e99584..539329a7 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -287,7 +287,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; std::lock_guard __{context->EffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) @@ -358,7 +358,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; std::lock_guard __{context->EffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) diff --git a/OpenAL32/alListener.cpp b/OpenAL32/alListener.cpp index 2d3482bf..c86c8374 100644 --- a/OpenAL32/alListener.cpp +++ b/OpenAL32/alListener.cpp @@ -43,7 +43,7 @@ AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) if(UNLIKELY(!context)) return; ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; switch(param) { case AL_GAIN: @@ -76,7 +76,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val if(UNLIKELY(!context)) return; ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; switch(param) { case AL_POSITION: @@ -125,7 +125,7 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) if(UNLIKELY(!context)) return; ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; if(!values) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "NULL pointer"); switch(param) { @@ -154,7 +154,7 @@ AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value)) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; switch(param) { default: @@ -176,7 +176,7 @@ AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, A ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; switch(param) { default: @@ -212,7 +212,7 @@ AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; if(!values) alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) @@ -229,7 +229,7 @@ AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) if(UNLIKELY(!context)) return; ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; if(!value) alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) @@ -254,7 +254,7 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat if(UNLIKELY(!context)) return; ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; if(!value1 || !value2 || !value3) alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) @@ -296,7 +296,7 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) if(UNLIKELY(!context)) return; ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; if(!values) alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) @@ -322,7 +322,7 @@ AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; if(!value) alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) @@ -339,7 +339,7 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu if(UNLIKELY(!context)) return; ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; if(!value1 || !value2 || !value3) alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) @@ -376,7 +376,7 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) if(UNLIKELY(!context)) return; ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; if(!values) alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 0515074c..bbcd318e 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -2192,7 +2192,7 @@ AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; std::lock_guard __{context->SourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) @@ -2208,7 +2208,7 @@ AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1 ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; std::lock_guard __{context->SourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) @@ -2227,7 +2227,7 @@ AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; std::lock_guard __{context->SourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) @@ -2246,7 +2246,7 @@ AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble va ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; std::lock_guard __{context->SourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) @@ -2265,7 +2265,7 @@ AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble v ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; std::lock_guard __{context->SourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) @@ -2284,7 +2284,7 @@ AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdo ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; std::lock_guard __{context->SourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) @@ -2314,7 +2314,7 @@ AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; std::lock_guard __{context->SourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) @@ -2330,7 +2330,7 @@ AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, AL ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; std::lock_guard __{context->SourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) @@ -2349,7 +2349,7 @@ AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *val ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; std::lock_guard __{context->SourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) @@ -2368,7 +2368,7 @@ AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SO ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; std::lock_guard __{context->SourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) @@ -2384,7 +2384,7 @@ AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOF ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; std::lock_guard __{context->SourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) @@ -2403,7 +2403,7 @@ AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALin ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; std::lock_guard __{context->SourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) diff --git a/OpenAL32/alState.cpp b/OpenAL32/alState.cpp index e2cd96d6..37bddea3 100644 --- a/OpenAL32/alState.cpp +++ b/OpenAL32/alState.cpp @@ -79,7 +79,7 @@ AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; switch(capability) { case AL_SOURCE_DISTANCE_MODEL: @@ -97,7 +97,7 @@ AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; switch(capability) { case AL_SOURCE_DISTANCE_MODEL: @@ -115,7 +115,7 @@ AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return AL_FALSE; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; ALboolean value{AL_FALSE}; switch(capability) { @@ -135,7 +135,7 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return AL_FALSE; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; ALboolean value{AL_FALSE}; switch(pname) { @@ -190,7 +190,7 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return 0.0; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; ALdouble value{0.0}; switch(pname) { @@ -239,7 +239,7 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return 0.0f; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; ALfloat value{0.0f}; switch(pname) { @@ -288,7 +288,7 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return 0; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; ALint value{0}; switch(pname) { @@ -337,7 +337,7 @@ extern "C" AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return 0; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; ALint64SOFT value{0}; switch(pname) { @@ -386,7 +386,7 @@ AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname) ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return nullptr; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; void *value{nullptr}; switch(pname) { @@ -648,7 +648,7 @@ AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value) alSetError(context.get(), AL_INVALID_VALUE, "Doppler factor %f out of range", value); else { - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; context->DopplerFactor = value; DO_UPDATEPROPS(); } @@ -675,7 +675,7 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) alSetError(context.get(), AL_INVALID_VALUE, "Doppler velocity %f out of range", value); else { - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; context->DopplerVelocity = value; DO_UPDATEPROPS(); } @@ -690,7 +690,7 @@ AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value) alSetError(context.get(), AL_INVALID_VALUE, "Speed of sound %f out of range", value); else { - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; context->SpeedOfSound = value; DO_UPDATEPROPS(); } @@ -708,7 +708,7 @@ AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value) alSetError(context.get(), AL_INVALID_VALUE, "Distance model 0x%04x out of range", value); else { - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; context->mDistanceModel = static_cast(value); if(!context->SourceDistanceModel) DO_UPDATEPROPS(); diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index 0491c7c6..233794bd 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -135,7 +135,7 @@ AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *user ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->PropLock}; std::lock_guard __{context->EventCbLock}; context->EventCb = callback; context->EventParam = userParam; -- cgit v1.2.3 From 68eef6abb4f48262ec4d514fb3c77b8d4e9c0bf7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 21:50:48 -0800 Subject: Use a standard mutex for the source and effect slot locks --- Alc/alc.cpp | 9 ++---- Alc/alcontext.h | 4 +-- OpenAL32/alAuxEffectSlot.cpp | 24 ++++++++-------- OpenAL32/alSource.cpp | 66 ++++++++++++++++++++++---------------------- 4 files changed, 49 insertions(+), 54 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index d6331862..0bb6fbf6 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2261,7 +2261,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } std::unique_lock proplock{context->PropLock}; - std::unique_lock slotlock{context->EffectSlotLock}; + std::unique_lock slotlock{context->EffectSlotLock}; for(auto &slot : context->EffectSlotList) { EffectState *state = slot->Effect.State; @@ -2275,7 +2275,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } slotlock.unlock(); - std::unique_lock srclock{context->SourceLock}; + std::unique_lock srclock{context->SourceLock}; for(auto &sublist : context->SourceList) { uint64_t usemask = ~sublist.FreeMask; @@ -2513,9 +2513,6 @@ static ALvoid InitContext(ALCcontext *Context) struct ALeffectslotArray *auxslots; //Validate Context - almtx_init(&Context->SourceLock, almtx_plain); - almtx_init(&Context->EffectSlotLock, almtx_plain); - if(Context->DefaultSlot) { auxslots = static_cast(al_calloc(DEF_ALIGN, @@ -2596,7 +2593,6 @@ ALCcontext_struct::~ALCcontext_struct() WARN(SZFMT " Source%s not deleted\n", count, (count==1)?"":"s"); SourceList.clear(); NumSources = 0; - almtx_destroy(&SourceLock); count = 0; struct ALeffectslotProps *eprops{FreeEffectslotProps.load(std::memory_order_acquire)}; @@ -2616,7 +2612,6 @@ ALCcontext_struct::~ALCcontext_struct() if(count > 0) WARN(SZFMT " AuxiliaryEffectSlot%s not deleted\n", count, (count==1)?"":"s"); EffectSlotList.clear(); - almtx_destroy(&EffectSlotLock); count = 0; struct ALvoiceProps *vprops{FreeVoiceProps.load(std::memory_order_acquire)}; diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 0b285bfb..426d06e8 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -66,10 +66,10 @@ struct ALCcontext_struct { al::vector SourceList; ALuint NumSources{0}; - almtx_t SourceLock; + std::mutex SourceLock; al::vector EffectSlotList; - almtx_t EffectSlotLock; + std::mutex EffectSlotLock; std::atomic LastError{AL_NO_ERROR}; diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index 539329a7..d8c5076a 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -189,7 +189,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Generating %d effect slots", n); if(n == 0) return; - std::unique_lock slotlock{context->EffectSlotLock}; + std::unique_lock slotlock{context->EffectSlotLock}; ALCdevice *device{context->Device}; for(ALsizei cur{0};cur < n;cur++) { @@ -240,7 +240,7 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Deleting %d effect slots", n); if(n == 0) return; - std::lock_guard _{context->EffectSlotLock}; + std::lock_guard _{context->EffectSlotLock}; auto effectslots_end = effectslots + n; auto bad_slot = std::find_if(effectslots, effectslots_end, [&context](ALuint id) -> bool @@ -275,7 +275,7 @@ AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot) ContextRef context{GetContextRef()}; if(LIKELY(context)) { - std::lock_guard _{context->EffectSlotLock}; + std::lock_guard _{context->EffectSlotLock}; if(LookupEffectSlot(context.get(), effectslot) != nullptr) return AL_TRUE; } @@ -288,7 +288,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param if(UNLIKELY(!context)) return; std::lock_guard _{context->PropLock}; - std::lock_guard __{context->EffectSlotLock}; + std::lock_guard __{context->EffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); @@ -340,7 +340,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum para ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard __{context->EffectSlotLock}; + std::lock_guard _{context->EffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); @@ -359,7 +359,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param if(UNLIKELY(!context)) return; std::lock_guard _{context->PropLock}; - std::lock_guard __{context->EffectSlotLock}; + std::lock_guard __{context->EffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); @@ -391,7 +391,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum para ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->EffectSlotLock}; + std::lock_guard _{context->EffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); @@ -409,7 +409,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum pa ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard __{context->EffectSlotLock}; + std::lock_guard _{context->EffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); @@ -439,7 +439,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum p ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->EffectSlotLock}; + std::lock_guard _{context->EffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); @@ -457,7 +457,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum pa ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->EffectSlotLock}; + std::lock_guard _{context->EffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); @@ -486,7 +486,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum p ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->EffectSlotLock}; + std::lock_guard _{context->EffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); @@ -647,7 +647,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) void UpdateAllEffectSlotProps(ALCcontext *context) { - std::lock_guard _{context->EffectSlotLock}; + std::lock_guard _{context->EffectSlotLock}; ALeffectslotArray *auxslots{context->ActiveAuxSlots.load(std::memory_order_acquire)}; for(ALsizei i{0};i < auxslots->count;i++) { diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index bbcd318e..2370487f 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -458,7 +458,7 @@ ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) ALsource *AllocSource(ALCcontext *context) { ALCdevice *device{context->Device}; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->SourceLock}; if(context->NumSources >= device->SourcesMax) { alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax); @@ -1207,7 +1207,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co ALfilter *filter{nullptr}; ALeffectslot *slot{nullptr}; ALbufferlistitem *oldlist{nullptr}; - std::unique_lock slotlock; + std::unique_lock slotlock; std::unique_lock filtlock; std::unique_lock buflock; ALfloat fvals[6]; @@ -1419,7 +1419,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co case AL_AUXILIARY_SEND_FILTER: - slotlock = std::unique_lock{Context->EffectSlotLock}; + slotlock = std::unique_lock{Context->EffectSlotLock}; if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != nullptr)) SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid effect ID %u", values[0]); @@ -2145,7 +2145,7 @@ AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) if(n < 0) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Deleting %d sources", n); - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->SourceLock}; /* Check that all Sources are valid */ const ALuint *sources_end = sources + n; @@ -2179,7 +2179,7 @@ AL_API ALboolean AL_APIENTRY alIsSource(ALuint source) ContextRef context{GetContextRef()}; if(LIKELY(context)) { - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->SourceLock}; if(LookupSource(context.get(), source) != nullptr) return AL_TRUE; } @@ -2193,7 +2193,7 @@ AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) if(UNLIKELY(!context)) return; std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard __{context->SourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2209,7 +2209,7 @@ AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1 if(UNLIKELY(!context)) return; std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard __{context->SourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2228,7 +2228,7 @@ AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat if(UNLIKELY(!context)) return; std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard __{context->SourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2247,7 +2247,7 @@ AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble va if(UNLIKELY(!context)) return; std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard __{context->SourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2266,7 +2266,7 @@ AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble v if(UNLIKELY(!context)) return; std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard __{context->SourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2285,7 +2285,7 @@ AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdo if(UNLIKELY(!context)) return; std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard __{context->SourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2315,7 +2315,7 @@ AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) if(UNLIKELY(!context)) return; std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard __{context->SourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2331,7 +2331,7 @@ AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, AL if(UNLIKELY(!context)) return; std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard __{context->SourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2350,7 +2350,7 @@ AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *val if(UNLIKELY(!context)) return; std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard __{context->SourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2369,7 +2369,7 @@ AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SO if(UNLIKELY(!context)) return; std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard __{context->SourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2385,7 +2385,7 @@ AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOF if(UNLIKELY(!context)) return; std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard __{context->SourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2404,7 +2404,7 @@ AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALin if(UNLIKELY(!context)) return; std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard __{context->SourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2422,7 +2422,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *val ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->SourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2444,7 +2444,7 @@ AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *va ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->SourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2470,7 +2470,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *va ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->SourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2499,7 +2499,7 @@ AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble * ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->SourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2516,7 +2516,7 @@ AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->SourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2541,7 +2541,7 @@ AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->SourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2559,7 +2559,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->SourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2577,7 +2577,7 @@ AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1 ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->SourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2603,7 +2603,7 @@ AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->SourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2621,7 +2621,7 @@ AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64S ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->SourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2638,7 +2638,7 @@ AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64 ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->SourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2663,7 +2663,7 @@ AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64 ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->SourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2689,7 +2689,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Playing %d sources", n); if(n == 0) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->SourceLock}; for(ALsizei i{0};i < n;i++) { if(!LookupSource(context.get(), sources[i])) @@ -2980,7 +2980,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffers", nb); if(nb == 0) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->SourceLock}; ALsource *source{LookupSource(context.get(),src)}; if(!source) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); @@ -3097,7 +3097,7 @@ AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, co SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffer layers", nb); if(nb == 0) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->SourceLock}; ALsource *source{LookupSource(context.get(),src)}; if(!source) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); @@ -3205,7 +3205,7 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing %d buffers", nb); if(nb == 0) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->SourceLock}; ALsource *source{LookupSource(context.get(),src)}; if(!source) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); -- cgit v1.2.3 From 2d45ec8dc360cbdf9f813db0b8286d8e11a432d9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 22:06:53 -0800 Subject: Use a standard mutex for the remaining locks --- Alc/alc.cpp | 7 ------- OpenAL32/Include/alMain.h | 6 +++--- OpenAL32/alAuxEffectSlot.cpp | 2 +- OpenAL32/alBuffer.cpp | 48 +++++++++++++++++++------------------------- OpenAL32/alEffect.cpp | 28 +++++++++++--------------- OpenAL32/alFilter.cpp | 28 +++++++++++--------------- OpenAL32/alSource.cpp | 14 ++++++------- 7 files changed, 56 insertions(+), 77 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 0bb6fbf6..58b2349f 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2374,9 +2374,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ALCdevice_struct::ALCdevice_struct(DeviceType type) : Type{type} { - almtx_init(&BufferLock, almtx_plain); - almtx_init(&EffectLock, almtx_plain); - almtx_init(&FilterLock, almtx_plain); } /* ALCdevice_struct::~ALCdevice_struct @@ -2409,10 +2406,6 @@ ALCdevice_struct::~ALCdevice_struct() if(count > 0) WARN(SZFMT " Filter%s not deleted\n", count, (count==1)?"":"s"); - almtx_destroy(&BufferLock); - almtx_destroy(&EffectLock); - almtx_destroy(&FilterLock); - if(HrtfHandle) Hrtf_DecRef(HrtfHandle); HrtfHandle = nullptr; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 3643dd77..cf1cd6b2 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -700,15 +700,15 @@ struct ALCdevice_struct { // Map of Buffers for this device al::vector BufferList; - almtx_t BufferLock; + std::mutex BufferLock; // Map of Effects for this device al::vector EffectList; - almtx_t EffectLock; + std::mutex EffectLock; // Map of Filters for this device al::vector FilterList; - almtx_t FilterLock; + std::mutex FilterLock; POSTPROCESS PostProcess{}; diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index d8c5076a..663d99ba 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -300,7 +300,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param case AL_EFFECTSLOT_EFFECT: device = context->Device; - { std::lock_guard ___{device->EffectLock}; + { std::lock_guard ___{device->EffectLock}; ALeffect *effect{value ? LookupEffect(device, value) : nullptr}; if(!(value == 0 || effect != nullptr)) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Invalid effect ID %u", value); diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index 1b50f075..dbd48ad0 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -52,9 +52,8 @@ constexpr ALbitfieldSOFT INVALID_MAP_FLAGS{~unsigned(AL_MAP_READ_BIT_SOFT | AL_M ALbuffer *AllocBuffer(ALCcontext *context) { - ALCdevice *device = context->Device; - std::unique_lock buflock{device->BufferLock}; - + ALCdevice *device{context->Device}; + std::lock_guard _{device->BufferLock}; auto sublist = std::find_if(device->BufferList.begin(), device->BufferList.end(), [](const BufferSubList &entry) noexcept -> bool { return entry.FreeMask != 0; } @@ -75,7 +74,6 @@ ALbuffer *AllocBuffer(ALCcontext *context) */ if(UNLIKELY(device->BufferList.size() >= 1<<25)) { - buflock.unlock(); alSetError(context, AL_OUT_OF_MEMORY, "Too many buffers allocated"); return nullptr; } @@ -86,7 +84,6 @@ ALbuffer *AllocBuffer(ALCcontext *context) if(UNLIKELY(!sublist->Buffers)) { device->BufferList.pop_back(); - buflock.unlock(); alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate buffer batch"); return nullptr; } @@ -469,7 +466,7 @@ AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) return; ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; + std::lock_guard _{device->BufferLock}; /* First try to find any buffers that are invalid or in-use. */ const ALuint *buffers_end = buffers + n; @@ -510,7 +507,7 @@ AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer) if(LIKELY(context)) { ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; + std::lock_guard _{device->BufferLock}; if(!buffer || LookupBuffer(device, buffer)) return AL_TRUE; } @@ -527,7 +524,7 @@ AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const if(UNLIKELY(!context)) return; ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; + std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) @@ -562,7 +559,7 @@ AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei if(UNLIKELY(!context)) return nullptr; ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; + std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) @@ -612,7 +609,7 @@ AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer) if(UNLIKELY(!context)) return; ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; + std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) @@ -633,7 +630,7 @@ AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, A if(UNLIKELY(!context)) return; ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; + std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) @@ -663,7 +660,7 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons if(UNLIKELY(!context)) return; ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; + std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) @@ -787,7 +784,7 @@ AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(va if(UNLIKELY(!context)) return; ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; + std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); @@ -805,7 +802,7 @@ AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat UNUSED(v if(UNLIKELY(!context)) return; ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; + std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); @@ -823,7 +820,7 @@ AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *v if(UNLIKELY(!context)) return; ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; + std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); @@ -843,7 +840,7 @@ AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) if(UNLIKELY(!context)) return; ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; + std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) @@ -876,7 +873,7 @@ AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint UNUSED(val if(UNLIKELY(!context)) return; ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; + std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); @@ -905,7 +902,7 @@ AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *val if(UNLIKELY(!context)) return; ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; + std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) @@ -941,7 +938,7 @@ AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *val if(UNLIKELY(!context)) return; ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; + std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) @@ -962,7 +959,7 @@ AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *valu if(UNLIKELY(!context)) return; ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; + std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); @@ -989,7 +986,7 @@ AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *valu if(UNLIKELY(!context)) return; ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; + std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); @@ -1009,8 +1006,7 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value if(UNLIKELY(!context)) return; ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - + std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); @@ -1055,8 +1051,7 @@ AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1 if(UNLIKELY(!context)) return; ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - + std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!value1 || !value2 || !value3)) @@ -1090,8 +1085,7 @@ AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values if(UNLIKELY(!context)) return; ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - + std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); diff --git a/OpenAL32/alEffect.cpp b/OpenAL32/alEffect.cpp index 7f479c83..1c08d402 100644 --- a/OpenAL32/alEffect.cpp +++ b/OpenAL32/alEffect.cpp @@ -209,9 +209,8 @@ void InitEffectParams(ALeffect *effect, ALenum type) ALeffect *AllocEffect(ALCcontext *context) { - ALCdevice *device = context->Device; - almtx_lock(&device->EffectLock); - + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; auto sublist = std::find_if(device->EffectList.begin(), device->EffectList.end(), [](const EffectSubList &entry) noexcept -> bool { return entry.FreeMask != 0; } @@ -232,7 +231,6 @@ ALeffect *AllocEffect(ALCcontext *context) */ if(UNLIKELY(device->EffectList.size() >= 1<<25)) { - almtx_unlock(&device->EffectLock); alSetError(context, AL_OUT_OF_MEMORY, "Too many effects allocated"); return NULL; } @@ -243,7 +241,6 @@ ALeffect *AllocEffect(ALCcontext *context) if(UNLIKELY(!sublist->Effects)) { device->EffectList.pop_back(); - almtx_unlock(&device->EffectLock); alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect batch"); return NULL; } @@ -259,7 +256,6 @@ ALeffect *AllocEffect(ALCcontext *context) effect->id = ((lidx<<6) | slidx) + 1; sublist->FreeMask &= ~(U64(1)<EffectLock); return effect; } @@ -342,7 +338,7 @@ AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects) return; ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; + std::lock_guard _{device->EffectLock}; /* First try to find any effects that are invalid. */ const ALuint *effects_end = effects + n; @@ -378,7 +374,7 @@ AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect) if(LIKELY(context)) { ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; + std::lock_guard _{device->EffectLock}; if(!effect || LookupEffect(device, effect)) return AL_TRUE; } @@ -391,7 +387,7 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) if(UNLIKELY(!context)) return; ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; + std::lock_guard _{device->EffectLock}; ALeffect *aleffect{LookupEffect(device, effect)}; if(UNLIKELY(!aleffect)) @@ -433,7 +429,7 @@ AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *v if(UNLIKELY(!context)) return; ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; + std::lock_guard _{device->EffectLock}; ALeffect *aleffect{LookupEffect(device, effect)}; if(UNLIKELY(!aleffect)) @@ -451,7 +447,7 @@ AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value) if(UNLIKELY(!context)) return; ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; + std::lock_guard _{device->EffectLock}; ALeffect *aleffect{LookupEffect(device, effect)}; if(UNLIKELY(!aleffect)) @@ -469,7 +465,7 @@ AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat if(UNLIKELY(!context)) return; ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; + std::lock_guard _{device->EffectLock}; ALeffect *aleffect{LookupEffect(device, effect)}; if(UNLIKELY(!aleffect)) @@ -487,7 +483,7 @@ AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value if(UNLIKELY(!context)) return; ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; + std::lock_guard _{device->EffectLock}; const ALeffect *aleffect{LookupEffect(device, effect)}; if(UNLIKELY(!aleffect)) @@ -517,7 +513,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *valu if(UNLIKELY(!context)) return; ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; + std::lock_guard _{device->EffectLock}; const ALeffect *aleffect{LookupEffect(device, effect)}; if(UNLIKELY(!aleffect)) @@ -535,7 +531,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *val if(UNLIKELY(!context)) return; ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; + std::lock_guard _{device->EffectLock}; const ALeffect *aleffect{LookupEffect(device, effect)}; if(UNLIKELY(!aleffect)) @@ -553,7 +549,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *va if(UNLIKELY(!context)) return; ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; + std::lock_guard _{device->EffectLock}; const ALeffect *aleffect{LookupEffect(device, effect)}; if(UNLIKELY(!aleffect)) diff --git a/OpenAL32/alFilter.cpp b/OpenAL32/alFilter.cpp index 390432cb..52135569 100644 --- a/OpenAL32/alFilter.cpp +++ b/OpenAL32/alFilter.cpp @@ -269,9 +269,8 @@ void InitFilterParams(ALfilter *filter, ALenum type) ALfilter *AllocFilter(ALCcontext *context) { - ALCdevice *device = context->Device; - almtx_lock(&device->FilterLock); - + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; auto sublist = std::find_if(device->FilterList.begin(), device->FilterList.end(), [](const FilterSubList &entry) noexcept -> bool { return entry.FreeMask != 0; } @@ -292,7 +291,6 @@ ALfilter *AllocFilter(ALCcontext *context) */ if(UNLIKELY(device->FilterList.size() >= 1<<25)) { - almtx_unlock(&device->FilterLock); alSetError(context, AL_OUT_OF_MEMORY, "Too many filters allocated"); return NULL; } @@ -303,7 +301,6 @@ ALfilter *AllocFilter(ALCcontext *context) if(UNLIKELY(!sublist->Filters)) { device->FilterList.pop_back(); - almtx_unlock(&device->FilterLock); alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate filter batch"); return NULL; } @@ -319,7 +316,6 @@ ALfilter *AllocFilter(ALCcontext *context) filter->id = ((lidx<<6) | slidx) + 1; sublist->FreeMask &= ~(U64(1)<FilterLock); return filter; } @@ -403,7 +399,7 @@ AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) return; ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; + std::lock_guard _{device->FilterLock}; /* First try to find any filters that are invalid. */ const ALuint *filters_end = filters + n; @@ -439,7 +435,7 @@ AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter) if(LIKELY(context)) { ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; + std::lock_guard _{device->FilterLock}; if(!filter || LookupFilter(device, filter)) return AL_TRUE; } @@ -453,7 +449,7 @@ AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) if(UNLIKELY(!context)) return; ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; + std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; if(UNLIKELY(!alfilt)) @@ -489,7 +485,7 @@ AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *v if(UNLIKELY(!context)) return; ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; + std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; if(UNLIKELY(!alfilt)) @@ -507,7 +503,7 @@ AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value) if(UNLIKELY(!context)) return; ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; + std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; if(UNLIKELY(!alfilt)) @@ -525,7 +521,7 @@ AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat if(UNLIKELY(!context)) return; ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; + std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; if(UNLIKELY(!alfilt)) @@ -543,7 +539,7 @@ AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value if(UNLIKELY(!context)) return; ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; + std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; if(UNLIKELY(!alfilt)) @@ -573,7 +569,7 @@ AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *valu if(UNLIKELY(!context)) return; ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; + std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; if(UNLIKELY(!alfilt)) @@ -591,7 +587,7 @@ AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *val if(UNLIKELY(!context)) return; ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; + std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; if(UNLIKELY(!alfilt)) @@ -609,7 +605,7 @@ AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *va if(UNLIKELY(!context)) return; ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; + std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; if(UNLIKELY(!alfilt)) diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 2370487f..7cba253a 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -1208,8 +1208,8 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co ALeffectslot *slot{nullptr}; ALbufferlistitem *oldlist{nullptr}; std::unique_lock slotlock; - std::unique_lock filtlock; - std::unique_lock buflock; + std::unique_lock filtlock; + std::unique_lock buflock; ALfloat fvals[6]; switch(prop) @@ -1254,7 +1254,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co return AL_TRUE; case AL_BUFFER: - buflock = std::unique_lock{device->BufferLock}; + buflock = std::unique_lock{device->BufferLock}; if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != nullptr)) SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid buffer ID %u", *values); @@ -1336,7 +1336,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co return AL_TRUE; case AL_DIRECT_FILTER: - filtlock = std::unique_lock{device->FilterLock}; + filtlock = std::unique_lock{device->FilterLock}; if(!(*values == 0 || (filter=LookupFilter(device, *values)) != nullptr)) SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", *values); @@ -1426,7 +1426,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co if((ALuint)values[1] >= (ALuint)device->NumAuxSends) SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid send %u", values[1]); - filtlock = std::unique_lock{device->FilterLock}; + filtlock = std::unique_lock{device->FilterLock}; if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != nullptr)) SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", values[2]); @@ -3004,7 +3004,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu BufferList = BufferList->next.load(std::memory_order_relaxed); } - std::unique_lock buflock{device->BufferLock}; + std::unique_lock buflock{device->BufferLock}; ALbufferlistitem *BufferListStart{nullptr}; BufferList = nullptr; for(ALsizei i{0};i < nb;i++) @@ -3121,7 +3121,7 @@ AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, co BufferList = BufferList->next.load(std::memory_order_relaxed); } - std::unique_lock buflock{device->BufferLock}; + std::unique_lock buflock{device->BufferLock}; auto BufferListStart = static_cast(al_calloc(DEF_ALIGN, FAM_SIZE(ALbufferlistitem, buffers, nb))); BufferList = BufferListStart; -- cgit v1.2.3 From 4c1fc3ae00ad4890708a8789539eea4556b0634c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 22:36:55 -0800 Subject: Remove unused almtx stuff --- common/threads.cpp | 58 ------------------------------ common/threads.h | 101 ++--------------------------------------------------- 2 files changed, 2 insertions(+), 157 deletions(-) diff --git a/common/threads.cpp b/common/threads.cpp index 489e5f5b..b4f471d7 100644 --- a/common/threads.cpp +++ b/common/threads.cpp @@ -78,24 +78,6 @@ void althrd_setname(const char *name) } -int almtx_init(almtx_t *mtx, int type) -{ - if(!mtx) return althrd_error; - - type &= ~almtx_recursive; - if(type != almtx_plain) - return althrd_error; - - InitializeCriticalSection(mtx); - return althrd_success; -} - -void almtx_destroy(almtx_t *mtx) -{ - DeleteCriticalSection(mtx); -} - - int alsem_init(alsem_t *sem, unsigned int initial) { *sem = CreateSemaphore(NULL, initial, INT_MAX, NULL); @@ -158,46 +140,6 @@ void althrd_setname(const char *name) } -int almtx_init(almtx_t *mtx, int type) -{ - int ret; - - if(!mtx) return althrd_error; - if((type&~almtx_recursive) != 0) - return althrd_error; - - if(type == almtx_plain) - ret = pthread_mutex_init(mtx, NULL); - else - { - pthread_mutexattr_t attr; - - ret = pthread_mutexattr_init(&attr); - if(ret) return althrd_error; - - if(type == almtx_recursive) - { - ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); -#ifdef HAVE_PTHREAD_MUTEXATTR_SETKIND_NP - if(ret != 0) - ret = pthread_mutexattr_setkind_np(&attr, PTHREAD_MUTEX_RECURSIVE); -#endif - } - else - ret = 1; - if(ret == 0) - ret = pthread_mutex_init(mtx, &attr); - pthread_mutexattr_destroy(&attr); - } - return ret ? althrd_error : althrd_success; -} - -void almtx_destroy(almtx_t *mtx) -{ - pthread_mutex_destroy(mtx); -} - - #ifdef __APPLE__ int alsem_init(alsem_t *sem, unsigned int initial) diff --git a/common/threads.h b/common/threads.h index 53b56147..064b8482 100644 --- a/common/threads.h +++ b/common/threads.h @@ -14,6 +14,8 @@ #endif #ifdef __cplusplus +#include + extern "C" { #endif @@ -25,17 +27,11 @@ enum { althrd_busy }; -enum { - almtx_plain = 0, - almtx_recursive = 1, -}; - #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include -typedef CRITICAL_SECTION almtx_t; typedef HANDLE alsem_t; @@ -44,21 +40,6 @@ inline void althrd_yield(void) SwitchToThread(); } - -inline int almtx_lock(almtx_t *mtx) -{ - if(!mtx) return althrd_error; - EnterCriticalSection(mtx); - return althrd_success; -} - -inline int almtx_unlock(almtx_t *mtx) -{ - if(!mtx) return althrd_error; - LeaveCriticalSection(mtx); - return althrd_success; -} - #else #include @@ -70,7 +51,6 @@ inline int almtx_unlock(almtx_t *mtx) #include #endif /* __APPLE__ */ -typedef pthread_mutex_t almtx_t; #ifdef __APPLE__ typedef dispatch_semaphore_t alsem_t; #else /* !__APPLE__ */ @@ -84,27 +64,10 @@ inline void althrd_yield(void) } -inline int almtx_lock(almtx_t *mtx) -{ - if(pthread_mutex_lock(mtx) != 0) - return althrd_error; - return althrd_success; -} - -inline int almtx_unlock(almtx_t *mtx) -{ - if(pthread_mutex_unlock(mtx) != 0) - return althrd_error; - return althrd_success; -} - #endif void althrd_setname(const char *name); -int almtx_init(almtx_t *mtx, int type); -void almtx_destroy(almtx_t *mtx); - int alsem_init(alsem_t *sem, unsigned int initial); void alsem_destroy(alsem_t *sem); int alsem_post(alsem_t *sem); @@ -113,66 +76,6 @@ int alsem_trywait(alsem_t *sem); #ifdef __cplusplus } // extern "C" - -#include - -/* Add specializations for std::lock_guard and std::unique_lock which take an - * almtx_t and call the appropriate almtx_* functions. - */ -namespace std { - -template<> -class lock_guard { - almtx_t &mMtx; - -public: - using mutex_type = almtx_t; - - explicit lock_guard(almtx_t &mtx) : mMtx(mtx) { almtx_lock(&mMtx); } - lock_guard(almtx_t &mtx, std::adopt_lock_t) noexcept : mMtx(mtx) { } - ~lock_guard() { almtx_unlock(&mMtx); } - - lock_guard(const lock_guard&) = delete; - lock_guard& operator=(const lock_guard&) = delete; -}; - -template<> -class unique_lock { - almtx_t *mMtx{nullptr}; - bool mLocked{false}; - -public: - using mutex_type = almtx_t; - - unique_lock() noexcept = default; - explicit unique_lock(almtx_t &mtx) : mMtx(&mtx) { almtx_lock(mMtx); mLocked = true; } - unique_lock(unique_lock&& rhs) noexcept : mMtx(rhs.mMtx), mLocked(rhs.mLocked) - { rhs.mMtx = nullptr; rhs.mLocked = false; } - ~unique_lock() { if(mLocked) almtx_unlock(mMtx); } - - unique_lock& operator=(const unique_lock&) = delete; - unique_lock& operator=(unique_lock&& rhs) - { - if(mLocked) - almtx_unlock(mMtx); - mMtx = rhs.mMtx; rhs.mMtx = nullptr; - mLocked = rhs.mLocked; rhs.mLocked = false; - return *this; - } - - void lock() - { - almtx_lock(mMtx); - mLocked = true; - } - void unlock() - { - mLocked = false; - almtx_unlock(mMtx); - } -}; - -} // namespace std #endif #endif /* AL_THREADS_H */ -- cgit v1.2.3 From d06f76957c6ea2bf5311322e103946b45bde9796 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 23:06:49 -0800 Subject: Remove althrd_yield --- Alc/alc.cpp | 4 ++-- Alc/backends/base.cpp | 4 +++- Alc/backends/opensl.cpp | 2 +- OpenAL32/alAuxEffectSlot.cpp | 5 +++-- OpenAL32/alSource.cpp | 9 +++++---- OpenAL32/event.cpp | 2 +- common/threads.h | 13 ------------- 7 files changed, 15 insertions(+), 24 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 58b2349f..ba693616 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1624,7 +1624,7 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) */ context->HoldUpdates.store(AL_TRUE); while((context->UpdateCount.load(std::memory_order_acquire)&1) != 0) - althrd_yield(); + std::this_thread::yield(); if(!context->PropsClean.test_and_set(std::memory_order_acq_rel)) UpdateContextProps(context); @@ -3434,7 +3434,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALuint refcount; do { while(((refcount=ReadRef(&dev->MixCount))&1) != 0) - althrd_yield(); + std::this_thread::yield(); basecount = dev->ClockBase; samplecount = dev->SamplesDone; } while(refcount != ReadRef(&dev->MixCount)); diff --git a/Alc/backends/base.cpp b/Alc/backends/base.cpp index e4c7588c..85f4b034 100644 --- a/Alc/backends/base.cpp +++ b/Alc/backends/base.cpp @@ -3,6 +3,8 @@ #include +#include + #include "alMain.h" #include "alu.h" @@ -56,7 +58,7 @@ ClockLatency ALCbackend_getClockLatency(ALCbackend *self) do { while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) - althrd_yield(); + std::this_thread::yield(); ret.ClockTime = GetDeviceClockTime(device); std::atomic_thread_fence(std::memory_order_acquire); } while(refcount != device->MixCount.load(std::memory_order_relaxed)); diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 8cea36f3..e8d4a862 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -632,7 +632,7 @@ static void ALCopenslPlayback_stop(ALCopenslPlayback *self) { SLAndroidSimpleBufferQueueState state; do { - althrd_yield(); + std::this_thread::yield(); result = VCALL(bufferQueue,GetState)(&state); } while(SL_RESULT_SUCCESS == result && state.count > 0); PRINTERR(result, "bufferQueue->GetState"); diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index 663d99ba..7f05187e 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include "AL/al.h" @@ -108,7 +109,7 @@ void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *cont curarray = context->ActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); ALCdevice *device{context->Device}; while((device->MixCount.load(std::memory_order_acquire)&1)) - althrd_yield(); + std::this_thread::yield(); al_free(curarray); } @@ -136,7 +137,7 @@ void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *c curarray = context->ActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); ALCdevice *device{context->Device}; while((device->MixCount.load(std::memory_order_acquire)&1)) - althrd_yield(); + std::this_thread::yield(); al_free(curarray); } diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 7cba253a..d113ad40 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -159,7 +160,7 @@ ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, std::chrono Current = nullptr; readPos = 0; while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) - althrd_yield(); + std::this_thread::yield(); *clocktime = GetDeviceClockTime(device); voice = GetSourceVoice(Source, context); @@ -205,7 +206,7 @@ ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, std::chrono:: Current = nullptr; readPos = 0; while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) - althrd_yield(); + std::this_thread::yield(); *clocktime = GetDeviceClockTime(device); voice = GetSourceVoice(Source, context); @@ -266,7 +267,7 @@ ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) Current = nullptr; readPos = readPosFrac = 0; while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) - althrd_yield(); + std::this_thread::yield(); voice = GetSourceVoice(Source, context); if(voice) { @@ -1248,7 +1249,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co * end. */ while((device->MixCount.load(std::memory_order_acquire)&1)) - althrd_yield(); + std::this_thread::yield(); } } return AL_TRUE; diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index 233794bd..a47787bd 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -65,7 +65,7 @@ void StopEventThrd(ALCcontext *ctx) { static constexpr AsyncEvent kill_evt = ASYNC_EVENT(EventType_KillThread); while(ll_ringbuffer_write(ctx->AsyncEvents, &kill_evt, 1) == 0) - althrd_yield(); + std::this_thread::yield(); alsem_post(&ctx->EventSem); if(ctx->EventThread.joinable()) ctx->EventThread.join(); diff --git a/common/threads.h b/common/threads.h index 064b8482..a357b494 100644 --- a/common/threads.h +++ b/common/threads.h @@ -34,12 +34,6 @@ enum { typedef HANDLE alsem_t; - -inline void althrd_yield(void) -{ - SwitchToThread(); -} - #else #include @@ -57,13 +51,6 @@ typedef dispatch_semaphore_t alsem_t; typedef sem_t alsem_t; #endif /* __APPLE__ */ - -inline void althrd_yield(void) -{ - sched_yield(); -} - - #endif void althrd_setname(const char *name); -- cgit v1.2.3 From d7d99adc915583416dd8c70491ec7fc4ac71a543 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 23:18:51 -0800 Subject: Avoid including threads.h in the example helpers --- examples/alrecord.c | 1 + examples/common/alhelpers.c | 1 + examples/common/alhelpers.h | 10 +++++----- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/alrecord.c b/examples/alrecord.c index f60a3055..30f5f792 100644 --- a/examples/alrecord.c +++ b/examples/alrecord.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "AL/al.h" diff --git a/examples/common/alhelpers.c b/examples/common/alhelpers.c index 657c10d3..6a583497 100644 --- a/examples/common/alhelpers.c +++ b/examples/common/alhelpers.c @@ -29,6 +29,7 @@ * channel configs and sample types. */ #include +#include #include #include "AL/al.h" diff --git a/examples/common/alhelpers.h b/examples/common/alhelpers.h index e3e638ac..14edf5d9 100644 --- a/examples/common/alhelpers.h +++ b/examples/common/alhelpers.h @@ -1,15 +1,15 @@ #ifndef ALHELPERS_H #define ALHELPERS_H +#include + #include "AL/alc.h" #include "AL/al.h" #include "AL/alext.h" -#include "threads.h" - #ifdef __cplusplus extern "C" { -#endif /* __cplusplus */ +#endif /* Some helper functions to get the name from the format enums. */ const char *FormatName(ALenum type); @@ -30,7 +30,7 @@ int altimespec_get(struct timespec *ts, int base); void al_nssleep(unsigned long nsec); #ifdef __cplusplus -} -#endif /* __cplusplus */ +} // extern "C" +#endif #endif /* ALHELPERS_H */ -- cgit v1.2.3 From 2530370ff29009fccad472c9e9194ebdd561a398 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Nov 2018 23:45:04 -0800 Subject: Avoid relying on struct timespec --- CMakeLists.txt | 7 ------ examples/almultireverb.c | 13 +++++----- examples/common/alhelpers.c | 61 ++++++++++++++++++++++----------------------- examples/common/alhelpers.h | 11 +------- 4 files changed, 37 insertions(+), 55 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 26476a67..c9f2e336 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -204,13 +204,6 @@ IF(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_REQUIRED_FLAGS "${OLD_REQUIRED_FLAGS}") ENDIF() -# Check if we have a proper timespec declaration -CHECK_STRUCT_HAS_MEMBER("struct timespec" tv_sec time.h HAVE_STRUCT_TIMESPEC) -IF(HAVE_STRUCT_TIMESPEC) - # Define it here so we don't have to include config.h for it - SET(CPP_DEFS ${CPP_DEFS} HAVE_STRUCT_TIMESPEC) -ENDIF() - # Some systems may need libatomic for C11 atomic functions to work SET(OLD_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) SET(CMAKE_REQUIRED_LIBRARIES ${OLD_REQUIRED_LIBRARIES} atomic) diff --git a/examples/almultireverb.c b/examples/almultireverb.c index a2587585..e512d399 100644 --- a/examples/almultireverb.c +++ b/examples/almultireverb.c @@ -452,7 +452,7 @@ int main(int argc, char **argv) EFX_REVERB_PRESET_CARPETEDHALLWAY, EFX_REVERB_PRESET_BATHROOM }; - struct timespec basetime; + unsigned int basetime; ALCdevice *device = NULL; ALCcontext *context = NULL; ALuint effects[2] = { 0, 0 }; @@ -633,14 +633,14 @@ int main(int argc, char **argv) assert(alGetError()==AL_NO_ERROR && "Failed to setup sound source"); /* Get the current time as the base for timing in the main loop. */ - altimespec_get(&basetime, AL_TIME_UTC); + basetime = altime_get(); loops = 0; printf("Transition %d of %d...\n", loops+1, MaxTransitions); /* Play the sound for a while. */ alSourcePlay(source); do { - struct timespec curtime; + unsigned int curtime; ALfloat timediff; /* Start a batch update, to ensure all changes apply simultaneously. */ @@ -649,9 +649,8 @@ int main(int argc, char **argv) /* Get the current time to track the amount of time that passed. * Convert the difference to seconds. */ - altimespec_get(&curtime, AL_TIME_UTC); - timediff = (ALfloat)(curtime.tv_sec - basetime.tv_sec); - timediff += (ALfloat)(curtime.tv_nsec - basetime.tv_nsec) / 1000000000.0f; + curtime = altime_get(); + timediff = (ALfloat)(curtime - basetime) / 1000.0f; /* Avoid negative time deltas, in case of non-monotonic clocks. */ if(timediff < 0.0f) @@ -669,7 +668,7 @@ int main(int argc, char **argv) * time to start a new cycle. */ timediff -= 8.0f; - basetime.tv_sec += 8; + basetime += 8000; } } diff --git a/examples/common/alhelpers.c b/examples/common/alhelpers.c index 6a583497..fec51e6b 100644 --- a/examples/common/alhelpers.c +++ b/examples/common/alhelpers.c @@ -28,6 +28,7 @@ * finding an appropriate buffer format, and getting readable strings for * channel configs and sample types. */ +#include #include #include #include @@ -123,22 +124,21 @@ const char *FormatName(ALenum format) #include #include -int altimespec_get(struct timespec *ts, int base) +unsigned int altime_get(void) { - if(base == AL_TIME_UTC) - { - union { - FILETIME ftime; - ULARGE_INTEGER ulint; - } systime; - GetSystemTimeAsFileTime(&systime.ftime); - /* FILETIME is in 100-nanosecond units, or 1/10th of a microsecond. */ - ts->tv_sec = systime.ulint.QuadPart/10000000; - ts->tv_nsec = (systime.ulint.QuadPart%10000000) * 100; - return base; - } - - return 0; + static unsigned int start_time = 0; + unsigned int cur_time; + union { + FILETIME ftime; + ULARGE_INTEGER ulint; + } systime; + GetSystemTimeAsFileTime(&systime.ftime); + /* FILETIME is in 100-nanosecond units, or 1/10th of a microsecond. */ + cur_time = (unsigned int)(systime.ulint.QuadPart/10000); + + if(!start_time) + start_time = cur_time; + return cur_time - start_time; } void al_nssleep(unsigned long nsec) @@ -151,27 +151,26 @@ void al_nssleep(unsigned long nsec) #include #include -int altimespec_get(struct timespec *ts, int base) +unsigned int altime_get(void) { - if(base == AL_TIME_UTC) - { - int ret; + static unsigned int start_time = 0u; + unsigned int cur_time; + #if _POSIX_TIMERS > 0 - ret = clock_gettime(CLOCK_REALTIME, ts); - if(ret == 0) return base; + struct timespec ts; + int ret = clock_gettime(CLOCK_REALTIME, ts); + if(ret != 0) return 0; + cur_time = ts.ts_sec*1000 + ts.ts_nsec/1000000; #else /* _POSIX_TIMERS > 0 */ - struct timeval tv; - ret = gettimeofday(&tv, NULL); - if(ret == 0) - { - ts->tv_sec = tv.tv_sec; - ts->tv_nsec = tv.tv_usec * 1000; - return base; - } + struct timeval tv; + int ret = gettimeofday(&tv, NULL); + if(ret != 0) return 0; + cur_time = tv.tv_sec*1000 + tv.tv_usec/1000; #endif - } - return 0; + if(!start_time) + start_time = cur_time; + return cur_time - start_time; } void al_nssleep(unsigned long nsec) diff --git a/examples/common/alhelpers.h b/examples/common/alhelpers.h index 14edf5d9..4193e86f 100644 --- a/examples/common/alhelpers.h +++ b/examples/common/alhelpers.h @@ -1,8 +1,6 @@ #ifndef ALHELPERS_H #define ALHELPERS_H -#include - #include "AL/alc.h" #include "AL/al.h" #include "AL/alext.h" @@ -19,14 +17,7 @@ int InitAL(char ***argv, int *argc); void CloseAL(void); /* Cross-platform timeget and sleep functions. */ -#ifndef HAVE_STRUCT_TIMESPEC -struct timespec { - time_t tv_sec; - long tv_nsec; -}; -#endif -#define AL_TIME_UTC 1 -int altimespec_get(struct timespec *ts, int base); +unsigned int altime_get(void); void al_nssleep(unsigned long nsec); #ifdef __cplusplus -- cgit v1.2.3 From 9b2b83f99c1349d68f15e36efe36566e9cbe582a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 27 Nov 2018 00:02:31 -0800 Subject: Fix use of clock_gettime --- examples/common/alhelpers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/common/alhelpers.c b/examples/common/alhelpers.c index fec51e6b..5d2c6536 100644 --- a/examples/common/alhelpers.c +++ b/examples/common/alhelpers.c @@ -158,9 +158,9 @@ unsigned int altime_get(void) #if _POSIX_TIMERS > 0 struct timespec ts; - int ret = clock_gettime(CLOCK_REALTIME, ts); + int ret = clock_gettime(CLOCK_REALTIME, &ts); if(ret != 0) return 0; - cur_time = ts.ts_sec*1000 + ts.ts_nsec/1000000; + cur_time = ts.tv_sec*1000 + ts.tv_nsec/1000000; #else /* _POSIX_TIMERS > 0 */ struct timeval tv; int ret = gettimeofday(&tv, NULL); -- cgit v1.2.3 From ee2d756d940ddd798290e1539a08167d05397f7f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 27 Nov 2018 00:04:55 -0800 Subject: Disable MSVC warning C4065 "switch statement contains 'default' but no 'case' labels" --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c9f2e336..04617d32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -244,7 +244,7 @@ ENDIF() IF(MSVC) SET(CPP_DEFS ${CPP_DEFS} _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE NOMINMAX) - SET(C_FLAGS ${C_FLAGS} /wd4098 /wd4200) + SET(C_FLAGS ${C_FLAGS} /wd4065 /wd4098 /wd4200) IF(NOT DXSDK_DIR) STRING(REGEX REPLACE "\\\\" "/" DXSDK_DIR "$ENV{DXSDK_DIR}") -- cgit v1.2.3 From 07670ed36aeb32e8a7da12110bed1003c46c704e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 27 Nov 2018 10:08:25 -0800 Subject: Swap context references in the move assignment --- Alc/alcontext.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 426d06e8..274888e0 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -168,12 +168,7 @@ public: ContextRef& operator=(const ContextRef&) = delete; ContextRef& operator=(ContextRef&& rhs) noexcept - { - reset(); - mCtx = rhs.mCtx; - rhs.mCtx = nullptr; - return *this; - } + { std::swap(mCtx, rhs.mCtx); return *this; } operator bool() const noexcept { return mCtx != nullptr; } -- cgit v1.2.3 From ff6dda06ad66d71d4178bfa2aee282abe6c3ec23 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 27 Nov 2018 10:35:00 -0800 Subject: Add the appropriate include for the _POSIX_TIMERS macro --- examples/common/alhelpers.c | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/common/alhelpers.c b/examples/common/alhelpers.c index 5d2c6536..c8f0bb37 100644 --- a/examples/common/alhelpers.c +++ b/examples/common/alhelpers.c @@ -149,6 +149,7 @@ void al_nssleep(unsigned long nsec) #else #include +#include #include unsigned int altime_get(void) -- cgit v1.2.3 From 3f745be1dc4df7ffeec89f1d90af41e139fb49db Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 27 Nov 2018 10:41:07 -0800 Subject: Return a signed integer from altime_get --- examples/almultireverb.c | 4 ++-- examples/common/alhelpers.c | 14 +++++++------- examples/common/alhelpers.h | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/almultireverb.c b/examples/almultireverb.c index e512d399..f1b1872f 100644 --- a/examples/almultireverb.c +++ b/examples/almultireverb.c @@ -452,7 +452,6 @@ int main(int argc, char **argv) EFX_REVERB_PRESET_CARPETEDHALLWAY, EFX_REVERB_PRESET_BATHROOM }; - unsigned int basetime; ALCdevice *device = NULL; ALCcontext *context = NULL; ALuint effects[2] = { 0, 0 }; @@ -463,6 +462,7 @@ int main(int argc, char **argv) ALCint num_sends = 0; ALenum state = AL_INITIAL; ALfloat direct_gain = 1.0f; + int basetime = 0; int loops = 0; /* Print out usage if no arguments were specified */ @@ -640,7 +640,7 @@ int main(int argc, char **argv) /* Play the sound for a while. */ alSourcePlay(source); do { - unsigned int curtime; + int curtime; ALfloat timediff; /* Start a batch update, to ensure all changes apply simultaneously. */ diff --git a/examples/common/alhelpers.c b/examples/common/alhelpers.c index c8f0bb37..3077d0b7 100644 --- a/examples/common/alhelpers.c +++ b/examples/common/alhelpers.c @@ -124,17 +124,17 @@ const char *FormatName(ALenum format) #include #include -unsigned int altime_get(void) +int altime_get(void) { - static unsigned int start_time = 0; - unsigned int cur_time; + static int start_time = 0; + int cur_time; union { FILETIME ftime; ULARGE_INTEGER ulint; } systime; GetSystemTimeAsFileTime(&systime.ftime); /* FILETIME is in 100-nanosecond units, or 1/10th of a microsecond. */ - cur_time = (unsigned int)(systime.ulint.QuadPart/10000); + cur_time = (int)(systime.ulint.QuadPart/10000); if(!start_time) start_time = cur_time; @@ -152,10 +152,10 @@ void al_nssleep(unsigned long nsec) #include #include -unsigned int altime_get(void) +int altime_get(void) { - static unsigned int start_time = 0u; - unsigned int cur_time; + static int start_time = 0u; + int cur_time; #if _POSIX_TIMERS > 0 struct timespec ts; diff --git a/examples/common/alhelpers.h b/examples/common/alhelpers.h index 4193e86f..5caeda38 100644 --- a/examples/common/alhelpers.h +++ b/examples/common/alhelpers.h @@ -17,7 +17,7 @@ int InitAL(char ***argv, int *argc); void CloseAL(void); /* Cross-platform timeget and sleep functions. */ -unsigned int altime_get(void); +int altime_get(void); void al_nssleep(unsigned long nsec); #ifdef __cplusplus -- cgit v1.2.3 From f26083e9edc6491f553aae951886d89b70288528 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 27 Nov 2018 13:41:30 -0800 Subject: Make and use a semaphore class --- Alc/alc.cpp | 3 --- Alc/alcontext.h | 2 +- Alc/alu.cpp | 6 +++--- Alc/mixvoice.cpp | 2 +- OpenAL32/alSource.cpp | 2 +- OpenAL32/event.cpp | 4 ++-- common/threads.cpp | 50 +++++++++++++++++++++++++++++++------------------- common/threads.h | 20 ++++++++++++++++++++ 8 files changed, 59 insertions(+), 30 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index ba693616..59ff2306 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2528,7 +2528,6 @@ static ALvoid InitContext(ALCcontext *Context) Context->DopplerVelocity = 1.0f; Context->SpeedOfSound = SPEEDOFSOUNDMETRESPERSEC; Context->MetersPerUnit = AL_DEFAULT_METERS_PER_UNIT; - alsem_init(&Context->EventSem, 0); Context->ExtensionList = alExtList; @@ -2642,8 +2641,6 @@ ALCcontext_struct::~ALCcontext_struct() } TRACE("Freed " SZFMT " listener property object%s\n", count, (count==1)?"":"s"); - alsem_destroy(&EventSem); - ll_ringbuffer_free(AsyncEvents); AsyncEvents = nullptr; diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 274888e0..7b7688ac 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -111,7 +111,7 @@ struct ALCcontext_struct { std::atomic ActiveAuxSlots{nullptr}; std::thread EventThread; - alsem_t EventSem; + al::semaphore EventSem; ll_ringbuffer *AsyncEvents{nullptr}; std::atomic EnabledEvts{0u}; std::mutex EventCbLock; diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 5036ae24..c7ed0878 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -313,7 +313,7 @@ void SendSourceStoppedEvent(ALCcontext *context, ALuint id) strcpy(evt.u.user.msg+strpos, " state changed to AL_STOPPED"); if(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) == 1) - alsem_post(&context->EventSem); + context->EventSem.post(); } @@ -441,7 +441,7 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) props->State = NULL; if(LIKELY(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) != 0)) - alsem_post(&context->EventSem); + context->EventSem.post(); else { /* If writing the event failed, the queue was probably full. @@ -1857,7 +1857,7 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) ALbitfieldSOFT enabledevt = ctx->EnabledEvts.load(std::memory_order_acquire); if((enabledevt&EventType_Disconnected) && ll_ringbuffer_write(ctx->AsyncEvents, &evt, 1) == 1) - alsem_post(&ctx->EventSem); + ctx->EventSem.post(); std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire), [ctx](ALvoice *voice) -> void diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 86de61ee..1aa3000b 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -204,7 +204,7 @@ static void SendAsyncEvent(ALCcontext *context, ALuint enumtype, ALenum type, evt.u.user.param = param; strcpy(evt.u.user.msg, msg); if(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) == 1) - alsem_post(&context->EventSem); + context->EventSem.post(); } diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index d113ad40..a60701e7 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -705,7 +705,7 @@ void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) * it through the async queue to ensure proper ordering. */ if(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) == 1) - alsem_post(&context->EventSem); + context->EventSem.post(); } diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index a47787bd..b7599a02 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -23,7 +23,7 @@ static int EventThread(ALCcontext *context) AsyncEvent evt; if(ll_ringbuffer_read(context->AsyncEvents, &evt, 1) == 0) { - alsem_wait(&context->EventSem); + context->EventSem.wait(); continue; } @@ -66,7 +66,7 @@ void StopEventThrd(ALCcontext *ctx) static constexpr AsyncEvent kill_evt = ASYNC_EVENT(EventType_KillThread); while(ll_ringbuffer_write(ctx->AsyncEvents, &kill_evt, 1) == 0) std::this_thread::yield(); - alsem_post(&ctx->EventSem); + ctx->EventSem.post(); if(ctx->EventThread.joinable()) ctx->EventThread.join(); } diff --git a/common/threads.cpp b/common/threads.cpp index b4f471d7..c9478871 100644 --- a/common/threads.cpp +++ b/common/threads.cpp @@ -22,25 +22,7 @@ #include "threads.h" -#include -#include -#include - - -#ifndef UNUSED -#if defined(__cplusplus) -#define UNUSED(x) -#elif defined(__GNUC__) -#define UNUSED(x) UNUSED_##x __attribute__((unused)) -#elif defined(__LCLINT__) -#define UNUSED(x) /*@unused@*/ x -#else -#define UNUSED(x) x -#endif -#endif - - -#define THREAD_STACK_SIZE (2*1024*1024) /* 2MB */ +#include #ifdef _WIN32 @@ -116,6 +98,7 @@ int alsem_trywait(alsem_t *sem) #include #include +#include #include #ifdef HAVE_PTHREAD_NP_H #include @@ -210,3 +193,32 @@ int alsem_trywait(alsem_t *sem) #endif /* __APPLE__ */ #endif + + +namespace al { + +semaphore::semaphore(unsigned int initial) +{ + if(alsem_init(&mSem, initial) != althrd_success) + throw std::system_error(std::make_error_code(std::errc::resource_unavailable_try_again)); +} + +semaphore::~semaphore() +{ alsem_destroy(&mSem); } + +void semaphore::post() +{ + if(alsem_post(&mSem) != althrd_success) + throw std::system_error(std::make_error_code(std::errc::value_too_large)); +} + +void semaphore::wait() noexcept +{ + while(alsem_wait(&mSem) == -2) { + } +} + +int semaphore::trywait() noexcept +{ return alsem_wait(&mSem) == althrd_success; } + +} // namespace al diff --git a/common/threads.h b/common/threads.h index a357b494..03a3899c 100644 --- a/common/threads.h +++ b/common/threads.h @@ -63,6 +63,26 @@ int alsem_trywait(alsem_t *sem); #ifdef __cplusplus } // extern "C" + +namespace al { + +class semaphore { + alsem_t mSem; + +public: + semaphore(unsigned int initial=0); + semaphore(const semaphore&) = delete; + ~semaphore(); + + semaphore& operator=(const semaphore&) = delete; + + void post(); + void wait() noexcept; + int trywait() noexcept; +}; + +} // namespace al + #endif #endif /* AL_THREADS_H */ -- cgit v1.2.3 From 89abbe8d94436376c1dc00f5af226a79fe3bc811 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 27 Nov 2018 14:05:56 -0800 Subject: Replace last uses of alsem_t with al::semaphore --- Alc/backends/jack.cpp | 12 ++++-------- Alc/backends/opensl.cpp | 12 ++++-------- Alc/backends/winmm.cpp | 22 ++++++++-------------- 3 files changed, 16 insertions(+), 30 deletions(-) diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index 0862f685..0679dd73 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -151,7 +151,7 @@ struct ALCjackPlayback final : public ALCbackend { jack_port_t *Port[MAX_OUTPUT_CHANNELS]{}; ll_ringbuffer_t *Ring{nullptr}; - alsem_t Sem; + al::semaphore Sem; std::atomic mKillNow{AL_TRUE}; std::thread mThread; @@ -183,8 +183,6 @@ static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device) new (self) ALCjackPlayback{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCjackPlayback, ALCbackend, self); - - alsem_init(&self->Sem, 0); } static void ALCjackPlayback_Destruct(ALCjackPlayback *self) @@ -201,8 +199,6 @@ static void ALCjackPlayback_Destruct(ALCjackPlayback *self) self->Client = NULL; } - alsem_destroy(&self->Sem); - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCjackPlayback(); } @@ -278,7 +274,7 @@ static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) } ll_ringbuffer_read_advance(self->Ring, total); - alsem_post(&self->Sem); + self->Sem.post(); if(numframes > total) { @@ -309,7 +305,7 @@ static int ALCjackPlayback_mixerProc(ALCjackPlayback *self) if(ll_ringbuffer_write_space(self->Ring) < device->UpdateSize) { ALCjackPlayback_unlock(self); - alsem_wait(&self->Sem); + self->Sem.wait(); ALCjackPlayback_lock(self); continue; } @@ -485,7 +481,7 @@ static void ALCjackPlayback_stop(ALCjackPlayback *self) if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->mThread.joinable()) return; - alsem_post(&self->Sem); + self->Sem.post(); self->mThread.join(); jack_deactivate(self->Client); diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index e8d4a862..c2acda3a 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -146,7 +146,7 @@ struct ALCopenslPlayback final : public ALCbackend { SLObjectItf mBufferQueueObj{nullptr}; ll_ringbuffer_t *mRing{nullptr}; - alsem_t mSem; + al::semaphore mSem; ALsizei mFrameSize{0}; @@ -178,8 +178,6 @@ static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *devi new (self) ALCopenslPlayback{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCopenslPlayback, ALCbackend, self); - - alsem_init(&self->mSem, 0); } static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self) @@ -200,8 +198,6 @@ static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self) ll_ringbuffer_free(self->mRing); self->mRing = NULL; - alsem_destroy(&self->mSem); - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCopenslPlayback(); } @@ -222,7 +218,7 @@ static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), */ ll_ringbuffer_read_advance(self->mRing, 1); - alsem_post(&self->mSem); + self->mSem.post(); } @@ -274,7 +270,7 @@ static int ALCopenslPlayback_mixerProc(ALCopenslPlayback *self) if(ll_ringbuffer_write_space(self->mRing) == 0) { ALCopenslPlayback_unlock(self); - alsem_wait(&self->mSem); + self->mSem.wait(); ALCopenslPlayback_lock(self); continue; } @@ -604,7 +600,7 @@ static void ALCopenslPlayback_stop(ALCopenslPlayback *self) if(self->mKillNow.exchange(AL_TRUE) || !self->mThread.joinable()) return; - alsem_post(&self->mSem); + self->mSem.post(); self->mThread.join(); result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player); diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 2524ecc1..c88a43b6 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -122,7 +122,7 @@ void ProbeCaptureDevices(void) struct ALCwinmmPlayback final : public ALCbackend { std::atomic Writable{0u}; - alsem_t Sem; + al::semaphore Sem; int Idx{0}; std::array WaveBuffer; @@ -160,7 +160,6 @@ void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device) ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCwinmmPlayback, ALCbackend, self); - alsem_init(&self->Sem, 0); std::fill(self->WaveBuffer.begin(), self->WaveBuffer.end(), WAVEHDR{}); } @@ -173,8 +172,6 @@ void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self) al_free(self->WaveBuffer[0].lpData); std::fill(self->WaveBuffer.begin(), self->WaveBuffer.end(), WAVEHDR{}); - alsem_destroy(&self->Sem); - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCwinmmPlayback(); } @@ -194,7 +191,7 @@ void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT UNUSED(device), UINT msg, auto self = reinterpret_cast(instance); self->Writable.fetch_add(1, std::memory_order_acq_rel); - alsem_post(&self->Sem); + self->Sem.post(); } FORCE_ALIGN int ALCwinmmPlayback_mixerProc(ALCwinmmPlayback *self) @@ -212,7 +209,7 @@ FORCE_ALIGN int ALCwinmmPlayback_mixerProc(ALCwinmmPlayback *self) if(todo < 1) { ALCwinmmPlayback_unlock(self); - alsem_wait(&self->Sem); + self->Sem.wait(); ALCwinmmPlayback_lock(self); continue; } @@ -387,7 +384,7 @@ void ALCwinmmPlayback_stop(ALCwinmmPlayback *self) self->mThread.join(); while(self->Writable.load(std::memory_order_acquire) < self->WaveBuffer.size()) - alsem_wait(&self->Sem); + self->Sem.wait(); std::for_each(self->WaveBuffer.begin(), self->WaveBuffer.end(), [self](WAVEHDR &waveHdr) -> void { waveOutUnprepareHeader(self->OutHdl, &waveHdr, sizeof(WAVEHDR)); } @@ -398,7 +395,7 @@ void ALCwinmmPlayback_stop(ALCwinmmPlayback *self) struct ALCwinmmCapture final : public ALCbackend { std::atomic Readable{0u}; - alsem_t Sem; + al::semaphore Sem; int Idx{0}; std::array WaveBuffer; @@ -438,7 +435,6 @@ void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device) ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCwinmmCapture, ALCbackend, self); - alsem_init(&self->Sem, 0); std::fill(self->WaveBuffer.begin(), self->WaveBuffer.end(), WAVEHDR{}); } @@ -455,8 +451,6 @@ void ALCwinmmCapture_Destruct(ALCwinmmCapture *self) ll_ringbuffer_free(self->Ring); self->Ring = nullptr; - alsem_destroy(&self->Sem); - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCwinmmCapture(); } @@ -476,7 +470,7 @@ void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN UNUSED(device), UINT msg, auto self = reinterpret_cast(instance); self->Readable.fetch_add(1, std::memory_order_acq_rel); - alsem_post(&self->Sem); + self->Sem.post(); } int ALCwinmmCapture_captureProc(ALCwinmmCapture *self) @@ -493,7 +487,7 @@ int ALCwinmmCapture_captureProc(ALCwinmmCapture *self) if(todo < 1) { ALCwinmmCapture_unlock(self); - alsem_wait(&self->Sem); + self->Sem.wait(); ALCwinmmCapture_lock(self); continue; } @@ -639,7 +633,7 @@ void ALCwinmmCapture_stop(ALCwinmmCapture *self) self->mKillNow.store(AL_TRUE, std::memory_order_release); if(self->mThread.joinable()) { - alsem_post(&self->Sem); + self->Sem.post(); self->mThread.join(); } -- cgit v1.2.3 From c2da83dea86f57e3095a704ef1f9c7b01852cd03 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 27 Nov 2018 14:50:41 -0800 Subject: Avoid alsem* wrappers for al::semaphore --- common/threads.cpp | 143 ++++++++++++++++------------------------------------- common/threads.h | 57 +++++---------------- 2 files changed, 54 insertions(+), 146 deletions(-) diff --git a/common/threads.cpp b/common/threads.cpp index c9478871..eaf2cbbc 100644 --- a/common/threads.cpp +++ b/common/threads.cpp @@ -22,14 +22,11 @@ #include "threads.h" +#include #include -#ifdef _WIN32 - -#define WIN32_LEAN_AND_MEAN -#include -#include +#ifdef _WIN32 void althrd_setname(const char *name) { @@ -59,52 +56,42 @@ void althrd_setname(const char *name) #endif } +namespace al { -int alsem_init(alsem_t *sem, unsigned int initial) +semaphore::semaphore(unsigned int initial) { - *sem = CreateSemaphore(NULL, initial, INT_MAX, NULL); - if(*sem != NULL) return althrd_success; - return althrd_error; + if(initial > static_cast(std::numeric_limits::max())) + throw std::system_error(std::make_error_code(std::errc::value_too_large)); + mSem = CreateSemaphore(nullptr, initial, std::numeric_limits::max(), nullptr); + if(mSem == nullptr) + throw std::system_error(std::make_error_code(std::errc::resource_unavailable_try_again)); } -void alsem_destroy(alsem_t *sem) -{ - CloseHandle(*sem); -} +semaphore::~semaphore() +{ CloseHandle(mSem); } -int alsem_post(alsem_t *sem) +void semaphore::post() { - DWORD ret = ReleaseSemaphore(*sem, 1, NULL); - if(ret) return althrd_success; - return althrd_error; + if(!ReleaseSemaphore(mSem, 1, nullptr)) + throw std::system_error(std::make_error_code(std::errc::value_too_large)); } -int alsem_wait(alsem_t *sem) -{ - DWORD ret = WaitForSingleObject(*sem, INFINITE); - if(ret == WAIT_OBJECT_0) return althrd_success; - return althrd_error; -} +void semaphore::wait() noexcept +{ WaitForSingleObject(mSem, INFINITE); } -int alsem_trywait(alsem_t *sem) -{ - DWORD ret = WaitForSingleObject(*sem, 0); - if(ret == WAIT_OBJECT_0) return althrd_success; - if(ret == WAIT_TIMEOUT) return althrd_busy; - return althrd_error; -} +int semaphore::trywait() noexcept +{ return WaitForSingleObject(mSem, 0) == WAIT_OBJECT_0; } + +} // namespace al #else -#include -#include #include #include #ifdef HAVE_PTHREAD_NP_H #include #endif - void althrd_setname(const char *name) { #if defined(HAVE_PTHREAD_SETNAME_NP) @@ -122,103 +109,57 @@ void althrd_setname(const char *name) #endif } +namespace al { #ifdef __APPLE__ -int alsem_init(alsem_t *sem, unsigned int initial) +semaphore::semaphore(unsigned int initial) { - *sem = dispatch_semaphore_create(initial); - return *sem ? althrd_success : althrd_error; + mSem = dispatch_semaphore_create(initial); + if(!mSem) + throw std::system_error(std::make_error_code(std::errc::resource_unavailable_try_again)); } -void alsem_destroy(alsem_t *sem) -{ - dispatch_release(*sem); -} +semaphore::~semaphore() +{ dispatch_release(mSem); } -int alsem_post(alsem_t *sem) -{ - dispatch_semaphore_signal(*sem); - return althrd_success; -} +void semaphore::post() +{ dispatch_semaphore_signal(mSem); } -int alsem_wait(alsem_t *sem) -{ - dispatch_semaphore_wait(*sem, DISPATCH_TIME_FOREVER); - return althrd_success; -} +void semaphore::wait() noexcept +{ dispatch_semaphore_wait(mSem, DISPATCH_TIME_FOREVER); } -int alsem_trywait(alsem_t *sem) -{ - long value = dispatch_semaphore_wait(*sem, DISPATCH_TIME_NOW); - return value == 0 ? althrd_success : althrd_busy; -} +int semaphore::trywait() noexcept +{ return dispatch_semaphore_wait(mSem, DISPATCH_TIME_NOW) == 0; } #else /* !__APPLE__ */ -int alsem_init(alsem_t *sem, unsigned int initial) -{ - if(sem_init(sem, 0, initial) == 0) - return althrd_success; - return althrd_error; -} - -void alsem_destroy(alsem_t *sem) -{ - sem_destroy(sem); -} - -int alsem_post(alsem_t *sem) -{ - if(sem_post(sem) == 0) - return althrd_success; - return althrd_error; -} - -int alsem_wait(alsem_t *sem) -{ - if(sem_wait(sem) == 0) return althrd_success; - if(errno == EINTR) return -2; - return althrd_error; -} - -int alsem_trywait(alsem_t *sem) -{ - if(sem_trywait(sem) == 0) return althrd_success; - if(errno == EWOULDBLOCK) return althrd_busy; - if(errno == EINTR) return -2; - return althrd_error; -} - -#endif /* __APPLE__ */ - -#endif - - -namespace al { - semaphore::semaphore(unsigned int initial) { - if(alsem_init(&mSem, initial) != althrd_success) + if(sem_init(&mSem, 0, initial) != 0) throw std::system_error(std::make_error_code(std::errc::resource_unavailable_try_again)); } semaphore::~semaphore() -{ alsem_destroy(&mSem); } +{ sem_destroy(&mSem); } void semaphore::post() { - if(alsem_post(&mSem) != althrd_success) + if(sem_post(&mSem) != 0) throw std::system_error(std::make_error_code(std::errc::value_too_large)); } void semaphore::wait() noexcept { - while(alsem_wait(&mSem) == -2) { + while(sem_wait(&mSem) == -1 && errno == EINTR) { } } int semaphore::trywait() noexcept -{ return alsem_wait(&mSem) == althrd_success; } +{ return sem_trywait(&mSem) == 0; } + +#endif /* __APPLE__ */ } // namespace al + +#endif /* _WIN32 */ diff --git a/common/threads.h b/common/threads.h index 03a3899c..7eb2d608 100644 --- a/common/threads.h +++ b/common/threads.h @@ -3,6 +3,8 @@ #include +#include + #if defined(__GNUC__) && defined(__i386__) /* force_align_arg_pointer is required for proper function arguments aligning * when SSE code is used. Some systems (Windows, QNX) do not guarantee our @@ -13,61 +15,28 @@ #define FORCE_ALIGN #endif -#ifdef __cplusplus -#include - -extern "C" { -#endif - -enum { - althrd_success = 0, - althrd_error, - althrd_nomem, - althrd_timedout, - althrd_busy -}; - - #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include - -typedef HANDLE alsem_t; - -#else - -#include -#include -#include -#ifdef __APPLE__ +#elif defined(__APPLE__) #include -#else /* !__APPLE__ */ +#else #include -#endif /* __APPLE__ */ - -#ifdef __APPLE__ -typedef dispatch_semaphore_t alsem_t; -#else /* !__APPLE__ */ -typedef sem_t alsem_t; -#endif /* __APPLE__ */ - #endif void althrd_setname(const char *name); -int alsem_init(alsem_t *sem, unsigned int initial); -void alsem_destroy(alsem_t *sem); -int alsem_post(alsem_t *sem); -int alsem_wait(alsem_t *sem); -int alsem_trywait(alsem_t *sem); - -#ifdef __cplusplus -} // extern "C" - namespace al { class semaphore { - alsem_t mSem; +#ifdef _WIN32 + using native_type = HANDLE; +#elif defined(__APPLE__) + using native_type = dispatch_semaphore_t; +#else + using native_type = sem_t; +#endif + native_type mSem; public: semaphore(unsigned int initial=0); @@ -83,6 +52,4 @@ public: } // namespace al -#endif - #endif /* AL_THREADS_H */ -- cgit v1.2.3 From 21793884303edc4d5702b5a5fcd88a45c954028b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 27 Nov 2018 15:23:18 -0800 Subject: Remove unneeded mutex checks --- CMakeLists.txt | 4 ---- config.h.in | 6 ------ 2 files changed, 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 04617d32..71e20eec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -636,7 +636,6 @@ int main() PTHREAD_SETNAME_NP_THREE_PARAMS ) ENDIF() - CHECK_SYMBOL_EXISTS(pthread_mutexattr_setkind_np "pthread.h;pthread_np.h" HAVE_PTHREAD_MUTEXATTR_SETKIND_NP) ELSE() CHECK_SYMBOL_EXISTS(pthread_setname_np pthread.h HAVE_PTHREAD_SETNAME_NP) IF(NOT HAVE_PTHREAD_SETNAME_NP) @@ -661,11 +660,8 @@ int main() PTHREAD_SETNAME_NP_THREE_PARAMS ) ENDIF() - CHECK_SYMBOL_EXISTS(pthread_mutexattr_setkind_np pthread.h HAVE_PTHREAD_MUTEXATTR_SETKIND_NP) ENDIF() - CHECK_SYMBOL_EXISTS(pthread_mutex_timedlock pthread.h HAVE_PTHREAD_MUTEX_TIMEDLOCK) - CHECK_LIBRARY_EXISTS(rt clock_gettime "" HAVE_LIBRT) IF(HAVE_LIBRT) SET(EXTRA_LIBS rt ${EXTRA_LIBS}) diff --git a/config.h.in b/config.h.in index 6c83b7f5..4c68e77f 100644 --- a/config.h.in +++ b/config.h.in @@ -178,9 +178,3 @@ /* Define if we have pthread_set_name_np() */ #cmakedefine HAVE_PTHREAD_SET_NAME_NP - -/* Define if we have pthread_mutexattr_setkind_np() */ -#cmakedefine HAVE_PTHREAD_MUTEXATTR_SETKIND_NP - -/* Define if we have pthread_mutex_timedlock() */ -#cmakedefine HAVE_PTHREAD_MUTEX_TIMEDLOCK -- cgit v1.2.3 From 0116e763ea22538b6cac2b78acc918185f54e2f9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 27 Nov 2018 19:49:45 -0800 Subject: Add a unique_ptr alias for the ringbuffer --- Alc/ringbuffer.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Alc/ringbuffer.h b/Alc/ringbuffer.h index b516ab57..cb2077f8 100644 --- a/Alc/ringbuffer.h +++ b/Alc/ringbuffer.h @@ -3,6 +3,7 @@ #include +#include #include @@ -72,4 +73,11 @@ size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const void *src, size_t cnt); /** Advance the write pointer `cnt' places. */ void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt); + +struct RingBufferDeleter { + void operator()(ll_ringbuffer_t *ring) const + { ll_ringbuffer_free(ring); } +}; +using RingBufferPtr = std::unique_ptr; + #endif /* RINGBUFFER_H */ -- cgit v1.2.3 From ff8c6949576b40d11c3cb4276390d355d1b0231f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 27 Nov 2018 20:28:58 -0800 Subject: Clean up the JACK backend --- Alc/backends/jack.cpp | 355 ++++++++++++++++++++++++++------------------------ 1 file changed, 186 insertions(+), 169 deletions(-) diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index 0679dd73..d141f991 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -39,7 +39,9 @@ #include -static const ALCchar jackDevice[] = "JACK Default"; +namespace { + +constexpr ALCchar jackDevice[] = "JACK Default"; #ifdef HAVE_DYNLOAD @@ -64,10 +66,10 @@ static const ALCchar jackDevice[] = "JACK Default"; MAGIC(jack_set_buffer_size); \ MAGIC(jack_get_buffer_size); -static void *jack_handle; -#define MAKE_FUNC(f) static decltype(f) * p##f +void *jack_handle; +#define MAKE_FUNC(f) decltype(f) * p##f JACK_FUNCS(MAKE_FUNC); -static decltype(jack_error_callback) * pjack_error_callback; +decltype(jack_error_callback) * pjack_error_callback; #undef MAKE_FUNC #ifndef IN_IDE_PARSER @@ -95,9 +97,9 @@ static decltype(jack_error_callback) * pjack_error_callback; #endif -static jack_options_t ClientOptions = JackNullOption; +jack_options_t ClientOptions = JackNullOption; -static ALCboolean jack_load(void) +ALCboolean jack_load(void) { ALCboolean error = ALC_FALSE; @@ -137,7 +139,7 @@ static ALCboolean jack_load(void) { WARN("Missing expected functions:%s\n", missing_funcs.c_str()); CloseLib(jack_handle); - jack_handle = NULL; + jack_handle = nullptr; } } #endif @@ -147,56 +149,55 @@ static ALCboolean jack_load(void) struct ALCjackPlayback final : public ALCbackend { - jack_client_t *Client{nullptr}; - jack_port_t *Port[MAX_OUTPUT_CHANNELS]{}; + jack_client_t *mClient{nullptr}; + jack_port_t *mPort[MAX_OUTPUT_CHANNELS]{}; - ll_ringbuffer_t *Ring{nullptr}; - al::semaphore Sem; + RingBufferPtr mRing; + al::semaphore mSem; - std::atomic mKillNow{AL_TRUE}; + std::atomic mKillNow{true}; std::thread mThread; }; -static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg); - -static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg); -static int ALCjackPlayback_mixerProc(ALCjackPlayback *self); - -static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device); -static void ALCjackPlayback_Destruct(ALCjackPlayback *self); -static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name); -static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self); -static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self); -static void ALCjackPlayback_stop(ALCjackPlayback *self); -static DECLARE_FORWARD2(ALCjackPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, ALCuint, availableSamples) -static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self); -static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, unlock) +int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg); + +int ALCjackPlayback_process(jack_nframes_t numframes, void *arg); +int ALCjackPlayback_mixerProc(ALCjackPlayback *self); + +void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device); +void ALCjackPlayback_Destruct(ALCjackPlayback *self); +ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name); +ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self); +ALCboolean ALCjackPlayback_start(ALCjackPlayback *self); +void ALCjackPlayback_stop(ALCjackPlayback *self); +DECLARE_FORWARD2(ALCjackPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +DECLARE_FORWARD(ALCjackPlayback, ALCbackend, ALCuint, availableSamples) +ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self); +DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, lock) +DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCjackPlayback) DEFINE_ALCBACKEND_VTABLE(ALCjackPlayback); -static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device) +void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device) { new (self) ALCjackPlayback{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCjackPlayback, ALCbackend, self); } -static void ALCjackPlayback_Destruct(ALCjackPlayback *self) +void ALCjackPlayback_Destruct(ALCjackPlayback *self) { - if(self->Client) + if(self->mClient) { - for(ALsizei i{0};i < MAX_OUTPUT_CHANNELS;i++) - { - if(self->Port[i]) - jack_port_unregister(self->Client, self->Port[i]); - self->Port[i] = NULL; - } - jack_client_close(self->Client); - self->Client = NULL; + std::for_each(std::begin(self->mPort), std::end(self->mPort), + [self](jack_port_t *port) -> void + { if(port) jack_port_unregister(self->mClient, port); } + ); + std::fill(std::begin(self->mPort), std::end(self->mPort), nullptr); + jack_client_close(self->mClient); + self->mClient = nullptr; } ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); @@ -204,29 +205,28 @@ static void ALCjackPlayback_Destruct(ALCjackPlayback *self) } -static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg) +int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg) { - ALCjackPlayback *self = static_cast(arg); - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - ALuint bufsize; + auto self = static_cast(arg); + ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; ALCjackPlayback_lock(self); device->UpdateSize = numframes; device->NumUpdates = 2; - bufsize = device->UpdateSize; + ALuint bufsize{device->UpdateSize}; if(ConfigValueUInt(device->DeviceName.c_str(), "jack", "buffer-size", &bufsize)) bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize; TRACE("%u update size x%u\n", device->UpdateSize, device->NumUpdates); - ll_ringbuffer_free(self->Ring); - self->Ring = ll_ringbuffer_create(bufsize, + self->mRing = nullptr; + self->mRing.reset(ll_ringbuffer_create(bufsize, FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder), true - ); - if(!self->Ring) + )); + if(!self->mRing) { ERR("Failed to reallocate ringbuffer\n"); aluHandleDisconnect(device, "Failed to reallocate %u-sample buffer", bufsize); @@ -236,62 +236,81 @@ static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg) } -static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) +int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) { - ALCjackPlayback *self = static_cast(arg); - jack_default_audio_sample_t *out[MAX_OUTPUT_CHANNELS]; - jack_nframes_t total{0}; - jack_nframes_t todo; - ALsizei i, c, numchans; - - auto data = ll_ringbuffer_get_read_vector(self->Ring); + auto self = static_cast(arg); - for(c = 0;c < MAX_OUTPUT_CHANNELS && self->Port[c];c++) - out[c] = static_cast(jack_port_get_buffer(self->Port[c], numframes)); - numchans = c; - - todo = minu(numframes, data.first.len); - for(c = 0;c < numchans;c++) + jack_default_audio_sample_t *out[MAX_OUTPUT_CHANNELS]; + ALsizei numchans{0}; + for(auto port : self->mPort) { - const ALfloat *RESTRICT in = ((ALfloat*)data.first.buf) + c; - for(i = 0;(jack_nframes_t)i < todo;i++) - out[c][i] = in[i*numchans]; - out[c] += todo; + if(!port) break; + out[numchans++] = static_cast(jack_port_get_buffer(port, numframes)); } - total += todo; + + auto data = ll_ringbuffer_get_read_vector(self->mRing.get()); + jack_nframes_t todo{minu(numframes, data.first.len)}; + std::transform(out, out+numchans, out, + [&data,numchans,todo](ALfloat *outbuf) -> ALfloat* + { + const ALfloat *RESTRICT in = reinterpret_cast(data.first.buf); + std::generate_n(outbuf, todo, + [&in,numchans]() noexcept -> ALfloat + { + ALfloat ret{*in}; + in += numchans; + return ret; + } + ); + data.first.buf += sizeof(ALfloat); + return outbuf + todo; + } + ); + jack_nframes_t total{todo}; todo = minu(numframes-total, data.second.len); if(todo > 0) { - for(c = 0;c < numchans;c++) - { - const ALfloat *RESTRICT in = ((ALfloat*)data.second.buf) + c; - for(i = 0;(jack_nframes_t)i < todo;i++) - out[c][i] = in[i*numchans]; - out[c] += todo; - } + std::transform(out, out+numchans, out, + [&data,numchans,todo](ALfloat *outbuf) -> ALfloat* + { + const ALfloat *RESTRICT in = reinterpret_cast(data.second.buf); + std::generate_n(outbuf, todo, + [&in,numchans]() noexcept -> ALfloat + { + ALfloat ret{*in}; + in += numchans; + return ret; + } + ); + data.second.buf += sizeof(ALfloat); + return outbuf + todo; + } + ); total += todo; } - ll_ringbuffer_read_advance(self->Ring, total); - self->Sem.post(); + ll_ringbuffer_read_advance(self->mRing.get(), total); + self->mSem.post(); if(numframes > total) { todo = numframes-total; - for(c = 0;c < numchans;c++) - { - for(i = 0;(jack_nframes_t)i < todo;i++) - out[c][i] = 0.0f; - } + std::transform(out, out+numchans, out, + [todo](ALfloat *outbuf) -> ALfloat* + { + std::fill_n(outbuf, todo, 0.0f); + return outbuf + todo; + } + ); } return 0; } -static int ALCjackPlayback_mixerProc(ALCjackPlayback *self) +int ALCjackPlayback_mixerProc(ALCjackPlayback *self) { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); @@ -300,27 +319,25 @@ static int ALCjackPlayback_mixerProc(ALCjackPlayback *self) while(!self->mKillNow.load(std::memory_order_acquire) && device->Connected.load(std::memory_order_acquire)) { - ALuint todo, len1, len2; - - if(ll_ringbuffer_write_space(self->Ring) < device->UpdateSize) + if(ll_ringbuffer_write_space(self->mRing.get()) < device->UpdateSize) { ALCjackPlayback_unlock(self); - self->Sem.wait(); + self->mSem.wait(); ALCjackPlayback_lock(self); continue; } - auto data = ll_ringbuffer_get_write_vector(self->Ring); - todo = data.first.len + data.second.len; + auto data = ll_ringbuffer_get_write_vector(self->mRing.get()); + auto todo = static_cast(data.first.len + data.second.len); todo -= todo%device->UpdateSize; - len1 = minu(data.first.len, todo); - len2 = minu(data.second.len, todo-len1); + ALuint len1{minu(data.first.len, todo)}; + ALuint len2{minu(data.second.len, todo-len1)}; aluMixData(device, data.first.buf, len1); if(len2 > 0) aluMixData(device, data.second.buf, len2); - ll_ringbuffer_write_advance(self->Ring, todo); + ll_ringbuffer_write_advance(self->mRing.get(), todo); } ALCjackPlayback_unlock(self); @@ -328,19 +345,17 @@ static int ALCjackPlayback_mixerProc(ALCjackPlayback *self) } -static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name) +ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - const char *client_name = "alsoft"; - jack_status_t status; - if(!name) name = jackDevice; else if(strcmp(name, jackDevice) != 0) return ALC_INVALID_VALUE; - self->Client = jack_client_open(client_name, ClientOptions, &status, NULL); - if(self->Client == NULL) + const char *client_name{"alsoft"}; + jack_status_t status; + self->mClient = jack_client_open(client_name, ClientOptions, &status, nullptr); + if(self->mClient == nullptr) { ERR("jack_client_open() failed, status = 0x%02x\n", status); return ALC_INVALID_VALUE; @@ -349,38 +364,35 @@ static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name) TRACE("JACK server started\n"); if((status&JackNameNotUnique)) { - client_name = jack_get_client_name(self->Client); + client_name = jack_get_client_name(self->mClient); TRACE("Client name not unique, got `%s' instead\n", client_name); } - jack_set_process_callback(self->Client, ALCjackPlayback_process, self); - jack_set_buffer_size_callback(self->Client, ALCjackPlayback_bufferSizeNotify, self); + jack_set_process_callback(self->mClient, ALCjackPlayback_process, self); + jack_set_buffer_size_callback(self->mClient, ALCjackPlayback_bufferSizeNotify, self); + ALCdevice *device{self->mDevice}; device->DeviceName = name; return ALC_NO_ERROR; } -static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) +ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ALsizei numchans, i; - ALuint bufsize; - - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - { - if(self->Port[i]) - jack_port_unregister(self->Client, self->Port[i]); - self->Port[i] = NULL; - } + std::for_each(std::begin(self->mPort), std::end(self->mPort), + [self](jack_port_t *port) -> void + { if(port) jack_port_unregister(self->mClient, port); } + ); + std::fill(std::begin(self->mPort), std::end(self->mPort), nullptr); /* Ignore the requested buffer metrics and just keep one JACK-sized buffer * ready for when requested. */ - device->Frequency = jack_get_sample_rate(self->Client); - device->UpdateSize = jack_get_buffer_size(self->Client); + ALCdevice *device{self->mDevice}; + device->Frequency = jack_get_sample_rate(self->mClient); + device->UpdateSize = jack_get_buffer_size(self->mClient); device->NumUpdates = 2; - bufsize = device->UpdateSize; + ALuint bufsize{device->UpdateSize}; if(ConfigValueUInt(device->DeviceName.c_str(), "jack", "buffer-size", &bufsize)) bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize; @@ -388,40 +400,43 @@ static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) /* Force 32-bit float output. */ device->FmtType = DevFmtFloat; - numchans = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); - for(i = 0;i < numchans;i++) - { - char name[64]; - snprintf(name, sizeof(name), "channel_%d", i+1); - self->Port[i] = jack_port_register(self->Client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); - if(self->Port[i] == NULL) + ALsizei numchans{ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder)}; + auto ports_end = std::begin(self->mPort) + numchans; + auto bad_port = std::find_if_not(std::begin(self->mPort), ports_end, + [self](jack_port_t *&port) -> bool { - ERR("Not enough JACK ports available for %s output\n", DevFmtChannelsString(device->FmtChans)); - if(i == 0) return ALC_FALSE; - break; + std::string name{"channel_" + std::to_string(&port - self->mPort + 1)}; + port = jack_port_register(self->mClient, name.c_str(), JACK_DEFAULT_AUDIO_TYPE, + JackPortIsOutput, 0); + return port != nullptr; } - } - if(i < numchans) + ); + if(bad_port != ports_end) { - if(i == 1) + ERR("Not enough JACK ports available for %s output\n", DevFmtChannelsString(device->FmtChans)); + if(bad_port == std::begin(self->mPort)) return ALC_FALSE; + + if(bad_port == std::begin(self->mPort)+1) device->FmtChans = DevFmtMono; else { - for(--i;i >= 2;i--) + ports_end = self->mPort+2; + while(bad_port != ports_end) { - jack_port_unregister(self->Client, self->Port[i]); - self->Port[i] = NULL; + jack_port_unregister(self->mClient, *(--bad_port)); + *bad_port = nullptr; } device->FmtChans = DevFmtStereo; } + numchans = std::distance(std::begin(self->mPort), bad_port); } - ll_ringbuffer_free(self->Ring); - self->Ring = ll_ringbuffer_create(bufsize, + self->mRing = nullptr; + self->mRing.reset(ll_ringbuffer_create(bufsize, FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder), true - ); - if(!self->Ring) + )); + if(!self->mRing) { ERR("Failed to allocate ringbuffer\n"); return ALC_FALSE; @@ -432,38 +447,41 @@ static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) return ALC_TRUE; } -static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self) +ALCboolean ALCjackPlayback_start(ALCjackPlayback *self) { - const char **ports; - ALsizei i; - - if(jack_activate(self->Client)) + if(jack_activate(self->mClient)) { ERR("Failed to activate client\n"); return ALC_FALSE; } - ports = jack_get_ports(self->Client, NULL, NULL, JackPortIsPhysical|JackPortIsInput); - if(ports == NULL) + const char **ports{jack_get_ports(self->mClient, nullptr, nullptr, + JackPortIsPhysical|JackPortIsInput)}; + if(ports == nullptr) { ERR("No physical playback ports found\n"); - jack_deactivate(self->Client); + jack_deactivate(self->mClient); return ALC_FALSE; } - for(i = 0;i < MAX_OUTPUT_CHANNELS && self->Port[i];i++) - { - if(!ports[i]) + std::mismatch(std::begin(self->mPort), std::end(self->mPort), ports, + [self](const jack_port_t *port, const char *pname) -> bool { - ERR("No physical playback port for \"%s\"\n", jack_port_name(self->Port[i])); - break; + if(!port) return false; + if(!pname) + { + ERR("No physical playback port for \"%s\"\n", jack_port_name(port)); + return false; + } + if(jack_connect(self->mClient, jack_port_name(port), pname)) + ERR("Failed to connect output port \"%s\" to \"%s\"\n", jack_port_name(port), + pname); + return true; } - if(jack_connect(self->Client, jack_port_name(self->Port[i]), ports[i])) - ERR("Failed to connect output port \"%s\" to \"%s\"\n", jack_port_name(self->Port[i]), ports[i]); - } + ); jack_free(ports); try { - self->mKillNow.store(AL_FALSE, std::memory_order_release); + self->mKillNow.store(false, std::memory_order_release); self->mThread = std::thread(ALCjackPlayback_mixerProc, self); return ALC_TRUE; } @@ -472,30 +490,30 @@ static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self) } catch(...) { } - jack_deactivate(self->Client); + jack_deactivate(self->mClient); return ALC_FALSE; } -static void ALCjackPlayback_stop(ALCjackPlayback *self) +void ALCjackPlayback_stop(ALCjackPlayback *self) { - if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->mThread.joinable()) + if(self->mKillNow.exchange(true, std::memory_order_acq_rel) || !self->mThread.joinable()) return; - self->Sem.post(); + self->mSem.post(); self->mThread.join(); - jack_deactivate(self->Client); + jack_deactivate(self->mClient); } -static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self) +ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; ClockLatency ret; ALCjackPlayback_lock(self); + ALCdevice *device{self->mDevice}; ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = std::chrono::seconds{ll_ringbuffer_read_space(self->Ring)}; + ret.Latency = std::chrono::seconds{ll_ringbuffer_read_space(self->mRing.get())}; ret.Latency /= device->Frequency; ALCjackPlayback_unlock(self); @@ -503,26 +521,25 @@ static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self) } -static void jack_msg_handler(const char *message) +void jack_msg_handler(const char *message) { WARN("%s\n", message); } +} // namespace + bool JackBackendFactory::init() { - void (*old_error_cb)(const char*); - jack_client_t *client; - jack_status_t status; - if(!jack_load()) return false; - if(!GetConfigValueBool(NULL, "jack", "spawn-server", 0)) + if(!GetConfigValueBool(nullptr, "jack", "spawn-server", 0)) ClientOptions = static_cast(ClientOptions | JackNoStartServer); - old_error_cb = (&jack_error_callback ? jack_error_callback : NULL); + void (*old_error_cb)(const char*){&jack_error_callback ? jack_error_callback : nullptr}; jack_set_error_function(jack_msg_handler); - client = jack_client_open("alsoft", ClientOptions, &status, NULL); + jack_status_t status; + jack_client_t *client{jack_client_open("alsoft", ClientOptions, &status, nullptr)}; jack_set_error_function(old_error_cb); if(!client) { -- cgit v1.2.3 From ec2927cd32a1d3a48da81947d611ace6d8361dca Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 27 Nov 2018 21:19:30 -0800 Subject: Small cleanup for ~ALCcontext_struct --- Alc/alc.cpp | 34 +++++++++++++++++----------------- Alc/alu.cpp | 2 +- OpenAL32/Include/alu.h | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 59ff2306..3d636354 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2558,26 +2558,23 @@ ALCcontext_struct::~ALCcontext_struct() { TRACE("%p\n", this); - struct ALcontextProps *cprops{Update.load(std::memory_order_relaxed)}; + ALcontextProps *cprops{Update.exchange(nullptr, std::memory_order_relaxed)}; if(cprops) { TRACE("Freed unapplied context update %p\n", cprops); al_free(cprops); } size_t count{0}; - cprops = FreeContextProps.load(std::memory_order_acquire); + cprops = FreeContextProps.exchange(nullptr, std::memory_order_acquire); while(cprops) { - struct ALcontextProps *next{cprops->next.load(std::memory_order_relaxed)}; + ALcontextProps *next{cprops->next.load(std::memory_order_relaxed)}; al_free(cprops); cprops = next; ++count; } TRACE("Freed " SZFMT " context property object%s\n", count, (count==1)?"":"s"); - al_free(ActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed)); - DefaultSlot = nullptr; - count = 0; for(auto &sublist : SourceList) count += POPCNT64(~sublist.FreeMask); @@ -2587,10 +2584,10 @@ ALCcontext_struct::~ALCcontext_struct() NumSources = 0; count = 0; - struct ALeffectslotProps *eprops{FreeEffectslotProps.load(std::memory_order_acquire)}; + ALeffectslotProps *eprops{FreeEffectslotProps.exchange(nullptr, std::memory_order_acquire)}; while(eprops) { - struct ALeffectslotProps *next{eprops->next.load(std::memory_order_relaxed)}; + ALeffectslotProps *next{eprops->next.load(std::memory_order_relaxed)}; if(eprops->State) eprops->State->DecRef(); al_free(eprops); eprops = next; @@ -2598,18 +2595,21 @@ ALCcontext_struct::~ALCcontext_struct() } TRACE("Freed " SZFMT " AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s"); - count = 0; - for(auto &slot : EffectSlotList) - count += slot ? 1 : 0; + al_free(ActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed)); + DefaultSlot = nullptr; + + count = std::count_if(EffectSlotList.cbegin(), EffectSlotList.cend(), + [](const ALeffectslotPtr &slot) noexcept -> bool { return slot != nullptr; } + ); if(count > 0) WARN(SZFMT " AuxiliaryEffectSlot%s not deleted\n", count, (count==1)?"":"s"); EffectSlotList.clear(); count = 0; - struct ALvoiceProps *vprops{FreeVoiceProps.load(std::memory_order_acquire)}; + ALvoiceProps *vprops{FreeVoiceProps.exchange(nullptr, std::memory_order_acquire)}; while(vprops) { - struct ALvoiceProps *next{vprops->next.load(std::memory_order_relaxed)}; + ALvoiceProps *next{vprops->next.load(std::memory_order_relaxed)}; al_free(vprops); vprops = next; ++count; @@ -2617,24 +2617,24 @@ ALCcontext_struct::~ALCcontext_struct() TRACE("Freed " SZFMT " voice property object%s\n", count, (count==1)?"":"s"); std::for_each(Voices, Voices + VoiceCount.load(std::memory_order_relaxed), - [](ALvoice *voice) -> void { DeinitVoice(voice); } + [](ALvoice *voice) noexcept -> void { DeinitVoice(voice); } ); al_free(Voices); Voices = nullptr; VoiceCount.store(0, std::memory_order_relaxed); MaxVoices = 0; - struct ALlistenerProps *lprops{Listener.Update.load(std::memory_order_relaxed)}; + ALlistenerProps *lprops{Listener.Update.exchange(nullptr, std::memory_order_relaxed)}; if(lprops) { TRACE("Freed unapplied listener update %p\n", lprops); al_free(lprops); } count = 0; - lprops = FreeListenerProps.load(std::memory_order_acquire); + lprops = FreeListenerProps.exchange(nullptr, std::memory_order_acquire); while(lprops) { - struct ALlistenerProps *next{lprops->next.load(std::memory_order_relaxed)}; + ALlistenerProps *next{lprops->next.load(std::memory_order_relaxed)}; al_free(lprops); lprops = next; ++count; diff --git a/Alc/alu.cpp b/Alc/alu.cpp index c7ed0878..edf3249d 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -99,7 +99,7 @@ void aluInit(void) } -void DeinitVoice(ALvoice *voice) +void DeinitVoice(ALvoice *voice) noexcept { al_free(voice->Update.exchange(nullptr)); } diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index d51000c8..68f539f3 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -264,7 +264,7 @@ typedef struct ALvoice { } Send[]; } ALvoice; -void DeinitVoice(ALvoice *voice); +void DeinitVoice(ALvoice *voice) noexcept; typedef void (*MixerFunc)(const ALfloat *data, ALsizei OutChans, -- cgit v1.2.3 From 8d95b6a0f2cb9c2cbbe745e37ff1ba2589d6aa17 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 28 Nov 2018 08:42:30 -0800 Subject: Avoid an unnecessary lambda --- Alc/alc.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 3d636354..a0f61c8d 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2616,9 +2616,7 @@ ALCcontext_struct::~ALCcontext_struct() } TRACE("Freed " SZFMT " voice property object%s\n", count, (count==1)?"":"s"); - std::for_each(Voices, Voices + VoiceCount.load(std::memory_order_relaxed), - [](ALvoice *voice) noexcept -> void { DeinitVoice(voice); } - ); + std::for_each(Voices, Voices + VoiceCount.load(std::memory_order_relaxed), DeinitVoice); al_free(Voices); Voices = nullptr; VoiceCount.store(0, std::memory_order_relaxed); -- cgit v1.2.3 From ed2e456dfb6b0c11466a579142499767f7c80b73 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 28 Nov 2018 11:30:44 -0800 Subject: Avoid some explicit loops --- Alc/alc.cpp | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index a0f61c8d..9956adc0 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include "alMain.h" @@ -2388,21 +2389,24 @@ ALCdevice_struct::~ALCdevice_struct() DELETE_OBJ(Backend); Backend = nullptr; - size_t count{0u}; - for(auto &sublist : BufferList) - count += POPCNT64(~sublist.FreeMask); + size_t count{std::accumulate(BufferList.cbegin(), BufferList.cend(), size_t{0u}, + [](size_t cur, const BufferSubList &sublist) noexcept -> size_t + { return cur + POPCNT64(~sublist.FreeMask); } + )}; if(count > 0) WARN(SZFMT " Buffer%s not deleted\n", count, (count==1)?"":"s"); - count = 0; - for(auto &sublist : EffectList) - count += POPCNT64(~sublist.FreeMask); + count = std::accumulate(EffectList.cbegin(), EffectList.cend(), size_t{0u}, + [](size_t cur, const EffectSubList &sublist) noexcept -> size_t + { return cur + POPCNT64(~sublist.FreeMask); } + ); if(count > 0) WARN(SZFMT " Effect%s not deleted\n", count, (count==1)?"":"s"); - count = 0; - for(auto &sublist : FilterList) - count += POPCNT64(~sublist.FreeMask); + count = std::accumulate(FilterList.cbegin(), FilterList.cend(), size_t{0u}, + [](size_t cur, const FilterSubList &sublist) noexcept -> size_t + { return cur + POPCNT64(~sublist.FreeMask); } + ); if(count > 0) WARN(SZFMT " Filter%s not deleted\n", count, (count==1)?"":"s"); @@ -2575,9 +2579,10 @@ ALCcontext_struct::~ALCcontext_struct() } TRACE("Freed " SZFMT " context property object%s\n", count, (count==1)?"":"s"); - count = 0; - for(auto &sublist : SourceList) - count += POPCNT64(~sublist.FreeMask); + count = std::accumulate(SourceList.cbegin(), SourceList.cend(), size_t{0u}, + [](size_t cur, const SourceSubList &sublist) noexcept -> size_t + { return cur + POPCNT64(~sublist.FreeMask); } + ); if(count > 0) WARN(SZFMT " Source%s not deleted\n", count, (count==1)?"":"s"); SourceList.clear(); -- cgit v1.2.3 From 16aa3ab1962a4f77e79521ee344077c37e24bf4f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 28 Nov 2018 11:55:43 -0800 Subject: Reduce some indentation --- Alc/alc.cpp | 57 ++++++++++++++++++++++++++------------------------------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 9956adc0..6c522462 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -4315,27 +4315,27 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) { DeviceRef dev{VerifyDevice(device)}; if(!dev || dev->Type != Playback) + { alcSetError(dev.get(), ALC_INVALID_DEVICE); - else + return; + } + + std::lock_guard _{dev->BackendLock}; + if(!(dev->Flags&DEVICE_PAUSED)) + return; + dev->Flags &= ~DEVICE_PAUSED; + if(dev->ContextList.load() == nullptr) + return; + + if(V0(dev->Backend,start)() == ALC_FALSE) { - std::lock_guard _{dev->BackendLock}; - if((dev->Flags&DEVICE_PAUSED)) - { - dev->Flags &= ~DEVICE_PAUSED; - if(dev->ContextList.load() != nullptr) - { - if(V0(dev->Backend,start)() != ALC_FALSE) - dev->Flags |= DEVICE_RUNNING; - else - { - V0(dev->Backend,lock)(); - aluHandleDisconnect(dev.get(), "Device start failure"); - V0(dev->Backend,unlock)(); - alcSetError(dev.get(), ALC_INVALID_DEVICE); - } - } - } + V0(dev->Backend,lock)(); + aluHandleDisconnect(dev.get(), "Device start failure"); + V0(dev->Backend,unlock)(); + alcSetError(dev.get(), ALC_INVALID_DEVICE); + return; } + dev->Flags |= DEVICE_RUNNING; } @@ -4382,23 +4382,18 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi alcSetError(dev.get(), ALC_INVALID_DEVICE); return ALC_FALSE; } - std::unique_lock backlock{dev->BackendLock}; + std::lock_guard _{dev->BackendLock}; listlock.unlock(); ALCenum err{UpdateDeviceParams(dev.get(), attribs)}; - backlock.unlock(); + if(LIKELY(err == ALC_NO_ERROR)) return ALC_TRUE; - if(err != ALC_NO_ERROR) + alcSetError(dev.get(), err); + if(err == ALC_INVALID_DEVICE) { - alcSetError(dev.get(), err); - if(err == ALC_INVALID_DEVICE) - { - V0(dev->Backend,lock)(); - aluHandleDisconnect(dev.get(), "Device start failure"); - V0(dev->Backend,unlock)(); - } - return ALC_FALSE; + V0(dev->Backend,lock)(); + aluHandleDisconnect(dev.get(), "Device start failure"); + V0(dev->Backend,unlock)(); } - - return ALC_TRUE; + return ALC_FALSE; } -- cgit v1.2.3 From 598851fed7dfdd787de3487002afb13ed6e9dc82 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 28 Nov 2018 12:24:12 -0800 Subject: Attempt to reconnect lost devices with alcResetDeviceSOFT Be aware there's currently possible race conditions with PulseAudio's callbacks (the state callbacks need to be cleared while not playing). Also paused sources will assert/crash if attempted to play again without being explicitly stopped or rewound first. Both of these will eventually be fixed (though a paused source's offset will be lost regardless). --- Alc/alc.cpp | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 6c522462..8a4407aa 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -3102,7 +3102,9 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_CONNECTED: - values[0] = device->Connected.load(std::memory_order_acquire); + { std::lock_guard _{device->BackendLock}; + values[0] = device->Connected.load(std::memory_order_acquire); + } return 1; default: @@ -3289,7 +3291,9 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_CONNECTED: - values[0] = device->Connected.load(std::memory_order_acquire); + { std::lock_guard _{device->BackendLock}; + values[0] = device->Connected.load(std::memory_order_acquire); + } return 1; case ALC_HRTF_SOFT: @@ -3583,11 +3587,6 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin if((err=UpdateDeviceParams(dev.get(), attrList)) != ALC_NO_ERROR) { - backlock.unlock(); - - delete ALContext; - ALContext = nullptr; - alcSetError(dev.get(), err); if(err == ALC_INVALID_DEVICE) { @@ -3595,6 +3594,11 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin aluHandleDisconnect(dev.get(), "Device update failure"); V0(dev->Backend,unlock)(); } + backlock.unlock(); + + delete ALContext; + ALContext = nullptr; + return nullptr; } AllocateVoices(ALContext, 256, dev->NumAuxSends); @@ -4385,6 +4389,14 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi std::lock_guard _{dev->BackendLock}; listlock.unlock(); + /* Force the backend to stop mixing first since we're resetting. Also reset + * the connected state so lost devices can attempt recover. + */ + if((dev->Flags&DEVICE_RUNNING)) + V0(dev->Backend,stop)(); + dev->Flags &= ~DEVICE_RUNNING; + device->Connected.store(AL_TRUE); + ALCenum err{UpdateDeviceParams(dev.get(), attribs)}; if(LIKELY(err == ALC_NO_ERROR)) return ALC_TRUE; -- cgit v1.2.3 From 14d746e7c2614d17c5c00bf3ec8433bda1501638 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 28 Nov 2018 14:38:26 -0800 Subject: Don't sever a paused source from its voice on disconnect --- Alc/alu.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index edf3249d..ecf5f024 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1862,16 +1862,17 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire), [ctx](ALvoice *voice) -> void { - ALsource *source{voice->Source.exchange(nullptr, std::memory_order_relaxed)}; - if(source && voice->Playing.load(std::memory_order_relaxed)) - { - /* If the source's voice was playing, it's now effectively - * stopped (the source state will be updated the next time - * it's checked). - */ - SendSourceStoppedEvent(ctx, source->id); - } + ALsource *source{voice->Source.load(std::memory_order_relaxed)}; + if(!source || !voice->Playing.load(std::memory_order_relaxed)) + return; + + voice->Source.store(nullptr, std::memory_order_relaxed); voice->Playing.store(false, std::memory_order_release); + /* If the source's voice was playing, it's now effectively + * stopped (the source state will be updated the next time it's + * checked). + */ + SendSourceStoppedEvent(ctx, source->id); } ); -- cgit v1.2.3 From c3c0a5022a4b9d429c90cd7e6f3fc1bd284efd24 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 28 Nov 2018 15:09:19 -0800 Subject: Don't bother with (really) old pulseaudio headers --- Alc/backends/pulseaudio.cpp | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 51b7c0a9..b7dcd87c 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -39,7 +39,6 @@ #include -#if PA_API_VERSION == 12 namespace { @@ -1835,24 +1834,6 @@ ALCbackend *PulseBackendFactory::createBackend(ALCdevice *device, ALCbackend_Typ return nullptr; } - -#else /* PA_API_VERSION == 12 */ - -#warning "Unsupported API version, backend will be unavailable!" - -bool PulseBackendFactory::init() { return false; } - -void PulseBackendFactory::deinit() { } - -bool PulseBackendFactory::querySupport(ALCbackend_Type) { return false; } - -void PulseBackendFactory::probe(enum DevProbe, std::string*) { } - -ALCbackend *PulseBackendFactory::createBackend(ALCdevice*, ALCbackend_Type) -{ return nullptr; } - -#endif /* PA_API_VERSION == 12 */ - BackendFactory &PulseBackendFactory::getFactory() { static PulseBackendFactory factory{}; -- cgit v1.2.3 From 38f4a0cf2c7ffc359f88594a7728b275f7158636 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 28 Nov 2018 18:45:35 -0800 Subject: Avoid the update size going to 0 with a relatively large device period --- Alc/backends/wasapi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 3d6c3e8c..dfc91489 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -1040,7 +1040,7 @@ HRESULT ALCwasapiPlayback::resetProxy() min_len = (UINT32)ScaleCeil(min_per, device->Frequency, REFTIME_PER_SEC); /* 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; + min_len *= maxu((device->UpdateSize + min_len/2) / min_len, 1u); hr = mClient->GetBufferSize(&buffer_len); } if(FAILED(hr)) -- cgit v1.2.3 From 5df89c504e875fc956567a357dff2611772a95c0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 28 Nov 2018 19:29:20 -0800 Subject: Remove an improper Connected check --- Alc/alc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 8a4407aa..aa786244 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -4380,7 +4380,7 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi { std::unique_lock listlock{ListLock}; DeviceRef dev{VerifyDevice(device)}; - if(!dev || dev->Type == Capture || !dev->Connected.load(std::memory_order_relaxed)) + if(!dev || dev->Type == Capture) { listlock.unlock(); alcSetError(dev.get(), ALC_INVALID_DEVICE); -- cgit v1.2.3 From e017d9e40f4ce1698d31adc2d2a6ac4f13159a39 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 28 Nov 2018 22:42:46 -0800 Subject: Clean up the converter a bit --- Alc/converter.cpp | 120 +++++++++++++++++++++++++----------------------------- Alc/converter.h | 5 +++ 2 files changed, 61 insertions(+), 64 deletions(-) diff --git a/Alc/converter.cpp b/Alc/converter.cpp index 72015db0..d16d2cb7 100644 --- a/Alc/converter.cpp +++ b/Alc/converter.cpp @@ -3,6 +3,8 @@ #include "converter.h" +#include + #include "fpu_modes.h" #include "mixer/defs.h" @@ -136,14 +138,11 @@ void Stereo2Mono(ALfloat *RESTRICT dst, const void *src, ALsizei frames) SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, ALsizei numchans, ALsizei srcRate, ALsizei dstRate) { - SampleConverter *converter; - ALsizei step; - if(numchans <= 0 || srcRate <= 0 || dstRate <= 0) - return NULL; + return nullptr; - converter = static_cast(al_calloc(16, - FAM_SIZE(SampleConverter, Chan, numchans))); + size_t alloc_size{FAM_SIZE(SampleConverter, Chan, numchans)}; + auto converter = new (al_calloc(16, alloc_size)) SampleConverter{}; converter->mSrcType = srcType; converter->mDstType = dstType; converter->mNumChannels = numchans; @@ -155,8 +154,8 @@ SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType /* Have to set the mixer FPU mode since that's what the resampler code expects. */ FPUCtl mixer_mode{}; - step = (ALsizei)mind(((ALdouble)srcRate/dstRate*FRACTIONONE) + 0.5, - MAX_PITCH * FRACTIONONE); + auto step = static_cast( + mind((ALdouble)srcRate/dstRate*FRACTIONONE + 0.5, MAX_PITCH*FRACTIONONE)); converter->mIncrement = maxi(step, 1); if(converter->mIncrement == FRACTIONONE) converter->mResample = Resample_copy_C; @@ -174,19 +173,15 @@ void DestroySampleConverter(SampleConverter **converter) { if(converter) { - al_free(*converter); - *converter = NULL; + delete *converter; + *converter = nullptr; } } ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframes) { - ALint prepcount = converter->mSrcPrepCount; - ALsizei increment = converter->mIncrement; - ALsizei DataPosFrac = converter->mFracOffset; - ALuint64 DataSize64; - + ALint prepcount{converter->mSrcPrepCount}; if(prepcount < 0) { /* Negative prepcount means we need to skip that many input samples. */ @@ -209,7 +204,9 @@ ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframe return 0; } - DataSize64 = prepcount; + ALsizei increment{converter->mIncrement}; + ALsizei DataPosFrac{converter->mFracOffset}; + auto DataSize64 = static_cast(prepcount); DataSize64 += srcframes; DataSize64 -= MAX_RESAMPLE_PADDING*2; DataSize64 <<= FRACTIONBITS; @@ -221,38 +218,32 @@ ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframe ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes) { - const ALsizei SrcFrameSize = converter->mNumChannels * converter->mSrcTypeSize; - const ALsizei DstFrameSize = converter->mNumChannels * converter->mDstTypeSize; - const ALsizei increment = converter->mIncrement; - ALsizei pos = 0; + const ALsizei SrcFrameSize{converter->mNumChannels * converter->mSrcTypeSize}; + const ALsizei DstFrameSize{converter->mNumChannels * converter->mDstTypeSize}; + const ALsizei increment{converter->mIncrement}; + auto SamplesIn = static_cast(*src); + ALsizei NumSrcSamples{*srcframes}; FPUCtl mixer_mode{}; - while(pos < dstframes && *srcframes > 0) + ALsizei pos{0}; + while(pos < dstframes && NumSrcSamples > 0) { - ALfloat *RESTRICT SrcData = converter->mSrcSamples; - ALfloat *RESTRICT DstData = converter->mDstSamples; - ALint prepcount = converter->mSrcPrepCount; - ALsizei DataPosFrac = converter->mFracOffset; - ALuint64 DataSize64; - ALsizei DstSize; - ALint toread; - ALsizei chan; - + ALint prepcount{converter->mSrcPrepCount}; if(prepcount < 0) { /* Negative prepcount means we need to skip that many input samples. */ - if(-prepcount >= *srcframes) + if(-prepcount >= NumSrcSamples) { - converter->mSrcPrepCount = prepcount + *srcframes; - *srcframes = 0; + converter->mSrcPrepCount = prepcount + NumSrcSamples; + NumSrcSamples = 0; break; } - *src = (const ALbyte*)*src + SrcFrameSize*-prepcount; - *srcframes += prepcount; + SamplesIn += SrcFrameSize*-prepcount; + NumSrcSamples += prepcount; converter->mSrcPrepCount = 0; continue; } - toread = mini(*srcframes, BUFFERSIZE - MAX_RESAMPLE_PADDING*2); + ALint toread{mini(NumSrcSamples, BUFFERSIZE - MAX_RESAMPLE_PADDING*2)}; if(prepcount < MAX_RESAMPLE_PADDING*2 && MAX_RESAMPLE_PADDING*2 - prepcount >= toread) @@ -260,39 +251,40 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs /* Not enough input samples to generate an output sample. Store * what we're given for later. */ - for(chan = 0;chan < converter->mNumChannels;chan++) + for(ALsizei chan{0};chan < converter->mNumChannels;chan++) LoadSamples(&converter->Chan[chan].mPrevSamples[prepcount], - (const ALbyte*)*src + converter->mSrcTypeSize*chan, + SamplesIn + converter->mSrcTypeSize*chan, converter->mNumChannels, converter->mSrcType, toread ); converter->mSrcPrepCount = prepcount + toread; - *srcframes = 0; + NumSrcSamples = 0; break; } - DataSize64 = prepcount; + ALfloat *RESTRICT SrcData{converter->mSrcSamples}; + ALfloat *RESTRICT DstData{converter->mDstSamples}; + ALsizei DataPosFrac{converter->mFracOffset}; + auto DataSize64 = static_cast(prepcount); DataSize64 += toread; DataSize64 -= MAX_RESAMPLE_PADDING*2; DataSize64 <<= FRACTIONBITS; DataSize64 -= DataPosFrac; /* If we have a full prep, we can generate at least one sample. */ - DstSize = (ALsizei)clampu64((DataSize64 + increment-1)/increment, 1, BUFFERSIZE); + auto DstSize = static_cast( + clampu64((DataSize64 + increment-1)/increment, 1, BUFFERSIZE)); DstSize = mini(DstSize, dstframes-pos); - for(chan = 0;chan < converter->mNumChannels;chan++) + for(ALsizei chan{0};chan < converter->mNumChannels;chan++) { - const ALbyte *SrcSamples = (const ALbyte*)*src + converter->mSrcTypeSize*chan; + const ALbyte *SrcSamples = SamplesIn + converter->mSrcTypeSize*chan; ALbyte *DstSamples = (ALbyte*)dst + converter->mDstTypeSize*chan; - const ALfloat *ResampledData; - ALsizei SrcDataEnd; /* Load the previous samples into the source data first, then the * new samples from the input buffer. */ - memcpy(SrcData, converter->Chan[chan].mPrevSamples, - prepcount*sizeof(ALfloat)); + std::copy_n(converter->Chan[chan].mPrevSamples, prepcount, SrcData); LoadSamples(SrcData + prepcount, SrcSamples, converter->mNumChannels, converter->mSrcType, toread ); @@ -300,24 +292,23 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs /* Store as many prep samples for next time as possible, given the * number of output samples being generated. */ - SrcDataEnd = (DataPosFrac + increment*DstSize)>>FRACTIONBITS; + ALsizei SrcDataEnd{(DstSize*increment + DataPosFrac)>>FRACTIONBITS}; if(SrcDataEnd >= prepcount+toread) - memset(converter->Chan[chan].mPrevSamples, 0, - sizeof(converter->Chan[chan].mPrevSamples)); + std::fill(std::begin(converter->Chan[chan].mPrevSamples), + std::end(converter->Chan[chan].mPrevSamples), 0.0f); else { size_t len = mini(MAX_RESAMPLE_PADDING*2, prepcount+toread-SrcDataEnd); - memcpy(converter->Chan[chan].mPrevSamples, &SrcData[SrcDataEnd], - len*sizeof(ALfloat)); - memset(converter->Chan[chan].mPrevSamples+len, 0, - sizeof(converter->Chan[chan].mPrevSamples) - len*sizeof(ALfloat)); + std::copy_n(SrcData+SrcDataEnd, len, converter->Chan[chan].mPrevSamples); + std::fill(std::begin(converter->Chan[chan].mPrevSamples)+len, + std::end(converter->Chan[chan].mPrevSamples), 0.0f); } /* Now resample, and store the result in the output buffer. */ - ResampledData = converter->mResample(&converter->mState, + const ALfloat *ResampledData{converter->mResample(&converter->mState, SrcData+MAX_RESAMPLE_PADDING, DataPosFrac, increment, DstData, DstSize - ); + )}; StoreSamples(DstSamples, ResampledData, converter->mNumChannels, converter->mDstType, DstSize); @@ -332,26 +323,27 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs converter->mFracOffset = DataPosFrac & FRACTIONMASK; /* Update the src and dst pointers in case there's still more to do. */ - *src = (const ALbyte*)*src + SrcFrameSize*(DataPosFrac>>FRACTIONBITS); - *srcframes -= mini(*srcframes, (DataPosFrac>>FRACTIONBITS)); + SamplesIn += SrcFrameSize*(DataPosFrac>>FRACTIONBITS); + NumSrcSamples -= mini(NumSrcSamples, (DataPosFrac>>FRACTIONBITS)); dst = (ALbyte*)dst + DstFrameSize*DstSize; pos += DstSize; } + *src = SamplesIn; + *srcframes = NumSrcSamples; + return pos; } ChannelConverter *CreateChannelConverter(enum DevFmtType srcType, enum DevFmtChannels srcChans, enum DevFmtChannels dstChans) { - ChannelConverter *converter; - if(srcChans != dstChans && !((srcChans == DevFmtMono && dstChans == DevFmtStereo) || (srcChans == DevFmtStereo && dstChans == DevFmtMono))) - return NULL; + return nullptr; - converter = static_cast(al_calloc(DEF_ALIGN, sizeof(*converter))); + auto converter = new (al_calloc(DEF_ALIGN, sizeof(ChannelConverter))) ChannelConverter{}; converter->mSrcType = srcType; converter->mSrcChans = srcChans; converter->mDstChans = dstChans; @@ -363,8 +355,8 @@ void DestroyChannelConverter(ChannelConverter **converter) { if(converter) { - al_free(*converter); - *converter = NULL; + delete *converter; + *converter = nullptr; } } diff --git a/Alc/converter.h b/Alc/converter.h index 78cbdf64..326c8033 100644 --- a/Alc/converter.h +++ b/Alc/converter.h @@ -3,6 +3,7 @@ #include "alMain.h" #include "alu.h" +#include "almalloc.h" struct SampleConverter { enum DevFmtType mSrcType; @@ -24,6 +25,8 @@ struct SampleConverter { struct { alignas(16) ALfloat mPrevSamples[MAX_RESAMPLE_PADDING*2]; } Chan[]; + + DEF_PLACE_NEWDEL() }; SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, ALsizei numchans, ALsizei srcRate, ALsizei dstRate); @@ -37,6 +40,8 @@ struct ChannelConverter { enum DevFmtType mSrcType; enum DevFmtChannels mSrcChans; enum DevFmtChannels mDstChans; + + DEF_PLACE_NEWDEL() }; ChannelConverter *CreateChannelConverter(enum DevFmtType srcType, enum DevFmtChannels srcChans, enum DevFmtChannels dstChans); -- cgit v1.2.3 From 57bb4670727c3c26644933b19d4620d565a177e2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 28 Nov 2018 23:19:25 -0800 Subject: Pass the desired resampler to CreateSampleConverter --- Alc/backends/wasapi.cpp | 2 +- Alc/converter.cpp | 12 ++++++++---- Alc/converter.h | 4 +++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index dfc91489..04afe807 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -1666,7 +1666,7 @@ HRESULT ALCwasapiCapture::resetProxy() { mSampleConv = CreateSampleConverter( srcType, device->FmtType, ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder), - OutputType.Format.nSamplesPerSec, device->Frequency + OutputType.Format.nSamplesPerSec, device->Frequency, BSinc24Resampler ); if(!mSampleConv) { diff --git a/Alc/converter.cpp b/Alc/converter.cpp index d16d2cb7..958936a1 100644 --- a/Alc/converter.cpp +++ b/Alc/converter.cpp @@ -136,7 +136,9 @@ void Stereo2Mono(ALfloat *RESTRICT dst, const void *src, ALsizei frames) } // namespace -SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, ALsizei numchans, ALsizei srcRate, ALsizei dstRate) +SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, + ALsizei numchans, ALsizei srcRate, ALsizei dstRate, + Resampler resampler) { if(numchans <= 0 || srcRate <= 0 || dstRate <= 0) return nullptr; @@ -161,9 +163,11 @@ SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType converter->mResample = Resample_copy_C; else { - /* TODO: Allow other resamplers. */ - BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc12); - converter->mResample = SelectResampler(BSinc12Resampler); + if(resampler == BSinc24Resampler) + BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc24); + else if(resampler == BSinc12Resampler) + BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc12); + converter->mResample = SelectResampler(resampler); } return converter; diff --git a/Alc/converter.h b/Alc/converter.h index 326c8033..e0aeb7d4 100644 --- a/Alc/converter.h +++ b/Alc/converter.h @@ -29,7 +29,9 @@ struct SampleConverter { DEF_PLACE_NEWDEL() }; -SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, ALsizei numchans, ALsizei srcRate, ALsizei dstRate); +SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, + ALsizei numchans, ALsizei srcRate, ALsizei dstRate, + Resampler resampler); void DestroySampleConverter(SampleConverter **converter); ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes); -- cgit v1.2.3 From c5d5d574e6312df70a181dff3bf23de15163dee9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 29 Nov 2018 13:08:03 -0800 Subject: Reorganize some device members --- OpenAL32/Include/alMain.h | 59 ++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index cf1cd6b2..898c8a08 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -687,6 +687,13 @@ struct ALCdevice_struct { std::string DeviceName; + // Device flags + ALuint Flags{0u}; + + std::string HrtfName; + al::vector HrtfList; + ALCenum HrtfStatus{ALC_FALSE}; + std::atomic LastError{ALC_NO_ERROR}; // Maximum number of sources that can be created @@ -710,32 +717,13 @@ struct ALCdevice_struct { al::vector FilterList; std::mutex FilterLock; - POSTPROCESS PostProcess{}; - - /* HRTF state and info */ - std::unique_ptr mHrtfState; - std::string HrtfName; - Hrtf *HrtfHandle{nullptr}; - al::vector HrtfList; - ALCenum HrtfStatus{ALC_FALSE}; - - /* UHJ encoder state */ - std::unique_ptr Uhj_Encoder; - - /* High quality Ambisonic decoder */ - std::unique_ptr AmbiDecoder; - - /* Stereo-to-binaural filter */ - std::unique_ptr Bs2b; - - /* First-order ambisonic upsampler for higher-order output */ - std::unique_ptr AmbiUp; - /* Rendering mode. */ RenderMode Render_Mode{NormalRender}; - // Device flags - ALuint Flags{0u}; + /* The average speaker distance as determined by the ambdec configuration + * (or alternatively, by the NFC-HOA reference delay). Only used for NFC. + */ + ALfloat AvgSpeakerDist{0.0f}; ALuint SamplesDone{0u}; std::chrono::nanoseconds ClockBase{0}; @@ -759,18 +747,31 @@ struct ALCdevice_struct { */ RealMixParams RealOut; - std::unique_ptr Stablizer; + /* HRTF state and info */ + std::unique_ptr mHrtfState; + Hrtf *HrtfHandle{nullptr}; - std::unique_ptr Limiter; + /* UHJ encoder state */ + std::unique_ptr Uhj_Encoder; - /* The average speaker distance as determined by the ambdec configuration - * (or alternatively, by the NFC-HOA reference delay). Only used for NFC. - */ - ALfloat AvgSpeakerDist{0.0f}; + /* High quality Ambisonic decoder */ + std::unique_ptr AmbiDecoder; + + /* Stereo-to-binaural filter */ + std::unique_ptr Bs2b; + + /* First-order ambisonic upsampler for higher-order output */ + std::unique_ptr AmbiUp; + + POSTPROCESS PostProcess{}; + + std::unique_ptr Stablizer; /* Delay buffers used to compensate for speaker distances. */ DistanceComp ChannelDelay; + std::unique_ptr Limiter; + /* Dithering control. */ ALfloat DitherDepth{0.0f}; ALuint DitherSeed{0u}; -- cgit v1.2.3 From 0d2bbe17f2401feeae02972d927a8b72a4c28500 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 29 Nov 2018 13:34:06 -0800 Subject: Rename a function for consistency --- common/threads.cpp | 6 +++--- common/threads.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common/threads.cpp b/common/threads.cpp index eaf2cbbc..69989ae4 100644 --- a/common/threads.cpp +++ b/common/threads.cpp @@ -79,7 +79,7 @@ void semaphore::post() void semaphore::wait() noexcept { WaitForSingleObject(mSem, INFINITE); } -int semaphore::trywait() noexcept +bool semaphore::try_wait() noexcept { return WaitForSingleObject(mSem, 0) == WAIT_OBJECT_0; } } // namespace al @@ -129,7 +129,7 @@ void semaphore::post() void semaphore::wait() noexcept { dispatch_semaphore_wait(mSem, DISPATCH_TIME_FOREVER); } -int semaphore::trywait() noexcept +bool semaphore::try_wait() noexcept { return dispatch_semaphore_wait(mSem, DISPATCH_TIME_NOW) == 0; } #else /* !__APPLE__ */ @@ -155,7 +155,7 @@ void semaphore::wait() noexcept } } -int semaphore::trywait() noexcept +bool semaphore::try_wait() noexcept { return sem_trywait(&mSem) == 0; } #endif /* __APPLE__ */ diff --git a/common/threads.h b/common/threads.h index 7eb2d608..8a640390 100644 --- a/common/threads.h +++ b/common/threads.h @@ -47,7 +47,7 @@ public: void post(); void wait() noexcept; - int trywait() noexcept; + bool try_wait() noexcept; }; } // namespace al -- cgit v1.2.3 From 8ca8da30bd587cefcd86e3a2b9401821af65e502 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 29 Nov 2018 22:49:01 -0800 Subject: Store the source ID with the voice instead of the source pointer --- Alc/alc.cpp | 2 +- Alc/alu.cpp | 22 +++++++++++----------- OpenAL32/Include/alu.h | 2 +- OpenAL32/alSource.cpp | 16 +++++++++------- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index aa786244..d8e35d29 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2332,7 +2332,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { al_free(voice->Update.exchange(nullptr, std::memory_order_acq_rel)); - if(voice->Source.load(std::memory_order_acquire) == nullptr) + if(voice->SourceID.load(std::memory_order_acquire) == 0u) return; if(device->AvgSpeakerDist > 0.0f) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index ecf5f024..607798ba 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1506,8 +1506,8 @@ void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray *slots) std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire), [ctx,force](ALvoice *voice) -> void { - ALsource *source{voice->Source.load(std::memory_order_acquire)}; - if(source) CalcSourceParams(voice, ctx, force); + ALuint sid{voice->SourceID.load(std::memory_order_acquire)}; + if(sid) CalcSourceParams(voice, ctx, force); } ); } @@ -1536,16 +1536,16 @@ void ProcessContext(ALCcontext *ctx, ALsizei SamplesToDo) std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire), [SamplesToDo,ctx](ALvoice *voice) -> void { - ALsource *source{voice->Source.load(std::memory_order_acquire)}; - if(!source) return; + ALuint sid{voice->SourceID.load(std::memory_order_acquire)}; + if(!sid) return; if(!voice->Playing.load(std::memory_order_relaxed) || voice->Step < 1) return; - if(!MixSource(voice, source->id, ctx, SamplesToDo)) + if(!MixSource(voice, sid, ctx, SamplesToDo)) { - voice->Source.store(nullptr, std::memory_order_relaxed); + voice->SourceID.store(0u, std::memory_order_relaxed); voice->Playing.store(false, std::memory_order_release); - SendSourceStoppedEvent(ctx, source->id); + SendSourceStoppedEvent(ctx, sid); } } ); @@ -1862,17 +1862,17 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire), [ctx](ALvoice *voice) -> void { - ALsource *source{voice->Source.load(std::memory_order_relaxed)}; - if(!source || !voice->Playing.load(std::memory_order_relaxed)) + ALuint sid{voice->SourceID.load(std::memory_order_relaxed)}; + if(!sid || !voice->Playing.load(std::memory_order_relaxed)) return; - voice->Source.store(nullptr, std::memory_order_relaxed); + voice->SourceID.store(0u, std::memory_order_relaxed); voice->Playing.store(false, std::memory_order_release); /* If the source's voice was playing, it's now effectively * stopped (the source state will be updated the next time it's * checked). */ - SendSourceStoppedEvent(ctx, source->id); + SendSourceStoppedEvent(ctx, sid); } ); diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 68f539f3..e178a5a6 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -207,7 +207,7 @@ typedef struct ALvoice { std::atomic Update; - std::atomic Source; + std::atomic SourceID; std::atomic Playing; /** diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index a60701e7..9911bcc5 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -52,10 +52,11 @@ namespace { inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) { ALint idx{source->VoiceIdx}; + ALuint sid{source->id}; if(idx >= 0 && idx < context->VoiceCount.load(std::memory_order_relaxed)) { ALvoice *voice{context->Voices[idx]}; - if(voice->Source.load(std::memory_order_acquire) == source) + if(voice->SourceID.load(std::memory_order_acquire) == sid) return voice; } source->VoiceIdx = -1; @@ -525,7 +526,7 @@ void FreeSource(ALCcontext *context, ALsource *source) ALvoice *voice{GetSourceVoice(source, context)}; if(voice) { - voice->Source.store(nullptr, std::memory_order_relaxed); + voice->SourceID.store(0u, std::memory_order_relaxed); voice->Playing.store(false, std::memory_order_release); } ALCdevice_Unlock(device); @@ -2782,7 +2783,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed); auto voice_iter = std::find_if(context->Voices, voices_end, [](const ALvoice *voice) noexcept -> bool - { return voice->Source.load(std::memory_order_relaxed) == nullptr; } + { return voice->SourceID.load(std::memory_order_relaxed) == 0u; } ); auto vidx = static_cast(std::distance(context->Voices, voice_iter)); voice = *voice_iter; @@ -2841,7 +2842,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) NfcFilterCreate(&voice->Direct.Params[j].NFCtrlFilter, 0.0f, w1); } - voice->Source.store(source, std::memory_order_relaxed); + voice->SourceID.store(source->id, std::memory_order_relaxed); voice->Playing.store(true, std::memory_order_release); source->state = AL_PLAYING; source->VoiceIdx = vidx; @@ -2913,7 +2914,7 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) ALvoice *voice{GetSourceVoice(source, context.get())}; if(voice != nullptr) { - voice->Source.store(nullptr, std::memory_order_relaxed); + voice->SourceID.store(0u, std::memory_order_relaxed); voice->Playing.store(false, std::memory_order_release); voice = nullptr; } @@ -2956,7 +2957,7 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) ALvoice *voice{GetSourceVoice(source, context.get())}; if(voice != nullptr) { - voice->Source.store(nullptr, std::memory_order_relaxed); + voice->SourceID.store(0u, std::memory_order_relaxed); voice->Playing.store(false, std::memory_order_release); voice = nullptr; } @@ -3389,7 +3390,8 @@ void UpdateAllSourceProps(ALCcontext *context) std::for_each(context->Voices, voices_end, [context](ALvoice *voice) -> void { - ALsource *source{voice->Source.load(std::memory_order_acquire)}; + ALuint sid{voice->SourceID.load(std::memory_order_acquire)}; + ALsource *source = sid ? LookupSource(context, sid) : nullptr; if(source && !source->PropsClean.test_and_set(std::memory_order_acq_rel)) UpdateSourceProps(source, voice, context); } -- cgit v1.2.3 From b582f1346a2e0e2e82eb4a2d4e72d670cc066971 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 29 Nov 2018 22:56:33 -0800 Subject: Avoid hard-coding a couple sizes --- OpenAL32/alSource.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 9911bcc5..0eaed61f 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -91,11 +91,11 @@ void UpdateSourceProps(ALsource *source, ALvoice *voice, ALCcontext *context) props->RefDistance = source->RefDistance; props->MaxDistance = source->MaxDistance; props->RolloffFactor = source->RolloffFactor; - std::copy_n(source->Position, 3, props->Position); - std::copy_n(source->Velocity, 3, props->Velocity); - std::copy_n(source->Direction, 3, props->Direction); - for(ALsizei i{0};i < 2;i++) - std::copy_n(source->Orientation[i], 3, props->Orientation[i]); + std::copy(std::begin(source->Position), std::end(source->Position), props->Position); + std::copy(std::begin(source->Velocity), std::end(source->Velocity), props->Velocity); + std::copy(std::begin(source->Direction), std::end(source->Direction), props->Direction); + std::copy(std::begin(source->Orientation[0]), std::end(source->Orientation[0]), props->Orientation[0]); + std::copy(std::begin(source->Orientation[1]), std::end(source->Orientation[1]), props->Orientation[1]); props->HeadRelative = source->HeadRelative; props->mDistanceModel = source->mDistanceModel; props->Resampler = source->Resampler; @@ -111,7 +111,7 @@ void UpdateSourceProps(ALsource *source, ALvoice *voice, ALCcontext *context) props->RoomRolloffFactor = source->RoomRolloffFactor; props->DopplerFactor = source->DopplerFactor; - std::copy_n(source->StereoPan, 2, props->StereoPan); + std::copy(std::begin(source->StereoPan), std::end(source->StereoPan), props->StereoPan); props->Radius = source->Radius; -- cgit v1.2.3 From 364850e8f9a224144c91c7b562d44321b7aa4505 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 30 Nov 2018 10:08:18 -0800 Subject: Move a variable declaration to a more appropriate place --- OpenAL32/alSource.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 0eaed61f..c0e48c5c 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -52,9 +52,9 @@ namespace { inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) { ALint idx{source->VoiceIdx}; - ALuint sid{source->id}; if(idx >= 0 && idx < context->VoiceCount.load(std::memory_order_relaxed)) { + ALuint sid{source->id}; ALvoice *voice{context->Voices[idx]}; if(voice->SourceID.load(std::memory_order_acquire) == sid) return voice; -- cgit v1.2.3 From 4b7ac4a6ed290182de945274afd90fc4cece0283 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 30 Nov 2018 16:56:23 -0800 Subject: Don't bother making ALvoiceProps dynamically sized --- Alc/alc.cpp | 30 +++++++++--------------------- Alc/alu.cpp | 14 ++++++-------- OpenAL32/Include/alSource.h | 1 - OpenAL32/Include/alu.h | 24 ++++++++++-------------- OpenAL32/alSource.cpp | 4 +--- 5 files changed, 26 insertions(+), 47 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index d8e35d29..4d0dd192 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2320,8 +2320,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ALvoiceProps *vprops{context->FreeVoiceProps.exchange(nullptr, std::memory_order_acq_rel)}; while(vprops) { - struct ALvoiceProps *next = vprops->next.load(std::memory_order_relaxed); - al_free(vprops); + ALvoiceProps *next = vprops->next.load(std::memory_order_relaxed); + delete vprops; vprops = next; } @@ -2330,7 +2330,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) std::for_each(context->Voices, voices_end, [device](ALvoice *voice) -> void { - al_free(voice->Update.exchange(nullptr, std::memory_order_acq_rel)); + delete voice->Update.exchange(nullptr, std::memory_order_acq_rel); if(voice->SourceID.load(std::memory_order_acquire) == 0u) return; @@ -2615,7 +2615,7 @@ ALCcontext_struct::~ALCcontext_struct() while(vprops) { ALvoiceProps *next{vprops->next.load(std::memory_order_relaxed)}; - al_free(vprops); + delete vprops; vprops = next; ++count; } @@ -2780,15 +2780,10 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) * chunk. */ size_t sizeof_voice{RoundUp(FAM_SIZE(ALvoice, Send, num_sends), 16)}; - size_t sizeof_props{RoundUp(FAM_SIZE(struct ALvoiceProps, Send, num_sends), 16)}; - size_t size{sizeof(ALvoice*) + sizeof_voice + sizeof_props}; + size_t size{sizeof(ALvoice*) + sizeof_voice}; auto voices = static_cast(al_calloc(16, RoundUp(size*num_voices, 16))); - /* The voice and property objects are stored interleaved since they're - * paired together. - */ auto voice = reinterpret_cast((char*)voices + RoundUp(num_voices*sizeof(ALvoice*), 16)); - auto props = reinterpret_cast((char*)voice + sizeof_voice); ALsizei v{0}; if(context->Voices) @@ -2806,17 +2801,12 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) */ memcpy(voice, old_voice, sizeof(*voice)); std::copy_n(old_voice->Send, s_count, voice->Send); - - memcpy(props, old_voice->Props, sizeof(*props)); - std::copy_n(old_voice->Props->Send, s_count, props->Send); - /* Set this voice's property set pointer and voice reference. */ - voice->Props = props; + /* Set this voice's reference. */ voices[v] = voice; - /* Increment pointers to the next storage space. */ - voice = reinterpret_cast((char*)props + sizeof_props); - props = reinterpret_cast((char*)voice + sizeof_voice); + /* Increment pointer to the next storage space. */ + voice = reinterpret_cast((char*)voice + sizeof_voice); } /* Deinit any left over voices that weren't copied over to the new * array. NOTE: If this does anything, v equals num_voices and @@ -2833,11 +2823,9 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) { voice->Update.store(nullptr, std::memory_order_relaxed); - voice->Props = props; voices[v] = voice; - voice = reinterpret_cast((char*)props + sizeof_props); - props = reinterpret_cast((char*)voice + sizeof_voice); + voice = reinterpret_cast((char*)voice + sizeof_voice); } al_free(context->Voices); diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 607798ba..0dec32bc 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -101,7 +101,7 @@ void aluInit(void) void DeinitVoice(ALvoice *voice) noexcept { - al_free(voice->Update.exchange(nullptr)); + delete voice->Update.exchange(nullptr, std::memory_order_acq_rel); } @@ -505,7 +505,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev const ALfloat DryGainLF, const ALfloat *WetGain, const ALfloat *WetGainLF, const ALfloat *WetGainHF, ALeffectslot **SendSlots, const ALbuffer *Buffer, - const struct ALvoiceProps *props, const ALlistener &Listener, + const ALvoiceProps *props, const ALlistener &Listener, const ALCdevice *Device) { struct ChanMap StereoMap[2] = { @@ -1023,7 +1023,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev } } -void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) +void CalcNonAttnSourceParams(ALvoice *voice, const ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { const ALCdevice *Device = ALContext->Device; const ALlistener &Listener = ALContext->Listener; @@ -1086,7 +1086,7 @@ void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, c WetGainLF, WetGainHF, SendSlots, ALBuffer, props, Listener, Device); } -void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) +void CalcAttnSourceParams(ALvoice *voice, const ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { const ALCdevice *Device = ALContext->Device; const ALlistener &Listener = ALContext->Listener; @@ -1461,13 +1461,11 @@ void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) if(props) { - memcpy(voice->Props, props, - FAM_SIZE(struct ALvoiceProps, Send, context->Device->NumAuxSends) - ); + memcpy(&voice->Props, props, FAM_SIZE(ALvoiceProps, Send, context->Device->NumAuxSends)); AtomicReplaceHead(context->FreeVoiceProps, props); } - props = voice->Props; + props = &voice->Props; ALbufferlistitem *BufferListItem{voice->current_buffer.load(std::memory_order_relaxed)}; while(BufferListItem) diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 2cbc5ddc..62c6fae3 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -7,7 +7,6 @@ #include "almalloc.h" #include "atomic.h" -#define MAX_SENDS 16 #define DEFAULT_SENDS 2 #ifdef __cplusplus diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index e178a5a6..2ff69058 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -17,11 +17,13 @@ #include "math_defs.h" #include "filters/defs.h" #include "filters/nfc.h" +#include "almalloc.h" enum class DistanceModel; -#define MAX_PITCH (255) +#define MAX_PITCH 255 +#define MAX_SENDS 16 /* Maximum number of samples to pad on either end of a buffer for resampling. * Note that both the beginning and end need padding! @@ -29,10 +31,6 @@ enum class DistanceModel; #define MAX_RESAMPLE_PADDING 24 -#ifdef __cplusplus -extern "C" { -#endif - struct BSincTable; struct ALsource; struct ALbufferlistitem; @@ -144,8 +142,6 @@ typedef struct SendParams { struct ALvoiceProps { - std::atomic next; - ALfloat Pitch; ALfloat Gain; ALfloat OuterGain; @@ -194,7 +190,11 @@ struct ALvoiceProps { ALfloat HFReference; ALfloat GainLF; ALfloat LFReference; - } Send[]; + } Send[MAX_SENDS]; + + std::atomic next; + + DEF_NEWDEL(ALvoiceProps) }; #define VOICE_IS_STATIC (1<<0) @@ -203,13 +203,13 @@ struct ALvoiceProps { #define VOICE_HAS_NFC (1<<3) typedef struct ALvoice { - ALvoiceProps *Props; - std::atomic Update; std::atomic SourceID; std::atomic Playing; + ALvoiceProps Props; + /** * Source offset in samples, relative to the currently playing buffer, NOT * the whole queue, and the fractional (fixed-point) offset to the next @@ -487,8 +487,4 @@ extern ALfloat ConeScale; extern ALfloat ZScale; extern ALboolean OverrideReverbSpeedOfSound; -#ifdef __cplusplus -} -#endif - #endif diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index c0e48c5c..87729c73 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -68,9 +68,7 @@ void UpdateSourceProps(ALsource *source, ALvoice *voice, ALCcontext *context) /* Get an unused property container, or allocate a new one as needed. */ ALvoiceProps *props{context->FreeVoiceProps.load(std::memory_order_acquire)}; if(!props) - props = static_cast(al_calloc(16, - FAM_SIZE(ALvoiceProps, Send, source->Send.size())) - ); + props = new ALvoiceProps{}; else { ALvoiceProps *next; -- cgit v1.2.3 From c7569c31ad4b731f1b6c86cbc1833f8b0af4bf82 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 30 Nov 2018 19:04:38 -0800 Subject: Improve construction and destruction of ALvoices --- Alc/alc.cpp | 57 +++++++++++++++++++++++++++++++++++++++----------- Alc/alu.cpp | 18 ++++++++-------- OpenAL32/Include/alu.h | 20 ++++++++++-------- 3 files changed, 65 insertions(+), 30 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 4d0dd192..b5cc5716 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2795,11 +2795,51 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) for(;v < v_count;v++) { ALvoice *old_voice{context->Voices[v]}; + voice = new (voice) ALvoice{}; /* Copy the old voice data and source property set to the new - * storage. + * storage. Make sure the old voice's Update (if any) is cleared so + * it doesn't get deleted on deinit. */ - memcpy(voice, old_voice, sizeof(*voice)); + voice->Update.store(old_voice->Update.exchange(nullptr, std::memory_order_relaxed), + std::memory_order_relaxed); + + voice->SourceID.store(old_voice->SourceID.load(std::memory_order_relaxed), + std::memory_order_relaxed); + voice->Playing.store(old_voice->Playing.load(std::memory_order_relaxed), + std::memory_order_relaxed); + + voice->Props = old_voice->Props; + /* Clear extraneous property set sends. */ + std::fill(std::begin(voice->Props.Send)+s_count, std::end(voice->Props.Send), + ALvoiceProps::SendData{}); + + voice->position.store(old_voice->position.load(std::memory_order_relaxed), + std::memory_order_relaxed); + voice->position_fraction.store( + old_voice->position_fraction.load(std::memory_order_relaxed), + std::memory_order_relaxed); + + voice->current_buffer.store(old_voice->current_buffer.load(std::memory_order_relaxed), + std::memory_order_relaxed); + voice->loop_buffer.store(old_voice->loop_buffer.load(std::memory_order_relaxed), + std::memory_order_relaxed); + + voice->NumChannels = old_voice->NumChannels; + voice->SampleSize = old_voice->SampleSize; + + voice->Step = old_voice->Step; + voice->Resampler = old_voice->Resampler; + + voice->Flags = old_voice->Flags; + + voice->Offset = old_voice->Offset; + + memcpy(voice->PrevSamples, old_voice->PrevSamples, sizeof(voice->PrevSamples)); + + voice->ResampleState = old_voice->ResampleState; + + voice->Direct = old_voice->Direct; std::copy_n(old_voice->Send, s_count, voice->Send); /* Set this voice's reference. */ @@ -2808,21 +2848,14 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) /* Increment pointer to the next storage space. */ voice = reinterpret_cast((char*)voice + sizeof_voice); } - /* Deinit any left over voices that weren't copied over to the new - * array. NOTE: If this does anything, v equals num_voices and - * num_voices is less than VoiceCount, so the following loop won't do - * anything. - */ + /* Deinit old voices. */ auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed); - std::for_each(context->Voices + v, voices_end, - [](ALvoice *voice) -> void { DeinitVoice(voice); } - ); + std::for_each(context->Voices, voices_end, DeinitVoice); } /* Finish setting the voices' property set pointers and references. */ for(;v < num_voices;v++) { - voice->Update.store(nullptr, std::memory_order_relaxed); - + voice = new (voice) ALvoice{}; voices[v] = voice; voice = reinterpret_cast((char*)voice + sizeof_voice); diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 0dec32bc..b9fe95f0 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -102,6 +102,7 @@ void aluInit(void) void DeinitVoice(ALvoice *voice) noexcept { delete voice->Update.exchange(nullptr, std::memory_order_acq_rel); + voice->~ALvoice(); } @@ -505,7 +506,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev const ALfloat DryGainLF, const ALfloat *WetGain, const ALfloat *WetGainLF, const ALfloat *WetGainHF, ALeffectslot **SendSlots, const ALbuffer *Buffer, - const ALvoiceProps *props, const ALlistener &Listener, + const ALvoicePropsBase *props, const ALlistener &Listener, const ALCdevice *Device) { struct ChanMap StereoMap[2] = { @@ -1023,7 +1024,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev } } -void CalcNonAttnSourceParams(ALvoice *voice, const ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) +void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { const ALCdevice *Device = ALContext->Device; const ALlistener &Listener = ALContext->Listener; @@ -1086,7 +1087,7 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoiceProps *props, const AL WetGainLF, WetGainHF, SendSlots, ALBuffer, props, Listener, Device); } -void CalcAttnSourceParams(ALvoice *voice, const ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) +void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { const ALCdevice *Device = ALContext->Device; const ALlistener &Listener = ALContext->Listener; @@ -1461,11 +1462,10 @@ void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) if(props) { - memcpy(&voice->Props, props, FAM_SIZE(ALvoiceProps, Send, context->Device->NumAuxSends)); + voice->Props = *props; AtomicReplaceHead(context->FreeVoiceProps, props); } - props = &voice->Props; ALbufferlistitem *BufferListItem{voice->current_buffer.load(std::memory_order_relaxed)}; while(BufferListItem) @@ -1477,11 +1477,11 @@ void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) ); if(LIKELY(buffer != buffers_end)) { - if(props->SpatializeMode == SpatializeOn || - (props->SpatializeMode == SpatializeAuto && (*buffer)->FmtChannels == FmtMono)) - CalcAttnSourceParams(voice, props, *buffer, context); + if(voice->Props.SpatializeMode == SpatializeOn || + (voice->Props.SpatializeMode == SpatializeAuto && (*buffer)->FmtChannels == FmtMono)) + CalcAttnSourceParams(voice, &voice->Props, *buffer, context); else - CalcNonAttnSourceParams(voice, props, *buffer, context); + CalcNonAttnSourceParams(voice, &voice->Props, *buffer, context); break; } BufferListItem = BufferListItem->next.load(std::memory_order_acquire); diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 2ff69058..1fd092c3 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -141,7 +141,7 @@ typedef struct SendParams { } SendParams; -struct ALvoiceProps { +struct ALvoicePropsBase { ALfloat Pitch; ALfloat Gain; ALfloat OuterGain; @@ -183,7 +183,7 @@ struct ALvoiceProps { ALfloat GainLF; ALfloat LFReference; } Direct; - struct { + struct SendData { struct ALeffectslot *Slot; ALfloat Gain; ALfloat GainHF; @@ -191,8 +191,10 @@ struct ALvoiceProps { ALfloat GainLF; ALfloat LFReference; } Send[MAX_SENDS]; +}; - std::atomic next; +struct ALvoiceProps : public ALvoicePropsBase { + std::atomic next{nullptr}; DEF_NEWDEL(ALvoiceProps) }; @@ -202,13 +204,13 @@ struct ALvoiceProps { #define VOICE_HAS_HRTF (1<<2) #define VOICE_HAS_NFC (1<<3) -typedef struct ALvoice { - std::atomic Update; +struct ALvoice { + std::atomic Update{nullptr}; - std::atomic SourceID; - std::atomic Playing; + std::atomic SourceID{0u}; + std::atomic Playing{false}; - ALvoiceProps Props; + ALvoicePropsBase Props; /** * Source offset in samples, relative to the currently playing buffer, NOT @@ -262,7 +264,7 @@ typedef struct ALvoice { ALfloat (*Buffer)[BUFFERSIZE]; ALsizei Channels; } Send[]; -} ALvoice; +}; void DeinitVoice(ALvoice *voice) noexcept; -- cgit v1.2.3 From 1e6e84374b9928b614e7f36a26499d806f3c89cc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 30 Nov 2018 21:23:43 -0800 Subject: Use std::array for the voice's PrevSamples --- Alc/alc.cpp | 3 ++- Alc/mixvoice.cpp | 11 ++++++----- OpenAL32/Include/alu.h | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index b5cc5716..03cbcd53 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2835,7 +2835,8 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) voice->Offset = old_voice->Offset; - memcpy(voice->PrevSamples, old_voice->PrevSamples, sizeof(voice->PrevSamples)); + std::copy(std::begin(old_voice->PrevSamples), std::end(old_voice->PrevSamples), + std::begin(voice->PrevSamples)); voice->ResampleState = old_voice->ResampleState; diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 1aa3000b..f0ee8bb6 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -356,13 +356,14 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize for(ALsizei chan{0};chan < NumChannels;chan++) { - ALfloat *SrcData{Device->TempBuffer[SOURCE_DATA_BUF]}; + ALfloat (&SrcData)[BUFFERSIZE] = Device->TempBuffer[SOURCE_DATA_BUF]; /* Load the previous samples into the source data first, and clear the rest. */ - std::copy_n(voice->PrevSamples[chan], MAX_RESAMPLE_PADDING, SrcData); - std::fill_n(SrcData+MAX_RESAMPLE_PADDING, BUFFERSIZE-MAX_RESAMPLE_PADDING, 0.0f); - ALsizei FilledAmt{MAX_RESAMPLE_PADDING}; + auto srciter = std::copy(std::begin(voice->PrevSamples[chan]), + std::end(voice->PrevSamples[chan]), std::begin(SrcData)); + std::fill(srciter, std::end(SrcData), 0.0f); + auto FilledAmt = static_cast(voice->PrevSamples[chan].size()); if(isstatic) { /* TODO: For static sources, loop points are taken from the @@ -501,7 +502,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize /* Store the last source samples used for next time. */ std::copy_n(&SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS], - MAX_RESAMPLE_PADDING, voice->PrevSamples[chan]); + voice->PrevSamples[chan].size(), std::begin(voice->PrevSamples[chan])); /* Now resample, then filter and mix to the appropriate outputs. */ const ALfloat *ResampledData{Resample(&voice->ResampleState, diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 1fd092c3..5cf5f069 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -244,7 +244,7 @@ struct ALvoice { ALuint Offset; /* Number of output samples mixed since starting. */ - alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_RESAMPLE_PADDING]; + alignas(16) std::array,MAX_INPUT_CHANNELS> PrevSamples; InterpState ResampleState; -- cgit v1.2.3 From 7b1548af3cdda7f0023510a9ec12813a137a1668 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 30 Nov 2018 21:39:59 -0800 Subject: Handle source state changed events uniquely in the event loop To avoid the need of constructing the string in the mixer thread, which is commonly formatted anyway. --- Alc/alu.cpp | 27 ++++----------------------- OpenAL32/Include/alMain.h | 10 +++++++--- OpenAL32/alSource.cpp | 18 +++++------------- OpenAL32/event.cpp | 21 ++++++++++++++++++++- 4 files changed, 36 insertions(+), 40 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index b9fe95f0..197d554d 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -287,31 +287,12 @@ aluVector aluMatrixfVector(const aluMatrixf *mtx, const aluVector *vec) void SendSourceStoppedEvent(ALCcontext *context, ALuint id) { - AsyncEvent evt = ASYNC_EVENT(EventType_SourceStateChange); - ALbitfieldSOFT enabledevt; - size_t strpos; - ALuint scale; - - enabledevt = context->EnabledEvts.load(std::memory_order_acquire); + ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)}; if(!(enabledevt&EventType_SourceStateChange)) return; - evt.u.user.type = AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT; - evt.u.user.id = id; - evt.u.user.param = AL_STOPPED; - - /* Normally snprintf would be used, but this is called from the mixer and - * that function's not real-time safe, so we have to construct it manually. - */ - strcpy(evt.u.user.msg, "Source ID "); strpos = 10; - scale = 1000000000; - while(scale > 0 && scale > id) - scale /= 10; - while(scale > 0) - { - evt.u.user.msg[strpos++] = '0' + ((id/scale)%10); - scale /= 10; - } - strcpy(evt.u.user.msg+strpos, " state changed to AL_STOPPED"); + AsyncEvent evt{ASYNC_EVENT(EventType_SourceStateChange)}; + evt.u.srcstate.id = id; + evt.u.srcstate.state = AL_STOPPED; if(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) == 1) context->EventSem.post(); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 898c8a08..bff3d52e 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -841,10 +841,14 @@ enum { EventType_ReleaseEffectState = 65536, }; -typedef struct AsyncEvent { +struct AsyncEvent { unsigned int EnumType; union { char dummy; + struct { + ALuint id; + ALenum state; + } srcstate; struct { ALenum type; ALuint id; @@ -853,8 +857,8 @@ typedef struct AsyncEvent { } user; EffectState *mEffectState; } u; -} AsyncEvent; -#define ASYNC_EVENT(t) { t, { 0 } } +}; +#define ASYNC_EVENT(t) AsyncEvent{ t, { 0 } } void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends); diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 87729c73..11cea945 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -684,21 +684,13 @@ inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context) /** Can only be called while the mixer is locked! */ void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) { - AsyncEvent evt = ASYNC_EVENT(EventType_SourceStateChange); - ALbitfieldSOFT enabledevt; - - enabledevt = context->EnabledEvts.load(std::memory_order_acquire); + ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)}; if(!(enabledevt&EventType_SourceStateChange)) return; - evt.u.user.type = AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT; - evt.u.user.id = id; - evt.u.user.param = state; - snprintf(evt.u.user.msg, sizeof(evt.u.user.msg), "Source ID %u state changed to %s", id, - (state==AL_INITIAL) ? "AL_INITIAL" : - (state==AL_PLAYING) ? "AL_PLAYING" : - (state==AL_PAUSED) ? "AL_PAUSED" : - (state==AL_STOPPED) ? "AL_STOPPED" : "" - ); + AsyncEvent evt{ASYNC_EVENT(EventType_SourceStateChange)}; + evt.u.srcstate.id = id; + evt.u.srcstate.state = state; + /* The mixer may have queued a state change that's not yet been processed, * and we don't want state change messages to occur out of order, so send * it through the async queue to ensure proper ordering. diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index b7599a02..4980abee 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -39,7 +39,26 @@ static int EventThread(ALCcontext *context) } ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_acquire)}; - if(context->EventCb && (enabledevts&evt.EnumType) == evt.EnumType) + if(!context->EventCb) continue; + + if(evt.EnumType == EventType_SourceStateChange) + { + if(!(enabledevts&EventType_SourceStateChange)) + continue; + char msg[1024]{}; + int msglen{snprintf(msg, sizeof(msg), "Source ID %u state changed to %s", + evt.u.srcstate.id, + (evt.u.srcstate.state==AL_INITIAL) ? "AL_INITIAL" : + (evt.u.srcstate.state==AL_PLAYING) ? "AL_PLAYING" : + (evt.u.srcstate.state==AL_PAUSED) ? "AL_PAUSED" : + (evt.u.srcstate.state==AL_STOPPED) ? "AL_STOPPED" : "" + )}; + if(msglen < 1) msglen = strlen(msg); + context->EventCb(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, evt.u.srcstate.id, + evt.u.srcstate.state, msglen, msg, context->EventParam + ); + } + else if((enabledevts&evt.EnumType) == evt.EnumType) context->EventCb(evt.u.user.type, evt.u.user.id, evt.u.user.param, (ALsizei)strlen(evt.u.user.msg), evt.u.user.msg, context->EventParam ); -- cgit v1.2.3 From cc161fe7c12182ebca3a49a380c4c60ebb1afb5f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 1 Dec 2018 01:12:05 -0800 Subject: Add a missing include --- OpenAL32/Include/alu.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 5cf5f069..36d3be84 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -10,6 +10,8 @@ #include #endif +#include + #include "alMain.h" #include "alBuffer.h" -- cgit v1.2.3 From 255c07def9814b1c07196983a0a670dccccc0d50 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 1 Dec 2018 11:28:11 -0800 Subject: Try to pacify MSVC's missing a suitable default constructor --- Alc/converter.cpp | 9 ++------- Alc/converter.h | 37 ++++++++++++++++++++----------------- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/Alc/converter.cpp b/Alc/converter.cpp index 958936a1..3effddd8 100644 --- a/Alc/converter.cpp +++ b/Alc/converter.cpp @@ -341,18 +341,13 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs } -ChannelConverter *CreateChannelConverter(enum DevFmtType srcType, enum DevFmtChannels srcChans, enum DevFmtChannels dstChans) +ChannelConverter *CreateChannelConverter(DevFmtType srcType, DevFmtChannels srcChans, DevFmtChannels dstChans) { if(srcChans != dstChans && !((srcChans == DevFmtMono && dstChans == DevFmtStereo) || (srcChans == DevFmtStereo && dstChans == DevFmtMono))) return nullptr; - auto converter = new (al_calloc(DEF_ALIGN, sizeof(ChannelConverter))) ChannelConverter{}; - converter->mSrcType = srcType; - converter->mSrcChans = srcChans; - converter->mDstChans = dstChans; - - return converter; + return new ChannelConverter{srcType, srcChans, dstChans}; } void DestroyChannelConverter(ChannelConverter **converter) diff --git a/Alc/converter.h b/Alc/converter.h index e0aeb7d4..7444d4fa 100644 --- a/Alc/converter.h +++ b/Alc/converter.h @@ -6,21 +6,21 @@ #include "almalloc.h" struct SampleConverter { - enum DevFmtType mSrcType; - enum DevFmtType mDstType; - ALsizei mNumChannels; - ALsizei mSrcTypeSize; - ALsizei mDstTypeSize; + DevFmtType mSrcType{}; + DevFmtType mDstType{}; + ALsizei mNumChannels{}; + ALsizei mSrcTypeSize{}; + ALsizei mDstTypeSize{}; - ALint mSrcPrepCount; + ALint mSrcPrepCount{}; - ALsizei mFracOffset; - ALsizei mIncrement; - InterpState mState; - ResamplerFunc mResample; + ALsizei mFracOffset{}; + ALsizei mIncrement{}; + InterpState mState{}; + ResamplerFunc mResample{}; - alignas(16) ALfloat mSrcSamples[BUFFERSIZE]; - alignas(16) ALfloat mDstSamples[BUFFERSIZE]; + alignas(16) ALfloat mSrcSamples[BUFFERSIZE]{}; + alignas(16) ALfloat mDstSamples[BUFFERSIZE]{}; struct { alignas(16) ALfloat mPrevSamples[MAX_RESAMPLE_PADDING*2]; @@ -39,11 +39,14 @@ ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframe struct ChannelConverter { - enum DevFmtType mSrcType; - enum DevFmtChannels mSrcChans; - enum DevFmtChannels mDstChans; - - DEF_PLACE_NEWDEL() + DevFmtType mSrcType; + DevFmtChannels mSrcChans; + DevFmtChannels mDstChans; + + ChannelConverter(DevFmtType srctype, DevFmtChannels srcchans, DevFmtChannels dstchans) + : mSrcType(srctype), mSrcChans(srcchans), mDstChans(dstchans) + { } + DEF_NEWDEL(ChannelConverter) }; ChannelConverter *CreateChannelConverter(enum DevFmtType srcType, enum DevFmtChannels srcChans, enum DevFmtChannels dstChans); -- cgit v1.2.3 From e1af866a3df96b5af3173c5ce85ebba25841dc4d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 1 Dec 2018 13:47:56 -0800 Subject: Rework source sample counting for mixing a bit --- Alc/mixvoice.cpp | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index f0ee8bb6..b873a744 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -331,25 +331,33 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize do { /* Figure out how many buffer samples will be needed */ - ALint64 DataSize64{SamplesToDo - OutPos}; - DataSize64 *= increment; - DataSize64 += DataPosFrac+FRACTIONMASK; - DataSize64 >>= FRACTIONBITS; - DataSize64 += MAX_RESAMPLE_PADDING*2; - ALsizei SrcBufferSize{(ALsizei)mini64(DataSize64, BUFFERSIZE)}; - - /* Figure out how many samples we can actually mix from this. */ - DataSize64 = SrcBufferSize; - DataSize64 -= MAX_RESAMPLE_PADDING*2; - DataSize64 <<= FRACTIONBITS; - DataSize64 -= DataPosFrac; - ALsizei DstBufferSize{(ALsizei)mini64((DataSize64+(increment-1)) / increment, - SamplesToDo - OutPos)}; - - /* Some mixers like having a multiple of 4, so try to give that unless - * this is the last update. */ - if(DstBufferSize < SamplesToDo-OutPos) - DstBufferSize &= ~3; + ALsizei DstBufferSize{SamplesToDo - OutPos}; + + /* Calculate the last written dst sample pos. */ + ALint64 DataSize64{DstBufferSize - 1}; + /* Calculate the last read src sample pos. */ + DataSize64 = (DataSize64*increment + DataPosFrac) >> FRACTIONBITS; + /* +1 to get the src sample count, include padding. */ + DataSize64 += 1 + MAX_RESAMPLE_PADDING*2; + + auto SrcBufferSize = static_cast(mini64(DataSize64, BUFFERSIZE+1)); + if(SrcBufferSize > BUFFERSIZE) + { + SrcBufferSize = BUFFERSIZE; + /* If the source buffer got saturated, we can't fill the desired + * dst size. Figure out how many samples we can actually mix from + * this. + */ + DataSize64 = SrcBufferSize - MAX_RESAMPLE_PADDING*2; + DataSize64 = ((DataSize64<(mini64(DataSize64, DstBufferSize)); + + /* Some mixers like having a multiple of 4, so try to give that + * unless this is the last update. + */ + if(DstBufferSize < SamplesToDo-OutPos) + DstBufferSize &= ~3; + } /* It's impossible to have a buffer list item with no entries. */ assert(BufferListItem->num_buffers > 0); -- cgit v1.2.3 From 607fb3e632ecc218a5739709805bc4d83760a1c9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 1 Dec 2018 23:25:34 -0800 Subject: Use a lambda to apply the NFC mixes --- Alc/mixvoice.cpp | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index b873a744..02e31266 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -537,30 +537,29 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize ); else { - ALfloat *nfcsamples = Device->TempBuffer[NFC_DATA_BUF]; - ALsizei chanoffset = 0; - MixSamples(samples, voice->Direct.ChannelsPerOrder[0], voice->Direct.Buffer, parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize ); - chanoffset += voice->Direct.ChannelsPerOrder[0]; -#define APPLY_NFC_MIX(order) \ - if(voice->Direct.ChannelsPerOrder[order] > 0) \ - { \ - NfcFilterProcess##order(&parms->NFCtrlFilter, nfcsamples, samples, \ - DstBufferSize); \ - MixSamples(nfcsamples, voice->Direct.ChannelsPerOrder[order], \ - voice->Direct.Buffer+chanoffset, parms->Gains.Current+chanoffset, \ - parms->Gains.Target+chanoffset, Counter, OutPos, DstBufferSize \ - ); \ - chanoffset += voice->Direct.ChannelsPerOrder[order]; \ - } - APPLY_NFC_MIX(1) - APPLY_NFC_MIX(2) - APPLY_NFC_MIX(3) -#undef APPLY_NFC_MIX + + ALfloat *nfcsamples{Device->TempBuffer[NFC_DATA_BUF]}; + ALsizei chanoffset{voice->Direct.ChannelsPerOrder[0]}; + using FilterProc = void(NfcFilter*,ALfloat*,const ALfloat*,ALsizei); + auto apply_nfc = [voice,parms,samples,DstBufferSize,Counter,OutPos,&chanoffset,nfcsamples](FilterProc &process, ALsizei order) -> void + { + if(voice->Direct.ChannelsPerOrder[order] < 1) + return; + process(&parms->NFCtrlFilter, nfcsamples, samples, DstBufferSize); + MixSamples(nfcsamples, voice->Direct.ChannelsPerOrder[order], + voice->Direct.Buffer+chanoffset, parms->Gains.Current+chanoffset, + parms->Gains.Target+chanoffset, Counter, OutPos, DstBufferSize + ); + chanoffset += voice->Direct.ChannelsPerOrder[order]; + }; + apply_nfc(NfcFilterProcess1, 1); + apply_nfc(NfcFilterProcess2, 2); + apply_nfc(NfcFilterProcess3, 3); } } else -- cgit v1.2.3 From 4e17ad3ec03f171509ed58a5cbb997b3955bc5ce Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 2 Dec 2018 13:35:07 -0800 Subject: Avoid a few more explicit loops --- Alc/mixvoice.cpp | 84 ++++++++++++++++++++++++-------------------------- OpenAL32/Include/alu.h | 2 +- 2 files changed, 42 insertions(+), 44 deletions(-) diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 02e31266..fdff0eca 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -392,65 +392,62 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize BufferLoopItem = nullptr; ALsizei CompLen{0}; - for(ALsizei i{0};i < BufferListItem->num_buffers;i++) + auto load_buffer = [DataPosInt,&SrcData,NumChannels,SampleSize,chan,FilledAmt,SizeToDo,&CompLen](const ALbuffer *buffer) -> void { - const ALbuffer *buffer = BufferListItem->buffers[i]; - const ALbyte *Data = buffer->mData.data(); - ALsizei DataSize; - if(DataPosInt >= buffer->SampleLen) - continue; + return; /* Load what's left to play from the buffer */ - DataSize = mini(SizeToDo, buffer->SampleLen - DataPosInt); + ALsizei DataSize{mini(SizeToDo, buffer->SampleLen - DataPosInt)}; CompLen = maxi(CompLen, DataSize); + const ALbyte *Data{buffer->mData.data()}; LoadSamples(&SrcData[FilledAmt], &Data[(DataPosInt*NumChannels + chan)*SampleSize], NumChannels, buffer->FmtType, DataSize ); - } + }; + auto buffers_end = BufferListItem->buffers + BufferListItem->num_buffers; + std::for_each(BufferListItem->buffers, buffers_end, load_buffer); FilledAmt += CompLen; } else { - const ALsizei LoopSize{LoopEnd - LoopStart}; - ALsizei SizeToDo = mini(SrcBufferSize - FilledAmt, LoopEnd - DataPosInt); + const ALsizei SizeToDo{mini(SrcBufferSize - FilledAmt, LoopEnd - DataPosInt)}; ALsizei CompLen{0}; - for(ALsizei i{0};i < BufferListItem->num_buffers;i++) + auto load_buffer = [DataPosInt,&SrcData,NumChannels,SampleSize,chan,FilledAmt,SizeToDo,&CompLen](const ALbuffer *buffer) -> void { - const ALbuffer *buffer = BufferListItem->buffers[i]; - const ALbyte *Data = buffer->mData.data(); - ALsizei DataSize; - if(DataPosInt >= buffer->SampleLen) - continue; + return; /* Load what's left of this loop iteration */ - DataSize = mini(SizeToDo, buffer->SampleLen - DataPosInt); + ALsizei DataSize{mini(SizeToDo, buffer->SampleLen - DataPosInt)}; CompLen = maxi(CompLen, DataSize); + const ALbyte *Data{buffer->mData.data()}; LoadSamples(&SrcData[FilledAmt], &Data[(DataPosInt*NumChannels + chan)*SampleSize], NumChannels, buffer->FmtType, DataSize ); - } + }; + auto buffers_end = BufferListItem->buffers + BufferListItem->num_buffers; + std::for_each(BufferListItem->buffers, buffers_end, load_buffer); FilledAmt += CompLen; + const ALsizei LoopSize{LoopEnd - LoopStart}; while(SrcBufferSize > FilledAmt) { - const ALsizei SizeToDo = mini(SrcBufferSize - FilledAmt, LoopSize); + const ALsizei SizeToDo{mini(SrcBufferSize - FilledAmt, LoopSize)}; CompLen = 0; - for(ALsizei i{0};i < BufferListItem->num_buffers;i++) + auto load_buffer_loop = [LoopStart,&SrcData,NumChannels,SampleSize,chan,FilledAmt,SizeToDo,&CompLen](const ALbuffer *buffer) -> void { - const ALbuffer *buffer = BufferListItem->buffers[i]; const ALbyte *Data = buffer->mData.data(); ALsizei DataSize; if(LoopStart >= buffer->SampleLen) - continue; + return; DataSize = mini(SizeToDo, buffer->SampleLen - LoopStart); CompLen = maxi(CompLen, DataSize); @@ -459,7 +456,8 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize &Data[(LoopStart*NumChannels + chan)*SampleSize], NumChannels, buffer->FmtType, DataSize ); - } + }; + std::for_each(BufferListItem->buffers, buffers_end, load_buffer_loop); FilledAmt += CompLen; } } @@ -482,24 +480,24 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize const ALsizei SizeToDo{SrcBufferSize - FilledAmt}; ALsizei CompLen{0}; - for(ALsizei i{0};i < tmpiter->num_buffers;i++) + auto load_buffer = [pos,&SrcData,NumChannels,SampleSize,chan,FilledAmt,SizeToDo,&CompLen](const ALbuffer *buffer) -> void { - const ALbuffer *ALBuffer{tmpiter->buffers[i]}; - ALsizei DataSize{ALBuffer ? ALBuffer->SampleLen : 0}; - - if(pos >= DataSize) - continue; - - const ALbyte *Data{ALBuffer->mData.data()}; - Data += (pos*NumChannels + chan)*SampleSize; + ALsizei DataSize{buffer ? buffer->SampleLen : 0}; + if(pos >= DataSize) return; DataSize = mini(SizeToDo, DataSize - pos); CompLen = maxi(CompLen, DataSize); + const ALbyte *Data{buffer->mData.data()}; + Data += (pos*NumChannels + chan)*SampleSize; + LoadSamples(&SrcData[FilledAmt], Data, NumChannels, - ALBuffer->FmtType, DataSize); - } + buffer->FmtType, DataSize); + }; + auto buffers_end = tmpiter->buffers + tmpiter->num_buffers; + std::for_each(tmpiter->buffers, buffers_end, load_buffer); FilledAmt += CompLen; + if(SrcBufferSize <= FilledAmt) break; pos = 0; @@ -649,25 +647,25 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize } } - for(ALsizei send{0};send < Device->NumAuxSends;send++) + ALfloat (&FilterBuf)[BUFFERSIZE] = Device->TempBuffer[FILTERED_BUF]; + auto mix_send = [Counter,OutPos,DstBufferSize,chan,ResampledData,&FilterBuf](ALvoice::SendData &send) -> void { - SendParams *parms = &voice->Send[send].Params[chan]; - - if(!voice->Send[send].Buffer) - continue; + if(!send.Buffer) + return; + SendParams *parms = &send.Params[chan]; const ALfloat *samples{DoFilters(&parms->LowPass, &parms->HighPass, - Device->TempBuffer[FILTERED_BUF], ResampledData, DstBufferSize, - voice->Send[send].FilterType + FilterBuf, ResampledData, DstBufferSize, send.FilterType )}; if(!Counter) std::copy(std::begin(parms->Gains.Target), std::end(parms->Gains.Target), std::begin(parms->Gains.Current)); - MixSamples(samples, voice->Send[send].Channels, voice->Send[send].Buffer, + MixSamples(samples, send.Channels, send.Buffer, parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize ); - } + }; + std::for_each(voice->Send, voice->Send+Device->NumAuxSends, mix_send); } /* Update positions */ DataPosFrac += increment*DstBufferSize; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 36d3be84..e7f84423 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -259,7 +259,7 @@ struct ALvoice { ALsizei ChannelsPerOrder[MAX_AMBI_ORDER+1]; } Direct; - struct { + struct SendData { int FilterType; SendParams Params[MAX_INPUT_CHANNELS]; -- cgit v1.2.3 From 60254488e9faa2934e9d261328a3c0359056bdd0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 2 Dec 2018 14:36:53 -0800 Subject: Add a couple missing source lock guards --- OpenAL32/alSource.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 11cea945..4cc3526b 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -2855,6 +2855,7 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Pausing %d sources", n); if(n == 0) return; + std::lock_guard _{context->SourceLock}; for(ALsizei i{0};i < n;i++) { if(!LookupSource(context.get(), sources[i])) @@ -2890,6 +2891,7 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Stopping %d sources", n); if(n == 0) return; + std::lock_guard _{context->SourceLock}; for(ALsizei i{0};i < n;i++) { if(!LookupSource(context.get(), sources[i])) @@ -2933,6 +2935,7 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Rewinding %d sources", n); if(n == 0) return; + std::lock_guard _{context->SourceLock}; for(ALsizei i{0};i < n;i++) { if(!LookupSource(context.get(), sources[i])) -- cgit v1.2.3 From 45b65366bb2ba6c11756e2509589e310b9f0df88 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 2 Dec 2018 15:29:26 -0800 Subject: Improve some checks for compiler analysis --- Alc/mixvoice.cpp | 3 ++- OpenAL32/alAuxEffectSlot.cpp | 1 + OpenAL32/alSource.cpp | 18 +++++++++--------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index fdff0eca..d19a4861 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -482,7 +482,8 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize ALsizei CompLen{0}; auto load_buffer = [pos,&SrcData,NumChannels,SampleSize,chan,FilledAmt,SizeToDo,&CompLen](const ALbuffer *buffer) -> void { - ALsizei DataSize{buffer ? buffer->SampleLen : 0}; + if(!buffer) return; + ALsizei DataSize{buffer->SampleLen}; if(pos >= DataSize) return; DataSize = mini(SizeToDo, DataSize - pos); diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index 7f05187e..ad33fe50 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -577,6 +577,7 @@ void EffectState::DecRef() noexcept ALenum InitEffectSlot(ALeffectslot *slot) { EffectStateFactory *factory{getFactoryByType(slot->Effect.Type)}; + if(!factory) return AL_INVALID_VALUE; slot->Effect.State = factory->create(); if(!slot->Effect.State) return AL_OUT_OF_MEMORY; diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 4cc3526b..463d2438 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -2977,11 +2977,11 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu std::lock_guard _{context->SourceLock}; ALsource *source{LookupSource(context.get(),src)}; - if(!source) + if(UNLIKELY(!source)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); /* Can't queue on a Static Source */ - if(source->SourceType == AL_STATIC) + if(UNLIKELY(source->SourceType == AL_STATIC)) SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src); /* Check for a valid Buffer, for its frequency and format */ @@ -3094,11 +3094,11 @@ AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, co std::lock_guard _{context->SourceLock}; ALsource *source{LookupSource(context.get(),src)}; - if(!source) + if(UNLIKELY(!source)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); /* Can't queue on a Static Source */ - if(source->SourceType == AL_STATIC) + if(UNLIKELY(source->SourceType == AL_STATIC)) SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src); /* Check for a valid Buffer, for its frequency and format */ @@ -3202,12 +3202,12 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint std::lock_guard _{context->SourceLock}; ALsource *source{LookupSource(context.get(),src)}; - if(!source) + if(UNLIKELY(!source)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); - if(source->Looping) + if(UNLIKELY(source->Looping)) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing from looping source %u", src); - if(source->SourceType != AL_STREAMING) + if(UNLIKELY(source->SourceType != AL_STREAMING)) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing from a non-streaming source %u", src); @@ -3219,7 +3219,7 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint Current = voice->current_buffer.load(std::memory_order_relaxed); else if(source->state == AL_INITIAL) Current = BufferList; - if(BufferList == Current) + if(UNLIKELY(BufferList == Current)) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing pending buffers"); ALsizei i{BufferList->num_buffers}; @@ -3229,7 +3229,7 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint * trying to unqueue pending buffers. */ ALbufferlistitem *next{BufferList->next.load(std::memory_order_relaxed)}; - if(!next || next == Current) + if(UNLIKELY(!next) || UNLIKELY(next == Current)) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing pending buffers"); BufferList = next; -- cgit v1.2.3 From 85e83bbdff9f07132b9fcdddeeccb9d252a13b8c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 2 Dec 2018 19:34:09 -0800 Subject: Use a std::string for the source state change message --- OpenAL32/event.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index 4980abee..d263acc5 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -45,17 +45,14 @@ static int EventThread(ALCcontext *context) { if(!(enabledevts&EventType_SourceStateChange)) continue; - char msg[1024]{}; - int msglen{snprintf(msg, sizeof(msg), "Source ID %u state changed to %s", - evt.u.srcstate.id, - (evt.u.srcstate.state==AL_INITIAL) ? "AL_INITIAL" : + std::string msg{"Source ID " + std::to_string(evt.u.srcstate.id)}; + msg += " state has changed to "; + msg += (evt.u.srcstate.state==AL_INITIAL) ? "AL_INITIAL" : (evt.u.srcstate.state==AL_PLAYING) ? "AL_PLAYING" : (evt.u.srcstate.state==AL_PAUSED) ? "AL_PAUSED" : - (evt.u.srcstate.state==AL_STOPPED) ? "AL_STOPPED" : "" - )}; - if(msglen < 1) msglen = strlen(msg); + (evt.u.srcstate.state==AL_STOPPED) ? "AL_STOPPED" : ""; context->EventCb(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, evt.u.srcstate.id, - evt.u.srcstate.state, msglen, msg, context->EventParam + evt.u.srcstate.state, msg.length(), msg.c_str(), context->EventParam ); } else if((enabledevts&evt.EnumType) == evt.EnumType) -- cgit v1.2.3 From 31b54eb86a25457e561f4e27324163def0a8bd66 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 3 Dec 2018 01:41:52 -0800 Subject: Avoid a few more explicit loops --- OpenAL32/alSource.cpp | 102 ++++++++++++++++++++++++++++---------------------- 1 file changed, 58 insertions(+), 44 deletions(-) diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 463d2438..42f05131 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -2682,44 +2682,51 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) if(n == 0) return; std::lock_guard _{context->SourceLock}; - for(ALsizei i{0};i < n;i++) - { - if(!LookupSource(context.get(), sources[i])) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); - } + auto sources_end = sources+n; + auto bad_sid = std::find_if_not(sources, sources_end, + [&context](ALuint sid) -> bool + { + ALsource *source{LookupSource(context.get(), sid)}; + return LIKELY(source != nullptr); + } + ); + if(UNLIKELY(bad_sid != sources+n)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", *bad_sid); ALCdevice *device{context->Device}; ALCdevice_Lock(device); /* If the device is disconnected, go right to stopped. */ - if(!device->Connected.load(std::memory_order_acquire)) + if(UNLIKELY(!device->Connected.load(std::memory_order_acquire))) { /* TODO: Send state change event? */ - for(ALsizei i{0};i < n;i++) - { - ALsource *source{LookupSource(context.get(), sources[i])}; - source->OffsetType = AL_NONE; - source->Offset = 0.0; - source->state = AL_STOPPED; - } + std::for_each(sources, sources_end, + [&context](ALuint sid) -> void + { + ALsource *source{LookupSource(context.get(), sid)}; + source->OffsetType = AL_NONE; + source->Offset = 0.0; + source->state = AL_STOPPED; + } + ); ALCdevice_Unlock(device); return; } while(n > context->MaxVoices-context->VoiceCount.load(std::memory_order_relaxed)) { - ALsizei newcount = context->MaxVoices << 1; - if(context->MaxVoices >= newcount) + if(UNLIKELY(context->MaxVoices > std::numeric_limits::max()>>1)) { ALCdevice_Unlock(device); SETERR_RETURN(context.get(), AL_OUT_OF_MEMORY,, - "Overflow increasing voice count %d -> %d", context->MaxVoices, newcount); + "Overflow increasing voice count from %d", context->MaxVoices); } + ALsizei newcount = context->MaxVoices << 1; AllocateVoices(context.get(), newcount, device->NumAuxSends); } - for(ALsizei i{0};i < n;i++) + auto start_source = [&context,device](ALuint sid) -> void { - ALsource *source{LookupSource(context.get(), sources[i])}; + ALsource *source{LookupSource(context.get(), sid)}; /* Check that there is a queue containing at least one valid, non zero * length buffer. */ @@ -2742,34 +2749,34 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) source->state = AL_STOPPED; SendStateChangeEvent(context.get(), source->id, AL_STOPPED); } - continue; + return; } ALvoice *voice{GetSourceVoice(source, context.get())}; switch(GetSourceState(source, voice)) { - case AL_PLAYING: - assert(voice != nullptr); - /* A source that's already playing is restarted from the beginning. */ - voice->current_buffer.store(BufferList, std::memory_order_relaxed); - voice->position.store(0u, std::memory_order_relaxed); - voice->position_fraction.store(0, std::memory_order_release); - continue; - - case AL_PAUSED: - assert(voice != nullptr); - /* A source that's paused simply resumes. */ - voice->Playing.store(true, std::memory_order_release); - source->state = AL_PLAYING; - SendStateChangeEvent(context.get(), source->id, AL_PLAYING); - continue; - - default: - break; + case AL_PLAYING: + assert(voice != nullptr); + /* A source that's already playing is restarted from the beginning. */ + voice->current_buffer.store(BufferList, std::memory_order_relaxed); + voice->position.store(0u, std::memory_order_relaxed); + voice->position_fraction.store(0, std::memory_order_release); + return; + + case AL_PAUSED: + assert(voice != nullptr); + /* A source that's paused simply resumes. */ + voice->Playing.store(true, std::memory_order_release); + source->state = AL_PLAYING; + SendStateChangeEvent(context.get(), source->id, AL_PLAYING); + return; + + default: + assert(voice == nullptr); + break; } /* Look for an unused voice to play this source with. */ - assert(voice == nullptr); auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed); auto voice_iter = std::find_if(context->Voices, voices_end, [](const ALvoice *voice) noexcept -> bool @@ -2821,15 +2828,21 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) voice->Flags = start_fading ? VOICE_IS_FADING : 0; if(source->SourceType == AL_STATIC) voice->Flags |= VOICE_IS_STATIC; - memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])*voice->NumChannels); - for(ALsizei j{0};j < device->NumAuxSends;j++) - memset(voice->Send[j].Params, 0, sizeof(voice->Send[j].Params[0])*voice->NumChannels); + + std::fill_n(std::begin(voice->Direct.Params), voice->NumChannels, DirectParams{}); + std::for_each(voice->Send+0, voice->Send+source->Send.size(), + [voice](ALvoice::SendData &send) -> void + { std::fill_n(std::begin(send.Params), voice->NumChannels, SendParams{}); } + ); + if(device->AvgSpeakerDist > 0.0f) { ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / (device->AvgSpeakerDist * device->Frequency); - for(ALsizei j{0};j < voice->NumChannels;j++) - NfcFilterCreate(&voice->Direct.Params[j].NFCtrlFilter, 0.0f, w1); + std::for_each(voice->Direct.Params+0, voice->Direct.Params+voice->NumChannels, + [w1](DirectParams &parms) -> void + { NfcFilterCreate(&parms.NFCtrlFilter, 0.0f, w1); } + ); } voice->SourceID.store(source->id, std::memory_order_relaxed); @@ -2838,7 +2851,8 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) source->VoiceIdx = vidx; SendStateChangeEvent(context.get(), source->id, AL_PLAYING); - } + }; + std::for_each(sources, sources_end, start_source); ALCdevice_Unlock(device); } -- cgit v1.2.3 From a0967967de999d1381e827aa4a73fc9e80ec031b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 4 Dec 2018 14:48:08 -0800 Subject: Read atomic variables in the reverse order they're set --- Alc/alu.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 197d554d..facb70ed 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1515,10 +1515,9 @@ void ProcessContext(ALCcontext *ctx, ALsizei SamplesToDo) std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire), [SamplesToDo,ctx](ALvoice *voice) -> void { - ALuint sid{voice->SourceID.load(std::memory_order_acquire)}; - if(!sid) return; - if(!voice->Playing.load(std::memory_order_relaxed) || voice->Step < 1) - return; + if(!voice->Playing.load(std::memory_order_acquire)) return; + ALuint sid{voice->SourceID.load(std::memory_order_relaxed)}; + if(!sid || voice->Step < 1) return; if(!MixSource(voice, sid, ctx, SamplesToDo)) { @@ -1841,9 +1840,9 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire), [ctx](ALvoice *voice) -> void { + if(!voice->Playing.load(std::memory_order_acquire)) return; ALuint sid{voice->SourceID.load(std::memory_order_relaxed)}; - if(!sid || !voice->Playing.load(std::memory_order_relaxed)) - return; + if(!sid) return; voice->SourceID.store(0u, std::memory_order_relaxed); voice->Playing.store(false, std::memory_order_release); -- cgit v1.2.3 From f79b0e24d4cc5c1d4e9aa289b7eb2caba750bb9a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 4 Dec 2018 15:30:39 -0800 Subject: Avoid a few more explicit loops --- Alc/alu.cpp | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index facb70ed..de46633a 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -61,11 +61,9 @@ ALboolean OverrideReverbSpeedOfSound = AL_FALSE; namespace { -void ClearArray(ALfloat f[MAX_OUTPUT_CHANNELS]) +void ClearArray(ALfloat (&f)[MAX_OUTPUT_CHANNELS]) { - size_t i; - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - f[i] = 0.0f; + std::fill(std::begin(f), std::end(f), 0.0f); } struct ChanMap { @@ -568,17 +566,21 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev break; } - for(c = 0;c < num_channels;c++) - { - memset(&voice->Direct.Params[c].Hrtf.Target, 0, - sizeof(voice->Direct.Params[c].Hrtf.Target)); - ClearArray(voice->Direct.Params[c].Gains.Target); - } - for(i = 0;i < NumSends;i++) - { - for(c = 0;c < num_channels;c++) - ClearArray(voice->Send[i].Params[c].Gains.Target); - } + std::for_each(std::begin(voice->Direct.Params), std::begin(voice->Direct.Params)+num_channels, + [](DirectParams ¶ms) -> void + { + params.Hrtf.Target = HrtfParams{}; + ClearArray(params.Gains.Target); + } + ); + std::for_each(voice->Send+0, voice->Send+NumSends, + [num_channels](ALvoice::SendData &send) -> void + { + std::for_each(std::begin(send.Params), std::begin(send.Params)+num_channels, + [](SendParams ¶ms) -> void { ClearArray(params.Gains.Target); } + ); + } + ); voice->Flags &= ~(VOICE_HAS_HRTF | VOICE_HAS_NFC); if(isbformat) @@ -608,8 +610,9 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev /* Only need to adjust the first channel of a B-Format source. */ NfcFilterAdjust(&voice->Direct.Params[0].NFCtrlFilter, w0); - for(i = 0;i < MAX_AMBI_ORDER+1;i++) - voice->Direct.ChannelsPerOrder[i] = Device->NumChannelsPerOrder[i]; + std::copy(std::begin(Device->NumChannelsPerOrder), + std::end(Device->NumChannelsPerOrder), + std::begin(voice->Direct.ChannelsPerOrder)); voice->Flags |= VOICE_HAS_NFC; } @@ -650,8 +653,8 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev voice->Direct.ChannelsPerOrder[0] = 1; voice->Direct.ChannelsPerOrder[1] = mini(voice->Direct.Channels-1, 3); - for(i = 2;i < MAX_AMBI_ORDER+1;i++) - voice->Direct.ChannelsPerOrder[i] = 0; + std::fill(std::begin(voice->Direct.ChannelsPerOrder)+2, + std::end(voice->Direct.ChannelsPerOrder), 0); voice->Flags |= VOICE_HAS_NFC; } -- cgit v1.2.3 From 64099105437741233255704733cd69c24b1579ea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 4 Dec 2018 16:33:26 -0800 Subject: Handle EventType_BufferCompleted uniquely --- Alc/mixvoice.cpp | 27 +++++++++------------------ OpenAL32/Include/alMain.h | 4 ++++ OpenAL32/event.cpp | 11 +++++++++++ 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index d19a4861..04bb1130 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -195,19 +195,6 @@ void aluInitMixer(void) namespace { -static void SendAsyncEvent(ALCcontext *context, ALuint enumtype, ALenum type, - ALuint objid, ALuint param, const char *msg) -{ - AsyncEvent evt = ASYNC_EVENT(enumtype); - evt.u.user.type = type; - evt.u.user.id = objid; - evt.u.user.param = param; - strcpy(evt.u.user.msg, msg); - if(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) == 1) - context->EventSem.post(); -} - - /* Base template left undefined. Should be marked =delete, but Clang 3.8.1 * chokes on that given the inline specializations. */ @@ -237,8 +224,8 @@ inline void LoadSampleArray(ALfloat *RESTRICT dst, const void *src, ALint srcste dst[i] += LoadSample(ssrc[i*srcstep]); } -static void LoadSamples(ALfloat *RESTRICT dst, const ALvoid *RESTRICT src, ALint srcstep, - enum FmtType srctype, ALsizei samples) +void LoadSamples(ALfloat *RESTRICT dst, const ALvoid *RESTRICT src, ALint srcstep, FmtType srctype, + ALsizei samples) { #define HANDLE_FMT(T) \ case T: LoadSampleArray(dst, src, srcstep, samples); break @@ -734,9 +721,13 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize /* Send any events now, after the position/buffer info was updated. */ ALbitfieldSOFT enabledevt{Context->EnabledEvts.load(std::memory_order_acquire)}; if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) - SendAsyncEvent(Context, EventType_BufferCompleted, - AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, SourceID, buffers_done, "Buffer completed" - ); + { + AsyncEvent evt{ASYNC_EVENT(EventType_BufferCompleted)}; + evt.u.bufcomp.id = SourceID; + evt.u.bufcomp.count = buffers_done; + if(ll_ringbuffer_write(Context->AsyncEvents, &evt, 1) == 1) + Context->EventSem.post(); + } return isplaying; } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index bff3d52e..75dc6c74 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -849,6 +849,10 @@ struct AsyncEvent { ALuint id; ALenum state; } srcstate; + struct { + ALuint id; + ALsizei count; + } bufcomp; struct { ALenum type; ALuint id; diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index d263acc5..1a4e1df0 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -55,6 +55,17 @@ static int EventThread(ALCcontext *context) evt.u.srcstate.state, msg.length(), msg.c_str(), context->EventParam ); } + else if(evt.EnumType == EventType_BufferCompleted) + { + if(!(enabledevts&EventType_BufferCompleted)) + continue; + std::string msg{std::to_string(evt.u.bufcomp.count)}; + if(evt.u.bufcomp.count == 1) msg += " buffer completed"; + else msg += " buffers completed"; + context->EventCb(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, evt.u.bufcomp.id, + evt.u.bufcomp.count, msg.length(), msg.c_str(), context->EventParam + ); + } else if((enabledevts&evt.EnumType) == evt.EnumType) context->EventCb(evt.u.user.type, evt.u.user.id, evt.u.user.param, (ALsizei)strlen(evt.u.user.msg), evt.u.user.msg, context->EventParam -- cgit v1.2.3 From a94bfd3ec9af053cd4ce777574c2a95c432f5164 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 4 Dec 2018 16:38:22 -0800 Subject: Increase the async event queue size --- Alc/alc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 03cbcd53..9e7f2d95 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2548,7 +2548,7 @@ static ALvoid InitContext(ALCcontext *Context) listener.Params.mDistanceModel = Context->mDistanceModel; - Context->AsyncEvents = ll_ringbuffer_create(63, sizeof(AsyncEvent), false); + Context->AsyncEvents = ll_ringbuffer_create(511, sizeof(AsyncEvent), false); StartEventThrd(Context); } -- cgit v1.2.3 From 3866c9f9414e91e760f397d0d01514a411c77bcd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 4 Dec 2018 19:45:11 -0800 Subject: Avoid more explicit loops --- Alc/alc.cpp | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 9e7f2d95..0c6bd5dc 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2621,7 +2621,7 @@ ALCcontext_struct::~ALCcontext_struct() } TRACE("Freed " SZFMT " voice property object%s\n", count, (count==1)?"":"s"); - std::for_each(Voices, Voices + VoiceCount.load(std::memory_order_relaxed), DeinitVoice); + std::for_each(Voices, Voices + MaxVoices, DeinitVoice); al_free(Voices); Voices = nullptr; VoiceCount.store(0, std::memory_order_relaxed); @@ -2770,7 +2770,7 @@ ContextRef GetContextRef(void) void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) { ALCdevice *device{context->Device}; - ALsizei num_sends{device->NumAuxSends}; + const ALsizei num_sends{device->NumAuxSends}; if(num_voices == context->MaxVoices && num_sends == old_sends) return; @@ -2779,27 +2779,26 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) * property set (including the dynamically-sized Send[] array) in one * chunk. */ - size_t sizeof_voice{RoundUp(FAM_SIZE(ALvoice, Send, num_sends), 16)}; - size_t size{sizeof(ALvoice*) + sizeof_voice}; + const size_t sizeof_voice{RoundUp(FAM_SIZE(ALvoice, Send, num_sends), 16)}; + const size_t size{sizeof(ALvoice*) + sizeof_voice}; auto voices = static_cast(al_calloc(16, RoundUp(size*num_voices, 16))); auto voice = reinterpret_cast((char*)voices + RoundUp(num_voices*sizeof(ALvoice*), 16)); - ALsizei v{0}; + auto viter = voices; if(context->Voices) { const ALsizei v_count = mini(context->VoiceCount.load(std::memory_order_relaxed), num_voices); const ALsizei s_count = mini(old_sends, num_sends); - for(;v < v_count;v++) + /* Copy the old voice data to the new storage. */ + auto copy_voice = [&voice,sizeof_voice,s_count](ALvoice *old_voice) -> ALvoice* { - ALvoice *old_voice{context->Voices[v]}; voice = new (voice) ALvoice{}; - /* Copy the old voice data and source property set to the new - * storage. Make sure the old voice's Update (if any) is cleared so - * it doesn't get deleted on deinit. + /* Make sure the old voice's Update (if any) is cleared so it + * doesn't get deleted on deinit. */ voice->Update.store(old_voice->Update.exchange(nullptr, std::memory_order_relaxed), std::memory_order_relaxed); @@ -2844,23 +2843,25 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) std::copy_n(old_voice->Send, s_count, voice->Send); /* Set this voice's reference. */ - voices[v] = voice; - + ALvoice *ret = voice; /* Increment pointer to the next storage space. */ voice = reinterpret_cast((char*)voice + sizeof_voice); - } + return ret; + }; + viter = std::transform(context->Voices, context->Voices+v_count, viter, copy_voice); + /* Deinit old voices. */ - auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed); + auto voices_end = context->Voices + context->MaxVoices; std::for_each(context->Voices, voices_end, DeinitVoice); } - /* Finish setting the voices' property set pointers and references. */ - for(;v < num_voices;v++) + /* Finish setting the voices and references. */ + auto init_voice = [&voice,sizeof_voice]() -> ALvoice* { - voice = new (voice) ALvoice{}; - voices[v] = voice; - + ALvoice *ret = new (voice) ALvoice{}; voice = reinterpret_cast((char*)voice + sizeof_voice); - } + return ret; + }; + std::generate(viter, voices+num_voices, init_voice); al_free(context->Voices); context->Voices = voices; -- cgit v1.2.3 From 2a30ae3807134be37cf79139e7e7943df5b1bf64 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 4 Dec 2018 20:35:23 -0800 Subject: Avoid some more explicit loops in the filters --- Alc/filters/filter.cpp | 13 +++++----- Alc/filters/nfc.cpp | 35 ++++++++++++------------- Alc/filters/splitter.cpp | 66 +++++++++++++++++++++--------------------------- 3 files changed, 53 insertions(+), 61 deletions(-) diff --git a/Alc/filters/filter.cpp b/Alc/filters/filter.cpp index 6099cf13..5dc5d9b4 100644 --- a/Alc/filters/filter.cpp +++ b/Alc/filters/filter.cpp @@ -92,14 +92,13 @@ void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, void BiquadFilter_processC(BiquadFilter *filter, ALfloat *RESTRICT dst, const ALfloat *RESTRICT src, ALsizei numsamples) { - const ALfloat a1 = filter->a1; - const ALfloat a2 = filter->a2; const ALfloat b0 = filter->b0; const ALfloat b1 = filter->b1; const ALfloat b2 = filter->b2; + const ALfloat a1 = filter->a1; + const ALfloat a2 = filter->a2; ALfloat z1 = filter->z1; ALfloat z2 = filter->z2; - ALsizei i; ASSUME(numsamples > 0); @@ -111,14 +110,14 @@ void BiquadFilter_processC(BiquadFilter *filter, ALfloat *RESTRICT dst, const AL * * See: http://www.earlevel.com/main/2003/02/28/biquads/ */ - for(i = 0;i < numsamples;i++) + auto proc_sample = [b0,b1,b2,a1,a2,&z1,&z2](ALfloat input) noexcept -> ALfloat { - ALfloat input = src[i]; ALfloat output = input*b0 + z1; z1 = input*b1 - output*a1 + z2; z2 = input*b2 - output*a2; - dst[i] = output; - } + return output; + }; + std::transform(src, src+numsamples, dst, proc_sample); filter->z1 = z1; filter->z2 = z2; diff --git a/Alc/filters/nfc.cpp b/Alc/filters/nfc.cpp index 8d61bb37..11a7b467 100644 --- a/Alc/filters/nfc.cpp +++ b/Alc/filters/nfc.cpp @@ -2,6 +2,9 @@ #include "config.h" #include "nfc.h" + +#include + #include "alMain.h" #include @@ -228,18 +231,17 @@ void NfcFilterProcess1(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRIC const float b1 = nfc->first.b1; const float a1 = nfc->first.a1; float z1 = nfc->first.z[0]; - int i; ASSUME(count > 0); - for(i = 0;i < count;i++) + auto proc_sample = [gain,b1,a1,&z1](float in) noexcept -> float { - float y = src[i]*gain - a1*z1; + float y = in*gain - a1*z1; float out = y + b1*z1; z1 += y; - - dst[i] = out; - } + return out; + }; + std::transform(src, src+count, dst, proc_sample); nfc->first.z[0] = z1; } @@ -252,19 +254,18 @@ void NfcFilterProcess2(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRIC const float a2 = nfc->second.a2; float z1 = nfc->second.z[0]; float z2 = nfc->second.z[1]; - int i; ASSUME(count > 0); - for(i = 0;i < count;i++) + auto proc_sample = [gain,b1,b2,a1,a2,&z1,&z2](float in) noexcept -> float { - float y = src[i]*gain - a1*z1 - a2*z2; + float y = in*gain - a1*z1 - a2*z2; float out = y + b1*z1 + b2*z2; z2 += z1; z1 += y; - - dst[i] = out; - } + return out; + }; + std::transform(src, src+count, dst, proc_sample); nfc->second.z[0] = z1; nfc->second.z[1] = z2; } @@ -281,13 +282,12 @@ void NfcFilterProcess3(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRIC float z1 = nfc->third.z[0]; float z2 = nfc->third.z[1]; float z3 = nfc->third.z[2]; - int i; ASSUME(count > 0); - for(i = 0;i < count;i++) + auto proc_sample = [gain,b1,b2,b3,a1,a2,a3,&z1,&z2,&z3](float in) noexcept -> float { - float y = src[i]*gain - a1*z1 - a2*z2; + float y = in*gain - a1*z1 - a2*z2; float out = y + b1*z1 + b2*z2; z2 += z1; z1 += y; @@ -296,8 +296,9 @@ void NfcFilterProcess3(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRIC out = y + b3*z3; z3 += y; - dst[i] = out; - } + return out; + }; + std::transform(src, src+count, dst, proc_sample); nfc->third.z[0] = z1; nfc->third.z[1] = z2; nfc->third.z[2] = z3; diff --git a/Alc/filters/splitter.cpp b/Alc/filters/splitter.cpp index 6aed7493..570f5e2c 100644 --- a/Alc/filters/splitter.cpp +++ b/Alc/filters/splitter.cpp @@ -3,15 +3,18 @@ #include "splitter.h" +#include +#include + #include "math_defs.h" void bandsplit_init(BandSplitter *splitter, ALfloat f0norm) { ALfloat w = f0norm * F_TAU; - ALfloat cw = cosf(w); + ALfloat cw = std::cos(w); if(cw > FLT_EPSILON) - splitter->coeff = (sinf(w) - 1.0f) / cw; + splitter->coeff = (std::sin(w) - 1.0f) / cw; else splitter->coeff = cw * -0.5f; @@ -30,51 +33,46 @@ void bandsplit_clear(BandSplitter *splitter) void bandsplit_process(BandSplitter *splitter, ALfloat *RESTRICT hpout, ALfloat *RESTRICT lpout, const ALfloat *input, ALsizei count) { - ALfloat lp_coeff, hp_coeff, lp_y, hp_y, d; - ALfloat lp_z1, lp_z2, hp_z1; - ALsizei i; - ASSUME(count > 0); - hp_coeff = splitter->coeff; - lp_coeff = splitter->coeff*0.5f + 0.5f; - lp_z1 = splitter->lp_z1; - lp_z2 = splitter->lp_z2; - hp_z1 = splitter->hp_z1; - for(i = 0;i < count;i++) + const float ap_coeff{splitter->coeff}; + const float lp_coeff{splitter->coeff*0.5f + 0.5f}; + float lp_z1{splitter->lp_z1}; + float lp_z2{splitter->lp_z2}; + float ap_z1{splitter->hp_z1}; + auto proc_sample = [ap_coeff,lp_coeff,&lp_z1,&lp_z2,&ap_z1,&lpout](const float in) noexcept -> float { - ALfloat in = input[i]; - /* Low-pass sample processing. */ - d = (in - lp_z1) * lp_coeff; - lp_y = lp_z1 + d; + float d{(in - lp_z1) * lp_coeff}; + float lp_y{lp_z1 + d}; lp_z1 = lp_y + d; d = (lp_y - lp_z2) * lp_coeff; lp_y = lp_z2 + d; lp_z2 = lp_y + d; - lpout[i] = lp_y; + *(lpout++) = lp_y; /* All-pass sample processing. */ - hp_y = in*hp_coeff + hp_z1; - hp_z1 = in - hp_y*hp_coeff; + float ap_y{in*ap_coeff + ap_z1}; + ap_z1 = in - ap_y*ap_coeff; /* High-pass generated from removing low-passed output. */ - hpout[i] = hp_y - lp_y; - } + return ap_y - lp_y; + }; + std::transform(input, input+count, hpout, proc_sample); splitter->lp_z1 = lp_z1; splitter->lp_z2 = lp_z2; - splitter->hp_z1 = hp_z1; + splitter->hp_z1 = ap_z1; } void splitterap_init(SplitterAllpass *splitter, ALfloat f0norm) { ALfloat w = f0norm * F_TAU; - ALfloat cw = cosf(w); + ALfloat cw = std::cos(w); if(cw > FLT_EPSILON) - splitter->coeff = (sinf(w) - 1.0f) / cw; + splitter->coeff = (std::sin(w) - 1.0f) / cw; else splitter->coeff = cw * -0.5f; @@ -88,22 +86,16 @@ void splitterap_clear(SplitterAllpass *splitter) void splitterap_process(SplitterAllpass *splitter, ALfloat *RESTRICT samples, ALsizei count) { - ALfloat coeff, in, out; - ALfloat z1; - ALsizei i; - ASSUME(count > 0); - coeff = splitter->coeff; - z1 = splitter->z1; - for(i = 0;i < count;i++) + const float coeff{splitter->coeff}; + float z1{splitter->z1}; + auto proc_sample = [coeff,&z1](const float in) noexcept -> float { - in = samples[i]; - - out = in*coeff + z1; + float out{in*coeff + z1}; z1 = in - out*coeff; - - samples[i] = out; - } + return out; + }; + std::transform(samples, samples+count, samples, proc_sample); splitter->z1 = z1; } -- cgit v1.2.3 From 36a8b615c883ccc90705b97402e2e2046058720a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 4 Dec 2018 20:55:10 -0800 Subject: Avoid using AL types with the filters --- Alc/filters/defs.h | 18 +++++++++--------- Alc/filters/filter.cpp | 34 +++++++++++++++++----------------- Alc/filters/splitter.cpp | 18 +++++++++--------- Alc/filters/splitter.h | 26 +++++++++++++------------- 4 files changed, 48 insertions(+), 48 deletions(-) diff --git a/Alc/filters/defs.h b/Alc/filters/defs.h index 19514b62..fb8c9312 100644 --- a/Alc/filters/defs.h +++ b/Alc/filters/defs.h @@ -35,11 +35,11 @@ enum class BiquadType { struct BiquadFilter { /* Last two delayed components for direct form II. */ - ALfloat z1{0.0f}, z2{0.0f}; + float z1{0.0f}, z2{0.0f}; /* Transfer function coefficients "b" (numerator) */ - ALfloat b0{1.0f}, b1{0.0f}, b2{0.0f}; + float b0{1.0f}, b1{0.0f}, b2{0.0f}; /* Transfer function coefficients "a" (denominator; a0 is pre-applied). */ - ALfloat a1{0.0f}, a2{0.0f}; + float a1{0.0f}, a2{0.0f}; }; /* Currently only a C-based filter process method is implemented. */ #define BiquadFilter_process BiquadFilter_processC @@ -50,7 +50,7 @@ struct BiquadFilter { * \param gain 0 < gain * \param slope 0 < slope <= 1 */ -inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope) +inline float calc_rcpQ_from_slope(float gain, float slope) { return std::sqrt((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f); } @@ -60,9 +60,9 @@ inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope) * \param f0norm 0 < f0norm < 0.5. * \param bandwidth 0 < bandwidth */ -inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth) +inline ALfloat calc_rcpQ_from_bandwidth(float f0norm, float bandwidth) { - ALfloat w0 = F_TAU * f0norm; + float w0 = F_TAU * f0norm; return 2.0f*std::sinh(std::log(2.0f)/2.0f*bandwidth*w0/std::sin(w0)); } @@ -87,7 +87,7 @@ inline void BiquadFilter_clear(BiquadFilter *filter) * band. Can be generated from calc_rcpQ_from_slope or * calc_rcpQ_from_bandwidth depending on the available data. */ -void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ); +void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, float gain, float f0norm, float rcpQ); inline void BiquadFilter_copyParams(BiquadFilter *RESTRICT dst, const BiquadFilter *RESTRICT src) { @@ -98,9 +98,9 @@ inline void BiquadFilter_copyParams(BiquadFilter *RESTRICT dst, const BiquadFilt dst->a2 = src->a2; } -void BiquadFilter_processC(BiquadFilter *filter, ALfloat *RESTRICT dst, const ALfloat *RESTRICT src, ALsizei numsamples); +void BiquadFilter_processC(BiquadFilter *filter, float *RESTRICT dst, const float *RESTRICT src, int numsamples); -inline void BiquadFilter_passthru(BiquadFilter *filter, ALsizei numsamples) +inline void BiquadFilter_passthru(BiquadFilter *filter, int numsamples) { if(LIKELY(numsamples >= 2)) { diff --git a/Alc/filters/filter.cpp b/Alc/filters/filter.cpp index 5dc5d9b4..980841c0 100644 --- a/Alc/filters/filter.cpp +++ b/Alc/filters/filter.cpp @@ -10,12 +10,12 @@ #include "defs.h" -void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ) +void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, float gain, float f0norm, float rcpQ) { - ALfloat alpha, sqrtgain_alpha_2; - ALfloat w0, sin_w0, cos_w0; - ALfloat a[3] = { 1.0f, 0.0f, 0.0f }; - ALfloat b[3] = { 1.0f, 0.0f, 0.0f }; + float alpha, sqrtgain_alpha_2; + float w0, sin_w0, cos_w0; + float a[3] = { 1.0f, 0.0f, 0.0f }; + float b[3] = { 1.0f, 0.0f, 0.0f }; // Limit gain to -100dB assert(gain > 0.00001f); @@ -90,18 +90,18 @@ void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, } -void BiquadFilter_processC(BiquadFilter *filter, ALfloat *RESTRICT dst, const ALfloat *RESTRICT src, ALsizei numsamples) +void BiquadFilter_processC(BiquadFilter *filter, float *RESTRICT dst, const float *RESTRICT src, int numsamples) { - const ALfloat b0 = filter->b0; - const ALfloat b1 = filter->b1; - const ALfloat b2 = filter->b2; - const ALfloat a1 = filter->a1; - const ALfloat a2 = filter->a2; - ALfloat z1 = filter->z1; - ALfloat z2 = filter->z2; - ASSUME(numsamples > 0); + const float b0{filter->b0}; + const float b1{filter->b1}; + const float b2{filter->b2}; + const float a1{filter->a1}; + const float a2{filter->a2}; + float z1{filter->z1}; + float z2{filter->z2}; + /* Processing loop is Transposed Direct Form II. This requires less storage * compared to Direct Form I (only two delay components, instead of a four- * sample history; the last two inputs and outputs), and works better for @@ -110,14 +110,14 @@ void BiquadFilter_processC(BiquadFilter *filter, ALfloat *RESTRICT dst, const AL * * See: http://www.earlevel.com/main/2003/02/28/biquads/ */ - auto proc_sample = [b0,b1,b2,a1,a2,&z1,&z2](ALfloat input) noexcept -> ALfloat + auto proc_sample = [b0,b1,b2,a1,a2,&z1,&z2](float input) noexcept -> float { - ALfloat output = input*b0 + z1; + float output = input*b0 + z1; z1 = input*b1 - output*a1 + z2; z2 = input*b2 - output*a2; return output; }; - std::transform(src, src+numsamples, dst, proc_sample); + std::transform(src, src+numsamples, dst, proc_sample); filter->z1 = z1; filter->z2 = z2; diff --git a/Alc/filters/splitter.cpp b/Alc/filters/splitter.cpp index 570f5e2c..d13c8a77 100644 --- a/Alc/filters/splitter.cpp +++ b/Alc/filters/splitter.cpp @@ -9,10 +9,10 @@ #include "math_defs.h" -void bandsplit_init(BandSplitter *splitter, ALfloat f0norm) +void bandsplit_init(BandSplitter *splitter, float f0norm) { - ALfloat w = f0norm * F_TAU; - ALfloat cw = std::cos(w); + float w = f0norm * F_TAU; + float cw = std::cos(w); if(cw > FLT_EPSILON) splitter->coeff = (std::sin(w) - 1.0f) / cw; else @@ -30,8 +30,8 @@ void bandsplit_clear(BandSplitter *splitter) splitter->hp_z1 = 0.0f; } -void bandsplit_process(BandSplitter *splitter, ALfloat *RESTRICT hpout, ALfloat *RESTRICT lpout, - const ALfloat *input, ALsizei count) +void bandsplit_process(BandSplitter *splitter, float *RESTRICT hpout, float *RESTRICT lpout, + const ALfloat *input, int count) { ASSUME(count > 0); @@ -67,10 +67,10 @@ void bandsplit_process(BandSplitter *splitter, ALfloat *RESTRICT hpout, ALfloat } -void splitterap_init(SplitterAllpass *splitter, ALfloat f0norm) +void splitterap_init(SplitterAllpass *splitter, float f0norm) { - ALfloat w = f0norm * F_TAU; - ALfloat cw = std::cos(w); + float w = f0norm * F_TAU; + float cw = std::cos(w); if(cw > FLT_EPSILON) splitter->coeff = (std::sin(w) - 1.0f) / cw; else @@ -84,7 +84,7 @@ void splitterap_clear(SplitterAllpass *splitter) splitter->z1 = 0.0f; } -void splitterap_process(SplitterAllpass *splitter, ALfloat *RESTRICT samples, ALsizei count) +void splitterap_process(SplitterAllpass *splitter, float *RESTRICT samples, int count) { ASSUME(count > 0); diff --git a/Alc/filters/splitter.h b/Alc/filters/splitter.h index 13f4cd55..96ecdb43 100644 --- a/Alc/filters/splitter.h +++ b/Alc/filters/splitter.h @@ -7,35 +7,35 @@ /* Band splitter. Splits a signal into two phase-matching frequency bands. */ struct BandSplitter { - ALfloat coeff{0.0f}; - ALfloat lp_z1{0.0f}; - ALfloat lp_z2{0.0f}; - ALfloat hp_z1{0.0f}; + float coeff{0.0f}; + float lp_z1{0.0f}; + float lp_z2{0.0f}; + float hp_z1{0.0f}; }; -void bandsplit_init(BandSplitter *splitter, ALfloat f0norm); +void bandsplit_init(BandSplitter *splitter, float f0norm); void bandsplit_clear(BandSplitter *splitter); -void bandsplit_process(BandSplitter *splitter, ALfloat *RESTRICT hpout, ALfloat *RESTRICT lpout, - const ALfloat *input, ALsizei count); +void bandsplit_process(BandSplitter *splitter, float *RESTRICT hpout, float *RESTRICT lpout, + const float *input, int count); /* The all-pass portion of the band splitter. Applies the same phase shift * without splitting the signal. */ struct SplitterAllpass { - ALfloat coeff{0.0f}; - ALfloat z1{0.0f}; + float coeff{0.0f}; + float z1{0.0f}; }; -void splitterap_init(SplitterAllpass *splitter, ALfloat f0norm); +void splitterap_init(SplitterAllpass *splitter, float f0norm); void splitterap_clear(SplitterAllpass *splitter); -void splitterap_process(SplitterAllpass *splitter, ALfloat *RESTRICT samples, ALsizei count); +void splitterap_process(SplitterAllpass *splitter, float *RESTRICT samples, int count); struct FrontStablizer { SplitterAllpass APFilter[MAX_OUTPUT_CHANNELS]; BandSplitter LFilter, RFilter; - alignas(16) ALfloat LSplit[2][BUFFERSIZE]; - alignas(16) ALfloat RSplit[2][BUFFERSIZE]; + alignas(16) float LSplit[2][BUFFERSIZE]; + alignas(16) float RSplit[2][BUFFERSIZE]; DEF_NEWDEL(FrontStablizer) }; -- cgit v1.2.3 From 164a86a381e4f51383c6afbfdf63dadd3ecb3785 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 4 Dec 2018 22:31:08 -0800 Subject: Use class methods for the biquad filter --- Alc/alu.cpp | 24 ++++------ Alc/effects/distortion.cpp | 16 +++---- Alc/effects/echo.cpp | 17 +++---- Alc/effects/equalizer.cpp | 36 +++++++-------- Alc/effects/modulator.cpp | 10 ++--- Alc/effects/reverb.cpp | 36 +++++++-------- Alc/filters/defs.h | 110 ++++++++++++++++++++++++--------------------- Alc/filters/filter.cpp | 34 +++++++------- Alc/mixvoice.cpp | 16 +++---- 9 files changed, 146 insertions(+), 153 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index de46633a..f3fa15ec 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -964,20 +964,16 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev voice->Direct.FilterType = AF_None; if(gainHF != 1.0f) voice->Direct.FilterType |= AF_LowPass; if(gainLF != 1.0f) voice->Direct.FilterType |= AF_HighPass; - BiquadFilter_setParams( - &voice->Direct.Params[0].LowPass, BiquadType::HighShelf, + voice->Direct.Params[0].LowPass.setParams(BiquadType::HighShelf, gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) ); - BiquadFilter_setParams( - &voice->Direct.Params[0].HighPass, BiquadType::LowShelf, + voice->Direct.Params[0].HighPass.setParams(BiquadType::LowShelf, gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) ); for(c = 1;c < num_channels;c++) { - BiquadFilter_copyParams(&voice->Direct.Params[c].LowPass, - &voice->Direct.Params[0].LowPass); - BiquadFilter_copyParams(&voice->Direct.Params[c].HighPass, - &voice->Direct.Params[0].HighPass); + voice->Direct.Params[c].LowPass.copyParamsFrom(voice->Direct.Params[0].LowPass); + voice->Direct.Params[c].HighPass.copyParamsFrom(voice->Direct.Params[0].HighPass); } } for(i = 0;i < NumSends;i++) @@ -990,20 +986,16 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev voice->Send[i].FilterType = AF_None; if(gainHF != 1.0f) voice->Send[i].FilterType |= AF_LowPass; if(gainLF != 1.0f) voice->Send[i].FilterType |= AF_HighPass; - BiquadFilter_setParams( - &voice->Send[i].Params[0].LowPass, BiquadType::HighShelf, + voice->Send[i].Params[0].LowPass.setParams(BiquadType::HighShelf, gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) ); - BiquadFilter_setParams( - &voice->Send[i].Params[0].HighPass, BiquadType::LowShelf, + voice->Send[i].Params[0].HighPass.setParams(BiquadType::LowShelf, gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) ); for(c = 1;c < num_channels;c++) { - BiquadFilter_copyParams(&voice->Send[i].Params[c].LowPass, - &voice->Send[i].Params[0].LowPass); - BiquadFilter_copyParams(&voice->Send[i].Params[c].HighPass, - &voice->Send[i].Params[0].HighPass); + voice->Send[i].Params[c].LowPass.copyParamsFrom(voice->Send[i].Params[0].LowPass); + voice->Send[i].Params[c].HighPass.copyParamsFrom(voice->Send[i].Params[0].HighPass); } } } diff --git a/Alc/effects/distortion.cpp b/Alc/effects/distortion.cpp index a2681e3d..b3d339ad 100644 --- a/Alc/effects/distortion.cpp +++ b/Alc/effects/distortion.cpp @@ -53,8 +53,8 @@ struct ALdistortionState final : public EffectState { ALboolean ALdistortionState::deviceUpdate(ALCdevice *UNUSED(device)) { - BiquadFilter_clear(&mLowpass); - BiquadFilter_clear(&mBandpass); + mLowpass.clear(); + mBandpass.clear(); return AL_TRUE; } @@ -78,15 +78,15 @@ void ALdistortionState::update(const ALCcontext *context, const ALeffectslot *sl /* Multiply sampling frequency by the amount of oversampling done during * processing. */ - BiquadFilter_setParams(&mLowpass, BiquadType::LowPass, 1.0f, - cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) + mLowpass.setParams(BiquadType::LowPass, 1.0f, cutoff / (frequency*4.0f), + calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); cutoff = props->Distortion.EQCenter; /* Convert bandwidth in Hz to octaves. */ bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f); - BiquadFilter_setParams(&mBandpass, BiquadType::BandPass, 1.0f, - cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) + mBandpass.setParams(BiquadType::BandPass, 1.0f, cutoff / (frequency*4.0f), + calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); @@ -120,7 +120,7 @@ void ALdistortionState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT Sa * (which is fortunately first step of distortion). So combine three * operations into the one. */ - BiquadFilter_process(&mLowpass, buffer[1], buffer[0], todo); + mLowpass.process(buffer[1], buffer[0], todo); /* Second step, do distortion using waveshaper function to emulate * signal processing during tube overdriving. Three steps of @@ -139,7 +139,7 @@ void ALdistortionState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT Sa } /* Third step, do bandpass filtering of distorted signal. */ - BiquadFilter_process(&mBandpass, buffer[1], buffer[0], todo); + mBandpass.process(buffer[1], buffer[0], todo); todo >>= 2; for(k = 0;k < NumChannels;k++) diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index 58728b50..91bdde9a 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -112,8 +112,8 @@ void ALechoState::update(const ALCcontext *context, const ALeffectslot *slot, co mFeedGain = props->Echo.Feedback; gainhf = maxf(1.0f - props->Echo.Damping, 0.0625f); /* Limit -24dB */ - BiquadFilter_setParams(&mFilter, BiquadType::HighShelf, - gainhf, LOWPASSFREQREF/frequency, calc_rcpQ_from_slope(gainhf, 1.0f) + mFilter.setParams(BiquadType::HighShelf, gainhf, LOWPASSFREQREF/frequency, + calc_rcpQ_from_slope(gainhf, 1.0f) ); /* First tap panning */ @@ -132,12 +132,11 @@ void ALechoState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesI const ALsizei tap2 = mTap[1].delay; ALfloat *RESTRICT delaybuf = mSampleBuffer.data(); ALsizei offset = mOffset; - ALfloat z1, z2, in, out; + ALfloat z1, z2; ALsizei base; ALsizei c, i; - z1 = mFilter.z1; - z2 = mFilter.z2; + std::tie(z1, z2) = mFilter.getComponents(); for(base = 0;base < SamplesToDo;) { alignas(16) ALfloat temps[2][128]; @@ -156,10 +155,7 @@ void ALechoState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesI /* Apply damping to the second tap, then add it to the buffer with * feedback attenuation. */ - in = temps[1][i]; - out = in*mFilter.b0 + z1; - z1 = in*mFilter.b1 - out*mFilter.a1 + z2; - z2 = in*mFilter.b2 - out*mFilter.a2; + float out{mFilter.processOne(temps[1][i], z1, z2)}; delaybuf[offset&mask] += out * mFeedGain; offset++; @@ -171,8 +167,7 @@ void ALechoState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesI base += td; } - mFilter.z1 = z1; - mFilter.z2 = z2; + mFilter.setComponents(z1, z2); mOffset = offset; } diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index 6329ede2..af571930 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -101,9 +101,7 @@ ALboolean ALequalizerState::deviceUpdate(ALCdevice *UNUSED(device)) for(auto &e : mChans) { std::for_each(std::begin(e.filter), std::end(e.filter), - [](BiquadFilter &f) -> void - { BiquadFilter_clear(&f); } - ); + std::mem_fun_ref(&BiquadFilter::clear)); std::fill(std::begin(e.CurrentGains), std::end(e.CurrentGains), 0.0f); } return AL_TRUE; @@ -122,35 +120,35 @@ void ALequalizerState::update(const ALCcontext *context, const ALeffectslot *slo */ gain = maxf(sqrtf(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */ f0norm = props->Equalizer.LowCutoff/frequency; - BiquadFilter_setParams(&mChans[0].filter[0], BiquadType::LowShelf, - gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f) + mChans[0].filter[0].setParams(BiquadType::LowShelf, gain, f0norm, + calc_rcpQ_from_slope(gain, 0.75f) ); gain = maxf(props->Equalizer.Mid1Gain, 0.0625f); f0norm = props->Equalizer.Mid1Center/frequency; - BiquadFilter_setParams(&mChans[0].filter[1], BiquadType::Peaking, - gain, f0norm, calc_rcpQ_from_bandwidth(f0norm, props->Equalizer.Mid1Width) + mChans[0].filter[1].setParams(BiquadType::Peaking, gain, f0norm, + calc_rcpQ_from_bandwidth(f0norm, props->Equalizer.Mid1Width) ); gain = maxf(props->Equalizer.Mid2Gain, 0.0625f); f0norm = props->Equalizer.Mid2Center/frequency; - BiquadFilter_setParams(&mChans[0].filter[2], BiquadType::Peaking, - gain, f0norm, calc_rcpQ_from_bandwidth(f0norm, props->Equalizer.Mid2Width) + mChans[0].filter[2].setParams(BiquadType::Peaking, gain, f0norm, + calc_rcpQ_from_bandwidth(f0norm, props->Equalizer.Mid2Width) ); gain = maxf(sqrtf(props->Equalizer.HighGain), 0.0625f); f0norm = props->Equalizer.HighCutoff/frequency; - BiquadFilter_setParams(&mChans[0].filter[3], BiquadType::HighShelf, - gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f) + mChans[0].filter[3].setParams(BiquadType::HighShelf, gain, f0norm, + calc_rcpQ_from_slope(gain, 0.75f) ); /* Copy the filter coefficients for the other input channels. */ for(i = 1;i < MAX_EFFECT_CHANNELS;i++) { - BiquadFilter_copyParams(&mChans[i].filter[0], &mChans[0].filter[0]); - BiquadFilter_copyParams(&mChans[i].filter[1], &mChans[0].filter[1]); - BiquadFilter_copyParams(&mChans[i].filter[2], &mChans[0].filter[2]); - BiquadFilter_copyParams(&mChans[i].filter[3], &mChans[0].filter[3]); + mChans[i].filter[0].copyParamsFrom(mChans[0].filter[0]); + mChans[i].filter[1].copyParamsFrom(mChans[0].filter[1]); + mChans[i].filter[2].copyParamsFrom(mChans[0].filter[2]); + mChans[i].filter[3].copyParamsFrom(mChans[0].filter[3]); } mOutBuffer = device->FOAOut.Buffer; @@ -167,10 +165,10 @@ void ALequalizerState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT Sam for(c = 0;c < MAX_EFFECT_CHANNELS;c++) { - BiquadFilter_process(&mChans[c].filter[0], temps[0], SamplesIn[c], SamplesToDo); - BiquadFilter_process(&mChans[c].filter[1], temps[1], temps[0], SamplesToDo); - BiquadFilter_process(&mChans[c].filter[2], temps[2], temps[1], SamplesToDo); - BiquadFilter_process(&mChans[c].filter[3], temps[3], temps[2], SamplesToDo); + mChans[c].filter[0].process(temps[0], SamplesIn[c], SamplesToDo); + mChans[c].filter[1].process(temps[1], temps[0], SamplesToDo); + mChans[c].filter[2].process(temps[2], temps[1], SamplesToDo); + mChans[c].filter[3].process(temps[3], temps[2], SamplesToDo); MixSamples(temps[3], NumChannels, SamplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, SamplesToDo, 0, SamplesToDo); diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index ac71e444..3d41bb65 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -99,7 +99,7 @@ ALboolean ALmodulatorState::deviceUpdate(ALCdevice *UNUSED(device)) { for(auto &e : mChans) { - BiquadFilter_clear(&e.Filter); + e.Filter.clear(); std::fill(std::begin(e.CurrentGains), std::end(e.CurrentGains), 0.0f); } return AL_TRUE; @@ -126,10 +126,10 @@ void ALmodulatorState::update(const ALCcontext *context, const ALeffectslot *slo f0norm = props->Modulator.HighPassCutoff / (ALfloat)device->Frequency; f0norm = clampf(f0norm, 1.0f/512.0f, 0.49f); /* Bandwidth value is constant in octaves. */ - BiquadFilter_setParams(&mChans[0].Filter, BiquadType::HighPass, 1.0f, - f0norm, calc_rcpQ_from_bandwidth(f0norm, 0.75f)); + mChans[0].Filter.setParams(BiquadType::HighPass, 1.0f, f0norm, + calc_rcpQ_from_bandwidth(f0norm, 0.75f)); for(i = 1;i < MAX_EFFECT_CHANNELS;i++) - BiquadFilter_copyParams(&mChans[i].Filter, &mChans[0].Filter); + mChans[i].Filter.copyParamsFrom(mChans[0].Filter); mOutBuffer = device->FOAOut.Buffer; mOutChannels = device->FOAOut.NumChannels; @@ -157,7 +157,7 @@ void ALmodulatorState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT Sam { alignas(16) ALfloat temps[MAX_UPDATE_SAMPLES]; - BiquadFilter_process(&mChans[c].Filter, temps, &SamplesIn[c][base], td); + mChans[c].Filter.process(temps, &SamplesIn[c][base], td); for(i = 0;i < td;i++) temps[i] *= modsamples[i]; diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index bf2e9a6f..ce7a9946 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -478,8 +478,8 @@ ALboolean ReverbState::deviceUpdate(ALCdevice *Device) */ for(i = 0;i < NUM_LINES;i++) { - BiquadFilter_clear(&mFilter[i].Lp); - BiquadFilter_clear(&mFilter[i].Hp); + mFilter[i].Lp.clear(); + mFilter[i].Hp.clear(); } for(i = 0;i < NUM_LINES;i++) @@ -500,8 +500,8 @@ ALboolean ReverbState::deviceUpdate(ALCdevice *Device) { mLate.T60[i].MidGain[0] = 0.0f; mLate.T60[i].MidGain[1] = 0.0f; - BiquadFilter_clear(&mLate.T60[i].HFFilter); - BiquadFilter_clear(&mLate.T60[i].LFFilter); + mLate.T60[i].HFFilter.clear(); + mLate.T60[i].LFFilter.clear(); } for(i = 0;i < NUM_LINES;i++) @@ -615,10 +615,10 @@ static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime ALfloat hfGain = CalcDecayCoeff(length, hfDecayTime); filter->MidGain[1] = mfGain; - BiquadFilter_setParams(&filter->LFFilter, BiquadType::LowShelf, lfGain/mfGain, lf0norm, - calc_rcpQ_from_slope(lfGain/mfGain, 1.0f)); - BiquadFilter_setParams(&filter->HFFilter, BiquadType::HighShelf, hfGain/mfGain, hf0norm, - calc_rcpQ_from_slope(hfGain/mfGain, 1.0f)); + filter->LFFilter.setParams(BiquadType::LowShelf, lfGain/mfGain, lf0norm, + calc_rcpQ_from_slope(lfGain/mfGain, 1.0f)); + filter->HFFilter.setParams(BiquadType::HighShelf, hfGain/mfGain, hf0norm, + calc_rcpQ_from_slope(hfGain/mfGain, 1.0f)); } /* Update the offsets for the main effect delay line. */ @@ -851,16 +851,16 @@ void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, co * killing most of the signal. */ gainhf = maxf(props->Reverb.GainHF, 0.001f); - BiquadFilter_setParams(&mFilter[0].Lp, BiquadType::HighShelf, gainhf, hf0norm, - calc_rcpQ_from_slope(gainhf, 1.0f)); + mFilter[0].Lp.setParams(BiquadType::HighShelf, gainhf, hf0norm, + calc_rcpQ_from_slope(gainhf, 1.0f)); lf0norm = minf(props->Reverb.LFReference / frequency, 0.49f); gainlf = maxf(props->Reverb.GainLF, 0.001f); - BiquadFilter_setParams(&mFilter[0].Hp, BiquadType::LowShelf, gainlf, lf0norm, - calc_rcpQ_from_slope(gainlf, 1.0f)); + mFilter[0].Hp.setParams(BiquadType::LowShelf, gainlf, lf0norm, + calc_rcpQ_from_slope(gainlf, 1.0f)); for(i = 1;i < NUM_LINES;i++) { - BiquadFilter_copyParams(&mFilter[i].Lp, &mFilter[0].Lp); - BiquadFilter_copyParams(&mFilter[i].Hp, &mFilter[0].Hp); + mFilter[i].Lp.copyParamsFrom(mFilter[0].Lp); + mFilter[i].Hp.copyParamsFrom(mFilter[0].Hp); } /* Update the main effect delay and associated taps. */ @@ -1245,8 +1245,8 @@ static void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsi static inline void LateT60Filter(ALfloat *RESTRICT samples, const ALsizei todo, T60Filter *filter) { ALfloat temp[MAX_UPDATE_SAMPLES]; - BiquadFilter_process(&filter->HFFilter, temp, samples, todo); - BiquadFilter_process(&filter->LFFilter, samples, temp, todo); + filter->HFFilter.process(temp, samples, todo); + filter->LFFilter.process(samples, temp, todo); } /* This generates the reverb tail using a modified feed-back delay network @@ -1389,8 +1389,8 @@ void ReverbState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesI for(c = 0;c < NUM_LINES;c++) { /* Band-pass the incoming samples. */ - BiquadFilter_process(&mFilter[c].Lp, samples[0], afmt[c], todo); - BiquadFilter_process(&mFilter[c].Hp, samples[1], samples[0], todo); + mFilter[c].Lp.process(samples[0], afmt[c], todo); + mFilter[c].Hp.process(samples[1], samples[0], todo); /* Feed the initial delay line. */ DelayLineIn(&mDelay, offset, c, samples[1], todo); diff --git a/Alc/filters/defs.h b/Alc/filters/defs.h index fb8c9312..b7628153 100644 --- a/Alc/filters/defs.h +++ b/Alc/filters/defs.h @@ -33,16 +33,72 @@ enum class BiquadType { BandPass, }; -struct BiquadFilter { +class BiquadFilter { /* Last two delayed components for direct form II. */ float z1{0.0f}, z2{0.0f}; /* Transfer function coefficients "b" (numerator) */ float b0{1.0f}, b1{0.0f}, b2{0.0f}; /* Transfer function coefficients "a" (denominator; a0 is pre-applied). */ float a1{0.0f}, a2{0.0f}; + +public: + void clear() noexcept { z1 = z2 = 0.0f; } + + /** + * Sets the filter state for the specified filter type and its parameters. + * + * \param type The type of filter to apply. + * \param gain The gain for the reference frequency response. Only used by + * the Shelf and Peaking filter types. + * \param f0norm The reference frequency normal (ref_freq / sample_rate). + * This is the center point for the Shelf, Peaking, and + * BandPass filter types, or the cutoff frequency for the + * LowPass and HighPass filter types. + * \param rcpQ The reciprocal of the Q coefficient for the filter's + * transition band. Can be generated from calc_rcpQ_from_slope + * or calc_rcpQ_from_bandwidth as needed. + */ + void setParams(BiquadType type, float gain, float f0norm, float rcpQ); + + void copyParamsFrom(const BiquadFilter &other) + { + b0 = other.b0; + b1 = other.b1; + b2 = other.b2; + a1 = other.a1; + a2 = other.a2; + } + + + void process(float *RESTRICT dst, const float *RESTRICT src, int numsamples); + + void passthru(int numsamples) noexcept + { + if(LIKELY(numsamples >= 2)) + { + z1 = 0.0f; + z2 = 0.0f; + } + else if(numsamples == 1) + { + z1 = z2; + z2 = 0.0f; + } + } + + /* Rather hacky. It's just here to support "manual" processing. */ + std::pair getComponents() const noexcept + { return {z1, z2}; } + void setComponents(float z1_, float z2_) noexcept + { z1 = z1_; z2 = z2_; } + float processOne(const float in, float &z1_, float &z2_) const noexcept + { + float out{in*b0 + z1_}; + z1_ = in*b1 - out*a1 + z2_; + z2_ = in*b2 - out*a2; + return out; + } }; -/* Currently only a C-based filter process method is implemented. */ -#define BiquadFilter_process BiquadFilter_processC /** * Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the @@ -66,52 +122,4 @@ inline ALfloat calc_rcpQ_from_bandwidth(float f0norm, float bandwidth) return 2.0f*std::sinh(std::log(2.0f)/2.0f*bandwidth*w0/std::sin(w0)); } -inline void BiquadFilter_clear(BiquadFilter *filter) -{ - filter->z1 = 0.0f; - filter->z2 = 0.0f; -} - -/** - * Sets up the filter state for the specified filter type and its parameters. - * - * \param filter The filter object to prepare. - * \param type The type of filter for the object to apply. - * \param gain The gain for the reference frequency response. Only used by the - * Shelf and Peaking filter types. - * \param f0norm The normalized reference frequency (ref_freq / sample_rate). - * This is the center point for the Shelf, Peaking, and BandPass - * filter types, or the cutoff frequency for the LowPass and - * HighPass filter types. - * \param rcpQ The reciprocal of the Q coefficient for the filter's transition - * band. Can be generated from calc_rcpQ_from_slope or - * calc_rcpQ_from_bandwidth depending on the available data. - */ -void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, float gain, float f0norm, float rcpQ); - -inline void BiquadFilter_copyParams(BiquadFilter *RESTRICT dst, const BiquadFilter *RESTRICT src) -{ - dst->b0 = src->b0; - dst->b1 = src->b1; - dst->b2 = src->b2; - dst->a1 = src->a1; - dst->a2 = src->a2; -} - -void BiquadFilter_processC(BiquadFilter *filter, float *RESTRICT dst, const float *RESTRICT src, int numsamples); - -inline void BiquadFilter_passthru(BiquadFilter *filter, int numsamples) -{ - if(LIKELY(numsamples >= 2)) - { - filter->z1 = 0.0f; - filter->z2 = 0.0f; - } - else if(numsamples == 1) - { - filter->z1 = filter->z2; - filter->z2 = 0.0f; - } -} - #endif /* ALC_FILTER_H */ diff --git a/Alc/filters/filter.cpp b/Alc/filters/filter.cpp index 980841c0..c9e7c9fe 100644 --- a/Alc/filters/filter.cpp +++ b/Alc/filters/filter.cpp @@ -10,7 +10,7 @@ #include "defs.h" -void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, float gain, float f0norm, float rcpQ) +void BiquadFilter::setParams(BiquadType type, float gain, float f0norm, float rcpQ) { float alpha, sqrtgain_alpha_2; float w0, sin_w0, cos_w0; @@ -82,25 +82,25 @@ void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, float gain, f break; } - filter->a1 = a[1] / a[0]; - filter->a2 = a[2] / a[0]; - filter->b0 = b[0] / a[0]; - filter->b1 = b[1] / a[0]; - filter->b2 = b[2] / a[0]; + a1 = a[1] / a[0]; + a2 = a[2] / a[0]; + b0 = b[0] / a[0]; + b1 = b[1] / a[0]; + b2 = b[2] / a[0]; } -void BiquadFilter_processC(BiquadFilter *filter, float *RESTRICT dst, const float *RESTRICT src, int numsamples) +void BiquadFilter::process(float *RESTRICT dst, const float *RESTRICT src, int numsamples) { ASSUME(numsamples > 0); - const float b0{filter->b0}; - const float b1{filter->b1}; - const float b2{filter->b2}; - const float a1{filter->a1}; - const float a2{filter->a2}; - float z1{filter->z1}; - float z2{filter->z2}; + const float b0{this->b0}; + const float b1{this->b1}; + const float b2{this->b2}; + const float a1{this->a1}; + const float a2{this->a2}; + float z1{this->z1}; + float z2{this->z2}; /* Processing loop is Transposed Direct Form II. This requires less storage * compared to Direct Form I (only two delay components, instead of a four- @@ -117,8 +117,8 @@ void BiquadFilter_processC(BiquadFilter *filter, float *RESTRICT dst, const floa z2 = input*b2 - output*a2; return output; }; - std::transform(src, src+numsamples, dst, proc_sample); + std::transform(src, src+numsamples, dst, proc_sample); - filter->z1 = z1; - filter->z2 = z2; + this->z1 = z1; + this->z2 = z2; } diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 04bb1130..91c48daf 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -250,17 +250,17 @@ const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, switch(type) { case AF_None: - BiquadFilter_passthru(lpfilter, numsamples); - BiquadFilter_passthru(hpfilter, numsamples); + lpfilter->passthru(numsamples); + hpfilter->passthru(numsamples); break; case AF_LowPass: - BiquadFilter_process(lpfilter, dst, src, numsamples); - BiquadFilter_passthru(hpfilter, numsamples); + lpfilter->process(dst, src, numsamples); + hpfilter->passthru(numsamples); return dst; case AF_HighPass: - BiquadFilter_passthru(lpfilter, numsamples); - BiquadFilter_process(hpfilter, dst, src, numsamples); + lpfilter->passthru(numsamples); + hpfilter->process(dst, src, numsamples); return dst; case AF_BandPass: @@ -269,8 +269,8 @@ const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, ALfloat temp[256]; ALsizei todo = mini(256, numsamples-i); - BiquadFilter_process(lpfilter, temp, src+i, todo); - BiquadFilter_process(hpfilter, dst+i, temp, todo); + lpfilter->process(temp, src+i, todo); + hpfilter->process(dst+i, temp, todo); i += todo; } return dst; -- cgit v1.2.3 From 10b39d57d53b541bd4e8fd60d166a03de0c9e28c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 5 Dec 2018 15:20:52 -0800 Subject: Use class methods for the NFC filters --- Alc/alc.cpp | 4 +- Alc/alu.cpp | 8 +-- Alc/filters/nfc.cpp | 191 ++++++++++++++++++++++++++------------------------ Alc/filters/nfc.h | 64 ++++++++--------- Alc/mixvoice.cpp | 12 ++-- OpenAL32/alSource.cpp | 4 +- 6 files changed, 141 insertions(+), 142 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 0c6bd5dc..810cba10 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2341,8 +2341,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / (device->AvgSpeakerDist * device->Frequency); std::for_each(voice->Direct.Params, voice->Direct.Params+voice->NumChannels, - [w1](DirectParams ¶ms) -> void - { NfcFilterCreate(¶ms.NFCtrlFilter, 0.0f, w1); } + [w1](DirectParams ¶ms) noexcept -> void + { params.NFCtrlFilter.init(0.0f, w1); } ); } } diff --git a/Alc/alu.cpp b/Alc/alu.cpp index f3fa15ec..def52e3d 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -608,7 +608,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev w0 = minf(w0, w1*4.0f); /* Only need to adjust the first channel of a B-Format source. */ - NfcFilterAdjust(&voice->Direct.Params[0].NFCtrlFilter, w0); + voice->Direct.Params[0].NFCtrlFilter.adjust(w0); std::copy(std::begin(Device->NumChannelsPerOrder), std::end(Device->NumChannelsPerOrder), @@ -649,7 +649,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev * is what we want for FOA input. The first channel may have * been previously re-adjusted if panned, so reset it. */ - NfcFilterAdjust(&voice->Direct.Params[0].NFCtrlFilter, 0.0f); + voice->Direct.Params[0].NFCtrlFilter.adjust(0.0f); voice->Direct.ChannelsPerOrder[0] = 1; voice->Direct.ChannelsPerOrder[1] = mini(voice->Direct.Channels-1, 3); @@ -853,7 +853,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev /* Adjust NFC filters. */ for(c = 0;c < num_channels;c++) - NfcFilterAdjust(&voice->Direct.Params[c].NFCtrlFilter, w0); + voice->Direct.Params[c].NFCtrlFilter.adjust(w0); for(i = 0;i < MAX_AMBI_ORDER+1;i++) voice->Direct.ChannelsPerOrder[i] = Device->NumChannelsPerOrder[i]; @@ -913,7 +913,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev (Device->AvgSpeakerDist * (ALfloat)Device->Frequency); for(c = 0;c < num_channels;c++) - NfcFilterAdjust(&voice->Direct.Params[c].NFCtrlFilter, w0); + voice->Direct.Params[c].NFCtrlFilter.adjust(w0); for(i = 0;i < MAX_AMBI_ORDER+1;i++) voice->Direct.ChannelsPerOrder[i] = Device->NumChannelsPerOrder[i]; diff --git a/Alc/filters/nfc.cpp b/Alc/filters/nfc.cpp index 11a7b467..8cabfc5b 100644 --- a/Alc/filters/nfc.cpp +++ b/Alc/filters/nfc.cpp @@ -48,7 +48,9 @@ * low frequencies. */ -static const float B[4][3] = { +namespace { + +constexpr float B[4][3] = { { 0.0f }, { 1.0f }, { 3.0f, 3.0f }, @@ -56,33 +58,36 @@ static const float B[4][3] = { /*{ 4.2076f, 11.4877f, 5.7924f, 9.1401f }*/ }; -static void NfcFilterCreate1(struct NfcFilter1 *nfc, const float w0, const float w1) +NfcFilter1 NfcFilterCreate1(const float w0, const float w1) noexcept { + NfcFilter1 nfc{}; float b_00, g_0; float r; - nfc->base_gain = 1.0f; - nfc->gain = 1.0f; + nfc.base_gain = 1.0f; + nfc.gain = 1.0f; /* Calculate bass-boost coefficients. */ r = 0.5f * w0; b_00 = B[1][0] * r; g_0 = 1.0f + b_00; - nfc->gain *= g_0; - nfc->b1 = 2.0f * b_00 / g_0; + nfc.gain *= g_0; + nfc.b1 = 2.0f * b_00 / g_0; /* Calculate bass-cut coefficients. */ r = 0.5f * w1; b_00 = B[1][0] * r; g_0 = 1.0f + b_00; - nfc->base_gain /= g_0; - nfc->gain /= g_0; - nfc->a1 = 2.0f * b_00 / g_0; + nfc.base_gain /= g_0; + nfc.gain /= g_0; + nfc.a1 = 2.0f * b_00 / g_0; + + return nfc; } -static void NfcFilterAdjust1(struct NfcFilter1 *nfc, const float w0) +void NfcFilterAdjust1(NfcFilter1 *nfc, const float w0) noexcept { float b_00, g_0; float r; @@ -96,13 +101,14 @@ static void NfcFilterAdjust1(struct NfcFilter1 *nfc, const float w0) } -static void NfcFilterCreate2(struct NfcFilter2 *nfc, const float w0, const float w1) +NfcFilter2 NfcFilterCreate2(const float w0, const float w1) noexcept { + NfcFilter2 nfc{}; float b_10, b_11, g_1; float r; - nfc->base_gain = 1.0f; - nfc->gain = 1.0f; + nfc.base_gain = 1.0f; + nfc.gain = 1.0f; /* Calculate bass-boost coefficients. */ r = 0.5f * w0; @@ -110,9 +116,9 @@ static void NfcFilterCreate2(struct NfcFilter2 *nfc, const float w0, const float b_11 = B[2][1] * r * r; g_1 = 1.0f + b_10 + b_11; - nfc->gain *= g_1; - nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; - nfc->b2 = 4.0f * b_11 / g_1; + nfc.gain *= g_1; + nfc.b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc.b2 = 4.0f * b_11 / g_1; /* Calculate bass-cut coefficients. */ r = 0.5f * w1; @@ -120,13 +126,15 @@ static void NfcFilterCreate2(struct NfcFilter2 *nfc, const float w0, const float b_11 = B[2][1] * r * r; g_1 = 1.0f + b_10 + b_11; - nfc->base_gain /= g_1; - nfc->gain /= g_1; - nfc->a1 = (2.0f*b_10 + 4.0f*b_11) / g_1; - nfc->a2 = 4.0f * b_11 / g_1; + nfc.base_gain /= g_1; + nfc.gain /= g_1; + nfc.a1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc.a2 = 4.0f * b_11 / g_1; + + return nfc; } -static void NfcFilterAdjust2(struct NfcFilter2 *nfc, const float w0) +void NfcFilterAdjust2(NfcFilter2 *nfc, const float w0) noexcept { float b_10, b_11, g_1; float r; @@ -142,14 +150,15 @@ static void NfcFilterAdjust2(struct NfcFilter2 *nfc, const float w0) } -static void NfcFilterCreate3(struct NfcFilter3 *nfc, const float w0, const float w1) +NfcFilter3 NfcFilterCreate3(const float w0, const float w1) noexcept { + NfcFilter3 nfc{}; float b_10, b_11, g_1; float b_00, g_0; float r; - nfc->base_gain = 1.0f; - nfc->gain = 1.0f; + nfc.base_gain = 1.0f; + nfc.gain = 1.0f; /* Calculate bass-boost coefficients. */ r = 0.5f * w0; @@ -157,15 +166,15 @@ static void NfcFilterCreate3(struct NfcFilter3 *nfc, const float w0, const float b_11 = B[3][1] * r * r; g_1 = 1.0f + b_10 + b_11; - nfc->gain *= g_1; - nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; - nfc->b2 = 4.0f * b_11 / g_1; + nfc.gain *= g_1; + nfc.b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc.b2 = 4.0f * b_11 / g_1; b_00 = B[3][2] * r; g_0 = 1.0f + b_00; - nfc->gain *= g_0; - nfc->b3 = 2.0f * b_00 / g_0; + nfc.gain *= g_0; + nfc.b3 = 2.0f * b_00 / g_0; /* Calculate bass-cut coefficients. */ r = 0.5f * w1; @@ -173,20 +182,22 @@ static void NfcFilterCreate3(struct NfcFilter3 *nfc, const float w0, const float b_11 = B[3][1] * r * r; g_1 = 1.0f + b_10 + b_11; - nfc->base_gain /= g_1; - nfc->gain /= g_1; - nfc->a1 = (2.0f*b_10 + 4.0f*b_11) / g_1; - nfc->a2 = 4.0f * b_11 / g_1; + nfc.base_gain /= g_1; + nfc.gain /= g_1; + nfc.a1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc.a2 = 4.0f * b_11 / g_1; b_00 = B[3][2] * r; g_0 = 1.0f + b_00; - nfc->base_gain /= g_0; - nfc->gain /= g_0; - nfc->a3 = 2.0f * b_00 / g_0; + nfc.base_gain /= g_0; + nfc.gain /= g_0; + nfc.a3 = 2.0f * b_00 / g_0; + + return nfc; } -static void NfcFilterAdjust3(struct NfcFilter3 *nfc, const float w0) +void NfcFilterAdjust3(NfcFilter3 *nfc, const float w0) noexcept { float b_10, b_11, g_1; float b_00, g_0; @@ -208,100 +219,96 @@ static void NfcFilterAdjust3(struct NfcFilter3 *nfc, const float w0) nfc->b3 = 2.0f * b_00 / g_0; } +} // namespace -void NfcFilterCreate(NfcFilter *nfc, const float w0, const float w1) +void NfcFilter::init(const float w0, const float w1) noexcept { - memset(nfc, 0, sizeof(*nfc)); - NfcFilterCreate1(&nfc->first, w0, w1); - NfcFilterCreate2(&nfc->second, w0, w1); - NfcFilterCreate3(&nfc->third, w0, w1); + first = NfcFilterCreate1(w0, w1); + second = NfcFilterCreate2(w0, w1); + third = NfcFilterCreate3(w0, w1); } -void NfcFilterAdjust(NfcFilter *nfc, const float w0) +void NfcFilter::adjust(const float w0) noexcept { - NfcFilterAdjust1(&nfc->first, w0); - NfcFilterAdjust2(&nfc->second, w0); - NfcFilterAdjust3(&nfc->third, w0); + NfcFilterAdjust1(&first, w0); + NfcFilterAdjust2(&second, w0); + NfcFilterAdjust3(&third, w0); } -void NfcFilterProcess1(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRICT src, const int count) +void NfcFilter::process1(float *RESTRICT dst, const float *RESTRICT src, const int count) { - const float gain = nfc->first.gain; - const float b1 = nfc->first.b1; - const float a1 = nfc->first.a1; - float z1 = nfc->first.z[0]; - ASSUME(count > 0); - auto proc_sample = [gain,b1,a1,&z1](float in) noexcept -> float + const float gain{first.gain}; + const float b1{first.b1}; + const float a1{first.a1}; + float z1{first.z[0]}; + auto proc_sample = [gain,b1,a1,&z1](const float in) noexcept -> float { - float y = in*gain - a1*z1; - float out = y + b1*z1; + const float y{in*gain - a1*z1}; + const float out{y + b1*z1}; z1 += y; return out; }; - std::transform(src, src+count, dst, proc_sample); - nfc->first.z[0] = z1; + std::transform(src, src+count, dst, proc_sample); + first.z[0] = z1; } -void NfcFilterProcess2(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRICT src, const int count) +void NfcFilter::process2(float *RESTRICT dst, const float *RESTRICT src, const int count) { - const float gain = nfc->second.gain; - const float b1 = nfc->second.b1; - const float b2 = nfc->second.b2; - const float a1 = nfc->second.a1; - const float a2 = nfc->second.a2; - float z1 = nfc->second.z[0]; - float z2 = nfc->second.z[1]; - ASSUME(count > 0); - auto proc_sample = [gain,b1,b2,a1,a2,&z1,&z2](float in) noexcept -> float + const float gain{second.gain}; + const float b1{second.b1}; + const float b2{second.b2}; + const float a1{second.a1}; + const float a2{second.a2}; + float z1{second.z[0]}; + float z2{second.z[1]}; + auto proc_sample = [gain,b1,b2,a1,a2,&z1,&z2](const float in) noexcept -> float { - float y = in*gain - a1*z1 - a2*z2; - float out = y + b1*z1 + b2*z2; + const float y{in*gain - a1*z1 - a2*z2}; + const float out{y + b1*z1 + b2*z2}; z2 += z1; z1 += y; return out; }; - std::transform(src, src+count, dst, proc_sample); - nfc->second.z[0] = z1; - nfc->second.z[1] = z2; + std::transform(src, src+count, dst, proc_sample); + second.z[0] = z1; + second.z[1] = z2; } -void NfcFilterProcess3(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRICT src, const int count) +void NfcFilter::process3(float *RESTRICT dst, const float *RESTRICT src, const int count) { - const float gain = nfc->third.gain; - const float b1 = nfc->third.b1; - const float b2 = nfc->third.b2; - const float b3 = nfc->third.b3; - const float a1 = nfc->third.a1; - const float a2 = nfc->third.a2; - const float a3 = nfc->third.a3; - float z1 = nfc->third.z[0]; - float z2 = nfc->third.z[1]; - float z3 = nfc->third.z[2]; - ASSUME(count > 0); - auto proc_sample = [gain,b1,b2,b3,a1,a2,a3,&z1,&z2,&z3](float in) noexcept -> float + const float gain{third.gain}; + const float b1{third.b1}; + const float b2{third.b2}; + const float b3{third.b3}; + const float a1{third.a1}; + const float a2{third.a2}; + const float a3{third.a3}; + float z1{third.z[0]}; + float z2{third.z[1]}; + float z3{third.z[2]}; + auto proc_sample = [gain,b1,b2,b3,a1,a2,a3,&z1,&z2,&z3](const float in) noexcept -> float { - float y = in*gain - a1*z1 - a2*z2; - float out = y + b1*z1 + b2*z2; + float y{in*gain - a1*z1 - a2*z2}; + float out{y + b1*z1 + b2*z2}; z2 += z1; z1 += y; y = out - a3*z3; out = y + b3*z3; z3 += y; - return out; }; - std::transform(src, src+count, dst, proc_sample); - nfc->third.z[0] = z1; - nfc->third.z[1] = z2; - nfc->third.z[2] = z3; + std::transform(src, src+count, dst, proc_sample); + third.z[0] = z1; + third.z[1] = z2; + third.z[2] = z3; } #if 0 /* Original methods the above are derived from. */ diff --git a/Alc/filters/nfc.h b/Alc/filters/nfc.h index d59280d0..40aca36e 100644 --- a/Alc/filters/nfc.h +++ b/Alc/filters/nfc.h @@ -1,10 +1,6 @@ #ifndef FILTER_NFC_H #define FILTER_NFC_H -#ifdef __cplusplus -extern "C" { -#endif - struct NfcFilter1 { float base_gain, gain; float b1, a1; @@ -21,37 +17,33 @@ struct NfcFilter3 { float z[3]; }; -typedef struct NfcFilter { - struct NfcFilter1 first; - struct NfcFilter2 second; - struct NfcFilter3 third; -} NfcFilter; - - -/* NOTE: - * w0 = speed_of_sound / (source_distance * sample_rate); - * w1 = speed_of_sound / (control_distance * sample_rate); - * - * Generally speaking, the control distance should be approximately the average - * speaker distance, or based on the reference delay if outputing NFC-HOA. It - * must not be negative, 0, or infinite. The source distance should not be too - * small relative to the control distance. - */ - -void NfcFilterCreate(NfcFilter *nfc, const float w0, const float w1); -void NfcFilterAdjust(NfcFilter *nfc, const float w0); - -/* Near-field control filter for first-order ambisonic channels (1-3). */ -void NfcFilterProcess1(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRICT src, const int count); - -/* Near-field control filter for second-order ambisonic channels (4-8). */ -void NfcFilterProcess2(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRICT src, const int count); - -/* Near-field control filter for third-order ambisonic channels (9-15). */ -void NfcFilterProcess3(NfcFilter *nfc, float *RESTRICT dst, const float *RESTRICT src, const int count); - -#ifdef __cplusplus -} // extern "C" -#endif +class NfcFilter { + NfcFilter1 first; + NfcFilter2 second; + NfcFilter3 third; + +public: + /* NOTE: + * w0 = speed_of_sound / (source_distance * sample_rate); + * w1 = speed_of_sound / (control_distance * sample_rate); + * + * Generally speaking, the control distance should be approximately the + * average speaker distance, or based on the reference delay if outputing + * NFC-HOA. It must not be negative, 0, or infinite. The source distance + * should not be too small relative to the control distance. + */ + + void init(const float w0, const float w1) noexcept; + void adjust(const float w0) noexcept; + + /* Near-field control filter for first-order ambisonic channels (1-3). */ + void process1(float *RESTRICT dst, const float *RESTRICT src, const int count); + + /* Near-field control filter for second-order ambisonic channels (4-8). */ + void process2(float *RESTRICT dst, const float *RESTRICT src, const int count); + + /* Near-field control filter for third-order ambisonic channels (9-15). */ + void process3(float *RESTRICT dst, const float *RESTRICT src, const int count); +}; #endif /* FILTER_NFC_H */ diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 91c48daf..f60043d7 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -531,21 +531,21 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize ALfloat *nfcsamples{Device->TempBuffer[NFC_DATA_BUF]}; ALsizei chanoffset{voice->Direct.ChannelsPerOrder[0]}; - using FilterProc = void(NfcFilter*,ALfloat*,const ALfloat*,ALsizei); - auto apply_nfc = [voice,parms,samples,DstBufferSize,Counter,OutPos,&chanoffset,nfcsamples](FilterProc &process, ALsizei order) -> void + using FilterProc = void (NfcFilter::*)(float*,const float*,int); + auto apply_nfc = [voice,parms,samples,DstBufferSize,Counter,OutPos,&chanoffset,nfcsamples](FilterProc process, ALsizei order) -> void { if(voice->Direct.ChannelsPerOrder[order] < 1) return; - process(&parms->NFCtrlFilter, nfcsamples, samples, DstBufferSize); + (parms->NFCtrlFilter.*process)(nfcsamples, samples, DstBufferSize); MixSamples(nfcsamples, voice->Direct.ChannelsPerOrder[order], voice->Direct.Buffer+chanoffset, parms->Gains.Current+chanoffset, parms->Gains.Target+chanoffset, Counter, OutPos, DstBufferSize ); chanoffset += voice->Direct.ChannelsPerOrder[order]; }; - apply_nfc(NfcFilterProcess1, 1); - apply_nfc(NfcFilterProcess2, 2); - apply_nfc(NfcFilterProcess3, 3); + apply_nfc(&NfcFilter::process1, 1); + apply_nfc(&NfcFilter::process2, 2); + apply_nfc(&NfcFilter::process3, 3); } } else diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 42f05131..872bc9ee 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -2840,8 +2840,8 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / (device->AvgSpeakerDist * device->Frequency); std::for_each(voice->Direct.Params+0, voice->Direct.Params+voice->NumChannels, - [w1](DirectParams &parms) -> void - { NfcFilterCreate(&parms.NFCtrlFilter, 0.0f, w1); } + [w1](DirectParams &parms) noexcept -> void + { parms.NFCtrlFilter.init(0.0f, w1); } ); } -- cgit v1.2.3 From e60d0886d070caa2dd82ef8ae1294d8dda77b745 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 5 Dec 2018 15:38:05 -0800 Subject: Use class methods for BandSplitter and SplitterAllpass filters --- Alc/alu.cpp | 6 ++--- Alc/bformatdec.cpp | 19 ++++++--------- Alc/filters/splitter.cpp | 63 +++++++++++++++++++++++------------------------- Alc/filters/splitter.h | 23 +++++++++--------- Alc/hrtf.cpp | 10 ++++---- Alc/panning.cpp | 4 +-- 6 files changed, 60 insertions(+), 65 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index def52e3d..4a8b6687 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1549,11 +1549,11 @@ void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*RESTRICT Buffer)[BUFFER { if(i == lidx || i == ridx) continue; - splitterap_process(&Stablizer->APFilter[i], Buffer[i], SamplesToDo); + Stablizer->APFilter[i].process(Buffer[i], SamplesToDo); } - bandsplit_process(&Stablizer->LFilter, lsplit[1], lsplit[0], Buffer[lidx], SamplesToDo); - bandsplit_process(&Stablizer->RFilter, rsplit[1], rsplit[0], Buffer[ridx], SamplesToDo); + Stablizer->LFilter.process(lsplit[1], lsplit[0], Buffer[lidx], SamplesToDo); + Stablizer->RFilter.process(rsplit[1], rsplit[0], Buffer[ridx], SamplesToDo); for(i = 0;i < SamplesToDo;i++) { diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index f82d2d9c..24b9053b 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -139,7 +139,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount memset(dec->UpSampler, 0, sizeof(dec->UpSampler)); ratio = 400.0f / (ALfloat)srate; for(i = 0;i < 4;i++) - bandsplit_init(&dec->UpSampler[i].XOver, ratio); + dec->UpSampler[i].XOver.init(ratio); if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { periphonic = true; @@ -216,7 +216,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount ratio = conf->XOverFreq / (ALfloat)srate; for(i = 0;i < MAX_AMBI_COEFFS;i++) - bandsplit_init(&dec->XOver[i], ratio); + dec->XOver[i].init(ratio); ratio = powf(10.0f, conf->XOverRatio / 40.0f); for(i = 0;i < conf->NumSpeakers;i++) @@ -285,8 +285,8 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BU if(dec->DualBand) { for(i = 0;i < dec->NumChannels;i++) - bandsplit_process(&dec->XOver[i], dec->SamplesHF[i].data(), dec->SamplesLF[i].data(), - InSamples[i], SamplesToDo); + dec->XOver[i].process(dec->SamplesHF[i].data(), dec->SamplesLF[i].data(), InSamples[i], + SamplesToDo); for(chan = 0;chan < OutChannels;chan++) { @@ -344,8 +344,7 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[B /* First, split the first-order components into low and high frequency * bands. */ - bandsplit_process(&dec->UpSampler[i].XOver, - dec->Samples[HF_BAND].data(), dec->Samples[LF_BAND].data(), + dec->UpSampler[i].XOver.process(dec->Samples[HF_BAND].data(), dec->Samples[LF_BAND].data(), InSamples[i], SamplesToDo ); @@ -365,7 +364,7 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat ratio = 400.0f / (ALfloat)device->Frequency; for(i = 0;i < 4;i++) - bandsplit_init(&ambiup->XOver[i], ratio); + ambiup->XOver[i].init(ratio); memset(ambiup->Gains, 0, sizeof(ambiup->Gains)); if(device->Dry.CoeffCount > 0) @@ -419,10 +418,8 @@ void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*RESTRICT OutBuffer)[ for(i = 0;i < 4;i++) { - bandsplit_process(&ambiup->XOver[i], - ambiup->Samples[HF_BAND], ambiup->Samples[LF_BAND], - InSamples[i], SamplesToDo - ); + ambiup->XOver[i].process(ambiup->Samples[HF_BAND], ambiup->Samples[LF_BAND], InSamples[i], + SamplesToDo); for(j = 0;j < OutChannels;j++) MixRowSamples(OutBuffer[j], ambiup->Gains[i][j], diff --git a/Alc/filters/splitter.cpp b/Alc/filters/splitter.cpp index d13c8a77..fb817d62 100644 --- a/Alc/filters/splitter.cpp +++ b/Alc/filters/splitter.cpp @@ -9,37 +9,36 @@ #include "math_defs.h" -void bandsplit_init(BandSplitter *splitter, float f0norm) +void BandSplitter::init(float f0norm) { float w = f0norm * F_TAU; float cw = std::cos(w); if(cw > FLT_EPSILON) - splitter->coeff = (std::sin(w) - 1.0f) / cw; + coeff = (std::sin(w) - 1.0f) / cw; else - splitter->coeff = cw * -0.5f; + coeff = cw * -0.5f; - splitter->lp_z1 = 0.0f; - splitter->lp_z2 = 0.0f; - splitter->hp_z1 = 0.0f; + lp_z1 = 0.0f; + lp_z2 = 0.0f; + hp_z1 = 0.0f; } -void bandsplit_clear(BandSplitter *splitter) +void BandSplitter::clear() { - splitter->lp_z1 = 0.0f; - splitter->lp_z2 = 0.0f; - splitter->hp_z1 = 0.0f; + lp_z1 = 0.0f; + lp_z2 = 0.0f; + hp_z1 = 0.0f; } -void bandsplit_process(BandSplitter *splitter, float *RESTRICT hpout, float *RESTRICT lpout, - const ALfloat *input, int count) +void BandSplitter::process(float *RESTRICT hpout, float *RESTRICT lpout, const float *input, int count) { ASSUME(count > 0); - const float ap_coeff{splitter->coeff}; - const float lp_coeff{splitter->coeff*0.5f + 0.5f}; - float lp_z1{splitter->lp_z1}; - float lp_z2{splitter->lp_z2}; - float ap_z1{splitter->hp_z1}; + const float ap_coeff{this->coeff}; + const float lp_coeff{this->coeff*0.5f + 0.5f}; + float lp_z1{this->lp_z1}; + float lp_z2{this->lp_z2}; + float ap_z1{this->hp_z1}; auto proc_sample = [ap_coeff,lp_coeff,&lp_z1,&lp_z2,&ap_z1,&lpout](const float in) noexcept -> float { /* Low-pass sample processing. */ @@ -60,36 +59,34 @@ void bandsplit_process(BandSplitter *splitter, float *RESTRICT hpout, float *RES /* High-pass generated from removing low-passed output. */ return ap_y - lp_y; }; - std::transform(input, input+count, hpout, proc_sample); - splitter->lp_z1 = lp_z1; - splitter->lp_z2 = lp_z2; - splitter->hp_z1 = ap_z1; + std::transform(input, input+count, hpout, proc_sample); + this->lp_z1 = lp_z1; + this->lp_z2 = lp_z2; + this->hp_z1 = ap_z1; } -void splitterap_init(SplitterAllpass *splitter, float f0norm) +void SplitterAllpass::init(float f0norm) { float w = f0norm * F_TAU; float cw = std::cos(w); if(cw > FLT_EPSILON) - splitter->coeff = (std::sin(w) - 1.0f) / cw; + coeff = (std::sin(w) - 1.0f) / cw; else - splitter->coeff = cw * -0.5f; + coeff = cw * -0.5f; - splitter->z1 = 0.0f; + z1 = 0.0f; } -void splitterap_clear(SplitterAllpass *splitter) -{ - splitter->z1 = 0.0f; -} +void SplitterAllpass::clear() +{ z1 = 0.0f; } -void splitterap_process(SplitterAllpass *splitter, float *RESTRICT samples, int count) +void SplitterAllpass::process(float *RESTRICT samples, int count) { ASSUME(count > 0); - const float coeff{splitter->coeff}; - float z1{splitter->z1}; + const float coeff{this->coeff}; + float z1{this->z1}; auto proc_sample = [coeff,&z1](const float in) noexcept -> float { float out{in*coeff + z1}; @@ -97,5 +94,5 @@ void splitterap_process(SplitterAllpass *splitter, float *RESTRICT samples, int return out; }; std::transform(samples, samples+count, samples, proc_sample); - splitter->z1 = z1; + this->z1 = z1; } diff --git a/Alc/filters/splitter.h b/Alc/filters/splitter.h index 96ecdb43..6e3b5cbb 100644 --- a/Alc/filters/splitter.h +++ b/Alc/filters/splitter.h @@ -6,29 +6,30 @@ /* Band splitter. Splits a signal into two phase-matching frequency bands. */ -struct BandSplitter { +class BandSplitter { float coeff{0.0f}; float lp_z1{0.0f}; float lp_z2{0.0f}; float hp_z1{0.0f}; -}; -void bandsplit_init(BandSplitter *splitter, float f0norm); -void bandsplit_clear(BandSplitter *splitter); -void bandsplit_process(BandSplitter *splitter, float *RESTRICT hpout, float *RESTRICT lpout, - const float *input, int count); +public: + void init(float f0norm); + void clear(); + void process(float *RESTRICT hpout, float *RESTRICT lpout, const float *input, int count); +}; /* The all-pass portion of the band splitter. Applies the same phase shift * without splitting the signal. */ -struct SplitterAllpass { +class SplitterAllpass { float coeff{0.0f}; float z1{0.0f}; -}; -void splitterap_init(SplitterAllpass *splitter, float f0norm); -void splitterap_clear(SplitterAllpass *splitter); -void splitterap_process(SplitterAllpass *splitter, float *RESTRICT samples, int count); +public: + void init(float f0norm); + void clear(); + void process(float *RESTRICT samples, int count); +}; struct FrontStablizer { diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 19919717..9b645b05 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -309,7 +309,7 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N ALfloat temps[3][HRIR_LENGTH]{}; BandSplitter splitter; - bandsplit_init(&splitter, 400.0f / (ALfloat)Hrtf->sampleRate); + splitter.init(400.0f / (ALfloat)Hrtf->sampleRate); for(ALsizei c{0};c < AmbiCount;++c) { const ALfloat (*fir)[2] = &Hrtf->coeffs[idx[c] * Hrtf->irSize]; @@ -334,10 +334,10 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N else { /* Band-split left HRIR into low and high frequency responses. */ - bandsplit_clear(&splitter); + splitter.clear(); for(ALsizei i{0};i < Hrtf->irSize;++i) temps[2][i] = fir[i][0]; - bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); + splitter.process(temps[0], temps[1], temps[2], HRIR_LENGTH); /* Apply left ear response with delay. */ for(ALsizei i{0};i < NumChannels;++i) @@ -354,10 +354,10 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N } /* Band-split right HRIR into low and high frequency responses. */ - bandsplit_clear(&splitter); + splitter.clear(); for(ALsizei i{0};i < Hrtf->irSize;++i) temps[2][i] = fir[i][1]; - bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); + splitter.process(temps[0], temps[1], temps[2], HRIR_LENGTH); /* Apply right ear response with delay. */ for(ALsizei i{0};i < NumChannels;++i) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 7b5a6674..d8909fda 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -1031,11 +1031,11 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf ALfloat scale = (ALfloat)(5000.0 / device->Frequency); std::unique_ptr stablizer{new FrontStablizer{}}; - bandsplit_init(&stablizer->LFilter, scale); + stablizer->LFilter.init(scale); stablizer->RFilter = stablizer->LFilter; /* Initialize all-pass filters for all other channels. */ - splitterap_init(&stablizer->APFilter[0], scale); + stablizer->APFilter[0].init(scale); for(i = 1;i < (size_t)device->RealOut.NumChannels;i++) stablizer->APFilter[i] = stablizer->APFilter[0]; -- cgit v1.2.3 From 42d26472eb514a2fcb1eafbed93f56a697ebb3a0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 5 Dec 2018 16:35:06 -0800 Subject: Remove some more explicit loops --- Alc/panning.cpp | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index d8909fda..3b98de5b 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -924,21 +924,16 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf { /* Hold the HRTF the device last used, in case it's used again. */ struct Hrtf *old_hrtf = device->HrtfHandle; - const char *mode; - bool headphones; - int bs2blevel; - size_t i; device->mHrtfState = nullptr; device->HrtfHandle = nullptr; device->HrtfName.clear(); device->Render_Mode = NormalRender; - memset(&device->Dry.Ambi, 0, sizeof(device->Dry.Ambi)); + device->Dry.Ambi = AmbiConfig{}; device->Dry.CoeffCount = 0; device->Dry.NumChannels = 0; - for(i = 0;i < MAX_AMBI_ORDER+1;i++) - device->NumChannelsPerOrder[i] = 0; + std::fill(std::begin(device->NumChannelsPerOrder), std::end(device->NumChannelsPerOrder), 0); device->AvgSpeakerDist = 0.0f; device->ChannelDelay.clear(); @@ -1036,8 +1031,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf /* Initialize all-pass filters for all other channels. */ stablizer->APFilter[0].init(scale); - for(i = 1;i < (size_t)device->RealOut.NumChannels;i++) - stablizer->APFilter[i] = stablizer->APFilter[0]; + std::fill(std::begin(stablizer->APFilter)+1, std::end(stablizer->APFilter), + stablizer->APFilter[0]); device->Stablizer = std::move(stablizer); } @@ -1055,7 +1050,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf device->AmbiDecoder = nullptr; - headphones = device->IsHeadphones; + bool headphones{device->IsHeadphones != AL_FALSE}; if(device->Type != Loopback) { const char *mode; @@ -1107,17 +1102,22 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf Hrtf_DecRef(hrtf); } - for(i = 0;!device->HrtfHandle && i < device->HrtfList.size();i++) + if(!device->HrtfHandle) { - const EnumeratedHrtf &entry = device->HrtfList[i]; - struct Hrtf *hrtf = GetLoadedHrtf(entry.hrtf); - if(hrtf && hrtf->sampleRate == device->Frequency) + auto find_hrtf = [device](const EnumeratedHrtf &entry) -> bool { + struct Hrtf *hrtf = GetLoadedHrtf(entry.hrtf); + if(!hrtf) return false; + if(hrtf->sampleRate != device->Frequency) + { + Hrtf_DecRef(hrtf); + return false; + } device->HrtfHandle = hrtf; device->HrtfName = entry.name; - } - else if(hrtf) - Hrtf_DecRef(hrtf); + return true; + }; + std::find_if(device->HrtfList.cbegin(), device->HrtfList.cend(), find_hrtf); } if(device->HrtfHandle) @@ -1127,6 +1127,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf old_hrtf = NULL; device->Render_Mode = HrtfRender; + const char *mode; if(ConfigValueStr(device->DeviceName.c_str(), NULL, "hrtf-mode", &mode)) { if(strcasecmp(mode, "full") == 0) @@ -1168,8 +1169,8 @@ no_hrtf: device->AmbiUp = nullptr; - bs2blevel = ((headphones && hrtf_appreq != Hrtf_Disable) || - (hrtf_appreq == Hrtf_Enable)) ? 5 : 0; + int bs2blevel{((headphones && hrtf_appreq != Hrtf_Disable) || + (hrtf_appreq == Hrtf_Enable)) ? 5 : 0}; if(device->Type != Loopback) ConfigValueInt(device->DeviceName.c_str(), NULL, "cf_level", &bs2blevel); if(bs2blevel > 0 && bs2blevel <= 6) @@ -1183,6 +1184,7 @@ no_hrtf: TRACE("BS2B disabled\n"); + const char *mode; if(ConfigValueStr(device->DeviceName.c_str(), NULL, "stereo-encoding", &mode)) { if(strcasecmp(mode, "uhj") == 0) -- cgit v1.2.3 From 0f24139b57460c71d66b9a090217d34706d64dde Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 6 Dec 2018 22:24:20 -0800 Subject: Use a constructor instead of a macro to initialize AsyncEvent --- Alc/alu.cpp | 6 +++--- Alc/mixvoice.cpp | 2 +- OpenAL32/Include/alMain.h | 8 +++++--- OpenAL32/alSource.cpp | 2 +- OpenAL32/event.cpp | 4 ++-- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 4a8b6687..f2068ead 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -288,7 +288,7 @@ void SendSourceStoppedEvent(ALCcontext *context, ALuint id) ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)}; if(!(enabledevt&EventType_SourceStateChange)) return; - AsyncEvent evt{ASYNC_EVENT(EventType_SourceStateChange)}; + AsyncEvent evt{EventType_SourceStateChange}; evt.u.srcstate.id = id; evt.u.srcstate.state = AL_STOPPED; @@ -414,7 +414,7 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) /* Otherwise, replace it and send off the old one with a release * event. */ - AsyncEvent evt = ASYNC_EVENT(EventType_ReleaseEffectState); + AsyncEvent evt{EventType_ReleaseEffectState}; evt.u.mEffectState = slot->Params.mEffectState; slot->Params.mEffectState = state; @@ -1811,7 +1811,7 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) if(!device->Connected.exchange(AL_FALSE, std::memory_order_acq_rel)) return; - AsyncEvent evt = ASYNC_EVENT(EventType_Disconnected); + AsyncEvent evt{EventType_Disconnected}; evt.u.user.type = AL_EVENT_TYPE_DISCONNECTED_SOFT; evt.u.user.id = 0; evt.u.user.param = 0; diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index f60043d7..cd5d2504 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -722,7 +722,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize ALbitfieldSOFT enabledevt{Context->EnabledEvts.load(std::memory_order_acquire)}; if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) { - AsyncEvent evt{ASYNC_EVENT(EventType_BufferCompleted)}; + AsyncEvent evt{EventType_BufferCompleted}; evt.u.bufcomp.id = SourceID; evt.u.bufcomp.count = buffers_done; if(ll_ringbuffer_write(Context->AsyncEvents, &evt, 1) == 1) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 75dc6c74..cbf00c50 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -842,7 +842,7 @@ enum { }; struct AsyncEvent { - unsigned int EnumType; + unsigned int EnumType{0u}; union { char dummy; struct { @@ -860,9 +860,11 @@ struct AsyncEvent { ALchar msg[1008]; } user; EffectState *mEffectState; - } u; + } u{}; + + AsyncEvent() noexcept = default; + constexpr AsyncEvent(unsigned int type) noexcept : EnumType{type} { } }; -#define ASYNC_EVENT(t) AsyncEvent{ t, { 0 } } void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends); diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 872bc9ee..f257da83 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -687,7 +687,7 @@ void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)}; if(!(enabledevt&EventType_SourceStateChange)) return; - AsyncEvent evt{ASYNC_EVENT(EventType_SourceStateChange)}; + AsyncEvent evt{EventType_SourceStateChange}; evt.u.srcstate.id = id; evt.u.srcstate.state = state; diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index 1a4e1df0..ad3fd4ab 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -18,9 +18,9 @@ static int EventThread(ALCcontext *context) { bool quitnow{false}; + AsyncEvent evt{}; while(LIKELY(!quitnow)) { - AsyncEvent evt; if(ll_ringbuffer_read(context->AsyncEvents, &evt, 1) == 0) { context->EventSem.wait(); @@ -90,7 +90,7 @@ void StartEventThrd(ALCcontext *ctx) void StopEventThrd(ALCcontext *ctx) { - static constexpr AsyncEvent kill_evt = ASYNC_EVENT(EventType_KillThread); + static constexpr AsyncEvent kill_evt{EventType_KillThread}; while(ll_ringbuffer_write(ctx->AsyncEvents, &kill_evt, 1) == 0) std::this_thread::yield(); ctx->EventSem.post(); -- cgit v1.2.3 From 6e4c85625707b28da7baf51d7c315c3982531439 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 7 Dec 2018 18:38:56 -0800 Subject: Add fourth-order methods to the NFC filter Unused, but it finishes out the currently possible implementations. --- Alc/filters/nfc.cpp | 228 +++++++++++++++++++++++++--------------------------- Alc/filters/nfc.h | 9 +++ 2 files changed, 119 insertions(+), 118 deletions(-) diff --git a/Alc/filters/nfc.cpp b/Alc/filters/nfc.cpp index 8cabfc5b..fd98eef0 100644 --- a/Alc/filters/nfc.cpp +++ b/Alc/filters/nfc.cpp @@ -50,12 +50,12 @@ namespace { -constexpr float B[4][3] = { +constexpr float B[5][4] = { { 0.0f }, { 1.0f }, { 3.0f, 3.0f }, { 3.6778f, 6.4595f, 2.3222f }, - /*{ 4.2076f, 11.4877f, 5.7924f, 9.1401f }*/ + { 4.2076f, 11.4877f, 5.7924f, 9.1401f } }; NfcFilter1 NfcFilterCreate1(const float w0, const float w1) noexcept @@ -219,6 +219,81 @@ void NfcFilterAdjust3(NfcFilter3 *nfc, const float w0) noexcept nfc->b3 = 2.0f * b_00 / g_0; } + +NfcFilter4 NfcFilterCreate4(const float w0, const float w1) noexcept +{ + NfcFilter4 nfc{}; + float b_10, b_11, g_1; + float r; + + nfc.base_gain = 1.0f; + nfc.gain = 1.0f; + + /* Calculate bass-boost coefficients. */ + r = 0.5f * w0; + b_10 = B[4][0] * r; + b_11 = B[4][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc.gain *= g_1; + nfc.b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc.b2 = 4.0f * b_11 / g_1; + + b_10 = B[4][2] * r; + b_11 = B[4][3] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc.gain *= g_1; + nfc.b3 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc.b4 = 4.0f * b_11 / g_1; + + /* Calculate bass-cut coefficients. */ + r = 0.5f * w1; + b_10 = B[4][0] * r; + b_11 = B[4][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc.base_gain /= g_1; + nfc.gain /= g_1; + nfc.a1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc.a2 = 4.0f * b_11 / g_1; + + b_10 = B[4][2] * r; + b_11 = B[4][3] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc.base_gain /= g_1; + nfc.gain /= g_1; + nfc.a3 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc.a4 = 4.0f * b_11 / g_1; + + return nfc; +} + +void NfcFilterAdjust4(NfcFilter4 *nfc, const float w0) noexcept +{ + float b_10, b_11, g_1; + float r; + + r = 0.5f * w0; + b_10 = B[4][0] * r; + b_11 = B[4][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc->gain = nfc->base_gain * g_1; + nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc->b2 = 4.0f * b_11 / g_1; + + b_10 = B[4][2] * r; + b_11 = B[4][3] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc->gain *= nfc->base_gain * g_1; + nfc->b3 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc->b4 = 4.0f * b_11 / g_1; +} + + } // namespace void NfcFilter::init(const float w0, const float w1) noexcept @@ -226,6 +301,7 @@ void NfcFilter::init(const float w0, const float w1) noexcept first = NfcFilterCreate1(w0, w1); second = NfcFilterCreate2(w0, w1); third = NfcFilterCreate3(w0, w1); + fourth = NfcFilterCreate4(w0, w1); } void NfcFilter::adjust(const float w0) noexcept @@ -233,6 +309,7 @@ void NfcFilter::adjust(const float w0) noexcept NfcFilterAdjust1(&first, w0); NfcFilterAdjust2(&second, w0); NfcFilterAdjust3(&third, w0); + NfcFilterAdjust4(&fourth, w0); } @@ -311,124 +388,39 @@ void NfcFilter::process3(float *RESTRICT dst, const float *RESTRICT src, const i third.z[2] = z3; } -#if 0 /* Original methods the above are derived from. */ -static void NfcFilterCreate(NfcFilter *nfc, const ALsizei order, const float src_dist, const float ctl_dist, const float rate) +void NfcFilter::process4(float *RESTRICT dst, const float *RESTRICT src, const int count) { - static const float B[4][5] = { - { }, - { 1.0f }, - { 3.0f, 3.0f }, - { 3.6778f, 6.4595f, 2.3222f }, - { 4.2076f, 11.4877f, 5.7924f, 9.1401f } - }; - float w0 = SPEEDOFSOUNDMETRESPERSEC / (src_dist * rate); - float w1 = SPEEDOFSOUNDMETRESPERSEC / (ctl_dist * rate); - ALsizei i; - float r; - - nfc->g = 1.0f; - nfc->coeffs[0] = 1.0f; - - /* NOTE: Slight adjustment from the literature to raise the center - * frequency a bit (0.5 -> 1.0). - */ - r = 1.0f * w0; - for(i = 0; i < (order-1);i += 2) - { - float b_10 = B[order][i ] * r; - float b_11 = B[order][i+1] * r * r; - float g_1 = 1.0f + b_10 + b_11; - - nfc->b[i] = b_10; - nfc->b[i + 1] = b_11; - nfc->coeffs[0] *= g_1; - nfc->coeffs[i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[i+2] = (4.0f * b_11) / g_1; - } - if(i < order) - { - float b_00 = B[order][i] * r; - float g_0 = 1.0f + b_00; - - nfc->b[i] = b_00; - nfc->coeffs[0] *= g_0; - nfc->coeffs[i+1] = (2.0f * b_00) / g_0; - } - - r = 1.0f * w1; - for(i = 0;i < (order-1);i += 2) - { - float b_10 = B[order][i ] * r; - float b_11 = B[order][i+1] * r * r; - float g_1 = 1.0f + b_10 + b_11; - - nfc->g /= g_1; - nfc->coeffs[0] /= g_1; - nfc->coeffs[order+i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[order+i+2] = (4.0f * b_11) / g_1; - } - if(i < order) - { - float b_00 = B[order][i] * r; - float g_0 = 1.0f + b_00; - - nfc->g /= g_0; - nfc->coeffs[0] /= g_0; - nfc->coeffs[order+i+1] = (2.0f * b_00) / g_0; - } - - for(i = 0; i < MAX_AMBI_ORDER; i++) - nfc->history[i] = 0.0f; -} - -static void NfcFilterAdjust(NfcFilter *nfc, const float distance) -{ - int i; - - nfc->coeffs[0] = nfc->g; - - for(i = 0;i < (nfc->order-1);i += 2) - { - float b_10 = nfc->b[i] / distance; - float b_11 = nfc->b[i+1] / (distance * distance); - float g_1 = 1.0f + b_10 + b_11; - - nfc->coeffs[0] *= g_1; - nfc->coeffs[i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[i+2] = (4.0f * b_11) / g_1; - } - if(i < nfc->order) - { - float b_00 = nfc->b[i] / distance; - float g_0 = 1.0f + b_00; - - nfc->coeffs[0] *= g_0; - nfc->coeffs[i+1] = (2.0f * b_00) / g_0; - } -} - -static float NfcFilterProcess(const float in, NfcFilter *nfc) -{ - int i; - float out = in * nfc->coeffs[0]; + ASSUME(count > 0); - for(i = 0;i < (nfc->order-1);i += 2) + const float gain{fourth.gain}; + const float b1{fourth.b1}; + const float b2{fourth.b2}; + const float b3{fourth.b3}; + const float b4{fourth.b4}; + const float a1{fourth.a1}; + const float a2{fourth.a2}; + const float a3{fourth.a3}; + const float a4{fourth.a4}; + float z1{fourth.z[0]}; + float z2{fourth.z[1]}; + float z3{fourth.z[2]}; + float z4{fourth.z[3]}; + auto proc_sample = [gain,b1,b2,b3,b4,a1,a2,a3,a4,&z1,&z2,&z3,&z4](const float in) noexcept -> float { - float y = out - (nfc->coeffs[nfc->order+i+1] * nfc->history[i]) - - (nfc->coeffs[nfc->order+i+2] * nfc->history[i+1]) + 1.0e-30f; - out = y + (nfc->coeffs[i+1]*nfc->history[i]) + (nfc->coeffs[i+2]*nfc->history[i+1]); - - nfc->history[i+1] += nfc->history[i]; - nfc->history[i] += y; - } - if(i < nfc->order) - { - float y = out - (nfc->coeffs[nfc->order+i+1] * nfc->history[i]) + 1.0e-30f; - - out = y + (nfc->coeffs[i+1] * nfc->history[i]); - nfc->history[i] += y; - } + float y{in*gain - a1*z1 - a2*z2}; + float out{y + b1*z1 + b2*z2}; + z2 += z1; + z1 += y; - return out; + y = out - a3*z3 - a4*z4; + out = y + b3*z3 + b4*z4; + z4 += z3; + z3 += y; + return out; + }; + std::transform(src, src+count, dst, proc_sample); + fourth.z[0] = z1; + fourth.z[1] = z2; + fourth.z[2] = z3; + fourth.z[3] = z4; } -#endif diff --git a/Alc/filters/nfc.h b/Alc/filters/nfc.h index 40aca36e..ca4f6f58 100644 --- a/Alc/filters/nfc.h +++ b/Alc/filters/nfc.h @@ -16,11 +16,17 @@ struct NfcFilter3 { float b1, b2, b3, a1, a2, a3; float z[3]; }; +struct NfcFilter4 { + float base_gain, gain; + float b1, b2, b3, b4, a1, a2, a3, a4; + float z[4]; +}; class NfcFilter { NfcFilter1 first; NfcFilter2 second; NfcFilter3 third; + NfcFilter4 fourth; public: /* NOTE: @@ -44,6 +50,9 @@ public: /* Near-field control filter for third-order ambisonic channels (9-15). */ void process3(float *RESTRICT dst, const float *RESTRICT src, const int count); + + /* Near-field control filter for fourth-order ambisonic channels (16-24). */ + void process4(float *RESTRICT dst, const float *RESTRICT src, const int count); }; #endif /* FILTER_NFC_H */ -- cgit v1.2.3 From ab5a11d5f39024e7a41b75f26045e0ac9504589f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 7 Dec 2018 21:46:22 -0800 Subject: Avoid using the deprecated mem_fun_ref method --- Alc/effects/equalizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index af571930..30408433 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -101,7 +101,7 @@ ALboolean ALequalizerState::deviceUpdate(ALCdevice *UNUSED(device)) for(auto &e : mChans) { std::for_each(std::begin(e.filter), std::end(e.filter), - std::mem_fun_ref(&BiquadFilter::clear)); + std::mem_fn(&BiquadFilter::clear)); std::fill(std::begin(e.CurrentGains), std::end(e.CurrentGains), 0.0f); } return AL_TRUE; -- cgit v1.2.3 From a603cc906f6fb50a2636350c0aa52bfddea55661 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 8 Dec 2018 00:08:39 -0800 Subject: Inline a simple method --- Alc/filters/splitter.cpp | 7 ------- Alc/filters/splitter.h | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/Alc/filters/splitter.cpp b/Alc/filters/splitter.cpp index fb817d62..85122890 100644 --- a/Alc/filters/splitter.cpp +++ b/Alc/filters/splitter.cpp @@ -23,13 +23,6 @@ void BandSplitter::init(float f0norm) hp_z1 = 0.0f; } -void BandSplitter::clear() -{ - lp_z1 = 0.0f; - lp_z2 = 0.0f; - hp_z1 = 0.0f; -} - void BandSplitter::process(float *RESTRICT hpout, float *RESTRICT lpout, const float *input, int count) { ASSUME(count > 0); diff --git a/Alc/filters/splitter.h b/Alc/filters/splitter.h index 6e3b5cbb..db31c138 100644 --- a/Alc/filters/splitter.h +++ b/Alc/filters/splitter.h @@ -14,7 +14,7 @@ class BandSplitter { public: void init(float f0norm); - void clear(); + void clear() noexcept { lp_z1 = lp_z2 = hp_z1 = 0.0f; } void process(float *RESTRICT hpout, float *RESTRICT lpout, const float *input, int count); }; -- cgit v1.2.3 From 7695afe0cb3a01ac32f4c04bedb57b3225effd3a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 8 Dec 2018 01:32:43 -0800 Subject: Clean up some more loops --- Alc/bformatdec.cpp | 98 ++++++++++++++++++++++++++++-------------------------- Alc/bformatdec.h | 2 +- Alc/panning.cpp | 8 ++--- 3 files changed, 55 insertions(+), 53 deletions(-) diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 24b9053b..6e8f9ca6 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include "bformatdec.h" #include "ambdec.h" @@ -108,15 +110,12 @@ ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn) } // namespace -void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS]) +void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]) { static constexpr ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; const ALfloat *coeff_scale = N3D2N3DScale; - bool periphonic; - ALfloat ratio; - ALsizei i; dec->Samples.clear(); dec->SamplesHF = nullptr; @@ -127,27 +126,31 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount dec->SamplesHF = dec->Samples.data(); dec->SamplesLF = dec->SamplesHF + dec->NumChannels; - dec->Enabled = 0; - for(i = 0;i < conf->NumSpeakers;i++) - dec->Enabled |= 1 << chanmap[i]; + dec->Enabled = std::accumulate(std::begin(chanmap), std::begin(chanmap)+conf->NumSpeakers, 0u, + [](ALuint mask, const ALsizei &chan) noexcept -> ALuint + { return mask | (1 << chan); } + ); if(conf->CoeffScale == AmbDecScale::SN3D) coeff_scale = SN3D2N3DScale; else if(conf->CoeffScale == AmbDecScale::FuMa) coeff_scale = FuMa2N3DScale; - memset(dec->UpSampler, 0, sizeof(dec->UpSampler)); - ratio = 400.0f / (ALfloat)srate; - for(i = 0;i < 4;i++) - dec->UpSampler[i].XOver.init(ratio); - if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) + float ratio{400.0f / (float)srate}; + for(auto &chan : dec->UpSampler) { - periphonic = true; + chan.XOver.init(ratio); + chan.XOver.clear(); + std::fill(std::begin(chan.Gains), std::end(chan.Gains), 0.0f); + } + const bool periphonic{(conf->ChanMask&AMBI_PERIPHONIC_MASK) != 0}; + if(periphonic) + { dec->UpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H3P : (conf->ChanMask > 0xf) ? W_SCALE_2H2P : 1.0f; dec->UpSampler[0].Gains[LF_BAND] = 1.0f; - for(i = 1;i < 4;i++) + for(ALsizei i{1};i < 4;i++) { dec->UpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H3P : (conf->ChanMask > 0xf) ? XYZ_SCALE_2H2P : 1.0f; @@ -156,12 +159,10 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount } else { - periphonic = false; - dec->UpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H0P : (conf->ChanMask > 0xf) ? W_SCALE_2H0P : 1.0f; dec->UpSampler[0].Gains[LF_BAND] = 1.0f; - for(i = 1;i < 3;i++) + for(ALsizei i{1};i < 3;i++) { dec->UpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H0P : (conf->ChanMask > 0xf) ? XYZ_SCALE_2H0P : 1.0f; @@ -175,7 +176,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount if(conf->FreqBands == 1) { dec->DualBand = AL_FALSE; - for(i = 0;i < conf->NumSpeakers;i++) + for(ALsizei i{0};i < conf->NumSpeakers;i++) { ALsizei chan = chanmap[i]; ALfloat gain; @@ -212,14 +213,15 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount } else { + using namespace std::placeholders; dec->DualBand = AL_TRUE; ratio = conf->XOverFreq / (ALfloat)srate; - for(i = 0;i < MAX_AMBI_COEFFS;i++) - dec->XOver[i].init(ratio); + std::for_each(std::begin(dec->XOver), std::end(dec->XOver), + std::bind(std::mem_fn(&BandSplitter::init), _1, ratio)); ratio = powf(10.0f, conf->XOverRatio / 40.0f); - for(i = 0;i < conf->NumSpeakers;i++) + for(ALsizei i{0};i < conf->NumSpeakers;i++) { ALsizei chan = chanmap[i]; ALfloat gain; @@ -280,8 +282,10 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount void bformatdec_process(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo) { - ALsizei chan, i; + ASSUME(OutChannels > 0); + ASSUME(SamplesToDo > 0); + ALsizei chan, i; if(dec->DualBand) { for(i = 0;i < dec->NumChannels;i++) @@ -290,10 +294,10 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BU for(chan = 0;chan < OutChannels;chan++) { - if(!(dec->Enabled&(1<Enabled&(1<ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); + std::fill(std::begin(dec->ChannelMix), std::begin(dec->ChannelMix)+SamplesToDo, 0.0f); MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][HF_BAND], &reinterpret_cast(dec->SamplesHF[0]), dec->NumChannels, 0, SamplesToDo @@ -303,23 +307,23 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BU dec->NumChannels, 0, SamplesToDo ); - for(i = 0;i < SamplesToDo;i++) - OutBuffer[chan][i] += dec->ChannelMix[i]; + std::transform(std::begin(dec->ChannelMix), std::begin(dec->ChannelMix)+SamplesToDo, + OutBuffer[chan], OutBuffer[chan], std::plus()); } } else { for(chan = 0;chan < OutChannels;chan++) { - if(!(dec->Enabled&(1<Enabled&(1<ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); + std::fill(std::begin(dec->ChannelMix), std::begin(dec->ChannelMix)+SamplesToDo, 0.0f); MixRowSamples(dec->ChannelMix, dec->Matrix.Single[chan], InSamples, dec->NumChannels, 0, SamplesToDo); - for(i = 0;i < SamplesToDo;i++) - OutBuffer[chan][i] += dec->ChannelMix[i]; + std::transform(std::begin(dec->ChannelMix), std::begin(dec->ChannelMix)+SamplesToDo, + OutBuffer[chan], OutBuffer[chan], std::plus()); } } } @@ -327,7 +331,8 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BU void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo) { - ALsizei i; + ASSUME(InChannels > 0); + ASSUME(SamplesToDo > 0); /* This up-sampler leverages the differences observed in dual-band second- * and third-order decoder matrices compared to first-order. For the same @@ -339,7 +344,7 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[B * subsequent higher-order decode generating the same response as a first- * order decode. */ - for(i = 0;i < InChannels;i++) + for(ALsizei i{0};i < InChannels;i++) { /* First, split the first-order components into low and high frequency * bands. @@ -359,21 +364,17 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[B void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat w_scale, ALfloat xyz_scale) { - ALfloat ratio; - ALsizei i; + using namespace std::placeholders; - ratio = 400.0f / (ALfloat)device->Frequency; - for(i = 0;i < 4;i++) - ambiup->XOver[i].init(ratio); + float ratio{400.0f / (float)device->Frequency}; + std::for_each(std::begin(ambiup->XOver), std::end(ambiup->XOver), + std::bind(std::mem_fn(&BandSplitter::init), _1, ratio)); memset(ambiup->Gains, 0, sizeof(ambiup->Gains)); if(device->Dry.CoeffCount > 0) { ALfloat encgains[8][MAX_OUTPUT_CHANNELS]; - ALsizei j; - size_t k; - - for(k = 0;k < COUNTOF(Ambi3DPoints);k++) + for(size_t k{0u};k < COUNTOF(Ambi3DPoints);k++) { ALfloat coeffs[MAX_AMBI_COEFFS] = { 0.0f }; CalcDirectionCoeffs(Ambi3DPoints[k], 0.0f, coeffs); @@ -385,12 +386,12 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat * (encgains) and output are transposed, so the input channels line up * with the rows and the output channels line up with the columns. */ - for(i = 0;i < 4;i++) + for(ALsizei i{0};i < 4;i++) { - for(j = 0;j < device->Dry.NumChannels;j++) + for(ALsizei j{0};j < device->Dry.NumChannels;j++) { ALdouble gain = 0.0; - for(k = 0;k < COUNTOF(Ambi3DDecoder);k++) + for(size_t k{0u};k < COUNTOF(Ambi3DDecoder);k++) gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][j]; ambiup->Gains[i][j][HF_BAND] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]); ambiup->Gains[i][j][LF_BAND] = (ALfloat)gain; @@ -399,7 +400,7 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat } else { - for(i = 0;i < 4;i++) + for(ALsizei i{0};i < 4;i++) { ALsizei index = GetChannelForACN(device->Dry, i); if(index != INVALID_UPSAMPLE_INDEX) @@ -414,14 +415,15 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo) { - ALsizei i, j; + ASSUME(OutChannels > 0); + ASSUME(SamplesToDo > 0); - for(i = 0;i < 4;i++) + for(ALsizei i{0};i < 4;i++) { ambiup->XOver[i].process(ambiup->Samples[HF_BAND], ambiup->Samples[LF_BAND], InSamples[i], SamplesToDo); - for(j = 0;j < OutChannels;j++) + for(ALsizei j{0};j < OutChannels;j++) MixRowSamples(OutBuffer[j], ambiup->Gains[i][j], ambiup->Samples, AmbiUpsampler::NumBands, 0, SamplesToDo ); diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 0d3fe611..56737a60 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -65,7 +65,7 @@ struct BFormatDec { DEF_NEWDEL(BFormatDec) }; -void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS]); +void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]); /* Decodes the ambisonic input to the given output channels. */ void bformatdec_process(BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo); diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 3b98de5b..2758a937 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -601,7 +601,7 @@ static void InitPanning(ALCdevice *device) device->RealOut.NumChannels = 0; } -static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) +static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) { ChannelMap chanmap[MAX_OUTPUT_CHANNELS]; const ALfloat *coeff_scale = N3D2N3DScale; @@ -686,10 +686,10 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A InitDistanceComp(device, conf, speakermap); } -static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) +static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) { - static const ALsizei chans_per_order2d[MAX_AMBI_ORDER+1] = { 1, 2, 2, 2 }; - static const ALsizei chans_per_order3d[MAX_AMBI_ORDER+1] = { 1, 3, 5, 7 }; + static constexpr ALsizei chans_per_order2d[MAX_AMBI_ORDER+1] = { 1, 2, 2, 2 }; + static constexpr ALsizei chans_per_order3d[MAX_AMBI_ORDER+1] = { 1, 3, 5, 7 }; ALfloat avg_dist; ALsizei count; ALsizei i; -- cgit v1.2.3 From 5ea3c8fb609f88446f73c4e0274b733f1bd5f1be Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 8 Dec 2018 02:50:34 -0800 Subject: Use member functions for BFormatDec and AmbiUpsampler --- Alc/alu.cpp | 20 +++--- Alc/bformatdec.cpp | 159 ++++++++++++++++++++++------------------------ Alc/bformatdec.h | 64 ++++++++++--------- Alc/panning.cpp | 8 +-- OpenAL32/Include/alMain.h | 4 +- 5 files changed, 124 insertions(+), 131 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index f2068ead..34634983 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -109,9 +109,8 @@ namespace { void ProcessHrtf(ALCdevice *device, ALsizei SamplesToDo) { if(device->AmbiUp) - ambiup_process(device->AmbiUp.get(), - device->Dry.Buffer, device->Dry.NumChannels, device->FOAOut.Buffer, - SamplesToDo + device->AmbiUp->process(device->Dry.Buffer, device->Dry.NumChannels, + device->FOAOut.Buffer, SamplesToDo ); int lidx{GetChannelIdxByName(&device->RealOut, FrontLeft)}; @@ -132,21 +131,18 @@ void ProcessHrtf(ALCdevice *device, ALsizei SamplesToDo) void ProcessAmbiDec(ALCdevice *device, ALsizei SamplesToDo) { if(device->Dry.Buffer != device->FOAOut.Buffer) - bformatdec_upSample(device->AmbiDecoder.get(), - device->Dry.Buffer, device->FOAOut.Buffer, device->FOAOut.NumChannels, - SamplesToDo + device->AmbiDecoder->upSample(device->Dry.Buffer, device->FOAOut.Buffer, + device->FOAOut.NumChannels, SamplesToDo ); - bformatdec_process(device->AmbiDecoder.get(), - device->RealOut.Buffer, device->RealOut.NumChannels, device->Dry.Buffer, - SamplesToDo + device->AmbiDecoder->process(device->RealOut.Buffer, device->RealOut.NumChannels, + device->Dry.Buffer, SamplesToDo ); } void ProcessAmbiUp(ALCdevice *device, ALsizei SamplesToDo) { - ambiup_process(device->AmbiUp.get(), - device->RealOut.Buffer, device->RealOut.NumChannels, device->FOAOut.Buffer, - SamplesToDo + device->AmbiUp->process(device->RealOut.Buffer, device->RealOut.NumChannels, + device->FOAOut.Buffer, SamplesToDo ); } diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 6e8f9ca6..00db0393 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -64,8 +64,8 @@ namespace { #define HF_BAND 0 #define LF_BAND 1 -static_assert(BFormatDec::NumBands == 2, "Unexpected BFormatDec::NumBands"); -static_assert(AmbiUpsampler::NumBands == 2, "Unexpected AmbiUpsampler::NumBands"); +static_assert(BFormatDec::sNumBands == 2, "Unexpected BFormatDec::sNumBands"); +static_assert(AmbiUpsampler::sNumBands == 2, "Unexpected AmbiUpsampler::sNumBands"); /* These points are in AL coordinates! */ constexpr ALfloat Ambi3DPoints[8][3] = { @@ -110,23 +110,23 @@ ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn) } // namespace -void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]) +void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]) { static constexpr ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; const ALfloat *coeff_scale = N3D2N3DScale; - dec->Samples.clear(); - dec->SamplesHF = nullptr; - dec->SamplesLF = nullptr; + mSamples.clear(); + mSamplesHF = nullptr; + mSamplesLF = nullptr; - dec->NumChannels = chancount; - dec->Samples.resize(dec->NumChannels * 2); - dec->SamplesHF = dec->Samples.data(); - dec->SamplesLF = dec->SamplesHF + dec->NumChannels; + mNumChannels = chancount; + mSamples.resize(mNumChannels * 2); + mSamplesHF = mSamples.data(); + mSamplesLF = mSamplesHF + mNumChannels; - dec->Enabled = std::accumulate(std::begin(chanmap), std::begin(chanmap)+conf->NumSpeakers, 0u, + mEnabled = std::accumulate(std::begin(chanmap), std::begin(chanmap)+conf->NumSpeakers, 0u, [](ALuint mask, const ALsizei &chan) noexcept -> ALuint { return mask | (1 << chan); } ); @@ -137,7 +137,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount coeff_scale = FuMa2N3DScale; float ratio{400.0f / (float)srate}; - for(auto &chan : dec->UpSampler) + for(auto &chan : mUpSampler) { chan.XOver.init(ratio); chan.XOver.clear(); @@ -147,35 +147,35 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount const bool periphonic{(conf->ChanMask&AMBI_PERIPHONIC_MASK) != 0}; if(periphonic) { - dec->UpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H3P : - (conf->ChanMask > 0xf) ? W_SCALE_2H2P : 1.0f; - dec->UpSampler[0].Gains[LF_BAND] = 1.0f; + mUpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H3P : + (conf->ChanMask > 0xf) ? W_SCALE_2H2P : 1.0f; + mUpSampler[0].Gains[LF_BAND] = 1.0f; for(ALsizei i{1};i < 4;i++) { - dec->UpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H3P : - (conf->ChanMask > 0xf) ? XYZ_SCALE_2H2P : 1.0f; - dec->UpSampler[i].Gains[LF_BAND] = 1.0f; + mUpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H3P : + (conf->ChanMask > 0xf) ? XYZ_SCALE_2H2P : 1.0f; + mUpSampler[i].Gains[LF_BAND] = 1.0f; } } else { - dec->UpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H0P : - (conf->ChanMask > 0xf) ? W_SCALE_2H0P : 1.0f; - dec->UpSampler[0].Gains[LF_BAND] = 1.0f; + mUpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H0P : + (conf->ChanMask > 0xf) ? W_SCALE_2H0P : 1.0f; + mUpSampler[0].Gains[LF_BAND] = 1.0f; for(ALsizei i{1};i < 3;i++) { - dec->UpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H0P : - (conf->ChanMask > 0xf) ? XYZ_SCALE_2H0P : 1.0f; - dec->UpSampler[i].Gains[LF_BAND] = 1.0f; + mUpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H0P : + (conf->ChanMask > 0xf) ? XYZ_SCALE_2H0P : 1.0f; + mUpSampler[i].Gains[LF_BAND] = 1.0f; } - dec->UpSampler[3].Gains[HF_BAND] = 0.0f; - dec->UpSampler[3].Gains[LF_BAND] = 0.0f; + mUpSampler[3].Gains[HF_BAND] = 0.0f; + mUpSampler[3].Gains[LF_BAND] = 0.0f; } - memset(&dec->Matrix, 0, sizeof(dec->Matrix)); + memset(&mMatrix, 0, sizeof(mMatrix)); if(conf->FreqBands == 1) { - dec->DualBand = AL_FALSE; + mDualBand = AL_FALSE; for(ALsizei i{0};i < conf->NumSpeakers;i++) { ALsizei chan = chanmap[i]; @@ -192,8 +192,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount else if(j == 3) gain = conf->HFOrderGain[2]; else if(j == 5) gain = conf->HFOrderGain[3]; if((conf->ChanMask&(1<Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] * - gain; + mMatrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] * gain; } } else @@ -205,8 +204,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount else if(j == 4) gain = conf->HFOrderGain[2]; else if(j == 9) gain = conf->HFOrderGain[3]; if((conf->ChanMask&(1<Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * - gain; + mMatrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * gain; } } } @@ -214,10 +212,10 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount else { using namespace std::placeholders; - dec->DualBand = AL_TRUE; + mDualBand = AL_TRUE; ratio = conf->XOverFreq / (ALfloat)srate; - std::for_each(std::begin(dec->XOver), std::end(dec->XOver), + std::for_each(std::begin(mXOver), std::end(mXOver), std::bind(std::mem_fn(&BandSplitter::init), _1, ratio)); ratio = powf(10.0f, conf->XOverRatio / 40.0f); @@ -237,8 +235,8 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount else if(j == 3) gain = conf->HFOrderGain[2] * ratio; else if(j == 5) gain = conf->HFOrderGain[3] * ratio; if((conf->ChanMask&(1<Matrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] / - coeff_scale[l] * gain; + mMatrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] / coeff_scale[l] * + gain; } for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++) { @@ -248,8 +246,8 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount else if(j == 3) gain = conf->LFOrderGain[2] / ratio; else if(j == 5) gain = conf->LFOrderGain[3] / ratio; if((conf->ChanMask&(1<Matrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] / - coeff_scale[l] * gain; + mMatrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] / coeff_scale[l] * + gain; } } else @@ -261,8 +259,8 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount else if(j == 4) gain = conf->HFOrderGain[2] * ratio; else if(j == 9) gain = conf->HFOrderGain[3] * ratio; if((conf->ChanMask&(1<Matrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] / - coeff_scale[j] * gain; + mMatrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * + gain; } for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++) { @@ -271,43 +269,42 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount else if(j == 4) gain = conf->LFOrderGain[2] / ratio; else if(j == 9) gain = conf->LFOrderGain[3] / ratio; if((conf->ChanMask&(1<Matrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] / - coeff_scale[j] * gain; + mMatrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] / coeff_scale[j] * + gain; } } } } } - -void bformatdec_process(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo) +void BFormatDec::process(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei SamplesToDo) { ASSUME(OutChannels > 0); ASSUME(SamplesToDo > 0); ALsizei chan, i; - if(dec->DualBand) + if(mDualBand) { - for(i = 0;i < dec->NumChannels;i++) - dec->XOver[i].process(dec->SamplesHF[i].data(), dec->SamplesLF[i].data(), InSamples[i], - SamplesToDo); + for(i = 0;i < mNumChannels;i++) + mXOver[i].process(mSamplesHF[i].data(), mSamplesLF[i].data(), InSamples[i], + SamplesToDo); for(chan = 0;chan < OutChannels;chan++) { - if(UNLIKELY(!(dec->Enabled&(1<ChannelMix), std::begin(dec->ChannelMix)+SamplesToDo, 0.0f); - MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][HF_BAND], - &reinterpret_cast(dec->SamplesHF[0]), - dec->NumChannels, 0, SamplesToDo + std::fill(std::begin(mChannelMix), std::begin(mChannelMix)+SamplesToDo, 0.0f); + MixRowSamples(mChannelMix, mMatrix.Dual[chan][HF_BAND], + &reinterpret_cast(mSamplesHF[0]), + mNumChannels, 0, SamplesToDo ); - MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][LF_BAND], - &reinterpret_cast(dec->SamplesLF[0]), - dec->NumChannels, 0, SamplesToDo + MixRowSamples(mChannelMix, mMatrix.Dual[chan][LF_BAND], + &reinterpret_cast(mSamplesLF[0]), + mNumChannels, 0, SamplesToDo ); - std::transform(std::begin(dec->ChannelMix), std::begin(dec->ChannelMix)+SamplesToDo, + std::transform(std::begin(mChannelMix), std::begin(mChannelMix)+SamplesToDo, OutBuffer[chan], OutBuffer[chan], std::plus()); } } @@ -315,21 +312,20 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BU { for(chan = 0;chan < OutChannels;chan++) { - if(UNLIKELY(!(dec->Enabled&(1<ChannelMix), std::begin(dec->ChannelMix)+SamplesToDo, 0.0f); - MixRowSamples(dec->ChannelMix, dec->Matrix.Single[chan], InSamples, - dec->NumChannels, 0, SamplesToDo); + std::fill(std::begin(mChannelMix), std::begin(mChannelMix)+SamplesToDo, 0.0f); + MixRowSamples(mChannelMix, mMatrix.Single[chan], InSamples, + mNumChannels, 0, SamplesToDo); - std::transform(std::begin(dec->ChannelMix), std::begin(dec->ChannelMix)+SamplesToDo, + std::transform(std::begin(mChannelMix), std::begin(mChannelMix)+SamplesToDo, OutBuffer[chan], OutBuffer[chan], std::plus()); } } } - -void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo) +void BFormatDec::upSample(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei InChannels, const ALsizei SamplesToDo) { ASSUME(InChannels > 0); ASSUME(SamplesToDo > 0); @@ -349,28 +345,26 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[B /* First, split the first-order components into low and high frequency * bands. */ - dec->UpSampler[i].XOver.process(dec->Samples[HF_BAND].data(), dec->Samples[LF_BAND].data(), - InSamples[i], SamplesToDo - ); + mUpSampler[i].XOver.process(mSamples[HF_BAND].data(), mSamples[LF_BAND].data(), + InSamples[i], SamplesToDo); /* Now write each band to the output. */ - MixRowSamples(OutBuffer[i], dec->UpSampler[i].Gains, - &reinterpret_cast(dec->Samples[0]), - BFormatDec::NumBands, 0, SamplesToDo - ); + MixRowSamples(OutBuffer[i], mUpSampler[i].Gains, + &reinterpret_cast(mSamples[0]), + sNumBands, 0, SamplesToDo); } } -void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat w_scale, ALfloat xyz_scale) +void AmbiUpsampler::reset(const ALCdevice *device, const ALfloat w_scale, const ALfloat xyz_scale) { using namespace std::placeholders; float ratio{400.0f / (float)device->Frequency}; - std::for_each(std::begin(ambiup->XOver), std::end(ambiup->XOver), + std::for_each(std::begin(mXOver), std::end(mXOver), std::bind(std::mem_fn(&BandSplitter::init), _1, ratio)); - memset(ambiup->Gains, 0, sizeof(ambiup->Gains)); + memset(mGains, 0, sizeof(mGains)); if(device->Dry.CoeffCount > 0) { ALfloat encgains[8][MAX_OUTPUT_CHANNELS]; @@ -393,8 +387,8 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat ALdouble gain = 0.0; for(size_t k{0u};k < COUNTOF(Ambi3DDecoder);k++) gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][j]; - ambiup->Gains[i][j][HF_BAND] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]); - ambiup->Gains[i][j][LF_BAND] = (ALfloat)gain; + mGains[i][j][HF_BAND] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]); + mGains[i][j][LF_BAND] = (ALfloat)gain; } } } @@ -406,26 +400,23 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat if(index != INVALID_UPSAMPLE_INDEX) { ALfloat scale = device->Dry.Ambi.Map[index].Scale; - ambiup->Gains[i][index][HF_BAND] = scale * ((i==0) ? w_scale : xyz_scale); - ambiup->Gains[i][index][LF_BAND] = scale; + mGains[i][index][HF_BAND] = scale * ((i==0) ? w_scale : xyz_scale); + mGains[i][index][LF_BAND] = scale; } } } } -void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo) +void AmbiUpsampler::process(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei SamplesToDo) { ASSUME(OutChannels > 0); ASSUME(SamplesToDo > 0); for(ALsizei i{0};i < 4;i++) { - ambiup->XOver[i].process(ambiup->Samples[HF_BAND], ambiup->Samples[LF_BAND], InSamples[i], - SamplesToDo); + mXOver[i].process(mSamples[HF_BAND], mSamples[LF_BAND], InSamples[i], SamplesToDo); for(ALsizei j{0};j < OutChannels;j++) - MixRowSamples(OutBuffer[j], ambiup->Gains[i][j], - ambiup->Samples, AmbiUpsampler::NumBands, 0, SamplesToDo - ); + MixRowSamples(OutBuffer[j], mGains[i][j], mSamples, sNumBands, 0, SamplesToDo); } } diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 56737a60..73754be8 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -34,62 +34,68 @@ extern const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS]; extern const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS]; -struct BFormatDec { - static constexpr size_t NumBands{2}; +class BFormatDec { +public: + static constexpr size_t sNumBands{2}; - ALuint Enabled; /* Bitfield of enabled channels. */ +private: + ALuint mEnabled; /* Bitfield of enabled channels. */ union { - alignas(16) ALfloat Dual[MAX_OUTPUT_CHANNELS][NumBands][MAX_AMBI_COEFFS]; + alignas(16) ALfloat Dual[MAX_OUTPUT_CHANNELS][sNumBands][MAX_AMBI_COEFFS]; alignas(16) ALfloat Single[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; - } Matrix; + } mMatrix; /* NOTE: BandSplitter filters are unused with single-band decoding */ - BandSplitter XOver[MAX_AMBI_COEFFS]; + BandSplitter mXOver[MAX_AMBI_COEFFS]; - al::vector, 16> Samples; + al::vector, 16> mSamples; /* These two alias into Samples */ - std::array *SamplesHF; - std::array *SamplesLF; + std::array *mSamplesHF; + std::array *mSamplesLF; - alignas(16) ALfloat ChannelMix[BUFFERSIZE]; + alignas(16) ALfloat mChannelMix[BUFFERSIZE]; struct { BandSplitter XOver; - ALfloat Gains[NumBands]; - } UpSampler[4]; + ALfloat Gains[sNumBands]; + } mUpSampler[4]; - ALsizei NumChannels; - ALboolean DualBand; + ALsizei mNumChannels; + ALboolean mDualBand; - DEF_NEWDEL(BFormatDec) -}; +public: + void reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]); -void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]); + /* Decodes the ambisonic input to the given output channels. */ + void process(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei SamplesToDo); -/* Decodes the ambisonic input to the given output channels. */ -void bformatdec_process(BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo); + /* Up-samples a first-order input to the decoder's configuration. */ + void upSample(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei InChannels, const ALsizei SamplesToDo); -/* Up-samples a first-order input to the decoder's configuration. */ -void bformatdec_upSample(BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo); + DEF_NEWDEL(BFormatDec) +}; /* Stand-alone first-order upsampler. Kept here because it shares some stuff * with bformatdec. Assumes a periphonic (4-channel) input mix! */ -struct AmbiUpsampler { - static constexpr size_t NumBands{2}; +class AmbiUpsampler { +public: + static constexpr size_t sNumBands{2}; + +private: + alignas(16) ALfloat mSamples[sNumBands][BUFFERSIZE]; - alignas(16) ALfloat Samples[NumBands][BUFFERSIZE]; + BandSplitter mXOver[4]; - BandSplitter XOver[4]; + ALfloat mGains[4][MAX_OUTPUT_CHANNELS][sNumBands]; - ALfloat Gains[4][MAX_OUTPUT_CHANNELS][NumBands]; +public: + void reset(const ALCdevice *device, const ALfloat w_scale, const ALfloat xyz_scale); + void process(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei SamplesToDo); DEF_NEWDEL(AmbiUpsampler) }; -void ambiup_reset(AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat w_scale, ALfloat xyz_scale); -void ambiup_process(AmbiUpsampler *ambiup, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo); - #endif /* BFORMATDEC_H */ diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 2758a937..f970799b 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -562,7 +562,7 @@ static void InitPanning(ALCdevice *device) w_scale = W_SCALE_2H2P; xyz_scale = XYZ_SCALE_2H2P; } - ambiup_reset(device->AmbiUp.get(), device, w_scale, xyz_scale); + device->AmbiUp->reset(device, w_scale, xyz_scale); } if(ConfigValueFloat(devname, "decoder", "nfc-ref-delay", &nfc_delay) && nfc_delay > 0.0f) @@ -724,7 +724,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz (conf->ChanMask > 0xf) ? (conf->ChanMask > 0x1ff) ? "third" : "second" : "first", (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? " periphonic" : "" ); - bformatdec_reset(device->AmbiDecoder.get(), conf, count, device->Frequency, speakermap); + device->AmbiDecoder->reset(conf, count, device->Frequency, speakermap); if(conf->ChanMask <= 0xf) { @@ -878,8 +878,8 @@ static void InitHrtfPanning(ALCdevice *device) device->FOAOut.CoeffCount = 0; device->FOAOut.NumChannels = 4; - ambiup_reset(device->AmbiUp.get(), device, AmbiOrderHFGainFOA[0] / AmbiOrderHFGain[0], - AmbiOrderHFGainFOA[1] / AmbiOrderHFGain[1]); + device->AmbiUp->reset(device, AmbiOrderHFGainFOA[0] / AmbiOrderHFGain[0], + AmbiOrderHFGainFOA[1] / AmbiOrderHFGain[1]); } else { diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index cbf00c50..422202bd 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -225,8 +225,8 @@ struct ALeffect; struct ALfilter; struct EffectState; struct Uhj2Encoder; -struct BFormatDec; -struct AmbiUpsampler; +class BFormatDec; +class AmbiUpsampler; struct bs2b; -- cgit v1.2.3 From 9e9b771e8a672f6b637a78f006da922e6cd7d026 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 8 Dec 2018 04:10:45 -0800 Subject: A bit more cleanup --- Alc/bformatdec.cpp | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 00db0393..7af3a864 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -1,9 +1,11 @@ #include "config.h" +#include #include #include #include +#include #include #include "bformatdec.h" @@ -136,13 +138,9 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, else if(conf->CoeffScale == AmbDecScale::FuMa) coeff_scale = FuMa2N3DScale; - float ratio{400.0f / (float)srate}; - for(auto &chan : mUpSampler) - { - chan.XOver.init(ratio); - chan.XOver.clear(); - std::fill(std::begin(chan.Gains), std::end(chan.Gains), 0.0f); - } + mUpSampler[0].XOver.init(400.0f / (float)srate); + std::fill(std::begin(mUpSampler[0].Gains), std::end(mUpSampler[0].Gains), 0.0f); + std::fill(std::begin(mUpSampler)+1, std::end(mUpSampler), mUpSampler[0]); const bool periphonic{(conf->ChanMask&AMBI_PERIPHONIC_MASK) != 0}; if(periphonic) @@ -211,23 +209,20 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, } else { - using namespace std::placeholders; mDualBand = AL_TRUE; - ratio = conf->XOverFreq / (ALfloat)srate; - std::for_each(std::begin(mXOver), std::end(mXOver), - std::bind(std::mem_fn(&BandSplitter::init), _1, ratio)); + mXOver[0].init(conf->XOverFreq / (float)srate); + std::fill(std::begin(mXOver)+1, std::end(mXOver), mXOver[0]); - ratio = powf(10.0f, conf->XOverRatio / 40.0f); + float ratio{std::pow(10.0f, conf->XOverRatio / 40.0f)}; for(ALsizei i{0};i < conf->NumSpeakers;i++) { ALsizei chan = chanmap[i]; - ALfloat gain; - ALsizei j, k; + ALfloat gain{}; if(!periphonic) { - for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++) + for(ALsizei j{0},k{0};j < MAX_AMBI2D_COEFFS;j++) { ALsizei l = map2DTo3D[j]; if(j == 0) gain = conf->HFOrderGain[0] * ratio; @@ -238,7 +233,7 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, mMatrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] / coeff_scale[l] * gain; } - for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++) + for(ALsizei j{0},k{0};j < MAX_AMBI2D_COEFFS;j++) { ALsizei l = map2DTo3D[j]; if(j == 0) gain = conf->LFOrderGain[0] / ratio; @@ -252,7 +247,7 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, } else { - for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++) + for(ALsizei j{0},k{0};j < MAX_AMBI_COEFFS;j++) { if(j == 0) gain = conf->HFOrderGain[0] * ratio; else if(j == 1) gain = conf->HFOrderGain[1] * ratio; @@ -262,7 +257,7 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, mMatrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * gain; } - for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++) + for(ALsizei j{0},k{0};j < MAX_AMBI_COEFFS;j++) { if(j == 0) gain = conf->LFOrderGain[0] / ratio; else if(j == 1) gain = conf->LFOrderGain[1] / ratio; @@ -360,9 +355,8 @@ void AmbiUpsampler::reset(const ALCdevice *device, const ALfloat w_scale, const { using namespace std::placeholders; - float ratio{400.0f / (float)device->Frequency}; - std::for_each(std::begin(mXOver), std::end(mXOver), - std::bind(std::mem_fn(&BandSplitter::init), _1, ratio)); + mXOver[0].init(400.0f / (float)device->Frequency); + std::fill(std::begin(mXOver)+1, std::end(mXOver), mXOver[0]); memset(mGains, 0, sizeof(mGains)); if(device->Dry.CoeffCount > 0) -- cgit v1.2.3 From 5a9a2cb1ed10f7f73bf44d95f4228ec056966f71 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 8 Dec 2018 04:10:59 -0800 Subject: Increase GAIN_MIX_MAX --- OpenAL32/Include/alu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index e7f84423..8a11b500 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -293,7 +293,7 @@ typedef void (*HrtfDirectMixerFunc)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT ALfloat (*RESTRICT Values)[2], ALsizei BufferSize); -#define GAIN_MIX_MAX (16.0f) /* +24dB */ +#define GAIN_MIX_MAX (1000.0f) /* +60dB */ #define GAIN_SILENCE_THRESHOLD (0.00001f) /* -100dB */ -- cgit v1.2.3 From fc8da0c16b34a964c637c721ff944e8e6a5f3277 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 8 Dec 2018 13:06:31 -0800 Subject: Add missing include --- Alc/effects/equalizer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index 30408433..85c0882c 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -24,6 +24,7 @@ #include #include +#include #include "alMain.h" #include "alcontext.h" -- cgit v1.2.3 From c9f5617f06503d951b3ed808cf07fb6362a7f8d1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 8 Dec 2018 14:22:20 -0800 Subject: Avoid several uses of memset --- Alc/alc.cpp | 4 ++-- Alc/backends/coreaudio.cpp | 2 +- Alc/backends/wasapi.cpp | 2 +- Alc/backends/winmm.cpp | 4 ++-- Alc/bformatdec.cpp | 6 +++--- Alc/bformatdec.h | 4 ++-- Alc/bs2b.cpp | 2 +- Alc/effects/reverb.cpp | 6 +++--- Alc/panning.cpp | 40 +++++++++++++++++----------------------- Alc/ringbuffer.cpp | 2 +- OpenAL32/Include/alu.h | 6 +++--- OpenAL32/alAuxEffectSlot.cpp | 2 +- common/almalloc.cpp | 4 +--- 13 files changed, 38 insertions(+), 46 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 810cba10..1d36dcbd 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1263,8 +1263,8 @@ static void alc_deinit(void) alc_cleanup(); - memset(&PlaybackBackend, 0, sizeof(PlaybackBackend)); - memset(&CaptureBackend, 0, sizeof(CaptureBackend)); + PlaybackBackend = BackendInfo{}; + CaptureBackend = BackendInfo{}; for(i = 0;i < BackendListSize;i++) BackendList[i].getFactory().deinit(); diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index f5574965..b2f6d2d3 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -68,7 +68,7 @@ static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice SET_VTABLE2(ALCcoreAudioPlayback, ALCbackend, self); self->FrameSize = 0; - memset(&self->Format, 0, sizeof(self->Format)); + self->Format = AudioStreamBasicDescription{}; } static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self) diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 04afe807..b928682f 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -637,7 +637,7 @@ FORCE_ALIGN int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self) ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) { - memset(out, 0, sizeof(*out)); + *out = WAVEFORMATEXTENSIBLE{}; if(in->wFormatTag == WAVE_FORMAT_EXTENSIBLE) *out = *(const WAVEFORMATEXTENSIBLE*)in; else if(in->wFormatTag == WAVE_FORMAT_PCM) diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index c88a43b6..32cabbde 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -246,7 +246,7 @@ ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *deviceName) UINT DeviceID{static_cast(std::distance(PlaybackDevices.cbegin(), iter))}; retry_open: - memset(&self->Format, 0, sizeof(WAVEFORMATEX)); + self->Format = WAVEFORMATEX{}; if(device->FmtType == DevFmtFloat) { self->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; @@ -554,7 +554,7 @@ ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName) return ALC_INVALID_ENUM; } - memset(&self->Format, 0, sizeof(WAVEFORMATEX)); + self->Format = WAVEFORMATEX{}; self->Format.wFormatTag = (device->FmtType == DevFmtFloat) ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM; self->Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 7af3a864..60e52b1b 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -170,7 +170,7 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, mUpSampler[3].Gains[LF_BAND] = 0.0f; } - memset(&mMatrix, 0, sizeof(mMatrix)); + mMatrix = MatrixU{}; if(conf->FreqBands == 1) { mDualBand = AL_FALSE; @@ -358,7 +358,7 @@ void AmbiUpsampler::reset(const ALCdevice *device, const ALfloat w_scale, const mXOver[0].init(400.0f / (float)device->Frequency); std::fill(std::begin(mXOver)+1, std::end(mXOver), mXOver[0]); - memset(mGains, 0, sizeof(mGains)); + mGains.fill({}); if(device->Dry.CoeffCount > 0) { ALfloat encgains[8][MAX_OUTPUT_CHANNELS]; @@ -411,6 +411,6 @@ void AmbiUpsampler::process(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALs mXOver[i].process(mSamples[HF_BAND], mSamples[LF_BAND], InSamples[i], SamplesToDo); for(ALsizei j{0};j < OutChannels;j++) - MixRowSamples(OutBuffer[j], mGains[i][j], mSamples, sNumBands, 0, SamplesToDo); + MixRowSamples(OutBuffer[j], mGains[i][j].data(), mSamples, sNumBands, 0, SamplesToDo); } } diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 73754be8..f2cdcdfb 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -41,7 +41,7 @@ public: private: ALuint mEnabled; /* Bitfield of enabled channels. */ - union { + union MatrixU { alignas(16) ALfloat Dual[MAX_OUTPUT_CHANNELS][sNumBands][MAX_AMBI_COEFFS]; alignas(16) ALfloat Single[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; } mMatrix; @@ -89,7 +89,7 @@ private: BandSplitter mXOver[4]; - ALfloat mGains[4][MAX_OUTPUT_CHANNELS][sNumBands]; + std::array,MAX_OUTPUT_CHANNELS>,4> mGains; public: void reset(const ALCdevice *device, const ALfloat w_scale, const ALfloat xyz_scale); diff --git a/Alc/bs2b.cpp b/Alc/bs2b.cpp index 1307e5c1..b1833b8c 100644 --- a/Alc/bs2b.cpp +++ b/Alc/bs2b.cpp @@ -127,7 +127,7 @@ int bs2b_get_srate(struct bs2b *bs2b) void bs2b_clear(struct bs2b *bs2b) { - std::memset(&bs2b->last_sample, 0, sizeof(bs2b->last_sample)); + std::fill(std::begin(bs2b->last_sample), std::end(bs2b->last_sample), bs2b::t_last_sample{}); } /* bs2b_clear */ void bs2b_cross_feed(struct bs2b *bs2b, float *RESTRICT Left, float *RESTRICT Right, int SamplesToDo) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index ce7a9946..b5e6dd94 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -821,14 +821,12 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection */ rot = GetTransformFromVector(ReflectionsPan); MATRIX_MULT(transform, rot, A2B); - memset(&State->mEarly.PanGain, 0, sizeof(State->mEarly.PanGain)); for(i = 0;i < MAX_EFFECT_CHANNELS;i++) ComputePanGains(&Device->FOAOut, transform.m[i], earlyGain, State->mEarly.PanGain[i]); rot = GetTransformFromVector(LateReverbPan); MATRIX_MULT(transform, rot, A2B); - memset(&State->mLate.PanGain, 0, sizeof(State->mLate.PanGain)); for(i = 0;i < MAX_EFFECT_CHANNELS;i++) ComputePanGains(&Device->FOAOut, transform.m[i], lateGain, State->mLate.PanGain[i]); @@ -1379,11 +1377,13 @@ void ReverbState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesI todo &= ~3; /* Convert B-Format to A-Format for processing. */ - memset(afmt, 0, sizeof(*afmt)*NUM_LINES); for(c = 0;c < NUM_LINES;c++) + { + std::fill(std::begin(afmt[c]), std::end(afmt[c]), 0.0f); MixRowSamples(afmt[c], B2A.m[c], SamplesIn, MAX_EFFECT_CHANNELS, base, todo ); + } /* Process the samples for reverb. */ for(c = 0;c < NUM_LINES;c++) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index f970799b..a8d593ce 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -26,6 +26,8 @@ #include #include +#include + #include "alMain.h" #include "alAuxEffectSlot.h" #include "alu.h" @@ -147,29 +149,25 @@ void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALf } -void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) { - ALsizei i, j; - + ALsizei i; for(i = 0;i < numchans;i++) { float gain = 0.0f; - for(j = 0;j < numcoeffs;j++) + for(ALsizei j{0};j < numcoeffs;j++) gain += chancoeffs[i][j]*coeffs[j]; gains[i] = clampf(gain, 0.0f, 1.0f) * ingain; } - for(;i < MAX_OUTPUT_CHANNELS;i++) - gains[i] = 0.0f; + std::fill(std::begin(gains)+i, std::end(gains), 0.0f); } -void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) { ALsizei i; - for(i = 0;i < numchans;i++) gains[i] = chanmap[i].Scale * coeffs[chanmap[i].Index] * ingain; - for(;i < MAX_OUTPUT_CHANNELS;i++) - gains[i] = 0.0f; + std::fill(std::begin(gains)+i, std::end(gains), 0.0f); } @@ -543,7 +541,7 @@ static void InitPanning(ALCdevice *device) /* FOA output is always ACN+N3D for higher-order ambisonic output. * The upsampler expects this and will convert it for output. */ - memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); + device->FOAOut.Ambi = AmbiConfig{}; for(i = 0;i < 4;i++) { device->FOAOut.Ambi.Map[i].Scale = 1.0f; @@ -588,7 +586,7 @@ static void InitPanning(ALCdevice *device) xyz_scale = (device->Dry.CoeffCount > 9) ? XYZ_SCALE_3H0P : (device->Dry.CoeffCount > 4) ? XYZ_SCALE_2H0P : 1.0f; - memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); + device->FOAOut.Ambi = AmbiConfig{}; for(i = 0;i < device->Dry.NumChannels;i++) { device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0] * w_scale; @@ -671,7 +669,7 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A device->Dry.CoeffCount = (conf->ChanMask > 0x1ff) ? 16 : (conf->ChanMask > 0xf) ? 9 : 4; - memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); + device->FOAOut.Ambi = AmbiConfig{}; for(i = 0;i < device->Dry.NumChannels;i++) { device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0] * w_scale; @@ -734,7 +732,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz } else { - memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); + device->FOAOut.Ambi = AmbiConfig{}; if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { count = 4; @@ -869,7 +867,7 @@ static void InitHrtfPanning(ALCdevice *device) if(device->AmbiUp) { - memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); + device->FOAOut.Ambi = AmbiConfig{}; for(i = 0;i < 4;i++) { device->FOAOut.Ambi.Map[i].Scale = 1.0f; @@ -1207,15 +1205,11 @@ no_hrtf: void aluInitEffectPanning(ALeffectslot *slot) { - ALsizei i; - - memset(slot->ChanMap, 0, sizeof(slot->ChanMap)); - slot->NumChannels = 0; - - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ALsizei i{0}; + for(auto &chanmap : slot->ChanMap) { - slot->ChanMap[i].Scale = 1.0f; - slot->ChanMap[i].Index = i; + chanmap.Scale = 1.0f; + chanmap.Index = i++; } slot->NumChannels = i; } diff --git a/Alc/ringbuffer.cpp b/Alc/ringbuffer.cpp index db44f8ae..5ee2616f 100644 --- a/Alc/ringbuffer.cpp +++ b/Alc/ringbuffer.cpp @@ -84,7 +84,7 @@ void ll_ringbuffer_reset(ll_ringbuffer_t *rb) { rb->write_ptr.store(0, std::memory_order_relaxed); rb->read_ptr.store(0, std::memory_order_relaxed); - memset(rb->buf, 0, (rb->size_mask+1)*rb->elem_size); + std::fill_n(rb->buf+0, (rb->size_mask+1)*rb->elem_size, 0); } diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 8a11b500..3cd9b557 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -457,8 +457,8 @@ inline float ScaleAzimuthFront(float azimuth, float scale) } -void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]); +void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]); /** * ComputePanGains @@ -468,7 +468,7 @@ void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, con * coeffs are a 'slice' of a transform matrix for the input channel, used to * scale and orient the sound samples. */ -inline void ComputePanGains(const MixParams *dry, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +inline void ComputePanGains(const MixParams *dry, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) { if(dry->CoeffCount > 0) ComputePanningGainsMC(dry->Ambi.Coeffs, dry->NumChannels, dry->CoeffCount, diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index ad33fe50..1e841c43 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -532,7 +532,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect if(!effect) { EffectSlot->Effect.Type = AL_EFFECT_NULL; - memset(&EffectSlot->Effect.Props, 0, sizeof(EffectSlot->Effect.Props)); + EffectSlot->Effect.Props = ALeffectProps{}; } else { diff --git a/common/almalloc.cpp b/common/almalloc.cpp index 6dcb6cfc..7e83672b 100644 --- a/common/almalloc.cpp +++ b/common/almalloc.cpp @@ -88,9 +88,7 @@ size_t al_get_page_size(void) noexcept #ifdef _WIN32 if(!psize) { - SYSTEM_INFO sysinfo; - memset(&sysinfo, 0, sizeof(sysinfo)); - + SYSTEM_INFO sysinfo{}; GetSystemInfo(&sysinfo); psize = sysinfo.dwPageSize; } -- cgit v1.2.3 From 30a3a19574713c9ca939019d7fdea35912ad168a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 8 Dec 2018 16:30:19 -0800 Subject: Rename a member variable and inline a function --- Alc/filters/splitter.cpp | 9 +++------ Alc/filters/splitter.h | 6 +++--- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Alc/filters/splitter.cpp b/Alc/filters/splitter.cpp index 85122890..18518dbb 100644 --- a/Alc/filters/splitter.cpp +++ b/Alc/filters/splitter.cpp @@ -20,7 +20,7 @@ void BandSplitter::init(float f0norm) lp_z1 = 0.0f; lp_z2 = 0.0f; - hp_z1 = 0.0f; + ap_z1 = 0.0f; } void BandSplitter::process(float *RESTRICT hpout, float *RESTRICT lpout, const float *input, int count) @@ -31,7 +31,7 @@ void BandSplitter::process(float *RESTRICT hpout, float *RESTRICT lpout, const f const float lp_coeff{this->coeff*0.5f + 0.5f}; float lp_z1{this->lp_z1}; float lp_z2{this->lp_z2}; - float ap_z1{this->hp_z1}; + float ap_z1{this->ap_z1}; auto proc_sample = [ap_coeff,lp_coeff,&lp_z1,&lp_z2,&ap_z1,&lpout](const float in) noexcept -> float { /* Low-pass sample processing. */ @@ -55,7 +55,7 @@ void BandSplitter::process(float *RESTRICT hpout, float *RESTRICT lpout, const f std::transform(input, input+count, hpout, proc_sample); this->lp_z1 = lp_z1; this->lp_z2 = lp_z2; - this->hp_z1 = ap_z1; + this->ap_z1 = ap_z1; } @@ -71,9 +71,6 @@ void SplitterAllpass::init(float f0norm) z1 = 0.0f; } -void SplitterAllpass::clear() -{ z1 = 0.0f; } - void SplitterAllpass::process(float *RESTRICT samples, int count) { ASSUME(count > 0); diff --git a/Alc/filters/splitter.h b/Alc/filters/splitter.h index db31c138..b39c3491 100644 --- a/Alc/filters/splitter.h +++ b/Alc/filters/splitter.h @@ -10,11 +10,11 @@ class BandSplitter { float coeff{0.0f}; float lp_z1{0.0f}; float lp_z2{0.0f}; - float hp_z1{0.0f}; + float ap_z1{0.0f}; public: void init(float f0norm); - void clear() noexcept { lp_z1 = lp_z2 = hp_z1 = 0.0f; } + void clear() noexcept { lp_z1 = lp_z2 = ap_z1 = 0.0f; } void process(float *RESTRICT hpout, float *RESTRICT lpout, const float *input, int count); }; @@ -27,7 +27,7 @@ class SplitterAllpass { public: void init(float f0norm); - void clear(); + void clear() noexcept { z1 = 0.0f; } void process(float *RESTRICT samples, int count); }; -- cgit v1.2.3 From a4009c47e7086611e70bafdf36666b40209f6608 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 8 Dec 2018 17:22:10 -0800 Subject: Add a cmake option to specify prebuilt native tools This should only be used with automated build systems that guarantee the native tools' binaries are up-to-date. Otherwise it's best to leave it alone so it can automatically rebuild them as needed. --- CMakeLists.txt | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 71e20eec..502e4cbd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1216,22 +1216,30 @@ ELSE() "${OpenAL_BINARY_DIR}/version.h") ENDIF() -SET(NATIVE_SRC_DIR "${OpenAL_SOURCE_DIR}/native-tools/") -SET(NATIVE_BIN_DIR "${OpenAL_BINARY_DIR}/native-tools/") -FILE(MAKE_DIRECTORY "${NATIVE_BIN_DIR}") - -SET(BIN2H_COMMAND "${NATIVE_BIN_DIR}bin2h") -SET(BSINCGEN_COMMAND "${NATIVE_BIN_DIR}bsincgen") -ADD_CUSTOM_COMMAND(OUTPUT "${BIN2H_COMMAND}" "${BSINCGEN_COMMAND}" - COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" "${NATIVE_SRC_DIR}" - COMMAND ${CMAKE_COMMAND} -E remove "${BIN2H_COMMAND}" "${BSINCGEN_COMMAND}" - COMMAND ${CMAKE_COMMAND} --build . --config "Release" - WORKING_DIRECTORY "${NATIVE_BIN_DIR}" - DEPENDS "${NATIVE_SRC_DIR}CMakeLists.txt" - IMPLICIT_DEPENDS C "${NATIVE_SRC_DIR}bin2h.c" - C "${NATIVE_SRC_DIR}bsincgen.c" - VERBATIM -) + +SET(NATIVE_SRC_DIR "${OpenAL_SOURCE_DIR}/native-tools") + +SET(ALSOFT_NATIVE_TOOLS_PATH "" CACHE STRING "Path to prebuilt native tools (leave blank to auto-build)") +IF(ALSOFT_NATIVE_TOOLS_PATH) + SET(BIN2H_COMMAND "${ALSOFT_NATIVE_TOOLS_PATH}/bin2h") + SET(BSINCGEN_COMMAND "${ALSOFT_NATIVE_TOOLS_PATH}/bsincgen") +ELSE() + SET(NATIVE_BIN_DIR "${OpenAL_BINARY_DIR}/native-tools") + FILE(MAKE_DIRECTORY "${NATIVE_BIN_DIR}") + + SET(BIN2H_COMMAND "${NATIVE_BIN_DIR}/bin2h") + SET(BSINCGEN_COMMAND "${NATIVE_BIN_DIR}/bsincgen") + ADD_CUSTOM_COMMAND(OUTPUT "${BIN2H_COMMAND}" "${BSINCGEN_COMMAND}" + COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" "${NATIVE_SRC_DIR}" + COMMAND ${CMAKE_COMMAND} -E remove "${BIN2H_COMMAND}" "${BSINCGEN_COMMAND}" + COMMAND ${CMAKE_COMMAND} --build . --config "Release" + WORKING_DIRECTORY "${NATIVE_BIN_DIR}" + DEPENDS "${NATIVE_SRC_DIR}/CMakeLists.txt" + IMPLICIT_DEPENDS C "${NATIVE_SRC_DIR}/bin2h.c" + C "${NATIVE_SRC_DIR}/bsincgen.c" + VERBATIM + ) +ENDIF() ADD_CUSTOM_TARGET(native-tools DEPENDS "${BIN2H_COMMAND}" "${BSINCGEN_COMMAND}" VERBATIM @@ -1257,7 +1265,7 @@ endif() ADD_CUSTOM_COMMAND(OUTPUT "${OpenAL_BINARY_DIR}/bsinc_inc.h" COMMAND "${BSINCGEN_COMMAND}" "${OpenAL_BINARY_DIR}/bsinc_inc.h" - DEPENDS native-tools "${NATIVE_SRC_DIR}bsincgen.c" + DEPENDS native-tools "${NATIVE_SRC_DIR}/bsincgen.c" VERBATIM ) SET(ALC_OBJS ${ALC_OBJS} "${OpenAL_BINARY_DIR}/bsinc_inc.h") -- cgit v1.2.3 From e5db9b237847db74a9228e2da925c0b6f127ab28 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 8 Dec 2018 21:58:44 -0800 Subject: Avoid static global initialization functions --- Alc/alc.cpp | 150 ++++++------------------------------------------- Alc/alconfig.cpp | 5 -- Alc/alconfig.h | 1 - Alc/alu.cpp | 37 +++++++++++- Alc/hrtf.cpp | 15 ----- Alc/hrtf.h | 2 - OpenAL32/Include/alu.h | 6 +- 7 files changed, 53 insertions(+), 163 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 1d36dcbd..b19ed410 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -800,7 +800,14 @@ constexpr ALchar alExtList[] = std::atomic LastNullDeviceError{ALC_NO_ERROR}; /* Thread-local current context */ -std::atomic ThreadCtxProc{nullptr}; +void ReleaseThreadCtx(ALCcontext *context) +{ + auto ref = DecrementRef(&context->ref); + TRACEREF("%p decreasing refcount to %u\n", context, ref); + ERR("Context %p current for thread being destroyed, possible leak!\n", context); +} + +std::atomic ThreadCtxProc{ReleaseThreadCtx}; class ThreadCtx { ALCcontext *ctx{nullptr}; @@ -865,94 +872,34 @@ std::recursive_mutex ListLock; /* Mixing thread piority level */ ALint RTPrioLevel; -FILE *LogFile; +FILE *LogFile{stderr}; #ifdef _DEBUG -enum LogLevel LogLevel = LogWarning; +enum LogLevel LogLevel{LogWarning}; #else -enum LogLevel LogLevel = LogError; +enum LogLevel LogLevel{LogError}; #endif /************************************************ * Library initialization ************************************************/ -#if defined(_WIN32) -static void alc_init(void); -static void alc_deinit(void); -static void alc_deinit_safe(void); - -#ifndef AL_LIBTYPE_STATIC -BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD reason, LPVOID lpReserved) +#if defined(_WIN32) && !defined(AL_LIBTYPE_STATIC) +BOOL APIENTRY DllMain(HINSTANCE module, DWORD reason, LPVOID /*reserved*/) { 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); - alc_init(); + (WCHAR*)module, &module); break; case DLL_PROCESS_DETACH: - if(!lpReserved) - alc_deinit(); - else - alc_deinit_safe(); break; } return TRUE; } -#elif defined(_MSC_VER) -#pragma section(".CRT$XCU",read) -static void alc_constructor(void); -static void alc_destructor(void); -__declspec(allocate(".CRT$XCU")) void (__cdecl* alc_constructor_)(void) = alc_constructor; - -static void alc_constructor(void) -{ - atexit(alc_destructor); - alc_init(); -} - -static void alc_destructor(void) -{ - alc_deinit(); -} -#elif defined(HAVE_GCC_DESTRUCTOR) -static void alc_init(void) __attribute__((constructor)); -static void alc_deinit(void) __attribute__((destructor)); -#else -#error "No static initialization available on this platform!" -#endif - -#elif defined(HAVE_GCC_DESTRUCTOR) - -static void alc_init(void) __attribute__((constructor)); -static void alc_deinit(void) __attribute__((destructor)); - -#else -#error "No global initialization available on this platform!" #endif -static void ReleaseThreadCtx(ALCcontext *ctx); -static void alc_init(void) -{ - LogFile = stderr; - - const char *str{getenv("__ALSOFT_HALF_ANGLE_CONES")}; - if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) - ConeScale *= 0.5f; - - str = getenv("__ALSOFT_REVERSE_Z"); - if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) - ZScale *= -1.0f; - - str = getenv("__ALSOFT_REVERB_IGNORES_SOUND_SPEED"); - if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) - OverrideReverbSpeedOfSound = AL_TRUE; - - ThreadCtxProc = ReleaseThreadCtx; -} - static void alc_initconfig(void) { const char *devs, *str; @@ -1027,9 +974,7 @@ static void alc_initconfig(void) capfilter = 0; else { - size_t len; const char *next = str; - do { str = next; while(isspace(str[0])) @@ -1039,7 +984,7 @@ static void alc_initconfig(void) if(!str[0] || str[0] == ',') continue; - len = (next ? ((size_t)(next-str)) : strlen(str)); + size_t len{next ? (size_t)(next-str) : strlen(str)}; while(len > 0 && isspace(str[len-1])) len--; if(len == 3 && strncasecmp(str, "sse", len) == 0) @@ -1193,9 +1138,7 @@ static void alc_initconfig(void) if(ConfigValueStr(nullptr, nullptr, "excludefx", &str)) { - size_t len; const char *next = str; - do { str = next; next = strchr(str, ','); @@ -1203,7 +1146,7 @@ static void alc_initconfig(void) if(!str[0] || next == str) continue; - len = (next ? ((size_t)(next-str)) : strlen(str)); + size_t len{next ? (size_t)(next-str) : strlen(str)}; for(n = 0;n < EFFECTLIST_SIZE;n++) { if(len == strlen(EffectList[n].name) && @@ -1221,60 +1164,6 @@ static void alc_initconfig(void) #define DO_INITCONFIG() std::call_once(alc_config_once, [](){alc_initconfig();}) -/************************************************ - * Library deinitialization - ************************************************/ -static void alc_cleanup(void) -{ - alcAllDevicesList.clear(); - alcCaptureDeviceList.clear(); - - alcDefaultAllDevicesSpecifier.clear(); - alcCaptureDefaultDeviceSpecifier.clear(); - - if(ALCdevice *dev{DeviceList.exchange(nullptr)}) - { - ALCuint num = 0; - do { - num++; - dev = dev->next.load(std::memory_order_relaxed); - } while(dev != nullptr); - ERR("%u device%s not closed\n", num, (num>1)?"s":""); - } -} - -static void alc_deinit_safe(void) -{ - alc_cleanup(); - - FreeHrtfs(); - FreeALConfig(); - - ThreadCtxProc = nullptr; - - if(LogFile != stderr) - fclose(LogFile); - LogFile = nullptr; -} - -static void alc_deinit(void) -{ - int i; - - alc_cleanup(); - - PlaybackBackend = BackendInfo{}; - CaptureBackend = BackendInfo{}; - - for(i = 0;i < BackendListSize;i++) - BackendList[i].getFactory().deinit(); - - LoopbackBackendFactory::getFactory().deinit(); - - alc_deinit_safe(); -} - - /************************************************ * Device enumeration ************************************************/ @@ -2714,13 +2603,6 @@ void ALCcontext_DecRef(ALCcontext *context) if(ref == 0) delete context; } -static void ReleaseThreadCtx(ALCcontext *context) -{ - auto ref = DecrementRef(&context->ref); - TRACEREF("%p decreasing refcount to %u\n", context, ref); - ERR("Context %p current for thread being destroyed, possible leak!\n", context); -} - /* VerifyContext * * Checks if the given context is valid, returning a new reference to it if so. diff --git a/Alc/alconfig.cpp b/Alc/alconfig.cpp index a6304ce7..4acbba5e 100644 --- a/Alc/alconfig.cpp +++ b/Alc/alconfig.cpp @@ -443,11 +443,6 @@ void ReadALConfig(void) noexcept } #endif -void FreeALConfig(void) -{ - ConfOpts.clear(); -} - const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def) { if(!keyName) diff --git a/Alc/alconfig.h b/Alc/alconfig.h index 627ef48a..0e9bcec3 100644 --- a/Alc/alconfig.h +++ b/Alc/alconfig.h @@ -9,7 +9,6 @@ extern "C" { #endif void ReadALConfig(void) NOEXCEPT; -void FreeALConfig(void); int ConfigValueExists(const char *devName, const char *blockName, const char *keyName); const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def); diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 34634983..f7640d71 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -49,14 +49,45 @@ #include "bsinc_inc.h" +namespace { + +ALfloat InitConeScale() +{ + ALfloat ret{1.0f}; + const char *str{getenv("__ALSOFT_HALF_ANGLE_CONES")}; + if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) + ret *= 0.5f; + return ret; +} + +ALfloat InitZScale() +{ + ALfloat ret{1.0f}; + const char *str{getenv("__ALSOFT_REVERSE_Z")}; + if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) + ret *= -1.0f; + return ret; +} + +ALboolean InitReverbSOS() +{ + ALboolean ret{AL_FALSE}; + const char *str{getenv("__ALSOFT_REVERB_IGNORES_SOUND_SPEED")}; + if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) + ret = AL_TRUE; + return ret; +} + +} // namespace + /* Cone scalar */ -ALfloat ConeScale = 1.0f; +const ALfloat ConeScale{InitConeScale()}; /* Localized Z scalar for mono sources */ -ALfloat ZScale = 1.0f; +const ALfloat ZScale{InitZScale()}; /* Force default speed of sound for distance-related reverb decay. */ -ALboolean OverrideReverbSpeedOfSound = AL_FALSE; +const ALboolean OverrideReverbSpeedOfSound{InitReverbSOS()}; namespace { diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 9b645b05..7ca2e3c7 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -1286,18 +1286,3 @@ void Hrtf_DecRef(struct Hrtf *hrtf) } } } - - -void FreeHrtfs(void) -{ - struct HrtfEntry *Hrtf{LoadedHrtfs}; - LoadedHrtfs = nullptr; - - while(Hrtf != nullptr) - { - struct HrtfEntry *next{Hrtf->next}; - al_free(Hrtf->handle); - al_free(Hrtf); - Hrtf = next; - } -} diff --git a/Alc/hrtf.h b/Alc/hrtf.h index cbec2fc7..b814c282 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -68,8 +68,6 @@ struct AngularPoint { }; -void FreeHrtfs(void); - al::vector EnumerateHrtf(const char *devname); struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry); void Hrtf_IncRef(struct Hrtf *hrtf); diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 3cd9b557..666cd8c0 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -487,8 +487,8 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) DECL_FORMAT(pr extern MixerFunc MixSamples; extern RowMixerFunc MixRowSamples; -extern ALfloat ConeScale; -extern ALfloat ZScale; -extern ALboolean OverrideReverbSpeedOfSound; +extern const ALfloat ConeScale; +extern const ALfloat ZScale; +extern const ALboolean OverrideReverbSpeedOfSound; #endif -- cgit v1.2.3 From 621f0dfe73cb76d670f205955b79d1554f1bbcf6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 9 Dec 2018 03:04:18 -0800 Subject: Use a vector for LoadedHrtfs --- Alc/hrtf.cpp | 132 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 65 insertions(+), 67 deletions(-) diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 7ca2e3c7..de964776 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -44,13 +44,16 @@ struct HrtfEntry { - struct HrtfEntry *next; - struct Hrtf *handle; + Hrtf *handle; char filename[]; + + DEF_PLACE_NEWDEL() }; namespace { +using HrtfEntryPtr = std::unique_ptr; + /* Current data set limits defined by the makehrtf utility. */ #define MIN_IR_SIZE (8) #define MAX_IR_SIZE (512) @@ -79,7 +82,7 @@ constexpr ALchar magicMarker02[8]{'M','i','n','P','H','R','0','2'}; constexpr ALfloat PassthruCoeff{0.707106781187f/*sqrt(0.5)*/}; std::mutex LoadedHrtfLock; -HrtfEntry *LoadedHrtfs{nullptr}; +al::vector LoadedHrtfs; class databuf final : public std::streambuf { @@ -955,38 +958,36 @@ bool checkName(al::vector &list, const std::string &name) void AddFileEntry(al::vector &list, const std::string &filename) { /* Check if this file has already been loaded globally. */ - HrtfEntry *loaded_entry{LoadedHrtfs}; - while(loaded_entry) + auto loaded_entry = LoadedHrtfs.begin(); + for(;loaded_entry != LoadedHrtfs.end();++loaded_entry) { - if(filename == loaded_entry->filename) - { - /* Check if this entry has already been added to the list. */ - auto iter = std::find_if(list.cbegin(), list.cend(), - [loaded_entry](const EnumeratedHrtf &entry) -> bool - { return loaded_entry == entry.hrtf; } - ); - if(iter != list.cend()) - { - TRACE("Skipping duplicate file entry %s\n", filename.c_str()); - return; - } + if(filename != (*loaded_entry)->filename) + continue; - break; + /* Check if this entry has already been added to the list. */ + auto iter = std::find_if(list.cbegin(), list.cend(), + [loaded_entry](const EnumeratedHrtf &entry) -> bool + { return loaded_entry->get() == entry.hrtf; } + ); + if(iter != list.cend()) + { + TRACE("Skipping duplicate file entry %s\n", filename.c_str()); + return; } - loaded_entry = loaded_entry->next; + + break; } - if(!loaded_entry) + if(loaded_entry == LoadedHrtfs.end()) { TRACE("Got new file \"%s\"\n", filename.c_str()); - loaded_entry = static_cast(al_calloc(DEF_ALIGN, - FAM_SIZE(struct HrtfEntry, filename, filename.length()+1) - )); - loaded_entry->next = LoadedHrtfs; - loaded_entry->handle = nullptr; - strcpy(loaded_entry->filename, filename.c_str()); - LoadedHrtfs = loaded_entry; + LoadedHrtfs.emplace_back(HrtfEntryPtr{new + (al_calloc(DEF_ALIGN, FAM_SIZE(HrtfEntry, filename, filename.length()+1))) + HrtfEntry{}}); + loaded_entry = LoadedHrtfs.end()-1; + (*loaded_entry)->handle = nullptr; + strcpy((*loaded_entry)->filename, filename.c_str()); } /* TODO: Get a human-readable name from the HRTF data (possibly coming in a @@ -1007,7 +1008,7 @@ void AddFileEntry(al::vector &list, const std::string &filename) newname += " #"; newname += std::to_string(++count); } - list.emplace_back(EnumeratedHrtf{newname, loaded_entry}); + list.emplace_back(EnumeratedHrtf{newname, loaded_entry->get()}); const EnumeratedHrtf &entry = list.back(); TRACE("Adding file entry \"%s\"\n", entry.name.c_str()); @@ -1018,41 +1019,39 @@ void AddFileEntry(al::vector &list, const std::string &filename) */ void AddBuiltInEntry(al::vector &list, const std::string &filename, ALuint residx) { - HrtfEntry *loaded_entry{LoadedHrtfs}; - while(loaded_entry) + auto loaded_entry = LoadedHrtfs.begin(); + for(;loaded_entry != LoadedHrtfs.end();++loaded_entry) { - if(filename == loaded_entry->filename) - { - /* Check if this entry has already been added to the list. */ - auto iter = std::find_if(list.cbegin(), list.cend(), - [loaded_entry](const EnumeratedHrtf &entry) -> bool - { return loaded_entry == entry.hrtf; } - ); - if(iter != list.cend()) - { - TRACE("Skipping duplicate file entry %s\n", filename.c_str()); - return; - } + if(filename != (*loaded_entry)->filename) + continue; - break; + /* Check if this entry has already been added to the list. */ + auto iter = std::find_if(list.cbegin(), list.cend(), + [loaded_entry](const EnumeratedHrtf &entry) -> bool + { return loaded_entry->get() == entry.hrtf; } + ); + if(iter != list.cend()) + { + TRACE("Skipping duplicate file entry %s\n", filename.c_str()); + return; } - loaded_entry = loaded_entry->next; + + break; } - if(!loaded_entry) + if(loaded_entry == LoadedHrtfs.end()) { - size_t namelen = filename.length()+32; + const size_t namelen{filename.length()+32}; TRACE("Got new file \"%s\"\n", filename.c_str()); - loaded_entry = static_cast(al_calloc(DEF_ALIGN, - FAM_SIZE(struct HrtfEntry, filename, namelen) - )); - loaded_entry->next = LoadedHrtfs; - loaded_entry->handle = nullptr; - snprintf(loaded_entry->filename, namelen, "!%u_%s", + LoadedHrtfs.emplace_back(HrtfEntryPtr{new + (al_calloc(DEF_ALIGN, FAM_SIZE(HrtfEntry, filename, namelen))) + HrtfEntry{}}); + loaded_entry = LoadedHrtfs.end()-1; + (*loaded_entry)->handle = nullptr; + snprintf((*loaded_entry)->filename, namelen, "!%u_%s", residx, filename.c_str()); - LoadedHrtfs = loaded_entry; } /* TODO: Get a human-readable name from the HRTF data (possibly coming in a @@ -1066,7 +1065,7 @@ void AddBuiltInEntry(al::vector &list, const std::string &filena newname += " #"; newname += std::to_string(++count); } - list.emplace_back(EnumeratedHrtf{newname, loaded_entry}); + list.emplace_back(EnumeratedHrtf{newname, loaded_entry->get()}); const EnumeratedHrtf &entry = list.back(); TRACE("Adding built-in entry \"%s\"\n", entry.name.c_str()); @@ -1269,20 +1268,19 @@ void Hrtf_DecRef(struct Hrtf *hrtf) { std::lock_guard _{LoadedHrtfLock}; - struct HrtfEntry *Hrtf{LoadedHrtfs}; - while(Hrtf != nullptr) + /* Need to double-check that it's still unused, as another device + * could've reacquired this HRTF after its reference went to 0 and + * before the lock was taken. + */ + auto iter = std::find_if(LoadedHrtfs.begin(), LoadedHrtfs.end(), + [hrtf](const HrtfEntryPtr &entry) noexcept -> bool + { return hrtf == entry->handle; } + ); + if(iter != LoadedHrtfs.end() && ReadRef(&hrtf->ref) == 0) { - /* Need to double-check that it's still unused, as another device - * could've reacquired this HRTF after its reference went to 0 and - * before the lock was taken. - */ - if(hrtf == Hrtf->handle && ReadRef(&hrtf->ref) == 0) - { - al_free(Hrtf->handle); - Hrtf->handle = nullptr; - TRACE("Unloaded unused HRTF %s\n", Hrtf->filename); - } - Hrtf = Hrtf->next; + al_free((*iter)->handle); + (*iter)->handle = nullptr; + TRACE("Unloaded unused HRTF %s\n", (*iter)->filename); } } } -- cgit v1.2.3 From d7d98708391e4701f3e27794982af55436ba6d41 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 9 Dec 2018 13:36:13 -0800 Subject: Add default construction to HrtfEntry --- Alc/hrtf.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index de964776..230574a9 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -44,7 +44,7 @@ struct HrtfEntry { - Hrtf *handle; + Hrtf *handle{nullptr}; char filename[]; DEF_PLACE_NEWDEL() @@ -986,7 +986,6 @@ void AddFileEntry(al::vector &list, const std::string &filename) (al_calloc(DEF_ALIGN, FAM_SIZE(HrtfEntry, filename, filename.length()+1))) HrtfEntry{}}); loaded_entry = LoadedHrtfs.end()-1; - (*loaded_entry)->handle = nullptr; strcpy((*loaded_entry)->filename, filename.c_str()); } @@ -1049,7 +1048,6 @@ void AddBuiltInEntry(al::vector &list, const std::string &filena (al_calloc(DEF_ALIGN, FAM_SIZE(HrtfEntry, filename, namelen))) HrtfEntry{}}); loaded_entry = LoadedHrtfs.end()-1; - (*loaded_entry)->handle = nullptr; snprintf((*loaded_entry)->filename, namelen, "!%u_%s", residx, filename.c_str()); } -- cgit v1.2.3 From 6c8f45b5f6eb2c94427078a4fb527f02d44b9f65 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 9 Dec 2018 15:07:44 -0800 Subject: Rename a couple global variables Avoid clashing with an enum name --- Alc/alc.cpp | 10 +++++----- Alc/helpers.cpp | 10 +++++----- Alc/logging.h | 14 +++++++------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index b19ed410..424a0eaa 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -872,11 +872,11 @@ std::recursive_mutex ListLock; /* Mixing thread piority level */ ALint RTPrioLevel; -FILE *LogFile{stderr}; +FILE *gLogFile{stderr}; #ifdef _DEBUG -enum LogLevel LogLevel{LogWarning}; +LogLevel gLogLevel{LogWarning}; #else -enum LogLevel LogLevel{LogError}; +LogLevel gLogLevel{LogError}; #endif /************************************************ @@ -912,7 +912,7 @@ static void alc_initconfig(void) { long lvl = strtol(str, nullptr, 0); if(lvl >= NoLog && lvl <= LogRef) - LogLevel = static_cast(lvl); + gLogLevel = static_cast(lvl); } str = getenv("ALSOFT_LOGFILE"); @@ -924,7 +924,7 @@ static void alc_initconfig(void) #else FILE *logfile = fopen(str, "wt"); #endif - if(logfile) LogFile = logfile; + if(logfile) gLogFile = logfile; else ERR("Failed to open log file '%s'\n", str); } diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index 8a2a851d..a46e857f 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -370,8 +370,8 @@ void al_print(const char *type, const char *func, const char *fmt, ...) str[sizeof(str)-1] = 0; std::wstring wstr{utf8_to_wstr(str)}; - fprintf(LogFile, "AL lib: %s %s: %ls", type, func, wstr.c_str()); - fflush(LogFile); + fprintf(gLogFile, "AL lib: %s %s: %ls", type, func, wstr.c_str()); + fflush(gLogFile); } @@ -589,11 +589,11 @@ void al_print(const char *type, const char *func, const char *fmt, ...) va_list ap; va_start(ap, fmt); - fprintf(LogFile, "AL lib: %s %s: ", type, func); - vfprintf(LogFile, fmt, ap); + fprintf(gLogFile, "AL lib: %s %s: ", type, func); + vfprintf(gLogFile, fmt, ap); va_end(ap); - fflush(LogFile); + fflush(gLogFile); } diff --git a/Alc/logging.h b/Alc/logging.h index 2d9f4063..f493d973 100644 --- a/Alc/logging.h +++ b/Alc/logging.h @@ -14,10 +14,10 @@ extern "C" { #endif -extern FILE *LogFile; +extern FILE *gLogFile; #if defined(__GNUC__) && !defined(_WIN32) -#define AL_PRINT(T, MSG, ...) fprintf(LogFile, "AL lib: %s %s: " MSG, T, __FUNCTION__ , ## __VA_ARGS__) +#define AL_PRINT(T, MSG, ...) fprintf(gLogFile, "AL lib: %s %s: " MSG, T, __FUNCTION__ , ## __VA_ARGS__) #else void al_print(const char *type, const char *func, const char *fmt, ...) DECL_FORMAT(printf, 3,4); #define AL_PRINT(T, ...) al_print((T), __FUNCTION__, __VA_ARGS__) @@ -37,27 +37,27 @@ enum LogLevel { LogTrace, LogRef }; -extern enum LogLevel LogLevel; +extern LogLevel gLogLevel; #define TRACEREF(...) do { \ - if(LogLevel >= LogRef) \ + if(gLogLevel >= LogRef) \ AL_PRINT("(--)", __VA_ARGS__); \ } while(0) #define TRACE(...) do { \ - if(LogLevel >= LogTrace) \ + if(gLogLevel >= LogTrace) \ AL_PRINT("(II)", __VA_ARGS__); \ LOG_ANDROID(ANDROID_LOG_DEBUG, __VA_ARGS__); \ } while(0) #define WARN(...) do { \ - if(LogLevel >= LogWarning) \ + if(gLogLevel >= LogWarning) \ AL_PRINT("(WW)", __VA_ARGS__); \ LOG_ANDROID(ANDROID_LOG_WARN, __VA_ARGS__); \ } while(0) #define ERR(...) do { \ - if(LogLevel >= LogError) \ + if(gLogLevel >= LogError) \ AL_PRINT("(EE)", __VA_ARGS__); \ LOG_ANDROID(ANDROID_LOG_ERROR, __VA_ARGS__); \ } while(0) -- cgit v1.2.3 From efb8e076c73fb77e342fe9f2e03b214a7f6c787d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 9 Dec 2018 15:21:24 -0800 Subject: Pass a reference to an array for a function parameter --- Alc/panning.cpp | 2 +- OpenAL32/Include/alu.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index a8d593ce..beb390e7 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -67,7 +67,7 @@ constexpr ALsizei ACN2ACN[MAX_AMBI_COEFFS] = { } // namespace void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread, - ALfloat coeffs[MAX_AMBI_COEFFS]) + ALfloat (&coeffs)[MAX_AMBI_COEFFS]) { /* Zeroth-order */ coeffs[0] = 1.0f; /* ACN 0 = 1 */ diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 666cd8c0..e011675c 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -411,7 +411,7 @@ void aluSelectPostProcess(ALCdevice *device); * second, and third parameters respectively -- simply negate X and Z. */ void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread, - ALfloat coeffs[MAX_AMBI_COEFFS]); + ALfloat (&coeffs)[MAX_AMBI_COEFFS]); /** * CalcDirectionCoeffs @@ -420,7 +420,7 @@ void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALf * vector must be normalized (unit length), and the spread is the angular width * of the sound (0...tau). */ -inline void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]) +inline void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat (&coeffs)[MAX_AMBI_COEFFS]) { /* Convert from OpenAL coords to Ambisonics. */ CalcAmbiCoeffs(-dir[0], dir[1], -dir[2], spread, coeffs); @@ -433,7 +433,7 @@ inline void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat co * azimuth and elevation parameters are in radians, going right and up * respectively. */ -inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]) +inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat (&coeffs)[MAX_AMBI_COEFFS]) { ALfloat x = -sinf(azimuth) * cosf(elevation); ALfloat y = sinf(elevation); -- cgit v1.2.3 From b1beb7dfdcc2324cefbcc28264f429e65f640285 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 9 Dec 2018 17:24:00 -0800 Subject: Avoid some more explicit loops --- Alc/panning.cpp | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index beb390e7..efacf81a 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include "alMain.h" @@ -151,23 +152,30 @@ void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALf void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) { - ALsizei i; - for(i = 0;i < numchans;i++) - { - float gain = 0.0f; - for(ALsizei j{0};j < numcoeffs;j++) - gain += chancoeffs[i][j]*coeffs[j]; - gains[i] = clampf(gain, 0.0f, 1.0f) * ingain; - } - std::fill(std::begin(gains)+i, std::end(gains), 0.0f); + ASSUME(numchans > 0); + auto iter = std::transform(chancoeffs, chancoeffs+numchans, std::begin(gains), + [numcoeffs,coeffs,ingain](const ChannelConfig &chancoeffs) -> ALfloat + { + ASSUME(numcoeffs > 0); + float gain{std::inner_product(std::begin(chancoeffs), std::begin(chancoeffs)+numcoeffs, + coeffs, float{0.0f})}; + return clampf(gain, 0.0f, 1.0f) * ingain; + } + ); + std::fill(iter, std::end(gains), 0.0f); } void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) { - ALsizei i; - for(i = 0;i < numchans;i++) - gains[i] = chanmap[i].Scale * coeffs[chanmap[i].Index] * ingain; - std::fill(std::begin(gains)+i, std::end(gains), 0.0f); + ASSUME(numchans > 0); + auto iter = std::transform(chanmap, chanmap+numchans, std::begin(gains), + [coeffs,ingain](const BFChannelConfig &chanmap) noexcept -> ALfloat + { + ASSUME(chanmap.Index >= 0); + return chanmap.Scale * coeffs[chanmap.Index] * ingain; + } + ); + std::fill(iter, std::end(gains), 0.0f); } -- cgit v1.2.3 From 0a805727dbdca65a4515bd5bbcbc25468784271e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 9 Dec 2018 18:16:00 -0800 Subject: Use std::accumulate to find the max channel count --- Alc/panning.cpp | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index efacf81a..77d5630e 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -234,23 +234,20 @@ static void SetChannelMap(const Channel (&devchans)[MAX_OUTPUT_CHANNELS], ChannelConfig *ambicoeffs, const ChannelMap *chanmap, ALsizei count, ALsizei *outcount) { - ALsizei maxchans{0}; - std::for_each(chanmap, chanmap+count, - [&maxchans,&devchans,ambicoeffs](const ChannelMap &channel) -> void + auto copy_coeffs = [&devchans,ambicoeffs](ALsizei maxchans, const ChannelMap &channel) -> ALsizei + { + const ALint idx{GetChannelIndex(devchans, channel.ChanName)}; + if(idx < 0) { - ALint idx = GetChannelIndex(devchans, channel.ChanName); - if(idx < 0) - { - ERR("Failed to find %s channel in device\n", - GetLabelFromChannel(channel.ChanName)); - return; - } - - maxchans = maxi(maxchans, idx+1); - std::copy_n(channel.Config, MAX_AMBI_COEFFS, ambicoeffs[idx]); + ERR("Failed to find %s channel in device\n", GetLabelFromChannel(channel.ChanName)); + return maxchans; } - ); - *outcount = mini(maxchans, MAX_OUTPUT_CHANNELS); + + std::copy(std::begin(channel.Config), std::end(channel.Config), ambicoeffs[idx]); + return maxi(maxchans, idx+1); + }; + ALsizei maxcount{std::accumulate(chanmap, chanmap+count, ALsizei{0}, copy_coeffs)}; + *outcount = mini(maxcount, MAX_OUTPUT_CHANNELS); } static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei speakermap[MAX_OUTPUT_CHANNELS]) -- cgit v1.2.3 From 0d56c59f14459b17028ebda710c3735d6ecab507 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 9 Dec 2018 22:34:21 -0800 Subject: Avoid some more explicit loops --- Alc/ambdec.h | 2 +- Alc/panning.cpp | 95 +++++++++++++++++++++++++-------------------------------- 2 files changed, 42 insertions(+), 55 deletions(-) diff --git a/Alc/ambdec.h b/Alc/ambdec.h index 33e74d36..99caf9a2 100644 --- a/Alc/ambdec.h +++ b/Alc/ambdec.h @@ -24,7 +24,7 @@ struct AmbDecConf { ALfloat XOverFreq; ALfloat XOverRatio; - struct { + struct SpeakerConf { std::string Name; ALfloat Distance; ALfloat Azimuth; diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 77d5630e..4d1cd2c0 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -693,31 +693,25 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz { static constexpr ALsizei chans_per_order2d[MAX_AMBI_ORDER+1] = { 1, 2, 2, 2 }; static constexpr ALsizei chans_per_order3d[MAX_AMBI_ORDER+1] = { 1, 3, 5, 7 }; - ALfloat avg_dist; ALsizei count; - ALsizei i; if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { + static constexpr int map[MAX_AMBI_COEFFS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; count = (conf->ChanMask > 0x1ff) ? 16 : (conf->ChanMask > 0xf) ? 9 : 4; - for(i = 0;i < count;i++) - { - device->Dry.Ambi.Map[i].Scale = 1.0f; - device->Dry.Ambi.Map[i].Index = i; - } + std::transform(std::begin(map), std::begin(map)+count, std::begin(device->Dry.Ambi.Map), + [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } + ); } else { - static const int map[MAX_AMBI2D_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; - + static constexpr int map[MAX_AMBI2D_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; count = (conf->ChanMask > 0x1ff) ? 7 : (conf->ChanMask > 0xf) ? 5 : 3; - for(i = 0;i < count;i++) - { - device->Dry.Ambi.Map[i].Scale = 1.0f; - device->Dry.Ambi.Map[i].Index = map[i]; - } + std::transform(std::begin(map), std::begin(map)+count, std::begin(device->Dry.Ambi.Map), + [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } + ); } device->Dry.CoeffCount = 0; device->Dry.NumChannels = count; @@ -740,22 +734,19 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz device->FOAOut.Ambi = AmbiConfig{}; if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { + static constexpr int map[4] = { 0, 1, 2, 3 }; count = 4; - for(i = 0;i < count;i++) - { - device->FOAOut.Ambi.Map[i].Scale = 1.0f; - device->FOAOut.Ambi.Map[i].Index = i; - } + std::transform(std::begin(map), std::begin(map)+count, std::begin(device->FOAOut.Ambi.Map), + [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } + ); } else { - static const int map[3] = { 0, 1, 3 }; + static constexpr int map[3] = { 0, 1, 3 }; count = 3; - for(i = 0;i < count;i++) - { - device->FOAOut.Ambi.Map[i].Scale = 1.0f; - device->FOAOut.Ambi.Map[i].Index = map[i]; - } + std::transform(std::begin(map), std::begin(map)+count, std::begin(device->FOAOut.Ambi.Map), + [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } + ); } device->FOAOut.CoeffCount = 0; device->FOAOut.NumChannels = count; @@ -763,10 +754,14 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); - avg_dist = 0.0f; - for(i = 0;i < conf->NumSpeakers;i++) - avg_dist += conf->Speakers[i].Distance; - avg_dist /= (ALfloat)conf->NumSpeakers; + using namespace std::placeholders; + auto accum_spkr_dist = std::bind( + std::plus{}, _1, std::bind(std::mem_fn(&AmbDecConf::SpeakerConf::Distance), _2) + ); + const ALfloat avg_dist{ + std::accumulate(std::begin(conf->Speakers), std::begin(conf->Speakers)+conf->NumSpeakers, + float{0.0f}, accum_spkr_dist) / (ALfloat)conf->NumSpeakers + }; InitNearFieldCtrl(device, avg_dist, (conf->ChanMask > 0x1ff) ? 3 : (conf->ChanMask > 0xf) ? 2 : 1, (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? chans_per_order3d : chans_per_order2d @@ -778,7 +773,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz static void InitHrtfPanning(ALCdevice *device) { /* NOTE: azimuth goes clockwise. */ - static const struct AngularPoint AmbiPoints[] = { + static constexpr struct AngularPoint AmbiPoints[] = { { DEG2RAD( 90.0f), DEG2RAD( 0.0f) }, { DEG2RAD( 35.2643897f), DEG2RAD( 45.0f) }, { DEG2RAD( 35.2643897f), DEG2RAD( 135.0f) }, @@ -798,7 +793,7 @@ static void InitHrtfPanning(ALCdevice *device) { DEG2RAD(-35.2643897f), DEG2RAD( -45.0f) }, { DEG2RAD(-90.0f), DEG2RAD( 0.0f) }, }; - static const ALfloat AmbiMatrixFOA[][MAX_AMBI_COEFFS] = { + static constexpr ALfloat AmbiMatrixFOA[][MAX_AMBI_COEFFS] = { { 5.55555556e-02f, 0.00000000e+00f, 1.23717915e-01f, 0.00000000e+00f }, { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f }, { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f }, @@ -837,17 +832,16 @@ static void InitHrtfPanning(ALCdevice *device) { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f }, { 5.55555556e-02f, 0.00000000e+00f, -1.23717915e-01f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, }; - static const ALfloat AmbiOrderHFGainFOA[MAX_AMBI_ORDER+1] = { + static constexpr ALfloat AmbiOrderHFGainFOA[MAX_AMBI_ORDER+1] = { 3.00000000e+00f, 1.73205081e+00f }, AmbiOrderHFGainHOA[MAX_AMBI_ORDER+1] = { 2.40192231e+00f, 1.86052102e+00f, 9.60768923e-01f }; - static const ALsizei IndexMap[6] = { 0, 1, 2, 3, 4, 8 }; - static const ALsizei ChansPerOrder[MAX_AMBI_ORDER+1] = { 1, 3, 2, 0 }; + static constexpr ALsizei IndexMap[6] = { 0, 1, 2, 3, 4, 8 }; + static constexpr ALsizei ChansPerOrder[MAX_AMBI_ORDER+1] = { 1, 3, 2, 0 }; const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_COEFFS] = AmbiMatrixFOA; const ALfloat *RESTRICT AmbiOrderHFGain = AmbiOrderHFGainFOA; - ALsizei count = 4; - ALsizei i; + ALsizei count{4}; static_assert(COUNTOF(AmbiPoints) == COUNTOF(AmbiMatrixFOA), "FOA Ambisonic HRTF mismatch"); static_assert(COUNTOF(AmbiPoints) == COUNTOF(AmbiMatrixHOA), "HOA Ambisonic HRTF mismatch"); @@ -862,22 +856,18 @@ static void InitHrtfPanning(ALCdevice *device) device->mHrtfState.reset( new (al_calloc(16, FAM_SIZE(DirectHrtfState, Chan, count))) DirectHrtfState{}); - for(i = 0;i < count;i++) - { - device->Dry.Ambi.Map[i].Scale = 1.0f; - device->Dry.Ambi.Map[i].Index = IndexMap[i]; - } + std::transform(std::begin(IndexMap), std::begin(IndexMap)+count, std::begin(device->Dry.Ambi.Map), + [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } + ); device->Dry.CoeffCount = 0; device->Dry.NumChannels = count; if(device->AmbiUp) { device->FOAOut.Ambi = AmbiConfig{}; - for(i = 0;i < 4;i++) - { - device->FOAOut.Ambi.Map[i].Scale = 1.0f; - device->FOAOut.Ambi.Map[i].Index = i; - } + std::transform(std::begin(IndexMap), std::begin(IndexMap)+4, std::begin(device->FOAOut.Ambi.Map), + [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } + ); device->FOAOut.CoeffCount = 0; device->FOAOut.NumChannels = 4; @@ -904,15 +894,12 @@ static void InitHrtfPanning(ALCdevice *device) static void InitUhjPanning(ALCdevice *device) { - ALsizei count = 3; - ALsizei i; + static constexpr ALsizei count{3}; - for(i = 0;i < count;i++) - { - ALsizei acn = FuMa2ACN[i]; - device->Dry.Ambi.Map[i].Scale = 1.0f/FuMa2N3DScale[acn]; - device->Dry.Ambi.Map[i].Index = acn; - } + std::transform(std::begin(FuMa2ACN), std::begin(FuMa2ACN)+count, std::begin(device->Dry.Ambi.Map), + [](const ALsizei &acn) noexcept -> BFChannelConfig + { return BFChannelConfig{1.0f/FuMa2N3DScale[acn], acn}; } + ); device->Dry.CoeffCount = 0; device->Dry.NumChannels = count; -- cgit v1.2.3 From 9bb7ed01294a1b87be503d1388d59406abb7eea0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 10 Dec 2018 02:08:54 -0800 Subject: Put static methods into an anonymous namespace --- Alc/panning.cpp | 259 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 128 insertions(+), 131 deletions(-) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 4d1cd2c0..507ea5f7 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -65,121 +65,7 @@ constexpr ALsizei ACN2ACN[MAX_AMBI_COEFFS] = { 8, 9, 10, 11, 12, 13, 14, 15 }; -} // namespace - -void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread, - ALfloat (&coeffs)[MAX_AMBI_COEFFS]) -{ - /* Zeroth-order */ - coeffs[0] = 1.0f; /* ACN 0 = 1 */ - /* First-order */ - coeffs[1] = SQRTF_3 * y; /* ACN 1 = sqrt(3) * Y */ - coeffs[2] = SQRTF_3 * z; /* ACN 2 = sqrt(3) * Z */ - coeffs[3] = SQRTF_3 * x; /* ACN 3 = sqrt(3) * X */ - /* Second-order */ - coeffs[4] = 3.872983346f * x * y; /* ACN 4 = sqrt(15) * X * Y */ - coeffs[5] = 3.872983346f * y * z; /* ACN 5 = sqrt(15) * Y * Z */ - coeffs[6] = 1.118033989f * (3.0f*z*z - 1.0f); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */ - coeffs[7] = 3.872983346f * x * z; /* ACN 7 = sqrt(15) * X * Z */ - coeffs[8] = 1.936491673f * (x*x - y*y); /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */ - /* Third-order */ - coeffs[9] = 2.091650066f * y * (3.0f*x*x - y*y); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */ - coeffs[10] = 10.246950766f * z * x * y; /* ACN 10 = sqrt(105) * Z * X * Y */ - coeffs[11] = 1.620185175f * y * (5.0f*z*z - 1.0f); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */ - coeffs[12] = 1.322875656f * z * (5.0f*z*z - 3.0f); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */ - coeffs[13] = 1.620185175f * x * (5.0f*z*z - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */ - coeffs[14] = 5.123475383f * z * (x*x - y*y); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */ - coeffs[15] = 2.091650066f * x * (x*x - 3.0f*y*y); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */ - - if(spread > 0.0f) - { - /* Implement the spread by using a spherical source that subtends the - * angle spread. See: - * http://www.ppsloan.org/publications/StupidSH36.pdf - Appendix A3 - * - * When adjusted for N3D normalization instead of SN3D, these - * calculations are: - * - * ZH0 = -sqrt(pi) * (-1+ca); - * ZH1 = 0.5*sqrt(pi) * sa*sa; - * ZH2 = -0.5*sqrt(pi) * ca*(-1+ca)*(ca+1); - * ZH3 = -0.125*sqrt(pi) * (-1+ca)*(ca+1)*(5*ca*ca - 1); - * ZH4 = -0.125*sqrt(pi) * ca*(-1+ca)*(ca+1)*(7*ca*ca - 3); - * ZH5 = -0.0625*sqrt(pi) * (-1+ca)*(ca+1)*(21*ca*ca*ca*ca - 14*ca*ca + 1); - * - * The gain of the source is compensated for size, so that the - * loundness doesn't depend on the spread. Thus: - * - * ZH0 = 1.0f; - * ZH1 = 0.5f * (ca+1.0f); - * ZH2 = 0.5f * (ca+1.0f)*ca; - * ZH3 = 0.125f * (ca+1.0f)*(5.0f*ca*ca - 1.0f); - * ZH4 = 0.125f * (ca+1.0f)*(7.0f*ca*ca - 3.0f)*ca; - * ZH5 = 0.0625f * (ca+1.0f)*(21.0f*ca*ca*ca*ca - 14.0f*ca*ca + 1.0f); - */ - ALfloat ca = cosf(spread * 0.5f); - /* Increase the source volume by up to +3dB for a full spread. */ - ALfloat scale = sqrtf(1.0f + spread/F_TAU); - - ALfloat ZH0_norm = scale; - ALfloat ZH1_norm = 0.5f * (ca+1.f) * scale; - ALfloat ZH2_norm = 0.5f * (ca+1.f)*ca * scale; - ALfloat ZH3_norm = 0.125f * (ca+1.f)*(5.f*ca*ca-1.f) * scale; - - /* Zeroth-order */ - coeffs[0] *= ZH0_norm; - /* First-order */ - coeffs[1] *= ZH1_norm; - coeffs[2] *= ZH1_norm; - coeffs[3] *= ZH1_norm; - /* Second-order */ - coeffs[4] *= ZH2_norm; - coeffs[5] *= ZH2_norm; - coeffs[6] *= ZH2_norm; - coeffs[7] *= ZH2_norm; - coeffs[8] *= ZH2_norm; - /* Third-order */ - coeffs[9] *= ZH3_norm; - coeffs[10] *= ZH3_norm; - coeffs[11] *= ZH3_norm; - coeffs[12] *= ZH3_norm; - coeffs[13] *= ZH3_norm; - coeffs[14] *= ZH3_norm; - coeffs[15] *= ZH3_norm; - } -} - - -void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) -{ - ASSUME(numchans > 0); - auto iter = std::transform(chancoeffs, chancoeffs+numchans, std::begin(gains), - [numcoeffs,coeffs,ingain](const ChannelConfig &chancoeffs) -> ALfloat - { - ASSUME(numcoeffs > 0); - float gain{std::inner_product(std::begin(chancoeffs), std::begin(chancoeffs)+numcoeffs, - coeffs, float{0.0f})}; - return clampf(gain, 0.0f, 1.0f) * ingain; - } - ); - std::fill(iter, std::end(gains), 0.0f); -} - -void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) -{ - ASSUME(numchans > 0); - auto iter = std::transform(chanmap, chanmap+numchans, std::begin(gains), - [coeffs,ingain](const BFChannelConfig &chanmap) noexcept -> ALfloat - { - ASSUME(chanmap.Index >= 0); - return chanmap.Scale * coeffs[chanmap.Index] * ingain; - } - ); - std::fill(iter, std::end(gains), 0.0f); -} - - -static inline const char *GetLabelFromChannel(enum Channel channel) +inline const char *GetLabelFromChannel(enum Channel channel) { switch(channel) { @@ -230,9 +116,8 @@ struct ChannelMap { ChannelConfig Config; }; -static void SetChannelMap(const Channel (&devchans)[MAX_OUTPUT_CHANNELS], - ChannelConfig *ambicoeffs, const ChannelMap *chanmap, - ALsizei count, ALsizei *outcount) +void SetChannelMap(const Channel (&devchans)[MAX_OUTPUT_CHANNELS], ChannelConfig *ambicoeffs, + const ChannelMap *chanmap, ALsizei count, ALsizei *outcount) { auto copy_coeffs = [&devchans,ambicoeffs](ALsizei maxchans, const ChannelMap &channel) -> ALsizei { @@ -250,11 +135,9 @@ static void SetChannelMap(const Channel (&devchans)[MAX_OUTPUT_CHANNELS], *outcount = mini(maxcount, MAX_OUTPUT_CHANNELS); } -static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei speakermap[MAX_OUTPUT_CHANNELS]) +bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei speakermap[MAX_OUTPUT_CHANNELS]) { - ALsizei i; - - for(i = 0;i < conf->NumSpeakers;i++) + for(ALsizei i{0};i < conf->NumSpeakers;i++) { enum Channel ch; int chidx = -1; @@ -343,7 +226,7 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei sp } -static const ChannelMap MonoCfg[1] = { +constexpr ChannelMap MonoCfg[1] = { { FrontCenter, { 1.0f } }, }, StereoCfg[2] = { { FrontLeft, { 5.00000000e-1f, 2.88675135e-1f, 0.0f, 5.52305643e-2f } }, @@ -378,8 +261,7 @@ static const ChannelMap MonoCfg[1] = { { BackRight, { 2.04124145e-1f, -1.08880247e-1f, 0.0f, -1.88586120e-1f, 1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, -3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, }; -static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, - const ALsizei *RESTRICT chans_per_order) +void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, const ALsizei *RESTRICT chans_per_order) { const char *devname = device->DeviceName.c_str(); ALsizei i; @@ -399,7 +281,7 @@ static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei orde } } -static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) +void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) { const char *devname = device->DeviceName.c_str(); ALfloat maxdist = 0.0f; @@ -457,7 +339,7 @@ static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const AL } } -static void InitPanning(ALCdevice *device) +void InitPanning(ALCdevice *device) { const ChannelMap *chanmap = NULL; ALsizei coeffcount = 0; @@ -604,7 +486,7 @@ static void InitPanning(ALCdevice *device) device->RealOut.NumChannels = 0; } -static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) +void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) { ChannelMap chanmap[MAX_OUTPUT_CHANNELS]; const ALfloat *coeff_scale = N3D2N3DScale; @@ -689,7 +571,7 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A InitDistanceComp(device, conf, speakermap); } -static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) +void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) { static constexpr ALsizei chans_per_order2d[MAX_AMBI_ORDER+1] = { 1, 2, 2, 2 }; static constexpr ALsizei chans_per_order3d[MAX_AMBI_ORDER+1] = { 1, 3, 5, 7 }; @@ -770,7 +652,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz InitDistanceComp(device, conf, speakermap); } -static void InitHrtfPanning(ALCdevice *device) +void InitHrtfPanning(ALCdevice *device) { /* NOTE: azimuth goes clockwise. */ static constexpr struct AngularPoint AmbiPoints[] = { @@ -892,7 +774,7 @@ static void InitHrtfPanning(ALCdevice *device) ChansPerOrder); } -static void InitUhjPanning(ALCdevice *device) +void InitUhjPanning(ALCdevice *device) { static constexpr ALsizei count{3}; @@ -910,6 +792,121 @@ static void InitUhjPanning(ALCdevice *device) device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); } +} // namespace + + +void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread, + ALfloat (&coeffs)[MAX_AMBI_COEFFS]) +{ + /* Zeroth-order */ + coeffs[0] = 1.0f; /* ACN 0 = 1 */ + /* First-order */ + coeffs[1] = SQRTF_3 * y; /* ACN 1 = sqrt(3) * Y */ + coeffs[2] = SQRTF_3 * z; /* ACN 2 = sqrt(3) * Z */ + coeffs[3] = SQRTF_3 * x; /* ACN 3 = sqrt(3) * X */ + /* Second-order */ + coeffs[4] = 3.872983346f * x * y; /* ACN 4 = sqrt(15) * X * Y */ + coeffs[5] = 3.872983346f * y * z; /* ACN 5 = sqrt(15) * Y * Z */ + coeffs[6] = 1.118033989f * (3.0f*z*z - 1.0f); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */ + coeffs[7] = 3.872983346f * x * z; /* ACN 7 = sqrt(15) * X * Z */ + coeffs[8] = 1.936491673f * (x*x - y*y); /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */ + /* Third-order */ + coeffs[9] = 2.091650066f * y * (3.0f*x*x - y*y); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */ + coeffs[10] = 10.246950766f * z * x * y; /* ACN 10 = sqrt(105) * Z * X * Y */ + coeffs[11] = 1.620185175f * y * (5.0f*z*z - 1.0f); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */ + coeffs[12] = 1.322875656f * z * (5.0f*z*z - 3.0f); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */ + coeffs[13] = 1.620185175f * x * (5.0f*z*z - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */ + coeffs[14] = 5.123475383f * z * (x*x - y*y); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */ + coeffs[15] = 2.091650066f * x * (x*x - 3.0f*y*y); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */ + + if(spread > 0.0f) + { + /* Implement the spread by using a spherical source that subtends the + * angle spread. See: + * http://www.ppsloan.org/publications/StupidSH36.pdf - Appendix A3 + * + * When adjusted for N3D normalization instead of SN3D, these + * calculations are: + * + * ZH0 = -sqrt(pi) * (-1+ca); + * ZH1 = 0.5*sqrt(pi) * sa*sa; + * ZH2 = -0.5*sqrt(pi) * ca*(-1+ca)*(ca+1); + * ZH3 = -0.125*sqrt(pi) * (-1+ca)*(ca+1)*(5*ca*ca - 1); + * ZH4 = -0.125*sqrt(pi) * ca*(-1+ca)*(ca+1)*(7*ca*ca - 3); + * ZH5 = -0.0625*sqrt(pi) * (-1+ca)*(ca+1)*(21*ca*ca*ca*ca - 14*ca*ca + 1); + * + * The gain of the source is compensated for size, so that the + * loundness doesn't depend on the spread. Thus: + * + * ZH0 = 1.0f; + * ZH1 = 0.5f * (ca+1.0f); + * ZH2 = 0.5f * (ca+1.0f)*ca; + * ZH3 = 0.125f * (ca+1.0f)*(5.0f*ca*ca - 1.0f); + * ZH4 = 0.125f * (ca+1.0f)*(7.0f*ca*ca - 3.0f)*ca; + * ZH5 = 0.0625f * (ca+1.0f)*(21.0f*ca*ca*ca*ca - 14.0f*ca*ca + 1.0f); + */ + ALfloat ca = cosf(spread * 0.5f); + /* Increase the source volume by up to +3dB for a full spread. */ + ALfloat scale = sqrtf(1.0f + spread/F_TAU); + + ALfloat ZH0_norm = scale; + ALfloat ZH1_norm = 0.5f * (ca+1.f) * scale; + ALfloat ZH2_norm = 0.5f * (ca+1.f)*ca * scale; + ALfloat ZH3_norm = 0.125f * (ca+1.f)*(5.f*ca*ca-1.f) * scale; + + /* Zeroth-order */ + coeffs[0] *= ZH0_norm; + /* First-order */ + coeffs[1] *= ZH1_norm; + coeffs[2] *= ZH1_norm; + coeffs[3] *= ZH1_norm; + /* Second-order */ + coeffs[4] *= ZH2_norm; + coeffs[5] *= ZH2_norm; + coeffs[6] *= ZH2_norm; + coeffs[7] *= ZH2_norm; + coeffs[8] *= ZH2_norm; + /* Third-order */ + coeffs[9] *= ZH3_norm; + coeffs[10] *= ZH3_norm; + coeffs[11] *= ZH3_norm; + coeffs[12] *= ZH3_norm; + coeffs[13] *= ZH3_norm; + coeffs[14] *= ZH3_norm; + coeffs[15] *= ZH3_norm; + } +} + + +void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) +{ + ASSUME(numchans > 0); + auto iter = std::transform(chancoeffs, chancoeffs+numchans, std::begin(gains), + [numcoeffs,coeffs,ingain](const ChannelConfig &chancoeffs) -> ALfloat + { + ASSUME(numcoeffs > 0); + float gain{std::inner_product(std::begin(chancoeffs), std::begin(chancoeffs)+numcoeffs, + coeffs, float{0.0f})}; + return clampf(gain, 0.0f, 1.0f) * ingain; + } + ); + std::fill(iter, std::end(gains), 0.0f); +} + +void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) +{ + ASSUME(numchans > 0); + auto iter = std::transform(chanmap, chanmap+numchans, std::begin(gains), + [coeffs,ingain](const BFChannelConfig &chanmap) noexcept -> ALfloat + { + ASSUME(chanmap.Index >= 0); + return chanmap.Scale * coeffs[chanmap.Index] * ingain; + } + ); + std::fill(iter, std::end(gains), 0.0f); +} + + void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq) { /* Hold the HRTF the device last used, in case it's used again. */ -- cgit v1.2.3 From d91ada2e028338df35929a79a9393c6ac6e7b168 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 10 Dec 2018 02:13:57 -0800 Subject: Add missing header --- Alc/panning.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 507ea5f7..c99cffa4 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -28,6 +28,7 @@ #include #include +#include #include "alMain.h" #include "alAuxEffectSlot.h" -- cgit v1.2.3 From ed18fd76c5546b295731fc5bbd9adcca896106e2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 10 Dec 2018 14:49:57 -0800 Subject: Clean up a few more loops --- Alc/panning.cpp | 167 +++++++++++++++++++++++----------------------- OpenAL32/Include/alMain.h | 15 ++++- 2 files changed, 97 insertions(+), 85 deletions(-) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index c99cffa4..c08961ed 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -136,13 +136,10 @@ void SetChannelMap(const Channel (&devchans)[MAX_OUTPUT_CHANNELS], ChannelConfig *outcount = mini(maxcount, MAX_OUTPUT_CHANNELS); } -bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei speakermap[MAX_OUTPUT_CHANNELS]) +bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) { - for(ALsizei i{0};i < conf->NumSpeakers;i++) + auto map_spkr = [device](const AmbDecConf::SpeakerConf &speaker) -> ALsizei { - enum Channel ch; - int chidx = -1; - /* NOTE: AmbDec does not define any standard speaker names, however * for this to work we have to by able to find the output channel * the speaker definition corresponds to. Therefore, OpenAL Soft @@ -163,67 +160,67 @@ bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei speakerma * use the side channels when the device is configured for back, * and vice-versa. */ - if(conf->Speakers[i].Name == "LF") + Channel ch{}; + if(speaker.Name == "LF") ch = FrontLeft; - else if(conf->Speakers[i].Name == "RF") + else if(speaker.Name == "RF") ch = FrontRight; - else if(conf->Speakers[i].Name == "CE") + else if(speaker.Name == "CE") ch = FrontCenter; - else if(conf->Speakers[i].Name == "LS") + else if(speaker.Name == "LS") { if(device->FmtChans == DevFmtX51Rear) ch = BackLeft; else ch = SideLeft; } - else if(conf->Speakers[i].Name == "RS") + else if(speaker.Name == "RS") { if(device->FmtChans == DevFmtX51Rear) ch = BackRight; else ch = SideRight; } - else if(conf->Speakers[i].Name == "LB") + else if(speaker.Name == "LB") { if(device->FmtChans == DevFmtX51) ch = SideLeft; else ch = BackLeft; } - else if(conf->Speakers[i].Name == "RB") + else if(speaker.Name == "RB") { if(device->FmtChans == DevFmtX51) ch = SideRight; else ch = BackRight; } - else if(conf->Speakers[i].Name == "CB") + else if(speaker.Name == "CB") ch = BackCenter; else { - const char *name = conf->Speakers[i].Name.c_str(); + const char *name{speaker.Name.c_str()}; unsigned int n; char c; if(sscanf(name, "AUX%u%c", &n, &c) == 1 && n < 16) - ch = static_cast(Aux0+n); + ch = static_cast(Aux0+n); else { ERR("AmbDec speaker label \"%s\" not recognized\n", name); - return false; + return -1; } } - chidx = GetChannelIdxByName(&device->RealOut, ch); + const int chidx{GetChannelIdxByName(&device->RealOut, ch)}; if(chidx == -1) - { - ERR("Failed to lookup AmbDec speaker label %s\n", - conf->Speakers[i].Name.c_str()); - return false; - } - speakermap[i] = chidx; - } - - return true; + ERR("Failed to lookup AmbDec speaker label %s\n", speaker.Name.c_str()); + return chidx; + }; + auto speakers_end = std::begin(conf->Speakers) + conf->NumSpeakers; + std::transform(std::begin(conf->Speakers), speakers_end, std::begin(speakermap), map_spkr); + /* Return success if no invalid entries are found. */ + auto speakermap_end = std::begin(speakermap) + conf->NumSpeakers; + return std::find(std::begin(speakermap), speakermap_end, -1) == speakermap_end; } @@ -264,79 +261,83 @@ constexpr ChannelMap MonoCfg[1] = { void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, const ALsizei *RESTRICT chans_per_order) { - const char *devname = device->DeviceName.c_str(); - ALsizei i; + /* NFC is only used when AvgSpeakerDist is greater than 0, and can only be + * used when rendering to an ambisonic buffer. + */ + const char *devname{device->DeviceName.c_str()}; + if(!GetConfigValueBool(devname, "decoder", "nfc", 1) || !(ctrl_dist > 0.0f)) + return; - if(GetConfigValueBool(devname, "decoder", "nfc", 1) && ctrl_dist > 0.0f) - { - /* NFC is only used when AvgSpeakerDist is greater than 0, and can only - * be used when rendering to an ambisonic buffer. - */ - device->AvgSpeakerDist = minf(ctrl_dist, 10.0f); - TRACE("Using near-field reference distance: %.2f meters\n", device->AvgSpeakerDist); + device->AvgSpeakerDist = minf(ctrl_dist, 10.0f); + TRACE("Using near-field reference distance: %.2f meters\n", device->AvgSpeakerDist); - for(i = 0;i < order+1;i++) - device->NumChannelsPerOrder[i] = chans_per_order[i]; - for(;i < MAX_AMBI_ORDER+1;i++) - device->NumChannelsPerOrder[i] = 0; - } + auto iter = std::copy(chans_per_order, chans_per_order+order+1, + std::begin(device->NumChannelsPerOrder)); + std::fill(iter, std::end(device->NumChannelsPerOrder), 0); } -void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) +void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) { - const char *devname = device->DeviceName.c_str(); - ALfloat maxdist = 0.0f; - size_t total = 0; - ALsizei i; + using namespace std::placeholders; - for(i = 0;i < conf->NumSpeakers;i++) - maxdist = maxf(maxdist, conf->Speakers[i].Distance); + auto speakers_end = std::begin(conf->Speakers) + conf->NumSpeakers; + const ALfloat maxdist{ + std::accumulate(std::begin(conf->Speakers), speakers_end, float{0.0f}, + std::bind(maxf, _1, std::bind(std::mem_fn(&AmbDecConf::SpeakerConf::Distance), _2)) + ) + }; - if(GetConfigValueBool(devname, "decoder", "distance-comp", 1) && maxdist > 0.0f) + const char *devname{device->DeviceName.c_str()}; + if(!GetConfigValueBool(devname, "decoder", "distance-comp", 1) || !(maxdist > 0.0f)) + return; + + auto srate = static_cast(device->Frequency); + size_t total{0u}; + for(ALsizei i{0};i < conf->NumSpeakers;i++) { - ALfloat srate = (ALfloat)device->Frequency; - for(i = 0;i < conf->NumSpeakers;i++) - { - ALsizei chan = speakermap[i]; - ALfloat delay; - - /* Distance compensation only delays in steps of the sample rate. - * This is a bit less accurate since the delay time falls to the - * nearest sample time, but it's far simpler as it doesn't have to - * deal with phase offsets. This means at 48khz, for instance, the - * distance delay will be in steps of about 7 millimeters. - */ - delay = floorf((maxdist-conf->Speakers[i].Distance) / SPEEDOFSOUNDMETRESPERSEC * - srate + 0.5f); - if(delay >= (ALfloat)MAX_DELAY_LENGTH) - ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n", - conf->Speakers[i].Name.c_str(), delay, MAX_DELAY_LENGTH); - - device->ChannelDelay[chan].Length = (ALsizei)clampf( - delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1) - ); - device->ChannelDelay[chan].Gain = conf->Speakers[i].Distance / maxdist; - TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan, - conf->Speakers[i].Name.c_str(), device->ChannelDelay[chan].Length, - device->ChannelDelay[chan].Gain - ); + const AmbDecConf::SpeakerConf &speaker = conf->Speakers[i]; + const ALsizei chan{speakermap[i]}; + + /* Distance compensation only delays in steps of the sample rate. This + * is a bit less accurate since the delay time falls to the nearest + * sample time, but it's far simpler as it doesn't have to deal with + * phase offsets. This means at 48khz, for instance, the distance delay + * will be in steps of about 7 millimeters. + */ + const ALfloat delay{ + std::floor((maxdist - speaker.Distance)/SPEEDOFSOUNDMETRESPERSEC*srate + 0.5f) + }; + if(delay >= (ALfloat)MAX_DELAY_LENGTH) + ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %d)\n", + speaker.Name.c_str(), delay, MAX_DELAY_LENGTH); + + device->ChannelDelay[chan].Length = static_cast(clampf( + delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1) + )); + device->ChannelDelay[chan].Gain = speaker.Distance / maxdist; + TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan, + speaker.Name.c_str(), device->ChannelDelay[chan].Length, + device->ChannelDelay[chan].Gain + ); - /* Round up to the next 4th sample, so each channel buffer starts - * 16-byte aligned. - */ - total += RoundUp(device->ChannelDelay[chan].Length, 4); - } + /* Round up to the next 4th sample, so each channel buffer starts + * 16-byte aligned. + */ + total += RoundUp(device->ChannelDelay[chan].Length, 4); } if(total > 0) { device->ChannelDelay.resize(total); device->ChannelDelay[0].Buffer = device->ChannelDelay.data(); - for(i = 1;i < MAX_OUTPUT_CHANNELS;i++) + auto set_bufptr = [](const DistanceComp::DistData &last, const DistanceComp::DistData &cur) -> DistanceComp::DistData { - size_t len = RoundUp(device->ChannelDelay[i-1].Length, 4); - device->ChannelDelay[i].Buffer = device->ChannelDelay[i-1].Buffer + len; - } + DistanceComp::DistData ret{cur}; + ret.Buffer = last.Buffer + RoundUp(last.Length, 4); + return ret; + }; + std::partial_sum(device->ChannelDelay.begin(), device->ChannelDelay.end(), + device->ChannelDelay.begin(), set_bufptr); } } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 422202bd..0f65965a 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -608,15 +608,19 @@ typedef struct EnumeratedHrtf { #define MAX_DELAY_LENGTH 1024 class DistanceComp { +public: struct DistData { ALfloat Gain{1.0f}; ALsizei Length{0}; /* Valid range is [0...MAX_DELAY_LENGTH). */ ALfloat *Buffer{nullptr}; - } mChannel[MAX_OUTPUT_CHANNELS]; + }; + +private: + DistData mChannel[MAX_OUTPUT_CHANNELS]; al::vector mSamples; public: - void resize(size_t amt) { mSamples.resize(amt); } + void resize(size_t new_size) { mSamples.resize(new_size); } void shrink_to_fit() { mSamples.shrink_to_fit(); } void clear() noexcept { @@ -629,6 +633,13 @@ public: mSamples.clear(); } + DistData *begin() noexcept { return std::begin(mChannel); } + const DistData *begin() const noexcept { return std::begin(mChannel); } + const DistData *cbegin() const noexcept { return std::begin(mChannel); } + DistData *end() noexcept { return std::end(mChannel); } + const DistData *end() const noexcept { return std::end(mChannel); } + const DistData *cend() const noexcept { return std::end(mChannel); } + ALfloat *data() noexcept { return mSamples.data(); } const ALfloat *data() const noexcept { return mSamples.data(); } -- cgit v1.2.3 From e87eb07db411a0ecd02b5b5c50a4a721150e846e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 10 Dec 2018 21:30:22 -0800 Subject: A bit more cleanup --- Alc/bformatdec.cpp | 117 ++++++++++++++----------------------------------- Alc/bformatdec.h | 45 +++++++++++++++++-- Alc/panning.cpp | 79 +++++++++++++++------------------ OpenAL32/Include/alu.h | 4 +- 4 files changed, 113 insertions(+), 132 deletions(-) diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 60e52b1b..8b12149a 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -17,49 +17,9 @@ #include "almalloc.h" -/* NOTE: These are scale factors as applied to Ambisonics content. Decoder - * coefficients should be divided by these values to get proper N3D scalings. - */ -const ALfloat N3D2N3DScale[MAX_AMBI_COEFFS] = { - 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f -}; -const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = { - 1.000000000f, /* ACN 0 (W), sqrt(1) */ - 1.732050808f, /* ACN 1 (Y), sqrt(3) */ - 1.732050808f, /* ACN 2 (Z), sqrt(3) */ - 1.732050808f, /* ACN 3 (X), sqrt(3) */ - 2.236067978f, /* ACN 4 (V), sqrt(5) */ - 2.236067978f, /* ACN 5 (T), sqrt(5) */ - 2.236067978f, /* ACN 6 (R), sqrt(5) */ - 2.236067978f, /* ACN 7 (S), sqrt(5) */ - 2.236067978f, /* ACN 8 (U), sqrt(5) */ - 2.645751311f, /* ACN 9 (Q), sqrt(7) */ - 2.645751311f, /* ACN 10 (O), sqrt(7) */ - 2.645751311f, /* ACN 11 (M), sqrt(7) */ - 2.645751311f, /* ACN 12 (K), sqrt(7) */ - 2.645751311f, /* ACN 13 (L), sqrt(7) */ - 2.645751311f, /* ACN 14 (N), sqrt(7) */ - 2.645751311f, /* ACN 15 (P), sqrt(7) */ -}; -const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = { - 1.414213562f, /* ACN 0 (W), sqrt(2) */ - 1.732050808f, /* ACN 1 (Y), sqrt(3) */ - 1.732050808f, /* ACN 2 (Z), sqrt(3) */ - 1.732050808f, /* ACN 3 (X), sqrt(3) */ - 1.936491673f, /* ACN 4 (V), sqrt(15)/2 */ - 1.936491673f, /* ACN 5 (T), sqrt(15)/2 */ - 2.236067978f, /* ACN 6 (R), sqrt(5) */ - 1.936491673f, /* ACN 7 (S), sqrt(15)/2 */ - 1.936491673f, /* ACN 8 (U), sqrt(15)/2 */ - 2.091650066f, /* ACN 9 (Q), sqrt(35/8) */ - 1.972026594f, /* ACN 10 (O), sqrt(35)/3 */ - 2.231093404f, /* ACN 11 (M), sqrt(224/45) */ - 2.645751311f, /* ACN 12 (K), sqrt(7) */ - 2.231093404f, /* ACN 13 (L), sqrt(224/45) */ - 1.972026594f, /* ACN 14 (N), sqrt(35)/3 */ - 2.091650066f, /* ACN 15 (P), sqrt(35/8) */ -}; +constexpr float AmbiScale::N3D2N3D[MAX_AMBI_COEFFS]; +constexpr float AmbiScale::SN3D2N3D[MAX_AMBI_COEFFS]; +constexpr float AmbiScale::FuMa2N3D[MAX_AMBI_COEFFS]; namespace { @@ -114,10 +74,7 @@ ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn) void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]) { - static constexpr ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = { - 0, 1, 3, 4, 8, 9, 15 - }; - const ALfloat *coeff_scale = N3D2N3DScale; + static constexpr ALsizei map2DTo3D[MAX_AMBI2D_COEFFS]{ 0, 1, 3, 4, 8, 9, 15 }; mSamples.clear(); mSamplesHF = nullptr; @@ -133,11 +90,6 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, { return mask | (1 << chan); } ); - if(conf->CoeffScale == AmbDecScale::SN3D) - coeff_scale = SN3D2N3DScale; - else if(conf->CoeffScale == AmbDecScale::FuMa) - coeff_scale = FuMa2N3DScale; - mUpSampler[0].XOver.init(400.0f / (float)srate); std::fill(std::begin(mUpSampler[0].Gains), std::end(mUpSampler[0].Gains), 0.0f); std::fill(std::begin(mUpSampler)+1, std::end(mUpSampler), mUpSampler[0]); @@ -170,23 +122,25 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, mUpSampler[3].Gains[LF_BAND] = 0.0f; } + const ALfloat (&coeff_scale)[MAX_AMBI_COEFFS] = + (conf->CoeffScale == AmbDecScale::FuMa) ? AmbiScale::FuMa2N3D : + (conf->CoeffScale == AmbDecScale::SN3D) ? AmbiScale::SN3D2N3D : + /*(conf->CoeffScale == AmbDecScale::N3D) ?*/ AmbiScale::N3D2N3D; + mMatrix = MatrixU{}; if(conf->FreqBands == 1) { mDualBand = AL_FALSE; for(ALsizei i{0};i < conf->NumSpeakers;i++) { - ALsizei chan = chanmap[i]; - ALfloat gain; - ALsizei j, k; - + const ALsizei chan{chanmap[i]}; if(!periphonic) { - for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++) + ALfloat gain{conf->HFOrderGain[0]}; + for(ALsizei j{0},k{0};j < MAX_AMBI2D_COEFFS;j++) { - ALsizei l = map2DTo3D[j]; - if(j == 0) gain = conf->HFOrderGain[0]; - else if(j == 1) gain = conf->HFOrderGain[1]; + const ALsizei l{map2DTo3D[j]}; + if(j == 1) gain = conf->HFOrderGain[1]; else if(j == 3) gain = conf->HFOrderGain[2]; else if(j == 5) gain = conf->HFOrderGain[3]; if((conf->ChanMask&(1<HFOrderGain[0]}; + for(ALsizei j{0},k{0};j < MAX_AMBI_COEFFS;j++) { - if(j == 0) gain = conf->HFOrderGain[0]; - else if(j == 1) gain = conf->HFOrderGain[1]; + if(j == 1) gain = conf->HFOrderGain[1]; else if(j == 4) gain = conf->HFOrderGain[2]; else if(j == 9) gain = conf->HFOrderGain[3]; if((conf->ChanMask&(1<XOverFreq / (float)srate); std::fill(std::begin(mXOver)+1, std::end(mXOver), mXOver[0]); - float ratio{std::pow(10.0f, conf->XOverRatio / 40.0f)}; + const float ratio{std::pow(10.0f, conf->XOverRatio / 40.0f)}; for(ALsizei i{0};i < conf->NumSpeakers;i++) { - ALsizei chan = chanmap[i]; - - ALfloat gain{}; + const ALsizei chan{chanmap[i]}; if(!periphonic) { + ALfloat gain{conf->HFOrderGain[0] * ratio}; for(ALsizei j{0},k{0};j < MAX_AMBI2D_COEFFS;j++) { ALsizei l = map2DTo3D[j]; - if(j == 0) gain = conf->HFOrderGain[0] * ratio; - else if(j == 1) gain = conf->HFOrderGain[1] * ratio; + if(j == 1) gain = conf->HFOrderGain[1] * ratio; else if(j == 3) gain = conf->HFOrderGain[2] * ratio; else if(j == 5) gain = conf->HFOrderGain[3] * ratio; if((conf->ChanMask&(1<HFMatrix[i][k++] / coeff_scale[l] * gain; } + gain = conf->HFOrderGain[0] / ratio; for(ALsizei j{0},k{0};j < MAX_AMBI2D_COEFFS;j++) { ALsizei l = map2DTo3D[j]; - if(j == 0) gain = conf->LFOrderGain[0] / ratio; - else if(j == 1) gain = conf->LFOrderGain[1] / ratio; + if(j == 1) gain = conf->LFOrderGain[1] / ratio; else if(j == 3) gain = conf->LFOrderGain[2] / ratio; else if(j == 5) gain = conf->LFOrderGain[3] / ratio; if((conf->ChanMask&(1<HFOrderGain[0] * ratio}; for(ALsizei j{0},k{0};j < MAX_AMBI_COEFFS;j++) { - if(j == 0) gain = conf->HFOrderGain[0] * ratio; - else if(j == 1) gain = conf->HFOrderGain[1] * ratio; + if(j == 1) gain = conf->HFOrderGain[1] * ratio; else if(j == 4) gain = conf->HFOrderGain[2] * ratio; else if(j == 9) gain = conf->HFOrderGain[3] * ratio; if((conf->ChanMask&(1<HFMatrix[i][k++] / coeff_scale[j] * gain; } + gain = conf->HFOrderGain[0] / ratio; for(ALsizei j{0},k{0};j < MAX_AMBI_COEFFS;j++) { - if(j == 0) gain = conf->LFOrderGain[0] / ratio; - else if(j == 1) gain = conf->LFOrderGain[1] / ratio; + if(j == 1) gain = conf->LFOrderGain[1] / ratio; else if(j == 4) gain = conf->LFOrderGain[2] / ratio; else if(j == 9) gain = conf->LFOrderGain[3] / ratio; if((conf->ChanMask&(1< 0); ASSUME(SamplesToDo > 0); - ALsizei chan, i; if(mDualBand) { - for(i = 0;i < mNumChannels;i++) + for(ALsizei i{0};i < mNumChannels;i++) mXOver[i].process(mSamplesHF[i].data(), mSamplesLF[i].data(), InSamples[i], SamplesToDo); - for(chan = 0;chan < OutChannels;chan++) + for(ALsizei chan{0};chan < OutChannels;chan++) { if(UNLIKELY(!(mEnabled&(1<Dry, coeffs, 1.0f, encgains[k]); } @@ -378,7 +329,7 @@ void AmbiUpsampler::reset(const ALCdevice *device, const ALfloat w_scale, const { for(ALsizei j{0};j < device->Dry.NumChannels;j++) { - ALdouble gain = 0.0; + ALdouble gain{0.0}; for(size_t k{0u};k < COUNTOF(Ambi3DDecoder);k++) gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][j]; mGains[i][j][HF_BAND] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]); @@ -390,10 +341,10 @@ void AmbiUpsampler::reset(const ALCdevice *device, const ALfloat w_scale, const { for(ALsizei i{0};i < 4;i++) { - ALsizei index = GetChannelForACN(device->Dry, i); + const ALsizei index{GetChannelForACN(device->Dry, i)}; if(index != INVALID_UPSAMPLE_INDEX) { - ALfloat scale = device->Dry.Ambi.Map[index].Scale; + const ALfloat scale{device->Dry.Ambi.Map[index].Scale}; mGains[i][index][HF_BAND] = scale * ((i==0) ? w_scale : xyz_scale); mGains[i][index][LF_BAND] = scale; } diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index f2cdcdfb..d855041d 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -29,9 +29,48 @@ struct AmbDecConf; /* NOTE: These are scale factors as applied to Ambisonics content. Decoder * coefficients should be divided by these values to get proper N3D scalings. */ -extern const ALfloat N3D2N3DScale[MAX_AMBI_COEFFS]; -extern const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS]; -extern const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS]; +struct AmbiScale { + static constexpr float N3D2N3D[MAX_AMBI_COEFFS]{ + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f + }; + static constexpr float SN3D2N3D[MAX_AMBI_COEFFS]{ + 1.000000000f, /* ACN 0 (W), sqrt(1) */ + 1.732050808f, /* ACN 1 (Y), sqrt(3) */ + 1.732050808f, /* ACN 2 (Z), sqrt(3) */ + 1.732050808f, /* ACN 3 (X), sqrt(3) */ + 2.236067978f, /* ACN 4 (V), sqrt(5) */ + 2.236067978f, /* ACN 5 (T), sqrt(5) */ + 2.236067978f, /* ACN 6 (R), sqrt(5) */ + 2.236067978f, /* ACN 7 (S), sqrt(5) */ + 2.236067978f, /* ACN 8 (U), sqrt(5) */ + 2.645751311f, /* ACN 9 (Q), sqrt(7) */ + 2.645751311f, /* ACN 10 (O), sqrt(7) */ + 2.645751311f, /* ACN 11 (M), sqrt(7) */ + 2.645751311f, /* ACN 12 (K), sqrt(7) */ + 2.645751311f, /* ACN 13 (L), sqrt(7) */ + 2.645751311f, /* ACN 14 (N), sqrt(7) */ + 2.645751311f, /* ACN 15 (P), sqrt(7) */ + }; + static constexpr float FuMa2N3D[MAX_AMBI_COEFFS]{ + 1.414213562f, /* ACN 0 (W), sqrt(2) */ + 1.732050808f, /* ACN 1 (Y), sqrt(3) */ + 1.732050808f, /* ACN 2 (Z), sqrt(3) */ + 1.732050808f, /* ACN 3 (X), sqrt(3) */ + 1.936491673f, /* ACN 4 (V), sqrt(15)/2 */ + 1.936491673f, /* ACN 5 (T), sqrt(15)/2 */ + 2.236067978f, /* ACN 6 (R), sqrt(5) */ + 1.936491673f, /* ACN 7 (S), sqrt(15)/2 */ + 1.936491673f, /* ACN 8 (U), sqrt(15)/2 */ + 2.091650066f, /* ACN 9 (Q), sqrt(35/8) */ + 1.972026594f, /* ACN 10 (O), sqrt(35)/3 */ + 2.231093404f, /* ACN 11 (M), sqrt(224/45) */ + 2.645751311f, /* ACN 12 (K), sqrt(7) */ + 2.231093404f, /* ACN 13 (L), sqrt(224/45) */ + 1.972026594f, /* ACN 14 (N), sqrt(35)/3 */ + 2.091650066f, /* ACN 15 (P), sqrt(35/8) */ + }; +}; class BFormatDec { diff --git a/Alc/panning.cpp b/Alc/panning.cpp index c08961ed..2d42106b 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -398,12 +399,13 @@ void InitPanning(ALCdevice *device) if(device->FmtChans == DevFmtAmbi3D) { - const char *devname = device->DeviceName.c_str(); - const ALsizei *acnmap = (device->mAmbiLayout == AmbiLayout::FuMa) ? FuMa2ACN : ACN2ACN; - const ALfloat *n3dscale = (device->mAmbiScale == AmbiNorm::FuMa) ? FuMa2N3DScale : - (device->mAmbiScale == AmbiNorm::SN3D) ? SN3D2N3DScale : - /*(device->mAmbiScale == AmbiNorm::N3D) ?*/ N3D2N3DScale; - ALfloat nfc_delay = 0.0f; + const char *devname{device->DeviceName.c_str()}; + const ALsizei (&acnmap)[MAX_AMBI_COEFFS] = + (device->mAmbiLayout == AmbiLayout::FuMa) ? FuMa2ACN : ACN2ACN; + const ALfloat (&n3dscale)[MAX_AMBI_COEFFS] = + (device->mAmbiScale == AmbiNorm::FuMa) ? AmbiScale::FuMa2N3D : + (device->mAmbiScale == AmbiNorm::SN3D) ? AmbiScale::SN3D2N3D : + /*(device->mAmbiScale == AmbiNorm::N3D) ?*/ AmbiScale::N3D2N3D; count = (device->mAmbiOrder == 3) ? 16 : (device->mAmbiOrder == 2) ? 9 : @@ -425,8 +427,6 @@ void InitPanning(ALCdevice *device) } else { - ALfloat w_scale=1.0f, xyz_scale=1.0f; - /* FOA output is always ACN+N3D for higher-order ambisonic output. * The upsampler expects this and will convert it for output. */ @@ -439,6 +439,7 @@ void InitPanning(ALCdevice *device) device->FOAOut.CoeffCount = 0; device->FOAOut.NumChannels = 4; + ALfloat w_scale{1.0f}, xyz_scale{1.0f}; if(device->mAmbiOrder >= 3) { w_scale = W_SCALE_3H3P; @@ -452,11 +453,10 @@ void InitPanning(ALCdevice *device) device->AmbiUp->reset(device, w_scale, xyz_scale); } + ALfloat nfc_delay{0.0f}; if(ConfigValueFloat(devname, "decoder", "nfc-ref-delay", &nfc_delay) && nfc_delay > 0.0f) { - static const ALsizei chans_per_order[MAX_AMBI_ORDER+1] = { - 1, 3, 5, 7 - }; + static constexpr ALsizei chans_per_order[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; nfc_delay = clampf(nfc_delay, 0.001f, 1000.0f); InitNearFieldCtrl(device, nfc_delay * SPEEDOFSOUNDMETRESPERSEC, device->mAmbiOrder, chans_per_order); @@ -464,16 +464,14 @@ void InitPanning(ALCdevice *device) } else { - ALfloat w_scale, xyz_scale; - SetChannelMap(device->RealOut.ChannelName, device->Dry.Ambi.Coeffs, chanmap, count, &device->Dry.NumChannels); device->Dry.CoeffCount = coeffcount; - w_scale = (device->Dry.CoeffCount > 9) ? W_SCALE_3H0P : - (device->Dry.CoeffCount > 4) ? W_SCALE_2H0P : 1.0f; - xyz_scale = (device->Dry.CoeffCount > 9) ? XYZ_SCALE_3H0P : - (device->Dry.CoeffCount > 4) ? XYZ_SCALE_2H0P : 1.0f; + const ALfloat w_scale{(device->Dry.CoeffCount > 9) ? W_SCALE_3H0P : + (device->Dry.CoeffCount > 4) ? W_SCALE_2H0P : 1.0f}; + const ALfloat xyz_scale{(device->Dry.CoeffCount > 9) ? XYZ_SCALE_3H0P : + (device->Dry.CoeffCount > 4) ? XYZ_SCALE_2H0P : 1.0f}; device->FOAOut.Ambi = AmbiConfig{}; for(i = 0;i < device->Dry.NumChannels;i++) @@ -490,16 +488,11 @@ void InitPanning(ALCdevice *device) void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) { - ChannelMap chanmap[MAX_OUTPUT_CHANNELS]; - const ALfloat *coeff_scale = N3D2N3DScale; - ALfloat w_scale = 1.0f; - ALfloat xyz_scale = 1.0f; - ALsizei i, j; - if(conf->FreqBands != 1) ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n", conf->XOverFreq); + ALfloat w_scale{1.0f}, xyz_scale{1.0f}; if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { if(conf->ChanMask > 0x1ff) @@ -527,25 +520,23 @@ void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei } } - if(conf->CoeffScale == AmbDecScale::SN3D) - coeff_scale = SN3D2N3DScale; - else if(conf->CoeffScale == AmbDecScale::FuMa) - coeff_scale = FuMa2N3DScale; - - for(i = 0;i < conf->NumSpeakers;i++) + const ALfloat (&coeff_scale)[MAX_AMBI_COEFFS] = + (conf->CoeffScale == AmbDecScale::FuMa) ? AmbiScale::FuMa2N3D : + (conf->CoeffScale == AmbDecScale::SN3D) ? AmbiScale::SN3D2N3D : + /*(conf->CoeffScale == AmbDecScale::N3D) ?*/ AmbiScale::N3D2N3D; + ChannelMap chanmap[MAX_OUTPUT_CHANNELS]{}; + for(ALsizei i{0};i < conf->NumSpeakers;i++) { - ALsizei chan = speakermap[i]; - ALfloat gain; - ALsizei k = 0; - - for(j = 0;j < MAX_AMBI_COEFFS;j++) - chanmap[i].Config[j] = 0.0f; + const ALsizei chan{speakermap[i]}; chanmap[i].ChanName = device->RealOut.ChannelName[chan]; - for(j = 0;j < MAX_AMBI_COEFFS;j++) + std::fill(std::begin(chanmap[i].Config), std::end(chanmap[i].Config), 0.0f); + + ALsizei k{0}; + ALfloat gain{conf->HFOrderGain[0]}; + for(ALsizei j{0};j < MAX_AMBI_COEFFS;j++) { - if(j == 0) gain = conf->HFOrderGain[0]; - else if(j == 1) gain = conf->HFOrderGain[1]; + if(j == 1) gain = conf->HFOrderGain[1]; else if(j == 4) gain = conf->HFOrderGain[2]; else if(j == 9) gain = conf->HFOrderGain[3]; if((conf->ChanMask&(1<ChanMask > 0xf) ? 9 : 4; device->FOAOut.Ambi = AmbiConfig{}; - for(i = 0;i < device->Dry.NumChannels;i++) + for(ALsizei i{0};i < device->Dry.NumChannels;i++) { device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0] * w_scale; - for(j = 1;j < 4;j++) + for(ALsizei j{1};j < 4;j++) device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * xyz_scale; } device->FOAOut.CoeffCount = 4; @@ -577,8 +568,8 @@ void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&sp { static constexpr ALsizei chans_per_order2d[MAX_AMBI_ORDER+1] = { 1, 2, 2, 2 }; static constexpr ALsizei chans_per_order3d[MAX_AMBI_ORDER+1] = { 1, 3, 5, 7 }; - ALsizei count; + ALsizei count; if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { static constexpr int map[MAX_AMBI_COEFFS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; @@ -782,7 +773,7 @@ void InitUhjPanning(ALCdevice *device) std::transform(std::begin(FuMa2ACN), std::begin(FuMa2ACN)+count, std::begin(device->Dry.Ambi.Map), [](const ALsizei &acn) noexcept -> BFChannelConfig - { return BFChannelConfig{1.0f/FuMa2N3DScale[acn], acn}; } + { return BFChannelConfig{1.0f/AmbiScale::FuMa2N3D[acn], acn}; } ); device->Dry.CoeffCount = 0; device->Dry.NumChannels = count; @@ -847,9 +838,9 @@ void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALf * ZH4 = 0.125f * (ca+1.0f)*(7.0f*ca*ca - 3.0f)*ca; * ZH5 = 0.0625f * (ca+1.0f)*(21.0f*ca*ca*ca*ca - 14.0f*ca*ca + 1.0f); */ - ALfloat ca = cosf(spread * 0.5f); + ALfloat ca = std::cos(spread * 0.5f); /* Increase the source volume by up to +3dB for a full spread. */ - ALfloat scale = sqrtf(1.0f + spread/F_TAU); + ALfloat scale = std::sqrt(1.0f + spread/F_TAU); ALfloat ZH0_norm = scale; ALfloat ZH1_norm = 0.5f * (ca+1.f) * scale; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index e011675c..1b5c274d 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -94,8 +94,8 @@ typedef const ALfloat* (*ResamplerFunc)(const InterpState *state, void BsincPrepare(const ALuint increment, BsincState *state, const struct BSincTable *table); -extern const struct BSincTable bsinc12; -extern const struct BSincTable bsinc24; +extern const BSincTable bsinc12; +extern const BSincTable bsinc24; enum { -- cgit v1.2.3 From 0d36ba0fbbed583e5f5fbe0a99fa0fd60773e2e0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 10 Dec 2018 22:32:10 -0800 Subject: Use helpers to get the Ambisonic scales and layout maps --- Alc/bformatdec.cpp | 12 ++++++++---- Alc/panning.cpp | 34 ++++++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 8b12149a..888c7cab 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -69,6 +69,13 @@ ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn) } #define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a)) +auto GetAmbiScales(AmbDecScale scaletype) noexcept -> decltype(AmbiScale::N3D2N3D)& +{ + if(scaletype == AmbDecScale::FuMa) return AmbiScale::FuMa2N3D; + if(scaletype == AmbDecScale::SN3D) return AmbiScale::SN3D2N3D; + return AmbiScale::N3D2N3D; +} + } // namespace @@ -122,10 +129,7 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, mUpSampler[3].Gains[LF_BAND] = 0.0f; } - const ALfloat (&coeff_scale)[MAX_AMBI_COEFFS] = - (conf->CoeffScale == AmbDecScale::FuMa) ? AmbiScale::FuMa2N3D : - (conf->CoeffScale == AmbDecScale::SN3D) ? AmbiScale::SN3D2N3D : - /*(conf->CoeffScale == AmbDecScale::N3D) ?*/ AmbiScale::N3D2N3D; + const ALfloat (&coeff_scale)[MAX_AMBI_COEFFS] = GetAmbiScales(conf->CoeffScale); mMatrix = MatrixU{}; if(conf->FreqBands == 1) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 2d42106b..6a510e7b 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -342,6 +342,27 @@ void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei ( } } +auto GetAmbiScales(AmbDecScale scaletype) noexcept -> const float(&)[MAX_AMBI_COEFFS] +{ + if(scaletype == AmbDecScale::FuMa) return AmbiScale::FuMa2N3D; + if(scaletype == AmbDecScale::SN3D) return AmbiScale::SN3D2N3D; + return AmbiScale::N3D2N3D; +} + +auto GetAmbiScales(AmbiNorm scaletype) noexcept -> const float(&)[MAX_AMBI_COEFFS] +{ + if(scaletype == AmbiNorm::FuMa) return AmbiScale::FuMa2N3D; + if(scaletype == AmbiNorm::SN3D) return AmbiScale::SN3D2N3D; + return AmbiScale::N3D2N3D; +} + +auto GetAmbiLayout(AmbiLayout layouttype) noexcept -> const ALsizei(&)[MAX_AMBI_COEFFS] +{ + if(layouttype == AmbiLayout::FuMa) return FuMa2ACN; + return ACN2ACN; +} + + void InitPanning(ALCdevice *device) { const ChannelMap *chanmap = NULL; @@ -400,12 +421,8 @@ void InitPanning(ALCdevice *device) if(device->FmtChans == DevFmtAmbi3D) { const char *devname{device->DeviceName.c_str()}; - const ALsizei (&acnmap)[MAX_AMBI_COEFFS] = - (device->mAmbiLayout == AmbiLayout::FuMa) ? FuMa2ACN : ACN2ACN; - const ALfloat (&n3dscale)[MAX_AMBI_COEFFS] = - (device->mAmbiScale == AmbiNorm::FuMa) ? AmbiScale::FuMa2N3D : - (device->mAmbiScale == AmbiNorm::SN3D) ? AmbiScale::SN3D2N3D : - /*(device->mAmbiScale == AmbiNorm::N3D) ?*/ AmbiScale::N3D2N3D; + const ALsizei (&acnmap)[MAX_AMBI_COEFFS] = GetAmbiLayout(device->mAmbiLayout); + const ALfloat (&n3dscale)[MAX_AMBI_COEFFS] = GetAmbiScales(device->mAmbiScale); count = (device->mAmbiOrder == 3) ? 16 : (device->mAmbiOrder == 2) ? 9 : @@ -520,10 +537,7 @@ void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei } } - const ALfloat (&coeff_scale)[MAX_AMBI_COEFFS] = - (conf->CoeffScale == AmbDecScale::FuMa) ? AmbiScale::FuMa2N3D : - (conf->CoeffScale == AmbDecScale::SN3D) ? AmbiScale::SN3D2N3D : - /*(conf->CoeffScale == AmbDecScale::N3D) ?*/ AmbiScale::N3D2N3D; + const ALfloat (&coeff_scale)[MAX_AMBI_COEFFS] = GetAmbiScales(conf->CoeffScale); ChannelMap chanmap[MAX_OUTPUT_CHANNELS]{}; for(ALsizei i{0};i < conf->NumSpeakers;i++) { -- cgit v1.2.3 From 19c5c41c704d121b126b3b496278970bdd35c512 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 12 Dec 2018 01:09:04 -0800 Subject: Cleanup alu.cpp some --- Alc/alu.cpp | 538 ++++++++++++++++++++++++++---------------------------------- 1 file changed, 237 insertions(+), 301 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index f7640d71..37d23c60 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include "alMain.h" @@ -105,7 +106,6 @@ struct ChanMap { HrtfDirectMixerFunc MixDirectHrtf = MixDirectHrtf_C; - inline HrtfDirectMixerFunc SelectHrtfMixer(void) { #ifdef HAVE_NEON @@ -120,22 +120,6 @@ inline HrtfDirectMixerFunc SelectHrtfMixer(void) return MixDirectHrtf_C; } -} // namespace - -void aluInit(void) -{ - MixDirectHrtf = SelectHrtfMixer(); -} - - -void DeinitVoice(ALvoice *voice) noexcept -{ - delete voice->Update.exchange(nullptr, std::memory_order_acq_rel); - voice->~ALvoice(); -} - - -namespace { void ProcessHrtf(ALCdevice *device, ALsizei SamplesToDo) { @@ -203,6 +187,19 @@ void ProcessBs2b(ALCdevice *device, ALsizei SamplesToDo) } // namespace +void aluInit(void) +{ + MixDirectHrtf = SelectHrtfMixer(); +} + + +void DeinitVoice(ALvoice *voice) noexcept +{ + delete voice->Update.exchange(nullptr, std::memory_order_acq_rel); + voice->~ALvoice(); +} + + void aluSelectPostProcess(ALCdevice *device) { if(device->HrtfHandle) @@ -216,7 +213,7 @@ void aluSelectPostProcess(ALCdevice *device) else if(device->Bs2b) device->PostProcess = ProcessBs2b; else - device->PostProcess = NULL; + device->PostProcess = nullptr; } @@ -228,8 +225,8 @@ void aluSelectPostProcess(ALCdevice *device) */ void BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *table) { - ALfloat sf = 0.0f; - ALsizei si = BSINC_SCALE_COUNT-1; + ALsizei si{BSINC_SCALE_COUNT - 1}; + ALfloat sf{0.0f}; if(increment > FRACTIONONE) { @@ -240,7 +237,7 @@ void BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *t * to reduce the transition ripple caused by interpolating different * scales of the sinc function. */ - sf = 1.0f - cosf(asinf(sf - si)); + sf = 1.0f - std::cos(std::asin(sf - si)); } state->sf = sf; @@ -277,7 +274,7 @@ inline ALfloat aluDotproduct(const aluVector *vec1, const aluVector *vec2) ALfloat aluNormalize(ALfloat *vec) { - ALfloat length = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); + const ALfloat length{std::sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2])}; if(length > FLT_EPSILON) { ALfloat inv_length = 1.0f/length; @@ -292,7 +289,7 @@ ALfloat aluNormalize(ALfloat *vec) void aluMatrixfFloat3(ALfloat *vec, ALfloat w, const aluMatrixf *mtx) { - ALfloat v[4] = { vec[0], vec[1], vec[2], w }; + const ALfloat v[4]{ vec[0], vec[1], vec[2], w }; vec[0] = v[0]*mtx->m[0][0] + v[1]*mtx->m[1][0] + v[2]*mtx->m[2][0] + v[3]*mtx->m[3][0]; vec[1] = v[0]*mtx->m[0][1] + v[1]*mtx->m[1][1] + v[2]*mtx->m[2][1] + v[3]*mtx->m[3][1]; @@ -326,12 +323,10 @@ void SendSourceStoppedEvent(ALCcontext *context, ALuint id) bool CalcContextParams(ALCcontext *Context) { - ALlistener &Listener = Context->Listener; - struct ALcontextProps *props; - - props = Context->Update.exchange(nullptr, std::memory_order_acq_rel); + ALcontextProps *props{Context->Update.exchange(nullptr, std::memory_order_acq_rel)}; if(!props) return false; + ALlistener &Listener = Context->Listener; Listener.Params.MetersPerUnit = props->MetersPerUnit; Listener.Params.DopplerFactor = props->DopplerFactor; @@ -350,23 +345,17 @@ bool CalcContextParams(ALCcontext *Context) bool CalcListenerParams(ALCcontext *Context) { ALlistener &Listener = Context->Listener; - ALfloat N[3], V[3], U[3], P[3]; - struct ALlistenerProps *props; - aluVector vel; - props = Listener.Update.exchange(nullptr, std::memory_order_acq_rel); + ALlistenerProps *props{Listener.Update.exchange(nullptr, std::memory_order_acq_rel)}; if(!props) return false; /* AT then UP */ - N[0] = props->Forward[0]; - N[1] = props->Forward[1]; - N[2] = props->Forward[2]; + ALfloat N[3]{ props->Forward[0], props->Forward[1], props->Forward[2] }; aluNormalize(N); - V[0] = props->Up[0]; - V[1] = props->Up[1]; - V[2] = props->Up[2]; + ALfloat V[3]{ props->Up[0], props->Up[1], props->Up[2] }; aluNormalize(V); /* Build and normalize right-vector */ + ALfloat U[3]; aluCrossproduct(N, V, U); aluNormalize(U); @@ -377,12 +366,11 @@ bool CalcListenerParams(ALCcontext *Context) 0.0, 0.0, 0.0, 1.0 ); - P[0] = props->Position[0]; - P[1] = props->Position[1]; - P[2] = props->Position[2]; + ALfloat P[3]{ props->Position[0], props->Position[1], props->Position[2] }; aluMatrixfFloat3(P, 1.0, &Listener.Params.Matrix); aluMatrixfSetRow(&Listener.Params.Matrix, 3, -P[0], -P[1], -P[2], 1.0f); + aluVector vel; aluVectorSet(&vel, props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f); Listener.Params.Velocity = aluMatrixfVector(&Listener.Params.Matrix, &vel); @@ -394,13 +382,13 @@ bool CalcListenerParams(ALCcontext *Context) bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) { - struct ALeffectslotProps *props; - EffectState *state; - - props = slot->Update.exchange(nullptr, std::memory_order_acq_rel); + ALeffectslotProps *props{slot->Update.exchange(nullptr, std::memory_order_acq_rel)}; if(!props && !force) return false; - if(props) + EffectState *state; + if(!props) + state = slot->Params.mEffectState; + else { slot->Params.Gain = props->Gain; slot->Params.AuxSendAuto = props->AuxSendAuto; @@ -462,40 +450,38 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) AtomicReplaceHead(context->FreeEffectslotProps, props); } - else - state = slot->Params.mEffectState; state->update(context, slot, &slot->Params.EffectProps); return true; } -constexpr struct ChanMap MonoMap[1] = { +constexpr struct ChanMap MonoMap[1]{ { FrontCenter, 0.0f, 0.0f } -}, RearMap[2] = { +}, RearMap[2]{ { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) }, { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) } -}, QuadMap[4] = { +}, QuadMap[4]{ { FrontLeft, DEG2RAD( -45.0f), DEG2RAD(0.0f) }, { FrontRight, DEG2RAD( 45.0f), DEG2RAD(0.0f) }, { BackLeft, DEG2RAD(-135.0f), DEG2RAD(0.0f) }, { BackRight, DEG2RAD( 135.0f), DEG2RAD(0.0f) } -}, X51Map[6] = { +}, X51Map[6]{ { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) }, { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, { LFE, 0.0f, 0.0f }, { SideLeft, DEG2RAD(-110.0f), DEG2RAD(0.0f) }, { SideRight, DEG2RAD( 110.0f), DEG2RAD(0.0f) } -}, X61Map[7] = { - { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, - { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, - { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, +}, X61Map[7]{ + { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, + { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, + { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, { LFE, 0.0f, 0.0f }, - { BackCenter, DEG2RAD(180.0f), DEG2RAD(0.0f) }, - { SideLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) }, - { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } -}, X71Map[8] = { + { BackCenter, DEG2RAD(180.0f), DEG2RAD(0.0f) }, + { SideLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) }, + { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } +}, X71Map[8]{ { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) }, { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, @@ -515,19 +501,16 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev const ALvoicePropsBase *props, const ALlistener &Listener, const ALCdevice *Device) { - struct ChanMap StereoMap[2] = { + ChanMap StereoMap[2]{ { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) } }; - bool DirectChannels = props->DirectChannels; - const ALsizei NumSends = Device->NumAuxSends; - const ALuint Frequency = Device->Frequency; - const struct ChanMap *chans = NULL; - ALsizei num_channels = 0; - bool isbformat = false; - ALfloat downmix_gain = 1.0f; - ALsizei c, i; + bool DirectChannels{props->DirectChannels != AL_FALSE}; + const ChanMap *chans{nullptr}; + ALsizei num_channels{0}; + bool isbformat{false}; + ALfloat downmix_gain{1.0f}; switch(Buffer->FmtChannels) { case FmtMono: @@ -600,6 +583,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev ClearArray(params.Gains.Target); } ); + const ALsizei NumSends{Device->NumAuxSends}; std::for_each(voice->Send+0, voice->Send+NumSends, [num_channels](ALvoice::SendData &send) -> void { @@ -620,15 +604,14 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev * the first (W) channel as a normal mono sound and silence the * others. */ - ALfloat coeffs[MAX_AMBI_COEFFS]; if(Device->AvgSpeakerDist > 0.0f) { - ALfloat mdist = Distance * Listener.Params.MetersPerUnit; - ALfloat w0 = SPEEDOFSOUNDMETRESPERSEC / - (mdist * (ALfloat)Device->Frequency); - ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / - (Device->AvgSpeakerDist * (ALfloat)Device->Frequency); + const ALfloat mdist{Distance * Listener.Params.MetersPerUnit}; + const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC / + (Device->AvgSpeakerDist * (ALfloat)Device->Frequency)}; + ALfloat w0{SPEEDOFSOUNDMETRESPERSEC / + (mdist * (ALfloat)Device->Frequency)}; /* Clamp w0 for really close distances, to prevent excessive * bass. */ @@ -647,16 +630,16 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev * moved to +/-90 degrees for direct right and left speaker * responses. */ + ALfloat coeffs[MAX_AMBI_COEFFS]; CalcAngleCoeffs((Device->Render_Mode==StereoPair) ? ScaleAzimuthFront(Azi, 1.5f) : Azi, Elev, Spread, coeffs); /* NOTE: W needs to be scaled by sqrt(2) due to FuMa normalization. */ ComputePanGains(&Device->Dry, coeffs, DryGain*SQRTF_2, - voice->Direct.Params[0].Gains.Target); - for(i = 0;i < NumSends;i++) + voice->Direct.Params[0].Gains.Target); + for(ALsizei i{0};i < NumSends;i++) { - const ALeffectslot *Slot = SendSlots[i]; - if(Slot) + if(const ALeffectslot *Slot{SendSlots[i]}) ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, WetGain[i]*SQRTF_2, voice->Send[i].Params[0].Gains.Target ); @@ -664,12 +647,6 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev } else { - /* Local B-Format sources have their XYZ channels rotated according - * to the orientation. - */ - ALfloat N[3], V[3], U[3]; - aluMatrixf matrix; - if(Device->AvgSpeakerDist > 0.0f) { /* NOTE: The NFCtrlFilters were created with a w0 of 0, which @@ -685,14 +662,15 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev voice->Flags |= VOICE_HAS_NFC; } + /* Local B-Format sources have their XYZ channels rotated according + * to the orientation. + */ /* AT then UP */ - N[0] = props->Orientation[0][0]; - N[1] = props->Orientation[0][1]; - N[2] = props->Orientation[0][2]; + ALfloat N[3]{ props->Orientation[0][0], props->Orientation[0][1], + props->Orientation[0][2] }; aluNormalize(N); - V[0] = props->Orientation[1][0]; - V[1] = props->Orientation[1][1]; - V[2] = props->Orientation[1][2]; + ALfloat V[3]{ props->Orientation[1][0], props->Orientation[1][1], + props->Orientation[1][2] }; aluNormalize(V); if(!props->HeadRelative) { @@ -701,6 +679,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev aluMatrixfFloat3(V, 0.0f, lmatrix); } /* Build and normalize right-vector */ + ALfloat U[3]; aluCrossproduct(N, V, U); aluNormalize(U); @@ -708,6 +687,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev * matrix is transposed, for the inputs to align on the rows and * outputs on the columns. */ + aluMatrixf matrix; aluMatrixfSet(&matrix, // ACN0 ACN1 ACN2 ACN3 SQRTF_2, 0.0f, 0.0f, 0.0f, // Ambi W @@ -718,19 +698,16 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev voice->Direct.Buffer = Device->FOAOut.Buffer; voice->Direct.Channels = Device->FOAOut.NumChannels; - for(c = 0;c < num_channels;c++) + for(ALsizei c{0};c < num_channels;c++) ComputePanGains(&Device->FOAOut, matrix.m[c], DryGain, voice->Direct.Params[c].Gains.Target); - for(i = 0;i < NumSends;i++) + for(ALsizei i{0};i < NumSends;i++) { - const ALeffectslot *Slot = SendSlots[i]; - if(Slot) - { - for(c = 0;c < num_channels;c++) - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, - matrix.m[c], WetGain[i], voice->Send[i].Params[c].Gains.Target + if(const ALeffectslot *Slot{SendSlots[i]}) + for(ALsizei c{0};c < num_channels;c++) + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, matrix.m[c], + WetGain[i], voice->Send[i].Params[c].Gains.Target ); - } } } } @@ -742,26 +719,25 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev voice->Direct.Buffer = Device->RealOut.Buffer; voice->Direct.Channels = Device->RealOut.NumChannels; - for(c = 0;c < num_channels;c++) + for(ALsizei c{0};c < num_channels;c++) { - int idx = GetChannelIdxByName(&Device->RealOut, chans[c].channel); + int idx{GetChannelIdxByName(&Device->RealOut, chans[c].channel)}; if(idx != -1) voice->Direct.Params[c].Gains.Target[idx] = DryGain; } /* Auxiliary sends still use normal channel panning since they mix to * B-Format, which can't channel-match. */ - for(c = 0;c < num_channels;c++) + for(ALsizei c{0};c < num_channels;c++) { ALfloat coeffs[MAX_AMBI_COEFFS]; CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); - for(i = 0;i < NumSends;i++) + for(ALsizei i{0};i < NumSends;i++) { - const ALeffectslot *Slot = SendSlots[i]; - if(Slot) - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, - coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target + if(const ALeffectslot *Slot{SendSlots[i]}) + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, + WetGain[i], voice->Send[i].Params[c].Gains.Target ); } } @@ -776,8 +752,6 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev if(Distance > FLT_EPSILON) { - ALfloat coeffs[MAX_AMBI_COEFFS]; - /* Get the HRIR coefficients and delays just once, for the given * source direction. */ @@ -787,7 +761,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev voice->Direct.Params[0].Hrtf.Target.Gain = DryGain * downmix_gain; /* Remaining channels use the same results as the first. */ - for(c = 1;c < num_channels;c++) + for(ALsizei c{1};c < num_channels;c++) { /* Skip LFE */ if(chans[c].channel != LFE) @@ -797,19 +771,18 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev /* Calculate the directional coefficients once, which apply to all * input channels of the source sends. */ + ALfloat coeffs[MAX_AMBI_COEFFS]; CalcAngleCoeffs(Azi, Elev, Spread, coeffs); - for(i = 0;i < NumSends;i++) + for(ALsizei i{0};i < NumSends;i++) { - const ALeffectslot *Slot = SendSlots[i]; - if(Slot) - for(c = 0;c < num_channels;c++) + if(const ALeffectslot *Slot{SendSlots[i]}) + for(ALsizei c{0};c < num_channels;c++) { /* Skip LFE */ if(chans[c].channel != LFE) - ComputePanningGainsBF(Slot->ChanMap, - Slot->NumChannels, coeffs, WetGain[i] * downmix_gain, - voice->Send[i].Params[c].Gains.Target + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, + WetGain[i]*downmix_gain, voice->Send[i].Params[c].Gains.Target ); } } @@ -820,15 +793,11 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev * relative location around the listener, providing "virtual * speaker" responses. */ - for(c = 0;c < num_channels;c++) + for(ALsizei c{0};c < num_channels;c++) { - ALfloat coeffs[MAX_AMBI_COEFFS]; - + /* Skip LFE */ if(chans[c].channel == LFE) - { - /* Skip LFE */ continue; - } /* Get the HRIR coefficients and delays for this channel * position. @@ -841,14 +810,14 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev voice->Direct.Params[c].Hrtf.Target.Gain = DryGain; /* Normal panning for auxiliary sends. */ + ALfloat coeffs[MAX_AMBI_COEFFS]; CalcAngleCoeffs(chans[c].angle, chans[c].elevation, Spread, coeffs); - for(i = 0;i < NumSends;i++) + for(ALsizei i{0};i < NumSends;i++) { - const ALeffectslot *Slot = SendSlots[i]; - if(Slot) - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, - coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target + if(const ALeffectslot *Slot{SendSlots[i]}) + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, + WetGain[i], voice->Send[i].Params[c].Gains.Target ); } } @@ -862,38 +831,37 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev if(Distance > FLT_EPSILON) { - ALfloat coeffs[MAX_AMBI_COEFFS]; - ALfloat w0 = 0.0f; - /* Calculate NFC filter coefficient if needed. */ if(Device->AvgSpeakerDist > 0.0f) { - ALfloat mdist = Distance * Listener.Params.MetersPerUnit; - ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / - (Device->AvgSpeakerDist * (ALfloat)Device->Frequency); - w0 = SPEEDOFSOUNDMETRESPERSEC / - (mdist * (ALfloat)Device->Frequency); + const ALfloat mdist{Distance * Listener.Params.MetersPerUnit}; + const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC / + (Device->AvgSpeakerDist * (ALfloat)Device->Frequency)}; + ALfloat w0{SPEEDOFSOUNDMETRESPERSEC / + (mdist * (ALfloat)Device->Frequency)}; /* Clamp w0 for really close distances, to prevent excessive * bass. */ w0 = minf(w0, w1*4.0f); /* Adjust NFC filters. */ - for(c = 0;c < num_channels;c++) + for(ALsizei c{0};c < num_channels;c++) voice->Direct.Params[c].NFCtrlFilter.adjust(w0); - for(i = 0;i < MAX_AMBI_ORDER+1;i++) - voice->Direct.ChannelsPerOrder[i] = Device->NumChannelsPerOrder[i]; + std::copy(std::begin(Device->NumChannelsPerOrder), + std::end(Device->NumChannelsPerOrder), + std::begin(voice->Direct.ChannelsPerOrder)); voice->Flags |= VOICE_HAS_NFC; } /* Calculate the directional coefficients once, which apply to all * input channels. */ + ALfloat coeffs[MAX_AMBI_COEFFS]; CalcAngleCoeffs((Device->Render_Mode==StereoPair) ? ScaleAzimuthFront(Azi, 1.5f) : Azi, Elev, Spread, coeffs); - for(c = 0;c < num_channels;c++) + for(ALsizei c{0};c < num_channels;c++) { /* Special-case LFE */ if(chans[c].channel == LFE) @@ -910,25 +878,21 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev voice->Direct.Params[c].Gains.Target); } - for(i = 0;i < NumSends;i++) + for(ALsizei i{0};i < NumSends;i++) { - const ALeffectslot *Slot = SendSlots[i]; - if(Slot) - for(c = 0;c < num_channels;c++) + if(const ALeffectslot *Slot{SendSlots[i]}) + for(ALsizei c{0};c < num_channels;c++) { /* Skip LFE */ if(chans[c].channel != LFE) - ComputePanningGainsBF(Slot->ChanMap, - Slot->NumChannels, coeffs, WetGain[i] * downmix_gain, - voice->Send[i].Params[c].Gains.Target + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, + WetGain[i]*downmix_gain, voice->Send[i].Params[c].Gains.Target ); } } } else { - ALfloat w0 = 0.0f; - if(Device->AvgSpeakerDist > 0.0f) { /* If the source distance is 0, set w0 to w1 to act as a pass- @@ -936,21 +900,20 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev * filters so they keep an appropriate history, in case the * source moves away from the listener. */ - w0 = SPEEDOFSOUNDMETRESPERSEC / - (Device->AvgSpeakerDist * (ALfloat)Device->Frequency); + const ALfloat w0{SPEEDOFSOUNDMETRESPERSEC / + (Device->AvgSpeakerDist * (ALfloat)Device->Frequency)}; - for(c = 0;c < num_channels;c++) + for(ALsizei c{0};c < num_channels;c++) voice->Direct.Params[c].NFCtrlFilter.adjust(w0); - for(i = 0;i < MAX_AMBI_ORDER+1;i++) - voice->Direct.ChannelsPerOrder[i] = Device->NumChannelsPerOrder[i]; + std::copy(std::begin(Device->NumChannelsPerOrder), + std::end(Device->NumChannelsPerOrder), + std::begin(voice->Direct.ChannelsPerOrder)); voice->Flags |= VOICE_HAS_NFC; } - for(c = 0;c < num_channels;c++) + for(ALsizei c{0};c < num_channels;c++) { - ALfloat coeffs[MAX_AMBI_COEFFS]; - /* Special-case LFE */ if(chans[c].channel == LFE) { @@ -962,6 +925,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev continue; } + ALfloat coeffs[MAX_AMBI_COEFFS]; CalcAngleCoeffs( (Device->Render_Mode==StereoPair) ? ScaleAzimuthFront(chans[c].angle, 3.0f) : chans[c].angle, @@ -969,11 +933,10 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev ); ComputePanGains(&Device->Dry, coeffs, DryGain, - voice->Direct.Params[c].Gains.Target); - for(i = 0;i < NumSends;i++) + voice->Direct.Params[c].Gains.Target); + for(ALsizei i{0};i < NumSends;i++) { - const ALeffectslot *Slot = SendSlots[i]; - if(Slot) + if(const ALeffectslot *Slot{SendSlots[i]}) ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target ); @@ -982,11 +945,12 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev } } + const auto Frequency = static_cast(Device->Frequency); { - ALfloat hfScale = props->Direct.HFReference / Frequency; - ALfloat lfScale = props->Direct.LFReference / Frequency; - ALfloat gainHF = maxf(DryGainHF, 0.001f); /* Limit -60dB */ - ALfloat gainLF = maxf(DryGainLF, 0.001f); + const ALfloat hfScale{props->Direct.HFReference / Frequency}; + const ALfloat lfScale{props->Direct.LFReference / Frequency}; + const ALfloat gainHF{maxf(DryGainHF, 0.001f)}; /* Limit -60dB */ + const ALfloat gainLF{maxf(DryGainLF, 0.001f)}; voice->Direct.FilterType = AF_None; if(gainHF != 1.0f) voice->Direct.FilterType |= AF_LowPass; @@ -997,18 +961,18 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev voice->Direct.Params[0].HighPass.setParams(BiquadType::LowShelf, gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) ); - for(c = 1;c < num_channels;c++) + for(ALsizei c{1};c < num_channels;c++) { voice->Direct.Params[c].LowPass.copyParamsFrom(voice->Direct.Params[0].LowPass); voice->Direct.Params[c].HighPass.copyParamsFrom(voice->Direct.Params[0].HighPass); } } - for(i = 0;i < NumSends;i++) + for(ALsizei i{0};i < NumSends;i++) { - ALfloat hfScale = props->Send[i].HFReference / Frequency; - ALfloat lfScale = props->Send[i].LFReference / Frequency; - ALfloat gainHF = maxf(WetGainHF[i], 0.001f); - ALfloat gainLF = maxf(WetGainLF[i], 0.001f); + const ALfloat hfScale{props->Send[i].HFReference / Frequency}; + const ALfloat lfScale{props->Send[i].LFReference / Frequency}; + const ALfloat gainHF{maxf(WetGainHF[i], 0.001f)}; + const ALfloat gainLF{maxf(WetGainLF[i], 0.001f)}; voice->Send[i].FilterType = AF_None; if(gainHF != 1.0f) voice->Send[i].FilterType |= AF_LowPass; @@ -1019,7 +983,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev voice->Send[i].Params[0].HighPass.setParams(BiquadType::LowShelf, gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) ); - for(c = 1;c < num_channels;c++) + for(ALsizei c{1};c < num_channels;c++) { voice->Send[i].Params[c].LowPass.copyParamsFrom(voice->Send[i].Params[0].LowPass); voice->Send[i].Params[c].HighPass.copyParamsFrom(voice->Send[i].Params[0].HighPass); @@ -1029,19 +993,12 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { - const ALCdevice *Device = ALContext->Device; - const ALlistener &Listener = ALContext->Listener; - ALfloat DryGain, DryGainHF, DryGainLF; - ALfloat WetGain[MAX_SENDS]; - ALfloat WetGainHF[MAX_SENDS]; - ALfloat WetGainLF[MAX_SENDS]; + const ALCdevice *Device{ALContext->Device}; ALeffectslot *SendSlots[MAX_SENDS]; - ALfloat Pitch; - ALsizei i; voice->Direct.Buffer = Device->Dry.Buffer; voice->Direct.Channels = Device->Dry.NumChannels; - for(i = 0;i < Device->NumAuxSends;i++) + for(ALsizei i{0};i < Device->NumAuxSends;i++) { SendSlots[i] = props->Send[i].Slot; if(!SendSlots[i] && i == 0) @@ -1060,7 +1017,8 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons } /* Calculate the stepping value */ - Pitch = (ALfloat)ALBuffer->Frequency/(ALfloat)Device->Frequency * props->Pitch; + const auto Pitch = static_cast(ALBuffer->Frequency) / + static_cast(Device->Frequency) * props->Pitch; if(Pitch > (ALfloat)MAX_PITCH) voice->Step = MAX_PITCH<Resampler = SelectResampler(props->Resampler); /* Calculate gains */ - DryGain = clampf(props->Gain, props->MinGain, props->MaxGain); + const ALlistener &Listener = ALContext->Listener; + ALfloat DryGain{clampf(props->Gain, props->MinGain, props->MaxGain)}; DryGain *= props->Direct.Gain * Listener.Params.Gain; DryGain = minf(DryGain, GAIN_MIX_MAX); - DryGainHF = props->Direct.GainHF; - DryGainLF = props->Direct.GainLF; - for(i = 0;i < Device->NumAuxSends;i++) + ALfloat DryGainHF{props->Direct.GainHF}; + ALfloat DryGainLF{props->Direct.GainLF}; + ALfloat WetGain[MAX_SENDS], WetGainHF[MAX_SENDS], WetGainLF[MAX_SENDS]; + for(ALsizei i{0};i < Device->NumAuxSends;i++) { WetGain[i] = clampf(props->Gain, props->MinGain, props->MaxGain); WetGain[i] *= props->Send[i].Gain * Listener.Params.Gain; @@ -1092,37 +1052,26 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { - const ALCdevice *Device = ALContext->Device; + const ALCdevice *Device{ALContext->Device}; + const ALsizei NumSends{Device->NumAuxSends}; const ALlistener &Listener = ALContext->Listener; - const ALsizei NumSends = Device->NumAuxSends; - aluVector Position, Velocity, Direction, SourceToListener; - ALfloat Distance, ClampedDist, DopplerFactor; + + /* Set mixing buffers and get send parameters. */ + voice->Direct.Buffer = Device->Dry.Buffer; + voice->Direct.Channels = Device->Dry.NumChannels; ALeffectslot *SendSlots[MAX_SENDS]; ALfloat RoomRolloff[MAX_SENDS]; ALfloat DecayDistance[MAX_SENDS]; ALfloat DecayLFDistance[MAX_SENDS]; ALfloat DecayHFDistance[MAX_SENDS]; - ALfloat DryGain, DryGainHF, DryGainLF; - ALfloat WetGain[MAX_SENDS]; - ALfloat WetGainHF[MAX_SENDS]; - ALfloat WetGainLF[MAX_SENDS]; - bool directional; - ALfloat ev, az; - ALfloat spread; - ALfloat Pitch; - ALint i; - - /* Set mixing buffers and get send parameters. */ - voice->Direct.Buffer = Device->Dry.Buffer; - voice->Direct.Channels = Device->Dry.NumChannels; - for(i = 0;i < NumSends;i++) + for(ALsizei i{0};i < NumSends;i++) { SendSlots[i] = props->Send[i].Slot; if(!SendSlots[i] && i == 0) SendSlots[i] = ALContext->DefaultSlot.get(); if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) { - SendSlots[i] = NULL; + SendSlots[i] = nullptr; RoomRolloff[i] = 0.0f; DecayDistance[i] = 0.0f; DecayLFDistance[i] = 0.0f; @@ -1165,7 +1114,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A if(!SendSlots[i]) { - voice->Send[i].Buffer = NULL; + voice->Send[i].Buffer = nullptr; voice->Send[i].Channels = 0; } else @@ -1176,6 +1125,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A } /* Transform source to listener space (convert to head relative) */ + aluVector Position, Velocity, Direction; aluVectorSet(&Position, props->Position[0], props->Position[1], props->Position[2], 1.0f); aluVectorSet(&Direction, props->Direction[0], props->Direction[1], props->Direction[2], 0.0f); aluVectorSet(&Velocity, props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f); @@ -1196,18 +1146,20 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A Velocity.v[2] += lvelocity->v[2]; } - directional = aluNormalize(Direction.v) > 0.0f; + bool directional{aluNormalize(Direction.v) > 0.0f}; + aluVector SourceToListener; SourceToListener.v[0] = -Position.v[0]; SourceToListener.v[1] = -Position.v[1]; SourceToListener.v[2] = -Position.v[2]; SourceToListener.v[3] = 0.0f; - Distance = aluNormalize(SourceToListener.v); + ALfloat Distance{aluNormalize(SourceToListener.v)}; /* Initial source gain */ - DryGain = props->Gain; - DryGainHF = 1.0f; - DryGainLF = 1.0f; - for(i = 0;i < NumSends;i++) + ALfloat DryGain{props->Gain}; + ALfloat DryGainHF{1.0f}; + ALfloat DryGainLF{1.0f}; + ALfloat WetGain[MAX_SENDS], WetGainHF[MAX_SENDS], WetGainLF[MAX_SENDS]; + for(ALsizei i{0};i < NumSends;i++) { WetGain[i] = props->Gain; WetGainHF[i] = 1.0f; @@ -1215,15 +1167,14 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A } /* Calculate distance attenuation */ - ClampedDist = Distance; + ALfloat ClampedDist{Distance}; switch(Listener.Params.SourceDistanceModel ? props->mDistanceModel : Listener.Params.mDistanceModel) { case DistanceModel::InverseClamped: ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); - if(props->MaxDistance < props->RefDistance) - break; + if(props->MaxDistance < props->RefDistance) break; /*fall-through*/ case DistanceModel::Inverse: if(!(props->RefDistance > 0.0f)) @@ -1232,7 +1183,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A { ALfloat dist = lerp(props->RefDistance, ClampedDist, props->RolloffFactor); if(dist > 0.0f) DryGain *= props->RefDistance / dist; - for(i = 0;i < NumSends;i++) + for(ALsizei i{0};i < NumSends;i++) { dist = lerp(props->RefDistance, ClampedDist, RoomRolloff[i]); if(dist > 0.0f) WetGain[i] *= props->RefDistance / dist; @@ -1242,8 +1193,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A case DistanceModel::LinearClamped: ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); - if(props->MaxDistance < props->RefDistance) - break; + if(props->MaxDistance < props->RefDistance) break; /*fall-through*/ case DistanceModel::Linear: if(!(props->MaxDistance != props->RefDistance)) @@ -1253,7 +1203,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A ALfloat attn = props->RolloffFactor * (ClampedDist-props->RefDistance) / (props->MaxDistance-props->RefDistance); DryGain *= maxf(1.0f - attn, 0.0f); - for(i = 0;i < NumSends;i++) + for(ALsizei i{0};i < NumSends;i++) { attn = RoomRolloff[i] * (ClampedDist-props->RefDistance) / (props->MaxDistance-props->RefDistance); @@ -1264,17 +1214,16 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A case DistanceModel::ExponentClamped: ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); - if(props->MaxDistance < props->RefDistance) - break; + if(props->MaxDistance < props->RefDistance) break; /*fall-through*/ case DistanceModel::Exponent: if(!(ClampedDist > 0.0f && props->RefDistance > 0.0f)) ClampedDist = props->RefDistance; else { - DryGain *= powf(ClampedDist/props->RefDistance, -props->RolloffFactor); - for(i = 0;i < NumSends;i++) - WetGain[i] *= powf(ClampedDist/props->RefDistance, -RoomRolloff[i]); + DryGain *= std::pow(ClampedDist/props->RefDistance, -props->RolloffFactor); + for(ALsizei i{0};i < NumSends;i++) + WetGain[i] *= std::pow(ClampedDist/props->RefDistance, -RoomRolloff[i]); } break; @@ -1286,12 +1235,10 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A /* Calculate directional soundcones */ if(directional && props->InnerAngle < 360.0f) { - ALfloat ConeVolume; - ALfloat ConeHF; - ALfloat Angle; - - Angle = acosf(aluDotproduct(&Direction, &SourceToListener)); + ALfloat Angle{std::acos(aluDotproduct(&Direction, &SourceToListener))}; Angle = RAD2DEG(Angle * ConeScale * 2.0f); + + ALfloat ConeVolume, ConeHF; if(!(Angle > props->InnerAngle)) { ConeVolume = 1.0f; @@ -1314,26 +1261,25 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A if(props->DryGainHFAuto) DryGainHF *= ConeHF; if(props->WetGainAuto) - { - for(i = 0;i < NumSends;i++) - WetGain[i] *= ConeVolume; - } + std::transform(std::begin(WetGain), std::begin(WetGain)+NumSends, std::begin(WetGain), + [ConeVolume](ALfloat gain) noexcept -> ALfloat { return gain * ConeVolume; } + ); if(props->WetGainHFAuto) - { - for(i = 0;i < NumSends;i++) - WetGainHF[i] *= ConeHF; - } + std::transform(std::begin(WetGainHF), std::begin(WetGainHF)+NumSends, + std::begin(WetGainHF), + [ConeHF](ALfloat gain) noexcept -> ALfloat { return gain * ConeHF; } + ); } /* Apply gain and frequency filters */ - DryGain = clampf(DryGain, props->MinGain, props->MaxGain); - DryGain = minf(DryGain*props->Direct.Gain*Listener.Params.Gain, GAIN_MIX_MAX); + DryGain = clampf(DryGain, props->MinGain, props->MaxGain); + DryGain = minf(DryGain*props->Direct.Gain*Listener.Params.Gain, GAIN_MIX_MAX); DryGainHF *= props->Direct.GainHF; DryGainLF *= props->Direct.GainLF; - for(i = 0;i < NumSends;i++) + for(ALsizei i{0};i < NumSends;i++) { - WetGain[i] = clampf(WetGain[i], props->MinGain, props->MaxGain); - WetGain[i] = minf(WetGain[i]*props->Send[i].Gain*Listener.Params.Gain, GAIN_MIX_MAX); + WetGain[i] = clampf(WetGain[i], props->MinGain, props->MaxGain); + WetGain[i] = minf(WetGain[i]*props->Send[i].Gain*Listener.Params.Gain, GAIN_MIX_MAX); WetGainHF[i] *= props->Send[i].GainHF; WetGainLF[i] *= props->Send[i].GainLF; } @@ -1341,14 +1287,16 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A /* Distance-based air absorption and initial send decay. */ if(ClampedDist > props->RefDistance && props->RolloffFactor > 0.0f) { - ALfloat meters_base = (ClampedDist-props->RefDistance) * props->RolloffFactor * - Listener.Params.MetersPerUnit; + ALfloat meters_base{(ClampedDist-props->RefDistance) * props->RolloffFactor * + Listener.Params.MetersPerUnit}; if(props->AirAbsorptionFactor > 0.0f) { - ALfloat hfattn = powf(AIRABSORBGAINHF, meters_base * props->AirAbsorptionFactor); + ALfloat hfattn{std::pow(AIRABSORBGAINHF, meters_base * props->AirAbsorptionFactor)}; DryGainHF *= hfattn; - for(i = 0;i < NumSends;i++) - WetGainHF[i] *= hfattn; + std::transform(std::begin(WetGainHF), std::begin(WetGainHF)+NumSends, + std::begin(WetGainHF), + [hfattn](ALfloat gain) noexcept -> ALfloat { return gain * hfattn; } + ); } if(props->WetGainAuto) @@ -1357,23 +1305,21 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A * source distance in meters. The initial decay of the reverb * effect is calculated and applied to the wet path. */ - for(i = 0;i < NumSends;i++) + for(ALsizei i{0};i < NumSends;i++) { - ALfloat gain, gainhf, gainlf; - if(!(DecayDistance[i] > 0.0f)) continue; - gain = powf(REVERB_DECAY_GAIN, meters_base/DecayDistance[i]); + const ALfloat gain{std::pow(REVERB_DECAY_GAIN, meters_base/DecayDistance[i])}; WetGain[i] *= gain; /* Yes, the wet path's air absorption is applied with * WetGainAuto on, rather than WetGainHFAuto. */ if(gain > 0.0f) { - gainhf = powf(REVERB_DECAY_GAIN, meters_base/DecayHFDistance[i]); + ALfloat gainhf{std::pow(REVERB_DECAY_GAIN, meters_base/DecayHFDistance[i])}; WetGainHF[i] *= minf(gainhf / gain, 1.0f); - gainlf = powf(REVERB_DECAY_GAIN, meters_base/DecayLFDistance[i]); + ALfloat gainlf{std::pow(REVERB_DECAY_GAIN, meters_base/DecayLFDistance[i])}; WetGainLF[i] *= minf(gainlf / gain, 1.0f); } } @@ -1382,19 +1328,17 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A /* Initial source pitch */ - Pitch = props->Pitch; + ALfloat Pitch{props->Pitch}; /* Calculate velocity-based doppler effect */ - DopplerFactor = props->DopplerFactor * Listener.Params.DopplerFactor; + ALfloat DopplerFactor{props->DopplerFactor * Listener.Params.DopplerFactor}; if(DopplerFactor > 0.0f) { const aluVector *lvelocity = &Listener.Params.Velocity; - const ALfloat SpeedOfSound = Listener.Params.SpeedOfSound; - ALfloat vss, vls; - - vss = aluDotproduct(&Velocity, &SourceToListener) * DopplerFactor; - vls = aluDotproduct(lvelocity, &SourceToListener) * DopplerFactor; + ALfloat vss{aluDotproduct(&Velocity, &SourceToListener) * DopplerFactor}; + ALfloat vls{aluDotproduct(lvelocity, &SourceToListener) * DopplerFactor}; + const ALfloat SpeedOfSound{Listener.Params.SpeedOfSound}; if(!(vls < SpeedOfSound)) { /* Listener moving away from the source at the speed of sound. @@ -1432,27 +1376,25 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A BsincPrepare(voice->Step, &voice->ResampleState.bsinc, &bsinc12); voice->Resampler = SelectResampler(props->Resampler); + ALfloat ev{0.0f}, az{0.0f}; if(Distance > 0.0f) { /* Clamp Y, in case rounding errors caused it to end up outside of * -1...+1. */ - ev = asinf(clampf(-SourceToListener.v[1], -1.0f, 1.0f)); + ev = std::asin(clampf(-SourceToListener.v[1], -1.0f, 1.0f)); /* Double negation on Z cancels out; negate once for changing source- * to-listener to listener-to-source, and again for right-handed coords * with -Z in front. */ - az = atan2f(-SourceToListener.v[0], SourceToListener.v[2]*ZScale); + az = std::atan2(-SourceToListener.v[0], SourceToListener.v[2]*ZScale); } - else - ev = az = 0.0f; + ALfloat spread{0.0f}; if(props->Radius > Distance) spread = F_TAU - Distance/props->Radius*F_PI; else if(Distance > 0.0f) - spread = asinf(props->Radius / Distance) * 2.0f; - else - spread = 0.0f; + spread = std::asin(props->Radius/Distance) * 2.0f; CalcPanningAndFilters(voice, az, ev, Distance, spread, DryGain, DryGainHF, DryGainLF, WetGain, WetGainLF, WetGainHF, SendSlots, ALBuffer, props, Listener, Device); @@ -1480,8 +1422,8 @@ void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) ); if(LIKELY(buffer != buffers_end)) { - if(voice->Props.SpatializeMode == SpatializeOn || - (voice->Props.SpatializeMode == SpatializeAuto && (*buffer)->FmtChannels == FmtMono)) + if(voice->Props.SpatializeMode==SpatializeOn || + (voice->Props.SpatializeMode==SpatializeAuto && (*buffer)->FmtChannels==FmtMono)) CalcAttnSourceParams(voice, &voice->Props, *buffer, context); else CalcNonAttnSourceParams(voice, &voice->Props, *buffer, context); @@ -1497,8 +1439,8 @@ void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray *slots) IncrementRef(&ctx->UpdateCount); if(LIKELY(!ctx->HoldUpdates.load(std::memory_order_acquire))) { - bool cforce = CalcContextParams(ctx); - bool force = CalcListenerParams(ctx) | cforce; + bool cforce{CalcContextParams(ctx)}; + bool force{CalcListenerParams(ctx) || cforce}; std::for_each(slots->slot, slots->slot+slots->count, [ctx,cforce,&force](ALeffectslot *slot) -> void { force |= CalcEffectSlotParams(slot, ctx, cforce); } @@ -1565,31 +1507,26 @@ void ProcessContext(ALCcontext *ctx, ALsizei SamplesToDo) void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*RESTRICT Buffer)[BUFFERSIZE], int lidx, int ridx, int cidx, ALsizei SamplesToDo, ALsizei NumChannels) { - ALfloat (*RESTRICT lsplit)[BUFFERSIZE] = Stablizer->LSplit; - ALfloat (*RESTRICT rsplit)[BUFFERSIZE] = Stablizer->RSplit; - ALsizei i; - /* Apply an all-pass to all channels, except the front-left and front- * right, so they maintain the same relative phase. */ - for(i = 0;i < NumChannels;i++) + for(ALsizei i{0};i < NumChannels;i++) { if(i == lidx || i == ridx) continue; Stablizer->APFilter[i].process(Buffer[i], SamplesToDo); } + ALfloat (*RESTRICT lsplit)[BUFFERSIZE]{Stablizer->LSplit}; + ALfloat (*RESTRICT rsplit)[BUFFERSIZE]{Stablizer->RSplit}; Stablizer->LFilter.process(lsplit[1], lsplit[0], Buffer[lidx], SamplesToDo); Stablizer->RFilter.process(rsplit[1], rsplit[0], Buffer[ridx], SamplesToDo); - for(i = 0;i < SamplesToDo;i++) + for(ALsizei i{0};i < SamplesToDo;i++) { - ALfloat lfsum, hfsum; - ALfloat m, s, c; - - lfsum = lsplit[0][i] + rsplit[0][i]; - hfsum = lsplit[1][i] + rsplit[1][i]; - s = lsplit[0][i] + lsplit[1][i] - rsplit[0][i] - rsplit[1][i]; + ALfloat lfsum{lsplit[0][i] + rsplit[0][i]}; + ALfloat hfsum{lsplit[1][i] + rsplit[1][i]}; + ALfloat s{lsplit[0][i] + lsplit[1][i] - rsplit[0][i] - rsplit[1][i]}; /* This pans the separate low- and high-frequency sums between being on * the center channel and the left/right channels. The low-frequency @@ -1597,8 +1534,8 @@ void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*RESTRICT Buffer)[BUFFER * frequency sum is 1/4th toward center (3/4ths on left/right). These * values can be tweaked. */ - m = lfsum*cosf(1.0f/3.0f * F_PI_2) + hfsum*cosf(1.0f/4.0f * F_PI_2); - c = lfsum*sinf(1.0f/3.0f * F_PI_2) + hfsum*sinf(1.0f/4.0f * F_PI_2); + ALfloat m{lfsum*std::cos(1.0f/3.0f * F_PI_2) + hfsum*std::cos(1.0f/4.0f * F_PI_2)}; + ALfloat c{lfsum*std::sin(1.0f/3.0f * F_PI_2) + hfsum*std::sin(1.0f/4.0f * F_PI_2)}; /* The generated center channel signal adds to the existing signal, * while the modified left and right channels replace. @@ -1614,10 +1551,10 @@ void ApplyDistanceComp(ALfloat (*RESTRICT Samples)[BUFFERSIZE], const DistanceCo { for(ALsizei c{0};c < numchans;c++) { - ALfloat *RESTRICT inout = Samples[c]; - const ALfloat gain = distcomp[c].Gain; - const ALsizei base = distcomp[c].Length; - ALfloat *RESTRICT distbuf = distcomp[c].Buffer; + ALfloat *RESTRICT inout{Samples[c]}; + const ALfloat gain{distcomp[c].Gain}; + const ALsizei base{distcomp[c].Length}; + ALfloat *RESTRICT distbuf{distcomp[c].Buffer}; if(base == 0) { @@ -1642,8 +1579,7 @@ void ApplyDistanceComp(ALfloat (*RESTRICT Samples)[BUFFERSIZE], const DistanceCo std::copy_n(inout, SamplesToDo, out); } std::transform(Values, Values+SamplesToDo, inout, - [gain](ALfloat in) noexcept -> ALfloat - { return in * gain; } + [gain](ALfloat in) noexcept -> ALfloat { return in * gain; } ); } } @@ -1657,8 +1593,8 @@ void ApplyDither(ALfloat (*RESTRICT Samples)[BUFFERSIZE], ALuint *dither_seed, * between -1 and +1) and add it to the sample values, after scaling up to * the desired quantization depth amd before rounding. */ - const ALfloat invscale = 1.0f / quant_scale; - ALuint seed = *dither_seed; + const ALfloat invscale{1.0f / quant_scale}; + ALuint seed{*dither_seed}; auto dither_channel = [&seed,invscale,quant_scale,SamplesToDo](ALfloat *buffer) -> void { ASSUME(SamplesToDo > 0); @@ -1709,8 +1645,8 @@ template<> inline ALubyte SampleConv(ALfloat val) noexcept { return SampleConv(val) + 128; } template -void Write(const ALfloat (*RESTRICT InBuffer)[BUFFERSIZE], ALvoid *OutBuffer, - ALsizei Offset, ALsizei SamplesToDo, ALsizei numchans) +void Write(const ALfloat (*InBuffer)[BUFFERSIZE], ALvoid *OutBuffer, ALsizei Offset, + ALsizei SamplesToDo, ALsizei numchans) { using SampleType = typename DevFmtTypeTraits::Type; @@ -1781,9 +1717,9 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) /* Apply front image stablization for surround sound, if applicable. */ if(device->Stablizer) { - int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); - int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); - int cidx = GetChannelIdxByName(&device->RealOut, FrontCenter); + const int lidx{GetChannelIdxByName(&device->RealOut, FrontLeft)}; + const int ridx{GetChannelIdxByName(&device->RealOut, FrontRight)}; + const int cidx{GetChannelIdxByName(&device->RealOut, FrontCenter)}; assert(lidx >= 0 && ridx >= 0 && cidx >= 0); ApplyStablizer(device->Stablizer.get(), device->RealOut.Buffer, lidx, ridx, cidx, @@ -1807,8 +1743,8 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) if(LIKELY(OutBuffer)) { - ALfloat (*Buffer)[BUFFERSIZE] = device->RealOut.Buffer; - ALsizei Channels = device->RealOut.NumChannels; + ALfloat (*Buffer)[BUFFERSIZE]{device->RealOut.Buffer}; + ALsizei Channels{device->RealOut.NumChannels}; /* Finally, interleave and convert samples, writing to the device's * output buffer. @@ -1854,7 +1790,7 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) ALCcontext *ctx{device->ContextList.load()}; while(ctx) { - ALbitfieldSOFT enabledevt = ctx->EnabledEvts.load(std::memory_order_acquire); + const ALbitfieldSOFT enabledevt{ctx->EnabledEvts.load(std::memory_order_acquire)}; if((enabledevt&EventType_Disconnected) && ll_ringbuffer_write(ctx->AsyncEvents, &evt, 1) == 1) ctx->EventSem.post(); -- cgit v1.2.3 From 5a283c66eef69f5fd573d55f2411703968355eac Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 12 Dec 2018 04:22:11 -0800 Subject: Use proper classes for Vector and Matrix types --- Alc/alc.cpp | 4 +- Alc/alu.cpp | 162 +++++++++++++++++------------------------- Alc/effects/autowah.cpp | 2 +- Alc/effects/compressor.cpp | 3 +- Alc/effects/equalizer.cpp | 2 +- Alc/effects/modulator.cpp | 2 +- Alc/effects/reverb.cpp | 82 ++++++++++----------- OpenAL32/Include/alListener.h | 4 +- common/vecmat.cpp | 8 --- common/vecmat.h | 120 ++++++++++++++++++++++--------- 10 files changed, 199 insertions(+), 190 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 424a0eaa..3ccf545a 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2425,8 +2425,8 @@ static ALvoid InitContext(ALCcontext *Context) Context->ExtensionList = alExtList; - listener.Params.Matrix = aluMatrixf::Identity; - aluVectorSet(&listener.Params.Velocity, 0.0f, 0.0f, 0.0f, 0.0f); + listener.Params.Matrix = alu::Matrix::Identity(); + listener.Params.Velocity = alu::Vector{}; listener.Params.Gain = listener.Gain; listener.Params.MetersPerUnit = Context->MetersPerUnit; listener.Params.DopplerFactor = Context->DopplerFactor; diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 37d23c60..75504af5 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -260,50 +260,30 @@ inline ALuint dither_rng(ALuint *seed) noexcept } -inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector) +inline alu::Vector aluCrossproduct(const alu::Vector &in1, const alu::Vector &in2) { - outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1]; - outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2]; - outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0]; + return alu::Vector{ + in1[1]*in2[2] - in1[2]*in2[1], + in1[2]*in2[0] - in1[0]*in2[2], + in1[0]*in2[1] - in1[1]*in2[0], + 0.0f + }; } -inline ALfloat aluDotproduct(const aluVector *vec1, const aluVector *vec2) +inline ALfloat aluDotproduct(const alu::Vector &vec1, const alu::Vector &vec2) { - return vec1->v[0]*vec2->v[0] + vec1->v[1]*vec2->v[1] + vec1->v[2]*vec2->v[2]; + return vec1[0]*vec2[0] + vec1[1]*vec2[1] + vec1[2]*vec2[2]; } -ALfloat aluNormalize(ALfloat *vec) -{ - const ALfloat length{std::sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2])}; - if(length > FLT_EPSILON) - { - ALfloat inv_length = 1.0f/length; - vec[0] *= inv_length; - vec[1] *= inv_length; - vec[2] *= inv_length; - return length; - } - vec[0] = vec[1] = vec[2] = 0.0f; - return 0.0f; -} -void aluMatrixfFloat3(ALfloat *vec, ALfloat w, const aluMatrixf *mtx) +alu::Vector operator*(const alu::Matrix &mtx, const alu::Vector &vec) noexcept { - const ALfloat v[4]{ vec[0], vec[1], vec[2], w }; - - vec[0] = v[0]*mtx->m[0][0] + v[1]*mtx->m[1][0] + v[2]*mtx->m[2][0] + v[3]*mtx->m[3][0]; - vec[1] = v[0]*mtx->m[0][1] + v[1]*mtx->m[1][1] + v[2]*mtx->m[2][1] + v[3]*mtx->m[3][1]; - vec[2] = v[0]*mtx->m[0][2] + v[1]*mtx->m[1][2] + v[2]*mtx->m[2][2] + v[3]*mtx->m[3][2]; -} - -aluVector aluMatrixfVector(const aluMatrixf *mtx, const aluVector *vec) -{ - aluVector v; - v.v[0] = vec->v[0]*mtx->m[0][0] + vec->v[1]*mtx->m[1][0] + vec->v[2]*mtx->m[2][0] + vec->v[3]*mtx->m[3][0]; - v.v[1] = vec->v[0]*mtx->m[0][1] + vec->v[1]*mtx->m[1][1] + vec->v[2]*mtx->m[2][1] + vec->v[3]*mtx->m[3][1]; - v.v[2] = vec->v[0]*mtx->m[0][2] + vec->v[1]*mtx->m[1][2] + vec->v[2]*mtx->m[2][2] + vec->v[3]*mtx->m[3][2]; - v.v[3] = vec->v[0]*mtx->m[0][3] + vec->v[1]*mtx->m[1][3] + vec->v[2]*mtx->m[2][3] + vec->v[3]*mtx->m[3][3]; - return v; + return alu::Vector{ + vec[0]*mtx[0][0] + vec[1]*mtx[1][0] + vec[2]*mtx[2][0] + vec[3]*mtx[3][0], + vec[0]*mtx[0][1] + vec[1]*mtx[1][1] + vec[2]*mtx[2][1] + vec[3]*mtx[3][1], + vec[0]*mtx[0][2] + vec[1]*mtx[1][2] + vec[2]*mtx[2][2] + vec[3]*mtx[3][2], + vec[0]*mtx[0][3] + vec[1]*mtx[1][3] + vec[2]*mtx[2][3] + vec[3]*mtx[3][3] + }; } @@ -350,29 +330,27 @@ bool CalcListenerParams(ALCcontext *Context) if(!props) return false; /* AT then UP */ - ALfloat N[3]{ props->Forward[0], props->Forward[1], props->Forward[2] }; - aluNormalize(N); - ALfloat V[3]{ props->Up[0], props->Up[1], props->Up[2] }; - aluNormalize(V); + alu::Vector N{props->Forward[0], props->Forward[1], props->Forward[2], 0.0f}; + N.normalize(); + alu::Vector V{props->Up[0], props->Up[1], props->Up[2], 0.0f}; + V.normalize(); /* Build and normalize right-vector */ - ALfloat U[3]; - aluCrossproduct(N, V, U); - aluNormalize(U); - - aluMatrixfSet(&Listener.Params.Matrix, - U[0], V[0], -N[0], 0.0, - U[1], V[1], -N[1], 0.0, - U[2], V[2], -N[2], 0.0, - 0.0, 0.0, 0.0, 1.0 - ); + alu::Vector U{aluCrossproduct(N, V)}; + U.normalize(); + + Listener.Params.Matrix = alu::Matrix{ + U[0], V[0], -N[0], 0.0f, + U[1], V[1], -N[1], 0.0f, + U[2], V[2], -N[2], 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; - ALfloat P[3]{ props->Position[0], props->Position[1], props->Position[2] }; - aluMatrixfFloat3(P, 1.0, &Listener.Params.Matrix); - aluMatrixfSetRow(&Listener.Params.Matrix, 3, -P[0], -P[1], -P[2], 1.0f); + alu::Vector P{props->Position[0], props->Position[1], props->Position[2], 1.0f}; + P = Listener.Params.Matrix * P; + Listener.Params.Matrix.setRow(3, -P[0], -P[1], -P[2], 1.0f); - aluVector vel; - aluVectorSet(&vel, props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f); - Listener.Params.Velocity = aluMatrixfVector(&Listener.Params.Matrix, &vel); + alu::Vector vel{props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f}; + Listener.Params.Velocity = Listener.Params.Matrix * vel; Listener.Params.Gain = props->Gain * Context->GainBoost; @@ -666,46 +644,43 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev * to the orientation. */ /* AT then UP */ - ALfloat N[3]{ props->Orientation[0][0], props->Orientation[0][1], - props->Orientation[0][2] }; - aluNormalize(N); - ALfloat V[3]{ props->Orientation[1][0], props->Orientation[1][1], - props->Orientation[1][2] }; - aluNormalize(V); + alu::Vector N{props->Orientation[0][0], props->Orientation[0][1], + props->Orientation[0][2], 0.0f}; + N.normalize(); + alu::Vector V{props->Orientation[1][0], props->Orientation[1][1], + props->Orientation[1][2], 0.0f}; + V.normalize(); if(!props->HeadRelative) { - const aluMatrixf *lmatrix = &Listener.Params.Matrix; - aluMatrixfFloat3(N, 0.0f, lmatrix); - aluMatrixfFloat3(V, 0.0f, lmatrix); + N = Listener.Params.Matrix * N; + V = Listener.Params.Matrix * V; } /* Build and normalize right-vector */ - ALfloat U[3]; - aluCrossproduct(N, V, U); - aluNormalize(U); + alu::Vector U{aluCrossproduct(N, V)}; + U.normalize(); /* Build a rotate + conversion matrix (FuMa -> ACN+N3D). NOTE: This * matrix is transposed, for the inputs to align on the rows and * outputs on the columns. */ - aluMatrixf matrix; - aluMatrixfSet(&matrix, + const alu::Matrix matrix{ // ACN0 ACN1 ACN2 ACN3 SQRTF_2, 0.0f, 0.0f, 0.0f, // Ambi W 0.0f, -N[0]*SQRTF_3, N[1]*SQRTF_3, -N[2]*SQRTF_3, // Ambi X 0.0f, U[0]*SQRTF_3, -U[1]*SQRTF_3, U[2]*SQRTF_3, // Ambi Y 0.0f, -V[0]*SQRTF_3, V[1]*SQRTF_3, -V[2]*SQRTF_3 // Ambi Z - ); + }; voice->Direct.Buffer = Device->FOAOut.Buffer; voice->Direct.Channels = Device->FOAOut.NumChannels; for(ALsizei c{0};c < num_channels;c++) - ComputePanGains(&Device->FOAOut, matrix.m[c], DryGain, + ComputePanGains(&Device->FOAOut, matrix[c].data(), DryGain, voice->Direct.Params[c].Gains.Target); for(ALsizei i{0};i < NumSends;i++) { if(const ALeffectslot *Slot{SendSlots[i]}) for(ALsizei c{0};c < num_channels;c++) - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, matrix.m[c], + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, matrix[c].data(), WetGain[i], voice->Send[i].Params[c].Gains.Target ); } @@ -1125,34 +1100,25 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A } /* Transform source to listener space (convert to head relative) */ - aluVector Position, Velocity, Direction; - aluVectorSet(&Position, props->Position[0], props->Position[1], props->Position[2], 1.0f); - aluVectorSet(&Direction, props->Direction[0], props->Direction[1], props->Direction[2], 0.0f); - aluVectorSet(&Velocity, props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f); + alu::Vector Position{props->Position[0], props->Position[1], props->Position[2], 1.0f}; + alu::Vector Velocity{props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f}; + alu::Vector Direction{props->Direction[0], props->Direction[1], props->Direction[2], 0.0f}; if(props->HeadRelative == AL_FALSE) { - const aluMatrixf *Matrix = &Listener.Params.Matrix; /* Transform source vectors */ - Position = aluMatrixfVector(Matrix, &Position); - Velocity = aluMatrixfVector(Matrix, &Velocity); - Direction = aluMatrixfVector(Matrix, &Direction); + Position = Listener.Params.Matrix * Position; + Velocity = Listener.Params.Matrix * Velocity; + Direction = Listener.Params.Matrix * Direction; } else { - const aluVector *lvelocity = &Listener.Params.Velocity; /* Offset the source velocity to be relative of the listener velocity */ - Velocity.v[0] += lvelocity->v[0]; - Velocity.v[1] += lvelocity->v[1]; - Velocity.v[2] += lvelocity->v[2]; + Velocity += Listener.Params.Velocity; } - bool directional{aluNormalize(Direction.v) > 0.0f}; - aluVector SourceToListener; - SourceToListener.v[0] = -Position.v[0]; - SourceToListener.v[1] = -Position.v[1]; - SourceToListener.v[2] = -Position.v[2]; - SourceToListener.v[3] = 0.0f; - ALfloat Distance{aluNormalize(SourceToListener.v)}; + const bool directional{Direction.normalize() > 0.0f}; + alu::Vector SourceToListener{-Position[0], -Position[1], -Position[2], 0.0f}; + const ALfloat Distance{SourceToListener.normalize()}; /* Initial source gain */ ALfloat DryGain{props->Gain}; @@ -1235,7 +1201,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A /* Calculate directional soundcones */ if(directional && props->InnerAngle < 360.0f) { - ALfloat Angle{std::acos(aluDotproduct(&Direction, &SourceToListener))}; + ALfloat Angle{std::acos(aluDotproduct(Direction, SourceToListener))}; Angle = RAD2DEG(Angle * ConeScale * 2.0f); ALfloat ConeVolume, ConeHF; @@ -1334,9 +1300,9 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A ALfloat DopplerFactor{props->DopplerFactor * Listener.Params.DopplerFactor}; if(DopplerFactor > 0.0f) { - const aluVector *lvelocity = &Listener.Params.Velocity; - ALfloat vss{aluDotproduct(&Velocity, &SourceToListener) * DopplerFactor}; - ALfloat vls{aluDotproduct(lvelocity, &SourceToListener) * DopplerFactor}; + const alu::Vector &lvelocity = Listener.Params.Velocity; + ALfloat vss{aluDotproduct(Velocity, SourceToListener) * DopplerFactor}; + ALfloat vls{aluDotproduct(lvelocity, SourceToListener) * DopplerFactor}; const ALfloat SpeedOfSound{Listener.Params.SpeedOfSound}; if(!(vls < SpeedOfSound)) @@ -1382,12 +1348,12 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A /* Clamp Y, in case rounding errors caused it to end up outside of * -1...+1. */ - ev = std::asin(clampf(-SourceToListener.v[1], -1.0f, 1.0f)); + ev = std::asin(clampf(-SourceToListener[1], -1.0f, 1.0f)); /* Double negation on Z cancels out; negate once for changing source- * to-listener to listener-to-source, and again for right-handed coords * with -Z in front. */ - az = std::atan2(-SourceToListener.v[0], SourceToListener.v[2]*ZScale); + az = std::atan2(-SourceToListener[0], SourceToListener[2]*ZScale); } ALfloat spread{0.0f}; diff --git a/Alc/effects/autowah.cpp b/Alc/effects/autowah.cpp index 8e789652..19c247a9 100644 --- a/Alc/effects/autowah.cpp +++ b/Alc/effects/autowah.cpp @@ -122,7 +122,7 @@ void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, mOutBuffer = device->FOAOut.Buffer; mOutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain, + ComputePanGains(&device->FOAOut, alu::Matrix::Identity()[i].data(), slot->Params.Gain, mChans[i].TargetGains); } diff --git a/Alc/effects/compressor.cpp b/Alc/effects/compressor.cpp index c8bdef15..31210264 100644 --- a/Alc/effects/compressor.cpp +++ b/Alc/effects/compressor.cpp @@ -81,7 +81,8 @@ void ALcompressorState::update(const ALCcontext *context, const ALeffectslot *sl mOutBuffer = device->FOAOut.Buffer; mOutChannels = device->FOAOut.NumChannels; for(ALsizei i{0};i < 4;i++) - ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain, mGain[i]); + ComputePanGains(&device->FOAOut, alu::Matrix::Identity()[i].data(), + slot->Params.Gain, mGain[i]); } void ALcompressorState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index 85c0882c..2c46c2f3 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -155,7 +155,7 @@ void ALequalizerState::update(const ALCcontext *context, const ALeffectslot *slo mOutBuffer = device->FOAOut.Buffer; mOutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain, + ComputePanGains(&device->FOAOut, alu::Matrix::Identity()[i].data(), slot->Params.Gain, mChans[i].TargetGains); } diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index 3d41bb65..bf584898 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -134,7 +134,7 @@ void ALmodulatorState::update(const ALCcontext *context, const ALeffectslot *slo mOutBuffer = device->FOAOut.Buffer; mOutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&device->FOAOut, aluMatrixf::Identity.m[i], slot->Params.Gain, + ComputePanGains(&device->FOAOut, alu::Matrix::Identity()[i].data(), slot->Params.Gain, mChans[i].TargetGains); } diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index b5e6dd94..70324dad 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -68,20 +68,20 @@ ALfloat ReverbBoost = 1.0f; * tetrahedron, but it's close enough. Should the model be extended to 8-lines * in the future, true opposites can be used. */ -static const aluMatrixf B2A = {{ - { 0.288675134595f, 0.288675134595f, 0.288675134595f, 0.288675134595f }, - { 0.288675134595f, -0.288675134595f, -0.288675134595f, 0.288675134595f }, - { 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f }, - { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f } -}}; +static constexpr alu::Matrix B2A{ + 0.288675134595f, 0.288675134595f, 0.288675134595f, 0.288675134595f, + 0.288675134595f, -0.288675134595f, -0.288675134595f, 0.288675134595f, + 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f, + 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f +}; /* Converts A-Format to B-Format. */ -static const aluMatrixf A2B = {{ - { 0.866025403785f, 0.866025403785f, 0.866025403785f, 0.866025403785f }, - { 0.866025403785f, -0.866025403785f, 0.866025403785f, -0.866025403785f }, - { 0.866025403785f, -0.866025403785f, -0.866025403785f, 0.866025403785f }, - { 0.866025403785f, 0.866025403785f, -0.866025403785f, -0.866025403785f } -}}; +static constexpr alu::Matrix A2B{ + 0.866025403785f, 0.866025403785f, 0.866025403785f, 0.866025403785f, + 0.866025403785f, -0.866025403785f, 0.866025403785f, -0.866025403785f, + 0.866025403785f, -0.866025403785f, -0.866025403785f, 0.866025403785f, + 0.866025403785f, 0.866025403785f, -0.866025403785f, -0.866025403785f +}; static const ALfloat FadeStep = 1.0f / FADE_SAMPLES; @@ -755,12 +755,8 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co * focal strength. This function results in a B-Format transformation matrix * that spatially focuses the signal in the desired direction. */ -static aluMatrixf GetTransformFromVector(const ALfloat *vec) +static alu::Matrix GetTransformFromVector(const ALfloat *vec) { - aluMatrixf focus; - ALfloat norm[3]; - ALfloat mag; - /* Normalize the panning vector according to the N3D scale, which has an * extra sqrt(3) term on the directional components. Converting from OpenAL * to B-Format also requires negating X (ACN 1) and Z (ACN 3). Note however @@ -768,7 +764,8 @@ static aluMatrixf GetTransformFromVector(const ALfloat *vec) * rest of OpenAL which use right-handed. This is fixed by negating Z, * which cancels out with the B-Format Z negation. */ - mag = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); + ALfloat norm[3]; + ALfloat mag{sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2])}; if(mag > 1.0f) { norm[0] = vec[0] / mag * -SQRTF_3; @@ -787,50 +784,47 @@ static aluMatrixf GetTransformFromVector(const ALfloat *vec) norm[2] = vec[2] * SQRTF_3; } - aluMatrixfSet(&focus, + return alu::Matrix{ 1.0f, 0.0f, 0.0f, 0.0f, norm[0], 1.0f-mag, 0.0f, 0.0f, norm[1], 0.0f, 1.0f-mag, 0.0f, norm[2], 0.0f, 0.0f, 1.0f-mag - ); - - return focus; + }; } /* Update the early and late 3D panning gains. */ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, const ALfloat earlyGain, const ALfloat lateGain, ReverbState *State) { - aluMatrixf transform, rot; - ALsizei i; - State->mOutBuffer = Device->FOAOut.Buffer; State->mOutChannels = Device->FOAOut.NumChannels; - /* Note: _res is transposed. */ -#define MATRIX_MULT(_res, _m1, _m2) do { \ - int row, col; \ - for(col = 0;col < 4;col++) \ - { \ - for(row = 0;row < 4;row++) \ - _res.m[col][row] = _m1.m[row][0]*_m2.m[0][col] + _m1.m[row][1]*_m2.m[1][col] + \ - _m1.m[row][2]*_m2.m[2][col] + _m1.m[row][3]*_m2.m[3][col]; \ - } \ -} while(0) + /* Note: ret is transposed. */ + auto MatrixMult = [](const alu::Matrix &m1, const alu::Matrix &m2) noexcept -> alu::Matrix + { + alu::Matrix ret; + for(int col{0};col < 4;col++) + { + for(int row{0};row < 4;row++) + ret[col][row] = m1[row][0]*m2[0][col] + m1[row][1]*m2[1][col] + + m1[row][2]*m2[2][col] + m1[row][3]*m2[3][col]; + } + return ret; + }; + /* Create a matrix that first converts A-Format to B-Format, then * transforms the B-Format signal according to the panning vector. */ - rot = GetTransformFromVector(ReflectionsPan); - MATRIX_MULT(transform, rot, A2B); - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&Device->FOAOut, transform.m[i], earlyGain, + alu::Matrix rot{GetTransformFromVector(ReflectionsPan)}; + alu::Matrix transform{MatrixMult(rot, A2B)}; + for(ALsizei i{0};i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(&Device->FOAOut, transform[i].data(), earlyGain, State->mEarly.PanGain[i]); rot = GetTransformFromVector(LateReverbPan); - MATRIX_MULT(transform, rot, A2B); - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&Device->FOAOut, transform.m[i], lateGain, + transform = MatrixMult(rot, A2B); + for(ALsizei i{0};i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(&Device->FOAOut, transform[i].data(), lateGain, State->mLate.PanGain[i]); -#undef MATRIX_MULT } void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) @@ -1380,7 +1374,7 @@ void ReverbState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesI for(c = 0;c < NUM_LINES;c++) { std::fill(std::begin(afmt[c]), std::end(afmt[c]), 0.0f); - MixRowSamples(afmt[c], B2A.m[c], + MixRowSamples(afmt[c], B2A[c].data(), SamplesIn, MAX_EFFECT_CHANNELS, base, todo ); } diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h index f3a39dfa..490f1594 100644 --- a/OpenAL32/Include/alListener.h +++ b/OpenAL32/Include/alListener.h @@ -35,8 +35,8 @@ struct ALlistener { std::atomic Update{nullptr}; struct { - aluMatrixf Matrix; - aluVector Velocity; + alu::Matrix Matrix; + alu::Vector Velocity; ALfloat Gain; ALfloat MetersPerUnit; diff --git a/common/vecmat.cpp b/common/vecmat.cpp index ccb9ad9f..50c2ff5b 100644 --- a/common/vecmat.cpp +++ b/common/vecmat.cpp @@ -2,11 +2,3 @@ #include "config.h" #include "vecmat.h" - - -const aluMatrixf aluMatrixf::Identity{{ - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, 0.0f }, - { 0.0f, 0.0f, 0.0f, 1.0f }, -}}; diff --git a/common/vecmat.h b/common/vecmat.h index 0a60cb9e..1ecc4b7c 100644 --- a/common/vecmat.h +++ b/common/vecmat.h @@ -1,46 +1,102 @@ #ifndef COMMON_VECMAT_H #define COMMON_VECMAT_H -#include "AL/al.h" +#include +#include +#include +#include "math_defs.h" -struct aluVector { - alignas(16) ALfloat v[4]; +namespace alu { + +class Vector { + alignas(16) std::array mVals{}; + +public: + constexpr Vector() noexcept = default; + constexpr Vector(float a, float b, float c, float d) noexcept + : mVals{{a, b, c, d}} + { } + Vector(const Vector &rhs) noexcept + { std::copy(rhs.mVals.begin(), rhs.mVals.end(), mVals.begin()); } + + Vector& operator=(const Vector &rhs) noexcept + { + std::copy(rhs.mVals.begin(), rhs.mVals.end(), mVals.begin()); + return *this; + } + + float& operator[](size_t idx) noexcept { return mVals[idx]; } + constexpr const float& operator[](size_t idx) const noexcept { return mVals[idx]; } + + Vector& operator+=(const Vector &rhs) noexcept + { + mVals[0] += rhs.mVals[0]; + mVals[1] += rhs.mVals[1]; + mVals[2] += rhs.mVals[2]; + mVals[3] += rhs.mVals[3]; + return *this; + } + + float normalize() + { + const float length{std::sqrt(mVals[0]*mVals[0] + mVals[1]*mVals[1] + mVals[2]*mVals[2])}; + if(length > FLT_EPSILON) + { + float inv_length = 1.0f/length; + mVals[0] *= inv_length; + mVals[1] *= inv_length; + mVals[2] *= inv_length; + return length; + } + mVals[0] = mVals[1] = mVals[2] = 0.0f; + return 0.0f; + } }; -inline void aluVectorSet(aluVector *vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w) -{ - vector->v[0] = x; - vector->v[1] = y; - vector->v[2] = z; - vector->v[3] = w; -} +class Matrix { + alignas(16) std::array,4> mVals{}; + +public: + constexpr Matrix() noexcept = default; + constexpr Matrix(float aa, float ab, float ac, float ad, + float ba, float bb, float bc, float bd, + float ca, float cb, float cc, float cd, + float da, float db, float dc, float dd) noexcept + : mVals{{{{aa, ab, ac, ad}}, {{ba, bb, bc, bd}}, {{ca, cb, cc, cd}}, {{da, db, dc, dd}}}} + { } + Matrix(const Matrix &rhs) noexcept + { std::copy(rhs.mVals.begin(), rhs.mVals.end(), mVals.begin()); } + + Matrix& operator=(const Matrix &rhs) noexcept + { + std::copy(rhs.mVals.begin(), rhs.mVals.end(), mVals.begin()); + return *this; + } + std::array& operator[](size_t idx) noexcept { return mVals[idx]; } + constexpr const std::array& operator[](size_t idx) const noexcept { return mVals[idx]; } -struct aluMatrixf { - alignas(16) ALfloat m[4][4]; + void setRow(size_t idx, float a, float b, float c, float d) noexcept + { + mVals[idx][0] = a; + mVals[idx][1] = b; + mVals[idx][2] = c; + mVals[idx][3] = d; + } - static const aluMatrixf Identity; + static const Matrix &Identity() noexcept + { + static constexpr Matrix identity{ + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + return identity; + } }; -inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row, - ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3) -{ - matrix->m[row][0] = m0; - matrix->m[row][1] = m1; - matrix->m[row][2] = m2; - matrix->m[row][3] = m3; -} - -inline void aluMatrixfSet(aluMatrixf *matrix, ALfloat m00, ALfloat m01, ALfloat m02, ALfloat m03, - ALfloat m10, ALfloat m11, ALfloat m12, ALfloat m13, - ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23, - ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33) -{ - aluMatrixfSetRow(matrix, 0, m00, m01, m02, m03); - aluMatrixfSetRow(matrix, 1, m10, m11, m12, m13); - aluMatrixfSetRow(matrix, 2, m20, m21, m22, m23); - aluMatrixfSetRow(matrix, 3, m30, m31, m32, m33); -} +} // namespace alu #endif /* COMMON_VECMAT_H */ -- cgit v1.2.3 From 43f6a7c6267f85f4e2588467bfee12715874932b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 12 Dec 2018 04:34:09 -0800 Subject: Remove an unused source --- CMakeLists.txt | 1 - common/vecmat.cpp | 4 ---- 2 files changed, 5 deletions(-) delete mode 100644 common/vecmat.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 502e4cbd..25392911 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -698,7 +698,6 @@ SET(COMMON_OBJS common/math_defs.h common/threads.cpp common/threads.h - common/vecmat.cpp common/vecmat.h ) SET(OPENAL_OBJS diff --git a/common/vecmat.cpp b/common/vecmat.cpp deleted file mode 100644 index 50c2ff5b..00000000 --- a/common/vecmat.cpp +++ /dev/null @@ -1,4 +0,0 @@ - -#include "config.h" - -#include "vecmat.h" -- cgit v1.2.3 From b37bc9f8b7c5ff5f25069ae307c0255ec4320458 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 12 Dec 2018 19:24:06 -0800 Subject: Fix an MSVC warning --- router/alc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/router/alc.cpp b/router/alc.cpp index c129198a..0f552523 100644 --- a/router/alc.cpp +++ b/router/alc.cpp @@ -707,7 +707,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para { auto drv = std::find_if(DriverList.cbegin(), DriverList.cend(), [](const DriverIface &drv) -> bool - { return drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT"); } + { return drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT") != ALC_FALSE; } ); if(drv != DriverList.cend()) return drv->alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER); -- cgit v1.2.3 From b779ebb512b840a325b32f258261c37bf36a1b7a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 12 Dec 2018 21:18:31 -0800 Subject: Fix some MSVC conversion warnings --- Alc/ambdec.cpp | 16 +++++++--------- Alc/backends/dsound.cpp | 6 +++--- Alc/backends/wave.cpp | 8 ++++---- Alc/backends/winmm.cpp | 7 ++++--- Alc/effects/chorus.cpp | 10 +++++----- Alc/effects/echo.cpp | 10 +++++----- Alc/panning.cpp | 18 +++++++++--------- OpenAL32/Include/alMain.h | 12 ++++++------ OpenAL32/alAuxEffectSlot.cpp | 6 +++--- OpenAL32/alBuffer.cpp | 4 ++-- OpenAL32/alEffect.cpp | 4 ++-- OpenAL32/alFilter.cpp | 4 ++-- OpenAL32/alSource.cpp | 5 +++-- OpenAL32/event.cpp | 9 ++++++--- 14 files changed, 61 insertions(+), 58 deletions(-) diff --git a/Alc/ambdec.cpp b/Alc/ambdec.cpp index c408a2af..d25b8966 100644 --- a/Alc/ambdec.cpp +++ b/Alc/ambdec.cpp @@ -57,9 +57,7 @@ bool is_at_end(const std::string &buffer, std::size_t endpos) { while(endpos < buffer.length() && std::isspace(buffer[endpos])) ++endpos; - if(endpos < buffer.length()) - return false; - return true; + return !(endpos < buffer.length()); } @@ -103,7 +101,7 @@ bool load_ambdec_speakers(AmbDecConf *conf, std::istream &f, std::string &buffer } istr.clear(); - std::istream::pos_type endpos{istr.tellg()}; + const auto endpos = static_cast(istr.tellg()); if(!is_at_end(buffer, endpos)) { ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); @@ -182,7 +180,7 @@ bool load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsi } istr.clear(); - std::istream::pos_type endpos{istr.tellg()}; + const auto endpos = static_cast(istr.tellg()); if(!is_at_end(buffer, endpos)) { ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); @@ -314,7 +312,7 @@ int AmbDecConf::load(const char *fname) noexcept } else if(command == "/speakers/{") { - std::istream::pos_type endpos{istr.tellg()}; + const auto endpos = static_cast(istr.tellg()); if(!is_at_end(buffer, endpos)) { ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); @@ -341,7 +339,7 @@ int AmbDecConf::load(const char *fname) noexcept } else if(command == "/lfmatrix/{" || command == "/hfmatrix/{" || command == "/matrix/{") { - std::istream::pos_type endpos{istr.tellg()}; + const auto endpos = static_cast(istr.tellg()); if(!is_at_end(buffer, endpos)) { ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); @@ -394,7 +392,7 @@ int AmbDecConf::load(const char *fname) noexcept } else if(command == "/end") { - std::istream::pos_type endpos{istr.tellg()}; + const auto endpos = static_cast(istr.tellg()); if(!is_at_end(buffer, endpos)) { ERR("Unexpected junk on end: %s\n", buffer.c_str()+endpos); @@ -410,7 +408,7 @@ int AmbDecConf::load(const char *fname) noexcept } istr.clear(); - std::istream::pos_type endpos{istr.tellg()}; + const auto endpos = static_cast(istr.tellg()); if(!is_at_end(buffer, endpos)) { ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 2bb6048a..79e6b01e 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -902,7 +902,7 @@ ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; if(!device->Connected.load(std::memory_order_acquire)) - return ll_ringbuffer_read_space(self->Ring); + return static_cast(ll_ringbuffer_read_space(self->Ring)); ALsizei FrameSize{FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder)}; DWORD BufferBytes{self->BufferBytes}; @@ -915,7 +915,7 @@ ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) if(SUCCEEDED(hr)) { DWORD NumBytes{(ReadCursor-LastCursor + BufferBytes) % BufferBytes}; - if(!NumBytes) return ll_ringbuffer_read_space(self->Ring); + if(!NumBytes) return static_cast(ll_ringbuffer_read_space(self->Ring)); hr = self->DSCbuffer->Lock(LastCursor, NumBytes, &ReadPtr1, &ReadCnt1, &ReadPtr2, &ReadCnt2, 0); } @@ -934,7 +934,7 @@ ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) aluHandleDisconnect(device, "Failure retrieving capture data: 0x%lx", hr); } - return ll_ringbuffer_read_space(self->Ring); + return static_cast(ll_ringbuffer_read_space(self->Ring)); } } // namespace diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index 25245a1b..afa948cb 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -155,13 +155,13 @@ int ALCwaveBackend_mixerProc(ALCwaveBackend *self) if(!IS_LITTLE_ENDIAN) { - ALuint bytesize = BytesFromDevFmt(device->FmtType); - ALuint i; + const ALsizei bytesize{BytesFromDevFmt(device->FmtType)}; + ALsizei i; if(bytesize == 2) { ALushort *samples = reinterpret_cast(self->mBuffer.data()); - ALuint len = self->mBuffer.size() / 2; + const auto len = static_cast(self->mBuffer.size() / 2); for(i = 0;i < len;i++) { ALushort samp = samples[i]; @@ -171,7 +171,7 @@ int ALCwaveBackend_mixerProc(ALCwaveBackend *self) else if(bytesize == 4) { ALuint *samples = reinterpret_cast(self->mBuffer.data()); - ALuint len = self->mBuffer.size() / 4; + const auto len = static_cast(self->mBuffer.size() / 4); for(i = 0;i < len;i++) { ALuint samp = samples[i]; diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 32cabbde..0d353906 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -361,7 +361,7 @@ ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self) try { std::for_each(self->WaveBuffer.begin(), self->WaveBuffer.end(), [self](WAVEHDR &waveHdr) -> void - { waveOutPrepareHeader(self->OutHdl, &waveHdr, sizeof(WAVEHDR)); } + { waveOutPrepareHeader(self->OutHdl, &waveHdr, static_cast(sizeof(WAVEHDR))); } ); self->Writable.store(self->WaveBuffer.size(), std::memory_order_release); @@ -581,8 +581,9 @@ ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName) // Allocate circular memory buffer for the captured audio // Make sure circular buffer is at least 100ms in size - DWORD CapturedDataSize{std::max(device->UpdateSize*device->NumUpdates, - BufferSize*self->WaveBuffer.size())}; + auto CapturedDataSize = static_cast( + std::max(device->UpdateSize*device->NumUpdates, BufferSize*self->WaveBuffer.size()) + ); self->Ring = ll_ringbuffer_create(CapturedDataSize, self->Format.nBlockAlign, false); if(!self->Ring) return ALC_INVALID_VALUE; diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp index 95f47d36..e0878eb0 100644 --- a/Alc/effects/chorus.cpp +++ b/Alc/effects/chorus.cpp @@ -188,11 +188,11 @@ void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, co void ChorusState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - const ALsizei bufmask = mSampleBuffer.size()-1; - const ALfloat feedback = mFeedback; - const ALsizei avgdelay = (mDelay + (FRACTIONONE>>1)) >> FRACTIONBITS; - ALfloat *RESTRICT delaybuf = mSampleBuffer.data(); - ALsizei offset = mOffset; + const auto bufmask = static_cast(mSampleBuffer.size()-1); + const ALfloat feedback{mFeedback}; + const ALsizei avgdelay{(mDelay + (FRACTIONONE>>1)) >> FRACTIONBITS}; + ALfloat *RESTRICT delaybuf{mSampleBuffer.data()}; + ALsizei offset{mOffset}; ALsizei i, c; ALsizei base; diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index 91bdde9a..3604bed4 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -127,11 +127,11 @@ void ALechoState::update(const ALCcontext *context, const ALeffectslot *slot, co void ALechoState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - const ALsizei mask = mSampleBuffer.size()-1; - const ALsizei tap1 = mTap[0].delay; - const ALsizei tap2 = mTap[1].delay; - ALfloat *RESTRICT delaybuf = mSampleBuffer.data(); - ALsizei offset = mOffset; + const auto mask = static_cast(mSampleBuffer.size()-1); + const ALsizei tap1{mTap[0].delay}; + const ALsizei tap2{mTap[1].delay}; + ALfloat *RESTRICT delaybuf{mSampleBuffer.data()}; + ALsizei offset{mOffset}; ALfloat z1, z2; ALsizei base; ALsizei c, i; diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 6a510e7b..075c6648 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -373,43 +373,43 @@ void InitPanning(ALCdevice *device) switch(device->FmtChans) { case DevFmtMono: - count = COUNTOF(MonoCfg); + count = static_cast(COUNTOF(MonoCfg)); chanmap = MonoCfg; coeffcount = 1; break; case DevFmtStereo: - count = COUNTOF(StereoCfg); + count = static_cast(COUNTOF(StereoCfg)); chanmap = StereoCfg; coeffcount = 4; break; case DevFmtQuad: - count = COUNTOF(QuadCfg); + count = static_cast(COUNTOF(QuadCfg)); chanmap = QuadCfg; coeffcount = 4; break; case DevFmtX51: - count = COUNTOF(X51SideCfg); + count = static_cast(COUNTOF(X51SideCfg)); chanmap = X51SideCfg; coeffcount = 9; break; case DevFmtX51Rear: - count = COUNTOF(X51RearCfg); + count = static_cast(COUNTOF(X51RearCfg)); chanmap = X51RearCfg; coeffcount = 9; break; case DevFmtX61: - count = COUNTOF(X61Cfg); + count = static_cast(COUNTOF(X61Cfg)); chanmap = X61Cfg; coeffcount = 9; break; case DevFmtX71: - count = COUNTOF(X71Cfg); + count = static_cast(COUNTOF(X71Cfg)); chanmap = X71Cfg; coeffcount = 16; break; @@ -739,7 +739,7 @@ void InitHrtfPanning(ALCdevice *device) { AmbiMatrix = AmbiMatrixHOA; AmbiOrderHFGain = AmbiOrderHFGainHOA; - count = COUNTOF(IndexMap); + count = static_cast(COUNTOF(IndexMap)); } device->mHrtfState.reset( @@ -774,7 +774,7 @@ void InitHrtfPanning(ALCdevice *device) BuildBFormatHrtf(device->HrtfHandle, device->mHrtfState.get(), device->Dry.NumChannels, AmbiPoints, AmbiMatrix, - COUNTOF(AmbiPoints), AmbiOrderHFGain + static_cast(COUNTOF(AmbiPoints)), AmbiOrderHFGain ); InitNearFieldCtrl(device, device->HrtfHandle->distance, device->AmbiUp ? 2 : 1, diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 0f65965a..d44671db 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -146,7 +146,7 @@ typedef ALuint64SOFT ALuint64; inline int msvc64_popcnt64(ALuint64 v) { - return __popcnt64(v); + return (int)__popcnt64(v); } #define POPCNT64 msvc64_popcnt64 @@ -162,7 +162,7 @@ inline int msvc64_ctz64(ALuint64 v) inline int msvc_popcnt64(ALuint64 v) { - return __popcnt((ALuint)v) + __popcnt((ALuint)(v>>32)); + return (int)(__popcnt((ALuint)v) + __popcnt((ALuint)(v>>32))); } #define POPCNT64 msvc_popcnt64 @@ -887,14 +887,14 @@ void SetRTPriority(void); void SetDefaultChannelOrder(ALCdevice *device); void SetDefaultWFXChannelOrder(ALCdevice *device); -const ALCchar *DevFmtTypeString(enum DevFmtType type); -const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans); +const ALCchar *DevFmtTypeString(DevFmtType type); +const ALCchar *DevFmtChannelsString(DevFmtChannels chans); -inline ALint GetChannelIndex(const enum Channel (&names)[MAX_OUTPUT_CHANNELS], enum Channel chan) +inline ALint GetChannelIndex(const Channel (&names)[MAX_OUTPUT_CHANNELS], Channel chan) { auto iter = std::find(std::begin(names), std::end(names), chan); if(iter == std::end(names)) return -1; - return std::distance(std::begin(names), iter); + return static_cast(std::distance(std::begin(names), iter)); } /** * GetChannelIdxByName diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index 1e841c43..db22ca4c 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -90,7 +90,7 @@ void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *cont if(start == last) break; ++start; } - newcount = std::distance(newarray->slot, last); + newcount = static_cast(std::distance(newarray->slot, last)); /* Reallocate newarray if the new size ended up smaller from duplicate * removal. @@ -130,7 +130,7 @@ void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *c [slotids, slotids_end](const ALeffectslot *slot) -> bool { return std::find(slotids, slotids_end, slot->id) == slotids_end; } ); - newarray->count = std::distance(newarray->slot, slotiter); + newarray->count = static_cast(std::distance(newarray->slot, slotiter)); /* TODO: Could reallocate newarray now that we know it's needed size. */ @@ -225,7 +225,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo } aluInitEffectPanning(iter->get()); - ALuint id = std::distance(context->EffectSlotList.begin(), iter) + 1; + auto id = static_cast(std::distance(context->EffectSlotList.begin(), iter) + 1); (*iter)->id = id; effectslots[cur] = id; } diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index dbd48ad0..6bc965c2 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -59,7 +59,7 @@ ALbuffer *AllocBuffer(ALCcontext *context) { return entry.FreeMask != 0; } ); - auto lidx = std::distance(device->BufferList.begin(), sublist); + auto lidx = static_cast(std::distance(device->BufferList.begin(), sublist)); ALbuffer *buffer{nullptr}; ALsizei slidx{0}; if(LIKELY(sublist != device->BufferList.end())) @@ -442,7 +442,7 @@ AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) ALbuffer *buffer = AllocBuffer(context.get()); if(!buffer) { - alDeleteBuffers(ids.size(), ids.data()); + alDeleteBuffers(static_cast(ids.size()), ids.data()); return; } diff --git a/OpenAL32/alEffect.cpp b/OpenAL32/alEffect.cpp index 1c08d402..dd16acfb 100644 --- a/OpenAL32/alEffect.cpp +++ b/OpenAL32/alEffect.cpp @@ -216,7 +216,7 @@ ALeffect *AllocEffect(ALCcontext *context) { return entry.FreeMask != 0; } ); - auto lidx = std::distance(device->EffectList.begin(), sublist); + auto lidx = static_cast(std::distance(device->EffectList.begin(), sublist)); ALeffect *effect{nullptr}; ALsizei slidx{0}; if(LIKELY(sublist != device->EffectList.end())) @@ -314,7 +314,7 @@ AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) ALeffect *effect = AllocEffect(context.get()); if(!effect) { - alDeleteEffects(ids.size(), ids.data()); + alDeleteEffects(static_cast(ids.size()), ids.data()); return; } diff --git a/OpenAL32/alFilter.cpp b/OpenAL32/alFilter.cpp index 52135569..c4416a38 100644 --- a/OpenAL32/alFilter.cpp +++ b/OpenAL32/alFilter.cpp @@ -276,7 +276,7 @@ ALfilter *AllocFilter(ALCcontext *context) { return entry.FreeMask != 0; } ); - auto lidx = std::distance(device->FilterList.begin(), sublist); + auto lidx = static_cast(std::distance(device->FilterList.begin(), sublist)); ALfilter *filter{nullptr}; ALsizei slidx{0}; if(LIKELY(sublist != device->FilterList.end())) @@ -375,7 +375,7 @@ AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) ALfilter *filter = AllocFilter(context.get()); if(!filter) { - alDeleteFilters(ids.size(), ids.data()); + alDeleteFilters(static_cast(ids.size()), ids.data()); return; } diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index f257da83..3697b232 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -468,7 +468,7 @@ ALsource *AllocSource(ALCcontext *context) [](const SourceSubList &entry) -> bool { return entry.FreeMask != 0; } ); - ALsizei lidx = std::distance(context->SourceList.begin(), sublist); + auto lidx = static_cast(std::distance(context->SourceList.begin(), sublist)); ALsource *source; ALsizei slidx; if(LIKELY(sublist != context->SourceList.end())) @@ -2122,7 +2122,8 @@ AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) } ); if(alloc_end != tempids.end()) - alDeleteSources(std::distance(tempids.begin(), alloc_end), tempids.data()); + alDeleteSources(static_cast(std::distance(tempids.begin(), alloc_end)), + tempids.data()); else std::copy(tempids.cbegin(), tempids.cend(), sources); } diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index ad3fd4ab..6a3dc4bc 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -52,7 +52,8 @@ static int EventThread(ALCcontext *context) (evt.u.srcstate.state==AL_PAUSED) ? "AL_PAUSED" : (evt.u.srcstate.state==AL_STOPPED) ? "AL_STOPPED" : ""; context->EventCb(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, evt.u.srcstate.id, - evt.u.srcstate.state, msg.length(), msg.c_str(), context->EventParam + evt.u.srcstate.state, static_cast(msg.length()), msg.c_str(), + context->EventParam ); } else if(evt.EnumType == EventType_BufferCompleted) @@ -63,12 +64,14 @@ static int EventThread(ALCcontext *context) if(evt.u.bufcomp.count == 1) msg += " buffer completed"; else msg += " buffers completed"; context->EventCb(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, evt.u.bufcomp.id, - evt.u.bufcomp.count, msg.length(), msg.c_str(), context->EventParam + evt.u.bufcomp.count, static_cast(msg.length()), msg.c_str(), + context->EventParam ); } else if((enabledevts&evt.EnumType) == evt.EnumType) context->EventCb(evt.u.user.type, evt.u.user.id, evt.u.user.param, - (ALsizei)strlen(evt.u.user.msg), evt.u.user.msg, context->EventParam + static_cast(strlen(evt.u.user.msg)), evt.u.user.msg, + context->EventParam ); } while(ll_ringbuffer_read(context->AsyncEvents, &evt, 1) != 0); } -- cgit v1.2.3 From 0d73b13f59e5df1bc87266e4ee3bced85a8dd5ef Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 12 Dec 2018 21:58:41 -0800 Subject: Add more casts for MSVC --- Alc/alc.cpp | 2 +- Alc/ambdec.cpp | 23 +++++++++++++++-------- Alc/backends/winmm.cpp | 3 ++- Alc/helpers.cpp | 2 +- Alc/hrtf.cpp | 2 +- 5 files changed, 20 insertions(+), 12 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 3ccf545a..5ef486cf 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -171,7 +171,7 @@ struct BackendInfo BackendList[] = { { "wave", WaveBackendFactory::getFactory }, #endif }; -ALsizei BackendListSize = COUNTOF(BackendList); +ALsizei BackendListSize = static_cast(COUNTOF(BackendList)); struct BackendInfo PlaybackBackend; struct BackendInfo CaptureBackend; diff --git a/Alc/ambdec.cpp b/Alc/ambdec.cpp index d25b8966..66fc2255 100644 --- a/Alc/ambdec.cpp +++ b/Alc/ambdec.cpp @@ -142,7 +142,8 @@ bool load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsi if(istr.fail()) break; if(!istr.eof() && !std::isspace(istr.peek())) { - ERR("Extra junk on gain %u: %s\n", curgain+1, buffer.c_str()+istr.tellg()); + ERR("Extra junk on gain %u: %s\n", curgain+1, + buffer.c_str()+static_cast(istr.tellg())); return false; } if(curgain < MAX_AMBI_ORDER+1) @@ -163,7 +164,7 @@ bool load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsi if(!istr.eof() && !std::isspace(istr.peek())) { ERR("Extra junk on matrix element %ux%u: %s\n", cur, curidx, - buffer.c_str()+istr.tellg()); + buffer.c_str()+static_cast(istr.tellg())); return false; } if(curidx < MAX_AMBI_COEFFS) @@ -228,7 +229,8 @@ int AmbDecConf::load(const char *fname) noexcept istr >> Version; if(!istr.eof() && !std::isspace(istr.peek())) { - ERR("Extra junk after version: %s\n", buffer.c_str()+istr.tellg()); + ERR("Extra junk after version: %s\n", + buffer.c_str()+static_cast(istr.tellg())); return 0; } if(Version != 3) @@ -242,7 +244,8 @@ int AmbDecConf::load(const char *fname) noexcept istr >> std::hex >> ChanMask >> std::dec; if(!istr.eof() && !std::isspace(istr.peek())) { - ERR("Extra junk after mask: %s\n", buffer.c_str()+istr.tellg()); + ERR("Extra junk after mask: %s\n", + buffer.c_str()+static_cast(istr.tellg())); return 0; } } @@ -251,7 +254,8 @@ int AmbDecConf::load(const char *fname) noexcept istr >> FreqBands; if(!istr.eof() && !std::isspace(istr.peek())) { - ERR("Extra junk after freq_bands: %s\n", buffer.c_str()+istr.tellg()); + ERR("Extra junk after freq_bands: %s\n", + buffer.c_str()+static_cast(istr.tellg())); return 0; } if(FreqBands != 1 && FreqBands != 2) @@ -265,7 +269,8 @@ int AmbDecConf::load(const char *fname) noexcept istr >> NumSpeakers; if(!istr.eof() && !std::isspace(istr.peek())) { - ERR("Extra junk after speakers: %s\n", buffer.c_str()+istr.tellg()); + ERR("Extra junk after speakers: %s\n", + buffer.c_str()+static_cast(istr.tellg())); return 0; } if(NumSpeakers > MAX_OUTPUT_CHANNELS) @@ -291,7 +296,8 @@ int AmbDecConf::load(const char *fname) noexcept istr >> XOverFreq; if(!istr.eof() && !std::isspace(istr.peek())) { - ERR("Extra junk after xover_freq: %s\n", buffer.c_str()+istr.tellg()); + ERR("Extra junk after xover_freq: %s\n", + buffer.c_str()+static_cast(istr.tellg())); return 0; } } @@ -300,7 +306,8 @@ int AmbDecConf::load(const char *fname) noexcept istr >> XOverRatio; if(!istr.eof() && !std::isspace(istr.peek())) { - ERR("Extra junk after xover_ratio: %s\n", buffer.c_str()+istr.tellg()); + ERR("Extra junk after xover_ratio: %s\n", + buffer.c_str()+static_cast(istr.tellg())); return 0; } } diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 0d353906..ff5d026c 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -363,7 +363,8 @@ ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self) [self](WAVEHDR &waveHdr) -> void { waveOutPrepareHeader(self->OutHdl, &waveHdr, static_cast(sizeof(WAVEHDR))); } ); - self->Writable.store(self->WaveBuffer.size(), std::memory_order_release); + self->Writable.store(static_cast(self->WaveBuffer.size()), + std::memory_order_release); self->mKillNow.store(AL_FALSE, std::memory_order_release); self->mThread = std::thread(ALCwinmmPlayback_mixerProc, self); diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index a46e857f..17942855 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -316,7 +316,7 @@ PathNamePair GetProcBinary() al::vector fullpath(256); DWORD len; - while((len=GetModuleFileNameW(nullptr, fullpath.data(), fullpath.size())) == fullpath.size()) + while((len=GetModuleFileNameW(nullptr, fullpath.data(), static_cast(fullpath.size()))) == fullpath.size()) fullpath.resize(fullpath.size() << 1); if(len == 0) { diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 230574a9..5cc1e8b4 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -133,7 +133,7 @@ class databuf final : public std::streambuf { if(pos < 0 || pos > egptr()-eback()) return traits_type::eof(); - setg(eback(), eback() + pos, egptr()); + setg(eback(), eback() + static_cast(pos), egptr()); return pos; } -- cgit v1.2.3 From d18ae81e9c10df8ca2d93d367331f3820f9e766e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 13 Dec 2018 22:05:47 -0800 Subject: Add POPCNT32 and CTZ32 macros --- OpenAL32/Include/alMain.h | 54 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index d44671db..132e6c21 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -129,11 +129,14 @@ typedef ALuint64SOFT ALuint64; #endif #endif -/* Define a CTZ64 macro (count trailing zeros, for 64-bit integers). The result - * is *UNDEFINED* if the value is 0. +/* Define CTZ macros (count trailing zeros), and POPCNT macros (population + * count/count 1 bits), for 32- and 64-bit integers. The CTZ macros' results + * are *UNDEFINED* if the value is 0. */ #ifdef __GNUC__ +#define POPCNT32 __builtin_popcount +#define CTZ32 __builtin_ctz #if SIZEOF_LONG == 8 #define POPCNT64 __builtin_popcountl #define CTZ64 __builtin_ctzl @@ -144,12 +147,20 @@ typedef ALuint64SOFT ALuint64; #elif defined(HAVE_BITSCANFORWARD64_INTRINSIC) -inline int msvc64_popcnt64(ALuint64 v) +inline int msvc64_popcnt32(ALuint v) +{ return (int)__popcnt(v); } +#define POPCNT32 msvc64_popcnt32 +inline int msvc64_ctz32(ALuint v) { - return (int)__popcnt64(v); + unsigned long idx = 32; + _BitScanForward(&idx, v); + return (int)idx; } -#define POPCNT64 msvc64_popcnt64 +#define CTZ32 msvc64_ctz32 +inline int msvc64_popcnt64(ALuint64 v) +{ return (int)__popcnt64(v); } +#define POPCNT64 msvc64_popcnt64 inline int msvc64_ctz64(ALuint64 v) { unsigned long idx = 64; @@ -160,12 +171,20 @@ inline int msvc64_ctz64(ALuint64 v) #elif defined(HAVE_BITSCANFORWARD_INTRINSIC) -inline int msvc_popcnt64(ALuint64 v) +inline int msvc_popcnt32(ALuint v) +{ return (int)__popcnt(v); } +#define POPCNT32 msvc_popcnt32 +inline int msvc_ctz32(ALuint v) { - return (int)(__popcnt((ALuint)v) + __popcnt((ALuint)(v>>32))); + unsigned long idx = 32; + _BitScanForward(&idx, v); + return (int)idx; } -#define POPCNT64 msvc_popcnt64 +#define CTZ32 msvc_ctz32 +inline int msvc_popcnt64(ALuint64 v) +{ return (int)(__popcnt((ALuint)v) + __popcnt((ALuint)(v>>32))); } +#define POPCNT64 msvc_popcnt64 inline int msvc_ctz64(ALuint64 v) { unsigned long idx = 64; @@ -180,13 +199,25 @@ inline int msvc_ctz64(ALuint64 v) #else -/* There be black magics here. The popcnt64 method is derived from +/* There be black magics here. The popcnt method is derived from * https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel * while the ctz-utilizing-popcnt algorithm is shown here * http://www.hackersdelight.org/hdcodetxt/ntz.c.txt * as the ntz2 variant. These likely aren't the most efficient methods, but * they're good enough if the GCC or MSVC intrinsics aren't available. */ +inline int fallback_popcnt32(ALuint v) +{ + v = v - ((v >> 1) & 0x55555555u); + v = (v & 0x33333333u) + ((v >> 2) & 0x33333333u); + v = (v + (v >> 4)) & 0x0f0f0f0fu; + return (int)((v * 0x01010101u) >> 24); +} +#define POPCNT32 fallback_popcnt32 +inline int fallback_ctz32(ALuint value) +{ return fallback_popcnt32(~value & (value - 1)); } +#define CTZ32 fallback_ctz32 + inline int fallback_popcnt64(ALuint64 v) { v = v - ((v >> 1) & U64(0x5555555555555555)); @@ -195,11 +226,8 @@ inline int fallback_popcnt64(ALuint64 v) return (int)((v * U64(0x0101010101010101)) >> 56); } #define POPCNT64 fallback_popcnt64 - inline int fallback_ctz64(ALuint64 value) -{ - return fallback_popcnt64(~value & (value - 1)); -} +{ return fallback_popcnt64(~value & (value - 1)); } #define CTZ64 fallback_ctz64 #endif -- cgit v1.2.3 From 0882728dec2b9109fb60d98a46da31dc92acb790 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 13 Dec 2018 22:48:02 -0800 Subject: Cleanup bformatdec.cpp a bit --- Alc/bformatdec.cpp | 111 +++++++++++++++-------------------------------------- 1 file changed, 30 insertions(+), 81 deletions(-) diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 888c7cab..322a7977 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -59,8 +59,7 @@ constexpr ALfloat Ambi3DDecoderHFScale[MAX_AMBI_COEFFS] = { #define INVALID_UPSAMPLE_INDEX INT_MAX ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn) { - ALsizei i; - for(i = 0;i < numchans;i++) + for(ALsizei i{0};i < numchans;i++) { if(chans[i].Index == acn) return i; @@ -69,7 +68,7 @@ ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn) } #define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a)) -auto GetAmbiScales(AmbDecScale scaletype) noexcept -> decltype(AmbiScale::N3D2N3D)& +auto GetAmbiScales(AmbDecScale scaletype) noexcept -> const float(&)[MAX_AMBI_COEFFS] { if(scaletype == AmbDecScale::FuMa) return AmbiScale::FuMa2N3D; if(scaletype == AmbDecScale::SN3D) return AmbiScale::SN3D2N3D; @@ -88,9 +87,9 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, mSamplesLF = nullptr; mNumChannels = chancount; - mSamples.resize(mNumChannels * 2); + mSamples.resize(chancount * 2); mSamplesHF = mSamples.data(); - mSamplesLF = mSamplesHF + mNumChannels; + mSamplesLF = mSamplesHF + chancount; mEnabled = std::accumulate(std::begin(chanmap), std::begin(chanmap)+conf->NumSpeakers, 0u, [](ALuint mask, const ALsizei &chan) noexcept -> ALuint @@ -129,100 +128,50 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, mUpSampler[3].Gains[LF_BAND] = 0.0f; } - const ALfloat (&coeff_scale)[MAX_AMBI_COEFFS] = GetAmbiScales(conf->CoeffScale); + const float (&coeff_scale)[MAX_AMBI_COEFFS] = GetAmbiScales(conf->CoeffScale); + const ALsizei coeff_count{periphonic ? MAX_AMBI_COEFFS : MAX_AMBI2D_COEFFS}; mMatrix = MatrixU{}; - if(conf->FreqBands == 1) + mDualBand = (conf->FreqBands == 2); + if(!mDualBand) { - mDualBand = AL_FALSE; for(ALsizei i{0};i < conf->NumSpeakers;i++) { - const ALsizei chan{chanmap[i]}; - if(!periphonic) + ALfloat (&mtx)[MAX_AMBI_COEFFS] = mMatrix.Single[chanmap[i]]; + for(ALsizei j{0},k{0};j < coeff_count;j++) { - ALfloat gain{conf->HFOrderGain[0]}; - for(ALsizei j{0},k{0};j < MAX_AMBI2D_COEFFS;j++) - { - const ALsizei l{map2DTo3D[j]}; - if(j == 1) gain = conf->HFOrderGain[1]; - else if(j == 3) gain = conf->HFOrderGain[2]; - else if(j == 5) gain = conf->HFOrderGain[3]; - if((conf->ChanMask&(1<HFMatrix[i][k++] / coeff_scale[l] * gain; - } - } - else - { - ALfloat gain{conf->HFOrderGain[0]}; - for(ALsizei j{0},k{0};j < MAX_AMBI_COEFFS;j++) - { - if(j == 1) gain = conf->HFOrderGain[1]; - else if(j == 4) gain = conf->HFOrderGain[2]; - else if(j == 9) gain = conf->HFOrderGain[3]; - if((conf->ChanMask&(1<HFMatrix[i][k++] / coeff_scale[j] * gain; - } + const ALsizei l{periphonic ? j : map2DTo3D[j]}; + if(!(conf->ChanMask&(1<HFMatrix[i][k] / coeff_scale[l] * + ((l>=9) ? conf->HFOrderGain[3] : + (l>=4) ? conf->HFOrderGain[2] : + (l>=1) ? conf->HFOrderGain[1] : conf->HFOrderGain[0]); + ++k; } } } else { - mDualBand = AL_TRUE; - mXOver[0].init(conf->XOverFreq / (float)srate); std::fill(std::begin(mXOver)+1, std::end(mXOver), mXOver[0]); const float ratio{std::pow(10.0f, conf->XOverRatio / 40.0f)}; for(ALsizei i{0};i < conf->NumSpeakers;i++) { - const ALsizei chan{chanmap[i]}; - if(!periphonic) - { - ALfloat gain{conf->HFOrderGain[0] * ratio}; - for(ALsizei j{0},k{0};j < MAX_AMBI2D_COEFFS;j++) - { - ALsizei l = map2DTo3D[j]; - if(j == 1) gain = conf->HFOrderGain[1] * ratio; - else if(j == 3) gain = conf->HFOrderGain[2] * ratio; - else if(j == 5) gain = conf->HFOrderGain[3] * ratio; - if((conf->ChanMask&(1<HFMatrix[i][k++] / coeff_scale[l] * - gain; - } - gain = conf->HFOrderGain[0] / ratio; - for(ALsizei j{0},k{0};j < MAX_AMBI2D_COEFFS;j++) - { - ALsizei l = map2DTo3D[j]; - if(j == 1) gain = conf->LFOrderGain[1] / ratio; - else if(j == 3) gain = conf->LFOrderGain[2] / ratio; - else if(j == 5) gain = conf->LFOrderGain[3] / ratio; - if((conf->ChanMask&(1<LFMatrix[i][k++] / coeff_scale[l] * - gain; - } - } - else + ALfloat (&mtx)[sNumBands][MAX_AMBI_COEFFS] = mMatrix.Dual[chanmap[i]]; + for(ALsizei j{0},k{0};j < coeff_count;j++) { - ALfloat gain{conf->HFOrderGain[0] * ratio}; - for(ALsizei j{0},k{0};j < MAX_AMBI_COEFFS;j++) - { - if(j == 1) gain = conf->HFOrderGain[1] * ratio; - else if(j == 4) gain = conf->HFOrderGain[2] * ratio; - else if(j == 9) gain = conf->HFOrderGain[3] * ratio; - if((conf->ChanMask&(1<HFMatrix[i][k++] / coeff_scale[j] * - gain; - } - gain = conf->HFOrderGain[0] / ratio; - for(ALsizei j{0},k{0};j < MAX_AMBI_COEFFS;j++) - { - if(j == 1) gain = conf->LFOrderGain[1] / ratio; - else if(j == 4) gain = conf->LFOrderGain[2] / ratio; - else if(j == 9) gain = conf->LFOrderGain[3] / ratio; - if((conf->ChanMask&(1<LFMatrix[i][k++] / coeff_scale[j] * - gain; - } + const ALsizei l{periphonic ? j : map2DTo3D[j]}; + if(!(conf->ChanMask&(1<HFMatrix[i][k] / coeff_scale[l] * + ((l>=9) ? conf->HFOrderGain[3] : + (l>=4) ? conf->HFOrderGain[2] : + (l>=1) ? conf->HFOrderGain[1] : conf->HFOrderGain[0]) * ratio; + mtx[LF_BAND][j] = conf->LFMatrix[i][k] / coeff_scale[l] * + ((l>=9) ? conf->LFOrderGain[3] : + (l>=4) ? conf->LFOrderGain[2] : + (l>=1) ? conf->LFOrderGain[1] : conf->LFOrderGain[0]) / ratio; + ++k; } } } -- cgit v1.2.3 From 2d13e0af29144815e5fc55b2a532ffa9d3bc12f6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Dec 2018 23:26:44 -0800 Subject: Add macros for the ambisonic order masks --- Alc/bformatdec.cpp | 20 ++++++++++++-------- Alc/panning.cpp | 33 ++++++++++++++++++--------------- OpenAL32/Include/alMain.h | 14 +++++++++++--- 3 files changed, 41 insertions(+), 26 deletions(-) diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 322a7977..882184a3 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -103,25 +103,29 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, const bool periphonic{(conf->ChanMask&AMBI_PERIPHONIC_MASK) != 0}; if(periphonic) { - mUpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H3P : - (conf->ChanMask > 0xf) ? W_SCALE_2H2P : 1.0f; + mUpSampler[0].Gains[HF_BAND] = + (conf->ChanMask > AMBI_2ORDER_MASK) ? W_SCALE_3H3P : + (conf->ChanMask > AMBI_1ORDER_MASK) ? W_SCALE_2H2P : 1.0f; mUpSampler[0].Gains[LF_BAND] = 1.0f; for(ALsizei i{1};i < 4;i++) { - mUpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H3P : - (conf->ChanMask > 0xf) ? XYZ_SCALE_2H2P : 1.0f; + mUpSampler[i].Gains[HF_BAND] = + (conf->ChanMask > AMBI_2ORDER_MASK) ? XYZ_SCALE_3H3P : + (conf->ChanMask > AMBI_1ORDER_MASK) ? XYZ_SCALE_2H2P : 1.0f; mUpSampler[i].Gains[LF_BAND] = 1.0f; } } else { - mUpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H0P : - (conf->ChanMask > 0xf) ? W_SCALE_2H0P : 1.0f; + mUpSampler[0].Gains[HF_BAND] = + (conf->ChanMask > AMBI_2ORDER_MASK) ? W_SCALE_3H0P : + (conf->ChanMask > AMBI_1ORDER_MASK) ? W_SCALE_2H0P : 1.0f; mUpSampler[0].Gains[LF_BAND] = 1.0f; for(ALsizei i{1};i < 3;i++) { - mUpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H0P : - (conf->ChanMask > 0xf) ? XYZ_SCALE_2H0P : 1.0f; + mUpSampler[i].Gains[HF_BAND] = + (conf->ChanMask > AMBI_2ORDER_MASK) ? XYZ_SCALE_3H0P : + (conf->ChanMask > AMBI_1ORDER_MASK) ? XYZ_SCALE_2H0P : 1.0f; mUpSampler[i].Gains[LF_BAND] = 1.0f; } mUpSampler[3].Gains[HF_BAND] = 0.0f; diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 075c6648..897dc23a 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -512,12 +512,12 @@ void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei ALfloat w_scale{1.0f}, xyz_scale{1.0f}; if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { - if(conf->ChanMask > 0x1ff) + if(conf->ChanMask > AMBI_2ORDER_MASK) { w_scale = W_SCALE_3H3P; xyz_scale = XYZ_SCALE_3H3P; } - else if(conf->ChanMask > 0xf) + else if(conf->ChanMask > AMBI_1ORDER_MASK) { w_scale = W_SCALE_2H2P; xyz_scale = XYZ_SCALE_2H2P; @@ -525,12 +525,12 @@ void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei } else { - if(conf->ChanMask > 0x1ff) + if(conf->ChanMask > AMBI_2ORDER_MASK) { w_scale = W_SCALE_3H0P; xyz_scale = XYZ_SCALE_3H0P; } - else if(conf->ChanMask > 0xf) + else if(conf->ChanMask > AMBI_1ORDER_MASK) { w_scale = W_SCALE_2H0P; xyz_scale = XYZ_SCALE_2H0P; @@ -560,8 +560,8 @@ void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei SetChannelMap(device->RealOut.ChannelName, device->Dry.Ambi.Coeffs, chanmap, conf->NumSpeakers, &device->Dry.NumChannels); - device->Dry.CoeffCount = (conf->ChanMask > 0x1ff) ? 16 : - (conf->ChanMask > 0xf) ? 9 : 4; + device->Dry.CoeffCount = (conf->ChanMask > AMBI_2ORDER_MASK) ? 16 : + (conf->ChanMask > AMBI_1ORDER_MASK) ? 9 : 4; device->FOAOut.Ambi = AmbiConfig{}; for(ALsizei i{0};i < device->Dry.NumChannels;i++) @@ -587,8 +587,8 @@ void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&sp if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { static constexpr int map[MAX_AMBI_COEFFS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; - count = (conf->ChanMask > 0x1ff) ? 16 : - (conf->ChanMask > 0xf) ? 9 : 4; + count = (conf->ChanMask > AMBI_2ORDER_MASK) ? 16 : + (conf->ChanMask > AMBI_1ORDER_MASK) ? 9 : 4; std::transform(std::begin(map), std::begin(map)+count, std::begin(device->Dry.Ambi.Map), [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } ); @@ -596,8 +596,8 @@ void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&sp else { static constexpr int map[MAX_AMBI2D_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; - count = (conf->ChanMask > 0x1ff) ? 7 : - (conf->ChanMask > 0xf) ? 5 : 3; + count = (conf->ChanMask > AMBI_2ORDER_MASK) ? 7 : + (conf->ChanMask > AMBI_1ORDER_MASK) ? 5 : 3; std::transform(std::begin(map), std::begin(map)+count, std::begin(device->Dry.Ambi.Map), [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } ); @@ -607,12 +607,13 @@ void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&sp TRACE("Enabling %s-band %s-order%s ambisonic decoder\n", (conf->FreqBands == 1) ? "single" : "dual", - (conf->ChanMask > 0xf) ? (conf->ChanMask > 0x1ff) ? "third" : "second" : "first", + (conf->ChanMask > AMBI_2ORDER_MASK) ? "third" : + (conf->ChanMask > AMBI_1ORDER_MASK) ? "second" : "first", (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? " periphonic" : "" ); device->AmbiDecoder->reset(conf, count, device->Frequency, speakermap); - if(conf->ChanMask <= 0xf) + if(conf->ChanMask <= AMBI_1ORDER_MASK) { device->FOAOut.Ambi = device->Dry.Ambi; device->FOAOut.CoeffCount = device->Dry.CoeffCount; @@ -652,7 +653,8 @@ void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&sp float{0.0f}, accum_spkr_dist) / (ALfloat)conf->NumSpeakers }; InitNearFieldCtrl(device, avg_dist, - (conf->ChanMask > 0x1ff) ? 3 : (conf->ChanMask > 0xf) ? 2 : 1, + (conf->ChanMask > AMBI_2ORDER_MASK) ? 3 : + (conf->ChanMask > AMBI_1ORDER_MASK) ? 2 : 1, (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? chans_per_order3d : chans_per_order2d ); @@ -969,8 +971,9 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf ERR("Failed to load layout file %s\n", fname); else { - if(conf.ChanMask > 0xffff) - ERR("Unsupported channel mask 0x%04x (max 0xffff)\n", conf.ChanMask); + if(conf.ChanMask > AMBI_3ORDER_MASK) + ERR("Unsupported channel mask 0x%04x (max 0x%x)\n", conf.ChanMask, + AMBI_3ORDER_MASK); else { if(MakeSpeakerMap(device, &conf, speakermap)) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 132e6c21..8eafa6a4 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -550,11 +550,19 @@ enum RenderMode { #define MAX_AMBI_ORDER 3 #define MAX_AMBI_COEFFS ((MAX_AMBI_ORDER+1) * (MAX_AMBI_ORDER+1)) +/* A bitmask of ambisonic channels for 0 to 4th order. This only specifies up + * to 4th order, which is the highest order a 32-bit mask value can specify (a + * 64-bit mask could handle up to 7th order). + */ +#define AMBI_0ORDER_MASK 0x00000001 +#define AMBI_1ORDER_MASK 0x0000000f +#define AMBI_2ORDER_MASK 0x000001ff +#define AMBI_3ORDER_MASK 0x0000ffff +#define AMBI_4ORDER_MASK 0x01ffffff + /* A bitmask of ambisonic channels with height information. If none of these * channels are used/needed, there's no height (e.g. with most surround sound - * speaker setups). This only specifies up to 4th order, which is the highest - * order a 32-bit mask value can specify (a 64-bit mask could handle up to 7th - * order). This is ACN ordering, with bit 0 being ACN 0, etc. + * speaker setups). This is ACN ordering, with bit 0 being ACN 0, etc. */ #define AMBI_PERIPHONIC_MASK (0xfe7ce4) -- cgit v1.2.3 From 4d36730baa0aac3cc874488d9c7503f02e7cb0ab Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2018 00:38:38 -0800 Subject: Clean up panning.cpp a bit --- Alc/panning.cpp | 115 +++++++++++++++++++++++++------------------------------- 1 file changed, 51 insertions(+), 64 deletions(-) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 897dc23a..e854a966 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -67,7 +67,7 @@ constexpr ALsizei ACN2ACN[MAX_AMBI_COEFFS] = { 8, 9, 10, 11, 12, 13, 14, 15 }; -inline const char *GetLabelFromChannel(enum Channel channel) +inline const char *GetLabelFromChannel(Channel channel) { switch(channel) { @@ -365,10 +365,9 @@ auto GetAmbiLayout(AmbiLayout layouttype) noexcept -> const ALsizei(&)[MAX_AMBI_ void InitPanning(ALCdevice *device) { - const ChannelMap *chanmap = NULL; - ALsizei coeffcount = 0; - ALsizei count = 0; - ALsizei i, j; + const ChannelMap *chanmap{nullptr}; + ALsizei coeffcount{0}; + ALsizei count{0}; switch(device->FmtChans) { @@ -427,12 +426,11 @@ void InitPanning(ALCdevice *device) count = (device->mAmbiOrder == 3) ? 16 : (device->mAmbiOrder == 2) ? 9 : (device->mAmbiOrder == 1) ? 4 : 1; - for(i = 0;i < count;i++) - { - ALsizei acn = acnmap[i]; - device->Dry.Ambi.Map[i].Scale = 1.0f/n3dscale[acn]; - device->Dry.Ambi.Map[i].Index = acn; - } + auto acnmap_end = std::begin(acnmap) + count; + std::transform(std::begin(acnmap), acnmap_end, std::begin(device->Dry.Ambi.Map), + [&n3dscale](const ALsizei &acn) noexcept -> BFChannelConfig + { return BFChannelConfig{1.0f/n3dscale[acn], acn}; } + ); device->Dry.CoeffCount = 0; device->Dry.NumChannels = count; @@ -448,11 +446,10 @@ void InitPanning(ALCdevice *device) * The upsampler expects this and will convert it for output. */ device->FOAOut.Ambi = AmbiConfig{}; - for(i = 0;i < 4;i++) - { - device->FOAOut.Ambi.Map[i].Scale = 1.0f; - device->FOAOut.Ambi.Map[i].Index = i; - } + acnmap_end = std::begin(ACN2ACN) + 4; + std::transform(std::begin(ACN2ACN), acnmap_end, std::begin(device->FOAOut.Ambi.Map), + [](const ALsizei &acn) noexcept { return BFChannelConfig{1.0f, acn}; } + ); device->FOAOut.CoeffCount = 0; device->FOAOut.NumChannels = 4; @@ -491,10 +488,10 @@ void InitPanning(ALCdevice *device) (device->Dry.CoeffCount > 4) ? XYZ_SCALE_2H0P : 1.0f}; device->FOAOut.Ambi = AmbiConfig{}; - for(i = 0;i < device->Dry.NumChannels;i++) + for(ALsizei i{0};i < device->Dry.NumChannels;i++) { device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0] * w_scale; - for(j = 1;j < 4;j++) + for(ALsizei j{1};j < 4;j++) device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * xyz_scale; } device->FOAOut.CoeffCount = 4; @@ -541,20 +538,17 @@ void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei ChannelMap chanmap[MAX_OUTPUT_CHANNELS]{}; for(ALsizei i{0};i < conf->NumSpeakers;i++) { - const ALsizei chan{speakermap[i]}; - - chanmap[i].ChanName = device->RealOut.ChannelName[chan]; + chanmap[i].ChanName = device->RealOut.ChannelName[speakermap[i]]; std::fill(std::begin(chanmap[i].Config), std::end(chanmap[i].Config), 0.0f); - ALsizei k{0}; - ALfloat gain{conf->HFOrderGain[0]}; - for(ALsizei j{0};j < MAX_AMBI_COEFFS;j++) + for(ALsizei j{0},k{0};j < MAX_AMBI_COEFFS;j++) { - if(j == 1) gain = conf->HFOrderGain[1]; - else if(j == 4) gain = conf->HFOrderGain[2]; - else if(j == 9) gain = conf->HFOrderGain[3]; - if((conf->ChanMask&(1<HFMatrix[i][k++] / coeff_scale[j] * gain; + if(!(conf->ChanMask&(1<HFMatrix[i][k++] / coeff_scale[j] * + ((j >= 9) ? conf->HFOrderGain[3] : + (j >= 4) ? conf->HFOrderGain[2] : + (j >= 1) ? conf->HFOrderGain[1] : conf->HFOrderGain[0]); } } @@ -664,7 +658,7 @@ void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&sp void InitHrtfPanning(ALCdevice *device) { /* NOTE: azimuth goes clockwise. */ - static constexpr struct AngularPoint AmbiPoints[] = { + static constexpr AngularPoint AmbiPoints[] = { { DEG2RAD( 90.0f), DEG2RAD( 0.0f) }, { DEG2RAD( 35.2643897f), DEG2RAD( 45.0f) }, { DEG2RAD( 35.2643897f), DEG2RAD( 135.0f) }, @@ -916,10 +910,10 @@ void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, con } -void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq) +void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appreq, HrtfRequestMode hrtf_userreq) { /* Hold the HRTF the device last used, in case it's used again. */ - struct Hrtf *old_hrtf = device->HrtfHandle; + Hrtf *old_hrtf{device->HrtfHandle}; device->mHrtfState = nullptr; device->HrtfHandle = nullptr; @@ -938,17 +932,13 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(device->FmtChans != DevFmtStereo) { - ALsizei speakermap[MAX_OUTPUT_CHANNELS]; - const char *devname, *layout = NULL; - AmbDecConf conf, *pconf = NULL; - if(old_hrtf) Hrtf_DecRef(old_hrtf); - old_hrtf = NULL; + old_hrtf = nullptr; if(hrtf_appreq == Hrtf_Enable) device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; - devname = device->DeviceName.c_str(); + const char *layout{nullptr}; switch(device->FmtChans) { case DevFmtQuad: layout = "quad"; break; @@ -962,6 +952,11 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf case DevFmtAmbi3D: break; } + + const char *devname{device->DeviceName.c_str()}; + ALsizei speakermap[MAX_OUTPUT_CHANNELS]; + AmbDecConf *pconf{nullptr}; + AmbDecConf conf{}; if(layout) { const char *fname; @@ -969,17 +964,11 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf { if(!conf.load(fname)) ERR("Failed to load layout file %s\n", fname); - else - { - if(conf.ChanMask > AMBI_3ORDER_MASK) - ERR("Unsupported channel mask 0x%04x (max 0x%x)\n", conf.ChanMask, - AMBI_3ORDER_MASK); - else - { - if(MakeSpeakerMap(device, &conf, speakermap)) - pconf = &conf; - } - } + else if(conf.ChanMask > AMBI_3ORDER_MASK) + ERR("Unsupported channel mask 0x%04x (max 0x%x)\n", conf.ChanMask, + AMBI_3ORDER_MASK); + else if(MakeSpeakerMap(device, &conf, speakermap)) + pconf = &conf; } } @@ -1014,7 +1003,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf case DevFmtX51Rear: case DevFmtX61: case DevFmtX71: - if(GetConfigValueBool(devname, NULL, "front-stablizer", 0)) + if(GetConfigValueBool(devname, nullptr, "front-stablizer", 0)) { /* Initialize band-splitting filters for the front-left and * front-right channels, with a crossover at 5khz (could be @@ -1051,7 +1040,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(device->Type != Loopback) { const char *mode; - if(ConfigValueStr(device->DeviceName.c_str(), NULL, "stereo-mode", &mode)) + if(ConfigValueStr(device->DeviceName.c_str(), nullptr, "stereo-mode", &mode)) { if(strcasecmp(mode, "headphones") == 0) headphones = true; @@ -1089,7 +1078,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(hrtf_id >= 0 && (size_t)hrtf_id < device->HrtfList.size()) { const EnumeratedHrtf &entry = device->HrtfList[hrtf_id]; - struct Hrtf *hrtf = GetLoadedHrtf(entry.hrtf); + Hrtf *hrtf{GetLoadedHrtf(entry.hrtf)}; if(hrtf && hrtf->sampleRate == device->Frequency) { device->HrtfHandle = hrtf; @@ -1103,7 +1092,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf { auto find_hrtf = [device](const EnumeratedHrtf &entry) -> bool { - struct Hrtf *hrtf = GetLoadedHrtf(entry.hrtf); + Hrtf *hrtf{GetLoadedHrtf(entry.hrtf)}; if(!hrtf) return false; if(hrtf->sampleRate != device->Frequency) { @@ -1121,11 +1110,11 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf { if(old_hrtf) Hrtf_DecRef(old_hrtf); - old_hrtf = NULL; + old_hrtf = nullptr; device->Render_Mode = HrtfRender; const char *mode; - if(ConfigValueStr(device->DeviceName.c_str(), NULL, "hrtf-mode", &mode)) + if(ConfigValueStr(device->DeviceName.c_str(), nullptr, "hrtf-mode", &mode)) { if(strcasecmp(mode, "full") == 0) device->Render_Mode = HrtfRender; @@ -1169,7 +1158,7 @@ no_hrtf: int bs2blevel{((headphones && hrtf_appreq != Hrtf_Disable) || (hrtf_appreq == Hrtf_Enable)) ? 5 : 0}; if(device->Type != Loopback) - ConfigValueInt(device->DeviceName.c_str(), NULL, "cf_level", &bs2blevel); + ConfigValueInt(device->DeviceName.c_str(), nullptr, "cf_level", &bs2blevel); if(bs2blevel > 0 && bs2blevel <= 6) { device->Bs2b.reset(new bs2b{}); @@ -1182,7 +1171,7 @@ no_hrtf: TRACE("BS2B disabled\n"); const char *mode; - if(ConfigValueStr(device->DeviceName.c_str(), NULL, "stereo-encoding", &mode)) + if(ConfigValueStr(device->DeviceName.c_str(), nullptr, "stereo-encoding", &mode)) { if(strcasecmp(mode, "uhj") == 0) device->Render_Mode = NormalRender; @@ -1204,11 +1193,9 @@ no_hrtf: void aluInitEffectPanning(ALeffectslot *slot) { - ALsizei i{0}; - for(auto &chanmap : slot->ChanMap) - { - chanmap.Scale = 1.0f; - chanmap.Index = i++; - } - slot->NumChannels = i; + const size_t count{countof(slot->ChanMap)}; + std::transform(std::begin(ACN2ACN), std::begin(ACN2ACN)+count, std::begin(slot->ChanMap), + [](const ALsizei &acn) noexcept { return BFChannelConfig{1.0f, acn}; } + ); + slot->NumChannels = static_cast(count); } -- cgit v1.2.3 From 640c06c292632f2ac78d349b0ad3b8b5f000c61a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2018 01:48:54 -0800 Subject: Avoid some explicit loop counts --- Alc/alc.cpp | 12 ++++------- Alc/effects/reverb.cpp | 58 ++++++++++++++++++++------------------------------ 2 files changed, 27 insertions(+), 43 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 5ef486cf..2a76c846 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1359,10 +1359,8 @@ static ALCboolean IsValidAmbiScaling(ALCenum scaling) */ void SetDefaultWFXChannelOrder(ALCdevice *device) { - ALsizei i; - - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - device->RealOut.ChannelName[i] = InvalidChannel; + std::fill(std::begin(device->RealOut.ChannelName), std::end(device->RealOut.ChannelName), + InvalidChannel); switch(device->FmtChans) { @@ -1450,10 +1448,8 @@ void SetDefaultWFXChannelOrder(ALCdevice *device) */ void SetDefaultChannelOrder(ALCdevice *device) { - ALsizei i; - - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - device->RealOut.ChannelName[i] = InvalidChannel; + std::fill(std::begin(device->RealOut.ChannelName), std::end(device->RealOut.ChannelName), + InvalidChannel); switch(device->FmtChans) { diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 70324dad..67945b27 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -458,15 +458,13 @@ static ALboolean AllocLines(const ALuint frequency, ReverbState *State) ALboolean ReverbState::deviceUpdate(ALCdevice *Device) { - ALuint frequency = Device->Frequency; - ALfloat multiplier; - ALsizei i, j; + const ALuint frequency{Device->Frequency}; /* Allocate the delay lines. */ if(!AllocLines(frequency, this)) return AL_FALSE; - multiplier = CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY); + const ALfloat multiplier{CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY)}; /* The late feed taps are set a fixed position past the latest delay tap. */ mLateFeedTap = float2int((AL_EAXREVERB_MAX_REFLECTIONS_DELAY + @@ -476,49 +474,39 @@ ALboolean ReverbState::deviceUpdate(ALCdevice *Device) /* Clear filters and gain coefficients since the delay lines were all just * cleared (if not reallocated). */ - for(i = 0;i < NUM_LINES;i++) - { - mFilter[i].Lp.clear(); - mFilter[i].Hp.clear(); - } - - for(i = 0;i < NUM_LINES;i++) + for(auto &filter : mFilter) { - mEarlyDelayCoeff[i][0] = 0.0f; - mEarlyDelayCoeff[i][1] = 0.0f; + filter.Lp.clear(); + filter.Hp.clear(); } - for(i = 0;i < NUM_LINES;i++) - { - mEarly.Coeff[i][0] = 0.0f; - mEarly.Coeff[i][1] = 0.0f; - } + for(auto &coeff : mEarlyDelayCoeff) + std::fill(std::begin(coeff), std::end(coeff), 0.0f); + for(auto &coeff : mEarly.Coeff) + std::fill(std::begin(coeff), std::end(coeff), 0.0f); mLate.DensityGain[0] = 0.0f; mLate.DensityGain[1] = 0.0f; - for(i = 0;i < NUM_LINES;i++) + for(auto &t60 : mLate.T60) { - mLate.T60[i].MidGain[0] = 0.0f; - mLate.T60[i].MidGain[1] = 0.0f; - mLate.T60[i].HFFilter.clear(); - mLate.T60[i].LFFilter.clear(); + t60.MidGain[0] = 0.0f; + t60.MidGain[1] = 0.0f; + t60.HFFilter.clear(); + t60.LFFilter.clear(); } - for(i = 0;i < NUM_LINES;i++) - { - for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - { - mEarly.CurrentGain[i][j] = 0.0f; - mEarly.PanGain[i][j] = 0.0f; - mLate.CurrentGain[i][j] = 0.0f; - mLate.PanGain[i][j] = 0.0f; - } - } + for(auto &gains : mEarly.CurrentGain) + std::fill(std::begin(gains), std::end(gains), 0.0f); + for(auto &gains : mEarly.PanGain) + std::fill(std::begin(gains), std::end(gains), 0.0f); + for(auto &gains : mLate.CurrentGain) + std::fill(std::begin(gains), std::end(gains), 0.0f); + for(auto &gains : mLate.PanGain) + std::fill(std::begin(gains), std::end(gains), 0.0f); /* Reset counters and offset base. */ mFadeCount = 0; - mMaxUpdate[0] = MAX_UPDATE_SAMPLES; - mMaxUpdate[1] = MAX_UPDATE_SAMPLES; + std::fill(std::begin(mMaxUpdate), std::end(mMaxUpdate), MAX_UPDATE_SAMPLES); mOffset = 0; return AL_TRUE; -- cgit v1.2.3 From 0dd13a9dfed47660946fa9d37a1fc35e44b73687 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2018 02:42:04 -0800 Subject: Make the AmbDec speaker and matrix arrays dynamic --- Alc/ambdec.cpp | 86 ++++++++++++++++++++++++++++-------------------------- Alc/ambdec.h | 31 +++++++++++--------- Alc/bformatdec.cpp | 6 ++-- Alc/panning.cpp | 23 ++++++++------- 4 files changed, 76 insertions(+), 70 deletions(-) diff --git a/Alc/ambdec.cpp b/Alc/ambdec.cpp index 66fc2255..8b251187 100644 --- a/Alc/ambdec.cpp +++ b/Alc/ambdec.cpp @@ -3,8 +3,9 @@ #include "ambdec.h" -#include #include +#include +#include #include #include @@ -61,10 +62,9 @@ bool is_at_end(const std::string &buffer, std::size_t endpos) } -bool load_ambdec_speakers(AmbDecConf *conf, std::istream &f, std::string &buffer) +bool load_ambdec_speakers(al::vector &spkrs, const std::size_t num_speakers, std::istream &f, std::string &buffer) { - ALsizei cur = 0; - while(cur < conf->NumSpeakers) + while(spkrs.size() < num_speakers) { std::istringstream istr{buffer}; @@ -81,18 +81,20 @@ bool load_ambdec_speakers(AmbDecConf *conf, std::istream &f, std::string &buffer if(cmd == "add_spkr") { - istr >> conf->Speakers[cur].Name; - if(istr.fail()) WARN("Name not specified for speaker %u\n", cur+1); - istr >> conf->Speakers[cur].Distance; - if(istr.fail()) WARN("Distance not specified for speaker %u\n", cur+1); - istr >> conf->Speakers[cur].Azimuth; - if(istr.fail()) WARN("Azimuth not specified for speaker %u\n", cur+1); - istr >> conf->Speakers[cur].Elevation; - if(istr.fail()) WARN("Elevation not specified for speaker %u\n", cur+1); - istr >> conf->Speakers[cur].Connection; - if(istr.fail()) TRACE("Connection not specified for speaker %u\n", cur+1); - - cur++; + spkrs.emplace_back(); + AmbDecConf::SpeakerConf &spkr = spkrs.back(); + const size_t spkr_num{spkrs.size()}; + + istr >> spkr.Name; + if(istr.fail()) WARN("Name not specified for speaker " SZFMT "\n", spkr_num); + istr >> spkr.Distance; + if(istr.fail()) WARN("Distance not specified for speaker " SZFMT "\n", spkr_num); + istr >> spkr.Azimuth; + if(istr.fail()) WARN("Azimuth not specified for speaker " SZFMT "\n", spkr_num); + istr >> spkr.Elevation; + if(istr.fail()) WARN("Elevation not specified for speaker " SZFMT "\n", spkr_num); + istr >> spkr.Connection; + if(istr.fail()) TRACE("Connection not specified for speaker " SZFMT "\n", spkr_num); } else { @@ -113,10 +115,10 @@ bool load_ambdec_speakers(AmbDecConf *conf, std::istream &f, std::string &buffer return true; } -bool load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsizei maxrow, std::istream &f, std::string &buffer) +bool load_ambdec_matrix(float (&gains)[MAX_AMBI_ORDER+1], al::vector &matrix, const std::size_t maxrow, std::istream &f, std::string &buffer) { - bool gotgains = false; - ALsizei cur = 0; + bool gotgains{false}; + std::size_t cur{0u}; while(cur < maxrow) { std::istringstream istr{buffer}; @@ -134,7 +136,7 @@ bool load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsi if(cmd == "order_gain") { - ALuint curgain = 0; + std::size_t curgain{0u}; float value; while(istr.good()) { @@ -142,36 +144,37 @@ bool load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsi if(istr.fail()) break; if(!istr.eof() && !std::isspace(istr.peek())) { - ERR("Extra junk on gain %u: %s\n", curgain+1, + ERR("Extra junk on gain " SZFMT ": %s\n", curgain+1, buffer.c_str()+static_cast(istr.tellg())); return false; } - if(curgain < MAX_AMBI_ORDER+1) + if(curgain < countof(gains)) gains[curgain++] = value; } - while(curgain < MAX_AMBI_ORDER+1) - gains[curgain++] = 0.0f; + std::fill(std::begin(gains)+curgain, std::end(gains), 0.0f); gotgains = true; } else if(cmd == "add_row") { - ALuint curidx = 0; - float value; + matrix.emplace_back(); + AmbDecConf::CoeffArray &mtxrow = matrix.back(); + std::size_t curidx{0u}; + float value{}; while(istr.good()) { istr >> value; if(istr.fail()) break; if(!istr.eof() && !std::isspace(istr.peek())) { - ERR("Extra junk on matrix element %ux%u: %s\n", cur, curidx, - buffer.c_str()+static_cast(istr.tellg())); + ERR("Extra junk on matrix element " SZFMT "x" SZFMT ": %s\n", curidx, + matrix.size(), buffer.c_str()+static_cast(istr.tellg())); + matrix.pop_back(); return false; } - if(curidx < MAX_AMBI_COEFFS) - matrix[cur][curidx++] = value; + if(curidx < mtxrow.size()) + mtxrow[curidx++] = value; } - while(curidx < MAX_AMBI_COEFFS) - matrix[cur][curidx++] = 0.0f; + std::fill(mtxrow.begin()+curidx, mtxrow.end(), 0.0f); cur++; } else @@ -210,6 +213,7 @@ int AmbDecConf::load(const char *fname) noexcept return 0; } + std::size_t num_speakers{0u}; std::string buffer; while(read_clipped_line(f, buffer)) { @@ -266,18 +270,16 @@ int AmbDecConf::load(const char *fname) noexcept } else if(command == "/dec/speakers") { - istr >> NumSpeakers; + istr >> num_speakers; if(!istr.eof() && !std::isspace(istr.peek())) { ERR("Extra junk after speakers: %s\n", buffer.c_str()+static_cast(istr.tellg())); return 0; } - if(NumSpeakers > MAX_OUTPUT_CHANNELS) - { - ERR("Unsupported speaker count: %u\n", NumSpeakers); - return 0; - } + Speakers.reserve(num_speakers); + LFMatrix.reserve(num_speakers); + HFMatrix.reserve(num_speakers); } else if(command == "/dec/coeff_scale") { @@ -327,7 +329,7 @@ int AmbDecConf::load(const char *fname) noexcept } buffer.clear(); - if(!load_ambdec_speakers(this, f, buffer)) + if(!load_ambdec_speakers(Speakers, num_speakers, f, buffer)) return 0; if(!read_clipped_line(f, buffer)) @@ -361,19 +363,19 @@ int AmbDecConf::load(const char *fname) noexcept ERR("Unexpected \"%s\" type for a single-band decoder\n", command.c_str()); return 0; } - if(!load_ambdec_matrix(HFOrderGain, HFMatrix, NumSpeakers, f, buffer)) + if(!load_ambdec_matrix(HFOrderGain, HFMatrix, num_speakers, f, buffer)) return 0; } else { if(command == "/lfmatrix/{") { - if(!load_ambdec_matrix(LFOrderGain, LFMatrix, NumSpeakers, f, buffer)) + if(!load_ambdec_matrix(LFOrderGain, LFMatrix, num_speakers, f, buffer)) return 0; } else if(command == "/hfmatrix/{") { - if(!load_ambdec_matrix(HFOrderGain, HFMatrix, NumSpeakers, f, buffer)) + if(!load_ambdec_matrix(HFOrderGain, HFMatrix, num_speakers, f, buffer)) return 0; } else diff --git a/Alc/ambdec.h b/Alc/ambdec.h index 99caf9a2..5ec5eb0c 100644 --- a/Alc/ambdec.h +++ b/Alc/ambdec.h @@ -1,9 +1,11 @@ #ifndef AMBDEC_H #define AMBDEC_H +#include #include #include "alMain.h" +#include "vector.h" /* Helpers to read .ambdec configuration files. */ @@ -14,30 +16,31 @@ enum class AmbDecScale { }; struct AmbDecConf { std::string Description; - ALuint Version; /* Must be 3 */ + int Version; /* Must be 3 */ - ALuint ChanMask; - ALuint FreqBands; /* Must be 1 or 2 */ - ALsizei NumSpeakers; + unsigned int ChanMask; + unsigned int FreqBands; /* Must be 1 or 2 */ AmbDecScale CoeffScale; - ALfloat XOverFreq; - ALfloat XOverRatio; + float XOverFreq; + float XOverRatio; struct SpeakerConf { std::string Name; - ALfloat Distance; - ALfloat Azimuth; - ALfloat Elevation; + float Distance{0.0f}; + float Azimuth{0.0f}; + float Elevation{0.0f}; std::string Connection; - } Speakers[MAX_OUTPUT_CHANNELS]; + }; + al::vector Speakers; + using CoeffArray = std::array; /* Unused when FreqBands == 1 */ - ALfloat LFOrderGain[MAX_AMBI_ORDER+1]; - ALfloat LFMatrix[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; + float LFOrderGain[MAX_AMBI_ORDER+1]; + al::vector LFMatrix; - ALfloat HFOrderGain[MAX_AMBI_ORDER+1]; - ALfloat HFMatrix[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; + float HFOrderGain[MAX_AMBI_ORDER+1]; + al::vector HFMatrix; int load(const char *fname) noexcept; }; diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 882184a3..d92c84db 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -91,7 +91,7 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, mSamplesHF = mSamples.data(); mSamplesLF = mSamplesHF + chancount; - mEnabled = std::accumulate(std::begin(chanmap), std::begin(chanmap)+conf->NumSpeakers, 0u, + mEnabled = std::accumulate(std::begin(chanmap), std::begin(chanmap)+conf->Speakers.size(), 0u, [](ALuint mask, const ALsizei &chan) noexcept -> ALuint { return mask | (1 << chan); } ); @@ -139,7 +139,7 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, mDualBand = (conf->FreqBands == 2); if(!mDualBand) { - for(ALsizei i{0};i < conf->NumSpeakers;i++) + for(size_t i{0u};i < conf->Speakers.size();i++) { ALfloat (&mtx)[MAX_AMBI_COEFFS] = mMatrix.Single[chanmap[i]]; for(ALsizei j{0},k{0};j < coeff_count;j++) @@ -160,7 +160,7 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, std::fill(std::begin(mXOver)+1, std::end(mXOver), mXOver[0]); const float ratio{std::pow(10.0f, conf->XOverRatio / 40.0f)}; - for(ALsizei i{0};i < conf->NumSpeakers;i++) + for(size_t i{0u};i < conf->Speakers.size();i++) { ALfloat (&mtx)[sNumBands][MAX_AMBI_COEFFS] = mMatrix.Dual[chanmap[i]]; for(ALsizei j{0},k{0};j < coeff_count;j++) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index e854a966..bf0c1931 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -119,7 +119,7 @@ struct ChannelMap { }; void SetChannelMap(const Channel (&devchans)[MAX_OUTPUT_CHANNELS], ChannelConfig *ambicoeffs, - const ChannelMap *chanmap, ALsizei count, ALsizei *outcount) + const ChannelMap *chanmap, const size_t count, ALsizei *outcount) { auto copy_coeffs = [&devchans,ambicoeffs](ALsizei maxchans, const ChannelMap &channel) -> ALsizei { @@ -217,10 +217,9 @@ bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei (&speaker ERR("Failed to lookup AmbDec speaker label %s\n", speaker.Name.c_str()); return chidx; }; - auto speakers_end = std::begin(conf->Speakers) + conf->NumSpeakers; - std::transform(std::begin(conf->Speakers), speakers_end, std::begin(speakermap), map_spkr); + std::transform(conf->Speakers.begin(), conf->Speakers.end(), std::begin(speakermap), map_spkr); /* Return success if no invalid entries are found. */ - auto speakermap_end = std::begin(speakermap) + conf->NumSpeakers; + auto speakermap_end = std::begin(speakermap) + conf->Speakers.size(); return std::find(std::begin(speakermap), speakermap_end, -1) == speakermap_end; } @@ -281,9 +280,8 @@ void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei ( { using namespace std::placeholders; - auto speakers_end = std::begin(conf->Speakers) + conf->NumSpeakers; const ALfloat maxdist{ - std::accumulate(std::begin(conf->Speakers), speakers_end, float{0.0f}, + std::accumulate(conf->Speakers.begin(), conf->Speakers.end(), float{0.0f}, std::bind(maxf, _1, std::bind(std::mem_fn(&AmbDecConf::SpeakerConf::Distance), _2)) ) }; @@ -294,7 +292,7 @@ void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei ( auto srate = static_cast(device->Frequency); size_t total{0u}; - for(ALsizei i{0};i < conf->NumSpeakers;i++) + for(size_t i{0u};i < conf->Speakers.size();i++) { const AmbDecConf::SpeakerConf &speaker = conf->Speakers[i]; const ALsizei chan{speakermap[i]}; @@ -536,7 +534,7 @@ void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei const ALfloat (&coeff_scale)[MAX_AMBI_COEFFS] = GetAmbiScales(conf->CoeffScale); ChannelMap chanmap[MAX_OUTPUT_CHANNELS]{}; - for(ALsizei i{0};i < conf->NumSpeakers;i++) + for(size_t i{0u};i < conf->Speakers.size();i++) { chanmap[i].ChanName = device->RealOut.ChannelName[speakermap[i]]; std::fill(std::begin(chanmap[i].Config), std::end(chanmap[i].Config), 0.0f); @@ -553,7 +551,7 @@ void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei } SetChannelMap(device->RealOut.ChannelName, device->Dry.Ambi.Coeffs, chanmap, - conf->NumSpeakers, &device->Dry.NumChannels); + conf->Speakers.size(), &device->Dry.NumChannels); device->Dry.CoeffCount = (conf->ChanMask > AMBI_2ORDER_MASK) ? 16 : (conf->ChanMask > AMBI_1ORDER_MASK) ? 9 : 4; @@ -643,8 +641,8 @@ void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&sp std::plus{}, _1, std::bind(std::mem_fn(&AmbDecConf::SpeakerConf::Distance), _2) ); const ALfloat avg_dist{ - std::accumulate(std::begin(conf->Speakers), std::begin(conf->Speakers)+conf->NumSpeakers, - float{0.0f}, accum_spkr_dist) / (ALfloat)conf->NumSpeakers + std::accumulate(conf->Speakers.begin(), conf->Speakers.end(), float{0.0f}, + accum_spkr_dist) / static_cast(conf->Speakers.size()) }; InitNearFieldCtrl(device, avg_dist, (conf->ChanMask > AMBI_2ORDER_MASK) ? 3 : @@ -964,6 +962,9 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr { if(!conf.load(fname)) ERR("Failed to load layout file %s\n", fname); + else if(conf.Speakers.size() > MAX_OUTPUT_CHANNELS) + ERR("Unsupported speaker count " SZFMT " (max %d)\n", conf.Speakers.size(), + MAX_OUTPUT_CHANNELS); else if(conf.ChanMask > AMBI_3ORDER_MASK) ERR("Unsupported channel mask 0x%04x (max 0x%x)\n", conf.ChanMask, AMBI_3ORDER_MASK); -- cgit v1.2.3 From e0f635b20d989a5083112aa70960cc89e6bc553c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2018 03:30:47 -0800 Subject: Move some ambisonic-related macros to a separate header --- Alc/ambdec.cpp | 7 ++++++- Alc/ambdec.h | 18 +++++++++--------- Alc/ambidefs.h | 33 +++++++++++++++++++++++++++++++++ Alc/logging.h | 8 ++++++++ CMakeLists.txt | 1 + OpenAL32/Include/alMain.h | 38 +------------------------------------- 6 files changed, 58 insertions(+), 47 deletions(-) create mode 100644 Alc/ambidefs.h diff --git a/Alc/ambdec.cpp b/Alc/ambdec.cpp index 8b251187..e37a5a09 100644 --- a/Alc/ambdec.cpp +++ b/Alc/ambdec.cpp @@ -12,11 +12,16 @@ #include #include +#include "logging.h" #include "compat.h" namespace { +template +constexpr inline std::size_t size(const T(&)[N]) noexcept +{ return N; } + int readline(std::istream &f, std::string &output) { while(f.good() && f.peek() == '\n') @@ -148,7 +153,7 @@ bool load_ambdec_matrix(float (&gains)[MAX_AMBI_ORDER+1], al::vector(istr.tellg())); return false; } - if(curgain < countof(gains)) + if(curgain < size(gains)) gains[curgain++] = value; } std::fill(std::begin(gains)+curgain, std::end(gains), 0.0f); diff --git a/Alc/ambdec.h b/Alc/ambdec.h index 5ec5eb0c..1629c14d 100644 --- a/Alc/ambdec.h +++ b/Alc/ambdec.h @@ -4,7 +4,7 @@ #include #include -#include "alMain.h" +#include "ambidefs.h" #include "vector.h" /* Helpers to read .ambdec configuration files. */ @@ -16,14 +16,14 @@ enum class AmbDecScale { }; struct AmbDecConf { std::string Description; - int Version; /* Must be 3 */ + int Version{0}; /* Must be 3 */ - unsigned int ChanMask; - unsigned int FreqBands; /* Must be 1 or 2 */ - AmbDecScale CoeffScale; + unsigned int ChanMask{0u}; + unsigned int FreqBands{0u}; /* Must be 1 or 2 */ + AmbDecScale CoeffScale{}; - float XOverFreq; - float XOverRatio; + float XOverFreq{0.0f}; + float XOverRatio{0.0f}; struct SpeakerConf { std::string Name; @@ -36,10 +36,10 @@ struct AmbDecConf { using CoeffArray = std::array; /* Unused when FreqBands == 1 */ - float LFOrderGain[MAX_AMBI_ORDER+1]; + float LFOrderGain[MAX_AMBI_ORDER+1]{}; al::vector LFMatrix; - float HFOrderGain[MAX_AMBI_ORDER+1]; + float HFOrderGain[MAX_AMBI_ORDER+1]{}; al::vector HFMatrix; int load(const char *fname) noexcept; diff --git a/Alc/ambidefs.h b/Alc/ambidefs.h new file mode 100644 index 00000000..124a0c8e --- /dev/null +++ b/Alc/ambidefs.h @@ -0,0 +1,33 @@ +#ifndef AMBIDEFS_H +#define AMBIDEFS_H + +/* The maximum number of Ambisonics coefficients. For a given order (o), the + * size needed will be (o+1)**2, thus zero-order has 1, first-order has 4, + * second-order has 9, third-order has 16, and fourth-order has 25. + */ +#define MAX_AMBI_ORDER 3 +#define MAX_AMBI_COEFFS ((MAX_AMBI_ORDER+1) * (MAX_AMBI_ORDER+1)) + +/* A bitmask of ambisonic channels for 0 to 4th order. This only specifies up + * to 4th order, which is the highest order a 32-bit mask value can specify (a + * 64-bit mask could handle up to 7th order). + */ +#define AMBI_0ORDER_MASK 0x00000001 +#define AMBI_1ORDER_MASK 0x0000000f +#define AMBI_2ORDER_MASK 0x000001ff +#define AMBI_3ORDER_MASK 0x0000ffff +#define AMBI_4ORDER_MASK 0x01ffffff + +/* A bitmask of ambisonic channels with height information. If none of these + * channels are used/needed, there's no height (e.g. with most surround sound + * speaker setups). This is ACN ordering, with bit 0 being ACN 0, etc. + */ +#define AMBI_PERIPHONIC_MASK (0xfe7ce4) + +/* The maximum number of Ambisonic coefficients for 2D (non-periphonic) + * representation. This is 2 per each order above zero-order, plus 1 for zero- + * order. Or simply, o*2 + 1. + */ +#define MAX_AMBI2D_COEFFS (MAX_AMBI_ORDER*2 + 1) + +#endif /* AMBIDEFS_H */ diff --git a/Alc/logging.h b/Alc/logging.h index f493d973..41f64f77 100644 --- a/Alc/logging.h +++ b/Alc/logging.h @@ -4,6 +4,14 @@ #include +#if defined(_WIN64) +#define SZFMT "%I64u" +#elif defined(_WIN32) +#define SZFMT "%u" +#else +#define SZFMT "%zu" +#endif + #ifdef __GNUC__ #define DECL_FORMAT(x, y, z) __attribute__((format(x, (y), (z)))) #else diff --git a/CMakeLists.txt b/CMakeLists.txt index 25392911..4e1d0081 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -730,6 +730,7 @@ SET(ALC_OBJS Alc/alconfig.cpp Alc/alconfig.h Alc/alcontext.h + Alc/ambidefs.h Alc/bs2b.cpp Alc/bs2b.h Alc/converter.cpp diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 8eafa6a4..9d2e7bfc 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -33,6 +33,7 @@ #include "vector.h" #include "almalloc.h" #include "threads.h" +#include "ambidefs.h" template @@ -40,13 +41,6 @@ constexpr inline size_t countof(const T(&)[N]) noexcept { return N; } #define COUNTOF countof -#if defined(_WIN64) -#define SZFMT "%I64u" -#elif defined(_WIN32) -#define SZFMT "%u" -#else -#define SZFMT "%zu" -#endif #ifdef __has_builtin #define HAS_BUILTIN __has_builtin @@ -543,36 +537,6 @@ enum RenderMode { }; -/* The maximum number of Ambisonics coefficients. For a given order (o), the - * size needed will be (o+1)**2, thus zero-order has 1, first-order has 4, - * second-order has 9, third-order has 16, and fourth-order has 25. - */ -#define MAX_AMBI_ORDER 3 -#define MAX_AMBI_COEFFS ((MAX_AMBI_ORDER+1) * (MAX_AMBI_ORDER+1)) - -/* A bitmask of ambisonic channels for 0 to 4th order. This only specifies up - * to 4th order, which is the highest order a 32-bit mask value can specify (a - * 64-bit mask could handle up to 7th order). - */ -#define AMBI_0ORDER_MASK 0x00000001 -#define AMBI_1ORDER_MASK 0x0000000f -#define AMBI_2ORDER_MASK 0x000001ff -#define AMBI_3ORDER_MASK 0x0000ffff -#define AMBI_4ORDER_MASK 0x01ffffff - -/* A bitmask of ambisonic channels with height information. If none of these - * channels are used/needed, there's no height (e.g. with most surround sound - * speaker setups). This is ACN ordering, with bit 0 being ACN 0, etc. - */ -#define AMBI_PERIPHONIC_MASK (0xfe7ce4) - -/* The maximum number of Ambisonic coefficients for 2D (non-periphonic) - * representation. This is 2 per each order above zero-order, plus 1 for zero- - * order. Or simply, o*2 + 1. - */ -#define MAX_AMBI2D_COEFFS (MAX_AMBI_ORDER*2 + 1) - - typedef ALfloat ChannelConfig[MAX_AMBI_COEFFS]; typedef struct BFChannelConfig { ALfloat Scale; -- cgit v1.2.3 From dea077cbae1f180a5c7ee77517ea73901f59aff2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2018 19:23:42 -0800 Subject: Add encoding calculations for fourth-order ambisonics --- Alc/panning.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index bf0c1931..cffb6e46 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -819,6 +819,16 @@ void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALf coeffs[13] = 1.620185175f * x * (5.0f*z*z - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */ coeffs[14] = 5.123475383f * z * (x*x - y*y); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */ coeffs[15] = 2.091650066f * x * (x*x - 3.0f*y*y); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */ + /* Fourth-order */ + /* ACN 16 = sqrt(35)*3/2 * X * Y * (X*X - Y*Y) */ + /* ACN 17 = sqrt(35/2)*3/2 * (3*X*X - Y*Y) * Y * Z */ + /* ACN 18 = sqrt(5)*3/2 * X * Y * (7*Z*Z - 1) */ + /* ACN 19 = sqrt(5/2)*3/2 * Y * Z * (7*Z*Z - 3) */ + /* ACN 20 = 3/8 * (35*Z*Z*Z*Z - 30*Z*Z + 3) */ + /* ACN 21 = sqrt(5/2)*3/2 * X * Z * (7*Z*Z - 3) */ + /* ACN 22 = sqrt(5)*3/4 * (X*X - Y*Y) * (7*Z*Z - 1) */ + /* ACN 23 = sqrt(35/2)*3/2 * (X*X - 3*Y*Y) * X * Z */ + /* ACN 24 = sqrt(35)*3/8 * (X*X*X*X - 6*X*X*Y*Y + Y*Y*Y*Y) */ if(spread > 0.0f) { @@ -837,7 +847,7 @@ void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALf * ZH5 = -0.0625*sqrt(pi) * (-1+ca)*(ca+1)*(21*ca*ca*ca*ca - 14*ca*ca + 1); * * The gain of the source is compensated for size, so that the - * loundness doesn't depend on the spread. Thus: + * loudness doesn't depend on the spread. Thus: * * ZH0 = 1.0f; * ZH1 = 0.5f * (ca+1.0f); -- cgit v1.2.3 From a6a5634adb1bdec44fa7cb8557e5b6d59642d7aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2018 20:28:52 -0800 Subject: Reorder some math terms to help optimizations Because floating-point math is not associative ((a*b)*c does not necessarily give the same result as a*(b*c)), the ordering of terms can inhibit reuse of temporary values. For example, both coeffs[9] = 2.091650066f * y * (3.0f*x*x - y*y); and coeffs[15] = 2.091650066f * x * (x*x - 3.0f*y*y); contain x*x and y*y terms that could be calculated once, stored in temporary registers, and reused to multiply with 3. But since 3.0f*(x*x) would produce different results, the compiler is not allowed to make that optimization. If, however, the multiply with 3 is moved to the right side: coeffs[9] = 2.091650066f * y * (x*x*3.0f - y*y); and coeffs[15] = 2.091650066f * x * (x*x - y*y*3.0f); in both cases x*x and y*y are calculated first in their respective groups, guaranteeing the same results for both instances prior to the multiply with 3 and allowing the compiler to reuse those intermediate values. --- Alc/panning.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index cffb6e46..37559620 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -808,17 +808,17 @@ void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALf /* Second-order */ coeffs[4] = 3.872983346f * x * y; /* ACN 4 = sqrt(15) * X * Y */ coeffs[5] = 3.872983346f * y * z; /* ACN 5 = sqrt(15) * Y * Z */ - coeffs[6] = 1.118033989f * (3.0f*z*z - 1.0f); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */ + coeffs[6] = 1.118033989f * (z*z*3.0f - 1.0f); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */ coeffs[7] = 3.872983346f * x * z; /* ACN 7 = sqrt(15) * X * Z */ coeffs[8] = 1.936491673f * (x*x - y*y); /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */ /* Third-order */ - coeffs[9] = 2.091650066f * y * (3.0f*x*x - y*y); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */ + coeffs[9] = 2.091650066f * y * (x*x*3.0f - y*y); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */ coeffs[10] = 10.246950766f * z * x * y; /* ACN 10 = sqrt(105) * Z * X * Y */ - coeffs[11] = 1.620185175f * y * (5.0f*z*z - 1.0f); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */ - coeffs[12] = 1.322875656f * z * (5.0f*z*z - 3.0f); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */ - coeffs[13] = 1.620185175f * x * (5.0f*z*z - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */ + coeffs[11] = 1.620185175f * y * (z*z*5.0f - 1.0f); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */ + coeffs[12] = 1.322875656f * z * (z*z*5.0f - 3.0f); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */ + coeffs[13] = 1.620185175f * x * (z*z*5.0f - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */ coeffs[14] = 5.123475383f * z * (x*x - y*y); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */ - coeffs[15] = 2.091650066f * x * (x*x - 3.0f*y*y); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */ + coeffs[15] = 2.091650066f * x * (x*x - y*y*3.0f); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */ /* Fourth-order */ /* ACN 16 = sqrt(35)*3/2 * X * Y * (X*X - Y*Y) */ /* ACN 17 = sqrt(35/2)*3/2 * (3*X*X - Y*Y) * Y * Z */ -- cgit v1.2.3 From 741861eaa62bd555255f19467fa115a12b7fd577 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2018 23:28:49 -0800 Subject: Put the ACN index map in a header Also put it and the Ambisonic scales in a more appropriate header. --- Alc/ambidefs.h | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ Alc/bformatdec.cpp | 5 ---- Alc/bformatdec.h | 47 ----------------------------------- Alc/panning.cpp | 46 ++++++++++++---------------------- 4 files changed, 88 insertions(+), 82 deletions(-) diff --git a/Alc/ambidefs.h b/Alc/ambidefs.h index 124a0c8e..bdeac18e 100644 --- a/Alc/ambidefs.h +++ b/Alc/ambidefs.h @@ -30,4 +30,76 @@ */ #define MAX_AMBI2D_COEFFS (MAX_AMBI_ORDER*2 + 1) + +/* NOTE: These are scale factors as applied to Ambisonics content. Decoder + * coefficients should be divided by these values to get proper N3D scalings. + */ +struct AmbiScale { + static constexpr float N3D2N3D[MAX_AMBI_COEFFS]{ + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f + }; + static constexpr float SN3D2N3D[MAX_AMBI_COEFFS]{ + 1.000000000f, /* ACN 0, sqrt(1) */ + 1.732050808f, /* ACN 1, sqrt(3) */ + 1.732050808f, /* ACN 2, sqrt(3) */ + 1.732050808f, /* ACN 3, sqrt(3) */ + 2.236067978f, /* ACN 4, sqrt(5) */ + 2.236067978f, /* ACN 5, sqrt(5) */ + 2.236067978f, /* ACN 6, sqrt(5) */ + 2.236067978f, /* ACN 7, sqrt(5) */ + 2.236067978f, /* ACN 8, sqrt(5) */ + 2.645751311f, /* ACN 9, sqrt(7) */ + 2.645751311f, /* ACN 10, sqrt(7) */ + 2.645751311f, /* ACN 11, sqrt(7) */ + 2.645751311f, /* ACN 12, sqrt(7) */ + 2.645751311f, /* ACN 13, sqrt(7) */ + 2.645751311f, /* ACN 14, sqrt(7) */ + 2.645751311f, /* ACN 15, sqrt(7) */ + }; + static constexpr float FuMa2N3D[MAX_AMBI_COEFFS]{ + 1.414213562f, /* ACN 0 (W), sqrt(2) */ + 1.732050808f, /* ACN 1 (Y), sqrt(3) */ + 1.732050808f, /* ACN 2 (Z), sqrt(3) */ + 1.732050808f, /* ACN 3 (X), sqrt(3) */ + 1.936491673f, /* ACN 4 (V), sqrt(15)/2 */ + 1.936491673f, /* ACN 5 (T), sqrt(15)/2 */ + 2.236067978f, /* ACN 6 (R), sqrt(5) */ + 1.936491673f, /* ACN 7 (S), sqrt(15)/2 */ + 1.936491673f, /* ACN 8 (U), sqrt(15)/2 */ + 2.091650066f, /* ACN 9 (Q), sqrt(35/8) */ + 1.972026594f, /* ACN 10 (O), sqrt(35)/3 */ + 2.231093404f, /* ACN 11 (M), sqrt(224/45) */ + 2.645751311f, /* ACN 12 (K), sqrt(7) */ + 2.231093404f, /* ACN 13 (L), sqrt(224/45) */ + 1.972026594f, /* ACN 14 (N), sqrt(35)/3 */ + 2.091650066f, /* ACN 15 (P), sqrt(35/8) */ + }; +}; + +struct AmbiIndex { + static constexpr int FuMa2ACN[MAX_AMBI_COEFFS]{ + 0, /* W */ + 3, /* X */ + 1, /* Y */ + 2, /* Z */ + 6, /* R */ + 7, /* S */ + 5, /* T */ + 8, /* U */ + 4, /* V */ + 12, /* K */ + 13, /* L */ + 11, /* M */ + 14, /* N */ + 10, /* O */ + 15, /* P */ + 9, /* Q */ + }; + static constexpr int ACN2ACN[MAX_AMBI_COEFFS]{ + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 + }; +}; + #endif /* AMBIDEFS_H */ diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index d92c84db..9c6e3dff 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -17,11 +17,6 @@ #include "almalloc.h" -constexpr float AmbiScale::N3D2N3D[MAX_AMBI_COEFFS]; -constexpr float AmbiScale::SN3D2N3D[MAX_AMBI_COEFFS]; -constexpr float AmbiScale::FuMa2N3D[MAX_AMBI_COEFFS]; - - namespace { #define HF_BAND 0 diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index d855041d..4da5547e 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -26,53 +26,6 @@ struct AmbDecConf; #define XYZ_SCALE_3H3P 1.136697713f -/* NOTE: These are scale factors as applied to Ambisonics content. Decoder - * coefficients should be divided by these values to get proper N3D scalings. - */ -struct AmbiScale { - static constexpr float N3D2N3D[MAX_AMBI_COEFFS]{ - 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f - }; - static constexpr float SN3D2N3D[MAX_AMBI_COEFFS]{ - 1.000000000f, /* ACN 0 (W), sqrt(1) */ - 1.732050808f, /* ACN 1 (Y), sqrt(3) */ - 1.732050808f, /* ACN 2 (Z), sqrt(3) */ - 1.732050808f, /* ACN 3 (X), sqrt(3) */ - 2.236067978f, /* ACN 4 (V), sqrt(5) */ - 2.236067978f, /* ACN 5 (T), sqrt(5) */ - 2.236067978f, /* ACN 6 (R), sqrt(5) */ - 2.236067978f, /* ACN 7 (S), sqrt(5) */ - 2.236067978f, /* ACN 8 (U), sqrt(5) */ - 2.645751311f, /* ACN 9 (Q), sqrt(7) */ - 2.645751311f, /* ACN 10 (O), sqrt(7) */ - 2.645751311f, /* ACN 11 (M), sqrt(7) */ - 2.645751311f, /* ACN 12 (K), sqrt(7) */ - 2.645751311f, /* ACN 13 (L), sqrt(7) */ - 2.645751311f, /* ACN 14 (N), sqrt(7) */ - 2.645751311f, /* ACN 15 (P), sqrt(7) */ - }; - static constexpr float FuMa2N3D[MAX_AMBI_COEFFS]{ - 1.414213562f, /* ACN 0 (W), sqrt(2) */ - 1.732050808f, /* ACN 1 (Y), sqrt(3) */ - 1.732050808f, /* ACN 2 (Z), sqrt(3) */ - 1.732050808f, /* ACN 3 (X), sqrt(3) */ - 1.936491673f, /* ACN 4 (V), sqrt(15)/2 */ - 1.936491673f, /* ACN 5 (T), sqrt(15)/2 */ - 2.236067978f, /* ACN 6 (R), sqrt(5) */ - 1.936491673f, /* ACN 7 (S), sqrt(15)/2 */ - 1.936491673f, /* ACN 8 (U), sqrt(15)/2 */ - 2.091650066f, /* ACN 9 (Q), sqrt(35/8) */ - 1.972026594f, /* ACN 10 (O), sqrt(35)/3 */ - 2.231093404f, /* ACN 11 (M), sqrt(224/45) */ - 2.645751311f, /* ACN 12 (K), sqrt(7) */ - 2.231093404f, /* ACN 13 (L), sqrt(224/45) */ - 1.972026594f, /* ACN 14 (N), sqrt(35)/3 */ - 2.091650066f, /* ACN 15 (P), sqrt(35/8) */ - }; -}; - - class BFormatDec { public: static constexpr size_t sNumBands{2}; diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 37559620..3ea0ae06 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -42,30 +42,14 @@ #include "bs2b.h" -namespace { +constexpr float AmbiScale::N3D2N3D[MAX_AMBI_COEFFS]; +constexpr float AmbiScale::SN3D2N3D[MAX_AMBI_COEFFS]; +constexpr float AmbiScale::FuMa2N3D[MAX_AMBI_COEFFS]; +constexpr int AmbiIndex::FuMa2ACN[MAX_AMBI_COEFFS]; +constexpr int AmbiIndex::ACN2ACN[MAX_AMBI_COEFFS]; -constexpr ALsizei FuMa2ACN[MAX_AMBI_COEFFS] = { - 0, /* W */ - 3, /* X */ - 1, /* Y */ - 2, /* Z */ - 6, /* R */ - 7, /* S */ - 5, /* T */ - 8, /* U */ - 4, /* V */ - 12, /* K */ - 13, /* L */ - 11, /* M */ - 14, /* N */ - 10, /* O */ - 15, /* P */ - 9, /* Q */ -}; -constexpr ALsizei ACN2ACN[MAX_AMBI_COEFFS] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15 -}; + +namespace { inline const char *GetLabelFromChannel(Channel channel) { @@ -354,10 +338,10 @@ auto GetAmbiScales(AmbiNorm scaletype) noexcept -> const float(&)[MAX_AMBI_COEFF return AmbiScale::N3D2N3D; } -auto GetAmbiLayout(AmbiLayout layouttype) noexcept -> const ALsizei(&)[MAX_AMBI_COEFFS] +auto GetAmbiLayout(AmbiLayout layouttype) noexcept -> const int(&)[MAX_AMBI_COEFFS] { - if(layouttype == AmbiLayout::FuMa) return FuMa2ACN; - return ACN2ACN; + if(layouttype == AmbiLayout::FuMa) return AmbiIndex::FuMa2ACN; + return AmbiIndex::ACN2ACN; } @@ -444,8 +428,8 @@ void InitPanning(ALCdevice *device) * The upsampler expects this and will convert it for output. */ device->FOAOut.Ambi = AmbiConfig{}; - acnmap_end = std::begin(ACN2ACN) + 4; - std::transform(std::begin(ACN2ACN), acnmap_end, std::begin(device->FOAOut.Ambi.Map), + acnmap_end = std::begin(AmbiIndex::ACN2ACN) + 4; + std::transform(std::begin(AmbiIndex::ACN2ACN), acnmap_end, std::begin(device->FOAOut.Ambi.Map), [](const ALsizei &acn) noexcept { return BFChannelConfig{1.0f, acn}; } ); device->FOAOut.CoeffCount = 0; @@ -779,7 +763,8 @@ void InitUhjPanning(ALCdevice *device) { static constexpr ALsizei count{3}; - std::transform(std::begin(FuMa2ACN), std::begin(FuMa2ACN)+count, std::begin(device->Dry.Ambi.Map), + auto acnmap_end = std::begin(AmbiIndex::FuMa2ACN) + count; + std::transform(std::begin(AmbiIndex::FuMa2ACN), acnmap_end, std::begin(device->Dry.Ambi.Map), [](const ALsizei &acn) noexcept -> BFChannelConfig { return BFChannelConfig{1.0f/AmbiScale::FuMa2N3D[acn], acn}; } ); @@ -1205,7 +1190,8 @@ no_hrtf: void aluInitEffectPanning(ALeffectslot *slot) { const size_t count{countof(slot->ChanMap)}; - std::transform(std::begin(ACN2ACN), std::begin(ACN2ACN)+count, std::begin(slot->ChanMap), + auto acnmap_end = std::begin(AmbiIndex::ACN2ACN) + count; + std::transform(std::begin(AmbiIndex::ACN2ACN), acnmap_end, std::begin(slot->ChanMap), [](const ALsizei &acn) noexcept { return BFChannelConfig{1.0f, acn}; } ); slot->NumChannels = static_cast(count); -- cgit v1.2.3 From 064f4f500a2805167f543670d999977322ba3e87 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 16 Dec 2018 01:27:52 -0800 Subject: Avoid extraneous alignment requirements --- Alc/bformatdec.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 4da5547e..385fe0fa 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -34,8 +34,8 @@ private: ALuint mEnabled; /* Bitfield of enabled channels. */ union MatrixU { - alignas(16) ALfloat Dual[MAX_OUTPUT_CHANNELS][sNumBands][MAX_AMBI_COEFFS]; - alignas(16) ALfloat Single[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; + ALfloat Dual[MAX_OUTPUT_CHANNELS][sNumBands][MAX_AMBI_COEFFS]; + ALfloat Single[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; } mMatrix; /* NOTE: BandSplitter filters are unused with single-band decoding */ -- cgit v1.2.3 From 3b0fd20bee855bbd7075b34e32f2272f71e28462 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 16 Dec 2018 21:03:24 -0800 Subject: Always use the transcode method with the AmbiUpsampler --- Alc/bformatdec.cpp | 68 ++++++++++++++++-------------------------------------- Alc/bformatdec.h | 2 +- Alc/panning.cpp | 16 ++----------- 3 files changed, 23 insertions(+), 63 deletions(-) diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 9c6e3dff..ee3d977e 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -51,18 +51,6 @@ constexpr ALfloat Ambi3DDecoderHFScale[MAX_AMBI_COEFFS] = { }; -#define INVALID_UPSAMPLE_INDEX INT_MAX -ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn) -{ - for(ALsizei i{0};i < numchans;i++) - { - if(chans[i].Index == acn) - return i; - } - return INVALID_UPSAMPLE_INDEX; -} -#define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a)) - auto GetAmbiScales(AmbDecScale scaletype) noexcept -> const float(&)[MAX_AMBI_COEFFS] { if(scaletype == AmbDecScale::FuMa) return AmbiScale::FuMa2N3D; @@ -254,52 +242,36 @@ void BFormatDec::upSample(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALflo } -void AmbiUpsampler::reset(const ALCdevice *device, const ALfloat w_scale, const ALfloat xyz_scale) +void AmbiUpsampler::reset(const ALCdevice *device) { using namespace std::placeholders; mXOver[0].init(400.0f / (float)device->Frequency); std::fill(std::begin(mXOver)+1, std::end(mXOver), mXOver[0]); - mGains.fill({}); - if(device->Dry.CoeffCount > 0) + ALfloat encgains[8][MAX_OUTPUT_CHANNELS]; + for(size_t k{0u};k < COUNTOF(Ambi3DPoints);k++) { - ALfloat encgains[8][MAX_OUTPUT_CHANNELS]; - for(size_t k{0u};k < COUNTOF(Ambi3DPoints);k++) - { - ALfloat coeffs[MAX_AMBI_COEFFS]; - CalcDirectionCoeffs(Ambi3DPoints[k], 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, 1.0f, encgains[k]); - } - - /* Combine the matrices that do the in->virt and virt->out conversions - * so we get a single in->out conversion. NOTE: the Encoder matrix - * (encgains) and output are transposed, so the input channels line up - * with the rows and the output channels line up with the columns. - */ - for(ALsizei i{0};i < 4;i++) - { - for(ALsizei j{0};j < device->Dry.NumChannels;j++) - { - ALdouble gain{0.0}; - for(size_t k{0u};k < COUNTOF(Ambi3DDecoder);k++) - gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][j]; - mGains[i][j][HF_BAND] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]); - mGains[i][j][LF_BAND] = (ALfloat)gain; - } - } + ALfloat coeffs[MAX_AMBI_COEFFS]; + CalcDirectionCoeffs(Ambi3DPoints[k], 0.0f, coeffs); + ComputePanGains(&device->Dry, coeffs, 1.0f, encgains[k]); } - else + + /* Combine the matrices that do the in->virt and virt->out conversions so + * we get a single in->out conversion. NOTE: the Encoder matrix (encgains) + * and output are transposed, so the input channels line up with the rows + * and the output channels line up with the columns. + */ + mGains.fill({}); + for(ALsizei i{0};i < 4;i++) { - for(ALsizei i{0};i < 4;i++) + for(ALsizei j{0};j < device->Dry.NumChannels;j++) { - const ALsizei index{GetChannelForACN(device->Dry, i)}; - if(index != INVALID_UPSAMPLE_INDEX) - { - const ALfloat scale{device->Dry.Ambi.Map[index].Scale}; - mGains[i][index][HF_BAND] = scale * ((i==0) ? w_scale : xyz_scale); - mGains[i][index][LF_BAND] = scale; - } + ALdouble gain{0.0}; + for(size_t k{0u};k < COUNTOF(Ambi3DDecoder);k++) + gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][j]; + mGains[i][j][HF_BAND] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]); + mGains[i][j][LF_BAND] = (ALfloat)gain; } } } diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 385fe0fa..c52472b5 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -84,7 +84,7 @@ private: std::array,MAX_OUTPUT_CHANNELS>,4> mGains; public: - void reset(const ALCdevice *device, const ALfloat w_scale, const ALfloat xyz_scale); + void reset(const ALCdevice *device); void process(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei SamplesToDo); DEF_NEWDEL(AmbiUpsampler) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 3ea0ae06..28df87d0 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -435,18 +435,7 @@ void InitPanning(ALCdevice *device) device->FOAOut.CoeffCount = 0; device->FOAOut.NumChannels = 4; - ALfloat w_scale{1.0f}, xyz_scale{1.0f}; - if(device->mAmbiOrder >= 3) - { - w_scale = W_SCALE_3H3P; - xyz_scale = XYZ_SCALE_3H3P; - } - else - { - w_scale = W_SCALE_2H2P; - xyz_scale = XYZ_SCALE_2H2P; - } - device->AmbiUp->reset(device, w_scale, xyz_scale); + device->AmbiUp->reset(device); } ALfloat nfc_delay{0.0f}; @@ -738,8 +727,7 @@ void InitHrtfPanning(ALCdevice *device) device->FOAOut.CoeffCount = 0; device->FOAOut.NumChannels = 4; - device->AmbiUp->reset(device, AmbiOrderHFGainFOA[0] / AmbiOrderHFGain[0], - AmbiOrderHFGainFOA[1] / AmbiOrderHFGain[1]); + device->AmbiUp->reset(device); } else { -- cgit v1.2.3 From a359cb85e600f1b8853ec0b77496cf626f93d3a3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 16 Dec 2018 22:37:29 -0800 Subject: Mix each frequency band individually for ambisonic upsampling --- Alc/bformatdec.cpp | 13 ++++++------- Alc/bformatdec.h | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index ee3d977e..db374c8a 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -270,22 +270,21 @@ void AmbiUpsampler::reset(const ALCdevice *device) ALdouble gain{0.0}; for(size_t k{0u};k < COUNTOF(Ambi3DDecoder);k++) gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][j]; - mGains[i][j][HF_BAND] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]); - mGains[i][j][LF_BAND] = (ALfloat)gain; + mGains[i][HF_BAND][j] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]); + mGains[i][LF_BAND][j] = (ALfloat)gain; } } } void AmbiUpsampler::process(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei SamplesToDo) { - ASSUME(OutChannels > 0); - ASSUME(SamplesToDo > 0); - for(ALsizei i{0};i < 4;i++) { mXOver[i].process(mSamples[HF_BAND], mSamples[LF_BAND], InSamples[i], SamplesToDo); - for(ALsizei j{0};j < OutChannels;j++) - MixRowSamples(OutBuffer[j], mGains[i][j].data(), mSamples, sNumBands, 0, SamplesToDo); + MixSamples(mSamples[HF_BAND], OutChannels, OutBuffer, mGains[i][HF_BAND].data(), + mGains[i][HF_BAND].data(), 0, 0, SamplesToDo); + MixSamples(mSamples[LF_BAND], OutChannels, OutBuffer, mGains[i][LF_BAND].data(), + mGains[i][LF_BAND].data(), 0, 0, SamplesToDo); } } diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index c52472b5..14e02b4f 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -81,7 +81,7 @@ private: BandSplitter mXOver[4]; - std::array,MAX_OUTPUT_CHANNELS>,4> mGains; + std::array,sNumBands>,4> mGains; public: void reset(const ALCdevice *device); -- cgit v1.2.3 From 59013b5cb5888b765c6b1ffa5a983651f985eae9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 17 Dec 2018 07:12:37 -0800 Subject: Avoid hard-coded scale factors in BFormatDec's upsampler --- Alc/bformatdec.cpp | 59 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index db374c8a..2be6eae8 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -86,30 +86,45 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, const bool periphonic{(conf->ChanMask&AMBI_PERIPHONIC_MASK) != 0}; if(periphonic) { - mUpSampler[0].Gains[HF_BAND] = - (conf->ChanMask > AMBI_2ORDER_MASK) ? W_SCALE_3H3P : - (conf->ChanMask > AMBI_1ORDER_MASK) ? W_SCALE_2H2P : 1.0f; - mUpSampler[0].Gains[LF_BAND] = 1.0f; - for(ALsizei i{1};i < 4;i++) + ALfloat encgains[8][MAX_OUTPUT_CHANNELS]{}; + for(size_t k{0u};k < COUNTOF(Ambi3DPoints);k++) { - mUpSampler[i].Gains[HF_BAND] = - (conf->ChanMask > AMBI_2ORDER_MASK) ? XYZ_SCALE_3H3P : - (conf->ChanMask > AMBI_1ORDER_MASK) ? XYZ_SCALE_2H2P : 1.0f; - mUpSampler[i].Gains[LF_BAND] = 1.0f; + ALfloat coeffs[MAX_AMBI_COEFFS]; + CalcDirectionCoeffs(Ambi3DPoints[k], 0.0f, coeffs); + std::copy(std::begin(coeffs), std::begin(coeffs)+chancount, std::begin(encgains[k])); + } + assert(chancount >= 4); + for(ALsizei i{0};i < 4;i++) + { + ALdouble gain{0.0}; + for(size_t k{0u};k < COUNTOF(Ambi3DDecoder);k++) + gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][i]; + mUpSampler[i].Gains[HF_BAND] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]); + mUpSampler[i].Gains[LF_BAND] = (ALfloat)gain; } } else { - mUpSampler[0].Gains[HF_BAND] = - (conf->ChanMask > AMBI_2ORDER_MASK) ? W_SCALE_3H0P : - (conf->ChanMask > AMBI_1ORDER_MASK) ? W_SCALE_2H0P : 1.0f; - mUpSampler[0].Gains[LF_BAND] = 1.0f; - for(ALsizei i{1};i < 3;i++) + ALfloat encgains[8][MAX_OUTPUT_CHANNELS]{}; + for(size_t k{0u};k < COUNTOF(Ambi3DPoints);k++) + { + ALfloat coeffs[MAX_AMBI_COEFFS]; + CalcDirectionCoeffs(Ambi3DPoints[k], 0.0f, coeffs); + auto ambimap_end = std::begin(map2DTo3D) + chancount; + std::transform(std::begin(map2DTo3D), ambimap_end, std::begin(encgains[k]), + [&coeffs](const ALsizei &index) noexcept -> ALfloat + { ASSUME(index > 0); return coeffs[index]; } + ); + } + assert(chancount >= 3); + for(ALsizei c{0};c < 3;c++) { - mUpSampler[i].Gains[HF_BAND] = - (conf->ChanMask > AMBI_2ORDER_MASK) ? XYZ_SCALE_3H0P : - (conf->ChanMask > AMBI_1ORDER_MASK) ? XYZ_SCALE_2H0P : 1.0f; - mUpSampler[i].Gains[LF_BAND] = 1.0f; + const ALsizei i{map2DTo3D[c]}; + ALdouble gain{0.0}; + for(size_t k{0u};k < COUNTOF(Ambi3DDecoder);k++) + gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][c]; + mUpSampler[c].Gains[HF_BAND] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]); + mUpSampler[c].Gains[LF_BAND] = (ALfloat)gain; } mUpSampler[3].Gains[HF_BAND] = 0.0f; mUpSampler[3].Gains[LF_BAND] = 0.0f; @@ -216,9 +231,9 @@ void BFormatDec::upSample(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALflo ASSUME(InChannels > 0); ASSUME(SamplesToDo > 0); - /* This up-sampler leverages the differences observed in dual-band second- - * and third-order decoder matrices compared to first-order. For the same - * output channel configuration, the low-frequency matrix has identical + /* This up-sampler leverages the differences observed in dual-band higher- + * order decoder matrices compared to first-order. For the same output + * channel configuration, the low-frequency matrix has identical * coefficients in the shared input channels, while the high-frequency * matrix has extra scalars applied to the W channel and X/Y/Z channels. * Mixing the first-order content into the higher-order stream with the @@ -244,8 +259,6 @@ void BFormatDec::upSample(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALflo void AmbiUpsampler::reset(const ALCdevice *device) { - using namespace std::placeholders; - mXOver[0].init(400.0f / (float)device->Frequency); std::fill(std::begin(mXOver)+1, std::end(mXOver), mXOver[0]); -- cgit v1.2.3 From 5243516149ac9bcf383006b1ab0520d3385979fa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 17 Dec 2018 07:29:55 -0800 Subject: Use the AmbiUpsampler with higher order basic and custom panning Also allocate the BFormatDec and AmbiUpsampler where they're (re)set. --- Alc/bformatdec.h | 17 -------- Alc/panning.cpp | 126 +++++++++++++++++++++---------------------------------- 2 files changed, 47 insertions(+), 96 deletions(-) diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 14e02b4f..b5824545 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -9,23 +9,6 @@ struct AmbDecConf; -/* These are the necessary scales for first-order HF responses to play over - * higher-order 2D (non-periphonic) decoders. - */ -#define W_SCALE_2H0P 1.224744871f /* sqrt(1.5) */ -#define XYZ_SCALE_2H0P 1.0f -#define W_SCALE_3H0P 1.414213562f /* sqrt(2) */ -#define XYZ_SCALE_3H0P 1.082392196f - -/* These are the necessary scales for first-order HF responses to play over - * higher-order 3D (periphonic) decoders. - */ -#define W_SCALE_2H2P 1.341640787f /* sqrt(1.8) */ -#define XYZ_SCALE_2H2P 1.0f -#define W_SCALE_3H3P 1.695486018f -#define XYZ_SCALE_3H3P 1.136697713f - - class BFormatDec { public: static constexpr size_t sNumBands{2}; diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 28df87d0..a8dace5a 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -435,6 +435,7 @@ void InitPanning(ALCdevice *device) device->FOAOut.CoeffCount = 0; device->FOAOut.NumChannels = 4; + device->AmbiUp.reset(new AmbiUpsampler{}); device->AmbiUp->reset(device); } @@ -453,20 +454,25 @@ void InitPanning(ALCdevice *device) chanmap, count, &device->Dry.NumChannels); device->Dry.CoeffCount = coeffcount; - const ALfloat w_scale{(device->Dry.CoeffCount > 9) ? W_SCALE_3H0P : - (device->Dry.CoeffCount > 4) ? W_SCALE_2H0P : 1.0f}; - const ALfloat xyz_scale{(device->Dry.CoeffCount > 9) ? XYZ_SCALE_3H0P : - (device->Dry.CoeffCount > 4) ? XYZ_SCALE_2H0P : 1.0f}; - - device->FOAOut.Ambi = AmbiConfig{}; - for(ALsizei i{0};i < device->Dry.NumChannels;i++) + if(coeffcount <= 4) { - device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0] * w_scale; - for(ALsizei j{1};j < 4;j++) - device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * xyz_scale; + device->FOAOut.Ambi = device->Dry.Ambi; + device->FOAOut.CoeffCount = device->Dry.CoeffCount; + device->FOAOut.NumChannels = 0; + } + else + { + device->FOAOut.Ambi = AmbiConfig{}; + auto acnmap_end = std::begin(AmbiIndex::ACN2ACN) + 4; + std::transform(std::begin(AmbiIndex::ACN2ACN), acnmap_end, std::begin(device->FOAOut.Ambi.Map), + [](const ALsizei &acn) noexcept { return BFChannelConfig{1.0f, acn}; } + ); + device->FOAOut.CoeffCount = 0; + device->FOAOut.NumChannels = 4; + + device->AmbiUp.reset(new AmbiUpsampler{}); + device->AmbiUp->reset(device); } - device->FOAOut.CoeffCount = 4; - device->FOAOut.NumChannels = 0; } device->RealOut.NumChannels = 0; } @@ -477,34 +483,6 @@ void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n", conf->XOverFreq); - ALfloat w_scale{1.0f}, xyz_scale{1.0f}; - if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) - { - if(conf->ChanMask > AMBI_2ORDER_MASK) - { - w_scale = W_SCALE_3H3P; - xyz_scale = XYZ_SCALE_3H3P; - } - else if(conf->ChanMask > AMBI_1ORDER_MASK) - { - w_scale = W_SCALE_2H2P; - xyz_scale = XYZ_SCALE_2H2P; - } - } - else - { - if(conf->ChanMask > AMBI_2ORDER_MASK) - { - w_scale = W_SCALE_3H0P; - xyz_scale = XYZ_SCALE_3H0P; - } - else if(conf->ChanMask > AMBI_1ORDER_MASK) - { - w_scale = W_SCALE_2H0P; - xyz_scale = XYZ_SCALE_2H0P; - } - } - const ALfloat (&coeff_scale)[MAX_AMBI_COEFFS] = GetAmbiScales(conf->CoeffScale); ChannelMap chanmap[MAX_OUTPUT_CHANNELS]{}; for(size_t i{0u};i < conf->Speakers.size();i++) @@ -528,15 +506,27 @@ void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei device->Dry.CoeffCount = (conf->ChanMask > AMBI_2ORDER_MASK) ? 16 : (conf->ChanMask > AMBI_1ORDER_MASK) ? 9 : 4; - device->FOAOut.Ambi = AmbiConfig{}; - for(ALsizei i{0};i < device->Dry.NumChannels;i++) + if(conf->ChanMask <= AMBI_1ORDER_MASK) + { + device->FOAOut.Ambi = device->Dry.Ambi; + device->FOAOut.CoeffCount = device->Dry.CoeffCount; + device->FOAOut.NumChannels = 0; + } + else { - device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0] * w_scale; - for(ALsizei j{1};j < 4;j++) - device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * xyz_scale; + static constexpr int map[4] = { 0, 1, 2, 3 }; + static constexpr ALsizei count{4}; + + device->FOAOut.Ambi = AmbiConfig{}; + std::transform(std::begin(map), std::begin(map)+count, std::begin(device->FOAOut.Ambi.Map), + [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } + ); + device->FOAOut.CoeffCount = 0; + device->FOAOut.NumChannels = count; + + device->AmbiUp.reset(new AmbiUpsampler{}); + device->AmbiUp->reset(device); } - device->FOAOut.CoeffCount = 4; - device->FOAOut.NumChannels = 0; device->RealOut.NumChannels = 0; @@ -576,6 +566,7 @@ void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&sp (conf->ChanMask > AMBI_1ORDER_MASK) ? "second" : "first", (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? " periphonic" : "" ); + device->AmbiDecoder.reset(new BFormatDec{}); device->AmbiDecoder->reset(conf, count, device->Frequency, speakermap); if(conf->ChanMask <= AMBI_1ORDER_MASK) @@ -702,8 +693,13 @@ void InitHrtfPanning(ALCdevice *device) static_assert(COUNTOF(AmbiPoints) == COUNTOF(AmbiMatrixFOA), "FOA Ambisonic HRTF mismatch"); static_assert(COUNTOF(AmbiPoints) == COUNTOF(AmbiMatrixHOA), "HOA Ambisonic HRTF mismatch"); - if(device->AmbiUp) + /* Don't bother with HOA when using full HRTF rendering. Nothing needs it, + * and it eases the CPU/memory load. + */ + if(device->Render_Mode != HrtfRender) { + device->AmbiUp.reset(new AmbiUpsampler{}); + AmbiMatrix = AmbiMatrixHOA; AmbiOrderHFGain = AmbiOrderHFGainHOA; count = static_cast(COUNTOF(IndexMap)); @@ -909,6 +905,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr device->AvgSpeakerDist = 0.0f; device->ChannelDelay.clear(); + device->AmbiDecoder = nullptr; + device->AmbiUp = nullptr; device->Stablizer = nullptr; if(device->FmtChans != DevFmtStereo) @@ -956,24 +954,9 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr } } - if(pconf && GetConfigValueBool(devname, "decoder", "hq-mode", 0)) - { - device->AmbiUp = nullptr; - if(!device->AmbiDecoder) - device->AmbiDecoder.reset(new BFormatDec{}); - } - else - { - device->AmbiDecoder = nullptr; - if(device->FmtChans != DevFmtAmbi3D || device->mAmbiOrder < 2) - device->AmbiUp = nullptr; - else if(!device->AmbiUp) - device->AmbiUp.reset(new AmbiUpsampler{}); - } - if(!pconf) InitPanning(device); - else if(device->AmbiDecoder) + else if(GetConfigValueBool(devname, "decoder", "hq-mode", 0)) InitHQPanning(device, pconf, speakermap); else InitCustomPanning(device, pconf, speakermap); @@ -1108,19 +1091,6 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr ERR("Unexpected hrtf-mode: %s\n", mode); } - if(device->Render_Mode == HrtfRender) - { - /* Don't bother with HOA when using full HRTF rendering. Nothing - * needs it, and it eases the CPU/memory load. - */ - device->AmbiUp = nullptr; - } - else - { - if(!device->AmbiUp) - device->AmbiUp.reset(new AmbiUpsampler{}); - } - TRACE("%s HRTF rendering enabled, using \"%s\"\n", ((device->Render_Mode == HrtfRender) ? "Full" : "Basic"), device->HrtfName.c_str() ); @@ -1137,8 +1107,6 @@ no_hrtf: device->Render_Mode = StereoPair; - device->AmbiUp = nullptr; - int bs2blevel{((headphones && hrtf_appreq != Hrtf_Disable) || (hrtf_appreq == Hrtf_Enable)) ? 5 : 0}; if(device->Type != Loopback) -- cgit v1.2.3 From e2896dc839e334f62f4975e37a68a3faa9bbdaf8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 18 Dec 2018 09:27:00 -0800 Subject: Combine handling of attribute processing --- Alc/alc.cpp | 351 +++++++++++++++++++--------------------------- OpenAL32/Include/alMain.h | 2 + 2 files changed, 145 insertions(+), 208 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 2a76c846..142ee4d2 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1599,10 +1599,15 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ALCuint oldFreq; int val; + if((!attrList || !attrList[0]) && device->Type == Loopback) + { + WARN("Missing attributes for loopback device\n"); + return ALC_INVALID_VALUE; + } + // Check for attributes - if(device->Type == Loopback) + if(attrList && attrList[0]) { - ALCsizei numMono, numStereo, numSends; ALCenum alayout = AL_NONE; ALCenum ascale = AL_NONE; ALCenum schans = AL_NONE; @@ -1611,120 +1616,124 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ALCsizei aorder = 0; ALCuint freq = 0; - if(!attrList) + const char *devname{nullptr}; + const bool loopback{device->Type == Loopback}; + if(!loopback) { - WARN("Missing attributes for loopback device\n"); - return ALC_INVALID_VALUE; + devname = device->DeviceName.c_str(); + /* If a context is already running on the device, stop playback so + * the device attributes can be updated. + */ + if((device->Flags&DEVICE_RUNNING)) + V0(device->Backend,stop)(); + device->Flags &= ~DEVICE_RUNNING; } - numMono = device->NumMonoSources; - numStereo = device->NumStereoSources; - numSends = old_sends; + auto numMono = static_cast(device->NumMonoSources); + auto numStereo = static_cast(device->NumStereoSources); + auto numSends = ALsizei{old_sends}; -#define TRACE_ATTR(a, v) TRACE("Loopback %s = %d\n", #a, v) +#define TRACE_ATTR(a, v) TRACE("%s = %d\n", #a, v) while(attrList[attrIdx]) { switch(attrList[attrIdx]) { - case ALC_FORMAT_CHANNELS_SOFT: - schans = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_FORMAT_CHANNELS_SOFT, schans); - if(!IsValidALCChannels(schans)) - return ALC_INVALID_VALUE; - break; + case ALC_FORMAT_CHANNELS_SOFT: + schans = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_FORMAT_CHANNELS_SOFT, schans); + break; - case ALC_FORMAT_TYPE_SOFT: - stype = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_FORMAT_TYPE_SOFT, stype); - if(!IsValidALCType(stype)) - return ALC_INVALID_VALUE; - break; + case ALC_FORMAT_TYPE_SOFT: + stype = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_FORMAT_TYPE_SOFT, stype); + break; - case ALC_FREQUENCY: - freq = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_FREQUENCY, freq); - if(freq < MIN_OUTPUT_RATE) - return ALC_INVALID_VALUE; - break; + case ALC_FREQUENCY: + freq = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_FREQUENCY, freq); + break; - case ALC_AMBISONIC_LAYOUT_SOFT: - alayout = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_AMBISONIC_LAYOUT_SOFT, alayout); - if(!IsValidAmbiLayout(alayout)) - return ALC_INVALID_VALUE; - break; + case ALC_AMBISONIC_LAYOUT_SOFT: + alayout = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_AMBISONIC_LAYOUT_SOFT, alayout); + break; - case ALC_AMBISONIC_SCALING_SOFT: - ascale = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_AMBISONIC_SCALING_SOFT, ascale); - if(!IsValidAmbiScaling(ascale)) - return ALC_INVALID_VALUE; - break; + case ALC_AMBISONIC_SCALING_SOFT: + ascale = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_AMBISONIC_SCALING_SOFT, ascale); + break; - case ALC_AMBISONIC_ORDER_SOFT: - aorder = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_AMBISONIC_ORDER_SOFT, aorder); - if(aorder < 1 || aorder > MAX_AMBI_ORDER) - return ALC_INVALID_VALUE; - break; + case ALC_AMBISONIC_ORDER_SOFT: + aorder = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_AMBISONIC_ORDER_SOFT, aorder); + break; - case ALC_MONO_SOURCES: - numMono = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_MONO_SOURCES, numMono); - numMono = maxi(numMono, 0); - break; + case ALC_MONO_SOURCES: + numMono = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_MONO_SOURCES, numMono); + numMono = maxi(numMono, 0); + break; - case ALC_STEREO_SOURCES: - numStereo = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); - numStereo = maxi(numStereo, 0); - break; + case ALC_STEREO_SOURCES: + numStereo = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); + numStereo = maxi(numStereo, 0); + break; - case ALC_MAX_AUXILIARY_SENDS: - numSends = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_MAX_AUXILIARY_SENDS, numSends); - numSends = clampi(numSends, 0, MAX_SENDS); - break; + case ALC_MAX_AUXILIARY_SENDS: + numSends = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_MAX_AUXILIARY_SENDS, numSends); + numSends = clampi(numSends, 0, MAX_SENDS); + break; - case ALC_HRTF_SOFT: - TRACE_ATTR(ALC_HRTF_SOFT, attrList[attrIdx + 1]); - if(attrList[attrIdx + 1] == ALC_FALSE) - hrtf_appreq = Hrtf_Disable; - else if(attrList[attrIdx + 1] == ALC_TRUE) - hrtf_appreq = Hrtf_Enable; - else - hrtf_appreq = Hrtf_Default; - break; + case ALC_HRTF_SOFT: + TRACE_ATTR(ALC_HRTF_SOFT, attrList[attrIdx + 1]); + if(attrList[attrIdx + 1] == ALC_FALSE) + hrtf_appreq = Hrtf_Disable; + else if(attrList[attrIdx + 1] == ALC_TRUE) + hrtf_appreq = Hrtf_Enable; + else + hrtf_appreq = Hrtf_Default; + break; - case ALC_HRTF_ID_SOFT: - hrtf_id = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_HRTF_ID_SOFT, hrtf_id); - break; + case ALC_HRTF_ID_SOFT: + hrtf_id = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_HRTF_ID_SOFT, hrtf_id); + break; - case ALC_OUTPUT_LIMITER_SOFT: - gainLimiter = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_OUTPUT_LIMITER_SOFT, gainLimiter); - break; + case ALC_OUTPUT_LIMITER_SOFT: + gainLimiter = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_OUTPUT_LIMITER_SOFT, gainLimiter); + break; - default: - TRACE("Loopback 0x%04X = %d (0x%x)\n", attrList[attrIdx], - attrList[attrIdx + 1], attrList[attrIdx + 1]); - break; + default: + TRACE("0x%04X = %d (0x%x)\n", attrList[attrIdx], + attrList[attrIdx + 1], attrList[attrIdx + 1]); + break; } attrIdx += 2; } #undef TRACE_ATTR - if(!schans || !stype || !freq) + if(loopback) { - WARN("Missing format for loopback device\n"); - return ALC_INVALID_VALUE; - } - if(schans == ALC_BFORMAT3D_SOFT && (!alayout || !ascale || !aorder)) - { - WARN("Missing ambisonic info for loopback device\n"); - return ALC_INVALID_VALUE; + if(!schans || !stype || !freq) + { + WARN("Missing format for loopback device\n"); + return ALC_INVALID_VALUE; + } + if(schans == ALC_BFORMAT3D_SOFT && (!alayout || !ascale || !aorder)) + { + WARN("Missing ambisonic info for loopback device\n"); + return ALC_INVALID_VALUE; + } + if(!IsValidALCChannels(schans) || !IsValidALCType(stype) || freq < MIN_OUTPUT_RATE) + return ALC_INVALID_VALUE; + if(!IsValidAmbiLayout(alayout) || !IsValidAmbiScaling(ascale)) + return ALC_INVALID_VALUE; + if(aorder < 1 || aorder > MAX_AMBI_ORDER) + return ALC_INVALID_VALUE; } if((device->Flags&DEVICE_RUNNING)) @@ -1733,131 +1742,52 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) UpdateClockBase(device); - device->Frequency = freq; - device->FmtChans = static_cast(schans); - device->FmtType = static_cast(stype); - if(schans == ALC_BFORMAT3D_SOFT) - { - device->mAmbiOrder = aorder; - device->mAmbiLayout = static_cast(alayout); - device->mAmbiScale = static_cast(ascale); - } - - if(numMono > INT_MAX-numStereo) - numMono = INT_MAX-numStereo; - numMono += numStereo; - if(ConfigValueInt(nullptr, nullptr, "sources", &numMono)) + if(!loopback) { - if(numMono <= 0) - numMono = 256; - } - else - numMono = maxi(numMono, 256); - numStereo = mini(numStereo, numMono); - numMono -= numStereo; - device->SourcesMax = numMono + numStereo; - - device->NumMonoSources = numMono; - device->NumStereoSources = numStereo; + device->NumUpdates = DEFAULT_NUM_UPDATES; + device->UpdateSize = DEFAULT_UPDATE_SIZE; + device->Frequency = DEFAULT_OUTPUT_RATE; - if(ConfigValueInt(nullptr, nullptr, "sends", &new_sends)) - new_sends = mini(numSends, clampi(new_sends, 0, MAX_SENDS)); - else - new_sends = numSends; - } - else if(attrList && attrList[0]) - { - ALCsizei numMono, numStereo, numSends; - ALCsizei attrIdx = 0; - ALCuint freq; + ConfigValueUInt(devname, nullptr, "frequency", &freq); + if(freq < 1) + device->Flags &= ~DEVICE_FREQUENCY_REQUEST; + else + { + freq = maxi(freq, MIN_OUTPUT_RATE); - /* If a context is already running on the device, stop playback so the - * device attributes can be updated. */ - if((device->Flags&DEVICE_RUNNING)) - V0(device->Backend,stop)(); - device->Flags &= ~DEVICE_RUNNING; + device->NumUpdates = (device->NumUpdates*freq + device->NumUpdates/2) / + device->Frequency; - UpdateClockBase(device); + device->Frequency = freq; + device->Flags |= DEVICE_FREQUENCY_REQUEST; + } - freq = device->Frequency; - numMono = device->NumMonoSources; - numStereo = device->NumStereoSources; - numSends = old_sends; + ConfigValueUInt(devname, nullptr, "periods", &device->NumUpdates); + device->NumUpdates = clampu(device->NumUpdates, 2, 16); -#define TRACE_ATTR(a, v) TRACE("%s = %d\n", #a, v) - while(attrList[attrIdx]) + ConfigValueUInt(devname, nullptr, "period_size", &device->UpdateSize); + device->UpdateSize = clampu(device->UpdateSize, 64, 8192); + /* SSE and Neon do best with the update size being a multiple of 4. */ + if((CPUCapFlags&(CPU_CAP_SSE|CPU_CAP_NEON)) != 0) + device->UpdateSize = (device->UpdateSize+3u)&~3u; + } + else { - switch(attrList[attrIdx]) + device->Frequency = freq; + device->FmtChans = static_cast(schans); + device->FmtType = static_cast(stype); + if(schans == ALC_BFORMAT3D_SOFT) { - case ALC_FREQUENCY: - freq = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_FREQUENCY, freq); - device->Flags |= DEVICE_FREQUENCY_REQUEST; - break; - - case ALC_MONO_SOURCES: - numMono = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_MONO_SOURCES, numMono); - numMono = maxi(numMono, 0); - break; - - case ALC_STEREO_SOURCES: - numStereo = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); - numStereo = maxi(numStereo, 0); - break; - - case ALC_MAX_AUXILIARY_SENDS: - numSends = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_MAX_AUXILIARY_SENDS, numSends); - numSends = clampi(numSends, 0, MAX_SENDS); - break; - - case ALC_HRTF_SOFT: - TRACE_ATTR(ALC_HRTF_SOFT, attrList[attrIdx + 1]); - if(attrList[attrIdx + 1] == ALC_FALSE) - hrtf_appreq = Hrtf_Disable; - else if(attrList[attrIdx + 1] == ALC_TRUE) - hrtf_appreq = Hrtf_Enable; - else - hrtf_appreq = Hrtf_Default; - break; - - case ALC_HRTF_ID_SOFT: - hrtf_id = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_HRTF_ID_SOFT, hrtf_id); - break; - - case ALC_OUTPUT_LIMITER_SOFT: - gainLimiter = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_OUTPUT_LIMITER_SOFT, gainLimiter); - break; - - default: - TRACE("0x%04X = %d (0x%x)\n", attrList[attrIdx], - attrList[attrIdx + 1], attrList[attrIdx + 1]); - break; + device->mAmbiOrder = aorder; + device->mAmbiLayout = static_cast(alayout); + device->mAmbiScale = static_cast(ascale); } - - attrIdx += 2; } -#undef TRACE_ATTR - - ConfigValueUInt(device->DeviceName.c_str(), nullptr, "frequency", &freq); - freq = maxu(freq, MIN_OUTPUT_RATE); - - device->UpdateSize = (ALuint64)device->UpdateSize * freq / - device->Frequency; - /* SSE and Neon do best with the update size being a multiple of 4 */ - if((CPUCapFlags&(CPU_CAP_SSE|CPU_CAP_NEON)) != 0) - device->UpdateSize = (device->UpdateSize+3)&~3; - - device->Frequency = freq; if(numMono > INT_MAX-numStereo) numMono = INT_MAX-numStereo; numMono += numStereo; - if(ConfigValueInt(device->DeviceName.c_str(), nullptr, "sources", &numMono)) + if(ConfigValueInt(devname, nullptr, "sources", &numMono)) { if(numMono <= 0) numMono = 256; @@ -1871,7 +1801,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->NumMonoSources = numMono; device->NumStereoSources = numStereo; - if(ConfigValueInt(device->DeviceName.c_str(), nullptr, "sends", &new_sends)) + if(ConfigValueInt(devname, nullptr, "sends", &new_sends)) new_sends = mini(numSends, clampi(new_sends, 0, MAX_SENDS)); else new_sends = numSends; @@ -3711,9 +3641,9 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->FmtChans = DevFmtChannelsDefault; device->FmtType = DevFmtTypeDefault; device->Frequency = DEFAULT_OUTPUT_RATE; + device->UpdateSize = DEFAULT_UPDATE_SIZE; + device->NumUpdates = DEFAULT_NUM_UPDATES; device->LimiterState = ALC_TRUE; - device->NumUpdates = 3; - device->UpdateSize = 1024; device->SourcesMax = 256; device->AuxiliaryEffectSlotMax = 64; @@ -3780,12 +3710,17 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) } } - if(ConfigValueUInt(deviceName, nullptr, "frequency", &device->Frequency)) + ALuint freq{}; + if(ConfigValueUInt(deviceName, nullptr, "frequency", &freq) && freq > 0) { + if(freq < MIN_OUTPUT_RATE) + { + ERR("%uhz request clamped to %uhz minimum\n", freq, MIN_OUTPUT_RATE); + freq = MIN_OUTPUT_RATE; + } + device->NumUpdates = (device->NumUpdates*freq + device->Frequency/2) / device->Frequency; + device->Frequency = freq; device->Flags |= DEVICE_FREQUENCY_REQUEST; - if(device->Frequency < MIN_OUTPUT_RATE) - ERR("%uhz request clamped to %uhz minimum\n", device->Frequency, MIN_OUTPUT_RATE); - device->Frequency = maxu(device->Frequency, MIN_OUTPUT_RATE); } ConfigValueUInt(deviceName, nullptr, "periods", &device->NumUpdates); @@ -3794,7 +3729,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) ConfigValueUInt(deviceName, nullptr, "period_size", &device->UpdateSize); device->UpdateSize = clampu(device->UpdateSize, 64, 8192); if((CPUCapFlags&(CPU_CAP_SSE|CPU_CAP_NEON)) != 0) - device->UpdateSize = (device->UpdateSize+3)&~3; + device->UpdateSize = (device->UpdateSize+3u)&~3u; ConfigValueUInt(deviceName, nullptr, "sources", &device->SourcesMax); if(device->SourcesMax == 0) device->SourcesMax = 256; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 9d2e7bfc..b4fc67dd 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -252,6 +252,8 @@ class AmbiUpsampler; struct bs2b; +#define DEFAULT_UPDATE_SIZE (1024) +#define DEFAULT_NUM_UPDATES (3) #define DEFAULT_OUTPUT_RATE (44100) #define MIN_OUTPUT_RATE (8000) -- cgit v1.2.3 From fbd47961d54fdc9fa14e9fe9310b578bfbc84e56 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 19 Dec 2018 02:55:21 -0800 Subject: Don't allow FuMa ordering or normalization above third-order --- Alc/alc.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 142ee4d2..5de9bd49 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1734,6 +1734,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) return ALC_INVALID_VALUE; if(aorder < 1 || aorder > MAX_AMBI_ORDER) return ALC_INVALID_VALUE; + if((alayout == ALC_FUMA_SOFT || ascale == ALC_FUMA_SOFT) && aorder > 3) + return ALC_INVALID_VALUE; } if((device->Flags&DEVICE_RUNNING)) @@ -3768,8 +3770,18 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) { if(strcasecmp(fmt, "fuma") == 0) { - device->mAmbiLayout = AmbiLayout::FuMa; - device->mAmbiScale = AmbiNorm::FuMa; + if(device->mAmbiOrder > 3) + ERR("FuMa is incompatible with %d%s order ambisonics (up to third-order only)\n", + device->mAmbiOrder, + (((device->mAmbiOrder%100)/10) == 1) ? "th" : + ((device->mAmbiOrder%10) == 1) ? "st" : + ((device->mAmbiOrder%10) == 2) ? "nd" : + ((device->mAmbiOrder%10) == 3) ? "rd" : "th"); + else + { + device->mAmbiLayout = AmbiLayout::FuMa; + device->mAmbiScale = AmbiNorm::FuMa; + } } else if(strcasecmp(fmt, "acn+sn3d") == 0) { -- cgit v1.2.3 From b49e8985a47f384dfde0ddd04d97426e3c37f480 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 19 Dec 2018 03:13:15 -0800 Subject: Don't hardcode the channel count from the device ambisonic order --- Alc/alc.cpp | 12 +++++------- OpenAL32/Include/alMain.h | 19 +++++++++++-------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 5de9bd49..5b6d3bb3 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1185,7 +1185,7 @@ static void ProbeCaptureDeviceList(void) /************************************************ * Device format information ************************************************/ -const ALCchar *DevFmtTypeString(enum DevFmtType type) +const ALCchar *DevFmtTypeString(DevFmtType type) noexcept { switch(type) { @@ -1199,7 +1199,7 @@ const ALCchar *DevFmtTypeString(enum DevFmtType type) } return "(unknown type)"; } -const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) +const ALCchar *DevFmtChannelsString(DevFmtChannels chans) noexcept { switch(chans) { @@ -1215,7 +1215,7 @@ const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) return "(unknown channels)"; } -ALsizei BytesFromDevFmt(enum DevFmtType type) +ALsizei BytesFromDevFmt(DevFmtType type) noexcept { switch(type) { @@ -1229,7 +1229,7 @@ ALsizei BytesFromDevFmt(enum DevFmtType type) } return 0; } -ALsizei ChannelsFromDevFmt(enum DevFmtChannels chans, ALsizei ambiorder) +ALsizei ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept { switch(chans) { @@ -1240,9 +1240,7 @@ ALsizei ChannelsFromDevFmt(enum DevFmtChannels chans, ALsizei ambiorder) case DevFmtX51Rear: return 6; case DevFmtX61: return 7; case DevFmtX71: return 8; - case DevFmtAmbi3D: return (ambiorder >= 3) ? 16 : - (ambiorder == 2) ? 9 : - (ambiorder == 1) ? 4 : 1; + case DevFmtAmbi3D: return (ambiorder+1) * (ambiorder+1); } return 0; } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index b4fc67dd..da9b51ac 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -502,12 +502,10 @@ template<> struct DevFmtTypeTraits { using Type = ALfloat; }; -ALsizei BytesFromDevFmt(enum DevFmtType type); -ALsizei ChannelsFromDevFmt(enum DevFmtChannels chans, ALsizei ambiorder); -inline ALsizei FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type, ALsizei ambiorder) -{ - return ChannelsFromDevFmt(chans, ambiorder) * BytesFromDevFmt(type); -} +ALsizei BytesFromDevFmt(DevFmtType type) noexcept; +ALsizei ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept; +inline ALsizei FrameSizeFromDevFmt(DevFmtChannels chans, DevFmtType type, ALsizei ambiorder) noexcept +{ return ChannelsFromDevFmt(chans, ambiorder) * BytesFromDevFmt(type); } enum class AmbiLayout { FuMa = ALC_FUMA_SOFT, /* FuMa channel order */ @@ -810,6 +808,11 @@ struct ALCdevice_struct { ALCdevice_struct& operator=(const ALCdevice_struct&) = delete; ~ALCdevice_struct(); + ALsizei bytesFromFmt() const noexcept { return BytesFromDevFmt(FmtType); } + ALsizei channelsFromFmt() const noexcept { return ChannelsFromDevFmt(FmtChans, mAmbiOrder); } + ALsizei frameSizeFromFmt() const noexcept + { return FrameSizeFromDevFmt(FmtChans, FmtType, mAmbiOrder); } + DEF_NEWDEL(ALCdevice) }; @@ -889,8 +892,8 @@ void SetRTPriority(void); void SetDefaultChannelOrder(ALCdevice *device); void SetDefaultWFXChannelOrder(ALCdevice *device); -const ALCchar *DevFmtTypeString(DevFmtType type); -const ALCchar *DevFmtChannelsString(DevFmtChannels chans); +const ALCchar *DevFmtTypeString(DevFmtType type) noexcept; +const ALCchar *DevFmtChannelsString(DevFmtChannels chans) noexcept; inline ALint GetChannelIndex(const Channel (&names)[MAX_OUTPUT_CHANNELS], Channel chan) { -- cgit v1.2.3 From 0214a1102497003df07f354adc1e77d2b3185953 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 19 Dec 2018 05:57:36 -0800 Subject: Use inline methods for the device format sizes --- Alc/backends/alsa.cpp | 13 +++++-------- Alc/backends/coreaudio.cpp | 4 ++-- Alc/backends/dsound.cpp | 12 ++++++------ Alc/backends/jack.cpp | 12 +++--------- Alc/backends/opensl.cpp | 20 ++++++++++---------- Alc/backends/oss.cpp | 20 +++++++++----------- Alc/backends/portaudio.cpp | 4 ++-- Alc/backends/pulseaudio.cpp | 4 ++-- Alc/backends/qsa.cpp | 21 ++++++++------------- Alc/backends/sdl2.cpp | 4 ++-- Alc/backends/sndio.cpp | 12 +++++------- Alc/backends/solaris.cpp | 15 +++++++-------- Alc/backends/wasapi.cpp | 12 ++++-------- Alc/backends/wave.cpp | 13 ++++++------- Alc/backends/winmm.cpp | 7 +++---- Alc/panning.cpp | 6 +++--- OpenAL32/Include/alMain.h | 3 +-- 17 files changed, 78 insertions(+), 104 deletions(-) diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index 629038b8..606877a8 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -765,7 +765,7 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) } CHECK(snd_pcm_hw_params_set_format(self->PcmHandle, hp, format)); /* test and set channels (implicitly sets frame bits) */ - if(snd_pcm_hw_params_test_channels(self->PcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder)) < 0) + if(snd_pcm_hw_params_test_channels(self->PcmHandle, hp, device->channelsFromFmt()) < 0) { static const enum DevFmtChannels channellist[] = { DevFmtStereo, @@ -785,7 +785,7 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) } } } - CHECK(snd_pcm_hw_params_set_channels(self->PcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder))); + CHECK(snd_pcm_hw_params_set_channels(self->PcmHandle, hp, device->channelsFromFmt())); /* set rate (implicitly constrains period/buffer parameters) */ if(!GetConfigValueBool(device->DeviceName.c_str(), "alsa", "allow-resampler", 0) || !(device->Flags&DEVICE_FREQUENCY_REQUEST)) @@ -1046,7 +1046,7 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) /* set format (implicitly sets sample bits) */ CHECK(snd_pcm_hw_params_set_format(self->PcmHandle, hp, format)); /* set channels (implicitly sets frame bits) */ - CHECK(snd_pcm_hw_params_set_channels(self->PcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder))); + CHECK(snd_pcm_hw_params_set_channels(self->PcmHandle, hp, device->channelsFromFmt())); /* set rate (implicitly constrains period/buffer parameters) */ CHECK(snd_pcm_hw_params_set_rate(self->PcmHandle, hp, device->Frequency, 0)); /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ @@ -1068,11 +1068,8 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) if(needring) { - self->Ring = ll_ringbuffer_create( - device->UpdateSize*device->NumUpdates, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder), - false - ); + self->Ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, + device->frameSizeFromFmt(), false); if(!self->Ring) { ERR("ring buffer create failed\n"); diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index b2f6d2d3..228d1d76 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -271,7 +271,7 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) } /* setup callback */ - self->FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); + self->FrameSize = device->frameSizeFromFmt(); input.inputProc = ALCcoreAudioPlayback_MixerProc; input.inputProcRefCon = self; @@ -622,7 +622,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar // save requested format description for later use self->Format = requestedFormat; - self->FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); + self->FrameSize = device->frameSizeFromFmt(); // Use intermediate format for sample rate conversion (outputFormat) // Set sample rate to the same as hardware for resampling later diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 79e6b01e..5aa95f0f 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -265,7 +265,7 @@ FORCE_ALIGN int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) return 1; } - ALsizei FrameSize{FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder)}; + ALsizei FrameSize{device->frameSizeFromFmt()}; DWORD FragSize{device->UpdateSize * FrameSize}; bool Playing{false}; @@ -521,8 +521,8 @@ ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) retry_open: hr = S_OK; OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; - OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); - OutputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + OutputType.Format.nChannels = device->channelsFromFmt(); + OutputType.Format.wBitsPerSample = device->bytesFromFmt() * 8; OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8; OutputType.Format.nSamplesPerSec = device->Frequency; OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign; @@ -805,8 +805,8 @@ ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) } InputType.Format.wFormatTag = WAVE_FORMAT_PCM; - InputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); - InputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + InputType.Format.nChannels = device->channelsFromFmt(); + InputType.Format.wBitsPerSample = device->bytesFromFmt() * 8; InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8; InputType.Format.nSamplesPerSec = device->Frequency; InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign; @@ -904,7 +904,7 @@ ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) if(!device->Connected.load(std::memory_order_acquire)) return static_cast(ll_ringbuffer_read_space(self->Ring)); - ALsizei FrameSize{FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder)}; + ALsizei FrameSize{device->frameSizeFromFmt()}; DWORD BufferBytes{self->BufferBytes}; DWORD LastCursor{self->Cursor}; diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index d141f991..88f60c93 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -222,10 +222,7 @@ int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg) TRACE("%u update size x%u\n", device->UpdateSize, device->NumUpdates); self->mRing = nullptr; - self->mRing.reset(ll_ringbuffer_create(bufsize, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder), - true - )); + self->mRing.reset(ll_ringbuffer_create(bufsize, device->frameSizeFromFmt(), true)); if(!self->mRing) { ERR("Failed to reallocate ringbuffer\n"); @@ -400,7 +397,7 @@ ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) /* Force 32-bit float output. */ device->FmtType = DevFmtFloat; - ALsizei numchans{ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder)}; + ALsizei numchans{device->channelsFromFmt()}; auto ports_end = std::begin(self->mPort) + numchans; auto bad_port = std::find_if_not(std::begin(self->mPort), ports_end, [self](jack_port_t *&port) -> bool @@ -432,10 +429,7 @@ ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) } self->mRing = nullptr; - self->mRing.reset(ll_ringbuffer_create(bufsize, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder), - true - )); + self->mRing.reset(ll_ringbuffer_create(bufsize, device->frameSizeFromFmt(), true)); if(!self->mRing) { ERR("Failed to allocate ringbuffer\n"); diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index c2acda3a..78212791 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -464,7 +464,7 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) device->FmtType = DevFmtShort; SetDefaultWFXChannelOrder(device); - self->mFrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); + self->mFrameSize = device->frameSizeFromFmt(); loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; @@ -473,9 +473,9 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) #ifdef SL_DATAFORMAT_PCM_EX SLDataFormat_PCM_EX format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM_EX; - format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); + format_pcm.numChannels = device->channelsFromFmt(); format_pcm.sampleRate = device->Frequency * 1000; - format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + format_pcm.bitsPerSample = device->bytesFromFmt() * 8; format_pcm.containerSize = format_pcm.bitsPerSample; format_pcm.channelMask = GetChannelMask(device->FmtChans); format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : @@ -484,9 +484,9 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) #else SLDataFormat_PCM format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); + format_pcm.numChannels = device->channelsFromFmt(); format_pcm.samplesPerSec = device->Frequency * 1000; - format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + format_pcm.bitsPerSample = device->bytesFromFmt() * 8; format_pcm.containerSize = format_pcm.bitsPerSample; format_pcm.channelMask = GetChannelMask(device->FmtChans); format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : @@ -755,7 +755,7 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name device->UpdateSize = update_len; device->NumUpdates = (length+update_len-1) / update_len; - self->mFrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); + self->mFrameSize = device->frameSizeFromFmt(); } loc_dev.locatorType = SL_DATALOCATOR_IODEVICE; loc_dev.deviceType = SL_IODEVICE_AUDIOINPUT; @@ -771,9 +771,9 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name #ifdef SL_DATAFORMAT_PCM_EX SLDataFormat_PCM_EX format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM_EX; - format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); + format_pcm.numChannels = device->channelsFromFmt(); format_pcm.sampleRate = device->Frequency * 1000; - format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + format_pcm.bitsPerSample = device->bytesFromFmt() * 8; format_pcm.containerSize = format_pcm.bitsPerSample; format_pcm.channelMask = GetChannelMask(device->FmtChans); format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : @@ -782,9 +782,9 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name #else SLDataFormat_PCM format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); + format_pcm.numChannels = device->channelsFromFmt(); format_pcm.samplesPerSec = device->Frequency * 1000; - format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + format_pcm.bitsPerSample = device->bytesFromFmt() * 8; format_pcm.containerSize = format_pcm.bitsPerSample; format_pcm.channelMask = GetChannelMask(device->FmtChans); format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 5e8100fb..110672c7 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -298,7 +298,7 @@ int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self) SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); + frame_size = device->frameSizeFromFmt(); ALCplaybackOSS_lock(self); while(!self->mKillNow.load(std::memory_order_acquire) && @@ -417,9 +417,9 @@ ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) } periods = device->NumUpdates; - numChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); + numChannels = device->channelsFromFmt(); ossSpeed = device->Frequency; - frameSize = numChannels * BytesFromDevFmt(device->FmtType); + frameSize = numChannels * device->bytesFromFmt(); /* According to the OSS spec, 16 bytes (log2(16)) is the minimum. */ log2FragmentSize = maxi(log2i(device->UpdateSize*frameSize), 4); numFragmentsLogSize = (periods << 16) | log2FragmentSize; @@ -443,7 +443,7 @@ ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) } #undef CHECKERR - if((int)ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder) != numChannels) + if(device->channelsFromFmt() != numChannels) { ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); return ALC_FALSE; @@ -471,9 +471,7 @@ ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self) ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; try { - self->mMixData.resize(device->UpdateSize * FrameSizeFromDevFmt( - device->FmtChans, device->FmtType, device->mAmbiOrder - )); + self->mMixData.resize(device->UpdateSize * device->frameSizeFromFmt()); self->mKillNow.store(AL_FALSE); self->mThread = std::thread(ALCplaybackOSS_mixerProc, self); @@ -558,7 +556,7 @@ int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) SetRTPriority(); althrd_setname(RECORD_THREAD_NAME); - frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); + frame_size = device->frameSizeFromFmt(); while(!self->mKillNow.load()) { @@ -651,8 +649,8 @@ ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) } int periods{4}; - int numChannels{ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder)}; - int frameSize{numChannels * BytesFromDevFmt(device->FmtType)}; + int numChannels{device->channelsFromFmt()}; + int frameSize{numChannels * device->bytesFromFmt()}; int ossSpeed{static_cast(device->Frequency)}; int log2FragmentSize{log2i(device->UpdateSize * device->NumUpdates * frameSize / periods)}; @@ -682,7 +680,7 @@ ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) } #undef CHECKERR - if((int)ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder) != numChannels) + if(device->channelsFromFmt() != numChannels) { ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); close(self->fd); diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index 8b8c7fef..93384489 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -390,7 +390,7 @@ ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) samples = device->UpdateSize * device->NumUpdates; samples = maxu(samples, 100 * device->Frequency / 1000); - frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); + frame_size = device->frameSizeFromFmt(); self->Ring = ll_ringbuffer_create(samples, frame_size, false); if(self->Ring == nullptr) return ALC_INVALID_VALUE; @@ -424,7 +424,7 @@ ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); return ALC_INVALID_VALUE; } - self->Params.channelCount = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); + self->Params.channelCount = device->channelsFromFmt(); err = Pa_OpenStream(&self->Stream, &self->Params, nullptr, device->Frequency, paFramesPerBufferUnspecified, paNoFlag, diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index b7dcd87c..cbf2992d 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -1037,7 +1037,7 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) break; } self->spec.rate = device->Frequency; - self->spec.channels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); + self->spec.channels = device->channelsFromFmt(); if(pa_sample_spec_valid(&self->spec) == 0) { @@ -1552,7 +1552,7 @@ ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) } self->spec.rate = device->Frequency; - self->spec.channels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); + self->spec.channels = device->channelsFromFmt(); if(pa_sample_spec_valid(&self->spec) == 0) { diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index 3d09a744..f8b26878 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -210,9 +210,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) param.sched_priority=param.sched_curpriority+1; SchedSet(0, 0, SCHED_NOCHANGE, ¶m); - const ALint frame_size = FrameSizeFromDevFmt( - device->FmtChans, device->FmtType, device->mAmbiOrder - ); + const ALint frame_size = device->frameSizeFromFmt(); PlaybackWrapper_lock(self); while(!data->mKillNow.load(std::memory_order_acquire)) @@ -385,14 +383,13 @@ static ALCboolean qsa_reset_playback(PlaybackWrapper *self) data->cparams.start_mode=SND_PCM_START_FULL; data->cparams.stop_mode=SND_PCM_STOP_STOP; - data->cparams.buf.block.frag_size=device->UpdateSize * - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); + data->cparams.buf.block.frag_size=device->UpdateSize * device->frameSizeFromFmt(); data->cparams.buf.block.frags_max=device->NumUpdates; data->cparams.buf.block.frags_min=device->NumUpdates; data->cparams.format.interleave=1; data->cparams.format.rate=device->Frequency; - data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); + data->cparams.format.voices=device->channelsFromFmt(); data->cparams.format.format=format; if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0) @@ -575,8 +572,7 @@ static ALCboolean qsa_reset_playback(PlaybackWrapper *self) SetDefaultChannelOrder(device); - device->UpdateSize=data->csetup.buf.block.frag_size/ - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); + device->UpdateSize=data->csetup.buf.block.frag_size / device->frameSizeFromFmt(); device->NumUpdates=data->csetup.buf.block.frags; data->size=data->csetup.buf.block.frag_size; @@ -757,14 +753,13 @@ static ALCenum qsa_open_capture(CaptureWrapper *self, const ALCchar *deviceName) data->cparams.start_mode=SND_PCM_START_GO; data->cparams.stop_mode=SND_PCM_STOP_STOP; - data->cparams.buf.block.frag_size=device->UpdateSize* - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); + data->cparams.buf.block.frag_size=device->UpdateSize * device->frameSizeFromFmt(); data->cparams.buf.block.frags_max=device->NumUpdates; data->cparams.buf.block.frags_min=device->NumUpdates; data->cparams.format.interleave=1; data->cparams.format.rate=device->Frequency; - data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); + data->cparams.format.voices=device->channelsFromFmt(); data->cparams.format.format=format; if(snd_pcm_plugin_params(data->pcmHandle, &data->cparams) < 0) @@ -822,7 +817,7 @@ static ALCuint qsa_available_samples(CaptureWrapper *self) ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; qsa_data *data = self->ExtraData.get(); snd_pcm_channel_status_t status; - ALint frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); + ALint frame_size = device->frameSizeFromFmt(); ALint free_size; int rstatus; @@ -859,7 +854,7 @@ static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuin int selectret; struct timeval timeout; int bytes_read; - ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); + ALint frame_size=device->frameSizeFromFmt(); ALint len=samples*frame_size; int rstatus; diff --git a/Alc/backends/sdl2.cpp b/Alc/backends/sdl2.cpp index d643faa3..f0c98fab 100644 --- a/Alc/backends/sdl2.cpp +++ b/Alc/backends/sdl2.cpp @@ -73,7 +73,7 @@ static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device) SET_VTABLE2(ALCsdl2Backend, ALCbackend, self); self->deviceID = 0; - self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); + self->frameSize = device->frameSizeFromFmt(); self->Frequency = device->Frequency; self->FmtChans = device->FmtChans; self->FmtType = device->FmtType; @@ -168,7 +168,7 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) device->UpdateSize = have.samples; device->NumUpdates = 2; /* SDL always (tries to) use two periods. */ - self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); + self->frameSize = device->frameSizeFromFmt(); self->Frequency = device->Frequency; self->FmtChans = device->FmtChans; self->FmtType = device->FmtType; diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index 1dabe5ca..9ebad671 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -97,7 +97,7 @@ static int SndioPlayback_mixerProc(SndioPlayback *self) SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); + frameSize = device->frameSizeFromFmt(); while(!self->mKillNow.load(std::memory_order_acquire) && device->Connected.load(std::memory_order_acquire)) @@ -238,9 +238,7 @@ static ALCboolean SndioPlayback_start(SndioPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - self->data_size = device->UpdateSize * FrameSizeFromDevFmt( - device->FmtChans, device->FmtType, device->mAmbiOrder - ); + self->data_size = device->UpdateSize * device->frameSizeFromFmt(); al_free(self->mix_data); self->mix_data = al_calloc(16, self->data_size); @@ -334,7 +332,7 @@ static int SndioCapture_recordProc(SndioCapture *self) SetRTPriority(); althrd_setname(RECORD_THREAD_NAME); - frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); + frameSize = device->frameSizeFromFmt(); while(!self->mKillNow.load(std::memory_order_acquire) && device->Connected.load(std::memory_order_acquire)) @@ -433,7 +431,7 @@ static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) par.bits = par.bps * 8; par.le = SIO_LE_NATIVE; par.msb = SIO_LE_NATIVE ? 0 : 1; - par.rchan = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); + par.rchan = device->channelsFromFmt(); par.rate = device->Frequency; par.appbufsz = maxu(device->UpdateSize*device->NumUpdates, (device->Frequency+9)/10); @@ -461,7 +459,7 @@ static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) (device->FmtType == DevFmtUShort && par.bits == 16 && par.sig == 0) || (device->FmtType == DevFmtInt && par.bits == 32 && par.sig != 0) || (device->FmtType == DevFmtUInt && par.bits == 32 && par.sig == 0)) || - ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder) != (ALsizei)par.rchan || + device->channelsFromFmt() != (ALsizei)par.rchan || device->Frequency != par.rate) { ERR("Failed to set format %s %s %uhz, got %c%u %u-channel %uhz instead\n", diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index 941ca015..8871fb93 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -114,7 +114,7 @@ static int ALCsolarisBackend_mixerProc(ALCsolarisBackend *self) SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder); + frame_size = device->frameSizeFromFmt(); ALCsolarisBackend_lock(self); while(!self->mKillNow.load(std::memory_order_acquire) && @@ -203,7 +203,7 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) if(device->FmtChans != DevFmtMono) device->FmtChans = DevFmtStereo; - numChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); + numChannels = device->channelsFromFmt(); info.play.channels = numChannels; switch(device->FmtType) @@ -228,7 +228,7 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) break; } - frameSize = numChannels * BytesFromDevFmt(device->FmtType); + frameSize = numChannels * device->bytesFromFmt(); info.play.buffer_size = device->UpdateSize*device->NumUpdates * frameSize; if(ioctl(self->fd, AUDIO_SETINFO, &info) < 0) @@ -237,9 +237,10 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) return ALC_FALSE; } - if(ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder) != (ALsizei)info.play.channels) + if(device->channelsFromFmt() != (ALsizei)info.play.channels) { - ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(device->FmtChans), info.play.channels); + ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(device->FmtChans), + info.play.channels); return ALC_FALSE; } @@ -259,9 +260,7 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) SetDefaultChannelOrder(device); free(self->mix_data); - self->data_size = device->UpdateSize * FrameSizeFromDevFmt( - device->FmtChans, device->FmtType, device->mAmbiOrder - ); + self->data_size = device->UpdateSize * device->frameSizeFromFmt(); self->mix_data = static_cast(calloc(1, self->data_size)); return ALC_TRUE; diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index b928682f..79e4af04 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -1301,8 +1301,7 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) } else { - ALuint framesize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, - device->mAmbiOrder); + const auto framesize = static_cast(device->frameSizeFromFmt()); size_t len1 = minz(data.first.len, numsamples); size_t len2 = minz(data.second.len, numsamples-len1); @@ -1665,8 +1664,8 @@ HRESULT ALCwasapiCapture::resetProxy() if(device->Frequency != OutputType.Format.nSamplesPerSec || device->FmtType != srcType) { mSampleConv = CreateSampleConverter( - srcType, device->FmtType, ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder), - OutputType.Format.nSamplesPerSec, device->Frequency, BSinc24Resampler + srcType, device->FmtType, device->channelsFromFmt(), OutputType.Format.nSamplesPerSec, + device->Frequency, BSinc24Resampler ); if(!mSampleConv) { @@ -1698,10 +1697,7 @@ HRESULT ALCwasapiCapture::resetProxy() buffer_len = maxu(device->UpdateSize*device->NumUpdates, buffer_len); ll_ringbuffer_free(mRing); - mRing = ll_ringbuffer_create(buffer_len, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder), - false - ); + mRing = ll_ringbuffer_create(buffer_len, device->frameSizeFromFmt(), false); if(!mRing) { ERR("Failed to allocate capture ring buffer\n"); diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index afa948cb..463e6bd7 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -130,7 +130,7 @@ int ALCwaveBackend_mixerProc(ALCwaveBackend *self) althrd_setname(MIXER_THREAD_NAME); - ALsizei frameSize{FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder)}; + const ALsizei frameSize{device->frameSizeFromFmt()}; ALint64 done{0}; auto start = std::chrono::steady_clock::now(); @@ -155,7 +155,7 @@ int ALCwaveBackend_mixerProc(ALCwaveBackend *self) if(!IS_LITTLE_ENDIAN) { - const ALsizei bytesize{BytesFromDevFmt(device->FmtType)}; + const ALsizei bytesize{device->bytesFromFmt()}; ALsizei i; if(bytesize == 2) @@ -284,14 +284,15 @@ ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break; case DevFmtAmbi3D: /* .amb output requires FuMa */ + device->mAmbiOrder = mini(device->mAmbiOrder, 3); device->mAmbiLayout = AmbiLayout::FuMa; device->mAmbiScale = AmbiNorm::FuMa; isbformat = 1; chanmask = 0; break; } - bits = BytesFromDevFmt(device->FmtType) * 8; - channels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); + bits = device->bytesFromFmt() * 8; + channels = device->channelsFromFmt(); fputs("RIFF", self->mFile); fwrite32le(0xFFFFFFFF, self->mFile); // 'RIFF' header len; filled in at close @@ -337,9 +338,7 @@ ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) SetDefaultWFXChannelOrder(device); - ALuint bufsize{FrameSizeFromDevFmt( - device->FmtChans, device->FmtType, device->mAmbiOrder - ) * device->UpdateSize}; + const ALuint bufsize{device->frameSizeFromFmt() * device->UpdateSize}; self->mBuffer.resize(bufsize); return ALC_TRUE; diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index ff5d026c..362b2e5e 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -336,8 +336,7 @@ ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self) } SetDefaultWFXChannelOrder(device); - ALuint BufferSize{device->UpdateSize * - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->mAmbiOrder)}; + ALuint BufferSize{device->UpdateSize * device->frameSizeFromFmt()}; al_free(self->WaveBuffer[0].lpData); self->WaveBuffer[0] = WAVEHDR{}; @@ -558,8 +557,8 @@ ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName) self->Format = WAVEFORMATEX{}; self->Format.wFormatTag = (device->FmtType == DevFmtFloat) ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM; - self->Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); - self->Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + self->Format.nChannels = device->channelsFromFmt(); + self->Format.wBitsPerSample = device->bytesFromFmt() * 8; self->Format.nBlockAlign = self->Format.wBitsPerSample * self->Format.nChannels / 8; self->Format.nSamplesPerSec = device->Frequency; diff --git a/Alc/panning.cpp b/Alc/panning.cpp index a8dace5a..5163f59a 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -598,7 +598,7 @@ void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&sp device->FOAOut.NumChannels = count; } - device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); + device->RealOut.NumChannels = device->channelsFromFmt(); using namespace std::placeholders; auto accum_spkr_dist = std::bind( @@ -732,7 +732,7 @@ void InitHrtfPanning(ALCdevice *device) device->FOAOut.NumChannels = 0; } - device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); + device->RealOut.NumChannels = device->channelsFromFmt(); BuildBFormatHrtf(device->HrtfHandle, device->mHrtfState.get(), device->Dry.NumChannels, AmbiPoints, AmbiMatrix, @@ -759,7 +759,7 @@ void InitUhjPanning(ALCdevice *device) device->FOAOut.CoeffCount = device->Dry.CoeffCount; device->FOAOut.NumChannels = 0; - device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->mAmbiOrder); + device->RealOut.NumChannels = device->channelsFromFmt(); } } // namespace diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index da9b51ac..a2666435 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -810,8 +810,7 @@ struct ALCdevice_struct { ALsizei bytesFromFmt() const noexcept { return BytesFromDevFmt(FmtType); } ALsizei channelsFromFmt() const noexcept { return ChannelsFromDevFmt(FmtChans, mAmbiOrder); } - ALsizei frameSizeFromFmt() const noexcept - { return FrameSizeFromDevFmt(FmtChans, FmtType, mAmbiOrder); } + ALsizei frameSizeFromFmt() const noexcept { return bytesFromFmt() * channelsFromFmt(); } DEF_NEWDEL(ALCdevice) }; -- cgit v1.2.3 From d18140391ae6a33775493c0ffad309085992ac54 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 20 Dec 2018 02:46:59 -0800 Subject: Rename some conversion arrays --- Alc/ambidefs.h | 12 ++++++------ Alc/bformatdec.cpp | 6 +++--- Alc/panning.cpp | 44 ++++++++++++++++++++++---------------------- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Alc/ambidefs.h b/Alc/ambidefs.h index bdeac18e..bbf11403 100644 --- a/Alc/ambidefs.h +++ b/Alc/ambidefs.h @@ -32,14 +32,14 @@ /* NOTE: These are scale factors as applied to Ambisonics content. Decoder - * coefficients should be divided by these values to get proper N3D scalings. + * coefficients should be divided by these values to get proper scalings. */ struct AmbiScale { - static constexpr float N3D2N3D[MAX_AMBI_COEFFS]{ + static constexpr float FromN3D[MAX_AMBI_COEFFS]{ 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; - static constexpr float SN3D2N3D[MAX_AMBI_COEFFS]{ + static constexpr float FromSN3D[MAX_AMBI_COEFFS]{ 1.000000000f, /* ACN 0, sqrt(1) */ 1.732050808f, /* ACN 1, sqrt(3) */ 1.732050808f, /* ACN 2, sqrt(3) */ @@ -57,7 +57,7 @@ struct AmbiScale { 2.645751311f, /* ACN 14, sqrt(7) */ 2.645751311f, /* ACN 15, sqrt(7) */ }; - static constexpr float FuMa2N3D[MAX_AMBI_COEFFS]{ + static constexpr float FromFuMa[MAX_AMBI_COEFFS]{ 1.414213562f, /* ACN 0 (W), sqrt(2) */ 1.732050808f, /* ACN 1 (Y), sqrt(3) */ 1.732050808f, /* ACN 2 (Z), sqrt(3) */ @@ -78,7 +78,7 @@ struct AmbiScale { }; struct AmbiIndex { - static constexpr int FuMa2ACN[MAX_AMBI_COEFFS]{ + static constexpr int FromFuMa[MAX_AMBI_COEFFS]{ 0, /* W */ 3, /* X */ 1, /* Y */ @@ -96,7 +96,7 @@ struct AmbiIndex { 15, /* P */ 9, /* Q */ }; - static constexpr int ACN2ACN[MAX_AMBI_COEFFS]{ + static constexpr int FromACN[MAX_AMBI_COEFFS]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 2be6eae8..aeaa89a0 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -53,9 +53,9 @@ constexpr ALfloat Ambi3DDecoderHFScale[MAX_AMBI_COEFFS] = { auto GetAmbiScales(AmbDecScale scaletype) noexcept -> const float(&)[MAX_AMBI_COEFFS] { - if(scaletype == AmbDecScale::FuMa) return AmbiScale::FuMa2N3D; - if(scaletype == AmbDecScale::SN3D) return AmbiScale::SN3D2N3D; - return AmbiScale::N3D2N3D; + if(scaletype == AmbDecScale::FuMa) return AmbiScale::FromFuMa; + if(scaletype == AmbDecScale::SN3D) return AmbiScale::FromSN3D; + return AmbiScale::FromN3D; } } // namespace diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 5163f59a..819b5eb4 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -42,11 +42,11 @@ #include "bs2b.h" -constexpr float AmbiScale::N3D2N3D[MAX_AMBI_COEFFS]; -constexpr float AmbiScale::SN3D2N3D[MAX_AMBI_COEFFS]; -constexpr float AmbiScale::FuMa2N3D[MAX_AMBI_COEFFS]; -constexpr int AmbiIndex::FuMa2ACN[MAX_AMBI_COEFFS]; -constexpr int AmbiIndex::ACN2ACN[MAX_AMBI_COEFFS]; +constexpr float AmbiScale::FromN3D[MAX_AMBI_COEFFS]; +constexpr float AmbiScale::FromSN3D[MAX_AMBI_COEFFS]; +constexpr float AmbiScale::FromFuMa[MAX_AMBI_COEFFS]; +constexpr int AmbiIndex::FromFuMa[MAX_AMBI_COEFFS]; +constexpr int AmbiIndex::FromACN[MAX_AMBI_COEFFS]; namespace { @@ -326,22 +326,22 @@ void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei ( auto GetAmbiScales(AmbDecScale scaletype) noexcept -> const float(&)[MAX_AMBI_COEFFS] { - if(scaletype == AmbDecScale::FuMa) return AmbiScale::FuMa2N3D; - if(scaletype == AmbDecScale::SN3D) return AmbiScale::SN3D2N3D; - return AmbiScale::N3D2N3D; + if(scaletype == AmbDecScale::FuMa) return AmbiScale::FromFuMa; + if(scaletype == AmbDecScale::SN3D) return AmbiScale::FromSN3D; + return AmbiScale::FromN3D; } auto GetAmbiScales(AmbiNorm scaletype) noexcept -> const float(&)[MAX_AMBI_COEFFS] { - if(scaletype == AmbiNorm::FuMa) return AmbiScale::FuMa2N3D; - if(scaletype == AmbiNorm::SN3D) return AmbiScale::SN3D2N3D; - return AmbiScale::N3D2N3D; + if(scaletype == AmbiNorm::FuMa) return AmbiScale::FromFuMa; + if(scaletype == AmbiNorm::SN3D) return AmbiScale::FromSN3D; + return AmbiScale::FromN3D; } auto GetAmbiLayout(AmbiLayout layouttype) noexcept -> const int(&)[MAX_AMBI_COEFFS] { - if(layouttype == AmbiLayout::FuMa) return AmbiIndex::FuMa2ACN; - return AmbiIndex::ACN2ACN; + if(layouttype == AmbiLayout::FuMa) return AmbiIndex::FromFuMa; + return AmbiIndex::FromACN; } @@ -428,8 +428,8 @@ void InitPanning(ALCdevice *device) * The upsampler expects this and will convert it for output. */ device->FOAOut.Ambi = AmbiConfig{}; - acnmap_end = std::begin(AmbiIndex::ACN2ACN) + 4; - std::transform(std::begin(AmbiIndex::ACN2ACN), acnmap_end, std::begin(device->FOAOut.Ambi.Map), + std::transform(std::begin(AmbiIndex::FromACN), std::begin(AmbiIndex::FromACN)+4, + std::begin(device->FOAOut.Ambi.Map), [](const ALsizei &acn) noexcept { return BFChannelConfig{1.0f, acn}; } ); device->FOAOut.CoeffCount = 0; @@ -463,8 +463,8 @@ void InitPanning(ALCdevice *device) else { device->FOAOut.Ambi = AmbiConfig{}; - auto acnmap_end = std::begin(AmbiIndex::ACN2ACN) + 4; - std::transform(std::begin(AmbiIndex::ACN2ACN), acnmap_end, std::begin(device->FOAOut.Ambi.Map), + std::transform(std::begin(AmbiIndex::FromACN), std::begin(AmbiIndex::FromACN)+4, + std::begin(device->FOAOut.Ambi.Map), [](const ALsizei &acn) noexcept { return BFChannelConfig{1.0f, acn}; } ); device->FOAOut.CoeffCount = 0; @@ -747,10 +747,10 @@ void InitUhjPanning(ALCdevice *device) { static constexpr ALsizei count{3}; - auto acnmap_end = std::begin(AmbiIndex::FuMa2ACN) + count; - std::transform(std::begin(AmbiIndex::FuMa2ACN), acnmap_end, std::begin(device->Dry.Ambi.Map), + auto acnmap_end = std::begin(AmbiIndex::FromFuMa) + count; + std::transform(std::begin(AmbiIndex::FromFuMa), acnmap_end, std::begin(device->Dry.Ambi.Map), [](const ALsizei &acn) noexcept -> BFChannelConfig - { return BFChannelConfig{1.0f/AmbiScale::FuMa2N3D[acn], acn}; } + { return BFChannelConfig{1.0f/AmbiScale::FromFuMa[acn], acn}; } ); device->Dry.CoeffCount = 0; device->Dry.NumChannels = count; @@ -1146,8 +1146,8 @@ no_hrtf: void aluInitEffectPanning(ALeffectslot *slot) { const size_t count{countof(slot->ChanMap)}; - auto acnmap_end = std::begin(AmbiIndex::ACN2ACN) + count; - std::transform(std::begin(AmbiIndex::ACN2ACN), acnmap_end, std::begin(slot->ChanMap), + auto acnmap_end = std::begin(AmbiIndex::FromACN) + count; + std::transform(std::begin(AmbiIndex::FromACN), acnmap_end, std::begin(slot->ChanMap), [](const ALsizei &acn) noexcept { return BFChannelConfig{1.0f, acn}; } ); slot->NumChannels = static_cast(count); -- cgit v1.2.3 From 8d3f7651c9d188f047a2b2c2ee4e2012b56d9b50 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 20 Dec 2018 03:26:46 -0800 Subject: Use std::array in place of some C-style arrays --- Alc/ambidefs.h | 22 ++++++++++++---------- Alc/bformatdec.cpp | 4 ++-- Alc/panning.cpp | 37 ++++++++++++++++++------------------- 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/Alc/ambidefs.h b/Alc/ambidefs.h index bbf11403..82eb7ee3 100644 --- a/Alc/ambidefs.h +++ b/Alc/ambidefs.h @@ -1,6 +1,8 @@ #ifndef AMBIDEFS_H #define AMBIDEFS_H +#include + /* The maximum number of Ambisonics coefficients. For a given order (o), the * size needed will be (o+1)**2, thus zero-order has 1, first-order has 4, * second-order has 9, third-order has 16, and fourth-order has 25. @@ -35,11 +37,11 @@ * coefficients should be divided by these values to get proper scalings. */ struct AmbiScale { - static constexpr float FromN3D[MAX_AMBI_COEFFS]{ + static constexpr std::array FromN3D{{ 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f - }; - static constexpr float FromSN3D[MAX_AMBI_COEFFS]{ + }}; + static constexpr std::array FromSN3D{{ 1.000000000f, /* ACN 0, sqrt(1) */ 1.732050808f, /* ACN 1, sqrt(3) */ 1.732050808f, /* ACN 2, sqrt(3) */ @@ -56,8 +58,8 @@ struct AmbiScale { 2.645751311f, /* ACN 13, sqrt(7) */ 2.645751311f, /* ACN 14, sqrt(7) */ 2.645751311f, /* ACN 15, sqrt(7) */ - }; - static constexpr float FromFuMa[MAX_AMBI_COEFFS]{ + }}; + static constexpr std::array FromFuMa{{ 1.414213562f, /* ACN 0 (W), sqrt(2) */ 1.732050808f, /* ACN 1 (Y), sqrt(3) */ 1.732050808f, /* ACN 2 (Z), sqrt(3) */ @@ -74,11 +76,11 @@ struct AmbiScale { 2.231093404f, /* ACN 13 (L), sqrt(224/45) */ 1.972026594f, /* ACN 14 (N), sqrt(35)/3 */ 2.091650066f, /* ACN 15 (P), sqrt(35/8) */ - }; + }}; }; struct AmbiIndex { - static constexpr int FromFuMa[MAX_AMBI_COEFFS]{ + static constexpr std::array FromFuMa{{ 0, /* W */ 3, /* X */ 1, /* Y */ @@ -95,11 +97,11 @@ struct AmbiIndex { 10, /* O */ 15, /* P */ 9, /* Q */ - }; - static constexpr int FromACN[MAX_AMBI_COEFFS]{ + }}; + static constexpr std::array FromACN{{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 - }; + }}; }; #endif /* AMBIDEFS_H */ diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index aeaa89a0..6a149611 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -51,7 +51,7 @@ constexpr ALfloat Ambi3DDecoderHFScale[MAX_AMBI_COEFFS] = { }; -auto GetAmbiScales(AmbDecScale scaletype) noexcept -> const float(&)[MAX_AMBI_COEFFS] +auto GetAmbiScales(AmbDecScale scaletype) noexcept -> const std::array& { if(scaletype == AmbDecScale::FuMa) return AmbiScale::FromFuMa; if(scaletype == AmbDecScale::SN3D) return AmbiScale::FromSN3D; @@ -130,7 +130,7 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, mUpSampler[3].Gains[LF_BAND] = 0.0f; } - const float (&coeff_scale)[MAX_AMBI_COEFFS] = GetAmbiScales(conf->CoeffScale); + const std::array &coeff_scale = GetAmbiScales(conf->CoeffScale); const ALsizei coeff_count{periphonic ? MAX_AMBI_COEFFS : MAX_AMBI2D_COEFFS}; mMatrix = MatrixU{}; diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 819b5eb4..50d1eec2 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -42,11 +42,11 @@ #include "bs2b.h" -constexpr float AmbiScale::FromN3D[MAX_AMBI_COEFFS]; -constexpr float AmbiScale::FromSN3D[MAX_AMBI_COEFFS]; -constexpr float AmbiScale::FromFuMa[MAX_AMBI_COEFFS]; -constexpr int AmbiIndex::FromFuMa[MAX_AMBI_COEFFS]; -constexpr int AmbiIndex::FromACN[MAX_AMBI_COEFFS]; +constexpr std::array AmbiScale::FromN3D; +constexpr std::array AmbiScale::FromSN3D; +constexpr std::array AmbiScale::FromFuMa; +constexpr std::array AmbiIndex::FromFuMa; +constexpr std::array AmbiIndex::FromACN; namespace { @@ -324,21 +324,21 @@ void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei ( } } -auto GetAmbiScales(AmbDecScale scaletype) noexcept -> const float(&)[MAX_AMBI_COEFFS] +auto GetAmbiScales(AmbDecScale scaletype) noexcept -> const std::array& { if(scaletype == AmbDecScale::FuMa) return AmbiScale::FromFuMa; if(scaletype == AmbDecScale::SN3D) return AmbiScale::FromSN3D; return AmbiScale::FromN3D; } -auto GetAmbiScales(AmbiNorm scaletype) noexcept -> const float(&)[MAX_AMBI_COEFFS] +auto GetAmbiScales(AmbiNorm scaletype) noexcept -> const std::array& { if(scaletype == AmbiNorm::FuMa) return AmbiScale::FromFuMa; if(scaletype == AmbiNorm::SN3D) return AmbiScale::FromSN3D; return AmbiScale::FromN3D; } -auto GetAmbiLayout(AmbiLayout layouttype) noexcept -> const int(&)[MAX_AMBI_COEFFS] +auto GetAmbiLayout(AmbiLayout layouttype) noexcept -> const std::array& { if(layouttype == AmbiLayout::FuMa) return AmbiIndex::FromFuMa; return AmbiIndex::FromACN; @@ -402,14 +402,13 @@ void InitPanning(ALCdevice *device) if(device->FmtChans == DevFmtAmbi3D) { const char *devname{device->DeviceName.c_str()}; - const ALsizei (&acnmap)[MAX_AMBI_COEFFS] = GetAmbiLayout(device->mAmbiLayout); - const ALfloat (&n3dscale)[MAX_AMBI_COEFFS] = GetAmbiScales(device->mAmbiScale); + const std::array &acnmap = GetAmbiLayout(device->mAmbiLayout); + const std::array &n3dscale = GetAmbiScales(device->mAmbiScale); count = (device->mAmbiOrder == 3) ? 16 : (device->mAmbiOrder == 2) ? 9 : (device->mAmbiOrder == 1) ? 4 : 1; - auto acnmap_end = std::begin(acnmap) + count; - std::transform(std::begin(acnmap), acnmap_end, std::begin(device->Dry.Ambi.Map), + std::transform(acnmap.begin(), acnmap.begin()+count, std::begin(device->Dry.Ambi.Map), [&n3dscale](const ALsizei &acn) noexcept -> BFChannelConfig { return BFChannelConfig{1.0f/n3dscale[acn], acn}; } ); @@ -428,7 +427,7 @@ void InitPanning(ALCdevice *device) * The upsampler expects this and will convert it for output. */ device->FOAOut.Ambi = AmbiConfig{}; - std::transform(std::begin(AmbiIndex::FromACN), std::begin(AmbiIndex::FromACN)+4, + std::transform(AmbiIndex::FromACN.begin(), AmbiIndex::FromACN.begin()+4, std::begin(device->FOAOut.Ambi.Map), [](const ALsizei &acn) noexcept { return BFChannelConfig{1.0f, acn}; } ); @@ -463,7 +462,7 @@ void InitPanning(ALCdevice *device) else { device->FOAOut.Ambi = AmbiConfig{}; - std::transform(std::begin(AmbiIndex::FromACN), std::begin(AmbiIndex::FromACN)+4, + std::transform(AmbiIndex::FromACN.begin(), AmbiIndex::FromACN.begin()+4, std::begin(device->FOAOut.Ambi.Map), [](const ALsizei &acn) noexcept { return BFChannelConfig{1.0f, acn}; } ); @@ -483,7 +482,7 @@ void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n", conf->XOverFreq); - const ALfloat (&coeff_scale)[MAX_AMBI_COEFFS] = GetAmbiScales(conf->CoeffScale); + const std::array &coeff_scale = GetAmbiScales(conf->CoeffScale); ChannelMap chanmap[MAX_OUTPUT_CHANNELS]{}; for(size_t i{0u};i < conf->Speakers.size();i++) { @@ -747,8 +746,8 @@ void InitUhjPanning(ALCdevice *device) { static constexpr ALsizei count{3}; - auto acnmap_end = std::begin(AmbiIndex::FromFuMa) + count; - std::transform(std::begin(AmbiIndex::FromFuMa), acnmap_end, std::begin(device->Dry.Ambi.Map), + auto acnmap_end = AmbiIndex::FromFuMa.begin() + count; + std::transform(AmbiIndex::FromFuMa.begin(), acnmap_end, std::begin(device->Dry.Ambi.Map), [](const ALsizei &acn) noexcept -> BFChannelConfig { return BFChannelConfig{1.0f/AmbiScale::FromFuMa[acn], acn}; } ); @@ -1146,8 +1145,8 @@ no_hrtf: void aluInitEffectPanning(ALeffectslot *slot) { const size_t count{countof(slot->ChanMap)}; - auto acnmap_end = std::begin(AmbiIndex::FromACN) + count; - std::transform(std::begin(AmbiIndex::FromACN), acnmap_end, std::begin(slot->ChanMap), + auto acnmap_end = AmbiIndex::FromACN.begin() + count; + std::transform(AmbiIndex::FromACN.begin(), acnmap_end, std::begin(slot->ChanMap), [](const ALsizei &acn) noexcept { return BFChannelConfig{1.0f, acn}; } ); slot->NumChannels = static_cast(count); -- cgit v1.2.3 From 49ac268334bf8875ff1b5baa1e79edc8b7fe15bd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 20 Dec 2018 04:19:35 -0800 Subject: Add index maps from 2D and 3D --- Alc/ambidefs.h | 8 ++++++++ Alc/bformatdec.cpp | 14 ++++++-------- Alc/panning.cpp | 33 ++++++++++++++++----------------- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/Alc/ambidefs.h b/Alc/ambidefs.h index 82eb7ee3..eeb09f75 100644 --- a/Alc/ambidefs.h +++ b/Alc/ambidefs.h @@ -102,6 +102,14 @@ struct AmbiIndex { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }}; + + static constexpr std::array From2D{{ + 0, 1,3, 4,8, 9,15 + }}; + static constexpr std::array From3D{{ + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 + }}; }; #endif /* AMBIDEFS_H */ diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 6a149611..d0d1325a 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -63,8 +63,6 @@ auto GetAmbiScales(AmbDecScale scaletype) noexcept -> const std::array ALfloat - { ASSUME(index > 0); return coeffs[index]; } + { ASSUME(index >= 0); return coeffs[index]; } ); } assert(chancount >= 3); for(ALsizei c{0};c < 3;c++) { - const ALsizei i{map2DTo3D[c]}; + const ALsizei i{AmbiIndex::From2D[c]}; ALdouble gain{0.0}; for(size_t k{0u};k < COUNTOF(Ambi3DDecoder);k++) gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][c]; @@ -142,7 +140,7 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, ALfloat (&mtx)[MAX_AMBI_COEFFS] = mMatrix.Single[chanmap[i]]; for(ALsizei j{0},k{0};j < coeff_count;j++) { - const ALsizei l{periphonic ? j : map2DTo3D[j]}; + const ALsizei l{periphonic ? j : AmbiIndex::From2D[j]}; if(!(conf->ChanMask&(1<HFMatrix[i][k] / coeff_scale[l] * ((l>=9) ? conf->HFOrderGain[3] : @@ -163,7 +161,7 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, ALfloat (&mtx)[sNumBands][MAX_AMBI_COEFFS] = mMatrix.Dual[chanmap[i]]; for(ALsizei j{0},k{0};j < coeff_count;j++) { - const ALsizei l{periphonic ? j : map2DTo3D[j]}; + const ALsizei l{periphonic ? j : AmbiIndex::From2D[j]}; if(!(conf->ChanMask&(1<HFMatrix[i][k] / coeff_scale[l] * ((l>=9) ? conf->HFOrderGain[3] : diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 50d1eec2..d03977b8 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -47,6 +47,8 @@ constexpr std::array AmbiScale::FromSN3D; constexpr std::array AmbiScale::FromFuMa; constexpr std::array AmbiIndex::FromFuMa; constexpr std::array AmbiIndex::FromACN; +constexpr std::array AmbiIndex::From2D; +constexpr std::array AmbiIndex::From3D; namespace { @@ -423,11 +425,8 @@ void InitPanning(ALCdevice *device) } else { - /* FOA output is always ACN+N3D for higher-order ambisonic output. - * The upsampler expects this and will convert it for output. - */ device->FOAOut.Ambi = AmbiConfig{}; - std::transform(AmbiIndex::FromACN.begin(), AmbiIndex::FromACN.begin()+4, + std::transform(AmbiIndex::From3D.begin(), AmbiIndex::From3D.begin()+4, std::begin(device->FOAOut.Ambi.Map), [](const ALsizei &acn) noexcept { return BFChannelConfig{1.0f, acn}; } ); @@ -462,7 +461,7 @@ void InitPanning(ALCdevice *device) else { device->FOAOut.Ambi = AmbiConfig{}; - std::transform(AmbiIndex::FromACN.begin(), AmbiIndex::FromACN.begin()+4, + std::transform(AmbiIndex::From3D.begin(), AmbiIndex::From3D.begin()+4, std::begin(device->FOAOut.Ambi.Map), [](const ALsizei &acn) noexcept { return BFChannelConfig{1.0f, acn}; } ); @@ -513,11 +512,11 @@ void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei } else { - static constexpr int map[4] = { 0, 1, 2, 3 }; static constexpr ALsizei count{4}; device->FOAOut.Ambi = AmbiConfig{}; - std::transform(std::begin(map), std::begin(map)+count, std::begin(device->FOAOut.Ambi.Map), + std::transform(AmbiIndex::From3D.begin(), AmbiIndex::From3D.begin()+count, + std::begin(device->FOAOut.Ambi.Map), [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } ); device->FOAOut.CoeffCount = 0; @@ -540,19 +539,19 @@ void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&sp ALsizei count; if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { - static constexpr int map[MAX_AMBI_COEFFS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; count = (conf->ChanMask > AMBI_2ORDER_MASK) ? 16 : (conf->ChanMask > AMBI_1ORDER_MASK) ? 9 : 4; - std::transform(std::begin(map), std::begin(map)+count, std::begin(device->Dry.Ambi.Map), + std::transform(AmbiIndex::From3D.begin(), AmbiIndex::From3D.begin()+count, + std::begin(device->Dry.Ambi.Map), [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } ); } else { - static constexpr int map[MAX_AMBI2D_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; count = (conf->ChanMask > AMBI_2ORDER_MASK) ? 7 : (conf->ChanMask > AMBI_1ORDER_MASK) ? 5 : 3; - std::transform(std::begin(map), std::begin(map)+count, std::begin(device->Dry.Ambi.Map), + std::transform(AmbiIndex::From2D.begin(), AmbiIndex::From2D.begin()+count, + std::begin(device->Dry.Ambi.Map), [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } ); } @@ -579,17 +578,17 @@ void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&sp device->FOAOut.Ambi = AmbiConfig{}; if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { - static constexpr int map[4] = { 0, 1, 2, 3 }; count = 4; - std::transform(std::begin(map), std::begin(map)+count, std::begin(device->FOAOut.Ambi.Map), + std::transform(AmbiIndex::From3D.begin(), AmbiIndex::From3D.begin()+count, + std::begin(device->FOAOut.Ambi.Map), [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } ); } else { - static constexpr int map[3] = { 0, 1, 3 }; count = 3; - std::transform(std::begin(map), std::begin(map)+count, std::begin(device->FOAOut.Ambi.Map), + std::transform(AmbiIndex::From2D.begin(), AmbiIndex::From2D.begin()+count, + std::begin(device->FOAOut.Ambi.Map), [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } ); } @@ -1145,8 +1144,8 @@ no_hrtf: void aluInitEffectPanning(ALeffectslot *slot) { const size_t count{countof(slot->ChanMap)}; - auto acnmap_end = AmbiIndex::FromACN.begin() + count; - std::transform(AmbiIndex::FromACN.begin(), acnmap_end, std::begin(slot->ChanMap), + auto acnmap_end = AmbiIndex::From3D.begin() + count; + std::transform(AmbiIndex::From3D.begin(), acnmap_end, std::begin(slot->ChanMap), [](const ALsizei &acn) noexcept { return BFChannelConfig{1.0f, acn}; } ); slot->NumChannels = static_cast(count); -- cgit v1.2.3 From 10f87c5d26cf0cf4995228ce9671b6d0aeda5b9f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 20 Dec 2018 07:10:09 -0800 Subject: Use std::accumulate to get the max composited buffer length loaded --- Alc/mixvoice.cpp | 71 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index cd5d2504..682e552f 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -26,6 +26,9 @@ #include #include +#include +#include + #include "AL/al.h" #include "AL/alc.h" @@ -374,18 +377,17 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize /* If current pos is beyond the loop range, do not loop */ if(!BufferLoopItem || DataPosInt >= LoopEnd) { - ALsizei SizeToDo = SrcBufferSize - FilledAmt; + const ALsizei SizeToDo{SrcBufferSize - FilledAmt}; BufferLoopItem = nullptr; - ALsizei CompLen{0}; - auto load_buffer = [DataPosInt,&SrcData,NumChannels,SampleSize,chan,FilledAmt,SizeToDo,&CompLen](const ALbuffer *buffer) -> void + auto load_buffer = [DataPosInt,&SrcData,NumChannels,SampleSize,chan,FilledAmt,SizeToDo](ALsizei CompLen, const ALbuffer *buffer) -> ALsizei { if(DataPosInt >= buffer->SampleLen) - return; + return CompLen; /* Load what's left to play from the buffer */ - ALsizei DataSize{mini(SizeToDo, buffer->SampleLen - DataPosInt)}; + const ALsizei DataSize{mini(SizeToDo, buffer->SampleLen - DataPosInt)}; CompLen = maxi(CompLen, DataSize); const ALbyte *Data{buffer->mData.data()}; @@ -393,23 +395,23 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize &Data[(DataPosInt*NumChannels + chan)*SampleSize], NumChannels, buffer->FmtType, DataSize ); + return CompLen; }; auto buffers_end = BufferListItem->buffers + BufferListItem->num_buffers; - std::for_each(BufferListItem->buffers, buffers_end, load_buffer); - FilledAmt += CompLen; + FilledAmt += std::accumulate(BufferListItem->buffers, buffers_end, ALsizei{0}, + load_buffer); } else { const ALsizei SizeToDo{mini(SrcBufferSize - FilledAmt, LoopEnd - DataPosInt)}; - ALsizei CompLen{0}; - auto load_buffer = [DataPosInt,&SrcData,NumChannels,SampleSize,chan,FilledAmt,SizeToDo,&CompLen](const ALbuffer *buffer) -> void + auto load_buffer = [DataPosInt,&SrcData,NumChannels,SampleSize,chan,FilledAmt,SizeToDo](ALsizei CompLen, const ALbuffer *buffer) -> ALsizei { if(DataPosInt >= buffer->SampleLen) - return; + return CompLen; /* Load what's left of this loop iteration */ - ALsizei DataSize{mini(SizeToDo, buffer->SampleLen - DataPosInt)}; + const ALsizei DataSize{mini(SizeToDo, buffer->SampleLen - DataPosInt)}; CompLen = maxi(CompLen, DataSize); const ALbyte *Data{buffer->mData.data()}; @@ -417,35 +419,33 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize &Data[(DataPosInt*NumChannels + chan)*SampleSize], NumChannels, buffer->FmtType, DataSize ); + return CompLen; }; auto buffers_end = BufferListItem->buffers + BufferListItem->num_buffers; - std::for_each(BufferListItem->buffers, buffers_end, load_buffer); - FilledAmt += CompLen; + FilledAmt = std::accumulate(BufferListItem->buffers, buffers_end, ALsizei{0}, load_buffer); const ALsizei LoopSize{LoopEnd - LoopStart}; while(SrcBufferSize > FilledAmt) { const ALsizei SizeToDo{mini(SrcBufferSize - FilledAmt, LoopSize)}; - CompLen = 0; - auto load_buffer_loop = [LoopStart,&SrcData,NumChannels,SampleSize,chan,FilledAmt,SizeToDo,&CompLen](const ALbuffer *buffer) -> void + auto load_buffer_loop = [LoopStart,&SrcData,NumChannels,SampleSize,chan,FilledAmt,SizeToDo](ALsizei CompLen, const ALbuffer *buffer) -> ALsizei { - const ALbyte *Data = buffer->mData.data(); - ALsizei DataSize; - if(LoopStart >= buffer->SampleLen) - return; + return CompLen; - DataSize = mini(SizeToDo, buffer->SampleLen - LoopStart); + const ALsizei DataSize{mini(SizeToDo, buffer->SampleLen - LoopStart)}; CompLen = maxi(CompLen, DataSize); + const ALbyte *Data{buffer->mData.data()}; LoadSamples(&SrcData[FilledAmt], &Data[(LoopStart*NumChannels + chan)*SampleSize], NumChannels, buffer->FmtType, DataSize ); + return CompLen; }; - std::for_each(BufferListItem->buffers, buffers_end, load_buffer_loop); - FilledAmt += CompLen; + FilledAmt += std::accumulate(BufferListItem->buffers, buffers_end, + ALsizei{0}, load_buffer_loop); } } } @@ -466,12 +466,11 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize } const ALsizei SizeToDo{SrcBufferSize - FilledAmt}; - ALsizei CompLen{0}; - auto load_buffer = [pos,&SrcData,NumChannels,SampleSize,chan,FilledAmt,SizeToDo,&CompLen](const ALbuffer *buffer) -> void + auto load_buffer = [pos,&SrcData,NumChannels,SampleSize,chan,FilledAmt,SizeToDo](ALsizei CompLen, const ALbuffer *buffer) -> ALsizei { - if(!buffer) return; + if(!buffer) return CompLen; ALsizei DataSize{buffer->SampleLen}; - if(pos >= DataSize) return; + if(pos >= DataSize) return CompLen; DataSize = mini(SizeToDo, DataSize - pos); CompLen = maxi(CompLen, DataSize); @@ -481,10 +480,11 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize LoadSamples(&SrcData[FilledAmt], Data, NumChannels, buffer->FmtType, DataSize); + return CompLen; }; auto buffers_end = tmpiter->buffers + tmpiter->num_buffers; - std::for_each(tmpiter->buffers, buffers_end, load_buffer); - FilledAmt += CompLen; + FilledAmt += std::accumulate(tmpiter->buffers, buffers_end, ALsizei{0}, + load_buffer); if(SrcBufferSize <= FilledAmt) break; @@ -550,14 +550,11 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize } else { - MixHrtfParams hrtfparams; - ALsizei fademix = 0; - int lidx, ridx; - - lidx = GetChannelIdxByName(&Device->RealOut, FrontLeft); - ridx = GetChannelIdxByName(&Device->RealOut, FrontRight); + const int lidx{GetChannelIdxByName(&Device->RealOut, FrontLeft)}; + const int ridx{GetChannelIdxByName(&Device->RealOut, FrontRight)}; assert(lidx != -1 && ridx != -1); + ALsizei fademix{0}; if(!Counter) { /* No fading, just overwrite the old HRTF params. */ @@ -585,6 +582,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize */ ALfloat gain{lerp(parms->Hrtf.Old.Gain, parms->Hrtf.Target.Gain, minf(1.0f, (ALfloat)fademix/Counter))}; + MixHrtfParams hrtfparams; hrtfparams.Coeffs = parms->Hrtf.Target.Coeffs; hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; @@ -604,8 +602,8 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize if(fademix < DstBufferSize) { - ALsizei todo = DstBufferSize - fademix; - ALfloat gain = parms->Hrtf.Target.Gain; + const ALsizei todo{DstBufferSize - fademix}; + ALfloat gain{parms->Hrtf.Target.Gain}; /* Interpolate the target gain if the gain fading lasts * longer than this mix. @@ -614,6 +612,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize gain = lerp(parms->Hrtf.Old.Gain, gain, (ALfloat)todo/(Counter-fademix)); + MixHrtfParams hrtfparams; hrtfparams.Coeffs = parms->Hrtf.Target.Coeffs; hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; -- cgit v1.2.3 From 08b79b9bbfa96ee6dcbc4d58bf082c9e6df911df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 20 Dec 2018 11:46:40 -0800 Subject: Add an assume_aligned helper --- common/almalloc.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/common/almalloc.h b/common/almalloc.h index d9b285fe..7ec07004 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -68,6 +68,21 @@ struct allocator : public std::allocator { { } }; +template +inline T* assume_aligned(T *ptr) noexcept +{ + static_assert((alignment & (alignment-1)) == 0, "alignment must be a power of 2"); +#ifdef __GNUC__ + return reinterpret_cast(__builtin_assume_aligned(ptr, alignment)); +#elif defined(_MSC_VER) + auto ptrval = reinterpret_cast(ptr); + if((ptrval&(alignment-1)) != 0) __assume(0); + return reinterpret_cast(ptrval); +#else + return ptr; +#endif +} + } // namespace al #endif /* AL_MALLOC_H */ -- cgit v1.2.3 From 7dc553350bd70b77608b3da175d9146494fb861d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 20 Dec 2018 11:46:57 -0800 Subject: Clean up most of the compressor loops --- Alc/mastering.cpp | 357 +++++++++++++++++++++++++----------------------------- Alc/mastering.h | 16 +-- 2 files changed, 171 insertions(+), 202 deletions(-) diff --git a/Alc/mastering.cpp b/Alc/mastering.cpp index bf999709..007c2657 100644 --- a/Alc/mastering.cpp +++ b/Alc/mastering.cpp @@ -1,8 +1,8 @@ #include "config.h" -#include - +#include #include +#include #include "mastering.h" #include "alu.h" @@ -10,18 +10,6 @@ #include "math_defs.h" -/* Early MSVC lacks round/roundf */ -#if defined(_MSC_VER) && _MSC_VER < 1800 -static double round(double val) -{ - if(val < 0.0) - return ceil(val-0.5); - return floor(val+0.5); -} -#define roundf(f) ((float)round((float)(f))) -#endif - - /* These structures assume BUFFERSIZE is a power of 2. */ static_assert((BUFFERSIZE & (BUFFERSIZE-1)) == 0, "BUFFERSIZE is not a power of 2"); @@ -34,6 +22,10 @@ struct SlidingHold { }; +namespace { + +using namespace std::placeholders; + /* This sliding hold follows the input level with an instant attack and a * fixed duration hold before an instant release to the next highest level. * It is a sliding window maximum (descending maxima) implementation based on @@ -43,12 +35,12 @@ struct SlidingHold { */ static ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALfloat in) { - const ALsizei mask = BUFFERSIZE - 1; - const ALsizei length = Hold->Length; - ALfloat *RESTRICT values = Hold->Values; - ALsizei *RESTRICT expiries = Hold->Expiries; - ALsizei lowerIndex = Hold->LowerIndex; - ALsizei upperIndex = Hold->UpperIndex; + static constexpr ALsizei mask{BUFFERSIZE - 1}; + const ALsizei length{Hold->Length}; + ALfloat (&values)[BUFFERSIZE] = Hold->Values; + ALsizei (&expiries)[BUFFERSIZE] = Hold->Expiries; + ALsizei lowerIndex{Hold->LowerIndex}; + ALsizei upperIndex{Hold->UpperIndex}; if(i >= expiries[upperIndex]) upperIndex = (upperIndex + 1) & mask; @@ -83,47 +75,42 @@ static ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALflo static void ShiftSlidingHold(SlidingHold *Hold, const ALsizei n) { - const ALsizei lowerIndex = Hold->LowerIndex; - ALsizei *RESTRICT expiries = Hold->Expiries; - ALsizei i = Hold->UpperIndex; + ASSUME(Hold->UpperIndex >= 0); + ASSUME(Hold->LowerIndex >= 0); - if(lowerIndex < i) + auto exp_begin = std::begin(Hold->Expiries) + Hold->UpperIndex; + auto exp_last = std::begin(Hold->Expiries) + Hold->LowerIndex; + if(exp_last < exp_begin) { - for(;i < BUFFERSIZE;i++) - expiries[i] -= n; - i = 0; + std::transform(exp_begin, std::end(Hold->Expiries), exp_begin, + std::bind(std::minus{}, _1, n)); + exp_begin = std::begin(Hold->Expiries); } - for(;i < lowerIndex;i++) - expiries[i] -= n; - - expiries[i] -= n; + std::transform(exp_begin, exp_last+1, exp_begin, std::bind(std::minus{}, _1, n)); } /* Multichannel compression is linked via the absolute maximum of all * channels. */ -static void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]) +void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, const ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]) { - const ALsizei index = Comp->LookAhead; - const ALsizei numChans = Comp->NumChans; - ALfloat *RESTRICT sideChain = Comp->SideChain; - ALsizei c, i; + const ALsizei index{Comp->LookAhead}; + const ALsizei numChans{Comp->NumChans}; ASSUME(SamplesToDo > 0); ASSUME(numChans > 0); + ASSUME(index >= 0); - for(i = 0;i < SamplesToDo;i++) - sideChain[index + i] = 0.0f; + auto side_begin = std::begin(Comp->SideChain) + index; + std::fill(side_begin, side_begin+SamplesToDo, 0.0f); - for(c = 0;c < numChans;c++) + auto fill_max = [SamplesToDo,side_begin](const ALfloat *input) -> void { - ALsizei offset = index; - for(i = 0;i < SamplesToDo;i++) - { - sideChain[offset] = maxf(sideChain[offset], fabsf(OutBuffer[c][i])); - ++offset; - } - } + const ALfloat *RESTRICT buffer{al::assume_aligned<16>(input)}; + auto max_abs = std::bind(maxf, _1, std::bind(static_cast(std::fabs), _2)); + std::transform(side_begin, side_begin+SamplesToDo, buffer, side_begin, max_abs); + }; + std::for_each(OutBuffer, OutBuffer+numChans, fill_max); } /* This calculates the squared crest factor of the control signal for the @@ -133,25 +120,24 @@ static void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (* */ static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo) { - const ALfloat a_crest = Comp->CrestCoeff; - const ALsizei index = Comp->LookAhead; - const ALfloat *RESTRICT sideChain = Comp->SideChain; - ALfloat *RESTRICT crestFactor = Comp->CrestFactor; - ALfloat y2_peak = Comp->LastPeakSq; - ALfloat y2_rms = Comp->LastRmsSq; - ALsizei i; + const ALfloat a_crest{Comp->CrestCoeff}; + const ALsizei index{Comp->LookAhead}; + ALfloat y2_peak{Comp->LastPeakSq}; + ALfloat y2_rms{Comp->LastRmsSq}; ASSUME(SamplesToDo > 0); + ASSUME(index >= 0); - for(i = 0;i < SamplesToDo;i++) + auto calc_crest = [&y2_rms,&y2_peak,a_crest](const ALfloat x_abs) noexcept -> ALfloat { - ALfloat x_abs = sideChain[index + i]; ALfloat x2 = maxf(0.000001f, x_abs * x_abs); y2_peak = maxf(x2, lerp(x2, y2_peak, a_crest)); y2_rms = lerp(x2, y2_rms, a_crest); - crestFactor[i] = y2_peak / y2_rms; - } + return y2_peak / y2_rms; + }; + auto side_begin = std::begin(Comp->SideChain) + index; + std::transform(side_begin, side_begin+SamplesToDo, std::begin(Comp->CrestFactor), calc_crest); Comp->LastPeakSq = y2_peak; Comp->LastRmsSq = y2_rms; @@ -161,44 +147,39 @@ static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo) * value of the incoming signal) and performs most of its operations in the * log domain. */ -static void PeakDetector(Compressor *Comp, const ALsizei SamplesToDo) +void PeakDetector(Compressor *Comp, const ALsizei SamplesToDo) { - const ALsizei index = Comp->LookAhead; - ALfloat *RESTRICT sideChain = Comp->SideChain; - ALsizei i; + const ALsizei index{Comp->LookAhead}; ASSUME(SamplesToDo > 0); + ASSUME(index >= 0); - for(i = 0;i < SamplesToDo;i++) - { - const ALuint offset = index + i; - const ALfloat x_abs = sideChain[offset]; - - sideChain[offset] = logf(maxf(0.000001f, x_abs)); - } + /* Clamp the minimum amplitude to near-zero and convert to logarithm. */ + auto side_begin = std::begin(Comp->SideChain) + index; + std::transform(side_begin, side_begin+SamplesToDo, side_begin, + std::bind(static_cast(std::log), std::bind(maxf, 0.000001f, _1))); } /* An optional hold can be used to extend the peak detector so it can more * solidly detect fast transients. This is best used when operating as a * limiter. */ -static void PeakHoldDetector(Compressor *Comp, const ALsizei SamplesToDo) +void PeakHoldDetector(Compressor *Comp, const ALsizei SamplesToDo) { - const ALsizei index = Comp->LookAhead; - ALfloat *RESTRICT sideChain = Comp->SideChain; - SlidingHold *hold = Comp->Hold; - ALsizei i; + const ALsizei index{Comp->LookAhead}; ASSUME(SamplesToDo > 0); + ASSUME(index >= 0); - for(i = 0;i < SamplesToDo;i++) + SlidingHold *hold{Comp->Hold}; + ALsizei i{0}; + auto detect_peak = [&i,hold](const ALfloat x_abs) -> ALfloat { - const ALsizei offset = index + i; - const ALfloat x_abs = sideChain[offset]; - const ALfloat x_G = logf(maxf(0.000001f, x_abs)); - - sideChain[offset] = UpdateSlidingHold(hold, i, x_G); - } + const ALfloat x_G{std::log(maxf(0.000001f, x_abs))}; + return UpdateSlidingHold(hold, i++, x_G); + }; + auto side_begin = std::begin(Comp->SideChain) + index; + std::transform(side_begin, side_begin+SamplesToDo, side_begin, detect_peak); ShiftSlidingHold(hold, SamplesToDo); } @@ -208,76 +189,68 @@ static void PeakHoldDetector(Compressor *Comp, const ALsizei SamplesToDo) * to knee width, attack/release times, make-up/post gain, and clipping * reduction. */ -static void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) +void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) { - const bool autoKnee = Comp->Auto.Knee; - const bool autoAttack = Comp->Auto.Attack; - const bool autoRelease = Comp->Auto.Release; - const bool autoPostGain = Comp->Auto.PostGain; - const bool autoDeclip = Comp->Auto.Declip; - const ALsizei lookAhead = Comp->LookAhead; - const ALfloat threshold = Comp->Threshold; - const ALfloat slope = Comp->Slope; - const ALfloat attack = Comp->Attack; - const ALfloat release = Comp->Release; - const ALfloat c_est = Comp->GainEstimate; - const ALfloat a_adp = Comp->AdaptCoeff; - const ALfloat *RESTRICT crestFactor = Comp->CrestFactor; - ALfloat *RESTRICT sideChain = Comp->SideChain; - ALfloat postGain = Comp->PostGain; - ALfloat knee = Comp->Knee; - ALfloat t_att = attack; - ALfloat t_rel = release - attack; - ALfloat a_att = expf(-1.0f / t_att); - ALfloat a_rel = expf(-1.0f / t_rel); - ALfloat y_1 = Comp->LastRelease; - ALfloat y_L = Comp->LastAttack; - ALfloat c_dev = Comp->LastGainDev; - ALsizei i; + const bool autoKnee{Comp->Auto.Knee}; + const bool autoAttack{Comp->Auto.Attack}; + const bool autoRelease{Comp->Auto.Release}; + const bool autoPostGain{Comp->Auto.PostGain}; + const bool autoDeclip{Comp->Auto.Declip}; + const ALsizei lookAhead{Comp->LookAhead}; + const ALfloat threshold{Comp->Threshold}; + const ALfloat slope{Comp->Slope}; + const ALfloat attack{Comp->Attack}; + const ALfloat release{Comp->Release}; + const ALfloat c_est{Comp->GainEstimate}; + const ALfloat a_adp{Comp->AdaptCoeff}; + const ALfloat (&crestFactor)[BUFFERSIZE] = Comp->CrestFactor; + ALfloat (&sideChain)[BUFFERSIZE*2] = Comp->SideChain; + ALfloat postGain{Comp->PostGain}; + ALfloat knee{Comp->Knee}; + ALfloat t_att{attack}; + ALfloat t_rel{release - attack}; + ALfloat a_att{std::exp(-1.0f / t_att)}; + ALfloat a_rel{std::exp(-1.0f / t_rel)}; + ALfloat y_1{Comp->LastRelease}; + ALfloat y_L{Comp->LastAttack}; + ALfloat c_dev{Comp->LastGainDev}; ASSUME(SamplesToDo > 0); + ASSUME(lookAhead >= 0); - for(i = 0;i < SamplesToDo;i++) + for(ALsizei i{0};i < SamplesToDo;i++) { - const ALfloat y2_crest = crestFactor[i]; - const ALfloat x_G = sideChain[lookAhead + i]; - const ALfloat x_over = x_G - threshold; - ALfloat knee_h; - ALfloat y_G; - ALfloat x_L; - if(autoKnee) knee = maxf(0.0f, 2.5f * (c_dev + c_est)); - knee_h = 0.5f * knee; + const ALfloat knee_h{0.5f * knee}; /* This is the gain computer. It applies a static compression curve * to the control signal. */ - if(x_over <= -knee_h) - y_G = 0.0f; - else if(fabsf(x_over) < knee_h) - y_G = (x_over + knee_h) * (x_over + knee_h) / (2.0f * knee); - else - y_G = x_over; - - x_L = -slope * y_G; - + const ALfloat x_over{sideChain[lookAhead+i] - threshold}; + const ALfloat y_G{ + (x_over <= -knee_h) ? 0.0f : + (std::fabs(x_over) < knee_h) ? (x_over + knee_h) * (x_over + knee_h) / (2.0f * knee) : + x_over + }; + + const ALfloat y2_crest{crestFactor[i]}; if(autoAttack) { - t_att = 2.0f * attack / y2_crest; - a_att = expf(-1.0f / t_att); + t_att = 2.0f*attack/y2_crest; + a_att = std::exp(-1.0f / t_att); } - if(autoRelease) { - t_rel = 2.0f * release / y2_crest - t_att; - a_rel = expf(-1.0f / t_rel); + t_rel = 2.0f*release/y2_crest - t_att; + a_rel = std::exp(-1.0f / t_rel); } /* Gain smoothing (ballistics) is done via a smooth decoupled peak * detector. The attack time is subtracted from the release time * above to compensate for the chained operating mode. */ + const ALfloat x_L{-slope * y_G}; y_1 = maxf(x_L, lerp(x_L, y_1, a_rel)); y_L = lerp(y_1, y_L, a_att); @@ -286,15 +259,15 @@ static void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) * The estimate is also used to bias the measurement to hot-start its * average. */ - c_dev = lerp(-y_L - c_est, c_dev, a_adp); + c_dev = lerp(-(y_L+c_est), c_dev, a_adp); if(autoPostGain) { /* Clipping reduction is only viable when make-up gain is being - * automated. It modifies the deviation to further attenuate the - * control signal when clipping is detected. The adaptation - * time is sufficiently long enough to suppress further clipping - * at the same output level. + * automated. It modifies the deviation to further attenuate the + * control signal when clipping is detected. The adaptation time + * is sufficiently long enough to suppress further clipping at the + * same output level. */ if(autoDeclip) c_dev = maxf(c_dev, sideChain[i] - y_L - threshold - c_est); @@ -302,7 +275,7 @@ static void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) postGain = -(c_dev + c_est); } - sideChain[i] = expf(postGain - y_L); + sideChain[i] = std::exp(postGain - y_L); } Comp->LastRelease = y_1; @@ -315,32 +288,34 @@ static void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) * reaching the offending impulse. This is best used when operating as a * limiter. */ -static void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]) +void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]) { - const ALsizei mask = BUFFERSIZE - 1; - const ALsizei numChans = Comp->NumChans; - const ALsizei indexIn = Comp->DelayIndex; - const ALsizei indexOut = Comp->DelayIndex - Comp->LookAhead; - ALfloat (*RESTRICT delay)[BUFFERSIZE] = Comp->Delay; - ALsizei c, i; + static constexpr ALsizei mask{BUFFERSIZE - 1}; + const ALsizei numChans{Comp->NumChans}; + const ALsizei indexIn{Comp->DelayIndex}; + const ALsizei indexOut{Comp->DelayIndex - Comp->LookAhead}; ASSUME(SamplesToDo > 0); ASSUME(numChans > 0); - for(c = 0;c < numChans;c++) + for(ALsizei c{0};c < numChans;c++) { - for(i = 0;i < SamplesToDo;i++) + ALfloat *RESTRICT inout{al::assume_aligned<16>(OutBuffer[c])}; + ALfloat *RESTRICT delay{al::assume_aligned<16>(Comp->Delay[c])}; + for(ALsizei i{0};i < SamplesToDo;i++) { - ALfloat sig = OutBuffer[c][i]; + const ALfloat sig{inout[i]}; - OutBuffer[c][i] = delay[c][(indexOut + i) & mask]; - delay[c][(indexIn + i) & mask] = sig; + inout[i] = delay[(indexOut + i) & mask]; + delay[(indexIn + i) & mask] = sig; } } Comp->DelayIndex = (indexIn + SamplesToDo) & mask; } +} // namespace + /* The compressor is initialized with the following settings: * * NumChans - Number of channels to process. @@ -374,25 +349,20 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, const ALfloat Ratio, const ALfloat KneeDb, const ALfloat AttackTime, const ALfloat ReleaseTime) { - Compressor *Comp; - ALsizei lookAhead; - ALsizei hold; - size_t size; - - lookAhead = (ALsizei)clampf(roundf(LookAheadTime*SampleRate), 0.0f, BUFFERSIZE-1); - hold = (ALsizei)clampf(roundf(HoldTime*SampleRate), 0.0f, BUFFERSIZE-1); - /* The sliding hold implementation doesn't handle a length of 1. A 1-sample - * hold is useless anyway, it would only ever give back what was just given - * to it. - */ - if(hold == 1) - hold = 0; + auto lookAhead = static_cast( + clampf(std::round(LookAheadTime*SampleRate), 0.0f, BUFFERSIZE-1)); + auto hold = static_cast(clampf(std::round(HoldTime*SampleRate), 0.0f, BUFFERSIZE-1)); - size = sizeof(*Comp); + Compressor *Comp; + size_t size{sizeof(*Comp)}; if(lookAhead > 0) { size += sizeof(*Comp->Delay) * NumChans; - if(hold > 0) + /* The sliding hold implementation doesn't handle a length of 1. A 1- + * sample hold is useless anyway, it would only ever give back what was + * just given to it. + */ + if(hold > 1) size += sizeof(*Comp->Hold); } @@ -405,11 +375,11 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, Comp->Auto.PostGain = AutoPostGain; Comp->Auto.Declip = AutoPostGain && AutoDeclip; Comp->LookAhead = lookAhead; - Comp->PreGain = powf(10.0f, PreGainDb / 20.0f); - Comp->PostGain = PostGainDb * logf(10.0f) / 20.0f; - Comp->Threshold = ThresholdDb * logf(10.0f) / 20.0f; + Comp->PreGain = std::pow(10.0f, PreGainDb / 20.0f); + Comp->PostGain = PostGainDb * std::log(10.0f) / 20.0f; + Comp->Threshold = ThresholdDb * std::log(10.0f) / 20.0f; Comp->Slope = 1.0f / maxf(1.0f, Ratio) - 1.0f; - Comp->Knee = maxf(0.0f, KneeDb * logf(10.0f) / 20.0f); + Comp->Knee = maxf(0.0f, KneeDb * std::log(10.0f) / 20.0f); Comp->Attack = maxf(1.0f, AttackTime * SampleRate); Comp->Release = maxf(1.0f, ReleaseTime * SampleRate); @@ -422,7 +392,7 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, if(lookAhead > 0) { - if(hold > 0) + if(hold > 1) { Comp->Hold = new ((void*)(Comp + 1)) SlidingHold{}; Comp->Hold->Values[0] = -HUGE_VALF; @@ -436,14 +406,14 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, } } - Comp->CrestCoeff = expf(-1.0f / (0.200f * SampleRate)); // 200ms + Comp->CrestCoeff = std::exp(-1.0f / (0.200f * SampleRate)); // 200ms Comp->GainEstimate = Comp->Threshold * -0.5f * Comp->Slope; - Comp->AdaptCoeff = expf(-1.0f / (2.0f * SampleRate)); // 2s + Comp->AdaptCoeff = std::exp(-1.0f / (2.0f * SampleRate)); // 2s return Comp; } -void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]) +void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*OutBuffer)[BUFFERSIZE]) { const ALsizei numChans{Comp->NumChans}; @@ -453,15 +423,13 @@ void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RES const ALfloat preGain{Comp->PreGain}; if(preGain != 1.0f) { - std::for_each(OutBuffer, OutBuffer+numChans, - [SamplesToDo, preGain](ALfloat *buffer) noexcept -> void - { - std::for_each(buffer, buffer+SamplesToDo, - [preGain](ALfloat &samp) noexcept -> void - { samp *= preGain; } - ); - } - ); + auto apply_gain = [SamplesToDo,preGain](ALfloat *input) noexcept -> void + { + ALfloat *buffer{al::assume_aligned<16>(input)}; + std::transform(buffer, buffer+SamplesToDo, buffer, + std::bind(std::multiplies{}, _1, preGain)); + }; + std::for_each(OutBuffer, OutBuffer+numChans, apply_gain); } LinkChannels(Comp, SamplesToDo, OutBuffer); @@ -479,22 +447,23 @@ void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RES if(Comp->Delay) SignalDelay(Comp, SamplesToDo, OutBuffer); - ALfloat *RESTRICT sideChain{Comp->SideChain}; - std::for_each(OutBuffer, OutBuffer+numChans, - [SamplesToDo, sideChain](ALfloat *buffer) noexcept -> void - { - /* Mark the sideChain "input-1 type" as restrict, so the compiler - * can vectorize this loop (otherwise it assumes a write to - * buffer[n] can change sideChain[n+1]). - */ - std::transform(sideChain, sideChain+SamplesToDo, buffer, buffer, - [](const ALfloat gain, const ALfloat samp) noexcept -> ALfloat - { return samp * gain; } - ); - } - ); - - std::copy(sideChain+SamplesToDo, sideChain+SamplesToDo+Comp->LookAhead, sideChain); + const ALfloat (&sideChain)[BUFFERSIZE*2] = Comp->SideChain; + auto apply_comp = [SamplesToDo,&sideChain](ALfloat *input) noexcept -> void + { + ALfloat *buffer{al::assume_aligned<16>(input)}; + const ALfloat *gains{al::assume_aligned<16>(sideChain)}; + /* Mark the gains "input-1 type" as restrict, so the compiler can + * vectorize this loop (otherwise it assumes a write to buffer[n] can + * change gains[n+1]). + */ + std::transform(gains, gains+SamplesToDo, buffer, buffer, + std::bind(std::multiplies{}, _1, _2)); + }; + std::for_each(OutBuffer, OutBuffer+numChans, apply_comp); + + ASSUME(Comp->LookAhead >= 0); + auto side_begin = std::begin(Comp->SideChain) + SamplesToDo; + std::copy(side_begin, side_begin+Comp->LookAhead, std::begin(Comp->SideChain)); } diff --git a/Alc/mastering.h b/Alc/mastering.h index 14111130..55b7c258 100644 --- a/Alc/mastering.h +++ b/Alc/mastering.h @@ -25,11 +25,11 @@ struct Compressor { ALuint SampleRate; struct { - ALuint Knee : 1; - ALuint Attack : 1; - ALuint Release : 1; - ALuint PostGain : 1; - ALuint Declip : 1; + bool Knee : 1; + bool Attack : 1; + bool Release : 1; + bool PostGain : 1; + bool Declip : 1; } Auto; ALsizei LookAhead; @@ -97,9 +97,9 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, const ALfloat Ratio, const ALfloat KneeDb, const ALfloat AttackTime, const ALfloat ReleaseTime); -void ApplyCompression(struct Compressor *Comp, const ALsizei SamplesToDo, - ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]); +void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, + ALfloat (*OutBuffer)[BUFFERSIZE]); -ALsizei GetCompressorLookAhead(const struct Compressor *Comp); +ALsizei GetCompressorLookAhead(const Compressor *Comp); #endif /* MASTERING_H */ -- cgit v1.2.3 From 837881eb7986a56f1e83c1cb23faef0b020bfbd1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 20 Dec 2018 12:03:32 -0800 Subject: Fix the type used for subtraction --- Alc/mastering.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/mastering.cpp b/Alc/mastering.cpp index 007c2657..37752f4f 100644 --- a/Alc/mastering.cpp +++ b/Alc/mastering.cpp @@ -83,7 +83,7 @@ static void ShiftSlidingHold(SlidingHold *Hold, const ALsizei n) if(exp_last < exp_begin) { std::transform(exp_begin, std::end(Hold->Expiries), exp_begin, - std::bind(std::minus{}, _1, n)); + std::bind(std::minus{}, _1, n)); exp_begin = std::begin(Hold->Expiries); } std::transform(exp_begin, exp_last+1, exp_begin, std::bind(std::minus{}, _1, n)); -- cgit v1.2.3 From 768ed3cfbb9b07b6f3a008e7e5e7d67559806abc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 20 Dec 2018 12:04:34 -0800 Subject: Silence some MSVC warnings --- Alc/mastering.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/mastering.cpp b/Alc/mastering.cpp index 37752f4f..fa2c9dac 100644 --- a/Alc/mastering.cpp +++ b/Alc/mastering.cpp @@ -369,10 +369,10 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, Comp = new (al_calloc(16, size)) Compressor{}; Comp->NumChans = NumChans; Comp->SampleRate = SampleRate; - Comp->Auto.Knee = AutoKnee; - Comp->Auto.Attack = AutoAttack; - Comp->Auto.Release = AutoRelease; - Comp->Auto.PostGain = AutoPostGain; + Comp->Auto.Knee = AutoKnee != AL_FALSE; + Comp->Auto.Attack = AutoAttack != AL_FALSE; + Comp->Auto.Release = AutoRelease != AL_FALSE; + Comp->Auto.PostGain = AutoPostGain != AL_FALSE; Comp->Auto.Declip = AutoPostGain && AutoDeclip; Comp->LookAhead = lookAhead; Comp->PreGain = std::pow(10.0f, PreGainDb / 20.0f); -- cgit v1.2.3 From 9fde260df9237cd99967a816332be31ce1524770 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 20 Dec 2018 12:29:46 -0800 Subject: Fix the type used for another subtraction --- Alc/mastering.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/mastering.cpp b/Alc/mastering.cpp index fa2c9dac..91ea207b 100644 --- a/Alc/mastering.cpp +++ b/Alc/mastering.cpp @@ -86,7 +86,7 @@ static void ShiftSlidingHold(SlidingHold *Hold, const ALsizei n) std::bind(std::minus{}, _1, n)); exp_begin = std::begin(Hold->Expiries); } - std::transform(exp_begin, exp_last+1, exp_begin, std::bind(std::minus{}, _1, n)); + std::transform(exp_begin, exp_last+1, exp_begin, std::bind(std::minus{}, _1, n)); } /* Multichannel compression is linked via the absolute maximum of all -- cgit v1.2.3 From 7744e4ff72def926a26feca391170d25df39c469 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 20 Dec 2018 13:26:39 -0800 Subject: Pass RealMixParams by reference instead of pointer --- Alc/alu.cpp | 24 ++++++++++++------------ Alc/effects/dedicated.cpp | 4 ++-- Alc/mixvoice.cpp | 4 ++-- Alc/panning.cpp | 2 +- OpenAL32/Include/alMain.h | 4 ++-- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 75504af5..92502eee 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -128,8 +128,8 @@ void ProcessHrtf(ALCdevice *device, ALsizei SamplesToDo) device->FOAOut.Buffer, SamplesToDo ); - int lidx{GetChannelIdxByName(&device->RealOut, FrontLeft)}; - int ridx{GetChannelIdxByName(&device->RealOut, FrontRight)}; + int lidx{GetChannelIdxByName(device->RealOut, FrontLeft)}; + int ridx{GetChannelIdxByName(device->RealOut, FrontRight)}; assert(lidx != -1 && ridx != -1); DirectHrtfState *state{device->mHrtfState.get()}; @@ -163,8 +163,8 @@ void ProcessAmbiUp(ALCdevice *device, ALsizei SamplesToDo) void ProcessUhj(ALCdevice *device, ALsizei SamplesToDo) { - int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); - int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); + int lidx = GetChannelIdxByName(device->RealOut, FrontLeft); + int ridx = GetChannelIdxByName(device->RealOut, FrontRight); assert(lidx != -1 && ridx != -1); /* Encode to stereo-compatible 2-channel UHJ output. */ @@ -176,8 +176,8 @@ void ProcessUhj(ALCdevice *device, ALsizei SamplesToDo) void ProcessBs2b(ALCdevice *device, ALsizei SamplesToDo) { - int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); - int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); + int lidx = GetChannelIdxByName(device->RealOut, FrontLeft); + int ridx = GetChannelIdxByName(device->RealOut, FrontRight); assert(lidx != -1 && ridx != -1); /* Apply binaural/crossfeed filter */ @@ -696,7 +696,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev for(ALsizei c{0};c < num_channels;c++) { - int idx{GetChannelIdxByName(&Device->RealOut, chans[c].channel)}; + int idx{GetChannelIdxByName(Device->RealOut, chans[c].channel)}; if(idx != -1) voice->Direct.Params[c].Gains.Target[idx] = DryGain; } @@ -843,7 +843,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev { if(Device->Dry.Buffer == Device->RealOut.Buffer) { - int idx = GetChannelIdxByName(&Device->RealOut, chans[c].channel); + int idx = GetChannelIdxByName(Device->RealOut, chans[c].channel); if(idx != -1) voice->Direct.Params[c].Gains.Target[idx] = DryGain; } continue; @@ -894,7 +894,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev { if(Device->Dry.Buffer == Device->RealOut.Buffer) { - int idx = GetChannelIdxByName(&Device->RealOut, chans[c].channel); + int idx = GetChannelIdxByName(Device->RealOut, chans[c].channel); if(idx != -1) voice->Direct.Params[c].Gains.Target[idx] = DryGain; } continue; @@ -1683,9 +1683,9 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) /* Apply front image stablization for surround sound, if applicable. */ if(device->Stablizer) { - const int lidx{GetChannelIdxByName(&device->RealOut, FrontLeft)}; - const int ridx{GetChannelIdxByName(&device->RealOut, FrontRight)}; - const int cidx{GetChannelIdxByName(&device->RealOut, FrontCenter)}; + const int lidx{GetChannelIdxByName(device->RealOut, FrontLeft)}; + const int ridx{GetChannelIdxByName(device->RealOut, FrontRight)}; + const int cidx{GetChannelIdxByName(device->RealOut, FrontCenter)}; assert(lidx >= 0 && ridx >= 0 && cidx >= 0); ApplyStablizer(device->Stablizer.get(), device->RealOut.Buffer, lidx, ridx, cidx, diff --git a/Alc/effects/dedicated.cpp b/Alc/effects/dedicated.cpp index 491b57ec..c0af33e1 100644 --- a/Alc/effects/dedicated.cpp +++ b/Alc/effects/dedicated.cpp @@ -60,7 +60,7 @@ void ALdedicatedState::update(const ALCcontext *context, const ALeffectslot *slo if(slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) { int idx; - if((idx=GetChannelIdxByName(&device->RealOut, LFE)) != -1) + if((idx=GetChannelIdxByName(device->RealOut, LFE)) != -1) { mOutBuffer = device->RealOut.Buffer; mOutChannels = device->RealOut.NumChannels; @@ -71,7 +71,7 @@ void ALdedicatedState::update(const ALCcontext *context, const ALeffectslot *slo { /* Dialog goes to the front-center speaker if it exists, otherwise it * plays from the front-center location. */ - int idx{GetChannelIdxByName(&device->RealOut, FrontCenter)}; + int idx{GetChannelIdxByName(device->RealOut, FrontCenter)}; if(idx != -1) { mOutBuffer = device->RealOut.Buffer; diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 682e552f..f43ae127 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -550,8 +550,8 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize } else { - const int lidx{GetChannelIdxByName(&Device->RealOut, FrontLeft)}; - const int ridx{GetChannelIdxByName(&Device->RealOut, FrontRight)}; + const int lidx{GetChannelIdxByName(Device->RealOut, FrontLeft)}; + const int ridx{GetChannelIdxByName(Device->RealOut, FrontRight)}; assert(lidx != -1 && ridx != -1); ALsizei fademix{0}; diff --git a/Alc/panning.cpp b/Alc/panning.cpp index d03977b8..783fe480 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -198,7 +198,7 @@ bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei (&speaker return -1; } } - const int chidx{GetChannelIdxByName(&device->RealOut, ch)}; + const int chidx{GetChannelIdxByName(device->RealOut, ch)}; if(chidx == -1) ERR("Failed to lookup AmbDec speaker label %s\n", speaker.Name.c_str()); return chidx; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index a2666435..daafaad1 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -906,8 +906,8 @@ inline ALint GetChannelIndex(const Channel (&names)[MAX_OUTPUT_CHANNELS], Channe * Returns the index for the given channel name (e.g. FrontCenter), or -1 if it * doesn't exist. */ -inline ALint GetChannelIdxByName(const RealMixParams *real, enum Channel chan) -{ return GetChannelIndex(real->ChannelName, chan); } +inline ALint GetChannelIdxByName(const RealMixParams &real, Channel chan) +{ return GetChannelIndex(real.ChannelName, chan); } void StartEventThrd(ALCcontext *ctx); -- cgit v1.2.3 From b785d805263c9517c1523785b2da39f9a47b6002 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 21 Dec 2018 06:32:18 -0800 Subject: Use a dodecahedron for the ambisonic HRTF decode Also uses full second-order for "basic" HRTF rendering. Note that the supplied matrix is full third-order, but only the first- and second-order coefficients are used. The base matrices are the identical, only differing by the high- frequency scalars. --- Alc/panning.cpp | 119 ++++++++++++++++++++++++-------------------------------- 1 file changed, 51 insertions(+), 68 deletions(-) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 783fe480..9c3be106 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -618,78 +618,62 @@ void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&sp void InitHrtfPanning(ALCdevice *device) { /* NOTE: azimuth goes clockwise. */ - static constexpr AngularPoint AmbiPoints[] = { - { DEG2RAD( 90.0f), DEG2RAD( 0.0f) }, - { DEG2RAD( 35.2643897f), DEG2RAD( 45.0f) }, - { DEG2RAD( 35.2643897f), DEG2RAD( 135.0f) }, - { DEG2RAD( 35.2643897f), DEG2RAD(-135.0f) }, - { DEG2RAD( 35.2643897f), DEG2RAD( -45.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( 0.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( 45.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( 90.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( 135.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( 180.0f) }, - { DEG2RAD( 0.0f), DEG2RAD(-135.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( -90.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( -45.0f) }, - { DEG2RAD(-35.2643897f), DEG2RAD( 45.0f) }, - { DEG2RAD(-35.2643897f), DEG2RAD( 135.0f) }, - { DEG2RAD(-35.2643897f), DEG2RAD(-135.0f) }, - { DEG2RAD(-35.2643897f), DEG2RAD( -45.0f) }, - { DEG2RAD(-90.0f), DEG2RAD( 0.0f) }, + static constexpr AngularPoint AmbiPoints[]{ + { DEG2RAD( 35.264390f), DEG2RAD( -45.000000f) }, + { DEG2RAD( 35.264390f), DEG2RAD( 45.000000f) }, + { DEG2RAD( 35.264390f), DEG2RAD( 135.000000f) }, + { DEG2RAD( 35.264390f), DEG2RAD(-135.000000f) }, + { DEG2RAD(-35.264390f), DEG2RAD( -45.000000f) }, + { DEG2RAD(-35.264390f), DEG2RAD( 45.000000f) }, + { DEG2RAD(-35.264390f), DEG2RAD( 135.000000f) }, + { DEG2RAD(-35.264390f), DEG2RAD(-135.000000f) }, + { DEG2RAD( 0.000000f), DEG2RAD( -20.905157f) }, + { DEG2RAD( 0.000000f), DEG2RAD( 20.905157f) }, + { DEG2RAD( 0.000000f), DEG2RAD( 159.094843f) }, + { DEG2RAD( 0.000000f), DEG2RAD(-159.094843f) }, + { DEG2RAD( 20.905157f), DEG2RAD( -90.000000f) }, + { DEG2RAD(-20.905157f), DEG2RAD( -90.000000f) }, + { DEG2RAD(-20.905157f), DEG2RAD( 90.000000f) }, + { DEG2RAD( 20.905157f), DEG2RAD( 90.000000f) }, + { DEG2RAD( 69.094843f), DEG2RAD( 0.000000f) }, + { DEG2RAD(-69.094843f), DEG2RAD( 0.000000f) }, + { DEG2RAD(-69.094843f), DEG2RAD( 180.000000f) }, + { DEG2RAD( 69.094843f), DEG2RAD( 180.000000f) }, }; - static constexpr ALfloat AmbiMatrixFOA[][MAX_AMBI_COEFFS] = { - { 5.55555556e-02f, 0.00000000e+00f, 1.23717915e-01f, 0.00000000e+00f }, - { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f }, - { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f }, - { 5.55555556e-02f, 5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f }, - { 5.55555556e-02f, 5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f }, - { 5.55555556e-02f, 0.00000000e+00f, 0.00000000e+00f, 8.66025404e-02f }, - { 5.55555556e-02f, -6.12372435e-02f, 0.00000000e+00f, 6.12372435e-02f }, - { 5.55555556e-02f, -8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f }, - { 5.55555556e-02f, -6.12372435e-02f, 0.00000000e+00f, -6.12372435e-02f }, - { 5.55555556e-02f, 0.00000000e+00f, 0.00000000e+00f, -8.66025404e-02f }, - { 5.55555556e-02f, 6.12372435e-02f, 0.00000000e+00f, -6.12372435e-02f }, - { 5.55555556e-02f, 8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f }, - { 5.55555556e-02f, 6.12372435e-02f, 0.00000000e+00f, 6.12372435e-02f }, - { 5.55555556e-02f, -5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f }, - { 5.55555556e-02f, -5.00000000e-02f, -7.14285715e-02f, -5.00000000e-02f }, - { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, -5.00000000e-02f }, - { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f }, - { 5.55555556e-02f, 0.00000000e+00f, -1.23717915e-01f, 0.00000000e+00f }, - }, AmbiMatrixHOA[][MAX_AMBI_COEFFS] = { - { 5.55555556e-02f, 0.00000000e+00f, 1.23717915e-01f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, - { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, 5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, 5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, 0.00000000e+00f, 0.00000000e+00f, 8.66025404e-02f, 0.00000000e+00f, 1.29099445e-01f }, - { 5.55555556e-02f, -6.12372435e-02f, 0.00000000e+00f, 6.12372435e-02f, -6.83467648e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, -8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -1.29099445e-01f }, - { 5.55555556e-02f, -6.12372435e-02f, 0.00000000e+00f, -6.12372435e-02f, 6.83467648e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, 0.00000000e+00f, 0.00000000e+00f, -8.66025404e-02f, 0.00000000e+00f, 1.29099445e-01f }, - { 5.55555556e-02f, 6.12372435e-02f, 0.00000000e+00f, -6.12372435e-02f, -6.83467648e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, 8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -1.29099445e-01f }, - { 5.55555556e-02f, 6.12372435e-02f, 0.00000000e+00f, 6.12372435e-02f, 6.83467648e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, -5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, -5.00000000e-02f, -7.14285715e-02f, -5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, -5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f }, - { 5.55555556e-02f, 0.00000000e+00f, -1.23717915e-01f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + static constexpr ALfloat AmbiMatrix[][MAX_AMBI_COEFFS]{ + { 5.00000000e-02f, 5.00000000e-02f, 5.00000000e-02f, 5.00000000e-02f, 6.45497224e-02f, 6.45497224e-02f, 0.00000000e+00f, 6.45497224e-02f, 0.00000000e+00f, 1.48264644e-02f, 6.33865691e-02f, 1.01126676e-01f, -7.36485380e-02f, -1.09260065e-02f, 7.08683387e-02f, -1.01622099e-01f }, + { 5.00000000e-02f, -5.00000000e-02f, 5.00000000e-02f, 5.00000000e-02f, -6.45497224e-02f, -6.45497224e-02f, 0.00000000e+00f, 6.45497224e-02f, 0.00000000e+00f, -1.48264644e-02f, -6.33865691e-02f, -1.01126676e-01f, -7.36485380e-02f, -1.09260065e-02f, 7.08683387e-02f, -1.01622099e-01f }, + { 5.00000000e-02f, -5.00000000e-02f, 5.00000000e-02f, -5.00000000e-02f, 6.45497224e-02f, -6.45497224e-02f, 0.00000000e+00f, -6.45497224e-02f, 0.00000000e+00f, -1.48264644e-02f, 6.33865691e-02f, -1.01126676e-01f, -7.36485380e-02f, 1.09260065e-02f, 7.08683387e-02f, 1.01622099e-01f }, + { 5.00000000e-02f, 5.00000000e-02f, 5.00000000e-02f, -5.00000000e-02f, -6.45497224e-02f, 6.45497224e-02f, 0.00000000e+00f, -6.45497224e-02f, 0.00000000e+00f, 1.48264644e-02f, -6.33865691e-02f, 1.01126676e-01f, -7.36485380e-02f, 1.09260065e-02f, 7.08683387e-02f, 1.01622099e-01f }, + { 5.00000000e-02f, 5.00000000e-02f, -5.00000000e-02f, 5.00000000e-02f, 6.45497224e-02f, -6.45497224e-02f, 0.00000000e+00f, -6.45497224e-02f, 0.00000000e+00f, 1.48264644e-02f, -6.33865691e-02f, 1.01126676e-01f, 7.36485380e-02f, -1.09260065e-02f, -7.08683387e-02f, -1.01622099e-01f }, + { 5.00000000e-02f, -5.00000000e-02f, -5.00000000e-02f, 5.00000000e-02f, -6.45497224e-02f, 6.45497224e-02f, 0.00000000e+00f, -6.45497224e-02f, 0.00000000e+00f, -1.48264644e-02f, 6.33865691e-02f, -1.01126676e-01f, 7.36485380e-02f, -1.09260065e-02f, -7.08683387e-02f, -1.01622099e-01f }, + { 5.00000000e-02f, -5.00000000e-02f, -5.00000000e-02f, -5.00000000e-02f, 6.45497224e-02f, 6.45497224e-02f, 0.00000000e+00f, 6.45497224e-02f, 0.00000000e+00f, -1.48264644e-02f, -6.33865691e-02f, -1.01126676e-01f, 7.36485380e-02f, 1.09260065e-02f, -7.08683387e-02f, 1.01622099e-01f }, + { 5.00000000e-02f, 5.00000000e-02f, -5.00000000e-02f, -5.00000000e-02f, -6.45497224e-02f, -6.45497224e-02f, 0.00000000e+00f, 6.45497224e-02f, 0.00000000e+00f, 1.48264644e-02f, 6.33865691e-02f, 1.01126676e-01f, 7.36485380e-02f, 1.09260065e-02f, -7.08683387e-02f, 1.01622099e-01f }, + { 5.00000000e-02f, 3.09016994e-02f, 0.00000000e+00f, 8.09016994e-02f, 6.45497224e-02f, 0.00000000e+00f, -5.59016994e-02f, 0.00000000e+00f, 7.21687836e-02f, 7.76323754e-02f, 0.00000000e+00f, -1.49775925e-01f, 0.00000000e+00f, -2.95083663e-02f, 0.00000000e+00f, 7.76323754e-02f }, + { 5.00000000e-02f, -3.09016994e-02f, 0.00000000e+00f, 8.09016994e-02f, -6.45497224e-02f, 0.00000000e+00f, -5.59016994e-02f, 0.00000000e+00f, 7.21687836e-02f, -7.76323754e-02f, 0.00000000e+00f, 1.49775925e-01f, 0.00000000e+00f, -2.95083663e-02f, 0.00000000e+00f, 7.76323754e-02f }, + { 5.00000000e-02f, -3.09016994e-02f, 0.00000000e+00f, -8.09016994e-02f, 6.45497224e-02f, 0.00000000e+00f, -5.59016994e-02f, 0.00000000e+00f, 7.21687836e-02f, -7.76323754e-02f, 0.00000000e+00f, 1.49775925e-01f, 0.00000000e+00f, 2.95083663e-02f, 0.00000000e+00f, -7.76323754e-02f }, + { 5.00000000e-02f, 3.09016994e-02f, 0.00000000e+00f, -8.09016994e-02f, -6.45497224e-02f, 0.00000000e+00f, -5.59016994e-02f, 0.00000000e+00f, 7.21687836e-02f, 7.76323754e-02f, 0.00000000e+00f, -1.49775925e-01f, 0.00000000e+00f, 2.95083663e-02f, 0.00000000e+00f, -7.76323754e-02f }, + { 5.00000000e-02f, 8.09016994e-02f, 3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 6.45497224e-02f, -3.45491503e-02f, 0.00000000e+00f, -8.44966837e-02f, -4.79794466e-02f, 0.00000000e+00f, -6.77901327e-02f, 3.03448665e-02f, 0.00000000e+00f, -1.65948192e-01f, 0.00000000e+00f }, + { 5.00000000e-02f, 8.09016994e-02f, -3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, -6.45497224e-02f, -3.45491503e-02f, 0.00000000e+00f, -8.44966837e-02f, -4.79794466e-02f, 0.00000000e+00f, -6.77901327e-02f, -3.03448665e-02f, 0.00000000e+00f, 1.65948192e-01f, 0.00000000e+00f }, + { 5.00000000e-02f, -8.09016994e-02f, -3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 6.45497224e-02f, -3.45491503e-02f, 0.00000000e+00f, -8.44966837e-02f, 4.79794466e-02f, 0.00000000e+00f, 6.77901327e-02f, -3.03448665e-02f, 0.00000000e+00f, 1.65948192e-01f, 0.00000000e+00f }, + { 5.00000000e-02f, -8.09016994e-02f, 3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, -6.45497224e-02f, -3.45491503e-02f, 0.00000000e+00f, -8.44966837e-02f, 4.79794466e-02f, 0.00000000e+00f, 6.77901327e-02f, 3.03448665e-02f, 0.00000000e+00f, -1.65948192e-01f, 0.00000000e+00f }, + { 5.00000000e-02f, 0.00000000e+00f, 8.09016994e-02f, 3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 9.04508497e-02f, 6.45497224e-02f, 1.23279000e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 7.94438918e-02f, 1.12611206e-01f, -2.42115150e-02f, 1.25611822e-01f }, + { 5.00000000e-02f, 0.00000000e+00f, -8.09016994e-02f, 3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 9.04508497e-02f, -6.45497224e-02f, 1.23279000e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -7.94438918e-02f, 1.12611206e-01f, 2.42115150e-02f, 1.25611822e-01f }, + { 5.00000000e-02f, 0.00000000e+00f, -8.09016994e-02f, -3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 9.04508497e-02f, 6.45497224e-02f, 1.23279000e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -7.94438918e-02f, -1.12611206e-01f, 2.42115150e-02f, -1.25611822e-01f }, + { 5.00000000e-02f, 0.00000000e+00f, 8.09016994e-02f, -3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 9.04508497e-02f, -6.45497224e-02f, 1.23279000e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 7.94438918e-02f, -1.12611206e-01f, -2.42115150e-02f, -1.25611822e-01f } }; - static constexpr ALfloat AmbiOrderHFGainFOA[MAX_AMBI_ORDER+1] = { - 3.00000000e+00f, 1.73205081e+00f - }, AmbiOrderHFGainHOA[MAX_AMBI_ORDER+1] = { - 2.40192231e+00f, 1.86052102e+00f, 9.60768923e-01f + static constexpr ALfloat AmbiOrderHFGainFOA[MAX_AMBI_ORDER+1]{ + 3.16227766e+00f, 1.82574186e+00f + }, AmbiOrderHFGainHOA[MAX_AMBI_ORDER+1]{ + 2.35702260e+00f, 1.82574186e+00f, 9.42809042e-01f + /* 1.86508671e+00f, 1.60609389e+00f, 1.14205530e+00f, 5.68379553e-01f */ }; - static constexpr ALsizei IndexMap[6] = { 0, 1, 2, 3, 4, 8 }; - static constexpr ALsizei ChansPerOrder[MAX_AMBI_ORDER+1] = { 1, 3, 2, 0 }; - const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_COEFFS] = AmbiMatrixFOA; - const ALfloat *RESTRICT AmbiOrderHFGain = AmbiOrderHFGainFOA; + static constexpr ALsizei IndexMap[9]{ 0, 1, 2, 3, 4, 5, 6, 7, 8 }; + static constexpr ALsizei ChansPerOrder[MAX_AMBI_ORDER+1]{ 1, 3, 5, 0 }; + const ALfloat *AmbiOrderHFGain{AmbiOrderHFGainFOA}; ALsizei count{4}; - static_assert(COUNTOF(AmbiPoints) == COUNTOF(AmbiMatrixFOA), "FOA Ambisonic HRTF mismatch"); - static_assert(COUNTOF(AmbiPoints) == COUNTOF(AmbiMatrixHOA), "HOA Ambisonic HRTF mismatch"); + static_assert(COUNTOF(AmbiPoints) == COUNTOF(AmbiMatrix), "Ambisonic HRTF mismatch"); /* Don't bother with HOA when using full HRTF rendering. Nothing needs it, * and it eases the CPU/memory load. @@ -698,7 +682,6 @@ void InitHrtfPanning(ALCdevice *device) { device->AmbiUp.reset(new AmbiUpsampler{}); - AmbiMatrix = AmbiMatrixHOA; AmbiOrderHFGain = AmbiOrderHFGainHOA; count = static_cast(COUNTOF(IndexMap)); } -- cgit v1.2.3 From 3553ce1f67d46573e338ff6e53a31d60a722d5c6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 21 Dec 2018 08:55:22 -0800 Subject: Don't convert the HRTF decoder virtual speaker positions to radians --- Alc/hrtf.cpp | 18 ++++++++---------- Alc/hrtf.h | 5 +++-- Alc/panning.cpp | 42 +++++++++++++++++++++--------------------- 3 files changed, 32 insertions(+), 33 deletions(-) diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 5cc1e8b4..ab202e53 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -275,7 +275,7 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, } -void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const struct AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_COEFFS], ALsizei AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain) +void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, const ALsizei NumChannels, const AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_COEFFS], const ALsizei AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain) { /* Set this to 2 for dual-band HRTF processing. May require a higher quality * band-splitter, or better calculation of the new IR length to deal with the @@ -287,19 +287,17 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N al::vector idx(AmbiCount); for(ALsizei c{0};c < AmbiCount;c++) { - ALuint evidx, azidx; - ALuint evoffset; - ALuint azcount; - /* Calculate elevation index. */ - evidx = (ALsizei)((F_PI_2+AmbiPoints[c].Elev) * (Hrtf->evCount-1) / F_PI + 0.5f); - evidx = clampi(evidx, 0, Hrtf->evCount-1); + const auto evidx = clampi( + static_cast((90.0f+AmbiPoints[c].Elev)*(Hrtf->evCount-1)/180.0f + 0.5f), + 0, Hrtf->evCount-1); - azcount = Hrtf->azCount[evidx]; - evoffset = Hrtf->evOffset[evidx]; + const ALsizei azcount{Hrtf->azCount[evidx]}; + const ALsizei evoffset{Hrtf->evOffset[evidx]}; /* Calculate azimuth index for this elevation. */ - azidx = (ALsizei)((F_TAU+AmbiPoints[c].Azim) * azcount / F_TAU + 0.5f) % azcount; + const auto azidx = static_cast( + (360.0f+AmbiPoints[c].Azim)*azcount/360.0f + 0.5f) % azcount; /* Calculate indices for left and right channels. */ idx[c] = evoffset + azidx; diff --git a/Alc/hrtf.h b/Alc/hrtf.h index b814c282..756795c9 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -79,8 +79,9 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, * Produces HRTF filter coefficients for decoding B-Format, given a set of * virtual speaker positions, a matching decoding matrix, and per-order high- * frequency gains for the decoder. The calculated impulse responses are - * ordered and scaled according to the matrix input. + * ordered and scaled according to the matrix input. Note the specified virtual + * positions should be in degrees, not radians! */ -void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const struct AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_COEFFS], ALsizei AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain); +void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, const ALsizei NumChannels, const AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_COEFFS], const ALsizei AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain); #endif /* ALC_HRTF_H */ diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 9c3be106..e4a9d787 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -617,28 +617,28 @@ void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&sp void InitHrtfPanning(ALCdevice *device) { - /* NOTE: azimuth goes clockwise. */ + /* NOTE: In degrees, and azimuth goes clockwise. */ static constexpr AngularPoint AmbiPoints[]{ - { DEG2RAD( 35.264390f), DEG2RAD( -45.000000f) }, - { DEG2RAD( 35.264390f), DEG2RAD( 45.000000f) }, - { DEG2RAD( 35.264390f), DEG2RAD( 135.000000f) }, - { DEG2RAD( 35.264390f), DEG2RAD(-135.000000f) }, - { DEG2RAD(-35.264390f), DEG2RAD( -45.000000f) }, - { DEG2RAD(-35.264390f), DEG2RAD( 45.000000f) }, - { DEG2RAD(-35.264390f), DEG2RAD( 135.000000f) }, - { DEG2RAD(-35.264390f), DEG2RAD(-135.000000f) }, - { DEG2RAD( 0.000000f), DEG2RAD( -20.905157f) }, - { DEG2RAD( 0.000000f), DEG2RAD( 20.905157f) }, - { DEG2RAD( 0.000000f), DEG2RAD( 159.094843f) }, - { DEG2RAD( 0.000000f), DEG2RAD(-159.094843f) }, - { DEG2RAD( 20.905157f), DEG2RAD( -90.000000f) }, - { DEG2RAD(-20.905157f), DEG2RAD( -90.000000f) }, - { DEG2RAD(-20.905157f), DEG2RAD( 90.000000f) }, - { DEG2RAD( 20.905157f), DEG2RAD( 90.000000f) }, - { DEG2RAD( 69.094843f), DEG2RAD( 0.000000f) }, - { DEG2RAD(-69.094843f), DEG2RAD( 0.000000f) }, - { DEG2RAD(-69.094843f), DEG2RAD( 180.000000f) }, - { DEG2RAD( 69.094843f), DEG2RAD( 180.000000f) }, + { 35.264390f, -45.000000f }, + { 35.264390f, 45.000000f }, + { 35.264390f, 135.000000f }, + { 35.264390f, -135.000000f }, + { -35.264390f, -45.000000f }, + { -35.264390f, 45.000000f }, + { -35.264390f, 135.000000f }, + { -35.264390f, -135.000000f }, + { 0.000000f, -20.905157f }, + { 0.000000f, 20.905157f }, + { 0.000000f, 159.094843f }, + { 0.000000f, -159.094843f }, + { 20.905157f, -90.000000f }, + { -20.905157f, -90.000000f }, + { -20.905157f, 90.000000f }, + { 20.905157f, 90.000000f }, + { 69.094843f, 0.000000f }, + { -69.094843f, 0.000000f }, + { -69.094843f, 180.000000f }, + { 69.094843f, 180.000000f }, }; static constexpr ALfloat AmbiMatrix[][MAX_AMBI_COEFFS]{ { 5.00000000e-02f, 5.00000000e-02f, 5.00000000e-02f, 5.00000000e-02f, 6.45497224e-02f, 6.45497224e-02f, 0.00000000e+00f, 6.45497224e-02f, 0.00000000e+00f, 1.48264644e-02f, 6.33865691e-02f, 1.01126676e-01f, -7.36485380e-02f, -1.09260065e-02f, 7.08683387e-02f, -1.01622099e-01f }, -- cgit v1.2.3 From 5e4378f30a4b3599a2d77809c34390d893e99081 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 21 Dec 2018 18:17:59 -0800 Subject: Small cleanup for BuildBFormatHrtf --- Alc/hrtf.cpp | 74 ++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index ab202e53..b7422653 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -277,6 +277,13 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, const ALsizei NumChannels, const AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_COEFFS], const ALsizei AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain) { + static constexpr int OrderFromChan[MAX_AMBI_COEFFS]{ + 0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3, + }; + + ASSUME(NumChannels > 0); + ASSUME(AmbiCount > 0); + /* Set this to 2 for dual-band HRTF processing. May require a higher quality * band-splitter, or better calculation of the new IR length to deal with the * tail generated by the filter. @@ -285,92 +292,89 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, const ALs ALsizei min_delay{HRTF_HISTORY_LENGTH}; ALsizei max_delay{0}; al::vector idx(AmbiCount); - for(ALsizei c{0};c < AmbiCount;c++) + auto calc_idxs = [Hrtf,&max_delay,&min_delay](const AngularPoint &pt) noexcept -> ALsizei { /* Calculate elevation index. */ const auto evidx = clampi( - static_cast((90.0f+AmbiPoints[c].Elev)*(Hrtf->evCount-1)/180.0f + 0.5f), + static_cast((90.0f+pt.Elev)*(Hrtf->evCount-1)/180.0f + 0.5f), 0, Hrtf->evCount-1); const ALsizei azcount{Hrtf->azCount[evidx]}; const ALsizei evoffset{Hrtf->evOffset[evidx]}; /* Calculate azimuth index for this elevation. */ - const auto azidx = static_cast( - (360.0f+AmbiPoints[c].Azim)*azcount/360.0f + 0.5f) % azcount; + const auto azidx = static_cast((360.0f+pt.Azim)*azcount/360.0f + 0.5f) % azcount; - /* Calculate indices for left and right channels. */ - idx[c] = evoffset + azidx; + /* Calculate the index for the impulse response. */ + ALsizei idx{evoffset + azidx}; - min_delay = mini(min_delay, mini(Hrtf->delays[idx[c]][0], Hrtf->delays[idx[c]][1])); - max_delay = maxi(max_delay, maxi(Hrtf->delays[idx[c]][0], Hrtf->delays[idx[c]][1])); - } + min_delay = mini(min_delay, mini(Hrtf->delays[idx][0], Hrtf->delays[idx][1])); + max_delay = maxi(max_delay, maxi(Hrtf->delays[idx][0], Hrtf->delays[idx][1])); - al::vector,HRIR_LENGTH>> tmpres(NumChannels); - ALfloat temps[3][HRIR_LENGTH]{}; + return idx; + }; + std::transform(AmbiPoints, AmbiPoints+AmbiCount, idx.begin(), calc_idxs); + al::vector,HRIR_LENGTH>> tmpres(NumChannels); BandSplitter splitter; splitter.init(400.0f / (ALfloat)Hrtf->sampleRate); for(ALsizei c{0};c < AmbiCount;++c) { - const ALfloat (*fir)[2] = &Hrtf->coeffs[idx[c] * Hrtf->irSize]; - ALsizei ldelay = Hrtf->delays[idx[c]][0] - min_delay; - ALsizei rdelay = Hrtf->delays[idx[c]][1] - min_delay; + const ALfloat (*fir)[2]{&Hrtf->coeffs[idx[c] * Hrtf->irSize]}; + ALsizei ldelay{Hrtf->delays[idx[c]][0] - min_delay}; + ALsizei rdelay{Hrtf->delays[idx[c]][1] - min_delay}; if(NUM_BANDS == 1) { for(ALsizei i{0};i < NumChannels;++i) { - ALdouble mult = (ALdouble)AmbiOrderHFGain[(ALsizei)sqrt(i)] * AmbiMatrix[c][i]; - ALsizei lidx = ldelay, ridx = rdelay; - ALsizei j = 0; - while(lidx < HRIR_LENGTH && ridx < HRIR_LENGTH && j < Hrtf->irSize) + const ALdouble mult{(ALdouble)AmbiOrderHFGain[OrderFromChan[i]] * AmbiMatrix[c][i]}; + const ALsizei numirs{mini(Hrtf->irSize, HRIR_LENGTH-maxi(ldelay, rdelay))}; + ALsizei lidx{ldelay}, ridx{rdelay}; + for(ALsizei j{0};j < numirs;++j) { tmpres[i][lidx++][0] += fir[j][0] * mult; tmpres[i][ridx++][1] += fir[j][1] * mult; - j++; } } } else { + ALfloat temps[3][HRIR_LENGTH]{}; + /* Band-split left HRIR into low and high frequency responses. */ splitter.clear(); - for(ALsizei i{0};i < Hrtf->irSize;++i) - temps[2][i] = fir[i][0]; + std::transform(fir, fir+Hrtf->irSize, std::begin(temps[2]), + [](const ALfloat (&ir)[2]) noexcept { return ir[0]; }); splitter.process(temps[0], temps[1], temps[2], HRIR_LENGTH); /* Apply left ear response with delay. */ for(ALsizei i{0};i < NumChannels;++i) { - ALdouble hfgain = AmbiOrderHFGain[(ALsizei)sqrt(i)]; + const ALdouble hfgain{AmbiOrderHFGain[OrderFromChan[i]]}; for(ALsizei b{0};b < NUM_BANDS;++b) { - ALdouble mult = AmbiMatrix[c][i] * ((b==0) ? hfgain : 1.0); - ALsizei lidx = ldelay; - ALsizei j = 0; - while(lidx < HRIR_LENGTH) - tmpres[i][lidx++][0] += temps[b][j++] * mult; + const ALdouble mult{AmbiMatrix[c][i] * ((b==0) ? hfgain : 1.0)}; + for(ALsizei lidx{ldelay},j{0};lidx < HRIR_LENGTH;++lidx,++j) + tmpres[i][lidx][0] += temps[b][j] * mult; } } /* Band-split right HRIR into low and high frequency responses. */ splitter.clear(); - for(ALsizei i{0};i < Hrtf->irSize;++i) - temps[2][i] = fir[i][1]; + std::transform(fir, fir+Hrtf->irSize, std::begin(temps[2]), + [](const ALfloat (&ir)[2]) noexcept { return ir[1]; }); splitter.process(temps[0], temps[1], temps[2], HRIR_LENGTH); /* Apply right ear response with delay. */ for(ALsizei i{0};i < NumChannels;++i) { - ALdouble hfgain = AmbiOrderHFGain[(ALsizei)sqrt(i)]; + const ALdouble hfgain{AmbiOrderHFGain[OrderFromChan[i]]}; for(ALsizei b{0};b < NUM_BANDS;++b) { - ALdouble mult = AmbiMatrix[c][i] * ((b==0) ? hfgain : 1.0); - ALsizei ridx = rdelay; - ALsizei j = 0; - while(ridx < HRIR_LENGTH) - tmpres[i][ridx++][1] += temps[b][j++] * mult; + const ALdouble mult{AmbiMatrix[c][i] * ((b==0) ? hfgain : 1.0)}; + for(ALsizei ridx{rdelay},j{0};ridx < HRIR_LENGTH;++ridx,++j) + tmpres[i][ridx][1] += temps[b][j] * mult; } } } -- cgit v1.2.3 From 985d03d13dd675135250b91ee6a78b17489da1f8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 21 Dec 2018 21:07:42 -0800 Subject: Try to help GetHrtfCoeffs vectorize --- Alc/hrtf.cpp | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index b7422653..f5613f5b 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -188,7 +188,7 @@ ALsizei CalcAzIndex(ALsizei azcount, ALfloat az, ALfloat *mu) void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat (*RESTRICT coeffs)[2], ALsizei *delays) { - ALfloat dirfact{1.0f - (spread / F_TAU)}; + const ALfloat dirfact{1.0f - (spread / F_TAU)}; /* Claculate the lower elevation index. */ ALfloat emu; @@ -230,7 +230,7 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, /* Calculate bilinear blending weights, attenuated according to the * directional panning factor. */ - ALfloat blend[4]{ + const ALfloat blend[4]{ (1.0f-emu) * (1.0f-amu[0]) * dirfact, (1.0f-emu) * ( amu[0]) * dirfact, ( emu) * (1.0f-amu[1]) * dirfact, @@ -247,30 +247,28 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, Hrtf->delays[idx[2]][1]*blend[2] + Hrtf->delays[idx[3]][1]*blend[3] ); - /* Calculate the sample offsets for the HRIR indices. */ - idx[0] *= Hrtf->irSize; - idx[1] *= Hrtf->irSize; - idx[2] *= Hrtf->irSize; - idx[3] *= Hrtf->irSize; + const ALsizei irSize{Hrtf->irSize}; + ASSUME(irSize >= MIN_IR_SIZE); - ASSUME(Hrtf->irSize >= MIN_IR_SIZE && (Hrtf->irSize%MOD_IR_SIZE) == 0); + /* Calculate the sample offsets for the HRIR indices. */ + idx[0] *= irSize; + idx[1] *= irSize; + idx[2] *= irSize; + idx[3] *= irSize; /* Calculate the blended HRIR coefficients. */ - coeffs[0][0] = PassthruCoeff * (1.0f-dirfact); - coeffs[0][1] = PassthruCoeff * (1.0f-dirfact); - for(ALsizei i{1};i < Hrtf->irSize;i++) - { - coeffs[i][0] = 0.0f; - coeffs[i][1] = 0.0f; - } + ALfloat *coeffout{al::assume_aligned<16>(coeffs[0])}; + coeffout[0] = PassthruCoeff * (1.0f-dirfact); + coeffout[1] = PassthruCoeff * (1.0f-dirfact); + std::fill(coeffout+2, coeffout + irSize*2, 0.0f); for(ALsizei c{0};c < 4;c++) { - const ALfloat (*RESTRICT srccoeffs)[2] = Hrtf->coeffs + idx[c]; - for(ALsizei i{0};i < Hrtf->irSize;i++) - { - coeffs[i][0] += srccoeffs[i][0] * blend[c]; - coeffs[i][1] += srccoeffs[i][1] * blend[c]; - } + const ALfloat *srccoeffs{al::assume_aligned<16>(Hrtf->coeffs[idx[c]])}; + const ALfloat mult{blend[c]}; + auto blend_coeffs = [mult](const ALfloat src, const ALfloat coeff) noexcept -> ALfloat + { return src*mult + coeff; }; + std::transform(srccoeffs, srccoeffs + irSize*2, coeffout, + coeffout, blend_coeffs); } } -- cgit v1.2.3 From 87724db6e3f60ec9866b01a50e4e1e163efda28f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 22 Dec 2018 09:20:50 -0800 Subject: Rename a couple HRTF structs --- Alc/alc.cpp | 40 ++++++++++++------------- Alc/alu.cpp | 7 ++--- Alc/hrtf.cpp | 74 +++++++++++++++++++++++------------------------ Alc/hrtf.h | 14 ++++----- Alc/mixvoice.cpp | 2 +- Alc/panning.cpp | 20 ++++++------- OpenAL32/Include/alMain.h | 6 ++-- 7 files changed, 81 insertions(+), 82 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 5b6d3bb3..cbd586b8 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -122,7 +122,7 @@ struct BackendInfo { BackendFactory& (*getFactory)(void); }; -struct BackendInfo BackendList[] = { +BackendInfo BackendList[] = { #ifdef HAVE_JACK { "jack", JackBackendFactory::getFactory }, #endif @@ -173,8 +173,8 @@ struct BackendInfo BackendList[] = { }; ALsizei BackendListSize = static_cast(COUNTOF(BackendList)); -struct BackendInfo PlaybackBackend; -struct BackendInfo CaptureBackend; +BackendInfo PlaybackBackend; +BackendInfo CaptureBackend; /************************************************ @@ -1087,7 +1087,7 @@ static void alc_initconfig(void) } else { - struct BackendInfo Bkp = BackendList[n]; + BackendInfo Bkp = BackendList[n]; for(;n > i;n--) BackendList[n] = BackendList[n-1]; BackendList[n] = Bkp; @@ -1167,7 +1167,7 @@ static void alc_initconfig(void) /************************************************ * Device enumeration ************************************************/ -static void ProbeDevices(std::string *list, struct BackendInfo *backendinfo, enum DevProbe type) +static void ProbeDevices(std::string *list, BackendInfo *backendinfo, enum DevProbe type) { DO_INITCONFIG(); @@ -1550,7 +1550,7 @@ static void alcSetError(ALCdevice *device, ALCenum errorCode) } -static struct Compressor *CreateDeviceLimiter(const ALCdevice *device, const ALfloat threshold) +static Compressor *CreateDeviceLimiter(const ALCdevice *device, const ALfloat threshold) { return CompressorInit(device->RealOut.NumChannels, device->Frequency, AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, 0.001f, 0.002f, @@ -1849,7 +1849,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(hrtf_userreq == Hrtf_Enable || (hrtf_userreq != Hrtf_Disable && hrtf_appreq == Hrtf_Enable)) { - struct Hrtf *hrtf = nullptr; + HrtfEntry *hrtf{nullptr}; if(device->HrtfList.empty()) device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); if(!device->HrtfList.empty()) @@ -1865,9 +1865,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->FmtChans = DevFmtStereo; device->Frequency = hrtf->sampleRate; device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_FREQUENCY_REQUEST; - if(device->HrtfHandle) - Hrtf_DecRef(device->HrtfHandle); - device->HrtfHandle = hrtf; + if(device->mHrtf) + Hrtf_DecRef(device->mHrtf); + device->mHrtf = hrtf; } else { @@ -2225,9 +2225,9 @@ ALCdevice_struct::~ALCdevice_struct() if(count > 0) WARN(SZFMT " Filter%s not deleted\n", count, (count==1)?"":"s"); - if(HrtfHandle) - Hrtf_DecRef(HrtfHandle); - HrtfHandle = nullptr; + if(mHrtf) + Hrtf_DecRef(mHrtf); + mHrtf = nullptr; } @@ -2322,20 +2322,20 @@ ALCcontext_struct::ALCcontext_struct(ALCdevice *device) static ALvoid InitContext(ALCcontext *Context) { ALlistener &listener = Context->Listener; - struct ALeffectslotArray *auxslots; + ALeffectslotArray *auxslots; //Validate Context if(Context->DefaultSlot) { auxslots = static_cast(al_calloc(DEF_ALIGN, - FAM_SIZE(struct ALeffectslotArray, slot, 1))); + FAM_SIZE(ALeffectslotArray, slot, 1))); auxslots->count = 1; auxslots->slot[0] = Context->DefaultSlot.get(); } else { auxslots = static_cast(al_calloc(DEF_ALIGN, - sizeof(struct ALeffectslotArray))); + sizeof(ALeffectslotArray))); auxslots->count = 0; } Context->ActiveAuxSlots.store(auxslots, std::memory_order_relaxed); @@ -2824,7 +2824,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para else { std::lock_guard _{dev->BackendLock}; - value = (dev->HrtfHandle ? dev->HrtfName.c_str() : ""); + value = (dev->mHrtf ? dev->HrtfName.c_str() : ""); } break; @@ -3009,7 +3009,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC values[i++] = device->NumAuxSends; values[i++] = ALC_HRTF_SOFT; - values[i++] = (device->HrtfHandle ? ALC_TRUE : ALC_FALSE); + values[i++] = (device->mHrtf ? ALC_TRUE : ALC_FALSE); values[i++] = ALC_HRTF_STATUS_SOFT; values[i++] = device->HrtfStatus; @@ -3128,7 +3128,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_HRTF_SOFT: - values[0] = (device->HrtfHandle ? ALC_TRUE : ALC_FALSE); + values[0] = (device->mHrtf ? ALC_TRUE : ALC_FALSE); return 1; case ALC_HRTF_STATUS_SOFT: @@ -3239,7 +3239,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, values[i++] = dev->NumAuxSends; values[i++] = ALC_HRTF_SOFT; - values[i++] = (dev->HrtfHandle ? ALC_TRUE : ALC_FALSE); + values[i++] = (dev->mHrtf ? ALC_TRUE : ALC_FALSE); values[i++] = ALC_HRTF_STATUS_SOFT; values[i++] = dev->HrtfStatus; diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 92502eee..419334d5 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -202,7 +202,7 @@ void DeinitVoice(ALvoice *voice) noexcept void aluSelectPostProcess(ALCdevice *device) { - if(device->HrtfHandle) + if(device->mHrtf) device->PostProcess = ProcessHrtf; else if(device->AmbiDecoder) device->PostProcess = ProcessAmbiDec; @@ -730,7 +730,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev /* Get the HRIR coefficients and delays just once, for the given * source direction. */ - GetHrtfCoeffs(Device->HrtfHandle, Elev, Azi, Spread, + GetHrtfCoeffs(Device->mHrtf, Elev, Azi, Spread, voice->Direct.Params[0].Hrtf.Target.Coeffs, voice->Direct.Params[0].Hrtf.Target.Delay); voice->Direct.Params[0].Hrtf.Target.Gain = DryGain * downmix_gain; @@ -777,8 +777,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev /* Get the HRIR coefficients and delays for this channel * position. */ - GetHrtfCoeffs(Device->HrtfHandle, - chans[c].elevation, chans[c].angle, Spread, + GetHrtfCoeffs(Device->mHrtf, chans[c].elevation, chans[c].angle, Spread, voice->Direct.Params[c].Hrtf.Target.Coeffs, voice->Direct.Params[c].Hrtf.Target.Delay ); diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index f5613f5b..1995119a 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -43,8 +43,8 @@ #include "almalloc.h" -struct HrtfEntry { - Hrtf *handle{nullptr}; +struct HrtfHandle { + HrtfEntry *entry{nullptr}; char filename[]; DEF_PLACE_NEWDEL() @@ -52,7 +52,7 @@ struct HrtfEntry { namespace { -using HrtfEntryPtr = std::unique_ptr; +using HrtfHandlePtr = std::unique_ptr; /* Current data set limits defined by the makehrtf utility. */ #define MIN_IR_SIZE (8) @@ -82,7 +82,7 @@ constexpr ALchar magicMarker02[8]{'M','i','n','P','H','R','0','2'}; constexpr ALfloat PassthruCoeff{0.707106781187f/*sqrt(0.5)*/}; std::mutex LoadedHrtfLock; -al::vector LoadedHrtfs; +al::vector LoadedHrtfs; class databuf final : public std::streambuf { @@ -185,7 +185,7 @@ ALsizei CalcAzIndex(ALsizei azcount, ALfloat az, ALfloat *mu) /* Calculates static HRIR coefficients and delays for the given polar elevation * and azimuth in radians. The coefficients are normalized. */ -void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, +void GetHrtfCoeffs(const HrtfEntry *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat (*RESTRICT coeffs)[2], ALsizei *delays) { const ALfloat dirfact{1.0f - (spread / F_TAU)}; @@ -273,7 +273,7 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, } -void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, const ALsizei NumChannels, const AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_COEFFS], const ALsizei AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain) +void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsizei NumChannels, const AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_COEFFS], const ALsizei AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain) { static constexpr int OrderFromChan[MAX_AMBI_COEFFS]{ 0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3, @@ -413,14 +413,14 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, const ALs namespace { -struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALfloat distance, ALsizei evCount, +HrtfEntry *CreateHrtfStore(ALuint rate, ALsizei irSize, ALfloat distance, ALsizei evCount, ALsizei irCount, const ALubyte *azCount, const ALushort *evOffset, const ALfloat (*coeffs)[2], const ALubyte (*delays)[2], const char *filename) { - struct Hrtf *Hrtf; + HrtfEntry *Hrtf; size_t total; - total = sizeof(struct Hrtf); + total = sizeof(HrtfEntry); total += sizeof(Hrtf->azCount[0])*evCount; total = RoundUp(total, sizeof(ALushort)); /* Align for ushort fields */ total += sizeof(Hrtf->evOffset[0])*evCount; @@ -428,12 +428,12 @@ struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALfloat distance, ALsi total += sizeof(Hrtf->coeffs[0])*irSize*irCount; total += sizeof(Hrtf->delays[0])*irCount; - Hrtf = static_cast(al_calloc(16, total)); + Hrtf = static_cast(al_calloc(16, total)); if(Hrtf == nullptr) ERR("Out of memory allocating storage for %s.\n", filename); else { - uintptr_t offset = sizeof(struct Hrtf); + uintptr_t offset = sizeof(HrtfEntry); char *base = (char*)Hrtf; ALushort *_evOffset; ALubyte *_azCount; @@ -524,7 +524,7 @@ ALuint GetLE_ALuint(std::istream &data) return ret; } -struct Hrtf *LoadHrtf00(std::istream &data, const char *filename) +HrtfEntry *LoadHrtf00(std::istream &data, const char *filename) { ALuint rate{GetLE_ALuint(data)}; ALushort irCount{GetLE_ALushort(data)}; @@ -642,7 +642,7 @@ struct Hrtf *LoadHrtf00(std::istream &data, const char *filename) &reinterpret_cast(delays[0]), filename); } -struct Hrtf *LoadHrtf01(std::istream &data, const char *filename) +HrtfEntry *LoadHrtf01(std::istream &data, const char *filename) { ALuint rate{GetLE_ALuint(data)}; ALushort irSize{GetLE_ALubyte(data)}; @@ -746,7 +746,7 @@ struct Hrtf *LoadHrtf01(std::istream &data, const char *filename) #define CHANTYPE_LEFTONLY 0 #define CHANTYPE_LEFTRIGHT 1 -struct Hrtf *LoadHrtf02(std::istream &data, const char *filename) +HrtfEntry *LoadHrtf02(std::istream &data, const char *filename) { ALuint rate{GetLE_ALuint(data)}; ALubyte sampleType{GetLE_ALubyte(data)}; @@ -982,9 +982,9 @@ void AddFileEntry(al::vector &list, const std::string &filename) { TRACE("Got new file \"%s\"\n", filename.c_str()); - LoadedHrtfs.emplace_back(HrtfEntryPtr{new - (al_calloc(DEF_ALIGN, FAM_SIZE(HrtfEntry, filename, filename.length()+1))) - HrtfEntry{}}); + LoadedHrtfs.emplace_back(HrtfHandlePtr{new + (al_calloc(DEF_ALIGN, FAM_SIZE(HrtfHandle, filename, filename.length()+1))) + HrtfHandle{}}); loaded_entry = LoadedHrtfs.end()-1; strcpy((*loaded_entry)->filename, filename.c_str()); } @@ -1044,9 +1044,9 @@ void AddBuiltInEntry(al::vector &list, const std::string &filena TRACE("Got new file \"%s\"\n", filename.c_str()); - LoadedHrtfs.emplace_back(HrtfEntryPtr{new - (al_calloc(DEF_ALIGN, FAM_SIZE(HrtfEntry, filename, namelen))) - HrtfEntry{}}); + LoadedHrtfs.emplace_back(HrtfHandlePtr{new + (al_calloc(DEF_ALIGN, FAM_SIZE(HrtfHandle, filename, namelen))) + HrtfHandle{}}); loaded_entry = LoadedHrtfs.end()-1; snprintf((*loaded_entry)->filename, namelen, "!%u_%s", residx, filename.c_str()); @@ -1172,13 +1172,13 @@ al::vector EnumerateHrtf(const char *devname) return list; } -struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry) +HrtfEntry *GetLoadedHrtf(HrtfHandle *handle) { std::lock_guard _{LoadedHrtfLock}; - if(entry->handle) + if(handle->entry) { - Hrtf *hrtf{entry->handle}; + HrtfEntry *hrtf{handle->entry}; Hrtf_IncRef(hrtf); return hrtf; } @@ -1187,9 +1187,9 @@ struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry) const char *name{""}; ALuint residx{}; char ch{}; - if(sscanf(entry->filename, "!%u%c", &residx, &ch) == 2 && ch == '_') + if(sscanf(handle->filename, "!%u%c", &residx, &ch) == 2 && ch == '_') { - name = strchr(entry->filename, ch)+1; + name = strchr(handle->filename, ch)+1; TRACE("Loading %s...\n", name); ResData res{GetResource(residx)}; @@ -1202,19 +1202,19 @@ struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry) } else { - name = entry->filename; + name = handle->filename; - TRACE("Loading %s...\n", entry->filename); - std::unique_ptr fstr{new al::ifstream{entry->filename, std::ios::binary}}; + TRACE("Loading %s...\n", handle->filename); + std::unique_ptr fstr{new al::ifstream{handle->filename, std::ios::binary}}; if(!fstr->is_open()) { - ERR("Could not open %s\n", entry->filename); + ERR("Could not open %s\n", handle->filename); return nullptr; } stream = std::move(fstr); } - Hrtf *hrtf{}; + HrtfEntry *hrtf{nullptr}; char magic[sizeof(magicMarker02)]; stream->read(magic, sizeof(magic)); if(stream->gcount() < static_cast(sizeof(magicMarker02))) @@ -1242,7 +1242,7 @@ struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry) ERR("Failed to load %s\n", name); else { - entry->handle = hrtf; + handle->entry = hrtf; Hrtf_IncRef(hrtf); TRACE("Loaded HRTF support for format: %s %uhz\n", DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); @@ -1252,13 +1252,13 @@ struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry) } -void Hrtf_IncRef(struct Hrtf *hrtf) +void Hrtf_IncRef(HrtfEntry *hrtf) { auto ref = IncrementRef(&hrtf->ref); TRACEREF("%p increasing refcount to %u\n", hrtf, ref); } -void Hrtf_DecRef(struct Hrtf *hrtf) +void Hrtf_DecRef(HrtfEntry *hrtf) { auto ref = DecrementRef(&hrtf->ref); TRACEREF("%p decreasing refcount to %u\n", hrtf, ref); @@ -1271,13 +1271,13 @@ void Hrtf_DecRef(struct Hrtf *hrtf) * before the lock was taken. */ auto iter = std::find_if(LoadedHrtfs.begin(), LoadedHrtfs.end(), - [hrtf](const HrtfEntryPtr &entry) noexcept -> bool - { return hrtf == entry->handle; } + [hrtf](const HrtfHandlePtr &entry) noexcept -> bool + { return hrtf == entry->entry; } ); if(iter != LoadedHrtfs.end() && ReadRef(&hrtf->ref) == 0) { - al_free((*iter)->handle); - (*iter)->handle = nullptr; + al_free((*iter)->entry); + (*iter)->entry = nullptr; TRACE("Unloaded unused HRTF %s\n", (*iter)->filename); } } diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 756795c9..15c16723 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -19,9 +19,9 @@ #define HRIR_MASK (HRIR_LENGTH-1) -struct HrtfEntry; +struct HrtfHandle; -struct Hrtf { +struct HrtfEntry { RefCount ref; ALuint sampleRate; @@ -69,11 +69,11 @@ struct AngularPoint { al::vector EnumerateHrtf(const char *devname); -struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry); -void Hrtf_IncRef(struct Hrtf *hrtf); -void Hrtf_DecRef(struct Hrtf *hrtf); +HrtfEntry *GetLoadedHrtf(HrtfHandle *handle); +void Hrtf_IncRef(HrtfEntry *hrtf); +void Hrtf_DecRef(HrtfEntry *hrtf); -void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat (*RESTRICT coeffs)[2], ALsizei *delays); +void GetHrtfCoeffs(const HrtfEntry *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat (*RESTRICT coeffs)[2], ALsizei *delays); /** * Produces HRTF filter coefficients for decoding B-Format, given a set of @@ -82,6 +82,6 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, * ordered and scaled according to the matrix input. Note the specified virtual * positions should be in degrees, not radians! */ -void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, const ALsizei NumChannels, const AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_COEFFS], const ALsizei AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain); +void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsizei NumChannels, const AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_COEFFS], const ALsizei AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain); #endif /* ALC_HRTF_H */ diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index f43ae127..db2609f5 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -310,7 +310,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize ASSUME(increment > 0); ALCdevice *Device{Context->Device}; - ALsizei IrSize{Device->HrtfHandle ? Device->HrtfHandle->irSize : 0}; + ALsizei IrSize{Device->mHrtf ? Device->mHrtf->irSize : 0}; ResamplerFunc Resample{(increment == FRACTIONONE && DataPosFrac == 0) ? Resample_copy_C : voice->Resampler}; diff --git a/Alc/panning.cpp b/Alc/panning.cpp index e4a9d787..f15c086e 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -715,12 +715,12 @@ void InitHrtfPanning(ALCdevice *device) device->RealOut.NumChannels = device->channelsFromFmt(); - BuildBFormatHrtf(device->HrtfHandle, + BuildBFormatHrtf(device->mHrtf, device->mHrtfState.get(), device->Dry.NumChannels, AmbiPoints, AmbiMatrix, static_cast(COUNTOF(AmbiPoints)), AmbiOrderHFGain ); - InitNearFieldCtrl(device, device->HrtfHandle->distance, device->AmbiUp ? 2 : 1, + InitNearFieldCtrl(device, device->mHrtf->distance, device->AmbiUp ? 2 : 1, ChansPerOrder); } @@ -871,10 +871,10 @@ void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, con void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appreq, HrtfRequestMode hrtf_userreq) { /* Hold the HRTF the device last used, in case it's used again. */ - Hrtf *old_hrtf{device->HrtfHandle}; + HrtfEntry *old_hrtf{device->mHrtf}; device->mHrtfState = nullptr; - device->HrtfHandle = nullptr; + device->mHrtf = nullptr; device->HrtfName.clear(); device->Render_Mode = NormalRender; @@ -1026,35 +1026,35 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr if(hrtf_id >= 0 && (size_t)hrtf_id < device->HrtfList.size()) { const EnumeratedHrtf &entry = device->HrtfList[hrtf_id]; - Hrtf *hrtf{GetLoadedHrtf(entry.hrtf)}; + HrtfEntry *hrtf{GetLoadedHrtf(entry.hrtf)}; if(hrtf && hrtf->sampleRate == device->Frequency) { - device->HrtfHandle = hrtf; + device->mHrtf = hrtf; device->HrtfName = entry.name; } else if(hrtf) Hrtf_DecRef(hrtf); } - if(!device->HrtfHandle) + if(!device->mHrtf) { auto find_hrtf = [device](const EnumeratedHrtf &entry) -> bool { - Hrtf *hrtf{GetLoadedHrtf(entry.hrtf)}; + HrtfEntry *hrtf{GetLoadedHrtf(entry.hrtf)}; if(!hrtf) return false; if(hrtf->sampleRate != device->Frequency) { Hrtf_DecRef(hrtf); return false; } - device->HrtfHandle = hrtf; + device->mHrtf = hrtf; device->HrtfName = entry.name; return true; }; std::find_if(device->HrtfList.cbegin(), device->HrtfList.cend(), find_hrtf); } - if(device->HrtfHandle) + if(device->mHrtf) { if(old_hrtf) Hrtf_DecRef(old_hrtf); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index daafaad1..bc1dc222 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -236,8 +236,8 @@ static const union { #endif -struct Hrtf; struct HrtfEntry; +struct HrtfHandle; struct DirectHrtfState; struct FrontStablizer; struct Compressor; @@ -600,7 +600,7 @@ struct FilterSubList { typedef struct EnumeratedHrtf { std::string name; - struct HrtfEntry *hrtf; + HrtfHandle *hrtf; } EnumeratedHrtf; @@ -760,7 +760,7 @@ struct ALCdevice_struct { /* HRTF state and info */ std::unique_ptr mHrtfState; - Hrtf *HrtfHandle{nullptr}; + HrtfEntry *mHrtf{nullptr}; /* UHJ encoder state */ std::unique_ptr Uhj_Encoder; -- cgit v1.2.3 From b955c5cf5dbdc0814daa349e90907229774574aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 22 Dec 2018 10:00:06 -0800 Subject: A bit of cleanup for CalcPanningAndFilters --- Alc/alu.cpp | 54 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 419334d5..be0bafbf 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -585,15 +585,13 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev if(Device->AvgSpeakerDist > 0.0f) { - const ALfloat mdist{Distance * Listener.Params.MetersPerUnit}; - const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC / - (Device->AvgSpeakerDist * (ALfloat)Device->Frequency)}; - ALfloat w0{SPEEDOFSOUNDMETRESPERSEC / - (mdist * (ALfloat)Device->Frequency)}; - /* Clamp w0 for really close distances, to prevent excessive - * bass. + /* Clamp the distance for really close sources, to prevent + * excessive bass. */ - w0 = minf(w0, w1*4.0f); + const ALfloat mdist{maxf(Distance*Listener.Params.MetersPerUnit, + Device->AvgSpeakerDist/4.0f)}; + const ALfloat w0{SPEEDOFSOUNDMETRESPERSEC / + (mdist * (ALfloat)Device->Frequency)}; /* Only need to adjust the first channel of a B-Format source. */ voice->Direct.Params[0].NFCtrlFilter.adjust(w0); @@ -604,6 +602,12 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev voice->Flags |= VOICE_HAS_NFC; } + /* Always render B-Format sources to the FOA output, to ensure + * smooth changes if it switches between panned and unpanned. + */ + voice->Direct.Buffer = Device->FOAOut.Buffer; + voice->Direct.Channels = Device->FOAOut.NumChannels; + /* A scalar of 1.5 for plain stereo results in +/-60 degrees being * moved to +/-90 degrees for direct right and left speaker * responses. @@ -612,14 +616,14 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev CalcAngleCoeffs((Device->Render_Mode==StereoPair) ? ScaleAzimuthFront(Azi, 1.5f) : Azi, Elev, Spread, coeffs); - /* NOTE: W needs to be scaled by sqrt(2) due to FuMa normalization. */ - ComputePanGains(&Device->Dry, coeffs, DryGain*SQRTF_2, + /* NOTE: W needs to be scaled due to FuMa normalization. */ + ComputePanGains(&Device->FOAOut, coeffs, DryGain*AmbiScale::FromFuMa[0], voice->Direct.Params[0].Gains.Target); for(ALsizei i{0};i < NumSends;i++) { if(const ALeffectslot *Slot{SendSlots[i]}) ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, - WetGain[i]*SQRTF_2, voice->Send[i].Params[0].Gains.Target + WetGain[i]*AmbiScale::FromFuMa[0], voice->Send[i].Params[0].Gains.Target ); } } @@ -663,12 +667,16 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev * matrix is transposed, for the inputs to align on the rows and * outputs on the columns. */ + static constexpr ALfloat scale0{AmbiScale::FromFuMa[0]}; + static constexpr ALfloat scale1{AmbiScale::FromFuMa[1]}; + static constexpr ALfloat scale2{AmbiScale::FromFuMa[2]}; + static constexpr ALfloat scale3{AmbiScale::FromFuMa[3]}; const alu::Matrix matrix{ - // ACN0 ACN1 ACN2 ACN3 - SQRTF_2, 0.0f, 0.0f, 0.0f, // Ambi W - 0.0f, -N[0]*SQRTF_3, N[1]*SQRTF_3, -N[2]*SQRTF_3, // Ambi X - 0.0f, U[0]*SQRTF_3, -U[1]*SQRTF_3, U[2]*SQRTF_3, // Ambi Y - 0.0f, -V[0]*SQRTF_3, V[1]*SQRTF_3, -V[2]*SQRTF_3 // Ambi Z + // ACN0 ACN1 ACN2 ACN3 + scale0, 0.0f, 0.0f, 0.0f, // Ambi W + 0.0f, -N[0]*scale1, N[1]*scale2, -N[2]*scale3, // Ambi X + 0.0f, U[0]*scale1, -U[1]*scale2, U[2]*scale3, // Ambi Y + 0.0f, -V[0]*scale1, V[1]*scale2, -V[2]*scale3 // Ambi Z }; voice->Direct.Buffer = Device->FOAOut.Buffer; @@ -808,15 +816,13 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev /* Calculate NFC filter coefficient if needed. */ if(Device->AvgSpeakerDist > 0.0f) { - const ALfloat mdist{Distance * Listener.Params.MetersPerUnit}; - const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC / - (Device->AvgSpeakerDist * (ALfloat)Device->Frequency)}; - ALfloat w0{SPEEDOFSOUNDMETRESPERSEC / - (mdist * (ALfloat)Device->Frequency)}; - /* Clamp w0 for really close distances, to prevent excessive - * bass. + /* Clamp the distance for really close sources, to prevent + * excessive bass. */ - w0 = minf(w0, w1*4.0f); + const ALfloat mdist{maxf(Distance*Listener.Params.MetersPerUnit, + Device->AvgSpeakerDist/4.0f)}; + const ALfloat w0{SPEEDOFSOUNDMETRESPERSEC / + (mdist * (ALfloat)Device->Frequency)}; /* Adjust NFC filters. */ for(ALsizei c{0};c < num_channels;c++) -- cgit v1.2.3 From 10ce121dbd05e048c89a2b7c32f2ddabbc8fbe77 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 22 Dec 2018 11:38:38 -0800 Subject: Use a normal delete instead of ll_ringbuffer_free And use RingBufferPtr in more places --- Alc/alc.cpp | 2 +- Alc/backends/alsa.cpp | 18 ++++++---------- Alc/backends/coreaudio.cpp | 20 ++++++----------- Alc/backends/dsound.cpp | 22 ++++++++----------- Alc/backends/opensl.cpp | 48 +++++++++++++++++------------------------ Alc/backends/oss.cpp | 15 ++++++------- Alc/backends/portaudio.cpp | 18 ++++++---------- Alc/backends/sndio.cpp | 16 ++++++-------- Alc/backends/wasapi.cpp | 18 ++++++---------- Alc/backends/winmm.cpp | 13 +++++------- Alc/ringbuffer.cpp | 45 +++++++++++---------------------------- Alc/ringbuffer.h | 53 ++++++++++++++++++++++++++++------------------ 12 files changed, 119 insertions(+), 169 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index cbd586b8..fb7f9c67 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2459,7 +2459,7 @@ ALCcontext_struct::~ALCcontext_struct() } TRACE("Freed " SZFMT " listener property object%s\n", count, (count==1)?"":"s"); - ll_ringbuffer_free(AsyncEvents); + delete AsyncEvents; AsyncEvents = nullptr; ALCdevice_DecRef(Device); diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index 606877a8..228cafe0 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -929,7 +929,7 @@ struct ALCcaptureAlsa final : public ALCbackend { al::vector Buffer; bool DoCapture{false}; - ll_ringbuffer_t *Ring{nullptr}; + RingBufferPtr Ring{nullptr}; snd_pcm_sframes_t mLastAvail{0}; }; @@ -963,9 +963,6 @@ void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self) snd_pcm_close(self->PcmHandle); self->PcmHandle = nullptr; - ll_ringbuffer_free(self->Ring); - self->Ring = nullptr; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCcaptureAlsa(); } @@ -1068,8 +1065,8 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) if(needring) { - self->Ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, - device->frameSizeFromFmt(), false); + self->Ring.reset(ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, + device->frameSizeFromFmt(), false)); if(!self->Ring) { ERR("ring buffer create failed\n"); @@ -1086,7 +1083,6 @@ error: if(hp) snd_pcm_hw_params_free(hp); error2: - ll_ringbuffer_free(self->Ring); self->Ring = nullptr; snd_pcm_close(self->PcmHandle); self->PcmHandle = nullptr; @@ -1142,7 +1138,7 @@ ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALC if(self->Ring) { - ll_ringbuffer_read(self->Ring, static_cast(buffer), samples); + ll_ringbuffer_read(self->Ring.get(), static_cast(buffer), samples); return ALC_NO_ERROR; } @@ -1235,7 +1231,7 @@ ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) while(avail > 0) { - auto vec = ll_ringbuffer_get_write_vector(self->Ring); + auto vec = ll_ringbuffer_get_write_vector(self->Ring.get()); if(vec.first.len == 0) break; snd_pcm_sframes_t amt{std::min(vec.first.len, avail)}; @@ -1263,11 +1259,11 @@ ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) continue; } - ll_ringbuffer_write_advance(self->Ring, amt); + ll_ringbuffer_write_advance(self->Ring.get(), amt); avail -= amt; } - return ll_ringbuffer_read_space(self->Ring); + return ll_ringbuffer_read_space(self->Ring.get()); } ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self) diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index 228d1d76..aaaf6221 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -324,7 +324,7 @@ struct ALCcoreAudioCapture final : public ALCbackend { AudioBufferList *BufferList; // Buffer for data coming from the input device ALCvoid *ResampleBuffer; // Buffer for returned RingBuffer data when resampling - ll_ringbuffer_t *Ring; + RingBufferPtr Ring{nullptr}; }; static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device); @@ -376,14 +376,10 @@ static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice * self->AudioConverter = NULL; self->BufferList = NULL; self->ResampleBuffer = NULL; - self->Ring = NULL; } static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self) { - ll_ringbuffer_free(self->Ring); - self->Ring = NULL; - free(self->ResampleBuffer); self->ResampleBuffer = NULL; @@ -420,7 +416,7 @@ static OSStatus ALCcoreAudioCapture_RecordProc(void *inRefCon, return err; } - ll_ringbuffer_write(self->Ring, self->BufferList->mBuffers[0].mData, inNumberFrames); + ll_ringbuffer_write(self->Ring.get(), self->BufferList->mBuffers[0].mData, inNumberFrames); return noErr; } @@ -432,7 +428,7 @@ static OSStatus ALCcoreAudioCapture_ConvertCallback(AudioConverterRef UNUSED(inA ALCcoreAudioCapture *self = reinterpret_cast(inUserData); // Read from the ring buffer and store temporarily in a large buffer - ll_ringbuffer_read(self->Ring, self->ResampleBuffer, *ioNumberDataPackets); + ll_ringbuffer_read(self->Ring.get(), self->ResampleBuffer, *ioNumberDataPackets); // Set the input data ioData->mNumberBuffers = 1; @@ -666,18 +662,16 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar if(self->BufferList == NULL) goto error; - self->Ring = ll_ringbuffer_create( + self->Ring.reset(ll_ringbuffer_create( (size_t)ceil(device->UpdateSize*self->SampleRateRatio*device->NumUpdates), - self->FrameSize, false - ); + self->FrameSize, false)); if(!self->Ring) goto error; device->DeviceName = name; return ALC_NO_ERROR; error: - ll_ringbuffer_free(self->Ring); - self->Ring = NULL; + self->Ring = nullptr; free(self->ResampleBuffer); self->ResampleBuffer = NULL; destroy_buffer_list(self->BufferList); @@ -745,7 +739,7 @@ static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALC static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self) { - return ll_ringbuffer_read_space(self->Ring) / self->SampleRateRatio; + return ll_ringbuffer_read_space(self->Ring.get()) / self->SampleRateRatio; } diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 5aa95f0f..26e561bf 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -655,7 +655,7 @@ struct ALCdsoundCapture final : public ALCbackend { DWORD BufferBytes{0u}; DWORD Cursor{0u}; - ll_ringbuffer_t *Ring{nullptr}; + RingBufferPtr Ring{nullptr}; }; void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device); @@ -681,9 +681,6 @@ void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device) void ALCdsoundCapture_Destruct(ALCdsoundCapture *self) { - ll_ringbuffer_free(self->Ring); - self->Ring = nullptr; - if(self->DSCbuffer) { self->DSCbuffer->Stop(); @@ -838,8 +835,8 @@ ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) self->DSC->CreateCaptureBuffer(&DSCBDescription, &self->DSCbuffer, nullptr); if(SUCCEEDED(hr)) { - self->Ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, - InputType.Format.nBlockAlign, false); + self->Ring.reset(ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, + InputType.Format.nBlockAlign, false)); if(!self->Ring) hr = DSERR_OUTOFMEMORY; } @@ -847,7 +844,6 @@ ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) { ERR("Device init failed: 0x%08lx\n", hr); - ll_ringbuffer_free(self->Ring); self->Ring = nullptr; if(self->DSCbuffer) self->DSCbuffer->Release(); @@ -893,7 +889,7 @@ void ALCdsoundCapture_stop(ALCdsoundCapture *self) ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint samples) { - ll_ringbuffer_read(self->Ring, buffer, samples); + ll_ringbuffer_read(self->Ring.get(), buffer, samples); return ALC_NO_ERROR; } @@ -902,7 +898,7 @@ ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; if(!device->Connected.load(std::memory_order_acquire)) - return static_cast(ll_ringbuffer_read_space(self->Ring)); + return static_cast(ll_ringbuffer_read_space(self->Ring.get())); ALsizei FrameSize{device->frameSizeFromFmt()}; DWORD BufferBytes{self->BufferBytes}; @@ -915,15 +911,15 @@ ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) if(SUCCEEDED(hr)) { DWORD NumBytes{(ReadCursor-LastCursor + BufferBytes) % BufferBytes}; - if(!NumBytes) return static_cast(ll_ringbuffer_read_space(self->Ring)); + if(!NumBytes) return static_cast(ll_ringbuffer_read_space(self->Ring.get())); hr = self->DSCbuffer->Lock(LastCursor, NumBytes, &ReadPtr1, &ReadCnt1, &ReadPtr2, &ReadCnt2, 0); } if(SUCCEEDED(hr)) { - ll_ringbuffer_write(self->Ring, ReadPtr1, ReadCnt1/FrameSize); + ll_ringbuffer_write(self->Ring.get(), ReadPtr1, ReadCnt1/FrameSize); if(ReadPtr2 != nullptr) - ll_ringbuffer_write(self->Ring, ReadPtr2, ReadCnt2/FrameSize); + ll_ringbuffer_write(self->Ring.get(), ReadPtr2, ReadCnt2/FrameSize); hr = self->DSCbuffer->Unlock(ReadPtr1, ReadCnt1, ReadPtr2, ReadCnt2); self->Cursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes; } @@ -934,7 +930,7 @@ ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) aluHandleDisconnect(device, "Failure retrieving capture data: 0x%lx", hr); } - return static_cast(ll_ringbuffer_read_space(self->Ring)); + return static_cast(ll_ringbuffer_read_space(self->Ring.get())); } } // namespace diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 78212791..ab829e05 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -145,7 +145,7 @@ struct ALCopenslPlayback final : public ALCbackend { /* buffer queue player interfaces */ SLObjectItf mBufferQueueObj{nullptr}; - ll_ringbuffer_t *mRing{nullptr}; + RingBufferPtr mRing{nullptr}; al::semaphore mSem; ALsizei mFrameSize{0}; @@ -195,9 +195,6 @@ static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self) self->mEngineObj = NULL; self->mEngine = NULL; - ll_ringbuffer_free(self->mRing); - self->mRing = NULL; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCopenslPlayback(); } @@ -216,7 +213,7 @@ static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), * available for writing again, and wake up the mixer thread to mix and * queue more audio. */ - ll_ringbuffer_read_advance(self->mRing, 1); + ll_ringbuffer_read_advance(self->mRing.get(), 1); self->mSem.post(); } @@ -250,7 +247,7 @@ static int ALCopenslPlayback_mixerProc(ALCopenslPlayback *self) { size_t todo; - if(ll_ringbuffer_write_space(self->mRing) == 0) + if(ll_ringbuffer_write_space(self->mRing.get()) == 0) { SLuint32 state = 0; @@ -267,7 +264,7 @@ static int ALCopenslPlayback_mixerProc(ALCopenslPlayback *self) break; } - if(ll_ringbuffer_write_space(self->mRing) == 0) + if(ll_ringbuffer_write_space(self->mRing.get()) == 0) { ALCopenslPlayback_unlock(self); self->mSem.wait(); @@ -276,13 +273,13 @@ static int ALCopenslPlayback_mixerProc(ALCopenslPlayback *self) } } - auto data = ll_ringbuffer_get_write_vector(self->mRing); + auto data = ll_ringbuffer_get_write_vector(self->mRing.get()); aluMixData(device, data.first.buf, data.first.len*device->UpdateSize); if(data.second.len > 0) aluMixData(device, data.second.buf, data.second.len*device->UpdateSize); todo = data.first.len+data.second.len; - ll_ringbuffer_write_advance(self->mRing, todo); + ll_ringbuffer_write_advance(self->mRing.get(), todo); for(size_t i = 0;i < todo;i++) { @@ -380,8 +377,7 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) VCALL0(self->mBufferQueueObj,Destroy)(); self->mBufferQueueObj = NULL; - ll_ringbuffer_free(self->mRing); - self->mRing = NULL; + self->mRing = nullptr; sampleRate = device->Frequency; #if 0 @@ -536,9 +532,8 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) } if(SL_RESULT_SUCCESS == result) { - self->mRing = ll_ringbuffer_create(device->NumUpdates, - self->mFrameSize*device->UpdateSize, true - ); + self->mRing.reset(ll_ringbuffer_create(device->NumUpdates, + self->mFrameSize*device->UpdateSize, true)); if(!self->mRing) { ERR("Out of memory allocating ring buffer %ux%u %u\n", device->UpdateSize, @@ -564,7 +559,7 @@ static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self) SLAndroidSimpleBufferQueueItf bufferQueue; SLresult result; - ll_ringbuffer_reset(self->mRing); + ll_ringbuffer_reset(self->mRing.get()); result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); @@ -642,7 +637,8 @@ static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self) ALCopenslPlayback_lock(self); ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = std::chrono::seconds{ll_ringbuffer_read_space(self->mRing)*device->UpdateSize}; + ret.Latency = std::chrono::seconds{ll_ringbuffer_read_space(self->mRing.get()) * + device->UpdateSize}; ret.Latency /= device->Frequency; ALCopenslPlayback_unlock(self); @@ -658,7 +654,7 @@ struct ALCopenslCapture final : public ALCbackend { /* recording interfaces */ SLObjectItf mRecordObj{nullptr}; - ll_ringbuffer_t *mRing{nullptr}; + RingBufferPtr mRing{nullptr}; ALCuint mSplOffset{0u}; ALsizei mFrameSize{0}; @@ -699,9 +695,6 @@ static void ALCopenslCapture_Destruct(ALCopenslCapture *self) self->mEngineObj = NULL; self->mEngine = NULL; - ll_ringbuffer_free(self->mRing); - self->mRing = NULL; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCopenslCapture(); } @@ -711,7 +704,7 @@ static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), v { ALCopenslCapture *self = static_cast(context); /* A new chunk has been written into the ring buffer, advance it. */ - ll_ringbuffer_write_advance(self->mRing, 1); + ll_ringbuffer_write_advance(self->mRing.get(), 1); } @@ -830,9 +823,8 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name if(SL_RESULT_SUCCESS == result) { - self->mRing = ll_ringbuffer_create(device->NumUpdates, - device->UpdateSize*self->mFrameSize, false - ); + self->mRing.reset(ll_ringbuffer_create(device->NumUpdates, + device->UpdateSize*self->mFrameSize, false)); result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); @@ -848,7 +840,7 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name ALsizei chunk_size = device->UpdateSize * self->mFrameSize; size_t i; - auto data = ll_ringbuffer_get_write_vector(self->mRing); + auto data = ll_ringbuffer_get_write_vector(self->mRing.get()); for(i = 0;i < data.first.len && SL_RESULT_SUCCESS == result;i++) { result = VCALL(bufferQueue,Enqueue)(data.first.buf + chunk_size*i, chunk_size); @@ -935,7 +927,7 @@ static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid * /* Read the desired samples from the ring buffer then advance its read * pointer. */ - auto data = ll_ringbuffer_get_read_vector(self->mRing); + auto data = ll_ringbuffer_get_read_vector(self->mRing.get()); for(i = 0;i < samples;) { ALCuint rem = minu(samples - i, device->UpdateSize - self->mSplOffset); @@ -949,7 +941,7 @@ static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid * /* Finished a chunk, reset the offset and advance the read pointer. */ self->mSplOffset = 0; - ll_ringbuffer_read_advance(self->mRing, 1); + ll_ringbuffer_read_advance(self->mRing.get(), 1); result = VCALL(bufferQueue,Enqueue)(data.first.buf, chunk_size); PRINTERR(result, "bufferQueue->Enqueue"); if(SL_RESULT_SUCCESS != result) break; @@ -978,7 +970,7 @@ static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid * static ALCuint ALCopenslCapture_availableSamples(ALCopenslCapture *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - return ll_ringbuffer_read_space(self->mRing) * device->UpdateSize; + return ll_ringbuffer_read_space(self->mRing.get()) * device->UpdateSize; } diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 110672c7..065f159a 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -501,7 +501,7 @@ void ALCplaybackOSS_stop(ALCplaybackOSS *self) struct ALCcaptureOSS final : public ALCbackend { int fd{-1}; - ll_ringbuffer_t *mRing{nullptr}; + RingBufferPtr mRing{nullptr}; std::atomic mKillNow{AL_TRUE}; std::thread mThread; @@ -537,8 +537,6 @@ void ALCcaptureOSS_Destruct(ALCcaptureOSS *self) close(self->fd); self->fd = -1; - ll_ringbuffer_free(self->mRing); - self->mRing = nullptr; ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCcaptureOSS(); } @@ -580,7 +578,7 @@ int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) continue; } - auto vec = ll_ringbuffer_get_write_vector(self->mRing); + auto vec = ll_ringbuffer_get_write_vector(self->mRing.get()); if(vec.first.len > 0) { amt = read(self->fd, vec.first.buf, vec.first.len*frame_size); @@ -592,7 +590,7 @@ int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) ALCcaptureOSS_unlock(self); break; } - ll_ringbuffer_write_advance(self->mRing, amt/frame_size); + ll_ringbuffer_write_advance(self->mRing.get(), amt/frame_size); } } @@ -698,7 +696,8 @@ ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) return ALC_INVALID_VALUE; } - self->mRing = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, frameSize, false); + self->mRing.reset(ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, frameSize, + false)); if(!self->mRing) { ERR("Ring buffer create failed\n"); @@ -739,13 +738,13 @@ void ALCcaptureOSS_stop(ALCcaptureOSS *self) ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples) { - ll_ringbuffer_read(self->mRing, static_cast(buffer), samples); + ll_ringbuffer_read(self->mRing.get(), static_cast(buffer), samples); return ALC_NO_ERROR; } ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self) { - return ll_ringbuffer_read_space(self->mRing); + return ll_ringbuffer_read_space(self->mRing.get()); } } // namespace diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index 93384489..a89959b6 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -319,7 +319,7 @@ struct ALCportCapture final : public ALCbackend { PaStream *Stream{nullptr}; PaStreamParameters Params; - ll_ringbuffer_t *Ring{nullptr}; + RingBufferPtr Ring{nullptr}; }; int ALCportCapture_ReadCallback(const void *inputBuffer, void *outputBuffer, @@ -356,9 +356,6 @@ void ALCportCapture_Destruct(ALCportCapture *self) ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); self->Stream = nullptr; - ll_ringbuffer_free(self->Ring); - self->Ring = nullptr; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCportCapture(); } @@ -369,10 +366,7 @@ int ALCportCapture_ReadCallback(const void *inputBuffer, void *UNUSED(outputBuff const PaStreamCallbackFlags UNUSED(statusFlags), void *userData) { ALCportCapture *self = static_cast(userData); - size_t writable = ll_ringbuffer_write_space(self->Ring); - - if(framesPerBuffer > writable) framesPerBuffer = writable; - ll_ringbuffer_write(self->Ring, inputBuffer, framesPerBuffer); + ll_ringbuffer_write(self->Ring.get(), inputBuffer, framesPerBuffer); return 0; } @@ -392,8 +386,8 @@ ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) samples = maxu(samples, 100 * device->Frequency / 1000); frame_size = device->frameSizeFromFmt(); - self->Ring = ll_ringbuffer_create(samples, frame_size, false); - if(self->Ring == nullptr) return ALC_INVALID_VALUE; + self->Ring.reset(ll_ringbuffer_create(samples, frame_size, false)); + if(!self->Ring) return ALC_INVALID_VALUE; self->Params.device = -1; if(!ConfigValueInt(nullptr, "port", "capture", &self->Params.device) || @@ -462,12 +456,12 @@ void ALCportCapture_stop(ALCportCapture *self) ALCuint ALCportCapture_availableSamples(ALCportCapture *self) { - return ll_ringbuffer_read_space(self->Ring); + return ll_ringbuffer_read_space(self->Ring.get()); } ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples) { - ll_ringbuffer_read(self->Ring, buffer, samples); + ll_ringbuffer_read(self->Ring.get(), buffer, samples); return ALC_NO_ERROR; } diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index 9ebad671..25566490 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -279,7 +279,7 @@ static void SndioPlayback_stop(SndioPlayback *self) struct SndioCapture final : public ALCbackend { struct sio_hdl *sndHandle{nullptr}; - ll_ringbuffer_t *ring{nullptr}; + RingBufferPtr ring{nullptr}; std::atomic mKillNow{AL_TRUE}; std::thread mThread; @@ -316,9 +316,6 @@ static void SndioCapture_Destruct(SndioCapture *self) sio_close(self->sndHandle); self->sndHandle = nullptr; - ll_ringbuffer_free(self->ring); - self->ring = nullptr; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~SndioCapture(); } @@ -339,7 +336,7 @@ static int SndioCapture_recordProc(SndioCapture *self) { size_t total, todo; - auto data = ll_ringbuffer_get_write_vector(self->ring); + auto data = ll_ringbuffer_get_write_vector(self->ring.get()); todo = data.first.len + data.second.len; if(todo == 0) { @@ -372,7 +369,7 @@ static int SndioCapture_recordProc(SndioCapture *self) data.first.len -= got; total += got; } - ll_ringbuffer_write_advance(self->ring, total / frameSize); + ll_ringbuffer_write_advance(self->ring.get(), total / frameSize); } return 0; @@ -468,7 +465,8 @@ static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) return ALC_INVALID_VALUE; } - self->ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, par.bps*par.rchan, 0); + self->ring.reset(ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, + par.bps*par.rchan, false)); if(!self->ring) { ERR("Failed to allocate %u-byte ringbuffer\n", @@ -516,13 +514,13 @@ static void SndioCapture_stop(SndioCapture *self) static ALCenum SndioCapture_captureSamples(SndioCapture *self, void *buffer, ALCuint samples) { - ll_ringbuffer_read(self->ring, static_cast(buffer), samples); + ll_ringbuffer_read(self->ring.get(), static_cast(buffer), samples); return ALC_NO_ERROR; } static ALCuint SndioCapture_availableSamples(SndioCapture *self) { - return ll_ringbuffer_read_space(self->ring); + return ll_ringbuffer_read_space(self->ring.get()); } diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 79e4af04..3f8cad23 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -1172,7 +1172,7 @@ struct ALCwasapiCapture final : public ALCbackend, WasapiProxy { ChannelConverter *mChannelConv{nullptr}; SampleConverter *mSampleConv{nullptr}; - ll_ringbuffer_t *mRing{nullptr}; + RingBufferPtr mRing{nullptr}; std::atomic mKillNow{AL_TRUE}; std::thread mThread; @@ -1220,9 +1220,6 @@ void ALCwasapiCapture_Destruct(ALCwasapiCapture *self) CloseHandle(self->mNotifyEvent); self->mNotifyEvent = nullptr; - ll_ringbuffer_free(self->mRing); - self->mRing = nullptr; - DestroySampleConverter(&self->mSampleConv); DestroyChannelConverter(&self->mChannelConv); @@ -1275,7 +1272,7 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) rdata = reinterpret_cast(samples.data()); } - auto data = ll_ringbuffer_get_write_vector(self->mRing); + auto data = ll_ringbuffer_get_write_vector(self->mRing.get()); size_t dstframes; if(self->mSampleConv) @@ -1311,7 +1308,7 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) dstframes = len1 + len2; } - ll_ringbuffer_write_advance(self->mRing, dstframes); + ll_ringbuffer_write_advance(self->mRing.get(), dstframes); hr = capture->ReleaseBuffer(numsamples); if(FAILED(hr)) ERR("Failed to release capture buffer: 0x%08lx\n", hr); @@ -1696,8 +1693,7 @@ HRESULT ALCwasapiCapture::resetProxy() } buffer_len = maxu(device->UpdateSize*device->NumUpdates, buffer_len); - ll_ringbuffer_free(mRing); - mRing = ll_ringbuffer_create(buffer_len, device->frameSizeFromFmt(), false); + mRing.reset(ll_ringbuffer_create(buffer_len, device->frameSizeFromFmt(), false)); if(!mRing) { ERR("Failed to allocate capture ring buffer\n"); @@ -1790,14 +1786,12 @@ void ALCwasapiCapture::stopProxy() ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self) { - return (ALuint)ll_ringbuffer_read_space(self->mRing); + return (ALuint)ll_ringbuffer_read_space(self->mRing.get()); } ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, ALCuint samples) { - if(ALCwasapiCapture_availableSamples(self) < samples) - return ALC_INVALID_VALUE; - ll_ringbuffer_read(self->mRing, reinterpret_cast(buffer), samples); + ll_ringbuffer_read(self->mRing.get(), reinterpret_cast(buffer), samples); return ALC_NO_ERROR; } diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 362b2e5e..38766869 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -401,7 +401,7 @@ struct ALCwinmmCapture final : public ALCbackend { HWAVEIN InHdl{nullptr}; - ll_ringbuffer_t *Ring{nullptr}; + RingBufferPtr Ring{nullptr}; WAVEFORMATEX Format{}; @@ -448,9 +448,6 @@ void ALCwinmmCapture_Destruct(ALCwinmmCapture *self) al_free(self->WaveBuffer[0].lpData); std::fill(self->WaveBuffer.begin(), self->WaveBuffer.end(), WAVEHDR{}); - ll_ringbuffer_free(self->Ring); - self->Ring = nullptr; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCwinmmCapture(); } @@ -497,7 +494,7 @@ int ALCwinmmCapture_captureProc(ALCwinmmCapture *self) WAVEHDR &waveHdr = self->WaveBuffer[widx]; widx = (widx+1) % self->WaveBuffer.size(); - ll_ringbuffer_write(self->Ring, waveHdr.lpData, + ll_ringbuffer_write(self->Ring.get(), waveHdr.lpData, waveHdr.dwBytesRecorded / self->Format.nBlockAlign ); self->Readable.fetch_sub(1, std::memory_order_acq_rel); @@ -585,7 +582,7 @@ ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName) std::max(device->UpdateSize*device->NumUpdates, BufferSize*self->WaveBuffer.size()) ); - self->Ring = ll_ringbuffer_create(CapturedDataSize, self->Format.nBlockAlign, false); + self->Ring.reset(ll_ringbuffer_create(CapturedDataSize, self->Format.nBlockAlign, false)); if(!self->Ring) return ALC_INVALID_VALUE; al_free(self->WaveBuffer[0].lpData); @@ -648,13 +645,13 @@ void ALCwinmmCapture_stop(ALCwinmmCapture *self) ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples) { - ll_ringbuffer_read(self->Ring, buffer, samples); + ll_ringbuffer_read(self->Ring.get(), buffer, samples); return ALC_NO_ERROR; } ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self) { - return (ALCuint)ll_ringbuffer_read_space(self->Ring); + return (ALCuint)ll_ringbuffer_read_space(self->Ring.get()); } } // namespace diff --git a/Alc/ringbuffer.cpp b/Alc/ringbuffer.cpp index 5ee2616f..a298ff43 100644 --- a/Alc/ringbuffer.cpp +++ b/Alc/ringbuffer.cpp @@ -31,25 +31,9 @@ #include "compat.h" -/* NOTE: This lockless ringbuffer implementation is copied from JACK, extended - * to include an element size. Consequently, parameters and return values for a - * size or count is in 'elements', not bytes. Additionally, it only supports - * single-consumer/single-provider operation. */ -struct ll_ringbuffer { - std::atomic write_ptr{0u}; - std::atomic read_ptr{0u}; - size_t size{0u}; - size_t size_mask{0u}; - size_t elem_size{0u}; - - alignas(16) char buf[]; - - DEF_PLACE_NEWDEL() -}; - -ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes) +ll_ringbuffer *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes) { - ll_ringbuffer_t *rb; + ll_ringbuffer *rb; size_t power_of_two = 0; if(sz > 0) @@ -75,12 +59,7 @@ ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_write return rb; } -void ll_ringbuffer_free(ll_ringbuffer_t *rb) -{ - delete rb; -} - -void ll_ringbuffer_reset(ll_ringbuffer_t *rb) +void ll_ringbuffer_reset(ll_ringbuffer *rb) { rb->write_ptr.store(0, std::memory_order_relaxed); rb->read_ptr.store(0, std::memory_order_relaxed); @@ -88,14 +67,14 @@ void ll_ringbuffer_reset(ll_ringbuffer_t *rb) } -size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb) +size_t ll_ringbuffer_read_space(const ll_ringbuffer *rb) { size_t w = rb->write_ptr.load(std::memory_order_acquire); size_t r = rb->read_ptr.load(std::memory_order_acquire); return (w-r) & rb->size_mask; } -size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb) +size_t ll_ringbuffer_write_space(const ll_ringbuffer *rb) { size_t w = rb->write_ptr.load(std::memory_order_acquire); size_t r = rb->read_ptr.load(std::memory_order_acquire); @@ -104,7 +83,7 @@ size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb) } -size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, void *dest, size_t cnt) +size_t ll_ringbuffer_read(ll_ringbuffer *rb, void *dest, size_t cnt) { size_t read_ptr; size_t free_cnt; @@ -143,7 +122,7 @@ size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, void *dest, size_t cnt) return to_read; } -size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, void *dest, size_t cnt) +size_t ll_ringbuffer_peek(ll_ringbuffer *rb, void *dest, size_t cnt) { size_t free_cnt; size_t cnt2; @@ -180,7 +159,7 @@ size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, void *dest, size_t cnt) return to_read; } -size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const void *src, size_t cnt) +size_t ll_ringbuffer_write(ll_ringbuffer *rb, const void *src, size_t cnt) { size_t write_ptr; size_t free_cnt; @@ -220,18 +199,18 @@ size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const void *src, size_t cnt) } -void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt) +void ll_ringbuffer_read_advance(ll_ringbuffer *rb, size_t cnt) { rb->read_ptr.fetch_add(cnt, std::memory_order_acq_rel); } -void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt) +void ll_ringbuffer_write_advance(ll_ringbuffer *rb, size_t cnt) { rb->write_ptr.fetch_add(cnt, std::memory_order_acq_rel); } -ll_ringbuffer_data_pair ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb) +ll_ringbuffer_data_pair ll_ringbuffer_get_read_vector(const ll_ringbuffer *rb) { ll_ringbuffer_data_pair ret; size_t free_cnt; @@ -265,7 +244,7 @@ ll_ringbuffer_data_pair ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb) return ret; } -ll_ringbuffer_data_pair ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb) +ll_ringbuffer_data_pair ll_ringbuffer_get_write_vector(const ll_ringbuffer *rb) { ll_ringbuffer_data_pair ret; size_t free_cnt; diff --git a/Alc/ringbuffer.h b/Alc/ringbuffer.h index cb2077f8..5111023e 100644 --- a/Alc/ringbuffer.h +++ b/Alc/ringbuffer.h @@ -3,19 +3,36 @@ #include +#include #include #include +#include "almalloc.h" + + +/* NOTE: This lockless ringbuffer implementation is copied from JACK, extended + * to include an element size. Consequently, parameters and return values for a + * size or count is in 'elements', not bytes. Additionally, it only supports + * single-consumer/single-provider operation. + */ +struct ll_ringbuffer { + std::atomic write_ptr{0u}; + std::atomic read_ptr{0u}; + size_t size{0u}; + size_t size_mask{0u}; + size_t elem_size{0u}; + + alignas(16) char buf[]; + + DEF_PLACE_NEWDEL() +}; -struct ll_ringbuffer; -using ll_ringbuffer_t = struct ll_ringbuffer; struct ll_ringbuffer_data { char *buf; size_t len; }; using ll_ringbuffer_data_pair = std::pair; -using ll_ringbuffer_data_t = struct ll_ringbuffer_data; /** @@ -23,61 +40,55 @@ using ll_ringbuffer_data_t = struct ll_ringbuffer_data; * The number of elements is rounded up to the next power of two (even if it is * already a power of two, to ensure the requested amount can be written). */ -ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes); -/** Free all data associated with the ringbuffer `rb'. */ -void ll_ringbuffer_free(ll_ringbuffer_t *rb); +ll_ringbuffer *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes); /** Reset the read and write pointers to zero. This is not thread safe. */ -void ll_ringbuffer_reset(ll_ringbuffer_t *rb); +void ll_ringbuffer_reset(ll_ringbuffer *rb); /** * The non-copying data reader. Returns two ringbuffer data pointers that hold * the current readable data at `rb'. If the readable data is in one segment * the second segment has zero length. */ -ll_ringbuffer_data_pair ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb); +ll_ringbuffer_data_pair ll_ringbuffer_get_read_vector(const ll_ringbuffer *rb); /** * The non-copying data writer. Returns two ringbuffer data pointers that hold * the current writeable data at `rb'. If the writeable data is in one segment * the second segment has zero length. */ -ll_ringbuffer_data_pair ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb); +ll_ringbuffer_data_pair ll_ringbuffer_get_write_vector(const ll_ringbuffer *rb); /** * Return the number of elements available for reading. This is the number of * elements in front of the read pointer and behind the write pointer. */ -size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb); +size_t ll_ringbuffer_read_space(const ll_ringbuffer *rb); /** * The copying data reader. Copy at most `cnt' elements from `rb' to `dest'. * Returns the actual number of elements copied. */ -size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, void *dest, size_t cnt); +size_t ll_ringbuffer_read(ll_ringbuffer *rb, void *dest, size_t cnt); /** * The copying data reader w/o read pointer advance. Copy at most `cnt' * elements from `rb' to `dest'. Returns the actual number of elements copied. */ -size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, void *dest, size_t cnt); +size_t ll_ringbuffer_peek(ll_ringbuffer *rb, void *dest, size_t cnt); /** Advance the read pointer `cnt' places. */ -void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt); +void ll_ringbuffer_read_advance(ll_ringbuffer *rb, size_t cnt); /** * Return the number of elements available for writing. This is the number of * elements in front of the write pointer and behind the read pointer. */ -size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb); +size_t ll_ringbuffer_write_space(const ll_ringbuffer *rb); /** * The copying data writer. Copy at most `cnt' elements to `rb' from `src'. * Returns the actual number of elements copied. */ -size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const void *src, size_t cnt); +size_t ll_ringbuffer_write(ll_ringbuffer *rb, const void *src, size_t cnt); /** Advance the write pointer `cnt' places. */ -void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt); +void ll_ringbuffer_write_advance(ll_ringbuffer *rb, size_t cnt); -struct RingBufferDeleter { - void operator()(ll_ringbuffer_t *ring) const - { ll_ringbuffer_free(ring); } -}; -using RingBufferPtr = std::unique_ptr; +using RingBufferPtr = std::unique_ptr; #endif /* RINGBUFFER_H */ -- cgit v1.2.3 From d4d98e2fe9820f390515baf581dea7dc9bec1431 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 22 Dec 2018 11:41:03 -0800 Subject: Fix for C++11 compatibility std::array::operator[] isn't constexpr until C++14. --- Alc/alu.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index be0bafbf..a2c930fc 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -667,10 +667,10 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev * matrix is transposed, for the inputs to align on the rows and * outputs on the columns. */ - static constexpr ALfloat scale0{AmbiScale::FromFuMa[0]}; - static constexpr ALfloat scale1{AmbiScale::FromFuMa[1]}; - static constexpr ALfloat scale2{AmbiScale::FromFuMa[2]}; - static constexpr ALfloat scale3{AmbiScale::FromFuMa[3]}; + static const ALfloat scale0{AmbiScale::FromFuMa[0]}; + static const ALfloat scale1{AmbiScale::FromFuMa[1]}; + static const ALfloat scale2{AmbiScale::FromFuMa[2]}; + static const ALfloat scale3{AmbiScale::FromFuMa[3]}; const alu::Matrix matrix{ // ACN0 ACN1 ACN2 ACN3 scale0, 0.0f, 0.0f, 0.0f, // Ambi W -- cgit v1.2.3 From 334b3a905a1a387d5fb5f74483a7520bb5d5449a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 22 Dec 2018 16:01:14 -0800 Subject: Clean up some math stuff --- Alc/alu.cpp | 65 ++++++++++++++++++++++++------------------------ Alc/filters/splitter.cpp | 5 ++-- Alc/mastering.cpp | 3 ++- Alc/mixer/mixer_c.cpp | 4 ++- Alc/mixer/mixer_neon.cpp | 4 ++- Alc/mixer/mixer_sse.cpp | 4 ++- OpenAL32/Include/alu.h | 35 +++++++++++++------------- OpenAL32/alSource.cpp | 4 +-- common/math_defs.h | 23 ++--------------- common/vecmat.h | 3 ++- 10 files changed, 70 insertions(+), 80 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index a2c930fc..a6e53f4b 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include "alMain.h" @@ -437,37 +438,37 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) constexpr struct ChanMap MonoMap[1]{ { FrontCenter, 0.0f, 0.0f } }, RearMap[2]{ - { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) }, - { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) } + { BackLeft, Deg2Rad(-150.0f), Deg2Rad(0.0f) }, + { BackRight, Deg2Rad( 150.0f), Deg2Rad(0.0f) } }, QuadMap[4]{ - { FrontLeft, DEG2RAD( -45.0f), DEG2RAD(0.0f) }, - { FrontRight, DEG2RAD( 45.0f), DEG2RAD(0.0f) }, - { BackLeft, DEG2RAD(-135.0f), DEG2RAD(0.0f) }, - { BackRight, DEG2RAD( 135.0f), DEG2RAD(0.0f) } + { FrontLeft, Deg2Rad( -45.0f), Deg2Rad(0.0f) }, + { FrontRight, Deg2Rad( 45.0f), Deg2Rad(0.0f) }, + { BackLeft, Deg2Rad(-135.0f), Deg2Rad(0.0f) }, + { BackRight, Deg2Rad( 135.0f), Deg2Rad(0.0f) } }, X51Map[6]{ - { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) }, - { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, - { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, + { FrontLeft, Deg2Rad( -30.0f), Deg2Rad(0.0f) }, + { FrontRight, Deg2Rad( 30.0f), Deg2Rad(0.0f) }, + { FrontCenter, Deg2Rad( 0.0f), Deg2Rad(0.0f) }, { LFE, 0.0f, 0.0f }, - { SideLeft, DEG2RAD(-110.0f), DEG2RAD(0.0f) }, - { SideRight, DEG2RAD( 110.0f), DEG2RAD(0.0f) } + { SideLeft, Deg2Rad(-110.0f), Deg2Rad(0.0f) }, + { SideRight, Deg2Rad( 110.0f), Deg2Rad(0.0f) } }, X61Map[7]{ - { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, - { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, - { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, + { FrontLeft, Deg2Rad(-30.0f), Deg2Rad(0.0f) }, + { FrontRight, Deg2Rad( 30.0f), Deg2Rad(0.0f) }, + { FrontCenter, Deg2Rad( 0.0f), Deg2Rad(0.0f) }, { LFE, 0.0f, 0.0f }, - { BackCenter, DEG2RAD(180.0f), DEG2RAD(0.0f) }, - { SideLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) }, - { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } + { BackCenter, Deg2Rad(180.0f), Deg2Rad(0.0f) }, + { SideLeft, Deg2Rad(-90.0f), Deg2Rad(0.0f) }, + { SideRight, Deg2Rad( 90.0f), Deg2Rad(0.0f) } }, X71Map[8]{ - { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) }, - { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, - { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, + { FrontLeft, Deg2Rad( -30.0f), Deg2Rad(0.0f) }, + { FrontRight, Deg2Rad( 30.0f), Deg2Rad(0.0f) }, + { FrontCenter, Deg2Rad( 0.0f), Deg2Rad(0.0f) }, { LFE, 0.0f, 0.0f }, - { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) }, - { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) }, - { SideLeft, DEG2RAD( -90.0f), DEG2RAD(0.0f) }, - { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } + { BackLeft, Deg2Rad(-150.0f), Deg2Rad(0.0f) }, + { BackRight, Deg2Rad( 150.0f), Deg2Rad(0.0f) }, + { SideLeft, Deg2Rad( -90.0f), Deg2Rad(0.0f) }, + { SideRight, Deg2Rad( 90.0f), Deg2Rad(0.0f) } }; void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev, @@ -480,8 +481,8 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev const ALCdevice *Device) { ChanMap StereoMap[2]{ - { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, - { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) } + { FrontLeft, Deg2Rad(-30.0f), Deg2Rad(0.0f) }, + { FrontRight, Deg2Rad( 30.0f), Deg2Rad(0.0f) } }; bool DirectChannels{props->DirectChannels != AL_FALSE}; @@ -576,7 +577,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev { /* Special handling for B-Format sources. */ - if(Distance > FLT_EPSILON) + if(Distance > std::numeric_limits::epsilon()) { /* Panning a B-Format sound toward some direction is easy. Just pan * the first (W) channel as a normal mono sound and silence the @@ -733,7 +734,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev voice->Direct.Buffer = Device->RealOut.Buffer; voice->Direct.Channels = Device->RealOut.NumChannels; - if(Distance > FLT_EPSILON) + if(Distance > std::numeric_limits::epsilon()) { /* Get the HRIR coefficients and delays just once, for the given * source direction. @@ -811,7 +812,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev { /* Non-HRTF rendering. Use normal panning to the output. */ - if(Distance > FLT_EPSILON) + if(Distance > std::numeric_limits::epsilon()) { /* Calculate NFC filter coefficient if needed. */ if(Device->AvgSpeakerDist > 0.0f) @@ -1206,8 +1207,8 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A /* Calculate directional soundcones */ if(directional && props->InnerAngle < 360.0f) { - ALfloat Angle{std::acos(aluDotproduct(Direction, SourceToListener))}; - Angle = RAD2DEG(Angle * ConeScale * 2.0f); + const ALfloat Angle{Rad2Deg(std::acos(aluDotproduct(Direction, SourceToListener)) * + ConeScale * 2.0f)}; ALfloat ConeVolume, ConeHF; if(!(Angle > props->InnerAngle)) @@ -1322,7 +1323,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A /* Source moving toward the listener at the speed of sound. Sound * waves bunch up to extreme frequencies. */ - Pitch = HUGE_VALF; + Pitch = std::numeric_limits::infinity(); } else { diff --git a/Alc/filters/splitter.cpp b/Alc/filters/splitter.cpp index 18518dbb..27ea697a 100644 --- a/Alc/filters/splitter.cpp +++ b/Alc/filters/splitter.cpp @@ -4,6 +4,7 @@ #include "splitter.h" #include +#include #include #include "math_defs.h" @@ -13,7 +14,7 @@ void BandSplitter::init(float f0norm) { float w = f0norm * F_TAU; float cw = std::cos(w); - if(cw > FLT_EPSILON) + if(cw > std::numeric_limits::epsilon()) coeff = (std::sin(w) - 1.0f) / cw; else coeff = cw * -0.5f; @@ -63,7 +64,7 @@ void SplitterAllpass::init(float f0norm) { float w = f0norm * F_TAU; float cw = std::cos(w); - if(cw > FLT_EPSILON) + if(cw > std::numeric_limits::epsilon()) coeff = (std::sin(w) - 1.0f) / cw; else coeff = cw * -0.5f; diff --git a/Alc/mastering.cpp b/Alc/mastering.cpp index 91ea207b..bdd67aa4 100644 --- a/Alc/mastering.cpp +++ b/Alc/mastering.cpp @@ -1,6 +1,7 @@ #include "config.h" #include +#include #include #include @@ -395,7 +396,7 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, if(hold > 1) { Comp->Hold = new ((void*)(Comp + 1)) SlidingHold{}; - Comp->Hold->Values[0] = -HUGE_VALF; + Comp->Hold->Values[0] = -std::numeric_limits::infinity(); Comp->Hold->Expiries[0] = hold; Comp->Hold->Length = hold; Comp->Delay = (ALfloat(*)[BUFFERSIZE])(Comp->Hold + 1); diff --git a/Alc/mixer/mixer_c.cpp b/Alc/mixer/mixer_c.cpp index 99d3e343..7a2a6319 100644 --- a/Alc/mixer/mixer_c.cpp +++ b/Alc/mixer/mixer_c.cpp @@ -2,6 +2,8 @@ #include +#include + #include "alMain.h" #include "alu.h" #include "alSource.h" @@ -137,7 +139,7 @@ void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*RESTRICT OutBuffer)[ ALfloat gain = CurrentGains[c]; const ALfloat diff = TargetGains[c] - gain; - if(fabsf(diff) > FLT_EPSILON) + if(fabsf(diff) > std::numeric_limits::epsilon()) { ALsizei minsize = mini(BufferSize, Counter); const ALfloat step = diff * delta; diff --git a/Alc/mixer/mixer_neon.cpp b/Alc/mixer/mixer_neon.cpp index f7fe57d1..fa777eac 100644 --- a/Alc/mixer/mixer_neon.cpp +++ b/Alc/mixer/mixer_neon.cpp @@ -2,6 +2,8 @@ #include +#include + #include "AL/al.h" #include "AL/alc.h" #include "alMain.h" @@ -182,7 +184,7 @@ void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*RESTRICT OutBuffe ALfloat gain = CurrentGains[c]; const ALfloat diff = TargetGains[c] - gain; - if(fabsf(diff) > FLT_EPSILON) + if(fabsf(diff) > std::numeric_limits::epsilon()) { ALsizei minsize = mini(BufferSize, Counter); const ALfloat step = diff * delta; diff --git a/Alc/mixer/mixer_sse.cpp b/Alc/mixer/mixer_sse.cpp index 000196ca..f0620cb5 100644 --- a/Alc/mixer/mixer_sse.cpp +++ b/Alc/mixer/mixer_sse.cpp @@ -2,6 +2,8 @@ #include +#include + #include "AL/al.h" #include "AL/alc.h" #include "alMain.h" @@ -151,7 +153,7 @@ void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*RESTRICT OutBuffer ALfloat gain = CurrentGains[c]; const ALfloat diff = TargetGains[c] - gain; - if(fabsf(diff) > FLT_EPSILON) + if(fabsf(diff) > std::numeric_limits::epsilon()) { ALsizei minsize = mini(BufferSize, Counter); const ALfloat step = diff * delta; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 1b5c274d..2b7be726 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -10,6 +10,7 @@ #include #endif +#include #include #include "alMain.h" @@ -106,15 +107,15 @@ enum { }; -typedef struct MixHrtfParams { +struct MixHrtfParams { const ALfloat (*Coeffs)[2]; ALsizei Delay[2]; ALfloat Gain; ALfloat GainStep; -} MixHrtfParams; +}; -typedef struct DirectParams { +struct DirectParams { BiquadFilter LowPass; BiquadFilter HighPass; @@ -130,9 +131,9 @@ typedef struct DirectParams { ALfloat Current[MAX_OUTPUT_CHANNELS]; ALfloat Target[MAX_OUTPUT_CHANNELS]; } Gains; -} DirectParams; +}; -typedef struct SendParams { +struct SendParams { BiquadFilter LowPass; BiquadFilter HighPass; @@ -140,7 +141,7 @@ typedef struct SendParams { ALfloat Current[MAX_OUTPUT_CHANNELS]; ALfloat Target[MAX_OUTPUT_CHANNELS]; } Gains; -} SendParams; +}; struct ALvoicePropsBase { @@ -359,9 +360,7 @@ inline size_t clampz(size_t val, size_t min, size_t max) noexcept inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu) noexcept -{ - return val1 + (val2-val1)*mu; -} +{ return val1 + (val2-val1)*mu; } inline ALfloat cubic(ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat mu) noexcept { ALfloat mu2 = mu*mu, mu3 = mu2*mu; @@ -383,16 +382,16 @@ void aluInit(void); void aluInitMixer(void); -ResamplerFunc SelectResampler(enum Resampler resampler); +ResamplerFunc SelectResampler(Resampler resampler); /* aluInitRenderer * * Set up the appropriate panning method and mixing method given the device * properties. */ -void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq); +void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appreq, HrtfRequestMode hrtf_userreq); -void aluInitEffectPanning(struct ALeffectslot *slot); +void aluInitEffectPanning(ALeffectslot *slot); void aluSelectPostProcess(ALCdevice *device); @@ -435,9 +434,9 @@ inline void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat (& */ inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat (&coeffs)[MAX_AMBI_COEFFS]) { - ALfloat x = -sinf(azimuth) * cosf(elevation); - ALfloat y = sinf(elevation); - ALfloat z = cosf(azimuth) * cosf(elevation); + ALfloat x = -std::sin(azimuth) * std::cos(elevation); + ALfloat y = std::sin(elevation); + ALfloat z = std::cos(azimuth) * std::cos(elevation); CalcAmbiCoeffs(x, y, z, spread, coeffs); } @@ -450,9 +449,9 @@ inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, */ inline float ScaleAzimuthFront(float azimuth, float scale) { - ALfloat sign = copysignf(1.0f, azimuth); - if(!(fabsf(azimuth) > F_PI_2)) - return minf(fabsf(azimuth) * scale, F_PI_2) * sign; + ALfloat sign = std::copysign(1.0f, azimuth); + if(!(std::fabs(azimuth) > F_PI_2)) + return minf(std::fabs(azimuth) * scale, F_PI_2) * sign; return azimuth; } diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 3697b232..53aa9389 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -3335,8 +3335,8 @@ ALsource::ALsource(ALsizei num_sends) DirectChannels = AL_FALSE; Spatialize = SpatializeAuto; - StereoPan[0] = DEG2RAD( 30.0f); - StereoPan[1] = DEG2RAD(-30.0f); + StereoPan[0] = Deg2Rad( 30.0f); + StereoPan[1] = Deg2Rad(-30.0f); Radius = 0.0f; diff --git a/common/math_defs.h b/common/math_defs.h index 513570f0..4686e96b 100644 --- a/common/math_defs.h +++ b/common/math_defs.h @@ -2,9 +2,6 @@ #define AL_MATH_DEFS_H #include -#ifdef HAVE_FLOAT_H -#include -#endif #ifndef M_PI #define M_PI (3.14159265358979323846) @@ -14,25 +11,9 @@ #define F_PI_2 (1.57079632679489661923f) #define F_TAU (6.28318530717958647692f) -#ifndef FLT_EPSILON -#define FLT_EPSILON (1.19209290e-07f) -#endif - -#define SQRT_2 1.41421356237309504880 -#define SQRT_3 1.73205080756887719318 - -#define SQRTF_2 1.41421356237309504880f #define SQRTF_3 1.73205080756887719318f -#ifndef HUGE_VALF -static const union msvc_inf_hack { - unsigned char b[4]; - float f; -} msvc_inf_union = {{ 0x00, 0x00, 0x80, 0x7F }}; -#define HUGE_VALF (msvc_inf_union.f) -#endif - -#define DEG2RAD(x) ((float)(x) * (float)(M_PI/180.0)) -#define RAD2DEG(x) ((float)(x) * (float)(180.0/M_PI)) +constexpr inline float Deg2Rad(float x) noexcept { return x * float{M_PI/180.0}; } +constexpr inline float Rad2Deg(float x) noexcept { return x * float{180.0/M_PI}; } #endif /* AL_MATH_DEFS_H */ diff --git a/common/vecmat.h b/common/vecmat.h index 1ecc4b7c..ab407b15 100644 --- a/common/vecmat.h +++ b/common/vecmat.h @@ -3,6 +3,7 @@ #include #include +#include #include #include "math_defs.h" @@ -41,7 +42,7 @@ public: float normalize() { const float length{std::sqrt(mVals[0]*mVals[0] + mVals[1]*mVals[1] + mVals[2]*mVals[2])}; - if(length > FLT_EPSILON) + if(length > std::numeric_limits::epsilon()) { float inv_length = 1.0f/length; mVals[0] *= inv_length; -- cgit v1.2.3 From 86caf2683e77098d4e9855ef2eaab88b9f90df60 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 22 Dec 2018 18:43:34 -0800 Subject: Constify a parameter --- Alc/effects/autowah.cpp | 4 ++-- Alc/effects/chorus.cpp | 4 ++-- Alc/effects/compressor.cpp | 4 ++-- Alc/effects/dedicated.cpp | 4 ++-- Alc/effects/distortion.cpp | 4 ++-- Alc/effects/echo.cpp | 4 ++-- Alc/effects/equalizer.cpp | 4 ++-- Alc/effects/fshifter.cpp | 4 ++-- Alc/effects/modulator.cpp | 4 ++-- Alc/effects/null.cpp | 4 ++-- Alc/effects/pshifter.cpp | 4 ++-- Alc/effects/reverb.cpp | 4 ++-- OpenAL32/Include/alAuxEffectSlot.h | 2 +- 13 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Alc/effects/autowah.cpp b/Alc/effects/autowah.cpp index 19c247a9..e034c610 100644 --- a/Alc/effects/autowah.cpp +++ b/Alc/effects/autowah.cpp @@ -68,14 +68,14 @@ struct ALautowahState final : public EffectState { alignas(16) ALfloat mBufferOut[BUFFERSIZE]; - ALboolean deviceUpdate(ALCdevice *device) override; + ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ALautowahState) }; -ALboolean ALautowahState::deviceUpdate(ALCdevice *UNUSED(device)) +ALboolean ALautowahState::deviceUpdate(const ALCdevice *UNUSED(device)) { /* (Re-)initializing parameters and clear the buffers. */ diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp index e0878eb0..925cd09f 100644 --- a/Alc/effects/chorus.cpp +++ b/Alc/effects/chorus.cpp @@ -90,14 +90,14 @@ struct ChorusState final : public EffectState { ALfloat mFeedback{0.0f}; - ALboolean deviceUpdate(ALCdevice *device) override; + ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ChorusState) }; -ALboolean ChorusState::deviceUpdate(ALCdevice *Device) +ALboolean ChorusState::deviceUpdate(const ALCdevice *Device) { const ALfloat max_delay = maxf(AL_CHORUS_MAX_DELAY, AL_FLANGER_MAX_DELAY); size_t maxlen; diff --git a/Alc/effects/compressor.cpp b/Alc/effects/compressor.cpp index 31210264..d502be43 100644 --- a/Alc/effects/compressor.cpp +++ b/Alc/effects/compressor.cpp @@ -48,14 +48,14 @@ struct ALcompressorState final : public EffectState { ALfloat mEnvFollower{1.0f}; - ALboolean deviceUpdate(ALCdevice *device) override; + ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ALcompressorState) }; -ALboolean ALcompressorState::deviceUpdate(ALCdevice *device) +ALboolean ALcompressorState::deviceUpdate(const ALCdevice *device) { /* Number of samples to do a full attack and release (non-integer sample * counts are okay). diff --git a/Alc/effects/dedicated.cpp b/Alc/effects/dedicated.cpp index c0af33e1..fa550397 100644 --- a/Alc/effects/dedicated.cpp +++ b/Alc/effects/dedicated.cpp @@ -36,14 +36,14 @@ struct ALdedicatedState final : public EffectState { ALfloat mTargetGains[MAX_OUTPUT_CHANNELS]; - ALboolean deviceUpdate(ALCdevice *device) override; + ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ALdedicatedState) }; -ALboolean ALdedicatedState::deviceUpdate(ALCdevice *UNUSED(device)) +ALboolean ALdedicatedState::deviceUpdate(const ALCdevice *UNUSED(device)) { std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f); return AL_TRUE; diff --git a/Alc/effects/distortion.cpp b/Alc/effects/distortion.cpp index b3d339ad..58d05e8f 100644 --- a/Alc/effects/distortion.cpp +++ b/Alc/effects/distortion.cpp @@ -44,14 +44,14 @@ struct ALdistortionState final : public EffectState { ALfloat mBuffer[2][BUFFERSIZE]{}; - ALboolean deviceUpdate(ALCdevice *device) override; + ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ALdistortionState) }; -ALboolean ALdistortionState::deviceUpdate(ALCdevice *UNUSED(device)) +ALboolean ALdistortionState::deviceUpdate(const ALCdevice *UNUSED(device)) { mLowpass.clear(); mBandpass.clear(); diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index 3604bed4..b9310193 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -56,14 +56,14 @@ struct ALechoState final : public EffectState { BiquadFilter mFilter; - ALboolean deviceUpdate(ALCdevice *device) override; + ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ALechoState) }; -ALboolean ALechoState::deviceUpdate(ALCdevice *Device) +ALboolean ALechoState::deviceUpdate(const ALCdevice *Device) { ALuint maxlen; diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index 2c46c2f3..a10316e8 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -90,14 +90,14 @@ struct ALequalizerState final : public EffectState { ALfloat mSampleBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE]{}; - ALboolean deviceUpdate(ALCdevice *device) override; + ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ALequalizerState) }; -ALboolean ALequalizerState::deviceUpdate(ALCdevice *UNUSED(device)) +ALboolean ALequalizerState::deviceUpdate(const ALCdevice *UNUSED(device)) { for(auto &e : mChans) { diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp index 38fb5492..9b6d700c 100644 --- a/Alc/effects/fshifter.cpp +++ b/Alc/effects/fshifter.cpp @@ -81,14 +81,14 @@ struct ALfshifterState final : public EffectState { ALfloat mTargetGains[MAX_OUTPUT_CHANNELS]{}; - ALboolean deviceUpdate(ALCdevice *device) override; + ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ALfshifterState) }; -ALboolean ALfshifterState::deviceUpdate(ALCdevice *UNUSED(device)) +ALboolean ALfshifterState::deviceUpdate(const ALCdevice *UNUSED(device)) { /* (Re-)initializing parameters and clear the buffers. */ mCount = FIFO_LATENCY; diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index bf584898..d686c362 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -88,14 +88,14 @@ struct ALmodulatorState final : public EffectState { } mChans[MAX_EFFECT_CHANNELS]; - ALboolean deviceUpdate(ALCdevice *device) override; + ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ALmodulatorState) }; -ALboolean ALmodulatorState::deviceUpdate(ALCdevice *UNUSED(device)) +ALboolean ALmodulatorState::deviceUpdate(const ALCdevice *UNUSED(device)) { for(auto &e : mChans) { diff --git a/Alc/effects/null.cpp b/Alc/effects/null.cpp index d28a6889..ba591565 100644 --- a/Alc/effects/null.cpp +++ b/Alc/effects/null.cpp @@ -15,7 +15,7 @@ struct ALnullState final : public EffectState { ALnullState(); ~ALnullState() override; - ALboolean deviceUpdate(ALCdevice *device) override; + ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; @@ -40,7 +40,7 @@ ALnullState::~ALnullState() * initialization and any time the device parameters (eg. playback frequency, * format) have been changed. */ -ALboolean ALnullState::deviceUpdate(ALCdevice* UNUSED(device)) +ALboolean ALnullState::deviceUpdate(const ALCdevice* UNUSED(device)) { return AL_TRUE; } diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp index 3c375499..3825bfd5 100644 --- a/Alc/effects/pshifter.cpp +++ b/Alc/effects/pshifter.cpp @@ -143,14 +143,14 @@ struct ALpshifterState final : public EffectState { ALfloat mTargetGains[MAX_OUTPUT_CHANNELS]; - ALboolean deviceUpdate(ALCdevice *device) override; + ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ALpshifterState) }; -ALboolean ALpshifterState::deviceUpdate(ALCdevice *device) +ALboolean ALpshifterState::deviceUpdate(const ALCdevice *device) { /* (Re-)initializing parameters and clear the buffers. */ mCount = FIFO_LATENCY; diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 67945b27..cc0f3fb0 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -338,7 +338,7 @@ struct ReverbState final : public EffectState { alignas(16) ALfloat mMixBuffer[NUM_LINES][MAX_UPDATE_SAMPLES]{}; - ALboolean deviceUpdate(ALCdevice *device) override; + ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; @@ -456,7 +456,7 @@ static ALboolean AllocLines(const ALuint frequency, ReverbState *State) return AL_TRUE; } -ALboolean ReverbState::deviceUpdate(ALCdevice *Device) +ALboolean ReverbState::deviceUpdate(const ALCdevice *Device) { const ALuint frequency{Device->Frequency}; diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 586fc507..539cee53 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -20,7 +20,7 @@ struct EffectState { virtual ~EffectState() = default; - virtual ALboolean deviceUpdate(ALCdevice *device) = 0; + virtual ALboolean deviceUpdate(const ALCdevice *device) = 0; virtual void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) = 0; virtual void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) = 0; -- cgit v1.2.3 From bfa98be48a4e84902d4c4bb2836f58cbbf582583 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 22 Dec 2018 19:31:12 -0800 Subject: Cleanup definitions and declarations in reverb.cpp --- Alc/effects/reverb.cpp | 474 +++++++++++++++++++++++-------------------------- 1 file changed, 221 insertions(+), 253 deletions(-) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index cc0f3fb0..b70e3d45 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -42,8 +42,11 @@ */ ALfloat ReverbBoost = 1.0f; +namespace { + /* This is the maximum number of samples processed for each inner loop - * iteration. */ + * iteration. + */ #define MAX_UPDATE_SAMPLES 256 /* The number of samples used for cross-faded delay lines. This can be used @@ -68,7 +71,7 @@ ALfloat ReverbBoost = 1.0f; * tetrahedron, but it's close enough. Should the model be extended to 8-lines * in the future, true opposites can be used. */ -static constexpr alu::Matrix B2A{ +constexpr alu::Matrix B2A{ 0.288675134595f, 0.288675134595f, 0.288675134595f, 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f, 0.288675134595f, 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f, @@ -76,14 +79,14 @@ static constexpr alu::Matrix B2A{ }; /* Converts A-Format to B-Format. */ -static constexpr alu::Matrix A2B{ +constexpr alu::Matrix A2B{ 0.866025403785f, 0.866025403785f, 0.866025403785f, 0.866025403785f, 0.866025403785f, -0.866025403785f, 0.866025403785f, -0.866025403785f, 0.866025403785f, -0.866025403785f, -0.866025403785f, 0.866025403785f, 0.866025403785f, 0.866025403785f, -0.866025403785f, -0.866025403785f }; -static const ALfloat FadeStep = 1.0f / FADE_SAMPLES; +constexpr ALfloat FadeStep{1.0f / FADE_SAMPLES}; /* The all-pass and delay lines have a variable length dependent on the * effect's density parameter, which helps alter the perceived environment @@ -95,12 +98,12 @@ static const ALfloat FadeStep = 1.0f / FADE_SAMPLES; * conversion is needed, taking the cube root of the re-scaled density to * calculate the line length multiplier: * - * length_mult = max(5.0, cbrtf(density*DENSITY_SCALE)); + * length_mult = max(5.0, cbrt(density*DENSITY_SCALE)); * * The density scale below will result in a max line multiplier of 50, for an * effective size range of 5m to 50m. */ -static const ALfloat DENSITY_SCALE = 125000.0f; +constexpr ALfloat DENSITY_SCALE{125000.0f}; /* All delay line lengths are specified in seconds. * @@ -146,8 +149,7 @@ static const ALfloat DENSITY_SCALE = 125000.0f; * * Assuming an average of 1m, we get the following taps: */ -static const ALfloat EARLY_TAP_LENGTHS[NUM_LINES] = -{ +constexpr ALfloat EARLY_TAP_LENGTHS[NUM_LINES]{ 0.0000000e+0f, 2.0213520e-4f, 4.2531060e-4f, 6.7171600e-4f }; @@ -157,8 +159,7 @@ static const ALfloat EARLY_TAP_LENGTHS[NUM_LINES] = * * Where a is the approximate maximum all-pass cycle limit (20). */ -static const ALfloat EARLY_ALLPASS_LENGTHS[NUM_LINES] = -{ +const ALfloat EARLY_ALLPASS_LENGTHS[NUM_LINES]{ 9.7096800e-5f, 1.0720356e-4f, 1.1836234e-4f, 1.3068260e-4f }; @@ -184,8 +185,7 @@ static const ALfloat EARLY_ALLPASS_LENGTHS[NUM_LINES] = * * Using an average dimension of 1m, we get: */ -static const ALfloat EARLY_LINE_LENGTHS[NUM_LINES] = -{ +constexpr ALfloat EARLY_LINE_LENGTHS[NUM_LINES]{ 5.9850400e-4f, 1.0913150e-3f, 1.5376658e-3f, 1.9419362e-3f }; @@ -193,8 +193,7 @@ static const ALfloat EARLY_LINE_LENGTHS[NUM_LINES] = * * A_i = (5 / 3) L_i / r_1 */ -static const ALfloat LATE_ALLPASS_LENGTHS[NUM_LINES] = -{ +constexpr ALfloat LATE_ALLPASS_LENGTHS[NUM_LINES]{ 1.6182800e-4f, 2.0389060e-4f, 2.8159360e-4f, 3.2365600e-4f }; @@ -213,35 +212,34 @@ static const ALfloat LATE_ALLPASS_LENGTHS[NUM_LINES] = * * For our 1m average room, we get: */ -static const ALfloat LATE_LINE_LENGTHS[NUM_LINES] = -{ +constexpr ALfloat LATE_LINE_LENGTHS[NUM_LINES]{ 1.9419362e-3f, 2.4466860e-3f, 3.3791220e-3f, 3.8838720e-3f }; -typedef struct DelayLineI { +struct DelayLineI { /* The delay lines use interleaved samples, with the lengths being powers * of 2 to allow the use of bit-masking instead of a modulus for wrapping. */ ALsizei Mask{0}; ALfloat (*Line)[NUM_LINES]{nullptr}; -} DelayLineI; +}; -typedef struct VecAllpass { +struct VecAllpass { DelayLineI Delay; ALfloat Coeff{0.0f}; ALsizei Offset[NUM_LINES][2]{}; -} VecAllpass; +}; -typedef struct T60Filter { +struct T60Filter { /* Two filters are used to adjust the signal. One to control the low * frequencies, and one to control the high frequencies. */ ALfloat MidGain[2]{0.0f, 0.0f}; BiquadFilter HFFilter, LFFilter; -} T60Filter; +}; -typedef struct EarlyReflections { +struct EarlyReflections { /* A Gerzon vector all-pass filter is used to simulate initial diffusion. * The spread from this filter also helps smooth out the reverb tail. */ @@ -257,9 +255,9 @@ typedef struct EarlyReflections { /* The gain for each output channel based on 3D panning. */ ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]{}; ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]{}; -} EarlyReflections; +}; -typedef struct LateReverb { +struct LateReverb { /* A recursive delay line is used fill in the reverb tail. */ DelayLineI Delay; ALsizei Offset[NUM_LINES][2]{}; @@ -278,7 +276,7 @@ typedef struct LateReverb { /* The gain for each output channel based on 3D panning. */ ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]{}; ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]{}; -} LateReverb; +}; struct ReverbState final : public EffectState { /* All delay lines are allocated as a single buffer to reduce memory @@ -349,15 +347,13 @@ struct ReverbState final : public EffectState { * Device Update * **************************************/ -static inline ALfloat CalcDelayLengthMult(ALfloat density) -{ - return maxf(5.0f, cbrtf(density*DENSITY_SCALE)); -} +inline ALfloat CalcDelayLengthMult(ALfloat density) +{ return maxf(5.0f, std::cbrt(density*DENSITY_SCALE)); } /* Given the allocated sample buffer, this function updates each delay line * offset. */ -static inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLineI *Delay) +inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLineI *Delay) { union { ALfloat *f; @@ -368,8 +364,8 @@ static inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLineI *Delay) } /* Calculate the length of a delay line and store its mask and offset. */ -static ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const ALuint frequency, - const ALuint extra, DelayLineI *Delay) +ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const ALuint frequency, + const ALuint extra, DelayLineI *Delay) { ALuint samples; @@ -391,7 +387,7 @@ static ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const * for all lines given the sample rate (frequency). If an allocation failure * occurs, it returns AL_FALSE. */ -static ALboolean AllocLines(const ALuint frequency, ReverbState *State) +ALboolean AllocLines(const ALuint frequency, ReverbState *State) { /* All delay line lengths are calculated to accomodate the full range of * lengths given their respective paramters. @@ -519,23 +515,19 @@ ALboolean ReverbState::deviceUpdate(const ALCdevice *Device) /* Calculate a decay coefficient given the length of each cycle and the time * until the decay reaches -60 dB. */ -static inline ALfloat CalcDecayCoeff(const ALfloat length, const ALfloat decayTime) -{ - return powf(REVERB_DECAY_GAIN, length/decayTime); -} +inline ALfloat CalcDecayCoeff(const ALfloat length, const ALfloat decayTime) +{ return std::pow(REVERB_DECAY_GAIN, length/decayTime); } /* Calculate a decay length from a coefficient and the time until the decay * reaches -60 dB. */ -static inline ALfloat CalcDecayLength(const ALfloat coeff, const ALfloat decayTime) -{ - return log10f(coeff) * decayTime / log10f(REVERB_DECAY_GAIN); -} +inline ALfloat CalcDecayLength(const ALfloat coeff, const ALfloat decayTime) +{ return std::log10(coeff) * decayTime / std::log10(REVERB_DECAY_GAIN); } /* Calculate an attenuation to be applied to the input of any echo models to * compensate for modal density and decay time. */ -static inline ALfloat CalcDensityGain(const ALfloat a) +inline ALfloat CalcDensityGain(const ALfloat a) { /* The energy of a signal can be obtained by finding the area under the * squared signal. This takes the form of Sum(x_n^2), where x is the @@ -550,38 +542,34 @@ static inline ALfloat CalcDensityGain(const ALfloat a) * calculated by inverting the square root of this approximation, * yielding: 1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2). */ - return sqrtf(1.0f - a*a); + return std::sqrt(1.0f - a*a); } /* Calculate the scattering matrix coefficients given a diffusion factor. */ -static inline ALvoid CalcMatrixCoeffs(const ALfloat diffusion, ALfloat *x, ALfloat *y) +inline ALvoid CalcMatrixCoeffs(const ALfloat diffusion, ALfloat *x, ALfloat *y) { - ALfloat n, t; - /* The matrix is of order 4, so n is sqrt(4 - 1). */ - n = sqrtf(3.0f); - t = diffusion * atanf(n); + ALfloat n{std::sqrt(3.0f)}; + ALfloat t{diffusion * std::atan(n)}; /* Calculate the first mixing matrix coefficient. */ - *x = cosf(t); + *x = std::cos(t); /* Calculate the second mixing matrix coefficient. */ - *y = sinf(t) / n; + *y = std::sin(t) / n; } /* Calculate the limited HF ratio for use with the late reverb low-pass * filters. */ -static ALfloat CalcLimitedHfRatio(const ALfloat hfRatio, const ALfloat airAbsorptionGainHF, - const ALfloat decayTime, const ALfloat SpeedOfSound) +ALfloat CalcLimitedHfRatio(const ALfloat hfRatio, const ALfloat airAbsorptionGainHF, + const ALfloat decayTime, const ALfloat SpeedOfSound) { - ALfloat limitRatio; - /* Find the attenuation due to air absorption in dB (converting delay * time to meters using the speed of sound). Then reversing the decay * equation, solve for HF ratio. The delay length is cancelled out of * the equation, so it can be calculated once for all lines. */ - limitRatio = 1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) * SpeedOfSound); + ALfloat limitRatio{1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) * SpeedOfSound)}; /* Using the limit calculated above, apply the upper bound to the HF ratio. */ @@ -593,14 +581,14 @@ static ALfloat CalcLimitedHfRatio(const ALfloat hfRatio, const ALfloat airAbsorp * of specified length, using a combination of two shelf filter sections given * decay times for each band split at two reference frequencies. */ -static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime, - const ALfloat mfDecayTime, const ALfloat hfDecayTime, - const ALfloat lf0norm, const ALfloat hf0norm, - T60Filter *filter) +void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime, + const ALfloat mfDecayTime, const ALfloat hfDecayTime, + const ALfloat lf0norm, const ALfloat hf0norm, + T60Filter *filter) { - ALfloat lfGain = CalcDecayCoeff(length, lfDecayTime); - ALfloat mfGain = CalcDecayCoeff(length, mfDecayTime); - ALfloat hfGain = CalcDecayCoeff(length, hfDecayTime); + ALfloat lfGain{CalcDecayCoeff(length, lfDecayTime)}; + ALfloat mfGain{CalcDecayCoeff(length, mfDecayTime)}; + ALfloat hfGain{CalcDecayCoeff(length, hfDecayTime)}; filter->MidGain[1] = mfGain; filter->LFFilter.setParams(BiquadType::LowShelf, lfGain/mfGain, lf0norm, @@ -610,12 +598,9 @@ static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime } /* Update the offsets for the main effect delay line. */ -static ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, const ALfloat density, const ALfloat decayTime, const ALuint frequency, ReverbState *State) +ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, const ALfloat density, const ALfloat decayTime, const ALuint frequency, ReverbState *State) { - ALfloat multiplier, length; - ALuint i; - - multiplier = CalcDelayLengthMult(density); + const ALfloat multiplier{CalcDelayLengthMult(density)}; /* Early reflection taps are decorrelated by means of an average room * reflection approximation described above the definition of the taps. @@ -627,9 +612,9 @@ static ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, * delay path and offsets that would continue the propagation naturally * into the late lines. */ - for(i = 0;i < NUM_LINES;i++) + for(ALsizei i{0};i < NUM_LINES;i++) { - length = earlyDelay + EARLY_TAP_LENGTHS[i]*multiplier; + ALfloat length{earlyDelay + EARLY_TAP_LENGTHS[i]*multiplier}; State->mEarlyDelayTap[i][1] = float2int(length * frequency); length = EARLY_TAP_LENGTHS[i]*multiplier; @@ -641,20 +626,17 @@ static ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, } /* Update the early reflection line lengths and gain coefficients. */ -static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat diffusion, const ALfloat decayTime, const ALuint frequency, EarlyReflections *Early) +ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat diffusion, const ALfloat decayTime, const ALuint frequency, EarlyReflections *Early) { - ALfloat multiplier, length; - ALsizei i; - - multiplier = CalcDelayLengthMult(density); + const ALfloat multiplier{CalcDelayLengthMult(density)}; /* Calculate the all-pass feed-back/forward coefficient. */ Early->VecAp.Coeff = sqrtf(0.5f) * powf(diffusion, 2.0f); - for(i = 0;i < NUM_LINES;i++) + for(ALsizei i{0};i < NUM_LINES;i++) { /* Calculate the length (in seconds) of each all-pass line. */ - length = EARLY_ALLPASS_LENGTHS[i] * multiplier; + ALfloat length{EARLY_ALLPASS_LENGTHS[i] * multiplier}; /* Calculate the delay offset for each all-pass line. */ Early->VecAp.Offset[i][1] = float2int(length * frequency); @@ -671,14 +653,12 @@ static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat diffusion, c } /* Update the late reverb line lengths and T60 coefficients. */ -static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lf0norm, const ALfloat hf0norm, const ALuint frequency, LateReverb *Late) +ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lf0norm, const ALfloat hf0norm, const ALuint frequency, LateReverb *Late) { /* Scaling factor to convert the normalized reference frequencies from * representing 0...freq to 0...max_reference. */ const ALfloat norm_weight_factor = (ALfloat)frequency / AL_EAXREVERB_MAX_HFREFERENCE; - ALfloat multiplier, length, bandWeights[3]; - ALsizei i; /* To compensate for changes in modal density and decay time of the late * reverb signal, the input is attenuated based on the maximal energy of @@ -688,18 +668,20 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co * The average length of the delay lines is used to calculate the * attenuation coefficient. */ - multiplier = CalcDelayLengthMult(density); - length = (LATE_LINE_LENGTHS[0] + LATE_LINE_LENGTHS[1] + - LATE_LINE_LENGTHS[2] + LATE_LINE_LENGTHS[3]) / 4.0f * multiplier; + const ALfloat multiplier{CalcDelayLengthMult(density)}; + ALfloat length{ + (LATE_LINE_LENGTHS[0] + LATE_LINE_LENGTHS[1] + LATE_LINE_LENGTHS[2] + + LATE_LINE_LENGTHS[3]) / 4.0f * multiplier}; length += (LATE_ALLPASS_LENGTHS[0] + LATE_ALLPASS_LENGTHS[1] + LATE_ALLPASS_LENGTHS[2] + LATE_ALLPASS_LENGTHS[3]) / 4.0f * multiplier; /* The density gain calculation uses an average decay time weighted by * approximate bandwidth. This attempts to compensate for losses of energy * that reduce decay time due to scattering into highly attenuated bands. */ - bandWeights[0] = lf0norm*norm_weight_factor; - bandWeights[1] = hf0norm*norm_weight_factor - lf0norm*norm_weight_factor; - bandWeights[2] = 1.0f - hf0norm*norm_weight_factor; + const ALfloat bandWeights[3]{ + lf0norm*norm_weight_factor, + hf0norm*norm_weight_factor - lf0norm*norm_weight_factor, + 1.0f - hf0norm*norm_weight_factor}; Late->DensityGain[1] = CalcDensityGain( CalcDecayCoeff(length, bandWeights[0]*lfDecayTime + bandWeights[1]*mfDecayTime + bandWeights[2]*hfDecayTime @@ -707,9 +689,9 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co ); /* Calculate the all-pass feed-back/forward coefficient. */ - Late->VecAp.Coeff = sqrtf(0.5f) * powf(diffusion, 2.0f); + Late->VecAp.Coeff = std::sqrt(0.5f) * std::pow(diffusion, 2.0f); - for(i = 0;i < NUM_LINES;i++) + for(ALsizei i{0};i < NUM_LINES;i++) { /* Calculate the length (in seconds) of each all-pass line. */ length = LATE_ALLPASS_LENGTHS[i] * multiplier; @@ -743,7 +725,7 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co * focal strength. This function results in a B-Format transformation matrix * that spatially focuses the signal in the desired direction. */ -static alu::Matrix GetTransformFromVector(const ALfloat *vec) +alu::Matrix GetTransformFromVector(const ALfloat *vec) { /* Normalize the panning vector according to the N3D scale, which has an * extra sqrt(3) term on the directional components. Converting from OpenAL @@ -753,7 +735,7 @@ static alu::Matrix GetTransformFromVector(const ALfloat *vec) * which cancels out with the B-Format Z negation. */ ALfloat norm[3]; - ALfloat mag{sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2])}; + ALfloat mag{std::sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2])}; if(mag > 1.0f) { norm[0] = vec[0] / mag * -SQRTF_3; @@ -781,7 +763,7 @@ static alu::Matrix GetTransformFromVector(const ALfloat *vec) } /* Update the early and late 3D panning gains. */ -static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, const ALfloat earlyGain, const ALfloat lateGain, ReverbState *State) +ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, const ALfloat earlyGain, const ALfloat lateGain, ReverbState *State) { State->mOutBuffer = Device->FOAOut.Buffer; State->mOutChannels = Device->FOAOut.NumChannels; @@ -817,27 +799,23 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) { - const ALCdevice *Device = Context->Device; + const ALCdevice *Device{Context->Device}; const ALlistener &Listener = Context->Listener; - ALuint frequency = Device->Frequency; - ALfloat lf0norm, hf0norm, hfRatio; - ALfloat lfDecayTime, hfDecayTime; - ALfloat gain, gainlf, gainhf; - ALsizei i; + const ALuint frequency{Device->Frequency}; /* Calculate the master filters */ - hf0norm = minf(props->Reverb.HFReference / frequency, 0.49f); + ALfloat hf0norm{minf(props->Reverb.HFReference / frequency, 0.49f)}; /* Restrict the filter gains from going below -60dB to keep the filter from * killing most of the signal. */ - gainhf = maxf(props->Reverb.GainHF, 0.001f); + ALfloat gainhf{maxf(props->Reverb.GainHF, 0.001f)}; mFilter[0].Lp.setParams(BiquadType::HighShelf, gainhf, hf0norm, calc_rcpQ_from_slope(gainhf, 1.0f)); - lf0norm = minf(props->Reverb.LFReference / frequency, 0.49f); - gainlf = maxf(props->Reverb.GainLF, 0.001f); + ALfloat lf0norm{minf(props->Reverb.LFReference / frequency, 0.49f)}; + ALfloat gainlf{maxf(props->Reverb.GainLF, 0.001f)}; mFilter[0].Hp.setParams(BiquadType::LowShelf, gainlf, lf0norm, calc_rcpQ_from_slope(gainlf, 1.0f)); - for(i = 1;i < NUM_LINES;i++) + for(ALsizei i{1};i < NUM_LINES;i++) { mFilter[i].Lp.copyParamsFrom(mFilter[0].Lp); mFilter[i].Hp.copyParamsFrom(mFilter[0].Hp); @@ -858,17 +836,17 @@ void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, co /* If the HF limit parameter is flagged, calculate an appropriate limit * based on the air absorption parameter. */ - hfRatio = props->Reverb.DecayHFRatio; + ALfloat hfRatio{props->Reverb.DecayHFRatio}; if(props->Reverb.DecayHFLimit && props->Reverb.AirAbsorptionGainHF < 1.0f) hfRatio = CalcLimitedHfRatio(hfRatio, props->Reverb.AirAbsorptionGainHF, props->Reverb.DecayTime, Listener.Params.ReverbSpeedOfSound ); /* Calculate the LF/HF decay times. */ - lfDecayTime = clampf(props->Reverb.DecayTime * props->Reverb.DecayLFRatio, - AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME); - hfDecayTime = clampf(props->Reverb.DecayTime * hfRatio, - AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME); + const ALfloat lfDecayTime{clampf(props->Reverb.DecayTime * props->Reverb.DecayLFRatio, + AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME)}; + const ALfloat hfDecayTime{clampf(props->Reverb.DecayTime * hfRatio, + AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME)}; /* Update the late lines. */ UpdateLateLines(props->Reverb.Density, props->Reverb.Diffusion, @@ -877,7 +855,7 @@ void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, co ); /* Update early and late 3D panning. */ - gain = props->Reverb.Gain * Slot->Params.Gain * ReverbBoost; + const ALfloat gain{props->Reverb.Gain * Slot->Params.Gain * ReverbBoost}; Update3DPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain, this); @@ -918,28 +896,25 @@ void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, co **************************************/ /* Basic delay line input/output routines. */ -static inline ALfloat DelayLineOut(const DelayLineI *Delay, const ALsizei offset, const ALsizei c) -{ - return Delay->Line[offset&Delay->Mask][c]; -} +inline ALfloat DelayLineOut(const DelayLineI *Delay, const ALsizei offset, const ALsizei c) +{ return Delay->Line[offset&Delay->Mask][c]; } /* Cross-faded delay line output routine. Instead of interpolating the * offsets, this interpolates (cross-fades) the outputs at each offset. */ -static inline ALfloat FadedDelayLineOut(const DelayLineI *Delay, const ALsizei off0, - const ALsizei off1, const ALsizei c, - const ALfloat sc0, const ALfloat sc1) +inline ALfloat FadedDelayLineOut(const DelayLineI *Delay, const ALsizei off0, const ALsizei off1, + const ALsizei c, const ALfloat sc0, const ALfloat sc1) { return Delay->Line[off0&Delay->Mask][c]*sc0 + Delay->Line[off1&Delay->Mask][c]*sc1; } -static inline void DelayLineIn(const DelayLineI *Delay, ALsizei offset, const ALsizei c, - const ALfloat *RESTRICT in, ALsizei count) +inline void DelayLineIn(const DelayLineI *Delay, ALsizei offset, const ALsizei c, + const ALfloat *RESTRICT in, ALsizei count) { - ALsizei i; - for(i = 0;i < count;i++) + ASSUME(count > 0); + for(ALsizei i{0};i < count;i++) Delay->Line[(offset++)&Delay->Mask][c] = *(in++); } @@ -981,8 +956,8 @@ static inline void DelayLineIn(const DelayLineI *Delay, ALsizei offset, const AL * Where D is a diagonal matrix (of x), and S is a triangular matrix (of y) * whose combination of signs are being iterated. */ -static inline void VectorPartialScatter(ALfloat *RESTRICT out, const ALfloat *RESTRICT in, - const ALfloat xCoeff, const ALfloat yCoeff) +inline void VectorPartialScatter(ALfloat *RESTRICT out, const ALfloat *RESTRICT in, + const ALfloat xCoeff, const ALfloat yCoeff) { out[0] = xCoeff*in[0] + yCoeff*( in[1] + -in[2] + in[3]); out[1] = xCoeff*in[1] + yCoeff*(-in[0] + in[2] + in[3]); @@ -993,18 +968,16 @@ static inline void VectorPartialScatter(ALfloat *RESTRICT out, const ALfloat *RE VectorPartialScatter((delay)->Line[(o)&(delay)->Mask], in, xcoeff, ycoeff) /* Utilizes the above, but reverses the input channels. */ -static inline void VectorScatterRevDelayIn(const DelayLineI *Delay, ALint offset, - const ALfloat xCoeff, const ALfloat yCoeff, - const ALfloat (*RESTRICT in)[MAX_UPDATE_SAMPLES], - const ALsizei count) +inline void VectorScatterRevDelayIn(const DelayLineI *Delay, ALint offset, + const ALfloat xCoeff, const ALfloat yCoeff, + const ALfloat (*RESTRICT in)[MAX_UPDATE_SAMPLES], + const ALsizei count) { - const DelayLineI delay = *Delay; - ALsizei i, j; - - for(i = 0;i < count;++i) + const DelayLineI delay{*Delay}; + for(ALsizei i{0};i < count;++i) { ALfloat f[NUM_LINES]; - for(j = 0;j < NUM_LINES;j++) + for(ALsizei j{0};j < NUM_LINES;j++) f[NUM_LINES-1-j] = in[j][i]; VectorScatterDelayIn(&delay, offset++, f, xCoeff, yCoeff); @@ -1021,24 +994,23 @@ static inline void VectorScatterRevDelayIn(const DelayLineI *Delay, ALint offset * Two static specializations are used for transitional (cross-faded) delay * line processing and non-transitional processing. */ -static void VectorAllpass_Unfaded(ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES], ALsizei offset, - const ALfloat xCoeff, const ALfloat yCoeff, ALsizei todo, - VecAllpass *Vap) +void VectorAllpass_Unfaded(ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES], ALsizei offset, + const ALfloat xCoeff, const ALfloat yCoeff, ALsizei todo, + VecAllpass *Vap) { - const DelayLineI delay = Vap->Delay; - const ALfloat feedCoeff = Vap->Coeff; - ALsizei vap_offset[NUM_LINES]; - ALsizei i, j; + const DelayLineI delay{Vap->Delay}; + const ALfloat feedCoeff{Vap->Coeff}; ASSUME(todo > 0); - for(j = 0;j < NUM_LINES;j++) - vap_offset[j] = offset-Vap->Offset[j][0]; - for(i = 0;i < todo;i++) + ALsizei vap_offset[NUM_LINES]; + for(ALsizei j{0};j < NUM_LINES;j++) + vap_offset[j] = offset - Vap->Offset[j][0]; + for(ALsizei i{0};i < todo;i++) { ALfloat f[NUM_LINES]; - for(j = 0;j < NUM_LINES;j++) + for(ALsizei j{0};j < NUM_LINES;j++) { ALfloat input = samples[j][i]; ALfloat out = DelayLineOut(&delay, vap_offset[j]++, j) - feedCoeff*input; @@ -1051,28 +1023,27 @@ static void VectorAllpass_Unfaded(ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES ++offset; } } -static void VectorAllpass_Faded(ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES], ALsizei offset, - const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, - ALsizei todo, VecAllpass *Vap) +void VectorAllpass_Faded(ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES], ALsizei offset, + const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, + ALsizei todo, VecAllpass *Vap) { - const DelayLineI delay = Vap->Delay; - const ALfloat feedCoeff = Vap->Coeff; - ALsizei vap_offset[NUM_LINES][2]; - ALsizei i, j; + const DelayLineI delay{Vap->Delay}; + const ALfloat feedCoeff{Vap->Coeff}; ASSUME(todo > 0); fade *= 1.0f/FADE_SAMPLES; - for(j = 0;j < NUM_LINES;j++) + ALsizei vap_offset[NUM_LINES][2]; + for(ALsizei j{0};j < NUM_LINES;j++) { - vap_offset[j][0] = offset-Vap->Offset[j][0]; - vap_offset[j][1] = offset-Vap->Offset[j][1]; + vap_offset[j][0] = offset - Vap->Offset[j][0]; + vap_offset[j][1] = offset - Vap->Offset[j][1]; } - for(i = 0;i < todo;i++) + for(ALsizei i{0};i < todo;i++) { ALfloat f[NUM_LINES]; - for(j = 0;j < NUM_LINES;j++) + for(ALsizei j{0};j < NUM_LINES;j++) { ALfloat input = samples[j][i]; ALfloat out = @@ -1109,27 +1080,25 @@ static void VectorAllpass_Faded(ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES], * Two static specializations are used for transitional (cross-faded) delay * line processing and non-transitional processing. */ -static void EarlyReflection_Unfaded(ReverbState *State, ALsizei offset, const ALsizei todo, - ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) +void EarlyReflection_Unfaded(ReverbState *State, ALsizei offset, const ALsizei todo, + ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) { - ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->mTempSamples; - const DelayLineI early_delay = State->mEarly.Delay; - const DelayLineI main_delay = State->mDelay; - const ALfloat mixX = State->mMixX; - const ALfloat mixY = State->mMixY; - ALsizei late_feed_tap; - ALsizei i, j; + ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES]{State->mTempSamples}; + const DelayLineI early_delay{State->mEarly.Delay}; + const DelayLineI main_delay{State->mDelay}; + const ALfloat mixX{State->mMixX}; + const ALfloat mixY{State->mMixY}; ASSUME(todo > 0); /* First, load decorrelated samples from the main delay line as the primary * reflections. */ - for(j = 0;j < NUM_LINES;j++) + for(ALsizei j{0};j < NUM_LINES;j++) { - ALsizei early_delay_tap = offset - State->mEarlyDelayTap[j][0]; - ALfloat coeff = State->mEarlyDelayCoeff[j][0]; - for(i = 0;i < todo;i++) + ALsizei early_delay_tap{offset - State->mEarlyDelayTap[j][0]}; + const ALfloat coeff{State->mEarlyDelayCoeff[j][0]}; + for(ALsizei i{0};i < todo;i++) temps[j][i] = DelayLineOut(&main_delay, early_delay_tap++, j) * coeff; } @@ -1141,39 +1110,37 @@ static void EarlyReflection_Unfaded(ReverbState *State, ALsizei offset, const AL /* Apply a delay and bounce to generate secondary reflections, combine with * the primary reflections and write out the result for mixing. */ - for(j = 0;j < NUM_LINES;j++) + for(ALsizei j{0};j < NUM_LINES;j++) { - ALint early_feedb_tap = offset - State->mEarly.Offset[j][0]; - ALfloat early_feedb_coeff = State->mEarly.Coeff[j][0]; + ALint early_feedb_tap{offset - State->mEarly.Offset[j][0]}; + const ALfloat early_feedb_coeff{State->mEarly.Coeff[j][0]}; - for(i = 0;i < todo;i++) + for(ALsizei i{0};i < todo;i++) out[j][i] = DelayLineOut(&early_delay, early_feedb_tap++, j)*early_feedb_coeff + temps[j][i]; } - for(j = 0;j < NUM_LINES;j++) + for(ALsizei j{0};j < NUM_LINES;j++) DelayLineIn(&early_delay, offset, NUM_LINES-1-j, temps[j], todo); /* Also write the result back to the main delay line for the late reverb * stage to pick up at the appropriate time, appplying a scatter and * bounce to improve the initial diffusion in the late reverb. */ - late_feed_tap = offset - State->mLateFeedTap; + const ALsizei late_feed_tap{offset - State->mLateFeedTap}; VectorScatterRevDelayIn(&main_delay, late_feed_tap, mixX, mixY, out, todo); } -static void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsizei todo, - const ALfloat fade, ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) +void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsizei todo, + const ALfloat fade, ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) { - ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->mTempSamples; - const DelayLineI early_delay = State->mEarly.Delay; - const DelayLineI main_delay = State->mDelay; - const ALfloat mixX = State->mMixX; - const ALfloat mixY = State->mMixY; - ALsizei late_feed_tap; - ALsizei i, j; + ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES]{State->mTempSamples}; + const DelayLineI early_delay{State->mEarly.Delay}; + const DelayLineI main_delay{State->mDelay}; + const ALfloat mixX{State->mMixX}; + const ALfloat mixY{State->mMixY}; ASSUME(todo > 0); - for(j = 0;j < NUM_LINES;j++) + for(ALsizei j{0};j < NUM_LINES;j++) { ALsizei early_delay_tap0 = offset - State->mEarlyDelayTap[j][0]; ALsizei early_delay_tap1 = offset - State->mEarlyDelayTap[j][1]; @@ -1182,7 +1149,7 @@ static void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsi ALfloat newCoeffStep = State->mEarlyDelayCoeff[j][1] / FADE_SAMPLES; ALfloat fadeCount = fade; - for(i = 0;i < todo;i++) + for(ALsizei i{0};i < todo;i++) { const ALfloat fade0 = oldCoeff + oldCoeffStep*fadeCount; const ALfloat fade1 = newCoeffStep*fadeCount; @@ -1195,29 +1162,29 @@ static void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsi VectorAllpass_Faded(temps, offset, mixX, mixY, fade, todo, &State->mEarly.VecAp); - for(j = 0;j < NUM_LINES;j++) + for(ALsizei j{0};j < NUM_LINES;j++) { - ALint feedb_tap0 = offset - State->mEarly.Offset[j][0]; - ALint feedb_tap1 = offset - State->mEarly.Offset[j][1]; - ALfloat feedb_oldCoeff = State->mEarly.Coeff[j][0]; - ALfloat feedb_oldCoeffStep = -feedb_oldCoeff / FADE_SAMPLES; - ALfloat feedb_newCoeffStep = State->mEarly.Coeff[j][1] / FADE_SAMPLES; - ALfloat fadeCount = fade; - - for(i = 0;i < todo;i++) + ALint feedb_tap0{offset - State->mEarly.Offset[j][0]}; + ALint feedb_tap1{offset - State->mEarly.Offset[j][1]}; + const ALfloat feedb_oldCoeff{State->mEarly.Coeff[j][0]}; + const ALfloat feedb_oldCoeffStep{-feedb_oldCoeff / FADE_SAMPLES}; + const ALfloat feedb_newCoeffStep{State->mEarly.Coeff[j][1] / FADE_SAMPLES}; + ALfloat fadeCount{fade}; + + for(ALsizei i{0};i < todo;i++) { - const ALfloat fade0 = feedb_oldCoeff + feedb_oldCoeffStep*fadeCount; - const ALfloat fade1 = feedb_newCoeffStep*fadeCount; + const ALfloat fade0{feedb_oldCoeff + feedb_oldCoeffStep*fadeCount}; + const ALfloat fade1{feedb_newCoeffStep*fadeCount}; out[j][i] = FadedDelayLineOut(&early_delay, feedb_tap0++, feedb_tap1++, j, fade0, fade1 ) + temps[j][i]; fadeCount += 1.0f; } } - for(j = 0;j < NUM_LINES;j++) + for(ALsizei j{0};j < NUM_LINES;j++) DelayLineIn(&early_delay, offset, NUM_LINES-1-j, temps[j], todo); - late_feed_tap = offset - State->mLateFeedTap; + const ALsizei late_feed_tap{offset - State->mLateFeedTap}; VectorScatterRevDelayIn(&main_delay, late_feed_tap, mixX, mixY, out, todo); } @@ -1243,28 +1210,27 @@ static inline void LateT60Filter(ALfloat *RESTRICT samples, const ALsizei todo, * Two variations are made, one for for transitional (cross-faded) delay line * processing and one for non-transitional processing. */ -static void LateReverb_Unfaded(ReverbState *State, ALsizei offset, const ALsizei todo, - ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) +void LateReverb_Unfaded(ReverbState *State, ALsizei offset, const ALsizei todo, + ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) { - ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->mTempSamples; - const DelayLineI late_delay = State->mLate.Delay; - const DelayLineI main_delay = State->mDelay; - const ALfloat mixX = State->mMixX; - const ALfloat mixY = State->mMixY; - ALsizei i, j; + ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES]{State->mTempSamples}; + const DelayLineI late_delay{State->mLate.Delay}; + const DelayLineI main_delay{State->mDelay}; + const ALfloat mixX{State->mMixX}; + const ALfloat mixY{State->mMixY}; ASSUME(todo > 0); /* First, load decorrelated samples from the main and feedback delay lines. * Filter the signal to apply its frequency-dependent decay. */ - for(j = 0;j < NUM_LINES;j++) + for(ALsizei j{0};j < NUM_LINES;j++) { - ALsizei late_delay_tap = offset - State->mLateDelayTap[j][0]; - ALsizei late_feedb_tap = offset - State->mLate.Offset[j][0]; - ALfloat midGain = State->mLate.T60[j].MidGain[0]; - const ALfloat densityGain = State->mLate.DensityGain[0] * midGain; - for(i = 0;i < todo;i++) + ALsizei late_delay_tap{offset - State->mLateDelayTap[j][0]}; + ALsizei late_feedb_tap{offset - State->mLate.Offset[j][0]}; + const ALfloat midGain{State->mLate.T60[j].MidGain[0]}; + const ALfloat densityGain{State->mLate.DensityGain[0] * midGain}; + for(ALsizei i{0};i < todo;i++) temps[j][i] = DelayLineOut(&main_delay, late_delay_tap++, j)*densityGain + DelayLineOut(&late_delay, late_feedb_tap++, j)*midGain; LateT60Filter(temps[j], todo, &State->mLate.T60[j]); @@ -1275,41 +1241,40 @@ static void LateReverb_Unfaded(ReverbState *State, ALsizei offset, const ALsizei */ VectorAllpass_Unfaded(temps, offset, mixX, mixY, todo, &State->mLate.VecAp); - for(j = 0;j < NUM_LINES;j++) - memcpy(out[j], temps[j], todo*sizeof(ALfloat)); + for(ALsizei j{0};j < NUM_LINES;j++) + std::copy_n(temps[j], todo, out[j]); /* Finally, scatter and bounce the results to refeed the feedback buffer. */ VectorScatterRevDelayIn(&late_delay, offset, mixX, mixY, out, todo); } -static void LateReverb_Faded(ReverbState *State, ALsizei offset, const ALsizei todo, - const ALfloat fade, ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) +void LateReverb_Faded(ReverbState *State, ALsizei offset, const ALsizei todo, const ALfloat fade, + ALfloat (*RESTRICT out)[MAX_UPDATE_SAMPLES]) { - ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES] = State->mTempSamples; - const DelayLineI late_delay = State->mLate.Delay; - const DelayLineI main_delay = State->mDelay; - const ALfloat mixX = State->mMixX; - const ALfloat mixY = State->mMixY; - ALsizei i, j; + ALfloat (*RESTRICT temps)[MAX_UPDATE_SAMPLES]{State->mTempSamples}; + const DelayLineI late_delay{State->mLate.Delay}; + const DelayLineI main_delay{State->mDelay}; + const ALfloat mixX{State->mMixX}; + const ALfloat mixY{State->mMixY}; ASSUME(todo > 0); - for(j = 0;j < NUM_LINES;j++) + for(ALsizei j{0};j < NUM_LINES;j++) { - const ALfloat oldMidGain = State->mLate.T60[j].MidGain[0]; - const ALfloat midGain = State->mLate.T60[j].MidGain[1]; - const ALfloat oldMidStep = -oldMidGain / FADE_SAMPLES; - const ALfloat midStep = midGain / FADE_SAMPLES; - const ALfloat oldDensityGain = State->mLate.DensityGain[0] * oldMidGain; - const ALfloat densityGain = State->mLate.DensityGain[1] * midGain; - const ALfloat oldDensityStep = -oldDensityGain / FADE_SAMPLES; - const ALfloat densityStep = densityGain / FADE_SAMPLES; - ALsizei late_delay_tap0 = offset - State->mLateDelayTap[j][0]; - ALsizei late_delay_tap1 = offset - State->mLateDelayTap[j][1]; - ALsizei late_feedb_tap0 = offset - State->mLate.Offset[j][0]; - ALsizei late_feedb_tap1 = offset - State->mLate.Offset[j][1]; - ALfloat fadeCount = fade; - - for(i = 0;i < todo;i++) + const ALfloat oldMidGain{State->mLate.T60[j].MidGain[0]}; + const ALfloat midGain{State->mLate.T60[j].MidGain[1]}; + const ALfloat oldMidStep{-oldMidGain / FADE_SAMPLES}; + const ALfloat midStep{midGain / FADE_SAMPLES}; + const ALfloat oldDensityGain{State->mLate.DensityGain[0] * oldMidGain}; + const ALfloat densityGain{State->mLate.DensityGain[1] * midGain}; + const ALfloat oldDensityStep{-oldDensityGain / FADE_SAMPLES}; + const ALfloat densityStep{densityGain / FADE_SAMPLES}; + ALsizei late_delay_tap0{offset - State->mLateDelayTap[j][0]}; + ALsizei late_delay_tap1{offset - State->mLateDelayTap[j][1]}; + ALsizei late_feedb_tap0{offset - State->mLate.Offset[j][0]}; + ALsizei late_feedb_tap1{offset - State->mLate.Offset[j][1]}; + ALfloat fadeCount{fade}; + + for(ALsizei i{0};i < todo;i++) { const ALfloat fade0 = oldDensityGain + oldDensityStep*fadeCount; const ALfloat fade1 = densityStep*fadeCount; @@ -1327,24 +1292,25 @@ static void LateReverb_Faded(ReverbState *State, ALsizei offset, const ALsizei t VectorAllpass_Faded(temps, offset, mixX, mixY, fade, todo, &State->mLate.VecAp); - for(j = 0;j < NUM_LINES;j++) - memcpy(out[j], temps[j], todo*sizeof(ALfloat)); + for(ALsizei j{0};j < NUM_LINES;j++) + std::copy_n(temps[j], todo, out[j]); VectorScatterRevDelayIn(&late_delay, offset, mixX, mixY, temps, todo); } void ReverbState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALfloat (*RESTRICT afmt)[MAX_UPDATE_SAMPLES] = mTempSamples; - ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES] = mMixBuffer; - ALsizei fadeCount = mFadeCount; - ALsizei offset = mOffset; - ALsizei base, c; + ALfloat (*RESTRICT afmt)[MAX_UPDATE_SAMPLES]{mTempSamples}; + ALfloat (*RESTRICT samples)[MAX_UPDATE_SAMPLES]{mMixBuffer}; + ALsizei fadeCount{mFadeCount}; + ALsizei offset{mOffset}; + + ASSUME(SamplesToDo > 0); /* Process reverb for these samples. */ - for(base = 0;base < SamplesToDo;) + for(ALsizei base{0};base < SamplesToDo;) { - ALsizei todo = SamplesToDo - base; + ALsizei todo{SamplesToDo - base}; /* If cross-fading, don't do more samples than there are to fade. */ if(FADE_SAMPLES-fadeCount > 0) { @@ -1359,7 +1325,7 @@ void ReverbState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesI todo &= ~3; /* Convert B-Format to A-Format for processing. */ - for(c = 0;c < NUM_LINES;c++) + for(ALsizei c{0};c < NUM_LINES;c++) { std::fill(std::begin(afmt[c]), std::end(afmt[c]), 0.0f); MixRowSamples(afmt[c], B2A[c].data(), @@ -1368,7 +1334,7 @@ void ReverbState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesI } /* Process the samples for reverb. */ - for(c = 0;c < NUM_LINES;c++) + for(ALsizei c{0};c < NUM_LINES;c++) { /* Band-pass the incoming samples. */ mFilter[c].Lp.process(samples[0], afmt[c], todo); @@ -1380,14 +1346,14 @@ void ReverbState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesI if(UNLIKELY(fadeCount < FADE_SAMPLES)) { - ALfloat fade = (ALfloat)fadeCount; + auto fade = static_cast(fadeCount); /* Generate early reflections. */ EarlyReflection_Faded(this, offset, todo, fade, samples); /* Mix the A-Format results to output, implicitly converting back * to B-Format. */ - for(c = 0;c < NUM_LINES;c++) + for(ALsizei c{0};c < NUM_LINES;c++) MixSamples(samples[c], NumChannels, SamplesOut, mEarly.CurrentGain[c], mEarly.PanGain[c], SamplesToDo-base, base, todo @@ -1395,7 +1361,7 @@ void ReverbState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesI /* Generate and mix late reverb. */ LateReverb_Faded(this, offset, todo, fade, samples); - for(c = 0;c < NUM_LINES;c++) + for(ALsizei c{0};c < NUM_LINES;c++) MixSamples(samples[c], NumChannels, SamplesOut, mLate.CurrentGain[c], mLate.PanGain[c], SamplesToDo-base, base, todo @@ -1407,7 +1373,7 @@ void ReverbState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesI { /* Update the cross-fading delay line taps. */ fadeCount = FADE_SAMPLES; - for(c = 0;c < NUM_LINES;c++) + for(ALsizei c{0};c < NUM_LINES;c++) { mEarlyDelayTap[c][0] = mEarlyDelayTap[c][1]; mEarlyDelayCoeff[c][0] = mEarlyDelayCoeff[c][1]; @@ -1427,7 +1393,7 @@ void ReverbState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesI { /* Generate and mix early reflections. */ EarlyReflection_Unfaded(this, offset, todo, samples); - for(c = 0;c < NUM_LINES;c++) + for(ALsizei c{0};c < NUM_LINES;c++) MixSamples(samples[c], NumChannels, SamplesOut, mEarly.CurrentGain[c], mEarly.PanGain[c], SamplesToDo-base, base, todo @@ -1435,7 +1401,7 @@ void ReverbState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesI /* Generate and mix late reverb. */ LateReverb_Unfaded(this, offset, todo, samples); - for(c = 0;c < NUM_LINES;c++) + for(ALsizei c{0};c < NUM_LINES;c++) MixSamples(samples[c], NumChannels, SamplesOut, mLate.CurrentGain[c], mLate.PanGain[c], SamplesToDo-base, base, todo @@ -1459,6 +1425,8 @@ struct ReverbStateFactory final : public EffectStateFactory { EffectState *ReverbStateFactory::create() { return new ReverbState{}; } +} // namespace + EffectStateFactory *ReverbStateFactory_getFactory(void) { static ReverbStateFactory ReverbFactory{}; -- cgit v1.2.3 From ebfe818d2eb3a5c4e27040f139ae3fb349f13865 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 22 Dec 2018 20:32:00 -0800 Subject: Fix narrowing conversion from double to float --- common/math_defs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/math_defs.h b/common/math_defs.h index 4686e96b..6471e2e7 100644 --- a/common/math_defs.h +++ b/common/math_defs.h @@ -13,7 +13,7 @@ #define SQRTF_3 1.73205080756887719318f -constexpr inline float Deg2Rad(float x) noexcept { return x * float{M_PI/180.0}; } -constexpr inline float Rad2Deg(float x) noexcept { return x * float{180.0/M_PI}; } +constexpr inline float Deg2Rad(float x) noexcept { return x * static_cast(M_PI/180.0); } +constexpr inline float Rad2Deg(float x) noexcept { return x * static_cast(180.0/M_PI); } #endif /* AL_MATH_DEFS_H */ -- cgit v1.2.3 From e218999b4f408b7fd35daa9d021288b68f5b4ab5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 22 Dec 2018 22:14:25 -0800 Subject: Dynamically sort the effect slots when mixing This is to be able to support effects that output to other effects. When an effect outputs to another effect, the former needs to process first, so the former mixes to the latter's buffer before the latter is processed. This sorting needs to happen in the mixer because the effect slot's "Target" property changes asynchronously. --- Alc/alc.cpp | 8 ++++++-- Alc/alu.cpp | 41 ++++++++++++++++++++++++++++++++++++-- OpenAL32/Include/alAuxEffectSlot.h | 1 + OpenAL32/alAuxEffectSlot.cpp | 9 +++++---- 4 files changed, 51 insertions(+), 8 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index fb7f9c67..a5353cb9 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2327,9 +2327,13 @@ static ALvoid InitContext(ALCcontext *Context) //Validate Context if(Context->DefaultSlot) { + static constexpr int count{1}; + /* Allocate twice as much space for effect slots so the mixer has a + * place to sort them. + */ auxslots = static_cast(al_calloc(DEF_ALIGN, - FAM_SIZE(ALeffectslotArray, slot, 1))); - auxslots->count = 1; + FAM_SIZE(ALeffectslotArray, slot, count*2))); + auxslots->count = count; auxslots->slot[0] = Context->DefaultSlot.get(); } else diff --git a/Alc/alu.cpp b/Alc/alu.cpp index a6e53f4b..3ea82354 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1429,8 +1429,10 @@ void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray *slots) IncrementRef(&ctx->UpdateCount); } -void ProcessContext(ALCcontext *ctx, ALsizei SamplesToDo) +void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) { + ASSUME(SamplesToDo > 0); + const ALeffectslotArray *auxslots{ctx->ActiveAuxSlots.load(std::memory_order_acquire)}; /* Process pending propery updates for objects on the context. */ @@ -1465,7 +1467,42 @@ void ProcessContext(ALCcontext *ctx, ALsizei SamplesToDo) ); /* Process effects. */ - std::for_each(auxslots->slot, auxslots->slot+auxslots->count, + if(auxslots->count < 1) return; + auto slots = auxslots->slot; + auto slots_end = slots + auxslots->count; + + /* First sort the slots into scratch storage, so that effects come before + * their effect target (or their targets' target). + */ + auto sorted_slots = const_cast(slots_end); + auto sorted_slots_end = sorted_slots; + auto in_chain = [](const ALeffectslot *slot1, const ALeffectslot *slot2) noexcept -> bool + { + while((slot1=slot1->Params.Target) != nullptr) { + if(slot1 == slot2) return true; + } + return false; + }; + + *sorted_slots_end = *slots; + ++sorted_slots_end; + while(++slots != slots_end) + { + /* If this effect slot targets an effect slot already in the list (i.e. + * slots outputs to something in sorted_slots), directly or indirectly, + * insert it prior to that element. + */ + auto checker = sorted_slots; + do { + if(in_chain(*slots, *checker)) break; + } while(++checker != sorted_slots_end); + + checker = std::move_backward(checker, sorted_slots_end, sorted_slots_end+1); + *--checker = *slots; + ++sorted_slots_end; + } + + std::for_each(sorted_slots, sorted_slots_end, [SamplesToDo](const ALeffectslot *slot) -> void { EffectState *state{slot->Params.mEffectState}; diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 539cee53..04f00758 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -78,6 +78,7 @@ struct ALeffectslot { struct { ALfloat Gain{1.0f}; ALboolean AuxSendAuto{AL_TRUE}; + ALeffectslot *Target{nullptr}; ALenum EffectType{AL_EFFECT_NULL}; ALeffectProps EffectProps{}; diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index db22ca4c..ca279aee 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -71,10 +71,11 @@ void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *cont ALsizei newcount{curarray->count + count}; /* Insert the new effect slots into the head of the array, followed by the - * existing ones. + * existing ones. Allocate twice as much space for effect slots so the + * mixer has a place to sort them. */ auto newarray = static_cast(al_calloc(DEF_ALIGN, - FAM_SIZE(ALeffectslotArray, slot, newcount))); + FAM_SIZE(ALeffectslotArray, slot, newcount*2))); newarray->count = newcount; auto slotiter = std::transform(slotids, slotids+count, newarray->slot, [context](ALuint id) noexcept -> ALeffectslot* @@ -99,7 +100,7 @@ void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *cont { curarray = newarray; newarray = static_cast(al_calloc(DEF_ALIGN, - FAM_SIZE(ALeffectslotArray, slot, newcount))); + FAM_SIZE(ALeffectslotArray, slot, newcount*2))); newarray->count = newcount; std::copy_n(curarray->slot, newcount, newarray->slot); al_free(curarray); @@ -122,7 +123,7 @@ void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *c * any) of the effect slots to remove are in the array. */ auto newarray = static_cast(al_calloc(DEF_ALIGN, - FAM_SIZE(ALeffectslotArray, slot, curarray->count))); + FAM_SIZE(ALeffectslotArray, slot, curarray->count*2))); /* Copy each element in curarray to newarray whose ID is not in slotids. */ const ALuint *slotids_end{slotids + count}; -- cgit v1.2.3 From 3fe38fed7c29869a43b42d634417452b1a5fedbc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 23 Dec 2018 08:51:28 -0800 Subject: Mix effect slot output to the effect target if it's set --- Alc/effects/autowah.cpp | 21 ++++++++++++++++----- Alc/effects/chorus.cpp | 22 +++++++++++++++++----- Alc/effects/compressor.cpp | 24 +++++++++++++++++------- Alc/effects/dedicated.cpp | 16 ++++++++++++++-- Alc/effects/distortion.cpp | 13 ++++++++++++- Alc/effects/echo.cpp | 24 +++++++++++++++++------- Alc/effects/equalizer.cpp | 21 ++++++++++++++++----- Alc/effects/fshifter.cpp | 13 ++++++++++++- Alc/effects/modulator.cpp | 21 ++++++++++++++++----- Alc/effects/pshifter.cpp | 23 ++++++++++++++++------- Alc/effects/reverb.cpp | 39 +++++++++++++++++++++++---------------- Alc/panning.cpp | 3 +++ OpenAL32/Include/alu.h | 2 ++ 13 files changed, 181 insertions(+), 61 deletions(-) diff --git a/Alc/effects/autowah.cpp b/Alc/effects/autowah.cpp index e034c610..e455acf2 100644 --- a/Alc/effects/autowah.cpp +++ b/Alc/effects/autowah.cpp @@ -119,11 +119,22 @@ void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, mFreqMinNorm = MIN_FREQ / device->Frequency; mBandwidthNorm = (MAX_FREQ-MIN_FREQ) / device->Frequency; - mOutBuffer = device->FOAOut.Buffer; - mOutChannels = device->FOAOut.NumChannels; - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&device->FOAOut, alu::Matrix::Identity()[i].data(), slot->Params.Gain, - mChans[i].TargetGains); + if(ALeffectslot *target{slot->Params.Target}) + { + mOutBuffer = target->WetBuffer; + mOutChannels = target->NumChannels; + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(target, alu::Matrix::Identity()[i].data(), slot->Params.Gain, + mChans[i].TargetGains); + } + else + { + mOutBuffer = device->FOAOut.Buffer; + mOutChannels = device->FOAOut.NumChannels; + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(&device->FOAOut, alu::Matrix::Identity()[i].data(), slot->Params.Gain, + mChans[i].TargetGains); + } } void ALautowahState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp index 925cd09f..1a444525 100644 --- a/Alc/effects/chorus.cpp +++ b/Alc/effects/chorus.cpp @@ -146,11 +146,23 @@ void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, co mFeedback = props->Chorus.Feedback; /* Gains for left and right sides */ - ALfloat coeffs[MAX_AMBI_COEFFS]; - CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, mGains[0].Target); - CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, mGains[1].Target); + ALfloat coeffs[2][MAX_AMBI_COEFFS]; + CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs[0]); + CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs[1]); + if(ALeffectslot *target{Slot->Params.Target}) + { + mOutBuffer = target->WetBuffer; + mOutChannels = target->NumChannels; + ComputePanGains(target, coeffs[0], Slot->Params.Gain, mGains[0].Target); + ComputePanGains(target, coeffs[1], Slot->Params.Gain, mGains[1].Target); + } + else + { + mOutBuffer = device->Dry.Buffer; + mOutChannels = device->Dry.NumChannels; + ComputePanGains(&device->Dry, coeffs[0], Slot->Params.Gain, mGains[0].Target); + ComputePanGains(&device->Dry, coeffs[1], Slot->Params.Gain, mGains[1].Target); + } ALfloat rate{props->Chorus.Rate}; if(!(rate > 0.0f)) diff --git a/Alc/effects/compressor.cpp b/Alc/effects/compressor.cpp index d502be43..8505f161 100644 --- a/Alc/effects/compressor.cpp +++ b/Alc/effects/compressor.cpp @@ -74,15 +74,25 @@ ALboolean ALcompressorState::deviceUpdate(const ALCdevice *device) void ALcompressorState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) { - const ALCdevice *device = context->Device; - mEnabled = props->Compressor.OnOff; - mOutBuffer = device->FOAOut.Buffer; - mOutChannels = device->FOAOut.NumChannels; - for(ALsizei i{0};i < 4;i++) - ComputePanGains(&device->FOAOut, alu::Matrix::Identity()[i].data(), - slot->Params.Gain, mGain[i]); + if(ALeffectslot *target{slot->Params.Target}) + { + mOutBuffer = target->WetBuffer; + mOutChannels = target->NumChannels; + for(ALsizei i{0};i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(target, alu::Matrix::Identity()[i].data(), slot->Params.Gain, + mGain[i]); + } + else + { + const ALCdevice *device{context->Device}; + mOutBuffer = device->FOAOut.Buffer; + mOutChannels = device->FOAOut.NumChannels; + for(ALsizei i{0};i < 4;i++) + ComputePanGains(&device->FOAOut, alu::Matrix::Identity()[i].data(), + slot->Params.Gain, mGain[i]); + } } void ALcompressorState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/dedicated.cpp b/Alc/effects/dedicated.cpp index fa550397..851e48a5 100644 --- a/Alc/effects/dedicated.cpp +++ b/Alc/effects/dedicated.cpp @@ -52,11 +52,23 @@ ALboolean ALdedicatedState::deviceUpdate(const ALCdevice *UNUSED(device)) void ALdedicatedState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) { const ALCdevice *device = context->Device; - ALfloat Gain; std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f); - Gain = slot->Params.Gain * props->Dedicated.Gain; + const ALfloat Gain{slot->Params.Gain * props->Dedicated.Gain}; + if(ALeffectslot *target{slot->Params.Target}) + { + mOutBuffer = target->WetBuffer; + mOutChannels = target->NumChannels; + if(slot->Params.EffectType == AL_EFFECT_DEDICATED_DIALOGUE) + { + ALfloat coeffs[MAX_AMBI_COEFFS]; + CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); + ComputePanGains(target, coeffs, Gain, mTargetGains); + } + return; + } + if(slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) { int idx; diff --git a/Alc/effects/distortion.cpp b/Alc/effects/distortion.cpp index 58d05e8f..eb4ff975 100644 --- a/Alc/effects/distortion.cpp +++ b/Alc/effects/distortion.cpp @@ -90,7 +90,18 @@ void ALdistortionState::update(const ALCcontext *context, const ALeffectslot *sl ); CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain*props->Distortion.Gain, mGain); + if(ALeffectslot *target{slot->Params.Target}) + { + mOutBuffer = target->WetBuffer; + mOutChannels = target->NumChannels; + ComputePanGains(target, coeffs, slot->Params.Gain*props->Distortion.Gain, mGain); + } + else + { + mOutBuffer = device->Dry.Buffer; + mOutChannels = device->Dry.NumChannels; + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain*props->Distortion.Gain, mGain); + } } void ALdistortionState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index b9310193..dae99912 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -94,7 +94,6 @@ void ALechoState::update(const ALCcontext *context, const ALeffectslot *slot, co { const ALCdevice *device = context->Device; ALuint frequency = device->Frequency; - ALfloat coeffs[MAX_AMBI_COEFFS]; ALfloat gainhf, lrpan, spread; mTap[0].delay = maxi(float2int(props->Echo.Delay*frequency + 0.5f), 1); @@ -116,13 +115,24 @@ void ALechoState::update(const ALCcontext *context, const ALeffectslot *slot, co calc_rcpQ_from_slope(gainhf, 1.0f) ); - /* First tap panning */ - CalcAngleCoeffs(-F_PI_2*lrpan, 0.0f, spread, coeffs); - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, mGains[0].Target); + ALfloat coeffs[2][MAX_AMBI_COEFFS]; + CalcAngleCoeffs(-F_PI_2*lrpan, 0.0f, spread, coeffs[0]); + CalcAngleCoeffs( F_PI_2*lrpan, 0.0f, spread, coeffs[1]); - /* Second tap panning */ - CalcAngleCoeffs( F_PI_2*lrpan, 0.0f, spread, coeffs); - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, mGains[1].Target); + if(ALeffectslot *target{slot->Params.Target}) + { + mOutBuffer = target->WetBuffer; + mOutChannels = target->NumChannels; + ComputePanGains(target, coeffs[0], slot->Params.Gain, mGains[0].Target); + ComputePanGains(target, coeffs[1], slot->Params.Gain, mGains[1].Target); + } + else + { + mOutBuffer = device->Dry.Buffer; + mOutChannels = device->Dry.NumChannels; + ComputePanGains(&device->Dry, coeffs[0], slot->Params.Gain, mGains[0].Target); + ComputePanGains(&device->Dry, coeffs[1], slot->Params.Gain, mGains[1].Target); + } } void ALechoState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index a10316e8..53975d19 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -152,11 +152,22 @@ void ALequalizerState::update(const ALCcontext *context, const ALeffectslot *slo mChans[i].filter[3].copyParamsFrom(mChans[0].filter[3]); } - mOutBuffer = device->FOAOut.Buffer; - mOutChannels = device->FOAOut.NumChannels; - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&device->FOAOut, alu::Matrix::Identity()[i].data(), slot->Params.Gain, - mChans[i].TargetGains); + if(ALeffectslot *target{slot->Params.Target}) + { + mOutBuffer = target->WetBuffer; + mOutChannels = target->NumChannels; + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(target, alu::Matrix::Identity()[i].data(), slot->Params.Gain, + mChans[i].TargetGains); + } + else + { + mOutBuffer = device->FOAOut.Buffer; + mOutChannels = device->FOAOut.NumChannels; + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(&device->FOAOut, alu::Matrix::Identity()[i].data(), slot->Params.Gain, + mChans[i].TargetGains); + } } void ALequalizerState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp index 9b6d700c..e8311620 100644 --- a/Alc/effects/fshifter.cpp +++ b/Alc/effects/fshifter.cpp @@ -132,7 +132,18 @@ void ALfshifterState::update(const ALCcontext *context, const ALeffectslot *slot ALfloat coeffs[MAX_AMBI_COEFFS]; CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, mTargetGains); + if(ALeffectslot *target{slot->Params.Target}) + { + mOutBuffer = target->WetBuffer; + mOutChannels = target->NumChannels; + ComputePanGains(target, coeffs, slot->Params.Gain, mTargetGains); + } + else + { + mOutBuffer = device->Dry.Buffer; + mOutChannels = device->Dry.NumChannels; + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, mTargetGains); + } } void ALfshifterState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index d686c362..84aa0e2c 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -131,11 +131,22 @@ void ALmodulatorState::update(const ALCcontext *context, const ALeffectslot *slo for(i = 1;i < MAX_EFFECT_CHANNELS;i++) mChans[i].Filter.copyParamsFrom(mChans[0].Filter); - mOutBuffer = device->FOAOut.Buffer; - mOutChannels = device->FOAOut.NumChannels; - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&device->FOAOut, alu::Matrix::Identity()[i].data(), slot->Params.Gain, - mChans[i].TargetGains); + if(ALeffectslot *target{slot->Params.Target}) + { + mOutBuffer = target->WetBuffer; + mOutChannels = target->NumChannels; + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(target, alu::Matrix::Identity()[i].data(), slot->Params.Gain, + mChans[i].TargetGains); + } + else + { + mOutBuffer = device->FOAOut.Buffer; + mOutChannels = device->FOAOut.NumChannels; + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(&device->FOAOut, alu::Matrix::Identity()[i].data(), slot->Params.Gain, + mChans[i].TargetGains); + } } void ALmodulatorState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp index 3825bfd5..321e7492 100644 --- a/Alc/effects/pshifter.cpp +++ b/Alc/effects/pshifter.cpp @@ -175,18 +175,27 @@ ALboolean ALpshifterState::deviceUpdate(const ALCdevice *device) void ALpshifterState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) { - const ALCdevice *device = context->Device; - ALfloat coeffs[MAX_AMBI_COEFFS]; - float pitch; - - pitch = std::pow(2.0f, + const float pitch{std::pow(2.0f, (ALfloat)(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f - ); + )}; mPitchShiftI = fastf2i(pitch*FRACTIONONE); mPitchShift = mPitchShiftI * (1.0f/FRACTIONONE); + ALfloat coeffs[MAX_AMBI_COEFFS]; CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, mTargetGains); + if(ALeffectslot *target{slot->Params.Target}) + { + mOutBuffer = target->WetBuffer; + mOutChannels = target->NumChannels; + ComputePanGains(target, coeffs, slot->Params.Gain, mTargetGains); + } + else + { + const ALCdevice *device{context->Device}; + mOutBuffer = device->Dry.Buffer; + mOutChannels = device->Dry.NumChannels; + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, mTargetGains); + } } void ALpshifterState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index b70e3d45..a84749d8 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -763,11 +763,8 @@ alu::Matrix GetTransformFromVector(const ALfloat *vec) } /* Update the early and late 3D panning gains. */ -ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, const ALfloat earlyGain, const ALfloat lateGain, ReverbState *State) +ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, const ALfloat earlyGain, const ALfloat lateGain, ALeffectslot *target, ReverbState *State) { - State->mOutBuffer = Device->FOAOut.Buffer; - State->mOutChannels = Device->FOAOut.NumChannels; - /* Note: ret is transposed. */ auto MatrixMult = [](const alu::Matrix &m1, const alu::Matrix &m2) noexcept -> alu::Matrix { @@ -784,17 +781,27 @@ ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, c /* Create a matrix that first converts A-Format to B-Format, then * transforms the B-Format signal according to the panning vector. */ - alu::Matrix rot{GetTransformFromVector(ReflectionsPan)}; - alu::Matrix transform{MatrixMult(rot, A2B)}; - for(ALsizei i{0};i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&Device->FOAOut, transform[i].data(), earlyGain, - State->mEarly.PanGain[i]); - - rot = GetTransformFromVector(LateReverbPan); - transform = MatrixMult(rot, A2B); - for(ALsizei i{0};i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&Device->FOAOut, transform[i].data(), lateGain, - State->mLate.PanGain[i]); + alu::Matrix earlymat{MatrixMult(GetTransformFromVector(ReflectionsPan), A2B)}; + alu::Matrix latemat{MatrixMult(GetTransformFromVector(LateReverbPan), A2B)}; + if(target) + { + State->mOutBuffer = target->WetBuffer; + State->mOutChannels = target->NumChannels; + for(ALsizei i{0};i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(target, earlymat[i].data(), earlyGain, State->mEarly.PanGain[i]); + for(ALsizei i{0};i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(target, latemat[i].data(), lateGain, State->mLate.PanGain[i]); + } + else + { + State->mOutBuffer = Device->FOAOut.Buffer; + State->mOutChannels = Device->FOAOut.NumChannels; + for(ALsizei i{0};i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(&Device->FOAOut, earlymat[i].data(), earlyGain, + State->mEarly.PanGain[i]); + for(ALsizei i{0};i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(&Device->FOAOut, latemat[i].data(), lateGain, State->mLate.PanGain[i]); + } } void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) @@ -858,7 +865,7 @@ void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, co const ALfloat gain{props->Reverb.Gain * Slot->Params.Gain * ReverbBoost}; Update3DPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain, - this); + Slot->Params.Target, this); /* Calculate the max update size from the smallest relevant delay. */ mMaxUpdate[1] = mini(MAX_UPDATE_SAMPLES, mini(mEarly.Offset[0][1], mLate.Offset[0][1])); diff --git a/Alc/panning.cpp b/Alc/panning.cpp index f15c086e..cec6eaf7 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -867,6 +867,9 @@ void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, con std::fill(iter, std::end(gains), 0.0f); } +void ComputePanGains(const ALeffectslot *slot, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) +{ ComputePanningGainsBF(slot->ChanMap, slot->NumChannels, coeffs, ingain, gains); } + void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appreq, HrtfRequestMode hrtf_userreq) { diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 2b7be726..695fc380 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -476,6 +476,8 @@ inline void ComputePanGains(const MixParams *dry, const ALfloat*RESTRICT coeffs, ComputePanningGainsBF(dry->Ambi.Map, dry->NumChannels, coeffs, ingain, gains); } +void ComputePanGains(const ALeffectslot *slot, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]); + ALboolean MixSource(struct ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo); -- cgit v1.2.3 From ba9aba699d00bf2d2f29d298d24dfc87eb5e7904 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 23 Dec 2018 10:37:07 -0800 Subject: Properly rebalance the HF scale with ambisonic upsampling --- Alc/bformatdec.cpp | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index d0d1325a..e9ff2b76 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -49,9 +49,23 @@ constexpr ALfloat Ambi3DDecoderHFScale[MAX_AMBI_COEFFS] = { 2.0f, 1.15470054f, 1.15470054f, 1.15470054f }; +constexpr ALfloat Ambi3DDecoderHFScale2O[MAX_AMBI_COEFFS] = { + 1.49071198f, + 1.15470054f, 1.15470054f, 1.15470054f +}; +constexpr ALfloat Ambi3DDecoderHFScale3O[MAX_AMBI_COEFFS] = { + 1.17958441f, + 1.01578297f, 1.01578297f, 1.01578297f +}; +inline auto GetDecoderHFScales(ALsizei order) noexcept -> const ALfloat(&)[MAX_AMBI_COEFFS] +{ + if(order >= 3) return Ambi3DDecoderHFScale3O; + if(order == 2) return Ambi3DDecoderHFScale2O; + return Ambi3DDecoderHFScale; +} -auto GetAmbiScales(AmbDecScale scaletype) noexcept -> const std::array& +inline auto GetAmbiScales(AmbDecScale scaletype) noexcept -> const std::array& { if(scaletype == AmbDecScale::FuMa) return AmbiScale::FromFuMa; if(scaletype == AmbDecScale::SN3D) return AmbiScale::FromSN3D; @@ -77,10 +91,15 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, { return mask | (1 << chan); } ); - mUpSampler[0].XOver.init(400.0f / (float)srate); + mUpSampler[0].XOver.init(conf->XOverFreq / (float)srate); std::fill(std::begin(mUpSampler[0].Gains), std::end(mUpSampler[0].Gains), 0.0f); std::fill(std::begin(mUpSampler)+1, std::end(mUpSampler), mUpSampler[0]); + const ALsizei out_order{ + (conf->ChanMask > AMBI_3ORDER_MASK) ? 4 : + (conf->ChanMask > AMBI_2ORDER_MASK) ? 3 : + (conf->ChanMask > AMBI_1ORDER_MASK) ? 2 : 1 + }; const bool periphonic{(conf->ChanMask&AMBI_PERIPHONIC_MASK) != 0}; if(periphonic) { @@ -92,12 +111,13 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, std::copy(std::begin(coeffs), std::begin(coeffs)+chancount, std::begin(encgains[k])); } assert(chancount >= 4); + const ALfloat (&hfscales)[MAX_AMBI_COEFFS] = GetDecoderHFScales(out_order); for(ALsizei i{0};i < 4;i++) { ALdouble gain{0.0}; for(size_t k{0u};k < COUNTOF(Ambi3DDecoder);k++) gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][i]; - mUpSampler[i].Gains[HF_BAND] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]); + mUpSampler[i].Gains[HF_BAND] = (ALfloat)(gain*Ambi3DDecoderHFScale[i]/hfscales[i]); mUpSampler[i].Gains[LF_BAND] = (ALfloat)gain; } } @@ -115,13 +135,14 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, ); } assert(chancount >= 3); + const ALfloat (&hfscales)[MAX_AMBI_COEFFS] = GetDecoderHFScales(out_order); for(ALsizei c{0};c < 3;c++) { const ALsizei i{AmbiIndex::From2D[c]}; ALdouble gain{0.0}; for(size_t k{0u};k < COUNTOF(Ambi3DDecoder);k++) gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][c]; - mUpSampler[c].Gains[HF_BAND] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]); + mUpSampler[c].Gains[HF_BAND] = (ALfloat)(gain*Ambi3DDecoderHFScale[i]/hfscales[i]); mUpSampler[c].Gains[LF_BAND] = (ALfloat)gain; } mUpSampler[3].Gains[HF_BAND] = 0.0f; @@ -273,15 +294,21 @@ void AmbiUpsampler::reset(const ALCdevice *device) * and output are transposed, so the input channels line up with the rows * and the output channels line up with the columns. */ + const ALfloat (&hfscales)[MAX_AMBI_COEFFS] = GetDecoderHFScales( + (device->Dry.NumChannels > 16) ? 4 : + (device->Dry.NumChannels > 9) ? 3 : + (device->Dry.NumChannels > 4) ? 2 : 1 + ); mGains.fill({}); for(ALsizei i{0};i < 4;i++) { + const ALdouble hfscale = static_cast(Ambi3DDecoderHFScale[i]) / hfscales[i]; for(ALsizei j{0};j < device->Dry.NumChannels;j++) { ALdouble gain{0.0}; for(size_t k{0u};k < COUNTOF(Ambi3DDecoder);k++) gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][j]; - mGains[i][HF_BAND][j] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]); + mGains[i][HF_BAND][j] = (ALfloat)(gain * hfscale); mGains[i][LF_BAND][j] = (ALfloat)gain; } } -- cgit v1.2.3 From 11d815cfd304da3f1a0fd4178db932ad6c47d8ce Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 23 Dec 2018 15:55:12 -0800 Subject: Repack some AmbiUpsampler fields for better access patterns --- Alc/bformatdec.cpp | 25 +++++++++++++------------ Alc/bformatdec.h | 9 +++++---- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index e9ff2b76..b22784c1 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -278,8 +278,9 @@ void BFormatDec::upSample(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALflo void AmbiUpsampler::reset(const ALCdevice *device) { - mXOver[0].init(400.0f / (float)device->Frequency); - std::fill(std::begin(mXOver)+1, std::end(mXOver), mXOver[0]); + mInput[0].XOver.init(400.0f / (float)device->Frequency); + for(auto input = std::begin(mInput)+1;input != std::end(mInput);++input) + input->XOver = mInput[0].XOver; ALfloat encgains[8][MAX_OUTPUT_CHANNELS]; for(size_t k{0u};k < COUNTOF(Ambi3DPoints);k++) @@ -299,30 +300,30 @@ void AmbiUpsampler::reset(const ALCdevice *device) (device->Dry.NumChannels > 9) ? 3 : (device->Dry.NumChannels > 4) ? 2 : 1 ); - mGains.fill({}); for(ALsizei i{0};i < 4;i++) { + mInput[i].Gains.fill({}); const ALdouble hfscale = static_cast(Ambi3DDecoderHFScale[i]) / hfscales[i]; for(ALsizei j{0};j < device->Dry.NumChannels;j++) { ALdouble gain{0.0}; for(size_t k{0u};k < COUNTOF(Ambi3DDecoder);k++) gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][j]; - mGains[i][HF_BAND][j] = (ALfloat)(gain * hfscale); - mGains[i][LF_BAND][j] = (ALfloat)gain; + mInput[i].Gains[HF_BAND][j] = (ALfloat)(gain * hfscale); + mInput[i].Gains[LF_BAND][j] = (ALfloat)gain; } } } -void AmbiUpsampler::process(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei SamplesToDo) +void AmbiUpsampler::process(ALfloat (*OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*InSamples)[BUFFERSIZE], const ALsizei SamplesToDo) { - for(ALsizei i{0};i < 4;i++) + for(auto input = std::begin(mInput);input != std::end(mInput);++input) { - mXOver[i].process(mSamples[HF_BAND], mSamples[LF_BAND], InSamples[i], SamplesToDo); + input->XOver.process(mSamples[HF_BAND], mSamples[LF_BAND], *(InSamples++), SamplesToDo); - MixSamples(mSamples[HF_BAND], OutChannels, OutBuffer, mGains[i][HF_BAND].data(), - mGains[i][HF_BAND].data(), 0, 0, SamplesToDo); - MixSamples(mSamples[LF_BAND], OutChannels, OutBuffer, mGains[i][LF_BAND].data(), - mGains[i][LF_BAND].data(), 0, 0, SamplesToDo); + MixSamples(mSamples[HF_BAND], OutChannels, OutBuffer, input->Gains[HF_BAND].data(), + input->Gains[HF_BAND].data(), 0, 0, SamplesToDo); + MixSamples(mSamples[LF_BAND], OutChannels, OutBuffer, input->Gains[LF_BAND].data(), + input->Gains[LF_BAND].data(), 0, 0, SamplesToDo); } } diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index b5824545..ba6ceaa2 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -62,13 +62,14 @@ public: private: alignas(16) ALfloat mSamples[sNumBands][BUFFERSIZE]; - BandSplitter mXOver[4]; - - std::array,sNumBands>,4> mGains; + struct { + BandSplitter XOver; + std::array,sNumBands> Gains; + } mInput[4]; public: void reset(const ALCdevice *device); - void process(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei SamplesToDo); + void process(ALfloat (*OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*InSamples)[BUFFERSIZE], const ALsizei SamplesToDo); DEF_NEWDEL(AmbiUpsampler) }; -- cgit v1.2.3 From 1f966c11ef5728b446203212b62191ab440a1ee3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 23 Dec 2018 17:56:01 -0800 Subject: Add some more ASSUMEs --- Alc/alu.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 3ea82354..45c47008 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1514,8 +1514,12 @@ void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*RESTRICT Buffer)[BUFFERSIZE], - int lidx, int ridx, int cidx, ALsizei SamplesToDo, ALsizei NumChannels) + int lidx, int ridx, int cidx, const ALsizei SamplesToDo, + const ALsizei NumChannels) { + ASSUME(SamplesToDo > 0); + ASSUME(NumChannels > 0); + /* Apply an all-pass to all channels, except the front-left and front- * right, so they maintain the same relative phase. */ @@ -1558,6 +1562,9 @@ void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*RESTRICT Buffer)[BUFFER void ApplyDistanceComp(ALfloat (*RESTRICT Samples)[BUFFERSIZE], const DistanceComp &distcomp, ALfloat *RESTRICT Values, ALsizei SamplesToDo, ALsizei numchans) { + ASSUME(SamplesToDo > 0); + ASSUME(numchans > 0); + for(ALsizei c{0};c < numchans;c++) { ALfloat *RESTRICT inout{Samples[c]}; @@ -1565,12 +1572,12 @@ void ApplyDistanceComp(ALfloat (*RESTRICT Samples)[BUFFERSIZE], const DistanceCo const ALsizei base{distcomp[c].Length}; ALfloat *RESTRICT distbuf{distcomp[c].Buffer}; - if(base == 0) + if(base <= 0) { if(gain < 1.0f) - std::for_each(inout, inout+SamplesToDo, - [gain](ALfloat &in) noexcept -> void - { in *= gain; } + std::transform(inout, inout+SamplesToDo, inout, + [gain](const ALfloat in) noexcept -> ALfloat + { return in * gain; } ); continue; } @@ -1588,7 +1595,7 @@ void ApplyDistanceComp(ALfloat (*RESTRICT Samples)[BUFFERSIZE], const DistanceCo std::copy_n(inout, SamplesToDo, out); } std::transform(Values, Values+SamplesToDo, inout, - [gain](ALfloat in) noexcept -> ALfloat { return in * gain; } + [gain](const ALfloat in) noexcept -> ALfloat { return in * gain; } ); } } -- cgit v1.2.3 From ef101523610a26639228fd88bfd303cb31dbd025 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 23 Dec 2018 20:56:27 -0800 Subject: Assume alignment for some buffers --- Alc/alu.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 45c47008..b95f0d7c 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1530,8 +1530,8 @@ void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*RESTRICT Buffer)[BUFFER Stablizer->APFilter[i].process(Buffer[i], SamplesToDo); } - ALfloat (*RESTRICT lsplit)[BUFFERSIZE]{Stablizer->LSplit}; - ALfloat (*RESTRICT rsplit)[BUFFERSIZE]{Stablizer->RSplit}; + ALfloat (&lsplit)[2][BUFFERSIZE] = Stablizer->LSplit; + ALfloat (&rsplit)[2][BUFFERSIZE] = Stablizer->RSplit; Stablizer->LFilter.process(lsplit[1], lsplit[0], Buffer[lidx], SamplesToDo); Stablizer->RFilter.process(rsplit[1], rsplit[0], Buffer[ridx], SamplesToDo); @@ -1560,17 +1560,17 @@ void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*RESTRICT Buffer)[BUFFER } void ApplyDistanceComp(ALfloat (*RESTRICT Samples)[BUFFERSIZE], const DistanceComp &distcomp, - ALfloat *RESTRICT Values, ALsizei SamplesToDo, ALsizei numchans) + ALfloat *RESTRICT Values, const ALsizei SamplesToDo, const ALsizei numchans) { ASSUME(SamplesToDo > 0); ASSUME(numchans > 0); for(ALsizei c{0};c < numchans;c++) { - ALfloat *RESTRICT inout{Samples[c]}; + ALfloat *RESTRICT inout{al::assume_aligned<16>(Samples[c])}; const ALfloat gain{distcomp[c].Gain}; const ALsizei base{distcomp[c].Length}; - ALfloat *RESTRICT distbuf{distcomp[c].Buffer}; + ALfloat *RESTRICT distbuf{al::assume_aligned<16>(distcomp[c].Buffer)}; if(base <= 0) { @@ -1600,8 +1600,8 @@ void ApplyDistanceComp(ALfloat (*RESTRICT Samples)[BUFFERSIZE], const DistanceCo } } -void ApplyDither(ALfloat (*RESTRICT Samples)[BUFFERSIZE], ALuint *dither_seed, - const ALfloat quant_scale, const ALsizei SamplesToDo, const ALsizei numchans) +void ApplyDither(ALfloat (*Samples)[BUFFERSIZE], ALuint *dither_seed, const ALfloat quant_scale, + const ALsizei SamplesToDo, const ALsizei numchans) { ASSUME(numchans > 0); @@ -1611,9 +1611,10 @@ void ApplyDither(ALfloat (*RESTRICT Samples)[BUFFERSIZE], ALuint *dither_seed, */ const ALfloat invscale{1.0f / quant_scale}; ALuint seed{*dither_seed}; - auto dither_channel = [&seed,invscale,quant_scale,SamplesToDo](ALfloat *buffer) -> void + auto dither_channel = [&seed,invscale,quant_scale,SamplesToDo](ALfloat *input) -> void { ASSUME(SamplesToDo > 0); + ALfloat *buffer{al::assume_aligned<16>(input)}; std::transform(buffer, buffer+SamplesToDo, buffer, [&seed,invscale,quant_scale](ALfloat sample) noexcept -> ALfloat { -- cgit v1.2.3 From 68352d318863105573e5022d1fc5383ac52f5de2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 24 Dec 2018 07:30:01 -0800 Subject: Apply the limiter before distance compensation --- Alc/alu.cpp | 19 ++++++++++--------- OpenAL32/Include/alMain.h | 4 ++-- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index b95f0d7c..fbdbc4b2 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1559,12 +1559,13 @@ void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*RESTRICT Buffer)[BUFFER } } -void ApplyDistanceComp(ALfloat (*RESTRICT Samples)[BUFFERSIZE], const DistanceComp &distcomp, - ALfloat *RESTRICT Values, const ALsizei SamplesToDo, const ALsizei numchans) +void ApplyDistanceComp(ALfloat (*Samples)[BUFFERSIZE], const DistanceComp &distcomp, + ALfloat (&Values)[BUFFERSIZE], const ALsizei SamplesToDo, const ALsizei numchans) { ASSUME(SamplesToDo > 0); ASSUME(numchans > 0); + ALfloat *RESTRICT tempvals{al::assume_aligned<16>(&Values[0])}; for(ALsizei c{0};c < numchans;c++) { ALfloat *RESTRICT inout{al::assume_aligned<16>(Samples[c])}; @@ -1584,17 +1585,17 @@ void ApplyDistanceComp(ALfloat (*RESTRICT Samples)[BUFFERSIZE], const DistanceCo if(LIKELY(SamplesToDo >= base)) { - auto out = std::copy_n(distbuf, base, Values); + auto out = std::copy_n(distbuf, base, tempvals); std::copy_n(inout, SamplesToDo-base, out); std::copy_n(inout+SamplesToDo-base, base, distbuf); } else { - std::copy_n(distbuf, SamplesToDo, Values); + std::copy_n(distbuf, SamplesToDo, tempvals); auto out = std::copy(distbuf+SamplesToDo, distbuf+base, distbuf); std::copy_n(inout, SamplesToDo, out); } - std::transform(Values, Values+SamplesToDo, inout, + std::transform(tempvals, tempvals+SamplesToDo, inout, [gain](const ALfloat in) noexcept -> ALfloat { return in * gain; } ); } @@ -1743,14 +1744,14 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) SamplesToDo, device->RealOut.NumChannels); } + /* Apply compression, limiting sample amplitude if needed or desired. */ + if(device->Limiter) + ApplyCompression(device->Limiter.get(), SamplesToDo, device->RealOut.Buffer); + /* Apply delays and attenuation for mismatched speaker distances. */ ApplyDistanceComp(device->RealOut.Buffer, device->ChannelDelay, device->TempBuffer[0], SamplesToDo, device->RealOut.NumChannels); - /* Apply compression, limiting final sample amplitude, if desired. */ - if(device->Limiter) - ApplyCompression(device->Limiter.get(), SamplesToDo, device->RealOut.Buffer); - /* Apply dithering. The compressor should have left enough headroom for * the dither noise to not saturate. */ diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index bc1dc222..3ed11193 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -778,11 +778,11 @@ struct ALCdevice_struct { std::unique_ptr Stablizer; + std::unique_ptr Limiter; + /* Delay buffers used to compensate for speaker distances. */ DistanceComp ChannelDelay; - std::unique_ptr Limiter; - /* Dithering control. */ ALfloat DitherDepth{0.0f}; ALuint DitherSeed{0u}; -- cgit v1.2.3 From d49eeb576cbcba966f56aed0dccbdd4694ffbaf7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 24 Dec 2018 07:33:38 -0800 Subject: Only check ambisonic attributes with B-Format output --- Alc/alc.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index a5353cb9..ad47e43c 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1721,19 +1721,22 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) WARN("Missing format for loopback device\n"); return ALC_INVALID_VALUE; } - if(schans == ALC_BFORMAT3D_SOFT && (!alayout || !ascale || !aorder)) - { - WARN("Missing ambisonic info for loopback device\n"); - return ALC_INVALID_VALUE; - } if(!IsValidALCChannels(schans) || !IsValidALCType(stype) || freq < MIN_OUTPUT_RATE) return ALC_INVALID_VALUE; - if(!IsValidAmbiLayout(alayout) || !IsValidAmbiScaling(ascale)) - return ALC_INVALID_VALUE; - if(aorder < 1 || aorder > MAX_AMBI_ORDER) - return ALC_INVALID_VALUE; - if((alayout == ALC_FUMA_SOFT || ascale == ALC_FUMA_SOFT) && aorder > 3) - return ALC_INVALID_VALUE; + if(schans == ALC_BFORMAT3D_SOFT) + { + if(!alayout || !ascale || !aorder) + { + WARN("Missing ambisonic info for loopback device\n"); + return ALC_INVALID_VALUE; + } + if(!IsValidAmbiLayout(alayout) || !IsValidAmbiScaling(ascale)) + return ALC_INVALID_VALUE; + if(aorder < 1 || aorder > MAX_AMBI_ORDER) + return ALC_INVALID_VALUE; + if((alayout == ALC_FUMA_SOFT || ascale == ALC_FUMA_SOFT) && aorder > 3) + return ALC_INVALID_VALUE; + } } if((device->Flags&DEVICE_RUNNING)) -- cgit v1.2.3 From 95631aa358a99b5f70a3edcebf2b76d1d4ae5af2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 24 Dec 2018 09:17:00 -0800 Subject: Make the Compressor more class-like --- Alc/alc.cpp | 11 ++- Alc/alu.cpp | 4 +- Alc/mastering.cpp | 238 ++++++++++++++++++++++++++++-------------------------- Alc/mastering.h | 62 +++++++------- 4 files changed, 162 insertions(+), 153 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index ad47e43c..c225eaf2 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1550,7 +1550,7 @@ static void alcSetError(ALCdevice *device, ALCenum errorCode) } -static Compressor *CreateDeviceLimiter(const ALCdevice *device, const ALfloat threshold) +static std::unique_ptr CreateDeviceLimiter(const ALCdevice *device, const ALfloat threshold) { return CompressorInit(device->RealOut.NumChannels, device->Frequency, AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, 0.001f, 0.002f, @@ -1816,6 +1816,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->Uhj_Encoder = nullptr; device->Bs2b = nullptr; + device->Limiter = nullptr; device->ChannelDelay.clear(); device->ChannelDelay.shrink_to_fit(); @@ -2044,14 +2045,12 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(device->DitherDepth > 0.0f) thrshld -= 1.0f / device->DitherDepth; - device->Limiter.reset(CreateDeviceLimiter(device, std::log10(thrshld) * 20.0f)); + auto limiter = CreateDeviceLimiter(device, std::log10(thrshld) * 20.0f); /* Convert the lookahead from samples to nanosamples to nanoseconds. */ device->FixedLatency += std::chrono::duration_cast( - std::chrono::seconds(GetCompressorLookAhead(device->Limiter.get())) - ) / device->Frequency; + std::chrono::seconds(limiter->getLookAhead())) / device->Frequency; + device->Limiter = std::move(limiter); } - else - device->Limiter = nullptr; TRACE("Output limiter %s\n", device->Limiter ? "enabled" : "disabled"); aluSelectPostProcess(device); diff --git a/Alc/alu.cpp b/Alc/alu.cpp index fbdbc4b2..1917dd9d 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1745,8 +1745,8 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) } /* Apply compression, limiting sample amplitude if needed or desired. */ - if(device->Limiter) - ApplyCompression(device->Limiter.get(), SamplesToDo, device->RealOut.Buffer); + if(Compressor *comp{device->Limiter.get()}) + comp->process(SamplesToDo, device->RealOut.Buffer); /* Apply delays and attenuation for mismatched speaker distances. */ ApplyDistanceComp(device->RealOut.Buffer, device->ChannelDelay, device->TempBuffer[0], diff --git a/Alc/mastering.cpp b/Alc/mastering.cpp index bdd67aa4..e886b127 100644 --- a/Alc/mastering.cpp +++ b/Alc/mastering.cpp @@ -15,11 +15,11 @@ static_assert((BUFFERSIZE & (BUFFERSIZE-1)) == 0, "BUFFERSIZE is not a power of 2"); struct SlidingHold { - ALfloat Values[BUFFERSIZE]; - ALsizei Expiries[BUFFERSIZE]; - ALsizei LowerIndex; - ALsizei UpperIndex; - ALsizei Length; + ALfloat mValues[BUFFERSIZE]; + ALsizei mExpiries[BUFFERSIZE]; + ALsizei mLowerIndex; + ALsizei mUpperIndex; + ALsizei mLength; }; @@ -34,14 +34,17 @@ using namespace std::placeholders; * * http://www.richardhartersworld.com/cri/2001/slidingmin.html */ -static ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALfloat in) +ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALfloat in) { static constexpr ALsizei mask{BUFFERSIZE - 1}; - const ALsizei length{Hold->Length}; - ALfloat (&values)[BUFFERSIZE] = Hold->Values; - ALsizei (&expiries)[BUFFERSIZE] = Hold->Expiries; - ALsizei lowerIndex{Hold->LowerIndex}; - ALsizei upperIndex{Hold->UpperIndex}; + const ALsizei length{Hold->mLength}; + ALfloat (&values)[BUFFERSIZE] = Hold->mValues; + ALsizei (&expiries)[BUFFERSIZE] = Hold->mExpiries; + ALsizei lowerIndex{Hold->mLowerIndex}; + ALsizei upperIndex{Hold->mUpperIndex}; + + ASSUME(upperIndex >= 0); + ASSUME(lowerIndex >= 0); if(i >= expiries[upperIndex]) upperIndex = (upperIndex + 1) & mask; @@ -68,41 +71,42 @@ static ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALflo expiries[lowerIndex] = i + length; } - Hold->LowerIndex = lowerIndex; - Hold->UpperIndex = upperIndex; + Hold->mLowerIndex = lowerIndex; + Hold->mUpperIndex = upperIndex; return values[upperIndex]; } -static void ShiftSlidingHold(SlidingHold *Hold, const ALsizei n) +void ShiftSlidingHold(SlidingHold *Hold, const ALsizei n) { - ASSUME(Hold->UpperIndex >= 0); - ASSUME(Hold->LowerIndex >= 0); + ASSUME(Hold->mUpperIndex >= 0); + ASSUME(Hold->mLowerIndex >= 0); - auto exp_begin = std::begin(Hold->Expiries) + Hold->UpperIndex; - auto exp_last = std::begin(Hold->Expiries) + Hold->LowerIndex; + auto exp_begin = std::begin(Hold->mExpiries) + Hold->mUpperIndex; + auto exp_last = std::begin(Hold->mExpiries) + Hold->mLowerIndex; if(exp_last < exp_begin) { - std::transform(exp_begin, std::end(Hold->Expiries), exp_begin, + std::transform(exp_begin, std::end(Hold->mExpiries), exp_begin, std::bind(std::minus{}, _1, n)); - exp_begin = std::begin(Hold->Expiries); + exp_begin = std::begin(Hold->mExpiries); } std::transform(exp_begin, exp_last+1, exp_begin, std::bind(std::minus{}, _1, n)); } + /* Multichannel compression is linked via the absolute maximum of all * channels. */ void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, const ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]) { - const ALsizei index{Comp->LookAhead}; - const ALsizei numChans{Comp->NumChans}; + const ALsizei index{Comp->mLookAhead}; + const ALsizei numChans{Comp->mNumChans}; ASSUME(SamplesToDo > 0); ASSUME(numChans > 0); ASSUME(index >= 0); - auto side_begin = std::begin(Comp->SideChain) + index; + auto side_begin = std::begin(Comp->mSideChain) + index; std::fill(side_begin, side_begin+SamplesToDo, 0.0f); auto fill_max = [SamplesToDo,side_begin](const ALfloat *input) -> void @@ -121,10 +125,10 @@ void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, const ALfloat (*R */ static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo) { - const ALfloat a_crest{Comp->CrestCoeff}; - const ALsizei index{Comp->LookAhead}; - ALfloat y2_peak{Comp->LastPeakSq}; - ALfloat y2_rms{Comp->LastRmsSq}; + const ALfloat a_crest{Comp->mCrestCoeff}; + const ALsizei index{Comp->mLookAhead}; + ALfloat y2_peak{Comp->mLastPeakSq}; + ALfloat y2_rms{Comp->mLastRmsSq}; ASSUME(SamplesToDo > 0); ASSUME(index >= 0); @@ -137,11 +141,11 @@ static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo) y2_rms = lerp(x2, y2_rms, a_crest); return y2_peak / y2_rms; }; - auto side_begin = std::begin(Comp->SideChain) + index; - std::transform(side_begin, side_begin+SamplesToDo, std::begin(Comp->CrestFactor), calc_crest); + auto side_begin = std::begin(Comp->mSideChain) + index; + std::transform(side_begin, side_begin+SamplesToDo, std::begin(Comp->mCrestFactor), calc_crest); - Comp->LastPeakSq = y2_peak; - Comp->LastRmsSq = y2_rms; + Comp->mLastPeakSq = y2_peak; + Comp->mLastRmsSq = y2_rms; } /* The side-chain starts with a simple peak detector (based on the absolute @@ -150,13 +154,13 @@ static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo) */ void PeakDetector(Compressor *Comp, const ALsizei SamplesToDo) { - const ALsizei index{Comp->LookAhead}; + const ALsizei index{Comp->mLookAhead}; ASSUME(SamplesToDo > 0); ASSUME(index >= 0); /* Clamp the minimum amplitude to near-zero and convert to logarithm. */ - auto side_begin = std::begin(Comp->SideChain) + index; + auto side_begin = std::begin(Comp->mSideChain) + index; std::transform(side_begin, side_begin+SamplesToDo, side_begin, std::bind(static_cast(std::log), std::bind(maxf, 0.000001f, _1))); } @@ -167,19 +171,19 @@ void PeakDetector(Compressor *Comp, const ALsizei SamplesToDo) */ void PeakHoldDetector(Compressor *Comp, const ALsizei SamplesToDo) { - const ALsizei index{Comp->LookAhead}; + const ALsizei index{Comp->mLookAhead}; ASSUME(SamplesToDo > 0); ASSUME(index >= 0); - SlidingHold *hold{Comp->Hold}; + SlidingHold *hold{Comp->mHold}; ALsizei i{0}; auto detect_peak = [&i,hold](const ALfloat x_abs) -> ALfloat { const ALfloat x_G{std::log(maxf(0.000001f, x_abs))}; return UpdateSlidingHold(hold, i++, x_G); }; - auto side_begin = std::begin(Comp->SideChain) + index; + auto side_begin = std::begin(Comp->mSideChain) + index; std::transform(side_begin, side_begin+SamplesToDo, side_begin, detect_peak); ShiftSlidingHold(hold, SamplesToDo); @@ -192,29 +196,29 @@ void PeakHoldDetector(Compressor *Comp, const ALsizei SamplesToDo) */ void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) { - const bool autoKnee{Comp->Auto.Knee}; - const bool autoAttack{Comp->Auto.Attack}; - const bool autoRelease{Comp->Auto.Release}; - const bool autoPostGain{Comp->Auto.PostGain}; - const bool autoDeclip{Comp->Auto.Declip}; - const ALsizei lookAhead{Comp->LookAhead}; - const ALfloat threshold{Comp->Threshold}; - const ALfloat slope{Comp->Slope}; - const ALfloat attack{Comp->Attack}; - const ALfloat release{Comp->Release}; - const ALfloat c_est{Comp->GainEstimate}; - const ALfloat a_adp{Comp->AdaptCoeff}; - const ALfloat (&crestFactor)[BUFFERSIZE] = Comp->CrestFactor; - ALfloat (&sideChain)[BUFFERSIZE*2] = Comp->SideChain; - ALfloat postGain{Comp->PostGain}; - ALfloat knee{Comp->Knee}; + const bool autoKnee{Comp->mAuto.Knee}; + const bool autoAttack{Comp->mAuto.Attack}; + const bool autoRelease{Comp->mAuto.Release}; + const bool autoPostGain{Comp->mAuto.PostGain}; + const bool autoDeclip{Comp->mAuto.Declip}; + const ALsizei lookAhead{Comp->mLookAhead}; + const ALfloat threshold{Comp->mThreshold}; + const ALfloat slope{Comp->mSlope}; + const ALfloat attack{Comp->mAttack}; + const ALfloat release{Comp->mRelease}; + const ALfloat c_est{Comp->mGainEstimate}; + const ALfloat a_adp{Comp->mAdaptCoeff}; + const ALfloat (&crestFactor)[BUFFERSIZE] = Comp->mCrestFactor; + ALfloat (&sideChain)[BUFFERSIZE*2] = Comp->mSideChain; + ALfloat postGain{Comp->mPostGain}; + ALfloat knee{Comp->mKnee}; ALfloat t_att{attack}; ALfloat t_rel{release - attack}; ALfloat a_att{std::exp(-1.0f / t_att)}; ALfloat a_rel{std::exp(-1.0f / t_rel)}; - ALfloat y_1{Comp->LastRelease}; - ALfloat y_L{Comp->LastAttack}; - ALfloat c_dev{Comp->LastGainDev}; + ALfloat y_1{Comp->mLastRelease}; + ALfloat y_L{Comp->mLastAttack}; + ALfloat c_dev{Comp->mLastGainDev}; ASSUME(SamplesToDo > 0); ASSUME(lookAhead >= 0); @@ -279,9 +283,9 @@ void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) sideChain[i] = std::exp(postGain - y_L); } - Comp->LastRelease = y_1; - Comp->LastAttack = y_L; - Comp->LastGainDev = c_dev; + Comp->mLastRelease = y_1; + Comp->mLastAttack = y_L; + Comp->mLastGainDev = c_dev; } /* Combined with the hold time, a look-ahead delay can improve handling of @@ -292,9 +296,9 @@ void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]) { static constexpr ALsizei mask{BUFFERSIZE - 1}; - const ALsizei numChans{Comp->NumChans}; - const ALsizei indexIn{Comp->DelayIndex}; - const ALsizei indexOut{Comp->DelayIndex - Comp->LookAhead}; + const ALsizei numChans{Comp->mNumChans}; + const ALsizei indexIn{Comp->mDelayIndex}; + const ALsizei indexOut{Comp->mDelayIndex - Comp->mLookAhead}; ASSUME(SamplesToDo > 0); ASSUME(numChans > 0); @@ -302,7 +306,7 @@ void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT for(ALsizei c{0};c < numChans;c++) { ALfloat *RESTRICT inout{al::assume_aligned<16>(OutBuffer[c])}; - ALfloat *RESTRICT delay{al::assume_aligned<16>(Comp->Delay[c])}; + ALfloat *RESTRICT delay{al::assume_aligned<16>(Comp->mDelay[c])}; for(ALsizei i{0};i < SamplesToDo;i++) { const ALfloat sig{inout[i]}; @@ -312,7 +316,7 @@ void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT } } - Comp->DelayIndex = (indexIn + SamplesToDo) & mask; + Comp->mDelayIndex = (indexIn + SamplesToDo) & mask; } } // namespace @@ -341,7 +345,7 @@ void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT * ReleaseTimeMin - Release time (in seconds). Acts as a maximum when * automating release time. */ -Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, +std::unique_ptr CompressorInit(const ALsizei NumChans, const ALuint SampleRate, const ALboolean AutoKnee, const ALboolean AutoAttack, const ALboolean AutoRelease, const ALboolean AutoPostGain, const ALboolean AutoDeclip, const ALfloat LookAheadTime, @@ -354,74 +358,82 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, clampf(std::round(LookAheadTime*SampleRate), 0.0f, BUFFERSIZE-1)); auto hold = static_cast(clampf(std::round(HoldTime*SampleRate), 0.0f, BUFFERSIZE-1)); - Compressor *Comp; - size_t size{sizeof(*Comp)}; + std::unique_ptr Comp; + size_t size{sizeof(Compressor)}; if(lookAhead > 0) { - size += sizeof(*Comp->Delay) * NumChans; + size += sizeof(*Comp->mDelay) * NumChans; /* The sliding hold implementation doesn't handle a length of 1. A 1- * sample hold is useless anyway, it would only ever give back what was * just given to it. */ if(hold > 1) - size += sizeof(*Comp->Hold); + size += sizeof(*Comp->mHold); } - Comp = new (al_calloc(16, size)) Compressor{}; - Comp->NumChans = NumChans; - Comp->SampleRate = SampleRate; - Comp->Auto.Knee = AutoKnee != AL_FALSE; - Comp->Auto.Attack = AutoAttack != AL_FALSE; - Comp->Auto.Release = AutoRelease != AL_FALSE; - Comp->Auto.PostGain = AutoPostGain != AL_FALSE; - Comp->Auto.Declip = AutoPostGain && AutoDeclip; - Comp->LookAhead = lookAhead; - Comp->PreGain = std::pow(10.0f, PreGainDb / 20.0f); - Comp->PostGain = PostGainDb * std::log(10.0f) / 20.0f; - Comp->Threshold = ThresholdDb * std::log(10.0f) / 20.0f; - Comp->Slope = 1.0f / maxf(1.0f, Ratio) - 1.0f; - Comp->Knee = maxf(0.0f, KneeDb * std::log(10.0f) / 20.0f); - Comp->Attack = maxf(1.0f, AttackTime * SampleRate); - Comp->Release = maxf(1.0f, ReleaseTime * SampleRate); + Comp = std::unique_ptr{new (al_calloc(16, size)) Compressor{}}; + Comp->mNumChans = NumChans; + Comp->mSampleRate = SampleRate; + Comp->mAuto.Knee = AutoKnee != AL_FALSE; + Comp->mAuto.Attack = AutoAttack != AL_FALSE; + Comp->mAuto.Release = AutoRelease != AL_FALSE; + Comp->mAuto.PostGain = AutoPostGain != AL_FALSE; + Comp->mAuto.Declip = AutoPostGain && AutoDeclip; + Comp->mLookAhead = lookAhead; + Comp->mPreGain = std::pow(10.0f, PreGainDb / 20.0f); + Comp->mPostGain = PostGainDb * std::log(10.0f) / 20.0f; + Comp->mThreshold = ThresholdDb * std::log(10.0f) / 20.0f; + Comp->mSlope = 1.0f / maxf(1.0f, Ratio) - 1.0f; + Comp->mKnee = maxf(0.0f, KneeDb * std::log(10.0f) / 20.0f); + Comp->mAttack = maxf(1.0f, AttackTime * SampleRate); + Comp->mRelease = maxf(1.0f, ReleaseTime * SampleRate); /* Knee width automation actually treats the compressor as a limiter. By * varying the knee width, it can effectively be seen as applying * compression over a wide range of ratios. */ if(AutoKnee) - Comp->Slope = -1.0f; + Comp->mSlope = -1.0f; if(lookAhead > 0) { if(hold > 1) { - Comp->Hold = new ((void*)(Comp + 1)) SlidingHold{}; - Comp->Hold->Values[0] = -std::numeric_limits::infinity(); - Comp->Hold->Expiries[0] = hold; - Comp->Hold->Length = hold; - Comp->Delay = (ALfloat(*)[BUFFERSIZE])(Comp->Hold + 1); + Comp->mHold = new ((void*)(Comp.get() + 1)) SlidingHold{}; + Comp->mHold->mValues[0] = -std::numeric_limits::infinity(); + Comp->mHold->mExpiries[0] = hold; + Comp->mHold->mLength = hold; + Comp->mDelay = (ALfloat(*)[BUFFERSIZE])(Comp->mHold + 1); } else { - Comp->Delay = (ALfloat(*)[BUFFERSIZE])(Comp + 1); + Comp->mDelay = (ALfloat(*)[BUFFERSIZE])(Comp.get() + 1); } } - Comp->CrestCoeff = std::exp(-1.0f / (0.200f * SampleRate)); // 200ms - Comp->GainEstimate = Comp->Threshold * -0.5f * Comp->Slope; - Comp->AdaptCoeff = std::exp(-1.0f / (2.0f * SampleRate)); // 2s + Comp->mCrestCoeff = std::exp(-1.0f / (0.200f * SampleRate)); // 200ms + Comp->mGainEstimate = Comp->mThreshold * -0.5f * Comp->mSlope; + Comp->mAdaptCoeff = std::exp(-1.0f / (2.0f * SampleRate)); // 2s return Comp; } -void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*OutBuffer)[BUFFERSIZE]) +Compressor::~Compressor() +{ + if(mHold) + mHold->~SlidingHold(); + mHold = nullptr; +} + + +void Compressor::process(const ALsizei SamplesToDo, ALfloat (*OutBuffer)[BUFFERSIZE]) { - const ALsizei numChans{Comp->NumChans}; + const ALsizei numChans{mNumChans}; ASSUME(SamplesToDo > 0); ASSUME(numChans > 0); - const ALfloat preGain{Comp->PreGain}; + const ALfloat preGain{mPreGain}; if(preGain != 1.0f) { auto apply_gain = [SamplesToDo,preGain](ALfloat *input) noexcept -> void @@ -433,26 +445,26 @@ void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*Out std::for_each(OutBuffer, OutBuffer+numChans, apply_gain); } - LinkChannels(Comp, SamplesToDo, OutBuffer); + LinkChannels(this, SamplesToDo, OutBuffer); - if(Comp->Auto.Attack || Comp->Auto.Release) - CrestDetector(Comp, SamplesToDo); + if(mAuto.Attack || mAuto.Release) + CrestDetector(this, SamplesToDo); - if(Comp->Hold) - PeakHoldDetector(Comp, SamplesToDo); + if(mHold) + PeakHoldDetector(this, SamplesToDo); else - PeakDetector(Comp, SamplesToDo); + PeakDetector(this, SamplesToDo); - GainCompressor(Comp, SamplesToDo); + GainCompressor(this, SamplesToDo); - if(Comp->Delay) - SignalDelay(Comp, SamplesToDo, OutBuffer); + if(mDelay) + SignalDelay(this, SamplesToDo, OutBuffer); - const ALfloat (&sideChain)[BUFFERSIZE*2] = Comp->SideChain; + const ALfloat (&sideChain)[BUFFERSIZE*2] = mSideChain; auto apply_comp = [SamplesToDo,&sideChain](ALfloat *input) noexcept -> void { ALfloat *buffer{al::assume_aligned<16>(input)}; - const ALfloat *gains{al::assume_aligned<16>(sideChain)}; + const ALfloat *gains{al::assume_aligned<16>(&sideChain[0])}; /* Mark the gains "input-1 type" as restrict, so the compiler can * vectorize this loop (otherwise it assumes a write to buffer[n] can * change gains[n+1]). @@ -462,11 +474,7 @@ void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*Out }; std::for_each(OutBuffer, OutBuffer+numChans, apply_comp); - ASSUME(Comp->LookAhead >= 0); - auto side_begin = std::begin(Comp->SideChain) + SamplesToDo; - std::copy(side_begin, side_begin+Comp->LookAhead, std::begin(Comp->SideChain)); + ASSUME(mLookAhead >= 0); + auto side_begin = std::begin(mSideChain) + SamplesToDo; + std::copy(side_begin, side_begin+mLookAhead, std::begin(mSideChain)); } - - -ALsizei GetCompressorLookAhead(const Compressor *Comp) -{ return Comp->LookAhead; } diff --git a/Alc/mastering.h b/Alc/mastering.h index 55b7c258..a9411bd0 100644 --- a/Alc/mastering.h +++ b/Alc/mastering.h @@ -1,6 +1,8 @@ #ifndef MASTERING_H #define MASTERING_H +#include + #include "AL/al.h" #include "almalloc.h" @@ -21,8 +23,8 @@ struct SlidingHold; * http://c4dm.eecs.qmul.ac.uk/audioengineering/compressors/ */ struct Compressor { - ALsizei NumChans; - ALuint SampleRate; + ALsizei mNumChans{0}; + ALuint mSampleRate{0u}; struct { bool Knee : 1; @@ -30,36 +32,41 @@ struct Compressor { bool Release : 1; bool PostGain : 1; bool Declip : 1; - } Auto; + } mAuto{}; + + ALsizei mLookAhead{0}; + + ALfloat mPreGain{0.0f}; + ALfloat mPostGain{0.0f}; - ALsizei LookAhead; + ALfloat mThreshold{0.0f}; + ALfloat mSlope{0.0f}; + ALfloat mKnee{0.0f}; - ALfloat PreGain; - ALfloat PostGain; + ALfloat mAttack{0.0f}; + ALfloat mRelease{0.0f}; - ALfloat Threshold; - ALfloat Slope; - ALfloat Knee; + alignas(16) ALfloat mSideChain[2*BUFFERSIZE]{}; + alignas(16) ALfloat mCrestFactor[BUFFERSIZE]{}; - ALfloat Attack; - ALfloat Release; + SlidingHold *mHold{nullptr}; + ALfloat (*mDelay)[BUFFERSIZE]{nullptr}; + ALsizei mDelayIndex{0}; - alignas(16) ALfloat SideChain[2*BUFFERSIZE]; - alignas(16) ALfloat CrestFactor[BUFFERSIZE]; + ALfloat mCrestCoeff{0.0f}; + ALfloat mGainEstimate{0.0f}; + ALfloat mAdaptCoeff{0.0f}; - SlidingHold *Hold; - ALfloat (*Delay)[BUFFERSIZE]; - ALsizei DelayIndex; + ALfloat mLastPeakSq{0.0f}; + ALfloat mLastRmsSq{0.0f}; + ALfloat mLastRelease{0.0f}; + ALfloat mLastAttack{0.0f}; + ALfloat mLastGainDev{0.0f}; - ALfloat CrestCoeff; - ALfloat GainEstimate; - ALfloat AdaptCoeff; - ALfloat LastPeakSq; - ALfloat LastRmsSq; - ALfloat LastRelease; - ALfloat LastAttack; - ALfloat LastGainDev; + ~Compressor(); + void process(const ALsizei SamplesToDo, ALfloat (*OutBuffer)[BUFFERSIZE]); + ALsizei getLookAhead() const noexcept { return mLookAhead; } DEF_PLACE_NEWDEL() }; @@ -88,7 +95,7 @@ struct Compressor { * ReleaseTimeMin - Release time (in seconds). Acts as a maximum when * automating release time. */ -Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, +std::unique_ptr CompressorInit(const ALsizei NumChans, const ALuint SampleRate, const ALboolean AutoKnee, const ALboolean AutoAttack, const ALboolean AutoRelease, const ALboolean AutoPostGain, const ALboolean AutoDeclip, const ALfloat LookAheadTime, @@ -97,9 +104,4 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, const ALfloat Ratio, const ALfloat KneeDb, const ALfloat AttackTime, const ALfloat ReleaseTime); -void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, - ALfloat (*OutBuffer)[BUFFERSIZE]); - -ALsizei GetCompressorLookAhead(const Compressor *Comp); - #endif /* MASTERING_H */ -- cgit v1.2.3 From cd213fe6b731269caa484eb3cb9b830dac7f5c58 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 24 Dec 2018 09:58:48 -0800 Subject: Avoid using select() --- Alc/backends/oss.cpp | 64 +++++++++++++++++++----------------------------- Alc/backends/qsa.cpp | 36 +++++++++++---------------- Alc/backends/solaris.cpp | 37 ++++++++++++---------------- 3 files changed, 54 insertions(+), 83 deletions(-) diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 065f159a..4b1d468c 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -286,52 +287,44 @@ void ALCplaybackOSS_Destruct(ALCplaybackOSS *self) int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - struct timeval timeout; - ALubyte *write_ptr; - ALint frame_size; - ALint to_write; - ssize_t wrote; - fd_set wfds; - int sret; + ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - frame_size = device->frameSizeFromFmt(); + const int frame_size{device->frameSizeFromFmt()}; ALCplaybackOSS_lock(self); while(!self->mKillNow.load(std::memory_order_acquire) && device->Connected.load(std::memory_order_acquire)) { - FD_ZERO(&wfds); - FD_SET(self->fd, &wfds); - timeout.tv_sec = 1; - timeout.tv_usec = 0; + pollfd pollitem{}; + pollitem.fd = self->fd; + pollitem.events = POLLOUT; ALCplaybackOSS_unlock(self); - sret = select(self->fd+1, nullptr, &wfds, nullptr, &timeout); + int pret{poll(&pollitem, 1, 1000)}; ALCplaybackOSS_lock(self); - if(sret < 0) + if(pret < 0) { - if(errno == EINTR) + if(errno == EINTR || errno == EAGAIN) continue; - ERR("select failed: %s\n", strerror(errno)); + ERR("poll failed: %s\n", strerror(errno)); aluHandleDisconnect(device, "Failed waiting for playback buffer: %s", strerror(errno)); break; } - else if(sret == 0) + else if(pret == 0) { - WARN("select timeout\n"); + WARN("poll timeout\n"); continue; } - write_ptr = self->mMixData.data(); - to_write = self->mMixData.size(); + ALubyte *write_ptr{self->mMixData.data()}; + size_t to_write{self->mMixData.size()}; aluMixData(device, write_ptr, to_write/frame_size); while(to_write > 0 && !self->mKillNow.load()) { - wrote = write(self->fd, write_ptr, to_write); + ssize_t wrote{write(self->fd, write_ptr, to_write)}; if(wrote < 0) { if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) @@ -544,44 +537,37 @@ void ALCcaptureOSS_Destruct(ALCcaptureOSS *self) int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - struct timeval timeout; - int frame_size; - fd_set rfds; - ssize_t amt; - int sret; + ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; SetRTPriority(); althrd_setname(RECORD_THREAD_NAME); - frame_size = device->frameSizeFromFmt(); - + const int frame_size{device->frameSizeFromFmt()}; while(!self->mKillNow.load()) { - FD_ZERO(&rfds); - FD_SET(self->fd, &rfds); - timeout.tv_sec = 1; - timeout.tv_usec = 0; + pollfd pollitem{}; + pollitem.fd = self->fd; + pollitem.events = POLLIN; - sret = select(self->fd+1, &rfds, nullptr, nullptr, &timeout); + int sret{poll(&pollitem, 1, 1000)}; if(sret < 0) { - if(errno == EINTR) + if(errno == EINTR || errno == EAGAIN) continue; - ERR("select failed: %s\n", strerror(errno)); + ERR("poll failed: %s\n", strerror(errno)); aluHandleDisconnect(device, "Failed to check capture samples: %s", strerror(errno)); break; } else if(sret == 0) { - WARN("select timeout\n"); + WARN("poll timeout\n"); continue; } auto vec = ll_ringbuffer_get_write_vector(self->mRing.get()); if(vec.first.len > 0) { - amt = read(self->fd, vec.first.buf, vec.first.len*frame_size); + ssize_t amt{read(self->fd, vec.first.buf, vec.first.len*frame_size)}; if(amt < 0) { ERR("read failed: %s\n", strerror(errno)); diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index f8b26878..f0d1876e 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -36,7 +37,6 @@ #include "alu.h" #include "threads.h" -#include #include #include @@ -196,9 +196,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) qsa_data *data = self->ExtraData; snd_pcm_channel_status_t status; struct sched_param param; - struct timeval timeout; char* write_ptr; - fd_set wfds; ALint len; int sret; @@ -215,24 +213,25 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) PlaybackWrapper_lock(self); while(!data->mKillNow.load(std::memory_order_acquire)) { - FD_ZERO(&wfds); - FD_SET(data->audio_fd, &wfds); - timeout.tv_sec=2; - timeout.tv_usec=0; + pollfd pollitem{}; + pollitem.fd = data->audio_fd; + pollitem.events = POLLOUT; /* Select also works like time slice to OS */ PlaybackWrapper_unlock(self); - sret = select(data->audio_fd+1, NULL, &wfds, NULL, &timeout); + sret = poll(&pollitem, 1, 2000); PlaybackWrapper_lock(self); if(sret == -1) { - ERR("select error: %s\n", strerror(errno)); + if(errno == EINTR || errno == EAGAIN) + continue; + ERR("poll error: %s\n", strerror(errno)); aluHandleDisconnect(device, "Failed waiting for playback buffer: %s", strerror(errno)); break; } if(sret == 0) { - ERR("select timeout\n"); + ERR("poll timeout\n"); continue; } @@ -850,9 +849,7 @@ static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuin qsa_data *data = self->ExtraData.get(); char* read_ptr; snd_pcm_channel_status_t status; - fd_set rfds; int selectret; - struct timeval timeout; int bytes_read; ALint frame_size=device->frameSizeFromFmt(); ALint len=samples*frame_size; @@ -862,14 +859,13 @@ static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuin while (len>0) { - FD_ZERO(&rfds); - FD_SET(data->audio_fd, &rfds); - timeout.tv_sec=2; - timeout.tv_usec=0; + pollfd pollitem{}; + pollitem.fd = data->audio_fd; + pollitem.events = POLLOUT; /* Select also works like time slice to OS */ bytes_read=0; - selectret=select(data->audio_fd+1, &rfds, NULL, NULL, &timeout); + selectret = poll(&pollitem, 1, 2000); switch (selectret) { case -1: @@ -878,11 +874,7 @@ static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuin case 0: break; default: - if (FD_ISSET(data->audio_fd, &rfds)) - { - bytes_read=snd_pcm_plugin_read(data->pcmHandle, read_ptr, len); - break; - } + bytes_read=snd_pcm_plugin_read(data->pcmHandle, read_ptr, len); break; } diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index 8871fb93..79341ad1 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -102,52 +103,44 @@ static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self) static int ALCsolarisBackend_mixerProc(ALCsolarisBackend *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - struct timeval timeout; - ALubyte *write_ptr; - ALint frame_size; - ALint to_write; - ssize_t wrote; - fd_set wfds; - int sret; + ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - frame_size = device->frameSizeFromFmt(); + const int frame_size{device->frameSizeFromFmt()}; ALCsolarisBackend_lock(self); while(!self->mKillNow.load(std::memory_order_acquire) && device->Connected.load(std::memory_order_acquire)) { - FD_ZERO(&wfds); - FD_SET(self->fd, &wfds); - timeout.tv_sec = 1; - timeout.tv_usec = 0; + pollfd pollitem{}; + pollitem.fd = self->fd; + pollitem.events = POLLOUT; ALCsolarisBackend_unlock(self); - sret = select(self->fd+1, nullptr, &wfds, nullptr, &timeout); + int pret{poll(&pollitem, 1, 1000)}; ALCsolarisBackend_lock(self); - if(sret < 0) + if(pret < 0) { - if(errno == EINTR) + if(errno == EINTR || errno == EAGAIN) continue; - ERR("select failed: %s\n", strerror(errno)); + ERR("poll failed: %s\n", strerror(errno)); aluHandleDisconnect(device, "Failed to wait for playback buffer: %s", strerror(errno)); break; } - else if(sret == 0) + else if(pret == 0) { - WARN("select timeout\n"); + WARN("poll timeout\n"); continue; } - write_ptr = self->mix_data; - to_write = self->data_size; + ALubyte *write_ptr{self->mix_data}; + int to_write{self->data_size}; aluMixData(device, write_ptr, to_write/frame_size); while(to_write > 0 && !self->mKillNow.load()) { - wrote = write(self->fd, write_ptr, to_write); + ssize_t wrote{write(self->fd, write_ptr, to_write)}; if(wrote < 0) { if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) -- cgit v1.2.3 From ae86aef4db02675ec64d690556905ea034753c87 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 24 Dec 2018 13:29:36 -0800 Subject: Provide effect target parameters through a common struct --- Alc/alu.cpp | 22 ++++++++++++++++++++-- Alc/effects/autowah.cpp | 25 +++++++------------------ Alc/effects/chorus.cpp | 23 +++++++---------------- Alc/effects/compressor.cpp | 26 +++++++------------------- Alc/effects/dedicated.cpp | 38 ++++++++++++-------------------------- Alc/effects/distortion.cpp | 38 ++++++++++++++------------------------ Alc/effects/echo.cpp | 22 ++++++---------------- Alc/effects/equalizer.cpp | 25 +++++++------------------ Alc/effects/fshifter.cpp | 20 ++++++-------------- Alc/effects/modulator.cpp | 25 +++++++------------------ Alc/effects/null.cpp | 4 ++-- Alc/effects/pshifter.cpp | 21 ++++++--------------- Alc/effects/reverb.cpp | 37 ++++++++++++------------------------- OpenAL32/Include/alAuxEffectSlot.h | 7 ++++++- OpenAL32/Include/alMain.h | 4 ++-- 15 files changed, 121 insertions(+), 216 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 1917dd9d..93aeff2a 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -412,7 +412,7 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) evt.u.mEffectState = slot->Params.mEffectState; slot->Params.mEffectState = state; - props->State = NULL; + props->State = nullptr; if(LIKELY(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) != 0)) context->EventSem.post(); @@ -430,7 +430,25 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) AtomicReplaceHead(context->FreeEffectslotProps, props); } - state->update(context, slot, &slot->Params.EffectProps); + MixParams params; + EffectTarget output; + if(ALeffectslot *target{slot->Params.Target}) + { + auto iter = std::copy(std::begin(target->ChanMap), std::end(target->ChanMap), + std::begin(params.Ambi.Map)); + std::fill(iter, std::end(params.Ambi.Map), BFChannelConfig{}); + params.CoeffCount = 0; + params.Buffer = target->WetBuffer; + params.NumChannels = target->NumChannels; + + output = EffectTarget{¶ms, ¶ms, nullptr}; + } + else + { + ALCdevice *device{context->Device}; + output = EffectTarget{&device->Dry, &device->FOAOut, &device->RealOut}; + } + state->update(context, slot, &slot->Params.EffectProps, output); return true; } diff --git a/Alc/effects/autowah.cpp b/Alc/effects/autowah.cpp index e455acf2..8590360a 100644 --- a/Alc/effects/autowah.cpp +++ b/Alc/effects/autowah.cpp @@ -69,7 +69,7 @@ struct ALautowahState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ALautowahState) @@ -103,7 +103,7 @@ ALboolean ALautowahState::deviceUpdate(const ALCdevice *UNUSED(device)) return AL_TRUE; } -void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) { const ALCdevice *device = context->Device; ALfloat ReleaseTime; @@ -119,22 +119,11 @@ void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, mFreqMinNorm = MIN_FREQ / device->Frequency; mBandwidthNorm = (MAX_FREQ-MIN_FREQ) / device->Frequency; - if(ALeffectslot *target{slot->Params.Target}) - { - mOutBuffer = target->WetBuffer; - mOutChannels = target->NumChannels; - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(target, alu::Matrix::Identity()[i].data(), slot->Params.Gain, - mChans[i].TargetGains); - } - else - { - mOutBuffer = device->FOAOut.Buffer; - mOutChannels = device->FOAOut.NumChannels; - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&device->FOAOut, alu::Matrix::Identity()[i].data(), slot->Params.Gain, - mChans[i].TargetGains); - } + mOutBuffer = target.FOAOut->Buffer; + mOutChannels = target.FOAOut->NumChannels; + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(target.FOAOut, alu::Matrix::Identity()[i].data(), slot->Params.Gain, + mChans[i].TargetGains); } void ALautowahState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp index 1a444525..9219ece5 100644 --- a/Alc/effects/chorus.cpp +++ b/Alc/effects/chorus.cpp @@ -91,7 +91,7 @@ struct ChorusState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ChorusState) @@ -121,7 +121,7 @@ ALboolean ChorusState::deviceUpdate(const ALCdevice *Device) return AL_TRUE; } -void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) +void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props, const EffectTarget target) { static constexpr ALsizei mindelay = MAX_RESAMPLE_PADDING << FRACTIONBITS; @@ -149,20 +149,11 @@ void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, co ALfloat coeffs[2][MAX_AMBI_COEFFS]; CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs[0]); CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs[1]); - if(ALeffectslot *target{Slot->Params.Target}) - { - mOutBuffer = target->WetBuffer; - mOutChannels = target->NumChannels; - ComputePanGains(target, coeffs[0], Slot->Params.Gain, mGains[0].Target); - ComputePanGains(target, coeffs[1], Slot->Params.Gain, mGains[1].Target); - } - else - { - mOutBuffer = device->Dry.Buffer; - mOutChannels = device->Dry.NumChannels; - ComputePanGains(&device->Dry, coeffs[0], Slot->Params.Gain, mGains[0].Target); - ComputePanGains(&device->Dry, coeffs[1], Slot->Params.Gain, mGains[1].Target); - } + + mOutBuffer = target.Main->Buffer; + mOutChannels = target.Main->NumChannels; + ComputePanGains(target.Main, coeffs[0], Slot->Params.Gain, mGains[0].Target); + ComputePanGains(target.Main, coeffs[1], Slot->Params.Gain, mGains[1].Target); ALfloat rate{props->Chorus.Rate}; if(!(rate > 0.0f)) diff --git a/Alc/effects/compressor.cpp b/Alc/effects/compressor.cpp index 8505f161..ddf104f4 100644 --- a/Alc/effects/compressor.cpp +++ b/Alc/effects/compressor.cpp @@ -49,7 +49,7 @@ struct ALcompressorState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ALcompressorState) @@ -72,27 +72,15 @@ ALboolean ALcompressorState::deviceUpdate(const ALCdevice *device) return AL_TRUE; } -void ALcompressorState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +void ALcompressorState::update(const ALCcontext* UNUSED(context), const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) { mEnabled = props->Compressor.OnOff; - if(ALeffectslot *target{slot->Params.Target}) - { - mOutBuffer = target->WetBuffer; - mOutChannels = target->NumChannels; - for(ALsizei i{0};i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(target, alu::Matrix::Identity()[i].data(), slot->Params.Gain, - mGain[i]); - } - else - { - const ALCdevice *device{context->Device}; - mOutBuffer = device->FOAOut.Buffer; - mOutChannels = device->FOAOut.NumChannels; - for(ALsizei i{0};i < 4;i++) - ComputePanGains(&device->FOAOut, alu::Matrix::Identity()[i].data(), - slot->Params.Gain, mGain[i]); - } + mOutBuffer = target.FOAOut->Buffer; + mOutChannels = target.FOAOut->NumChannels; + for(ALsizei i{0};i < 4;i++) + ComputePanGains(target.FOAOut, alu::Matrix::Identity()[i].data(), + slot->Params.Gain, mGain[i]); } void ALcompressorState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/dedicated.cpp b/Alc/effects/dedicated.cpp index 851e48a5..f9faa63d 100644 --- a/Alc/effects/dedicated.cpp +++ b/Alc/effects/dedicated.cpp @@ -37,7 +37,7 @@ struct ALdedicatedState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ALdedicatedState) @@ -49,33 +49,19 @@ ALboolean ALdedicatedState::deviceUpdate(const ALCdevice *UNUSED(device)) return AL_TRUE; } -void ALdedicatedState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +void ALdedicatedState::update(const ALCcontext* UNUSED(context), const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) { - const ALCdevice *device = context->Device; - std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f); const ALfloat Gain{slot->Params.Gain * props->Dedicated.Gain}; - if(ALeffectslot *target{slot->Params.Target}) - { - mOutBuffer = target->WetBuffer; - mOutChannels = target->NumChannels; - if(slot->Params.EffectType == AL_EFFECT_DEDICATED_DIALOGUE) - { - ALfloat coeffs[MAX_AMBI_COEFFS]; - CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputePanGains(target, coeffs, Gain, mTargetGains); - } - return; - } if(slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) { - int idx; - if((idx=GetChannelIdxByName(device->RealOut, LFE)) != -1) + const int idx{!target.RealOut ? -1 : GetChannelIdxByName(*target.RealOut, LFE)}; + if(idx != -1) { - mOutBuffer = device->RealOut.Buffer; - mOutChannels = device->RealOut.NumChannels; + mOutBuffer = target.RealOut->Buffer; + mOutChannels = target.RealOut->NumChannels; mTargetGains[idx] = Gain; } } @@ -83,11 +69,11 @@ void ALdedicatedState::update(const ALCcontext *context, const ALeffectslot *slo { /* Dialog goes to the front-center speaker if it exists, otherwise it * plays from the front-center location. */ - int idx{GetChannelIdxByName(device->RealOut, FrontCenter)}; + const int idx{!target.RealOut ? -1 : GetChannelIdxByName(*target.RealOut, FrontCenter)}; if(idx != -1) { - mOutBuffer = device->RealOut.Buffer; - mOutChannels = device->RealOut.NumChannels; + mOutBuffer = target.RealOut->Buffer; + mOutChannels = target.RealOut->NumChannels; mTargetGains[idx] = Gain; } else @@ -95,9 +81,9 @@ void ALdedicatedState::update(const ALCcontext *context, const ALeffectslot *slo ALfloat coeffs[MAX_AMBI_COEFFS]; CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - mOutBuffer = device->Dry.Buffer; - mOutChannels = device->Dry.NumChannels; - ComputePanGains(&device->Dry, coeffs, Gain, mTargetGains); + mOutBuffer = target.Main->Buffer; + mOutChannels = target.Main->NumChannels; + ComputePanGains(target.Main, coeffs, Gain, mTargetGains); } } } diff --git a/Alc/effects/distortion.cpp b/Alc/effects/distortion.cpp index eb4ff975..d094ee5f 100644 --- a/Alc/effects/distortion.cpp +++ b/Alc/effects/distortion.cpp @@ -23,6 +23,8 @@ #include #include +#include + #include "alMain.h" #include "alcontext.h" #include "alAuxEffectSlot.h" @@ -45,7 +47,7 @@ struct ALdistortionState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ALdistortionState) @@ -58,26 +60,21 @@ ALboolean ALdistortionState::deviceUpdate(const ALCdevice *UNUSED(device)) return AL_TRUE; } -void ALdistortionState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +void ALdistortionState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) { - const ALCdevice *device = context->Device; - ALfloat frequency = (ALfloat)device->Frequency; - ALfloat coeffs[MAX_AMBI_COEFFS]; - ALfloat bandwidth; - ALfloat cutoff; - ALfloat edge; + const ALCdevice *device{context->Device}; /* Store waveshaper edge settings. */ - edge = sinf(props->Distortion.Edge * (F_PI_2)); - edge = minf(edge, 0.99f); + const ALfloat edge{minf(std::sin(props->Distortion.Edge * F_PI_2), 0.99f)}; mEdgeCoeff = 2.0f * edge / (1.0f-edge); - cutoff = props->Distortion.LowpassCutoff; + ALfloat cutoff{props->Distortion.LowpassCutoff}; /* Bandwidth value is constant in octaves. */ - bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f); + ALfloat bandwidth{(cutoff / 2.0f) / (cutoff * 0.67f)}; /* Multiply sampling frequency by the amount of oversampling done during * processing. */ + auto frequency = static_cast(device->Frequency); mLowpass.setParams(BiquadType::LowPass, 1.0f, cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); @@ -89,19 +86,12 @@ void ALdistortionState::update(const ALCcontext *context, const ALeffectslot *sl calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); + ALfloat coeffs[MAX_AMBI_COEFFS]; CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - if(ALeffectslot *target{slot->Params.Target}) - { - mOutBuffer = target->WetBuffer; - mOutChannels = target->NumChannels; - ComputePanGains(target, coeffs, slot->Params.Gain*props->Distortion.Gain, mGain); - } - else - { - mOutBuffer = device->Dry.Buffer; - mOutChannels = device->Dry.NumChannels; - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain*props->Distortion.Gain, mGain); - } + + mOutBuffer = target.Main->Buffer; + mOutChannels = target.Main->NumChannels; + ComputePanGains(target.Main, coeffs, slot->Params.Gain*props->Distortion.Gain, mGain); } void ALdistortionState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index dae99912..f48f1e89 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -57,7 +57,7 @@ struct ALechoState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ALechoState) @@ -90,7 +90,7 @@ ALboolean ALechoState::deviceUpdate(const ALCdevice *Device) return AL_TRUE; } -void ALechoState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +void ALechoState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) { const ALCdevice *device = context->Device; ALuint frequency = device->Frequency; @@ -119,20 +119,10 @@ void ALechoState::update(const ALCcontext *context, const ALeffectslot *slot, co CalcAngleCoeffs(-F_PI_2*lrpan, 0.0f, spread, coeffs[0]); CalcAngleCoeffs( F_PI_2*lrpan, 0.0f, spread, coeffs[1]); - if(ALeffectslot *target{slot->Params.Target}) - { - mOutBuffer = target->WetBuffer; - mOutChannels = target->NumChannels; - ComputePanGains(target, coeffs[0], slot->Params.Gain, mGains[0].Target); - ComputePanGains(target, coeffs[1], slot->Params.Gain, mGains[1].Target); - } - else - { - mOutBuffer = device->Dry.Buffer; - mOutChannels = device->Dry.NumChannels; - ComputePanGains(&device->Dry, coeffs[0], slot->Params.Gain, mGains[0].Target); - ComputePanGains(&device->Dry, coeffs[1], slot->Params.Gain, mGains[1].Target); - } + mOutBuffer = target.Main->Buffer; + mOutChannels = target.Main->NumChannels; + ComputePanGains(target.Main, coeffs[0], slot->Params.Gain, mGains[0].Target); + ComputePanGains(target.Main, coeffs[1], slot->Params.Gain, mGains[1].Target); } void ALechoState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index 53975d19..443bf118 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -91,7 +91,7 @@ struct ALequalizerState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ALequalizerState) @@ -108,7 +108,7 @@ ALboolean ALequalizerState::deviceUpdate(const ALCdevice *UNUSED(device)) return AL_TRUE; } -void ALequalizerState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +void ALequalizerState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) { const ALCdevice *device = context->Device; ALfloat frequency = (ALfloat)device->Frequency; @@ -152,22 +152,11 @@ void ALequalizerState::update(const ALCcontext *context, const ALeffectslot *slo mChans[i].filter[3].copyParamsFrom(mChans[0].filter[3]); } - if(ALeffectslot *target{slot->Params.Target}) - { - mOutBuffer = target->WetBuffer; - mOutChannels = target->NumChannels; - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(target, alu::Matrix::Identity()[i].data(), slot->Params.Gain, - mChans[i].TargetGains); - } - else - { - mOutBuffer = device->FOAOut.Buffer; - mOutChannels = device->FOAOut.NumChannels; - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&device->FOAOut, alu::Matrix::Identity()[i].data(), slot->Params.Gain, - mChans[i].TargetGains); - } + mOutBuffer = target.FOAOut->Buffer; + mOutChannels = target.FOAOut->NumChannels; + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(target.FOAOut, alu::Matrix::Identity()[i].data(), slot->Params.Gain, + mChans[i].TargetGains); } void ALequalizerState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp index e8311620..9b8499cf 100644 --- a/Alc/effects/fshifter.cpp +++ b/Alc/effects/fshifter.cpp @@ -82,7 +82,7 @@ struct ALfshifterState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ALfshifterState) @@ -107,7 +107,7 @@ ALboolean ALfshifterState::deviceUpdate(const ALCdevice *UNUSED(device)) return AL_TRUE; } -void ALfshifterState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +void ALfshifterState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) { const ALCdevice *device{context->Device}; @@ -132,18 +132,10 @@ void ALfshifterState::update(const ALCcontext *context, const ALeffectslot *slot ALfloat coeffs[MAX_AMBI_COEFFS]; CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - if(ALeffectslot *target{slot->Params.Target}) - { - mOutBuffer = target->WetBuffer; - mOutChannels = target->NumChannels; - ComputePanGains(target, coeffs, slot->Params.Gain, mTargetGains); - } - else - { - mOutBuffer = device->Dry.Buffer; - mOutChannels = device->Dry.NumChannels; - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, mTargetGains); - } + + mOutBuffer = target.Main->Buffer; + mOutChannels = target.Main->NumChannels; + ComputePanGains(target.Main, coeffs, slot->Params.Gain, mTargetGains); } void ALfshifterState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index 84aa0e2c..2b62d66a 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -89,7 +89,7 @@ struct ALmodulatorState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ALmodulatorState) @@ -105,7 +105,7 @@ ALboolean ALmodulatorState::deviceUpdate(const ALCdevice *UNUSED(device)) return AL_TRUE; } -void ALmodulatorState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +void ALmodulatorState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) { const ALCdevice *device = context->Device; ALfloat f0norm; @@ -131,22 +131,11 @@ void ALmodulatorState::update(const ALCcontext *context, const ALeffectslot *slo for(i = 1;i < MAX_EFFECT_CHANNELS;i++) mChans[i].Filter.copyParamsFrom(mChans[0].Filter); - if(ALeffectslot *target{slot->Params.Target}) - { - mOutBuffer = target->WetBuffer; - mOutChannels = target->NumChannels; - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(target, alu::Matrix::Identity()[i].data(), slot->Params.Gain, - mChans[i].TargetGains); - } - else - { - mOutBuffer = device->FOAOut.Buffer; - mOutChannels = device->FOAOut.NumChannels; - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&device->FOAOut, alu::Matrix::Identity()[i].data(), slot->Params.Gain, - mChans[i].TargetGains); - } + mOutBuffer = target.FOAOut->Buffer; + mOutChannels = target.FOAOut->NumChannels; + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(target.FOAOut, alu::Matrix::Identity()[i].data(), slot->Params.Gain, + mChans[i].TargetGains); } void ALmodulatorState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/null.cpp b/Alc/effects/null.cpp index ba591565..fa35b3c4 100644 --- a/Alc/effects/null.cpp +++ b/Alc/effects/null.cpp @@ -16,7 +16,7 @@ struct ALnullState final : public EffectState { ~ALnullState() override; ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ALnullState) @@ -48,7 +48,7 @@ ALboolean ALnullState::deviceUpdate(const ALCdevice* UNUSED(device)) /* This updates the effect state. This is called any time the effect is * (re)loaded into a slot. */ -void ALnullState::update(const ALCcontext* UNUSED(context), const ALeffectslot* UNUSED(slot), const ALeffectProps* UNUSED(props)) +void ALnullState::update(const ALCcontext* UNUSED(context), const ALeffectslot* UNUSED(slot), const ALeffectProps* UNUSED(props), const EffectTarget UNUSED(target)) { } diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp index 321e7492..a70fae52 100644 --- a/Alc/effects/pshifter.cpp +++ b/Alc/effects/pshifter.cpp @@ -144,7 +144,7 @@ struct ALpshifterState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ALpshifterState) @@ -173,7 +173,7 @@ ALboolean ALpshifterState::deviceUpdate(const ALCdevice *device) return AL_TRUE; } -void ALpshifterState::update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +void ALpshifterState::update(const ALCcontext* UNUSED(context), const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) { const float pitch{std::pow(2.0f, (ALfloat)(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f @@ -183,19 +183,10 @@ void ALpshifterState::update(const ALCcontext *context, const ALeffectslot *slot ALfloat coeffs[MAX_AMBI_COEFFS]; CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - if(ALeffectslot *target{slot->Params.Target}) - { - mOutBuffer = target->WetBuffer; - mOutChannels = target->NumChannels; - ComputePanGains(target, coeffs, slot->Params.Gain, mTargetGains); - } - else - { - const ALCdevice *device{context->Device}; - mOutBuffer = device->Dry.Buffer; - mOutChannels = device->Dry.NumChannels; - ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, mTargetGains); - } + + mOutBuffer = target.Main->Buffer; + mOutChannels = target.Main->NumChannels; + ComputePanGains(target.Main, coeffs, slot->Params.Gain, mTargetGains); } void ALpshifterState::process(ALsizei SamplesToDo, const ALfloat (*RESTRICT SamplesIn)[BUFFERSIZE], ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index a84749d8..574f9e7f 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -337,7 +337,7 @@ struct ReverbState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) override; void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) override; DEF_NEWDEL(ReverbState) @@ -763,7 +763,7 @@ alu::Matrix GetTransformFromVector(const ALfloat *vec) } /* Update the early and late 3D panning gains. */ -ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, const ALfloat earlyGain, const ALfloat lateGain, ALeffectslot *target, ReverbState *State) +ALvoid Update3DPanning(const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, const ALfloat earlyGain, const ALfloat lateGain, const EffectTarget &target, ReverbState *State) { /* Note: ret is transposed. */ auto MatrixMult = [](const alu::Matrix &m1, const alu::Matrix &m2) noexcept -> alu::Matrix @@ -783,28 +783,16 @@ ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, c */ alu::Matrix earlymat{MatrixMult(GetTransformFromVector(ReflectionsPan), A2B)}; alu::Matrix latemat{MatrixMult(GetTransformFromVector(LateReverbPan), A2B)}; - if(target) - { - State->mOutBuffer = target->WetBuffer; - State->mOutChannels = target->NumChannels; - for(ALsizei i{0};i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(target, earlymat[i].data(), earlyGain, State->mEarly.PanGain[i]); - for(ALsizei i{0};i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(target, latemat[i].data(), lateGain, State->mLate.PanGain[i]); - } - else - { - State->mOutBuffer = Device->FOAOut.Buffer; - State->mOutChannels = Device->FOAOut.NumChannels; - for(ALsizei i{0};i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&Device->FOAOut, earlymat[i].data(), earlyGain, - State->mEarly.PanGain[i]); - for(ALsizei i{0};i < MAX_EFFECT_CHANNELS;i++) - ComputePanGains(&Device->FOAOut, latemat[i].data(), lateGain, State->mLate.PanGain[i]); - } + State->mOutBuffer = target.FOAOut->Buffer; + State->mOutChannels = target.FOAOut->NumChannels; + for(ALsizei i{0};i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(target.FOAOut, earlymat[i].data(), earlyGain, + State->mEarly.PanGain[i]); + for(ALsizei i{0};i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(target.FOAOut, latemat[i].data(), lateGain, State->mLate.PanGain[i]); } -void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) +void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props, const EffectTarget target) { const ALCdevice *Device{Context->Device}; const ALlistener &Listener = Context->Listener; @@ -863,9 +851,8 @@ void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, co /* Update early and late 3D panning. */ const ALfloat gain{props->Reverb.Gain * Slot->Params.Gain * ReverbBoost}; - Update3DPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, - props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain, - Slot->Params.Target, this); + Update3DPanning(props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, + props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain, target, this); /* Calculate the max update size from the smallest relevant delay. */ mMaxUpdate[1] = mini(MAX_UPDATE_SAMPLES, mini(mEarly.Offset[0][1], mLate.Offset[0][1])); diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 04f00758..a3a308d9 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -10,6 +10,11 @@ struct ALeffectslot; +struct EffectTarget { + MixParams *Main; + MixParams *FOAOut; + RealMixParams *RealOut; +}; struct EffectState { RefCount mRef{1u}; @@ -21,7 +26,7 @@ struct EffectState { virtual ~EffectState() = default; virtual ALboolean deviceUpdate(const ALCdevice *device) = 0; - virtual void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) = 0; + virtual void update(const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props, const EffectTarget target) = 0; virtual void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], ALsizei numChannels) = 0; void IncRef() noexcept; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 3ed11193..d12ea780 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -538,10 +538,10 @@ enum RenderMode { typedef ALfloat ChannelConfig[MAX_AMBI_COEFFS]; -typedef struct BFChannelConfig { +struct BFChannelConfig { ALfloat Scale; ALsizei Index; -} BFChannelConfig; +}; typedef union AmbiConfig { /* Ambisonic coefficients for mixing to the dry buffer. */ -- cgit v1.2.3 From bbf9e6931cf607da49bb5a541e86f9760ea68047 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 24 Dec 2018 15:17:38 -0800 Subject: Propagate an effectslot target property --- Alc/alu.cpp | 1 + OpenAL32/Include/alAuxEffectSlot.h | 2 ++ OpenAL32/alAuxEffectSlot.cpp | 5 +++++ 3 files changed, 8 insertions(+) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 93aeff2a..b039f5af 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -371,6 +371,7 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) { slot->Params.Gain = props->Gain; slot->Params.AuxSendAuto = props->AuxSendAuto; + slot->Params.Target = props->Target; slot->Params.EffectType = props->Type; slot->Params.EffectProps = props->Props; if(IsReverbEffect(props->Type)) diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index a3a308d9..1b14dd36 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -53,6 +53,7 @@ struct ALeffectslotArray { struct ALeffectslotProps { ALfloat Gain; ALboolean AuxSendAuto; + ALeffectslot *Target; ALenum Type; ALeffectProps Props; @@ -66,6 +67,7 @@ struct ALeffectslotProps { struct ALeffectslot { ALfloat Gain{1.0f}; ALboolean AuxSendAuto{AL_TRUE}; + ALeffectslot *Target{nullptr}; struct { ALenum Type{AL_EFFECT_NULL}; diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index ca279aee..4add1668 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -589,6 +589,10 @@ ALenum InitEffectSlot(ALeffectslot *slot) ALeffectslot::~ALeffectslot() { + if(Target) + DecrementRef(&Target->ref); + Target = nullptr; + struct ALeffectslotProps *props{Update.load()}; if(props) { @@ -621,6 +625,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) /* Copy in current property values. */ props->Gain = slot->Gain; props->AuxSendAuto = slot->AuxSendAuto; + props->Target = slot->Target; props->Type = slot->Effect.Type; props->Props = slot->Effect.Props; -- cgit v1.2.3 From 194e7ff815d744830c8aaedfb0d32ed3c3d01645 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 24 Dec 2018 15:52:37 -0800 Subject: Add an in-progress extension to set the effect slot target --- Alc/alc.cpp | 1 + Alc/inprogext.h | 5 +++++ OpenAL32/alAuxEffectSlot.cpp | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index c225eaf2..bde9aa79 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -786,6 +786,7 @@ constexpr ALchar alExtList[] = "AL_SOFT_block_alignment " "AL_SOFT_deferred_updates " "AL_SOFT_direct_channels " + "AL_SOFTX_effect_chain " "AL_SOFTX_events " "AL_SOFTX_filter_gain_ex " "AL_SOFT_gain_clamp_ex " diff --git a/Alc/inprogext.h b/Alc/inprogext.h index 3025abe2..6921de8c 100644 --- a/Alc/inprogext.h +++ b/Alc/inprogext.h @@ -80,6 +80,11 @@ AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, co #endif #endif +#ifndef AL_SOFT_effect_chain +#define AL_SOFT_effect_chain +#define AL_EFFECTSLOT_TARGET_SOFT 0xf000 +#endif + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index 4add1668..b91774dc 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -295,6 +295,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param if(UNLIKELY(!slot)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + ALeffectslot *target{}; ALCdevice *device{}; ALenum err{}; switch(param) @@ -322,6 +323,37 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param slot->AuxSendAuto = value; break; + case AL_EFFECTSLOT_TARGET_SOFT: + target = (value ? LookupEffectSlot(context.get(), value) : nullptr); + if(value && !target) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Invalid effect slot target ID"); + if(target) + { + ALeffectslot *checker{target}; + while(checker && checker != slot) + checker = checker->Target; + if(checker) + SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, + "Setting target of effect slot ID %u to %u creates circular chain", slot->id, + target->id); + } + + if(ALeffectslot *oldtarget{slot->Target}) + { + /* We must force an update if there was an existing effect slot + * target, in case it's about to be deleted. + */ + if(target) IncrementRef(&target->ref); + DecrementRef(&oldtarget->ref); + slot->Target = target; + UpdateEffectSlotProps(slot, context.get()); + return; + } + + if(target) IncrementRef(&target->ref); + slot->Target = target; + break; + default: SETERR_RETURN(context.get(), AL_INVALID_ENUM,, "Invalid effect slot integer property 0x%04x", param); @@ -335,6 +367,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum para { case AL_EFFECTSLOT_EFFECT: case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + case AL_EFFECTSLOT_TARGET_SOFT: alAuxiliaryEffectSloti(effectslot, param, values[0]); return; } @@ -422,6 +455,10 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum pa *value = slot->AuxSendAuto; break; + case AL_EFFECTSLOT_TARGET_SOFT: + *value = slot->Target ? slot->Target->id : 0; + break; + default: SETERR_RETURN(context.get(), AL_INVALID_ENUM,, "Invalid effect slot integer property 0x%04x", param); @@ -434,6 +471,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum p { case AL_EFFECTSLOT_EFFECT: case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + case AL_EFFECTSLOT_TARGET_SOFT: alGetAuxiliaryEffectSloti(effectslot, param, values); return; } -- cgit v1.2.3 From fbae41020d8968d0e65af08584df4736b5ed7239 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 24 Dec 2018 19:29:01 -0800 Subject: Remove extraneous typedef, struct, and enum keywords --- Alc/alc.cpp | 33 ++++++++++----------- Alc/alu.cpp | 30 +++++++++---------- Alc/backends/alsa.cpp | 6 ++-- Alc/backends/alsa.h | 2 +- Alc/backends/base.h | 6 ++-- Alc/backends/coreaudio.cpp | 2 +- Alc/backends/coreaudio.h | 2 +- Alc/backends/dsound.cpp | 4 +-- Alc/backends/dsound.h | 2 +- Alc/backends/jack.cpp | 2 +- Alc/backends/jack.h | 2 +- Alc/backends/loopback.cpp | 2 +- Alc/backends/loopback.h | 2 +- Alc/backends/null.cpp | 2 +- Alc/backends/null.h | 2 +- Alc/backends/opensl.cpp | 6 ++-- Alc/backends/opensl.h | 2 +- Alc/backends/oss.cpp | 6 ++-- Alc/backends/oss.h | 2 +- Alc/backends/portaudio.cpp | 2 +- Alc/backends/portaudio.h | 2 +- Alc/backends/pulseaudio.cpp | 2 +- Alc/backends/pulseaudio.h | 2 +- Alc/backends/qsa.cpp | 6 ++-- Alc/backends/qsa.h | 2 +- Alc/backends/sdl2.cpp | 6 ++-- Alc/backends/sdl2.h | 2 +- Alc/backends/sndio.cpp | 10 +++---- Alc/backends/sndio.h | 2 +- Alc/backends/solaris.cpp | 2 +- Alc/backends/solaris.h | 2 +- Alc/backends/wasapi.cpp | 4 +-- Alc/backends/wasapi.h | 2 +- Alc/backends/wave.cpp | 2 +- Alc/backends/wave.h | 2 +- Alc/backends/winmm.cpp | 2 +- Alc/backends/winmm.h | 2 +- Alc/converter.cpp | 10 +++---- Alc/converter.h | 7 ++--- Alc/helpers.cpp | 4 +-- Alc/mixer/defs.h | 20 ++++--------- Alc/mixvoice.cpp | 14 ++++----- Alc/panning.cpp | 18 +++++------ OpenAL32/Include/alAuxEffectSlot.h | 2 +- OpenAL32/Include/alBuffer.h | 26 +++++++--------- OpenAL32/Include/alEffect.h | 8 ++--- OpenAL32/Include/alFilter.h | 40 ++++++++++++------------- OpenAL32/Include/alMain.h | 34 ++++++++++----------- OpenAL32/Include/alSource.h | 25 ++++++---------- OpenAL32/Include/alu.h | 61 +++++++++++++++++--------------------- OpenAL32/alAuxEffectSlot.cpp | 4 +-- OpenAL32/alBuffer.cpp | 25 ++++++++-------- OpenAL32/alEffect.cpp | 6 ++-- OpenAL32/alListener.cpp | 2 +- OpenAL32/alSource.cpp | 38 ++++++++++++------------ OpenAL32/alState.cpp | 4 +-- 56 files changed, 242 insertions(+), 275 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index bde9aa79..b6065e97 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1148,11 +1148,11 @@ static void alc_initconfig(void) continue; size_t len{next ? (size_t)(next-str) : strlen(str)}; - for(n = 0;n < EFFECTLIST_SIZE;n++) + for(size_t n{0u};n < countof(gEffectList);n++) { - if(len == strlen(EffectList[n].name) && - strncmp(EffectList[n].name, str, len) == 0) - DisabledEffects[EffectList[n].type] = AL_TRUE; + if(len == strlen(gEffectList[n].name) && + strncmp(gEffectList[n].name, str, len) == 0) + DisabledEffects[gEffectList[n].type] = AL_TRUE; } } while(next++); } @@ -1168,7 +1168,7 @@ static void alc_initconfig(void) /************************************************ * Device enumeration ************************************************/ -static void ProbeDevices(std::string *list, BackendInfo *backendinfo, enum DevProbe type) +static void ProbeDevices(std::string *list, BackendInfo *backendinfo, DevProbe type) { DO_INITCONFIG(); @@ -1246,13 +1246,12 @@ ALsizei ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept return 0; } -static ALboolean DecomposeDevFormat(ALenum format, enum DevFmtChannels *chans, - enum DevFmtType *type) +static ALboolean DecomposeDevFormat(ALenum format, DevFmtChannels *chans, DevFmtType *type) { static const struct { ALenum format; - enum DevFmtChannels channels; - enum DevFmtType type; + DevFmtChannels channels; + DevFmtType type; } list[] = { { AL_FORMAT_MONO8, DevFmtMono, DevFmtUByte }, { AL_FORMAT_MONO16, DevFmtMono, DevFmtShort }, @@ -1585,13 +1584,13 @@ static inline void UpdateClockBase(ALCdevice *device) */ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { - enum HrtfRequestMode hrtf_userreq = Hrtf_Default; - enum HrtfRequestMode hrtf_appreq = Hrtf_Default; + HrtfRequestMode hrtf_userreq = Hrtf_Default; + HrtfRequestMode hrtf_appreq = Hrtf_Default; ALCenum gainLimiter = device->LimiterState; const ALsizei old_sends = device->NumAuxSends; ALsizei new_sends = device->NumAuxSends; - enum DevFmtChannels oldChans; - enum DevFmtType oldType; + DevFmtChannels oldChans; + DevFmtType oldType; ALboolean update_failed; ALCsizei hrtf_id = -1; ALCcontext *context; @@ -1778,8 +1777,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) else { device->Frequency = freq; - device->FmtChans = static_cast(schans); - device->FmtType = static_cast(stype); + device->FmtChans = static_cast(schans); + device->FmtType = static_cast(stype); if(schans == ALC_BFORMAT3D_SOFT) { device->mAmbiOrder = aorder; @@ -3661,7 +3660,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) { static constexpr struct ChannelMap { const char name[16]; - enum DevFmtChannels chans; + DevFmtChannels chans; ALsizei order; } chanlist[] = { { "mono", DevFmtMono, 0 }, @@ -3693,7 +3692,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) { static constexpr struct TypeMap { const char name[16]; - enum DevFmtType type; + DevFmtType type; } typelist[] = { { "int8", DevFmtByte }, { "uint8", DevFmtUByte }, diff --git a/Alc/alu.cpp b/Alc/alu.cpp index b039f5af..01b4f3c3 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -100,7 +100,7 @@ void ClearArray(ALfloat (&f)[MAX_OUTPUT_CHANNELS]) } struct ChanMap { - enum Channel channel; + Channel channel; ALfloat angle; ALfloat elevation; }; @@ -454,7 +454,7 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) } -constexpr struct ChanMap MonoMap[1]{ +constexpr ChanMap MonoMap[1]{ { FrontCenter, 0.0f, 0.0f } }, RearMap[2]{ { BackLeft, Deg2Rad(-150.0f), Deg2Rad(0.0f) }, @@ -509,7 +509,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev ALsizei num_channels{0}; bool isbformat{false}; ALfloat downmix_gain{1.0f}; - switch(Buffer->FmtChannels) + switch(Buffer->mFmtChannels) { case FmtMono: chans = MonoMap; @@ -633,7 +633,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev * responses. */ ALfloat coeffs[MAX_AMBI_COEFFS]; - CalcAngleCoeffs((Device->Render_Mode==StereoPair) ? ScaleAzimuthFront(Azi, 1.5f) : Azi, + CalcAngleCoeffs((Device->mRenderMode==StereoPair) ? ScaleAzimuthFront(Azi, 1.5f) : Azi, Elev, Spread, coeffs); /* NOTE: W needs to be scaled due to FuMa normalization. */ @@ -745,7 +745,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev } } } - else if(Device->Render_Mode == HrtfRender) + else if(Device->mRenderMode == HrtfRender) { /* Full HRTF rendering. Skip the virtual channels and render to the * real outputs. @@ -858,7 +858,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev * input channels. */ ALfloat coeffs[MAX_AMBI_COEFFS]; - CalcAngleCoeffs((Device->Render_Mode==StereoPair) ? ScaleAzimuthFront(Azi, 1.5f) : Azi, + CalcAngleCoeffs((Device->mRenderMode==StereoPair) ? ScaleAzimuthFront(Azi, 1.5f) : Azi, Elev, Spread, coeffs); for(ALsizei c{0};c < num_channels;c++) @@ -927,7 +927,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev ALfloat coeffs[MAX_AMBI_COEFFS]; CalcAngleCoeffs( - (Device->Render_Mode==StereoPair) ? ScaleAzimuthFront(chans[c].angle, 3.0f) + (Device->mRenderMode==StereoPair) ? ScaleAzimuthFront(chans[c].angle, 3.0f) : chans[c].angle, chans[c].elevation, Spread, coeffs ); @@ -1023,11 +1023,11 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons voice->Step = MAX_PITCH<Step = maxi(fastf2i(Pitch * FRACTIONONE), 1); - if(props->Resampler == BSinc24Resampler) + if(props->mResampler == BSinc24Resampler) BsincPrepare(voice->Step, &voice->ResampleState.bsinc, &bsinc24); - else if(props->Resampler == BSinc12Resampler) + else if(props->mResampler == BSinc12Resampler) BsincPrepare(voice->Step, &voice->ResampleState.bsinc, &bsinc12); - voice->Resampler = SelectResampler(props->Resampler); + voice->Resampler = SelectResampler(props->mResampler); /* Calculate gains */ const ALlistener &Listener = ALContext->Listener; @@ -1361,11 +1361,11 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A voice->Step = MAX_PITCH<Step = maxi(fastf2i(Pitch * FRACTIONONE), 1); - if(props->Resampler == BSinc24Resampler) + if(props->mResampler == BSinc24Resampler) BsincPrepare(voice->Step, &voice->ResampleState.bsinc, &bsinc24); - else if(props->Resampler == BSinc12Resampler) + else if(props->mResampler == BSinc12Resampler) BsincPrepare(voice->Step, &voice->ResampleState.bsinc, &bsinc12); - voice->Resampler = SelectResampler(props->Resampler); + voice->Resampler = SelectResampler(props->mResampler); ALfloat ev{0.0f}, az{0.0f}; if(Distance > 0.0f) @@ -1413,8 +1413,8 @@ void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) ); if(LIKELY(buffer != buffers_end)) { - if(voice->Props.SpatializeMode==SpatializeOn || - (voice->Props.SpatializeMode==SpatializeAuto && (*buffer)->FmtChannels==FmtMono)) + if(voice->Props.mSpatializeMode==SpatializeOn || + (voice->Props.mSpatializeMode==SpatializeAuto && (*buffer)->mFmtChannels==FmtMono)) CalcAttnSourceParams(voice, &voice->Props, *buffer, context); else CalcNonAttnSourceParams(voice, &voice->Props, *buffer, context); diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index 228cafe0..cf3f7fff 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -742,7 +742,7 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) { static const struct { snd_pcm_format_t format; - enum DevFmtType fmttype; + DevFmtType fmttype; } formatlist[] = { { SND_PCM_FORMAT_FLOAT, DevFmtFloat }, { SND_PCM_FORMAT_S32, DevFmtInt }, @@ -767,7 +767,7 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) /* test and set channels (implicitly sets frame bits) */ if(snd_pcm_hw_params_test_channels(self->PcmHandle, hp, device->channelsFromFmt()) < 0) { - static const enum DevFmtChannels channellist[] = { + static const DevFmtChannels channellist[] = { DevFmtStereo, DevFmtQuad, DevFmtX51, @@ -1308,7 +1308,7 @@ void AlsaBackendFactory::deinit() bool AlsaBackendFactory::querySupport(ALCbackend_Type type) { return (type == ALCbackend_Playback || type == ALCbackend_Capture); } -void AlsaBackendFactory::probe(enum DevProbe type, std::string *outnames) +void AlsaBackendFactory::probe(DevProbe type, std::string *outnames) { auto add_device = [outnames](const DevMap &entry) -> void { diff --git a/Alc/backends/alsa.h b/Alc/backends/alsa.h index 3f772115..8ee78f56 100644 --- a/Alc/backends/alsa.h +++ b/Alc/backends/alsa.h @@ -10,7 +10,7 @@ public: bool querySupport(ALCbackend_Type type) override; - void probe(enum DevProbe type, std::string *outnames) override; + void probe(DevProbe type, std::string *outnames) override; ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; diff --git a/Alc/backends/base.h b/Alc/backends/base.h index f4de5176..f7be5cd0 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -34,7 +34,7 @@ ClockLatency GetClockLatency(ALCdevice *device); struct ALCbackendVtable; struct ALCbackend { - const struct ALCbackendVtable *vtbl; + const ALCbackendVtable *vtbl; ALCdevice *mDevice; @@ -84,7 +84,7 @@ DECLARE_THUNK(T, ALCbackend, void, unlock) \ static void T##_ALCbackend_Delete(void *ptr) \ { T##_Delete(STATIC_UPCAST(T, ALCbackend, (ALCbackend*)ptr)); } \ \ -static const struct ALCbackendVtable T##_ALCbackend_vtable = { \ +static const ALCbackendVtable T##_ALCbackend_vtable = { \ T##_ALCbackend_Destruct, \ \ T##_ALCbackend_open, \ @@ -114,7 +114,7 @@ struct BackendFactory { virtual bool querySupport(ALCbackend_Type type) = 0; - virtual void probe(enum DevProbe type, std::string *outnames) = 0; + virtual void probe(DevProbe type, std::string *outnames) = 0; virtual ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) = 0; }; diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index aaaf6221..c73a67f9 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -754,7 +754,7 @@ bool CoreAudioBackendFactory::init() { return true; } bool CoreAudioBackendFactory::querySupport(ALCbackend_Type type) { return (type == ALCbackend_Playback || ALCbackend_Capture); } -void CoreAudioBackendFactory::probe(enum DevProbe type, std::string *outnames) +void CoreAudioBackendFactory::probe(DevProbe type, std::string *outnames) { switch(type) { diff --git a/Alc/backends/coreaudio.h b/Alc/backends/coreaudio.h index 2926ee12..bc9c492c 100644 --- a/Alc/backends/coreaudio.h +++ b/Alc/backends/coreaudio.h @@ -10,7 +10,7 @@ public: bool querySupport(ALCbackend_Type type) override; - void probe(enum DevProbe type, std::string *outnames) override; + void probe(DevProbe type, std::string *outnames) override; ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 26e561bf..4ada7419 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -45,7 +45,7 @@ #include "compat.h" /* MinGW-w64 needs this for some unknown reason now. */ -typedef const WAVEFORMATEX *LPCWAVEFORMATEX; +using LPCWAVEFORMATEX = const WAVEFORMATEX*; #include @@ -960,7 +960,7 @@ void DSoundBackendFactory::deinit() bool DSoundBackendFactory::querySupport(ALCbackend_Type type) { return (type == ALCbackend_Playback || type == ALCbackend_Capture); } -void DSoundBackendFactory::probe(enum DevProbe type, std::string *outnames) +void DSoundBackendFactory::probe(DevProbe type, std::string *outnames) { auto add_device = [outnames](const DevMap &entry) -> void { diff --git a/Alc/backends/dsound.h b/Alc/backends/dsound.h index ebaa9c64..3911686e 100644 --- a/Alc/backends/dsound.h +++ b/Alc/backends/dsound.h @@ -10,7 +10,7 @@ public: bool querySupport(ALCbackend_Type type) override; - void probe(enum DevProbe type, std::string *outnames) override; + void probe(DevProbe type, std::string *outnames) override; ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index 88f60c93..c768983d 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -559,7 +559,7 @@ void JackBackendFactory::deinit() bool JackBackendFactory::querySupport(ALCbackend_Type type) { return (type == ALCbackend_Playback); } -void JackBackendFactory::probe(enum DevProbe type, std::string *outnames) +void JackBackendFactory::probe(DevProbe type, std::string *outnames) { switch(type) { diff --git a/Alc/backends/jack.h b/Alc/backends/jack.h index 8a6e3a22..bdf73701 100644 --- a/Alc/backends/jack.h +++ b/Alc/backends/jack.h @@ -10,7 +10,7 @@ public: bool querySupport(ALCbackend_Type type) override; - void probe(enum DevProbe type, std::string *outnames) override; + void probe(DevProbe type, std::string *outnames) override; ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; diff --git a/Alc/backends/loopback.cpp b/Alc/backends/loopback.cpp index 5a6e14b5..65c87971 100644 --- a/Alc/backends/loopback.cpp +++ b/Alc/backends/loopback.cpp @@ -92,7 +92,7 @@ bool LoopbackBackendFactory::init() bool LoopbackBackendFactory::querySupport(ALCbackend_Type type) { return (type == ALCbackend_Loopback); } -void LoopbackBackendFactory::probe(enum DevProbe, std::string*) +void LoopbackBackendFactory::probe(DevProbe, std::string*) { } ALCbackend *LoopbackBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) diff --git a/Alc/backends/loopback.h b/Alc/backends/loopback.h index 68f33a5c..4607d6ed 100644 --- a/Alc/backends/loopback.h +++ b/Alc/backends/loopback.h @@ -10,7 +10,7 @@ public: bool querySupport(ALCbackend_Type type) override; - void probe(enum DevProbe type, std::string *outnames) override; + void probe(DevProbe type, std::string *outnames) override; ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 969193b8..fb113077 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -180,7 +180,7 @@ bool NullBackendFactory::init() bool NullBackendFactory::querySupport(ALCbackend_Type type) { return (type == ALCbackend_Playback); } -void NullBackendFactory::probe(enum DevProbe type, std::string *outnames) +void NullBackendFactory::probe(DevProbe type, std::string *outnames) { switch(type) { diff --git a/Alc/backends/null.h b/Alc/backends/null.h index e2adfc33..37457d94 100644 --- a/Alc/backends/null.h +++ b/Alc/backends/null.h @@ -10,7 +10,7 @@ public: bool querySupport(ALCbackend_Type type) override; - void probe(enum DevProbe type, std::string *outnames) override; + void probe(DevProbe type, std::string *outnames) override; ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index ab829e05..9213919b 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -46,7 +46,7 @@ static const ALCchar opensl_device[] = "OpenSL"; -static SLuint32 GetChannelMask(enum DevFmtChannels chans) +static SLuint32 GetChannelMask(DevFmtChannels chans) { switch(chans) { @@ -75,7 +75,7 @@ static SLuint32 GetChannelMask(enum DevFmtChannels chans) } #ifdef SL_DATAFORMAT_PCM_EX -static SLuint32 GetTypeRepresentation(enum DevFmtType type) +static SLuint32 GetTypeRepresentation(DevFmtType type) { switch(type) { @@ -979,7 +979,7 @@ bool OSLBackendFactory::init() { return true; } bool OSLBackendFactory::querySupport(ALCbackend_Type type) { return (type == ALCbackend_Playback || type == ALCbackend_Capture); } -void OSLBackendFactory::probe(enum DevProbe type, std::string *outnames) +void OSLBackendFactory::probe(DevProbe type, std::string *outnames) { switch(type) { diff --git a/Alc/backends/opensl.h b/Alc/backends/opensl.h index 799d568f..31d0caae 100644 --- a/Alc/backends/opensl.h +++ b/Alc/backends/opensl.h @@ -10,7 +10,7 @@ public: bool querySupport(ALCbackend_Type type) override; - void probe(enum DevProbe type, std::string *outnames) override; + void probe(DevProbe type, std::string *outnames) override; ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 4b1d468c..e338c40d 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -170,7 +170,7 @@ void ALCossListPopulate(al::vector *devlist, int type_flag) goto done; } - struct oss_sysinfo si; + oss_sysinfo si; if(ioctl(fd, SNDCTL_SYSINFO, &si) == -1) { TRACE("SNDCTL_SYSINFO failed: %s\n", strerror(errno)); @@ -179,7 +179,7 @@ void ALCossListPopulate(al::vector *devlist, int type_flag) for(int i{0};i < si.numaudios;i++) { - struct oss_audioinfo ai; + oss_audioinfo ai; ai.dev = i; if(ioctl(fd, SNDCTL_AUDIOINFO, &ai) == -1) { @@ -759,7 +759,7 @@ void OSSBackendFactory::deinit() bool OSSBackendFactory::querySupport(ALCbackend_Type type) { return (type == ALCbackend_Playback || type == ALCbackend_Capture); } -void OSSBackendFactory::probe(enum DevProbe type, std::string *outnames) +void OSSBackendFactory::probe(DevProbe type, std::string *outnames) { auto add_device = [outnames](const DevMap &entry) -> void { diff --git a/Alc/backends/oss.h b/Alc/backends/oss.h index c3865d84..4652a779 100644 --- a/Alc/backends/oss.h +++ b/Alc/backends/oss.h @@ -10,7 +10,7 @@ public: bool querySupport(ALCbackend_Type type) override; - void probe(enum DevProbe type, std::string *outnames) override; + void probe(DevProbe type, std::string *outnames) override; ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index a89959b6..59b357b5 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -488,7 +488,7 @@ void PortBackendFactory::deinit() bool PortBackendFactory::querySupport(ALCbackend_Type type) { return (type == ALCbackend_Playback || type == ALCbackend_Capture); } -void PortBackendFactory::probe(enum DevProbe type, std::string *outnames) +void PortBackendFactory::probe(DevProbe type, std::string *outnames) { switch(type) { diff --git a/Alc/backends/portaudio.h b/Alc/backends/portaudio.h index 598cd13d..581d4901 100644 --- a/Alc/backends/portaudio.h +++ b/Alc/backends/portaudio.h @@ -10,7 +10,7 @@ public: bool querySupport(ALCbackend_Type type) override; - void probe(enum DevProbe type, std::string *outnames) override; + void probe(DevProbe type, std::string *outnames) override; ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index cbf2992d..8428b9d8 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -1791,7 +1791,7 @@ bool PulseBackendFactory::querySupport(ALCbackend_Type type) return false; } -void PulseBackendFactory::probe(enum DevProbe type, std::string *outnames) +void PulseBackendFactory::probe(DevProbe type, std::string *outnames) { auto add_device = [outnames](const DevMap &entry) -> void { diff --git a/Alc/backends/pulseaudio.h b/Alc/backends/pulseaudio.h index 63b5bbbb..eb7045dc 100644 --- a/Alc/backends/pulseaudio.h +++ b/Alc/backends/pulseaudio.h @@ -10,7 +10,7 @@ public: bool querySupport(ALCbackend_Type type) override; - void probe(enum DevProbe type, std::string *outnames) override; + void probe(DevProbe type, std::string *outnames) override; ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index f0d1876e..f14718c0 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -119,7 +119,7 @@ void deviceList(int type, al::vector *devmap) int max_cards, card, err, dev; DevMap entry; char name[1024]; - struct snd_ctl_hw_info info; + snd_ctl_hw_info info; max_cards = snd_cards(); if(max_cards < 0) @@ -195,7 +195,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; qsa_data *data = self->ExtraData; snd_pcm_channel_status_t status; - struct sched_param param; + sched_param param; char* write_ptr; ALint len; int sret; @@ -978,7 +978,7 @@ void QSABackendFactory::deinit() bool QSABackendFactory::querySupport(ALCbackend_Type type) { return (type == ALCbackend_Playback || type == ALCbackend_Capture); } -void QSABackendFactory::probe(enum DevProbe type, std::string *outnames) +void QSABackendFactory::probe(DevProbe type, std::string *outnames) { auto add_device = [outnames](const DevMap &entry) -> void { diff --git a/Alc/backends/qsa.h b/Alc/backends/qsa.h index c4941392..99d80106 100644 --- a/Alc/backends/qsa.h +++ b/Alc/backends/qsa.h @@ -10,7 +10,7 @@ public: bool querySupport(ALCbackend_Type type) override; - void probe(enum DevProbe type, std::string *outnames) override; + void probe(DevProbe type, std::string *outnames) override; ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; diff --git a/Alc/backends/sdl2.cpp b/Alc/backends/sdl2.cpp index f0c98fab..d61e0a1b 100644 --- a/Alc/backends/sdl2.cpp +++ b/Alc/backends/sdl2.cpp @@ -44,8 +44,8 @@ struct ALCsdl2Backend final : public ALCbackend { ALsizei frameSize; ALuint Frequency; - enum DevFmtChannels FmtChans; - enum DevFmtType FmtType; + DevFmtChannels FmtChans; + DevFmtType FmtType; ALuint UpdateSize; }; @@ -233,7 +233,7 @@ bool SDL2BackendFactory::querySupport(ALCbackend_Type type) return (type == ALCbackend_Playback); } -void SDL2BackendFactory::probe(enum DevProbe type, std::string *outnames) +void SDL2BackendFactory::probe(DevProbe type, std::string *outnames) { if(type != ALL_DEVICE_PROBE) return; diff --git a/Alc/backends/sdl2.h b/Alc/backends/sdl2.h index 7f383447..7bf4d0e4 100644 --- a/Alc/backends/sdl2.h +++ b/Alc/backends/sdl2.h @@ -10,7 +10,7 @@ public: bool querySupport(ALCbackend_Type type) override; - void probe(enum DevProbe type, std::string *outnames) override; + void probe(DevProbe type, std::string *outnames) override; ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index 25566490..2be1d26c 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -40,7 +40,7 @@ static const ALCchar sndio_device[] = "SndIO Default"; struct SndioPlayback final : public ALCbackend { - struct sio_hdl *sndHandle{nullptr}; + sio_hdl *sndHandle{nullptr}; ALvoid *mix_data{nullptr}; ALsizei data_size{0}; @@ -152,7 +152,7 @@ static ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name) static ALCboolean SndioPlayback_reset(SndioPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - struct sio_par par; + sio_par par; sio_initpar(&par); @@ -277,7 +277,7 @@ static void SndioPlayback_stop(SndioPlayback *self) struct SndioCapture final : public ALCbackend { - struct sio_hdl *sndHandle{nullptr}; + sio_hdl *sndHandle{nullptr}; RingBufferPtr ring{nullptr}; @@ -379,7 +379,7 @@ static int SndioCapture_recordProc(SndioCapture *self) static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - struct sio_par par; + sio_par par; if(!name) name = sndio_device; @@ -536,7 +536,7 @@ bool SndIOBackendFactory::init() bool SndIOBackendFactory::querySupport(ALCbackend_Type type) { return (type == ALCbackend_Playback || type == ALCbackend_Capture); } -void SndIOBackendFactory::probe(enum DevProbe type, std::string *outnames) +void SndIOBackendFactory::probe(DevProbe type, std::string *outnames) { switch(type) { diff --git a/Alc/backends/sndio.h b/Alc/backends/sndio.h index 38cd2767..20e99afb 100644 --- a/Alc/backends/sndio.h +++ b/Alc/backends/sndio.h @@ -10,7 +10,7 @@ public: bool querySupport(ALCbackend_Type type) override; - void probe(enum DevProbe type, std::string *outnames) override; + void probe(DevProbe type, std::string *outnames) override; ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index 79341ad1..41026de8 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -301,7 +301,7 @@ bool SolarisBackendFactory::init() bool SolarisBackendFactory::querySupport(ALCbackend_Type type) { return (type == ALCbackend_Playback); } -void SolarisBackendFactory::probe(enum DevProbe type, std::string *outnames) +void SolarisBackendFactory::probe(DevProbe type, std::string *outnames) { switch(type) { diff --git a/Alc/backends/solaris.h b/Alc/backends/solaris.h index dcb34570..73f4a467 100644 --- a/Alc/backends/solaris.h +++ b/Alc/backends/solaris.h @@ -10,7 +10,7 @@ public: bool querySupport(ALCbackend_Type type) override; - void probe(enum DevProbe type, std::string *outnames) override; + void probe(DevProbe type, std::string *outnames) override; ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 3f8cad23..c1b4bddb 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -1601,7 +1601,7 @@ HRESULT ALCwasapiCapture::resetProxy() wfx = nullptr; } - enum DevFmtType srcType; + DevFmtType srcType; if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_PCM)) { if(OutputType.Format.wBitsPerSample == 8) @@ -1839,7 +1839,7 @@ void WasapiBackendFactory::deinit() bool WasapiBackendFactory::querySupport(ALCbackend_Type type) { return (type == ALCbackend_Playback || type == ALCbackend_Capture); } -void WasapiBackendFactory::probe(enum DevProbe type, std::string *outnames) +void WasapiBackendFactory::probe(DevProbe type, std::string *outnames) { ThreadRequest req{ nullptr, 0 }; diff --git a/Alc/backends/wasapi.h b/Alc/backends/wasapi.h index 2ee10ac8..a94f85df 100644 --- a/Alc/backends/wasapi.h +++ b/Alc/backends/wasapi.h @@ -10,7 +10,7 @@ public: bool querySupport(ALCbackend_Type type) override; - void probe(enum DevProbe type, std::string *outnames) override; + void probe(DevProbe type, std::string *outnames) override; ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index 463e6bd7..d40e93f0 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -385,7 +385,7 @@ bool WaveBackendFactory::init() bool WaveBackendFactory::querySupport(ALCbackend_Type type) { return (type == ALCbackend_Playback); } -void WaveBackendFactory::probe(enum DevProbe type, std::string *outnames) +void WaveBackendFactory::probe(DevProbe type, std::string *outnames) { switch(type) { diff --git a/Alc/backends/wave.h b/Alc/backends/wave.h index 65bb5ecf..bb51cc71 100644 --- a/Alc/backends/wave.h +++ b/Alc/backends/wave.h @@ -10,7 +10,7 @@ public: bool querySupport(ALCbackend_Type type) override; - void probe(enum DevProbe type, std::string *outnames) override; + void probe(DevProbe type, std::string *outnames) override; ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 38766869..0ebba81c 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -669,7 +669,7 @@ void WinMMBackendFactory::deinit() bool WinMMBackendFactory::querySupport(ALCbackend_Type type) { return (type == ALCbackend_Playback || type == ALCbackend_Capture); } -void WinMMBackendFactory::probe(enum DevProbe type, std::string *outnames) +void WinMMBackendFactory::probe(DevProbe type, std::string *outnames) { auto add_device = [outnames](const std::string &dname) -> void { diff --git a/Alc/backends/winmm.h b/Alc/backends/winmm.h index b60dbc10..e5801c01 100644 --- a/Alc/backends/winmm.h +++ b/Alc/backends/winmm.h @@ -10,7 +10,7 @@ public: bool querySupport(ALCbackend_Type type) override; - void probe(enum DevProbe type, std::string *outnames) override; + void probe(DevProbe type, std::string *outnames) override; ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; diff --git a/Alc/converter.cpp b/Alc/converter.cpp index 3effddd8..66627879 100644 --- a/Alc/converter.cpp +++ b/Alc/converter.cpp @@ -44,8 +44,7 @@ inline void LoadSampleArray(ALfloat *RESTRICT dst, const void *src, ALint srcste dst[i] = LoadSample(ssrc[i*srcstep]); } -void LoadSamples(ALfloat *dst, const ALvoid *src, ALint srcstep, enum DevFmtType srctype, - ALsizei samples) +void LoadSamples(ALfloat *dst, const ALvoid *src, ALint srcstep, DevFmtType srctype, ALsizei samples) { #define HANDLE_FMT(T) \ case T: LoadSampleArray(dst, src, srcstep, samples); break @@ -95,7 +94,7 @@ inline void StoreSampleArray(void *dst, const ALfloat *RESTRICT src, ALint dstst } -void StoreSamples(ALvoid *dst, const ALfloat *src, ALint dststep, enum DevFmtType dsttype, ALsizei samples) +void StoreSamples(ALvoid *dst, const ALfloat *src, ALint dststep, DevFmtType dsttype, ALsizei samples) { #define HANDLE_FMT(T) \ case T: StoreSampleArray(dst, src, dststep, samples); break @@ -136,9 +135,8 @@ void Stereo2Mono(ALfloat *RESTRICT dst, const void *src, ALsizei frames) } // namespace -SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, - ALsizei numchans, ALsizei srcRate, ALsizei dstRate, - Resampler resampler) +SampleConverter *CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, ALsizei numchans, + ALsizei srcRate, ALsizei dstRate, Resampler resampler) { if(numchans <= 0 || srcRate <= 0 || dstRate <= 0) return nullptr; diff --git a/Alc/converter.h b/Alc/converter.h index 7444d4fa..1c473f49 100644 --- a/Alc/converter.h +++ b/Alc/converter.h @@ -29,9 +29,8 @@ struct SampleConverter { DEF_PLACE_NEWDEL() }; -SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, - ALsizei numchans, ALsizei srcRate, ALsizei dstRate, - Resampler resampler); +SampleConverter *CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, ALsizei numchans, + ALsizei srcRate, ALsizei dstRate, Resampler resampler); void DestroySampleConverter(SampleConverter **converter); ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes); @@ -49,7 +48,7 @@ struct ChannelConverter { DEF_NEWDEL(ChannelConverter) }; -ChannelConverter *CreateChannelConverter(enum DevFmtType srcType, enum DevFmtChannels srcChans, enum DevFmtChannels dstChans); +ChannelConverter *CreateChannelConverter(DevFmtType srcType, DevFmtChannels srcChans, DevFmtChannels dstChans); void DestroyChannelConverter(ChannelConverter **converter); void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALfloat *dst, ALsizei frames); diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index 17942855..beee4bff 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -125,13 +125,13 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x #if defined(HAVE_GCC_GET_CPUID) && (defined(__i386__) || defined(__x86_64__) || \ defined(_M_IX86) || defined(_M_X64)) -typedef unsigned int reg_type; +using reg_type = unsigned int; static inline void get_cpuid(int f, reg_type *regs) { __get_cpuid(f, ®s[0], ®s[1], ®s[2], ®s[3]); } #define CAN_GET_CPUID #elif defined(HAVE_CPUID_INTRINSIC) && (defined(__i386__) || defined(__x86_64__) || \ defined(_M_IX86) || defined(_M_X64)) -typedef int reg_type; +using reg_type = int; static inline void get_cpuid(int f, reg_type *regs) { (__cpuid)(regs, f); } #define CAN_GET_CPUID diff --git a/Alc/mixer/defs.h b/Alc/mixer/defs.h index 46f70982..5fa88773 100644 --- a/Alc/mixer/defs.h +++ b/Alc/mixer/defs.h @@ -6,12 +6,8 @@ #include "alMain.h" #include "alu.h" -#ifdef __cplusplus -extern "C" { -#endif struct MixGains; - struct MixHrtfParams; struct HrtfState; @@ -26,8 +22,8 @@ const ALfloat *Resample_bsinc_C(const InterpState *state, const ALfloat *RESTRIC /* C mixers */ void MixHrtf_C(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, struct MixHrtfParams *hrtfparams, - struct HrtfState *hrtfstate, ALsizei BufferSize); + const ALsizei IrSize, MixHrtfParams *hrtfparams, + HrtfState *hrtfstate, ALsizei BufferSize); void MixHrtfBlend_C(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, @@ -47,8 +43,8 @@ void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, /* SSE mixers */ void MixHrtf_SSE(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, struct MixHrtfParams *hrtfparams, - struct HrtfState *hrtfstate, ALsizei BufferSize); + const ALsizei IrSize, MixHrtfParams *hrtfparams, + HrtfState *hrtfstate, ALsizei BufferSize); void MixHrtfBlend_SSE(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, @@ -94,8 +90,8 @@ const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *RESTR /* Neon mixers */ void MixHrtf_Neon(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, struct MixHrtfParams *hrtfparams, - struct HrtfState *hrtfstate, ALsizei BufferSize); + const ALsizei IrSize, MixHrtfParams *hrtfparams, + HrtfState *hrtfstate, ALsizei BufferSize); void MixHrtfBlend_Neon(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, @@ -120,8 +116,4 @@ const ALfloat *Resample_bsinc_Neon(const InterpState *state, const ALfloat *REST ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen); -#ifdef __cplusplus -} // extern "C" -#endif - #endif /* MIXER_DEFS_H */ diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index db2609f5..680f4a31 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -54,7 +54,7 @@ static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, static_assert(MAX_RESAMPLE_PADDING >= 24, "MAX_RESAMPLE_PADDING must be at least 24!"); -enum Resampler ResamplerDefault = LinearResampler; +Resampler ResamplerDefault = LinearResampler; MixerFunc MixSamples = Mix_C; RowMixerFunc MixRowSamples = MixRow_C; @@ -113,7 +113,7 @@ static inline HrtfMixerBlendFunc SelectHrtfBlendMixer(void) return MixHrtfBlend_C; } -ResamplerFunc SelectResampler(enum Resampler resampler) +ResamplerFunc SelectResampler(Resampler resampler) { switch(resampler) { @@ -183,7 +183,7 @@ void aluInitMixer(void) char *end; long n = strtol(str, &end, 0); if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == FIR4Resampler)) - ResamplerDefault = static_cast(n); + ResamplerDefault = static_cast(n); else WARN("Invalid resampler: %s\n", str); } @@ -393,7 +393,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize const ALbyte *Data{buffer->mData.data()}; LoadSamples(&SrcData[FilledAmt], &Data[(DataPosInt*NumChannels + chan)*SampleSize], - NumChannels, buffer->FmtType, DataSize + NumChannels, buffer->mFmtType, DataSize ); return CompLen; }; @@ -417,7 +417,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize const ALbyte *Data{buffer->mData.data()}; LoadSamples(&SrcData[FilledAmt], &Data[(DataPosInt*NumChannels + chan)*SampleSize], - NumChannels, buffer->FmtType, DataSize + NumChannels, buffer->mFmtType, DataSize ); return CompLen; }; @@ -440,7 +440,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize const ALbyte *Data{buffer->mData.data()}; LoadSamples(&SrcData[FilledAmt], &Data[(LoopStart*NumChannels + chan)*SampleSize], - NumChannels, buffer->FmtType, DataSize + NumChannels, buffer->mFmtType, DataSize ); return CompLen; }; @@ -479,7 +479,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize Data += (pos*NumChannels + chan)*SampleSize; LoadSamples(&SrcData[FilledAmt], Data, NumChannels, - buffer->FmtType, DataSize); + buffer->mFmtType, DataSize); return CompLen; }; auto buffers_end = tmpiter->buffers + tmpiter->num_buffers; diff --git a/Alc/panning.cpp b/Alc/panning.cpp index cec6eaf7..5e7806ec 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -678,7 +678,7 @@ void InitHrtfPanning(ALCdevice *device) /* Don't bother with HOA when using full HRTF rendering. Nothing needs it, * and it eases the CPU/memory load. */ - if(device->Render_Mode != HrtfRender) + if(device->mRenderMode != HrtfRender) { device->AmbiUp.reset(new AmbiUpsampler{}); @@ -879,7 +879,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr device->mHrtfState = nullptr; device->mHrtf = nullptr; device->HrtfName.clear(); - device->Render_Mode = NormalRender; + device->mRenderMode = NormalRender; device->Dry.Ambi = AmbiConfig{}; device->Dry.CoeffCount = 0; @@ -1063,20 +1063,20 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr Hrtf_DecRef(old_hrtf); old_hrtf = nullptr; - device->Render_Mode = HrtfRender; + device->mRenderMode = HrtfRender; const char *mode; if(ConfigValueStr(device->DeviceName.c_str(), nullptr, "hrtf-mode", &mode)) { if(strcasecmp(mode, "full") == 0) - device->Render_Mode = HrtfRender; + device->mRenderMode = HrtfRender; else if(strcasecmp(mode, "basic") == 0) - device->Render_Mode = NormalRender; + device->mRenderMode = NormalRender; else ERR("Unexpected hrtf-mode: %s\n", mode); } TRACE("%s HRTF rendering enabled, using \"%s\"\n", - ((device->Render_Mode == HrtfRender) ? "Full" : "Basic"), device->HrtfName.c_str() + ((device->mRenderMode == HrtfRender) ? "Full" : "Basic"), device->HrtfName.c_str() ); InitHrtfPanning(device); return; @@ -1089,7 +1089,7 @@ no_hrtf: old_hrtf = nullptr; TRACE("HRTF disabled\n"); - device->Render_Mode = StereoPair; + device->mRenderMode = StereoPair; int bs2blevel{((headphones && hrtf_appreq != Hrtf_Disable) || (hrtf_appreq == Hrtf_Enable)) ? 5 : 0}; @@ -1110,11 +1110,11 @@ no_hrtf: if(ConfigValueStr(device->DeviceName.c_str(), nullptr, "stereo-encoding", &mode)) { if(strcasecmp(mode, "uhj") == 0) - device->Render_Mode = NormalRender; + device->mRenderMode = NormalRender; else if(strcasecmp(mode, "panpot") != 0) ERR("Unexpected stereo-encoding: %s\n", mode); } - if(device->Render_Mode == NormalRender) + if(device->mRenderMode == NormalRender) { device->Uhj_Encoder.reset(new Uhj2Encoder{}); TRACE("UHJ enabled\n"); diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 1b14dd36..d970444c 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -46,7 +46,7 @@ struct EffectStateFactory { struct ALeffectslotArray { ALsizei count; - struct ALeffectslot *slot[]; + ALeffectslot *slot[]; }; diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 691c7e22..ec9f6c37 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -33,12 +33,10 @@ enum UserFmtChannels { UserFmtBFormat3D, /* WXYZ */ }; -ALsizei BytesFromUserFmt(enum UserFmtType type); -ALsizei ChannelsFromUserFmt(enum UserFmtChannels chans); -inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type) -{ - return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type); -} +ALsizei BytesFromUserFmt(UserFmtType type); +ALsizei ChannelsFromUserFmt(UserFmtChannels chans); +inline ALsizei FrameSizeFromUserFmt(UserFmtChannels chans, UserFmtType type) +{ return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type); } /* Storable formats */ @@ -81,12 +79,10 @@ template<> struct FmtTypeTraits { using Type = ALubyte; }; -ALsizei BytesFromFmt(enum FmtType type); -ALsizei ChannelsFromFmt(enum FmtChannels chans); -inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type) -{ - return ChannelsFromFmt(chans) * BytesFromFmt(type); -} +ALsizei BytesFromFmt(FmtType type); +ALsizei ChannelsFromFmt(FmtChannels chans); +inline ALsizei FrameSizeFromFmt(FmtChannels chans, FmtType type) +{ return ChannelsFromFmt(chans) * BytesFromFmt(type); } struct ALbuffer { @@ -96,11 +92,11 @@ struct ALbuffer { ALbitfieldSOFT Access{0u}; ALsizei SampleLen{0}; - enum FmtChannels FmtChannels{}; - enum FmtType FmtType{}; + FmtChannels mFmtChannels{}; + FmtType mFmtType{}; ALsizei BytesAlloc{0}; - enum UserFmtType OriginalType{}; + UserFmtType OriginalType{}; ALsizei OriginalSize{0}; ALsizei OriginalAlign{0}; diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index 441a8e97..710f512a 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -32,9 +32,7 @@ struct EffectList { int type; ALenum val; }; -#define EFFECTLIST_SIZE 14 -extern const EffectList EffectList[EFFECTLIST_SIZE]; - +extern const EffectList gEffectList[14]; struct ALeffectVtable { void (*const setParami)(ALeffect *effect, ALCcontext *context, ALenum param, ALint val); @@ -72,7 +70,7 @@ extern const ALeffectVtable ALpshifter_vtable; extern const ALeffectVtable ALdedicated_vtable; -typedef union ALeffectProps { +union ALeffectProps { struct { // Shared Reverb Properties ALfloat Density; @@ -173,7 +171,7 @@ typedef union ALeffectProps { struct { ALfloat Gain; } Dedicated; -} ALeffectProps; +}; struct ALeffect { // Effect type (AL_EFFECT_NULL, ...) diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h index feca54e3..1c033ac3 100644 --- a/OpenAL32/Include/alFilter.h +++ b/OpenAL32/Include/alFilter.h @@ -11,27 +11,25 @@ struct ALfilter; -typedef struct ALfilterVtable { - void (*const setParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint val); - void (*const setParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals); - void (*const setParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val); - void (*const setParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals); - - void (*const getParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *val); - void (*const getParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals); - void (*const getParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val); - void (*const getParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals); -} ALfilterVtable; - -#define DEFINE_ALFILTER_VTABLE(T) \ -const struct ALfilterVtable T##_vtable = { \ - T##_setParami, T##_setParamiv, \ - T##_setParamf, T##_setParamfv, \ - T##_getParami, T##_getParamiv, \ - T##_getParamf, T##_getParamfv, \ +struct ALfilterVtable { + void (*const setParami)(ALfilter *filter, ALCcontext *context, ALenum param, ALint val); + void (*const setParamiv)(ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals); + void (*const setParamf)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val); + void (*const setParamfv)(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals); + + void (*const getParami)(ALfilter *filter, ALCcontext *context, ALenum param, ALint *val); + void (*const getParamiv)(ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals); + void (*const getParamf)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val); + void (*const getParamfv)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals); +}; + +#define DEFINE_ALFILTER_VTABLE(T) \ +const ALfilterVtable T##_vtable = { \ + T##_setParami, T##_setParamiv, T##_setParamf, T##_setParamfv, \ + T##_getParami, T##_getParamiv, T##_getParamf, T##_getParamfv, \ } -typedef struct ALfilter { +struct ALfilter { // Filter type (AL_FILTER_NULL, ...) ALenum type; @@ -41,11 +39,11 @@ typedef struct ALfilter { ALfloat GainLF; ALfloat LFReference; - const struct ALfilterVtable *vtab; + const ALfilterVtable *vtab; /* Self ID */ ALuint id; -} ALfilter; +}; #define ALfilter_setParami(o, c, p, v) ((o)->vtab->setParami(o, c, p, v)) #define ALfilter_setParamf(o, c, p, v) ((o)->vtab->setParamf(o, c, p, v)) #define ALfilter_setParamiv(o, c, p, v) ((o)->vtab->setParamiv(o, c, p, v)) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index d12ea780..2ffea8aa 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -100,8 +100,8 @@ constexpr inline size_t countof(const T(&)[N]) noexcept #define FAM_SIZE(T, M, N) (offsetof(T, M) + sizeof(((T*)NULL)->M[0])*(N)) -typedef ALint64SOFT ALint64; -typedef ALuint64SOFT ALuint64; +using ALint64 = ALint64SOFT; +using ALuint64 = ALuint64SOFT; #ifndef U64 #if defined(_MSC_VER) @@ -537,23 +537,23 @@ enum RenderMode { }; -typedef ALfloat ChannelConfig[MAX_AMBI_COEFFS]; +using ChannelConfig = ALfloat[MAX_AMBI_COEFFS]; struct BFChannelConfig { ALfloat Scale; ALsizei Index; }; -typedef union AmbiConfig { +union AmbiConfig { /* Ambisonic coefficients for mixing to the dry buffer. */ ChannelConfig Coeffs[MAX_OUTPUT_CHANNELS]; /* Coefficient channel mapping for mixing to the dry buffer. */ BFChannelConfig Map[MAX_OUTPUT_CHANNELS]; -} AmbiConfig; +}; struct BufferSubList { uint64_t FreeMask{~uint64_t{}}; - struct ALbuffer *Buffers{nullptr}; /* 64 */ + ALbuffer *Buffers{nullptr}; /* 64 */ BufferSubList() noexcept = default; BufferSubList(const BufferSubList&) = delete; @@ -568,7 +568,7 @@ struct BufferSubList { struct EffectSubList { uint64_t FreeMask{~uint64_t{}}; - struct ALeffect *Effects{nullptr}; /* 64 */ + ALeffect *Effects{nullptr}; /* 64 */ EffectSubList() noexcept = default; EffectSubList(const EffectSubList&) = delete; @@ -583,7 +583,7 @@ struct EffectSubList { struct FilterSubList { uint64_t FreeMask{~uint64_t{}}; - struct ALfilter *Filters{nullptr}; /* 64 */ + ALfilter *Filters{nullptr}; /* 64 */ FilterSubList() noexcept = default; FilterSubList(const FilterSubList&) = delete; @@ -597,11 +597,11 @@ struct FilterSubList { }; -typedef struct EnumeratedHrtf { +struct EnumeratedHrtf { std::string name; HrtfHandle *hrtf; -} EnumeratedHrtf; +}; /* Maximum delay in samples for speaker distance compensation. */ @@ -654,7 +654,7 @@ public: */ #define BUFFERSIZE 2048 -typedef struct MixParams { +struct MixParams { AmbiConfig Ambi{}; /* Number of coefficients in each Ambi.Coeffs to mix together (4 for first- * order, 9 for second-order, etc). If the count is 0, Ambi.Map is used @@ -664,16 +664,16 @@ typedef struct MixParams { ALfloat (*Buffer)[BUFFERSIZE]{nullptr}; ALsizei NumChannels{0}; -} MixParams; +}; -typedef struct RealMixParams { - enum Channel ChannelName[MAX_OUTPUT_CHANNELS]{}; +struct RealMixParams { + Channel ChannelName[MAX_OUTPUT_CHANNELS]{}; ALfloat (*Buffer)[BUFFERSIZE]{nullptr}; ALsizei NumChannels{0}; -} RealMixParams; +}; -typedef void (*POSTPROCESS)(ALCdevice *device, ALsizei SamplesToDo); +using POSTPROCESS = void(*)(ALCdevice *device, ALsizei SamplesToDo); struct ALCdevice_struct { RefCount ref{1u}; @@ -729,7 +729,7 @@ struct ALCdevice_struct { std::mutex FilterLock; /* Rendering mode. */ - RenderMode Render_Mode{NormalRender}; + RenderMode mRenderMode{NormalRender}; /* The average speaker distance as determined by the ambdec configuration * (or alternatively, by the NFC-HOA reference delay). Only used for NFC. diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 62c6fae3..381e0a9b 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -9,23 +9,20 @@ #define DEFAULT_SENDS 2 -#ifdef __cplusplus -extern "C" { -#endif - struct ALbuffer; struct ALsource; +struct ALeffectslot; -typedef struct ALbufferlistitem { +struct ALbufferlistitem { std::atomic next; ALsizei max_samples; ALsizei num_buffers; - struct ALbuffer *buffers[]; -} ALbufferlistitem; + ALbuffer *buffers[]; +}; -typedef struct ALsource { +struct ALsource { /** Source properties. */ ALfloat Pitch; ALfloat Gain; @@ -44,9 +41,9 @@ typedef struct ALsource { ALboolean HeadRelative; ALboolean Looping; DistanceModel mDistanceModel; - enum Resampler Resampler; + Resampler mResampler; ALboolean DirectChannels; - enum SpatializeMode Spatialize; + SpatializeMode mSpatialize; ALboolean DryGainHFAuto; ALboolean WetGainAuto; @@ -73,7 +70,7 @@ typedef struct ALsource { ALfloat LFReference; } Direct; struct SendData { - struct ALeffectslot *Slot; + ALeffectslot *Slot; ALfloat Gain; ALfloat GainHF; ALfloat HFReference; @@ -114,12 +111,8 @@ typedef struct ALsource { ALsource(const ALsource&) = delete; ALsource& operator=(const ALsource&) = delete; -} ALsource; +}; void UpdateAllSourceProps(ALCcontext *context); -#ifdef __cplusplus -} -#endif - #endif diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 695fc380..78733d8d 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -59,7 +59,7 @@ enum Resampler { ResamplerMax = BSinc24Resampler }; -extern enum Resampler ResamplerDefault; +extern Resampler ResamplerDefault; /* The number of distinct scale and phase intervals within the bsinc filter * table. @@ -73,7 +73,7 @@ extern enum Resampler ResamplerDefault; * stateless. This just keeps it from having to recompute scale-related * mappings for every sample. */ -typedef struct BsincState { +struct BsincState { ALfloat sf; /* Scale interpolation factor. */ ALsizei m; /* Coefficient count. */ ALsizei l; /* Left coefficient offset. */ @@ -82,18 +82,17 @@ typedef struct BsincState { * index follows contiguously. */ const ALfloat *filter; -} BsincState; +}; -typedef union InterpState { +union InterpState { BsincState bsinc; -} InterpState; +}; -typedef const ALfloat* (*ResamplerFunc)(const InterpState *state, +using ResamplerFunc = const ALfloat*(*)(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, ALint increment, - ALfloat *RESTRICT dst, ALsizei dstlen -); + ALfloat *RESTRICT dst, ALsizei dstlen); -void BsincPrepare(const ALuint increment, BsincState *state, const struct BSincTable *table); +void BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *table); extern const BSincTable bsinc12; extern const BSincTable bsinc24; @@ -161,9 +160,9 @@ struct ALvoicePropsBase { ALfloat Orientation[2][3]; ALboolean HeadRelative; DistanceModel mDistanceModel; - enum Resampler Resampler; + Resampler mResampler; ALboolean DirectChannels; - enum SpatializeMode SpatializeMode; + SpatializeMode mSpatializeMode; ALboolean DryGainHFAuto; ALboolean WetGainAuto; @@ -187,7 +186,7 @@ struct ALvoicePropsBase { ALfloat LFReference; } Direct; struct SendData { - struct ALeffectslot *Slot; + ALeffectslot *Slot; ALfloat Gain; ALfloat GainHF; ALfloat HFReference; @@ -272,26 +271,22 @@ struct ALvoice { void DeinitVoice(ALvoice *voice) noexcept; -typedef void (*MixerFunc)(const ALfloat *data, ALsizei OutChans, - ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, - const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, - ALsizei BufferSize); -typedef void (*RowMixerFunc)(ALfloat *OutBuffer, const ALfloat *gains, - const ALfloat (*RESTRICT data)[BUFFERSIZE], ALsizei InChans, - ALsizei InPos, ALsizei BufferSize); -typedef void (*HrtfMixerFunc)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, MixHrtfParams *hrtfparams, - HrtfState *hrtfstate, ALsizei BufferSize); -typedef void (*HrtfMixerBlendFunc)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, const HrtfParams *oldparams, - MixHrtfParams *newparams, HrtfState *hrtfstate, - ALsizei BufferSize); -typedef void (*HrtfDirectMixerFunc)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - const ALfloat (*RESTRICT Coeffs)[2], - ALfloat (*RESTRICT Values)[2], ALsizei BufferSize); +using MixerFunc = void(*)(const ALfloat *data, ALsizei OutChans, + ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, + const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, ALsizei BufferSize); +using RowMixerFunc = void(*)(ALfloat *OutBuffer, const ALfloat *gains, + const ALfloat (*RESTRICT data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, + ALsizei BufferSize); +using HrtfMixerFunc = void(*)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, + MixHrtfParams *hrtfparams, HrtfState *hrtfstate, ALsizei BufferSize); +using HrtfMixerBlendFunc = void(*)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, + const HrtfParams *oldparams, MixHrtfParams *newparams, HrtfState *hrtfstate, + ALsizei BufferSize); +using HrtfDirectMixerFunc = void(*)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, + const ALfloat *data, ALsizei Offset, const ALsizei IrSize, const ALfloat (*RESTRICT Coeffs)[2], + ALfloat (*RESTRICT Values)[2], ALsizei BufferSize); #define GAIN_MIX_MAX (1000.0f) /* +60dB */ @@ -479,7 +474,7 @@ inline void ComputePanGains(const MixParams *dry, const ALfloat*RESTRICT coeffs, void ComputePanGains(const ALeffectslot *slot, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]); -ALboolean MixSource(struct ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo); +ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo); void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples); /* Caller must lock the device, and the mixer must not be running. */ diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index b91774dc..1b3b97be 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -631,7 +631,7 @@ ALeffectslot::~ALeffectslot() DecrementRef(&Target->ref); Target = nullptr; - struct ALeffectslotProps *props{Update.load()}; + ALeffectslotProps *props{Update.load()}; if(props) { if(props->State) props->State->DecRef(); @@ -653,7 +653,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) props = static_cast(al_calloc(16, sizeof(*props))); else { - struct ALeffectslotProps *next; + ALeffectslotProps *next; do { next = props->next.load(std::memory_order_relaxed); } while(context->FreeEffectslotProps.compare_exchange_weak(props, next, diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index 6bc965c2..2f4b9d4d 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -241,7 +241,7 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U if((access&AL_PRESERVE_DATA_BIT_SOFT)) { /* Can only preserve data with the same format and alignment. */ - if(UNLIKELY(ALBuf->FmtChannels != DstChannels || ALBuf->OriginalType != SrcType)) + if(UNLIKELY(ALBuf->mFmtChannels != DstChannels || ALBuf->OriginalType != SrcType)) SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched format"); if(UNLIKELY(ALBuf->OriginalAlign != align)) SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched alignment"); @@ -322,8 +322,8 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U ALBuf->OriginalType = SrcType; ALBuf->Frequency = freq; - ALBuf->FmtChannels = DstChannels; - ALBuf->FmtType = DstType; + ALBuf->mFmtChannels = DstChannels; + ALBuf->mFmtType = DstType; ALBuf->Access = access; ALBuf->SampleLen = frames; @@ -683,7 +683,7 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons ALsizei align{SanitizeAlignment(srctype, unpack_align)}; if(UNLIKELY(align < 1)) alSetError(context.get(), AL_INVALID_VALUE, "Invalid unpack alignment %d", unpack_align); - else if(UNLIKELY((long)srcchannels != (long)albuf->FmtChannels || + else if(UNLIKELY((long)srcchannels != (long)albuf->mFmtChannels || srctype != albuf->OriginalType)) alSetError(context.get(), AL_INVALID_ENUM, "Unpacking data with mismatched format"); else if(UNLIKELY(align != albuf->OriginalAlign)) @@ -695,8 +695,8 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons buffer); else { - ALsizei num_chans{ChannelsFromFmt(albuf->FmtChannels)}; - ALsizei frame_size{num_chans * BytesFromFmt(albuf->FmtType)}; + ALsizei num_chans{ChannelsFromFmt(albuf->mFmtChannels)}; + ALsizei frame_size{num_chans * BytesFromFmt(albuf->mFmtType)}; ALsizei byte_align{ (albuf->OriginalType == UserFmtIMA4) ? ((align-1)/2 + 4) * num_chans : (albuf->OriginalType == UserFmtMSADPCM) ? ((align-2)/2 + 7) * num_chans : @@ -722,15 +722,15 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons length = length/byte_align * align; void *dst = albuf->mData.data() + offset; - if(srctype == UserFmtIMA4 && albuf->FmtType == FmtShort) + if(srctype == UserFmtIMA4 && albuf->mFmtType == FmtShort) Convert_ALshort_ALima4(static_cast(dst), static_cast(data), num_chans, length, align); - else if(srctype == UserFmtMSADPCM && albuf->FmtType == FmtShort) + else if(srctype == UserFmtMSADPCM && albuf->mFmtType == FmtShort) Convert_ALshort_ALmsadpcm(static_cast(dst), static_cast(data), num_chans, length, align); else { - assert((long)srctype == (long)albuf->FmtType); + assert((long)srctype == (long)albuf->mFmtType); memcpy(dst, data, length*frame_size); } } @@ -1019,16 +1019,15 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value break; case AL_BITS: - *value = BytesFromFmt(albuf->FmtType) * 8; + *value = BytesFromFmt(albuf->mFmtType) * 8; break; case AL_CHANNELS: - *value = ChannelsFromFmt(albuf->FmtChannels); + *value = ChannelsFromFmt(albuf->mFmtChannels); break; case AL_SIZE: - *value = albuf->SampleLen * FrameSizeFromFmt(albuf->FmtChannels, - albuf->FmtType); + *value = albuf->SampleLen * FrameSizeFromFmt(albuf->mFmtChannels, albuf->mFmtType); break; case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: diff --git a/OpenAL32/alEffect.cpp b/OpenAL32/alEffect.cpp index dd16acfb..6a91c852 100644 --- a/OpenAL32/alEffect.cpp +++ b/OpenAL32/alEffect.cpp @@ -35,7 +35,7 @@ #include "alError.h" -const struct EffectList EffectList[EFFECTLIST_SIZE] = { +const EffectList gEffectList[14]{ { "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB }, { "reverb", REVERB_EFFECT, AL_EFFECT_REVERB }, { "autowah", AUTOWAH_EFFECT, AL_EFFECT_AUTOWAH }, @@ -397,9 +397,9 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) if(param == AL_EFFECT_TYPE) { ALboolean isOk = (value == AL_EFFECT_NULL); - for(ALsizei i{0};!isOk && i < EFFECTLIST_SIZE;i++) + for(size_t i{0u};!isOk && i < countof(gEffectList);i++) { - if(value == EffectList[i].val && !DisabledEffects[EffectList[i].type]) + if(value == gEffectList[i].val && !DisabledEffects[gEffectList[i].type]) isOk = AL_TRUE; } diff --git a/OpenAL32/alListener.cpp b/OpenAL32/alListener.cpp index c86c8374..b7fdf9ce 100644 --- a/OpenAL32/alListener.cpp +++ b/OpenAL32/alListener.cpp @@ -405,7 +405,7 @@ void UpdateListenerProps(ALCcontext *context) props = static_cast(al_calloc(16, sizeof(*props))); else { - struct ALlistenerProps *next; + ALlistenerProps *next; do { next = props->next.load(std::memory_order_relaxed); } while(context->FreeListenerProps.compare_exchange_weak(props, next, diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 53aa9389..e88df598 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -96,9 +96,9 @@ void UpdateSourceProps(ALsource *source, ALvoice *voice, ALCcontext *context) std::copy(std::begin(source->Orientation[1]), std::end(source->Orientation[1]), props->Orientation[1]); props->HeadRelative = source->HeadRelative; props->mDistanceModel = source->mDistanceModel; - props->Resampler = source->Resampler; + props->mResampler = source->mResampler; props->DirectChannels = source->DirectChannels; - props->SpatializeMode = source->Spatialize; + props->mSpatializeMode = source->mSpatialize; props->DryGainHFAuto = source->DryGainHFAuto; props->WetGainAuto = source->WetGainAuto; @@ -323,7 +323,7 @@ ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) if(BufferFmt->OriginalType == UserFmtIMA4) { ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; - ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels); + ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->mFmtChannels); ALuint FrameBlockSize = BufferFmt->OriginalAlign; /* Round down to nearest ADPCM block */ @@ -332,7 +332,7 @@ ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) else if(BufferFmt->OriginalType == UserFmtMSADPCM) { ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; - ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels); + ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->mFmtChannels); ALuint FrameBlockSize = BufferFmt->OriginalAlign; /* Round down to nearest ADPCM block */ @@ -340,8 +340,8 @@ ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) } else { - ALuint FrameSize = FrameSizeFromFmt(BufferFmt->FmtChannels, - BufferFmt->FmtType); + const ALsizei FrameSize{FrameSizeFromFmt(BufferFmt->mFmtChannels, + BufferFmt->mFmtType)}; offset = (ALdouble)(readPos * FrameSize); } break; @@ -388,17 +388,17 @@ ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac) if(BufferFmt->OriginalType == UserFmtIMA4) { ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; - *offset /= align * ChannelsFromFmt(BufferFmt->FmtChannels); + *offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels); *offset *= BufferFmt->OriginalAlign; } else if(BufferFmt->OriginalType == UserFmtMSADPCM) { ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; - *offset /= align * ChannelsFromFmt(BufferFmt->FmtChannels); + *offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels); *offset *= BufferFmt->OriginalAlign; } else - *offset /= FrameSizeFromFmt(BufferFmt->FmtChannels, BufferFmt->FmtType); + *offset /= FrameSizeFromFmt(BufferFmt->mFmtChannels, BufferFmt->mFmtType); *frac = 0; break; @@ -1398,14 +1398,14 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co case AL_SOURCE_RESAMPLER_SOFT: CHECKVAL(*values >= 0 && *values <= ResamplerMax); - Source->Resampler = static_cast(*values); + Source->mResampler = static_cast(*values); DO_UPDATEPROPS(); return AL_TRUE; case AL_SOURCE_SPATIALIZE_SOFT: CHECKVAL(*values >= AL_FALSE && *values <= AL_AUTO_SOFT); - Source->Spatialize = static_cast(*values); + Source->mSpatialize = static_cast(*values); DO_UPDATEPROPS(); return AL_TRUE; @@ -1889,11 +1889,11 @@ ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL return AL_TRUE; case AL_SOURCE_RESAMPLER_SOFT: - *values = Source->Resampler; + *values = Source->mResampler; return AL_TRUE; case AL_SOURCE_SPATIALIZE_SOFT: - *values = Source->Spatialize; + *values = Source->mSpatialize; return AL_TRUE; /* 1x float/double */ @@ -2814,8 +2814,8 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) ); if(buffer != buffers_end) { - voice->NumChannels = ChannelsFromFmt((*buffer)->FmtChannels); - voice->SampleSize = BytesFromFmt((*buffer)->FmtType); + voice->NumChannels = ChannelsFromFmt((*buffer)->mFmtChannels); + voice->SampleSize = BytesFromFmt((*buffer)->mFmtType); } /* Clear previous samples. */ @@ -3058,7 +3058,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu if(BufferFmt == nullptr) BufferFmt = buffer; else if(BufferFmt->Frequency != buffer->Frequency || - BufferFmt->FmtChannels != buffer->FmtChannels || + BufferFmt->mFmtChannels != buffer->mFmtChannels || BufferFmt->OriginalType != buffer->OriginalType) { alSetError(context.get(), AL_INVALID_OPERATION, @@ -3166,7 +3166,7 @@ AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, co if(BufferFmt == nullptr) BufferFmt = buffer; else if(BufferFmt->Frequency != buffer->Frequency || - BufferFmt->FmtChannels != buffer->FmtChannels || + BufferFmt->mFmtChannels != buffer->mFmtChannels || BufferFmt->OriginalType != buffer->OriginalType) { alSetError(context.get(), AL_INVALID_OPERATION, @@ -3331,9 +3331,9 @@ ALsource::ALsource(ALsizei num_sends) HeadRelative = AL_FALSE; Looping = AL_FALSE; mDistanceModel = DistanceModel::Default; - Resampler = ResamplerDefault; + mResampler = ResamplerDefault; DirectChannels = AL_FALSE; - Spatialize = SpatializeAuto; + mSpatialize = SpatializeAuto; StereoPan[0] = Deg2Rad( 30.0f); StereoPan[1] = Deg2Rad(-30.0f); diff --git a/OpenAL32/alState.cpp b/OpenAL32/alState.cpp index 37bddea3..3f55687d 100644 --- a/OpenAL32/alState.cpp +++ b/OpenAL32/alState.cpp @@ -766,12 +766,12 @@ AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index) void UpdateContextProps(ALCcontext *context) { /* Get an unused proprty container, or allocate a new one as needed. */ - struct ALcontextProps *props{context->FreeContextProps.load(std::memory_order_acquire)}; + ALcontextProps *props{context->FreeContextProps.load(std::memory_order_acquire)}; if(!props) props = static_cast(al_calloc(16, sizeof(*props))); else { - struct ALcontextProps *next; + ALcontextProps *next; do { next = props->next.load(std::memory_order_relaxed); } while(context->FreeContextProps.compare_exchange_weak(props, next, -- cgit v1.2.3 From 3b7f668b28dbc5ef156bad9aa79f16b32efb2eb3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 24 Dec 2018 20:44:55 -0800 Subject: Avoid an intermediate mixing buffer --- Alc/bformatdec.cpp | 19 ++++++------------- Alc/bformatdec.h | 6 ++---- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index b22784c1..500cd276 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -198,10 +198,11 @@ void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, } } -void BFormatDec::process(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei SamplesToDo) +void BFormatDec::process(ALfloat (*OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*InSamples)[BUFFERSIZE], const ALsizei SamplesToDo) { ASSUME(OutChannels > 0); ASSUME(SamplesToDo > 0); + ASSUME(mNumChannels > 0); if(mDualBand) { @@ -214,18 +215,14 @@ void BFormatDec::process(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALsize if(UNLIKELY(!(mEnabled&(1<(mSamplesHF[0]), mNumChannels, 0, SamplesToDo ); - MixRowSamples(mChannelMix, mMatrix.Dual[chan][LF_BAND], + MixRowSamples(OutBuffer[chan], mMatrix.Dual[chan][LF_BAND], &reinterpret_cast(mSamplesLF[0]), mNumChannels, 0, SamplesToDo ); - - std::transform(std::begin(mChannelMix), std::begin(mChannelMix)+SamplesToDo, - OutBuffer[chan], OutBuffer[chan], std::plus()); } } else @@ -235,17 +232,13 @@ void BFormatDec::process(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALsize if(UNLIKELY(!(mEnabled&(1<()); } } } -void BFormatDec::upSample(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei InChannels, const ALsizei SamplesToDo) +void BFormatDec::upSample(ALfloat (*OutBuffer)[BUFFERSIZE], const ALfloat (*InSamples)[BUFFERSIZE], const ALsizei InChannels, const ALsizei SamplesToDo) { ASSUME(InChannels > 0); ASSUME(SamplesToDo > 0); diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index ba6ceaa2..7b5d1cd2 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -29,8 +29,6 @@ private: std::array *mSamplesHF; std::array *mSamplesLF; - alignas(16) ALfloat mChannelMix[BUFFERSIZE]; - struct { BandSplitter XOver; ALfloat Gains[sNumBands]; @@ -43,10 +41,10 @@ public: void reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]); /* Decodes the ambisonic input to the given output channels. */ - void process(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei SamplesToDo); + void process(ALfloat (*OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*InSamples)[BUFFERSIZE], const ALsizei SamplesToDo); /* Up-samples a first-order input to the decoder's configuration. */ - void upSample(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei InChannels, const ALsizei SamplesToDo); + void upSample(ALfloat (*OutBuffer)[BUFFERSIZE], const ALfloat (*InSamples)[BUFFERSIZE], const ALsizei InChannels, const ALsizei SamplesToDo); DEF_NEWDEL(BFormatDec) }; -- cgit v1.2.3 From 63df7cd537bd43fb2548a112b051a1790ff1140e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 25 Dec 2018 09:32:38 -0800 Subject: Construct AsyncEvent objects directly in the ringbuffer --- Alc/alc.cpp | 19 +++++++++++++++++++ Alc/alu.cpp | 44 ++++++++++++++++++++++++++++---------------- Alc/mixvoice.cpp | 12 ++++++++---- OpenAL32/alSource.cpp | 14 ++++++++------ OpenAL32/event.cpp | 35 ++++++++++++++++++++++++++++++----- 5 files changed, 93 insertions(+), 31 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index b6065e97..d13cfc54 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2465,6 +2465,25 @@ ALCcontext_struct::~ALCcontext_struct() } TRACE("Freed " SZFMT " listener property object%s\n", count, (count==1)?"":"s"); + count = 0; + auto evt_vec = ll_ringbuffer_get_read_vector(AsyncEvents); + while(evt_vec.first.len > 0) + { + reinterpret_cast(evt_vec.first.buf)->~AsyncEvent(); + evt_vec.first.buf += sizeof(AsyncEvent); + evt_vec.first.len -= 1; + ++count; + } + while(evt_vec.second.len > 0) + { + reinterpret_cast(evt_vec.second.buf)->~AsyncEvent(); + evt_vec.second.buf += sizeof(AsyncEvent); + evt_vec.second.len -= 1; + ++count; + } + if(count > 0) + TRACE("Destructed " SZFMT " orphaned event%s\n", count, (count==1)?"":"s"); + delete AsyncEvents; AsyncEvents = nullptr; diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 01b4f3c3..abe938f1 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -293,12 +293,14 @@ void SendSourceStoppedEvent(ALCcontext *context, ALuint id) ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)}; if(!(enabledevt&EventType_SourceStateChange)) return; - AsyncEvent evt{EventType_SourceStateChange}; - evt.u.srcstate.id = id; - evt.u.srcstate.state = AL_STOPPED; - - if(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) == 1) - context->EventSem.post(); + auto evt_data = ll_ringbuffer_get_write_vector(context->AsyncEvents).first; + if(evt_data.len < 1) return; + + AsyncEvent *evt{new (evt_data.buf) AsyncEvent{EventType_SourceStateChange}}; + evt->u.srcstate.id = id; + evt->u.srcstate.state = AL_STOPPED; + ll_ringbuffer_write_advance(context->AsyncEvents, 1); + context->EventSem.post(); } @@ -394,6 +396,7 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) } state = props->State; + props->State = nullptr; if(state == slot->Params.mEffectState) { @@ -402,21 +405,23 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) * 0 refs since the current params also hold a reference). */ DecrementRef(&state->mRef); - props->State = nullptr; } else { /* Otherwise, replace it and send off the old one with a release * event. */ - AsyncEvent evt{EventType_ReleaseEffectState}; - evt.u.mEffectState = slot->Params.mEffectState; - + EffectState *oldstate{slot->Params.mEffectState}; slot->Params.mEffectState = state; - props->State = nullptr; - if(LIKELY(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) != 0)) + auto evt_data = ll_ringbuffer_get_write_vector(context->AsyncEvents).first; + if(LIKELY(evt_data.len > 0)) + { + AsyncEvent *evt{new (evt_data.buf) AsyncEvent{EventType_ReleaseEffectState}}; + evt->u.mEffectState = oldstate; + ll_ringbuffer_write_advance(context->AsyncEvents, 1); context->EventSem.post(); + } else { /* If writing the event failed, the queue was probably full. @@ -424,7 +429,7 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) * eventually be cleaned up sometime later (not ideal, but * better than blocking or leaking). */ - props->State = evt.u.mEffectState; + props->State = oldstate; } } @@ -1828,9 +1833,16 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) while(ctx) { const ALbitfieldSOFT enabledevt{ctx->EnabledEvts.load(std::memory_order_acquire)}; - if((enabledevt&EventType_Disconnected) && - ll_ringbuffer_write(ctx->AsyncEvents, &evt, 1) == 1) - ctx->EventSem.post(); + if((enabledevt&EventType_Disconnected)) + { + auto evt_data = ll_ringbuffer_get_write_vector(ctx->AsyncEvents).first; + if(evt_data.len > 0) + { + new (evt_data.buf) AsyncEvent{evt}; + ll_ringbuffer_write_advance(ctx->AsyncEvents, 1); + ctx->EventSem.post(); + } + } std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire), [ctx](ALvoice *voice) -> void diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 680f4a31..f68c0f0a 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -721,11 +721,15 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize ALbitfieldSOFT enabledevt{Context->EnabledEvts.load(std::memory_order_acquire)}; if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) { - AsyncEvent evt{EventType_BufferCompleted}; - evt.u.bufcomp.id = SourceID; - evt.u.bufcomp.count = buffers_done; - if(ll_ringbuffer_write(Context->AsyncEvents, &evt, 1) == 1) + auto evt_data = ll_ringbuffer_get_write_vector(Context->AsyncEvents).first; + if(evt_data.len > 0) + { + AsyncEvent *evt{new (evt_data.buf) AsyncEvent{EventType_BufferCompleted}}; + evt->u.bufcomp.id = SourceID; + evt->u.bufcomp.count = buffers_done; + ll_ringbuffer_write_advance(Context->AsyncEvents, 1); Context->EventSem.post(); + } } return isplaying; diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index e88df598..b70fc872 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -687,16 +687,18 @@ void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)}; if(!(enabledevt&EventType_SourceStateChange)) return; - AsyncEvent evt{EventType_SourceStateChange}; - evt.u.srcstate.id = id; - evt.u.srcstate.state = state; - /* The mixer may have queued a state change that's not yet been processed, * and we don't want state change messages to occur out of order, so send * it through the async queue to ensure proper ordering. */ - if(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) == 1) - context->EventSem.post(); + auto evt_data = ll_ringbuffer_get_write_vector(context->AsyncEvents).first; + if(evt_data.len < 1) return; + + AsyncEvent *evt{new (evt_data.buf) AsyncEvent{EventType_SourceStateChange}}; + evt->u.srcstate.id = id; + evt->u.srcstate.state = state; + ll_ringbuffer_write_advance(context->AsyncEvents, 1); + context->EventSem.post(); } diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index 6a3dc4bc..6399603b 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -18,10 +18,10 @@ static int EventThread(ALCcontext *context) { bool quitnow{false}; - AsyncEvent evt{}; while(LIKELY(!quitnow)) { - if(ll_ringbuffer_read(context->AsyncEvents, &evt, 1) == 0) + auto evt_data = ll_ringbuffer_get_read_vector(context->AsyncEvents).first; + if(evt_data.len == 0) { context->EventSem.wait(); continue; @@ -29,6 +29,22 @@ static int EventThread(ALCcontext *context) std::lock_guard _{context->EventCbLock}; do { + auto &evt = *reinterpret_cast(evt_data.buf); + evt_data.buf += sizeof(AsyncEvent); + evt_data.len -= 1; + /* This automatically destructs the event object and advances the + * ringbuffer's read offset at the end of scope. + */ + const struct EventAutoDestructor { + AsyncEvent &evt; + ll_ringbuffer *ring; + ~EventAutoDestructor() + { + evt.~AsyncEvent(); + ll_ringbuffer_read_advance(ring, 1); + } + } _{evt, context->AsyncEvents}; + quitnow = evt.EnumType == EventType_KillThread; if(UNLIKELY(quitnow)) break; @@ -73,7 +89,7 @@ static int EventThread(ALCcontext *context) static_cast(strlen(evt.u.user.msg)), evt.u.user.msg, context->EventParam ); - } while(ll_ringbuffer_read(context->AsyncEvents, &evt, 1) != 0); + } while(evt_data.len != 0); } return 0; } @@ -94,8 +110,17 @@ void StartEventThrd(ALCcontext *ctx) void StopEventThrd(ALCcontext *ctx) { static constexpr AsyncEvent kill_evt{EventType_KillThread}; - while(ll_ringbuffer_write(ctx->AsyncEvents, &kill_evt, 1) == 0) - std::this_thread::yield(); + ll_ringbuffer_data evt_data = ll_ringbuffer_get_write_vector(ctx->AsyncEvents).first; + if(evt_data.len == 0) + { + do { + std::this_thread::yield(); + evt_data = ll_ringbuffer_get_write_vector(ctx->AsyncEvents).first; + } while(evt_data.len == 0); + } + new (evt_data.buf) AsyncEvent{kill_evt}; + ll_ringbuffer_write_advance(ctx->AsyncEvents, 1); + ctx->EventSem.post(); if(ctx->EventThread.joinable()) ctx->EventThread.join(); -- cgit v1.2.3 From 9e19acd9e1bf4627d99a0ef87757da4c227ef2db Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 25 Dec 2018 10:06:17 -0800 Subject: Avoid making static local copies of constexpr values --- Alc/alu.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index abe938f1..cad1a9e6 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -642,14 +642,14 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev Elev, Spread, coeffs); /* NOTE: W needs to be scaled due to FuMa normalization. */ - ComputePanGains(&Device->FOAOut, coeffs, DryGain*AmbiScale::FromFuMa[0], + const ALfloat &scale0 = AmbiScale::FromFuMa[0]; + ComputePanGains(&Device->FOAOut, coeffs, DryGain*scale0, voice->Direct.Params[0].Gains.Target); for(ALsizei i{0};i < NumSends;i++) { if(const ALeffectslot *Slot{SendSlots[i]}) ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, - WetGain[i]*AmbiScale::FromFuMa[0], voice->Send[i].Params[0].Gains.Target - ); + WetGain[i]*scale0, voice->Send[i].Params[0].Gains.Target); } } else @@ -692,10 +692,10 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev * matrix is transposed, for the inputs to align on the rows and * outputs on the columns. */ - static const ALfloat scale0{AmbiScale::FromFuMa[0]}; - static const ALfloat scale1{AmbiScale::FromFuMa[1]}; - static const ALfloat scale2{AmbiScale::FromFuMa[2]}; - static const ALfloat scale3{AmbiScale::FromFuMa[3]}; + const ALfloat &scale0 = AmbiScale::FromFuMa[0]; + const ALfloat &scale1 = AmbiScale::FromFuMa[1]; + const ALfloat &scale2 = AmbiScale::FromFuMa[2]; + const ALfloat &scale3 = AmbiScale::FromFuMa[3]; const alu::Matrix matrix{ // ACN0 ACN1 ACN2 ACN3 scale0, 0.0f, 0.0f, 0.0f, // Ambi W -- cgit v1.2.3 From 8336de665306e3d1669b9af675b3cf39f0bcbc4a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 25 Dec 2018 10:28:02 -0800 Subject: Rename a couple filter files for consistency --- Alc/effects/autowah.cpp | 2 +- Alc/effects/chorus.cpp | 2 +- Alc/effects/distortion.cpp | 2 +- Alc/effects/echo.cpp | 2 +- Alc/effects/equalizer.cpp | 2 +- Alc/effects/modulator.cpp | 2 +- Alc/effects/reverb.cpp | 2 +- Alc/filters/biquad.cpp | 124 ++++++++++++++++++++++++++++++++++++++++++++ Alc/filters/biquad.h | 126 +++++++++++++++++++++++++++++++++++++++++++++ Alc/filters/defs.h | 125 -------------------------------------------- Alc/filters/filter.cpp | 124 -------------------------------------------- CMakeLists.txt | 4 +- OpenAL32/Include/alu.h | 2 +- 13 files changed, 260 insertions(+), 259 deletions(-) create mode 100644 Alc/filters/biquad.cpp create mode 100644 Alc/filters/biquad.h delete mode 100644 Alc/filters/defs.h delete mode 100644 Alc/filters/filter.cpp diff --git a/Alc/effects/autowah.cpp b/Alc/effects/autowah.cpp index 8590360a..b116cc0f 100644 --- a/Alc/effects/autowah.cpp +++ b/Alc/effects/autowah.cpp @@ -30,7 +30,7 @@ #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" -#include "filters/defs.h" +#include "filters/biquad.h" #include "vecmat.h" #define MIN_FREQ 20.0f diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp index 9219ece5..1a89a015 100644 --- a/Alc/effects/chorus.cpp +++ b/Alc/effects/chorus.cpp @@ -30,7 +30,7 @@ #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" -#include "filters/defs.h" +#include "filters/biquad.h" #include "vector.h" diff --git a/Alc/effects/distortion.cpp b/Alc/effects/distortion.cpp index d094ee5f..e54ae455 100644 --- a/Alc/effects/distortion.cpp +++ b/Alc/effects/distortion.cpp @@ -30,7 +30,7 @@ #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" -#include "filters/defs.h" +#include "filters/biquad.h" struct ALdistortionState final : public EffectState { diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index f48f1e89..b774052a 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -31,7 +31,7 @@ #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" -#include "filters/defs.h" +#include "filters/biquad.h" #include "vector.h" diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index 443bf118..cb421914 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -31,7 +31,7 @@ #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" -#include "filters/defs.h" +#include "filters/biquad.h" #include "vecmat.h" diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index 2b62d66a..889d6a86 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -31,7 +31,7 @@ #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" -#include "filters/defs.h" +#include "filters/biquad.h" #include "vecmat.h" diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 574f9e7f..d984ceab 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -33,7 +33,7 @@ #include "alAuxEffectSlot.h" #include "alListener.h" #include "alError.h" -#include "filters/defs.h" +#include "filters/biquad.h" #include "vector.h" #include "vecmat.h" diff --git a/Alc/filters/biquad.cpp b/Alc/filters/biquad.cpp new file mode 100644 index 00000000..c6266949 --- /dev/null +++ b/Alc/filters/biquad.cpp @@ -0,0 +1,124 @@ + +#include "config.h" + +#include + +#include "AL/alc.h" +#include "AL/al.h" + +#include "alMain.h" +#include "biquad.h" + + +void BiquadFilter::setParams(BiquadType type, float gain, float f0norm, float rcpQ) +{ + float alpha, sqrtgain_alpha_2; + float w0, sin_w0, cos_w0; + float a[3] = { 1.0f, 0.0f, 0.0f }; + float b[3] = { 1.0f, 0.0f, 0.0f }; + + // Limit gain to -100dB + assert(gain > 0.00001f); + + w0 = F_TAU * f0norm; + sin_w0 = std::sin(w0); + cos_w0 = std::cos(w0); + alpha = sin_w0/2.0f * rcpQ; + + /* Calculate filter coefficients depending on filter type */ + switch(type) + { + case BiquadType::HighShelf: + sqrtgain_alpha_2 = 2.0f * std::sqrt(gain) * alpha; + b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); + b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 ); + b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); + a[0] = (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; + a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 ); + a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; + break; + case BiquadType::LowShelf: + sqrtgain_alpha_2 = 2.0f * std::sqrt(gain) * alpha; + b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); + b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 ); + b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); + a[0] = (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; + a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 ); + a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; + break; + case BiquadType::Peaking: + gain = std::sqrt(gain); + b[0] = 1.0f + alpha * gain; + b[1] = -2.0f * cos_w0; + b[2] = 1.0f - alpha * gain; + a[0] = 1.0f + alpha / gain; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha / gain; + break; + + case BiquadType::LowPass: + b[0] = (1.0f - cos_w0) / 2.0f; + b[1] = 1.0f - cos_w0; + b[2] = (1.0f - cos_w0) / 2.0f; + a[0] = 1.0f + alpha; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha; + break; + case BiquadType::HighPass: + b[0] = (1.0f + cos_w0) / 2.0f; + b[1] = -(1.0f + cos_w0); + b[2] = (1.0f + cos_w0) / 2.0f; + a[0] = 1.0f + alpha; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha; + break; + case BiquadType::BandPass: + b[0] = alpha; + b[1] = 0; + b[2] = -alpha; + a[0] = 1.0f + alpha; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha; + break; + } + + a1 = a[1] / a[0]; + a2 = a[2] / a[0]; + b0 = b[0] / a[0]; + b1 = b[1] / a[0]; + b2 = b[2] / a[0]; +} + + +void BiquadFilter::process(float *RESTRICT dst, const float *RESTRICT src, int numsamples) +{ + ASSUME(numsamples > 0); + + const float b0{this->b0}; + const float b1{this->b1}; + const float b2{this->b2}; + const float a1{this->a1}; + const float a2{this->a2}; + float z1{this->z1}; + float z2{this->z2}; + + /* Processing loop is Transposed Direct Form II. This requires less storage + * compared to Direct Form I (only two delay components, instead of a four- + * sample history; the last two inputs and outputs), and works better for + * floating-point which favors summing similarly-sized values while being + * less bothered by overflow. + * + * See: http://www.earlevel.com/main/2003/02/28/biquads/ + */ + auto proc_sample = [b0,b1,b2,a1,a2,&z1,&z2](float input) noexcept -> float + { + float output = input*b0 + z1; + z1 = input*b1 - output*a1 + z2; + z2 = input*b2 - output*a2; + return output; + }; + std::transform(src, src+numsamples, dst, proc_sample); + + this->z1 = z1; + this->z2 = z2; +} diff --git a/Alc/filters/biquad.h b/Alc/filters/biquad.h new file mode 100644 index 00000000..98085dbb --- /dev/null +++ b/Alc/filters/biquad.h @@ -0,0 +1,126 @@ +#ifndef FILTERS_BIQUAD_H +#define FILTERS_BIQUAD_H + +#include +#include + +#include "AL/al.h" +#include "math_defs.h" + + +/* Filters implementation is based on the "Cookbook formulae for audio + * EQ biquad filter coefficients" by Robert Bristow-Johnson + * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt + */ +/* Implementation note: For the shelf filters, the specified gain is for the + * reference frequency, which is the centerpoint of the transition band. This + * better matches EFX filter design. To set the gain for the shelf itself, use + * the square root of the desired linear gain (or halve the dB gain). + */ + +enum class BiquadType { + /** EFX-style low-pass filter, specifying a gain and reference frequency. */ + HighShelf, + /** EFX-style high-pass filter, specifying a gain and reference frequency. */ + LowShelf, + /** Peaking filter, specifying a gain and reference frequency. */ + Peaking, + + /** Low-pass cut-off filter, specifying a cut-off frequency. */ + LowPass, + /** High-pass cut-off filter, specifying a cut-off frequency. */ + HighPass, + /** Band-pass filter, specifying a center frequency. */ + BandPass, +}; + +class BiquadFilter { + /* Last two delayed components for direct form II. */ + float z1{0.0f}, z2{0.0f}; + /* Transfer function coefficients "b" (numerator) */ + float b0{1.0f}, b1{0.0f}, b2{0.0f}; + /* Transfer function coefficients "a" (denominator; a0 is pre-applied). */ + float a1{0.0f}, a2{0.0f}; + +public: + void clear() noexcept { z1 = z2 = 0.0f; } + + /** + * Sets the filter state for the specified filter type and its parameters. + * + * \param type The type of filter to apply. + * \param gain The gain for the reference frequency response. Only used by + * the Shelf and Peaking filter types. + * \param f0norm The reference frequency normal (ref_freq / sample_rate). + * This is the center point for the Shelf, Peaking, and + * BandPass filter types, or the cutoff frequency for the + * LowPass and HighPass filter types. + * \param rcpQ The reciprocal of the Q coefficient for the filter's + * transition band. Can be generated from calc_rcpQ_from_slope + * or calc_rcpQ_from_bandwidth as needed. + */ + void setParams(BiquadType type, float gain, float f0norm, float rcpQ); + + void copyParamsFrom(const BiquadFilter &other) + { + b0 = other.b0; + b1 = other.b1; + b2 = other.b2; + a1 = other.a1; + a2 = other.a2; + } + + + void process(float *RESTRICT dst, const float *RESTRICT src, int numsamples); + + void passthru(int numsamples) noexcept + { + if(LIKELY(numsamples >= 2)) + { + z1 = 0.0f; + z2 = 0.0f; + } + else if(numsamples == 1) + { + z1 = z2; + z2 = 0.0f; + } + } + + /* Rather hacky. It's just here to support "manual" processing. */ + std::pair getComponents() const noexcept + { return {z1, z2}; } + void setComponents(float z1_, float z2_) noexcept + { z1 = z1_; z2 = z2_; } + float processOne(const float in, float &z1_, float &z2_) const noexcept + { + float out{in*b0 + z1_}; + z1_ = in*b1 - out*a1 + z2_; + z2_ = in*b2 - out*a2; + return out; + } +}; + +/** + * Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the + * reference gain and shelf slope parameter. + * \param gain 0 < gain + * \param slope 0 < slope <= 1 + */ +inline float calc_rcpQ_from_slope(float gain, float slope) +{ + return std::sqrt((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f); +} +/** + * Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the normalized + * reference frequency and bandwidth. + * \param f0norm 0 < f0norm < 0.5. + * \param bandwidth 0 < bandwidth + */ +inline ALfloat calc_rcpQ_from_bandwidth(float f0norm, float bandwidth) +{ + float w0 = F_TAU * f0norm; + return 2.0f*std::sinh(std::log(2.0f)/2.0f*bandwidth*w0/std::sin(w0)); +} + +#endif /* FILTERS_BIQUAD_H */ diff --git a/Alc/filters/defs.h b/Alc/filters/defs.h deleted file mode 100644 index b7628153..00000000 --- a/Alc/filters/defs.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef ALC_FILTER_H -#define ALC_FILTER_H - -#include - -#include "AL/al.h" -#include "math_defs.h" - - -/* Filters implementation is based on the "Cookbook formulae for audio - * EQ biquad filter coefficients" by Robert Bristow-Johnson - * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt - */ -/* Implementation note: For the shelf filters, the specified gain is for the - * reference frequency, which is the centerpoint of the transition band. This - * better matches EFX filter design. To set the gain for the shelf itself, use - * the square root of the desired linear gain (or halve the dB gain). - */ - -enum class BiquadType { - /** EFX-style low-pass filter, specifying a gain and reference frequency. */ - HighShelf, - /** EFX-style high-pass filter, specifying a gain and reference frequency. */ - LowShelf, - /** Peaking filter, specifying a gain and reference frequency. */ - Peaking, - - /** Low-pass cut-off filter, specifying a cut-off frequency. */ - LowPass, - /** High-pass cut-off filter, specifying a cut-off frequency. */ - HighPass, - /** Band-pass filter, specifying a center frequency. */ - BandPass, -}; - -class BiquadFilter { - /* Last two delayed components for direct form II. */ - float z1{0.0f}, z2{0.0f}; - /* Transfer function coefficients "b" (numerator) */ - float b0{1.0f}, b1{0.0f}, b2{0.0f}; - /* Transfer function coefficients "a" (denominator; a0 is pre-applied). */ - float a1{0.0f}, a2{0.0f}; - -public: - void clear() noexcept { z1 = z2 = 0.0f; } - - /** - * Sets the filter state for the specified filter type and its parameters. - * - * \param type The type of filter to apply. - * \param gain The gain for the reference frequency response. Only used by - * the Shelf and Peaking filter types. - * \param f0norm The reference frequency normal (ref_freq / sample_rate). - * This is the center point for the Shelf, Peaking, and - * BandPass filter types, or the cutoff frequency for the - * LowPass and HighPass filter types. - * \param rcpQ The reciprocal of the Q coefficient for the filter's - * transition band. Can be generated from calc_rcpQ_from_slope - * or calc_rcpQ_from_bandwidth as needed. - */ - void setParams(BiquadType type, float gain, float f0norm, float rcpQ); - - void copyParamsFrom(const BiquadFilter &other) - { - b0 = other.b0; - b1 = other.b1; - b2 = other.b2; - a1 = other.a1; - a2 = other.a2; - } - - - void process(float *RESTRICT dst, const float *RESTRICT src, int numsamples); - - void passthru(int numsamples) noexcept - { - if(LIKELY(numsamples >= 2)) - { - z1 = 0.0f; - z2 = 0.0f; - } - else if(numsamples == 1) - { - z1 = z2; - z2 = 0.0f; - } - } - - /* Rather hacky. It's just here to support "manual" processing. */ - std::pair getComponents() const noexcept - { return {z1, z2}; } - void setComponents(float z1_, float z2_) noexcept - { z1 = z1_; z2 = z2_; } - float processOne(const float in, float &z1_, float &z2_) const noexcept - { - float out{in*b0 + z1_}; - z1_ = in*b1 - out*a1 + z2_; - z2_ = in*b2 - out*a2; - return out; - } -}; - -/** - * Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the - * reference gain and shelf slope parameter. - * \param gain 0 < gain - * \param slope 0 < slope <= 1 - */ -inline float calc_rcpQ_from_slope(float gain, float slope) -{ - return std::sqrt((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f); -} -/** - * Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the normalized - * reference frequency and bandwidth. - * \param f0norm 0 < f0norm < 0.5. - * \param bandwidth 0 < bandwidth - */ -inline ALfloat calc_rcpQ_from_bandwidth(float f0norm, float bandwidth) -{ - float w0 = F_TAU * f0norm; - return 2.0f*std::sinh(std::log(2.0f)/2.0f*bandwidth*w0/std::sin(w0)); -} - -#endif /* ALC_FILTER_H */ diff --git a/Alc/filters/filter.cpp b/Alc/filters/filter.cpp deleted file mode 100644 index c9e7c9fe..00000000 --- a/Alc/filters/filter.cpp +++ /dev/null @@ -1,124 +0,0 @@ - -#include "config.h" - -#include - -#include "AL/alc.h" -#include "AL/al.h" - -#include "alMain.h" -#include "defs.h" - - -void BiquadFilter::setParams(BiquadType type, float gain, float f0norm, float rcpQ) -{ - float alpha, sqrtgain_alpha_2; - float w0, sin_w0, cos_w0; - float a[3] = { 1.0f, 0.0f, 0.0f }; - float b[3] = { 1.0f, 0.0f, 0.0f }; - - // Limit gain to -100dB - assert(gain > 0.00001f); - - w0 = F_TAU * f0norm; - sin_w0 = std::sin(w0); - cos_w0 = std::cos(w0); - alpha = sin_w0/2.0f * rcpQ; - - /* Calculate filter coefficients depending on filter type */ - switch(type) - { - case BiquadType::HighShelf: - sqrtgain_alpha_2 = 2.0f * std::sqrt(gain) * alpha; - b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); - b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 ); - b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); - a[0] = (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; - a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 ); - a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; - break; - case BiquadType::LowShelf: - sqrtgain_alpha_2 = 2.0f * std::sqrt(gain) * alpha; - b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); - b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 ); - b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); - a[0] = (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; - a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 ); - a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; - break; - case BiquadType::Peaking: - gain = std::sqrt(gain); - b[0] = 1.0f + alpha * gain; - b[1] = -2.0f * cos_w0; - b[2] = 1.0f - alpha * gain; - a[0] = 1.0f + alpha / gain; - a[1] = -2.0f * cos_w0; - a[2] = 1.0f - alpha / gain; - break; - - case BiquadType::LowPass: - b[0] = (1.0f - cos_w0) / 2.0f; - b[1] = 1.0f - cos_w0; - b[2] = (1.0f - cos_w0) / 2.0f; - a[0] = 1.0f + alpha; - a[1] = -2.0f * cos_w0; - a[2] = 1.0f - alpha; - break; - case BiquadType::HighPass: - b[0] = (1.0f + cos_w0) / 2.0f; - b[1] = -(1.0f + cos_w0); - b[2] = (1.0f + cos_w0) / 2.0f; - a[0] = 1.0f + alpha; - a[1] = -2.0f * cos_w0; - a[2] = 1.0f - alpha; - break; - case BiquadType::BandPass: - b[0] = alpha; - b[1] = 0; - b[2] = -alpha; - a[0] = 1.0f + alpha; - a[1] = -2.0f * cos_w0; - a[2] = 1.0f - alpha; - break; - } - - a1 = a[1] / a[0]; - a2 = a[2] / a[0]; - b0 = b[0] / a[0]; - b1 = b[1] / a[0]; - b2 = b[2] / a[0]; -} - - -void BiquadFilter::process(float *RESTRICT dst, const float *RESTRICT src, int numsamples) -{ - ASSUME(numsamples > 0); - - const float b0{this->b0}; - const float b1{this->b1}; - const float b2{this->b2}; - const float a1{this->a1}; - const float a2{this->a2}; - float z1{this->z1}; - float z2{this->z2}; - - /* Processing loop is Transposed Direct Form II. This requires less storage - * compared to Direct Form I (only two delay components, instead of a four- - * sample history; the last two inputs and outputs), and works better for - * floating-point which favors summing similarly-sized values while being - * less bothered by overflow. - * - * See: http://www.earlevel.com/main/2003/02/28/biquads/ - */ - auto proc_sample = [b0,b1,b2,a1,a2,&z1,&z2](float input) noexcept -> float - { - float output = input*b0 + z1; - z1 = input*b1 - output*a1 + z2; - z2 = input*b2 - output*a2; - return output; - }; - std::transform(src, src+numsamples, dst, proc_sample); - - this->z1 = z1; - this->z2 = z2; -} diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e1d0081..270d2a4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -752,8 +752,8 @@ SET(ALC_OBJS Alc/effects/null.cpp Alc/effects/pshifter.cpp Alc/effects/reverb.cpp - Alc/filters/defs.h - Alc/filters/filter.cpp + Alc/filters/biquad.h + Alc/filters/biquad.cpp Alc/filters/nfc.cpp Alc/filters/nfc.h Alc/filters/splitter.cpp diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 78733d8d..4620aeb6 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -18,7 +18,7 @@ #include "hrtf.h" #include "math_defs.h" -#include "filters/defs.h" +#include "filters/biquad.h" #include "filters/nfc.h" #include "almalloc.h" -- cgit v1.2.3 From 208ea76922e8d69dc9ad93cbb0cf43634d9782a4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 25 Dec 2018 11:09:41 -0800 Subject: Cleanup some includes --- Alc/alconfig.cpp | 1 + Alc/backends/base.h | 12 +++++++----- Alc/hrtf.h | 10 ++++++++-- OpenAL32/Include/alMain.h | 14 +------------- OpenAL32/Include/alu.h | 1 + 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/Alc/alconfig.cpp b/Alc/alconfig.cpp index 4acbba5e..40131cc1 100644 --- a/Alc/alconfig.cpp +++ b/Alc/alconfig.cpp @@ -45,6 +45,7 @@ #include "alMain.h" #include "alconfig.h" +#include "logging.h" #include "compat.h" diff --git a/Alc/backends/base.h b/Alc/backends/base.h index f7be5cd0..15622967 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -1,12 +1,14 @@ -#ifndef AL_BACKENDS_BASE_H -#define AL_BACKENDS_BASE_H - -#include "alMain.h" +#ifndef ALC_BACKENDS_BASE_H +#define ALC_BACKENDS_BASE_H #include #include #include +#include "alMain.h" +#include "polymorphism.h" + + struct ClockLatency { std::chrono::nanoseconds ClockTime; std::chrono::nanoseconds Latency; @@ -119,4 +121,4 @@ struct BackendFactory { virtual ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) = 0; }; -#endif /* AL_BACKENDS_BASE_H */ +#endif /* ALC_BACKENDS_BASE_H */ diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 15c16723..7954ac11 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -1,11 +1,11 @@ #ifndef ALC_HRTF_H #define ALC_HRTF_H +#include + #include "AL/al.h" #include "AL/alc.h" -#include "alMain.h" -#include "atomic.h" #include "vector.h" #include "almalloc.h" @@ -36,6 +36,12 @@ struct HrtfEntry { const ALubyte (*delays)[2]; }; +struct EnumeratedHrtf { + std::string name; + + HrtfHandle *hrtf; +}; + struct HrtfState { alignas(16) ALfloat History[HRTF_HISTORY_LENGTH]; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 2ffea8aa..bca4c49e 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -27,8 +27,6 @@ #include "AL/alext.h" #include "inprogext.h" -#include "logging.h" -#include "polymorphism.h" #include "atomic.h" #include "vector.h" #include "almalloc.h" @@ -77,10 +75,6 @@ constexpr inline size_t countof(const T(&)[N]) noexcept #endif #endif -#ifndef UINT64_MAX -#define UINT64_MAX U64(18446744073709551615) -#endif - #ifndef UNUSED #if defined(__cplusplus) #define UNUSED(x) @@ -238,6 +232,7 @@ static const union { struct HrtfEntry; struct HrtfHandle; +struct EnumeratedHrtf; struct DirectHrtfState; struct FrontStablizer; struct Compressor; @@ -597,13 +592,6 @@ struct FilterSubList { }; -struct EnumeratedHrtf { - std::string name; - - HrtfHandle *hrtf; -}; - - /* Maximum delay in samples for speaker distance compensation. */ #define MAX_DELAY_LENGTH 1024 diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 4620aeb6..934d6866 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -17,6 +17,7 @@ #include "alBuffer.h" #include "hrtf.h" +#include "logging.h" #include "math_defs.h" #include "filters/biquad.h" #include "filters/nfc.h" -- cgit v1.2.3 From 0314370eb58303bf0176b3222044bf27739ee5f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 25 Dec 2018 11:27:22 -0800 Subject: Cache the process binary path and name --- Alc/alconfig.cpp | 22 +++++++++++----------- Alc/backends/pulseaudio.cpp | 2 +- Alc/compat.h | 2 +- Alc/helpers.cpp | 14 +++++++++----- 4 files changed, 22 insertions(+), 18 deletions(-) diff --git a/Alc/alconfig.cpp b/Alc/alconfig.cpp index 40131cc1..eecaf6fc 100644 --- a/Alc/alconfig.cpp +++ b/Alc/alconfig.cpp @@ -299,12 +299,12 @@ void ReadALConfig(void) noexcept LoadConfigFromFile(f); } - PathNamePair ppath = GetProcBinary(); - if(!ppath.path.empty()) + std::string ppath{GetProcBinary().path}; + if(!ppath.empty()) { - ppath.path += "\\alsoft.ini"; - TRACE("Loading config %s...\n", ppath.path.c_str()); - al::ifstream f{ppath.path.c_str()}; + ppath += "\\alsoft.ini"; + TRACE("Loading config %s...\n", ppath.c_str()); + al::ifstream f{ppath}; if(f.is_open()) LoadConfigFromFile(f); } @@ -422,14 +422,14 @@ void ReadALConfig(void) noexcept LoadConfigFromFile(f); } - PathNamePair ppath = GetProcBinary(); - if(!ppath.path.empty()) + std::string ppath{GetProcBinary().path}; + if(!ppath.empty()) { - if(ppath.path.back() != '/') ppath.path += "/alsoft.conf"; - else ppath.path += "alsoft.conf"; + if(ppath.back() != '/') ppath += "/alsoft.conf"; + else ppath += "alsoft.conf"; - TRACE("Loading config %s...\n", ppath.path.c_str()); - al::ifstream f{ppath.path}; + TRACE("Loading config %s...\n", ppath.c_str()); + al::ifstream f{ppath}; if(f.is_open()) LoadConfigFromFile(f); } diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 8428b9d8..16e64cdf 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -406,7 +406,7 @@ pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent) { const char *name{"OpenAL Soft"}; - PathNamePair binname = GetProcBinary(); + const PathNamePair &binname = GetProcBinary(); if(!binname.fname.empty()) name = binname.fname.c_str(); diff --git a/Alc/compat.h b/Alc/compat.h index 18ba8da9..dc652bca 100644 --- a/Alc/compat.h +++ b/Alc/compat.h @@ -223,7 +223,7 @@ using ifstream = std::ifstream; #include struct PathNamePair { std::string path, fname; }; -PathNamePair GetProcBinary(void); +const PathNamePair &GetProcBinary(void); #ifdef HAVE_DYNLOAD void *LoadLib(const char *name); diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index beee4bff..2db544b8 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -310,9 +310,11 @@ void FPUCtl::leave() noexcept #ifdef _WIN32 -PathNamePair GetProcBinary() +const PathNamePair &GetProcBinary() { - PathNamePair ret; + static PathNamePair ret; + if(!ret.fname.empty() || !ret.path.empty()) + return ret; al::vector fullpath(256); DWORD len; @@ -477,11 +479,13 @@ void SetRTPriority(void) #else -PathNamePair GetProcBinary() +const PathNamePair &GetProcBinary() { - PathNamePair ret; - al::vector pathname; + static PathNamePair ret; + if(!ret.fname.empty() || !ret.path.empty()) + return ret; + al::vector pathname; #ifdef __FreeBSD__ size_t pathlen; int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; -- cgit v1.2.3 From 6a8c791e3c8ef68dcb9db551e593d5fc2ea7d7b0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 25 Dec 2018 16:31:31 -0800 Subject: Rework the pulseaudio backend to avoid an explicit mixer thread --- Alc/backends/pulseaudio.cpp | 181 +++++++++++++++----------------------------- 1 file changed, 59 insertions(+), 122 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 16e64cdf..42fc267f 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -533,8 +533,8 @@ struct PulsePlayback final : public ALCbackend { pa_stream *stream{nullptr}; pa_context *context{nullptr}; - std::atomic mKillNow{ALC_TRUE}; - std::thread mThread; + ALuint mBufferSize{0u}; + ALuint mFrameSize{0u}; }; void PulsePlayback_deviceCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); @@ -551,7 +551,6 @@ pa_stream *PulsePlayback_connectStream(const char *device_name, pa_threaded_main pa_context *context, pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, pa_channel_map *chanmap); -int PulsePlayback_mixerProc(PulsePlayback *self); void PulsePlayback_Construct(PulsePlayback *self, ALCdevice *device); void PulsePlayback_Destruct(PulsePlayback *self); @@ -679,13 +678,17 @@ void PulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata) { auto self = reinterpret_cast(pdata); - self->attr = *pa_stream_get_buffer_attr(stream); - TRACE("minreq=%d, tlength=%d, prebuf=%d\n", self->attr.minreq, self->attr.tlength, self->attr.prebuf); /* FIXME: Update the device's UpdateSize (and/or NumUpdates) using the new * buffer attributes? Changing UpdateSize will change the ALC_REFRESH * property, which probably shouldn't change between device resets. But * leaving it alone means ALC_REFRESH will be off. */ + self->attr = *(pa_stream_get_buffer_attr(stream)); + TRACE("minreq=%d, tlength=%d, prebuf=%d\n", self->attr.minreq, self->attr.tlength, + self->attr.prebuf); + + const ALuint num_periods{(self->attr.tlength + self->attr.minreq/2u) / self->attr.minreq}; + self->mBufferSize = maxu(num_periods, 2u) * self->attr.minreq; } void PulsePlayback_contextStateCallback(pa_context *context, void *pdata) @@ -710,10 +713,22 @@ void PulsePlayback_streamStateCallback(pa_stream *stream, void *pdata) pa_threaded_mainloop_signal(self->loop, 0); } -void PulsePlayback_streamWriteCallback(pa_stream* UNUSED(p), size_t UNUSED(nbytes), void *pdata) +void PulsePlayback_streamWriteCallback(pa_stream *stream, size_t nbytes, void *pdata) { - auto self = reinterpret_cast(pdata); - pa_threaded_mainloop_signal(self->loop, 0); + auto self = static_cast(pdata); + ALCdevice *device{self->mDevice}; + + /* Round down to the nearest period/minreq multiple if doing more than 1. */ + const size_t frame_size{self->mFrameSize}; + if(nbytes > self->attr.minreq) + nbytes -= nbytes%self->attr.minreq; + + void *buf{pa_xmalloc(nbytes)}; + aluMixData(device, buf, nbytes/frame_size); + + int ret{pa_stream_write(stream, buf, nbytes, pa_xfree, 0, PA_SEEK_RELATIVE)}; + if(UNLIKELY(ret != PA_OK)) + ERR("Failed to write to stream: %d, %s\n", ret, pa_strerror(ret)); } void PulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) @@ -824,8 +839,7 @@ pa_stream *PulsePlayback_connectStream(const char *device_name, } pa_stream *stream{pa_stream_new_with_proplist(context, - "Playback Stream", spec, chanmap, prop_filter - )}; + "Playback Stream", spec, chanmap, prop_filter)}; if(!stream) { ERR("pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context))); @@ -859,65 +873,6 @@ pa_stream *PulsePlayback_connectStream(const char *device_name, } -int PulsePlayback_mixerProc(PulsePlayback *self) -{ - ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; - - SetRTPriority(); - althrd_setname(MIXER_THREAD_NAME); - - unique_palock palock{self->loop}; - size_t frame_size{pa_frame_size(&self->spec)}; - - while(!self->mKillNow.load(std::memory_order_acquire) && - device->Connected.load(std::memory_order_acquire)) - { - ssize_t len{static_cast(pa_stream_writable_size(self->stream))}; - if(UNLIKELY(len < 0)) - { - ERR("Failed to get writable size: %ld", (long)len); - aluHandleDisconnect(device, "Failed to get writable size: %ld", (long)len); - break; - } - - /* Make sure we're going to write at least 2 'periods' (minreqs), in - * case the server increased it since starting playback. Also round up - * the number of writable periods if it's not an integer count. - */ - ALint buffer_size{static_cast(self->attr.minreq) * maxi( - (self->attr.tlength + self->attr.minreq/2) / self->attr.minreq, 2 - )}; - - /* NOTE: This assumes pa_stream_writable_size returns between 0 and - * tlength, else there will be more latency than intended. - */ - len = buffer_size - maxi((ssize_t)self->attr.tlength - len, 0); - if(len < self->attr.minreq) - { - if(pa_stream_is_corked(self->stream)) - { - pa_operation *op{pa_stream_cork(self->stream, 0, nullptr, nullptr)}; - if(op) pa_operation_unref(op); - } - pa_threaded_mainloop_wait(self->loop); - continue; - } - - len -= len%self->attr.minreq; - len -= len%frame_size; - - void *buf{pa_xmalloc(len)}; - aluMixData(device, buf, len/frame_size); - - int ret{pa_stream_write(self->stream, buf, len, pa_xfree, 0, PA_SEEK_RELATIVE)}; - if(UNLIKELY(ret != PA_OK)) - ERR("Failed to write to stream: %d, %s\n", ret, pa_strerror(ret)); - } - - return 0; -} - - ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) { const char *pulse_name{nullptr}; @@ -965,6 +920,7 @@ ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) return ALC_INVALID_VALUE; } pa_stream_set_moved_callback(self->stream, PulsePlayback_streamMovedCallback, self); + self->mFrameSize = pa_frame_size(pa_stream_get_sample_spec(self->stream)); self->device_name = pa_stream_get_device_name(self->stream); if(!dev_name) @@ -999,15 +955,16 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) } pa_operation *op{pa_context_get_sink_info_by_name(self->context, - self->device_name.c_str(), PulsePlayback_sinkInfoCallback, self - )}; + self->device_name.c_str(), PulsePlayback_sinkInfoCallback, self)}; wait_for_operation(op, self->loop); ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; - pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_ADJUST_LATENCY | - PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE}; + pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | + PA_STREAM_AUTO_TIMING_UPDATE}; if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 0)) flags |= PA_STREAM_DONT_MOVE; + if(GetConfigValueBool(device->DeviceName.c_str(), "pulse", "adjust-latency", 0)) + flags |= PA_STREAM_ADJUST_LATENCY; if(GetConfigValueBool(device->DeviceName.c_str(), "pulse", "fix-rate", 0) || !(device->Flags&DEVICE_FREQUENCY_REQUEST)) flags |= PA_STREAM_FIX_RATE; @@ -1081,37 +1038,38 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) } SetDefaultWFXChannelOrder(device); - self->attr.fragsize = -1; - self->attr.prebuf = 0; - self->attr.minreq = device->UpdateSize * pa_frame_size(&self->spec); - self->attr.tlength = self->attr.minreq * maxu(device->NumUpdates, 2); + size_t period_size{device->UpdateSize * pa_frame_size(&self->spec)}; self->attr.maxlength = -1; + self->attr.tlength = period_size * maxu(device->NumUpdates, 2); + self->attr.prebuf = 0; + self->attr.minreq = period_size; + self->attr.fragsize = -1; self->stream = PulsePlayback_connectStream(self->device_name.c_str(), - self->loop, self->context, flags, &self->attr, &self->spec, &chanmap - ); - if(!self->stream) - return ALC_FALSE; + self->loop, self->context, flags, &self->attr, &self->spec, &chanmap); + if(!self->stream) return ALC_FALSE; + pa_stream_set_state_callback(self->stream, PulsePlayback_streamStateCallback, self); pa_stream_set_moved_callback(self->stream, PulsePlayback_streamMovedCallback, self); - pa_stream_set_write_callback(self->stream, PulsePlayback_streamWriteCallback, self); self->spec = *(pa_stream_get_sample_spec(self->stream)); + self->mFrameSize = pa_frame_size(&self->spec); + if(device->Frequency != self->spec.rate) { /* Server updated our playback rate, so modify the buffer attribs * accordingly. */ - device->NumUpdates = (ALuint)clampd( - (ALdouble)device->NumUpdates/device->Frequency*self->spec.rate + 0.5, 2.0, 16.0 - ); + device->NumUpdates = static_cast(clampd( + (ALdouble)self->spec.rate/device->Frequency*device->NumUpdates + 0.5, 2.0, 16.0)); - self->attr.minreq = device->UpdateSize * pa_frame_size(&self->spec); - self->attr.tlength = self->attr.minreq * device->NumUpdates; + period_size = device->UpdateSize * self->mFrameSize; self->attr.maxlength = -1; - self->attr.prebuf = 0; + self->attr.tlength = period_size * maxu(device->NumUpdates, 2); + self->attr.prebuf = 0; + self->attr.minreq = period_size; - op = pa_stream_set_buffer_attr(self->stream, &self->attr, - stream_success_callback, self->loop); + op = pa_stream_set_buffer_attr(self->stream, &self->attr, stream_success_callback, + self->loop); wait_for_operation(op, self->loop); device->Frequency = self->spec.rate; @@ -1120,10 +1078,8 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) pa_stream_set_buffer_attr_callback(self->stream, PulsePlayback_bufferAttrCallback, self); PulsePlayback_bufferAttrCallback(self->stream, self); - device->NumUpdates = (ALuint)clampu64( - (self->attr.tlength + self->attr.minreq/2) / self->attr.minreq, 2, 16 - ); - device->UpdateSize = self->attr.minreq / pa_frame_size(&self->spec); + device->NumUpdates = clampu((self->attr.tlength + self->attr.minreq/2u) / self->attr.minreq, 2u, 16u); + device->UpdateSize = self->attr.minreq / self->mFrameSize; /* HACK: prebuf should be 0 as that's what we set it to. However on some * systems it comes back as non-0, so we have to make sure the device will @@ -1133,7 +1089,7 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) */ if(self->attr.prebuf != 0) { - ALuint len{self->attr.prebuf / (ALuint)pa_frame_size(&self->spec)}; + ALuint len{self->attr.prebuf / self->mFrameSize}; if(len <= device->UpdateSize*device->NumUpdates) ERR("Non-0 prebuf, %u samples (%u bytes), device has %u samples\n", len, self->attr.prebuf, device->UpdateSize*device->NumUpdates); @@ -1150,39 +1106,20 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) ALCboolean PulsePlayback_start(PulsePlayback *self) { - try { - self->mKillNow.store(AL_FALSE, std::memory_order_release); - self->mThread = std::thread(PulsePlayback_mixerProc, self); - return ALC_TRUE; - } - catch(std::exception& e) { - ERR("Failed to start thread: %s\n", e.what()); - } - catch(...) { - ERR("Failed to start thread\n"); - } - return ALC_FALSE; + unique_palock palock{self->loop}; + + pa_stream_set_write_callback(self->stream, PulsePlayback_streamWriteCallback, self); + pa_operation *op{pa_stream_cork(self->stream, 0, stream_success_callback, self->loop)}; + wait_for_operation(op, self->loop); + + return ALC_TRUE; } void PulsePlayback_stop(PulsePlayback *self) { - self->mKillNow.store(AL_TRUE, std::memory_order_release); - if(!self->stream || !self->mThread.joinable()) - return; - - /* Signal the main loop in case PulseAudio isn't sending us audio requests - * (e.g. if the device is suspended). We need to lock the mainloop in case - * the mixer is between checking the mKillNow flag but before waiting for - * the signal. - */ unique_palock palock{self->loop}; - palock.unlock(); - - pa_threaded_mainloop_signal(self->loop, 0); - self->mThread.join(); - - palock.lock(); + pa_stream_set_write_callback(self->stream, nullptr, nullptr); pa_operation *op{pa_stream_cork(self->stream, 1, stream_success_callback, self->loop)}; wait_for_operation(op, self->loop); } -- cgit v1.2.3 From 497226f11e811923936e6978a8f68055f5fe7467 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 25 Dec 2018 17:04:54 -0800 Subject: Add an adjust-latency config option for PulseAudio --- alsoftrc.sample | 8 ++++++++ utils/alsoft-config/mainwindow.cpp | 5 +++++ utils/alsoft-config/mainwindow.ui | 35 +++++++++++++++++++++++++++++------ 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/alsoftrc.sample b/alsoftrc.sample index 8061ed1c..f18899a0 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -345,6 +345,14 @@ surround71 = # PulseAudio server. #fix-rate = false +## adjust-latency: +# Attempts to adjust the overall latency of device playback. Note that this +# may have adverse effects on the resulting internal buffer sizes and mixing +# updates, leading to performance problems and drop-outs. However, if the +# PulseAudio server is creating a lot of latency, enabling this may help make +# it more manageable. +#adjust-latency = false + ## ## ALSA backend stuff ## diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 56ac4f3f..2b873955 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -387,6 +387,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->pulseAutospawnCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->pulseAllowMovesCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->pulseFixRateCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->pulseAdjLatencyCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->jackAutospawnCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->jackBufferSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(updateJackBufferSizeEdit(int))); @@ -855,6 +856,7 @@ void MainWindow::loadConfig(const QString &fname) ui->pulseAutospawnCheckBox->setChecked(settings.value("pulse/spawn-server", true).toBool()); ui->pulseAllowMovesCheckBox->setChecked(settings.value("pulse/allow-moves", false).toBool()); ui->pulseFixRateCheckBox->setChecked(settings.value("pulse/fix-rate", false).toBool()); + ui->pulseAdjLatencyCheckBox->setChecked(settings.value("pulse/adjust-latency", false).toBool()); ui->jackAutospawnCheckBox->setChecked(settings.value("jack/spawn-server", false).toBool()); ui->jackBufferSizeLine->setText(settings.value("jack/buffer-size", QString()).toString()); @@ -1081,6 +1083,9 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("pulse/fix-rate", ui->pulseFixRateCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) ); + settings.setValue("pulse/adjust-latency", + ui->pulseAdjLatencyCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) + ); settings.setValue("jack/spawn-server", ui->jackAutospawnCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 9c89cbc7..81f50b4c 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -53,7 +53,7 @@ - 5 + 0 @@ -131,8 +131,8 @@ to stereo output. 380 20 - 80 - 20 + 93 + 29 @@ -1185,6 +1185,9 @@ application or system to determine if it should be used. 361 + + 0 + @@ -1319,6 +1322,26 @@ rate to match the PulseAudio device. Fix Sample Rate + + + + 20 + 100 + 111 + 21 + + + + Attempts to adjust the overall latency of device +playback. Note that this may have adverse effects +on the resulting internal buffer sizes and mixing +updates, leading to performance problems and +drop-outs. + + + Adjust Latency + + @@ -2178,8 +2201,8 @@ added by the ALC_EXT_DEDICATED extension. 160 20 - 108 - 20 + 125 + 29 @@ -2348,7 +2371,7 @@ added by the ALC_EXT_DEDICATED extension. 0 0 564 - 21 + 27 -- cgit v1.2.3 From a7c58decfbf57fc5e502a1cbf8f40dd78c7465e5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 25 Dec 2018 18:49:12 -0800 Subject: Add a couple more ASSUMEs for number of channels and sends --- Alc/alu.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index cad1a9e6..96d73d1a 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -578,6 +578,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev DirectChannels = false; break; } + ASSUME(num_channels > 0); std::for_each(std::begin(voice->Direct.Params), std::begin(voice->Direct.Params)+num_channels, [](DirectParams ¶ms) -> void @@ -587,6 +588,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev } ); const ALsizei NumSends{Device->NumAuxSends}; + ASSUME(NumSends >= 0); std::for_each(voice->Send+0, voice->Send+NumSends, [num_channels](ALvoice::SendData &send) -> void { -- cgit v1.2.3 From b2665a503f024ae78f004443bd853198322daa79 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 25 Dec 2018 19:54:14 -0800 Subject: Do some pre-mixing fading checks once before preparing to mix --- Alc/mixvoice.cpp | 161 +++++++++++++++++++++++++++---------------------- OpenAL32/Include/alu.h | 2 +- 2 files changed, 89 insertions(+), 74 deletions(-) diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index f68c0f0a..5b18d547 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -288,7 +288,7 @@ const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, #define RESAMPLED_BUF 1 #define FILTERED_BUF 2 #define NFC_DATA_BUF 3 -ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo) +ALboolean MixSource(ALvoice *voice, const ALuint SourceID, ALCcontext *Context, const ALsizei SamplesToDo) { ASSUME(SamplesToDo > 0); @@ -310,15 +310,60 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize ASSUME(increment > 0); ALCdevice *Device{Context->Device}; - ALsizei IrSize{Device->mHrtf ? Device->mHrtf->irSize : 0}; + const ALsizei IrSize{Device->mHrtf ? Device->mHrtf->irSize : 0}; + const ALsizei NumAuxSends{Device->NumAuxSends}; + const int OutLIdx{GetChannelIdxByName(Device->RealOut, FrontLeft)}; + const int OutRIdx{GetChannelIdxByName(Device->RealOut, FrontRight)}; + + ASSUME(IrSize >= 0); + ASSUME(NumAuxSends >= 0); ResamplerFunc Resample{(increment == FRACTIONONE && DataPosFrac == 0) ? Resample_copy_C : voice->Resampler}; ALsizei Counter{(voice->Flags&VOICE_IS_FADING) ? SamplesToDo : 0}; + if(!Counter) + { + /* No fading, just overwrite the old/current params. */ + for(ALsizei chan{0};chan < NumChannels;chan++) + { + DirectParams &parms = voice->Direct.Params[chan]; + if(!(voice->Flags&VOICE_HAS_HRTF)) + std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target), + std::begin(parms.Gains.Current)); + else + parms.Hrtf.Old = parms.Hrtf.Target; + auto set_current = [chan](ALvoice::SendData &send) -> void + { + if(!send.Buffer) + return; + + SendParams &parms = send.Params[chan]; + std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target), + std::begin(parms.Gains.Current)); + }; + std::for_each(voice->Send, voice->Send+NumAuxSends, set_current); + } + } + else if((voice->Flags&VOICE_HAS_HRTF)) + { + for(ALsizei chan{0};chan < NumChannels;chan++) + { + DirectParams &parms = voice->Direct.Params[chan]; + if(!(parms.Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD)) + { + /* The old HRTF params are silent, so overwrite the old + * coefficients with the new, and reset the old gain to 0. The + * future mix will then fade from silence. + */ + parms.Hrtf.Old = parms.Hrtf.Target; + parms.Hrtf.Old.Gain = 0.0f; + } + } + } + ALsizei buffers_done{0}; ALsizei OutPos{0}; - do { /* Figure out how many buffer samples will be needed */ ALsizei DstBufferSize{SamplesToDo - OutPos}; @@ -504,43 +549,36 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize Device->TempBuffer[RESAMPLED_BUF], DstBufferSize )}; { - DirectParams *parms{&voice->Direct.Params[chan]}; - const ALfloat *samples{DoFilters(&parms->LowPass, &parms->HighPass, + DirectParams &parms = voice->Direct.Params[chan]; + const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, Device->TempBuffer[FILTERED_BUF], ResampledData, DstBufferSize, voice->Direct.FilterType )}; if(!(voice->Flags&VOICE_HAS_HRTF)) { - if(!Counter) - std::copy(std::begin(parms->Gains.Target), std::end(parms->Gains.Target), - std::begin(parms->Gains.Current)); - if(!(voice->Flags&VOICE_HAS_NFC)) MixSamples(samples, voice->Direct.Channels, voice->Direct.Buffer, - parms->Gains.Current, parms->Gains.Target, Counter, OutPos, - DstBufferSize - ); + parms.Gains.Current, parms.Gains.Target, Counter, OutPos, + DstBufferSize); else { MixSamples(samples, voice->Direct.ChannelsPerOrder[0], voice->Direct.Buffer, - parms->Gains.Current, parms->Gains.Target, Counter, OutPos, - DstBufferSize - ); + parms.Gains.Current, parms.Gains.Target, Counter, OutPos, + DstBufferSize); ALfloat *nfcsamples{Device->TempBuffer[NFC_DATA_BUF]}; ALsizei chanoffset{voice->Direct.ChannelsPerOrder[0]}; using FilterProc = void (NfcFilter::*)(float*,const float*,int); - auto apply_nfc = [voice,parms,samples,DstBufferSize,Counter,OutPos,&chanoffset,nfcsamples](FilterProc process, ALsizei order) -> void + auto apply_nfc = [voice,&parms,samples,DstBufferSize,Counter,OutPos,&chanoffset,nfcsamples](FilterProc process, ALsizei order) -> void { if(voice->Direct.ChannelsPerOrder[order] < 1) return; - (parms->NFCtrlFilter.*process)(nfcsamples, samples, DstBufferSize); + (parms.NFCtrlFilter.*process)(nfcsamples, samples, DstBufferSize); MixSamples(nfcsamples, voice->Direct.ChannelsPerOrder[order], - voice->Direct.Buffer+chanoffset, parms->Gains.Current+chanoffset, - parms->Gains.Target+chanoffset, Counter, OutPos, DstBufferSize - ); + voice->Direct.Buffer+chanoffset, parms.Gains.Current+chanoffset, + parms.Gains.Target+chanoffset, Counter, OutPos, DstBufferSize); chanoffset += voice->Direct.ChannelsPerOrder[order]; }; apply_nfc(&NfcFilter::process1, 1); @@ -550,28 +588,12 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize } else { - const int lidx{GetChannelIdxByName(Device->RealOut, FrontLeft)}; - const int ridx{GetChannelIdxByName(Device->RealOut, FrontRight)}; - assert(lidx != -1 && ridx != -1); - ALsizei fademix{0}; - if(!Counter) + /* If fading, the old gain is not silence, and this is the + * first mixing pass, fade between the IRs. + */ + if(Counter && (parms.Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD) && OutPos == 0) { - /* No fading, just overwrite the old HRTF params. */ - parms->Hrtf.Old = parms->Hrtf.Target; - } - else if(!(parms->Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD)) - { - /* The old HRTF params are silent, so overwrite the old - * coefficients with the new, and reset the old gain to - * 0. The future mix will then fade from silence. - */ - parms->Hrtf.Old = parms->Hrtf.Target; - parms->Hrtf.Old.Gain = 0.0f; - } - else if(OutPos == 0) - { - /* First mixing pass, fade between the coefficients. */ fademix = mini(DstBufferSize, 128); /* The new coefficients need to fade in completely @@ -580,56 +602,54 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize * and new target gains given how much of the fade time * this mix handles. */ - ALfloat gain{lerp(parms->Hrtf.Old.Gain, parms->Hrtf.Target.Gain, + ALfloat gain{lerp(parms.Hrtf.Old.Gain, parms.Hrtf.Target.Gain, minf(1.0f, (ALfloat)fademix/Counter))}; MixHrtfParams hrtfparams; - hrtfparams.Coeffs = parms->Hrtf.Target.Coeffs; - hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; - hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; + hrtfparams.Coeffs = parms.Hrtf.Target.Coeffs; + hrtfparams.Delay[0] = parms.Hrtf.Target.Delay[0]; + hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1]; hrtfparams.Gain = 0.0f; hrtfparams.GainStep = gain / (ALfloat)fademix; MixHrtfBlendSamples( - voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], - samples, voice->Offset, OutPos, IrSize, &parms->Hrtf.Old, - &hrtfparams, &parms->Hrtf.State, fademix - ); + voice->Direct.Buffer[OutLIdx], voice->Direct.Buffer[OutRIdx], + samples, voice->Offset, OutPos, IrSize, &parms.Hrtf.Old, + &hrtfparams, &parms.Hrtf.State, fademix); /* Update the old parameters with the result. */ - parms->Hrtf.Old = parms->Hrtf.Target; + parms.Hrtf.Old = parms.Hrtf.Target; if(fademix < Counter) - parms->Hrtf.Old.Gain = hrtfparams.Gain; + parms.Hrtf.Old.Gain = hrtfparams.Gain; } if(fademix < DstBufferSize) { const ALsizei todo{DstBufferSize - fademix}; - ALfloat gain{parms->Hrtf.Target.Gain}; + ALfloat gain{parms.Hrtf.Target.Gain}; /* Interpolate the target gain if the gain fading lasts * longer than this mix. */ if(Counter > DstBufferSize) - gain = lerp(parms->Hrtf.Old.Gain, gain, + gain = lerp(parms.Hrtf.Old.Gain, gain, (ALfloat)todo/(Counter-fademix)); MixHrtfParams hrtfparams; - hrtfparams.Coeffs = parms->Hrtf.Target.Coeffs; - hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; - hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; - hrtfparams.Gain = parms->Hrtf.Old.Gain; - hrtfparams.GainStep = (gain - parms->Hrtf.Old.Gain) / (ALfloat)todo; + hrtfparams.Coeffs = parms.Hrtf.Target.Coeffs; + hrtfparams.Delay[0] = parms.Hrtf.Target.Delay[0]; + hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1]; + hrtfparams.Gain = parms.Hrtf.Old.Gain; + hrtfparams.GainStep = (gain - parms.Hrtf.Old.Gain) / (ALfloat)todo; MixHrtfSamples( - voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], + voice->Direct.Buffer[OutLIdx], voice->Direct.Buffer[OutRIdx], samples+fademix, voice->Offset+fademix, OutPos+fademix, IrSize, - &hrtfparams, &parms->Hrtf.State, todo - ); + &hrtfparams, &parms.Hrtf.State, todo); /* Store the interpolated gain or the final target gain * depending if the fade is done. */ if(DstBufferSize < Counter) - parms->Hrtf.Old.Gain = gain; + parms.Hrtf.Old.Gain = gain; else - parms->Hrtf.Old.Gain = parms->Hrtf.Target.Gain; + parms.Hrtf.Old.Gain = parms.Hrtf.Target.Gain; } } } @@ -640,19 +660,14 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize if(!send.Buffer) return; - SendParams *parms = &send.Params[chan]; - const ALfloat *samples{DoFilters(&parms->LowPass, &parms->HighPass, - FilterBuf, ResampledData, DstBufferSize, send.FilterType - )}; + SendParams &parms = send.Params[chan]; + const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, + FilterBuf, ResampledData, DstBufferSize, send.FilterType)}; - if(!Counter) - std::copy(std::begin(parms->Gains.Target), std::end(parms->Gains.Target), - std::begin(parms->Gains.Current)); - MixSamples(samples, send.Channels, send.Buffer, - parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize - ); + MixSamples(samples, send.Channels, send.Buffer, parms.Gains.Current, + parms.Gains.Target, Counter, OutPos, DstBufferSize); }; - std::for_each(voice->Send, voice->Send+Device->NumAuxSends, mix_send); + std::for_each(voice->Send, voice->Send+NumAuxSends, mix_send); } /* Update positions */ DataPosFrac += increment*DstBufferSize; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 934d6866..42c754cc 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -475,7 +475,7 @@ inline void ComputePanGains(const MixParams *dry, const ALfloat*RESTRICT coeffs, void ComputePanGains(const ALeffectslot *slot, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]); -ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo); +ALboolean MixSource(ALvoice *voice, const ALuint SourceID, ALCcontext *Context, const ALsizei SamplesToDo); void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples); /* Caller must lock the device, and the mixer must not be running. */ -- cgit v1.2.3 From 38537a35ccc2ad713a31943bb699d013b004d075 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 25 Dec 2018 22:32:30 -0800 Subject: Avoid using a local for a temporary --- Alc/alu.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 96d73d1a..fec574d8 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -348,11 +348,11 @@ bool CalcListenerParams(ALCcontext *Context) 0.0f, 0.0f, 0.0f, 1.0f }; - alu::Vector P{props->Position[0], props->Position[1], props->Position[2], 1.0f}; - P = Listener.Params.Matrix * P; + const alu::Vector P{Listener.Params.Matrix * + alu::Vector{props->Position[0], props->Position[1], props->Position[2], 1.0f}}; Listener.Params.Matrix.setRow(3, -P[0], -P[1], -P[2], 1.0f); - alu::Vector vel{props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f}; + const alu::Vector vel{props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f}; Listener.Params.Velocity = Listener.Params.Matrix * vel; Listener.Params.Gain = props->Gain * Context->GainBoost; -- cgit v1.2.3 From 5cc545f157877d5ae6911c9778a90e9400e3fbd2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 26 Dec 2018 12:25:34 -0800 Subject: More aggressively try to decrement an effect's refcount in-place --- Alc/alu.cpp | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index fec574d8..07ad540d 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -397,27 +397,31 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) state = props->State; props->State = nullptr; + EffectState *oldstate{slot->Params.mEffectState}; + slot->Params.mEffectState = state; - if(state == slot->Params.mEffectState) + /* Manually decrement the old effect state's refcount if it's greater + * than 1. We need to be a bit clever here to avoid the refcount + * reaching 0 since it can't be deleted in the mixer. + */ + ALuint oldval{oldstate->mRef.load(std::memory_order_acquire)}; + while(oldval > 1 && !oldstate->mRef.compare_exchange_weak(oldval, oldval-1, + std::memory_order_acq_rel, std::memory_order_acquire)) { - /* If the effect state is the same as current, we can decrement its - * count safely to remove it from the update object (it can't reach - * 0 refs since the current params also hold a reference). + /* oldval was updated with the current value on failure, so just + * try again. */ - DecrementRef(&state->mRef); } - else + + if(oldval < 2) { - /* Otherwise, replace it and send off the old one with a release + /* Otherwise, if it would be deleted, send it off with a release * event. */ - EffectState *oldstate{slot->Params.mEffectState}; - slot->Params.mEffectState = state; - - auto evt_data = ll_ringbuffer_get_write_vector(context->AsyncEvents).first; - if(LIKELY(evt_data.len > 0)) + auto evt_vec = ll_ringbuffer_get_write_vector(context->AsyncEvents); + if(LIKELY(evt_vec.first.len > 0)) { - AsyncEvent *evt{new (evt_data.buf) AsyncEvent{EventType_ReleaseEffectState}}; + AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_ReleaseEffectState}}; evt->u.mEffectState = oldstate; ll_ringbuffer_write_advance(context->AsyncEvents, 1); context->EventSem.post(); -- cgit v1.2.3 From 3b9defa4afcbfa96b47cb528d91abb65416d4330 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 26 Dec 2018 12:46:01 -0800 Subject: Improve some post-process handlers --- Alc/alu.cpp | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 07ad540d..861932c9 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -124,49 +124,49 @@ inline HrtfDirectMixerFunc SelectHrtfMixer(void) void ProcessHrtf(ALCdevice *device, ALsizei SamplesToDo) { - if(device->AmbiUp) - device->AmbiUp->process(device->Dry.Buffer, device->Dry.NumChannels, - device->FOAOut.Buffer, SamplesToDo - ); + const ALsizei num_chans{device->Dry.NumChannels}; + ASSUME(num_chans > 0); + + if(AmbiUpsampler *ambiup{device->AmbiUp.get()}) + ambiup->process(device->Dry.Buffer, num_chans, device->FOAOut.Buffer, SamplesToDo); - int lidx{GetChannelIdxByName(device->RealOut, FrontLeft)}; - int ridx{GetChannelIdxByName(device->RealOut, FrontRight)}; - assert(lidx != -1 && ridx != -1); + /* HRTF is stereo output only. */ + const int lidx{(device->RealOut.ChannelName[0]==FrontLeft) ? 0 : 1}; + const int ridx{(device->RealOut.ChannelName[1]==FrontRight) ? 1 : 0}; + ALfloat *LeftOut{device->RealOut.Buffer[lidx]}; + ALfloat *RightOut{device->RealOut.Buffer[ridx]}; + const ALfloat (*Input)[BUFFERSIZE]{device->Dry.Buffer}; DirectHrtfState *state{device->mHrtfState.get()}; - for(ALsizei c{0};c < device->Dry.NumChannels;c++) + for(ALsizei c{0};c < num_chans;c++) { - MixDirectHrtf(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], - device->Dry.Buffer[c], state->Offset, state->IrSize, - state->Chan[c].Coeffs, state->Chan[c].Values, SamplesToDo - ); + MixDirectHrtf(LeftOut, RightOut, Input[c], state->Offset, state->IrSize, + state->Chan[c].Coeffs, state->Chan[c].Values, SamplesToDo); } state->Offset += SamplesToDo; } void ProcessAmbiDec(ALCdevice *device, ALsizei SamplesToDo) { + BFormatDec *ambidec{device->AmbiDecoder.get()}; if(device->Dry.Buffer != device->FOAOut.Buffer) - device->AmbiDecoder->upSample(device->Dry.Buffer, device->FOAOut.Buffer, - device->FOAOut.NumChannels, SamplesToDo - ); - device->AmbiDecoder->process(device->RealOut.Buffer, device->RealOut.NumChannels, - device->Dry.Buffer, SamplesToDo - ); + ambidec->upSample(device->Dry.Buffer, device->FOAOut.Buffer, device->FOAOut.NumChannels, + SamplesToDo); + ambidec->process(device->RealOut.Buffer, device->RealOut.NumChannels, device->Dry.Buffer, + SamplesToDo); } void ProcessAmbiUp(ALCdevice *device, ALsizei SamplesToDo) { device->AmbiUp->process(device->RealOut.Buffer, device->RealOut.NumChannels, - device->FOAOut.Buffer, SamplesToDo - ); + device->FOAOut.Buffer, SamplesToDo); } void ProcessUhj(ALCdevice *device, ALsizei SamplesToDo) { - int lidx = GetChannelIdxByName(device->RealOut, FrontLeft); - int ridx = GetChannelIdxByName(device->RealOut, FrontRight); - assert(lidx != -1 && ridx != -1); + /* UHJ is stereo output only. */ + const int lidx{(device->RealOut.ChannelName[0]==FrontLeft) ? 0 : 1}; + const int ridx{(device->RealOut.ChannelName[1]==FrontRight) ? 1 : 0}; /* Encode to stereo-compatible 2-channel UHJ output. */ EncodeUhj2(device->Uhj_Encoder.get(), @@ -177,9 +177,9 @@ void ProcessUhj(ALCdevice *device, ALsizei SamplesToDo) void ProcessBs2b(ALCdevice *device, ALsizei SamplesToDo) { - int lidx = GetChannelIdxByName(device->RealOut, FrontLeft); - int ridx = GetChannelIdxByName(device->RealOut, FrontRight); - assert(lidx != -1 && ridx != -1); + /* BS2B is stereo output only. */ + const int lidx{(device->RealOut.ChannelName[0]==FrontLeft) ? 0 : 1}; + const int ridx{(device->RealOut.ChannelName[1]==FrontRight) ? 1 : 0}; /* Apply binaural/crossfeed filter */ bs2b_cross_feed(device->Bs2b.get(), device->RealOut.Buffer[lidx], -- cgit v1.2.3 From 5c449de73f491a73cbc948b3301b8305f20be648 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 26 Dec 2018 13:20:59 -0800 Subject: Improve UHJ2 encoding --- Alc/alu.cpp | 7 +++-- Alc/uhjfilter.cpp | 79 +++++++++++++++++++++++++++---------------------------- Alc/uhjfilter.h | 18 ++++++------- 3 files changed, 51 insertions(+), 53 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 861932c9..2490f0cb 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -169,10 +169,9 @@ void ProcessUhj(ALCdevice *device, ALsizei SamplesToDo) const int ridx{(device->RealOut.ChannelName[1]==FrontRight) ? 1 : 0}; /* Encode to stereo-compatible 2-channel UHJ output. */ - EncodeUhj2(device->Uhj_Encoder.get(), - device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], - device->Dry.Buffer, SamplesToDo - ); + Uhj2Encoder *uhj2enc{device->Uhj_Encoder.get()}; + uhj2enc->encode(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], + device->Dry.Buffer, SamplesToDo); } void ProcessBs2b(ALCdevice *device, ALsizei SamplesToDo) diff --git a/Alc/uhjfilter.cpp b/Alc/uhjfilter.cpp index 4fae721f..1c5c836c 100644 --- a/Alc/uhjfilter.cpp +++ b/Alc/uhjfilter.cpp @@ -22,16 +22,13 @@ void allpass_process(AllPassState *state, ALfloat *RESTRICT dst, const ALfloat * { ALfloat z1 = state->z[0]; ALfloat z2 = state->z[1]; - ALsizei i; - - for(i = 0;i < todo;i++) + for(ALsizei i{0};i < todo;i++) { ALfloat input = src[i]; ALfloat output = input*aa + z1; z1 = z2; z2 = output*aa - input; dst[i] = output; } - state->z[0] = z1; state->z[1] = z2; } @@ -59,65 +56,67 @@ void allpass_process(AllPassState *state, ALfloat *RESTRICT dst, const ALfloat * * know which is the intended result. */ -void EncodeUhj2(Uhj2Encoder *enc, ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo) +void Uhj2Encoder::encode(ALfloat *LeftOut, ALfloat *RightOut, ALfloat (*InSamples)[BUFFERSIZE], const ALsizei SamplesToDo) { - ALfloat D[MAX_UPDATE_SAMPLES], S[MAX_UPDATE_SAMPLES]; - ALfloat temp[2][MAX_UPDATE_SAMPLES]; - ALsizei base, i; + alignas(16) ALfloat D[MAX_UPDATE_SAMPLES], S[MAX_UPDATE_SAMPLES]; + alignas(16) ALfloat temp[2][MAX_UPDATE_SAMPLES]; ASSUME(SamplesToDo > 0); - for(base = 0;base < SamplesToDo;) + for(ALsizei base{0};base < SamplesToDo;) { ALsizei todo = mini(SamplesToDo - base, MAX_UPDATE_SAMPLES); ASSUME(todo > 0); /* D = 0.6554516*Y */ - for(i = 0;i < todo;i++) - temp[0][i] = 0.6554516f*InSamples[2][base+i]; - allpass_process(&enc->Filter1_Y[0], temp[1], temp[0], Filter1CoeffSqr[0], todo); - allpass_process(&enc->Filter1_Y[1], temp[0], temp[1], Filter1CoeffSqr[1], todo); - allpass_process(&enc->Filter1_Y[2], temp[1], temp[0], Filter1CoeffSqr[2], todo); - allpass_process(&enc->Filter1_Y[3], temp[0], temp[1], Filter1CoeffSqr[3], todo); + const ALfloat *RESTRICT input{al::assume_aligned<16>(InSamples[2]+base)}; + for(ALsizei i{0};i < todo;i++) + temp[0][i] = 0.6554516f*input[i]; + allpass_process(&mFilter1_Y[0], temp[1], temp[0], Filter1CoeffSqr[0], todo); + allpass_process(&mFilter1_Y[1], temp[0], temp[1], Filter1CoeffSqr[1], todo); + allpass_process(&mFilter1_Y[2], temp[1], temp[0], Filter1CoeffSqr[2], todo); + allpass_process(&mFilter1_Y[3], temp[0], temp[1], Filter1CoeffSqr[3], todo); /* NOTE: Filter1 requires a 1 sample delay for the final output, so * take the last processed sample from the previous run as the first * output sample. */ - D[0] = enc->LastY; - for(i = 1;i < todo;i++) + D[0] = mLastY; + for(ALsizei i{1};i < todo;i++) D[i] = temp[0][i-1]; - enc->LastY = temp[0][i-1]; + mLastY = temp[0][todo-1]; /* D += j(-0.3420201*W + 0.5098604*X) */ - for(i = 0;i < todo;i++) - temp[0][i] = -0.3420201f*InSamples[0][base+i] + - 0.5098604f*InSamples[1][base+i]; - allpass_process(&enc->Filter2_WX[0], temp[1], temp[0], Filter2CoeffSqr[0], todo); - allpass_process(&enc->Filter2_WX[1], temp[0], temp[1], Filter2CoeffSqr[1], todo); - allpass_process(&enc->Filter2_WX[2], temp[1], temp[0], Filter2CoeffSqr[2], todo); - allpass_process(&enc->Filter2_WX[3], temp[0], temp[1], Filter2CoeffSqr[3], todo); - for(i = 0;i < todo;i++) + const ALfloat *RESTRICT input0{al::assume_aligned<16>(InSamples[0]+base)}; + const ALfloat *RESTRICT input1{al::assume_aligned<16>(InSamples[1]+base)}; + for(ALsizei i{0};i < todo;i++) + temp[0][i] = -0.3420201f*input0[i] + 0.5098604f*input1[i]; + allpass_process(&mFilter2_WX[0], temp[1], temp[0], Filter2CoeffSqr[0], todo); + allpass_process(&mFilter2_WX[1], temp[0], temp[1], Filter2CoeffSqr[1], todo); + allpass_process(&mFilter2_WX[2], temp[1], temp[0], Filter2CoeffSqr[2], todo); + allpass_process(&mFilter2_WX[3], temp[0], temp[1], Filter2CoeffSqr[3], todo); + for(ALsizei i{0};i < todo;i++) D[i] += temp[0][i]; /* S = 0.9396926*W + 0.1855740*X */ - for(i = 0;i < todo;i++) - temp[0][i] = 0.9396926f*InSamples[0][base+i] + - 0.1855740f*InSamples[1][base+i]; - allpass_process(&enc->Filter1_WX[0], temp[1], temp[0], Filter1CoeffSqr[0], todo); - allpass_process(&enc->Filter1_WX[1], temp[0], temp[1], Filter1CoeffSqr[1], todo); - allpass_process(&enc->Filter1_WX[2], temp[1], temp[0], Filter1CoeffSqr[2], todo); - allpass_process(&enc->Filter1_WX[3], temp[0], temp[1], Filter1CoeffSqr[3], todo); - S[0] = enc->LastWX; - for(i = 1;i < todo;i++) + for(ALsizei i{0};i < todo;i++) + temp[0][i] = 0.9396926f*input0[i] + 0.1855740f*input1[i]; + allpass_process(&mFilter1_WX[0], temp[1], temp[0], Filter1CoeffSqr[0], todo); + allpass_process(&mFilter1_WX[1], temp[0], temp[1], Filter1CoeffSqr[1], todo); + allpass_process(&mFilter1_WX[2], temp[1], temp[0], Filter1CoeffSqr[2], todo); + allpass_process(&mFilter1_WX[3], temp[0], temp[1], Filter1CoeffSqr[3], todo); + S[0] = mLastWX; + for(ALsizei i{1};i < todo;i++) S[i] = temp[0][i-1]; - enc->LastWX = temp[0][i-1]; + mLastWX = temp[0][todo-1]; /* Left = (S + D)/2.0 */ - for(i = 0;i < todo;i++) - *(LeftOut++) += (S[i] + D[i]) * 0.5f; + ALfloat *RESTRICT left = al::assume_aligned<16>(LeftOut+base); + for(ALsizei i{0};i < todo;i++) + left[i] += (S[i] + D[i]) * 0.5f; /* Right = (S - D)/2.0 */ - for(i = 0;i < todo;i++) - *(RightOut++) += (S[i] - D[i]) * 0.5f; + ALfloat *RESTRICT right = al::assume_aligned<16>(RightOut+base); + for(ALsizei i{0};i < todo;i++) + right[i] += (S[i] - D[i]) * 0.5f; base += todo; } diff --git a/Alc/uhjfilter.h b/Alc/uhjfilter.h index c6335af3..1351491b 100644 --- a/Alc/uhjfilter.h +++ b/Alc/uhjfilter.h @@ -37,17 +37,17 @@ struct AllPassState { */ struct Uhj2Encoder { - AllPassState Filter1_Y[4]; - AllPassState Filter2_WX[4]; - AllPassState Filter1_WX[4]; - ALfloat LastY{0.0f}, LastWX{0.0f}; + AllPassState mFilter1_Y[4]; + AllPassState mFilter2_WX[4]; + AllPassState mFilter1_WX[4]; + ALfloat mLastY{0.0f}, mLastWX{0.0f}; + + /* Encodes a 2-channel UHJ (stereo-compatible) signal from a B-Format input + * signal. The input must use FuMa channel ordering and scaling. + */ + void encode(ALfloat *LeftOut, ALfloat *RightOut, ALfloat (*InSamples)[BUFFERSIZE], const ALsizei SamplesToDo); DEF_NEWDEL(Uhj2Encoder) }; -/* Encodes a 2-channel UHJ (stereo-compatible) signal from a B-Format input - * signal. The input must use FuMa channel ordering and scaling. - */ -void EncodeUhj2(Uhj2Encoder *enc, ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo); - #endif /* UHJFILTER_H */ -- cgit v1.2.3 From c5be03b51e8fd9bda3a46c345bdc945cfd965c2e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 26 Dec 2018 14:59:21 -0800 Subject: Avoid masking in ApplyCoeffs's inner loop This unfortunately does not apply to NEON, which would need a bit more reworking of its method. --- Alc/mixer/hrtf_inc.cpp | 7 ++--- Alc/mixer/mixer_c.cpp | 22 ++++++++++++---- Alc/mixer/mixer_sse.cpp | 68 +++++++++++++++++++++++++++++++------------------ 3 files changed, 62 insertions(+), 35 deletions(-) diff --git a/Alc/mixer/hrtf_inc.cpp b/Alc/mixer/hrtf_inc.cpp index 22715abc..d811bd61 100644 --- a/Alc/mixer/hrtf_inc.cpp +++ b/Alc/mixer/hrtf_inc.cpp @@ -107,19 +107,16 @@ void MixDirectHrtf(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat (*RESTRICT Coeffs)[2], ALfloat (*RESTRICT Values)[2], ALsizei BufferSize) { - ALfloat insample; - ALsizei i; - ASSUME(IrSize >= 4); ASSUME(BufferSize > 0); - for(i = 0;i < BufferSize;i++) + for(ALsizei i{0};i < BufferSize;i++) { Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; Offset++; - insample = *(data++); + const ALfloat insample{*(data++)}; ApplyCoeffs(Offset, Values, IrSize, Coeffs, insample, insample); *(LeftOut++) += Values[Offset&HRIR_MASK][0]; *(RightOut++) += Values[Offset&HRIR_MASK][1]; diff --git a/Alc/mixer/mixer_c.cpp b/Alc/mixer/mixer_c.cpp index 7a2a6319..bbf58325 100644 --- a/Alc/mixer/mixer_c.cpp +++ b/Alc/mixer/mixer_c.cpp @@ -108,12 +108,24 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], const ALfloat (*RESTRICT Coeffs)[2], ALfloat left, ALfloat right) { - ALsizei c; - for(c = 0;c < IrSize;c++) + ALsizei off{Offset&HRIR_MASK}; + ALsizei count{mini(IrSize, HRIR_LENGTH - off)}; + + ASSUME(IrSize > 0); + ASSUME(count > 0); + + for(ALsizei c{0};;) { - const ALsizei off = (Offset+c)&HRIR_MASK; - Values[off][0] += Coeffs[c][0] * left; - Values[off][1] += Coeffs[c][1] * right; + for(;c < count;++c) + { + Values[off][0] += Coeffs[c][0] * left; + Values[off][1] += Coeffs[c][1] * right; + ++off; + } + if(c >= IrSize) + break; + off = 0; + count = IrSize; } } diff --git a/Alc/mixer/mixer_sse.cpp b/Alc/mixer/mixer_sse.cpp index f0620cb5..09307697 100644 --- a/Alc/mixer/mixer_sse.cpp +++ b/Alc/mixer/mixer_sse.cpp @@ -87,46 +87,64 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], const __m128 lrlr = _mm_setr_ps(left, right, left, right); __m128 vals = _mm_setzero_ps(); __m128 coeffs; - ALsizei i; + ASSUME(IrSize > 1); + + ALsizei off{Offset&HRIR_MASK}; if((Offset&1)) { - const ALsizei o0 = Offset&HRIR_MASK; - const ALsizei o1 = (Offset+IrSize-1)&HRIR_MASK; - __m128 imp0, imp1; + ALsizei count{mini(IrSize-1, HRIR_LENGTH - off)}; + ASSUME(count >= 1); + __m128 imp0, imp1; coeffs = _mm_load_ps(&Coeffs[0][0]); - vals = _mm_loadl_pi(vals, (__m64*)&Values[o0][0]); + vals = _mm_loadl_pi(vals, (__m64*)&Values[off][0]); imp0 = _mm_mul_ps(lrlr, coeffs); vals = _mm_add_ps(imp0, vals); - _mm_storel_pi((__m64*)&Values[o0][0], vals); - for(i = 1;i < IrSize-1;i += 2) + _mm_storel_pi((__m64*)&Values[off][0], vals); + ++off; + for(ALsizei i{1};;) { - const ALsizei o2 = (Offset+i)&HRIR_MASK; - - coeffs = _mm_load_ps(&Coeffs[i+1][0]); - vals = _mm_load_ps(&Values[o2][0]); - imp1 = _mm_mul_ps(lrlr, coeffs); - imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2)); - vals = _mm_add_ps(imp0, vals); - _mm_store_ps(&Values[o2][0], vals); - imp0 = imp1; + for(;i < count;i += 2) + { + coeffs = _mm_load_ps(&Coeffs[i+1][0]); + vals = _mm_load_ps(&Values[off][0]); + imp1 = _mm_mul_ps(lrlr, coeffs); + imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2)); + vals = _mm_add_ps(imp0, vals); + _mm_store_ps(&Values[off][0], vals); + imp0 = imp1; + off += 2; + } + off &= HRIR_MASK; + if(i >= IrSize-1) + break; + count = IrSize-1; } - vals = _mm_loadl_pi(vals, (__m64*)&Values[o1][0]); + vals = _mm_loadl_pi(vals, (__m64*)&Values[off][0]); imp0 = _mm_movehl_ps(imp0, imp0); vals = _mm_add_ps(imp0, vals); - _mm_storel_pi((__m64*)&Values[o1][0], vals); + _mm_storel_pi((__m64*)&Values[off][0], vals); } else { - for(i = 0;i < IrSize;i += 2) - { - const ALsizei o = (Offset + i)&HRIR_MASK; + ALsizei count{mini(IrSize, HRIR_LENGTH - off)}; + ASSUME(count >= 2); - coeffs = _mm_load_ps(&Coeffs[i][0]); - vals = _mm_load_ps(&Values[o][0]); - vals = _mm_add_ps(vals, _mm_mul_ps(lrlr, coeffs)); - _mm_store_ps(&Values[o][0], vals); + for(ALsizei i{0};;) + { + for(;i < count;i += 2) + { + coeffs = _mm_load_ps(&Coeffs[i][0]); + vals = _mm_load_ps(&Values[off][0]); + vals = _mm_add_ps(vals, _mm_mul_ps(lrlr, coeffs)); + _mm_store_ps(&Values[off][0], vals); + off += 2; + } + if(i >= IrSize) + break; + off = 0; + count = IrSize; } } } -- cgit v1.2.3 From 4f253a935a14e49a77516a56e0d4c6d6177a56b6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 26 Dec 2018 15:35:05 -0800 Subject: Handle HRTF coefficients and values by reference where possible --- Alc/alu.cpp | 5 +---- Alc/mixer/defs.h | 16 +++++++--------- Alc/mixer/hrtf_inc.cpp | 23 +++++++++++++---------- Alc/mixer/mixer_c.cpp | 10 +++++----- Alc/mixer/mixer_neon.cpp | 13 +++++++------ Alc/mixer/mixer_sse.cpp | 10 +++++----- Alc/mixvoice.cpp | 4 ++-- OpenAL32/Include/alu.h | 5 ++--- 8 files changed, 42 insertions(+), 44 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 2490f0cb..6655bd81 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -139,10 +139,7 @@ void ProcessHrtf(ALCdevice *device, ALsizei SamplesToDo) const ALfloat (*Input)[BUFFERSIZE]{device->Dry.Buffer}; DirectHrtfState *state{device->mHrtfState.get()}; for(ALsizei c{0};c < num_chans;c++) - { - MixDirectHrtf(LeftOut, RightOut, Input[c], state->Offset, state->IrSize, - state->Chan[c].Coeffs, state->Chan[c].Values, SamplesToDo); - } + MixDirectHrtf(LeftOut, RightOut, Input[c], state, c, SamplesToDo); state->Offset += SamplesToDo; } diff --git a/Alc/mixer/defs.h b/Alc/mixer/defs.h index 5fa88773..5bdf6e30 100644 --- a/Alc/mixer/defs.h +++ b/Alc/mixer/defs.h @@ -10,6 +10,7 @@ struct MixGains; struct MixHrtfParams; struct HrtfState; +struct DirectHrtfState; /* C resamplers */ const ALfloat *Resample_copy_C(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen); @@ -30,9 +31,8 @@ void MixHrtfBlend_C(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, MixHrtfParams *newparams, HrtfState *hrtfstate, ALsizei BufferSize); void MixDirectHrtf_C(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - const ALfloat (*RESTRICT Coeffs)[2], ALfloat (*RESTRICT Values)[2], - ALsizei BufferSize); + const ALfloat *data, DirectHrtfState *State, const ALsizei Chan, + const ALsizei BufferSize); void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, ALsizei BufferSize); @@ -51,9 +51,8 @@ void MixHrtfBlend_SSE(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, MixHrtfParams *newparams, HrtfState *hrtfstate, ALsizei BufferSize); void MixDirectHrtf_SSE(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - const ALfloat (*RESTRICT Coeffs)[2], ALfloat (*RESTRICT Values)[2], - ALsizei BufferSize); + const ALfloat *data, DirectHrtfState *State, const ALsizei Chan, + const ALsizei BufferSize); void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, ALsizei BufferSize); @@ -98,9 +97,8 @@ void MixHrtfBlend_Neon(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, MixHrtfParams *newparams, HrtfState *hrtfstate, ALsizei BufferSize); void MixDirectHrtf_Neon(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - const ALfloat (*RESTRICT Coeffs)[2], ALfloat (*RESTRICT Values)[2], - ALsizei BufferSize); + const ALfloat *data, DirectHrtfState *State, const ALsizei Chan, + const ALsizei BufferSize); void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, ALsizei BufferSize); diff --git a/Alc/mixer/hrtf_inc.cpp b/Alc/mixer/hrtf_inc.cpp index d811bd61..e82bad85 100644 --- a/Alc/mixer/hrtf_inc.cpp +++ b/Alc/mixer/hrtf_inc.cpp @@ -8,10 +8,9 @@ #include "defs.h" -static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], - const ALsizei irSize, - const ALfloat (*RESTRICT Coeffs)[2], - ALfloat left, ALfloat right); +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (&Values)[HRIR_LENGTH][2], + const ALsizei irSize, const ALfloat (&Coeffs)[HRIR_LENGTH][2], + const ALfloat left, const ALfloat right); void MixHrtf(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, @@ -19,7 +18,7 @@ void MixHrtf(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALsizei IrSize, MixHrtfParams *hrtfparams, HrtfState *hrtfstate, ALsizei BufferSize) { - const ALfloat (*Coeffs)[2] = hrtfparams->Coeffs; + const ALfloat (&Coeffs)[HRIR_LENGTH][2] = *hrtfparams->Coeffs; const ALsizei Delay[2] = { hrtfparams->Delay[0], hrtfparams->Delay[1] }; const ALfloat gainstep = hrtfparams->GainStep; const ALfloat gain = hrtfparams->Gain; @@ -59,11 +58,11 @@ void MixHrtfBlend(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, MixHrtfParams *newparams, HrtfState *hrtfstate, ALsizei BufferSize) { - const ALfloat (*OldCoeffs)[2] = oldparams->Coeffs; + const ALfloat (&OldCoeffs)[HRIR_LENGTH][2] = oldparams->Coeffs; const ALsizei OldDelay[2] = { oldparams->Delay[0], oldparams->Delay[1] }; const ALfloat oldGain = oldparams->Gain; const ALfloat oldGainStep = -oldGain / (ALfloat)BufferSize; - const ALfloat (*NewCoeffs)[2] = newparams->Coeffs; + const ALfloat (&NewCoeffs)[HRIR_LENGTH][2] = *newparams->Coeffs; const ALsizei NewDelay[2] = { newparams->Delay[0], newparams->Delay[1] }; const ALfloat newGain = newparams->Gain; const ALfloat newGainStep = newparams->GainStep; @@ -103,10 +102,14 @@ void MixHrtfBlend(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, } void MixDirectHrtf(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - const ALfloat (*RESTRICT Coeffs)[2], ALfloat (*RESTRICT Values)[2], - ALsizei BufferSize) + const ALfloat *data, DirectHrtfState *State, const ALsizei Chan, + const ALsizei BufferSize) { + const ALsizei IrSize{State->IrSize}; + ALsizei Offset{State->Offset}; + ALfloat (&Values)[HRIR_LENGTH][2] = State->Chan[Chan].Values; + const ALfloat (&Coeffs)[HRIR_LENGTH][2] = State->Chan[Chan].Coeffs; + ASSUME(IrSize >= 4); ASSUME(BufferSize > 0); diff --git a/Alc/mixer/mixer_c.cpp b/Alc/mixer/mixer_c.cpp index bbf58325..d98b8e2e 100644 --- a/Alc/mixer/mixer_c.cpp +++ b/Alc/mixer/mixer_c.cpp @@ -103,15 +103,15 @@ const ALfloat *Resample_bsinc_C(const InterpState *state, const ALfloat *RESTRIC { return DoResample(state, src-state->bsinc.l, frac, increment, dst, numsamples); } -static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], - const ALsizei IrSize, - const ALfloat (*RESTRICT Coeffs)[2], - ALfloat left, ALfloat right) +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (&Values)[HRIR_LENGTH][2], + const ALsizei IrSize, const ALfloat (&Coeffs)[HRIR_LENGTH][2], + const ALfloat left, const ALfloat right) { ALsizei off{Offset&HRIR_MASK}; ALsizei count{mini(IrSize, HRIR_LENGTH - off)}; - ASSUME(IrSize > 0); + ASSUME(IrSize >= 2); + ASSUME(&Values != &Coeffs); ASSUME(count > 0); for(ALsizei c{0};;) diff --git a/Alc/mixer/mixer_neon.cpp b/Alc/mixer/mixer_neon.cpp index fa777eac..4843922f 100644 --- a/Alc/mixer/mixer_neon.cpp +++ b/Alc/mixer/mixer_neon.cpp @@ -133,12 +133,13 @@ const ALfloat *Resample_bsinc_Neon(const InterpState *state, } -static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], - const ALsizei IrSize, - const ALfloat (*RESTRICT Coeffs)[2], - ALfloat left, ALfloat right) +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (&Values)[HRIR_LENGTH][2], + const ALsizei IrSize, const ALfloat (&Coeffs)[HRIR_LENGTH][2], + const ALfloat left, const ALfloat right) { - ALsizei c; + ASSUME(IrSize >= 2); + ASSUME(&Values != &Coeffs); + float32x4_t leftright4; { float32x2_t leftright2 = vdup_n_f32(0.0); @@ -147,7 +148,7 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], leftright4 = vcombine_f32(leftright2, leftright2); } - for(c = 0;c < IrSize;c += 2) + for(ALsizei c{0};c < IrSize;c += 2) { const ALsizei o0 = (Offset+c)&HRIR_MASK; const ALsizei o1 = (o0+1)&HRIR_MASK; diff --git a/Alc/mixer/mixer_sse.cpp b/Alc/mixer/mixer_sse.cpp index 09307697..5d82e5ae 100644 --- a/Alc/mixer/mixer_sse.cpp +++ b/Alc/mixer/mixer_sse.cpp @@ -79,16 +79,16 @@ const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *RESTR } -static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*RESTRICT Values)[2], - const ALsizei IrSize, - const ALfloat (*RESTRICT Coeffs)[2], - ALfloat left, ALfloat right) +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (&Values)[HRIR_LENGTH][2], + const ALsizei IrSize, const ALfloat (&Coeffs)[HRIR_LENGTH][2], + const ALfloat left, const ALfloat right) { const __m128 lrlr = _mm_setr_ps(left, right, left, right); __m128 vals = _mm_setzero_ps(); __m128 coeffs; - ASSUME(IrSize > 1); + ASSUME(IrSize >= 2); + ASSUME(&Values != &Coeffs); ALsizei off{Offset&HRIR_MASK}; if((Offset&1)) diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 5b18d547..b94f26be 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -605,7 +605,7 @@ ALboolean MixSource(ALvoice *voice, const ALuint SourceID, ALCcontext *Context, ALfloat gain{lerp(parms.Hrtf.Old.Gain, parms.Hrtf.Target.Gain, minf(1.0f, (ALfloat)fademix/Counter))}; MixHrtfParams hrtfparams; - hrtfparams.Coeffs = parms.Hrtf.Target.Coeffs; + hrtfparams.Coeffs = &parms.Hrtf.Target.Coeffs; hrtfparams.Delay[0] = parms.Hrtf.Target.Delay[0]; hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1]; hrtfparams.Gain = 0.0f; @@ -634,7 +634,7 @@ ALboolean MixSource(ALvoice *voice, const ALuint SourceID, ALCcontext *Context, (ALfloat)todo/(Counter-fademix)); MixHrtfParams hrtfparams; - hrtfparams.Coeffs = parms.Hrtf.Target.Coeffs; + hrtfparams.Coeffs = &parms.Hrtf.Target.Coeffs; hrtfparams.Delay[0] = parms.Hrtf.Target.Delay[0]; hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1]; hrtfparams.Gain = parms.Hrtf.Old.Gain; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 42c754cc..775d34f6 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -108,7 +108,7 @@ enum { struct MixHrtfParams { - const ALfloat (*Coeffs)[2]; + const ALfloat (*Coeffs)[HRIR_LENGTH][2]; ALsizei Delay[2]; ALfloat Gain; ALfloat GainStep; @@ -286,8 +286,7 @@ using HrtfMixerBlendFunc = void(*)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT const HrtfParams *oldparams, MixHrtfParams *newparams, HrtfState *hrtfstate, ALsizei BufferSize); using HrtfDirectMixerFunc = void(*)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, ALsizei Offset, const ALsizei IrSize, const ALfloat (*RESTRICT Coeffs)[2], - ALfloat (*RESTRICT Values)[2], ALsizei BufferSize); + const ALfloat *data, DirectHrtfState *State, const ALsizei Chan, const ALsizei BufferSize); #define GAIN_MIX_MAX (1000.0f) /* +60dB */ -- cgit v1.2.3 From 8a0295503db394ea895bfa079d1f3eda0d758e61 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 26 Dec 2018 21:22:17 -0800 Subject: Clean up the ring buffer struct and use member functions --- Alc/alc.cpp | 2 +- Alc/alcontext.h | 4 +- Alc/alu.cpp | 16 ++-- Alc/backends/alsa.cpp | 13 +-- Alc/backends/coreaudio.cpp | 13 +-- Alc/backends/dsound.cpp | 16 ++-- Alc/backends/jack.cpp | 17 ++-- Alc/backends/opensl.cpp | 54 ++++++------ Alc/backends/oss.cpp | 13 +-- Alc/backends/portaudio.cpp | 11 ++- Alc/backends/sndio.cpp | 16 ++-- Alc/backends/wasapi.cpp | 13 +-- Alc/backends/winmm.cpp | 13 +-- Alc/mixvoice.cpp | 5 +- Alc/ringbuffer.cpp | 203 ++++++++++++++++++++------------------------- Alc/ringbuffer.h | 122 +++++++++++++-------------- OpenAL32/alSource.cpp | 9 +- OpenAL32/event.cpp | 14 ++-- 18 files changed, 285 insertions(+), 269 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index d13cfc54..294ba394 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2466,7 +2466,7 @@ ALCcontext_struct::~ALCcontext_struct() TRACE("Freed " SZFMT " listener property object%s\n", count, (count==1)?"":"s"); count = 0; - auto evt_vec = ll_ringbuffer_get_read_vector(AsyncEvents); + auto evt_vec = AsyncEvents->getReadVector(); while(evt_vec.first.len > 0) { reinterpret_cast(evt_vec.first.buf)->~AsyncEvent(); diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 7b7688ac..dadb4f8f 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -27,7 +27,7 @@ struct ALvoiceProps; struct ALeffectslotProps; struct ALvoice; struct ALeffectslotArray; -struct ll_ringbuffer; +struct RingBuffer; enum class DistanceModel { InverseClamped = AL_INVERSE_DISTANCE_CLAMPED, @@ -112,7 +112,7 @@ struct ALCcontext_struct { std::thread EventThread; al::semaphore EventSem; - ll_ringbuffer *AsyncEvents{nullptr}; + RingBuffer *AsyncEvents{nullptr}; std::atomic EnabledEvts{0u}; std::mutex EventCbLock; ALEVENTPROCSOFT EventCb{}; diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 6655bd81..1ebf3adc 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -289,13 +289,15 @@ void SendSourceStoppedEvent(ALCcontext *context, ALuint id) ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)}; if(!(enabledevt&EventType_SourceStateChange)) return; - auto evt_data = ll_ringbuffer_get_write_vector(context->AsyncEvents).first; + RingBuffer *ring{context->AsyncEvents}; + auto evt_data = ring->getWriteVector().first; if(evt_data.len < 1) return; AsyncEvent *evt{new (evt_data.buf) AsyncEvent{EventType_SourceStateChange}}; evt->u.srcstate.id = id; evt->u.srcstate.state = AL_STOPPED; - ll_ringbuffer_write_advance(context->AsyncEvents, 1); + + ring->writeAdvance(1); context->EventSem.post(); } @@ -414,12 +416,13 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) /* Otherwise, if it would be deleted, send it off with a release * event. */ - auto evt_vec = ll_ringbuffer_get_write_vector(context->AsyncEvents); + RingBuffer *ring{context->AsyncEvents}; + auto evt_vec = ring->getWriteVector(); if(LIKELY(evt_vec.first.len > 0)) { AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_ReleaseEffectState}}; evt->u.mEffectState = oldstate; - ll_ringbuffer_write_advance(context->AsyncEvents, 1); + ring->writeAdvance(1); context->EventSem.post(); } else @@ -1837,11 +1840,12 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) const ALbitfieldSOFT enabledevt{ctx->EnabledEvts.load(std::memory_order_acquire)}; if((enabledevt&EventType_Disconnected)) { - auto evt_data = ll_ringbuffer_get_write_vector(ctx->AsyncEvents).first; + RingBuffer *ring{ctx->AsyncEvents}; + auto evt_data = ring->getWriteVector().first; if(evt_data.len > 0) { new (evt_data.buf) AsyncEvent{evt}; - ll_ringbuffer_write_advance(ctx->AsyncEvents, 1); + ring->writeAdvance(1); ctx->EventSem.post(); } } diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index cf3f7fff..fd6981f8 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -1136,9 +1136,9 @@ ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALC { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - if(self->Ring) + if(RingBuffer *ring{self->Ring.get()}) { - ll_ringbuffer_read(self->Ring.get(), static_cast(buffer), samples); + ring->read(static_cast(buffer), samples); return ALC_NO_ERROR; } @@ -1221,7 +1221,8 @@ ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) } } - if(!self->Ring) + RingBuffer *ring{self->Ring.get()}; + if(!ring) { if(avail < 0) avail = 0; avail += snd_pcm_bytes_to_frames(self->PcmHandle, self->Buffer.size()); @@ -1231,7 +1232,7 @@ ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) while(avail > 0) { - auto vec = ll_ringbuffer_get_write_vector(self->Ring.get()); + auto vec = ring->getWriteVector(); if(vec.first.len == 0) break; snd_pcm_sframes_t amt{std::min(vec.first.len, avail)}; @@ -1259,11 +1260,11 @@ ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) continue; } - ll_ringbuffer_write_advance(self->Ring.get(), amt); + ring->writeAdvance(amt); avail -= amt; } - return ll_ringbuffer_read_space(self->Ring.get()); + return ring->readSpace(); } ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self) diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index c73a67f9..808e7cb8 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -404,7 +404,8 @@ static OSStatus ALCcoreAudioCapture_RecordProc(void *inRefCon, const AudioTimeStamp *inTimeStamp, UInt32 UNUSED(inBusNumber), UInt32 inNumberFrames, AudioBufferList* UNUSED(ioData)) { - ALCcoreAudioCapture *self = static_cast(inRefCon); + auto self = static_cast(inRefCon); + RingBuffer *ring{self->Ring.get()}; AudioUnitRenderActionFlags flags = 0; OSStatus err; @@ -416,7 +417,7 @@ static OSStatus ALCcoreAudioCapture_RecordProc(void *inRefCon, return err; } - ll_ringbuffer_write(self->Ring.get(), self->BufferList->mBuffers[0].mData, inNumberFrames); + ring->write(self->BufferList->mBuffers[0].mData, inNumberFrames); return noErr; } @@ -425,10 +426,11 @@ static OSStatus ALCcoreAudioCapture_ConvertCallback(AudioConverterRef UNUSED(inA AudioStreamPacketDescription** UNUSED(outDataPacketDescription), void *inUserData) { - ALCcoreAudioCapture *self = reinterpret_cast(inUserData); + auto self = reinterpret_cast(inUserData); + RingBuffer *ring{self->Ring.get()}; // Read from the ring buffer and store temporarily in a large buffer - ll_ringbuffer_read(self->Ring.get(), self->ResampleBuffer, *ioNumberDataPackets); + ring->read(self->ResampleBuffer, *ioNumberDataPackets); // Set the input data ioData->mNumberBuffers = 1; @@ -739,7 +741,8 @@ static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALC static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self) { - return ll_ringbuffer_read_space(self->Ring.get()) / self->SampleRateRatio; + RingBuffer *ring{self->Ring.get()}; + return ring->readSpace() / self->SampleRateRatio; } diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 4ada7419..516a7770 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -889,16 +889,18 @@ void ALCdsoundCapture_stop(ALCdsoundCapture *self) ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint samples) { - ll_ringbuffer_read(self->Ring.get(), buffer, samples); + RingBuffer *ring{self->Ring.get()}; + ring->read(buffer, samples); return ALC_NO_ERROR; } ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; + RingBuffer *ring{self->Ring.get()}; if(!device->Connected.load(std::memory_order_acquire)) - return static_cast(ll_ringbuffer_read_space(self->Ring.get())); + return static_cast(ring->readSpace()); ALsizei FrameSize{device->frameSizeFromFmt()}; DWORD BufferBytes{self->BufferBytes}; @@ -911,15 +913,15 @@ ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) if(SUCCEEDED(hr)) { DWORD NumBytes{(ReadCursor-LastCursor + BufferBytes) % BufferBytes}; - if(!NumBytes) return static_cast(ll_ringbuffer_read_space(self->Ring.get())); + if(!NumBytes) return static_cast(ring->readSpace()); hr = self->DSCbuffer->Lock(LastCursor, NumBytes, &ReadPtr1, &ReadCnt1, &ReadPtr2, &ReadCnt2, 0); } if(SUCCEEDED(hr)) { - ll_ringbuffer_write(self->Ring.get(), ReadPtr1, ReadCnt1/FrameSize); + ring->write(ReadPtr1, ReadCnt1/FrameSize); if(ReadPtr2 != nullptr) - ll_ringbuffer_write(self->Ring.get(), ReadPtr2, ReadCnt2/FrameSize); + ring->write(ReadPtr2, ReadCnt2/FrameSize); hr = self->DSCbuffer->Unlock(ReadPtr1, ReadCnt1, ReadPtr2, ReadCnt2); self->Cursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes; } @@ -930,7 +932,7 @@ ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) aluHandleDisconnect(device, "Failure retrieving capture data: 0x%lx", hr); } - return static_cast(ll_ringbuffer_read_space(self->Ring.get())); + return static_cast(ring->readSpace()); } } // namespace diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index c768983d..02e29973 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -245,7 +245,8 @@ int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) out[numchans++] = static_cast(jack_port_get_buffer(port, numframes)); } - auto data = ll_ringbuffer_get_read_vector(self->mRing.get()); + RingBuffer *ring{self->mRing.get()}; + auto data = ring->getReadVector(); jack_nframes_t todo{minu(numframes, data.first.len)}; std::transform(out, out+numchans, out, [&data,numchans,todo](ALfloat *outbuf) -> ALfloat* @@ -287,7 +288,7 @@ int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) total += todo; } - ll_ringbuffer_read_advance(self->mRing.get(), total); + ring->readAdvance(total); self->mSem.post(); if(numframes > total) @@ -307,7 +308,8 @@ int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) int ALCjackPlayback_mixerProc(ALCjackPlayback *self) { - ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; + ALCdevice *device{self->mDevice}; + RingBuffer *ring{self->mRing.get()}; SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); @@ -316,7 +318,7 @@ int ALCjackPlayback_mixerProc(ALCjackPlayback *self) while(!self->mKillNow.load(std::memory_order_acquire) && device->Connected.load(std::memory_order_acquire)) { - if(ll_ringbuffer_write_space(self->mRing.get()) < device->UpdateSize) + if(ring->writeSpace() < device->UpdateSize) { ALCjackPlayback_unlock(self); self->mSem.wait(); @@ -324,7 +326,7 @@ int ALCjackPlayback_mixerProc(ALCjackPlayback *self) continue; } - auto data = ll_ringbuffer_get_write_vector(self->mRing.get()); + auto data = ring->getWriteVector(); auto todo = static_cast(data.first.len + data.second.len); todo -= todo%device->UpdateSize; @@ -334,7 +336,7 @@ int ALCjackPlayback_mixerProc(ALCjackPlayback *self) aluMixData(device, data.first.buf, len1); if(len2 > 0) aluMixData(device, data.second.buf, len2); - ll_ringbuffer_write_advance(self->mRing.get(), todo); + ring->writeAdvance(todo); } ALCjackPlayback_unlock(self); @@ -506,8 +508,9 @@ ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self) ALCjackPlayback_lock(self); ALCdevice *device{self->mDevice}; + RingBuffer *ring{self->mRing.get()}; ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = std::chrono::seconds{ll_ringbuffer_read_space(self->mRing.get())}; + ret.Latency = std::chrono::seconds{ring->readSpace()}; ret.Latency /= device->Frequency; ALCjackPlayback_unlock(self); diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 9213919b..872fbc91 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -203,7 +203,8 @@ static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self) /* this callback handler is called every time a buffer finishes playing */ static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), void *context) { - ALCopenslPlayback *self = static_cast(context); + auto self = static_cast(context); + RingBuffer *ring{self->mRing.get()}; /* A note on the ringbuffer usage: The buffer queue seems to hold on to the * pointer passed to the Enqueue method, rather than copying the audio. @@ -213,7 +214,7 @@ static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), * available for writing again, and wake up the mixer thread to mix and * queue more audio. */ - ll_ringbuffer_read_advance(self->mRing.get(), 1); + ring->readAdvance(1); self->mSem.post(); } @@ -221,7 +222,8 @@ static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), static int ALCopenslPlayback_mixerProc(ALCopenslPlayback *self) { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCdevice *device{self->mDevice}; + RingBuffer *ring{self->mRing.get()}; SLAndroidSimpleBufferQueueItf bufferQueue; SLPlayItf player; SLresult result; @@ -247,7 +249,7 @@ static int ALCopenslPlayback_mixerProc(ALCopenslPlayback *self) { size_t todo; - if(ll_ringbuffer_write_space(self->mRing.get()) == 0) + if(ring->writeSpace() == 0) { SLuint32 state = 0; @@ -264,7 +266,7 @@ static int ALCopenslPlayback_mixerProc(ALCopenslPlayback *self) break; } - if(ll_ringbuffer_write_space(self->mRing.get()) == 0) + if(ring->writeSpace() == 0) { ALCopenslPlayback_unlock(self); self->mSem.wait(); @@ -273,15 +275,15 @@ static int ALCopenslPlayback_mixerProc(ALCopenslPlayback *self) } } - auto data = ll_ringbuffer_get_write_vector(self->mRing.get()); + auto data = ring->getWriteVector(); aluMixData(device, data.first.buf, data.first.len*device->UpdateSize); if(data.second.len > 0) aluMixData(device, data.second.buf, data.second.len*device->UpdateSize); todo = data.first.len+data.second.len; - ll_ringbuffer_write_advance(self->mRing.get(), todo); + ring->writeAdvance(todo); - for(size_t i = 0;i < todo;i++) + for(size_t i{0};i < todo;i++) { if(!data.first.len) { @@ -556,13 +558,13 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self) { - SLAndroidSimpleBufferQueueItf bufferQueue; - SLresult result; + RingBuffer *ring{self->mRing.get()}; - ll_ringbuffer_reset(self->mRing.get()); + ring->reset(); - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue); + SLAndroidSimpleBufferQueueItf bufferQueue; + SLresult result{VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &bufferQueue)}; PRINTERR(result, "bufferQueue->GetInterface"); if(SL_RESULT_SUCCESS != result) return ALC_FALSE; @@ -632,13 +634,13 @@ static void ALCopenslPlayback_stop(ALCopenslPlayback *self) static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; + RingBuffer *ring{self->mRing.get()}; ClockLatency ret; ALCopenslPlayback_lock(self); ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = std::chrono::seconds{ll_ringbuffer_read_space(self->mRing.get()) * - device->UpdateSize}; + ret.Latency = std::chrono::seconds{ring->readSpace() * device->UpdateSize}; ret.Latency /= device->Frequency; ALCopenslPlayback_unlock(self); @@ -702,9 +704,10 @@ static void ALCopenslCapture_Destruct(ALCopenslCapture *self) static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), void *context) { - ALCopenslCapture *self = static_cast(context); + auto *self = static_cast(context); + RingBuffer *ring{self->mRing.get()}; /* A new chunk has been written into the ring buffer, advance it. */ - ll_ringbuffer_write_advance(self->mRing.get(), 1); + ring->writeAdvance(1); } @@ -837,10 +840,11 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name } if(SL_RESULT_SUCCESS == result) { + RingBuffer *ring{self->mRing.get()}; ALsizei chunk_size = device->UpdateSize * self->mFrameSize; size_t i; - auto data = ll_ringbuffer_get_write_vector(self->mRing.get()); + auto data = ring->getWriteVector(); for(i = 0;i < data.first.len && SL_RESULT_SUCCESS == result;i++) { result = VCALL(bufferQueue,Enqueue)(data.first.buf + chunk_size*i, chunk_size); @@ -914,7 +918,8 @@ static void ALCopenslCapture_stop(ALCopenslCapture *self) static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid *buffer, ALCuint samples) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; + RingBuffer *ring{self->mRing.get()}; ALsizei chunk_size = device->UpdateSize * self->mFrameSize; SLAndroidSimpleBufferQueueItf bufferQueue; SLresult result; @@ -927,7 +932,7 @@ static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid * /* Read the desired samples from the ring buffer then advance its read * pointer. */ - auto data = ll_ringbuffer_get_read_vector(self->mRing.get()); + auto data = ring->getReadVector(); for(i = 0;i < samples;) { ALCuint rem = minu(samples - i, device->UpdateSize - self->mSplOffset); @@ -941,7 +946,7 @@ static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid * /* Finished a chunk, reset the offset and advance the read pointer. */ self->mSplOffset = 0; - ll_ringbuffer_read_advance(self->mRing.get(), 1); + ring->readAdvance(1); result = VCALL(bufferQueue,Enqueue)(data.first.buf, chunk_size); PRINTERR(result, "bufferQueue->Enqueue"); if(SL_RESULT_SUCCESS != result) break; @@ -969,8 +974,9 @@ static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid * static ALCuint ALCopenslCapture_availableSamples(ALCopenslCapture *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - return ll_ringbuffer_read_space(self->mRing.get()) * device->UpdateSize; + ALCdevice *device{self->mDevice}; + RingBuffer *ring{self->mRing.get()}; + return ring->readSpace() * device->UpdateSize; } diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index e338c40d..f6a75d12 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -537,7 +537,8 @@ void ALCcaptureOSS_Destruct(ALCcaptureOSS *self) int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) { - ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + ALCdevice *device{self->mDevice}; + RingBuffer *ring{self->mRing.get()}; SetRTPriority(); althrd_setname(RECORD_THREAD_NAME); @@ -564,7 +565,7 @@ int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) continue; } - auto vec = ll_ringbuffer_get_write_vector(self->mRing.get()); + auto vec = ring->getWriteVector(); if(vec.first.len > 0) { ssize_t amt{read(self->fd, vec.first.buf, vec.first.len*frame_size)}; @@ -576,7 +577,7 @@ int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) ALCcaptureOSS_unlock(self); break; } - ll_ringbuffer_write_advance(self->mRing.get(), amt/frame_size); + ring->writeAdvance(amt/frame_size); } } @@ -724,13 +725,15 @@ void ALCcaptureOSS_stop(ALCcaptureOSS *self) ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples) { - ll_ringbuffer_read(self->mRing.get(), static_cast(buffer), samples); + RingBuffer *ring{self->mRing.get()}; + ring->read(buffer, samples); return ALC_NO_ERROR; } ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self) { - return ll_ringbuffer_read_space(self->mRing.get()); + RingBuffer *ring{self->mRing.get()}; + return ring->readSpace(); } } // namespace diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index 59b357b5..f39661a7 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -365,8 +365,9 @@ int ALCportCapture_ReadCallback(const void *inputBuffer, void *UNUSED(outputBuff unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo), const PaStreamCallbackFlags UNUSED(statusFlags), void *userData) { - ALCportCapture *self = static_cast(userData); - ll_ringbuffer_write(self->Ring.get(), inputBuffer, framesPerBuffer); + auto self = static_cast(userData); + RingBuffer *ring{self->Ring.get()}; + ring->write(inputBuffer, framesPerBuffer); return 0; } @@ -456,12 +457,14 @@ void ALCportCapture_stop(ALCportCapture *self) ALCuint ALCportCapture_availableSamples(ALCportCapture *self) { - return ll_ringbuffer_read_space(self->Ring.get()); + RingBuffer *ring{self->Ring.get()}; + return ring->readSpace(); } ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples) { - ll_ringbuffer_read(self->Ring.get(), buffer, samples); + RingBuffer *ring{self->Ring.get()}; + ring->read(buffer, samples); return ALC_NO_ERROR; } diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index 2be1d26c..887b5703 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -323,20 +323,20 @@ static void SndioCapture_Destruct(SndioCapture *self) static int SndioCapture_recordProc(SndioCapture *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ALsizei frameSize; + ALCdevice *device{self->mDevice}; + RingBuffer *ring{self->ring.get()}; SetRTPriority(); althrd_setname(RECORD_THREAD_NAME); - frameSize = device->frameSizeFromFmt(); + const ALsizei frameSize{device->frameSizeFromFmt()}; while(!self->mKillNow.load(std::memory_order_acquire) && device->Connected.load(std::memory_order_acquire)) { size_t total, todo; - auto data = ll_ringbuffer_get_write_vector(self->ring.get()); + auto data = ring->getWriteVector(); todo = data.first.len + data.second.len; if(todo == 0) { @@ -369,7 +369,7 @@ static int SndioCapture_recordProc(SndioCapture *self) data.first.len -= got; total += got; } - ll_ringbuffer_write_advance(self->ring.get(), total / frameSize); + ring->writeAdvance(total / frameSize); } return 0; @@ -514,13 +514,15 @@ static void SndioCapture_stop(SndioCapture *self) static ALCenum SndioCapture_captureSamples(SndioCapture *self, void *buffer, ALCuint samples) { - ll_ringbuffer_read(self->ring.get(), static_cast(buffer), samples); + RingBuffer *ring{self->ring.get()}; + ring->read(buffer, samples); return ALC_NO_ERROR; } static ALCuint SndioCapture_availableSamples(SndioCapture *self) { - return ll_ringbuffer_read_space(self->ring.get()); + RingBuffer *ring{self->ring.get()}; + return ring->readSpace(); } diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index c1b4bddb..e1783ef9 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -1230,7 +1230,8 @@ void ALCwasapiCapture_Destruct(ALCwasapiCapture *self) FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) { - ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + ALCdevice *device{self->mDevice}; + RingBuffer *ring{self->mRing.get()}; IAudioCaptureClient *capture{self->mCapture}; HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); @@ -1272,7 +1273,7 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) rdata = reinterpret_cast(samples.data()); } - auto data = ll_ringbuffer_get_write_vector(self->mRing.get()); + auto data = ring->getWriteVector(); size_t dstframes; if(self->mSampleConv) @@ -1308,7 +1309,7 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) dstframes = len1 + len2; } - ll_ringbuffer_write_advance(self->mRing.get(), dstframes); + ring->writeAdvance(dstframes); hr = capture->ReleaseBuffer(numsamples); if(FAILED(hr)) ERR("Failed to release capture buffer: 0x%08lx\n", hr); @@ -1786,12 +1787,14 @@ void ALCwasapiCapture::stopProxy() ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self) { - return (ALuint)ll_ringbuffer_read_space(self->mRing.get()); + RingBuffer *ring{self->mRing.get()}; + return (ALuint)ring->readSpace(); } ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, ALCuint samples) { - ll_ringbuffer_read(self->mRing.get(), reinterpret_cast(buffer), samples); + RingBuffer *ring{self->mRing.get()}; + ring->read(buffer, samples); return ALC_NO_ERROR; } diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 0ebba81c..7bfb7f6c 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -472,7 +472,8 @@ void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN UNUSED(device), UINT msg, int ALCwinmmCapture_captureProc(ALCwinmmCapture *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; + RingBuffer *ring{self->Ring.get()}; althrd_setname(RECORD_THREAD_NAME); @@ -494,9 +495,7 @@ int ALCwinmmCapture_captureProc(ALCwinmmCapture *self) WAVEHDR &waveHdr = self->WaveBuffer[widx]; widx = (widx+1) % self->WaveBuffer.size(); - ll_ringbuffer_write(self->Ring.get(), waveHdr.lpData, - waveHdr.dwBytesRecorded / self->Format.nBlockAlign - ); + ring->write(waveHdr.lpData, waveHdr.dwBytesRecorded / self->Format.nBlockAlign); self->Readable.fetch_sub(1, std::memory_order_acq_rel); waveInAddBuffer(self->InHdl, &waveHdr, sizeof(WAVEHDR)); } while(--todo); @@ -645,13 +644,15 @@ void ALCwinmmCapture_stop(ALCwinmmCapture *self) ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples) { - ll_ringbuffer_read(self->Ring.get(), buffer, samples); + RingBuffer *ring{self->Ring.get()}; + ring->read(buffer, samples); return ALC_NO_ERROR; } ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self) { - return (ALCuint)ll_ringbuffer_read_space(self->Ring.get()); + RingBuffer *ring{self->Ring.get()}; + return (ALCuint)ring->readSpace(); } } // namespace diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index b94f26be..48844219 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -736,13 +736,14 @@ ALboolean MixSource(ALvoice *voice, const ALuint SourceID, ALCcontext *Context, ALbitfieldSOFT enabledevt{Context->EnabledEvts.load(std::memory_order_acquire)}; if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) { - auto evt_data = ll_ringbuffer_get_write_vector(Context->AsyncEvents).first; + RingBuffer *ring{Context->AsyncEvents}; + auto evt_data = ring->getWriteVector().first; if(evt_data.len > 0) { AsyncEvent *evt{new (evt_data.buf) AsyncEvent{EventType_BufferCompleted}}; evt->u.bufcomp.id = SourceID; evt->u.bufcomp.count = buffers_done; - ll_ringbuffer_write_advance(Context->AsyncEvents, 1); + ring->writeAdvance(1); Context->EventSem.post(); } } diff --git a/Alc/ringbuffer.cpp b/Alc/ringbuffer.cpp index a298ff43..9e531316 100644 --- a/Alc/ringbuffer.cpp +++ b/Alc/ringbuffer.cpp @@ -24,6 +24,8 @@ #include #include +#include + #include "ringbuffer.h" #include "atomic.h" #include "threads.h" @@ -31,9 +33,9 @@ #include "compat.h" -ll_ringbuffer *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes) +RingBuffer *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes) { - ll_ringbuffer *rb; + RingBuffer *rb; size_t power_of_two = 0; if(sz > 0) @@ -51,57 +53,52 @@ ll_ringbuffer *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes) power_of_two++; if(power_of_two < sz) return NULL; - rb = new (al_malloc(16, sizeof(*rb) + power_of_two*elem_sz)) ll_ringbuffer{}; + rb = new (al_malloc(16, sizeof(*rb) + power_of_two*elem_sz)) RingBuffer{}; - rb->size = limit_writes ? sz : power_of_two; - rb->size_mask = power_of_two - 1; - rb->elem_size = elem_sz; + rb->mSize = limit_writes ? sz : power_of_two; + rb->mSizeMask = power_of_two - 1; + rb->mElemSize = elem_sz; return rb; } -void ll_ringbuffer_reset(ll_ringbuffer *rb) +void RingBuffer::reset() noexcept { - rb->write_ptr.store(0, std::memory_order_relaxed); - rb->read_ptr.store(0, std::memory_order_relaxed); - std::fill_n(rb->buf+0, (rb->size_mask+1)*rb->elem_size, 0); + mWritePtr.store(0, std::memory_order_relaxed); + mReadPtr.store(0, std::memory_order_relaxed); + std::fill_n(mBuffer, (mSizeMask+1)*mElemSize, 0); } -size_t ll_ringbuffer_read_space(const ll_ringbuffer *rb) +size_t RingBuffer::readSpace() const noexcept { - size_t w = rb->write_ptr.load(std::memory_order_acquire); - size_t r = rb->read_ptr.load(std::memory_order_acquire); - return (w-r) & rb->size_mask; + size_t w = mWritePtr.load(std::memory_order_acquire); + size_t r = mReadPtr.load(std::memory_order_acquire); + return (w-r) & mSizeMask; } -size_t ll_ringbuffer_write_space(const ll_ringbuffer *rb) +size_t RingBuffer::writeSpace() const noexcept { - size_t w = rb->write_ptr.load(std::memory_order_acquire); - size_t r = rb->read_ptr.load(std::memory_order_acquire); - w = (r-w-1) & rb->size_mask; - return (w > rb->size) ? rb->size : w; + size_t w = mWritePtr.load(std::memory_order_acquire); + size_t r = mReadPtr.load(std::memory_order_acquire); + w = (r-w-1) & mSizeMask; + return std::max(w, mSize); } -size_t ll_ringbuffer_read(ll_ringbuffer *rb, void *dest, size_t cnt) +size_t RingBuffer::read(void *dest, size_t cnt) noexcept { - size_t read_ptr; - size_t free_cnt; - size_t cnt2; - size_t to_read; - size_t n1, n2; - - free_cnt = ll_ringbuffer_read_space(rb); + const size_t free_cnt{readSpace()}; if(free_cnt == 0) return 0; - to_read = (cnt > free_cnt) ? free_cnt : cnt; - read_ptr = rb->read_ptr.load(std::memory_order_relaxed) & rb->size_mask; + const size_t to_read{std::min(cnt, free_cnt)}; + size_t read_ptr{mReadPtr.load(std::memory_order_relaxed) & mSizeMask}; - cnt2 = read_ptr + to_read; - if(cnt2 > rb->size_mask+1) + size_t n1, n2; + const size_t cnt2{read_ptr + to_read}; + if(cnt2 > mSizeMask+1) { - n1 = rb->size_mask+1 - read_ptr; - n2 = cnt2 & rb->size_mask; + n1 = mSizeMask+1 - read_ptr; + n2 = cnt2 & mSizeMask; } else { @@ -109,38 +106,32 @@ size_t ll_ringbuffer_read(ll_ringbuffer *rb, void *dest, size_t cnt) n2 = 0; } - memcpy(dest, &rb->buf[read_ptr*rb->elem_size], n1*rb->elem_size); + memcpy(dest, &mBuffer[read_ptr*mElemSize], n1*mElemSize); read_ptr += n1; if(n2) { - memcpy(static_cast(dest) + n1*rb->elem_size, - &rb->buf[(read_ptr&rb->size_mask)*rb->elem_size], - n2*rb->elem_size); + memcpy(static_cast(dest) + n1*mElemSize, &mBuffer[(read_ptr&mSizeMask)*mElemSize], + n2*mElemSize); read_ptr += n2; } - rb->read_ptr.store(read_ptr, std::memory_order_release); + mReadPtr.store(read_ptr, std::memory_order_release); return to_read; } -size_t ll_ringbuffer_peek(ll_ringbuffer *rb, void *dest, size_t cnt) +size_t RingBuffer::peek(void *dest, size_t cnt) const noexcept { - size_t free_cnt; - size_t cnt2; - size_t to_read; - size_t n1, n2; - size_t read_ptr; - - free_cnt = ll_ringbuffer_read_space(rb); + const size_t free_cnt{readSpace()}; if(free_cnt == 0) return 0; - to_read = (cnt > free_cnt) ? free_cnt : cnt; - read_ptr = rb->read_ptr.load(std::memory_order_relaxed) & rb->size_mask; + const size_t to_read{std::min(cnt, free_cnt)}; + size_t read_ptr{mReadPtr.load(std::memory_order_relaxed) & mSizeMask}; - cnt2 = read_ptr + to_read; - if(cnt2 > rb->size_mask+1) + size_t n1, n2; + const size_t cnt2{read_ptr + to_read}; + if(cnt2 > mSizeMask+1) { - n1 = rb->size_mask+1 - read_ptr; - n2 = cnt2 & rb->size_mask; + n1 = mSizeMask+1 - read_ptr; + n2 = cnt2 & mSizeMask; } else { @@ -148,36 +139,30 @@ size_t ll_ringbuffer_peek(ll_ringbuffer *rb, void *dest, size_t cnt) n2 = 0; } - memcpy(dest, &rb->buf[read_ptr*rb->elem_size], n1*rb->elem_size); + memcpy(dest, &mBuffer[read_ptr*mElemSize], n1*mElemSize); if(n2) { read_ptr += n1; - memcpy(static_cast(dest) + n1*rb->elem_size, - &rb->buf[(read_ptr&rb->size_mask)*rb->elem_size], - n2*rb->elem_size); + memcpy(static_cast(dest) + n1*mElemSize, &mBuffer[(read_ptr&mSizeMask)*mElemSize], + n2*mElemSize); } return to_read; } -size_t ll_ringbuffer_write(ll_ringbuffer *rb, const void *src, size_t cnt) +size_t RingBuffer::write(const void *src, size_t cnt) noexcept { - size_t write_ptr; - size_t free_cnt; - size_t cnt2; - size_t to_write; - size_t n1, n2; - - free_cnt = ll_ringbuffer_write_space(rb); + const size_t free_cnt{writeSpace()}; if(free_cnt == 0) return 0; - to_write = (cnt > free_cnt) ? free_cnt : cnt; - write_ptr = rb->write_ptr.load(std::memory_order_relaxed) & rb->size_mask; + const size_t to_write{std::min(cnt, free_cnt)}; + size_t write_ptr{mWritePtr.load(std::memory_order_relaxed) & mSizeMask}; - cnt2 = write_ptr + to_write; - if(cnt2 > rb->size_mask+1) + size_t n1, n2; + const size_t cnt2{write_ptr + to_write}; + if(cnt2 > mSizeMask+1) { - n1 = rb->size_mask+1 - write_ptr; - n2 = cnt2 & rb->size_mask; + n1 = mSizeMask+1 - write_ptr; + n2 = cnt2 & mSizeMask; } else { @@ -185,57 +170,54 @@ size_t ll_ringbuffer_write(ll_ringbuffer *rb, const void *src, size_t cnt) n2 = 0; } - memcpy(&rb->buf[write_ptr*rb->elem_size], src, n1*rb->elem_size); + memcpy(&mBuffer[write_ptr*mElemSize], src, n1*mElemSize); write_ptr += n1; if(n2) { - memcpy(&rb->buf[(write_ptr&rb->size_mask)*rb->elem_size], - static_cast(src) + n1*rb->elem_size, - n2*rb->elem_size); + memcpy(&mBuffer[(write_ptr&mSizeMask)*mElemSize], + static_cast(src) + n1*mElemSize, n2*mElemSize); write_ptr += n2; } - rb->write_ptr.store(write_ptr, std::memory_order_release); + mWritePtr.store(write_ptr, std::memory_order_release); return to_write; } -void ll_ringbuffer_read_advance(ll_ringbuffer *rb, size_t cnt) +void RingBuffer::readAdvance(size_t cnt) noexcept { - rb->read_ptr.fetch_add(cnt, std::memory_order_acq_rel); + mReadPtr.fetch_add(cnt, std::memory_order_acq_rel); } -void ll_ringbuffer_write_advance(ll_ringbuffer *rb, size_t cnt) +void RingBuffer::writeAdvance(size_t cnt) noexcept { - rb->write_ptr.fetch_add(cnt, std::memory_order_acq_rel); + mWritePtr.fetch_add(cnt, std::memory_order_acq_rel); } -ll_ringbuffer_data_pair ll_ringbuffer_get_read_vector(const ll_ringbuffer *rb) +ll_ringbuffer_data_pair RingBuffer::getWriteVector() const noexcept { ll_ringbuffer_data_pair ret; - size_t free_cnt; - size_t cnt2; - size_t w = rb->write_ptr.load(std::memory_order_acquire); - size_t r = rb->read_ptr.load(std::memory_order_acquire); - w &= rb->size_mask; - r &= rb->size_mask; - free_cnt = (w-r) & rb->size_mask; + size_t w{mWritePtr.load(std::memory_order_acquire)}; + size_t r{mReadPtr.load(std::memory_order_acquire)}; + w &= mSizeMask; + r &= mSizeMask; + const size_t free_cnt{(w-r) & mSizeMask}; - cnt2 = r + free_cnt; - if(cnt2 > rb->size_mask+1) + const size_t cnt2{r + free_cnt}; + if(cnt2 > mSizeMask+1) { /* Two part vector: the rest of the buffer after the current write ptr, * plus some from the start of the buffer. */ - ret.first.buf = const_cast(&rb->buf[r*rb->elem_size]); - ret.first.len = rb->size_mask+1 - r; - ret.second.buf = const_cast(rb->buf); - ret.second.len = cnt2 & rb->size_mask; + ret.first.buf = const_cast(&mBuffer[r*mElemSize]); + ret.first.len = mSizeMask+1 - r; + ret.second.buf = const_cast(mBuffer); + ret.second.len = cnt2 & mSizeMask; } else { /* Single part vector: just the rest of the buffer */ - ret.first.buf = const_cast(&rb->buf[r*rb->elem_size]); + ret.first.buf = const_cast(&mBuffer[r*mElemSize]); ret.first.len = free_cnt; ret.second.buf = nullptr; ret.second.len = 0; @@ -244,32 +226,29 @@ ll_ringbuffer_data_pair ll_ringbuffer_get_read_vector(const ll_ringbuffer *rb) return ret; } -ll_ringbuffer_data_pair ll_ringbuffer_get_write_vector(const ll_ringbuffer *rb) +ll_ringbuffer_data_pair RingBuffer::getReadVector() const noexcept { ll_ringbuffer_data_pair ret; - size_t free_cnt; - size_t cnt2; - - size_t w = rb->write_ptr.load(std::memory_order_acquire); - size_t r = rb->read_ptr.load(std::memory_order_acquire); - w &= rb->size_mask; - r &= rb->size_mask; - free_cnt = (r-w-1) & rb->size_mask; - if(free_cnt > rb->size) free_cnt = rb->size; - - cnt2 = w + free_cnt; - if(cnt2 > rb->size_mask+1) + + size_t w{mWritePtr.load(std::memory_order_acquire)}; + size_t r{mReadPtr.load(std::memory_order_acquire)}; + w &= mSizeMask; + r &= mSizeMask; + const size_t free_cnt{std::min((r-w-1) & mSizeMask, mSize)}; + + const size_t cnt2{w + free_cnt}; + if(cnt2 > mSizeMask+1) { /* Two part vector: the rest of the buffer after the current write ptr, * plus some from the start of the buffer. */ - ret.first.buf = const_cast(&rb->buf[w*rb->elem_size]); - ret.first.len = rb->size_mask+1 - w; - ret.second.buf = const_cast(rb->buf); - ret.second.len = cnt2 & rb->size_mask; + ret.first.buf = const_cast(&mBuffer[w*mElemSize]); + ret.first.len = mSizeMask+1 - w; + ret.second.buf = const_cast(mBuffer); + ret.second.len = cnt2 & mSizeMask; } else { - ret.first.buf = const_cast(&rb->buf[w*rb->elem_size]); + ret.first.buf = const_cast(&mBuffer[w*mElemSize]); ret.first.len = free_cnt; ret.second.buf = nullptr; ret.second.len = 0; diff --git a/Alc/ringbuffer.h b/Alc/ringbuffer.h index 5111023e..a2871859 100644 --- a/Alc/ringbuffer.h +++ b/Alc/ringbuffer.h @@ -15,18 +15,6 @@ * size or count is in 'elements', not bytes. Additionally, it only supports * single-consumer/single-provider operation. */ -struct ll_ringbuffer { - std::atomic write_ptr{0u}; - std::atomic read_ptr{0u}; - size_t size{0u}; - size_t size_mask{0u}; - size_t elem_size{0u}; - - alignas(16) char buf[]; - - DEF_PLACE_NEWDEL() -}; - struct ll_ringbuffer_data { char *buf; @@ -35,60 +23,74 @@ struct ll_ringbuffer_data { using ll_ringbuffer_data_pair = std::pair; -/** - * Create a new ringbuffer to hold at least `sz' elements of `elem_sz' bytes. - * The number of elements is rounded up to the next power of two (even if it is - * already a power of two, to ensure the requested amount can be written). - */ -ll_ringbuffer *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes); -/** Reset the read and write pointers to zero. This is not thread safe. */ -void ll_ringbuffer_reset(ll_ringbuffer *rb); +struct RingBuffer { + std::atomic mWritePtr{0u}; + std::atomic mReadPtr{0u}; + size_t mSize{0u}; + size_t mSizeMask{0u}; + size_t mElemSize{0u}; + + alignas(16) char mBuffer[]; + + /** Reset the read and write pointers to zero. This is not thread safe. */ + void reset() noexcept; + + /** + * The non-copying data reader. Returns two ringbuffer data pointers that + * hold the current readable data. If the readable data is in one segment + * the second segment has zero length. + */ + ll_ringbuffer_data_pair getReadVector() const noexcept; + /** + * The non-copying data writer. Returns two ringbuffer data pointers that + * hold the current writeable data. If the writeable data is in one segment + * the second segment has zero length. + */ + ll_ringbuffer_data_pair getWriteVector() const noexcept; + + /** + * Return the number of elements available for reading. This is the number + * of elements in front of the read pointer and behind the write pointer. + */ + size_t readSpace() const noexcept; + /** + * The copying data reader. Copy at most `cnt' elements into `dest'. + * Returns the actual number of elements copied. + */ + size_t read(void *dest, size_t cnt) noexcept; + /** + * The copying data reader w/o read pointer advance. Copy at most `cnt' + * elements into `dest'. Returns the actual number of elements copied. + */ + size_t peek(void *dest, size_t cnt) const noexcept; + /** Advance the read pointer `cnt' places. */ + void readAdvance(size_t cnt) noexcept; + + /** + * Return the number of elements available for writing. This is the number + * of elements in front of the write pointer and behind the read pointer. + */ + size_t writeSpace() const noexcept; + /** + * The copying data writer. Copy at most `cnt' elements from `src'. Returns + * the actual number of elements copied. + */ + size_t write(const void *src, size_t cnt) noexcept; + /** Advance the write pointer `cnt' places. */ + void writeAdvance(size_t cnt) noexcept; -/** - * The non-copying data reader. Returns two ringbuffer data pointers that hold - * the current readable data at `rb'. If the readable data is in one segment - * the second segment has zero length. - */ -ll_ringbuffer_data_pair ll_ringbuffer_get_read_vector(const ll_ringbuffer *rb); -/** - * The non-copying data writer. Returns two ringbuffer data pointers that hold - * the current writeable data at `rb'. If the writeable data is in one segment - * the second segment has zero length. - */ -ll_ringbuffer_data_pair ll_ringbuffer_get_write_vector(const ll_ringbuffer *rb); + DEF_PLACE_NEWDEL() +}; -/** - * Return the number of elements available for reading. This is the number of - * elements in front of the read pointer and behind the write pointer. - */ -size_t ll_ringbuffer_read_space(const ll_ringbuffer *rb); -/** - * The copying data reader. Copy at most `cnt' elements from `rb' to `dest'. - * Returns the actual number of elements copied. - */ -size_t ll_ringbuffer_read(ll_ringbuffer *rb, void *dest, size_t cnt); -/** - * The copying data reader w/o read pointer advance. Copy at most `cnt' - * elements from `rb' to `dest'. Returns the actual number of elements copied. - */ -size_t ll_ringbuffer_peek(ll_ringbuffer *rb, void *dest, size_t cnt); -/** Advance the read pointer `cnt' places. */ -void ll_ringbuffer_read_advance(ll_ringbuffer *rb, size_t cnt); /** - * Return the number of elements available for writing. This is the number of - * elements in front of the write pointer and behind the read pointer. - */ -size_t ll_ringbuffer_write_space(const ll_ringbuffer *rb); -/** - * The copying data writer. Copy at most `cnt' elements to `rb' from `src'. - * Returns the actual number of elements copied. + * Create a new ringbuffer to hold at least `sz' elements of `elem_sz' bytes. + * The number of elements is rounded up to the next power of two (even if it is + * already a power of two, to ensure the requested amount can be written). */ -size_t ll_ringbuffer_write(ll_ringbuffer *rb, const void *src, size_t cnt); -/** Advance the write pointer `cnt' places. */ -void ll_ringbuffer_write_advance(ll_ringbuffer *rb, size_t cnt); +RingBuffer *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes); -using RingBufferPtr = std::unique_ptr; +using RingBufferPtr = std::unique_ptr; #endif /* RINGBUFFER_H */ diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index b70fc872..03375e2d 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -691,13 +691,14 @@ void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) * and we don't want state change messages to occur out of order, so send * it through the async queue to ensure proper ordering. */ - auto evt_data = ll_ringbuffer_get_write_vector(context->AsyncEvents).first; - if(evt_data.len < 1) return; + RingBuffer *ring{context->AsyncEvents}; + auto evt_vec = ring->getWriteVector(); + if(evt_vec.first.len < 1) return; - AsyncEvent *evt{new (evt_data.buf) AsyncEvent{EventType_SourceStateChange}}; + AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_SourceStateChange}}; evt->u.srcstate.id = id; evt->u.srcstate.state = state; - ll_ringbuffer_write_advance(context->AsyncEvents, 1); + ring->writeAdvance(1); context->EventSem.post(); } diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index 6399603b..f14c3229 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -17,10 +17,11 @@ static int EventThread(ALCcontext *context) { + RingBuffer *ring{context->AsyncEvents}; bool quitnow{false}; while(LIKELY(!quitnow)) { - auto evt_data = ll_ringbuffer_get_read_vector(context->AsyncEvents).first; + auto evt_data = ring->getReadVector().first; if(evt_data.len == 0) { context->EventSem.wait(); @@ -37,11 +38,11 @@ static int EventThread(ALCcontext *context) */ const struct EventAutoDestructor { AsyncEvent &evt; - ll_ringbuffer *ring; + RingBuffer *ring; ~EventAutoDestructor() { evt.~AsyncEvent(); - ll_ringbuffer_read_advance(ring, 1); + ring->readAdvance(1); } } _{evt, context->AsyncEvents}; @@ -110,16 +111,17 @@ void StartEventThrd(ALCcontext *ctx) void StopEventThrd(ALCcontext *ctx) { static constexpr AsyncEvent kill_evt{EventType_KillThread}; - ll_ringbuffer_data evt_data = ll_ringbuffer_get_write_vector(ctx->AsyncEvents).first; + RingBuffer *ring{ctx->AsyncEvents}; + auto evt_data = ring->getWriteVector().first; if(evt_data.len == 0) { do { std::this_thread::yield(); - evt_data = ll_ringbuffer_get_write_vector(ctx->AsyncEvents).first; + evt_data = ring->getWriteVector().first; } while(evt_data.len == 0); } new (evt_data.buf) AsyncEvent{kill_evt}; - ll_ringbuffer_write_advance(ctx->AsyncEvents, 1); + ring->writeAdvance(1); ctx->EventSem.post(); if(ctx->EventThread.joinable()) -- cgit v1.2.3 From a4ac43b60294c5e21913c977942b19f174407d85 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 26 Dec 2018 21:55:39 -0800 Subject: Avoid a lambda to find a not-null entry in an array --- Alc/alu.cpp | 7 ++++--- OpenAL32/alSource.cpp | 9 +++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 1ebf3adc..e9d251fc 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include "alMain.h" #include "alcontext.h" @@ -53,6 +54,8 @@ namespace { +using namespace std::placeholders; + ALfloat InitConeScale() { ALfloat ret{1.0f}; @@ -1418,9 +1421,7 @@ void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) { auto buffers_end = BufferListItem->buffers+BufferListItem->num_buffers; auto buffer = std::find_if(BufferListItem->buffers, buffers_end, - [](const ALbuffer *buffer) noexcept -> bool - { return buffer != nullptr; } - ); + std::bind(std::not_equal_to{}, _1, nullptr)); if(LIKELY(buffer != buffers_end)) { if(voice->Props.mSpatializeMode==SpatializeOn || diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 03375e2d..6db7161a 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "AL/al.h" #include "AL/alc.h" @@ -49,6 +50,8 @@ namespace { +using namespace std::placeholders; + inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) { ALint idx{source->VoiceIdx}; @@ -465,7 +468,7 @@ ALsource *AllocSource(ALCcontext *context) return nullptr; } auto sublist = std::find_if(context->SourceList.begin(), context->SourceList.end(), - [](const SourceSubList &entry) -> bool + [](const SourceSubList &entry) noexcept -> bool { return entry.FreeMask != 0; } ); auto lidx = static_cast(std::distance(context->SourceList.begin(), sublist)); @@ -2812,9 +2815,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) auto buffers_end = BufferList->buffers + BufferList->num_buffers; auto buffer = std::find_if(BufferList->buffers, buffers_end, - [](const ALbuffer *buffer) noexcept -> bool - { return buffer != nullptr; } - ); + std::bind(std::not_equal_to{}, _1, nullptr)); if(buffer != buffers_end) { voice->NumChannels = ChannelsFromFmt((*buffer)->mFmtChannels); -- cgit v1.2.3 From d367093c0616e561a14ca1c486aff99cde98f4be Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 26 Dec 2018 22:27:34 -0800 Subject: Use std::array for appropriate source and listener properties --- Alc/alu.cpp | 10 +++--- OpenAL32/Include/alListener.h | 18 ++++++----- OpenAL32/Include/alSource.h | 13 +++++--- OpenAL32/Include/alu.h | 11 ++++--- OpenAL32/alListener.cpp | 55 ++++++++++++++------------------- OpenAL32/alSource.cpp | 71 ++++++++++++++++++++++--------------------- 6 files changed, 87 insertions(+), 91 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index e9d251fc..dfbd15a9 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -334,9 +334,9 @@ bool CalcListenerParams(ALCcontext *Context) if(!props) return false; /* AT then UP */ - alu::Vector N{props->Forward[0], props->Forward[1], props->Forward[2], 0.0f}; + alu::Vector N{props->OrientAt[0], props->OrientAt[1], props->OrientAt[2], 0.0f}; N.normalize(); - alu::Vector V{props->Up[0], props->Up[1], props->Up[2], 0.0f}; + alu::Vector V{props->OrientUp[0], props->OrientUp[1], props->OrientUp[2], 0.0f}; V.normalize(); /* Build and normalize right-vector */ alu::Vector U{aluCrossproduct(N, V)}; @@ -681,11 +681,9 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev * to the orientation. */ /* AT then UP */ - alu::Vector N{props->Orientation[0][0], props->Orientation[0][1], - props->Orientation[0][2], 0.0f}; + alu::Vector N{props->OrientAt[0], props->OrientAt[1], props->OrientAt[2], 0.0f}; N.normalize(); - alu::Vector V{props->Orientation[1][0], props->Orientation[1][1], - props->Orientation[1][2], 0.0f}; + alu::Vector V{props->OrientUp[0], props->OrientUp[1], props->OrientUp[2], 0.0f}; V.normalize(); if(!props->HeadRelative) { diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h index 490f1594..0aa28a46 100644 --- a/OpenAL32/Include/alListener.h +++ b/OpenAL32/Include/alListener.h @@ -1,6 +1,8 @@ #ifndef _AL_LISTENER_H_ #define _AL_LISTENER_H_ +#include + #include "AL/alc.h" #include "AL/al.h" #include "AL/alext.h" @@ -12,20 +14,20 @@ enum class DistanceModel; struct ALlistenerProps { - ALfloat Position[3]; - ALfloat Velocity[3]; - ALfloat Forward[3]; - ALfloat Up[3]; + std::array Position; + std::array Velocity; + std::array OrientAt; + std::array OrientUp; ALfloat Gain; std::atomic next; }; struct ALlistener { - ALfloat Position[3]{0.0f, 0.0f, 0.0f}; - ALfloat Velocity[3]{0.0f, 0.0f, 0.0f}; - ALfloat Forward[3]{0.0f, 0.0f, -1.0f}; - ALfloat Up[3]{0.0f, 1.0f, 0.0f}; + std::array Position{{0.0f, 0.0f, 0.0f}}; + std::array Velocity{{0.0f, 0.0f, 0.0f}}; + std::array OrientAt{{0.0f, 0.0f, -1.0f}}; + std::array OrientUp{{0.0f, 1.0f, 0.0f}}; ALfloat Gain{1.0f}; std::atomic_flag PropsClean{true}; diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 381e0a9b..ac17fc0d 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -1,6 +1,8 @@ #ifndef _AL_SOURCE_H_ #define _AL_SOURCE_H_ +#include + #include "alMain.h" #include "alu.h" #include "hrtf.h" @@ -34,10 +36,11 @@ struct ALsource { ALfloat RefDistance; ALfloat MaxDistance; ALfloat RolloffFactor; - ALfloat Position[3]; - ALfloat Velocity[3]; - ALfloat Direction[3]; - ALfloat Orientation[2][3]; + std::array Position; + std::array Velocity; + std::array Direction; + std::array OrientAt; + std::array OrientUp; ALboolean HeadRelative; ALboolean Looping; DistanceModel mDistanceModel; @@ -57,7 +60,7 @@ struct ALsource { /* NOTE: Stereo pan angles are specified in radians, counter-clockwise * rather than clockwise. */ - ALfloat StereoPan[2]; + std::array StereoPan; ALfloat Radius; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 775d34f6..7a378562 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -155,10 +155,11 @@ struct ALvoicePropsBase { ALfloat RefDistance; ALfloat MaxDistance; ALfloat RolloffFactor; - ALfloat Position[3]; - ALfloat Velocity[3]; - ALfloat Direction[3]; - ALfloat Orientation[2][3]; + std::array Position; + std::array Velocity; + std::array Direction; + std::array OrientAt; + std::array OrientUp; ALboolean HeadRelative; DistanceModel mDistanceModel; Resampler mResampler; @@ -174,7 +175,7 @@ struct ALvoicePropsBase { ALfloat RoomRolloffFactor; ALfloat DopplerFactor; - ALfloat StereoPan[2]; + std::array StereoPan; ALfloat Radius; diff --git a/OpenAL32/alListener.cpp b/OpenAL32/alListener.cpp index b7fdf9ce..7ed36f14 100644 --- a/OpenAL32/alListener.cpp +++ b/OpenAL32/alListener.cpp @@ -134,12 +134,12 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5]))) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener orientation out of range"); /* AT then UP */ - listener.Forward[0] = values[0]; - listener.Forward[1] = values[1]; - listener.Forward[2] = values[2]; - listener.Up[0] = values[3]; - listener.Up[1] = values[4]; - listener.Up[2] = values[5]; + listener.OrientAt[0] = values[0]; + listener.OrientAt[1] = values[1]; + listener.OrientAt[2] = values[2]; + listener.OrientUp[0] = values[3]; + listener.OrientUp[1] = values[4]; + listener.OrientUp[2] = values[5]; DO_UPDATEPROPS(); break; @@ -303,12 +303,12 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) { case AL_ORIENTATION: // AT then UP - values[0] = listener.Forward[0]; - values[1] = listener.Forward[1]; - values[2] = listener.Forward[2]; - values[3] = listener.Up[0]; - values[4] = listener.Up[1]; - values[5] = listener.Up[2]; + values[0] = listener.OrientAt[0]; + values[1] = listener.OrientAt[1]; + values[2] = listener.OrientAt[2]; + values[3] = listener.OrientUp[0]; + values[4] = listener.OrientUp[1]; + values[5] = listener.OrientUp[2]; break; default: @@ -383,12 +383,12 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) { case AL_ORIENTATION: // AT then UP - values[0] = (ALint)listener.Forward[0]; - values[1] = (ALint)listener.Forward[1]; - values[2] = (ALint)listener.Forward[2]; - values[3] = (ALint)listener.Up[0]; - values[4] = (ALint)listener.Up[1]; - values[5] = (ALint)listener.Up[2]; + values[0] = (ALint)listener.OrientAt[0]; + values[1] = (ALint)listener.OrientAt[1]; + values[2] = (ALint)listener.OrientAt[2]; + values[3] = (ALint)listener.OrientUp[0]; + values[4] = (ALint)listener.OrientUp[1]; + values[5] = (ALint)listener.OrientUp[2]; break; default: @@ -414,21 +414,10 @@ void UpdateListenerProps(ALCcontext *context) /* Copy in current property values. */ ALlistener &listener = context->Listener; - props->Position[0] = listener.Position[0]; - props->Position[1] = listener.Position[1]; - props->Position[2] = listener.Position[2]; - - props->Velocity[0] = listener.Velocity[0]; - props->Velocity[1] = listener.Velocity[1]; - props->Velocity[2] = listener.Velocity[2]; - - props->Forward[0] = listener.Forward[0]; - props->Forward[1] = listener.Forward[1]; - props->Forward[2] = listener.Forward[2]; - props->Up[0] = listener.Up[0]; - props->Up[1] = listener.Up[1]; - props->Up[2] = listener.Up[2]; - + props->Position = listener.Position; + props->Velocity = listener.Velocity; + props->OrientAt = listener.OrientAt; + props->OrientUp = listener.OrientUp; props->Gain = listener.Gain; /* Set the new container for updating internal parameters. */ diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 6db7161a..ac2979a5 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -66,7 +66,7 @@ inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) return nullptr; } -void UpdateSourceProps(ALsource *source, ALvoice *voice, ALCcontext *context) +void UpdateSourceProps(const ALsource *source, ALvoice *voice, ALCcontext *context) { /* Get an unused property container, or allocate a new one as needed. */ ALvoiceProps *props{context->FreeVoiceProps.load(std::memory_order_acquire)}; @@ -92,11 +92,11 @@ void UpdateSourceProps(ALsource *source, ALvoice *voice, ALCcontext *context) props->RefDistance = source->RefDistance; props->MaxDistance = source->MaxDistance; props->RolloffFactor = source->RolloffFactor; - std::copy(std::begin(source->Position), std::end(source->Position), props->Position); - std::copy(std::begin(source->Velocity), std::end(source->Velocity), props->Velocity); - std::copy(std::begin(source->Direction), std::end(source->Direction), props->Direction); - std::copy(std::begin(source->Orientation[0]), std::end(source->Orientation[0]), props->Orientation[0]); - std::copy(std::begin(source->Orientation[1]), std::end(source->Orientation[1]), props->Orientation[1]); + props->Position = source->Position; + props->Velocity = source->Velocity; + props->Direction = source->Direction; + props->OrientAt = source->OrientAt; + props->OrientUp = source->OrientUp; props->HeadRelative = source->HeadRelative; props->mDistanceModel = source->mDistanceModel; props->mResampler = source->mResampler; @@ -112,7 +112,7 @@ void UpdateSourceProps(ALsource *source, ALvoice *voice, ALCcontext *context) props->RoomRolloffFactor = source->RoomRolloffFactor; props->DopplerFactor = source->DopplerFactor; - std::copy(std::begin(source->StereoPan), std::end(source->StereoPan), props->StereoPan); + props->StereoPan = source->StereoPan; props->Radius = source->Radius; @@ -122,15 +122,18 @@ void UpdateSourceProps(ALsource *source, ALvoice *voice, ALCcontext *context) props->Direct.GainLF = source->Direct.GainLF; props->Direct.LFReference = source->Direct.LFReference; - for(size_t i{0u};i < source->Send.size();i++) + auto copy_send = [](const ALsource::SendData &srcsend) noexcept -> ALvoicePropsBase::SendData { - props->Send[i].Slot = source->Send[i].Slot; - props->Send[i].Gain = source->Send[i].Gain; - props->Send[i].GainHF = source->Send[i].GainHF; - props->Send[i].HFReference = source->Send[i].HFReference; - props->Send[i].GainLF = source->Send[i].GainLF; - props->Send[i].LFReference = source->Send[i].LFReference; - } + ALvoicePropsBase::SendData ret; + ret.Slot = srcsend.Slot; + ret.Gain = srcsend.Gain; + ret.GainHF = srcsend.GainHF; + ret.HFReference = srcsend.HFReference; + ret.GainLF = srcsend.GainLF; + ret.LFReference = srcsend.LFReference; + return ret; + }; + std::transform(source->Send.cbegin(), source->Send.cend(), props->Send, copy_send); /* Set the new container for updating internal parameters. */ props = voice->Update.exchange(props, std::memory_order_acq_rel); @@ -1157,12 +1160,12 @@ ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, co CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) && std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5])); - Source->Orientation[0][0] = values[0]; - Source->Orientation[0][1] = values[1]; - Source->Orientation[0][2] = values[2]; - Source->Orientation[1][0] = values[3]; - Source->Orientation[1][1] = values[4]; - Source->Orientation[1][2] = values[5]; + Source->OrientAt[0] = values[0]; + Source->OrientAt[1] = values[1]; + Source->OrientAt[2] = values[2]; + Source->OrientUp[0] = values[3]; + Source->OrientUp[1] = values[4]; + Source->OrientUp[2] = values[5]; DO_UPDATEPROPS(); return AL_TRUE; @@ -1763,12 +1766,12 @@ ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL return AL_TRUE; case AL_ORIENTATION: - values[0] = Source->Orientation[0][0]; - values[1] = Source->Orientation[0][1]; - values[2] = Source->Orientation[0][2]; - values[3] = Source->Orientation[1][0]; - values[4] = Source->Orientation[1][1]; - values[5] = Source->Orientation[1][2]; + values[0] = Source->OrientAt[0]; + values[1] = Source->OrientAt[1]; + values[2] = Source->OrientAt[2]; + values[3] = Source->OrientUp[0]; + values[4] = Source->OrientUp[1]; + values[5] = Source->OrientUp[2]; return AL_TRUE; /* 1x int */ @@ -3311,14 +3314,14 @@ ALsource::ALsource(ALsizei num_sends) Direction[0] = 0.0f; Direction[1] = 0.0f; Direction[2] = 0.0f; - Orientation[0][0] = 0.0f; - Orientation[0][1] = 0.0f; - Orientation[0][2] = -1.0f; - Orientation[1][0] = 0.0f; - Orientation[1][1] = 1.0f; - Orientation[1][2] = 0.0f; + OrientAt[0] = 0.0f; + OrientAt[1] = 0.0f; + OrientAt[2] = -1.0f; + OrientUp[0] = 0.0f; + OrientUp[1] = 1.0f; + OrientUp[2] = 0.0f; RefDistance = 1.0f; - MaxDistance = FLT_MAX; + MaxDistance = std::numeric_limits::max(); RolloffFactor = 1.0f; Gain = 1.0f; MinGain = 0.0f; -- cgit v1.2.3 From 7d821551ac32c6775d1f02a4631bd050aabcc254 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Dec 2018 01:18:10 -0800 Subject: Recognize ambix as an alias for acn+sn3d --- Alc/alc.cpp | 2 +- alsoftrc.sample | 4 ++-- utils/alsoft-config/mainwindow.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 294ba394..27475652 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -3806,7 +3806,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->mAmbiScale = AmbiNorm::FuMa; } } - else if(strcasecmp(fmt, "acn+sn3d") == 0) + else if(strcasecmp(fmt, "ambix") == 0 || strcasecmp(fmt, "acn+sn3d") == 0) { device->mAmbiLayout = AmbiLayout::ACN; device->mAmbiScale = AmbiNorm::SN3D; diff --git a/alsoftrc.sample b/alsoftrc.sample index f18899a0..1c1e113d 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -100,8 +100,8 @@ ## ambi-format: # Specifies the channel order and normalization for the "ambi*" set of channel -# configurations. Valid settings are: fuma, acn+sn3d, acn+n3d -#ambi-format = acn+sn3d +# configurations. Valid settings are: fuma, ambix (or acn+sn3d), acn+n3d +#ambi-format = ambix ## hrtf: # Controls HRTF processing. These filters provide better spatialization of diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 2b873955..449c91e5 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -119,8 +119,8 @@ static const struct NameValuePair { { "", "" } }, ambiFormatList[] = { { "Default", "" }, - { "ACN + SN3D", "acn+sn3d" }, - { "ACN + N3D", "acn+n3d" }, + { "AmbiX (ACN, SN3D)", "ambix" }, + { "ACN, N3D", "acn+n3d" }, { "Furse-Malham", "fuma" }, { "", "" } -- cgit v1.2.3 From c3f370fa413943c03e08f69101d964d4dde05d2a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Dec 2018 10:25:09 -0800 Subject: Constify and reorder a couple device fields --- OpenAL32/Include/alMain.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index bca4c49e..e5ad21ef 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -667,7 +667,7 @@ struct ALCdevice_struct { RefCount ref{1u}; std::atomic Connected{AL_TRUE}; - DeviceType Type{}; + const DeviceType Type{}; ALuint Frequency{}; ALuint UpdateSize{}; @@ -705,16 +705,16 @@ struct ALCdevice_struct { ALsizei NumAuxSends{}; // Map of Buffers for this device - al::vector BufferList; std::mutex BufferLock; + al::vector BufferList; // Map of Effects for this device - al::vector EffectList; std::mutex EffectLock; + al::vector EffectList; // Map of Filters for this device - al::vector FilterList; std::mutex FilterLock; + al::vector FilterList; /* Rendering mode. */ RenderMode mRenderMode{NormalRender}; -- cgit v1.2.3 From be85ab6f826a724105cef05e740b5013a1e6149e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Dec 2018 10:34:22 -0800 Subject: Rename some ALSA class members for consistency --- Alc/backends/alsa.cpp | 216 +++++++++++++++++++++++++------------------------- 1 file changed, 108 insertions(+), 108 deletions(-) diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index fd6981f8..c0ceb4f7 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -423,9 +423,9 @@ int verify_state(snd_pcm_t *handle) struct ALCplaybackAlsa final : public ALCbackend { - snd_pcm_t *PcmHandle{nullptr}; + snd_pcm_t *mPcmHandle{nullptr}; - al::vector Buffer; + al::vector mBuffer; std::atomic mKillNow{AL_TRUE}; std::thread mThread; @@ -458,9 +458,9 @@ void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device) void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self) { - if(self->PcmHandle) - snd_pcm_close(self->PcmHandle); - self->PcmHandle = nullptr; + if(self->mPcmHandle) + snd_pcm_close(self->mPcmHandle); + self->mPcmHandle = nullptr; ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCplaybackAlsa(); @@ -478,7 +478,7 @@ int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) snd_pcm_uframes_t num_updates{device->NumUpdates}; while(!self->mKillNow.load(std::memory_order_acquire)) { - int state{verify_state(self->PcmHandle)}; + int state{verify_state(self->mPcmHandle)}; if(state < 0) { ERR("Invalid state detected: %s\n", snd_strerror(state)); @@ -488,7 +488,7 @@ int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) break; } - snd_pcm_sframes_t avail{snd_pcm_avail_update(self->PcmHandle)}; + snd_pcm_sframes_t avail{snd_pcm_avail_update(self->mPcmHandle)}; if(avail < 0) { ERR("available update failed: %s\n", snd_strerror(avail)); @@ -498,7 +498,7 @@ int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) if((snd_pcm_uframes_t)avail > update_size*(num_updates+1)) { WARN("available samples exceeds the buffer size\n"); - snd_pcm_reset(self->PcmHandle); + snd_pcm_reset(self->mPcmHandle); continue; } @@ -507,14 +507,14 @@ int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) { if(state != SND_PCM_STATE_RUNNING) { - int err{snd_pcm_start(self->PcmHandle)}; + int err{snd_pcm_start(self->mPcmHandle)}; if(err < 0) { ERR("start failed: %s\n", snd_strerror(err)); continue; } } - if(snd_pcm_wait(self->PcmHandle, 1000) == 0) + if(snd_pcm_wait(self->mPcmHandle, 1000) == 0) ERR("Wait timeout... buffer size too low?\n"); continue; } @@ -528,7 +528,7 @@ int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) const snd_pcm_channel_area_t *areas{}; snd_pcm_uframes_t offset{}; - int err{snd_pcm_mmap_begin(self->PcmHandle, &areas, &offset, &frames)}; + int err{snd_pcm_mmap_begin(self->mPcmHandle, &areas, &offset, &frames)}; if(err < 0) { ERR("mmap begin error: %s\n", snd_strerror(err)); @@ -538,7 +538,7 @@ int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) char *WritePtr{(char*)areas->addr + (offset * areas->step / 8)}; aluMixData(device, WritePtr, frames); - snd_pcm_sframes_t commitres{snd_pcm_mmap_commit(self->PcmHandle, offset, frames)}; + snd_pcm_sframes_t commitres{snd_pcm_mmap_commit(self->mPcmHandle, offset, frames)}; if(commitres < 0 || (commitres-frames) != 0) { ERR("mmap commit error: %s\n", @@ -565,7 +565,7 @@ int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self) snd_pcm_uframes_t num_updates{device->NumUpdates}; while(!self->mKillNow.load(std::memory_order_acquire)) { - int state{verify_state(self->PcmHandle)}; + int state{verify_state(self->mPcmHandle)}; if(state < 0) { ERR("Invalid state detected: %s\n", snd_strerror(state)); @@ -575,7 +575,7 @@ int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self) break; } - snd_pcm_sframes_t avail{snd_pcm_avail_update(self->PcmHandle)}; + snd_pcm_sframes_t avail{snd_pcm_avail_update(self->mPcmHandle)}; if(avail < 0) { ERR("available update failed: %s\n", snd_strerror(avail)); @@ -585,7 +585,7 @@ int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self) if((snd_pcm_uframes_t)avail > update_size*num_updates) { WARN("available samples exceeds the buffer size\n"); - snd_pcm_reset(self->PcmHandle); + snd_pcm_reset(self->mPcmHandle); continue; } @@ -593,25 +593,25 @@ int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self) { if(state != SND_PCM_STATE_RUNNING) { - int err{snd_pcm_start(self->PcmHandle)}; + int err{snd_pcm_start(self->mPcmHandle)}; if(err < 0) { ERR("start failed: %s\n", snd_strerror(err)); continue; } } - if(snd_pcm_wait(self->PcmHandle, 1000) == 0) + if(snd_pcm_wait(self->mPcmHandle, 1000) == 0) ERR("Wait timeout... buffer size too low?\n"); continue; } ALCplaybackAlsa_lock(self); - char *WritePtr{self->Buffer.data()}; - avail = snd_pcm_bytes_to_frames(self->PcmHandle, self->Buffer.size()); + char *WritePtr{self->mBuffer.data()}; + avail = snd_pcm_bytes_to_frames(self->mPcmHandle, self->mBuffer.size()); aluMixData(device, WritePtr, avail); while(avail > 0) { - int ret = snd_pcm_writei(self->PcmHandle, WritePtr, avail); + int ret = snd_pcm_writei(self->mPcmHandle, WritePtr, avail); switch (ret) { case -EAGAIN: @@ -621,21 +621,21 @@ int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self) #endif case -EPIPE: case -EINTR: - ret = snd_pcm_recover(self->PcmHandle, ret, 1); + ret = snd_pcm_recover(self->mPcmHandle, ret, 1); if(ret < 0) avail = 0; break; default: if (ret >= 0) { - WritePtr += snd_pcm_frames_to_bytes(self->PcmHandle, ret); + WritePtr += snd_pcm_frames_to_bytes(self->mPcmHandle, ret); avail -= ret; } break; } if (ret < 0) { - ret = snd_pcm_prepare(self->PcmHandle); + ret = snd_pcm_prepare(self->mPcmHandle); if(ret < 0) break; } @@ -670,7 +670,7 @@ ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name) } TRACE("Opening device \"%s\"\n", driver); - int err{snd_pcm_open(&self->PcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)}; + int err{snd_pcm_open(&self->mPcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)}; if(err < 0) { ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(err)); @@ -730,15 +730,15 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) int dir, err; snd_pcm_hw_params_malloc(&hp); #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error - CHECK(snd_pcm_hw_params_any(self->PcmHandle, hp)); + CHECK(snd_pcm_hw_params_any(self->mPcmHandle, hp)); /* set interleaved access */ - if(!allowmmap || snd_pcm_hw_params_set_access(self->PcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) + if(!allowmmap || snd_pcm_hw_params_set_access(self->mPcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) { /* No mmap */ - CHECK(snd_pcm_hw_params_set_access(self->PcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); + CHECK(snd_pcm_hw_params_set_access(self->mPcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); } /* test and set format (implicitly sets sample bits) */ - if(snd_pcm_hw_params_test_format(self->PcmHandle, hp, format) < 0) + if(snd_pcm_hw_params_test_format(self->mPcmHandle, hp, format) < 0) { static const struct { snd_pcm_format_t format; @@ -756,16 +756,16 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) for(const auto &fmt : formatlist) { format = fmt.format; - if(snd_pcm_hw_params_test_format(self->PcmHandle, hp, format) >= 0) + if(snd_pcm_hw_params_test_format(self->mPcmHandle, hp, format) >= 0) { device->FmtType = fmt.fmttype; break; } } } - CHECK(snd_pcm_hw_params_set_format(self->PcmHandle, hp, format)); + CHECK(snd_pcm_hw_params_set_format(self->mPcmHandle, hp, format)); /* test and set channels (implicitly sets frame bits) */ - if(snd_pcm_hw_params_test_channels(self->PcmHandle, hp, device->channelsFromFmt()) < 0) + if(snd_pcm_hw_params_test_channels(self->mPcmHandle, hp, device->channelsFromFmt()) < 0) { static const DevFmtChannels channellist[] = { DevFmtStereo, @@ -777,7 +777,7 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) for(const auto &chan : channellist) { - if(snd_pcm_hw_params_test_channels(self->PcmHandle, hp, ChannelsFromDevFmt(chan, 0)) >= 0) + if(snd_pcm_hw_params_test_channels(self->mPcmHandle, hp, ChannelsFromDevFmt(chan, 0)) >= 0) { device->FmtChans = chan; device->mAmbiOrder = 0; @@ -785,25 +785,25 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) } } } - CHECK(snd_pcm_hw_params_set_channels(self->PcmHandle, hp, device->channelsFromFmt())); + CHECK(snd_pcm_hw_params_set_channels(self->mPcmHandle, hp, device->channelsFromFmt())); /* set rate (implicitly constrains period/buffer parameters) */ if(!GetConfigValueBool(device->DeviceName.c_str(), "alsa", "allow-resampler", 0) || !(device->Flags&DEVICE_FREQUENCY_REQUEST)) { - if(snd_pcm_hw_params_set_rate_resample(self->PcmHandle, hp, 0) < 0) + if(snd_pcm_hw_params_set_rate_resample(self->mPcmHandle, hp, 0) < 0) ERR("Failed to disable ALSA resampler\n"); } - else if(snd_pcm_hw_params_set_rate_resample(self->PcmHandle, hp, 1) < 0) + else if(snd_pcm_hw_params_set_rate_resample(self->mPcmHandle, hp, 1) < 0) ERR("Failed to enable ALSA resampler\n"); - CHECK(snd_pcm_hw_params_set_rate_near(self->PcmHandle, hp, &rate, nullptr)); + CHECK(snd_pcm_hw_params_set_rate_near(self->mPcmHandle, hp, &rate, nullptr)); /* set buffer time (implicitly constrains period/buffer parameters) */ - if((err=snd_pcm_hw_params_set_buffer_time_near(self->PcmHandle, hp, &bufferLen, nullptr)) < 0) + if((err=snd_pcm_hw_params_set_buffer_time_near(self->mPcmHandle, hp, &bufferLen, nullptr)) < 0) ERR("snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err)); /* set period time (implicitly sets buffer size/bytes/time and period size/bytes) */ - if((err=snd_pcm_hw_params_set_period_time_near(self->PcmHandle, hp, &periodLen, nullptr)) < 0) + if((err=snd_pcm_hw_params_set_period_time_near(self->mPcmHandle, hp, &periodLen, nullptr)) < 0) ERR("snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err)); /* install and prepare hardware configuration */ - CHECK(snd_pcm_hw_params(self->PcmHandle, hp)); + CHECK(snd_pcm_hw_params(self->mPcmHandle, hp)); /* retrieve configuration info */ CHECK(snd_pcm_hw_params_get_access(hp, &access)); @@ -815,10 +815,10 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) hp = nullptr; snd_pcm_sw_params_malloc(&sp); - CHECK(snd_pcm_sw_params_current(self->PcmHandle, sp)); - CHECK(snd_pcm_sw_params_set_avail_min(self->PcmHandle, sp, periodSizeInFrames)); - CHECK(snd_pcm_sw_params_set_stop_threshold(self->PcmHandle, sp, periodSizeInFrames*periods)); - CHECK(snd_pcm_sw_params(self->PcmHandle, sp)); + CHECK(snd_pcm_sw_params_current(self->mPcmHandle, sp)); + CHECK(snd_pcm_sw_params_set_avail_min(self->mPcmHandle, sp, periodSizeInFrames)); + CHECK(snd_pcm_sw_params_set_stop_threshold(self->mPcmHandle, sp, periodSizeInFrames*periods)); + CHECK(snd_pcm_sw_params(self->mPcmHandle, sp)); #undef CHECK snd_pcm_sw_params_free(sp); sp = nullptr; @@ -849,7 +849,7 @@ ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) snd_pcm_hw_params_malloc(&hp); #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error - CHECK(snd_pcm_hw_params_current(self->PcmHandle, hp)); + CHECK(snd_pcm_hw_params_current(self->mPcmHandle, hp)); /* retrieve configuration info */ CHECK(snd_pcm_hw_params_get_access(hp, &access)); #undef CHECK @@ -858,15 +858,15 @@ ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) if(access == SND_PCM_ACCESS_RW_INTERLEAVED) { - self->Buffer.resize(snd_pcm_frames_to_bytes(self->PcmHandle, device->UpdateSize)); + self->mBuffer.resize(snd_pcm_frames_to_bytes(self->mPcmHandle, device->UpdateSize)); thread_func = ALCplaybackAlsa_mixerNoMMapProc; } else { - err = snd_pcm_prepare(self->PcmHandle); + err = snd_pcm_prepare(self->mPcmHandle); if(err < 0) { - ERR("snd_pcm_prepare(data->PcmHandle) failed: %s\n", snd_strerror(err)); + ERR("snd_pcm_prepare(data->mPcmHandle) failed: %s\n", snd_strerror(err)); return ALC_FALSE; } thread_func = ALCplaybackAlsa_mixerProc; @@ -882,7 +882,7 @@ ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) } catch(...) { } - self->Buffer.clear(); + self->mBuffer.clear(); return ALC_FALSE; error: @@ -898,7 +898,7 @@ void ALCplaybackAlsa_stop(ALCplaybackAlsa *self) self->mThread.join(); - self->Buffer.clear(); + self->mBuffer.clear(); } ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self) @@ -909,7 +909,7 @@ ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self) ALCplaybackAlsa_lock(self); ret.ClockTime = GetDeviceClockTime(device); snd_pcm_sframes_t delay{}; - int err{snd_pcm_delay(self->PcmHandle, &delay)}; + int err{snd_pcm_delay(self->mPcmHandle, &delay)}; if(err < 0) { ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); @@ -924,12 +924,12 @@ ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self) struct ALCcaptureAlsa final : public ALCbackend { - snd_pcm_t *PcmHandle{nullptr}; + snd_pcm_t *mPcmHandle{nullptr}; - al::vector Buffer; + al::vector mBuffer; - bool DoCapture{false}; - RingBufferPtr Ring{nullptr}; + bool mDoCapture{false}; + RingBufferPtr mRing{nullptr}; snd_pcm_sframes_t mLastAvail{0}; }; @@ -959,9 +959,9 @@ void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device) void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self) { - if(self->PcmHandle) - snd_pcm_close(self->PcmHandle); - self->PcmHandle = nullptr; + if(self->mPcmHandle) + snd_pcm_close(self->mPcmHandle); + self->mPcmHandle = nullptr; ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCcaptureAlsa(); @@ -992,7 +992,7 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) } TRACE("Opening device \"%s\"\n", driver); - int err{snd_pcm_open(&self->PcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)}; + int err{snd_pcm_open(&self->mPcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)}; if(err < 0) { ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err)); @@ -1037,26 +1037,26 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) snd_pcm_hw_params_t *hp{}; snd_pcm_hw_params_malloc(&hp); #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error - CHECK(snd_pcm_hw_params_any(self->PcmHandle, hp)); + CHECK(snd_pcm_hw_params_any(self->mPcmHandle, hp)); /* set interleaved access */ - CHECK(snd_pcm_hw_params_set_access(self->PcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); + CHECK(snd_pcm_hw_params_set_access(self->mPcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); /* set format (implicitly sets sample bits) */ - CHECK(snd_pcm_hw_params_set_format(self->PcmHandle, hp, format)); + CHECK(snd_pcm_hw_params_set_format(self->mPcmHandle, hp, format)); /* set channels (implicitly sets frame bits) */ - CHECK(snd_pcm_hw_params_set_channels(self->PcmHandle, hp, device->channelsFromFmt())); + CHECK(snd_pcm_hw_params_set_channels(self->mPcmHandle, hp, device->channelsFromFmt())); /* set rate (implicitly constrains period/buffer parameters) */ - CHECK(snd_pcm_hw_params_set_rate(self->PcmHandle, hp, device->Frequency, 0)); + CHECK(snd_pcm_hw_params_set_rate(self->mPcmHandle, hp, device->Frequency, 0)); /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ - if(snd_pcm_hw_params_set_buffer_size_min(self->PcmHandle, hp, &bufferSizeInFrames) < 0) + if(snd_pcm_hw_params_set_buffer_size_min(self->mPcmHandle, hp, &bufferSizeInFrames) < 0) { TRACE("Buffer too large, using intermediate ring buffer\n"); needring = true; - CHECK(snd_pcm_hw_params_set_buffer_size_near(self->PcmHandle, hp, &bufferSizeInFrames)); + CHECK(snd_pcm_hw_params_set_buffer_size_near(self->mPcmHandle, hp, &bufferSizeInFrames)); } /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ - CHECK(snd_pcm_hw_params_set_period_size_near(self->PcmHandle, hp, &periodSizeInFrames, nullptr)); + CHECK(snd_pcm_hw_params_set_period_size_near(self->mPcmHandle, hp, &periodSizeInFrames, nullptr)); /* install and prepare hardware configuration */ - CHECK(snd_pcm_hw_params(self->PcmHandle, hp)); + CHECK(snd_pcm_hw_params(self->mPcmHandle, hp)); /* retrieve configuration info */ CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, nullptr)); #undef CHECK @@ -1065,9 +1065,9 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) if(needring) { - self->Ring.reset(ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, + self->mRing.reset(ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, device->frameSizeFromFmt(), false)); - if(!self->Ring) + if(!self->mRing) { ERR("ring buffer create failed\n"); goto error2; @@ -1083,21 +1083,21 @@ error: if(hp) snd_pcm_hw_params_free(hp); error2: - self->Ring = nullptr; - snd_pcm_close(self->PcmHandle); - self->PcmHandle = nullptr; + self->mRing = nullptr; + snd_pcm_close(self->mPcmHandle); + self->mPcmHandle = nullptr; return ALC_INVALID_VALUE; } ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self) { - int err{snd_pcm_prepare(self->PcmHandle)}; + int err{snd_pcm_prepare(self->mPcmHandle)}; if(err < 0) ERR("prepare failed: %s\n", snd_strerror(err)); else { - err = snd_pcm_start(self->PcmHandle); + err = snd_pcm_start(self->mPcmHandle); if(err < 0) ERR("start failed: %s\n", snd_strerror(err)); } @@ -1108,7 +1108,7 @@ ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self) return ALC_FALSE; } - self->DoCapture = true; + self->mDoCapture = true; return ALC_TRUE; } @@ -1118,27 +1118,27 @@ void ALCcaptureAlsa_stop(ALCcaptureAlsa *self) * snd_pcm_drain is unreliable and snd_pcm_drop drops it. Capture what's * available now so it'll be available later after the drop. */ ALCuint avail{ALCcaptureAlsa_availableSamples(self)}; - if(!self->Ring && avail > 0) + if(!self->mRing && avail > 0) { /* The ring buffer implicitly captures when checking availability. * Direct access needs to explicitly capture it into temp storage. */ - al::vector temp(snd_pcm_frames_to_bytes(self->PcmHandle, avail)); + al::vector temp(snd_pcm_frames_to_bytes(self->mPcmHandle, avail)); ALCcaptureAlsa_captureSamples(self, temp.data(), avail); - self->Buffer = std::move(temp); + self->mBuffer = std::move(temp); } - int err{snd_pcm_drop(self->PcmHandle)}; + int err{snd_pcm_drop(self->mPcmHandle)}; if(err < 0) ERR("drop failed: %s\n", snd_strerror(err)); - self->DoCapture = false; + self->mDoCapture = false; } ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALCuint samples) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - if(RingBuffer *ring{self->Ring.get()}) + if(RingBuffer *ring{self->mRing.get()}) { - ring->read(static_cast(buffer), samples); + ring->read(buffer, samples); return ALC_NO_ERROR; } @@ -1147,31 +1147,31 @@ ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALC { snd_pcm_sframes_t amt{0}; - if(!self->Buffer.empty()) + if(!self->mBuffer.empty()) { /* First get any data stored from the last stop */ - amt = snd_pcm_bytes_to_frames(self->PcmHandle, self->Buffer.size()); + amt = snd_pcm_bytes_to_frames(self->mPcmHandle, self->mBuffer.size()); if((snd_pcm_uframes_t)amt > samples) amt = samples; - amt = snd_pcm_frames_to_bytes(self->PcmHandle, amt); - memcpy(buffer, self->Buffer.data(), amt); + amt = snd_pcm_frames_to_bytes(self->mPcmHandle, amt); + memcpy(buffer, self->mBuffer.data(), amt); - self->Buffer.erase(self->Buffer.begin(), self->Buffer.begin()+amt); - amt = snd_pcm_bytes_to_frames(self->PcmHandle, amt); + self->mBuffer.erase(self->mBuffer.begin(), self->mBuffer.begin()+amt); + amt = snd_pcm_bytes_to_frames(self->mPcmHandle, amt); } - else if(self->DoCapture) - amt = snd_pcm_readi(self->PcmHandle, buffer, samples); + else if(self->mDoCapture) + amt = snd_pcm_readi(self->mPcmHandle, buffer, samples); if(amt < 0) { ERR("read error: %s\n", snd_strerror(amt)); if(amt == -EAGAIN) continue; - if((amt=snd_pcm_recover(self->PcmHandle, amt, 1)) >= 0) + if((amt=snd_pcm_recover(self->mPcmHandle, amt, 1)) >= 0) { - amt = snd_pcm_start(self->PcmHandle); + amt = snd_pcm_start(self->mPcmHandle); if(amt >= 0) - amt = snd_pcm_avail_update(self->PcmHandle); + amt = snd_pcm_avail_update(self->mPcmHandle); } if(amt < 0) { @@ -1191,7 +1191,7 @@ ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALC } if(samples > 0) memset(buffer, ((device->FmtType == DevFmtUByte) ? 0x80 : 0), - snd_pcm_frames_to_bytes(self->PcmHandle, samples)); + snd_pcm_frames_to_bytes(self->mPcmHandle, samples)); return ALC_NO_ERROR; } @@ -1201,18 +1201,18 @@ ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; snd_pcm_sframes_t avail{0}; - if(device->Connected.load(std::memory_order_acquire) && self->DoCapture) - avail = snd_pcm_avail_update(self->PcmHandle); + if(device->Connected.load(std::memory_order_acquire) && self->mDoCapture) + avail = snd_pcm_avail_update(self->mPcmHandle); if(avail < 0) { ERR("avail update failed: %s\n", snd_strerror(avail)); - if((avail=snd_pcm_recover(self->PcmHandle, avail, 1)) >= 0) + if((avail=snd_pcm_recover(self->mPcmHandle, avail, 1)) >= 0) { - if(self->DoCapture) - avail = snd_pcm_start(self->PcmHandle); + if(self->mDoCapture) + avail = snd_pcm_start(self->mPcmHandle); if(avail >= 0) - avail = snd_pcm_avail_update(self->PcmHandle); + avail = snd_pcm_avail_update(self->mPcmHandle); } if(avail < 0) { @@ -1221,11 +1221,11 @@ ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) } } - RingBuffer *ring{self->Ring.get()}; + RingBuffer *ring{self->mRing.get()}; if(!ring) { if(avail < 0) avail = 0; - avail += snd_pcm_bytes_to_frames(self->PcmHandle, self->Buffer.size()); + avail += snd_pcm_bytes_to_frames(self->mPcmHandle, self->mBuffer.size()); if(avail > self->mLastAvail) self->mLastAvail = avail; return self->mLastAvail; } @@ -1236,19 +1236,19 @@ ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) if(vec.first.len == 0) break; snd_pcm_sframes_t amt{std::min(vec.first.len, avail)}; - amt = snd_pcm_readi(self->PcmHandle, vec.first.buf, amt); + amt = snd_pcm_readi(self->mPcmHandle, vec.first.buf, amt); if(amt < 0) { ERR("read error: %s\n", snd_strerror(amt)); if(amt == -EAGAIN) continue; - if((amt=snd_pcm_recover(self->PcmHandle, amt, 1)) >= 0) + if((amt=snd_pcm_recover(self->mPcmHandle, amt, 1)) >= 0) { - if(self->DoCapture) - amt = snd_pcm_start(self->PcmHandle); + if(self->mDoCapture) + amt = snd_pcm_start(self->mPcmHandle); if(amt >= 0) - amt = snd_pcm_avail_update(self->PcmHandle); + amt = snd_pcm_avail_update(self->mPcmHandle); } if(amt < 0) { @@ -1275,7 +1275,7 @@ ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self) ALCcaptureAlsa_lock(self); ret.ClockTime = GetDeviceClockTime(device); snd_pcm_sframes_t delay{}; - int err{snd_pcm_delay(self->PcmHandle, &delay)}; + int err{snd_pcm_delay(self->mPcmHandle, &delay)}; if(err < 0) { ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); -- cgit v1.2.3 From 4dca2f2ee5ef488fbe05397de1ab3029e559cf61 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Dec 2018 10:44:02 -0800 Subject: Use a unique_ptr for the AsyncEvents ringbuffer --- Alc/alc.cpp | 5 +---- Alc/alcontext.h | 2 +- Alc/alu.cpp | 12 ++++++------ Alc/mixvoice.cpp | 8 ++++---- OpenAL32/alSource.cpp | 2 +- OpenAL32/event.cpp | 6 +++--- 6 files changed, 16 insertions(+), 19 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 27475652..9a93fbdc 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2369,7 +2369,7 @@ static ALvoid InitContext(ALCcontext *Context) listener.Params.mDistanceModel = Context->mDistanceModel; - Context->AsyncEvents = ll_ringbuffer_create(511, sizeof(AsyncEvent), false); + Context->AsyncEvents.reset(ll_ringbuffer_create(511, sizeof(AsyncEvent), false)); StartEventThrd(Context); } @@ -2484,9 +2484,6 @@ ALCcontext_struct::~ALCcontext_struct() if(count > 0) TRACE("Destructed " SZFMT " orphaned event%s\n", count, (count==1)?"":"s"); - delete AsyncEvents; - AsyncEvents = nullptr; - ALCdevice_DecRef(Device); } diff --git a/Alc/alcontext.h b/Alc/alcontext.h index dadb4f8f..f843809b 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -112,7 +112,7 @@ struct ALCcontext_struct { std::thread EventThread; al::semaphore EventSem; - RingBuffer *AsyncEvents{nullptr}; + std::unique_ptr AsyncEvents; std::atomic EnabledEvts{0u}; std::mutex EventCbLock; ALEVENTPROCSOFT EventCb{}; diff --git a/Alc/alu.cpp b/Alc/alu.cpp index dfbd15a9..672b571b 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -292,11 +292,11 @@ void SendSourceStoppedEvent(ALCcontext *context, ALuint id) ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)}; if(!(enabledevt&EventType_SourceStateChange)) return; - RingBuffer *ring{context->AsyncEvents}; - auto evt_data = ring->getWriteVector().first; - if(evt_data.len < 1) return; + RingBuffer *ring{context->AsyncEvents.get()}; + auto evt_vec = ring->getWriteVector(); + if(evt_vec.first.len < 1) return; - AsyncEvent *evt{new (evt_data.buf) AsyncEvent{EventType_SourceStateChange}}; + AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_SourceStateChange}}; evt->u.srcstate.id = id; evt->u.srcstate.state = AL_STOPPED; @@ -419,7 +419,7 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) /* Otherwise, if it would be deleted, send it off with a release * event. */ - RingBuffer *ring{context->AsyncEvents}; + RingBuffer *ring{context->AsyncEvents.get()}; auto evt_vec = ring->getWriteVector(); if(LIKELY(evt_vec.first.len > 0)) { @@ -1839,7 +1839,7 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) const ALbitfieldSOFT enabledevt{ctx->EnabledEvts.load(std::memory_order_acquire)}; if((enabledevt&EventType_Disconnected)) { - RingBuffer *ring{ctx->AsyncEvents}; + RingBuffer *ring{ctx->AsyncEvents.get()}; auto evt_data = ring->getWriteVector().first; if(evt_data.len > 0) { diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 48844219..53721201 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -736,11 +736,11 @@ ALboolean MixSource(ALvoice *voice, const ALuint SourceID, ALCcontext *Context, ALbitfieldSOFT enabledevt{Context->EnabledEvts.load(std::memory_order_acquire)}; if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) { - RingBuffer *ring{Context->AsyncEvents}; - auto evt_data = ring->getWriteVector().first; - if(evt_data.len > 0) + RingBuffer *ring{Context->AsyncEvents.get()}; + auto evt_vec = ring->getWriteVector(); + if(evt_vec.first.len > 0) { - AsyncEvent *evt{new (evt_data.buf) AsyncEvent{EventType_BufferCompleted}}; + AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_BufferCompleted}}; evt->u.bufcomp.id = SourceID; evt->u.bufcomp.count = buffers_done; ring->writeAdvance(1); diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index ac2979a5..98c79213 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -697,7 +697,7 @@ void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) * and we don't want state change messages to occur out of order, so send * it through the async queue to ensure proper ordering. */ - RingBuffer *ring{context->AsyncEvents}; + RingBuffer *ring{context->AsyncEvents.get()}; auto evt_vec = ring->getWriteVector(); if(evt_vec.first.len < 1) return; diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index f14c3229..f3474139 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -17,7 +17,7 @@ static int EventThread(ALCcontext *context) { - RingBuffer *ring{context->AsyncEvents}; + RingBuffer *ring{context->AsyncEvents.get()}; bool quitnow{false}; while(LIKELY(!quitnow)) { @@ -44,7 +44,7 @@ static int EventThread(ALCcontext *context) evt.~AsyncEvent(); ring->readAdvance(1); } - } _{evt, context->AsyncEvents}; + } _{evt, context->AsyncEvents.get()}; quitnow = evt.EnumType == EventType_KillThread; if(UNLIKELY(quitnow)) break; @@ -111,7 +111,7 @@ void StartEventThrd(ALCcontext *ctx) void StopEventThrd(ALCcontext *ctx) { static constexpr AsyncEvent kill_evt{EventType_KillThread}; - RingBuffer *ring{ctx->AsyncEvents}; + RingBuffer *ring{ctx->AsyncEvents.get()}; auto evt_data = ring->getWriteVector().first; if(evt_data.len == 0) { -- cgit v1.2.3 From 323cf58f02bd2a8a92006a5ee20014d2eb8ff3a9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Dec 2018 12:04:18 -0800 Subject: Simplify resampling with CoreAudio capture The ringbuffer holds the samples from the device, and we use our own converter for resampling, calling it on demand with data from the ring buffer. --- Alc/backends/coreaudio.cpp | 317 +++++++++++++++++++-------------------------- 1 file changed, 136 insertions(+), 181 deletions(-) diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index 808e7cb8..c0b6601b 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -29,6 +29,7 @@ #include "alMain.h" #include "alu.h" #include "ringbuffer.h" +#include "converter.h" #include #include @@ -39,10 +40,10 @@ static const ALCchar ca_device[] = "CoreAudio Default"; struct ALCcoreAudioPlayback final : public ALCbackend { - AudioUnit AudioUnit; + AudioUnit mAudioUnit; - ALuint FrameSize; - AudioStreamBasicDescription Format; // This is the OpenAL format as a CoreAudio ASBD + ALuint mFrameSize{0u}; + AudioStreamBasicDescription mFormat{}; // This is the OpenAL format as a CoreAudio ASBD }; static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device); @@ -66,15 +67,12 @@ static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice new (self) ALCcoreAudioPlayback{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCcoreAudioPlayback, ALCbackend, self); - - self->FrameSize = 0; - self->Format = AudioStreamBasicDescription{}; } static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self) { - AudioUnitUninitialize(self->AudioUnit); - AudioComponentInstanceDispose(self->AudioUnit); + AudioUnitUninitialize(self->mAudioUnit); + AudioComponentInstanceDispose(self->mAudioUnit); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCcoreAudioPlayback(); @@ -90,7 +88,7 @@ static OSStatus ALCcoreAudioPlayback_MixerProc(void *inRefCon, ALCcoreAudioPlayback_lock(self); aluMixData(device, ioData->mBuffers[0].mData, - ioData->mBuffers[0].mDataByteSize / self->FrameSize); + ioData->mBuffers[0].mDataByteSize / self->mFrameSize); ALCcoreAudioPlayback_unlock(self); return noErr; @@ -127,7 +125,7 @@ static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCch return ALC_INVALID_VALUE; } - err = AudioComponentInstanceNew(comp, &self->AudioUnit); + err = AudioComponentInstanceNew(comp, &self->mAudioUnit); if(err != noErr) { ERR("AudioComponentInstanceNew failed\n"); @@ -135,11 +133,11 @@ static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCch } /* init and start the default audio unit... */ - err = AudioUnitInitialize(self->AudioUnit); + err = AudioUnitInitialize(self->mAudioUnit); if(err != noErr) { ERR("AudioUnitInitialize failed\n"); - AudioComponentInstanceDispose(self->AudioUnit); + AudioComponentInstanceDispose(self->mAudioUnit); return ALC_INVALID_VALUE; } @@ -155,13 +153,14 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) OSStatus err; UInt32 size; - err = AudioUnitUninitialize(self->AudioUnit); + err = AudioUnitUninitialize(self->mAudioUnit); if(err != noErr) ERR("-- AudioUnitUninitialize failed.\n"); /* retrieve default output unit's properties (output side) */ size = sizeof(AudioStreamBasicDescription); - err = AudioUnitGetProperty(self->AudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, &size); + err = AudioUnitGetProperty(self->mAudioUnit, kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, 0, &streamFormat, &size); if(err != noErr || size != sizeof(AudioStreamBasicDescription)) { ERR("AudioUnitGetProperty failed\n"); @@ -179,7 +178,8 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) #endif /* set default output unit's input side to match output side */ - err = AudioUnitSetProperty(self->AudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, size); + err = AudioUnitSetProperty(self->mAudioUnit, kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, 0, &streamFormat, size); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -263,7 +263,8 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) streamFormat.mFormatFlags |= kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsPacked; - err = AudioUnitSetProperty(self->AudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription)); + err = AudioUnitSetProperty(self->mAudioUnit, kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -271,11 +272,12 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) } /* setup callback */ - self->FrameSize = device->frameSizeFromFmt(); + self->mFrameSize = device->frameSizeFromFmt(); input.inputProc = ALCcoreAudioPlayback_MixerProc; input.inputProcRefCon = self; - err = AudioUnitSetProperty(self->AudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct)); + err = AudioUnitSetProperty(self->mAudioUnit, kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -283,7 +285,7 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) } /* init the default audio unit... */ - err = AudioUnitInitialize(self->AudioUnit); + err = AudioUnitInitialize(self->mAudioUnit); if(err != noErr) { ERR("AudioUnitInitialize failed\n"); @@ -295,7 +297,7 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self) { - OSStatus err = AudioOutputUnitStart(self->AudioUnit); + OSStatus err = AudioOutputUnitStart(self->mAudioUnit); if(err != noErr) { ERR("AudioOutputUnitStart failed\n"); @@ -307,24 +309,21 @@ static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self) static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self) { - OSStatus err = AudioOutputUnitStop(self->AudioUnit); + OSStatus err = AudioOutputUnitStop(self->mAudioUnit); if(err != noErr) ERR("AudioOutputUnitStop failed\n"); } struct ALCcoreAudioCapture final : public ALCbackend { - AudioUnit AudioUnit; + AudioUnit mAudioUnit{0}; - ALuint FrameSize; - ALdouble SampleRateRatio; // Ratio of hardware sample rate / requested sample rate - AudioStreamBasicDescription Format; // This is the OpenAL format as a CoreAudio ASBD + ALuint mFrameSize{0u}; + AudioStreamBasicDescription mFormat{}; // This is the OpenAL format as a CoreAudio ASBD - AudioConverterRef AudioConverter; // Sample rate converter if needed - AudioBufferList *BufferList; // Buffer for data coming from the input device - ALCvoid *ResampleBuffer; // Buffer for returned RingBuffer data when resampling + std::unique_ptr mConverter; - RingBufferPtr Ring{nullptr}; + RingBufferPtr mRing{nullptr}; }; static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device); @@ -343,56 +342,18 @@ DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioCapture) DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioCapture); -static AudioBufferList *allocate_buffer_list(UInt32 channelCount, UInt32 byteSize) -{ - AudioBufferList *list; - - list = static_cast(calloc(1, - FAM_SIZE(AudioBufferList, mBuffers, 1) + byteSize)); - if(list) - { - list->mNumberBuffers = 1; - - list->mBuffers[0].mNumberChannels = channelCount; - list->mBuffers[0].mDataByteSize = byteSize; - list->mBuffers[0].mData = &list->mBuffers[1]; - } - return list; -} - -static void destroy_buffer_list(AudioBufferList *list) -{ - free(list); -} - - static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device) { new (self) ALCcoreAudioCapture{}; ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCcoreAudioCapture, ALCbackend, self); - - self->AudioUnit = 0; - self->AudioConverter = NULL; - self->BufferList = NULL; - self->ResampleBuffer = NULL; } static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self) { - free(self->ResampleBuffer); - self->ResampleBuffer = NULL; - - destroy_buffer_list(self->BufferList); - self->BufferList = NULL; - - if(self->AudioConverter) - AudioConverterDispose(self->AudioConverter); - self->AudioConverter = NULL; - - if(self->AudioUnit) - AudioComponentInstanceDispose(self->AudioUnit); - self->AudioUnit = 0; + if(self->mAudioUnit) + AudioComponentInstanceDispose(self->mAudioUnit); + self->mAudioUnit = 0; ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCcoreAudioCapture(); @@ -405,39 +366,47 @@ static OSStatus ALCcoreAudioCapture_RecordProc(void *inRefCon, UInt32 inNumberFrames, AudioBufferList* UNUSED(ioData)) { auto self = static_cast(inRefCon); - RingBuffer *ring{self->Ring.get()}; + RingBuffer *ring{self->mRing.get()}; AudioUnitRenderActionFlags flags = 0; + union { + ALbyte _[sizeof(AudioBufferList) + sizeof(AudioBuffer)]; + AudioBufferList list; + } audiobuf = { { 0 } }; OSStatus err; - // fill the BufferList with data from the input device - err = AudioUnitRender(self->AudioUnit, &flags, inTimeStamp, 1, inNumberFrames, self->BufferList); + auto rec_vec = ring->getWriteVector(); + + // Fill the ringbuffer's first segment with data from the input device + size_t total_read{minz(rec_vec.first.len, inNumberFrames)}; + audiobuf.list.mNumberBuffers = 1; + audiobuf.list.mBuffers[0].mNumberChannels = self->mFormat.mChannelsPerFrame; + audiobuf.list.mBuffers[0].mData = rec_vec.first.buf; + audiobuf.list.mBuffers[0].mDataByteSize = total_read * self->mFormat.mBytesPerFrame; + err = AudioUnitRender(self->mAudioUnit, &flags, inTimeStamp, 1, inNumberFrames, + &audiobuf.list); + if(err == noErr && inNumberFrames > rec_vec.first.len && rec_vec.second.len > 0) + { + /* If there's still more to get and there's space in the ringbuffer's + * second segment, fill that with data too. + */ + const size_t remlen{inNumberFrames - rec_vec.first.len}; + const size_t toread{minz(rec_vec.second.len, remlen)}; + total_read += toread; + + audiobuf.list.mNumberBuffers = 1; + audiobuf.list.mBuffers[0].mNumberChannels = self->mFormat.mChannelsPerFrame; + audiobuf.list.mBuffers[0].mData = rec_vec.second.buf; + audiobuf.list.mBuffers[0].mDataByteSize = toread * self->mFormat.mBytesPerFrame; + err = AudioUnitRender(self->mAudioUnit, &flags, inTimeStamp, 1, inNumberFrames, + &audiobuf.list); + } if(err != noErr) { ERR("AudioUnitRender error: %d\n", err); return err; } - ring->write(self->BufferList->mBuffers[0].mData, inNumberFrames); - return noErr; -} - -static OSStatus ALCcoreAudioCapture_ConvertCallback(AudioConverterRef UNUSED(inAudioConverter), - UInt32 *ioNumberDataPackets, AudioBufferList *ioData, - AudioStreamPacketDescription** UNUSED(outDataPacketDescription), - void *inUserData) -{ - auto self = reinterpret_cast(inUserData); - RingBuffer *ring{self->Ring.get()}; - - // Read from the ring buffer and store temporarily in a large buffer - ring->read(self->ResampleBuffer, *ioNumberDataPackets); - - // Set the input data - ioData->mNumberBuffers = 1; - ioData->mBuffers[0].mNumberChannels = self->Format.mChannelsPerFrame; - ioData->mBuffers[0].mData = self->ResampleBuffer; - ioData->mBuffers[0].mDataByteSize = (*ioNumberDataPackets) * self->Format.mBytesPerFrame; - + ring->writeAdvance(total_read); return noErr; } @@ -481,29 +450,31 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } // Open the component - err = AudioComponentInstanceNew(comp, &self->AudioUnit); + err = AudioComponentInstanceNew(comp, &self->mAudioUnit); if(err != noErr) { ERR("AudioComponentInstanceNew failed\n"); - goto error; + return ALC_INVALID_VALUE; } // Turn off AudioUnit output enableIO = 0; - err = AudioUnitSetProperty(self->AudioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint)); + err = AudioUnitSetProperty(self->mAudioUnit, kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); - goto error; + return ALC_INVALID_VALUE; } // Turn on AudioUnit input enableIO = 1; - err = AudioUnitSetProperty(self->AudioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint)); + err = AudioUnitSetProperty(self->mAudioUnit, kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); - goto error; + return ALC_INVALID_VALUE; } #if !TARGET_OS_IOS @@ -520,20 +491,21 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar if(err != noErr) { ERR("AudioObjectGetPropertyData failed\n"); - goto error; + return ALC_INVALID_VALUE; } if(inputDevice == kAudioDeviceUnknown) { ERR("No input device found\n"); - goto error; + return ALC_INVALID_VALUE; } // Track the input device - err = AudioUnitSetProperty(self->AudioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID)); + err = AudioUnitSetProperty(self->mAudioUnit, kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); - goto error; + return ALC_INVALID_VALUE; } } #endif @@ -542,28 +514,30 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar input.inputProc = ALCcoreAudioCapture_RecordProc; input.inputProcRefCon = self; - err = AudioUnitSetProperty(self->AudioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct)); + err = AudioUnitSetProperty(self->mAudioUnit, kAudioOutputUnitProperty_SetInputCallback, + kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); - goto error; + return ALC_INVALID_VALUE; } // Initialize the device - err = AudioUnitInitialize(self->AudioUnit); + err = AudioUnitInitialize(self->mAudioUnit); if(err != noErr) { ERR("AudioUnitInitialize failed\n"); - goto error; + return ALC_INVALID_VALUE; } // Get the hardware format propertySize = sizeof(AudioStreamBasicDescription); - err = AudioUnitGetProperty(self->AudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize); + err = AudioUnitGetProperty(self->mAudioUnit, kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize); if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription)) { ERR("AudioUnitGetProperty failed\n"); - goto error; + return ALC_INVALID_VALUE; } // Set up the requested format description @@ -589,7 +563,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar case DevFmtUShort: case DevFmtUInt: ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); - goto error; + return ALC_INVALID_VALUE; } switch(device->FmtChans) @@ -608,7 +582,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar case DevFmtX71: case DevFmtAmbi3D: ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans)); - goto error; + return ALC_INVALID_VALUE; } requestedFormat.mBytesPerFrame = requestedFormat.mChannelsPerFrame * requestedFormat.mBitsPerChannel / 8; @@ -619,80 +593,61 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar requestedFormat.mFramesPerPacket = 1; // save requested format description for later use - self->Format = requestedFormat; - self->FrameSize = device->frameSizeFromFmt(); + self->mFormat = requestedFormat; + self->mFrameSize = device->frameSizeFromFmt(); // Use intermediate format for sample rate conversion (outputFormat) // Set sample rate to the same as hardware for resampling later outputFormat = requestedFormat; outputFormat.mSampleRate = hardwareFormat.mSampleRate; - // Determine sample rate ratio for resampling - self->SampleRateRatio = outputFormat.mSampleRate / device->Frequency; - // The output format should be the requested format, but using the hardware sample rate // This is because the AudioUnit will automatically scale other properties, except for sample rate - err = AudioUnitSetProperty(self->AudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat)); + err = AudioUnitSetProperty(self->mAudioUnit, kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); - goto error; + return ALC_INVALID_VALUE; } // Set the AudioUnit output format frame count - outputFrameCount = device->UpdateSize * self->SampleRateRatio; - err = AudioUnitSetProperty(self->AudioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount)); - if(err != noErr) + ALuint64 FrameCount64{device->UpdateSize}; + FrameCount64 = (FrameCount64*outputFormat.mSampleRate + device->Frequency-1) / + device->Frequency; + FrameCount64 += MAX_RESAMPLE_PADDING*2; + if(FrameCount64 > std::numeric_limits::max()/2) { - ERR("AudioUnitSetProperty failed: %d\n", err); - goto error; + ERR("FrameCount too large\n"); + return ALC_INVALID_VALUE; } - // Set up sample converter - err = AudioConverterNew(&outputFormat, &requestedFormat, &self->AudioConverter); + outputFrameCount = static_cast(FrameCount64); + err = AudioUnitSetProperty(self->mAudioUnit, kAudioUnitProperty_MaximumFramesPerSlice, + kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount)); if(err != noErr) { - ERR("AudioConverterNew failed: %d\n", err); - goto error; + ERR("AudioUnitSetProperty failed: %d\n", err); + return ALC_INVALID_VALUE; } - // Create a buffer for use in the resample callback - self->ResampleBuffer = malloc(device->UpdateSize * self->FrameSize * self->SampleRateRatio); + // Set up sample converter if needed + if(outputFormat.mSampleRate != device->Frequency) + self->mConverter.reset(CreateSampleConverter(device->FmtType, device->FmtType, + self->mFormat.mChannelsPerFrame, hardwareFormat.mSampleRate, device->Frequency, + BSinc24Resampler)); - // Allocate buffer for the AudioUnit output - self->BufferList = allocate_buffer_list(outputFormat.mChannelsPerFrame, device->UpdateSize * self->FrameSize * self->SampleRateRatio); - if(self->BufferList == NULL) - goto error; - - self->Ring.reset(ll_ringbuffer_create( - (size_t)ceil(device->UpdateSize*self->SampleRateRatio*device->NumUpdates), - self->FrameSize, false)); - if(!self->Ring) goto error; + self->mRing.reset(ll_ringbuffer_create(outputFrameCount, self->mFrameSize, false)); + if(!self->mRing) return ALC_INVALID_VALUE; device->DeviceName = name; return ALC_NO_ERROR; - -error: - self->Ring = nullptr; - free(self->ResampleBuffer); - self->ResampleBuffer = NULL; - destroy_buffer_list(self->BufferList); - self->BufferList = NULL; - - if(self->AudioConverter) - AudioConverterDispose(self->AudioConverter); - self->AudioConverter = NULL; - if(self->AudioUnit) - AudioComponentInstanceDispose(self->AudioUnit); - self->AudioUnit = 0; - - return ALC_INVALID_VALUE; } static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self) { - OSStatus err = AudioOutputUnitStart(self->AudioUnit); + OSStatus err = AudioOutputUnitStart(self->mAudioUnit); if(err != noErr) { ERR("AudioOutputUnitStart failed\n"); @@ -703,46 +658,46 @@ static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self) static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self) { - OSStatus err = AudioOutputUnitStop(self->AudioUnit); + OSStatus err = AudioOutputUnitStop(self->mAudioUnit); if(err != noErr) ERR("AudioOutputUnitStop failed\n"); } static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples) { - union { - ALbyte _[sizeof(AudioBufferList) + sizeof(AudioBuffer)]; - AudioBufferList list; - } audiobuf = { { 0 } }; - UInt32 frameCount; - OSStatus err; + RingBuffer *ring{self->mRing.get()}; - // If no samples are requested, just return - if(samples == 0) return ALC_NO_ERROR; + if(!self->mConverter) + { + ring->read(buffer, samples); + return ALC_NO_ERROR; + } - // Point the resampling buffer to the capture buffer - audiobuf.list.mNumberBuffers = 1; - audiobuf.list.mBuffers[0].mNumberChannels = self->Format.mChannelsPerFrame; - audiobuf.list.mBuffers[0].mDataByteSize = samples * self->FrameSize; - audiobuf.list.mBuffers[0].mData = buffer; - - // Resample into another AudioBufferList - frameCount = samples; - err = AudioConverterFillComplexBuffer(self->AudioConverter, - ALCcoreAudioCapture_ConvertCallback, self, &frameCount, &audiobuf.list, NULL - ); - if(err != noErr) + auto rec_vec = ring->getReadVector(); + const void *src0{rec_vec.first.buf}; + auto src0len = static_cast(rec_vec.first.len); + auto got = static_cast(SampleConverterInput(self->mConverter.get(), &src0, &src0len, + buffer, samples)); + size_t total_read{rec_vec.first.len - src0len}; + if(got < samples && !src0len && rec_vec.second.len > 0) { - ERR("AudioConverterFillComplexBuffer error: %d\n", err); - return ALC_INVALID_VALUE; + const void *src1{rec_vec.second.buf}; + auto src1len = static_cast(rec_vec.second.len); + got += static_cast(SampleConverterInput(self->mConverter.get(), &src1, &src1len, + static_cast(buffer)+got, samples-got)); + total_read += rec_vec.second.len - src1len; } + + ring->readAdvance(total_read); return ALC_NO_ERROR; } static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self) { - RingBuffer *ring{self->Ring.get()}; - return ring->readSpace() / self->SampleRateRatio; + RingBuffer *ring{self->mRing.get()}; + + if(!self->mConverter) return ring->readSpace(); + return SampleConverterAvailableOut(self->mConverter.get(), ring->readSpace()); } -- cgit v1.2.3 From 1a4387d137acb57f69a2b5d073faf55d4a4c32ed Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Dec 2018 12:55:43 -0800 Subject: Return unique_ptrs instead of raw pointers For the ring buffer, channel converter, and sample converter. --- Alc/alc.cpp | 2 +- Alc/backends/alsa.cpp | 4 ++-- Alc/backends/coreaudio.cpp | 8 ++++---- Alc/backends/dsound.cpp | 4 ++-- Alc/backends/jack.cpp | 4 ++-- Alc/backends/opensl.cpp | 8 ++++---- Alc/backends/oss.cpp | 3 +-- Alc/backends/portaudio.cpp | 2 +- Alc/backends/sndio.cpp | 3 +-- Alc/backends/wasapi.cpp | 33 +++++++++++++-------------------- Alc/backends/winmm.cpp | 2 +- Alc/converter.cpp | 31 ++++++------------------------- Alc/converter.h | 14 +++++++++----- Alc/ringbuffer.cpp | 14 ++++++-------- Alc/ringbuffer.h | 6 ++---- 15 files changed, 55 insertions(+), 83 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 9a93fbdc..1b3692e2 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2369,7 +2369,7 @@ static ALvoid InitContext(ALCcontext *Context) listener.Params.mDistanceModel = Context->mDistanceModel; - Context->AsyncEvents.reset(ll_ringbuffer_create(511, sizeof(AsyncEvent), false)); + Context->AsyncEvents = CreateRingBuffer(511, sizeof(AsyncEvent), false); StartEventThrd(Context); } diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index c0ceb4f7..97b2e965 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -1065,8 +1065,8 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) if(needring) { - self->mRing.reset(ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, - device->frameSizeFromFmt(), false)); + self->mRing = CreateRingBuffer(device->UpdateSize*device->NumUpdates, + device->frameSizeFromFmt(), false); if(!self->mRing) { ERR("ring buffer create failed\n"); diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index c0b6601b..8f4a8d2a 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -321,7 +321,7 @@ struct ALCcoreAudioCapture final : public ALCbackend { ALuint mFrameSize{0u}; AudioStreamBasicDescription mFormat{}; // This is the OpenAL format as a CoreAudio ASBD - std::unique_ptr mConverter; + SampleConverterPtr mConverter; RingBufferPtr mRing{nullptr}; }; @@ -633,11 +633,11 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar // Set up sample converter if needed if(outputFormat.mSampleRate != device->Frequency) - self->mConverter.reset(CreateSampleConverter(device->FmtType, device->FmtType, + self->mConverter = CreateSampleConverter(device->FmtType, device->FmtType, self->mFormat.mChannelsPerFrame, hardwareFormat.mSampleRate, device->Frequency, - BSinc24Resampler)); + BSinc24Resampler); - self->mRing.reset(ll_ringbuffer_create(outputFrameCount, self->mFrameSize, false)); + self->mRing = CreateRingBuffer(outputFrameCount, self->mFrameSize, false); if(!self->mRing) return ALC_INVALID_VALUE; device->DeviceName = name; diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 516a7770..a1493fa8 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -835,8 +835,8 @@ ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) self->DSC->CreateCaptureBuffer(&DSCBDescription, &self->DSCbuffer, nullptr); if(SUCCEEDED(hr)) { - self->Ring.reset(ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, - InputType.Format.nBlockAlign, false)); + self->Ring = CreateRingBuffer(device->UpdateSize*device->NumUpdates, + InputType.Format.nBlockAlign, false); if(!self->Ring) hr = DSERR_OUTOFMEMORY; } diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index 02e29973..ca537323 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -222,7 +222,7 @@ int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg) TRACE("%u update size x%u\n", device->UpdateSize, device->NumUpdates); self->mRing = nullptr; - self->mRing.reset(ll_ringbuffer_create(bufsize, device->frameSizeFromFmt(), true)); + self->mRing = CreateRingBuffer(bufsize, device->frameSizeFromFmt(), true); if(!self->mRing) { ERR("Failed to reallocate ringbuffer\n"); @@ -431,7 +431,7 @@ ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) } self->mRing = nullptr; - self->mRing.reset(ll_ringbuffer_create(bufsize, device->frameSizeFromFmt(), true)); + self->mRing = CreateRingBuffer(bufsize, device->frameSizeFromFmt(), true); if(!self->mRing) { ERR("Failed to allocate ringbuffer\n"); diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 872fbc91..e1a0faa6 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -534,8 +534,8 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) } if(SL_RESULT_SUCCESS == result) { - self->mRing.reset(ll_ringbuffer_create(device->NumUpdates, - self->mFrameSize*device->UpdateSize, true)); + self->mRing = CreateRingBuffer(device->NumUpdates, + self->mFrameSize*device->UpdateSize, true); if(!self->mRing) { ERR("Out of memory allocating ring buffer %ux%u %u\n", device->UpdateSize, @@ -826,8 +826,8 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name if(SL_RESULT_SUCCESS == result) { - self->mRing.reset(ll_ringbuffer_create(device->NumUpdates, - device->UpdateSize*self->mFrameSize, false)); + self->mRing = CreateRingBuffer(device->NumUpdates, + device->UpdateSize*self->mFrameSize, false); result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index f6a75d12..ec9028eb 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -683,8 +683,7 @@ ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) return ALC_INVALID_VALUE; } - self->mRing.reset(ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, frameSize, - false)); + self->mRing = CreateRingBuffer(device->UpdateSize*device->NumUpdates, frameSize, false); if(!self->mRing) { ERR("Ring buffer create failed\n"); diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index f39661a7..354389c3 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -387,7 +387,7 @@ ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) samples = maxu(samples, 100 * device->Frequency / 1000); frame_size = device->frameSizeFromFmt(); - self->Ring.reset(ll_ringbuffer_create(samples, frame_size, false)); + self->Ring = CreateRingBuffer(samples, frame_size, false); if(!self->Ring) return ALC_INVALID_VALUE; self->Params.device = -1; diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index 887b5703..027ff9f2 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -465,8 +465,7 @@ static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) return ALC_INVALID_VALUE; } - self->ring.reset(ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, - par.bps*par.rchan, false)); + self->ring = CreateRingBuffer(device->UpdateSize*device->NumUpdates, par.bps*par.rchan, false); if(!self->ring) { ERR("Failed to allocate %u-byte ringbuffer\n", diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index e1783ef9..a7524ce1 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -1170,9 +1170,9 @@ struct ALCwasapiCapture final : public ALCbackend, WasapiProxy { HANDLE mMsgEvent{nullptr}; - ChannelConverter *mChannelConv{nullptr}; - SampleConverter *mSampleConv{nullptr}; - RingBufferPtr mRing{nullptr}; + ChannelConverterPtr mChannelConv; + SampleConverterPtr mSampleConv; + RingBufferPtr mRing; std::atomic mKillNow{AL_TRUE}; std::thread mThread; @@ -1220,9 +1220,6 @@ void ALCwasapiCapture_Destruct(ALCwasapiCapture *self) CloseHandle(self->mNotifyEvent); self->mNotifyEvent = nullptr; - DestroySampleConverter(&self->mSampleConv); - DestroyChannelConverter(&self->mChannelConv); - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCwasapiCapture(); } @@ -1266,35 +1263,31 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) ERR("Failed to get capture buffer: 0x%08lx\n", hr); else { - if(self->mChannelConv) + if(ChannelConverter *conv{self->mChannelConv.get()}) { samples.resize(numsamples*2); - ChannelConverterInput(self->mChannelConv, rdata, samples.data(), numsamples); + ChannelConverterInput(conv, rdata, samples.data(), numsamples); rdata = reinterpret_cast(samples.data()); } auto data = ring->getWriteVector(); size_t dstframes; - if(self->mSampleConv) + if(SampleConverter *conv{self->mSampleConv.get()}) { const ALvoid *srcdata = rdata; ALsizei srcframes = numsamples; - dstframes = SampleConverterInput(self->mSampleConv, - &srcdata, &srcframes, data.first.buf, - (ALsizei)minz(data.first.len, INT_MAX) - ); + dstframes = SampleConverterInput(conv, &srcdata, &srcframes, data.first.buf, + (ALsizei)minz(data.first.len, INT_MAX)); if(srcframes > 0 && dstframes == data.first.len && data.second.len > 0) { /* If some source samples remain, all of the first dest * block was filled, and there's space in the second * dest block, do another run for the second block. */ - dstframes += SampleConverterInput(self->mSampleConv, - &srcdata, &srcframes, data.second.buf, - (ALsizei)minz(data.second.len, INT_MAX) - ); + dstframes += SampleConverterInput(conv, &srcdata, &srcframes, + data.second.buf, (ALsizei)minz(data.second.len, INT_MAX)); } } else @@ -1576,8 +1569,8 @@ HRESULT ALCwasapiCapture::resetProxy() return hr; } - DestroySampleConverter(&mSampleConv); - DestroyChannelConverter(&mChannelConv); + mSampleConv = nullptr; + mChannelConv = nullptr; if(wfx != nullptr) { @@ -1694,7 +1687,7 @@ HRESULT ALCwasapiCapture::resetProxy() } buffer_len = maxu(device->UpdateSize*device->NumUpdates, buffer_len); - mRing.reset(ll_ringbuffer_create(buffer_len, device->frameSizeFromFmt(), false)); + mRing = CreateRingBuffer(buffer_len, device->frameSizeFromFmt(), false); if(!mRing) { ERR("Failed to allocate capture ring buffer\n"); diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 7bfb7f6c..485586f6 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -581,7 +581,7 @@ ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName) std::max(device->UpdateSize*device->NumUpdates, BufferSize*self->WaveBuffer.size()) ); - self->Ring.reset(ll_ringbuffer_create(CapturedDataSize, self->Format.nBlockAlign, false)); + self->Ring = CreateRingBuffer(CapturedDataSize, self->Format.nBlockAlign, false); if(!self->Ring) return ALC_INVALID_VALUE; al_free(self->WaveBuffer[0].lpData); diff --git a/Alc/converter.cpp b/Alc/converter.cpp index 66627879..52472bde 100644 --- a/Alc/converter.cpp +++ b/Alc/converter.cpp @@ -135,14 +135,14 @@ void Stereo2Mono(ALfloat *RESTRICT dst, const void *src, ALsizei frames) } // namespace -SampleConverter *CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, ALsizei numchans, - ALsizei srcRate, ALsizei dstRate, Resampler resampler) +SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, ALsizei numchans, + ALsizei srcRate, ALsizei dstRate, Resampler resampler) { if(numchans <= 0 || srcRate <= 0 || dstRate <= 0) return nullptr; - size_t alloc_size{FAM_SIZE(SampleConverter, Chan, numchans)}; - auto converter = new (al_calloc(16, alloc_size)) SampleConverter{}; + const size_t alloc_size{FAM_SIZE(SampleConverter, Chan, numchans)}; + SampleConverterPtr converter{new (al_calloc(16, alloc_size)) SampleConverter{}}; converter->mSrcType = srcType; converter->mDstType = dstType; converter->mNumChannels = numchans; @@ -171,16 +171,6 @@ SampleConverter *CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, A return converter; } -void DestroySampleConverter(SampleConverter **converter) -{ - if(converter) - { - delete *converter; - *converter = nullptr; - } -} - - ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframes) { ALint prepcount{converter->mSrcPrepCount}; @@ -339,22 +329,13 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs } -ChannelConverter *CreateChannelConverter(DevFmtType srcType, DevFmtChannels srcChans, DevFmtChannels dstChans) +ChannelConverterPtr CreateChannelConverter(DevFmtType srcType, DevFmtChannels srcChans, DevFmtChannels dstChans) { if(srcChans != dstChans && !((srcChans == DevFmtMono && dstChans == DevFmtStereo) || (srcChans == DevFmtStereo && dstChans == DevFmtMono))) return nullptr; - return new ChannelConverter{srcType, srcChans, dstChans}; -} - -void DestroyChannelConverter(ChannelConverter **converter) -{ - if(converter) - { - delete *converter; - *converter = nullptr; - } + return ChannelConverterPtr{new ChannelConverter{srcType, srcChans, dstChans}}; } void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALfloat *dst, ALsizei frames) diff --git a/Alc/converter.h b/Alc/converter.h index 1c473f49..6c76be07 100644 --- a/Alc/converter.h +++ b/Alc/converter.h @@ -1,6 +1,8 @@ #ifndef CONVERTER_H #define CONVERTER_H +#include + #include "alMain.h" #include "alu.h" #include "almalloc.h" @@ -28,10 +30,10 @@ struct SampleConverter { DEF_PLACE_NEWDEL() }; +using SampleConverterPtr = std::unique_ptr; -SampleConverter *CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, ALsizei numchans, +SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, ALsizei numchans, ALsizei srcRate, ALsizei dstRate, Resampler resampler); -void DestroySampleConverter(SampleConverter **converter); ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes); ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframes); @@ -47,10 +49,12 @@ struct ChannelConverter { { } DEF_NEWDEL(ChannelConverter) }; +using ChannelConverterPtr = std::unique_ptr; -ChannelConverter *CreateChannelConverter(DevFmtType srcType, DevFmtChannels srcChans, DevFmtChannels dstChans); -void DestroyChannelConverter(ChannelConverter **converter); +ChannelConverterPtr CreateChannelConverter(DevFmtType srcType, DevFmtChannels srcChans, + DevFmtChannels dstChans); -void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALfloat *dst, ALsizei frames); +void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALfloat *dst, + ALsizei frames); #endif /* CONVERTER_H */ diff --git a/Alc/ringbuffer.cpp b/Alc/ringbuffer.cpp index 9e531316..767db246 100644 --- a/Alc/ringbuffer.cpp +++ b/Alc/ringbuffer.cpp @@ -33,11 +33,9 @@ #include "compat.h" -RingBuffer *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes) +RingBufferPtr CreateRingBuffer(size_t sz, size_t elem_sz, int limit_writes) { - RingBuffer *rb; - size_t power_of_two = 0; - + size_t power_of_two{0u}; if(sz > 0) { power_of_two = sz; @@ -50,14 +48,14 @@ RingBuffer *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes) power_of_two |= power_of_two>>32; #endif } - power_of_two++; - if(power_of_two < sz) return NULL; - - rb = new (al_malloc(16, sizeof(*rb) + power_of_two*elem_sz)) RingBuffer{}; + ++power_of_two; + if(power_of_two < sz) return nullptr; + RingBufferPtr rb{new (al_malloc(16, sizeof(*rb) + power_of_two*elem_sz)) RingBuffer{}}; rb->mSize = limit_writes ? sz : power_of_two; rb->mSizeMask = power_of_two - 1; rb->mElemSize = elem_sz; + return rb; } diff --git a/Alc/ringbuffer.h b/Alc/ringbuffer.h index a2871859..317995b0 100644 --- a/Alc/ringbuffer.h +++ b/Alc/ringbuffer.h @@ -81,6 +81,7 @@ struct RingBuffer { DEF_PLACE_NEWDEL() }; +using RingBufferPtr = std::unique_ptr; /** @@ -88,9 +89,6 @@ struct RingBuffer { * The number of elements is rounded up to the next power of two (even if it is * already a power of two, to ensure the requested amount can be written). */ -RingBuffer *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes); - - -using RingBufferPtr = std::unique_ptr; +RingBufferPtr CreateRingBuffer(size_t sz, size_t elem_sz, int limit_writes); #endif /* RINGBUFFER_H */ -- cgit v1.2.3 From 7880f27054cd69cd1e36ebd3d20aa9d6148e3bbd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Dec 2018 13:07:14 -0800 Subject: Rename DSound class members for consistency --- Alc/backends/dsound.cpp | 190 ++++++++++++++++++++++++------------------------ 1 file changed, 95 insertions(+), 95 deletions(-) diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index a1493fa8..19fe8053 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -185,11 +185,11 @@ BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR* UNUS struct ALCdsoundPlayback final : public ALCbackend { - IDirectSound *DS{nullptr}; - IDirectSoundBuffer *PrimaryBuffer{nullptr}; - IDirectSoundBuffer *Buffer{nullptr}; - IDirectSoundNotify *Notifies{nullptr}; - HANDLE NotifyEvent{nullptr}; + IDirectSound *mDS{nullptr}; + IDirectSoundBuffer *mPrimaryBuffer{nullptr}; + IDirectSoundBuffer *mBuffer{nullptr}; + IDirectSoundNotify *mNotifies{nullptr}; + HANDLE mNotifyEvent{nullptr}; std::atomic mKillNow{AL_TRUE}; std::thread mThread; @@ -222,22 +222,22 @@ void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device) void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self) { - if(self->Notifies) - self->Notifies->Release(); - self->Notifies = nullptr; - if(self->Buffer) - self->Buffer->Release(); - self->Buffer = nullptr; - if(self->PrimaryBuffer) - self->PrimaryBuffer->Release(); - self->PrimaryBuffer = nullptr; - - if(self->DS) - self->DS->Release(); - self->DS = nullptr; - if(self->NotifyEvent) - CloseHandle(self->NotifyEvent); - self->NotifyEvent = nullptr; + if(self->mNotifies) + self->mNotifies->Release(); + self->mNotifies = nullptr; + if(self->mBuffer) + self->mBuffer->Release(); + self->mBuffer = nullptr; + if(self->mPrimaryBuffer) + self->mPrimaryBuffer->Release(); + self->mPrimaryBuffer = nullptr; + + if(self->mDS) + self->mDS->Release(); + self->mDS = nullptr; + if(self->mNotifyEvent) + CloseHandle(self->mNotifyEvent); + self->mNotifyEvent = nullptr; ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCdsoundPlayback(); @@ -251,7 +251,7 @@ FORCE_ALIGN int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - IDirectSoundBuffer *const Buffer{self->Buffer}; + IDirectSoundBuffer *const Buffer{self->mBuffer}; DSBCAPS DSBCaps{}; DSBCaps.dwSize = sizeof(DSBCaps); @@ -295,7 +295,7 @@ FORCE_ALIGN int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) Playing = true; } - avail = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE); + avail = WaitForSingleObjectEx(self->mNotifyEvent, 2000, FALSE); if(avail != WAIT_OBJECT_0) ERR("WaitForSingleObjectEx error: 0x%lx\n", avail); continue; @@ -384,14 +384,14 @@ ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *deviceNam } hr = DS_OK; - self->NotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - if(!self->NotifyEvent) hr = E_FAIL; + self->mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + if(!self->mNotifyEvent) hr = E_FAIL; //DirectSound Init code if(SUCCEEDED(hr)) - hr = DirectSoundCreate(guid, &self->DS, nullptr); + hr = DirectSoundCreate(guid, &self->mDS, nullptr); if(SUCCEEDED(hr)) - hr = self->DS->SetCooperativeLevel(GetForegroundWindow(), DSSCL_PRIORITY); + hr = self->mDS->SetCooperativeLevel(GetForegroundWindow(), DSSCL_PRIORITY); if(FAILED(hr)) { ERR("Device init failed: 0x%08lx\n", hr); @@ -406,15 +406,15 @@ ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - if(self->Notifies) - self->Notifies->Release(); - self->Notifies = nullptr; - if(self->Buffer) - self->Buffer->Release(); - self->Buffer = nullptr; - if(self->PrimaryBuffer) - self->PrimaryBuffer->Release(); - self->PrimaryBuffer = nullptr; + if(self->mNotifies) + self->mNotifies->Release(); + self->mNotifies = nullptr; + if(self->mBuffer) + self->mBuffer->Release(); + self->mBuffer = nullptr; + if(self->mPrimaryBuffer) + self->mPrimaryBuffer->Release(); + self->mPrimaryBuffer = nullptr; switch(device->FmtType) { @@ -439,7 +439,7 @@ ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) WAVEFORMATEXTENSIBLE OutputType{}; DWORD speakers; - HRESULT hr{self->DS->GetSpeakerConfig(&speakers)}; + HRESULT hr{self->mDS->GetSpeakerConfig(&speakers)}; if(SUCCEEDED(hr)) { speakers = DSSPEAKER_CONFIG(speakers); @@ -539,21 +539,21 @@ retry_open: else OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - if(self->PrimaryBuffer) - self->PrimaryBuffer->Release(); - self->PrimaryBuffer = nullptr; + if(self->mPrimaryBuffer) + self->mPrimaryBuffer->Release(); + self->mPrimaryBuffer = nullptr; } else { - if(SUCCEEDED(hr) && !self->PrimaryBuffer) + if(SUCCEEDED(hr) && !self->mPrimaryBuffer) { DSBUFFERDESC DSBDescription{}; DSBDescription.dwSize = sizeof(DSBDescription); DSBDescription.dwFlags = DSBCAPS_PRIMARYBUFFER; - hr = self->DS->CreateSoundBuffer(&DSBDescription, &self->PrimaryBuffer, nullptr); + hr = self->mDS->CreateSoundBuffer(&DSBDescription, &self->mPrimaryBuffer, nullptr); } if(SUCCEEDED(hr)) - hr = self->PrimaryBuffer->SetFormat(&OutputType.Format); + hr = self->mPrimaryBuffer->SetFormat(&OutputType.Format); } if(SUCCEEDED(hr)) @@ -573,7 +573,7 @@ retry_open: OutputType.Format.nBlockAlign; DSBDescription.lpwfxFormat = &OutputType.Format; - hr = self->DS->CreateSoundBuffer(&DSBDescription, &self->Buffer, nullptr); + hr = self->mDS->CreateSoundBuffer(&DSBDescription, &self->mBuffer, nullptr); if(FAILED(hr) && device->FmtType == DevFmtFloat) { device->FmtType = DevFmtShort; @@ -584,11 +584,11 @@ retry_open: if(SUCCEEDED(hr)) { void *ptr; - hr = self->Buffer->QueryInterface(IID_IDirectSoundNotify, &ptr); + hr = self->mBuffer->QueryInterface(IID_IDirectSoundNotify, &ptr); if(SUCCEEDED(hr)) { - auto Notifies = reinterpret_cast(ptr); - self->Notifies = Notifies; + auto Notifies = static_cast(ptr); + self->mNotifies = Notifies; device->NumUpdates = minu(device->NumUpdates, MAX_UPDATES); @@ -596,7 +596,7 @@ retry_open: for(ALuint i{0};i < device->NumUpdates;++i) { nots[i].dwOffset = i * device->UpdateSize * OutputType.Format.nBlockAlign; - nots[i].hEventNotify = self->NotifyEvent; + nots[i].hEventNotify = self->mNotifyEvent; } if(Notifies->SetNotificationPositions(device->NumUpdates, nots.data()) != DS_OK) hr = E_FAIL; @@ -605,19 +605,19 @@ retry_open: if(FAILED(hr)) { - if(self->Notifies) - self->Notifies->Release(); - self->Notifies = nullptr; - if(self->Buffer) - self->Buffer->Release(); - self->Buffer = nullptr; - if(self->PrimaryBuffer) - self->PrimaryBuffer->Release(); - self->PrimaryBuffer = nullptr; + if(self->mNotifies) + self->mNotifies->Release(); + self->mNotifies = nullptr; + if(self->mBuffer) + self->mBuffer->Release(); + self->mBuffer = nullptr; + if(self->mPrimaryBuffer) + self->mPrimaryBuffer->Release(); + self->mPrimaryBuffer = nullptr; return ALC_FALSE; } - ResetEvent(self->NotifyEvent); + ResetEvent(self->mNotifyEvent); SetDefaultWFXChannelOrder(device); return ALC_TRUE; @@ -645,17 +645,17 @@ void ALCdsoundPlayback_stop(ALCdsoundPlayback *self) self->mThread.join(); - self->Buffer->Stop(); + self->mBuffer->Stop(); } struct ALCdsoundCapture final : public ALCbackend { - IDirectSoundCapture *DSC{nullptr}; - IDirectSoundCaptureBuffer *DSCbuffer{nullptr}; - DWORD BufferBytes{0u}; - DWORD Cursor{0u}; + IDirectSoundCapture *mDSC{nullptr}; + IDirectSoundCaptureBuffer *mDSCbuffer{nullptr}; + DWORD mBufferBytes{0u}; + DWORD mCursor{0u}; - RingBufferPtr Ring{nullptr}; + RingBufferPtr mRing; }; void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device); @@ -681,16 +681,16 @@ void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device) void ALCdsoundCapture_Destruct(ALCdsoundCapture *self) { - if(self->DSCbuffer) + if(self->mDSCbuffer) { - self->DSCbuffer->Stop(); - self->DSCbuffer->Release(); - self->DSCbuffer = nullptr; + self->mDSCbuffer->Stop(); + self->mDSCbuffer->Release(); + self->mDSCbuffer = nullptr; } - if(self->DSC) - self->DSC->Release(); - self->DSC = nullptr; + if(self->mDSC) + self->mDSC->Release(); + self->mDSC = nullptr; ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCdsoundCapture(); @@ -830,32 +830,32 @@ ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) DSCBDescription.lpwfxFormat = &InputType.Format; //DirectSoundCapture Init code - hr = DirectSoundCaptureCreate(guid, &self->DSC, nullptr); + hr = DirectSoundCaptureCreate(guid, &self->mDSC, nullptr); if(SUCCEEDED(hr)) - self->DSC->CreateCaptureBuffer(&DSCBDescription, &self->DSCbuffer, nullptr); + self->mDSC->CreateCaptureBuffer(&DSCBDescription, &self->mDSCbuffer, nullptr); if(SUCCEEDED(hr)) { - self->Ring = CreateRingBuffer(device->UpdateSize*device->NumUpdates, + self->mRing = CreateRingBuffer(device->UpdateSize*device->NumUpdates, InputType.Format.nBlockAlign, false); - if(!self->Ring) hr = DSERR_OUTOFMEMORY; + if(!self->mRing) hr = DSERR_OUTOFMEMORY; } if(FAILED(hr)) { ERR("Device init failed: 0x%08lx\n", hr); - self->Ring = nullptr; - if(self->DSCbuffer) - self->DSCbuffer->Release(); - self->DSCbuffer = nullptr; - if(self->DSC) - self->DSC->Release(); - self->DSC = nullptr; + self->mRing = nullptr; + if(self->mDSCbuffer) + self->mDSCbuffer->Release(); + self->mDSCbuffer = nullptr; + if(self->mDSC) + self->mDSC->Release(); + self->mDSC = nullptr; return ALC_INVALID_VALUE; } - self->BufferBytes = DSCBDescription.dwBufferBytes; + self->mBufferBytes = DSCBDescription.dwBufferBytes; SetDefaultWFXChannelOrder(device); device->DeviceName = deviceName; @@ -864,7 +864,7 @@ ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self) { - HRESULT hr{self->DSCbuffer->Start(DSCBSTART_LOOPING)}; + HRESULT hr{self->mDSCbuffer->Start(DSCBSTART_LOOPING)}; if(FAILED(hr)) { ERR("start failed: 0x%08lx\n", hr); @@ -878,7 +878,7 @@ ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self) void ALCdsoundCapture_stop(ALCdsoundCapture *self) { - HRESULT hr{self->DSCbuffer->Stop()}; + HRESULT hr{self->mDSCbuffer->Stop()}; if(FAILED(hr)) { ERR("stop failed: 0x%08lx\n", hr); @@ -889,7 +889,7 @@ void ALCdsoundCapture_stop(ALCdsoundCapture *self) ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint samples) { - RingBuffer *ring{self->Ring.get()}; + RingBuffer *ring{self->mRing.get()}; ring->read(buffer, samples); return ALC_NO_ERROR; } @@ -897,33 +897,33 @@ ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) { ALCdevice *device{self->mDevice}; - RingBuffer *ring{self->Ring.get()}; + RingBuffer *ring{self->mRing.get()}; if(!device->Connected.load(std::memory_order_acquire)) return static_cast(ring->readSpace()); ALsizei FrameSize{device->frameSizeFromFmt()}; - DWORD BufferBytes{self->BufferBytes}; - DWORD LastCursor{self->Cursor}; + DWORD BufferBytes{self->mBufferBytes}; + DWORD LastCursor{self->mCursor}; DWORD ReadCursor; void *ReadPtr1, *ReadPtr2; DWORD ReadCnt1, ReadCnt2; - HRESULT hr{self->DSCbuffer->GetCurrentPosition(nullptr, &ReadCursor)}; + HRESULT hr{self->mDSCbuffer->GetCurrentPosition(nullptr, &ReadCursor)}; if(SUCCEEDED(hr)) { DWORD NumBytes{(ReadCursor-LastCursor + BufferBytes) % BufferBytes}; if(!NumBytes) return static_cast(ring->readSpace()); - hr = self->DSCbuffer->Lock(LastCursor, NumBytes, &ReadPtr1, &ReadCnt1, - &ReadPtr2, &ReadCnt2, 0); + hr = self->mDSCbuffer->Lock(LastCursor, NumBytes, &ReadPtr1, &ReadCnt1, + &ReadPtr2, &ReadCnt2, 0); } if(SUCCEEDED(hr)) { ring->write(ReadPtr1, ReadCnt1/FrameSize); - if(ReadPtr2 != nullptr) + if(ReadPtr2 != nullptr && ReadCnt2 > 0) ring->write(ReadPtr2, ReadCnt2/FrameSize); - hr = self->DSCbuffer->Unlock(ReadPtr1, ReadCnt1, ReadPtr2, ReadCnt2); - self->Cursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes; + hr = self->mDSCbuffer->Unlock(ReadPtr1, ReadCnt1, ReadPtr2, ReadCnt2); + self->mCursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes; } if(FAILED(hr)) -- cgit v1.2.3 From 4782d6107d250e3528c5e567dca48da727584ee7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Dec 2018 13:40:43 -0800 Subject: Use a proper constructor/destructor for the ALCbackend base --- Alc/backends/alsa.cpp | 12 ++++++------ Alc/backends/base.cpp | 11 ++++------- Alc/backends/base.h | 5 +++-- Alc/backends/coreaudio.cpp | 12 ++++++------ Alc/backends/dsound.cpp | 12 ++++++------ Alc/backends/jack.cpp | 6 +++--- Alc/backends/loopback.cpp | 5 ++--- Alc/backends/null.cpp | 6 +++--- Alc/backends/opensl.cpp | 12 ++++++------ Alc/backends/oss.cpp | 12 ++++++------ Alc/backends/portaudio.cpp | 12 ++++++------ Alc/backends/pulseaudio.cpp | 12 ++++++------ Alc/backends/qsa.cpp | 14 ++++++-------- Alc/backends/sdl2.cpp | 19 +++++++++---------- Alc/backends/sndio.cpp | 12 ++++++------ Alc/backends/solaris.cpp | 6 +++--- Alc/backends/wasapi.cpp | 12 ++++++------ Alc/backends/wave.cpp | 6 +++--- Alc/backends/winmm.cpp | 12 ++++++------ 19 files changed, 96 insertions(+), 102 deletions(-) diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index 97b2e965..2d0b3070 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -429,6 +429,8 @@ struct ALCplaybackAlsa final : public ALCbackend { std::atomic mKillNow{AL_TRUE}; std::thread mThread; + + ALCplaybackAlsa(ALCdevice *device) noexcept : ALCbackend{device} { } }; int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self); @@ -451,8 +453,7 @@ DEFINE_ALCBACKEND_VTABLE(ALCplaybackAlsa); void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device) { - new (self) ALCplaybackAlsa{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) ALCplaybackAlsa{device}; SET_VTABLE2(ALCplaybackAlsa, ALCbackend, self); } @@ -462,7 +463,6 @@ void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self) snd_pcm_close(self->mPcmHandle); self->mPcmHandle = nullptr; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCplaybackAlsa(); } @@ -932,6 +932,8 @@ struct ALCcaptureAlsa final : public ALCbackend { RingBufferPtr mRing{nullptr}; snd_pcm_sframes_t mLastAvail{0}; + + ALCcaptureAlsa(ALCdevice *device) noexcept : ALCbackend{device} { } }; void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device); @@ -952,8 +954,7 @@ DEFINE_ALCBACKEND_VTABLE(ALCcaptureAlsa); void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device) { - new (self) ALCcaptureAlsa{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) ALCcaptureAlsa{device}; SET_VTABLE2(ALCcaptureAlsa, ALCbackend, self); } @@ -963,7 +964,6 @@ void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self) snd_pcm_close(self->mPcmHandle); self->mPcmHandle = nullptr; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCcaptureAlsa(); } diff --git a/Alc/backends/base.cpp b/Alc/backends/base.cpp index 85f4b034..021a0f17 100644 --- a/Alc/backends/base.cpp +++ b/Alc/backends/base.cpp @@ -26,14 +26,11 @@ ClockLatency GetClockLatency(ALCdevice *device) /* Base ALCbackend method implementations. */ -void ALCbackend_Construct(ALCbackend *self, ALCdevice *device) -{ - self->mDevice = device; -} +ALCbackend::ALCbackend(ALCdevice *device) noexcept : mDevice{device} +{ } -void ALCbackend_Destruct(ALCbackend* UNUSED(self)) -{ -} +ALCbackend::~ALCbackend() +{ } ALCboolean ALCbackend_reset(ALCbackend* UNUSED(self)) { diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 15622967..aaa2b037 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -41,10 +41,11 @@ struct ALCbackend { ALCdevice *mDevice; std::recursive_mutex mMutex; + + ALCbackend(ALCdevice *device) noexcept; + virtual ~ALCbackend(); }; -void ALCbackend_Construct(ALCbackend *self, ALCdevice *device); -void ALCbackend_Destruct(ALCbackend *self); ALCboolean ALCbackend_reset(ALCbackend *self); ALCenum ALCbackend_captureSamples(ALCbackend *self, void *buffer, ALCuint samples); ALCuint ALCbackend_availableSamples(ALCbackend *self); diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index 8f4a8d2a..d0d0060c 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -44,6 +44,8 @@ struct ALCcoreAudioPlayback final : public ALCbackend { ALuint mFrameSize{0u}; AudioStreamBasicDescription mFormat{}; // This is the OpenAL format as a CoreAudio ASBD + + ALCcoreAudioPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } }; static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device); @@ -64,8 +66,7 @@ DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioPlayback); static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device) { - new (self) ALCcoreAudioPlayback{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) ALCcoreAudioPlayback{device}; SET_VTABLE2(ALCcoreAudioPlayback, ALCbackend, self); } @@ -74,7 +75,6 @@ static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self) AudioUnitUninitialize(self->mAudioUnit); AudioComponentInstanceDispose(self->mAudioUnit); - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCcoreAudioPlayback(); } @@ -324,6 +324,8 @@ struct ALCcoreAudioCapture final : public ALCbackend { SampleConverterPtr mConverter; RingBufferPtr mRing{nullptr}; + + ALCcoreAudioCapture(ALCdevice *device) noexcept : ALCbackend{device} { } }; static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device); @@ -344,8 +346,7 @@ DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioCapture); static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device) { - new (self) ALCcoreAudioCapture{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) ALCcoreAudioCapture{device}; SET_VTABLE2(ALCcoreAudioCapture, ALCbackend, self); } @@ -355,7 +356,6 @@ static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self) AudioComponentInstanceDispose(self->mAudioUnit); self->mAudioUnit = 0; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCcoreAudioCapture(); } diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 19fe8053..7bfe79df 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -193,6 +193,8 @@ struct ALCdsoundPlayback final : public ALCbackend { std::atomic mKillNow{AL_TRUE}; std::thread mThread; + + ALCdsoundPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } }; int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self); @@ -215,8 +217,7 @@ DEFINE_ALCBACKEND_VTABLE(ALCdsoundPlayback); void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device) { - new (self) ALCdsoundPlayback{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) ALCdsoundPlayback{device}; SET_VTABLE2(ALCdsoundPlayback, ALCbackend, self); } @@ -239,7 +240,6 @@ void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self) CloseHandle(self->mNotifyEvent); self->mNotifyEvent = nullptr; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCdsoundPlayback(); } @@ -656,6 +656,8 @@ struct ALCdsoundCapture final : public ALCbackend { DWORD mCursor{0u}; RingBufferPtr mRing; + + ALCdsoundCapture(ALCdevice *device) noexcept : ALCbackend{device} { } }; void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device); @@ -674,8 +676,7 @@ DEFINE_ALCBACKEND_VTABLE(ALCdsoundCapture); void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device) { - new (self) ALCdsoundCapture{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) ALCdsoundCapture{device}; SET_VTABLE2(ALCdsoundCapture, ALCbackend, self); } @@ -692,7 +693,6 @@ void ALCdsoundCapture_Destruct(ALCdsoundCapture *self) self->mDSC->Release(); self->mDSC = nullptr; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCdsoundCapture(); } diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index ca537323..059f9c96 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -157,6 +157,8 @@ struct ALCjackPlayback final : public ALCbackend { std::atomic mKillNow{true}; std::thread mThread; + + ALCjackPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } }; int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg); @@ -182,8 +184,7 @@ DEFINE_ALCBACKEND_VTABLE(ALCjackPlayback); void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device) { - new (self) ALCjackPlayback{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) ALCjackPlayback{device}; SET_VTABLE2(ALCjackPlayback, ALCbackend, self); } @@ -200,7 +201,6 @@ void ALCjackPlayback_Destruct(ALCjackPlayback *self) self->mClient = nullptr; } - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCjackPlayback(); } diff --git a/Alc/backends/loopback.cpp b/Alc/backends/loopback.cpp index 65c87971..9291ae77 100644 --- a/Alc/backends/loopback.cpp +++ b/Alc/backends/loopback.cpp @@ -29,6 +29,7 @@ namespace { struct ALCloopback final : public ALCbackend { + ALCloopback(ALCdevice *device) noexcept : ALCbackend{device} { } }; void ALCloopback_Construct(ALCloopback *self, ALCdevice *device); @@ -48,14 +49,12 @@ DEFINE_ALCBACKEND_VTABLE(ALCloopback); void ALCloopback_Construct(ALCloopback *self, ALCdevice *device) { - new (self) ALCloopback{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) ALCloopback{device}; SET_VTABLE2(ALCloopback, ALCbackend, self); } void ALCloopback_Destruct(ALCloopback *self) { - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCloopback(); } diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index fb113077..2b2a4b84 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -47,6 +47,8 @@ constexpr ALCchar nullDevice[] = "No Output"; struct ALCnullBackend final : public ALCbackend { std::atomic mKillNow{AL_TRUE}; std::thread mThread; + + ALCnullBackend(ALCdevice *device) noexcept : ALCbackend{device} { } }; int ALCnullBackend_mixerProc(ALCnullBackend *self); @@ -69,14 +71,12 @@ DEFINE_ALCBACKEND_VTABLE(ALCnullBackend); void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device) { - new (self) ALCnullBackend{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) ALCnullBackend{device}; SET_VTABLE2(ALCnullBackend, ALCbackend, self); } void ALCnullBackend_Destruct(ALCnullBackend *self) { - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCnullBackend(); } diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index e1a0faa6..3aa2d267 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -152,6 +152,8 @@ struct ALCopenslPlayback final : public ALCbackend { std::atomic mKillNow{AL_TRUE}; std::thread mThread; + + ALCopenslPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } }; static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf bq, void *context); @@ -175,8 +177,7 @@ DEFINE_ALCBACKEND_VTABLE(ALCopenslPlayback); static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *device) { - new (self) ALCopenslPlayback{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) ALCopenslPlayback{device}; SET_VTABLE2(ALCopenslPlayback, ALCbackend, self); } @@ -195,7 +196,6 @@ static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self) self->mEngineObj = NULL; self->mEngine = NULL; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCopenslPlayback(); } @@ -660,6 +660,8 @@ struct ALCopenslCapture final : public ALCbackend { ALCuint mSplOffset{0u}; ALsizei mFrameSize{0}; + + ALCopenslCapture(ALCdevice *device) noexcept : ALCbackend{device} { } }; static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf bq, void *context); @@ -681,8 +683,7 @@ DEFINE_ALCBACKEND_VTABLE(ALCopenslCapture); static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device) { - new (self) ALCopenslCapture{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) ALCopenslCapture{device}; SET_VTABLE2(ALCopenslCapture, ALCbackend, self); } @@ -697,7 +698,6 @@ static void ALCopenslCapture_Destruct(ALCopenslCapture *self) self->mEngineObj = NULL; self->mEngine = NULL; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCopenslCapture(); } diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index ec9028eb..73b62b30 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -248,6 +248,8 @@ struct ALCplaybackOSS final : public ALCbackend { std::atomic mKillNow{AL_TRUE}; std::thread mThread; + + ALCplaybackOSS(ALCdevice *device) noexcept : ALCbackend{device} { } }; int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self); @@ -269,8 +271,7 @@ DEFINE_ALCBACKEND_VTABLE(ALCplaybackOSS); void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device) { - new (self) ALCplaybackOSS{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) ALCplaybackOSS{device}; SET_VTABLE2(ALCplaybackOSS, ALCbackend, self); } @@ -280,7 +281,6 @@ void ALCplaybackOSS_Destruct(ALCplaybackOSS *self) close(self->fd); self->fd = -1; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCplaybackOSS(); } @@ -498,6 +498,8 @@ struct ALCcaptureOSS final : public ALCbackend { std::atomic mKillNow{AL_TRUE}; std::thread mThread; + + ALCcaptureOSS(ALCdevice *device) noexcept : ALCbackend{device} { } }; int ALCcaptureOSS_recordProc(ALCcaptureOSS *self); @@ -519,8 +521,7 @@ DEFINE_ALCBACKEND_VTABLE(ALCcaptureOSS); void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device) { - new (self) ALCcaptureOSS{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) ALCcaptureOSS{device}; SET_VTABLE2(ALCcaptureOSS, ALCbackend, self); } @@ -530,7 +531,6 @@ void ALCcaptureOSS_Destruct(ALCcaptureOSS *self) close(self->fd); self->fd = -1; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCcaptureOSS(); } diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index 354389c3..f49c0d2c 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -134,6 +134,8 @@ struct ALCportPlayback final : public ALCbackend { PaStream *Stream{nullptr}; PaStreamParameters Params; ALuint UpdateSize{0u}; + + ALCportPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } }; int ALCportPlayback_WriteCallback(const void *inputBuffer, void *outputBuffer, @@ -158,8 +160,7 @@ DEFINE_ALCBACKEND_VTABLE(ALCportPlayback); void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device) { - new (self) ALCportPlayback{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) ALCportPlayback{device}; SET_VTABLE2(ALCportPlayback, ALCbackend, self); } @@ -170,7 +171,6 @@ void ALCportPlayback_Destruct(ALCportPlayback *self) ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); self->Stream = nullptr; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCportPlayback(); } @@ -320,6 +320,8 @@ struct ALCportCapture final : public ALCbackend { PaStreamParameters Params; RingBufferPtr Ring{nullptr}; + + ALCportCapture(ALCdevice *device) noexcept : ALCbackend{device} { } }; int ALCportCapture_ReadCallback(const void *inputBuffer, void *outputBuffer, @@ -344,8 +346,7 @@ DEFINE_ALCBACKEND_VTABLE(ALCportCapture); void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device) { - new (self) ALCportCapture{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) ALCportCapture{device}; SET_VTABLE2(ALCportCapture, ALCbackend, self); } @@ -356,7 +357,6 @@ void ALCportCapture_Destruct(ALCportCapture *self) ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); self->Stream = nullptr; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCportCapture(); } diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 42fc267f..dc7f97b3 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -535,6 +535,8 @@ struct PulsePlayback final : public ALCbackend { ALuint mBufferSize{0u}; ALuint mFrameSize{0u}; + + PulsePlayback(ALCdevice *device) noexcept : ALCbackend{device} { } }; void PulsePlayback_deviceCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); @@ -570,8 +572,7 @@ DEFINE_ALCBACKEND_VTABLE(PulsePlayback); void PulsePlayback_Construct(PulsePlayback *self, ALCdevice *device) { - new (self) PulsePlayback(); - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) PulsePlayback{device}; SET_VTABLE2(PulsePlayback, ALCbackend, self); } @@ -584,7 +585,6 @@ void PulsePlayback_Destruct(PulsePlayback *self) self->context = nullptr; self->stream = nullptr; } - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~PulsePlayback(); } @@ -1182,6 +1182,8 @@ struct PulseCapture final : public ALCbackend { pa_stream *stream{nullptr}; pa_context *context{nullptr}; + + PulseCapture(ALCdevice *device) noexcept : ALCbackend{device} { } }; void PulseCapture_deviceCallback(pa_context *context, const pa_source_info *info, int eol, void *pdata); @@ -1214,8 +1216,7 @@ DEFINE_ALCBACKEND_VTABLE(PulseCapture); void PulseCapture_Construct(PulseCapture *self, ALCdevice *device) { - new (self) PulseCapture(); - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) PulseCapture{device}; SET_VTABLE2(PulseCapture, ALCbackend, self); } @@ -1228,7 +1229,6 @@ void PulseCapture_Destruct(PulseCapture *self) self->context = nullptr; self->stream = nullptr; } - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~PulseCapture(); } diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index f14718c0..ff74ff21 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -172,6 +172,8 @@ void deviceList(int type, al::vector *devmap) /* Wrappers to use an old-style backend with the new interface. */ struct PlaybackWrapper final : public ALCbackend { std::unique_ptr ExtraData; + + PlaybackWrapper(ALCdevice *device) noexcept : ALCbackend{device} { } }; static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device); @@ -613,11 +615,8 @@ static void qsa_stop_playback(PlaybackWrapper *self) static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device) { - new (self) PlaybackWrapper{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) PlaybackWrapper{device}; SET_VTABLE2(PlaybackWrapper, ALCbackend, self); - - self->ExtraData = NULL; } static void PlaybackWrapper_Destruct(PlaybackWrapper *self) @@ -625,7 +624,6 @@ static void PlaybackWrapper_Destruct(PlaybackWrapper *self) if(self->ExtraData) qsa_close_playback(self); - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~PlaybackWrapper(); } @@ -657,6 +655,8 @@ static void PlaybackWrapper_stop(PlaybackWrapper *self) struct CaptureWrapper final : public ALCbackend { std::unique_ptr ExtraData; + + CaptureWrapper(ALCdevice *device) noexcept : ALCbackend{device} { } }; static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device); @@ -916,8 +916,7 @@ static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuin static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device) { - new (self) CaptureWrapper{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) CaptureWrapper{device}; SET_VTABLE2(CaptureWrapper, ALCbackend, self); } @@ -926,7 +925,6 @@ static void CaptureWrapper_Destruct(CaptureWrapper *self) if(self->ExtraData) qsa_close_capture(self); - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~CaptureWrapper(); } diff --git a/Alc/backends/sdl2.cpp b/Alc/backends/sdl2.cpp index d61e0a1b..75052b0f 100644 --- a/Alc/backends/sdl2.cpp +++ b/Alc/backends/sdl2.cpp @@ -40,13 +40,15 @@ #endif struct ALCsdl2Backend final : public ALCbackend { - SDL_AudioDeviceID deviceID; - ALsizei frameSize; + SDL_AudioDeviceID deviceID{0u}; + ALsizei frameSize{0}; - ALuint Frequency; - DevFmtChannels FmtChans; - DevFmtType FmtType; - ALuint UpdateSize; + ALuint Frequency{0u}; + DevFmtChannels FmtChans{}; + DevFmtType FmtType{}; + ALuint UpdateSize{0u}; + + ALCsdl2Backend(ALCdevice *device) noexcept : ALCbackend{device} { } }; static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device); @@ -68,11 +70,9 @@ static const ALCchar defaultDeviceName[] = DEVNAME_PREFIX "Default Device"; static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device) { - new (self) ALCsdl2Backend{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) ALCsdl2Backend{device}; SET_VTABLE2(ALCsdl2Backend, ALCbackend, self); - self->deviceID = 0; self->frameSize = device->frameSizeFromFmt(); self->Frequency = device->Frequency; self->FmtChans = device->FmtChans; @@ -86,7 +86,6 @@ static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self) SDL_CloseAudioDevice(self->deviceID); self->deviceID = 0; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCsdl2Backend(); } diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index 027ff9f2..576e9ba9 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -47,6 +47,8 @@ struct SndioPlayback final : public ALCbackend { std::atomic mKillNow{AL_TRUE}; std::thread mThread; + + SndioPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } }; static int SndioPlayback_mixerProc(SndioPlayback *self); @@ -69,8 +71,7 @@ DEFINE_ALCBACKEND_VTABLE(SndioPlayback); static void SndioPlayback_Construct(SndioPlayback *self, ALCdevice *device) { - new (self) SndioPlayback{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) SndioPlayback{device}; SET_VTABLE2(SndioPlayback, ALCbackend, self); } @@ -83,7 +84,6 @@ static void SndioPlayback_Destruct(SndioPlayback *self) al_free(self->mix_data); self->mix_data = nullptr; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~SndioPlayback(); } @@ -283,6 +283,8 @@ struct SndioCapture final : public ALCbackend { std::atomic mKillNow{AL_TRUE}; std::thread mThread; + + SndioCapture(ALCdevice *device) noexcept : ALCbackend{device} { } }; static int SndioCapture_recordProc(SndioCapture *self); @@ -305,8 +307,7 @@ DEFINE_ALCBACKEND_VTABLE(SndioCapture); static void SndioCapture_Construct(SndioCapture *self, ALCdevice *device) { - new (self) SndioCapture{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) SndioCapture{device}; SET_VTABLE2(SndioCapture, ALCbackend, self); } @@ -316,7 +317,6 @@ static void SndioCapture_Destruct(SndioCapture *self) sio_close(self->sndHandle); self->sndHandle = nullptr; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~SndioCapture(); } diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index 41026de8..60db963b 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -54,6 +54,8 @@ struct ALCsolarisBackend final : public ALCbackend { std::atomic mKillNow{AL_TRUE}; std::thread mThread; + + ALCsolarisBackend(ALCdevice *device) noexcept : ALCbackend{device} { } }; static int ALCsolarisBackend_mixerProc(ALCsolarisBackend *self); @@ -81,8 +83,7 @@ static const char *solaris_driver = "/dev/audio"; static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *device) { - new (self) ALCsolarisBackend{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) ALCsolarisBackend{device}; SET_VTABLE2(ALCsolarisBackend, ALCbackend, self); } @@ -96,7 +97,6 @@ static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self) self->mix_data = nullptr; self->data_size = 0; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCsolarisBackend(); } diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index a7524ce1..c7a216eb 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -491,6 +491,8 @@ DWORD CALLBACK WasapiProxy_messageHandler(void *ptr) struct ALCwasapiPlayback final : public ALCbackend, WasapiProxy { + ALCwasapiPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } + HRESULT openProxy() override; void closeProxy() override; @@ -533,9 +535,8 @@ DEFINE_ALCBACKEND_VTABLE(ALCwasapiPlayback); void ALCwasapiPlayback_Construct(ALCwasapiPlayback *self, ALCdevice *device) { - new (self) ALCwasapiPlayback{}; + new (self) ALCwasapiPlayback{device}; SET_VTABLE2(ALCwasapiPlayback, ALCbackend, self); - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); } void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self) @@ -558,7 +559,6 @@ void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self) CloseHandle(self->mMsgEvent); self->mMsgEvent = nullptr; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCwasapiPlayback(); } @@ -1154,6 +1154,8 @@ ClockLatency ALCwasapiPlayback_getClockLatency(ALCwasapiPlayback *self) struct ALCwasapiCapture final : public ALCbackend, WasapiProxy { + ALCwasapiCapture(ALCdevice *device) noexcept : ALCbackend{device} { } + HRESULT openProxy() override; void closeProxy() override; @@ -1198,9 +1200,8 @@ DEFINE_ALCBACKEND_VTABLE(ALCwasapiCapture); void ALCwasapiCapture_Construct(ALCwasapiCapture *self, ALCdevice *device) { - new (self) ALCwasapiCapture{}; + new (self) ALCwasapiCapture{device}; SET_VTABLE2(ALCwasapiCapture, ALCbackend, self); - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); } void ALCwasapiCapture_Destruct(ALCwasapiCapture *self) @@ -1220,7 +1221,6 @@ void ALCwasapiCapture_Destruct(ALCwasapiCapture *self) CloseHandle(self->mNotifyEvent); self->mNotifyEvent = nullptr; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCwasapiCapture(); } diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index d40e93f0..3a65fc64 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -86,6 +86,8 @@ struct ALCwaveBackend final : public ALCbackend { std::atomic mKillNow{AL_TRUE}; std::thread mThread; + + ALCwaveBackend(ALCdevice *device) noexcept : ALCbackend{device} { } }; int ALCwaveBackend_mixerProc(ALCwaveBackend *self); @@ -108,8 +110,7 @@ DEFINE_ALCBACKEND_VTABLE(ALCwaveBackend); void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device) { - new (self) ALCwaveBackend{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) ALCwaveBackend{device}; SET_VTABLE2(ALCwaveBackend, ALCbackend, self); } @@ -119,7 +120,6 @@ void ALCwaveBackend_Destruct(ALCwaveBackend *self) fclose(self->mFile); self->mFile = nullptr; - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCwaveBackend(); } diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 485586f6..ab638cd4 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -132,6 +132,8 @@ struct ALCwinmmPlayback final : public ALCbackend { std::atomic mKillNow{AL_TRUE}; std::thread mThread; + + ALCwinmmPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } }; void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device); @@ -156,8 +158,7 @@ DEFINE_ALCBACKEND_VTABLE(ALCwinmmPlayback); void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device) { - new (self) ALCwinmmPlayback{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) ALCwinmmPlayback{device}; SET_VTABLE2(ALCwinmmPlayback, ALCbackend, self); std::fill(self->WaveBuffer.begin(), self->WaveBuffer.end(), WAVEHDR{}); @@ -172,7 +173,6 @@ void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self) al_free(self->WaveBuffer[0].lpData); std::fill(self->WaveBuffer.begin(), self->WaveBuffer.end(), WAVEHDR{}); - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCwinmmPlayback(); } @@ -407,6 +407,8 @@ struct ALCwinmmCapture final : public ALCbackend { std::atomic mKillNow{AL_TRUE}; std::thread mThread; + + ALCwinmmCapture(ALCdevice *device) noexcept : ALCbackend{device} { } }; void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device); @@ -431,8 +433,7 @@ DEFINE_ALCBACKEND_VTABLE(ALCwinmmCapture); void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device) { - new (self) ALCwinmmCapture{}; - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + new (self) ALCwinmmCapture{device}; SET_VTABLE2(ALCwinmmCapture, ALCbackend, self); std::fill(self->WaveBuffer.begin(), self->WaveBuffer.end(), WAVEHDR{}); @@ -448,7 +449,6 @@ void ALCwinmmCapture_Destruct(ALCwinmmCapture *self) al_free(self->WaveBuffer[0].lpData); std::fill(self->WaveBuffer.begin(), self->WaveBuffer.end(), WAVEHDR{}); - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); self->~ALCwinmmCapture(); } -- cgit v1.2.3 From f2c2b7c5383ddd999b56f28730258f270b0d2576 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Dec 2018 14:27:35 -0800 Subject: Get rid of the unnecessary STATIC_(UP)CAST macros --- Alc/backends/alsa.cpp | 29 ++++---- Alc/backends/base.h | 2 +- Alc/backends/coreaudio.cpp | 17 ++--- Alc/backends/dsound.cpp | 20 +++--- Alc/backends/jack.cpp | 5 +- Alc/backends/loopback.cpp | 7 +- Alc/backends/null.cpp | 11 ++- Alc/backends/opensl.cpp | 15 ++-- Alc/backends/oss.cpp | 16 ++--- Alc/backends/portaudio.cpp | 19 +++-- Alc/backends/pulseaudio.cpp | 48 ++++++------- Alc/backends/qsa.cpp | 20 +++--- Alc/backends/sdl2.cpp | 12 ++-- Alc/backends/sndio.cpp | 16 ++--- Alc/backends/solaris.cpp | 9 ++- Alc/backends/wasapi.cpp | 167 ++++++++++++++++++++------------------------ Alc/backends/wave.cpp | 9 ++- Alc/backends/winmm.cpp | 14 ++-- Alc/polymorphism.h | 40 +++-------- 19 files changed, 204 insertions(+), 272 deletions(-) diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index 2d0b3070..f0838d25 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -469,7 +469,7 @@ void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self) int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) { - ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + ALCdevice *device{self->mDevice}; SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); @@ -556,7 +556,7 @@ int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self) { - ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + ALCdevice *device{self->mDevice}; SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); @@ -680,7 +680,7 @@ 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(); - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device = self->mDevice; device->DeviceName = name; return ALC_NO_ERROR; @@ -688,7 +688,7 @@ ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name) ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) { - ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + ALCdevice *device{self->mDevice}; snd_pcm_format_t format{SND_PCM_FORMAT_UNKNOWN}; switch(device->FmtType) @@ -840,7 +840,7 @@ error: ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) { - ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + ALCdevice *device{self->mDevice}; int (*thread_func)(ALCplaybackAlsa*){}; snd_pcm_hw_params_t *hp{}; snd_pcm_access_t access; @@ -903,7 +903,7 @@ void ALCplaybackAlsa_stop(ALCplaybackAlsa *self) ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self) { - ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + ALCdevice *device{self->mDevice}; ClockLatency ret; ALCplaybackAlsa_lock(self); @@ -970,7 +970,7 @@ void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self) ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; const char *driver{}; if(name) { @@ -1103,8 +1103,7 @@ ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self) } if(err < 0) { - aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, "Capture state failure: %s", - snd_strerror(err)); + aluHandleDisconnect(self->mDevice, "Capture state failure: %s", snd_strerror(err)); return ALC_FALSE; } @@ -1134,7 +1133,7 @@ void ALCcaptureAlsa_stop(ALCcaptureAlsa *self) ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALCuint samples) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; if(RingBuffer *ring{self->mRing.get()}) { @@ -1198,7 +1197,7 @@ ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALC ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; snd_pcm_sframes_t avail{0}; if(device->Connected.load(std::memory_order_acquire) && self->mDoCapture) @@ -1269,7 +1268,7 @@ ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self) { - ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + ALCdevice *device{self->mDevice}; ClockLatency ret; ALCcaptureAlsa_lock(self); @@ -1338,15 +1337,13 @@ ALCbackend *AlsaBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type { ALCplaybackAlsa *backend; NEW_OBJ(backend, ALCplaybackAlsa)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } if(type == ALCbackend_Capture) { ALCcaptureAlsa *backend; NEW_OBJ(backend, ALCcaptureAlsa)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } return nullptr; diff --git a/Alc/backends/base.h b/Alc/backends/base.h index aaa2b037..4380540f 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -85,7 +85,7 @@ DECLARE_THUNK(T, ALCbackend, ClockLatency, getClockLatency) \ DECLARE_THUNK(T, ALCbackend, void, lock) \ DECLARE_THUNK(T, ALCbackend, void, unlock) \ static void T##_ALCbackend_Delete(void *ptr) \ -{ T##_Delete(STATIC_UPCAST(T, ALCbackend, (ALCbackend*)ptr)); } \ +{ T##_Delete(static_cast(static_cast(ptr))); } \ \ static const ALCbackendVtable T##_ALCbackend_vtable = { \ T##_ALCbackend_Destruct, \ diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index d0d0060c..62a88da1 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -83,11 +83,10 @@ static OSStatus ALCcoreAudioPlayback_MixerProc(void *inRefCon, AudioUnitRenderActionFlags* UNUSED(ioActionFlags), const AudioTimeStamp* UNUSED(inTimeStamp), UInt32 UNUSED(inBusNumber), UInt32 UNUSED(inNumberFrames), AudioBufferList *ioData) { - ALCcoreAudioPlayback *self = static_cast(inRefCon); - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + auto self = static_cast(inRefCon); ALCcoreAudioPlayback_lock(self); - aluMixData(device, ioData->mBuffers[0].mData, + aluMixData(self->mDevice, ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize / self->mFrameSize); ALCcoreAudioPlayback_unlock(self); @@ -97,7 +96,7 @@ static OSStatus ALCcoreAudioPlayback_MixerProc(void *inRefCon, static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name) { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCdevice *device{self->mDevice}; AudioComponentDescription desc; AudioComponent comp; OSStatus err; @@ -147,7 +146,7 @@ static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCch static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCdevice *device{self->mDevice}; AudioStreamBasicDescription streamFormat; AURenderCallbackStruct input; OSStatus err; @@ -413,7 +412,7 @@ static OSStatus ALCcoreAudioCapture_RecordProc(void *inRefCon, static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name) { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCdevice *device{self->mDevice}; AudioStreamBasicDescription requestedFormat; // The application requested format AudioStreamBasicDescription hardwareFormat; // The hardware format AudioStreamBasicDescription outputFormat; // The AudioUnit output format @@ -730,15 +729,13 @@ ALCbackend *CoreAudioBackendFactory::createBackend(ALCdevice *device, ALCbackend { ALCcoreAudioPlayback *backend; NEW_OBJ(backend, ALCcoreAudioPlayback)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } if(type == ALCbackend_Capture) { ALCcoreAudioCapture *backend; NEW_OBJ(backend, ALCcoreAudioCapture)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } return nullptr; diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 7bfe79df..421c3107 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -246,7 +246,7 @@ void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self) FORCE_ALIGN int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); @@ -352,7 +352,7 @@ FORCE_ALIGN int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *deviceName) { - ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + ALCdevice *device{self->mDevice}; HRESULT hr; if(PlaybackDevices.empty()) @@ -404,7 +404,7 @@ ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *deviceNam ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; if(self->mNotifies) self->mNotifies->Release(); @@ -699,7 +699,7 @@ void ALCdsoundCapture_Destruct(ALCdsoundCapture *self) ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; HRESULT hr; if(CaptureDevices.empty()) @@ -868,8 +868,7 @@ ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self) if(FAILED(hr)) { ERR("start failed: 0x%08lx\n", hr); - aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, - "Failure starting capture: 0x%lx", hr); + aluHandleDisconnect(self->mDevice, "Failure starting capture: 0x%lx", hr); return ALC_FALSE; } @@ -882,8 +881,7 @@ void ALCdsoundCapture_stop(ALCdsoundCapture *self) if(FAILED(hr)) { ERR("stop failed: 0x%08lx\n", hr); - aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, - "Failure stopping capture: 0x%lx", hr); + aluHandleDisconnect(self->mDevice, "Failure stopping capture: 0x%lx", hr); } } @@ -1003,16 +1001,14 @@ ALCbackend *DSoundBackendFactory::createBackend(ALCdevice *device, ALCbackend_Ty { ALCdsoundPlayback *backend; NEW_OBJ(backend, ALCdsoundPlayback)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } if(type == ALCbackend_Capture) { ALCdsoundCapture *backend; NEW_OBJ(backend, ALCdsoundCapture)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } return nullptr; diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index 059f9c96..37855fe3 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -208,7 +208,7 @@ void ALCjackPlayback_Destruct(ALCjackPlayback *self) int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg) { auto self = static_cast(arg); - ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; + ALCdevice *device{self->mDevice}; ALCjackPlayback_lock(self); device->UpdateSize = numframes; @@ -582,8 +582,7 @@ ALCbackend *JackBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type { ALCjackPlayback *backend; NEW_OBJ(backend, ALCjackPlayback)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } return nullptr; diff --git a/Alc/backends/loopback.cpp b/Alc/backends/loopback.cpp index 9291ae77..eadacdfb 100644 --- a/Alc/backends/loopback.cpp +++ b/Alc/backends/loopback.cpp @@ -61,7 +61,7 @@ void ALCloopback_Destruct(ALCloopback *self) ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; device->DeviceName = name; return ALC_NO_ERROR; @@ -69,7 +69,7 @@ ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name) ALCboolean ALCloopback_reset(ALCloopback *self) { - SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice); + SetDefaultWFXChannelOrder(self->mDevice); return ALC_TRUE; } @@ -100,8 +100,7 @@ ALCbackend *LoopbackBackendFactory::createBackend(ALCdevice *device, ALCbackend_ { ALCloopback *backend; NEW_OBJ(backend, ALCloopback)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } return nullptr; diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 2b2a4b84..7a4cf475 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -83,7 +83,7 @@ void ALCnullBackend_Destruct(ALCnullBackend *self) int ALCnullBackend_mixerProc(ALCnullBackend *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; const milliseconds restTime{device->UpdateSize*1000/device->Frequency / 2}; SetRTPriority(); @@ -130,14 +130,12 @@ int ALCnullBackend_mixerProc(ALCnullBackend *self) ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name) { - ALCdevice *device; - if(!name) name = nullDevice; else if(strcmp(name, nullDevice) != 0) return ALC_INVALID_VALUE; - device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; device->DeviceName = name; return ALC_NO_ERROR; @@ -145,7 +143,7 @@ ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name) ALCboolean ALCnullBackend_reset(ALCnullBackend *self) { - SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice); + SetDefaultWFXChannelOrder(self->mDevice); return ALC_TRUE; } @@ -199,8 +197,7 @@ ALCbackend *NullBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type { ALCnullBackend *backend; NEW_OBJ(backend, ALCnullBackend)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); + return backend; } return NULL; diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 3aa2d267..0853e32f 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -313,7 +313,7 @@ static int ALCopenslPlayback_mixerProc(ALCopenslPlayback *self) static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name) { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCdevice *device{self->mDevice}; SLresult result; if(!name) @@ -365,7 +365,7 @@ static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *na static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCdevice *device{self->mDevice}; SLDataLocator_AndroidSimpleBufferQueue loc_bufq; SLDataLocator_OutputMix loc_outmix; SLDataSource audioSrc; @@ -713,7 +713,7 @@ static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), v static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; SLDataLocator_AndroidSimpleBufferQueue loc_bq; SLAndroidSimpleBufferQueueItf bufferQueue; SLDataLocator_IODevice loc_dev; @@ -892,8 +892,7 @@ static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self) if(SL_RESULT_SUCCESS != result) { ALCopenslCapture_lock(self); - aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, - "Failed to start capture: 0x%08x", result); + aluHandleDisconnect(self->mDevice, "Failed to start capture: 0x%08x", result); ALCopenslCapture_unlock(self); return ALC_FALSE; } @@ -1003,15 +1002,13 @@ ALCbackend *OSLBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type { ALCopenslPlayback *backend; NEW_OBJ(backend, ALCopenslPlayback)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } if(type == ALCbackend_Capture) { ALCopenslCapture *backend; NEW_OBJ(backend, ALCopenslCapture)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } return nullptr; diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 73b62b30..e5630ad3 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -287,7 +287,7 @@ void ALCplaybackOSS_Destruct(ALCplaybackOSS *self) int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self) { - ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + ALCdevice *device{self->mDevice}; SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); @@ -347,7 +347,7 @@ int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self) ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; const char *devname{DefaultPlayback}; if(!name) @@ -379,7 +379,7 @@ ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; int numFragmentsLogSize; int log2FragmentSize; unsigned int periods; @@ -461,7 +461,7 @@ ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; try { self->mMixData.resize(device->UpdateSize * device->frameSizeFromFmt()); @@ -587,7 +587,7 @@ int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; const char *devname{DefaultCapture}; if(!name) @@ -797,15 +797,13 @@ ALCbackend *OSSBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type { ALCplaybackOSS *backend; NEW_OBJ(backend, ALCplaybackOSS)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } if(type == ALCbackend_Capture) { ALCcaptureOSS *backend; NEW_OBJ(backend, ALCcaptureOSS)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } return nullptr; diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index f49c0d2c..7c0569c2 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -179,10 +179,10 @@ int ALCportPlayback_WriteCallback(const void *UNUSED(inputBuffer), void *outputB unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo), const PaStreamCallbackFlags UNUSED(statusFlags), void *userData) { - ALCportPlayback *self = static_cast(userData); + auto self = static_cast(userData); ALCportPlayback_lock(self); - aluMixData(STATIC_CAST(ALCbackend, self)->mDevice, outputBuffer, framesPerBuffer); + aluMixData(self->mDevice, outputBuffer, framesPerBuffer); ALCportPlayback_unlock(self); return 0; } @@ -190,7 +190,7 @@ int ALCportPlayback_WriteCallback(const void *UNUSED(inputBuffer), void *outputB ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; PaError err; if(!name) @@ -256,10 +256,9 @@ retry_open: ALCboolean ALCportPlayback_reset(ALCportPlayback *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - const PaStreamInfo *streamInfo; + ALCdevice *device{self->mDevice}; - streamInfo = Pa_GetStreamInfo(self->Stream); + const PaStreamInfo *streamInfo{Pa_GetStreamInfo(self->Stream)}; device->Frequency = streamInfo->sampleRate; device->UpdateSize = self->UpdateSize; @@ -374,7 +373,7 @@ int ALCportCapture_ReadCallback(const void *inputBuffer, void *UNUSED(outputBuff ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; ALuint samples, frame_size; PaError err; @@ -509,15 +508,13 @@ ALCbackend *PortBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type { ALCportPlayback *backend; NEW_OBJ(backend, ALCportPlayback)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } if(type == ALCbackend_Capture) { ALCportCapture *backend; NEW_OBJ(backend, ALCportCapture)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } return nullptr; diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index dc7f97b3..23685178 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -697,7 +697,7 @@ void PulsePlayback_contextStateCallback(pa_context *context, void *pdata) if(pa_context_get_state(context) == PA_CONTEXT_FAILED) { ERR("Received context failure!\n"); - aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice, "Playback state failure"); + aluHandleDisconnect(self->mDevice, "Playback state failure"); } pa_threaded_mainloop_signal(self->loop, 0); } @@ -708,7 +708,7 @@ void PulsePlayback_streamStateCallback(pa_stream *stream, void *pdata) if(pa_stream_get_state(stream) == PA_STREAM_FAILED) { ERR("Received stream failure!\n"); - aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice, "Playback stream failure"); + aluHandleDisconnect(self->mDevice, "Playback stream failure"); } pa_threaded_mainloop_signal(self->loop, 0); } @@ -769,7 +769,7 @@ void PulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa_sink_i } } }, { DevFmtMono, { 1, {PA_CHANNEL_POSITION_MONO} } } }}; - auto self = reinterpret_cast(pdata); + auto self = static_cast(pdata); if(eol) { @@ -777,7 +777,7 @@ void PulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa_sink_i return; } - ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; + ALCdevice *device{self->mDevice}; auto chanmap = std::find_if(chanmaps.cbegin(), chanmaps.cend(), [info](const ChannelMap &chanmap) -> bool { return pa_channel_map_superset(&info->channel_map, &chanmap.map); } @@ -803,7 +803,7 @@ void PulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa_sink_i void PulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) { - auto self = reinterpret_cast(pdata); + auto self = static_cast(pdata); if(eol) { @@ -811,14 +811,14 @@ void PulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const pa_sink_i return; } - ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; + ALCdevice *device{self->mDevice}; device->DeviceName = info->description; } void PulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata) { - auto self = reinterpret_cast(pdata); + auto self = static_cast(pdata); self->device_name = pa_stream_get_device_name(stream); @@ -932,7 +932,7 @@ ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) } else { - ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; + ALCdevice *device{self->mDevice}; device->DeviceName = dev_name; } @@ -958,7 +958,7 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) self->device_name.c_str(), PulsePlayback_sinkInfoCallback, self)}; wait_for_operation(op, self->loop); - ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; + ALCdevice *device{self->mDevice}; pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE}; if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 0)) @@ -1132,7 +1132,7 @@ ClockLatency PulsePlayback_getClockLatency(PulsePlayback *self) int neg, err; { palock_guard _{self->loop}; - ret.ClockTime = GetDeviceClockTime(STATIC_CAST(ALCbackend,self)->mDevice); + ret.ClockTime = GetDeviceClockTime(self->mDevice); err = pa_stream_get_latency(self->stream, &latency, &neg); } @@ -1320,22 +1320,22 @@ void PulseCapture_probeDevices(void) void PulseCapture_contextStateCallback(pa_context *context, void *pdata) { - auto self = reinterpret_cast(pdata); + auto self = static_cast(pdata); if(pa_context_get_state(context) == PA_CONTEXT_FAILED) { ERR("Received context failure!\n"); - aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice, "Capture state failure"); + aluHandleDisconnect(self->mDevice, "Capture state failure"); } pa_threaded_mainloop_signal(self->loop, 0); } void PulseCapture_streamStateCallback(pa_stream *stream, void *pdata) { - auto self = reinterpret_cast(pdata); + auto self = static_cast(pdata); if(pa_stream_get_state(stream) == PA_STREAM_FAILED) { ERR("Received stream failure!\n"); - aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice, "Capture stream failure"); + aluHandleDisconnect(self->mDevice, "Capture stream failure"); } pa_threaded_mainloop_signal(self->loop, 0); } @@ -1343,7 +1343,7 @@ void PulseCapture_streamStateCallback(pa_stream *stream, void *pdata) void PulseCapture_sourceNameCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata) { - auto self = reinterpret_cast(pdata); + auto self = static_cast(pdata); if(eol) { @@ -1351,14 +1351,14 @@ void PulseCapture_sourceNameCallback(pa_context *UNUSED(context), const pa_sourc return; } - ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; + ALCdevice *device{self->mDevice}; device->DeviceName = info->description; } void PulseCapture_streamMovedCallback(pa_stream *stream, void *pdata) { - auto self = reinterpret_cast(pdata); + auto self = static_cast(pdata); self->device_name = pa_stream_get_device_name(stream); @@ -1409,7 +1409,7 @@ pa_stream *PulseCapture_connectStream(const char *device_name, ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) { - ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; + ALCdevice *device{self->mDevice}; const char *pulse_name{nullptr}; if(name) @@ -1555,7 +1555,7 @@ void PulseCapture_stop(PulseCapture *self) ALCenum PulseCapture_captureSamples(PulseCapture *self, ALCvoid *buffer, ALCuint samples) { - ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; + ALCdevice *device{self->mDevice}; ALCuint todo{samples * static_cast(pa_frame_size(&self->spec))}; /* Capture is done in fragment-sized chunks, so we loop until we get all @@ -1609,7 +1609,7 @@ ALCenum PulseCapture_captureSamples(PulseCapture *self, ALCvoid *buffer, ALCuint ALCuint PulseCapture_availableSamples(PulseCapture *self) { - ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; + ALCdevice *device{self->mDevice}; size_t readable{self->cap_remain}; if(device->Connected.load(std::memory_order_acquire)) @@ -1638,7 +1638,7 @@ ClockLatency PulseCapture_getClockLatency(PulseCapture *self) int neg, err; { palock_guard _{self->loop}; - ret.ClockTime = GetDeviceClockTime(STATIC_CAST(ALCbackend,self)->mDevice); + ret.ClockTime = GetDeviceClockTime(self->mDevice); err = pa_stream_get_latency(self->stream, &latency, &neg); } @@ -1757,15 +1757,13 @@ ALCbackend *PulseBackendFactory::createBackend(ALCdevice *device, ALCbackend_Typ { PulsePlayback *backend; NEW_OBJ(backend, PulsePlayback)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } if(type == ALCbackend_Capture) { PulseCapture *backend; NEW_OBJ(backend, PulseCapture)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } return nullptr; diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index ff74ff21..7469d874 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -194,8 +194,8 @@ DEFINE_ALCBACKEND_VTABLE(PlaybackWrapper); FORCE_ALIGN static int qsa_proc_playback(void *ptr) { PlaybackWrapper *self = static_cast(ptr); - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - qsa_data *data = self->ExtraData; + ALCdevice *device = self->mDevice; + qsa_data *data = self->ExtraData.get(); snd_pcm_channel_status_t status; sched_param param; char* write_ptr; @@ -282,7 +282,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) static ALCenum qsa_open_playback(PlaybackWrapper *self, const ALCchar* deviceName) { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCdevice *device = self->mDevice; int card, dev; int status; @@ -342,7 +342,7 @@ static void qsa_close_playback(PlaybackWrapper *self) static ALCboolean qsa_reset_playback(PlaybackWrapper *self) { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCdevice *device = self->mDevice; qsa_data *data = self->ExtraData.get(); int32_t format=-1; @@ -676,7 +676,7 @@ DEFINE_ALCBACKEND_VTABLE(CaptureWrapper); static ALCenum qsa_open_capture(CaptureWrapper *self, const ALCchar *deviceName) { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCdevice *device = self->mDevice; int card, dev; int format=-1; int status; @@ -813,7 +813,7 @@ static void qsa_stop_capture(CaptureWrapper *self) static ALCuint qsa_available_samples(CaptureWrapper *self) { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCdevice *device = self->mDevice; qsa_data *data = self->ExtraData.get(); snd_pcm_channel_status_t status; ALint frame_size = device->frameSizeFromFmt(); @@ -845,7 +845,7 @@ static ALCuint qsa_available_samples(CaptureWrapper *self) static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuint samples) { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCdevice *device = self->mDevice; qsa_data *data = self->ExtraData.get(); char* read_ptr; snd_pcm_channel_status_t status; @@ -1004,15 +1004,13 @@ ALCbackend *QSABackendFactory::createBackend(ALCdevice *device, ALCbackend_Type { PlaybackWrapper *backend; NEW_OBJ(backend, PlaybackWrapper)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); + return backend; } if(type == ALCbackend_Capture) { CaptureWrapper *backend; NEW_OBJ(backend, CaptureWrapper)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); + return backend; } return NULL; diff --git a/Alc/backends/sdl2.cpp b/Alc/backends/sdl2.cpp index 75052b0f..cb5f875a 100644 --- a/Alc/backends/sdl2.cpp +++ b/Alc/backends/sdl2.cpp @@ -92,16 +92,15 @@ static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self) static void ALCsdl2Backend_audioCallback(void *ptr, Uint8 *stream, int len) { - ALCsdl2Backend *self = static_cast(ptr); - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + auto self = static_cast(ptr); assert((len % self->frameSize) == 0); - aluMixData(device, stream, len / self->frameSize); + aluMixData(self->mDevice, stream, len / self->frameSize); } static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; SDL_AudioSpec want, have; SDL_zero(want); @@ -179,7 +178,7 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; device->Frequency = self->Frequency; device->FmtChans = self->FmtChans; device->FmtType = self->FmtType; @@ -256,8 +255,7 @@ ALCbackend *SDL2BackendFactory::createBackend(ALCdevice *device, ALCbackend_Type { ALCsdl2Backend *backend; NEW_OBJ(backend, ALCsdl2Backend)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } return nullptr; diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index 576e9ba9..ef9ce549 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -90,7 +90,7 @@ static void SndioPlayback_Destruct(SndioPlayback *self) static int SndioPlayback_mixerProc(SndioPlayback *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; ALsizei frameSize; size_t wrote; @@ -131,7 +131,7 @@ static int SndioPlayback_mixerProc(SndioPlayback *self) static ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name) { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCdevice *device{self->mDevice}; if(!name) name = sndio_device; @@ -151,7 +151,7 @@ static ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name) static ALCboolean SndioPlayback_reset(SndioPlayback *self) { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCdevice *device{self->mDevice}; sio_par par; sio_initpar(&par); @@ -236,7 +236,7 @@ static ALCboolean SndioPlayback_reset(SndioPlayback *self) static ALCboolean SndioPlayback_start(SndioPlayback *self) { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCdevice *device{self->mDevice}; self->data_size = device->UpdateSize * device->frameSizeFromFmt(); al_free(self->mix_data); @@ -378,7 +378,7 @@ static int SndioCapture_recordProc(SndioCapture *self) static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCdevice *device{self->mDevice}; sio_par par; if(!name) @@ -555,15 +555,13 @@ ALCbackend *SndIOBackendFactory::createBackend(ALCdevice *device, ALCbackend_Typ { SndioPlayback *backend; NEW_OBJ(backend, SndioPlayback)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } if(type == ALCbackend_Capture) { SndioCapture *backend; NEW_OBJ(backend, SndioCapture)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } return nullptr; diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index 60db963b..bbbe1612 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -103,7 +103,7 @@ static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self) static int ALCsolarisBackend_mixerProc(ALCsolarisBackend *self) { - ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + ALCdevice *device{self->mDevice}; SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); @@ -177,7 +177,7 @@ static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *na return ALC_INVALID_VALUE; } - device = STATIC_CAST(ALCbackend,self)->mDevice; + device = self->mDevice; device->DeviceName = name; return ALC_NO_ERROR; @@ -185,7 +185,7 @@ static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *na static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCdevice *device{self->mDevice}; audio_info_t info; ALsizei frameSize; ALsizei numChannels; @@ -326,8 +326,7 @@ ALCbackend *SolarisBackendFactory::createBackend(ALCdevice *device, ALCbackend_T { ALCsolarisBackend *backend; NEW_OBJ(backend, ALCsolarisBackend)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } return nullptr; diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index c7a216eb..1c760b4e 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -565,7 +565,7 @@ void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self) FORCE_ALIGN int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self) { - ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + ALCdevice *device{self->mDevice}; IAudioClient *client{self->mClient}; IAudioRenderClient *render{self->mRender}; @@ -714,7 +714,7 @@ ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *deviceNam WARN("Failed to find device name matching \"%s\"\n", deviceName); else { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCdevice *device{self->mDevice}; self->mDevId = iter->devid; device->DeviceName = iter->name; hr = S_OK; @@ -754,8 +754,6 @@ ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *deviceNam HRESULT ALCwasapiPlayback::openProxy() { - ALCdevice *device = STATIC_CAST(ALCbackend, this)->mDevice; - void *ptr; HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, &ptr); if(SUCCEEDED(hr)) @@ -772,8 +770,8 @@ HRESULT ALCwasapiPlayback::openProxy() if(SUCCEEDED(hr)) { mClient = reinterpret_cast(ptr); - if(device->DeviceName.empty()) - device->DeviceName = get_device_name_and_guid(mMMDev).first; + if(mDevice->DeviceName.empty()) + mDevice->DeviceName = get_device_name_and_guid(mMMDev).first; } if(FAILED(hr)) @@ -812,8 +810,6 @@ ALCboolean ALCwasapiPlayback_reset(ALCwasapiPlayback *self) HRESULT ALCwasapiPlayback::resetProxy() { - ALCdevice *device{STATIC_CAST(ALCbackend, this)->mDevice}; - if(mClient) mClient->Release(); mClient = nullptr; @@ -844,39 +840,39 @@ HRESULT ALCwasapiPlayback::resetProxy() CoTaskMemFree(wfx); wfx = nullptr; - REFERENCE_TIME buf_time{ScaleCeil(device->UpdateSize*device->NumUpdates, REFTIME_PER_SEC, - device->Frequency)}; + REFERENCE_TIME buf_time{ScaleCeil(mDevice->UpdateSize*mDevice->NumUpdates, REFTIME_PER_SEC, + mDevice->Frequency)}; - if(!(device->Flags&DEVICE_FREQUENCY_REQUEST)) - device->Frequency = OutputType.Format.nSamplesPerSec; - if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) + if(!(mDevice->Flags&DEVICE_FREQUENCY_REQUEST)) + mDevice->Frequency = OutputType.Format.nSamplesPerSec; + if(!(mDevice->Flags&DEVICE_CHANNELS_REQUEST)) { if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) - device->FmtChans = DevFmtMono; + mDevice->FmtChans = DevFmtMono; else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO) - device->FmtChans = DevFmtStereo; + mDevice->FmtChans = DevFmtStereo; else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD) - device->FmtChans = DevFmtQuad; + mDevice->FmtChans = DevFmtQuad; else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1) - device->FmtChans = DevFmtX51; + mDevice->FmtChans = DevFmtX51; else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR) - device->FmtChans = DevFmtX51Rear; + mDevice->FmtChans = DevFmtX51Rear; else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1) - device->FmtChans = DevFmtX61; + mDevice->FmtChans = DevFmtX61; else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE)) - device->FmtChans = DevFmtX71; + mDevice->FmtChans = DevFmtX71; else ERR("Unhandled channel config: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask); } - switch(device->FmtChans) + switch(mDevice->FmtChans) { case DevFmtMono: OutputType.Format.nChannels = 1; OutputType.dwChannelMask = MONO; break; case DevFmtAmbi3D: - device->FmtChans = DevFmtStereo; + mDevice->FmtChans = DevFmtStereo; /*fall-through*/ case DevFmtStereo: OutputType.Format.nChannels = 2; @@ -903,10 +899,10 @@ HRESULT ALCwasapiPlayback::resetProxy() OutputType.dwChannelMask = X7DOT1; break; } - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: - device->FmtType = DevFmtUByte; + mDevice->FmtType = DevFmtUByte; /* fall-through */ case DevFmtUByte: OutputType.Format.wBitsPerSample = 8; @@ -914,7 +910,7 @@ HRESULT ALCwasapiPlayback::resetProxy() OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; break; case DevFmtUShort: - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; /* fall-through */ case DevFmtShort: OutputType.Format.wBitsPerSample = 16; @@ -922,7 +918,7 @@ HRESULT ALCwasapiPlayback::resetProxy() OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; break; case DevFmtUInt: - device->FmtType = DevFmtInt; + mDevice->FmtType = DevFmtInt; /* fall-through */ case DevFmtInt: OutputType.Format.wBitsPerSample = 32; @@ -935,7 +931,7 @@ HRESULT ALCwasapiPlayback::resetProxy() OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; break; } - OutputType.Format.nSamplesPerSec = device->Frequency; + OutputType.Format.nSamplesPerSec = mDevice->Frequency; OutputType.Format.nBlockAlign = OutputType.Format.nChannels * OutputType.Format.wBitsPerSample / 8; @@ -964,25 +960,25 @@ HRESULT ALCwasapiPlayback::resetProxy() CoTaskMemFree(wfx); wfx = nullptr; - device->Frequency = OutputType.Format.nSamplesPerSec; + mDevice->Frequency = OutputType.Format.nSamplesPerSec; if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) - device->FmtChans = DevFmtMono; + mDevice->FmtChans = DevFmtMono; else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO) - device->FmtChans = DevFmtStereo; + mDevice->FmtChans = DevFmtStereo; else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD) - device->FmtChans = DevFmtQuad; + mDevice->FmtChans = DevFmtQuad; else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1) - device->FmtChans = DevFmtX51; + mDevice->FmtChans = DevFmtX51; else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR) - device->FmtChans = DevFmtX51Rear; + mDevice->FmtChans = DevFmtX51Rear; else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1) - device->FmtChans = DevFmtX61; + mDevice->FmtChans = DevFmtX61; else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE)) - device->FmtChans = DevFmtX71; + mDevice->FmtChans = DevFmtX71; else { ERR("Unhandled extensible channels: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask); - device->FmtChans = DevFmtStereo; + mDevice->FmtChans = DevFmtStereo; OutputType.Format.nChannels = 2; OutputType.dwChannelMask = STEREO; } @@ -990,26 +986,26 @@ HRESULT ALCwasapiPlayback::resetProxy() if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_PCM)) { if(OutputType.Format.wBitsPerSample == 8) - device->FmtType = DevFmtUByte; + mDevice->FmtType = DevFmtUByte; else if(OutputType.Format.wBitsPerSample == 16) - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; else if(OutputType.Format.wBitsPerSample == 32) - device->FmtType = DevFmtInt; + mDevice->FmtType = DevFmtInt; else { - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; OutputType.Format.wBitsPerSample = 16; } } else if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) { - device->FmtType = DevFmtFloat; + mDevice->FmtType = DevFmtFloat; OutputType.Format.wBitsPerSample = 32; } else { ERR("Unhandled format sub-type\n"); - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; OutputType.Format.wBitsPerSample = 16; OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; } @@ -1018,11 +1014,10 @@ HRESULT ALCwasapiPlayback::resetProxy() EndpointFormFactor formfactor = UnknownFormFactor; get_device_formfactor(mMMDev, &formfactor); - device->IsHeadphones = (device->FmtChans == DevFmtStereo && - (formfactor == Headphones || formfactor == Headset) - ); + mDevice->IsHeadphones = (mDevice->FmtChans == DevFmtStereo && + (formfactor == Headphones || formfactor == Headset)); - SetDefaultWFXChannelOrder(device); + SetDefaultWFXChannelOrder(mDevice); hr = mClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, buf_time, 0, &OutputType.Format, nullptr); @@ -1037,10 +1032,10 @@ HRESULT ALCwasapiPlayback::resetProxy() hr = mClient->GetDevicePeriod(&min_per, nullptr); if(SUCCEEDED(hr)) { - min_len = (UINT32)ScaleCeil(min_per, device->Frequency, REFTIME_PER_SEC); + min_len = (UINT32)ScaleCeil(min_per, mDevice->Frequency, REFTIME_PER_SEC); /* Find the nearest multiple of the period size to the update size */ - if(min_len < device->UpdateSize) - min_len *= maxu((device->UpdateSize + min_len/2) / min_len, 1u); + if(min_len < mDevice->UpdateSize) + min_len *= maxu((mDevice->UpdateSize + min_len/2) / min_len, 1u); hr = mClient->GetBufferSize(&buffer_len); } if(FAILED(hr)) @@ -1049,13 +1044,13 @@ HRESULT ALCwasapiPlayback::resetProxy() return hr; } - device->UpdateSize = min_len; - device->NumUpdates = buffer_len / device->UpdateSize; - if(device->NumUpdates <= 1) + mDevice->UpdateSize = min_len; + mDevice->NumUpdates = buffer_len / mDevice->UpdateSize; + if(mDevice->NumUpdates <= 1) { ERR("Audio client returned buffer_len < period*2; expect break up\n"); - device->NumUpdates = 2; - device->UpdateSize = buffer_len / device->NumUpdates; + mDevice->NumUpdates = 2; + mDevice->UpdateSize = buffer_len / mDevice->NumUpdates; } hr = mClient->SetEventHandle(mNotifyEvent); @@ -1143,7 +1138,7 @@ ClockLatency ALCwasapiPlayback_getClockLatency(ALCwasapiPlayback *self) ClockLatency ret; ALCwasapiPlayback_lock(self); - ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + ALCdevice *device{self->mDevice}; ret.ClockTime = GetDeviceClockTime(device); ret.Latency = std::chrono::seconds{self->mPadding.load(std::memory_order_relaxed)}; ret.Latency /= device->Frequency; @@ -1367,7 +1362,7 @@ ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *deviceName) WARN("Failed to find device name matching \"%s\"\n", deviceName); else { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + ALCdevice *device{self->mDevice}; self->mDevId = iter->devid; device->DeviceName = iter->name; hr = S_OK; @@ -1425,8 +1420,6 @@ ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *deviceName) HRESULT ALCwasapiCapture::openProxy() { - ALCdevice *device{STATIC_CAST(ALCbackend, this)->mDevice}; - void *ptr; HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, &ptr); @@ -1444,8 +1437,8 @@ HRESULT ALCwasapiCapture::openProxy() if(SUCCEEDED(hr)) { mClient = reinterpret_cast(ptr); - if(device->DeviceName.empty()) - device->DeviceName = get_device_name_and_guid(mMMDev).first; + if(mDevice->DeviceName.empty()) + mDevice->DeviceName = get_device_name_and_guid(mMMDev).first; } if(FAILED(hr)) @@ -1471,8 +1464,6 @@ void ALCwasapiCapture::closeProxy() HRESULT ALCwasapiCapture::resetProxy() { - ALCdevice *device{STATIC_CAST(ALCbackend, this)->mDevice}; - if(mClient) mClient->Release(); mClient = nullptr; @@ -1486,16 +1477,16 @@ HRESULT ALCwasapiCapture::resetProxy() } mClient = reinterpret_cast(ptr); - REFERENCE_TIME buf_time{ScaleCeil(device->UpdateSize*device->NumUpdates, REFTIME_PER_SEC, - device->Frequency)}; + REFERENCE_TIME buf_time{ScaleCeil(mDevice->UpdateSize*mDevice->NumUpdates, REFTIME_PER_SEC, + mDevice->Frequency)}; // Make sure buffer is at least 100ms in size buf_time = maxu64(buf_time, REFTIME_PER_SEC/10); - device->UpdateSize = (ALuint)ScaleCeil(buf_time, device->Frequency, REFTIME_PER_SEC) / - device->NumUpdates; + mDevice->UpdateSize = (ALuint)ScaleCeil(buf_time, mDevice->Frequency, REFTIME_PER_SEC) / + mDevice->NumUpdates; WAVEFORMATEXTENSIBLE OutputType; OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - switch(device->FmtChans) + switch(mDevice->FmtChans) { case DevFmtMono: OutputType.Format.nChannels = 1; @@ -1529,7 +1520,7 @@ HRESULT ALCwasapiCapture::resetProxy() case DevFmtAmbi3D: return E_FAIL; } - switch(device->FmtType) + switch(mDevice->FmtType) { /* NOTE: Signedness doesn't matter, the converter will handle it. */ case DevFmtByte: @@ -1553,7 +1544,7 @@ HRESULT ALCwasapiCapture::resetProxy() break; } OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; - OutputType.Format.nSamplesPerSec = device->Frequency; + OutputType.Format.nSamplesPerSec = mDevice->Frequency; OutputType.Format.nBlockAlign = OutputType.Format.nChannels * OutputType.Format.wBitsPerSample / 8; @@ -1579,8 +1570,8 @@ HRESULT ALCwasapiCapture::resetProxy() (wfx->nChannels == 2 && OutputType.Format.nChannels == 1))) { ERR("Failed to get matching format, wanted: %s %s %uhz, got: %d channel%s %d-bit %luhz\n", - DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), - device->Frequency, wfx->nChannels, (wfx->nChannels==1)?"":"s", wfx->wBitsPerSample, + DevFmtChannelsString(mDevice->FmtChans), DevFmtTypeString(mDevice->FmtType), + mDevice->Frequency, wfx->nChannels, (wfx->nChannels==1)?"":"s", wfx->wBitsPerSample, wfx->nSamplesPerSec); CoTaskMemFree(wfx); return E_FAIL; @@ -1626,9 +1617,9 @@ HRESULT ALCwasapiCapture::resetProxy() return E_FAIL; } - if(device->FmtChans == DevFmtMono && OutputType.Format.nChannels == 2) + if(mDevice->FmtChans == DevFmtMono && OutputType.Format.nChannels == 2) { - mChannelConv = CreateChannelConverter(srcType, DevFmtStereo, device->FmtChans); + mChannelConv = CreateChannelConverter(srcType, DevFmtStereo, mDevice->FmtChans); if(!mChannelConv) { ERR("Failed to create %s stereo-to-mono converter\n", DevFmtTypeString(srcType)); @@ -1640,9 +1631,9 @@ HRESULT ALCwasapiCapture::resetProxy() */ srcType = DevFmtFloat; } - else if(device->FmtChans == DevFmtStereo && OutputType.Format.nChannels == 1) + else if(mDevice->FmtChans == DevFmtStereo && OutputType.Format.nChannels == 1) { - mChannelConv = CreateChannelConverter(srcType, DevFmtMono, device->FmtChans); + mChannelConv = CreateChannelConverter(srcType, DevFmtMono, mDevice->FmtChans); if(!mChannelConv) { ERR("Failed to create %s mono-to-stereo converter\n", DevFmtTypeString(srcType)); @@ -1652,22 +1643,20 @@ HRESULT ALCwasapiCapture::resetProxy() srcType = DevFmtFloat; } - if(device->Frequency != OutputType.Format.nSamplesPerSec || device->FmtType != srcType) + if(mDevice->Frequency != OutputType.Format.nSamplesPerSec || mDevice->FmtType != srcType) { - mSampleConv = CreateSampleConverter( - srcType, device->FmtType, device->channelsFromFmt(), OutputType.Format.nSamplesPerSec, - device->Frequency, BSinc24Resampler - ); + mSampleConv = CreateSampleConverter(srcType, mDevice->FmtType, mDevice->channelsFromFmt(), + OutputType.Format.nSamplesPerSec, mDevice->Frequency, BSinc24Resampler); if(!mSampleConv) { ERR("Failed to create converter for %s format, dst: %s %uhz, src: %s %luhz\n", - DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), - device->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec); + DevFmtChannelsString(mDevice->FmtChans), DevFmtTypeString(mDevice->FmtType), + mDevice->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec); return E_FAIL; } TRACE("Created converter for %s format, dst: %s %uhz, src: %s %luhz\n", - DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), - device->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec); + DevFmtChannelsString(mDevice->FmtChans), DevFmtTypeString(mDevice->FmtType), + mDevice->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec); } hr = mClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, @@ -1686,8 +1675,8 @@ HRESULT ALCwasapiCapture::resetProxy() return hr; } - buffer_len = maxu(device->UpdateSize*device->NumUpdates, buffer_len); - mRing = CreateRingBuffer(buffer_len, device->frameSizeFromFmt(), false); + buffer_len = maxu(mDevice->UpdateSize*mDevice->NumUpdates, buffer_len); + mRing = CreateRingBuffer(buffer_len, mDevice->frameSizeFromFmt(), false); if(!mRing) { ERR("Failed to allocate capture ring buffer\n"); @@ -1875,15 +1864,13 @@ ALCbackend *WasapiBackendFactory::createBackend(ALCdevice *device, ALCbackend_Ty { ALCwasapiPlayback *backend; NEW_OBJ(backend, ALCwasapiPlayback)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } if(type == ALCbackend_Capture) { ALCwasapiCapture *backend; NEW_OBJ(backend, ALCwasapiCapture)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } return nullptr; diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index 3a65fc64..11e8a440 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -125,7 +125,7 @@ void ALCwaveBackend_Destruct(ALCwaveBackend *self) int ALCwaveBackend_mixerProc(ALCwaveBackend *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; const milliseconds restTime{device->UpdateSize*1000/device->Frequency / 2}; althrd_setname(MIXER_THREAD_NAME); @@ -234,7 +234,7 @@ ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name) return ALC_INVALID_VALUE; } - ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + ALCdevice *device{self->mDevice}; device->DeviceName = name; return ALC_NO_ERROR; @@ -242,7 +242,7 @@ ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name) ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; ALuint channels=0, bits=0, chanmask=0; int isbformat = 0; size_t val; @@ -404,8 +404,7 @@ ALCbackend *WaveBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type { ALCwaveBackend *backend; NEW_OBJ(backend, ALCwaveBackend)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } return nullptr; diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index ab638cd4..31c39c52 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -196,7 +196,7 @@ void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT UNUSED(device), UINT msg, FORCE_ALIGN int ALCwinmmPlayback_mixerProc(ALCwinmmPlayback *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); @@ -233,7 +233,7 @@ FORCE_ALIGN int ALCwinmmPlayback_mixerProc(ALCwinmmPlayback *self) ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *deviceName) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; if(PlaybackDevices.empty()) ProbePlaybackDevices(); @@ -288,7 +288,7 @@ retry_open: ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize * self->Format.nSamplesPerSec / @@ -509,7 +509,7 @@ int ALCwinmmCapture_captureProc(ALCwinmmCapture *self) ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALCdevice *device{self->mDevice}; if(CaptureDevices.empty()) ProbeCaptureDevices(); @@ -700,15 +700,13 @@ ALCbackend *WinMMBackendFactory::createBackend(ALCdevice *device, ALCbackend_Typ { ALCwinmmPlayback *backend; NEW_OBJ(backend, ALCwinmmPlayback)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } if(type == ALCbackend_Capture) { ALCwinmmCapture *backend; NEW_OBJ(backend, ALCwinmmCapture)(device); - if(!backend) return nullptr; - return STATIC_CAST(ALCbackend, backend); + return backend; } return nullptr; diff --git a/Alc/polymorphism.h b/Alc/polymorphism.h index 83d5585f..211d5db3 100644 --- a/Alc/polymorphism.h +++ b/Alc/polymorphism.h @@ -1,63 +1,43 @@ #ifndef POLYMORPHISM_H #define POLYMORPHISM_H -/* Macros to declare inheriting types, and to (down-)cast and up-cast. */ -#ifdef __cplusplus -#define STATIC_CAST(to, obj) static_cast(obj) -#define STATIC_UPCAST(to, from, obj) static_cast(obj) -#else - -#define DERIVE_FROM_TYPE(t) t t##_parent -#define STATIC_CAST(to, obj) (&(obj)->to##_parent) - -#if defined(__GNUC__) -#define STATIC_UPCAST(to, from, obj) __extension__({ \ - static_assert(__builtin_types_compatible_p(from, __typeof(*(obj))), \ - "Invalid upcast object from type"); \ - (to*)((char*)(obj) - offsetof(to, from##_parent)); \ -}) -#else -#define STATIC_UPCAST(to, from, obj) ((to*)((char*)(obj) - offsetof(to, from##_parent))) -#endif -#endif /* __cplusplus */ - /* Defines method forwards, which call the given parent's (T2's) implementation. */ #define DECLARE_FORWARD(T1, T2, rettype, func) \ rettype T1##_##func(T1 *obj) \ -{ return T2##_##func(STATIC_CAST(T2, obj)); } +{ return T2##_##func(static_cast(obj)); } #define DECLARE_FORWARD1(T1, T2, rettype, func, argtype1) \ rettype T1##_##func(T1 *obj, argtype1 a) \ -{ return T2##_##func(STATIC_CAST(T2, obj), a); } +{ return T2##_##func(static_cast(obj), a); } #define DECLARE_FORWARD2(T1, T2, rettype, func, argtype1, argtype2) \ rettype T1##_##func(T1 *obj, argtype1 a, argtype2 b) \ -{ return T2##_##func(STATIC_CAST(T2, obj), a, b); } +{ return T2##_##func(static_cast(obj), a, b); } #define DECLARE_FORWARD3(T1, T2, rettype, func, argtype1, argtype2, argtype3) \ rettype T1##_##func(T1 *obj, argtype1 a, argtype2 b, argtype3 c) \ -{ return T2##_##func(STATIC_CAST(T2, obj), a, b, c); } +{ return T2##_##func(static_cast(obj), a, b, c); } /* Defines method thunks, functions that call to the child's method. */ #define DECLARE_THUNK(T1, T2, rettype, func) \ static rettype T1##_##T2##_##func(T2 *obj) \ -{ return T1##_##func(STATIC_UPCAST(T1, T2, obj)); } +{ return T1##_##func(static_cast(obj)); } #define DECLARE_THUNK1(T1, T2, rettype, func, argtype1) \ static rettype T1##_##T2##_##func(T2 *obj, argtype1 a) \ -{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a); } +{ return T1##_##func(static_cast(obj), a); } #define DECLARE_THUNK2(T1, T2, rettype, func, argtype1, argtype2) \ static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b) \ -{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b); } +{ return T1##_##func(static_cast(obj), a, b); } #define DECLARE_THUNK3(T1, T2, rettype, func, argtype1, argtype2, argtype3) \ static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c) \ -{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c); } +{ return T1##_##func(static_cast(obj), a, b, c); } #define DECLARE_THUNK4(T1, T2, rettype, func, argtype1, argtype2, argtype3, argtype4) \ static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c, argtype4 d) \ -{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c, d); } +{ return T1##_##func(static_cast(obj), a, b, c, d); } /* Defines the default functions used to (de)allocate a polymorphic object. */ #define DECLARE_DEFAULT_ALLOCATORS(T) \ @@ -105,6 +85,6 @@ static void T##_Delete(void *ptr) { al_free(ptr); } /* Helper to get a type's vtable thunk for a child type. */ #define GET_VTABLE2(T1, T2) (&(T1##_##T2##_vtable)) /* Helper to set an object's vtable thunk for a child type. Used when constructing an object. */ -#define SET_VTABLE2(T1, T2, obj) (STATIC_CAST(T2, obj)->vtbl = GET_VTABLE2(T1, T2)) +#define SET_VTABLE2(T1, T2, obj) (static_cast(obj)->vtbl = GET_VTABLE2(T1, T2)) #endif /* POLYMORPHISM_H */ -- cgit v1.2.3 From 515edc3deea8ba2661cb86571410fdd9a8eae158 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Dec 2018 15:05:12 -0800 Subject: Fix ring buffer vector methods --- Alc/ringbuffer.cpp | 6 +++--- OpenAL32/event.cpp | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Alc/ringbuffer.cpp b/Alc/ringbuffer.cpp index 767db246..791fff63 100644 --- a/Alc/ringbuffer.cpp +++ b/Alc/ringbuffer.cpp @@ -192,7 +192,7 @@ void RingBuffer::writeAdvance(size_t cnt) noexcept } -ll_ringbuffer_data_pair RingBuffer::getWriteVector() const noexcept +ll_ringbuffer_data_pair RingBuffer::getReadVector() const noexcept { ll_ringbuffer_data_pair ret; @@ -205,7 +205,7 @@ ll_ringbuffer_data_pair RingBuffer::getWriteVector() const noexcept const size_t cnt2{r + free_cnt}; if(cnt2 > mSizeMask+1) { - /* Two part vector: the rest of the buffer after the current write ptr, + /* Two part vector: the rest of the buffer after the current read ptr, * plus some from the start of the buffer. */ ret.first.buf = const_cast(&mBuffer[r*mElemSize]); ret.first.len = mSizeMask+1 - r; @@ -224,7 +224,7 @@ ll_ringbuffer_data_pair RingBuffer::getWriteVector() const noexcept return ret; } -ll_ringbuffer_data_pair RingBuffer::getReadVector() const noexcept +ll_ringbuffer_data_pair RingBuffer::getWriteVector() const noexcept { ll_ringbuffer_data_pair ret; diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index f3474139..a2e3addd 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -37,14 +37,14 @@ static int EventThread(ALCcontext *context) * ringbuffer's read offset at the end of scope. */ const struct EventAutoDestructor { - AsyncEvent &evt; - RingBuffer *ring; + AsyncEvent &evt_; + RingBuffer *ring_; ~EventAutoDestructor() { - evt.~AsyncEvent(); - ring->readAdvance(1); + evt_.~AsyncEvent(); + ring_->readAdvance(1); } - } _{evt, context->AsyncEvents.get()}; + } _{evt, ring}; quitnow = evt.EnumType == EventType_KillThread; if(UNLIKELY(quitnow)) break; -- cgit v1.2.3 From e48b8c4cdada7bd1df0c221d633d0ddc3f81fddd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Dec 2018 17:09:14 -0800 Subject: Rename some more struct members for consistency --- Alc/backends/oss.cpp | 72 ++++----- Alc/backends/portaudio.cpp | 121 +++++++------- Alc/backends/pulseaudio.cpp | 381 ++++++++++++++++++++++---------------------- 3 files changed, 285 insertions(+), 289 deletions(-) diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index e5630ad3..c35c7247 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -242,7 +242,7 @@ int log2i(ALCuint x) struct ALCplaybackOSS final : public ALCbackend { - int fd{-1}; + int mFd{-1}; al::vector mMixData; @@ -277,9 +277,9 @@ void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device) void ALCplaybackOSS_Destruct(ALCplaybackOSS *self) { - if(self->fd != -1) - close(self->fd); - self->fd = -1; + if(self->mFd != -1) + close(self->mFd); + self->mFd = -1; self->~ALCplaybackOSS(); } @@ -299,7 +299,7 @@ int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self) device->Connected.load(std::memory_order_acquire)) { pollfd pollitem{}; - pollitem.fd = self->fd; + pollitem.fd = self->mFd; pollitem.events = POLLOUT; ALCplaybackOSS_unlock(self); @@ -324,7 +324,7 @@ int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self) aluMixData(device, write_ptr, to_write/frame_size); while(to_write > 0 && !self->mKillNow.load()) { - ssize_t wrote{write(self->fd, write_ptr, to_write)}; + ssize_t wrote{write(self->mFd, write_ptr, to_write)}; if(wrote < 0) { if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) @@ -366,8 +366,8 @@ ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) devname = iter->device_name.c_str(); } - self->fd = open(devname, O_WRONLY); - if(self->fd == -1) + self->mFd = open(devname, O_WRONLY); + if(self->mFd == -1) { ERR("Could not open %s: %s\n", devname, strerror(errno)); return ALC_INVALID_VALUE; @@ -423,11 +423,11 @@ ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) } /* Don't fail if SETFRAGMENT fails. We can handle just about anything * that's reported back via GETOSPACE */ - ioctl(self->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize); - CHECKERR(ioctl(self->fd, SNDCTL_DSP_SETFMT, &ossFormat)); - CHECKERR(ioctl(self->fd, SNDCTL_DSP_CHANNELS, &numChannels)); - CHECKERR(ioctl(self->fd, SNDCTL_DSP_SPEED, &ossSpeed)); - CHECKERR(ioctl(self->fd, SNDCTL_DSP_GETOSPACE, &info)); + ioctl(self->mFd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize); + CHECKERR(ioctl(self->mFd, SNDCTL_DSP_SETFMT, &ossFormat)); + CHECKERR(ioctl(self->mFd, SNDCTL_DSP_CHANNELS, &numChannels)); + CHECKERR(ioctl(self->mFd, SNDCTL_DSP_SPEED, &ossSpeed)); + CHECKERR(ioctl(self->mFd, SNDCTL_DSP_GETOSPACE, &info)); if(0) { err: @@ -484,7 +484,7 @@ void ALCplaybackOSS_stop(ALCplaybackOSS *self) return; self->mThread.join(); - if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0) + if(ioctl(self->mFd, SNDCTL_DSP_RESET) != 0) ERR("Error resetting device: %s\n", strerror(errno)); self->mMixData.clear(); @@ -492,7 +492,7 @@ void ALCplaybackOSS_stop(ALCplaybackOSS *self) struct ALCcaptureOSS final : public ALCbackend { - int fd{-1}; + int mFd{-1}; RingBufferPtr mRing{nullptr}; @@ -527,9 +527,9 @@ void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device) void ALCcaptureOSS_Destruct(ALCcaptureOSS *self) { - if(self->fd != -1) - close(self->fd); - self->fd = -1; + if(self->mFd != -1) + close(self->mFd); + self->mFd = -1; self->~ALCcaptureOSS(); } @@ -547,7 +547,7 @@ int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) while(!self->mKillNow.load()) { pollfd pollitem{}; - pollitem.fd = self->fd; + pollitem.fd = self->mFd; pollitem.events = POLLIN; int sret{poll(&pollitem, 1, 1000)}; @@ -568,7 +568,7 @@ int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) auto vec = ring->getWriteVector(); if(vec.first.len > 0) { - ssize_t amt{read(self->fd, vec.first.buf, vec.first.len*frame_size)}; + ssize_t amt{read(self->mFd, vec.first.buf, vec.first.len*frame_size)}; if(amt < 0) { ERR("read failed: %s\n", strerror(errno)); @@ -606,8 +606,8 @@ ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) devname = iter->device_name.c_str(); } - self->fd = open(devname, O_RDONLY); - if(self->fd == -1) + self->mFd = open(devname, O_RDONLY); + if(self->mFd == -1) { ERR("Could not open %s: %s\n", devname, strerror(errno)); return ALC_INVALID_VALUE; @@ -650,17 +650,17 @@ ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) err = #func; \ goto err; \ } - CHECKERR(ioctl(self->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize)); - CHECKERR(ioctl(self->fd, SNDCTL_DSP_SETFMT, &ossFormat)); - CHECKERR(ioctl(self->fd, SNDCTL_DSP_CHANNELS, &numChannels)); - CHECKERR(ioctl(self->fd, SNDCTL_DSP_SPEED, &ossSpeed)); - CHECKERR(ioctl(self->fd, SNDCTL_DSP_GETISPACE, &info)); + CHECKERR(ioctl(self->mFd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize)); + CHECKERR(ioctl(self->mFd, SNDCTL_DSP_SETFMT, &ossFormat)); + CHECKERR(ioctl(self->mFd, SNDCTL_DSP_CHANNELS, &numChannels)); + CHECKERR(ioctl(self->mFd, SNDCTL_DSP_SPEED, &ossSpeed)); + CHECKERR(ioctl(self->mFd, SNDCTL_DSP_GETISPACE, &info)); if(0) { err: ERR("%s failed: %s\n", err, strerror(errno)); - close(self->fd); - self->fd = -1; + close(self->mFd); + self->mFd = -1; return ALC_INVALID_VALUE; } #undef CHECKERR @@ -668,8 +668,8 @@ ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) if(device->channelsFromFmt() != numChannels) { ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); - close(self->fd); - self->fd = -1; + close(self->mFd); + self->mFd = -1; return ALC_INVALID_VALUE; } @@ -678,8 +678,8 @@ ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort))) { ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat); - close(self->fd); - self->fd = -1; + close(self->mFd); + self->mFd = -1; return ALC_INVALID_VALUE; } @@ -687,8 +687,8 @@ ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) if(!self->mRing) { ERR("Ring buffer create failed\n"); - close(self->fd); - self->fd = -1; + close(self->mFd); + self->mFd = -1; return ALC_OUT_OF_MEMORY; } @@ -718,7 +718,7 @@ void ALCcaptureOSS_stop(ALCcaptureOSS *self) self->mThread.join(); - if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0) + if(ioctl(self->mFd, SNDCTL_DSP_RESET) != 0) ERR("Error resetting device: %s\n", strerror(errno)); } diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index 7c0569c2..10c9079b 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -131,9 +131,9 @@ bool pa_load(void) struct ALCportPlayback final : public ALCbackend { - PaStream *Stream{nullptr}; - PaStreamParameters Params; - ALuint UpdateSize{0u}; + PaStream *mStream{nullptr}; + PaStreamParameters mParams{}; + ALuint mUpdateSize{0u}; ALCportPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } }; @@ -166,10 +166,10 @@ void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device) void ALCportPlayback_Destruct(ALCportPlayback *self) { - PaError err = self->Stream ? Pa_CloseStream(self->Stream) : paNoError; + PaError err = self->mStream ? Pa_CloseStream(self->mStream) : paNoError; if(err != paNoError) ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); - self->Stream = nullptr; + self->mStream = nullptr; self->~ALCportPlayback(); } @@ -198,51 +198,51 @@ ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name) else if(strcmp(name, pa_device) != 0) return ALC_INVALID_VALUE; - self->UpdateSize = device->UpdateSize; + self->mUpdateSize = device->UpdateSize; - self->Params.device = -1; - if(!ConfigValueInt(nullptr, "port", "device", &self->Params.device) || - self->Params.device < 0) - self->Params.device = Pa_GetDefaultOutputDevice(); - self->Params.suggestedLatency = (device->UpdateSize*device->NumUpdates) / + self->mParams.device = -1; + if(!ConfigValueInt(nullptr, "port", "device", &self->mParams.device) || + self->mParams.device < 0) + self->mParams.device = Pa_GetDefaultOutputDevice(); + self->mParams.suggestedLatency = (device->UpdateSize*device->NumUpdates) / (float)device->Frequency; - self->Params.hostApiSpecificStreamInfo = nullptr; + self->mParams.hostApiSpecificStreamInfo = nullptr; - self->Params.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2); + self->mParams.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2); switch(device->FmtType) { case DevFmtByte: - self->Params.sampleFormat = paInt8; + self->mParams.sampleFormat = paInt8; break; case DevFmtUByte: - self->Params.sampleFormat = paUInt8; + self->mParams.sampleFormat = paUInt8; break; case DevFmtUShort: /* fall-through */ case DevFmtShort: - self->Params.sampleFormat = paInt16; + self->mParams.sampleFormat = paInt16; break; case DevFmtUInt: /* fall-through */ case DevFmtInt: - self->Params.sampleFormat = paInt32; + self->mParams.sampleFormat = paInt32; break; case DevFmtFloat: - self->Params.sampleFormat = paFloat32; + self->mParams.sampleFormat = paFloat32; break; } retry_open: - err = Pa_OpenStream(&self->Stream, nullptr, &self->Params, + err = Pa_OpenStream(&self->mStream, nullptr, &self->mParams, device->Frequency, device->UpdateSize, paNoFlag, ALCportPlayback_WriteCallback, self ); if(err != paNoError) { - if(self->Params.sampleFormat == paFloat32) + if(self->mParams.sampleFormat == paFloat32) { - self->Params.sampleFormat = paInt16; + self->mParams.sampleFormat = paInt16; goto retry_open; } ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); @@ -258,33 +258,33 @@ ALCboolean ALCportPlayback_reset(ALCportPlayback *self) { ALCdevice *device{self->mDevice}; - const PaStreamInfo *streamInfo{Pa_GetStreamInfo(self->Stream)}; + const PaStreamInfo *streamInfo{Pa_GetStreamInfo(self->mStream)}; device->Frequency = streamInfo->sampleRate; - device->UpdateSize = self->UpdateSize; + device->UpdateSize = self->mUpdateSize; - if(self->Params.sampleFormat == paInt8) + if(self->mParams.sampleFormat == paInt8) device->FmtType = DevFmtByte; - else if(self->Params.sampleFormat == paUInt8) + else if(self->mParams.sampleFormat == paUInt8) device->FmtType = DevFmtUByte; - else if(self->Params.sampleFormat == paInt16) + else if(self->mParams.sampleFormat == paInt16) device->FmtType = DevFmtShort; - else if(self->Params.sampleFormat == paInt32) + else if(self->mParams.sampleFormat == paInt32) device->FmtType = DevFmtInt; - else if(self->Params.sampleFormat == paFloat32) + else if(self->mParams.sampleFormat == paFloat32) device->FmtType = DevFmtFloat; else { - ERR("Unexpected sample format: 0x%lx\n", self->Params.sampleFormat); + ERR("Unexpected sample format: 0x%lx\n", self->mParams.sampleFormat); return ALC_FALSE; } - if(self->Params.channelCount == 2) + if(self->mParams.channelCount == 2) device->FmtChans = DevFmtStereo; - else if(self->Params.channelCount == 1) + else if(self->mParams.channelCount == 1) device->FmtChans = DevFmtMono; else { - ERR("Unexpected channel count: %u\n", self->Params.channelCount); + ERR("Unexpected channel count: %u\n", self->mParams.channelCount); return ALC_FALSE; } SetDefaultChannelOrder(device); @@ -294,31 +294,28 @@ ALCboolean ALCportPlayback_reset(ALCportPlayback *self) ALCboolean ALCportPlayback_start(ALCportPlayback *self) { - PaError err; - - err = Pa_StartStream(self->Stream); + PaError err{Pa_StartStream(self->mStream)}; if(err != paNoError) { ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err)); return ALC_FALSE; } - return ALC_TRUE; } void ALCportPlayback_stop(ALCportPlayback *self) { - PaError err = Pa_StopStream(self->Stream); + PaError err{Pa_StopStream(self->mStream)}; if(err != paNoError) ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); } struct ALCportCapture final : public ALCbackend { - PaStream *Stream{nullptr}; - PaStreamParameters Params; + PaStream *mStream{nullptr}; + PaStreamParameters mParams; - RingBufferPtr Ring{nullptr}; + RingBufferPtr mRing{nullptr}; ALCportCapture(ALCdevice *device) noexcept : ALCbackend{device} { } }; @@ -351,10 +348,10 @@ void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device) void ALCportCapture_Destruct(ALCportCapture *self) { - PaError err = self->Stream ? Pa_CloseStream(self->Stream) : paNoError; + PaError err = self->mStream ? Pa_CloseStream(self->mStream) : paNoError; if(err != paNoError) ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); - self->Stream = nullptr; + self->mStream = nullptr; self->~ALCportCapture(); } @@ -365,7 +362,7 @@ int ALCportCapture_ReadCallback(const void *inputBuffer, void *UNUSED(outputBuff const PaStreamCallbackFlags UNUSED(statusFlags), void *userData) { auto self = static_cast(userData); - RingBuffer *ring{self->Ring.get()}; + RingBuffer *ring{self->mRing.get()}; ring->write(inputBuffer, framesPerBuffer); return 0; } @@ -386,41 +383,41 @@ ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) samples = maxu(samples, 100 * device->Frequency / 1000); frame_size = device->frameSizeFromFmt(); - self->Ring = CreateRingBuffer(samples, frame_size, false); - if(!self->Ring) return ALC_INVALID_VALUE; + self->mRing = CreateRingBuffer(samples, frame_size, false); + if(!self->mRing) return ALC_INVALID_VALUE; - self->Params.device = -1; - if(!ConfigValueInt(nullptr, "port", "capture", &self->Params.device) || - self->Params.device < 0) - self->Params.device = Pa_GetDefaultInputDevice(); - self->Params.suggestedLatency = 0.0f; - self->Params.hostApiSpecificStreamInfo = nullptr; + self->mParams.device = -1; + if(!ConfigValueInt(nullptr, "port", "capture", &self->mParams.device) || + self->mParams.device < 0) + self->mParams.device = Pa_GetDefaultInputDevice(); + self->mParams.suggestedLatency = 0.0f; + self->mParams.hostApiSpecificStreamInfo = nullptr; switch(device->FmtType) { case DevFmtByte: - self->Params.sampleFormat = paInt8; + self->mParams.sampleFormat = paInt8; break; case DevFmtUByte: - self->Params.sampleFormat = paUInt8; + self->mParams.sampleFormat = paUInt8; break; case DevFmtShort: - self->Params.sampleFormat = paInt16; + self->mParams.sampleFormat = paInt16; break; case DevFmtInt: - self->Params.sampleFormat = paInt32; + self->mParams.sampleFormat = paInt32; break; case DevFmtFloat: - self->Params.sampleFormat = paFloat32; + self->mParams.sampleFormat = paFloat32; break; case DevFmtUInt: case DevFmtUShort: ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); return ALC_INVALID_VALUE; } - self->Params.channelCount = device->channelsFromFmt(); + self->mParams.channelCount = device->channelsFromFmt(); - err = Pa_OpenStream(&self->Stream, &self->Params, nullptr, + err = Pa_OpenStream(&self->mStream, &self->mParams, nullptr, device->Frequency, paFramesPerBufferUnspecified, paNoFlag, ALCportCapture_ReadCallback, self ); @@ -437,7 +434,7 @@ ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) ALCboolean ALCportCapture_start(ALCportCapture *self) { - PaError err = Pa_StartStream(self->Stream); + PaError err = Pa_StartStream(self->mStream); if(err != paNoError) { ERR("Error starting stream: %s\n", Pa_GetErrorText(err)); @@ -448,7 +445,7 @@ ALCboolean ALCportCapture_start(ALCportCapture *self) void ALCportCapture_stop(ALCportCapture *self) { - PaError err = Pa_StopStream(self->Stream); + PaError err = Pa_StopStream(self->mStream); if(err != paNoError) ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); } @@ -456,13 +453,13 @@ void ALCportCapture_stop(ALCportCapture *self) ALCuint ALCportCapture_availableSamples(ALCportCapture *self) { - RingBuffer *ring{self->Ring.get()}; + RingBuffer *ring{self->mRing.get()}; return ring->readSpace(); } ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples) { - RingBuffer *ring{self->Ring.get()}; + RingBuffer *ring{self->mRing.get()}; ring->read(buffer, samples); return ALC_NO_ERROR; } diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 23685178..6e5e07b8 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -523,15 +523,15 @@ al::vector CaptureDevices; struct PulsePlayback final : public ALCbackend { - std::string device_name; + std::string mDeviceName; - pa_buffer_attr attr; - pa_sample_spec spec; + pa_buffer_attr mAttr; + pa_sample_spec mSpec; - pa_threaded_mainloop *loop{nullptr}; + pa_threaded_mainloop *mLoop{nullptr}; - pa_stream *stream{nullptr}; - pa_context *context{nullptr}; + pa_stream *mStream{nullptr}; + pa_context *mContext{nullptr}; ALuint mBufferSize{0u}; ALuint mFrameSize{0u}; @@ -578,12 +578,12 @@ void PulsePlayback_Construct(PulsePlayback *self, ALCdevice *device) void PulsePlayback_Destruct(PulsePlayback *self) { - if(self->loop) + if(self->mLoop) { - pulse_close(self->loop, self->context, self->stream); - self->loop = nullptr; - self->context = nullptr; - self->stream = nullptr; + pulse_close(self->mLoop, self->mContext, self->mStream); + self->mLoop = nullptr; + self->mContext = nullptr; + self->mStream = nullptr; } self->~PulsePlayback(); } @@ -591,7 +591,7 @@ void PulsePlayback_Destruct(PulsePlayback *self) void PulsePlayback_deviceCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) { - auto loop = reinterpret_cast(pdata); + auto loop = static_cast(pdata); if(eol) { @@ -676,41 +676,41 @@ void PulsePlayback_probeDevices(void) void PulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata) { - auto self = reinterpret_cast(pdata); + auto self = static_cast(pdata); /* FIXME: Update the device's UpdateSize (and/or NumUpdates) using the new * buffer attributes? Changing UpdateSize will change the ALC_REFRESH * property, which probably shouldn't change between device resets. But * leaving it alone means ALC_REFRESH will be off. */ - self->attr = *(pa_stream_get_buffer_attr(stream)); - TRACE("minreq=%d, tlength=%d, prebuf=%d\n", self->attr.minreq, self->attr.tlength, - self->attr.prebuf); + self->mAttr = *(pa_stream_get_buffer_attr(stream)); + TRACE("minreq=%d, tlength=%d, prebuf=%d\n", self->mAttr.minreq, self->mAttr.tlength, + self->mAttr.prebuf); - const ALuint num_periods{(self->attr.tlength + self->attr.minreq/2u) / self->attr.minreq}; - self->mBufferSize = maxu(num_periods, 2u) * self->attr.minreq; + const ALuint num_periods{(self->mAttr.tlength + self->mAttr.minreq/2u) / self->mAttr.minreq}; + self->mBufferSize = maxu(num_periods, 2u) * self->mAttr.minreq; } void PulsePlayback_contextStateCallback(pa_context *context, void *pdata) { - auto self = reinterpret_cast(pdata); + auto self = static_cast(pdata); if(pa_context_get_state(context) == PA_CONTEXT_FAILED) { ERR("Received context failure!\n"); aluHandleDisconnect(self->mDevice, "Playback state failure"); } - pa_threaded_mainloop_signal(self->loop, 0); + pa_threaded_mainloop_signal(self->mLoop, 0); } void PulsePlayback_streamStateCallback(pa_stream *stream, void *pdata) { - auto self = reinterpret_cast(pdata); + auto self = static_cast(pdata); if(pa_stream_get_state(stream) == PA_STREAM_FAILED) { ERR("Received stream failure!\n"); aluHandleDisconnect(self->mDevice, "Playback stream failure"); } - pa_threaded_mainloop_signal(self->loop, 0); + pa_threaded_mainloop_signal(self->mLoop, 0); } void PulsePlayback_streamWriteCallback(pa_stream *stream, size_t nbytes, void *pdata) @@ -720,8 +720,8 @@ void PulsePlayback_streamWriteCallback(pa_stream *stream, size_t nbytes, void *p /* Round down to the nearest period/minreq multiple if doing more than 1. */ const size_t frame_size{self->mFrameSize}; - if(nbytes > self->attr.minreq) - nbytes -= nbytes%self->attr.minreq; + if(nbytes > self->mAttr.minreq) + nbytes -= nbytes%self->mAttr.minreq; void *buf{pa_xmalloc(nbytes)}; aluMixData(device, buf, nbytes/frame_size); @@ -773,7 +773,7 @@ void PulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa_sink_i if(eol) { - pa_threaded_mainloop_signal(self->loop, 0); + pa_threaded_mainloop_signal(self->mLoop, 0); return; } @@ -807,7 +807,7 @@ void PulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const pa_sink_i if(eol) { - pa_threaded_mainloop_signal(self->loop, 0); + pa_threaded_mainloop_signal(self->mLoop, 0); return; } @@ -820,9 +820,9 @@ void PulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata) { auto self = static_cast(pdata); - self->device_name = pa_stream_get_device_name(stream); + self->mDeviceName = pa_stream_get_device_name(stream); - TRACE("Stream moved to %s\n", self->device_name.c_str()); + TRACE("Stream moved to %s\n", self->mDeviceName.c_str()); } @@ -893,10 +893,10 @@ ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) dev_name = iter->name.c_str(); } - std::tie(self->loop, self->context) = pulse_open(PulsePlayback_contextStateCallback, self); - if(!self->loop) return ALC_INVALID_VALUE; + std::tie(self->mLoop, self->mContext) = pulse_open(PulsePlayback_contextStateCallback, self); + if(!self->mLoop) return ALC_INVALID_VALUE; - unique_palock palock{self->loop}; + unique_palock palock{self->mLoop}; pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS}; @@ -909,26 +909,25 @@ ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) spec.channels = 2; TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); - self->stream = PulsePlayback_connectStream(pulse_name, self->loop, self->context, - flags, nullptr, &spec, nullptr); - if(!self->stream) + self->mStream = PulsePlayback_connectStream(pulse_name, self->mLoop, self->mContext, flags, + nullptr, &spec, nullptr); + if(!self->mStream) { palock = unique_palock{}; - pulse_close(self->loop, self->context, self->stream); - self->loop = nullptr; - self->context = nullptr; + pulse_close(self->mLoop, self->mContext, self->mStream); + self->mLoop = nullptr; + self->mContext = nullptr; return ALC_INVALID_VALUE; } - pa_stream_set_moved_callback(self->stream, PulsePlayback_streamMovedCallback, self); - self->mFrameSize = pa_frame_size(pa_stream_get_sample_spec(self->stream)); + pa_stream_set_moved_callback(self->mStream, PulsePlayback_streamMovedCallback, self); + self->mFrameSize = pa_frame_size(pa_stream_get_sample_spec(self->mStream)); - self->device_name = pa_stream_get_device_name(self->stream); + self->mDeviceName = pa_stream_get_device_name(self->mStream); if(!dev_name) { - pa_operation *op{pa_context_get_sink_info_by_name(self->context, - self->device_name.c_str(), PulsePlayback_sinkNameCallback, self - )}; - wait_for_operation(op, self->loop); + pa_operation *op{pa_context_get_sink_info_by_name(self->mContext, + self->mDeviceName.c_str(), PulsePlayback_sinkNameCallback, self)}; + wait_for_operation(op, self->mLoop); } else { @@ -941,22 +940,22 @@ ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) ALCboolean PulsePlayback_reset(PulsePlayback *self) { - unique_palock palock{self->loop}; + unique_palock palock{self->mLoop}; - if(self->stream) + if(self->mStream) { - pa_stream_set_state_callback(self->stream, nullptr, nullptr); - pa_stream_set_moved_callback(self->stream, nullptr, nullptr); - pa_stream_set_write_callback(self->stream, nullptr, nullptr); - pa_stream_set_buffer_attr_callback(self->stream, nullptr, nullptr); - pa_stream_disconnect(self->stream); - pa_stream_unref(self->stream); - self->stream = nullptr; + pa_stream_set_state_callback(self->mStream, nullptr, nullptr); + pa_stream_set_moved_callback(self->mStream, nullptr, nullptr); + pa_stream_set_write_callback(self->mStream, nullptr, nullptr); + pa_stream_set_buffer_attr_callback(self->mStream, nullptr, nullptr); + pa_stream_disconnect(self->mStream); + pa_stream_unref(self->mStream); + self->mStream = nullptr; } - pa_operation *op{pa_context_get_sink_info_by_name(self->context, - self->device_name.c_str(), PulsePlayback_sinkInfoCallback, self)}; - wait_for_operation(op, self->loop); + pa_operation *op{pa_context_get_sink_info_by_name(self->mContext, + self->mDeviceName.c_str(), PulsePlayback_sinkInfoCallback, self)}; + wait_for_operation(op, self->mLoop); ALCdevice *device{self->mDevice}; pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | @@ -975,28 +974,28 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) device->FmtType = DevFmtUByte; /* fall-through */ case DevFmtUByte: - self->spec.format = PA_SAMPLE_U8; + self->mSpec.format = PA_SAMPLE_U8; break; case DevFmtUShort: device->FmtType = DevFmtShort; /* fall-through */ case DevFmtShort: - self->spec.format = PA_SAMPLE_S16NE; + self->mSpec.format = PA_SAMPLE_S16NE; break; case DevFmtUInt: device->FmtType = DevFmtInt; /* fall-through */ case DevFmtInt: - self->spec.format = PA_SAMPLE_S32NE; + self->mSpec.format = PA_SAMPLE_S32NE; break; case DevFmtFloat: - self->spec.format = PA_SAMPLE_FLOAT32NE; + self->mSpec.format = PA_SAMPLE_FLOAT32NE; break; } - self->spec.rate = device->Frequency; - self->spec.channels = device->channelsFromFmt(); + self->mSpec.rate = device->Frequency; + self->mSpec.channels = device->channelsFromFmt(); - if(pa_sample_spec_valid(&self->spec) == 0) + if(pa_sample_spec_valid(&self->mSpec) == 0) { ERR("Invalid sample format\n"); return ALC_FALSE; @@ -1038,48 +1037,49 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) } SetDefaultWFXChannelOrder(device); - size_t period_size{device->UpdateSize * pa_frame_size(&self->spec)}; - self->attr.maxlength = -1; - self->attr.tlength = period_size * maxu(device->NumUpdates, 2); - self->attr.prebuf = 0; - self->attr.minreq = period_size; - self->attr.fragsize = -1; + size_t period_size{device->UpdateSize * pa_frame_size(&self->mSpec)}; + self->mAttr.maxlength = -1; + self->mAttr.tlength = period_size * maxu(device->NumUpdates, 2); + self->mAttr.prebuf = 0; + self->mAttr.minreq = period_size; + self->mAttr.fragsize = -1; - self->stream = PulsePlayback_connectStream(self->device_name.c_str(), - self->loop, self->context, flags, &self->attr, &self->spec, &chanmap); - if(!self->stream) return ALC_FALSE; + self->mStream = PulsePlayback_connectStream(self->mDeviceName.c_str(), self->mLoop, + self->mContext, flags, &self->mAttr, &self->mSpec, &chanmap); + if(!self->mStream) return ALC_FALSE; - pa_stream_set_state_callback(self->stream, PulsePlayback_streamStateCallback, self); - pa_stream_set_moved_callback(self->stream, PulsePlayback_streamMovedCallback, self); + pa_stream_set_state_callback(self->mStream, PulsePlayback_streamStateCallback, self); + pa_stream_set_moved_callback(self->mStream, PulsePlayback_streamMovedCallback, self); - self->spec = *(pa_stream_get_sample_spec(self->stream)); - self->mFrameSize = pa_frame_size(&self->spec); + self->mSpec = *(pa_stream_get_sample_spec(self->mStream)); + self->mFrameSize = pa_frame_size(&self->mSpec); - if(device->Frequency != self->spec.rate) + if(device->Frequency != self->mSpec.rate) { /* Server updated our playback rate, so modify the buffer attribs * accordingly. */ device->NumUpdates = static_cast(clampd( - (ALdouble)self->spec.rate/device->Frequency*device->NumUpdates + 0.5, 2.0, 16.0)); + (ALdouble)self->mSpec.rate/device->Frequency*device->NumUpdates + 0.5, 2.0, 16.0)); period_size = device->UpdateSize * self->mFrameSize; - self->attr.maxlength = -1; - self->attr.tlength = period_size * maxu(device->NumUpdates, 2); - self->attr.prebuf = 0; - self->attr.minreq = period_size; + self->mAttr.maxlength = -1; + self->mAttr.tlength = period_size * maxu(device->NumUpdates, 2); + self->mAttr.prebuf = 0; + self->mAttr.minreq = period_size; - op = pa_stream_set_buffer_attr(self->stream, &self->attr, stream_success_callback, - self->loop); - wait_for_operation(op, self->loop); + op = pa_stream_set_buffer_attr(self->mStream, &self->mAttr, stream_success_callback, + self->mLoop); + wait_for_operation(op, self->mLoop); - device->Frequency = self->spec.rate; + device->Frequency = self->mSpec.rate; } - pa_stream_set_buffer_attr_callback(self->stream, PulsePlayback_bufferAttrCallback, self); - PulsePlayback_bufferAttrCallback(self->stream, self); + pa_stream_set_buffer_attr_callback(self->mStream, PulsePlayback_bufferAttrCallback, self); + PulsePlayback_bufferAttrCallback(self->mStream, self); - device->NumUpdates = clampu((self->attr.tlength + self->attr.minreq/2u) / self->attr.minreq, 2u, 16u); - device->UpdateSize = self->attr.minreq / self->mFrameSize; + device->NumUpdates = clampu( + (self->mAttr.tlength + self->mAttr.minreq/2u) / self->mAttr.minreq, 2u, 16u); + device->UpdateSize = self->mAttr.minreq / self->mFrameSize; /* HACK: prebuf should be 0 as that's what we set it to. However on some * systems it comes back as non-0, so we have to make sure the device will @@ -1087,16 +1087,16 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) * may have unintended consequences, but it's better than not starting at * all. */ - if(self->attr.prebuf != 0) + if(self->mAttr.prebuf != 0) { - ALuint len{self->attr.prebuf / self->mFrameSize}; + ALuint len{self->mAttr.prebuf / self->mFrameSize}; if(len <= device->UpdateSize*device->NumUpdates) ERR("Non-0 prebuf, %u samples (%u bytes), device has %u samples\n", - len, self->attr.prebuf, device->UpdateSize*device->NumUpdates); + len, self->mAttr.prebuf, device->UpdateSize*device->NumUpdates); else { ERR("Large prebuf, %u samples (%u bytes), increasing device from %u samples", - len, self->attr.prebuf, device->UpdateSize*device->NumUpdates); + len, self->mAttr.prebuf, device->UpdateSize*device->NumUpdates); device->NumUpdates = (len+device->UpdateSize-1) / device->UpdateSize; } } @@ -1106,22 +1106,22 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) ALCboolean PulsePlayback_start(PulsePlayback *self) { - unique_palock palock{self->loop}; + unique_palock palock{self->mLoop}; - pa_stream_set_write_callback(self->stream, PulsePlayback_streamWriteCallback, self); - pa_operation *op{pa_stream_cork(self->stream, 0, stream_success_callback, self->loop)}; - wait_for_operation(op, self->loop); + pa_stream_set_write_callback(self->mStream, PulsePlayback_streamWriteCallback, self); + pa_operation *op{pa_stream_cork(self->mStream, 0, stream_success_callback, self->mLoop)}; + wait_for_operation(op, self->mLoop); return ALC_TRUE; } void PulsePlayback_stop(PulsePlayback *self) { - unique_palock palock{self->loop}; + unique_palock palock{self->mLoop}; - pa_stream_set_write_callback(self->stream, nullptr, nullptr); - pa_operation *op{pa_stream_cork(self->stream, 1, stream_success_callback, self->loop)}; - wait_for_operation(op, self->loop); + pa_stream_set_write_callback(self->mStream, nullptr, nullptr); + pa_operation *op{pa_stream_cork(self->mStream, 1, stream_success_callback, self->mLoop)}; + wait_for_operation(op, self->mLoop); } @@ -1131,9 +1131,9 @@ ClockLatency PulsePlayback_getClockLatency(PulsePlayback *self) pa_usec_t latency; int neg, err; - { palock_guard _{self->loop}; + { palock_guard _{self->mLoop}; ret.ClockTime = GetDeviceClockTime(self->mDevice); - err = pa_stream_get_latency(self->stream, &latency, &neg); + err = pa_stream_get_latency(self->mStream, &latency, &neg); } if(UNLIKELY(err != 0)) @@ -1157,31 +1157,31 @@ ClockLatency PulsePlayback_getClockLatency(PulsePlayback *self) void PulsePlayback_lock(PulsePlayback *self) { - pa_threaded_mainloop_lock(self->loop); + pa_threaded_mainloop_lock(self->mLoop); } void PulsePlayback_unlock(PulsePlayback *self) { - pa_threaded_mainloop_unlock(self->loop); + pa_threaded_mainloop_unlock(self->mLoop); } struct PulseCapture final : public ALCbackend { - std::string device_name; + std::string mDeviceName; - const void *cap_store{nullptr}; - size_t cap_len{0}; - size_t cap_remain{0}; + const void *mCapStore{nullptr}; + size_t mCapLen{0u}; + size_t mCapRemain{0u}; - ALCuint last_readable{0}; + ALCuint mLastReadable{0u}; - pa_buffer_attr attr; - pa_sample_spec spec; + pa_buffer_attr mAttr{}; + pa_sample_spec mSpec{}; - pa_threaded_mainloop *loop{nullptr}; + pa_threaded_mainloop *mLoop{nullptr}; - pa_stream *stream{nullptr}; - pa_context *context{nullptr}; + pa_stream *mStream{nullptr}; + pa_context *mContext{nullptr}; PulseCapture(ALCdevice *device) noexcept : ALCbackend{device} { } }; @@ -1222,12 +1222,12 @@ void PulseCapture_Construct(PulseCapture *self, ALCdevice *device) void PulseCapture_Destruct(PulseCapture *self) { - if(self->loop) + if(self->mLoop) { - pulse_close(self->loop, self->context, self->stream); - self->loop = nullptr; - self->context = nullptr; - self->stream = nullptr; + pulse_close(self->mLoop, self->mContext, self->mStream); + self->mLoop = nullptr; + self->mContext = nullptr; + self->mStream = nullptr; } self->~PulseCapture(); } @@ -1235,7 +1235,7 @@ void PulseCapture_Destruct(PulseCapture *self) void PulseCapture_deviceCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata) { - auto loop = reinterpret_cast(pdata); + auto loop = static_cast(pdata); if(eol) { @@ -1326,7 +1326,7 @@ void PulseCapture_contextStateCallback(pa_context *context, void *pdata) ERR("Received context failure!\n"); aluHandleDisconnect(self->mDevice, "Capture state failure"); } - pa_threaded_mainloop_signal(self->loop, 0); + pa_threaded_mainloop_signal(self->mLoop, 0); } void PulseCapture_streamStateCallback(pa_stream *stream, void *pdata) @@ -1337,7 +1337,7 @@ void PulseCapture_streamStateCallback(pa_stream *stream, void *pdata) ERR("Received stream failure!\n"); aluHandleDisconnect(self->mDevice, "Capture stream failure"); } - pa_threaded_mainloop_signal(self->loop, 0); + pa_threaded_mainloop_signal(self->mLoop, 0); } @@ -1347,7 +1347,7 @@ void PulseCapture_sourceNameCallback(pa_context *UNUSED(context), const pa_sourc if(eol) { - pa_threaded_mainloop_signal(self->loop, 0); + pa_threaded_mainloop_signal(self->mLoop, 0); return; } @@ -1360,9 +1360,9 @@ void PulseCapture_streamMovedCallback(pa_stream *stream, void *pdata) { auto self = static_cast(pdata); - self->device_name = pa_stream_get_device_name(stream); + self->mDeviceName = pa_stream_get_device_name(stream); - TRACE("Stream moved to %s\n", self->device_name.c_str()); + TRACE("Stream moved to %s\n", self->mDeviceName.c_str()); } @@ -1427,24 +1427,24 @@ ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) device->DeviceName = iter->name; } - std::tie(self->loop, self->context) = pulse_open(PulseCapture_contextStateCallback, self); - if(!self->loop) return ALC_INVALID_VALUE; + std::tie(self->mLoop, self->mContext) = pulse_open(PulseCapture_contextStateCallback, self); + if(!self->mLoop) return ALC_INVALID_VALUE; - unique_palock palock{self->loop}; + unique_palock palock{self->mLoop}; switch(device->FmtType) { case DevFmtUByte: - self->spec.format = PA_SAMPLE_U8; + self->mSpec.format = PA_SAMPLE_U8; break; case DevFmtShort: - self->spec.format = PA_SAMPLE_S16NE; + self->mSpec.format = PA_SAMPLE_S16NE; break; case DevFmtInt: - self->spec.format = PA_SAMPLE_S32NE; + self->mSpec.format = PA_SAMPLE_S32NE; break; case DevFmtFloat: - self->spec.format = PA_SAMPLE_FLOAT32NE; + self->mSpec.format = PA_SAMPLE_FLOAT32NE; break; case DevFmtByte: case DevFmtUShort: @@ -1488,51 +1488,50 @@ ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) return ALC_INVALID_VALUE; } - self->spec.rate = device->Frequency; - self->spec.channels = device->channelsFromFmt(); + self->mSpec.rate = device->Frequency; + self->mSpec.channels = device->channelsFromFmt(); - if(pa_sample_spec_valid(&self->spec) == 0) + if(pa_sample_spec_valid(&self->mSpec) == 0) { ERR("Invalid sample format\n"); return ALC_INVALID_VALUE; } - if(!pa_channel_map_init_auto(&chanmap, self->spec.channels, PA_CHANNEL_MAP_WAVEEX)) + if(!pa_channel_map_init_auto(&chanmap, self->mSpec.channels, PA_CHANNEL_MAP_WAVEEX)) { - ERR("Couldn't build map for channel count (%d)!\n", self->spec.channels); + ERR("Couldn't build map for channel count (%d)!\n", self->mSpec.channels); return ALC_INVALID_VALUE; } ALuint samples{device->UpdateSize * device->NumUpdates}; samples = maxu(samples, 100 * device->Frequency / 1000); - self->attr.minreq = -1; - self->attr.prebuf = -1; - self->attr.maxlength = samples * pa_frame_size(&self->spec); - self->attr.tlength = -1; - self->attr.fragsize = minu(samples, 50*device->Frequency/1000) * - pa_frame_size(&self->spec); + self->mAttr.minreq = -1; + self->mAttr.prebuf = -1; + self->mAttr.maxlength = samples * pa_frame_size(&self->mSpec); + self->mAttr.tlength = -1; + self->mAttr.fragsize = minu(samples, 50*device->Frequency/1000) * + pa_frame_size(&self->mSpec); pa_stream_flags_t flags{PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY}; if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 0)) flags |= PA_STREAM_DONT_MOVE; TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); - self->stream = PulseCapture_connectStream(pulse_name, - self->loop, self->context, flags, &self->attr, &self->spec, &chanmap - ); - if(!self->stream) - return ALC_INVALID_VALUE; - pa_stream_set_moved_callback(self->stream, PulseCapture_streamMovedCallback, self); - pa_stream_set_state_callback(self->stream, PulseCapture_streamStateCallback, self); + self->mStream = PulseCapture_connectStream(pulse_name, self->mLoop, self->mContext, flags, + &self->mAttr, &self->mSpec, &chanmap); + if(!self->mStream) return ALC_INVALID_VALUE; + + pa_stream_set_moved_callback(self->mStream, PulseCapture_streamMovedCallback, self); + pa_stream_set_state_callback(self->mStream, PulseCapture_streamStateCallback, self); - self->device_name = pa_stream_get_device_name(self->stream); + self->mDeviceName = pa_stream_get_device_name(self->mStream); if(device->DeviceName.empty()) { - pa_operation *op{pa_context_get_source_info_by_name(self->context, - self->device_name.c_str(), PulseCapture_sourceNameCallback, self + pa_operation *op{pa_context_get_source_info_by_name(self->mContext, + self->mDeviceName.c_str(), PulseCapture_sourceNameCallback, self )}; - wait_for_operation(op, self->loop); + wait_for_operation(op, self->mLoop); } return ALC_NO_ERROR; @@ -1540,64 +1539,64 @@ ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) ALCboolean PulseCapture_start(PulseCapture *self) { - palock_guard _{self->loop}; - pa_operation *op{pa_stream_cork(self->stream, 0, stream_success_callback, self->loop)}; - wait_for_operation(op, self->loop); + palock_guard _{self->mLoop}; + pa_operation *op{pa_stream_cork(self->mStream, 0, stream_success_callback, self->mLoop)}; + wait_for_operation(op, self->mLoop); return ALC_TRUE; } void PulseCapture_stop(PulseCapture *self) { - palock_guard _{self->loop}; - pa_operation *op{pa_stream_cork(self->stream, 1, stream_success_callback, self->loop)}; - wait_for_operation(op, self->loop); + palock_guard _{self->mLoop}; + pa_operation *op{pa_stream_cork(self->mStream, 1, stream_success_callback, self->mLoop)}; + wait_for_operation(op, self->mLoop); } ALCenum PulseCapture_captureSamples(PulseCapture *self, ALCvoid *buffer, ALCuint samples) { ALCdevice *device{self->mDevice}; - ALCuint todo{samples * static_cast(pa_frame_size(&self->spec))}; + ALCuint todo{samples * static_cast(pa_frame_size(&self->mSpec))}; /* Capture is done in fragment-sized chunks, so we loop until we get all * that's available */ - self->last_readable -= todo; - unique_palock palock{self->loop}; + self->mLastReadable -= todo; + unique_palock palock{self->mLoop}; while(todo > 0) { size_t rem{todo}; - if(self->cap_len == 0) + if(self->mCapLen == 0) { - pa_stream_state_t state{pa_stream_get_state(self->stream)}; + pa_stream_state_t state{pa_stream_get_state(self->mStream)}; if(!PA_STREAM_IS_GOOD(state)) { aluHandleDisconnect(device, "Bad capture state: %u", state); return ALC_INVALID_DEVICE; } - if(pa_stream_peek(self->stream, &self->cap_store, &self->cap_len) < 0) + if(pa_stream_peek(self->mStream, &self->mCapStore, &self->mCapLen) < 0) { ERR("pa_stream_peek() failed: %s\n", - pa_strerror(pa_context_errno(self->context))); + pa_strerror(pa_context_errno(self->mContext))); aluHandleDisconnect(device, "Failed retrieving capture samples: %s", - pa_strerror(pa_context_errno(self->context))); + pa_strerror(pa_context_errno(self->mContext))); return ALC_INVALID_DEVICE; } - self->cap_remain = self->cap_len; + self->mCapRemain = self->mCapLen; } - if(rem > self->cap_remain) - rem = self->cap_remain; + if(rem > self->mCapRemain) + rem = self->mCapRemain; - memcpy(buffer, self->cap_store, rem); + memcpy(buffer, self->mCapStore, rem); buffer = (ALbyte*)buffer + rem; todo -= rem; - self->cap_store = (ALbyte*)self->cap_store + rem; - self->cap_remain -= rem; - if(self->cap_remain == 0) + self->mCapStore = (ALbyte*)self->mCapStore + rem; + self->mCapRemain -= rem; + if(self->mCapRemain == 0) { - pa_stream_drop(self->stream); - self->cap_len = 0; + pa_stream_drop(self->mStream); + self->mCapLen = 0; } } palock.unlock(); @@ -1610,24 +1609,24 @@ ALCenum PulseCapture_captureSamples(PulseCapture *self, ALCvoid *buffer, ALCuint ALCuint PulseCapture_availableSamples(PulseCapture *self) { ALCdevice *device{self->mDevice}; - size_t readable{self->cap_remain}; + size_t readable{self->mCapRemain}; if(device->Connected.load(std::memory_order_acquire)) { - palock_guard _{self->loop}; - size_t got{pa_stream_readable_size(self->stream)}; + palock_guard _{self->mLoop}; + size_t got{pa_stream_readable_size(self->mStream)}; if(static_cast(got) < 0) { ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got)); aluHandleDisconnect(device, "Failed getting readable size: %s", pa_strerror(got)); } - else if(got > self->cap_len) - readable += got - self->cap_len; + else if(got > self->mCapLen) + readable += got - self->mCapLen; } - if(self->last_readable < readable) - self->last_readable = readable; - return self->last_readable / pa_frame_size(&self->spec); + if(self->mLastReadable < readable) + self->mLastReadable = readable; + return self->mLastReadable / pa_frame_size(&self->mSpec); } @@ -1637,9 +1636,9 @@ ClockLatency PulseCapture_getClockLatency(PulseCapture *self) pa_usec_t latency; int neg, err; - { palock_guard _{self->loop}; + { palock_guard _{self->mLoop}; ret.ClockTime = GetDeviceClockTime(self->mDevice); - err = pa_stream_get_latency(self->stream, &latency, &neg); + err = pa_stream_get_latency(self->mStream, &latency, &neg); } if(UNLIKELY(err != 0)) @@ -1658,12 +1657,12 @@ ClockLatency PulseCapture_getClockLatency(PulseCapture *self) void PulseCapture_lock(PulseCapture *self) { - pa_threaded_mainloop_lock(self->loop); + pa_threaded_mainloop_lock(self->mLoop); } void PulseCapture_unlock(PulseCapture *self) { - pa_threaded_mainloop_unlock(self->loop); + pa_threaded_mainloop_unlock(self->mLoop); } } // namespace -- cgit v1.2.3 From 465ab11748cab17536ae6487027e2743134ab26f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Dec 2018 17:48:02 -0800 Subject: Finish renaming backend struct fields --- Alc/backends/qsa.cpp | 36 +++--- Alc/backends/sdl2.cpp | 62 +++++------ Alc/backends/sndio.cpp | 80 +++++++------- Alc/backends/solaris.cpp | 40 +++---- Alc/backends/winmm.cpp | 283 +++++++++++++++++++++++------------------------ 5 files changed, 246 insertions(+), 255 deletions(-) diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index 7469d874..6ceaf0a6 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -171,7 +171,7 @@ void deviceList(int type, al::vector *devmap) /* Wrappers to use an old-style backend with the new interface. */ struct PlaybackWrapper final : public ALCbackend { - std::unique_ptr ExtraData; + std::unique_ptr mExtraData; PlaybackWrapper(ALCdevice *device) noexcept : ALCbackend{device} { } }; @@ -195,7 +195,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) { PlaybackWrapper *self = static_cast(ptr); ALCdevice *device = self->mDevice; - qsa_data *data = self->ExtraData.get(); + qsa_data *data = self->mExtraData.get(); snd_pcm_channel_status_t status; sched_param param; char* write_ptr; @@ -320,14 +320,14 @@ static ALCenum qsa_open_playback(PlaybackWrapper *self, const ALCchar* deviceNam } device->DeviceName = deviceName; - self->ExtraData = std::move(data); + self->mExtraData = std::move(data); return ALC_NO_ERROR; } static void qsa_close_playback(PlaybackWrapper *self) { - qsa_data *data = self->ExtraData.get(); + qsa_data *data = self->mExtraData.get(); if (data->buffer!=NULL) { @@ -337,13 +337,13 @@ static void qsa_close_playback(PlaybackWrapper *self) snd_pcm_close(data->pcmHandle); - self->ExtraData = nullptr; + self->mExtraData = nullptr; } static ALCboolean qsa_reset_playback(PlaybackWrapper *self) { ALCdevice *device = self->mDevice; - qsa_data *data = self->ExtraData.get(); + qsa_data *data = self->mExtraData.get(); int32_t format=-1; switch(device->FmtType) @@ -588,7 +588,7 @@ static ALCboolean qsa_reset_playback(PlaybackWrapper *self) static ALCboolean qsa_start_playback(PlaybackWrapper *self) { - qsa_data *data = self->ExtraData.get(); + qsa_data *data = self->mExtraData.get(); try { data->mKillNow.store(AL_FALSE, std::memory_order_release); @@ -605,7 +605,7 @@ static ALCboolean qsa_start_playback(PlaybackWrapper *self) static void qsa_stop_playback(PlaybackWrapper *self) { - qsa_data *data = self->ExtraData.get(); + qsa_data *data = self->mExtraData.get(); if(data->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !data->mThread.joinable()) return; @@ -621,7 +621,7 @@ static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device) static void PlaybackWrapper_Destruct(PlaybackWrapper *self) { - if(self->ExtraData) + if(self->mExtraData) qsa_close_playback(self); self->~PlaybackWrapper(); @@ -654,7 +654,7 @@ static void PlaybackWrapper_stop(PlaybackWrapper *self) /***********/ struct CaptureWrapper final : public ALCbackend { - std::unique_ptr ExtraData; + std::unique_ptr mExtraData; CaptureWrapper(ALCdevice *device) noexcept : ALCbackend{device} { } }; @@ -767,25 +767,25 @@ static ALCenum qsa_open_capture(CaptureWrapper *self, const ALCchar *deviceName) return ALC_INVALID_VALUE; } - self->ExtraData = std::move(data); + self->mExtraData = std::move(data); return ALC_NO_ERROR; } static void qsa_close_capture(CaptureWrapper *self) { - qsa_data *data = self->ExtraData.get(); + qsa_data *data = self->mExtraData.get(); if (data->pcmHandle!=nullptr) snd_pcm_close(data->pcmHandle); data->pcmHandle = nullptr - self->ExtraData = nullptr; + self->mExtraData = nullptr; } static void qsa_start_capture(CaptureWrapper *self) { - qsa_data *data = self->ExtraData.get(); + qsa_data *data = self->mExtraData.get(); int rstatus; if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0) @@ -807,14 +807,14 @@ static void qsa_start_capture(CaptureWrapper *self) static void qsa_stop_capture(CaptureWrapper *self) { - qsa_data *data = self->ExtraData.get(); + qsa_data *data = self->mExtraData.get(); snd_pcm_capture_flush(data->pcmHandle); } static ALCuint qsa_available_samples(CaptureWrapper *self) { ALCdevice *device = self->mDevice; - qsa_data *data = self->ExtraData.get(); + qsa_data *data = self->mExtraData.get(); snd_pcm_channel_status_t status; ALint frame_size = device->frameSizeFromFmt(); ALint free_size; @@ -846,7 +846,7 @@ static ALCuint qsa_available_samples(CaptureWrapper *self) static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuint samples) { ALCdevice *device = self->mDevice; - qsa_data *data = self->ExtraData.get(); + qsa_data *data = self->mExtraData.get(); char* read_ptr; snd_pcm_channel_status_t status; int selectret; @@ -922,7 +922,7 @@ static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device) static void CaptureWrapper_Destruct(CaptureWrapper *self) { - if(self->ExtraData) + if(self->mExtraData) qsa_close_capture(self); self->~CaptureWrapper(); diff --git a/Alc/backends/sdl2.cpp b/Alc/backends/sdl2.cpp index cb5f875a..12cf7a35 100644 --- a/Alc/backends/sdl2.cpp +++ b/Alc/backends/sdl2.cpp @@ -40,13 +40,13 @@ #endif struct ALCsdl2Backend final : public ALCbackend { - SDL_AudioDeviceID deviceID{0u}; - ALsizei frameSize{0}; + SDL_AudioDeviceID mDeviceID{0u}; + ALsizei mFrameSize{0}; - ALuint Frequency{0u}; - DevFmtChannels FmtChans{}; - DevFmtType FmtType{}; - ALuint UpdateSize{0u}; + ALuint mFrequency{0u}; + DevFmtChannels mFmtChans{}; + DevFmtType mFmtType{}; + ALuint mUpdateSize{0u}; ALCsdl2Backend(ALCdevice *device) noexcept : ALCbackend{device} { } }; @@ -72,19 +72,13 @@ static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device) { new (self) ALCsdl2Backend{device}; SET_VTABLE2(ALCsdl2Backend, ALCbackend, self); - - self->frameSize = device->frameSizeFromFmt(); - self->Frequency = device->Frequency; - self->FmtChans = device->FmtChans; - self->FmtType = device->FmtType; - self->UpdateSize = device->UpdateSize; } static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self) { - if(self->deviceID) - SDL_CloseAudioDevice(self->deviceID); - self->deviceID = 0; + if(self->mDeviceID) + SDL_CloseAudioDevice(self->mDeviceID); + self->mDeviceID = 0; self->~ALCsdl2Backend(); } @@ -94,8 +88,8 @@ static void ALCsdl2Backend_audioCallback(void *ptr, Uint8 *stream, int len) { auto self = static_cast(ptr); - assert((len % self->frameSize) == 0); - aluMixData(self->mDevice, stream, len / self->frameSize); + assert((len % self->mFrameSize) == 0); + aluMixData(self->mDevice, stream, len / self->mFrameSize); } static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) @@ -126,19 +120,19 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) * necessarily the first in the list. */ if(!name || strcmp(name, defaultDeviceName) == 0) - self->deviceID = SDL_OpenAudioDevice(nullptr, SDL_FALSE, &want, &have, + self->mDeviceID = SDL_OpenAudioDevice(nullptr, SDL_FALSE, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE); else { const size_t prefix_len = strlen(DEVNAME_PREFIX); if(strncmp(name, DEVNAME_PREFIX, prefix_len) == 0) - self->deviceID = SDL_OpenAudioDevice(name+prefix_len, SDL_FALSE, &want, &have, + self->mDeviceID = SDL_OpenAudioDevice(name+prefix_len, SDL_FALSE, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE); else - self->deviceID = SDL_OpenAudioDevice(name, SDL_FALSE, &want, &have, + self->mDeviceID = SDL_OpenAudioDevice(name, SDL_FALSE, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE); } - if(self->deviceID == 0) + if(self->mDeviceID == 0) return ALC_INVALID_VALUE; device->Frequency = have.freq; @@ -166,11 +160,11 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) device->UpdateSize = have.samples; device->NumUpdates = 2; /* SDL always (tries to) use two periods. */ - self->frameSize = device->frameSizeFromFmt(); - self->Frequency = device->Frequency; - self->FmtChans = device->FmtChans; - self->FmtType = device->FmtType; - self->UpdateSize = device->UpdateSize; + self->mFrameSize = device->frameSizeFromFmt(); + self->mFrequency = device->Frequency; + self->mFmtChans = device->FmtChans; + self->mFmtType = device->FmtType; + self->mUpdateSize = device->UpdateSize; device->DeviceName = name ? name : defaultDeviceName; return ALC_NO_ERROR; @@ -179,10 +173,10 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self) { ALCdevice *device{self->mDevice}; - device->Frequency = self->Frequency; - device->FmtChans = self->FmtChans; - device->FmtType = self->FmtType; - device->UpdateSize = self->UpdateSize; + device->Frequency = self->mFrequency; + device->FmtChans = self->mFmtChans; + device->FmtType = self->mFmtType; + device->UpdateSize = self->mUpdateSize; device->NumUpdates = 2; SetDefaultWFXChannelOrder(device); return ALC_TRUE; @@ -190,23 +184,23 @@ static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self) static ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self) { - SDL_PauseAudioDevice(self->deviceID, 0); + SDL_PauseAudioDevice(self->mDeviceID, 0); return ALC_TRUE; } static void ALCsdl2Backend_stop(ALCsdl2Backend *self) { - SDL_PauseAudioDevice(self->deviceID, 1); + SDL_PauseAudioDevice(self->mDeviceID, 1); } static void ALCsdl2Backend_lock(ALCsdl2Backend *self) { - SDL_LockAudioDevice(self->deviceID); + SDL_LockAudioDevice(self->mDeviceID); } static void ALCsdl2Backend_unlock(ALCsdl2Backend *self) { - SDL_UnlockAudioDevice(self->deviceID); + SDL_UnlockAudioDevice(self->mDeviceID); } diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index ef9ce549..a37c1cd3 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -40,10 +40,10 @@ static const ALCchar sndio_device[] = "SndIO Default"; struct SndioPlayback final : public ALCbackend { - sio_hdl *sndHandle{nullptr}; + sio_hdl *mSndHandle{nullptr}; - ALvoid *mix_data{nullptr}; - ALsizei data_size{0}; + ALvoid *mMixData{nullptr}; + ALsizei mDataSize{0}; std::atomic mKillNow{AL_TRUE}; std::thread mThread; @@ -77,12 +77,12 @@ static void SndioPlayback_Construct(SndioPlayback *self, ALCdevice *device) static void SndioPlayback_Destruct(SndioPlayback *self) { - if(self->sndHandle) - sio_close(self->sndHandle); - self->sndHandle = nullptr; + if(self->mSndHandle) + sio_close(self->mSndHandle); + self->mSndHandle = nullptr; - al_free(self->mix_data); - self->mix_data = nullptr; + al_free(self->mMixData); + self->mMixData = nullptr; self->~SndioPlayback(); } @@ -102,15 +102,15 @@ static int SndioPlayback_mixerProc(SndioPlayback *self) while(!self->mKillNow.load(std::memory_order_acquire) && device->Connected.load(std::memory_order_acquire)) { - ALsizei len = self->data_size; - ALubyte *WritePtr = static_cast(self->mix_data); + ALsizei len = self->mDataSize; + ALubyte *WritePtr = static_cast(self->mMixData); SndioPlayback_lock(self); aluMixData(device, WritePtr, len/frameSize); SndioPlayback_unlock(self); while(len > 0 && !self->mKillNow.load(std::memory_order_acquire)) { - wrote = sio_write(self->sndHandle, WritePtr, len); + wrote = sio_write(self->mSndHandle, WritePtr, len); if(wrote == 0) { ERR("sio_write failed\n"); @@ -138,8 +138,8 @@ static ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name) else if(strcmp(name, sndio_device) != 0) return ALC_INVALID_VALUE; - self->sndHandle = sio_open(nullptr, SIO_PLAY, 0); - if(self->sndHandle == nullptr) + self->mSndHandle = sio_open(nullptr, SIO_PLAY, 0); + if(self->mSndHandle == nullptr) { ERR("Could not open device\n"); return ALC_INVALID_VALUE; @@ -193,7 +193,7 @@ static ALCboolean SndioPlayback_reset(SndioPlayback *self) par.appbufsz = device->UpdateSize * (device->NumUpdates-1); if(!par.appbufsz) par.appbufsz = device->UpdateSize; - if(!sio_setpar(self->sndHandle, &par) || !sio_getpar(self->sndHandle, &par)) + if(!sio_setpar(self->mSndHandle, &par) || !sio_getpar(self->mSndHandle, &par)) { ERR("Failed to set device parameters\n"); return ALC_FALSE; @@ -238,11 +238,11 @@ static ALCboolean SndioPlayback_start(SndioPlayback *self) { ALCdevice *device{self->mDevice}; - self->data_size = device->UpdateSize * device->frameSizeFromFmt(); - al_free(self->mix_data); - self->mix_data = al_calloc(16, self->data_size); + self->mDataSize = device->UpdateSize * device->frameSizeFromFmt(); + al_free(self->mMixData); + self->mMixData = al_calloc(16, self->mDataSize); - if(!sio_start(self->sndHandle)) + if(!sio_start(self->mSndHandle)) { ERR("Error starting playback\n"); return ALC_FALSE; @@ -258,7 +258,7 @@ static ALCboolean SndioPlayback_start(SndioPlayback *self) } catch(...) { } - sio_stop(self->sndHandle); + sio_stop(self->mSndHandle); return ALC_FALSE; } @@ -268,18 +268,18 @@ static void SndioPlayback_stop(SndioPlayback *self) return; self->mThread.join(); - if(!sio_stop(self->sndHandle)) + if(!sio_stop(self->mSndHandle)) ERR("Error stopping device\n"); - al_free(self->mix_data); - self->mix_data = nullptr; + al_free(self->mMixData); + self->mMixData = nullptr; } struct SndioCapture final : public ALCbackend { - sio_hdl *sndHandle{nullptr}; + sio_hdl *mSndHandle{nullptr}; - RingBufferPtr ring{nullptr}; + RingBufferPtr mRing; std::atomic mKillNow{AL_TRUE}; std::thread mThread; @@ -313,9 +313,9 @@ static void SndioCapture_Construct(SndioCapture *self, ALCdevice *device) static void SndioCapture_Destruct(SndioCapture *self) { - if(self->sndHandle) - sio_close(self->sndHandle); - self->sndHandle = nullptr; + if(self->mSndHandle) + sio_close(self->mSndHandle); + self->mSndHandle = nullptr; self->~SndioCapture(); } @@ -324,7 +324,7 @@ static void SndioCapture_Destruct(SndioCapture *self) static int SndioCapture_recordProc(SndioCapture *self) { ALCdevice *device{self->mDevice}; - RingBuffer *ring{self->ring.get()}; + RingBuffer *ring{self->mRing.get()}; SetRTPriority(); althrd_setname(RECORD_THREAD_NAME); @@ -341,7 +341,7 @@ static int SndioCapture_recordProc(SndioCapture *self) if(todo == 0) { static char junk[4096]; - sio_read(self->sndHandle, junk, minz(sizeof(junk)/frameSize, device->UpdateSize)*frameSize); + sio_read(self->mSndHandle, junk, minz(sizeof(junk)/frameSize, device->UpdateSize)*frameSize); continue; } @@ -356,7 +356,7 @@ static int SndioCapture_recordProc(SndioCapture *self) if(!data.first.len) data.first = data.second; - got = sio_read(self->sndHandle, data.first.buf, minz(todo-total, data.first.len)); + got = sio_read(self->mSndHandle, data.first.buf, minz(todo-total, data.first.len)); if(!got) { SndioCapture_lock(self); @@ -386,8 +386,8 @@ static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) else if(strcmp(name, sndio_device) != 0) return ALC_INVALID_VALUE; - self->sndHandle = sio_open(nullptr, SIO_REC, 0); - if(self->sndHandle == nullptr) + self->mSndHandle = sio_open(nullptr, SIO_REC, 0); + if(self->mSndHandle == nullptr) { ERR("Could not open device\n"); return ALC_INVALID_VALUE; @@ -438,7 +438,7 @@ static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) device->UpdateSize = par.round; device->NumUpdates = maxu(par.appbufsz/par.round, 1); - if(!sio_setpar(self->sndHandle, &par) || !sio_getpar(self->sndHandle, &par)) + if(!sio_setpar(self->mSndHandle, &par) || !sio_getpar(self->mSndHandle, &par)) { ERR("Failed to set device parameters\n"); return ALC_INVALID_VALUE; @@ -465,8 +465,8 @@ static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) return ALC_INVALID_VALUE; } - self->ring = CreateRingBuffer(device->UpdateSize*device->NumUpdates, par.bps*par.rchan, false); - if(!self->ring) + self->mRing = CreateRingBuffer(device->UpdateSize*device->NumUpdates, par.bps*par.rchan, false); + if(!self->mRing) { ERR("Failed to allocate %u-byte ringbuffer\n", device->UpdateSize*device->NumUpdates*par.bps*par.rchan); @@ -481,7 +481,7 @@ static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) static ALCboolean SndioCapture_start(SndioCapture *self) { - if(!sio_start(self->sndHandle)) + if(!sio_start(self->mSndHandle)) { ERR("Error starting playback\n"); return ALC_FALSE; @@ -497,7 +497,7 @@ static ALCboolean SndioCapture_start(SndioCapture *self) } catch(...) { } - sio_stop(self->sndHandle); + sio_stop(self->mSndHandle); return ALC_FALSE; } @@ -507,20 +507,20 @@ static void SndioCapture_stop(SndioCapture *self) return; self->mThread.join(); - if(!sio_stop(self->sndHandle)) + if(!sio_stop(self->mSndHandle)) ERR("Error stopping device\n"); } static ALCenum SndioCapture_captureSamples(SndioCapture *self, void *buffer, ALCuint samples) { - RingBuffer *ring{self->ring.get()}; + RingBuffer *ring{self->mRing.get()}; ring->read(buffer, samples); return ALC_NO_ERROR; } static ALCuint SndioCapture_availableSamples(SndioCapture *self) { - RingBuffer *ring{self->ring.get()}; + RingBuffer *ring{self->mRing.get()}; return ring->readSpace(); } diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index bbbe1612..ab622927 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -47,10 +47,10 @@ struct ALCsolarisBackend final : public ALCbackend { - int fd{-1}; + int mFd{-1}; - ALubyte *mix_data{nullptr}; - int data_size{0}; + ALubyte *mMixData{nullptr}; + int mDataSize{0}; std::atomic mKillNow{AL_TRUE}; std::thread mThread; @@ -89,13 +89,13 @@ static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *devi static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self) { - if(self->fd != -1) - close(self->fd); - self->fd = -1; + if(self->mFd != -1) + close(self->mFd); + self->mFd = -1; - free(self->mix_data); - self->mix_data = nullptr; - self->data_size = 0; + free(self->mMixData); + self->mMixData = nullptr; + self->mDataSize = 0; self->~ALCsolarisBackend(); } @@ -115,7 +115,7 @@ static int ALCsolarisBackend_mixerProc(ALCsolarisBackend *self) device->Connected.load(std::memory_order_acquire)) { pollfd pollitem{}; - pollitem.fd = self->fd; + pollitem.fd = self->mFd; pollitem.events = POLLOUT; ALCsolarisBackend_unlock(self); @@ -135,12 +135,12 @@ static int ALCsolarisBackend_mixerProc(ALCsolarisBackend *self) continue; } - ALubyte *write_ptr{self->mix_data}; - int to_write{self->data_size}; + ALubyte *write_ptr{self->mMixData}; + int to_write{self->mDataSize}; aluMixData(device, write_ptr, to_write/frame_size); while(to_write > 0 && !self->mKillNow.load()) { - ssize_t wrote{write(self->fd, write_ptr, to_write)}; + ssize_t wrote{write(self->mFd, write_ptr, to_write)}; if(wrote < 0) { if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) @@ -170,8 +170,8 @@ static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *na else if(strcmp(name, solaris_device) != 0) return ALC_INVALID_VALUE; - self->fd = open(solaris_driver, O_WRONLY); - if(self->fd == -1) + self->mFd = open(solaris_driver, O_WRONLY); + if(self->mFd == -1) { ERR("Could not open %s: %s\n", solaris_driver, strerror(errno)); return ALC_INVALID_VALUE; @@ -224,7 +224,7 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) frameSize = numChannels * device->bytesFromFmt(); info.play.buffer_size = device->UpdateSize*device->NumUpdates * frameSize; - if(ioctl(self->fd, AUDIO_SETINFO, &info) < 0) + if(ioctl(self->mFd, AUDIO_SETINFO, &info) < 0) { ERR("ioctl failed: %s\n", strerror(errno)); return ALC_FALSE; @@ -252,9 +252,9 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) SetDefaultChannelOrder(device); - free(self->mix_data); - self->data_size = device->UpdateSize * device->frameSizeFromFmt(); - self->mix_data = static_cast(calloc(1, self->data_size)); + free(self->mMixData); + self->mDataSize = device->UpdateSize * device->frameSizeFromFmt(); + self->mMixData = static_cast(calloc(1, self->mDataSize)); return ALC_TRUE; } @@ -281,7 +281,7 @@ static void ALCsolarisBackend_stop(ALCsolarisBackend *self) self->mThread.join(); - if(ioctl(self->fd, AUDIO_DRAIN) < 0) + if(ioctl(self->mFd, AUDIO_DRAIN) < 0) ERR("Error draining device: %s\n", strerror(errno)); } diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 31c39c52..1258b6a2 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -121,14 +121,14 @@ void ProbeCaptureDevices(void) struct ALCwinmmPlayback final : public ALCbackend { - std::atomic Writable{0u}; - al::semaphore Sem; - int Idx{0}; - std::array WaveBuffer; + std::atomic mWritable{0u}; + al::semaphore mSem; + int mIdx{0}; + std::array mWaveBuffer; - HWAVEOUT OutHdl{nullptr}; + HWAVEOUT mOutHdl{nullptr}; - WAVEFORMATEX Format{}; + WAVEFORMATEX mFormat{}; std::atomic mKillNow{AL_TRUE}; std::thread mThread; @@ -161,17 +161,17 @@ void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device) new (self) ALCwinmmPlayback{device}; SET_VTABLE2(ALCwinmmPlayback, ALCbackend, self); - std::fill(self->WaveBuffer.begin(), self->WaveBuffer.end(), WAVEHDR{}); + std::fill(self->mWaveBuffer.begin(), self->mWaveBuffer.end(), WAVEHDR{}); } void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self) { - if(self->OutHdl) - waveOutClose(self->OutHdl); - self->OutHdl = nullptr; + if(self->mOutHdl) + waveOutClose(self->mOutHdl); + self->mOutHdl = nullptr; - al_free(self->WaveBuffer[0].lpData); - std::fill(self->WaveBuffer.begin(), self->WaveBuffer.end(), WAVEHDR{}); + al_free(self->mWaveBuffer[0].lpData); + std::fill(self->mWaveBuffer.begin(), self->mWaveBuffer.end(), WAVEHDR{}); self->~ALCwinmmPlayback(); } @@ -190,8 +190,8 @@ void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT UNUSED(device), UINT msg, return; auto self = reinterpret_cast(instance); - self->Writable.fetch_add(1, std::memory_order_acq_rel); - self->Sem.post(); + self->mWritable.fetch_add(1, std::memory_order_acq_rel); + self->mSem.post(); } FORCE_ALIGN int ALCwinmmPlayback_mixerProc(ALCwinmmPlayback *self) @@ -205,25 +205,25 @@ FORCE_ALIGN int ALCwinmmPlayback_mixerProc(ALCwinmmPlayback *self) while(!self->mKillNow.load(std::memory_order_acquire) && device->Connected.load(std::memory_order_acquire)) { - ALsizei todo = self->Writable.load(std::memory_order_acquire); + ALsizei todo = self->mWritable.load(std::memory_order_acquire); if(todo < 1) { ALCwinmmPlayback_unlock(self); - self->Sem.wait(); + self->mSem.wait(); ALCwinmmPlayback_lock(self); continue; } - int widx{self->Idx}; + int widx{self->mIdx}; do { - WAVEHDR &waveHdr = self->WaveBuffer[widx]; - widx = (widx+1) % self->WaveBuffer.size(); + WAVEHDR &waveHdr = self->mWaveBuffer[widx]; + widx = (widx+1) % self->mWaveBuffer.size(); aluMixData(device, waveHdr.lpData, device->UpdateSize); - self->Writable.fetch_sub(1, std::memory_order_acq_rel); - waveOutWrite(self->OutHdl, &waveHdr, sizeof(WAVEHDR)); + self->mWritable.fetch_sub(1, std::memory_order_acq_rel); + waveOutWrite(self->mOutHdl, &waveHdr, sizeof(WAVEHDR)); } while(--todo); - self->Idx = widx; + self->mIdx = widx; } ALCwinmmPlayback_unlock(self); @@ -243,32 +243,32 @@ ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *deviceName) std::find(PlaybackDevices.cbegin(), PlaybackDevices.cend(), deviceName) : PlaybackDevices.cbegin(); if(iter == PlaybackDevices.cend()) return ALC_INVALID_VALUE; - UINT DeviceID{static_cast(std::distance(PlaybackDevices.cbegin(), iter))}; + auto DeviceID = static_cast(std::distance(PlaybackDevices.cbegin(), iter)); retry_open: - self->Format = WAVEFORMATEX{}; + self->mFormat = WAVEFORMATEX{}; if(device->FmtType == DevFmtFloat) { - self->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; - self->Format.wBitsPerSample = 32; + self->mFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + self->mFormat.wBitsPerSample = 32; } else { - self->Format.wFormatTag = WAVE_FORMAT_PCM; + self->mFormat.wFormatTag = WAVE_FORMAT_PCM; if(device->FmtType == DevFmtUByte || device->FmtType == DevFmtByte) - self->Format.wBitsPerSample = 8; + self->mFormat.wBitsPerSample = 8; else - self->Format.wBitsPerSample = 16; + self->mFormat.wBitsPerSample = 16; } - self->Format.nChannels = ((device->FmtChans == DevFmtMono) ? 1 : 2); - self->Format.nBlockAlign = self->Format.wBitsPerSample * - self->Format.nChannels / 8; - self->Format.nSamplesPerSec = device->Frequency; - self->Format.nAvgBytesPerSec = self->Format.nSamplesPerSec * - self->Format.nBlockAlign; - self->Format.cbSize = 0; - - MMRESULT res{waveOutOpen(&self->OutHdl, DeviceID, &self->Format, + self->mFormat.nChannels = ((device->FmtChans == DevFmtMono) ? 1 : 2); + self->mFormat.nBlockAlign = self->mFormat.wBitsPerSample * + self->mFormat.nChannels / 8; + self->mFormat.nSamplesPerSec = device->Frequency; + self->mFormat.nAvgBytesPerSec = self->mFormat.nSamplesPerSec * + self->mFormat.nBlockAlign; + self->mFormat.cbSize = 0; + + MMRESULT res{waveOutOpen(&self->mOutHdl, DeviceID, &self->mFormat, (DWORD_PTR)&ALCwinmmPlayback_waveOutProc, (DWORD_PTR)self, CALLBACK_FUNCTION )}; if(res != MMSYSERR_NOERROR) @@ -290,67 +290,66 @@ ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self) { ALCdevice *device{self->mDevice}; - device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize * - self->Format.nSamplesPerSec / - device->Frequency); + device->UpdateSize = static_cast( + (ALuint64)device->UpdateSize * self->mFormat.nSamplesPerSec / device->Frequency); device->UpdateSize = (device->UpdateSize*device->NumUpdates + 3) / 4; device->NumUpdates = 4; - device->Frequency = self->Format.nSamplesPerSec; + device->Frequency = self->mFormat.nSamplesPerSec; - if(self->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) + if(self->mFormat.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) { - if(self->Format.wBitsPerSample == 32) + if(self->mFormat.wBitsPerSample == 32) device->FmtType = DevFmtFloat; else { - ERR("Unhandled IEEE float sample depth: %d\n", self->Format.wBitsPerSample); + ERR("Unhandled IEEE float sample depth: %d\n", self->mFormat.wBitsPerSample); return ALC_FALSE; } } - else if(self->Format.wFormatTag == WAVE_FORMAT_PCM) + else if(self->mFormat.wFormatTag == WAVE_FORMAT_PCM) { - if(self->Format.wBitsPerSample == 16) + if(self->mFormat.wBitsPerSample == 16) device->FmtType = DevFmtShort; - else if(self->Format.wBitsPerSample == 8) + else if(self->mFormat.wBitsPerSample == 8) device->FmtType = DevFmtUByte; else { - ERR("Unhandled PCM sample depth: %d\n", self->Format.wBitsPerSample); + ERR("Unhandled PCM sample depth: %d\n", self->mFormat.wBitsPerSample); return ALC_FALSE; } } else { - ERR("Unhandled format tag: 0x%04x\n", self->Format.wFormatTag); + ERR("Unhandled format tag: 0x%04x\n", self->mFormat.wFormatTag); return ALC_FALSE; } - if(self->Format.nChannels == 2) + if(self->mFormat.nChannels == 2) device->FmtChans = DevFmtStereo; - else if(self->Format.nChannels == 1) + else if(self->mFormat.nChannels == 1) device->FmtChans = DevFmtMono; else { - ERR("Unhandled channel count: %d\n", self->Format.nChannels); + ERR("Unhandled channel count: %d\n", self->mFormat.nChannels); return ALC_FALSE; } SetDefaultWFXChannelOrder(device); ALuint BufferSize{device->UpdateSize * device->frameSizeFromFmt()}; - al_free(self->WaveBuffer[0].lpData); - self->WaveBuffer[0] = WAVEHDR{}; - self->WaveBuffer[0].lpData = static_cast(al_calloc(16, - BufferSize * self->WaveBuffer.size())); - self->WaveBuffer[0].dwBufferLength = BufferSize; - for(size_t i{1};i < self->WaveBuffer.size();i++) + al_free(self->mWaveBuffer[0].lpData); + self->mWaveBuffer[0] = WAVEHDR{}; + self->mWaveBuffer[0].lpData = static_cast(al_calloc(16, + BufferSize * self->mWaveBuffer.size())); + self->mWaveBuffer[0].dwBufferLength = BufferSize; + for(size_t i{1};i < self->mWaveBuffer.size();i++) { - self->WaveBuffer[i] = WAVEHDR{}; - self->WaveBuffer[i].lpData = self->WaveBuffer[i-1].lpData + - self->WaveBuffer[i-1].dwBufferLength; - self->WaveBuffer[i].dwBufferLength = BufferSize; + self->mWaveBuffer[i] = WAVEHDR{}; + self->mWaveBuffer[i].lpData = self->mWaveBuffer[i-1].lpData + + self->mWaveBuffer[i-1].dwBufferLength; + self->mWaveBuffer[i].dwBufferLength = BufferSize; } - self->Idx = 0; + self->mIdx = 0; return ALC_TRUE; } @@ -358,11 +357,11 @@ ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self) ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self) { try { - std::for_each(self->WaveBuffer.begin(), self->WaveBuffer.end(), + std::for_each(self->mWaveBuffer.begin(), self->mWaveBuffer.end(), [self](WAVEHDR &waveHdr) -> void - { waveOutPrepareHeader(self->OutHdl, &waveHdr, static_cast(sizeof(WAVEHDR))); } + { waveOutPrepareHeader(self->mOutHdl, &waveHdr, static_cast(sizeof(WAVEHDR))); } ); - self->Writable.store(static_cast(self->WaveBuffer.size()), + self->mWritable.store(static_cast(self->mWaveBuffer.size()), std::memory_order_release); self->mKillNow.store(AL_FALSE, std::memory_order_release); @@ -383,27 +382,27 @@ void ALCwinmmPlayback_stop(ALCwinmmPlayback *self) return; self->mThread.join(); - while(self->Writable.load(std::memory_order_acquire) < self->WaveBuffer.size()) - self->Sem.wait(); - std::for_each(self->WaveBuffer.begin(), self->WaveBuffer.end(), + while(self->mWritable.load(std::memory_order_acquire) < self->mWaveBuffer.size()) + self->mSem.wait(); + std::for_each(self->mWaveBuffer.begin(), self->mWaveBuffer.end(), [self](WAVEHDR &waveHdr) -> void - { waveOutUnprepareHeader(self->OutHdl, &waveHdr, sizeof(WAVEHDR)); } + { waveOutUnprepareHeader(self->mOutHdl, &waveHdr, sizeof(WAVEHDR)); } ); - self->Writable.store(0, std::memory_order_release); + self->mWritable.store(0, std::memory_order_release); } struct ALCwinmmCapture final : public ALCbackend { - std::atomic Readable{0u}; - al::semaphore Sem; - int Idx{0}; - std::array WaveBuffer; + std::atomic mReadable{0u}; + al::semaphore mSem; + int mIdx{0}; + std::array mWaveBuffer{}; - HWAVEIN InHdl{nullptr}; + HWAVEIN mInHdl{nullptr}; - RingBufferPtr Ring{nullptr}; + RingBufferPtr mRing{nullptr}; - WAVEFORMATEX Format{}; + WAVEFORMATEX mFormat{}; std::atomic mKillNow{AL_TRUE}; std::thread mThread; @@ -435,19 +434,17 @@ void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device) { new (self) ALCwinmmCapture{device}; SET_VTABLE2(ALCwinmmCapture, ALCbackend, self); - - std::fill(self->WaveBuffer.begin(), self->WaveBuffer.end(), WAVEHDR{}); } void ALCwinmmCapture_Destruct(ALCwinmmCapture *self) { // Close the Wave device - if(self->InHdl) - waveInClose(self->InHdl); - self->InHdl = nullptr; + if(self->mInHdl) + waveInClose(self->mInHdl); + self->mInHdl = nullptr; - al_free(self->WaveBuffer[0].lpData); - std::fill(self->WaveBuffer.begin(), self->WaveBuffer.end(), WAVEHDR{}); + al_free(self->mWaveBuffer[0].lpData); + std::fill(self->mWaveBuffer.begin(), self->mWaveBuffer.end(), WAVEHDR{}); self->~ALCwinmmCapture(); } @@ -466,14 +463,14 @@ void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN UNUSED(device), UINT msg, return; auto self = reinterpret_cast(instance); - self->Readable.fetch_add(1, std::memory_order_acq_rel); - self->Sem.post(); + self->mReadable.fetch_add(1, std::memory_order_acq_rel); + self->mSem.post(); } int ALCwinmmCapture_captureProc(ALCwinmmCapture *self) { ALCdevice *device{self->mDevice}; - RingBuffer *ring{self->Ring.get()}; + RingBuffer *ring{self->mRing.get()}; althrd_setname(RECORD_THREAD_NAME); @@ -481,25 +478,25 @@ int ALCwinmmCapture_captureProc(ALCwinmmCapture *self) while(!self->mKillNow.load(std::memory_order_acquire) && device->Connected.load(std::memory_order_acquire)) { - ALsizei todo = self->Readable.load(std::memory_order_acquire); + ALuint todo{self->mReadable.load(std::memory_order_acquire)}; if(todo < 1) { ALCwinmmCapture_unlock(self); - self->Sem.wait(); + self->mSem.wait(); ALCwinmmCapture_lock(self); continue; } - int widx{self->Idx}; + int widx{self->mIdx}; do { - WAVEHDR &waveHdr = self->WaveBuffer[widx]; - widx = (widx+1) % self->WaveBuffer.size(); + WAVEHDR &waveHdr = self->mWaveBuffer[widx]; + widx = (widx+1) % self->mWaveBuffer.size(); - ring->write(waveHdr.lpData, waveHdr.dwBytesRecorded / self->Format.nBlockAlign); - self->Readable.fetch_sub(1, std::memory_order_acq_rel); - waveInAddBuffer(self->InHdl, &waveHdr, sizeof(WAVEHDR)); + ring->write(waveHdr.lpData, waveHdr.dwBytesRecorded / self->mFormat.nBlockAlign); + self->mReadable.fetch_sub(1, std::memory_order_acq_rel); + waveInAddBuffer(self->mInHdl, &waveHdr, sizeof(WAVEHDR)); } while(--todo); - self->Idx = widx; + self->mIdx = widx; } ALCwinmmCapture_unlock(self); @@ -519,7 +516,7 @@ ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName) std::find(CaptureDevices.cbegin(), CaptureDevices.cend(), deviceName) : CaptureDevices.cbegin(); if(iter == CaptureDevices.cend()) return ALC_INVALID_VALUE; - UINT DeviceID{static_cast(std::distance(CaptureDevices.cbegin(), iter))}; + auto DeviceID = static_cast(std::distance(CaptureDevices.cbegin(), iter)); switch(device->FmtChans) { @@ -550,19 +547,19 @@ ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName) return ALC_INVALID_ENUM; } - self->Format = WAVEFORMATEX{}; - self->Format.wFormatTag = (device->FmtType == DevFmtFloat) ? - WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM; - self->Format.nChannels = device->channelsFromFmt(); - self->Format.wBitsPerSample = device->bytesFromFmt() * 8; - self->Format.nBlockAlign = self->Format.wBitsPerSample * - self->Format.nChannels / 8; - self->Format.nSamplesPerSec = device->Frequency; - self->Format.nAvgBytesPerSec = self->Format.nSamplesPerSec * - self->Format.nBlockAlign; - self->Format.cbSize = 0; - - MMRESULT res{waveInOpen(&self->InHdl, DeviceID, &self->Format, + self->mFormat = WAVEFORMATEX{}; + self->mFormat.wFormatTag = (device->FmtType == DevFmtFloat) ? + WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM; + self->mFormat.nChannels = device->channelsFromFmt(); + self->mFormat.wBitsPerSample = device->bytesFromFmt() * 8; + self->mFormat.nBlockAlign = self->mFormat.wBitsPerSample * + self->mFormat.nChannels / 8; + self->mFormat.nSamplesPerSec = device->Frequency; + self->mFormat.nAvgBytesPerSec = self->mFormat.nSamplesPerSec * + self->mFormat.nBlockAlign; + self->mFormat.cbSize = 0; + + MMRESULT res{waveInOpen(&self->mInHdl, DeviceID, &self->mFormat, (DWORD_PTR)&ALCwinmmCapture_waveInProc, (DWORD_PTR)self, CALLBACK_FUNCTION )}; if(res != MMSYSERR_NOERROR) @@ -572,28 +569,28 @@ ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName) } // Ensure each buffer is 50ms each - DWORD BufferSize{self->Format.nAvgBytesPerSec / 20}; - BufferSize -= (BufferSize % self->Format.nBlockAlign); + DWORD BufferSize{self->mFormat.nAvgBytesPerSec / 20u}; + BufferSize -= (BufferSize % self->mFormat.nBlockAlign); // Allocate circular memory buffer for the captured audio // Make sure circular buffer is at least 100ms in size - auto CapturedDataSize = static_cast( - std::max(device->UpdateSize*device->NumUpdates, BufferSize*self->WaveBuffer.size()) - ); - - self->Ring = CreateRingBuffer(CapturedDataSize, self->Format.nBlockAlign, false); - if(!self->Ring) return ALC_INVALID_VALUE; - - al_free(self->WaveBuffer[0].lpData); - self->WaveBuffer[0] = WAVEHDR{}; - self->WaveBuffer[0].lpData = static_cast(al_calloc(16, BufferSize*4)); - self->WaveBuffer[0].dwBufferLength = BufferSize; - for(size_t i{1};i < self->WaveBuffer.size();++i) + ALuint CapturedDataSize{device->UpdateSize*device->NumUpdates}; + CapturedDataSize = static_cast( + std::max(CapturedDataSize, BufferSize*self->mWaveBuffer.size())); + + self->mRing = CreateRingBuffer(CapturedDataSize, self->mFormat.nBlockAlign, false); + if(!self->mRing) return ALC_INVALID_VALUE; + + al_free(self->mWaveBuffer[0].lpData); + self->mWaveBuffer[0] = WAVEHDR{}; + self->mWaveBuffer[0].lpData = static_cast(al_calloc(16, BufferSize*4)); + self->mWaveBuffer[0].dwBufferLength = BufferSize; + for(size_t i{1};i < self->mWaveBuffer.size();++i) { - self->WaveBuffer[i] = WAVEHDR{}; - self->WaveBuffer[i].lpData = self->WaveBuffer[i-1].lpData + - self->WaveBuffer[i-1].dwBufferLength; - self->WaveBuffer[i].dwBufferLength = self->WaveBuffer[i-1].dwBufferLength; + self->mWaveBuffer[i] = WAVEHDR{}; + self->mWaveBuffer[i].lpData = self->mWaveBuffer[i-1].lpData + + self->mWaveBuffer[i-1].dwBufferLength; + self->mWaveBuffer[i].dwBufferLength = self->mWaveBuffer[i-1].dwBufferLength; } device->DeviceName = CaptureDevices[DeviceID]; @@ -603,16 +600,16 @@ ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName) ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self) { try { - for(size_t i{0};i < self->WaveBuffer.size();++i) + for(size_t i{0};i < self->mWaveBuffer.size();++i) { - waveInPrepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); - waveInAddBuffer(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + waveInPrepareHeader(self->mInHdl, &self->mWaveBuffer[i], sizeof(WAVEHDR)); + waveInAddBuffer(self->mInHdl, &self->mWaveBuffer[i], sizeof(WAVEHDR)); } self->mKillNow.store(AL_FALSE, std::memory_order_release); self->mThread = std::thread(ALCwinmmCapture_captureProc, self); - waveInStart(self->InHdl); + waveInStart(self->mInHdl); return ALC_TRUE; } catch(std::exception& e) { @@ -625,33 +622,33 @@ ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self) void ALCwinmmCapture_stop(ALCwinmmCapture *self) { - waveInStop(self->InHdl); + waveInStop(self->mInHdl); self->mKillNow.store(AL_TRUE, std::memory_order_release); if(self->mThread.joinable()) { - self->Sem.post(); + self->mSem.post(); self->mThread.join(); } - waveInReset(self->InHdl); - for(size_t i{0};i < self->WaveBuffer.size();++i) - waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + waveInReset(self->mInHdl); + for(size_t i{0};i < self->mWaveBuffer.size();++i) + waveInUnprepareHeader(self->mInHdl, &self->mWaveBuffer[i], sizeof(WAVEHDR)); - self->Readable.store(0, std::memory_order_release); - self->Idx = 0; + self->mReadable.store(0, std::memory_order_release); + self->mIdx = 0; } ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples) { - RingBuffer *ring{self->Ring.get()}; + RingBuffer *ring{self->mRing.get()}; ring->read(buffer, samples); return ALC_NO_ERROR; } ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self) { - RingBuffer *ring{self->Ring.get()}; + RingBuffer *ring{self->mRing.get()}; return (ALCuint)ring->readSpace(); } -- cgit v1.2.3 From 0f3645902886b52102ffec51636c2fd8f1e7c3c5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Dec 2018 18:33:49 -0800 Subject: Use vectors instead of malloc'd buffers --- Alc/backends/sndio.cpp | 46 +++++++++++++++++++--------------------------- Alc/backends/solaris.cpp | 28 +++++++++++++--------------- 2 files changed, 32 insertions(+), 42 deletions(-) diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index a37c1cd3..e4d1e9f0 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -31,21 +31,23 @@ #include "alMain.h" #include "alu.h" #include "threads.h" +#include "vector.h" #include "ringbuffer.h" #include +namespace { + static const ALCchar sndio_device[] = "SndIO Default"; struct SndioPlayback final : public ALCbackend { sio_hdl *mSndHandle{nullptr}; - ALvoid *mMixData{nullptr}; - ALsizei mDataSize{0}; + al::vector mBuffer; - std::atomic mKillNow{AL_TRUE}; + std::atomic mKillNow{true}; std::thread mThread; SndioPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } @@ -81,9 +83,6 @@ static void SndioPlayback_Destruct(SndioPlayback *self) sio_close(self->mSndHandle); self->mSndHandle = nullptr; - al_free(self->mMixData); - self->mMixData = nullptr; - self->~SndioPlayback(); } @@ -91,26 +90,24 @@ static void SndioPlayback_Destruct(SndioPlayback *self) static int SndioPlayback_mixerProc(SndioPlayback *self) { ALCdevice *device{self->mDevice}; - ALsizei frameSize; - size_t wrote; SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - frameSize = device->frameSizeFromFmt(); + const ALsizei frameSize{device->frameSizeFromFmt()}; while(!self->mKillNow.load(std::memory_order_acquire) && device->Connected.load(std::memory_order_acquire)) { - ALsizei len = self->mDataSize; - ALubyte *WritePtr = static_cast(self->mMixData); + auto WritePtr = static_cast(self->mBuffer.data()); + size_t len{self->mBuffer.size()}; SndioPlayback_lock(self); aluMixData(device, WritePtr, len/frameSize); SndioPlayback_unlock(self); while(len > 0 && !self->mKillNow.load(std::memory_order_acquire)) { - wrote = sio_write(self->mSndHandle, WritePtr, len); + size_t wrote{sio_write(self->mSndHandle, WritePtr, len)}; if(wrote == 0) { ERR("sio_write failed\n"); @@ -226,22 +223,19 @@ static ALCboolean SndioPlayback_reset(SndioPlayback *self) return ALC_FALSE; } + SetDefaultChannelOrder(device); + device->UpdateSize = par.round; device->NumUpdates = (par.bufsz/par.round) + 1; - SetDefaultChannelOrder(device); + self->mBuffer.resize(device->UpdateSize * device->frameSizeFromFmt()); + std::fill(self->mBuffer.begin(), self->mBuffer.end(), 0); return ALC_TRUE; } static ALCboolean SndioPlayback_start(SndioPlayback *self) { - ALCdevice *device{self->mDevice}; - - self->mDataSize = device->UpdateSize * device->frameSizeFromFmt(); - al_free(self->mMixData); - self->mMixData = al_calloc(16, self->mDataSize); - if(!sio_start(self->mSndHandle)) { ERR("Error starting playback\n"); @@ -249,7 +243,7 @@ static ALCboolean SndioPlayback_start(SndioPlayback *self) } try { - self->mKillNow.store(AL_FALSE, std::memory_order_release); + self->mKillNow.store(false, std::memory_order_release); self->mThread = std::thread(SndioPlayback_mixerProc, self); return ALC_TRUE; } @@ -264,15 +258,12 @@ static ALCboolean SndioPlayback_start(SndioPlayback *self) static void SndioPlayback_stop(SndioPlayback *self) { - if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->mThread.joinable()) + if(self->mKillNow.exchange(true, std::memory_order_acq_rel) || !self->mThread.joinable()) return; self->mThread.join(); if(!sio_stop(self->mSndHandle)) ERR("Error stopping device\n"); - - al_free(self->mMixData); - self->mMixData = nullptr; } @@ -281,7 +272,7 @@ struct SndioCapture final : public ALCbackend { RingBufferPtr mRing; - std::atomic mKillNow{AL_TRUE}; + std::atomic mKillNow{true}; std::thread mThread; SndioCapture(ALCdevice *device) noexcept : ALCbackend{device} { } @@ -488,7 +479,7 @@ static ALCboolean SndioCapture_start(SndioCapture *self) } try { - self->mKillNow.store(AL_FALSE, std::memory_order_release); + self->mKillNow.store(false, std::memory_order_release); self->mThread = std::thread(SndioCapture_recordProc, self); return ALC_TRUE; } @@ -503,7 +494,7 @@ static ALCboolean SndioCapture_start(SndioCapture *self) static void SndioCapture_stop(SndioCapture *self) { - if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->mThread.joinable()) + if(self->mKillNow.exchange(true, std::memory_order_acq_rel) || !self->mThread.joinable()) return; self->mThread.join(); @@ -524,6 +515,7 @@ static ALCuint SndioCapture_availableSamples(SndioCapture *self) return ring->readSpace(); } +} // namespace BackendFactory &SndIOBackendFactory::getFactory() { diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index ab622927..e56b1c81 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -41,18 +41,20 @@ #include "alu.h" #include "alconfig.h" #include "threads.h" +#include "vector.h" #include "compat.h" #include +namespace { + struct ALCsolarisBackend final : public ALCbackend { int mFd{-1}; - ALubyte *mMixData{nullptr}; - int mDataSize{0}; + al::vector mBuffer; - std::atomic mKillNow{AL_TRUE}; + std::atomic mKillNow{true}; std::thread mThread; ALCsolarisBackend(ALCdevice *device) noexcept : ALCbackend{device} { } @@ -93,10 +95,6 @@ static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self) close(self->mFd); self->mFd = -1; - free(self->mMixData); - self->mMixData = nullptr; - self->mDataSize = 0; - self->~ALCsolarisBackend(); } @@ -135,10 +133,10 @@ static int ALCsolarisBackend_mixerProc(ALCsolarisBackend *self) continue; } - ALubyte *write_ptr{self->mMixData}; - int to_write{self->mDataSize}; + ALubyte *write_ptr{self->mBuffer.data()}; + size_t to_write{self->mBuffer.size()}; aluMixData(device, write_ptr, to_write/frame_size); - while(to_write > 0 && !self->mKillNow.load()) + while(to_write > 0 && !self->mKillNow.load(std::memory_order_acquire)) { ssize_t wrote{write(self->mFd, write_ptr, to_write)}; if(wrote < 0) @@ -252,9 +250,8 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) SetDefaultChannelOrder(device); - free(self->mMixData); - self->mDataSize = device->UpdateSize * device->frameSizeFromFmt(); - self->mMixData = static_cast(calloc(1, self->mDataSize)); + self->mBuffer.resize(device->UpdateSize * device->frameSizeFromFmt()); + std::fill(self->mBuffer.begin(), self->mBuffer.end(), 0); return ALC_TRUE; } @@ -262,7 +259,7 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self) { try { - self->mKillNow.store(AL_FALSE); + self->mKillNow.store(false, std::memory_order_release); self->mThread = std::thread(ALCsolarisBackend_mixerProc, self); return ALC_TRUE; } @@ -276,7 +273,7 @@ static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self) static void ALCsolarisBackend_stop(ALCsolarisBackend *self) { - if(self->mKillNow.exchange(AL_TRUE) || !self->mThread.joinable()) + if(self->mKillNow.exchange(true, std::memory_order_acq_rel) || !self->mThread.joinable()) return; self->mThread.join(); @@ -285,6 +282,7 @@ static void ALCsolarisBackend_stop(ALCsolarisBackend *self) ERR("Error draining device: %s\n", strerror(errno)); } +} // namespace BackendFactory &SolarisBackendFactory::getFactory() { -- cgit v1.2.3 From 015a4b060b2f0461f412e519c2a219ed1e7465c2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Dec 2018 19:38:02 -0800 Subject: Make some ancillary methods into member functions --- Alc/backends/alsa.cpp | 123 ++++++++++++++++++++++---------------------- Alc/backends/coreaudio.cpp | 125 +++++++++++++++++++++++++-------------------- 2 files changed, 131 insertions(+), 117 deletions(-) diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index f0838d25..f363fc4e 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -423,19 +423,19 @@ int verify_state(snd_pcm_t *handle) struct ALCplaybackAlsa final : public ALCbackend { + ALCplaybackAlsa(ALCdevice *device) noexcept : ALCbackend{device} { } + + int mixerProc(); + int mixerNoMMapProc(); + snd_pcm_t *mPcmHandle{nullptr}; al::vector mBuffer; std::atomic mKillNow{AL_TRUE}; std::thread mThread; - - ALCplaybackAlsa(ALCdevice *device) noexcept : ALCbackend{device} { } }; -int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self); -int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self); - void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device); void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self); ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name); @@ -467,28 +467,26 @@ void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self) } -int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) +int ALCplaybackAlsa::mixerProc() { - ALCdevice *device{self->mDevice}; - SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - snd_pcm_uframes_t update_size{device->UpdateSize}; - snd_pcm_uframes_t num_updates{device->NumUpdates}; - while(!self->mKillNow.load(std::memory_order_acquire)) + snd_pcm_uframes_t update_size{mDevice->UpdateSize}; + snd_pcm_uframes_t num_updates{mDevice->NumUpdates}; + while(!mKillNow.load(std::memory_order_acquire)) { - int state{verify_state(self->mPcmHandle)}; + int state{verify_state(mPcmHandle)}; if(state < 0) { ERR("Invalid state detected: %s\n", snd_strerror(state)); - ALCplaybackAlsa_lock(self); - aluHandleDisconnect(device, "Bad state: %s", snd_strerror(state)); - ALCplaybackAlsa_unlock(self); + ALCplaybackAlsa_lock(this); + aluHandleDisconnect(mDevice, "Bad state: %s", snd_strerror(state)); + ALCplaybackAlsa_unlock(this); break; } - snd_pcm_sframes_t avail{snd_pcm_avail_update(self->mPcmHandle)}; + snd_pcm_sframes_t avail{snd_pcm_avail_update(mPcmHandle)}; if(avail < 0) { ERR("available update failed: %s\n", snd_strerror(avail)); @@ -498,7 +496,7 @@ int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) if((snd_pcm_uframes_t)avail > update_size*(num_updates+1)) { WARN("available samples exceeds the buffer size\n"); - snd_pcm_reset(self->mPcmHandle); + snd_pcm_reset(mPcmHandle); continue; } @@ -507,28 +505,28 @@ int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) { if(state != SND_PCM_STATE_RUNNING) { - int err{snd_pcm_start(self->mPcmHandle)}; + int err{snd_pcm_start(mPcmHandle)}; if(err < 0) { ERR("start failed: %s\n", snd_strerror(err)); continue; } } - if(snd_pcm_wait(self->mPcmHandle, 1000) == 0) + if(snd_pcm_wait(mPcmHandle, 1000) == 0) ERR("Wait timeout... buffer size too low?\n"); continue; } avail -= avail%update_size; // it is possible that contiguous areas are smaller, thus we use a loop - ALCplaybackAlsa_lock(self); + ALCplaybackAlsa_lock(this); while(avail > 0) { snd_pcm_uframes_t frames{static_cast(avail)}; const snd_pcm_channel_area_t *areas{}; snd_pcm_uframes_t offset{}; - int err{snd_pcm_mmap_begin(self->mPcmHandle, &areas, &offset, &frames)}; + int err{snd_pcm_mmap_begin(mPcmHandle, &areas, &offset, &frames)}; if(err < 0) { ERR("mmap begin error: %s\n", snd_strerror(err)); @@ -536,9 +534,9 @@ int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) } char *WritePtr{(char*)areas->addr + (offset * areas->step / 8)}; - aluMixData(device, WritePtr, frames); + aluMixData(mDevice, WritePtr, frames); - snd_pcm_sframes_t commitres{snd_pcm_mmap_commit(self->mPcmHandle, offset, frames)}; + snd_pcm_sframes_t commitres{snd_pcm_mmap_commit(mPcmHandle, offset, frames)}; if(commitres < 0 || (commitres-frames) != 0) { ERR("mmap commit error: %s\n", @@ -548,34 +546,32 @@ int ALCplaybackAlsa_mixerProc(ALCplaybackAlsa *self) avail -= frames; } - ALCplaybackAlsa_unlock(self); + ALCplaybackAlsa_unlock(this); } return 0; } -int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self) +int ALCplaybackAlsa::mixerNoMMapProc() { - ALCdevice *device{self->mDevice}; - SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - snd_pcm_uframes_t update_size{device->UpdateSize}; - snd_pcm_uframes_t num_updates{device->NumUpdates}; - while(!self->mKillNow.load(std::memory_order_acquire)) + snd_pcm_uframes_t update_size{mDevice->UpdateSize}; + snd_pcm_uframes_t num_updates{mDevice->NumUpdates}; + while(!mKillNow.load(std::memory_order_acquire)) { - int state{verify_state(self->mPcmHandle)}; + int state{verify_state(mPcmHandle)}; if(state < 0) { ERR("Invalid state detected: %s\n", snd_strerror(state)); - ALCplaybackAlsa_lock(self); - aluHandleDisconnect(device, "Bad state: %s", snd_strerror(state)); - ALCplaybackAlsa_unlock(self); + ALCplaybackAlsa_lock(this); + aluHandleDisconnect(mDevice, "Bad state: %s", snd_strerror(state)); + ALCplaybackAlsa_unlock(this); break; } - snd_pcm_sframes_t avail{snd_pcm_avail_update(self->mPcmHandle)}; + snd_pcm_sframes_t avail{snd_pcm_avail_update(mPcmHandle)}; if(avail < 0) { ERR("available update failed: %s\n", snd_strerror(avail)); @@ -585,7 +581,7 @@ int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self) if((snd_pcm_uframes_t)avail > update_size*num_updates) { WARN("available samples exceeds the buffer size\n"); - snd_pcm_reset(self->mPcmHandle); + snd_pcm_reset(mPcmHandle); continue; } @@ -593,26 +589,26 @@ int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self) { if(state != SND_PCM_STATE_RUNNING) { - int err{snd_pcm_start(self->mPcmHandle)}; + int err{snd_pcm_start(mPcmHandle)}; if(err < 0) { ERR("start failed: %s\n", snd_strerror(err)); continue; } } - if(snd_pcm_wait(self->mPcmHandle, 1000) == 0) + if(snd_pcm_wait(mPcmHandle, 1000) == 0) ERR("Wait timeout... buffer size too low?\n"); continue; } - ALCplaybackAlsa_lock(self); - char *WritePtr{self->mBuffer.data()}; - avail = snd_pcm_bytes_to_frames(self->mPcmHandle, self->mBuffer.size()); - aluMixData(device, WritePtr, avail); + ALCplaybackAlsa_lock(this); + char *WritePtr{mBuffer.data()}; + avail = snd_pcm_bytes_to_frames(mPcmHandle, mBuffer.size()); + aluMixData(mDevice, WritePtr, avail); while(avail > 0) { - int ret = snd_pcm_writei(self->mPcmHandle, WritePtr, avail); - switch (ret) + snd_pcm_sframes_t ret{snd_pcm_writei(mPcmHandle, WritePtr, avail)}; + switch(ret) { case -EAGAIN: continue; @@ -621,26 +617,25 @@ int ALCplaybackAlsa_mixerNoMMapProc(ALCplaybackAlsa *self) #endif case -EPIPE: case -EINTR: - ret = snd_pcm_recover(self->mPcmHandle, ret, 1); + ret = snd_pcm_recover(mPcmHandle, ret, 1); if(ret < 0) avail = 0; break; default: - if (ret >= 0) + if(ret >= 0) { - WritePtr += snd_pcm_frames_to_bytes(self->mPcmHandle, ret); + WritePtr += snd_pcm_frames_to_bytes(mPcmHandle, ret); avail -= ret; } break; } - if (ret < 0) + if(ret < 0) { - ret = snd_pcm_prepare(self->mPcmHandle); - if(ret < 0) - break; + ret = snd_pcm_prepare(mPcmHandle); + if(ret < 0) break; } } - ALCplaybackAlsa_unlock(self); + ALCplaybackAlsa_unlock(this); } return 0; @@ -841,7 +836,6 @@ error: ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) { ALCdevice *device{self->mDevice}; - int (*thread_func)(ALCplaybackAlsa*){}; snd_pcm_hw_params_t *hp{}; snd_pcm_access_t access; const char *funcerr; @@ -853,13 +847,21 @@ ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) /* retrieve configuration info */ CHECK(snd_pcm_hw_params_get_access(hp, &access)); #undef CHECK + if(0) + { + error: + ERR("%s failed: %s\n", funcerr, snd_strerror(err)); + if(hp) snd_pcm_hw_params_free(hp); + return ALC_FALSE; + } snd_pcm_hw_params_free(hp); hp = nullptr; + int (ALCplaybackAlsa::*thread_func)(){}; if(access == SND_PCM_ACCESS_RW_INTERLEAVED) { self->mBuffer.resize(snd_pcm_frames_to_bytes(self->mPcmHandle, device->UpdateSize)); - thread_func = ALCplaybackAlsa_mixerNoMMapProc; + thread_func = &ALCplaybackAlsa::mixerNoMMapProc; } else { @@ -869,12 +871,12 @@ ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) ERR("snd_pcm_prepare(data->mPcmHandle) failed: %s\n", snd_strerror(err)); return ALC_FALSE; } - thread_func = ALCplaybackAlsa_mixerProc; + thread_func = &ALCplaybackAlsa::mixerProc; } try { self->mKillNow.store(AL_FALSE, std::memory_order_release); - self->mThread = std::thread(thread_func, self); + self->mThread = std::thread{std::mem_fn(thread_func), self}; return ALC_TRUE; } catch(std::exception& e) { @@ -884,11 +886,6 @@ ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) } self->mBuffer.clear(); return ALC_FALSE; - -error: - ERR("%s failed: %s\n", funcerr, snd_strerror(err)); - if(hp) snd_pcm_hw_params_free(hp); - return ALC_FALSE; } void ALCplaybackAlsa_stop(ALCplaybackAlsa *self) @@ -924,6 +921,8 @@ ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self) struct ALCcaptureAlsa final : public ALCbackend { + ALCcaptureAlsa(ALCdevice *device) noexcept : ALCbackend{device} { } + snd_pcm_t *mPcmHandle{nullptr}; al::vector mBuffer; @@ -932,8 +931,6 @@ struct ALCcaptureAlsa final : public ALCbackend { RingBufferPtr mRing{nullptr}; snd_pcm_sframes_t mLastAvail{0}; - - ALCcaptureAlsa(ALCdevice *device) noexcept : ALCbackend{device} { } }; void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device); diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index 62a88da1..9af370ca 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -36,16 +36,25 @@ #include +namespace { + static const ALCchar ca_device[] = "CoreAudio Default"; struct ALCcoreAudioPlayback final : public ALCbackend { + ALCcoreAudioPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } + + static OSStatus MixerProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, + AudioBufferList *ioData); + OSStatus MixerProc(AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, + AudioBufferList *ioData); + AudioUnit mAudioUnit; ALuint mFrameSize{0u}; AudioStreamBasicDescription mFormat{}; // This is the OpenAL format as a CoreAudio ASBD - - ALCcoreAudioPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } }; static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device); @@ -79,34 +88,34 @@ static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self) } -static OSStatus ALCcoreAudioPlayback_MixerProc(void *inRefCon, - AudioUnitRenderActionFlags* UNUSED(ioActionFlags), const AudioTimeStamp* UNUSED(inTimeStamp), - UInt32 UNUSED(inBusNumber), UInt32 UNUSED(inNumberFrames), AudioBufferList *ioData) +OSStatus ALCcoreAudioPlayback::MixerProcC(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { - auto self = static_cast(inRefCon); - - ALCcoreAudioPlayback_lock(self); - aluMixData(self->mDevice, ioData->mBuffers[0].mData, - ioData->mBuffers[0].mDataByteSize / self->mFrameSize); - ALCcoreAudioPlayback_unlock(self); + return static_cast(inRefCon)->MixerProc(ioActionFlags, inTimeStamp, + inBusNumber, inNumberFrames, ioData); +} +OSStatus ALCcoreAudioPlayback::MixerProc(AudioUnitRenderActionFlags* UNUSED(ioActionFlags), + const AudioTimeStamp* UNUSED(inTimeStamp), UInt32 UNUSED(inBusNumber), + UInt32 UNUSED(inNumberFrames), AudioBufferList *ioData) +{ + ALCcoreAudioPlayback_lock(this); + aluMixData(mDevice, ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize/mFrameSize); + ALCcoreAudioPlayback_unlock(this); return noErr; } static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name) { - ALCdevice *device{self->mDevice}; - AudioComponentDescription desc; - AudioComponent comp; - OSStatus err; - if(!name) name = ca_device; else if(strcmp(name, ca_device) != 0) return ALC_INVALID_VALUE; /* open the default output unit */ + AudioComponentDescription desc{}; desc.componentType = kAudioUnitType_Output; #if TARGET_OS_IOS desc.componentSubType = kAudioUnitSubType_RemoteIO; @@ -117,14 +126,14 @@ static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCch desc.componentFlags = 0; desc.componentFlagsMask = 0; - comp = AudioComponentFindNext(NULL, &desc); - if(comp == NULL) + AudioComponent comp{AudioComponentFindNext(NULL, &desc)}; + if(comp == nullptr) { ERR("AudioComponentFindNext failed\n"); return ALC_INVALID_VALUE; } - err = AudioComponentInstanceNew(comp, &self->mAudioUnit); + OSStatus err{AudioComponentInstanceNew(comp, &self->mAudioUnit)}; if(err != noErr) { ERR("AudioComponentInstanceNew failed\n"); @@ -140,6 +149,7 @@ static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCch return ALC_INVALID_VALUE; } + ALCdevice *device{self->mDevice}; device->DeviceName = name; return ALC_NO_ERROR; } @@ -147,17 +157,14 @@ static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCch static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) { ALCdevice *device{self->mDevice}; - AudioStreamBasicDescription streamFormat; - AURenderCallbackStruct input; - OSStatus err; - UInt32 size; - err = AudioUnitUninitialize(self->mAudioUnit); + OSStatus err{AudioUnitUninitialize(self->mAudioUnit)}; if(err != noErr) ERR("-- AudioUnitUninitialize failed.\n"); /* retrieve default output unit's properties (output side) */ - size = sizeof(AudioStreamBasicDescription); + AudioStreamBasicDescription streamFormat{}; + auto size = static_cast(sizeof(AudioStreamBasicDescription)); err = AudioUnitGetProperty(self->mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, &size); if(err != noErr || size != sizeof(AudioStreamBasicDescription)) @@ -187,9 +194,8 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) if(device->Frequency != streamFormat.mSampleRate) { - device->NumUpdates = (ALuint)((ALuint64)device->NumUpdates * - streamFormat.mSampleRate / - device->Frequency); + device->NumUpdates = static_cast( + (ALuint64)device->NumUpdates*streamFormat.mSampleRate/device->Frequency); device->Frequency = streamFormat.mSampleRate; } @@ -272,7 +278,8 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) /* setup callback */ self->mFrameSize = device->frameSizeFromFmt(); - input.inputProc = ALCcoreAudioPlayback_MixerProc; + AURenderCallbackStruct input{}; + input.inputProc = ALCcoreAudioPlayback::MixerProcC; input.inputProcRefCon = self; err = AudioUnitSetProperty(self->mAudioUnit, kAudioUnitProperty_SetRenderCallback, @@ -296,25 +303,33 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self) { - OSStatus err = AudioOutputUnitStart(self->mAudioUnit); + OSStatus err{AudioOutputUnitStart(self->mAudioUnit)}; if(err != noErr) { ERR("AudioOutputUnitStart failed\n"); return ALC_FALSE; } - return ALC_TRUE; } static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self) { - OSStatus err = AudioOutputUnitStop(self->mAudioUnit); + OSStatus err{AudioOutputUnitStop(self->mAudioUnit)}; if(err != noErr) ERR("AudioOutputUnitStop failed\n"); } struct ALCcoreAudioCapture final : public ALCbackend { + ALCcoreAudioCapture(ALCdevice *device) noexcept : ALCbackend{device} { } + + static OSStatus RecordProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, + AudioBufferList *ioData); + OSStatus RecordProc(AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, + UInt32 inNumberFrames, AudioBufferList *ioData); + AudioUnit mAudioUnit{0}; ALuint mFrameSize{0u}; @@ -323,8 +338,6 @@ struct ALCcoreAudioCapture final : public ALCbackend { SampleConverterPtr mConverter; RingBufferPtr mRing{nullptr}; - - ALCcoreAudioCapture(ALCdevice *device) noexcept : ALCbackend{device} { } }; static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device); @@ -359,30 +372,34 @@ static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self) } -static OSStatus ALCcoreAudioCapture_RecordProc(void *inRefCon, - AudioUnitRenderActionFlags* UNUSED(ioActionFlags), - const AudioTimeStamp *inTimeStamp, UInt32 UNUSED(inBusNumber), - UInt32 inNumberFrames, AudioBufferList* UNUSED(ioData)) +OSStatus ALCcoreAudioCapture::RecordProcC(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) +{ + return static_cast(inRefCon)->RecordProc(ioActionFlags, inTimeStamp, + inBusNumber, inNumberFrames, ioData); +} + +OSStatus ALCcoreAudioCapture::RecordProc(AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, + AudioBufferList *ioData) { - auto self = static_cast(inRefCon); - RingBuffer *ring{self->mRing.get()}; AudioUnitRenderActionFlags flags = 0; union { ALbyte _[sizeof(AudioBufferList) + sizeof(AudioBuffer)]; AudioBufferList list; } audiobuf = { { 0 } }; - OSStatus err; - auto rec_vec = ring->getWriteVector(); + auto rec_vec = mRing->getWriteVector(); // Fill the ringbuffer's first segment with data from the input device size_t total_read{minz(rec_vec.first.len, inNumberFrames)}; audiobuf.list.mNumberBuffers = 1; - audiobuf.list.mBuffers[0].mNumberChannels = self->mFormat.mChannelsPerFrame; + audiobuf.list.mBuffers[0].mNumberChannels = mFormat.mChannelsPerFrame; audiobuf.list.mBuffers[0].mData = rec_vec.first.buf; - audiobuf.list.mBuffers[0].mDataByteSize = total_read * self->mFormat.mBytesPerFrame; - err = AudioUnitRender(self->mAudioUnit, &flags, inTimeStamp, 1, inNumberFrames, - &audiobuf.list); + audiobuf.list.mBuffers[0].mDataByteSize = total_read * mFormat.mBytesPerFrame; + OSStatus err{AudioUnitRender(mAudioUnit, &flags, inTimeStamp, 1, inNumberFrames, + &audiobuf.list)}; if(err == noErr && inNumberFrames > rec_vec.first.len && rec_vec.second.len > 0) { /* If there's still more to get and there's space in the ringbuffer's @@ -393,11 +410,10 @@ static OSStatus ALCcoreAudioCapture_RecordProc(void *inRefCon, total_read += toread; audiobuf.list.mNumberBuffers = 1; - audiobuf.list.mBuffers[0].mNumberChannels = self->mFormat.mChannelsPerFrame; + audiobuf.list.mBuffers[0].mNumberChannels = mFormat.mChannelsPerFrame; audiobuf.list.mBuffers[0].mData = rec_vec.second.buf; - audiobuf.list.mBuffers[0].mDataByteSize = toread * self->mFormat.mBytesPerFrame; - err = AudioUnitRender(self->mAudioUnit, &flags, inTimeStamp, 1, inNumberFrames, - &audiobuf.list); + audiobuf.list.mBuffers[0].mDataByteSize = toread * mFormat.mBytesPerFrame; + err = AudioUnitRender(mAudioUnit, &flags, inTimeStamp, 1, inNumberFrames, &audiobuf.list); } if(err != noErr) { @@ -405,7 +421,7 @@ static OSStatus ALCcoreAudioCapture_RecordProc(void *inRefCon, return err; } - ring->writeAdvance(total_read); + mRing->writeAdvance(total_read); return noErr; } @@ -510,7 +526,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar #endif // set capture callback - input.inputProc = ALCcoreAudioCapture_RecordProc; + input.inputProc = ALCcoreAudioCapture::RecordProcC; input.inputProcRefCon = self; err = AudioUnitSetProperty(self->mAudioUnit, kAudioOutputUnitProperty_SetInputCallback, @@ -646,7 +662,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self) { - OSStatus err = AudioOutputUnitStart(self->mAudioUnit); + OSStatus err{AudioOutputUnitStart(self->mAudioUnit)}; if(err != noErr) { ERR("AudioOutputUnitStart failed\n"); @@ -657,7 +673,7 @@ static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self) static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self) { - OSStatus err = AudioOutputUnitStop(self->mAudioUnit); + OSStatus err{AudioOutputUnitStop(self->mAudioUnit)}; if(err != noErr) ERR("AudioOutputUnitStop failed\n"); } @@ -699,6 +715,7 @@ static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self) return SampleConverterAvailableOut(self->mConverter.get(), ring->readSpace()); } +} // namespace BackendFactory &CoreAudioBackendFactory::getFactory() { -- cgit v1.2.3 From 885f68268feb21c7c7fbb6f01c7bd899b9846bfe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Dec 2018 20:24:35 -0800 Subject: Turn more methods into member functions --- Alc/backends/alsa.cpp | 24 ++++---- Alc/backends/coreaudio.cpp | 22 +++++--- Alc/backends/dsound.cpp | 133 +++++++++++++++++++++++---------------------- 3 files changed, 94 insertions(+), 85 deletions(-) diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index f363fc4e..17af2364 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -424,6 +424,7 @@ int verify_state(snd_pcm_t *handle) struct ALCplaybackAlsa final : public ALCbackend { ALCplaybackAlsa(ALCdevice *device) noexcept : ALCbackend{device} { } + ~ALCplaybackAlsa() override; int mixerProc(); int mixerNoMMapProc(); @@ -458,12 +459,13 @@ void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device) } void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self) -{ - if(self->mPcmHandle) - snd_pcm_close(self->mPcmHandle); - self->mPcmHandle = nullptr; +{ self->~ALCplaybackAlsa(); } - self->~ALCplaybackAlsa(); +ALCplaybackAlsa::~ALCplaybackAlsa() +{ + if(mPcmHandle) + snd_pcm_close(mPcmHandle); + mPcmHandle = nullptr; } @@ -922,6 +924,7 @@ ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self) struct ALCcaptureAlsa final : public ALCbackend { ALCcaptureAlsa(ALCdevice *device) noexcept : ALCbackend{device} { } + ~ALCcaptureAlsa() override; snd_pcm_t *mPcmHandle{nullptr}; @@ -956,12 +959,13 @@ void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device) } void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self) -{ - if(self->mPcmHandle) - snd_pcm_close(self->mPcmHandle); - self->mPcmHandle = nullptr; +{ self->~ALCcaptureAlsa(); } - self->~ALCcaptureAlsa(); +ALCcaptureAlsa::~ALCcaptureAlsa() +{ + if(mPcmHandle) + snd_pcm_close(mPcmHandle); + mPcmHandle = nullptr; } diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index 9af370ca..82312d67 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -43,6 +43,7 @@ static const ALCchar ca_device[] = "CoreAudio Default"; struct ALCcoreAudioPlayback final : public ALCbackend { ALCcoreAudioPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } + ~ALCcoreAudioPlayback() override; static OSStatus MixerProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, @@ -80,11 +81,12 @@ static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice } static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self) -{ - AudioUnitUninitialize(self->mAudioUnit); - AudioComponentInstanceDispose(self->mAudioUnit); +{ self->~ALCcoreAudioPlayback(); } - self->~ALCcoreAudioPlayback(); +ALCcoreAudioPlayback::~ALCcoreAudioPlayback() +{ + AudioUnitUninitialize(mAudioUnit); + AudioComponentInstanceDispose(mAudioUnit); } @@ -322,6 +324,7 @@ static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self) struct ALCcoreAudioCapture final : public ALCbackend { ALCcoreAudioCapture(ALCdevice *device) noexcept : ALCbackend{device} { } + ~ALCcoreAudioCapture() override; static OSStatus RecordProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, @@ -363,12 +366,13 @@ static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice * } static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self) -{ - if(self->mAudioUnit) - AudioComponentInstanceDispose(self->mAudioUnit); - self->mAudioUnit = 0; +{ self->~ALCcoreAudioCapture(); } - self->~ALCcoreAudioCapture(); +ALCcoreAudioCapture::~ALCcoreAudioCapture() +{ + if(mAudioUnit) + AudioComponentInstanceDispose(mAudioUnit); + mAudioUnit = 0; } diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 421c3107..83cc712f 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -185,6 +185,11 @@ BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR* UNUS struct ALCdsoundPlayback final : public ALCbackend { + ALCdsoundPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } + ~ALCdsoundPlayback() override; + + int mixerProc(); + IDirectSound *mDS{nullptr}; IDirectSoundBuffer *mPrimaryBuffer{nullptr}; IDirectSoundBuffer *mBuffer{nullptr}; @@ -193,12 +198,8 @@ struct ALCdsoundPlayback final : public ALCbackend { std::atomic mKillNow{AL_TRUE}; std::thread mThread; - - ALCdsoundPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } }; -int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self); - void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device); void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self); ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *name); @@ -222,80 +223,77 @@ void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device) } void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self) -{ - if(self->mNotifies) - self->mNotifies->Release(); - self->mNotifies = nullptr; - if(self->mBuffer) - self->mBuffer->Release(); - self->mBuffer = nullptr; - if(self->mPrimaryBuffer) - self->mPrimaryBuffer->Release(); - self->mPrimaryBuffer = nullptr; - - if(self->mDS) - self->mDS->Release(); - self->mDS = nullptr; - if(self->mNotifyEvent) - CloseHandle(self->mNotifyEvent); - self->mNotifyEvent = nullptr; +{ self->~ALCdsoundPlayback(); } - self->~ALCdsoundPlayback(); +ALCdsoundPlayback::~ALCdsoundPlayback() +{ + if(mNotifies) + mNotifies->Release(); + mNotifies = nullptr; + if(mBuffer) + mBuffer->Release(); + mBuffer = nullptr; + if(mPrimaryBuffer) + mPrimaryBuffer->Release(); + mPrimaryBuffer = nullptr; + + if(mDS) + mDS->Release(); + mDS = nullptr; + if(mNotifyEvent) + CloseHandle(mNotifyEvent); + mNotifyEvent = nullptr; } -FORCE_ALIGN int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) +FORCE_ALIGN int ALCdsoundPlayback::mixerProc() { - ALCdevice *device{self->mDevice}; - SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - IDirectSoundBuffer *const Buffer{self->mBuffer}; - DSBCAPS DSBCaps{}; DSBCaps.dwSize = sizeof(DSBCaps); - HRESULT err{Buffer->GetCaps(&DSBCaps)}; + HRESULT err{mBuffer->GetCaps(&DSBCaps)}; if(FAILED(err)) { ERR("Failed to get buffer caps: 0x%lx\n", err); - ALCdsoundPlayback_lock(self); - aluHandleDisconnect(device, "Failure retrieving playback buffer info: 0x%lx", err); - ALCdsoundPlayback_unlock(self); + ALCdsoundPlayback_lock(this); + aluHandleDisconnect(mDevice, "Failure retrieving playback buffer info: 0x%lx", err); + ALCdsoundPlayback_unlock(this); return 1; } - ALsizei FrameSize{device->frameSizeFromFmt()}; - DWORD FragSize{device->UpdateSize * FrameSize}; + ALsizei FrameSize{mDevice->frameSizeFromFmt()}; + DWORD FragSize{mDevice->UpdateSize * FrameSize}; bool Playing{false}; DWORD LastCursor{0u}; - Buffer->GetCurrentPosition(&LastCursor, nullptr); - while(!self->mKillNow.load(std::memory_order_acquire) && - device->Connected.load(std::memory_order_acquire)) + mBuffer->GetCurrentPosition(&LastCursor, nullptr); + while(!mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) { // Get current play cursor DWORD PlayCursor; - Buffer->GetCurrentPosition(&PlayCursor, nullptr); + mBuffer->GetCurrentPosition(&PlayCursor, nullptr); DWORD avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes; if(avail < FragSize) { if(!Playing) { - err = Buffer->Play(0, 0, DSBPLAY_LOOPING); + err = mBuffer->Play(0, 0, DSBPLAY_LOOPING); if(FAILED(err)) { ERR("Failed to play buffer: 0x%lx\n", err); - ALCdsoundPlayback_lock(self); - aluHandleDisconnect(device, "Failure starting playback: 0x%lx", err); - ALCdsoundPlayback_unlock(self); + ALCdsoundPlayback_lock(this); + aluHandleDisconnect(mDevice, "Failure starting playback: 0x%lx", err); + ALCdsoundPlayback_unlock(this); return 1; } Playing = true; } - avail = WaitForSingleObjectEx(self->mNotifyEvent, 2000, FALSE); + avail = WaitForSingleObjectEx(mNotifyEvent, 2000, FALSE); if(avail != WAIT_OBJECT_0) ERR("WaitForSingleObjectEx error: 0x%lx\n", avail); continue; @@ -305,19 +303,19 @@ FORCE_ALIGN int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) // Lock output buffer void *WritePtr1, *WritePtr2; DWORD WriteCnt1{0u}, WriteCnt2{0u}; - err = Buffer->Lock(LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0); + err = mBuffer->Lock(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 = Buffer->Restore(); + err = mBuffer->Restore(); if(SUCCEEDED(err)) { Playing = false; LastCursor = 0; - err = Buffer->Lock(0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, - &WritePtr2, &WriteCnt2, 0); + err = mBuffer->Lock(0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, + &WritePtr2, &WriteCnt2, 0); } } @@ -325,20 +323,21 @@ FORCE_ALIGN int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) if(SUCCEEDED(err)) { // If we have an active context, mix data directly into output buffer otherwise fill with silence - ALCdsoundPlayback_lock(self); - aluMixData(device, WritePtr1, WriteCnt1/FrameSize); - aluMixData(device, WritePtr2, WriteCnt2/FrameSize); - ALCdsoundPlayback_unlock(self); + ALCdsoundPlayback_lock(this); + aluMixData(mDevice, WritePtr1, WriteCnt1/FrameSize); + if(WriteCnt2 > 0) + aluMixData(mDevice, WritePtr2, WriteCnt2/FrameSize); + ALCdsoundPlayback_unlock(this); // Unlock output buffer only when successfully locked - Buffer->Unlock(WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); + mBuffer->Unlock(WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); } else { ERR("Buffer lock error: %#lx\n", err); - ALCdsoundPlayback_lock(self); - aluHandleDisconnect(device, "Failed to lock output buffer: 0x%lx", err); - ALCdsoundPlayback_unlock(self); + ALCdsoundPlayback_lock(this); + aluHandleDisconnect(mDevice, "Failed to lock output buffer: 0x%lx", err); + ALCdsoundPlayback_unlock(this); return 1; } @@ -627,7 +626,7 @@ ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self) { try { self->mKillNow.store(AL_FALSE, std::memory_order_release); - self->mThread = std::thread(ALCdsoundPlayback_mixerProc, self); + self->mThread = std::thread(std::mem_fn(&ALCdsoundPlayback::mixerProc), self); return ALC_TRUE; } catch(std::exception& e) { @@ -650,14 +649,15 @@ void ALCdsoundPlayback_stop(ALCdsoundPlayback *self) struct ALCdsoundCapture final : public ALCbackend { + ALCdsoundCapture(ALCdevice *device) noexcept : ALCbackend{device} { } + ~ALCdsoundCapture() override; + IDirectSoundCapture *mDSC{nullptr}; IDirectSoundCaptureBuffer *mDSCbuffer{nullptr}; DWORD mBufferBytes{0u}; DWORD mCursor{0u}; RingBufferPtr mRing; - - ALCdsoundCapture(ALCdevice *device) noexcept : ALCbackend{device} { } }; void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device); @@ -681,19 +681,20 @@ void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device) } void ALCdsoundCapture_Destruct(ALCdsoundCapture *self) +{ self->~ALCdsoundCapture(); } + +ALCdsoundCapture::~ALCdsoundCapture() { - if(self->mDSCbuffer) + if(mDSCbuffer) { - self->mDSCbuffer->Stop(); - self->mDSCbuffer->Release(); - self->mDSCbuffer = nullptr; + mDSCbuffer->Stop(); + mDSCbuffer->Release(); + mDSCbuffer = nullptr; } - if(self->mDSC) - self->mDSC->Release(); - self->mDSC = nullptr; - - self->~ALCdsoundCapture(); + if(mDSC) + mDSC->Release(); + mDSC = nullptr; } -- cgit v1.2.3 From 28308226e76f8378dc74db12b085d50bb97b11cb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Dec 2018 21:50:54 -0800 Subject: Turn more methods into member functions --- Alc/backends/jack.cpp | 128 +++++++++++++++++++------------------ Alc/backends/null.cpp | 43 ++++++------- Alc/backends/opensl.cpp | 165 ++++++++++++++++++++++++------------------------ 3 files changed, 169 insertions(+), 167 deletions(-) diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index 37855fe3..26086bf9 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -149,6 +149,17 @@ ALCboolean jack_load(void) struct ALCjackPlayback final : public ALCbackend { + ALCjackPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } + ~ALCjackPlayback() override; + + static int bufferSizeNotifyC(jack_nframes_t numframes, void *arg); + int bufferSizeNotify(jack_nframes_t numframes); + + static int processC(jack_nframes_t numframes, void *arg); + int process(jack_nframes_t numframes); + + int mixerProc(); + jack_client_t *mClient{nullptr}; jack_port_t *mPort[MAX_OUTPUT_CHANNELS]{}; @@ -157,15 +168,8 @@ struct ALCjackPlayback final : public ALCbackend { std::atomic mKillNow{true}; std::thread mThread; - - ALCjackPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } }; -int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg); - -int ALCjackPlayback_process(jack_nframes_t numframes, void *arg); -int ALCjackPlayback_mixerProc(ALCjackPlayback *self); - void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device); void ALCjackPlayback_Destruct(ALCjackPlayback *self); ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name); @@ -189,64 +193,65 @@ void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device) } void ALCjackPlayback_Destruct(ALCjackPlayback *self) +{ self->~ALCjackPlayback(); } + +ALCjackPlayback::~ALCjackPlayback() { - if(self->mClient) - { - std::for_each(std::begin(self->mPort), std::end(self->mPort), - [self](jack_port_t *port) -> void - { if(port) jack_port_unregister(self->mClient, port); } - ); - std::fill(std::begin(self->mPort), std::end(self->mPort), nullptr); - jack_client_close(self->mClient); - self->mClient = nullptr; - } + if(!mClient) + return; - self->~ALCjackPlayback(); + std::for_each(std::begin(mPort), std::end(mPort), + [this](jack_port_t *port) -> void + { if(port) jack_port_unregister(mClient, port); } + ); + std::fill(std::begin(mPort), std::end(mPort), nullptr); + jack_client_close(mClient); + mClient = nullptr; } -int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg) -{ - auto self = static_cast(arg); - ALCdevice *device{self->mDevice}; +int ALCjackPlayback::bufferSizeNotifyC(jack_nframes_t numframes, void *arg) +{ return static_cast(arg)->bufferSizeNotify(numframes); } - ALCjackPlayback_lock(self); - device->UpdateSize = numframes; - device->NumUpdates = 2; +int ALCjackPlayback::bufferSizeNotify(jack_nframes_t numframes) +{ + ALCjackPlayback_lock(this); + mDevice->UpdateSize = numframes; + mDevice->NumUpdates = 2; - ALuint bufsize{device->UpdateSize}; - if(ConfigValueUInt(device->DeviceName.c_str(), "jack", "buffer-size", &bufsize)) - bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); - device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize; + ALuint bufsize{mDevice->UpdateSize}; + if(ConfigValueUInt(mDevice->DeviceName.c_str(), "jack", "buffer-size", &bufsize)) + bufsize = maxu(NextPowerOf2(bufsize), mDevice->UpdateSize); + mDevice->NumUpdates = (bufsize+mDevice->UpdateSize) / mDevice->UpdateSize; - TRACE("%u update size x%u\n", device->UpdateSize, device->NumUpdates); + TRACE("%u update size x%u\n", mDevice->UpdateSize, mDevice->NumUpdates); - self->mRing = nullptr; - self->mRing = CreateRingBuffer(bufsize, device->frameSizeFromFmt(), true); - if(!self->mRing) + mRing = nullptr; + mRing = CreateRingBuffer(bufsize, mDevice->frameSizeFromFmt(), true); + if(!mRing) { ERR("Failed to reallocate ringbuffer\n"); - aluHandleDisconnect(device, "Failed to reallocate %u-sample buffer", bufsize); + aluHandleDisconnect(mDevice, "Failed to reallocate %u-sample buffer", bufsize); } - ALCjackPlayback_unlock(self); + ALCjackPlayback_unlock(this); return 0; } -int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) -{ - auto self = static_cast(arg); +int ALCjackPlayback::processC(jack_nframes_t numframes, void *arg) +{ return static_cast(arg)->process(numframes); } +int ALCjackPlayback::process(jack_nframes_t numframes) +{ jack_default_audio_sample_t *out[MAX_OUTPUT_CHANNELS]; ALsizei numchans{0}; - for(auto port : self->mPort) + for(auto port : mPort) { if(!port) break; out[numchans++] = static_cast(jack_port_get_buffer(port, numframes)); } - RingBuffer *ring{self->mRing.get()}; - auto data = ring->getReadVector(); + auto data = mRing->getReadVector(); jack_nframes_t todo{minu(numframes, data.first.len)}; std::transform(out, out+numchans, out, [&data,numchans,todo](ALfloat *outbuf) -> ALfloat* @@ -288,8 +293,8 @@ int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) total += todo; } - ring->readAdvance(total); - self->mSem.post(); + mRing->readAdvance(total); + mSem.post(); if(numframes > total) { @@ -306,39 +311,36 @@ int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) return 0; } -int ALCjackPlayback_mixerProc(ALCjackPlayback *self) +int ALCjackPlayback::mixerProc() { - ALCdevice *device{self->mDevice}; - RingBuffer *ring{self->mRing.get()}; - SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - ALCjackPlayback_lock(self); - while(!self->mKillNow.load(std::memory_order_acquire) && - device->Connected.load(std::memory_order_acquire)) + ALCjackPlayback_lock(this); + while(!mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) { - if(ring->writeSpace() < device->UpdateSize) + if(mRing->writeSpace() < mDevice->UpdateSize) { - ALCjackPlayback_unlock(self); - self->mSem.wait(); - ALCjackPlayback_lock(self); + ALCjackPlayback_unlock(this); + mSem.wait(); + ALCjackPlayback_lock(this); continue; } - auto data = ring->getWriteVector(); + auto data = mRing->getWriteVector(); auto todo = static_cast(data.first.len + data.second.len); - todo -= todo%device->UpdateSize; + todo -= todo%mDevice->UpdateSize; ALuint len1{minu(data.first.len, todo)}; ALuint len2{minu(data.second.len, todo-len1)}; - aluMixData(device, data.first.buf, len1); + aluMixData(mDevice, data.first.buf, len1); if(len2 > 0) - aluMixData(device, data.second.buf, len2); - ring->writeAdvance(todo); + aluMixData(mDevice, data.second.buf, len2); + mRing->writeAdvance(todo); } - ALCjackPlayback_unlock(self); + ALCjackPlayback_unlock(this); return 0; } @@ -367,8 +369,8 @@ ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name) TRACE("Client name not unique, got `%s' instead\n", client_name); } - jack_set_process_callback(self->mClient, ALCjackPlayback_process, self); - jack_set_buffer_size_callback(self->mClient, ALCjackPlayback_bufferSizeNotify, self); + jack_set_process_callback(self->mClient, &ALCjackPlayback::processC, self); + jack_set_buffer_size_callback(self->mClient, &ALCjackPlayback::bufferSizeNotifyC, self); ALCdevice *device{self->mDevice}; device->DeviceName = name; @@ -478,7 +480,7 @@ ALCboolean ALCjackPlayback_start(ALCjackPlayback *self) try { self->mKillNow.store(false, std::memory_order_release); - self->mThread = std::thread(ALCjackPlayback_mixerProc, self); + self->mThread = std::thread(std::mem_fn(&ALCjackPlayback::mixerProc), self); return ALC_TRUE; } catch(std::exception& e) { diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 7a4cf475..5367c46f 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -45,14 +45,14 @@ constexpr ALCchar nullDevice[] = "No Output"; struct ALCnullBackend final : public ALCbackend { + ALCnullBackend(ALCdevice *device) noexcept : ALCbackend{device} { } + + int mixerProc(); + std::atomic mKillNow{AL_TRUE}; std::thread mThread; - - ALCnullBackend(ALCdevice *device) noexcept : ALCbackend{device} { } }; -int ALCnullBackend_mixerProc(ALCnullBackend *self); - void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device); void ALCnullBackend_Destruct(ALCnullBackend *self); ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name); @@ -76,39 +76,36 @@ void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device) } void ALCnullBackend_Destruct(ALCnullBackend *self) -{ - self->~ALCnullBackend(); -} +{ self->~ALCnullBackend(); } -int ALCnullBackend_mixerProc(ALCnullBackend *self) +int ALCnullBackend::mixerProc() { - ALCdevice *device{self->mDevice}; - const milliseconds restTime{device->UpdateSize*1000/device->Frequency / 2}; + const milliseconds restTime{mDevice->UpdateSize*1000/mDevice->Frequency / 2}; SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); ALint64 done{0}; auto start = std::chrono::steady_clock::now(); - while(!self->mKillNow.load(std::memory_order_acquire) && - device->Connected.load(std::memory_order_acquire)) + while(!mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) { auto now = std::chrono::steady_clock::now(); /* This converts from nanoseconds to nanosamples, then to samples. */ - ALint64 avail{std::chrono::duration_cast((now-start) * device->Frequency).count()}; - if(avail-done < device->UpdateSize) + ALint64 avail{std::chrono::duration_cast((now-start) * mDevice->Frequency).count()}; + if(avail-done < mDevice->UpdateSize) { std::this_thread::sleep_for(restTime); continue; } - while(avail-done >= device->UpdateSize) + while(avail-done >= mDevice->UpdateSize) { - ALCnullBackend_lock(self); - aluMixData(device, nullptr, device->UpdateSize); - ALCnullBackend_unlock(self); - done += device->UpdateSize; + ALCnullBackend_lock(this); + aluMixData(mDevice, nullptr, mDevice->UpdateSize); + ALCnullBackend_unlock(this); + done += mDevice->UpdateSize; } /* For every completed second, increment the start time and reduce the @@ -116,11 +113,11 @@ int ALCnullBackend_mixerProc(ALCnullBackend *self) * and current time from growing too large, while maintaining the * correct number of samples to render. */ - if(done >= device->Frequency) + if(done >= mDevice->Frequency) { - seconds s{done/device->Frequency}; + seconds s{done/mDevice->Frequency}; start += s; - done -= device->Frequency*s.count(); + done -= mDevice->Frequency*s.count(); } } @@ -151,7 +148,7 @@ ALCboolean ALCnullBackend_start(ALCnullBackend *self) { try { self->mKillNow.store(AL_FALSE, std::memory_order_release); - self->mThread = std::thread(ALCnullBackend_mixerProc, self); + self->mThread = std::thread(std::mem_fn(&ALCnullBackend::mixerProc), self); return ALC_TRUE; } catch(std::exception& e) { diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 0853e32f..b0e51441 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -38,6 +38,9 @@ #include #include + +namespace { + /* Helper macros */ #define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS #define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS @@ -135,6 +138,14 @@ static const char *res_str(SLresult result) struct ALCopenslPlayback final : public ALCbackend { + ALCopenslPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } + ~ALCopenslPlayback() override; + + static void processC(SLAndroidSimpleBufferQueueItf bq, void *context); + void process(SLAndroidSimpleBufferQueueItf bq); + + int mixerProc(); + /* engine interfaces */ SLObjectItf mEngineObj{nullptr}; SLEngineItf mEngine{nullptr}; @@ -152,13 +163,8 @@ struct ALCopenslPlayback final : public ALCbackend { std::atomic mKillNow{AL_TRUE}; std::thread mThread; - - ALCopenslPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } }; -static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf bq, void *context); -static int ALCopenslPlayback_mixerProc(ALCopenslPlayback *self); - static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *device); static void ALCopenslPlayback_Destruct(ALCopenslPlayback *self); static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name); @@ -182,30 +188,31 @@ static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *devi } static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self) -{ - if(self->mBufferQueueObj != NULL) - VCALL0(self->mBufferQueueObj,Destroy)(); - self->mBufferQueueObj = NULL; +{ self->~ALCopenslPlayback(); } - if(self->mOutputMix) - VCALL0(self->mOutputMix,Destroy)(); - self->mOutputMix = NULL; - - if(self->mEngineObj) - VCALL0(self->mEngineObj,Destroy)(); - self->mEngineObj = NULL; - self->mEngine = NULL; - - self->~ALCopenslPlayback(); +ALCopenslPlayback::~ALCopenslPlayback() +{ + if(mBufferQueueObj) + VCALL0(mBufferQueueObj,Destroy)(); + mBufferQueueObj = nullptr; + + if(mOutputMix) + VCALL0(mOutputMix,Destroy)(); + mOutputMix = nullptr; + + if(mEngineObj) + VCALL0(mEngineObj,Destroy)(); + mEngineObj = nullptr; + mEngine = nullptr; } /* this callback handler is called every time a buffer finishes playing */ -static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), void *context) -{ - auto self = static_cast(context); - RingBuffer *ring{self->mRing.get()}; +void ALCopenslPlayback::processC(SLAndroidSimpleBufferQueueItf bq, void *context) +{ static_cast(context)->process(bq); } +void ALCopenslPlayback::process(SLAndroidSimpleBufferQueueItf UNUSED(bq)) +{ /* A note on the ringbuffer usage: The buffer queue seems to hold on to the * pointer passed to the Enqueue method, rather than copying the audio. * Consequently, the ringbuffer contains the audio that is currently queued @@ -214,42 +221,35 @@ static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), * available for writing again, and wake up the mixer thread to mix and * queue more audio. */ - ring->readAdvance(1); + mRing->readAdvance(1); - self->mSem.post(); + mSem.post(); } - -static int ALCopenslPlayback_mixerProc(ALCopenslPlayback *self) +int ALCopenslPlayback::mixerProc() { - ALCdevice *device{self->mDevice}; - RingBuffer *ring{self->mRing.get()}; - SLAndroidSimpleBufferQueueItf bufferQueue; - SLPlayItf player; - SLresult result; - SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue); + SLPlayItf player; + SLAndroidSimpleBufferQueueItf bufferQueue; + SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &bufferQueue)}; PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE"); if(SL_RESULT_SUCCESS == result) { - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player); + result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player); PRINTERR(result, "bufferQueue->GetInterface SL_IID_PLAY"); } - ALCopenslPlayback_lock(self); + ALCopenslPlayback_lock(this); if(SL_RESULT_SUCCESS != result) - aluHandleDisconnect(device, "Failed to get playback buffer: 0x%08x", result); + aluHandleDisconnect(mDevice, "Failed to get playback buffer: 0x%08x", result); - while(SL_RESULT_SUCCESS == result && !self->mKillNow.load(std::memory_order_acquire) && - device->Connected.load(std::memory_order_acquire)) + while(SL_RESULT_SUCCESS == result && !mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) { - size_t todo; - - if(ring->writeSpace() == 0) + if(mRing->writeSpace() == 0) { SLuint32 state = 0; @@ -262,26 +262,26 @@ static int ALCopenslPlayback_mixerProc(ALCopenslPlayback *self) } if(SL_RESULT_SUCCESS != result) { - aluHandleDisconnect(device, "Failed to start platback: 0x%08x", result); + aluHandleDisconnect(mDevice, "Failed to start platback: 0x%08x", result); break; } - if(ring->writeSpace() == 0) + if(mRing->writeSpace() == 0) { - ALCopenslPlayback_unlock(self); - self->mSem.wait(); - ALCopenslPlayback_lock(self); + ALCopenslPlayback_unlock(this); + mSem.wait(); + ALCopenslPlayback_lock(this); continue; } } - auto data = ring->getWriteVector(); - aluMixData(device, data.first.buf, data.first.len*device->UpdateSize); + auto data = mRing->getWriteVector(); + aluMixData(mDevice, data.first.buf, data.first.len*mDevice->UpdateSize); if(data.second.len > 0) - aluMixData(device, data.second.buf, data.second.len*device->UpdateSize); + aluMixData(mDevice, data.second.buf, data.second.len*mDevice->UpdateSize); - todo = data.first.len+data.second.len; - ring->writeAdvance(todo); + size_t todo{data.first.len + data.second.len}; + mRing->writeAdvance(todo); for(size_t i{0};i < todo;i++) { @@ -292,20 +292,19 @@ static int ALCopenslPlayback_mixerProc(ALCopenslPlayback *self) data.second.len = 0; } - result = VCALL(bufferQueue,Enqueue)(data.first.buf, - device->UpdateSize*self->mFrameSize); + result = VCALL(bufferQueue,Enqueue)(data.first.buf, mDevice->UpdateSize*mFrameSize); PRINTERR(result, "bufferQueue->Enqueue"); if(SL_RESULT_SUCCESS != result) { - aluHandleDisconnect(device, "Failed to queue audio: 0x%08x", result); + aluHandleDisconnect(mDevice, "Failed to queue audio: 0x%08x", result); break; } data.first.len--; - data.first.buf += device->UpdateSize*self->mFrameSize; + data.first.buf += mDevice->UpdateSize*mFrameSize; } } - ALCopenslPlayback_unlock(self); + ALCopenslPlayback_unlock(this); return 0; } @@ -569,14 +568,13 @@ static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self) if(SL_RESULT_SUCCESS != result) return ALC_FALSE; - result = VCALL(bufferQueue,RegisterCallback)(ALCopenslPlayback_process, self); + result = VCALL(bufferQueue,RegisterCallback)(&ALCopenslPlayback::processC, self); PRINTERR(result, "bufferQueue->RegisterCallback"); - if(SL_RESULT_SUCCESS != result) - return ALC_FALSE; + if(SL_RESULT_SUCCESS != result) return ALC_FALSE; try { self->mKillNow.store(AL_FALSE); - self->mThread = std::thread(ALCopenslPlayback_mixerProc, self); + self->mThread = std::thread(std::mem_fn(&ALCopenslPlayback::mixerProc), self); return ALC_TRUE; } catch(std::exception& e) { @@ -649,6 +647,12 @@ static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self) struct ALCopenslCapture final : public ALCbackend { + ALCopenslCapture(ALCdevice *device) noexcept : ALCbackend{device} { } + ~ALCopenslCapture() override; + + static void processC(SLAndroidSimpleBufferQueueItf bq, void *context); + void process(SLAndroidSimpleBufferQueueItf bq); + /* engine interfaces */ SLObjectItf mEngineObj{nullptr}; SLEngineItf mEngine; @@ -660,12 +664,8 @@ struct ALCopenslCapture final : public ALCbackend { ALCuint mSplOffset{0u}; ALsizei mFrameSize{0}; - - ALCopenslCapture(ALCdevice *device) noexcept : ALCbackend{device} { } }; -static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf bq, void *context); - static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device); static void ALCopenslCapture_Destruct(ALCopenslCapture *self); static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name); @@ -688,26 +688,28 @@ static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device } static void ALCopenslCapture_Destruct(ALCopenslCapture *self) -{ - if(self->mRecordObj != NULL) - VCALL0(self->mRecordObj,Destroy)(); - self->mRecordObj = NULL; - - if(self->mEngineObj != NULL) - VCALL0(self->mEngineObj,Destroy)(); - self->mEngineObj = NULL; - self->mEngine = NULL; +{ self->~ALCopenslCapture(); } - self->~ALCopenslCapture(); +ALCopenslCapture::~ALCopenslCapture() +{ + if(mRecordObj) + VCALL0(mRecordObj,Destroy)(); + mRecordObj = nullptr; + + if(mEngineObj) + VCALL0(mEngineObj,Destroy)(); + mEngineObj = nullptr; + mEngine = nullptr; } -static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), void *context) +void ALCopenslCapture::processC(SLAndroidSimpleBufferQueueItf bq, void *context) +{ static_cast(context)->process(bq); } + +void ALCopenslCapture::process(SLAndroidSimpleBufferQueueItf UNUSED(bq)) { - auto *self = static_cast(context); - RingBuffer *ring{self->mRing.get()}; /* A new chunk has been written into the ring buffer, advance it. */ - ring->writeAdvance(1); + mRing->writeAdvance(1); } @@ -835,7 +837,7 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name } if(SL_RESULT_SUCCESS == result) { - result = VCALL(bufferQueue,RegisterCallback)(ALCopenslCapture_process, self); + result = VCALL(bufferQueue,RegisterCallback)(&ALCopenslCapture::processC, self); PRINTERR(result, "bufferQueue->RegisterCallback"); } if(SL_RESULT_SUCCESS == result) @@ -978,6 +980,7 @@ static ALCuint ALCopenslCapture_availableSamples(ALCopenslCapture *self) return ring->readSpace() * device->UpdateSize; } +} // namespace bool OSLBackendFactory::init() { return true; } -- cgit v1.2.3 From aff58265cb458b2ac2c42fef96383e9751d094d1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Dec 2018 23:37:24 -0800 Subject: Make more methods into member functions --- Alc/backends/oss.cpp | 104 +++++----- Alc/backends/portaudio.cpp | 88 ++++---- Alc/backends/pulseaudio.cpp | 475 ++++++++++++++++++++------------------------ 3 files changed, 316 insertions(+), 351 deletions(-) diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index c35c7247..54d7e0af 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -242,18 +242,19 @@ int log2i(ALCuint x) struct ALCplaybackOSS final : public ALCbackend { + ALCplaybackOSS(ALCdevice *device) noexcept : ALCbackend{device} { } + ~ALCplaybackOSS() override; + + int mixerProc(); + int mFd{-1}; al::vector mMixData; std::atomic mKillNow{AL_TRUE}; std::thread mThread; - - ALCplaybackOSS(ALCdevice *device) noexcept : ALCbackend{device} { } }; -int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self); - void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device); void ALCplaybackOSS_Destruct(ALCplaybackOSS *self); ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name); @@ -276,41 +277,40 @@ void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device) } void ALCplaybackOSS_Destruct(ALCplaybackOSS *self) -{ - if(self->mFd != -1) - close(self->mFd); - self->mFd = -1; +{ self->~ALCplaybackOSS(); } - self->~ALCplaybackOSS(); +ALCplaybackOSS::~ALCplaybackOSS() +{ + if(mFd != -1) + close(mFd); + mFd = -1; } -int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self) +int ALCplaybackOSS::mixerProc() { - ALCdevice *device{self->mDevice}; - SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - const int frame_size{device->frameSizeFromFmt()}; + const int frame_size{mDevice->frameSizeFromFmt()}; - ALCplaybackOSS_lock(self); - while(!self->mKillNow.load(std::memory_order_acquire) && - device->Connected.load(std::memory_order_acquire)) + ALCplaybackOSS_lock(this); + while(!mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) { pollfd pollitem{}; - pollitem.fd = self->mFd; + pollitem.fd = mFd; pollitem.events = POLLOUT; - ALCplaybackOSS_unlock(self); + ALCplaybackOSS_unlock(this); int pret{poll(&pollitem, 1, 1000)}; - ALCplaybackOSS_lock(self); + ALCplaybackOSS_lock(this); if(pret < 0) { if(errno == EINTR || errno == EAGAIN) continue; ERR("poll failed: %s\n", strerror(errno)); - aluHandleDisconnect(device, "Failed waiting for playback buffer: %s", strerror(errno)); + aluHandleDisconnect(mDevice, "Failed waiting for playback buffer: %s", strerror(errno)); break; } else if(pret == 0) @@ -319,18 +319,18 @@ int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self) continue; } - ALubyte *write_ptr{self->mMixData.data()}; - size_t to_write{self->mMixData.size()}; - aluMixData(device, write_ptr, to_write/frame_size); - while(to_write > 0 && !self->mKillNow.load()) + ALubyte *write_ptr{mMixData.data()}; + size_t to_write{mMixData.size()}; + aluMixData(mDevice, write_ptr, to_write/frame_size); + while(to_write > 0 && !mKillNow.load(std::memory_order_acquire)) { - ssize_t wrote{write(self->mFd, write_ptr, to_write)}; + ssize_t wrote{write(mFd, write_ptr, to_write)}; if(wrote < 0) { if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) continue; ERR("write failed: %s\n", strerror(errno)); - aluHandleDisconnect(device, "Failed writing playback samples: %s", + aluHandleDisconnect(mDevice, "Failed writing playback samples: %s", strerror(errno)); break; } @@ -339,7 +339,7 @@ int ALCplaybackOSS_mixerProc(ALCplaybackOSS *self) write_ptr += wrote; } } - ALCplaybackOSS_unlock(self); + ALCplaybackOSS_unlock(this); return 0; } @@ -467,7 +467,7 @@ ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self) self->mMixData.resize(device->UpdateSize * device->frameSizeFromFmt()); self->mKillNow.store(AL_FALSE); - self->mThread = std::thread(ALCplaybackOSS_mixerProc, self); + self->mThread = std::thread{std::mem_fn(&ALCplaybackOSS::mixerProc), self}; return ALC_TRUE; } catch(std::exception& e) { @@ -492,18 +492,19 @@ void ALCplaybackOSS_stop(ALCplaybackOSS *self) struct ALCcaptureOSS final : public ALCbackend { + ALCcaptureOSS(ALCdevice *device) noexcept : ALCbackend{device} { } + ~ALCcaptureOSS() override; + + int recordProc(); + int mFd{-1}; RingBufferPtr mRing{nullptr}; std::atomic mKillNow{AL_TRUE}; std::thread mThread; - - ALCcaptureOSS(ALCdevice *device) noexcept : ALCbackend{device} { } }; -int ALCcaptureOSS_recordProc(ALCcaptureOSS *self); - void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device); void ALCcaptureOSS_Destruct(ALCcaptureOSS *self); ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name); @@ -526,28 +527,26 @@ void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device) } void ALCcaptureOSS_Destruct(ALCcaptureOSS *self) -{ - if(self->mFd != -1) - close(self->mFd); - self->mFd = -1; +{ self->~ALCcaptureOSS(); } - self->~ALCcaptureOSS(); +ALCcaptureOSS::~ALCcaptureOSS() +{ + if(mFd != -1) + close(mFd); + mFd = -1; } -int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) +int ALCcaptureOSS::recordProc() { - ALCdevice *device{self->mDevice}; - RingBuffer *ring{self->mRing.get()}; - SetRTPriority(); althrd_setname(RECORD_THREAD_NAME); - const int frame_size{device->frameSizeFromFmt()}; - while(!self->mKillNow.load()) + const int frame_size{mDevice->frameSizeFromFmt()}; + while(!mKillNow.load(std::memory_order_acquire)) { pollfd pollitem{}; - pollitem.fd = self->mFd; + pollitem.fd = mFd; pollitem.events = POLLIN; int sret{poll(&pollitem, 1, 1000)}; @@ -556,7 +555,7 @@ int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) if(errno == EINTR || errno == EAGAIN) continue; ERR("poll failed: %s\n", strerror(errno)); - aluHandleDisconnect(device, "Failed to check capture samples: %s", strerror(errno)); + aluHandleDisconnect(mDevice, "Failed to check capture samples: %s", strerror(errno)); break; } else if(sret == 0) @@ -565,19 +564,20 @@ int ALCcaptureOSS_recordProc(ALCcaptureOSS *self) continue; } - auto vec = ring->getWriteVector(); + auto vec = mRing->getWriteVector(); if(vec.first.len > 0) { - ssize_t amt{read(self->mFd, vec.first.buf, vec.first.len*frame_size)}; + ssize_t amt{read(mFd, vec.first.buf, vec.first.len*frame_size)}; if(amt < 0) { ERR("read failed: %s\n", strerror(errno)); - ALCcaptureOSS_lock(self); - aluHandleDisconnect(device, "Failed reading capture samples: %s", strerror(errno)); - ALCcaptureOSS_unlock(self); + ALCcaptureOSS_lock(this); + aluHandleDisconnect(mDevice, "Failed reading capture samples: %s", + strerror(errno)); + ALCcaptureOSS_unlock(this); break; } - ring->writeAdvance(amt/frame_size); + mRing->writeAdvance(amt/frame_size); } } @@ -700,7 +700,7 @@ ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self) { try { self->mKillNow.store(AL_FALSE); - self->mThread = std::thread(ALCcaptureOSS_recordProc, self); + self->mThread = std::thread{std::mem_fn(&ALCcaptureOSS::recordProc), self}; return ALC_TRUE; } catch(std::exception& e) { diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index 10c9079b..44ffd9bd 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -131,17 +131,20 @@ bool pa_load(void) struct ALCportPlayback final : public ALCbackend { + ALCportPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } + ~ALCportPlayback() override; + + static int writeCallbackC(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, + const PaStreamCallbackFlags statusFlags, void *userData); + int writeCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags); + PaStream *mStream{nullptr}; PaStreamParameters mParams{}; ALuint mUpdateSize{0u}; - - ALCportPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } }; -int ALCportPlayback_WriteCallback(const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, - const PaStreamCallbackFlags statusFlags, void *userData); - void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device); void ALCportPlayback_Destruct(ALCportPlayback *self); ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name); @@ -165,25 +168,32 @@ void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device) } void ALCportPlayback_Destruct(ALCportPlayback *self) +{ self->~ALCportPlayback(); } + +ALCportPlayback::~ALCportPlayback() { - PaError err = self->mStream ? Pa_CloseStream(self->mStream) : paNoError; + PaError err{mStream ? Pa_CloseStream(mStream) : paNoError}; if(err != paNoError) ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); - self->mStream = nullptr; - - self->~ALCportPlayback(); + mStream = nullptr; } -int ALCportPlayback_WriteCallback(const void *UNUSED(inputBuffer), void *outputBuffer, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo), - const PaStreamCallbackFlags UNUSED(statusFlags), void *userData) +int ALCportPlayback::writeCallbackC(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, + const PaStreamCallbackFlags statusFlags, void *userData) { - auto self = static_cast(userData); + return static_cast(userData)->writeCallback(inputBuffer, outputBuffer, + framesPerBuffer, timeInfo, statusFlags); +} - ALCportPlayback_lock(self); - aluMixData(self->mDevice, outputBuffer, framesPerBuffer); - ALCportPlayback_unlock(self); +int ALCportPlayback::writeCallback(const void* UNUSED(inputBuffer), void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* UNUSED(timeInfo), + const PaStreamCallbackFlags UNUSED(statusFlags)) +{ + ALCportPlayback_lock(this); + aluMixData(mDevice, outputBuffer, framesPerBuffer); + ALCportPlayback_unlock(this); return 0; } @@ -236,7 +246,7 @@ ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name) retry_open: err = Pa_OpenStream(&self->mStream, nullptr, &self->mParams, device->Frequency, device->UpdateSize, paNoFlag, - ALCportPlayback_WriteCallback, self + &ALCportPlayback::writeCallbackC, self ); if(err != paNoError) { @@ -312,18 +322,21 @@ void ALCportPlayback_stop(ALCportPlayback *self) struct ALCportCapture final : public ALCbackend { + ALCportCapture(ALCdevice *device) noexcept : ALCbackend{device} { } + ~ALCportCapture() override; + + static int readCallbackC(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, + const PaStreamCallbackFlags statusFlags, void *userData); + int readCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags); + PaStream *mStream{nullptr}; PaStreamParameters mParams; RingBufferPtr mRing{nullptr}; - - ALCportCapture(ALCdevice *device) noexcept : ALCbackend{device} { } }; -int ALCportCapture_ReadCallback(const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, - const PaStreamCallbackFlags statusFlags, void *userData); - void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device); void ALCportCapture_Destruct(ALCportCapture *self); ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name); @@ -347,23 +360,30 @@ void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device) } void ALCportCapture_Destruct(ALCportCapture *self) +{ self->~ALCportCapture(); } + +ALCportCapture::~ALCportCapture() { - PaError err = self->mStream ? Pa_CloseStream(self->mStream) : paNoError; + PaError err{mStream ? Pa_CloseStream(mStream) : paNoError}; if(err != paNoError) ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); - self->mStream = nullptr; - - self->~ALCportCapture(); + mStream = nullptr; } -int ALCportCapture_ReadCallback(const void *inputBuffer, void *UNUSED(outputBuffer), +int ALCportCapture::readCallbackC(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, + const PaStreamCallbackFlags statusFlags, void* userData) +{ + return static_cast(userData)->readCallback(inputBuffer, outputBuffer, + framesPerBuffer, timeInfo, statusFlags); +} + +int ALCportCapture::readCallback(const void *inputBuffer, void *UNUSED(outputBuffer), unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo), - const PaStreamCallbackFlags UNUSED(statusFlags), void *userData) + const PaStreamCallbackFlags UNUSED(statusFlags)) { - auto self = static_cast(userData); - RingBuffer *ring{self->mRing.get()}; - ring->write(inputBuffer, framesPerBuffer); + mRing->write(inputBuffer, framesPerBuffer); return 0; } @@ -419,7 +439,7 @@ ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) err = Pa_OpenStream(&self->mStream, &self->mParams, nullptr, device->Frequency, paFramesPerBufferUnspecified, paNoFlag, - ALCportCapture_ReadCallback, self + &ALCportCapture::readCallbackC, self ); if(err != paNoError) { diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 6e5e07b8..3130df19 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -522,74 +522,132 @@ al::vector PlaybackDevices; al::vector CaptureDevices; -struct PulsePlayback final : public ALCbackend { - std::string mDeviceName; +pa_stream *pulse_connect_stream(const char *device_name, pa_threaded_mainloop *loop, + pa_context *context, pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, + pa_channel_map *chanmap, ALCbackend_Type type) +{ + pa_stream *stream{pa_stream_new_with_proplist(context, + (type==ALCbackend_Playback) ? "Playback Stream" : "Capture Stream", spec, chanmap, + prop_filter)}; + if(!stream) + { + ERR("pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context))); + return nullptr; + } - pa_buffer_attr mAttr; - pa_sample_spec mSpec; + pa_stream_set_state_callback(stream, stream_state_callback, loop); - pa_threaded_mainloop *mLoop{nullptr}; + int err{(type==ALCbackend_Playback) ? + pa_stream_connect_playback(stream, device_name, attr, flags, nullptr, nullptr) : + pa_stream_connect_record(stream, device_name, attr, flags)}; + if(err < 0) + { + ERR("Stream did not connect: %s\n", pa_strerror(err)); + pa_stream_unref(stream); + return nullptr; + } - pa_stream *mStream{nullptr}; - pa_context *mContext{nullptr}; + pa_stream_state_t state; + while((state=pa_stream_get_state(stream)) != PA_STREAM_READY) + { + if(!PA_STREAM_IS_GOOD(state)) + { + ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(context))); + pa_stream_unref(stream); + return nullptr; + } - ALuint mBufferSize{0u}; - ALuint mFrameSize{0u}; + pa_threaded_mainloop_wait(loop); + } + pa_stream_set_state_callback(stream, nullptr, nullptr); - PulsePlayback(ALCdevice *device) noexcept : ALCbackend{device} { } -}; + return stream; +} -void PulsePlayback_deviceCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); -void PulsePlayback_probeDevices(void); -void PulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata); -void PulsePlayback_contextStateCallback(pa_context *context, void *pdata); -void PulsePlayback_streamStateCallback(pa_stream *stream, void *pdata); -void PulsePlayback_streamWriteCallback(pa_stream *p, size_t nbytes, void *userdata); -void PulsePlayback_sinkInfoCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); -void PulsePlayback_sinkNameCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); -void PulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata); -pa_stream *PulsePlayback_connectStream(const char *device_name, pa_threaded_mainloop *loop, - pa_context *context, pa_stream_flags_t flags, - pa_buffer_attr *attr, pa_sample_spec *spec, - pa_channel_map *chanmap); +void device_sink_callback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) +{ + auto loop = static_cast(pdata); -void PulsePlayback_Construct(PulsePlayback *self, ALCdevice *device); -void PulsePlayback_Destruct(PulsePlayback *self); -ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name); -ALCboolean PulsePlayback_reset(PulsePlayback *self); -ALCboolean PulsePlayback_start(PulsePlayback *self); -void PulsePlayback_stop(PulsePlayback *self); -DECLARE_FORWARD2(PulsePlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -DECLARE_FORWARD(PulsePlayback, ALCbackend, ALCuint, availableSamples) -ClockLatency PulsePlayback_getClockLatency(PulsePlayback *self); -void PulsePlayback_lock(PulsePlayback *self); -void PulsePlayback_unlock(PulsePlayback *self); -DECLARE_DEFAULT_ALLOCATORS(PulsePlayback) + if(eol) + { + pa_threaded_mainloop_signal(loop, 0); + return; + } -DEFINE_ALCBACKEND_VTABLE(PulsePlayback); + /* Skip this device is if it's already in the list. */ + if(std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + [info](const DevMap &entry) -> bool + { return entry.device_name == info->name; } + ) != PlaybackDevices.cend()) + return; + /* Make sure the display name (description) is unique. Append a number + * counter as needed. + */ + int count{1}; + std::string newname{info->description}; + while(checkName(PlaybackDevices, newname)) + { + newname = info->description; + newname += " #"; + newname += std::to_string(++count); + } + PlaybackDevices.emplace_back(std::move(newname), info->name); + DevMap &newentry = PlaybackDevices.back(); -void PulsePlayback_Construct(PulsePlayback *self, ALCdevice *device) -{ - new (self) PulsePlayback{device}; - SET_VTABLE2(PulsePlayback, ALCbackend, self); + TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str()); } -void PulsePlayback_Destruct(PulsePlayback *self) +void probePlaybackDevices(void) { - if(self->mLoop) + PlaybackDevices.clear(); + + pa_threaded_mainloop *loop{pa_threaded_mainloop_new()}; + if(loop && pa_threaded_mainloop_start(loop) >= 0) { - pulse_close(self->mLoop, self->mContext, self->mStream); - self->mLoop = nullptr; - self->mContext = nullptr; - self->mStream = nullptr; + unique_palock palock{loop}; + + pa_context *context{connect_context(loop, AL_FALSE)}; + if(context) + { + pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | + PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE}; + + pa_sample_spec spec; + spec.format = PA_SAMPLE_S16NE; + spec.rate = 44100; + spec.channels = 2; + + pa_stream *stream{pulse_connect_stream(nullptr, loop, context, flags, nullptr, &spec, + nullptr, ALCbackend_Playback)}; + if(stream) + { + pa_operation *op{pa_context_get_sink_info_by_name(context, + pa_stream_get_device_name(stream), device_sink_callback, loop)}; + wait_for_operation(op, loop); + + pa_stream_disconnect(stream); + pa_stream_unref(stream); + stream = nullptr; + } + + pa_operation *op{pa_context_get_sink_info_list(context, + device_sink_callback, loop)}; + wait_for_operation(op, loop); + + pa_context_disconnect(context); + pa_context_unref(context); + } + palock = unique_palock{}; + pa_threaded_mainloop_stop(loop); } - self->~PulsePlayback(); + if(loop) + pa_threaded_mainloop_free(loop); } -void PulsePlayback_deviceCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) +void device_source_callback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata) { auto loop = static_cast(pdata); @@ -600,10 +658,10 @@ void PulsePlayback_deviceCallback(pa_context *UNUSED(context), const pa_sink_inf } /* Skip this device is if it's already in the list. */ - if(std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + if(std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), [info](const DevMap &entry) -> bool { return entry.device_name == info->name; } - ) != PlaybackDevices.cend()) + ) != CaptureDevices.cend()) return; /* Make sure the display name (description) is unique. Append a number @@ -611,21 +669,21 @@ void PulsePlayback_deviceCallback(pa_context *UNUSED(context), const pa_sink_inf */ int count{1}; std::string newname{info->description}; - while(checkName(PlaybackDevices, newname)) + while(checkName(CaptureDevices, newname)) { newname = info->description; newname += " #"; newname += std::to_string(++count); } - PlaybackDevices.emplace_back(std::move(newname), info->name); - DevMap &newentry = PlaybackDevices.back(); + CaptureDevices.emplace_back(std::move(newname), info->name); + DevMap &newentry = CaptureDevices.back(); TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str()); } -void PulsePlayback_probeDevices(void) +void probeCaptureDevices(void) { - PlaybackDevices.clear(); + CaptureDevices.clear(); pa_threaded_mainloop *loop{pa_threaded_mainloop_new()}; if(loop && pa_threaded_mainloop_start(loop) >= 0) @@ -641,16 +699,14 @@ void PulsePlayback_probeDevices(void) pa_sample_spec spec; spec.format = PA_SAMPLE_S16NE; spec.rate = 44100; - spec.channels = 2; + spec.channels = 1; - pa_stream *stream{PulsePlayback_connectStream(nullptr, - loop, context, flags, nullptr, &spec, nullptr - )}; + pa_stream *stream{pulse_connect_stream(nullptr, loop, context, flags, nullptr, &spec, + nullptr, ALCbackend_Capture)}; if(stream) { - pa_operation *op{pa_context_get_sink_info_by_name(context, - pa_stream_get_device_name(stream), PulsePlayback_deviceCallback, loop - )}; + pa_operation *op{pa_context_get_source_info_by_name(context, + pa_stream_get_device_name(stream), device_source_callback, loop)}; wait_for_operation(op, loop); pa_stream_disconnect(stream); @@ -658,15 +714,14 @@ void PulsePlayback_probeDevices(void) stream = nullptr; } - pa_operation *op{pa_context_get_sink_info_list(context, - PulsePlayback_deviceCallback, loop - )}; + pa_operation *op{pa_context_get_source_info_list(context, + device_source_callback, loop)}; wait_for_operation(op, loop); pa_context_disconnect(context); pa_context_unref(context); } - palock = unique_palock{}; + palock.unlock(); pa_threaded_mainloop_stop(loop); } if(loop) @@ -674,6 +729,69 @@ void PulsePlayback_probeDevices(void) } +struct PulsePlayback final : public ALCbackend { + PulsePlayback(ALCdevice *device) noexcept : ALCbackend{device} { } + ~PulsePlayback() override; + + std::string mDeviceName; + + pa_buffer_attr mAttr; + pa_sample_spec mSpec; + + pa_threaded_mainloop *mLoop{nullptr}; + + pa_stream *mStream{nullptr}; + pa_context *mContext{nullptr}; + + ALuint mBufferSize{0u}; + ALuint mFrameSize{0u}; +}; + +void PulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata); +void PulsePlayback_contextStateCallback(pa_context *context, void *pdata); +void PulsePlayback_streamStateCallback(pa_stream *stream, void *pdata); +void PulsePlayback_streamWriteCallback(pa_stream *p, size_t nbytes, void *userdata); +void PulsePlayback_sinkInfoCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); +void PulsePlayback_sinkNameCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); +void PulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata); + +void PulsePlayback_Construct(PulsePlayback *self, ALCdevice *device); +void PulsePlayback_Destruct(PulsePlayback *self); +ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name); +ALCboolean PulsePlayback_reset(PulsePlayback *self); +ALCboolean PulsePlayback_start(PulsePlayback *self); +void PulsePlayback_stop(PulsePlayback *self); +DECLARE_FORWARD2(PulsePlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) +DECLARE_FORWARD(PulsePlayback, ALCbackend, ALCuint, availableSamples) +ClockLatency PulsePlayback_getClockLatency(PulsePlayback *self); +void PulsePlayback_lock(PulsePlayback *self); +void PulsePlayback_unlock(PulsePlayback *self); +DECLARE_DEFAULT_ALLOCATORS(PulsePlayback) + +DEFINE_ALCBACKEND_VTABLE(PulsePlayback); + + +void PulsePlayback_Construct(PulsePlayback *self, ALCdevice *device) +{ + new (self) PulsePlayback{device}; + SET_VTABLE2(PulsePlayback, ALCbackend, self); +} + +void PulsePlayback_Destruct(PulsePlayback *self) +{ self->~PulsePlayback(); } + +PulsePlayback::~PulsePlayback() +{ + if(!mLoop) + return; + + pulse_close(mLoop, mContext, mStream); + mLoop = nullptr; + mContext = nullptr; + mStream = nullptr; +} + + void PulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata) { auto self = static_cast(pdata); @@ -826,53 +944,6 @@ void PulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata) } -pa_stream *PulsePlayback_connectStream(const char *device_name, - pa_threaded_mainloop *loop, pa_context *context, - pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, - pa_channel_map *chanmap) -{ - if(!device_name) - { - device_name = getenv("ALSOFT_PULSE_DEFAULT"); - if(device_name && !device_name[0]) - device_name = nullptr; - } - - pa_stream *stream{pa_stream_new_with_proplist(context, - "Playback Stream", spec, chanmap, prop_filter)}; - if(!stream) - { - ERR("pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context))); - return nullptr; - } - - pa_stream_set_state_callback(stream, stream_state_callback, loop); - - if(pa_stream_connect_playback(stream, device_name, attr, flags, nullptr, nullptr) < 0) - { - ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(context))); - pa_stream_unref(stream); - return nullptr; - } - - pa_stream_state_t state; - while((state=pa_stream_get_state(stream)) != PA_STREAM_READY) - { - if(!PA_STREAM_IS_GOOD(state)) - { - ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(context))); - pa_stream_unref(stream); - return nullptr; - } - - pa_threaded_mainloop_wait(loop); - } - pa_stream_set_state_callback(stream, nullptr, nullptr); - - return stream; -} - - ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) { const char *pulse_name{nullptr}; @@ -881,7 +952,7 @@ ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) if(name) { if(PlaybackDevices.empty()) - PulsePlayback_probeDevices(); + probePlaybackDevices(); auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), [name](const DevMap &entry) -> bool @@ -909,8 +980,13 @@ ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) spec.channels = 2; TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); - self->mStream = PulsePlayback_connectStream(pulse_name, self->mLoop, self->mContext, flags, - nullptr, &spec, nullptr); + if(!pulse_name) + { + pulse_name = getenv("ALSOFT_PULSE_DEFAULT"); + if(pulse_name && !pulse_name[0]) pulse_name = nullptr; + } + self->mStream = pulse_connect_stream(pulse_name, self->mLoop, self->mContext, flags, nullptr, + &spec, nullptr, ALCbackend_Playback); if(!self->mStream) { palock = unique_palock{}; @@ -1044,8 +1120,8 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) self->mAttr.minreq = period_size; self->mAttr.fragsize = -1; - self->mStream = PulsePlayback_connectStream(self->mDeviceName.c_str(), self->mLoop, - self->mContext, flags, &self->mAttr, &self->mSpec, &chanmap); + self->mStream = pulse_connect_stream(self->mDeviceName.c_str(), self->mLoop, self->mContext, + flags, &self->mAttr, &self->mSpec, &chanmap, ALCbackend_Playback); if(!self->mStream) return ALC_FALSE; pa_stream_set_state_callback(self->mStream, PulsePlayback_streamStateCallback, self); @@ -1167,6 +1243,9 @@ void PulsePlayback_unlock(PulsePlayback *self) struct PulseCapture final : public ALCbackend { + PulseCapture(ALCdevice *device) noexcept : ALCbackend{device} { } + ~PulseCapture() override; + std::string mDeviceName; const void *mCapStore{nullptr}; @@ -1182,21 +1261,12 @@ struct PulseCapture final : public ALCbackend { pa_stream *mStream{nullptr}; pa_context *mContext{nullptr}; - - PulseCapture(ALCdevice *device) noexcept : ALCbackend{device} { } }; -void PulseCapture_deviceCallback(pa_context *context, const pa_source_info *info, int eol, void *pdata); -void PulseCapture_probeDevices(void); - void PulseCapture_contextStateCallback(pa_context *context, void *pdata); void PulseCapture_streamStateCallback(pa_stream *stream, void *pdata); void PulseCapture_sourceNameCallback(pa_context *context, const pa_source_info *info, int eol, void *pdata); void PulseCapture_streamMovedCallback(pa_stream *stream, void *pdata); -pa_stream *PulseCapture_connectStream(const char *device_name, - pa_threaded_mainloop *loop, pa_context *context, - pa_stream_flags_t flags, pa_buffer_attr *attr, - pa_sample_spec *spec, pa_channel_map *chanmap); void PulseCapture_Construct(PulseCapture *self, ALCdevice *device); void PulseCapture_Destruct(PulseCapture *self); @@ -1221,100 +1291,16 @@ void PulseCapture_Construct(PulseCapture *self, ALCdevice *device) } void PulseCapture_Destruct(PulseCapture *self) -{ - if(self->mLoop) - { - pulse_close(self->mLoop, self->mContext, self->mStream); - self->mLoop = nullptr; - self->mContext = nullptr; - self->mStream = nullptr; - } - self->~PulseCapture(); -} - +{ self->~PulseCapture(); } -void PulseCapture_deviceCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata) +PulseCapture::~PulseCapture() { - auto loop = static_cast(pdata); - - if(eol) - { - pa_threaded_mainloop_signal(loop, 0); + if(!mLoop) return; - } - - /* Skip this device is if it's already in the list. */ - if(std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), - [info](const DevMap &entry) -> bool - { return entry.device_name == info->name; } - ) != CaptureDevices.cend()) - return; - - /* Make sure the display name (description) is unique. Append a number - * counter as needed. - */ - int count{1}; - std::string newname{info->description}; - while(checkName(CaptureDevices, newname)) - { - newname = info->description; - newname += " #"; - newname += std::to_string(++count); - } - CaptureDevices.emplace_back(std::move(newname), info->name); - DevMap &newentry = CaptureDevices.back(); - - TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str()); -} - -void PulseCapture_probeDevices(void) -{ - CaptureDevices.clear(); - - pa_threaded_mainloop *loop{pa_threaded_mainloop_new()}; - if(loop && pa_threaded_mainloop_start(loop) >= 0) - { - unique_palock palock{loop}; - - pa_context *context{connect_context(loop, AL_FALSE)}; - if(context) - { - pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | - PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE}; - - pa_sample_spec spec; - spec.format = PA_SAMPLE_S16NE; - spec.rate = 44100; - spec.channels = 1; - - pa_stream *stream{PulseCapture_connectStream(nullptr, - loop, context, flags, nullptr, &spec, nullptr - )}; - if(stream) - { - pa_operation *op{pa_context_get_source_info_by_name(context, - pa_stream_get_device_name(stream), PulseCapture_deviceCallback, loop - )}; - wait_for_operation(op, loop); - - pa_stream_disconnect(stream); - pa_stream_unref(stream); - stream = nullptr; - } - - pa_operation *op{pa_context_get_source_info_list(context, - PulseCapture_deviceCallback, loop - )}; - wait_for_operation(op, loop); - - pa_context_disconnect(context); - pa_context_unref(context); - } - palock.unlock(); - pa_threaded_mainloop_stop(loop); - } - if(loop) - pa_threaded_mainloop_free(loop); + pulse_close(mLoop, mContext, mStream); + mLoop = nullptr; + mContext = nullptr; + mStream = nullptr; } @@ -1366,47 +1352,6 @@ void PulseCapture_streamMovedCallback(pa_stream *stream, void *pdata) } -pa_stream *PulseCapture_connectStream(const char *device_name, - pa_threaded_mainloop *loop, pa_context *context, - pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, - pa_channel_map *chanmap) -{ - pa_stream *stream{pa_stream_new_with_proplist(context, - "Capture Stream", spec, chanmap, prop_filter - )}; - if(!stream) - { - ERR("pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context))); - return nullptr; - } - - pa_stream_set_state_callback(stream, stream_state_callback, loop); - - if(pa_stream_connect_record(stream, device_name, attr, flags) < 0) - { - ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(context))); - pa_stream_unref(stream); - return nullptr; - } - - pa_stream_state_t state; - while((state=pa_stream_get_state(stream)) != PA_STREAM_READY) - { - if(!PA_STREAM_IS_GOOD(state)) - { - ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(context))); - pa_stream_unref(stream); - return nullptr; - } - - pa_threaded_mainloop_wait(loop); - } - pa_stream_set_state_callback(stream, nullptr, nullptr); - - return stream; -} - - ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) { ALCdevice *device{self->mDevice}; @@ -1415,7 +1360,7 @@ ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) if(name) { if(CaptureDevices.empty()) - PulseCapture_probeDevices(); + probeCaptureDevices(); auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), [name](const DevMap &entry) -> bool @@ -1518,8 +1463,8 @@ ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) flags |= PA_STREAM_DONT_MOVE; TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); - self->mStream = PulseCapture_connectStream(pulse_name, self->mLoop, self->mContext, flags, - &self->mAttr, &self->mSpec, &chanmap); + self->mStream = pulse_connect_stream(pulse_name, self->mLoop, self->mContext, flags, + &self->mAttr, &self->mSpec, &chanmap, ALCbackend_Capture); if(!self->mStream) return ALC_INVALID_VALUE; pa_stream_set_moved_callback(self->mStream, PulseCapture_streamMovedCallback, self); @@ -1739,12 +1684,12 @@ void PulseBackendFactory::probe(DevProbe type, std::string *outnames) switch(type) { case ALL_DEVICE_PROBE: - PulsePlayback_probeDevices(); + probePlaybackDevices(); std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); break; case CAPTURE_DEVICE_PROBE: - PulseCapture_probeDevices(); + probeCaptureDevices(); std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); break; } -- cgit v1.2.3 From 983904bbdce5d0973c3cda143f499872e55013e3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 28 Dec 2018 02:16:46 -0800 Subject: Add a method to prefix logged function names --- Alc/helpers.cpp | 8 ++++---- Alc/logging.h | 16 +++++----------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index 2db544b8..4a80c7e5 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -361,7 +361,7 @@ void *GetSymbol(void *handle, const char *name) } -void al_print(const char *type, const char *func, const char *fmt, ...) +void al_print(const char *type, const char *prefix, const char *func, const char *fmt, ...) { char str[1024]; va_list ap; @@ -372,7 +372,7 @@ void al_print(const char *type, const char *func, const char *fmt, ...) str[sizeof(str)-1] = 0; std::wstring wstr{utf8_to_wstr(str)}; - fprintf(gLogFile, "AL lib: %s %s: %ls", type, func, wstr.c_str()); + fprintf(gLogFile, "AL lib: %s %s%s: %ls", type, prefix, func, wstr.c_str()); fflush(gLogFile); } @@ -588,12 +588,12 @@ void *GetSymbol(void *handle, const char *name) #endif /* HAVE_DLFCN_H */ -void al_print(const char *type, const char *func, const char *fmt, ...) +void al_print(const char *type, const char *prefix, const char *func, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - fprintf(gLogFile, "AL lib: %s %s: ", type, func); + fprintf(gLogFile, "AL lib: %s %s%s: ", type, prefix, func); vfprintf(gLogFile, fmt, ap); va_end(ap); diff --git a/Alc/logging.h b/Alc/logging.h index 41f64f77..ae70e598 100644 --- a/Alc/logging.h +++ b/Alc/logging.h @@ -18,22 +18,20 @@ #define DECL_FORMAT(x, y, z) #endif -#ifdef __cplusplus -extern "C" { -#endif extern FILE *gLogFile; +constexpr inline const char *CurrentPrefix() noexcept { return ""; } #if defined(__GNUC__) && !defined(_WIN32) -#define AL_PRINT(T, MSG, ...) fprintf(gLogFile, "AL lib: %s %s: " MSG, T, __FUNCTION__ , ## __VA_ARGS__) +#define AL_PRINT(T, MSG, ...) fprintf(gLogFile, "AL lib: %s %s%s: " MSG, T, CurrentPrefix(), __FUNCTION__ , ## __VA_ARGS__) #else -void al_print(const char *type, const char *func, const char *fmt, ...) DECL_FORMAT(printf, 3,4); -#define AL_PRINT(T, ...) al_print((T), __FUNCTION__, __VA_ARGS__) +void al_print(const char *type, const char *prefix, const char *func, const char *fmt, ...) DECL_FORMAT(printf, 4,5); +#define AL_PRINT(T, ...) al_print((T), CurrentPrefix(), __FUNCTION__, __VA_ARGS__) #endif #ifdef __ANDROID__ #include -#define LOG_ANDROID(T, MSG, ...) __android_log_print(T, "openal", "AL lib: %s: " MSG, __FUNCTION__ , ## __VA_ARGS__) +#define LOG_ANDROID(T, MSG, ...) __android_log_print(T, "openal", "AL lib: %s%s: " MSG, CurrentPrefix(), __FUNCTION__ , ## __VA_ARGS__) #else #define LOG_ANDROID(T, MSG, ...) ((void)0) #endif @@ -70,8 +68,4 @@ extern LogLevel gLogLevel; LOG_ANDROID(ANDROID_LOG_ERROR, __VA_ARGS__); \ } while(0) -#ifdef __cplusplus -} /* extern "C" */ -#endif - #endif /* LOGGING_H */ -- cgit v1.2.3 From 200e267b8113a00485bbb216acb7fa6e65332d1f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 28 Dec 2018 12:58:01 -0800 Subject: Turn some more methods into member functions --- Alc/backends/pulseaudio.cpp | 211 +++++++++++++++++++++++++------------------- 1 file changed, 118 insertions(+), 93 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 3130df19..60307e94 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -733,6 +733,27 @@ struct PulsePlayback final : public ALCbackend { PulsePlayback(ALCdevice *device) noexcept : ALCbackend{device} { } ~PulsePlayback() override; + static void bufferAttrCallbackC(pa_stream *stream, void *pdata); + void bufferAttrCallback(pa_stream *stream); + + static void contextStateCallbackC(pa_context *context, void *pdata); + void contextStateCallback(pa_context *context); + + static void streamStateCallbackC(pa_stream *stream, void *pdata); + void streamStateCallback(pa_stream *stream); + + static void streamWriteCallbackC(pa_stream *stream, size_t nbytes, void *pdata); + void streamWriteCallback(pa_stream *stream, size_t nbytes); + + static void sinkInfoCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata); + void sinkInfoCallback(pa_context *context, const pa_sink_info *info, int eol); + + static void sinkNameCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata); + void sinkNameCallback(pa_context *context, const pa_sink_info *info, int eol); + + static void streamMovedCallbackC(pa_stream *stream, void *pdata); + void streamMovedCallback(pa_stream *stream); + std::string mDeviceName; pa_buffer_attr mAttr; @@ -745,15 +766,9 @@ struct PulsePlayback final : public ALCbackend { ALuint mBufferSize{0u}; ALuint mFrameSize{0u}; -}; -void PulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata); -void PulsePlayback_contextStateCallback(pa_context *context, void *pdata); -void PulsePlayback_streamStateCallback(pa_stream *stream, void *pdata); -void PulsePlayback_streamWriteCallback(pa_stream *p, size_t nbytes, void *userdata); -void PulsePlayback_sinkInfoCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); -void PulsePlayback_sinkNameCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata); -void PulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata); + static constexpr inline const char *CurrentPrefix() noexcept { return "PulsePlayback::"; } +}; void PulsePlayback_Construct(PulsePlayback *self, ALCdevice *device); void PulsePlayback_Destruct(PulsePlayback *self); @@ -792,64 +807,70 @@ PulsePlayback::~PulsePlayback() } -void PulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata) -{ - auto self = static_cast(pdata); +void PulsePlayback::bufferAttrCallbackC(pa_stream *stream, void *pdata) +{ static_cast(pdata)->bufferAttrCallback(stream); } +void PulsePlayback::bufferAttrCallback(pa_stream *stream) +{ /* FIXME: Update the device's UpdateSize (and/or NumUpdates) using the new * buffer attributes? Changing UpdateSize will change the ALC_REFRESH * property, which probably shouldn't change between device resets. But * leaving it alone means ALC_REFRESH will be off. */ - self->mAttr = *(pa_stream_get_buffer_attr(stream)); - TRACE("minreq=%d, tlength=%d, prebuf=%d\n", self->mAttr.minreq, self->mAttr.tlength, - self->mAttr.prebuf); + mAttr = *(pa_stream_get_buffer_attr(stream)); + TRACE("minreq=%d, tlength=%d, prebuf=%d\n", mAttr.minreq, mAttr.tlength, mAttr.prebuf); - const ALuint num_periods{(self->mAttr.tlength + self->mAttr.minreq/2u) / self->mAttr.minreq}; - self->mBufferSize = maxu(num_periods, 2u) * self->mAttr.minreq; + const ALuint num_periods{(mAttr.tlength + mAttr.minreq/2u) / mAttr.minreq}; + mBufferSize = maxu(num_periods, 2u) * mAttr.minreq; } -void PulsePlayback_contextStateCallback(pa_context *context, void *pdata) +void PulsePlayback::contextStateCallbackC(pa_context *context, void *pdata) +{ static_cast(pdata)->contextStateCallback(context); } + +void PulsePlayback::contextStateCallback(pa_context *context) { - auto self = static_cast(pdata); if(pa_context_get_state(context) == PA_CONTEXT_FAILED) { ERR("Received context failure!\n"); - aluHandleDisconnect(self->mDevice, "Playback state failure"); + aluHandleDisconnect(mDevice, "Playback state failure"); } - pa_threaded_mainloop_signal(self->mLoop, 0); + pa_threaded_mainloop_signal(mLoop, 0); } -void PulsePlayback_streamStateCallback(pa_stream *stream, void *pdata) +void PulsePlayback::streamStateCallbackC(pa_stream *stream, void *pdata) +{ static_cast(pdata)->streamStateCallback(stream); } + +void PulsePlayback::streamStateCallback(pa_stream *stream) { - auto self = static_cast(pdata); if(pa_stream_get_state(stream) == PA_STREAM_FAILED) { ERR("Received stream failure!\n"); - aluHandleDisconnect(self->mDevice, "Playback stream failure"); + aluHandleDisconnect(mDevice, "Playback stream failure"); } - pa_threaded_mainloop_signal(self->mLoop, 0); + pa_threaded_mainloop_signal(mLoop, 0); } -void PulsePlayback_streamWriteCallback(pa_stream *stream, size_t nbytes, void *pdata) -{ - auto self = static_cast(pdata); - ALCdevice *device{self->mDevice}; +void PulsePlayback::streamWriteCallbackC(pa_stream *stream, size_t nbytes, void *pdata) +{ static_cast(pdata)->streamWriteCallback(stream, nbytes); } +void PulsePlayback::streamWriteCallback(pa_stream *stream, size_t nbytes) +{ /* Round down to the nearest period/minreq multiple if doing more than 1. */ - const size_t frame_size{self->mFrameSize}; - if(nbytes > self->mAttr.minreq) - nbytes -= nbytes%self->mAttr.minreq; + if(nbytes > mAttr.minreq) + nbytes -= nbytes%mAttr.minreq; void *buf{pa_xmalloc(nbytes)}; - aluMixData(device, buf, nbytes/frame_size); + aluMixData(mDevice, buf, nbytes/mFrameSize); int ret{pa_stream_write(stream, buf, nbytes, pa_xfree, 0, PA_SEEK_RELATIVE)}; if(UNLIKELY(ret != PA_OK)) ERR("Failed to write to stream: %d, %s\n", ret, pa_strerror(ret)); } -void PulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) +void PulsePlayback::sinkInfoCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata) +{ static_cast(pdata)->sinkInfoCallback(context, info, eol); } + +void PulsePlayback::sinkInfoCallback(pa_context* UNUSED(context), const pa_sink_info *info, int eol) { struct ChannelMap { DevFmtChannels chans; @@ -887,23 +908,21 @@ void PulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa_sink_i } } }, { DevFmtMono, { 1, {PA_CHANNEL_POSITION_MONO} } } }}; - auto self = static_cast(pdata); if(eol) { - pa_threaded_mainloop_signal(self->mLoop, 0); + pa_threaded_mainloop_signal(mLoop, 0); return; } - ALCdevice *device{self->mDevice}; auto chanmap = std::find_if(chanmaps.cbegin(), chanmaps.cend(), [info](const ChannelMap &chanmap) -> bool { return pa_channel_map_superset(&info->channel_map, &chanmap.map); } ); if(chanmap != chanmaps.cend()) { - if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) - device->FmtChans = chanmap->chans; + if(!(mDevice->Flags&DEVICE_CHANNELS_REQUEST)) + mDevice->FmtChans = chanmap->chans; } else { @@ -914,33 +933,30 @@ void PulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa_sink_i if(info->active_port) TRACE("Active port: %s (%s)\n", info->active_port->name, info->active_port->description); - device->IsHeadphones = (info->active_port && - strcmp(info->active_port->name, "analog-output-headphones") == 0 && - device->FmtChans == DevFmtStereo); + mDevice->IsHeadphones = (mDevice->FmtChans == DevFmtStereo && + info->active_port && strcmp(info->active_port->name, "analog-output-headphones") == 0); } -void PulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) -{ - auto self = static_cast(pdata); +void PulsePlayback::sinkNameCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata) +{ static_cast(pdata)->sinkNameCallback(context, info, eol); } +void PulsePlayback::sinkNameCallback(pa_context* UNUSED(context), const pa_sink_info *info, int eol) +{ if(eol) { - pa_threaded_mainloop_signal(self->mLoop, 0); + pa_threaded_mainloop_signal(mLoop, 0); return; } - - ALCdevice *device{self->mDevice}; - device->DeviceName = info->description; + mDevice->DeviceName = info->description; } +void PulsePlayback::streamMovedCallbackC(pa_stream *stream, void *pdata) +{ static_cast(pdata)->streamMovedCallback(stream); } -void PulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata) +void PulsePlayback::streamMovedCallback(pa_stream *stream) { - auto self = static_cast(pdata); - - self->mDeviceName = pa_stream_get_device_name(stream); - - TRACE("Stream moved to %s\n", self->mDeviceName.c_str()); + mDeviceName = pa_stream_get_device_name(stream); + TRACE("Stream moved to %s\n", mDeviceName.c_str()); } @@ -964,7 +980,7 @@ ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) dev_name = iter->name.c_str(); } - std::tie(self->mLoop, self->mContext) = pulse_open(PulsePlayback_contextStateCallback, self); + std::tie(self->mLoop, self->mContext) = pulse_open(&PulsePlayback::contextStateCallbackC, self); if(!self->mLoop) return ALC_INVALID_VALUE; unique_palock palock{self->mLoop}; @@ -995,14 +1011,14 @@ ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) self->mContext = nullptr; return ALC_INVALID_VALUE; } - pa_stream_set_moved_callback(self->mStream, PulsePlayback_streamMovedCallback, self); + pa_stream_set_moved_callback(self->mStream, &PulsePlayback::streamMovedCallbackC, self); self->mFrameSize = pa_frame_size(pa_stream_get_sample_spec(self->mStream)); self->mDeviceName = pa_stream_get_device_name(self->mStream); if(!dev_name) { pa_operation *op{pa_context_get_sink_info_by_name(self->mContext, - self->mDeviceName.c_str(), PulsePlayback_sinkNameCallback, self)}; + self->mDeviceName.c_str(), &PulsePlayback::sinkNameCallbackC, self)}; wait_for_operation(op, self->mLoop); } else @@ -1030,7 +1046,7 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) } pa_operation *op{pa_context_get_sink_info_by_name(self->mContext, - self->mDeviceName.c_str(), PulsePlayback_sinkInfoCallback, self)}; + self->mDeviceName.c_str(), &PulsePlayback::sinkInfoCallbackC, self)}; wait_for_operation(op, self->mLoop); ALCdevice *device{self->mDevice}; @@ -1124,8 +1140,8 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) flags, &self->mAttr, &self->mSpec, &chanmap, ALCbackend_Playback); if(!self->mStream) return ALC_FALSE; - pa_stream_set_state_callback(self->mStream, PulsePlayback_streamStateCallback, self); - pa_stream_set_moved_callback(self->mStream, PulsePlayback_streamMovedCallback, self); + pa_stream_set_state_callback(self->mStream, &PulsePlayback::streamStateCallbackC, self); + pa_stream_set_moved_callback(self->mStream, &PulsePlayback::streamMovedCallbackC, self); self->mSpec = *(pa_stream_get_sample_spec(self->mStream)); self->mFrameSize = pa_frame_size(&self->mSpec); @@ -1150,8 +1166,8 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) device->Frequency = self->mSpec.rate; } - pa_stream_set_buffer_attr_callback(self->mStream, PulsePlayback_bufferAttrCallback, self); - PulsePlayback_bufferAttrCallback(self->mStream, self); + pa_stream_set_buffer_attr_callback(self->mStream, &PulsePlayback::bufferAttrCallbackC, self); + self->bufferAttrCallback(self->mStream); device->NumUpdates = clampu( (self->mAttr.tlength + self->mAttr.minreq/2u) / self->mAttr.minreq, 2u, 16u); @@ -1184,7 +1200,7 @@ ALCboolean PulsePlayback_start(PulsePlayback *self) { unique_palock palock{self->mLoop}; - pa_stream_set_write_callback(self->mStream, PulsePlayback_streamWriteCallback, self); + pa_stream_set_write_callback(self->mStream, &PulsePlayback::streamWriteCallbackC, self); pa_operation *op{pa_stream_cork(self->mStream, 0, stream_success_callback, self->mLoop)}; wait_for_operation(op, self->mLoop); @@ -1246,6 +1262,18 @@ struct PulseCapture final : public ALCbackend { PulseCapture(ALCdevice *device) noexcept : ALCbackend{device} { } ~PulseCapture() override; + static void contextStateCallbackC(pa_context *context, void *pdata); + void contextStateCallback(pa_context *context); + + static void streamStateCallbackC(pa_stream *stream, void *pdata); + void streamStateCallback(pa_stream *stream); + + static void sourceNameCallbackC(pa_context *context, const pa_source_info *info, int eol, void *pdata); + void sourceNameCallback(pa_context *context, const pa_source_info *info, int eol); + + static void streamMovedCallbackC(pa_stream *stream, void *pdata); + void streamMovedCallback(pa_stream *stream); + std::string mDeviceName; const void *mCapStore{nullptr}; @@ -1261,12 +1289,9 @@ struct PulseCapture final : public ALCbackend { pa_stream *mStream{nullptr}; pa_context *mContext{nullptr}; -}; -void PulseCapture_contextStateCallback(pa_context *context, void *pdata); -void PulseCapture_streamStateCallback(pa_stream *stream, void *pdata); -void PulseCapture_sourceNameCallback(pa_context *context, const pa_source_info *info, int eol, void *pdata); -void PulseCapture_streamMovedCallback(pa_stream *stream, void *pdata); + static constexpr inline const char *CurrentPrefix() noexcept { return "PulseCapture::"; } +}; void PulseCapture_Construct(PulseCapture *self, ALCdevice *device); void PulseCapture_Destruct(PulseCapture *self); @@ -1303,52 +1328,52 @@ PulseCapture::~PulseCapture() mStream = nullptr; } +void PulseCapture::contextStateCallbackC(pa_context *context, void *pdata) +{ static_cast(pdata)->contextStateCallback(context); } -void PulseCapture_contextStateCallback(pa_context *context, void *pdata) +void PulseCapture::contextStateCallback(pa_context *context) { - auto self = static_cast(pdata); if(pa_context_get_state(context) == PA_CONTEXT_FAILED) { ERR("Received context failure!\n"); - aluHandleDisconnect(self->mDevice, "Capture state failure"); + aluHandleDisconnect(mDevice, "Capture state failure"); } - pa_threaded_mainloop_signal(self->mLoop, 0); + pa_threaded_mainloop_signal(mLoop, 0); } -void PulseCapture_streamStateCallback(pa_stream *stream, void *pdata) +void PulseCapture::streamStateCallbackC(pa_stream *stream, void *pdata) +{ static_cast(pdata)->streamStateCallback(stream); } + +void PulseCapture::streamStateCallback(pa_stream *stream) { - auto self = static_cast(pdata); if(pa_stream_get_state(stream) == PA_STREAM_FAILED) { ERR("Received stream failure!\n"); - aluHandleDisconnect(self->mDevice, "Capture stream failure"); + aluHandleDisconnect(mDevice, "Capture stream failure"); } - pa_threaded_mainloop_signal(self->mLoop, 0); + pa_threaded_mainloop_signal(mLoop, 0); } +void PulseCapture::sourceNameCallbackC(pa_context *context, const pa_source_info *info, int eol, void *pdata) +{ static_cast(pdata)->sourceNameCallback(context, info, eol); } -void PulseCapture_sourceNameCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata) +void PulseCapture::sourceNameCallback(pa_context* UNUSED(context), const pa_source_info *info, int eol) { - auto self = static_cast(pdata); - if(eol) { - pa_threaded_mainloop_signal(self->mLoop, 0); + pa_threaded_mainloop_signal(mLoop, 0); return; } - - ALCdevice *device{self->mDevice}; - device->DeviceName = info->description; + mDevice->DeviceName = info->description; } +void PulseCapture::streamMovedCallbackC(pa_stream *stream, void *pdata) +{ static_cast(pdata)->streamMovedCallback(stream); } -void PulseCapture_streamMovedCallback(pa_stream *stream, void *pdata) +void PulseCapture::streamMovedCallback(pa_stream *stream) { - auto self = static_cast(pdata); - - self->mDeviceName = pa_stream_get_device_name(stream); - - TRACE("Stream moved to %s\n", self->mDeviceName.c_str()); + mDeviceName = pa_stream_get_device_name(stream); + TRACE("Stream moved to %s\n", mDeviceName.c_str()); } @@ -1372,7 +1397,7 @@ ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) device->DeviceName = iter->name; } - std::tie(self->mLoop, self->mContext) = pulse_open(PulseCapture_contextStateCallback, self); + std::tie(self->mLoop, self->mContext) = pulse_open(&PulseCapture::contextStateCallbackC, self); if(!self->mLoop) return ALC_INVALID_VALUE; unique_palock palock{self->mLoop}; @@ -1467,14 +1492,14 @@ ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) &self->mAttr, &self->mSpec, &chanmap, ALCbackend_Capture); if(!self->mStream) return ALC_INVALID_VALUE; - pa_stream_set_moved_callback(self->mStream, PulseCapture_streamMovedCallback, self); - pa_stream_set_state_callback(self->mStream, PulseCapture_streamStateCallback, self); + pa_stream_set_moved_callback(self->mStream, &PulseCapture::streamMovedCallbackC, self); + pa_stream_set_state_callback(self->mStream, &PulseCapture::streamStateCallbackC, self); self->mDeviceName = pa_stream_get_device_name(self->mStream); if(device->DeviceName.empty()) { pa_operation *op{pa_context_get_source_info_by_name(self->mContext, - self->mDeviceName.c_str(), PulseCapture_sourceNameCallback, self + self->mDeviceName.c_str(), &PulseCapture::sourceNameCallbackC, self )}; wait_for_operation(op, self->mLoop); } -- cgit v1.2.3 From b7f5166d59bc3782cc804eb2019f028fd6cdd4e7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 28 Dec 2018 14:06:15 -0800 Subject: Turn even more methods into member functions --- Alc/backends/qsa.cpp | 30 ++++---- Alc/backends/sdl2.cpp | 81 +++++++++++---------- Alc/backends/sndio.cpp | 184 +++++++++++++++++++++++------------------------ Alc/backends/solaris.cpp | 127 ++++++++++++++++---------------- Alc/backends/wave.cpp | 127 ++++++++++++++++---------------- 5 files changed, 278 insertions(+), 271 deletions(-) diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index 6ceaf0a6..c7c8e90b 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -171,9 +171,10 @@ void deviceList(int type, al::vector *devmap) /* Wrappers to use an old-style backend with the new interface. */ struct PlaybackWrapper final : public ALCbackend { - std::unique_ptr mExtraData; - PlaybackWrapper(ALCdevice *device) noexcept : ALCbackend{device} { } + ~PlaybackWrapper() override; + + std::unique_ptr mExtraData; }; static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device); @@ -620,11 +621,12 @@ static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device) } static void PlaybackWrapper_Destruct(PlaybackWrapper *self) -{ - if(self->mExtraData) - qsa_close_playback(self); +{ self->~PlaybackWrapper(); } - self->~PlaybackWrapper(); +PlaybackWrapper::~PlaybackWrapper() +{ + if(mExtraData) + qsa_close_playback(this); } static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name) @@ -654,9 +656,10 @@ static void PlaybackWrapper_stop(PlaybackWrapper *self) /***********/ struct CaptureWrapper final : public ALCbackend { - std::unique_ptr mExtraData; - CaptureWrapper(ALCdevice *device) noexcept : ALCbackend{device} { } + ~CaptureWrapper() override; + + std::unique_ptr mExtraData; }; static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device); @@ -778,7 +781,7 @@ static void qsa_close_capture(CaptureWrapper *self) if (data->pcmHandle!=nullptr) snd_pcm_close(data->pcmHandle); - data->pcmHandle = nullptr + data->pcmHandle = nullptr; self->mExtraData = nullptr; } @@ -921,11 +924,12 @@ static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device) } static void CaptureWrapper_Destruct(CaptureWrapper *self) -{ - if(self->mExtraData) - qsa_close_capture(self); +{ self->~CaptureWrapper(); } - self->~CaptureWrapper(); +CaptureWrapper::~CaptureWrapper() +{ + if(mExtraData) + qsa_close_capture(this); } static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name) diff --git a/Alc/backends/sdl2.cpp b/Alc/backends/sdl2.cpp index 12cf7a35..985afa2e 100644 --- a/Alc/backends/sdl2.cpp +++ b/Alc/backends/sdl2.cpp @@ -33,13 +33,23 @@ #include "compat.h" +namespace { + #ifdef _WIN32 #define DEVNAME_PREFIX "OpenAL Soft on " #else #define DEVNAME_PREFIX "" #endif +constexpr ALCchar defaultDeviceName[] = DEVNAME_PREFIX "Default Device"; + struct ALCsdl2Backend final : public ALCbackend { + ALCsdl2Backend(ALCdevice *device) noexcept : ALCbackend{device} { } + ~ALCsdl2Backend() override; + + static void audioCallbackC(void *ptr, Uint8 *stream, int len); + void audioCallback(Uint8 *stream, int len); + SDL_AudioDeviceID mDeviceID{0u}; ALsizei mFrameSize{0}; @@ -47,58 +57,52 @@ struct ALCsdl2Backend final : public ALCbackend { DevFmtChannels mFmtChans{}; DevFmtType mFmtType{}; ALuint mUpdateSize{0u}; - - ALCsdl2Backend(ALCdevice *device) noexcept : ALCbackend{device} { } }; -static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device); -static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self); -static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name); -static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self); -static ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self); -static void ALCsdl2Backend_stop(ALCsdl2Backend *self); -static DECLARE_FORWARD2(ALCsdl2Backend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ClockLatency, getClockLatency) -static void ALCsdl2Backend_lock(ALCsdl2Backend *self); -static void ALCsdl2Backend_unlock(ALCsdl2Backend *self); +void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device); +void ALCsdl2Backend_Destruct(ALCsdl2Backend *self); +ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name); +ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self); +ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self); +void ALCsdl2Backend_stop(ALCsdl2Backend *self); +DECLARE_FORWARD2(ALCsdl2Backend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ALCuint, availableSamples) +DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ClockLatency, getClockLatency) +void ALCsdl2Backend_lock(ALCsdl2Backend *self); +void ALCsdl2Backend_unlock(ALCsdl2Backend *self); DECLARE_DEFAULT_ALLOCATORS(ALCsdl2Backend) DEFINE_ALCBACKEND_VTABLE(ALCsdl2Backend); -static const ALCchar defaultDeviceName[] = DEVNAME_PREFIX "Default Device"; - -static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device) +void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device) { new (self) ALCsdl2Backend{device}; SET_VTABLE2(ALCsdl2Backend, ALCbackend, self); } -static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self) -{ - if(self->mDeviceID) - SDL_CloseAudioDevice(self->mDeviceID); - self->mDeviceID = 0; +void ALCsdl2Backend_Destruct(ALCsdl2Backend *self) +{ self->~ALCsdl2Backend(); } - self->~ALCsdl2Backend(); +ALCsdl2Backend::~ALCsdl2Backend() +{ + if(mDeviceID) + SDL_CloseAudioDevice(mDeviceID); + mDeviceID = 0; } +void ALCsdl2Backend::audioCallbackC(void *ptr, Uint8 *stream, int len) +{ static_cast(ptr)->audioCallback(stream, len); } -static void ALCsdl2Backend_audioCallback(void *ptr, Uint8 *stream, int len) +void ALCsdl2Backend::audioCallback(Uint8 *stream, int len) { - auto self = static_cast(ptr); - - assert((len % self->mFrameSize) == 0); - aluMixData(self->mDevice, stream, len / self->mFrameSize); + assert((len % mFrameSize) == 0); + aluMixData(mDevice, stream, len / mFrameSize); } -static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) +ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) { ALCdevice *device{self->mDevice}; - SDL_AudioSpec want, have; - - SDL_zero(want); - SDL_zero(have); + SDL_AudioSpec want{}, have{}; want.freq = device->Frequency; switch(device->FmtType) @@ -113,7 +117,7 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) } want.channels = (device->FmtChans == DevFmtMono) ? 1 : 2; want.samples = device->UpdateSize; - want.callback = ALCsdl2Backend_audioCallback; + want.callback = &ALCsdl2Backend::audioCallbackC; want.userdata = self; /* Passing nullptr to SDL_OpenAudioDevice opens a default, which isn't @@ -170,7 +174,7 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) return ALC_NO_ERROR; } -static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self) +ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self) { ALCdevice *device{self->mDevice}; device->Frequency = self->mFrequency; @@ -182,27 +186,28 @@ static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self) return ALC_TRUE; } -static ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self) +ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self) { SDL_PauseAudioDevice(self->mDeviceID, 0); return ALC_TRUE; } -static void ALCsdl2Backend_stop(ALCsdl2Backend *self) +void ALCsdl2Backend_stop(ALCsdl2Backend *self) { SDL_PauseAudioDevice(self->mDeviceID, 1); } -static void ALCsdl2Backend_lock(ALCsdl2Backend *self) +void ALCsdl2Backend_lock(ALCsdl2Backend *self) { SDL_LockAudioDevice(self->mDeviceID); } -static void ALCsdl2Backend_unlock(ALCsdl2Backend *self) +void ALCsdl2Backend_unlock(ALCsdl2Backend *self) { SDL_UnlockAudioDevice(self->mDeviceID); } +} // namespace BackendFactory &SDL2BackendFactory::getFactory() { diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index e4d1e9f0..d185adab 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -43,6 +43,11 @@ static const ALCchar sndio_device[] = "SndIO Default"; struct SndioPlayback final : public ALCbackend { + SndioPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } + ~SndioPlayback() override; + + int mixerProc(); + sio_hdl *mSndHandle{nullptr}; al::vector mBuffer; @@ -50,70 +55,65 @@ struct SndioPlayback final : public ALCbackend { std::atomic mKillNow{true}; std::thread mThread; - SndioPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } + static constexpr inline const char *CurrentPrefix() noexcept { return "SndioPlayback::"; } }; -static int SndioPlayback_mixerProc(SndioPlayback *self); - -static void SndioPlayback_Construct(SndioPlayback *self, ALCdevice *device); -static void SndioPlayback_Destruct(SndioPlayback *self); -static ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name); -static ALCboolean SndioPlayback_reset(SndioPlayback *self); -static ALCboolean SndioPlayback_start(SndioPlayback *self); -static void SndioPlayback_stop(SndioPlayback *self); -static DECLARE_FORWARD2(SndioPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(SndioPlayback, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(SndioPlayback, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(SndioPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(SndioPlayback, ALCbackend, void, unlock) +void SndioPlayback_Construct(SndioPlayback *self, ALCdevice *device); +void SndioPlayback_Destruct(SndioPlayback *self); +ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name); +ALCboolean SndioPlayback_reset(SndioPlayback *self); +ALCboolean SndioPlayback_start(SndioPlayback *self); +void SndioPlayback_stop(SndioPlayback *self); +DECLARE_FORWARD2(SndioPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +DECLARE_FORWARD(SndioPlayback, ALCbackend, ALCuint, availableSamples) +DECLARE_FORWARD(SndioPlayback, ALCbackend, ClockLatency, getClockLatency) +DECLARE_FORWARD(SndioPlayback, ALCbackend, void, lock) +DECLARE_FORWARD(SndioPlayback, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(SndioPlayback) DEFINE_ALCBACKEND_VTABLE(SndioPlayback); - -static void SndioPlayback_Construct(SndioPlayback *self, ALCdevice *device) +void SndioPlayback_Construct(SndioPlayback *self, ALCdevice *device) { new (self) SndioPlayback{device}; SET_VTABLE2(SndioPlayback, ALCbackend, self); } -static void SndioPlayback_Destruct(SndioPlayback *self) -{ - if(self->mSndHandle) - sio_close(self->mSndHandle); - self->mSndHandle = nullptr; +void SndioPlayback_Destruct(SndioPlayback *self) +{ self->~SndioPlayback(); } - self->~SndioPlayback(); +SndioPlayback::~SndioPlayback() +{ + if(mSndHandle) + sio_close(mSndHandle); + mSndHandle = nullptr; } - -static int SndioPlayback_mixerProc(SndioPlayback *self) +int SndioPlayback::mixerProc() { - ALCdevice *device{self->mDevice}; - SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - const ALsizei frameSize{device->frameSizeFromFmt()}; + const ALsizei frameSize{mDevice->frameSizeFromFmt()}; - while(!self->mKillNow.load(std::memory_order_acquire) && - device->Connected.load(std::memory_order_acquire)) + while(!mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) { - auto WritePtr = static_cast(self->mBuffer.data()); - size_t len{self->mBuffer.size()}; + auto WritePtr = static_cast(mBuffer.data()); + size_t len{mBuffer.size()}; - SndioPlayback_lock(self); - aluMixData(device, WritePtr, len/frameSize); - SndioPlayback_unlock(self); - while(len > 0 && !self->mKillNow.load(std::memory_order_acquire)) + SndioPlayback_lock(this); + aluMixData(mDevice, WritePtr, len/frameSize); + SndioPlayback_unlock(this); + while(len > 0 && !mKillNow.load(std::memory_order_acquire)) { - size_t wrote{sio_write(self->mSndHandle, WritePtr, len)}; + size_t wrote{sio_write(mSndHandle, WritePtr, len)}; if(wrote == 0) { ERR("sio_write failed\n"); - SndioPlayback_lock(self); - aluHandleDisconnect(device, "Failed to write playback samples"); - SndioPlayback_unlock(self); + SndioPlayback_lock(this); + aluHandleDisconnect(mDevice, "Failed to write playback samples"); + SndioPlayback_unlock(this); break; } @@ -126,7 +126,7 @@ static int SndioPlayback_mixerProc(SndioPlayback *self) } -static ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name) +ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name) { ALCdevice *device{self->mDevice}; @@ -146,7 +146,7 @@ static ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name) return ALC_NO_ERROR; } -static ALCboolean SndioPlayback_reset(SndioPlayback *self) +ALCboolean SndioPlayback_reset(SndioPlayback *self) { ALCdevice *device{self->mDevice}; sio_par par; @@ -234,7 +234,7 @@ static ALCboolean SndioPlayback_reset(SndioPlayback *self) return ALC_TRUE; } -static ALCboolean SndioPlayback_start(SndioPlayback *self) +ALCboolean SndioPlayback_start(SndioPlayback *self) { if(!sio_start(self->mSndHandle)) { @@ -244,7 +244,7 @@ static ALCboolean SndioPlayback_start(SndioPlayback *self) try { self->mKillNow.store(false, std::memory_order_release); - self->mThread = std::thread(SndioPlayback_mixerProc, self); + self->mThread = std::thread{std::mem_fn(&SndioPlayback::mixerProc), self}; return ALC_TRUE; } catch(std::exception& e) { @@ -256,7 +256,7 @@ static ALCboolean SndioPlayback_start(SndioPlayback *self) return ALC_FALSE; } -static void SndioPlayback_stop(SndioPlayback *self) +void SndioPlayback_stop(SndioPlayback *self) { if(self->mKillNow.exchange(true, std::memory_order_acq_rel) || !self->mThread.joinable()) return; @@ -268,6 +268,11 @@ static void SndioPlayback_stop(SndioPlayback *self) struct SndioCapture final : public ALCbackend { + SndioCapture(ALCdevice *device) noexcept : ALCbackend{device} { } + ~SndioCapture() override; + + int recordProc(); + sio_hdl *mSndHandle{nullptr}; RingBufferPtr mRing; @@ -275,84 +280,75 @@ struct SndioCapture final : public ALCbackend { std::atomic mKillNow{true}; std::thread mThread; - SndioCapture(ALCdevice *device) noexcept : ALCbackend{device} { } + static constexpr inline const char *CurrentPrefix() noexcept { return "SndioCapture::"; } }; -static int SndioCapture_recordProc(SndioCapture *self); - -static void SndioCapture_Construct(SndioCapture *self, ALCdevice *device); -static void SndioCapture_Destruct(SndioCapture *self); -static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name); -static DECLARE_FORWARD(SndioCapture, ALCbackend, ALCboolean, reset) -static ALCboolean SndioCapture_start(SndioCapture *self); -static void SndioCapture_stop(SndioCapture *self); -static ALCenum SndioCapture_captureSamples(SndioCapture *self, void *buffer, ALCuint samples); -static ALCuint SndioCapture_availableSamples(SndioCapture *self); -static DECLARE_FORWARD(SndioCapture, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(SndioCapture, ALCbackend, void, lock) -static DECLARE_FORWARD(SndioCapture, ALCbackend, void, unlock) +void SndioCapture_Construct(SndioCapture *self, ALCdevice *device); +void SndioCapture_Destruct(SndioCapture *self); +ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name); +DECLARE_FORWARD(SndioCapture, ALCbackend, ALCboolean, reset) +ALCboolean SndioCapture_start(SndioCapture *self); +void SndioCapture_stop(SndioCapture *self); +ALCenum SndioCapture_captureSamples(SndioCapture *self, void *buffer, ALCuint samples); +ALCuint SndioCapture_availableSamples(SndioCapture *self); +DECLARE_FORWARD(SndioCapture, ALCbackend, ClockLatency, getClockLatency) +DECLARE_FORWARD(SndioCapture, ALCbackend, void, lock) +DECLARE_FORWARD(SndioCapture, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(SndioCapture) DEFINE_ALCBACKEND_VTABLE(SndioCapture); - -static void SndioCapture_Construct(SndioCapture *self, ALCdevice *device) +void SndioCapture_Construct(SndioCapture *self, ALCdevice *device) { new (self) SndioCapture{device}; SET_VTABLE2(SndioCapture, ALCbackend, self); } -static void SndioCapture_Destruct(SndioCapture *self) -{ - if(self->mSndHandle) - sio_close(self->mSndHandle); - self->mSndHandle = nullptr; +void SndioCapture_Destruct(SndioCapture *self) +{ self->~SndioCapture(); } - self->~SndioCapture(); +SndioCapture::~SndioCapture() +{ + if(mSndHandle) + sio_close(mSndHandle); + mSndHandle = nullptr; } - -static int SndioCapture_recordProc(SndioCapture *self) +int SndioCapture::recordProc() { - ALCdevice *device{self->mDevice}; - RingBuffer *ring{self->mRing.get()}; - SetRTPriority(); althrd_setname(RECORD_THREAD_NAME); - const ALsizei frameSize{device->frameSizeFromFmt()}; + const ALsizei frameSize{mDevice->frameSizeFromFmt()}; - while(!self->mKillNow.load(std::memory_order_acquire) && - device->Connected.load(std::memory_order_acquire)) + while(!mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) { - size_t total, todo; - - auto data = ring->getWriteVector(); - todo = data.first.len + data.second.len; + auto data = mRing->getWriteVector(); + size_t todo{data.first.len + data.second.len}; if(todo == 0) { static char junk[4096]; - sio_read(self->mSndHandle, junk, minz(sizeof(junk)/frameSize, device->UpdateSize)*frameSize); + sio_read(mSndHandle, junk, + minz(sizeof(junk)/frameSize, mDevice->UpdateSize)*frameSize); continue; } - total = 0; + size_t total{0u}; data.first.len *= frameSize; data.second.len *= frameSize; - todo = minz(todo, device->UpdateSize) * frameSize; + todo = minz(todo, mDevice->UpdateSize) * frameSize; while(total < todo) { - size_t got; - if(!data.first.len) data.first = data.second; - got = sio_read(self->mSndHandle, data.first.buf, minz(todo-total, data.first.len)); + size_t got{sio_read(mSndHandle, data.first.buf, minz(todo-total, data.first.len))}; if(!got) { - SndioCapture_lock(self); - aluHandleDisconnect(device, "Failed to read capture samples"); - SndioCapture_unlock(self); + SndioCapture_lock(this); + aluHandleDisconnect(mDevice, "Failed to read capture samples"); + SndioCapture_unlock(this); break; } @@ -360,14 +356,14 @@ static int SndioCapture_recordProc(SndioCapture *self) data.first.len -= got; total += got; } - ring->writeAdvance(total / frameSize); + mRing->writeAdvance(total / frameSize); } return 0; } -static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) +ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) { ALCdevice *device{self->mDevice}; sio_par par; @@ -470,7 +466,7 @@ static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) return ALC_NO_ERROR; } -static ALCboolean SndioCapture_start(SndioCapture *self) +ALCboolean SndioCapture_start(SndioCapture *self) { if(!sio_start(self->mSndHandle)) { @@ -480,7 +476,7 @@ static ALCboolean SndioCapture_start(SndioCapture *self) try { self->mKillNow.store(false, std::memory_order_release); - self->mThread = std::thread(SndioCapture_recordProc, self); + self->mThread = std::thread{std::mem_fn(&SndioCapture::recordProc), self}; return ALC_TRUE; } catch(std::exception& e) { @@ -492,7 +488,7 @@ static ALCboolean SndioCapture_start(SndioCapture *self) return ALC_FALSE; } -static void SndioCapture_stop(SndioCapture *self) +void SndioCapture_stop(SndioCapture *self) { if(self->mKillNow.exchange(true, std::memory_order_acq_rel) || !self->mThread.joinable()) return; @@ -502,14 +498,14 @@ static void SndioCapture_stop(SndioCapture *self) ERR("Error stopping device\n"); } -static ALCenum SndioCapture_captureSamples(SndioCapture *self, void *buffer, ALCuint samples) +ALCenum SndioCapture_captureSamples(SndioCapture *self, void *buffer, ALCuint samples) { RingBuffer *ring{self->mRing.get()}; ring->read(buffer, samples); return ALC_NO_ERROR; } -static ALCuint SndioCapture_availableSamples(SndioCapture *self) +ALCuint SndioCapture_availableSamples(SndioCapture *self) { RingBuffer *ring{self->mRing.get()}; return ring->readSpace(); diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index e56b1c81..7d7e3883 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -49,82 +49,83 @@ namespace { -struct ALCsolarisBackend final : public ALCbackend { - int mFd{-1}; - - al::vector mBuffer; - - std::atomic mKillNow{true}; - std::thread mThread; +constexpr ALCchar solaris_device[] = "Solaris Default"; - ALCsolarisBackend(ALCdevice *device) noexcept : ALCbackend{device} { } -}; +const char *solaris_driver = "/dev/audio"; -static int ALCsolarisBackend_mixerProc(ALCsolarisBackend *self); -static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *device); -static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self); -static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *name); -static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self); -static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self); -static void ALCsolarisBackend_stop(ALCsolarisBackend *self); -static DECLARE_FORWARD2(ALCsolarisBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCsolarisBackend) +struct SolarisBackend final : public ALCbackend { + SolarisBackend(ALCdevice *device) noexcept : ALCbackend{device} { } + ~SolarisBackend() override; -DEFINE_ALCBACKEND_VTABLE(ALCsolarisBackend); + int mixerProc(); + int mFd{-1}; -static const ALCchar solaris_device[] = "Solaris Default"; + al::vector mBuffer; -static const char *solaris_driver = "/dev/audio"; + std::atomic mKillNow{true}; + std::thread mThread; + static constexpr inline const char *CurrentPrefix() noexcept { return "SolarisBackend::"; } +}; -static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *device) +void SolarisBackend_Construct(SolarisBackend *self, ALCdevice *device); +void SolarisBackend_Destruct(SolarisBackend *self); +ALCenum SolarisBackend_open(SolarisBackend *self, const ALCchar *name); +ALCboolean SolarisBackend_reset(SolarisBackend *self); +ALCboolean SolarisBackend_start(SolarisBackend *self); +void SolarisBackend_stop(SolarisBackend *self); +DECLARE_FORWARD2(SolarisBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +DECLARE_FORWARD(SolarisBackend, ALCbackend, ALCuint, availableSamples) +DECLARE_FORWARD(SolarisBackend, ALCbackend, ClockLatency, getClockLatency) +DECLARE_FORWARD(SolarisBackend, ALCbackend, void, lock) +DECLARE_FORWARD(SolarisBackend, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(SolarisBackend) + +DEFINE_ALCBACKEND_VTABLE(SolarisBackend); + +void SolarisBackend_Construct(SolarisBackend *self, ALCdevice *device) { - new (self) ALCsolarisBackend{device}; - SET_VTABLE2(ALCsolarisBackend, ALCbackend, self); + new (self) SolarisBackend{device}; + SET_VTABLE2(SolarisBackend, ALCbackend, self); } -static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self) -{ - if(self->mFd != -1) - close(self->mFd); - self->mFd = -1; +void SolarisBackend_Destruct(SolarisBackend *self) +{ self->~SolarisBackend(); } - self->~ALCsolarisBackend(); +SolarisBackend::~SolarisBackend() +{ + if(mFd != -1) + close(mFd); + mFd = -1; } - -static int ALCsolarisBackend_mixerProc(ALCsolarisBackend *self) +int SolarisBackend::mixerProc() { - ALCdevice *device{self->mDevice}; - SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - const int frame_size{device->frameSizeFromFmt()}; + const int frame_size{mDevice->frameSizeFromFmt()}; - ALCsolarisBackend_lock(self); - while(!self->mKillNow.load(std::memory_order_acquire) && - device->Connected.load(std::memory_order_acquire)) + SolarisBackend_lock(this); + while(!mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) { pollfd pollitem{}; - pollitem.fd = self->mFd; + pollitem.fd = mFd; pollitem.events = POLLOUT; - ALCsolarisBackend_unlock(self); + SolarisBackend_unlock(this); int pret{poll(&pollitem, 1, 1000)}; - ALCsolarisBackend_lock(self); + SolarisBackend_lock(this); if(pret < 0) { if(errno == EINTR || errno == EAGAIN) continue; ERR("poll failed: %s\n", strerror(errno)); - aluHandleDisconnect(device, "Failed to wait for playback buffer: %s", strerror(errno)); + aluHandleDisconnect(mDevice, "Failed to wait for playback buffer: %s", + strerror(errno)); break; } else if(pret == 0) @@ -133,19 +134,19 @@ static int ALCsolarisBackend_mixerProc(ALCsolarisBackend *self) continue; } - ALubyte *write_ptr{self->mBuffer.data()}; - size_t to_write{self->mBuffer.size()}; - aluMixData(device, write_ptr, to_write/frame_size); - while(to_write > 0 && !self->mKillNow.load(std::memory_order_acquire)) + ALubyte *write_ptr{mBuffer.data()}; + size_t to_write{mBuffer.size()}; + aluMixData(mDevice, write_ptr, to_write/frame_size); + while(to_write > 0 && !mKillNow.load(std::memory_order_acquire)) { - ssize_t wrote{write(self->mFd, write_ptr, to_write)}; + ssize_t wrote{write(mFd, write_ptr, to_write)}; if(wrote < 0) { if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) continue; ERR("write failed: %s\n", strerror(errno)); - aluHandleDisconnect(device, "Failed to write playback samples: %s", - strerror(errno)); + aluHandleDisconnect(mDevice, "Failed to write playback samples: %s", + strerror(errno)); break; } @@ -153,16 +154,14 @@ static int ALCsolarisBackend_mixerProc(ALCsolarisBackend *self) write_ptr += wrote; } } - ALCsolarisBackend_unlock(self); + SolarisBackend_unlock(this); return 0; } -static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *name) +ALCenum SolarisBackend_open(SolarisBackend *self, const ALCchar *name) { - ALCdevice *device; - if(!name) name = solaris_device; else if(strcmp(name, solaris_device) != 0) @@ -175,13 +174,13 @@ static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *na return ALC_INVALID_VALUE; } - device = self->mDevice; + ALCdevice *device{self->mDevice}; device->DeviceName = name; return ALC_NO_ERROR; } -static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) +ALCboolean SolarisBackend_reset(SolarisBackend *self) { ALCdevice *device{self->mDevice}; audio_info_t info; @@ -256,11 +255,11 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) return ALC_TRUE; } -static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self) +ALCboolean SolarisBackend_start(SolarisBackend *self) { try { self->mKillNow.store(false, std::memory_order_release); - self->mThread = std::thread(ALCsolarisBackend_mixerProc, self); + self->mThread = std::thread{std::mem_fn(&SolarisBackend::mixerProc), self}; return ALC_TRUE; } catch(std::exception& e) { @@ -271,7 +270,7 @@ static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self) return ALC_FALSE; } -static void ALCsolarisBackend_stop(ALCsolarisBackend *self) +void SolarisBackend_stop(SolarisBackend *self) { if(self->mKillNow.exchange(true, std::memory_order_acq_rel) || !self->mThread.joinable()) return; @@ -322,8 +321,8 @@ ALCbackend *SolarisBackendFactory::createBackend(ALCdevice *device, ALCbackend_T { if(type == ALCbackend_Playback) { - ALCsolarisBackend *backend; - NEW_OBJ(backend, ALCsolarisBackend)(device); + SolarisBackend *backend; + NEW_OBJ(backend, SolarisBackend)(device); return backend; } diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index 11e8a440..a1951c7b 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -78,7 +78,12 @@ void fwrite32le(ALuint val, FILE *f) } -struct ALCwaveBackend final : public ALCbackend { +struct WaveBackend final : public ALCbackend { + WaveBackend(ALCdevice *device) noexcept : ALCbackend{device} { } + ~WaveBackend() override; + + int mixerProc(); + FILE *mFile{nullptr}; long mDataStart{-1}; @@ -87,81 +92,79 @@ struct ALCwaveBackend final : public ALCbackend { std::atomic mKillNow{AL_TRUE}; std::thread mThread; - ALCwaveBackend(ALCdevice *device) noexcept : ALCbackend{device} { } + static constexpr inline const char *CurrentPrefix() noexcept { return "WaveBackend::"; } }; -int ALCwaveBackend_mixerProc(ALCwaveBackend *self); - -void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device); -void ALCwaveBackend_Destruct(ALCwaveBackend *self); -ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name); -ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self); -ALCboolean ALCwaveBackend_start(ALCwaveBackend *self); -void ALCwaveBackend_stop(ALCwaveBackend *self); -DECLARE_FORWARD2(ALCwaveBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, lock) -DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCwaveBackend) - -DEFINE_ALCBACKEND_VTABLE(ALCwaveBackend); - - -void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device) +void WaveBackend_Construct(WaveBackend *self, ALCdevice *device); +void WaveBackend_Destruct(WaveBackend *self); +ALCenum WaveBackend_open(WaveBackend *self, const ALCchar *name); +ALCboolean WaveBackend_reset(WaveBackend *self); +ALCboolean WaveBackend_start(WaveBackend *self); +void WaveBackend_stop(WaveBackend *self); +DECLARE_FORWARD2(WaveBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +DECLARE_FORWARD(WaveBackend, ALCbackend, ALCuint, availableSamples) +DECLARE_FORWARD(WaveBackend, ALCbackend, ClockLatency, getClockLatency) +DECLARE_FORWARD(WaveBackend, ALCbackend, void, lock) +DECLARE_FORWARD(WaveBackend, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(WaveBackend) + +DEFINE_ALCBACKEND_VTABLE(WaveBackend); + +void WaveBackend_Construct(WaveBackend *self, ALCdevice *device) { - new (self) ALCwaveBackend{device}; - SET_VTABLE2(ALCwaveBackend, ALCbackend, self); + new (self) WaveBackend{device}; + SET_VTABLE2(WaveBackend, ALCbackend, self); } -void ALCwaveBackend_Destruct(ALCwaveBackend *self) -{ - if(self->mFile) - fclose(self->mFile); - self->mFile = nullptr; +void WaveBackend_Destruct(WaveBackend *self) +{ self->~WaveBackend(); } - self->~ALCwaveBackend(); +WaveBackend::~WaveBackend() +{ + if(mFile) + fclose(mFile); + mFile = nullptr; } -int ALCwaveBackend_mixerProc(ALCwaveBackend *self) +int WaveBackend::mixerProc() { - ALCdevice *device{self->mDevice}; - const milliseconds restTime{device->UpdateSize*1000/device->Frequency / 2}; + const milliseconds restTime{mDevice->UpdateSize*1000/mDevice->Frequency / 2}; althrd_setname(MIXER_THREAD_NAME); - const ALsizei frameSize{device->frameSizeFromFmt()}; + const ALsizei frameSize{mDevice->frameSizeFromFmt()}; ALint64 done{0}; auto start = std::chrono::steady_clock::now(); - while(!self->mKillNow.load(std::memory_order_acquire) && - device->Connected.load(std::memory_order_acquire)) + while(!mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) { auto now = std::chrono::steady_clock::now(); /* This converts from nanoseconds to nanosamples, then to samples. */ - ALint64 avail{std::chrono::duration_cast((now-start) * device->Frequency).count()}; - if(avail-done < device->UpdateSize) + ALint64 avail{std::chrono::duration_cast((now-start) * + mDevice->Frequency).count()}; + if(avail-done < mDevice->UpdateSize) { std::this_thread::sleep_for(restTime); continue; } - while(avail-done >= device->UpdateSize) + while(avail-done >= mDevice->UpdateSize) { - ALCwaveBackend_lock(self); - aluMixData(device, self->mBuffer.data(), device->UpdateSize); - ALCwaveBackend_unlock(self); - done += device->UpdateSize; + WaveBackend_lock(this); + aluMixData(mDevice, mBuffer.data(), mDevice->UpdateSize); + WaveBackend_unlock(this); + done += mDevice->UpdateSize; if(!IS_LITTLE_ENDIAN) { - const ALsizei bytesize{device->bytesFromFmt()}; + const ALsizei bytesize{mDevice->bytesFromFmt()}; ALsizei i; if(bytesize == 2) { - ALushort *samples = reinterpret_cast(self->mBuffer.data()); - const auto len = static_cast(self->mBuffer.size() / 2); + ALushort *samples = reinterpret_cast(mBuffer.data()); + const auto len = static_cast(mBuffer.size() / 2); for(i = 0;i < len;i++) { ALushort samp = samples[i]; @@ -170,8 +173,8 @@ int ALCwaveBackend_mixerProc(ALCwaveBackend *self) } else if(bytesize == 4) { - ALuint *samples = reinterpret_cast(self->mBuffer.data()); - const auto len = static_cast(self->mBuffer.size() / 4); + ALuint *samples = reinterpret_cast(mBuffer.data()); + const auto len = static_cast(mBuffer.size() / 4); for(i = 0;i < len;i++) { ALuint samp = samples[i]; @@ -181,14 +184,14 @@ int ALCwaveBackend_mixerProc(ALCwaveBackend *self) } } - size_t fs{fwrite(self->mBuffer.data(), frameSize, device->UpdateSize, self->mFile)}; + size_t fs{fwrite(mBuffer.data(), frameSize, mDevice->UpdateSize, mFile)}; (void)fs; - if(ferror(self->mFile)) + if(ferror(mFile)) { ERR("Error writing to file\n"); - ALCwaveBackend_lock(self); - aluHandleDisconnect(device, "Failed to write playback samples"); - ALCwaveBackend_unlock(self); + WaveBackend_lock(this); + aluHandleDisconnect(mDevice, "Failed to write playback samples"); + WaveBackend_unlock(this); break; } } @@ -198,11 +201,11 @@ int ALCwaveBackend_mixerProc(ALCwaveBackend *self) * and current time from growing too large, while maintaining the * correct number of samples to render. */ - if(done >= device->Frequency) + if(done >= mDevice->Frequency) { - seconds s{done/device->Frequency}; + seconds s{done/mDevice->Frequency}; start += s; - done -= device->Frequency*s.count(); + done -= mDevice->Frequency*s.count(); } } @@ -210,7 +213,7 @@ int ALCwaveBackend_mixerProc(ALCwaveBackend *self) } -ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name) +ALCenum WaveBackend_open(WaveBackend *self, const ALCchar *name) { const char *fname{GetConfigValue(nullptr, "wave", "file", "")}; if(!fname[0]) return ALC_INVALID_VALUE; @@ -240,7 +243,7 @@ ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name) return ALC_NO_ERROR; } -ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) +ALCboolean WaveBackend_reset(WaveBackend *self) { ALCdevice *device{self->mDevice}; ALuint channels=0, bits=0, chanmask=0; @@ -344,11 +347,11 @@ ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) return ALC_TRUE; } -ALCboolean ALCwaveBackend_start(ALCwaveBackend *self) +ALCboolean WaveBackend_start(WaveBackend *self) { try { self->mKillNow.store(AL_FALSE, std::memory_order_release); - self->mThread = std::thread(ALCwaveBackend_mixerProc, self); + self->mThread = std::thread{std::mem_fn(&WaveBackend::mixerProc), self}; return ALC_TRUE; } catch(std::exception& e) { @@ -359,7 +362,7 @@ ALCboolean ALCwaveBackend_start(ALCwaveBackend *self) return ALC_FALSE; } -void ALCwaveBackend_stop(ALCwaveBackend *self) +void WaveBackend_stop(WaveBackend *self) { if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->mThread.joinable()) return; @@ -402,8 +405,8 @@ ALCbackend *WaveBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type { if(type == ALCbackend_Playback) { - ALCwaveBackend *backend; - NEW_OBJ(backend, ALCwaveBackend)(device); + WaveBackend *backend; + NEW_OBJ(backend, WaveBackend)(device); return backend; } -- cgit v1.2.3 From 01ed98c99bc66f4df589d73c3ec9e97c9387d4f7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 28 Dec 2018 15:09:51 -0800 Subject: Finish turning ancillary backend methods into member functions --- Alc/backends/wasapi.cpp | 313 ++++++++++++++++++++++++------------------------ Alc/backends/winmm.cpp | 293 ++++++++++++++++++++++---------------------- 2 files changed, 301 insertions(+), 305 deletions(-) diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 1c760b4e..11bc06e4 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -345,9 +345,13 @@ struct WasapiProxy { virtual HRESULT resetProxy() = 0; virtual HRESULT startProxy() = 0; virtual void stopProxy() = 0; + + static DWORD CALLBACK messageHandler(void *ptr); + + static constexpr inline const char *CurrentPrefix() noexcept { return "WasapiProxy::"; } }; -DWORD CALLBACK WasapiProxy_messageHandler(void *ptr) +DWORD WasapiProxy::messageHandler(void *ptr) { auto req = reinterpret_cast(ptr); @@ -490,8 +494,11 @@ DWORD CALLBACK WasapiProxy_messageHandler(void *ptr) } -struct ALCwasapiPlayback final : public ALCbackend, WasapiProxy { - ALCwasapiPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } +struct WasapiPlayback final : public ALCbackend, WasapiProxy { + WasapiPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } + ~WasapiPlayback() override; + + int mixerProc(); HRESULT openProxy() override; void closeProxy() override; @@ -513,96 +520,91 @@ struct ALCwasapiPlayback final : public ALCbackend, WasapiProxy { std::atomic mKillNow{AL_TRUE}; std::thread mThread; -}; - -int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self); - -void ALCwasapiPlayback_Construct(ALCwasapiPlayback *self, ALCdevice *device); -void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self); -ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *name); -ALCboolean ALCwasapiPlayback_reset(ALCwasapiPlayback *self); -ALCboolean ALCwasapiPlayback_start(ALCwasapiPlayback *self); -void ALCwasapiPlayback_stop(ALCwasapiPlayback *self); -DECLARE_FORWARD2(ALCwasapiPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, ALCuint, availableSamples) -ClockLatency ALCwasapiPlayback_getClockLatency(ALCwasapiPlayback *self); -DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, void, lock) -DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCwasapiPlayback) - -DEFINE_ALCBACKEND_VTABLE(ALCwasapiPlayback); + static constexpr inline const char *CurrentPrefix() noexcept { return "WasapiPlayback::"; } +}; -void ALCwasapiPlayback_Construct(ALCwasapiPlayback *self, ALCdevice *device) +void WasapiPlayback_Construct(WasapiPlayback *self, ALCdevice *device); +void WasapiPlayback_Destruct(WasapiPlayback *self); +ALCenum WasapiPlayback_open(WasapiPlayback *self, const ALCchar *name); +ALCboolean WasapiPlayback_reset(WasapiPlayback *self); +ALCboolean WasapiPlayback_start(WasapiPlayback *self); +void WasapiPlayback_stop(WasapiPlayback *self); +DECLARE_FORWARD2(WasapiPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) +DECLARE_FORWARD(WasapiPlayback, ALCbackend, ALCuint, availableSamples) +ClockLatency WasapiPlayback_getClockLatency(WasapiPlayback *self); +DECLARE_FORWARD(WasapiPlayback, ALCbackend, void, lock) +DECLARE_FORWARD(WasapiPlayback, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(WasapiPlayback) + +DEFINE_ALCBACKEND_VTABLE(WasapiPlayback); + +void WasapiPlayback_Construct(WasapiPlayback *self, ALCdevice *device) { - new (self) ALCwasapiPlayback{device}; - SET_VTABLE2(ALCwasapiPlayback, ALCbackend, self); + new (self) WasapiPlayback{device}; + SET_VTABLE2(WasapiPlayback, ALCbackend, self); } -void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self) +void WasapiPlayback_Destruct(WasapiPlayback *self) +{ self->~WasapiPlayback(); } + +WasapiPlayback::~WasapiPlayback() { - if(self->mMsgEvent) + if(mMsgEvent) { - ThreadRequest req = { self->mMsgEvent, 0 }; - auto proxy = static_cast(self); + ThreadRequest req{ mMsgEvent, 0 }; + auto proxy = static_cast(this); if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)proxy)) (void)WaitForResponse(&req); - CloseHandle(self->mMsgEvent); - self->mMsgEvent = nullptr; + CloseHandle(mMsgEvent); + mMsgEvent = nullptr; } - if(self->mNotifyEvent != nullptr) - CloseHandle(self->mNotifyEvent); - self->mNotifyEvent = nullptr; - if(self->mMsgEvent != nullptr) - CloseHandle(self->mMsgEvent); - self->mMsgEvent = nullptr; - - self->~ALCwasapiPlayback(); + if(mNotifyEvent != nullptr) + CloseHandle(mNotifyEvent); + mNotifyEvent = nullptr; + if(mMsgEvent != nullptr) + CloseHandle(mMsgEvent); + mMsgEvent = nullptr; } -FORCE_ALIGN int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self) +FORCE_ALIGN int WasapiPlayback::mixerProc() { - ALCdevice *device{self->mDevice}; - IAudioClient *client{self->mClient}; - IAudioRenderClient *render{self->mRender}; - HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if(FAILED(hr)) { ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); - ALCwasapiPlayback_lock(self); - aluHandleDisconnect(device, "COM init failed: 0x%08lx", hr); - ALCwasapiPlayback_unlock(self); + WasapiPlayback_lock(this); + aluHandleDisconnect(mDevice, "COM init failed: 0x%08lx", hr); + WasapiPlayback_unlock(this); return 1; } SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - ALuint update_size{device->UpdateSize}; - UINT32 buffer_len{update_size * device->NumUpdates}; - while(!self->mKillNow.load(std::memory_order_relaxed)) + const ALuint update_size{mDevice->UpdateSize}; + const UINT32 buffer_len{update_size * mDevice->NumUpdates}; + while(!mKillNow.load(std::memory_order_relaxed)) { UINT32 written; - hr = client->GetCurrentPadding(&written); + hr = mClient->GetCurrentPadding(&written); if(FAILED(hr)) { ERR("Failed to get padding: 0x%08lx\n", hr); - ALCwasapiPlayback_lock(self); - aluHandleDisconnect(device, "Failed to retrieve buffer padding: 0x%08lx", hr); - ALCwasapiPlayback_unlock(self); + WasapiPlayback_lock(this); + aluHandleDisconnect(mDevice, "Failed to retrieve buffer padding: 0x%08lx", hr); + WasapiPlayback_unlock(this); break; } - self->mPadding.store(written, std::memory_order_relaxed); + mPadding.store(written, std::memory_order_relaxed); ALuint len{buffer_len - written}; if(len < update_size) { - DWORD res; - res = WaitForSingleObjectEx(self->mNotifyEvent, 2000, FALSE); + DWORD res{WaitForSingleObjectEx(mNotifyEvent, 2000, FALSE)}; if(res != WAIT_OBJECT_0) ERR("WaitForSingleObjectEx error: 0x%lx\n", res); continue; @@ -610,25 +612,25 @@ FORCE_ALIGN int ALCwasapiPlayback_mixerProc(ALCwasapiPlayback *self) len -= len%update_size; BYTE *buffer; - hr = render->GetBuffer(len, &buffer); + hr = mRender->GetBuffer(len, &buffer); if(SUCCEEDED(hr)) { - ALCwasapiPlayback_lock(self); - aluMixData(device, buffer, len); - self->mPadding.store(written + len, std::memory_order_relaxed); - ALCwasapiPlayback_unlock(self); - hr = render->ReleaseBuffer(len, 0); + WasapiPlayback_lock(this); + aluMixData(mDevice, buffer, len); + mPadding.store(written + len, std::memory_order_relaxed); + WasapiPlayback_unlock(this); + hr = mRender->ReleaseBuffer(len, 0); } if(FAILED(hr)) { ERR("Failed to buffer data: 0x%08lx\n", hr); - ALCwasapiPlayback_lock(self); - aluHandleDisconnect(device, "Failed to send playback samples: 0x%08lx", hr); - ALCwasapiPlayback_unlock(self); + WasapiPlayback_lock(this); + aluHandleDisconnect(mDevice, "Failed to send playback samples: 0x%08lx", hr); + WasapiPlayback_unlock(this); break; } } - self->mPadding.store(0u, std::memory_order_release); + mPadding.store(0u, std::memory_order_release); CoUninitialize(); return 0; @@ -674,7 +676,7 @@ ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) return ALC_TRUE; } -ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *deviceName) +ALCenum WasapiPlayback_open(WasapiPlayback *self, const ALCchar *deviceName) { HRESULT hr = S_OK; @@ -752,7 +754,7 @@ ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *deviceNam return ALC_NO_ERROR; } -HRESULT ALCwasapiPlayback::openProxy() +HRESULT WasapiPlayback::openProxy() { void *ptr; HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, &ptr); @@ -784,7 +786,7 @@ HRESULT ALCwasapiPlayback::openProxy() return hr; } -void ALCwasapiPlayback::closeProxy() +void WasapiPlayback::closeProxy() { if(mClient) mClient->Release(); @@ -796,7 +798,7 @@ void ALCwasapiPlayback::closeProxy() } -ALCboolean ALCwasapiPlayback_reset(ALCwasapiPlayback *self) +ALCboolean WasapiPlayback_reset(WasapiPlayback *self) { ThreadRequest req{ self->mMsgEvent, 0 }; HRESULT hr{E_FAIL}; @@ -808,7 +810,7 @@ ALCboolean ALCwasapiPlayback_reset(ALCwasapiPlayback *self) return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; } -HRESULT ALCwasapiPlayback::resetProxy() +HRESULT WasapiPlayback::resetProxy() { if(mClient) mClient->Release(); @@ -1064,7 +1066,7 @@ HRESULT ALCwasapiPlayback::resetProxy() } -ALCboolean ALCwasapiPlayback_start(ALCwasapiPlayback *self) +ALCboolean WasapiPlayback_start(WasapiPlayback *self) { ThreadRequest req{ self->mMsgEvent, 0 }; HRESULT hr{E_FAIL}; @@ -1076,7 +1078,7 @@ ALCboolean ALCwasapiPlayback_start(ALCwasapiPlayback *self) return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; } -HRESULT ALCwasapiPlayback::startProxy() +HRESULT WasapiPlayback::startProxy() { ResetEvent(mNotifyEvent); @@ -1094,7 +1096,7 @@ HRESULT ALCwasapiPlayback::startProxy() mRender = reinterpret_cast(ptr); try { mKillNow.store(AL_FALSE, std::memory_order_release); - mThread = std::thread(ALCwasapiPlayback_mixerProc, this); + mThread = std::thread{std::mem_fn(&WasapiPlayback::mixerProc), this}; } catch(...) { mRender->Release(); @@ -1111,7 +1113,7 @@ HRESULT ALCwasapiPlayback::startProxy() } -void ALCwasapiPlayback_stop(ALCwasapiPlayback *self) +void WasapiPlayback_stop(WasapiPlayback *self) { ThreadRequest req{ self->mMsgEvent, 0 }; auto proxy = static_cast(self); @@ -1119,7 +1121,7 @@ void ALCwasapiPlayback_stop(ALCwasapiPlayback *self) (void)WaitForResponse(&req); } -void ALCwasapiPlayback::stopProxy() +void WasapiPlayback::stopProxy() { if(!mRender || !mThread.joinable()) return; @@ -1133,23 +1135,26 @@ void ALCwasapiPlayback::stopProxy() } -ClockLatency ALCwasapiPlayback_getClockLatency(ALCwasapiPlayback *self) +ClockLatency WasapiPlayback_getClockLatency(WasapiPlayback *self) { ClockLatency ret; - ALCwasapiPlayback_lock(self); + WasapiPlayback_lock(self); ALCdevice *device{self->mDevice}; ret.ClockTime = GetDeviceClockTime(device); ret.Latency = std::chrono::seconds{self->mPadding.load(std::memory_order_relaxed)}; ret.Latency /= device->Frequency; - ALCwasapiPlayback_unlock(self); + WasapiPlayback_unlock(self); return ret; } -struct ALCwasapiCapture final : public ALCbackend, WasapiProxy { - ALCwasapiCapture(ALCdevice *device) noexcept : ALCbackend{device} { } +struct WasapiCapture final : public ALCbackend, WasapiProxy { + WasapiCapture(ALCdevice *device) noexcept : ALCbackend{device} { } + ~WasapiCapture() override; + + int recordProc(); HRESULT openProxy() override; void closeProxy() override; @@ -1173,78 +1178,73 @@ struct ALCwasapiCapture final : public ALCbackend, WasapiProxy { std::atomic mKillNow{AL_TRUE}; std::thread mThread; -}; -int ALCwasapiCapture_recordProc(ALCwasapiCapture *self); + static constexpr inline const char *CurrentPrefix() noexcept { return "WasapiCapture::"; } +}; -void ALCwasapiCapture_Construct(ALCwasapiCapture *self, ALCdevice *device); -void ALCwasapiCapture_Destruct(ALCwasapiCapture *self); -ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *name); -DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, ALCboolean, reset) -ALCboolean ALCwasapiCapture_start(ALCwasapiCapture *self); -void ALCwasapiCapture_stop(ALCwasapiCapture *self); -ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, ALCuint samples); -ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self); -DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, void, lock) -DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCwasapiCapture) +void WasapiCapture_Construct(WasapiCapture *self, ALCdevice *device); +void WasapiCapture_Destruct(WasapiCapture *self); +ALCenum WasapiCapture_open(WasapiCapture *self, const ALCchar *name); +DECLARE_FORWARD(WasapiCapture, ALCbackend, ALCboolean, reset) +ALCboolean WasapiCapture_start(WasapiCapture *self); +void WasapiCapture_stop(WasapiCapture *self); +ALCenum WasapiCapture_captureSamples(WasapiCapture *self, ALCvoid *buffer, ALCuint samples); +ALuint WasapiCapture_availableSamples(WasapiCapture *self); +DECLARE_FORWARD(WasapiCapture, ALCbackend, ClockLatency, getClockLatency) +DECLARE_FORWARD(WasapiCapture, ALCbackend, void, lock) +DECLARE_FORWARD(WasapiCapture, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(WasapiCapture) -DEFINE_ALCBACKEND_VTABLE(ALCwasapiCapture); +DEFINE_ALCBACKEND_VTABLE(WasapiCapture); -void ALCwasapiCapture_Construct(ALCwasapiCapture *self, ALCdevice *device) +void WasapiCapture_Construct(WasapiCapture *self, ALCdevice *device) { - new (self) ALCwasapiCapture{device}; - SET_VTABLE2(ALCwasapiCapture, ALCbackend, self); + new (self) WasapiCapture{device}; + SET_VTABLE2(WasapiCapture, ALCbackend, self); } -void ALCwasapiCapture_Destruct(ALCwasapiCapture *self) +void WasapiCapture_Destruct(WasapiCapture *self) +{ self->~WasapiCapture(); } + +WasapiCapture::~WasapiCapture() { - if(self->mMsgEvent) + if(mMsgEvent) { - ThreadRequest req{ self->mMsgEvent, 0 }; - auto proxy = static_cast(self); + ThreadRequest req{ mMsgEvent, 0 }; + auto proxy = static_cast(this); if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)proxy)) (void)WaitForResponse(&req); - CloseHandle(self->mMsgEvent); - self->mMsgEvent = nullptr; + CloseHandle(mMsgEvent); + mMsgEvent = nullptr; } - if(self->mNotifyEvent != nullptr) - CloseHandle(self->mNotifyEvent); - self->mNotifyEvent = nullptr; - - self->~ALCwasapiCapture(); + if(mNotifyEvent != nullptr) + CloseHandle(mNotifyEvent); + mNotifyEvent = nullptr; } -FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) +FORCE_ALIGN int WasapiCapture::recordProc() { - ALCdevice *device{self->mDevice}; - RingBuffer *ring{self->mRing.get()}; - IAudioCaptureClient *capture{self->mCapture}; - HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if(FAILED(hr)) { ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); - ALCwasapiCapture_lock(self); - aluHandleDisconnect(device, "COM init failed: 0x%08lx", hr); - ALCwasapiCapture_unlock(self); + WasapiCapture_lock(this); + aluHandleDisconnect(mDevice, "COM init failed: 0x%08lx", hr); + WasapiCapture_unlock(this); return 1; } althrd_setname(RECORD_THREAD_NAME); al::vector samples; - while(!self->mKillNow.load(std::memory_order_relaxed)) + while(!mKillNow.load(std::memory_order_relaxed)) { UINT32 avail; - DWORD res; - - hr = capture->GetNextPacketSize(&avail); + hr = mCapture->GetNextPacketSize(&avail); if(FAILED(hr)) ERR("Failed to get next packet size: 0x%08lx\n", hr); else if(avail > 0) @@ -1253,41 +1253,41 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) DWORD flags; BYTE *rdata; - hr = capture->GetBuffer(&rdata, &numsamples, &flags, nullptr, nullptr); + hr = mCapture->GetBuffer(&rdata, &numsamples, &flags, nullptr, nullptr); if(FAILED(hr)) ERR("Failed to get capture buffer: 0x%08lx\n", hr); else { - if(ChannelConverter *conv{self->mChannelConv.get()}) + if(mChannelConv) { samples.resize(numsamples*2); - ChannelConverterInput(conv, rdata, samples.data(), numsamples); + ChannelConverterInput(mChannelConv.get(), rdata, samples.data(), numsamples); rdata = reinterpret_cast(samples.data()); } - auto data = ring->getWriteVector(); + auto data = mRing->getWriteVector(); size_t dstframes; - if(SampleConverter *conv{self->mSampleConv.get()}) + if(mSampleConv) { - const ALvoid *srcdata = rdata; - ALsizei srcframes = numsamples; + const ALvoid *srcdata{rdata}; + auto srcframes = static_cast(numsamples); - dstframes = SampleConverterInput(conv, &srcdata, &srcframes, data.first.buf, - (ALsizei)minz(data.first.len, INT_MAX)); + dstframes = SampleConverterInput(mSampleConv.get(), &srcdata, &srcframes, + data.first.buf, (ALsizei)minz(data.first.len, INT_MAX)); if(srcframes > 0 && dstframes == data.first.len && data.second.len > 0) { /* If some source samples remain, all of the first dest * block was filled, and there's space in the second * dest block, do another run for the second block. */ - dstframes += SampleConverterInput(conv, &srcdata, &srcframes, + dstframes += SampleConverterInput(mSampleConv.get(), &srcdata, &srcframes, data.second.buf, (ALsizei)minz(data.second.len, INT_MAX)); } } else { - const auto framesize = static_cast(device->frameSizeFromFmt()); + const auto framesize = static_cast(mDevice->frameSizeFromFmt()); size_t len1 = minz(data.first.len, numsamples); size_t len2 = minz(data.second.len, numsamples-len1); @@ -1297,22 +1297,22 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) dstframes = len1 + len2; } - ring->writeAdvance(dstframes); + mRing->writeAdvance(dstframes); - hr = capture->ReleaseBuffer(numsamples); + hr = mCapture->ReleaseBuffer(numsamples); if(FAILED(hr)) ERR("Failed to release capture buffer: 0x%08lx\n", hr); } } if(FAILED(hr)) { - ALCwasapiCapture_lock(self); - aluHandleDisconnect(device, "Failed to capture samples: 0x%08lx", hr); - ALCwasapiCapture_unlock(self); + WasapiCapture_lock(this); + aluHandleDisconnect(mDevice, "Failed to capture samples: 0x%08lx", hr); + WasapiCapture_unlock(this); break; } - res = WaitForSingleObjectEx(self->mNotifyEvent, 2000, FALSE); + DWORD res{WaitForSingleObjectEx(mNotifyEvent, 2000, FALSE)}; if(res != WAIT_OBJECT_0) ERR("WaitForSingleObjectEx error: 0x%lx\n", res); } @@ -1322,7 +1322,7 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(ALCwasapiCapture *self) } -ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *deviceName) +ALCenum WasapiCapture_open(WasapiCapture *self, const ALCchar *deviceName) { HRESULT hr{S_OK}; @@ -1418,7 +1418,7 @@ ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *deviceName) return ALC_NO_ERROR; } -HRESULT ALCwasapiCapture::openProxy() +HRESULT WasapiCapture::openProxy() { void *ptr; HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, @@ -1451,7 +1451,7 @@ HRESULT ALCwasapiCapture::openProxy() return hr; } -void ALCwasapiCapture::closeProxy() +void WasapiCapture::closeProxy() { if(mClient) mClient->Release(); @@ -1462,7 +1462,7 @@ void ALCwasapiCapture::closeProxy() mMMDev = nullptr; } -HRESULT ALCwasapiCapture::resetProxy() +HRESULT WasapiCapture::resetProxy() { if(mClient) mClient->Release(); @@ -1694,7 +1694,7 @@ HRESULT ALCwasapiCapture::resetProxy() } -ALCboolean ALCwasapiCapture_start(ALCwasapiCapture *self) +ALCboolean WasapiCapture_start(WasapiCapture *self) { ThreadRequest req{ self->mMsgEvent, 0 }; HRESULT hr{E_FAIL}; @@ -1706,7 +1706,7 @@ ALCboolean ALCwasapiCapture_start(ALCwasapiCapture *self) return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; } -HRESULT ALCwasapiCapture::startProxy() +HRESULT WasapiCapture::startProxy() { ResetEvent(mNotifyEvent); @@ -1724,7 +1724,7 @@ HRESULT ALCwasapiCapture::startProxy() mCapture = reinterpret_cast(ptr); try { mKillNow.store(AL_FALSE, std::memory_order_release); - mThread = std::thread(ALCwasapiCapture_recordProc, this); + mThread = std::thread{std::mem_fn(&WasapiCapture::recordProc), this}; } catch(...) { mCapture->Release(); @@ -1744,7 +1744,7 @@ HRESULT ALCwasapiCapture::startProxy() } -void ALCwasapiCapture_stop(ALCwasapiCapture *self) +void WasapiCapture_stop(WasapiCapture *self) { ThreadRequest req{ self->mMsgEvent, 0 }; auto proxy = static_cast(self); @@ -1752,7 +1752,7 @@ void ALCwasapiCapture_stop(ALCwasapiCapture *self) (void)WaitForResponse(&req); } -void ALCwasapiCapture::stopProxy() +void WasapiCapture::stopProxy() { if(!mCapture || !mThread.joinable()) return; @@ -1767,13 +1767,13 @@ void ALCwasapiCapture::stopProxy() } -ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self) +ALuint WasapiCapture_availableSamples(WasapiCapture *self) { RingBuffer *ring{self->mRing.get()}; return (ALuint)ring->readSpace(); } -ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum WasapiCapture_captureSamples(WasapiCapture *self, ALCvoid *buffer, ALCuint samples) { RingBuffer *ring{self->mRing.get()}; ring->read(buffer, samples); @@ -1797,9 +1797,8 @@ bool WasapiBackendFactory::init() ERR("Failed to create event: %lu\n", GetLastError()); else { - ThreadHdl = CreateThread(nullptr, 0, WasapiProxy_messageHandler, &req, 0, &ThreadID); - if(ThreadHdl != nullptr) - InitResult = WaitForResponse(&req); + ThreadHdl = CreateThread(nullptr, 0, &WasapiProxy::messageHandler, &req, 0, &ThreadID); + if(ThreadHdl != nullptr) InitResult = WaitForResponse(&req); CloseHandle(req.FinishedEvt); } } @@ -1862,14 +1861,14 @@ ALCbackend *WasapiBackendFactory::createBackend(ALCdevice *device, ALCbackend_Ty { if(type == ALCbackend_Playback) { - ALCwasapiPlayback *backend; - NEW_OBJ(backend, ALCwasapiPlayback)(device); + WasapiPlayback *backend; + NEW_OBJ(backend, WasapiPlayback)(device); return backend; } if(type == ALCbackend_Capture) { - ALCwasapiCapture *backend; - NEW_OBJ(backend, ALCwasapiCapture)(device); + WasapiCapture *backend; + NEW_OBJ(backend, WasapiCapture)(device); return backend; } diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 1258b6a2..09b7a2e2 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -120,11 +120,19 @@ void ProbeCaptureDevices(void) } -struct ALCwinmmPlayback final : public ALCbackend { +struct WinMMPlayback final : public ALCbackend { + WinMMPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } + ~WinMMPlayback() override; + + static void CALLBACK waveOutProcC(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); + void CALLBACK waveOutProc(HWAVEOUT device, UINT msg, DWORD_PTR param1, DWORD_PTR param2); + + int mixerProc(); + std::atomic mWritable{0u}; al::semaphore mSem; int mIdx{0}; - std::array mWaveBuffer; + std::array mWaveBuffer{}; HWAVEOUT mOutHdl{nullptr}; @@ -133,105 +141,96 @@ struct ALCwinmmPlayback final : public ALCbackend { std::atomic mKillNow{AL_TRUE}; std::thread mThread; - ALCwinmmPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } + static constexpr inline const char *CurrentPrefix() noexcept { return "WinMMPlayback::"; } }; -void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device); -void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self); - -void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); -int ALCwinmmPlayback_mixerProc(ALCwinmmPlayback *self); - -ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *name); -ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self); -ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self); -void ALCwinmmPlayback_stop(ALCwinmmPlayback *self); -DECLARE_FORWARD2(ALCwinmmPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, lock) -DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCwinmmPlayback) - -DEFINE_ALCBACKEND_VTABLE(ALCwinmmPlayback); - - -void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device) +void WinMMPlayback_Construct(WinMMPlayback *self, ALCdevice *device); +void WinMMPlayback_Destruct(WinMMPlayback *self); +ALCenum WinMMPlayback_open(WinMMPlayback *self, const ALCchar *name); +ALCboolean WinMMPlayback_reset(WinMMPlayback *self); +ALCboolean WinMMPlayback_start(WinMMPlayback *self); +void WinMMPlayback_stop(WinMMPlayback *self); +DECLARE_FORWARD2(WinMMPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) +DECLARE_FORWARD(WinMMPlayback, ALCbackend, ALCuint, availableSamples) +DECLARE_FORWARD(WinMMPlayback, ALCbackend, ClockLatency, getClockLatency) +DECLARE_FORWARD(WinMMPlayback, ALCbackend, void, lock) +DECLARE_FORWARD(WinMMPlayback, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(WinMMPlayback) + +DEFINE_ALCBACKEND_VTABLE(WinMMPlayback); + +void WinMMPlayback_Construct(WinMMPlayback *self, ALCdevice *device) { - new (self) ALCwinmmPlayback{device}; - SET_VTABLE2(ALCwinmmPlayback, ALCbackend, self); - - std::fill(self->mWaveBuffer.begin(), self->mWaveBuffer.end(), WAVEHDR{}); + new (self) WinMMPlayback{device}; + SET_VTABLE2(WinMMPlayback, ALCbackend, self); } -void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self) -{ - if(self->mOutHdl) - waveOutClose(self->mOutHdl); - self->mOutHdl = nullptr; +void WinMMPlayback_Destruct(WinMMPlayback *self) +{ self->~WinMMPlayback(); } - al_free(self->mWaveBuffer[0].lpData); - std::fill(self->mWaveBuffer.begin(), self->mWaveBuffer.end(), WAVEHDR{}); +WinMMPlayback::~WinMMPlayback() +{ + if(mOutHdl) + waveOutClose(mOutHdl); + mOutHdl = nullptr; - self->~ALCwinmmPlayback(); + al_free(mWaveBuffer[0].lpData); + std::fill(mWaveBuffer.begin(), mWaveBuffer.end(), WAVEHDR{}); } -/* ALCwinmmPlayback_waveOutProc +void CALLBACK WinMMPlayback::waveOutProcC(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2) +{ reinterpret_cast(instance)->waveOutProc(device, msg, param1, param2); } + +/* WinMMPlayback::waveOutProc * - * Posts a message to 'ALCwinmmPlayback_mixerProc' everytime a WaveOut Buffer - * is completed and returns to the application (for more data) + * Posts a message to 'WinMMPlayback::mixerProc' everytime a WaveOut Buffer is + * completed and returns to the application (for more data) */ -void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT UNUSED(device), UINT msg, - DWORD_PTR instance, DWORD_PTR UNUSED(param1), - DWORD_PTR UNUSED(param2)) +void CALLBACK WinMMPlayback::waveOutProc(HWAVEOUT UNUSED(device), UINT msg, + DWORD_PTR UNUSED(param1), DWORD_PTR UNUSED(param2)) { - if(msg != WOM_DONE) - return; - - auto self = reinterpret_cast(instance); - self->mWritable.fetch_add(1, std::memory_order_acq_rel); - self->mSem.post(); + if(msg != WOM_DONE) return; + mWritable.fetch_add(1, std::memory_order_acq_rel); + mSem.post(); } -FORCE_ALIGN int ALCwinmmPlayback_mixerProc(ALCwinmmPlayback *self) +FORCE_ALIGN int WinMMPlayback::mixerProc() { - ALCdevice *device{self->mDevice}; - SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - ALCwinmmPlayback_lock(self); - while(!self->mKillNow.load(std::memory_order_acquire) && - device->Connected.load(std::memory_order_acquire)) + WinMMPlayback_lock(this); + while(!mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) { - ALsizei todo = self->mWritable.load(std::memory_order_acquire); + ALsizei todo = mWritable.load(std::memory_order_acquire); if(todo < 1) { - ALCwinmmPlayback_unlock(self); - self->mSem.wait(); - ALCwinmmPlayback_lock(self); + WinMMPlayback_unlock(this); + mSem.wait(); + WinMMPlayback_lock(this); continue; } - int widx{self->mIdx}; + int widx{mIdx}; do { - WAVEHDR &waveHdr = self->mWaveBuffer[widx]; - widx = (widx+1) % self->mWaveBuffer.size(); + WAVEHDR &waveHdr = mWaveBuffer[widx]; + widx = (widx+1) % mWaveBuffer.size(); - aluMixData(device, waveHdr.lpData, device->UpdateSize); - self->mWritable.fetch_sub(1, std::memory_order_acq_rel); - waveOutWrite(self->mOutHdl, &waveHdr, sizeof(WAVEHDR)); + aluMixData(mDevice, waveHdr.lpData, mDevice->UpdateSize); + mWritable.fetch_sub(1, std::memory_order_acq_rel); + waveOutWrite(mOutHdl, &waveHdr, sizeof(WAVEHDR)); } while(--todo); - self->mIdx = widx; + mIdx = widx; } - ALCwinmmPlayback_unlock(self); + WinMMPlayback_unlock(this); return 0; } -ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *deviceName) +ALCenum WinMMPlayback_open(WinMMPlayback *self, const ALCchar *deviceName) { ALCdevice *device{self->mDevice}; @@ -269,8 +268,7 @@ retry_open: self->mFormat.cbSize = 0; MMRESULT res{waveOutOpen(&self->mOutHdl, DeviceID, &self->mFormat, - (DWORD_PTR)&ALCwinmmPlayback_waveOutProc, (DWORD_PTR)self, CALLBACK_FUNCTION - )}; + (DWORD_PTR)&WinMMPlayback::waveOutProcC, (DWORD_PTR)self, CALLBACK_FUNCTION)}; if(res != MMSYSERR_NOERROR) { if(device->FmtType == DevFmtFloat) @@ -286,7 +284,7 @@ retry_open: return ALC_NO_ERROR; } -ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self) +ALCboolean WinMMPlayback_reset(WinMMPlayback *self) { ALCdevice *device{self->mDevice}; @@ -354,7 +352,7 @@ ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self) return ALC_TRUE; } -ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self) +ALCboolean WinMMPlayback_start(WinMMPlayback *self) { try { std::for_each(self->mWaveBuffer.begin(), self->mWaveBuffer.end(), @@ -365,7 +363,7 @@ ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self) std::memory_order_release); self->mKillNow.store(AL_FALSE, std::memory_order_release); - self->mThread = std::thread(ALCwinmmPlayback_mixerProc, self); + self->mThread = std::thread{std::mem_fn(&WinMMPlayback::mixerProc), self}; return ALC_TRUE; } catch(std::exception& e) { @@ -376,7 +374,7 @@ ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self) return ALC_FALSE; } -void ALCwinmmPlayback_stop(ALCwinmmPlayback *self) +void WinMMPlayback_stop(WinMMPlayback *self) { if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->mThread.joinable()) return; @@ -392,7 +390,15 @@ void ALCwinmmPlayback_stop(ALCwinmmPlayback *self) } -struct ALCwinmmCapture final : public ALCbackend { +struct WinMMCapture final : public ALCbackend { + WinMMCapture(ALCdevice *device) noexcept : ALCbackend{device} { } + ~WinMMCapture() override; + + static void CALLBACK waveInProcC(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); + void CALLBACK waveInProc(HWAVEIN device, UINT msg, DWORD_PTR param1, DWORD_PTR param2); + + int captureProc(); + std::atomic mReadable{0u}; al::semaphore mSem; int mIdx{0}; @@ -407,104 +413,95 @@ struct ALCwinmmCapture final : public ALCbackend { std::atomic mKillNow{AL_TRUE}; std::thread mThread; - ALCwinmmCapture(ALCdevice *device) noexcept : ALCbackend{device} { } + static constexpr inline const char *CurrentPrefix() noexcept { return "WinMMCapture::"; } }; -void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device); -void ALCwinmmCapture_Destruct(ALCwinmmCapture *self); - -void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); -int ALCwinmmCapture_captureProc(ALCwinmmCapture *self); - -ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName); -DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ALCboolean, reset) -ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self); -void ALCwinmmCapture_stop(ALCwinmmCapture *self); -ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples); -ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self); -DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, lock) -DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCwinmmCapture) - -DEFINE_ALCBACKEND_VTABLE(ALCwinmmCapture); - - -void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device) +void WinMMCapture_Construct(WinMMCapture *self, ALCdevice *device); +void WinMMCapture_Destruct(WinMMCapture *self); +ALCenum WinMMCapture_open(WinMMCapture *self, const ALCchar *deviceName); +DECLARE_FORWARD(WinMMCapture, ALCbackend, ALCboolean, reset) +ALCboolean WinMMCapture_start(WinMMCapture *self); +void WinMMCapture_stop(WinMMCapture *self); +ALCenum WinMMCapture_captureSamples(WinMMCapture *self, ALCvoid *buffer, ALCuint samples); +ALCuint WinMMCapture_availableSamples(WinMMCapture *self); +DECLARE_FORWARD(WinMMCapture, ALCbackend, ClockLatency, getClockLatency) +DECLARE_FORWARD(WinMMCapture, ALCbackend, void, lock) +DECLARE_FORWARD(WinMMCapture, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(WinMMCapture) + +DEFINE_ALCBACKEND_VTABLE(WinMMCapture); + +void WinMMCapture_Construct(WinMMCapture *self, ALCdevice *device) { - new (self) ALCwinmmCapture{device}; - SET_VTABLE2(ALCwinmmCapture, ALCbackend, self); + new (self) WinMMCapture{device}; + SET_VTABLE2(WinMMCapture, ALCbackend, self); } -void ALCwinmmCapture_Destruct(ALCwinmmCapture *self) +void WinMMCapture_Destruct(WinMMCapture *self) +{ self->~WinMMCapture(); } + +WinMMCapture::~WinMMCapture() { // Close the Wave device - if(self->mInHdl) - waveInClose(self->mInHdl); - self->mInHdl = nullptr; - - al_free(self->mWaveBuffer[0].lpData); - std::fill(self->mWaveBuffer.begin(), self->mWaveBuffer.end(), WAVEHDR{}); + if(mInHdl) + waveInClose(mInHdl); + mInHdl = nullptr; - self->~ALCwinmmCapture(); + al_free(mWaveBuffer[0].lpData); + std::fill(mWaveBuffer.begin(), mWaveBuffer.end(), WAVEHDR{}); } +void CALLBACK WinMMCapture::waveInProcC(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2) +{ reinterpret_cast(instance)->waveInProc(device, msg, param1, param2); } -/* ALCwinmmCapture_waveInProc +/* WinMMCapture::waveInProc * - * Posts a message to 'ALCwinmmCapture_captureProc' everytime a WaveIn Buffer - * is completed and returns to the application (with more data). + * Posts a message to 'WinMMCapture::captureProc' everytime a WaveIn Buffer is + * completed and returns to the application (with more data). */ -void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN UNUSED(device), UINT msg, - DWORD_PTR instance, DWORD_PTR UNUSED(param1), - DWORD_PTR UNUSED(param2)) +void CALLBACK WinMMCapture::waveInProc(HWAVEIN UNUSED(device), UINT msg, + DWORD_PTR UNUSED(param1), DWORD_PTR UNUSED(param2)) { - if(msg != WIM_DATA) - return; - - auto self = reinterpret_cast(instance); - self->mReadable.fetch_add(1, std::memory_order_acq_rel); - self->mSem.post(); + if(msg != WIM_DATA) return; + mReadable.fetch_add(1, std::memory_order_acq_rel); + mSem.post(); } -int ALCwinmmCapture_captureProc(ALCwinmmCapture *self) +int WinMMCapture::captureProc() { - ALCdevice *device{self->mDevice}; - RingBuffer *ring{self->mRing.get()}; - althrd_setname(RECORD_THREAD_NAME); - ALCwinmmCapture_lock(self); - while(!self->mKillNow.load(std::memory_order_acquire) && - device->Connected.load(std::memory_order_acquire)) + WinMMCapture_lock(this); + while(!mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) { - ALuint todo{self->mReadable.load(std::memory_order_acquire)}; + ALuint todo{mReadable.load(std::memory_order_acquire)}; if(todo < 1) { - ALCwinmmCapture_unlock(self); - self->mSem.wait(); - ALCwinmmCapture_lock(self); + WinMMCapture_unlock(this); + mSem.wait(); + WinMMCapture_lock(this); continue; } - int widx{self->mIdx}; + int widx{mIdx}; do { - WAVEHDR &waveHdr = self->mWaveBuffer[widx]; - widx = (widx+1) % self->mWaveBuffer.size(); + WAVEHDR &waveHdr = mWaveBuffer[widx]; + widx = (widx+1) % mWaveBuffer.size(); - ring->write(waveHdr.lpData, waveHdr.dwBytesRecorded / self->mFormat.nBlockAlign); - self->mReadable.fetch_sub(1, std::memory_order_acq_rel); - waveInAddBuffer(self->mInHdl, &waveHdr, sizeof(WAVEHDR)); + mRing->write(waveHdr.lpData, waveHdr.dwBytesRecorded / mFormat.nBlockAlign); + mReadable.fetch_sub(1, std::memory_order_acq_rel); + waveInAddBuffer(mInHdl, &waveHdr, sizeof(WAVEHDR)); } while(--todo); - self->mIdx = widx; + mIdx = widx; } - ALCwinmmCapture_unlock(self); + WinMMCapture_unlock(this); return 0; } -ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName) +ALCenum WinMMCapture_open(WinMMCapture *self, const ALCchar *deviceName) { ALCdevice *device{self->mDevice}; @@ -560,7 +557,7 @@ ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName) self->mFormat.cbSize = 0; MMRESULT res{waveInOpen(&self->mInHdl, DeviceID, &self->mFormat, - (DWORD_PTR)&ALCwinmmCapture_waveInProc, (DWORD_PTR)self, CALLBACK_FUNCTION + (DWORD_PTR)&WinMMCapture::waveInProcC, (DWORD_PTR)self, CALLBACK_FUNCTION )}; if(res != MMSYSERR_NOERROR) { @@ -597,7 +594,7 @@ ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *deviceName) return ALC_NO_ERROR; } -ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self) +ALCboolean WinMMCapture_start(WinMMCapture *self) { try { for(size_t i{0};i < self->mWaveBuffer.size();++i) @@ -607,7 +604,7 @@ ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self) } self->mKillNow.store(AL_FALSE, std::memory_order_release); - self->mThread = std::thread(ALCwinmmCapture_captureProc, self); + self->mThread = std::thread{std::mem_fn(&WinMMCapture::captureProc), self}; waveInStart(self->mInHdl); return ALC_TRUE; @@ -620,7 +617,7 @@ ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self) return ALC_FALSE; } -void ALCwinmmCapture_stop(ALCwinmmCapture *self) +void WinMMCapture_stop(WinMMCapture *self) { waveInStop(self->mInHdl); @@ -639,14 +636,14 @@ void ALCwinmmCapture_stop(ALCwinmmCapture *self) self->mIdx = 0; } -ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum WinMMCapture_captureSamples(WinMMCapture *self, ALCvoid *buffer, ALCuint samples) { RingBuffer *ring{self->mRing.get()}; ring->read(buffer, samples); return ALC_NO_ERROR; } -ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self) +ALCuint WinMMCapture_availableSamples(WinMMCapture *self) { RingBuffer *ring{self->mRing.get()}; return (ALCuint)ring->readSpace(); @@ -695,14 +692,14 @@ ALCbackend *WinMMBackendFactory::createBackend(ALCdevice *device, ALCbackend_Typ { if(type == ALCbackend_Playback) { - ALCwinmmPlayback *backend; - NEW_OBJ(backend, ALCwinmmPlayback)(device); + WinMMPlayback *backend; + NEW_OBJ(backend, WinMMPlayback)(device); return backend; } if(type == ALCbackend_Capture) { - ALCwinmmCapture *backend; - NEW_OBJ(backend, ALCwinmmCapture)(device); + WinMMCapture *backend; + NEW_OBJ(backend, WinMMCapture)(device); return backend; } -- cgit v1.2.3 From 67b874328d60062558eeb5068a3f79dab2b6f7e3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 28 Dec 2018 16:13:28 -0800 Subject: Use static_cast instead of reinterpret_cast where possible --- Alc/backends/dsound.cpp | 2 +- Alc/backends/pulseaudio.cpp | 6 +++--- Alc/backends/wasapi.cpp | 32 ++++++++++++++++---------------- common/almalloc.h | 2 +- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 83cc712f..832068ad 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -158,7 +158,7 @@ BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR* UNUS if(!guid) return TRUE; - auto& devices = *reinterpret_cast*>(data); + auto& devices = *static_cast*>(data); const std::string basename{DEVNAME_HEAD + wstr_to_utf8(desc)}; int count{1}; diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 60307e94..a99503e1 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -371,7 +371,7 @@ pa_proplist *prop_filter; /* PulseAudio Event Callbacks */ void context_state_callback(pa_context *context, void *pdata) { - auto loop = reinterpret_cast(pdata); + auto loop = static_cast(pdata); pa_context_state_t state{pa_context_get_state(context)}; if(state == PA_CONTEXT_READY || !PA_CONTEXT_IS_GOOD(state)) pa_threaded_mainloop_signal(loop, 0); @@ -379,7 +379,7 @@ void context_state_callback(pa_context *context, void *pdata) void stream_state_callback(pa_stream *stream, void *pdata) { - auto loop = reinterpret_cast(pdata); + auto loop = static_cast(pdata); pa_stream_state_t state{pa_stream_get_state(stream)}; if(state == PA_STREAM_READY || !PA_STREAM_IS_GOOD(state)) pa_threaded_mainloop_signal(loop, 0); @@ -387,7 +387,7 @@ void stream_state_callback(pa_stream *stream, void *pdata) void stream_success_callback(pa_stream *UNUSED(stream), int UNUSED(success), void *pdata) { - auto loop = reinterpret_cast(pdata); + auto loop = static_cast(pdata); pa_threaded_mainloop_signal(loop, 0); } diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 11bc06e4..5c97324e 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -353,7 +353,7 @@ struct WasapiProxy { DWORD WasapiProxy::messageHandler(void *ptr) { - auto req = reinterpret_cast(ptr); + auto req = static_cast(ptr); TRACE("Starting message thread\n"); @@ -365,8 +365,8 @@ DWORD WasapiProxy::messageHandler(void *ptr) return 0; } - HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, - IID_IMMDeviceEnumerator, &ptr); + HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, + IID_IMMDeviceEnumerator, &ptr)}; if(FAILED(hr)) { WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr); @@ -374,7 +374,7 @@ DWORD WasapiProxy::messageHandler(void *ptr) ReturnMsgResponse(req, hr); return 0; } - auto Enumerator = reinterpret_cast(ptr); + auto Enumerator = static_cast(ptr); Enumerator->Release(); Enumerator = nullptr; @@ -466,7 +466,7 @@ DWORD WasapiProxy::messageHandler(void *ptr) hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, &ptr); if(SUCCEEDED(hr)) { - Enumerator = reinterpret_cast(ptr); + Enumerator = static_cast(ptr); if(msg.lParam == ALL_DEVICE_PROBE) hr = probe_devices(Enumerator, eRender, PlaybackDevices); @@ -757,10 +757,10 @@ ALCenum WasapiPlayback_open(WasapiPlayback *self, const ALCchar *deviceName) HRESULT WasapiPlayback::openProxy() { void *ptr; - HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, &ptr); + HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, &ptr)}; if(SUCCEEDED(hr)) { - auto Enumerator = reinterpret_cast(ptr); + auto Enumerator = static_cast(ptr); if(mDevId.empty()) hr = Enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &mMMDev); else @@ -771,7 +771,7 @@ HRESULT WasapiPlayback::openProxy() hr = mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); if(SUCCEEDED(hr)) { - mClient = reinterpret_cast(ptr); + mClient = static_cast(ptr); if(mDevice->DeviceName.empty()) mDevice->DeviceName = get_device_name_and_guid(mMMDev).first; } @@ -823,7 +823,7 @@ HRESULT WasapiPlayback::resetProxy() ERR("Failed to reactivate audio client: 0x%08lx\n", hr); return hr; } - mClient = reinterpret_cast(ptr); + mClient = static_cast(ptr); WAVEFORMATEX *wfx; hr = mClient->GetMixFormat(&wfx); @@ -1093,7 +1093,7 @@ HRESULT WasapiPlayback::startProxy() hr = mClient->GetService(IID_IAudioRenderClient, &ptr); if(SUCCEEDED(hr)) { - mRender = reinterpret_cast(ptr); + mRender = static_cast(ptr); try { mKillNow.store(AL_FALSE, std::memory_order_release); mThread = std::thread{std::mem_fn(&WasapiPlayback::mixerProc), this}; @@ -1421,11 +1421,11 @@ ALCenum WasapiCapture_open(WasapiCapture *self, const ALCchar *deviceName) HRESULT WasapiCapture::openProxy() { void *ptr; - HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, - IID_IMMDeviceEnumerator, &ptr); + HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, + IID_IMMDeviceEnumerator, &ptr)}; if(SUCCEEDED(hr)) { - auto Enumerator = reinterpret_cast(ptr); + auto Enumerator = static_cast(ptr); if(mDevId.empty()) hr = Enumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, &mMMDev); else @@ -1436,7 +1436,7 @@ HRESULT WasapiCapture::openProxy() hr = mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); if(SUCCEEDED(hr)) { - mClient = reinterpret_cast(ptr); + mClient = static_cast(ptr); if(mDevice->DeviceName.empty()) mDevice->DeviceName = get_device_name_and_guid(mMMDev).first; } @@ -1475,7 +1475,7 @@ HRESULT WasapiCapture::resetProxy() ERR("Failed to reactivate audio client: 0x%08lx\n", hr); return hr; } - mClient = reinterpret_cast(ptr); + mClient = static_cast(ptr); REFERENCE_TIME buf_time{ScaleCeil(mDevice->UpdateSize*mDevice->NumUpdates, REFTIME_PER_SEC, mDevice->Frequency)}; @@ -1721,7 +1721,7 @@ HRESULT WasapiCapture::startProxy() hr = mClient->GetService(IID_IAudioCaptureClient, &ptr); if(SUCCEEDED(hr)) { - mCapture = reinterpret_cast(ptr); + mCapture = static_cast(ptr); try { mKillNow.store(AL_FALSE, std::memory_order_release); mThread = std::thread{std::mem_fn(&WasapiCapture::recordProc), this}; diff --git a/common/almalloc.h b/common/almalloc.h index 7ec07004..26fa37ee 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -73,7 +73,7 @@ inline T* assume_aligned(T *ptr) noexcept { static_assert((alignment & (alignment-1)) == 0, "alignment must be a power of 2"); #ifdef __GNUC__ - return reinterpret_cast(__builtin_assume_aligned(ptr, alignment)); + return static_cast(__builtin_assume_aligned(ptr, alignment)); #elif defined(_MSC_VER) auto ptrval = reinterpret_cast(ptr); if((ptrval&(alignment-1)) != 0) __assume(0); -- cgit v1.2.3 From 3d92e8c4df4ebaffbe44507f787f2382e3982c96 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 28 Dec 2018 22:56:20 -0800 Subject: Convert the backends to use proper inheritence --- Alc/alc.cpp | 61 +++--- Alc/backends/alsa.cpp | 413 +++++++++++++++++--------------------- Alc/backends/alsa.h | 2 +- Alc/backends/base.cpp | 68 +++---- Alc/backends/base.h | 79 ++------ Alc/backends/coreaudio.cpp | 291 +++++++++++---------------- Alc/backends/coreaudio.h | 2 +- Alc/backends/dsound.cpp | 399 ++++++++++++++++-------------------- Alc/backends/dsound.h | 2 +- Alc/backends/jack.cpp | 199 ++++++++---------- Alc/backends/jack.h | 2 +- Alc/backends/loopback.cpp | 65 ++---- Alc/backends/loopback.h | 2 +- Alc/backends/null.cpp | 76 +++---- Alc/backends/null.h | 2 +- Alc/backends/opensl.cpp | 440 +++++++++++++++++----------------------- Alc/backends/opensl.h | 2 +- Alc/backends/oss.cpp | 287 +++++++++++--------------- Alc/backends/oss.h | 2 +- Alc/backends/portaudio.cpp | 285 +++++++++++--------------- Alc/backends/portaudio.h | 2 +- Alc/backends/pulseaudio.cpp | 479 +++++++++++++++++++------------------------- Alc/backends/pulseaudio.h | 2 +- Alc/backends/qsa.cpp | 153 +++++--------- Alc/backends/qsa.h | 2 +- Alc/backends/sdl2.cpp | 158 ++++++--------- Alc/backends/sdl2.h | 2 +- Alc/backends/sndio.cpp | 258 ++++++++++-------------- Alc/backends/sndio.h | 2 +- Alc/backends/solaris.cpp | 124 +++++------- Alc/backends/solaris.h | 2 +- Alc/backends/wasapi.cpp | 262 ++++++++++-------------- Alc/backends/wasapi.h | 2 +- Alc/backends/wave.cpp | 164 +++++++-------- Alc/backends/wave.h | 2 +- Alc/backends/winmm.cpp | 369 ++++++++++++++-------------------- Alc/backends/winmm.h | 2 +- Alc/polymorphism.h | 90 --------- CMakeLists.txt | 1 - OpenAL32/Include/alMain.h | 4 +- 40 files changed, 1903 insertions(+), 2856 deletions(-) delete mode 100644 Alc/polymorphism.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 1b3692e2..95592556 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1623,7 +1623,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) * the device attributes can be updated. */ if((device->Flags&DEVICE_RUNNING)) - V0(device->Backend,stop)(); + device->Backend->stop(); device->Flags &= ~DEVICE_RUNNING; } @@ -1740,7 +1740,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } if((device->Flags&DEVICE_RUNNING)) - V0(device->Backend,stop)(); + device->Backend->stop(); device->Flags &= ~DEVICE_RUNNING; UpdateClockBase(device); @@ -1893,7 +1893,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->UpdateSize, device->NumUpdates ); - if(V0(device->Backend,reset)() == ALC_FALSE) + if(device->Backend->reset() == ALC_FALSE) return ALC_INVALID_DEVICE; if(device->FmtChans != oldChans && (device->Flags&DEVICE_CHANNELS_REQUEST)) @@ -2180,7 +2180,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(!(device->Flags&DEVICE_PAUSED)) { - if(V0(device->Backend,start)() == ALC_FALSE) + if(device->Backend->start() == ALC_FALSE) return ALC_INVALID_DEVICE; device->Flags |= DEVICE_RUNNING; } @@ -2203,7 +2203,7 @@ ALCdevice_struct::~ALCdevice_struct() { TRACE("%p\n", this); - DELETE_OBJ(Backend); + delete Backend; Backend = nullptr; size_t count{std::accumulate(BufferList.cbegin(), BufferList.cend(), size_t{0u}, @@ -2509,7 +2509,7 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) if(GlobalContext.compare_exchange_strong(origctx, nullptr)) ALCcontext_DecRef(context); - V0(device->Backend,lock)(); + device->Backend->lock(); origctx = context; newhead = context->next.load(std::memory_order_relaxed); if(!device->ContextList.compare_exchange_strong(origctx, newhead)) @@ -2525,7 +2525,7 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) } else ret = !!newhead; - V0(device->Backend,unlock)(); + device->Backend->unlock(); /* Make sure the context is finished and no longer processing in the mixer * before sending the message queue kill event. The backend's lock does @@ -2934,7 +2934,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC values[i++] = ALC_MINOR_VERSION; values[i++] = alcMinorVersion; values[i++] = ALC_CAPTURE_SAMPLES; - values[i++] = V0(device->Backend,availableSamples)(); + values[i++] = device->Backend->availableSamples(); values[i++] = ALC_CONNECTED; values[i++] = device->Connected.load(std::memory_order_relaxed); values[i++] = 0; @@ -2950,7 +2950,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC case ALC_CAPTURE_SAMPLES: { std::lock_guard _{device->BackendLock}; - values[0] = V0(device->Backend,availableSamples)(); + values[0] = device->Backend->availableSamples(); } return 1; @@ -3443,9 +3443,9 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin alcSetError(dev.get(), err); if(err == ALC_INVALID_DEVICE) { - V0(dev->Backend,lock)(); + dev->Backend->lock(); aluHandleDisconnect(dev.get(), "Device update failure"); - V0(dev->Backend,unlock)(); + dev->Backend->unlock(); } backlock.unlock(); @@ -3526,7 +3526,7 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) std::lock_guard _{Device->BackendLock}; if(!ReleaseContext(ctx.get(), Device)) { - V0(Device->Backend,stop)(); + Device->Backend->stop(); Device->Flags &= ~DEVICE_RUNNING; } } @@ -3778,7 +3778,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) } // Find a playback device to open - ALCenum err{V(device->Backend,open)(deviceName)}; + ALCenum err{device->Backend->open(deviceName)}; if(err != ALC_NO_ERROR) { device = nullptr; @@ -3869,7 +3869,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) ctx = next; } if((device->Flags&DEVICE_RUNNING)) - V0(device->Backend,stop)(); + device->Backend->stop(); device->Flags &= ~DEVICE_RUNNING; backlock.unlock(); @@ -3929,7 +3929,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), device->Frequency, device->UpdateSize, device->NumUpdates ); - ALCenum err{V(device->Backend,open)(deviceName)}; + ALCenum err{device->Backend->open(deviceName)}; if(err != ALC_NO_ERROR) { device = nullptr; @@ -3978,7 +3978,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) { std::lock_guard _{device->BackendLock}; if((device->Flags&DEVICE_RUNNING)) - V0(device->Backend,stop)(); + device->Backend->stop(); device->Flags &= ~DEVICE_RUNNING; } @@ -4001,7 +4001,7 @@ ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) alcSetError(dev.get(), ALC_INVALID_DEVICE); else if(!(dev->Flags&DEVICE_RUNNING)) { - if(V0(dev->Backend,start)()) + if(dev->Backend->start()) dev->Flags |= DEVICE_RUNNING; else { @@ -4020,7 +4020,7 @@ ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) { std::lock_guard _{dev->BackendLock}; if((dev->Flags&DEVICE_RUNNING)) - V0(dev->Backend,stop)(); + dev->Backend->stop(); dev->Flags &= ~DEVICE_RUNNING; } } @@ -4036,8 +4036,9 @@ ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCenum err{ALC_INVALID_VALUE}; { std::lock_guard _{dev->BackendLock}; - if(samples >= 0 && V0(dev->Backend,availableSamples)() >= (ALCuint)samples) - err = V(dev->Backend,captureSamples)(buffer, samples); + BackendBase *backend{dev->Backend}; + if(samples >= 0 && backend->availableSamples() >= (ALCuint)samples) + err = backend->captureSamples(buffer, samples); } if(err != ALC_NO_ERROR) alcSetError(dev.get(), err); @@ -4102,7 +4103,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN } // Open the "backend" - V(device->Backend,open)("Loopback"); + device->Backend->open("Loopback"); { ALCdevice *head{DeviceList.load()}; @@ -4149,9 +4150,9 @@ FORCE_ALIGN ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, AL alcSetError(dev.get(), ALC_INVALID_VALUE); else { - V0(dev->Backend,lock)(); + dev->Backend->lock(); aluMixData(dev.get(), buffer, samples); - V0(dev->Backend,unlock)(); + dev->Backend->unlock(); } } @@ -4173,7 +4174,7 @@ ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device) { std::lock_guard _{dev->BackendLock}; if((dev->Flags&DEVICE_RUNNING)) - V0(dev->Backend,stop)(); + dev->Backend->stop(); dev->Flags &= ~DEVICE_RUNNING; dev->Flags |= DEVICE_PAUSED; } @@ -4199,11 +4200,11 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) if(dev->ContextList.load() == nullptr) return; - if(V0(dev->Backend,start)() == ALC_FALSE) + if(dev->Backend->start() == ALC_FALSE) { - V0(dev->Backend,lock)(); + dev->Backend->lock(); aluHandleDisconnect(dev.get(), "Device start failure"); - V0(dev->Backend,unlock)(); + dev->Backend->unlock(); alcSetError(dev.get(), ALC_INVALID_DEVICE); return; } @@ -4261,7 +4262,7 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi * the connected state so lost devices can attempt recover. */ if((dev->Flags&DEVICE_RUNNING)) - V0(dev->Backend,stop)(); + dev->Backend->stop(); dev->Flags &= ~DEVICE_RUNNING; device->Connected.store(AL_TRUE); @@ -4271,9 +4272,9 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi alcSetError(dev.get(), err); if(err == ALC_INVALID_DEVICE) { - V0(dev->Backend,lock)(); + dev->Backend->lock(); aluHandleDisconnect(dev.get(), "Device start failure"); - V0(dev->Backend,unlock)(); + dev->Backend->unlock(); } return ALC_FALSE; } diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index 17af2364..c5d75fe3 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -422,46 +422,32 @@ int verify_state(snd_pcm_t *handle) } -struct ALCplaybackAlsa final : public ALCbackend { - ALCplaybackAlsa(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCplaybackAlsa() override; +struct AlsaPlayback final : public BackendBase { + AlsaPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~AlsaPlayback() override; int mixerProc(); int mixerNoMMapProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + + ClockLatency getClockLatency() override; + snd_pcm_t *mPcmHandle{nullptr}; al::vector mBuffer; std::atomic mKillNow{AL_TRUE}; std::thread mThread; -}; -void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device); -void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self); -ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name); -ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self); -ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self); -void ALCplaybackAlsa_stop(ALCplaybackAlsa *self); -DECLARE_FORWARD2(ALCplaybackAlsa, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, ALCuint, availableSamples) -ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self); -DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, lock) -DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCplaybackAlsa) -DEFINE_ALCBACKEND_VTABLE(ALCplaybackAlsa); - - -void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device) -{ - new (self) ALCplaybackAlsa{device}; - SET_VTABLE2(ALCplaybackAlsa, ALCbackend, self); -} - -void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self) -{ self->~ALCplaybackAlsa(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "AlsaPlayback::"; } + DEF_NEWDEL(AlsaPlayback) +}; -ALCplaybackAlsa::~ALCplaybackAlsa() +AlsaPlayback::~AlsaPlayback() { if(mPcmHandle) snd_pcm_close(mPcmHandle); @@ -469,7 +455,7 @@ ALCplaybackAlsa::~ALCplaybackAlsa() } -int ALCplaybackAlsa::mixerProc() +int AlsaPlayback::mixerProc() { SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); @@ -482,9 +468,9 @@ int ALCplaybackAlsa::mixerProc() if(state < 0) { ERR("Invalid state detected: %s\n", snd_strerror(state)); - ALCplaybackAlsa_lock(this); + lock(); aluHandleDisconnect(mDevice, "Bad state: %s", snd_strerror(state)); - ALCplaybackAlsa_unlock(this); + unlock(); break; } @@ -521,7 +507,7 @@ int ALCplaybackAlsa::mixerProc() avail -= avail%update_size; // it is possible that contiguous areas are smaller, thus we use a loop - ALCplaybackAlsa_lock(this); + lock(); while(avail > 0) { snd_pcm_uframes_t frames{static_cast(avail)}; @@ -548,13 +534,13 @@ int ALCplaybackAlsa::mixerProc() avail -= frames; } - ALCplaybackAlsa_unlock(this); + unlock(); } return 0; } -int ALCplaybackAlsa::mixerNoMMapProc() +int AlsaPlayback::mixerNoMMapProc() { SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); @@ -567,9 +553,9 @@ int ALCplaybackAlsa::mixerNoMMapProc() if(state < 0) { ERR("Invalid state detected: %s\n", snd_strerror(state)); - ALCplaybackAlsa_lock(this); + lock(); aluHandleDisconnect(mDevice, "Bad state: %s", snd_strerror(state)); - ALCplaybackAlsa_unlock(this); + unlock(); break; } @@ -603,7 +589,7 @@ int ALCplaybackAlsa::mixerNoMMapProc() continue; } - ALCplaybackAlsa_lock(this); + lock(); char *WritePtr{mBuffer.data()}; avail = snd_pcm_bytes_to_frames(mPcmHandle, mBuffer.size()); aluMixData(mDevice, WritePtr, avail); @@ -637,14 +623,14 @@ int ALCplaybackAlsa::mixerNoMMapProc() if(ret < 0) break; } } - ALCplaybackAlsa_unlock(this); + unlock(); } return 0; } -ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name) +ALCenum AlsaPlayback::open(const ALCchar *name) { const char *driver{}; if(name) @@ -667,7 +653,7 @@ ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name) } TRACE("Opening device \"%s\"\n", driver); - int err{snd_pcm_open(&self->mPcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)}; + int err{snd_pcm_open(&mPcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)}; if(err < 0) { ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(err)); @@ -677,18 +663,15 @@ 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(); - ALCdevice *device = self->mDevice; - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) +ALCboolean AlsaPlayback::reset() { - ALCdevice *device{self->mDevice}; - snd_pcm_format_t format{SND_PCM_FORMAT_UNKNOWN}; - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: format = SND_PCM_FORMAT_S8; @@ -713,11 +696,11 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) break; } - bool allowmmap{!!GetConfigValueBool(device->DeviceName.c_str(), "alsa", "mmap", 1)}; - ALuint periods{device->NumUpdates}; - ALuint periodLen{static_cast(device->UpdateSize * U64(1000000) / device->Frequency)}; + bool allowmmap{!!GetConfigValueBool(mDevice->DeviceName.c_str(), "alsa", "mmap", 1)}; + ALuint periods{mDevice->NumUpdates}; + ALuint periodLen{static_cast(mDevice->UpdateSize * U64(1000000) / mDevice->Frequency)}; ALuint bufferLen{periodLen * periods}; - ALuint rate{device->Frequency}; + ALuint rate{mDevice->Frequency}; snd_pcm_uframes_t periodSizeInFrames; snd_pcm_sw_params_t *sp{}; @@ -727,15 +710,15 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) int dir, err; snd_pcm_hw_params_malloc(&hp); #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error - CHECK(snd_pcm_hw_params_any(self->mPcmHandle, hp)); + CHECK(snd_pcm_hw_params_any(mPcmHandle, hp)); /* set interleaved access */ - if(!allowmmap || snd_pcm_hw_params_set_access(self->mPcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) + if(!allowmmap || snd_pcm_hw_params_set_access(mPcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) { /* No mmap */ - CHECK(snd_pcm_hw_params_set_access(self->mPcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); + CHECK(snd_pcm_hw_params_set_access(mPcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); } /* test and set format (implicitly sets sample bits) */ - if(snd_pcm_hw_params_test_format(self->mPcmHandle, hp, format) < 0) + if(snd_pcm_hw_params_test_format(mPcmHandle, hp, format) < 0) { static const struct { snd_pcm_format_t format; @@ -753,16 +736,16 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) for(const auto &fmt : formatlist) { format = fmt.format; - if(snd_pcm_hw_params_test_format(self->mPcmHandle, hp, format) >= 0) + if(snd_pcm_hw_params_test_format(mPcmHandle, hp, format) >= 0) { - device->FmtType = fmt.fmttype; + mDevice->FmtType = fmt.fmttype; break; } } } - CHECK(snd_pcm_hw_params_set_format(self->mPcmHandle, hp, format)); + CHECK(snd_pcm_hw_params_set_format(mPcmHandle, hp, format)); /* test and set channels (implicitly sets frame bits) */ - if(snd_pcm_hw_params_test_channels(self->mPcmHandle, hp, device->channelsFromFmt()) < 0) + if(snd_pcm_hw_params_test_channels(mPcmHandle, hp, mDevice->channelsFromFmt()) < 0) { static const DevFmtChannels channellist[] = { DevFmtStereo, @@ -774,33 +757,33 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) for(const auto &chan : channellist) { - if(snd_pcm_hw_params_test_channels(self->mPcmHandle, hp, ChannelsFromDevFmt(chan, 0)) >= 0) + if(snd_pcm_hw_params_test_channels(mPcmHandle, hp, ChannelsFromDevFmt(chan, 0)) >= 0) { - device->FmtChans = chan; - device->mAmbiOrder = 0; + mDevice->FmtChans = chan; + mDevice->mAmbiOrder = 0; break; } } } - CHECK(snd_pcm_hw_params_set_channels(self->mPcmHandle, hp, device->channelsFromFmt())); + CHECK(snd_pcm_hw_params_set_channels(mPcmHandle, hp, mDevice->channelsFromFmt())); /* set rate (implicitly constrains period/buffer parameters) */ - if(!GetConfigValueBool(device->DeviceName.c_str(), "alsa", "allow-resampler", 0) || - !(device->Flags&DEVICE_FREQUENCY_REQUEST)) + if(!GetConfigValueBool(mDevice->DeviceName.c_str(), "alsa", "allow-resampler", 0) || + !(mDevice->Flags&DEVICE_FREQUENCY_REQUEST)) { - if(snd_pcm_hw_params_set_rate_resample(self->mPcmHandle, hp, 0) < 0) + if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp, 0) < 0) ERR("Failed to disable ALSA resampler\n"); } - else if(snd_pcm_hw_params_set_rate_resample(self->mPcmHandle, hp, 1) < 0) + else if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp, 1) < 0) ERR("Failed to enable ALSA resampler\n"); - CHECK(snd_pcm_hw_params_set_rate_near(self->mPcmHandle, hp, &rate, nullptr)); + CHECK(snd_pcm_hw_params_set_rate_near(mPcmHandle, hp, &rate, nullptr)); /* set buffer time (implicitly constrains period/buffer parameters) */ - if((err=snd_pcm_hw_params_set_buffer_time_near(self->mPcmHandle, hp, &bufferLen, nullptr)) < 0) + if((err=snd_pcm_hw_params_set_buffer_time_near(mPcmHandle, hp, &bufferLen, nullptr)) < 0) ERR("snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err)); /* set period time (implicitly sets buffer size/bytes/time and period size/bytes) */ - if((err=snd_pcm_hw_params_set_period_time_near(self->mPcmHandle, hp, &periodLen, nullptr)) < 0) + if((err=snd_pcm_hw_params_set_period_time_near(mPcmHandle, hp, &periodLen, nullptr)) < 0) ERR("snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err)); /* install and prepare hardware configuration */ - CHECK(snd_pcm_hw_params(self->mPcmHandle, hp)); + CHECK(snd_pcm_hw_params(mPcmHandle, hp)); /* retrieve configuration info */ CHECK(snd_pcm_hw_params_get_access(hp, &access)); @@ -812,19 +795,19 @@ ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) hp = nullptr; snd_pcm_sw_params_malloc(&sp); - CHECK(snd_pcm_sw_params_current(self->mPcmHandle, sp)); - CHECK(snd_pcm_sw_params_set_avail_min(self->mPcmHandle, sp, periodSizeInFrames)); - CHECK(snd_pcm_sw_params_set_stop_threshold(self->mPcmHandle, sp, periodSizeInFrames*periods)); - CHECK(snd_pcm_sw_params(self->mPcmHandle, sp)); + CHECK(snd_pcm_sw_params_current(mPcmHandle, sp)); + CHECK(snd_pcm_sw_params_set_avail_min(mPcmHandle, sp, periodSizeInFrames)); + CHECK(snd_pcm_sw_params_set_stop_threshold(mPcmHandle, sp, periodSizeInFrames*periods)); + CHECK(snd_pcm_sw_params(mPcmHandle, sp)); #undef CHECK snd_pcm_sw_params_free(sp); sp = nullptr; - device->NumUpdates = periods; - device->UpdateSize = periodSizeInFrames; - device->Frequency = rate; + mDevice->NumUpdates = periods; + mDevice->UpdateSize = periodSizeInFrames; + mDevice->Frequency = rate; - SetDefaultChannelOrder(device); + SetDefaultChannelOrder(mDevice); return ALC_TRUE; @@ -835,9 +818,8 @@ error: return ALC_FALSE; } -ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) +ALCboolean AlsaPlayback::start() { - ALCdevice *device{self->mDevice}; snd_pcm_hw_params_t *hp{}; snd_pcm_access_t access; const char *funcerr; @@ -845,7 +827,7 @@ ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) snd_pcm_hw_params_malloc(&hp); #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error - CHECK(snd_pcm_hw_params_current(self->mPcmHandle, hp)); + CHECK(snd_pcm_hw_params_current(mPcmHandle, hp)); /* retrieve configuration info */ CHECK(snd_pcm_hw_params_get_access(hp, &access)); #undef CHECK @@ -859,26 +841,26 @@ ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) snd_pcm_hw_params_free(hp); hp = nullptr; - int (ALCplaybackAlsa::*thread_func)(){}; + int (AlsaPlayback::*thread_func)(){}; if(access == SND_PCM_ACCESS_RW_INTERLEAVED) { - self->mBuffer.resize(snd_pcm_frames_to_bytes(self->mPcmHandle, device->UpdateSize)); - thread_func = &ALCplaybackAlsa::mixerNoMMapProc; + mBuffer.resize(snd_pcm_frames_to_bytes(mPcmHandle, mDevice->UpdateSize)); + thread_func = &AlsaPlayback::mixerNoMMapProc; } else { - err = snd_pcm_prepare(self->mPcmHandle); + err = snd_pcm_prepare(mPcmHandle); if(err < 0) { ERR("snd_pcm_prepare(data->mPcmHandle) failed: %s\n", snd_strerror(err)); return ALC_FALSE; } - thread_func = &ALCplaybackAlsa::mixerProc; + thread_func = &AlsaPlayback::mixerProc; } try { - self->mKillNow.store(AL_FALSE, std::memory_order_release); - self->mThread = std::thread{std::mem_fn(thread_func), self}; + mKillNow.store(AL_FALSE, std::memory_order_release); + mThread = std::thread{std::mem_fn(thread_func), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -886,45 +868,50 @@ ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) } catch(...) { } - self->mBuffer.clear(); + mBuffer.clear(); return ALC_FALSE; } -void ALCplaybackAlsa_stop(ALCplaybackAlsa *self) +void AlsaPlayback::stop() { - if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->mThread.joinable()) + if(mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !mThread.joinable()) return; + mThread.join(); - self->mThread.join(); - - self->mBuffer.clear(); + mBuffer.clear(); } -ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self) +ClockLatency AlsaPlayback::getClockLatency() { - ALCdevice *device{self->mDevice}; ClockLatency ret; - ALCplaybackAlsa_lock(self); - ret.ClockTime = GetDeviceClockTime(device); + lock(); + ret.ClockTime = GetDeviceClockTime(mDevice); snd_pcm_sframes_t delay{}; - int err{snd_pcm_delay(self->mPcmHandle, &delay)}; + int err{snd_pcm_delay(mPcmHandle, &delay)}; if(err < 0) { ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); delay = 0; } ret.Latency = std::chrono::seconds{std::max(0, delay)}; - ret.Latency /= device->Frequency; - ALCplaybackAlsa_unlock(self); + ret.Latency /= mDevice->Frequency; + unlock(); return ret; } -struct ALCcaptureAlsa final : public ALCbackend { - ALCcaptureAlsa(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCcaptureAlsa() override; +struct AlsaCapture final : public BackendBase { + AlsaCapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~AlsaCapture() override; + + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + ClockLatency getClockLatency() override; snd_pcm_t *mPcmHandle{nullptr}; @@ -934,34 +921,12 @@ struct ALCcaptureAlsa final : public ALCbackend { RingBufferPtr mRing{nullptr}; snd_pcm_sframes_t mLastAvail{0}; -}; - -void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device); -void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self); -ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name); -DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, ALCboolean, reset) -ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self); -void ALCcaptureAlsa_stop(ALCcaptureAlsa *self); -ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALCuint samples); -ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self); -ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self); -DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, lock) -DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCcaptureAlsa) - -DEFINE_ALCBACKEND_VTABLE(ALCcaptureAlsa); - -void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device) -{ - new (self) ALCcaptureAlsa{device}; - SET_VTABLE2(ALCcaptureAlsa, ALCbackend, self); -} - -void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self) -{ self->~ALCcaptureAlsa(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "AlsaCapture::"; } + DEF_NEWDEL(AlsaCapture) +}; -ALCcaptureAlsa::~ALCcaptureAlsa() +AlsaCapture::~AlsaCapture() { if(mPcmHandle) snd_pcm_close(mPcmHandle); @@ -969,9 +934,8 @@ ALCcaptureAlsa::~ALCcaptureAlsa() } -ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) +ALCenum AlsaCapture::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; const char *driver{}; if(name) { @@ -993,7 +957,7 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) } TRACE("Opening device \"%s\"\n", driver); - int err{snd_pcm_open(&self->mPcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)}; + int err{snd_pcm_open(&mPcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)}; if(err < 0) { ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err)); @@ -1004,7 +968,7 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) snd_config_update_free_global(); snd_pcm_format_t format{SND_PCM_FORMAT_UNKNOWN}; - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: format = SND_PCM_FORMAT_S8; @@ -1029,35 +993,35 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) break; } - snd_pcm_uframes_t bufferSizeInFrames{maxu(device->UpdateSize*device->NumUpdates, - 100*device->Frequency/1000)}; - snd_pcm_uframes_t periodSizeInFrames{minu(bufferSizeInFrames, 25*device->Frequency/1000)}; + snd_pcm_uframes_t bufferSizeInFrames{maxu(mDevice->UpdateSize*mDevice->NumUpdates, + 100*mDevice->Frequency/1000)}; + snd_pcm_uframes_t periodSizeInFrames{minu(bufferSizeInFrames, 25*mDevice->Frequency/1000)}; bool needring{false}; const char *funcerr{}; snd_pcm_hw_params_t *hp{}; snd_pcm_hw_params_malloc(&hp); #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error - CHECK(snd_pcm_hw_params_any(self->mPcmHandle, hp)); + CHECK(snd_pcm_hw_params_any(mPcmHandle, hp)); /* set interleaved access */ - CHECK(snd_pcm_hw_params_set_access(self->mPcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); + CHECK(snd_pcm_hw_params_set_access(mPcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); /* set format (implicitly sets sample bits) */ - CHECK(snd_pcm_hw_params_set_format(self->mPcmHandle, hp, format)); + CHECK(snd_pcm_hw_params_set_format(mPcmHandle, hp, format)); /* set channels (implicitly sets frame bits) */ - CHECK(snd_pcm_hw_params_set_channels(self->mPcmHandle, hp, device->channelsFromFmt())); + CHECK(snd_pcm_hw_params_set_channels(mPcmHandle, hp, mDevice->channelsFromFmt())); /* set rate (implicitly constrains period/buffer parameters) */ - CHECK(snd_pcm_hw_params_set_rate(self->mPcmHandle, hp, device->Frequency, 0)); + CHECK(snd_pcm_hw_params_set_rate(mPcmHandle, hp, mDevice->Frequency, 0)); /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ - if(snd_pcm_hw_params_set_buffer_size_min(self->mPcmHandle, hp, &bufferSizeInFrames) < 0) + if(snd_pcm_hw_params_set_buffer_size_min(mPcmHandle, hp, &bufferSizeInFrames) < 0) { TRACE("Buffer too large, using intermediate ring buffer\n"); needring = true; - CHECK(snd_pcm_hw_params_set_buffer_size_near(self->mPcmHandle, hp, &bufferSizeInFrames)); + CHECK(snd_pcm_hw_params_set_buffer_size_near(mPcmHandle, hp, &bufferSizeInFrames)); } /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ - CHECK(snd_pcm_hw_params_set_period_size_near(self->mPcmHandle, hp, &periodSizeInFrames, nullptr)); + CHECK(snd_pcm_hw_params_set_period_size_near(mPcmHandle, hp, &periodSizeInFrames, nullptr)); /* install and prepare hardware configuration */ - CHECK(snd_pcm_hw_params(self->mPcmHandle, hp)); + CHECK(snd_pcm_hw_params(mPcmHandle, hp)); /* retrieve configuration info */ CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, nullptr)); #undef CHECK @@ -1066,16 +1030,16 @@ ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) if(needring) { - self->mRing = CreateRingBuffer(device->UpdateSize*device->NumUpdates, - device->frameSizeFromFmt(), false); - if(!self->mRing) + mRing = CreateRingBuffer(mDevice->UpdateSize*mDevice->NumUpdates, + mDevice->frameSizeFromFmt(), false); + if(!mRing) { ERR("ring buffer create failed\n"); goto error2; } } - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; @@ -1084,99 +1048,99 @@ error: if(hp) snd_pcm_hw_params_free(hp); error2: - self->mRing = nullptr; - snd_pcm_close(self->mPcmHandle); - self->mPcmHandle = nullptr; + mRing = nullptr; + snd_pcm_close(mPcmHandle); + mPcmHandle = nullptr; return ALC_INVALID_VALUE; } -ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self) + +ALCboolean AlsaCapture::start() { - int err{snd_pcm_prepare(self->mPcmHandle)}; + int err{snd_pcm_prepare(mPcmHandle)}; if(err < 0) ERR("prepare failed: %s\n", snd_strerror(err)); else { - err = snd_pcm_start(self->mPcmHandle); + err = snd_pcm_start(mPcmHandle); if(err < 0) ERR("start failed: %s\n", snd_strerror(err)); } if(err < 0) { - aluHandleDisconnect(self->mDevice, "Capture state failure: %s", snd_strerror(err)); + aluHandleDisconnect(mDevice, "Capture state failure: %s", snd_strerror(err)); return ALC_FALSE; } - self->mDoCapture = true; + mDoCapture = true; return ALC_TRUE; } -void ALCcaptureAlsa_stop(ALCcaptureAlsa *self) +void AlsaCapture::stop() { /* OpenAL requires access to unread audio after stopping, but ALSA's * snd_pcm_drain is unreliable and snd_pcm_drop drops it. Capture what's - * available now so it'll be available later after the drop. */ - ALCuint avail{ALCcaptureAlsa_availableSamples(self)}; - if(!self->mRing && avail > 0) + * available now so it'll be available later after the drop. + */ + ALCuint avail{availableSamples()}; + if(!mRing && avail > 0) { /* The ring buffer implicitly captures when checking availability. * Direct access needs to explicitly capture it into temp storage. */ - al::vector temp(snd_pcm_frames_to_bytes(self->mPcmHandle, avail)); - ALCcaptureAlsa_captureSamples(self, temp.data(), avail); - self->mBuffer = std::move(temp); + al::vector temp(snd_pcm_frames_to_bytes(mPcmHandle, avail)); + captureSamples(temp.data(), avail); + mBuffer = std::move(temp); } - int err{snd_pcm_drop(self->mPcmHandle)}; + int err{snd_pcm_drop(mPcmHandle)}; if(err < 0) ERR("drop failed: %s\n", snd_strerror(err)); - self->mDoCapture = false; + mDoCapture = false; } -ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALCuint samples) +ALCenum AlsaCapture::captureSamples(ALCvoid *buffer, ALCuint samples) { - ALCdevice *device{self->mDevice}; - - if(RingBuffer *ring{self->mRing.get()}) + if(mRing) { - ring->read(buffer, samples); + mRing->read(buffer, samples); return ALC_NO_ERROR; } - self->mLastAvail -= samples; - while(device->Connected.load(std::memory_order_acquire) && samples > 0) + mLastAvail -= samples; + while(mDevice->Connected.load(std::memory_order_acquire) && samples > 0) { snd_pcm_sframes_t amt{0}; - if(!self->mBuffer.empty()) + if(!mBuffer.empty()) { /* First get any data stored from the last stop */ - amt = snd_pcm_bytes_to_frames(self->mPcmHandle, self->mBuffer.size()); + amt = snd_pcm_bytes_to_frames(mPcmHandle, mBuffer.size()); if((snd_pcm_uframes_t)amt > samples) amt = samples; - amt = snd_pcm_frames_to_bytes(self->mPcmHandle, amt); - memcpy(buffer, self->mBuffer.data(), amt); + amt = snd_pcm_frames_to_bytes(mPcmHandle, amt); + memcpy(buffer, mBuffer.data(), amt); - self->mBuffer.erase(self->mBuffer.begin(), self->mBuffer.begin()+amt); - amt = snd_pcm_bytes_to_frames(self->mPcmHandle, amt); + mBuffer.erase(mBuffer.begin(), mBuffer.begin()+amt); + amt = snd_pcm_bytes_to_frames(mPcmHandle, amt); } - else if(self->mDoCapture) - amt = snd_pcm_readi(self->mPcmHandle, buffer, samples); + else if(mDoCapture) + amt = snd_pcm_readi(mPcmHandle, buffer, samples); if(amt < 0) { ERR("read error: %s\n", snd_strerror(amt)); if(amt == -EAGAIN) continue; - if((amt=snd_pcm_recover(self->mPcmHandle, amt, 1)) >= 0) + if((amt=snd_pcm_recover(mPcmHandle, amt, 1)) >= 0) { - amt = snd_pcm_start(self->mPcmHandle); + amt = snd_pcm_start(mPcmHandle); if(amt >= 0) - amt = snd_pcm_avail_update(self->mPcmHandle); + amt = snd_pcm_avail_update(mPcmHandle); } if(amt < 0) { ERR("restore error: %s\n", snd_strerror(amt)); - aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(amt)); + aluHandleDisconnect(mDevice, "Capture recovery failure: %s", snd_strerror(amt)); break; } /* If the amount available is less than what's asked, we lost it @@ -1190,100 +1154,96 @@ ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALC samples -= amt; } if(samples > 0) - memset(buffer, ((device->FmtType == DevFmtUByte) ? 0x80 : 0), - snd_pcm_frames_to_bytes(self->mPcmHandle, samples)); + memset(buffer, ((mDevice->FmtType == DevFmtUByte) ? 0x80 : 0), + snd_pcm_frames_to_bytes(mPcmHandle, samples)); return ALC_NO_ERROR; } -ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) +ALCuint AlsaCapture::availableSamples() { - ALCdevice *device{self->mDevice}; - snd_pcm_sframes_t avail{0}; - if(device->Connected.load(std::memory_order_acquire) && self->mDoCapture) - avail = snd_pcm_avail_update(self->mPcmHandle); + if(mDevice->Connected.load(std::memory_order_acquire) && mDoCapture) + avail = snd_pcm_avail_update(mPcmHandle); if(avail < 0) { ERR("avail update failed: %s\n", snd_strerror(avail)); - if((avail=snd_pcm_recover(self->mPcmHandle, avail, 1)) >= 0) + if((avail=snd_pcm_recover(mPcmHandle, avail, 1)) >= 0) { - if(self->mDoCapture) - avail = snd_pcm_start(self->mPcmHandle); + if(mDoCapture) + avail = snd_pcm_start(mPcmHandle); if(avail >= 0) - avail = snd_pcm_avail_update(self->mPcmHandle); + avail = snd_pcm_avail_update(mPcmHandle); } if(avail < 0) { ERR("restore error: %s\n", snd_strerror(avail)); - aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(avail)); + aluHandleDisconnect(mDevice, "Capture recovery failure: %s", snd_strerror(avail)); } } - RingBuffer *ring{self->mRing.get()}; - if(!ring) + if(!mRing) { if(avail < 0) avail = 0; - avail += snd_pcm_bytes_to_frames(self->mPcmHandle, self->mBuffer.size()); - if(avail > self->mLastAvail) self->mLastAvail = avail; - return self->mLastAvail; + avail += snd_pcm_bytes_to_frames(mPcmHandle, mBuffer.size()); + if(avail > mLastAvail) mLastAvail = avail; + return mLastAvail; } while(avail > 0) { - auto vec = ring->getWriteVector(); + auto vec = mRing->getWriteVector(); if(vec.first.len == 0) break; snd_pcm_sframes_t amt{std::min(vec.first.len, avail)}; - amt = snd_pcm_readi(self->mPcmHandle, vec.first.buf, amt); + amt = snd_pcm_readi(mPcmHandle, vec.first.buf, amt); if(amt < 0) { ERR("read error: %s\n", snd_strerror(amt)); if(amt == -EAGAIN) continue; - if((amt=snd_pcm_recover(self->mPcmHandle, amt, 1)) >= 0) + if((amt=snd_pcm_recover(mPcmHandle, amt, 1)) >= 0) { - if(self->mDoCapture) - amt = snd_pcm_start(self->mPcmHandle); + if(mDoCapture) + amt = snd_pcm_start(mPcmHandle); if(amt >= 0) - amt = snd_pcm_avail_update(self->mPcmHandle); + amt = snd_pcm_avail_update(mPcmHandle); } if(amt < 0) { ERR("restore error: %s\n", snd_strerror(amt)); - aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(amt)); + aluHandleDisconnect(mDevice, "Capture recovery failure: %s", snd_strerror(amt)); break; } avail = amt; continue; } - ring->writeAdvance(amt); + mRing->writeAdvance(amt); avail -= amt; } - return ring->readSpace(); + return mRing->readSpace(); } -ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self) +ClockLatency AlsaCapture::getClockLatency() { - ALCdevice *device{self->mDevice}; ClockLatency ret; - ALCcaptureAlsa_lock(self); - ret.ClockTime = GetDeviceClockTime(device); + lock(); + ret.ClockTime = GetDeviceClockTime(mDevice); snd_pcm_sframes_t delay{}; - int err{snd_pcm_delay(self->mPcmHandle, &delay)}; + int err{snd_pcm_delay(mPcmHandle, &delay)}; if(err < 0) { ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); delay = 0; } ret.Latency = std::chrono::seconds{std::max(0, delay)}; - ret.Latency /= device->Frequency; - ALCcaptureAlsa_unlock(self); + ret.Latency /= mDevice->Frequency; + unlock(); return ret; } @@ -1332,21 +1292,12 @@ void AlsaBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *AlsaBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *AlsaBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - ALCplaybackAlsa *backend; - NEW_OBJ(backend, ALCplaybackAlsa)(device); - return backend; - } + return new AlsaPlayback{device}; if(type == ALCbackend_Capture) - { - ALCcaptureAlsa *backend; - NEW_OBJ(backend, ALCcaptureAlsa)(device); - return backend; - } - + return new AlsaCapture{device}; return nullptr; } diff --git a/Alc/backends/alsa.h b/Alc/backends/alsa.h index 8ee78f56..e9169c48 100644 --- a/Alc/backends/alsa.h +++ b/Alc/backends/alsa.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/base.cpp b/Alc/backends/base.cpp index 021a0f17..1fef0439 100644 --- a/Alc/backends/base.cpp +++ b/Alc/backends/base.cpp @@ -12,80 +12,60 @@ void ALCdevice_Lock(ALCdevice *device) -{ V0(device->Backend,lock)(); } +{ device->Backend->lock(); } void ALCdevice_Unlock(ALCdevice *device) -{ V0(device->Backend,unlock)(); } +{ device->Backend->unlock(); } ClockLatency GetClockLatency(ALCdevice *device) { - ClockLatency ret = V0(device->Backend,getClockLatency)(); + BackendBase *backend{device->Backend}; + ClockLatency ret{backend->getClockLatency()}; ret.Latency += device->FixedLatency; return ret; } -/* Base ALCbackend method implementations. */ -ALCbackend::ALCbackend(ALCdevice *device) noexcept : mDevice{device} +/* BackendBase method implementations. */ +BackendBase::BackendBase(ALCdevice *device) noexcept : mDevice{device} { } -ALCbackend::~ALCbackend() +BackendBase::~BackendBase() { } -ALCboolean ALCbackend_reset(ALCbackend* UNUSED(self)) -{ - return ALC_FALSE; -} +ALCboolean BackendBase::reset() +{ return ALC_FALSE; } -ALCenum ALCbackend_captureSamples(ALCbackend* UNUSED(self), void* UNUSED(buffer), ALCuint UNUSED(samples)) -{ - return ALC_INVALID_DEVICE; -} +ALCenum BackendBase::captureSamples(void* UNUSED(buffer), ALCuint UNUSED(samples)) +{ return ALC_INVALID_DEVICE; } -ALCuint ALCbackend_availableSamples(ALCbackend* UNUSED(self)) -{ - return 0; -} +ALCuint BackendBase::availableSamples() +{ return 0; } -ClockLatency ALCbackend_getClockLatency(ALCbackend *self) +ClockLatency BackendBase::getClockLatency() { - ALCdevice *device = self->mDevice; - ALuint refcount; ClockLatency ret; + ALuint refcount; do { - while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) + while(((refcount=mDevice->MixCount.load(std::memory_order_acquire))&1)) std::this_thread::yield(); - ret.ClockTime = GetDeviceClockTime(device); + ret.ClockTime = GetDeviceClockTime(mDevice); std::atomic_thread_fence(std::memory_order_acquire); - } while(refcount != device->MixCount.load(std::memory_order_relaxed)); + } while(refcount != mDevice->MixCount.load(std::memory_order_relaxed)); /* NOTE: The device will generally have about all but one periods filled at * any given time during playback. Without a more accurate measurement from * the output, this is an okay approximation. */ - ret.Latency = std::chrono::seconds{device->UpdateSize*maxi(device->NumUpdates-1, 0)}; - ret.Latency /= device->Frequency; + ret.Latency = std::chrono::seconds{mDevice->UpdateSize*maxi(mDevice->NumUpdates-1, 0)}; + ret.Latency /= mDevice->Frequency; return ret; } -void ALCbackend_lock(ALCbackend *self) -{ - try { - self->mMutex.lock(); - } - catch(...) { - std::terminate(); - } -} +void BackendBase::lock() noexcept +{ mMutex.lock(); } -void ALCbackend_unlock(ALCbackend *self) -{ - try { - self->mMutex.unlock(); - } - catch(...) { - std::terminate(); - } -} +void BackendBase::unlock() noexcept +{ mMutex.unlock(); } diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 4380540f..b9ea3b61 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -6,7 +6,6 @@ #include #include "alMain.h" -#include "polymorphism.h" struct ClockLatency { @@ -32,77 +31,29 @@ void ALCdevice_Unlock(ALCdevice *device); ClockLatency GetClockLatency(ALCdevice *device); +struct BackendBase { + virtual ALCenum open(const ALCchar *name) = 0; -struct ALCbackendVtable; + virtual ALCboolean reset(); + virtual ALCboolean start() = 0; + virtual void stop() = 0; -struct ALCbackend { - const ALCbackendVtable *vtbl; + virtual ALCenum captureSamples(void *buffer, ALCuint samples); + virtual ALCuint availableSamples(); - ALCdevice *mDevice; - - std::recursive_mutex mMutex; - - ALCbackend(ALCdevice *device) noexcept; - virtual ~ALCbackend(); -}; - -ALCboolean ALCbackend_reset(ALCbackend *self); -ALCenum ALCbackend_captureSamples(ALCbackend *self, void *buffer, ALCuint samples); -ALCuint ALCbackend_availableSamples(ALCbackend *self); -ClockLatency ALCbackend_getClockLatency(ALCbackend *self); -void ALCbackend_lock(ALCbackend *self); -void ALCbackend_unlock(ALCbackend *self); - -struct ALCbackendVtable { - void (*const Destruct)(ALCbackend*); + virtual ClockLatency getClockLatency(); - ALCenum (*const open)(ALCbackend*, const ALCchar*); + virtual void lock() noexcept; + virtual void unlock() noexcept; - ALCboolean (*const reset)(ALCbackend*); - ALCboolean (*const start)(ALCbackend*); - void (*const stop)(ALCbackend*); - - ALCenum (*const captureSamples)(ALCbackend*, void*, ALCuint); - ALCuint (*const availableSamples)(ALCbackend*); - - ClockLatency (*const getClockLatency)(ALCbackend*); + ALCdevice *mDevice; - void (*const lock)(ALCbackend*); - void (*const unlock)(ALCbackend*); + std::recursive_mutex mMutex; - void (*const Delete)(void*); + BackendBase(ALCdevice *device) noexcept; + virtual ~BackendBase(); }; -#define DEFINE_ALCBACKEND_VTABLE(T) \ -DECLARE_THUNK(T, ALCbackend, void, Destruct) \ -DECLARE_THUNK1(T, ALCbackend, ALCenum, open, const ALCchar*) \ -DECLARE_THUNK(T, ALCbackend, ALCboolean, reset) \ -DECLARE_THUNK(T, ALCbackend, ALCboolean, start) \ -DECLARE_THUNK(T, ALCbackend, void, stop) \ -DECLARE_THUNK2(T, ALCbackend, ALCenum, captureSamples, void*, ALCuint) \ -DECLARE_THUNK(T, ALCbackend, ALCuint, availableSamples) \ -DECLARE_THUNK(T, ALCbackend, ClockLatency, getClockLatency) \ -DECLARE_THUNK(T, ALCbackend, void, lock) \ -DECLARE_THUNK(T, ALCbackend, void, unlock) \ -static void T##_ALCbackend_Delete(void *ptr) \ -{ T##_Delete(static_cast(static_cast(ptr))); } \ - \ -static const ALCbackendVtable T##_ALCbackend_vtable = { \ - T##_ALCbackend_Destruct, \ - \ - T##_ALCbackend_open, \ - T##_ALCbackend_reset, \ - T##_ALCbackend_start, \ - T##_ALCbackend_stop, \ - T##_ALCbackend_captureSamples, \ - T##_ALCbackend_availableSamples, \ - T##_ALCbackend_getClockLatency, \ - T##_ALCbackend_lock, \ - T##_ALCbackend_unlock, \ - \ - T##_ALCbackend_Delete, \ -} - enum ALCbackend_Type { ALCbackend_Playback, @@ -119,7 +70,7 @@ struct BackendFactory { virtual void probe(DevProbe type, std::string *outnames) = 0; - virtual ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) = 0; + virtual BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) = 0; }; #endif /* ALC_BACKENDS_BASE_H */ diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index 82312d67..3f1f48d8 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -30,6 +30,7 @@ #include "alu.h" #include "ringbuffer.h" #include "converter.h" +#include "backends/base.h" #include #include @@ -41,9 +42,9 @@ namespace { static const ALCchar ca_device[] = "CoreAudio Default"; -struct ALCcoreAudioPlayback final : public ALCbackend { - ALCcoreAudioPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCcoreAudioPlayback() override; +struct CoreAudioPlayback final : public BackendBase { + CoreAudioPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~CoreAudioPlayback() override; static OSStatus MixerProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, @@ -52,64 +53,47 @@ struct ALCcoreAudioPlayback final : public ALCbackend { const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + AudioUnit mAudioUnit; ALuint mFrameSize{0u}; AudioStreamBasicDescription mFormat{}; // This is the OpenAL format as a CoreAudio ASBD -}; - -static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device); -static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self); -static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name); -static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self); -static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self); -static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self); -static DECLARE_FORWARD2(ALCcoreAudioPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioPlayback) - -DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioPlayback); - - -static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device) -{ - new (self) ALCcoreAudioPlayback{device}; - SET_VTABLE2(ALCcoreAudioPlayback, ALCbackend, self); -} -static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self) -{ self->~ALCcoreAudioPlayback(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "CoreAudioPlayback::"; } + DEF_NEWDEL(CoreAudioPlayback) +}; -ALCcoreAudioPlayback::~ALCcoreAudioPlayback() +CoreAudioPlayback::~CoreAudioPlayback() { AudioUnitUninitialize(mAudioUnit); AudioComponentInstanceDispose(mAudioUnit); } -OSStatus ALCcoreAudioPlayback::MixerProcC(void *inRefCon, +OSStatus CoreAudioPlayback::MixerProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { - return static_cast(inRefCon)->MixerProc(ioActionFlags, inTimeStamp, + return static_cast(inRefCon)->MixerProc(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); } -OSStatus ALCcoreAudioPlayback::MixerProc(AudioUnitRenderActionFlags* UNUSED(ioActionFlags), +OSStatus CoreAudioPlayback::MixerProc(AudioUnitRenderActionFlags* UNUSED(ioActionFlags), const AudioTimeStamp* UNUSED(inTimeStamp), UInt32 UNUSED(inBusNumber), UInt32 UNUSED(inNumberFrames), AudioBufferList *ioData) { - ALCcoreAudioPlayback_lock(this); + lock(); aluMixData(mDevice, ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize/mFrameSize); - ALCcoreAudioPlayback_unlock(this); + unlock(); return noErr; } -static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name) +ALCenum CoreAudioPlayback::open(const ALCchar *name) { if(!name) name = ca_device; @@ -135,7 +119,7 @@ static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCch return ALC_INVALID_VALUE; } - OSStatus err{AudioComponentInstanceNew(comp, &self->mAudioUnit)}; + OSStatus err{AudioComponentInstanceNew(comp, &mAudioUnit)}; if(err != noErr) { ERR("AudioComponentInstanceNew failed\n"); @@ -143,32 +127,29 @@ static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCch } /* init and start the default audio unit... */ - err = AudioUnitInitialize(self->mAudioUnit); + err = AudioUnitInitialize(mAudioUnit); if(err != noErr) { ERR("AudioUnitInitialize failed\n"); - AudioComponentInstanceDispose(self->mAudioUnit); + AudioComponentInstanceDispose(mAudioUnit); return ALC_INVALID_VALUE; } - ALCdevice *device{self->mDevice}; - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) +ALCboolean CoreAudioPlayback::reset() { - ALCdevice *device{self->mDevice}; - - OSStatus err{AudioUnitUninitialize(self->mAudioUnit)}; + OSStatus err{AudioUnitUninitialize(mAudioUnit)}; if(err != noErr) ERR("-- AudioUnitUninitialize failed.\n"); /* retrieve default output unit's properties (output side) */ AudioStreamBasicDescription streamFormat{}; auto size = static_cast(sizeof(AudioStreamBasicDescription)); - err = AudioUnitGetProperty(self->mAudioUnit, kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Output, 0, &streamFormat, &size); + err = AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, + 0, &streamFormat, &size); if(err != noErr || size != sizeof(AudioStreamBasicDescription)) { ERR("AudioUnitGetProperty failed\n"); @@ -186,19 +167,19 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) #endif /* set default output unit's input side to match output side */ - err = AudioUnitSetProperty(self->mAudioUnit, kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, 0, &streamFormat, size); + err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, + 0, &streamFormat, size); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); return ALC_FALSE; } - if(device->Frequency != streamFormat.mSampleRate) + if(mDevice->Frequency != streamFormat.mSampleRate) { - device->NumUpdates = static_cast( - (ALuint64)device->NumUpdates*streamFormat.mSampleRate/device->Frequency); - device->Frequency = streamFormat.mSampleRate; + mDevice->NumUpdates = static_cast( + (ALuint64)mDevice->NumUpdates*streamFormat.mSampleRate/mDevice->Frequency); + mDevice->Frequency = streamFormat.mSampleRate; } /* FIXME: How to tell what channels are what in the output device, and how @@ -206,53 +187,53 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) switch(streamFormat.mChannelsPerFrame) { case 1: - device->FmtChans = DevFmtMono; + mDevice->FmtChans = DevFmtMono; break; case 2: - device->FmtChans = DevFmtStereo; + mDevice->FmtChans = DevFmtStereo; break; case 4: - device->FmtChans = DevFmtQuad; + mDevice->FmtChans = DevFmtQuad; break; case 6: - device->FmtChans = DevFmtX51; + mDevice->FmtChans = DevFmtX51; break; case 7: - device->FmtChans = DevFmtX61; + mDevice->FmtChans = DevFmtX61; break; case 8: - device->FmtChans = DevFmtX71; + mDevice->FmtChans = DevFmtX71; break; default: ERR("Unhandled channel count (%d), using Stereo\n", streamFormat.mChannelsPerFrame); - device->FmtChans = DevFmtStereo; + mDevice->FmtChans = DevFmtStereo; streamFormat.mChannelsPerFrame = 2; break; } - SetDefaultWFXChannelOrder(device); + SetDefaultWFXChannelOrder(mDevice); /* use channel count and sample rate from the default output unit's current * parameters, but reset everything else */ streamFormat.mFramesPerPacket = 1; streamFormat.mFormatFlags = 0; - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtUByte: - device->FmtType = DevFmtByte; + mDevice->FmtType = DevFmtByte; /* fall-through */ case DevFmtByte: streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; streamFormat.mBitsPerChannel = 8; break; case DevFmtUShort: - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; /* fall-through */ case DevFmtShort: streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; streamFormat.mBitsPerChannel = 16; break; case DevFmtUInt: - device->FmtType = DevFmtInt; + mDevice->FmtType = DevFmtInt; /* fall-through */ case DevFmtInt: streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; @@ -270,8 +251,8 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) streamFormat.mFormatFlags |= kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsPacked; - err = AudioUnitSetProperty(self->mAudioUnit, kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription)); + err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, + 0, &streamFormat, sizeof(AudioStreamBasicDescription)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -279,12 +260,12 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) } /* setup callback */ - self->mFrameSize = device->frameSizeFromFmt(); + mFrameSize = mDevice->frameSizeFromFmt(); AURenderCallbackStruct input{}; - input.inputProc = ALCcoreAudioPlayback::MixerProcC; - input.inputProcRefCon = self; + input.inputProc = CoreAudioPlayback::MixerProcC; + input.inputProcRefCon = this; - err = AudioUnitSetProperty(self->mAudioUnit, kAudioUnitProperty_SetRenderCallback, + err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct)); if(err != noErr) { @@ -293,7 +274,7 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) } /* init the default audio unit... */ - err = AudioUnitInitialize(self->mAudioUnit); + err = AudioUnitInitialize(mAudioUnit); if(err != noErr) { ERR("AudioUnitInitialize failed\n"); @@ -303,9 +284,9 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) return ALC_TRUE; } -static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self) +ALCboolean CoreAudioPlayback::start() { - OSStatus err{AudioOutputUnitStart(self->mAudioUnit)}; + OSStatus err{AudioOutputUnitStart(mAudioUnit)}; if(err != noErr) { ERR("AudioOutputUnitStart failed\n"); @@ -314,17 +295,17 @@ static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self) return ALC_TRUE; } -static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self) +void CoreAudioPlayback::stop() { - OSStatus err{AudioOutputUnitStop(self->mAudioUnit)}; + OSStatus err{AudioOutputUnitStop(mAudioUnit)}; if(err != noErr) ERR("AudioOutputUnitStop failed\n"); } -struct ALCcoreAudioCapture final : public ALCbackend { - ALCcoreAudioCapture(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCcoreAudioCapture() override; +struct CoreAudioCapture final : public BackendBase { + CoreAudioCapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~CoreAudioCapture() override; static OSStatus RecordProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, @@ -333,6 +314,12 @@ struct ALCcoreAudioCapture final : public ALCbackend { const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + AudioUnit mAudioUnit{0}; ALuint mFrameSize{0u}; @@ -341,34 +328,12 @@ struct ALCcoreAudioCapture final : public ALCbackend { SampleConverterPtr mConverter; RingBufferPtr mRing{nullptr}; -}; - -static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device); -static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self); -static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name); -static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ALCboolean, reset) -static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self); -static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self); -static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples); -static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self); -static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioCapture) -DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioCapture); - - -static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device) -{ - new (self) ALCcoreAudioCapture{device}; - SET_VTABLE2(ALCcoreAudioCapture, ALCbackend, self); -} - -static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self) -{ self->~ALCcoreAudioCapture(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "CoreAudioCapture::"; } + DEF_NEWDEL(CoreAudioCapture) +}; -ALCcoreAudioCapture::~ALCcoreAudioCapture() +CoreAudioCapture::~CoreAudioCapture() { if(mAudioUnit) AudioComponentInstanceDispose(mAudioUnit); @@ -376,17 +341,17 @@ ALCcoreAudioCapture::~ALCcoreAudioCapture() } -OSStatus ALCcoreAudioCapture::RecordProcC(void *inRefCon, +OSStatus CoreAudioCapture::RecordProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { - return static_cast(inRefCon)->RecordProc(ioActionFlags, inTimeStamp, + return static_cast(inRefCon)->RecordProc(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); } -OSStatus ALCcoreAudioCapture::RecordProc(AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, - AudioBufferList *ioData) +OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags* UNUSED(ioActionFlags), + const AudioTimeStamp *inTimeStamp, UInt32 UNUSED(inBusNumber), UInt32 inNumberFrames, + AudioBufferList* UNUSED(ioData)) { AudioUnitRenderActionFlags flags = 0; union { @@ -430,9 +395,8 @@ OSStatus ALCcoreAudioCapture::RecordProc(AudioUnitRenderActionFlags *ioActionFla } -static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name) +ALCenum CoreAudioCapture::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; AudioStreamBasicDescription requestedFormat; // The application requested format AudioStreamBasicDescription hardwareFormat; // The hardware format AudioStreamBasicDescription outputFormat; // The AudioUnit output format @@ -469,7 +433,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } // Open the component - err = AudioComponentInstanceNew(comp, &self->mAudioUnit); + err = AudioComponentInstanceNew(comp, &mAudioUnit); if(err != noErr) { ERR("AudioComponentInstanceNew failed\n"); @@ -478,7 +442,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar // Turn off AudioUnit output enableIO = 0; - err = AudioUnitSetProperty(self->mAudioUnit, kAudioOutputUnitProperty_EnableIO, + err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint)); if(err != noErr) { @@ -488,7 +452,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar // Turn on AudioUnit input enableIO = 1; - err = AudioUnitSetProperty(self->mAudioUnit, kAudioOutputUnitProperty_EnableIO, + err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint)); if(err != noErr) { @@ -519,7 +483,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } // Track the input device - err = AudioUnitSetProperty(self->mAudioUnit, kAudioOutputUnitProperty_CurrentDevice, + err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID)); if(err != noErr) { @@ -530,10 +494,10 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar #endif // set capture callback - input.inputProc = ALCcoreAudioCapture::RecordProcC; - input.inputProcRefCon = self; + input.inputProc = CoreAudioCapture::RecordProcC; + input.inputProcRefCon = this; - err = AudioUnitSetProperty(self->mAudioUnit, kAudioOutputUnitProperty_SetInputCallback, + err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct)); if(err != noErr) { @@ -542,7 +506,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } // Initialize the device - err = AudioUnitInitialize(self->mAudioUnit); + err = AudioUnitInitialize(mAudioUnit); if(err != noErr) { ERR("AudioUnitInitialize failed\n"); @@ -551,8 +515,8 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar // Get the hardware format propertySize = sizeof(AudioStreamBasicDescription); - err = AudioUnitGetProperty(self->mAudioUnit, kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize); + err = AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, + 1, &hardwareFormat, &propertySize); if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription)) { ERR("AudioUnitGetProperty failed\n"); @@ -560,7 +524,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } // Set up the requested format description - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtUByte: requestedFormat.mBitsPerChannel = 8; @@ -581,11 +545,11 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar case DevFmtByte: case DevFmtUShort: case DevFmtUInt: - ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); + ERR("%s samples not supported\n", DevFmtTypeString(mDevice->FmtType)); return ALC_INVALID_VALUE; } - switch(device->FmtChans) + switch(mDevice->FmtChans) { case DevFmtMono: requestedFormat.mChannelsPerFrame = 1; @@ -600,20 +564,20 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar case DevFmtX61: case DevFmtX71: case DevFmtAmbi3D: - ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans)); + ERR("%s not supported\n", DevFmtChannelsString(mDevice->FmtChans)); return ALC_INVALID_VALUE; } requestedFormat.mBytesPerFrame = requestedFormat.mChannelsPerFrame * requestedFormat.mBitsPerChannel / 8; requestedFormat.mBytesPerPacket = requestedFormat.mBytesPerFrame; - requestedFormat.mSampleRate = device->Frequency; + requestedFormat.mSampleRate = mDevice->Frequency; requestedFormat.mFormatID = kAudioFormatLinearPCM; requestedFormat.mReserved = 0; requestedFormat.mFramesPerPacket = 1; // save requested format description for later use - self->mFormat = requestedFormat; - self->mFrameSize = device->frameSizeFromFmt(); + mFormat = requestedFormat; + mFrameSize = mDevice->frameSizeFromFmt(); // Use intermediate format for sample rate conversion (outputFormat) // Set sample rate to the same as hardware for resampling later @@ -622,8 +586,8 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar // The output format should be the requested format, but using the hardware sample rate // This is because the AudioUnit will automatically scale other properties, except for sample rate - err = AudioUnitSetProperty(self->mAudioUnit, kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat)); + err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, + 1, (void*)&outputFormat, sizeof(outputFormat)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -631,9 +595,9 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } // Set the AudioUnit output format frame count - ALuint64 FrameCount64{device->UpdateSize}; - FrameCount64 = (FrameCount64*outputFormat.mSampleRate + device->Frequency-1) / - device->Frequency; + ALuint64 FrameCount64{mDevice->UpdateSize}; + FrameCount64 = (FrameCount64*outputFormat.mSampleRate + mDevice->Frequency-1) / + mDevice->Frequency; FrameCount64 += MAX_RESAMPLE_PADDING*2; if(FrameCount64 > std::numeric_limits::max()/2) { @@ -642,7 +606,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } outputFrameCount = static_cast(FrameCount64); - err = AudioUnitSetProperty(self->mAudioUnit, kAudioUnitProperty_MaximumFramesPerSlice, + err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount)); if(err != noErr) { @@ -651,22 +615,22 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar } // Set up sample converter if needed - if(outputFormat.mSampleRate != device->Frequency) - self->mConverter = CreateSampleConverter(device->FmtType, device->FmtType, - self->mFormat.mChannelsPerFrame, hardwareFormat.mSampleRate, device->Frequency, + if(outputFormat.mSampleRate != mDevice->Frequency) + mConverter = CreateSampleConverter(mDevice->FmtType, mDevice->FmtType, + mFormat.mChannelsPerFrame, hardwareFormat.mSampleRate, mDevice->Frequency, BSinc24Resampler); - self->mRing = CreateRingBuffer(outputFrameCount, self->mFrameSize, false); - if(!self->mRing) return ALC_INVALID_VALUE; + mRing = CreateRingBuffer(outputFrameCount, mFrameSize, false); + if(!mRing) return ALC_INVALID_VALUE; - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self) +ALCboolean CoreAudioCapture::start() { - OSStatus err{AudioOutputUnitStart(self->mAudioUnit)}; + OSStatus err{AudioOutputUnitStart(mAudioUnit)}; if(err != noErr) { ERR("AudioOutputUnitStart failed\n"); @@ -675,48 +639,44 @@ static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self) return ALC_TRUE; } -static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self) +void CoreAudioCapture::stop() { - OSStatus err{AudioOutputUnitStop(self->mAudioUnit)}; + OSStatus err{AudioOutputUnitStop(mAudioUnit)}; if(err != noErr) ERR("AudioOutputUnitStop failed\n"); } -static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum CoreAudioCapture::captureSamples(void *buffer, ALCuint samples) { - RingBuffer *ring{self->mRing.get()}; - - if(!self->mConverter) + if(!mConverter) { - ring->read(buffer, samples); + mRing->read(buffer, samples); return ALC_NO_ERROR; } - auto rec_vec = ring->getReadVector(); + auto rec_vec = mRing->getReadVector(); const void *src0{rec_vec.first.buf}; auto src0len = static_cast(rec_vec.first.len); - auto got = static_cast(SampleConverterInput(self->mConverter.get(), &src0, &src0len, + auto got = static_cast(SampleConverterInput(mConverter.get(), &src0, &src0len, buffer, samples)); size_t total_read{rec_vec.first.len - src0len}; if(got < samples && !src0len && rec_vec.second.len > 0) { const void *src1{rec_vec.second.buf}; auto src1len = static_cast(rec_vec.second.len); - got += static_cast(SampleConverterInput(self->mConverter.get(), &src1, &src1len, + got += static_cast(SampleConverterInput(mConverter.get(), &src1, &src1len, static_cast(buffer)+got, samples-got)); total_read += rec_vec.second.len - src1len; } - ring->readAdvance(total_read); + mRing->readAdvance(total_read); return ALC_NO_ERROR; } -static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self) +ALCuint CoreAudioCapture::availableSamples() { - RingBuffer *ring{self->mRing.get()}; - - if(!self->mConverter) return ring->readSpace(); - return SampleConverterAvailableOut(self->mConverter.get(), ring->readSpace()); + if(!mConverter) return mRing->readSpace(); + return SampleConverterAvailableOut(mConverter.get(), mRing->readSpace()); } } // namespace @@ -744,20 +704,11 @@ void CoreAudioBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *CoreAudioBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *CoreAudioBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - ALCcoreAudioPlayback *backend; - NEW_OBJ(backend, ALCcoreAudioPlayback)(device); - return backend; - } + return new CoreAudioPlayback{device}; if(type == ALCbackend_Capture) - { - ALCcoreAudioCapture *backend; - NEW_OBJ(backend, ALCcoreAudioCapture)(device); - return backend; - } - + return new CoreAudioCapture{device}; return nullptr; } diff --git a/Alc/backends/coreaudio.h b/Alc/backends/coreaudio.h index bc9c492c..db151b8a 100644 --- a/Alc/backends/coreaudio.h +++ b/Alc/backends/coreaudio.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 832068ad..44e6fde4 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -184,12 +184,17 @@ BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR* UNUS } -struct ALCdsoundPlayback final : public ALCbackend { - ALCdsoundPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCdsoundPlayback() override; +struct DSoundPlayback final : public BackendBase { + DSoundPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~DSoundPlayback() override; int mixerProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + IDirectSound *mDS{nullptr}; IDirectSoundBuffer *mPrimaryBuffer{nullptr}; IDirectSoundBuffer *mBuffer{nullptr}; @@ -198,34 +203,12 @@ struct ALCdsoundPlayback final : public ALCbackend { std::atomic mKillNow{AL_TRUE}; std::thread mThread; -}; - -void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device); -void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self); -ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *name); -ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self); -ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self); -void ALCdsoundPlayback_stop(ALCdsoundPlayback *self); -DECLARE_FORWARD2(ALCdsoundPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, lock) -DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCdsoundPlayback) - -DEFINE_ALCBACKEND_VTABLE(ALCdsoundPlayback); - -void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device) -{ - new (self) ALCdsoundPlayback{device}; - SET_VTABLE2(ALCdsoundPlayback, ALCbackend, self); -} - -void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self) -{ self->~ALCdsoundPlayback(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "DSoundPlayback::"; } + DEF_NEWDEL(DSoundPlayback) +}; -ALCdsoundPlayback::~ALCdsoundPlayback() +DSoundPlayback::~DSoundPlayback() { if(mNotifies) mNotifies->Release(); @@ -246,7 +229,7 @@ ALCdsoundPlayback::~ALCdsoundPlayback() } -FORCE_ALIGN int ALCdsoundPlayback::mixerProc() +FORCE_ALIGN int DSoundPlayback::mixerProc() { SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); @@ -257,9 +240,9 @@ FORCE_ALIGN int ALCdsoundPlayback::mixerProc() if(FAILED(err)) { ERR("Failed to get buffer caps: 0x%lx\n", err); - ALCdsoundPlayback_lock(this); + lock(); aluHandleDisconnect(mDevice, "Failure retrieving playback buffer info: 0x%lx", err); - ALCdsoundPlayback_unlock(this); + unlock(); return 1; } @@ -285,9 +268,9 @@ FORCE_ALIGN int ALCdsoundPlayback::mixerProc() if(FAILED(err)) { ERR("Failed to play buffer: 0x%lx\n", err); - ALCdsoundPlayback_lock(this); + lock(); aluHandleDisconnect(mDevice, "Failure starting playback: 0x%lx", err); - ALCdsoundPlayback_unlock(this); + unlock(); return 1; } Playing = true; @@ -319,25 +302,22 @@ FORCE_ALIGN int ALCdsoundPlayback::mixerProc() } } - // Successfully locked the output buffer if(SUCCEEDED(err)) { - // If we have an active context, mix data directly into output buffer otherwise fill with silence - ALCdsoundPlayback_lock(this); + lock(); aluMixData(mDevice, WritePtr1, WriteCnt1/FrameSize); if(WriteCnt2 > 0) aluMixData(mDevice, WritePtr2, WriteCnt2/FrameSize); - ALCdsoundPlayback_unlock(this); + unlock(); - // Unlock output buffer only when successfully locked mBuffer->Unlock(WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); } else { ERR("Buffer lock error: %#lx\n", err); - ALCdsoundPlayback_lock(this); + lock(); aluHandleDisconnect(mDevice, "Failed to lock output buffer: 0x%lx", err); - ALCdsoundPlayback_unlock(this); + unlock(); return 1; } @@ -349,10 +329,8 @@ FORCE_ALIGN int ALCdsoundPlayback::mixerProc() return 0; } -ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *deviceName) +ALCenum DSoundPlayback::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - HRESULT hr; if(PlaybackDevices.empty()) { @@ -366,16 +344,16 @@ ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *deviceNam } const GUID *guid{nullptr}; - if(!deviceName && !PlaybackDevices.empty()) + if(!name && !PlaybackDevices.empty()) { - deviceName = PlaybackDevices[0].name.c_str(); + name = PlaybackDevices[0].name.c_str(); guid = &PlaybackDevices[0].guid; } else { auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), - [deviceName](const DevMap &entry) -> bool - { return entry.name == deviceName; } + [name](const DevMap &entry) -> bool + { return entry.name == name; } ); if(iter == PlaybackDevices.cend()) return ALC_INVALID_VALUE; @@ -383,52 +361,50 @@ ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *deviceNam } hr = DS_OK; - self->mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - if(!self->mNotifyEvent) hr = E_FAIL; + mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + if(!mNotifyEvent) hr = E_FAIL; //DirectSound Init code if(SUCCEEDED(hr)) - hr = DirectSoundCreate(guid, &self->mDS, nullptr); + hr = DirectSoundCreate(guid, &mDS, nullptr); if(SUCCEEDED(hr)) - hr = self->mDS->SetCooperativeLevel(GetForegroundWindow(), DSSCL_PRIORITY); + hr = mDS->SetCooperativeLevel(GetForegroundWindow(), DSSCL_PRIORITY); if(FAILED(hr)) { ERR("Device init failed: 0x%08lx\n", hr); return ALC_INVALID_VALUE; } - device->DeviceName = deviceName; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) +ALCboolean DSoundPlayback::reset() { - ALCdevice *device{self->mDevice}; - - if(self->mNotifies) - self->mNotifies->Release(); - self->mNotifies = nullptr; - if(self->mBuffer) - self->mBuffer->Release(); - self->mBuffer = nullptr; - if(self->mPrimaryBuffer) - self->mPrimaryBuffer->Release(); - self->mPrimaryBuffer = nullptr; + if(mNotifies) + mNotifies->Release(); + mNotifies = nullptr; + if(mBuffer) + mBuffer->Release(); + mBuffer = nullptr; + if(mPrimaryBuffer) + mPrimaryBuffer->Release(); + mPrimaryBuffer = nullptr; - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: - device->FmtType = DevFmtUByte; + mDevice->FmtType = DevFmtUByte; break; case DevFmtFloat: - if((device->Flags&DEVICE_SAMPLE_TYPE_REQUEST)) + if((mDevice->Flags&DEVICE_SAMPLE_TYPE_REQUEST)) break; /* fall-through */ case DevFmtUShort: - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; break; case DevFmtUInt: - device->FmtType = DevFmtInt; + mDevice->FmtType = DevFmtInt; break; case DevFmtUByte: case DevFmtShort: @@ -438,37 +414,37 @@ ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) WAVEFORMATEXTENSIBLE OutputType{}; DWORD speakers; - HRESULT hr{self->mDS->GetSpeakerConfig(&speakers)}; + HRESULT hr{mDS->GetSpeakerConfig(&speakers)}; if(SUCCEEDED(hr)) { speakers = DSSPEAKER_CONFIG(speakers); - if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) + if(!(mDevice->Flags&DEVICE_CHANNELS_REQUEST)) { if(speakers == DSSPEAKER_MONO) - device->FmtChans = DevFmtMono; + mDevice->FmtChans = DevFmtMono; else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE) - device->FmtChans = DevFmtStereo; + mDevice->FmtChans = DevFmtStereo; else if(speakers == DSSPEAKER_QUAD) - device->FmtChans = DevFmtQuad; + mDevice->FmtChans = DevFmtQuad; else if(speakers == DSSPEAKER_5POINT1_SURROUND) - device->FmtChans = DevFmtX51; + mDevice->FmtChans = DevFmtX51; else if(speakers == DSSPEAKER_5POINT1_BACK) - device->FmtChans = DevFmtX51Rear; + mDevice->FmtChans = DevFmtX51Rear; else if(speakers == DSSPEAKER_7POINT1 || speakers == DSSPEAKER_7POINT1_SURROUND) - device->FmtChans = DevFmtX71; + mDevice->FmtChans = DevFmtX71; else ERR("Unknown system speaker config: 0x%lx\n", speakers); } - device->IsHeadphones = (device->FmtChans == DevFmtStereo && - speakers == DSSPEAKER_HEADPHONE); + mDevice->IsHeadphones = (mDevice->FmtChans == DevFmtStereo && + speakers == DSSPEAKER_HEADPHONE); - switch(device->FmtChans) + switch(mDevice->FmtChans) { case DevFmtMono: OutputType.dwChannelMask = SPEAKER_FRONT_CENTER; break; case DevFmtAmbi3D: - device->FmtChans = DevFmtStereo; + mDevice->FmtChans = DevFmtStereo; /*fall-through*/ case DevFmtStereo: OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | @@ -520,62 +496,62 @@ ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) retry_open: hr = S_OK; OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; - OutputType.Format.nChannels = device->channelsFromFmt(); - OutputType.Format.wBitsPerSample = device->bytesFromFmt() * 8; + OutputType.Format.nChannels = mDevice->channelsFromFmt(); + OutputType.Format.wBitsPerSample = mDevice->bytesFromFmt() * 8; OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8; - OutputType.Format.nSamplesPerSec = device->Frequency; + OutputType.Format.nSamplesPerSec = mDevice->Frequency; OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign; OutputType.Format.cbSize = 0; } - if(OutputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat) + if(OutputType.Format.nChannels > 2 || mDevice->FmtType == DevFmtFloat) { OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; OutputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); - if(device->FmtType == DevFmtFloat) + if(mDevice->FmtType == DevFmtFloat) OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; else OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - if(self->mPrimaryBuffer) - self->mPrimaryBuffer->Release(); - self->mPrimaryBuffer = nullptr; + if(mPrimaryBuffer) + mPrimaryBuffer->Release(); + mPrimaryBuffer = nullptr; } else { - if(SUCCEEDED(hr) && !self->mPrimaryBuffer) + if(SUCCEEDED(hr) && !mPrimaryBuffer) { DSBUFFERDESC DSBDescription{}; DSBDescription.dwSize = sizeof(DSBDescription); DSBDescription.dwFlags = DSBCAPS_PRIMARYBUFFER; - hr = self->mDS->CreateSoundBuffer(&DSBDescription, &self->mPrimaryBuffer, nullptr); + hr = mDS->CreateSoundBuffer(&DSBDescription, &mPrimaryBuffer, nullptr); } if(SUCCEEDED(hr)) - hr = self->mPrimaryBuffer->SetFormat(&OutputType.Format); + hr = mPrimaryBuffer->SetFormat(&OutputType.Format); } if(SUCCEEDED(hr)) { - if(device->NumUpdates > MAX_UPDATES) + if(mDevice->NumUpdates > MAX_UPDATES) { - device->UpdateSize = (device->UpdateSize*device->NumUpdates + - MAX_UPDATES-1) / MAX_UPDATES; - device->NumUpdates = MAX_UPDATES; + mDevice->UpdateSize = (mDevice->UpdateSize*mDevice->NumUpdates + MAX_UPDATES-1) / + MAX_UPDATES; + mDevice->NumUpdates = MAX_UPDATES; } DSBUFFERDESC DSBDescription{}; DSBDescription.dwSize = sizeof(DSBDescription); DSBDescription.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS; - DSBDescription.dwBufferBytes = device->UpdateSize * device->NumUpdates * + DSBDescription.dwBufferBytes = mDevice->UpdateSize * mDevice->NumUpdates * OutputType.Format.nBlockAlign; DSBDescription.lpwfxFormat = &OutputType.Format; - hr = self->mDS->CreateSoundBuffer(&DSBDescription, &self->mBuffer, nullptr); - if(FAILED(hr) && device->FmtType == DevFmtFloat) + hr = mDS->CreateSoundBuffer(&DSBDescription, &mBuffer, nullptr); + if(FAILED(hr) && mDevice->FmtType == DevFmtFloat) { - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; goto retry_open; } } @@ -583,50 +559,50 @@ retry_open: if(SUCCEEDED(hr)) { void *ptr; - hr = self->mBuffer->QueryInterface(IID_IDirectSoundNotify, &ptr); + hr = mBuffer->QueryInterface(IID_IDirectSoundNotify, &ptr); if(SUCCEEDED(hr)) { auto Notifies = static_cast(ptr); - self->mNotifies = Notifies; + mNotifies = Notifies; - device->NumUpdates = minu(device->NumUpdates, MAX_UPDATES); + mDevice->NumUpdates = minu(mDevice->NumUpdates, MAX_UPDATES); std::array nots; - for(ALuint i{0};i < device->NumUpdates;++i) + for(ALuint i{0};i < mDevice->NumUpdates;++i) { - nots[i].dwOffset = i * device->UpdateSize * OutputType.Format.nBlockAlign; - nots[i].hEventNotify = self->mNotifyEvent; + nots[i].dwOffset = i * mDevice->UpdateSize * OutputType.Format.nBlockAlign; + nots[i].hEventNotify = mNotifyEvent; } - if(Notifies->SetNotificationPositions(device->NumUpdates, nots.data()) != DS_OK) + if(Notifies->SetNotificationPositions(mDevice->NumUpdates, nots.data()) != DS_OK) hr = E_FAIL; } } if(FAILED(hr)) { - if(self->mNotifies) - self->mNotifies->Release(); - self->mNotifies = nullptr; - if(self->mBuffer) - self->mBuffer->Release(); - self->mBuffer = nullptr; - if(self->mPrimaryBuffer) - self->mPrimaryBuffer->Release(); - self->mPrimaryBuffer = nullptr; + if(mNotifies) + mNotifies->Release(); + mNotifies = nullptr; + if(mBuffer) + mBuffer->Release(); + mBuffer = nullptr; + if(mPrimaryBuffer) + mPrimaryBuffer->Release(); + mPrimaryBuffer = nullptr; return ALC_FALSE; } - ResetEvent(self->mNotifyEvent); - SetDefaultWFXChannelOrder(device); + ResetEvent(mNotifyEvent); + SetDefaultWFXChannelOrder(mDevice); return ALC_TRUE; } -ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self) +ALCboolean DSoundPlayback::start() { try { - self->mKillNow.store(AL_FALSE, std::memory_order_release); - self->mThread = std::thread(std::mem_fn(&ALCdsoundPlayback::mixerProc), self); + mKillNow.store(AL_FALSE, std::memory_order_release); + mThread = std::thread{std::mem_fn(&DSoundPlayback::mixerProc), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -637,20 +613,25 @@ ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self) return ALC_FALSE; } -void ALCdsoundPlayback_stop(ALCdsoundPlayback *self) +void DSoundPlayback::stop() { - if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->mThread.joinable()) + if(mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !mThread.joinable()) return; + mThread.join(); - self->mThread.join(); - - self->mBuffer->Stop(); + mBuffer->Stop(); } -struct ALCdsoundCapture final : public ALCbackend { - ALCdsoundCapture(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCdsoundCapture() override; +struct DSoundCapture final : public BackendBase { + DSoundCapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~DSoundCapture() override; + + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; IDirectSoundCapture *mDSC{nullptr}; IDirectSoundCaptureBuffer *mDSCbuffer{nullptr}; @@ -658,32 +639,12 @@ struct ALCdsoundCapture final : public ALCbackend { DWORD mCursor{0u}; RingBufferPtr mRing; -}; - -void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device); -void ALCdsoundCapture_Destruct(ALCdsoundCapture *self); -ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *name); -DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, ALCboolean, reset) -ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self); -void ALCdsoundCapture_stop(ALCdsoundCapture *self); -ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint samples); -ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self); -DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, void, lock) -DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCdsoundCapture) -DEFINE_ALCBACKEND_VTABLE(ALCdsoundCapture); - -void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device) -{ - new (self) ALCdsoundCapture{device}; - SET_VTABLE2(ALCdsoundCapture, ALCbackend, self); -} -void ALCdsoundCapture_Destruct(ALCdsoundCapture *self) -{ self->~ALCdsoundCapture(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "DSoundCapture::"; } + DEF_NEWDEL(DSoundCapture) +}; -ALCdsoundCapture::~ALCdsoundCapture() +DSoundCapture::~DSoundCapture() { if(mDSCbuffer) { @@ -698,10 +659,8 @@ ALCdsoundCapture::~ALCdsoundCapture() } -ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) +ALCenum DSoundCapture::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - HRESULT hr; if(CaptureDevices.empty()) { @@ -715,28 +674,28 @@ ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) } const GUID *guid{nullptr}; - if(!deviceName && !CaptureDevices.empty()) + if(!name && !CaptureDevices.empty()) { - deviceName = CaptureDevices[0].name.c_str(); + name = CaptureDevices[0].name.c_str(); guid = &CaptureDevices[0].guid; } else { auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), - [deviceName](const DevMap &entry) -> bool - { return entry.name == deviceName; } + [name](const DevMap &entry) -> bool + { return entry.name == name; } ); if(iter == CaptureDevices.cend()) return ALC_INVALID_VALUE; guid = &iter->guid; } - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: case DevFmtUShort: case DevFmtUInt: - WARN("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); + WARN("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); return ALC_INVALID_ENUM; case DevFmtUByte: @@ -747,7 +706,7 @@ ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) } WAVEFORMATEXTENSIBLE InputType{}; - switch(device->FmtChans) + switch(mDevice->FmtChans) { case DevFmtMono: InputType.dwChannelMask = SPEAKER_FRONT_CENTER; @@ -798,31 +757,31 @@ ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) SPEAKER_SIDE_RIGHT; break; case DevFmtAmbi3D: - WARN("%s capture not supported\n", DevFmtChannelsString(device->FmtChans)); + WARN("%s capture not supported\n", DevFmtChannelsString(mDevice->FmtChans)); return ALC_INVALID_ENUM; } InputType.Format.wFormatTag = WAVE_FORMAT_PCM; - InputType.Format.nChannels = device->channelsFromFmt(); - InputType.Format.wBitsPerSample = device->bytesFromFmt() * 8; + InputType.Format.nChannels = mDevice->channelsFromFmt(); + InputType.Format.wBitsPerSample = mDevice->bytesFromFmt() * 8; InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8; - InputType.Format.nSamplesPerSec = device->Frequency; + InputType.Format.nSamplesPerSec = mDevice->Frequency; InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign; InputType.Format.cbSize = 0; InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample; - if(device->FmtType == DevFmtFloat) + if(mDevice->FmtType == DevFmtFloat) InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; else InputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - if(InputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat) + if(InputType.Format.nChannels > 2 || mDevice->FmtType == DevFmtFloat) { InputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); } - ALuint samples{device->UpdateSize * device->NumUpdates}; - samples = maxu(samples, 100 * device->Frequency / 1000); + ALuint samples{mDevice->UpdateSize * mDevice->NumUpdates}; + samples = maxu(samples, 100 * mDevice->Frequency / 1000); DSCBUFFERDESC DSCBDescription{}; DSCBDescription.dwSize = sizeof(DSCBDescription); @@ -831,107 +790,101 @@ ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) DSCBDescription.lpwfxFormat = &InputType.Format; //DirectSoundCapture Init code - hr = DirectSoundCaptureCreate(guid, &self->mDSC, nullptr); + hr = DirectSoundCaptureCreate(guid, &mDSC, nullptr); if(SUCCEEDED(hr)) - self->mDSC->CreateCaptureBuffer(&DSCBDescription, &self->mDSCbuffer, nullptr); + mDSC->CreateCaptureBuffer(&DSCBDescription, &mDSCbuffer, nullptr); if(SUCCEEDED(hr)) { - self->mRing = CreateRingBuffer(device->UpdateSize*device->NumUpdates, + mRing = CreateRingBuffer(mDevice->UpdateSize*mDevice->NumUpdates, InputType.Format.nBlockAlign, false); - if(!self->mRing) hr = DSERR_OUTOFMEMORY; + if(!mRing) hr = DSERR_OUTOFMEMORY; } if(FAILED(hr)) { ERR("Device init failed: 0x%08lx\n", hr); - self->mRing = nullptr; - if(self->mDSCbuffer) - self->mDSCbuffer->Release(); - self->mDSCbuffer = nullptr; - if(self->mDSC) - self->mDSC->Release(); - self->mDSC = nullptr; + mRing = nullptr; + if(mDSCbuffer) + mDSCbuffer->Release(); + mDSCbuffer = nullptr; + if(mDSC) + mDSC->Release(); + mDSC = nullptr; return ALC_INVALID_VALUE; } - self->mBufferBytes = DSCBDescription.dwBufferBytes; - SetDefaultWFXChannelOrder(device); + mBufferBytes = DSCBDescription.dwBufferBytes; + SetDefaultWFXChannelOrder(mDevice); - device->DeviceName = deviceName; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self) +ALCboolean DSoundCapture::start() { - HRESULT hr{self->mDSCbuffer->Start(DSCBSTART_LOOPING)}; + HRESULT hr{mDSCbuffer->Start(DSCBSTART_LOOPING)}; if(FAILED(hr)) { ERR("start failed: 0x%08lx\n", hr); - aluHandleDisconnect(self->mDevice, "Failure starting capture: 0x%lx", hr); + aluHandleDisconnect(mDevice, "Failure starting capture: 0x%lx", hr); return ALC_FALSE; } - return ALC_TRUE; } -void ALCdsoundCapture_stop(ALCdsoundCapture *self) +void DSoundCapture::stop() { - HRESULT hr{self->mDSCbuffer->Stop()}; + HRESULT hr{mDSCbuffer->Stop()}; if(FAILED(hr)) { ERR("stop failed: 0x%08lx\n", hr); - aluHandleDisconnect(self->mDevice, "Failure stopping capture: 0x%lx", hr); + aluHandleDisconnect(mDevice, "Failure stopping capture: 0x%lx", hr); } } -ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum DSoundCapture::captureSamples(void *buffer, ALCuint samples) { - RingBuffer *ring{self->mRing.get()}; - ring->read(buffer, samples); + mRing->read(buffer, samples); return ALC_NO_ERROR; } -ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) +ALCuint DSoundCapture::availableSamples() { - ALCdevice *device{self->mDevice}; - RingBuffer *ring{self->mRing.get()}; - - if(!device->Connected.load(std::memory_order_acquire)) - return static_cast(ring->readSpace()); + if(!mDevice->Connected.load(std::memory_order_acquire)) + return static_cast(mRing->readSpace()); - ALsizei FrameSize{device->frameSizeFromFmt()}; - DWORD BufferBytes{self->mBufferBytes}; - DWORD LastCursor{self->mCursor}; + ALsizei FrameSize{mDevice->frameSizeFromFmt()}; + DWORD BufferBytes{mBufferBytes}; + DWORD LastCursor{mCursor}; DWORD ReadCursor; void *ReadPtr1, *ReadPtr2; DWORD ReadCnt1, ReadCnt2; - HRESULT hr{self->mDSCbuffer->GetCurrentPosition(nullptr, &ReadCursor)}; + HRESULT hr{mDSCbuffer->GetCurrentPosition(nullptr, &ReadCursor)}; if(SUCCEEDED(hr)) { DWORD NumBytes{(ReadCursor-LastCursor + BufferBytes) % BufferBytes}; - if(!NumBytes) return static_cast(ring->readSpace()); - hr = self->mDSCbuffer->Lock(LastCursor, NumBytes, &ReadPtr1, &ReadCnt1, - &ReadPtr2, &ReadCnt2, 0); + if(!NumBytes) return static_cast(mRing->readSpace()); + hr = mDSCbuffer->Lock(LastCursor, NumBytes, &ReadPtr1, &ReadCnt1, &ReadPtr2, &ReadCnt2, 0); } if(SUCCEEDED(hr)) { - ring->write(ReadPtr1, ReadCnt1/FrameSize); + mRing->write(ReadPtr1, ReadCnt1/FrameSize); if(ReadPtr2 != nullptr && ReadCnt2 > 0) - ring->write(ReadPtr2, ReadCnt2/FrameSize); - hr = self->mDSCbuffer->Unlock(ReadPtr1, ReadCnt1, ReadPtr2, ReadCnt2); - self->mCursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes; + mRing->write(ReadPtr2, ReadCnt2/FrameSize); + hr = mDSCbuffer->Unlock(ReadPtr1, ReadCnt1, ReadPtr2, ReadCnt2); + mCursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes; } if(FAILED(hr)) { ERR("update failed: 0x%08lx\n", hr); - aluHandleDisconnect(device, "Failure retrieving capture data: 0x%lx", hr); + aluHandleDisconnect(mDevice, "Failure retrieving capture data: 0x%lx", hr); } - return static_cast(ring->readSpace()); + return static_cast(mRing->readSpace()); } } // namespace @@ -996,21 +949,11 @@ void DSoundBackendFactory::probe(DevProbe type, std::string *outnames) CoUninitialize(); } -ALCbackend *DSoundBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *DSoundBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - ALCdsoundPlayback *backend; - NEW_OBJ(backend, ALCdsoundPlayback)(device); - return backend; - } - + return new DSoundPlayback{device}; if(type == ALCbackend_Capture) - { - ALCdsoundCapture *backend; - NEW_OBJ(backend, ALCdsoundCapture)(device); - return backend; - } - + return new DSoundCapture{device}; return nullptr; } diff --git a/Alc/backends/dsound.h b/Alc/backends/dsound.h index 3911686e..93b76c7c 100644 --- a/Alc/backends/dsound.h +++ b/Alc/backends/dsound.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index 26086bf9..77bbf487 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -148,9 +148,9 @@ ALCboolean jack_load(void) } -struct ALCjackPlayback final : public ALCbackend { - ALCjackPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCjackPlayback() override; +struct JackPlayback final : public BackendBase { + JackPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~JackPlayback() override; static int bufferSizeNotifyC(jack_nframes_t numframes, void *arg); int bufferSizeNotify(jack_nframes_t numframes); @@ -160,6 +160,12 @@ struct ALCjackPlayback final : public ALCbackend { int mixerProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + ClockLatency getClockLatency() override; + jack_client_t *mClient{nullptr}; jack_port_t *mPort[MAX_OUTPUT_CHANNELS]{}; @@ -168,34 +174,12 @@ struct ALCjackPlayback final : public ALCbackend { std::atomic mKillNow{true}; std::thread mThread; -}; - -void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device); -void ALCjackPlayback_Destruct(ALCjackPlayback *self); -ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name); -ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self); -ALCboolean ALCjackPlayback_start(ALCjackPlayback *self); -void ALCjackPlayback_stop(ALCjackPlayback *self); -DECLARE_FORWARD2(ALCjackPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -DECLARE_FORWARD(ALCjackPlayback, ALCbackend, ALCuint, availableSamples) -ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self); -DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, lock) -DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCjackPlayback) - -DEFINE_ALCBACKEND_VTABLE(ALCjackPlayback); + static constexpr inline const char *CurrentPrefix() noexcept { return "JackPlayback::"; } + DEF_NEWDEL(JackPlayback) +}; -void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device) -{ - new (self) ALCjackPlayback{device}; - SET_VTABLE2(ALCjackPlayback, ALCbackend, self); -} - -void ALCjackPlayback_Destruct(ALCjackPlayback *self) -{ self->~ALCjackPlayback(); } - -ALCjackPlayback::~ALCjackPlayback() +JackPlayback::~JackPlayback() { if(!mClient) return; @@ -210,12 +194,12 @@ ALCjackPlayback::~ALCjackPlayback() } -int ALCjackPlayback::bufferSizeNotifyC(jack_nframes_t numframes, void *arg) -{ return static_cast(arg)->bufferSizeNotify(numframes); } +int JackPlayback::bufferSizeNotifyC(jack_nframes_t numframes, void *arg) +{ return static_cast(arg)->bufferSizeNotify(numframes); } -int ALCjackPlayback::bufferSizeNotify(jack_nframes_t numframes) +int JackPlayback::bufferSizeNotify(jack_nframes_t numframes) { - ALCjackPlayback_lock(this); + lock(); mDevice->UpdateSize = numframes; mDevice->NumUpdates = 2; @@ -233,15 +217,15 @@ int ALCjackPlayback::bufferSizeNotify(jack_nframes_t numframes) ERR("Failed to reallocate ringbuffer\n"); aluHandleDisconnect(mDevice, "Failed to reallocate %u-sample buffer", bufsize); } - ALCjackPlayback_unlock(this); + unlock(); return 0; } -int ALCjackPlayback::processC(jack_nframes_t numframes, void *arg) -{ return static_cast(arg)->process(numframes); } +int JackPlayback::processC(jack_nframes_t numframes, void *arg) +{ return static_cast(arg)->process(numframes); } -int ALCjackPlayback::process(jack_nframes_t numframes) +int JackPlayback::process(jack_nframes_t numframes) { jack_default_audio_sample_t *out[MAX_OUTPUT_CHANNELS]; ALsizei numchans{0}; @@ -311,20 +295,20 @@ int ALCjackPlayback::process(jack_nframes_t numframes) return 0; } -int ALCjackPlayback::mixerProc() +int JackPlayback::mixerProc() { SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - ALCjackPlayback_lock(this); + lock(); while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) { if(mRing->writeSpace() < mDevice->UpdateSize) { - ALCjackPlayback_unlock(this); + unlock(); mSem.wait(); - ALCjackPlayback_lock(this); + lock(); continue; } @@ -340,13 +324,13 @@ int ALCjackPlayback::mixerProc() aluMixData(mDevice, data.second.buf, len2); mRing->writeAdvance(todo); } - ALCjackPlayback_unlock(this); + unlock(); return 0; } -ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name) +ALCenum JackPlayback::open(const ALCchar *name) { if(!name) name = jackDevice; @@ -355,8 +339,8 @@ ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name) const char *client_name{"alsoft"}; jack_status_t status; - self->mClient = jack_client_open(client_name, ClientOptions, &status, nullptr); - if(self->mClient == nullptr) + mClient = jack_client_open(client_name, ClientOptions, &status, nullptr); + if(mClient == nullptr) { ERR("jack_client_open() failed, status = 0x%02x\n", status); return ALC_INVALID_VALUE; @@ -365,104 +349,102 @@ ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name) TRACE("JACK server started\n"); if((status&JackNameNotUnique)) { - client_name = jack_get_client_name(self->mClient); + client_name = jack_get_client_name(mClient); TRACE("Client name not unique, got `%s' instead\n", client_name); } - jack_set_process_callback(self->mClient, &ALCjackPlayback::processC, self); - jack_set_buffer_size_callback(self->mClient, &ALCjackPlayback::bufferSizeNotifyC, self); + jack_set_process_callback(mClient, &JackPlayback::processC, this); + jack_set_buffer_size_callback(mClient, &JackPlayback::bufferSizeNotifyC, this); - ALCdevice *device{self->mDevice}; - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) +ALCboolean JackPlayback::reset() { - std::for_each(std::begin(self->mPort), std::end(self->mPort), - [self](jack_port_t *port) -> void - { if(port) jack_port_unregister(self->mClient, port); } + std::for_each(std::begin(mPort), std::end(mPort), + [this](jack_port_t *port) -> void + { if(port) jack_port_unregister(mClient, port); } ); - std::fill(std::begin(self->mPort), std::end(self->mPort), nullptr); + std::fill(std::begin(mPort), std::end(mPort), nullptr); /* Ignore the requested buffer metrics and just keep one JACK-sized buffer * ready for when requested. */ - ALCdevice *device{self->mDevice}; - device->Frequency = jack_get_sample_rate(self->mClient); - device->UpdateSize = jack_get_buffer_size(self->mClient); - device->NumUpdates = 2; + mDevice->Frequency = jack_get_sample_rate(mClient); + mDevice->UpdateSize = jack_get_buffer_size(mClient); + mDevice->NumUpdates = 2; - ALuint bufsize{device->UpdateSize}; - if(ConfigValueUInt(device->DeviceName.c_str(), "jack", "buffer-size", &bufsize)) - bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); - device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize; + ALuint bufsize{mDevice->UpdateSize}; + if(ConfigValueUInt(mDevice->DeviceName.c_str(), "jack", "buffer-size", &bufsize)) + bufsize = maxu(NextPowerOf2(bufsize), mDevice->UpdateSize); + mDevice->NumUpdates = (bufsize+mDevice->UpdateSize) / mDevice->UpdateSize; /* Force 32-bit float output. */ - device->FmtType = DevFmtFloat; + mDevice->FmtType = DevFmtFloat; - ALsizei numchans{device->channelsFromFmt()}; - auto ports_end = std::begin(self->mPort) + numchans; - auto bad_port = std::find_if_not(std::begin(self->mPort), ports_end, - [self](jack_port_t *&port) -> bool + ALsizei numchans{mDevice->channelsFromFmt()}; + auto ports_end = std::begin(mPort) + numchans; + auto bad_port = std::find_if_not(std::begin(mPort), ports_end, + [this](jack_port_t *&port) -> bool { - std::string name{"channel_" + std::to_string(&port - self->mPort + 1)}; - port = jack_port_register(self->mClient, name.c_str(), JACK_DEFAULT_AUDIO_TYPE, + std::string name{"channel_" + std::to_string(&port - mPort + 1)}; + port = jack_port_register(mClient, name.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); return port != nullptr; } ); if(bad_port != ports_end) { - ERR("Not enough JACK ports available for %s output\n", DevFmtChannelsString(device->FmtChans)); - if(bad_port == std::begin(self->mPort)) return ALC_FALSE; + ERR("Not enough JACK ports available for %s output\n", DevFmtChannelsString(mDevice->FmtChans)); + if(bad_port == std::begin(mPort)) return ALC_FALSE; - if(bad_port == std::begin(self->mPort)+1) - device->FmtChans = DevFmtMono; + if(bad_port == std::begin(mPort)+1) + mDevice->FmtChans = DevFmtMono; else { - ports_end = self->mPort+2; + ports_end = mPort+2; while(bad_port != ports_end) { - jack_port_unregister(self->mClient, *(--bad_port)); + jack_port_unregister(mClient, *(--bad_port)); *bad_port = nullptr; } - device->FmtChans = DevFmtStereo; + mDevice->FmtChans = DevFmtStereo; } - numchans = std::distance(std::begin(self->mPort), bad_port); + numchans = std::distance(std::begin(mPort), bad_port); } - self->mRing = nullptr; - self->mRing = CreateRingBuffer(bufsize, device->frameSizeFromFmt(), true); - if(!self->mRing) + mRing = nullptr; + mRing = CreateRingBuffer(bufsize, mDevice->frameSizeFromFmt(), true); + if(!mRing) { ERR("Failed to allocate ringbuffer\n"); return ALC_FALSE; } - SetDefaultChannelOrder(device); + SetDefaultChannelOrder(mDevice); return ALC_TRUE; } -ALCboolean ALCjackPlayback_start(ALCjackPlayback *self) +ALCboolean JackPlayback::start() { - if(jack_activate(self->mClient)) + if(jack_activate(mClient)) { ERR("Failed to activate client\n"); return ALC_FALSE; } - const char **ports{jack_get_ports(self->mClient, nullptr, nullptr, + const char **ports{jack_get_ports(mClient, nullptr, nullptr, JackPortIsPhysical|JackPortIsInput)}; if(ports == nullptr) { ERR("No physical playback ports found\n"); - jack_deactivate(self->mClient); + jack_deactivate(mClient); return ALC_FALSE; } - std::mismatch(std::begin(self->mPort), std::end(self->mPort), ports, - [self](const jack_port_t *port, const char *pname) -> bool + std::mismatch(std::begin(mPort), std::end(mPort), ports, + [this](const jack_port_t *port, const char *pname) -> bool { if(!port) return false; if(!pname) @@ -470,7 +452,7 @@ ALCboolean ALCjackPlayback_start(ALCjackPlayback *self) ERR("No physical playback port for \"%s\"\n", jack_port_name(port)); return false; } - if(jack_connect(self->mClient, jack_port_name(port), pname)) + if(jack_connect(mClient, jack_port_name(port), pname)) ERR("Failed to connect output port \"%s\" to \"%s\"\n", jack_port_name(port), pname); return true; @@ -479,8 +461,8 @@ ALCboolean ALCjackPlayback_start(ALCjackPlayback *self) jack_free(ports); try { - self->mKillNow.store(false, std::memory_order_release); - self->mThread = std::thread(std::mem_fn(&ALCjackPlayback::mixerProc), self); + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&JackPlayback::mixerProc), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -488,33 +470,31 @@ ALCboolean ALCjackPlayback_start(ALCjackPlayback *self) } catch(...) { } - jack_deactivate(self->mClient); + jack_deactivate(mClient); return ALC_FALSE; } -void ALCjackPlayback_stop(ALCjackPlayback *self) +void JackPlayback::stop() { - if(self->mKillNow.exchange(true, std::memory_order_acq_rel) || !self->mThread.joinable()) + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) return; - self->mSem.post(); - self->mThread.join(); + mSem.post(); + mThread.join(); - jack_deactivate(self->mClient); + jack_deactivate(mClient); } -ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self) +ClockLatency JackPlayback::getClockLatency() { ClockLatency ret; - ALCjackPlayback_lock(self); - ALCdevice *device{self->mDevice}; - RingBuffer *ring{self->mRing.get()}; - ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = std::chrono::seconds{ring->readSpace()}; - ret.Latency /= device->Frequency; - ALCjackPlayback_unlock(self); + lock(); + ret.ClockTime = GetDeviceClockTime(mDevice); + ret.Latency = std::chrono::seconds{mRing->readSpace()}; + ret.Latency /= mDevice->Frequency; + unlock(); return ret; } @@ -578,15 +558,10 @@ void JackBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *JackBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *JackBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - ALCjackPlayback *backend; - NEW_OBJ(backend, ALCjackPlayback)(device); - return backend; - } - + return new JackPlayback{device}; return nullptr; } diff --git a/Alc/backends/jack.h b/Alc/backends/jack.h index bdf73701..b9bb13b2 100644 --- a/Alc/backends/jack.h +++ b/Alc/backends/jack.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/loopback.cpp b/Alc/backends/loopback.cpp index eadacdfb..373b11c9 100644 --- a/Alc/backends/loopback.cpp +++ b/Alc/backends/loopback.cpp @@ -28,59 +28,35 @@ namespace { -struct ALCloopback final : public ALCbackend { - ALCloopback(ALCdevice *device) noexcept : ALCbackend{device} { } -}; +struct LoopbackBackend final : public BackendBase { + LoopbackBackend(ALCdevice *device) noexcept : BackendBase{device} { } -void ALCloopback_Construct(ALCloopback *self, ALCdevice *device); -void ALCloopback_Destruct(ALCloopback *self); -ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name); -ALCboolean ALCloopback_reset(ALCloopback *self); -ALCboolean ALCloopback_start(ALCloopback *self); -void ALCloopback_stop(ALCloopback *self); -DECLARE_FORWARD2(ALCloopback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -DECLARE_FORWARD(ALCloopback, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(ALCloopback, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(ALCloopback, ALCbackend, void, lock) -DECLARE_FORWARD(ALCloopback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCloopback) -DEFINE_ALCBACKEND_VTABLE(ALCloopback); - - -void ALCloopback_Construct(ALCloopback *self, ALCdevice *device) -{ - new (self) ALCloopback{device}; - SET_VTABLE2(ALCloopback, ALCbackend, self); -} + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; -void ALCloopback_Destruct(ALCloopback *self) -{ - self->~ALCloopback(); -} + DEF_NEWDEL(LoopbackBackend) +}; -ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name) +ALCenum LoopbackBackend::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean ALCloopback_reset(ALCloopback *self) +ALCboolean LoopbackBackend::reset() { - SetDefaultWFXChannelOrder(self->mDevice); + SetDefaultWFXChannelOrder(mDevice); return ALC_TRUE; } -ALCboolean ALCloopback_start(ALCloopback* UNUSED(self)) -{ - return ALC_TRUE; -} +ALCboolean LoopbackBackend::start() +{ return ALC_TRUE; } -void ALCloopback_stop(ALCloopback* UNUSED(self)) -{ -} +void LoopbackBackend::stop() +{ } } // namespace @@ -94,15 +70,10 @@ bool LoopbackBackendFactory::querySupport(ALCbackend_Type type) void LoopbackBackendFactory::probe(DevProbe, std::string*) { } -ALCbackend *LoopbackBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *LoopbackBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Loopback) - { - ALCloopback *backend; - NEW_OBJ(backend, ALCloopback)(device); - return backend; - } - + new LoopbackBackend{device}; return nullptr; } diff --git a/Alc/backends/loopback.h b/Alc/backends/loopback.h index 4607d6ed..ab37c2d7 100644 --- a/Alc/backends/loopback.h +++ b/Alc/backends/loopback.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 5367c46f..33340a5d 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -44,42 +44,24 @@ using std::chrono::nanoseconds; constexpr ALCchar nullDevice[] = "No Output"; -struct ALCnullBackend final : public ALCbackend { - ALCnullBackend(ALCdevice *device) noexcept : ALCbackend{device} { } +struct NullBackend final : public BackendBase { + NullBackend(ALCdevice *device) noexcept : BackendBase{device} { } int mixerProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + std::atomic mKillNow{AL_TRUE}; std::thread mThread; -}; - -void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device); -void ALCnullBackend_Destruct(ALCnullBackend *self); -ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name); -ALCboolean ALCnullBackend_reset(ALCnullBackend *self); -ALCboolean ALCnullBackend_start(ALCnullBackend *self); -void ALCnullBackend_stop(ALCnullBackend *self); -DECLARE_FORWARD2(ALCnullBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -DECLARE_FORWARD(ALCnullBackend, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(ALCnullBackend, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, lock) -DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCnullBackend) - -DEFINE_ALCBACKEND_VTABLE(ALCnullBackend); - - -void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device) -{ - new (self) ALCnullBackend{device}; - SET_VTABLE2(ALCnullBackend, ALCbackend, self); -} - -void ALCnullBackend_Destruct(ALCnullBackend *self) -{ self->~ALCnullBackend(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "NullBackend::"; } + DEF_NEWDEL(NullBackend) +}; -int ALCnullBackend::mixerProc() +int NullBackend::mixerProc() { const milliseconds restTime{mDevice->UpdateSize*1000/mDevice->Frequency / 2}; @@ -102,9 +84,9 @@ int ALCnullBackend::mixerProc() } while(avail-done >= mDevice->UpdateSize) { - ALCnullBackend_lock(this); + lock(); aluMixData(mDevice, nullptr, mDevice->UpdateSize); - ALCnullBackend_unlock(this); + unlock(); done += mDevice->UpdateSize; } @@ -125,30 +107,29 @@ int ALCnullBackend::mixerProc() } -ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name) +ALCenum NullBackend::open(const ALCchar *name) { if(!name) name = nullDevice; else if(strcmp(name, nullDevice) != 0) return ALC_INVALID_VALUE; - ALCdevice *device{self->mDevice}; - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean ALCnullBackend_reset(ALCnullBackend *self) +ALCboolean NullBackend::reset() { - SetDefaultWFXChannelOrder(self->mDevice); + SetDefaultWFXChannelOrder(mDevice); return ALC_TRUE; } -ALCboolean ALCnullBackend_start(ALCnullBackend *self) +ALCboolean NullBackend::start() { try { - self->mKillNow.store(AL_FALSE, std::memory_order_release); - self->mThread = std::thread(std::mem_fn(&ALCnullBackend::mixerProc), self); + mKillNow.store(AL_FALSE, std::memory_order_release); + mThread = std::thread{std::mem_fn(&NullBackend::mixerProc), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -159,11 +140,11 @@ ALCboolean ALCnullBackend_start(ALCnullBackend *self) return ALC_FALSE; } -void ALCnullBackend_stop(ALCnullBackend *self) +void NullBackend::stop() { - if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->mThread.joinable()) + if(mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !mThread.joinable()) return; - self->mThread.join(); + mThread.join(); } } // namespace @@ -188,16 +169,11 @@ void NullBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *NullBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *NullBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - ALCnullBackend *backend; - NEW_OBJ(backend, ALCnullBackend)(device); - return backend; - } - - return NULL; + return new NullBackend{device}; + return nullptr; } BackendFactory &NullBackendFactory::getFactory() diff --git a/Alc/backends/null.h b/Alc/backends/null.h index 37457d94..d4164198 100644 --- a/Alc/backends/null.h +++ b/Alc/backends/null.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index b0e51441..4f2e07be 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -42,14 +42,15 @@ namespace { /* Helper macros */ +#define EXTRACT_VCALL_ARGS(...) __VA_ARGS__)) #define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS #define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS -static const ALCchar opensl_device[] = "OpenSL"; +constexpr ALCchar opensl_device[] = "OpenSL"; -static SLuint32 GetChannelMask(DevFmtChannels chans) +SLuint32 GetChannelMask(DevFmtChannels chans) { switch(chans) { @@ -78,7 +79,7 @@ static SLuint32 GetChannelMask(DevFmtChannels chans) } #ifdef SL_DATAFORMAT_PCM_EX -static SLuint32 GetTypeRepresentation(DevFmtType type) +SLuint32 GetTypeRepresentation(DevFmtType type) { switch(type) { @@ -97,7 +98,7 @@ static SLuint32 GetTypeRepresentation(DevFmtType type) } #endif -static const char *res_str(SLresult result) +const char *res_str(SLresult result) { switch(result) { @@ -132,20 +133,26 @@ static const char *res_str(SLresult result) } #define PRINTERR(x, s) do { \ - if((x) != SL_RESULT_SUCCESS) \ + if(UNLIKELY((x) != SL_RESULT_SUCCESS)) \ ERR("%s: %s\n", (s), res_str((x))); \ } while(0) -struct ALCopenslPlayback final : public ALCbackend { - ALCopenslPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCopenslPlayback() override; +struct OpenSLPlayback final : public BackendBase { + OpenSLPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~OpenSLPlayback() override; static void processC(SLAndroidSimpleBufferQueueItf bq, void *context); void process(SLAndroidSimpleBufferQueueItf bq); int mixerProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + ClockLatency getClockLatency() override; + /* engine interfaces */ SLObjectItf mEngineObj{nullptr}; SLEngineItf mEngine{nullptr}; @@ -163,34 +170,12 @@ struct ALCopenslPlayback final : public ALCbackend { std::atomic mKillNow{AL_TRUE}; std::thread mThread; -}; - -static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *device); -static void ALCopenslPlayback_Destruct(ALCopenslPlayback *self); -static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name); -static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self); -static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self); -static void ALCopenslPlayback_stop(ALCopenslPlayback *self); -static DECLARE_FORWARD2(ALCopenslPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, ALCuint, availableSamples) -static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self); -static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCopenslPlayback) -DEFINE_ALCBACKEND_VTABLE(ALCopenslPlayback); - - -static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *device) -{ - new (self) ALCopenslPlayback{device}; - SET_VTABLE2(ALCopenslPlayback, ALCbackend, self); -} - -static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self) -{ self->~ALCopenslPlayback(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "OpenSLPlayback::"; } + DEF_NEWDEL(OpenSLPlayback) +}; -ALCopenslPlayback::~ALCopenslPlayback() +OpenSLPlayback::~OpenSLPlayback() { if(mBufferQueueObj) VCALL0(mBufferQueueObj,Destroy)(); @@ -208,10 +193,10 @@ ALCopenslPlayback::~ALCopenslPlayback() /* this callback handler is called every time a buffer finishes playing */ -void ALCopenslPlayback::processC(SLAndroidSimpleBufferQueueItf bq, void *context) -{ static_cast(context)->process(bq); } +void OpenSLPlayback::processC(SLAndroidSimpleBufferQueueItf bq, void *context) +{ static_cast(context)->process(bq); } -void ALCopenslPlayback::process(SLAndroidSimpleBufferQueueItf UNUSED(bq)) +void OpenSLPlayback::process(SLAndroidSimpleBufferQueueItf UNUSED(bq)) { /* A note on the ringbuffer usage: The buffer queue seems to hold on to the * pointer passed to the Enqueue method, rather than copying the audio. @@ -226,7 +211,7 @@ void ALCopenslPlayback::process(SLAndroidSimpleBufferQueueItf UNUSED(bq)) mSem.post(); } -int ALCopenslPlayback::mixerProc() +int OpenSLPlayback::mixerProc() { SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); @@ -242,7 +227,7 @@ int ALCopenslPlayback::mixerProc() PRINTERR(result, "bufferQueue->GetInterface SL_IID_PLAY"); } - ALCopenslPlayback_lock(this); + lock(); if(SL_RESULT_SUCCESS != result) aluHandleDisconnect(mDevice, "Failed to get playback buffer: 0x%08x", result); @@ -251,7 +236,7 @@ int ALCopenslPlayback::mixerProc() { if(mRing->writeSpace() == 0) { - SLuint32 state = 0; + SLuint32 state{0}; result = VCALL(player,GetPlayState)(&state); PRINTERR(result, "player->GetPlayState"); @@ -268,9 +253,9 @@ int ALCopenslPlayback::mixerProc() if(mRing->writeSpace() == 0) { - ALCopenslPlayback_unlock(this); + unlock(); mSem.wait(); - ALCopenslPlayback_lock(this); + lock(); continue; } } @@ -304,67 +289,63 @@ int ALCopenslPlayback::mixerProc() data.first.buf += mDevice->UpdateSize*mFrameSize; } } - ALCopenslPlayback_unlock(this); + unlock(); return 0; } -static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name) +ALCenum OpenSLPlayback::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - SLresult result; - if(!name) name = opensl_device; else if(strcmp(name, opensl_device) != 0) return ALC_INVALID_VALUE; // create engine - result = slCreateEngine(&self->mEngineObj, 0, NULL, 0, NULL, NULL); + SLresult result{slCreateEngine(&mEngineObj, 0, NULL, 0, NULL, NULL)}; PRINTERR(result, "slCreateEngine"); if(SL_RESULT_SUCCESS == result) { - result = VCALL(self->mEngineObj,Realize)(SL_BOOLEAN_FALSE); + result = VCALL(mEngineObj,Realize)(SL_BOOLEAN_FALSE); PRINTERR(result, "engine->Realize"); } if(SL_RESULT_SUCCESS == result) { - result = VCALL(self->mEngineObj,GetInterface)(SL_IID_ENGINE, &self->mEngine); + result = VCALL(mEngineObj,GetInterface)(SL_IID_ENGINE, &mEngine); PRINTERR(result, "engine->GetInterface"); } if(SL_RESULT_SUCCESS == result) { - result = VCALL(self->mEngine,CreateOutputMix)(&self->mOutputMix, 0, NULL, NULL); + result = VCALL(mEngine,CreateOutputMix)(&mOutputMix, 0, NULL, NULL); PRINTERR(result, "engine->CreateOutputMix"); } if(SL_RESULT_SUCCESS == result) { - result = VCALL(self->mOutputMix,Realize)(SL_BOOLEAN_FALSE); + result = VCALL(mOutputMix,Realize)(SL_BOOLEAN_FALSE); PRINTERR(result, "outputMix->Realize"); } if(SL_RESULT_SUCCESS != result) { - if(self->mOutputMix != NULL) - VCALL0(self->mOutputMix,Destroy)(); - self->mOutputMix = NULL; + if(mOutputMix) + VCALL0(mOutputMix,Destroy)(); + mOutputMix = NULL; - if(self->mEngineObj != NULL) - VCALL0(self->mEngineObj,Destroy)(); - self->mEngineObj = NULL; - self->mEngine = NULL; + if(mEngineObj) + VCALL0(mEngineObj,Destroy)(); + mEngineObj = NULL; + mEngine = NULL; return ALC_INVALID_VALUE; } - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) +ALCboolean OpenSLPlayback::reset() { - ALCdevice *device{self->mDevice}; SLDataLocator_AndroidSimpleBufferQueue loc_bufq; SLDataLocator_OutputMix loc_outmix; SLDataSource audioSrc; @@ -374,15 +355,15 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) SLboolean reqs[2]; SLresult result; - if(self->mBufferQueueObj != NULL) - VCALL0(self->mBufferQueueObj,Destroy)(); - self->mBufferQueueObj = NULL; + if(mBufferQueueObj) + VCALL0(mBufferQueueObj,Destroy)(); + mBufferQueueObj = NULL; - self->mRing = nullptr; + mRing = nullptr; - sampleRate = device->Frequency; + sampleRate = mDevice->Frequency; #if 0 - if(!(device->Flags&DEVICE_FREQUENCY_REQUEST)) + if(!(mDevice->Flags&DEVICE_FREQUENCY_REQUEST)) { /* FIXME: Disabled until I figure out how to get the Context needed for * the getSystemService call. @@ -449,43 +430,43 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) } #endif - if(sampleRate != device->Frequency) + if(sampleRate != mDevice->Frequency) { - device->NumUpdates = (device->NumUpdates*sampleRate + (device->Frequency>>1)) / - device->Frequency; - device->NumUpdates = maxu(device->NumUpdates, 2); - device->Frequency = sampleRate; + mDevice->NumUpdates = (mDevice->NumUpdates*sampleRate + (mDevice->Frequency>>1)) / + mDevice->Frequency; + mDevice->NumUpdates = maxu(mDevice->NumUpdates, 2); + mDevice->Frequency = sampleRate; } - device->FmtChans = DevFmtStereo; - device->FmtType = DevFmtShort; + mDevice->FmtChans = DevFmtStereo; + mDevice->FmtType = DevFmtShort; - SetDefaultWFXChannelOrder(device); - self->mFrameSize = device->frameSizeFromFmt(); + SetDefaultWFXChannelOrder(mDevice); + mFrameSize = mDevice->frameSizeFromFmt(); loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; - loc_bufq.numBuffers = device->NumUpdates; + loc_bufq.numBuffers = mDevice->NumUpdates; #ifdef SL_DATAFORMAT_PCM_EX SLDataFormat_PCM_EX format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM_EX; - format_pcm.numChannels = device->channelsFromFmt(); - format_pcm.sampleRate = device->Frequency * 1000; - format_pcm.bitsPerSample = device->bytesFromFmt() * 8; + format_pcm.numChannels = mDevice->channelsFromFmt(); + format_pcm.sampleRate = mDevice->Frequency * 1000; + format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(device->FmtChans); + format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; - format_pcm.representation = GetTypeRepresentation(device->FmtType); + format_pcm.representation = GetTypeRepresentation(mDevice->FmtType); #else SLDataFormat_PCM format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = device->channelsFromFmt(); - format_pcm.samplesPerSec = device->Frequency * 1000; - format_pcm.bitsPerSample = device->bytesFromFmt() * 8; + format_pcm.numChannels = mDevice->channelsFromFmt(); + format_pcm.samplesPerSec = mDevice->Frequency * 1000; + format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(device->FmtChans); + format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; #endif @@ -494,7 +475,7 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) audioSrc.pFormat = &format_pcm; loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; - loc_outmix.outputMix = self->mOutputMix; + loc_outmix.outputMix = mOutputMix; audioSnk.pLocator = &loc_outmix; audioSnk.pFormat = NULL; @@ -504,22 +485,20 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) ids[1] = SL_IID_ANDROIDCONFIGURATION; reqs[1] = SL_BOOLEAN_FALSE; - result = VCALL(self->mEngine,CreateAudioPlayer)(&self->mBufferQueueObj, - &audioSrc, &audioSnk, COUNTOF(ids), ids, reqs - ); + result = VCALL(mEngine,CreateAudioPlayer)(&mBufferQueueObj, &audioSrc, &audioSnk, COUNTOF(ids), + ids, reqs); PRINTERR(result, "engine->CreateAudioPlayer"); if(SL_RESULT_SUCCESS == result) { /* Set the stream type to "media" (games, music, etc), if possible. */ SLAndroidConfigurationItf config; - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config); + result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config); PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION"); if(SL_RESULT_SUCCESS == result) { SLint32 streamType = SL_ANDROID_STREAM_MEDIA; - result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_STREAM_TYPE, - &streamType, sizeof(streamType) - ); + result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_STREAM_TYPE, &streamType, + sizeof(streamType)); PRINTERR(result, "config->SetConfiguration"); } @@ -528,26 +507,25 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) } if(SL_RESULT_SUCCESS == result) { - result = VCALL(self->mBufferQueueObj,Realize)(SL_BOOLEAN_FALSE); + result = VCALL(mBufferQueueObj,Realize)(SL_BOOLEAN_FALSE); PRINTERR(result, "bufferQueue->Realize"); } if(SL_RESULT_SUCCESS == result) { - self->mRing = CreateRingBuffer(device->NumUpdates, - self->mFrameSize*device->UpdateSize, true); - if(!self->mRing) + mRing = CreateRingBuffer(mDevice->NumUpdates, mFrameSize*mDevice->UpdateSize, true); + if(!mRing) { - ERR("Out of memory allocating ring buffer %ux%u %u\n", device->UpdateSize, - device->NumUpdates, self->mFrameSize); + ERR("Out of memory allocating ring buffer %ux%u %u\n", mDevice->UpdateSize, + mDevice->NumUpdates, mFrameSize); result = SL_RESULT_MEMORY_FAILURE; } } if(SL_RESULT_SUCCESS != result) { - if(self->mBufferQueueObj != NULL) - VCALL0(self->mBufferQueueObj,Destroy)(); - self->mBufferQueueObj = NULL; + if(mBufferQueueObj) + VCALL0(mBufferQueueObj,Destroy)(); + mBufferQueueObj = NULL; return ALC_FALSE; } @@ -555,26 +533,24 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) return ALC_TRUE; } -static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self) +ALCboolean OpenSLPlayback::start() { - RingBuffer *ring{self->mRing.get()}; - - ring->reset(); + mRing->reset(); SLAndroidSimpleBufferQueueItf bufferQueue; - SLresult result{VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue)}; PRINTERR(result, "bufferQueue->GetInterface"); if(SL_RESULT_SUCCESS != result) return ALC_FALSE; - result = VCALL(bufferQueue,RegisterCallback)(&ALCopenslPlayback::processC, self); + result = VCALL(bufferQueue,RegisterCallback)(&OpenSLPlayback::processC, this); PRINTERR(result, "bufferQueue->RegisterCallback"); if(SL_RESULT_SUCCESS != result) return ALC_FALSE; try { - self->mKillNow.store(AL_FALSE); - self->mThread = std::thread(std::mem_fn(&ALCopenslPlayback::mixerProc), self); + mKillNow.store(AL_FALSE); + mThread = std::thread(std::mem_fn(&OpenSLPlayback::mixerProc), this); return ALC_TRUE; } catch(std::exception& e) { @@ -585,20 +561,16 @@ static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self) return ALC_FALSE; } - -static void ALCopenslPlayback_stop(ALCopenslPlayback *self) +void OpenSLPlayback::stop() { - SLAndroidSimpleBufferQueueItf bufferQueue; - SLPlayItf player; - SLresult result; - - if(self->mKillNow.exchange(AL_TRUE) || !self->mThread.joinable()) + if(mKillNow.exchange(AL_TRUE) || !mThread.joinable()) return; - self->mSem.post(); - self->mThread.join(); + mSem.post(); + mThread.join(); - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player); + SLPlayItf player; + SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player)}; PRINTERR(result, "bufferQueue->GetInterface"); if(SL_RESULT_SUCCESS == result) { @@ -606,8 +578,8 @@ static void ALCopenslPlayback_stop(ALCopenslPlayback *self) PRINTERR(result, "player->SetPlayState"); } - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue); + SLAndroidSimpleBufferQueueItf bufferQueue; + result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); PRINTERR(result, "bufferQueue->GetInterface"); if(SL_RESULT_SUCCESS == result) { @@ -630,29 +602,33 @@ static void ALCopenslPlayback_stop(ALCopenslPlayback *self) } } -static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self) +ClockLatency OpenSLPlayback::getClockLatency() { - ALCdevice *device{self->mDevice}; - RingBuffer *ring{self->mRing.get()}; ClockLatency ret; - ALCopenslPlayback_lock(self); - ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = std::chrono::seconds{ring->readSpace() * device->UpdateSize}; - ret.Latency /= device->Frequency; - ALCopenslPlayback_unlock(self); + lock(); + ret.ClockTime = GetDeviceClockTime(mDevice); + ret.Latency = std::chrono::seconds{mRing->readSpace() * mDevice->UpdateSize}; + ret.Latency /= mDevice->Frequency; + unlock(); return ret; } -struct ALCopenslCapture final : public ALCbackend { - ALCopenslCapture(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCopenslCapture() override; +struct OpenSLCapture final : public BackendBase { + OpenSLCapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~OpenSLCapture() override; static void processC(SLAndroidSimpleBufferQueueItf bq, void *context); void process(SLAndroidSimpleBufferQueueItf bq); + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + /* engine interfaces */ SLObjectItf mEngineObj{nullptr}; SLEngineItf mEngine; @@ -664,33 +640,12 @@ struct ALCopenslCapture final : public ALCbackend { ALCuint mSplOffset{0u}; ALsizei mFrameSize{0}; -}; -static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device); -static void ALCopenslCapture_Destruct(ALCopenslCapture *self); -static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name); -static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, ALCboolean, reset) -static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self); -static void ALCopenslCapture_stop(ALCopenslCapture *self); -static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid *buffer, ALCuint samples); -static ALCuint ALCopenslCapture_availableSamples(ALCopenslCapture *self); -static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCopenslCapture) -DEFINE_ALCBACKEND_VTABLE(ALCopenslCapture); - - -static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device) -{ - new (self) ALCopenslCapture{device}; - SET_VTABLE2(ALCopenslCapture, ALCbackend, self); -} - -static void ALCopenslCapture_Destruct(ALCopenslCapture *self) -{ self->~ALCopenslCapture(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "OpenSLCapture::"; } + DEF_NEWDEL(OpenSLCapture) +}; -ALCopenslCapture::~ALCopenslCapture() +OpenSLCapture::~OpenSLCapture() { if(mRecordObj) VCALL0(mRecordObj,Destroy)(); @@ -703,19 +658,18 @@ ALCopenslCapture::~ALCopenslCapture() } -void ALCopenslCapture::processC(SLAndroidSimpleBufferQueueItf bq, void *context) -{ static_cast(context)->process(bq); } +void OpenSLCapture::processC(SLAndroidSimpleBufferQueueItf bq, void *context) +{ static_cast(context)->process(bq); } -void ALCopenslCapture::process(SLAndroidSimpleBufferQueueItf UNUSED(bq)) +void OpenSLCapture::process(SLAndroidSimpleBufferQueueItf UNUSED(bq)) { /* A new chunk has been written into the ring buffer, advance it. */ mRing->writeAdvance(1); } -static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name) +ALCenum OpenSLCapture::open(const ALCchar* name) { - ALCdevice *device{self->mDevice}; SLDataLocator_AndroidSimpleBufferQueue loc_bq; SLAndroidSimpleBufferQueueItf bufferQueue; SLDataLocator_IODevice loc_dev; @@ -728,32 +682,30 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name else if(strcmp(name, opensl_device) != 0) return ALC_INVALID_VALUE; - result = slCreateEngine(&self->mEngineObj, 0, NULL, 0, NULL, NULL); + result = slCreateEngine(&mEngineObj, 0, NULL, 0, NULL, NULL); PRINTERR(result, "slCreateEngine"); if(SL_RESULT_SUCCESS == result) { - result = VCALL(self->mEngineObj,Realize)(SL_BOOLEAN_FALSE); + result = VCALL(mEngineObj,Realize)(SL_BOOLEAN_FALSE); PRINTERR(result, "engine->Realize"); } if(SL_RESULT_SUCCESS == result) { - result = VCALL(self->mEngineObj,GetInterface)(SL_IID_ENGINE, &self->mEngine); + result = VCALL(mEngineObj,GetInterface)(SL_IID_ENGINE, &mEngine); PRINTERR(result, "engine->GetInterface"); } if(SL_RESULT_SUCCESS == result) { /* Ensure the total length is at least 100ms */ - ALsizei length = maxi(device->NumUpdates * device->UpdateSize, - device->Frequency / 10); + ALsizei length{maxi(mDevice->NumUpdates*mDevice->UpdateSize, mDevice->Frequency/10)}; /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */ - ALsizei update_len = clampi(device->NumUpdates*device->UpdateSize / 3, - device->Frequency / 100, - device->Frequency / 100 * 5); + ALsizei update_len{clampi(mDevice->NumUpdates*mDevice->UpdateSize / 3, + mDevice->Frequency/100, mDevice->Frequency/100*5)}; - device->UpdateSize = update_len; - device->NumUpdates = (length+update_len-1) / update_len; + mDevice->UpdateSize = update_len; + mDevice->NumUpdates = (length+update_len-1) / update_len; - self->mFrameSize = device->frameSizeFromFmt(); + mFrameSize = mDevice->frameSizeFromFmt(); } loc_dev.locatorType = SL_DATALOCATOR_IODEVICE; loc_dev.deviceType = SL_IODEVICE_AUDIOINPUT; @@ -764,27 +716,27 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name audioSrc.pFormat = NULL; loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; - loc_bq.numBuffers = device->NumUpdates; + loc_bq.numBuffers = mDevice->NumUpdates; #ifdef SL_DATAFORMAT_PCM_EX SLDataFormat_PCM_EX format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM_EX; - format_pcm.numChannels = device->channelsFromFmt(); - format_pcm.sampleRate = device->Frequency * 1000; - format_pcm.bitsPerSample = device->bytesFromFmt() * 8; + format_pcm.numChannels = mDevice->channelsFromFmt(); + format_pcm.sampleRate = mDevice->Frequency * 1000; + format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(device->FmtChans); + format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; - format_pcm.representation = GetTypeRepresentation(device->FmtType); + format_pcm.representation = GetTypeRepresentation(mDevice->FmtType); #else SLDataFormat_PCM format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = device->channelsFromFmt(); - format_pcm.samplesPerSec = device->Frequency * 1000; - format_pcm.bitsPerSample = device->bytesFromFmt() * 8; + format_pcm.numChannels = mDevice->channelsFromFmt(); + format_pcm.samplesPerSec = mDevice->Frequency * 1000; + format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(device->FmtChans); + format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; #endif @@ -797,23 +749,21 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name const SLInterfaceID ids[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }; const SLboolean reqs[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }; - result = VCALL(self->mEngine,CreateAudioRecorder)(&self->mRecordObj, - &audioSrc, &audioSnk, COUNTOF(ids), ids, reqs - ); + result = VCALL(mEngine,CreateAudioRecorder)(&mRecordObj, &audioSrc, &audioSnk, + COUNTOF(ids), ids, reqs); PRINTERR(result, "engine->CreateAudioRecorder"); } if(SL_RESULT_SUCCESS == result) { /* Set the record preset to "generic", if possible. */ SLAndroidConfigurationItf config; - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config); + result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config); PRINTERR(result, "recordObj->GetInterface SL_IID_ANDROIDCONFIGURATION"); if(SL_RESULT_SUCCESS == result) { SLuint32 preset = SL_ANDROID_RECORDING_PRESET_GENERIC; - result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_RECORDING_PRESET, - &preset, sizeof(preset) - ); + result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_RECORDING_PRESET, &preset, + sizeof(preset)); PRINTERR(result, "config->SetConfiguration"); } @@ -822,31 +772,28 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name } if(SL_RESULT_SUCCESS == result) { - result = VCALL(self->mRecordObj,Realize)(SL_BOOLEAN_FALSE); + result = VCALL(mRecordObj,Realize)(SL_BOOLEAN_FALSE); PRINTERR(result, "recordObj->Realize"); } if(SL_RESULT_SUCCESS == result) { - self->mRing = CreateRingBuffer(device->NumUpdates, - device->UpdateSize*self->mFrameSize, false); + mRing = CreateRingBuffer(mDevice->NumUpdates, mDevice->UpdateSize*mFrameSize, false); - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue); + result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); PRINTERR(result, "recordObj->GetInterface"); } if(SL_RESULT_SUCCESS == result) { - result = VCALL(bufferQueue,RegisterCallback)(&ALCopenslCapture::processC, self); + result = VCALL(bufferQueue,RegisterCallback)(&OpenSLCapture::processC, this); PRINTERR(result, "bufferQueue->RegisterCallback"); } if(SL_RESULT_SUCCESS == result) { - RingBuffer *ring{self->mRing.get()}; - ALsizei chunk_size = device->UpdateSize * self->mFrameSize; + ALsizei chunk_size = mDevice->UpdateSize * mFrameSize; size_t i; - auto data = ring->getWriteVector(); + auto data = mRing->getWriteVector(); for(i = 0;i < data.first.len && SL_RESULT_SUCCESS == result;i++) { result = VCALL(bufferQueue,Enqueue)(data.first.buf + chunk_size*i, chunk_size); @@ -861,28 +808,26 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name if(SL_RESULT_SUCCESS != result) { - if(self->mRecordObj != NULL) - VCALL0(self->mRecordObj,Destroy)(); - self->mRecordObj = NULL; + if(mRecordObj) + VCALL0(mRecordObj,Destroy)(); + mRecordObj = nullptr; - if(self->mEngineObj != NULL) - VCALL0(self->mEngineObj,Destroy)(); - self->mEngineObj = NULL; - self->mEngine = NULL; + if(mEngineObj) + VCALL0(mEngineObj,Destroy)(); + mEngineObj = nullptr; + mEngine = nullptr; return ALC_INVALID_VALUE; } - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self) +ALCboolean OpenSLCapture::start() { SLRecordItf record; - SLresult result; - - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_RECORD, &record); + SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_RECORD, &record)}; PRINTERR(result, "recordObj->GetInterface"); if(SL_RESULT_SUCCESS == result) @@ -893,21 +838,19 @@ static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self) if(SL_RESULT_SUCCESS != result) { - ALCopenslCapture_lock(self); - aluHandleDisconnect(self->mDevice, "Failed to start capture: 0x%08x", result); - ALCopenslCapture_unlock(self); + lock(); + aluHandleDisconnect(mDevice, "Failed to start capture: 0x%08x", result); + unlock(); return ALC_FALSE; } return ALC_TRUE; } -static void ALCopenslCapture_stop(ALCopenslCapture *self) +void OpenSLCapture::stop() { SLRecordItf record; - SLresult result; - - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_RECORD, &record); + SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_RECORD, &record)}; PRINTERR(result, "recordObj->GetInterface"); if(SL_RESULT_SUCCESS == result) @@ -917,37 +860,33 @@ static void ALCopenslCapture_stop(ALCopenslCapture *self) } } -static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum OpenSLCapture::captureSamples(void* buffer, ALCuint samples) { - ALCdevice *device{self->mDevice}; - RingBuffer *ring{self->mRing.get()}; - ALsizei chunk_size = device->UpdateSize * self->mFrameSize; + ALsizei chunk_size = mDevice->UpdateSize * mFrameSize; SLAndroidSimpleBufferQueueItf bufferQueue; SLresult result; ALCuint i; - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue); + result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); PRINTERR(result, "recordObj->GetInterface"); /* Read the desired samples from the ring buffer then advance its read * pointer. */ - auto data = ring->getReadVector(); + auto data = mRing->getReadVector(); for(i = 0;i < samples;) { - ALCuint rem = minu(samples - i, device->UpdateSize - self->mSplOffset); - memcpy((ALCbyte*)buffer + i*self->mFrameSize, - data.first.buf + self->mSplOffset*self->mFrameSize, - rem * self->mFrameSize); + ALCuint rem{minu(samples - i, mDevice->UpdateSize - mSplOffset)}; + memcpy((ALCbyte*)buffer + i*mFrameSize, data.first.buf + mSplOffset*mFrameSize, + rem * mFrameSize); - self->mSplOffset += rem; - if(self->mSplOffset == device->UpdateSize) + mSplOffset += rem; + if(mSplOffset == mDevice->UpdateSize) { /* Finished a chunk, reset the offset and advance the read pointer. */ - self->mSplOffset = 0; + mSplOffset = 0; - ring->readAdvance(1); + mRing->readAdvance(1); result = VCALL(bufferQueue,Enqueue)(data.first.buf, chunk_size); PRINTERR(result, "bufferQueue->Enqueue"); if(SL_RESULT_SUCCESS != result) break; @@ -964,21 +903,17 @@ static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid * if(SL_RESULT_SUCCESS != result) { - ALCopenslCapture_lock(self); - aluHandleDisconnect(device, "Failed to update capture buffer: 0x%08x", result); - ALCopenslCapture_unlock(self); + lock(); + aluHandleDisconnect(mDevice, "Failed to update capture buffer: 0x%08x", result); + unlock(); return ALC_INVALID_DEVICE; } return ALC_NO_ERROR; } -static ALCuint ALCopenslCapture_availableSamples(ALCopenslCapture *self) -{ - ALCdevice *device{self->mDevice}; - RingBuffer *ring{self->mRing.get()}; - return ring->readSpace() * device->UpdateSize; -} +ALCuint OpenSLCapture::availableSamples() +{ return mRing->readSpace()*mDevice->UpdateSize - mSplOffset; } } // namespace @@ -999,21 +934,12 @@ void OSLBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *OSLBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *OSLBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - ALCopenslPlayback *backend; - NEW_OBJ(backend, ALCopenslPlayback)(device); - return backend; - } + return new OpenSLPlayback{device}; if(type == ALCbackend_Capture) - { - ALCopenslCapture *backend; - NEW_OBJ(backend, ALCopenslCapture)(device); - return backend; - } - + return new OpenSLCapture{device}; return nullptr; } diff --git a/Alc/backends/opensl.h b/Alc/backends/opensl.h index 31d0caae..bab15115 100644 --- a/Alc/backends/opensl.h +++ b/Alc/backends/opensl.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 54d7e0af..c2139d4d 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -241,45 +241,29 @@ int log2i(ALCuint x) } -struct ALCplaybackOSS final : public ALCbackend { - ALCplaybackOSS(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCplaybackOSS() override; +struct OSSPlayback final : public BackendBase { + OSSPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~OSSPlayback() override; int mixerProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + int mFd{-1}; al::vector mMixData; std::atomic mKillNow{AL_TRUE}; std::thread mThread; -}; - -void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device); -void ALCplaybackOSS_Destruct(ALCplaybackOSS *self); -ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name); -ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self); -ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self); -void ALCplaybackOSS_stop(ALCplaybackOSS *self); -DECLARE_FORWARD2(ALCplaybackOSS, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, lock) -DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCplaybackOSS) -DEFINE_ALCBACKEND_VTABLE(ALCplaybackOSS); - - -void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device) -{ - new (self) ALCplaybackOSS{device}; - SET_VTABLE2(ALCplaybackOSS, ALCbackend, self); -} -void ALCplaybackOSS_Destruct(ALCplaybackOSS *self) -{ self->~ALCplaybackOSS(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "OSSPlayback::"; } + DEF_NEWDEL(OSSPlayback) +}; -ALCplaybackOSS::~ALCplaybackOSS() +OSSPlayback::~OSSPlayback() { if(mFd != -1) close(mFd); @@ -287,14 +271,14 @@ ALCplaybackOSS::~ALCplaybackOSS() } -int ALCplaybackOSS::mixerProc() +int OSSPlayback::mixerProc() { SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); const int frame_size{mDevice->frameSizeFromFmt()}; - ALCplaybackOSS_lock(this); + lock(); while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) { @@ -302,9 +286,9 @@ int ALCplaybackOSS::mixerProc() pollitem.fd = mFd; pollitem.events = POLLOUT; - ALCplaybackOSS_unlock(this); + unlock(); int pret{poll(&pollitem, 1, 1000)}; - ALCplaybackOSS_lock(this); + lock(); if(pret < 0) { if(errno == EINTR || errno == EAGAIN) @@ -339,16 +323,14 @@ int ALCplaybackOSS::mixerProc() write_ptr += wrote; } } - ALCplaybackOSS_unlock(this); + unlock(); return 0; } -ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) +ALCenum OSSPlayback::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - const char *devname{DefaultPlayback}; if(!name) name = DefaultName; @@ -366,20 +348,19 @@ ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) devname = iter->device_name.c_str(); } - self->mFd = open(devname, O_WRONLY); - if(self->mFd == -1) + mFd = ::open(devname, O_WRONLY); + if(mFd == -1) { ERR("Could not open %s: %s\n", devname, strerror(errno)); return ALC_INVALID_VALUE; } - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) +ALCboolean OSSPlayback::reset() { - ALCdevice *device{self->mDevice}; int numFragmentsLogSize; int log2FragmentSize; unsigned int periods; @@ -390,7 +371,7 @@ ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) int ossSpeed; const char *err; - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: ossFormat = AFMT_S8; @@ -402,19 +383,19 @@ ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) case DevFmtInt: case DevFmtUInt: case DevFmtFloat: - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; /* fall-through */ case DevFmtShort: ossFormat = AFMT_S16_NE; break; } - periods = device->NumUpdates; - numChannels = device->channelsFromFmt(); - ossSpeed = device->Frequency; - frameSize = numChannels * device->bytesFromFmt(); + periods = mDevice->NumUpdates; + numChannels = mDevice->channelsFromFmt(); + ossSpeed = mDevice->Frequency; + frameSize = numChannels * mDevice->bytesFromFmt(); /* According to the OSS spec, 16 bytes (log2(16)) is the minimum. */ - log2FragmentSize = maxi(log2i(device->UpdateSize*frameSize), 4); + log2FragmentSize = maxi(log2i(mDevice->UpdateSize*frameSize), 4); numFragmentsLogSize = (periods << 16) | log2FragmentSize; #define CHECKERR(func) if((func) < 0) { \ @@ -423,11 +404,11 @@ ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) } /* Don't fail if SETFRAGMENT fails. We can handle just about anything * that's reported back via GETOSPACE */ - ioctl(self->mFd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize); - CHECKERR(ioctl(self->mFd, SNDCTL_DSP_SETFMT, &ossFormat)); - CHECKERR(ioctl(self->mFd, SNDCTL_DSP_CHANNELS, &numChannels)); - CHECKERR(ioctl(self->mFd, SNDCTL_DSP_SPEED, &ossSpeed)); - CHECKERR(ioctl(self->mFd, SNDCTL_DSP_GETOSPACE, &info)); + ioctl(mFd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize); + CHECKERR(ioctl(mFd, SNDCTL_DSP_SETFMT, &ossFormat)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_CHANNELS, &numChannels)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_SPEED, &ossSpeed)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_GETOSPACE, &info)); if(0) { err: @@ -436,38 +417,38 @@ ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) } #undef CHECKERR - if(device->channelsFromFmt() != numChannels) + if(mDevice->channelsFromFmt() != numChannels) { - ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); + ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(mDevice->FmtChans), + numChannels); return ALC_FALSE; } - if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) || - (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) || - (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort))) + if(!((ossFormat == AFMT_S8 && mDevice->FmtType == DevFmtByte) || + (ossFormat == AFMT_U8 && mDevice->FmtType == DevFmtUByte) || + (ossFormat == AFMT_S16_NE && mDevice->FmtType == DevFmtShort))) { - ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat); + ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(mDevice->FmtType), + ossFormat); return ALC_FALSE; } - device->Frequency = ossSpeed; - device->UpdateSize = info.fragsize / frameSize; - device->NumUpdates = info.fragments; + mDevice->Frequency = ossSpeed; + mDevice->UpdateSize = info.fragsize / frameSize; + mDevice->NumUpdates = info.fragments; + + SetDefaultChannelOrder(mDevice); - SetDefaultChannelOrder(device); + mMixData.resize(mDevice->UpdateSize * mDevice->frameSizeFromFmt()); return ALC_TRUE; } -ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self) +ALCboolean OSSPlayback::start() { - ALCdevice *device{self->mDevice}; - try { - self->mMixData.resize(device->UpdateSize * device->frameSizeFromFmt()); - - self->mKillNow.store(AL_FALSE); - self->mThread = std::thread{std::mem_fn(&ALCplaybackOSS::mixerProc), self}; + mKillNow.store(AL_FALSE); + mThread = std::thread{std::mem_fn(&OSSPlayback::mixerProc), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -478,58 +459,41 @@ ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self) return ALC_FALSE; } -void ALCplaybackOSS_stop(ALCplaybackOSS *self) +void OSSPlayback::stop() { - if(self->mKillNow.exchange(AL_TRUE) || !self->mThread.joinable()) + if(mKillNow.exchange(AL_TRUE) || !mThread.joinable()) return; - self->mThread.join(); + mThread.join(); - if(ioctl(self->mFd, SNDCTL_DSP_RESET) != 0) + if(ioctl(mFd, SNDCTL_DSP_RESET) != 0) ERR("Error resetting device: %s\n", strerror(errno)); - - self->mMixData.clear(); } -struct ALCcaptureOSS final : public ALCbackend { - ALCcaptureOSS(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCcaptureOSS() override; +struct OSScapture final : public BackendBase { + OSScapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~OSScapture() override; int recordProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + int mFd{-1}; RingBufferPtr mRing{nullptr}; std::atomic mKillNow{AL_TRUE}; std::thread mThread; -}; - -void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device); -void ALCcaptureOSS_Destruct(ALCcaptureOSS *self); -ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name); -DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ALCboolean, reset) -ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self); -void ALCcaptureOSS_stop(ALCcaptureOSS *self); -ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples); -ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self); -DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, lock) -DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCcaptureOSS) -DEFINE_ALCBACKEND_VTABLE(ALCcaptureOSS); - - -void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device) -{ - new (self) ALCcaptureOSS{device}; - SET_VTABLE2(ALCcaptureOSS, ALCbackend, self); -} -void ALCcaptureOSS_Destruct(ALCcaptureOSS *self) -{ self->~ALCcaptureOSS(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "OSScapture::"; } + DEF_NEWDEL(OSScapture) +}; -ALCcaptureOSS::~ALCcaptureOSS() +OSScapture::~OSScapture() { if(mFd != -1) close(mFd); @@ -537,7 +501,7 @@ ALCcaptureOSS::~ALCcaptureOSS() } -int ALCcaptureOSS::recordProc() +int OSScapture::recordProc() { SetRTPriority(); althrd_setname(RECORD_THREAD_NAME); @@ -555,7 +519,9 @@ int ALCcaptureOSS::recordProc() if(errno == EINTR || errno == EAGAIN) continue; ERR("poll failed: %s\n", strerror(errno)); + lock(); aluHandleDisconnect(mDevice, "Failed to check capture samples: %s", strerror(errno)); + unlock(); break; } else if(sret == 0) @@ -571,10 +537,10 @@ int ALCcaptureOSS::recordProc() if(amt < 0) { ERR("read failed: %s\n", strerror(errno)); - ALCcaptureOSS_lock(this); + lock(); aluHandleDisconnect(mDevice, "Failed reading capture samples: %s", strerror(errno)); - ALCcaptureOSS_unlock(this); + unlock(); break; } mRing->writeAdvance(amt/frame_size); @@ -585,10 +551,8 @@ int ALCcaptureOSS::recordProc() } -ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) +ALCenum OSScapture::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - const char *devname{DefaultCapture}; if(!name) name = DefaultName; @@ -606,15 +570,15 @@ ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) devname = iter->device_name.c_str(); } - self->mFd = open(devname, O_RDONLY); - if(self->mFd == -1) + mFd = ::open(devname, O_RDONLY); + if(mFd == -1) { ERR("Could not open %s: %s\n", devname, strerror(errno)); return ALC_INVALID_VALUE; } int ossFormat{}; - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: ossFormat = AFMT_S8; @@ -629,15 +593,15 @@ ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) case DevFmtInt: case DevFmtUInt: case DevFmtFloat: - ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); + ERR("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); return ALC_INVALID_VALUE; } int periods{4}; - int numChannels{device->channelsFromFmt()}; - int frameSize{numChannels * device->bytesFromFmt()}; - int ossSpeed{static_cast(device->Frequency)}; - int log2FragmentSize{log2i(device->UpdateSize * device->NumUpdates * + int numChannels{mDevice->channelsFromFmt()}; + int frameSize{numChannels * mDevice->bytesFromFmt()}; + int ossSpeed{static_cast(mDevice->Frequency)}; + int log2FragmentSize{log2i(mDevice->UpdateSize * mDevice->NumUpdates * frameSize / periods)}; /* according to the OSS spec, 16 bytes are the minimum */ @@ -650,57 +614,58 @@ ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) err = #func; \ goto err; \ } - CHECKERR(ioctl(self->mFd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize)); - CHECKERR(ioctl(self->mFd, SNDCTL_DSP_SETFMT, &ossFormat)); - CHECKERR(ioctl(self->mFd, SNDCTL_DSP_CHANNELS, &numChannels)); - CHECKERR(ioctl(self->mFd, SNDCTL_DSP_SPEED, &ossSpeed)); - CHECKERR(ioctl(self->mFd, SNDCTL_DSP_GETISPACE, &info)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_SETFMT, &ossFormat)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_CHANNELS, &numChannels)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_SPEED, &ossSpeed)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_GETISPACE, &info)); if(0) { err: ERR("%s failed: %s\n", err, strerror(errno)); - close(self->mFd); - self->mFd = -1; + close(mFd); + mFd = -1; return ALC_INVALID_VALUE; } #undef CHECKERR - if(device->channelsFromFmt() != numChannels) + if(mDevice->channelsFromFmt() != numChannels) { - ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); - close(self->mFd); - self->mFd = -1; + ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(mDevice->FmtChans), + numChannels); + close(mFd); + mFd = -1; return ALC_INVALID_VALUE; } - if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) || - (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) || - (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort))) + if(!((ossFormat == AFMT_S8 && mDevice->FmtType == DevFmtByte) || + (ossFormat == AFMT_U8 && mDevice->FmtType == DevFmtUByte) || + (ossFormat == AFMT_S16_NE && mDevice->FmtType == DevFmtShort))) { - ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat); - close(self->mFd); - self->mFd = -1; + ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(mDevice->FmtType), ossFormat); + close(mFd); + mFd = -1; return ALC_INVALID_VALUE; } - self->mRing = CreateRingBuffer(device->UpdateSize*device->NumUpdates, frameSize, false); - if(!self->mRing) + mRing = CreateRingBuffer(mDevice->UpdateSize*mDevice->NumUpdates, frameSize, false); + if(!mRing) { ERR("Ring buffer create failed\n"); - close(self->mFd); - self->mFd = -1; + close(mFd); + mFd = -1; return ALC_OUT_OF_MEMORY; } - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self) +ALCboolean OSScapture::start() { try { - self->mKillNow.store(AL_FALSE); - self->mThread = std::thread{std::mem_fn(&ALCcaptureOSS::recordProc), self}; + mKillNow.store(AL_FALSE); + mThread = std::thread{std::mem_fn(&OSScapture::recordProc), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -711,29 +676,24 @@ ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self) return ALC_FALSE; } -void ALCcaptureOSS_stop(ALCcaptureOSS *self) +void OSScapture::stop() { - if(self->mKillNow.exchange(AL_TRUE) || !self->mThread.joinable()) + if(mKillNow.exchange(AL_TRUE) || !mThread.joinable()) return; + mThread.join(); - self->mThread.join(); - - if(ioctl(self->mFd, SNDCTL_DSP_RESET) != 0) + if(ioctl(mFd, SNDCTL_DSP_RESET) != 0) ERR("Error resetting device: %s\n", strerror(errno)); } -ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples) +ALCenum OSScapture::captureSamples(ALCvoid *buffer, ALCuint samples) { - RingBuffer *ring{self->mRing.get()}; - ring->read(buffer, samples); + mRing->read(buffer, samples); return ALC_NO_ERROR; } -ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self) -{ - RingBuffer *ring{self->mRing.get()}; - return ring->readSpace(); -} +ALCuint OSScapture::availableSamples() +{ return mRing->readSpace(); } } // namespace @@ -791,20 +751,11 @@ void OSSBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *OSSBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *OSSBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - ALCplaybackOSS *backend; - NEW_OBJ(backend, ALCplaybackOSS)(device); - return backend; - } + return new OSSPlayback{device}; if(type == ALCbackend_Capture) - { - ALCcaptureOSS *backend; - NEW_OBJ(backend, ALCcaptureOSS)(device); - return backend; - } - + return new OSScapture{device}; return nullptr; } diff --git a/Alc/backends/oss.h b/Alc/backends/oss.h index 4652a779..8f65f1cc 100644 --- a/Alc/backends/oss.h +++ b/Alc/backends/oss.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index 44ffd9bd..34688db9 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -130,9 +130,9 @@ bool pa_load(void) } -struct ALCportPlayback final : public ALCbackend { - ALCportPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCportPlayback() override; +struct PortPlayback final : public BackendBase { + PortPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~PortPlayback() override; static int writeCallbackC(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, @@ -140,37 +140,20 @@ struct ALCportPlayback final : public ALCbackend { int writeCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + PaStream *mStream{nullptr}; PaStreamParameters mParams{}; ALuint mUpdateSize{0u}; -}; - -void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device); -void ALCportPlayback_Destruct(ALCportPlayback *self); -ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name); -ALCboolean ALCportPlayback_reset(ALCportPlayback *self); -ALCboolean ALCportPlayback_start(ALCportPlayback *self); -void ALCportPlayback_stop(ALCportPlayback *self); -DECLARE_FORWARD2(ALCportPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -DECLARE_FORWARD(ALCportPlayback, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(ALCportPlayback, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, lock) -DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCportPlayback) - -DEFINE_ALCBACKEND_VTABLE(ALCportPlayback); - - -void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device) -{ - new (self) ALCportPlayback{device}; - SET_VTABLE2(ALCportPlayback, ALCbackend, self); -} -void ALCportPlayback_Destruct(ALCportPlayback *self) -{ self->~ALCportPlayback(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "PortPlayback::"; } + DEF_NEWDEL(PortPlayback) +}; -ALCportPlayback::~ALCportPlayback() +PortPlayback::~PortPlayback() { PaError err{mStream ? Pa_CloseStream(mStream) : paNoError}; if(err != paNoError) @@ -179,132 +162,124 @@ ALCportPlayback::~ALCportPlayback() } -int ALCportPlayback::writeCallbackC(const void *inputBuffer, void *outputBuffer, +int PortPlayback::writeCallbackC(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags, void *userData) { - return static_cast(userData)->writeCallback(inputBuffer, outputBuffer, + return static_cast(userData)->writeCallback(inputBuffer, outputBuffer, framesPerBuffer, timeInfo, statusFlags); } -int ALCportPlayback::writeCallback(const void* UNUSED(inputBuffer), void *outputBuffer, +int PortPlayback::writeCallback(const void* UNUSED(inputBuffer), void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* UNUSED(timeInfo), const PaStreamCallbackFlags UNUSED(statusFlags)) { - ALCportPlayback_lock(this); + lock(); aluMixData(mDevice, outputBuffer, framesPerBuffer); - ALCportPlayback_unlock(this); + unlock(); return 0; } -ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name) +ALCenum PortPlayback::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - PaError err; - if(!name) name = pa_device; else if(strcmp(name, pa_device) != 0) return ALC_INVALID_VALUE; - self->mUpdateSize = device->UpdateSize; + mUpdateSize = mDevice->UpdateSize; - self->mParams.device = -1; - if(!ConfigValueInt(nullptr, "port", "device", &self->mParams.device) || - self->mParams.device < 0) - self->mParams.device = Pa_GetDefaultOutputDevice(); - self->mParams.suggestedLatency = (device->UpdateSize*device->NumUpdates) / - (float)device->Frequency; - self->mParams.hostApiSpecificStreamInfo = nullptr; + mParams.device = -1; + if(!ConfigValueInt(nullptr, "port", "device", &mParams.device) || mParams.device < 0) + mParams.device = Pa_GetDefaultOutputDevice(); + mParams.suggestedLatency = (mDevice->UpdateSize*mDevice->NumUpdates) / + (float)mDevice->Frequency; + mParams.hostApiSpecificStreamInfo = nullptr; - self->mParams.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2); + mParams.channelCount = ((mDevice->FmtChans == DevFmtMono) ? 1 : 2); - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: - self->mParams.sampleFormat = paInt8; + mParams.sampleFormat = paInt8; break; case DevFmtUByte: - self->mParams.sampleFormat = paUInt8; + mParams.sampleFormat = paUInt8; break; case DevFmtUShort: /* fall-through */ case DevFmtShort: - self->mParams.sampleFormat = paInt16; + mParams.sampleFormat = paInt16; break; case DevFmtUInt: /* fall-through */ case DevFmtInt: - self->mParams.sampleFormat = paInt32; + mParams.sampleFormat = paInt32; break; case DevFmtFloat: - self->mParams.sampleFormat = paFloat32; + mParams.sampleFormat = paFloat32; break; } retry_open: - err = Pa_OpenStream(&self->mStream, nullptr, &self->mParams, - device->Frequency, device->UpdateSize, paNoFlag, - &ALCportPlayback::writeCallbackC, self - ); + PaError err{Pa_OpenStream(&mStream, nullptr, &mParams, mDevice->Frequency, mDevice->UpdateSize, + paNoFlag, &PortPlayback::writeCallbackC, this)}; if(err != paNoError) { - if(self->mParams.sampleFormat == paFloat32) + if(mParams.sampleFormat == paFloat32) { - self->mParams.sampleFormat = paInt16; + mParams.sampleFormat = paInt16; goto retry_open; } ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); return ALC_INVALID_VALUE; } - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean ALCportPlayback_reset(ALCportPlayback *self) +ALCboolean PortPlayback::reset() { - ALCdevice *device{self->mDevice}; - - const PaStreamInfo *streamInfo{Pa_GetStreamInfo(self->mStream)}; - device->Frequency = streamInfo->sampleRate; - device->UpdateSize = self->mUpdateSize; - - if(self->mParams.sampleFormat == paInt8) - device->FmtType = DevFmtByte; - else if(self->mParams.sampleFormat == paUInt8) - device->FmtType = DevFmtUByte; - else if(self->mParams.sampleFormat == paInt16) - device->FmtType = DevFmtShort; - else if(self->mParams.sampleFormat == paInt32) - device->FmtType = DevFmtInt; - else if(self->mParams.sampleFormat == paFloat32) - device->FmtType = DevFmtFloat; + const PaStreamInfo *streamInfo{Pa_GetStreamInfo(mStream)}; + mDevice->Frequency = streamInfo->sampleRate; + mDevice->UpdateSize = mUpdateSize; + + if(mParams.sampleFormat == paInt8) + mDevice->FmtType = DevFmtByte; + else if(mParams.sampleFormat == paUInt8) + mDevice->FmtType = DevFmtUByte; + else if(mParams.sampleFormat == paInt16) + mDevice->FmtType = DevFmtShort; + else if(mParams.sampleFormat == paInt32) + mDevice->FmtType = DevFmtInt; + else if(mParams.sampleFormat == paFloat32) + mDevice->FmtType = DevFmtFloat; else { - ERR("Unexpected sample format: 0x%lx\n", self->mParams.sampleFormat); + ERR("Unexpected sample format: 0x%lx\n", mParams.sampleFormat); return ALC_FALSE; } - if(self->mParams.channelCount == 2) - device->FmtChans = DevFmtStereo; - else if(self->mParams.channelCount == 1) - device->FmtChans = DevFmtMono; + if(mParams.channelCount == 2) + mDevice->FmtChans = DevFmtStereo; + else if(mParams.channelCount == 1) + mDevice->FmtChans = DevFmtMono; else { - ERR("Unexpected channel count: %u\n", self->mParams.channelCount); + ERR("Unexpected channel count: %u\n", mParams.channelCount); return ALC_FALSE; } - SetDefaultChannelOrder(device); + SetDefaultChannelOrder(mDevice); return ALC_TRUE; } -ALCboolean ALCportPlayback_start(ALCportPlayback *self) +ALCboolean PortPlayback::start() { - PaError err{Pa_StartStream(self->mStream)}; + PaError err{Pa_StartStream(mStream)}; if(err != paNoError) { ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err)); @@ -313,17 +288,17 @@ ALCboolean ALCportPlayback_start(ALCportPlayback *self) return ALC_TRUE; } -void ALCportPlayback_stop(ALCportPlayback *self) +void PortPlayback::stop() { - PaError err{Pa_StopStream(self->mStream)}; + PaError err{Pa_StopStream(mStream)}; if(err != paNoError) ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); } -struct ALCportCapture final : public ALCbackend { - ALCportCapture(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCportCapture() override; +struct PortCapture final : public BackendBase { + PortCapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~PortCapture() override; static int readCallbackC(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, @@ -331,38 +306,22 @@ struct ALCportCapture final : public ALCbackend { int readCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags); + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + PaStream *mStream{nullptr}; PaStreamParameters mParams; RingBufferPtr mRing{nullptr}; -}; - -void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device); -void ALCportCapture_Destruct(ALCportCapture *self); -ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name); -DECLARE_FORWARD(ALCportCapture, ALCbackend, ALCboolean, reset) -ALCboolean ALCportCapture_start(ALCportCapture *self); -void ALCportCapture_stop(ALCportCapture *self); -ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples); -ALCuint ALCportCapture_availableSamples(ALCportCapture *self); -DECLARE_FORWARD(ALCportCapture, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(ALCportCapture, ALCbackend, void, lock) -DECLARE_FORWARD(ALCportCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCportCapture) - -DEFINE_ALCBACKEND_VTABLE(ALCportCapture); + static constexpr inline const char *CurrentPrefix() noexcept { return "PortCapture::"; } + DEF_NEWDEL(PortCapture) +}; -void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device) -{ - new (self) ALCportCapture{device}; - SET_VTABLE2(ALCportCapture, ALCbackend, self); -} - -void ALCportCapture_Destruct(ALCportCapture *self) -{ self->~ALCportCapture(); } - -ALCportCapture::~ALCportCapture() +PortCapture::~PortCapture() { PaError err{mStream ? Pa_CloseStream(mStream) : paNoError}; if(err != paNoError) @@ -371,15 +330,15 @@ ALCportCapture::~ALCportCapture() } -int ALCportCapture::readCallbackC(const void *inputBuffer, void *outputBuffer, +int PortCapture::readCallbackC(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags, void* userData) { - return static_cast(userData)->readCallback(inputBuffer, outputBuffer, + return static_cast(userData)->readCallback(inputBuffer, outputBuffer, framesPerBuffer, timeInfo, statusFlags); } -int ALCportCapture::readCallback(const void *inputBuffer, void *UNUSED(outputBuffer), +int PortCapture::readCallback(const void *inputBuffer, void *UNUSED(outputBuffer), unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo), const PaStreamCallbackFlags UNUSED(statusFlags)) { @@ -388,73 +347,66 @@ int ALCportCapture::readCallback(const void *inputBuffer, void *UNUSED(outputBuf } -ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) +ALCenum PortCapture::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - ALuint samples, frame_size; - PaError err; - if(!name) name = pa_device; else if(strcmp(name, pa_device) != 0) return ALC_INVALID_VALUE; - samples = device->UpdateSize * device->NumUpdates; - samples = maxu(samples, 100 * device->Frequency / 1000); - frame_size = device->frameSizeFromFmt(); + ALuint samples{mDevice->UpdateSize * mDevice->NumUpdates}; + samples = maxu(samples, 100 * mDevice->Frequency / 1000); + ALsizei frame_size{mDevice->frameSizeFromFmt()}; - self->mRing = CreateRingBuffer(samples, frame_size, false); - if(!self->mRing) return ALC_INVALID_VALUE; + mRing = CreateRingBuffer(samples, frame_size, false); + if(!mRing) return ALC_INVALID_VALUE; - self->mParams.device = -1; - if(!ConfigValueInt(nullptr, "port", "capture", &self->mParams.device) || - self->mParams.device < 0) - self->mParams.device = Pa_GetDefaultInputDevice(); - self->mParams.suggestedLatency = 0.0f; - self->mParams.hostApiSpecificStreamInfo = nullptr; + mParams.device = -1; + if(!ConfigValueInt(nullptr, "port", "capture", &mParams.device) || mParams.device < 0) + mParams.device = Pa_GetDefaultInputDevice(); + mParams.suggestedLatency = 0.0f; + mParams.hostApiSpecificStreamInfo = nullptr; - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: - self->mParams.sampleFormat = paInt8; + mParams.sampleFormat = paInt8; break; case DevFmtUByte: - self->mParams.sampleFormat = paUInt8; + mParams.sampleFormat = paUInt8; break; case DevFmtShort: - self->mParams.sampleFormat = paInt16; + mParams.sampleFormat = paInt16; break; case DevFmtInt: - self->mParams.sampleFormat = paInt32; + mParams.sampleFormat = paInt32; break; case DevFmtFloat: - self->mParams.sampleFormat = paFloat32; + mParams.sampleFormat = paFloat32; break; case DevFmtUInt: case DevFmtUShort: - ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); + ERR("%s samples not supported\n", DevFmtTypeString(mDevice->FmtType)); return ALC_INVALID_VALUE; } - self->mParams.channelCount = device->channelsFromFmt(); + mParams.channelCount = mDevice->channelsFromFmt(); - err = Pa_OpenStream(&self->mStream, &self->mParams, nullptr, - device->Frequency, paFramesPerBufferUnspecified, paNoFlag, - &ALCportCapture::readCallbackC, self - ); + PaError err{Pa_OpenStream(&mStream, &mParams, nullptr, mDevice->Frequency, + paFramesPerBufferUnspecified, paNoFlag, &PortCapture::readCallbackC, this)}; if(err != paNoError) { ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); return ALC_INVALID_VALUE; } - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean ALCportCapture_start(ALCportCapture *self) +ALCboolean PortCapture::start() { - PaError err = Pa_StartStream(self->mStream); + PaError err{Pa_StartStream(mStream)}; if(err != paNoError) { ERR("Error starting stream: %s\n", Pa_GetErrorText(err)); @@ -463,24 +415,20 @@ ALCboolean ALCportCapture_start(ALCportCapture *self) return ALC_TRUE; } -void ALCportCapture_stop(ALCportCapture *self) +void PortCapture::stop() { - PaError err = Pa_StopStream(self->mStream); + PaError err{Pa_StopStream(mStream)}; if(err != paNoError) ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); } -ALCuint ALCportCapture_availableSamples(ALCportCapture *self) -{ - RingBuffer *ring{self->mRing.get()}; - return ring->readSpace(); -} +ALCuint PortCapture::availableSamples() +{ return mRing->readSpace(); } -ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum PortCapture::captureSamples(ALCvoid *buffer, ALCuint samples) { - RingBuffer *ring{self->mRing.get()}; - ring->read(buffer, samples); + mRing->read(buffer, samples); return ALC_NO_ERROR; } @@ -519,21 +467,12 @@ void PortBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *PortBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *PortBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - ALCportPlayback *backend; - NEW_OBJ(backend, ALCportPlayback)(device); - return backend; - } + return new PortPlayback{device}; if(type == ALCbackend_Capture) - { - ALCportCapture *backend; - NEW_OBJ(backend, ALCportCapture)(device); - return backend; - } - + return new PortCapture{device}; return nullptr; } diff --git a/Alc/backends/portaudio.h b/Alc/backends/portaudio.h index 581d4901..7687c6b3 100644 --- a/Alc/backends/portaudio.h +++ b/Alc/backends/portaudio.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index a99503e1..c911e365 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -729,8 +729,8 @@ void probeCaptureDevices(void) } -struct PulsePlayback final : public ALCbackend { - PulsePlayback(ALCdevice *device) noexcept : ALCbackend{device} { } +struct PulsePlayback final : public BackendBase { + PulsePlayback(ALCdevice *device) noexcept : BackendBase{device} { } ~PulsePlayback() override; static void bufferAttrCallbackC(pa_stream *stream, void *pdata); @@ -754,6 +754,14 @@ struct PulsePlayback final : public ALCbackend { static void streamMovedCallbackC(pa_stream *stream, void *pdata); void streamMovedCallback(pa_stream *stream); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + ClockLatency getClockLatency() override; + void lock() noexcept override; + void unlock() noexcept override; + std::string mDeviceName; pa_buffer_attr mAttr; @@ -768,33 +776,9 @@ struct PulsePlayback final : public ALCbackend { ALuint mFrameSize{0u}; static constexpr inline const char *CurrentPrefix() noexcept { return "PulsePlayback::"; } + DEF_NEWDEL(PulsePlayback) }; -void PulsePlayback_Construct(PulsePlayback *self, ALCdevice *device); -void PulsePlayback_Destruct(PulsePlayback *self); -ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name); -ALCboolean PulsePlayback_reset(PulsePlayback *self); -ALCboolean PulsePlayback_start(PulsePlayback *self); -void PulsePlayback_stop(PulsePlayback *self); -DECLARE_FORWARD2(PulsePlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -DECLARE_FORWARD(PulsePlayback, ALCbackend, ALCuint, availableSamples) -ClockLatency PulsePlayback_getClockLatency(PulsePlayback *self); -void PulsePlayback_lock(PulsePlayback *self); -void PulsePlayback_unlock(PulsePlayback *self); -DECLARE_DEFAULT_ALLOCATORS(PulsePlayback) - -DEFINE_ALCBACKEND_VTABLE(PulsePlayback); - - -void PulsePlayback_Construct(PulsePlayback *self, ALCdevice *device) -{ - new (self) PulsePlayback{device}; - SET_VTABLE2(PulsePlayback, ALCbackend, self); -} - -void PulsePlayback_Destruct(PulsePlayback *self) -{ self->~PulsePlayback(); } - PulsePlayback::~PulsePlayback() { if(!mLoop) @@ -960,7 +944,7 @@ void PulsePlayback::streamMovedCallback(pa_stream *stream) } -ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) +ALCenum PulsePlayback::open(const ALCchar *name) { const char *pulse_name{nullptr}; const char *dev_name{nullptr}; @@ -980,10 +964,10 @@ ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) dev_name = iter->name.c_str(); } - std::tie(self->mLoop, self->mContext) = pulse_open(&PulsePlayback::contextStateCallbackC, self); - if(!self->mLoop) return ALC_INVALID_VALUE; + std::tie(mLoop, mContext) = pulse_open(&PulsePlayback::contextStateCallbackC, this); + if(!mLoop) return ALC_INVALID_VALUE; - unique_palock palock{self->mLoop}; + unique_palock palock{mLoop}; pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS}; @@ -1001,93 +985,89 @@ ALCenum PulsePlayback_open(PulsePlayback *self, const ALCchar *name) pulse_name = getenv("ALSOFT_PULSE_DEFAULT"); if(pulse_name && !pulse_name[0]) pulse_name = nullptr; } - self->mStream = pulse_connect_stream(pulse_name, self->mLoop, self->mContext, flags, nullptr, - &spec, nullptr, ALCbackend_Playback); - if(!self->mStream) + mStream = pulse_connect_stream(pulse_name, mLoop, mContext, flags, nullptr, &spec, nullptr, + ALCbackend_Playback); + if(!mStream) { palock = unique_palock{}; - pulse_close(self->mLoop, self->mContext, self->mStream); - self->mLoop = nullptr; - self->mContext = nullptr; + pulse_close(mLoop, mContext, mStream); + mLoop = nullptr; + mContext = nullptr; return ALC_INVALID_VALUE; } - pa_stream_set_moved_callback(self->mStream, &PulsePlayback::streamMovedCallbackC, self); - self->mFrameSize = pa_frame_size(pa_stream_get_sample_spec(self->mStream)); + pa_stream_set_moved_callback(mStream, &PulsePlayback::streamMovedCallbackC, this); + mFrameSize = pa_frame_size(pa_stream_get_sample_spec(mStream)); - self->mDeviceName = pa_stream_get_device_name(self->mStream); + mDeviceName = pa_stream_get_device_name(mStream); if(!dev_name) { - pa_operation *op{pa_context_get_sink_info_by_name(self->mContext, - self->mDeviceName.c_str(), &PulsePlayback::sinkNameCallbackC, self)}; - wait_for_operation(op, self->mLoop); + pa_operation *op{pa_context_get_sink_info_by_name(mContext, mDeviceName.c_str(), + &PulsePlayback::sinkNameCallbackC, this)}; + wait_for_operation(op, mLoop); } else - { - ALCdevice *device{self->mDevice}; - device->DeviceName = dev_name; - } + mDevice->DeviceName = dev_name; return ALC_NO_ERROR; } -ALCboolean PulsePlayback_reset(PulsePlayback *self) +ALCboolean PulsePlayback::reset() { - unique_palock palock{self->mLoop}; + unique_palock palock{mLoop}; - if(self->mStream) + if(mStream) { - pa_stream_set_state_callback(self->mStream, nullptr, nullptr); - pa_stream_set_moved_callback(self->mStream, nullptr, nullptr); - pa_stream_set_write_callback(self->mStream, nullptr, nullptr); - pa_stream_set_buffer_attr_callback(self->mStream, nullptr, nullptr); - pa_stream_disconnect(self->mStream); - pa_stream_unref(self->mStream); - self->mStream = nullptr; + pa_stream_set_state_callback(mStream, nullptr, nullptr); + pa_stream_set_moved_callback(mStream, nullptr, nullptr); + pa_stream_set_write_callback(mStream, nullptr, nullptr); + pa_stream_set_buffer_attr_callback(mStream, nullptr, nullptr); + pa_stream_disconnect(mStream); + pa_stream_unref(mStream); + mStream = nullptr; } - pa_operation *op{pa_context_get_sink_info_by_name(self->mContext, - self->mDeviceName.c_str(), &PulsePlayback::sinkInfoCallbackC, self)}; - wait_for_operation(op, self->mLoop); + pa_operation *op{pa_context_get_sink_info_by_name(mContext, mDeviceName.c_str(), + &PulsePlayback::sinkInfoCallbackC, this)}; + wait_for_operation(op, mLoop); - ALCdevice *device{self->mDevice}; pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE}; if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 0)) flags |= PA_STREAM_DONT_MOVE; - if(GetConfigValueBool(device->DeviceName.c_str(), "pulse", "adjust-latency", 0)) + if(GetConfigValueBool(mDevice->DeviceName.c_str(), "pulse", "adjust-latency", 0)) flags |= PA_STREAM_ADJUST_LATENCY; - if(GetConfigValueBool(device->DeviceName.c_str(), "pulse", "fix-rate", 0) || - !(device->Flags&DEVICE_FREQUENCY_REQUEST)) + if(GetConfigValueBool(mDevice->DeviceName.c_str(), "pulse", "fix-rate", 0) || + !(mDevice->Flags&DEVICE_FREQUENCY_REQUEST)) flags |= PA_STREAM_FIX_RATE; - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: - device->FmtType = DevFmtUByte; + mDevice->FmtType = DevFmtUByte; /* fall-through */ case DevFmtUByte: - self->mSpec.format = PA_SAMPLE_U8; + mSpec.format = PA_SAMPLE_U8; break; case DevFmtUShort: - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; /* fall-through */ case DevFmtShort: - self->mSpec.format = PA_SAMPLE_S16NE; + mSpec.format = PA_SAMPLE_S16NE; break; case DevFmtUInt: - device->FmtType = DevFmtInt; + mDevice->FmtType = DevFmtInt; /* fall-through */ case DevFmtInt: - self->mSpec.format = PA_SAMPLE_S32NE; + mSpec.format = PA_SAMPLE_S32NE; break; case DevFmtFloat: - self->mSpec.format = PA_SAMPLE_FLOAT32NE; + mSpec.format = PA_SAMPLE_FLOAT32NE; break; } - self->mSpec.rate = device->Frequency; - self->mSpec.channels = device->channelsFromFmt(); + mSpec.rate = mDevice->Frequency; + mSpec.channels = mDevice->channelsFromFmt(); - if(pa_sample_spec_valid(&self->mSpec) == 0) + if(pa_sample_spec_valid(&mSpec) == 0) { ERR("Invalid sample format\n"); return ALC_FALSE; @@ -1095,13 +1075,13 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) const char *mapname{nullptr}; pa_channel_map chanmap; - switch(device->FmtChans) + switch(mDevice->FmtChans) { case DevFmtMono: mapname = "mono"; break; case DevFmtAmbi3D: - device->FmtChans = DevFmtStereo; + mDevice->FmtChans = DevFmtStereo; /*fall-through*/ case DevFmtStereo: mapname = "front-left,front-right"; @@ -1124,54 +1104,52 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) } if(!pa_channel_map_parse(&chanmap, mapname)) { - ERR("Failed to build channel map for %s\n", DevFmtChannelsString(device->FmtChans)); + ERR("Failed to build channel map for %s\n", DevFmtChannelsString(mDevice->FmtChans)); return ALC_FALSE; } - SetDefaultWFXChannelOrder(device); + SetDefaultWFXChannelOrder(mDevice); - size_t period_size{device->UpdateSize * pa_frame_size(&self->mSpec)}; - self->mAttr.maxlength = -1; - self->mAttr.tlength = period_size * maxu(device->NumUpdates, 2); - self->mAttr.prebuf = 0; - self->mAttr.minreq = period_size; - self->mAttr.fragsize = -1; + size_t period_size{mDevice->UpdateSize * pa_frame_size(&mSpec)}; + mAttr.maxlength = -1; + mAttr.tlength = period_size * maxu(mDevice->NumUpdates, 2); + mAttr.prebuf = 0; + mAttr.minreq = period_size; + mAttr.fragsize = -1; - self->mStream = pulse_connect_stream(self->mDeviceName.c_str(), self->mLoop, self->mContext, - flags, &self->mAttr, &self->mSpec, &chanmap, ALCbackend_Playback); - if(!self->mStream) return ALC_FALSE; + mStream = pulse_connect_stream(mDeviceName.c_str(), mLoop, mContext, flags, &mAttr, &mSpec, + &chanmap, ALCbackend_Playback); + if(!mStream) return ALC_FALSE; - pa_stream_set_state_callback(self->mStream, &PulsePlayback::streamStateCallbackC, self); - pa_stream_set_moved_callback(self->mStream, &PulsePlayback::streamMovedCallbackC, self); + pa_stream_set_state_callback(mStream, &PulsePlayback::streamStateCallbackC, this); + pa_stream_set_moved_callback(mStream, &PulsePlayback::streamMovedCallbackC, this); - self->mSpec = *(pa_stream_get_sample_spec(self->mStream)); - self->mFrameSize = pa_frame_size(&self->mSpec); + mSpec = *(pa_stream_get_sample_spec(mStream)); + mFrameSize = pa_frame_size(&mSpec); - if(device->Frequency != self->mSpec.rate) + if(mDevice->Frequency != mSpec.rate) { /* Server updated our playback rate, so modify the buffer attribs * accordingly. */ - device->NumUpdates = static_cast(clampd( - (ALdouble)self->mSpec.rate/device->Frequency*device->NumUpdates + 0.5, 2.0, 16.0)); + mDevice->NumUpdates = static_cast(clampd( + (ALdouble)mSpec.rate/mDevice->Frequency*mDevice->NumUpdates + 0.5, 2.0, 16.0)); - period_size = device->UpdateSize * self->mFrameSize; - self->mAttr.maxlength = -1; - self->mAttr.tlength = period_size * maxu(device->NumUpdates, 2); - self->mAttr.prebuf = 0; - self->mAttr.minreq = period_size; + period_size = mDevice->UpdateSize * mFrameSize; + mAttr.maxlength = -1; + mAttr.tlength = period_size * maxu(mDevice->NumUpdates, 2); + mAttr.prebuf = 0; + mAttr.minreq = period_size; - op = pa_stream_set_buffer_attr(self->mStream, &self->mAttr, stream_success_callback, - self->mLoop); - wait_for_operation(op, self->mLoop); + op = pa_stream_set_buffer_attr(mStream, &mAttr, stream_success_callback, mLoop); + wait_for_operation(op, mLoop); - device->Frequency = self->mSpec.rate; + mDevice->Frequency = mSpec.rate; } - pa_stream_set_buffer_attr_callback(self->mStream, &PulsePlayback::bufferAttrCallbackC, self); - self->bufferAttrCallback(self->mStream); + pa_stream_set_buffer_attr_callback(mStream, &PulsePlayback::bufferAttrCallbackC, this); + bufferAttrCallback(mStream); - device->NumUpdates = clampu( - (self->mAttr.tlength + self->mAttr.minreq/2u) / self->mAttr.minreq, 2u, 16u); - device->UpdateSize = self->mAttr.minreq / self->mFrameSize; + mDevice->NumUpdates = clampu((mAttr.tlength + mAttr.minreq/2u) / mAttr.minreq, 2u, 16u); + mDevice->UpdateSize = mAttr.minreq / mFrameSize; /* HACK: prebuf should be 0 as that's what we set it to. However on some * systems it comes back as non-0, so we have to make sure the device will @@ -1179,53 +1157,53 @@ ALCboolean PulsePlayback_reset(PulsePlayback *self) * may have unintended consequences, but it's better than not starting at * all. */ - if(self->mAttr.prebuf != 0) + if(mAttr.prebuf != 0) { - ALuint len{self->mAttr.prebuf / self->mFrameSize}; - if(len <= device->UpdateSize*device->NumUpdates) + ALuint len{mAttr.prebuf / mFrameSize}; + if(len <= mDevice->UpdateSize*mDevice->NumUpdates) ERR("Non-0 prebuf, %u samples (%u bytes), device has %u samples\n", - len, self->mAttr.prebuf, device->UpdateSize*device->NumUpdates); + len, mAttr.prebuf, mDevice->UpdateSize*mDevice->NumUpdates); else { ERR("Large prebuf, %u samples (%u bytes), increasing device from %u samples", - len, self->mAttr.prebuf, device->UpdateSize*device->NumUpdates); - device->NumUpdates = (len+device->UpdateSize-1) / device->UpdateSize; + len, mAttr.prebuf, mDevice->UpdateSize*mDevice->NumUpdates); + mDevice->NumUpdates = (len+mDevice->UpdateSize-1) / mDevice->UpdateSize; } } return ALC_TRUE; } -ALCboolean PulsePlayback_start(PulsePlayback *self) +ALCboolean PulsePlayback::start() { - unique_palock palock{self->mLoop}; + unique_palock palock{mLoop}; - pa_stream_set_write_callback(self->mStream, &PulsePlayback::streamWriteCallbackC, self); - pa_operation *op{pa_stream_cork(self->mStream, 0, stream_success_callback, self->mLoop)}; - wait_for_operation(op, self->mLoop); + pa_stream_set_write_callback(mStream, &PulsePlayback::streamWriteCallbackC, this); + pa_operation *op{pa_stream_cork(mStream, 0, stream_success_callback, mLoop)}; + wait_for_operation(op, mLoop); return ALC_TRUE; } -void PulsePlayback_stop(PulsePlayback *self) +void PulsePlayback::stop() { - unique_palock palock{self->mLoop}; + unique_palock palock{mLoop}; - pa_stream_set_write_callback(self->mStream, nullptr, nullptr); - pa_operation *op{pa_stream_cork(self->mStream, 1, stream_success_callback, self->mLoop)}; - wait_for_operation(op, self->mLoop); + pa_stream_set_write_callback(mStream, nullptr, nullptr); + pa_operation *op{pa_stream_cork(mStream, 1, stream_success_callback, mLoop)}; + wait_for_operation(op, mLoop); } -ClockLatency PulsePlayback_getClockLatency(PulsePlayback *self) +ClockLatency PulsePlayback::getClockLatency() { ClockLatency ret; pa_usec_t latency; int neg, err; - { palock_guard _{self->mLoop}; - ret.ClockTime = GetDeviceClockTime(self->mDevice); - err = pa_stream_get_latency(self->mStream, &latency, &neg); + { palock_guard _{mLoop}; + ret.ClockTime = GetDeviceClockTime(mDevice); + err = pa_stream_get_latency(mStream, &latency, &neg); } if(UNLIKELY(err != 0)) @@ -1247,19 +1225,15 @@ ClockLatency PulsePlayback_getClockLatency(PulsePlayback *self) } -void PulsePlayback_lock(PulsePlayback *self) -{ - pa_threaded_mainloop_lock(self->mLoop); -} +void PulsePlayback::lock() noexcept +{ pa_threaded_mainloop_lock(mLoop); } -void PulsePlayback_unlock(PulsePlayback *self) -{ - pa_threaded_mainloop_unlock(self->mLoop); -} +void PulsePlayback::unlock() noexcept +{ pa_threaded_mainloop_unlock(mLoop); } -struct PulseCapture final : public ALCbackend { - PulseCapture(ALCdevice *device) noexcept : ALCbackend{device} { } +struct PulseCapture final : public BackendBase { + PulseCapture(ALCdevice *device) noexcept : BackendBase{device} { } ~PulseCapture() override; static void contextStateCallbackC(pa_context *context, void *pdata); @@ -1274,6 +1248,15 @@ struct PulseCapture final : public ALCbackend { static void streamMovedCallbackC(pa_stream *stream, void *pdata); void streamMovedCallback(pa_stream *stream); + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + ClockLatency getClockLatency() override; + void lock() noexcept override; + void unlock() noexcept override; + std::string mDeviceName; const void *mCapStore{nullptr}; @@ -1291,33 +1274,9 @@ struct PulseCapture final : public ALCbackend { pa_context *mContext{nullptr}; static constexpr inline const char *CurrentPrefix() noexcept { return "PulseCapture::"; } + DEF_NEWDEL(PulseCapture) }; -void PulseCapture_Construct(PulseCapture *self, ALCdevice *device); -void PulseCapture_Destruct(PulseCapture *self); -ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name); -DECLARE_FORWARD(PulseCapture, ALCbackend, ALCboolean, reset) -ALCboolean PulseCapture_start(PulseCapture *self); -void PulseCapture_stop(PulseCapture *self); -ALCenum PulseCapture_captureSamples(PulseCapture *self, ALCvoid *buffer, ALCuint samples); -ALCuint PulseCapture_availableSamples(PulseCapture *self); -ClockLatency PulseCapture_getClockLatency(PulseCapture *self); -void PulseCapture_lock(PulseCapture *self); -void PulseCapture_unlock(PulseCapture *self); -DECLARE_DEFAULT_ALLOCATORS(PulseCapture) - -DEFINE_ALCBACKEND_VTABLE(PulseCapture); - - -void PulseCapture_Construct(PulseCapture *self, ALCdevice *device) -{ - new (self) PulseCapture{device}; - SET_VTABLE2(PulseCapture, ALCbackend, self); -} - -void PulseCapture_Destruct(PulseCapture *self) -{ self->~PulseCapture(); } - PulseCapture::~PulseCapture() { if(!mLoop) @@ -1377,11 +1336,9 @@ void PulseCapture::streamMovedCallback(pa_stream *stream) } -ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) +ALCenum PulseCapture::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; const char *pulse_name{nullptr}; - if(name) { if(CaptureDevices.empty()) @@ -1394,38 +1351,38 @@ ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) if(iter == CaptureDevices.cend()) return ALC_INVALID_VALUE; pulse_name = iter->device_name.c_str(); - device->DeviceName = iter->name; + mDevice->DeviceName = iter->name; } - std::tie(self->mLoop, self->mContext) = pulse_open(&PulseCapture::contextStateCallbackC, self); - if(!self->mLoop) return ALC_INVALID_VALUE; + std::tie(mLoop, mContext) = pulse_open(&PulseCapture::contextStateCallbackC, this); + if(!mLoop) return ALC_INVALID_VALUE; - unique_palock palock{self->mLoop}; + unique_palock palock{mLoop}; - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtUByte: - self->mSpec.format = PA_SAMPLE_U8; + mSpec.format = PA_SAMPLE_U8; break; case DevFmtShort: - self->mSpec.format = PA_SAMPLE_S16NE; + mSpec.format = PA_SAMPLE_S16NE; break; case DevFmtInt: - self->mSpec.format = PA_SAMPLE_S32NE; + mSpec.format = PA_SAMPLE_S32NE; break; case DevFmtFloat: - self->mSpec.format = PA_SAMPLE_FLOAT32NE; + mSpec.format = PA_SAMPLE_FLOAT32NE; break; case DevFmtByte: case DevFmtUShort: case DevFmtUInt: - ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); + ERR("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); return ALC_INVALID_VALUE; } const char *mapname{nullptr}; pa_channel_map chanmap; - switch(device->FmtChans) + switch(mDevice->FmtChans) { case DevFmtMono: mapname = "mono"; @@ -1449,166 +1406,161 @@ ALCenum PulseCapture_open(PulseCapture *self, const ALCchar *name) mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right"; break; case DevFmtAmbi3D: - ERR("%s capture samples not supported\n", DevFmtChannelsString(device->FmtChans)); + ERR("%s capture samples not supported\n", DevFmtChannelsString(mDevice->FmtChans)); return ALC_INVALID_VALUE; } if(!pa_channel_map_parse(&chanmap, mapname)) { - ERR("Failed to build channel map for %s\n", DevFmtChannelsString(device->FmtChans)); + ERR("Failed to build channel map for %s\n", DevFmtChannelsString(mDevice->FmtChans)); return ALC_INVALID_VALUE; } - self->mSpec.rate = device->Frequency; - self->mSpec.channels = device->channelsFromFmt(); + mSpec.rate = mDevice->Frequency; + mSpec.channels = mDevice->channelsFromFmt(); - if(pa_sample_spec_valid(&self->mSpec) == 0) + if(pa_sample_spec_valid(&mSpec) == 0) { ERR("Invalid sample format\n"); return ALC_INVALID_VALUE; } - if(!pa_channel_map_init_auto(&chanmap, self->mSpec.channels, PA_CHANNEL_MAP_WAVEEX)) + if(!pa_channel_map_init_auto(&chanmap, mSpec.channels, PA_CHANNEL_MAP_WAVEEX)) { - ERR("Couldn't build map for channel count (%d)!\n", self->mSpec.channels); + ERR("Couldn't build map for channel count (%d)!\n", mSpec.channels); return ALC_INVALID_VALUE; } - ALuint samples{device->UpdateSize * device->NumUpdates}; - samples = maxu(samples, 100 * device->Frequency / 1000); + ALuint samples{mDevice->UpdateSize * mDevice->NumUpdates}; + samples = maxu(samples, 100 * mDevice->Frequency / 1000); - self->mAttr.minreq = -1; - self->mAttr.prebuf = -1; - self->mAttr.maxlength = samples * pa_frame_size(&self->mSpec); - self->mAttr.tlength = -1; - self->mAttr.fragsize = minu(samples, 50*device->Frequency/1000) * - pa_frame_size(&self->mSpec); + mAttr.minreq = -1; + mAttr.prebuf = -1; + mAttr.maxlength = samples * pa_frame_size(&mSpec); + mAttr.tlength = -1; + mAttr.fragsize = minu(samples, 50*mDevice->Frequency/1000) * pa_frame_size(&mSpec); pa_stream_flags_t flags{PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY}; if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 0)) flags |= PA_STREAM_DONT_MOVE; TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); - self->mStream = pulse_connect_stream(pulse_name, self->mLoop, self->mContext, flags, - &self->mAttr, &self->mSpec, &chanmap, ALCbackend_Capture); - if(!self->mStream) return ALC_INVALID_VALUE; + mStream = pulse_connect_stream(pulse_name, mLoop, mContext, flags, &mAttr, &mSpec, &chanmap, + ALCbackend_Capture); + if(!mStream) return ALC_INVALID_VALUE; - pa_stream_set_moved_callback(self->mStream, &PulseCapture::streamMovedCallbackC, self); - pa_stream_set_state_callback(self->mStream, &PulseCapture::streamStateCallbackC, self); + pa_stream_set_moved_callback(mStream, &PulseCapture::streamMovedCallbackC, this); + pa_stream_set_state_callback(mStream, &PulseCapture::streamStateCallbackC, this); - self->mDeviceName = pa_stream_get_device_name(self->mStream); - if(device->DeviceName.empty()) + mDeviceName = pa_stream_get_device_name(mStream); + if(mDevice->DeviceName.empty()) { - pa_operation *op{pa_context_get_source_info_by_name(self->mContext, - self->mDeviceName.c_str(), &PulseCapture::sourceNameCallbackC, self - )}; - wait_for_operation(op, self->mLoop); + pa_operation *op{pa_context_get_source_info_by_name(mContext, mDeviceName.c_str(), + &PulseCapture::sourceNameCallbackC, this)}; + wait_for_operation(op, mLoop); } return ALC_NO_ERROR; } -ALCboolean PulseCapture_start(PulseCapture *self) +ALCboolean PulseCapture::start() { - palock_guard _{self->mLoop}; - pa_operation *op{pa_stream_cork(self->mStream, 0, stream_success_callback, self->mLoop)}; - wait_for_operation(op, self->mLoop); + palock_guard _{mLoop}; + pa_operation *op{pa_stream_cork(mStream, 0, stream_success_callback, mLoop)}; + wait_for_operation(op, mLoop); return ALC_TRUE; } -void PulseCapture_stop(PulseCapture *self) +void PulseCapture::stop() { - palock_guard _{self->mLoop}; - pa_operation *op{pa_stream_cork(self->mStream, 1, stream_success_callback, self->mLoop)}; - wait_for_operation(op, self->mLoop); + palock_guard _{mLoop}; + pa_operation *op{pa_stream_cork(mStream, 1, stream_success_callback, mLoop)}; + wait_for_operation(op, mLoop); } -ALCenum PulseCapture_captureSamples(PulseCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum PulseCapture::captureSamples(ALCvoid *buffer, ALCuint samples) { - ALCdevice *device{self->mDevice}; - ALCuint todo{samples * static_cast(pa_frame_size(&self->mSpec))}; + ALCuint todo{samples * static_cast(pa_frame_size(&mSpec))}; /* Capture is done in fragment-sized chunks, so we loop until we get all * that's available */ - self->mLastReadable -= todo; - unique_palock palock{self->mLoop}; + mLastReadable -= todo; + unique_palock palock{mLoop}; while(todo > 0) { size_t rem{todo}; - if(self->mCapLen == 0) + if(mCapLen == 0) { - pa_stream_state_t state{pa_stream_get_state(self->mStream)}; + pa_stream_state_t state{pa_stream_get_state(mStream)}; if(!PA_STREAM_IS_GOOD(state)) { - aluHandleDisconnect(device, "Bad capture state: %u", state); + aluHandleDisconnect(mDevice, "Bad capture state: %u", state); return ALC_INVALID_DEVICE; } - if(pa_stream_peek(self->mStream, &self->mCapStore, &self->mCapLen) < 0) + if(pa_stream_peek(mStream, &mCapStore, &mCapLen) < 0) { ERR("pa_stream_peek() failed: %s\n", - pa_strerror(pa_context_errno(self->mContext))); - aluHandleDisconnect(device, "Failed retrieving capture samples: %s", - pa_strerror(pa_context_errno(self->mContext))); + pa_strerror(pa_context_errno(mContext))); + aluHandleDisconnect(mDevice, "Failed retrieving capture samples: %s", + pa_strerror(pa_context_errno(mContext))); return ALC_INVALID_DEVICE; } - self->mCapRemain = self->mCapLen; + mCapRemain = mCapLen; } - if(rem > self->mCapRemain) - rem = self->mCapRemain; + rem = minz(rem, mCapRemain); - memcpy(buffer, self->mCapStore, rem); + memcpy(buffer, mCapStore, rem); buffer = (ALbyte*)buffer + rem; todo -= rem; - self->mCapStore = (ALbyte*)self->mCapStore + rem; - self->mCapRemain -= rem; - if(self->mCapRemain == 0) + mCapStore = (ALbyte*)mCapStore + rem; + mCapRemain -= rem; + if(mCapRemain == 0) { - pa_stream_drop(self->mStream); - self->mCapLen = 0; + pa_stream_drop(mStream); + mCapLen = 0; } } palock.unlock(); if(todo > 0) - memset(buffer, ((device->FmtType==DevFmtUByte) ? 0x80 : 0), todo); + memset(buffer, ((mDevice->FmtType==DevFmtUByte) ? 0x80 : 0), todo); return ALC_NO_ERROR; } -ALCuint PulseCapture_availableSamples(PulseCapture *self) +ALCuint PulseCapture::availableSamples() { - ALCdevice *device{self->mDevice}; - size_t readable{self->mCapRemain}; + size_t readable{mCapRemain}; - if(device->Connected.load(std::memory_order_acquire)) + if(mDevice->Connected.load(std::memory_order_acquire)) { - palock_guard _{self->mLoop}; - size_t got{pa_stream_readable_size(self->mStream)}; + palock_guard _{mLoop}; + size_t got{pa_stream_readable_size(mStream)}; if(static_cast(got) < 0) { ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got)); - aluHandleDisconnect(device, "Failed getting readable size: %s", pa_strerror(got)); + aluHandleDisconnect(mDevice, "Failed getting readable size: %s", pa_strerror(got)); } - else if(got > self->mCapLen) - readable += got - self->mCapLen; + else if(got > mCapLen) + readable += got - mCapLen; } - if(self->mLastReadable < readable) - self->mLastReadable = readable; - return self->mLastReadable / pa_frame_size(&self->mSpec); + if(mLastReadable < readable) + mLastReadable = readable; + return mLastReadable / pa_frame_size(&mSpec); } -ClockLatency PulseCapture_getClockLatency(PulseCapture *self) +ClockLatency PulseCapture::getClockLatency() { ClockLatency ret; pa_usec_t latency; int neg, err; - { palock_guard _{self->mLoop}; - ret.ClockTime = GetDeviceClockTime(self->mDevice); - err = pa_stream_get_latency(self->mStream, &latency, &neg); + { palock_guard _{mLoop}; + ret.ClockTime = GetDeviceClockTime(mDevice); + err = pa_stream_get_latency(mStream, &latency, &neg); } if(UNLIKELY(err != 0)) @@ -1625,15 +1577,11 @@ ClockLatency PulseCapture_getClockLatency(PulseCapture *self) } -void PulseCapture_lock(PulseCapture *self) -{ - pa_threaded_mainloop_lock(self->mLoop); -} +void PulseCapture::lock() noexcept +{ pa_threaded_mainloop_lock(mLoop); } -void PulseCapture_unlock(PulseCapture *self) -{ - pa_threaded_mainloop_unlock(self->mLoop); -} +void PulseCapture::unlock() noexcept +{ pa_threaded_mainloop_unlock(mLoop); } } // namespace @@ -1720,21 +1668,12 @@ void PulseBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *PulseBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *PulseBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - PulsePlayback *backend; - NEW_OBJ(backend, PulsePlayback)(device); - return backend; - } + return new PulsePlayback{device}; if(type == ALCbackend_Capture) - { - PulseCapture *backend; - NEW_OBJ(backend, PulseCapture)(device); - return backend; - } - + return new PulseCapture{device}; return nullptr; } diff --git a/Alc/backends/pulseaudio.h b/Alc/backends/pulseaudio.h index eb7045dc..07d74b64 100644 --- a/Alc/backends/pulseaudio.h +++ b/Alc/backends/pulseaudio.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index c7c8e90b..7641ad57 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -170,26 +170,20 @@ void deviceList(int type, al::vector *devmap) /* Wrappers to use an old-style backend with the new interface. */ -struct PlaybackWrapper final : public ALCbackend { - PlaybackWrapper(ALCdevice *device) noexcept : ALCbackend{device} { } +struct PlaybackWrapper final : public BackendBase { + PlaybackWrapper(ALCdevice *device) noexcept : BackendBase{device} { } ~PlaybackWrapper() override; + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + std::unique_ptr mExtraData; -}; -static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device); -static void PlaybackWrapper_Destruct(PlaybackWrapper *self); -static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name); -static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self); -static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self); -static void PlaybackWrapper_stop(PlaybackWrapper *self); -static DECLARE_FORWARD2(PlaybackWrapper, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, lock) -static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(PlaybackWrapper) -DEFINE_ALCBACKEND_VTABLE(PlaybackWrapper); + static constexpr inline const char *CurrentPrefix() noexcept { return "PlaybackWrapper::"; } + DEF_NEWDEL(PlaybackWrapper) +}; FORCE_ALIGN static int qsa_proc_playback(void *ptr) @@ -213,7 +207,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) const ALint frame_size = device->frameSizeFromFmt(); - PlaybackWrapper_lock(self); + self->lock(); while(!data->mKillNow.load(std::memory_order_acquire)) { pollfd pollitem{}; @@ -221,9 +215,9 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) pollitem.events = POLLOUT; /* Select also works like time slice to OS */ - PlaybackWrapper_unlock(self); + self->unlock(); sret = poll(&pollitem, 1, 2000); - PlaybackWrapper_lock(self); + self->lock(); if(sret == -1) { if(errno == EINTR || errno == EAGAIN) @@ -272,7 +266,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) } } } - PlaybackWrapper_unlock(self); + self->unlock(); return 0; } @@ -614,68 +608,44 @@ static void qsa_stop_playback(PlaybackWrapper *self) } -static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device) -{ - new (self) PlaybackWrapper{device}; - SET_VTABLE2(PlaybackWrapper, ALCbackend, self); -} - -static void PlaybackWrapper_Destruct(PlaybackWrapper *self) -{ self->~PlaybackWrapper(); } - PlaybackWrapper::~PlaybackWrapper() { if(mExtraData) qsa_close_playback(this); } -static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name) -{ - return qsa_open_playback(self, name); -} - -static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self) -{ - return qsa_reset_playback(self); -} +ALCenum PlaybackWrapper::open(const ALCchar *name) +{ return qsa_open_playback(this, name); } -static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self) -{ - return qsa_start_playback(self); -} +ALCboolean PlaybackWrapper::reset() +{ return qsa_reset_playback(this); } -static void PlaybackWrapper_stop(PlaybackWrapper *self) -{ - qsa_stop_playback(self); -} +ALCboolean PlaybackWrapper::start() +{ return qsa_start_playback(this); } +void PlaybackWrapper::stop() +{ qsa_stop_playback(this); } /***********/ /* Capture */ /***********/ -struct CaptureWrapper final : public ALCbackend { - CaptureWrapper(ALCdevice *device) noexcept : ALCbackend{device} { } +struct CaptureWrapper final : public BackendBase { + CaptureWrapper(ALCdevice *device) noexcept : BackendBase{device} { } ~CaptureWrapper() override; - std::unique_ptr mExtraData; -}; + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; -static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device); -static void CaptureWrapper_Destruct(CaptureWrapper *self); -static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name); -static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ALCboolean, reset) -static ALCboolean CaptureWrapper_start(CaptureWrapper *self); -static void CaptureWrapper_stop(CaptureWrapper *self); -static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples); -static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self); -static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, lock) -static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(CaptureWrapper) -DEFINE_ALCBACKEND_VTABLE(CaptureWrapper); + std::unique_ptr mExtraData; + static constexpr inline const char *CurrentPrefix() noexcept { return "CaptureWrapper::"; } + DEF_NEWDEL(CaptureWrapper) +}; static ALCenum qsa_open_capture(CaptureWrapper *self, const ALCchar *deviceName) { @@ -917,46 +887,26 @@ static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuin } -static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device) -{ - new (self) CaptureWrapper{device}; - SET_VTABLE2(CaptureWrapper, ALCbackend, self); -} - -static void CaptureWrapper_Destruct(CaptureWrapper *self) -{ self->~CaptureWrapper(); } - CaptureWrapper::~CaptureWrapper() { if(mExtraData) qsa_close_capture(this); } -static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name) -{ - return qsa_open_capture(self, name); -} +ALCenum CaptureWrapper::open(const ALCchar *name) +{ return qsa_open_capture(this, name); } -static ALCboolean CaptureWrapper_start(CaptureWrapper *self) -{ - qsa_start_capture(self); - return ALC_TRUE; -} +ALCboolean CaptureWrapper::start() +{ qsa_start_capture(this); return ALC_TRUE; } -static void CaptureWrapper_stop(CaptureWrapper *self) -{ - qsa_stop_capture(self); -} +void CaptureWrapper::stop() +{ qsa_stop_capture(this); } -static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples) -{ - return qsa_capture_samples(self, buffer, samples); -} +ALCenum CaptureWrapper::captureSamples(void *buffer, ALCuint samples) +{ return qsa_capture_samples(this, buffer, samples); } -static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self) -{ - return qsa_available_samples(self); -} +ALCuint CaptureWrapper::availableSamples() +{ return qsa_available_samples(this); } } // namespace @@ -1002,22 +952,13 @@ void QSABackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *QSABackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *QSABackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - PlaybackWrapper *backend; - NEW_OBJ(backend, PlaybackWrapper)(device); - return backend; - } + return new PlaybackWrapper{device}; if(type == ALCbackend_Capture) - { - CaptureWrapper *backend; - NEW_OBJ(backend, CaptureWrapper)(device); - return backend; - } - - return NULL; + return new CaptureWrapper{device}; + return nullptr; } BackendFactory &QSABackendFactory::getFactory() diff --git a/Alc/backends/qsa.h b/Alc/backends/qsa.h index 99d80106..46cc7dd1 100644 --- a/Alc/backends/qsa.h +++ b/Alc/backends/qsa.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/sdl2.cpp b/Alc/backends/sdl2.cpp index 985afa2e..91d1cece 100644 --- a/Alc/backends/sdl2.cpp +++ b/Alc/backends/sdl2.cpp @@ -43,13 +43,20 @@ namespace { constexpr ALCchar defaultDeviceName[] = DEVNAME_PREFIX "Default Device"; -struct ALCsdl2Backend final : public ALCbackend { - ALCsdl2Backend(ALCdevice *device) noexcept : ALCbackend{device} { } - ~ALCsdl2Backend() override; +struct Sdl2Backend final : public BackendBase { + Sdl2Backend(ALCdevice *device) noexcept : BackendBase{device} { } + ~Sdl2Backend() override; static void audioCallbackC(void *ptr, Uint8 *stream, int len); void audioCallback(Uint8 *stream, int len); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + void lock() noexcept override; + void unlock() noexcept override; + SDL_AudioDeviceID mDeviceID{0u}; ALsizei mFrameSize{0}; @@ -57,55 +64,32 @@ struct ALCsdl2Backend final : public ALCbackend { DevFmtChannels mFmtChans{}; DevFmtType mFmtType{}; ALuint mUpdateSize{0u}; -}; - -void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device); -void ALCsdl2Backend_Destruct(ALCsdl2Backend *self); -ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name); -ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self); -ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self); -void ALCsdl2Backend_stop(ALCsdl2Backend *self); -DECLARE_FORWARD2(ALCsdl2Backend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ClockLatency, getClockLatency) -void ALCsdl2Backend_lock(ALCsdl2Backend *self); -void ALCsdl2Backend_unlock(ALCsdl2Backend *self); -DECLARE_DEFAULT_ALLOCATORS(ALCsdl2Backend) - -DEFINE_ALCBACKEND_VTABLE(ALCsdl2Backend); - -void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device) -{ - new (self) ALCsdl2Backend{device}; - SET_VTABLE2(ALCsdl2Backend, ALCbackend, self); -} -void ALCsdl2Backend_Destruct(ALCsdl2Backend *self) -{ self->~ALCsdl2Backend(); } + static constexpr inline const char *CurrentPrefix() noexcept { return "ALCsdl2Playback::"; } + DEF_NEWDEL(Sdl2Backend) +}; -ALCsdl2Backend::~ALCsdl2Backend() +Sdl2Backend::~Sdl2Backend() { if(mDeviceID) SDL_CloseAudioDevice(mDeviceID); mDeviceID = 0; } -void ALCsdl2Backend::audioCallbackC(void *ptr, Uint8 *stream, int len) -{ static_cast(ptr)->audioCallback(stream, len); } +void Sdl2Backend::audioCallbackC(void *ptr, Uint8 *stream, int len) +{ static_cast(ptr)->audioCallback(stream, len); } -void ALCsdl2Backend::audioCallback(Uint8 *stream, int len) +void Sdl2Backend::audioCallback(Uint8 *stream, int len) { assert((len % mFrameSize) == 0); aluMixData(mDevice, stream, len / mFrameSize); } -ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) +ALCenum Sdl2Backend::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; SDL_AudioSpec want{}, have{}; - - want.freq = device->Frequency; - switch(device->FmtType) + want.freq = mDevice->Frequency; + switch(mDevice->FmtType) { case DevFmtUByte: want.format = AUDIO_U8; break; case DevFmtByte: want.format = AUDIO_S8; break; @@ -115,35 +99,35 @@ ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) case DevFmtInt: want.format = AUDIO_S32SYS; break; case DevFmtFloat: want.format = AUDIO_F32; break; } - want.channels = (device->FmtChans == DevFmtMono) ? 1 : 2; - want.samples = device->UpdateSize; - want.callback = &ALCsdl2Backend::audioCallbackC; - want.userdata = self; + want.channels = (mDevice->FmtChans == DevFmtMono) ? 1 : 2; + want.samples = mDevice->UpdateSize; + want.callback = &Sdl2Backend::audioCallbackC; + want.userdata = this; /* Passing nullptr to SDL_OpenAudioDevice opens a default, which isn't * necessarily the first in the list. */ if(!name || strcmp(name, defaultDeviceName) == 0) - self->mDeviceID = SDL_OpenAudioDevice(nullptr, SDL_FALSE, &want, &have, - SDL_AUDIO_ALLOW_ANY_CHANGE); + mDeviceID = SDL_OpenAudioDevice(nullptr, SDL_FALSE, &want, &have, + SDL_AUDIO_ALLOW_ANY_CHANGE); else { const size_t prefix_len = strlen(DEVNAME_PREFIX); if(strncmp(name, DEVNAME_PREFIX, prefix_len) == 0) - self->mDeviceID = SDL_OpenAudioDevice(name+prefix_len, SDL_FALSE, &want, &have, - SDL_AUDIO_ALLOW_ANY_CHANGE); + mDeviceID = SDL_OpenAudioDevice(name+prefix_len, SDL_FALSE, &want, &have, + SDL_AUDIO_ALLOW_ANY_CHANGE); else - self->mDeviceID = SDL_OpenAudioDevice(name, SDL_FALSE, &want, &have, - SDL_AUDIO_ALLOW_ANY_CHANGE); + mDeviceID = SDL_OpenAudioDevice(name, SDL_FALSE, &want, &have, + SDL_AUDIO_ALLOW_ANY_CHANGE); } - if(self->mDeviceID == 0) + if(mDeviceID == 0) return ALC_INVALID_VALUE; - device->Frequency = have.freq; + mDevice->Frequency = have.freq; if(have.channels == 1) - device->FmtChans = DevFmtMono; + mDevice->FmtChans = DevFmtMono; else if(have.channels == 2) - device->FmtChans = DevFmtStereo; + mDevice->FmtChans = DevFmtStereo; else { ERR("Got unhandled SDL channel count: %d\n", (int)have.channels); @@ -151,61 +135,54 @@ ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) } switch(have.format) { - case AUDIO_U8: device->FmtType = DevFmtUByte; break; - case AUDIO_S8: device->FmtType = DevFmtByte; break; - case AUDIO_U16SYS: device->FmtType = DevFmtUShort; break; - case AUDIO_S16SYS: device->FmtType = DevFmtShort; break; - case AUDIO_S32SYS: device->FmtType = DevFmtInt; break; - case AUDIO_F32SYS: device->FmtType = DevFmtFloat; break; + case AUDIO_U8: mDevice->FmtType = DevFmtUByte; break; + case AUDIO_S8: mDevice->FmtType = DevFmtByte; break; + case AUDIO_U16SYS: mDevice->FmtType = DevFmtUShort; break; + case AUDIO_S16SYS: mDevice->FmtType = DevFmtShort; break; + case AUDIO_S32SYS: mDevice->FmtType = DevFmtInt; break; + case AUDIO_F32SYS: mDevice->FmtType = DevFmtFloat; break; default: ERR("Got unsupported SDL format: 0x%04x\n", have.format); return ALC_INVALID_VALUE; } - device->UpdateSize = have.samples; - device->NumUpdates = 2; /* SDL always (tries to) use two periods. */ + mDevice->UpdateSize = have.samples; + mDevice->NumUpdates = 2; /* SDL always (tries to) use two periods. */ - self->mFrameSize = device->frameSizeFromFmt(); - self->mFrequency = device->Frequency; - self->mFmtChans = device->FmtChans; - self->mFmtType = device->FmtType; - self->mUpdateSize = device->UpdateSize; + mFrameSize = mDevice->frameSizeFromFmt(); + mFrequency = mDevice->Frequency; + mFmtChans = mDevice->FmtChans; + mFmtType = mDevice->FmtType; + mUpdateSize = mDevice->UpdateSize; - device->DeviceName = name ? name : defaultDeviceName; + mDevice->DeviceName = name ? name : defaultDeviceName; return ALC_NO_ERROR; } -ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self) +ALCboolean Sdl2Backend::reset() { - ALCdevice *device{self->mDevice}; - device->Frequency = self->mFrequency; - device->FmtChans = self->mFmtChans; - device->FmtType = self->mFmtType; - device->UpdateSize = self->mUpdateSize; - device->NumUpdates = 2; - SetDefaultWFXChannelOrder(device); + mDevice->Frequency = mFrequency; + mDevice->FmtChans = mFmtChans; + mDevice->FmtType = mFmtType; + mDevice->UpdateSize = mUpdateSize; + mDevice->NumUpdates = 2; + SetDefaultWFXChannelOrder(mDevice); return ALC_TRUE; } -ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self) +ALCboolean Sdl2Backend::start() { - SDL_PauseAudioDevice(self->mDeviceID, 0); + SDL_PauseAudioDevice(mDeviceID, 0); return ALC_TRUE; } -void ALCsdl2Backend_stop(ALCsdl2Backend *self) -{ - SDL_PauseAudioDevice(self->mDeviceID, 1); -} +void Sdl2Backend::stop() +{ SDL_PauseAudioDevice(mDeviceID, 1); } -void ALCsdl2Backend_lock(ALCsdl2Backend *self) -{ - SDL_LockAudioDevice(self->mDeviceID); -} +void Sdl2Backend::lock() noexcept +{ SDL_LockAudioDevice(mDeviceID); } -void ALCsdl2Backend_unlock(ALCsdl2Backend *self) -{ - SDL_UnlockAudioDevice(self->mDeviceID); -} +void Sdl2Backend::unlock() noexcept +{ SDL_UnlockAudioDevice(mDeviceID); } } // namespace @@ -248,14 +225,9 @@ void SDL2BackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *SDL2BackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *SDL2BackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - ALCsdl2Backend *backend; - NEW_OBJ(backend, ALCsdl2Backend)(device); - return backend; - } - + return new Sdl2Backend{device}; return nullptr; } diff --git a/Alc/backends/sdl2.h b/Alc/backends/sdl2.h index 7bf4d0e4..7a4ae9eb 100644 --- a/Alc/backends/sdl2.h +++ b/Alc/backends/sdl2.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index d185adab..2c2397e6 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -42,12 +42,17 @@ namespace { static const ALCchar sndio_device[] = "SndIO Default"; -struct SndioPlayback final : public ALCbackend { - SndioPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } +struct SndioPlayback final : public BackendBase { + SndioPlayback(ALCdevice *device) noexcept : BackendBase{device} { } ~SndioPlayback() override; int mixerProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + sio_hdl *mSndHandle{nullptr}; al::vector mBuffer; @@ -56,32 +61,9 @@ struct SndioPlayback final : public ALCbackend { std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "SndioPlayback::"; } + DEF_NEWDEL(SndioPlayback) }; -void SndioPlayback_Construct(SndioPlayback *self, ALCdevice *device); -void SndioPlayback_Destruct(SndioPlayback *self); -ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name); -ALCboolean SndioPlayback_reset(SndioPlayback *self); -ALCboolean SndioPlayback_start(SndioPlayback *self); -void SndioPlayback_stop(SndioPlayback *self); -DECLARE_FORWARD2(SndioPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -DECLARE_FORWARD(SndioPlayback, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(SndioPlayback, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(SndioPlayback, ALCbackend, void, lock) -DECLARE_FORWARD(SndioPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(SndioPlayback) - -DEFINE_ALCBACKEND_VTABLE(SndioPlayback); - -void SndioPlayback_Construct(SndioPlayback *self, ALCdevice *device) -{ - new (self) SndioPlayback{device}; - SET_VTABLE2(SndioPlayback, ALCbackend, self); -} - -void SndioPlayback_Destruct(SndioPlayback *self) -{ self->~SndioPlayback(); } - SndioPlayback::~SndioPlayback() { if(mSndHandle) @@ -102,18 +84,18 @@ int SndioPlayback::mixerProc() auto WritePtr = static_cast(mBuffer.data()); size_t len{mBuffer.size()}; - SndioPlayback_lock(this); + lock(); aluMixData(mDevice, WritePtr, len/frameSize); - SndioPlayback_unlock(this); + unlock(); while(len > 0 && !mKillNow.load(std::memory_order_acquire)) { size_t wrote{sio_write(mSndHandle, WritePtr, len)}; if(wrote == 0) { ERR("sio_write failed\n"); - SndioPlayback_lock(this); + lock(); aluHandleDisconnect(mDevice, "Failed to write playback samples"); - SndioPlayback_unlock(this); + unlock(); break; } @@ -126,37 +108,33 @@ int SndioPlayback::mixerProc() } -ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name) +ALCenum SndioPlayback::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - if(!name) name = sndio_device; else if(strcmp(name, sndio_device) != 0) return ALC_INVALID_VALUE; - self->mSndHandle = sio_open(nullptr, SIO_PLAY, 0); - if(self->mSndHandle == nullptr) + mSndHandle = sio_open(nullptr, SIO_PLAY, 0); + if(mSndHandle == nullptr) { ERR("Could not open device\n"); return ALC_INVALID_VALUE; } - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean SndioPlayback_reset(SndioPlayback *self) +ALCboolean SndioPlayback::reset() { - ALCdevice *device{self->mDevice}; sio_par par; - sio_initpar(&par); - par.rate = device->Frequency; - par.pchan = ((device->FmtChans != DevFmtMono) ? 2 : 1); + par.rate = mDevice->Frequency; + par.pchan = ((mDevice->FmtChans != DevFmtMono) ? 2 : 1); - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: par.bits = 8; @@ -186,11 +164,11 @@ ALCboolean SndioPlayback_reset(SndioPlayback *self) } par.le = SIO_LE_NATIVE; - par.round = device->UpdateSize; - par.appbufsz = device->UpdateSize * (device->NumUpdates-1); - if(!par.appbufsz) par.appbufsz = device->UpdateSize; + par.round = mDevice->UpdateSize; + par.appbufsz = mDevice->UpdateSize * (mDevice->NumUpdates-1); + if(!par.appbufsz) par.appbufsz = mDevice->UpdateSize; - if(!sio_setpar(self->mSndHandle, &par) || !sio_getpar(self->mSndHandle, &par)) + if(!sio_setpar(mSndHandle, &par) || !sio_getpar(mSndHandle, &par)) { ERR("Failed to set device parameters\n"); return ALC_FALSE; @@ -202,49 +180,49 @@ ALCboolean SndioPlayback_reset(SndioPlayback *self) return ALC_FALSE; } - device->Frequency = par.rate; - device->FmtChans = ((par.pchan==1) ? DevFmtMono : DevFmtStereo); + mDevice->Frequency = par.rate; + mDevice->FmtChans = ((par.pchan==1) ? DevFmtMono : DevFmtStereo); if(par.bits == 8 && par.sig == 1) - device->FmtType = DevFmtByte; + mDevice->FmtType = DevFmtByte; else if(par.bits == 8 && par.sig == 0) - device->FmtType = DevFmtUByte; + mDevice->FmtType = DevFmtUByte; else if(par.bits == 16 && par.sig == 1) - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; else if(par.bits == 16 && par.sig == 0) - device->FmtType = DevFmtUShort; + mDevice->FmtType = DevFmtUShort; else if(par.bits == 32 && par.sig == 1) - device->FmtType = DevFmtInt; + mDevice->FmtType = DevFmtInt; else if(par.bits == 32 && par.sig == 0) - device->FmtType = DevFmtUInt; + mDevice->FmtType = DevFmtUInt; else { ERR("Unhandled sample format: %s %u-bit\n", (par.sig?"signed":"unsigned"), par.bits); return ALC_FALSE; } - SetDefaultChannelOrder(device); + SetDefaultChannelOrder(mDevice); - device->UpdateSize = par.round; - device->NumUpdates = (par.bufsz/par.round) + 1; + mDevice->UpdateSize = par.round; + mDevice->NumUpdates = (par.bufsz/par.round) + 1; - self->mBuffer.resize(device->UpdateSize * device->frameSizeFromFmt()); - std::fill(self->mBuffer.begin(), self->mBuffer.end(), 0); + mBuffer.resize(mDevice->UpdateSize * mDevice->frameSizeFromFmt()); + std::fill(mBuffer.begin(), mBuffer.end(), 0); return ALC_TRUE; } -ALCboolean SndioPlayback_start(SndioPlayback *self) +ALCboolean SndioPlayback::start() { - if(!sio_start(self->mSndHandle)) + if(!sio_start(mSndHandle)) { ERR("Error starting playback\n"); return ALC_FALSE; } try { - self->mKillNow.store(false, std::memory_order_release); - self->mThread = std::thread{std::mem_fn(&SndioPlayback::mixerProc), self}; + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&SndioPlayback::mixerProc), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -252,27 +230,33 @@ ALCboolean SndioPlayback_start(SndioPlayback *self) } catch(...) { } - sio_stop(self->mSndHandle); + sio_stop(mSndHandle); return ALC_FALSE; } -void SndioPlayback_stop(SndioPlayback *self) +void SndioPlayback::stop() { - if(self->mKillNow.exchange(true, std::memory_order_acq_rel) || !self->mThread.joinable()) + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) return; - self->mThread.join(); + mThread.join(); - if(!sio_stop(self->mSndHandle)) + if(!sio_stop(mSndHandle)) ERR("Error stopping device\n"); } -struct SndioCapture final : public ALCbackend { - SndioCapture(ALCdevice *device) noexcept : ALCbackend{device} { } +struct SndioCapture final : public BackendBase { + SndioCapture(ALCdevice *device) noexcept : BackendBase{device} { } ~SndioCapture() override; int recordProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + sio_hdl *mSndHandle{nullptr}; RingBufferPtr mRing; @@ -281,32 +265,9 @@ struct SndioCapture final : public ALCbackend { std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "SndioCapture::"; } + DEF_NEWDEL(SndioCapture) }; -void SndioCapture_Construct(SndioCapture *self, ALCdevice *device); -void SndioCapture_Destruct(SndioCapture *self); -ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name); -DECLARE_FORWARD(SndioCapture, ALCbackend, ALCboolean, reset) -ALCboolean SndioCapture_start(SndioCapture *self); -void SndioCapture_stop(SndioCapture *self); -ALCenum SndioCapture_captureSamples(SndioCapture *self, void *buffer, ALCuint samples); -ALCuint SndioCapture_availableSamples(SndioCapture *self); -DECLARE_FORWARD(SndioCapture, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(SndioCapture, ALCbackend, void, lock) -DECLARE_FORWARD(SndioCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(SndioCapture) - -DEFINE_ALCBACKEND_VTABLE(SndioCapture); - -void SndioCapture_Construct(SndioCapture *self, ALCdevice *device) -{ - new (self) SndioCapture{device}; - SET_VTABLE2(SndioCapture, ALCbackend, self); -} - -void SndioCapture_Destruct(SndioCapture *self) -{ self->~SndioCapture(); } - SndioCapture::~SndioCapture() { if(mSndHandle) @@ -346,9 +307,9 @@ int SndioCapture::recordProc() size_t got{sio_read(mSndHandle, data.first.buf, minz(todo-total, data.first.len))}; if(!got) { - SndioCapture_lock(this); + lock(); aluHandleDisconnect(mDevice, "Failed to read capture samples"); - SndioCapture_unlock(this); + unlock(); break; } @@ -363,26 +324,24 @@ int SndioCapture::recordProc() } -ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) +ALCenum SndioCapture::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - sio_par par; - if(!name) name = sndio_device; else if(strcmp(name, sndio_device) != 0) return ALC_INVALID_VALUE; - self->mSndHandle = sio_open(nullptr, SIO_REC, 0); - if(self->mSndHandle == nullptr) + mSndHandle = sio_open(nullptr, SIO_REC, 0); + if(mSndHandle == nullptr) { ERR("Could not open device\n"); return ALC_INVALID_VALUE; } + sio_par par; sio_initpar(&par); - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: par.bps = 1; @@ -409,23 +368,23 @@ ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) par.sig = 0; break; case DevFmtFloat: - ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); + ERR("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); return ALC_INVALID_VALUE; } par.bits = par.bps * 8; par.le = SIO_LE_NATIVE; par.msb = SIO_LE_NATIVE ? 0 : 1; - par.rchan = device->channelsFromFmt(); - par.rate = device->Frequency; + par.rchan = mDevice->channelsFromFmt(); + par.rate = mDevice->Frequency; - par.appbufsz = maxu(device->UpdateSize*device->NumUpdates, (device->Frequency+9)/10); - par.round = clampu(par.appbufsz/device->NumUpdates, (device->Frequency+99)/100, - (device->Frequency+19)/20); + par.appbufsz = maxu(mDevice->UpdateSize*mDevice->NumUpdates, (mDevice->Frequency+9)/10); + par.round = clampu(par.appbufsz/mDevice->NumUpdates, (mDevice->Frequency+99)/100, + (mDevice->Frequency+19)/20); - device->UpdateSize = par.round; - device->NumUpdates = maxu(par.appbufsz/par.round, 1); + mDevice->UpdateSize = par.round; + mDevice->NumUpdates = maxu(par.appbufsz/par.round, 1); - if(!sio_setpar(self->mSndHandle, &par) || !sio_getpar(self->mSndHandle, &par)) + if(!sio_setpar(mSndHandle, &par) || !sio_getpar(mSndHandle, &par)) { ERR("Failed to set device parameters\n"); return ALC_INVALID_VALUE; @@ -437,46 +396,46 @@ ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) return ALC_INVALID_VALUE; } - if(!((device->FmtType == DevFmtByte && par.bits == 8 && par.sig != 0) || - (device->FmtType == DevFmtUByte && par.bits == 8 && par.sig == 0) || - (device->FmtType == DevFmtShort && par.bits == 16 && par.sig != 0) || - (device->FmtType == DevFmtUShort && par.bits == 16 && par.sig == 0) || - (device->FmtType == DevFmtInt && par.bits == 32 && par.sig != 0) || - (device->FmtType == DevFmtUInt && par.bits == 32 && par.sig == 0)) || - device->channelsFromFmt() != (ALsizei)par.rchan || - device->Frequency != par.rate) + if(!((mDevice->FmtType == DevFmtByte && par.bits == 8 && par.sig != 0) || + (mDevice->FmtType == DevFmtUByte && par.bits == 8 && par.sig == 0) || + (mDevice->FmtType == DevFmtShort && par.bits == 16 && par.sig != 0) || + (mDevice->FmtType == DevFmtUShort && par.bits == 16 && par.sig == 0) || + (mDevice->FmtType == DevFmtInt && par.bits == 32 && par.sig != 0) || + (mDevice->FmtType == DevFmtUInt && par.bits == 32 && par.sig == 0)) || + mDevice->channelsFromFmt() != (ALsizei)par.rchan || + mDevice->Frequency != par.rate) { ERR("Failed to set format %s %s %uhz, got %c%u %u-channel %uhz instead\n", - DevFmtTypeString(device->FmtType), DevFmtChannelsString(device->FmtChans), - device->Frequency, par.sig?'s':'u', par.bits, par.rchan, par.rate); + DevFmtTypeString(mDevice->FmtType), DevFmtChannelsString(mDevice->FmtChans), + mDevice->Frequency, par.sig?'s':'u', par.bits, par.rchan, par.rate); return ALC_INVALID_VALUE; } - self->mRing = CreateRingBuffer(device->UpdateSize*device->NumUpdates, par.bps*par.rchan, false); - if(!self->mRing) + mRing = CreateRingBuffer(mDevice->UpdateSize*mDevice->NumUpdates, par.bps*par.rchan, false); + if(!mRing) { ERR("Failed to allocate %u-byte ringbuffer\n", - device->UpdateSize*device->NumUpdates*par.bps*par.rchan); + mDevice->UpdateSize*mDevice->NumUpdates*par.bps*par.rchan); return ALC_OUT_OF_MEMORY; } - SetDefaultChannelOrder(device); + SetDefaultChannelOrder(mDevice); - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean SndioCapture_start(SndioCapture *self) +ALCboolean SndioCapture::start() { - if(!sio_start(self->mSndHandle)) + if(!sio_start(mSndHandle)) { ERR("Error starting playback\n"); return ALC_FALSE; } try { - self->mKillNow.store(false, std::memory_order_release); - self->mThread = std::thread{std::mem_fn(&SndioCapture::recordProc), self}; + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&SndioCapture::recordProc), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -484,32 +443,28 @@ ALCboolean SndioCapture_start(SndioCapture *self) } catch(...) { } - sio_stop(self->mSndHandle); + sio_stop(mSndHandle); return ALC_FALSE; } -void SndioCapture_stop(SndioCapture *self) +void SndioCapture::stop() { - if(self->mKillNow.exchange(true, std::memory_order_acq_rel) || !self->mThread.joinable()) + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) return; - self->mThread.join(); + mThread.join(); - if(!sio_stop(self->mSndHandle)) + if(!sio_stop(mSndHandle)) ERR("Error stopping device\n"); } -ALCenum SndioCapture_captureSamples(SndioCapture *self, void *buffer, ALCuint samples) +ALCenum SndioCapture::captureSamples(void *buffer, ALCuint samples) { - RingBuffer *ring{self->mRing.get()}; - ring->read(buffer, samples); + mRing->read(buffer, samples); return ALC_NO_ERROR; } -ALCuint SndioCapture_availableSamples(SndioCapture *self) -{ - RingBuffer *ring{self->mRing.get()}; - return ring->readSpace(); -} +ALCuint SndioCapture::availableSamples() +{ return mRing->readSpace(); } } // namespace @@ -537,20 +492,11 @@ void SndIOBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *SndIOBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *SndIOBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - SndioPlayback *backend; - NEW_OBJ(backend, SndioPlayback)(device); - return backend; - } + return new SndioPlayback{device}; if(type == ALCbackend_Capture) - { - SndioCapture *backend; - NEW_OBJ(backend, SndioCapture)(device); - return backend; - } - + return new SndioCapture{device}; return nullptr; } diff --git a/Alc/backends/sndio.h b/Alc/backends/sndio.h index 20e99afb..bf8d833d 100644 --- a/Alc/backends/sndio.h +++ b/Alc/backends/sndio.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index 7d7e3883..6463c225 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -54,12 +54,17 @@ constexpr ALCchar solaris_device[] = "Solaris Default"; const char *solaris_driver = "/dev/audio"; -struct SolarisBackend final : public ALCbackend { - SolarisBackend(ALCdevice *device) noexcept : ALCbackend{device} { } +struct SolarisBackend final : public BackendBase { + SolarisBackend(ALCdevice *device) noexcept : BackendBase{device} { } ~SolarisBackend() override; int mixerProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + int mFd{-1}; al::vector mBuffer; @@ -68,32 +73,9 @@ struct SolarisBackend final : public ALCbackend { std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "SolarisBackend::"; } + DEF_NEWDEL(SolarisBackend) }; -void SolarisBackend_Construct(SolarisBackend *self, ALCdevice *device); -void SolarisBackend_Destruct(SolarisBackend *self); -ALCenum SolarisBackend_open(SolarisBackend *self, const ALCchar *name); -ALCboolean SolarisBackend_reset(SolarisBackend *self); -ALCboolean SolarisBackend_start(SolarisBackend *self); -void SolarisBackend_stop(SolarisBackend *self); -DECLARE_FORWARD2(SolarisBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -DECLARE_FORWARD(SolarisBackend, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(SolarisBackend, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(SolarisBackend, ALCbackend, void, lock) -DECLARE_FORWARD(SolarisBackend, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(SolarisBackend) - -DEFINE_ALCBACKEND_VTABLE(SolarisBackend); - -void SolarisBackend_Construct(SolarisBackend *self, ALCdevice *device) -{ - new (self) SolarisBackend{device}; - SET_VTABLE2(SolarisBackend, ALCbackend, self); -} - -void SolarisBackend_Destruct(SolarisBackend *self) -{ self->~SolarisBackend(); } - SolarisBackend::~SolarisBackend() { if(mFd != -1) @@ -108,7 +90,7 @@ int SolarisBackend::mixerProc() const int frame_size{mDevice->frameSizeFromFmt()}; - SolarisBackend_lock(this); + lock(); while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) { @@ -116,9 +98,9 @@ int SolarisBackend::mixerProc() pollitem.fd = mFd; pollitem.events = POLLOUT; - SolarisBackend_unlock(this); + unlock(); int pret{poll(&pollitem, 1, 1000)}; - SolarisBackend_lock(this); + lock(); if(pret < 0) { if(errno == EINTR || errno == EAGAIN) @@ -154,49 +136,43 @@ int SolarisBackend::mixerProc() write_ptr += wrote; } } - SolarisBackend_unlock(this); + unlock(); return 0; } -ALCenum SolarisBackend_open(SolarisBackend *self, const ALCchar *name) +ALCenum SolarisBackend::open(const ALCchar *name) { if(!name) name = solaris_device; else if(strcmp(name, solaris_device) != 0) return ALC_INVALID_VALUE; - self->mFd = open(solaris_driver, O_WRONLY); - if(self->mFd == -1) + mFd = ::open(solaris_driver, O_WRONLY); + if(mFd == -1) { ERR("Could not open %s: %s\n", solaris_driver, strerror(errno)); return ALC_INVALID_VALUE; } - ALCdevice *device{self->mDevice}; - device->DeviceName = name; - + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean SolarisBackend_reset(SolarisBackend *self) +ALCboolean SolarisBackend::reset() { - ALCdevice *device{self->mDevice}; audio_info_t info; - ALsizei frameSize; - ALsizei numChannels; - AUDIO_INITINFO(&info); - info.play.sample_rate = device->Frequency; + info.play.sample_rate = mDevice->Frequency; - if(device->FmtChans != DevFmtMono) - device->FmtChans = DevFmtStereo; - numChannels = device->channelsFromFmt(); + if(mDevice->FmtChans != DevFmtMono) + mDevice->FmtChans = DevFmtStereo; + ALsizei numChannels{mDevice->channelsFromFmt()}; info.play.channels = numChannels; - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: info.play.precision = 8; @@ -210,7 +186,7 @@ ALCboolean SolarisBackend_reset(SolarisBackend *self) case DevFmtInt: case DevFmtUInt: case DevFmtFloat: - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; /* fall-through */ case DevFmtShort: info.play.precision = 16; @@ -218,48 +194,48 @@ ALCboolean SolarisBackend_reset(SolarisBackend *self) break; } - frameSize = numChannels * device->bytesFromFmt(); - info.play.buffer_size = device->UpdateSize*device->NumUpdates * frameSize; + ALsizei frameSize{numChannels * mDevice->bytesFromFmt()}; + info.play.buffer_size = mDevice->UpdateSize*mDevice->NumUpdates * frameSize; - if(ioctl(self->mFd, AUDIO_SETINFO, &info) < 0) + if(ioctl(mFd, AUDIO_SETINFO, &info) < 0) { ERR("ioctl failed: %s\n", strerror(errno)); return ALC_FALSE; } - if(device->channelsFromFmt() != (ALsizei)info.play.channels) + if(mDevice->channelsFromFmt() != (ALsizei)info.play.channels) { - ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(device->FmtChans), + ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(mDevice->FmtChans), info.play.channels); return ALC_FALSE; } - if(!((info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR8 && device->FmtType == DevFmtUByte) || - (info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtByte) || - (info.play.precision == 16 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtShort) || - (info.play.precision == 32 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtInt))) + if(!((info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR8 && mDevice->FmtType == DevFmtUByte) || + (info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR && mDevice->FmtType == DevFmtByte) || + (info.play.precision == 16 && info.play.encoding == AUDIO_ENCODING_LINEAR && mDevice->FmtType == DevFmtShort) || + (info.play.precision == 32 && info.play.encoding == AUDIO_ENCODING_LINEAR && mDevice->FmtType == DevFmtInt))) { - ERR("Could not set %s samples, got %d (0x%x)\n", DevFmtTypeString(device->FmtType), + ERR("Could not set %s samples, got %d (0x%x)\n", DevFmtTypeString(mDevice->FmtType), info.play.precision, info.play.encoding); return ALC_FALSE; } - device->Frequency = info.play.sample_rate; - device->UpdateSize = (info.play.buffer_size/device->NumUpdates) + 1; + mDevice->Frequency = info.play.sample_rate; + mDevice->UpdateSize = (info.play.buffer_size/mDevice->NumUpdates) + 1; - SetDefaultChannelOrder(device); + SetDefaultChannelOrder(mDevice); - self->mBuffer.resize(device->UpdateSize * device->frameSizeFromFmt()); - std::fill(self->mBuffer.begin(), self->mBuffer.end(), 0); + mBuffer.resize(mDevice->UpdateSize * mDevice->frameSizeFromFmt()); + std::fill(mBuffer.begin(), mBuffer.end(), 0); return ALC_TRUE; } -ALCboolean SolarisBackend_start(SolarisBackend *self) +ALCboolean SolarisBackend::start() { try { - self->mKillNow.store(false, std::memory_order_release); - self->mThread = std::thread{std::mem_fn(&SolarisBackend::mixerProc), self}; + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&SolarisBackend::mixerProc), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -270,14 +246,13 @@ ALCboolean SolarisBackend_start(SolarisBackend *self) return ALC_FALSE; } -void SolarisBackend_stop(SolarisBackend *self) +void SolarisBackend::stop() { - if(self->mKillNow.exchange(true, std::memory_order_acq_rel) || !self->mThread.joinable()) + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) return; + mThread.join(); - self->mThread.join(); - - if(ioctl(self->mFd, AUDIO_DRAIN) < 0) + if(ioctl(mFd, AUDIO_DRAIN) < 0) ERR("Error draining device: %s\n", strerror(errno)); } @@ -317,14 +292,9 @@ void SolarisBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *SolarisBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *SolarisBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - SolarisBackend *backend; - NEW_OBJ(backend, SolarisBackend)(device); - return backend; - } - + return new SolarisBackend{device}; return nullptr; } diff --git a/Alc/backends/solaris.h b/Alc/backends/solaris.h index 73f4a467..f675d6d7 100644 --- a/Alc/backends/solaris.h +++ b/Alc/backends/solaris.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 5c97324e..0d3d067e 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -494,19 +494,25 @@ DWORD WasapiProxy::messageHandler(void *ptr) } -struct WasapiPlayback final : public ALCbackend, WasapiProxy { - WasapiPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } +struct WasapiPlayback final : public BackendBase, WasapiProxy { + WasapiPlayback(ALCdevice *device) noexcept : BackendBase{device} { } ~WasapiPlayback() override; int mixerProc(); + ALCenum open(const ALCchar *name) override; HRESULT openProxy() override; void closeProxy() override; + ALCboolean reset() override; HRESULT resetProxy() override; + ALCboolean start() override; HRESULT startProxy() override; + void stop() override; void stopProxy() override; + ClockLatency getClockLatency() override; + std::wstring mDevId; IMMDevice *mMMDev{nullptr}; @@ -522,32 +528,9 @@ struct WasapiPlayback final : public ALCbackend, WasapiProxy { std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "WasapiPlayback::"; } + DEF_NEWDEL(WasapiPlayback) }; -void WasapiPlayback_Construct(WasapiPlayback *self, ALCdevice *device); -void WasapiPlayback_Destruct(WasapiPlayback *self); -ALCenum WasapiPlayback_open(WasapiPlayback *self, const ALCchar *name); -ALCboolean WasapiPlayback_reset(WasapiPlayback *self); -ALCboolean WasapiPlayback_start(WasapiPlayback *self); -void WasapiPlayback_stop(WasapiPlayback *self); -DECLARE_FORWARD2(WasapiPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -DECLARE_FORWARD(WasapiPlayback, ALCbackend, ALCuint, availableSamples) -ClockLatency WasapiPlayback_getClockLatency(WasapiPlayback *self); -DECLARE_FORWARD(WasapiPlayback, ALCbackend, void, lock) -DECLARE_FORWARD(WasapiPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(WasapiPlayback) - -DEFINE_ALCBACKEND_VTABLE(WasapiPlayback); - -void WasapiPlayback_Construct(WasapiPlayback *self, ALCdevice *device) -{ - new (self) WasapiPlayback{device}; - SET_VTABLE2(WasapiPlayback, ALCbackend, self); -} - -void WasapiPlayback_Destruct(WasapiPlayback *self) -{ self->~WasapiPlayback(); } - WasapiPlayback::~WasapiPlayback() { if(mMsgEvent) @@ -576,9 +559,9 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() if(FAILED(hr)) { ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); - WasapiPlayback_lock(this); + lock(); aluHandleDisconnect(mDevice, "COM init failed: 0x%08lx", hr); - WasapiPlayback_unlock(this); + unlock(); return 1; } @@ -594,9 +577,9 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() if(FAILED(hr)) { ERR("Failed to get padding: 0x%08lx\n", hr); - WasapiPlayback_lock(this); + lock(); aluHandleDisconnect(mDevice, "Failed to retrieve buffer padding: 0x%08lx", hr); - WasapiPlayback_unlock(this); + unlock(); break; } mPadding.store(written, std::memory_order_relaxed); @@ -615,18 +598,18 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() hr = mRender->GetBuffer(len, &buffer); if(SUCCEEDED(hr)) { - WasapiPlayback_lock(this); + lock(); aluMixData(mDevice, buffer, len); mPadding.store(written + len, std::memory_order_relaxed); - WasapiPlayback_unlock(this); + unlock(); hr = mRender->ReleaseBuffer(len, 0); } if(FAILED(hr)) { ERR("Failed to buffer data: 0x%08lx\n", hr); - WasapiPlayback_lock(this); + lock(); aluHandleDisconnect(mDevice, "Failed to send playback samples: 0x%08lx", hr); - WasapiPlayback_unlock(this); + unlock(); break; } } @@ -676,13 +659,13 @@ ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) return ALC_TRUE; } -ALCenum WasapiPlayback_open(WasapiPlayback *self, const ALCchar *deviceName) +ALCenum WasapiPlayback::open(const ALCchar *name) { - HRESULT hr = S_OK; + HRESULT hr{S_OK}; - self->mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - self->mMsgEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - if(self->mNotifyEvent == nullptr || self->mMsgEvent == nullptr) + mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + mMsgEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + if(mNotifyEvent == nullptr || mMsgEvent == nullptr) { ERR("Failed to create message events: %lu\n", GetLastError()); hr = E_FAIL; @@ -690,35 +673,34 @@ ALCenum WasapiPlayback_open(WasapiPlayback *self, const ALCchar *deviceName) if(SUCCEEDED(hr)) { - if(deviceName) + if(name) { if(PlaybackDevices.empty()) { - ThreadRequest req = { self->mMsgEvent, 0 }; + ThreadRequest req = { mMsgEvent, 0 }; if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, ALL_DEVICE_PROBE)) (void)WaitForResponse(&req); } hr = E_FAIL; auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), - [deviceName](const DevMap &entry) -> bool - { return entry.name == deviceName || entry.endpoint_guid == deviceName; } + [name](const DevMap &entry) -> bool + { return entry.name == name || entry.endpoint_guid == name; } ); if(iter == PlaybackDevices.cend()) { - std::wstring wname{utf8_to_wstr(deviceName)}; + std::wstring wname{utf8_to_wstr(name)}; iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), [&wname](const DevMap &entry) -> bool { return entry.devid == wname; } ); } if(iter == PlaybackDevices.cend()) - WARN("Failed to find device name matching \"%s\"\n", deviceName); + WARN("Failed to find device name matching \"%s\"\n", name); else { - ALCdevice *device{self->mDevice}; - self->mDevId = iter->devid; - device->DeviceName = iter->name; + mDevId = iter->devid; + mDevice->DeviceName = iter->name; hr = S_OK; } } @@ -726,8 +708,8 @@ ALCenum WasapiPlayback_open(WasapiPlayback *self, const ALCchar *deviceName) if(SUCCEEDED(hr)) { - ThreadRequest req{ self->mMsgEvent, 0 }; - auto proxy = static_cast(self); + ThreadRequest req{ mMsgEvent, 0 }; + auto proxy = static_cast(this); hr = E_FAIL; if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)proxy)) @@ -738,14 +720,14 @@ ALCenum WasapiPlayback_open(WasapiPlayback *self, const ALCchar *deviceName) if(FAILED(hr)) { - if(self->mNotifyEvent != nullptr) - CloseHandle(self->mNotifyEvent); - self->mNotifyEvent = nullptr; - if(self->mMsgEvent != nullptr) - CloseHandle(self->mMsgEvent); - self->mMsgEvent = nullptr; + if(mNotifyEvent != nullptr) + CloseHandle(mNotifyEvent); + mNotifyEvent = nullptr; + if(mMsgEvent != nullptr) + CloseHandle(mMsgEvent); + mMsgEvent = nullptr; - self->mDevId.clear(); + mDevId.clear(); ERR("Device init failed: 0x%08lx\n", hr); return ALC_INVALID_VALUE; @@ -798,12 +780,11 @@ void WasapiPlayback::closeProxy() } -ALCboolean WasapiPlayback_reset(WasapiPlayback *self) +ALCboolean WasapiPlayback::reset() { - ThreadRequest req{ self->mMsgEvent, 0 }; + ThreadRequest req{ mMsgEvent, 0 }; + auto proxy = static_cast(this); HRESULT hr{E_FAIL}; - - auto proxy = static_cast(self); if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)proxy)) hr = WaitForResponse(&req); @@ -1066,12 +1047,11 @@ HRESULT WasapiPlayback::resetProxy() } -ALCboolean WasapiPlayback_start(WasapiPlayback *self) +ALCboolean WasapiPlayback::start() { - ThreadRequest req{ self->mMsgEvent, 0 }; + ThreadRequest req{ mMsgEvent, 0 }; + auto proxy = static_cast(this); HRESULT hr{E_FAIL}; - - auto proxy = static_cast(self); if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)proxy)) hr = WaitForResponse(&req); @@ -1113,10 +1093,10 @@ HRESULT WasapiPlayback::startProxy() } -void WasapiPlayback_stop(WasapiPlayback *self) +void WasapiPlayback::stop() { - ThreadRequest req{ self->mMsgEvent, 0 }; - auto proxy = static_cast(self); + ThreadRequest req{ mMsgEvent, 0 }; + auto proxy = static_cast(this); if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)proxy)) (void)WaitForResponse(&req); } @@ -1135,34 +1115,39 @@ void WasapiPlayback::stopProxy() } -ClockLatency WasapiPlayback_getClockLatency(WasapiPlayback *self) +ClockLatency WasapiPlayback::getClockLatency() { ClockLatency ret; - WasapiPlayback_lock(self); - ALCdevice *device{self->mDevice}; - ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = std::chrono::seconds{self->mPadding.load(std::memory_order_relaxed)}; - ret.Latency /= device->Frequency; - WasapiPlayback_unlock(self); + lock(); + ret.ClockTime = GetDeviceClockTime(mDevice); + ret.Latency = std::chrono::seconds{mPadding.load(std::memory_order_relaxed)}; + ret.Latency /= mDevice->Frequency; + unlock(); return ret; } -struct WasapiCapture final : public ALCbackend, WasapiProxy { - WasapiCapture(ALCdevice *device) noexcept : ALCbackend{device} { } +struct WasapiCapture final : public BackendBase, WasapiProxy { + WasapiCapture(ALCdevice *device) noexcept : BackendBase{device} { } ~WasapiCapture() override; int recordProc(); + ALCenum open(const ALCchar *name) override; HRESULT openProxy() override; void closeProxy() override; HRESULT resetProxy() override; + ALCboolean start() override; HRESULT startProxy() override; + void stop() override; void stopProxy() override; + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + std::wstring mDevId; IMMDevice *mMMDev{nullptr}; @@ -1180,33 +1165,9 @@ struct WasapiCapture final : public ALCbackend, WasapiProxy { std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "WasapiCapture::"; } + DEF_NEWDEL(WasapiCapture) }; -void WasapiCapture_Construct(WasapiCapture *self, ALCdevice *device); -void WasapiCapture_Destruct(WasapiCapture *self); -ALCenum WasapiCapture_open(WasapiCapture *self, const ALCchar *name); -DECLARE_FORWARD(WasapiCapture, ALCbackend, ALCboolean, reset) -ALCboolean WasapiCapture_start(WasapiCapture *self); -void WasapiCapture_stop(WasapiCapture *self); -ALCenum WasapiCapture_captureSamples(WasapiCapture *self, ALCvoid *buffer, ALCuint samples); -ALuint WasapiCapture_availableSamples(WasapiCapture *self); -DECLARE_FORWARD(WasapiCapture, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(WasapiCapture, ALCbackend, void, lock) -DECLARE_FORWARD(WasapiCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(WasapiCapture) - -DEFINE_ALCBACKEND_VTABLE(WasapiCapture); - - -void WasapiCapture_Construct(WasapiCapture *self, ALCdevice *device) -{ - new (self) WasapiCapture{device}; - SET_VTABLE2(WasapiCapture, ALCbackend, self); -} - -void WasapiCapture_Destruct(WasapiCapture *self) -{ self->~WasapiCapture(); } - WasapiCapture::~WasapiCapture() { if(mMsgEvent) @@ -1232,9 +1193,9 @@ FORCE_ALIGN int WasapiCapture::recordProc() if(FAILED(hr)) { ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); - WasapiCapture_lock(this); + lock(); aluHandleDisconnect(mDevice, "COM init failed: 0x%08lx", hr); - WasapiCapture_unlock(this); + unlock(); return 1; } @@ -1306,9 +1267,9 @@ FORCE_ALIGN int WasapiCapture::recordProc() if(FAILED(hr)) { - WasapiCapture_lock(this); + lock(); aluHandleDisconnect(mDevice, "Failed to capture samples: 0x%08lx", hr); - WasapiCapture_unlock(this); + unlock(); break; } @@ -1322,13 +1283,13 @@ FORCE_ALIGN int WasapiCapture::recordProc() } -ALCenum WasapiCapture_open(WasapiCapture *self, const ALCchar *deviceName) +ALCenum WasapiCapture::open(const ALCchar *name) { HRESULT hr{S_OK}; - self->mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - self->mMsgEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - if(self->mNotifyEvent == nullptr || self->mMsgEvent == nullptr) + mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + mMsgEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + if(mNotifyEvent == nullptr || mMsgEvent == nullptr) { ERR("Failed to create message events: %lu\n", GetLastError()); hr = E_FAIL; @@ -1336,35 +1297,34 @@ ALCenum WasapiCapture_open(WasapiCapture *self, const ALCchar *deviceName) if(SUCCEEDED(hr)) { - if(deviceName) + if(name) { if(CaptureDevices.empty()) { - ThreadRequest req{ self->mMsgEvent, 0 }; + ThreadRequest req{ mMsgEvent, 0 }; if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, CAPTURE_DEVICE_PROBE)) (void)WaitForResponse(&req); } hr = E_FAIL; auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), - [deviceName](const DevMap &entry) -> bool - { return entry.name == deviceName || entry.endpoint_guid == deviceName; } + [name](const DevMap &entry) -> bool + { return entry.name == name || entry.endpoint_guid == name; } ); if(iter == CaptureDevices.cend()) { - std::wstring wname{utf8_to_wstr(deviceName)}; + std::wstring wname{utf8_to_wstr(name)}; iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), [&wname](const DevMap &entry) -> bool { return entry.devid == wname; } ); } if(iter == CaptureDevices.cend()) - WARN("Failed to find device name matching \"%s\"\n", deviceName); + WARN("Failed to find device name matching \"%s\"\n", name); else { - ALCdevice *device{self->mDevice}; - self->mDevId = iter->devid; - device->DeviceName = iter->name; + mDevId = iter->devid; + mDevice->DeviceName = iter->name; hr = S_OK; } } @@ -1372,10 +1332,9 @@ ALCenum WasapiCapture_open(WasapiCapture *self, const ALCchar *deviceName) if(SUCCEEDED(hr)) { - ThreadRequest req{ self->mMsgEvent, 0 }; - + ThreadRequest req{ mMsgEvent, 0 }; + auto proxy = static_cast(this); hr = E_FAIL; - auto proxy = static_cast(self); if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)proxy)) hr = WaitForResponse(&req); else @@ -1384,24 +1343,23 @@ ALCenum WasapiCapture_open(WasapiCapture *self, const ALCchar *deviceName) if(FAILED(hr)) { - if(self->mNotifyEvent != nullptr) - CloseHandle(self->mNotifyEvent); - self->mNotifyEvent = nullptr; - if(self->mMsgEvent != nullptr) - CloseHandle(self->mMsgEvent); - self->mMsgEvent = nullptr; + if(mNotifyEvent != nullptr) + CloseHandle(mNotifyEvent); + mNotifyEvent = nullptr; + if(mMsgEvent != nullptr) + CloseHandle(mMsgEvent); + mMsgEvent = nullptr; - self->mDevId.clear(); + mDevId.clear(); ERR("Device init failed: 0x%08lx\n", hr); return ALC_INVALID_VALUE; } else { - ThreadRequest req{ self->mMsgEvent, 0 }; - + ThreadRequest req{ mMsgEvent, 0 }; + auto proxy = static_cast(this); hr = E_FAIL; - auto proxy = static_cast(self); if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)proxy)) hr = WaitForResponse(&req); else @@ -1694,12 +1652,11 @@ HRESULT WasapiCapture::resetProxy() } -ALCboolean WasapiCapture_start(WasapiCapture *self) +ALCboolean WasapiCapture::start() { - ThreadRequest req{ self->mMsgEvent, 0 }; + ThreadRequest req{ mMsgEvent, 0 }; + auto proxy = static_cast(this); HRESULT hr{E_FAIL}; - - auto proxy = static_cast(self); if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)proxy)) hr = WaitForResponse(&req); @@ -1744,10 +1701,10 @@ HRESULT WasapiCapture::startProxy() } -void WasapiCapture_stop(WasapiCapture *self) +void WasapiCapture::stop() { - ThreadRequest req{ self->mMsgEvent, 0 }; - auto proxy = static_cast(self); + ThreadRequest req{ mMsgEvent, 0 }; + auto proxy = static_cast(this); if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)proxy)) (void)WaitForResponse(&req); } @@ -1767,16 +1724,12 @@ void WasapiCapture::stopProxy() } -ALuint WasapiCapture_availableSamples(WasapiCapture *self) -{ - RingBuffer *ring{self->mRing.get()}; - return (ALuint)ring->readSpace(); -} +ALCuint WasapiCapture::availableSamples() +{ return (ALCuint)mRing->readSpace(); } -ALCenum WasapiCapture_captureSamples(WasapiCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum WasapiCapture::captureSamples(void *buffer, ALCuint samples) { - RingBuffer *ring{self->mRing.get()}; - ring->read(buffer, samples); + mRing->read(buffer, samples); return ALC_NO_ERROR; } @@ -1857,21 +1810,12 @@ void WasapiBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *WasapiBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *WasapiBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - WasapiPlayback *backend; - NEW_OBJ(backend, WasapiPlayback)(device); - return backend; - } + return new WasapiPlayback{device}; if(type == ALCbackend_Capture) - { - WasapiCapture *backend; - NEW_OBJ(backend, WasapiCapture)(device); - return backend; - } - + return new WasapiCapture{device}; return nullptr; } diff --git a/Alc/backends/wasapi.h b/Alc/backends/wasapi.h index a94f85df..47bd0e0c 100644 --- a/Alc/backends/wasapi.h +++ b/Alc/backends/wasapi.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index a1951c7b..01948b20 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -78,12 +78,17 @@ void fwrite32le(ALuint val, FILE *f) } -struct WaveBackend final : public ALCbackend { - WaveBackend(ALCdevice *device) noexcept : ALCbackend{device} { } +struct WaveBackend final : public BackendBase { + WaveBackend(ALCdevice *device) noexcept : BackendBase{device} { } ~WaveBackend() override; int mixerProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + FILE *mFile{nullptr}; long mDataStart{-1}; @@ -93,32 +98,9 @@ struct WaveBackend final : public ALCbackend { std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "WaveBackend::"; } + DEF_NEWDEL(WaveBackend) }; -void WaveBackend_Construct(WaveBackend *self, ALCdevice *device); -void WaveBackend_Destruct(WaveBackend *self); -ALCenum WaveBackend_open(WaveBackend *self, const ALCchar *name); -ALCboolean WaveBackend_reset(WaveBackend *self); -ALCboolean WaveBackend_start(WaveBackend *self); -void WaveBackend_stop(WaveBackend *self); -DECLARE_FORWARD2(WaveBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -DECLARE_FORWARD(WaveBackend, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(WaveBackend, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(WaveBackend, ALCbackend, void, lock) -DECLARE_FORWARD(WaveBackend, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(WaveBackend) - -DEFINE_ALCBACKEND_VTABLE(WaveBackend); - -void WaveBackend_Construct(WaveBackend *self, ALCdevice *device) -{ - new (self) WaveBackend{device}; - SET_VTABLE2(WaveBackend, ALCbackend, self); -} - -void WaveBackend_Destruct(WaveBackend *self) -{ self->~WaveBackend(); } - WaveBackend::~WaveBackend() { if(mFile) @@ -151,9 +133,9 @@ int WaveBackend::mixerProc() } while(avail-done >= mDevice->UpdateSize) { - WaveBackend_lock(this); + lock(); aluMixData(mDevice, mBuffer.data(), mDevice->UpdateSize); - WaveBackend_unlock(this); + unlock(); done += mDevice->UpdateSize; if(!IS_LITTLE_ENDIAN) @@ -189,9 +171,9 @@ int WaveBackend::mixerProc() if(ferror(mFile)) { ERR("Error writing to file\n"); - WaveBackend_lock(this); + lock(); aluHandleDisconnect(mDevice, "Failed to write playback samples"); - WaveBackend_unlock(this); + unlock(); break; } } @@ -212,8 +194,7 @@ int WaveBackend::mixerProc() return 0; } - -ALCenum WaveBackend_open(WaveBackend *self, const ALCchar *name) +ALCenum WaveBackend::open(const ALCchar *name) { const char *fname{GetConfigValue(nullptr, "wave", "file", "")}; if(!fname[0]) return ALC_INVALID_VALUE; @@ -226,49 +207,47 @@ ALCenum WaveBackend_open(WaveBackend *self, const ALCchar *name) #ifdef _WIN32 { std::wstring wname = utf8_to_wstr(fname); - self->mFile = _wfopen(wname.c_str(), L"wb"); + mFile = _wfopen(wname.c_str(), L"wb"); } #else - self->mFile = fopen(fname, "wb"); + mFile = fopen(fname, "wb"); #endif - if(!self->mFile) + if(!mFile) { ERR("Could not open file '%s': %s\n", fname, strerror(errno)); return ALC_INVALID_VALUE; } - ALCdevice *device{self->mDevice}; - device->DeviceName = name; + mDevice->DeviceName = name; return ALC_NO_ERROR; } -ALCboolean WaveBackend_reset(WaveBackend *self) +ALCboolean WaveBackend::reset() { - ALCdevice *device{self->mDevice}; ALuint channels=0, bits=0, chanmask=0; int isbformat = 0; size_t val; - fseek(self->mFile, 0, SEEK_SET); - clearerr(self->mFile); + fseek(mFile, 0, SEEK_SET); + clearerr(mFile); if(GetConfigValueBool(nullptr, "wave", "bformat", 0)) { - device->FmtChans = DevFmtAmbi3D; - device->mAmbiOrder = 1; + mDevice->FmtChans = DevFmtAmbi3D; + mDevice->mAmbiOrder = 1; } - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtByte: - device->FmtType = DevFmtUByte; + mDevice->FmtType = DevFmtUByte; break; case DevFmtUShort: - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; break; case DevFmtUInt: - device->FmtType = DevFmtInt; + mDevice->FmtType = DevFmtInt; break; case DevFmtUByte: case DevFmtShort: @@ -276,7 +255,7 @@ ALCboolean WaveBackend_reset(WaveBackend *self) case DevFmtFloat: break; } - switch(device->FmtChans) + switch(mDevice->FmtChans) { case DevFmtMono: chanmask = 0x04; break; case DevFmtStereo: chanmask = 0x01 | 0x02; break; @@ -287,71 +266,71 @@ ALCboolean WaveBackend_reset(WaveBackend *self) case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break; case DevFmtAmbi3D: /* .amb output requires FuMa */ - device->mAmbiOrder = mini(device->mAmbiOrder, 3); - device->mAmbiLayout = AmbiLayout::FuMa; - device->mAmbiScale = AmbiNorm::FuMa; + mDevice->mAmbiOrder = mini(mDevice->mAmbiOrder, 3); + mDevice->mAmbiLayout = AmbiLayout::FuMa; + mDevice->mAmbiScale = AmbiNorm::FuMa; isbformat = 1; chanmask = 0; break; } - bits = device->bytesFromFmt() * 8; - channels = device->channelsFromFmt(); + bits = mDevice->bytesFromFmt() * 8; + channels = mDevice->channelsFromFmt(); - fputs("RIFF", self->mFile); - fwrite32le(0xFFFFFFFF, self->mFile); // 'RIFF' header len; filled in at close + fputs("RIFF", mFile); + fwrite32le(0xFFFFFFFF, mFile); // 'RIFF' header len; filled in at close - fputs("WAVE", self->mFile); + fputs("WAVE", mFile); - fputs("fmt ", self->mFile); - fwrite32le(40, self->mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE + fputs("fmt ", mFile); + fwrite32le(40, mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE // 16-bit val, format type id (extensible: 0xFFFE) - fwrite16le(0xFFFE, self->mFile); + fwrite16le(0xFFFE, mFile); // 16-bit val, channel count - fwrite16le(channels, self->mFile); + fwrite16le(channels, mFile); // 32-bit val, frequency - fwrite32le(device->Frequency, self->mFile); + fwrite32le(mDevice->Frequency, mFile); // 32-bit val, bytes per second - fwrite32le(device->Frequency * channels * bits / 8, self->mFile); + fwrite32le(mDevice->Frequency * channels * bits / 8, mFile); // 16-bit val, frame size - fwrite16le(channels * bits / 8, self->mFile); + fwrite16le(channels * bits / 8, mFile); // 16-bit val, bits per sample - fwrite16le(bits, self->mFile); + fwrite16le(bits, mFile); // 16-bit val, extra byte count - fwrite16le(22, self->mFile); + fwrite16le(22, mFile); // 16-bit val, valid bits per sample - fwrite16le(bits, self->mFile); + fwrite16le(bits, mFile); // 32-bit val, channel mask - fwrite32le(chanmask, self->mFile); + fwrite32le(chanmask, mFile); // 16 byte GUID, sub-type format - val = fwrite((device->FmtType == DevFmtFloat) ? + val = fwrite((mDevice->FmtType == DevFmtFloat) ? (isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) : - (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM), 1, 16, self->mFile); + (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM), 1, 16, mFile); (void)val; - fputs("data", self->mFile); - fwrite32le(0xFFFFFFFF, self->mFile); // 'data' header len; filled in at close + fputs("data", mFile); + fwrite32le(0xFFFFFFFF, mFile); // 'data' header len; filled in at close - if(ferror(self->mFile)) + if(ferror(mFile)) { ERR("Error writing header: %s\n", strerror(errno)); return ALC_FALSE; } - self->mDataStart = ftell(self->mFile); + mDataStart = ftell(mFile); - SetDefaultWFXChannelOrder(device); + SetDefaultWFXChannelOrder(mDevice); - const ALuint bufsize{device->frameSizeFromFmt() * device->UpdateSize}; - self->mBuffer.resize(bufsize); + const ALuint bufsize{mDevice->frameSizeFromFmt() * mDevice->UpdateSize}; + mBuffer.resize(bufsize); return ALC_TRUE; } -ALCboolean WaveBackend_start(WaveBackend *self) +ALCboolean WaveBackend::start() { try { - self->mKillNow.store(AL_FALSE, std::memory_order_release); - self->mThread = std::thread{std::mem_fn(&WaveBackend::mixerProc), self}; + mKillNow.store(AL_FALSE, std::memory_order_release); + mThread = std::thread{std::mem_fn(&WaveBackend::mixerProc), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -362,20 +341,20 @@ ALCboolean WaveBackend_start(WaveBackend *self) return ALC_FALSE; } -void WaveBackend_stop(WaveBackend *self) +void WaveBackend::stop() { - if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->mThread.joinable()) + if(mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !mThread.joinable()) return; - self->mThread.join(); + mThread.join(); - long size{ftell(self->mFile)}; + long size{ftell(mFile)}; if(size > 0) { - long dataLen{size - self->mDataStart}; - if(fseek(self->mFile, self->mDataStart-4, SEEK_SET) == 0) - fwrite32le(dataLen, self->mFile); // 'data' header len - if(fseek(self->mFile, 4, SEEK_SET) == 0) - fwrite32le(size-8, self->mFile); // 'WAVE' header len + long dataLen{size - mDataStart}; + if(fseek(mFile, mDataStart-4, SEEK_SET) == 0) + fwrite32le(dataLen, mFile); // 'data' header len + if(fseek(mFile, 4, SEEK_SET) == 0) + fwrite32le(size-8, mFile); // 'WAVE' header len } } @@ -401,15 +380,10 @@ void WaveBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *WaveBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *WaveBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - WaveBackend *backend; - NEW_OBJ(backend, WaveBackend)(device); - return backend; - } - + return new WaveBackend{device}; return nullptr; } diff --git a/Alc/backends/wave.h b/Alc/backends/wave.h index bb51cc71..08d3f0c2 100644 --- a/Alc/backends/wave.h +++ b/Alc/backends/wave.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 09b7a2e2..5051aa00 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -120,8 +120,8 @@ void ProbeCaptureDevices(void) } -struct WinMMPlayback final : public ALCbackend { - WinMMPlayback(ALCdevice *device) noexcept : ALCbackend{device} { } +struct WinMMPlayback final : public BackendBase { + WinMMPlayback(ALCdevice *device) noexcept : BackendBase{device} { } ~WinMMPlayback() override; static void CALLBACK waveOutProcC(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); @@ -129,6 +129,11 @@ struct WinMMPlayback final : public ALCbackend { int mixerProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + std::atomic mWritable{0u}; al::semaphore mSem; int mIdx{0}; @@ -142,32 +147,9 @@ struct WinMMPlayback final : public ALCbackend { std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "WinMMPlayback::"; } + DEF_NEWDEL(WinMMPlayback) }; -void WinMMPlayback_Construct(WinMMPlayback *self, ALCdevice *device); -void WinMMPlayback_Destruct(WinMMPlayback *self); -ALCenum WinMMPlayback_open(WinMMPlayback *self, const ALCchar *name); -ALCboolean WinMMPlayback_reset(WinMMPlayback *self); -ALCboolean WinMMPlayback_start(WinMMPlayback *self); -void WinMMPlayback_stop(WinMMPlayback *self); -DECLARE_FORWARD2(WinMMPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -DECLARE_FORWARD(WinMMPlayback, ALCbackend, ALCuint, availableSamples) -DECLARE_FORWARD(WinMMPlayback, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(WinMMPlayback, ALCbackend, void, lock) -DECLARE_FORWARD(WinMMPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(WinMMPlayback) - -DEFINE_ALCBACKEND_VTABLE(WinMMPlayback); - -void WinMMPlayback_Construct(WinMMPlayback *self, ALCdevice *device) -{ - new (self) WinMMPlayback{device}; - SET_VTABLE2(WinMMPlayback, ALCbackend, self); -} - -void WinMMPlayback_Destruct(WinMMPlayback *self) -{ self->~WinMMPlayback(); } - WinMMPlayback::~WinMMPlayback() { if(mOutHdl) @@ -200,16 +182,16 @@ FORCE_ALIGN int WinMMPlayback::mixerProc() SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - WinMMPlayback_lock(this); + lock(); while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) { ALsizei todo = mWritable.load(std::memory_order_acquire); if(todo < 1) { - WinMMPlayback_unlock(this); + unlock(); mSem.wait(); - WinMMPlayback_lock(this); + lock(); continue; } @@ -224,146 +206,137 @@ FORCE_ALIGN int WinMMPlayback::mixerProc() } while(--todo); mIdx = widx; } - WinMMPlayback_unlock(this); + unlock(); return 0; } -ALCenum WinMMPlayback_open(WinMMPlayback *self, const ALCchar *deviceName) +ALCenum WinMMPlayback::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - if(PlaybackDevices.empty()) ProbePlaybackDevices(); // Find the Device ID matching the deviceName if valid - auto iter = deviceName ? - std::find(PlaybackDevices.cbegin(), PlaybackDevices.cend(), deviceName) : + auto iter = name ? + std::find(PlaybackDevices.cbegin(), PlaybackDevices.cend(), name) : PlaybackDevices.cbegin(); if(iter == PlaybackDevices.cend()) return ALC_INVALID_VALUE; auto DeviceID = static_cast(std::distance(PlaybackDevices.cbegin(), iter)); retry_open: - self->mFormat = WAVEFORMATEX{}; - if(device->FmtType == DevFmtFloat) + mFormat = WAVEFORMATEX{}; + if(mDevice->FmtType == DevFmtFloat) { - self->mFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; - self->mFormat.wBitsPerSample = 32; + mFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + mFormat.wBitsPerSample = 32; } else { - self->mFormat.wFormatTag = WAVE_FORMAT_PCM; - if(device->FmtType == DevFmtUByte || device->FmtType == DevFmtByte) - self->mFormat.wBitsPerSample = 8; + mFormat.wFormatTag = WAVE_FORMAT_PCM; + if(mDevice->FmtType == DevFmtUByte || mDevice->FmtType == DevFmtByte) + mFormat.wBitsPerSample = 8; else - self->mFormat.wBitsPerSample = 16; + mFormat.wBitsPerSample = 16; } - self->mFormat.nChannels = ((device->FmtChans == DevFmtMono) ? 1 : 2); - self->mFormat.nBlockAlign = self->mFormat.wBitsPerSample * - self->mFormat.nChannels / 8; - self->mFormat.nSamplesPerSec = device->Frequency; - self->mFormat.nAvgBytesPerSec = self->mFormat.nSamplesPerSec * - self->mFormat.nBlockAlign; - self->mFormat.cbSize = 0; - - MMRESULT res{waveOutOpen(&self->mOutHdl, DeviceID, &self->mFormat, - (DWORD_PTR)&WinMMPlayback::waveOutProcC, (DWORD_PTR)self, CALLBACK_FUNCTION)}; + mFormat.nChannels = ((mDevice->FmtChans == DevFmtMono) ? 1 : 2); + mFormat.nBlockAlign = mFormat.wBitsPerSample * mFormat.nChannels / 8; + mFormat.nSamplesPerSec = mDevice->Frequency; + mFormat.nAvgBytesPerSec = mFormat.nSamplesPerSec * mFormat.nBlockAlign; + mFormat.cbSize = 0; + + MMRESULT res{waveOutOpen(&mOutHdl, DeviceID, &mFormat, (DWORD_PTR)&WinMMPlayback::waveOutProcC, + reinterpret_cast(this), CALLBACK_FUNCTION)}; if(res != MMSYSERR_NOERROR) { - if(device->FmtType == DevFmtFloat) + if(mDevice->FmtType == DevFmtFloat) { - device->FmtType = DevFmtShort; + mDevice->FmtType = DevFmtShort; goto retry_open; } ERR("waveOutOpen failed: %u\n", res); return ALC_INVALID_VALUE; } - device->DeviceName = PlaybackDevices[DeviceID]; + mDevice->DeviceName = PlaybackDevices[DeviceID]; return ALC_NO_ERROR; } -ALCboolean WinMMPlayback_reset(WinMMPlayback *self) +ALCboolean WinMMPlayback::reset() { - ALCdevice *device{self->mDevice}; + mDevice->UpdateSize = static_cast( + (ALuint64)mDevice->UpdateSize * mFormat.nSamplesPerSec / mDevice->Frequency); + mDevice->UpdateSize = (mDevice->UpdateSize*mDevice->NumUpdates + 3) / 4; + mDevice->NumUpdates = 4; + mDevice->Frequency = mFormat.nSamplesPerSec; - device->UpdateSize = static_cast( - (ALuint64)device->UpdateSize * self->mFormat.nSamplesPerSec / device->Frequency); - device->UpdateSize = (device->UpdateSize*device->NumUpdates + 3) / 4; - device->NumUpdates = 4; - device->Frequency = self->mFormat.nSamplesPerSec; - - if(self->mFormat.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) + if(mFormat.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) { - if(self->mFormat.wBitsPerSample == 32) - device->FmtType = DevFmtFloat; + if(mFormat.wBitsPerSample == 32) + mDevice->FmtType = DevFmtFloat; else { - ERR("Unhandled IEEE float sample depth: %d\n", self->mFormat.wBitsPerSample); + ERR("Unhandled IEEE float sample depth: %d\n", mFormat.wBitsPerSample); return ALC_FALSE; } } - else if(self->mFormat.wFormatTag == WAVE_FORMAT_PCM) + else if(mFormat.wFormatTag == WAVE_FORMAT_PCM) { - if(self->mFormat.wBitsPerSample == 16) - device->FmtType = DevFmtShort; - else if(self->mFormat.wBitsPerSample == 8) - device->FmtType = DevFmtUByte; + if(mFormat.wBitsPerSample == 16) + mDevice->FmtType = DevFmtShort; + else if(mFormat.wBitsPerSample == 8) + mDevice->FmtType = DevFmtUByte; else { - ERR("Unhandled PCM sample depth: %d\n", self->mFormat.wBitsPerSample); + ERR("Unhandled PCM sample depth: %d\n", mFormat.wBitsPerSample); return ALC_FALSE; } } else { - ERR("Unhandled format tag: 0x%04x\n", self->mFormat.wFormatTag); + ERR("Unhandled format tag: 0x%04x\n", mFormat.wFormatTag); return ALC_FALSE; } - if(self->mFormat.nChannels == 2) - device->FmtChans = DevFmtStereo; - else if(self->mFormat.nChannels == 1) - device->FmtChans = DevFmtMono; + if(mFormat.nChannels == 2) + mDevice->FmtChans = DevFmtStereo; + else if(mFormat.nChannels == 1) + mDevice->FmtChans = DevFmtMono; else { - ERR("Unhandled channel count: %d\n", self->mFormat.nChannels); + ERR("Unhandled channel count: %d\n", mFormat.nChannels); return ALC_FALSE; } - SetDefaultWFXChannelOrder(device); + SetDefaultWFXChannelOrder(mDevice); - ALuint BufferSize{device->UpdateSize * device->frameSizeFromFmt()}; + ALuint BufferSize{mDevice->UpdateSize * mDevice->frameSizeFromFmt()}; - al_free(self->mWaveBuffer[0].lpData); - self->mWaveBuffer[0] = WAVEHDR{}; - self->mWaveBuffer[0].lpData = static_cast(al_calloc(16, - BufferSize * self->mWaveBuffer.size())); - self->mWaveBuffer[0].dwBufferLength = BufferSize; - for(size_t i{1};i < self->mWaveBuffer.size();i++) + al_free(mWaveBuffer[0].lpData); + mWaveBuffer[0] = WAVEHDR{}; + mWaveBuffer[0].lpData = static_cast(al_calloc(16, BufferSize * mWaveBuffer.size())); + mWaveBuffer[0].dwBufferLength = BufferSize; + for(size_t i{1};i < mWaveBuffer.size();i++) { - self->mWaveBuffer[i] = WAVEHDR{}; - self->mWaveBuffer[i].lpData = self->mWaveBuffer[i-1].lpData + - self->mWaveBuffer[i-1].dwBufferLength; - self->mWaveBuffer[i].dwBufferLength = BufferSize; + mWaveBuffer[i] = WAVEHDR{}; + mWaveBuffer[i].lpData = mWaveBuffer[i-1].lpData + mWaveBuffer[i-1].dwBufferLength; + mWaveBuffer[i].dwBufferLength = BufferSize; } - self->mIdx = 0; + mIdx = 0; return ALC_TRUE; } -ALCboolean WinMMPlayback_start(WinMMPlayback *self) +ALCboolean WinMMPlayback::start() { try { - std::for_each(self->mWaveBuffer.begin(), self->mWaveBuffer.end(), - [self](WAVEHDR &waveHdr) -> void - { waveOutPrepareHeader(self->mOutHdl, &waveHdr, static_cast(sizeof(WAVEHDR))); } + std::for_each(mWaveBuffer.begin(), mWaveBuffer.end(), + [this](WAVEHDR &waveHdr) -> void + { waveOutPrepareHeader(mOutHdl, &waveHdr, static_cast(sizeof(WAVEHDR))); } ); - self->mWritable.store(static_cast(self->mWaveBuffer.size()), - std::memory_order_release); + mWritable.store(static_cast(mWaveBuffer.size()), std::memory_order_release); - self->mKillNow.store(AL_FALSE, std::memory_order_release); - self->mThread = std::thread{std::mem_fn(&WinMMPlayback::mixerProc), self}; + mKillNow.store(AL_FALSE, std::memory_order_release); + mThread = std::thread{std::mem_fn(&WinMMPlayback::mixerProc), this}; return ALC_TRUE; } catch(std::exception& e) { @@ -374,24 +347,24 @@ ALCboolean WinMMPlayback_start(WinMMPlayback *self) return ALC_FALSE; } -void WinMMPlayback_stop(WinMMPlayback *self) +void WinMMPlayback::stop() { - if(self->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !self->mThread.joinable()) + if(mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !mThread.joinable()) return; - self->mThread.join(); + mThread.join(); - while(self->mWritable.load(std::memory_order_acquire) < self->mWaveBuffer.size()) - self->mSem.wait(); - std::for_each(self->mWaveBuffer.begin(), self->mWaveBuffer.end(), - [self](WAVEHDR &waveHdr) -> void - { waveOutUnprepareHeader(self->mOutHdl, &waveHdr, sizeof(WAVEHDR)); } + while(mWritable.load(std::memory_order_acquire) < mWaveBuffer.size()) + mSem.wait(); + std::for_each(mWaveBuffer.begin(), mWaveBuffer.end(), + [this](WAVEHDR &waveHdr) -> void + { waveOutUnprepareHeader(mOutHdl, &waveHdr, sizeof(WAVEHDR)); } ); - self->mWritable.store(0, std::memory_order_release); + mWritable.store(0, std::memory_order_release); } -struct WinMMCapture final : public ALCbackend { - WinMMCapture(ALCdevice *device) noexcept : ALCbackend{device} { } +struct WinMMCapture final : public BackendBase { + WinMMCapture(ALCdevice *device) noexcept : BackendBase{device} { } ~WinMMCapture() override; static void CALLBACK waveInProcC(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); @@ -399,6 +372,12 @@ struct WinMMCapture final : public ALCbackend { int captureProc(); + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + std::atomic mReadable{0u}; al::semaphore mSem; int mIdx{0}; @@ -414,32 +393,9 @@ struct WinMMCapture final : public ALCbackend { std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "WinMMCapture::"; } + DEF_NEWDEL(WinMMCapture) }; -void WinMMCapture_Construct(WinMMCapture *self, ALCdevice *device); -void WinMMCapture_Destruct(WinMMCapture *self); -ALCenum WinMMCapture_open(WinMMCapture *self, const ALCchar *deviceName); -DECLARE_FORWARD(WinMMCapture, ALCbackend, ALCboolean, reset) -ALCboolean WinMMCapture_start(WinMMCapture *self); -void WinMMCapture_stop(WinMMCapture *self); -ALCenum WinMMCapture_captureSamples(WinMMCapture *self, ALCvoid *buffer, ALCuint samples); -ALCuint WinMMCapture_availableSamples(WinMMCapture *self); -DECLARE_FORWARD(WinMMCapture, ALCbackend, ClockLatency, getClockLatency) -DECLARE_FORWARD(WinMMCapture, ALCbackend, void, lock) -DECLARE_FORWARD(WinMMCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(WinMMCapture) - -DEFINE_ALCBACKEND_VTABLE(WinMMCapture); - -void WinMMCapture_Construct(WinMMCapture *self, ALCdevice *device) -{ - new (self) WinMMCapture{device}; - SET_VTABLE2(WinMMCapture, ALCbackend, self); -} - -void WinMMCapture_Destruct(WinMMCapture *self) -{ self->~WinMMCapture(); } - WinMMCapture::~WinMMCapture() { // Close the Wave device @@ -471,16 +427,16 @@ int WinMMCapture::captureProc() { althrd_setname(RECORD_THREAD_NAME); - WinMMCapture_lock(this); + lock(); while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) { ALuint todo{mReadable.load(std::memory_order_acquire)}; if(todo < 1) { - WinMMCapture_unlock(this); + unlock(); mSem.wait(); - WinMMCapture_lock(this); + lock(); continue; } @@ -495,27 +451,25 @@ int WinMMCapture::captureProc() } while(--todo); mIdx = widx; } - WinMMCapture_unlock(this); + unlock(); return 0; } -ALCenum WinMMCapture_open(WinMMCapture *self, const ALCchar *deviceName) +ALCenum WinMMCapture::open(const ALCchar *name) { - ALCdevice *device{self->mDevice}; - if(CaptureDevices.empty()) ProbeCaptureDevices(); // Find the Device ID matching the deviceName if valid - auto iter = deviceName ? - std::find(CaptureDevices.cbegin(), CaptureDevices.cend(), deviceName) : + auto iter = name ? + std::find(CaptureDevices.cbegin(), CaptureDevices.cend(), name) : CaptureDevices.cbegin(); if(iter == CaptureDevices.cend()) return ALC_INVALID_VALUE; auto DeviceID = static_cast(std::distance(CaptureDevices.cbegin(), iter)); - switch(device->FmtChans) + switch(mDevice->FmtChans) { case DevFmtMono: case DevFmtStereo: @@ -530,7 +484,7 @@ ALCenum WinMMCapture_open(WinMMCapture *self, const ALCchar *deviceName) return ALC_INVALID_ENUM; } - switch(device->FmtType) + switch(mDevice->FmtType) { case DevFmtUByte: case DevFmtShort: @@ -544,21 +498,18 @@ ALCenum WinMMCapture_open(WinMMCapture *self, const ALCchar *deviceName) return ALC_INVALID_ENUM; } - self->mFormat = WAVEFORMATEX{}; - self->mFormat.wFormatTag = (device->FmtType == DevFmtFloat) ? - WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM; - self->mFormat.nChannels = device->channelsFromFmt(); - self->mFormat.wBitsPerSample = device->bytesFromFmt() * 8; - self->mFormat.nBlockAlign = self->mFormat.wBitsPerSample * - self->mFormat.nChannels / 8; - self->mFormat.nSamplesPerSec = device->Frequency; - self->mFormat.nAvgBytesPerSec = self->mFormat.nSamplesPerSec * - self->mFormat.nBlockAlign; - self->mFormat.cbSize = 0; - - MMRESULT res{waveInOpen(&self->mInHdl, DeviceID, &self->mFormat, - (DWORD_PTR)&WinMMCapture::waveInProcC, (DWORD_PTR)self, CALLBACK_FUNCTION - )}; + mFormat = WAVEFORMATEX{}; + mFormat.wFormatTag = (mDevice->FmtType == DevFmtFloat) ? + WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM; + mFormat.nChannels = mDevice->channelsFromFmt(); + mFormat.wBitsPerSample = mDevice->bytesFromFmt() * 8; + mFormat.nBlockAlign = mFormat.wBitsPerSample * mFormat.nChannels / 8; + mFormat.nSamplesPerSec = mDevice->Frequency; + mFormat.nAvgBytesPerSec = mFormat.nSamplesPerSec * mFormat.nBlockAlign; + mFormat.cbSize = 0; + + MMRESULT res{waveInOpen(&mInHdl, DeviceID, &mFormat, (DWORD_PTR)&WinMMCapture::waveInProcC, + reinterpret_cast(this), CALLBACK_FUNCTION)}; if(res != MMSYSERR_NOERROR) { ERR("waveInOpen failed: %u\n", res); @@ -566,47 +517,46 @@ ALCenum WinMMCapture_open(WinMMCapture *self, const ALCchar *deviceName) } // Ensure each buffer is 50ms each - DWORD BufferSize{self->mFormat.nAvgBytesPerSec / 20u}; - BufferSize -= (BufferSize % self->mFormat.nBlockAlign); + DWORD BufferSize{mFormat.nAvgBytesPerSec / 20u}; + BufferSize -= (BufferSize % mFormat.nBlockAlign); // Allocate circular memory buffer for the captured audio // Make sure circular buffer is at least 100ms in size - ALuint CapturedDataSize{device->UpdateSize*device->NumUpdates}; + ALuint CapturedDataSize{mDevice->UpdateSize*mDevice->NumUpdates}; CapturedDataSize = static_cast( - std::max(CapturedDataSize, BufferSize*self->mWaveBuffer.size())); + std::max(CapturedDataSize, BufferSize*mWaveBuffer.size())); - self->mRing = CreateRingBuffer(CapturedDataSize, self->mFormat.nBlockAlign, false); - if(!self->mRing) return ALC_INVALID_VALUE; + mRing = CreateRingBuffer(CapturedDataSize, mFormat.nBlockAlign, false); + if(!mRing) return ALC_INVALID_VALUE; - al_free(self->mWaveBuffer[0].lpData); - self->mWaveBuffer[0] = WAVEHDR{}; - self->mWaveBuffer[0].lpData = static_cast(al_calloc(16, BufferSize*4)); - self->mWaveBuffer[0].dwBufferLength = BufferSize; - for(size_t i{1};i < self->mWaveBuffer.size();++i) + al_free(mWaveBuffer[0].lpData); + mWaveBuffer[0] = WAVEHDR{}; + mWaveBuffer[0].lpData = static_cast(al_calloc(16, BufferSize*4)); + mWaveBuffer[0].dwBufferLength = BufferSize; + for(size_t i{1};i < mWaveBuffer.size();++i) { - self->mWaveBuffer[i] = WAVEHDR{}; - self->mWaveBuffer[i].lpData = self->mWaveBuffer[i-1].lpData + - self->mWaveBuffer[i-1].dwBufferLength; - self->mWaveBuffer[i].dwBufferLength = self->mWaveBuffer[i-1].dwBufferLength; + mWaveBuffer[i] = WAVEHDR{}; + mWaveBuffer[i].lpData = mWaveBuffer[i-1].lpData + mWaveBuffer[i-1].dwBufferLength; + mWaveBuffer[i].dwBufferLength = mWaveBuffer[i-1].dwBufferLength; } - device->DeviceName = CaptureDevices[DeviceID]; + mDevice->DeviceName = CaptureDevices[DeviceID]; return ALC_NO_ERROR; } -ALCboolean WinMMCapture_start(WinMMCapture *self) +ALCboolean WinMMCapture::start() { try { - for(size_t i{0};i < self->mWaveBuffer.size();++i) + for(size_t i{0};i < mWaveBuffer.size();++i) { - waveInPrepareHeader(self->mInHdl, &self->mWaveBuffer[i], sizeof(WAVEHDR)); - waveInAddBuffer(self->mInHdl, &self->mWaveBuffer[i], sizeof(WAVEHDR)); + waveInPrepareHeader(mInHdl, &mWaveBuffer[i], sizeof(WAVEHDR)); + waveInAddBuffer(mInHdl, &mWaveBuffer[i], sizeof(WAVEHDR)); } - self->mKillNow.store(AL_FALSE, std::memory_order_release); - self->mThread = std::thread{std::mem_fn(&WinMMCapture::captureProc), self}; + mKillNow.store(AL_FALSE, std::memory_order_release); + mThread = std::thread{std::mem_fn(&WinMMCapture::captureProc), this}; - waveInStart(self->mInHdl); + waveInStart(mInHdl); return ALC_TRUE; } catch(std::exception& e) { @@ -617,37 +567,33 @@ ALCboolean WinMMCapture_start(WinMMCapture *self) return ALC_FALSE; } -void WinMMCapture_stop(WinMMCapture *self) +void WinMMCapture::stop() { - waveInStop(self->mInHdl); + waveInStop(mInHdl); - self->mKillNow.store(AL_TRUE, std::memory_order_release); - if(self->mThread.joinable()) + mKillNow.store(AL_TRUE, std::memory_order_release); + if(mThread.joinable()) { - self->mSem.post(); - self->mThread.join(); + mSem.post(); + mThread.join(); } - waveInReset(self->mInHdl); - for(size_t i{0};i < self->mWaveBuffer.size();++i) - waveInUnprepareHeader(self->mInHdl, &self->mWaveBuffer[i], sizeof(WAVEHDR)); + waveInReset(mInHdl); + for(size_t i{0};i < mWaveBuffer.size();++i) + waveInUnprepareHeader(mInHdl, &mWaveBuffer[i], sizeof(WAVEHDR)); - self->mReadable.store(0, std::memory_order_release); - self->mIdx = 0; + mReadable.store(0, std::memory_order_release); + mIdx = 0; } -ALCenum WinMMCapture_captureSamples(WinMMCapture *self, ALCvoid *buffer, ALCuint samples) +ALCenum WinMMCapture::captureSamples(void *buffer, ALCuint samples) { - RingBuffer *ring{self->mRing.get()}; - ring->read(buffer, samples); + mRing->read(buffer, samples); return ALC_NO_ERROR; } -ALCuint WinMMCapture_availableSamples(WinMMCapture *self) -{ - RingBuffer *ring{self->mRing.get()}; - return (ALCuint)ring->readSpace(); -} +ALCuint WinMMCapture::availableSamples() +{ return (ALCuint)mRing->readSpace(); } } // namespace @@ -688,21 +634,12 @@ void WinMMBackendFactory::probe(DevProbe type, std::string *outnames) } } -ALCbackend *WinMMBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *WinMMBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) - { - WinMMPlayback *backend; - NEW_OBJ(backend, WinMMPlayback)(device); - return backend; - } + return new WinMMPlayback{device}; if(type == ALCbackend_Capture) - { - WinMMCapture *backend; - NEW_OBJ(backend, WinMMCapture)(device); - return backend; - } - + return new WinMMCapture{device}; return nullptr; } diff --git a/Alc/backends/winmm.h b/Alc/backends/winmm.h index e5801c01..63be6598 100644 --- a/Alc/backends/winmm.h +++ b/Alc/backends/winmm.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - ALCbackend *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/polymorphism.h b/Alc/polymorphism.h deleted file mode 100644 index 211d5db3..00000000 --- a/Alc/polymorphism.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef POLYMORPHISM_H -#define POLYMORPHISM_H - -/* Defines method forwards, which call the given parent's (T2's) implementation. */ -#define DECLARE_FORWARD(T1, T2, rettype, func) \ -rettype T1##_##func(T1 *obj) \ -{ return T2##_##func(static_cast(obj)); } - -#define DECLARE_FORWARD1(T1, T2, rettype, func, argtype1) \ -rettype T1##_##func(T1 *obj, argtype1 a) \ -{ return T2##_##func(static_cast(obj), a); } - -#define DECLARE_FORWARD2(T1, T2, rettype, func, argtype1, argtype2) \ -rettype T1##_##func(T1 *obj, argtype1 a, argtype2 b) \ -{ return T2##_##func(static_cast(obj), a, b); } - -#define DECLARE_FORWARD3(T1, T2, rettype, func, argtype1, argtype2, argtype3) \ -rettype T1##_##func(T1 *obj, argtype1 a, argtype2 b, argtype3 c) \ -{ return T2##_##func(static_cast(obj), a, b, c); } - -/* Defines method thunks, functions that call to the child's method. */ -#define DECLARE_THUNK(T1, T2, rettype, func) \ -static rettype T1##_##T2##_##func(T2 *obj) \ -{ return T1##_##func(static_cast(obj)); } - -#define DECLARE_THUNK1(T1, T2, rettype, func, argtype1) \ -static rettype T1##_##T2##_##func(T2 *obj, argtype1 a) \ -{ return T1##_##func(static_cast(obj), a); } - -#define DECLARE_THUNK2(T1, T2, rettype, func, argtype1, argtype2) \ -static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b) \ -{ return T1##_##func(static_cast(obj), a, b); } - -#define DECLARE_THUNK3(T1, T2, rettype, func, argtype1, argtype2, argtype3) \ -static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c) \ -{ return T1##_##func(static_cast(obj), a, b, c); } - -#define DECLARE_THUNK4(T1, T2, rettype, func, argtype1, argtype2, argtype3, argtype4) \ -static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c, argtype4 d) \ -{ return T1##_##func(static_cast(obj), a, b, c, d); } - -/* Defines the default functions used to (de)allocate a polymorphic object. */ -#define DECLARE_DEFAULT_ALLOCATORS(T) \ -static void* T##_New(size_t size) { return al_calloc(16, size); } \ -static void T##_Delete(void *ptr) { al_free(ptr); } - - -/* Helper to extract an argument list for virtual method calls. */ -#define EXTRACT_VCALL_ARGS(...) __VA_ARGS__)) - -/* Call a "virtual" method on an object, with arguments. */ -#define V(obj, func) ((obj)->vtbl->func((obj), EXTRACT_VCALL_ARGS -/* Call a "virtual" method on an object, with no arguments. */ -#define V0(obj, func) ((obj)->vtbl->func((obj) EXTRACT_VCALL_ARGS - - -/* Helper to extract an argument list for NEW_OBJ calls. */ -#define EXTRACT_NEW_ARGS(...) __VA_ARGS__); \ - } \ -} while(0) - -/* Allocate and construct an object, with arguments. */ -#define NEW_OBJ(_res, T) do { \ - _res = (T*)T##_New(sizeof(T)); \ - if(_res) \ - { \ - T##_Construct(_res, EXTRACT_NEW_ARGS -/* Allocate and construct an object, with no arguments. */ -#define NEW_OBJ0(_res, T) do { \ - _res = (T*)T##_New(sizeof(T)); \ - if(_res) \ - { \ - T##_Construct(_res EXTRACT_NEW_ARGS - -/* Destructs and deallocate an object. */ -#define DELETE_OBJ(obj) do { \ - if((obj) != NULL) \ - { \ - V0((obj),Destruct)(); \ - V0((obj),Delete)(); \ - } \ -} while(0) - - -/* Helper to get a type's vtable thunk for a child type. */ -#define GET_VTABLE2(T1, T2) (&(T1##_##T2##_vtable)) -/* Helper to set an object's vtable thunk for a child type. Used when constructing an object. */ -#define SET_VTABLE2(T1, T2, obj) (static_cast(obj)->vtbl = GET_VTABLE2(T1, T2)) - -#endif /* POLYMORPHISM_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 270d2a4e..3b2be332 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -773,7 +773,6 @@ SET(ALC_OBJS Alc/bformatdec.cpp Alc/bformatdec.h Alc/panning.cpp - Alc/polymorphism.h Alc/mixvoice.cpp Alc/mixer/defs.h Alc/mixer/mixer_c.cpp diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index e5ad21ef..391ef8df 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -236,7 +236,7 @@ struct EnumeratedHrtf; struct DirectHrtfState; struct FrontStablizer; struct Compressor; -struct ALCbackend; +struct BackendBase; struct ALbuffer; struct ALeffect; struct ALfilter; @@ -786,7 +786,7 @@ struct ALCdevice_struct { std::atomic ContextList{nullptr}; std::mutex BackendLock; - ALCbackend *Backend{nullptr}; + BackendBase *Backend{nullptr}; std::atomic next{nullptr}; -- cgit v1.2.3 From 8fd44772153c903e47529bde63fce40c56d7277d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 28 Dec 2018 23:19:49 -0800 Subject: Get CoreAudio capture samples in one call --- Alc/backends/coreaudio.cpp | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index 3f1f48d8..f117ea59 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -355,42 +355,41 @@ OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags* UNUSED(ioActio { AudioUnitRenderActionFlags flags = 0; union { - ALbyte _[sizeof(AudioBufferList) + sizeof(AudioBuffer)]; + ALbyte _[sizeof(AudioBufferList) + sizeof(AudioBuffer)*2]; AudioBufferList list; } audiobuf = { { 0 } }; auto rec_vec = mRing->getWriteVector(); + inNumberFrames = minz(inNumberFrames, rec_vec.first.len+rec_vec.second.len); - // Fill the ringbuffer's first segment with data from the input device - size_t total_read{minz(rec_vec.first.len, inNumberFrames)}; - audiobuf.list.mNumberBuffers = 1; - audiobuf.list.mBuffers[0].mNumberChannels = mFormat.mChannelsPerFrame; - audiobuf.list.mBuffers[0].mData = rec_vec.first.buf; - audiobuf.list.mBuffers[0].mDataByteSize = total_read * mFormat.mBytesPerFrame; - OSStatus err{AudioUnitRender(mAudioUnit, &flags, inTimeStamp, 1, inNumberFrames, - &audiobuf.list)}; - if(err == noErr && inNumberFrames > rec_vec.first.len && rec_vec.second.len > 0) - { - /* If there's still more to get and there's space in the ringbuffer's - * second segment, fill that with data too. - */ - const size_t remlen{inNumberFrames - rec_vec.first.len}; - const size_t toread{minz(rec_vec.second.len, remlen)}; - total_read += toread; - + // Fill the ringbuffer's two segments with data from the input device + if(rec_vec.first.len >= inNumberFrames) + { audiobuf.list.mNumberBuffers = 1; audiobuf.list.mBuffers[0].mNumberChannels = mFormat.mChannelsPerFrame; - audiobuf.list.mBuffers[0].mData = rec_vec.second.buf; - audiobuf.list.mBuffers[0].mDataByteSize = toread * mFormat.mBytesPerFrame; - err = AudioUnitRender(mAudioUnit, &flags, inTimeStamp, 1, inNumberFrames, &audiobuf.list); + audiobuf.list.mBuffers[0].mData = rec_vec.first.buf; + audiobuf.list.mBuffers[0].mDataByteSize = inNumberFrames * mFormat.mBytesPerFrame; + } + else + { + const size_t remaining{inNumberFrames-rec_vec.first.len}; + audiobuf.list.mNumberBuffers = 2; + audiobuf.list.mBuffers[0].mNumberChannels = mFormat.mChannelsPerFrame; + audiobuf.list.mBuffers[0].mData = rec_vec.first.buf; + audiobuf.list.mBuffers[0].mDataByteSize = rec_vec.first.len * mFormat.mBytesPerFrame; + audiobuf.list.mBuffers[1].mNumberChannels = mFormat.mChannelsPerFrame; + audiobuf.list.mBuffers[1].mData = rec_vec.second.buf; + audiobuf.list.mBuffers[1].mDataByteSize = remaining * mFormat.mBytesPerFrame; } + OSStatus err{AudioUnitRender(mAudioUnit, &flags, inTimeStamp, audiobuf.list.mNumberBuffers, + inNumberFrames, &audiobuf.list)}; if(err != noErr) { ERR("AudioUnitRender error: %d\n", err); return err; } - mRing->writeAdvance(total_read); + mRing->writeAdvance(inNumberFrames); return noErr; } -- cgit v1.2.3 From 3c637d5fd70e7bdb5dfc79c515359cba3eb0c9af Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Dec 2018 01:38:26 -0800 Subject: Make the backend type an enum class --- Alc/alc.cpp | 15 ++++++++------- Alc/backends/alsa.cpp | 10 +++++----- Alc/backends/alsa.h | 4 ++-- Alc/backends/base.h | 12 ++++++------ Alc/backends/coreaudio.cpp | 10 +++++----- Alc/backends/coreaudio.h | 4 ++-- Alc/backends/dsound.cpp | 10 +++++----- Alc/backends/dsound.h | 4 ++-- Alc/backends/jack.cpp | 8 ++++---- Alc/backends/jack.h | 4 ++-- Alc/backends/loopback.cpp | 8 ++++---- Alc/backends/loopback.h | 4 ++-- Alc/backends/null.cpp | 8 ++++---- Alc/backends/null.h | 4 ++-- Alc/backends/opensl.cpp | 10 +++++----- Alc/backends/opensl.h | 4 ++-- Alc/backends/oss.cpp | 10 +++++----- Alc/backends/oss.h | 4 ++-- Alc/backends/portaudio.cpp | 10 +++++----- Alc/backends/portaudio.h | 4 ++-- Alc/backends/pulseaudio.cpp | 30 +++++++++++++----------------- Alc/backends/pulseaudio.h | 4 ++-- Alc/backends/qsa.cpp | 10 +++++----- Alc/backends/qsa.h | 4 ++-- Alc/backends/sdl2.cpp | 10 ++++------ Alc/backends/sdl2.h | 4 ++-- Alc/backends/sndio.cpp | 10 +++++----- Alc/backends/sndio.h | 4 ++-- Alc/backends/solaris.cpp | 8 ++++---- Alc/backends/solaris.h | 4 ++-- Alc/backends/wasapi.cpp | 10 +++++----- Alc/backends/wasapi.h | 4 ++-- Alc/backends/wave.cpp | 8 ++++---- Alc/backends/wave.h | 4 ++-- Alc/backends/winmm.cpp | 10 +++++----- Alc/backends/winmm.h | 4 ++-- 36 files changed, 135 insertions(+), 140 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 95592556..c625fd20 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1116,12 +1116,12 @@ static void alc_initconfig(void) } TRACE("Initialized backend \"%s\"\n", BackendList[n].name); - if(!PlaybackBackend.name && factory.querySupport(ALCbackend_Playback)) + if(!PlaybackBackend.name && factory.querySupport(BackendType::Playback)) { PlaybackBackend = BackendList[n]; TRACE("Added \"%s\" for playback\n", PlaybackBackend.name); } - if(!CaptureBackend.name && factory.querySupport(ALCbackend_Capture)) + if(!CaptureBackend.name && factory.querySupport(BackendType::Capture)) { CaptureBackend = BackendList[n]; TRACE("Added \"%s\" for capture\n", CaptureBackend.name); @@ -3768,8 +3768,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->NumStereoSources = 1; device->NumMonoSources = device->SourcesMax - device->NumStereoSources; - device->Backend = PlaybackBackend.getFactory().createBackend( - device.get(), ALCbackend_Playback); + device->Backend = PlaybackBackend.getFactory().createBackend(device.get(), + BackendType::Playback); if(!device->Backend) { device = nullptr; @@ -3917,7 +3917,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, device->UpdateSize = samples; device->NumUpdates = 1; - device->Backend = CaptureBackend.getFactory().createBackend(device.get(), ALCbackend_Capture); + device->Backend = CaptureBackend.getFactory().createBackend(device.get(), + BackendType::Capture); if(!device->Backend) { device = nullptr; @@ -4093,8 +4094,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->NumStereoSources = 1; device->NumMonoSources = device->SourcesMax - device->NumStereoSources; - device->Backend = LoopbackBackendFactory::getFactory().createBackend( - device.get(), ALCbackend_Loopback); + device->Backend = LoopbackBackendFactory::getFactory().createBackend(device.get(), + BackendType::Loopback); if(!device->Backend) { device = nullptr; diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index c5d75fe3..543c2bee 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -1266,8 +1266,8 @@ void AlsaBackendFactory::deinit() #endif } -bool AlsaBackendFactory::querySupport(ALCbackend_Type type) -{ return (type == ALCbackend_Playback || type == ALCbackend_Capture); } +bool AlsaBackendFactory::querySupport(BackendType type) +{ return (type == BackendType::Playback || type == BackendType::Capture); } void AlsaBackendFactory::probe(DevProbe type, std::string *outnames) { @@ -1292,11 +1292,11 @@ void AlsaBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *AlsaBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *AlsaBackendFactory::createBackend(ALCdevice *device, BackendType type) { - if(type == ALCbackend_Playback) + if(type == BackendType::Playback) return new AlsaPlayback{device}; - if(type == ALCbackend_Capture) + if(type == BackendType::Capture) return new AlsaCapture{device}; return nullptr; } diff --git a/Alc/backends/alsa.h b/Alc/backends/alsa.h index e9169c48..15a646f9 100644 --- a/Alc/backends/alsa.h +++ b/Alc/backends/alsa.h @@ -8,11 +8,11 @@ public: bool init() override; void deinit() override; - bool querySupport(ALCbackend_Type type) override; + bool querySupport(BackendType type) override; void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/base.h b/Alc/backends/base.h index b9ea3b61..0fc7de38 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -55,10 +55,10 @@ struct BackendBase { }; -enum ALCbackend_Type { - ALCbackend_Playback, - ALCbackend_Capture, - ALCbackend_Loopback +enum class BackendType { + Playback, + Capture, + Loopback }; @@ -66,11 +66,11 @@ struct BackendFactory { virtual bool init() = 0; virtual void deinit() { } - virtual bool querySupport(ALCbackend_Type type) = 0; + virtual bool querySupport(BackendType type) = 0; virtual void probe(DevProbe type, std::string *outnames) = 0; - virtual BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) = 0; + virtual BackendBase *createBackend(ALCdevice *device, BackendType type) = 0; }; #endif /* ALC_BACKENDS_BASE_H */ diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index f117ea59..f4010631 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -688,8 +688,8 @@ BackendFactory &CoreAudioBackendFactory::getFactory() bool CoreAudioBackendFactory::init() { return true; } -bool CoreAudioBackendFactory::querySupport(ALCbackend_Type type) -{ return (type == ALCbackend_Playback || ALCbackend_Capture); } +bool CoreAudioBackendFactory::querySupport(BackendType type) +{ return type == BackendType::Playback || type == BackendType::Capture; } void CoreAudioBackendFactory::probe(DevProbe type, std::string *outnames) { @@ -703,11 +703,11 @@ void CoreAudioBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *CoreAudioBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *CoreAudioBackendFactory::createBackend(ALCdevice *device, BackendType type) { - if(type == ALCbackend_Playback) + if(type == BackendType::Playback) return new CoreAudioPlayback{device}; - if(type == ALCbackend_Capture) + if(type == BackendType::Capture) return new CoreAudioCapture{device}; return nullptr; } diff --git a/Alc/backends/coreaudio.h b/Alc/backends/coreaudio.h index db151b8a..d0ac9558 100644 --- a/Alc/backends/coreaudio.h +++ b/Alc/backends/coreaudio.h @@ -8,11 +8,11 @@ public: bool init() override; /*void deinit() override;*/ - bool querySupport(ALCbackend_Type type) override; + bool querySupport(BackendType type) override; void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 44e6fde4..bdb9cf28 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -911,8 +911,8 @@ void DSoundBackendFactory::deinit() #endif } -bool DSoundBackendFactory::querySupport(ALCbackend_Type type) -{ return (type == ALCbackend_Playback || type == ALCbackend_Capture); } +bool DSoundBackendFactory::querySupport(BackendType type) +{ return (type == BackendType::Playback || type == BackendType::Capture); } void DSoundBackendFactory::probe(DevProbe type, std::string *outnames) { @@ -949,11 +949,11 @@ void DSoundBackendFactory::probe(DevProbe type, std::string *outnames) CoUninitialize(); } -BackendBase *DSoundBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *DSoundBackendFactory::createBackend(ALCdevice *device, BackendType type) { - if(type == ALCbackend_Playback) + if(type == BackendType::Playback) return new DSoundPlayback{device}; - if(type == ALCbackend_Capture) + if(type == BackendType::Capture) return new DSoundCapture{device}; return nullptr; } diff --git a/Alc/backends/dsound.h b/Alc/backends/dsound.h index 93b76c7c..819c4231 100644 --- a/Alc/backends/dsound.h +++ b/Alc/backends/dsound.h @@ -8,11 +8,11 @@ public: bool init() override; void deinit() override; - bool querySupport(ALCbackend_Type type) override; + bool querySupport(BackendType type) override; void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index 77bbf487..eb96392f 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -541,8 +541,8 @@ void JackBackendFactory::deinit() #endif } -bool JackBackendFactory::querySupport(ALCbackend_Type type) -{ return (type == ALCbackend_Playback); } +bool JackBackendFactory::querySupport(BackendType type) +{ return (type == BackendType::Playback); } void JackBackendFactory::probe(DevProbe type, std::string *outnames) { @@ -558,9 +558,9 @@ void JackBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *JackBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *JackBackendFactory::createBackend(ALCdevice *device, BackendType type) { - if(type == ALCbackend_Playback) + if(type == BackendType::Playback) return new JackPlayback{device}; return nullptr; } diff --git a/Alc/backends/jack.h b/Alc/backends/jack.h index b9bb13b2..421fafde 100644 --- a/Alc/backends/jack.h +++ b/Alc/backends/jack.h @@ -8,11 +8,11 @@ public: bool init() override; void deinit() override; - bool querySupport(ALCbackend_Type type) override; + bool querySupport(BackendType type) override; void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/loopback.cpp b/Alc/backends/loopback.cpp index 373b11c9..6bce90ff 100644 --- a/Alc/backends/loopback.cpp +++ b/Alc/backends/loopback.cpp @@ -64,15 +64,15 @@ void LoopbackBackend::stop() bool LoopbackBackendFactory::init() { return true; } -bool LoopbackBackendFactory::querySupport(ALCbackend_Type type) -{ return (type == ALCbackend_Loopback); } +bool LoopbackBackendFactory::querySupport(BackendType type) +{ return (type == BackendType::Loopback); } void LoopbackBackendFactory::probe(DevProbe, std::string*) { } -BackendBase *LoopbackBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *LoopbackBackendFactory::createBackend(ALCdevice *device, BackendType type) { - if(type == ALCbackend_Loopback) + if(type == BackendType::Loopback) new LoopbackBackend{device}; return nullptr; } diff --git a/Alc/backends/loopback.h b/Alc/backends/loopback.h index ab37c2d7..cf5eb02a 100644 --- a/Alc/backends/loopback.h +++ b/Alc/backends/loopback.h @@ -8,11 +8,11 @@ public: bool init() override; /*void deinit() override;*/ - bool querySupport(ALCbackend_Type type) override; + bool querySupport(BackendType type) override; void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 33340a5d..480b5554 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -153,8 +153,8 @@ void NullBackend::stop() bool NullBackendFactory::init() { return true; } -bool NullBackendFactory::querySupport(ALCbackend_Type type) -{ return (type == ALCbackend_Playback); } +bool NullBackendFactory::querySupport(BackendType type) +{ return (type == BackendType::Playback); } void NullBackendFactory::probe(DevProbe type, std::string *outnames) { @@ -169,9 +169,9 @@ void NullBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *NullBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *NullBackendFactory::createBackend(ALCdevice *device, BackendType type) { - if(type == ALCbackend_Playback) + if(type == BackendType::Playback) return new NullBackend{device}; return nullptr; } diff --git a/Alc/backends/null.h b/Alc/backends/null.h index d4164198..87796b7a 100644 --- a/Alc/backends/null.h +++ b/Alc/backends/null.h @@ -8,11 +8,11 @@ public: bool init() override; /*void deinit() override;*/ - bool querySupport(ALCbackend_Type type) override; + bool querySupport(BackendType type) override; void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 4f2e07be..c6a8cf82 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -919,8 +919,8 @@ ALCuint OpenSLCapture::availableSamples() bool OSLBackendFactory::init() { return true; } -bool OSLBackendFactory::querySupport(ALCbackend_Type type) -{ return (type == ALCbackend_Playback || type == ALCbackend_Capture); } +bool OSLBackendFactory::querySupport(BackendType type) +{ return (type == BackendType::Playback || type == BackendType::Capture); } void OSLBackendFactory::probe(DevProbe type, std::string *outnames) { @@ -934,11 +934,11 @@ void OSLBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *OSLBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *OSLBackendFactory::createBackend(ALCdevice *device, BackendType type) { - if(type == ALCbackend_Playback) + if(type == BackendType::Playback) return new OpenSLPlayback{device}; - if(type == ALCbackend_Capture) + if(type == BackendType::Capture) return new OpenSLCapture{device}; return nullptr; } diff --git a/Alc/backends/opensl.h b/Alc/backends/opensl.h index bab15115..d553b80d 100644 --- a/Alc/backends/opensl.h +++ b/Alc/backends/opensl.h @@ -8,11 +8,11 @@ public: bool init() override; /*void deinit() override;*/ - bool querySupport(ALCbackend_Type type) override; + bool querySupport(BackendType type) override; void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index c2139d4d..90da18c7 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -718,8 +718,8 @@ void OSSBackendFactory::deinit() CaptureDevices.clear(); } -bool OSSBackendFactory::querySupport(ALCbackend_Type type) -{ return (type == ALCbackend_Playback || type == ALCbackend_Capture); } +bool OSSBackendFactory::querySupport(BackendType type) +{ return (type == BackendType::Playback || type == BackendType::Capture); } void OSSBackendFactory::probe(DevProbe type, std::string *outnames) { @@ -751,11 +751,11 @@ void OSSBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *OSSBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *OSSBackendFactory::createBackend(ALCdevice *device, BackendType type) { - if(type == ALCbackend_Playback) + if(type == BackendType::Playback) return new OSSPlayback{device}; - if(type == ALCbackend_Capture) + if(type == BackendType::Capture) return new OSScapture{device}; return nullptr; } diff --git a/Alc/backends/oss.h b/Alc/backends/oss.h index 8f65f1cc..f59bfe18 100644 --- a/Alc/backends/oss.h +++ b/Alc/backends/oss.h @@ -8,11 +8,11 @@ public: bool init() override; void deinit() override; - bool querySupport(ALCbackend_Type type) override; + bool querySupport(BackendType type) override; void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index 34688db9..ae01da70 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -452,8 +452,8 @@ void PortBackendFactory::deinit() #endif } -bool PortBackendFactory::querySupport(ALCbackend_Type type) -{ return (type == ALCbackend_Playback || type == ALCbackend_Capture); } +bool PortBackendFactory::querySupport(BackendType type) +{ return (type == BackendType::Playback || type == BackendType::Capture); } void PortBackendFactory::probe(DevProbe type, std::string *outnames) { @@ -467,11 +467,11 @@ void PortBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *PortBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *PortBackendFactory::createBackend(ALCdevice *device, BackendType type) { - if(type == ALCbackend_Playback) + if(type == BackendType::Playback) return new PortPlayback{device}; - if(type == ALCbackend_Capture) + if(type == BackendType::Capture) return new PortCapture{device}; return nullptr; } diff --git a/Alc/backends/portaudio.h b/Alc/backends/portaudio.h index 7687c6b3..84ef11d9 100644 --- a/Alc/backends/portaudio.h +++ b/Alc/backends/portaudio.h @@ -8,11 +8,11 @@ public: bool init() override; void deinit() override; - bool querySupport(ALCbackend_Type type) override; + bool querySupport(BackendType type) override; void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index c911e365..8a089b88 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -524,10 +524,10 @@ al::vector CaptureDevices; pa_stream *pulse_connect_stream(const char *device_name, pa_threaded_mainloop *loop, pa_context *context, pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, - pa_channel_map *chanmap, ALCbackend_Type type) + pa_channel_map *chanmap, BackendType type) { pa_stream *stream{pa_stream_new_with_proplist(context, - (type==ALCbackend_Playback) ? "Playback Stream" : "Capture Stream", spec, chanmap, + (type==BackendType::Playback) ? "Playback Stream" : "Capture Stream", spec, chanmap, prop_filter)}; if(!stream) { @@ -537,7 +537,7 @@ pa_stream *pulse_connect_stream(const char *device_name, pa_threaded_mainloop *l pa_stream_set_state_callback(stream, stream_state_callback, loop); - int err{(type==ALCbackend_Playback) ? + int err{(type==BackendType::Playback) ? pa_stream_connect_playback(stream, device_name, attr, flags, nullptr, nullptr) : pa_stream_connect_record(stream, device_name, attr, flags)}; if(err < 0) @@ -620,7 +620,7 @@ void probePlaybackDevices(void) spec.channels = 2; pa_stream *stream{pulse_connect_stream(nullptr, loop, context, flags, nullptr, &spec, - nullptr, ALCbackend_Playback)}; + nullptr, BackendType::Playback)}; if(stream) { pa_operation *op{pa_context_get_sink_info_by_name(context, @@ -702,7 +702,7 @@ void probeCaptureDevices(void) spec.channels = 1; pa_stream *stream{pulse_connect_stream(nullptr, loop, context, flags, nullptr, &spec, - nullptr, ALCbackend_Capture)}; + nullptr, BackendType::Capture)}; if(stream) { pa_operation *op{pa_context_get_source_info_by_name(context, @@ -986,7 +986,7 @@ ALCenum PulsePlayback::open(const ALCchar *name) if(pulse_name && !pulse_name[0]) pulse_name = nullptr; } mStream = pulse_connect_stream(pulse_name, mLoop, mContext, flags, nullptr, &spec, nullptr, - ALCbackend_Playback); + BackendType::Playback); if(!mStream) { palock = unique_palock{}; @@ -1117,7 +1117,7 @@ ALCboolean PulsePlayback::reset() mAttr.fragsize = -1; mStream = pulse_connect_stream(mDeviceName.c_str(), mLoop, mContext, flags, &mAttr, &mSpec, - &chanmap, ALCbackend_Playback); + &chanmap, BackendType::Playback); if(!mStream) return ALC_FALSE; pa_stream_set_state_callback(mStream, &PulsePlayback::streamStateCallbackC, this); @@ -1445,7 +1445,7 @@ ALCenum PulseCapture::open(const ALCchar *name) TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); mStream = pulse_connect_stream(pulse_name, mLoop, mContext, flags, &mAttr, &mSpec, &chanmap, - ALCbackend_Capture); + BackendType::Capture); if(!mStream) return ALC_INVALID_VALUE; pa_stream_set_moved_callback(mStream, &PulseCapture::streamMovedCallbackC, this); @@ -1638,12 +1638,8 @@ void PulseBackendFactory::deinit() /* PulseAudio doesn't like being CloseLib'd sometimes */ } -bool PulseBackendFactory::querySupport(ALCbackend_Type type) -{ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return true; - return false; -} +bool PulseBackendFactory::querySupport(BackendType type) +{ return type == BackendType::Playback || type == BackendType::Capture; } void PulseBackendFactory::probe(DevProbe type, std::string *outnames) { @@ -1668,11 +1664,11 @@ void PulseBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *PulseBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *PulseBackendFactory::createBackend(ALCdevice *device, BackendType type) { - if(type == ALCbackend_Playback) + if(type == BackendType::Playback) return new PulsePlayback{device}; - if(type == ALCbackend_Capture) + if(type == BackendType::Capture) return new PulseCapture{device}; return nullptr; } diff --git a/Alc/backends/pulseaudio.h b/Alc/backends/pulseaudio.h index 07d74b64..b7e71d82 100644 --- a/Alc/backends/pulseaudio.h +++ b/Alc/backends/pulseaudio.h @@ -8,11 +8,11 @@ public: bool init() override; void deinit() override; - bool querySupport(ALCbackend_Type type) override; + bool querySupport(BackendType type) override; void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index 7641ad57..0c695d92 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -927,8 +927,8 @@ void QSABackendFactory::deinit() CaptureNameMap.clear(); } -bool QSABackendFactory::querySupport(ALCbackend_Type type) -{ return (type == ALCbackend_Playback || type == ALCbackend_Capture); } +bool QSABackendFactory::querySupport(BackendType type) +{ return (type == BackendType::Playback || type == BackendType::Capture); } void QSABackendFactory::probe(DevProbe type, std::string *outnames) { @@ -952,11 +952,11 @@ void QSABackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *QSABackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *QSABackendFactory::createBackend(ALCdevice *device, BackendType type) { - if(type == ALCbackend_Playback) + if(type == BackendType::Playback) return new PlaybackWrapper{device}; - if(type == ALCbackend_Capture) + if(type == BackendType::Capture) return new CaptureWrapper{device}; return nullptr; } diff --git a/Alc/backends/qsa.h b/Alc/backends/qsa.h index 46cc7dd1..c136f652 100644 --- a/Alc/backends/qsa.h +++ b/Alc/backends/qsa.h @@ -8,11 +8,11 @@ public: bool init() override; void deinit() override; - bool querySupport(ALCbackend_Type type) override; + bool querySupport(BackendType type) override; void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/sdl2.cpp b/Alc/backends/sdl2.cpp index 91d1cece..72c2dbcd 100644 --- a/Alc/backends/sdl2.cpp +++ b/Alc/backends/sdl2.cpp @@ -202,10 +202,8 @@ void SDL2BackendFactory::deinit() SDL_QuitSubSystem(SDL_INIT_AUDIO); } -bool SDL2BackendFactory::querySupport(ALCbackend_Type type) -{ - return (type == ALCbackend_Playback); -} +bool SDL2BackendFactory::querySupport(BackendType type) +{ return type == BackendType::Playback; } void SDL2BackendFactory::probe(DevProbe type, std::string *outnames) { @@ -225,9 +223,9 @@ void SDL2BackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *SDL2BackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *SDL2BackendFactory::createBackend(ALCdevice *device, BackendType type) { - if(type == ALCbackend_Playback) + if(type == BackendType::Playback) return new Sdl2Backend{device}; return nullptr; } diff --git a/Alc/backends/sdl2.h b/Alc/backends/sdl2.h index 7a4ae9eb..34d30b16 100644 --- a/Alc/backends/sdl2.h +++ b/Alc/backends/sdl2.h @@ -8,11 +8,11 @@ public: bool init() override; void deinit() override; - bool querySupport(ALCbackend_Type type) override; + bool querySupport(BackendType type) override; void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index 2c2397e6..a592632c 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -477,8 +477,8 @@ BackendFactory &SndIOBackendFactory::getFactory() bool SndIOBackendFactory::init() { return true; } -bool SndIOBackendFactory::querySupport(ALCbackend_Type type) -{ return (type == ALCbackend_Playback || type == ALCbackend_Capture); } +bool SndIOBackendFactory::querySupport(BackendType type) +{ return (type == BackendType::Playback || type == BackendType::Capture); } void SndIOBackendFactory::probe(DevProbe type, std::string *outnames) { @@ -492,11 +492,11 @@ void SndIOBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *SndIOBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *SndIOBackendFactory::createBackend(ALCdevice *device, BackendType type) { - if(type == ALCbackend_Playback) + if(type == BackendType::Playback) return new SndioPlayback{device}; - if(type == ALCbackend_Capture) + if(type == BackendType::Capture) return new SndioCapture{device}; return nullptr; } diff --git a/Alc/backends/sndio.h b/Alc/backends/sndio.h index bf8d833d..2280ca2c 100644 --- a/Alc/backends/sndio.h +++ b/Alc/backends/sndio.h @@ -8,11 +8,11 @@ public: bool init() override; /*void deinit() override;*/ - bool querySupport(ALCbackend_Type type) override; + bool querySupport(BackendType type) override; void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index 6463c225..5b93f8ca 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -270,8 +270,8 @@ bool SolarisBackendFactory::init() return true; } -bool SolarisBackendFactory::querySupport(ALCbackend_Type type) -{ return (type == ALCbackend_Playback); } +bool SolarisBackendFactory::querySupport(BackendType type) +{ return type == BackendType::Playback; } void SolarisBackendFactory::probe(DevProbe type, std::string *outnames) { @@ -292,9 +292,9 @@ void SolarisBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *SolarisBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *SolarisBackendFactory::createBackend(ALCdevice *device, BackendType type) { - if(type == ALCbackend_Playback) + if(type == BackendType::Playback) return new SolarisBackend{device}; return nullptr; } diff --git a/Alc/backends/solaris.h b/Alc/backends/solaris.h index f675d6d7..60c5c677 100644 --- a/Alc/backends/solaris.h +++ b/Alc/backends/solaris.h @@ -8,11 +8,11 @@ public: bool init() override; /*void deinit() override;*/ - bool querySupport(ALCbackend_Type type) override; + bool querySupport(BackendType type) override; void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 0d3d067e..ca4bdbd3 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -1773,8 +1773,8 @@ void WasapiBackendFactory::deinit() } } -bool WasapiBackendFactory::querySupport(ALCbackend_Type type) -{ return (type == ALCbackend_Playback || type == ALCbackend_Capture); } +bool WasapiBackendFactory::querySupport(BackendType type) +{ return type == BackendType::Playback || type == BackendType::Capture; } void WasapiBackendFactory::probe(DevProbe type, std::string *outnames) { @@ -1810,11 +1810,11 @@ void WasapiBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *WasapiBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *WasapiBackendFactory::createBackend(ALCdevice *device, BackendType type) { - if(type == ALCbackend_Playback) + if(type == BackendType::Playback) return new WasapiPlayback{device}; - if(type == ALCbackend_Capture) + if(type == BackendType::Capture) return new WasapiCapture{device}; return nullptr; } diff --git a/Alc/backends/wasapi.h b/Alc/backends/wasapi.h index 47bd0e0c..16395371 100644 --- a/Alc/backends/wasapi.h +++ b/Alc/backends/wasapi.h @@ -8,11 +8,11 @@ public: bool init() override; void deinit() override; - bool querySupport(ALCbackend_Type type) override; + bool querySupport(BackendType type) override; void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index 01948b20..ef0f6db7 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -364,8 +364,8 @@ void WaveBackend::stop() bool WaveBackendFactory::init() { return true; } -bool WaveBackendFactory::querySupport(ALCbackend_Type type) -{ return (type == ALCbackend_Playback); } +bool WaveBackendFactory::querySupport(BackendType type) +{ return type == BackendType::Playback; } void WaveBackendFactory::probe(DevProbe type, std::string *outnames) { @@ -380,9 +380,9 @@ void WaveBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *WaveBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *WaveBackendFactory::createBackend(ALCdevice *device, BackendType type) { - if(type == ALCbackend_Playback) + if(type == BackendType::Playback) return new WaveBackend{device}; return nullptr; } diff --git a/Alc/backends/wave.h b/Alc/backends/wave.h index 08d3f0c2..6dde7e0b 100644 --- a/Alc/backends/wave.h +++ b/Alc/backends/wave.h @@ -8,11 +8,11 @@ public: bool init() override; /*void deinit() override;*/ - bool querySupport(ALCbackend_Type type) override; + bool querySupport(BackendType type) override; void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 5051aa00..dad505f4 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -607,8 +607,8 @@ void WinMMBackendFactory::deinit() CaptureDevices.clear(); } -bool WinMMBackendFactory::querySupport(ALCbackend_Type type) -{ return (type == ALCbackend_Playback || type == ALCbackend_Capture); } +bool WinMMBackendFactory::querySupport(BackendType type) +{ return type == BackendType::Playback || type == BackendType::Capture; } void WinMMBackendFactory::probe(DevProbe type, std::string *outnames) { @@ -634,11 +634,11 @@ void WinMMBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *WinMMBackendFactory::createBackend(ALCdevice *device, ALCbackend_Type type) +BackendBase *WinMMBackendFactory::createBackend(ALCdevice *device, BackendType type) { - if(type == ALCbackend_Playback) + if(type == BackendType::Playback) return new WinMMPlayback{device}; - if(type == ALCbackend_Capture) + if(type == BackendType::Capture) return new WinMMCapture{device}; return nullptr; } diff --git a/Alc/backends/winmm.h b/Alc/backends/winmm.h index 63be6598..85f23b3a 100644 --- a/Alc/backends/winmm.h +++ b/Alc/backends/winmm.h @@ -8,11 +8,11 @@ public: bool init() override; void deinit() override; - bool querySupport(ALCbackend_Type type) override; + bool querySupport(BackendType type) override; void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, ALCbackend_Type type) override; + BackendBase *createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; -- cgit v1.2.3 From 71a4d6db6f88cbb735cd959b3dd16d83a27474cf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Dec 2018 02:16:16 -0800 Subject: Return a unique_ptr for the backend --- Alc/alc.cpp | 3 +-- Alc/backends/alsa.cpp | 6 +++--- Alc/backends/alsa.h | 2 +- Alc/backends/base.cpp | 2 +- Alc/backends/base.h | 5 +++-- Alc/backends/coreaudio.cpp | 6 +++--- Alc/backends/coreaudio.h | 2 +- Alc/backends/dsound.cpp | 6 +++--- Alc/backends/dsound.h | 2 +- Alc/backends/jack.cpp | 4 ++-- Alc/backends/jack.h | 2 +- Alc/backends/loopback.cpp | 4 ++-- Alc/backends/loopback.h | 2 +- Alc/backends/null.cpp | 4 ++-- Alc/backends/null.h | 2 +- Alc/backends/opensl.cpp | 6 +++--- Alc/backends/opensl.h | 2 +- Alc/backends/oss.cpp | 6 +++--- Alc/backends/oss.h | 2 +- Alc/backends/portaudio.cpp | 6 +++--- Alc/backends/portaudio.h | 2 +- Alc/backends/pulseaudio.cpp | 6 +++--- Alc/backends/pulseaudio.h | 2 +- Alc/backends/qsa.cpp | 6 +++--- Alc/backends/qsa.h | 2 +- Alc/backends/sdl2.cpp | 4 ++-- Alc/backends/sdl2.h | 2 +- Alc/backends/sndio.cpp | 6 +++--- Alc/backends/sndio.h | 2 +- Alc/backends/solaris.cpp | 4 ++-- Alc/backends/solaris.h | 2 +- Alc/backends/wasapi.cpp | 6 +++--- Alc/backends/wasapi.h | 2 +- Alc/backends/wave.cpp | 4 ++-- Alc/backends/wave.h | 2 +- Alc/backends/winmm.cpp | 6 +++--- Alc/backends/winmm.h | 2 +- OpenAL32/Include/alMain.h | 2 +- 38 files changed, 68 insertions(+), 68 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index c625fd20..517e98d3 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2203,7 +2203,6 @@ ALCdevice_struct::~ALCdevice_struct() { TRACE("%p\n", this); - delete Backend; Backend = nullptr; size_t count{std::accumulate(BufferList.cbegin(), BufferList.cend(), size_t{0u}, @@ -4037,7 +4036,7 @@ ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCenum err{ALC_INVALID_VALUE}; { std::lock_guard _{dev->BackendLock}; - BackendBase *backend{dev->Backend}; + BackendBase *backend{dev->Backend.get()}; if(samples >= 0 && backend->availableSamples() >= (ALCuint)samples) err = backend->captureSamples(buffer, samples); } diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index 543c2bee..7ff26a33 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -1292,12 +1292,12 @@ void AlsaBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *AlsaBackendFactory::createBackend(ALCdevice *device, BackendType type) +BackendPtr AlsaBackendFactory::createBackend(ALCdevice *device, BackendType type) { if(type == BackendType::Playback) - return new AlsaPlayback{device}; + return BackendPtr{new AlsaPlayback{device}}; if(type == BackendType::Capture) - return new AlsaCapture{device}; + return BackendPtr{new AlsaCapture{device}}; return nullptr; } diff --git a/Alc/backends/alsa.h b/Alc/backends/alsa.h index 15a646f9..5730ba9a 100644 --- a/Alc/backends/alsa.h +++ b/Alc/backends/alsa.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, BackendType type) override; + BackendPtr createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/base.cpp b/Alc/backends/base.cpp index 1fef0439..0afc4ee1 100644 --- a/Alc/backends/base.cpp +++ b/Alc/backends/base.cpp @@ -19,7 +19,7 @@ void ALCdevice_Unlock(ALCdevice *device) ClockLatency GetClockLatency(ALCdevice *device) { - BackendBase *backend{device->Backend}; + BackendBase *backend{device->Backend.get()}; ClockLatency ret{backend->getClockLatency()}; ret.Latency += device->FixedLatency; return ret; diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 0fc7de38..0b9803a2 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -1,6 +1,7 @@ #ifndef ALC_BACKENDS_BASE_H #define ALC_BACKENDS_BASE_H +#include #include #include #include @@ -53,7 +54,7 @@ struct BackendBase { BackendBase(ALCdevice *device) noexcept; virtual ~BackendBase(); }; - +using BackendPtr = std::unique_ptr; enum class BackendType { Playback, @@ -70,7 +71,7 @@ struct BackendFactory { virtual void probe(DevProbe type, std::string *outnames) = 0; - virtual BackendBase *createBackend(ALCdevice *device, BackendType type) = 0; + virtual BackendPtr createBackend(ALCdevice *device, BackendType type) = 0; }; #endif /* ALC_BACKENDS_BASE_H */ diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index f4010631..2caa0852 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -703,11 +703,11 @@ void CoreAudioBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *CoreAudioBackendFactory::createBackend(ALCdevice *device, BackendType type) +BackendPtr CoreAudioBackendFactory::createBackend(ALCdevice *device, BackendType type) { if(type == BackendType::Playback) - return new CoreAudioPlayback{device}; + return BackendPtr{new CoreAudioPlayback{device}}; if(type == BackendType::Capture) - return new CoreAudioCapture{device}; + return BackendPtr{new CoreAudioCapture{device}}; return nullptr; } diff --git a/Alc/backends/coreaudio.h b/Alc/backends/coreaudio.h index d0ac9558..fd6dd4fc 100644 --- a/Alc/backends/coreaudio.h +++ b/Alc/backends/coreaudio.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, BackendType type) override; + BackendPtr createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index bdb9cf28..aa0f80df 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -949,11 +949,11 @@ void DSoundBackendFactory::probe(DevProbe type, std::string *outnames) CoUninitialize(); } -BackendBase *DSoundBackendFactory::createBackend(ALCdevice *device, BackendType type) +BackendPtr DSoundBackendFactory::createBackend(ALCdevice *device, BackendType type) { if(type == BackendType::Playback) - return new DSoundPlayback{device}; + return BackendPtr{new DSoundPlayback{device}}; if(type == BackendType::Capture) - return new DSoundCapture{device}; + return BackendPtr{new DSoundCapture{device}}; return nullptr; } diff --git a/Alc/backends/dsound.h b/Alc/backends/dsound.h index 819c4231..89484b4d 100644 --- a/Alc/backends/dsound.h +++ b/Alc/backends/dsound.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, BackendType type) override; + BackendPtr createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index eb96392f..e917d3e6 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -558,10 +558,10 @@ void JackBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *JackBackendFactory::createBackend(ALCdevice *device, BackendType type) +BackendPtr JackBackendFactory::createBackend(ALCdevice *device, BackendType type) { if(type == BackendType::Playback) - return new JackPlayback{device}; + return BackendPtr{new JackPlayback{device}}; return nullptr; } diff --git a/Alc/backends/jack.h b/Alc/backends/jack.h index 421fafde..0948213f 100644 --- a/Alc/backends/jack.h +++ b/Alc/backends/jack.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, BackendType type) override; + BackendPtr createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/loopback.cpp b/Alc/backends/loopback.cpp index 6bce90ff..6404d413 100644 --- a/Alc/backends/loopback.cpp +++ b/Alc/backends/loopback.cpp @@ -70,10 +70,10 @@ bool LoopbackBackendFactory::querySupport(BackendType type) void LoopbackBackendFactory::probe(DevProbe, std::string*) { } -BackendBase *LoopbackBackendFactory::createBackend(ALCdevice *device, BackendType type) +BackendPtr LoopbackBackendFactory::createBackend(ALCdevice *device, BackendType type) { if(type == BackendType::Loopback) - new LoopbackBackend{device}; + return BackendPtr{new LoopbackBackend{device}}; return nullptr; } diff --git a/Alc/backends/loopback.h b/Alc/backends/loopback.h index cf5eb02a..e40ce963 100644 --- a/Alc/backends/loopback.h +++ b/Alc/backends/loopback.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, BackendType type) override; + BackendPtr createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 480b5554..3aee7204 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -169,10 +169,10 @@ void NullBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *NullBackendFactory::createBackend(ALCdevice *device, BackendType type) +BackendPtr NullBackendFactory::createBackend(ALCdevice *device, BackendType type) { if(type == BackendType::Playback) - return new NullBackend{device}; + return BackendPtr{new NullBackend{device}}; return nullptr; } diff --git a/Alc/backends/null.h b/Alc/backends/null.h index 87796b7a..1488e1d0 100644 --- a/Alc/backends/null.h +++ b/Alc/backends/null.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, BackendType type) override; + BackendPtr createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index c6a8cf82..adcc943c 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -934,12 +934,12 @@ void OSLBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *OSLBackendFactory::createBackend(ALCdevice *device, BackendType type) +BackendPtr OSLBackendFactory::createBackend(ALCdevice *device, BackendType type) { if(type == BackendType::Playback) - return new OpenSLPlayback{device}; + return BackendPtr{new OpenSLPlayback{device}}; if(type == BackendType::Capture) - return new OpenSLCapture{device}; + return BackendPtr{new OpenSLCapture{device}}; return nullptr; } diff --git a/Alc/backends/opensl.h b/Alc/backends/opensl.h index d553b80d..cf694f01 100644 --- a/Alc/backends/opensl.h +++ b/Alc/backends/opensl.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, BackendType type) override; + BackendPtr createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 90da18c7..776d665b 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -751,11 +751,11 @@ void OSSBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *OSSBackendFactory::createBackend(ALCdevice *device, BackendType type) +BackendPtr OSSBackendFactory::createBackend(ALCdevice *device, BackendType type) { if(type == BackendType::Playback) - return new OSSPlayback{device}; + return BackendPtr{new OSSPlayback{device}}; if(type == BackendType::Capture) - return new OSScapture{device}; + return BackendPtr{new OSScapture{device}}; return nullptr; } diff --git a/Alc/backends/oss.h b/Alc/backends/oss.h index f59bfe18..e07cd573 100644 --- a/Alc/backends/oss.h +++ b/Alc/backends/oss.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, BackendType type) override; + BackendPtr createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index ae01da70..258f981e 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -467,12 +467,12 @@ void PortBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *PortBackendFactory::createBackend(ALCdevice *device, BackendType type) +BackendPtr PortBackendFactory::createBackend(ALCdevice *device, BackendType type) { if(type == BackendType::Playback) - return new PortPlayback{device}; + return BackendPtr{new PortPlayback{device}}; if(type == BackendType::Capture) - return new PortCapture{device}; + return BackendPtr{new PortCapture{device}}; return nullptr; } diff --git a/Alc/backends/portaudio.h b/Alc/backends/portaudio.h index 84ef11d9..1fd45ff3 100644 --- a/Alc/backends/portaudio.h +++ b/Alc/backends/portaudio.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, BackendType type) override; + BackendPtr createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 8a089b88..e714ac3f 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -1664,12 +1664,12 @@ void PulseBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *PulseBackendFactory::createBackend(ALCdevice *device, BackendType type) +BackendPtr PulseBackendFactory::createBackend(ALCdevice *device, BackendType type) { if(type == BackendType::Playback) - return new PulsePlayback{device}; + return BackendPtr{new PulsePlayback{device}}; if(type == BackendType::Capture) - return new PulseCapture{device}; + return BackendPtr{new PulseCapture{device}}; return nullptr; } diff --git a/Alc/backends/pulseaudio.h b/Alc/backends/pulseaudio.h index b7e71d82..336276e6 100644 --- a/Alc/backends/pulseaudio.h +++ b/Alc/backends/pulseaudio.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, BackendType type) override; + BackendPtr createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index 0c695d92..abf046b1 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -952,12 +952,12 @@ void QSABackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *QSABackendFactory::createBackend(ALCdevice *device, BackendType type) +BackendPtr QSABackendFactory::createBackend(ALCdevice *device, BackendType type) { if(type == BackendType::Playback) - return new PlaybackWrapper{device}; + return BackendPtr{new PlaybackWrapper{device}}; if(type == BackendType::Capture) - return new CaptureWrapper{device}; + return BackendPtr{new CaptureWrapper{device}}; return nullptr; } diff --git a/Alc/backends/qsa.h b/Alc/backends/qsa.h index c136f652..fdd81b4f 100644 --- a/Alc/backends/qsa.h +++ b/Alc/backends/qsa.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, BackendType type) override; + BackendPtr createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/sdl2.cpp b/Alc/backends/sdl2.cpp index 72c2dbcd..7665146a 100644 --- a/Alc/backends/sdl2.cpp +++ b/Alc/backends/sdl2.cpp @@ -223,9 +223,9 @@ void SDL2BackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *SDL2BackendFactory::createBackend(ALCdevice *device, BackendType type) +BackendPtr SDL2BackendFactory::createBackend(ALCdevice *device, BackendType type) { if(type == BackendType::Playback) - return new Sdl2Backend{device}; + return BackendPtr{new Sdl2Backend{device}}; return nullptr; } diff --git a/Alc/backends/sdl2.h b/Alc/backends/sdl2.h index 34d30b16..aefe1ef5 100644 --- a/Alc/backends/sdl2.h +++ b/Alc/backends/sdl2.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, BackendType type) override; + BackendPtr createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index a592632c..dd2cb8a8 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -492,11 +492,11 @@ void SndIOBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *SndIOBackendFactory::createBackend(ALCdevice *device, BackendType type) +BackendPtr SndIOBackendFactory::createBackend(ALCdevice *device, BackendType type) { if(type == BackendType::Playback) - return new SndioPlayback{device}; + return BackendPtr{new SndioPlayback{device}}; if(type == BackendType::Capture) - return new SndioCapture{device}; + return BackendPtr{new SndioCapture{device}}; return nullptr; } diff --git a/Alc/backends/sndio.h b/Alc/backends/sndio.h index 2280ca2c..5cd4ff8a 100644 --- a/Alc/backends/sndio.h +++ b/Alc/backends/sndio.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, BackendType type) override; + BackendPtr createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index 5b93f8ca..dd940887 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -292,9 +292,9 @@ void SolarisBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *SolarisBackendFactory::createBackend(ALCdevice *device, BackendType type) +BackendPtr SolarisBackendFactory::createBackend(ALCdevice *device, BackendType type) { if(type == BackendType::Playback) - return new SolarisBackend{device}; + return BackendPtr{new SolarisBackend{device}}; return nullptr; } diff --git a/Alc/backends/solaris.h b/Alc/backends/solaris.h index 60c5c677..99623be4 100644 --- a/Alc/backends/solaris.h +++ b/Alc/backends/solaris.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, BackendType type) override; + BackendPtr createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index ca4bdbd3..51a2f58d 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -1810,12 +1810,12 @@ void WasapiBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *WasapiBackendFactory::createBackend(ALCdevice *device, BackendType type) +BackendPtr WasapiBackendFactory::createBackend(ALCdevice *device, BackendType type) { if(type == BackendType::Playback) - return new WasapiPlayback{device}; + return BackendPtr{new WasapiPlayback{device}}; if(type == BackendType::Capture) - return new WasapiCapture{device}; + return BackendPtr{new WasapiCapture{device}}; return nullptr; } diff --git a/Alc/backends/wasapi.h b/Alc/backends/wasapi.h index 16395371..ab9f8162e 100644 --- a/Alc/backends/wasapi.h +++ b/Alc/backends/wasapi.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, BackendType type) override; + BackendPtr createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index ef0f6db7..435de766 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -380,10 +380,10 @@ void WaveBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *WaveBackendFactory::createBackend(ALCdevice *device, BackendType type) +BackendPtr WaveBackendFactory::createBackend(ALCdevice *device, BackendType type) { if(type == BackendType::Playback) - return new WaveBackend{device}; + return BackendPtr{new WaveBackend{device}}; return nullptr; } diff --git a/Alc/backends/wave.h b/Alc/backends/wave.h index 6dde7e0b..f3617b6d 100644 --- a/Alc/backends/wave.h +++ b/Alc/backends/wave.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, BackendType type) override; + BackendPtr createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index dad505f4..3c9aa776 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -634,12 +634,12 @@ void WinMMBackendFactory::probe(DevProbe type, std::string *outnames) } } -BackendBase *WinMMBackendFactory::createBackend(ALCdevice *device, BackendType type) +BackendPtr WinMMBackendFactory::createBackend(ALCdevice *device, BackendType type) { if(type == BackendType::Playback) - return new WinMMPlayback{device}; + return BackendPtr{new WinMMPlayback{device}}; if(type == BackendType::Capture) - return new WinMMCapture{device}; + return BackendPtr{new WinMMCapture{device}}; return nullptr; } diff --git a/Alc/backends/winmm.h b/Alc/backends/winmm.h index 85f23b3a..4d9fe32d 100644 --- a/Alc/backends/winmm.h +++ b/Alc/backends/winmm.h @@ -12,7 +12,7 @@ public: void probe(DevProbe type, std::string *outnames) override; - BackendBase *createBackend(ALCdevice *device, BackendType type) override; + BackendPtr createBackend(ALCdevice *device, BackendType type) override; static BackendFactory &getFactory(); }; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 391ef8df..e23eb1fb 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -786,7 +786,7 @@ struct ALCdevice_struct { std::atomic ContextList{nullptr}; std::mutex BackendLock; - BackendBase *Backend{nullptr}; + std::unique_ptr Backend; std::atomic next{nullptr}; -- cgit v1.2.3 From 63fc74beaac497d35bd74cb202e3f4ffb2dbe7fb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Dec 2018 02:21:53 -0800 Subject: Don't bother with an explicit Loopback backend type --- Alc/alc.cpp | 2 +- Alc/backends/base.h | 3 +-- Alc/backends/loopback.cpp | 12 ++++-------- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 517e98d3..167ee3e6 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -4094,7 +4094,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->NumMonoSources = device->SourcesMax - device->NumStereoSources; device->Backend = LoopbackBackendFactory::getFactory().createBackend(device.get(), - BackendType::Loopback); + BackendType::Playback); if(!device->Backend) { device = nullptr; diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 0b9803a2..0b3b24fb 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -58,8 +58,7 @@ using BackendPtr = std::unique_ptr; enum class BackendType { Playback, - Capture, - Loopback + Capture }; diff --git a/Alc/backends/loopback.cpp b/Alc/backends/loopback.cpp index 6404d413..5d133d8e 100644 --- a/Alc/backends/loopback.cpp +++ b/Alc/backends/loopback.cpp @@ -64,18 +64,14 @@ void LoopbackBackend::stop() bool LoopbackBackendFactory::init() { return true; } -bool LoopbackBackendFactory::querySupport(BackendType type) -{ return (type == BackendType::Loopback); } +bool LoopbackBackendFactory::querySupport(BackendType UNUSED(type)) +{ return true; } void LoopbackBackendFactory::probe(DevProbe, std::string*) { } -BackendPtr LoopbackBackendFactory::createBackend(ALCdevice *device, BackendType type) -{ - if(type == BackendType::Loopback) - return BackendPtr{new LoopbackBackend{device}}; - return nullptr; -} +BackendPtr LoopbackBackendFactory::createBackend(ALCdevice *device, BackendType UNUSED(type)) +{ return BackendPtr{new LoopbackBackend{device}}; } BackendFactory &LoopbackBackendFactory::getFactory() { -- cgit v1.2.3 From 9b0b722d7209d3cb8a31ba0823ef252906e2eb5d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Dec 2018 03:11:06 -0800 Subject: Add missing includes for mem_fn --- Alc/backends/alsa.cpp | 1 + Alc/backends/dsound.cpp | 1 + Alc/backends/jack.cpp | 1 + Alc/backends/null.cpp | 1 + Alc/backends/opensl.cpp | 1 + Alc/backends/oss.cpp | 1 + Alc/backends/sndio.cpp | 1 + Alc/backends/solaris.cpp | 1 + Alc/backends/wasapi.cpp | 1 + Alc/backends/wave.cpp | 1 + Alc/backends/winmm.cpp | 1 + 11 files changed, 11 insertions(+) diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index 7ff26a33..43336026 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "alMain.h" #include "alu.h" diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index aa0f80df..b7424473 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include "alMain.h" #include "alu.h" diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index e917d3e6..5ac0ff4d 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -27,6 +27,7 @@ #include #include +#include #include "alMain.h" #include "alu.h" diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 3aee7204..7f02ad62 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -29,6 +29,7 @@ #include #include +#include #include "alMain.h" #include "alu.h" diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index adcc943c..66bc6e8d 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -27,6 +27,7 @@ #include #include +#include #include "alMain.h" #include "alu.h" diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 776d665b..c18a1d86 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include "alMain.h" #include "alu.h" diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index dd2cb8a8..5d74dd5a 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -27,6 +27,7 @@ #include #include +#include #include "alMain.h" #include "alu.h" diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index dd940887..043691ce 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -36,6 +36,7 @@ #include #include +#include #include "alMain.h" #include "alu.h" diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 51a2f58d..d6b50985 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include "alMain.h" #include "alu.h" diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index 435de766..49d4a735 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "alMain.h" #include "alu.h" diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 3c9aa776..bc599006 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include "alMain.h" #include "alu.h" -- cgit v1.2.3 From 8a84e7b662959015ee1e7d066351e5b7cc4fe283 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Dec 2018 12:26:45 -0800 Subject: Use member functions for the sample and channel converters --- Alc/backends/coreaudio.cpp | 7 ++-- Alc/backends/wasapi.cpp | 10 ++--- Alc/converter.cpp | 92 +++++++++++++++++++++------------------------- Alc/converter.h | 12 +++--- 4 files changed, 55 insertions(+), 66 deletions(-) diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index 2caa0852..c5da9f24 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -656,14 +656,13 @@ ALCenum CoreAudioCapture::captureSamples(void *buffer, ALCuint samples) auto rec_vec = mRing->getReadVector(); const void *src0{rec_vec.first.buf}; auto src0len = static_cast(rec_vec.first.len); - auto got = static_cast(SampleConverterInput(mConverter.get(), &src0, &src0len, - buffer, samples)); + auto got = static_cast(mConverter->convert(&src0, &src0len, buffer, samples)); size_t total_read{rec_vec.first.len - src0len}; if(got < samples && !src0len && rec_vec.second.len > 0) { const void *src1{rec_vec.second.buf}; auto src1len = static_cast(rec_vec.second.len); - got += static_cast(SampleConverterInput(mConverter.get(), &src1, &src1len, + got += static_cast(mConverter->convert(&src1, &src1len, static_cast(buffer)+got, samples-got)); total_read += rec_vec.second.len - src1len; } @@ -675,7 +674,7 @@ ALCenum CoreAudioCapture::captureSamples(void *buffer, ALCuint samples) ALCuint CoreAudioCapture::availableSamples() { if(!mConverter) return mRing->readSpace(); - return SampleConverterAvailableOut(mConverter.get(), mRing->readSpace()); + return mConverter->availableOut(mRing->readSpace()); } } // namespace diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index d6b50985..cb0b665b 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -1223,7 +1223,7 @@ FORCE_ALIGN int WasapiCapture::recordProc() if(mChannelConv) { samples.resize(numsamples*2); - ChannelConverterInput(mChannelConv.get(), rdata, samples.data(), numsamples); + mChannelConv->convert(rdata, samples.data(), numsamples); rdata = reinterpret_cast(samples.data()); } @@ -1235,16 +1235,16 @@ FORCE_ALIGN int WasapiCapture::recordProc() const ALvoid *srcdata{rdata}; auto srcframes = static_cast(numsamples); - dstframes = SampleConverterInput(mSampleConv.get(), &srcdata, &srcframes, - data.first.buf, (ALsizei)minz(data.first.len, INT_MAX)); + dstframes = mSampleConv->convert(&srcdata, &srcframes, data.first.buf, + static_cast(minz(data.first.len, INT_MAX))); if(srcframes > 0 && dstframes == data.first.len && data.second.len > 0) { /* If some source samples remain, all of the first dest * block was filled, and there's space in the second * dest block, do another run for the second block. */ - dstframes += SampleConverterInput(mSampleConv.get(), &srcdata, &srcframes, - data.second.buf, (ALsizei)minz(data.second.len, INT_MAX)); + dstframes += mSampleConv->convert(&srcdata, &srcframes, data.second.buf, + static_cast(minz(data.second.len, INT_MAX))); } } else diff --git a/Alc/converter.cpp b/Alc/converter.cpp index 52472bde..0ee97fa7 100644 --- a/Alc/converter.cpp +++ b/Alc/converter.cpp @@ -171,9 +171,9 @@ SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, return converter; } -ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframes) +ALsizei SampleConverter::availableOut(ALsizei srcframes) const { - ALint prepcount{converter->mSrcPrepCount}; + ALint prepcount{mSrcPrepCount}; if(prepcount < 0) { /* Negative prepcount means we need to skip that many input samples. */ @@ -196,23 +196,21 @@ ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframe return 0; } - ALsizei increment{converter->mIncrement}; - ALsizei DataPosFrac{converter->mFracOffset}; auto DataSize64 = static_cast(prepcount); DataSize64 += srcframes; DataSize64 -= MAX_RESAMPLE_PADDING*2; DataSize64 <<= FRACTIONBITS; - DataSize64 -= DataPosFrac; + DataSize64 -= mFracOffset; /* If we have a full prep, we can generate at least one sample. */ - return (ALsizei)clampu64((DataSize64 + increment-1)/increment, 1, BUFFERSIZE); + return (ALsizei)clampu64((DataSize64 + mIncrement-1)/mIncrement, 1, BUFFERSIZE); } -ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes) +ALsizei SampleConverter::convert(const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes) { - const ALsizei SrcFrameSize{converter->mNumChannels * converter->mSrcTypeSize}; - const ALsizei DstFrameSize{converter->mNumChannels * converter->mDstTypeSize}; - const ALsizei increment{converter->mIncrement}; + const ALsizei SrcFrameSize{mNumChannels * mSrcTypeSize}; + const ALsizei DstFrameSize{mNumChannels * mDstTypeSize}; + const ALsizei increment{mIncrement}; auto SamplesIn = static_cast(*src); ALsizei NumSrcSamples{*srcframes}; @@ -220,19 +218,19 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs ALsizei pos{0}; while(pos < dstframes && NumSrcSamples > 0) { - ALint prepcount{converter->mSrcPrepCount}; + ALint prepcount{mSrcPrepCount}; if(prepcount < 0) { /* Negative prepcount means we need to skip that many input samples. */ if(-prepcount >= NumSrcSamples) { - converter->mSrcPrepCount = prepcount + NumSrcSamples; + mSrcPrepCount = prepcount + NumSrcSamples; NumSrcSamples = 0; break; } SamplesIn += SrcFrameSize*-prepcount; NumSrcSamples += prepcount; - converter->mSrcPrepCount = 0; + mSrcPrepCount = 0; continue; } ALint toread{mini(NumSrcSamples, BUFFERSIZE - MAX_RESAMPLE_PADDING*2)}; @@ -243,20 +241,18 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs /* Not enough input samples to generate an output sample. Store * what we're given for later. */ - for(ALsizei chan{0};chan < converter->mNumChannels;chan++) - LoadSamples(&converter->Chan[chan].mPrevSamples[prepcount], - SamplesIn + converter->mSrcTypeSize*chan, - converter->mNumChannels, converter->mSrcType, toread - ); + for(ALsizei chan{0};chan < mNumChannels;chan++) + LoadSamples(&Chan[chan].mPrevSamples[prepcount], SamplesIn + mSrcTypeSize*chan, + mNumChannels, mSrcType, toread); - converter->mSrcPrepCount = prepcount + toread; + mSrcPrepCount = prepcount + toread; NumSrcSamples = 0; break; } - ALfloat *RESTRICT SrcData{converter->mSrcSamples}; - ALfloat *RESTRICT DstData{converter->mDstSamples}; - ALsizei DataPosFrac{converter->mFracOffset}; + ALfloat *RESTRICT SrcData{mSrcSamples}; + ALfloat *RESTRICT DstData{mDstSamples}; + ALsizei DataPosFrac{mFracOffset}; auto DataSize64 = static_cast(prepcount); DataSize64 += toread; DataSize64 -= MAX_RESAMPLE_PADDING*2; @@ -268,51 +264,46 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs clampu64((DataSize64 + increment-1)/increment, 1, BUFFERSIZE)); DstSize = mini(DstSize, dstframes-pos); - for(ALsizei chan{0};chan < converter->mNumChannels;chan++) + for(ALsizei chan{0};chan < mNumChannels;chan++) { - const ALbyte *SrcSamples = SamplesIn + converter->mSrcTypeSize*chan; - ALbyte *DstSamples = (ALbyte*)dst + converter->mDstTypeSize*chan; + const ALbyte *SrcSamples = SamplesIn + mSrcTypeSize*chan; + ALbyte *DstSamples = (ALbyte*)dst + mDstTypeSize*chan; /* Load the previous samples into the source data first, then the * new samples from the input buffer. */ - std::copy_n(converter->Chan[chan].mPrevSamples, prepcount, SrcData); - LoadSamples(SrcData + prepcount, SrcSamples, - converter->mNumChannels, converter->mSrcType, toread - ); + std::copy_n(Chan[chan].mPrevSamples, prepcount, SrcData); + LoadSamples(SrcData + prepcount, SrcSamples, mNumChannels, mSrcType, toread); /* Store as many prep samples for next time as possible, given the * number of output samples being generated. */ ALsizei SrcDataEnd{(DstSize*increment + DataPosFrac)>>FRACTIONBITS}; if(SrcDataEnd >= prepcount+toread) - std::fill(std::begin(converter->Chan[chan].mPrevSamples), - std::end(converter->Chan[chan].mPrevSamples), 0.0f); + std::fill(std::begin(Chan[chan].mPrevSamples), + std::end(Chan[chan].mPrevSamples), 0.0f); else { size_t len = mini(MAX_RESAMPLE_PADDING*2, prepcount+toread-SrcDataEnd); - std::copy_n(SrcData+SrcDataEnd, len, converter->Chan[chan].mPrevSamples); - std::fill(std::begin(converter->Chan[chan].mPrevSamples)+len, - std::end(converter->Chan[chan].mPrevSamples), 0.0f); + std::copy_n(SrcData+SrcDataEnd, len, Chan[chan].mPrevSamples); + std::fill(std::begin(Chan[chan].mPrevSamples)+len, + std::end(Chan[chan].mPrevSamples), 0.0f); } /* Now resample, and store the result in the output buffer. */ - const ALfloat *ResampledData{converter->mResample(&converter->mState, - SrcData+MAX_RESAMPLE_PADDING, DataPosFrac, increment, - DstData, DstSize - )}; + const ALfloat *ResampledData{mResample(&mState, SrcData+MAX_RESAMPLE_PADDING, + DataPosFrac, increment, DstData, DstSize)}; - StoreSamples(DstSamples, ResampledData, converter->mNumChannels, - converter->mDstType, DstSize); + StoreSamples(DstSamples, ResampledData, mNumChannels, mDstType, DstSize); } /* Update the number of prep samples still available, as well as the * fractional offset. */ DataPosFrac += increment*DstSize; - converter->mSrcPrepCount = mini(prepcount + toread - (DataPosFrac>>FRACTIONBITS), - MAX_RESAMPLE_PADDING*2); - converter->mFracOffset = DataPosFrac & FRACTIONMASK; + mSrcPrepCount = mini(prepcount + toread - (DataPosFrac>>FRACTIONBITS), + MAX_RESAMPLE_PADDING*2); + mFracOffset = DataPosFrac & FRACTIONMASK; /* Update the src and dst pointers in case there's still more to do. */ SamplesIn += SrcFrameSize*(DataPosFrac>>FRACTIONBITS); @@ -338,18 +329,17 @@ ChannelConverterPtr CreateChannelConverter(DevFmtType srcType, DevFmtChannels sr return ChannelConverterPtr{new ChannelConverter{srcType, srcChans, dstChans}}; } -void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALfloat *dst, ALsizei frames) +void ChannelConverter::convert(const ALvoid *src, ALfloat *dst, ALsizei frames) const { - if(converter->mSrcChans == converter->mDstChans) + if(mSrcChans == mDstChans) { - LoadSamples(dst, src, 1, converter->mSrcType, - frames*ChannelsFromDevFmt(converter->mSrcChans, 0)); + LoadSamples(dst, src, 1, mSrcType, frames*ChannelsFromDevFmt(mSrcChans, 0)); return; } - if(converter->mSrcChans == DevFmtStereo && converter->mDstChans == DevFmtMono) + if(mSrcChans == DevFmtStereo && mDstChans == DevFmtMono) { - switch(converter->mSrcType) + switch(mSrcType) { #define HANDLE_FMT(T) case T: Stereo2Mono(dst, src, frames); break HANDLE_FMT(DevFmtByte); @@ -362,9 +352,9 @@ void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALflo #undef HANDLE_FMT } } - else /*if(converter->mSrcChans == DevFmtMono && converter->mDstChans == DevFmtStereo)*/ + else /*if(mSrcChans == DevFmtMono && mDstChans == DevFmtStereo)*/ { - switch(converter->mSrcType) + switch(mSrcType) { #define HANDLE_FMT(T) case T: Mono2Stereo(dst, src, frames); break HANDLE_FMT(DevFmtByte); diff --git a/Alc/converter.h b/Alc/converter.h index 6c76be07..504d60a7 100644 --- a/Alc/converter.h +++ b/Alc/converter.h @@ -28,6 +28,9 @@ struct SampleConverter { alignas(16) ALfloat mPrevSamples[MAX_RESAMPLE_PADDING*2]; } Chan[]; + ALsizei convert(const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes); + ALsizei availableOut(ALsizei srcframes) const; + DEF_PLACE_NEWDEL() }; using SampleConverterPtr = std::unique_ptr; @@ -35,9 +38,6 @@ using SampleConverterPtr = std::unique_ptr; SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, ALsizei numchans, ALsizei srcRate, ALsizei dstRate, Resampler resampler); -ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes); -ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframes); - struct ChannelConverter { DevFmtType mSrcType; @@ -47,6 +47,9 @@ struct ChannelConverter { ChannelConverter(DevFmtType srctype, DevFmtChannels srcchans, DevFmtChannels dstchans) : mSrcType(srctype), mSrcChans(srcchans), mDstChans(dstchans) { } + + void convert(const ALvoid *src, ALfloat *dst, ALsizei frames) const; + DEF_NEWDEL(ChannelConverter) }; using ChannelConverterPtr = std::unique_ptr; @@ -54,7 +57,4 @@ using ChannelConverterPtr = std::unique_ptr; ChannelConverterPtr CreateChannelConverter(DevFmtType srcType, DevFmtChannels srcChans, DevFmtChannels dstChans); -void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALfloat *dst, - ALsizei frames); - #endif /* CONVERTER_H */ -- cgit v1.2.3 From bdf7c16cfbdeadf3cfd2d4ae969a2b96ad21dbc3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Dec 2018 13:21:47 -0800 Subject: Clean up a member name --- Alc/converter.cpp | 16 ++++++++-------- Alc/converter.h | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Alc/converter.cpp b/Alc/converter.cpp index 0ee97fa7..22a01552 100644 --- a/Alc/converter.cpp +++ b/Alc/converter.cpp @@ -141,7 +141,7 @@ SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, if(numchans <= 0 || srcRate <= 0 || dstRate <= 0) return nullptr; - const size_t alloc_size{FAM_SIZE(SampleConverter, Chan, numchans)}; + const size_t alloc_size{FAM_SIZE(SampleConverter, mChan, numchans)}; SampleConverterPtr converter{new (al_calloc(16, alloc_size)) SampleConverter{}}; converter->mSrcType = srcType; converter->mDstType = dstType; @@ -242,7 +242,7 @@ ALsizei SampleConverter::convert(const ALvoid **src, ALsizei *srcframes, ALvoid * what we're given for later. */ for(ALsizei chan{0};chan < mNumChannels;chan++) - LoadSamples(&Chan[chan].mPrevSamples[prepcount], SamplesIn + mSrcTypeSize*chan, + LoadSamples(&mChan[chan].PrevSamples[prepcount], SamplesIn + mSrcTypeSize*chan, mNumChannels, mSrcType, toread); mSrcPrepCount = prepcount + toread; @@ -272,7 +272,7 @@ ALsizei SampleConverter::convert(const ALvoid **src, ALsizei *srcframes, ALvoid /* Load the previous samples into the source data first, then the * new samples from the input buffer. */ - std::copy_n(Chan[chan].mPrevSamples, prepcount, SrcData); + std::copy_n(mChan[chan].PrevSamples, prepcount, SrcData); LoadSamples(SrcData + prepcount, SrcSamples, mNumChannels, mSrcType, toread); /* Store as many prep samples for next time as possible, given the @@ -280,14 +280,14 @@ ALsizei SampleConverter::convert(const ALvoid **src, ALsizei *srcframes, ALvoid */ ALsizei SrcDataEnd{(DstSize*increment + DataPosFrac)>>FRACTIONBITS}; if(SrcDataEnd >= prepcount+toread) - std::fill(std::begin(Chan[chan].mPrevSamples), - std::end(Chan[chan].mPrevSamples), 0.0f); + std::fill(std::begin(mChan[chan].PrevSamples), + std::end(mChan[chan].PrevSamples), 0.0f); else { size_t len = mini(MAX_RESAMPLE_PADDING*2, prepcount+toread-SrcDataEnd); - std::copy_n(SrcData+SrcDataEnd, len, Chan[chan].mPrevSamples); - std::fill(std::begin(Chan[chan].mPrevSamples)+len, - std::end(Chan[chan].mPrevSamples), 0.0f); + std::copy_n(SrcData+SrcDataEnd, len, mChan[chan].PrevSamples); + std::fill(std::begin(mChan[chan].PrevSamples)+len, + std::end(mChan[chan].PrevSamples), 0.0f); } /* Now resample, and store the result in the output buffer. */ diff --git a/Alc/converter.h b/Alc/converter.h index 504d60a7..bfd0dd1a 100644 --- a/Alc/converter.h +++ b/Alc/converter.h @@ -25,8 +25,8 @@ struct SampleConverter { alignas(16) ALfloat mDstSamples[BUFFERSIZE]{}; struct { - alignas(16) ALfloat mPrevSamples[MAX_RESAMPLE_PADDING*2]; - } Chan[]; + alignas(16) ALfloat PrevSamples[MAX_RESAMPLE_PADDING*2]; + } mChan[]; ALsizei convert(const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes); ALsizei availableOut(ALsizei srcframes) const; -- cgit v1.2.3 From 24e763f2a12fda79ff4ff87b46d8cfad15dc9b9e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Dec 2018 14:00:34 -0800 Subject: Get rid of ALCdevice_Lock/Unlock --- Alc/backends/base.cpp | 6 ------ Alc/backends/base.h | 3 --- OpenAL32/alSource.cpp | 41 +++++++++++++++++++++-------------------- 3 files changed, 21 insertions(+), 29 deletions(-) diff --git a/Alc/backends/base.cpp b/Alc/backends/base.cpp index 0afc4ee1..5c25b366 100644 --- a/Alc/backends/base.cpp +++ b/Alc/backends/base.cpp @@ -11,12 +11,6 @@ #include "backends/base.h" -void ALCdevice_Lock(ALCdevice *device) -{ device->Backend->lock(); } - -void ALCdevice_Unlock(ALCdevice *device) -{ device->Backend->unlock(); } - ClockLatency GetClockLatency(ALCdevice *device) { BackendBase *backend{device->Backend.get()}; diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 0b3b24fb..81424bef 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -27,9 +27,6 @@ inline std::chrono::nanoseconds GetDeviceClockTime(ALCdevice *device) return device->ClockBase + ns; } -void ALCdevice_Lock(ALCdevice *device); -void ALCdevice_Unlock(ALCdevice *device); - ClockLatency GetClockLatency(ALCdevice *device); struct BackendBase { diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 98c79213..069d600b 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -526,14 +526,14 @@ void FreeSource(ALCcontext *context, ALsource *source) ALsizei slidx = id & 0x3f; ALCdevice *device{context->Device}; - ALCdevice_Lock(device); + device->Backend->lock(); ALvoice *voice{GetSourceVoice(source, context)}; if(voice) { voice->SourceID.store(0u, std::memory_order_relaxed); voice->Playing.store(false, std::memory_order_release); } - ALCdevice_Unlock(device); + device->Backend->unlock(); source->~ALsource(); @@ -1094,22 +1094,22 @@ ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, co if(IsPlayingOrPaused(Source)) { - ALvoice *voice; + ALCdevice *device{Context->Device}; - ALCdevice_Lock(Context->Device); + device->Backend->lock(); /* Double-check that the source is still playing while we have * the lock. */ - voice = GetSourceVoice(Source, Context); + ALvoice *voice{GetSourceVoice(Source, Context)}; if(voice) { if(ApplyOffset(Source, voice) == AL_FALSE) { - ALCdevice_Unlock(Context->Device); + device->Backend->unlock(); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid offset"); } } - ALCdevice_Unlock(Context->Device); + device->Backend->unlock(); } return AL_TRUE; @@ -1321,18 +1321,19 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co if(IsPlayingOrPaused(Source)) { - ALCdevice_Lock(Context->Device); + ALCdevice *device{Context->Device}; + device->Backend->lock(); ALvoice *voice{GetSourceVoice(Source, Context)}; if(voice) { if(ApplyOffset(Source, voice) == AL_FALSE) { - ALCdevice_Unlock(Context->Device); + device->Backend->unlock(); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid source offset"); } } - ALCdevice_Unlock(Context->Device); + device->Backend->unlock(); } return AL_TRUE; @@ -2704,7 +2705,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", *bad_sid); ALCdevice *device{context->Device}; - ALCdevice_Lock(device); + device->Backend->lock(); /* If the device is disconnected, go right to stopped. */ if(UNLIKELY(!device->Connected.load(std::memory_order_acquire))) { @@ -2718,7 +2719,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) source->state = AL_STOPPED; } ); - ALCdevice_Unlock(device); + device->Backend->unlock(); return; } @@ -2726,7 +2727,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) { if(UNLIKELY(context->MaxVoices > std::numeric_limits::max()>>1)) { - ALCdevice_Unlock(device); + device->Backend->unlock(); SETERR_RETURN(context.get(), AL_OUT_OF_MEMORY,, "Overflow increasing voice count from %d", context->MaxVoices); } @@ -2861,7 +2862,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) SendStateChangeEvent(context.get(), source->id, AL_PLAYING); }; std::for_each(sources, sources_end, start_source); - ALCdevice_Unlock(device); + device->Backend->unlock(); } AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source) @@ -2885,7 +2886,7 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) } ALCdevice *device{context->Device}; - ALCdevice_Lock(device); + device->Backend->lock(); for(ALsizei i{0};i < n;i++) { ALsource *source{LookupSource(context.get(), sources[i])}; @@ -2897,7 +2898,7 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) SendStateChangeEvent(context.get(), source->id, AL_PAUSED); } } - ALCdevice_Unlock(device); + device->Backend->unlock(); } AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source) @@ -2921,7 +2922,7 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) } ALCdevice *device{context->Device}; - ALCdevice_Lock(device); + device->Backend->lock(); for(ALsizei i{0};i < n;i++) { ALsource *source{LookupSource(context.get(), sources[i])}; @@ -2941,7 +2942,7 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) source->OffsetType = AL_NONE; source->Offset = 0.0; } - ALCdevice_Unlock(device); + device->Backend->unlock(); } AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source) @@ -2965,7 +2966,7 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) } ALCdevice *device{context->Device}; - ALCdevice_Lock(device); + device->Backend->lock(); for(ALsizei i{0};i < n;i++) { ALsource *source{LookupSource(context.get(), sources[i])}; @@ -2984,7 +2985,7 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) source->OffsetType = AL_NONE; source->Offset = 0.0; } - ALCdevice_Unlock(device); + device->Backend->unlock(); } -- cgit v1.2.3 From 3df1d185f8bcf8d470249594a15d0e781a705ca2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Dec 2018 17:29:52 -0800 Subject: Don't make the backend's lock/unlock methods noexcept --- Alc/backends/base.cpp | 6 ------ Alc/backends/base.h | 4 ++-- Alc/backends/pulseaudio.cpp | 16 ++++++++-------- Alc/backends/sdl2.cpp | 8 ++++---- 4 files changed, 14 insertions(+), 20 deletions(-) diff --git a/Alc/backends/base.cpp b/Alc/backends/base.cpp index 5c25b366..e3753426 100644 --- a/Alc/backends/base.cpp +++ b/Alc/backends/base.cpp @@ -57,9 +57,3 @@ ClockLatency BackendBase::getClockLatency() return ret; } - -void BackendBase::lock() noexcept -{ mMutex.lock(); } - -void BackendBase::unlock() noexcept -{ mMutex.unlock(); } diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 81424bef..fc50af2b 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -41,8 +41,8 @@ struct BackendBase { virtual ClockLatency getClockLatency(); - virtual void lock() noexcept; - virtual void unlock() noexcept; + virtual void lock() { mMutex.lock(); }; + virtual void unlock() { mMutex.unlock(); }; ALCdevice *mDevice; diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index e714ac3f..34c5fbfe 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -759,8 +759,8 @@ struct PulsePlayback final : public BackendBase { ALCboolean start() override; void stop() override; ClockLatency getClockLatency() override; - void lock() noexcept override; - void unlock() noexcept override; + void lock() override; + void unlock() override; std::string mDeviceName; @@ -1225,10 +1225,10 @@ ClockLatency PulsePlayback::getClockLatency() } -void PulsePlayback::lock() noexcept +void PulsePlayback::lock() { pa_threaded_mainloop_lock(mLoop); } -void PulsePlayback::unlock() noexcept +void PulsePlayback::unlock() { pa_threaded_mainloop_unlock(mLoop); } @@ -1254,8 +1254,8 @@ struct PulseCapture final : public BackendBase { ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override; ALCuint availableSamples() override; ClockLatency getClockLatency() override; - void lock() noexcept override; - void unlock() noexcept override; + void lock() override; + void unlock() override; std::string mDeviceName; @@ -1577,10 +1577,10 @@ ClockLatency PulseCapture::getClockLatency() } -void PulseCapture::lock() noexcept +void PulseCapture::lock() { pa_threaded_mainloop_lock(mLoop); } -void PulseCapture::unlock() noexcept +void PulseCapture::unlock() { pa_threaded_mainloop_unlock(mLoop); } } // namespace diff --git a/Alc/backends/sdl2.cpp b/Alc/backends/sdl2.cpp index 7665146a..84b34014 100644 --- a/Alc/backends/sdl2.cpp +++ b/Alc/backends/sdl2.cpp @@ -54,8 +54,8 @@ struct Sdl2Backend final : public BackendBase { ALCboolean reset() override; ALCboolean start() override; void stop() override; - void lock() noexcept override; - void unlock() noexcept override; + void lock() override; + void unlock() override; SDL_AudioDeviceID mDeviceID{0u}; ALsizei mFrameSize{0}; @@ -178,10 +178,10 @@ ALCboolean Sdl2Backend::start() void Sdl2Backend::stop() { SDL_PauseAudioDevice(mDeviceID, 1); } -void Sdl2Backend::lock() noexcept +void Sdl2Backend::lock() { SDL_LockAudioDevice(mDeviceID); } -void Sdl2Backend::unlock() noexcept +void Sdl2Backend::unlock() { SDL_UnlockAudioDevice(mDeviceID); } } // namespace -- cgit v1.2.3 From 9f5c9a2260849240bd680b8fdf533acdef7f9de1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Dec 2018 21:38:42 -0800 Subject: Rename BackendLock to StateLock --- Alc/alc.cpp | 64 +++++++++++++++++++------------------------- Alc/backends/alsa.cpp | 4 --- Alc/backends/dsound.cpp | 6 ----- Alc/backends/jack.cpp | 3 +-- Alc/backends/opensl.cpp | 4 --- Alc/backends/oss.cpp | 4 --- Alc/backends/sndio.cpp | 4 --- Alc/backends/wasapi.cpp | 10 ------- Alc/backends/wave.cpp | 2 -- OpenAL32/Include/alMain.h | 6 ++++- OpenAL32/Include/alu.h | 2 +- OpenAL32/alAuxEffectSlot.cpp | 4 +-- OpenAL32/alSource.cpp | 4 +-- 13 files changed, 38 insertions(+), 79 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 167ee3e6..b74f4918 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2844,7 +2844,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para alcSetError(nullptr, ALC_INVALID_DEVICE); else { - std::lock_guard _{dev->BackendLock}; + std::lock_guard _{dev->StateLock}; value = (dev->mHrtf ? dev->HrtfName.c_str() : ""); } break; @@ -2927,7 +2927,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC alcSetError(device, ALC_INVALID_VALUE); else { - std::lock_guard _{device->BackendLock}; + std::lock_guard _{device->StateLock}; values[i++] = ALC_MAJOR_VERSION; values[i++] = alcMajorVersion; values[i++] = ALC_MINOR_VERSION; @@ -2948,13 +2948,13 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_CAPTURE_SAMPLES: - { std::lock_guard _{device->BackendLock}; + { std::lock_guard _{device->StateLock}; values[0] = device->Backend->availableSamples(); } return 1; case ALC_CONNECTED: - { std::lock_guard _{device->BackendLock}; + { std::lock_guard _{device->StateLock}; values[0] = device->Connected.load(std::memory_order_acquire); } return 1; @@ -2979,7 +2979,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC alcSetError(device, ALC_INVALID_VALUE); else { - std::lock_guard _{device->BackendLock}; + std::lock_guard _{device->StateLock}; values[i++] = ALC_MAJOR_VERSION; values[i++] = alcMajorVersion; values[i++] = ALC_MINOR_VERSION; @@ -3071,7 +3071,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC alcSetError(device, ALC_INVALID_DEVICE); return 0; } - { std::lock_guard _{device->BackendLock}; + { std::lock_guard _{device->StateLock}; values[0] = device->Frequency / device->UpdateSize; } return 1; @@ -3143,7 +3143,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_CONNECTED: - { std::lock_guard _{device->BackendLock}; + { std::lock_guard _{device->StateLock}; values[0] = device->Connected.load(std::memory_order_acquire); } return 1; @@ -3157,7 +3157,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_NUM_HRTF_SPECIFIERS_SOFT: - { std::lock_guard _{device->BackendLock}; + { std::lock_guard _{device->StateLock}; device->HrtfList.clear(); device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); values[0] = (ALCint)device->HrtfList.size(); @@ -3217,7 +3217,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, else { ALsizei i{0}; - std::lock_guard _{dev->BackendLock}; + std::lock_guard _{dev->StateLock}; values[i++] = ALC_FREQUENCY; values[i++] = dev->Frequency; @@ -3280,7 +3280,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, break; case ALC_DEVICE_CLOCK_SOFT: - { std::lock_guard _{dev->BackendLock}; + { std::lock_guard _{dev->StateLock}; using std::chrono::seconds; using std::chrono::nanoseconds; using std::chrono::duration_cast; @@ -3300,7 +3300,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, break; case ALC_DEVICE_LATENCY_SOFT: - { std::lock_guard _{dev->BackendLock}; + { std::lock_guard _{dev->StateLock}; ClockLatency clock{GetClockLatency(dev.get())}; *values = clock.Latency.count(); } @@ -3311,7 +3311,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, alcSetError(dev.get(), ALC_INVALID_VALUE); else { - std::lock_guard _{dev->BackendLock}; + std::lock_guard _{dev->StateLock}; ClockLatency clock{GetClockLatency(dev.get())}; values[0] = clock.ClockTime.count(); values[1] = clock.Latency.count(); @@ -3417,8 +3417,8 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ALfloat valf; ALCenum err; - /* Explicitly hold the list lock while taking the BackendLock in case the - * device is asynchronously destropyed, to ensure this new context is + /* Explicitly hold the list lock while taking the StateLock in case the + * device is asynchronously destroyed, to ensure this new context is * properly cleaned up after being made. */ std::unique_lock listlock{ListLock}; @@ -3429,7 +3429,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin alcSetError(dev.get(), ALC_INVALID_DEVICE); return nullptr; } - std::unique_lock backlock{dev->BackendLock}; + std::unique_lock statelock{dev->StateLock}; listlock.unlock(); dev->LastError.store(ALC_NO_ERROR); @@ -3441,12 +3441,8 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin { alcSetError(dev.get(), err); if(err == ALC_INVALID_DEVICE) - { - dev->Backend->lock(); aluHandleDisconnect(dev.get(), "Device update failure"); - dev->Backend->unlock(); - } - backlock.unlock(); + statelock.unlock(); delete ALContext; ALContext = nullptr; @@ -3490,7 +3486,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ALContext->next.store(head, std::memory_order_relaxed); } while(!dev->ContextList.compare_exchange_weak(head, ALContext)); } - backlock.unlock(); + statelock.unlock(); if(ALContext->DefaultSlot) { @@ -3522,7 +3518,7 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) ALCdevice* Device{ctx->Device}; if(Device) { - std::lock_guard _{Device->BackendLock}; + std::lock_guard _{Device->StateLock}; if(!ReleaseContext(ctx.get(), Device)) { Device->Backend->stop(); @@ -3845,7 +3841,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) alcSetError(iter, ALC_INVALID_DEVICE); return ALC_FALSE; } - std::unique_lock backlock{device->BackendLock}; + std::unique_lock statelock{device->StateLock}; ALCdevice *origdev{device}; ALCdevice *nextdev{device->next.load(std::memory_order_relaxed)}; @@ -3870,7 +3866,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) if((device->Flags&DEVICE_RUNNING)) device->Backend->stop(); device->Flags &= ~DEVICE_RUNNING; - backlock.unlock(); + statelock.unlock(); ALCdevice_DecRef(device); @@ -3976,7 +3972,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) } listlock.unlock(); - { std::lock_guard _{device->BackendLock}; + { std::lock_guard _{device->StateLock}; if((device->Flags&DEVICE_RUNNING)) device->Backend->stop(); device->Flags &= ~DEVICE_RUNNING; @@ -3996,7 +3992,7 @@ ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) return; } - std::lock_guard _{dev->BackendLock}; + std::lock_guard _{dev->StateLock}; if(!dev->Connected.load(std::memory_order_acquire)) alcSetError(dev.get(), ALC_INVALID_DEVICE); else if(!(dev->Flags&DEVICE_RUNNING)) @@ -4018,7 +4014,7 @@ ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) alcSetError(dev.get(), ALC_INVALID_DEVICE); else { - std::lock_guard _{dev->BackendLock}; + std::lock_guard _{dev->StateLock}; if((dev->Flags&DEVICE_RUNNING)) dev->Backend->stop(); dev->Flags &= ~DEVICE_RUNNING; @@ -4035,7 +4031,7 @@ ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, } ALCenum err{ALC_INVALID_VALUE}; - { std::lock_guard _{dev->BackendLock}; + { std::lock_guard _{dev->StateLock}; BackendBase *backend{dev->Backend.get()}; if(samples >= 0 && backend->availableSamples() >= (ALCuint)samples) err = backend->captureSamples(buffer, samples); @@ -4172,7 +4168,7 @@ ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device) alcSetError(dev.get(), ALC_INVALID_DEVICE); else { - std::lock_guard _{dev->BackendLock}; + std::lock_guard _{dev->StateLock}; if((dev->Flags&DEVICE_RUNNING)) dev->Backend->stop(); dev->Flags &= ~DEVICE_RUNNING; @@ -4193,7 +4189,7 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) return; } - std::lock_guard _{dev->BackendLock}; + std::lock_guard _{dev->StateLock}; if(!(dev->Flags&DEVICE_PAUSED)) return; dev->Flags &= ~DEVICE_PAUSED; @@ -4202,9 +4198,7 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) if(dev->Backend->start() == ALC_FALSE) { - dev->Backend->lock(); aluHandleDisconnect(dev.get(), "Device start failure"); - dev->Backend->unlock(); alcSetError(dev.get(), ALC_INVALID_DEVICE); return; } @@ -4255,7 +4249,7 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi alcSetError(dev.get(), ALC_INVALID_DEVICE); return ALC_FALSE; } - std::lock_guard _{dev->BackendLock}; + std::lock_guard _{dev->StateLock}; listlock.unlock(); /* Force the backend to stop mixing first since we're resetting. Also reset @@ -4271,10 +4265,6 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi alcSetError(dev.get(), err); if(err == ALC_INVALID_DEVICE) - { - dev->Backend->lock(); aluHandleDisconnect(dev.get(), "Device start failure"); - dev->Backend->unlock(); - } return ALC_FALSE; } diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index 43336026..a3c30732 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -469,9 +469,7 @@ int AlsaPlayback::mixerProc() if(state < 0) { ERR("Invalid state detected: %s\n", snd_strerror(state)); - lock(); aluHandleDisconnect(mDevice, "Bad state: %s", snd_strerror(state)); - unlock(); break; } @@ -554,9 +552,7 @@ int AlsaPlayback::mixerNoMMapProc() if(state < 0) { ERR("Invalid state detected: %s\n", snd_strerror(state)); - lock(); aluHandleDisconnect(mDevice, "Bad state: %s", snd_strerror(state)); - unlock(); break; } diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index b7424473..4138c180 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -241,9 +241,7 @@ FORCE_ALIGN int DSoundPlayback::mixerProc() if(FAILED(err)) { ERR("Failed to get buffer caps: 0x%lx\n", err); - lock(); aluHandleDisconnect(mDevice, "Failure retrieving playback buffer info: 0x%lx", err); - unlock(); return 1; } @@ -269,9 +267,7 @@ FORCE_ALIGN int DSoundPlayback::mixerProc() if(FAILED(err)) { ERR("Failed to play buffer: 0x%lx\n", err); - lock(); aluHandleDisconnect(mDevice, "Failure starting playback: 0x%lx", err); - unlock(); return 1; } Playing = true; @@ -316,9 +312,7 @@ FORCE_ALIGN int DSoundPlayback::mixerProc() else { ERR("Buffer lock error: %#lx\n", err); - lock(); aluHandleDisconnect(mDevice, "Failed to lock output buffer: 0x%lx", err); - unlock(); return 1; } diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index 5ac0ff4d..78de2699 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -200,7 +200,7 @@ int JackPlayback::bufferSizeNotifyC(jack_nframes_t numframes, void *arg) int JackPlayback::bufferSizeNotify(jack_nframes_t numframes) { - lock(); + std::lock_guard _{mDevice->StateLock}; mDevice->UpdateSize = numframes; mDevice->NumUpdates = 2; @@ -218,7 +218,6 @@ int JackPlayback::bufferSizeNotify(jack_nframes_t numframes) ERR("Failed to reallocate ringbuffer\n"); aluHandleDisconnect(mDevice, "Failed to reallocate %u-sample buffer", bufsize); } - unlock(); return 0; } diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 66bc6e8d..766b7675 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -839,9 +839,7 @@ ALCboolean OpenSLCapture::start() if(SL_RESULT_SUCCESS != result) { - lock(); aluHandleDisconnect(mDevice, "Failed to start capture: 0x%08x", result); - unlock(); return ALC_FALSE; } @@ -904,9 +902,7 @@ ALCenum OpenSLCapture::captureSamples(void* buffer, ALCuint samples) if(SL_RESULT_SUCCESS != result) { - lock(); aluHandleDisconnect(mDevice, "Failed to update capture buffer: 0x%08x", result); - unlock(); return ALC_INVALID_DEVICE; } diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index c18a1d86..b5640ae3 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -520,9 +520,7 @@ int OSScapture::recordProc() if(errno == EINTR || errno == EAGAIN) continue; ERR("poll failed: %s\n", strerror(errno)); - lock(); aluHandleDisconnect(mDevice, "Failed to check capture samples: %s", strerror(errno)); - unlock(); break; } else if(sret == 0) @@ -538,10 +536,8 @@ int OSScapture::recordProc() if(amt < 0) { ERR("read failed: %s\n", strerror(errno)); - lock(); aluHandleDisconnect(mDevice, "Failed reading capture samples: %s", strerror(errno)); - unlock(); break; } mRing->writeAdvance(amt/frame_size); diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index 5d74dd5a..c75eebee 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -94,9 +94,7 @@ int SndioPlayback::mixerProc() if(wrote == 0) { ERR("sio_write failed\n"); - lock(); aluHandleDisconnect(mDevice, "Failed to write playback samples"); - unlock(); break; } @@ -308,9 +306,7 @@ int SndioCapture::recordProc() size_t got{sio_read(mSndHandle, data.first.buf, minz(todo-total, data.first.len))}; if(!got) { - lock(); aluHandleDisconnect(mDevice, "Failed to read capture samples"); - unlock(); break; } diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index cb0b665b..d221565c 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -560,9 +560,7 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() if(FAILED(hr)) { ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); - lock(); aluHandleDisconnect(mDevice, "COM init failed: 0x%08lx", hr); - unlock(); return 1; } @@ -578,9 +576,7 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() if(FAILED(hr)) { ERR("Failed to get padding: 0x%08lx\n", hr); - lock(); aluHandleDisconnect(mDevice, "Failed to retrieve buffer padding: 0x%08lx", hr); - unlock(); break; } mPadding.store(written, std::memory_order_relaxed); @@ -608,9 +604,7 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() if(FAILED(hr)) { ERR("Failed to buffer data: 0x%08lx\n", hr); - lock(); aluHandleDisconnect(mDevice, "Failed to send playback samples: 0x%08lx", hr); - unlock(); break; } } @@ -1194,9 +1188,7 @@ FORCE_ALIGN int WasapiCapture::recordProc() if(FAILED(hr)) { ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); - lock(); aluHandleDisconnect(mDevice, "COM init failed: 0x%08lx", hr); - unlock(); return 1; } @@ -1268,9 +1260,7 @@ FORCE_ALIGN int WasapiCapture::recordProc() if(FAILED(hr)) { - lock(); aluHandleDisconnect(mDevice, "Failed to capture samples: 0x%08lx", hr); - unlock(); break; } diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index 49d4a735..36adce95 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -172,9 +172,7 @@ int WaveBackend::mixerProc() if(ferror(mFile)) { ERR("Error writing to file\n"); - lock(); aluHandleDisconnect(mDevice, "Failed to write playback samples"); - unlock(); break; } } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index e23eb1fb..5e53a047 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -785,7 +785,11 @@ struct ALCdevice_struct { // Contexts created on this device std::atomic ContextList{nullptr}; - std::mutex BackendLock; + /* This lock protects the device state (format, update size, etc) from + * being from being changed in multiple threads, or being accessed while + * being changed. It's also used to serialize calls to the backend. + */ + std::mutex StateLock; std::unique_ptr Backend; std::atomic next{nullptr}; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 7a378562..4fcc4c9c 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -478,7 +478,7 @@ void ComputePanGains(const ALeffectslot *slot, const ALfloat*RESTRICT coeffs, AL ALboolean MixSource(ALvoice *voice, const ALuint SourceID, ALCcontext *Context, const ALsizei SamplesToDo); void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples); -/* Caller must lock the device, and the mixer must not be running. */ +/* Caller must lock the device state, and the mixer must not be running. */ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) DECL_FORMAT(printf, 2, 3); extern MixerFunc MixSamples; diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index 1b3b97be..fc43edbe 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -556,12 +556,12 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect FPUCtl mixer_mode{}; ALCdevice *Device{Context->Device}; - std::unique_lock backlock{Device->BackendLock}; + std::unique_lock statelock{Device->StateLock}; State->mOutBuffer = Device->Dry.Buffer; State->mOutChannels = Device->Dry.NumChannels; if(State->deviceUpdate(Device) == AL_FALSE) { - backlock.unlock(); + statelock.unlock(); mixer_mode.leave(); State->DecRef(); return AL_OUT_OF_MEMORY; diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 069d600b..a3428e02 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -1726,7 +1726,7 @@ ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL * clock time with the device latency. Order is important. */ values[0] = GetSourceSecOffset(Source, Context, &srcclock); - { std::lock_guard _{device->BackendLock}; + { std::lock_guard _{device->StateLock}; clocktime = GetClockLatency(device); } if(srcclock == clocktime.ClockTime) @@ -1989,7 +1989,7 @@ ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, * clock time with the device latency. Order is important. */ values[0] = GetSourceSampleOffset(Source, Context, &srcclock); - { std::lock_guard _{device->BackendLock}; + { std::lock_guard _{device->StateLock}; clocktime = GetClockLatency(device); } if(srcclock == clocktime.ClockTime) -- cgit v1.2.3 From 5e03941701c112083b5dce14257fd8c51262f04f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Dec 2018 21:58:14 -0800 Subject: Use an atomic bool on things that only take true or false --- Alc/alc.cpp | 2 +- Alc/alu.cpp | 2 +- Alc/backends/alsa.cpp | 6 +++--- Alc/backends/dsound.cpp | 6 +++--- Alc/backends/null.cpp | 6 +++--- Alc/backends/opensl.cpp | 6 +++--- Alc/backends/oss.cpp | 12 ++++++------ Alc/backends/wasapi.cpp | 12 ++++++------ Alc/backends/wave.cpp | 6 +++--- Alc/backends/winmm.cpp | 12 ++++++------ OpenAL32/Include/alMain.h | 2 +- 11 files changed, 36 insertions(+), 36 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index b74f4918..0b89bd71 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -4258,7 +4258,7 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi if((dev->Flags&DEVICE_RUNNING)) dev->Backend->stop(); dev->Flags &= ~DEVICE_RUNNING; - device->Connected.store(AL_TRUE); + device->Connected.store(true); ALCenum err{UpdateDeviceParams(dev.get(), attribs)}; if(LIKELY(err == ALC_NO_ERROR)) return ALC_TRUE; diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 672b571b..1711d3bf 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1817,7 +1817,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) { - if(!device->Connected.exchange(AL_FALSE, std::memory_order_acq_rel)) + if(!device->Connected.exchange(false, std::memory_order_acq_rel)) return; AsyncEvent evt{EventType_Disconnected}; diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index a3c30732..aee9c1d3 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -441,7 +441,7 @@ struct AlsaPlayback final : public BackendBase { al::vector mBuffer; - std::atomic mKillNow{AL_TRUE}; + std::atomic mKillNow{true}; std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "AlsaPlayback::"; } @@ -856,7 +856,7 @@ ALCboolean AlsaPlayback::start() } try { - mKillNow.store(AL_FALSE, std::memory_order_release); + mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(thread_func), this}; return ALC_TRUE; } @@ -871,7 +871,7 @@ ALCboolean AlsaPlayback::start() void AlsaPlayback::stop() { - if(mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !mThread.joinable()) + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) return; mThread.join(); diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 4138c180..6de108cd 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -202,7 +202,7 @@ struct DSoundPlayback final : public BackendBase { IDirectSoundNotify *mNotifies{nullptr}; HANDLE mNotifyEvent{nullptr}; - std::atomic mKillNow{AL_TRUE}; + std::atomic mKillNow{true}; std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "DSoundPlayback::"; } @@ -596,7 +596,7 @@ retry_open: ALCboolean DSoundPlayback::start() { try { - mKillNow.store(AL_FALSE, std::memory_order_release); + mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&DSoundPlayback::mixerProc), this}; return ALC_TRUE; } @@ -610,7 +610,7 @@ ALCboolean DSoundPlayback::start() void DSoundPlayback::stop() { - if(mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !mThread.joinable()) + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) return; mThread.join(); diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 7f02ad62..cba204f6 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -55,7 +55,7 @@ struct NullBackend final : public BackendBase { ALCboolean start() override; void stop() override; - std::atomic mKillNow{AL_TRUE}; + std::atomic mKillNow{true}; std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "NullBackend::"; } @@ -129,7 +129,7 @@ ALCboolean NullBackend::reset() ALCboolean NullBackend::start() { try { - mKillNow.store(AL_FALSE, std::memory_order_release); + mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&NullBackend::mixerProc), this}; return ALC_TRUE; } @@ -143,7 +143,7 @@ ALCboolean NullBackend::start() void NullBackend::stop() { - if(mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !mThread.joinable()) + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) return; mThread.join(); } diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 766b7675..69f9cda4 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -169,7 +169,7 @@ struct OpenSLPlayback final : public BackendBase { ALsizei mFrameSize{0}; - std::atomic mKillNow{AL_TRUE}; + std::atomic mKillNow{true}; std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "OpenSLPlayback::"; } @@ -550,7 +550,7 @@ ALCboolean OpenSLPlayback::start() if(SL_RESULT_SUCCESS != result) return ALC_FALSE; try { - mKillNow.store(AL_FALSE); + mKillNow.store(false, std::memory_order_release); mThread = std::thread(std::mem_fn(&OpenSLPlayback::mixerProc), this); return ALC_TRUE; } @@ -564,7 +564,7 @@ ALCboolean OpenSLPlayback::start() void OpenSLPlayback::stop() { - if(mKillNow.exchange(AL_TRUE) || !mThread.joinable()) + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) return; mSem.post(); diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index b5640ae3..05394f34 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -257,7 +257,7 @@ struct OSSPlayback final : public BackendBase { al::vector mMixData; - std::atomic mKillNow{AL_TRUE}; + std::atomic mKillNow{true}; std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "OSSPlayback::"; } @@ -448,7 +448,7 @@ ALCboolean OSSPlayback::reset() ALCboolean OSSPlayback::start() { try { - mKillNow.store(AL_FALSE); + mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&OSSPlayback::mixerProc), this}; return ALC_TRUE; } @@ -462,7 +462,7 @@ ALCboolean OSSPlayback::start() void OSSPlayback::stop() { - if(mKillNow.exchange(AL_TRUE) || !mThread.joinable()) + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) return; mThread.join(); @@ -487,7 +487,7 @@ struct OSScapture final : public BackendBase { RingBufferPtr mRing{nullptr}; - std::atomic mKillNow{AL_TRUE}; + std::atomic mKillNow{true}; std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "OSScapture::"; } @@ -661,7 +661,7 @@ ALCenum OSScapture::open(const ALCchar *name) ALCboolean OSScapture::start() { try { - mKillNow.store(AL_FALSE); + mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&OSScapture::recordProc), this}; return ALC_TRUE; } @@ -675,7 +675,7 @@ ALCboolean OSScapture::start() void OSScapture::stop() { - if(mKillNow.exchange(AL_TRUE) || !mThread.joinable()) + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) return; mThread.join(); diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index d221565c..6fe97cb0 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -525,7 +525,7 @@ struct WasapiPlayback final : public BackendBase, WasapiProxy { std::atomic mPadding{0u}; - std::atomic mKillNow{AL_TRUE}; + std::atomic mKillNow{true}; std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "WasapiPlayback::"; } @@ -1070,7 +1070,7 @@ HRESULT WasapiPlayback::startProxy() { mRender = static_cast(ptr); try { - mKillNow.store(AL_FALSE, std::memory_order_release); + mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&WasapiPlayback::mixerProc), this}; } catch(...) { @@ -1101,7 +1101,7 @@ void WasapiPlayback::stopProxy() if(!mRender || !mThread.joinable()) return; - mKillNow.store(AL_TRUE); + mKillNow.store(true, std::memory_order_release); mThread.join(); mRender->Release(); @@ -1156,7 +1156,7 @@ struct WasapiCapture final : public BackendBase, WasapiProxy { SampleConverterPtr mSampleConv; RingBufferPtr mRing; - std::atomic mKillNow{AL_TRUE}; + std::atomic mKillNow{true}; std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "WasapiCapture::"; } @@ -1671,7 +1671,7 @@ HRESULT WasapiCapture::startProxy() { mCapture = static_cast(ptr); try { - mKillNow.store(AL_FALSE, std::memory_order_release); + mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&WasapiCapture::recordProc), this}; } catch(...) { @@ -1705,7 +1705,7 @@ void WasapiCapture::stopProxy() if(!mCapture || !mThread.joinable()) return; - mKillNow.store(AL_TRUE); + mKillNow.store(true, std::memory_order_release); mThread.join(); mCapture->Release(); diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index 36adce95..42b67a19 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -95,7 +95,7 @@ struct WaveBackend final : public BackendBase { al::vector mBuffer; - std::atomic mKillNow{AL_TRUE}; + std::atomic mKillNow{true}; std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "WaveBackend::"; } @@ -328,7 +328,7 @@ ALCboolean WaveBackend::reset() ALCboolean WaveBackend::start() { try { - mKillNow.store(AL_FALSE, std::memory_order_release); + mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&WaveBackend::mixerProc), this}; return ALC_TRUE; } @@ -342,7 +342,7 @@ ALCboolean WaveBackend::start() void WaveBackend::stop() { - if(mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !mThread.joinable()) + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) return; mThread.join(); diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index bc599006..34eade29 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -144,7 +144,7 @@ struct WinMMPlayback final : public BackendBase { WAVEFORMATEX mFormat{}; - std::atomic mKillNow{AL_TRUE}; + std::atomic mKillNow{true}; std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "WinMMPlayback::"; } @@ -336,7 +336,7 @@ ALCboolean WinMMPlayback::start() ); mWritable.store(static_cast(mWaveBuffer.size()), std::memory_order_release); - mKillNow.store(AL_FALSE, std::memory_order_release); + mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&WinMMPlayback::mixerProc), this}; return ALC_TRUE; } @@ -350,7 +350,7 @@ ALCboolean WinMMPlayback::start() void WinMMPlayback::stop() { - if(mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !mThread.joinable()) + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) return; mThread.join(); @@ -390,7 +390,7 @@ struct WinMMCapture final : public BackendBase { WAVEFORMATEX mFormat{}; - std::atomic mKillNow{AL_TRUE}; + std::atomic mKillNow{true}; std::thread mThread; static constexpr inline const char *CurrentPrefix() noexcept { return "WinMMCapture::"; } @@ -554,7 +554,7 @@ ALCboolean WinMMCapture::start() waveInAddBuffer(mInHdl, &mWaveBuffer[i], sizeof(WAVEHDR)); } - mKillNow.store(AL_FALSE, std::memory_order_release); + mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&WinMMCapture::captureProc), this}; waveInStart(mInHdl); @@ -572,7 +572,7 @@ void WinMMCapture::stop() { waveInStop(mInHdl); - mKillNow.store(AL_TRUE, std::memory_order_release); + mKillNow.store(true, std::memory_order_release); if(mThread.joinable()) { mSem.post(); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 5e53a047..e3f24829 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -666,7 +666,7 @@ using POSTPROCESS = void(*)(ALCdevice *device, ALsizei SamplesToDo); struct ALCdevice_struct { RefCount ref{1u}; - std::atomic Connected{AL_TRUE}; + std::atomic Connected{true}; const DeviceType Type{}; ALuint Frequency{}; -- cgit v1.2.3 From 5a9a1c8d7d97f589d978ff00859797e76b087a73 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 31 Dec 2018 04:12:20 -0800 Subject: Further improve HRTF methods to avoid masking in the inner loops --- Alc/mixer/hrtf_inc.cpp | 208 +++++++++++++++++++++++++++++++----------------- Alc/mixer/mixer_c.cpp | 15 ++-- Alc/mixer/mixer_sse.cpp | 32 ++++---- OpenAL32/Include/alu.h | 8 +- 4 files changed, 163 insertions(+), 100 deletions(-) diff --git a/Alc/mixer/hrtf_inc.cpp b/Alc/mixer/hrtf_inc.cpp index e82bad85..caac7e54 100644 --- a/Alc/mixer/hrtf_inc.cpp +++ b/Alc/mixer/hrtf_inc.cpp @@ -14,114 +14,178 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (&Values)[HRIR_LENGTH][2] void MixHrtf(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALfloat *data, ALsizei Offset, const ALsizei OutPos, const ALsizei IrSize, MixHrtfParams *hrtfparams, HrtfState *hrtfstate, - ALsizei BufferSize) + const ALsizei BufferSize) { - const ALfloat (&Coeffs)[HRIR_LENGTH][2] = *hrtfparams->Coeffs; - const ALsizei Delay[2] = { hrtfparams->Delay[0], hrtfparams->Delay[1] }; - const ALfloat gainstep = hrtfparams->GainStep; - const ALfloat gain = hrtfparams->Gain; - ALfloat g, stepcount = 0.0f; - ALfloat left, right; - ALsizei i; - + ASSUME(OutPos >= 0); ASSUME(IrSize >= 4); ASSUME(BufferSize > 0); - LeftOut += OutPos; - RightOut += OutPos; - for(i = 0;i < BufferSize;i++) - { - hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++); - - g = gain + gainstep*stepcount; - left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK]*g; - right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK]*g; + const ALfloat (&Coeffs)[HRIR_LENGTH][2] = *hrtfparams->Coeffs; + const ALfloat gainstep{hrtfparams->GainStep}; + const ALfloat gain{hrtfparams->Gain}; + ALfloat stepcount{0.0f}; - hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f; - hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f; + ALsizei HistOffset{Offset&HRTF_HISTORY_MASK}; + ALsizei Delay[2]{ + (HistOffset-hrtfparams->Delay[0])&HRTF_HISTORY_MASK, + (HistOffset-hrtfparams->Delay[1])&HRTF_HISTORY_MASK }; - ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right); - *(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0]; - *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1]; + Offset &= HRIR_MASK; + ALsizei HeadOffset{(Offset+IrSize-1)&HRIR_MASK}; - stepcount += 1.0f; - Offset++; + LeftOut += OutPos; + RightOut += OutPos; + for(ALsizei i{0};i < BufferSize;) + { + /* Calculate the number of samples we can do until one of the indices + * wraps on its buffer, or we reach the end. + */ + const ALsizei todo_hist{HRTF_HISTORY_LENGTH - maxi(maxi(HistOffset, Delay[0]), Delay[1])}; + const ALsizei todo_hrir{HRIR_LENGTH - maxi(HeadOffset, Offset)}; + const ALsizei todo{mini(BufferSize-i, mini(todo_hist, todo_hrir)) + i}; + ASSUME(todo > i); + + for(;i < todo;++i) + { + hrtfstate->Values[HeadOffset][0] = 0.0f; + hrtfstate->Values[HeadOffset][1] = 0.0f; + ++HeadOffset; + + hrtfstate->History[HistOffset++] = *(data++); + + const ALfloat g{gain + gainstep*stepcount}; + const ALfloat left{hrtfstate->History[Delay[0]++] * g}; + const ALfloat right{hrtfstate->History[Delay[1]++] * g}; + ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right); + + *(LeftOut++) += hrtfstate->Values[Offset][0]; + *(RightOut++) += hrtfstate->Values[Offset][1]; + ++Offset; + + stepcount += 1.0f; + } + + HeadOffset &= HRIR_MASK; + HistOffset &= HRTF_HISTORY_MASK; + Delay[0] &= HRTF_HISTORY_MASK; + Delay[1] &= HRTF_HISTORY_MASK; + Offset &= HRIR_MASK; } hrtfparams->Gain = gain + gainstep*stepcount; } void MixHrtfBlend(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALfloat *data, ALsizei Offset, const ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, HrtfState *hrtfstate, - ALsizei BufferSize) + const ALsizei BufferSize) { const ALfloat (&OldCoeffs)[HRIR_LENGTH][2] = oldparams->Coeffs; - const ALsizei OldDelay[2] = { oldparams->Delay[0], oldparams->Delay[1] }; - const ALfloat oldGain = oldparams->Gain; - const ALfloat oldGainStep = -oldGain / (ALfloat)BufferSize; + const ALfloat oldGain{oldparams->Gain}; + const ALfloat oldGainStep{-oldGain / (ALfloat)BufferSize}; const ALfloat (&NewCoeffs)[HRIR_LENGTH][2] = *newparams->Coeffs; - const ALsizei NewDelay[2] = { newparams->Delay[0], newparams->Delay[1] }; - const ALfloat newGain = newparams->Gain; - const ALfloat newGainStep = newparams->GainStep; - ALfloat g, stepcount = 0.0f; - ALfloat left, right; - ALsizei i; + const ALfloat newGainStep{newparams->GainStep}; + ALfloat stepcount{0.0f}; + ASSUME(OutPos >= 0); ASSUME(IrSize >= 4); ASSUME(BufferSize > 0); + ALsizei HistOffset{Offset&HRTF_HISTORY_MASK}; + ALsizei OldDelay[2]{ + (HistOffset-oldparams->Delay[0])&HRTF_HISTORY_MASK, + (HistOffset-oldparams->Delay[1])&HRTF_HISTORY_MASK }; + ALsizei NewDelay[2]{ + (HistOffset-newparams->Delay[0])&HRTF_HISTORY_MASK, + (HistOffset-newparams->Delay[1])&HRTF_HISTORY_MASK }; + + Offset &= HRIR_MASK; + ALsizei HeadOffset{(Offset+IrSize-1)&HRIR_MASK}; + LeftOut += OutPos; RightOut += OutPos; - for(i = 0;i < BufferSize;i++) + for(ALsizei i{0};i < BufferSize;) { - hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f; - hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f; - - hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++); - - g = oldGain + oldGainStep*stepcount; - left = hrtfstate->History[(Offset-OldDelay[0])&HRTF_HISTORY_MASK]*g; - right = hrtfstate->History[(Offset-OldDelay[1])&HRTF_HISTORY_MASK]*g; - ApplyCoeffs(Offset, hrtfstate->Values, IrSize, OldCoeffs, left, right); - - g = newGain + newGainStep*stepcount; - left = hrtfstate->History[(Offset-NewDelay[0])&HRTF_HISTORY_MASK]*g; - right = hrtfstate->History[(Offset-NewDelay[1])&HRTF_HISTORY_MASK]*g; - ApplyCoeffs(Offset, hrtfstate->Values, IrSize, NewCoeffs, left, right); - - *(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0]; - *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1]; - - stepcount += 1.0f; - Offset++; + const ALsizei todo_hist{HRTF_HISTORY_LENGTH - + maxi(maxi(maxi(maxi(HistOffset, OldDelay[0]), OldDelay[1]), NewDelay[0]), NewDelay[1]) + }; + const ALsizei todo_hrir{HRIR_LENGTH - maxi(HeadOffset, Offset)}; + const ALsizei todo{mini(BufferSize-i, mini(todo_hist, todo_hrir)) + i}; + ASSUME(todo > i); + + for(;i < todo;++i) + { + hrtfstate->Values[HeadOffset][0] = 0.0f; + hrtfstate->Values[HeadOffset][1] = 0.0f; + ++HeadOffset; + + hrtfstate->History[HistOffset++] = *(data++); + + ALfloat g{oldGain + oldGainStep*stepcount}; + ALfloat left{hrtfstate->History[OldDelay[0]++] * g}; + ALfloat right{hrtfstate->History[OldDelay[1]++] * g}; + ApplyCoeffs(Offset, hrtfstate->Values, IrSize, OldCoeffs, left, right); + + g = newGainStep*stepcount; + left = hrtfstate->History[NewDelay[0]++] * g; + right = hrtfstate->History[NewDelay[1]++] * g; + ApplyCoeffs(Offset, hrtfstate->Values, IrSize, NewCoeffs, left, right); + + *(LeftOut++) += hrtfstate->Values[Offset][0]; + *(RightOut++) += hrtfstate->Values[Offset][1]; + ++Offset; + + stepcount += 1.0f; + } + + HeadOffset &= HRIR_MASK; + HistOffset &= HRTF_HISTORY_MASK; + OldDelay[0] &= HRTF_HISTORY_MASK; + OldDelay[1] &= HRTF_HISTORY_MASK; + NewDelay[0] &= HRTF_HISTORY_MASK; + NewDelay[1] &= HRTF_HISTORY_MASK; + Offset &= HRIR_MASK; } - newparams->Gain = newGain + newGainStep*stepcount; + newparams->Gain = newGainStep*stepcount; } void MixDirectHrtf(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, DirectHrtfState *State, const ALsizei Chan, const ALsizei BufferSize) { - const ALsizei IrSize{State->IrSize}; - ALsizei Offset{State->Offset}; - ALfloat (&Values)[HRIR_LENGTH][2] = State->Chan[Chan].Values; + ASSUME(Chan >= 0); + ASSUME(BufferSize > 0); + const ALfloat (&Coeffs)[HRIR_LENGTH][2] = State->Chan[Chan].Coeffs; + ALfloat (&Values)[HRIR_LENGTH][2] = State->Chan[Chan].Values; + ALsizei Offset{State->Offset&HRIR_MASK}; + const ALsizei IrSize{State->IrSize}; ASSUME(IrSize >= 4); - ASSUME(BufferSize > 0); - for(ALsizei i{0};i < BufferSize;i++) + ALsizei HeadOffset{(Offset+IrSize-1)&HRIR_MASK}; + for(ALsizei i{0};i < BufferSize;) { - Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; - Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; - Offset++; - - const ALfloat insample{*(data++)}; - ApplyCoeffs(Offset, Values, IrSize, Coeffs, insample, insample); - *(LeftOut++) += Values[Offset&HRIR_MASK][0]; - *(RightOut++) += Values[Offset&HRIR_MASK][1]; + const ALsizei todo_hrir{HRIR_LENGTH - maxi(HeadOffset, Offset)}; + const ALsizei todo{mini(BufferSize-i, todo_hrir) + i}; + ASSUME(todo > i); + + for(;i < todo;++i) + { + Values[HeadOffset][0] = 0.0f; + Values[HeadOffset][1] = 0.0f; + ++HeadOffset; + + const ALfloat insample{*(data++)}; + ApplyCoeffs(Offset, Values, IrSize, Coeffs, insample, insample); + + *(LeftOut++) += Values[Offset][0]; + *(RightOut++) += Values[Offset][1]; + ++Offset; + } + HeadOffset &= HRIR_MASK; + Offset &= HRIR_MASK; } } diff --git a/Alc/mixer/mixer_c.cpp b/Alc/mixer/mixer_c.cpp index d98b8e2e..22d3642e 100644 --- a/Alc/mixer/mixer_c.cpp +++ b/Alc/mixer/mixer_c.cpp @@ -107,24 +107,23 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (&Values)[HRIR_LENGTH][2] const ALsizei IrSize, const ALfloat (&Coeffs)[HRIR_LENGTH][2], const ALfloat left, const ALfloat right) { - ALsizei off{Offset&HRIR_MASK}; - ALsizei count{mini(IrSize, HRIR_LENGTH - off)}; - + ASSUME(Offset >= 0 && Offset < HRIR_LENGTH); ASSUME(IrSize >= 2); ASSUME(&Values != &Coeffs); - ASSUME(count > 0); + ALsizei count{mini(IrSize, HRIR_LENGTH - Offset)}; + ASSUME(count > 0); for(ALsizei c{0};;) { for(;c < count;++c) { - Values[off][0] += Coeffs[c][0] * left; - Values[off][1] += Coeffs[c][1] * right; - ++off; + Values[Offset][0] += Coeffs[c][0] * left; + Values[Offset][1] += Coeffs[c][1] * right; + ++Offset; } if(c >= IrSize) break; - off = 0; + Offset = 0; count = IrSize; } } diff --git a/Alc/mixer/mixer_sse.cpp b/Alc/mixer/mixer_sse.cpp index 5d82e5ae..2637883b 100644 --- a/Alc/mixer/mixer_sse.cpp +++ b/Alc/mixer/mixer_sse.cpp @@ -90,45 +90,45 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (&Values)[HRIR_LENGTH][2] ASSUME(IrSize >= 2); ASSUME(&Values != &Coeffs); - ALsizei off{Offset&HRIR_MASK}; + ASSUME(Offset >= 0 && Offset < HRIR_LENGTH); if((Offset&1)) { - ALsizei count{mini(IrSize-1, HRIR_LENGTH - off)}; + ALsizei count{mini(IrSize-1, HRIR_LENGTH - Offset)}; ASSUME(count >= 1); __m128 imp0, imp1; coeffs = _mm_load_ps(&Coeffs[0][0]); - vals = _mm_loadl_pi(vals, (__m64*)&Values[off][0]); + vals = _mm_loadl_pi(vals, (__m64*)&Values[Offset][0]); imp0 = _mm_mul_ps(lrlr, coeffs); vals = _mm_add_ps(imp0, vals); - _mm_storel_pi((__m64*)&Values[off][0], vals); - ++off; + _mm_storel_pi((__m64*)&Values[Offset][0], vals); + ++Offset; for(ALsizei i{1};;) { for(;i < count;i += 2) { coeffs = _mm_load_ps(&Coeffs[i+1][0]); - vals = _mm_load_ps(&Values[off][0]); + vals = _mm_load_ps(&Values[Offset][0]); imp1 = _mm_mul_ps(lrlr, coeffs); imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2)); vals = _mm_add_ps(imp0, vals); - _mm_store_ps(&Values[off][0], vals); + _mm_store_ps(&Values[Offset][0], vals); imp0 = imp1; - off += 2; + Offset += 2; } - off &= HRIR_MASK; + Offset &= HRIR_MASK; if(i >= IrSize-1) break; count = IrSize-1; } - vals = _mm_loadl_pi(vals, (__m64*)&Values[off][0]); + vals = _mm_loadl_pi(vals, (__m64*)&Values[Offset][0]); imp0 = _mm_movehl_ps(imp0, imp0); vals = _mm_add_ps(imp0, vals); - _mm_storel_pi((__m64*)&Values[off][0], vals); + _mm_storel_pi((__m64*)&Values[Offset][0], vals); } else { - ALsizei count{mini(IrSize, HRIR_LENGTH - off)}; + ALsizei count{mini(IrSize, HRIR_LENGTH - Offset)}; ASSUME(count >= 2); for(ALsizei i{0};;) @@ -136,14 +136,14 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (&Values)[HRIR_LENGTH][2] for(;i < count;i += 2) { coeffs = _mm_load_ps(&Coeffs[i][0]); - vals = _mm_load_ps(&Values[off][0]); + vals = _mm_load_ps(&Values[Offset][0]); vals = _mm_add_ps(vals, _mm_mul_ps(lrlr, coeffs)); - _mm_store_ps(&Values[off][0], vals); - off += 2; + _mm_store_ps(&Values[Offset][0], vals); + Offset += 2; } if(i >= IrSize) break; - off = 0; + Offset = 0; count = IrSize; } } diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 4fcc4c9c..08e6319e 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -280,12 +280,12 @@ using RowMixerFunc = void(*)(ALfloat *OutBuffer, const ALfloat *gains, const ALfloat (*RESTRICT data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize); using HrtfMixerFunc = void(*)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, - MixHrtfParams *hrtfparams, HrtfState *hrtfstate, ALsizei BufferSize); + const ALfloat *data, ALsizei Offset, const ALsizei OutPos, const ALsizei IrSize, + MixHrtfParams *hrtfparams, HrtfState *hrtfstate, const ALsizei BufferSize); using HrtfMixerBlendFunc = void(*)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, + const ALfloat *data, ALsizei Offset, const ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, HrtfState *hrtfstate, - ALsizei BufferSize); + const ALsizei BufferSize); using HrtfDirectMixerFunc = void(*)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, DirectHrtfState *State, const ALsizei Chan, const ALsizei BufferSize); -- cgit v1.2.3 From d8eecc89e0dfd4441f2d47e274c98b184a9bb4f0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 31 Dec 2018 18:07:00 -0800 Subject: Pass a reference to an array instead of a pointer --- OpenAL32/Include/alu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 08e6319e..f575ba52 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -415,7 +415,7 @@ void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALf * vector must be normalized (unit length), and the spread is the angular width * of the sound (0...tau). */ -inline void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat (&coeffs)[MAX_AMBI_COEFFS]) +inline void CalcDirectionCoeffs(const ALfloat (&dir)[3], ALfloat spread, ALfloat (&coeffs)[MAX_AMBI_COEFFS]) { /* Convert from OpenAL coords to Ambisonics. */ CalcAmbiCoeffs(-dir[0], dir[1], -dir[2], spread, coeffs); -- cgit v1.2.3 From 4c4572ae8a54f4aefd76c1db0b576f6ae37339a0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 31 Dec 2018 18:23:30 -0800 Subject: Compile makehrtf as C++ --- CMakeLists.txt | 2 +- common/win_main_utf8.h | 4 +- utils/makehrtf.c | 3455 ------------------------------------------------ utils/makehrtf.cpp | 3455 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 3458 insertions(+), 3458 deletions(-) delete mode 100644 utils/makehrtf.c create mode 100644 utils/makehrtf.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b2be332..f0161048 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1514,7 +1514,7 @@ IF(ALSOFT_UTILS) TARGET_COMPILE_OPTIONS(openal-info PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(openal-info PRIVATE ${LINKER_FLAGS} OpenAL) - SET(MAKEHRTF_SRCS utils/makehrtf.c) + SET(MAKEHRTF_SRCS utils/makehrtf.cpp) IF(NOT HAVE_GETOPT) SET(MAKEHRTF_SRCS ${MAKEHRTF_SRCS} utils/getopt.c utils/getopt.h) ENDIF() diff --git a/common/win_main_utf8.h b/common/win_main_utf8.h index faddc257..242d3b8a 100644 --- a/common/win_main_utf8.h +++ b/common/win_main_utf8.h @@ -30,7 +30,7 @@ static FILE *my_fopen(const char *fname, const char *mode) return NULL; } - wname = calloc(sizeof(WCHAR), namelen+modelen); + wname = (WCHAR*)calloc(sizeof(WCHAR), namelen+modelen); wmode = wname + namelen; MultiByteToWideChar(CP_UTF8, 0, fname, -1, wname, namelen); MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, modelen); @@ -73,7 +73,7 @@ static void GetUnicodeArgs(int *argc, char ***argv) total += WideCharToMultiByte(CP_UTF8, 0, args[i], -1, NULL, 0, NULL, NULL); atexit(cleanup_arglist); - arglist = *argv = calloc(1, total); + arglist = *argv = (char**)calloc(1, total); (*argv)[0] = (char*)(*argv + nargs); for(i = 0;i < nargs-1;i++) { diff --git a/utils/makehrtf.c b/utils/makehrtf.c deleted file mode 100644 index eb174c8a..00000000 --- a/utils/makehrtf.c +++ /dev/null @@ -1,3455 +0,0 @@ -/* - * HRTF utility for producing and demonstrating the process of creating an - * OpenAL Soft compatible HRIR data set. - * - * Copyright (C) 2011-2017 Christopher Fitzgerald - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Or visit: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * - * -------------------------------------------------------------------------- - * - * A big thanks goes out to all those whose work done in the field of - * binaural sound synthesis using measured HRTFs makes this utility and the - * OpenAL Soft implementation possible. - * - * The algorithm for diffuse-field equalization was adapted from the work - * done by Rio Emmanuel and Larcher Veronique of IRCAM and Bill Gardner of - * MIT Media Laboratory. It operates as follows: - * - * 1. Take the FFT of each HRIR and only keep the magnitude responses. - * 2. Calculate the diffuse-field power-average of all HRIRs weighted by - * their contribution to the total surface area covered by their - * measurement. - * 3. Take the diffuse-field average and limit its magnitude range. - * 4. Equalize the responses by using the inverse of the diffuse-field - * average. - * 5. Reconstruct the minimum-phase responses. - * 5. Zero the DC component. - * 6. IFFT the result and truncate to the desired-length minimum-phase FIR. - * - * The spherical head algorithm for calculating propagation delay was adapted - * from the paper: - * - * Modeling Interaural Time Difference Assuming a Spherical Head - * Joel David Miller - * Music 150, Musical Acoustics, Stanford University - * December 2, 2001 - * - * The formulae for calculating the Kaiser window metrics are from the - * the textbook: - * - * Discrete-Time Signal Processing - * Alan V. Oppenheim and Ronald W. Schafer - * Prentice-Hall Signal Processing Series - * 1999 - */ - -#include "config.h" - -#define _UNICODE -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_STRINGS_H -#include -#endif -#ifdef HAVE_GETOPT -#include -#else -#include "getopt.h" -#endif - -#include "win_main_utf8.h" - -/* Define int64_t and uint64_t types */ -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -#include -#elif defined(_WIN32) && defined(__GNUC__) -#include -#elif defined(_WIN32) -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#else -/* Fallback if nothing above works */ -#include -#endif - -#ifndef M_PI -#define M_PI (3.14159265358979323846) -#endif - -#ifndef HUGE_VAL -#define HUGE_VAL (1.0 / 0.0) -#endif - - -// The epsilon used to maintain signal stability. -#define EPSILON (1e-9) - -// Constants for accessing the token reader's ring buffer. -#define TR_RING_BITS (16) -#define TR_RING_SIZE (1 << TR_RING_BITS) -#define TR_RING_MASK (TR_RING_SIZE - 1) - -// The token reader's load interval in bytes. -#define TR_LOAD_SIZE (TR_RING_SIZE >> 2) - -// The maximum identifier length used when processing the data set -// definition. -#define MAX_IDENT_LEN (16) - -// The maximum path length used when processing filenames. -#define MAX_PATH_LEN (256) - -// The limits for the sample 'rate' metric in the data set definition and for -// resampling. -#define MIN_RATE (32000) -#define MAX_RATE (96000) - -// The limits for the HRIR 'points' metric in the data set definition. -#define MIN_POINTS (16) -#define MAX_POINTS (8192) - -// The limit to the number of 'distances' listed in the data set definition. -#define MAX_FD_COUNT (16) - -// The limits to the number of 'azimuths' listed in the data set definition. -#define MIN_EV_COUNT (5) -#define MAX_EV_COUNT (128) - -// The limits for each of the 'azimuths' listed in the data set definition. -#define MIN_AZ_COUNT (1) -#define MAX_AZ_COUNT (128) - -// The limits for the listener's head 'radius' in the data set definition. -#define MIN_RADIUS (0.05) -#define MAX_RADIUS (0.15) - -// The limits for the 'distance' from source to listener for each field in -// the definition file. -#define MIN_DISTANCE (0.05) -#define MAX_DISTANCE (2.50) - -// The maximum number of channels that can be addressed for a WAVE file -// source listed in the data set definition. -#define MAX_WAVE_CHANNELS (65535) - -// The limits to the byte size for a binary source listed in the definition -// file. -#define MIN_BIN_SIZE (2) -#define MAX_BIN_SIZE (4) - -// The minimum number of significant bits for binary sources listed in the -// data set definition. The maximum is calculated from the byte size. -#define MIN_BIN_BITS (16) - -// The limits to the number of significant bits for an ASCII source listed in -// the data set definition. -#define MIN_ASCII_BITS (16) -#define MAX_ASCII_BITS (32) - -// The limits to the FFT window size override on the command line. -#define MIN_FFTSIZE (65536) -#define MAX_FFTSIZE (131072) - -// The limits to the equalization range limit on the command line. -#define MIN_LIMIT (2.0) -#define MAX_LIMIT (120.0) - -// The limits to the truncation window size on the command line. -#define MIN_TRUNCSIZE (16) -#define MAX_TRUNCSIZE (512) - -// The limits to the custom head radius on the command line. -#define MIN_CUSTOM_RADIUS (0.05) -#define MAX_CUSTOM_RADIUS (0.15) - -// The truncation window size must be a multiple of the below value to allow -// for vectorized convolution. -#define MOD_TRUNCSIZE (8) - -// The defaults for the command line options. -#define DEFAULT_FFTSIZE (65536) -#define DEFAULT_EQUALIZE (1) -#define DEFAULT_SURFACE (1) -#define DEFAULT_LIMIT (24.0) -#define DEFAULT_TRUNCSIZE (32) -#define DEFAULT_HEAD_MODEL (HM_DATASET) -#define DEFAULT_CUSTOM_RADIUS (0.0) - -// The four-character-codes for RIFF/RIFX WAVE file chunks. -#define FOURCC_RIFF (0x46464952) // 'RIFF' -#define FOURCC_RIFX (0x58464952) // 'RIFX' -#define FOURCC_WAVE (0x45564157) // 'WAVE' -#define FOURCC_FMT (0x20746D66) // 'fmt ' -#define FOURCC_DATA (0x61746164) // 'data' -#define FOURCC_LIST (0x5453494C) // 'LIST' -#define FOURCC_WAVL (0x6C766177) // 'wavl' -#define FOURCC_SLNT (0x746E6C73) // 'slnt' - -// The supported wave formats. -#define WAVE_FORMAT_PCM (0x0001) -#define WAVE_FORMAT_IEEE_FLOAT (0x0003) -#define WAVE_FORMAT_EXTENSIBLE (0xFFFE) - -// The maximum propagation delay value supported by OpenAL Soft. -#define MAX_HRTD (63.0) - -// The OpenAL Soft HRTF format marker. It stands for minimum-phase head -// response protocol 02. -#define MHR_FORMAT ("MinPHR02") - -// Sample and channel type enum values. -typedef enum SampleTypeT { - ST_S16 = 0, - ST_S24 = 1 -} SampleTypeT; - -// Certain iterations rely on these integer enum values. -typedef enum ChannelTypeT { - CT_NONE = -1, - CT_MONO = 0, - CT_STEREO = 1 -} ChannelTypeT; - -// Byte order for the serialization routines. -typedef enum ByteOrderT { - BO_NONE, - BO_LITTLE, - BO_BIG -} ByteOrderT; - -// Source format for the references listed in the data set definition. -typedef enum SourceFormatT { - SF_NONE, - SF_WAVE, // RIFF/RIFX WAVE file. - SF_BIN_LE, // Little-endian binary file. - SF_BIN_BE, // Big-endian binary file. - SF_ASCII // ASCII text file. -} SourceFormatT; - -// Element types for the references listed in the data set definition. -typedef enum ElementTypeT { - ET_NONE, - ET_INT, // Integer elements. - ET_FP // Floating-point elements. -} ElementTypeT; - -// Head model used for calculating the impulse delays. -typedef enum HeadModelT { - HM_NONE, - HM_DATASET, // Measure the onset from the dataset. - HM_SPHERE // Calculate the onset using a spherical head model. -} HeadModelT; - -// Unsigned integer type. -typedef unsigned int uint; - -// Serialization types. The trailing digit indicates the number of bits. -typedef unsigned char uint8; -typedef int int32; -typedef unsigned int uint32; -typedef uint64_t uint64; - -// Token reader state for parsing the data set definition. -typedef struct TokenReaderT { - FILE *mFile; - const char *mName; - uint mLine; - uint mColumn; - char mRing[TR_RING_SIZE]; - size_t mIn; - size_t mOut; -} TokenReaderT; - -// Source reference state used when loading sources. -typedef struct SourceRefT { - SourceFormatT mFormat; - ElementTypeT mType; - uint mSize; - int mBits; - uint mChannel; - uint mSkip; - uint mOffset; - char mPath[MAX_PATH_LEN+1]; -} SourceRefT; - -// Structured HRIR storage for stereo azimuth pairs, elevations, and fields. -typedef struct HrirAzT { - double mAzimuth; - uint mIndex; - double mDelays[2]; - double *mIrs[2]; -} HrirAzT; - -typedef struct HrirEvT { - double mElevation; - uint mIrCount; - uint mAzCount; - HrirAzT *mAzs; -} HrirEvT; - -typedef struct HrirFdT { - double mDistance; - uint mIrCount; - uint mEvCount; - uint mEvStart; - HrirEvT *mEvs; -} HrirFdT; - -// The HRIR metrics and data set used when loading, processing, and storing -// the resulting HRTF. -typedef struct HrirDataT { - uint mIrRate; - SampleTypeT mSampleType; - ChannelTypeT mChannelType; - uint mIrPoints; - uint mFftSize; - uint mIrSize; - double mRadius; - uint mIrCount; - uint mFdCount; - HrirFdT *mFds; -} HrirDataT; - -// The resampler metrics and FIR filter. -typedef struct ResamplerT { - uint mP, mQ, mM, mL; - double *mF; -} ResamplerT; - - -/**************************************** - *** Complex number type and routines *** - ****************************************/ - -typedef struct { - double Real, Imag; -} Complex; - -static Complex MakeComplex(double r, double i) -{ - Complex c = { r, i }; - return c; -} - -static Complex c_add(Complex a, Complex b) -{ - Complex r; - r.Real = a.Real + b.Real; - r.Imag = a.Imag + b.Imag; - return r; -} - -static Complex c_sub(Complex a, Complex b) -{ - Complex r; - r.Real = a.Real - b.Real; - r.Imag = a.Imag - b.Imag; - return r; -} - -static Complex c_mul(Complex a, Complex b) -{ - Complex r; - r.Real = a.Real*b.Real - a.Imag*b.Imag; - r.Imag = a.Imag*b.Real + a.Real*b.Imag; - return r; -} - -static Complex c_muls(Complex a, double s) -{ - Complex r; - r.Real = a.Real * s; - r.Imag = a.Imag * s; - return r; -} - -static double c_abs(Complex a) -{ - return sqrt(a.Real*a.Real + a.Imag*a.Imag); -} - -static Complex c_exp(Complex a) -{ - Complex r; - double e = exp(a.Real); - r.Real = e * cos(a.Imag); - r.Imag = e * sin(a.Imag); - return r; -} - -/***************************** - *** Token reader routines *** - *****************************/ - -/* Whitespace is not significant. It can process tokens as identifiers, numbers - * (integer and floating-point), strings, and operators. Strings must be - * encapsulated by double-quotes and cannot span multiple lines. - */ - -// Setup the reader on the given file. The filename can be NULL if no error -// output is desired. -static void TrSetup(FILE *fp, const char *filename, TokenReaderT *tr) -{ - const char *name = NULL; - - if(filename) - { - const char *slash = strrchr(filename, '/'); - if(slash) - { - const char *bslash = strrchr(slash+1, '\\'); - if(bslash) name = bslash+1; - else name = slash+1; - } - else - { - const char *bslash = strrchr(filename, '\\'); - if(bslash) name = bslash+1; - else name = filename; - } - } - - tr->mFile = fp; - tr->mName = name; - tr->mLine = 1; - tr->mColumn = 1; - tr->mIn = 0; - tr->mOut = 0; -} - -// Prime the reader's ring buffer, and return a result indicating that there -// is text to process. -static int TrLoad(TokenReaderT *tr) -{ - size_t toLoad, in, count; - - toLoad = TR_RING_SIZE - (tr->mIn - tr->mOut); - if(toLoad >= TR_LOAD_SIZE && !feof(tr->mFile)) - { - // Load TR_LOAD_SIZE (or less if at the end of the file) per read. - toLoad = TR_LOAD_SIZE; - in = tr->mIn&TR_RING_MASK; - count = TR_RING_SIZE - in; - if(count < toLoad) - { - tr->mIn += fread(&tr->mRing[in], 1, count, tr->mFile); - tr->mIn += fread(&tr->mRing[0], 1, toLoad-count, tr->mFile); - } - else - tr->mIn += fread(&tr->mRing[in], 1, toLoad, tr->mFile); - - if(tr->mOut >= TR_RING_SIZE) - { - tr->mOut -= TR_RING_SIZE; - tr->mIn -= TR_RING_SIZE; - } - } - if(tr->mIn > tr->mOut) - return 1; - return 0; -} - -// Error display routine. Only displays when the base name is not NULL. -static void TrErrorVA(const TokenReaderT *tr, uint line, uint column, const char *format, va_list argPtr) -{ - if(!tr->mName) - return; - fprintf(stderr, "Error (%s:%u:%u): ", tr->mName, line, column); - vfprintf(stderr, format, argPtr); -} - -// Used to display an error at a saved line/column. -static void TrErrorAt(const TokenReaderT *tr, uint line, uint column, const char *format, ...) -{ - va_list argPtr; - - va_start(argPtr, format); - TrErrorVA(tr, line, column, format, argPtr); - va_end(argPtr); -} - -// Used to display an error at the current line/column. -static void TrError(const TokenReaderT *tr, const char *format, ...) -{ - va_list argPtr; - - va_start(argPtr, format); - TrErrorVA(tr, tr->mLine, tr->mColumn, format, argPtr); - va_end(argPtr); -} - -// Skips to the next line. -static void TrSkipLine(TokenReaderT *tr) -{ - char ch; - - while(TrLoad(tr)) - { - ch = tr->mRing[tr->mOut&TR_RING_MASK]; - tr->mOut++; - if(ch == '\n') - { - tr->mLine++; - tr->mColumn = 1; - break; - } - tr->mColumn ++; - } -} - -// Skips to the next token. -static int TrSkipWhitespace(TokenReaderT *tr) -{ - char ch; - - while(TrLoad(tr)) - { - ch = tr->mRing[tr->mOut&TR_RING_MASK]; - if(isspace(ch)) - { - tr->mOut++; - if(ch == '\n') - { - tr->mLine++; - tr->mColumn = 1; - } - else - tr->mColumn++; - } - else if(ch == '#') - TrSkipLine(tr); - else - return 1; - } - return 0; -} - -// Get the line and/or column of the next token (or the end of input). -static void TrIndication(TokenReaderT *tr, uint *line, uint *column) -{ - TrSkipWhitespace(tr); - if(line) *line = tr->mLine; - if(column) *column = tr->mColumn; -} - -// Checks to see if a token is (likely to be) an identifier. It does not -// display any errors and will not proceed to the next token. -static int TrIsIdent(TokenReaderT *tr) -{ - char ch; - - if(!TrSkipWhitespace(tr)) - return 0; - ch = tr->mRing[tr->mOut&TR_RING_MASK]; - return ch == '_' || isalpha(ch); -} - - -// Checks to see if a token is the given operator. It does not display any -// errors and will not proceed to the next token. -static int TrIsOperator(TokenReaderT *tr, const char *op) -{ - size_t out, len; - char ch; - - if(!TrSkipWhitespace(tr)) - return 0; - out = tr->mOut; - len = 0; - while(op[len] != '\0' && out < tr->mIn) - { - ch = tr->mRing[out&TR_RING_MASK]; - if(ch != op[len]) break; - len++; - out++; - } - if(op[len] == '\0') - return 1; - return 0; -} - -/* The TrRead*() routines obtain the value of a matching token type. They - * display type, form, and boundary errors and will proceed to the next - * token. - */ - -// Reads and validates an identifier token. -static int TrReadIdent(TokenReaderT *tr, const uint maxLen, char *ident) -{ - uint col, len; - char ch; - - col = tr->mColumn; - if(TrSkipWhitespace(tr)) - { - col = tr->mColumn; - ch = tr->mRing[tr->mOut&TR_RING_MASK]; - if(ch == '_' || isalpha(ch)) - { - len = 0; - do { - if(len < maxLen) - ident[len] = ch; - len++; - tr->mOut++; - if(!TrLoad(tr)) - break; - ch = tr->mRing[tr->mOut&TR_RING_MASK]; - } while(ch == '_' || isdigit(ch) || isalpha(ch)); - - tr->mColumn += len; - if(len < maxLen) - { - ident[len] = '\0'; - return 1; - } - TrErrorAt(tr, tr->mLine, col, "Identifier is too long.\n"); - return 0; - } - } - TrErrorAt(tr, tr->mLine, col, "Expected an identifier.\n"); - return 0; -} - -// Reads and validates (including bounds) an integer token. -static int TrReadInt(TokenReaderT *tr, const int loBound, const int hiBound, int *value) -{ - uint col, digis, len; - char ch, temp[64+1]; - - col = tr->mColumn; - if(TrSkipWhitespace(tr)) - { - col = tr->mColumn; - len = 0; - ch = tr->mRing[tr->mOut&TR_RING_MASK]; - if(ch == '+' || ch == '-') - { - temp[len] = ch; - len++; - tr->mOut++; - } - digis = 0; - while(TrLoad(tr)) - { - ch = tr->mRing[tr->mOut&TR_RING_MASK]; - if(!isdigit(ch)) break; - if(len < 64) - temp[len] = ch; - len++; - digis++; - tr->mOut++; - } - tr->mColumn += len; - if(digis > 0 && ch != '.' && !isalpha(ch)) - { - if(len > 64) - { - TrErrorAt(tr, tr->mLine, col, "Integer is too long."); - return 0; - } - temp[len] = '\0'; - *value = strtol(temp, NULL, 10); - if(*value < loBound || *value > hiBound) - { - TrErrorAt(tr, tr->mLine, col, "Expected a value from %d to %d.\n", loBound, hiBound); - return 0; - } - return 1; - } - } - TrErrorAt(tr, tr->mLine, col, "Expected an integer.\n"); - return 0; -} - -// Reads and validates (including bounds) a float token. -static int TrReadFloat(TokenReaderT *tr, const double loBound, const double hiBound, double *value) -{ - uint col, digis, len; - char ch, temp[64+1]; - - col = tr->mColumn; - if(TrSkipWhitespace(tr)) - { - col = tr->mColumn; - len = 0; - ch = tr->mRing[tr->mOut&TR_RING_MASK]; - if(ch == '+' || ch == '-') - { - temp[len] = ch; - len++; - tr->mOut++; - } - - digis = 0; - while(TrLoad(tr)) - { - ch = tr->mRing[tr->mOut&TR_RING_MASK]; - if(!isdigit(ch)) break; - if(len < 64) - temp[len] = ch; - len++; - digis++; - tr->mOut++; - } - if(ch == '.') - { - if(len < 64) - temp[len] = ch; - len++; - tr->mOut++; - } - while(TrLoad(tr)) - { - ch = tr->mRing[tr->mOut&TR_RING_MASK]; - if(!isdigit(ch)) break; - if(len < 64) - temp[len] = ch; - len++; - digis++; - tr->mOut++; - } - if(digis > 0) - { - if(ch == 'E' || ch == 'e') - { - if(len < 64) - temp[len] = ch; - len++; - digis = 0; - tr->mOut++; - if(ch == '+' || ch == '-') - { - if(len < 64) - temp[len] = ch; - len++; - tr->mOut++; - } - while(TrLoad(tr)) - { - ch = tr->mRing[tr->mOut&TR_RING_MASK]; - if(!isdigit(ch)) break; - if(len < 64) - temp[len] = ch; - len++; - digis++; - tr->mOut++; - } - } - tr->mColumn += len; - if(digis > 0 && ch != '.' && !isalpha(ch)) - { - if(len > 64) - { - TrErrorAt(tr, tr->mLine, col, "Float is too long."); - return 0; - } - temp[len] = '\0'; - *value = strtod(temp, NULL); - if(*value < loBound || *value > hiBound) - { - TrErrorAt(tr, tr->mLine, col, "Expected a value from %f to %f.\n", loBound, hiBound); - return 0; - } - return 1; - } - } - else - tr->mColumn += len; - } - TrErrorAt(tr, tr->mLine, col, "Expected a float.\n"); - return 0; -} - -// Reads and validates a string token. -static int TrReadString(TokenReaderT *tr, const uint maxLen, char *text) -{ - uint col, len; - char ch; - - col = tr->mColumn; - if(TrSkipWhitespace(tr)) - { - col = tr->mColumn; - ch = tr->mRing[tr->mOut&TR_RING_MASK]; - if(ch == '\"') - { - tr->mOut++; - len = 0; - while(TrLoad(tr)) - { - ch = tr->mRing[tr->mOut&TR_RING_MASK]; - tr->mOut++; - if(ch == '\"') - break; - if(ch == '\n') - { - TrErrorAt(tr, tr->mLine, col, "Unterminated string at end of line.\n"); - return 0; - } - if(len < maxLen) - text[len] = ch; - len++; - } - if(ch != '\"') - { - tr->mColumn += 1 + len; - TrErrorAt(tr, tr->mLine, col, "Unterminated string at end of input.\n"); - return 0; - } - tr->mColumn += 2 + len; - if(len > maxLen) - { - TrErrorAt(tr, tr->mLine, col, "String is too long.\n"); - return 0; - } - text[len] = '\0'; - return 1; - } - } - TrErrorAt(tr, tr->mLine, col, "Expected a string.\n"); - return 0; -} - -// Reads and validates the given operator. -static int TrReadOperator(TokenReaderT *tr, const char *op) -{ - uint col, len; - char ch; - - col = tr->mColumn; - if(TrSkipWhitespace(tr)) - { - col = tr->mColumn; - len = 0; - while(op[len] != '\0' && TrLoad(tr)) - { - ch = tr->mRing[tr->mOut&TR_RING_MASK]; - if(ch != op[len]) break; - len++; - tr->mOut++; - } - tr->mColumn += len; - if(op[len] == '\0') - return 1; - } - TrErrorAt(tr, tr->mLine, col, "Expected '%s' operator.\n", op); - return 0; -} - -/* Performs a string substitution. Any case-insensitive occurrences of the - * pattern string are replaced with the replacement string. The result is - * truncated if necessary. - */ -static int StrSubst(const char *in, const char *pat, const char *rep, const size_t maxLen, char *out) -{ - size_t inLen, patLen, repLen; - size_t si, di; - int truncated; - - inLen = strlen(in); - patLen = strlen(pat); - repLen = strlen(rep); - si = 0; - di = 0; - truncated = 0; - while(si < inLen && di < maxLen) - { - if(patLen <= inLen-si) - { - if(strncasecmp(&in[si], pat, patLen) == 0) - { - if(repLen > maxLen-di) - { - repLen = maxLen - di; - truncated = 1; - } - strncpy(&out[di], rep, repLen); - si += patLen; - di += repLen; - } - } - out[di] = in[si]; - si++; - di++; - } - if(si < inLen) - truncated = 1; - out[di] = '\0'; - return !truncated; -} - - -/********************* - *** Math routines *** - *********************/ - -// Provide missing math routines for MSVC versions < 1800 (Visual Studio 2013). -#if defined(_MSC_VER) && _MSC_VER < 1800 -static double round(double val) -{ - if(val < 0.0) - return ceil(val-0.5); - return floor(val+0.5); -} - -static double fmin(double a, double b) -{ - return (ab) ? a : b; -} -#endif - -// Simple clamp routine. -static double Clamp(const double val, const double lower, const double upper) -{ - return fmin(fmax(val, lower), upper); -} - -// Performs linear interpolation. -static double Lerp(const double a, const double b, const double f) -{ - return a + f * (b - a); -} - -static inline uint dither_rng(uint *seed) -{ - *seed = *seed * 96314165 + 907633515; - return *seed; -} - -// Performs a triangular probability density function dither. The input samples -// should be normalized (-1 to +1). -static void TpdfDither(double *RESTRICT out, const double *RESTRICT in, const double scale, - const int count, const int step, uint *seed) -{ - static const double PRNG_SCALE = 1.0 / UINT_MAX; - uint prn0, prn1; - int i; - - for(i = 0;i < count;i++) - { - prn0 = dither_rng(seed); - prn1 = dither_rng(seed); - out[i*step] = round(in[i]*scale + (prn0*PRNG_SCALE - prn1*PRNG_SCALE)); - } -} - -// Allocates an array of doubles. -static double *CreateDoubles(size_t n) -{ - double *a; - - a = calloc(n?n:1, sizeof(*a)); - if(a == NULL) - { - fprintf(stderr, "Error: Out of memory.\n"); - exit(-1); - } - return a; -} - -// Allocates an array of complex numbers. -static Complex *CreateComplexes(size_t n) -{ - Complex *a; - - a = calloc(n?n:1, sizeof(*a)); - if(a == NULL) - { - fprintf(stderr, "Error: Out of memory.\n"); - exit(-1); - } - return a; -} - -/* Fast Fourier transform routines. The number of points must be a power of - * two. - */ - -// Performs bit-reversal ordering. -static void FftArrange(const uint n, Complex *inout) -{ - uint rk, k, m; - - // Handle in-place arrangement. - rk = 0; - for(k = 0;k < n;k++) - { - if(rk > k) - { - Complex temp = inout[rk]; - inout[rk] = inout[k]; - inout[k] = temp; - } - - m = n; - while(rk&(m >>= 1)) - rk &= ~m; - rk |= m; - } -} - -// Performs the summation. -static void FftSummation(const int n, const double s, Complex *cplx) -{ - double pi; - int m, m2; - int i, k, mk; - - pi = s * M_PI; - for(m = 1, m2 = 2;m < n; m <<= 1, m2 <<= 1) - { - // v = Complex (-2.0 * sin (0.5 * pi / m) * sin (0.5 * pi / m), -sin (pi / m)) - double sm = sin(0.5 * pi / m); - Complex v = MakeComplex(-2.0*sm*sm, -sin(pi / m)); - Complex w = MakeComplex(1.0, 0.0); - for(i = 0;i < m;i++) - { - for(k = i;k < n;k += m2) - { - Complex t; - mk = k + m; - t = c_mul(w, cplx[mk]); - cplx[mk] = c_sub(cplx[k], t); - cplx[k] = c_add(cplx[k], t); - } - w = c_add(w, c_mul(v, w)); - } - } -} - -// Performs a forward FFT. -static void FftForward(const uint n, Complex *inout) -{ - FftArrange(n, inout); - FftSummation(n, 1.0, inout); -} - -// Performs an inverse FFT. -static void FftInverse(const uint n, Complex *inout) -{ - double f; - uint i; - - FftArrange(n, inout); - FftSummation(n, -1.0, inout); - f = 1.0 / n; - for(i = 0;i < n;i++) - inout[i] = c_muls(inout[i], f); -} - -/* Calculate the complex helical sequence (or discrete-time analytical signal) - * of the given input using the Hilbert transform. Given the natural logarithm - * of a signal's magnitude response, the imaginary components can be used as - * the angles for minimum-phase reconstruction. - */ -static void Hilbert(const uint n, Complex *inout) -{ - uint i; - - // Handle in-place operation. - for(i = 0;i < n;i++) - inout[i].Imag = 0.0; - - FftInverse(n, inout); - for(i = 1;i < (n+1)/2;i++) - inout[i] = c_muls(inout[i], 2.0); - /* Increment i if n is even. */ - i += (n&1)^1; - for(;i < n;i++) - inout[i] = MakeComplex(0.0, 0.0); - FftForward(n, inout); -} - -/* Calculate the magnitude response of the given input. This is used in - * place of phase decomposition, since the phase residuals are discarded for - * minimum phase reconstruction. The mirrored half of the response is also - * discarded. - */ -static void MagnitudeResponse(const uint n, const Complex *in, double *out) -{ - const uint m = 1 + (n / 2); - uint i; - for(i = 0;i < m;i++) - out[i] = fmax(c_abs(in[i]), EPSILON); -} - -/* Apply a range limit (in dB) to the given magnitude response. This is used - * to adjust the effects of the diffuse-field average on the equalization - * process. - */ -static void LimitMagnitudeResponse(const uint n, const uint m, const double limit, const double *in, double *out) -{ - double halfLim; - uint i, lower, upper; - double ave; - - halfLim = limit / 2.0; - // Convert the response to dB. - for(i = 0;i < m;i++) - out[i] = 20.0 * log10(in[i]); - // Use six octaves to calculate the average magnitude of the signal. - lower = ((uint)ceil(n / pow(2.0, 8.0))) - 1; - upper = ((uint)floor(n / pow(2.0, 2.0))) - 1; - ave = 0.0; - for(i = lower;i <= upper;i++) - ave += out[i]; - ave /= upper - lower + 1; - // Keep the response within range of the average magnitude. - for(i = 0;i < m;i++) - out[i] = Clamp(out[i], ave - halfLim, ave + halfLim); - // Convert the response back to linear magnitude. - for(i = 0;i < m;i++) - out[i] = pow(10.0, out[i] / 20.0); -} - -/* Reconstructs the minimum-phase component for the given magnitude response - * of a signal. This is equivalent to phase recomposition, sans the missing - * residuals (which were discarded). The mirrored half of the response is - * reconstructed. - */ -static void MinimumPhase(const uint n, const double *in, Complex *out) -{ - const uint m = 1 + (n / 2); - double *mags; - uint i; - - mags = CreateDoubles(n); - for(i = 0;i < m;i++) - { - mags[i] = fmax(EPSILON, in[i]); - out[i] = MakeComplex(log(mags[i]), 0.0); - } - for(;i < n;i++) - { - mags[i] = mags[n - i]; - out[i] = out[n - i]; - } - Hilbert(n, out); - // Remove any DC offset the filter has. - mags[0] = EPSILON; - for(i = 0;i < n;i++) - { - Complex a = c_exp(MakeComplex(0.0, out[i].Imag)); - out[i] = c_mul(MakeComplex(mags[i], 0.0), a); - } - free(mags); -} - - -/*************************** - *** Resampler functions *** - ***************************/ - -/* This is the normalized cardinal sine (sinc) function. - * - * sinc(x) = { 1, x = 0 - * { sin(pi x) / (pi x), otherwise. - */ -static double Sinc(const double x) -{ - if(fabs(x) < EPSILON) - return 1.0; - return sin(M_PI * x) / (M_PI * x); -} - -/* The zero-order modified Bessel function of the first kind, used for the - * Kaiser window. - * - * I_0(x) = sum_{k=0}^inf (1 / k!)^2 (x / 2)^(2 k) - * = sum_{k=0}^inf ((x / 2)^k / k!)^2 - */ -static double BesselI_0(const double x) -{ - double term, sum, x2, y, last_sum; - int k; - - // Start at k=1 since k=0 is trivial. - term = 1.0; - sum = 1.0; - x2 = x/2.0; - k = 1; - - // Let the integration converge until the term of the sum is no longer - // significant. - do { - y = x2 / k; - k++; - last_sum = sum; - term *= y * y; - sum += term; - } while(sum != last_sum); - return sum; -} - -/* Calculate a Kaiser window from the given beta value and a normalized k - * [-1, 1]. - * - * w(k) = { I_0(B sqrt(1 - k^2)) / I_0(B), -1 <= k <= 1 - * { 0, elsewhere. - * - * Where k can be calculated as: - * - * k = i / l, where -l <= i <= l. - * - * or: - * - * k = 2 i / M - 1, where 0 <= i <= M. - */ -static double Kaiser(const double b, const double k) -{ - if(!(k >= -1.0 && k <= 1.0)) - return 0.0; - return BesselI_0(b * sqrt(1.0 - k*k)) / BesselI_0(b); -} - -// Calculates the greatest common divisor of a and b. -static uint Gcd(uint x, uint y) -{ - while(y > 0) - { - uint z = y; - y = x % y; - x = z; - } - return x; -} - -/* Calculates the size (order) of the Kaiser window. Rejection is in dB and - * the transition width is normalized frequency (0.5 is nyquist). - * - * M = { ceil((r - 7.95) / (2.285 2 pi f_t)), r > 21 - * { ceil(5.79 / 2 pi f_t), r <= 21. - * - */ -static uint CalcKaiserOrder(const double rejection, const double transition) -{ - double w_t = 2.0 * M_PI * transition; - if(rejection > 21.0) - return (uint)ceil((rejection - 7.95) / (2.285 * w_t)); - return (uint)ceil(5.79 / w_t); -} - -// Calculates the beta value of the Kaiser window. Rejection is in dB. -static double CalcKaiserBeta(const double rejection) -{ - if(rejection > 50.0) - return 0.1102 * (rejection - 8.7); - if(rejection >= 21.0) - return (0.5842 * pow(rejection - 21.0, 0.4)) + - (0.07886 * (rejection - 21.0)); - return 0.0; -} - -/* Calculates a point on the Kaiser-windowed sinc filter for the given half- - * width, beta, gain, and cutoff. The point is specified in non-normalized - * samples, from 0 to M, where M = (2 l + 1). - * - * w(k) 2 p f_t sinc(2 f_t x) - * - * x -- centered sample index (i - l) - * k -- normalized and centered window index (x / l) - * w(k) -- window function (Kaiser) - * p -- gain compensation factor when sampling - * f_t -- normalized center frequency (or cutoff; 0.5 is nyquist) - */ -static double SincFilter(const int l, const double b, const double gain, const double cutoff, const int i) -{ - return Kaiser(b, (double)(i - l) / l) * 2.0 * gain * cutoff * Sinc(2.0 * cutoff * (i - l)); -} - -/* This is a polyphase sinc-filtered resampler. - * - * Upsample Downsample - * - * p/q = 3/2 p/q = 3/5 - * - * M-+-+-+-> M-+-+-+-> - * -------------------+ ---------------------+ - * p s * f f f f|f| | p s * f f f f f | - * | 0 * 0 0 0|0|0 | | 0 * 0 0 0 0|0| | - * v 0 * 0 0|0|0 0 | v 0 * 0 0 0|0|0 | - * s * f|f|f f f | s * f f|f|f f | - * 0 * |0|0 0 0 0 | 0 * 0|0|0 0 0 | - * --------+=+--------+ 0 * |0|0 0 0 0 | - * d . d .|d|. d . d ----------+=+--------+ - * d . . . .|d|. . . . - * q-> - * q-+-+-+-> - * - * P_f(i,j) = q i mod p + pj - * P_s(i,j) = floor(q i / p) - j - * d[i=0..N-1] = sum_{j=0}^{floor((M - 1) / p)} { - * { f[P_f(i,j)] s[P_s(i,j)], P_f(i,j) < M - * { 0, P_f(i,j) >= M. } - */ - -// Calculate the resampling metrics and build the Kaiser-windowed sinc filter -// that's used to cut frequencies above the destination nyquist. -static void ResamplerSetup(ResamplerT *rs, const uint srcRate, const uint dstRate) -{ - double cutoff, width, beta; - uint gcd, l; - int i; - - gcd = Gcd(srcRate, dstRate); - rs->mP = dstRate / gcd; - rs->mQ = srcRate / gcd; - /* The cutoff is adjusted by half the transition width, so the transition - * ends before the nyquist (0.5). Both are scaled by the downsampling - * factor. - */ - if(rs->mP > rs->mQ) - { - cutoff = 0.475 / rs->mP; - width = 0.05 / rs->mP; - } - else - { - cutoff = 0.475 / rs->mQ; - width = 0.05 / rs->mQ; - } - // A rejection of -180 dB is used for the stop band. Round up when - // calculating the left offset to avoid increasing the transition width. - l = (CalcKaiserOrder(180.0, width)+1) / 2; - beta = CalcKaiserBeta(180.0); - rs->mM = l*2 + 1; - rs->mL = l; - rs->mF = CreateDoubles(rs->mM); - for(i = 0;i < ((int)rs->mM);i++) - rs->mF[i] = SincFilter((int)l, beta, rs->mP, cutoff, i); -} - -// Clean up after the resampler. -static void ResamplerClear(ResamplerT *rs) -{ - free(rs->mF); - rs->mF = NULL; -} - -// Perform the upsample-filter-downsample resampling operation using a -// polyphase filter implementation. -static void ResamplerRun(ResamplerT *rs, const uint inN, const double *in, const uint outN, double *out) -{ - const uint p = rs->mP, q = rs->mQ, m = rs->mM, l = rs->mL; - const double *f = rs->mF; - uint j_f, j_s; - double *work; - uint i; - - if(outN == 0) - return; - - // Handle in-place operation. - if(in == out) - work = CreateDoubles(outN); - else - work = out; - // Resample the input. - for(i = 0;i < outN;i++) - { - double r = 0.0; - // Input starts at l to compensate for the filter delay. This will - // drop any build-up from the first half of the filter. - j_f = (l + (q * i)) % p; - j_s = (l + (q * i)) / p; - while(j_f < m) - { - // Only take input when 0 <= j_s < inN. This single unsigned - // comparison catches both cases. - if(j_s < inN) - r += f[j_f] * in[j_s]; - j_f += p; - j_s--; - } - work[i] = r; - } - // Clean up after in-place operation. - if(work != out) - { - for(i = 0;i < outN;i++) - out[i] = work[i]; - free(work); - } -} - -/************************* - *** File source input *** - *************************/ - -// Read a binary value of the specified byte order and byte size from a file, -// storing it as a 32-bit unsigned integer. -static int ReadBin4(FILE *fp, const char *filename, const ByteOrderT order, const uint bytes, uint32 *out) -{ - uint8 in[4]; - uint32 accum; - uint i; - - if(fread(in, 1, bytes, fp) != bytes) - { - fprintf(stderr, "Error: Bad read from file '%s'.\n", filename); - return 0; - } - accum = 0; - switch(order) - { - case BO_LITTLE: - for(i = 0;i < bytes;i++) - accum = (accum<<8) | in[bytes - i - 1]; - break; - case BO_BIG: - for(i = 0;i < bytes;i++) - accum = (accum<<8) | in[i]; - break; - default: - break; - } - *out = accum; - return 1; -} - -// Read a binary value of the specified byte order from a file, storing it as -// a 64-bit unsigned integer. -static int ReadBin8(FILE *fp, const char *filename, const ByteOrderT order, uint64 *out) -{ - uint8 in [8]; - uint64 accum; - uint i; - - if(fread(in, 1, 8, fp) != 8) - { - fprintf(stderr, "Error: Bad read from file '%s'.\n", filename); - return 0; - } - accum = 0ULL; - switch(order) - { - case BO_LITTLE: - for(i = 0;i < 8;i++) - accum = (accum<<8) | in[8 - i - 1]; - break; - case BO_BIG: - for(i = 0;i < 8;i++) - accum = (accum<<8) | in[i]; - break; - default: - break; - } - *out = accum; - return 1; -} - -/* Read a binary value of the specified type, byte order, and byte size from - * a file, converting it to a double. For integer types, the significant - * bits are used to normalize the result. The sign of bits determines - * whether they are padded toward the MSB (negative) or LSB (positive). - * Floating-point types are not normalized. - */ -static int ReadBinAsDouble(FILE *fp, const char *filename, const ByteOrderT order, const ElementTypeT type, const uint bytes, const int bits, double *out) -{ - union { - uint32 ui; - int32 i; - float f; - } v4; - union { - uint64 ui; - double f; - } v8; - - *out = 0.0; - if(bytes > 4) - { - if(!ReadBin8(fp, filename, order, &v8.ui)) - return 0; - if(type == ET_FP) - *out = v8.f; - } - else - { - if(!ReadBin4(fp, filename, order, bytes, &v4.ui)) - return 0; - if(type == ET_FP) - *out = v4.f; - else - { - if(bits > 0) - v4.ui >>= (8*bytes) - ((uint)bits); - else - v4.ui &= (0xFFFFFFFF >> (32+bits)); - - if(v4.ui&(uint)(1<<(abs(bits)-1))) - v4.ui |= (0xFFFFFFFF << abs (bits)); - *out = v4.i / (double)(1<<(abs(bits)-1)); - } - } - return 1; -} - -/* Read an ascii value of the specified type from a file, converting it to a - * double. For integer types, the significant bits are used to normalize the - * result. The sign of the bits should always be positive. This also skips - * up to one separator character before the element itself. - */ -static int ReadAsciiAsDouble(TokenReaderT *tr, const char *filename, const ElementTypeT type, const uint bits, double *out) -{ - if(TrIsOperator(tr, ",")) - TrReadOperator(tr, ","); - else if(TrIsOperator(tr, ":")) - TrReadOperator(tr, ":"); - else if(TrIsOperator(tr, ";")) - TrReadOperator(tr, ";"); - else if(TrIsOperator(tr, "|")) - TrReadOperator(tr, "|"); - - if(type == ET_FP) - { - if(!TrReadFloat(tr, -HUGE_VAL, HUGE_VAL, out)) - { - fprintf(stderr, "Error: Bad read from file '%s'.\n", filename); - return 0; - } - } - else - { - int v; - if(!TrReadInt(tr, -(1<<(bits-1)), (1<<(bits-1))-1, &v)) - { - fprintf(stderr, "Error: Bad read from file '%s'.\n", filename); - return 0; - } - *out = v / (double)((1<<(bits-1))-1); - } - return 1; -} - -// Read the RIFF/RIFX WAVE format chunk from a file, validating it against -// the source parameters and data set metrics. -static int ReadWaveFormat(FILE *fp, const ByteOrderT order, const uint hrirRate, SourceRefT *src) -{ - uint32 fourCC, chunkSize; - uint32 format, channels, rate, dummy, block, size, bits; - - chunkSize = 0; - do { - if(chunkSize > 0) - fseek (fp, (long) chunkSize, SEEK_CUR); - if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC) || - !ReadBin4(fp, src->mPath, order, 4, &chunkSize)) - return 0; - } while(fourCC != FOURCC_FMT); - if(!ReadBin4(fp, src->mPath, order, 2, &format) || - !ReadBin4(fp, src->mPath, order, 2, &channels) || - !ReadBin4(fp, src->mPath, order, 4, &rate) || - !ReadBin4(fp, src->mPath, order, 4, &dummy) || - !ReadBin4(fp, src->mPath, order, 2, &block)) - return 0; - block /= channels; - if(chunkSize > 14) - { - if(!ReadBin4(fp, src->mPath, order, 2, &size)) - return 0; - size /= 8; - if(block > size) - size = block; - } - else - size = block; - if(format == WAVE_FORMAT_EXTENSIBLE) - { - fseek(fp, 2, SEEK_CUR); - if(!ReadBin4(fp, src->mPath, order, 2, &bits)) - return 0; - if(bits == 0) - bits = 8 * size; - fseek(fp, 4, SEEK_CUR); - if(!ReadBin4(fp, src->mPath, order, 2, &format)) - return 0; - fseek(fp, (long)(chunkSize - 26), SEEK_CUR); - } - else - { - bits = 8 * size; - if(chunkSize > 14) - fseek(fp, (long)(chunkSize - 16), SEEK_CUR); - else - fseek(fp, (long)(chunkSize - 14), SEEK_CUR); - } - if(format != WAVE_FORMAT_PCM && format != WAVE_FORMAT_IEEE_FLOAT) - { - fprintf(stderr, "Error: Unsupported WAVE format in file '%s'.\n", src->mPath); - return 0; - } - if(src->mChannel >= channels) - { - fprintf(stderr, "Error: Missing source channel in WAVE file '%s'.\n", src->mPath); - return 0; - } - if(rate != hrirRate) - { - fprintf(stderr, "Error: Mismatched source sample rate in WAVE file '%s'.\n", src->mPath); - return 0; - } - if(format == WAVE_FORMAT_PCM) - { - if(size < 2 || size > 4) - { - fprintf(stderr, "Error: Unsupported sample size in WAVE file '%s'.\n", src->mPath); - return 0; - } - if(bits < 16 || bits > (8*size)) - { - fprintf (stderr, "Error: Bad significant bits in WAVE file '%s'.\n", src->mPath); - return 0; - } - src->mType = ET_INT; - } - else - { - if(size != 4 && size != 8) - { - fprintf(stderr, "Error: Unsupported sample size in WAVE file '%s'.\n", src->mPath); - return 0; - } - src->mType = ET_FP; - } - src->mSize = size; - src->mBits = (int)bits; - src->mSkip = channels; - return 1; -} - -// Read a RIFF/RIFX WAVE data chunk, converting all elements to doubles. -static int ReadWaveData(FILE *fp, const SourceRefT *src, const ByteOrderT order, const uint n, double *hrir) -{ - int pre, post, skip; - uint i; - - pre = (int)(src->mSize * src->mChannel); - post = (int)(src->mSize * (src->mSkip - src->mChannel - 1)); - skip = 0; - for(i = 0;i < n;i++) - { - skip += pre; - if(skip > 0) - fseek(fp, skip, SEEK_CUR); - if(!ReadBinAsDouble(fp, src->mPath, order, src->mType, src->mSize, src->mBits, &hrir[i])) - return 0; - skip = post; - } - if(skip > 0) - fseek(fp, skip, SEEK_CUR); - return 1; -} - -// Read the RIFF/RIFX WAVE list or data chunk, converting all elements to -// doubles. -static int ReadWaveList(FILE *fp, const SourceRefT *src, const ByteOrderT order, const uint n, double *hrir) -{ - uint32 fourCC, chunkSize, listSize, count; - uint block, skip, offset, i; - double lastSample; - - for(;;) - { - if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC) || - !ReadBin4(fp, src->mPath, order, 4, &chunkSize)) - return 0; - - if(fourCC == FOURCC_DATA) - { - block = src->mSize * src->mSkip; - count = chunkSize / block; - if(count < (src->mOffset + n)) - { - fprintf(stderr, "Error: Bad read from file '%s'.\n", src->mPath); - return 0; - } - fseek(fp, (long)(src->mOffset * block), SEEK_CUR); - if(!ReadWaveData(fp, src, order, n, &hrir[0])) - return 0; - return 1; - } - else if(fourCC == FOURCC_LIST) - { - if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC)) - return 0; - chunkSize -= 4; - if(fourCC == FOURCC_WAVL) - break; - } - if(chunkSize > 0) - fseek(fp, (long)chunkSize, SEEK_CUR); - } - listSize = chunkSize; - block = src->mSize * src->mSkip; - skip = src->mOffset; - offset = 0; - lastSample = 0.0; - while(offset < n && listSize > 8) - { - if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC) || - !ReadBin4(fp, src->mPath, order, 4, &chunkSize)) - return 0; - listSize -= 8 + chunkSize; - if(fourCC == FOURCC_DATA) - { - count = chunkSize / block; - if(count > skip) - { - fseek(fp, (long)(skip * block), SEEK_CUR); - chunkSize -= skip * block; - count -= skip; - skip = 0; - if(count > (n - offset)) - count = n - offset; - if(!ReadWaveData(fp, src, order, count, &hrir[offset])) - return 0; - chunkSize -= count * block; - offset += count; - lastSample = hrir [offset - 1]; - } - else - { - skip -= count; - count = 0; - } - } - else if(fourCC == FOURCC_SLNT) - { - if(!ReadBin4(fp, src->mPath, order, 4, &count)) - return 0; - chunkSize -= 4; - if(count > skip) - { - count -= skip; - skip = 0; - if(count > (n - offset)) - count = n - offset; - for(i = 0; i < count; i ++) - hrir[offset + i] = lastSample; - offset += count; - } - else - { - skip -= count; - count = 0; - } - } - if(chunkSize > 0) - fseek(fp, (long)chunkSize, SEEK_CUR); - } - if(offset < n) - { - fprintf(stderr, "Error: Bad read from file '%s'.\n", src->mPath); - return 0; - } - return 1; -} - -// Load a source HRIR from a RIFF/RIFX WAVE file. -static int LoadWaveSource(FILE *fp, SourceRefT *src, const uint hrirRate, const uint n, double *hrir) -{ - uint32 fourCC, dummy; - ByteOrderT order; - - if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC) || - !ReadBin4(fp, src->mPath, BO_LITTLE, 4, &dummy)) - return 0; - if(fourCC == FOURCC_RIFF) - order = BO_LITTLE; - else if(fourCC == FOURCC_RIFX) - order = BO_BIG; - else - { - fprintf(stderr, "Error: No RIFF/RIFX chunk in file '%s'.\n", src->mPath); - return 0; - } - - if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC)) - return 0; - if(fourCC != FOURCC_WAVE) - { - fprintf(stderr, "Error: Not a RIFF/RIFX WAVE file '%s'.\n", src->mPath); - return 0; - } - if(!ReadWaveFormat(fp, order, hrirRate, src)) - return 0; - if(!ReadWaveList(fp, src, order, n, hrir)) - return 0; - return 1; -} - -// Load a source HRIR from a binary file. -static int LoadBinarySource(FILE *fp, const SourceRefT *src, const ByteOrderT order, const uint n, double *hrir) -{ - uint i; - - fseek(fp, (long)src->mOffset, SEEK_SET); - for(i = 0;i < n;i++) - { - if(!ReadBinAsDouble(fp, src->mPath, order, src->mType, src->mSize, src->mBits, &hrir[i])) - return 0; - if(src->mSkip > 0) - fseek(fp, (long)src->mSkip, SEEK_CUR); - } - return 1; -} - -// Load a source HRIR from an ASCII text file containing a list of elements -// separated by whitespace or common list operators (',', ';', ':', '|'). -static int LoadAsciiSource(FILE *fp, const SourceRefT *src, const uint n, double *hrir) -{ - TokenReaderT tr; - uint i, j; - double dummy; - - TrSetup(fp, NULL, &tr); - for(i = 0;i < src->mOffset;i++) - { - if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, (uint)src->mBits, &dummy)) - return 0; - } - for(i = 0;i < n;i++) - { - if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, (uint)src->mBits, &hrir[i])) - return 0; - for(j = 0;j < src->mSkip;j++) - { - if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, (uint)src->mBits, &dummy)) - return 0; - } - } - return 1; -} - -// Load a source HRIR from a supported file type. -static int LoadSource(SourceRefT *src, const uint hrirRate, const uint n, double *hrir) -{ - int result; - FILE *fp; - - if(src->mFormat == SF_ASCII) - fp = fopen(src->mPath, "r"); - else - fp = fopen(src->mPath, "rb"); - if(fp == NULL) - { - fprintf(stderr, "Error: Could not open source file '%s'.\n", src->mPath); - return 0; - } - if(src->mFormat == SF_WAVE) - result = LoadWaveSource(fp, src, hrirRate, n, hrir); - else if(src->mFormat == SF_BIN_LE) - result = LoadBinarySource(fp, src, BO_LITTLE, n, hrir); - else if(src->mFormat == SF_BIN_BE) - result = LoadBinarySource(fp, src, BO_BIG, n, hrir); - else - result = LoadAsciiSource(fp, src, n, hrir); - fclose(fp); - return result; -} - - -/*************************** - *** File storage output *** - ***************************/ - -// Write an ASCII string to a file. -static int WriteAscii(const char *out, FILE *fp, const char *filename) -{ - size_t len; - - len = strlen(out); - if(fwrite(out, 1, len, fp) != len) - { - fclose(fp); - fprintf(stderr, "Error: Bad write to file '%s'.\n", filename); - return 0; - } - return 1; -} - -// Write a binary value of the given byte order and byte size to a file, -// loading it from a 32-bit unsigned integer. -static int WriteBin4(const ByteOrderT order, const uint bytes, const uint32 in, FILE *fp, const char *filename) -{ - uint8 out[4]; - uint i; - - switch(order) - { - case BO_LITTLE: - for(i = 0;i < bytes;i++) - out[i] = (in>>(i*8)) & 0x000000FF; - break; - case BO_BIG: - for(i = 0;i < bytes;i++) - out[bytes - i - 1] = (in>>(i*8)) & 0x000000FF; - break; - default: - break; - } - if(fwrite(out, 1, bytes, fp) != bytes) - { - fprintf(stderr, "Error: Bad write to file '%s'.\n", filename); - return 0; - } - return 1; -} - -// Store the OpenAL Soft HRTF data set. -static int StoreMhr(const HrirDataT *hData, const char *filename) -{ - uint channels = (hData->mChannelType == CT_STEREO) ? 2 : 1; - uint n = hData->mIrPoints; - FILE *fp; - uint fi, ei, ai, i; - uint dither_seed = 22222; - - if((fp=fopen(filename, "wb")) == NULL) - { - fprintf(stderr, "Error: Could not open MHR file '%s'.\n", filename); - return 0; - } - if(!WriteAscii(MHR_FORMAT, fp, filename)) - return 0; - if(!WriteBin4(BO_LITTLE, 4, (uint32)hData->mIrRate, fp, filename)) - return 0; - if(!WriteBin4(BO_LITTLE, 1, (uint32)hData->mSampleType, fp, filename)) - return 0; - if(!WriteBin4(BO_LITTLE, 1, (uint32)hData->mChannelType, fp, filename)) - return 0; - if(!WriteBin4(BO_LITTLE, 1, (uint32)hData->mIrPoints, fp, filename)) - return 0; - if(!WriteBin4(BO_LITTLE, 1, (uint32)hData->mFdCount, fp, filename)) - return 0; - for(fi = 0;fi < hData->mFdCount;fi++) - { - if(!WriteBin4(BO_LITTLE, 2, (uint32)(1000.0 * hData->mFds[fi].mDistance), fp, filename)) - return 0; - if(!WriteBin4(BO_LITTLE, 1, (uint32)hData->mFds[fi].mEvCount, fp, filename)) - return 0; - for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) - { - if(!WriteBin4(BO_LITTLE, 1, (uint32)hData->mFds[fi].mEvs[ei].mAzCount, fp, filename)) - return 0; - } - } - - for(fi = 0;fi < hData->mFdCount;fi++) - { - const double scale = (hData->mSampleType == ST_S16) ? 32767.0 : - ((hData->mSampleType == ST_S24) ? 8388607.0 : 0.0); - const int bps = (hData->mSampleType == ST_S16) ? 2 : - ((hData->mSampleType == ST_S24) ? 3 : 0); - - for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) - { - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - { - HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; - double out[2 * MAX_TRUNCSIZE]; - - TpdfDither(out, azd->mIrs[0], scale, n, channels, &dither_seed); - if(hData->mChannelType == CT_STEREO) - TpdfDither(out+1, azd->mIrs[1], scale, n, channels, &dither_seed); - for(i = 0;i < (channels * n);i++) - { - int v = (int)Clamp(out[i], -scale-1.0, scale); - if(!WriteBin4(BO_LITTLE, bps, (uint32)v, fp, filename)) - return 0; - } - } - } - } - for(fi = 0;fi < hData->mFdCount;fi++) - { - for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) - { - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - { - HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; - int v = (int)fmin(round(hData->mIrRate * azd->mDelays[0]), MAX_HRTD); - - if(!WriteBin4(BO_LITTLE, 1, (uint32)v, fp, filename)) - return 0; - if(hData->mChannelType == CT_STEREO) - { - v = (int)fmin(round(hData->mIrRate * azd->mDelays[1]), MAX_HRTD); - - if(!WriteBin4(BO_LITTLE, 1, (uint32)v, fp, filename)) - return 0; - } - } - } - } - fclose(fp); - return 1; -} - - -/*********************** - *** HRTF processing *** - ***********************/ - -// Calculate the onset time of an HRIR and average it with any existing -// timing for its field, elevation, azimuth, and ear. -static double AverageHrirOnset(const uint rate, const uint n, const double *hrir, const double f, const double onset) -{ - double mag = 0.0; - uint i; - - for(i = 0;i < n;i++) - mag = fmax(fabs(hrir[i]), mag); - mag *= 0.15; - for(i = 0;i < n;i++) - { - if(fabs(hrir[i]) >= mag) - break; - } - return Lerp(onset, (double)i / rate, f); -} - -// Calculate the magnitude response of an HRIR and average it with any -// existing responses for its field, elevation, azimuth, and ear. -static void AverageHrirMagnitude(const uint points, const uint n, const double *hrir, const double f, double *mag) -{ - uint m = 1 + (n / 2), i; - Complex *h = CreateComplexes(n); - double *r = CreateDoubles(n); - - for(i = 0;i < points;i++) - h[i] = MakeComplex(hrir[i], 0.0); - for(;i < n;i++) - h[i] = MakeComplex(0.0, 0.0); - FftForward(n, h); - MagnitudeResponse(n, h, r); - for(i = 0;i < m;i++) - mag[i] = Lerp(mag[i], r[i], f); - free(r); - free(h); -} - -/* Calculate the contribution of each HRIR to the diffuse-field average based - * on the area of its surface patch. All patches are centered at the HRIR - * coordinates on the unit sphere and are measured by solid angle. - */ -static void CalculateDfWeights(const HrirDataT *hData, double *weights) -{ - double sum, evs, ev, upperEv, lowerEv, solidAngle; - uint fi, ei; - - sum = 0.0; - for(fi = 0;fi < hData->mFdCount;fi++) - { - evs = M_PI / 2.0 / (hData->mFds[fi].mEvCount - 1); - for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++) - { - // For each elevation, calculate the upper and lower limits of - // the patch band. - ev = hData->mFds[fi].mEvs[ei].mElevation; - lowerEv = fmax(-M_PI / 2.0, ev - evs); - upperEv = fmin(M_PI / 2.0, ev + evs); - // Calculate the area of the patch band. - solidAngle = 2.0 * M_PI * (sin(upperEv) - sin(lowerEv)); - // Each weight is the area of one patch. - weights[(fi * MAX_EV_COUNT) + ei] = solidAngle / hData->mFds[fi].mEvs[ei].mAzCount; - // Sum the total surface area covered by the HRIRs of all fields. - sum += solidAngle; - } - } - /* TODO: It may be interesting to experiment with how a volume-based - weighting performs compared to the existing distance-indepenent - surface patches. - */ - for(fi = 0;fi < hData->mFdCount;fi++) - { - // Normalize the weights given the total surface coverage for all - // fields. - for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++) - weights[(fi * MAX_EV_COUNT) + ei] /= sum; - } -} - -/* Calculate the diffuse-field average from the given magnitude responses of - * the HRIR set. Weighting can be applied to compensate for the varying - * surface area covered by each HRIR. The final average can then be limited - * by the specified magnitude range (in positive dB; 0.0 to skip). - */ -static void CalculateDiffuseFieldAverage(const HrirDataT *hData, const uint channels, const uint m, const int weighted, const double limit, double *dfa) -{ - double *weights = CreateDoubles(hData->mFdCount * MAX_EV_COUNT); - uint count, ti, fi, ei, i, ai; - - if(weighted) - { - // Use coverage weighting to calculate the average. - CalculateDfWeights(hData, weights); - } - else - { - double weight; - - // If coverage weighting is not used, the weights still need to be - // averaged by the number of existing HRIRs. - count = hData->mIrCount; - for(fi = 0;fi < hData->mFdCount;fi++) - { - for(ei = 0;ei < hData->mFds[fi].mEvStart;ei++) - count -= hData->mFds[fi].mEvs[ei].mAzCount; - } - weight = 1.0 / count; - - for(fi = 0;fi < hData->mFdCount;fi++) - { - for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++) - weights[(fi * MAX_EV_COUNT) + ei] = weight; - } - } - for(ti = 0;ti < channels;ti++) - { - for(i = 0;i < m;i++) - dfa[(ti * m) + i] = 0.0; - for(fi = 0;fi < hData->mFdCount;fi++) - { - for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++) - { - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - { - HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; - // Get the weight for this HRIR's contribution. - double weight = weights[(fi * MAX_EV_COUNT) + ei]; - - // Add this HRIR's weighted power average to the total. - for(i = 0;i < m;i++) - dfa[(ti * m) + i] += weight * azd->mIrs[ti][i] * azd->mIrs[ti][i]; - } - } - } - // Finish the average calculation and keep it from being too small. - for(i = 0;i < m;i++) - dfa[(ti * m) + i] = fmax(sqrt(dfa[(ti * m) + i]), EPSILON); - // Apply a limit to the magnitude range of the diffuse-field average - // if desired. - if(limit > 0.0) - LimitMagnitudeResponse(hData->mFftSize, m, limit, &dfa[ti * m], &dfa[ti * m]); - } - free(weights); -} - -// Perform diffuse-field equalization on the magnitude responses of the HRIR -// set using the given average response. -static void DiffuseFieldEqualize(const uint channels, const uint m, const double *dfa, const HrirDataT *hData) -{ - uint ti, fi, ei, ai, i; - - for(fi = 0;fi < hData->mFdCount;fi++) - { - for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++) - { - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - { - HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; - - for(ti = 0;ti < channels;ti++) - { - for(i = 0;i < m;i++) - azd->mIrs[ti][i] /= dfa[(ti * m) + i]; - } - } - } - } -} - -// Perform minimum-phase reconstruction using the magnitude responses of the -// HRIR set. -static void ReconstructHrirs(const HrirDataT *hData) -{ - uint channels = (hData->mChannelType == CT_STEREO) ? 2 : 1; - uint n = hData->mFftSize; - uint ti, fi, ei, ai, i; - Complex *h = CreateComplexes(n); - uint total, count, pcdone, lastpc; - - total = hData->mIrCount; - for(fi = 0;fi < hData->mFdCount;fi++) - { - for(ei = 0;ei < hData->mFds[fi].mEvStart;ei++) - total -= hData->mFds[fi].mEvs[ei].mAzCount; - } - total *= channels; - count = pcdone = lastpc = 0; - printf("%3d%% done.", pcdone); - fflush(stdout); - for(fi = 0;fi < hData->mFdCount;fi++) - { - for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++) - { - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - { - HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; - - for(ti = 0;ti < channels;ti++) - { - MinimumPhase(n, azd->mIrs[ti], h); - FftInverse(n, h); - for(i = 0;i < hData->mIrPoints;i++) - azd->mIrs[ti][i] = h[i].Real; - pcdone = ++count * 100 / total; - if(pcdone != lastpc) - { - lastpc = pcdone; - printf("\r%3d%% done.", pcdone); - fflush(stdout); - } - } - } - } - } - printf("\n"); - free(h); -} - -// Resamples the HRIRs for use at the given sampling rate. -static void ResampleHrirs(const uint rate, HrirDataT *hData) -{ - uint channels = (hData->mChannelType == CT_STEREO) ? 2 : 1; - uint n = hData->mIrPoints; - uint ti, fi, ei, ai; - ResamplerT rs; - - ResamplerSetup(&rs, hData->mIrRate, rate); - for(fi = 0;fi < hData->mFdCount;fi++) - { - for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++) - { - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - { - HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; - - for(ti = 0;ti < channels;ti++) - ResamplerRun(&rs, n, azd->mIrs[ti], n, azd->mIrs[ti]); - } - } - } - hData->mIrRate = rate; - ResamplerClear(&rs); -} - -/* Given field and elevation indices and an azimuth, calculate the indices of - * the two HRIRs that bound the coordinate along with a factor for - * calculating the continuous HRIR using interpolation. - */ -static void CalcAzIndices(const HrirDataT *hData, const uint fi, const uint ei, const double az, uint *a0, uint *a1, double *af) -{ - double f = (2.0*M_PI + az) * hData->mFds[fi].mEvs[ei].mAzCount / (2.0*M_PI); - uint i = (uint)f % hData->mFds[fi].mEvs[ei].mAzCount; - - f -= floor(f); - *a0 = i; - *a1 = (i + 1) % hData->mFds[fi].mEvs[ei].mAzCount; - *af = f; -} - -// Synthesize any missing onset timings at the bottom elevations of each -// field. This just blends between slightly exaggerated known onsets (not -// an accurate model). -static void SynthesizeOnsets(HrirDataT *hData) -{ - uint channels = (hData->mChannelType == CT_STEREO) ? 2 : 1; - uint ti, fi, oi, ai, ei, a0, a1; - double t, of, af; - - for(fi = 0;fi < hData->mFdCount;fi++) - { - if(hData->mFds[fi].mEvStart <= 0) - continue; - oi = hData->mFds[fi].mEvStart; - - for(ti = 0;ti < channels;ti++) - { - t = 0.0; - for(ai = 0;ai < hData->mFds[fi].mEvs[oi].mAzCount;ai++) - t += hData->mFds[fi].mEvs[oi].mAzs[ai].mDelays[ti]; - hData->mFds[fi].mEvs[0].mAzs[0].mDelays[ti] = 1.32e-4 + (t / hData->mFds[fi].mEvs[oi].mAzCount); - for(ei = 1;ei < hData->mFds[fi].mEvStart;ei++) - { - of = (double)ei / hData->mFds[fi].mEvStart; - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - { - CalcAzIndices(hData, fi, oi, hData->mFds[fi].mEvs[ei].mAzs[ai].mAzimuth, &a0, &a1, &af); - hData->mFds[fi].mEvs[ei].mAzs[ai].mDelays[ti] = Lerp( - hData->mFds[fi].mEvs[0].mAzs[0].mDelays[ti], - Lerp(hData->mFds[fi].mEvs[oi].mAzs[a0].mDelays[ti], - hData->mFds[fi].mEvs[oi].mAzs[a1].mDelays[ti], af), - of - ); - } - } - } - } -} - -/* Attempt to synthesize any missing HRIRs at the bottom elevations of each - * field. Right now this just blends the lowest elevation HRIRs together and - * applies some attenuation and high frequency damping. It is a simple, if - * inaccurate model. - */ -static void SynthesizeHrirs(HrirDataT *hData) -{ - uint channels = (hData->mChannelType == CT_STEREO) ? 2 : 1; - uint n = hData->mIrPoints; - uint ti, fi, ai, ei, i; - double lp[4], s0, s1; - double of, b; - uint a0, a1; - double af; - - for(fi = 0;fi < hData->mFdCount;fi++) - { - const uint oi = hData->mFds[fi].mEvStart; - if(oi <= 0) continue; - - for(ti = 0;ti < channels;ti++) - { - for(i = 0;i < n;i++) - hData->mFds[fi].mEvs[0].mAzs[0].mIrs[ti][i] = 0.0; - for(ai = 0;ai < hData->mFds[fi].mEvs[oi].mAzCount;ai++) - { - for(i = 0;i < n;i++) - hData->mFds[fi].mEvs[0].mAzs[0].mIrs[ti][i] += hData->mFds[fi].mEvs[oi].mAzs[ai].mIrs[ti][i] / - hData->mFds[fi].mEvs[oi].mAzCount; - } - for(ei = 1;ei < hData->mFds[fi].mEvStart;ei++) - { - of = (double)ei / hData->mFds[fi].mEvStart; - b = (1.0 - of) * (3.5e-6 * hData->mIrRate); - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - { - CalcAzIndices(hData, fi, oi, hData->mFds[fi].mEvs[ei].mAzs[ai].mAzimuth, &a0, &a1, &af); - lp[0] = 0.0; - lp[1] = 0.0; - lp[2] = 0.0; - lp[3] = 0.0; - for(i = 0;i < n;i++) - { - s0 = hData->mFds[fi].mEvs[0].mAzs[0].mIrs[ti][i]; - s1 = Lerp(hData->mFds[fi].mEvs[oi].mAzs[a0].mIrs[ti][i], - hData->mFds[fi].mEvs[oi].mAzs[a1].mIrs[ti][i], af); - s0 = Lerp(s0, s1, of); - lp[0] = Lerp(s0, lp[0], b); - lp[1] = Lerp(lp[0], lp[1], b); - lp[2] = Lerp(lp[1], lp[2], b); - lp[3] = Lerp(lp[2], lp[3], b); - hData->mFds[fi].mEvs[ei].mAzs[ai].mIrs[ti][i] = lp[3]; - } - } - } - b = 3.5e-6 * hData->mIrRate; - lp[0] = 0.0; - lp[1] = 0.0; - lp[2] = 0.0; - lp[3] = 0.0; - for(i = 0;i < n;i++) - { - s0 = hData->mFds[fi].mEvs[0].mAzs[0].mIrs[ti][i]; - lp[0] = Lerp(s0, lp[0], b); - lp[1] = Lerp(lp[0], lp[1], b); - lp[2] = Lerp(lp[1], lp[2], b); - lp[3] = Lerp(lp[2], lp[3], b); - hData->mFds[fi].mEvs[0].mAzs[0].mIrs[ti][i] = lp[3]; - } - } - hData->mFds[fi].mEvStart = 0; - } -} - -// The following routines assume a full set of HRIRs for all elevations. - -// Normalize the HRIR set and slightly attenuate the result. -static void NormalizeHrirs(const HrirDataT *hData) -{ - uint channels = (hData->mChannelType == CT_STEREO) ? 2 : 1; - uint n = hData->mIrPoints; - uint ti, fi, ei, ai, i; - double maxLevel = 0.0; - - for(fi = 0;fi < hData->mFdCount;fi++) - { - for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) - { - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - { - HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; - - for(ti = 0;ti < channels;ti++) - { - for(i = 0;i < n;i++) - maxLevel = fmax(fabs(azd->mIrs[ti][i]), maxLevel); - } - } - } - } - maxLevel = 1.01 * maxLevel; - for(fi = 0;fi < hData->mFdCount;fi++) - { - for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) - { - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - { - HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; - - for(ti = 0;ti < channels;ti++) - { - for(i = 0;i < n;i++) - azd->mIrs[ti][i] /= maxLevel; - } - } - } - } -} - -// Calculate the left-ear time delay using a spherical head model. -static double CalcLTD(const double ev, const double az, const double rad, const double dist) -{ - double azp, dlp, l, al; - - azp = asin(cos(ev) * sin(az)); - dlp = sqrt((dist*dist) + (rad*rad) + (2.0*dist*rad*sin(azp))); - l = sqrt((dist*dist) - (rad*rad)); - al = (0.5 * M_PI) + azp; - if(dlp > l) - dlp = l + (rad * (al - acos(rad / dist))); - return dlp / 343.3; -} - -// Calculate the effective head-related time delays for each minimum-phase -// HRIR. -static void CalculateHrtds(const HeadModelT model, const double radius, HrirDataT *hData) -{ - uint channels = (hData->mChannelType == CT_STEREO) ? 2 : 1; - double minHrtd = INFINITY, maxHrtd = -INFINITY; - uint ti, fi, ei, ai; - double t; - - if(model == HM_DATASET) - { - for(fi = 0;fi < hData->mFdCount;fi++) - { - for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) - { - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - { - HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; - - for(ti = 0;ti < channels;ti++) - { - t = azd->mDelays[ti] * radius / hData->mRadius; - azd->mDelays[ti] = t; - maxHrtd = fmax(t, maxHrtd); - minHrtd = fmin(t, minHrtd); - } - } - } - } - } - else - { - for(fi = 0;fi < hData->mFdCount;fi++) - { - for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) - { - HrirEvT *evd = &hData->mFds[fi].mEvs[ei]; - - for(ai = 0;ai < evd->mAzCount;ai++) - { - HrirAzT *azd = &evd->mAzs[ai]; - - for(ti = 0;ti < channels;ti++) - { - t = CalcLTD(evd->mElevation, azd->mAzimuth, radius, hData->mFds[fi].mDistance); - azd->mDelays[ti] = t; - maxHrtd = fmax(t, maxHrtd); - minHrtd = fmin(t, minHrtd); - } - } - } - } - } - for(fi = 0;fi < hData->mFdCount;fi++) - { - for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) - { - for(ti = 0;ti < channels;ti++) - { - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - hData->mFds[fi].mEvs[ei].mAzs[ai].mDelays[ti] -= minHrtd; - } - } - } -} - -// Clear the initial HRIR data state. -static void ResetHrirData(HrirDataT *hData) -{ - hData->mIrRate = 0; - hData->mSampleType = ST_S24; - hData->mChannelType = CT_NONE; - hData->mIrPoints = 0; - hData->mFftSize = 0; - hData->mIrSize = 0; - hData->mRadius = 0.0; - hData->mIrCount = 0; - hData->mFdCount = 0; - hData->mFds = NULL; -} - -// Allocate and configure dynamic HRIR structures. -static int PrepareHrirData(const uint fdCount, const double distances[MAX_FD_COUNT], const uint evCounts[MAX_FD_COUNT], const uint azCounts[MAX_FD_COUNT * MAX_EV_COUNT], HrirDataT *hData) -{ - uint evTotal = 0, azTotal = 0, fi, ei, ai; - - for(fi = 0;fi < fdCount;fi++) - { - evTotal += evCounts[fi]; - for(ei = 0;ei < evCounts[fi];ei++) - azTotal += azCounts[(fi * MAX_EV_COUNT) + ei]; - } - if(!fdCount || !evTotal || !azTotal) - return 0; - - hData->mFds = calloc(fdCount, sizeof(*hData->mFds)); - if(hData->mFds == NULL) - return 0; - hData->mFds[0].mEvs = calloc(evTotal, sizeof(*hData->mFds[0].mEvs)); - if(hData->mFds[0].mEvs == NULL) - return 0; - hData->mFds[0].mEvs[0].mAzs = calloc(azTotal, sizeof(*hData->mFds[0].mEvs[0].mAzs)); - if(hData->mFds[0].mEvs[0].mAzs == NULL) - return 0; - hData->mIrCount = azTotal; - hData->mFdCount = fdCount; - evTotal = 0; - azTotal = 0; - for(fi = 0;fi < fdCount;fi++) - { - hData->mFds[fi].mDistance = distances[fi]; - hData->mFds[fi].mEvCount = evCounts[fi]; - hData->mFds[fi].mEvStart = 0; - hData->mFds[fi].mEvs = &hData->mFds[0].mEvs[evTotal]; - evTotal += evCounts[fi]; - for(ei = 0;ei < evCounts[fi];ei++) - { - uint azCount = azCounts[(fi * MAX_EV_COUNT) + ei]; - - hData->mFds[fi].mIrCount += azCount; - hData->mFds[fi].mEvs[ei].mElevation = -M_PI / 2.0 + M_PI * ei / (evCounts[fi] - 1); - hData->mFds[fi].mEvs[ei].mIrCount += azCount; - hData->mFds[fi].mEvs[ei].mAzCount = azCount; - hData->mFds[fi].mEvs[ei].mAzs = &hData->mFds[0].mEvs[0].mAzs[azTotal]; - for(ai = 0;ai < azCount;ai++) - { - hData->mFds[fi].mEvs[ei].mAzs[ai].mAzimuth = 2.0 * M_PI * ai / azCount; - hData->mFds[fi].mEvs[ei].mAzs[ai].mIndex = azTotal + ai; - hData->mFds[fi].mEvs[ei].mAzs[ai].mDelays[0] = 0.0; - hData->mFds[fi].mEvs[ei].mAzs[ai].mDelays[1] = 0.0; - hData->mFds[fi].mEvs[ei].mAzs[ai].mIrs[0] = NULL; - hData->mFds[fi].mEvs[ei].mAzs[ai].mIrs[1] = NULL; - } - azTotal += azCount; - } - } - return 1; -} - -// Clean up HRIR data. -static void FreeHrirData(HrirDataT *hData) -{ - if(hData->mFds != NULL) - { - if(hData->mFds[0].mEvs != NULL) - { - if(hData->mFds[0].mEvs[0].mAzs) - { - free(hData->mFds[0].mEvs[0].mAzs[0].mIrs[0]); - free(hData->mFds[0].mEvs[0].mAzs); - } - free(hData->mFds[0].mEvs); - } - free(hData->mFds); - hData->mFds = NULL; - } -} - -// Match the channel type from a given identifier. -static ChannelTypeT MatchChannelType(const char *ident) -{ - if(strcasecmp(ident, "mono") == 0) - return CT_MONO; - if(strcasecmp(ident, "stereo") == 0) - return CT_STEREO; - return CT_NONE; -} - -// Process the data set definition to read and validate the data set metrics. -static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint truncSize, HrirDataT *hData) -{ - int hasRate = 0, hasType = 0, hasPoints = 0, hasRadius = 0; - int hasDistance = 0, hasAzimuths = 0; - char ident[MAX_IDENT_LEN+1]; - uint line, col; - double fpVal; - uint points; - int intVal; - double distances[MAX_FD_COUNT]; - uint fdCount = 0; - uint evCounts[MAX_FD_COUNT]; - uint *azCounts = calloc(MAX_FD_COUNT * MAX_EV_COUNT, sizeof(*azCounts)); - - if(azCounts == NULL) - { - fprintf(stderr, "Error: Out of memory.\n"); - exit(-1); - } - TrIndication(tr, &line, &col); - while(TrIsIdent(tr)) - { - TrIndication(tr, &line, &col); - if(!TrReadIdent(tr, MAX_IDENT_LEN, ident)) - goto error; - if(strcasecmp(ident, "rate") == 0) - { - if(hasRate) - { - TrErrorAt(tr, line, col, "Redefinition of 'rate'.\n"); - goto error; - } - if(!TrReadOperator(tr, "=")) - goto error; - if(!TrReadInt(tr, MIN_RATE, MAX_RATE, &intVal)) - goto error; - hData->mIrRate = (uint)intVal; - hasRate = 1; - } - else if(strcasecmp(ident, "type") == 0) - { - char type[MAX_IDENT_LEN+1]; - - if(hasType) - { - TrErrorAt(tr, line, col, "Redefinition of 'type'.\n"); - goto error; - } - if(!TrReadOperator(tr, "=")) - goto error; - - if(!TrReadIdent(tr, MAX_IDENT_LEN, type)) - goto error; - hData->mChannelType = MatchChannelType(type); - if(hData->mChannelType == CT_NONE) - { - TrErrorAt(tr, line, col, "Expected a channel type.\n"); - goto error; - } - hasType = 1; - } - else if(strcasecmp(ident, "points") == 0) - { - if(hasPoints) - { - TrErrorAt(tr, line, col, "Redefinition of 'points'.\n"); - goto error; - } - if(!TrReadOperator(tr, "=")) - goto error; - TrIndication(tr, &line, &col); - if(!TrReadInt(tr, MIN_POINTS, MAX_POINTS, &intVal)) - goto error; - points = (uint)intVal; - if(fftSize > 0 && points > fftSize) - { - TrErrorAt(tr, line, col, "Value exceeds the overridden FFT size.\n"); - goto error; - } - if(points < truncSize) - { - TrErrorAt(tr, line, col, "Value is below the truncation size.\n"); - goto error; - } - hData->mIrPoints = points; - if(fftSize <= 0) - { - hData->mFftSize = DEFAULT_FFTSIZE; - hData->mIrSize = 1 + (DEFAULT_FFTSIZE / 2); - } - else - { - hData->mFftSize = fftSize; - hData->mIrSize = 1 + (fftSize / 2); - if(points > hData->mIrSize) - hData->mIrSize = points; - } - hasPoints = 1; - } - else if(strcasecmp(ident, "radius") == 0) - { - if(hasRadius) - { - TrErrorAt(tr, line, col, "Redefinition of 'radius'.\n"); - goto error; - } - if(!TrReadOperator(tr, "=")) - goto error; - if(!TrReadFloat(tr, MIN_RADIUS, MAX_RADIUS, &fpVal)) - goto error; - hData->mRadius = fpVal; - hasRadius = 1; - } - else if(strcasecmp(ident, "distance") == 0) - { - uint count = 0; - - if(hasDistance) - { - TrErrorAt(tr, line, col, "Redefinition of 'distance'.\n"); - goto error; - } - if(!TrReadOperator(tr, "=")) - goto error; - - for(;;) - { - if(!TrReadFloat(tr, MIN_DISTANCE, MAX_DISTANCE, &fpVal)) - goto error; - if(count > 0 && fpVal <= distances[count - 1]) - { - TrError(tr, "Distances are not ascending.\n"); - goto error; - } - distances[count++] = fpVal; - if(!TrIsOperator(tr, ",")) - break; - if(count >= MAX_FD_COUNT) - { - TrError(tr, "Exceeded the maximum of %d fields.\n", MAX_FD_COUNT); - goto error; - } - TrReadOperator(tr, ","); - } - if(fdCount != 0 && count != fdCount) - { - TrError(tr, "Did not match the specified number of %d fields.\n", fdCount); - goto error; - } - fdCount = count; - hasDistance = 1; - } - else if(strcasecmp(ident, "azimuths") == 0) - { - uint count = 0; - - if(hasAzimuths) - { - TrErrorAt(tr, line, col, "Redefinition of 'azimuths'.\n"); - goto error; - } - if(!TrReadOperator(tr, "=")) - goto error; - - evCounts[0] = 0; - for(;;) - { - if(!TrReadInt(tr, MIN_AZ_COUNT, MAX_AZ_COUNT, &intVal)) - goto error; - azCounts[(count * MAX_EV_COUNT) + evCounts[count]++] = (uint)intVal; - if(TrIsOperator(tr, ",")) - { - if(evCounts[count] >= MAX_EV_COUNT) - { - TrError(tr, "Exceeded the maximum of %d elevations.\n", MAX_EV_COUNT); - goto error; - } - TrReadOperator(tr, ","); - } - else - { - if(evCounts[count] < MIN_EV_COUNT) - { - TrErrorAt(tr, line, col, "Did not reach the minimum of %d azimuth counts.\n", MIN_EV_COUNT); - goto error; - } - if(azCounts[count * MAX_EV_COUNT] != 1 || azCounts[(count * MAX_EV_COUNT) + evCounts[count] - 1] != 1) - { - TrError(tr, "Poles are not singular for field %d.\n", count - 1); - goto error; - } - count++; - if(TrIsOperator(tr, ";")) - { - if(count >= MAX_FD_COUNT) - { - TrError(tr, "Exceeded the maximum number of %d fields.\n", MAX_FD_COUNT); - goto error; - } - evCounts[count] = 0; - TrReadOperator(tr, ";"); - } - else - { - break; - } - } - } - if(fdCount != 0 && count != fdCount) - { - TrError(tr, "Did not match the specified number of %d fields.\n", fdCount); - goto error; - } - fdCount = count; - hasAzimuths = 1; - } - else - { - TrErrorAt(tr, line, col, "Expected a metric name.\n"); - goto error; - } - TrSkipWhitespace(tr); - } - if(!(hasRate && hasPoints && hasRadius && hasDistance && hasAzimuths)) - { - TrErrorAt(tr, line, col, "Expected a metric name.\n"); - goto error; - } - if(distances[0] < hData->mRadius) - { - TrError(tr, "Distance cannot start below head radius.\n"); - goto error; - } - if(hData->mChannelType == CT_NONE) - hData->mChannelType = CT_MONO; - if(!PrepareHrirData(fdCount, distances, evCounts, azCounts, hData)) - { - fprintf(stderr, "Error: Out of memory.\n"); - exit(-1); - } - free(azCounts); - return 1; - -error: - free(azCounts); - return 0; -} - -// Parse an index triplet from the data set definition. -static int ReadIndexTriplet(TokenReaderT *tr, const HrirDataT *hData, uint *fi, uint *ei, uint *ai) -{ - int intVal; - - if(hData->mFdCount > 1) - { - if(!TrReadInt(tr, 0, (int)hData->mFdCount - 1, &intVal)) - return 0; - *fi = (uint)intVal; - if(!TrReadOperator(tr, ",")) - return 0; - } - else - { - *fi = 0; - } - if(!TrReadInt(tr, 0, (int)hData->mFds[*fi].mEvCount - 1, &intVal)) - return 0; - *ei = (uint)intVal; - if(!TrReadOperator(tr, ",")) - return 0; - if(!TrReadInt(tr, 0, (int)hData->mFds[*fi].mEvs[*ei].mAzCount - 1, &intVal)) - return 0; - *ai = (uint)intVal; - return 1; -} - -// Match the source format from a given identifier. -static SourceFormatT MatchSourceFormat(const char *ident) -{ - if(strcasecmp(ident, "wave") == 0) - return SF_WAVE; - if(strcasecmp(ident, "bin_le") == 0) - return SF_BIN_LE; - if(strcasecmp(ident, "bin_be") == 0) - return SF_BIN_BE; - if(strcasecmp(ident, "ascii") == 0) - return SF_ASCII; - return SF_NONE; -} - -// Match the source element type from a given identifier. -static ElementTypeT MatchElementType(const char *ident) -{ - if(strcasecmp(ident, "int") == 0) - return ET_INT; - if(strcasecmp(ident, "fp") == 0) - return ET_FP; - return ET_NONE; -} - -// Parse and validate a source reference from the data set definition. -static int ReadSourceRef(TokenReaderT *tr, SourceRefT *src) -{ - char ident[MAX_IDENT_LEN+1]; - uint line, col; - int intVal; - - TrIndication(tr, &line, &col); - if(!TrReadIdent(tr, MAX_IDENT_LEN, ident)) - return 0; - src->mFormat = MatchSourceFormat(ident); - if(src->mFormat == SF_NONE) - { - TrErrorAt(tr, line, col, "Expected a source format.\n"); - return 0; - } - if(!TrReadOperator(tr, "(")) - return 0; - if(src->mFormat == SF_WAVE) - { - if(!TrReadInt(tr, 0, MAX_WAVE_CHANNELS, &intVal)) - return 0; - src->mType = ET_NONE; - src->mSize = 0; - src->mBits = 0; - src->mChannel = (uint)intVal; - src->mSkip = 0; - } - else - { - TrIndication(tr, &line, &col); - if(!TrReadIdent(tr, MAX_IDENT_LEN, ident)) - return 0; - src->mType = MatchElementType(ident); - if(src->mType == ET_NONE) - { - TrErrorAt(tr, line, col, "Expected a source element type.\n"); - return 0; - } - if(src->mFormat == SF_BIN_LE || src->mFormat == SF_BIN_BE) - { - if(!TrReadOperator(tr, ",")) - return 0; - if(src->mType == ET_INT) - { - if(!TrReadInt(tr, MIN_BIN_SIZE, MAX_BIN_SIZE, &intVal)) - return 0; - src->mSize = (uint)intVal; - if(!TrIsOperator(tr, ",")) - src->mBits = (int)(8*src->mSize); - else - { - TrReadOperator(tr, ","); - TrIndication(tr, &line, &col); - if(!TrReadInt(tr, -2147483647-1, 2147483647, &intVal)) - return 0; - if(abs(intVal) < MIN_BIN_BITS || (uint)abs(intVal) > (8*src->mSize)) - { - TrErrorAt(tr, line, col, "Expected a value of (+/-) %d to %d.\n", MIN_BIN_BITS, 8*src->mSize); - return 0; - } - src->mBits = intVal; - } - } - else - { - TrIndication(tr, &line, &col); - if(!TrReadInt(tr, -2147483647-1, 2147483647, &intVal)) - return 0; - if(intVal != 4 && intVal != 8) - { - TrErrorAt(tr, line, col, "Expected a value of 4 or 8.\n"); - return 0; - } - src->mSize = (uint)intVal; - src->mBits = 0; - } - } - else if(src->mFormat == SF_ASCII && src->mType == ET_INT) - { - if(!TrReadOperator(tr, ",")) - return 0; - if(!TrReadInt(tr, MIN_ASCII_BITS, MAX_ASCII_BITS, &intVal)) - return 0; - src->mSize = 0; - src->mBits = intVal; - } - else - { - src->mSize = 0; - src->mBits = 0; - } - - if(!TrIsOperator(tr, ";")) - src->mSkip = 0; - else - { - TrReadOperator(tr, ";"); - if(!TrReadInt(tr, 0, 0x7FFFFFFF, &intVal)) - return 0; - src->mSkip = (uint)intVal; - } - } - if(!TrReadOperator(tr, ")")) - return 0; - if(TrIsOperator(tr, "@")) - { - TrReadOperator(tr, "@"); - if(!TrReadInt(tr, 0, 0x7FFFFFFF, &intVal)) - return 0; - src->mOffset = (uint)intVal; - } - else - src->mOffset = 0; - if(!TrReadOperator(tr, ":")) - return 0; - if(!TrReadString(tr, MAX_PATH_LEN, src->mPath)) - return 0; - return 1; -} - -// Match the target ear (index) from a given identifier. -static int MatchTargetEar(const char *ident) -{ - if(strcasecmp(ident, "left") == 0) - return 0; - if(strcasecmp(ident, "right") == 0) - return 1; - return -1; -} - -// Process the list of sources in the data set definition. -static int ProcessSources(const HeadModelT model, TokenReaderT *tr, HrirDataT *hData) -{ - uint channels = (hData->mChannelType == CT_STEREO) ? 2 : 1; - double *hrirs = CreateDoubles(channels * hData->mIrCount * hData->mIrSize); - double *hrir = CreateDoubles(hData->mIrPoints); - uint line, col, fi, ei, ai, ti; - int count; - - printf("Loading sources..."); - fflush(stdout); - count = 0; - while(TrIsOperator(tr, "[")) - { - double factor[2] = { 1.0, 1.0 }; - - TrIndication(tr, &line, &col); - TrReadOperator(tr, "["); - if(!ReadIndexTriplet(tr, hData, &fi, &ei, &ai)) - goto error; - if(!TrReadOperator(tr, "]")) - goto error; - HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; - - if(azd->mIrs[0] != NULL) - { - TrErrorAt(tr, line, col, "Redefinition of source.\n"); - goto error; - } - if(!TrReadOperator(tr, "=")) - goto error; - - for(;;) - { - SourceRefT src; - uint ti = 0; - - if(!ReadSourceRef(tr, &src)) - goto error; - - // TODO: Would be nice to display 'x of y files', but that would - // require preparing the source refs first to get a total count - // before loading them. - ++count; - printf("\rLoading sources... %d file%s", count, (count==1)?"":"s"); - fflush(stdout); - - if(!LoadSource(&src, hData->mIrRate, hData->mIrPoints, hrir)) - goto error; - - if(hData->mChannelType == CT_STEREO) - { - char ident[MAX_IDENT_LEN+1]; - - if(!TrReadIdent(tr, MAX_IDENT_LEN, ident)) - goto error; - ti = MatchTargetEar(ident); - if((int)ti < 0) - { - TrErrorAt(tr, line, col, "Expected a target ear.\n"); - goto error; - } - } - azd->mIrs[ti] = &hrirs[hData->mIrSize * (ti * hData->mIrCount + azd->mIndex)]; - if(model == HM_DATASET) - azd->mDelays[ti] = AverageHrirOnset(hData->mIrRate, hData->mIrPoints, hrir, 1.0 / factor[ti], azd->mDelays[ti]); - AverageHrirMagnitude(hData->mIrPoints, hData->mFftSize, hrir, 1.0 / factor[ti], azd->mIrs[ti]); - factor[ti] += 1.0; - if(!TrIsOperator(tr, "+")) - break; - TrReadOperator(tr, "+"); - } - if(hData->mChannelType == CT_STEREO) - { - if(azd->mIrs[0] == NULL) - { - TrErrorAt(tr, line, col, "Missing left ear source reference(s).\n"); - goto error; - } - else if(azd->mIrs[1] == NULL) - { - TrErrorAt(tr, line, col, "Missing right ear source reference(s).\n"); - goto error; - } - } - } - printf("\n"); - for(fi = 0;fi < hData->mFdCount;fi++) - { - for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) - { - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - { - HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; - - if(azd->mIrs[0] != NULL) - break; - } - if(ai < hData->mFds[fi].mEvs[ei].mAzCount) - break; - } - if(ei >= hData->mFds[fi].mEvCount) - { - TrError(tr, "Missing source references [ %d, *, * ].\n", fi); - goto error; - } - hData->mFds[fi].mEvStart = ei; - for(;ei < hData->mFds[fi].mEvCount;ei++) - { - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - { - HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; - - if(azd->mIrs[0] == NULL) - { - TrError(tr, "Missing source reference [ %d, %d, %d ].\n", fi, ei, ai); - goto error; - } - } - } - } - for(ti = 0;ti < channels;ti++) - { - for(fi = 0;fi < hData->mFdCount;fi++) - { - for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) - { - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - { - HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; - - azd->mIrs[ti] = &hrirs[hData->mIrSize * (ti * hData->mIrCount + azd->mIndex)]; - } - } - } - } - if(!TrLoad(tr)) - { - free(hrir); - return 1; - } - TrError(tr, "Errant data at end of source list.\n"); - -error: - free(hrir); - return 0; -} - -/* Parse the data set definition and process the source data, storing the - * resulting data set as desired. If the input name is NULL it will read - * from standard input. - */ -static int ProcessDefinition(const char *inName, const uint outRate, const uint fftSize, const int equalize, const int surface, const double limit, const uint truncSize, const HeadModelT model, const double radius, const char *outName) -{ - char rateStr[8+1], expName[MAX_PATH_LEN]; - TokenReaderT tr; - HrirDataT hData; - FILE *fp; - int ret; - - ResetHrirData(&hData); - fprintf(stdout, "Reading HRIR definition from %s...\n", inName?inName:"stdin"); - if(inName != NULL) - { - fp = fopen(inName, "r"); - if(fp == NULL) - { - fprintf(stderr, "Error: Could not open definition file '%s'\n", inName); - return 0; - } - TrSetup(fp, inName, &tr); - } - else - { - fp = stdin; - TrSetup(fp, "", &tr); - } - if(!ProcessMetrics(&tr, fftSize, truncSize, &hData)) - { - if(inName != NULL) - fclose(fp); - return 0; - } - if(!ProcessSources(model, &tr, &hData)) - { - FreeHrirData(&hData); - if(inName != NULL) - fclose(fp); - return 0; - } - if(fp != stdin) - fclose(fp); - if(equalize) - { - uint c = (hData.mChannelType == CT_STEREO) ? 2 : 1; - uint m = 1 + hData.mFftSize / 2; - double *dfa = CreateDoubles(c * m); - - fprintf(stdout, "Calculating diffuse-field average...\n"); - CalculateDiffuseFieldAverage(&hData, c, m, surface, limit, dfa); - fprintf(stdout, "Performing diffuse-field equalization...\n"); - DiffuseFieldEqualize(c, m, dfa, &hData); - free(dfa); - } - fprintf(stdout, "Performing minimum phase reconstruction...\n"); - ReconstructHrirs(&hData); - if(outRate != 0 && outRate != hData.mIrRate) - { - fprintf(stdout, "Resampling HRIRs...\n"); - ResampleHrirs(outRate, &hData); - } - fprintf(stdout, "Truncating minimum-phase HRIRs...\n"); - hData.mIrPoints = truncSize; - fprintf(stdout, "Synthesizing missing elevations...\n"); - if(model == HM_DATASET) - SynthesizeOnsets(&hData); - SynthesizeHrirs(&hData); - fprintf(stdout, "Normalizing final HRIRs...\n"); - NormalizeHrirs(&hData); - fprintf(stdout, "Calculating impulse delays...\n"); - CalculateHrtds(model, (radius > DEFAULT_CUSTOM_RADIUS) ? radius : hData.mRadius, &hData); - snprintf(rateStr, 8, "%u", hData.mIrRate); - StrSubst(outName, "%r", rateStr, MAX_PATH_LEN, expName); - fprintf(stdout, "Creating MHR data set %s...\n", expName); - ret = StoreMhr(&hData, expName); - - FreeHrirData(&hData); - return ret; -} - -static void PrintHelp(const char *argv0, FILE *ofile) -{ - fprintf(ofile, "Usage: %s [ @@ -2201,8 +2201,8 @@ added by the ALC_EXT_DEDICATED extension. 160 20 - 125 - 29 + 129 + 31 @@ -2371,7 +2371,7 @@ added by the ALC_EXT_DEDICATED extension. 0 0 564 - 27 + 29 -- cgit v1.2.3 From c724798c85c035da506ccf06dd604654de8a19fb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Apr 2019 08:48:14 -0700 Subject: Don't round WASAPI updates to the update size --- Alc/backends/wasapi.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index e361b7bc..f4448621 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -582,7 +582,6 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() ERR("WaitForSingleObjectEx error: 0x%lx\n", res); continue; } - len -= len%update_size; BYTE *buffer; hr = mRender->GetBuffer(len, &buffer); -- cgit v1.2.3 From f9f34def8247e4d9a5002c176113cb0f4beb36e7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Apr 2019 12:25:49 -0700 Subject: Use a custom PulseAudio mainloop This allows using RT priority again with the mixer. It also consolidates all mainloop instances into one. --- Alc/backends/pulseaudio.cpp | 434 ++++++++++++++++++++------------------------ 1 file changed, 199 insertions(+), 235 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 9561407c..aaf5f083 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -23,6 +23,7 @@ #include "backends/pulseaudio.h" +#include #include #include @@ -31,6 +32,7 @@ #include #include #include +#include #include "alMain.h" #include "alu.h" @@ -263,41 +265,72 @@ pa_context_flags_t pulse_ctx_flags; pa_proplist *prop_filter; +pa_mainloop *pulse_mainloop{nullptr}; + +std::mutex pulse_lock; +std::condition_variable pulse_condvar; + +int pulse_poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) +{ + auto plock = static_cast*>(userdata); + plock->unlock(); + int r{poll(ufds, nfds, timeout)}; + plock->lock(); + return r; +} + +int pulse_mainloop_thread() +{ + SetRTPriority(); + + std::unique_lock plock{pulse_lock}; + pulse_mainloop = pa_mainloop_new(); + + pa_mainloop_set_poll_func(pulse_mainloop, pulse_poll_func, &plock); + pulse_condvar.notify_all(); + + int ret{}; + pa_mainloop_run(pulse_mainloop, &ret); + + pa_mainloop_free(pulse_mainloop); + pulse_mainloop = nullptr; + + return ret; +} + + /* PulseAudio Event Callbacks */ -void context_state_callback(pa_context *context, void *pdata) +void context_state_callback(pa_context *context, void* /*pdata*/) { - auto loop = static_cast(pdata); pa_context_state_t state{pa_context_get_state(context)}; if(state == PA_CONTEXT_READY || !PA_CONTEXT_IS_GOOD(state)) - pa_threaded_mainloop_signal(loop, 0); + pulse_condvar.notify_all(); } -void stream_state_callback(pa_stream *stream, void *pdata) +void stream_state_callback(pa_stream *stream, void* /*pdata*/) { - auto loop = static_cast(pdata); pa_stream_state_t state{pa_stream_get_state(stream)}; if(state == PA_STREAM_READY || !PA_STREAM_IS_GOOD(state)) - pa_threaded_mainloop_signal(loop, 0); + pulse_condvar.notify_all(); } -void stream_success_callback(pa_stream *UNUSED(stream), int UNUSED(success), void *pdata) +void stream_success_callback(pa_stream* /*stream*/, int /*success*/, void* /*pdata*/) { - auto loop = static_cast(pdata); - pa_threaded_mainloop_signal(loop, 0); + pulse_condvar.notify_all(); } -void wait_for_operation(pa_operation *op, pa_threaded_mainloop *loop) +void wait_for_operation(pa_operation *op, std::unique_lock &plock) { if(op) { while(pa_operation_get_state(op) == PA_OPERATION_RUNNING) - pa_threaded_mainloop_wait(loop); + pulse_condvar.wait(plock); pa_operation_unref(op); } } -pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent) +pa_context *connect_context(std::unique_lock &plock, ALboolean silent) { const char *name{"OpenAL Soft"}; @@ -305,14 +338,21 @@ pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent) if(!binname.fname.empty()) name = binname.fname.c_str(); - pa_context *context{pa_context_new(pa_threaded_mainloop_get_api(loop), name)}; + if(UNLIKELY(!pulse_mainloop)) + { + std::thread{pulse_mainloop_thread}.detach(); + while(!pulse_mainloop) + pulse_condvar.wait(plock); + } + + pa_context *context{pa_context_new(pa_mainloop_get_api(pulse_mainloop), name)}; if(!context) { ERR("pa_context_new() failed\n"); return nullptr; } - pa_context_set_state_callback(context, context_state_callback, loop); + pa_context_set_state_callback(context, context_state_callback, nullptr); int err; if((err=pa_context_connect(context, nullptr, pulse_ctx_flags, nullptr)) >= 0) @@ -327,7 +367,7 @@ pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent) break; } - pa_threaded_mainloop_wait(loop); + pulse_condvar.wait(plock); } } pa_context_set_state_callback(context, nullptr, nullptr); @@ -344,65 +384,36 @@ pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent) } -using MainloopContextPair = std::pair; -MainloopContextPair pulse_open(void(*state_cb)(pa_context*,void*), void *ptr) +pa_context *pulse_open(void(*state_cb)(pa_context*,void*), void *ptr) { - pa_threaded_mainloop *loop{pa_threaded_mainloop_new()}; - if(UNLIKELY(!loop)) - { - ERR("pa_threaded_mainloop_new() failed!\n"); - return {nullptr, nullptr}; - } - if(UNLIKELY(pa_threaded_mainloop_start(loop) < 0)) - { - ERR("pa_threaded_mainloop_start() failed\n"); - pa_threaded_mainloop_free(loop); - return {nullptr, nullptr}; - } - - unique_palock palock{loop}; - pa_context *context{connect_context(loop, AL_FALSE)}; - if(UNLIKELY(!context)) - { - palock = unique_palock{}; - pa_threaded_mainloop_stop(loop); - pa_threaded_mainloop_free(loop); - return {nullptr, nullptr}; - } - pa_context_set_state_callback(context, state_cb, ptr); - return {loop, context}; + std::unique_lock plock{pulse_lock}; + pa_context *context{connect_context(plock, AL_FALSE)}; + if(LIKELY(context)) + pa_context_set_state_callback(context, state_cb, ptr); + return context; } -void pulse_close(pa_threaded_mainloop *loop, pa_context *context, pa_stream *stream) +void pulse_close(pa_context *context, pa_stream *stream) { - { palock_guard _{loop}; - if(stream) - { - pa_stream_set_state_callback(stream, nullptr, nullptr); - pa_stream_set_moved_callback(stream, nullptr, nullptr); - pa_stream_set_write_callback(stream, nullptr, nullptr); - pa_stream_set_buffer_attr_callback(stream, nullptr, nullptr); - pa_stream_disconnect(stream); - pa_stream_unref(stream); - } - - pa_context_disconnect(context); - pa_context_unref(context); + std::lock_guard _{pulse_lock}; + if(stream) + { + pa_stream_set_state_callback(stream, nullptr, nullptr); + pa_stream_set_moved_callback(stream, nullptr, nullptr); + pa_stream_set_write_callback(stream, nullptr, nullptr); + pa_stream_set_buffer_attr_callback(stream, nullptr, nullptr); + pa_stream_disconnect(stream); + pa_stream_unref(stream); } - pa_threaded_mainloop_stop(loop); - pa_threaded_mainloop_free(loop); + pa_context_disconnect(context); + pa_context_unref(context); } struct DevMap { std::string name; std::string device_name; - - template - DevMap(StrT0&& name_, StrT1&& devname_) - : name{std::forward(name_)}, device_name{std::forward(devname_)} - { } }; bool checkName(const al::vector &list, const std::string &name) @@ -417,7 +428,7 @@ al::vector PlaybackDevices; al::vector CaptureDevices; -pa_stream *pulse_connect_stream(const char *device_name, pa_threaded_mainloop *loop, +pa_stream *pulse_connect_stream(const char *device_name, std::unique_lock &plock, pa_context *context, pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, pa_channel_map *chanmap, BackendType type) { @@ -430,7 +441,7 @@ pa_stream *pulse_connect_stream(const char *device_name, pa_threaded_mainloop *l return nullptr; } - pa_stream_set_state_callback(stream, stream_state_callback, loop); + pa_stream_set_state_callback(stream, stream_state_callback, nullptr); int err{(type==BackendType::Playback) ? pa_stream_connect_playback(stream, device_name, attr, flags, nullptr, nullptr) : @@ -452,7 +463,7 @@ pa_stream *pulse_connect_stream(const char *device_name, pa_threaded_mainloop *l return nullptr; } - pa_threaded_mainloop_wait(loop); + pulse_condvar.wait(plock); } pa_stream_set_state_callback(stream, nullptr, nullptr); @@ -460,13 +471,11 @@ pa_stream *pulse_connect_stream(const char *device_name, pa_threaded_mainloop *l } -void device_sink_callback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) +void device_sink_callback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void* /*pdata*/) { - auto loop = static_cast(pdata); - if(eol) { - pa_threaded_mainloop_signal(loop, 0); + pulse_condvar.notify_all(); return; } @@ -488,7 +497,7 @@ void device_sink_callback(pa_context *UNUSED(context), const pa_sink_info *info, newname += " #"; newname += std::to_string(++count); } - PlaybackDevices.emplace_back(std::move(newname), info->name); + PlaybackDevices.emplace_back(DevMap{std::move(newname), info->name}); DevMap &newentry = PlaybackDevices.back(); TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str()); @@ -498,57 +507,45 @@ void probePlaybackDevices() { PlaybackDevices.clear(); - pa_threaded_mainloop *loop{pa_threaded_mainloop_new()}; - if(loop && pa_threaded_mainloop_start(loop) >= 0) - { - unique_palock palock{loop}; - - pa_context *context{connect_context(loop, AL_FALSE)}; - if(context) - { - pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | - PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE}; + std::unique_lock plock{pulse_lock}; - pa_sample_spec spec; - spec.format = PA_SAMPLE_S16NE; - spec.rate = 44100; - spec.channels = 2; + pa_context *context{connect_context(plock, AL_FALSE)}; + if(!context) return; - pa_stream *stream{pulse_connect_stream(nullptr, loop, context, flags, nullptr, &spec, - nullptr, BackendType::Playback)}; - if(stream) - { - pa_operation *op{pa_context_get_sink_info_by_name(context, - pa_stream_get_device_name(stream), device_sink_callback, loop)}; - wait_for_operation(op, loop); + pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS | + PA_STREAM_DONT_MOVE}; - pa_stream_disconnect(stream); - pa_stream_unref(stream); - stream = nullptr; - } + pa_sample_spec spec{}; + spec.format = PA_SAMPLE_S16NE; + spec.rate = 44100; + spec.channels = 2; - pa_operation *op{pa_context_get_sink_info_list(context, - device_sink_callback, loop)}; - wait_for_operation(op, loop); + pa_stream *stream{pulse_connect_stream(nullptr, plock, context, flags, nullptr, &spec, nullptr, + BackendType::Playback)}; + if(stream) + { + pa_operation *op{pa_context_get_sink_info_by_name(context, + pa_stream_get_device_name(stream), device_sink_callback, nullptr)}; + wait_for_operation(op, plock); - pa_context_disconnect(context); - pa_context_unref(context); - } - palock = unique_palock{}; - pa_threaded_mainloop_stop(loop); + pa_stream_disconnect(stream); + pa_stream_unref(stream); + stream = nullptr; } - if(loop) - pa_threaded_mainloop_free(loop); + + pa_operation *op{pa_context_get_sink_info_list(context, device_sink_callback, nullptr)}; + wait_for_operation(op, plock); + + pa_context_disconnect(context); + pa_context_unref(context); } -void device_source_callback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata) +void device_source_callback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void* /*pdata*/) { - auto loop = static_cast(pdata); - if(eol) { - pa_threaded_mainloop_signal(loop, 0); + pulse_condvar.notify_all(); return; } @@ -570,7 +567,7 @@ void device_source_callback(pa_context *UNUSED(context), const pa_source_info *i newname += " #"; newname += std::to_string(++count); } - CaptureDevices.emplace_back(std::move(newname), info->name); + CaptureDevices.emplace_back(DevMap{std::move(newname), info->name}); DevMap &newentry = CaptureDevices.back(); TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str()); @@ -580,47 +577,37 @@ void probeCaptureDevices() { CaptureDevices.clear(); - pa_threaded_mainloop *loop{pa_threaded_mainloop_new()}; - if(loop && pa_threaded_mainloop_start(loop) >= 0) - { - unique_palock palock{loop}; + std::unique_lock plock{pulse_lock}; - pa_context *context{connect_context(loop, AL_FALSE)}; - if(context) - { - pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | - PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE}; + pa_context *context{connect_context(plock, AL_FALSE)}; + if(!context) return; - pa_sample_spec spec; - spec.format = PA_SAMPLE_S16NE; - spec.rate = 44100; - spec.channels = 1; - - pa_stream *stream{pulse_connect_stream(nullptr, loop, context, flags, nullptr, &spec, - nullptr, BackendType::Capture)}; - if(stream) - { - pa_operation *op{pa_context_get_source_info_by_name(context, - pa_stream_get_device_name(stream), device_source_callback, loop)}; - wait_for_operation(op, loop); + pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS | + PA_STREAM_DONT_MOVE}; - pa_stream_disconnect(stream); - pa_stream_unref(stream); - stream = nullptr; - } + pa_sample_spec spec{}; + spec.format = PA_SAMPLE_S16NE; + spec.rate = 44100; + spec.channels = 1; - pa_operation *op{pa_context_get_source_info_list(context, - device_source_callback, loop)}; - wait_for_operation(op, loop); + pa_stream *stream{pulse_connect_stream(nullptr, plock, context, flags, nullptr, &spec, nullptr, + BackendType::Capture)}; + if(stream) + { + pa_operation *op{pa_context_get_source_info_by_name(context, + pa_stream_get_device_name(stream), device_source_callback, nullptr)}; + wait_for_operation(op, plock); - pa_context_disconnect(context); - pa_context_unref(context); - } - palock.unlock(); - pa_threaded_mainloop_stop(loop); + pa_stream_disconnect(stream); + pa_stream_unref(stream); + stream = nullptr; } - if(loop) - pa_threaded_mainloop_free(loop); + + pa_operation *op{pa_context_get_source_info_list(context, device_source_callback, nullptr)}; + wait_for_operation(op, plock); + + pa_context_disconnect(context); + pa_context_unref(context); } @@ -662,12 +649,9 @@ struct PulsePlayback final : public BackendBase { pa_buffer_attr mAttr; pa_sample_spec mSpec; - pa_threaded_mainloop *mLoop{nullptr}; - pa_stream *mStream{nullptr}; pa_context *mContext{nullptr}; - ALuint mBufferSize{0u}; ALuint mFrameSize{0u}; static constexpr inline const char *CurrentPrefix() noexcept { return "PulsePlayback::"; } @@ -676,11 +660,10 @@ struct PulsePlayback final : public BackendBase { PulsePlayback::~PulsePlayback() { - if(!mLoop) + if(!mContext) return; - pulse_close(mLoop, mContext, mStream); - mLoop = nullptr; + pulse_close(mContext, mStream); mContext = nullptr; mStream = nullptr; } @@ -698,9 +681,6 @@ void PulsePlayback::bufferAttrCallback(pa_stream *stream) */ mAttr = *(pa_stream_get_buffer_attr(stream)); TRACE("minreq=%d, tlength=%d, prebuf=%d\n", mAttr.minreq, mAttr.tlength, mAttr.prebuf); - - const ALuint num_periods{(mAttr.tlength + mAttr.minreq/2u) / mAttr.minreq}; - mBufferSize = maxu(num_periods, 2u) * mAttr.minreq; } void PulsePlayback::contextStateCallbackC(pa_context *context, void *pdata) @@ -713,7 +693,7 @@ void PulsePlayback::contextStateCallback(pa_context *context) ERR("Received context failure!\n"); aluHandleDisconnect(mDevice, "Playback state failure"); } - pa_threaded_mainloop_signal(mLoop, 0); + pulse_condvar.notify_all(); } void PulsePlayback::streamStateCallbackC(pa_stream *stream, void *pdata) @@ -726,7 +706,7 @@ void PulsePlayback::streamStateCallback(pa_stream *stream) ERR("Received stream failure!\n"); aluHandleDisconnect(mDevice, "Playback stream failure"); } - pa_threaded_mainloop_signal(mLoop, 0); + pulse_condvar.notify_all(); } void PulsePlayback::streamWriteCallbackC(pa_stream *stream, size_t nbytes, void *pdata) @@ -786,7 +766,7 @@ void PulsePlayback::sinkInfoCallback(pa_context* UNUSED(context), const pa_sink_ if(eol) { - pa_threaded_mainloop_signal(mLoop, 0); + pulse_condvar.notify_all(); return; } @@ -819,7 +799,7 @@ void PulsePlayback::sinkNameCallback(pa_context* UNUSED(context), const pa_sink_ { if(eol) { - pa_threaded_mainloop_signal(mLoop, 0); + pulse_condvar.notify_all(); return; } mDevice->DeviceName = info->description; @@ -855,13 +835,12 @@ ALCenum PulsePlayback::open(const ALCchar *name) dev_name = iter->name.c_str(); } - std::tie(mLoop, mContext) = pulse_open(&PulsePlayback::contextStateCallbackC, this); - if(!mLoop) return ALC_INVALID_VALUE; + mContext = pulse_open(&PulsePlayback::contextStateCallbackC, this); + if(!mContext) return ALC_INVALID_VALUE; - unique_palock palock{mLoop}; + std::unique_lock plock{pulse_lock}; - pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | - PA_STREAM_FIX_CHANNELS}; + pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS}; if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 0)) flags |= PA_STREAM_DONT_MOVE; @@ -876,13 +855,12 @@ ALCenum PulsePlayback::open(const ALCchar *name) pulse_name = getenv("ALSOFT_PULSE_DEFAULT"); if(pulse_name && !pulse_name[0]) pulse_name = nullptr; } - mStream = pulse_connect_stream(pulse_name, mLoop, mContext, flags, nullptr, &spec, nullptr, + mStream = pulse_connect_stream(pulse_name, plock, mContext, flags, nullptr, &spec, nullptr, BackendType::Playback); if(!mStream) { - palock = unique_palock{}; - pulse_close(mLoop, mContext, mStream); - mLoop = nullptr; + plock.unlock(); + pulse_close(mContext, mStream); mContext = nullptr; return ALC_INVALID_VALUE; } @@ -894,7 +872,7 @@ ALCenum PulsePlayback::open(const ALCchar *name) { pa_operation *op{pa_context_get_sink_info_by_name(mContext, mDeviceName.c_str(), &PulsePlayback::sinkNameCallbackC, this)}; - wait_for_operation(op, mLoop); + wait_for_operation(op, plock); } else mDevice->DeviceName = dev_name; @@ -904,7 +882,7 @@ ALCenum PulsePlayback::open(const ALCchar *name) ALCboolean PulsePlayback::reset() { - unique_palock palock{mLoop}; + std::unique_lock plock{pulse_lock}; if(mStream) { @@ -919,7 +897,7 @@ ALCboolean PulsePlayback::reset() pa_operation *op{pa_context_get_sink_info_by_name(mContext, mDeviceName.c_str(), &PulsePlayback::sinkInfoCallbackC, this)}; - wait_for_operation(op, mLoop); + wait_for_operation(op, plock); pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_EARLY_REQUESTS}; @@ -1013,7 +991,7 @@ ALCboolean PulsePlayback::reset() mAttr.minreq = mDevice->UpdateSize * pa_frame_size(&mSpec); mAttr.fragsize = -1; - mStream = pulse_connect_stream(mDeviceName.c_str(), mLoop, mContext, flags, &mAttr, &mSpec, + mStream = pulse_connect_stream(mDeviceName.c_str(), plock, mContext, flags, &mAttr, &mSpec, &chanmap, BackendType::Playback); if(!mStream) return ALC_FALSE; @@ -1039,8 +1017,8 @@ ALCboolean PulsePlayback::reset() mAttr.prebuf = 0; mAttr.minreq = perlen * mFrameSize; - op = pa_stream_set_buffer_attr(mStream, &mAttr, stream_success_callback, mLoop); - wait_for_operation(op, mLoop); + op = pa_stream_set_buffer_attr(mStream, &mAttr, stream_success_callback, nullptr); + wait_for_operation(op, plock); mDevice->Frequency = mSpec.rate; } @@ -1070,22 +1048,22 @@ ALCboolean PulsePlayback::reset() ALCboolean PulsePlayback::start() { - unique_palock palock{mLoop}; + std::unique_lock plock{pulse_lock}; pa_stream_set_write_callback(mStream, &PulsePlayback::streamWriteCallbackC, this); - pa_operation *op{pa_stream_cork(mStream, 0, stream_success_callback, mLoop)}; - wait_for_operation(op, mLoop); + pa_operation *op{pa_stream_cork(mStream, 0, stream_success_callback, nullptr)}; + wait_for_operation(op, plock); return ALC_TRUE; } void PulsePlayback::stop() { - unique_palock palock{mLoop}; + std::unique_lock plock{pulse_lock}; pa_stream_set_write_callback(mStream, nullptr, nullptr); - pa_operation *op{pa_stream_cork(mStream, 1, stream_success_callback, mLoop)}; - wait_for_operation(op, mLoop); + pa_operation *op{pa_stream_cork(mStream, 1, stream_success_callback, nullptr)}; + wait_for_operation(op, plock); } @@ -1095,7 +1073,7 @@ ClockLatency PulsePlayback::getClockLatency() pa_usec_t latency; int neg, err; - { palock_guard _{mLoop}; + { std::lock_guard _{pulse_lock}; ret.ClockTime = GetDeviceClockTime(mDevice); err = pa_stream_get_latency(mStream, &latency, &neg); } @@ -1120,10 +1098,10 @@ ClockLatency PulsePlayback::getClockLatency() void PulsePlayback::lock() -{ pa_threaded_mainloop_lock(mLoop); } +{ pulse_lock.lock(); } void PulsePlayback::unlock() -{ pa_threaded_mainloop_unlock(mLoop); } +{ pulse_lock.unlock(); } struct PulseCapture final : public BackendBase { @@ -1162,8 +1140,6 @@ struct PulseCapture final : public BackendBase { pa_buffer_attr mAttr{}; pa_sample_spec mSpec{}; - pa_threaded_mainloop *mLoop{nullptr}; - pa_stream *mStream{nullptr}; pa_context *mContext{nullptr}; @@ -1173,10 +1149,10 @@ struct PulseCapture final : public BackendBase { PulseCapture::~PulseCapture() { - if(!mLoop) + if(!mContext) return; - pulse_close(mLoop, mContext, mStream); - mLoop = nullptr; + + pulse_close(mContext, mStream); mContext = nullptr; mStream = nullptr; } @@ -1191,7 +1167,7 @@ void PulseCapture::contextStateCallback(pa_context *context) ERR("Received context failure!\n"); aluHandleDisconnect(mDevice, "Capture state failure"); } - pa_threaded_mainloop_signal(mLoop, 0); + pulse_condvar.notify_all(); } void PulseCapture::streamStateCallbackC(pa_stream *stream, void *pdata) @@ -1204,7 +1180,7 @@ void PulseCapture::streamStateCallback(pa_stream *stream) ERR("Received stream failure!\n"); aluHandleDisconnect(mDevice, "Capture stream failure"); } - pa_threaded_mainloop_signal(mLoop, 0); + pulse_condvar.notify_all(); } void PulseCapture::sourceNameCallbackC(pa_context *context, const pa_source_info *info, int eol, void *pdata) @@ -1214,7 +1190,7 @@ void PulseCapture::sourceNameCallback(pa_context* UNUSED(context), const pa_sour { if(eol) { - pa_threaded_mainloop_signal(mLoop, 0); + pulse_condvar.notify_all(); return; } mDevice->DeviceName = info->description; @@ -1248,10 +1224,10 @@ ALCenum PulseCapture::open(const ALCchar *name) mDevice->DeviceName = iter->name; } - std::tie(mLoop, mContext) = pulse_open(&PulseCapture::contextStateCallbackC, this); - if(!mLoop) return ALC_INVALID_VALUE; + mContext = pulse_open(&PulseCapture::contextStateCallbackC, this); + if(!mContext) return ALC_INVALID_VALUE; - unique_palock palock{mLoop}; + std::unique_lock plock{pulse_lock}; switch(mDevice->FmtType) { @@ -1338,7 +1314,7 @@ ALCenum PulseCapture::open(const ALCchar *name) flags |= PA_STREAM_DONT_MOVE; TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); - mStream = pulse_connect_stream(pulse_name, mLoop, mContext, flags, &mAttr, &mSpec, &chanmap, + mStream = pulse_connect_stream(pulse_name, plock, mContext, flags, &mAttr, &mSpec, &chanmap, BackendType::Capture); if(!mStream) return ALC_INVALID_VALUE; @@ -1350,7 +1326,7 @@ ALCenum PulseCapture::open(const ALCchar *name) { pa_operation *op{pa_context_get_source_info_by_name(mContext, mDeviceName.c_str(), &PulseCapture::sourceNameCallbackC, this)}; - wait_for_operation(op, mLoop); + wait_for_operation(op, plock); } return ALC_NO_ERROR; @@ -1358,17 +1334,17 @@ ALCenum PulseCapture::open(const ALCchar *name) ALCboolean PulseCapture::start() { - palock_guard _{mLoop}; - pa_operation *op{pa_stream_cork(mStream, 0, stream_success_callback, mLoop)}; - wait_for_operation(op, mLoop); + std::unique_lock plock{pulse_lock}; + pa_operation *op{pa_stream_cork(mStream, 0, stream_success_callback, nullptr)}; + wait_for_operation(op, plock); return ALC_TRUE; } void PulseCapture::stop() { - palock_guard _{mLoop}; - pa_operation *op{pa_stream_cork(mStream, 1, stream_success_callback, mLoop)}; - wait_for_operation(op, mLoop); + std::unique_lock plock{pulse_lock}; + pa_operation *op{pa_stream_cork(mStream, 1, stream_success_callback, nullptr)}; + wait_for_operation(op, plock); } ALCenum PulseCapture::captureSamples(ALCvoid *buffer, ALCuint samples) @@ -1378,7 +1354,7 @@ ALCenum PulseCapture::captureSamples(ALCvoid *buffer, ALCuint samples) /* Capture is done in fragment-sized chunks, so we loop until we get all * that's available */ mLastReadable -= todo; - unique_palock palock{mLoop}; + std::lock_guard _{pulse_lock}; while(todo > 0) { size_t rem{todo}; @@ -1416,7 +1392,6 @@ ALCenum PulseCapture::captureSamples(ALCvoid *buffer, ALCuint samples) mCapLen = 0; } } - palock.unlock(); if(todo > 0) memset(buffer, ((mDevice->FmtType==DevFmtUByte) ? 0x80 : 0), todo); @@ -1429,7 +1404,7 @@ ALCuint PulseCapture::availableSamples() if(mDevice->Connected.load(std::memory_order_acquire)) { - palock_guard _{mLoop}; + std::lock_guard _{pulse_lock}; size_t got{pa_stream_readable_size(mStream)}; if(static_cast(got) < 0) { @@ -1452,7 +1427,7 @@ ClockLatency PulseCapture::getClockLatency() pa_usec_t latency; int neg, err; - { palock_guard _{mLoop}; + { std::lock_guard _{pulse_lock}; ret.ClockTime = GetDeviceClockTime(mDevice); err = pa_stream_get_latency(mStream, &latency, &neg); } @@ -1472,10 +1447,10 @@ ClockLatency PulseCapture::getClockLatency() void PulseCapture::lock() -{ pa_threaded_mainloop_lock(mLoop); } +{ pulse_lock.lock(); } void PulseCapture::unlock() -{ pa_threaded_mainloop_unlock(mLoop); } +{ pulse_lock.unlock(); } } // namespace @@ -1592,35 +1567,24 @@ bool PulseBackendFactory::init() if(!GetConfigValueBool(nullptr, "pulse", "spawn-server", 1)) pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN; - bool ret{false}; - pa_threaded_mainloop *loop{pa_threaded_mainloop_new()}; - if(loop && pa_threaded_mainloop_start(loop) >= 0) - { - unique_palock palock{loop}; - pa_context *context{connect_context(loop, AL_TRUE)}; - if(context) - { - ret = true; - - /* Some libraries (Phonon, Qt) set some pulseaudio properties - * through environment variables, which causes all streams in the - * process to inherit them. This attempts to filter those - * properties out by setting them to 0-length data. - */ - prop_filter = pa_proplist_new(); - pa_proplist_set(prop_filter, PA_PROP_MEDIA_ROLE, nullptr, 0); - pa_proplist_set(prop_filter, "phonon.streamid", nullptr, 0); - - pa_context_disconnect(context); - pa_context_unref(context); - } - palock.unlock(); - pa_threaded_mainloop_stop(loop); - } - if(loop) - pa_threaded_mainloop_free(loop); + std::unique_lock plock{pulse_lock}; - return ret; + pa_context *context{connect_context(plock, AL_TRUE)}; + if(!context) return false; + + /* Some libraries (Phonon, Qt) set some pulseaudio properties through + * environment variables, which causes all streams in the process to + * inherit them. This attempts to filter those properties out by setting + * them to 0-length data. + */ + prop_filter = pa_proplist_new(); + pa_proplist_set(prop_filter, PA_PROP_MEDIA_ROLE, nullptr, 0); + pa_proplist_set(prop_filter, "phonon.streamid", nullptr, 0); + + pa_context_disconnect(context); + pa_context_unref(context); + + return true; } bool PulseBackendFactory::querySupport(BackendType type) -- cgit v1.2.3 From 150dc92f68bf10783344d81f57acff59aaf79369 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Apr 2019 13:06:39 -0700 Subject: Remove unused pa_threaded* functions --- Alc/backends/pulseaudio.cpp | 83 --------------------------------------------- 1 file changed, 83 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index aaf5f083..58f075c8 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -54,16 +54,9 @@ MAKE_FUNC(pa_stream_drop); MAKE_FUNC(pa_strerror); MAKE_FUNC(pa_context_get_state); MAKE_FUNC(pa_stream_get_state); -MAKE_FUNC(pa_threaded_mainloop_signal); MAKE_FUNC(pa_stream_peek); -MAKE_FUNC(pa_threaded_mainloop_wait); -MAKE_FUNC(pa_threaded_mainloop_unlock); -MAKE_FUNC(pa_threaded_mainloop_in_thread); MAKE_FUNC(pa_context_new); -MAKE_FUNC(pa_threaded_mainloop_stop); MAKE_FUNC(pa_context_disconnect); -MAKE_FUNC(pa_threaded_mainloop_start); -MAKE_FUNC(pa_threaded_mainloop_get_api); MAKE_FUNC(pa_context_set_state_callback); MAKE_FUNC(pa_stream_write); MAKE_FUNC(pa_xfree); @@ -78,13 +71,10 @@ MAKE_FUNC(pa_stream_get_device_name); MAKE_FUNC(pa_stream_get_latency); MAKE_FUNC(pa_path_get_filename); MAKE_FUNC(pa_get_binary_name); -MAKE_FUNC(pa_threaded_mainloop_free); MAKE_FUNC(pa_context_errno); MAKE_FUNC(pa_xmalloc); MAKE_FUNC(pa_stream_unref); -MAKE_FUNC(pa_threaded_mainloop_accept); MAKE_FUNC(pa_stream_set_write_callback); -MAKE_FUNC(pa_threaded_mainloop_new); MAKE_FUNC(pa_context_connect); MAKE_FUNC(pa_stream_set_buffer_attr); MAKE_FUNC(pa_stream_get_buffer_attr); @@ -96,7 +86,6 @@ MAKE_FUNC(pa_stream_set_moved_callback); MAKE_FUNC(pa_stream_set_underflow_callback); MAKE_FUNC(pa_stream_new_with_proplist); MAKE_FUNC(pa_stream_disconnect); -MAKE_FUNC(pa_threaded_mainloop_lock); MAKE_FUNC(pa_channel_map_init_auto); MAKE_FUNC(pa_channel_map_parse); MAKE_FUNC(pa_channel_map_snprint); @@ -124,16 +113,9 @@ MAKE_FUNC(pa_stream_begin_write); #define pa_strerror ppa_strerror #define pa_context_get_state ppa_context_get_state #define pa_stream_get_state ppa_stream_get_state -#define pa_threaded_mainloop_signal ppa_threaded_mainloop_signal #define pa_stream_peek ppa_stream_peek -#define pa_threaded_mainloop_wait ppa_threaded_mainloop_wait -#define pa_threaded_mainloop_unlock ppa_threaded_mainloop_unlock -#define pa_threaded_mainloop_in_thread ppa_threaded_mainloop_in_thread #define pa_context_new ppa_context_new -#define pa_threaded_mainloop_stop ppa_threaded_mainloop_stop #define pa_context_disconnect ppa_context_disconnect -#define pa_threaded_mainloop_start ppa_threaded_mainloop_start -#define pa_threaded_mainloop_get_api ppa_threaded_mainloop_get_api #define pa_context_set_state_callback ppa_context_set_state_callback #define pa_stream_write ppa_stream_write #define pa_xfree ppa_xfree @@ -148,13 +130,10 @@ MAKE_FUNC(pa_stream_begin_write); #define pa_stream_get_latency ppa_stream_get_latency #define pa_path_get_filename ppa_path_get_filename #define pa_get_binary_name ppa_get_binary_name -#define pa_threaded_mainloop_free ppa_threaded_mainloop_free #define pa_context_errno ppa_context_errno #define pa_xmalloc ppa_xmalloc #define pa_stream_unref ppa_stream_unref -#define pa_threaded_mainloop_accept ppa_threaded_mainloop_accept #define pa_stream_set_write_callback ppa_stream_set_write_callback -#define pa_threaded_mainloop_new ppa_threaded_mainloop_new #define pa_context_connect ppa_context_connect #define pa_stream_set_buffer_attr ppa_stream_set_buffer_attr #define pa_stream_get_buffer_attr ppa_stream_get_buffer_attr @@ -166,7 +145,6 @@ MAKE_FUNC(pa_stream_begin_write); #define pa_stream_set_underflow_callback ppa_stream_set_underflow_callback #define pa_stream_new_with_proplist ppa_stream_new_with_proplist #define pa_stream_disconnect ppa_stream_disconnect -#define pa_threaded_mainloop_lock ppa_threaded_mainloop_lock #define pa_channel_map_init_auto ppa_channel_map_init_auto #define pa_channel_map_parse ppa_channel_map_parse #define pa_channel_map_snprint ppa_channel_map_snprint @@ -210,56 +188,6 @@ inline pa_stream_flags_t& operator&=(pa_stream_flags_t &lhs, int rhs) } -class palock_guard { - pa_threaded_mainloop *mLoop; - -public: - explicit palock_guard(pa_threaded_mainloop *loop) : mLoop(loop) - { pa_threaded_mainloop_lock(mLoop); } - ~palock_guard() { pa_threaded_mainloop_unlock(mLoop); } - - palock_guard(const palock_guard&) = delete; - palock_guard& operator=(const palock_guard&) = delete; -}; - -class unique_palock { - pa_threaded_mainloop *mLoop{nullptr}; - bool mLocked{false}; - -public: - unique_palock() noexcept = default; - explicit unique_palock(pa_threaded_mainloop *loop) : mLoop(loop) - { - pa_threaded_mainloop_lock(mLoop); - mLocked = true; - } - unique_palock(unique_palock&& rhs) : mLoop(rhs.mLoop), mLocked(rhs.mLocked) - { rhs.mLoop = nullptr; rhs.mLocked = false; } - ~unique_palock() { if(mLocked) pa_threaded_mainloop_unlock(mLoop); } - - unique_palock& operator=(const unique_palock&) = delete; - unique_palock& operator=(unique_palock&& rhs) - { - if(mLocked) - pa_threaded_mainloop_unlock(mLoop); - mLoop = rhs.mLoop; rhs.mLoop = nullptr; - mLocked = rhs.mLocked; rhs.mLocked = false; - return *this; - } - - void lock() - { - pa_threaded_mainloop_lock(mLoop); - mLocked = true; - } - void unlock() - { - mLocked = false; - pa_threaded_mainloop_unlock(mLoop); - } -}; - - /* Global flags and properties */ pa_context_flags_t pulse_ctx_flags; pa_proplist *prop_filter; @@ -1491,16 +1419,9 @@ bool PulseBackendFactory::init() LOAD_FUNC(pa_strerror); LOAD_FUNC(pa_context_get_state); LOAD_FUNC(pa_stream_get_state); - LOAD_FUNC(pa_threaded_mainloop_signal); LOAD_FUNC(pa_stream_peek); - LOAD_FUNC(pa_threaded_mainloop_wait); - LOAD_FUNC(pa_threaded_mainloop_unlock); - LOAD_FUNC(pa_threaded_mainloop_in_thread); LOAD_FUNC(pa_context_new); - LOAD_FUNC(pa_threaded_mainloop_stop); LOAD_FUNC(pa_context_disconnect); - LOAD_FUNC(pa_threaded_mainloop_start); - LOAD_FUNC(pa_threaded_mainloop_get_api); LOAD_FUNC(pa_context_set_state_callback); LOAD_FUNC(pa_stream_write); LOAD_FUNC(pa_xfree); @@ -1515,13 +1436,10 @@ bool PulseBackendFactory::init() LOAD_FUNC(pa_stream_get_latency); LOAD_FUNC(pa_path_get_filename); LOAD_FUNC(pa_get_binary_name); - LOAD_FUNC(pa_threaded_mainloop_free); LOAD_FUNC(pa_context_errno); LOAD_FUNC(pa_xmalloc); LOAD_FUNC(pa_stream_unref); - LOAD_FUNC(pa_threaded_mainloop_accept); LOAD_FUNC(pa_stream_set_write_callback); - LOAD_FUNC(pa_threaded_mainloop_new); LOAD_FUNC(pa_context_connect); LOAD_FUNC(pa_stream_set_buffer_attr); LOAD_FUNC(pa_stream_get_buffer_attr); @@ -1533,7 +1451,6 @@ bool PulseBackendFactory::init() LOAD_FUNC(pa_stream_set_underflow_callback); LOAD_FUNC(pa_stream_new_with_proplist); LOAD_FUNC(pa_stream_disconnect); - LOAD_FUNC(pa_threaded_mainloop_lock); LOAD_FUNC(pa_channel_map_init_auto); LOAD_FUNC(pa_channel_map_parse); LOAD_FUNC(pa_channel_map_snprint); -- cgit v1.2.3 From c135629eae544b0e7785803b98987c1ab1eb95ca Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Apr 2019 13:39:46 -0700 Subject: Remove some ancient PulseAudio KDE/Phonon/Qt hacks Unfortuantely, the relevant KDE bug still seems to exist (streams are forced to KDE's default device after opening, even when they're created with a specific device at user request). I do not know why KDE thinks this is in any way good behavior (the user doesn't get their desired device, nor does the stream get the appropriate format for the device its ultimately put on), but making streams non-movable as a workaround has been a thorn in the side of non-KDE users for too long. C'mon KDE, it's been nearly (if not more than) 7 years now. --- Alc/backends/pulseaudio.cpp | 22 +++++----------------- alsoftrc.sample | 2 +- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 58f075c8..55935423 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -190,8 +190,6 @@ inline pa_stream_flags_t& operator&=(pa_stream_flags_t &lhs, int rhs) /* Global flags and properties */ pa_context_flags_t pulse_ctx_flags; -pa_proplist *prop_filter; - pa_mainloop *pulse_mainloop{nullptr}; @@ -360,9 +358,8 @@ pa_stream *pulse_connect_stream(const char *device_name, std::unique_lock plock{pulse_lock}; pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS}; - if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 0)) + if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 1)) flags |= PA_STREAM_DONT_MOVE; pa_sample_spec spec{}; @@ -829,7 +826,7 @@ ALCboolean PulsePlayback::reset() pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_EARLY_REQUESTS}; - if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 0)) + if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 1)) flags |= PA_STREAM_DONT_MOVE; if(GetConfigValueBool(mDevice->DeviceName.c_str(), "pulse", "adjust-latency", 0)) { @@ -1238,7 +1235,7 @@ ALCenum PulseCapture::open(const ALCchar *name) mAttr.fragsize = minu(samples, 50*mDevice->Frequency/1000) * pa_frame_size(&mSpec); pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_ADJUST_LATENCY}; - if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 0)) + if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 1)) flags |= PA_STREAM_DONT_MOVE; TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); @@ -1489,15 +1486,6 @@ bool PulseBackendFactory::init() pa_context *context{connect_context(plock, AL_TRUE)}; if(!context) return false; - /* Some libraries (Phonon, Qt) set some pulseaudio properties through - * environment variables, which causes all streams in the process to - * inherit them. This attempts to filter those properties out by setting - * them to 0-length data. - */ - prop_filter = pa_proplist_new(); - pa_proplist_set(prop_filter, PA_PROP_MEDIA_ROLE, nullptr, 0); - pa_proplist_set(prop_filter, "phonon.streamid", nullptr, 0); - pa_context_disconnect(context); pa_context_unref(context); diff --git a/alsoftrc.sample b/alsoftrc.sample index 10a59a1f..9b5dd2f9 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -338,7 +338,7 @@ surround71 = # device specifier (seen by applications) will not be updated when this # occurs, and neither will the AL device configuration (sample rate, format, # etc). -#allow-moves = false +#allow-moves = true ## fix-rate: # Specifies whether to match the playback stream's sample rate to the device's -- cgit v1.2.3 From 0577028b65656f6994d4a13d2c1ee9abc1a006da Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Apr 2019 18:01:26 -0700 Subject: Add missing function pointers --- Alc/backends/pulseaudio.cpp | 261 ++++++++++++++++++-------------------------- 1 file changed, 107 insertions(+), 154 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 55935423..3e6bf160 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -45,96 +45,95 @@ namespace { #ifdef HAVE_DYNLOAD -void *pa_handle; +#define PULSE_FUNCS(MAGIC) \ + MAGIC(pa_mainloop_new); \ + MAGIC(pa_mainloop_free); \ + MAGIC(pa_mainloop_set_poll_func); \ + MAGIC(pa_mainloop_run); \ + MAGIC(pa_mainloop_get_api); \ + MAGIC(pa_context_new); \ + MAGIC(pa_context_unref); \ + MAGIC(pa_context_get_state); \ + MAGIC(pa_context_disconnect); \ + MAGIC(pa_context_set_state_callback); \ + MAGIC(pa_context_errno); \ + MAGIC(pa_context_connect); \ + MAGIC(pa_context_get_server_info); \ + MAGIC(pa_context_get_sink_info_by_name); \ + MAGIC(pa_context_get_sink_info_list); \ + MAGIC(pa_context_get_source_info_by_name); \ + MAGIC(pa_context_get_source_info_list); \ + MAGIC(pa_stream_new); \ + MAGIC(pa_stream_unref); \ + MAGIC(pa_stream_drop); \ + MAGIC(pa_stream_get_state); \ + MAGIC(pa_stream_peek); \ + MAGIC(pa_stream_write); \ + MAGIC(pa_stream_connect_record); \ + MAGIC(pa_stream_connect_playback); \ + MAGIC(pa_stream_readable_size); \ + MAGIC(pa_stream_writable_size); \ + MAGIC(pa_stream_is_corked); \ + MAGIC(pa_stream_cork); \ + MAGIC(pa_stream_is_suspended); \ + MAGIC(pa_stream_get_device_name); \ + MAGIC(pa_stream_get_latency); \ + MAGIC(pa_stream_set_write_callback); \ + MAGIC(pa_stream_set_buffer_attr); \ + MAGIC(pa_stream_get_buffer_attr); \ + MAGIC(pa_stream_get_sample_spec); \ + MAGIC(pa_stream_get_time); \ + MAGIC(pa_stream_set_read_callback); \ + MAGIC(pa_stream_set_state_callback); \ + MAGIC(pa_stream_set_moved_callback); \ + MAGIC(pa_stream_set_underflow_callback); \ + MAGIC(pa_stream_new_with_proplist); \ + MAGIC(pa_stream_disconnect); \ + MAGIC(pa_stream_set_buffer_attr_callback); \ + MAGIC(pa_stream_begin_write); \ + MAGIC(pa_channel_map_init_auto); \ + MAGIC(pa_channel_map_parse); \ + MAGIC(pa_channel_map_snprint); \ + MAGIC(pa_channel_map_equal); \ + MAGIC(pa_channel_map_superset); \ + MAGIC(pa_operation_get_state); \ + MAGIC(pa_operation_unref); \ + MAGIC(pa_sample_spec_valid); \ + MAGIC(pa_frame_size); \ + MAGIC(pa_strerror); \ + MAGIC(pa_path_get_filename); \ + MAGIC(pa_get_binary_name); \ + MAGIC(pa_xmalloc); \ + MAGIC(pa_xfree); + +void *pulse_handle; #define MAKE_FUNC(x) decltype(x) * p##x -MAKE_FUNC(pa_context_unref); -MAKE_FUNC(pa_sample_spec_valid); -MAKE_FUNC(pa_frame_size); -MAKE_FUNC(pa_stream_drop); -MAKE_FUNC(pa_strerror); -MAKE_FUNC(pa_context_get_state); -MAKE_FUNC(pa_stream_get_state); -MAKE_FUNC(pa_stream_peek); -MAKE_FUNC(pa_context_new); -MAKE_FUNC(pa_context_disconnect); -MAKE_FUNC(pa_context_set_state_callback); -MAKE_FUNC(pa_stream_write); -MAKE_FUNC(pa_xfree); -MAKE_FUNC(pa_stream_connect_record); -MAKE_FUNC(pa_stream_connect_playback); -MAKE_FUNC(pa_stream_readable_size); -MAKE_FUNC(pa_stream_writable_size); -MAKE_FUNC(pa_stream_is_corked); -MAKE_FUNC(pa_stream_cork); -MAKE_FUNC(pa_stream_is_suspended); -MAKE_FUNC(pa_stream_get_device_name); -MAKE_FUNC(pa_stream_get_latency); -MAKE_FUNC(pa_path_get_filename); -MAKE_FUNC(pa_get_binary_name); -MAKE_FUNC(pa_context_errno); -MAKE_FUNC(pa_xmalloc); -MAKE_FUNC(pa_stream_unref); -MAKE_FUNC(pa_stream_set_write_callback); -MAKE_FUNC(pa_context_connect); -MAKE_FUNC(pa_stream_set_buffer_attr); -MAKE_FUNC(pa_stream_get_buffer_attr); -MAKE_FUNC(pa_stream_get_sample_spec); -MAKE_FUNC(pa_stream_get_time); -MAKE_FUNC(pa_stream_set_read_callback); -MAKE_FUNC(pa_stream_set_state_callback); -MAKE_FUNC(pa_stream_set_moved_callback); -MAKE_FUNC(pa_stream_set_underflow_callback); -MAKE_FUNC(pa_stream_new_with_proplist); -MAKE_FUNC(pa_stream_disconnect); -MAKE_FUNC(pa_channel_map_init_auto); -MAKE_FUNC(pa_channel_map_parse); -MAKE_FUNC(pa_channel_map_snprint); -MAKE_FUNC(pa_channel_map_equal); -MAKE_FUNC(pa_context_get_server_info); -MAKE_FUNC(pa_context_get_sink_info_by_name); -MAKE_FUNC(pa_context_get_sink_info_list); -MAKE_FUNC(pa_context_get_source_info_by_name); -MAKE_FUNC(pa_context_get_source_info_list); -MAKE_FUNC(pa_operation_get_state); -MAKE_FUNC(pa_operation_unref); -MAKE_FUNC(pa_proplist_new); -MAKE_FUNC(pa_proplist_free); -MAKE_FUNC(pa_proplist_set); -MAKE_FUNC(pa_channel_map_superset); -MAKE_FUNC(pa_stream_set_buffer_attr_callback); -MAKE_FUNC(pa_stream_begin_write); +PULSE_FUNCS(MAKE_FUNC) #undef MAKE_FUNC #ifndef IN_IDE_PARSER +#define pa_mainloop_new ppa_mainloop_new +#define pa_mainloop_free ppa_mainloop_free +#define pa_mainloop_set_poll_func ppa_mainloop_set_poll_func +#define pa_mainloop_run ppa_mainloop_run +#define pa_mainloop_get_api ppa_mainloop_get_api +#define pa_context_new ppa_context_new #define pa_context_unref ppa_context_unref -#define pa_sample_spec_valid ppa_sample_spec_valid -#define pa_frame_size ppa_frame_size -#define pa_stream_drop ppa_stream_drop -#define pa_strerror ppa_strerror #define pa_context_get_state ppa_context_get_state -#define pa_stream_get_state ppa_stream_get_state -#define pa_stream_peek ppa_stream_peek -#define pa_context_new ppa_context_new #define pa_context_disconnect ppa_context_disconnect #define pa_context_set_state_callback ppa_context_set_state_callback -#define pa_stream_write ppa_stream_write -#define pa_xfree ppa_xfree -#define pa_stream_connect_record ppa_stream_connect_record -#define pa_stream_connect_playback ppa_stream_connect_playback -#define pa_stream_readable_size ppa_stream_readable_size -#define pa_stream_writable_size ppa_stream_writable_size -#define pa_stream_is_corked ppa_stream_is_corked -#define pa_stream_cork ppa_stream_cork -#define pa_stream_is_suspended ppa_stream_is_suspended -#define pa_stream_get_device_name ppa_stream_get_device_name -#define pa_stream_get_latency ppa_stream_get_latency -#define pa_path_get_filename ppa_path_get_filename -#define pa_get_binary_name ppa_get_binary_name #define pa_context_errno ppa_context_errno -#define pa_xmalloc ppa_xmalloc +#define pa_context_connect ppa_context_connect +#define pa_context_get_server_info ppa_context_get_server_info +#define pa_context_get_sink_info_by_name ppa_context_get_sink_info_by_name +#define pa_context_get_sink_info_list ppa_context_get_sink_info_list +#define pa_context_get_source_info_by_name ppa_context_get_source_info_by_name +#define pa_context_get_source_info_list ppa_context_get_source_info_list +#define pa_stream_new ppa_stream_new #define pa_stream_unref ppa_stream_unref +#define pa_stream_disconnect ppa_stream_disconnect +#define pa_stream_drop ppa_stream_drop #define pa_stream_set_write_callback ppa_stream_set_write_callback -#define pa_context_connect ppa_context_connect #define pa_stream_set_buffer_attr ppa_stream_set_buffer_attr #define pa_stream_get_buffer_attr ppa_stream_get_buffer_attr #define pa_stream_get_sample_spec ppa_stream_get_sample_spec @@ -143,25 +142,34 @@ MAKE_FUNC(pa_stream_begin_write); #define pa_stream_set_state_callback ppa_stream_set_state_callback #define pa_stream_set_moved_callback ppa_stream_set_moved_callback #define pa_stream_set_underflow_callback ppa_stream_set_underflow_callback -#define pa_stream_new_with_proplist ppa_stream_new_with_proplist -#define pa_stream_disconnect ppa_stream_disconnect +#define pa_stream_connect_record ppa_stream_connect_record +#define pa_stream_connect_playback ppa_stream_connect_playback +#define pa_stream_readable_size ppa_stream_readable_size +#define pa_stream_writable_size ppa_stream_writable_size +#define pa_stream_is_corked ppa_stream_is_corked +#define pa_stream_cork ppa_stream_cork +#define pa_stream_is_suspended ppa_stream_is_suspended +#define pa_stream_get_device_name ppa_stream_get_device_name +#define pa_stream_get_latency ppa_stream_get_latency +#define pa_stream_set_buffer_attr_callback ppa_stream_set_buffer_attr_callback +#define pa_stream_begin_write ppa_stream_begin_write*/ #define pa_channel_map_init_auto ppa_channel_map_init_auto #define pa_channel_map_parse ppa_channel_map_parse #define pa_channel_map_snprint ppa_channel_map_snprint #define pa_channel_map_equal ppa_channel_map_equal -#define pa_context_get_server_info ppa_context_get_server_info -#define pa_context_get_sink_info_by_name ppa_context_get_sink_info_by_name -#define pa_context_get_sink_info_list ppa_context_get_sink_info_list -#define pa_context_get_source_info_by_name ppa_context_get_source_info_by_name -#define pa_context_get_source_info_list ppa_context_get_source_info_list +#define pa_channel_map_superset ppa_channel_map_superset #define pa_operation_get_state ppa_operation_get_state #define pa_operation_unref ppa_operation_unref -#define pa_proplist_new ppa_proplist_new -#define pa_proplist_free ppa_proplist_free -#define pa_proplist_set ppa_proplist_set -#define pa_channel_map_superset ppa_channel_map_superset -#define pa_stream_set_buffer_attr_callback ppa_stream_set_buffer_attr_callback -#define pa_stream_begin_write ppa_stream_begin_write +#define pa_sample_spec_valid ppa_sample_spec_valid +#define pa_frame_size ppa_frame_size +#define pa_strerror ppa_strerror +#define pa_stream_get_state ppa_stream_get_state +#define pa_stream_peek ppa_stream_peek +#define pa_stream_write ppa_stream_write +#define pa_xfree ppa_xfree +#define pa_path_get_filename ppa_path_get_filename +#define pa_get_binary_name ppa_get_binary_name +#define pa_xmalloc ppa_xmalloc #endif /* IN_IDE_PARSER */ #endif @@ -1383,7 +1391,7 @@ void PulseCapture::unlock() bool PulseBackendFactory::init() { #ifdef HAVE_DYNLOAD - if(!pa_handle) + if(!pulse_handle) { bool ret{true}; std::string missing_funcs; @@ -1395,83 +1403,28 @@ bool PulseBackendFactory::init() #else #define PALIB "libpulse.so.0" #endif - pa_handle = LoadLib(PALIB); - if(!pa_handle) + pulse_handle = LoadLib(PALIB); + if(!pulse_handle) { WARN("Failed to load %s\n", PALIB); return false; } #define LOAD_FUNC(x) do { \ - p##x = reinterpret_cast(GetSymbol(pa_handle, #x)); \ + p##x = reinterpret_cast(GetSymbol(pulse_handle, #x)); \ if(!(p##x)) { \ ret = false; \ missing_funcs += "\n" #x; \ } \ } while(0) - LOAD_FUNC(pa_context_unref); - LOAD_FUNC(pa_sample_spec_valid); - LOAD_FUNC(pa_stream_drop); - LOAD_FUNC(pa_frame_size); - LOAD_FUNC(pa_strerror); - LOAD_FUNC(pa_context_get_state); - LOAD_FUNC(pa_stream_get_state); - LOAD_FUNC(pa_stream_peek); - LOAD_FUNC(pa_context_new); - LOAD_FUNC(pa_context_disconnect); - LOAD_FUNC(pa_context_set_state_callback); - LOAD_FUNC(pa_stream_write); - LOAD_FUNC(pa_xfree); - LOAD_FUNC(pa_stream_connect_record); - LOAD_FUNC(pa_stream_connect_playback); - LOAD_FUNC(pa_stream_readable_size); - LOAD_FUNC(pa_stream_writable_size); - LOAD_FUNC(pa_stream_is_corked); - LOAD_FUNC(pa_stream_cork); - LOAD_FUNC(pa_stream_is_suspended); - LOAD_FUNC(pa_stream_get_device_name); - LOAD_FUNC(pa_stream_get_latency); - LOAD_FUNC(pa_path_get_filename); - LOAD_FUNC(pa_get_binary_name); - LOAD_FUNC(pa_context_errno); - LOAD_FUNC(pa_xmalloc); - LOAD_FUNC(pa_stream_unref); - LOAD_FUNC(pa_stream_set_write_callback); - LOAD_FUNC(pa_context_connect); - LOAD_FUNC(pa_stream_set_buffer_attr); - LOAD_FUNC(pa_stream_get_buffer_attr); - LOAD_FUNC(pa_stream_get_sample_spec); - LOAD_FUNC(pa_stream_get_time); - LOAD_FUNC(pa_stream_set_read_callback); - LOAD_FUNC(pa_stream_set_state_callback); - LOAD_FUNC(pa_stream_set_moved_callback); - LOAD_FUNC(pa_stream_set_underflow_callback); - LOAD_FUNC(pa_stream_new_with_proplist); - LOAD_FUNC(pa_stream_disconnect); - LOAD_FUNC(pa_channel_map_init_auto); - LOAD_FUNC(pa_channel_map_parse); - LOAD_FUNC(pa_channel_map_snprint); - LOAD_FUNC(pa_channel_map_equal); - LOAD_FUNC(pa_context_get_server_info); - LOAD_FUNC(pa_context_get_sink_info_by_name); - LOAD_FUNC(pa_context_get_sink_info_list); - LOAD_FUNC(pa_context_get_source_info_by_name); - LOAD_FUNC(pa_context_get_source_info_list); - LOAD_FUNC(pa_operation_get_state); - LOAD_FUNC(pa_operation_unref); - LOAD_FUNC(pa_proplist_new); - LOAD_FUNC(pa_proplist_free); - LOAD_FUNC(pa_proplist_set); - LOAD_FUNC(pa_channel_map_superset); - LOAD_FUNC(pa_stream_set_buffer_attr_callback); - LOAD_FUNC(pa_stream_begin_write); + PULSE_FUNCS(LOAD_FUNC) #undef LOAD_FUNC if(!ret) { WARN("Missing expected functions:%s\n", missing_funcs.c_str()); - CloseLib(pa_handle); - pa_handle = nullptr; + CloseLib(pulse_handle); + pulse_handle = nullptr; return false; } } -- cgit v1.2.3 From 014936ceff04dbc5075213d0e3002ebbc57524fb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Apr 2019 21:25:42 -0700 Subject: Be more robust with PulseAudio capture Particularly, handle "holes" in the record stream and premature end-of-buffer. Also don't bail out when capturing while disconnected (the extension says it should provide anything it previously reported available, going to silence for anything no longer readable). --- Alc/backends/pulseaudio.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 3e6bf160..f3d5d453 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -1290,34 +1290,37 @@ ALCenum PulseCapture::captureSamples(ALCvoid *buffer, ALCuint samples) std::lock_guard _{pulse_lock}; while(todo > 0) { - size_t rem{todo}; - if(mCapLen == 0) { - pa_stream_state_t state{pa_stream_get_state(mStream)}; - if(!PA_STREAM_IS_GOOD(state)) + if(UNLIKELY(!mDevice->Connected.load(std::memory_order_acquire))) + break; + const pa_stream_state_t state{pa_stream_get_state(mStream)}; + if(UNLIKELY(!PA_STREAM_IS_GOOD(state))) { aluHandleDisconnect(mDevice, "Bad capture state: %u", state); - return ALC_INVALID_DEVICE; + break; } - if(pa_stream_peek(mStream, &mCapStore, &mCapLen) < 0) + if(UNLIKELY(pa_stream_peek(mStream, &mCapStore, &mCapLen) < 0)) { - ERR("pa_stream_peek() failed: %s\n", - pa_strerror(pa_context_errno(mContext))); aluHandleDisconnect(mDevice, "Failed retrieving capture samples: %s", pa_strerror(pa_context_errno(mContext))); - return ALC_INVALID_DEVICE; + break; } + if(mCapLen == 0) break; mCapRemain = mCapLen; } - rem = minz(rem, mCapRemain); - memcpy(buffer, mCapStore, rem); + const size_t rem{minz(todo, mCapRemain)}; + if(LIKELY(mCapStore)) + memcpy(buffer, mCapStore, rem); + else + memset(buffer, ((mDevice->FmtType==DevFmtUByte) ? 0x80 : 0), rem); buffer = static_cast(buffer) + rem; todo -= rem; - mCapStore = reinterpret_cast(mCapStore) + rem; + if(LIKELY(mCapStore)) + mCapStore = reinterpret_cast(mCapStore) + rem; mCapRemain -= rem; if(mCapRemain == 0) { -- cgit v1.2.3 From ec869234f7f69887ca02ea0982d18e8c5d3195d2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Apr 2019 08:51:50 -0700 Subject: Remove restrict from in+out parameters --- Alc/filters/splitter.cpp | 6 +++--- Alc/filters/splitter.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Alc/filters/splitter.cpp b/Alc/filters/splitter.cpp index 58a5029b..8b1a4db4 100644 --- a/Alc/filters/splitter.cpp +++ b/Alc/filters/splitter.cpp @@ -61,7 +61,7 @@ void BandSplitterR::process(Real *hpout, Real *lpout, const Real *input, c } template -void BandSplitterR::applyHfScale(Real *RESTRICT samples, const Real hfscale, const int count) +void BandSplitterR::applyHfScale(Real *samples, const Real hfscale, const int count) { ASSUME(count > 0); @@ -112,7 +112,7 @@ void SplitterAllpassR::init(Real f0norm) } template -void SplitterAllpassR::process(Real *RESTRICT samples, int count) +void SplitterAllpassR::process(Real *samples, int count) { ASSUME(count > 0); @@ -120,7 +120,7 @@ void SplitterAllpassR::process(Real *RESTRICT samples, int count) Real z1{this->z1}; auto proc_sample = [coeff,&z1](const Real in) noexcept -> Real { - Real out{in*coeff + z1}; + const Real out{in*coeff + z1}; z1 = in - out*coeff; return out; }; diff --git a/Alc/filters/splitter.h b/Alc/filters/splitter.h index ccb4f104..669d9d03 100644 --- a/Alc/filters/splitter.h +++ b/Alc/filters/splitter.h @@ -17,7 +17,7 @@ public: void init(Real f0norm); void clear() noexcept { lp_z1 = lp_z2 = ap_z1 = 0.0f; } void process(Real *hpout, Real *lpout, const Real *input, const int count); - void applyHfScale(Real *RESTRICT samples, const Real hfscale, const int count); + void applyHfScale(Real *samples, const Real hfscale, const int count); }; using BandSplitter = BandSplitterR; @@ -32,7 +32,7 @@ class SplitterAllpassR { public: void init(Real f0norm); void clear() noexcept { z1 = 0.0f; } - void process(Real *RESTRICT samples, int count); + void process(Real *samples, int count); }; using SplitterAllpass = SplitterAllpassR; -- cgit v1.2.3 From 9d6619efdc35aad2d33878c28b13dc5e56b495a7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Apr 2019 08:56:41 -0700 Subject: Combine some reverb processing loops Specifically, the A2B and output mixing, as well as applying the band-pass with B2A mixing (the latter of which hiding a bug that was overwriting the early buffer storage). --- Alc/effects/reverb.cpp | 60 ++++++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index c0a835fc..628f4349 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -90,15 +90,6 @@ alignas(16) constexpr ALfloat A2B[NUM_LINES][NUM_LINES]{ { 0.866025403785f, 0.866025403785f, -0.866025403785f, -0.866025403785f } }; -inline void ConvertA2B(ALfloat (&dst)[NUM_LINES][BUFFERSIZE], - const ALfloat (&src)[NUM_LINES][BUFFERSIZE], const ALsizei todo) -{ - for(ALsizei c{0};c < NUM_LINES;c++) - { - std::fill(std::begin(dst[c]), std::end(dst[c]), 0.0f); - MixRowSamples(dst[c], A2B[c], src, NUM_LINES, 0, todo); - } -} constexpr ALfloat FadeStep{1.0f / FADE_SAMPLES}; @@ -404,42 +395,55 @@ struct ReverbState final : public EffectState { void MixOutPlain(const ALsizei numOutput, ALfloat (*samplesOut)[BUFFERSIZE], const ALsizei todo) { + ASSUME(todo > 0); + /* Convert back to B-Format, and mix the results to output. */ - ConvertA2B(mTempSamples, mEarlyBuffer, todo); for(ALsizei c{0};c < NUM_LINES;c++) - MixSamples(mTempSamples[c], numOutput, samplesOut, mEarly.CurrentGain[c], + { + std::fill_n(std::begin(mTempSamples[0]), todo, 0.0f); + MixRowSamples(mTempSamples[0], A2B[c], mEarlyBuffer, NUM_LINES, 0, todo); + MixSamples(mTempSamples[0], numOutput, samplesOut, mEarly.CurrentGain[c], mEarly.PanGain[c], todo, 0, todo); + } - ConvertA2B(mTempSamples, mLateBuffer, todo); for(ALsizei c{0};c < NUM_LINES;c++) - MixSamples(mTempSamples[c], numOutput, samplesOut, mLate.CurrentGain[c], + { + std::fill_n(std::begin(mTempSamples[0]), todo, 0.0f); + MixRowSamples(mTempSamples[0], A2B[c], mLateBuffer, NUM_LINES, 0, todo); + MixSamples(mTempSamples[0], numOutput, samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], todo, 0, todo); + } } void MixOutAmbiUp(const ALsizei numOutput, ALfloat (*samplesOut)[BUFFERSIZE], const ALsizei todo) { ASSUME(todo > 0); - ConvertA2B(mTempSamples, mEarlyBuffer, todo); + for(ALsizei c{0};c < NUM_LINES;c++) { + std::fill_n(std::begin(mTempSamples[0]), todo, 0.0f); + MixRowSamples(mTempSamples[0], A2B[c], mEarlyBuffer, NUM_LINES, 0, todo); + /* Apply scaling to the B-Format's HF response to "upsample" it to * higher-order output. */ const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; - mAmbiSplitter[0][c].applyHfScale(mTempSamples[c], hfscale, todo); + mAmbiSplitter[0][c].applyHfScale(mTempSamples[0], hfscale, todo); - MixSamples(mTempSamples[c], numOutput, samplesOut, mEarly.CurrentGain[c], + MixSamples(mTempSamples[0], numOutput, samplesOut, mEarly.CurrentGain[c], mEarly.PanGain[c], todo, 0, todo); } - ConvertA2B(mTempSamples, mLateBuffer, todo); for(ALsizei c{0};c < NUM_LINES;c++) { + std::fill_n(std::begin(mTempSamples[0]), todo, 0.0f); + MixRowSamples(mTempSamples[0], A2B[c], mLateBuffer, NUM_LINES, 0, todo); + const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; - mAmbiSplitter[1][c].applyHfScale(mTempSamples[c], hfscale, todo); + mAmbiSplitter[1][c].applyHfScale(mTempSamples[0], hfscale, todo); - MixSamples(mTempSamples[c], numOutput, samplesOut, mLate.CurrentGain[c], + MixSamples(mTempSamples[0], numOutput, samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], todo, 0, todo); } } @@ -1382,8 +1386,12 @@ void ReverbState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesI ALfloat (&afmt)[NUM_LINES][BUFFERSIZE] = mTempSamples; for(ALsizei c{0};c < NUM_LINES;c++) { - std::fill(std::begin(afmt[c]), std::end(afmt[c]), 0.0f); + std::fill_n(std::begin(afmt[c]), samplesToDo, 0.0f); MixRowSamples(afmt[c], B2A[c], samplesIn, numInput, 0, samplesToDo); + + /* Band-pass the incoming samples. */ + mFilter[c].Lp.process(afmt[c], afmt[c], samplesToDo); + mFilter[c].Hp.process(afmt[c], afmt[c], samplesToDo); } /* Process reverb for these samples. */ @@ -1399,17 +1407,11 @@ void ReverbState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesI todo = mini(todo, mMaxUpdate[1]); ASSUME(todo > 0); - /* Process the samples for reverb. */ + /* Feed the initial delay line. */ for(ALsizei c{0};c < NUM_LINES;c++) - { - /* Band-pass the incoming samples. */ - mFilter[c].Lp.process(mEarlyBuffer[0], afmt[c]+base, todo); - mFilter[c].Hp.process(mEarlyBuffer[1], mEarlyBuffer[0], todo); - - /* Feed the initial delay line. */ - mDelay.write(offset, c, mEarlyBuffer[1], todo); - } + mDelay.write(offset, c, afmt[c]+base, todo); + /* Process the samples for reverb. */ if(UNLIKELY(fadeCount < FADE_SAMPLES)) { auto fade = static_cast(fadeCount); -- cgit v1.2.3 From ace7481b8ec3f6dfa45feda4795913c2206d04f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Apr 2019 21:49:10 -0700 Subject: Only enable NFC with HRTF when hq-mode is enabled --- Alc/panning.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 2b8c8143..9fb0bebb 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -624,8 +624,11 @@ void InitHrtfPanning(ALCdevice *device) BuildBFormatHrtf(device->mHrtf, device->mHrtfState.get(), device->Dry.NumChannels, AmbiPoints, AmbiMatrix, COUNTOF(AmbiPoints), AmbiOrderHFGain); - HrtfEntry *Hrtf{device->mHrtf}; - InitNearFieldCtrl(device, Hrtf->field[0].distance, ambi_order, ChansPerOrder); + if(GetConfigValueBool(device->DeviceName.c_str(), "decoder", "hq-mode", 0)) + { + HrtfEntry *Hrtf{device->mHrtf}; + InitNearFieldCtrl(device, Hrtf->field[0].distance, ambi_order, ChansPerOrder); + } } void InitUhjPanning(ALCdevice *device) -- cgit v1.2.3 From 8ca849655f6c292527d0e260718ba0eca4179fb1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Apr 2019 21:51:47 -0700 Subject: Properly replace sinc4 with cubic in alsoft-config --- utils/alsoft-config/mainwindow.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 920bc5a3..ad0223da 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -609,11 +609,11 @@ void MainWindow::loadConfig(const QString &fname) QString resampler = settings.value("resampler").toString().trimmed(); ui->resamplerSlider->setValue(2); ui->resamplerLabel->setText(resamplerList[2].name); - /* The "cubic" and "sinc8" resamplers are no longer supported. Use "sinc4" + /* The "sinc4" and "sinc8" resamplers are no longer supported. Use "cubic" * as a fallback. */ - if(resampler == "cubic" || resampler == "sinc8") - resampler = "sinc4"; + if(resampler == "sinc4" || resampler == "sinc8") + resampler = "cubic"; /* The "bsinc" resampler name is an alias for "bsinc12". */ else if(resampler == "bsinc") resampler = "bsinc12"; -- cgit v1.2.3 From c7e388873c075daa58c26d168080b36300372fd0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Apr 2019 22:21:23 -0700 Subject: Increase the period size slider and don't use steps of 64 --- utils/alsoft-config/mainwindow.cpp | 3 --- utils/alsoft-config/mainwindow.ui | 18 +++++++++--------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index ad0223da..a83133b3 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -1144,10 +1144,7 @@ void MainWindow::updatePeriodSizeEdit(int size) { ui->periodSizeEdit->clear(); if(size >= 64) - { - size = (size+32)&~0x3f; ui->periodSizeEdit->insert(QString::number(size)); - } enableApplyButton(); } diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 95e9ebe6..158a3316 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -283,9 +283,9 @@ mixed and being heard. - 20 + 60 0 - 201 + 161 21 @@ -299,9 +299,9 @@ mixed and being heard. - 80 + 99 20 - 160 + 141 21 @@ -336,7 +336,7 @@ mixed and being heard. - 20 + 40 20 51 21 @@ -365,24 +365,24 @@ frames needed for each mixing update. 60 20 - 160 + 191 21 - 0 + 63 8192 - 64 + 1 1024 - 0 + 63 true -- cgit v1.2.3 From 2eb657f2dfad41e7d0946de4c91f766eb9b846f4 Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Mon, 29 Apr 2019 23:59:36 +0200 Subject: CMAKE: export PUBLIC headers of OpenAL. Remove the cmake function: INCLUDE_DIRECTORIES(..) Replace it by: TARGET_INCLUDE_DIRECTORIES(...) It gives us the opportunity to define whether or not OpenAL dependencies should be exported or not (using PUBLIC or PRIVATE keywoard). [user visible changes] The OpenAL PUBLIC headers are exported. When a target depends on OpenAL, it will have access to its public headers. Some small refactor along the way. --- CMakeLists.txt | 98 +++++++++++++++++++++----------------- utils/alsoft-config/CMakeLists.txt | 2 + 2 files changed, 56 insertions(+), 44 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 411ae1ed..fba05186 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -193,9 +193,6 @@ IF(HAVE_LIBLOG) SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} log) ENDIF() -# Add definitions, compiler switches, etc. -INCLUDE_DIRECTORIES("${OpenAL_SOURCE_DIR}/include" "${OpenAL_SOURCE_DIR}/common" "${OpenAL_BINARY_DIR}") - IF(NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." @@ -639,6 +636,8 @@ IF(NOT HAVE_STDINT_H) ENDIF() +# Common sources used by both the OpenAL implementation library and potentially +# the OpenAL router. SET(COMMON_OBJS common/alcomplex.cpp common/alcomplex.h @@ -1260,15 +1259,8 @@ CONFIGURE_FILE( @ONLY) -# Add a static library with common functions used by multiple targets -ADD_LIBRARY(common STATIC ${COMMON_OBJS}) -TARGET_COMPILE_DEFINITIONS(common PRIVATE ${CPP_DEFS}) -TARGET_COMPILE_OPTIONS(common PRIVATE ${C_FLAGS}) - - UNSET(HAS_ROUTER) -SET(IMPL_TARGET OpenAL) -SET(COMMON_LIB ) +SET(IMPL_TARGET OpenAL) # Either OpenAL or soft_oal. SET(SUBSYS_FLAG ) # Build main library @@ -1279,10 +1271,6 @@ IF(LIBTYPE STREQUAL "STATIC") ENDIF() ADD_LIBRARY(OpenAL STATIC ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS}) ELSE() - # Make sure to compile the common code with PIC, since it'll be linked into - # shared libs that needs it. - SET_PROPERTY(TARGET common PROPERTY POSITION_INDEPENDENT_CODE TRUE) - SET(COMMON_LIB common) IF(WIN32) IF(MSVC) @@ -1293,11 +1281,25 @@ ELSE() ENDIF() IF(WIN32 AND ALSOFT_BUILD_ROUTER) - ADD_LIBRARY(OpenAL SHARED router/router.cpp router/router.h router/alc.cpp router/al.cpp) + ADD_LIBRARY(OpenAL SHARED + router/router.cpp + router/router.h + router/alc.cpp + router/al.cpp + ${COMMON_OBJS} + ) TARGET_COMPILE_DEFINITIONS(OpenAL PRIVATE AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES ${CPP_DEFS}) TARGET_COMPILE_OPTIONS(OpenAL PRIVATE ${C_FLAGS}) - TARGET_LINK_LIBRARIES(OpenAL PRIVATE ${COMMON_LIB} ${LINKER_FLAGS}) + TARGET_LINK_LIBRARIES(OpenAL PRIVATE ${LINKER_FLAGS}) + TARGET_INCLUDE_DIRECTORIES(OpenAL + PUBLIC + $ + $ + PRIVATE + ${OpenAL_SOURCE_DIR}/common + ${OpenAL_BINARY_DIR} + ) SET_TARGET_PROPERTIES(OpenAL PROPERTIES PREFIX "") SET_TARGET_PROPERTIES(OpenAL PROPERTIES OUTPUT_NAME ${LIBNAME}) IF(TARGET build_version) @@ -1309,22 +1311,35 @@ ELSE() SET(IMPL_TARGET soft_oal) ENDIF() - ADD_LIBRARY(${IMPL_TARGET} SHARED ${OPENAL_OBJS} ${ALC_OBJS}) + ADD_LIBRARY(${IMPL_TARGET} SHARED ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS}) IF(WIN32) SET_TARGET_PROPERTIES(${IMPL_TARGET} PROPERTIES PREFIX "") ENDIF() ENDIF() + +TARGET_LINK_LIBRARIES(${IMPL_TARGET} + PRIVATE ${LINKER_FLAGS} ${EXTRA_LIBS} ${MATH_LIB}) + +TARGET_INCLUDE_DIRECTORIES(${IMPL_TARGET} + PUBLIC + $ + $ + PRIVATE + ${INC_PATHS} + ${OpenAL_BINARY_DIR} + ${OpenAL_SOURCE_DIR}/Alc + ${OpenAL_SOURCE_DIR}/OpenAL32/Include + ${OpenAL_SOURCE_DIR}/common +) + SET_TARGET_PROPERTIES(${IMPL_TARGET} PROPERTIES OUTPUT_NAME ${LIBNAME} VERSION ${LIB_VERSION} SOVERSION ${LIB_MAJOR_VERSION} ) TARGET_COMPILE_DEFINITIONS(${IMPL_TARGET} PRIVATE AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES ${CPP_DEFS}) -TARGET_INCLUDE_DIRECTORIES(${IMPL_TARGET} - PRIVATE "${OpenAL_SOURCE_DIR}/OpenAL32/Include" "${OpenAL_SOURCE_DIR}/Alc" ${INC_PATHS}) TARGET_COMPILE_OPTIONS(${IMPL_TARGET} PRIVATE ${C_FLAGS}) -TARGET_LINK_LIBRARIES(${IMPL_TARGET} - PRIVATE ${COMMON_LIB} ${LINKER_FLAGS} ${EXTRA_LIBS} ${MATH_LIB}) + IF(TARGET build_version) ADD_DEPENDENCIES(${IMPL_TARGET} build_version) ENDIF() @@ -1497,12 +1512,13 @@ IF(ALSOFT_UTILS) ENDIF() IF(ALSOFT_TESTS) - SET(TEST_COMMON_OBJS examples/common/alhelpers.c) - - ADD_EXECUTABLE(altonegen examples/altonegen.c ${TEST_COMMON_OBJS}) + ADD_EXECUTABLE(altonegen + examples/altonegen.c + examples/common/alhelpers.c + ) TARGET_COMPILE_DEFINITIONS(altonegen PRIVATE ${CPP_DEFS}) TARGET_COMPILE_OPTIONS(altonegen PRIVATE ${C_FLAGS}) - TARGET_LINK_LIBRARIES(altonegen PRIVATE ${LINKER_FLAGS} common OpenAL ${MATH_LIB}) + TARGET_LINK_LIBRARIES(altonegen PRIVATE ${LINKER_FLAGS} OpenAL ${MATH_LIB}) IF(ALSOFT_INSTALL) INSTALL(TARGETS altonegen @@ -1520,12 +1536,13 @@ IF(ALSOFT_EXAMPLES) # Add a static library with common functions used by multiple targets ADD_LIBRARY(ex-common STATIC examples/common/alhelpers.c) TARGET_COMPILE_DEFINITIONS(ex-common PRIVATE ${CPP_DEFS}) - TARGET_COMPILE_OPTIONS(ex-common PRIVATE ${C_FLAGS}) + TARGET_COMPILE_OPTIONS(ex-common PUBLIC ${C_FLAGS}) + TARGET_LINK_LIBRARIES(ex-common PUBLIC OpenAL) ADD_EXECUTABLE(alrecord examples/alrecord.c) TARGET_COMPILE_DEFINITIONS(alrecord PRIVATE ${CPP_DEFS}) TARGET_COMPILE_OPTIONS(alrecord PRIVATE ${C_FLAGS}) - TARGET_LINK_LIBRARIES(alrecord PRIVATE ${LINKER_FLAGS} ex-common common OpenAL) + TARGET_LINK_LIBRARIES(alrecord PRIVATE ${LINKER_FLAGS} ex-common) IF(ALSOFT_INSTALL) INSTALL(TARGETS alrecord @@ -1545,8 +1562,7 @@ IF(ALSOFT_EXAMPLES) PRIVATE ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) TARGET_COMPILE_OPTIONS(alplay PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(alplay - PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common common - OpenAL) + PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common) ADD_EXECUTABLE(alstream examples/alstream.c) TARGET_COMPILE_DEFINITIONS(alstream PRIVATE ${CPP_DEFS}) @@ -1554,8 +1570,7 @@ IF(ALSOFT_EXAMPLES) PRIVATE ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) TARGET_COMPILE_OPTIONS(alstream PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(alstream - PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common common - OpenAL) + PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common) ADD_EXECUTABLE(alreverb examples/alreverb.c) TARGET_COMPILE_DEFINITIONS(alreverb PRIVATE ${CPP_DEFS}) @@ -1563,8 +1578,7 @@ IF(ALSOFT_EXAMPLES) PRIVATE ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) TARGET_COMPILE_OPTIONS(alreverb PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(alreverb - PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common common - OpenAL) + PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common) ADD_EXECUTABLE(almultireverb examples/almultireverb.c) TARGET_COMPILE_DEFINITIONS(almultireverb PRIVATE ${CPP_DEFS}) @@ -1572,8 +1586,8 @@ IF(ALSOFT_EXAMPLES) PRIVATE ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) TARGET_COMPILE_OPTIONS(almultireverb PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(almultireverb - PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common common - OpenAL ${MATH_LIB}) + PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common + ${MATH_LIB}) ADD_EXECUTABLE(allatency examples/allatency.c) TARGET_COMPILE_DEFINITIONS(allatency PRIVATE ${CPP_DEFS}) @@ -1581,8 +1595,7 @@ IF(ALSOFT_EXAMPLES) PRIVATE ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) TARGET_COMPILE_OPTIONS(allatency PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(allatency - PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common common - OpenAL) + PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common) ADD_EXECUTABLE(alloopback examples/alloopback.c) TARGET_COMPILE_DEFINITIONS(alloopback PRIVATE ${CPP_DEFS}) @@ -1590,8 +1603,7 @@ IF(ALSOFT_EXAMPLES) PRIVATE ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) TARGET_COMPILE_OPTIONS(alloopback PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(alloopback - PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common common - OpenAL ${MATH_LIB}) + PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common ${MATH_LIB}) ADD_EXECUTABLE(alhrtf examples/alhrtf.c) TARGET_COMPILE_DEFINITIONS(alhrtf PRIVATE ${CPP_DEFS}) @@ -1599,8 +1611,7 @@ IF(ALSOFT_EXAMPLES) PRIVATE ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) TARGET_COMPILE_OPTIONS(alhrtf PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(alhrtf - PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common common - OpenAL ${MATH_LIB}) + PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common ${MATH_LIB}) IF(ALSOFT_INSTALL) INSTALL(TARGETS alplay alstream alreverb almultireverb allatency alloopback alhrtf @@ -1644,8 +1655,7 @@ IF(ALSOFT_EXAMPLES) PRIVATE ${SDL2_INCLUDE_DIR} ${FFMPEG_INCLUDE_DIRS}) TARGET_COMPILE_OPTIONS(alffplay PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(alffplay - PRIVATE ${LINKER_FLAGS} ${SDL2_LIBRARY} ${FFMPEG_LIBRARIES} ex-common common - OpenAL) + PRIVATE ${LINKER_FLAGS} ${SDL2_LIBRARY} ${FFMPEG_LIBRARIES} ex-common) IF(ALSOFT_INSTALL) INSTALL(TARGETS alffplay diff --git a/utils/alsoft-config/CMakeLists.txt b/utils/alsoft-config/CMakeLists.txt index 67cc44c7..7996ee97 100644 --- a/utils/alsoft-config/CMakeLists.txt +++ b/utils/alsoft-config/CMakeLists.txt @@ -20,6 +20,7 @@ if(Qt5Widgets_FOUND AND NOT ALSOFT_NO_QT5) add_executable(alsoft-config ${alsoft-config_SRCS} ${UIS} ${RSCS} ${TRS} ${MOCS}) target_link_libraries(alsoft-config Qt5::Widgets) + target_include_directories(alsoft-config PRIVATE "${OpenAL_BINARY_DIR}") set_property(TARGET alsoft-config APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) set_target_properties(alsoft-config PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OpenAL_BINARY_DIR}) if(TARGET build_version) @@ -43,6 +44,7 @@ else() add_executable(alsoft-config ${alsoft-config_SRCS} ${UIS} ${RSCS} ${TRS} ${MOCS}) target_link_libraries(alsoft-config ${QT_LIBRARIES}) + target_include_directories(alsoft-config PRIVATE "${OpenAL_BINARY_DIR}") set_property(TARGET alsoft-config APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) set_target_properties(alsoft-config PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OpenAL_BINARY_DIR}) if(TARGET build_version) -- cgit v1.2.3 From b42694ea31b3c72348e2467c43171b31f7eef5a8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Apr 2019 12:50:13 -0700 Subject: Allow NFC filters without HQ decoding It still requires a proper custom decoder configuration for speakers, so that proper distances can be specified. Ambisonic output still relies on the nfc-ref-delay option, and HRTF uses the dataset's distance. --- Alc/panning.cpp | 82 +++++++++++++-------------------------------------------- 1 file changed, 18 insertions(+), 64 deletions(-) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 9fb0bebb..cb9a486d 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -233,9 +233,7 @@ constexpr ChannelMap MonoCfg[1] = { void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, const ALsizei *RESTRICT chans_per_order) { - /* NFC is only used when AvgSpeakerDist is greater than 0, and can only be - * used when rendering to an ambisonic buffer. - */ + /* NFC is only used when AvgSpeakerDist is greater than 0. */ const char *devname{device->DeviceName.c_str()}; if(!GetConfigValueBool(devname, "decoder", "nfc", 1) || !(ctrl_dist > 0.0f)) return; @@ -444,53 +442,15 @@ void InitPanning(ALCdevice *device) } } -void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) -{ - if(conf->FreqBands != 1) - ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n", - conf->XOverFreq); - - ALsizei order{(conf->ChanMask > AMBI_2ORDER_MASK) ? 3 : - (conf->ChanMask > AMBI_1ORDER_MASK) ? 2 : 1}; - device->mAmbiOrder = order; - - ALsizei count; - if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) - { - count = static_cast(AmbiChannelsFromOrder(order)); - std::transform(AmbiIndex::From3D.begin(), AmbiIndex::From3D.begin()+count, - std::begin(device->Dry.AmbiMap), - [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } - ); - } - else - { - count = static_cast(Ambi2DChannelsFromOrder(order)); - std::transform(AmbiIndex::From2D.begin(), AmbiIndex::From2D.begin()+count, - std::begin(device->Dry.AmbiMap), - [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } - ); - } - device->Dry.NumChannels = count; - - TRACE("Enabling %s-order%s ambisonic decoder\n", - (conf->ChanMask > AMBI_2ORDER_MASK) ? "third" : - (conf->ChanMask > AMBI_1ORDER_MASK) ? "second" : "first", - (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? " periphonic" : "" - ); - device->AmbiDecoder = al::make_unique(conf, false, count, device->Frequency, - speakermap); - - device->RealOut.NumChannels = device->channelsFromFmt(); - - InitDistanceComp(device, conf, speakermap); -} - -void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) +void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) { static constexpr ALsizei chans_per_order2d[MAX_AMBI_ORDER+1] = { 1, 2, 2, 2 }; static constexpr ALsizei chans_per_order3d[MAX_AMBI_ORDER+1] = { 1, 3, 5, 7 }; + if(!hqdec && conf->FreqBands != 1) + ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n", + conf->XOverFreq); + ALsizei order{(conf->ChanMask > AMBI_2ORDER_MASK) ? 3 : (conf->ChanMask > AMBI_1ORDER_MASK) ? 2 : 1}; device->mAmbiOrder = order; @@ -515,28 +475,24 @@ void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&sp device->Dry.NumChannels = count; TRACE("Enabling %s-band %s-order%s ambisonic decoder\n", - (conf->FreqBands == 1) ? "single" : "dual", + (!hqdec || conf->FreqBands == 1) ? "single" : "dual", (conf->ChanMask > AMBI_2ORDER_MASK) ? "third" : (conf->ChanMask > AMBI_1ORDER_MASK) ? "second" : "first", (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? " periphonic" : "" ); - device->AmbiDecoder = al::make_unique(conf, true, count, device->Frequency, + device->AmbiDecoder = al::make_unique(conf, hqdec, count, device->Frequency, speakermap); device->RealOut.NumChannels = device->channelsFromFmt(); - auto accum_spkr_dist = std::bind( - std::plus{}, _1, std::bind(std::mem_fn(&AmbDecConf::SpeakerConf::Distance), _2) - ); + auto accum_spkr_dist = std::bind(std::plus{}, _1, + std::bind(std::mem_fn(&AmbDecConf::SpeakerConf::Distance), _2)); const ALfloat avg_dist{ std::accumulate(conf->Speakers.begin(), conf->Speakers.end(), float{0.0f}, accum_spkr_dist) / static_cast(conf->Speakers.size()) }; - InitNearFieldCtrl(device, avg_dist, - (conf->ChanMask > AMBI_2ORDER_MASK) ? 3 : - (conf->ChanMask > AMBI_1ORDER_MASK) ? 2 : 1, - (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? chans_per_order3d : chans_per_order2d - ); + InitNearFieldCtrl(device, avg_dist, order, + (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? chans_per_order3d : chans_per_order2d); InitDistanceComp(device, conf, speakermap); } @@ -624,11 +580,8 @@ void InitHrtfPanning(ALCdevice *device) BuildBFormatHrtf(device->mHrtf, device->mHrtfState.get(), device->Dry.NumChannels, AmbiPoints, AmbiMatrix, COUNTOF(AmbiPoints), AmbiOrderHFGain); - if(GetConfigValueBool(device->DeviceName.c_str(), "decoder", "hq-mode", 0)) - { - HrtfEntry *Hrtf{device->mHrtf}; - InitNearFieldCtrl(device, Hrtf->field[0].distance, ambi_order, ChansPerOrder); - } + HrtfEntry *Hrtf{device->mHrtf}; + InitNearFieldCtrl(device, Hrtf->field[0].distance, ambi_order, ChansPerOrder); } void InitUhjPanning(ALCdevice *device) @@ -827,10 +780,11 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr if(!pconf) InitPanning(device); - else if(GetConfigValueBool(devname, "decoder", "hq-mode", 0)) - InitHQPanning(device, pconf, speakermap); else - InitCustomPanning(device, pconf, speakermap); + { + int hqdec{GetConfigValueBool(devname, "decoder", "hq-mode", 0)}; + InitCustomPanning(device, hqdec, pconf, speakermap); + } /* Enable the stablizer only for formats that have front-left, front- * right, and front-center outputs. -- cgit v1.2.3 From cef7eebed663e1daf8704eceb09f05ff75609ec5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Apr 2019 13:07:02 -0700 Subject: Disable NFC by default --- Alc/panning.cpp | 2 +- alsoftrc.sample | 19 ++++++++++--------- utils/alsoft-config/mainwindow.cpp | 4 ++-- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index cb9a486d..ce822123 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -235,7 +235,7 @@ void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, cons { /* NFC is only used when AvgSpeakerDist is greater than 0. */ const char *devname{device->DeviceName.c_str()}; - if(!GetConfigValueBool(devname, "decoder", "nfc", 1) || !(ctrl_dist > 0.0f)) + if(!GetConfigValueBool(devname, "decoder", "nfc", 0) || !(ctrl_dist > 0.0f)) return; device->AvgSpeakerDist = minf(ctrl_dist, 10.0f); diff --git a/alsoftrc.sample b/alsoftrc.sample index 9b5dd2f9..95d4ff82 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -275,17 +275,18 @@ distance-comp = true # creates a more realistic perception of sound distance. Note that the effect # may be stronger or weaker than intended if the application doesn't use or # specify an appropriate unit scale, or if incorrect speaker distances are set -# in the decoder configuration file. Requires hq-mode to be enabled. -nfc = true +# in the decoder configuration file. +nfc = false ## nfc-ref-delay -# Specifies the reference delay value for ambisonic output. When channels is -# set to one of the ambi* formats, this option enables NFC-HOA output with the -# specified Reference Delay parameter. The specified value can then be shared -# with an appropriate NFC-HOA decoder to reproduce correct near-field effects. -# Keep in mind that despite being designed for higher-order ambisonics, this -# applies to first-order output all the same. When left unset, normal output -# is created with no near-field simulation. +# Specifies the reference delay value for ambisonic output when NFC filters +# are enabled. If channels is set to one of the ambi* formats, this option +# enables NFC-HOA output with the specified Reference Delay parameter. The +# specified value can then be shared with an appropriate NFC-HOA decoder to +# reproduce correct near-field effects. Keep in mind that despite being +# designed for higher-order ambisonics, this also applies to first-order +# output. When left unset, normal output is created with no near-field +# simulation. Requires the nfc option to also be enabled. nfc-ref-delay = ## quad: diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index a83133b3..37ea3dd7 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -697,7 +697,7 @@ void MainWindow::loadConfig(const QString &fname) ui->decoderHQModeCheckBox->setChecked(hqmode); bool distcomp = settings.value("decoder/distance-comp", true).toBool(); ui->decoderDistCompCheckBox->setChecked(distcomp); - bool nfeffects = settings.value("decoder/nfc", true).toBool(); + bool nfeffects = settings.value("decoder/nfc", false).toBool(); ui->decoderNFEffectsCheckBox->setChecked(nfeffects); double refdelay = settings.value("decoder/nfc-ref-delay", 0.0).toDouble(); ui->decoderNFRefDelaySpinBox->setValue(refdelay); @@ -958,7 +958,7 @@ void MainWindow::saveConfig(const QString &fname) const ui->decoderDistCompCheckBox->isChecked() ? QString(/*"true"*/) : QString("false") ); settings.setValue("decoder/nfc", - ui->decoderNFEffectsCheckBox->isChecked() ? QString(/*"true"*/) : QString("false") + ui->decoderNFEffectsCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) ); double refdelay = ui->decoderNFRefDelaySpinBox->value(); settings.setValue("decoder/nfc-ref-delay", -- cgit v1.2.3 From fb52413a6e1ba40643529343e6660ef760f9635d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Apr 2019 13:44:16 -0700 Subject: Make a number of settings tristate --- utils/alsoft-config/mainwindow.cpp | 110 +++++++++++++++---------------------- utils/alsoft-config/mainwindow.ui | 26 +++++++-- 2 files changed, 63 insertions(+), 73 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 37ea3dd7..4e2b2464 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -210,6 +210,26 @@ static QString getNameFromValue(const NameValuePair (&list)[N], const QString &s return QString(); } + +Qt::CheckState getCheckState(const QVariant &var) +{ + if(var.isNull()) + return Qt::PartiallyChecked; + if(var.toBool()) + return Qt::Checked; + return Qt::Unchecked; +} + +QString getCheckValue(const QCheckBox *checkbox) +{ + const Qt::CheckState state{checkbox->checkState()}; + if(state == Qt::Checked) + return QString("true"); + if(state == Qt::Unchecked) + return QString("false"); + return QString(); +} + } MainWindow::MainWindow(QWidget *parent) : @@ -655,19 +675,8 @@ void MainWindow::loadConfig(const QString &fname) updatePeriodCountSlider(); } - if(settings.value("output-limiter").isNull()) - ui->outputLimiterCheckBox->setCheckState(Qt::PartiallyChecked); - else - ui->outputLimiterCheckBox->setCheckState( - settings.value("output-limiter").toBool() ? Qt::Checked : Qt::Unchecked - ); - - if(settings.value("dither").isNull()) - ui->outputDitherCheckBox->setCheckState(Qt::PartiallyChecked); - else - ui->outputDitherCheckBox->setCheckState( - settings.value("dither").toBool() ? Qt::Checked : Qt::Unchecked - ); + ui->outputLimiterCheckBox->setCheckState(getCheckState(settings.value("output-limiter"))); + ui->outputDitherCheckBox->setCheckState(getCheckState(settings.value("dither"))); QString stereopan = settings.value("stereo-encoding").toString(); ui->stereoEncodingComboBox->setCurrentIndex(0); @@ -695,10 +704,8 @@ void MainWindow::loadConfig(const QString &fname) bool hqmode = settings.value("decoder/hq-mode", false).toBool(); ui->decoderHQModeCheckBox->setChecked(hqmode); - bool distcomp = settings.value("decoder/distance-comp", true).toBool(); - ui->decoderDistCompCheckBox->setChecked(distcomp); - bool nfeffects = settings.value("decoder/nfc", false).toBool(); - ui->decoderNFEffectsCheckBox->setChecked(nfeffects); + ui->decoderDistCompCheckBox->setCheckState(getCheckState(settings.value("decoder/distance-comp"))); + ui->decoderNFEffectsCheckBox->setCheckState(getCheckState(settings.value("decoder/nfc"))); double refdelay = settings.value("decoder/nfc-ref-delay", 0.0).toDouble(); ui->decoderNFRefDelaySpinBox->setValue(refdelay); @@ -853,19 +860,19 @@ void MainWindow::loadConfig(const QString &fname) ui->enableDedicatedCheck->setChecked(!excludefx.contains("dedicated", Qt::CaseInsensitive)); ui->enablePitchShifterCheck->setChecked(!excludefx.contains("pshifter", Qt::CaseInsensitive)); - ui->pulseAutospawnCheckBox->setChecked(settings.value("pulse/spawn-server", true).toBool()); - ui->pulseAllowMovesCheckBox->setChecked(settings.value("pulse/allow-moves", false).toBool()); - ui->pulseFixRateCheckBox->setChecked(settings.value("pulse/fix-rate", false).toBool()); - ui->pulseAdjLatencyCheckBox->setChecked(settings.value("pulse/adjust-latency", false).toBool()); + ui->pulseAutospawnCheckBox->setCheckState(getCheckState(settings.value("pulse/spawn-server"))); + ui->pulseAllowMovesCheckBox->setCheckState(getCheckState(settings.value("pulse/allow-moves"))); + ui->pulseFixRateCheckBox->setCheckState(getCheckState(settings.value("pulse/fix-rate"))); + ui->pulseAdjLatencyCheckBox->setCheckState(getCheckState(settings.value("pulse/adjust-latency"))); - ui->jackAutospawnCheckBox->setChecked(settings.value("jack/spawn-server", false).toBool()); + ui->jackAutospawnCheckBox->setCheckState(getCheckState(settings.value("jack/spawn-server"))); ui->jackBufferSizeLine->setText(settings.value("jack/buffer-size", QString()).toString()); updateJackBufferSizeSlider(); ui->alsaDefaultDeviceLine->setText(settings.value("alsa/device", QString()).toString()); ui->alsaDefaultCaptureLine->setText(settings.value("alsa/capture", QString()).toString()); - ui->alsaResamplerCheckBox->setChecked(settings.value("alsa/allow-resampler", false).toBool()); - ui->alsaMmapCheckBox->setChecked(settings.value("alsa/mmap", true).toBool()); + ui->alsaResamplerCheckBox->setCheckState(getCheckState(settings.value("alsa/allow-resampler"))); + ui->alsaMmapCheckBox->setCheckState(getCheckState(settings.value("alsa/mmap"))); ui->ossDefaultDeviceLine->setText(settings.value("oss/device", QString()).toString()); ui->ossDefaultCaptureLine->setText(settings.value("oss/capture", QString()).toString()); @@ -887,7 +894,7 @@ void MainWindow::saveCurrentConfig() ui->closeCancelButton->setText(tr("Close")); mNeedsSave = false; QMessageBox::information(this, tr("Information"), - tr("Applications using OpenAL need to be restarted for changes to take effect.")); + tr("Applications using OpenAL need to be restarted for changes to take effect.")); } void MainWindow::saveConfigAsFile() @@ -935,31 +942,14 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("stereo-encoding", getValueFromName(stereoEncList, ui->stereoEncodingComboBox->currentText())); settings.setValue("ambi-format", getValueFromName(ambiFormatList, ui->ambiFormatComboBox->currentText())); - Qt::CheckState limiter = ui->outputLimiterCheckBox->checkState(); - if(limiter == Qt::PartiallyChecked) - settings.setValue("output-limiter", QString()); - else if(limiter == Qt::Checked) - settings.setValue("output-limiter", QString("true")); - else if(limiter == Qt::Unchecked) - settings.setValue("output-limiter", QString("false")); - - Qt::CheckState dither = ui->outputDitherCheckBox->checkState(); - if(dither == Qt::PartiallyChecked) - settings.setValue("dither", QString()); - else if(dither == Qt::Checked) - settings.setValue("dither", QString("true")); - else if(dither == Qt::Unchecked) - settings.setValue("dither", QString("false")); + settings.setValue("output-limiter", getCheckValue(ui->outputLimiterCheckBox)); + settings.setValue("dither", getCheckValue(ui->outputDitherCheckBox)); settings.setValue("decoder/hq-mode", ui->decoderHQModeCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) ); - settings.setValue("decoder/distance-comp", - ui->decoderDistCompCheckBox->isChecked() ? QString(/*"true"*/) : QString("false") - ); - settings.setValue("decoder/nfc", - ui->decoderNFEffectsCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) - ); + settings.setValue("decoder/distance-comp", getCheckValue(ui->decoderDistCompCheckBox)); + settings.setValue("decoder/nfc", getCheckValue(ui->decoderNFEffectsCheckBox)); double refdelay = ui->decoderNFRefDelaySpinBox->value(); settings.setValue("decoder/nfc-ref-delay", (refdelay > 0.0) ? QString::number(refdelay) : QString() @@ -1074,32 +1064,18 @@ void MainWindow::saveConfig(const QString &fname) const strlist.append("pshifter"); settings.setValue("excludefx", strlist.join(QChar(','))); - settings.setValue("pulse/spawn-server", - ui->pulseAutospawnCheckBox->isChecked() ? QString(/*"true"*/) : QString("false") - ); - settings.setValue("pulse/allow-moves", - ui->pulseAllowMovesCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) - ); - settings.setValue("pulse/fix-rate", - ui->pulseFixRateCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) - ); - settings.setValue("pulse/adjust-latency", - ui->pulseAdjLatencyCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) - ); + settings.setValue("pulse/spawn-server", getCheckValue(ui->pulseAutospawnCheckBox)); + settings.setValue("pulse/allow-moves", getCheckValue(ui->pulseAllowMovesCheckBox)); + settings.setValue("pulse/fix-rate", getCheckValue(ui->pulseFixRateCheckBox)); + settings.setValue("pulse/adjust-latency", getCheckValue(ui->pulseAdjLatencyCheckBox)); - settings.setValue("jack/spawn-server", - ui->jackAutospawnCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) - ); + settings.setValue("jack/spawn-server", getCheckValue(ui->jackAutospawnCheckBox)); settings.setValue("jack/buffer-size", ui->jackBufferSizeLine->text()); settings.setValue("alsa/device", ui->alsaDefaultDeviceLine->text()); settings.setValue("alsa/capture", ui->alsaDefaultCaptureLine->text()); - settings.setValue("alsa/allow-resampler", - ui->alsaResamplerCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) - ); - settings.setValue("alsa/mmap", - ui->alsaMmapCheckBox->isChecked() ? QString(/*"true"*/) : QString("false") - ); + settings.setValue("alsa/allow-resampler", getCheckValue(ui->alsaResamplerCheckBox)); + settings.setValue("alsa/mmap", getCheckValue(ui->alsaMmapCheckBox)); settings.setValue("oss/device", ui->ossDefaultDeviceLine->text()); settings.setValue("oss/capture", ui->ossDefaultCaptureLine->text()); diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 158a3316..46d1b7a8 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -655,7 +655,7 @@ configuration file. Distance Compensation: - + true @@ -847,8 +847,7 @@ creates a more realistic perception of sound distance. Note that the effect may be stronger or weaker than intended if the application doesn't use or specify an appropriate unit scale, or if incorrect speaker distances -are set in the decoder configuration file. Requires High -Quality Mode to be enabled. +are set in the decoder configuration file. Qt::RightToLeft @@ -856,7 +855,7 @@ Quality Mode to be enabled. Near-Field Effects: - + true @@ -1282,7 +1281,7 @@ is not already running. AutoSpawn Server - + true @@ -1304,6 +1303,9 @@ to match the new device. Allow Moving Streams + + true + @@ -1321,6 +1323,9 @@ rate to match the PulseAudio device. Fix Sample Rate + + true + @@ -1341,6 +1346,9 @@ drop-outs. Adjust Latency + + true + @@ -1356,6 +1364,9 @@ drop-outs. AutoSpawn Server + + true + @@ -1497,6 +1508,9 @@ resample pass on top of OpenAL's resampler. Allow Resampler + + true + @@ -1515,7 +1529,7 @@ during updates. MMap Buffer - + true -- cgit v1.2.3 From 85439cbd87ca5db7aa9773cb2438c5c1fb5731b3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Apr 2019 20:03:51 -0700 Subject: Add some missing include directories --- CMakeLists.txt | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fba05186..4367b2df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1467,6 +1467,7 @@ IF(ALSOFT_UTILS) set(UTIL_TARGETS ) ADD_EXECUTABLE(openal-info utils/openal-info.c) + TARGET_INCLUDE_DIRECTORIES(openal-info PRIVATE ${OpenAL_SOURCE_DIR}/common) TARGET_COMPILE_OPTIONS(openal-info PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(openal-info PRIVATE ${LINKER_FLAGS} OpenAL) set(UTIL_TARGETS ${UTIL_TARGETS} openal-info) @@ -1485,6 +1486,8 @@ IF(ALSOFT_UTILS) endif() add_executable(makemhr ${MAKEMHR_SRCS}) target_compile_definitions(makemhr PRIVATE ${CPP_DEFS}) + target_include_directories(makemhr + PRIVATE ${OpenAL_SOURCE_DIR}/common ${OpenAL_BINARY_DIR}) target_compile_options(makemhr PRIVATE ${C_FLAGS}) target_link_libraries(makemhr PRIVATE ${LINKER_FLAGS} MySOFA::MySOFA) set(UTIL_TARGETS ${UTIL_TARGETS} makemhr) @@ -1492,6 +1495,7 @@ IF(ALSOFT_UTILS) set(SOFAINFO_SRCS utils/sofa-info.cpp) add_executable(sofa-info ${SOFAINFO_SRCS}) target_compile_definitions(sofa-info PRIVATE ${CPP_DEFS}) + target_include_directories(sofa-info PRIVATE ${OpenAL_SOURCE_DIR}/common) target_compile_options(sofa-info PRIVATE ${C_FLAGS}) target_link_libraries(sofa-info PRIVATE ${LINKER_FLAGS} MySOFA::MySOFA) endif() @@ -1517,6 +1521,7 @@ IF(ALSOFT_TESTS) examples/common/alhelpers.c ) TARGET_COMPILE_DEFINITIONS(altonegen PRIVATE ${CPP_DEFS}) + TARGET_INCLUDE_DIRECTORIES(altonegen PRIVATE ${OpenAL_SOURCE_DIR}/common) TARGET_COMPILE_OPTIONS(altonegen PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(altonegen PRIVATE ${LINKER_FLAGS} OpenAL ${MATH_LIB}) @@ -1535,13 +1540,12 @@ ENDIF() IF(ALSOFT_EXAMPLES) # Add a static library with common functions used by multiple targets ADD_LIBRARY(ex-common STATIC examples/common/alhelpers.c) - TARGET_COMPILE_DEFINITIONS(ex-common PRIVATE ${CPP_DEFS}) + TARGET_COMPILE_DEFINITIONS(ex-common PUBLIC ${CPP_DEFS}) + TARGET_INCLUDE_DIRECTORIES(ex-common PUBLIC ${OpenAL_SOURCE_DIR}/common) TARGET_COMPILE_OPTIONS(ex-common PUBLIC ${C_FLAGS}) TARGET_LINK_LIBRARIES(ex-common PUBLIC OpenAL) ADD_EXECUTABLE(alrecord examples/alrecord.c) - TARGET_COMPILE_DEFINITIONS(alrecord PRIVATE ${CPP_DEFS}) - TARGET_COMPILE_OPTIONS(alrecord PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(alrecord PRIVATE ${LINKER_FLAGS} ex-common) IF(ALSOFT_INSTALL) @@ -1557,59 +1561,45 @@ IF(ALSOFT_EXAMPLES) IF(SDL2_FOUND) IF(SDL_SOUND_FOUND) ADD_EXECUTABLE(alplay examples/alplay.c) - TARGET_COMPILE_DEFINITIONS(alplay PRIVATE ${CPP_DEFS}) TARGET_INCLUDE_DIRECTORIES(alplay PRIVATE ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) - TARGET_COMPILE_OPTIONS(alplay PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(alplay PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common) ADD_EXECUTABLE(alstream examples/alstream.c) - TARGET_COMPILE_DEFINITIONS(alstream PRIVATE ${CPP_DEFS}) TARGET_INCLUDE_DIRECTORIES(alstream PRIVATE ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) - TARGET_COMPILE_OPTIONS(alstream PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(alstream PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common) ADD_EXECUTABLE(alreverb examples/alreverb.c) - TARGET_COMPILE_DEFINITIONS(alreverb PRIVATE ${CPP_DEFS}) TARGET_INCLUDE_DIRECTORIES(alreverb PRIVATE ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) - TARGET_COMPILE_OPTIONS(alreverb PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(alreverb PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common) ADD_EXECUTABLE(almultireverb examples/almultireverb.c) - TARGET_COMPILE_DEFINITIONS(almultireverb PRIVATE ${CPP_DEFS}) TARGET_INCLUDE_DIRECTORIES(almultireverb PRIVATE ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) - TARGET_COMPILE_OPTIONS(almultireverb PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(almultireverb PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common ${MATH_LIB}) ADD_EXECUTABLE(allatency examples/allatency.c) - TARGET_COMPILE_DEFINITIONS(allatency PRIVATE ${CPP_DEFS}) TARGET_INCLUDE_DIRECTORIES(allatency PRIVATE ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) - TARGET_COMPILE_OPTIONS(allatency PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(allatency PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common) ADD_EXECUTABLE(alloopback examples/alloopback.c) - TARGET_COMPILE_DEFINITIONS(alloopback PRIVATE ${CPP_DEFS}) TARGET_INCLUDE_DIRECTORIES(alloopback PRIVATE ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) - TARGET_COMPILE_OPTIONS(alloopback PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(alloopback PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common ${MATH_LIB}) ADD_EXECUTABLE(alhrtf examples/alhrtf.c) - TARGET_COMPILE_DEFINITIONS(alhrtf PRIVATE ${CPP_DEFS}) TARGET_INCLUDE_DIRECTORIES(alhrtf PRIVATE ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) - TARGET_COMPILE_OPTIONS(alhrtf PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(alhrtf PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common ${MATH_LIB}) @@ -1650,10 +1640,8 @@ IF(ALSOFT_EXAMPLES) ENDIF() IF(FFVER_OK) ADD_EXECUTABLE(alffplay examples/alffplay.cpp) - TARGET_COMPILE_DEFINITIONS(alffplay PRIVATE ${CPP_DEFS}) TARGET_INCLUDE_DIRECTORIES(alffplay PRIVATE ${SDL2_INCLUDE_DIR} ${FFMPEG_INCLUDE_DIRS}) - TARGET_COMPILE_OPTIONS(alffplay PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(alffplay PRIVATE ${LINKER_FLAGS} ${SDL2_LIBRARY} ${FFMPEG_LIBRARIES} ex-common) -- cgit v1.2.3 From 6281f6e85a8f26ce1ca2b7ad018657805c2acdf4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 Apr 2019 23:27:09 -0700 Subject: Avoid masking offsets in the inner reverb loops --- Alc/effects/reverb.cpp | 242 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 158 insertions(+), 84 deletions(-) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 628f4349..927c545a 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -230,24 +230,17 @@ struct DelayLineI { ALfloat (*Line)[NUM_LINES]{nullptr}; - /* Basic delay line input/output routines. */ - inline ALfloat get(const ALsizei offset, const ALsizei c) const noexcept - { return Line[offset&Mask][c]; } - - /* Cross-faded delay line output routine. Instead of interpolating the - * offsets, this interpolates (cross-fades) the outputs at each offset. - */ - inline ALfloat getFaded(const ALsizei off0, const ALsizei off1, const ALsizei c, - const ALfloat sc0, const ALfloat sc1) const noexcept - { return Line[off0&Mask][c]*sc0 + Line[off1&Mask][c]*sc1; } - - - inline void write(ALsizei offset, const ALsizei c, const ALfloat *RESTRICT in, - ALsizei count) const noexcept + void write(ALsizei offset, const ALsizei c, const ALfloat *RESTRICT in, const ALsizei count) const noexcept { ASSUME(count > 0); - for(ALsizei i{0};i < count;i++) - Line[(offset++)&Mask][c] = in[i]; + for(ALsizei i{0};i < count;) + { + offset &= Mask; + ALsizei td{mini(Mask+1 - offset, count - i)}; + do { + Line[offset++][c] = in[i++]; + } while(--td); + } } }; @@ -273,7 +266,7 @@ struct T60Filter { const ALfloat hfDecayTime, const ALfloat lf0norm, const ALfloat hf0norm); /* Applies the two T60 damping filter sections. */ - inline void process(ALfloat *samples, const ALsizei todo) + void process(ALfloat *samples, const ALsizei todo) { HFFilter.process(samples, samples, todo); LFFilter.process(samples, samples, todo); @@ -1056,8 +1049,6 @@ inline void VectorPartialScatter(ALfloat *RESTRICT out, const ALfloat *RESTRICT out[2] = xCoeff*in[2] + yCoeff*( in[0] + -in[1] + in[3]); out[3] = xCoeff*in[3] + yCoeff*(-in[0] + -in[1] + -in[2] ); } -#define VectorScatterDelayIn(delay, o, in, xcoeff, ycoeff) \ - VectorPartialScatter((delay)->Line[(o)&(delay)->Mask], in, xcoeff, ycoeff) /* Utilizes the above, but reverses the input channels. */ inline void VectorScatterRevDelayIn(const DelayLineI *Delay, ALint offset, @@ -1065,14 +1056,21 @@ inline void VectorScatterRevDelayIn(const DelayLineI *Delay, ALint offset, const ALfloat (*RESTRICT in)[BUFFERSIZE], const ALsizei count) { const DelayLineI delay{*Delay}; + ASSUME(base >= 0); - for(ALsizei i{0};i < count;++i) - { - ALfloat f[NUM_LINES]; - for(ALsizei j{0};j < NUM_LINES;j++) - f[NUM_LINES-1-j] = in[j][base+i]; - VectorScatterDelayIn(&delay, offset++, f, xCoeff, yCoeff); + for(ALsizei i{0};i < count;) + { + offset &= delay.Mask; + ALsizei td{mini(delay.Mask+1 - offset, count-i)}; + do { + ALfloat f[NUM_LINES]; + for(ALsizei j{0};j < NUM_LINES;j++) + f[NUM_LINES-1-j] = in[j][base+i]; + ++i; + + VectorPartialScatter(delay.Line[offset++], f, xCoeff, yCoeff); + } while(--td); } } @@ -1097,21 +1095,31 @@ void VecAllpass::processUnfaded(ALfloat (*RESTRICT samples)[BUFFERSIZE], ALsizei ALsizei vap_offset[NUM_LINES]; for(ALsizei j{0};j < NUM_LINES;j++) vap_offset[j] = offset - Offset[j][0]; - for(ALsizei i{0};i < todo;i++) + for(ALsizei i{0};i < todo;) { - ALfloat f[NUM_LINES]; + for(ALsizei j{0};j < NUM_LINES;j++) + vap_offset[j] &= delay.Mask; + offset &= delay.Mask; + ALsizei maxoff{offset}; for(ALsizei j{0};j < NUM_LINES;j++) - { - ALfloat input = samples[j][i]; - ALfloat out = delay.get(vap_offset[j]++, j) - feedCoeff*input; - f[j] = input + feedCoeff*out; + maxoff = maxi(maxoff, vap_offset[j]); + ALsizei td{mini(delay.Mask+1 - maxoff, todo - i)}; - samples[j][i] = out; - } + do { + ALfloat f[NUM_LINES]; + for(ALsizei j{0};j < NUM_LINES;j++) + { + const ALfloat input{samples[j][i]}; + const ALfloat out{delay.Line[vap_offset[j]++][j] - feedCoeff*input}; + f[j] = input + feedCoeff*out; + + samples[j][i] = out; + } + ++i; - VectorScatterDelayIn(&delay, offset, f, xCoeff, yCoeff); - ++offset; + VectorPartialScatter(delay.Line[offset++], f, xCoeff, yCoeff); + } while(--td); } } void VecAllpass::processFaded(ALfloat (*RESTRICT samples)[BUFFERSIZE], ALsizei offset, @@ -1129,22 +1137,39 @@ void VecAllpass::processFaded(ALfloat (*RESTRICT samples)[BUFFERSIZE], ALsizei o vap_offset[j][0] = offset - Offset[j][0]; vap_offset[j][1] = offset - Offset[j][1]; } - for(ALsizei i{0};i < todo;i++) + for(ALsizei i{0};i < todo;) { - ALfloat f[NUM_LINES]; - for(ALsizei j{0};j < NUM_LINES;j++) { - ALfloat input{samples[j][i]}; - ALfloat out{delay.getFaded(vap_offset[j][0]++, vap_offset[j][1]++, j, 1.0f-fade, fade) - feedCoeff*input}; - f[j] = input + feedCoeff*out; - - samples[j][i] = out; + vap_offset[j][0] &= delay.Mask; + vap_offset[j][1] &= delay.Mask; } - fade += FadeStep; + offset &= delay.Mask; + + ALsizei maxoff{offset}; + for(ALsizei j{0};j < NUM_LINES;j++) + maxoff = maxi(maxoff, maxi(vap_offset[j][0], vap_offset[j][1])); + ALsizei td{mini(delay.Mask+1 - maxoff, todo - i)}; + + do { + fade += FadeStep; + ALfloat f[NUM_LINES]; + for(ALsizei j{0};j < NUM_LINES;j++) + f[j] = delay.Line[vap_offset[j][0]++][j]*(1.0f-fade) + + delay.Line[vap_offset[j][1]++][j]*fade; + + for(ALsizei j{0};j < NUM_LINES;j++) + { + const ALfloat input{samples[j][i]}; + const ALfloat out{f[j] - feedCoeff*input}; + f[j] = input + feedCoeff*out; + + samples[j][i] = out; + } + ++i; - VectorScatterDelayIn(&delay, offset, f, xCoeff, yCoeff); - ++offset; + VectorPartialScatter(delay.Line[offset++], f, xCoeff, yCoeff); + } while(--td); } } @@ -1185,8 +1210,14 @@ void EarlyReflection_Unfaded(ReverbState *State, ALsizei offset, const ALsizei t { ALsizei early_delay_tap{offset - State->mEarlyDelayTap[j][0]}; const ALfloat coeff{State->mEarlyDelayCoeff[j][0]}; - for(ALsizei i{0};i < todo;i++) - temps[j][i] = main_delay.get(early_delay_tap++, j) * coeff; + for(ALsizei i{0};i < todo;) + { + early_delay_tap &= main_delay.Mask; + ALsizei td{mini(main_delay.Mask+1 - early_delay_tap, todo-i)}; + do { + temps[j][i++] = main_delay.Line[early_delay_tap++][j] * coeff; + } while(--td); + } } /* Apply a vector all-pass, to help color the initial reflections based on @@ -1199,12 +1230,19 @@ void EarlyReflection_Unfaded(ReverbState *State, ALsizei offset, const ALsizei t */ for(ALsizei j{0};j < NUM_LINES;j++) { - ALint early_feedb_tap{offset - State->mEarly.Offset[j][0]}; - const ALfloat early_feedb_coeff{State->mEarly.Coeff[j][0]}; + ALint feedb_tap{offset - State->mEarly.Offset[j][0]}; + const ALfloat feedb_coeff{State->mEarly.Coeff[j][0]}; ASSUME(base >= 0); - for(ALsizei i{0};i < todo;i++) - out[j][base+i] = early_delay.get(early_feedb_tap++, j)*early_feedb_coeff + temps[j][i]; + for(ALsizei i{0};i < todo;) + { + feedb_tap &= early_delay.Mask; + ALsizei td{mini(early_delay.Mask+1 - feedb_tap, todo - i)}; + do { + out[j][base+i] = temps[j][i] + early_delay.Line[feedb_tap++][j]*feedb_coeff; + ++i; + } while(--td); + } } for(ALsizei j{0};j < NUM_LINES;j++) early_delay.write(offset, NUM_LINES-1-j, temps[j], todo); @@ -1230,20 +1268,26 @@ void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsizei tod for(ALsizei j{0};j < NUM_LINES;j++) { - ALsizei early_delay_tap0 = offset - State->mEarlyDelayTap[j][0]; - ALsizei early_delay_tap1 = offset - State->mEarlyDelayTap[j][1]; - ALfloat oldCoeff = State->mEarlyDelayCoeff[j][0]; - ALfloat oldCoeffStep = -oldCoeff / FADE_SAMPLES; - ALfloat newCoeffStep = State->mEarlyDelayCoeff[j][1] / FADE_SAMPLES; - ALfloat fadeCount = fade; - - for(ALsizei i{0};i < todo;i++) + ALsizei early_delay_tap0{offset - State->mEarlyDelayTap[j][0]}; + ALsizei early_delay_tap1{offset - State->mEarlyDelayTap[j][1]}; + const ALfloat oldCoeff{State->mEarlyDelayCoeff[j][0]}; + const ALfloat oldCoeffStep{-oldCoeff / FADE_SAMPLES}; + const ALfloat newCoeffStep{State->mEarlyDelayCoeff[j][1] / FADE_SAMPLES}; + ALfloat fadeCount{fade}; + + for(ALsizei i{0};i < todo;) { - const ALfloat fade0{oldCoeff + oldCoeffStep*fadeCount}; - const ALfloat fade1{newCoeffStep*fadeCount}; - temps[j][i] = main_delay.getFaded(early_delay_tap0++, early_delay_tap1++, j, - fade0, fade1); - fadeCount += 1.0f; + early_delay_tap0 &= main_delay.Mask; + early_delay_tap1 &= main_delay.Mask; + ALsizei td{mini(main_delay.Mask+1 - maxi(early_delay_tap0, early_delay_tap1), todo-i)}; + do { + fadeCount += 1.0f; + const ALfloat fade0{oldCoeff + oldCoeffStep*fadeCount}; + const ALfloat fade1{newCoeffStep*fadeCount}; + temps[j][i++] = + main_delay.Line[early_delay_tap0++][j]*fade0 + + main_delay.Line[early_delay_tap1++][j]*fade1; + } while(--td); } } @@ -1259,13 +1303,21 @@ void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsizei tod ALfloat fadeCount{fade}; ASSUME(base >= 0); - for(ALsizei i{0};i < todo;i++) + for(ALsizei i{0};i < todo;) { - const ALfloat fade0{feedb_oldCoeff + feedb_oldCoeffStep*fadeCount}; - const ALfloat fade1{feedb_newCoeffStep*fadeCount}; - out[j][base+i] = early_delay.getFaded(feedb_tap0++, feedb_tap1++, j, fade0, fade1) + - temps[j][i]; - fadeCount += 1.0f; + feedb_tap0 &= early_delay.Mask; + feedb_tap1 &= early_delay.Mask; + ALsizei td{mini(early_delay.Mask+1 - maxi(feedb_tap0, feedb_tap1), todo - i)}; + + do { + fadeCount += 1.0f; + const ALfloat fade0{feedb_oldCoeff + feedb_oldCoeffStep*fadeCount}; + const ALfloat fade1{feedb_newCoeffStep*fadeCount}; + out[j][base+i] = temps[j][i] + + early_delay.Line[feedb_tap0++][j]*fade0 + + early_delay.Line[feedb_tap1++][j]*fade1; + ++i; + } while(--td); } } for(ALsizei j{0};j < NUM_LINES;j++) @@ -1309,9 +1361,19 @@ void LateReverb_Unfaded(ReverbState *State, ALsizei offset, const ALsizei todo, ALsizei late_feedb_tap{offset - State->mLate.Offset[j][0]}; const ALfloat midGain{State->mLate.T60[j].MidGain[0]}; const ALfloat densityGain{State->mLate.DensityGain[0] * midGain}; - for(ALsizei i{0};i < todo;i++) - temps[j][i] = main_delay.get(late_delay_tap++, j)*densityGain + - late_delay.get(late_feedb_tap++, j)*midGain; + for(ALsizei i{0};i < todo;) + { + late_delay_tap &= main_delay.Mask; + late_feedb_tap &= late_delay.Mask; + ALsizei td{mini( + mini(main_delay.Mask+1 - late_delay_tap, late_delay.Mask+1 - late_feedb_tap), + todo - i)}; + do { + temps[j][i++] = + main_delay.Line[late_delay_tap++][j]*densityGain + + late_delay.Line[late_feedb_tap++][j]*midGain; + } while(--td); + } State->mLate.T60[j].process(temps[j], todo); } @@ -1353,16 +1415,28 @@ void LateReverb_Faded(ReverbState *State, ALsizei offset, const ALsizei todo, co ALsizei late_feedb_tap1{offset - State->mLate.Offset[j][1]}; ALfloat fadeCount{fade}; - for(ALsizei i{0};i < todo;i++) + for(ALsizei i{0};i < todo;) { - const ALfloat fade0 = oldDensityGain + oldDensityStep*fadeCount; - const ALfloat fade1 = densityStep*fadeCount; - const ALfloat gfade0 = oldMidGain + oldMidStep*fadeCount; - const ALfloat gfade1 = midStep*fadeCount; - temps[j][i] = - main_delay.getFaded(late_delay_tap0++, late_delay_tap1++, j, fade0, fade1) + - late_delay.getFaded(late_feedb_tap0++, late_feedb_tap1++, j, gfade0, gfade1); - fadeCount += 1.0f; + late_delay_tap0 &= main_delay.Mask; + late_delay_tap1 &= main_delay.Mask; + late_feedb_tap0 &= late_delay.Mask; + late_feedb_tap1 &= late_delay.Mask; + ALsizei td{mini( + mini(main_delay.Mask+1 - maxi(late_delay_tap0, late_delay_tap1), + late_delay.Mask+1 - maxi(late_feedb_tap0, late_feedb_tap1)), + todo - i)}; + do { + fadeCount += 1.0f; + const ALfloat fade0{oldDensityGain + oldDensityStep*fadeCount}; + const ALfloat fade1{densityStep*fadeCount}; + const ALfloat gfade0{oldMidGain + oldMidStep*fadeCount}; + const ALfloat gfade1{midStep*fadeCount}; + temps[j][i++] = + main_delay.Line[late_delay_tap0++][j]*fade0 + + main_delay.Line[late_delay_tap1++][j]*fade1 + + late_delay.Line[late_feedb_tap0++][j]*gfade0 + + late_delay.Line[late_feedb_tap1++][j]*gfade1; + } while(--td); } State->mLate.T60[j].process(temps[j], todo); } @@ -1456,7 +1530,7 @@ void ReverbState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesI base += todo; } - mOffset = offset; + mOffset = offset & 0x3fffffff; mFadeCount = fadeCount; /* Finally, mix early reflections and late reverb. */ -- cgit v1.2.3 From a72c47164ca3515249d9fca0a155a0588693b9df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 1 May 2019 11:15:17 -0700 Subject: Avoid a few more array length assumptions --- Alc/effects/reverb.cpp | 71 +++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 927c545a..ff4e744b 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -24,7 +24,8 @@ #include #include -#include +#include +#include #include #include @@ -51,21 +52,21 @@ using namespace std::placeholders; /* This is the maximum number of samples processed for each inner loop * iteration. */ -#define MAX_UPDATE_SAMPLES 256 +constexpr int MAX_UPDATE_SAMPLES{256}; /* The number of samples used for cross-faded delay lines. This can be used * to balance the compensation for abrupt line changes and attenuation due to * minimally lengthed recursive lines. Try to keep this below the device * update size. */ -#define FADE_SAMPLES 128 +constexpr int FADE_SAMPLES{128}; /* The number of spatialized lines or channels to process. Four channels allows * for a 3D A-Format response. NOTE: This can't be changed without taking care * of the conversion matrices, and a few places where the length arrays are * assumed to have 4 elements. */ -#define NUM_LINES 4 +constexpr int NUM_LINES{4}; /* The B-Format to A-Format conversion matrix. The arrangement of rows is @@ -154,9 +155,9 @@ constexpr ALfloat DENSITY_SCALE{125000.0f}; * * Assuming an average of 1m, we get the following taps: */ -constexpr ALfloat EARLY_TAP_LENGTHS[NUM_LINES]{ +constexpr std::array EARLY_TAP_LENGTHS{{ 0.0000000e+0f, 2.0213520e-4f, 4.2531060e-4f, 6.7171600e-4f -}; +}}; /* The early all-pass filter lengths are based on the early tap lengths: * @@ -164,9 +165,9 @@ constexpr ALfloat EARLY_TAP_LENGTHS[NUM_LINES]{ * * Where a is the approximate maximum all-pass cycle limit (20). */ -const ALfloat EARLY_ALLPASS_LENGTHS[NUM_LINES]{ +constexpr std::array EARLY_ALLPASS_LENGTHS{{ 9.7096800e-5f, 1.0720356e-4f, 1.1836234e-4f, 1.3068260e-4f -}; +}}; /* The early delay lines are used to transform the primary reflections into * the secondary reflections. The A-format is arranged in such a way that @@ -190,17 +191,17 @@ const ALfloat EARLY_ALLPASS_LENGTHS[NUM_LINES]{ * * Using an average dimension of 1m, we get: */ -constexpr ALfloat EARLY_LINE_LENGTHS[NUM_LINES]{ +constexpr std::array EARLY_LINE_LENGTHS{{ 5.9850400e-4f, 1.0913150e-3f, 1.5376658e-3f, 1.9419362e-3f -}; +}}; /* The late all-pass filter lengths are based on the late line lengths: * * A_i = (5 / 3) L_i / r_1 */ -constexpr ALfloat LATE_ALLPASS_LENGTHS[NUM_LINES]{ +constexpr std::array LATE_ALLPASS_LENGTHS{{ 1.6182800e-4f, 2.0389060e-4f, 2.8159360e-4f, 3.2365600e-4f -}; +}}; /* The late lines are used to approximate the decaying cycle of recursive * late reflections. @@ -217,9 +218,9 @@ constexpr ALfloat LATE_ALLPASS_LENGTHS[NUM_LINES]{ * * For our 1m average room, we get: */ -constexpr ALfloat LATE_LINE_LENGTHS[NUM_LINES]{ +constexpr std::array LATE_LINE_LENGTHS{{ 1.9419362e-3f, 2.4466860e-3f, 3.3791220e-3f, 3.8838720e-3f -}; +}}; struct DelayLineI { @@ -514,27 +515,27 @@ bool ReverbState::allocLines(const ALfloat frequency) * largest late tap width. Finally, it must also be extended by the * update size (MAX_UPDATE_SAMPLES) for block processing. */ - ALfloat length{AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier + - AL_EAXREVERB_MAX_LATE_REVERB_DELAY + - (LATE_LINE_LENGTHS[NUM_LINES-1] - LATE_LINE_LENGTHS[0])*0.25f*multiplier}; + ALfloat length{AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS.back()*multiplier + + AL_EAXREVERB_MAX_LATE_REVERB_DELAY + + (LATE_LINE_LENGTHS.back() - LATE_LINE_LENGTHS.front())*0.25f*multiplier}; totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES, &mDelay); /* The early vector all-pass line. */ - length = EARLY_ALLPASS_LENGTHS[NUM_LINES-1] * multiplier; + length = EARLY_ALLPASS_LENGTHS.back() * multiplier; totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &mEarly.VecAp.Delay); /* The early reflection line. */ - length = EARLY_LINE_LENGTHS[NUM_LINES-1] * multiplier; + length = EARLY_LINE_LENGTHS.back() * multiplier; totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &mEarly.Delay); /* The late vector all-pass line. */ - length = LATE_ALLPASS_LENGTHS[NUM_LINES-1] * multiplier; + length = LATE_ALLPASS_LENGTHS.back() * multiplier; totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &mLate.VecAp.Delay); /* The late delay lines are calculated from the largest maximum density * line length. */ - length = LATE_LINE_LENGTHS[NUM_LINES-1] * multiplier; + length = LATE_LINE_LENGTHS.back() * multiplier; totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &mLate.Delay); totalSamples *= NUM_LINES; @@ -568,9 +569,8 @@ ALboolean ReverbState::deviceUpdate(const ALCdevice *device) const ALfloat multiplier{CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY)}; /* The late feed taps are set a fixed position past the latest delay tap. */ - mLateFeedTap = float2int((AL_EAXREVERB_MAX_REFLECTIONS_DELAY + - EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier) * - frequency); + mLateFeedTap = float2int( + (AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS.back()*multiplier) * frequency); /* Clear filters and gain coefficients since the delay lines were all just * cleared (if not reallocated). @@ -753,6 +753,10 @@ void LateReverb::updateLines(const ALfloat density, const ALfloat diffusion, */ const ALfloat norm_weight_factor{frequency / AL_EAXREVERB_MAX_HFREFERENCE}; + const ALfloat late_allpass_avg{ + std::accumulate(LATE_ALLPASS_LENGTHS.begin(), LATE_ALLPASS_LENGTHS.end(), 0.0f) / + static_cast(LATE_ALLPASS_LENGTHS.size())}; + /* To compensate for changes in modal density and decay time of the late * reverb signal, the input is attenuated based on the maximal energy of * the outgoing signal. This approximation is used to keep the apparent @@ -762,11 +766,9 @@ void LateReverb::updateLines(const ALfloat density, const ALfloat diffusion, * attenuation coefficient. */ const ALfloat multiplier{CalcDelayLengthMult(density)}; - ALfloat length{ - (LATE_LINE_LENGTHS[0] + LATE_LINE_LENGTHS[1] + LATE_LINE_LENGTHS[2] + - LATE_LINE_LENGTHS[3]) / 4.0f * multiplier}; - length += (LATE_ALLPASS_LENGTHS[0] + LATE_ALLPASS_LENGTHS[1] + - LATE_ALLPASS_LENGTHS[2] + LATE_ALLPASS_LENGTHS[3]) / 4.0f * multiplier; + ALfloat length{std::accumulate(LATE_LINE_LENGTHS.begin(), LATE_LINE_LENGTHS.end(), 0.0f) / + static_cast(LATE_LINE_LENGTHS.size()) * multiplier}; + length += late_allpass_avg * multiplier; /* The density gain calculation uses an average decay time weighted by * approximate bandwidth. This attempts to compensate for losses of energy * that reduce decay time due to scattering into highly attenuated bands. @@ -802,10 +804,7 @@ void LateReverb::updateLines(const ALfloat density, const ALfloat diffusion, * given the current diffusion so we don't have to process a full T60 * filter for each of its four lines. */ - length += lerp(LATE_ALLPASS_LENGTHS[i], - (LATE_ALLPASS_LENGTHS[0] + LATE_ALLPASS_LENGTHS[1] + - LATE_ALLPASS_LENGTHS[2] + LATE_ALLPASS_LENGTHS[3]) / 4.0f, - diffusion) * multiplier; + length += lerp(LATE_ALLPASS_LENGTHS[i], late_allpass_avg, diffusion) * multiplier; /* Calculate the T60 damping coefficients for each line. */ T60[i].calcCoeffs(length, lfDecayTime, mfDecayTime, hfDecayTime, lf0norm, hf0norm); @@ -837,7 +836,7 @@ void ReverbState::updateDelayLine(const ALfloat earlyDelay, const ALfloat lateDe length = EARLY_TAP_LENGTHS[i]*multiplier; mEarlyDelayCoeff[i][1] = CalcDecayCoeff(length, decayTime); - length = lateDelay + (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS[0])*0.25f*multiplier; + length = lateDelay + (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS.front())*0.25f*multiplier; mLateDelayTap[i][1] = mLateFeedTap + float2int(length * frequency); } } @@ -895,13 +894,13 @@ void ReverbState::update3DPanning(const ALfloat *ReflectionsPan, const ALfloat * const alu::Matrix latemat{GetTransformFromVector(LateReverbPan)}; mOutBuffer = target.Main->Buffer; mOutChannels = target.Main->NumChannels; - for(size_t i{0u};i < NUM_LINES;i++) + for(ALsizei i{0};i < NUM_LINES;i++) { const ALfloat coeffs[MAX_AMBI_CHANNELS]{earlymat[0][i], earlymat[1][i], earlymat[2][i], earlymat[3][i]}; ComputePanGains(target.Main, coeffs, earlyGain, mEarly.PanGain[i]); } - for(size_t i{0u};i < NUM_LINES;i++) + for(ALsizei i{0};i < NUM_LINES;i++) { const ALfloat coeffs[MAX_AMBI_CHANNELS]{latemat[0][i], latemat[1][i], latemat[2][i], latemat[3][i]}; -- cgit v1.2.3 From 2f2ec2b6e3ff8718d2d60c41925ab34eca1e4207 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 3 May 2019 00:50:47 -0700 Subject: Add some assumes and consts --- Alc/effects/reverb.cpp | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index ff4e744b..bb8a075a 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -1057,6 +1057,7 @@ inline void VectorScatterRevDelayIn(const DelayLineI *Delay, ALint offset, const DelayLineI delay{*Delay}; ASSUME(base >= 0); + ASSUME(count > 0); for(ALsizei i{0};i < count;) { @@ -1191,8 +1192,8 @@ void VecAllpass::processFaded(ALfloat (*RESTRICT samples)[BUFFERSIZE], ALsizei o * Two static specializations are used for transitional (cross-faded) delay * line processing and non-transitional processing. */ -void EarlyReflection_Unfaded(ReverbState *State, ALsizei offset, const ALsizei todo, - const ALsizei base, ALfloat (*RESTRICT out)[BUFFERSIZE]) +void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei todo, + const ALsizei base, ALfloat (*RESTRICT out)[BUFFERSIZE]) { ALfloat (*RESTRICT temps)[BUFFERSIZE]{State->mTempSamples}; const DelayLineI early_delay{State->mEarly.Delay}; @@ -1212,7 +1213,7 @@ void EarlyReflection_Unfaded(ReverbState *State, ALsizei offset, const ALsizei t for(ALsizei i{0};i < todo;) { early_delay_tap &= main_delay.Mask; - ALsizei td{mini(main_delay.Mask+1 - early_delay_tap, todo-i)}; + ALsizei td{mini(main_delay.Mask+1 - early_delay_tap, todo - i)}; do { temps[j][i++] = main_delay.Line[early_delay_tap++][j] * coeff; } while(--td); @@ -1253,9 +1254,8 @@ void EarlyReflection_Unfaded(ReverbState *State, ALsizei offset, const ALsizei t const ALsizei late_feed_tap{offset - State->mLateFeedTap}; VectorScatterRevDelayIn(&main_delay, late_feed_tap, mixX, mixY, base, out, todo); } -void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsizei todo, - const ALfloat fade, const ALsizei base, - ALfloat (*RESTRICT out)[BUFFERSIZE]) +void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, + const ALfloat fade, const ALsizei base, ALfloat (*RESTRICT out)[BUFFERSIZE]) { ALfloat (*RESTRICT temps)[BUFFERSIZE]{State->mTempSamples}; const DelayLineI early_delay{State->mEarly.Delay}; @@ -1340,8 +1340,8 @@ void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsizei tod * Two variations are made, one for for transitional (cross-faded) delay line * processing and one for non-transitional processing. */ -void LateReverb_Unfaded(ReverbState *State, ALsizei offset, const ALsizei todo, - const ALsizei base, ALfloat (*RESTRICT out)[BUFFERSIZE]) +void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei todo, + const ALsizei base, ALfloat (*RESTRICT out)[BUFFERSIZE]) { ALfloat (*RESTRICT temps)[BUFFERSIZE]{State->mTempSamples}; const DelayLineI late_delay{State->mLate.Delay}; @@ -1387,8 +1387,8 @@ void LateReverb_Unfaded(ReverbState *State, ALsizei offset, const ALsizei todo, /* Finally, scatter and bounce the results to refeed the feedback buffer. */ VectorScatterRevDelayIn(&late_delay, offset, mixX, mixY, base, out, todo); } -void LateReverb_Faded(ReverbState *State, ALsizei offset, const ALsizei todo, const ALfloat fade, - const ALsizei base, ALfloat (*RESTRICT out)[BUFFERSIZE]) +void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, + const ALfloat fade, const ALsizei base, ALfloat (*RESTRICT out)[BUFFERSIZE]) { ALfloat (*RESTRICT temps)[BUFFERSIZE]{State->mTempSamples}; const DelayLineI late_delay{State->mLate.Delay}; @@ -1451,7 +1451,6 @@ void LateReverb_Faded(ReverbState *State, ALsizei offset, const ALsizei todo, co void ReverbState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) { ALsizei fadeCount{mFadeCount}; - ALsizei offset{mOffset}; ASSUME(samplesToDo > 0); @@ -1478,7 +1477,10 @@ void ReverbState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesI todo = mini(todo, mMaxUpdate[0]); } todo = mini(todo, mMaxUpdate[1]); - ASSUME(todo > 0); + ASSUME(todo > 0 && todo <= MAX_UPDATE_SAMPLES); + + const ALsizei offset{mOffset + base}; + ASSUME(offset >= 0); /* Feed the initial delay line. */ for(ALsizei c{0};c < NUM_LINES;c++) @@ -1524,12 +1526,9 @@ void ReverbState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesI LateReverb_Unfaded(this, offset, todo, base, mLateBuffer); } - /* Step all delays forward. */ - offset += todo; - base += todo; } - mOffset = offset & 0x3fffffff; + mOffset = (mOffset+samplesToDo) & 0x3fffffff; mFadeCount = fadeCount; /* Finally, mix early reflections and late reverb. */ -- cgit v1.2.3 From 9eea2e4c7387de1a310e1085c3661fff3fe6209d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 3 May 2019 12:59:04 -0700 Subject: Use BUFFERSIZE for the reverb loop limit At 44/48khz, the main delay line comes out to 20k to 22k samples, which gets rounded up to 32k as the next power of two. This leaves plenty of room for the full 1k BUFFERSIZE without having to increase the delay line beyond what it already is. --- Alc/effects/reverb.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index bb8a075a..6b159b0c 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -49,11 +49,6 @@ namespace { using namespace std::placeholders; -/* This is the maximum number of samples processed for each inner loop - * iteration. - */ -constexpr int MAX_UPDATE_SAMPLES{256}; - /* The number of samples used for cross-faded delay lines. This can be used * to balance the compensation for abrupt line changes and attenuation due to * minimally lengthed recursive lines. Try to keep this below the device @@ -368,7 +363,7 @@ struct ReverbState final : public EffectState { ALsizei mFadeCount{0}; /* Maximum number of samples to process at once. */ - ALsizei mMaxUpdate[2]{MAX_UPDATE_SAMPLES, MAX_UPDATE_SAMPLES}; + ALsizei mMaxUpdate[2]{BUFFERSIZE, BUFFERSIZE}; /* The current write offset for all delay lines. */ ALsizei mOffset{0}; @@ -513,12 +508,12 @@ bool ReverbState::allocLines(const ALfloat frequency) /* The main delay length includes the maximum early reflection delay, the * largest early tap width, the maximum late reverb delay, and the * largest late tap width. Finally, it must also be extended by the - * update size (MAX_UPDATE_SAMPLES) for block processing. + * update size (BUFFERSIZE) for block processing. */ ALfloat length{AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS.back()*multiplier + AL_EAXREVERB_MAX_LATE_REVERB_DELAY + (LATE_LINE_LENGTHS.back() - LATE_LINE_LENGTHS.front())*0.25f*multiplier}; - totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES, &mDelay); + totalSamples += CalcLineLength(length, totalSamples, frequency, BUFFERSIZE, &mDelay); /* The early vector all-pass line. */ length = EARLY_ALLPASS_LENGTHS.back() * multiplier; @@ -607,7 +602,7 @@ ALboolean ReverbState::deviceUpdate(const ALCdevice *device) /* Reset counters and offset base. */ mFadeCount = 0; - std::fill(std::begin(mMaxUpdate), std::end(mMaxUpdate), MAX_UPDATE_SAMPLES); + std::fill(std::begin(mMaxUpdate), std::end(mMaxUpdate), BUFFERSIZE); mOffset = 0; if(device->mAmbiOrder > 1) @@ -968,7 +963,7 @@ void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, co props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain, target); /* Calculate the max update size from the smallest relevant delay. */ - mMaxUpdate[1] = mini(MAX_UPDATE_SAMPLES, mini(mEarly.Offset[0][1], mLate.Offset[0][1])); + mMaxUpdate[1] = mini(BUFFERSIZE, mini(mEarly.Offset[0][1], mLate.Offset[0][1])); /* Determine if delay-line cross-fading is required. Density is essentially * a master control for the feedback delays, so changes the offsets of many @@ -1477,7 +1472,7 @@ void ReverbState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesI todo = mini(todo, mMaxUpdate[0]); } todo = mini(todo, mMaxUpdate[1]); - ASSUME(todo > 0 && todo <= MAX_UPDATE_SAMPLES); + ASSUME(todo > 0 && todo <= BUFFERSIZE); const ALsizei offset{mOffset + base}; ASSUME(offset >= 0); -- cgit v1.2.3 From 1607f9c525eedb4af5b736990fd4e6640f37def0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 4 May 2019 13:53:11 -0700 Subject: Report the threshold limit for the output limiter --- Alc/alc.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 7c218785..3bc365c8 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2008,7 +2008,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) break; } } - if(gainLimiter != ALC_FALSE) + if(gainLimiter == ALC_FALSE) + TRACE("Output limiter disabled\n"); + else { ALfloat thrshld = 1.0f; switch(device->FmtType) @@ -2029,12 +2031,13 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(device->DitherDepth > 0.0f) thrshld -= 1.0f / device->DitherDepth; - auto limiter = CreateDeviceLimiter(device, std::log10(thrshld) * 20.0f); + const float thrshld_dB{std::log10(thrshld) * 20.0f}; + auto limiter = CreateDeviceLimiter(device, thrshld_dB); /* Convert the lookahead from samples to nanosamples to nanoseconds. */ device->FixedLatency += nanoseconds{seconds{limiter->getLookAhead()}} / device->Frequency; device->Limiter = std::move(limiter); + TRACE("Output limiter enabled, %.4fdB limit\n", thrshld_dB); } - TRACE("Output limiter %s\n", device->Limiter ? "enabled" : "disabled"); aluSelectPostProcess(device); -- cgit v1.2.3 From 5ff8d5ae32943c5325172799f31b7c5b66c4f054 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 4 May 2019 18:03:25 -0700 Subject: Add an exception class to cover backend creation and opening --- Alc/alc.cpp | 76 +++++++++++++++++++++++++++++------------------------- CMakeLists.txt | 1 + common/alexcpt.cpp | 30 +++++++++++++++++++++ common/alexcpt.h | 18 +++++++++++++ 4 files changed, 90 insertions(+), 35 deletions(-) create mode 100644 common/alexcpt.cpp diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 3bc365c8..9b4c2978 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -3680,20 +3680,22 @@ START_API_FUNC device->AuxiliaryEffectSlotMax = 64; device->NumAuxSends = DEFAULT_SENDS; - /* Create the device backend. */ - device->Backend = PlaybackBackend.getFactory().createBackend(device.get(), - BackendType::Playback); - if(!device->Backend) - { - alcSetError(nullptr, ALC_OUT_OF_MEMORY); - return nullptr; + try { + /* Create the device backend. */ + device->Backend = PlaybackBackend.getFactory().createBackend(device.get(), + BackendType::Playback); + + /* Find a playback device to open */ + ALCenum err{device->Backend->open(deviceName)}; + if(err != ALC_NO_ERROR) + { + alcSetError(nullptr, err); + return nullptr; + } } - - /* Find a playback device to open */ - ALCenum err{device->Backend->open(deviceName)}; - if(err != ALC_NO_ERROR) - { - alcSetError(nullptr, err); + catch(al::backend_exception &e) { + WARN("Failed to open playback device: %s\n", e.what()); + alcSetError(nullptr, e.errorCode()); return nullptr; } @@ -3934,21 +3936,23 @@ START_API_FUNC device->UpdateSize = samples; device->BufferSize = samples; - device->Backend = CaptureBackend.getFactory().createBackend(device.get(), - BackendType::Capture); - if(!device->Backend) - { - alcSetError(nullptr, ALC_OUT_OF_MEMORY); - return nullptr; - } + try { + device->Backend = CaptureBackend.getFactory().createBackend(device.get(), + BackendType::Capture); - TRACE("Capture format: %s, %s, %uhz, %u / %u buffer\n", - DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), - device->Frequency, device->UpdateSize, device->BufferSize); - ALCenum err{device->Backend->open(deviceName)}; - if(err != ALC_NO_ERROR) - { - alcSetError(nullptr, err); + TRACE("Capture format: %s, %s, %uhz, %u / %u buffer\n", + DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), + device->Frequency, device->UpdateSize, device->BufferSize); + ALCenum err{device->Backend->open(deviceName)}; + if(err != ALC_NO_ERROR) + { + alcSetError(nullptr, err); + return nullptr; + } + } + catch(al::backend_exception &e) { + WARN("Failed to open capture device: %s\n", e.what()); + alcSetError(nullptr, e.errorCode()); return nullptr; } @@ -4108,17 +4112,19 @@ START_API_FUNC device->NumStereoSources = 1; device->NumMonoSources = device->SourcesMax - device->NumStereoSources; - device->Backend = LoopbackBackendFactory::getFactory().createBackend(device.get(), - BackendType::Playback); - if(!device->Backend) - { - alcSetError(nullptr, ALC_OUT_OF_MEMORY); + try { + device->Backend = LoopbackBackendFactory::getFactory().createBackend(device.get(), + BackendType::Playback); + + // Open the "backend" + device->Backend->open("Loopback"); + } + catch(al::backend_exception &e) { + WARN("Failed to open loopback device: %s\n", e.what()); + alcSetError(nullptr, e.errorCode()); return nullptr; } - // Open the "backend" - device->Backend->open("Loopback"); - { std::lock_guard _{ListLock}; auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get()); diff --git a/CMakeLists.txt b/CMakeLists.txt index 4367b2df..68a76dad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -641,6 +641,7 @@ ENDIF() SET(COMMON_OBJS common/alcomplex.cpp common/alcomplex.h + common/alexcpt.cpp common/alexcpt.h common/almalloc.cpp common/almalloc.h diff --git a/common/alexcpt.cpp b/common/alexcpt.cpp new file mode 100644 index 00000000..21508b13 --- /dev/null +++ b/common/alexcpt.cpp @@ -0,0 +1,30 @@ + +#include "config.h" + +#include "alexcpt.h" + +#include +#include + +#include "opthelpers.h" + + +namespace al { + +backend_exception::backend_exception(ALCenum code, const char *msg, ...) : mErrorCode{code} +{ + va_list args, args2; + va_start(args, msg); + va_copy(args2, args); + int msglen{std::vsnprintf(nullptr, 0, msg, args)}; + if(UNLIKELY(msglen > 0)) + { + mMessage.resize(static_cast(msglen)+1); + std::vsnprintf(&mMessage[0], mMessage.length(), msg, args2); + mMessage.pop_back(); + } + va_end(args2); + va_end(args); +} + +} // namespace al diff --git a/common/alexcpt.h b/common/alexcpt.h index 3e31667e..b4f6f55e 100644 --- a/common/alexcpt.h +++ b/common/alexcpt.h @@ -2,7 +2,25 @@ #define ALEXCPT_H #include +#include +#include "AL/alc.h" + + +namespace al { + +class backend_exception final : public std::exception { + std::string mMessage; + ALCenum mErrorCode; + +public: + backend_exception(ALCenum code, const char *msg, ...); + + const char *what() const noexcept override { return mMessage.c_str(); } + ALCenum errorCode() const noexcept { return mErrorCode; } +}; + +} // namespace al #define START_API_FUNC try -- cgit v1.2.3 From b9592bddbc014759941b94b76596c1dbf2245ad3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 4 May 2019 18:25:59 -0700 Subject: Add the printf format attribute to backend_exception's constructor --- common/alexcpt.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/common/alexcpt.h b/common/alexcpt.h index b4f6f55e..ff09bab2 100644 --- a/common/alexcpt.h +++ b/common/alexcpt.h @@ -7,6 +7,13 @@ #include "AL/alc.h" +#ifdef __GNUC__ +#define ALEXCPT_FORMAT(x, y, z) __attribute__((format(x, (y), (z)))) +#else +#define ALEXCPT_FORMAT(x, y, z) +#endif + + namespace al { class backend_exception final : public std::exception { @@ -14,7 +21,7 @@ class backend_exception final : public std::exception { ALCenum mErrorCode; public: - backend_exception(ALCenum code, const char *msg, ...); + backend_exception(ALCenum code, const char *msg, ...) ALEXCPT_FORMAT(printf, 3,4); const char *what() const noexcept override { return mMessage.c_str(); } ALCenum errorCode() const noexcept { return mErrorCode; } -- cgit v1.2.3 From 95d19be36bf1d8b08fdb9cd09d94bc37658deea6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 4 May 2019 20:17:54 -0700 Subject: Catch exceptions from backend reset --- Alc/alc.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 9b4c2978..6bd755bf 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1888,8 +1888,14 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) (device->Flags&DEVICE_FREQUENCY_REQUEST)?"*":"", device->Frequency, device->UpdateSize, device->BufferSize); - if(device->Backend->reset() == ALC_FALSE) + try { + if(device->Backend->reset() == ALC_FALSE) + return ALC_INVALID_DEVICE; + } + catch(std::exception &e) { + ERR("Device reset failed: %s\n", e.what()); return ALC_INVALID_DEVICE; + } if(device->FmtChans != oldChans && (device->Flags&DEVICE_CHANNELS_REQUEST)) { -- cgit v1.2.3 From 31c29f1ea85e9edf0061721082f6f39d8e862922 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 4 May 2019 20:35:24 -0700 Subject: Use exceptions when opening and reseting the PulseAudio backend --- Alc/backends/pulseaudio.cpp | 199 ++++++++++++++++++-------------------------- 1 file changed, 82 insertions(+), 117 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index f3d5d453..cc65e5fc 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -38,6 +38,7 @@ #include "alu.h" #include "alconfig.h" #include "compat.h" +#include "alexcpt.h" #include @@ -264,7 +265,7 @@ void wait_for_operation(pa_operation *op, std::unique_lock &plock) } -pa_context *connect_context(std::unique_lock &plock, ALboolean silent) +pa_context *connect_context(std::unique_lock &plock) { const char *name{"OpenAL Soft"}; @@ -280,11 +281,7 @@ pa_context *connect_context(std::unique_lock &plock, ALboolean silen } pa_context *context{pa_context_new(pa_mainloop_get_api(pulse_mainloop), name)}; - if(!context) - { - ERR("pa_context_new() failed\n"); - return nullptr; - } + if(!context) throw al::backend_exception{ALC_OUT_OF_MEMORY, "pa_context_new() failed"}; pa_context_set_state_callback(context, context_state_callback, nullptr); @@ -308,25 +305,15 @@ pa_context *connect_context(std::unique_lock &plock, ALboolean silen if(err < 0) { - if(!silent) - ERR("Context did not connect: %s\n", pa_strerror(err)); pa_context_unref(context); - context = nullptr; + throw al::backend_exception{ALC_INVALID_VALUE, "Context did not connect (%s)", + pa_strerror(err)}; } return context; } -pa_context *pulse_open(void(*state_cb)(pa_context*,void*), void *ptr) -{ - std::unique_lock plock{pulse_lock}; - pa_context *context{connect_context(plock, AL_FALSE)}; - if(LIKELY(context)) - pa_context_set_state_callback(context, state_cb, ptr); - return context; -} - void pulse_close(pa_context *context, pa_stream *stream) { std::lock_guard _{pulse_lock}; @@ -366,13 +353,11 @@ pa_stream *pulse_connect_stream(const char *device_name, std::unique_lock plock{pulse_lock}; + try { + std::unique_lock plock{pulse_lock}; - pa_context *context{connect_context(plock, AL_FALSE)}; - if(!context) return; + pa_context *context{connect_context(plock)}; - pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS | - PA_STREAM_DONT_MOVE}; + const pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | + PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE}; - pa_sample_spec spec{}; - spec.format = PA_SAMPLE_S16NE; - spec.rate = 44100; - spec.channels = 2; + pa_sample_spec spec{}; + spec.format = PA_SAMPLE_S16NE; + spec.rate = 44100; + spec.channels = 2; - pa_stream *stream{pulse_connect_stream(nullptr, plock, context, flags, nullptr, &spec, nullptr, - BackendType::Playback)}; - if(stream) - { + pa_stream *stream{pulse_connect_stream(nullptr, plock, context, flags, nullptr, &spec, + nullptr, BackendType::Playback)}; pa_operation *op{pa_context_get_sink_info_by_name(context, pa_stream_get_device_name(stream), device_sink_callback, nullptr)}; wait_for_operation(op, plock); @@ -464,13 +448,16 @@ void probePlaybackDevices() pa_stream_disconnect(stream); pa_stream_unref(stream); stream = nullptr; - } - pa_operation *op{pa_context_get_sink_info_list(context, device_sink_callback, nullptr)}; - wait_for_operation(op, plock); + op = pa_context_get_sink_info_list(context, device_sink_callback, nullptr); + wait_for_operation(op, plock); - pa_context_disconnect(context); - pa_context_unref(context); + pa_context_disconnect(context); + pa_context_unref(context); + } + catch(std::exception &e) { + ERR("Error enumerating devices: %s\n", e.what()); + } } @@ -510,23 +497,21 @@ void probeCaptureDevices() { CaptureDevices.clear(); - std::unique_lock plock{pulse_lock}; + try { + std::unique_lock plock{pulse_lock}; - pa_context *context{connect_context(plock, AL_FALSE)}; - if(!context) return; + pa_context *context{connect_context(plock)}; - pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS | - PA_STREAM_DONT_MOVE}; + const pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | + PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE}; - pa_sample_spec spec{}; - spec.format = PA_SAMPLE_S16NE; - spec.rate = 44100; - spec.channels = 1; + pa_sample_spec spec{}; + spec.format = PA_SAMPLE_S16NE; + spec.rate = 44100; + spec.channels = 1; - pa_stream *stream{pulse_connect_stream(nullptr, plock, context, flags, nullptr, &spec, nullptr, - BackendType::Capture)}; - if(stream) - { + pa_stream *stream{pulse_connect_stream(nullptr, plock, context, flags, nullptr, &spec, nullptr, + BackendType::Capture)}; pa_operation *op{pa_context_get_source_info_by_name(context, pa_stream_get_device_name(stream), device_source_callback, nullptr)}; wait_for_operation(op, plock); @@ -534,13 +519,16 @@ void probeCaptureDevices() pa_stream_disconnect(stream); pa_stream_unref(stream); stream = nullptr; - } - pa_operation *op{pa_context_get_source_info_list(context, device_source_callback, nullptr)}; - wait_for_operation(op, plock); + op = pa_context_get_source_info_list(context, device_source_callback, nullptr); + wait_for_operation(op, plock); - pa_context_disconnect(context); - pa_context_unref(context); + pa_context_disconnect(context); + pa_context_unref(context); + } + catch(std::exception &e) { + ERR("Error enumerating devices: %s\n", e.what()); + } } @@ -763,16 +751,16 @@ ALCenum PulsePlayback::open(const ALCchar *name) { return entry.name == name; } ); if(iter == PlaybackDevices.cend()) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; pulse_name = iter->device_name.c_str(); dev_name = iter->name.c_str(); } - mContext = pulse_open(&PulsePlayback::contextStateCallbackC, this); - if(!mContext) return ALC_INVALID_VALUE; - std::unique_lock plock{pulse_lock}; + mContext = connect_context(plock); + pa_context_set_state_callback(mContext, &PulsePlayback::contextStateCallbackC, this); + pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS}; if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 1)) flags |= PA_STREAM_DONT_MOVE; @@ -782,21 +770,15 @@ ALCenum PulsePlayback::open(const ALCchar *name) spec.rate = 44100; spec.channels = 2; - TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); if(!pulse_name) { pulse_name = getenv("ALSOFT_PULSE_DEFAULT"); if(pulse_name && !pulse_name[0]) pulse_name = nullptr; } + TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); mStream = pulse_connect_stream(pulse_name, plock, mContext, flags, nullptr, &spec, nullptr, BackendType::Playback); - if(!mStream) - { - plock.unlock(); - pulse_close(mContext, mStream); - mContext = nullptr; - return ALC_INVALID_VALUE; - } + pa_stream_set_moved_callback(mStream, &PulsePlayback::streamMovedCallbackC, this); mFrameSize = pa_frame_size(pa_stream_get_sample_spec(mStream)); @@ -877,10 +859,7 @@ ALCboolean PulsePlayback::reset() mSpec.channels = mDevice->channelsFromFmt(); if(pa_sample_spec_valid(&mSpec) == 0) - { - ERR("Invalid sample format\n"); - return ALC_FALSE; - } + throw al::backend_exception{ALC_INVALID_VALUE, "Invalid sample spec"}; const char *mapname{nullptr}; pa_channel_map chanmap; @@ -912,10 +891,8 @@ ALCboolean PulsePlayback::reset() break; } if(!pa_channel_map_parse(&chanmap, mapname)) - { - ERR("Failed to build channel map for %s\n", DevFmtChannelsString(mDevice->FmtChans)); - return ALC_FALSE; - } + throw al::backend_exception{ALC_INVALID_VALUE, "Could not build channel map for %s", + DevFmtChannelsString(mDevice->FmtChans)}; SetDefaultWFXChannelOrder(mDevice); mAttr.maxlength = -1; @@ -926,7 +903,6 @@ ALCboolean PulsePlayback::reset() mStream = pulse_connect_stream(mDeviceName.c_str(), plock, mContext, flags, &mAttr, &mSpec, &chanmap, BackendType::Playback); - if(!mStream) return ALC_FALSE; pa_stream_set_state_callback(mStream, &PulsePlayback::streamStateCallbackC, this); pa_stream_set_moved_callback(mStream, &PulsePlayback::streamMovedCallbackC, this); @@ -1152,16 +1128,16 @@ ALCenum PulseCapture::open(const ALCchar *name) { return entry.name == name; } ); if(iter == CaptureDevices.cend()) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; pulse_name = iter->device_name.c_str(); mDevice->DeviceName = iter->name; } - mContext = pulse_open(&PulseCapture::contextStateCallbackC, this); - if(!mContext) return ALC_INVALID_VALUE; - std::unique_lock plock{pulse_lock}; + mContext = connect_context(plock); + pa_context_set_state_callback(mContext, &PulseCapture::contextStateCallbackC, this); + switch(mDevice->FmtType) { case DevFmtUByte: @@ -1179,8 +1155,8 @@ ALCenum PulseCapture::open(const ALCchar *name) case DevFmtByte: case DevFmtUShort: case DevFmtUInt: - ERR("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", + DevFmtTypeString(mDevice->FmtType)}; } const char *mapname{nullptr}; @@ -1209,29 +1185,18 @@ ALCenum PulseCapture::open(const ALCchar *name) mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right"; break; case DevFmtAmbi3D: - ERR("%s capture samples not supported\n", DevFmtChannelsString(mDevice->FmtChans)); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", + DevFmtChannelsString(mDevice->FmtChans)}; } if(!pa_channel_map_parse(&chanmap, mapname)) - { - ERR("Failed to build channel map for %s\n", DevFmtChannelsString(mDevice->FmtChans)); - return ALC_INVALID_VALUE; - } + throw al::backend_exception{ALC_INVALID_VALUE, "Could not build channel map for %s", + DevFmtChannelsString(mDevice->FmtChans)}; mSpec.rate = mDevice->Frequency; mSpec.channels = mDevice->channelsFromFmt(); if(pa_sample_spec_valid(&mSpec) == 0) - { - ERR("Invalid sample format\n"); - return ALC_INVALID_VALUE; - } - - if(!pa_channel_map_init_auto(&chanmap, mSpec.channels, PA_CHANNEL_MAP_WAVEEX)) - { - ERR("Couldn't build map for channel count (%d)!\n", mSpec.channels); - return ALC_INVALID_VALUE; - } + throw al::backend_exception{ALC_INVALID_VALUE, "Invalid sample format"}; ALuint samples{mDevice->BufferSize}; samples = maxu(samples, 100 * mDevice->Frequency / 1000); @@ -1249,7 +1214,6 @@ ALCenum PulseCapture::open(const ALCchar *name) TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); mStream = pulse_connect_stream(pulse_name, plock, mContext, flags, &mAttr, &mSpec, &chanmap, BackendType::Capture); - if(!mStream) return ALC_INVALID_VALUE; pa_stream_set_moved_callback(mStream, &PulseCapture::streamMovedCallbackC, this); pa_stream_set_state_callback(mStream, &PulseCapture::streamStateCallbackC, this); @@ -1437,15 +1401,16 @@ bool PulseBackendFactory::init() if(!GetConfigValueBool(nullptr, "pulse", "spawn-server", 1)) pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN; - std::unique_lock plock{pulse_lock}; - - pa_context *context{connect_context(plock, AL_TRUE)}; - if(!context) return false; - - pa_context_disconnect(context); - pa_context_unref(context); - - return true; + try { + std::unique_lock plock{pulse_lock}; + pa_context *context{connect_context(plock)}; + pa_context_disconnect(context); + pa_context_unref(context); + return true; + } + catch(...) { + return false; + } } bool PulseBackendFactory::querySupport(BackendType type) -- cgit v1.2.3 From 1b11ca48dc90fc7a6e67c5074f9b63f5b2cd8711 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 4 May 2019 20:54:49 -0700 Subject: Avoid unnecessary parsing for channel maps --- Alc/backends/pulseaudio.cpp | 115 +++++++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 54 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index cc65e5fc..c640b293 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -176,6 +176,44 @@ PULSE_FUNCS(MAKE_FUNC) #endif +constexpr pa_channel_map MonoChanMap{ + 1, {PA_CHANNEL_POSITION_MONO} +}, StereoChanMap{ + 2, {PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT} +}, QuadChanMap{ + 4, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT + } +}, X51ChanMap{ + 6, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT + } +}, X51RearChanMap{ + 6, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT + } +}, X61ChanMap{ + 7, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_REAR_CENTER, + PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT + } +}, X71ChanMap{ + 8, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, + PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT + } +}; + + /* *grumble* Don't use enums for bitflags. */ inline pa_stream_flags_t operator|(pa_stream_flags_t lhs, pa_stream_flags_t rhs) { return pa_stream_flags_t(int(lhs) | int(rhs)); } @@ -653,36 +691,13 @@ void PulsePlayback::sinkInfoCallback(pa_context* UNUSED(context), const pa_sink_ pa_channel_map map; }; static constexpr std::array chanmaps{{ - { DevFmtX71, { 8, { - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, - PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, - PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT - } } }, - { DevFmtX61, { 7, { - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, - PA_CHANNEL_POSITION_REAR_CENTER, - PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT - } } }, - { DevFmtX51, { 6, { - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, - PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT - } } }, - { DevFmtX51Rear, { 6, { - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, - PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT - } } }, - { DevFmtQuad, { 4, { - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT - } } }, - { DevFmtStereo, { 2, { - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT - } } }, - { DevFmtMono, { 1, {PA_CHANNEL_POSITION_MONO} } } + { DevFmtX71, X71ChanMap }, + { DevFmtX61, X61ChanMap }, + { DevFmtX51, X51ChanMap }, + { DevFmtX51Rear, X51RearChanMap }, + { DevFmtQuad, QuadChanMap }, + { DevFmtStereo, StereoChanMap }, + { DevFmtMono, MonoChanMap } }}; if(eol) @@ -861,38 +876,34 @@ ALCboolean PulsePlayback::reset() if(pa_sample_spec_valid(&mSpec) == 0) throw al::backend_exception{ALC_INVALID_VALUE, "Invalid sample spec"}; - const char *mapname{nullptr}; - pa_channel_map chanmap; + pa_channel_map chanmap{}; switch(mDevice->FmtChans) { case DevFmtMono: - mapname = "mono"; + chanmap = MonoChanMap; break; case DevFmtAmbi3D: mDevice->FmtChans = DevFmtStereo; /*fall-through*/ case DevFmtStereo: - mapname = "front-left,front-right"; + chanmap = StereoChanMap; break; case DevFmtQuad: - mapname = "front-left,front-right,rear-left,rear-right"; + chanmap = QuadChanMap; break; case DevFmtX51: - mapname = "front-left,front-right,front-center,lfe,side-left,side-right"; + chanmap = X51ChanMap; break; case DevFmtX51Rear: - mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right"; + chanmap = X51RearChanMap; break; case DevFmtX61: - mapname = "front-left,front-right,front-center,lfe,rear-center,side-left,side-right"; + chanmap = X61ChanMap; break; case DevFmtX71: - mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right"; + chanmap = X71ChanMap; break; } - if(!pa_channel_map_parse(&chanmap, mapname)) - throw al::backend_exception{ALC_INVALID_VALUE, "Could not build channel map for %s", - DevFmtChannelsString(mDevice->FmtChans)}; SetDefaultWFXChannelOrder(mDevice); mAttr.maxlength = -1; @@ -1159,38 +1170,34 @@ ALCenum PulseCapture::open(const ALCchar *name) DevFmtTypeString(mDevice->FmtType)}; } - const char *mapname{nullptr}; - pa_channel_map chanmap; + pa_channel_map chanmap{}; switch(mDevice->FmtChans) { case DevFmtMono: - mapname = "mono"; + chanmap = MonoChanMap; break; case DevFmtStereo: - mapname = "front-left,front-right"; + chanmap = StereoChanMap; break; case DevFmtQuad: - mapname = "front-left,front-right,rear-left,rear-right"; + chanmap = QuadChanMap; break; case DevFmtX51: - mapname = "front-left,front-right,front-center,lfe,side-left,side-right"; + chanmap = X51ChanMap; break; case DevFmtX51Rear: - mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right"; + chanmap = X51RearChanMap; break; case DevFmtX61: - mapname = "front-left,front-right,front-center,lfe,rear-center,side-left,side-right"; + chanmap = X61ChanMap; break; case DevFmtX71: - mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right"; + chanmap = X71ChanMap; break; case DevFmtAmbi3D: throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", DevFmtChannelsString(mDevice->FmtChans)}; } - if(!pa_channel_map_parse(&chanmap, mapname)) - throw al::backend_exception{ALC_INVALID_VALUE, "Could not build channel map for %s", - DevFmtChannelsString(mDevice->FmtChans)}; mSpec.rate = mDevice->Frequency; mSpec.channels = mDevice->channelsFromFmt(); -- cgit v1.2.3 From 42dfefbb0e2d9564e977d392a651184b1ac8d490 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 4 May 2019 22:11:29 -0700 Subject: Fix when PulseAudio channel configuration changes --- Alc/backends/pulseaudio.cpp | 101 +++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 52 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index c640b293..d8e1c267 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -846,36 +846,6 @@ ALCboolean PulsePlayback::reset() !(mDevice->Flags&DEVICE_FREQUENCY_REQUEST)) flags |= PA_STREAM_FIX_RATE; - switch(mDevice->FmtType) - { - case DevFmtByte: - mDevice->FmtType = DevFmtUByte; - /* fall-through */ - case DevFmtUByte: - mSpec.format = PA_SAMPLE_U8; - break; - case DevFmtUShort: - mDevice->FmtType = DevFmtShort; - /* fall-through */ - case DevFmtShort: - mSpec.format = PA_SAMPLE_S16NE; - break; - case DevFmtUInt: - mDevice->FmtType = DevFmtInt; - /* fall-through */ - case DevFmtInt: - mSpec.format = PA_SAMPLE_S32NE; - break; - case DevFmtFloat: - mSpec.format = PA_SAMPLE_FLOAT32NE; - break; - } - mSpec.rate = mDevice->Frequency; - mSpec.channels = mDevice->channelsFromFmt(); - - if(pa_sample_spec_valid(&mSpec) == 0) - throw al::backend_exception{ALC_INVALID_VALUE, "Invalid sample spec"}; - pa_channel_map chanmap{}; switch(mDevice->FmtChans) { @@ -906,6 +876,35 @@ ALCboolean PulsePlayback::reset() } SetDefaultWFXChannelOrder(mDevice); + switch(mDevice->FmtType) + { + case DevFmtByte: + mDevice->FmtType = DevFmtUByte; + /* fall-through */ + case DevFmtUByte: + mSpec.format = PA_SAMPLE_U8; + break; + case DevFmtUShort: + mDevice->FmtType = DevFmtShort; + /* fall-through */ + case DevFmtShort: + mSpec.format = PA_SAMPLE_S16NE; + break; + case DevFmtUInt: + mDevice->FmtType = DevFmtInt; + /* fall-through */ + case DevFmtInt: + mSpec.format = PA_SAMPLE_S32NE; + break; + case DevFmtFloat: + mSpec.format = PA_SAMPLE_FLOAT32NE; + break; + } + mSpec.rate = mDevice->Frequency; + mSpec.channels = mDevice->channelsFromFmt(); + if(pa_sample_spec_valid(&mSpec) == 0) + throw al::backend_exception{ALC_INVALID_VALUE, "Invalid sample spec"}; + mAttr.maxlength = -1; mAttr.tlength = mDevice->BufferSize * pa_frame_size(&mSpec); mAttr.prebuf = 0; @@ -1149,27 +1148,6 @@ ALCenum PulseCapture::open(const ALCchar *name) mContext = connect_context(plock); pa_context_set_state_callback(mContext, &PulseCapture::contextStateCallbackC, this); - switch(mDevice->FmtType) - { - case DevFmtUByte: - mSpec.format = PA_SAMPLE_U8; - break; - case DevFmtShort: - mSpec.format = PA_SAMPLE_S16NE; - break; - case DevFmtInt: - mSpec.format = PA_SAMPLE_S32NE; - break; - case DevFmtFloat: - mSpec.format = PA_SAMPLE_FLOAT32NE; - break; - case DevFmtByte: - case DevFmtUShort: - case DevFmtUInt: - throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", - DevFmtTypeString(mDevice->FmtType)}; - } - pa_channel_map chanmap{}; switch(mDevice->FmtChans) { @@ -1199,9 +1177,28 @@ ALCenum PulseCapture::open(const ALCchar *name) DevFmtChannelsString(mDevice->FmtChans)}; } + switch(mDevice->FmtType) + { + case DevFmtUByte: + mSpec.format = PA_SAMPLE_U8; + break; + case DevFmtShort: + mSpec.format = PA_SAMPLE_S16NE; + break; + case DevFmtInt: + mSpec.format = PA_SAMPLE_S32NE; + break; + case DevFmtFloat: + mSpec.format = PA_SAMPLE_FLOAT32NE; + break; + case DevFmtByte: + case DevFmtUShort: + case DevFmtUInt: + throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", + DevFmtTypeString(mDevice->FmtType)}; + } mSpec.rate = mDevice->Frequency; mSpec.channels = mDevice->channelsFromFmt(); - if(pa_sample_spec_valid(&mSpec) == 0) throw al::backend_exception{ALC_INVALID_VALUE, "Invalid sample format"}; -- cgit v1.2.3 From 0c09c8378bc2c6a300177bcb417b7bf534ac4bf4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 4 May 2019 23:45:27 -0700 Subject: Set the device channel order from PulseAudio's channel map --- Alc/backends/pulseaudio.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index d8e1c267..f5483818 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -213,6 +213,74 @@ constexpr pa_channel_map MonoChanMap{ } }; +size_t ChannelFromPulse(pa_channel_position_t chan) +{ + switch(chan) + { + case PA_CHANNEL_POSITION_INVALID: break; + case PA_CHANNEL_POSITION_MONO: return FrontCenter; + case PA_CHANNEL_POSITION_FRONT_LEFT: return FrontLeft; + case PA_CHANNEL_POSITION_FRONT_RIGHT: return FrontRight; + case PA_CHANNEL_POSITION_FRONT_CENTER: return FrontCenter; + case PA_CHANNEL_POSITION_REAR_CENTER: return BackCenter; + case PA_CHANNEL_POSITION_REAR_LEFT: return BackLeft; + case PA_CHANNEL_POSITION_REAR_RIGHT: return BackRight; + case PA_CHANNEL_POSITION_LFE: return LFE; + case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER: break; + case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER: break; + case PA_CHANNEL_POSITION_SIDE_LEFT: return SideLeft; + case PA_CHANNEL_POSITION_SIDE_RIGHT: return SideRight; + case PA_CHANNEL_POSITION_AUX0: return Aux0; + case PA_CHANNEL_POSITION_AUX1: return Aux1; + case PA_CHANNEL_POSITION_AUX2: return Aux2; + case PA_CHANNEL_POSITION_AUX3: return Aux3; + case PA_CHANNEL_POSITION_AUX4: return Aux4; + case PA_CHANNEL_POSITION_AUX5: return Aux5; + case PA_CHANNEL_POSITION_AUX6: return Aux6; + case PA_CHANNEL_POSITION_AUX7: return Aux7; + case PA_CHANNEL_POSITION_AUX8: return Aux8; + case PA_CHANNEL_POSITION_AUX9: return Aux9; + case PA_CHANNEL_POSITION_AUX10: return Aux10; + case PA_CHANNEL_POSITION_AUX11: return Aux11; + case PA_CHANNEL_POSITION_AUX12: return Aux12; + case PA_CHANNEL_POSITION_AUX13: return Aux13; + case PA_CHANNEL_POSITION_AUX14: return Aux14; + case PA_CHANNEL_POSITION_AUX15: return Aux15; + case PA_CHANNEL_POSITION_AUX16: break; + case PA_CHANNEL_POSITION_AUX17: break; + case PA_CHANNEL_POSITION_AUX18: break; + case PA_CHANNEL_POSITION_AUX19: break; + case PA_CHANNEL_POSITION_AUX20: break; + case PA_CHANNEL_POSITION_AUX21: break; + case PA_CHANNEL_POSITION_AUX22: break; + case PA_CHANNEL_POSITION_AUX23: break; + case PA_CHANNEL_POSITION_AUX24: break; + case PA_CHANNEL_POSITION_AUX25: break; + case PA_CHANNEL_POSITION_AUX26: break; + case PA_CHANNEL_POSITION_AUX27: break; + case PA_CHANNEL_POSITION_AUX28: break; + case PA_CHANNEL_POSITION_AUX29: break; + case PA_CHANNEL_POSITION_AUX30: break; + case PA_CHANNEL_POSITION_AUX31: break; + case PA_CHANNEL_POSITION_TOP_CENTER: break; + case PA_CHANNEL_POSITION_TOP_FRONT_LEFT: return UpperFrontLeft; + case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT: return UpperFrontRight; + case PA_CHANNEL_POSITION_TOP_FRONT_CENTER: break; + case PA_CHANNEL_POSITION_TOP_REAR_LEFT: return UpperBackLeft; + case PA_CHANNEL_POSITION_TOP_REAR_RIGHT: return UpperBackRight; + case PA_CHANNEL_POSITION_TOP_REAR_CENTER: break; + case PA_CHANNEL_POSITION_MAX: break; + } + throw al::backend_exception{ALC_INVALID_VALUE, "Unexpected channel enum %d", chan}; +} + +void SetChannelOrderFromMap(ALCdevice *device, const pa_channel_map &chanmap) +{ + device->RealOut.ChannelIndex.fill(-1); + for(int i{0};i < chanmap.channels;++i) + device->RealOut.ChannelIndex[ChannelFromPulse(chanmap.map[i])] = i; +} + /* *grumble* Don't use enums for bitflags. */ inline pa_stream_flags_t operator|(pa_stream_flags_t lhs, pa_stream_flags_t rhs) @@ -874,7 +942,7 @@ ALCboolean PulsePlayback::reset() chanmap = X71ChanMap; break; } - SetDefaultWFXChannelOrder(mDevice); + SetChannelOrderFromMap(mDevice, chanmap); switch(mDevice->FmtType) { @@ -1176,6 +1244,7 @@ ALCenum PulseCapture::open(const ALCchar *name) throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", DevFmtChannelsString(mDevice->FmtChans)}; } + SetChannelOrderFromMap(mDevice, chanmap); switch(mDevice->FmtType) { -- cgit v1.2.3 From 0759ed721341cff00ddb3d8c40848cd20065500c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 5 May 2019 00:05:41 -0700 Subject: Properly mark a likely branch --- common/alexcpt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/alexcpt.cpp b/common/alexcpt.cpp index 21508b13..9e04bbaf 100644 --- a/common/alexcpt.cpp +++ b/common/alexcpt.cpp @@ -17,7 +17,7 @@ backend_exception::backend_exception(ALCenum code, const char *msg, ...) : mErro va_start(args, msg); va_copy(args2, args); int msglen{std::vsnprintf(nullptr, 0, msg, args)}; - if(UNLIKELY(msglen > 0)) + if(LIKELY(msglen > 0)) { mMessage.resize(static_cast(msglen)+1); std::vsnprintf(&mMessage[0], mMessage.length(), msg, args2); -- cgit v1.2.3 From 8d437a513539d016764e3297a441a318d7e7997c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 5 May 2019 01:51:46 -0700 Subject: Use available buffer samples when pausing a source --- Alc/mixvoice.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index e2e0a1e6..293de0b5 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -555,7 +555,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc std::fill(srciter, std::end(SrcData), 0.0f); auto srcdata_end = std::begin(SrcData) + SrcBufferSize; - if(vstate != ALvoice::Playing) + if(!BufferListItem) srciter = std::copy(voice->mPrevSamples[chan].begin()+MAX_RESAMPLE_PADDING, voice->mPrevSamples[chan].end(), srciter); else if(isstatic) @@ -787,9 +787,9 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc OutPos += DstBufferSize; Counter = maxi(DstBufferSize, Counter) - DstBufferSize; - if(UNLIKELY(vstate != ALvoice::Playing)) + if(UNLIKELY(!BufferListItem)) { - /* Do nothing extra for fading out. */ + /* Do nothing extra when there's no buffers. */ } else if(isstatic) { @@ -810,7 +810,8 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc /* Handle non-looping static source */ if(DataPosInt >= BufferListItem->max_samples) { - vstate = ALvoice::Stopped; + if(LIKELY(vstate == ALvoice::Playing)) + vstate = ALvoice::Stopped; BufferListItem = nullptr; break; } @@ -828,7 +829,8 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc BufferListItem = BufferListItem->next.load(std::memory_order_relaxed); if(!BufferListItem && !(BufferListItem=BufferLoopItem)) { - vstate = ALvoice::Stopped; + if(LIKELY(vstate == ALvoice::Playing)) + vstate = ALvoice::Stopped; break; } } -- cgit v1.2.3 From 5ac19673db211d1bee7687335af96cee4e6b40d8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 12 May 2019 19:41:34 -0700 Subject: Fix a couple type truncation warnings with MSVC --- Alc/backends/wasapi.cpp | 2 +- Alc/panning.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index f4448621..11664464 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -988,7 +988,7 @@ HRESULT WasapiPlayback::resetProxy() /* Find the nearest multiple of the period size to the update size */ if(min_per < per_time) - min_per *= maxu((per_time + min_per/2) / min_per, 1u); + min_per *= maxi64((per_time + min_per/2) / min_per, 1); min_len = (UINT32)ScaleCeil(min_per, mDevice->Frequency, REFTIME_PER_SEC); min_len = minu(min_len, buffer_len/2); diff --git a/Alc/panning.cpp b/Alc/panning.cpp index ce822123..4501efa5 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -783,7 +783,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr else { int hqdec{GetConfigValueBool(devname, "decoder", "hq-mode", 0)}; - InitCustomPanning(device, hqdec, pconf, speakermap); + InitCustomPanning(device, !!hqdec, pconf, speakermap); } /* Enable the stablizer only for formats that have front-left, front- -- cgit v1.2.3 From 515a201e30272826bd2bab58eecf42a5fa263230 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 17 May 2019 20:39:28 -0700 Subject: Restructure some voice fields --- Alc/alc.cpp | 13 ++++--------- Alc/mixvoice.cpp | 18 ++++++++++-------- OpenAL32/Include/alu.h | 14 ++++++++------ OpenAL32/alSource.cpp | 45 +++++++++++++++++++++++++++------------------ 4 files changed, 49 insertions(+), 41 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 6bd755bf..8a340b18 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2644,17 +2644,12 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) voice->mStep = old_voice->mStep; voice->mResampler = old_voice->mResampler; - voice->mFlags = old_voice->mFlags; - - std::copy(std::begin(old_voice->mPrevSamples), std::end(old_voice->mPrevSamples), - std::begin(voice->mPrevSamples)); - voice->mResampleState = old_voice->mResampleState; - voice->mAmbiScales = old_voice->mAmbiScales; - voice->mAmbiSplitter = old_voice->mAmbiSplitter; - std::for_each(voice->mAmbiSplitter.begin(),voice->mAmbiSplitter.end(), - std::bind(std::mem_fn(&BandSplitter::clear), _1)); + voice->mFlags = old_voice->mFlags; + + std::copy(old_voice->mResampleData.begin(), old_voice->mResampleData.end(), + voice->mResampleData.end()); voice->mDirect = old_voice->mDirect; std::copy_n(old_voice->mSend.begin(), s_count, voice->mSend.begin()); diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 293de0b5..cee0df5f 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -550,14 +550,15 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc auto &SrcData = Device->SourceData; /* Load the previous samples into the source data first, and clear the rest. */ - auto srciter = std::copy_n(voice->mPrevSamples[chan].begin(), MAX_RESAMPLE_PADDING, - std::begin(SrcData)); + auto srciter = std::copy_n(voice->mResampleData[chan].mPrevSamples.begin(), + MAX_RESAMPLE_PADDING, std::begin(SrcData)); std::fill(srciter, std::end(SrcData), 0.0f); auto srcdata_end = std::begin(SrcData) + SrcBufferSize; if(!BufferListItem) - srciter = std::copy(voice->mPrevSamples[chan].begin()+MAX_RESAMPLE_PADDING, - voice->mPrevSamples[chan].end(), srciter); + srciter = std::copy( + voice->mResampleData[chan].mPrevSamples.begin()+MAX_RESAMPLE_PADDING, + voice->mResampleData[chan].mPrevSamples.end(), srciter); else if(isstatic) srciter = LoadBufferStatic(BufferListItem, BufferLoopItem, NumChannels, SampleSize, chan, DataPosInt, srciter, srcdata_end); @@ -585,7 +586,8 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc /* Store the last source samples used for next time. */ std::copy_n(&SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS], - voice->mPrevSamples[chan].size(), std::begin(voice->mPrevSamples[chan])); + voice->mResampleData[chan].mPrevSamples.size(), + voice->mResampleData[chan].mPrevSamples.begin()); /* Resample, then apply ambisonic upsampling as needed. */ const ALfloat *ResampledData{Resample(&voice->mResampleState, @@ -593,15 +595,15 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc Device->ResampledData, DstBufferSize)}; if((voice->mFlags&VOICE_IS_AMBISONIC)) { - const ALfloat hfscale{voice->mAmbiScales[chan]}; + const ALfloat hfscale{voice->mResampleData[chan].mAmbiScale}; /* Beware the evil const_cast. It's safe since it's pointing to * either SrcData or Device->ResampledData (both non-const), * but the resample method takes its input as const float* and * may return it without copying to output, making it currently * unavoidable. */ - voice->mAmbiSplitter[chan].applyHfScale(const_cast(ResampledData), - hfscale, DstBufferSize); + voice->mResampleData[chan].mAmbiSplitter.applyHfScale( + const_cast(ResampledData), hfscale, DstBufferSize); } /* Now filter and mix to the appropriate outputs. */ diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 44083688..642aeddc 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -247,15 +247,17 @@ struct ALvoice { ResamplerFunc mResampler; + InterpState mResampleState; + ALuint mFlags; - using ResamplePaddingArray = std::array; - alignas(16) std::array mPrevSamples; + struct ResampleData { + alignas(16) std::array mPrevSamples; - InterpState mResampleState; - - std::array mAmbiScales; - std::array mAmbiSplitter; + ALfloat mAmbiScale; + BandSplitter mAmbiSplitter; + }; + std::array mResampleData; struct { int FilterType; diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 547f6a12..513adb88 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -2906,11 +2906,6 @@ START_API_FUNC voice->mSampleSize = BytesFromFmt((*buffer)->mFmtType); } - /* Clear previous samples. */ - std::for_each(voice->mPrevSamples.begin(), voice->mPrevSamples.begin()+voice->mNumChannels, - [](std::array &samples) -> void - { std::fill(std::begin(samples), std::end(samples), 0.0f); }); - /* Clear the stepping value so the mixer knows not to mix this until * the update gets applied. */ @@ -2925,31 +2920,45 @@ START_API_FUNC if((voice->mFmtChannels == FmtBFormat2D || voice->mFmtChannels == FmtBFormat3D) && device->mAmbiOrder > 1) { - auto scales = BFormatDec::GetHFOrderScales(1, device->mAmbiOrder); + const int *OrderFromChan; if(voice->mFmtChannels == FmtBFormat2D) { static constexpr int Order2DFromChan[MAX_AMBI2D_CHANNELS]{ 0, 1,1, 2,2, 3,3 }; - const size_t count{Ambi2DChannelsFromOrder(1u)}; - std::transform(Order2DFromChan, Order2DFromChan+count, voice->mAmbiScales.begin(), - [&scales](size_t idx) -> ALfloat { return scales[idx]; }); + OrderFromChan = Order2DFromChan; } else { - static constexpr int OrderFromChan[MAX_AMBI_CHANNELS]{ + static constexpr int Order3DFromChan[MAX_AMBI_CHANNELS]{ 0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3, }; - const size_t count{Ambi2DChannelsFromOrder(1u)}; - std::transform(OrderFromChan, OrderFromChan+count, voice->mAmbiScales.begin(), - [&scales](size_t idx) -> ALfloat { return scales[idx]; }); + OrderFromChan = Order3DFromChan; } - voice->mAmbiSplitter[0].init(400.0f / static_cast(device->Frequency)); - std::fill_n(voice->mAmbiSplitter.begin()+1, voice->mNumChannels-1, - voice->mAmbiSplitter[0]); + BandSplitter splitter; + splitter.init(400.0f / static_cast(device->Frequency)); + + const auto scales = BFormatDec::GetHFOrderScales(1, device->mAmbiOrder); + auto init_ambi = [scales,&OrderFromChan,&splitter](ALvoice::ResampleData &resdata) -> void + { + resdata.mPrevSamples.fill(0.0f); + resdata.mAmbiScale = scales[*(OrderFromChan++)]; + resdata.mAmbiSplitter = splitter; + }; + std::for_each(voice->mResampleData.begin(), + voice->mResampleData.begin()+voice->mNumChannels, init_ambi); + voice->mFlags |= VOICE_IS_AMBISONIC; } + else + { + /* Clear previous samples. */ + auto clear_prevs = [](ALvoice::ResampleData &resdata) -> void + { resdata.mPrevSamples.fill(0.0f); }; + std::for_each(voice->mResampleData.begin(), + voice->mResampleData.begin()+voice->mNumChannels, clear_prevs); + } std::fill_n(std::begin(voice->mDirect.Params), voice->mNumChannels, DirectParams{}); std::for_each(voice->mSend.begin(), voice->mSend.end(), @@ -2959,8 +2968,8 @@ START_API_FUNC if(device->AvgSpeakerDist > 0.0f) { - ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / - (device->AvgSpeakerDist * device->Frequency); + const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC / + (device->AvgSpeakerDist * device->Frequency)}; std::for_each(voice->mDirect.Params+0, voice->mDirect.Params+voice->mNumChannels, [w1](DirectParams &parms) noexcept -> void { parms.NFCtrlFilter.init(w1); } -- cgit v1.2.3 From 136caf0cb097943aa4d06aba8205fe6cd90de4b7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 19 May 2019 00:53:39 -0700 Subject: Don't attenuate the repeated sample The mixing gain stepping will handle it --- Alc/mixvoice.cpp | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index cee0df5f..f539f119 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -555,7 +555,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc std::fill(srciter, std::end(SrcData), 0.0f); auto srcdata_end = std::begin(SrcData) + SrcBufferSize; - if(!BufferListItem) + if(UNLIKELY(!BufferListItem)) srciter = std::copy( voice->mResampleData[chan].mPrevSamples.begin()+MAX_RESAMPLE_PADDING, voice->mResampleData[chan].mPrevSamples.end(), srciter); @@ -568,20 +568,13 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc if(UNLIKELY(srciter != srcdata_end)) { - /* If the source buffer wasn't filled, copy the last sample and - * fade it to 0 amplitude. Ideally it should have ended with - * silence, but if not this should help avoid clicks from - * sudden amplitude changes. + /* If the source buffer wasn't filled, copy the last sample for + * the remaining buffer. Ideally it should have ended with + * silence, but if not the gain fading should help avoid clicks + * from sudden amplitude changes. */ const ALfloat sample{*(srciter-1)}; - const ALfloat gainstep{1.0f / (BUFFERSIZE*2)}; - ALfloat step{BUFFERSIZE*2}; - - while(srciter != srcdata_end) - { - step -= 1.0f; - *(srciter++) = sample * gainstep*step; - } + std::fill(srciter, srcdata_end, sample); } /* Store the last source samples used for next time. */ -- cgit v1.2.3 From 6dbd488d13d455f4538595cb5b30788048a6d20a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 20 May 2019 21:16:13 -0700 Subject: Avoid unnecessary use of CalcAngleCoeffs --- Alc/alu.cpp | 2 +- Alc/effects/chorus.cpp | 6 +++--- Alc/effects/dedicated.cpp | 2 +- Alc/effects/distortion.cpp | 2 +- Alc/effects/fshifter.cpp | 2 +- Alc/effects/pshifter.cpp | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index dd99a9f5..d1e0772a 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -754,7 +754,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo * input channels of the source sends. */ ALfloat coeffs[MAX_AMBI_CHANNELS]; - CalcAngleCoeffs(az, ev, Spread, coeffs); + CalcDirectionCoeffs({xpos, ypos, zpos}, Spread, coeffs); for(ALsizei i{0};i < NumSends;i++) { diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp index 98f01fa7..74b46a10 100644 --- a/Alc/effects/chorus.cpp +++ b/Alc/effects/chorus.cpp @@ -139,7 +139,7 @@ void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, co * delay and depth to allow enough padding for resampling. */ const ALCdevice *device{Context->Device}; - auto frequency = static_cast(device->Frequency); + const auto frequency = static_cast(device->Frequency); mDelay = maxi(float2int(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f), mindelay); mDepth = minf(props->Chorus.Depth * mDelay, static_cast(mDelay - mindelay)); @@ -147,8 +147,8 @@ void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, co /* Gains for left and right sides */ ALfloat coeffs[2][MAX_AMBI_CHANNELS]; - CalcAngleCoeffs(al::MathDefs::Pi()*-0.5f, 0.0f, 0.0f, coeffs[0]); - CalcAngleCoeffs(al::MathDefs::Pi()* 0.5f, 0.0f, 0.0f, coeffs[1]); + CalcDirectionCoeffs({-1.0f, 0.0f, 0.0f}, 0.0f, coeffs[0]); + CalcDirectionCoeffs({ 1.0f, 0.0f, 0.0f}, 0.0f, coeffs[1]); mOutBuffer = target.Main->Buffer; mOutChannels = target.Main->NumChannels; diff --git a/Alc/effects/dedicated.cpp b/Alc/effects/dedicated.cpp index 4c528a61..14d0c3c8 100644 --- a/Alc/effects/dedicated.cpp +++ b/Alc/effects/dedicated.cpp @@ -81,7 +81,7 @@ void DedicatedState::update(const ALCcontext* UNUSED(context), const ALeffectslo else { ALfloat coeffs[MAX_AMBI_CHANNELS]; - CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); + CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); mOutBuffer = target.Main->Buffer; mOutChannels = target.Main->NumChannels; diff --git a/Alc/effects/distortion.cpp b/Alc/effects/distortion.cpp index 3639297f..d2bcd018 100644 --- a/Alc/effects/distortion.cpp +++ b/Alc/effects/distortion.cpp @@ -90,7 +90,7 @@ void DistortionState::update(const ALCcontext *context, const ALeffectslot *slot ); ALfloat coeffs[MAX_AMBI_CHANNELS]; - CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); + CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); mOutBuffer = target.Main->Buffer; mOutChannels = target.Main->NumChannels; diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp index 4587b721..e3dc6f1d 100644 --- a/Alc/effects/fshifter.cpp +++ b/Alc/effects/fshifter.cpp @@ -131,7 +131,7 @@ void FshifterState::update(const ALCcontext *context, const ALeffectslot *slot, } ALfloat coeffs[MAX_AMBI_CHANNELS]; - CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); + CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); mOutBuffer = target.Main->Buffer; mOutChannels = target.Main->NumChannels; diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp index f95579d7..1d85fb9e 100644 --- a/Alc/effects/pshifter.cpp +++ b/Alc/effects/pshifter.cpp @@ -190,7 +190,7 @@ void PshifterState::update(const ALCcontext* UNUSED(context), const ALeffectslot mPitchShift = mPitchShiftI * (1.0f/FRACTIONONE); ALfloat coeffs[MAX_AMBI_CHANNELS]; - CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); + CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); mOutBuffer = target.Main->Buffer; mOutChannels = target.Main->NumChannels; -- cgit v1.2.3 From 55845f316d5469f792e22b90435a17ca49f9d1c2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 20 May 2019 21:30:56 -0700 Subject: Don't use coverage spread for the echo spread --- Alc/effects/echo.cpp | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index 94971c99..92993f7e 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -95,31 +95,23 @@ ALboolean EchoState::deviceUpdate(const ALCdevice *Device) void EchoState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { const ALCdevice *device = context->Device; - ALuint frequency = device->Frequency; - ALfloat gainhf, lrpan, spread; + const auto frequency = static_cast(device->Frequency); mTap[0].delay = maxi(float2int(props->Echo.Delay*frequency + 0.5f), 1); - mTap[1].delay = float2int(props->Echo.LRDelay*frequency + 0.5f); - mTap[1].delay += mTap[0].delay; + mTap[1].delay = float2int(props->Echo.LRDelay*frequency + 0.5f) + mTap[0].delay; - spread = props->Echo.Spread; - if(spread < 0.0f) lrpan = -1.0f; - else lrpan = 1.0f; - /* Convert echo spread (where 0 = omni, +/-1 = directional) to coverage - * spread (where 0 = point, tau = omni). - */ - spread = asinf(1.0f - fabsf(spread))*4.0f; + const ALfloat gainhf{maxf(1.0f - props->Echo.Damping, 0.0625f)}; /* Limit -24dB */ + mFilter.setParams(BiquadType::HighShelf, gainhf, LOWPASSFREQREF/frequency, + calc_rcpQ_from_slope(gainhf, 1.0f)); mFeedGain = props->Echo.Feedback; - gainhf = maxf(1.0f - props->Echo.Damping, 0.0625f); /* Limit -24dB */ - mFilter.setParams(BiquadType::HighShelf, gainhf, LOWPASSFREQREF/frequency, - calc_rcpQ_from_slope(gainhf, 1.0f) - ); + /* Convert echo spread (where 0 = center, +/-1 = sides) to angle. */ + const ALfloat angle{std::asin(props->Echo.Spread)}; ALfloat coeffs[2][MAX_AMBI_CHANNELS]; - CalcAngleCoeffs(al::MathDefs::Pi()*-0.5f*lrpan, 0.0f, spread, coeffs[0]); - CalcAngleCoeffs(al::MathDefs::Pi()* 0.5f*lrpan, 0.0f, spread, coeffs[1]); + CalcAngleCoeffs(-angle, 0.0f, 0.0f, coeffs[0]); + CalcAngleCoeffs( angle, 0.0f, 0.0f, coeffs[1]); mOutBuffer = target.Main->Buffer; mOutChannels = target.Main->NumChannels; -- cgit v1.2.3 From d502397b37e1c4dce2735dada2075b8f08301826 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 20 May 2019 22:07:41 -0700 Subject: Simplify the echo feedback loop --- Alc/effects/echo.cpp | 56 ++++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index 92993f7e..9cd6fb87 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -53,10 +53,10 @@ struct EchoState final : public EffectState { ALfloat Target[MAX_OUTPUT_CHANNELS]{}; } mGains[2]; - ALfloat mFeedGain{0.0f}; - BiquadFilter mFilter; + ALfloat mFeedGain{0.0f}; + alignas(16) ALfloat mTempBuffer[2][BUFFERSIZE]; ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; @@ -122,48 +122,44 @@ void EchoState::update(const ALCcontext *context, const ALeffectslot *slot, cons void EchoState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei /*numInput*/, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) { const auto mask = static_cast(mSampleBuffer.size()-1); - const ALsizei tap1{mTap[0].delay}; - const ALsizei tap2{mTap[1].delay}; ALfloat *RESTRICT delaybuf{mSampleBuffer.data()}; ALsizei offset{mOffset}; + ALsizei tap1{offset - mTap[0].delay}; + ALsizei tap2{offset - mTap[1].delay}; ALfloat z1, z2; - ALsizei base; - ALsizei c, i; + + ASSUME(samplesToDo > 0); + ASSUME(mask > 0); std::tie(z1, z2) = mFilter.getComponents(); - for(base = 0;base < samplesToDo;) + for(ALsizei i{0};i < samplesToDo;) { - alignas(16) ALfloat temps[2][128]; - ALsizei td = mini(128, samplesToDo-base); + offset &= mask; + tap1 &= mask; + tap2 &= mask; - for(i = 0;i < td;i++) - { + ALsizei td{mini(mask+1 - maxi(offset, maxi(tap1, tap2)), samplesToDo-i)}; + do { /* Feed the delay buffer's input first. */ - delaybuf[offset&mask] = samplesIn[0][i+base]; - - /* First tap */ - temps[0][i] = delaybuf[(offset-tap1) & mask]; - /* Second tap */ - temps[1][i] = delaybuf[(offset-tap2) & mask]; + delaybuf[offset] = samplesIn[0][i]; - /* Apply damping to the second tap, then add it to the buffer with - * feedback attenuation. + /* Get delayed output from the first and second taps. Use the + * second tap for feedback. */ - float out{mFilter.processOne(temps[1][i], z1, z2)}; + mTempBuffer[0][i] = delaybuf[tap1++]; + mTempBuffer[1][i] = delaybuf[tap2++]; + const float feedb{mTempBuffer[1][i++]}; - delaybuf[offset&mask] += out * mFeedGain; - offset++; - } - - for(c = 0;c < 2;c++) - MixSamples(temps[c], numOutput, samplesOut, mGains[c].Current, mGains[c].Target, - samplesToDo-base, base, td); - - base += td; + /* Add feedback to the delay buffer with damping and attenuation. */ + delaybuf[offset++] += mFilter.processOne(feedb, z1, z2) * mFeedGain; + } while(--td); } mFilter.setComponents(z1, z2); - mOffset = offset; + + for(ALsizei c{0};c < 2;c++) + MixSamples(mTempBuffer[c], numOutput, samplesOut, mGains[c].Current, mGains[c].Target, + samplesToDo, 0, samplesToDo); } -- cgit v1.2.3 From 657978c732d3ed379ff4e65891fe21140433a248 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 21 May 2019 09:01:51 -0700 Subject: Don't change the format tag in MakeExtensible --- Alc/backends/wasapi.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 11664464..e41116d4 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -607,16 +607,17 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() } -ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) +bool MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) { *out = WAVEFORMATEXTENSIBLE{}; if(in->wFormatTag == WAVE_FORMAT_EXTENSIBLE) - *out = *(const WAVEFORMATEXTENSIBLE*)in; + { + *out = reinterpret_cast(*in); + out->Format.cbSize = sizeof(*out) - sizeof(out->Format); + } else if(in->wFormatTag == WAVE_FORMAT_PCM) { out->Format = *in; - out->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - out->Format.cbSize = sizeof(*out) - sizeof(*in); if(out->Format.nChannels == 1) out->dwChannelMask = MONO; else if(out->Format.nChannels == 2) @@ -628,8 +629,6 @@ ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) else if(in->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) { out->Format = *in; - out->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - out->Format.cbSize = sizeof(*out) - sizeof(*in); if(out->Format.nChannels == 1) out->dwChannelMask = MONO; else if(out->Format.nChannels == 2) @@ -641,9 +640,9 @@ ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) else { ERR("Unhandled format tag: 0x%04x\n", in->wFormatTag); - return ALC_FALSE; + return false; } - return ALC_TRUE; + return true; } ALCenum WasapiPlayback::open(const ALCchar *name) @@ -813,6 +812,7 @@ HRESULT WasapiPlayback::resetProxy() ERR("Unhandled channel config: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask); } + OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; switch(mDevice->FmtChans) { case DevFmtMono: @@ -954,6 +954,8 @@ HRESULT WasapiPlayback::resetProxy() { ERR("Unhandled format sub-type\n"); mDevice->FmtType = DevFmtShort; + if(OutputType.Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE) + OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; OutputType.Format.wBitsPerSample = 16; OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; } -- cgit v1.2.3 From b48bab33948dae90a27b4f8ccd3eb6b20d49ba86 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 22 May 2019 03:03:24 -0700 Subject: Allow initializing splitter filters with constructors --- Alc/filters/splitter.h | 8 ++++++++ Alc/hrtf.cpp | 6 ++---- OpenAL32/alSource.cpp | 3 +-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Alc/filters/splitter.h b/Alc/filters/splitter.h index 669d9d03..cd5fe864 100644 --- a/Alc/filters/splitter.h +++ b/Alc/filters/splitter.h @@ -14,6 +14,10 @@ class BandSplitterR { Real ap_z1{0.0f}; public: + BandSplitterR() = default; + BandSplitterR(const BandSplitterR&) = default; + BandSplitterR(Real f0norm) { init(f0norm); } + void init(Real f0norm); void clear() noexcept { lp_z1 = lp_z2 = ap_z1 = 0.0f; } void process(Real *hpout, Real *lpout, const Real *input, const int count); @@ -30,6 +34,10 @@ class SplitterAllpassR { Real z1{0.0f}; public: + SplitterAllpassR() = default; + SplitterAllpassR(const SplitterAllpassR&) = default; + SplitterAllpassR(Real f0norm) { init(f0norm); } + void init(Real f0norm); void clear() noexcept { z1 = 0.0f; } void process(Real *samples, int count); diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 9fa79e22..ede8f8c5 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -339,10 +339,8 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsiz */ static constexpr ALsizei base_delay{DualBand ? 12 : 0}; const ALdouble xover_norm{400.0 / Hrtf->sampleRate}; - BandSplitterR splitter; - SplitterAllpassR allpass; - splitter.init(xover_norm); - allpass.init(xover_norm); + BandSplitterR splitter{xover_norm}; + SplitterAllpassR allpass{xover_norm}; auto tmpres = al::vector>(NumChannels); auto tmpfilt = al::vector>(3); diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 513adb88..48f9a157 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -2936,8 +2936,7 @@ START_API_FUNC OrderFromChan = Order3DFromChan; } - BandSplitter splitter; - splitter.init(400.0f / static_cast(device->Frequency)); + BandSplitter splitter{400.0f / static_cast(device->Frequency)}; const auto scales = BFormatDec::GetHFOrderScales(1, device->mAmbiOrder); auto init_ambi = [scales,&OrderFromChan,&splitter](ALvoice::ResampleData &resdata) -> void -- cgit v1.2.3 From 67085040268003b6027317cca64ca72a18d90ce7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 22 May 2019 10:58:18 -0700 Subject: Properly reverse the HRTF field order when loading it And combine a couple arrays into an array structure --- Alc/hrtf.cpp | 167 ++++++++++++++++++++++++++++++++++++----------------------- Alc/hrtf.h | 13 ++--- 2 files changed, 108 insertions(+), 72 deletions(-) diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index ede8f8c5..bc183d1b 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -214,30 +214,29 @@ void GetHrtfCoeffs(const HrtfEntry *Hrtf, ALfloat elevation, ALfloat azimuth, AL const auto *field = Hrtf->field; const auto *field_end = field + Hrtf->fdCount-1; - ALsizei fdoffset{Hrtf->evFarBase}; + ALsizei ebase{0}; while(distance < field->distance && field != field_end) { + ebase += field->evCount; ++field; - fdoffset -= field->evCount; } - assert(fdoffset >= 0); /* Claculate the elevation indinces. */ const auto elev0 = CalcEvIndex(field->evCount, elevation); const ALsizei elev1_idx{mini(elev0.idx+1, field->evCount-1)}; - const ALsizei ev0offset{Hrtf->evOffset[fdoffset + elev0.idx]}; - const ALsizei ev1offset{Hrtf->evOffset[fdoffset + elev1_idx]}; + const ALsizei ir0offset{Hrtf->elev[ebase + elev0.idx].irOffset}; + const ALsizei ir1offset{Hrtf->elev[ebase + elev1_idx].irOffset}; /* Calculate azimuth indices. */ - const auto az0 = CalcAzIndex(Hrtf->azCount[fdoffset + elev0.idx], azimuth); - const auto az1 = CalcAzIndex(Hrtf->azCount[fdoffset + elev1_idx], azimuth); + const auto az0 = CalcAzIndex(Hrtf->elev[ebase + elev0.idx].azCount, azimuth); + const auto az1 = CalcAzIndex(Hrtf->elev[ebase + elev1_idx].azCount, azimuth); /* Calculate the HRIR indices to blend. */ ALsizei idx[4]{ - ev0offset + az0.idx, - ev0offset + ((az0.idx+1) % Hrtf->azCount[fdoffset + elev0.idx]), - ev1offset + az1.idx, - ev1offset + ((az1.idx+1) % Hrtf->azCount[fdoffset + elev1_idx]) + ir0offset + az0.idx, + ir0offset + ((az0.idx+1) % Hrtf->elev[ebase + elev0.idx].azCount), + ir1offset + az1.idx, + ir1offset + ((az1.idx+1) % Hrtf->elev[ebase + elev1_idx].azCount) }; /* Calculate bilinear blending weights, attenuated according to the @@ -307,25 +306,24 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsiz ASSUME(AmbiCount > 0); auto &field = Hrtf->field[0]; - const ALsizei ebase{Hrtf->evFarBase}; ALsizei min_delay{HRTF_HISTORY_LENGTH}; ALsizei max_delay{0}; auto idx = al::vector(AmbiCount); - auto calc_idxs = [Hrtf,ebase,&field,&max_delay,&min_delay](const AngularPoint &pt) noexcept -> ALsizei + auto calc_idxs = [Hrtf,&field,&max_delay,&min_delay](const AngularPoint &pt) noexcept -> ALsizei { /* Calculate elevation index. */ - const auto evidx = ebase + clampi( + const auto evidx = clampi( static_cast((90.0f+pt.Elev)*(field.evCount-1)/180.0f + 0.5f), 0, field.evCount-1); - const ALsizei azcount{Hrtf->azCount[evidx]}; - const ALsizei evoffset{Hrtf->evOffset[evidx]}; + const ALsizei azcount{Hrtf->elev[evidx].azCount}; + const ALsizei iroffset{Hrtf->elev[evidx].irOffset}; /* Calculate azimuth index for this elevation. */ const auto azidx = static_cast((360.0f+pt.Azim)*azcount/360.0f + 0.5f) % azcount; /* Calculate the index for the impulse response. */ - ALsizei idx{evoffset + azidx}; + ALsizei idx{iroffset + azidx}; min_delay = mini(min_delay, mini(Hrtf->delays[idx][0], Hrtf->delays[idx][1])); max_delay = maxi(max_delay, maxi(Hrtf->delays[idx][0], Hrtf->delays[idx][1])); @@ -459,8 +457,8 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsiz namespace { std::unique_ptr CreateHrtfStore(ALuint rate, ALsizei irSize, const ALsizei fdCount, - const ALubyte *evCount, const ALfloat *distance, const ALubyte *azCount, - const ALushort *evOffset, ALsizei irCount, const ALfloat (*coeffs)[2], + const ALubyte *evCount, const ALfloat *distance, const ALushort *azCount, + const ALushort *irOffset, ALsizei irCount, const ALfloat (*coeffs)[2], const ALubyte (*delays)[2], const char *filename) { std::unique_ptr Hrtf; @@ -469,9 +467,8 @@ std::unique_ptr CreateHrtfStore(ALuint rate, ALsizei irSize, const AL size_t total{sizeof(HrtfEntry)}; total = RoundUp(total, alignof(HrtfEntry::Field)); /* Align for field infos */ total += sizeof(HrtfEntry::Field)*fdCount; - total += sizeof(Hrtf->azCount[0])*evTotal; - total = RoundUp(total, sizeof(ALushort)); /* Align for ushort fields */ - total += sizeof(Hrtf->evOffset[0])*evTotal; + total = RoundUp(total, alignof(HrtfEntry::Elevation)); /* Align for elevation infos */ + total += sizeof(Hrtf->elev[0])*evTotal; total = RoundUp(total, 16); /* Align for coefficients using SIMD */ total += sizeof(Hrtf->coeffs[0])*irSize*irCount; total += sizeof(Hrtf->delays[0])*irCount; @@ -484,7 +481,6 @@ std::unique_ptr CreateHrtfStore(ALuint rate, ALsizei irSize, const AL InitRef(&Hrtf->ref, 1u); Hrtf->sampleRate = rate; Hrtf->irSize = irSize; - Hrtf->evFarBase = std::accumulate(evCount+1, evCount+fdCount, 0); Hrtf->fdCount = fdCount; /* Set up pointers to storage following the main HRTF struct. */ @@ -495,12 +491,9 @@ std::unique_ptr CreateHrtfStore(ALuint rate, ALsizei irSize, const AL auto field_ = reinterpret_cast(base + offset); offset += sizeof(field_[0])*fdCount; - auto azCount_ = reinterpret_cast(base + offset); - offset += sizeof(azCount_[0])*evTotal; - - offset = RoundUp(offset, sizeof(ALushort)); /* Align for ushort fields */ - auto evOffset_ = reinterpret_cast(base + offset); - offset += sizeof(evOffset_[0])*evTotal; + offset = RoundUp(offset, alignof(HrtfEntry::Elevation)); /* Align for elevation infos */ + auto elev_ = reinterpret_cast(base + offset); + offset += sizeof(elev_[0])*evTotal; offset = RoundUp(offset, 16); /* Align for coefficients using SIMD */ auto coeffs_ = reinterpret_cast(base + offset); @@ -514,11 +507,14 @@ std::unique_ptr CreateHrtfStore(ALuint rate, ALsizei irSize, const AL /* Copy input data to storage. */ for(ALsizei i{0};i < fdCount;i++) { - field_[i].evCount = evCount[i]; field_[i].distance = distance[i]; + field_[i].evCount = evCount[i]; + } + for(ALsizei i{0};i < evTotal;i++) + { + elev_[i].azCount = azCount[i]; + elev_[i].irOffset = irOffset[i]; } - for(ALsizei i{0};i < evTotal;i++) azCount_[i] = azCount[i]; - for(ALsizei i{0};i < evTotal;i++) evOffset_[i] = evOffset[i]; for(ALsizei i{0};i < irSize*irCount;i++) { coeffs_[i][0] = coeffs[i][0]; @@ -532,8 +528,7 @@ std::unique_ptr CreateHrtfStore(ALuint rate, ALsizei irSize, const AL /* Finally, assign the storage pointers. */ Hrtf->field = field_; - Hrtf->azCount = azCount_; - Hrtf->evOffset = evOffset_; + Hrtf->elev = elev_; Hrtf->coeffs = coeffs_; Hrtf->delays = delays_; } @@ -631,7 +626,7 @@ std::unique_ptr LoadHrtf00(std::istream &data, const char *filename) if(failed) return nullptr; - al::vector azCount(evCount); + al::vector azCount(evCount); for(ALsizei i{1};i < evCount;i++) { azCount[i-1] = evOffset[i] - evOffset[i-1]; @@ -723,9 +718,9 @@ std::unique_ptr LoadHrtf01(std::istream &data, const char *filename) if(failed) return nullptr; - al::vector azCount(evCount); - data.read(reinterpret_cast(azCount.data()), evCount); - if(!data || data.eof() || data.gcount() < evCount) + al::vector azCount(evCount); + std::generate(azCount.begin(), azCount.end(), std::bind(GetLE_ALubyte, std::ref(data))); + if(!data || data.eof()) { ERR("Failed reading %s\n", filename); return nullptr; @@ -843,7 +838,7 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) al::vector distance(fdCount); al::vector evCount(fdCount); - al::vector azCount; + al::vector azCount; for(ALsizei f{0};f < fdCount;f++) { distance[f] = GetLE_ALushort(data) / 1000.0f; @@ -877,8 +872,9 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) size_t ebase{azCount.size()}; azCount.resize(ebase + evCount[f]); - data.read(reinterpret_cast(azCount.data()+ebase), evCount[f]); - if(!data || data.eof() || data.gcount() < evCount[f]) + std::generate(azCount.begin()+ebase, azCount.end(), + std::bind(GetLE_ALubyte, std::ref(data))); + if(!data || data.eof()) { ERR("Failed reading %s\n", filename); return nullptr; @@ -897,31 +893,11 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) return nullptr; } - al::vector evOffset; - evOffset.resize(evCount[0]); - + al::vector evOffset(azCount.size()); evOffset[0] = 0; - ALushort irCount{azCount[0]}; - for(ALsizei e{1};e < evCount[0];++e) - { - evOffset[e] = evOffset[e-1] + azCount[e-1]; - irCount += azCount[e]; - } - - ALsizei irTotal{irCount}; - for(ALsizei f{1};f < fdCount;f++) - { - const ALsizei ebase{std::accumulate(evCount.begin(), evCount.begin()+f, 0)}; - evOffset.resize(ebase + evCount[f]); + std::partial_sum(azCount.cbegin(), azCount.cend()-1, evOffset.begin()+1); + const ALsizei irTotal{evOffset.back() + azCount.back()}; - evOffset[ebase] = irTotal; - irTotal += azCount[ebase]; - for(ALsizei e{1};e < evCount[f];++e) - { - evOffset[ebase+e] = evOffset[ebase+e-1] + azCount[ebase+e-1]; - irTotal += azCount[ebase+e]; - } - } al::vector> coeffs(irSize*irTotal); al::vector> delays(irTotal); if(channelType == CHANTYPE_LEFTONLY) @@ -1022,8 +998,67 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) } } - std::reverse(distance.begin(), distance.end()); - std::reverse(evCount.begin(), evCount.end()); + if(fdCount > 1) + { + auto distance_ = al::vector(distance.size()); + auto evCount_ = al::vector(evCount.size()); + auto azCount_ = al::vector(azCount.size()); + auto evOffset_ = al::vector(evOffset.size()); + auto coeffs_ = al::vector(coeffs.size()); + auto delays_ = al::vector>(delays.size()); + + /* Simple reverse for the per-field elements. */ + std::reverse_copy(distance.cbegin(), distance.cend(), distance_.begin()); + std::reverse_copy(evCount.cbegin(), evCount.cend(), evCount_.begin()); + + /* Each field has a group of elevations, which each have an azimuth + * count. Reverse the order of the groups, keeping the relative order + * of per-group azimuth counts. + */ + auto azcnt_end = azCount_.end(); + auto copy_azs = [&azCount,&azcnt_end](const size_t ebase, const ALubyte num_evs) -> size_t + { + auto azcnt_src = azCount.begin()+ebase; + azcnt_end = std::copy_backward(azcnt_src, azcnt_src+num_evs, azcnt_end); + return ebase + num_evs; + }; + std::accumulate(evCount.cbegin(), evCount.cend(), 0u, copy_azs); + assert(azCount_.begin() == azcnt_end); + + /* Reestablish the IR offset for each elevation index, given the new + * ordering of elevations. + */ + evOffset_[0] = 0; + std::partial_sum(azCount_.cbegin(), azCount_.cend()-1, evOffset_.begin()+1); + + /* Reverse the order of each field's group of IRs. */ + auto coeffs_end = coeffs_.end(); + auto delays_end = delays_.end(); + auto copy_irs = [irSize,&azCount,&coeffs,&delays,&coeffs_end,&delays_end](const size_t ebase, const ALubyte num_evs) -> size_t + { + const ALsizei abase{std::accumulate(azCount.cbegin(), azCount.cbegin()+ebase, 0)}; + const ALsizei num_azs{std::accumulate(azCount.cbegin()+ebase, + azCount.cbegin() + (ebase+num_evs), 0)}; + + coeffs_end = std::copy_backward(coeffs.cbegin() + abase*irSize, + coeffs.cbegin() + (abase+num_azs)*irSize, coeffs_end); + delays_end = std::copy_backward(delays.cbegin() + abase, + delays.cbegin() + (abase+num_azs), delays_end); + + return ebase + num_evs; + }; + std::accumulate(evCount.cbegin(), evCount.cend(), 0u, copy_irs); + assert(coeffs_.begin() == coeffs_end); + assert(delays_.begin() == delays_end); + + distance = std::move(distance_); + evCount = std::move(evCount_); + azCount = std::move(azCount_); + evOffset = std::move(evOffset_); + coeffs = std::move(coeffs_); + delays = std::move(delays_); + } + return CreateHrtfStore(rate, irSize, fdCount, evCount.data(), distance.data(), azCount.data(), evOffset.data(), irTotal, &reinterpret_cast(coeffs[0]), &reinterpret_cast(delays[0]), filename); diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 68a4301b..0283de13 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -29,20 +29,21 @@ struct HrtfEntry { ALuint sampleRate; ALsizei irSize; - /* Base elevation index for the farthest field. */ - ALsizei evFarBase; struct Field { - ALubyte evCount; ALfloat distance; + ALubyte evCount; }; /* NOTE: Fields are stored *backwards*. field[0] is the farthest field, and * field[fdCount-1] is the nearest. */ ALsizei fdCount; - Field *field; + const Field *field; - const ALubyte *azCount; - const ALushort *evOffset; + struct Elevation { + ALushort azCount; + ALushort irOffset; + }; + Elevation *elev; const ALfloat (*coeffs)[2]; const ALubyte (*delays)[2]; -- cgit v1.2.3 From e3d6f3d9882e319fc2819092a93d96d2022e2d52 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 23 May 2019 05:06:26 -0700 Subject: Use a function to mark a source for updating --- OpenAL32/alSource.cpp | 77 +++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 48f9a157..02396fd0 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -149,7 +149,6 @@ void UpdateSourceProps(const ALsource *source, ALvoice *voice, ALCcontext *conte } } - /* GetSourceSampleOffset * * Gets the current read offset for the given Source, in 32.32 fixed-point @@ -980,14 +979,14 @@ ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, } \ } while(0) -#define DO_UPDATEPROPS() do { \ - ALvoice *voice; \ - if(SourceShouldUpdate(Source, Context) && \ - (voice=GetSourceVoice(Source, Context)) != nullptr) \ - UpdateSourceProps(Source, voice, Context); \ - else \ - Source->PropsClean.clear(std::memory_order_release); \ -} while(0) +void UpdateSourceProps(ALsource *source, ALCcontext *context) +{ + ALvoice *voice; + if(SourceShouldUpdate(source, context) && (voice=GetSourceVoice(source, context)) != nullptr) + UpdateSourceProps(source, voice, context); + else + source->PropsClean.clear(std::memory_order_release); +} ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values) { @@ -1005,98 +1004,98 @@ ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, co CHECKVAL(*values >= 0.0f); Source->Pitch = *values; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_CONE_INNER_ANGLE: CHECKVAL(*values >= 0.0f && *values <= 360.0f); Source->InnerAngle = *values; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_CONE_OUTER_ANGLE: CHECKVAL(*values >= 0.0f && *values <= 360.0f); Source->OuterAngle = *values; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_GAIN: CHECKVAL(*values >= 0.0f); Source->Gain = *values; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_MAX_DISTANCE: CHECKVAL(*values >= 0.0f); Source->MaxDistance = *values; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_ROLLOFF_FACTOR: CHECKVAL(*values >= 0.0f); Source->RolloffFactor = *values; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_REFERENCE_DISTANCE: CHECKVAL(*values >= 0.0f); Source->RefDistance = *values; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_MIN_GAIN: CHECKVAL(*values >= 0.0f); Source->MinGain = *values; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_MAX_GAIN: CHECKVAL(*values >= 0.0f); Source->MaxGain = *values; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_CONE_OUTER_GAIN: CHECKVAL(*values >= 0.0f && *values <= 1.0f); Source->OuterGain = *values; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_CONE_OUTER_GAINHF: CHECKVAL(*values >= 0.0f && *values <= 1.0f); Source->OuterGainHF = *values; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_AIR_ABSORPTION_FACTOR: CHECKVAL(*values >= 0.0f && *values <= 10.0f); Source->AirAbsorptionFactor = *values; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_ROOM_ROLLOFF_FACTOR: CHECKVAL(*values >= 0.0f && *values <= 10.0f); Source->RoomRolloffFactor = *values; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_DOPPLER_FACTOR: CHECKVAL(*values >= 0.0f && *values <= 1.0f); Source->DopplerFactor = *values; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_SEC_OFFSET: @@ -1126,7 +1125,7 @@ ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, co CHECKVAL(*values >= 0.0f && std::isfinite(*values)); Source->Radius = *values; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_STEREO_ANGLES: @@ -1134,7 +1133,7 @@ ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, co Source->StereoPan[0] = values[0]; Source->StereoPan[1] = values[1]; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; @@ -1144,7 +1143,7 @@ ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, co Source->Position[0] = values[0]; Source->Position[1] = values[1]; Source->Position[2] = values[2]; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_VELOCITY: @@ -1153,7 +1152,7 @@ ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, co Source->Velocity[0] = values[0]; Source->Velocity[1] = values[1]; Source->Velocity[2] = values[2]; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_DIRECTION: @@ -1162,7 +1161,7 @@ ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, co Source->Direction[0] = values[0]; Source->Direction[1] = values[1]; Source->Direction[2] = values[2]; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_ORIENTATION: @@ -1175,7 +1174,7 @@ ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, co Source->OrientUp[0] = values[3]; Source->OrientUp[1] = values[4]; Source->OrientUp[2] = values[5]; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; @@ -1236,7 +1235,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); Source->HeadRelative = static_cast(*values); - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_LOOPING: @@ -1364,35 +1363,35 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co Source->Direct.LFReference = filter->LFReference; } filtlock.unlock(); - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_DIRECT_FILTER_GAINHF_AUTO: CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); Source->DryGainHFAuto = *values; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); Source->WetGainAuto = *values; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); Source->WetGainHFAuto = *values; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_DIRECT_CHANNELS_SOFT: CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); Source->DirectChannels = *values; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_DISTANCE_MODEL: @@ -1406,21 +1405,21 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co Source->mDistanceModel = static_cast(*values); if(Context->SourceDistanceModel) - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_SOURCE_RESAMPLER_SOFT: CHECKVAL(*values >= 0 && *values <= ResamplerMax); Source->mResampler = static_cast(*values); - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; case AL_SOURCE_SPATIALIZE_SOFT: CHECKVAL(*values >= AL_FALSE && *values <= AL_AUTO_SOFT); Source->mSpatialize = static_cast(*values); - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); return AL_TRUE; @@ -1477,7 +1476,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co if(Source->Send[values[1]].Slot) DecrementRef(&Source->Send[values[1]].Slot->ref); Source->Send[values[1]].Slot = slot; - DO_UPDATEPROPS(); + UpdateSourceProps(Source, Context); } return AL_TRUE; -- cgit v1.2.3 From a4af617532550a0e23b9df31d822318286aa87c5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 23 May 2019 08:15:02 -0700 Subject: Add a span class to act as a view to contiguous data --- CMakeLists.txt | 1 + common/alspan.h | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 common/alspan.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 68a76dad..a2eff245 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -646,6 +646,7 @@ SET(COMMON_OBJS common/almalloc.cpp common/almalloc.h common/alnumeric.h + common/alspan.h common/atomic.h common/math_defs.h common/opthelpers.h diff --git a/common/alspan.h b/common/alspan.h new file mode 100644 index 00000000..27584de4 --- /dev/null +++ b/common/alspan.h @@ -0,0 +1,105 @@ +#ifndef AL_SPAN_H +#define AL_SPAN_H + +#include +#include +#include + +namespace al { + +template +constexpr auto size(T &cont) -> decltype(cont.size()) +{ return cont.size(); } + +template +constexpr auto size(const T &cont) -> decltype(cont.size()) +{ return cont.size(); } + +template +constexpr size_t size(T (&)[N]) noexcept +{ return N; } + +template +constexpr size_t size(std::initializer_list list) noexcept +{ return list.size(); } + + +template +constexpr auto data(T &cont) -> decltype(cont.data()) +{ return cont.data(); } + +template +constexpr auto data(const T &cont) -> decltype(cont.data()) +{ return cont.data(); } + +template +constexpr T* data(T (&arr)[N]) noexcept +{ return arr; } + +template +constexpr const T* data(std::initializer_list list) noexcept +{ return list.begin(); } + + +template +class span { +public: + using element_type = T; + using value_type = typename std::remove_cv::type; + using index_type = size_t; + using difference_type = ptrdiff_t; + + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + constexpr span() noexcept = default; + constexpr span(pointer ptr, index_type count) : mData{ptr}, mCount{count} { } + constexpr span(pointer first, pointer last) : mData{first}, mCount{std::distance(first, last)} { } + template + constexpr span(element_type (&arr)[N]) noexcept : span{al::data(arr), al::size(arr)} { } + template + constexpr span(std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } + template + constexpr span(const std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } + template + constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { } + template + constexpr span(const U &cont) : span{al::data(cont), al::size(cont)} { } + constexpr span(const span&) noexcept = default; + + span& operator=(const span &rhs) noexcept = default; + + constexpr reference front() const { return mData[0]; } + constexpr reference back() const { return mData[mCount-1]; } + constexpr reference operator[](index_type idx) const { return mData[idx]; } + constexpr pointer data() const noexcept { return mData; } + + constexpr index_type size() const noexcept { return mCount; } + constexpr index_type size_bytes() const noexcept { return mCount * sizeof(value_type); } + constexpr bool empty() const noexcept { return mCount == 0; } + + constexpr iterator begin() const noexcept { return mData; } + constexpr iterator end() const noexcept { return mData + mCount; } + constexpr const_iterator cbegin() const noexcept { return mData; } + constexpr const_iterator cend() const noexcept { return mData + mCount; } + + constexpr reverse_iterator rbegin() const noexcept { return end(); } + constexpr reverse_iterator rend() const noexcept { return begin(); } + constexpr const_reverse_iterator crbegin() const noexcept { return cend(); } + constexpr const_reverse_iterator crend() const noexcept { return cbegin(); } + +private: + pointer mData{nullptr}; + index_type mCount{0u}; +}; + +} // namespace al + +#endif /* AL_SPAN_H */ -- cgit v1.2.3 From b46eca97a6b1a3826508d9afccfc765d15779f9c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 23 May 2019 08:17:05 -0700 Subject: Use a span for resource data --- Alc/hrtf.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index bc183d1b..92d7b47e 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -43,6 +43,7 @@ #include "compat.h" #include "almalloc.h" +#include "alspan.h" struct HrtfHandle { @@ -1185,11 +1186,11 @@ void AddBuiltInEntry(al::vector &list, const std::string &filena #define IDR_DEFAULT_44100_MHR 1 #define IDR_DEFAULT_48000_MHR 2 -struct ResData { const char *data; size_t size; }; +using ResData = al::span; #ifndef ALSOFT_EMBED_HRTF_DATA ResData GetResource(int UNUSED(name)) -{ return {nullptr, 0u}; } +{ return ResData{}; } #else @@ -1202,7 +1203,7 @@ ResData GetResource(int name) return {reinterpret_cast(hrtf_default_44100), sizeof(hrtf_default_44100)}; if(name == IDR_DEFAULT_48000_MHR) return {reinterpret_cast(hrtf_default_48000), sizeof(hrtf_default_48000)}; - return {nullptr, 0u}; + return ResData{}; } #endif @@ -1255,12 +1256,10 @@ al::vector EnumerateHrtf(const char *devname) for(const auto &fname : SearchDataFiles(".mhr", "openal/hrtf")) AddFileEntry(list, fname); - ResData res{GetResource(IDR_DEFAULT_44100_MHR)}; - if(res.data != nullptr && res.size > 0) + if(!GetResource(IDR_DEFAULT_44100_MHR).empty()) AddBuiltInEntry(list, "Built-In 44100hz", IDR_DEFAULT_44100_MHR); - res = GetResource(IDR_DEFAULT_48000_MHR); - if(res.data != nullptr && res.size > 0) + if(!GetResource(IDR_DEFAULT_48000_MHR).empty()) AddBuiltInEntry(list, "Built-In 48000hz", IDR_DEFAULT_48000_MHR); } @@ -1305,12 +1304,12 @@ HrtfEntry *GetLoadedHrtf(HrtfHandle *handle) TRACE("Loading %s...\n", name); ResData res{GetResource(residx)}; - if(!res.data || res.size == 0) + if(res.empty()) { ERR("Could not get resource %u, %s\n", residx, name); return nullptr; } - stream = al::make_unique(res.data, res.data+res.size); + stream = al::make_unique(res.begin(), res.end()); } else { -- cgit v1.2.3 From 517b8158a7a519ae86dbf4eed8ff667f96d82666 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 23 May 2019 08:30:02 -0700 Subject: Add a missing include --- common/alspan.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/alspan.h b/common/alspan.h index 27584de4..96823171 100644 --- a/common/alspan.h +++ b/common/alspan.h @@ -2,6 +2,8 @@ #define AL_SPAN_H #include + +#include #include #include -- cgit v1.2.3 From 3a9caec72f4f1f9b4095670c62318780ca566d18 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 23 May 2019 13:30:16 -0700 Subject: Use a span for referencing the channel map to initialize --- Alc/panning.cpp | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 4501efa5..a209c6cf 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -42,6 +42,8 @@ #include "uhjfilter.h" #include "bs2b.h" +#include "alspan.h" + constexpr std::array AmbiScale::FromN3D; constexpr std::array AmbiScale::FromSN3D; @@ -325,50 +327,42 @@ auto GetAmbiLayout(AmbiLayout layouttype) noexcept -> const std::array chanmap; + ALsizei coeffcount{}; switch(device->FmtChans) { case DevFmtMono: - count = static_cast(COUNTOF(MonoCfg)); chanmap = MonoCfg; coeffcount = 1; break; case DevFmtStereo: - count = static_cast(COUNTOF(StereoCfg)); chanmap = StereoCfg; coeffcount = 3; break; case DevFmtQuad: - count = static_cast(COUNTOF(QuadCfg)); chanmap = QuadCfg; coeffcount = 3; break; case DevFmtX51: - count = static_cast(COUNTOF(X51SideCfg)); chanmap = X51SideCfg; coeffcount = 5; break; case DevFmtX51Rear: - count = static_cast(COUNTOF(X51RearCfg)); chanmap = X51RearCfg; coeffcount = 5; break; case DevFmtX61: - count = static_cast(COUNTOF(X61Cfg)); chanmap = X61Cfg; coeffcount = 5; break; case DevFmtX71: - count = static_cast(COUNTOF(X71Cfg)); chanmap = X71Cfg; coeffcount = 7; break; @@ -384,12 +378,12 @@ void InitPanning(ALCdevice *device) const std::array &n3dscale = GetAmbiScales(device->mAmbiScale); /* For DevFmtAmbi3D, the ambisonic order is already set. */ - count = static_cast(AmbiChannelsFromOrder(device->mAmbiOrder)); + const size_t count{AmbiChannelsFromOrder(device->mAmbiOrder)}; std::transform(acnmap.begin(), acnmap.begin()+count, std::begin(device->Dry.AmbiMap), [&n3dscale](const ALsizei &acn) noexcept -> BFChannelConfig { return BFChannelConfig{1.0f/n3dscale[acn], acn}; } ); - device->Dry.NumChannels = count; + device->Dry.NumChannels = static_cast(count); ALfloat nfc_delay{0.0f}; if(ConfigValueFloat(devname, "decoder", "nfc-ref-delay", &nfc_delay) && nfc_delay > 0.0f) @@ -397,7 +391,7 @@ void InitPanning(ALCdevice *device) static constexpr ALsizei chans_per_order[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; nfc_delay = clampf(nfc_delay, 0.001f, 1000.0f); InitNearFieldCtrl(device, nfc_delay * SPEEDOFSOUNDMETRESPERSEC, - device->mAmbiOrder, chans_per_order); + device->mAmbiOrder, chans_per_order); } device->RealOut.NumChannels = 0; @@ -406,7 +400,7 @@ void InitPanning(ALCdevice *device) { ChannelDec chancoeffs[MAX_OUTPUT_CHANNELS]{}; ALsizei idxmap[MAX_OUTPUT_CHANNELS]{}; - for(ALsizei i{0};i < count;++i) + for(size_t i{0u};i < chanmap.size();++i) { const ALint idx{GetChannelIdxByName(device->RealOut, chanmap[i].ChanName)}; if(idx < 0) @@ -436,7 +430,8 @@ void InitPanning(ALCdevice *device) (coeffcount > 3) ? "second" : "first", "" ); - device->AmbiDecoder = al::make_unique(coeffcount, count, chancoeffs, idxmap); + device->AmbiDecoder = al::make_unique(coeffcount, + static_cast(chanmap.size()), chancoeffs, idxmap); device->RealOut.NumChannels = device->channelsFromFmt(); } @@ -553,7 +548,7 @@ void InitHrtfPanning(ALCdevice *device) static constexpr ALsizei ChansPerOrder[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; const ALfloat *AmbiOrderHFGain{AmbiOrderHFGainFOA}; - static_assert(COUNTOF(AmbiPoints) == COUNTOF(AmbiMatrix), "Ambisonic HRTF mismatch"); + static_assert(al::size(AmbiPoints) == al::size(AmbiMatrix), "Ambisonic HRTF mismatch"); /* Don't bother with HOA when using full HRTF rendering. Nothing needs it, * and it eases the CPU/memory load. @@ -578,7 +573,7 @@ void InitHrtfPanning(ALCdevice *device) device->RealOut.NumChannels = device->channelsFromFmt(); BuildBFormatHrtf(device->mHrtf, device->mHrtfState.get(), device->Dry.NumChannels, AmbiPoints, - AmbiMatrix, COUNTOF(AmbiPoints), AmbiOrderHFGain); + AmbiMatrix, al::size(AmbiPoints), AmbiOrderHFGain); HrtfEntry *Hrtf{device->mHrtf}; InitNearFieldCtrl(device, Hrtf->field[0].distance, ambi_order, ChansPerOrder); -- cgit v1.2.3 From 857473b6b06314e18f52e97cb440e5daee1ad523 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 24 May 2019 04:55:38 -0700 Subject: Store the span extents as a pair of pointers --- common/alspan.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/common/alspan.h b/common/alspan.h index 96823171..0c15b93c 100644 --- a/common/alspan.h +++ b/common/alspan.h @@ -62,8 +62,8 @@ public: using const_reverse_iterator = std::reverse_iterator; constexpr span() noexcept = default; - constexpr span(pointer ptr, index_type count) : mData{ptr}, mCount{count} { } - constexpr span(pointer first, pointer last) : mData{first}, mCount{std::distance(first, last)} { } + constexpr span(pointer ptr, index_type count) : mData{ptr}, mDataEnd{ptr+count} { } + constexpr span(pointer first, pointer last) : mData{first}, mDataEnd{last} { } template constexpr span(element_type (&arr)[N]) noexcept : span{al::data(arr), al::size(arr)} { } template @@ -78,19 +78,19 @@ public: span& operator=(const span &rhs) noexcept = default; - constexpr reference front() const { return mData[0]; } - constexpr reference back() const { return mData[mCount-1]; } + constexpr reference front() const { return *mData; } + constexpr reference back() const { return *(mDataEnd-1); } constexpr reference operator[](index_type idx) const { return mData[idx]; } constexpr pointer data() const noexcept { return mData; } - constexpr index_type size() const noexcept { return mCount; } - constexpr index_type size_bytes() const noexcept { return mCount * sizeof(value_type); } - constexpr bool empty() const noexcept { return mCount == 0; } + constexpr index_type size() const noexcept { return mDataEnd-mData; } + constexpr index_type size_bytes() const noexcept { return (mDataEnd-mData) * sizeof(value_type); } + constexpr bool empty() const noexcept { return mData == mDataEnd; } constexpr iterator begin() const noexcept { return mData; } - constexpr iterator end() const noexcept { return mData + mCount; } + constexpr iterator end() const noexcept { return mDataEnd; } constexpr const_iterator cbegin() const noexcept { return mData; } - constexpr const_iterator cend() const noexcept { return mData + mCount; } + constexpr const_iterator cend() const noexcept { return mDataEnd; } constexpr reverse_iterator rbegin() const noexcept { return end(); } constexpr reverse_iterator rend() const noexcept { return begin(); } @@ -99,7 +99,7 @@ public: private: pointer mData{nullptr}; - index_type mCount{0u}; + pointer mDataEnd{nullptr}; }; } // namespace al -- cgit v1.2.3 From 1945b50834e2be380e0ad206f9deefacb455191b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 24 May 2019 06:11:21 -0700 Subject: Add a unique byte type for dealing with raw bytes --- CMakeLists.txt | 1 + common/albyte.h | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 common/albyte.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a2eff245..53c3ff80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -639,6 +639,7 @@ ENDIF() # Common sources used by both the OpenAL implementation library and potentially # the OpenAL router. SET(COMMON_OBJS + common/albyte.h common/alcomplex.cpp common/alcomplex.h common/alexcpt.cpp diff --git a/common/albyte.h b/common/albyte.h new file mode 100644 index 00000000..6fc78dbd --- /dev/null +++ b/common/albyte.h @@ -0,0 +1,60 @@ +#ifndef AL_BYTE_H +#define AL_BYTE_H + +#include + +namespace al { + +/* The "canonical" way to store raw byte data. Like C++17's std::byte, it's not + * treated as a character type and does not work with arithmatic ops. Only + * bitwise ops are allowed. + */ +enum class byte : unsigned char { }; + +template::value,int>::type = 0> +inline constexpr T to_integer(al::byte b) noexcept { return T(b); } + + +template::value,int>::type = 0> +inline constexpr al::byte operator<<(al::byte lhs, T rhs) noexcept +{ return al::byte(to_integer(lhs) << rhs); } + +template::value,int>::type = 0> +inline constexpr al::byte operator>>(al::byte lhs, T rhs) noexcept +{ return al::byte(to_integer(lhs) >> rhs); } + +#define AL_DECL_OP(op) \ +inline constexpr al::byte operator op (al::byte lhs, al::byte rhs) noexcept \ +{ return al::byte(to_integer(lhs) op to_integer(rhs)); } + +AL_DECL_OP(|) +AL_DECL_OP(&) +AL_DECL_OP(^) + +#undef AL_DECL_OP + +inline constexpr al::byte operator~(al::byte b) noexcept +{ return al::byte(~to_integer(b)); } + + +template::value,int>::type = 0> +inline al::byte& operator<<=(al::byte &lhs, T rhs) noexcept +{ lhs = lhs << rhs; return lhs; } + +template::value,int>::type = 0> +inline al::byte& operator>>=(al::byte &lhs, T rhs) noexcept +{ lhs = lhs >> rhs; return lhs; } + +#define AL_DECL_OP(op) \ +inline al::byte& operator op##= (al::byte &lhs, al::byte rhs) noexcept \ +{ lhs = lhs op rhs; return lhs; } + +AL_DECL_OP(|) +AL_DECL_OP(&) +AL_DECL_OP(^) + +#undef AL_DECL_OP + +} // namespace al + +#endif /* AL_BYTE_H */ -- cgit v1.2.3 From 9c63bbd6ce90146939891f56cb0265e5d65ec846 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 24 May 2019 06:12:20 -0700 Subject: Use raw bytes for the buffer data --- Alc/mixvoice.cpp | 14 +++++++------- OpenAL32/Include/alBuffer.h | 3 ++- OpenAL32/alBuffer.cpp | 5 +++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index f539f119..5c7ce95d 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -271,17 +271,17 @@ template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) { return aLawDecompressionTable[val] * (1.0f/32768.0f); } template -inline void LoadSampleArray(ALfloat *RESTRICT dst, const void *src, ALint srcstep, +inline void LoadSampleArray(ALfloat *RESTRICT dst, const al::byte *src, ALint srcstep, const ptrdiff_t samples) { using SampleType = typename FmtTypeTraits::Type; - const SampleType *ssrc = static_cast(src); + const SampleType *RESTRICT ssrc{reinterpret_cast(src)}; for(ALsizei i{0};i < samples;i++) dst[i] += LoadSample(ssrc[i*srcstep]); } -void LoadSamples(ALfloat *RESTRICT dst, const ALvoid *RESTRICT src, ALint srcstep, FmtType srctype, +void LoadSamples(ALfloat *RESTRICT dst, const al::byte *src, ALint srcstep, FmtType srctype, const ptrdiff_t samples) { #define HANDLE_FMT(T) case T: LoadSampleArray(dst, src, srcstep, samples); break @@ -327,7 +327,7 @@ ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&B const ptrdiff_t DataSize{std::min(SizeToDo, buffer->SampleLen-DataPosInt)}; CompLen = std::max(CompLen, DataSize); - const ALbyte *Data{buffer->mData.data()}; + const al::byte *Data{buffer->mData.data()}; Data += (DataPosInt*NumChannels + chan)*SampleSize; LoadSamples(SrcData, Data, NumChannels, buffer->mFmtType, DataSize); @@ -353,7 +353,7 @@ ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&B const ptrdiff_t DataSize{std::min(SizeToDo, buffer->SampleLen-DataPosInt)}; CompLen = std::max(CompLen, DataSize); - const ALbyte *Data{buffer->mData.data()}; + const al::byte *Data{buffer->mData.data()}; Data += (DataPosInt*NumChannels + chan)*SampleSize; LoadSamples(SrcData, Data, NumChannels, buffer->mFmtType, DataSize); @@ -379,7 +379,7 @@ ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&B buffer->SampleLen-LoopStart)}; CompLen = std::max(CompLen, DataSize); - const ALbyte *Data{buffer->mData.data()}; + const al::byte *Data{buffer->mData.data()}; Data += (LoopStart*NumChannels + chan)*SampleSize; LoadSamples(SrcData, Data, NumChannels, buffer->mFmtType, DataSize); @@ -418,7 +418,7 @@ ALfloat *LoadBufferQueue(ALbufferlistitem *BufferListItem, ALbufferlistitem *Buf const ptrdiff_t DataSize{std::min(SizeToDo, buffer->SampleLen-DataPosInt)}; CompLen = std::max(CompLen, DataSize); - const ALbyte *Data{buffer->mData.data()}; + const al::byte *Data{buffer->mData.data()}; Data += (DataPosInt*NumChannels + chan)*SampleSize; LoadSamples(SrcData, Data, NumChannels, buffer->mFmtType, DataSize); diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index ec9f6c37..22e99b99 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -8,6 +8,7 @@ #include "inprogext.h" #include "atomic.h" #include "vector.h" +#include "albyte.h" /* User formats */ @@ -86,7 +87,7 @@ inline ALsizei FrameSizeFromFmt(FmtChannels chans, FmtType type) struct ALbuffer { - al::vector mData; + al::vector mData; ALsizei Frequency{0}; ALbitfieldSOFT Access{0u}; diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index 1dc37ec7..4524f81c 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -288,7 +288,7 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U newsize = (newsize+15) & ~0xf; if(newsize != ALBuf->BytesAlloc) { - al::vector newdata(newsize); + al::vector newdata(newsize); if((access&AL_PRESERVE_DATA_BIT_SOFT)) { ALsizei tocopy{std::min(newsize, ALBuf->BytesAlloc)}; @@ -318,7 +318,8 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U { assert(static_cast(SrcType) == static_cast(DstType)); if(data != nullptr && !ALBuf->mData.empty()) - std::copy_n(static_cast(data), frames*FrameSize, ALBuf->mData.begin()); + std::copy_n(static_cast(data), frames*FrameSize, + ALBuf->mData.begin()); ALBuf->OriginalAlign = 1; } ALBuf->OriginalSize = size; -- cgit v1.2.3 From e90a6beaa2a2712d25bb6e32d0034298876bd0de Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 24 May 2019 06:25:18 -0700 Subject: Remove an unnecessary struct member --- OpenAL32/Include/alBuffer.h | 1 - OpenAL32/alBuffer.cpp | 20 +++++++++----------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 22e99b99..1919dd5a 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -95,7 +95,6 @@ struct ALbuffer { FmtChannels mFmtChannels{}; FmtType mFmtType{}; - ALsizei BytesAlloc{0}; UserFmtType OriginalType{}; ALsizei OriginalSize{0}; diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index 4524f81c..700c0de9 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -235,8 +235,8 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U NameFromUserFmtType(SrcType)); } - ALsizei unpackalign{ALBuf->UnpackAlign.load()}; - ALsizei align{SanitizeAlignment(SrcType, unpackalign)}; + const ALsizei unpackalign{ALBuf->UnpackAlign.load()}; + const ALsizei align{SanitizeAlignment(SrcType, unpackalign)}; if(UNLIKELY(align < 1)) SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid unpack alignment %d for %s samples", unpackalign, NameFromUserFmtType(SrcType)); @@ -253,7 +253,7 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U /* Convert the input/source size in bytes to sample frames using the unpack * block alignment. */ - ALsizei SrcByteAlign{ + const ALsizei SrcByteAlign{ (SrcType == UserFmtIMA4) ? ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels) : (SrcType == UserFmtMSADPCM) ? ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels) : (align * FrameSizeFromUserFmt(SrcChannels, SrcType)) @@ -266,7 +266,7 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U if(UNLIKELY(size/SrcByteAlign > std::numeric_limits::max()/align)) SETERR_RETURN(context, AL_OUT_OF_MEMORY,, "Buffer size overflow, %d blocks x %d samples per block", size/SrcByteAlign, align); - ALsizei frames{size / SrcByteAlign * align}; + const ALsizei frames{size / SrcByteAlign * align}; /* Convert the sample frames to the number of bytes needed for internal * storage. @@ -276,7 +276,7 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U if(UNLIKELY(frames > std::numeric_limits::max()/FrameSize)) SETERR_RETURN(context, AL_OUT_OF_MEMORY,, "Buffer size overflow, %d frames x %d bytes per frame", frames, FrameSize); - ALsizei newsize{frames*FrameSize}; + size_t newsize{static_cast(frames) * FrameSize}; /* Round up to the next 16-byte multiple. This could reallocate only when * increasing or the new size is less than half the current, but then the @@ -284,18 +284,16 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U * usage, and reporting the real size could cause problems for apps that * use AL_SIZE to try to get the buffer's play length. */ - if(LIKELY(newsize <= std::numeric_limits::max()-15)) - newsize = (newsize+15) & ~0xf; - if(newsize != ALBuf->BytesAlloc) + newsize = RoundUp(newsize, 16); + if(newsize != ALBuf->mData.size()) { - al::vector newdata(newsize); + auto newdata = al::vector(newsize); if((access&AL_PRESERVE_DATA_BIT_SOFT)) { - ALsizei tocopy{std::min(newsize, ALBuf->BytesAlloc)}; + const size_t tocopy{minz(newdata.size(), ALBuf->mData.size())}; std::copy_n(ALBuf->mData.begin(), tocopy, newdata.begin()); } ALBuf->mData = std::move(newdata); - ALBuf->BytesAlloc = newsize; } if(SrcType == UserFmtIMA4) -- cgit v1.2.3 From 1f45cc051ad0aeac0033fd1c7e53c7834089021a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 24 May 2019 06:47:24 -0700 Subject: Fix some truncation warnings with MSVC --- Alc/hrtf.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 92d7b47e..427326d0 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -673,12 +673,12 @@ std::unique_ptr LoadHrtf00(std::istream &data, const char *filename) /* Mirror the left ear responses to the right ear. */ for(ALsizei i{0};i < evCount;i++) { - ALushort evoffset = evOffset[i]; - ALubyte azcount = azCount[i]; + const ALushort evoffset{evOffset[i]}; + const ALushort azcount{azCount[i]}; for(ALsizei j{0};j < azcount;j++) { - ALsizei lidx = evoffset + j; - ALsizei ridx = evoffset + ((azcount-j) % azcount); + const ALsizei lidx{evoffset + j}; + const ALsizei ridx{evoffset + ((azcount-j) % azcount)}; for(ALsizei k{0};k < irSize;k++) coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; @@ -772,12 +772,12 @@ std::unique_ptr LoadHrtf01(std::istream &data, const char *filename) /* Mirror the left ear responses to the right ear. */ for(ALsizei i{0};i < evCount;i++) { - ALushort evoffset = evOffset[i]; - ALubyte azcount = azCount[i]; + const ALushort evoffset{evOffset[i]}; + const ALushort azcount{azCount[i]}; for(ALsizei j{0};j < azcount;j++) { - ALsizei lidx = evoffset + j; - ALsizei ridx = evoffset + ((azcount-j) % azcount); + const ALsizei lidx{evoffset + j}; + const ALsizei ridx{evoffset + ((azcount-j) % azcount)}; for(ALsizei k{0};k < irSize;k++) coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; @@ -983,12 +983,12 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) { for(ALsizei e{0};e < evCount[f];e++) { - ALushort evoffset = evOffset[ebase+e]; - ALubyte azcount = azCount[ebase+e]; + const ALushort evoffset{evOffset[ebase+e]}; + const ALushort azcount{azCount[ebase+e]}; for(ALsizei a{0};a < azcount;a++) { - ALsizei lidx = evoffset + a; - ALsizei ridx = evoffset + ((azcount-a) % azcount); + const ALsizei lidx{evoffset + a}; + const ALsizei ridx{evoffset + ((azcount-a) % azcount)}; for(ALsizei k{0};k < irSize;k++) coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; @@ -1023,7 +1023,7 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) azcnt_end = std::copy_backward(azcnt_src, azcnt_src+num_evs, azcnt_end); return ebase + num_evs; }; - std::accumulate(evCount.cbegin(), evCount.cend(), 0u, copy_azs); + std::accumulate(evCount.cbegin(), evCount.cend(), size_t{0u}, copy_azs); assert(azCount_.begin() == azcnt_end); /* Reestablish the IR offset for each elevation index, given the new @@ -1048,7 +1048,7 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) return ebase + num_evs; }; - std::accumulate(evCount.cbegin(), evCount.cend(), 0u, copy_irs); + std::accumulate(evCount.cbegin(), evCount.cend(), size_t{0u}, copy_irs); assert(coeffs_.begin() == coeffs_end); assert(delays_.begin() == delays_end); -- cgit v1.2.3 From 674ca3cf243acfb4bb698fec86ca1b0da839dc9f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 24 May 2019 12:06:52 -0700 Subject: Move a couple table definitions to where they're used --- Alc/mixvoice.cpp | 75 +++++++++++++++++++++++++++++++++++++++ OpenAL32/Include/sample_cvt.h | 10 ------ OpenAL32/sample_cvt.cpp | 82 ++----------------------------------------- 3 files changed, 78 insertions(+), 89 deletions(-) diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 5c7ce95d..e1d2c6a0 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -198,6 +198,81 @@ void aluInitMixer() namespace { +/* A quick'n'dirty lookup table to decode a muLaw-encoded byte sample into a + * signed 16-bit sample */ +constexpr ALshort muLawDecompressionTable[256] = { + -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956, + -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764, + -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412, + -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316, + -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, + -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, + -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, + -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, + -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, + -876, -844, -812, -780, -748, -716, -684, -652, + -620, -588, -556, -524, -492, -460, -428, -396, + -372, -356, -340, -324, -308, -292, -276, -260, + -244, -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, -64, + -56, -48, -40, -32, -24, -16, -8, 0, + 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, + 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, + 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, + 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, + 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, + 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, + 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, + 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, + 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, + 876, 844, 812, 780, 748, 716, 684, 652, + 620, 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, 260, + 244, 228, 212, 196, 180, 164, 148, 132, + 120, 112, 104, 96, 88, 80, 72, 64, + 56, 48, 40, 32, 24, 16, 8, 0 +}; + +/* A quick'n'dirty lookup table to decode an aLaw-encoded byte sample into a + * signed 16-bit sample */ +constexpr ALshort aLawDecompressionTable[256] = { + -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, + -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, + -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, + -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, + -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944, + -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136, + -11008,-10496,-12032,-11520, -8960, -8448, -9984, -9472, + -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568, + -344, -328, -376, -360, -280, -264, -312, -296, + -472, -456, -504, -488, -408, -392, -440, -424, + -88, -72, -120, -104, -24, -8, -56, -40, + -216, -200, -248, -232, -152, -136, -184, -168, + -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, + -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, -592, + -944, -912, -1008, -976, -816, -784, -880, -848, + 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, + 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, + 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, + 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, + 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, + 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, + 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, + 344, 328, 376, 360, 280, 264, 312, 296, + 472, 456, 504, 488, 408, 392, 440, 424, + 88, 72, 120, 104, 24, 8, 56, 40, + 216, 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, + 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, + 688, 656, 752, 720, 560, 528, 624, 592, + 944, 912, 1008, 976, 816, 784, 880, 848 +}; + + void SendSourceStoppedEvent(ALCcontext *context, ALuint id) { ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)}; diff --git a/OpenAL32/Include/sample_cvt.h b/OpenAL32/Include/sample_cvt.h index a3b53d44..4d742f1c 100644 --- a/OpenAL32/Include/sample_cvt.h +++ b/OpenAL32/Include/sample_cvt.h @@ -4,20 +4,10 @@ #include "AL/al.h" #include "alBuffer.h" -#ifdef __cplusplus -extern "C" { -#endif - -extern const ALshort muLawDecompressionTable[256]; -extern const ALshort aLawDecompressionTable[256]; void Convert_ALshort_ALima4(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len, ALsizei align); void Convert_ALshort_ALmsadpcm(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len, ALsizei align); -#ifdef __cplusplus -} // extern "C" -#endif - #endif /* SAMPLE_CVT_H */ diff --git a/OpenAL32/sample_cvt.cpp b/OpenAL32/sample_cvt.cpp index 6d6707f3..b82b3a3d 100644 --- a/OpenAL32/sample_cvt.cpp +++ b/OpenAL32/sample_cvt.cpp @@ -8,80 +8,6 @@ #include "alBuffer.h" -/* A quick'n'dirty lookup table to decode a muLaw-encoded byte sample into a - * signed 16-bit sample */ -const ALshort muLawDecompressionTable[256] = { - -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956, - -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764, - -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412, - -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316, - -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, - -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, - -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, - -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, - -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, - -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, - -876, -844, -812, -780, -748, -716, -684, -652, - -620, -588, -556, -524, -492, -460, -428, -396, - -372, -356, -340, -324, -308, -292, -276, -260, - -244, -228, -212, -196, -180, -164, -148, -132, - -120, -112, -104, -96, -88, -80, -72, -64, - -56, -48, -40, -32, -24, -16, -8, 0, - 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, - 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, - 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, - 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, - 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, - 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, - 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, - 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, - 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, - 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, - 876, 844, 812, 780, 748, 716, 684, 652, - 620, 588, 556, 524, 492, 460, 428, 396, - 372, 356, 340, 324, 308, 292, 276, 260, - 244, 228, 212, 196, 180, 164, 148, 132, - 120, 112, 104, 96, 88, 80, 72, 64, - 56, 48, 40, 32, 24, 16, 8, 0 -}; - -/* A quick'n'dirty lookup table to decode an aLaw-encoded byte sample into a - * signed 16-bit sample */ -const ALshort aLawDecompressionTable[256] = { - -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, - -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, - -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, - -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, - -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944, - -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136, - -11008,-10496,-12032,-11520, -8960, -8448, -9984, -9472, - -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568, - -344, -328, -376, -360, -280, -264, -312, -296, - -472, -456, -504, -488, -408, -392, -440, -424, - -88, -72, -120, -104, -24, -8, -56, -40, - -216, -200, -248, -232, -152, -136, -184, -168, - -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, - -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, - -688, -656, -752, -720, -560, -528, -624, -592, - -944, -912, -1008, -976, -816, -784, -880, -848, - 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, - 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, - 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, - 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, - 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, - 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, - 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, - 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, - 344, 328, 376, 360, 280, 264, 312, 296, - 472, 456, 504, 488, 408, 392, 440, 424, - 88, 72, 120, 104, 24, 8, 56, 40, - 216, 200, 248, 232, 152, 136, 184, 168, - 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, - 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, - 688, 656, 752, 720, 560, 528, 624, 592, - 944, 912, 1008, 976, 816, 784, 880, 848 -}; - namespace { /* IMA ADPCM Stepsize table */ @@ -216,7 +142,7 @@ void DecodeMSADPCMBlock(ALshort *dst, const ALubyte *src, ALint numchans, ALsize { for(int c{0};c < numchans;c++) { - const ALint num = (i*numchans) + c; + const ALint num{(i*numchans) + c}; ALint nibble, pred; /* Read the nibble (first is in the upper bits). */ @@ -246,9 +172,8 @@ void DecodeMSADPCMBlock(ALshort *dst, const ALubyte *src, ALint numchans, ALsize void Convert_ALshort_ALima4(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len, ALsizei align) { - ALsizei byte_align = ((align-1)/2 + 4) * numchans; + const ALsizei byte_align{((align-1)/2 + 4) * numchans}; - assert(align > 0 && (len%align) == 0); len /= align; while(len--) { @@ -261,9 +186,8 @@ void Convert_ALshort_ALima4(ALshort *dst, const ALubyte *src, ALsizei numchans, void Convert_ALshort_ALmsadpcm(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len, ALsizei align) { - const ALsizei byte_align = ((align-2)/2 + 7) * numchans; + const ALsizei byte_align{((align-2)/2 + 7) * numchans}; - assert(align > 1 && (len%align) == 0); len /= align; while(len--) { -- cgit v1.2.3 From b4fbc271d297b084df310e827e241b44bf9532b3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 24 May 2019 13:30:40 -0700 Subject: Add byte ops that take an integer-based rhs parameter --- common/albyte.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/common/albyte.h b/common/albyte.h index 6fc78dbd..f9230005 100644 --- a/common/albyte.h +++ b/common/albyte.h @@ -24,8 +24,11 @@ inline constexpr al::byte operator>>(al::byte lhs, T rhs) noexcept { return al::byte(to_integer(lhs) >> rhs); } #define AL_DECL_OP(op) \ +template::value,int>::type = 0> \ +inline constexpr al::byte operator op (al::byte lhs, T rhs) noexcept \ +{ return al::byte(to_integer(lhs) op rhs); } \ inline constexpr al::byte operator op (al::byte lhs, al::byte rhs) noexcept \ -{ return al::byte(to_integer(lhs) op to_integer(rhs)); } +{ return al::byte(lhs op to_integer(rhs)); } AL_DECL_OP(|) AL_DECL_OP(&) @@ -46,6 +49,9 @@ inline al::byte& operator>>=(al::byte &lhs, T rhs) noexcept { lhs = lhs >> rhs; return lhs; } #define AL_DECL_OP(op) \ +template::value,int>::type = 0> \ +inline al::byte& operator op##= (al::byte &lhs, T rhs) noexcept \ +{ lhs = lhs op rhs; return lhs; } \ inline al::byte& operator op##= (al::byte &lhs, al::byte rhs) noexcept \ { lhs = lhs op rhs; return lhs; } -- cgit v1.2.3 From 219f818b165d6997d6a2f1f8f0c5f88ba68a5db2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 24 May 2019 13:32:20 -0700 Subject: Use al::byte for ADPCM decoders --- OpenAL32/Include/sample_cvt.h | 6 ++-- OpenAL32/alBuffer.cpp | 27 ++++++++------- OpenAL32/sample_cvt.cpp | 77 +++++++++++++++++++++---------------------- 3 files changed, 53 insertions(+), 57 deletions(-) diff --git a/OpenAL32/Include/sample_cvt.h b/OpenAL32/Include/sample_cvt.h index 4d742f1c..c8c1ad23 100644 --- a/OpenAL32/Include/sample_cvt.h +++ b/OpenAL32/Include/sample_cvt.h @@ -2,12 +2,12 @@ #define SAMPLE_CVT_H #include "AL/al.h" -#include "alBuffer.h" +#include "albyte.h" -void Convert_ALshort_ALima4(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len, +void Convert_ALshort_ALima4(ALshort *dst, const al::byte *src, ALsizei numchans, ALsizei len, ALsizei align); -void Convert_ALshort_ALmsadpcm(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len, +void Convert_ALshort_ALmsadpcm(ALshort *dst, const al::byte *src, ALsizei numchans, ALsizei len, ALsizei align); #endif /* SAMPLE_CVT_H */ diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index 700c0de9..738133f5 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -185,7 +185,7 @@ const ALchar *NameFromUserFmtType(UserFmtType type) * * Loads the specified data into the buffer, using the specified format. */ -void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, UserFmtChannels SrcChannels, UserFmtType SrcType, const ALvoid *data, ALbitfieldSOFT access) +void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, UserFmtChannels SrcChannels, UserFmtType SrcType, const al::byte *SrcData, ALbitfieldSOFT access) { if(UNLIKELY(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)) SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer %u", @@ -287,7 +287,7 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U newsize = RoundUp(newsize, 16); if(newsize != ALBuf->mData.size()) { - auto newdata = al::vector(newsize); + auto newdata = al::vector(newsize, al::byte{}); if((access&AL_PRESERVE_DATA_BIT_SOFT)) { const size_t tocopy{minz(newdata.size(), ALBuf->mData.size())}; @@ -299,25 +299,24 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U if(SrcType == UserFmtIMA4) { assert(DstType == FmtShort); - if(data != nullptr && !ALBuf->mData.empty()) + if(SrcData != nullptr && !ALBuf->mData.empty()) Convert_ALshort_ALima4(reinterpret_cast(ALBuf->mData.data()), - static_cast(data), NumChannels, frames, align); + SrcData, NumChannels, frames, align); ALBuf->OriginalAlign = align; } else if(SrcType == UserFmtMSADPCM) { assert(DstType == FmtShort); - if(data != nullptr && !ALBuf->mData.empty()) + if(SrcData != nullptr && !ALBuf->mData.empty()) Convert_ALshort_ALmsadpcm(reinterpret_cast(ALBuf->mData.data()), - static_cast(data), NumChannels, frames, align); + SrcData, NumChannels, frames, align); ALBuf->OriginalAlign = align; } else { assert(static_cast(SrcType) == static_cast(DstType)); - if(data != nullptr && !ALBuf->mData.empty()) - std::copy_n(static_cast(data), frames*FrameSize, - ALBuf->mData.begin()); + if(SrcData != nullptr && !ALBuf->mData.empty()) + std::copy_n(SrcData, frames*FrameSize, ALBuf->mData.begin()); ALBuf->OriginalAlign = 1; } ALBuf->OriginalSize = size; @@ -560,7 +559,8 @@ START_API_FUNC if(UNLIKELY(!success)) alSetError(context.get(), AL_INVALID_ENUM, "Invalid format 0x%04x", format); else - LoadData(context.get(), albuf, freq, size, srcchannels, srctype, data, flags); + LoadData(context.get(), albuf, freq, size, srcchannels, srctype, + static_cast(data), flags); } } END_API_FUNC @@ -745,14 +745,13 @@ START_API_FUNC void *dst = albuf->mData.data() + offset; if(srctype == UserFmtIMA4 && albuf->mFmtType == FmtShort) Convert_ALshort_ALima4(static_cast(dst), - static_cast(data), num_chans, length, align); + static_cast(data), num_chans, length, align); else if(srctype == UserFmtMSADPCM && albuf->mFmtType == FmtShort) Convert_ALshort_ALmsadpcm(static_cast(dst), - static_cast(data), num_chans, length, align); + static_cast(data), num_chans, length, align); else { - assert(static_cast(srctype) == - static_cast(albuf->mFmtType)); + assert(static_cast(srctype) == static_cast(albuf->mFmtType)); memcpy(dst, data, length * frame_size); } } diff --git a/OpenAL32/sample_cvt.cpp b/OpenAL32/sample_cvt.cpp index b82b3a3d..79d0d1c5 100644 --- a/OpenAL32/sample_cvt.cpp +++ b/OpenAL32/sample_cvt.cpp @@ -53,7 +53,8 @@ constexpr int MSADPCMAdaptionCoeff[7][2] = { { 392, -232 } }; -void DecodeIMA4Block(ALshort *dst, const ALubyte *src, ALint numchans, ALsizei align) + +void DecodeIMA4Block(ALshort *dst, const al::byte *src, ALint numchans, ALsizei align) { ALint sample[MAX_INPUT_CHANNELS]{}; ALint index[MAX_INPUT_CHANNELS]{}; @@ -61,16 +62,14 @@ void DecodeIMA4Block(ALshort *dst, const ALubyte *src, ALint numchans, ALsizei a for(int c{0};c < numchans;c++) { - sample[c] = *(src++); - sample[c] |= *(src++) << 8; - sample[c] = (sample[c]^0x8000) - 32768; - index[c] = *(src++); - index[c] |= *(src++) << 8; - index[c] = (index[c]^0x8000) - 32768; - - index[c] = clampi(index[c], 0, 88); - - dst[c] = sample[c]; + sample[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + sample[c] = (sample[c]^0x8000) - 32768; + src += 2; + index[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + index[c] = clampi((index[c]^0x8000) - 32768, 0, 88); + src += 2; + + *(dst++) = sample[c]; } for(int i{1};i < align;i++) @@ -79,16 +78,15 @@ void DecodeIMA4Block(ALshort *dst, const ALubyte *src, ALint numchans, ALsizei a { for(int c{0};c < numchans;c++) { - code[c] = *(src++); - code[c] |= *(src++) << 8; - code[c] |= *(src++) << 16; - code[c] |= *(src++) << 24; + code[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<< 8) | + (al::to_integer(src[2])<<16) | (al::to_integer(src[3])<<24); + src += 4; } } for(int c{0};c < numchans;c++) { - int nibble = code[c]&0xf; + const ALuint nibble{code[c]&0xf}; code[c] >>= 4; sample[c] += IMA4Codeword[nibble] * IMAStep_size[index[c]] / 8; @@ -102,7 +100,7 @@ void DecodeIMA4Block(ALshort *dst, const ALubyte *src, ALint numchans, ALsizei a } } -void DecodeMSADPCMBlock(ALshort *dst, const ALubyte *src, ALint numchans, ALsizei align) +void DecodeMSADPCMBlock(ALshort *dst, const al::byte *src, ALint numchans, ALsizei align) { ALubyte blockpred[MAX_INPUT_CHANNELS]{}; ALint delta[MAX_INPUT_CHANNELS]{}; @@ -110,26 +108,26 @@ void DecodeMSADPCMBlock(ALshort *dst, const ALubyte *src, ALint numchans, ALsize for(int c{0};c < numchans;c++) { - blockpred[c] = *(src++); - blockpred[c] = minu(blockpred[c], 6); + blockpred[c] = minu(al::to_integer(src[0]), 6); + ++src; } for(int c{0};c < numchans;c++) { - delta[c] = *(src++); - delta[c] |= *(src++) << 8; - delta[c] = (delta[c]^0x8000) - 32768; + delta[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + delta[c] = (delta[c]^0x8000) - 32768; + src += 2; } for(int c{0};c < numchans;c++) { - samples[c][0] = *(src++); - samples[c][0] |= *(src++) << 8; - samples[c][0] = (samples[c][0]^0x8000) - 32768; + samples[c][0] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + samples[c][0] = (samples[c][0]^0x8000) - 32768; + src += 2; } for(int c{0};c < numchans;c++) { - samples[c][1] = *(src++); - samples[c][1] |= *(src++) << 8; - samples[c][1] = (samples[c][1]^0x8000) - 0x8000; + samples[c][1] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + samples[c][1] = (samples[c][1]^0x8000) - 32768; + src += 2; } /* Second sample is written first. */ @@ -138,28 +136,27 @@ void DecodeMSADPCMBlock(ALshort *dst, const ALubyte *src, ALint numchans, ALsize for(int c{0};c < numchans;c++) *(dst++) = samples[c][0]; + int num{0}; for(int i{2};i < align;i++) { for(int c{0};c < numchans;c++) { - const ALint num{(i*numchans) + c}; - ALint nibble, pred; - /* Read the nibble (first is in the upper bits). */ - if(!(num&1)) - nibble = (*src>>4)&0x0f; + al::byte nibble; + if(!(num++ & 1)) + nibble = *src >> 4; else - nibble = (*(src++))&0x0f; + nibble = *(src++) & 0x0f; - pred = (samples[c][0]*MSADPCMAdaptionCoeff[blockpred[c]][0] + - samples[c][1]*MSADPCMAdaptionCoeff[blockpred[c]][1]) / 256; - pred += ((nibble^0x08) - 0x08) * delta[c]; + ALint pred{(samples[c][0]*MSADPCMAdaptionCoeff[blockpred[c]][0] + + samples[c][1]*MSADPCMAdaptionCoeff[blockpred[c]][1]) / 256}; + pred += (al::to_integer(nibble^0x08) - 0x08) * delta[c]; pred = clampi(pred, -32768, 32767); samples[c][1] = samples[c][0]; samples[c][0] = pred; - delta[c] = (MSADPCMAdaption[nibble] * delta[c]) / 256; + delta[c] = (MSADPCMAdaption[al::to_integer(nibble)] * delta[c]) / 256; delta[c] = maxi(16, delta[c]); *(dst++) = pred; @@ -169,7 +166,7 @@ void DecodeMSADPCMBlock(ALshort *dst, const ALubyte *src, ALint numchans, ALsize } // namespace -void Convert_ALshort_ALima4(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len, +void Convert_ALshort_ALima4(ALshort *dst, const al::byte *src, ALsizei numchans, ALsizei len, ALsizei align) { const ALsizei byte_align{((align-1)/2 + 4) * numchans}; @@ -183,7 +180,7 @@ void Convert_ALshort_ALima4(ALshort *dst, const ALubyte *src, ALsizei numchans, } } -void Convert_ALshort_ALmsadpcm(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len, +void Convert_ALshort_ALmsadpcm(ALshort *dst, const al::byte *src, ALsizei numchans, ALsizei len, ALsizei align) { const ALsizei byte_align{((align-2)/2 + 7) * numchans}; -- cgit v1.2.3 From ebf33b7c6b747b647eb2177080dc6f46db89867b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 25 May 2019 08:17:37 -0700 Subject: Avoid some uses of RESTRICT --- Alc/alu.cpp | 27 +++++++++++++-------------- Alc/effects/chorus.cpp | 45 +++++++++++++++++++++++++++------------------ Alc/hrtf.cpp | 3 +-- Alc/mastering.cpp | 6 +----- Alc/mixer/mixer_c.cpp | 18 ++++++++++-------- 5 files changed, 52 insertions(+), 47 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index d1e0772a..2bdfd092 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1476,9 +1476,8 @@ void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) } -void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*RESTRICT Buffer)[BUFFERSIZE], - int lidx, int ridx, int cidx, const ALsizei SamplesToDo, - const ALsizei NumChannels) +void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*Buffer)[BUFFERSIZE], const int lidx, + const int ridx, const int cidx, const ALsizei SamplesToDo, const ALsizei NumChannels) { ASSUME(SamplesToDo > 0); ASSUME(NumChannels > 0); @@ -1506,7 +1505,7 @@ void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*RESTRICT Buffer)[BUFFER } } - SplitterAllpass &APFilter = Stablizer->APFilter; + const SplitterAllpass &APFilter = Stablizer->APFilter; ALfloat (&lsplit)[2][BUFFERSIZE] = Stablizer->LSplit; ALfloat (&rsplit)[2][BUFFERSIZE] = Stablizer->RSplit; auto &tmpbuf = Stablizer->TempBuf; @@ -1514,7 +1513,7 @@ void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*RESTRICT Buffer)[BUFFER /* This applies the band-splitter, preserving phase at the cost of some * delay. The shorter the delay, the more error seeps into the result. */ - auto apply_splitter = [&APFilter,&tmpbuf,SamplesToDo](const ALfloat *RESTRICT Buffer, + auto apply_splitter = [&APFilter,&tmpbuf,SamplesToDo](const ALfloat *Buffer, ALfloat (&DelayBuf)[FrontStablizer::DelayLength], BandSplitter &Filter, ALfloat (&splitbuf)[2][BUFFERSIZE]) -> void { @@ -1665,24 +1664,24 @@ template<> inline ALubyte SampleConv(ALfloat val) noexcept { return SampleConv(val) + 128; } template -void Write(const ALfloat (*InBuffer)[BUFFERSIZE], ALvoid *OutBuffer, ALsizei Offset, - ALsizei SamplesToDo, ALsizei numchans) +void Write(const ALfloat (*InBuffer)[BUFFERSIZE], ALvoid *OutBuffer, const ALsizei Offset, + const ALsizei SamplesToDo, const ALsizei numchans) { using SampleType = typename DevFmtTypeTraits::Type; + ASSUME(Offset >= 0); ASSUME(numchans > 0); SampleType *outbase = static_cast(OutBuffer) + Offset*numchans; auto conv_channel = [&outbase,SamplesToDo,numchans](const ALfloat *inbuf) -> void { ASSUME(SamplesToDo > 0); SampleType *out{outbase++}; - std::for_each(inbuf, inbuf+SamplesToDo, - [numchans,&out](const ALfloat s) noexcept -> void - { - *out = SampleConv(s); - out += numchans; - } - ); + auto conv_sample = [numchans,&out](const ALfloat s) noexcept -> void + { + *out = SampleConv(s); + out += numchans; + }; + std::for_each(inbuf, inbuf+SamplesToDo, conv_sample); }; std::for_each(InBuffer, InBuffer+numchans, conv_channel); } diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp index 74b46a10..d12d2484 100644 --- a/Alc/effects/chorus.cpp +++ b/Alc/effects/chorus.cpp @@ -44,28 +44,37 @@ enum class WaveForm { Triangle }; -void GetTriangleDelays(ALint *delays, ALsizei offset, ALsizei lfo_range, ALfloat lfo_scale, - ALfloat depth, ALsizei delay, ALsizei todo) +void GetTriangleDelays(ALint *delays, const ALsizei start_offset, const ALsizei lfo_range, + const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, const ALsizei todo) { - std::generate_n(delays, todo, - [&offset,lfo_range,lfo_scale,depth,delay]() -> ALint - { - offset = (offset+1)%lfo_range; - return fastf2i((1.0f - std::abs(2.0f - lfo_scale*offset)) * depth) + delay; - } - ); + ASSUME(start_offset >= 0); + ASSUME(lfo_range > 0); + ASSUME(todo > 0); + + ALsizei offset{start_offset}; + auto gen_lfo = [&offset,lfo_range,lfo_scale,depth,delay]() -> ALint + { + offset = (offset+1)%lfo_range; + return fastf2i((1.0f - std::abs(2.0f - lfo_scale*offset)) * depth) + delay; + }; + std::generate_n(delays, todo, gen_lfo); } -void GetSinusoidDelays(ALint *delays, ALsizei offset, ALsizei lfo_range, ALfloat lfo_scale, - ALfloat depth, ALsizei delay, ALsizei todo) +void GetSinusoidDelays(ALint *delays, const ALsizei start_offset, const ALsizei lfo_range, + const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, const ALsizei todo) { - std::generate_n(delays, todo, - [&offset,lfo_range,lfo_scale,depth,delay]() -> ALint - { - offset = (offset+1)%lfo_range; - return fastf2i(std::sin(lfo_scale*offset) * depth) + delay; - } - ); + ASSUME(start_offset >= 0); + ASSUME(lfo_range > 0); + ASSUME(todo > 0); + + ALsizei offset{start_offset}; + auto gen_lfo = [&offset,lfo_range,lfo_scale,depth,delay]() -> ALint + { + ASSUME(delay >= 0); + offset = (offset+1)%lfo_range; + return fastf2i(std::sin(lfo_scale*offset) * depth) + delay; + }; + std::generate_n(delays, todo, gen_lfo); } struct ChorusState final : public EffectState { diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 427326d0..45f63c11 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -280,8 +280,7 @@ void GetHrtfCoeffs(const HrtfEntry *Hrtf, ALfloat elevation, ALfloat azimuth, AL const ALfloat mult{blend[c]}; auto blend_coeffs = [mult](const ALfloat src, const ALfloat coeff) noexcept -> ALfloat { return src*mult + coeff; }; - std::transform(srccoeffs, srccoeffs + irSize*2, coeffout, - coeffout, blend_coeffs); + std::transform(srccoeffs, srccoeffs + irSize*2, coeffout, coeffout, blend_coeffs); } } diff --git a/Alc/mastering.cpp b/Alc/mastering.cpp index c71b3cc9..23386cf4 100644 --- a/Alc/mastering.cpp +++ b/Alc/mastering.cpp @@ -464,11 +464,7 @@ void Compressor::process(const ALsizei SamplesToDo, ALfloat (*OutBuffer)[BUFFERS { ALfloat *buffer{al::assume_aligned<16>(input)}; const ALfloat *gains{al::assume_aligned<16>(&sideChain[0])}; - /* Mark the gains "input-1 type" as restrict, so the compiler can - * vectorize this loop (otherwise it assumes a write to buffer[n] can - * change gains[n+1]). - */ - std::transform(gains, gains+SamplesToDo, buffer, buffer, + std::transform(gains, gains+SamplesToDo, buffer, buffer, std::bind(std::multiplies{}, _1, _2)); }; std::for_each(OutBuffer, OutBuffer+numChans, apply_comp); diff --git a/Alc/mixer/mixer_c.cpp b/Alc/mixer/mixer_c.cpp index 1c22115d..6ee5df88 100644 --- a/Alc/mixer/mixer_c.cpp +++ b/Alc/mixer/mixer_c.cpp @@ -12,13 +12,15 @@ #include "hrtfbase.h" -static inline ALfloat do_point(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei) noexcept +namespace { + +inline ALfloat do_point(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei) noexcept { return vals[0]; } -static inline ALfloat do_lerp(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei frac) noexcept +inline ALfloat do_lerp(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei frac) noexcept { return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); } -static inline ALfloat do_cubic(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei frac) noexcept +inline ALfloat do_cubic(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei frac) noexcept { return cubic(vals[0], vals[1], vals[2], vals[3], frac * (1.0f/FRACTIONONE)); } -static inline ALfloat do_bsinc(const InterpState &istate, const ALfloat *RESTRICT vals, const ALsizei frac) noexcept +inline ALfloat do_bsinc(const InterpState &istate, const ALfloat *RESTRICT vals, const ALsizei frac) noexcept { ASSUME(istate.bsinc.m > 0); @@ -42,9 +44,8 @@ static inline ALfloat do_bsinc(const InterpState &istate, const ALfloat *RESTRIC using SamplerT = ALfloat(const InterpState&, const ALfloat*RESTRICT, const ALsizei); template -static const ALfloat *DoResample(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, - ALsizei numsamples) +const ALfloat *DoResample(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei numsamples) { ASSUME(numsamples > 0); ASSUME(increment > 0); @@ -61,11 +62,12 @@ static const ALfloat *DoResample(const InterpState *state, const ALfloat *RESTRI return ret; }; - std::generate_n(dst, numsamples, proc_sample); + std::generate_n(dst, numsamples, proc_sample); return dst; } +} // namespace template<> const ALfloat *Resample_(const InterpState* UNUSED(state), -- cgit v1.2.3 From 5b5dee07b43808907fba0d2dff5a00ea9069048b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 25 May 2019 11:36:13 -0700 Subject: Remove a couple unused functions --- Alc/filters/biquad.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Alc/filters/biquad.h b/Alc/filters/biquad.h index 57edd782..5d51945e 100644 --- a/Alc/filters/biquad.h +++ b/Alc/filters/biquad.h @@ -113,9 +113,6 @@ using BiquadFilter = BiquadFilterR; inline float calc_rcpQ_from_slope(float gain, float slope) { return std::sqrt((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f); } -inline double calc_rcpQ_from_slope(double gain, double slope) -{ return std::sqrt((gain + 1.0/gain)*(1.0/slope - 1.0) + 2.0); } - /** * Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the normalized * reference frequency and bandwidth. @@ -128,10 +125,4 @@ inline float calc_rcpQ_from_bandwidth(float f0norm, float bandwidth) return 2.0f*std::sinh(std::log(2.0f)/2.0f*bandwidth*w0/std::sin(w0)); } -inline double calc_rcpQ_from_bandwidth(double f0norm, double bandwidth) -{ - const double w0{al::MathDefs::Tau() * f0norm}; - return 2.0*std::sinh(std::log(2.0)/2.0*bandwidth*w0/std::sin(w0)); -} - #endif /* FILTERS_BIQUAD_H */ -- cgit v1.2.3 From 8ca97a7d9a336b9de7a1d1dc400279e8de76d65e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 25 May 2019 11:54:51 -0700 Subject: Move a couple functions into its related class --- Alc/alu.cpp | 12 ++++-------- Alc/effects/distortion.cpp | 6 ++---- Alc/effects/echo.cpp | 2 +- Alc/effects/equalizer.cpp | 8 ++++---- Alc/effects/modulator.cpp | 2 +- Alc/effects/reverb.cpp | 8 ++++---- Alc/filters/biquad.h | 46 +++++++++++++++++++++++----------------------- 7 files changed, 39 insertions(+), 45 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 2bdfd092..94ba3aa8 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -933,11 +933,9 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo if(gainHF != 1.0f) voice->mDirect.FilterType |= AF_LowPass; if(gainLF != 1.0f) voice->mDirect.FilterType |= AF_HighPass; voice->mDirect.Params[0].LowPass.setParams(BiquadType::HighShelf, - gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) - ); + gainHF, hfScale, BiquadFilter::rcpQFromSlope(gainHF, 1.0f)); voice->mDirect.Params[0].HighPass.setParams(BiquadType::LowShelf, - gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) - ); + gainLF, lfScale, BiquadFilter::rcpQFromSlope(gainLF, 1.0f)); for(ALsizei c{1};c < num_channels;c++) { voice->mDirect.Params[c].LowPass.copyParamsFrom(voice->mDirect.Params[0].LowPass); @@ -955,11 +953,9 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo if(gainHF != 1.0f) voice->mSend[i].FilterType |= AF_LowPass; if(gainLF != 1.0f) voice->mSend[i].FilterType |= AF_HighPass; voice->mSend[i].Params[0].LowPass.setParams(BiquadType::HighShelf, - gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) - ); + gainHF, hfScale, BiquadFilter::rcpQFromSlope(gainHF, 1.0f)); voice->mSend[i].Params[0].HighPass.setParams(BiquadType::LowShelf, - gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) - ); + gainLF, lfScale, BiquadFilter::rcpQFromSlope(gainLF, 1.0f)); for(ALsizei c{1};c < num_channels;c++) { voice->mSend[i].Params[c].LowPass.copyParamsFrom(voice->mSend[i].Params[0].LowPass); diff --git a/Alc/effects/distortion.cpp b/Alc/effects/distortion.cpp index d2bcd018..7ef77c69 100644 --- a/Alc/effects/distortion.cpp +++ b/Alc/effects/distortion.cpp @@ -79,15 +79,13 @@ void DistortionState::update(const ALCcontext *context, const ALeffectslot *slot */ auto frequency = static_cast(device->Frequency); mLowpass.setParams(BiquadType::LowPass, 1.0f, cutoff / (frequency*4.0f), - calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) - ); + mLowpass.rcpQFromBandwidth(cutoff / (frequency*4.0f), bandwidth)); cutoff = props->Distortion.EQCenter; /* Convert bandwidth in Hz to octaves. */ bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f); mBandpass.setParams(BiquadType::BandPass, 1.0f, cutoff / (frequency*4.0f), - calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) - ); + mBandpass.rcpQFromBandwidth(cutoff / (frequency*4.0f), bandwidth)); ALfloat coeffs[MAX_AMBI_CHANNELS]; CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index 9cd6fb87..158ab856 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -102,7 +102,7 @@ void EchoState::update(const ALCcontext *context, const ALeffectslot *slot, cons const ALfloat gainhf{maxf(1.0f - props->Echo.Damping, 0.0625f)}; /* Limit -24dB */ mFilter.setParams(BiquadType::HighShelf, gainhf, LOWPASSFREQREF/frequency, - calc_rcpQ_from_slope(gainhf, 1.0f)); + mFilter.rcpQFromSlope(gainhf, 1.0f)); mFeedGain = props->Echo.Feedback; diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index e1524943..cc701e8d 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -123,22 +123,22 @@ void EqualizerState::update(const ALCcontext *context, const ALeffectslot *slot, gain = maxf(sqrtf(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */ f0norm = props->Equalizer.LowCutoff/frequency; mChans[0].filter[0].setParams(BiquadType::LowShelf, gain, f0norm, - calc_rcpQ_from_slope(gain, 0.75f)); + BiquadFilter::rcpQFromSlope(gain, 0.75f)); gain = maxf(props->Equalizer.Mid1Gain, 0.0625f); f0norm = props->Equalizer.Mid1Center/frequency; mChans[0].filter[1].setParams(BiquadType::Peaking, gain, f0norm, - calc_rcpQ_from_bandwidth(f0norm, props->Equalizer.Mid1Width)); + BiquadFilter::rcpQFromBandwidth(f0norm, props->Equalizer.Mid1Width)); gain = maxf(props->Equalizer.Mid2Gain, 0.0625f); f0norm = props->Equalizer.Mid2Center/frequency; mChans[0].filter[2].setParams(BiquadType::Peaking, gain, f0norm, - calc_rcpQ_from_bandwidth(f0norm, props->Equalizer.Mid2Width)); + BiquadFilter::rcpQFromBandwidth(f0norm, props->Equalizer.Mid2Width)); gain = maxf(sqrtf(props->Equalizer.HighGain), 0.0625f); f0norm = props->Equalizer.HighCutoff/frequency; mChans[0].filter[3].setParams(BiquadType::HighShelf, gain, f0norm, - calc_rcpQ_from_slope(gain, 0.75f)); + BiquadFilter::rcpQFromSlope(gain, 0.75f)); /* Copy the filter coefficients for the other input channels. */ for(ALsizei i{1};i < slot->Wet.NumChannels;++i) diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index 0ddd0510..f926cb87 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -128,7 +128,7 @@ void ModulatorState::update(const ALCcontext *context, const ALeffectslot *slot, f0norm = clampf(f0norm, 1.0f/512.0f, 0.49f); /* Bandwidth value is constant in octaves. */ mChans[0].Filter.setParams(BiquadType::HighPass, 1.0f, f0norm, - calc_rcpQ_from_bandwidth(f0norm, 0.75f)); + BiquadFilter::rcpQFromBandwidth(f0norm, 0.75f)); for(ALsizei i{1};i < slot->Wet.NumChannels;++i) mChans[i].Filter.copyParamsFrom(mChans[0].Filter); diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 6b159b0c..3c39199d 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -705,9 +705,9 @@ void T60Filter::calcCoeffs(const ALfloat length, const ALfloat lfDecayTime, MidGain[1] = mfGain; LFFilter.setParams(BiquadType::LowShelf, lfGain/mfGain, lf0norm, - calc_rcpQ_from_slope(lfGain/mfGain, 1.0f)); + LFFilter.rcpQFromSlope(lfGain/mfGain, 1.0f)); HFFilter.setParams(BiquadType::HighShelf, hfGain/mfGain, hf0norm, - calc_rcpQ_from_slope(hfGain/mfGain, 1.0f)); + HFFilter.rcpQFromSlope(hfGain/mfGain, 1.0f)); } /* Update the early reflection line lengths and gain coefficients. */ @@ -916,11 +916,11 @@ void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, co */ ALfloat gainhf{maxf(props->Reverb.GainHF, 0.001f)}; mFilter[0].Lp.setParams(BiquadType::HighShelf, gainhf, hf0norm, - calc_rcpQ_from_slope(gainhf, 1.0f)); + mFilter[0].Lp.rcpQFromSlope(gainhf, 1.0f)); ALfloat lf0norm{minf(props->Reverb.LFReference / frequency, 0.49f)}; ALfloat gainlf{maxf(props->Reverb.GainLF, 0.001f)}; mFilter[0].Hp.setParams(BiquadType::LowShelf, gainlf, lf0norm, - calc_rcpQ_from_slope(gainlf, 1.0f)); + mFilter[0].Hp.rcpQFromSlope(gainlf, 1.0f)); for(ALsizei i{1};i < NUM_LINES;i++) { mFilter[i].Lp.copyParamsFrom(mFilter[0].Lp); diff --git a/Alc/filters/biquad.h b/Alc/filters/biquad.h index 5d51945e..96bf3407 100644 --- a/Alc/filters/biquad.h +++ b/Alc/filters/biquad.h @@ -57,8 +57,8 @@ public: * BandPass filter types, or the cutoff frequency for the * LowPass and HighPass filter types. * \param rcpQ The reciprocal of the Q coefficient for the filter's - * transition band. Can be generated from calc_rcpQ_from_slope - * or calc_rcpQ_from_bandwidth as needed. + * transition band. Can be generated from rcpQFromSlope or + * rcpQFromBandwidth as needed. */ void setParams(BiquadType type, Real gain, Real f0norm, Real rcpQ); @@ -100,29 +100,29 @@ public: z2_ = in*b2 - out*a2; return out; } + + /** + * Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using + * the reference gain and shelf slope parameter. + * \param gain 0 < gain + * \param slope 0 < slope <= 1 + */ + static Real rcpQFromSlope(Real gain, Real slope) + { return std::sqrt((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f); } + + /** + * Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the + * normalized reference frequency and bandwidth. + * \param f0norm 0 < f0norm < 0.5. + * \param bandwidth 0 < bandwidth + */ + static Real rcpQFromBandwidth(Real f0norm, Real bandwidth) + { + const Real w0{al::MathDefs::Tau() * f0norm}; + return 2.0f*std::sinh(std::log(Real{2.0f})/2.0f*bandwidth*w0/std::sin(w0)); + } }; using BiquadFilter = BiquadFilterR; -/** - * Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the - * reference gain and shelf slope parameter. - * \param gain 0 < gain - * \param slope 0 < slope <= 1 - */ -inline float calc_rcpQ_from_slope(float gain, float slope) -{ return std::sqrt((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f); } - -/** - * Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the normalized - * reference frequency and bandwidth. - * \param f0norm 0 < f0norm < 0.5. - * \param bandwidth 0 < bandwidth - */ -inline float calc_rcpQ_from_bandwidth(float f0norm, float bandwidth) -{ - const float w0{al::MathDefs::Tau() * f0norm}; - return 2.0f*std::sinh(std::log(2.0f)/2.0f*bandwidth*w0/std::sin(w0)); -} - #endif /* FILTERS_BIQUAD_H */ -- cgit v1.2.3 From 7cbf82afe4999addde6630fda2cc91614a264772 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 26 May 2019 11:34:17 -0700 Subject: Avoid a few more NUM_LINES assumptions --- Alc/effects/reverb.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 3c39199d..51d2d3a8 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -512,7 +512,7 @@ bool ReverbState::allocLines(const ALfloat frequency) */ ALfloat length{AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS.back()*multiplier + AL_EAXREVERB_MAX_LATE_REVERB_DELAY + - (LATE_LINE_LENGTHS.back() - LATE_LINE_LENGTHS.front())*0.25f*multiplier}; + (LATE_LINE_LENGTHS.back() - LATE_LINE_LENGTHS.front())/float{LATE_LINE_LENGTHS.size()}*multiplier}; totalSamples += CalcLineLength(length, totalSamples, frequency, BUFFERSIZE, &mDelay); /* The early vector all-pass line. */ @@ -750,7 +750,7 @@ void LateReverb::updateLines(const ALfloat density, const ALfloat diffusion, const ALfloat late_allpass_avg{ std::accumulate(LATE_ALLPASS_LENGTHS.begin(), LATE_ALLPASS_LENGTHS.end(), 0.0f) / - static_cast(LATE_ALLPASS_LENGTHS.size())}; + float{LATE_ALLPASS_LENGTHS.size()}}; /* To compensate for changes in modal density and decay time of the late * reverb signal, the input is attenuated based on the maximal energy of @@ -762,7 +762,7 @@ void LateReverb::updateLines(const ALfloat density, const ALfloat diffusion, */ const ALfloat multiplier{CalcDelayLengthMult(density)}; ALfloat length{std::accumulate(LATE_LINE_LENGTHS.begin(), LATE_LINE_LENGTHS.end(), 0.0f) / - static_cast(LATE_LINE_LENGTHS.size()) * multiplier}; + float{LATE_LINE_LENGTHS.size()} * multiplier}; length += late_allpass_avg * multiplier; /* The density gain calculation uses an average decay time weighted by * approximate bandwidth. This attempts to compensate for losses of energy @@ -831,7 +831,8 @@ void ReverbState::updateDelayLine(const ALfloat earlyDelay, const ALfloat lateDe length = EARLY_TAP_LENGTHS[i]*multiplier; mEarlyDelayCoeff[i][1] = CalcDecayCoeff(length, decayTime); - length = lateDelay + (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS.front())*0.25f*multiplier; + length = lateDelay + (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS.front()) / + float{LATE_LINE_LENGTHS.size()} * multiplier; mLateDelayTap[i][1] = mLateFeedTap + float2int(length * frequency); } } @@ -1045,12 +1046,10 @@ inline void VectorPartialScatter(ALfloat *RESTRICT out, const ALfloat *RESTRICT } /* Utilizes the above, but reverses the input channels. */ -inline void VectorScatterRevDelayIn(const DelayLineI *Delay, ALint offset, - const ALfloat xCoeff, const ALfloat yCoeff, const ALsizei base, - const ALfloat (*RESTRICT in)[BUFFERSIZE], const ALsizei count) +void VectorScatterRevDelayIn(const DelayLineI delay, ALint offset, const ALfloat xCoeff, + const ALfloat yCoeff, const ALsizei base, const ALfloat (*RESTRICT in)[BUFFERSIZE], + const ALsizei count) { - const DelayLineI delay{*Delay}; - ASSUME(base >= 0); ASSUME(count > 0); @@ -1247,7 +1246,7 @@ void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALs * bounce to improve the initial diffusion in the late reverb. */ const ALsizei late_feed_tap{offset - State->mLateFeedTap}; - VectorScatterRevDelayIn(&main_delay, late_feed_tap, mixX, mixY, base, out, todo); + VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, out, todo); } void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, const ALfloat fade, const ALsizei base, ALfloat (*RESTRICT out)[BUFFERSIZE]) @@ -1318,7 +1317,7 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz early_delay.write(offset, NUM_LINES-1-j, temps[j], todo); const ALsizei late_feed_tap{offset - State->mLateFeedTap}; - VectorScatterRevDelayIn(&main_delay, late_feed_tap, mixX, mixY, base, out, todo); + VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, out, todo); } /* This generates the reverb tail using a modified feed-back delay network @@ -1380,7 +1379,7 @@ void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei std::copy_n(temps[j], todo, out[j]+base); /* Finally, scatter and bounce the results to refeed the feedback buffer. */ - VectorScatterRevDelayIn(&late_delay, offset, mixX, mixY, base, out, todo); + VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, out, todo); } void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, const ALfloat fade, const ALsizei base, ALfloat (*RESTRICT out)[BUFFERSIZE]) @@ -1440,7 +1439,7 @@ void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei to for(ALsizei j{0};j < NUM_LINES;j++) std::copy_n(temps[j], todo, out[j]+base); - VectorScatterRevDelayIn(&late_delay, offset, mixX, mixY, base, out, todo); + VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, out, todo); } void ReverbState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) -- cgit v1.2.3 From 63a130204c829c5c81631cfa8c579d78048fdb6e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 26 May 2019 12:05:43 -0700 Subject: Add a few more methods to the span class --- common/alspan.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/common/alspan.h b/common/alspan.h index 0c15b93c..98da1a44 100644 --- a/common/alspan.h +++ b/common/alspan.h @@ -97,6 +97,17 @@ public: constexpr const_reverse_iterator crbegin() const noexcept { return cend(); } constexpr const_reverse_iterator crend() const noexcept { return cbegin(); } + constexpr span first(size_t count) const + { return (count >= size()) ? *this : span{mData, mData+count}; } + constexpr span last(size_t count) const + { return (count >= size()) ? *this : span{mDataEnd-count, mDataEnd}; } + constexpr span subspan(size_t offset, size_t count=static_cast(-1)) const + { + return (offset >= size()) ? span{} : + (count >= size()-offset) ? last(count) : + span{mData+offset, mData+offset+count}; + } + private: pointer mData{nullptr}; pointer mDataEnd{nullptr}; -- cgit v1.2.3 From 20e3c78aef6b745d656fa1a28f4a95c98aac6928 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 26 May 2019 12:54:54 -0700 Subject: Use al::byte instead of char for generic data storage --- Alc/ringbuffer.cpp | 20 ++++++++++---------- Alc/ringbuffer.h | 5 +++-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Alc/ringbuffer.cpp b/Alc/ringbuffer.cpp index 7f0aa630..ddfeab42 100644 --- a/Alc/ringbuffer.cpp +++ b/Alc/ringbuffer.cpp @@ -63,7 +63,7 @@ void RingBuffer::reset() noexcept { mWritePtr.store(0, std::memory_order_relaxed); mReadPtr.store(0, std::memory_order_relaxed); - std::fill_n(mBuffer, (mSizeMask+1)*mElemSize, 0); + std::fill_n(mBuffer, (mSizeMask+1)*mElemSize, al::byte{}); } @@ -107,7 +107,7 @@ size_t RingBuffer::read(void *dest, size_t cnt) noexcept read_ptr += n1; if(n2 > 0) { - memcpy(static_cast(dest) + n1*mElemSize, mBuffer, n2*mElemSize); + memcpy(static_cast(dest) + n1*mElemSize, mBuffer, n2*mElemSize); read_ptr += n2; } mReadPtr.store(read_ptr, std::memory_order_release); @@ -137,7 +137,7 @@ size_t RingBuffer::peek(void *dest, size_t cnt) const noexcept memcpy(dest, mBuffer + read_ptr*mElemSize, n1*mElemSize); if(n2 > 0) - memcpy(static_cast(dest) + n1*mElemSize, mBuffer, n2*mElemSize); + memcpy(static_cast(dest) + n1*mElemSize, mBuffer, n2*mElemSize); return to_read; } @@ -166,7 +166,7 @@ size_t RingBuffer::write(const void *src, size_t cnt) noexcept write_ptr += n1; if(n2 > 0) { - memcpy(mBuffer, static_cast(src) + n1*mElemSize, n2*mElemSize); + memcpy(mBuffer, static_cast(src) + n1*mElemSize, n2*mElemSize); write_ptr += n2; } mWritePtr.store(write_ptr, std::memory_order_release); @@ -200,15 +200,15 @@ ll_ringbuffer_data_pair RingBuffer::getReadVector() const noexcept { /* Two part vector: the rest of the buffer after the current read ptr, * plus some from the start of the buffer. */ - ret.first.buf = const_cast(&mBuffer[r*mElemSize]); + ret.first.buf = const_cast(&mBuffer[r*mElemSize]); ret.first.len = mSizeMask+1 - r; - ret.second.buf = const_cast(mBuffer); + ret.second.buf = const_cast(mBuffer); ret.second.len = cnt2 & mSizeMask; } else { /* Single part vector: just the rest of the buffer */ - ret.first.buf = const_cast(&mBuffer[r*mElemSize]); + ret.first.buf = const_cast(&mBuffer[r*mElemSize]); ret.first.len = free_cnt; ret.second.buf = nullptr; ret.second.len = 0; @@ -232,14 +232,14 @@ ll_ringbuffer_data_pair RingBuffer::getWriteVector() const noexcept { /* Two part vector: the rest of the buffer after the current write ptr, * plus some from the start of the buffer. */ - ret.first.buf = const_cast(&mBuffer[w*mElemSize]); + ret.first.buf = const_cast(&mBuffer[w*mElemSize]); ret.first.len = mSizeMask+1 - w; - ret.second.buf = const_cast(mBuffer); + ret.second.buf = const_cast(mBuffer); ret.second.len = cnt2 & mSizeMask; } else { - ret.first.buf = const_cast(&mBuffer[w*mElemSize]); + ret.first.buf = const_cast(&mBuffer[w*mElemSize]); ret.first.len = free_cnt; ret.second.buf = nullptr; ret.second.len = 0; diff --git a/Alc/ringbuffer.h b/Alc/ringbuffer.h index 311477c9..6554f95a 100644 --- a/Alc/ringbuffer.h +++ b/Alc/ringbuffer.h @@ -7,6 +7,7 @@ #include #include +#include "albyte.h" #include "almalloc.h" @@ -17,7 +18,7 @@ */ struct ll_ringbuffer_data { - char *buf; + al::byte *buf; size_t len; }; using ll_ringbuffer_data_pair = std::pair; @@ -30,7 +31,7 @@ struct RingBuffer { size_t mSizeMask{0u}; size_t mElemSize{0u}; - alignas(16) char mBuffer[]; + alignas(16) al::byte mBuffer[]; /** Reset the read and write pointers to zero. This is not thread safe. */ void reset() noexcept; -- cgit v1.2.3 From 01f717ae59f6fa34cbc6b28af58beb7b68d2b500 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 26 May 2019 14:45:53 -0700 Subject: Use SL_ANDROID_DATAFORMAT_PCM_EX for extended PCM info --- Alc/backends/opensl.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 818b381b..2072f99c 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -80,7 +80,7 @@ SLuint32 GetChannelMask(DevFmtChannels chans) return 0; } -#ifdef SL_DATAFORMAT_PCM_EX +#ifdef SL_ANDROID_DATAFORMAT_PCM_EX SLuint32 GetTypeRepresentation(DevFmtType type) { switch(type) @@ -88,13 +88,13 @@ SLuint32 GetTypeRepresentation(DevFmtType type) case DevFmtUByte: case DevFmtUShort: case DevFmtUInt: - return SL_PCM_REPRESENTATION_UNSIGNED_INT; + return SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT; case DevFmtByte: case DevFmtShort: case DevFmtInt: - return SL_PCM_REPRESENTATION_SIGNED_INT; + return SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT; case DevFmtFloat: - return SL_PCM_REPRESENTATION_FLOAT; + return SL_ANDROID_PCM_REPRESENTATION_FLOAT; } return 0; } @@ -440,9 +440,9 @@ ALCboolean OpenSLPlayback::reset() loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; loc_bufq.numBuffers = mDevice->BufferSize / mDevice->UpdateSize; -#ifdef SL_DATAFORMAT_PCM_EX - SLDataFormat_PCM_EX format_pcm; - format_pcm.formatType = SL_DATAFORMAT_PCM_EX; +#ifdef SL_ANDROID_DATAFORMAT_PCM_EX + SLAndroidDataFormat_PCM_EX format_pcm{}; + format_pcm.formatType = SL_ANDROID_DATAFORMAT_PCM_EX; format_pcm.numChannels = mDevice->channelsFromFmt(); format_pcm.sampleRate = mDevice->Frequency * 1000; format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; @@ -452,7 +452,7 @@ ALCboolean OpenSLPlayback::reset() SL_BYTEORDER_BIGENDIAN; format_pcm.representation = GetTypeRepresentation(mDevice->FmtType); #else - SLDataFormat_PCM format_pcm; + SLDataFormat_PCM format_pcm{}; format_pcm.formatType = SL_DATAFORMAT_PCM; format_pcm.numChannels = mDevice->channelsFromFmt(); format_pcm.samplesPerSec = mDevice->Frequency * 1000; @@ -721,9 +721,9 @@ ALCenum OpenSLCapture::open(const ALCchar* name) loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; loc_bq.numBuffers = mDevice->BufferSize / mDevice->UpdateSize; -#ifdef SL_DATAFORMAT_PCM_EX - SLDataFormat_PCM_EX format_pcm{}; - format_pcm.formatType = SL_DATAFORMAT_PCM_EX; +#ifdef SL_ANDROID_DATAFORMAT_PCM_EX + SLAndroidDataFormat_PCM_EX format_pcm{}; + format_pcm.formatType = SL_ANDROID_DATAFORMAT_PCM_EX; format_pcm.numChannels = mDevice->channelsFromFmt(); format_pcm.sampleRate = mDevice->Frequency * 1000; format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; -- cgit v1.2.3 From b0e12ccf711203484c85bb9052818bd00e15e415 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 26 May 2019 15:57:17 -0700 Subject: Ensure a couple calls are constexpr --- Alc/effects/reverb.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 51d2d3a8..d65a642d 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -197,6 +197,7 @@ constexpr std::array EARLY_LINE_LENGTHS{{ constexpr std::array LATE_ALLPASS_LENGTHS{{ 1.6182800e-4f, 2.0389060e-4f, 2.8159360e-4f, 3.2365600e-4f }}; +constexpr auto LATE_ALLPASS_LENGTHS_size = LATE_ALLPASS_LENGTHS.size(); /* The late lines are used to approximate the decaying cycle of recursive * late reflections. @@ -216,6 +217,7 @@ constexpr std::array LATE_ALLPASS_LENGTHS{{ constexpr std::array LATE_LINE_LENGTHS{{ 1.9419362e-3f, 2.4466860e-3f, 3.3791220e-3f, 3.8838720e-3f }}; +constexpr auto LATE_LINE_LENGTHS_size = LATE_LINE_LENGTHS.size(); struct DelayLineI { @@ -512,7 +514,7 @@ bool ReverbState::allocLines(const ALfloat frequency) */ ALfloat length{AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS.back()*multiplier + AL_EAXREVERB_MAX_LATE_REVERB_DELAY + - (LATE_LINE_LENGTHS.back() - LATE_LINE_LENGTHS.front())/float{LATE_LINE_LENGTHS.size()}*multiplier}; + (LATE_LINE_LENGTHS.back() - LATE_LINE_LENGTHS.front())/float{LATE_LINE_LENGTHS_size}*multiplier}; totalSamples += CalcLineLength(length, totalSamples, frequency, BUFFERSIZE, &mDelay); /* The early vector all-pass line. */ @@ -750,7 +752,7 @@ void LateReverb::updateLines(const ALfloat density, const ALfloat diffusion, const ALfloat late_allpass_avg{ std::accumulate(LATE_ALLPASS_LENGTHS.begin(), LATE_ALLPASS_LENGTHS.end(), 0.0f) / - float{LATE_ALLPASS_LENGTHS.size()}}; + float{LATE_ALLPASS_LENGTHS_size}}; /* To compensate for changes in modal density and decay time of the late * reverb signal, the input is attenuated based on the maximal energy of @@ -762,7 +764,7 @@ void LateReverb::updateLines(const ALfloat density, const ALfloat diffusion, */ const ALfloat multiplier{CalcDelayLengthMult(density)}; ALfloat length{std::accumulate(LATE_LINE_LENGTHS.begin(), LATE_LINE_LENGTHS.end(), 0.0f) / - float{LATE_LINE_LENGTHS.size()} * multiplier}; + float{LATE_LINE_LENGTHS_size} * multiplier}; length += late_allpass_avg * multiplier; /* The density gain calculation uses an average decay time weighted by * approximate bandwidth. This attempts to compensate for losses of energy @@ -832,7 +834,7 @@ void ReverbState::updateDelayLine(const ALfloat earlyDelay, const ALfloat lateDe mEarlyDelayCoeff[i][1] = CalcDecayCoeff(length, decayTime); length = lateDelay + (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS.front()) / - float{LATE_LINE_LENGTHS.size()} * multiplier; + float{LATE_LINE_LENGTHS_size} * multiplier; mLateDelayTap[i][1] = mLateFeedTap + float2int(length * frequency); } } -- cgit v1.2.3 From 3007fbf5e52145f002d15f3c8ff4943d992cea98 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 26 May 2019 19:41:11 -0700 Subject: Use a span for loading source samples --- Alc/mixvoice.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index e1d2c6a0..284621ab 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -42,10 +42,11 @@ #include "alu.h" #include "alconfig.h" #include "ringbuffer.h" - #include "cpu_caps.h" #include "mixer/defs.h" +#include "alspan.h" + static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!"); @@ -600,7 +601,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc /* +1 to get the src sample count, include padding. */ DataSize64 += 1 + MAX_RESAMPLE_PADDING*2; - auto SrcBufferSize = static_cast( + auto SrcBufferSize = static_cast( mini64(DataSize64, BUFFERSIZE + MAX_RESAMPLE_PADDING*2 + 1)); if(SrcBufferSize > BUFFERSIZE + MAX_RESAMPLE_PADDING*2) { @@ -622,26 +623,25 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc for(ALsizei chan{0};chan < NumChannels;chan++) { - auto &SrcData = Device->SourceData; + const al::span SrcData{Device->SourceData, SrcBufferSize}; /* Load the previous samples into the source data first, and clear the rest. */ auto srciter = std::copy_n(voice->mResampleData[chan].mPrevSamples.begin(), - MAX_RESAMPLE_PADDING, std::begin(SrcData)); - std::fill(srciter, std::end(SrcData), 0.0f); + MAX_RESAMPLE_PADDING, SrcData.begin()); + std::fill(srciter, SrcData.end(), 0.0f); - auto srcdata_end = std::begin(SrcData) + SrcBufferSize; if(UNLIKELY(!BufferListItem)) srciter = std::copy( voice->mResampleData[chan].mPrevSamples.begin()+MAX_RESAMPLE_PADDING, voice->mResampleData[chan].mPrevSamples.end(), srciter); else if(isstatic) srciter = LoadBufferStatic(BufferListItem, BufferLoopItem, NumChannels, - SampleSize, chan, DataPosInt, srciter, srcdata_end); + SampleSize, chan, DataPosInt, srciter, SrcData.end()); else srciter = LoadBufferQueue(BufferListItem, BufferLoopItem, NumChannels, - SampleSize, chan, DataPosInt, srciter, srcdata_end); + SampleSize, chan, DataPosInt, srciter, SrcData.end()); - if(UNLIKELY(srciter != srcdata_end)) + if(UNLIKELY(srciter != SrcData.end())) { /* If the source buffer wasn't filled, copy the last sample for * the remaining buffer. Ideally it should have ended with @@ -649,7 +649,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc * from sudden amplitude changes. */ const ALfloat sample{*(srciter-1)}; - std::fill(srciter, srcdata_end, sample); + std::fill(srciter, SrcData.end(), sample); } /* Store the last source samples used for next time. */ @@ -665,9 +665,9 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc { const ALfloat hfscale{voice->mResampleData[chan].mAmbiScale}; /* Beware the evil const_cast. It's safe since it's pointing to - * either SrcData or Device->ResampledData (both non-const), - * but the resample method takes its input as const float* and - * may return it without copying to output, making it currently + * either SourceData or ResampledData (both non-const), but the + * resample method takes the source as const float* and may + * return it without copying to output, making it currently * unavoidable. */ voice->mResampleData[chan].mAmbiSplitter.applyHfScale( -- cgit v1.2.3 From f6f220025bd9674a33d896258b315c006cfd78f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 26 May 2019 21:00:17 -0700 Subject: Fix subspan --- common/alspan.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/alspan.h b/common/alspan.h index 98da1a44..12254812 100644 --- a/common/alspan.h +++ b/common/alspan.h @@ -104,7 +104,7 @@ public: constexpr span subspan(size_t offset, size_t count=static_cast(-1)) const { return (offset >= size()) ? span{} : - (count >= size()-offset) ? last(count) : + (count >= size()-offset) ? span{mData+offset, mDataEnd} : span{mData+offset, mData+offset+count}; } -- cgit v1.2.3 From f57fedec7f8878230fb77be1d91d7c056f7e6de4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 26 May 2019 21:28:51 -0700 Subject: Get rid of the COUNTOF macro --- Alc/alc.cpp | 17 ++++++++--------- Alc/backends/opensl.cpp | 21 +++++++++------------ OpenAL32/Include/alMain.h | 6 ------ OpenAL32/alEffect.cpp | 24 ++++++++++++++---------- OpenAL32/alState.cpp | 5 +++-- 5 files changed, 34 insertions(+), 39 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 8a340b18..eb6269ec 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1151,11 +1151,11 @@ static void alc_initconfig(void) continue; size_t len{next ? static_cast(next-str) : strlen(str)}; - for(size_t n{0u};n < countof(gEffectList);n++) + for(const EffectList &effectitem : gEffectList) { - if(len == strlen(gEffectList[n].name) && - strncmp(gEffectList[n].name, str, len) == 0) - DisabledEffects[gEffectList[n].type] = AL_TRUE; + if(len == strlen(effectitem.name) && + strncmp(effectitem.name, str, len) == 0) + DisabledEffects[effectitem.type] = AL_TRUE; } } while(next++); } @@ -1280,14 +1280,13 @@ static ALboolean DecomposeDevFormat(ALenum format, DevFmtChannels *chans, DevFmt { AL_FORMAT_71CHN16, DevFmtX71, DevFmtShort }, { AL_FORMAT_71CHN32, DevFmtX71, DevFmtFloat }, }; - ALuint i; - for(i = 0;i < COUNTOF(list);i++) + for(const auto &item : list) { - if(list[i].format == format) + if(item.format == format) { - *chans = list[i].channels; - *type = list[i].type; + *chans = item.channels; + *type = item.type; return AL_TRUE; } } diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 2072f99c..1cf309f7 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -352,8 +353,6 @@ ALCboolean OpenSLPlayback::reset() SLDataLocator_OutputMix loc_outmix; SLDataSource audioSrc; SLDataSink audioSnk; - SLInterfaceID ids[2]; - SLboolean reqs[2]; SLresult result; if(mBufferQueueObj) @@ -437,6 +436,9 @@ ALCboolean OpenSLPlayback::reset() mFrameSize = mDevice->frameSizeFromFmt(); + const std::array ids{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }}; + const std::array reqs{{ SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }}; + loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; loc_bufq.numBuffers = mDevice->BufferSize / mDevice->UpdateSize; @@ -472,13 +474,8 @@ ALCboolean OpenSLPlayback::reset() audioSnk.pFormat = nullptr; - ids[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE; - reqs[0] = SL_BOOLEAN_TRUE; - ids[1] = SL_IID_ANDROIDCONFIGURATION; - reqs[1] = SL_BOOLEAN_FALSE; - - result = VCALL(mEngine,CreateAudioPlayer)(&mBufferQueueObj, &audioSrc, &audioSnk, COUNTOF(ids), - ids, reqs); + result = VCALL(mEngine,CreateAudioPlayer)(&mBufferQueueObj, &audioSrc, &audioSnk, ids.size(), + ids.data(), reqs.data()); PRINTERR(result, "engine->CreateAudioPlayer"); if(SL_RESULT_SUCCESS == result) { @@ -704,8 +701,8 @@ ALCenum OpenSLCapture::open(const ALCchar* name) } if(SL_RESULT_SUCCESS == result) { - const SLInterfaceID ids[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }; - const SLboolean reqs[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }; + const std::array ids{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }}; + const std::array reqs{{ SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }}; SLDataLocator_IODevice loc_dev{}; loc_dev.locatorType = SL_DATALOCATOR_IODEVICE; @@ -747,7 +744,7 @@ ALCenum OpenSLCapture::open(const ALCchar* name) audioSnk.pFormat = &format_pcm; result = VCALL(mEngine,CreateAudioRecorder)(&mRecordObj, &audioSrc, &audioSnk, - COUNTOF(ids), ids, reqs); + ids.size(), ids.data(), reqs.data()); PRINTERR(result, "engine->CreateAudioRecorder"); } if(SL_RESULT_SUCCESS == result) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index a8c7f3cd..7019a6d4 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -33,12 +33,6 @@ #include "hrtf.h" -template -constexpr inline size_t countof(const T(&)[N]) noexcept -{ return N; } -#define COUNTOF countof - - #ifndef UNUSED #if defined(__cplusplus) #define UNUSED(x) diff --git a/OpenAL32/alEffect.cpp b/OpenAL32/alEffect.cpp index 36a09442..51474af0 100644 --- a/OpenAL32/alEffect.cpp +++ b/OpenAL32/alEffect.cpp @@ -320,11 +320,17 @@ START_API_FUNC { if(param == AL_EFFECT_TYPE) { - ALboolean isOk = (value == AL_EFFECT_NULL); - for(size_t i{0u};!isOk && i < countof(gEffectList);i++) + ALboolean isOk{value == AL_EFFECT_NULL}; + if(!isOk) { - if(value == gEffectList[i].val && !DisabledEffects[gEffectList[i].type]) - isOk = AL_TRUE; + for(const EffectList &effectitem : gEffectList) + { + if(value == effectitem.val && !DisabledEffects[effectitem.type]) + { + isOk = AL_TRUE; + break; + } + } } if(isOk) @@ -669,8 +675,6 @@ static const struct { void LoadReverbPreset(const char *name, ALeffect *effect) { - size_t i; - if(strcasecmp(name, "NONE") == 0) { InitEffectParams(effect, AL_EFFECT_NULL); @@ -684,15 +688,15 @@ void LoadReverbPreset(const char *name, ALeffect *effect) InitEffectParams(effect, AL_EFFECT_REVERB); else InitEffectParams(effect, AL_EFFECT_NULL); - for(i = 0;i < COUNTOF(reverblist);i++) + for(const auto &reverbitem : reverblist) { const EFXEAXREVERBPROPERTIES *props; - if(strcasecmp(name, reverblist[i].name) != 0) + if(strcasecmp(name, reverbitem.name) != 0) continue; - TRACE("Loading reverb '%s'\n", reverblist[i].name); - props = &reverblist[i].props; + TRACE("Loading reverb '%s'\n", reverbitem.name); + props = &reverbitem.props; effect->Props.Reverb.Density = props->flDensity; effect->Props.Reverb.Diffusion = props->flDiffusion; effect->Props.Reverb.Gain = props->flGain; diff --git a/OpenAL32/alState.cpp b/OpenAL32/alState.cpp index 3f6a0388..0c447645 100644 --- a/OpenAL32/alState.cpp +++ b/OpenAL32/alState.cpp @@ -30,6 +30,7 @@ #include "alu.h" #include "alError.h" #include "alexcpt.h" +#include "alspan.h" #include "backends/base.h" @@ -788,7 +789,7 @@ START_API_FUNC alCubicResampler, alBSinc12Resampler, alBSinc24Resampler, }; - static_assert(COUNTOF(ResamplerNames) == ResamplerMax+1, "Incorrect ResamplerNames list"); + static_assert(al::size(ResamplerNames) == ResamplerMax+1, "Incorrect ResamplerNames list"); ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return nullptr; @@ -797,7 +798,7 @@ START_API_FUNC switch(pname) { case AL_RESAMPLER_NAME_SOFT: - if(index < 0 || static_cast(index) >= COUNTOF(ResamplerNames)) + if(index < 0 || static_cast(index) >= al::size(ResamplerNames)) alSetError(context.get(), AL_INVALID_VALUE, "Resampler name index %d out of range", index); else -- cgit v1.2.3 From aad49d666a68c893df2fe01d084b2f021ad402aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 27 May 2019 15:36:10 -0700 Subject: Implement static-sized spans, and handle overload requirements Note that span is specialized such that a static-sized span only has a single data member, making it a suitable replacement for Type (&arg)[Size] style variables/parameters. --- common/alspan.h | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 191 insertions(+), 6 deletions(-) diff --git a/common/alspan.h b/common/alspan.h index 12254812..e5a91686 100644 --- a/common/alspan.h +++ b/common/alspan.h @@ -43,8 +43,45 @@ constexpr const T* data(std::initializer_list list) noexcept { return list.begin(); } -template +template(-1)> +class span; + +namespace detail_ { + template + struct make_void { using type = void; }; + template + using void_t = typename make_void::type; + + template + struct is_span : std::false_type { }; + template + struct is_span> : std::true_type { }; + + template + struct is_std_array : std::false_type { }; + template + struct is_std_array> : std::true_type { }; + + template + struct has_size_and_data : std::false_type { }; + template + struct has_size_and_data())), decltype(al::data(std::declval()))>> + : std::true_type { }; +} // namespace detail_ + +#define REQUIRES(...) typename std::enable_if<(__VA_ARGS__),int>::type = 0 +#define IS_VALID_CONTAINER(C) \ + !detail_::is_span::type>::value && \ + !detail_::is_std_array::type>::value && \ + !std::is_array::type>::value && \ + detail_::has_size_and_data::type>::value && \ + std::is_convertible()))>::type(*)[],element_type(*)[]>::value + +template class span { + static constexpr size_t dynamic_extent{static_cast(-1)}; + public: using element_type = T; using value_type = typename std::remove_cv::type; @@ -61,22 +98,131 @@ public: using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; + static constexpr size_t extent{E}; + + template + constexpr span() noexcept { } + constexpr span(pointer ptr, index_type /*count*/) : mData{ptr} { } + constexpr span(pointer first, pointer /*last*/) : mData{first} { } + template + constexpr span(element_type (&arr)[N]) noexcept : span{al::data(arr), al::size(arr)} { } + template::value)> + constexpr span(std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } + template::value)> + constexpr span(const std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } + template + constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { } + template + constexpr span(const U &cont) : span{al::data(cont), al::size(cont)} { } + template::value)> + constexpr span(const span &span_) noexcept : span{al::data(span_), al::size(span_)} { } + constexpr span(const span&) noexcept = default; + + span& operator=(const span &rhs) noexcept = default; + template::value)> + span& operator=(const span &rhs) noexcept + { mData = rhs.data(); return *this; } + + constexpr reference front() const { return *mData; } + constexpr reference back() const { return *(mData+E-1); } + constexpr reference operator[](index_type idx) const { return mData[idx]; } + constexpr pointer data() const noexcept { return mData; } + + constexpr index_type size() const noexcept { return E; } + constexpr index_type size_bytes() const noexcept { return E * sizeof(value_type); } + constexpr bool empty() const noexcept { return E == 0; } + + constexpr iterator begin() const noexcept { return mData; } + constexpr iterator end() const noexcept { return mData+E; } + constexpr const_iterator cbegin() const noexcept { return mData; } + constexpr const_iterator cend() const noexcept { return mData+E; } + + constexpr reverse_iterator rbegin() const noexcept { return end(); } + constexpr reverse_iterator rend() const noexcept { return begin(); } + constexpr const_reverse_iterator crbegin() const noexcept { return cend(); } + constexpr const_reverse_iterator crend() const noexcept { return cbegin(); } + + template + constexpr span first() const + { + static_assert(E >= C, "New size exceeds original capacity"); + return span{mData, C}; + } + + template + constexpr span last() const + { + static_assert(E >= C, "New size exceeds original capacity"); + return span{mData+(E-C), C}; + } + + template + constexpr span subspan() const + { + static_assert(E >= O, "Offset exceeds extent"); + static_assert(E-O >= RealC, "New size exceeds original capacity"); + return span{mData+O, RealC}; + } + + /* NOTE: Can't declare objects of a specialized template class prior to + * defining the specialization. As a result, these methods need to be + * defined later. + */ + constexpr span first(size_t count) const; + constexpr span last(size_t count) const; + constexpr span subspan(size_t offset, size_t count=dynamic_extent) const; + +private: + pointer mData{nullptr}; +}; + +template +class span(-1)> { + static constexpr size_t dynamic_extent{static_cast(-1)}; + +public: + using element_type = T; + using value_type = typename std::remove_cv::type; + using index_type = size_t; + using difference_type = ptrdiff_t; + + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + static constexpr size_t extent{static_cast(-1)}; + constexpr span() noexcept = default; constexpr span(pointer ptr, index_type count) : mData{ptr}, mDataEnd{ptr+count} { } constexpr span(pointer first, pointer last) : mData{first}, mDataEnd{last} { } template constexpr span(element_type (&arr)[N]) noexcept : span{al::data(arr), al::size(arr)} { } - template + template::value)> constexpr span(std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } - template + template::value)> constexpr span(const std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } - template + template constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { } - template + template constexpr span(const U &cont) : span{al::data(cont), al::size(cont)} { } + template::value)> + constexpr span(const span &span_) noexcept : span{al::data(span_), al::size(span_)} { } constexpr span(const span&) noexcept = default; span& operator=(const span &rhs) noexcept = default; + template::value)> + span& operator=(const span &rhs) noexcept + { + mData = rhs.data(); + mDataEnd = mData + rhs.size(); + return *this; + } constexpr reference front() const { return *mData; } constexpr reference back() const { return *(mDataEnd-1); } @@ -97,11 +243,25 @@ public: constexpr const_reverse_iterator crbegin() const noexcept { return cend(); } constexpr const_reverse_iterator crend() const noexcept { return cbegin(); } + template + constexpr span first() const + { return span{mData, C}; } + constexpr span first(size_t count) const { return (count >= size()) ? *this : span{mData, mData+count}; } + + template + constexpr span last() const + { return span{mDataEnd-C, C}; } + constexpr span last(size_t count) const { return (count >= size()) ? *this : span{mDataEnd-count, mDataEnd}; } - constexpr span subspan(size_t offset, size_t count=static_cast(-1)) const + + template + constexpr span subspan() const + { return span{mData+O, C}; } + + constexpr span subspan(size_t offset, size_t count=dynamic_extent) const { return (offset >= size()) ? span{} : (count >= size()-offset) ? span{mData+offset, mDataEnd} : @@ -113,6 +273,31 @@ private: pointer mDataEnd{nullptr}; }; +template +constexpr inline auto span::first(size_t count) const -> span +{ + return (count >= size()) ? span{mData, extent} : + span{mData, count}; +} + +template +constexpr inline auto span::last(size_t count) const -> span +{ + return (count >= size()) ? span{mData, extent} : + span{mData+extent-count, count}; +} + +template +constexpr inline auto span::subspan(size_t offset, size_t count) const -> span +{ + return (offset >= size()) ? span{} : + (count >= size()-offset) ? span{mData+offset, mData+extent} : + span{mData+offset, mData+offset+count}; +} + +#undef IS_VALID_CONTAINER +#undef REQUIRES + } // namespace al #endif /* AL_SPAN_H */ -- cgit v1.2.3 From 28fbb5178a432f5027082c938118270b263230a2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 27 May 2019 15:56:50 -0700 Subject: Remove unnecessary assignment operators --- common/alspan.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/common/alspan.h b/common/alspan.h index e5a91686..ae3f1c06 100644 --- a/common/alspan.h +++ b/common/alspan.h @@ -119,9 +119,6 @@ public: constexpr span(const span&) noexcept = default; span& operator=(const span &rhs) noexcept = default; - template::value)> - span& operator=(const span &rhs) noexcept - { mData = rhs.data(); return *this; } constexpr reference front() const { return *mData; } constexpr reference back() const { return *(mData+E-1); } @@ -216,13 +213,6 @@ public: constexpr span(const span&) noexcept = default; span& operator=(const span &rhs) noexcept = default; - template::value)> - span& operator=(const span &rhs) noexcept - { - mData = rhs.data(); - mDataEnd = mData + rhs.size(); - return *this; - } constexpr reference front() const { return *mData; } constexpr reference back() const { return *(mDataEnd-1); } -- cgit v1.2.3 From bac52e95371e9a0342523314e718bb7c1cdf13ad Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 27 May 2019 17:48:19 -0700 Subject: Fix default constructor for static-sized spans --- common/alspan.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/alspan.h b/common/alspan.h index ae3f1c06..8ba211fa 100644 --- a/common/alspan.h +++ b/common/alspan.h @@ -100,7 +100,7 @@ public: static constexpr size_t extent{E}; - template + template constexpr span() noexcept { } constexpr span(pointer ptr, index_type /*count*/) : mData{ptr} { } constexpr span(pointer first, pointer /*last*/) : mData{first} { } -- cgit v1.2.3 From aa4b6afad64e3a1e4c5a55652494a8970a4c2fbc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 27 May 2019 22:01:59 -0700 Subject: Small cleanup for is_span and is_std_array --- common/alspan.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/common/alspan.h b/common/alspan.h index 8ba211fa..bd6b53bb 100644 --- a/common/alspan.h +++ b/common/alspan.h @@ -53,14 +53,18 @@ namespace detail_ { using void_t = typename make_void::type; template - struct is_span : std::false_type { }; + struct is_span_ : std::false_type { }; template - struct is_span> : std::true_type { }; + struct is_span_> : std::true_type { }; + template + struct is_span : is_span_::type> { }; template - struct is_std_array : std::false_type { }; + struct is_std_array_ : std::false_type { }; template - struct is_std_array> : std::true_type { }; + struct is_std_array_> : std::true_type { }; + template + struct is_std_array : is_std_array_::type> { }; template struct has_size_and_data : std::false_type { }; @@ -72,10 +76,8 @@ namespace detail_ { #define REQUIRES(...) typename std::enable_if<(__VA_ARGS__),int>::type = 0 #define IS_VALID_CONTAINER(C) \ - !detail_::is_span::type>::value && \ - !detail_::is_std_array::type>::value && \ - !std::is_array::type>::value && \ - detail_::has_size_and_data::type>::value && \ + !detail_::is_span::value && !detail_::is_std_array::value && \ + !std::is_array::value && detail_::has_size_and_data::value && \ std::is_convertible()))>::type(*)[],element_type(*)[]>::value template -- cgit v1.2.3 From 7ce2b632f51292c26014ad2efeb4b5429c3bf04f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 28 May 2019 08:49:53 -0700 Subject: Simplify template type requirement checking --- common/albyte.h | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/common/albyte.h b/common/albyte.h index f9230005..d1459e96 100644 --- a/common/albyte.h +++ b/common/albyte.h @@ -11,20 +11,22 @@ namespace al { */ enum class byte : unsigned char { }; -template::value,int>::type = 0> +#define REQUIRES(...) typename std::enable_if<(__VA_ARGS__),int>::type = 0 + +template::value)> inline constexpr T to_integer(al::byte b) noexcept { return T(b); } -template::value,int>::type = 0> +template::value)> inline constexpr al::byte operator<<(al::byte lhs, T rhs) noexcept { return al::byte(to_integer(lhs) << rhs); } -template::value,int>::type = 0> +template::value)> inline constexpr al::byte operator>>(al::byte lhs, T rhs) noexcept { return al::byte(to_integer(lhs) >> rhs); } #define AL_DECL_OP(op) \ -template::value,int>::type = 0> \ +template::value)> \ inline constexpr al::byte operator op (al::byte lhs, T rhs) noexcept \ { return al::byte(to_integer(lhs) op rhs); } \ inline constexpr al::byte operator op (al::byte lhs, al::byte rhs) noexcept \ @@ -40,16 +42,16 @@ inline constexpr al::byte operator~(al::byte b) noexcept { return al::byte(~to_integer(b)); } -template::value,int>::type = 0> +template::value)> inline al::byte& operator<<=(al::byte &lhs, T rhs) noexcept { lhs = lhs << rhs; return lhs; } -template::value,int>::type = 0> +template::value)> inline al::byte& operator>>=(al::byte &lhs, T rhs) noexcept { lhs = lhs >> rhs; return lhs; } #define AL_DECL_OP(op) \ -template::value,int>::type = 0> \ +template::value)> \ inline al::byte& operator op##= (al::byte &lhs, T rhs) noexcept \ { lhs = lhs op rhs; return lhs; } \ inline al::byte& operator op##= (al::byte &lhs, al::byte rhs) noexcept \ @@ -61,6 +63,8 @@ AL_DECL_OP(^) #undef AL_DECL_OP +#undef REQUIRES + } // namespace al #endif /* AL_BYTE_H */ -- cgit v1.2.3 From c80ee5b7014d12675e2c615574c9f3f3354ffd1b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 28 May 2019 16:22:36 -0700 Subject: Use std::array for most mixing buffer arrays --- Alc/alc.cpp | 2 +- Alc/alu.cpp | 58 ++++++++++++++++++++------------------ Alc/bformatdec.cpp | 19 +++++++------ Alc/bformatdec.h | 4 +-- Alc/effects/base.h | 2 +- Alc/mastering.cpp | 20 ++++++------- Alc/mastering.h | 4 +-- Alc/mixvoice.cpp | 29 ++++++++++--------- Alc/panning.cpp | 2 +- Alc/uhjfilter.cpp | 12 ++++---- Alc/uhjfilter.h | 3 +- OpenAL32/Include/alAuxEffectSlot.h | 2 +- OpenAL32/Include/alMain.h | 8 ++++-- OpenAL32/Include/alu.h | 4 +-- 14 files changed, 89 insertions(+), 80 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index eb6269ec..6d09b118 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1937,7 +1937,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) num_chans*sizeof(device->MixBuffer[0])); device->MixBuffer.resize(num_chans); - device->Dry.Buffer = &reinterpret_cast(device->MixBuffer[0]); + device->Dry.Buffer = device->MixBuffer.data(); if(device->RealOut.NumChannels != 0) device->RealOut.Buffer = device->Dry.Buffer + device->Dry.NumChannels; else diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 94ba3aa8..2ce74537 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -133,8 +133,9 @@ void ProcessHrtf(ALCdevice *device, const ALsizei SamplesToDo) ASSUME(lidx >= 0 && ridx >= 0); DirectHrtfState *state{device->mHrtfState.get()}; - MixDirectHrtf(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], device->Dry.Buffer, - device->HrtfAccumData, state, device->Dry.NumChannels, SamplesToDo); + MixDirectHrtf(device->RealOut.Buffer[lidx].data(), device->RealOut.Buffer[ridx].data(), + &reinterpret_cast(device->Dry.Buffer[0]), device->HrtfAccumData, + state, device->Dry.NumChannels, SamplesToDo); } void ProcessAmbiDec(ALCdevice *device, const ALsizei SamplesToDo) @@ -165,8 +166,8 @@ void ProcessBs2b(ALCdevice *device, const ALsizei SamplesToDo) ASSUME(lidx >= 0 && ridx >= 0); /* Apply binaural/crossfeed filter */ - bs2b_cross_feed(device->Bs2b.get(), device->RealOut.Buffer[lidx], - device->RealOut.Buffer[ridx], SamplesToDo); + bs2b_cross_feed(device->Bs2b.get(), device->RealOut.Buffer[lidx].data(), + device->RealOut.Buffer[ridx].data(), SamplesToDo); } } // namespace @@ -1465,14 +1466,17 @@ void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) [SamplesToDo](const ALeffectslot *slot) -> void { EffectState *state{slot->Params.mEffectState}; - state->process(SamplesToDo, slot->Wet.Buffer, slot->Wet.NumChannels, - state->mOutBuffer, state->mOutChannels); + state->process(SamplesToDo, + &reinterpret_cast(slot->Wet.Buffer[0]), + slot->Wet.NumChannels, + &reinterpret_cast(state->mOutBuffer[0]), + state->mOutChannels); } ); } -void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*Buffer)[BUFFERSIZE], const int lidx, +void ApplyStablizer(FrontStablizer *Stablizer, FloatBufferLine *Buffer, const int lidx, const int ridx, const int cidx, const ALsizei SamplesToDo, const ALsizei NumChannels) { ASSUME(SamplesToDo > 0); @@ -1487,16 +1491,17 @@ void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*Buffer)[BUFFERSIZE], co continue; auto &DelayBuf = Stablizer->DelayBuf[i]; - auto buffer_end = Buffer[i] + SamplesToDo; + auto buffer_end = Buffer[i].begin() + SamplesToDo; if(LIKELY(SamplesToDo >= ALsizei{FrontStablizer::DelayLength})) { - auto delay_end = std::rotate(Buffer[i], buffer_end - FrontStablizer::DelayLength, - buffer_end); - std::swap_ranges(Buffer[i], delay_end, std::begin(DelayBuf)); + auto delay_end = std::rotate(Buffer[i].begin(), + buffer_end - FrontStablizer::DelayLength, buffer_end); + std::swap_ranges(Buffer[i].begin(), delay_end, std::begin(DelayBuf)); } else { - auto delay_start = std::swap_ranges(Buffer[i], buffer_end, std::begin(DelayBuf)); + auto delay_start = std::swap_ranges(Buffer[i].begin(), buffer_end, + std::begin(DelayBuf)); std::rotate(std::begin(DelayBuf), delay_start, std::end(DelayBuf)); } } @@ -1509,7 +1514,7 @@ void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*Buffer)[BUFFERSIZE], co /* This applies the band-splitter, preserving phase at the cost of some * delay. The shorter the delay, the more error seeps into the result. */ - auto apply_splitter = [&APFilter,&tmpbuf,SamplesToDo](const ALfloat *Buffer, + auto apply_splitter = [&APFilter,&tmpbuf,SamplesToDo](const FloatBufferLine &Buffer, ALfloat (&DelayBuf)[FrontStablizer::DelayLength], BandSplitter &Filter, ALfloat (&splitbuf)[2][BUFFERSIZE]) -> void { @@ -1520,7 +1525,7 @@ void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*Buffer)[BUFFERSIZE], co */ auto tmpbuf_end = std::begin(tmpbuf) + SamplesToDo; std::copy_n(std::begin(DelayBuf), FrontStablizer::DelayLength, tmpbuf_end); - std::reverse_copy(Buffer, Buffer+SamplesToDo, std::begin(tmpbuf)); + std::reverse_copy(Buffer.begin(), Buffer.begin()+SamplesToDo, std::begin(tmpbuf)); std::copy_n(std::begin(tmpbuf), FrontStablizer::DelayLength, std::begin(DelayBuf)); /* Apply an all-pass on the reversed signal, then reverse the samples @@ -1568,8 +1573,8 @@ void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*Buffer)[BUFFERSIZE], co } } -void ApplyDistanceComp(ALfloat (*Samples)[BUFFERSIZE], const DistanceComp &distcomp, - const ALsizei SamplesToDo, const ALsizei numchans) +void ApplyDistanceComp(FloatBufferLine *Samples, const DistanceComp &distcomp, + const ALsizei SamplesToDo, const ALsizei numchans) { ASSUME(SamplesToDo > 0); ASSUME(numchans > 0); @@ -1583,7 +1588,7 @@ void ApplyDistanceComp(ALfloat (*Samples)[BUFFERSIZE], const DistanceComp &distc if(base < 1) continue; - ALfloat *inout{al::assume_aligned<16>(Samples[c])}; + ALfloat *inout{al::assume_aligned<16>(Samples[c].data())}; auto inout_end = inout + SamplesToDo; if(LIKELY(SamplesToDo >= base)) { @@ -1599,8 +1604,8 @@ void ApplyDistanceComp(ALfloat (*Samples)[BUFFERSIZE], const DistanceComp &distc } } -void ApplyDither(ALfloat (*Samples)[BUFFERSIZE], ALuint *dither_seed, const ALfloat quant_scale, - const ALsizei SamplesToDo, const ALsizei numchans) +void ApplyDither(FloatBufferLine *Samples, ALuint *dither_seed, const ALfloat quant_scale, + const ALsizei SamplesToDo, const ALsizei numchans) { ASSUME(numchans > 0); @@ -1610,11 +1615,10 @@ void ApplyDither(ALfloat (*Samples)[BUFFERSIZE], ALuint *dither_seed, const ALfl */ const ALfloat invscale{1.0f / quant_scale}; ALuint seed{*dither_seed}; - auto dither_channel = [&seed,invscale,quant_scale,SamplesToDo](ALfloat *input) -> void + auto dither_channel = [&seed,invscale,quant_scale,SamplesToDo](FloatBufferLine &input) -> void { ASSUME(SamplesToDo > 0); - ALfloat *buffer{al::assume_aligned<16>(input)}; - auto dither_sample = [&seed,invscale,quant_scale](ALfloat sample) noexcept -> ALfloat + auto dither_sample = [&seed,invscale,quant_scale](const ALfloat sample) noexcept -> ALfloat { ALfloat val{sample * quant_scale}; ALuint rng0{dither_rng(&seed)}; @@ -1622,7 +1626,7 @@ void ApplyDither(ALfloat (*Samples)[BUFFERSIZE], ALuint *dither_seed, const ALfl val += static_cast(rng0*(1.0/UINT_MAX) - rng1*(1.0/UINT_MAX)); return fast_roundf(val) * invscale; }; - std::transform(buffer, buffer+SamplesToDo, buffer, dither_sample); + std::transform(input.begin(), input.begin()+SamplesToDo, input.begin(), dither_sample); }; std::for_each(Samples, Samples+numchans, dither_channel); *dither_seed = seed; @@ -1660,7 +1664,7 @@ template<> inline ALubyte SampleConv(ALfloat val) noexcept { return SampleConv(val) + 128; } template -void Write(const ALfloat (*InBuffer)[BUFFERSIZE], ALvoid *OutBuffer, const ALsizei Offset, +void Write(const FloatBufferLine *InBuffer, ALvoid *OutBuffer, const ALsizei Offset, const ALsizei SamplesToDo, const ALsizei numchans) { using SampleType = typename DevFmtTypeTraits::Type; @@ -1668,7 +1672,7 @@ void Write(const ALfloat (*InBuffer)[BUFFERSIZE], ALvoid *OutBuffer, const ALsiz ASSUME(Offset >= 0); ASSUME(numchans > 0); SampleType *outbase = static_cast(OutBuffer) + Offset*numchans; - auto conv_channel = [&outbase,SamplesToDo,numchans](const ALfloat *inbuf) -> void + auto conv_channel = [&outbase,SamplesToDo,numchans](const FloatBufferLine &inbuf) -> void { ASSUME(SamplesToDo > 0); SampleType *out{outbase++}; @@ -1677,7 +1681,7 @@ void Write(const ALfloat (*InBuffer)[BUFFERSIZE], ALvoid *OutBuffer, const ALsiz *out = SampleConv(s); out += numchans; }; - std::for_each(inbuf, inbuf+SamplesToDo, conv_sample); + std::for_each(inbuf.begin(), inbuf.begin()+SamplesToDo, conv_sample); }; std::for_each(InBuffer, InBuffer+numchans, conv_channel); } @@ -1758,7 +1762,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) if(LIKELY(OutBuffer)) { - ALfloat (*Buffer)[BUFFERSIZE]{device->RealOut.Buffer}; + FloatBufferLine *Buffer{device->RealOut.Buffer}; ALsizei Channels{device->RealOut.NumChannels}; /* Finally, interleave and convert samples, writing to the device's diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 563282a7..33659e04 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -146,7 +146,7 @@ BFormatDec::BFormatDec(const ALsizei inchans, const ALsizei chancount, } -void BFormatDec::process(ALfloat (*OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*InSamples)[BUFFERSIZE], const ALsizei SamplesToDo) +void BFormatDec::process(FloatBufferLine *OutBuffer, const ALsizei OutChannels, const FloatBufferLine *InSamples, const ALsizei SamplesToDo) { ASSUME(OutChannels > 0); ASSUME(mNumChannels > 0); @@ -154,19 +154,19 @@ void BFormatDec::process(ALfloat (*OutBuffer)[BUFFERSIZE], const ALsizei OutChan if(mDualBand) { for(ALsizei i{0};i < mNumChannels;i++) - mXOver[i].process(mSamplesHF[i].data(), mSamplesLF[i].data(), InSamples[i], - SamplesToDo); + mXOver[i].process(mSamplesHF[i].data(), mSamplesLF[i].data(), InSamples[i].data(), + SamplesToDo); for(ALsizei chan{0};chan < OutChannels;chan++) { if(UNLIKELY(!(mEnabled&(1<(mSamplesHF[0]), + MixRowSamples(OutBuffer[chan].data(), mMatrix.Dual[chan][sHFBand], + &reinterpret_cast(mSamplesHF[0]), mNumChannels, 0, SamplesToDo); - MixRowSamples(OutBuffer[chan], mMatrix.Dual[chan][sLFBand], - &reinterpret_cast(mSamplesLF[0]), + MixRowSamples(OutBuffer[chan].data(), mMatrix.Dual[chan][sLFBand], + &reinterpret_cast(mSamplesLF[0]), mNumChannels, 0, SamplesToDo); } } @@ -177,8 +177,9 @@ void BFormatDec::process(ALfloat (*OutBuffer)[BUFFERSIZE], const ALsizei OutChan if(UNLIKELY(!(mEnabled&(1<(InSamples[0]), mNumChannels, 0, + SamplesToDo); } } } diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index d82f08ac..ef81b41d 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -43,8 +43,8 @@ public: const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]); /* Decodes the ambisonic input to the given output channels. */ - void process(ALfloat (*OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, - const ALfloat (*InSamples)[BUFFERSIZE], const ALsizei SamplesToDo); + void process(FloatBufferLine *OutBuffer, const ALsizei OutChannels, + const FloatBufferLine *InSamples, const ALsizei SamplesToDo); /* Retrieves per-order HF scaling factors for "upsampling" ambisonic data. */ static std::array GetHFOrderScales(const ALsizei in_order, diff --git a/Alc/effects/base.h b/Alc/effects/base.h index ba1fbf96..467fb5af 100644 --- a/Alc/effects/base.h +++ b/Alc/effects/base.h @@ -143,7 +143,7 @@ struct EffectTarget { struct EffectState { RefCount mRef{1u}; - ALfloat (*mOutBuffer)[BUFFERSIZE]{nullptr}; + FloatBufferLine *mOutBuffer{nullptr}; ALsizei mOutChannels{0}; diff --git a/Alc/mastering.cpp b/Alc/mastering.cpp index 23386cf4..2cf6acf5 100644 --- a/Alc/mastering.cpp +++ b/Alc/mastering.cpp @@ -97,7 +97,7 @@ void ShiftSlidingHold(SlidingHold *Hold, const ALsizei n) /* Multichannel compression is linked via the absolute maximum of all * channels. */ -void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, const ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]) +void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, const FloatBufferLine *OutBuffer) { const ALsizei index{Comp->mLookAhead}; const ALsizei numChans{Comp->mNumChans}; @@ -109,9 +109,9 @@ void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, const ALfloat (*R auto side_begin = std::begin(Comp->mSideChain) + index; std::fill(side_begin, side_begin+SamplesToDo, 0.0f); - auto fill_max = [SamplesToDo,side_begin](const ALfloat *input) -> void + auto fill_max = [SamplesToDo,side_begin](const FloatBufferLine &input) -> void { - const ALfloat *RESTRICT buffer{al::assume_aligned<16>(input)}; + const ALfloat *RESTRICT buffer{al::assume_aligned<16>(input.data())}; auto max_abs = std::bind(maxf, _1, std::bind(static_cast(std::fabs), _2)); std::transform(side_begin, side_begin+SamplesToDo, buffer, side_begin, max_abs); }; @@ -293,7 +293,7 @@ void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) * reaching the offending impulse. This is best used when operating as a * limiter. */ -void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE]) +void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, FloatBufferLine *OutBuffer) { static constexpr ALsizei mask{BUFFERSIZE - 1}; const ALsizei numChans{Comp->mNumChans}; @@ -305,7 +305,7 @@ void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*RESTRICT for(ALsizei c{0};c < numChans;c++) { - ALfloat *RESTRICT inout{al::assume_aligned<16>(OutBuffer[c])}; + ALfloat *RESTRICT inout{al::assume_aligned<16>(OutBuffer[c].data())}; ALfloat *RESTRICT delay{al::assume_aligned<16>(Comp->mDelay[c])}; for(ALsizei i{0};i < SamplesToDo;i++) { @@ -425,7 +425,7 @@ Compressor::~Compressor() } -void Compressor::process(const ALsizei SamplesToDo, ALfloat (*OutBuffer)[BUFFERSIZE]) +void Compressor::process(const ALsizei SamplesToDo, FloatBufferLine *OutBuffer) { const ALsizei numChans{mNumChans}; @@ -435,9 +435,9 @@ void Compressor::process(const ALsizei SamplesToDo, ALfloat (*OutBuffer)[BUFFERS const ALfloat preGain{mPreGain}; if(preGain != 1.0f) { - auto apply_gain = [SamplesToDo,preGain](ALfloat *input) noexcept -> void + auto apply_gain = [SamplesToDo,preGain](FloatBufferLine &input) noexcept -> void { - ALfloat *buffer{al::assume_aligned<16>(input)}; + ALfloat *buffer{al::assume_aligned<16>(input.data())}; std::transform(buffer, buffer+SamplesToDo, buffer, std::bind(std::multiplies{}, _1, preGain)); }; @@ -460,9 +460,9 @@ void Compressor::process(const ALsizei SamplesToDo, ALfloat (*OutBuffer)[BUFFERS SignalDelay(this, SamplesToDo, OutBuffer); const ALfloat (&sideChain)[BUFFERSIZE*2] = mSideChain; - auto apply_comp = [SamplesToDo,&sideChain](ALfloat *input) noexcept -> void + auto apply_comp = [SamplesToDo,&sideChain](FloatBufferLine &input) noexcept -> void { - ALfloat *buffer{al::assume_aligned<16>(input)}; + ALfloat *buffer{al::assume_aligned<16>(input.data())}; const ALfloat *gains{al::assume_aligned<16>(&sideChain[0])}; std::transform(gains, gains+SamplesToDo, buffer, buffer, std::bind(std::multiplies{}, _1, _2)); diff --git a/Alc/mastering.h b/Alc/mastering.h index a9411bd0..6cc40ba3 100644 --- a/Alc/mastering.h +++ b/Alc/mastering.h @@ -6,7 +6,7 @@ #include "AL/al.h" #include "almalloc.h" -/* For BUFFERSIZE. */ +/* For FloatBufferLine/BUFFERSIZE. */ #include "alMain.h" @@ -65,7 +65,7 @@ struct Compressor { ~Compressor(); - void process(const ALsizei SamplesToDo, ALfloat (*OutBuffer)[BUFFERSIZE]); + void process(const ALsizei SamplesToDo, FloatBufferLine *OutBuffer); ALsizei getLookAhead() const noexcept { return mLookAhead; } DEF_PLACE_NEWDEL() diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 284621ab..6df9f430 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -744,10 +744,9 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc hrtfparams.Gain = 0.0f; hrtfparams.GainStep = gain / static_cast(fademix); - MixHrtfBlendSamples( - voice->mDirect.Buffer[OutLIdx], voice->mDirect.Buffer[OutRIdx], - HrtfSamples, AccumSamples, OutPos, IrSize, &parms.Hrtf.Old, - &hrtfparams, fademix); + MixHrtfBlendSamples(voice->mDirect.Buffer[OutLIdx].data(), + voice->mDirect.Buffer[OutRIdx].data(), HrtfSamples, AccumSamples, + OutPos, IrSize, &parms.Hrtf.Old, &hrtfparams, fademix); /* Update the old parameters with the result. */ parms.Hrtf.Old = parms.Hrtf.Target; if(fademix < Counter) @@ -778,10 +777,9 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc hrtfparams.Gain = parms.Hrtf.Old.Gain; hrtfparams.GainStep = (gain - parms.Hrtf.Old.Gain) / static_cast(todo); - MixHrtfSamples( - voice->mDirect.Buffer[OutLIdx], voice->mDirect.Buffer[OutRIdx], - HrtfSamples+fademix, AccumSamples+fademix, OutPos+fademix, IrSize, - &hrtfparams, todo); + MixHrtfSamples(voice->mDirect.Buffer[OutLIdx].data(), + voice->mDirect.Buffer[OutRIdx].data(), HrtfSamples+fademix, + AccumSamples+fademix, OutPos+fademix, IrSize, &hrtfparams, todo); /* Store the interpolated gain or the final target gain * depending if the fade is done. */ @@ -803,8 +801,8 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc SilentTarget : parms.Gains.Target}; MixSamples(samples, voice->mDirect.ChannelsPerOrder[0], - voice->mDirect.Buffer, parms.Gains.Current, TargetGains, Counter, - OutPos, DstBufferSize); + &reinterpret_cast(voice->mDirect.Buffer[0]), + parms.Gains.Current, TargetGains, Counter, OutPos, DstBufferSize); ALfloat (&nfcsamples)[BUFFERSIZE] = Device->NfcSampleData; ALsizei chanoffset{voice->mDirect.ChannelsPerOrder[0]}; @@ -815,8 +813,9 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc return; (parms.NFCtrlFilter.*process)(nfcsamples, samples, DstBufferSize); MixSamples(nfcsamples, voice->mDirect.ChannelsPerOrder[order], - voice->mDirect.Buffer+chanoffset, parms.Gains.Current+chanoffset, - TargetGains+chanoffset, Counter, OutPos, DstBufferSize); + &reinterpret_cast(voice->mDirect.Buffer[chanoffset]), + parms.Gains.Current+chanoffset, TargetGains+chanoffset, Counter, + OutPos, DstBufferSize); chanoffset += voice->mDirect.ChannelsPerOrder[order]; }; apply_nfc(&NfcFilter::process1, 1); @@ -827,7 +826,8 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc { const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? SilentTarget : parms.Gains.Target}; - MixSamples(samples, voice->mDirect.Channels, voice->mDirect.Buffer, + MixSamples(samples, voice->mDirect.Channels, + &reinterpret_cast(voice->mDirect.Buffer[0]), parms.Gains.Current, TargetGains, Counter, OutPos, DstBufferSize); } } @@ -844,7 +844,8 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc const ALfloat *TargetGains{UNLIKELY(vstate==ALvoice::Stopping) ? SilentTarget : parms.Gains.Target}; - MixSamples(samples, send.Channels, send.Buffer, parms.Gains.Current, + MixSamples(samples, send.Channels, + &reinterpret_cast(send.Buffer[0]), parms.Gains.Current, TargetGains, Counter, OutPos, DstBufferSize); }; std::for_each(voice->mSend.begin(), voice->mSend.end(), mix_send); diff --git a/Alc/panning.cpp b/Alc/panning.cpp index a209c6cf..d1d40927 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -976,6 +976,6 @@ void aluInitEffectPanning(ALeffectslot *slot, ALCdevice *device) { return BFChannelConfig{1.0f, acn}; } ); std::fill(iter, slot->Wet.AmbiMap.end(), BFChannelConfig{}); - slot->Wet.Buffer = &reinterpret_cast(slot->MixBuffer[0]); + slot->Wet.Buffer = slot->MixBuffer.data(); slot->Wet.NumChannels = static_cast(count); } diff --git a/Alc/uhjfilter.cpp b/Alc/uhjfilter.cpp index 64d5f76c..acdf6f0b 100644 --- a/Alc/uhjfilter.cpp +++ b/Alc/uhjfilter.cpp @@ -59,7 +59,7 @@ void allpass_process(AllPassState *state, ALfloat *dst, const ALfloat *src, cons * know which is the intended result. */ -void Uhj2Encoder::encode(ALfloat *LeftOut, ALfloat *RightOut, ALfloat (*InSamples)[BUFFERSIZE], const ALsizei SamplesToDo) +void Uhj2Encoder::encode(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, FloatBufferLine *InSamples, const ALsizei SamplesToDo) { alignas(16) ALfloat D[MAX_UPDATE_SAMPLES], S[MAX_UPDATE_SAMPLES]; alignas(16) ALfloat temp[MAX_UPDATE_SAMPLES]; @@ -72,7 +72,7 @@ void Uhj2Encoder::encode(ALfloat *LeftOut, ALfloat *RightOut, ALfloat (*InSample ASSUME(todo > 0); /* D = 0.6554516*Y */ - const ALfloat *RESTRICT input{al::assume_aligned<16>(InSamples[2]+base)}; + const ALfloat *RESTRICT input{al::assume_aligned<16>(InSamples[2].data()+base)}; for(ALsizei i{0};i < todo;i++) temp[i] = 0.6554516f*input[i]; allpass_process(&mFilter1_Y[0], temp, temp, Filter1CoeffSqr[0], todo); @@ -89,8 +89,8 @@ void Uhj2Encoder::encode(ALfloat *LeftOut, ALfloat *RightOut, ALfloat (*InSample mLastY = temp[todo-1]; /* D += j(-0.3420201*W + 0.5098604*X) */ - const ALfloat *RESTRICT input0{al::assume_aligned<16>(InSamples[0]+base)}; - const ALfloat *RESTRICT input1{al::assume_aligned<16>(InSamples[1]+base)}; + const ALfloat *RESTRICT input0{al::assume_aligned<16>(InSamples[0].data()+base)}; + const ALfloat *RESTRICT input1{al::assume_aligned<16>(InSamples[1].data()+base)}; for(ALsizei i{0};i < todo;i++) temp[i] = -0.3420201f*input0[i] + 0.5098604f*input1[i]; allpass_process(&mFilter2_WX[0], temp, temp, Filter2CoeffSqr[0], todo); @@ -113,11 +113,11 @@ void Uhj2Encoder::encode(ALfloat *LeftOut, ALfloat *RightOut, ALfloat (*InSample mLastWX = temp[todo-1]; /* Left = (S + D)/2.0 */ - ALfloat *RESTRICT left = al::assume_aligned<16>(LeftOut+base); + ALfloat *RESTRICT left = al::assume_aligned<16>(LeftOut.data()+base); for(ALsizei i{0};i < todo;i++) left[i] += (S[i] + D[i]) * 0.5f; /* Right = (S - D)/2.0 */ - ALfloat *RESTRICT right = al::assume_aligned<16>(RightOut+base); + ALfloat *RESTRICT right = al::assume_aligned<16>(RightOut.data()+base); for(ALsizei i{0};i < todo;i++) right[i] += (S[i] - D[i]) * 0.5f; diff --git a/Alc/uhjfilter.h b/Alc/uhjfilter.h index 1351491b..181e036a 100644 --- a/Alc/uhjfilter.h +++ b/Alc/uhjfilter.h @@ -45,7 +45,8 @@ struct Uhj2Encoder { /* Encodes a 2-channel UHJ (stereo-compatible) signal from a B-Format input * signal. The input must use FuMa channel ordering and scaling. */ - void encode(ALfloat *LeftOut, ALfloat *RightOut, ALfloat (*InSamples)[BUFFERSIZE], const ALsizei SamplesToDo); + void encode(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, FloatBufferLine *InSamples, + const ALsizei SamplesToDo); DEF_NEWDEL(Uhj2Encoder) }; diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 06681276..9956c432 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -71,7 +71,7 @@ struct ALeffectslot { ALuint id{}; /* Mixing buffer used by the Wet mix. */ - al::vector,16> MixBuffer; + al::vector MixBuffer; /* Wet buffer configuration is ACN channel order with N3D scaling. * Consequently, effects that only want to work with mono input can use diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 7019a6d4..7538ade2 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -305,6 +305,8 @@ struct BFChannelConfig { */ #define BUFFERSIZE 1024 +using FloatBufferLine = std::array; + /* Maximum number of samples to pad on either end of a buffer for resampling. * Note that both the beginning and end need padding! */ @@ -315,14 +317,14 @@ struct MixParams { /* Coefficient channel mapping for mixing to the buffer. */ std::array AmbiMap; - ALfloat (*Buffer)[BUFFERSIZE]{nullptr}; + FloatBufferLine *Buffer{nullptr}; ALsizei NumChannels{0}; }; struct RealMixParams { std::array ChannelIndex{}; - ALfloat (*Buffer)[BUFFERSIZE]{nullptr}; + FloatBufferLine *Buffer{nullptr}; ALsizei NumChannels{0}; }; @@ -405,7 +407,7 @@ struct ALCdevice { alignas(16) float2 HrtfAccumData[BUFFERSIZE + HRIR_LENGTH]; /* Mixing buffer used by the Dry mix and Real output. */ - al::vector, 16> MixBuffer; + al::vector MixBuffer; /* The "dry" path corresponds to the main output. */ MixParams Dry; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 642aeddc..327adfc0 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -263,7 +263,7 @@ struct ALvoice { int FilterType; DirectParams Params[MAX_INPUT_CHANNELS]; - ALfloat (*Buffer)[BUFFERSIZE]; + FloatBufferLine *Buffer; ALsizei Channels; ALsizei ChannelsPerOrder[MAX_AMBI_ORDER+1]; } mDirect; @@ -272,7 +272,7 @@ struct ALvoice { int FilterType; SendParams Params[MAX_INPUT_CHANNELS]; - ALfloat (*Buffer)[BUFFERSIZE]; + FloatBufferLine *Buffer; ALsizei Channels; }; al::FlexArray mSend; -- cgit v1.2.3 From 838e2bae801fec73258c4b8332b4d95a34d0aff2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 28 May 2019 17:18:22 -0700 Subject: Improve a couple algorithms --- Alc/mastering.cpp | 40 +++++++++++++++++++++++----------------- Alc/mastering.h | 3 +-- Alc/uhjfilter.cpp | 25 +++++++++++++++---------- 3 files changed, 39 insertions(+), 29 deletions(-) diff --git a/Alc/mastering.cpp b/Alc/mastering.cpp index 2cf6acf5..00b79e67 100644 --- a/Alc/mastering.cpp +++ b/Alc/mastering.cpp @@ -295,28 +295,30 @@ void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) */ void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, FloatBufferLine *OutBuffer) { - static constexpr ALsizei mask{BUFFERSIZE - 1}; const ALsizei numChans{Comp->mNumChans}; - const ALsizei indexIn{Comp->mDelayIndex}; - const ALsizei indexOut{Comp->mDelayIndex - Comp->mLookAhead}; + const ALsizei lookAhead{Comp->mLookAhead}; ASSUME(SamplesToDo > 0); ASSUME(numChans > 0); + ASSUME(lookAhead > 0); for(ALsizei c{0};c < numChans;c++) { - ALfloat *RESTRICT inout{al::assume_aligned<16>(OutBuffer[c].data())}; - ALfloat *RESTRICT delay{al::assume_aligned<16>(Comp->mDelay[c])}; - for(ALsizei i{0};i < SamplesToDo;i++) - { - const ALfloat sig{inout[i]}; + ALfloat *inout{al::assume_aligned<16>(OutBuffer[c].data())}; + ALfloat *delaybuf{al::assume_aligned<16>(Comp->mDelay[c].data())}; - inout[i] = delay[(indexOut + i) & mask]; - delay[(indexIn + i) & mask] = sig; + auto inout_end = inout + SamplesToDo; + if(LIKELY(SamplesToDo >= lookAhead)) + { + auto delay_end = std::rotate(inout, inout_end - lookAhead, inout_end); + std::swap_ranges(inout, delay_end, delaybuf); + } + else + { + auto delay_start = std::swap_ranges(inout, inout_end, delaybuf); + std::rotate(delaybuf, delay_start, delaybuf + lookAhead); } } - - Comp->mDelayIndex = (indexIn + SamplesToDo) & mask; } } // namespace @@ -354,9 +356,10 @@ std::unique_ptr CompressorInit(const ALsizei NumChans, const ALuint const ALfloat Ratio, const ALfloat KneeDb, const ALfloat AttackTime, const ALfloat ReleaseTime) { - auto lookAhead = static_cast( + const auto lookAhead = static_cast( clampf(std::round(LookAheadTime*SampleRate), 0.0f, BUFFERSIZE-1)); - auto hold = static_cast(clampf(std::round(HoldTime*SampleRate), 0.0f, BUFFERSIZE-1)); + const auto hold = static_cast( + clampf(std::round(HoldTime*SampleRate), 0.0f, BUFFERSIZE-1)); size_t size{sizeof(Compressor)}; if(lookAhead > 0) @@ -398,15 +401,15 @@ std::unique_ptr CompressorInit(const ALsizei NumChans, const ALuint { if(hold > 1) { - Comp->mHold = new (reinterpret_cast(Comp.get() + 1)) SlidingHold{}; + Comp->mHold = new (static_cast(Comp.get() + 1)) SlidingHold{}; Comp->mHold->mValues[0] = -std::numeric_limits::infinity(); Comp->mHold->mExpiries[0] = hold; Comp->mHold->mLength = hold; - Comp->mDelay = reinterpret_cast(Comp->mHold + 1); + Comp->mDelay = new (static_cast(Comp->mHold + 1)) FloatBufferLine{}; } else { - Comp->mDelay = reinterpret_cast(Comp.get() + 1); + Comp->mDelay = new (static_cast(Comp.get() + 1)) FloatBufferLine{}; } } @@ -422,6 +425,9 @@ Compressor::~Compressor() if(mHold) mHold->~SlidingHold(); mHold = nullptr; + if(mDelay) + mDelay->~FloatBufferLine(); + mDelay = nullptr; } diff --git a/Alc/mastering.h b/Alc/mastering.h index 6cc40ba3..31d0ef97 100644 --- a/Alc/mastering.h +++ b/Alc/mastering.h @@ -50,8 +50,7 @@ struct Compressor { alignas(16) ALfloat mCrestFactor[BUFFERSIZE]{}; SlidingHold *mHold{nullptr}; - ALfloat (*mDelay)[BUFFERSIZE]{nullptr}; - ALsizei mDelayIndex{0}; + FloatBufferLine *mDelay{nullptr}; ALfloat mCrestCoeff{0.0f}; ALfloat mGainEstimate{0.0f}; diff --git a/Alc/uhjfilter.cpp b/Alc/uhjfilter.cpp index acdf6f0b..c2657f9f 100644 --- a/Alc/uhjfilter.cpp +++ b/Alc/uhjfilter.cpp @@ -66,15 +66,17 @@ void Uhj2Encoder::encode(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, Fl ASSUME(SamplesToDo > 0); + auto winput = InSamples[0].cbegin(); + auto xinput = InSamples[1].cbegin(); + auto yinput = InSamples[2].cbegin(); for(ALsizei base{0};base < SamplesToDo;) { - ALsizei todo = mini(SamplesToDo - base, MAX_UPDATE_SAMPLES); + const ALsizei todo{mini(SamplesToDo - base, MAX_UPDATE_SAMPLES)}; ASSUME(todo > 0); /* D = 0.6554516*Y */ - const ALfloat *RESTRICT input{al::assume_aligned<16>(InSamples[2].data()+base)}; - for(ALsizei i{0};i < todo;i++) - temp[i] = 0.6554516f*input[i]; + std::transform(yinput+base, yinput+todo, std::begin(temp), + [](const float y) noexcept -> float { return 0.6554516f*y; }); allpass_process(&mFilter1_Y[0], temp, temp, Filter1CoeffSqr[0], todo); allpass_process(&mFilter1_Y[1], temp, temp, Filter1CoeffSqr[1], todo); allpass_process(&mFilter1_Y[2], temp, temp, Filter1CoeffSqr[2], todo); @@ -89,10 +91,9 @@ void Uhj2Encoder::encode(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, Fl mLastY = temp[todo-1]; /* D += j(-0.3420201*W + 0.5098604*X) */ - const ALfloat *RESTRICT input0{al::assume_aligned<16>(InSamples[0].data()+base)}; - const ALfloat *RESTRICT input1{al::assume_aligned<16>(InSamples[1].data()+base)}; - for(ALsizei i{0};i < todo;i++) - temp[i] = -0.3420201f*input0[i] + 0.5098604f*input1[i]; + std::transform(winput, winput+todo, xinput, std::begin(temp), + [](const float w, const float x) noexcept -> float + { return -0.3420201f*w + 0.5098604f*x; }); allpass_process(&mFilter2_WX[0], temp, temp, Filter2CoeffSqr[0], todo); allpass_process(&mFilter2_WX[1], temp, temp, Filter2CoeffSqr[1], todo); allpass_process(&mFilter2_WX[2], temp, temp, Filter2CoeffSqr[2], todo); @@ -101,8 +102,9 @@ void Uhj2Encoder::encode(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, Fl D[i] += temp[i]; /* S = 0.9396926*W + 0.1855740*X */ - for(ALsizei i{0};i < todo;i++) - temp[i] = 0.9396926f*input0[i] + 0.1855740f*input1[i]; + std::transform(winput, winput+todo, xinput, std::begin(temp), + [](const float w, const float x) noexcept -> float + { return 0.9396926f*w + 0.1855740f*x; }); allpass_process(&mFilter1_WX[0], temp, temp, Filter1CoeffSqr[0], todo); allpass_process(&mFilter1_WX[1], temp, temp, Filter1CoeffSqr[1], todo); allpass_process(&mFilter1_WX[2], temp, temp, Filter1CoeffSqr[2], todo); @@ -121,6 +123,9 @@ void Uhj2Encoder::encode(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, Fl for(ALsizei i{0};i < todo;i++) right[i] += (S[i] - D[i]) * 0.5f; + winput += todo; + xinput += todo; + yinput += todo; base += todo; } } -- cgit v1.2.3 From b923eb187991a8db56fd23cffa70f946ce24c1ff Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 28 May 2019 22:44:50 -0700 Subject: Use FloatBufferLine with the HRTF mixer functions --- Alc/alu.cpp | 5 ++--- Alc/mixer/defs.h | 6 +++--- Alc/mixer/hrtfbase.h | 31 ++++++++++++++++--------------- Alc/mixer/mixer_c.cpp | 22 +++++++++++----------- Alc/mixer/mixer_neon.cpp | 22 +++++++++++----------- Alc/mixer/mixer_sse.cpp | 22 +++++++++++----------- Alc/mixvoice.cpp | 10 +++++----- OpenAL32/Include/alu.h | 12 ++++++------ 8 files changed, 65 insertions(+), 65 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 2ce74537..2a43cd88 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -133,9 +133,8 @@ void ProcessHrtf(ALCdevice *device, const ALsizei SamplesToDo) ASSUME(lidx >= 0 && ridx >= 0); DirectHrtfState *state{device->mHrtfState.get()}; - MixDirectHrtf(device->RealOut.Buffer[lidx].data(), device->RealOut.Buffer[ridx].data(), - &reinterpret_cast(device->Dry.Buffer[0]), device->HrtfAccumData, - state, device->Dry.NumChannels, SamplesToDo); + MixDirectHrtf(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], + device->Dry.Buffer, device->HrtfAccumData, state, device->Dry.NumChannels, SamplesToDo); } void ProcessAmbiDec(ALCdevice *device, const ALsizei SamplesToDo) diff --git a/Alc/mixer/defs.h b/Alc/mixer/defs.h index cd301833..a6131958 100644 --- a/Alc/mixer/defs.h +++ b/Alc/mixer/defs.h @@ -35,11 +35,11 @@ template void MixRow_(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*data)[BUFFERSIZE], const ALsizei InChans, const ALsizei InPos, const ALsizei BufferSize); template -void MixHrtf_(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, float2 *RESTRICT AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfParams *hrtfparams, const ALsizei BufferSize); +void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfParams *hrtfparams, const ALsizei BufferSize); template -void MixHrtfBlend_(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, float2 *RESTRICT AccumSamples, const ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, const ALsizei BufferSize); +void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, const ALsizei BufferSize); template -void MixDirectHrtf_(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat (*data)[BUFFERSIZE], float2 *RESTRICT AccumSamples, DirectHrtfState *State, const ALsizei NumChans, const ALsizei BufferSize); +void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const FloatBufferLine *InSamples, float2 *AccumSamples, DirectHrtfState *State, const ALsizei NumChans, const ALsizei BufferSize); /* Vectorized resampler helpers */ inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *RESTRICT frac_arr, ALsizei *RESTRICT pos_arr, ALsizei size) diff --git a/Alc/mixer/hrtfbase.h b/Alc/mixer/hrtfbase.h index 162d7289..8549f6ba 100644 --- a/Alc/mixer/hrtfbase.h +++ b/Alc/mixer/hrtfbase.h @@ -12,9 +12,9 @@ using ApplyCoeffsT = void(ALsizei Offset, float2 *RESTRICT Values, const ALsizei const HrirArray &Coeffs, const ALfloat left, const ALfloat right); template -inline void MixHrtfBase(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, - float2 *RESTRICT AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - MixHrtfParams *hrtfparams, const ALsizei BufferSize) +inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *RESTRICT AccumSamples, const ALsizei OutPos, + const ALsizei IrSize, MixHrtfParams *hrtfparams, const ALsizei BufferSize) { ASSUME(OutPos >= 0); ASSUME(IrSize >= 4); @@ -33,8 +33,8 @@ inline void MixHrtfBase(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, c for(ALsizei i{0};i < BufferSize;++i) { const ALfloat g{gain + gainstep*stepcount}; - const ALfloat left{data[Delay[0]++] * g}; - const ALfloat right{data[Delay[1]++] * g}; + const ALfloat left{InSamples[Delay[0]++] * g}; + const ALfloat right{InSamples[Delay[1]++] * g}; ApplyCoeffs(i, AccumSamples+i, IrSize, Coeffs, left, right); stepcount += 1.0f; @@ -48,9 +48,10 @@ inline void MixHrtfBase(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, c } template -inline void MixHrtfBlendBase(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, float2 *RESTRICT AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - const HrtfParams *oldparams, MixHrtfParams *newparams, const ALsizei BufferSize) +inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *RESTRICT AccumSamples, const ALsizei OutPos, + const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, + const ALsizei BufferSize) { const auto &OldCoeffs = oldparams->Coeffs; const ALfloat oldGain{oldparams->Gain}; @@ -75,13 +76,13 @@ inline void MixHrtfBlendBase(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightO for(ALsizei i{0};i < BufferSize;++i) { ALfloat g{oldGain + oldGainStep*stepcount}; - ALfloat left{data[OldDelay[0]++] * g}; - ALfloat right{data[OldDelay[1]++] * g}; + ALfloat left{InSamples[OldDelay[0]++] * g}; + ALfloat right{InSamples[OldDelay[1]++] * g}; ApplyCoeffs(i, AccumSamples+i, IrSize, OldCoeffs, left, right); g = newGainStep*stepcount; - left = data[NewDelay[0]++] * g; - right = data[NewDelay[1]++] * g; + left = InSamples[NewDelay[0]++] * g; + right = InSamples[NewDelay[1]++] * g; ApplyCoeffs(i, AccumSamples+i, IrSize, NewCoeffs, left, right); stepcount += 1.0f; @@ -95,8 +96,8 @@ inline void MixHrtfBlendBase(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightO } template -inline void MixDirectHrtfBase(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat (*data)[BUFFERSIZE], float2 *RESTRICT AccumSamples, DirectHrtfState *State, +inline void MixDirectHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const FloatBufferLine *InSamples, float2 *RESTRICT AccumSamples, DirectHrtfState *State, const ALsizei NumChans, const ALsizei BufferSize) { ASSUME(NumChans > 0); @@ -107,7 +108,7 @@ inline void MixDirectHrtfBase(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT Right for(ALsizei c{0};c < NumChans;++c) { - const ALfloat (&input)[BUFFERSIZE] = data[c]; + const FloatBufferLine &input = InSamples[c]; const auto &Coeffs = State->Chan[c].Coeffs; auto accum_iter = std::copy_n(State->Chan[c].Values.begin(), diff --git a/Alc/mixer/mixer_c.cpp b/Alc/mixer/mixer_c.cpp index 6ee5df88..79ee305b 100644 --- a/Alc/mixer/mixer_c.cpp +++ b/Alc/mixer/mixer_c.cpp @@ -117,29 +117,29 @@ static inline void ApplyCoeffs(ALsizei /*Offset*/, float2 *RESTRICT Values, cons } template<> -void MixHrtf_(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, - float2 *RESTRICT AccumSamples, const ALsizei OutPos, const ALsizei IrSize, +void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfParams *hrtfparams, const ALsizei BufferSize) { - MixHrtfBase(LeftOut, RightOut, data, AccumSamples, OutPos, IrSize, hrtfparams, - BufferSize); + MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, + hrtfparams, BufferSize); } template<> -void MixHrtfBlend_(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, float2 *RESTRICT AccumSamples, const ALsizei OutPos, const ALsizei IrSize, +void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, const ALsizei BufferSize) { - MixHrtfBlendBase(LeftOut, RightOut, data, AccumSamples, OutPos, IrSize, oldparams, - newparams, BufferSize); + MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, + oldparams, newparams, BufferSize); } template<> -void MixDirectHrtf_(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat (*data)[BUFFERSIZE], float2 *RESTRICT AccumSamples, DirectHrtfState *State, +void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const FloatBufferLine *InSamples, float2 *AccumSamples, DirectHrtfState *State, const ALsizei NumChans, const ALsizei BufferSize) { - MixDirectHrtfBase(LeftOut, RightOut, data, AccumSamples, State, NumChans, + MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, NumChans, BufferSize); } diff --git a/Alc/mixer/mixer_neon.cpp b/Alc/mixer/mixer_neon.cpp index cdd96296..e6f257fd 100644 --- a/Alc/mixer/mixer_neon.cpp +++ b/Alc/mixer/mixer_neon.cpp @@ -163,29 +163,29 @@ static inline void ApplyCoeffs(ALsizei /*Offset*/, float2 *RESTRICT Values, cons } template<> -void MixHrtf_(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, - float2 *RESTRICT AccumSamples, const ALsizei OutPos, const ALsizei IrSize, +void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfParams *hrtfparams, const ALsizei BufferSize) { - MixHrtfBase(LeftOut, RightOut, data, AccumSamples, OutPos, IrSize, hrtfparams, - BufferSize); + MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, + hrtfparams, BufferSize); } template<> -void MixHrtfBlend_(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, float2 *RESTRICT AccumSamples, const ALsizei OutPos, const ALsizei IrSize, +void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, const ALsizei BufferSize) { - MixHrtfBlendBase(LeftOut, RightOut, data, AccumSamples, OutPos, IrSize, oldparams, - newparams, BufferSize); + MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, + oldparams, newparams, BufferSize); } template<> -void MixDirectHrtf_(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat (*data)[BUFFERSIZE], float2 *RESTRICT AccumSamples, DirectHrtfState *State, +void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const FloatBufferLine *InSamples, float2 *AccumSamples, DirectHrtfState *State, const ALsizei NumChans, const ALsizei BufferSize) { - MixDirectHrtfBase(LeftOut, RightOut, data, AccumSamples, State, NumChans, + MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, NumChans, BufferSize); } diff --git a/Alc/mixer/mixer_sse.cpp b/Alc/mixer/mixer_sse.cpp index 629fa428..a4e80256 100644 --- a/Alc/mixer/mixer_sse.cpp +++ b/Alc/mixer/mixer_sse.cpp @@ -120,29 +120,29 @@ static inline void ApplyCoeffs(ALsizei Offset, float2 *RESTRICT Values, const AL } template<> -void MixHrtf_(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, const ALfloat *data, - float2 *RESTRICT AccumSamples, const ALsizei OutPos, const ALsizei IrSize, +void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfParams *hrtfparams, const ALsizei BufferSize) { - MixHrtfBase(LeftOut, RightOut, data, AccumSamples, OutPos, IrSize, hrtfparams, - BufferSize); + MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, + hrtfparams, BufferSize); } template<> -void MixHrtfBlend_(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, float2 *RESTRICT AccumSamples, const ALsizei OutPos, const ALsizei IrSize, +void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, const ALsizei BufferSize) { - MixHrtfBlendBase(LeftOut, RightOut, data, AccumSamples, OutPos, IrSize, oldparams, - newparams, BufferSize); + MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, + oldparams, newparams, BufferSize); } template<> -void MixDirectHrtf_(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat (*data)[BUFFERSIZE], float2 *RESTRICT AccumSamples, DirectHrtfState *State, +void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const FloatBufferLine *InSamples, float2 *AccumSamples, DirectHrtfState *State, const ALsizei NumChans, const ALsizei BufferSize) { - MixDirectHrtfBase(LeftOut, RightOut, data, AccumSamples, State, NumChans, + MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, NumChans, BufferSize); } diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 6df9f430..c9227919 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -744,9 +744,9 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc hrtfparams.Gain = 0.0f; hrtfparams.GainStep = gain / static_cast(fademix); - MixHrtfBlendSamples(voice->mDirect.Buffer[OutLIdx].data(), - voice->mDirect.Buffer[OutRIdx].data(), HrtfSamples, AccumSamples, - OutPos, IrSize, &parms.Hrtf.Old, &hrtfparams, fademix); + MixHrtfBlendSamples(voice->mDirect.Buffer[OutLIdx], + voice->mDirect.Buffer[OutRIdx], HrtfSamples, AccumSamples, OutPos, + IrSize, &parms.Hrtf.Old, &hrtfparams, fademix); /* Update the old parameters with the result. */ parms.Hrtf.Old = parms.Hrtf.Target; if(fademix < Counter) @@ -777,8 +777,8 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc hrtfparams.Gain = parms.Hrtf.Old.Gain; hrtfparams.GainStep = (gain - parms.Hrtf.Old.Gain) / static_cast(todo); - MixHrtfSamples(voice->mDirect.Buffer[OutLIdx].data(), - voice->mDirect.Buffer[OutRIdx].data(), HrtfSamples+fademix, + MixHrtfSamples(voice->mDirect.Buffer[OutLIdx], + voice->mDirect.Buffer[OutRIdx], HrtfSamples+fademix, AccumSamples+fademix, OutPos+fademix, IrSize, &hrtfparams, todo); /* Store the interpolated gain or the final target gain * depending if the fade is done. diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 327adfc0..8653b96c 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -297,14 +297,14 @@ using MixerFunc = void(*)(const ALfloat *data, const ALsizei OutChans, using RowMixerFunc = void(*)(ALfloat *OutBuffer, const ALfloat *gains, const ALfloat (*data)[BUFFERSIZE], const ALsizei InChans, const ALsizei InPos, const ALsizei BufferSize); -using HrtfMixerFunc = void(*)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, float2 *RESTRICT AccumSamples, const ALsizei OutPos, const ALsizei IrSize, +using HrtfMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfParams *hrtfparams, const ALsizei BufferSize); -using HrtfMixerBlendFunc = void(*)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat *data, float2 *RESTRICT AccumSamples, const ALsizei OutPos, const ALsizei IrSize, +using HrtfMixerBlendFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, const ALsizei BufferSize); -using HrtfDirectMixerFunc = void(*)(ALfloat *RESTRICT LeftOut, ALfloat *RESTRICT RightOut, - const ALfloat (*data)[BUFFERSIZE], float2 *RESTRICT AccumSamples, DirectHrtfState *State, +using HrtfDirectMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const FloatBufferLine *InSamples, float2 *RESTRICT AccumSamples, DirectHrtfState *State, const ALsizei NumChans, const ALsizei BufferSize); -- cgit v1.2.3 From ec3a6f8cded70aeb54e9c658fa68a680c017e1ef Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 29 May 2019 09:37:25 -0700 Subject: Use FloatBufferLine for the effect process method --- Alc/alu.cpp | 7 ++----- Alc/effects/autowah.cpp | 8 ++++---- Alc/effects/base.h | 2 +- Alc/effects/chorus.cpp | 9 +++++---- Alc/effects/compressor.cpp | 4 ++-- Alc/effects/dedicated.cpp | 9 +++++---- Alc/effects/distortion.cpp | 4 ++-- Alc/effects/echo.cpp | 9 +++++---- Alc/effects/equalizer.cpp | 9 +++++---- Alc/effects/fshifter.cpp | 8 ++++---- Alc/effects/modulator.cpp | 8 ++++---- Alc/effects/null.cpp | 4 ++-- Alc/effects/pshifter.cpp | 8 ++++---- Alc/effects/reverb.cpp | 30 +++++++++++++++++------------- 14 files changed, 62 insertions(+), 57 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 2a43cd88..9f61be10 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1465,11 +1465,8 @@ void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) [SamplesToDo](const ALeffectslot *slot) -> void { EffectState *state{slot->Params.mEffectState}; - state->process(SamplesToDo, - &reinterpret_cast(slot->Wet.Buffer[0]), - slot->Wet.NumChannels, - &reinterpret_cast(state->mOutBuffer[0]), - state->mOutChannels); + state->process(SamplesToDo, slot->Wet.Buffer, slot->Wet.NumChannels, + state->mOutBuffer, state->mOutChannels); } ); } diff --git a/Alc/effects/autowah.cpp b/Alc/effects/autowah.cpp index dc03dee1..2b01f70a 100644 --- a/Alc/effects/autowah.cpp +++ b/Alc/effects/autowah.cpp @@ -72,7 +72,7 @@ struct ALautowahState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; DEF_NEWDEL(ALautowahState) }; @@ -128,7 +128,7 @@ void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, } } -void ALautowahState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) +void ALautowahState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) { const ALfloat attack_rate = mAttackRate; const ALfloat release_rate = mReleaseRate; @@ -194,8 +194,8 @@ void ALautowahState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT sampl mChans[c].Filter.z2 = z2; /* Now, mix the processed sound data to the output. */ - MixSamples(mBufferOut, numOutput, samplesOut, mChans[c].CurrentGains, - mChans[c].TargetGains, samplesToDo, 0, samplesToDo); + MixSamples(mBufferOut, numOutput, &reinterpret_cast(samplesOut[0]), + mChans[c].CurrentGains, mChans[c].TargetGains, samplesToDo, 0, samplesToDo); } } diff --git a/Alc/effects/base.h b/Alc/effects/base.h index 467fb5af..c7c6f1c0 100644 --- a/Alc/effects/base.h +++ b/Alc/effects/base.h @@ -151,7 +151,7 @@ struct EffectState { virtual ALboolean deviceUpdate(const ALCdevice *device) = 0; virtual void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) = 0; - virtual void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) = 0; + virtual void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) = 0; void IncRef() noexcept; void DecRef() noexcept; diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp index d12d2484..e953d3e3 100644 --- a/Alc/effects/chorus.cpp +++ b/Alc/effects/chorus.cpp @@ -101,7 +101,7 @@ struct ChorusState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; DEF_NEWDEL(ChorusState) }; @@ -198,7 +198,7 @@ void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, co } } -void ChorusState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei /*numInput*/, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) +void ChorusState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) { const auto bufmask = static_cast(mSampleBuffer.size()-1); const ALfloat feedback{mFeedback}; @@ -255,8 +255,9 @@ void ChorusState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesI } for(c = 0;c < 2;c++) - MixSamples(temps[c], numOutput, samplesOut, mGains[c].Current, mGains[c].Target, - samplesToDo-base, base, todo); + MixSamples(temps[c], numOutput, + &reinterpret_cast(samplesOut[0]), mGains[c].Current, + mGains[c].Target, samplesToDo-base, base, todo); base += todo; } diff --git a/Alc/effects/compressor.cpp b/Alc/effects/compressor.cpp index 2a441b0e..a3435d61 100644 --- a/Alc/effects/compressor.cpp +++ b/Alc/effects/compressor.cpp @@ -52,7 +52,7 @@ struct CompressorState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; DEF_NEWDEL(CompressorState) }; @@ -87,7 +87,7 @@ void CompressorState::update(const ALCcontext* UNUSED(context), const ALeffectsl } } -void CompressorState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) +void CompressorState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) { ALsizei i, j, k; ALsizei base; diff --git a/Alc/effects/dedicated.cpp b/Alc/effects/dedicated.cpp index 14d0c3c8..7b44e392 100644 --- a/Alc/effects/dedicated.cpp +++ b/Alc/effects/dedicated.cpp @@ -40,7 +40,7 @@ struct DedicatedState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; DEF_NEWDEL(DedicatedState) }; @@ -90,10 +90,11 @@ void DedicatedState::update(const ALCcontext* UNUSED(context), const ALeffectslo } } -void DedicatedState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei /*numInput*/, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) +void DedicatedState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) { - MixSamples(samplesIn[0], numOutput, samplesOut, mCurrentGains, mTargetGains, samplesToDo, 0, - samplesToDo); + MixSamples(samplesIn[0].data(), numOutput, + &reinterpret_cast(samplesOut[0]), mCurrentGains, mTargetGains, + samplesToDo, 0, samplesToDo); } diff --git a/Alc/effects/distortion.cpp b/Alc/effects/distortion.cpp index 7ef77c69..ffe2a102 100644 --- a/Alc/effects/distortion.cpp +++ b/Alc/effects/distortion.cpp @@ -50,7 +50,7 @@ struct DistortionState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; DEF_NEWDEL(DistortionState) }; @@ -95,7 +95,7 @@ void DistortionState::update(const ALCcontext *context, const ALeffectslot *slot ComputePanGains(target.Main, coeffs, slot->Params.Gain*props->Distortion.Gain, mGain); } -void DistortionState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei /*numInput*/, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) +void DistortionState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) { ALfloat (*RESTRICT buffer)[BUFFERSIZE] = mBuffer; const ALfloat fc = mEdgeCoeff; diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index 158ab856..e684039d 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -60,7 +60,7 @@ struct EchoState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; DEF_NEWDEL(EchoState) }; @@ -119,7 +119,7 @@ void EchoState::update(const ALCcontext *context, const ALeffectslot *slot, cons ComputePanGains(target.Main, coeffs[1], slot->Params.Gain, mGains[1].Target); } -void EchoState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei /*numInput*/, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) +void EchoState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) { const auto mask = static_cast(mSampleBuffer.size()-1); ALfloat *RESTRICT delaybuf{mSampleBuffer.data()}; @@ -158,8 +158,9 @@ void EchoState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn) mOffset = offset; for(ALsizei c{0};c < 2;c++) - MixSamples(mTempBuffer[c], numOutput, samplesOut, mGains[c].Current, mGains[c].Target, - samplesToDo, 0, samplesToDo); + MixSamples(mTempBuffer[c], numOutput, + &reinterpret_cast(samplesOut[0]), mGains[c].Current, + mGains[c].Target, samplesToDo, 0, samplesToDo); } diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index cc701e8d..53f8e153 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -94,7 +94,7 @@ struct EqualizerState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; DEF_NEWDEL(EqualizerState) }; @@ -158,17 +158,18 @@ void EqualizerState::update(const ALCcontext *context, const ALeffectslot *slot, } } -void EqualizerState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) +void EqualizerState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) { ASSUME(numInput > 0); for(ALsizei c{0};c < numInput;c++) { - mChans[c].filter[0].process(mSampleBuffer, samplesIn[c], samplesToDo); + mChans[c].filter[0].process(mSampleBuffer, samplesIn[c].data(), samplesToDo); mChans[c].filter[1].process(mSampleBuffer, mSampleBuffer, samplesToDo); mChans[c].filter[2].process(mSampleBuffer, mSampleBuffer, samplesToDo); mChans[c].filter[3].process(mSampleBuffer, mSampleBuffer, samplesToDo); - MixSamples(mSampleBuffer, numOutput, samplesOut, mChans[c].CurrentGains, + MixSamples(mSampleBuffer, numOutput, + &reinterpret_cast(samplesOut[0]), mChans[c].CurrentGains, mChans[c].TargetGains, samplesToDo, 0, samplesToDo); } } diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp index e3dc6f1d..0b8d33e4 100644 --- a/Alc/effects/fshifter.cpp +++ b/Alc/effects/fshifter.cpp @@ -83,7 +83,7 @@ struct FshifterState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; DEF_NEWDEL(FshifterState) }; @@ -138,7 +138,7 @@ void FshifterState::update(const ALCcontext *context, const ALeffectslot *slot, ComputePanGains(target.Main, coeffs, slot->Params.Gain, mTargetGains); } -void FshifterState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei /*numInput*/, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) +void FshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) { static constexpr complex_d complex_zero{0.0, 0.0}; ALfloat *RESTRICT BufferOut = mBufferOut; @@ -198,8 +198,8 @@ void FshifterState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT sample } /* Now, mix the processed sound data to the output. */ - MixSamples(BufferOut, numOutput, samplesOut, mCurrentGains, mTargetGains, - maxi(samplesToDo, 512), 0, samplesToDo); + MixSamples(BufferOut, numOutput, &reinterpret_cast(samplesOut[0]), + mCurrentGains, mTargetGains, maxi(samplesToDo, 512), 0, samplesToDo); } diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index f926cb87..ec0b6184 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -93,7 +93,7 @@ struct ModulatorState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; DEF_NEWDEL(ModulatorState) }; @@ -141,7 +141,7 @@ void ModulatorState::update(const ALCcontext *context, const ALeffectslot *slot, } } -void ModulatorState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) +void ModulatorState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) { const ALsizei step = mStep; ALsizei base; @@ -165,8 +165,8 @@ void ModulatorState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT sampl for(i = 0;i < td;i++) temps[i] *= modsamples[i]; - MixSamples(temps, numOutput, samplesOut, mChans[c].CurrentGains, - mChans[c].TargetGains, samplesToDo-base, base, td); + MixSamples(temps, numOutput, &reinterpret_cast(samplesOut[0]), + mChans[c].CurrentGains, mChans[c].TargetGains, samplesToDo-base, base, td); } base += td; diff --git a/Alc/effects/null.cpp b/Alc/effects/null.cpp index 5a2e4d78..96c0e928 100644 --- a/Alc/effects/null.cpp +++ b/Alc/effects/null.cpp @@ -19,7 +19,7 @@ struct NullState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; DEF_NEWDEL(NullState) }; @@ -55,7 +55,7 @@ void NullState::update(const ALCcontext* UNUSED(context), const ALeffectslot* UN * input to the output buffer. The result should be added to the output buffer, * not replace it. */ -void NullState::process(ALsizei /*samplesToDo*/, const ALfloat (*RESTRICT /*samplesIn*/)[BUFFERSIZE], const ALsizei /*numInput*/, ALfloat (*RESTRICT /*samplesOut*/)[BUFFERSIZE], const ALsizei /*numOutput*/) +void NullState::process(const ALsizei /*samplesToDo*/, const FloatBufferLine *RESTRICT /*samplesIn*/, const ALsizei /*numInput*/, FloatBufferLine *RESTRICT /*samplesOut*/, const ALsizei /*numOutput*/) { } diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp index 1d85fb9e..a3e946c0 100644 --- a/Alc/effects/pshifter.cpp +++ b/Alc/effects/pshifter.cpp @@ -153,7 +153,7 @@ struct PshifterState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; DEF_NEWDEL(PshifterState) }; @@ -197,7 +197,7 @@ void PshifterState::update(const ALCcontext* UNUSED(context), const ALeffectslot ComputePanGains(target.Main, coeffs, slot->Params.Gain, mTargetGains); } -void PshifterState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei /*numInput*/, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) +void PshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) { /* Pitch shifter engine based on the work of Stephan Bernsee. * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/ @@ -321,8 +321,8 @@ void PshifterState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT sample mCount = count; /* Now, mix the processed sound data to the output. */ - MixSamples(bufferOut, numOutput, samplesOut, mCurrentGains, mTargetGains, - maxi(samplesToDo, 512), 0, samplesToDo); + MixSamples(bufferOut, numOutput, &reinterpret_cast(samplesOut[0]), + mCurrentGains, mTargetGains, maxi(samplesToDo, 512), 0, samplesToDo); } diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index d65a642d..fe660fd7 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -375,16 +375,15 @@ struct ReverbState final : public EffectState { alignas(16) ALfloat mEarlyBuffer[NUM_LINES][BUFFERSIZE]{}; alignas(16) ALfloat mLateBuffer[NUM_LINES][BUFFERSIZE]{}; - using MixOutT = void (ReverbState::*)(const ALsizei numOutput, - ALfloat (*samplesOut)[BUFFERSIZE], const ALsizei todo); + using MixOutT = void (ReverbState::*)(const ALsizei numOutput, FloatBufferLine *samplesOut, + const ALsizei todo); MixOutT mMixOut{&ReverbState::MixOutPlain}; std::array mOrderScales{}; std::array,2> mAmbiSplitter; - void MixOutPlain(const ALsizei numOutput, ALfloat (*samplesOut)[BUFFERSIZE], - const ALsizei todo) + void MixOutPlain(const ALsizei numOutput, FloatBufferLine *samplesOut, const ALsizei todo) { ASSUME(todo > 0); @@ -393,7 +392,8 @@ struct ReverbState final : public EffectState { { std::fill_n(std::begin(mTempSamples[0]), todo, 0.0f); MixRowSamples(mTempSamples[0], A2B[c], mEarlyBuffer, NUM_LINES, 0, todo); - MixSamples(mTempSamples[0], numOutput, samplesOut, mEarly.CurrentGain[c], + MixSamples(mTempSamples[0], numOutput, + &reinterpret_cast(samplesOut[0]), mEarly.CurrentGain[c], mEarly.PanGain[c], todo, 0, todo); } @@ -401,13 +401,13 @@ struct ReverbState final : public EffectState { { std::fill_n(std::begin(mTempSamples[0]), todo, 0.0f); MixRowSamples(mTempSamples[0], A2B[c], mLateBuffer, NUM_LINES, 0, todo); - MixSamples(mTempSamples[0], numOutput, samplesOut, mLate.CurrentGain[c], + MixSamples(mTempSamples[0], numOutput, + &reinterpret_cast(samplesOut[0]), mLate.CurrentGain[c], mLate.PanGain[c], todo, 0, todo); } } - void MixOutAmbiUp(const ALsizei numOutput, ALfloat (*samplesOut)[BUFFERSIZE], - const ALsizei todo) + void MixOutAmbiUp(const ALsizei numOutput, FloatBufferLine *samplesOut, const ALsizei todo) { ASSUME(todo > 0); @@ -422,7 +422,8 @@ struct ReverbState final : public EffectState { const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; mAmbiSplitter[0][c].applyHfScale(mTempSamples[0], hfscale, todo); - MixSamples(mTempSamples[0], numOutput, samplesOut, mEarly.CurrentGain[c], + MixSamples(mTempSamples[0], numOutput, + &reinterpret_cast(samplesOut[0]), mEarly.CurrentGain[c], mEarly.PanGain[c], todo, 0, todo); } @@ -434,7 +435,8 @@ struct ReverbState final : public EffectState { const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; mAmbiSplitter[1][c].applyHfScale(mTempSamples[0], hfscale, todo); - MixSamples(mTempSamples[0], numOutput, samplesOut, mLate.CurrentGain[c], + MixSamples(mTempSamples[0], numOutput, + &reinterpret_cast(samplesOut[0]), mLate.CurrentGain[c], mLate.PanGain[c], todo, 0, todo); } } @@ -448,7 +450,7 @@ struct ReverbState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; DEF_NEWDEL(ReverbState) }; @@ -1444,7 +1446,7 @@ void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei to VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, out, todo); } -void ReverbState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesIn)[BUFFERSIZE], const ALsizei numInput, ALfloat (*RESTRICT samplesOut)[BUFFERSIZE], const ALsizei numOutput) +void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) { ALsizei fadeCount{mFadeCount}; @@ -1455,7 +1457,9 @@ void ReverbState::process(ALsizei samplesToDo, const ALfloat (*RESTRICT samplesI for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(std::begin(afmt[c]), samplesToDo, 0.0f); - MixRowSamples(afmt[c], B2A[c], samplesIn, numInput, 0, samplesToDo); + MixRowSamples(afmt[c], B2A[c], + &reinterpret_cast(samplesIn[0]), numInput, 0, + samplesToDo); /* Band-pass the incoming samples. */ mFilter[c].Lp.process(afmt[c], afmt[c], samplesToDo); -- cgit v1.2.3 From d0f0a5fdca87f74ef46ad26cb79975e1c6cda8f0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 29 May 2019 11:13:35 -0700 Subject: Separate two HRTF passes into two loops --- Alc/mixer/hrtfbase.h | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/Alc/mixer/hrtfbase.h b/Alc/mixer/hrtfbase.h index 8549f6ba..571cdc89 100644 --- a/Alc/mixer/hrtfbase.h +++ b/Alc/mixer/hrtfbase.h @@ -23,13 +23,12 @@ inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const auto &Coeffs = *hrtfparams->Coeffs; const ALfloat gainstep{hrtfparams->GainStep}; const ALfloat gain{hrtfparams->Gain}; - ALfloat stepcount{0.0f}; ALsizei Delay[2]{ HRTF_HISTORY_LENGTH - hrtfparams->Delay[0], HRTF_HISTORY_LENGTH - hrtfparams->Delay[1] }; ASSUME(Delay[0] >= 0 && Delay[1] >= 0); - + ALfloat stepcount{0.0f}; for(ALsizei i{0};i < BufferSize;++i) { const ALfloat g{gain + gainstep*stepcount}; @@ -39,6 +38,7 @@ inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, stepcount += 1.0f; } + for(ALsizei i{0};i < BufferSize;++i) LeftOut[OutPos+i] += AccumSamples[i][0]; for(ALsizei i{0};i < BufferSize;++i) @@ -58,35 +58,40 @@ inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut const ALfloat oldGainStep{-oldGain / static_cast(BufferSize)}; const auto &NewCoeffs = *newparams->Coeffs; const ALfloat newGainStep{newparams->GainStep}; - ALfloat stepcount{0.0f}; ASSUME(OutPos >= 0); ASSUME(IrSize >= 4); ASSUME(BufferSize > 0); - ALsizei OldDelay[2]{ + ALsizei Delay[2]{ HRTF_HISTORY_LENGTH - oldparams->Delay[0], HRTF_HISTORY_LENGTH - oldparams->Delay[1] }; - ASSUME(OldDelay[0] >= 0 && OldDelay[1] >= 0); - ALsizei NewDelay[2]{ - HRTF_HISTORY_LENGTH - newparams->Delay[0], - HRTF_HISTORY_LENGTH - newparams->Delay[1] }; - ASSUME(NewDelay[0] >= 0 && NewDelay[1] >= 0); - + ASSUME(Delay[0] >= 0 && Delay[1] >= 0); + ALfloat stepcount{0.0f}; for(ALsizei i{0};i < BufferSize;++i) { - ALfloat g{oldGain + oldGainStep*stepcount}; - ALfloat left{InSamples[OldDelay[0]++] * g}; - ALfloat right{InSamples[OldDelay[1]++] * g}; + const ALfloat g{oldGain + oldGainStep*stepcount}; + const ALfloat left{InSamples[Delay[0]++] * g}; + const ALfloat right{InSamples[Delay[1]++] * g}; ApplyCoeffs(i, AccumSamples+i, IrSize, OldCoeffs, left, right); - g = newGainStep*stepcount; - left = InSamples[NewDelay[0]++] * g; - right = InSamples[NewDelay[1]++] * g; + stepcount += 1.0f; + } + + Delay[0] = HRTF_HISTORY_LENGTH - newparams->Delay[0]; + Delay[1] = HRTF_HISTORY_LENGTH - newparams->Delay[1]; + ASSUME(Delay[0] >= 0 && Delay[1] >= 0); + stepcount = 0.0f; + for(ALsizei i{0};i < BufferSize;++i) + { + const ALfloat g{newGainStep*stepcount}; + const ALfloat left{InSamples[Delay[0]++] * g}; + const ALfloat right{InSamples[Delay[1]++] * g}; ApplyCoeffs(i, AccumSamples+i, IrSize, NewCoeffs, left, right); stepcount += 1.0f; } + for(ALsizei i{0};i < BufferSize;++i) LeftOut[OutPos+i] += AccumSamples[i][0]; for(ALsizei i{0};i < BufferSize;++i) -- cgit v1.2.3 From ba449d2b087f791ad84394c22b4d4ec528da390b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 29 May 2019 17:32:16 -0700 Subject: Pass a span to MixDirectHrtf instead of a pointer+size --- Alc/alu.cpp | 3 ++- Alc/mixer/defs.h | 4 +++- Alc/mixer/hrtfbase.h | 20 ++++++++++---------- Alc/mixer/mixer_c.cpp | 7 +++---- Alc/mixer/mixer_neon.cpp | 7 +++---- Alc/mixer/mixer_sse.cpp | 7 +++---- OpenAL32/Include/alu.h | 6 ++++-- 7 files changed, 28 insertions(+), 26 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 9f61be10..ed89f903 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -134,7 +134,8 @@ void ProcessHrtf(ALCdevice *device, const ALsizei SamplesToDo) DirectHrtfState *state{device->mHrtfState.get()}; MixDirectHrtf(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], - device->Dry.Buffer, device->HrtfAccumData, state, device->Dry.NumChannels, SamplesToDo); + {device->Dry.Buffer,device->Dry.Buffer+device->Dry.NumChannels}, device->HrtfAccumData, + state, SamplesToDo); } void ProcessAmbiDec(ALCdevice *device, const ALsizei SamplesToDo) diff --git a/Alc/mixer/defs.h b/Alc/mixer/defs.h index a6131958..3de6b01e 100644 --- a/Alc/mixer/defs.h +++ b/Alc/mixer/defs.h @@ -6,6 +6,8 @@ #include "alMain.h" #include "alu.h" +#include "alspan.h" + struct MixGains; struct MixHrtfParams; @@ -39,7 +41,7 @@ void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat template void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, const ALsizei BufferSize); template -void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const FloatBufferLine *InSamples, float2 *AccumSamples, DirectHrtfState *State, const ALsizei NumChans, const ALsizei BufferSize); +void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, const ALsizei BufferSize); /* Vectorized resampler helpers */ inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *RESTRICT frac_arr, ALsizei *RESTRICT pos_arr, ALsizei size) diff --git a/Alc/mixer/hrtfbase.h b/Alc/mixer/hrtfbase.h index 571cdc89..bce9e573 100644 --- a/Alc/mixer/hrtfbase.h +++ b/Alc/mixer/hrtfbase.h @@ -102,22 +102,21 @@ inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut template inline void MixDirectHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const FloatBufferLine *InSamples, float2 *RESTRICT AccumSamples, DirectHrtfState *State, - const ALsizei NumChans, const ALsizei BufferSize) + const al::span InSamples, float2 *RESTRICT AccumSamples, + DirectHrtfState *State, const ALsizei BufferSize) { - ASSUME(NumChans > 0); ASSUME(BufferSize > 0); const ALsizei IrSize{State->IrSize}; ASSUME(IrSize >= 4); - for(ALsizei c{0};c < NumChans;++c) + auto chanstate = State->Chan.begin(); + for(const FloatBufferLine &input : InSamples) { - const FloatBufferLine &input = InSamples[c]; - const auto &Coeffs = State->Chan[c].Coeffs; + const auto &Coeffs = chanstate->Coeffs; - auto accum_iter = std::copy_n(State->Chan[c].Values.begin(), - State->Chan[c].Values.size(), AccumSamples); + auto accum_iter = std::copy_n(chanstate->Values.begin(), + chanstate->Values.size(), AccumSamples); std::fill_n(accum_iter, BufferSize, float2{}); for(ALsizei i{0};i < BufferSize;++i) @@ -130,8 +129,9 @@ inline void MixDirectHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOu for(ALsizei i{0};i < BufferSize;++i) RightOut[i] += AccumSamples[i][1]; - std::copy_n(AccumSamples + BufferSize, State->Chan[c].Values.size(), - State->Chan[c].Values.begin()); + std::copy_n(AccumSamples + BufferSize, chanstate->Values.size(), + chanstate->Values.begin()); + ++chanstate; } } diff --git a/Alc/mixer/mixer_c.cpp b/Alc/mixer/mixer_c.cpp index 79ee305b..8ad3aca3 100644 --- a/Alc/mixer/mixer_c.cpp +++ b/Alc/mixer/mixer_c.cpp @@ -136,11 +136,10 @@ void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const FloatBufferLine *InSamples, float2 *AccumSamples, DirectHrtfState *State, - const ALsizei NumChans, const ALsizei BufferSize) + const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, + const ALsizei BufferSize) { - MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, NumChans, - BufferSize); + MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, BufferSize); } diff --git a/Alc/mixer/mixer_neon.cpp b/Alc/mixer/mixer_neon.cpp index e6f257fd..6f4af98b 100644 --- a/Alc/mixer/mixer_neon.cpp +++ b/Alc/mixer/mixer_neon.cpp @@ -182,11 +182,10 @@ void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const FloatBufferLine *InSamples, float2 *AccumSamples, DirectHrtfState *State, - const ALsizei NumChans, const ALsizei BufferSize) + const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, + const ALsizei BufferSize) { - MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, NumChans, - BufferSize); + MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, BufferSize); } diff --git a/Alc/mixer/mixer_sse.cpp b/Alc/mixer/mixer_sse.cpp index a4e80256..156b3dab 100644 --- a/Alc/mixer/mixer_sse.cpp +++ b/Alc/mixer/mixer_sse.cpp @@ -139,11 +139,10 @@ void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const FloatBufferLine *InSamples, float2 *AccumSamples, DirectHrtfState *State, - const ALsizei NumChans, const ALsizei BufferSize) + const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, + const ALsizei BufferSize) { - MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, NumChans, - BufferSize); + MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, BufferSize); } diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 8653b96c..46fdb5a5 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -22,8 +22,10 @@ #include "filters/biquad.h" #include "filters/splitter.h" #include "filters/nfc.h" + #include "almalloc.h" #include "alnumeric.h" +#include "alspan.h" enum class DistanceModel; @@ -304,8 +306,8 @@ using HrtfMixerBlendFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &Ri const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, const ALsizei BufferSize); using HrtfDirectMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const FloatBufferLine *InSamples, float2 *RESTRICT AccumSamples, DirectHrtfState *State, - const ALsizei NumChans, const ALsizei BufferSize); + const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, + const ALsizei BufferSize); #define GAIN_MIX_MAX (1000.0f) /* +60dB */ -- cgit v1.2.3 From 7e6b6d7ad90f95fc95efefe7cdf996b8e2cb90fb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 29 May 2019 19:36:06 -0700 Subject: Use FloatBufferLine and span<> in the reverb effect --- Alc/effects/reverb.cpp | 92 +++++++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 42 deletions(-) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index fe660fd7..1c9e72c0 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -247,9 +247,9 @@ struct VecAllpass { ALfloat Coeff{0.0f}; ALsizei Offset[NUM_LINES][2]{}; - void processFaded(ALfloat (*RESTRICT samples)[BUFFERSIZE], ALsizei offset, + void processFaded(const al::span samples, ALsizei offset, const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, const ALsizei todo); - void processUnfaded(ALfloat (*RESTRICT samples)[BUFFERSIZE], ALsizei offset, + void processUnfaded(const al::span samples, ALsizei offset, const ALfloat xCoeff, const ALfloat yCoeff, const ALsizei todo); }; @@ -371,9 +371,9 @@ struct ReverbState final : public EffectState { ALsizei mOffset{0}; /* Temporary storage used when processing. */ - alignas(16) ALfloat mTempSamples[NUM_LINES][BUFFERSIZE]{}; - alignas(16) ALfloat mEarlyBuffer[NUM_LINES][BUFFERSIZE]{}; - alignas(16) ALfloat mLateBuffer[NUM_LINES][BUFFERSIZE]{}; + alignas(16) FloatBufferLine mTempSamples[NUM_LINES]{}; + alignas(16) FloatBufferLine mEarlyBuffer[NUM_LINES]{}; + alignas(16) FloatBufferLine mLateBuffer[NUM_LINES]{}; using MixOutT = void (ReverbState::*)(const ALsizei numOutput, FloatBufferLine *samplesOut, const ALsizei todo); @@ -390,18 +390,22 @@ struct ReverbState final : public EffectState { /* Convert back to B-Format, and mix the results to output. */ for(ALsizei c{0};c < NUM_LINES;c++) { - std::fill_n(std::begin(mTempSamples[0]), todo, 0.0f); - MixRowSamples(mTempSamples[0], A2B[c], mEarlyBuffer, NUM_LINES, 0, todo); - MixSamples(mTempSamples[0], numOutput, + std::fill_n(mTempSamples[0].begin(), todo, 0.0f); + MixRowSamples(mTempSamples[0].data(), A2B[c], + &reinterpret_cast(mEarlyBuffer[0]), NUM_LINES, 0, + todo); + MixSamples(mTempSamples[0].data(), numOutput, &reinterpret_cast(samplesOut[0]), mEarly.CurrentGain[c], mEarly.PanGain[c], todo, 0, todo); } for(ALsizei c{0};c < NUM_LINES;c++) { - std::fill_n(std::begin(mTempSamples[0]), todo, 0.0f); - MixRowSamples(mTempSamples[0], A2B[c], mLateBuffer, NUM_LINES, 0, todo); - MixSamples(mTempSamples[0], numOutput, + std::fill_n(mTempSamples[0].begin(), todo, 0.0f); + MixRowSamples(mTempSamples[0].data(), A2B[c], + &reinterpret_cast(mLateBuffer[0]), NUM_LINES, 0, + todo); + MixSamples(mTempSamples[0].data(), numOutput, &reinterpret_cast(samplesOut[0]), mLate.CurrentGain[c], mLate.PanGain[c], todo, 0, todo); } @@ -413,29 +417,33 @@ struct ReverbState final : public EffectState { for(ALsizei c{0};c < NUM_LINES;c++) { - std::fill_n(std::begin(mTempSamples[0]), todo, 0.0f); - MixRowSamples(mTempSamples[0], A2B[c], mEarlyBuffer, NUM_LINES, 0, todo); + std::fill_n(mTempSamples[0].begin(), todo, 0.0f); + MixRowSamples(mTempSamples[0].data(), A2B[c], + &reinterpret_cast(mEarlyBuffer[0]), NUM_LINES, 0, + todo); /* Apply scaling to the B-Format's HF response to "upsample" it to * higher-order output. */ const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; - mAmbiSplitter[0][c].applyHfScale(mTempSamples[0], hfscale, todo); + mAmbiSplitter[0][c].applyHfScale(mTempSamples[0].data(), hfscale, todo); - MixSamples(mTempSamples[0], numOutput, + MixSamples(mTempSamples[0].data(), numOutput, &reinterpret_cast(samplesOut[0]), mEarly.CurrentGain[c], mEarly.PanGain[c], todo, 0, todo); } for(ALsizei c{0};c < NUM_LINES;c++) { - std::fill_n(std::begin(mTempSamples[0]), todo, 0.0f); - MixRowSamples(mTempSamples[0], A2B[c], mLateBuffer, NUM_LINES, 0, todo); + std::fill_n(mTempSamples[0].begin(), todo, 0.0f); + MixRowSamples(mTempSamples[0].data(), A2B[c], + &reinterpret_cast(mLateBuffer[0]), NUM_LINES, 0, + todo); const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; - mAmbiSplitter[1][c].applyHfScale(mTempSamples[0], hfscale, todo); + mAmbiSplitter[1][c].applyHfScale(mTempSamples[0].data(), hfscale, todo); - MixSamples(mTempSamples[0], numOutput, + MixSamples(mTempSamples[0].data(), numOutput, &reinterpret_cast(samplesOut[0]), mLate.CurrentGain[c], mLate.PanGain[c], todo, 0, todo); } @@ -1051,7 +1059,7 @@ inline void VectorPartialScatter(ALfloat *RESTRICT out, const ALfloat *RESTRICT /* Utilizes the above, but reverses the input channels. */ void VectorScatterRevDelayIn(const DelayLineI delay, ALint offset, const ALfloat xCoeff, - const ALfloat yCoeff, const ALsizei base, const ALfloat (*RESTRICT in)[BUFFERSIZE], + const ALfloat yCoeff, const ALsizei base, const al::span in, const ALsizei count) { ASSUME(base >= 0); @@ -1082,7 +1090,7 @@ void VectorScatterRevDelayIn(const DelayLineI delay, ALint offset, const ALfloat * Two static specializations are used for transitional (cross-faded) delay * line processing and non-transitional processing. */ -void VecAllpass::processUnfaded(ALfloat (*RESTRICT samples)[BUFFERSIZE], ALsizei offset, +void VecAllpass::processUnfaded(const al::span samples, ALsizei offset, const ALfloat xCoeff, const ALfloat yCoeff, const ALsizei todo) { const DelayLineI delay{Delay}; @@ -1120,7 +1128,7 @@ void VecAllpass::processUnfaded(ALfloat (*RESTRICT samples)[BUFFERSIZE], ALsizei } while(--td); } } -void VecAllpass::processFaded(ALfloat (*RESTRICT samples)[BUFFERSIZE], ALsizei offset, +void VecAllpass::processFaded(const al::span samples, ALsizei offset, const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, const ALsizei todo) { const DelayLineI delay{Delay}; @@ -1191,9 +1199,9 @@ void VecAllpass::processFaded(ALfloat (*RESTRICT samples)[BUFFERSIZE], ALsizei o * line processing and non-transitional processing. */ void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei todo, - const ALsizei base, ALfloat (*RESTRICT out)[BUFFERSIZE]) + const ALsizei base, const al::span out) { - ALfloat (*RESTRICT temps)[BUFFERSIZE]{State->mTempSamples}; + const al::span temps{State->mTempSamples}; const DelayLineI early_delay{State->mEarly.Delay}; const DelayLineI main_delay{State->mDelay}; const ALfloat mixX{State->mMixX}; @@ -1243,7 +1251,7 @@ void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALs } } for(ALsizei j{0};j < NUM_LINES;j++) - early_delay.write(offset, NUM_LINES-1-j, temps[j], todo); + early_delay.write(offset, NUM_LINES-1-j, temps[j].data(), todo); /* Also write the result back to the main delay line for the late reverb * stage to pick up at the appropriate time, appplying a scatter and @@ -1253,9 +1261,9 @@ void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALs VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, out, todo); } void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, - const ALfloat fade, const ALsizei base, ALfloat (*RESTRICT out)[BUFFERSIZE]) + const ALfloat fade, const ALsizei base, const al::span out) { - ALfloat (*RESTRICT temps)[BUFFERSIZE]{State->mTempSamples}; + const al::span temps{State->mTempSamples}; const DelayLineI early_delay{State->mEarly.Delay}; const DelayLineI main_delay{State->mDelay}; const ALfloat mixX{State->mMixX}; @@ -1318,7 +1326,7 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz } } for(ALsizei j{0};j < NUM_LINES;j++) - early_delay.write(offset, NUM_LINES-1-j, temps[j], todo); + early_delay.write(offset, NUM_LINES-1-j, temps[j].data(), todo); const ALsizei late_feed_tap{offset - State->mLateFeedTap}; VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, out, todo); @@ -1339,9 +1347,9 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz * processing and one for non-transitional processing. */ void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei todo, - const ALsizei base, ALfloat (*RESTRICT out)[BUFFERSIZE]) + const ALsizei base, const al::span out) { - ALfloat (*RESTRICT temps)[BUFFERSIZE]{State->mTempSamples}; + const al::span temps{State->mTempSamples}; const DelayLineI late_delay{State->mLate.Delay}; const DelayLineI main_delay{State->mDelay}; const ALfloat mixX{State->mMixX}; @@ -1371,7 +1379,7 @@ void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei late_delay.Line[late_feedb_tap++][j]*midGain; } while(--td); } - State->mLate.T60[j].process(temps[j], todo); + State->mLate.T60[j].process(temps[j].data(), todo); } /* Apply a vector all-pass to improve micro-surface diffusion, and write @@ -1380,15 +1388,15 @@ void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei State->mLate.VecAp.processUnfaded(temps, offset, mixX, mixY, todo); for(ALsizei j{0};j < NUM_LINES;j++) - std::copy_n(temps[j], todo, out[j]+base); + std::copy_n(temps[j].begin(), todo, out[j].begin()+base); /* Finally, scatter and bounce the results to refeed the feedback buffer. */ VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, out, todo); } void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, - const ALfloat fade, const ALsizei base, ALfloat (*RESTRICT out)[BUFFERSIZE]) + const ALfloat fade, const ALsizei base, const al::span out) { - ALfloat (*RESTRICT temps)[BUFFERSIZE]{State->mTempSamples}; + const al::span temps{State->mTempSamples}; const DelayLineI late_delay{State->mLate.Delay}; const DelayLineI main_delay{State->mDelay}; const ALfloat mixX{State->mMixX}; @@ -1435,13 +1443,13 @@ void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei to late_delay.Line[late_feedb_tap1++][j]*gfade1; } while(--td); } - State->mLate.T60[j].process(temps[j], todo); + State->mLate.T60[j].process(temps[j].data(), todo); } State->mLate.VecAp.processFaded(temps, offset, mixX, mixY, fade, todo); for(ALsizei j{0};j < NUM_LINES;j++) - std::copy_n(temps[j], todo, out[j]+base); + std::copy_n(temps[j].begin(), todo, out[j].begin()+base); VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, out, todo); } @@ -1453,17 +1461,17 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST ASSUME(samplesToDo > 0); /* Convert B-Format to A-Format for processing. */ - ALfloat (&afmt)[NUM_LINES][BUFFERSIZE] = mTempSamples; + const al::span afmt{mTempSamples}; for(ALsizei c{0};c < NUM_LINES;c++) { - std::fill_n(std::begin(afmt[c]), samplesToDo, 0.0f); - MixRowSamples(afmt[c], B2A[c], + std::fill_n(afmt[c].begin(), samplesToDo, 0.0f); + MixRowSamples(afmt[c].data(), B2A[c], &reinterpret_cast(samplesIn[0]), numInput, 0, samplesToDo); /* Band-pass the incoming samples. */ - mFilter[c].Lp.process(afmt[c], afmt[c], samplesToDo); - mFilter[c].Hp.process(afmt[c], afmt[c], samplesToDo); + mFilter[c].Lp.process(afmt[c].data(), afmt[c].data(), samplesToDo); + mFilter[c].Hp.process(afmt[c].data(), afmt[c].data(), samplesToDo); } /* Process reverb for these samples. */ @@ -1484,7 +1492,7 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST /* Feed the initial delay line. */ for(ALsizei c{0};c < NUM_LINES;c++) - mDelay.write(offset, c, afmt[c]+base, todo); + mDelay.write(offset, c, afmt[c].data()+base, todo); /* Process the samples for reverb. */ if(UNLIKELY(fadeCount < FADE_SAMPLES)) -- cgit v1.2.3 From 8af7b4c6e0ddaf4d66455702a7ede0c9036f3825 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 29 May 2019 20:45:33 -0700 Subject: Use FloatBufferLine and span<> for MixRowSamples --- Alc/bformatdec.cpp | 15 ++++++--------- Alc/effects/reverb.cpp | 20 +++++--------------- Alc/mixer/defs.h | 2 +- Alc/mixer/mixer_c.cpp | 11 +++++------ Alc/mixer/mixer_neon.cpp | 13 ++++++------- Alc/mixer/mixer_sse.cpp | 11 +++++------ OpenAL32/Include/alu.h | 4 ++-- 7 files changed, 30 insertions(+), 46 deletions(-) diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 33659e04..5d9b3503 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -157,29 +157,26 @@ void BFormatDec::process(FloatBufferLine *OutBuffer, const ALsizei OutChannels, mXOver[i].process(mSamplesHF[i].data(), mSamplesLF[i].data(), InSamples[i].data(), SamplesToDo); + const al::span hfsamples{mSamplesHF, mSamplesHF+mNumChannels}; + const al::span lfsamples{mSamplesLF, mSamplesLF+mNumChannels}; for(ALsizei chan{0};chan < OutChannels;chan++) { if(UNLIKELY(!(mEnabled&(1<(mSamplesHF[0]), - mNumChannels, 0, SamplesToDo); - MixRowSamples(OutBuffer[chan].data(), mMatrix.Dual[chan][sLFBand], - &reinterpret_cast(mSamplesLF[0]), - mNumChannels, 0, SamplesToDo); + MixRowSamples(OutBuffer[chan], mMatrix.Dual[chan][sHFBand], hfsamples, 0, SamplesToDo); + MixRowSamples(OutBuffer[chan], mMatrix.Dual[chan][sLFBand], lfsamples, 0, SamplesToDo); } } else { + const al::span insamples{InSamples, InSamples+mNumChannels}; for(ALsizei chan{0};chan < OutChannels;chan++) { if(UNLIKELY(!(mEnabled&(1<(InSamples[0]), mNumChannels, 0, - SamplesToDo); + MixRowSamples(OutBuffer[chan], mMatrix.Single[chan], insamples, 0, SamplesToDo); } } } diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 1c9e72c0..74c9d3fc 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -391,9 +391,7 @@ struct ReverbState final : public EffectState { for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempSamples[0].begin(), todo, 0.0f); - MixRowSamples(mTempSamples[0].data(), A2B[c], - &reinterpret_cast(mEarlyBuffer[0]), NUM_LINES, 0, - todo); + MixRowSamples(mTempSamples[0], A2B[c], mEarlyBuffer, 0, todo); MixSamples(mTempSamples[0].data(), numOutput, &reinterpret_cast(samplesOut[0]), mEarly.CurrentGain[c], mEarly.PanGain[c], todo, 0, todo); @@ -402,9 +400,7 @@ struct ReverbState final : public EffectState { for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempSamples[0].begin(), todo, 0.0f); - MixRowSamples(mTempSamples[0].data(), A2B[c], - &reinterpret_cast(mLateBuffer[0]), NUM_LINES, 0, - todo); + MixRowSamples(mTempSamples[0], A2B[c], mLateBuffer, 0, todo); MixSamples(mTempSamples[0].data(), numOutput, &reinterpret_cast(samplesOut[0]), mLate.CurrentGain[c], mLate.PanGain[c], todo, 0, todo); @@ -418,9 +414,7 @@ struct ReverbState final : public EffectState { for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempSamples[0].begin(), todo, 0.0f); - MixRowSamples(mTempSamples[0].data(), A2B[c], - &reinterpret_cast(mEarlyBuffer[0]), NUM_LINES, 0, - todo); + MixRowSamples(mTempSamples[0], A2B[c], mEarlyBuffer, 0, todo); /* Apply scaling to the B-Format's HF response to "upsample" it to * higher-order output. @@ -436,9 +430,7 @@ struct ReverbState final : public EffectState { for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempSamples[0].begin(), todo, 0.0f); - MixRowSamples(mTempSamples[0].data(), A2B[c], - &reinterpret_cast(mLateBuffer[0]), NUM_LINES, 0, - todo); + MixRowSamples(mTempSamples[0], A2B[c], mLateBuffer, 0, todo); const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; mAmbiSplitter[1][c].applyHfScale(mTempSamples[0].data(), hfscale, todo); @@ -1465,9 +1457,7 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(afmt[c].begin(), samplesToDo, 0.0f); - MixRowSamples(afmt[c].data(), B2A[c], - &reinterpret_cast(samplesIn[0]), numInput, 0, - samplesToDo); + MixRowSamples(afmt[c], B2A[c], {samplesIn, samplesIn+numInput}, 0, samplesToDo); /* Band-pass the incoming samples. */ mFilter[c].Lp.process(afmt[c].data(), afmt[c].data(), samplesToDo); diff --git a/Alc/mixer/defs.h b/Alc/mixer/defs.h index 3de6b01e..e661b238 100644 --- a/Alc/mixer/defs.h +++ b/Alc/mixer/defs.h @@ -34,7 +34,7 @@ const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, template void Mix_(const ALfloat *data, const ALsizei OutChans, ALfloat (*OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize); template -void MixRow_(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*data)[BUFFERSIZE], const ALsizei InChans, const ALsizei InPos, const ALsizei BufferSize); +void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize); template void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfParams *hrtfparams, const ALsizei BufferSize); diff --git a/Alc/mixer/mixer_c.cpp b/Alc/mixer/mixer_c.cpp index 8ad3aca3..d1bbd25e 100644 --- a/Alc/mixer/mixer_c.cpp +++ b/Alc/mixer/mixer_c.cpp @@ -190,16 +190,15 @@ void Mix_(const ALfloat *data, const ALsizei OutChans, ALfloat (*OutBuffer * stepping is necessary. */ template<> -void MixRow_(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*data)[BUFFERSIZE], - const ALsizei InChans, const ALsizei InPos, const ALsizei BufferSize) +void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, + const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize) { - ASSUME(InChans > 0); ASSUME(BufferSize > 0); - for(ALsizei c{0};c < InChans;c++) + for(const FloatBufferLine &input : InSamples) { - const ALfloat *RESTRICT src{&data[c][InPos]}; - const ALfloat gain{Gains[c]}; + const ALfloat *RESTRICT src{input.data()+InPos}; + const ALfloat gain{*(Gains++)}; if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; diff --git a/Alc/mixer/mixer_neon.cpp b/Alc/mixer/mixer_neon.cpp index 6f4af98b..300d421f 100644 --- a/Alc/mixer/mixer_neon.cpp +++ b/Alc/mixer/mixer_neon.cpp @@ -276,20 +276,19 @@ void Mix_(const ALfloat *data, const ALsizei OutChans, ALfloat (*OutBuf } template<> -void MixRow_(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*data)[BUFFERSIZE], - const ALsizei InChans, const ALsizei InPos, const ALsizei BufferSize) +void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, + const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize) { - ASSUME(InChans > 0); ASSUME(BufferSize > 0); - for(ALsizei c{0};c < InChans;c++) + for(const FloatBufferLine &input : InSamples) { - const ALfloat *RESTRICT src{al::assume_aligned<16>(&data[c][InPos])}; - ALsizei pos{0}; - const ALfloat gain{Gains[c]}; + const ALfloat *RESTRICT src{al::assume_aligned<16>(input.data()+InPos)}; + const ALfloat gain{*(Gains++)}; if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; + ALsizei pos{0}; if(LIKELY(BufferSize > 3)) { ALsizei todo{BufferSize >> 2}; diff --git a/Alc/mixer/mixer_sse.cpp b/Alc/mixer/mixer_sse.cpp index 156b3dab..ac1c9b18 100644 --- a/Alc/mixer/mixer_sse.cpp +++ b/Alc/mixer/mixer_sse.cpp @@ -230,16 +230,15 @@ void Mix_(const ALfloat *data, const ALsizei OutChans, ALfloat (*OutBuff } template<> -void MixRow_(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*data)[BUFFERSIZE], - const ALsizei InChans, const ALsizei InPos, const ALsizei BufferSize) +void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, + const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize) { - ASSUME(InChans > 0); ASSUME(BufferSize > 0); - for(ALsizei c{0};c < InChans;c++) + for(const FloatBufferLine &input : InSamples) { - const ALfloat *RESTRICT src{al::assume_aligned<16>(&data[c][InPos])}; - const ALfloat gain{Gains[c]}; + const ALfloat *RESTRICT src{al::assume_aligned<16>(input.data()+InPos)}; + const ALfloat gain{*(Gains++)}; if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 46fdb5a5..49abe0f3 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -296,8 +296,8 @@ void DeinitVoice(ALvoice *voice) noexcept; using MixerFunc = void(*)(const ALfloat *data, const ALsizei OutChans, ALfloat (*OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize); -using RowMixerFunc = void(*)(ALfloat *OutBuffer, const ALfloat *gains, - const ALfloat (*data)[BUFFERSIZE], const ALsizei InChans, const ALsizei InPos, +using RowMixerFunc = void(*)(FloatBufferLine &OutBuffer, const ALfloat *gains, + const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize); using HrtfMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, -- cgit v1.2.3 From 893ffe9a84d497d38e6e472b0cffbd9c37e0c366 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 29 May 2019 21:58:37 -0700 Subject: Use span for MixSamples --- Alc/effects/autowah.cpp | 19 +++++++++---------- Alc/effects/chorus.cpp | 14 ++++++-------- Alc/effects/dedicated.cpp | 5 ++--- Alc/effects/echo.cpp | 6 +++--- Alc/effects/equalizer.cpp | 6 +++--- Alc/effects/fshifter.cpp | 4 ++-- Alc/effects/modulator.cpp | 10 +++++----- Alc/effects/pshifter.cpp | 4 ++-- Alc/effects/reverb.cpp | 24 ++++++++++-------------- Alc/mixer/defs.h | 2 +- Alc/mixer/mixer_c.cpp | 19 ++++++++++--------- Alc/mixer/mixer_neon.cpp | 19 ++++++++++--------- Alc/mixer/mixer_sse.cpp | 19 ++++++++++--------- Alc/mixvoice.cpp | 30 +++++++++++++++--------------- OpenAL32/Include/alu.h | 6 +++--- 15 files changed, 91 insertions(+), 96 deletions(-) diff --git a/Alc/effects/autowah.cpp b/Alc/effects/autowah.cpp index 2b01f70a..2b0cb610 100644 --- a/Alc/effects/autowah.cpp +++ b/Alc/effects/autowah.cpp @@ -136,11 +136,9 @@ void ALautowahState::process(const ALsizei samplesToDo, const FloatBufferLine *R const ALfloat peak_gain = mPeakGain; const ALfloat freq_min = mFreqMinNorm; const ALfloat bandwidth = mBandwidthNorm; - ALfloat env_delay; - ALsizei c, i; - env_delay = mEnvDelay; - for(i = 0;i < samplesToDo;i++) + ALfloat env_delay{mEnvDelay}; + for(ALsizei i{0};i < samplesToDo;i++) { ALfloat w0, sample, a; @@ -158,8 +156,9 @@ void ALautowahState::process(const ALsizei samplesToDo, const FloatBufferLine *R } mEnvDelay = env_delay; + const al::span output{samplesOut, samplesOut+numOutput}; ASSUME(numInput > 0); - for(c = 0;c < numInput;++c) + for(ALsizei c{0};c < numInput;++c) { /* This effectively inlines BiquadFilter_setParams for a peaking * filter and BiquadFilter_processC. The alpha and cosine components @@ -167,10 +166,10 @@ void ALautowahState::process(const ALsizei samplesToDo, const FloatBufferLine *R * envelope. Because the filter changes for each sample, the * coefficients are transient and don't need to be held. */ - ALfloat z1 = mChans[c].Filter.z1; - ALfloat z2 = mChans[c].Filter.z2; + ALfloat z1{mChans[c].Filter.z1}; + ALfloat z2{mChans[c].Filter.z2}; - for(i = 0;i < samplesToDo;i++) + for(ALsizei i{0};i < samplesToDo;i++) { const ALfloat alpha = mEnv[i].alpha; const ALfloat cos_w0 = mEnv[i].cos_w0; @@ -194,8 +193,8 @@ void ALautowahState::process(const ALsizei samplesToDo, const FloatBufferLine *R mChans[c].Filter.z2 = z2; /* Now, mix the processed sound data to the output. */ - MixSamples(mBufferOut, numOutput, &reinterpret_cast(samplesOut[0]), - mChans[c].CurrentGains, mChans[c].TargetGains, samplesToDo, 0, samplesToDo); + MixSamples(mBufferOut, output, mChans[c].CurrentGains, mChans[c].TargetGains, samplesToDo, + 0, samplesToDo); } } diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp index e953d3e3..cdbb2036 100644 --- a/Alc/effects/chorus.cpp +++ b/Alc/effects/chorus.cpp @@ -205,10 +205,9 @@ void ChorusState::process(const ALsizei samplesToDo, const FloatBufferLine *REST const ALsizei avgdelay{(mDelay + (FRACTIONONE>>1)) >> FRACTIONBITS}; ALfloat *RESTRICT delaybuf{mSampleBuffer.data()}; ALsizei offset{mOffset}; - ALsizei i, c; - ALsizei base; - for(base = 0;base < samplesToDo;) + const al::span output{samplesOut, samplesOut+numOutput}; + for(ALsizei base{0};base < samplesToDo;) { const ALsizei todo = mini(256, samplesToDo-base); ALint moddelays[2][256]; @@ -230,7 +229,7 @@ void ChorusState::process(const ALsizei samplesToDo, const FloatBufferLine *REST } mLfoOffset = (mLfoOffset+todo) % mLfoRange; - for(i = 0;i < todo;i++) + for(ALsizei i{0};i < todo;i++) { // Feed the buffer's input first (necessary for delays < 1). delaybuf[offset&bufmask] = samplesIn[0][base+i]; @@ -254,10 +253,9 @@ void ChorusState::process(const ALsizei samplesToDo, const FloatBufferLine *REST offset++; } - for(c = 0;c < 2;c++) - MixSamples(temps[c], numOutput, - &reinterpret_cast(samplesOut[0]), mGains[c].Current, - mGains[c].Target, samplesToDo-base, base, todo); + for(ALsizei c{0};c < 2;c++) + MixSamples(temps[c], output, mGains[c].Current, mGains[c].Target, samplesToDo-base, + base, todo); base += todo; } diff --git a/Alc/effects/dedicated.cpp b/Alc/effects/dedicated.cpp index 7b44e392..b4eaa8e8 100644 --- a/Alc/effects/dedicated.cpp +++ b/Alc/effects/dedicated.cpp @@ -92,9 +92,8 @@ void DedicatedState::update(const ALCcontext* UNUSED(context), const ALeffectslo void DedicatedState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) { - MixSamples(samplesIn[0].data(), numOutput, - &reinterpret_cast(samplesOut[0]), mCurrentGains, mTargetGains, - samplesToDo, 0, samplesToDo); + MixSamples(samplesIn[0].data(), {samplesOut, samplesOut+numOutput}, mCurrentGains, + mTargetGains, samplesToDo, 0, samplesToDo); } diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index e684039d..e82e75bd 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -157,10 +157,10 @@ void EchoState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRI mFilter.setComponents(z1, z2); mOffset = offset; + const al::span output{samplesOut, samplesOut+numOutput}; for(ALsizei c{0};c < 2;c++) - MixSamples(mTempBuffer[c], numOutput, - &reinterpret_cast(samplesOut[0]), mGains[c].Current, - mGains[c].Target, samplesToDo, 0, samplesToDo); + MixSamples(mTempBuffer[c], output, mGains[c].Current, mGains[c].Target, samplesToDo, 0, + samplesToDo); } diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index 53f8e153..f6be258b 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -160,6 +160,7 @@ void EqualizerState::update(const ALCcontext *context, const ALeffectslot *slot, void EqualizerState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) { + const al::span output{samplesOut, samplesOut+numOutput}; ASSUME(numInput > 0); for(ALsizei c{0};c < numInput;c++) { @@ -168,9 +169,8 @@ void EqualizerState::process(const ALsizei samplesToDo, const FloatBufferLine *R mChans[c].filter[2].process(mSampleBuffer, mSampleBuffer, samplesToDo); mChans[c].filter[3].process(mSampleBuffer, mSampleBuffer, samplesToDo); - MixSamples(mSampleBuffer, numOutput, - &reinterpret_cast(samplesOut[0]), mChans[c].CurrentGains, - mChans[c].TargetGains, samplesToDo, 0, samplesToDo); + MixSamples(mSampleBuffer, output, mChans[c].CurrentGains, mChans[c].TargetGains, + samplesToDo, 0, samplesToDo); } } diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp index 0b8d33e4..56068b06 100644 --- a/Alc/effects/fshifter.cpp +++ b/Alc/effects/fshifter.cpp @@ -198,8 +198,8 @@ void FshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE } /* Now, mix the processed sound data to the output. */ - MixSamples(BufferOut, numOutput, &reinterpret_cast(samplesOut[0]), - mCurrentGains, mTargetGains, maxi(samplesToDo, 512), 0, samplesToDo); + MixSamples(BufferOut, {samplesOut, samplesOut+numOutput}, mCurrentGains, mTargetGains, + maxi(samplesToDo, 512), 0, samplesToDo); } diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index ec0b6184..9b7abbb7 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -143,10 +143,10 @@ void ModulatorState::update(const ALCcontext *context, const ALeffectslot *slot, void ModulatorState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) { - const ALsizei step = mStep; - ALsizei base; + const ALsizei step{mStep}; - for(base = 0;base < samplesToDo;) + const al::span output{samplesOut, samplesOut+numOutput}; + for(ALsizei base{0};base < samplesToDo;) { alignas(16) ALfloat modsamples[MAX_UPDATE_SAMPLES]; ALsizei td = mini(MAX_UPDATE_SAMPLES, samplesToDo-base); @@ -165,8 +165,8 @@ void ModulatorState::process(const ALsizei samplesToDo, const FloatBufferLine *R for(i = 0;i < td;i++) temps[i] *= modsamples[i]; - MixSamples(temps, numOutput, &reinterpret_cast(samplesOut[0]), - mChans[c].CurrentGains, mChans[c].TargetGains, samplesToDo-base, base, td); + MixSamples(temps, output, mChans[c].CurrentGains, mChans[c].TargetGains, + samplesToDo-base, base, td); } base += td; diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp index a3e946c0..34f442bc 100644 --- a/Alc/effects/pshifter.cpp +++ b/Alc/effects/pshifter.cpp @@ -321,8 +321,8 @@ void PshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE mCount = count; /* Now, mix the processed sound data to the output. */ - MixSamples(bufferOut, numOutput, &reinterpret_cast(samplesOut[0]), - mCurrentGains, mTargetGains, maxi(samplesToDo, 512), 0, samplesToDo); + MixSamples(bufferOut, {samplesOut, samplesOut+numOutput}, mCurrentGains, mTargetGains, + maxi(samplesToDo, 512), 0, samplesToDo); } diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 74c9d3fc..5d2f25f9 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -375,7 +375,7 @@ struct ReverbState final : public EffectState { alignas(16) FloatBufferLine mEarlyBuffer[NUM_LINES]{}; alignas(16) FloatBufferLine mLateBuffer[NUM_LINES]{}; - using MixOutT = void (ReverbState::*)(const ALsizei numOutput, FloatBufferLine *samplesOut, + using MixOutT = void (ReverbState::*)(const al::span samplesOut, const ALsizei todo); MixOutT mMixOut{&ReverbState::MixOutPlain}; @@ -383,7 +383,7 @@ struct ReverbState final : public EffectState { std::array,2> mAmbiSplitter; - void MixOutPlain(const ALsizei numOutput, FloatBufferLine *samplesOut, const ALsizei todo) + void MixOutPlain(const al::span samplesOut, const ALsizei todo) { ASSUME(todo > 0); @@ -392,8 +392,7 @@ struct ReverbState final : public EffectState { { std::fill_n(mTempSamples[0].begin(), todo, 0.0f); MixRowSamples(mTempSamples[0], A2B[c], mEarlyBuffer, 0, todo); - MixSamples(mTempSamples[0].data(), numOutput, - &reinterpret_cast(samplesOut[0]), mEarly.CurrentGain[c], + MixSamples(mTempSamples[0].data(), samplesOut, mEarly.CurrentGain[c], mEarly.PanGain[c], todo, 0, todo); } @@ -401,13 +400,12 @@ struct ReverbState final : public EffectState { { std::fill_n(mTempSamples[0].begin(), todo, 0.0f); MixRowSamples(mTempSamples[0], A2B[c], mLateBuffer, 0, todo); - MixSamples(mTempSamples[0].data(), numOutput, - &reinterpret_cast(samplesOut[0]), mLate.CurrentGain[c], - mLate.PanGain[c], todo, 0, todo); + MixSamples(mTempSamples[0].data(), samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], + todo, 0, todo); } } - void MixOutAmbiUp(const ALsizei numOutput, FloatBufferLine *samplesOut, const ALsizei todo) + void MixOutAmbiUp(const al::span samplesOut, const ALsizei todo) { ASSUME(todo > 0); @@ -422,8 +420,7 @@ struct ReverbState final : public EffectState { const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; mAmbiSplitter[0][c].applyHfScale(mTempSamples[0].data(), hfscale, todo); - MixSamples(mTempSamples[0].data(), numOutput, - &reinterpret_cast(samplesOut[0]), mEarly.CurrentGain[c], + MixSamples(mTempSamples[0].data(), samplesOut, mEarly.CurrentGain[c], mEarly.PanGain[c], todo, 0, todo); } @@ -435,9 +432,8 @@ struct ReverbState final : public EffectState { const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; mAmbiSplitter[1][c].applyHfScale(mTempSamples[0].data(), hfscale, todo); - MixSamples(mTempSamples[0].data(), numOutput, - &reinterpret_cast(samplesOut[0]), mLate.CurrentGain[c], - mLate.PanGain[c], todo, 0, todo); + MixSamples(mTempSamples[0].data(), samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], + todo, 0, todo); } } @@ -1530,7 +1526,7 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST mFadeCount = fadeCount; /* Finally, mix early reflections and late reverb. */ - (this->*mMixOut)(numOutput, samplesOut, samplesToDo); + (this->*mMixOut)({samplesOut, samplesOut+numOutput}, samplesToDo); } diff --git a/Alc/mixer/defs.h b/Alc/mixer/defs.h index e661b238..a86da8a1 100644 --- a/Alc/mixer/defs.h +++ b/Alc/mixer/defs.h @@ -32,7 +32,7 @@ template const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen); template -void Mix_(const ALfloat *data, const ALsizei OutChans, ALfloat (*OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize); +void Mix_(const ALfloat *data, const al::span OutBuffer, ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize); template void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize); diff --git a/Alc/mixer/mixer_c.cpp b/Alc/mixer/mixer_c.cpp index d1bbd25e..9e8f2ad5 100644 --- a/Alc/mixer/mixer_c.cpp +++ b/Alc/mixer/mixer_c.cpp @@ -144,21 +144,20 @@ void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> -void Mix_(const ALfloat *data, const ALsizei OutChans, ALfloat (*OutBuffer)[BUFFERSIZE], +void Mix_(const ALfloat *data, const al::span OutBuffer, ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize) { - ASSUME(OutChans > 0); ASSUME(BufferSize > 0); const ALfloat delta{(Counter > 0) ? 1.0f / static_cast(Counter) : 0.0f}; - for(ALsizei c{0};c < OutChans;c++) + for(FloatBufferLine &output : OutBuffer) { - ALfloat *RESTRICT dst{&OutBuffer[c][OutPos]}; - ALsizei pos{0}; - ALfloat gain{CurrentGains[c]}; + ALfloat *RESTRICT dst{output.data()+OutPos}; + ALfloat gain{*CurrentGains}; + const ALfloat diff{*TargetGains - gain}; - const ALfloat diff{TargetGains[c] - gain}; + ALsizei pos{0}; if(std::fabs(diff) > std::numeric_limits::epsilon()) { ALsizei minsize{mini(BufferSize, Counter)}; @@ -170,11 +169,13 @@ void Mix_(const ALfloat *data, const ALsizei OutChans, ALfloat (*OutBuffer step_count += 1.0f; } if(pos == Counter) - gain = TargetGains[c]; + gain = *TargetGains; else gain += step*step_count; - CurrentGains[c] = gain; + *CurrentGains = gain; } + ++CurrentGains; + ++TargetGains; if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; diff --git a/Alc/mixer/mixer_neon.cpp b/Alc/mixer/mixer_neon.cpp index 300d421f..eaa09718 100644 --- a/Alc/mixer/mixer_neon.cpp +++ b/Alc/mixer/mixer_neon.cpp @@ -190,21 +190,20 @@ void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut template<> -void Mix_(const ALfloat *data, const ALsizei OutChans, ALfloat (*OutBuffer)[BUFFERSIZE], +void Mix_(const ALfloat *data, const al::span OutBuffer, ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize) { - ASSUME(OutChans > 0); ASSUME(BufferSize > 0); const ALfloat delta{(Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f}; - for(ALsizei c{0};c < OutChans;c++) + for(FloatBufferLine &output : OutBuffer) { - ALfloat *RESTRICT dst{al::assume_aligned<16>(&OutBuffer[c][OutPos])}; - ALsizei pos{0}; - ALfloat gain{CurrentGains[c]}; - const ALfloat diff{TargetGains[c] - gain}; + ALfloat *RESTRICT dst{al::assume_aligned<16>(output.data()+OutPos)}; + ALfloat gain{*CurrentGains}; + const ALfloat diff{*TargetGains - gain}; + ALsizei pos{0}; if(std::fabs(diff) > std::numeric_limits::epsilon()) { ALsizei minsize{mini(BufferSize, Counter)}; @@ -245,16 +244,18 @@ void Mix_(const ALfloat *data, const ALsizei OutChans, ALfloat (*OutBuf step_count += 1.0f; } if(pos == Counter) - gain = TargetGains[c]; + gain = *TargetGains; else gain += step*step_count; - CurrentGains[c] = gain; + *CurrentGains = gain; /* Mix until pos is aligned with 4 or the mix is done. */ minsize = mini(BufferSize, (pos+3)&~3); for(;pos < minsize;pos++) dst[pos] += data[pos]*gain; } + ++CurrentGains; + ++TargetGains; if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; diff --git a/Alc/mixer/mixer_sse.cpp b/Alc/mixer/mixer_sse.cpp index ac1c9b18..0f8b905f 100644 --- a/Alc/mixer/mixer_sse.cpp +++ b/Alc/mixer/mixer_sse.cpp @@ -147,21 +147,20 @@ void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> -void Mix_(const ALfloat *data, const ALsizei OutChans, ALfloat (*OutBuffer)[BUFFERSIZE], +void Mix_(const ALfloat *data, const al::span OutBuffer, ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize) { - ASSUME(OutChans > 0); ASSUME(BufferSize > 0); const ALfloat delta{(Counter > 0) ? 1.0f / static_cast(Counter) : 0.0f}; - for(ALsizei c{0};c < OutChans;c++) + for(FloatBufferLine &output : OutBuffer) { - ALfloat *RESTRICT dst{al::assume_aligned<16>(&OutBuffer[c][OutPos])}; - ALsizei pos{0}; - ALfloat gain{CurrentGains[c]}; - const ALfloat diff{TargetGains[c] - gain}; + ALfloat *RESTRICT dst{al::assume_aligned<16>(output.data()+OutPos)}; + ALfloat gain{*CurrentGains}; + const ALfloat diff{*TargetGains - gain}; + ALsizei pos{0}; if(std::fabs(diff) > std::numeric_limits::epsilon()) { ALsizei minsize{mini(BufferSize, Counter)}; @@ -199,16 +198,18 @@ void Mix_(const ALfloat *data, const ALsizei OutChans, ALfloat (*OutBuff step_count += 1.0f; } if(pos == Counter) - gain = TargetGains[c]; + gain = *TargetGains; else gain += step*step_count; - CurrentGains[c] = gain; + *CurrentGains = gain; /* Mix until pos is aligned with 4 or the mix is done. */ minsize = mini(BufferSize, (pos+3)&~3); for(;pos < minsize;pos++) dst[pos] += data[pos]*gain; } + ++CurrentGains; + ++TargetGains; if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index c9227919..d3b76492 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -800,23 +800,23 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? SilentTarget : parms.Gains.Target}; - MixSamples(samples, voice->mDirect.ChannelsPerOrder[0], - &reinterpret_cast(voice->mDirect.Buffer[0]), - parms.Gains.Current, TargetGains, Counter, OutPos, DstBufferSize); + const auto outcount = static_cast(voice->mDirect.ChannelsPerOrder[0]); + MixSamples(samples, {voice->mDirect.Buffer, outcount}, parms.Gains.Current, + TargetGains, Counter, OutPos, DstBufferSize); ALfloat (&nfcsamples)[BUFFERSIZE] = Device->NfcSampleData; - ALsizei chanoffset{voice->mDirect.ChannelsPerOrder[0]}; + size_t chanoffset{outcount}; using FilterProc = void (NfcFilter::*)(float*,const float*,int); auto apply_nfc = [voice,&parms,samples,TargetGains,DstBufferSize,Counter,OutPos,&chanoffset,&nfcsamples](FilterProc process, ALsizei order) -> void { - if(voice->mDirect.ChannelsPerOrder[order] < 1) - return; + const auto outcount = static_cast( + voice->mDirect.ChannelsPerOrder[order]); + if(outcount < 1) return; (parms.NFCtrlFilter.*process)(nfcsamples, samples, DstBufferSize); - MixSamples(nfcsamples, voice->mDirect.ChannelsPerOrder[order], - &reinterpret_cast(voice->mDirect.Buffer[chanoffset]), + MixSamples(nfcsamples, {voice->mDirect.Buffer+chanoffset, outcount}, parms.Gains.Current+chanoffset, TargetGains+chanoffset, Counter, OutPos, DstBufferSize); - chanoffset += voice->mDirect.ChannelsPerOrder[order]; + chanoffset += outcount; }; apply_nfc(&NfcFilter::process1, 1); apply_nfc(&NfcFilter::process2, 2); @@ -826,9 +826,9 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc { const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? SilentTarget : parms.Gains.Target}; - MixSamples(samples, voice->mDirect.Channels, - &reinterpret_cast(voice->mDirect.Buffer[0]), - parms.Gains.Current, TargetGains, Counter, OutPos, DstBufferSize); + const auto outcount = static_cast(voice->mDirect.Channels); + MixSamples(samples, {voice->mDirect.Buffer, outcount}, parms.Gains.Current, + TargetGains, Counter, OutPos, DstBufferSize); } } @@ -844,9 +844,9 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc const ALfloat *TargetGains{UNLIKELY(vstate==ALvoice::Stopping) ? SilentTarget : parms.Gains.Target}; - MixSamples(samples, send.Channels, - &reinterpret_cast(send.Buffer[0]), parms.Gains.Current, - TargetGains, Counter, OutPos, DstBufferSize); + const auto outcount = static_cast(send.Channels); + MixSamples(samples, {send.Buffer, outcount}, parms.Gains.Current, TargetGains, + Counter, OutPos, DstBufferSize); }; std::for_each(voice->mSend.begin(), voice->mSend.end(), mix_send); } diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 49abe0f3..b6914c37 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -293,9 +293,9 @@ struct ALvoice { void DeinitVoice(ALvoice *voice) noexcept; -using MixerFunc = void(*)(const ALfloat *data, const ALsizei OutChans, - ALfloat (*OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, - const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize); +using MixerFunc = void(*)(const ALfloat *data, const al::span OutBuffer, + ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, + const ALsizei BufferSize); using RowMixerFunc = void(*)(FloatBufferLine &OutBuffer, const ALfloat *gains, const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize); -- cgit v1.2.3 From 2909f263fd1a2e7122b0345c6d11209084815fd1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 29 May 2019 22:31:36 -0700 Subject: Use span for EffectState::process output --- Alc/alu.cpp | 3 ++- Alc/effects/autowah.cpp | 9 ++++----- Alc/effects/base.h | 3 ++- Alc/effects/chorus.cpp | 7 +++---- Alc/effects/compressor.cpp | 29 +++++++++++++---------------- Alc/effects/dedicated.cpp | 8 ++++---- Alc/effects/distortion.cpp | 35 ++++++++++++++++------------------- Alc/effects/echo.cpp | 7 +++---- Alc/effects/equalizer.cpp | 7 +++---- Alc/effects/fshifter.cpp | 8 ++++---- Alc/effects/modulator.cpp | 7 +++---- Alc/effects/null.cpp | 4 ++-- Alc/effects/pshifter.cpp | 8 ++++---- Alc/effects/reverb.cpp | 6 +++--- 14 files changed, 66 insertions(+), 75 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index ed89f903..2f172b99 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1466,8 +1466,9 @@ void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) [SamplesToDo](const ALeffectslot *slot) -> void { EffectState *state{slot->Params.mEffectState}; + const auto outchans = static_cast(state->mOutChannels); state->process(SamplesToDo, slot->Wet.Buffer, slot->Wet.NumChannels, - state->mOutBuffer, state->mOutChannels); + {state->mOutBuffer, outchans}); } ); } diff --git a/Alc/effects/autowah.cpp b/Alc/effects/autowah.cpp index 2b0cb610..90531229 100644 --- a/Alc/effects/autowah.cpp +++ b/Alc/effects/autowah.cpp @@ -72,7 +72,7 @@ struct ALautowahState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(ALautowahState) }; @@ -128,7 +128,7 @@ void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, } } -void ALautowahState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) +void ALautowahState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) { const ALfloat attack_rate = mAttackRate; const ALfloat release_rate = mReleaseRate; @@ -156,7 +156,6 @@ void ALautowahState::process(const ALsizei samplesToDo, const FloatBufferLine *R } mEnvDelay = env_delay; - const al::span output{samplesOut, samplesOut+numOutput}; ASSUME(numInput > 0); for(ALsizei c{0};c < numInput;++c) { @@ -193,8 +192,8 @@ void ALautowahState::process(const ALsizei samplesToDo, const FloatBufferLine *R mChans[c].Filter.z2 = z2; /* Now, mix the processed sound data to the output. */ - MixSamples(mBufferOut, output, mChans[c].CurrentGains, mChans[c].TargetGains, samplesToDo, - 0, samplesToDo); + MixSamples(mBufferOut, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, + samplesToDo, 0, samplesToDo); } } diff --git a/Alc/effects/base.h b/Alc/effects/base.h index c7c6f1c0..d2b33b9b 100644 --- a/Alc/effects/base.h +++ b/Alc/effects/base.h @@ -4,6 +4,7 @@ #include "alMain.h" #include "almalloc.h" +#include "alspan.h" #include "atomic.h" @@ -151,7 +152,7 @@ struct EffectState { virtual ALboolean deviceUpdate(const ALCdevice *device) = 0; virtual void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) = 0; - virtual void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) = 0; + virtual void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) = 0; void IncRef() noexcept; void DecRef() noexcept; diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp index cdbb2036..9226c747 100644 --- a/Alc/effects/chorus.cpp +++ b/Alc/effects/chorus.cpp @@ -101,7 +101,7 @@ struct ChorusState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(ChorusState) }; @@ -198,7 +198,7 @@ void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, co } } -void ChorusState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) +void ChorusState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) { const auto bufmask = static_cast(mSampleBuffer.size()-1); const ALfloat feedback{mFeedback}; @@ -206,7 +206,6 @@ void ChorusState::process(const ALsizei samplesToDo, const FloatBufferLine *REST ALfloat *RESTRICT delaybuf{mSampleBuffer.data()}; ALsizei offset{mOffset}; - const al::span output{samplesOut, samplesOut+numOutput}; for(ALsizei base{0};base < samplesToDo;) { const ALsizei todo = mini(256, samplesToDo-base); @@ -254,7 +253,7 @@ void ChorusState::process(const ALsizei samplesToDo, const FloatBufferLine *REST } for(ALsizei c{0};c < 2;c++) - MixSamples(temps[c], output, mGains[c].Current, mGains[c].Target, samplesToDo-base, + MixSamples(temps[c], samplesOut, mGains[c].Current, mGains[c].Target, samplesToDo-base, base, todo); base += todo; diff --git a/Alc/effects/compressor.cpp b/Alc/effects/compressor.cpp index a3435d61..5c0d0121 100644 --- a/Alc/effects/compressor.cpp +++ b/Alc/effects/compressor.cpp @@ -52,7 +52,7 @@ struct CompressorState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(CompressorState) }; @@ -87,21 +87,18 @@ void CompressorState::update(const ALCcontext* UNUSED(context), const ALeffectsl } } -void CompressorState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) +void CompressorState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) { - ALsizei i, j, k; - ALsizei base; - - for(base = 0;base < samplesToDo;) + for(ALsizei base{0};base < samplesToDo;) { ALfloat gains[256]; - ALsizei td = mini(256, samplesToDo-base); - ALfloat env = mEnvFollower; + const ALsizei td{mini(256, samplesToDo-base)}; /* Generate the per-sample gains from the signal envelope. */ + ALfloat env{mEnvFollower}; if(mEnabled) { - for(i = 0;i < td;++i) + for(ALsizei i{0};i < td;++i) { /* Clamp the absolute amplitude to the defined envelope limits, * then attack or release the envelope to reach it. @@ -125,7 +122,7 @@ void CompressorState::process(const ALsizei samplesToDo, const FloatBufferLine * * ensure smooth gain changes when the compressor is turned on and * off. */ - for(i = 0;i < td;++i) + for(ALsizei i{0};i < td;++i) { const ALfloat amplitude{1.0f}; if(amplitude > env) @@ -140,17 +137,17 @@ void CompressorState::process(const ALsizei samplesToDo, const FloatBufferLine * /* Now compress the signal amplitude to output. */ ASSUME(numInput > 0); - for(j = 0;j < numInput;j++) + for(ALsizei j{0};j < numInput;j++) { - ASSUME(numOutput > 0); - for(k = 0;k < numOutput;k++) + const ALfloat *outgains{mGain[j]}; + for(FloatBufferLine &output : samplesOut) { - const ALfloat gain{mGain[j][k]}; + const ALfloat gain{*(outgains++)}; if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; - for(i = 0;i < td;i++) - samplesOut[k][base+i] += samplesIn[j][base+i] * gains[i] * gain; + for(ALsizei i{0};i < td;i++) + output[base+i] += samplesIn[j][base+i] * gains[i] * gain; } } diff --git a/Alc/effects/dedicated.cpp b/Alc/effects/dedicated.cpp index b4eaa8e8..06d187fc 100644 --- a/Alc/effects/dedicated.cpp +++ b/Alc/effects/dedicated.cpp @@ -40,7 +40,7 @@ struct DedicatedState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(DedicatedState) }; @@ -90,10 +90,10 @@ void DedicatedState::update(const ALCcontext* UNUSED(context), const ALeffectslo } } -void DedicatedState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) +void DedicatedState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) { - MixSamples(samplesIn[0].data(), {samplesOut, samplesOut+numOutput}, mCurrentGains, - mTargetGains, samplesToDo, 0, samplesToDo); + MixSamples(samplesIn[0].data(), samplesOut, mCurrentGains, mTargetGains, samplesToDo, 0, + samplesToDo); } diff --git a/Alc/effects/distortion.cpp b/Alc/effects/distortion.cpp index ffe2a102..4830ad1c 100644 --- a/Alc/effects/distortion.cpp +++ b/Alc/effects/distortion.cpp @@ -50,7 +50,7 @@ struct DistortionState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(DistortionState) }; @@ -95,14 +95,10 @@ void DistortionState::update(const ALCcontext *context, const ALeffectslot *slot ComputePanGains(target.Main, coeffs, slot->Params.Gain*props->Distortion.Gain, mGain); } -void DistortionState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) +void DistortionState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) { - ALfloat (*RESTRICT buffer)[BUFFERSIZE] = mBuffer; - const ALfloat fc = mEdgeCoeff; - ALsizei base; - ALsizei i, k; - - for(base = 0;base < samplesToDo;) + const ALfloat fc{mEdgeCoeff}; + for(ALsizei base{0};base < samplesToDo;) { /* Perform 4x oversampling to avoid aliasing. Oversampling greatly * improves distortion quality and allows to implement lowpass and @@ -114,47 +110,48 @@ void DistortionState::process(const ALsizei samplesToDo, const FloatBufferLine * /* Fill oversample buffer using zero stuffing. Multiply the sample by * the amount of oversampling to maintain the signal's power. */ - for(i = 0;i < todo;i++) - buffer[0][i] = !(i&3) ? samplesIn[0][(i>>2)+base] * 4.0f : 0.0f; + for(ALsizei i{0};i < todo;i++) + mBuffer[0][i] = !(i&3) ? samplesIn[0][(i>>2)+base] * 4.0f : 0.0f; /* First step, do lowpass filtering of original signal. Additionally * perform buffer interpolation and lowpass cutoff for oversampling * (which is fortunately first step of distortion). So combine three * operations into the one. */ - mLowpass.process(buffer[1], buffer[0], todo); + mLowpass.process(mBuffer[1], mBuffer[0], todo); /* Second step, do distortion using waveshaper function to emulate * signal processing during tube overdriving. Three steps of * waveshaping are intended to modify waveform without boost/clipping/ * attenuation process. */ - for(i = 0;i < todo;i++) + for(ALsizei i{0};i < todo;i++) { - ALfloat smp = buffer[1][i]; + ALfloat smp{mBuffer[1][i]}; smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)); smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)) * -1.0f; smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)); - buffer[0][i] = smp; + mBuffer[0][i] = smp; } /* Third step, do bandpass filtering of distorted signal. */ - mBandpass.process(buffer[1], buffer[0], todo); + mBandpass.process(mBuffer[1], mBuffer[0], todo); todo >>= 2; - for(k = 0;k < numOutput;k++) + const ALfloat *outgains{mGain}; + for(FloatBufferLine &output : samplesOut) { /* Fourth step, final, do attenuation and perform decimation, * storing only one sample out of four. */ - const ALfloat gain{mGain[k]}; + const ALfloat gain{*(outgains++)}; if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; - for(i = 0;i < todo;i++) - samplesOut[k][base+i] += gain * buffer[1][i*4]; + for(ALsizei i{0};i < todo;i++) + output[base+i] += gain * mBuffer[1][i*4]; } base += todo; diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index e82e75bd..dadb41bb 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -60,7 +60,7 @@ struct EchoState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(EchoState) }; @@ -119,7 +119,7 @@ void EchoState::update(const ALCcontext *context, const ALeffectslot *slot, cons ComputePanGains(target.Main, coeffs[1], slot->Params.Gain, mGains[1].Target); } -void EchoState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) +void EchoState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) { const auto mask = static_cast(mSampleBuffer.size()-1); ALfloat *RESTRICT delaybuf{mSampleBuffer.data()}; @@ -157,9 +157,8 @@ void EchoState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRI mFilter.setComponents(z1, z2); mOffset = offset; - const al::span output{samplesOut, samplesOut+numOutput}; for(ALsizei c{0};c < 2;c++) - MixSamples(mTempBuffer[c], output, mGains[c].Current, mGains[c].Target, samplesToDo, 0, + MixSamples(mTempBuffer[c], samplesOut, mGains[c].Current, mGains[c].Target, samplesToDo, 0, samplesToDo); } diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index f6be258b..d37f15ea 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -94,7 +94,7 @@ struct EqualizerState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(EqualizerState) }; @@ -158,9 +158,8 @@ void EqualizerState::update(const ALCcontext *context, const ALeffectslot *slot, } } -void EqualizerState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) +void EqualizerState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) { - const al::span output{samplesOut, samplesOut+numOutput}; ASSUME(numInput > 0); for(ALsizei c{0};c < numInput;c++) { @@ -169,7 +168,7 @@ void EqualizerState::process(const ALsizei samplesToDo, const FloatBufferLine *R mChans[c].filter[2].process(mSampleBuffer, mSampleBuffer, samplesToDo); mChans[c].filter[3].process(mSampleBuffer, mSampleBuffer, samplesToDo); - MixSamples(mSampleBuffer, output, mChans[c].CurrentGains, mChans[c].TargetGains, + MixSamples(mSampleBuffer, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, samplesToDo, 0, samplesToDo); } } diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp index 56068b06..d50a7733 100644 --- a/Alc/effects/fshifter.cpp +++ b/Alc/effects/fshifter.cpp @@ -83,7 +83,7 @@ struct FshifterState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(FshifterState) }; @@ -138,7 +138,7 @@ void FshifterState::update(const ALCcontext *context, const ALeffectslot *slot, ComputePanGains(target.Main, coeffs, slot->Params.Gain, mTargetGains); } -void FshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) +void FshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) { static constexpr complex_d complex_zero{0.0, 0.0}; ALfloat *RESTRICT BufferOut = mBufferOut; @@ -198,8 +198,8 @@ void FshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE } /* Now, mix the processed sound data to the output. */ - MixSamples(BufferOut, {samplesOut, samplesOut+numOutput}, mCurrentGains, mTargetGains, - maxi(samplesToDo, 512), 0, samplesToDo); + MixSamples(BufferOut, samplesOut, mCurrentGains, mTargetGains, maxi(samplesToDo, 512), 0, + samplesToDo); } diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index 9b7abbb7..60728d2e 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -93,7 +93,7 @@ struct ModulatorState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(ModulatorState) }; @@ -141,11 +141,10 @@ void ModulatorState::update(const ALCcontext *context, const ALeffectslot *slot, } } -void ModulatorState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) +void ModulatorState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) { const ALsizei step{mStep}; - const al::span output{samplesOut, samplesOut+numOutput}; for(ALsizei base{0};base < samplesToDo;) { alignas(16) ALfloat modsamples[MAX_UPDATE_SAMPLES]; @@ -165,7 +164,7 @@ void ModulatorState::process(const ALsizei samplesToDo, const FloatBufferLine *R for(i = 0;i < td;i++) temps[i] *= modsamples[i]; - MixSamples(temps, output, mChans[c].CurrentGains, mChans[c].TargetGains, + MixSamples(temps, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, samplesToDo-base, base, td); } diff --git a/Alc/effects/null.cpp b/Alc/effects/null.cpp index 96c0e928..6076a2d9 100644 --- a/Alc/effects/null.cpp +++ b/Alc/effects/null.cpp @@ -19,7 +19,7 @@ struct NullState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(NullState) }; @@ -55,7 +55,7 @@ void NullState::update(const ALCcontext* UNUSED(context), const ALeffectslot* UN * input to the output buffer. The result should be added to the output buffer, * not replace it. */ -void NullState::process(const ALsizei /*samplesToDo*/, const FloatBufferLine *RESTRICT /*samplesIn*/, const ALsizei /*numInput*/, FloatBufferLine *RESTRICT /*samplesOut*/, const ALsizei /*numOutput*/) +void NullState::process(const ALsizei /*samplesToDo*/, const FloatBufferLine *RESTRICT /*samplesIn*/, const ALsizei /*numInput*/, const al::span /*samplesOut*/) { } diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp index 34f442bc..184c9a40 100644 --- a/Alc/effects/pshifter.cpp +++ b/Alc/effects/pshifter.cpp @@ -153,7 +153,7 @@ struct PshifterState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(PshifterState) }; @@ -197,7 +197,7 @@ void PshifterState::update(const ALCcontext* UNUSED(context), const ALeffectslot ComputePanGains(target.Main, coeffs, slot->Params.Gain, mTargetGains); } -void PshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) +void PshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) { /* Pitch shifter engine based on the work of Stephan Bernsee. * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/ @@ -321,8 +321,8 @@ void PshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE mCount = count; /* Now, mix the processed sound data to the output. */ - MixSamples(bufferOut, {samplesOut, samplesOut+numOutput}, mCurrentGains, mTargetGains, - maxi(samplesToDo, 512), 0, samplesToDo); + MixSamples(bufferOut, samplesOut, mCurrentGains, mTargetGains, maxi(samplesToDo, 512), 0, + samplesToDo); } diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 5d2f25f9..d3a60b5e 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -446,7 +446,7 @@ struct ReverbState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(ReverbState) }; @@ -1442,7 +1442,7 @@ void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei to VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, out, todo); } -void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, FloatBufferLine *RESTRICT samplesOut, const ALsizei numOutput) +void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) { ALsizei fadeCount{mFadeCount}; @@ -1526,7 +1526,7 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST mFadeCount = fadeCount; /* Finally, mix early reflections and late reverb. */ - (this->*mMixOut)({samplesOut, samplesOut+numOutput}, samplesToDo); + (this->*mMixOut)(samplesOut, samplesToDo); } -- cgit v1.2.3 From dbdf516dbf628c65d4115a00c78f5679308a0573 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 29 May 2019 23:06:24 -0700 Subject: Use a span for the voice's buffer references --- Alc/alu.cpp | 32 +++++++++++++------------------- Alc/mixvoice.cpp | 18 ++++++++---------- OpenAL32/Include/alu.h | 6 ++---- 3 files changed, 23 insertions(+), 33 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 2f172b99..befddd9a 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -641,7 +641,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo voice->mDirect.Params[0].NFCtrlFilter.adjust(0.0f); voice->mDirect.ChannelsPerOrder[0] = 1; - voice->mDirect.ChannelsPerOrder[1] = mini(voice->mDirect.Channels-1, 3); + voice->mDirect.ChannelsPerOrder[1] = minz(voice->mDirect.Buffer.size()-1, 3); std::fill(std::begin(voice->mDirect.ChannelsPerOrder)+2, std::end(voice->mDirect.ChannelsPerOrder), 0); voice->mFlags |= VOICE_HAS_NFC; @@ -697,8 +697,8 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo /* Direct source channels always play local. Skip the virtual channels * and write inputs to the matching real outputs. */ - voice->mDirect.Buffer = Device->RealOut.Buffer; - voice->mDirect.Channels = Device->RealOut.NumChannels; + voice->mDirect.Buffer = {Device->RealOut.Buffer, + static_cast(Device->RealOut.NumChannels)}; for(ALsizei c{0};c < num_channels;c++) { @@ -727,8 +727,8 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo /* Full HRTF rendering. Skip the virtual channels and render to the * real outputs. */ - voice->mDirect.Buffer = Device->RealOut.Buffer; - voice->mDirect.Channels = Device->RealOut.NumChannels; + voice->mDirect.Buffer = {Device->RealOut.Buffer, + static_cast(Device->RealOut.NumChannels)}; if(Distance > std::numeric_limits::epsilon()) { @@ -970,8 +970,7 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons const ALCdevice *Device{ALContext->Device}; ALeffectslot *SendSlots[MAX_SENDS]; - voice->mDirect.Buffer = Device->Dry.Buffer; - voice->mDirect.Channels = Device->Dry.NumChannels; + voice->mDirect.Buffer = {Device->Dry.Buffer, static_cast(Device->Dry.NumChannels)}; for(ALsizei i{0};i < Device->NumAuxSends;i++) { SendSlots[i] = props->Send[i].Slot; @@ -980,13 +979,12 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) { SendSlots[i] = nullptr; - voice->mSend[i].Buffer = nullptr; - voice->mSend[i].Channels = 0; + voice->mSend[i].Buffer = {}; } else { - voice->mSend[i].Buffer = SendSlots[i]->Wet.Buffer; - voice->mSend[i].Channels = SendSlots[i]->Wet.NumChannels; + voice->mSend[i].Buffer = {SendSlots[i]->Wet.Buffer, + static_cast(SendSlots[i]->Wet.NumChannels)}; } } @@ -1031,8 +1029,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A const ALlistener &Listener = ALContext->Listener; /* Set mixing buffers and get send parameters. */ - voice->mDirect.Buffer = Device->Dry.Buffer; - voice->mDirect.Channels = Device->Dry.NumChannels; + voice->mDirect.Buffer = {Device->Dry.Buffer, static_cast(Device->Dry.NumChannels)}; ALeffectslot *SendSlots[MAX_SENDS]; ALfloat RoomRolloff[MAX_SENDS]; ALfloat DecayDistance[MAX_SENDS]; @@ -1087,14 +1084,11 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A } if(!SendSlots[i]) - { - voice->mSend[i].Buffer = nullptr; - voice->mSend[i].Channels = 0; - } + voice->mSend[i].Buffer = {}; else { - voice->mSend[i].Buffer = SendSlots[i]->Wet.Buffer; - voice->mSend[i].Channels = SendSlots[i]->Wet.NumChannels; + voice->mSend[i].Buffer = {SendSlots[i]->Wet.Buffer, + static_cast(SendSlots[i]->Wet.NumChannels)}; } } diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index d3b76492..fc70fa2e 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -561,7 +561,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc parms.Hrtf.Old = parms.Hrtf.Target; auto set_current = [chan](ALvoice::SendData &send) -> void { - if(!send.Buffer) + if(send.Buffer.empty()) return; SendParams &parms = send.Params[chan]; @@ -801,7 +801,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc SilentTarget : parms.Gains.Target}; const auto outcount = static_cast(voice->mDirect.ChannelsPerOrder[0]); - MixSamples(samples, {voice->mDirect.Buffer, outcount}, parms.Gains.Current, + MixSamples(samples, voice->mDirect.Buffer.first(outcount), parms.Gains.Current, TargetGains, Counter, OutPos, DstBufferSize); ALfloat (&nfcsamples)[BUFFERSIZE] = Device->NfcSampleData; @@ -813,7 +813,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc voice->mDirect.ChannelsPerOrder[order]); if(outcount < 1) return; (parms.NFCtrlFilter.*process)(nfcsamples, samples, DstBufferSize); - MixSamples(nfcsamples, {voice->mDirect.Buffer+chanoffset, outcount}, + MixSamples(nfcsamples, voice->mDirect.Buffer.subspan(chanoffset, outcount), parms.Gains.Current+chanoffset, TargetGains+chanoffset, Counter, OutPos, DstBufferSize); chanoffset += outcount; @@ -826,16 +826,15 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc { const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? SilentTarget : parms.Gains.Target}; - const auto outcount = static_cast(voice->mDirect.Channels); - MixSamples(samples, {voice->mDirect.Buffer, outcount}, parms.Gains.Current, - TargetGains, Counter, OutPos, DstBufferSize); + MixSamples(samples, voice->mDirect.Buffer, parms.Gains.Current, TargetGains, + Counter, OutPos, DstBufferSize); } } ALfloat (&FilterBuf)[BUFFERSIZE] = Device->FilteredData; auto mix_send = [vstate,Counter,OutPos,DstBufferSize,chan,ResampledData,&FilterBuf](ALvoice::SendData &send) -> void { - if(!send.Buffer) + if(send.Buffer.empty()) return; SendParams &parms = send.Params[chan]; @@ -844,9 +843,8 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc const ALfloat *TargetGains{UNLIKELY(vstate==ALvoice::Stopping) ? SilentTarget : parms.Gains.Target}; - const auto outcount = static_cast(send.Channels); - MixSamples(samples, {send.Buffer, outcount}, parms.Gains.Current, TargetGains, - Counter, OutPos, DstBufferSize); + MixSamples(samples, send.Buffer, parms.Gains.Current, TargetGains, Counter, OutPos, + DstBufferSize); }; std::for_each(voice->mSend.begin(), voice->mSend.end(), mix_send); } diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index b6914c37..cb0b675c 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -265,8 +265,7 @@ struct ALvoice { int FilterType; DirectParams Params[MAX_INPUT_CHANNELS]; - FloatBufferLine *Buffer; - ALsizei Channels; + al::span Buffer; ALsizei ChannelsPerOrder[MAX_AMBI_ORDER+1]; } mDirect; @@ -274,8 +273,7 @@ struct ALvoice { int FilterType; SendParams Params[MAX_INPUT_CHANNELS]; - FloatBufferLine *Buffer; - ALsizei Channels; + al::span Buffer; }; al::FlexArray mSend; -- cgit v1.2.3 From 153f133435fe46a94eb4d26c0483f4e6166fb896 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 29 May 2019 23:41:09 -0700 Subject: Try to fix "ambiguous" initializations with older compilers --- Alc/effects/reverb.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index d3a60b5e..5361a58f 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -371,9 +371,9 @@ struct ReverbState final : public EffectState { ALsizei mOffset{0}; /* Temporary storage used when processing. */ - alignas(16) FloatBufferLine mTempSamples[NUM_LINES]{}; - alignas(16) FloatBufferLine mEarlyBuffer[NUM_LINES]{}; - alignas(16) FloatBufferLine mLateBuffer[NUM_LINES]{}; + alignas(16) std::array mTempSamples{}; + alignas(16) std::array mEarlyBuffer{}; + alignas(16) std::array mLateBuffer{}; using MixOutT = void (ReverbState::*)(const al::span samplesOut, const ALsizei todo); -- cgit v1.2.3 From 1961828d0bde4ea67b6a24a10f4fedacc88b6392 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 30 May 2019 10:06:12 -0700 Subject: Avoid potentially ambiguous span copy constructor --- common/alspan.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/alspan.h b/common/alspan.h index bd6b53bb..d02b13f2 100644 --- a/common/alspan.h +++ b/common/alspan.h @@ -116,7 +116,7 @@ public: constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { } template constexpr span(const U &cont) : span{al::data(cont), al::size(cont)} { } - template::value)> + template::value && extent == N && std::is_convertible::value)> constexpr span(const span &span_) noexcept : span{al::data(span_), al::size(span_)} { } constexpr span(const span&) noexcept = default; @@ -210,7 +210,7 @@ public: constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { } template constexpr span(const U &cont) : span{al::data(cont), al::size(cont)} { } - template::value)> + template::value || extent != N) && std::is_convertible::value)> constexpr span(const span &span_) noexcept : span{al::data(span_), al::size(span_)} { } constexpr span(const span&) noexcept = default; -- cgit v1.2.3 From 76e7c8b2440172d7cb480755768b09225a1521d3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 30 May 2019 10:52:28 -0700 Subject: Try to work around some MSVC short-comings --- Alc/effects/reverb.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 5361a58f..bb12826b 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -1189,7 +1189,7 @@ void VecAllpass::processFaded(const al::span samples, void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei todo, const ALsizei base, const al::span out) { - const al::span temps{State->mTempSamples}; + const auto temps = al::span(State->mTempSamples); const DelayLineI early_delay{State->mEarly.Delay}; const DelayLineI main_delay{State->mDelay}; const ALfloat mixX{State->mMixX}; @@ -1246,12 +1246,13 @@ void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALs * bounce to improve the initial diffusion in the late reverb. */ const ALsizei late_feed_tap{offset - State->mLateFeedTap}; - VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, out, todo); + VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, + {out.cbegin(), out.cend()}, todo); } void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, const ALfloat fade, const ALsizei base, const al::span out) { - const al::span temps{State->mTempSamples}; + const auto temps = al::span(State->mTempSamples); const DelayLineI early_delay{State->mEarly.Delay}; const DelayLineI main_delay{State->mDelay}; const ALfloat mixX{State->mMixX}; @@ -1317,7 +1318,8 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz early_delay.write(offset, NUM_LINES-1-j, temps[j].data(), todo); const ALsizei late_feed_tap{offset - State->mLateFeedTap}; - VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, out, todo); + VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, + {out.cbegin(), out.cend()}, todo); } /* This generates the reverb tail using a modified feed-back delay network @@ -1337,7 +1339,7 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei todo, const ALsizei base, const al::span out) { - const al::span temps{State->mTempSamples}; + const auto temps = al::span(State->mTempSamples); const DelayLineI late_delay{State->mLate.Delay}; const DelayLineI main_delay{State->mDelay}; const ALfloat mixX{State->mMixX}; @@ -1379,12 +1381,13 @@ void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei std::copy_n(temps[j].begin(), todo, out[j].begin()+base); /* Finally, scatter and bounce the results to refeed the feedback buffer. */ - VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, out, todo); + VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, + {out.cbegin(), out.cend()}, todo); } void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, const ALfloat fade, const ALsizei base, const al::span out) { - const al::span temps{State->mTempSamples}; + const auto temps = al::span(State->mTempSamples); const DelayLineI late_delay{State->mLate.Delay}; const DelayLineI main_delay{State->mDelay}; const ALfloat mixX{State->mMixX}; @@ -1439,7 +1442,8 @@ void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei to for(ALsizei j{0};j < NUM_LINES;j++) std::copy_n(temps[j].begin(), todo, out[j].begin()+base); - VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, out, todo); + VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, + {out.cbegin(), out.cend()}, todo); } void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) @@ -1449,7 +1453,7 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST ASSUME(samplesToDo > 0); /* Convert B-Format to A-Format for processing. */ - const al::span afmt{mTempSamples}; + auto &afmt = mTempSamples; for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(afmt[c].begin(), samplesToDo, 0.0f); -- cgit v1.2.3 From 1c8dfb55d8147ea646d7049aa15b181f24ac6c76 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 30 May 2019 11:46:48 -0700 Subject: Improve span constructor requirements Particularly, properly account for the const-ness of the data returned by it. --- common/alspan.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/common/alspan.h b/common/alspan.h index d02b13f2..62f7b2ab 100644 --- a/common/alspan.h +++ b/common/alspan.h @@ -75,10 +75,12 @@ namespace detail_ { } // namespace detail_ #define REQUIRES(...) typename std::enable_if<(__VA_ARGS__),int>::type = 0 +#define USABLE_CONTAINER_DATA(...) \ + std::is_convertible()))>::type(*)[],element_type(*)[]>::value #define IS_VALID_CONTAINER(C) \ !detail_::is_span::value && !detail_::is_std_array::value && \ !std::is_array::value && detail_::has_size_and_data::value && \ - std::is_convertible()))>::type(*)[],element_type(*)[]>::value + USABLE_CONTAINER_DATA(C&) template class span { @@ -108,13 +110,13 @@ public: constexpr span(pointer first, pointer /*last*/) : mData{first} { } template constexpr span(element_type (&arr)[N]) noexcept : span{al::data(arr), al::size(arr)} { } - template::value)> + template&))> constexpr span(std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } - template::value)> + template&))> constexpr span(const std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } template constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { } - template + template constexpr span(const U &cont) : span{al::data(cont), al::size(cont)} { } template::value && extent == N && std::is_convertible::value)> constexpr span(const span &span_) noexcept : span{al::data(span_), al::size(span_)} { } @@ -202,13 +204,13 @@ public: constexpr span(pointer first, pointer last) : mData{first}, mDataEnd{last} { } template constexpr span(element_type (&arr)[N]) noexcept : span{al::data(arr), al::size(arr)} { } - template::value)> + template&))> constexpr span(std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } - template::value)> + template&))> constexpr span(const std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } template constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { } - template + template constexpr span(const U &cont) : span{al::data(cont), al::size(cont)} { } template::value || extent != N) && std::is_convertible::value)> constexpr span(const span &span_) noexcept : span{al::data(span_), al::size(span_)} { } @@ -288,6 +290,7 @@ constexpr inline auto span::subspan(size_t offset, size_t count) const -> s } #undef IS_VALID_CONTAINER +#undef USABLE_CONTAINER_DATA #undef REQUIRES } // namespace al -- cgit v1.2.3 From a123c87ba5a0ba48490ba1f8cd859e557e9bbb62 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 30 May 2019 14:38:06 -0700 Subject: Avoid some MSVC workarounds that didn't seem to work --- Alc/effects/reverb.cpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index bb12826b..5361a58f 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -1189,7 +1189,7 @@ void VecAllpass::processFaded(const al::span samples, void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei todo, const ALsizei base, const al::span out) { - const auto temps = al::span(State->mTempSamples); + const al::span temps{State->mTempSamples}; const DelayLineI early_delay{State->mEarly.Delay}; const DelayLineI main_delay{State->mDelay}; const ALfloat mixX{State->mMixX}; @@ -1246,13 +1246,12 @@ void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALs * bounce to improve the initial diffusion in the late reverb. */ const ALsizei late_feed_tap{offset - State->mLateFeedTap}; - VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, - {out.cbegin(), out.cend()}, todo); + VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, out, todo); } void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, const ALfloat fade, const ALsizei base, const al::span out) { - const auto temps = al::span(State->mTempSamples); + const al::span temps{State->mTempSamples}; const DelayLineI early_delay{State->mEarly.Delay}; const DelayLineI main_delay{State->mDelay}; const ALfloat mixX{State->mMixX}; @@ -1318,8 +1317,7 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz early_delay.write(offset, NUM_LINES-1-j, temps[j].data(), todo); const ALsizei late_feed_tap{offset - State->mLateFeedTap}; - VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, - {out.cbegin(), out.cend()}, todo); + VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, out, todo); } /* This generates the reverb tail using a modified feed-back delay network @@ -1339,7 +1337,7 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei todo, const ALsizei base, const al::span out) { - const auto temps = al::span(State->mTempSamples); + const al::span temps{State->mTempSamples}; const DelayLineI late_delay{State->mLate.Delay}; const DelayLineI main_delay{State->mDelay}; const ALfloat mixX{State->mMixX}; @@ -1381,13 +1379,12 @@ void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei std::copy_n(temps[j].begin(), todo, out[j].begin()+base); /* Finally, scatter and bounce the results to refeed the feedback buffer. */ - VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, - {out.cbegin(), out.cend()}, todo); + VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, out, todo); } void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, const ALfloat fade, const ALsizei base, const al::span out) { - const auto temps = al::span(State->mTempSamples); + const al::span temps{State->mTempSamples}; const DelayLineI late_delay{State->mLate.Delay}; const DelayLineI main_delay{State->mDelay}; const ALfloat mixX{State->mMixX}; @@ -1442,8 +1439,7 @@ void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei to for(ALsizei j{0};j < NUM_LINES;j++) std::copy_n(temps[j].begin(), todo, out[j].begin()+base); - VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, - {out.cbegin(), out.cend()}, todo); + VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, out, todo); } void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) @@ -1453,7 +1449,7 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST ASSUME(samplesToDo > 0); /* Convert B-Format to A-Format for processing. */ - auto &afmt = mTempSamples; + const al::span afmt{mTempSamples}; for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(afmt[c].begin(), samplesToDo, 0.0f); -- cgit v1.2.3 From 4bae4cbafb36cd922492dbc1fb7a0cbc075592dc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 30 May 2019 18:39:51 -0700 Subject: Another attempt to fix MSVC 2015 --- common/alspan.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/common/alspan.h b/common/alspan.h index 62f7b2ab..6b0dc7d6 100644 --- a/common/alspan.h +++ b/common/alspan.h @@ -108,12 +108,10 @@ public: constexpr span() noexcept { } constexpr span(pointer ptr, index_type /*count*/) : mData{ptr} { } constexpr span(pointer first, pointer /*last*/) : mData{first} { } - template - constexpr span(element_type (&arr)[N]) noexcept : span{al::data(arr), al::size(arr)} { } - template&))> - constexpr span(std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } - template&))> - constexpr span(const std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } + constexpr span(element_type (&arr)[E]) noexcept : span{al::data(arr), al::size(arr)} { } + constexpr span(std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } + template::value, REQUIRES(is_const)> + constexpr span(const std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } template constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { } template @@ -204,9 +202,9 @@ public: constexpr span(pointer first, pointer last) : mData{first}, mDataEnd{last} { } template constexpr span(element_type (&arr)[N]) noexcept : span{al::data(arr), al::size(arr)} { } - template&))> + template constexpr span(std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } - template&))> + template::value, REQUIRES(is_const)> constexpr span(const std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } template constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { } -- cgit v1.2.3 From 6ee49cad522b5bd12d954c508bae977e3c98cb07 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 30 May 2019 18:55:24 -0700 Subject: Once more for MSVC --- Alc/effects/reverb.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 5361a58f..51c0c467 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -1246,7 +1246,8 @@ void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALs * bounce to improve the initial diffusion in the late reverb. */ const ALsizei late_feed_tap{offset - State->mLateFeedTap}; - VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, out, todo); + VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, + {out.cbegin(), out.cend()}, todo); } void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, const ALfloat fade, const ALsizei base, const al::span out) @@ -1317,7 +1318,8 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz early_delay.write(offset, NUM_LINES-1-j, temps[j].data(), todo); const ALsizei late_feed_tap{offset - State->mLateFeedTap}; - VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, out, todo); + VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, + {out.cbegin(), out.cend()}, todo); } /* This generates the reverb tail using a modified feed-back delay network @@ -1379,7 +1381,8 @@ void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei std::copy_n(temps[j].begin(), todo, out[j].begin()+base); /* Finally, scatter and bounce the results to refeed the feedback buffer. */ - VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, out, todo); + VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, + {out.cbegin(), out.cend()}, todo); } void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, const ALfloat fade, const ALsizei base, const al::span out) @@ -1439,7 +1442,8 @@ void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei to for(ALsizei j{0};j < NUM_LINES;j++) std::copy_n(temps[j].begin(), todo, out[j].begin()+base); - VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, out, todo); + VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, + {out.cbegin(), out.cend()}, todo); } void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) -- cgit v1.2.3 From 20ce461096c88e1bafa209a43541a599ff0ad610 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 31 May 2019 11:58:48 -0700 Subject: Make sure the T60 filter gains are properly clamped --- Alc/effects/reverb.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 51c0c467..54151d6e 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -699,15 +699,15 @@ void T60Filter::calcCoeffs(const ALfloat length, const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lf0norm, const ALfloat hf0norm) { - const ALfloat lfGain{CalcDecayCoeff(length, lfDecayTime)}; const ALfloat mfGain{CalcDecayCoeff(length, mfDecayTime)}; - const ALfloat hfGain{CalcDecayCoeff(length, hfDecayTime)}; + const ALfloat lfGain{maxf(CalcDecayCoeff(length, lfDecayTime)/mfGain, 0.001f)}; + const ALfloat hfGain{maxf(CalcDecayCoeff(length, hfDecayTime)/mfGain, 0.001f)}; MidGain[1] = mfGain; - LFFilter.setParams(BiquadType::LowShelf, lfGain/mfGain, lf0norm, - LFFilter.rcpQFromSlope(lfGain/mfGain, 1.0f)); - HFFilter.setParams(BiquadType::HighShelf, hfGain/mfGain, hf0norm, - HFFilter.rcpQFromSlope(hfGain/mfGain, 1.0f)); + LFFilter.setParams(BiquadType::LowShelf, lfGain, lf0norm, + LFFilter.rcpQFromSlope(lfGain, 1.0f)); + HFFilter.setParams(BiquadType::HighShelf, hfGain, hf0norm, + HFFilter.rcpQFromSlope(hfGain, 1.0f)); } /* Update the early reflection line lengths and gain coefficients. */ -- cgit v1.2.3 From 8c4a9a5a32e0294e2b2a3ac01df501f78f8d2160 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 1 Jun 2019 11:21:43 -0700 Subject: Properly search for prebuilt native-tools --- CMakeLists.txt | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 53c3ff80..d6448a25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1161,8 +1161,19 @@ SET(NATIVE_SRC_DIR "${OpenAL_SOURCE_DIR}/native-tools") SET(ALSOFT_NATIVE_TOOLS_PATH "" CACHE STRING "Path to prebuilt native tools (leave blank to auto-build)") IF(ALSOFT_NATIVE_TOOLS_PATH) - SET(BIN2H_COMMAND "${ALSOFT_NATIVE_TOOLS_PATH}/bin2h") - SET(BSINCGEN_COMMAND "${ALSOFT_NATIVE_TOOLS_PATH}/bsincgen") + find_program(BIN2H_NATIVE_COMMAND NAMES bin2h + PATHS "${ALSOFT_NATIVE_TOOLS_PATH}" + NO_DEFAULT_PATH) + find_program(BSINCGEN_NATIVE_COMMAND NAMES bsincgen + PATHS "${ALSOFT_NATIVE_TOOLS_PATH}" + NO_DEFAULT_PATH) + if(NOT BIN2H_NATIVE_COMMAND OR NOT BSINCGEN_NATIVE_COMMAND) + message(FATAL_ERROR "Failed to find native tools in ${ALSOFT_NATIVE_TOOLS_PATH}. +bin2h: ${BIN2H_NATIVE_COMMAND} +bsincgen: ${BSINCGEN_NATIVE_COMMAND}") + endif() + SET(BIN2H_COMMAND ${BIN2H_NATIVE_COMMAND}) + SET(BSINCGEN_COMMAND ${BSINCGEN_NATIVE_COMMAND}) ELSE() SET(NATIVE_BIN_DIR "${OpenAL_BINARY_DIR}/native-tools") FILE(MAKE_DIRECTORY "${NATIVE_BIN_DIR}") -- cgit v1.2.3 From 53e1415a6709140654b5d70cc277d25fafa0bf66 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 2 Jun 2019 20:38:43 -0700 Subject: Allow selecting the ambisonic order for basic HRTF rendering --- Alc/panning.cpp | 68 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index d1d40927..ab57ed45 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -539,26 +539,65 @@ void InitHrtfPanning(ALCdevice *device) { 5.00000000e-02f, 0.00000000e+00f, -8.09016994e-02f, -3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 9.04508497e-02f, 6.45497224e-02f, 1.23279000e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -7.94438918e-02f, -1.12611206e-01f, 2.42115150e-02f, -1.25611822e-01f }, { 5.00000000e-02f, 0.00000000e+00f, 8.09016994e-02f, -3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 9.04508497e-02f, -6.45497224e-02f, 1.23279000e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 7.94438918e-02f, -1.12611206e-01f, -2.42115150e-02f, -1.25611822e-01f } }; - static constexpr ALfloat AmbiOrderHFGainFOA[MAX_AMBI_ORDER+1]{ + static constexpr ALfloat AmbiOrderHFGain1O[MAX_AMBI_ORDER+1]{ 3.16227766e+00f, 1.82574186e+00f - }, AmbiOrderHFGainHOA[MAX_AMBI_ORDER+1]{ + }, AmbiOrderHFGain2O[MAX_AMBI_ORDER+1]{ 2.35702260e+00f, 1.82574186e+00f, 9.42809042e-01f - /*1.86508671e+00f, 1.60609389e+00f, 1.14205530e+00f, 5.68379553e-01f*/ + }, AmbiOrderHFGain3O[MAX_AMBI_ORDER+1]{ + 1.86508671e+00f, 1.60609389e+00f, 1.14205530e+00f, 5.68379553e-01f }; static constexpr ALsizei ChansPerOrder[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; - const ALfloat *AmbiOrderHFGain{AmbiOrderHFGainFOA}; + const ALfloat *AmbiOrderHFGain{AmbiOrderHFGain1O}; static_assert(al::size(AmbiPoints) == al::size(AmbiMatrix), "Ambisonic HRTF mismatch"); /* Don't bother with HOA when using full HRTF rendering. Nothing needs it, * and it eases the CPU/memory load. */ + device->mRenderMode = HrtfRender; ALsizei ambi_order{1}; - if(device->mRenderMode != HrtfRender) + const char *mode; + if(ConfigValueStr(device->DeviceName.c_str(), nullptr, "hrtf-mode", &mode)) { - ambi_order = 2; - AmbiOrderHFGain = AmbiOrderHFGainHOA; + if(strcasecmp(mode, "basic") == 0) + { + ERR("HRTF mode \"%s\" deprecated, substituting \"%s\"\n", mode, "ambi2"); + mode = "ambi2"; + } + + if(strcasecmp(mode, "full") == 0) + device->mRenderMode = HrtfRender; + else if(strcasecmp(mode, "ambi1") == 0) + { + device->mRenderMode = NormalRender; + ambi_order = 1; + } + else if(strcasecmp(mode, "ambi2") == 0) + { + device->mRenderMode = NormalRender; + ambi_order = 2; + } + else if(strcasecmp(mode, "ambi3") == 0) + { + device->mRenderMode = NormalRender; + ambi_order = 3; + } + else + ERR("Unexpected hrtf-mode: %s\n", mode); } + TRACE("%s HRTF rendering enabled, using \"%s\"\n", + (device->mRenderMode == HrtfRender) ? "Full" : + (ambi_order >= 3) ? "Third-Order" : + (ambi_order == 2) ? "Second-Order" : + (ambi_order == 1) ? "First-Order" : "Unknown", + device->HrtfName.c_str()); + + if(ambi_order >= 3) + AmbiOrderHFGain = AmbiOrderHFGain3O; + else if(ambi_order == 2) + AmbiOrderHFGain = AmbiOrderHFGain2O; + else if(ambi_order == 1) + AmbiOrderHFGain = AmbiOrderHFGain1O; device->mAmbiOrder = ambi_order; const size_t count{AmbiChannelsFromOrder(ambi_order)}; @@ -903,21 +942,6 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr old_hrtf->DecRef(); old_hrtf = nullptr; - device->mRenderMode = HrtfRender; - const char *mode; - if(ConfigValueStr(device->DeviceName.c_str(), nullptr, "hrtf-mode", &mode)) - { - if(strcasecmp(mode, "full") == 0) - device->mRenderMode = HrtfRender; - else if(strcasecmp(mode, "basic") == 0) - device->mRenderMode = NormalRender; - else - ERR("Unexpected hrtf-mode: %s\n", mode); - } - - TRACE("%s HRTF rendering enabled, using \"%s\"\n", - ((device->mRenderMode == HrtfRender) ? "Full" : "Basic"), device->HrtfName.c_str() - ); InitHrtfPanning(device); return; } -- cgit v1.2.3 From c76fb714ccd44584f18c1be7c8366c462c493831 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 3 Jun 2019 22:24:26 -0700 Subject: Restructure voice data members This should improve access patters by packing each buffer channel's data together, which is more inline with its use. --- Alc/alc.cpp | 42 +++++++------- Alc/alu.cpp | 147 +++++++++++++++++++++++++------------------------ Alc/mixvoice.cpp | 51 ++++++++--------- OpenAL32/Include/alu.h | 38 ++++++------- OpenAL32/alSource.cpp | 40 +++++++------- 5 files changed, 160 insertions(+), 158 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 6d09b118..6ade082e 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2161,12 +2161,12 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(device->AvgSpeakerDist > 0.0f) { /* Reinitialize the NFC filters for new parameters. */ - ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / - (device->AvgSpeakerDist * device->Frequency); - std::for_each(voice->mDirect.Params, voice->mDirect.Params+voice->mNumChannels, - [w1](DirectParams ¶ms) noexcept -> void - { params.NFCtrlFilter.init(w1); } - ); + const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC / + (device->AvgSpeakerDist * device->Frequency)}; + auto init_nfc = [w1](ALvoice::ChannelData &chandata) -> void + { chandata.mDryParams.NFCtrlFilter.init(w1); }; + std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, + init_nfc); } } ); @@ -2591,7 +2591,7 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) * property set (including the dynamically-sized Send[] array) in one * chunk. */ - const size_t sizeof_voice{RoundUp(ALvoice::Sizeof(num_sends), 16)}; + const size_t sizeof_voice{RoundUp(sizeof(ALvoice), 16)}; const size_t size{sizeof(ALvoice*) + sizeof_voice}; auto voices = static_cast(al_calloc(16, RoundUp(size*num_voices, 16))); @@ -2605,9 +2605,9 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) const ALsizei s_count = mini(old_sends, num_sends); /* Copy the old voice data to the new storage. */ - auto copy_voice = [&voice,num_sends,sizeof_voice,s_count](ALvoice *old_voice) -> ALvoice* + auto copy_voice = [&voice,s_count](ALvoice *old_voice) -> ALvoice* { - voice = new (voice) ALvoice{static_cast(num_sends)}; + voice = new (voice) ALvoice{}; /* Make sure the old voice's Update (if any) is cleared so it * doesn't get deleted on deinit. @@ -2647,16 +2647,21 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) voice->mFlags = old_voice->mFlags; - std::copy(old_voice->mResampleData.begin(), old_voice->mResampleData.end(), - voice->mResampleData.end()); - voice->mDirect = old_voice->mDirect; - std::copy_n(old_voice->mSend.begin(), s_count, voice->mSend.begin()); + voice->mSend = old_voice->mSend; + voice->mChans = old_voice->mChans; + + /* Clear old send data/params. */ + std::fill(voice->mSend.begin()+s_count, voice->mSend.end(), ALvoice::SendData{}); + auto clear_chan_sends = [s_count](ALvoice::ChannelData &chandata) -> void + { + std::fill(chandata.mWetParams.begin()+s_count, chandata.mWetParams.end(), + SendParams{}); + }; + std::for_each(voice->mChans.begin(), voice->mChans.end(), clear_chan_sends); /* Set this voice's reference. */ - ALvoice *ret = voice; - /* Increment pointer to the next storage space. */ - voice = reinterpret_cast(reinterpret_cast(voice) + sizeof_voice); + ALvoice *ret{voice++}; return ret; }; viter = std::transform(context->Voices, context->Voices+v_count, viter, copy_voice); @@ -2666,10 +2671,9 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) std::for_each(context->Voices, voices_end, DeinitVoice); } /* Finish setting the voices and references. */ - auto init_voice = [&voice,num_sends,sizeof_voice]() -> ALvoice* + auto init_voice = [&voice]() -> ALvoice* { - ALvoice *ret = new (voice) ALvoice{static_cast(num_sends)}; - voice = reinterpret_cast(reinterpret_cast(voice) + sizeof_voice); + ALvoice *ret{new (voice++) ALvoice{}}; return ret; }; std::generate(viter, voices+num_voices, init_voice); diff --git a/Alc/alu.cpp b/Alc/alu.cpp index befddd9a..d41a66aa 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -554,22 +554,14 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo } ASSUME(num_channels > 0); - std::for_each(std::begin(voice->mDirect.Params), - std::begin(voice->mDirect.Params)+num_channels, - [](DirectParams ¶ms) -> void + std::for_each(voice->mChans.begin(), voice->mChans.begin()+num_channels, + [NumSends](ALvoice::ChannelData &chandata) -> void { - params.Hrtf.Target = HrtfParams{}; - ClearArray(params.Gains.Target); - } - ); - std::for_each(voice->mSend.begin(), voice->mSend.end(), - [num_channels](ALvoice::SendData &send) -> void - { - std::for_each(std::begin(send.Params), std::begin(send.Params)+num_channels, - [](SendParams ¶ms) -> void { ClearArray(params.Gains.Target); } - ); - } - ); + chandata.mDryParams.Hrtf.Target = HrtfParams{}; + ClearArray(chandata.mDryParams.Gains.Target); + std::for_each(chandata.mWetParams.begin(), chandata.mWetParams.begin()+NumSends, + [](SendParams ¶ms) -> void { ClearArray(params.Gains.Target); }); + }); voice->mFlags &= ~(VOICE_HAS_HRTF | VOICE_HAS_NFC); if(isbformat) @@ -592,7 +584,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo const ALfloat w0{SPEEDOFSOUNDMETRESPERSEC / (mdist * Frequency)}; /* Only need to adjust the first channel of a B-Format source. */ - voice->mDirect.Params[0].NFCtrlFilter.adjust(w0); + voice->mChans[0].mDryParams.NFCtrlFilter.adjust(w0); std::copy(std::begin(Device->NumChannelsPerOrder), std::end(Device->NumChannelsPerOrder), @@ -622,12 +614,12 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo /* NOTE: W needs to be scaled due to FuMa normalization. */ const ALfloat &scale0 = AmbiScale::FromFuMa[0]; ComputePanGains(&Device->Dry, coeffs, DryGain*scale0, - voice->mDirect.Params[0].Gains.Target); + voice->mChans[0].mDryParams.Gains.Target); for(ALsizei i{0};i < NumSends;i++) { if(const ALeffectslot *Slot{SendSlots[i]}) ComputePanGains(&Slot->Wet, coeffs, WetGain[i]*scale0, - voice->mSend[i].Params[0].Gains.Target); + voice->mChans[0].mWetParams[i].Gains.Target); } } else @@ -638,7 +630,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo * is what we want for FOA input. The first channel may have * been previously re-adjusted if panned, so reset it. */ - voice->mDirect.Params[0].NFCtrlFilter.adjust(0.0f); + voice->mChans[0].mDryParams.NFCtrlFilter.adjust(0.0f); voice->mDirect.ChannelsPerOrder[0] = 1; voice->mDirect.ChannelsPerOrder[1] = minz(voice->mDirect.Buffer.size()-1, 3); @@ -681,14 +673,16 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo }; for(ALsizei c{0};c < num_channels;c++) - ComputePanGains(&Device->Dry, matrix[c], DryGain, - voice->mDirect.Params[c].Gains.Target); - for(ALsizei i{0};i < NumSends;i++) { - if(const ALeffectslot *Slot{SendSlots[i]}) - for(ALsizei c{0};c < num_channels;c++) + ComputePanGains(&Device->Dry, matrix[c], DryGain, + voice->mChans[c].mDryParams.Gains.Target); + + for(ALsizei i{0};i < NumSends;i++) + { + if(const ALeffectslot *Slot{SendSlots[i]}) ComputePanGains(&Slot->Wet, matrix[c], WetGain[i], - voice->mSend[i].Params[c].Gains.Target); + voice->mChans[c].mWetParams[i].Gains.Target); + } } } } @@ -703,7 +697,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo for(ALsizei c{0};c < num_channels;c++) { int idx{GetChannelIdxByName(Device->RealOut, chans[c].channel)}; - if(idx != -1) voice->mDirect.Params[c].Gains.Target[idx] = DryGain; + if(idx != -1) voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain; } /* Auxiliary sends still use normal channel panning since they mix to @@ -718,7 +712,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo { if(const ALeffectslot *Slot{SendSlots[i]}) ComputePanGains(&Slot->Wet, coeffs, WetGain[i], - voice->mSend[i].Params[c].Gains.Target); + voice->mChans[c].mWetParams[i].Gains.Target); } } } @@ -739,16 +733,16 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo * source direction. */ GetHrtfCoeffs(Device->mHrtf, ev, az, Distance, Spread, - voice->mDirect.Params[0].Hrtf.Target.Coeffs, - voice->mDirect.Params[0].Hrtf.Target.Delay); - voice->mDirect.Params[0].Hrtf.Target.Gain = DryGain * downmix_gain; + voice->mChans[0].mDryParams.Hrtf.Target.Coeffs, + voice->mChans[0].mDryParams.Hrtf.Target.Delay); + voice->mChans[0].mDryParams.Hrtf.Target.Gain = DryGain * downmix_gain; /* Remaining channels use the same results as the first. */ for(ALsizei c{1};c < num_channels;c++) { /* Skip LFE */ - if(chans[c].channel != LFE) - voice->mDirect.Params[c].Hrtf.Target = voice->mDirect.Params[0].Hrtf.Target; + if(chans[c].channel == LFE) continue; + voice->mChans[c].mDryParams.Hrtf.Target = voice->mChans[0].mDryParams.Hrtf.Target; } /* Calculate the directional coefficients once, which apply to all @@ -757,16 +751,17 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo ALfloat coeffs[MAX_AMBI_CHANNELS]; CalcDirectionCoeffs({xpos, ypos, zpos}, Spread, coeffs); - for(ALsizei i{0};i < NumSends;i++) + for(ALsizei c{0};c < num_channels;c++) { - if(const ALeffectslot *Slot{SendSlots[i]}) - for(ALsizei c{0};c < num_channels;c++) - { - /* Skip LFE */ - if(chans[c].channel != LFE) - ComputePanGains(&Slot->Wet, coeffs, WetGain[i] * downmix_gain, - voice->mSend[i].Params[c].Gains.Target); - } + /* Skip LFE */ + if(chans[c].channel == LFE) + continue; + for(ALsizei i{0};i < NumSends;i++) + { + if(const ALeffectslot *Slot{SendSlots[i]}) + ComputePanGains(&Slot->Wet, coeffs, WetGain[i] * downmix_gain, + voice->mChans[c].mWetParams[i].Gains.Target); + } } } else @@ -786,9 +781,9 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo */ GetHrtfCoeffs(Device->mHrtf, chans[c].elevation, chans[c].angle, std::numeric_limits::infinity(), Spread, - voice->mDirect.Params[c].Hrtf.Target.Coeffs, - voice->mDirect.Params[c].Hrtf.Target.Delay); - voice->mDirect.Params[c].Hrtf.Target.Gain = DryGain; + voice->mChans[c].mDryParams.Hrtf.Target.Coeffs, + voice->mChans[c].mDryParams.Hrtf.Target.Delay); + voice->mChans[c].mDryParams.Hrtf.Target.Gain = DryGain; /* Normal panning for auxiliary sends. */ ALfloat coeffs[MAX_AMBI_CHANNELS]; @@ -798,7 +793,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo { if(const ALeffectslot *Slot{SendSlots[i]}) ComputePanGains(&Slot->Wet, coeffs, WetGain[i], - voice->mSend[i].Params[c].Gains.Target); + voice->mChans[c].mWetParams[i].Gains.Target); } } } @@ -822,7 +817,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo /* Adjust NFC filters. */ for(ALsizei c{0};c < num_channels;c++) - voice->mDirect.Params[c].NFCtrlFilter.adjust(w0); + voice->mChans[c].mDryParams.NFCtrlFilter.adjust(w0); std::copy(std::begin(Device->NumChannelsPerOrder), std::end(Device->NumChannelsPerOrder), @@ -851,25 +846,26 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo if(Device->Dry.Buffer == Device->RealOut.Buffer) { int idx = GetChannelIdxByName(Device->RealOut, chans[c].channel); - if(idx != -1) voice->mDirect.Params[c].Gains.Target[idx] = DryGain; + if(idx != -1) voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain; } continue; } ComputePanGains(&Device->Dry, coeffs, DryGain * downmix_gain, - voice->mDirect.Params[c].Gains.Target); + voice->mChans[c].mDryParams.Gains.Target); } - for(ALsizei i{0};i < NumSends;i++) + for(ALsizei c{0};c < num_channels;c++) { - if(const ALeffectslot *Slot{SendSlots[i]}) - for(ALsizei c{0};c < num_channels;c++) - { - /* Skip LFE */ - if(chans[c].channel != LFE) - ComputePanGains(&Slot->Wet, coeffs, WetGain[i] * downmix_gain, - voice->mSend[i].Params[c].Gains.Target); - } + /* Skip LFE */ + if(chans[c].channel == LFE) + continue; + for(ALsizei i{0};i < NumSends;i++) + { + if(const ALeffectslot *Slot{SendSlots[i]}) + ComputePanGains(&Slot->Wet, coeffs, WetGain[i] * downmix_gain, + voice->mChans[c].mWetParams[i].Gains.Target); + } } } else @@ -884,7 +880,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo const ALfloat w0{SPEEDOFSOUNDMETRESPERSEC / (Device->AvgSpeakerDist * Frequency)}; for(ALsizei c{0};c < num_channels;c++) - voice->mDirect.Params[c].NFCtrlFilter.adjust(w0); + voice->mChans[c].mDryParams.NFCtrlFilter.adjust(w0); std::copy(std::begin(Device->NumChannelsPerOrder), std::end(Device->NumChannelsPerOrder), @@ -900,7 +896,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo if(Device->Dry.Buffer == Device->RealOut.Buffer) { int idx = GetChannelIdxByName(Device->RealOut, chans[c].channel); - if(idx != -1) voice->mDirect.Params[c].Gains.Target[idx] = DryGain; + if(idx != -1) voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain; } continue; } @@ -913,12 +909,12 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo ); ComputePanGains(&Device->Dry, coeffs, DryGain, - voice->mDirect.Params[c].Gains.Target); + voice->mChans[c].mDryParams.Gains.Target); for(ALsizei i{0};i < NumSends;i++) { if(const ALeffectslot *Slot{SendSlots[i]}) ComputePanGains(&Slot->Wet, coeffs, WetGain[i], - voice->mSend[i].Params[c].Gains.Target); + voice->mChans[c].mWetParams[i].Gains.Target); } } } @@ -933,14 +929,16 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo voice->mDirect.FilterType = AF_None; if(gainHF != 1.0f) voice->mDirect.FilterType |= AF_LowPass; if(gainLF != 1.0f) voice->mDirect.FilterType |= AF_HighPass; - voice->mDirect.Params[0].LowPass.setParams(BiquadType::HighShelf, - gainHF, hfScale, BiquadFilter::rcpQFromSlope(gainHF, 1.0f)); - voice->mDirect.Params[0].HighPass.setParams(BiquadType::LowShelf, - gainLF, lfScale, BiquadFilter::rcpQFromSlope(gainLF, 1.0f)); + auto &lowpass = voice->mChans[0].mDryParams.LowPass; + auto &highpass = voice->mChans[0].mDryParams.HighPass; + lowpass.setParams(BiquadType::HighShelf, gainHF, hfScale, + lowpass.rcpQFromSlope(gainHF, 1.0f)); + highpass.setParams(BiquadType::LowShelf, gainLF, lfScale, + highpass.rcpQFromSlope(gainLF, 1.0f)); for(ALsizei c{1};c < num_channels;c++) { - voice->mDirect.Params[c].LowPass.copyParamsFrom(voice->mDirect.Params[0].LowPass); - voice->mDirect.Params[c].HighPass.copyParamsFrom(voice->mDirect.Params[0].HighPass); + voice->mChans[c].mDryParams.LowPass.copyParamsFrom(lowpass); + voice->mChans[c].mDryParams.HighPass.copyParamsFrom(highpass); } } for(ALsizei i{0};i < NumSends;i++) @@ -953,14 +951,17 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo voice->mSend[i].FilterType = AF_None; if(gainHF != 1.0f) voice->mSend[i].FilterType |= AF_LowPass; if(gainLF != 1.0f) voice->mSend[i].FilterType |= AF_HighPass; - voice->mSend[i].Params[0].LowPass.setParams(BiquadType::HighShelf, - gainHF, hfScale, BiquadFilter::rcpQFromSlope(gainHF, 1.0f)); - voice->mSend[i].Params[0].HighPass.setParams(BiquadType::LowShelf, - gainLF, lfScale, BiquadFilter::rcpQFromSlope(gainLF, 1.0f)); + + auto &lowpass = voice->mChans[0].mWetParams[i].LowPass; + auto &highpass = voice->mChans[0].mWetParams[i].HighPass; + lowpass.setParams(BiquadType::HighShelf, gainHF, hfScale, + lowpass.rcpQFromSlope(gainHF, 1.0f)); + highpass.setParams(BiquadType::LowShelf, gainLF, lfScale, + highpass.rcpQFromSlope(gainLF, 1.0f)); for(ALsizei c{1};c < num_channels;c++) { - voice->mSend[i].Params[c].LowPass.copyParamsFrom(voice->mSend[i].Params[0].LowPass); - voice->mSend[i].Params[c].HighPass.copyParamsFrom(voice->mSend[i].Params[0].HighPass); + voice->mChans[c].mWetParams[i].LowPass.copyParamsFrom(lowpass); + voice->mChans[c].mWetParams[i].HighPass.copyParamsFrom(highpass); } } } diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index fc70fa2e..33ea00bb 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -540,8 +540,10 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc ASSUME(increment > 0); ALCdevice *Device{Context->Device}; + const ALsizei NumSends{Device->NumAuxSends}; const ALsizei IrSize{Device->mHrtf ? Device->mHrtf->irSize : 0}; + ASSUME(NumSends >= 0); ASSUME(IrSize >= 0); ResamplerFunc Resample{(increment == FRACTIONONE && DataPosFrac == 0) ? @@ -553,29 +555,29 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc /* No fading, just overwrite the old/current params. */ for(ALsizei chan{0};chan < NumChannels;chan++) { - DirectParams &parms = voice->mDirect.Params[chan]; + ALvoice::ChannelData &chandata = voice->mChans[chan]; + DirectParams &parms = chandata.mDryParams; if(!(voice->mFlags&VOICE_HAS_HRTF)) std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target), std::begin(parms.Gains.Current)); else parms.Hrtf.Old = parms.Hrtf.Target; - auto set_current = [chan](ALvoice::SendData &send) -> void + for(ALsizei send{0};send < NumSends;++send) { - if(send.Buffer.empty()) - return; + if(voice->mSend[send].Buffer.empty()) + continue; - SendParams &parms = send.Params[chan]; + SendParams &parms = chandata.mWetParams[chan]; std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target), std::begin(parms.Gains.Current)); - }; - std::for_each(voice->mSend.begin(), voice->mSend.end(), set_current); + } } } else if((voice->mFlags&VOICE_HAS_HRTF)) { for(ALsizei chan{0};chan < NumChannels;chan++) { - DirectParams &parms = voice->mDirect.Params[chan]; + DirectParams &parms = voice->mChans[chan].mDryParams; if(!(parms.Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD)) { /* The old HRTF params are silent, so overwrite the old @@ -626,14 +628,14 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc const al::span SrcData{Device->SourceData, SrcBufferSize}; /* Load the previous samples into the source data first, and clear the rest. */ - auto srciter = std::copy_n(voice->mResampleData[chan].mPrevSamples.begin(), + auto srciter = std::copy_n(voice->mChans[chan].mPrevSamples.begin(), MAX_RESAMPLE_PADDING, SrcData.begin()); std::fill(srciter, SrcData.end(), 0.0f); if(UNLIKELY(!BufferListItem)) srciter = std::copy( - voice->mResampleData[chan].mPrevSamples.begin()+MAX_RESAMPLE_PADDING, - voice->mResampleData[chan].mPrevSamples.end(), srciter); + voice->mChans[chan].mPrevSamples.begin()+MAX_RESAMPLE_PADDING, + voice->mChans[chan].mPrevSamples.end(), srciter); else if(isstatic) srciter = LoadBufferStatic(BufferListItem, BufferLoopItem, NumChannels, SampleSize, chan, DataPosInt, srciter, SrcData.end()); @@ -654,8 +656,8 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc /* Store the last source samples used for next time. */ std::copy_n(&SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS], - voice->mResampleData[chan].mPrevSamples.size(), - voice->mResampleData[chan].mPrevSamples.begin()); + voice->mChans[chan].mPrevSamples.size(), + voice->mChans[chan].mPrevSamples.begin()); /* Resample, then apply ambisonic upsampling as needed. */ const ALfloat *ResampledData{Resample(&voice->mResampleState, @@ -663,20 +665,20 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc Device->ResampledData, DstBufferSize)}; if((voice->mFlags&VOICE_IS_AMBISONIC)) { - const ALfloat hfscale{voice->mResampleData[chan].mAmbiScale}; + const ALfloat hfscale{voice->mChans[chan].mAmbiScale}; /* Beware the evil const_cast. It's safe since it's pointing to * either SourceData or ResampledData (both non-const), but the * resample method takes the source as const float* and may * return it without copying to output, making it currently * unavoidable. */ - voice->mResampleData[chan].mAmbiSplitter.applyHfScale( - const_cast(ResampledData), hfscale, DstBufferSize); + voice->mChans[chan].mAmbiSplitter.applyHfScale(const_cast(ResampledData), + hfscale, DstBufferSize); } /* Now filter and mix to the appropriate outputs. */ { - DirectParams &parms = voice->mDirect.Params[chan]; + DirectParams &parms = voice->mChans[chan].mDryParams; const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, Device->FilteredData, ResampledData, DstBufferSize, voice->mDirect.FilterType)}; @@ -832,21 +834,20 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc } ALfloat (&FilterBuf)[BUFFERSIZE] = Device->FilteredData; - auto mix_send = [vstate,Counter,OutPos,DstBufferSize,chan,ResampledData,&FilterBuf](ALvoice::SendData &send) -> void + for(ALsizei send{0};send < NumSends;++send) { - if(send.Buffer.empty()) - return; + if(voice->mSend[send].Buffer.empty()) + continue; - SendParams &parms = send.Params[chan]; + SendParams &parms = voice->mChans[chan].mWetParams[send]; const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, - FilterBuf, ResampledData, DstBufferSize, send.FilterType)}; + FilterBuf, ResampledData, DstBufferSize, voice->mSend[send].FilterType)}; const ALfloat *TargetGains{UNLIKELY(vstate==ALvoice::Stopping) ? SilentTarget : parms.Gains.Target}; - MixSamples(samples, send.Buffer, parms.Gains.Current, TargetGains, Counter, OutPos, - DstBufferSize); + MixSamples(samples, voice->mSend[send].Buffer, parms.Gains.Current, TargetGains, + Counter, OutPos, DstBufferSize); }; - std::for_each(voice->mSend.begin(), voice->mSend.end(), mix_send); } /* Update positions */ DataPosFrac += increment*DstBufferSize; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index cb0b675c..25a1d422 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -253,39 +253,33 @@ struct ALvoice { ALuint mFlags; - struct ResampleData { - alignas(16) std::array mPrevSamples; - - ALfloat mAmbiScale; - BandSplitter mAmbiSplitter; - }; - std::array mResampleData; - - struct { + struct DirectData { int FilterType; - DirectParams Params[MAX_INPUT_CHANNELS]; - al::span Buffer; ALsizei ChannelsPerOrder[MAX_AMBI_ORDER+1]; - } mDirect; + }; + DirectData mDirect; struct SendData { int FilterType; - SendParams Params[MAX_INPUT_CHANNELS]; - al::span Buffer; }; - al::FlexArray mSend; + std::array mSend; + + struct ChannelData { + alignas(16) std::array mPrevSamples; - ALvoice(size_t numsends) : mSend{numsends} { } + ALfloat mAmbiScale; + BandSplitter mAmbiSplitter; + + DirectParams mDryParams; + std::array mWetParams; + }; + std::array mChans; + + ALvoice() = default; ALvoice(const ALvoice&) = delete; ALvoice& operator=(const ALvoice&) = delete; - - static constexpr size_t Sizeof(size_t numsends) noexcept - { - return maxz(sizeof(ALvoice), - al::FlexArray::Sizeof(numsends, offsetof(ALvoice, mSend))); - } }; void DeinitVoice(ALvoice *voice) noexcept; diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 02396fd0..d2414e50 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -2938,40 +2938,42 @@ START_API_FUNC BandSplitter splitter{400.0f / static_cast(device->Frequency)}; const auto scales = BFormatDec::GetHFOrderScales(1, device->mAmbiOrder); - auto init_ambi = [scales,&OrderFromChan,&splitter](ALvoice::ResampleData &resdata) -> void + auto init_ambi = [scales,&OrderFromChan,&splitter](ALvoice::ChannelData &chandata) -> void { - resdata.mPrevSamples.fill(0.0f); - resdata.mAmbiScale = scales[*(OrderFromChan++)]; - resdata.mAmbiSplitter = splitter; + chandata.mPrevSamples.fill(0.0f); + chandata.mAmbiScale = scales[*(OrderFromChan++)]; + chandata.mAmbiSplitter = splitter; }; - std::for_each(voice->mResampleData.begin(), - voice->mResampleData.begin()+voice->mNumChannels, init_ambi); + std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, + init_ambi); voice->mFlags |= VOICE_IS_AMBISONIC; } else { /* Clear previous samples. */ - auto clear_prevs = [](ALvoice::ResampleData &resdata) -> void - { resdata.mPrevSamples.fill(0.0f); }; - std::for_each(voice->mResampleData.begin(), - voice->mResampleData.begin()+voice->mNumChannels, clear_prevs); + auto clear_prevs = [](ALvoice::ChannelData &chandata) -> void + { chandata.mPrevSamples.fill(0.0f); }; + std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, + clear_prevs); } - std::fill_n(std::begin(voice->mDirect.Params), voice->mNumChannels, DirectParams{}); - std::for_each(voice->mSend.begin(), voice->mSend.end(), - [voice](ALvoice::SendData &send) -> void - { std::fill_n(std::begin(send.Params), voice->mNumChannels, SendParams{}); } - ); + auto clear_params = [device](ALvoice::ChannelData &chandata) -> void + { + chandata.mDryParams = DirectParams{}; + std::fill_n(chandata.mWetParams.begin(), device->NumAuxSends, SendParams{}); + }; + std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, + clear_params); if(device->AvgSpeakerDist > 0.0f) { const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC / (device->AvgSpeakerDist * device->Frequency)}; - std::for_each(voice->mDirect.Params+0, voice->mDirect.Params+voice->mNumChannels, - [w1](DirectParams &parms) noexcept -> void - { parms.NFCtrlFilter.init(w1); } - ); + auto init_nfc = [w1](ALvoice::ChannelData &chandata) -> void + { chandata.mDryParams.NFCtrlFilter.init(w1); }; + std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, + init_nfc); } voice->mSourceID.store(source->id, std::memory_order_relaxed); -- cgit v1.2.3 From f0bc9d8a9b45a86cf0736a3f118b28ae6fdb90f0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 3 Jun 2019 22:58:56 -0700 Subject: Improve alignment handling for the alignment allocator --- Alc/hrtf.cpp | 2 +- OpenAL32/alAuxEffectSlot.cpp | 2 +- common/almalloc.cpp | 4 ++++ common/almalloc.h | 4 ++-- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 45f63c11..d1029aeb 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -66,7 +66,7 @@ struct HrtfHandle { std::unique_ptr HrtfHandle::Create(size_t fname_len) { - void *ptr{al_calloc(DEF_ALIGN, HrtfHandle::Sizeof(fname_len))}; + void *ptr{al_calloc(alignof(HrtfHandle), HrtfHandle::Sizeof(fname_len))}; return std::unique_ptr{new (ptr) HrtfHandle{fname_len}}; } diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index 44503436..ae038581 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -246,7 +246,7 @@ ALeffectslotArray *ALeffectslot::CreatePtrArray(size_t count) noexcept /* Allocate space for twice as many pointers, so the mixer has scratch * space to store a sorted list during mixing. */ - void *ptr{al_calloc(DEF_ALIGN, ALeffectslotArray::Sizeof(count*2))}; + void *ptr{al_calloc(alignof(ALeffectslotArray), ALeffectslotArray::Sizeof(count*2))}; return new (ptr) ALeffectslotArray{count}; } diff --git a/common/almalloc.cpp b/common/almalloc.cpp index 35b95001..f7af5bf3 100644 --- a/common/almalloc.cpp +++ b/common/almalloc.cpp @@ -3,6 +3,7 @@ #include "almalloc.h" +#include #include #include #ifdef HAVE_MALLOC_H @@ -26,6 +27,9 @@ void *al_malloc(size_t alignment, size_t size) { + assert((alignment & (alignment-1)) == 0); + alignment = std::max(alignment, sizeof(void*)); + #if defined(HAVE_ALIGNED_ALLOC) size = (size+(alignment-1))&~(alignment-1); return aligned_alloc(alignment, size); diff --git a/common/almalloc.h b/common/almalloc.h index 406c2d31..0d77c46d 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -39,7 +39,7 @@ int al_is_sane_alignment_allocator(void) noexcept; namespace al { -template +template struct allocator : public std::allocator { using size_type = size_t; using pointer = T*; @@ -97,7 +97,7 @@ std::unique_ptr make_unique(ArgsT&&...args) * struct, with placement new, to have a run-time-sized array that's embedded * with its size. */ -template +template struct FlexArray { const size_t mSize; alignas(alignment) T mArray[]; -- cgit v1.2.3 From 4522a51ea21813de9a59dd059c50f85d8a5116f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 4 Jun 2019 01:37:36 -0700 Subject: Don't log the function or prefix It's ultimately unnecessary since the message is an indicator about where it was logged from. The message itself is generally more important than where it was from, too. --- Alc/alc.cpp | 14 +++++++------- Alc/alcontext.h | 1 - Alc/backends/alsa.cpp | 2 -- Alc/backends/coreaudio.cpp | 2 -- Alc/backends/dsound.cpp | 2 -- Alc/backends/jack.cpp | 1 - Alc/backends/null.cpp | 1 - Alc/backends/opensl.cpp | 2 -- Alc/backends/oss.cpp | 2 -- Alc/backends/portaudio.cpp | 2 -- Alc/backends/pulseaudio.cpp | 2 -- Alc/backends/qsa.cpp | 2 -- Alc/backends/sdl2.cpp | 1 - Alc/backends/sndio.cpp | 2 -- Alc/backends/solaris.cpp | 1 - Alc/backends/wasapi.cpp | 4 ---- Alc/backends/wave.cpp | 1 - Alc/backends/winmm.cpp | 2 -- Alc/helpers.cpp | 12 ++++++------ Alc/hrtf.cpp | 4 ++-- Alc/hrtf.h | 1 - Alc/logging.h | 13 ++++++------- OpenAL32/Include/alMain.h | 1 - OpenAL32/alAuxEffectSlot.cpp | 4 ++-- 24 files changed, 23 insertions(+), 56 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 6ade082e..8378673d 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -811,7 +811,7 @@ std::atomic LastNullDeviceError{ALC_NO_ERROR}; void ReleaseThreadCtx(ALCcontext *context) { auto ref = DecrementRef(&context->ref); - TRACEREF("%p decreasing refcount to %u\n", context, ref); + TRACEREF("ALCcontext %p decreasing refcount to %u\n", context, ref); ERR("Context %p current for thread being destroyed, possible leak!\n", context); } @@ -2206,7 +2206,7 @@ ALCdevice::ALCdevice(DeviceType type) : Type{type} */ ALCdevice::~ALCdevice() { - TRACE("%p\n", this); + TRACE("Freeing device %p\n", this); Backend = nullptr; @@ -2240,13 +2240,13 @@ ALCdevice::~ALCdevice() static void ALCdevice_IncRef(ALCdevice *device) { auto ref = IncrementRef(&device->ref); - TRACEREF("%p increasing refcount to %u\n", device, ref); + TRACEREF("ALCdevice %p increasing refcount to %u\n", device, ref); } static void ALCdevice_DecRef(ALCdevice *device) { auto ref = DecrementRef(&device->ref); - TRACEREF("%p decreasing refcount to %u\n", device, ref); + TRACEREF("ALCdevice %p decreasing refcount to %u\n", device, ref); if(UNLIKELY(ref == 0)) delete device; } @@ -2370,7 +2370,7 @@ static ALvoid InitContext(ALCcontext *Context) */ ALCcontext::~ALCcontext() { - TRACE("%p\n", this); + TRACE("Freeing context %p\n", this); ALcontextProps *cprops{Update.exchange(nullptr, std::memory_order_relaxed)}; if(cprops) @@ -2533,13 +2533,13 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) static void ALCcontext_IncRef(ALCcontext *context) { auto ref = IncrementRef(&context->ref); - TRACEREF("%p increasing refcount to %u\n", context, ref); + TRACEREF("ALCcontext %p increasing refcount to %u\n", context, ref); } void ALCcontext_DecRef(ALCcontext *context) { auto ref = DecrementRef(&context->ref); - TRACEREF("%p decreasing refcount to %u\n", context, ref); + TRACEREF("ALCcontext %p decreasing refcount to %u\n", context, ref); if(UNLIKELY(ref == 0)) delete context; } diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 2c4ad1d3..769847f8 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -147,7 +147,6 @@ struct ALCcontext { ALCcontext& operator=(const ALCcontext&) = delete; ~ALCcontext(); - static constexpr inline const char *CurrentPrefix() noexcept { return "ALCcontext::"; } DEF_NEWDEL(ALCcontext) }; diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index a2937658..eee89b28 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -404,7 +404,6 @@ struct AlsaPlayback final : public BackendBase { std::atomic mKillNow{true}; std::thread mThread; - static constexpr inline const char *CurrentPrefix() noexcept { return "AlsaPlayback::"; } DEF_NEWDEL(AlsaPlayback) }; @@ -878,7 +877,6 @@ struct AlsaCapture final : public BackendBase { snd_pcm_sframes_t mLastAvail{0}; - static constexpr inline const char *CurrentPrefix() noexcept { return "AlsaCapture::"; } DEF_NEWDEL(AlsaCapture) }; diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index d8b4500e..a776cb9e 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -63,7 +63,6 @@ struct CoreAudioPlayback final : public BackendBase { ALuint mFrameSize{0u}; AudioStreamBasicDescription mFormat{}; // This is the OpenAL format as a CoreAudio ASBD - static constexpr inline const char *CurrentPrefix() noexcept { return "CoreAudioPlayback::"; } DEF_NEWDEL(CoreAudioPlayback) }; @@ -329,7 +328,6 @@ struct CoreAudioCapture final : public BackendBase { RingBufferPtr mRing{nullptr}; - static constexpr inline const char *CurrentPrefix() noexcept { return "CoreAudioCapture::"; } DEF_NEWDEL(CoreAudioCapture) }; diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 38b1b9f8..039f78ac 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -173,7 +173,6 @@ struct DSoundPlayback final : public BackendBase { std::atomic mKillNow{true}; std::thread mThread; - static constexpr inline const char *CurrentPrefix() noexcept { return "DSoundPlayback::"; } DEF_NEWDEL(DSoundPlayback) }; @@ -601,7 +600,6 @@ struct DSoundCapture final : public BackendBase { RingBufferPtr mRing; - static constexpr inline const char *CurrentPrefix() noexcept { return "DSoundCapture::"; } DEF_NEWDEL(DSoundCapture) }; diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index 74364f6a..c58f73bc 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -176,7 +176,6 @@ struct JackPlayback final : public BackendBase { std::atomic mKillNow{true}; std::thread mThread; - static constexpr inline const char *CurrentPrefix() noexcept { return "JackPlayback::"; } DEF_NEWDEL(JackPlayback) }; diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 07907dec..121d7700 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -58,7 +58,6 @@ struct NullBackend final : public BackendBase { std::atomic mKillNow{true}; std::thread mThread; - static constexpr inline const char *CurrentPrefix() noexcept { return "NullBackend::"; } DEF_NEWDEL(NullBackend) }; diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 1cf309f7..4cf7ca36 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -174,7 +174,6 @@ struct OpenSLPlayback final : public BackendBase { std::atomic mKillNow{true}; std::thread mThread; - static constexpr inline const char *CurrentPrefix() noexcept { return "OpenSLPlayback::"; } DEF_NEWDEL(OpenSLPlayback) }; @@ -632,7 +631,6 @@ struct OpenSLCapture final : public BackendBase { ALsizei mFrameSize{0}; - static constexpr inline const char *CurrentPrefix() noexcept { return "OpenSLCapture::"; } DEF_NEWDEL(OpenSLCapture) }; diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index cc385edf..0a28fcd8 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -260,7 +260,6 @@ struct OSSPlayback final : public BackendBase { std::atomic mKillNow{true}; std::thread mThread; - static constexpr inline const char *CurrentPrefix() noexcept { return "OSSPlayback::"; } DEF_NEWDEL(OSSPlayback) }; @@ -490,7 +489,6 @@ struct OSScapture final : public BackendBase { std::atomic mKillNow{true}; std::thread mThread; - static constexpr inline const char *CurrentPrefix() noexcept { return "OSScapture::"; } DEF_NEWDEL(OSScapture) }; diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index 6df98434..990fcbf6 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -89,7 +89,6 @@ struct PortPlayback final : public BackendBase { PaStreamParameters mParams{}; ALuint mUpdateSize{0u}; - static constexpr inline const char *CurrentPrefix() noexcept { return "PortPlayback::"; } DEF_NEWDEL(PortPlayback) }; @@ -256,7 +255,6 @@ struct PortCapture final : public BackendBase { RingBufferPtr mRing{nullptr}; - static constexpr inline const char *CurrentPrefix() noexcept { return "PortCapture::"; } DEF_NEWDEL(PortCapture) }; diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index f5483818..30c0053d 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -681,7 +681,6 @@ struct PulsePlayback final : public BackendBase { ALuint mFrameSize{0u}; - static constexpr inline const char *CurrentPrefix() noexcept { return "PulsePlayback::"; } DEF_NEWDEL(PulsePlayback) }; @@ -1130,7 +1129,6 @@ struct PulseCapture final : public BackendBase { pa_stream *mStream{nullptr}; pa_context *mContext{nullptr}; - static constexpr inline const char *CurrentPrefix() noexcept { return "PulseCapture::"; } DEF_NEWDEL(PulseCapture) }; diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index 534d5798..074430ca 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -181,7 +181,6 @@ struct PlaybackWrapper final : public BackendBase { std::unique_ptr mExtraData; - static constexpr inline const char *CurrentPrefix() noexcept { return "PlaybackWrapper::"; } DEF_NEWDEL(PlaybackWrapper) }; @@ -643,7 +642,6 @@ struct CaptureWrapper final : public BackendBase { std::unique_ptr mExtraData; - static constexpr inline const char *CurrentPrefix() noexcept { return "CaptureWrapper::"; } DEF_NEWDEL(CaptureWrapper) }; diff --git a/Alc/backends/sdl2.cpp b/Alc/backends/sdl2.cpp index 51c927cc..a7a1752e 100644 --- a/Alc/backends/sdl2.cpp +++ b/Alc/backends/sdl2.cpp @@ -65,7 +65,6 @@ struct Sdl2Backend final : public BackendBase { DevFmtType mFmtType{}; ALuint mUpdateSize{0u}; - static constexpr inline const char *CurrentPrefix() noexcept { return "ALCsdl2Playback::"; } DEF_NEWDEL(Sdl2Backend) }; diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index 163dd2ff..e696cf55 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -61,7 +61,6 @@ struct SndioPlayback final : public BackendBase { std::atomic mKillNow{true}; std::thread mThread; - static constexpr inline const char *CurrentPrefix() noexcept { return "SndioPlayback::"; } DEF_NEWDEL(SndioPlayback) }; @@ -263,7 +262,6 @@ struct SndioCapture final : public BackendBase { std::atomic mKillNow{true}; std::thread mThread; - static constexpr inline const char *CurrentPrefix() noexcept { return "SndioCapture::"; } DEF_NEWDEL(SndioCapture) }; diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index 3e59a78c..5c378bff 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -73,7 +73,6 @@ struct SolarisBackend final : public BackendBase { std::atomic mKillNow{true}; std::thread mThread; - static constexpr inline const char *CurrentPrefix() noexcept { return "SolarisBackend::"; } DEF_NEWDEL(SolarisBackend) }; diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index e41116d4..c80e5943 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -376,8 +376,6 @@ struct WasapiProxy { } static int messageHandler(std::promise *promise); - - static constexpr inline const char *CurrentPrefix() noexcept { return "WasapiProxy::"; } }; std::deque WasapiProxy::mMsgQueue; std::mutex WasapiProxy::mMsgQueueLock; @@ -533,7 +531,6 @@ struct WasapiPlayback final : public BackendBase, WasapiProxy { std::atomic mKillNow{true}; std::thread mThread; - static constexpr inline const char *CurrentPrefix() noexcept { return "WasapiPlayback::"; } DEF_NEWDEL(WasapiPlayback) }; @@ -1113,7 +1110,6 @@ struct WasapiCapture final : public BackendBase, WasapiProxy { std::atomic mKillNow{true}; std::thread mThread; - static constexpr inline const char *CurrentPrefix() noexcept { return "WasapiCapture::"; } DEF_NEWDEL(WasapiCapture) }; diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index bf1736f2..d06f36d7 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -98,7 +98,6 @@ struct WaveBackend final : public BackendBase { std::atomic mKillNow{true}; std::thread mThread; - static constexpr inline const char *CurrentPrefix() noexcept { return "WaveBackend::"; } DEF_NEWDEL(WaveBackend) }; diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 12fa02c4..f23ac53c 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -147,7 +147,6 @@ struct WinMMPlayback final : public BackendBase { std::atomic mKillNow{true}; std::thread mThread; - static constexpr inline const char *CurrentPrefix() noexcept { return "WinMMPlayback::"; } DEF_NEWDEL(WinMMPlayback) }; @@ -393,7 +392,6 @@ struct WinMMCapture final : public BackendBase { std::atomic mKillNow{true}; std::thread mThread; - static constexpr inline const char *CurrentPrefix() noexcept { return "WinMMCapture::"; } DEF_NEWDEL(WinMMCapture) }; diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index 1a62263e..813b954f 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -336,7 +336,7 @@ const PathNamePair &GetProcBinary() else ret.fname = wstr_to_utf8(fullpath.data()); - TRACE("Got: %s, %s\n", ret.path.c_str(), ret.fname.c_str()); + TRACE("Got binary: %s, %s\n", ret.path.c_str(), ret.fname.c_str()); return ret; } @@ -356,7 +356,7 @@ void *GetSymbol(void *handle, const char *name) } -void al_print(const char *type, const char *prefix, const char *func, const char *fmt, ...) +void al_print(const char *type, const char *fmt, ...) { al::vector dynmsg; char stcmsg[256]; @@ -376,7 +376,7 @@ void al_print(const char *type, const char *prefix, const char *func, const char va_end(args); std::wstring wstr{utf8_to_wstr(str)}; - fprintf(gLogFile, "AL lib: %s %s%s: %ls", type, prefix, func, wstr.c_str()); + fprintf(gLogFile, "AL lib: %s %ls", type, wstr.c_str()); fflush(gLogFile); } @@ -560,7 +560,7 @@ const PathNamePair &GetProcBinary() else ret.fname = std::string(pathname.cbegin(), pathname.cend()); - TRACE("Got: %s, %s\n", ret.path.c_str(), ret.fname.c_str()); + TRACE("Got binary: %s, %s\n", ret.path.c_str(), ret.fname.c_str()); return ret; } @@ -592,12 +592,12 @@ void *GetSymbol(void *handle, const char *name) #endif /* HAVE_DLFCN_H */ -void al_print(const char *type, const char *prefix, const char *func, const char *fmt, ...) +void al_print(const char *type, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - fprintf(gLogFile, "AL lib: %s %s%s: ", type, prefix, func); + fprintf(gLogFile, "AL lib: %s ", type); vfprintf(gLogFile, fmt, ap); va_end(ap); diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index d1029aeb..16b2dc3c 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -1365,13 +1365,13 @@ HrtfEntry *GetLoadedHrtf(HrtfHandle *handle) void HrtfEntry::IncRef() { auto ref = IncrementRef(&this->ref); - TRACEREF("%p increasing refcount to %u\n", this, ref); + TRACEREF("HrtfEntry %p increasing refcount to %u\n", this, ref); } void HrtfEntry::DecRef() { auto ref = DecrementRef(&this->ref); - TRACEREF("%p decreasing refcount to %u\n", this, ref); + TRACEREF("HrtfEntry %p decreasing refcount to %u\n", this, ref); if(ref == 0) { std::lock_guard _{LoadedHrtfLock}; diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 0283de13..46a03e43 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -50,7 +50,6 @@ struct HrtfEntry { void IncRef(); void DecRef(); - static constexpr inline const char *CurrentPrefix() noexcept { return "HrtfEntry::"; } DEF_PLACE_NEWDEL() }; diff --git a/Alc/logging.h b/Alc/logging.h index e709bbf2..b5faf698 100644 --- a/Alc/logging.h +++ b/Alc/logging.h @@ -15,19 +15,18 @@ extern FILE *gLogFile; -constexpr inline const char *CurrentPrefix() noexcept { return ""; } -#if defined(__GNUC__) && !defined(_WIN32) -#define AL_PRINT(T, MSG, ...) fprintf(gLogFile, "AL lib: %s %s%s: " MSG, T, CurrentPrefix(), __FUNCTION__ , ## __VA_ARGS__) +#if !defined(_WIN32) +#define AL_PRINT(T, ...) fprintf(gLogFile, "AL lib: " T " " __VA_ARGS__) #else -void al_print(const char *type, const char *prefix, const char *func, const char *fmt, ...) DECL_FORMAT(printf, 4,5); -#define AL_PRINT(T, ...) al_print((T), CurrentPrefix(), __FUNCTION__, __VA_ARGS__) +void al_print(const char *type, const char *fmt, ...) DECL_FORMAT(printf, 2,3); +#define AL_PRINT(T, ...) al_print((T), __VA_ARGS__) #endif #ifdef __ANDROID__ #include -#define LOG_ANDROID(T, MSG, ...) __android_log_print(T, "openal", "AL lib: %s%s: " MSG, CurrentPrefix(), __FUNCTION__ , ## __VA_ARGS__) +#define LOG_ANDROID(T, ...) __android_log_print(T, "openal", "AL lib: " __VA_ARGS__) #else -#define LOG_ANDROID(T, MSG, ...) ((void)0) +#define LOG_ANDROID(T, ...) ((void)0) #endif enum LogLevel { diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 7538ade2..36042782 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -471,7 +471,6 @@ struct ALCdevice { ALsizei channelsFromFmt() const noexcept { return ChannelsFromDevFmt(FmtChans, mAmbiOrder); } ALsizei frameSizeFromFmt() const noexcept { return bytesFromFmt() * channelsFromFmt(); } - static constexpr inline const char *CurrentPrefix() noexcept { return "ALCdevice::"; } DEF_NEWDEL(ALCdevice) }; diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index ae038581..eeb545c9 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -688,13 +688,13 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect void EffectState::IncRef() noexcept { auto ref = IncrementRef(&mRef); - TRACEREF("%p increasing refcount to %u\n", this, ref); + TRACEREF("EffectState %p increasing refcount to %u\n", this, ref); } void EffectState::DecRef() noexcept { auto ref = DecrementRef(&mRef); - TRACEREF("%p decreasing refcount to %u\n", this, ref); + TRACEREF("EffectState %p decreasing refcount to %u\n", this, ref); if(ref == 0) delete this; } -- cgit v1.2.3 From 9d861406c06d44f4b39e25f3a4deabdf11242ea1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 4 Jun 2019 17:50:36 -0700 Subject: Avoid a separate struct for the bandsplitter all-pass --- Alc/alu.cpp | 11 +++-------- Alc/filters/splitter.cpp | 27 +++++---------------------- Alc/filters/splitter.h | 27 +++++++-------------------- Alc/hrtf.cpp | 7 ++----- Alc/panning.cpp | 3 --- 5 files changed, 17 insertions(+), 58 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index d41a66aa..97ebf0cb 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1499,7 +1499,6 @@ void ApplyStablizer(FrontStablizer *Stablizer, FloatBufferLine *Buffer, const in } } - const SplitterAllpass &APFilter = Stablizer->APFilter; ALfloat (&lsplit)[2][BUFFERSIZE] = Stablizer->LSplit; ALfloat (&rsplit)[2][BUFFERSIZE] = Stablizer->RSplit; auto &tmpbuf = Stablizer->TempBuf; @@ -1507,7 +1506,7 @@ void ApplyStablizer(FrontStablizer *Stablizer, FloatBufferLine *Buffer, const in /* This applies the band-splitter, preserving phase at the cost of some * delay. The shorter the delay, the more error seeps into the result. */ - auto apply_splitter = [&APFilter,&tmpbuf,SamplesToDo](const FloatBufferLine &Buffer, + auto apply_splitter = [&tmpbuf,SamplesToDo](const FloatBufferLine &Buffer, ALfloat (&DelayBuf)[FrontStablizer::DelayLength], BandSplitter &Filter, ALfloat (&splitbuf)[2][BUFFERSIZE]) -> void { @@ -1522,13 +1521,9 @@ void ApplyStablizer(FrontStablizer *Stablizer, FloatBufferLine *Buffer, const in std::copy_n(std::begin(tmpbuf), FrontStablizer::DelayLength, std::begin(DelayBuf)); /* Apply an all-pass on the reversed signal, then reverse the samples - * to get the forward signal with a reversed phase shift. Note that the - * all-pass filter is copied to a local for use, since each pass is - * indepedent because the signal's processed backwards (with a delay - * being used to hide discontinuities). + * to get the forward signal with a reversed phase shift. */ - SplitterAllpass allpass{APFilter}; - allpass.process(tmpbuf, SamplesToDo+FrontStablizer::DelayLength); + Filter.applyAllpass(tmpbuf, SamplesToDo+FrontStablizer::DelayLength); std::reverse(std::begin(tmpbuf), tmpbuf_end+FrontStablizer::DelayLength); /* Now apply the band-splitter, combining its phase shift with the diff --git a/Alc/filters/splitter.cpp b/Alc/filters/splitter.cpp index 8b1a4db4..09e7bfe8 100644 --- a/Alc/filters/splitter.cpp +++ b/Alc/filters/splitter.cpp @@ -94,30 +94,13 @@ void BandSplitterR::applyHfScale(Real *samples, const Real hfscale, const this->ap_z1 = ap_z1; } -template class BandSplitterR; -template class BandSplitterR; - - -template -void SplitterAllpassR::init(Real f0norm) -{ - const Real w{f0norm * al::MathDefs::Tau()}; - const Real cw{std::cos(w)}; - if(cw > std::numeric_limits::epsilon()) - coeff = (std::sin(w) - 1.0f) / cw; - else - coeff = cw * -0.5f; - - z1 = 0.0f; -} - template -void SplitterAllpassR::process(Real *samples, int count) +void BandSplitterR::applyAllpass(Real *samples, const int count) const { ASSUME(count > 0); const Real coeff{this->coeff}; - Real z1{this->z1}; + Real z1{0.0f}; auto proc_sample = [coeff,&z1](const Real in) noexcept -> Real { const Real out{in*coeff + z1}; @@ -125,8 +108,8 @@ void SplitterAllpassR::process(Real *samples, int count) return out; }; std::transform(samples, samples+count, samples, proc_sample); - this->z1 = z1; } -template class SplitterAllpassR; -template class SplitterAllpassR; + +template class BandSplitterR; +template class BandSplitterR; diff --git a/Alc/filters/splitter.h b/Alc/filters/splitter.h index cd5fe864..70fddd9e 100644 --- a/Alc/filters/splitter.h +++ b/Alc/filters/splitter.h @@ -21,28 +21,16 @@ public: void init(Real f0norm); void clear() noexcept { lp_z1 = lp_z2 = ap_z1 = 0.0f; } void process(Real *hpout, Real *lpout, const Real *input, const int count); - void applyHfScale(Real *samples, const Real hfscale, const int count); -}; -using BandSplitter = BandSplitterR; - -/* The all-pass portion of the band splitter. Applies the same phase shift - * without splitting the signal. - */ -template -class SplitterAllpassR { - Real coeff{0.0f}; - Real z1{0.0f}; -public: - SplitterAllpassR() = default; - SplitterAllpassR(const SplitterAllpassR&) = default; - SplitterAllpassR(Real f0norm) { init(f0norm); } + void applyHfScale(Real *samples, const Real hfscale, const int count); - void init(Real f0norm); - void clear() noexcept { z1 = 0.0f; } - void process(Real *samples, int count); + /* The all-pass portion of the band splitter. Applies the same phase shift + * without splitting the signal. Note that each use of this method is + * indepedent, it does not track history between calls. + */ + void applyAllpass(Real *samples, const int count) const; }; -using SplitterAllpass = SplitterAllpassR; +using BandSplitter = BandSplitterR; struct FrontStablizer { @@ -50,7 +38,6 @@ struct FrontStablizer { alignas(16) float DelayBuf[MAX_OUTPUT_CHANNELS][DelayLength]; - SplitterAllpass APFilter; BandSplitter LFilter, RFilter; alignas(16) float LSplit[2][BUFFERSIZE]; alignas(16) float RSplit[2][BUFFERSIZE]; diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 16b2dc3c..0980dcb6 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -338,7 +338,6 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsiz static constexpr ALsizei base_delay{DualBand ? 12 : 0}; const ALdouble xover_norm{400.0 / Hrtf->sampleRate}; BandSplitterR splitter{xover_norm}; - SplitterAllpassR allpass{xover_norm}; auto tmpres = al::vector>(NumChannels); auto tmpfilt = al::vector>(3); @@ -381,8 +380,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsiz * sample array. This produces the forward response with a backwards * phase-shift (+n degrees becomes -n degrees). */ - allpass.clear(); - allpass.process(tmpfilt[2].data(), static_cast(tmpfilt[2].size())); + splitter.applyAllpass(tmpfilt[2].data(), static_cast(tmpfilt[2].size())); std::reverse(tmpfilt[2].begin(), tmpfilt[2].end()); /* Now apply the band-splitter. This applies the normal phase-shift, @@ -408,8 +406,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsiz std::transform(fir, fir+Hrtf->irSize, tmpfilt[2].rbegin() + HRIR_LENGTH*3, [](const ALfloat (&ir)[2]) noexcept -> ALdouble { return ir[1]; }); - allpass.clear(); - allpass.process(tmpfilt[2].data(), static_cast(tmpfilt[2].size())); + splitter.applyAllpass(tmpfilt[2].data(), static_cast(tmpfilt[2].size())); std::reverse(tmpfilt[2].begin(), tmpfilt[2].end()); splitter.clear(); diff --git a/Alc/panning.cpp b/Alc/panning.cpp index ab57ed45..87f8bf72 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -841,9 +841,6 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr stablizer->LFilter.init(scale); stablizer->RFilter = stablizer->LFilter; - /* Initialize an all-pass filter for the phase corrector. */ - stablizer->APFilter.init(scale); - device->Stablizer = std::move(stablizer); /* NOTE: Don't know why this has to be "copied" into a local * static constexpr variable to avoid a reference on -- cgit v1.2.3 From b2735331c021081878ef3a6aaede39c59348f19b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 4 Jun 2019 20:27:32 -0700 Subject: Use a 16-sample base delay for the B-Format decoder IRs --- Alc/hrtf.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 0980dcb6..438997ad 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -332,10 +332,10 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsiz }; std::transform(AmbiPoints, AmbiPoints+AmbiCount, idx.begin(), calc_idxs); - /* For dual-band processing, add a 12-sample delay to compensate for the HF + /* For dual-band processing, add a 16-sample delay to compensate for the HF * scale on the minimum-phase response. */ - static constexpr ALsizei base_delay{DualBand ? 12 : 0}; + static constexpr ALsizei base_delay{DualBand ? 16 : 0}; const ALdouble xover_norm{400.0 / Hrtf->sampleRate}; BandSplitterR splitter{xover_norm}; @@ -435,10 +435,10 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsiz tmpres.clear(); ALsizei max_length{HRIR_LENGTH}; - /* Increase the IR size by 24 samples with dual-band processing to account - * for the head and tail from the HF response scale. + /* Increase the IR size by double the base delay with dual-band processing + * to account for the head and tail from the HF response scale. */ - const ALsizei irsize{DualBand ? mini(Hrtf->irSize + base_delay*2, max_length) : Hrtf->irSize}; + const ALsizei irsize{mini(Hrtf->irSize + base_delay*2, max_length)}; max_length = mini(max_delay-min_delay + irsize, max_length); /* Round up to the next IR size multiple. */ -- cgit v1.2.3 From 142721df17af951212109bf0bdc4203b83fb871e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 5 Jun 2019 16:38:53 -0700 Subject: Add methods to construct and destruct objects in-place --- common/almalloc.h | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 5 deletions(-) diff --git a/common/almalloc.h b/common/almalloc.h index 0d77c46d..74aa4afe 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -39,6 +39,8 @@ int al_is_sane_alignment_allocator(void) noexcept; namespace al { +#define REQUIRES(...) typename std::enable_if<(__VA_ARGS__),int>::type = 0 + template struct allocator : public std::allocator { using size_type = size_t; @@ -85,6 +87,73 @@ inline T* assume_aligned(T *ptr) noexcept #endif } +template +inline void destroy_at(T *ptr) { ptr->~T(); } + +template +inline void destroy(T first, const T end) +{ + while(first != end) + { + destroy_at(std::addressof(*first)); + ++first; + } +} + +template::value)> +inline T destroy_n(T first, N count) +{ + if(count != 0) + { + do { + destroy_at(std::addressof(*first)); + ++first; + } while(--count); + } + return first; +} + + +template +inline void uninitialized_default_construct(T first, const T last) +{ + using ValueT = typename std::iterator_traits::value_type; + T current{first}; + try { + while(current != last) + { + ::new (static_cast(std::addressof(*current))) ValueT; + ++current; + } + } + catch(...) { + destroy(first, current); + throw; + } +} + +template::value)> +inline T uninitialized_default_construct_n(T first, N count) +{ + using ValueT = typename std::iterator_traits::value_type; + T current{first}; + if(count != 0) + { + try { + do { + ::new (static_cast(std::addressof(*current))) ValueT; + ++current; + } while(--count); + } + catch(...) { + destroy(first, current); + throw; + } + } + return current; +} + + /* std::make_unique was added with C++14, so until we rely on that, make our * own version. */ @@ -109,12 +178,9 @@ struct FlexArray { } FlexArray(size_t size) : mSize{size} - { new (mArray) T[mSize]; } + { uninitialized_default_construct_n(mArray, mSize); } ~FlexArray() - { - for(size_t i{0u};i < mSize;++i) - mArray[i].~T(); - } + { destroy_n(mArray, mSize); } FlexArray(const FlexArray&) = delete; FlexArray& operator=(const FlexArray&) = delete; @@ -143,6 +209,8 @@ struct FlexArray { DEF_PLACE_NEWDEL() }; +#undef REQUIRES + } // namespace al #endif /* AL_MALLOC_H */ -- cgit v1.2.3 From f27e73989c9831cde96880edafb01e662a7de2db Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 5 Jun 2019 17:09:15 -0700 Subject: Properly destroy the limiter's extra fields --- Alc/mastering.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Alc/mastering.cpp b/Alc/mastering.cpp index 00b79e67..f5d36a59 100644 --- a/Alc/mastering.cpp +++ b/Alc/mastering.cpp @@ -15,7 +15,7 @@ static_assert((BUFFERSIZE & (BUFFERSIZE-1)) == 0, "BUFFERSIZE is not a power of 2"); struct SlidingHold { - ALfloat mValues[BUFFERSIZE]; + alignas(16) ALfloat mValues[BUFFERSIZE]; ALsizei mExpiries[BUFFERSIZE]; ALsizei mLowerIndex; ALsizei mUpperIndex; @@ -401,15 +401,15 @@ std::unique_ptr CompressorInit(const ALsizei NumChans, const ALuint { if(hold > 1) { - Comp->mHold = new (static_cast(Comp.get() + 1)) SlidingHold{}; + Comp->mHold = ::new (static_cast(Comp.get() + 1)) SlidingHold{}; Comp->mHold->mValues[0] = -std::numeric_limits::infinity(); Comp->mHold->mExpiries[0] = hold; Comp->mHold->mLength = hold; - Comp->mDelay = new (static_cast(Comp->mHold + 1)) FloatBufferLine{}; + Comp->mDelay = ::new (static_cast(Comp->mHold + 1)) FloatBufferLine[NumChans]; } else { - Comp->mDelay = new (static_cast(Comp.get() + 1)) FloatBufferLine{}; + Comp->mDelay = ::new (static_cast(Comp.get() + 1)) FloatBufferLine[NumChans]; } } @@ -423,10 +423,10 @@ std::unique_ptr CompressorInit(const ALsizei NumChans, const ALuint Compressor::~Compressor() { if(mHold) - mHold->~SlidingHold(); + al::destroy_at(mHold); mHold = nullptr; if(mDelay) - mDelay->~FloatBufferLine(); + al::destroy_n(mDelay, mNumChans); mDelay = nullptr; } -- cgit v1.2.3 From 5f26205f8fb504c5f6fec3e2b02f0009a4f24be2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 5 Jun 2019 17:25:08 -0700 Subject: Properly destroy other objects --- Alc/alc.cpp | 4 ++-- Alc/alu.cpp | 2 +- OpenAL32/alAuxEffectSlot.cpp | 6 +++--- OpenAL32/alBuffer.cpp | 4 ++-- OpenAL32/alEffect.cpp | 4 ++-- OpenAL32/alFilter.cpp | 4 ++-- OpenAL32/alSource.cpp | 4 ++-- OpenAL32/event.cpp | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 8378673d..b7be4f7b 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2462,14 +2462,14 @@ ALCcontext::~ALCcontext() auto evt_vec = AsyncEvents->getReadVector(); while(evt_vec.first.len > 0) { - reinterpret_cast(evt_vec.first.buf)->~AsyncEvent(); + al::destroy_at(reinterpret_cast(evt_vec.first.buf)); evt_vec.first.buf += sizeof(AsyncEvent); evt_vec.first.len -= 1; ++count; } while(evt_vec.second.len > 0) { - reinterpret_cast(evt_vec.second.buf)->~AsyncEvent(); + al::destroy_at(reinterpret_cast(evt_vec.second.buf)); evt_vec.second.buf += sizeof(AsyncEvent); evt_vec.second.len -= 1; ++count; diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 97ebf0cb..00867810 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -181,7 +181,7 @@ void aluInit(void) void DeinitVoice(ALvoice *voice) noexcept { delete voice->mUpdate.exchange(nullptr, std::memory_order_acq_rel); - voice->~ALvoice(); + al::destroy_at(voice); } diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index eeb545c9..4c7b3507 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -204,7 +204,7 @@ ALeffectslot *AllocEffectSlot(ALCcontext *context) ALenum err{InitEffectSlot(slot)}; if(err != AL_NO_ERROR) { - slot->~ALeffectslot(); + al::destroy_at(slot); alSetError(context, err, "Effect slot object initialization failed"); return nullptr; } @@ -225,7 +225,7 @@ void FreeEffectSlot(ALCcontext *context, ALeffectslot *slot) ALsizei lidx = id >> 6; ALsizei slidx = id & 0x3f; - slot->~ALeffectslot(); + al::destroy_at(slot); context->EffectSlotList[lidx].FreeMask |= 1_u64 << slidx; context->NumEffectSlots--; @@ -794,7 +794,7 @@ EffectSlotSubList::~EffectSlotSubList() while(usemask) { ALsizei idx{CTZ64(usemask)}; - EffectSlots[idx].~ALeffectslot(); + al::destroy_at(EffectSlots+idx); usemask &= ~(1_u64 << idx); } FreeMask = ~usemask; diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index 738133f5..ec733ae1 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -108,7 +108,7 @@ void FreeBuffer(ALCdevice *device, ALbuffer *buffer) ALsizei lidx = id >> 6; ALsizei slidx = id & 0x3f; - buffer->~ALbuffer(); + al::destroy_at(buffer); device->BufferList[lidx].FreeMask |= 1_u64 << slidx; } @@ -1219,7 +1219,7 @@ BufferSubList::~BufferSubList() while(usemask) { ALsizei idx{CTZ64(usemask)}; - Buffers[idx].~ALbuffer(); + al::destroy_at(Buffers+idx); usemask &= ~(1_u64 << idx); } FreeMask = ~usemask; diff --git a/OpenAL32/alEffect.cpp b/OpenAL32/alEffect.cpp index 51474af0..a2a40ac5 100644 --- a/OpenAL32/alEffect.cpp +++ b/OpenAL32/alEffect.cpp @@ -183,7 +183,7 @@ void FreeEffect(ALCdevice *device, ALeffect *effect) ALsizei lidx = id >> 6; ALsizei slidx = id & 0x3f; - effect->~ALeffect(); + al::destroy_at(effect); device->EffectList[lidx].FreeMask |= 1_u64 << slidx; } @@ -518,7 +518,7 @@ EffectSubList::~EffectSubList() while(usemask) { ALsizei idx = CTZ64(usemask); - Effects[idx].~ALeffect(); + al::destroy_at(Effects+idx); usemask &= ~(1_u64 << idx); } FreeMask = ~usemask; diff --git a/OpenAL32/alFilter.cpp b/OpenAL32/alFilter.cpp index cf393692..d7826b6f 100644 --- a/OpenAL32/alFilter.cpp +++ b/OpenAL32/alFilter.cpp @@ -327,7 +327,7 @@ void FreeFilter(ALCdevice *device, ALfilter *filter) ALsizei lidx = id >> 6; ALsizei slidx = id & 0x3f; - filter->~ALfilter(); + al::destroy_at(filter); device->FilterList[lidx].FreeMask |= 1_u64 << slidx; } @@ -647,7 +647,7 @@ FilterSubList::~FilterSubList() while(usemask) { ALsizei idx = CTZ64(usemask); - Filters[idx].~ALfilter(); + al::destroy_at(Filters+idx); usemask &= ~(1_u64 << idx); } FreeMask = ~usemask; diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index d2414e50..6d4daecd 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -544,7 +544,7 @@ void FreeSource(ALCcontext *context, ALsource *source) } backlock.unlock(); - source->~ALsource(); + al::destroy_at(source); context->SourceList[lidx].FreeMask |= 1_u64 << slidx; context->NumSources--; @@ -3575,7 +3575,7 @@ SourceSubList::~SourceSubList() while(usemask) { ALsizei idx{CTZ64(usemask)}; - Sources[idx].~ALsource(); + al::destroy_at(Sources+idx); usemask &= ~(1_u64 << idx); } FreeMask = ~usemask; diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index f01227e9..2ee296b0 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -42,7 +42,7 @@ static int EventThread(ALCcontext *context) RingBuffer *ring_; ~EventAutoDestructor() { - evt_.~AsyncEvent(); + al::destroy_at(&evt_); ring_->readAdvance(1); } } _{evt, ring}; @@ -99,7 +99,7 @@ static int EventThread(ALCcontext *context) void StartEventThrd(ALCcontext *ctx) { try { - ctx->EventThread = std::thread(EventThread, ctx); + ctx->EventThread = std::thread{EventThread, ctx}; } catch(std::exception& e) { ERR("Failed to start event thread: %s\n", e.what()); -- cgit v1.2.3 From 410a5ca62129f03ba7cfc091fa63fc451cdfc24f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 5 Jun 2019 18:54:17 -0700 Subject: Make RealMixParams channel count unsigned --- Alc/alc.cpp | 4 ++-- Alc/alu.cpp | 25 +++++++++++-------------- Alc/bformatdec.cpp | 7 ++++--- Alc/bformatdec.h | 2 +- Alc/mastering.cpp | 22 ++++++++++------------ Alc/mastering.h | 16 +++++++--------- OpenAL32/Include/alMain.h | 2 +- 7 files changed, 36 insertions(+), 42 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index b7be4f7b..010ea5f9 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1931,9 +1931,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->RealOut.NumChannels); /* Allocate extra channels for any post-filter output. */ - const ALsizei num_chans{device->Dry.NumChannels + device->RealOut.NumChannels}; + const ALuint num_chans{device->Dry.NumChannels + device->RealOut.NumChannels}; - TRACE("Allocating %d channels, %zu bytes\n", num_chans, + TRACE("Allocating %u channels, %zu bytes\n", num_chans, num_chans*sizeof(device->MixBuffer[0])); device->MixBuffer.resize(num_chans); diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 00867810..fbafd021 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -691,8 +691,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo /* Direct source channels always play local. Skip the virtual channels * and write inputs to the matching real outputs. */ - voice->mDirect.Buffer = {Device->RealOut.Buffer, - static_cast(Device->RealOut.NumChannels)}; + voice->mDirect.Buffer = {Device->RealOut.Buffer, Device->RealOut.NumChannels}; for(ALsizei c{0};c < num_channels;c++) { @@ -721,8 +720,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo /* Full HRTF rendering. Skip the virtual channels and render to the * real outputs. */ - voice->mDirect.Buffer = {Device->RealOut.Buffer, - static_cast(Device->RealOut.NumChannels)}; + voice->mDirect.Buffer = {Device->RealOut.Buffer, Device->RealOut.NumChannels}; if(Distance > std::numeric_limits::epsilon()) { @@ -1469,8 +1467,8 @@ void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) } -void ApplyStablizer(FrontStablizer *Stablizer, FloatBufferLine *Buffer, const int lidx, - const int ridx, const int cidx, const ALsizei SamplesToDo, const ALsizei NumChannels) +void ApplyStablizer(FrontStablizer *Stablizer, FloatBufferLine *Buffer, const ALuint lidx, + const ALuint ridx, const ALuint cidx, const ALsizei SamplesToDo, const ALuint NumChannels) { ASSUME(SamplesToDo > 0); ASSUME(NumChannels > 0); @@ -1478,7 +1476,7 @@ void ApplyStablizer(FrontStablizer *Stablizer, FloatBufferLine *Buffer, const in /* Apply a delay to all channels, except the front-left and front-right, so * they maintain correct timing. */ - for(ALsizei i{0};i < NumChannels;i++) + for(ALuint i{0};i < NumChannels;i++) { if(i == lidx || i == ridx) continue; @@ -1562,12 +1560,12 @@ void ApplyStablizer(FrontStablizer *Stablizer, FloatBufferLine *Buffer, const in } void ApplyDistanceComp(FloatBufferLine *Samples, const DistanceComp &distcomp, - const ALsizei SamplesToDo, const ALsizei numchans) + const ALsizei SamplesToDo, const ALuint numchans) { ASSUME(SamplesToDo > 0); ASSUME(numchans > 0); - for(ALsizei c{0};c < numchans;c++) + for(ALuint c{0};c < numchans;c++) { const ALfloat gain{distcomp[c].Gain}; const ALsizei base{distcomp[c].Length}; @@ -1593,7 +1591,7 @@ void ApplyDistanceComp(FloatBufferLine *Samples, const DistanceComp &distcomp, } void ApplyDither(FloatBufferLine *Samples, ALuint *dither_seed, const ALfloat quant_scale, - const ALsizei SamplesToDo, const ALsizei numchans) + const ALsizei SamplesToDo, const ALuint numchans) { ASSUME(numchans > 0); @@ -1652,12 +1650,11 @@ template<> inline ALubyte SampleConv(ALfloat val) noexcept { return SampleConv(val) + 128; } template -void Write(const FloatBufferLine *InBuffer, ALvoid *OutBuffer, const ALsizei Offset, - const ALsizei SamplesToDo, const ALsizei numchans) +void Write(const FloatBufferLine *InBuffer, ALvoid *OutBuffer, const size_t Offset, + const ALsizei SamplesToDo, const ALuint numchans) { using SampleType = typename DevFmtTypeTraits::Type; - ASSUME(Offset >= 0); ASSUME(numchans > 0); SampleType *outbase = static_cast(OutBuffer) + Offset*numchans; auto conv_channel = [&outbase,SamplesToDo,numchans](const FloatBufferLine &inbuf) -> void @@ -1751,7 +1748,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) if(LIKELY(OutBuffer)) { FloatBufferLine *Buffer{device->RealOut.Buffer}; - ALsizei Channels{device->RealOut.NumChannels}; + ALuint Channels{device->RealOut.NumChannels}; /* Finally, interleave and convert samples, writing to the device's * output buffer. diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 5d9b3503..6d2dbfbe 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -146,7 +146,8 @@ BFormatDec::BFormatDec(const ALsizei inchans, const ALsizei chancount, } -void BFormatDec::process(FloatBufferLine *OutBuffer, const ALsizei OutChannels, const FloatBufferLine *InSamples, const ALsizei SamplesToDo) +void BFormatDec::process(FloatBufferLine *OutBuffer, const ALuint OutChannels, + const FloatBufferLine *InSamples, const ALsizei SamplesToDo) { ASSUME(OutChannels > 0); ASSUME(mNumChannels > 0); @@ -159,7 +160,7 @@ void BFormatDec::process(FloatBufferLine *OutBuffer, const ALsizei OutChannels, const al::span hfsamples{mSamplesHF, mSamplesHF+mNumChannels}; const al::span lfsamples{mSamplesLF, mSamplesLF+mNumChannels}; - for(ALsizei chan{0};chan < OutChannels;chan++) + for(ALuint chan{0};chan < OutChannels;chan++) { if(UNLIKELY(!(mEnabled&(1< insamples{InSamples, InSamples+mNumChannels}; - for(ALsizei chan{0};chan < OutChannels;chan++) + for(ALuint chan{0};chan < OutChannels;chan++) { if(UNLIKELY(!(mEnabled&(1<mLookAhead}; - const ALsizei numChans{Comp->mNumChans}; + const ALuint numChans{Comp->mNumChans}; ASSUME(SamplesToDo > 0); ASSUME(numChans > 0); @@ -295,14 +295,14 @@ void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) */ void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, FloatBufferLine *OutBuffer) { - const ALsizei numChans{Comp->mNumChans}; + const ALuint numChans{Comp->mNumChans}; const ALsizei lookAhead{Comp->mLookAhead}; ASSUME(SamplesToDo > 0); ASSUME(numChans > 0); ASSUME(lookAhead > 0); - for(ALsizei c{0};c < numChans;c++) + for(ALuint c{0};c < numChans;c++) { ALfloat *inout{al::assume_aligned<16>(OutBuffer[c].data())}; ALfloat *delaybuf{al::assume_aligned<16>(Comp->mDelay[c].data())}; @@ -347,14 +347,12 @@ void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, FloatBufferLine *O * ReleaseTimeMin - Release time (in seconds). Acts as a maximum when * automating release time. */ -std::unique_ptr CompressorInit(const ALsizei NumChans, const ALuint SampleRate, - const ALboolean AutoKnee, const ALboolean AutoAttack, - const ALboolean AutoRelease, const ALboolean AutoPostGain, - const ALboolean AutoDeclip, const ALfloat LookAheadTime, - const ALfloat HoldTime, const ALfloat PreGainDb, - const ALfloat PostGainDb, const ALfloat ThresholdDb, - const ALfloat Ratio, const ALfloat KneeDb, - const ALfloat AttackTime, const ALfloat ReleaseTime) +std::unique_ptr CompressorInit(const ALuint NumChans, const ALuint SampleRate, + const ALboolean AutoKnee, const ALboolean AutoAttack, const ALboolean AutoRelease, + const ALboolean AutoPostGain, const ALboolean AutoDeclip, const ALfloat LookAheadTime, + const ALfloat HoldTime, const ALfloat PreGainDb, const ALfloat PostGainDb, + const ALfloat ThresholdDb, const ALfloat Ratio, const ALfloat KneeDb, const ALfloat AttackTime, + const ALfloat ReleaseTime) { const auto lookAhead = static_cast( clampf(std::round(LookAheadTime*SampleRate), 0.0f, BUFFERSIZE-1)); @@ -433,7 +431,7 @@ Compressor::~Compressor() void Compressor::process(const ALsizei SamplesToDo, FloatBufferLine *OutBuffer) { - const ALsizei numChans{mNumChans}; + const ALuint numChans{mNumChans}; ASSUME(SamplesToDo > 0); ASSUME(numChans > 0); diff --git a/Alc/mastering.h b/Alc/mastering.h index 31d0ef97..1003fa6c 100644 --- a/Alc/mastering.h +++ b/Alc/mastering.h @@ -23,7 +23,7 @@ struct SlidingHold; * http://c4dm.eecs.qmul.ac.uk/audioengineering/compressors/ */ struct Compressor { - ALsizei mNumChans{0}; + ALuint mNumChans{0u}; ALuint mSampleRate{0u}; struct { @@ -94,13 +94,11 @@ struct Compressor { * ReleaseTimeMin - Release time (in seconds). Acts as a maximum when * automating release time. */ -std::unique_ptr CompressorInit(const ALsizei NumChans, const ALuint SampleRate, - const ALboolean AutoKnee, const ALboolean AutoAttack, - const ALboolean AutoRelease, const ALboolean AutoPostGain, - const ALboolean AutoDeclip, const ALfloat LookAheadTime, - const ALfloat HoldTime, const ALfloat PreGainDb, - const ALfloat PostGainDb, const ALfloat ThresholdDb, - const ALfloat Ratio, const ALfloat KneeDb, - const ALfloat AttackTime, const ALfloat ReleaseTime); +std::unique_ptr CompressorInit(const ALuint NumChans, const ALuint SampleRate, + const ALboolean AutoKnee, const ALboolean AutoAttack, const ALboolean AutoRelease, + const ALboolean AutoPostGain, const ALboolean AutoDeclip, const ALfloat LookAheadTime, + const ALfloat HoldTime, const ALfloat PreGainDb, const ALfloat PostGainDb, + const ALfloat ThresholdDb, const ALfloat Ratio, const ALfloat KneeDb, const ALfloat AttackTime, + const ALfloat ReleaseTime); #endif /* MASTERING_H */ diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 36042782..35ac617a 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -325,7 +325,7 @@ struct RealMixParams { std::array ChannelIndex{}; FloatBufferLine *Buffer{nullptr}; - ALsizei NumChannels{0}; + ALuint NumChannels{0u}; }; using POSTPROCESS = void(*)(ALCdevice *device, const ALsizei SamplesToDo); -- cgit v1.2.3 From 1ce310c6d1719c6f71664385e136b5510602ac21 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 5 Jun 2019 19:26:54 -0700 Subject: Make some more channel counts unsigned --- Alc/alc.cpp | 2 +- Alc/alu.cpp | 16 +++++----------- Alc/bformatdec.cpp | 12 ++++++------ Alc/bformatdec.h | 6 +++--- Alc/effects/autowah.cpp | 2 +- Alc/effects/base.h | 2 +- Alc/effects/compressor.cpp | 2 +- Alc/effects/equalizer.cpp | 4 ++-- Alc/effects/modulator.cpp | 4 ++-- Alc/hrtf.cpp | 12 +++++++----- Alc/hrtf.h | 4 +++- Alc/panning.cpp | 18 +++++++++--------- OpenAL32/Include/alMain.h | 2 +- 13 files changed, 42 insertions(+), 44 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 010ea5f9..a71cb662 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1927,7 +1927,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->Frequency, device->UpdateSize, device->BufferSize); aluInitRenderer(device, hrtf_id, hrtf_appreq, hrtf_userreq); - TRACE("Channel config, Main: %d, Real: %d\n", device->Dry.NumChannels, + TRACE("Channel config, Main: %u, Real: %u\n", device->Dry.NumChannels, device->RealOut.NumChannels); /* Allocate extra channels for any post-filter output. */ diff --git a/Alc/alu.cpp b/Alc/alu.cpp index fbafd021..eed4ddc3 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -134,8 +134,7 @@ void ProcessHrtf(ALCdevice *device, const ALsizei SamplesToDo) DirectHrtfState *state{device->mHrtfState.get()}; MixDirectHrtf(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], - {device->Dry.Buffer,device->Dry.Buffer+device->Dry.NumChannels}, device->HrtfAccumData, - state, SamplesToDo); + {device->Dry.Buffer, device->Dry.NumChannels}, device->HrtfAccumData, state, SamplesToDo); } void ProcessAmbiDec(ALCdevice *device, const ALsizei SamplesToDo) @@ -982,8 +981,7 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons } else { - voice->mSend[i].Buffer = {SendSlots[i]->Wet.Buffer, - static_cast(SendSlots[i]->Wet.NumChannels)}; + voice->mSend[i].Buffer = {SendSlots[i]->Wet.Buffer, SendSlots[i]->Wet.NumChannels}; } } @@ -1028,7 +1026,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A const ALlistener &Listener = ALContext->Listener; /* Set mixing buffers and get send parameters. */ - voice->mDirect.Buffer = {Device->Dry.Buffer, static_cast(Device->Dry.NumChannels)}; + voice->mDirect.Buffer = {Device->Dry.Buffer, Device->Dry.NumChannels}; ALeffectslot *SendSlots[MAX_SENDS]; ALfloat RoomRolloff[MAX_SENDS]; ALfloat DecayDistance[MAX_SENDS]; @@ -1085,10 +1083,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A if(!SendSlots[i]) voice->mSend[i].Buffer = {}; else - { - voice->mSend[i].Buffer = {SendSlots[i]->Wet.Buffer, - static_cast(SendSlots[i]->Wet.NumChannels)}; - } + voice->mSend[i].Buffer = {SendSlots[i]->Wet.Buffer, SendSlots[i]->Wet.NumChannels}; } /* Transform source to listener space (convert to head relative) */ @@ -1459,9 +1454,8 @@ void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) [SamplesToDo](const ALeffectslot *slot) -> void { EffectState *state{slot->Params.mEffectState}; - const auto outchans = static_cast(state->mOutChannels); state->process(SamplesToDo, slot->Wet.Buffer, slot->Wet.NumChannels, - {state->mOutBuffer, outchans}); + {state->mOutBuffer, state->mOutChannels}); } ); } diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 6d2dbfbe..9c0c72ec 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -49,7 +49,7 @@ inline auto GetAmbiScales(AmbDecScale scaletype) noexcept -> const std::arrayFreqBands == 2); @@ -119,7 +119,7 @@ BFormatDec::BFormatDec(const AmbDecConf *conf, const bool allow_2band, const ALs } } -BFormatDec::BFormatDec(const ALsizei inchans, const ALsizei chancount, +BFormatDec::BFormatDec(const ALuint inchans, const ALsizei chancount, const ChannelDec (&chancoeffs)[MAX_OUTPUT_CHANNELS], const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]) { @@ -154,12 +154,12 @@ void BFormatDec::process(FloatBufferLine *OutBuffer, const ALuint OutChannels, if(mDualBand) { - for(ALsizei i{0};i < mNumChannels;i++) + for(ALuint i{0};i < mNumChannels;i++) mXOver[i].process(mSamplesHF[i].data(), mSamplesLF[i].data(), InSamples[i].data(), SamplesToDo); - const al::span hfsamples{mSamplesHF, mSamplesHF+mNumChannels}; - const al::span lfsamples{mSamplesLF, mSamplesLF+mNumChannels}; + const al::span hfsamples{mSamplesHF, mNumChannels}; + const al::span lfsamples{mSamplesLF, mNumChannels}; for(ALuint chan{0};chan < OutChannels;chan++) { if(UNLIKELY(!(mEnabled&(1< insamples{InSamples, InSamples+mNumChannels}; + const al::span insamples{InSamples, mNumChannels}; for(ALuint chan{0};chan < OutChannels;chan++) { if(UNLIKELY(!(mEnabled&(1< *mSamplesHF{nullptr}; std::array *mSamplesLF{nullptr}; - ALsizei mNumChannels{0}; + ALuint mNumChannels{0u}; bool mDualBand{false}; public: - BFormatDec(const AmbDecConf *conf, const bool allow_2band, const ALsizei inchans, + BFormatDec(const AmbDecConf *conf, const bool allow_2band, const ALuint inchans, const ALuint srate, const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]); - BFormatDec(const ALsizei inchans, const ALsizei chancount, + BFormatDec(const ALuint inchans, const ALsizei chancount, const ChannelDec (&chancoeffs)[MAX_OUTPUT_CHANNELS], const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]); diff --git a/Alc/effects/autowah.cpp b/Alc/effects/autowah.cpp index 90531229..ab885460 100644 --- a/Alc/effects/autowah.cpp +++ b/Alc/effects/autowah.cpp @@ -121,7 +121,7 @@ void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, mOutBuffer = target.Main->Buffer; mOutChannels = target.Main->NumChannels; - for(ALsizei i{0};i < slot->Wet.NumChannels;++i) + for(ALuint i{0u};i < slot->Wet.NumChannels;++i) { auto coeffs = GetAmbiIdentityRow(i); ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mChans[i].TargetGains); diff --git a/Alc/effects/base.h b/Alc/effects/base.h index d2b33b9b..1a59078f 100644 --- a/Alc/effects/base.h +++ b/Alc/effects/base.h @@ -145,7 +145,7 @@ struct EffectState { RefCount mRef{1u}; FloatBufferLine *mOutBuffer{nullptr}; - ALsizei mOutChannels{0}; + ALuint mOutChannels{0u}; virtual ~EffectState() = default; diff --git a/Alc/effects/compressor.cpp b/Alc/effects/compressor.cpp index 5c0d0121..049f521b 100644 --- a/Alc/effects/compressor.cpp +++ b/Alc/effects/compressor.cpp @@ -80,7 +80,7 @@ void CompressorState::update(const ALCcontext* UNUSED(context), const ALeffectsl mOutBuffer = target.Main->Buffer; mOutChannels = target.Main->NumChannels; - for(ALsizei i{0};i < slot->Wet.NumChannels;++i) + for(ALuint i{0u};i < slot->Wet.NumChannels;++i) { auto coeffs = GetAmbiIdentityRow(i); ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mGain[i]); diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index d37f15ea..179dbc1b 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -141,7 +141,7 @@ void EqualizerState::update(const ALCcontext *context, const ALeffectslot *slot, BiquadFilter::rcpQFromSlope(gain, 0.75f)); /* Copy the filter coefficients for the other input channels. */ - for(ALsizei i{1};i < slot->Wet.NumChannels;++i) + for(ALuint i{1u};i < slot->Wet.NumChannels;++i) { mChans[i].filter[0].copyParamsFrom(mChans[0].filter[0]); mChans[i].filter[1].copyParamsFrom(mChans[0].filter[1]); @@ -151,7 +151,7 @@ void EqualizerState::update(const ALCcontext *context, const ALeffectslot *slot, mOutBuffer = target.Main->Buffer; mOutChannels = target.Main->NumChannels; - for(ALsizei i{0};i < slot->Wet.NumChannels;++i) + for(ALuint i{0u};i < slot->Wet.NumChannels;++i) { auto coeffs = GetAmbiIdentityRow(i); ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mChans[i].TargetGains); diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index 60728d2e..1630654f 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -129,12 +129,12 @@ void ModulatorState::update(const ALCcontext *context, const ALeffectslot *slot, /* Bandwidth value is constant in octaves. */ mChans[0].Filter.setParams(BiquadType::HighPass, 1.0f, f0norm, BiquadFilter::rcpQFromBandwidth(f0norm, 0.75f)); - for(ALsizei i{1};i < slot->Wet.NumChannels;++i) + for(ALuint i{1u};i < slot->Wet.NumChannels;++i) mChans[i].Filter.copyParamsFrom(mChans[0].Filter); mOutBuffer = target.Main->Buffer; mOutChannels = target.Main->NumChannels; - for(ALsizei i{0};i < slot->Wet.NumChannels;++i) + for(ALuint i{0u};i < slot->Wet.NumChannels;++i) { auto coeffs = GetAmbiIdentityRow(i); ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mChans[i].TargetGains); diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 438997ad..668e5b24 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -291,7 +291,9 @@ std::unique_ptr DirectHrtfState::Create(size_t num_chans) return std::unique_ptr{new (ptr) DirectHrtfState{num_chans}}; } -void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsizei NumChannels, const AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_CHANNELS], const size_t AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain) +void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuint NumChannels, + const AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_CHANNELS], + const size_t AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain) { static constexpr int OrderFromChan[MAX_AMBI_CHANNELS]{ 0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3, @@ -350,7 +352,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsiz if(!DualBand) { /* For single-band decoding, apply the HF scale to the response. */ - for(ALsizei i{0};i < NumChannels;++i) + for(ALuint i{0u};i < NumChannels;++i) { const ALdouble mult{ALdouble{AmbiOrderHFGain[OrderFromChan[i]]} * AmbiMatrix[c][i]}; @@ -392,7 +394,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsiz static_cast(tmpfilt[2].size())); /* Apply left ear response with delay and HF scale. */ - for(ALsizei i{0};i < NumChannels;++i) + for(ALuint i{0u};i < NumChannels;++i) { const ALdouble mult{AmbiMatrix[c][i]}; const ALdouble hfgain{AmbiOrderHFGain[OrderFromChan[i]]}; @@ -413,7 +415,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsiz splitter.process(tmpfilt[0].data(), tmpfilt[1].data(), tmpfilt[2].data(), static_cast(tmpfilt[2].size())); - for(ALsizei i{0};i < NumChannels;++i) + for(ALuint i{0u};i < NumChannels;++i) { const ALdouble mult{AmbiMatrix[c][i]}; const ALdouble hfgain{AmbiOrderHFGain[OrderFromChan[i]]}; @@ -425,7 +427,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsiz tmpfilt.clear(); idx.clear(); - for(ALsizei i{0};i < NumChannels;++i) + for(ALuint i{0u};i < NumChannels;++i) { auto copy_arr = [](const std::array &in) noexcept -> std::array { return std::array{{static_cast(in[0]), static_cast(in[1])}}; }; diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 46a03e43..1fb53e4c 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -115,6 +115,8 @@ void GetHrtfCoeffs(const HrtfEntry *Hrtf, ALfloat elevation, ALfloat azimuth, AL * ordered and scaled according to the matrix input. Note the specified virtual * positions should be in degrees, not radians! */ -void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsizei NumChannels, const AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_CHANNELS], const size_t AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain); +void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuint NumChannels, + const AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_CHANNELS], + const size_t AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain); #endif /* ALC_HRTF_H */ diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 87f8bf72..d43f3f0f 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -328,7 +328,7 @@ auto GetAmbiLayout(AmbiLayout layouttype) noexcept -> const std::array chanmap; - ALsizei coeffcount{}; + ALuint coeffcount{}; switch(device->FmtChans) { @@ -383,7 +383,7 @@ void InitPanning(ALCdevice *device) [&n3dscale](const ALsizei &acn) noexcept -> BFChannelConfig { return BFChannelConfig{1.0f/n3dscale[acn], acn}; } ); - device->Dry.NumChannels = static_cast(count); + device->Dry.NumChannels = static_cast(count); ALfloat nfc_delay{0.0f}; if(ConfigValueFloat(devname, "decoder", "nfc-ref-delay", &nfc_delay) && nfc_delay > 0.0f) @@ -417,7 +417,7 @@ void InitPanning(ALCdevice *device) * channel count. Built-in speaker decoders are always 2D, so just * reverse that calculation. */ - device->mAmbiOrder = (coeffcount-1) / 2; + device->mAmbiOrder = static_cast((coeffcount-1) / 2); std::transform(AmbiIndex::From2D.begin(), AmbiIndex::From2D.begin()+coeffcount, std::begin(device->Dry.AmbiMap), @@ -450,10 +450,10 @@ void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, co (conf->ChanMask > AMBI_1ORDER_MASK) ? 2 : 1}; device->mAmbiOrder = order; - ALsizei count; + ALuint count; if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { - count = static_cast(AmbiChannelsFromOrder(order)); + count = static_cast(AmbiChannelsFromOrder(order)); std::transform(AmbiIndex::From3D.begin(), AmbiIndex::From3D.begin()+count, std::begin(device->Dry.AmbiMap), [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } @@ -461,7 +461,7 @@ void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, co } else { - count = static_cast(Ambi2DChannelsFromOrder(order)); + count = static_cast(Ambi2DChannelsFromOrder(order)); std::transform(AmbiIndex::From2D.begin(), AmbiIndex::From2D.begin()+count, std::begin(device->Dry.AmbiMap), [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } @@ -607,7 +607,7 @@ void InitHrtfPanning(ALCdevice *device) std::begin(device->Dry.AmbiMap), [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } ); - device->Dry.NumChannels = static_cast(count); + device->Dry.NumChannels = static_cast(count); device->RealOut.NumChannels = device->channelsFromFmt(); @@ -733,7 +733,7 @@ void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALf void ComputePanGains(const MixParams *mix, const ALfloat *RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) { auto ambimap = mix->AmbiMap.cbegin(); - const ALsizei numchans{mix->NumChannels}; + const ALuint numchans{mix->NumChannels}; ASSUME(numchans > 0); auto iter = std::transform(ambimap, ambimap+numchans, std::begin(gains), @@ -998,5 +998,5 @@ void aluInitEffectPanning(ALeffectslot *slot, ALCdevice *device) ); std::fill(iter, slot->Wet.AmbiMap.end(), BFChannelConfig{}); slot->Wet.Buffer = slot->MixBuffer.data(); - slot->Wet.NumChannels = static_cast(count); + slot->Wet.NumChannels = static_cast(count); } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 35ac617a..0534751f 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -318,7 +318,7 @@ struct MixParams { std::array AmbiMap; FloatBufferLine *Buffer{nullptr}; - ALsizei NumChannels{0}; + ALuint NumChannels{0u}; }; struct RealMixParams { -- cgit v1.2.3 From f9da06fc6a265e3ab2f548a9533b222e7a183637 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 5 Jun 2019 19:58:58 -0700 Subject: Use a span for the effect state's output target --- Alc/alc.cpp | 6 ++---- Alc/alu.cpp | 2 +- Alc/effects/autowah.cpp | 3 +-- Alc/effects/base.h | 3 +-- Alc/effects/chorus.cpp | 3 +-- Alc/effects/compressor.cpp | 3 +-- Alc/effects/dedicated.cpp | 9 +++------ Alc/effects/distortion.cpp | 3 +-- Alc/effects/echo.cpp | 3 +-- Alc/effects/equalizer.cpp | 3 +-- Alc/effects/fshifter.cpp | 3 +-- Alc/effects/modulator.cpp | 3 +-- Alc/effects/pshifter.cpp | 3 +-- Alc/effects/reverb.cpp | 4 ++-- OpenAL32/alAuxEffectSlot.cpp | 3 +-- 15 files changed, 19 insertions(+), 35 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index a71cb662..58512f52 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2062,8 +2062,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) aluInitEffectPanning(slot, device); EffectState *state{slot->Effect.State}; - state->mOutBuffer = device->Dry.Buffer; - state->mOutChannels = device->Dry.NumChannels; + state->mOutTarget = {device->Dry.Buffer, device->Dry.NumChannels}; if(state->deviceUpdate(device) == AL_FALSE) update_failed = AL_TRUE; else @@ -2085,8 +2084,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) aluInitEffectPanning(slot, device); EffectState *state{slot->Effect.State}; - state->mOutBuffer = device->Dry.Buffer; - state->mOutChannels = device->Dry.NumChannels; + state->mOutTarget = {device->Dry.Buffer, device->Dry.NumChannels}; if(state->deviceUpdate(device) == AL_FALSE) update_failed = AL_TRUE; else diff --git a/Alc/alu.cpp b/Alc/alu.cpp index eed4ddc3..fc8b14d8 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1455,7 +1455,7 @@ void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) { EffectState *state{slot->Params.mEffectState}; state->process(SamplesToDo, slot->Wet.Buffer, slot->Wet.NumChannels, - {state->mOutBuffer, state->mOutChannels}); + state->mOutTarget); } ); } diff --git a/Alc/effects/autowah.cpp b/Alc/effects/autowah.cpp index ab885460..90af6134 100644 --- a/Alc/effects/autowah.cpp +++ b/Alc/effects/autowah.cpp @@ -119,8 +119,7 @@ void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, mFreqMinNorm = MIN_FREQ / device->Frequency; mBandwidthNorm = (MAX_FREQ-MIN_FREQ) / device->Frequency; - mOutBuffer = target.Main->Buffer; - mOutChannels = target.Main->NumChannels; + mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; for(ALuint i{0u};i < slot->Wet.NumChannels;++i) { auto coeffs = GetAmbiIdentityRow(i); diff --git a/Alc/effects/base.h b/Alc/effects/base.h index 1a59078f..c2848f37 100644 --- a/Alc/effects/base.h +++ b/Alc/effects/base.h @@ -144,8 +144,7 @@ struct EffectTarget { struct EffectState { RefCount mRef{1u}; - FloatBufferLine *mOutBuffer{nullptr}; - ALuint mOutChannels{0u}; + al::span mOutTarget; virtual ~EffectState() = default; diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp index 9226c747..b77c3439 100644 --- a/Alc/effects/chorus.cpp +++ b/Alc/effects/chorus.cpp @@ -159,8 +159,7 @@ void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, co CalcDirectionCoeffs({-1.0f, 0.0f, 0.0f}, 0.0f, coeffs[0]); CalcDirectionCoeffs({ 1.0f, 0.0f, 0.0f}, 0.0f, coeffs[1]); - mOutBuffer = target.Main->Buffer; - mOutChannels = target.Main->NumChannels; + mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; ComputePanGains(target.Main, coeffs[0], Slot->Params.Gain, mGains[0].Target); ComputePanGains(target.Main, coeffs[1], Slot->Params.Gain, mGains[1].Target); diff --git a/Alc/effects/compressor.cpp b/Alc/effects/compressor.cpp index 049f521b..883488cb 100644 --- a/Alc/effects/compressor.cpp +++ b/Alc/effects/compressor.cpp @@ -78,8 +78,7 @@ void CompressorState::update(const ALCcontext* UNUSED(context), const ALeffectsl { mEnabled = props->Compressor.OnOff; - mOutBuffer = target.Main->Buffer; - mOutChannels = target.Main->NumChannels; + mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; for(ALuint i{0u};i < slot->Wet.NumChannels;++i) { auto coeffs = GetAmbiIdentityRow(i); diff --git a/Alc/effects/dedicated.cpp b/Alc/effects/dedicated.cpp index 06d187fc..eb4076b2 100644 --- a/Alc/effects/dedicated.cpp +++ b/Alc/effects/dedicated.cpp @@ -62,8 +62,7 @@ void DedicatedState::update(const ALCcontext* UNUSED(context), const ALeffectslo const int idx{!target.RealOut ? -1 : GetChannelIdxByName(*target.RealOut, LFE)}; if(idx != -1) { - mOutBuffer = target.RealOut->Buffer; - mOutChannels = target.RealOut->NumChannels; + mOutTarget = {target.RealOut->Buffer, target.RealOut->NumChannels}; mTargetGains[idx] = Gain; } } @@ -74,8 +73,7 @@ void DedicatedState::update(const ALCcontext* UNUSED(context), const ALeffectslo const int idx{!target.RealOut ? -1 : GetChannelIdxByName(*target.RealOut, FrontCenter)}; if(idx != -1) { - mOutBuffer = target.RealOut->Buffer; - mOutChannels = target.RealOut->NumChannels; + mOutTarget = {target.RealOut->Buffer, target.RealOut->NumChannels}; mTargetGains[idx] = Gain; } else @@ -83,8 +81,7 @@ void DedicatedState::update(const ALCcontext* UNUSED(context), const ALeffectslo ALfloat coeffs[MAX_AMBI_CHANNELS]; CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); - mOutBuffer = target.Main->Buffer; - mOutChannels = target.Main->NumChannels; + mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; ComputePanGains(target.Main, coeffs, Gain, mTargetGains); } } diff --git a/Alc/effects/distortion.cpp b/Alc/effects/distortion.cpp index 4830ad1c..3b8b73b7 100644 --- a/Alc/effects/distortion.cpp +++ b/Alc/effects/distortion.cpp @@ -90,8 +90,7 @@ void DistortionState::update(const ALCcontext *context, const ALeffectslot *slot ALfloat coeffs[MAX_AMBI_CHANNELS]; CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); - mOutBuffer = target.Main->Buffer; - mOutChannels = target.Main->NumChannels; + mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; ComputePanGains(target.Main, coeffs, slot->Params.Gain*props->Distortion.Gain, mGain); } diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index dadb41bb..594d2a7c 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -113,8 +113,7 @@ void EchoState::update(const ALCcontext *context, const ALeffectslot *slot, cons CalcAngleCoeffs(-angle, 0.0f, 0.0f, coeffs[0]); CalcAngleCoeffs( angle, 0.0f, 0.0f, coeffs[1]); - mOutBuffer = target.Main->Buffer; - mOutChannels = target.Main->NumChannels; + mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; ComputePanGains(target.Main, coeffs[0], slot->Params.Gain, mGains[0].Target); ComputePanGains(target.Main, coeffs[1], slot->Params.Gain, mGains[1].Target); } diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index 179dbc1b..14013aad 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -149,8 +149,7 @@ void EqualizerState::update(const ALCcontext *context, const ALeffectslot *slot, mChans[i].filter[3].copyParamsFrom(mChans[0].filter[3]); } - mOutBuffer = target.Main->Buffer; - mOutChannels = target.Main->NumChannels; + mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; for(ALuint i{0u};i < slot->Wet.NumChannels;++i) { auto coeffs = GetAmbiIdentityRow(i); diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp index d50a7733..496a767d 100644 --- a/Alc/effects/fshifter.cpp +++ b/Alc/effects/fshifter.cpp @@ -133,8 +133,7 @@ void FshifterState::update(const ALCcontext *context, const ALeffectslot *slot, ALfloat coeffs[MAX_AMBI_CHANNELS]; CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); - mOutBuffer = target.Main->Buffer; - mOutChannels = target.Main->NumChannels; + mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; ComputePanGains(target.Main, coeffs, slot->Params.Gain, mTargetGains); } diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index 1630654f..131d275b 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -132,8 +132,7 @@ void ModulatorState::update(const ALCcontext *context, const ALeffectslot *slot, for(ALuint i{1u};i < slot->Wet.NumChannels;++i) mChans[i].Filter.copyParamsFrom(mChans[0].Filter); - mOutBuffer = target.Main->Buffer; - mOutChannels = target.Main->NumChannels; + mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; for(ALuint i{0u};i < slot->Wet.NumChannels;++i) { auto coeffs = GetAmbiIdentityRow(i); diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp index 184c9a40..f1865830 100644 --- a/Alc/effects/pshifter.cpp +++ b/Alc/effects/pshifter.cpp @@ -192,8 +192,7 @@ void PshifterState::update(const ALCcontext* UNUSED(context), const ALeffectslot ALfloat coeffs[MAX_AMBI_CHANNELS]; CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); - mOutBuffer = target.Main->Buffer; - mOutChannels = target.Main->NumChannels; + mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; ComputePanGains(target.Main, coeffs, slot->Params.Gain, mTargetGains); } diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 54151d6e..da8be835 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -888,8 +888,8 @@ void ReverbState::update3DPanning(const ALfloat *ReflectionsPan, const ALfloat * */ const alu::Matrix earlymat{GetTransformFromVector(ReflectionsPan)}; const alu::Matrix latemat{GetTransformFromVector(LateReverbPan)}; - mOutBuffer = target.Main->Buffer; - mOutChannels = target.Main->NumChannels; + + mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; for(ALsizei i{0};i < NUM_LINES;i++) { const ALfloat coeffs[MAX_AMBI_CHANNELS]{earlymat[0][i], earlymat[1][i], earlymat[2][i], diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index 4c7b3507..249f7cf3 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -643,8 +643,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect FPUCtl mixer_mode{}; ALCdevice *Device{Context->Device}; std::unique_lock statelock{Device->StateLock}; - State->mOutBuffer = Device->Dry.Buffer; - State->mOutChannels = Device->Dry.NumChannels; + State->mOutTarget = {Device->Dry.Buffer, Device->Dry.NumChannels}; if(State->deviceUpdate(Device) == AL_FALSE) { statelock.unlock(); -- cgit v1.2.3 From 24df52c0420128ec9808cd65efa1aad7fd6827ec Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 5 Jun 2019 23:00:28 -0700 Subject: Remove the per-voice ChannelsPerOrder field --- Alc/alu.cpp | 13 ------------- Alc/mixvoice.cpp | 12 +++++------- Alc/panning.cpp | 15 ++++++++------- OpenAL32/Include/alMain.h | 2 +- OpenAL32/Include/alu.h | 1 - 5 files changed, 14 insertions(+), 29 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index fc8b14d8..9a1958b6 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -585,9 +585,6 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo /* Only need to adjust the first channel of a B-Format source. */ voice->mChans[0].mDryParams.NFCtrlFilter.adjust(w0); - std::copy(std::begin(Device->NumChannelsPerOrder), - std::end(Device->NumChannelsPerOrder), - std::begin(voice->mDirect.ChannelsPerOrder)); voice->mFlags |= VOICE_HAS_NFC; } @@ -631,10 +628,6 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo */ voice->mChans[0].mDryParams.NFCtrlFilter.adjust(0.0f); - voice->mDirect.ChannelsPerOrder[0] = 1; - voice->mDirect.ChannelsPerOrder[1] = minz(voice->mDirect.Buffer.size()-1, 3); - std::fill(std::begin(voice->mDirect.ChannelsPerOrder)+2, - std::end(voice->mDirect.ChannelsPerOrder), 0); voice->mFlags |= VOICE_HAS_NFC; } @@ -816,9 +809,6 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo for(ALsizei c{0};c < num_channels;c++) voice->mChans[c].mDryParams.NFCtrlFilter.adjust(w0); - std::copy(std::begin(Device->NumChannelsPerOrder), - std::end(Device->NumChannelsPerOrder), - std::begin(voice->mDirect.ChannelsPerOrder)); voice->mFlags |= VOICE_HAS_NFC; } @@ -879,9 +869,6 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo for(ALsizei c{0};c < num_channels;c++) voice->mChans[c].mDryParams.NFCtrlFilter.adjust(w0); - std::copy(std::begin(Device->NumChannelsPerOrder), - std::end(Device->NumChannelsPerOrder), - std::begin(voice->mDirect.ChannelsPerOrder)); voice->mFlags |= VOICE_HAS_NFC; } diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 33ea00bb..8e208ff9 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -802,17 +802,15 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? SilentTarget : parms.Gains.Target}; - const auto outcount = static_cast(voice->mDirect.ChannelsPerOrder[0]); + const size_t outcount{Device->NumChannelsPerOrder[0]}; MixSamples(samples, voice->mDirect.Buffer.first(outcount), parms.Gains.Current, TargetGains, Counter, OutPos, DstBufferSize); ALfloat (&nfcsamples)[BUFFERSIZE] = Device->NfcSampleData; size_t chanoffset{outcount}; using FilterProc = void (NfcFilter::*)(float*,const float*,int); - auto apply_nfc = [voice,&parms,samples,TargetGains,DstBufferSize,Counter,OutPos,&chanoffset,&nfcsamples](FilterProc process, ALsizei order) -> void + auto apply_nfc = [voice,&parms,samples,TargetGains,DstBufferSize,Counter,OutPos,&chanoffset,&nfcsamples](const FilterProc process, const size_t outcount) -> void { - const auto outcount = static_cast( - voice->mDirect.ChannelsPerOrder[order]); if(outcount < 1) return; (parms.NFCtrlFilter.*process)(nfcsamples, samples, DstBufferSize); MixSamples(nfcsamples, voice->mDirect.Buffer.subspan(chanoffset, outcount), @@ -820,9 +818,9 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc OutPos, DstBufferSize); chanoffset += outcount; }; - apply_nfc(&NfcFilter::process1, 1); - apply_nfc(&NfcFilter::process2, 2); - apply_nfc(&NfcFilter::process3, 3); + apply_nfc(&NfcFilter::process1, Device->NumChannelsPerOrder[1]); + apply_nfc(&NfcFilter::process2, Device->NumChannelsPerOrder[2]); + apply_nfc(&NfcFilter::process3, Device->NumChannelsPerOrder[3]); } else { diff --git a/Alc/panning.cpp b/Alc/panning.cpp index d43f3f0f..714c3e98 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -233,7 +233,8 @@ constexpr ChannelMap MonoCfg[1] = { { BackRight, { 2.04124145e-1f, -1.08880247e-1f, -1.88586120e-1f, 1.29099444e-1f, 7.45355993e-2f, -3.73460789e-2f, 0.00000000e+0f } }, }; -void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, const ALsizei *RESTRICT chans_per_order) +void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, + const ALuint *RESTRICT chans_per_order) { /* NFC is only used when AvgSpeakerDist is greater than 0. */ const char *devname{device->DeviceName.c_str()}; @@ -245,7 +246,7 @@ void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, cons auto iter = std::copy(chans_per_order, chans_per_order+order+1, std::begin(device->NumChannelsPerOrder)); - std::fill(iter, std::end(device->NumChannelsPerOrder), 0); + std::fill(iter, std::end(device->NumChannelsPerOrder), 0u); } void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) @@ -388,7 +389,7 @@ void InitPanning(ALCdevice *device) ALfloat nfc_delay{0.0f}; if(ConfigValueFloat(devname, "decoder", "nfc-ref-delay", &nfc_delay) && nfc_delay > 0.0f) { - static constexpr ALsizei chans_per_order[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; + static constexpr ALuint chans_per_order[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; nfc_delay = clampf(nfc_delay, 0.001f, 1000.0f); InitNearFieldCtrl(device, nfc_delay * SPEEDOFSOUNDMETRESPERSEC, device->mAmbiOrder, chans_per_order); @@ -439,8 +440,8 @@ void InitPanning(ALCdevice *device) void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) { - static constexpr ALsizei chans_per_order2d[MAX_AMBI_ORDER+1] = { 1, 2, 2, 2 }; - static constexpr ALsizei chans_per_order3d[MAX_AMBI_ORDER+1] = { 1, 3, 5, 7 }; + static constexpr ALuint chans_per_order2d[MAX_AMBI_ORDER+1] = { 1, 2, 2, 2 }; + static constexpr ALuint chans_per_order3d[MAX_AMBI_ORDER+1] = { 1, 3, 5, 7 }; if(!hqdec && conf->FreqBands != 1) ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n", @@ -546,7 +547,7 @@ void InitHrtfPanning(ALCdevice *device) }, AmbiOrderHFGain3O[MAX_AMBI_ORDER+1]{ 1.86508671e+00f, 1.60609389e+00f, 1.14205530e+00f, 5.68379553e-01f }; - static constexpr ALsizei ChansPerOrder[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; + static constexpr ALuint ChansPerOrder[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; const ALfloat *AmbiOrderHFGain{AmbiOrderHFGain1O}; static_assert(al::size(AmbiPoints) == al::size(AmbiMatrix), "Ambisonic HRTF mismatch"); @@ -759,7 +760,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr device->Dry.AmbiMap.fill(BFChannelConfig{}); device->Dry.NumChannels = 0; - std::fill(std::begin(device->NumChannelsPerOrder), std::end(device->NumChannelsPerOrder), 0); + std::fill(std::begin(device->NumChannelsPerOrder), std::end(device->NumChannelsPerOrder), 0u); device->AvgSpeakerDist = 0.0f; device->ChannelDelay.clear(); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 0534751f..e0639825 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -411,7 +411,7 @@ struct ALCdevice { /* The "dry" path corresponds to the main output. */ MixParams Dry; - ALsizei NumChannelsPerOrder[MAX_AMBI_ORDER+1]{}; + ALuint NumChannelsPerOrder[MAX_AMBI_ORDER+1]{}; /* "Real" output, which will be written to the device buffer. May alias the * dry buffer. diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 25a1d422..3e18f857 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -256,7 +256,6 @@ struct ALvoice { struct DirectData { int FilterType; al::span Buffer; - ALsizei ChannelsPerOrder[MAX_AMBI_ORDER+1]; }; DirectData mDirect; -- cgit v1.2.3 From 5acae56ecd02ee1a47ab6c9c0b95c9612a51d26e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 5 Jun 2019 23:29:13 -0700 Subject: Use a FlexArray for ringbuffer storage --- Alc/ringbuffer.cpp | 32 ++++++++++++++++++-------------- Alc/ringbuffer.h | 6 +++++- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/Alc/ringbuffer.cpp b/Alc/ringbuffer.cpp index ddfeab42..6ef576a5 100644 --- a/Alc/ringbuffer.cpp +++ b/Alc/ringbuffer.cpp @@ -51,7 +51,8 @@ RingBufferPtr CreateRingBuffer(size_t sz, size_t elem_sz, int limit_writes) ++power_of_two; if(power_of_two < sz) return nullptr; - RingBufferPtr rb{new (al_malloc(16, sizeof(*rb) + power_of_two*elem_sz)) RingBuffer{}}; + const size_t bufbytes{power_of_two * elem_sz}; + RingBufferPtr rb{new (al_calloc(16, sizeof(*rb) + bufbytes)) RingBuffer{bufbytes}}; rb->mWriteSize = limit_writes ? sz : (power_of_two-1); rb->mSizeMask = power_of_two - 1; rb->mElemSize = elem_sz; @@ -63,7 +64,7 @@ void RingBuffer::reset() noexcept { mWritePtr.store(0, std::memory_order_relaxed); mReadPtr.store(0, std::memory_order_relaxed); - std::fill_n(mBuffer, (mSizeMask+1)*mElemSize, al::byte{}); + std::fill_n(mBuffer.begin(), (mSizeMask+1)*mElemSize, al::byte{}); } @@ -103,11 +104,12 @@ size_t RingBuffer::read(void *dest, size_t cnt) noexcept n2 = 0; } - memcpy(dest, mBuffer + read_ptr*mElemSize, n1*mElemSize); + auto outiter = std::copy_n(mBuffer.begin() + read_ptr*mElemSize, n1*mElemSize, + static_cast(dest)); read_ptr += n1; if(n2 > 0) { - memcpy(static_cast(dest) + n1*mElemSize, mBuffer, n2*mElemSize); + std::copy_n(mBuffer.begin(), n2*mElemSize, outiter); read_ptr += n2; } mReadPtr.store(read_ptr, std::memory_order_release); @@ -135,9 +137,10 @@ size_t RingBuffer::peek(void *dest, size_t cnt) const noexcept n2 = 0; } - memcpy(dest, mBuffer + read_ptr*mElemSize, n1*mElemSize); + auto outiter = std::copy_n(mBuffer.begin() + read_ptr*mElemSize, n1*mElemSize, + static_cast(dest)); if(n2 > 0) - memcpy(static_cast(dest) + n1*mElemSize, mBuffer, n2*mElemSize); + std::copy_n(mBuffer.begin(), n2*mElemSize, outiter); return to_read; } @@ -162,11 +165,12 @@ size_t RingBuffer::write(const void *src, size_t cnt) noexcept n2 = 0; } - memcpy(mBuffer + write_ptr*mElemSize, src, n1*mElemSize); + auto srcbytes = static_cast(src); + std::copy_n(srcbytes, n1*mElemSize, mBuffer.begin() + write_ptr*mElemSize); write_ptr += n1; if(n2 > 0) { - memcpy(mBuffer, static_cast(src) + n1*mElemSize, n2*mElemSize); + std::copy_n(srcbytes + n1*mElemSize, n2*mElemSize, mBuffer.begin()); write_ptr += n2; } mWritePtr.store(write_ptr, std::memory_order_release); @@ -200,15 +204,15 @@ ll_ringbuffer_data_pair RingBuffer::getReadVector() const noexcept { /* Two part vector: the rest of the buffer after the current read ptr, * plus some from the start of the buffer. */ - ret.first.buf = const_cast(&mBuffer[r*mElemSize]); + ret.first.buf = const_cast(mBuffer.data() + r*mElemSize); ret.first.len = mSizeMask+1 - r; - ret.second.buf = const_cast(mBuffer); + ret.second.buf = const_cast(mBuffer.data()); ret.second.len = cnt2 & mSizeMask; } else { /* Single part vector: just the rest of the buffer */ - ret.first.buf = const_cast(&mBuffer[r*mElemSize]); + ret.first.buf = const_cast(mBuffer.data() + r*mElemSize); ret.first.len = free_cnt; ret.second.buf = nullptr; ret.second.len = 0; @@ -232,14 +236,14 @@ ll_ringbuffer_data_pair RingBuffer::getWriteVector() const noexcept { /* Two part vector: the rest of the buffer after the current write ptr, * plus some from the start of the buffer. */ - ret.first.buf = const_cast(&mBuffer[w*mElemSize]); + ret.first.buf = const_cast(mBuffer.data() + w*mElemSize); ret.first.len = mSizeMask+1 - w; - ret.second.buf = const_cast(mBuffer); + ret.second.buf = const_cast(mBuffer.data()); ret.second.len = cnt2 & mSizeMask; } else { - ret.first.buf = const_cast(&mBuffer[w*mElemSize]); + ret.first.buf = const_cast(mBuffer.data() + w*mElemSize); ret.first.len = free_cnt; ret.second.buf = nullptr; ret.second.len = 0; diff --git a/Alc/ringbuffer.h b/Alc/ringbuffer.h index 6554f95a..84139b66 100644 --- a/Alc/ringbuffer.h +++ b/Alc/ringbuffer.h @@ -31,7 +31,11 @@ struct RingBuffer { size_t mSizeMask{0u}; size_t mElemSize{0u}; - alignas(16) al::byte mBuffer[]; + al::FlexArray mBuffer; + + RingBuffer(const size_t count) : mBuffer{count} { } + RingBuffer(const RingBuffer&) = delete; + RingBuffer& operator=(const RingBuffer&) = delete; /** Reset the read and write pointers to zero. This is not thread safe. */ void reset() noexcept; -- cgit v1.2.3 From d9d9e70ed8b2b27d9659afffe1bd4fb8683535e0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 6 Jun 2019 00:18:25 -0700 Subject: Don't disable some MSVC warnings --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d6448a25..5f2ae2ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,8 +205,8 @@ IF(NOT CMAKE_DEBUG_POSTFIX) ENDIF() IF(MSVC) - SET(CPP_DEFS ${CPP_DEFS} _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE NOMINMAX) - SET(C_FLAGS ${C_FLAGS} /wd4065 /wd4098 /wd4200) + SET(CPP_DEFS ${CPP_DEFS} NOMINMAX) + SET(C_FLAGS ${C_FLAGS} /wd4065) IF(NOT DXSDK_DIR) STRING(REGEX REPLACE "\\\\" "/" DXSDK_DIR "$ENV{DXSDK_DIR}") -- cgit v1.2.3 From a7be53104953ac67081db8e539d423509f44f801 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 6 Jun 2019 00:24:13 -0700 Subject: Remove the unused ALIGN macro --- CMakeLists.txt | 12 ------------ config.h.in | 3 --- 2 files changed, 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f2ae2ec..4743a4ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,7 +111,6 @@ SET(LIB_REVISION "1") SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_REVISION}") SET(EXPORT_DECL "") -SET(ALIGN_DECL "") CHECK_TYPE_SIZE("long" SIZEOF_LONG) @@ -323,11 +322,6 @@ ENDIF() # Set visibility/export options if available IF(WIN32) SET(EXPORT_DECL "__declspec(dllexport)") - IF(NOT MINGW) - SET(ALIGN_DECL "__declspec(align(x))") - ELSE() - SET(ALIGN_DECL "__declspec(aligned(x))") - ENDIF() ELSE() SET(OLD_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") # Yes GCC, really don't accept visibility modes you don't support @@ -352,12 +346,6 @@ ELSE() ENDIF() ENDIF() - CHECK_C_SOURCE_COMPILES("int foo __attribute__((aligned(16))); - int main() {return 0;}" HAVE_ATTRIBUTE_ALIGNED) - IF(HAVE_ATTRIBUTE_ALIGNED) - SET(ALIGN_DECL "__attribute__((aligned(x)))") - ENDIF() - SET(CMAKE_REQUIRED_FLAGS "${OLD_REQUIRED_FLAGS}") ENDIF() diff --git a/config.h.in b/config.h.in index cf46274d..a98faff8 100644 --- a/config.h.in +++ b/config.h.in @@ -2,9 +2,6 @@ #define AL_API ${EXPORT_DECL} #define ALC_API ${EXPORT_DECL} -/* Define any available alignment declaration */ -#define ALIGN(x) ${ALIGN_DECL} - /* Define a restrict macro for non-aliased pointers */ #define RESTRICT ${RESTRICT_DECL} -- cgit v1.2.3 From 585b0cf3bed7d1c5720633eb7e5358a9fca865f6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 6 Jun 2019 00:37:00 -0700 Subject: Remove the DEF_ALIGN macro --- Alc/vector.h | 2 +- OpenAL32/alSource.cpp | 8 ++++---- common/almalloc.cpp | 7 ++++--- common/almalloc.h | 2 -- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Alc/vector.h b/Alc/vector.h index a7df54f4..1b69d6a7 100644 --- a/Alc/vector.h +++ b/Alc/vector.h @@ -7,7 +7,7 @@ namespace al { -template +template using vector = std::vector>; } // namespace al diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 6d4daecd..b2878b8e 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -1284,7 +1284,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co if(buffer != nullptr) { /* Add the selected buffer to a one-item queue */ - auto newlist = static_cast(al_calloc(DEF_ALIGN, + auto newlist = static_cast(al_calloc(alignof(void*), ALbufferlistitem::Sizeof(1u))); newlist->next.store(nullptr, std::memory_order_relaxed); newlist->max_samples = buffer->SampleLen; @@ -3185,13 +3185,13 @@ START_API_FUNC if(!BufferListStart) { - BufferListStart = static_cast(al_calloc(DEF_ALIGN, + BufferListStart = static_cast(al_calloc(alignof(void*), ALbufferlistitem::Sizeof(1u))); BufferList = BufferListStart; } else { - auto item = static_cast(al_calloc(DEF_ALIGN, + auto item = static_cast(al_calloc(alignof(void*), ALbufferlistitem::Sizeof(1u))); BufferList->next.store(item, std::memory_order_relaxed); BufferList = item; @@ -3290,7 +3290,7 @@ START_API_FUNC } std::unique_lock buflock{device->BufferLock}; - auto BufferListStart = static_cast(al_calloc(DEF_ALIGN, + auto BufferListStart = static_cast(al_calloc(alignof(void*), ALbufferlistitem::Sizeof(nb))); BufferList = BufferListStart; BufferList->next.store(nullptr, std::memory_order_relaxed); diff --git a/common/almalloc.cpp b/common/almalloc.cpp index f7af5bf3..fbb84479 100644 --- a/common/almalloc.cpp +++ b/common/almalloc.cpp @@ -4,6 +4,7 @@ #include "almalloc.h" #include +#include #include #include #ifdef HAVE_MALLOC_H @@ -28,7 +29,7 @@ void *al_malloc(size_t alignment, size_t size) { assert((alignment & (alignment-1)) == 0); - alignment = std::max(alignment, sizeof(void*)); + alignment = std::max(alignment, alignof(std::max_align_t)); #if defined(HAVE_ALIGNED_ALLOC) size = (size+(alignment-1))&~(alignment-1); @@ -79,7 +80,7 @@ void al_free(void *ptr) noexcept size_t al_get_page_size() noexcept { - static size_t psize = 0; + static size_t psize{0u}; if(UNLIKELY(!psize)) { #ifdef HAVE_SYSCONF @@ -97,7 +98,7 @@ size_t al_get_page_size() noexcept psize = sysinfo.dwPageSize; } #endif - if(!psize) psize = DEF_ALIGN; + if(!psize) psize = alignof(std::max_align_t); } return psize; } diff --git a/common/almalloc.h b/common/almalloc.h index 74aa4afe..7b74b659 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -7,8 +7,6 @@ #include #include -/* Minimum alignment required by posix_memalign. */ -#define DEF_ALIGN sizeof(void*) void *al_malloc(size_t alignment, size_t size); void *al_calloc(size_t alignment, size_t size); -- cgit v1.2.3 From 39c2b18cd484478e633dc062b5f36a2c9544fb51 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 6 Jun 2019 00:42:59 -0700 Subject: Remove a couple unused functions --- common/almalloc.cpp | 43 ------------------------------------------- common/almalloc.h | 8 -------- 2 files changed, 51 deletions(-) diff --git a/common/almalloc.cpp b/common/almalloc.cpp index fbb84479..f94ae8bc 100644 --- a/common/almalloc.cpp +++ b/common/almalloc.cpp @@ -17,15 +17,6 @@ #endif -#ifdef __GNUC__ -#define LIKELY(x) __builtin_expect(!!(x), !0) -#define UNLIKELY(x) __builtin_expect(!!(x), 0) -#else -#define LIKELY(x) (!!(x)) -#define UNLIKELY(x) (!!(x)) -#endif - - void *al_malloc(size_t alignment, size_t size) { assert((alignment & (alignment-1)) == 0); @@ -77,37 +68,3 @@ void al_free(void *ptr) noexcept } #endif } - -size_t al_get_page_size() noexcept -{ - static size_t psize{0u}; - if(UNLIKELY(!psize)) - { -#ifdef HAVE_SYSCONF -#if defined(_SC_PAGESIZE) - if(!psize) psize = sysconf(_SC_PAGESIZE); -#elif defined(_SC_PAGE_SIZE) - if(!psize) psize = sysconf(_SC_PAGE_SIZE); -#endif -#endif /* HAVE_SYSCONF */ -#ifdef _WIN32 - if(!psize) - { - SYSTEM_INFO sysinfo{}; - GetSystemInfo(&sysinfo); - psize = sysinfo.dwPageSize; - } -#endif - if(!psize) psize = alignof(std::max_align_t); - } - return psize; -} - -int al_is_sane_alignment_allocator() noexcept -{ -#if defined(HAVE_ALIGNED_ALLOC) || defined(HAVE_POSIX_MEMALIGN) || defined(HAVE__ALIGNED_MALLOC) - return 1; -#else - return 0; -#endif -} diff --git a/common/almalloc.h b/common/almalloc.h index 7b74b659..df329747 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -12,14 +12,6 @@ void *al_malloc(size_t alignment, size_t size); void *al_calloc(size_t alignment, size_t size); void al_free(void *ptr) noexcept; -size_t al_get_page_size(void) noexcept; - -/** - * Returns non-0 if the allocation function has direct alignment handling. - * Otherwise, the standard malloc is used with an over-allocation and pointer - * offset strategy. - */ -int al_is_sane_alignment_allocator(void) noexcept; #define DEF_NEWDEL(T) \ void *operator new(size_t size) \ -- cgit v1.2.3 From 56faf66887acb1b8481efec21eb223670524a50a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 6 Jun 2019 03:32:28 -0700 Subject: Disable MSVC warning 4200 again --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4743a4ae..3bf15774 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,7 +205,7 @@ ENDIF() IF(MSVC) SET(CPP_DEFS ${CPP_DEFS} NOMINMAX) - SET(C_FLAGS ${C_FLAGS} /wd4065) + SET(C_FLAGS ${C_FLAGS} /wd4065 /wd4200) IF(NOT DXSDK_DIR) STRING(REGEX REPLACE "\\\\" "/" DXSDK_DIR "$ENV{DXSDK_DIR}") -- cgit v1.2.3 From 87ccdf02a7f2c9611badaa434a91eb1cf31a4b97 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 6 Jun 2019 04:39:30 -0700 Subject: Avoid strcpy --- Alc/hrtf.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 668e5b24..2584ef13 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -1101,7 +1101,8 @@ void AddFileEntry(al::vector &list, const std::string &filename) LoadedHrtfs.emplace_back(HrtfHandle::Create(filename.length()+1)); loaded_entry = LoadedHrtfs.end()-1; - strcpy((*loaded_entry)->filename.data(), filename.c_str()); + std::copy(filename.begin(), filename.end(), (*loaded_entry)->filename.begin()); + (*loaded_entry)->filename.back() = '\0'; } /* TODO: Get a human-readable name from the HRTF data (possibly coming in a -- cgit v1.2.3 From 7537bb349213bafb59e27117bbfe007ae7b573f3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 6 Jun 2019 15:57:15 -0700 Subject: Don't warn about standard functions with MSVC --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3bf15774..37b55e28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -204,7 +204,7 @@ IF(NOT CMAKE_DEBUG_POSTFIX) ENDIF() IF(MSVC) - SET(CPP_DEFS ${CPP_DEFS} NOMINMAX) + SET(CPP_DEFS ${CPP_DEFS} _CRT_SECURE_NO_WARNINGS NOMINMAX) SET(C_FLAGS ${C_FLAGS} /wd4065 /wd4200) IF(NOT DXSDK_DIR) -- cgit v1.2.3 From 7988bc6e91899179a71650bd2534d7749f2a68c3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 7 Jun 2019 23:42:31 -0700 Subject: Add and use proper types for FlexArray --- common/almalloc.h | 63 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/common/almalloc.h b/common/almalloc.h index df329747..d50aa1dd 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -158,16 +158,32 @@ std::unique_ptr make_unique(ArgsT&&...args) */ template struct FlexArray { - const size_t mSize; - alignas(alignment) T mArray[]; + using element_type = T; + using value_type = typename std::remove_cv::type; + using index_type = size_t; + using difference_type = ptrdiff_t; - static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + + const index_type mSize; + alignas(alignment) element_type mArray[]; + + static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept { return base + - std::max(offsetof(FlexArray, mArray) + sizeof(T)*count, sizeof(FlexArray)); + std::max(offsetof(FlexArray, mArray) + sizeof(T)*count, sizeof(FlexArray)); } - FlexArray(size_t size) : mSize{size} + FlexArray(index_type size) : mSize{size} { uninitialized_default_construct_n(mArray, mSize); } ~FlexArray() { destroy_n(mArray, mSize); } @@ -175,26 +191,33 @@ struct FlexArray { FlexArray(const FlexArray&) = delete; FlexArray& operator=(const FlexArray&) = delete; - size_t size() const noexcept { return mSize; } + index_type size() const noexcept { return mSize; } + + pointer data() noexcept { return mArray; } + const_pointer data() const noexcept { return mArray; } - T *data() noexcept { return mArray; } - const T *data() const noexcept { return mArray; } + reference operator[](index_type i) noexcept { return mArray[i]; } + const_reference operator[](index_type i) const noexcept { return mArray[i]; } - T& operator[](size_t i) noexcept { return mArray[i]; } - const T& operator[](size_t i) const noexcept { return mArray[i]; } + reference front() noexcept { return mArray[0]; } + const_reference front() const noexcept { return mArray[0]; } - T& front() noexcept { return mArray[0]; } - const T& front() const noexcept { return mArray[0]; } + reference back() noexcept { return mArray[mSize-1]; } + const_reference back() const noexcept { return mArray[mSize-1]; } - T& back() noexcept { return mArray[mSize-1]; } - const T& back() const noexcept { return mArray[mSize-1]; } + iterator begin() noexcept { return mArray; } + const_iterator begin() const noexcept { return mArray; } + const_iterator cbegin() const noexcept { return mArray; } + iterator end() noexcept { return mArray + mSize; } + const_iterator end() const noexcept { return mArray + mSize; } + const_iterator cend() const noexcept { return mArray + mSize; } - T *begin() noexcept { return mArray; } - const T *begin() const noexcept { return mArray; } - const T *cbegin() const noexcept { return mArray; } - T *end() noexcept { return mArray + mSize; } - const T *end() const noexcept { return mArray + mSize; } - const T *cend() const noexcept { return mArray + mSize; } + reverse_iterator rbegin() noexcept { return end(); } + const_reverse_iterator rbegin() const noexcept { return end(); } + const_reverse_iterator crbegin() const noexcept { return cend(); } + reverse_iterator rend() noexcept { return begin(); } + const_reverse_iterator rend() const noexcept { return begin(); } + const_reverse_iterator crend() const noexcept { return cbegin(); } DEF_PLACE_NEWDEL() }; -- cgit v1.2.3 From 91b7e8142caf297b97d6b403ee79ba2dcbcda09f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 8 Jun 2019 01:39:28 -0700 Subject: Simplify DistanceComp somewhat --- Alc/alc.cpp | 1 - Alc/alu.cpp | 20 ++++++++++---------- Alc/panning.cpp | 44 ++++++++++++++++++++------------------------ OpenAL32/Include/alMain.h | 20 ++++++-------------- 4 files changed, 36 insertions(+), 49 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 58512f52..aeac5354 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1815,7 +1815,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->Limiter = nullptr; device->ChannelDelay.clear(); - device->ChannelDelay.shrink_to_fit(); device->Dry.Buffer = nullptr; device->Dry.NumChannels = 0; diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 9a1958b6..e570c2ad 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1540,22 +1540,22 @@ void ApplyStablizer(FrontStablizer *Stablizer, FloatBufferLine *Buffer, const AL } } -void ApplyDistanceComp(FloatBufferLine *Samples, const DistanceComp &distcomp, - const ALsizei SamplesToDo, const ALuint numchans) +void ApplyDistanceComp(const al::span Samples, const ALsizei SamplesToDo, + const DistanceComp::DistData *distcomp) { ASSUME(SamplesToDo > 0); - ASSUME(numchans > 0); - for(ALuint c{0};c < numchans;c++) + for(auto &chanbuffer : Samples) { - const ALfloat gain{distcomp[c].Gain}; - const ALsizei base{distcomp[c].Length}; - ALfloat *distbuf{al::assume_aligned<16>(distcomp[c].Buffer)}; + const ALfloat gain{distcomp->Gain}; + const ALsizei base{distcomp->Length}; + ALfloat *distbuf{al::assume_aligned<16>(distcomp->Buffer)}; + ++distcomp; if(base < 1) continue; - ALfloat *inout{al::assume_aligned<16>(Samples[c].data())}; + ALfloat *inout{al::assume_aligned<16>(chanbuffer.data())}; auto inout_end = inout + SamplesToDo; if(LIKELY(SamplesToDo >= base)) { @@ -1716,8 +1716,8 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) comp->process(SamplesToDo, device->RealOut.Buffer); /* Apply delays and attenuation for mismatched speaker distances. */ - ApplyDistanceComp(device->RealOut.Buffer, device->ChannelDelay, SamplesToDo, - device->RealOut.NumChannels); + ApplyDistanceComp({device->RealOut.Buffer, device->RealOut.NumChannels}, SamplesToDo, + device->ChannelDelay.as_span().cbegin()); /* Apply dithering. The compressor should have left enough headroom for * the dither noise to not saturate. diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 714c3e98..4c899f66 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -251,17 +251,17 @@ void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) { + auto get_max = std::bind(maxf, _1, + std::bind(std::mem_fn(&AmbDecConf::SpeakerConf::Distance), _2)); const ALfloat maxdist{ - std::accumulate(conf->Speakers.begin(), conf->Speakers.end(), float{0.0f}, - std::bind(maxf, _1, std::bind(std::mem_fn(&AmbDecConf::SpeakerConf::Distance), _2)) - ) - }; + std::accumulate(conf->Speakers.begin(), conf->Speakers.end(), float{0.0f}, get_max)}; const char *devname{device->DeviceName.c_str()}; if(!GetConfigValueBool(devname, "decoder", "distance-comp", 1) || !(maxdist > 0.0f)) return; - auto srate = static_cast(device->Frequency); + const auto distSampleScale = static_cast(device->Frequency)/SPEEDOFSOUNDMETRESPERSEC; + const auto ChanDelay = device->ChannelDelay.as_span(); size_t total{0u}; for(size_t i{0u};i < conf->Speakers.size();i++) { @@ -274,40 +274,36 @@ void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei ( * phase offsets. This means at 48khz, for instance, the distance delay * will be in steps of about 7 millimeters. */ - const ALfloat delay{ - std::floor((maxdist - speaker.Distance)/SPEEDOFSOUNDMETRESPERSEC*srate + 0.5f) - }; - if(delay >= static_cast(MAX_DELAY_LENGTH)) - ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %d)\n", - speaker.Name.c_str(), delay, MAX_DELAY_LENGTH); - - device->ChannelDelay[chan].Length = static_cast(clampf( - delay, 0.0f, static_cast(MAX_DELAY_LENGTH-1) - )); - device->ChannelDelay[chan].Gain = speaker.Distance / maxdist; + ALfloat delay{std::floor((maxdist - speaker.Distance)*distSampleScale + 0.5f)}; + if(delay > ALfloat{MAX_DELAY_LENGTH-1}) + { + ERR("Delay for speaker \"%s\" exceeds buffer length (%f > %d)\n", + speaker.Name.c_str(), delay, MAX_DELAY_LENGTH-1); + delay = ALfloat{MAX_DELAY_LENGTH-1}; + } + + ChanDelay[chan].Length = static_cast(delay); + ChanDelay[chan].Gain = speaker.Distance / maxdist; TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan, - speaker.Name.c_str(), device->ChannelDelay[chan].Length, - device->ChannelDelay[chan].Gain - ); + speaker.Name.c_str(), ChanDelay[chan].Length, ChanDelay[chan].Gain); /* Round up to the next 4th sample, so each channel buffer starts * 16-byte aligned. */ - total += RoundUp(device->ChannelDelay[chan].Length, 4); + total += RoundUp(ChanDelay[chan].Length, 4); } if(total > 0) { - device->ChannelDelay.resize(total); - device->ChannelDelay[0].Buffer = device->ChannelDelay.data(); + device->ChannelDelay.setSampleCount(total); + ChanDelay[0].Buffer = device->ChannelDelay.getSamples(); auto set_bufptr = [](const DistanceComp::DistData &last, const DistanceComp::DistData &cur) -> DistanceComp::DistData { DistanceComp::DistData ret{cur}; ret.Buffer = last.Buffer + RoundUp(last.Length, 4); return ret; }; - std::partial_sum(device->ChannelDelay.begin(), device->ChannelDelay.end(), - device->ChannelDelay.begin(), set_bufptr); + std::partial_sum(ChanDelay.begin(), ChanDelay.end(), ChanDelay.begin(), set_bufptr); } } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index e0639825..962b8e15 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -28,6 +28,7 @@ #include "vector.h" #include "almalloc.h" #include "alnumeric.h" +#include "alspan.h" #include "threads.h" #include "ambidefs.h" #include "hrtf.h" @@ -266,8 +267,7 @@ private: al::vector mSamples; public: - void resize(size_t new_size) { mSamples.resize(new_size); } - void shrink_to_fit() { mSamples.shrink_to_fit(); } + void setSampleCount(size_t new_size) { mSamples.resize(new_size); } void clear() noexcept { for(auto &chan : mChannel) @@ -276,21 +276,13 @@ public: chan.Length = 0; chan.Buffer = nullptr; } - mSamples.clear(); + using SampleVecT = decltype(mSamples); + SampleVecT{}.swap(mSamples); } - DistData *begin() noexcept { return std::begin(mChannel); } - const DistData *begin() const noexcept { return std::begin(mChannel); } - const DistData *cbegin() const noexcept { return std::begin(mChannel); } - DistData *end() noexcept { return std::end(mChannel); } - const DistData *end() const noexcept { return std::end(mChannel); } - const DistData *cend() const noexcept { return std::end(mChannel); } + ALfloat *getSamples() noexcept { return mSamples.data(); } - ALfloat *data() noexcept { return mSamples.data(); } - const ALfloat *data() const noexcept { return mSamples.data(); } - - DistData& operator[](size_t o) noexcept { return mChannel[o]; } - const DistData& operator[](size_t o) const noexcept { return mChannel[o]; } + al::span as_span() { return mChannel; } }; struct BFChannelConfig { -- cgit v1.2.3 From 1569b79c5d133717c4913cfde7cdbf0e7c64f270 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 8 Jun 2019 02:17:08 -0700 Subject: Fix for GCC 5.4 --- OpenAL32/Include/alMain.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 962b8e15..5dc76552 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -263,14 +263,14 @@ public: }; private: - DistData mChannel[MAX_OUTPUT_CHANNELS]; + std::array mChannels; al::vector mSamples; public: void setSampleCount(size_t new_size) { mSamples.resize(new_size); } void clear() noexcept { - for(auto &chan : mChannel) + for(auto &chan : mChannels) { chan.Gain = 1.0f; chan.Length = 0; @@ -282,7 +282,7 @@ public: ALfloat *getSamples() noexcept { return mSamples.data(); } - al::span as_span() { return mChannel; } + al::span as_span() { return mChannels; } }; struct BFChannelConfig { -- cgit v1.2.3 From b6ce793f849c25cb9ddf992e2b647d3babcaf6cb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 8 Jun 2019 16:05:18 -0700 Subject: Use a span for the complex_fft/hilbert functions --- Alc/effects/fshifter.cpp | 2 +- Alc/effects/pshifter.cpp | 4 ++-- common/alcomplex.cpp | 58 ++++++++++++++++++++++++------------------------ common/alcomplex.h | 18 +++++++-------- 4 files changed, 41 insertions(+), 41 deletions(-) diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp index 496a767d..0bbcc859 100644 --- a/Alc/effects/fshifter.cpp +++ b/Alc/effects/fshifter.cpp @@ -171,7 +171,7 @@ void FshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE } /* Processing signal by Discrete Hilbert Transform (analytical signal). */ - complex_hilbert(mAnalytic, HIL_SIZE); + complex_hilbert(mAnalytic); /* Windowing and add to output accumulator */ for(k = 0;k < HIL_SIZE;k++) diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp index f1865830..619bde34 100644 --- a/Alc/effects/pshifter.cpp +++ b/Alc/effects/pshifter.cpp @@ -230,7 +230,7 @@ void PshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE /* ANALYSIS */ /* Apply FFT to FFTbuffer data */ - complex_fft(mFFTbuffer, STFT_SIZE, -1.0); + complex_fft(mFFTbuffer, -1.0); /* Analyze the obtained data. Since the real FFT is symmetric, only * STFT_HALF_SIZE+1 samples are needed. @@ -302,7 +302,7 @@ void PshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE mFFTbuffer[k] = complex_d{}; /* Apply iFFT to buffer data */ - complex_fft(mFFTbuffer, STFT_SIZE, 1.0); + complex_fft(mFFTbuffer, 1.0); /* Windowing and add to output */ for(ALsizei k{0};k < STFT_SIZE;k++) diff --git a/common/alcomplex.cpp b/common/alcomplex.cpp index ace1b43f..9074cf5f 100644 --- a/common/alcomplex.cpp +++ b/common/alcomplex.cpp @@ -4,6 +4,7 @@ #include "alcomplex.h" #include +#include namespace { @@ -11,13 +12,14 @@ constexpr double Pi{3.141592653589793238462643383279502884}; } // namespace -void complex_fft(std::complex *FFTBuffer, int FFTSize, double Sign) +void complex_fft(const al::span> buffer, const double sign) { + const size_t fftsize{buffer.size()}; /* Bit-reversal permutation applied to a sequence of FFTSize items */ - for(int i{1};i < FFTSize-1;i++) + for(size_t i{1u};i < fftsize-1;i++) { - int j{0}; - for(int mask{1};mask < FFTSize;mask <<= 1) + size_t j{0u}; + for(size_t mask{1u};mask < fftsize;mask <<= 1) { if((i&mask) != 0) j++; @@ -26,25 +28,25 @@ void complex_fft(std::complex *FFTBuffer, int FFTSize, double Sign) j >>= 1; if(i < j) - std::swap(FFTBuffer[i], FFTBuffer[j]); + std::swap(buffer[i], buffer[j]); } /* Iterative form of Danielson–Lanczos lemma */ - int step{2}; - for(int i{1};i < FFTSize;i<<=1, step<<=1) + size_t step{2u}; + for(size_t i{1u};i < fftsize;i<<=1, step<<=1) { - int step2{step >> 1}; + const size_t step2{step >> 1}; double arg{Pi / step2}; - std::complex w{std::cos(arg), std::sin(arg)*Sign}; + std::complex w{std::cos(arg), std::sin(arg)*sign}; std::complex u{1.0, 0.0}; - for(int j{0};j < step2;j++) + for(size_t j{0};j < step2;j++) { - for(int k{j};k < FFTSize;k+=step) + for(size_t k{j};k < fftsize;k+=step) { - std::complex temp{FFTBuffer[k+step2] * u}; - FFTBuffer[k+step2] = FFTBuffer[k] - temp; - FFTBuffer[k] += temp; + std::complex temp{buffer[k+step2] * u}; + buffer[k+step2] = buffer[k] - temp; + buffer[k] += temp; } u *= w; @@ -52,25 +54,23 @@ void complex_fft(std::complex *FFTBuffer, int FFTSize, double Sign) } } -void complex_hilbert(std::complex *Buffer, int size) +void complex_hilbert(const al::span> buffer) { - const double inverse_size = 1.0/static_cast(size); + std::for_each(buffer.begin(), buffer.end(), [](std::complex &c) { c.imag(0.0); }); - for(int i{0};i < size;i++) - Buffer[i].imag(0.0); + complex_fft(buffer, 1.0); - complex_fft(Buffer, size, 1.0); + const double inverse_size = 1.0/static_cast(buffer.size()); + auto bufiter = buffer.begin(); + const auto halfiter = bufiter + (buffer.size()>>1); - int todo{size>>1}; - int i{0}; + *bufiter *= inverse_size; ++bufiter; + bufiter = std::transform(bufiter, halfiter, bufiter, + [inverse_size](const std::complex &c) -> std::complex + { return c * (2.0*inverse_size); }); + *bufiter *= inverse_size; ++bufiter; - Buffer[i++] *= inverse_size; - while(i < todo) - Buffer[i++] *= 2.0*inverse_size; - Buffer[i++] *= inverse_size; + std::fill(bufiter, buffer.end(), std::complex{}); - for(;i < size;i++) - Buffer[i] = std::complex{}; - - complex_fft(Buffer, size, -1.0); + complex_fft(buffer, -1.0); } diff --git a/common/alcomplex.h b/common/alcomplex.h index 554886c4..f224cce2 100644 --- a/common/alcomplex.h +++ b/common/alcomplex.h @@ -3,22 +3,22 @@ #include +#include "alspan.h" + /** * Iterative implementation of 2-radix FFT (In-place algorithm). Sign = -1 is - * FFT and 1 is iFFT (inverse). Fills FFTBuffer[0...FFTSize-1] with the - * Discrete Fourier Transform (DFT) of the time domain data stored in - * FFTBuffer[0...FFTSize-1]. FFTBuffer is an array of complex numbers, FFTSize - * MUST BE power of two. + * FFT and 1 is iFFT (inverse). Fills the buffer with the Discrete Fourier + * Transform (DFT) of the time domain data stored in the buffer. The buffer is + * an array of complex numbers, and MUST BE power of two. */ -void complex_fft(std::complex *FFTBuffer, int FFTSize, double Sign); +void complex_fft(const al::span> buffer, const double sign); /** * Calculate the complex helical sequence (discrete-time analytical signal) of * the given input using the discrete Hilbert transform (In-place algorithm). - * Fills Buffer[0...size-1] with the discrete-time analytical signal stored in - * Buffer[0...size-1]. Buffer is an array of complex numbers, size MUST BE - * power of two. + * Fills the buffer with the discrete-time analytical signal stored in the + * buffer. The buffer is an array of complex numbers and MUST BE power of two. */ -void complex_hilbert(std::complex *Buffer, int size); +void complex_hilbert(const al::span> buffer); #endif /* ALCOMPLEX_H */ -- cgit v1.2.3 From c9ba7ba19353c9cf55dec668b2b059c267d1b0ea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 8 Jun 2019 23:33:59 -0700 Subject: Add a bitfield class for indexed, auto-sized flags --- common/albyte.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/common/albyte.h b/common/albyte.h index d1459e96..8257560e 100644 --- a/common/albyte.h +++ b/common/albyte.h @@ -1,6 +1,8 @@ #ifndef AL_BYTE_H #define AL_BYTE_H +#include +#include #include namespace al { @@ -63,6 +65,29 @@ AL_DECL_OP(^) #undef AL_DECL_OP +template +class bitfield { + static constexpr size_t bits_per_byte{std::numeric_limits::digits}; + static constexpr size_t NumElems{(N+bits_per_byte-1) / bits_per_byte}; + + byte vals[NumElems]{}; + +public: + void set(size_t b) noexcept { vals[b/bits_per_byte] |= 1 << (b%bits_per_byte); } + void unset(size_t b) noexcept { vals[b/bits_per_byte] &= ~(1 << (b%bits_per_byte)); } + bool get(size_t b) const noexcept + { return (vals[b/bits_per_byte] & (1 << (b%bits_per_byte))) != byte{}; } + + template 0)> + void set(size_t b, Args ...args) noexcept + { + set(b); + /* Trick for calling set() on each element of the parameter pack. */ + using CharArray = char[sizeof...(Args)]; + (void)(CharArray{ (set(args),'\0')... }); + } +}; + #undef REQUIRES } // namespace al -- cgit v1.2.3 From 2e154069c6aa3bfc9d00d420e2f508a4127dd649 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 8 Jun 2019 23:49:15 -0700 Subject: Use a bitfield for the device flags --- Alc/alc.cpp | 84 ++++++++++++++++++++++----------------------- Alc/backends/alsa.cpp | 2 +- Alc/backends/dsound.cpp | 4 +-- Alc/backends/opensl.cpp | 2 +- Alc/backends/pulseaudio.cpp | 4 +-- Alc/backends/wasapi.cpp | 4 +-- OpenAL32/Include/alMain.h | 33 ++++++++++-------- 7 files changed, 67 insertions(+), 66 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index aeac5354..dfd4ef23 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1617,9 +1617,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) /* If a context is already running on the device, stop playback so * the device attributes can be updated. */ - if((device->Flags&DEVICE_RUNNING)) + if(device->Flags.get(DeviceRunning)) device->Backend->stop(); - device->Flags &= ~DEVICE_RUNNING; + device->Flags.unset(DeviceRunning); } auto numMono = static_cast(device->NumMonoSources); @@ -1734,9 +1734,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } } - if((device->Flags&DEVICE_RUNNING)) + if(device->Flags.get(DeviceRunning)) device->Backend->stop(); - device->Flags &= ~DEVICE_RUNNING; + device->Flags.unset(DeviceRunning); UpdateClockBase(device); @@ -1748,7 +1748,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ConfigValueUInt(devname, nullptr, "frequency", &freq); if(freq < 1) - device->Flags &= ~DEVICE_FREQUENCY_REQUEST; + device->Flags.unset(FrequencyRequest); else { freq = maxi(freq, MIN_OUTPUT_RATE); @@ -1759,7 +1759,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->Frequency; device->Frequency = freq; - device->Flags |= DEVICE_FREQUENCY_REQUEST; + device->Flags.set(FrequencyRequest); } ConfigValueUInt(devname, nullptr, "period_size", &device->UpdateSize); @@ -1807,7 +1807,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) new_sends = numSends; } - if((device->Flags&DEVICE_RUNNING)) + if(device->Flags.get(DeviceRunning)) return ALC_NO_ERROR; device->Uhj_Encoder = nullptr; @@ -1862,7 +1862,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { device->FmtChans = DevFmtStereo; device->Frequency = hrtf->sampleRate; - device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_FREQUENCY_REQUEST; + device->Flags.set(ChannelsRequest, FrequencyRequest); if(HrtfEntry *oldhrtf{device->mHrtf}) oldhrtf->DecRef(); device->mHrtf = hrtf; @@ -1881,9 +1881,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) oldType = device->FmtType; TRACE("Pre-reset: %s%s, %s%s, %s%uhz, %u / %u buffer\n", - (device->Flags&DEVICE_CHANNELS_REQUEST)?"*":"", DevFmtChannelsString(device->FmtChans), - (device->Flags&DEVICE_SAMPLE_TYPE_REQUEST)?"*":"", DevFmtTypeString(device->FmtType), - (device->Flags&DEVICE_FREQUENCY_REQUEST)?"*":"", device->Frequency, + device->Flags.get(ChannelsRequest)?"*":"", DevFmtChannelsString(device->FmtChans), + device->Flags.get(SampleTypeRequest)?"*":"", DevFmtTypeString(device->FmtType), + device->Flags.get(FrequencyRequest)?"*":"", device->Frequency, device->UpdateSize, device->BufferSize); try { @@ -1895,22 +1895,22 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) return ALC_INVALID_DEVICE; } - if(device->FmtChans != oldChans && (device->Flags&DEVICE_CHANNELS_REQUEST)) + if(device->FmtChans != oldChans && device->Flags.get(ChannelsRequest)) { ERR("Failed to set %s, got %s instead\n", DevFmtChannelsString(oldChans), DevFmtChannelsString(device->FmtChans)); - device->Flags &= ~DEVICE_CHANNELS_REQUEST; + device->Flags.unset(ChannelsRequest); } - if(device->FmtType != oldType && (device->Flags&DEVICE_SAMPLE_TYPE_REQUEST)) + if(device->FmtType != oldType && device->Flags.get(SampleTypeRequest)) { ERR("Failed to set %s, got %s instead\n", DevFmtTypeString(oldType), DevFmtTypeString(device->FmtType)); - device->Flags &= ~DEVICE_SAMPLE_TYPE_REQUEST; + device->Flags.unset(SampleTypeRequest); } - if(device->Frequency != oldFreq && (device->Flags&DEVICE_FREQUENCY_REQUEST)) + if(device->Frequency != oldFreq && device->Flags.get(FrequencyRequest)) { ERR("Failed to set %uhz, got %uhz instead\n", oldFreq, device->Frequency); - device->Flags &= ~DEVICE_FREQUENCY_REQUEST; + device->Flags.unset(FrequencyRequest); } if((device->UpdateSize&3) != 0) @@ -2181,11 +2181,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(update_failed) return ALC_INVALID_DEVICE; - if(!(device->Flags&DEVICE_PAUSED)) + if(!device->Flags.get(DevicePaused)) { if(device->Backend->start() == ALC_FALSE) return ALC_INVALID_DEVICE; - device->Flags |= DEVICE_RUNNING; + device->Flags.set(DeviceRunning); } return ALC_NO_ERROR; @@ -3525,10 +3525,10 @@ START_API_FUNC if(ALCdevice *Device{ctx->Device}) { std::lock_guard _{Device->StateLock}; - if(!ReleaseContext(ctx.get(), Device) && (Device->Flags&DEVICE_RUNNING)) + if(!ReleaseContext(ctx.get(), Device) && Device->Flags.get(DeviceRunning)) { Device->Backend->stop(); - Device->Flags &= ~DEVICE_RUNNING; + Device->Flags.unset(DeviceRunning); } } listlock.unlock(); @@ -3731,7 +3731,7 @@ START_API_FUNC { device->FmtChans = iter->chans; device->mAmbiOrder = iter->order; - device->Flags |= DEVICE_CHANNELS_REQUEST; + device->Flags.set(ChannelsRequest); } } if(ConfigValueStr(deviceName, nullptr, "sample-type", &fmt)) @@ -3758,7 +3758,7 @@ START_API_FUNC else { device->FmtType = iter->type; - device->Flags |= DEVICE_SAMPLE_TYPE_REQUEST; + device->Flags.set(SampleTypeRequest); } } @@ -3773,7 +3773,7 @@ START_API_FUNC device->UpdateSize = (device->UpdateSize*freq + device->Frequency/2) / device->Frequency; device->BufferSize = (device->BufferSize*freq + device->Frequency/2) / device->Frequency; device->Frequency = freq; - device->Flags |= DEVICE_FREQUENCY_REQUEST; + device->Flags.set(FrequencyRequest); } ConfigValueUInt(deviceName, nullptr, "period_size", &device->UpdateSize); @@ -3887,9 +3887,9 @@ START_API_FUNC ReleaseContext(ctx, device); ctx = next; } - if((device->Flags&DEVICE_RUNNING)) + if(device->Flags.get(DeviceRunning)) device->Backend->stop(); - device->Flags &= ~DEVICE_RUNNING; + device->Flags.unset(DeviceRunning); statelock.unlock(); ALCdevice_DecRef(device); @@ -3925,14 +3925,12 @@ START_API_FUNC DeviceRef device{new ALCdevice{Capture}}; device->Frequency = frequency; - device->Flags |= DEVICE_FREQUENCY_REQUEST; - if(DecomposeDevFormat(format, &device->FmtChans, &device->FmtType) == AL_FALSE) { alcSetError(nullptr, ALC_INVALID_ENUM); return nullptr; } - device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_SAMPLE_TYPE_REQUEST; + device->Flags.set(FrequencyRequest, ChannelsRequest, SampleTypeRequest); device->UpdateSize = samples; device->BufferSize = samples; @@ -3989,9 +3987,9 @@ START_API_FUNC listlock.unlock(); { std::lock_guard _{device->StateLock}; - if((device->Flags&DEVICE_RUNNING)) + if(device->Flags.get(DeviceRunning)) device->Backend->stop(); - device->Flags &= ~DEVICE_RUNNING; + device->Flags.unset(DeviceRunning); } ALCdevice_DecRef(device); @@ -4013,10 +4011,10 @@ START_API_FUNC std::lock_guard _{dev->StateLock}; if(!dev->Connected.load(std::memory_order_acquire)) alcSetError(dev.get(), ALC_INVALID_DEVICE); - else if(!(dev->Flags&DEVICE_RUNNING)) + else if(!dev->Flags.get(DeviceRunning)) { if(dev->Backend->start()) - dev->Flags |= DEVICE_RUNNING; + dev->Flags.set(DeviceRunning); else { aluHandleDisconnect(dev.get(), "Device start failure"); @@ -4035,9 +4033,9 @@ START_API_FUNC else { std::lock_guard _{dev->StateLock}; - if((dev->Flags&DEVICE_RUNNING)) + if(dev->Flags.get(DeviceRunning)) dev->Backend->stop(); - dev->Flags &= ~DEVICE_RUNNING; + dev->Flags.unset(DeviceRunning); } } END_API_FUNC @@ -4199,10 +4197,10 @@ START_API_FUNC else { std::lock_guard _{dev->StateLock}; - if((dev->Flags&DEVICE_RUNNING)) + if(dev->Flags.get(DeviceRunning)) dev->Backend->stop(); - dev->Flags &= ~DEVICE_RUNNING; - dev->Flags |= DEVICE_PAUSED; + dev->Flags.unset(DeviceRunning); + dev->Flags.set(DevicePaused); } } END_API_FUNC @@ -4222,9 +4220,9 @@ START_API_FUNC } std::lock_guard _{dev->StateLock}; - if(!(dev->Flags&DEVICE_PAUSED)) + if(!dev->Flags.get(DevicePaused)) return; - dev->Flags &= ~DEVICE_PAUSED; + dev->Flags.unset(DevicePaused); if(dev->ContextList.load() == nullptr) return; @@ -4234,7 +4232,7 @@ START_API_FUNC alcSetError(dev.get(), ALC_INVALID_DEVICE); return; } - dev->Flags |= DEVICE_RUNNING; + dev->Flags.set(DeviceRunning); } END_API_FUNC @@ -4291,9 +4289,9 @@ START_API_FUNC /* Force the backend to stop mixing first since we're resetting. Also reset * the connected state so lost devices can attempt recover. */ - if((dev->Flags&DEVICE_RUNNING)) + if(dev->Flags.get(DeviceRunning)) dev->Backend->stop(); - dev->Flags &= ~DEVICE_RUNNING; + dev->Flags.unset(DeviceRunning); device->Connected.store(true); ALCenum err{UpdateDeviceParams(dev.get(), attribs)}; diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index eee89b28..1c0d7489 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -725,7 +725,7 @@ ALCboolean AlsaPlayback::reset() CHECK(snd_pcm_hw_params_set_channels(mPcmHandle, hp, mDevice->channelsFromFmt())); /* set rate (implicitly constrains period/buffer parameters) */ if(!GetConfigValueBool(mDevice->DeviceName.c_str(), "alsa", "allow-resampler", 0) || - !(mDevice->Flags&DEVICE_FREQUENCY_REQUEST)) + !mDevice->Flags.get(FrequencyRequest)) { if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp, 0) < 0) ERR("Failed to disable ALSA resampler\n"); diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 039f78ac..480d9a18 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -359,7 +359,7 @@ ALCboolean DSoundPlayback::reset() mDevice->FmtType = DevFmtUByte; break; case DevFmtFloat: - if((mDevice->Flags&DEVICE_SAMPLE_TYPE_REQUEST)) + if(mDevice->Flags.get(SampleTypeRequest)) break; /* fall-through */ case DevFmtUShort: @@ -380,7 +380,7 @@ ALCboolean DSoundPlayback::reset() if(SUCCEEDED(hr)) { speakers = DSSPEAKER_CONFIG(speakers); - if(!(mDevice->Flags&DEVICE_CHANNELS_REQUEST)) + if(!mDevice->Flags.get(ChannelsRequest)) { if(speakers == DSSPEAKER_MONO) mDevice->FmtChans = DevFmtMono; diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 4cf7ca36..37495abe 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -361,7 +361,7 @@ ALCboolean OpenSLPlayback::reset() mRing = nullptr; #if 0 - if(!(mDevice->Flags&DEVICE_FREQUENCY_REQUEST)) + if(!mDevice->Flags.get(FrequencyRequest)) { /* FIXME: Disabled until I figure out how to get the Context needed for * the getSystemService call. diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 30c0053d..0b7257d1 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -779,7 +779,7 @@ void PulsePlayback::sinkInfoCallback(pa_context* UNUSED(context), const pa_sink_ ); if(chanmap != chanmaps.cend()) { - if(!(mDevice->Flags&DEVICE_CHANNELS_REQUEST)) + if(!mDevice->Flags.get(ChannelsRequest)) mDevice->FmtChans = chanmap->chans; } else @@ -910,7 +910,7 @@ ALCboolean PulsePlayback::reset() flags |= PA_STREAM_ADJUST_LATENCY; } if(GetConfigValueBool(mDevice->DeviceName.c_str(), "pulse", "fix-rate", 0) || - !(mDevice->Flags&DEVICE_FREQUENCY_REQUEST)) + !mDevice->Flags.get(FrequencyRequest)) flags |= PA_STREAM_FIX_RATE; pa_channel_map chanmap{}; diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index c80e5943..6c3dc6e6 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -787,9 +787,9 @@ HRESULT WasapiPlayback::resetProxy() const REFERENCE_TIME per_time{mDevice->UpdateSize * REFTIME_PER_SEC / mDevice->Frequency}; const REFERENCE_TIME buf_time{mDevice->BufferSize * REFTIME_PER_SEC / mDevice->Frequency}; - if(!(mDevice->Flags&DEVICE_FREQUENCY_REQUEST)) + if(!mDevice->Flags.get(FrequencyRequest)) mDevice->Frequency = OutputType.Format.nSamplesPerSec; - if(!(mDevice->Flags&DEVICE_CHANNELS_REQUEST)) + if(!mDevice->Flags.get(ChannelsRequest)) { if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) mDevice->FmtChans = DevFmtMono; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 5dc76552..9a5b3814 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -26,6 +26,7 @@ #include "inprogext.h" #include "atomic.h" #include "vector.h" +#include "albyte.h" #include "almalloc.h" #include "alnumeric.h" #include "alspan.h" @@ -322,6 +323,22 @@ struct RealMixParams { using POSTPROCESS = void(*)(ALCdevice *device, const ALsizei SamplesToDo); +enum { + // Frequency was requested by the app or config file + FrequencyRequest, + // Channel configuration was requested by the config file + ChannelsRequest, + // Sample type was requested by the config file + SampleTypeRequest, + + // Specifies if the DSP is paused at user request + DevicePaused, + // Specifies if the device is currently running + DeviceRunning, + + DeviceFlagsCount +}; + struct ALCdevice { RefCount ref{1u}; @@ -347,7 +364,7 @@ struct ALCdevice { std::string DeviceName; // Device flags - ALuint Flags{0u}; + al::bitfield Flags{}; std::string HrtfName; al::vector HrtfList; @@ -466,20 +483,6 @@ struct ALCdevice { DEF_NEWDEL(ALCdevice) }; -// Frequency was requested by the app or config file -#define DEVICE_FREQUENCY_REQUEST (1u<<1) -// Channel configuration was requested by the config file -#define DEVICE_CHANNELS_REQUEST (1u<<2) -// Sample type was requested by the config file -#define DEVICE_SAMPLE_TYPE_REQUEST (1u<<3) - -// Specifies if the DSP is paused at user request -#define DEVICE_PAUSED (1u<<30) - -// Specifies if the device is currently running -#define DEVICE_RUNNING (1u<<31) - - /* Must be less than 15 characters (16 including terminating null) for * compatibility with pthread_setname_np limitations. */ #define MIXER_THREAD_NAME "alsoft-mixer" -- cgit v1.2.3 From 90d25e5187ca50a6e978603fabb6395035ad0db5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 9 Jun 2019 02:20:30 -0700 Subject: Make sure the bitfield indices are constants --- Alc/alc.cpp | 82 ++++++++++++++++++++++----------------------- Alc/backends/alsa.cpp | 2 +- Alc/backends/dsound.cpp | 4 +-- Alc/backends/opensl.cpp | 2 +- Alc/backends/pulseaudio.cpp | 4 +-- Alc/backends/wasapi.cpp | 4 +-- common/albyte.h | 32 ++++++++++++------ 7 files changed, 71 insertions(+), 59 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index dfd4ef23..0724f0ce 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1617,9 +1617,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) /* If a context is already running on the device, stop playback so * the device attributes can be updated. */ - if(device->Flags.get(DeviceRunning)) + if(device->Flags.get()) device->Backend->stop(); - device->Flags.unset(DeviceRunning); + device->Flags.unset(); } auto numMono = static_cast(device->NumMonoSources); @@ -1734,9 +1734,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } } - if(device->Flags.get(DeviceRunning)) + if(device->Flags.get()) device->Backend->stop(); - device->Flags.unset(DeviceRunning); + device->Flags.unset(); UpdateClockBase(device); @@ -1748,7 +1748,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ConfigValueUInt(devname, nullptr, "frequency", &freq); if(freq < 1) - device->Flags.unset(FrequencyRequest); + device->Flags.unset(); else { freq = maxi(freq, MIN_OUTPUT_RATE); @@ -1759,7 +1759,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->Frequency; device->Frequency = freq; - device->Flags.set(FrequencyRequest); + device->Flags.set(); } ConfigValueUInt(devname, nullptr, "period_size", &device->UpdateSize); @@ -1807,7 +1807,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) new_sends = numSends; } - if(device->Flags.get(DeviceRunning)) + if(device->Flags.get()) return ALC_NO_ERROR; device->Uhj_Encoder = nullptr; @@ -1862,7 +1862,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { device->FmtChans = DevFmtStereo; device->Frequency = hrtf->sampleRate; - device->Flags.set(ChannelsRequest, FrequencyRequest); + device->Flags.set(); if(HrtfEntry *oldhrtf{device->mHrtf}) oldhrtf->DecRef(); device->mHrtf = hrtf; @@ -1881,9 +1881,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) oldType = device->FmtType; TRACE("Pre-reset: %s%s, %s%s, %s%uhz, %u / %u buffer\n", - device->Flags.get(ChannelsRequest)?"*":"", DevFmtChannelsString(device->FmtChans), - device->Flags.get(SampleTypeRequest)?"*":"", DevFmtTypeString(device->FmtType), - device->Flags.get(FrequencyRequest)?"*":"", device->Frequency, + device->Flags.get()?"*":"", DevFmtChannelsString(device->FmtChans), + device->Flags.get()?"*":"", DevFmtTypeString(device->FmtType), + device->Flags.get()?"*":"", device->Frequency, device->UpdateSize, device->BufferSize); try { @@ -1895,22 +1895,22 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) return ALC_INVALID_DEVICE; } - if(device->FmtChans != oldChans && device->Flags.get(ChannelsRequest)) + if(device->FmtChans != oldChans && device->Flags.get()) { ERR("Failed to set %s, got %s instead\n", DevFmtChannelsString(oldChans), DevFmtChannelsString(device->FmtChans)); - device->Flags.unset(ChannelsRequest); + device->Flags.unset(); } - if(device->FmtType != oldType && device->Flags.get(SampleTypeRequest)) + if(device->FmtType != oldType && device->Flags.get()) { ERR("Failed to set %s, got %s instead\n", DevFmtTypeString(oldType), DevFmtTypeString(device->FmtType)); - device->Flags.unset(SampleTypeRequest); + device->Flags.unset(); } - if(device->Frequency != oldFreq && device->Flags.get(FrequencyRequest)) + if(device->Frequency != oldFreq && device->Flags.get()) { ERR("Failed to set %uhz, got %uhz instead\n", oldFreq, device->Frequency); - device->Flags.unset(FrequencyRequest); + device->Flags.unset(); } if((device->UpdateSize&3) != 0) @@ -2181,11 +2181,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(update_failed) return ALC_INVALID_DEVICE; - if(!device->Flags.get(DevicePaused)) + if(!device->Flags.get()) { if(device->Backend->start() == ALC_FALSE) return ALC_INVALID_DEVICE; - device->Flags.set(DeviceRunning); + device->Flags.set(); } return ALC_NO_ERROR; @@ -3525,10 +3525,10 @@ START_API_FUNC if(ALCdevice *Device{ctx->Device}) { std::lock_guard _{Device->StateLock}; - if(!ReleaseContext(ctx.get(), Device) && Device->Flags.get(DeviceRunning)) + if(!ReleaseContext(ctx.get(), Device) && Device->Flags.get()) { Device->Backend->stop(); - Device->Flags.unset(DeviceRunning); + Device->Flags.unset(); } } listlock.unlock(); @@ -3731,7 +3731,7 @@ START_API_FUNC { device->FmtChans = iter->chans; device->mAmbiOrder = iter->order; - device->Flags.set(ChannelsRequest); + device->Flags.set(); } } if(ConfigValueStr(deviceName, nullptr, "sample-type", &fmt)) @@ -3758,7 +3758,7 @@ START_API_FUNC else { device->FmtType = iter->type; - device->Flags.set(SampleTypeRequest); + device->Flags.set(); } } @@ -3773,7 +3773,7 @@ START_API_FUNC device->UpdateSize = (device->UpdateSize*freq + device->Frequency/2) / device->Frequency; device->BufferSize = (device->BufferSize*freq + device->Frequency/2) / device->Frequency; device->Frequency = freq; - device->Flags.set(FrequencyRequest); + device->Flags.set(); } ConfigValueUInt(deviceName, nullptr, "period_size", &device->UpdateSize); @@ -3887,9 +3887,9 @@ START_API_FUNC ReleaseContext(ctx, device); ctx = next; } - if(device->Flags.get(DeviceRunning)) + if(device->Flags.get()) device->Backend->stop(); - device->Flags.unset(DeviceRunning); + device->Flags.unset(); statelock.unlock(); ALCdevice_DecRef(device); @@ -3930,7 +3930,7 @@ START_API_FUNC alcSetError(nullptr, ALC_INVALID_ENUM); return nullptr; } - device->Flags.set(FrequencyRequest, ChannelsRequest, SampleTypeRequest); + device->Flags.set(); device->UpdateSize = samples; device->BufferSize = samples; @@ -3987,9 +3987,9 @@ START_API_FUNC listlock.unlock(); { std::lock_guard _{device->StateLock}; - if(device->Flags.get(DeviceRunning)) + if(device->Flags.get()) device->Backend->stop(); - device->Flags.unset(DeviceRunning); + device->Flags.unset(); } ALCdevice_DecRef(device); @@ -4011,10 +4011,10 @@ START_API_FUNC std::lock_guard _{dev->StateLock}; if(!dev->Connected.load(std::memory_order_acquire)) alcSetError(dev.get(), ALC_INVALID_DEVICE); - else if(!dev->Flags.get(DeviceRunning)) + else if(!dev->Flags.get()) { if(dev->Backend->start()) - dev->Flags.set(DeviceRunning); + dev->Flags.set(); else { aluHandleDisconnect(dev.get(), "Device start failure"); @@ -4033,9 +4033,9 @@ START_API_FUNC else { std::lock_guard _{dev->StateLock}; - if(dev->Flags.get(DeviceRunning)) + if(dev->Flags.get()) dev->Backend->stop(); - dev->Flags.unset(DeviceRunning); + dev->Flags.unset(); } } END_API_FUNC @@ -4197,10 +4197,10 @@ START_API_FUNC else { std::lock_guard _{dev->StateLock}; - if(dev->Flags.get(DeviceRunning)) + if(dev->Flags.get()) dev->Backend->stop(); - dev->Flags.unset(DeviceRunning); - dev->Flags.set(DevicePaused); + dev->Flags.unset(); + dev->Flags.set(); } } END_API_FUNC @@ -4220,9 +4220,9 @@ START_API_FUNC } std::lock_guard _{dev->StateLock}; - if(!dev->Flags.get(DevicePaused)) + if(!dev->Flags.get()) return; - dev->Flags.unset(DevicePaused); + dev->Flags.unset(); if(dev->ContextList.load() == nullptr) return; @@ -4232,7 +4232,7 @@ START_API_FUNC alcSetError(dev.get(), ALC_INVALID_DEVICE); return; } - dev->Flags.set(DeviceRunning); + dev->Flags.set(); } END_API_FUNC @@ -4289,9 +4289,9 @@ START_API_FUNC /* Force the backend to stop mixing first since we're resetting. Also reset * the connected state so lost devices can attempt recover. */ - if(dev->Flags.get(DeviceRunning)) + if(dev->Flags.get()) dev->Backend->stop(); - dev->Flags.unset(DeviceRunning); + dev->Flags.unset(); device->Connected.store(true); ALCenum err{UpdateDeviceParams(dev.get(), attribs)}; diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index 1c0d7489..ebdc6129 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -725,7 +725,7 @@ ALCboolean AlsaPlayback::reset() CHECK(snd_pcm_hw_params_set_channels(mPcmHandle, hp, mDevice->channelsFromFmt())); /* set rate (implicitly constrains period/buffer parameters) */ if(!GetConfigValueBool(mDevice->DeviceName.c_str(), "alsa", "allow-resampler", 0) || - !mDevice->Flags.get(FrequencyRequest)) + !mDevice->Flags.get()) { if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp, 0) < 0) ERR("Failed to disable ALSA resampler\n"); diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 480d9a18..93de3135 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -359,7 +359,7 @@ ALCboolean DSoundPlayback::reset() mDevice->FmtType = DevFmtUByte; break; case DevFmtFloat: - if(mDevice->Flags.get(SampleTypeRequest)) + if(mDevice->Flags.get()) break; /* fall-through */ case DevFmtUShort: @@ -380,7 +380,7 @@ ALCboolean DSoundPlayback::reset() if(SUCCEEDED(hr)) { speakers = DSSPEAKER_CONFIG(speakers); - if(!mDevice->Flags.get(ChannelsRequest)) + if(!mDevice->Flags.get()) { if(speakers == DSSPEAKER_MONO) mDevice->FmtChans = DevFmtMono; diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 37495abe..be483338 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -361,7 +361,7 @@ ALCboolean OpenSLPlayback::reset() mRing = nullptr; #if 0 - if(!mDevice->Flags.get(FrequencyRequest)) + if(!mDevice->Flags.get()) { /* FIXME: Disabled until I figure out how to get the Context needed for * the getSystemService call. diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 0b7257d1..6d4f387c 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -779,7 +779,7 @@ void PulsePlayback::sinkInfoCallback(pa_context* UNUSED(context), const pa_sink_ ); if(chanmap != chanmaps.cend()) { - if(!mDevice->Flags.get(ChannelsRequest)) + if(!mDevice->Flags.get()) mDevice->FmtChans = chanmap->chans; } else @@ -910,7 +910,7 @@ ALCboolean PulsePlayback::reset() flags |= PA_STREAM_ADJUST_LATENCY; } if(GetConfigValueBool(mDevice->DeviceName.c_str(), "pulse", "fix-rate", 0) || - !mDevice->Flags.get(FrequencyRequest)) + !mDevice->Flags.get()) flags |= PA_STREAM_FIX_RATE; pa_channel_map chanmap{}; diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 6c3dc6e6..84e85fe6 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -787,9 +787,9 @@ HRESULT WasapiPlayback::resetProxy() const REFERENCE_TIME per_time{mDevice->UpdateSize * REFTIME_PER_SEC / mDevice->Frequency}; const REFERENCE_TIME buf_time{mDevice->BufferSize * REFTIME_PER_SEC / mDevice->Frequency}; - if(!mDevice->Flags.get(FrequencyRequest)) + if(!mDevice->Flags.get()) mDevice->Frequency = OutputType.Format.nSamplesPerSec; - if(!mDevice->Flags.get(ChannelsRequest)) + if(!mDevice->Flags.get()) { if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) mDevice->FmtChans = DevFmtMono; diff --git a/common/albyte.h b/common/albyte.h index 8257560e..f95b92d7 100644 --- a/common/albyte.h +++ b/common/albyte.h @@ -73,18 +73,30 @@ class bitfield { byte vals[NumElems]{}; public: - void set(size_t b) noexcept { vals[b/bits_per_byte] |= 1 << (b%bits_per_byte); } - void unset(size_t b) noexcept { vals[b/bits_per_byte] &= ~(1 << (b%bits_per_byte)); } - bool get(size_t b) const noexcept - { return (vals[b/bits_per_byte] & (1 << (b%bits_per_byte))) != byte{}; } + template + inline void set() noexcept + { + static_assert(b < N, "Bit index out of range"); + vals[b/bits_per_byte] |= 1 << (b%bits_per_byte); + } + template + inline void unset() noexcept + { + static_assert(b < N, "Bit index out of range"); + vals[b/bits_per_byte] &= ~(1 << (b%bits_per_byte)); + } + template + inline bool get() const noexcept + { + static_assert(b < N, "Bit index out of range"); + return (vals[b/bits_per_byte] & (1 << (b%bits_per_byte))) != byte{}; + } - template 0)> - void set(size_t b, Args ...args) noexcept + template 0)> + void set() noexcept { - set(b); - /* Trick for calling set() on each element of the parameter pack. */ - using CharArray = char[sizeof...(Args)]; - (void)(CharArray{ (set(args),'\0')... }); + set(); + set(); } }; -- cgit v1.2.3 From bc8f206ee1361ec4b6e740a458bb7985bb7d1429 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 9 Jun 2019 18:13:54 -0700 Subject: Use a FlexArray for the context's voices --- Alc/alc.cpp | 145 ++++++++++++++++------------------------------ Alc/alcontext.h | 5 +- Alc/alu.cpp | 42 ++++++-------- OpenAL32/Include/alMain.h | 2 +- OpenAL32/Include/alu.h | 42 +++++++++++++- OpenAL32/alSource.cpp | 59 ++++++++++--------- common/almalloc.h | 2 +- 7 files changed, 143 insertions(+), 154 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 0724f0ce..10c093d5 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2141,18 +2141,37 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) vprops = next; } - AllocateVoices(context, context->MaxVoices, old_sends); - auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed); - std::for_each(context->Voices, voices_end, - [device](ALvoice *voice) -> void + auto voices = context->Voices.get(); + auto voices_end = voices->begin() + context->VoiceCount.load(std::memory_order_relaxed); + if(device->NumAuxSends < old_sends) + { + const ALsizei num_sends{device->NumAuxSends}; + /* Clear extraneous property set sends. */ + auto clear_sends = [num_sends](ALvoice &voice) -> void + { + std::fill(std::begin(voice.mProps.Send)+num_sends, std::end(voice.mProps.Send), + ALvoiceProps::SendData{}); + + std::fill(voice.mSend.begin()+num_sends, voice.mSend.end(), ALvoice::SendData{}); + auto clear_chan_sends = [num_sends](ALvoice::ChannelData &chandata) -> void + { + std::fill(chandata.mWetParams.begin()+num_sends, chandata.mWetParams.end(), + SendParams{}); + }; + std::for_each(voice.mChans.begin(), voice.mChans.end(), clear_chan_sends); + }; + std::for_each(voices->begin(), voices_end, clear_sends); + } + std::for_each(voices->begin(), voices_end, + [device](ALvoice &voice) -> void { - delete voice->mUpdate.exchange(nullptr, std::memory_order_acq_rel); + delete voice.mUpdate.exchange(nullptr, std::memory_order_acq_rel); /* Force the voice to stopped if it was stopping. */ ALvoice::State vstate{ALvoice::Stopping}; - voice->mPlayState.compare_exchange_strong(vstate, ALvoice::Stopped, + voice.mPlayState.compare_exchange_strong(vstate, ALvoice::Stopped, std::memory_order_acquire, std::memory_order_acquire); - if(voice->mSourceID.load(std::memory_order_relaxed) == 0u) + if(voice.mSourceID.load(std::memory_order_relaxed) == 0u) return; if(device->AvgSpeakerDist > 0.0f) @@ -2162,7 +2181,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) (device->AvgSpeakerDist * device->Frequency)}; auto init_nfc = [w1](ALvoice::ChannelData &chandata) -> void { chandata.mDryParams.NFCtrlFilter.init(w1); }; - std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, + std::for_each(voice.mChans.begin(), voice.mChans.begin()+voice.mNumChannels, init_nfc); } } @@ -2430,11 +2449,8 @@ ALCcontext::~ALCcontext() } TRACE("Freed %zu voice property object%s\n", count, (count==1)?"":"s"); - std::for_each(Voices, Voices + MaxVoices, DeinitVoice); - al_free(Voices); Voices = nullptr; VoiceCount.store(0, std::memory_order_relaxed); - MaxVoices = 0; ALlistenerProps *lprops{Listener.Update.exchange(nullptr, std::memory_order_relaxed)}; if(lprops) @@ -2576,109 +2592,46 @@ ContextRef GetContextRef(void) } -void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) +void AllocateVoices(ALCcontext *context, size_t num_voices) { ALCdevice *device{context->Device}; const ALsizei num_sends{device->NumAuxSends}; - if(num_voices == context->MaxVoices && num_sends == old_sends) + if(context->Voices && num_voices == context->Voices->size()) return; - /* Allocate the voice pointers, voices, and the voices' stored source - * property set (including the dynamically-sized Send[] array) in one - * chunk. - */ - const size_t sizeof_voice{RoundUp(sizeof(ALvoice), 16)}; - const size_t size{sizeof(ALvoice*) + sizeof_voice}; - - auto voices = static_cast(al_calloc(16, RoundUp(size*num_voices, 16))); - auto voice = reinterpret_cast(reinterpret_cast(voices) + RoundUp(num_voices*sizeof(ALvoice*), 16)); + std::unique_ptr> voices; + { + void *ptr{al_calloc(16, al::FlexArray::Sizeof(num_voices))}; + voices.reset(new (ptr) al::FlexArray{num_voices}); + } - auto viter = voices; + const ALsizei v_count{mini(context->VoiceCount.load(std::memory_order_relaxed), num_voices)}; if(context->Voices) { - const ALsizei v_count = mini(context->VoiceCount.load(std::memory_order_relaxed), - num_voices); - const ALsizei s_count = mini(old_sends, num_sends); - /* Copy the old voice data to the new storage. */ - auto copy_voice = [&voice,s_count](ALvoice *old_voice) -> ALvoice* - { - voice = new (voice) ALvoice{}; - - /* Make sure the old voice's Update (if any) is cleared so it - * doesn't get deleted on deinit. - */ - voice->mUpdate.store(old_voice->mUpdate.exchange(nullptr, std::memory_order_relaxed), - std::memory_order_relaxed); + auto viter = std::move(context->Voices->begin(), context->Voices->begin()+v_count, + voices->begin()); - voice->mSourceID.store(old_voice->mSourceID.load(std::memory_order_relaxed), - std::memory_order_relaxed); - voice->mPlayState.store(old_voice->mPlayState.load(std::memory_order_relaxed), - std::memory_order_relaxed); - - voice->mProps = old_voice->mProps; - /* Clear extraneous property set sends. */ - std::fill(std::begin(voice->mProps.Send)+s_count, std::end(voice->mProps.Send), + /* Clear extraneous property set sends. */ + auto clear_sends = [num_sends](ALvoice &voice) -> void + { + std::fill(std::begin(voice.mProps.Send)+num_sends, std::end(voice.mProps.Send), ALvoiceProps::SendData{}); - voice->mPosition.store(old_voice->mPosition.load(std::memory_order_relaxed), - std::memory_order_relaxed); - voice->mPositionFrac.store(old_voice->mPositionFrac.load(std::memory_order_relaxed), - std::memory_order_relaxed); - - voice->mCurrentBuffer.store(old_voice->mCurrentBuffer.load(std::memory_order_relaxed), - std::memory_order_relaxed); - voice->mLoopBuffer.store(old_voice->mLoopBuffer.load(std::memory_order_relaxed), - std::memory_order_relaxed); - - voice->mFrequency = old_voice->mFrequency; - voice->mFmtChannels = old_voice->mFmtChannels; - voice->mNumChannels = old_voice->mNumChannels; - voice->mSampleSize = old_voice->mSampleSize; - - voice->mStep = old_voice->mStep; - voice->mResampler = old_voice->mResampler; - - voice->mResampleState = old_voice->mResampleState; - - voice->mFlags = old_voice->mFlags; - - voice->mDirect = old_voice->mDirect; - voice->mSend = old_voice->mSend; - voice->mChans = old_voice->mChans; - - /* Clear old send data/params. */ - std::fill(voice->mSend.begin()+s_count, voice->mSend.end(), ALvoice::SendData{}); - auto clear_chan_sends = [s_count](ALvoice::ChannelData &chandata) -> void + std::fill(voice.mSend.begin()+num_sends, voice.mSend.end(), ALvoice::SendData{}); + auto clear_chan_sends = [num_sends](ALvoice::ChannelData &chandata) -> void { - std::fill(chandata.mWetParams.begin()+s_count, chandata.mWetParams.end(), + std::fill(chandata.mWetParams.begin()+num_sends, chandata.mWetParams.end(), SendParams{}); }; - std::for_each(voice->mChans.begin(), voice->mChans.end(), clear_chan_sends); - - /* Set this voice's reference. */ - ALvoice *ret{voice++}; - return ret; + std::for_each(voice.mChans.begin(), voice.mChans.end(), clear_chan_sends); }; - viter = std::transform(context->Voices, context->Voices+v_count, viter, copy_voice); - - /* Deinit old voices. */ - auto voices_end = context->Voices + context->MaxVoices; - std::for_each(context->Voices, voices_end, DeinitVoice); + std::for_each(voices->begin(), viter, clear_sends); } - /* Finish setting the voices and references. */ - auto init_voice = [&voice]() -> ALvoice* - { - ALvoice *ret{new (voice++) ALvoice{}}; - return ret; - }; - std::generate(viter, voices+num_voices, init_voice); - al_free(context->Voices); - context->Voices = voices; - context->MaxVoices = num_voices; - context->VoiceCount = mini(context->VoiceCount.load(std::memory_order_relaxed), num_voices); + context->Voices = std::move(voices); + context->VoiceCount.store(v_count, std::memory_order_relaxed); } @@ -3439,7 +3392,7 @@ START_API_FUNC return nullptr; } - AllocateVoices(context.get(), 256, dev->NumAuxSends); + AllocateVoices(context.get(), 256); if(DefaultEffect.type != AL_EFFECT_NULL && dev->Type == Playback) { diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 769847f8..63983ca3 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -18,6 +18,7 @@ #include "alnumeric.h" #include "alListener.h" +#include "alu.h" struct ALsource; @@ -26,7 +27,6 @@ struct ALcontextProps; struct ALlistenerProps; struct ALvoiceProps; struct ALeffectslotProps; -struct ALvoice; struct RingBuffer; enum class DistanceModel { @@ -116,9 +116,8 @@ struct ALCcontext { std::atomic FreeVoiceProps{nullptr}; std::atomic FreeEffectslotProps{nullptr}; - ALvoice **Voices{nullptr}; + std::unique_ptr> Voices{nullptr}; std::atomic VoiceCount{0}; - ALsizei MaxVoices{0}; using ALeffectslotArray = al::FlexArray; std::atomic ActiveAuxSlots{nullptr}; diff --git a/Alc/alu.cpp b/Alc/alu.cpp index e570c2ad..05a6970c 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -177,13 +177,6 @@ void aluInit(void) } -void DeinitVoice(ALvoice *voice) noexcept -{ - delete voice->mUpdate.exchange(nullptr, std::memory_order_acq_rel); - al::destroy_at(voice); -} - - void aluSelectPostProcess(ALCdevice *device) { if(device->mHrtf) @@ -1359,11 +1352,12 @@ void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray *slots) { return CalcEffectSlotParams(slot, ctx, cforce) | force; } ); - std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire), - [ctx,force](ALvoice *voice) -> void + std::for_each(ctx->Voices->begin(), + ctx->Voices->begin() + ctx->VoiceCount.load(std::memory_order_acquire), + [ctx,force](ALvoice &voice) -> void { - ALuint sid{voice->mSourceID.load(std::memory_order_acquire)}; - if(sid) CalcSourceParams(voice, ctx, force); + ALuint sid{voice.mSourceID.load(std::memory_order_acquire)}; + if(sid) CalcSourceParams(&voice, ctx, force); } ); } @@ -1389,15 +1383,16 @@ void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) ); /* Process voices that have a playing source. */ - std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire), - [SamplesToDo,ctx](ALvoice *voice) -> void + std::for_each(ctx->Voices->begin(), + ctx->Voices->begin() + ctx->VoiceCount.load(std::memory_order_acquire), + [SamplesToDo,ctx](ALvoice &voice) -> void { - const ALvoice::State vstate{voice->mPlayState.load(std::memory_order_acquire)}; + const ALvoice::State vstate{voice.mPlayState.load(std::memory_order_acquire)}; if(vstate == ALvoice::Stopped) return; - const ALuint sid{voice->mSourceID.load(std::memory_order_relaxed)}; - if(voice->mStep < 1) return; + const ALuint sid{voice.mSourceID.load(std::memory_order_relaxed)}; + if(voice.mStep < 1) return; - MixVoice(voice, vstate, sid, ctx, SamplesToDo); + MixVoice(&voice, vstate, sid, ctx, SamplesToDo); } ); @@ -1788,14 +1783,15 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) } } - auto stop_voice = [](ALvoice *voice) -> void + auto stop_voice = [](ALvoice &voice) -> void { - voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed); - voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); - voice->mSourceID.store(0u, std::memory_order_relaxed); - voice->mPlayState.store(ALvoice::Stopped, std::memory_order_release); + voice.mCurrentBuffer.store(nullptr, std::memory_order_relaxed); + voice.mLoopBuffer.store(nullptr, std::memory_order_relaxed); + voice.mSourceID.store(0u, std::memory_order_relaxed); + voice.mPlayState.store(ALvoice::Stopped, std::memory_order_release); }; - std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire), + std::for_each(ctx->Voices->begin(), + ctx->Voices->begin() + ctx->VoiceCount.load(std::memory_order_acquire), stop_voice); ctx = ctx->next.load(std::memory_order_relaxed); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 9a5b3814..80167417 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -532,7 +532,7 @@ struct AsyncEvent { }; -void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends); +void AllocateVoices(ALCcontext *context, size_t num_voices); extern ALint RTPrioLevel; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 3e18f857..3135f8fd 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -278,10 +278,48 @@ struct ALvoice { ALvoice() = default; ALvoice(const ALvoice&) = delete; + ~ALvoice() { delete mUpdate.exchange(nullptr, std::memory_order_acq_rel); } ALvoice& operator=(const ALvoice&) = delete; -}; + ALvoice& operator=(ALvoice&& rhs) noexcept + { + ALvoiceProps *old_update{mUpdate.load(std::memory_order_relaxed)}; + mUpdate.store(rhs.mUpdate.exchange(old_update, std::memory_order_relaxed), + std::memory_order_relaxed); + + mSourceID.store(rhs.mSourceID.load(std::memory_order_relaxed), std::memory_order_relaxed); + mPlayState.store(rhs.mPlayState.load(std::memory_order_relaxed), + std::memory_order_relaxed); + + mProps = rhs.mProps; + + mPosition.store(rhs.mPosition.load(std::memory_order_relaxed), std::memory_order_relaxed); + mPositionFrac.store(rhs.mPositionFrac.load(std::memory_order_relaxed), + std::memory_order_relaxed); + + mCurrentBuffer.store(rhs.mCurrentBuffer.load(std::memory_order_relaxed), + std::memory_order_relaxed); + mLoopBuffer.store(rhs.mLoopBuffer.load(std::memory_order_relaxed), + std::memory_order_relaxed); + + mFmtChannels = rhs.mFmtChannels; + mFrequency = rhs.mFrequency; + mNumChannels = rhs.mNumChannels; + mSampleSize = rhs.mSampleSize; -void DeinitVoice(ALvoice *voice) noexcept; + mStep = rhs.mStep; + mResampler = rhs.mResampler; + + mResampleState = rhs.mResampleState; + + mFlags = rhs.mFlags; + + mDirect = rhs.mDirect; + mSend = rhs.mSend; + mChans = rhs.mChans; + + return *this; + } +}; using MixerFunc = void(*)(const ALfloat *data, const al::span OutBuffer, diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index b2878b8e..9fba7e4f 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -61,9 +61,9 @@ inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) if(idx >= 0 && idx < context->VoiceCount.load(std::memory_order_relaxed)) { ALuint sid{source->id}; - ALvoice *voice{context->Voices[idx]}; - if(voice->mSourceID.load(std::memory_order_acquire) == sid) - return voice; + ALvoice &voice = (*context->Voices)[idx]; + if(voice.mSourceID.load(std::memory_order_acquire) == sid) + return &voice; } source->VoiceIdx = -1; return nullptr; @@ -2777,12 +2777,13 @@ START_API_FUNC } /* Count the number of reusable voices. */ - auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed); - auto free_voices = std::accumulate(context->Voices, voices_end, ALsizei{0}, - [](const ALsizei count, const ALvoice *voice) noexcept -> ALsizei + auto voices_end = context->Voices->begin() + + context->VoiceCount.load(std::memory_order_relaxed); + auto free_voices = std::accumulate(context->Voices->begin(), voices_end, ALsizei{0}, + [](const ALsizei count, const ALvoice &voice) noexcept -> ALsizei { - if(voice->mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && - voice->mSourceID.load(std::memory_order_relaxed) == 0u) + if(voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && + voice.mSourceID.load(std::memory_order_relaxed) == 0u) return count + 1; return count; } @@ -2790,20 +2791,21 @@ START_API_FUNC if(UNLIKELY(n > free_voices)) { /* Increment the number of voices to handle the request. */ - const ALsizei need_voices{n - free_voices}; - const ALsizei rem_voices{context->MaxVoices - + const ALuint need_voices{static_cast(n) - free_voices}; + const size_t rem_voices{context->Voices->size() - context->VoiceCount.load(std::memory_order_relaxed)}; if(UNLIKELY(need_voices > rem_voices)) { /* Allocate more voices to get enough. */ - const ALsizei alloc_count{need_voices - rem_voices}; - if(UNLIKELY(context->MaxVoices > std::numeric_limits::max()-alloc_count)) + const size_t alloc_count{need_voices - rem_voices}; + if(UNLIKELY(context->Voices->size() > std::numeric_limits::max()-alloc_count)) SETERR_RETURN(context.get(), AL_OUT_OF_MEMORY,, - "Overflow increasing voice count to %d + %d", context->MaxVoices, alloc_count); + "Overflow increasing voice count to %zu + %zu", context->Voices->size(), + alloc_count); - const ALsizei newcount{context->MaxVoices + alloc_count}; - AllocateVoices(context.get(), newcount, device->NumAuxSends); + const size_t newcount{context->Voices->size() + alloc_count}; + AllocateVoices(context.get(), newcount); } context->VoiceCount.fetch_add(need_voices, std::memory_order_relaxed); @@ -2862,17 +2864,17 @@ START_API_FUNC } /* Look for an unused voice to play this source with. */ - auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed); - auto voice_iter = std::find_if(context->Voices, voices_end, - [](const ALvoice *voice) noexcept -> bool + auto voices_end = context->Voices->begin() + + context->VoiceCount.load(std::memory_order_relaxed); + voice = std::find_if(context->Voices->begin(), voices_end, + [](const ALvoice &voice) noexcept -> bool { - return voice->mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && - voice->mSourceID.load(std::memory_order_relaxed) == 0u; + return voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && + voice.mSourceID.load(std::memory_order_relaxed) == 0u; } ); - assert(voice_iter != voices_end); - auto vidx = static_cast(std::distance(context->Voices, voice_iter)); - voice = *voice_iter; + assert(voice != voices_end); + auto vidx = static_cast(std::distance(context->Voices->begin(), voice)); voice->mPlayState.store(ALvoice::Stopped, std::memory_order_release); source->PropsClean.test_and_set(std::memory_order_acquire); @@ -3557,14 +3559,15 @@ ALsource::~ALsource() void UpdateAllSourceProps(ALCcontext *context) { - auto voices_end = context->Voices + context->VoiceCount.load(std::memory_order_relaxed); - std::for_each(context->Voices, voices_end, - [context](ALvoice *voice) -> void + auto voices_end = context->Voices->begin() + + context->VoiceCount.load(std::memory_order_relaxed); + std::for_each(context->Voices->begin(), voices_end, + [context](ALvoice &voice) -> void { - ALuint sid{voice->mSourceID.load(std::memory_order_acquire)}; + ALuint sid{voice.mSourceID.load(std::memory_order_acquire)}; ALsource *source = sid ? LookupSource(context, sid) : nullptr; if(source && !source->PropsClean.test_and_set(std::memory_order_acq_rel)) - UpdateSourceProps(source, voice, context); + UpdateSourceProps(source, &voice, context); } ); } diff --git a/common/almalloc.h b/common/almalloc.h index d50aa1dd..4bf3a281 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -175,7 +175,7 @@ struct FlexArray { const index_type mSize; - alignas(alignment) element_type mArray[]; + alignas(alignment) element_type mArray[0]; static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept { -- cgit v1.2.3 From ec6fdff0c68e883908039e396cd68883ee263684 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 9 Jun 2019 19:27:15 -0700 Subject: Make the voice count unsigned --- Alc/alc.cpp | 4 ++-- Alc/alcontext.h | 2 +- OpenAL32/alSource.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 10c093d5..99966853 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2606,7 +2606,7 @@ void AllocateVoices(ALCcontext *context, size_t num_voices) voices.reset(new (ptr) al::FlexArray{num_voices}); } - const ALsizei v_count{mini(context->VoiceCount.load(std::memory_order_relaxed), num_voices)}; + const size_t v_count{minz(context->VoiceCount.load(std::memory_order_relaxed), num_voices)}; if(context->Voices) { /* Copy the old voice data to the new storage. */ @@ -2631,7 +2631,7 @@ void AllocateVoices(ALCcontext *context, size_t num_voices) } context->Voices = std::move(voices); - context->VoiceCount.store(v_count, std::memory_order_relaxed); + context->VoiceCount.store(static_cast(v_count), std::memory_order_relaxed); } diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 63983ca3..1887e341 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -117,7 +117,7 @@ struct ALCcontext { std::atomic FreeEffectslotProps{nullptr}; std::unique_ptr> Voices{nullptr}; - std::atomic VoiceCount{0}; + std::atomic VoiceCount{0u}; using ALeffectslotArray = al::FlexArray; std::atomic ActiveAuxSlots{nullptr}; diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 9fba7e4f..3404cbf2 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -58,7 +58,7 @@ using namespace std::placeholders; inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) { ALint idx{source->VoiceIdx}; - if(idx >= 0 && idx < context->VoiceCount.load(std::memory_order_relaxed)) + if(idx >= 0 && static_cast(idx) < context->VoiceCount.load(std::memory_order_relaxed)) { ALuint sid{source->id}; ALvoice &voice = (*context->Voices)[idx]; @@ -2799,7 +2799,7 @@ START_API_FUNC { /* Allocate more voices to get enough. */ const size_t alloc_count{need_voices - rem_voices}; - if(UNLIKELY(context->Voices->size() > std::numeric_limits::max()-alloc_count)) + if(UNLIKELY(context->Voices->size() > std::numeric_limits::max()-alloc_count)) SETERR_RETURN(context.get(), AL_OUT_OF_MEMORY,, "Overflow increasing voice count to %zu + %zu", context->Voices->size(), alloc_count); -- cgit v1.2.3 From 8bb42c2f9827d051d5bfb41ebdce5ac62454e620 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 10 Jun 2019 01:51:14 -0700 Subject: Don't inline some file IO methods --- Alc/compat.h | 135 +++++--------------------------------------------------- Alc/helpers.cpp | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+), 125 deletions(-) diff --git a/Alc/compat.h b/Alc/compat.h index dc652bca..2e0ad1e7 100644 --- a/Alc/compat.h +++ b/Alc/compat.h @@ -54,115 +54,18 @@ class filebuf final : public std::streambuf { std::array mBuffer; HANDLE mFile{INVALID_HANDLE_VALUE}; - int_type underflow() override - { - if(mFile != INVALID_HANDLE_VALUE && gptr() == egptr()) - { - // Read in the next chunk of data, and set the pointers on success - DWORD got = 0; - if(ReadFile(mFile, mBuffer.data(), (DWORD)mBuffer.size(), &got, nullptr)) - setg(mBuffer.data(), mBuffer.data(), mBuffer.data()+got); - } - if(gptr() == egptr()) - return traits_type::eof(); - return traits_type::to_int_type(*gptr()); - } - - pos_type seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) override - { - if(mFile == INVALID_HANDLE_VALUE || (mode&std::ios_base::out) || !(mode&std::ios_base::in)) - return traits_type::eof(); - - LARGE_INTEGER fpos; - switch(whence) - { - case std::ios_base::beg: - fpos.QuadPart = offset; - if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_BEGIN)) - return traits_type::eof(); - break; - - case std::ios_base::cur: - // If the offset remains in the current buffer range, just - // update the pointer. - if((offset >= 0 && offset < off_type(egptr()-gptr())) || - (offset < 0 && -offset <= off_type(gptr()-eback()))) - { - // Get the current file offset to report the correct read - // offset. - fpos.QuadPart = 0; - if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_CURRENT)) - return traits_type::eof(); - setg(eback(), gptr()+offset, egptr()); - return fpos.QuadPart - off_type(egptr()-gptr()); - } - // Need to offset for the file offset being at egptr() while - // the requested offset is relative to gptr(). - offset -= off_type(egptr()-gptr()); - fpos.QuadPart = offset; - if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_CURRENT)) - return traits_type::eof(); - break; - - case std::ios_base::end: - fpos.QuadPart = offset; - if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_END)) - return traits_type::eof(); - break; - - default: - return traits_type::eof(); - } - setg(nullptr, nullptr, nullptr); - return fpos.QuadPart; - } - - pos_type seekpos(pos_type pos, std::ios_base::openmode mode) override - { - // Simplified version of seekoff - if(mFile == INVALID_HANDLE_VALUE || (mode&std::ios_base::out) || !(mode&std::ios_base::in)) - return traits_type::eof(); - - LARGE_INTEGER fpos; - fpos.QuadPart = pos; - if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_BEGIN)) - return traits_type::eof(); - - setg(nullptr, nullptr, nullptr); - return fpos.QuadPart; - } + int_type underflow() override; + pos_type seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) override; + pos_type seekpos(pos_type pos, std::ios_base::openmode mode) override; public: - bool open(const wchar_t *filename, std::ios_base::openmode mode) - { - if((mode&std::ios_base::out) || !(mode&std::ios_base::in)) - return false; - HANDLE f{CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)}; - if(f == INVALID_HANDLE_VALUE) return false; - - if(mFile != INVALID_HANDLE_VALUE) - CloseHandle(mFile); - mFile = f; - - setg(nullptr, nullptr, nullptr); - return true; - } - bool open(const char *filename, std::ios_base::openmode mode) - { - std::wstring wname{utf8_to_wstr(filename)}; - return open(wname.c_str(), mode); - } + filebuf() = default; + ~filebuf() override; - bool is_open() const noexcept { return mFile != INVALID_HANDLE_VALUE; } + bool open(const wchar_t *filename, std::ios_base::openmode mode); + bool open(const char *filename, std::ios_base::openmode mode); - filebuf() = default; - ~filebuf() override - { - if(mFile != INVALID_HANDLE_VALUE) - CloseHandle(mFile); - mFile = INVALID_HANDLE_VALUE; - } + bool is_open() const noexcept { return mFile != INVALID_HANDLE_VALUE; } }; // Inherit from std::istream to use our custom streambuf @@ -170,31 +73,13 @@ class ifstream final : public std::istream { filebuf mStreamBuf; public: + ifstream(const wchar_t *filename, std::ios_base::openmode mode = std::ios_base::in); ifstream(const std::wstring &filename, std::ios_base::openmode mode = std::ios_base::in) : ifstream(filename.c_str(), mode) { } - ifstream(const wchar_t *filename, std::ios_base::openmode mode = std::ios_base::in) - : std::istream{nullptr} - { - init(&mStreamBuf); - - // Set the failbit if the file failed to open. - if((mode&std::ios_base::out) || - !mStreamBuf.open(filename, mode|std::ios_base::in)) - clear(failbit); - } + ifstream(const char *filename, std::ios_base::openmode mode = std::ios_base::in); ifstream(const std::string &filename, std::ios_base::openmode mode = std::ios_base::in) : ifstream(filename.c_str(), mode) { } - ifstream(const char *filename, std::ios_base::openmode mode = std::ios_base::in) - : std::istream{nullptr} - { - init(&mStreamBuf); - - // Set the failbit if the file failed to open. - if((mode&std::ios_base::out) || - !mStreamBuf.open(filename, mode|std::ios_base::in)) - clear(failbit); - } bool is_open() const noexcept { return mStreamBuf.is_open(); } }; diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index 813b954f..fb7addd3 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -305,6 +305,137 @@ void FPUCtl::leave() #ifdef _WIN32 +namespace al { + +auto filebuf::underflow() -> int_type +{ + if(mFile != INVALID_HANDLE_VALUE && gptr() == egptr()) + { + // Read in the next chunk of data, and set the pointers on success + DWORD got{}; + if(ReadFile(mFile, mBuffer.data(), (DWORD)mBuffer.size(), &got, nullptr)) + setg(mBuffer.data(), mBuffer.data(), mBuffer.data()+got); + } + if(gptr() == egptr()) + return traits_type::eof(); + return traits_type::to_int_type(*gptr()); +} + +auto filebuf::seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) -> pos_type +{ + if(mFile == INVALID_HANDLE_VALUE || (mode&std::ios_base::out) || !(mode&std::ios_base::in)) + return traits_type::eof(); + + LARGE_INTEGER fpos{}; + switch(whence) + { + case std::ios_base::beg: + fpos.QuadPart = offset; + if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_BEGIN)) + return traits_type::eof(); + break; + + case std::ios_base::cur: + // If the offset remains in the current buffer range, just + // update the pointer. + if((offset >= 0 && offset < off_type(egptr()-gptr())) || + (offset < 0 && -offset <= off_type(gptr()-eback()))) + { + // Get the current file offset to report the correct read + // offset. + fpos.QuadPart = 0; + if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_CURRENT)) + return traits_type::eof(); + setg(eback(), gptr()+offset, egptr()); + return fpos.QuadPart - off_type(egptr()-gptr()); + } + // Need to offset for the file offset being at egptr() while + // the requested offset is relative to gptr(). + offset -= off_type(egptr()-gptr()); + fpos.QuadPart = offset; + if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_CURRENT)) + return traits_type::eof(); + break; + + case std::ios_base::end: + fpos.QuadPart = offset; + if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_END)) + return traits_type::eof(); + break; + + default: + return traits_type::eof(); + } + setg(nullptr, nullptr, nullptr); + return fpos.QuadPart; +} + +auto filebuf::seekpos(pos_type pos, std::ios_base::openmode mode) -> pos_type +{ + // Simplified version of seekoff + if(mFile == INVALID_HANDLE_VALUE || (mode&std::ios_base::out) || !(mode&std::ios_base::in)) + return traits_type::eof(); + + LARGE_INTEGER fpos{}; + fpos.QuadPart = pos; + if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_BEGIN)) + return traits_type::eof(); + + setg(nullptr, nullptr, nullptr); + return fpos.QuadPart; +} + +filebuf::~filebuf() +{ + if(mFile != INVALID_HANDLE_VALUE) + CloseHandle(mFile); + mFile = INVALID_HANDLE_VALUE; +} + +bool filebuf::open(const wchar_t *filename, std::ios_base::openmode mode) +{ + if((mode&std::ios_base::out) || !(mode&std::ios_base::in)) + return false; + HANDLE f{CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, nullptr)}; + if(f == INVALID_HANDLE_VALUE) return false; + + if(mFile != INVALID_HANDLE_VALUE) + CloseHandle(mFile); + mFile = f; + + setg(nullptr, nullptr, nullptr); + return true; +} +bool filebuf::open(const char *filename, std::ios_base::openmode mode) +{ + std::wstring wname{utf8_to_wstr(filename)}; + return open(wname.c_str(), mode); +} + + +ifstream::ifstream(const wchar_t *filename, std::ios_base::openmode mode) + : std::istream{nullptr} +{ + init(&mStreamBuf); + + // Set the failbit if the file failed to open. + if((mode&std::ios_base::out) || !mStreamBuf.open(filename, mode|std::ios_base::in)) + clear(failbit); +} + +ifstream::ifstream(const char *filename, std::ios_base::openmode mode) + : std::istream{nullptr} +{ + init(&mStreamBuf); + + // Set the failbit if the file failed to open. + if((mode&std::ios_base::out) || !mStreamBuf.open(filename, mode|std::ios_base::in)) + clear(failbit); +} + +} // namespace al + const PathNamePair &GetProcBinary() { static PathNamePair ret; -- cgit v1.2.3 From c22d537d93a131215600373010b0d240e7b2c0df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 10 Jun 2019 21:45:33 -0700 Subject: Remove some extern "C" blocks --- Alc/alconfig.cpp | 4 ++-- Alc/alconfig.h | 12 +----------- Alc/cpu_caps.h | 7 ------- OpenAL32/Include/alError.h | 7 ------- 4 files changed, 3 insertions(+), 27 deletions(-) diff --git a/Alc/alconfig.cpp b/Alc/alconfig.cpp index c4fde638..db5251f0 100644 --- a/Alc/alconfig.cpp +++ b/Alc/alconfig.cpp @@ -285,7 +285,7 @@ void LoadConfigFromFile(std::istream &f) #ifdef _WIN32 -void ReadALConfig(void) noexcept +void ReadALConfig() { WCHAR buffer[MAX_PATH]; if(SHGetSpecialFolderPathW(nullptr, buffer, CSIDL_APPDATA, FALSE) != FALSE) @@ -321,7 +321,7 @@ void ReadALConfig(void) noexcept } } #else -void ReadALConfig(void) noexcept +void ReadALConfig() { const char *str{"/etc/openal/alsoft.conf"}; diff --git a/Alc/alconfig.h b/Alc/alconfig.h index 0e9bcec3..290172a8 100644 --- a/Alc/alconfig.h +++ b/Alc/alconfig.h @@ -1,14 +1,8 @@ #ifndef ALCONFIG_H #define ALCONFIG_H -#ifdef __cplusplus -#define NOEXCEPT noexcept -extern "C" { -#else -#define NOEXCEPT -#endif -void ReadALConfig(void) NOEXCEPT; +void ReadALConfig(); int ConfigValueExists(const char *devName, const char *blockName, const char *keyName); const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def); @@ -20,8 +14,4 @@ int ConfigValueUInt(const char *devName, const char *blockName, const char *keyN int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret); int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret); -#ifdef __cplusplus -} // extern "C" -#endif - #endif /* ALCONFIG_H */ diff --git a/Alc/cpu_caps.h b/Alc/cpu_caps.h index 1d867f37..64a4ee45 100644 --- a/Alc/cpu_caps.h +++ b/Alc/cpu_caps.h @@ -1,9 +1,6 @@ #ifndef CPU_CAPS_H #define CPU_CAPS_H -#ifdef __cplusplus -extern "C" { -#endif extern int CPUCapFlags; enum { @@ -16,8 +13,4 @@ enum { void FillCPUCaps(int capfilter); -#ifdef __cplusplus -} // extern "C" -#endif - #endif /* CPU_CAPS_H */ diff --git a/OpenAL32/Include/alError.h b/OpenAL32/Include/alError.h index 858f81de..3e4f2373 100644 --- a/OpenAL32/Include/alError.h +++ b/OpenAL32/Include/alError.h @@ -4,9 +4,6 @@ #include "alMain.h" #include "logging.h" -#ifdef __cplusplus -extern "C" { -#endif extern ALboolean TrapALError; @@ -22,8 +19,4 @@ void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) DEC return retval; \ } while(0) -#ifdef __cplusplus -} -#endif - #endif -- cgit v1.2.3 From 1a14946306a29ce2a14bf3d3f536ab24100ada83 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 10 Jun 2019 21:56:09 -0700 Subject: Get rid of an unnecessary constructor --- Alc/alconfig.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Alc/alconfig.cpp b/Alc/alconfig.cpp index db5251f0..710c790c 100644 --- a/Alc/alconfig.cpp +++ b/Alc/alconfig.cpp @@ -54,11 +54,6 @@ namespace { struct ConfigEntry { std::string key; std::string value; - - template - ConfigEntry(T0&& key_, T1&& val_) - : key{std::forward(key_)}, value{std::forward(val_)} - { } }; al::vector ConfOpts; @@ -272,7 +267,7 @@ void LoadConfigFromFile(std::istream &f) ent->value = expdup(value); else { - ConfOpts.emplace_back(std::move(fullKey), expdup(value)); + ConfOpts.emplace_back(ConfigEntry{std::move(fullKey), expdup(value)}); ent = ConfOpts.end()-1; } -- cgit v1.2.3 From 97d56dd4243e1e16bef4e337e570022f170af118 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 10 Jun 2019 22:29:58 -0700 Subject: Use C++ I/O to check for NEON support --- Alc/helpers.cpp | 46 ++++++++++++++++++---------------------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index fb7addd3..9236e57a 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -206,45 +206,35 @@ void FillCPUCaps(int capfilter) #endif #endif #ifdef HAVE_NEON - FILE *file = fopen("/proc/cpuinfo", "rt"); - if(!file) + al::ifstream file{"/proc/cpuinfo"}; + if(!file.is_open()) ERR("Failed to open /proc/cpuinfo, cannot check for NEON support\n"); else { std::string features; - char buf[256]; - while(fgets(buf, sizeof(buf), file) != nullptr) + auto getline = [](std::istream &f, std::string &output) -> bool { - if(strncmp(buf, "Features\t:", 10) != 0) - continue; + while(f.good() && f.peek() == '\n') + f.ignore(); + return std::getline(f, output) && !output.empty(); - features = buf+10; - while(features.back() != '\n') - { - if(fgets(buf, sizeof(buf), file) == nullptr) - break; - features += buf; - } - break; + }; + while(getline(file, features)) + { + if(features.compare(0, 10, "Features\t:", 10) == 0) + break; } - fclose(file); - file = nullptr; + file.close(); - if(!features.empty()) + size_t extpos{9}; + while((extpos=features.find("neon", extpos+1)) != std::string::npos) { - const char *str = features.c_str(); - while(isspace(str[0])) ++str; - - TRACE("Got features string:%s\n", str); - while((str=strstr(str, "neon")) != nullptr) + if((extpos == 0 || std::isspace(features[extpos-1])) && + (extpos+4 == features.length() || std::isspace(features[extpos+4]))) { - if(isspace(*(str-1)) && (str[4] == 0 || isspace(str[4]))) - { - caps |= CPU_CAP_NEON; - break; - } - ++str; + caps |= CPU_CAP_NEON; + break; } } } -- cgit v1.2.3 From a478fd4b2506ab5105c7e759762786a9f855cf3e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 11 Jun 2019 14:59:06 -0700 Subject: Fix unsigned short/int sample converters And add const/noexcept in some places --- Alc/converter.cpp | 53 ++++++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/Alc/converter.cpp b/Alc/converter.cpp index 5535fd42..a6a5f2c4 100644 --- a/Alc/converter.cpp +++ b/Alc/converter.cpp @@ -15,27 +15,28 @@ namespace { * chokes on that given the inline specializations. */ template -inline ALfloat LoadSample(typename DevFmtTypeTraits::Type val); +inline ALfloat LoadSample(typename DevFmtTypeTraits::Type val) noexcept; -template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept { return val * (1.0f/128.0f); } -template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept { return val * (1.0f/32768.0f); } -template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept { return val * (1.0f/2147483648.0f); } -template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept { return val; } -template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept { return LoadSample(val - 128); } -template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) -{ return LoadSample(val - 32768); } -template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) -{ return LoadSample(val - 2147483648u); } +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept +{ return LoadSample(val - 32768); } +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept +{ return LoadSample(val - 2147483648u); } template -inline void LoadSampleArray(ALfloat *RESTRICT dst, const void *src, size_t srcstep, ALsizei samples) +inline void LoadSampleArray(ALfloat *RESTRICT dst, const void *src, const size_t srcstep, + const ALsizei samples) noexcept { using SampleType = typename DevFmtTypeTraits::Type; @@ -44,7 +45,8 @@ inline void LoadSampleArray(ALfloat *RESTRICT dst, const void *src, size_t srcst dst[i] = LoadSample(ssrc[i*srcstep]); } -void LoadSamples(ALfloat *dst, const ALvoid *src, size_t srcstep, DevFmtType srctype, ALsizei samples) +void LoadSamples(ALfloat *dst, const ALvoid *src, const size_t srcstep, const DevFmtType srctype, + const ALsizei samples) noexcept { #define HANDLE_FMT(T) \ case T: LoadSampleArray(dst, src, srcstep, samples); break @@ -63,28 +65,28 @@ void LoadSamples(ALfloat *dst, const ALvoid *src, size_t srcstep, DevFmtType src template -inline typename DevFmtTypeTraits::Type StoreSample(ALfloat); +inline typename DevFmtTypeTraits::Type StoreSample(ALfloat) noexcept; -template<> inline ALfloat StoreSample(ALfloat val) +template<> inline ALfloat StoreSample(ALfloat val) noexcept { return val; } -template<> inline ALint StoreSample(ALfloat val) +template<> inline ALint StoreSample(ALfloat val) noexcept { return fastf2i(clampf(val*2147483648.0f, -2147483648.0f, 2147483520.0f)); } -template<> inline ALshort StoreSample(ALfloat val) +template<> inline ALshort StoreSample(ALfloat val) noexcept { return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); } -template<> inline ALbyte StoreSample(ALfloat val) +template<> inline ALbyte StoreSample(ALfloat val) noexcept { return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); } /* Define unsigned output variations. */ -template<> inline ALuint StoreSample(ALfloat val) +template<> inline ALuint StoreSample(ALfloat val) noexcept { return StoreSample(val) + 2147483648u; } -template<> inline ALushort StoreSample(ALfloat val) +template<> inline ALushort StoreSample(ALfloat val) noexcept { return StoreSample(val) + 32768; } -template<> inline ALubyte StoreSample(ALfloat val) +template<> inline ALubyte StoreSample(ALfloat val) noexcept { return StoreSample(val) + 128; } template -inline void StoreSampleArray(void *dst, const ALfloat *RESTRICT src, size_t dststep, - ALsizei samples) +inline void StoreSampleArray(void *dst, const ALfloat *RESTRICT src, const size_t dststep, + const ALsizei samples) noexcept { using SampleType = typename DevFmtTypeTraits::Type; @@ -94,7 +96,8 @@ inline void StoreSampleArray(void *dst, const ALfloat *RESTRICT src, size_t dsts } -void StoreSamples(ALvoid *dst, const ALfloat *src, size_t dststep, DevFmtType dsttype, ALsizei samples) +void StoreSamples(ALvoid *dst, const ALfloat *src, const size_t dststep, const DevFmtType dsttype, + const ALsizei samples) noexcept { #define HANDLE_FMT(T) \ case T: StoreSampleArray(dst, src, dststep, samples); break @@ -113,7 +116,7 @@ void StoreSamples(ALvoid *dst, const ALfloat *src, size_t dststep, DevFmtType ds template -void Mono2Stereo(ALfloat *RESTRICT dst, const void *src, ALsizei frames) +void Mono2Stereo(ALfloat *RESTRICT dst, const void *src, const ALsizei frames) noexcept { using SampleType = typename DevFmtTypeTraits::Type; @@ -123,7 +126,7 @@ void Mono2Stereo(ALfloat *RESTRICT dst, const void *src, ALsizei frames) } template -void Stereo2Mono(ALfloat *RESTRICT dst, const void *src, ALsizei frames) +void Stereo2Mono(ALfloat *RESTRICT dst, const void *src, const ALsizei frames) noexcept { using SampleType = typename DevFmtTypeTraits::Type; -- cgit v1.2.3 From a2ba230e057d76b73b221f8dc44de17253b843cf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 11 Jun 2019 22:29:39 -0700 Subject: Combine two macros into one --- common/albyte.h | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/common/albyte.h b/common/albyte.h index f95b92d7..c7f4d219 100644 --- a/common/albyte.h +++ b/common/albyte.h @@ -27,23 +27,6 @@ template::value)> inline constexpr al::byte operator>>(al::byte lhs, T rhs) noexcept { return al::byte(to_integer(lhs) >> rhs); } -#define AL_DECL_OP(op) \ -template::value)> \ -inline constexpr al::byte operator op (al::byte lhs, T rhs) noexcept \ -{ return al::byte(to_integer(lhs) op rhs); } \ -inline constexpr al::byte operator op (al::byte lhs, al::byte rhs) noexcept \ -{ return al::byte(lhs op to_integer(rhs)); } - -AL_DECL_OP(|) -AL_DECL_OP(&) -AL_DECL_OP(^) - -#undef AL_DECL_OP - -inline constexpr al::byte operator~(al::byte b) noexcept -{ return al::byte(~to_integer(b)); } - - template::value)> inline al::byte& operator<<=(al::byte &lhs, T rhs) noexcept { lhs = lhs << rhs; return lhs; } @@ -54,8 +37,13 @@ inline al::byte& operator>>=(al::byte &lhs, T rhs) noexcept #define AL_DECL_OP(op) \ template::value)> \ +inline constexpr al::byte operator op (al::byte lhs, T rhs) noexcept \ +{ return al::byte(to_integer(lhs) op rhs); } \ +template::value)> \ inline al::byte& operator op##= (al::byte &lhs, T rhs) noexcept \ { lhs = lhs op rhs; return lhs; } \ +inline constexpr al::byte operator op (al::byte lhs, al::byte rhs) noexcept \ +{ return al::byte(lhs op to_integer(rhs)); } \ inline al::byte& operator op##= (al::byte &lhs, al::byte rhs) noexcept \ { lhs = lhs op rhs; return lhs; } @@ -65,6 +53,10 @@ AL_DECL_OP(^) #undef AL_DECL_OP +inline constexpr al::byte operator~(al::byte b) noexcept +{ return al::byte(~to_integer(b)); } + + template class bitfield { static constexpr size_t bits_per_byte{std::numeric_limits::digits}; -- cgit v1.2.3 From 8670fca3dc83094cc7f58bd813cf6b5e93096bfb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 12 Jun 2019 22:51:09 -0700 Subject: Fix BS2B output --- Alc/alu.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 05a6970c..07b3ccd3 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -159,12 +159,17 @@ void ProcessUhj(ALCdevice *device, const ALsizei SamplesToDo) void ProcessBs2b(ALCdevice *device, const ALsizei SamplesToDo) { + /* First, decode the ambisonic mix to the "real" output. */ + BFormatDec *ambidec{device->AmbiDecoder.get()}; + ambidec->process(device->RealOut.Buffer, device->RealOut.NumChannels, device->Dry.Buffer, + SamplesToDo); + /* BS2B is stereo output only. */ const int lidx{device->RealOut.ChannelIndex[FrontLeft]}; const int ridx{device->RealOut.ChannelIndex[FrontRight]}; ASSUME(lidx >= 0 && ridx >= 0); - /* Apply binaural/crossfeed filter */ + /* Now apply the BS2B binaural/crossfeed filter. */ bs2b_cross_feed(device->Bs2b.get(), device->RealOut.Buffer[lidx].data(), device->RealOut.Buffer[ridx].data(), SamplesToDo); } -- cgit v1.2.3 From 0a532729baeeaaf7e8bd7d9c20105668ca38665f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Jun 2019 23:10:11 -0700 Subject: Reorganize how some device fields are set and reset --- Alc/alc.cpp | 53 +++++++++++++++++++++++++++++++++++++++++----- Alc/alu.cpp | 29 +++++++------------------ Alc/panning.cpp | 57 ++++++-------------------------------------------- OpenAL32/Include/alu.h | 5 ++++- 4 files changed, 65 insertions(+), 79 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 99966853..1299e8e2 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1810,14 +1810,21 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(device->Flags.get()) return ALC_NO_ERROR; + device->AvgSpeakerDist = 0.0f; device->Uhj_Encoder = nullptr; + device->AmbiDecoder = nullptr; device->Bs2b = nullptr; + device->PostProcess = nullptr; + device->Stablizer = nullptr; device->Limiter = nullptr; device->ChannelDelay.clear(); + device->Dry.AmbiMap.fill(BFChannelConfig{}); device->Dry.Buffer = nullptr; device->Dry.NumChannels = 0; + std::fill(std::begin(device->NumChannelsPerOrder), std::end(device->NumChannelsPerOrder), 0u); + device->RealOut.ChannelIndex.fill(-1); device->RealOut.Buffer = nullptr; device->RealOut.NumChannels = 0; device->MixBuffer.clear(); @@ -1826,6 +1833,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) UpdateClockBase(device); device->FixedLatency = nanoseconds::zero(); + device->DitherDepth = 0.0f; device->DitherSeed = DITHER_RNG_SEED; /************************************************************************* @@ -1947,10 +1955,47 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->NumAuxSends = new_sends; TRACE("Max sources: %d (%d + %d), effect slots: %d, sends: %d\n", - device->SourcesMax, device->NumMonoSources, device->NumStereoSources, - device->AuxiliaryEffectSlotMax, device->NumAuxSends); + device->SourcesMax, device->NumMonoSources, device->NumStereoSources, + device->AuxiliaryEffectSlotMax, device->NumAuxSends); + + /* Enable the stablizer only for formats that have front-left, front-right, + * and front-center outputs. + */ + switch(device->FmtChans) + { + case DevFmtX51: + case DevFmtX51Rear: + case DevFmtX61: + case DevFmtX71: + if(GetConfigValueBool(device->DeviceName.c_str(), nullptr, "front-stablizer", 0)) + { + auto stablizer = al::make_unique(); + /* Initialize band-splitting filters for the front-left and + * front-right channels, with a crossover at 5khz (could be + * higher). + */ + const ALfloat scale{static_cast(5000.0 / device->Frequency)}; + + stablizer->LFilter.init(scale); + stablizer->RFilter = stablizer->LFilter; + + device->Stablizer = std::move(stablizer); + /* NOTE: Don't know why this has to be "copied" into a local static + * constexpr variable to avoid a reference on + * FrontStablizer::DelayLength... + */ + static constexpr size_t StablizerDelay{FrontStablizer::DelayLength}; + device->FixedLatency += nanoseconds{seconds{StablizerDelay}} / device->Frequency; + } + break; + case DevFmtMono: + case DevFmtStereo: + case DevFmtQuad: + case DevFmtAmbi3D: + break; + } + TRACE("Front stablizer %s\n", device->Stablizer ? "enabled" : "disabled"); - device->DitherDepth = 0.0f; if(GetConfigValueBool(device->DeviceName.c_str(), nullptr, "dither", 1)) { ALint depth = 0; @@ -2043,8 +2088,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) TRACE("Output limiter enabled, %.4fdB limit\n", thrshld_dB); } - aluSelectPostProcess(device); - TRACE("Fixed device latency: %ldns\n", (long)device->FixedLatency.count()); /* Need to delay returning failure until replacement Send arrays have been diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 07b3ccd3..cc478a89 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -124,6 +124,13 @@ inline HrtfDirectMixerFunc SelectHrtfMixer(void) return MixDirectHrtf_; } +} // namespace + +void aluInit(void) +{ + MixDirectHrtf = SelectHrtfMixer(); +} + void ProcessHrtf(ALCdevice *device, const ALsizei SamplesToDo) { @@ -174,28 +181,6 @@ void ProcessBs2b(ALCdevice *device, const ALsizei SamplesToDo) device->RealOut.Buffer[ridx].data(), SamplesToDo); } -} // namespace - -void aluInit(void) -{ - MixDirectHrtf = SelectHrtfMixer(); -} - - -void aluSelectPostProcess(ALCdevice *device) -{ - if(device->mHrtf) - device->PostProcess = ProcessHrtf; - else if(device->AmbiDecoder) - device->PostProcess = ProcessAmbiDec; - else if(device->Uhj_Encoder) - device->PostProcess = ProcessUhj; - else if(device->Bs2b) - device->PostProcess = ProcessBs2b; - else - device->PostProcess = nullptr; -} - /* Prepares the interpolator for a given rate (determined by increment). * diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 4c899f66..41e827ef 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -754,16 +754,6 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr device->HrtfName.clear(); device->mRenderMode = NormalRender; - device->Dry.AmbiMap.fill(BFChannelConfig{}); - device->Dry.NumChannels = 0; - std::fill(std::begin(device->NumChannelsPerOrder), std::end(device->NumChannelsPerOrder), 0u); - - device->AvgSpeakerDist = 0.0f; - device->ChannelDelay.clear(); - - device->AmbiDecoder = nullptr; - device->Stablizer = nullptr; - if(device->FmtChans != DevFmtStereo) { if(old_hrtf) @@ -816,50 +806,11 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr int hqdec{GetConfigValueBool(devname, "decoder", "hq-mode", 0)}; InitCustomPanning(device, !!hqdec, pconf, speakermap); } - - /* Enable the stablizer only for formats that have front-left, front- - * right, and front-center outputs. - */ - switch(device->FmtChans) - { - case DevFmtX51: - case DevFmtX51Rear: - case DevFmtX61: - case DevFmtX71: - if(GetConfigValueBool(devname, nullptr, "front-stablizer", 0)) - { - auto stablizer = al::make_unique(); - /* Initialize band-splitting filters for the front-left and - * front-right channels, with a crossover at 5khz (could be - * higher). - */ - const ALfloat scale{static_cast(5000.0 / device->Frequency)}; - - stablizer->LFilter.init(scale); - stablizer->RFilter = stablizer->LFilter; - - device->Stablizer = std::move(stablizer); - /* NOTE: Don't know why this has to be "copied" into a local - * static constexpr variable to avoid a reference on - * FrontStablizer::DelayLength... - */ - static constexpr size_t StablizerDelay{FrontStablizer::DelayLength}; - device->FixedLatency += nanoseconds{seconds{StablizerDelay}} / device->Frequency; - } - break; - case DevFmtMono: - case DevFmtStereo: - case DevFmtQuad: - case DevFmtAmbi3D: - break; - } - TRACE("Front stablizer %s\n", device->Stablizer ? "enabled" : "disabled"); - + if(device->AmbiDecoder) + device->PostProcess = ProcessAmbiDec; return; } - device->AmbiDecoder = nullptr; - bool headphones{device->IsHeadphones != AL_FALSE}; if(device->Type != Loopback) { @@ -937,6 +888,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr old_hrtf = nullptr; InitHrtfPanning(device); + device->PostProcess = ProcessHrtf; return; } device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; @@ -958,6 +910,7 @@ no_hrtf: bs2b_set_params(device->Bs2b.get(), bs2blevel, device->Frequency); TRACE("BS2B enabled\n"); InitPanning(device); + device->PostProcess = ProcessBs2b; return; } @@ -974,11 +927,13 @@ no_hrtf: device->Uhj_Encoder = al::make_unique(); TRACE("UHJ enabled\n"); InitUhjPanning(device); + device->PostProcess = ProcessUhj; return; } TRACE("Stereo rendering\n"); InitPanning(device); + device->PostProcess = ProcessAmbiDec; } diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 3135f8fd..74c8e0d4 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -388,7 +388,10 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr void aluInitEffectPanning(ALeffectslot *slot, ALCdevice *device); -void aluSelectPostProcess(ALCdevice *device); +void ProcessHrtf(ALCdevice *device, const ALsizei SamplesToDo); +void ProcessAmbiDec(ALCdevice *device, const ALsizei SamplesToDo); +void ProcessUhj(ALCdevice *device, const ALsizei SamplesToDo); +void ProcessBs2b(ALCdevice *device, const ALsizei SamplesToDo); /** * Calculates ambisonic encoder coefficients using the X, Y, and Z direction -- cgit v1.2.3 From a009b9502a59658f4e60b4c8c6313fa5d7b6dd46 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 16 Jun 2019 18:58:56 -0700 Subject: Avoid manually looping to destroy orphaned async events --- Alc/alc.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 1299e8e2..3c59782f 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2516,22 +2516,19 @@ ALCcontext::~ALCcontext() { count = 0; auto evt_vec = AsyncEvents->getReadVector(); - while(evt_vec.first.len > 0) + if(evt_vec.first.len > 0) { - al::destroy_at(reinterpret_cast(evt_vec.first.buf)); - evt_vec.first.buf += sizeof(AsyncEvent); - evt_vec.first.len -= 1; - ++count; + al::destroy_n(reinterpret_cast(evt_vec.first.buf), evt_vec.first.len); + count += evt_vec.first.len; } - while(evt_vec.second.len > 0) + if(evt_vec.second.len > 0) { - al::destroy_at(reinterpret_cast(evt_vec.second.buf)); - evt_vec.second.buf += sizeof(AsyncEvent); - evt_vec.second.len -= 1; - ++count; + al::destroy_n(reinterpret_cast(evt_vec.second.buf), evt_vec.second.len); + count += evt_vec.second.len; } if(count > 0) TRACE("Destructed %zu orphaned event%s\n", count, (count==1)?"":"s"); + AsyncEvents->readAdvance(count); } ALCdevice_DecRef(Device); -- cgit v1.2.3 From 21b8571f50d8d9959282b652eea45759e98ede55 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 16 Jun 2019 22:45:07 -0700 Subject: Avoid an implied else if check --- Alc/converter.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Alc/converter.cpp b/Alc/converter.cpp index a6a5f2c4..a36d05ad 100644 --- a/Alc/converter.cpp +++ b/Alc/converter.cpp @@ -333,12 +333,6 @@ ChannelConverterPtr CreateChannelConverter(DevFmtType srcType, DevFmtChannels sr void ChannelConverter::convert(const ALvoid *src, ALfloat *dst, ALsizei frames) const { - if(mSrcChans == mDstChans) - { - LoadSamples(dst, src, 1u, mSrcType, frames*ChannelsFromDevFmt(mSrcChans, 0)); - return; - } - if(mSrcChans == DevFmtStereo && mDstChans == DevFmtMono) { switch(mSrcType) @@ -354,7 +348,7 @@ void ChannelConverter::convert(const ALvoid *src, ALfloat *dst, ALsizei frames) #undef HANDLE_FMT } } - else /*if(mSrcChans == DevFmtMono && mDstChans == DevFmtStereo)*/ + else if(mSrcChans == DevFmtMono && mDstChans == DevFmtStereo) { switch(mSrcType) { @@ -369,4 +363,6 @@ void ChannelConverter::convert(const ALvoid *src, ALfloat *dst, ALsizei frames) #undef HANDLE_FMT } } + else + LoadSamples(dst, src, 1u, mSrcType, frames*ChannelsFromDevFmt(mSrcChans, 0)); } -- cgit v1.2.3 From 5a884572f023e323c73266fd29382c6ccebc275b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 17 Jun 2019 20:05:38 -0700 Subject: Use a span instead of pointer+size parameters --- Alc/alc.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 3c59782f..fde655be 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2852,11 +2852,11 @@ static inline ALCsizei NumAttrsForDevice(ALCdevice *device) return 29; } -static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) +static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, const al::span values) { ALCsizei i; - if(size <= 0 || values == nullptr) + if(values.empty()) { alcSetError(device, ALC_INVALID_VALUE); return 0; @@ -2907,7 +2907,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC case ALC_ALL_ATTRIBUTES: i = 0; - if(size < NumAttrsForDevice(device)) + if(values.size() < static_cast(NumAttrsForDevice(device))) alcSetError(device, ALC_INVALID_VALUE); else { @@ -2959,7 +2959,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC case ALC_ALL_ATTRIBUTES: i = 0; - if(size < NumAttrsForDevice(device)) + if(values.size() < static_cast(NumAttrsForDevice(device))) alcSetError(device, ALC_INVALID_VALUE); else { @@ -3144,7 +3144,8 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC { std::lock_guard _{device->StateLock}; device->HrtfList.clear(); device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); - values[0] = static_cast(device->HrtfList.size()); + values[0] = static_cast(minz(device->HrtfList.size(), + std::numeric_limits::max())); } return 1; @@ -3174,7 +3175,7 @@ START_API_FUNC if(size <= 0 || values == nullptr) alcSetError(dev.get(), ALC_INVALID_VALUE); else - GetIntegerv(dev.get(), param, size, values); + GetIntegerv(dev.get(), param, {values, values+size}); } END_API_FUNC @@ -3186,8 +3187,8 @@ START_API_FUNC alcSetError(dev.get(), ALC_INVALID_VALUE); else if(!dev || dev->Type == Capture) { - al::vector ivals(size); - size = GetIntegerv(dev.get(), pname, size, ivals.data()); + auto ivals = al::vector(size); + size = GetIntegerv(dev.get(), pname, {ivals.data(), ivals.size()}); std::copy(ivals.begin(), ivals.begin()+size, values); } else /* render device */ @@ -3302,8 +3303,8 @@ START_API_FUNC break; default: - al::vector ivals(size); - size = GetIntegerv(dev.get(), pname, size, ivals.data()); + auto ivals = al::vector(size); + size = GetIntegerv(dev.get(), pname, {ivals.data(), ivals.size()}); std::copy(ivals.begin(), ivals.begin()+size, values); break; } -- cgit v1.2.3 From 55785c0a16938fe5148693a59451f698bef4133c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 17 Jun 2019 20:15:37 -0700 Subject: Use al::make_unique for ChannelConverter --- Alc/converter.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Alc/converter.cpp b/Alc/converter.cpp index a36d05ad..aa74d510 100644 --- a/Alc/converter.cpp +++ b/Alc/converter.cpp @@ -327,8 +327,7 @@ ChannelConverterPtr CreateChannelConverter(DevFmtType srcType, DevFmtChannels sr if(srcChans != dstChans && !((srcChans == DevFmtMono && dstChans == DevFmtStereo) || (srcChans == DevFmtStereo && dstChans == DevFmtMono))) return nullptr; - - return ChannelConverterPtr{new ChannelConverter{srcType, srcChans, dstChans}}; + return al::make_unique(srcType, srcChans, dstChans); } void ChannelConverter::convert(const ALvoid *src, ALfloat *dst, ALsizei frames) const -- cgit v1.2.3 From 2b19c53ecec0deff0536865f71f44bef3ff14094 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 17 Jun 2019 20:26:00 -0700 Subject: Use al::byte instead of ALbyte for raw bytes --- Alc/converter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/converter.cpp b/Alc/converter.cpp index aa74d510..0f8e8941 100644 --- a/Alc/converter.cpp +++ b/Alc/converter.cpp @@ -213,7 +213,7 @@ ALsizei SampleConverter::convert(const ALvoid **src, ALsizei *srcframes, ALvoid const ALsizei SrcFrameSize{static_cast(mChan.size()) * mSrcTypeSize}; const ALsizei DstFrameSize{static_cast(mChan.size()) * mDstTypeSize}; const ALsizei increment{mIncrement}; - auto SamplesIn = static_cast(*src); + auto SamplesIn = static_cast(*src); ALsizei NumSrcSamples{*srcframes}; FPUCtl mixer_mode{}; @@ -268,8 +268,8 @@ ALsizei SampleConverter::convert(const ALvoid **src, ALsizei *srcframes, ALvoid for(size_t chan{0u};chan < mChan.size();chan++) { - const ALbyte *SrcSamples = SamplesIn + mSrcTypeSize*chan; - ALbyte *DstSamples = static_cast(dst) + mDstTypeSize*chan; + const al::byte *SrcSamples{SamplesIn + mSrcTypeSize*chan}; + al::byte *DstSamples = static_cast(dst) + mDstTypeSize*chan; /* Load the previous samples into the source data first, then the * new samples from the input buffer. @@ -311,7 +311,7 @@ ALsizei SampleConverter::convert(const ALvoid **src, ALsizei *srcframes, ALvoid SamplesIn += SrcFrameSize*(DataPosFrac>>FRACTIONBITS); NumSrcSamples -= mini(NumSrcSamples, (DataPosFrac>>FRACTIONBITS)); - dst = static_cast(dst) + DstFrameSize*DstSize; + dst = static_cast(dst) + DstFrameSize*DstSize; pos += DstSize; } -- cgit v1.2.3 From 706df72d1813272e6cdfe817cf4c0adfefa13bd9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 18 Jun 2019 06:20:35 -0700 Subject: Rename HrtfParams to HrtfFilter --- Alc/alu.cpp | 2 +- Alc/hrtf.h | 2 +- Alc/mixer/defs.h | 6 +++--- Alc/mixer/hrtfbase.h | 4 ++-- Alc/mixer/mixer_c.cpp | 4 ++-- Alc/mixer/mixer_neon.cpp | 4 ++-- Alc/mixer/mixer_sse.cpp | 4 ++-- Alc/mixvoice.cpp | 4 ++-- OpenAL32/Include/alu.h | 10 +++++----- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index cc478a89..e5dcfd01 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -539,7 +539,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo std::for_each(voice->mChans.begin(), voice->mChans.begin()+num_channels, [NumSends](ALvoice::ChannelData &chandata) -> void { - chandata.mDryParams.Hrtf.Target = HrtfParams{}; + chandata.mDryParams.Hrtf.Target = HrtfFilter{}; ClearArray(chandata.mDryParams.Gains.Target); std::for_each(chandata.mWetParams.begin(), chandata.mWetParams.begin()+NumSends, [](SendParams ¶ms) -> void { ClearArray(params.Gains.Target); }); diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 1fb53e4c..72533cc1 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -70,7 +70,7 @@ struct HrtfState { alignas(16) HrirArray Values; }; -struct HrtfParams { +struct HrtfFilter { alignas(16) HrirArray Coeffs; ALsizei Delay[2]; ALfloat Gain; diff --git a/Alc/mixer/defs.h b/Alc/mixer/defs.h index a86da8a1..0e91e30e 100644 --- a/Alc/mixer/defs.h +++ b/Alc/mixer/defs.h @@ -10,7 +10,7 @@ struct MixGains; -struct MixHrtfParams; +struct MixHrtfFilter; struct HrtfState; struct DirectHrtfState; @@ -37,9 +37,9 @@ template void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize); template -void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfParams *hrtfparams, const ALsizei BufferSize); +void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfFilter *hrtfparams, const ALsizei BufferSize); template -void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, const ALsizei BufferSize); +void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize); template void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, const ALsizei BufferSize); diff --git a/Alc/mixer/hrtfbase.h b/Alc/mixer/hrtfbase.h index bce9e573..a76bd62e 100644 --- a/Alc/mixer/hrtfbase.h +++ b/Alc/mixer/hrtfbase.h @@ -14,7 +14,7 @@ using ApplyCoeffsT = void(ALsizei Offset, float2 *RESTRICT Values, const ALsizei template inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *RESTRICT AccumSamples, const ALsizei OutPos, - const ALsizei IrSize, MixHrtfParams *hrtfparams, const ALsizei BufferSize) + const ALsizei IrSize, MixHrtfFilter *hrtfparams, const ALsizei BufferSize) { ASSUME(OutPos >= 0); ASSUME(IrSize >= 4); @@ -50,7 +50,7 @@ inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *RESTRICT AccumSamples, const ALsizei OutPos, - const ALsizei IrSize, const HrtfParams *oldparams, MixHrtfParams *newparams, + const ALsizei IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize) { const auto &OldCoeffs = oldparams->Coeffs; diff --git a/Alc/mixer/mixer_c.cpp b/Alc/mixer/mixer_c.cpp index 9e8f2ad5..80942eab 100644 --- a/Alc/mixer/mixer_c.cpp +++ b/Alc/mixer/mixer_c.cpp @@ -119,7 +119,7 @@ static inline void ApplyCoeffs(ALsizei /*Offset*/, float2 *RESTRICT Values, cons template<> void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - MixHrtfParams *hrtfparams, const ALsizei BufferSize) + MixHrtfFilter *hrtfparams, const ALsizei BufferSize) { MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, hrtfparams, BufferSize); @@ -128,7 +128,7 @@ void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - const HrtfParams *oldparams, MixHrtfParams *newparams, const ALsizei BufferSize) + const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize) { MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, oldparams, newparams, BufferSize); diff --git a/Alc/mixer/mixer_neon.cpp b/Alc/mixer/mixer_neon.cpp index eaa09718..c30e9861 100644 --- a/Alc/mixer/mixer_neon.cpp +++ b/Alc/mixer/mixer_neon.cpp @@ -165,7 +165,7 @@ static inline void ApplyCoeffs(ALsizei /*Offset*/, float2 *RESTRICT Values, cons template<> void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - MixHrtfParams *hrtfparams, const ALsizei BufferSize) + MixHrtfFilter *hrtfparams, const ALsizei BufferSize) { MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, hrtfparams, BufferSize); @@ -174,7 +174,7 @@ void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - const HrtfParams *oldparams, MixHrtfParams *newparams, const ALsizei BufferSize) + const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize) { MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, oldparams, newparams, BufferSize); diff --git a/Alc/mixer/mixer_sse.cpp b/Alc/mixer/mixer_sse.cpp index 0f8b905f..f407ac14 100644 --- a/Alc/mixer/mixer_sse.cpp +++ b/Alc/mixer/mixer_sse.cpp @@ -122,7 +122,7 @@ static inline void ApplyCoeffs(ALsizei Offset, float2 *RESTRICT Values, const AL template<> void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - MixHrtfParams *hrtfparams, const ALsizei BufferSize) + MixHrtfFilter *hrtfparams, const ALsizei BufferSize) { MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, hrtfparams, BufferSize); @@ -131,7 +131,7 @@ void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - const HrtfParams *oldparams, MixHrtfParams *newparams, const ALsizei BufferSize) + const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize) { MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, oldparams, newparams, BufferSize); diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 8e208ff9..e410e50e 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -739,7 +739,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc static_cast(Counter)}; gain = lerp(parms.Hrtf.Old.Gain, TargetGain, a); } - MixHrtfParams hrtfparams; + MixHrtfFilter hrtfparams; hrtfparams.Coeffs = &parms.Hrtf.Target.Coeffs; hrtfparams.Delay[0] = parms.Hrtf.Target.Delay[0]; hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1]; @@ -772,7 +772,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc gain = lerp(parms.Hrtf.Old.Gain, TargetGain, a); } - MixHrtfParams hrtfparams; + MixHrtfFilter hrtfparams; hrtfparams.Coeffs = &parms.Hrtf.Target.Coeffs; hrtfparams.Delay[0] = parms.Hrtf.Target.Delay[0]; hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1]; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 74c8e0d4..8abfe15f 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -106,7 +106,7 @@ enum { }; -struct MixHrtfParams { +struct MixHrtfFilter { const HrirArray *Coeffs; ALsizei Delay[2]; ALfloat Gain; @@ -121,8 +121,8 @@ struct DirectParams { NfcFilter NFCtrlFilter; struct { - HrtfParams Old; - HrtfParams Target; + HrtfFilter Old; + HrtfFilter Target; HrtfState State; } Hrtf; @@ -330,10 +330,10 @@ using RowMixerFunc = void(*)(FloatBufferLine &OutBuffer, const ALfloat *gains, const ALsizei BufferSize); using HrtfMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - MixHrtfParams *hrtfparams, const ALsizei BufferSize); + MixHrtfFilter *hrtfparams, const ALsizei BufferSize); using HrtfMixerBlendFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - const HrtfParams *oldparams, MixHrtfParams *newparams, const ALsizei BufferSize); + const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize); using HrtfDirectMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, const ALsizei BufferSize); -- cgit v1.2.3 From 0fa984027c37e6ae9f5acbfd013cba5ba90ea9aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 18 Jun 2019 22:57:48 -0700 Subject: Simplify al_print --- Alc/helpers.cpp | 13 ++++++------- Alc/logging.h | 4 ++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index 9236e57a..3efa989d 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -477,7 +477,7 @@ void *GetSymbol(void *handle, const char *name) } -void al_print(const char *type, const char *fmt, ...) +void al_print(FILE *logfile, const char *fmt, ...) { al::vector dynmsg; char stcmsg[256]; @@ -497,8 +497,8 @@ void al_print(const char *type, const char *fmt, ...) va_end(args); std::wstring wstr{utf8_to_wstr(str)}; - fprintf(gLogFile, "AL lib: %s %ls", type, wstr.c_str()); - fflush(gLogFile); + fprintf(logfile, "%ls", wstr.c_str()); + fflush(logfile); } @@ -713,16 +713,15 @@ void *GetSymbol(void *handle, const char *name) #endif /* HAVE_DLFCN_H */ -void al_print(const char *type, const char *fmt, ...) +void al_print(FILE *logfile, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - fprintf(gLogFile, "AL lib: %s ", type); - vfprintf(gLogFile, fmt, ap); + vfprintf(logfile, fmt, ap); va_end(ap); - fflush(gLogFile); + fflush(logfile); } diff --git a/Alc/logging.h b/Alc/logging.h index b5faf698..0bb0c87b 100644 --- a/Alc/logging.h +++ b/Alc/logging.h @@ -15,11 +15,11 @@ extern FILE *gLogFile; +void al_print(FILE *logfile, const char *fmt, ...) DECL_FORMAT(printf, 2,3); #if !defined(_WIN32) #define AL_PRINT(T, ...) fprintf(gLogFile, "AL lib: " T " " __VA_ARGS__) #else -void al_print(const char *type, const char *fmt, ...) DECL_FORMAT(printf, 2,3); -#define AL_PRINT(T, ...) al_print((T), __VA_ARGS__) +#define AL_PRINT(T, ...) al_print(gLogFile, "AL lib: " T " " __VA_ARGS__) #endif #ifdef __ANDROID__ -- cgit v1.2.3 From 723ab7f15a4bdaa7dd26a8a672057cb0c901f36a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 18 Jun 2019 23:04:24 -0700 Subject: Don't inline ifstream destructor --- Alc/compat.h | 2 +- Alc/helpers.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Alc/compat.h b/Alc/compat.h index 2e0ad1e7..4ffc40bf 100644 --- a/Alc/compat.h +++ b/Alc/compat.h @@ -76,10 +76,10 @@ public: ifstream(const wchar_t *filename, std::ios_base::openmode mode = std::ios_base::in); ifstream(const std::wstring &filename, std::ios_base::openmode mode = std::ios_base::in) : ifstream(filename.c_str(), mode) { } - ifstream(const char *filename, std::ios_base::openmode mode = std::ios_base::in); ifstream(const std::string &filename, std::ios_base::openmode mode = std::ios_base::in) : ifstream(filename.c_str(), mode) { } + ~ifstream() override; bool is_open() const noexcept { return mStreamBuf.is_open(); } }; diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index 3efa989d..ee0bb2dc 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -424,6 +424,12 @@ ifstream::ifstream(const char *filename, std::ios_base::openmode mode) clear(failbit); } +/* This is only here to ensure the compiler doesn't define an implicit + * destructor, which it tries to automatically inline and subsequently complain + * it can't inline without excessive code growth. + */ +ifstream::~ifstream() { } + } // namespace al const PathNamePair &GetProcBinary() -- cgit v1.2.3 From 499aa65a4b57328bd9a0d5af0eee450218f2b57c Mon Sep 17 00:00:00 2001 From: geneotech Date: Fri, 21 Jun 2019 18:25:09 +0200 Subject: Fix ambiguous calls to destroy_at --- common/almalloc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/almalloc.h b/common/almalloc.h index 4bf3a281..d649716c 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -85,7 +85,7 @@ inline void destroy(T first, const T end) { while(first != end) { - destroy_at(std::addressof(*first)); + al::destroy_at(std::addressof(*first)); ++first; } } @@ -96,7 +96,7 @@ inline T destroy_n(T first, N count) if(count != 0) { do { - destroy_at(std::addressof(*first)); + al::destroy_at(std::addressof(*first)); ++first; } while(--count); } -- cgit v1.2.3 From ee983bda75f341742b30dd205fbb88e962af54f6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 20 Jun 2019 01:33:17 -0700 Subject: Document the hrtf-mode config option --- alsoftrc.sample | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/alsoftrc.sample b/alsoftrc.sample index 95d4ff82..93f70cc1 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -115,6 +115,19 @@ # respectively. #hrtf = auto +## hrtf-mode: +# Specifies the rendering mode for HRTF processing. Setting the mode to full +# (default) applies a unique HRIR filter to each source given its relative +# location, providing the clearest directional response at the cost of the +# highest CPU usage. Setting the mode to ambi1, ambi2, or ambi3 will instead +# mix to a first-, second-, or third-order ambisonic buffer respectively, then +# decode that buffer with HRTF filters. Ambi1 has the lowest CPU usage, +# replacing the per-source HRIR filter for a simple 4-channel panning mix, but +# retains full 3D placement at the cost of a more diffuse response. Ambi2 and +# ambi3 increasingly improve the directional clarity, at the cost of more CPU +# usage (still less than "full", given some number of active sources). +#hrtf-mode = full + ## default-hrtf: # Specifies the default HRTF to use. When multiple HRTFs are available, this # determines the preferred one to use if none are specifically requested. Note -- cgit v1.2.3 From b46fc572f598bfa917c8cd7f3c099cb218962dd1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 23 Jun 2019 17:08:52 -0700 Subject: Use spans to handle pulseaudio capture buffers --- Alc/backends/pulseaudio.cpp | 66 ++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 6d4f387c..a19663eb 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -1117,11 +1117,11 @@ struct PulseCapture final : public BackendBase { std::string mDeviceName; - const void *mCapStore{nullptr}; - size_t mCapLen{0u}; - size_t mCapRemain{0u}; - ALCuint mLastReadable{0u}; + al::byte mSilentVal{}; + + al::span mCapBuffer; + ssize_t mCapLen{0}; pa_buffer_attr mAttr{}; pa_sample_spec mSpec{}; @@ -1247,6 +1247,7 @@ ALCenum PulseCapture::open(const ALCchar *name) switch(mDevice->FmtType) { case DevFmtUByte: + mSilentVal = al::byte(0x80); mSpec.format = PA_SAMPLE_U8; break; case DevFmtShort: @@ -1317,15 +1318,15 @@ void PulseCapture::stop() ALCenum PulseCapture::captureSamples(ALCvoid *buffer, ALCuint samples) { - ALCuint todo{samples * static_cast(pa_frame_size(&mSpec))}; + al::span dstbuf{static_cast(buffer), samples * pa_frame_size(&mSpec)}; /* Capture is done in fragment-sized chunks, so we loop until we get all * that's available */ - mLastReadable -= todo; + mLastReadable -= dstbuf.size(); std::lock_guard _{pulse_lock}; - while(todo > 0) + while(!dstbuf.empty()) { - if(mCapLen == 0) + if(mCapBuffer.empty()) { if(UNLIKELY(!mDevice->Connected.load(std::memory_order_acquire))) break; @@ -1335,43 +1336,45 @@ ALCenum PulseCapture::captureSamples(ALCvoid *buffer, ALCuint samples) aluHandleDisconnect(mDevice, "Bad capture state: %u", state); break; } - if(UNLIKELY(pa_stream_peek(mStream, &mCapStore, &mCapLen) < 0)) + const void *capbuf; + size_t caplen; + if(UNLIKELY(pa_stream_peek(mStream, &capbuf, &caplen) < 0)) { aluHandleDisconnect(mDevice, "Failed retrieving capture samples: %s", - pa_strerror(pa_context_errno(mContext))); + pa_strerror(pa_context_errno(mContext))); break; } - if(mCapLen == 0) break; - mCapRemain = mCapLen; + if(caplen == 0) break; + if(UNLIKELY(!capbuf)) + mCapLen = -static_cast(caplen); + else + mCapLen = static_cast(caplen); + mCapBuffer = {static_cast(capbuf), caplen}; } - const size_t rem{minz(todo, mCapRemain)}; - if(LIKELY(mCapStore)) - memcpy(buffer, mCapStore, rem); + const size_t rem{minz(dstbuf.size(), mCapBuffer.size())}; + if(UNLIKELY(mCapLen < 0)) + std::fill_n(dstbuf.begin(), rem, mSilentVal); else - memset(buffer, ((mDevice->FmtType==DevFmtUByte) ? 0x80 : 0), rem); - - buffer = static_cast(buffer) + rem; - todo -= rem; + std::copy_n(mCapBuffer.begin(), rem, dstbuf.begin()); + dstbuf = dstbuf.subspan(rem); + mCapBuffer = mCapBuffer.subspan(rem); - if(LIKELY(mCapStore)) - mCapStore = reinterpret_cast(mCapStore) + rem; - mCapRemain -= rem; - if(mCapRemain == 0) + if(mCapBuffer.empty()) { pa_stream_drop(mStream); mCapLen = 0; } } - if(todo > 0) - memset(buffer, ((mDevice->FmtType==DevFmtUByte) ? 0x80 : 0), todo); + if(!dstbuf.empty()) + std::fill(dstbuf.begin(), dstbuf.end(), mSilentVal); return ALC_NO_ERROR; } ALCuint PulseCapture::availableSamples() { - size_t readable{mCapRemain}; + size_t readable{mCapBuffer.size()}; if(mDevice->Connected.load(std::memory_order_acquire)) { @@ -1382,12 +1385,15 @@ ALCuint PulseCapture::availableSamples() ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got)); aluHandleDisconnect(mDevice, "Failed getting readable size: %s", pa_strerror(got)); } - else if(got > mCapLen) - readable += got - mCapLen; + else + { + const auto caplen = static_cast(std::abs(mCapLen)); + if(got > caplen) readable += got - caplen; + } } - if(mLastReadable < readable) - mLastReadable = readable; + readable = std::min(readable, std::numeric_limits::max()); + mLastReadable = std::max(mLastReadable, static_cast(readable)); return mLastReadable / pa_frame_size(&mSpec); } -- cgit v1.2.3 From e8cef0cdae5675f3d23f0de9e9093734c74ababb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 24 Jun 2019 12:55:36 -0700 Subject: Clean up all unused HRTFs when going through them --- Alc/hrtf.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 2584ef13..6b3edd9f 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -1376,18 +1376,16 @@ void HrtfEntry::DecRef() { std::lock_guard _{LoadedHrtfLock}; - /* Need to double-check that it's still unused, as another device - * could've reacquired this HRTF after its reference went to 0 and - * before the lock was taken. - */ - auto iter = std::find_if(LoadedHrtfs.begin(), LoadedHrtfs.end(), - [this](const HrtfHandlePtr &entry) noexcept -> bool - { return this == entry->entry.get(); } - ); - if(iter != LoadedHrtfs.end() && ReadRef(&this->ref) == 0) + /* Go through and clear all unused HRTFs. */ + auto delete_unused = [](HrtfHandlePtr &handle) -> void { - (*iter)->entry = nullptr; - TRACE("Unloaded unused HRTF %s\n", (*iter)->filename.data()); - } + HrtfEntry *entry{handle->entry.get()}; + if(entry && ReadRef(&entry->ref) == 0) + { + TRACE("Unloading unused HRTF %s\n", handle->filename.data()); + handle->entry = nullptr; + } + }; + std::for_each(LoadedHrtfs.begin(), LoadedHrtfs.end(), delete_unused); } } -- cgit v1.2.3 From eb5ff42d158ecc1b7675bf7692a32c21404f5adf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 24 Jun 2019 13:21:06 -0700 Subject: Correctly index the send params --- Alc/mixvoice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index e410e50e..7be65f65 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -567,7 +567,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc if(voice->mSend[send].Buffer.empty()) continue; - SendParams &parms = chandata.mWetParams[chan]; + SendParams &parms = chandata.mWetParams[send]; std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target), std::begin(parms.Gains.Current)); } -- cgit v1.2.3 From f5cb6ac20ec36a48002c4056d0eb342d7dcd7b26 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 24 Jun 2019 13:33:09 -0700 Subject: Use a reference instead of the same array index --- Alc/mixvoice.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 7be65f65..17da538d 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -625,17 +625,17 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc for(ALsizei chan{0};chan < NumChannels;chan++) { + ALvoice::ChannelData &chandata = voice->mChans[chan]; const al::span SrcData{Device->SourceData, SrcBufferSize}; /* Load the previous samples into the source data first, and clear the rest. */ - auto srciter = std::copy_n(voice->mChans[chan].mPrevSamples.begin(), - MAX_RESAMPLE_PADDING, SrcData.begin()); + auto srciter = std::copy_n(chandata.mPrevSamples.begin(), MAX_RESAMPLE_PADDING, + SrcData.begin()); std::fill(srciter, SrcData.end(), 0.0f); if(UNLIKELY(!BufferListItem)) - srciter = std::copy( - voice->mChans[chan].mPrevSamples.begin()+MAX_RESAMPLE_PADDING, - voice->mChans[chan].mPrevSamples.end(), srciter); + srciter = std::copy(chandata.mPrevSamples.begin()+MAX_RESAMPLE_PADDING, + chandata.mPrevSamples.end(), srciter); else if(isstatic) srciter = LoadBufferStatic(BufferListItem, BufferLoopItem, NumChannels, SampleSize, chan, DataPosInt, srciter, SrcData.end()); @@ -656,8 +656,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc /* Store the last source samples used for next time. */ std::copy_n(&SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS], - voice->mChans[chan].mPrevSamples.size(), - voice->mChans[chan].mPrevSamples.begin()); + chandata.mPrevSamples.size(), chandata.mPrevSamples.begin()); /* Resample, then apply ambisonic upsampling as needed. */ const ALfloat *ResampledData{Resample(&voice->mResampleState, @@ -665,20 +664,20 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc Device->ResampledData, DstBufferSize)}; if((voice->mFlags&VOICE_IS_AMBISONIC)) { - const ALfloat hfscale{voice->mChans[chan].mAmbiScale}; + const ALfloat hfscale{chandata.mAmbiScale}; /* Beware the evil const_cast. It's safe since it's pointing to * either SourceData or ResampledData (both non-const), but the * resample method takes the source as const float* and may * return it without copying to output, making it currently * unavoidable. */ - voice->mChans[chan].mAmbiSplitter.applyHfScale(const_cast(ResampledData), - hfscale, DstBufferSize); + chandata.mAmbiSplitter.applyHfScale(const_cast(ResampledData), hfscale, + DstBufferSize); } /* Now filter and mix to the appropriate outputs. */ { - DirectParams &parms = voice->mChans[chan].mDryParams; + DirectParams &parms = chandata.mDryParams; const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, Device->FilteredData, ResampledData, DstBufferSize, voice->mDirect.FilterType)}; @@ -837,7 +836,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc if(voice->mSend[send].Buffer.empty()) continue; - SendParams &parms = voice->mChans[chan].mWetParams[send]; + SendParams &parms = chandata.mWetParams[send]; const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, FilterBuf, ResampledData, DstBufferSize, voice->mSend[send].FilterType)}; -- cgit v1.2.3 From ab3c2ea777dd6a31163f0d31922004185ff8a180 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 24 Jun 2019 21:18:25 -0700 Subject: Don't bother with a passthru filter method There's not really a case where it'll process less than 2 samples, and it was wrong anyway. --- Alc/filters/biquad.h | 14 -------------- Alc/mixvoice.cpp | 23 ++++++++--------------- 2 files changed, 8 insertions(+), 29 deletions(-) diff --git a/Alc/filters/biquad.h b/Alc/filters/biquad.h index 96bf3407..eb4cf82a 100644 --- a/Alc/filters/biquad.h +++ b/Alc/filters/biquad.h @@ -74,20 +74,6 @@ public: void process(Real *dst, const Real *src, int numsamples); - void passthru(int numsamples) noexcept - { - if(LIKELY(numsamples >= 2)) - { - z1 = 0.0f; - z2 = 0.0f; - } - else if(numsamples == 1) - { - z1 = z2; - z2 = 0.0f; - } - } - /* Rather hacky. It's just here to support "manual" processing. */ std::pair getComponents() const noexcept { return {z1, z2}; } diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 17da538d..d3521f5b 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -292,35 +292,28 @@ void SendSourceStoppedEvent(ALCcontext *context, ALuint id) } -const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, - ALfloat *RESTRICT dst, const ALfloat *RESTRICT src, ALsizei numsamples, int type) +const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, ALfloat *dst, + const ALfloat *src, ALsizei numsamples, int type) { switch(type) { case AF_None: - lpfilter->passthru(numsamples); - hpfilter->passthru(numsamples); + lpfilter->clear(); + hpfilter->clear(); break; case AF_LowPass: lpfilter->process(dst, src, numsamples); - hpfilter->passthru(numsamples); + hpfilter->clear(); return dst; case AF_HighPass: - lpfilter->passthru(numsamples); + lpfilter->clear(); hpfilter->process(dst, src, numsamples); return dst; case AF_BandPass: - for(ALsizei i{0};i < numsamples;) - { - ALfloat temp[256]; - ALsizei todo = mini(256, numsamples-i); - - lpfilter->process(temp, src+i, todo); - hpfilter->process(dst+i, temp, todo); - i += todo; - } + lpfilter->process(dst, src, numsamples); + hpfilter->process(dst, dst, numsamples); return dst; } return src; -- cgit v1.2.3 From edd75b3b4eb4e43f4df7dfe6470989f22e4d3bcc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 25 Jun 2019 14:40:25 -0700 Subject: Don't return a blank span when offset==size() --- common/alspan.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/alspan.h b/common/alspan.h index 6b0dc7d6..b7995121 100644 --- a/common/alspan.h +++ b/common/alspan.h @@ -255,7 +255,7 @@ public: constexpr span subspan(size_t offset, size_t count=dynamic_extent) const { - return (offset >= size()) ? span{} : + return (offset > size()) ? span{} : (count >= size()-offset) ? span{mData+offset, mDataEnd} : span{mData+offset, mData+offset+count}; } @@ -282,7 +282,7 @@ constexpr inline auto span::last(size_t count) const -> span constexpr inline auto span::subspan(size_t offset, size_t count) const -> span { - return (offset >= size()) ? span{} : + return (offset > size()) ? span{} : (count >= size()-offset) ? span{mData+offset, mData+extent} : span{mData+offset, mData+offset+count}; } -- cgit v1.2.3 From 48191cbf0a72912d26aa6fa745239a6bd63a0edf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 25 Jun 2019 17:10:46 -0700 Subject: Use a span instead of explicit current and end pointers --- Alc/mixvoice.cpp | 83 +++++++++++++++++++++++++++----------------------------- 1 file changed, 40 insertions(+), 43 deletions(-) diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index d3521f5b..9408d096 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -368,7 +368,7 @@ void LoadSamples(ALfloat *RESTRICT dst, const al::byte *src, ALint srcstep, FmtT ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&BufferLoopItem, const ALsizei NumChannels, const ALsizei SampleSize, const ALsizei chan, ALsizei DataPosInt, - ALfloat *SrcData, const ALfloat *const SrcDataEnd) + al::span SrcBuffer) { /* TODO: For static sources, loop points are taken from the first buffer * (should be adjusted by any buffer offset, to possibly be added later). @@ -382,91 +382,90 @@ ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&B /* If current pos is beyond the loop range, do not loop */ if(!BufferLoopItem || DataPosInt >= LoopEnd) { - const ptrdiff_t SizeToDo{SrcDataEnd - SrcData}; - ASSUME(SizeToDo > 0); - BufferLoopItem = nullptr; - auto load_buffer = [DataPosInt,SrcData,NumChannels,SampleSize,chan,SizeToDo](ptrdiff_t CompLen, const ALbuffer *buffer) -> ptrdiff_t + auto load_buffer = [DataPosInt,NumChannels,SampleSize,chan,SrcBuffer](size_t CompLen, const ALbuffer *buffer) -> size_t { if(DataPosInt >= buffer->SampleLen) return CompLen; /* Load what's left to play from the buffer */ - const ptrdiff_t DataSize{std::min(SizeToDo, buffer->SampleLen-DataPosInt)}; - CompLen = std::max(CompLen, DataSize); + const size_t DataSize{std::min(SrcBuffer.size(), + buffer->SampleLen - DataPosInt)}; + CompLen = std::max(CompLen, DataSize); const al::byte *Data{buffer->mData.data()}; Data += (DataPosInt*NumChannels + chan)*SampleSize; - LoadSamples(SrcData, Data, NumChannels, buffer->mFmtType, DataSize); + LoadSamples(SrcBuffer.data(), Data, NumChannels, buffer->mFmtType, DataSize); return CompLen; }; /* It's impossible to have a buffer list item with no entries. */ ASSUME(BufferListItem->num_buffers > 0); auto buffers_end = BufferListItem->buffers + BufferListItem->num_buffers; - SrcData += std::accumulate(BufferListItem->buffers, buffers_end, ptrdiff_t{0}, - load_buffer); + SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->buffers, buffers_end, + size_t{0u}, load_buffer)); } else { - const ptrdiff_t SizeToDo{std::min(SrcDataEnd-SrcData, LoopEnd-DataPosInt)}; - ASSUME(SizeToDo > 0); + const al::span SrcData{SrcBuffer.first( + std::min(SrcBuffer.size(), LoopEnd - DataPosInt))}; - auto load_buffer = [DataPosInt,SrcData,NumChannels,SampleSize,chan,SizeToDo](ptrdiff_t CompLen, const ALbuffer *buffer) -> ptrdiff_t + auto load_buffer = [DataPosInt,NumChannels,SampleSize,chan,SrcData](size_t CompLen, const ALbuffer *buffer) -> size_t { if(DataPosInt >= buffer->SampleLen) return CompLen; /* Load what's left of this loop iteration */ - const ptrdiff_t DataSize{std::min(SizeToDo, buffer->SampleLen-DataPosInt)}; - CompLen = std::max(CompLen, DataSize); + const size_t DataSize{std::min(SrcData.size(), + buffer->SampleLen - DataPosInt)}; + CompLen = std::max(CompLen, DataSize); const al::byte *Data{buffer->mData.data()}; Data += (DataPosInt*NumChannels + chan)*SampleSize; - LoadSamples(SrcData, Data, NumChannels, buffer->mFmtType, DataSize); + LoadSamples(SrcData.data(), Data, NumChannels, buffer->mFmtType, DataSize); return CompLen; }; ASSUME(BufferListItem->num_buffers > 0); auto buffers_end = BufferListItem->buffers + BufferListItem->num_buffers; - SrcData += std::accumulate(BufferListItem->buffers, buffers_end, ptrdiff_t{0}, - load_buffer); + SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->buffers, buffers_end, + size_t{0u}, load_buffer)); - const auto LoopSize = static_cast(LoopEnd - LoopStart); - while(SrcData != SrcDataEnd) + const auto LoopSize = static_cast(LoopEnd - LoopStart); + while(!SrcBuffer.empty()) { - const ptrdiff_t SizeToDo{std::min(SrcDataEnd-SrcData, LoopSize)}; - ASSUME(SizeToDo > 0); + const al::span SrcData{SrcBuffer.first( + std::min(SrcBuffer.size(), LoopSize))}; - auto load_buffer_loop = [LoopStart,SrcData,NumChannels,SampleSize,chan,SizeToDo](ptrdiff_t CompLen, const ALbuffer *buffer) -> ptrdiff_t + auto load_buffer_loop = [LoopStart,NumChannels,SampleSize,chan,SrcData](size_t CompLen, const ALbuffer *buffer) -> size_t { if(LoopStart >= buffer->SampleLen) return CompLen; - const ptrdiff_t DataSize{std::min(SizeToDo, + const size_t DataSize{std::min(SrcData.size(), buffer->SampleLen-LoopStart)}; - CompLen = std::max(CompLen, DataSize); + CompLen = std::max(CompLen, DataSize); const al::byte *Data{buffer->mData.data()}; Data += (LoopStart*NumChannels + chan)*SampleSize; - LoadSamples(SrcData, Data, NumChannels, buffer->mFmtType, DataSize); + LoadSamples(SrcData.data(), Data, NumChannels, buffer->mFmtType, DataSize); return CompLen; }; - SrcData += std::accumulate(BufferListItem->buffers, buffers_end, ptrdiff_t{0}, - load_buffer_loop); + SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->buffers, buffers_end, + size_t{0u}, load_buffer_loop)); } } - return SrcData; + return SrcBuffer.begin(); } ALfloat *LoadBufferQueue(ALbufferlistitem *BufferListItem, ALbufferlistitem *BufferLoopItem, const ALsizei NumChannels, const ALsizei SampleSize, const ALsizei chan, ALsizei DataPosInt, - ALfloat *SrcData, const ALfloat *const SrcDataEnd) + al::span SrcBuffer) { /* Crawl the buffer queue to fill in the temp buffer */ - while(BufferListItem && SrcData != SrcDataEnd) + while(BufferListItem && !SrcBuffer.empty()) { if(DataPosInt >= BufferListItem->max_samples) { @@ -476,36 +475,34 @@ ALfloat *LoadBufferQueue(ALbufferlistitem *BufferListItem, ALbufferlistitem *Buf continue; } - const ptrdiff_t SizeToDo{SrcDataEnd - SrcData}; - ASSUME(SizeToDo > 0); - auto load_buffer = [DataPosInt,SrcData,NumChannels,SampleSize,chan,SizeToDo](ptrdiff_t CompLen, const ALbuffer *buffer) -> ptrdiff_t + auto load_buffer = [DataPosInt,NumChannels,SampleSize,chan,SrcBuffer](size_t CompLen, const ALbuffer *buffer) -> size_t { if(!buffer) return CompLen; if(DataPosInt >= buffer->SampleLen) return CompLen; - const ptrdiff_t DataSize{std::min(SizeToDo, buffer->SampleLen-DataPosInt)}; - CompLen = std::max(CompLen, DataSize); + const size_t DataSize{std::min(SrcBuffer.size(), buffer->SampleLen-DataPosInt)}; + CompLen = std::max(CompLen, DataSize); const al::byte *Data{buffer->mData.data()}; Data += (DataPosInt*NumChannels + chan)*SampleSize; - LoadSamples(SrcData, Data, NumChannels, buffer->mFmtType, DataSize); + LoadSamples(SrcBuffer.data(), Data, NumChannels, buffer->mFmtType, DataSize); return CompLen; }; ASSUME(BufferListItem->num_buffers > 0); auto buffers_end = BufferListItem->buffers + BufferListItem->num_buffers; - SrcData += std::accumulate(BufferListItem->buffers, buffers_end, ptrdiff_t{0u}, - load_buffer); + SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->buffers, buffers_end, + size_t{0u}, load_buffer)); - if(SrcData == SrcDataEnd) + if(SrcBuffer.empty()) break; DataPosInt = 0; BufferListItem = BufferListItem->next.load(std::memory_order_acquire); if(!BufferListItem) BufferListItem = BufferLoopItem; } - return SrcData; + return SrcBuffer.begin(); } } // namespace @@ -631,10 +628,10 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc chandata.mPrevSamples.end(), srciter); else if(isstatic) srciter = LoadBufferStatic(BufferListItem, BufferLoopItem, NumChannels, - SampleSize, chan, DataPosInt, srciter, SrcData.end()); + SampleSize, chan, DataPosInt, {srciter, SrcData.end()}); else srciter = LoadBufferQueue(BufferListItem, BufferLoopItem, NumChannels, - SampleSize, chan, DataPosInt, srciter, SrcData.end()); + SampleSize, chan, DataPosInt, {srciter, SrcData.end()}); if(UNLIKELY(srciter != SrcData.end())) { -- cgit v1.2.3 From 360869f23b30b060dce7890dbd49d3a274b9ada5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Jun 2019 08:49:04 -0700 Subject: Use a span for some post-mixing processing --- Alc/alu.cpp | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index e5dcfd01..846d9aea 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1556,11 +1556,9 @@ void ApplyDistanceComp(const al::span Samples, const ALsizei Sa } } -void ApplyDither(FloatBufferLine *Samples, ALuint *dither_seed, const ALfloat quant_scale, - const ALsizei SamplesToDo, const ALuint numchans) +void ApplyDither(const al::span Samples, ALuint *dither_seed, + const ALfloat quant_scale, const ALsizei SamplesToDo) { - ASSUME(numchans > 0); - /* Dithering. Generate whitenoise (uniform distribution of random values * between -1 and +1) and add it to the sample values, after scaling up to * the desired quantization depth amd before rounding. @@ -1580,7 +1578,7 @@ void ApplyDither(FloatBufferLine *Samples, ALuint *dither_seed, const ALfloat qu }; std::transform(input.begin(), input.begin()+SamplesToDo, input.begin(), dither_sample); }; - std::for_each(Samples, Samples+numchans, dither_channel); + std::for_each(Samples.begin(), Samples.end(), dither_channel); *dither_seed = seed; } @@ -1616,12 +1614,14 @@ template<> inline ALubyte SampleConv(ALfloat val) noexcept { return SampleConv(val) + 128; } template -void Write(const FloatBufferLine *InBuffer, ALvoid *OutBuffer, const size_t Offset, - const ALsizei SamplesToDo, const ALuint numchans) +void Write(const al::span InBuffer, ALvoid *OutBuffer, const size_t Offset, + const ALsizei SamplesToDo) { using SampleType = typename DevFmtTypeTraits::Type; + const size_t numchans{InBuffer.size()}; ASSUME(numchans > 0); + SampleType *outbase = static_cast(OutBuffer) + Offset*numchans; auto conv_channel = [&outbase,SamplesToDo,numchans](const FloatBufferLine &inbuf) -> void { @@ -1634,7 +1634,7 @@ void Write(const FloatBufferLine *InBuffer, ALvoid *OutBuffer, const size_t Offs }; std::for_each(inbuf.begin(), inbuf.begin()+SamplesToDo, conv_sample); }; - std::for_each(InBuffer, InBuffer+numchans, conv_channel); + std::for_each(InBuffer.cbegin(), InBuffer.cend(), conv_channel); } } // namespace @@ -1700,29 +1700,26 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) if(Compressor *comp{device->Limiter.get()}) comp->process(SamplesToDo, device->RealOut.Buffer); + const al::span RealOut{device->RealOut.Buffer, + device->RealOut.NumChannels}; /* Apply delays and attenuation for mismatched speaker distances. */ - ApplyDistanceComp({device->RealOut.Buffer, device->RealOut.NumChannels}, SamplesToDo, - device->ChannelDelay.as_span().cbegin()); + ApplyDistanceComp(RealOut, SamplesToDo, device->ChannelDelay.as_span().cbegin()); /* Apply dithering. The compressor should have left enough headroom for * the dither noise to not saturate. */ if(device->DitherDepth > 0.0f) - ApplyDither(device->RealOut.Buffer, &device->DitherSeed, device->DitherDepth, - SamplesToDo, device->RealOut.NumChannels); + ApplyDither(RealOut, &device->DitherSeed, device->DitherDepth, SamplesToDo); if(LIKELY(OutBuffer)) { - FloatBufferLine *Buffer{device->RealOut.Buffer}; - ALuint Channels{device->RealOut.NumChannels}; - /* Finally, interleave and convert samples, writing to the device's * output buffer. */ switch(device->FmtType) { #define HANDLE_WRITE(T) case T: \ - Write(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); break; + Write(RealOut, OutBuffer, SamplesDone, SamplesToDo); break; HANDLE_WRITE(DevFmtByte) HANDLE_WRITE(DevFmtUByte) HANDLE_WRITE(DevFmtShort) -- cgit v1.2.3 From 341c68c9a124b41b40294d73f83e96768b5e7097 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Jun 2019 09:41:52 -0700 Subject: Trace the requested and required formats for WASAPI --- Alc/backends/wasapi.cpp | 132 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 94 insertions(+), 38 deletions(-) diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 84e85fe6..976af0d0 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -300,6 +300,96 @@ HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, al::vecto } +bool MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) +{ + *out = WAVEFORMATEXTENSIBLE{}; + if(in->wFormatTag == WAVE_FORMAT_EXTENSIBLE) + { + *out = reinterpret_cast(*in); + out->Format.cbSize = sizeof(*out) - sizeof(out->Format); + } + else if(in->wFormatTag == WAVE_FORMAT_PCM) + { + out->Format = *in; + if(out->Format.nChannels == 1) + out->dwChannelMask = MONO; + else if(out->Format.nChannels == 2) + out->dwChannelMask = STEREO; + else + ERR("Unhandled PCM channel count: %d\n", out->Format.nChannels); + out->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + } + else if(in->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) + { + out->Format = *in; + if(out->Format.nChannels == 1) + out->dwChannelMask = MONO; + else if(out->Format.nChannels == 2) + out->dwChannelMask = STEREO; + else + ERR("Unhandled IEEE float channel count: %d\n", out->Format.nChannels); + out->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + } + else + { + ERR("Unhandled format tag: 0x%04x\n", in->wFormatTag); + return false; + } + return true; +} + +void TraceFormat(const char *msg, const WAVEFORMATEX *format) +{ + constexpr size_t fmtex_extra_size{sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX)}; + if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE && format->cbSize >= fmtex_extra_size) + { + class GuidPrinter { + char mMsg[64]; + + public: + GuidPrinter(const GUID &guid) + { + std::snprintf(mMsg, al::size(mMsg), + "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + DWORD{guid.Data1}, guid.Data2, guid.Data3, + guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], + guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); + } + const char *c_str() const { return mMsg; } + }; + + const WAVEFORMATEXTENSIBLE *fmtex{ + CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format)}; + TRACE("%s:\n" + " FormatTag = 0x%04x\n" + " Channels = %d\n" + " SamplesPerSec = %lu\n" + " AvgBytesPerSec = %lu\n" + " BlockAlign = %d\n" + " BitsPerSample = %d\n" + " Size = %d\n" + " Samples = %d\n" + " ChannelMask = 0x%lx\n" + " SubFormat = %s\n", + msg, fmtex->Format.wFormatTag, fmtex->Format.nChannels, fmtex->Format.nSamplesPerSec, + fmtex->Format.nAvgBytesPerSec, fmtex->Format.nBlockAlign, fmtex->Format.wBitsPerSample, + fmtex->Format.cbSize, fmtex->Samples.wReserved, fmtex->dwChannelMask, + GuidPrinter{fmtex->SubFormat}.c_str()); + } + else + TRACE("%s:\n" + " FormatTag = 0x%04x\n" + " Channels = %d\n" + " SamplesPerSec = %lu\n" + " AvgBytesPerSec = %lu\n" + " BlockAlign = %d\n" + " BitsPerSample = %d\n" + " Size = %d\n", + msg, format->wFormatTag, format->nChannels, format->nSamplesPerSec, + format->nAvgBytesPerSec, format->nBlockAlign, format->wBitsPerSample, format->cbSize); +} + + enum class MsgType : unsigned int { OpenDevice, ResetDevice, @@ -604,44 +694,6 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() } -bool MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) -{ - *out = WAVEFORMATEXTENSIBLE{}; - if(in->wFormatTag == WAVE_FORMAT_EXTENSIBLE) - { - *out = reinterpret_cast(*in); - out->Format.cbSize = sizeof(*out) - sizeof(out->Format); - } - else if(in->wFormatTag == WAVE_FORMAT_PCM) - { - out->Format = *in; - if(out->Format.nChannels == 1) - out->dwChannelMask = MONO; - else if(out->Format.nChannels == 2) - out->dwChannelMask = STEREO; - else - ERR("Unhandled PCM channel count: %d\n", out->Format.nChannels); - out->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - } - else if(in->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) - { - out->Format = *in; - if(out->Format.nChannels == 1) - out->dwChannelMask = MONO; - else if(out->Format.nChannels == 2) - out->dwChannelMask = STEREO; - else - ERR("Unhandled IEEE float channel count: %d\n", out->Format.nChannels); - out->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - } - else - { - ERR("Unhandled format tag: 0x%04x\n", in->wFormatTag); - return false; - } - return true; -} - ALCenum WasapiPlayback::open(const ALCchar *name) { HRESULT hr{S_OK}; @@ -883,6 +935,7 @@ HRESULT WasapiPlayback::resetProxy() OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * OutputType.Format.nBlockAlign; + TraceFormat("Requesting playback format", &OutputType.Format); hr = mClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); if(FAILED(hr)) { @@ -897,6 +950,7 @@ HRESULT WasapiPlayback::resetProxy() if(wfx != nullptr) { + TraceFormat("Got playback format", wfx); if(!MakeExtensible(&OutputType, wfx)) { CoTaskMemFree(wfx); @@ -1414,6 +1468,7 @@ HRESULT WasapiCapture::resetProxy() OutputType.Format.nBlockAlign; OutputType.Format.cbSize = sizeof(OutputType) - sizeof(OutputType.Format); + TraceFormat("Requesting capture format", &OutputType.Format); WAVEFORMATEX *wfx; hr = mClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); if(FAILED(hr)) @@ -1427,6 +1482,7 @@ HRESULT WasapiCapture::resetProxy() if(wfx != nullptr) { + TraceFormat("Got capture format", wfx); if(!(wfx->nChannels == OutputType.Format.nChannels || (wfx->nChannels == 1 && OutputType.Format.nChannels == 2) || (wfx->nChannels == 2 && OutputType.Format.nChannels == 1))) -- cgit v1.2.3 From 2598ee6f0a1d8c81b5b023e617d72934284ac9d7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Jun 2019 09:47:31 -0700 Subject: Properly set extra fields in MakeExtensible --- Alc/backends/wasapi.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 976af0d0..db4b5e4e 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -305,12 +305,14 @@ bool MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) *out = WAVEFORMATEXTENSIBLE{}; if(in->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { - *out = reinterpret_cast(*in); + *out = *CONTAINING_RECORD(in, const WAVEFORMATEXTENSIBLE, Format); out->Format.cbSize = sizeof(*out) - sizeof(out->Format); } else if(in->wFormatTag == WAVE_FORMAT_PCM) { out->Format = *in; + out->Format.cbSize = 0; + out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample; if(out->Format.nChannels == 1) out->dwChannelMask = MONO; else if(out->Format.nChannels == 2) @@ -322,6 +324,8 @@ bool MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) else if(in->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) { out->Format = *in; + out->Format.cbSize = 0; + out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample; if(out->Format.nChannels == 1) out->dwChannelMask = MONO; else if(out->Format.nChannels == 2) -- cgit v1.2.3 From 9326b98e2d2c180453900b7d8b5d31a986c144f9 Mon Sep 17 00:00:00 2001 From: Minmin Gong Date: Thu, 27 Jun 2019 22:29:42 -0700 Subject: Fix the error "a reinterpret_cast is not a constant expression" on GCC 9 --- Alc/alc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index fde655be..2533d5b7 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -188,7 +188,7 @@ BackendInfo CaptureBackend; * Functions, enums, and errors ************************************************/ #define DECL(x) { #x, (ALCvoid*)(x) } -constexpr struct { +const struct { const ALCchar *funcName; ALCvoid *address; } alcFunctions[] = { -- cgit v1.2.3 From 3ede66ae4580913b2dcec44de4481a4e50574bf4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 28 Jun 2019 18:54:31 -0700 Subject: Don't keep retrieving the backend factories --- Alc/alc.cpp | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 2533d5b7..834419c3 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -180,8 +180,8 @@ BackendInfo BackendList[] = { }; auto BackendListEnd = std::end(BackendList); -BackendInfo PlaybackBackend; -BackendInfo CaptureBackend; +BackendFactory *PlaybackFactory{}; +BackendFactory *CaptureFactory{}; /************************************************ @@ -1108,7 +1108,7 @@ static void alc_initconfig(void) auto init_backend = [](BackendInfo &backend) -> bool { - if(PlaybackBackend.name && CaptureBackend.name) + if(PlaybackFactory && CaptureFactory) return true; BackendFactory &factory = backend.getFactory(); @@ -1119,15 +1119,15 @@ static void alc_initconfig(void) } TRACE("Initialized backend \"%s\"\n", backend.name); - if(!PlaybackBackend.name && factory.querySupport(BackendType::Playback)) + if(!PlaybackFactory && factory.querySupport(BackendType::Playback)) { - PlaybackBackend = backend; - TRACE("Added \"%s\" for playback\n", PlaybackBackend.name); + PlaybackFactory = &factory; + TRACE("Added \"%s\" for playback\n", backend.name); } - if(!CaptureBackend.name && factory.querySupport(BackendType::Capture)) + if(!CaptureFactory && factory.querySupport(BackendType::Capture)) { - CaptureBackend = backend; - TRACE("Added \"%s\" for capture\n", CaptureBackend.name); + CaptureFactory = &factory; + TRACE("Added \"%s\" for capture\n", backend.name); } return false; }; @@ -1135,9 +1135,9 @@ static void alc_initconfig(void) LoopbackBackendFactory::getFactory().init(); - if(!PlaybackBackend.name) + if(!PlaybackFactory) WARN("No playback backend available!\n"); - if(!CaptureBackend.name) + if(!CaptureFactory) WARN("No capture backend available!\n"); if(ConfigValueStr(nullptr, nullptr, "excludefx", &str)) @@ -1171,19 +1171,21 @@ static void alc_initconfig(void) /************************************************ * Device enumeration ************************************************/ -static void ProbeDevices(std::string *list, BackendInfo *backendinfo, DevProbe type) +static void ProbeDevices(std::string *list, DevProbe type) { DO_INITCONFIG(); std::lock_guard _{ListLock}; list->clear(); - if(backendinfo->getFactory) - backendinfo->getFactory().probe(type, list); + if(type == DevProbe::Playback && PlaybackFactory) + PlaybackFactory->probe(type, list); + else if(type == DevProbe::Capture && CaptureFactory) + CaptureFactory->probe(type, list); } static void ProbeAllDevicesList(void) -{ ProbeDevices(&alcAllDevicesList, &PlaybackBackend, DevProbe::Playback); } +{ ProbeDevices(&alcAllDevicesList, DevProbe::Playback); } static void ProbeCaptureDeviceList(void) -{ ProbeDevices(&alcCaptureDeviceList, &CaptureBackend, DevProbe::Capture); } +{ ProbeDevices(&alcCaptureDeviceList, DevProbe::Capture); } /************************************************ @@ -3643,7 +3645,7 @@ START_API_FUNC { DO_INITCONFIG(); - if(!PlaybackBackend.name) + if(!PlaybackFactory) { alcSetError(nullptr, ALC_INVALID_VALUE); return nullptr; @@ -3677,8 +3679,7 @@ START_API_FUNC try { /* Create the device backend. */ - device->Backend = PlaybackBackend.getFactory().createBackend(device.get(), - BackendType::Playback); + device->Backend = PlaybackFactory->createBackend(device.get(), BackendType::Playback); /* Find a playback device to open */ ALCenum err{device->Backend->open(deviceName)}; @@ -3901,7 +3902,7 @@ START_API_FUNC { DO_INITCONFIG(); - if(!CaptureBackend.name) + if(!CaptureFactory) { alcSetError(nullptr, ALC_INVALID_VALUE); return nullptr; @@ -3930,8 +3931,7 @@ START_API_FUNC device->BufferSize = samples; try { - device->Backend = CaptureBackend.getFactory().createBackend(device.get(), - BackendType::Capture); + device->Backend = CaptureFactory->createBackend(device.get(), BackendType::Capture); TRACE("Capture format: %s, %s, %uhz, %u / %u buffer\n", DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), -- cgit v1.2.3 From 12911cc533a94c6aa99c0db57394b75d3fcb3f67 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Jun 2019 10:23:29 -0700 Subject: Use a range-for loop to concatenate available backends --- Alc/alc.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 834419c3..23cc4826 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -943,16 +943,21 @@ static void alc_initconfig(void) else ERR("Failed to open log file '%s'\n", str); } - TRACE("Initializing library v%s-%s %s\n", ALSOFT_VERSION, - ALSOFT_GIT_COMMIT_HASH, ALSOFT_GIT_BRANCH); + TRACE("Initializing library v%s-%s %s\n", ALSOFT_VERSION, ALSOFT_GIT_COMMIT_HASH, + ALSOFT_GIT_BRANCH); { std::string names; - if(std::begin(BackendList) != BackendListEnd) - names += BackendList[0].name; - for(auto backend = std::begin(BackendList)+1;backend != BackendListEnd;++backend) + if(std::begin(BackendList) == BackendListEnd) + names += "(none)"; + else { - names += ", "; - names += backend->name; + const al::span infos{std::begin(BackendList), BackendListEnd}; + names += infos[0].name; + for(const auto &backend : infos.subspan(1)) + { + names += ", "; + names += backend.name; + } } TRACE("Supported backends: %s\n", names.c_str()); } -- cgit v1.2.3 From 6790a9b44fd79f430b683cbd7761d174c530b82e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Jun 2019 11:22:29 -0700 Subject: Use a bool for the TrapALError flag --- Alc/alc.cpp | 6 +++--- OpenAL32/Include/alError.h | 2 +- OpenAL32/alError.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 23cc4826..3a083048 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1037,15 +1037,15 @@ static void alc_initconfig(void) str = getenv("ALSOFT_TRAP_ERROR"); if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) { - TrapALError = AL_TRUE; + TrapALError = true; TrapALCError = true; } else { str = getenv("ALSOFT_TRAP_AL_ERROR"); if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) - TrapALError = AL_TRUE; - TrapALError = GetConfigValueBool(nullptr, nullptr, "trap-al-error", TrapALError); + TrapALError = true; + TrapALError = !!GetConfigValueBool(nullptr, nullptr, "trap-al-error", TrapALError); str = getenv("ALSOFT_TRAP_ALC_ERROR"); if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) diff --git a/OpenAL32/Include/alError.h b/OpenAL32/Include/alError.h index 3e4f2373..7b64b302 100644 --- a/OpenAL32/Include/alError.h +++ b/OpenAL32/Include/alError.h @@ -5,7 +5,7 @@ #include "logging.h" -extern ALboolean TrapALError; +extern bool TrapALError; void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) DECL_FORMAT(printf, 3, 4); diff --git a/OpenAL32/alError.cpp b/OpenAL32/alError.cpp index 324f4c1b..a7895fb9 100644 --- a/OpenAL32/alError.cpp +++ b/OpenAL32/alError.cpp @@ -34,7 +34,7 @@ #include "alError.h" #include "alexcpt.h" -ALboolean TrapALError = AL_FALSE; +bool TrapALError{false}; void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) { -- cgit v1.2.3 From b905a224eece5e6679498fddf46d93874b2fb4af Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Jun 2019 11:45:55 -0700 Subject: Avoid a generic function for specialized behavior --- Alc/alc.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 3a083048..60c7e790 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1176,21 +1176,24 @@ static void alc_initconfig(void) /************************************************ * Device enumeration ************************************************/ -static void ProbeDevices(std::string *list, DevProbe type) +static void ProbeAllDevicesList() { DO_INITCONFIG(); std::lock_guard _{ListLock}; - list->clear(); - if(type == DevProbe::Playback && PlaybackFactory) - PlaybackFactory->probe(type, list); - else if(type == DevProbe::Capture && CaptureFactory) - CaptureFactory->probe(type, list); + alcAllDevicesList.clear(); + if(PlaybackFactory) + PlaybackFactory->probe(DevProbe::Playback, &alcAllDevicesList); +} +static void ProbeCaptureDeviceList() +{ + DO_INITCONFIG(); + + std::lock_guard _{ListLock}; + alcCaptureDeviceList.clear(); + if(CaptureFactory) + CaptureFactory->probe(DevProbe::Capture, &alcCaptureDeviceList); } -static void ProbeAllDevicesList(void) -{ ProbeDevices(&alcAllDevicesList, DevProbe::Playback); } -static void ProbeCaptureDeviceList(void) -{ ProbeDevices(&alcCaptureDeviceList, DevProbe::Capture); } /************************************************ -- cgit v1.2.3 From 811d0738fae78946712b17904b5d24c4b4af13ca Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Jun 2019 12:16:38 -0700 Subject: Put some static functions in an anonymous namespace --- Alc/alc.cpp | 70 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 60c7e790..8831cebd 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -887,40 +887,8 @@ al::vector ContextList; std::recursive_mutex ListLock; -} // namespace - -/* Mixing thread piority level */ -ALint RTPrioLevel; - -FILE *gLogFile{stderr}; -#ifdef _DEBUG -LogLevel gLogLevel{LogWarning}; -#else -LogLevel gLogLevel{LogError}; -#endif - -/************************************************ - * Library initialization - ************************************************/ -#if defined(_WIN32) && !defined(AL_LIBTYPE_STATIC) -BOOL APIENTRY DllMain(HINSTANCE module, DWORD reason, LPVOID /*reserved*/) -{ - 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*)module, &module); - break; - - case DLL_PROCESS_DETACH: - break; - } - return TRUE; -} -#endif -static void alc_initconfig(void) +void alc_initconfig(void) { const char *str{getenv("ALSOFT_LOGLEVEL")}; if(str) @@ -1176,7 +1144,7 @@ static void alc_initconfig(void) /************************************************ * Device enumeration ************************************************/ -static void ProbeAllDevicesList() +void ProbeAllDevicesList() { DO_INITCONFIG(); @@ -1185,7 +1153,7 @@ static void ProbeAllDevicesList() if(PlaybackFactory) PlaybackFactory->probe(DevProbe::Playback, &alcAllDevicesList); } -static void ProbeCaptureDeviceList() +void ProbeCaptureDeviceList() { DO_INITCONFIG(); @@ -1195,6 +1163,38 @@ static void ProbeCaptureDeviceList() CaptureFactory->probe(DevProbe::Capture, &alcCaptureDeviceList); } +} // namespace + +/* Mixing thread piority level */ +ALint RTPrioLevel; + +FILE *gLogFile{stderr}; +#ifdef _DEBUG +LogLevel gLogLevel{LogWarning}; +#else +LogLevel gLogLevel{LogError}; +#endif + +/************************************************ + * Library initialization + ************************************************/ +#if defined(_WIN32) && !defined(AL_LIBTYPE_STATIC) +BOOL APIENTRY DllMain(HINSTANCE module, DWORD reason, LPVOID /*reserved*/) +{ + 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*)module, &module); + break; + + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} +#endif /************************************************ * Device format information -- cgit v1.2.3 From c7797fa10fa35e607db61f4a37d0b35761f02e4e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Jun 2019 15:04:20 -0700 Subject: Declare variables closer to their use --- Alc/alc.cpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 8831cebd..0e395a89 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2748,7 +2748,6 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para START_API_FUNC { const ALCchar *value = nullptr; - DeviceRef dev; switch(param) { @@ -2781,8 +2780,7 @@ START_API_FUNC break; case ALC_ALL_DEVICES_SPECIFIER: - dev = VerifyDevice(Device); - if(dev) + if(DeviceRef dev{VerifyDevice(Device)}) value = dev->DeviceName.c_str(); else { @@ -2792,8 +2790,7 @@ START_API_FUNC break; case ALC_CAPTURE_DEVICE_SPECIFIER: - dev = VerifyDevice(Device); - if(dev) + if(DeviceRef dev{VerifyDevice(Device)}) value = dev->DeviceName.c_str(); else { @@ -2826,25 +2823,24 @@ START_API_FUNC break; case ALC_EXTENSIONS: - dev = VerifyDevice(Device); - if(dev) value = alcExtensionList; - else value = alcNoDeviceExtList; + if(VerifyDevice(Device)) + value = alcExtensionList; + else + value = alcNoDeviceExtList; break; case ALC_HRTF_SPECIFIER_SOFT: - dev = VerifyDevice(Device); - if(!dev) - alcSetError(nullptr, ALC_INVALID_DEVICE); - else + if(DeviceRef dev{VerifyDevice(Device)}) { std::lock_guard _{dev->StateLock}; value = (dev->mHrtf ? dev->HrtfName.c_str() : ""); } + else + alcSetError(nullptr, ALC_INVALID_DEVICE); break; default: - dev = VerifyDevice(Device); - alcSetError(dev.get(), ALC_INVALID_ENUM); + alcSetError(VerifyDevice(Device).get(), ALC_INVALID_ENUM); break; } -- cgit v1.2.3 From cbcee69ed14fb23db28bf36ef726a8d0f10d0a40 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Jun 2019 18:53:20 -0700 Subject: Add an empty() method to FlexArray --- common/almalloc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/almalloc.h b/common/almalloc.h index d649716c..23f9edce 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -185,13 +185,13 @@ struct FlexArray { FlexArray(index_type size) : mSize{size} { uninitialized_default_construct_n(mArray, mSize); } - ~FlexArray() - { destroy_n(mArray, mSize); } + ~FlexArray() { destroy_n(mArray, mSize); } FlexArray(const FlexArray&) = delete; FlexArray& operator=(const FlexArray&) = delete; index_type size() const noexcept { return mSize; } + bool empty() const noexcept { return mSize == 0; } pointer data() noexcept { return mArray; } const_pointer data() const noexcept { return mArray; } -- cgit v1.2.3 From 7303e22d895e64fb24b257c3b65a1744ac4020ba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Jun 2019 21:32:36 -0700 Subject: Use a FlexArray for a device's contexts --- Alc/alc.cpp | 127 ++++++++++++++++++++++++++++++---------------- Alc/alcontext.h | 2 - Alc/alu.cpp | 12 +---- OpenAL32/Include/alMain.h | 2 +- 4 files changed, 85 insertions(+), 58 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 0e395a89..e3eedbfa 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -879,6 +879,12 @@ constexpr ALCint alcEFXMajorVersion = 1; constexpr ALCint alcEFXMinorVersion = 0; +/* To avoid extraneous allocations, a 0-sized FlexArray is defined + * globally as a sharable object. + */ +al::FlexArray EmptyContextArray{0u}; + + /************************************************ * Device lists ************************************************/ @@ -1598,7 +1604,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) DevFmtType oldType; ALboolean update_failed; ALCsizei hrtf_id = -1; - ALCcontext *context; ALCuint oldFreq; int val; @@ -2105,8 +2110,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) */ update_failed = AL_FALSE; FPUCtl mixer_mode{}; - context = device->ContextList.load(); - while(context) + for(ALCcontext *context : *device->mContexts.load()) { if(context->DefaultSlot) { @@ -2246,8 +2250,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) context->Listener.PropsClean.test_and_set(std::memory_order_release); UpdateListenerProps(context); UpdateAllSourceProps(context); - - context = context->next.load(std::memory_order_relaxed); } mixer_mode.leave(); if(update_failed) @@ -2264,7 +2266,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } -ALCdevice::ALCdevice(DeviceType type) : Type{type} +ALCdevice::ALCdevice(DeviceType type) : Type{type}, mContexts{&EmptyContextArray} { } @@ -2303,6 +2305,9 @@ ALCdevice::~ALCdevice() if(mHrtf) mHrtf->DecRef(); mHrtf = nullptr; + + auto *oldarray = mContexts.exchange(nullptr, std::memory_order_relaxed); + if(oldarray != &EmptyContextArray) delete oldarray; } @@ -2563,30 +2568,45 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) if(GlobalContext.compare_exchange_strong(origctx, nullptr)) ALCcontext_DecRef(context); - bool ret{true}; - { BackendLockGuard _{*device->Backend}; - origctx = context; - ALCcontext *newhead{context->next.load(std::memory_order_relaxed)}; - if(!device->ContextList.compare_exchange_strong(origctx, newhead)) + bool ret{}; + { + using ContextArray = al::FlexArray; + + /* First make sure this context exists in the device's list. */ + auto *oldarray = device->mContexts.load(std::memory_order_acquire); + if(auto toremove = std::count(oldarray->begin(), oldarray->end(), context)) { - ALCcontext *list; - do { - /* origctx is what the desired context failed to match. Try - * swapping out the next one in the list. - */ - list = origctx; - origctx = context; - } while(!list->next.compare_exchange_strong(origctx, newhead)); + auto alloc_ctx_array = [](const size_t count) -> ContextArray* + { + if(count == 0) return &EmptyContextArray; + void *ptr{al_calloc(alignof(ContextArray), ContextArray::Sizeof(count))}; + return new (ptr) ContextArray{count}; + }; + auto *newarray = alloc_ctx_array(oldarray->size() - toremove); + + /* Copy the current/old context handles to the new array, excluding + * the given context. + */ + std::copy_if(oldarray->begin(), oldarray->end(), newarray->begin(), + std::bind(std::not_equal_to{}, _1, context)); + + /* Store the new context array in the device. Wait for any current + * mix to finish before deleting the old array. + */ + device->mContexts.store(newarray); + if(oldarray != &EmptyContextArray) + { + while((device->MixCount.load(std::memory_order_acquire)&1)) + std::this_thread::yield(); + delete oldarray; + } + + ret = !newarray->empty(); } else - ret = !!newhead; + ret = !oldarray->empty(); } - /* Make sure the context is finished and no longer processing in the mixer - * before sending the message queue kill event. The backend's lock does - * this, although waiting for a non-odd mix count would work too. - */ - StopEventThrd(context); ALCcontext_DecRef(context); @@ -3473,20 +3493,42 @@ START_API_FUNC UpdateListenerProps(context.get()); { + using ContextArray = al::FlexArray; + + /* Allocate a new context array, which holds 1 more than the current/ + * old array. + */ + auto *oldarray = device->mContexts.load(); + const size_t newcount{oldarray->size()+1}; + void *ptr{al_calloc(alignof(ContextArray), ContextArray::Sizeof(newcount))}; + auto *newarray = new (ptr) ContextArray{newcount}; + + /* Copy the current/old context handles to the new array, appending the + * new context. + */ + auto iter = std::copy(oldarray->begin(), oldarray->end(), newarray->begin()); + *iter = context.get(); + + /* Store the new context array in the device. Wait for any current mix + * to finish before deleting the old array. + */ + dev->mContexts.store(newarray); + if(oldarray != &EmptyContextArray) { - std::lock_guard _{ListLock}; - auto iter = std::lower_bound(ContextList.cbegin(), ContextList.cend(), context.get()); - ContextList.insert(iter, context.get()); - ALCcontext_IncRef(context.get()); + while((dev->MixCount.load(std::memory_order_acquire)&1)) + std::this_thread::yield(); + delete oldarray; } - - ALCcontext *head = dev->ContextList.load(); - do { - context->next.store(head, std::memory_order_relaxed); - } while(!dev->ContextList.compare_exchange_weak(head, context.get())); } statelock.unlock(); + { + std::lock_guard _{ListLock}; + auto iter = std::lower_bound(ContextList.cbegin(), ContextList.cend(), context.get()); + ContextList.insert(iter, context.get()); + ALCcontext_IncRef(context.get()); + } + if(context->DefaultSlot) { if(InitializeEffect(context.get(), context->DefaultSlot.get(), &DefaultEffect) == AL_NO_ERROR) @@ -3867,24 +3909,19 @@ START_API_FUNC * respective lists. */ DeviceList.erase(iter); - ALCcontext *ctx{device->ContextList.load()}; - while(ctx != nullptr) + for(ALCcontext *ctx : *device->mContexts.load()) { - ALCcontext *next = ctx->next.load(std::memory_order_relaxed); auto iter = std::lower_bound(ContextList.cbegin(), ContextList.cend(), ctx); if(iter != ContextList.cend() && *iter == ctx) ContextList.erase(iter); - ctx = next; } listlock.unlock(); - ctx = device->ContextList.load(std::memory_order_relaxed); - while(ctx != nullptr) + al::FlexArray *contexts; + while(!(contexts=device->mContexts.load(std::memory_order_relaxed))->empty()) { - ALCcontext *next = ctx->next.load(std::memory_order_relaxed); - WARN("Releasing context %p\n", ctx); - ReleaseContext(ctx, device); - ctx = next; + WARN("Releasing context %p\n", contexts->front()); + ReleaseContext(contexts->front(), device); } if(device->Flags.get()) device->Backend->stop(); @@ -4221,7 +4258,7 @@ START_API_FUNC if(!dev->Flags.get()) return; dev->Flags.unset(); - if(dev->ContextList.load() == nullptr) + if(dev->mContexts.load()->empty()) return; if(dev->Backend->start() == ALC_FALSE) diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 1887e341..0e3b864e 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -136,8 +136,6 @@ struct ALCcontext { ALCdevice *const Device; const ALCchar *ExtensionList{nullptr}; - std::atomic next{nullptr}; - ALlistener Listener{}; diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 846d9aea..094f0dc6 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1658,14 +1658,9 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) /* For each context on this device, process and mix its sources and * effects. */ - ALCcontext *ctx{device->ContextList.load(std::memory_order_acquire)}; - while(ctx) - { + for(ALCcontext *ctx : *device->mContexts.load(std::memory_order_acquire)) ProcessContext(ctx, SamplesToDo); - ctx = ctx->next.load(std::memory_order_relaxed); - } - /* Increment the clock time. Every second's worth of samples is * converted and added to clock base so that large sample counts don't * overflow during conversion. This also guarantees a stable @@ -1754,8 +1749,7 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) if(msglen < 0 || static_cast(msglen) >= sizeof(evt.u.user.msg)) evt.u.user.msg[sizeof(evt.u.user.msg)-1] = 0; - ALCcontext *ctx{device->ContextList.load()}; - while(ctx) + for(ALCcontext *ctx : *device->mContexts.load()) { const ALbitfieldSOFT enabledevt{ctx->EnabledEvts.load(std::memory_order_acquire)}; if((enabledevt&EventType_Disconnected)) @@ -1780,7 +1774,5 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) std::for_each(ctx->Voices->begin(), ctx->Voices->begin() + ctx->VoiceCount.load(std::memory_order_acquire), stop_voice); - - ctx = ctx->next.load(std::memory_order_relaxed); } } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 80167417..016cc535 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -461,7 +461,7 @@ struct ALCdevice { RefCount MixCount{0u}; // Contexts created on this device - std::atomic ContextList{nullptr}; + std::atomic*> mContexts{nullptr}; /* This lock protects the device state (format, update size, etc) from * being from being changed in multiple threads, or being accessed while -- cgit v1.2.3 From ada86d2fcf0731fb328c04be9166de659377de59 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Jun 2019 22:38:38 -0700 Subject: Hold references in the global device and context lists --- Alc/alc.cpp | 215 ++++++++++++++++++++++++++++---------------------------- Alc/alcontext.h | 11 ++- 2 files changed, 118 insertions(+), 108 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index e3eedbfa..fb6e15e4 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -885,11 +885,73 @@ constexpr ALCint alcEFXMinorVersion = 0; al::FlexArray EmptyContextArray{0u}; +void ALCdevice_IncRef(ALCdevice *device) +{ + auto ref = IncrementRef(&device->ref); + TRACEREF("ALCdevice %p increasing refcount to %u\n", device, ref); +} + +void ALCdevice_DecRef(ALCdevice *device) +{ + auto ref = DecrementRef(&device->ref); + TRACEREF("ALCdevice %p decreasing refcount to %u\n", device, ref); + if(UNLIKELY(ref == 0)) delete device; +} + +/* Simple RAII device reference. Takes the reference of the provided ALCdevice, + * and decrements it when leaving scope. Movable (transfer reference) but not + * copyable (no new references). + */ +class DeviceRef { + ALCdevice *mDev{nullptr}; + + void reset() noexcept + { + if(mDev) + ALCdevice_DecRef(mDev); + mDev = nullptr; + } + +public: + DeviceRef() noexcept = default; + DeviceRef(DeviceRef&& rhs) noexcept : mDev{rhs.mDev} + { rhs.mDev = nullptr; } + explicit DeviceRef(ALCdevice *dev) noexcept : mDev(dev) { } + ~DeviceRef() { reset(); } + + DeviceRef& operator=(const DeviceRef&) = delete; + DeviceRef& operator=(DeviceRef&& rhs) noexcept + { + std::swap(mDev, rhs.mDev); + return *this; + } + + operator bool() const noexcept { return mDev != nullptr; } + + ALCdevice* operator->() const noexcept { return mDev; } + ALCdevice* get() const noexcept { return mDev; } + + ALCdevice* release() noexcept + { + ALCdevice *ret{mDev}; + mDev = nullptr; + return ret; + } +}; + +inline bool operator==(const DeviceRef &lhs, const ALCdevice *rhs) noexcept +{ return lhs.get() == rhs; } +inline bool operator!=(const DeviceRef &lhs, const ALCdevice *rhs) noexcept +{ return !(lhs == rhs); } +inline bool operator<(const DeviceRef &lhs, const ALCdevice *rhs) noexcept +{ return lhs.get() < rhs; } + + /************************************************ * Device lists ************************************************/ -al::vector DeviceList; -al::vector ContextList; +al::vector DeviceList; +al::vector ContextList; std::recursive_mutex ListLock; @@ -2311,63 +2373,6 @@ ALCdevice::~ALCdevice() } -static void ALCdevice_IncRef(ALCdevice *device) -{ - auto ref = IncrementRef(&device->ref); - TRACEREF("ALCdevice %p increasing refcount to %u\n", device, ref); -} - -static void ALCdevice_DecRef(ALCdevice *device) -{ - auto ref = DecrementRef(&device->ref); - TRACEREF("ALCdevice %p decreasing refcount to %u\n", device, ref); - if(UNLIKELY(ref == 0)) delete device; -} - -/* Simple RAII device reference. Takes the reference of the provided ALCdevice, - * and decrements it when leaving scope. Movable (transfer reference) but not - * copyable (no new references). - */ -class DeviceRef { - ALCdevice *mDev{nullptr}; - - void reset() noexcept - { - if(mDev) - ALCdevice_DecRef(mDev); - mDev = nullptr; - } - -public: - DeviceRef() noexcept = default; - DeviceRef(DeviceRef&& rhs) noexcept : mDev{rhs.mDev} - { rhs.mDev = nullptr; } - explicit DeviceRef(ALCdevice *dev) noexcept : mDev(dev) { } - ~DeviceRef() { reset(); } - - DeviceRef& operator=(const DeviceRef&) = delete; - DeviceRef& operator=(DeviceRef&& rhs) noexcept - { - reset(); - mDev = rhs.mDev; - rhs.mDev = nullptr; - return *this; - } - - operator bool() const noexcept { return mDev != nullptr; } - - ALCdevice* operator->() noexcept { return mDev; } - ALCdevice* get() noexcept { return mDev; } - - ALCdevice* release() noexcept - { - ALCdevice *ret{mDev}; - mDev = nullptr; - return ret; - } -}; - - /* VerifyDevice * * Checks if the device handle is valid, and returns a new reference if so. @@ -2378,8 +2383,8 @@ static DeviceRef VerifyDevice(ALCdevice *device) auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device); if(iter != DeviceList.cend() && *iter == device) { - ALCdevice_IncRef(*iter); - return DeviceRef{*iter}; + ALCdevice_IncRef(iter->get()); + return DeviceRef{iter->get()}; } return DeviceRef{}; } @@ -2609,7 +2614,6 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) StopEventThrd(context); - ALCcontext_DecRef(context); return ret; } @@ -2636,8 +2640,8 @@ static ContextRef VerifyContext(ALCcontext *context) auto iter = std::lower_bound(ContextList.cbegin(), ContextList.cend(), context); if(iter != ContextList.cend() && *iter == context) { - ALCcontext_IncRef(*iter); - return ContextRef{*iter}; + ALCcontext_IncRef(iter->get()); + return ContextRef{iter->get()}; } return ContextRef{}; } @@ -3525,8 +3529,8 @@ START_API_FUNC { std::lock_guard _{ListLock}; auto iter = std::lower_bound(ContextList.cbegin(), ContextList.cend(), context.get()); - ContextList.insert(iter, context.get()); ALCcontext_IncRef(context.get()); + ContextList.insert(iter, ContextRef{context.get()}); } if(context->DefaultSlot) @@ -3550,8 +3554,8 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) START_API_FUNC { std::unique_lock listlock{ListLock}; - auto iter = std::lower_bound(ContextList.cbegin(), ContextList.cend(), context); - if(iter == ContextList.cend() || *iter != context) + auto iter = std::lower_bound(ContextList.begin(), ContextList.end(), context); + if(iter == ContextList.end() || *iter != context) { listlock.unlock(); alcSetError(nullptr, ALC_INVALID_CONTEXT); @@ -3560,20 +3564,17 @@ START_API_FUNC /* Hold an extra reference to this context so it remains valid until the * ListLock is released. */ - ALCcontext_IncRef(*iter); - ContextRef ctx{*iter}; + ContextRef ctx{std::move(*iter)}; ContextList.erase(iter); - if(ALCdevice *Device{ctx->Device}) + ALCdevice *Device{ctx->Device}; + + std::lock_guard _{Device->StateLock}; + if(!ReleaseContext(ctx.get(), Device) && Device->Flags.get()) { - std::lock_guard _{Device->StateLock}; - if(!ReleaseContext(ctx.get(), Device) && Device->Flags.get()) - { - Device->Backend->stop(); - Device->Flags.unset(); - } + Device->Backend->stop(); + Device->Flags.unset(); } - listlock.unlock(); } END_API_FUNC @@ -3875,8 +3876,8 @@ START_API_FUNC { std::lock_guard _{ListLock}; auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get()); - DeviceList.insert(iter, device.get()); ALCdevice_IncRef(device.get()); + DeviceList.insert(iter, DeviceRef{device.get()}); } TRACE("Created device %p, \"%s\"\n", device.get(), device->DeviceName.c_str()); @@ -3892,43 +3893,47 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) START_API_FUNC { std::unique_lock listlock{ListLock}; - auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device); - if(iter == DeviceList.cend() || *iter != device) + auto iter = std::lower_bound(DeviceList.begin(), DeviceList.end(), device); + if(iter == DeviceList.end() || *iter != device) { alcSetError(nullptr, ALC_INVALID_DEVICE); return ALC_FALSE; } if((*iter)->Type == Capture) { - alcSetError(*iter, ALC_INVALID_DEVICE); + alcSetError(iter->get(), ALC_INVALID_DEVICE); return ALC_FALSE; } - std::unique_lock statelock{device->StateLock}; /* Erase the device, and any remaining contexts left on it, from their * respective lists. */ + DeviceRef dev{std::move(*iter)}; DeviceList.erase(iter); - for(ALCcontext *ctx : *device->mContexts.load()) + + std::unique_lock statelock{dev->StateLock}; + al::vector orphanctxs; + for(ALCcontext *ctx : *dev->mContexts.load()) { - auto iter = std::lower_bound(ContextList.cbegin(), ContextList.cend(), ctx); - if(iter != ContextList.cend() && *iter == ctx) + auto iter = std::lower_bound(ContextList.begin(), ContextList.end(), ctx); + if(iter != ContextList.end() && *iter == ctx) + { + orphanctxs.emplace_back(std::move(*iter)); ContextList.erase(iter); + } } listlock.unlock(); - al::FlexArray *contexts; - while(!(contexts=device->mContexts.load(std::memory_order_relaxed))->empty()) + for(ContextRef &context : orphanctxs) { - WARN("Releasing context %p\n", contexts->front()); - ReleaseContext(contexts->front(), device); + WARN("Releasing context %p\n", context.get()); + ReleaseContext(context.get(), dev.get()); } - if(device->Flags.get()) - device->Backend->stop(); - device->Flags.unset(); - statelock.unlock(); + orphanctxs.clear(); - ALCdevice_DecRef(device); + if(dev->Flags.get()) + dev->Backend->stop(); + dev->Flags.unset(); return ALC_TRUE; } @@ -3993,8 +3998,8 @@ START_API_FUNC { std::lock_guard _{ListLock}; auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get()); - DeviceList.insert(iter, device.get()); ALCdevice_IncRef(device.get()); + DeviceList.insert(iter, DeviceRef{device.get()}); } TRACE("Created device %p, \"%s\"\n", device.get(), device->DeviceName.c_str()); @@ -4006,28 +4011,26 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) START_API_FUNC { std::unique_lock listlock{ListLock}; - auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device); - if(iter == DeviceList.cend() || *iter != device) + auto iter = std::lower_bound(DeviceList.begin(), DeviceList.end(), device); + if(iter == DeviceList.end() || *iter != device) { alcSetError(nullptr, ALC_INVALID_DEVICE); return ALC_FALSE; } if((*iter)->Type != Capture) { - alcSetError(*iter, ALC_INVALID_DEVICE); + alcSetError(iter->get(), ALC_INVALID_DEVICE); return ALC_FALSE; } + DeviceRef dev{std::move(*iter)}; DeviceList.erase(iter); listlock.unlock(); - { std::lock_guard _{device->StateLock}; - if(device->Flags.get()) - device->Backend->stop(); - device->Flags.unset(); - } - - ALCdevice_DecRef(device); + std::lock_guard _{dev->StateLock}; + if(dev->Flags.get()) + dev->Backend->stop(); + dev->Flags.unset(); return ALC_TRUE; } @@ -4162,8 +4165,8 @@ START_API_FUNC { std::lock_guard _{ListLock}; auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get()); - DeviceList.insert(iter, device.get()); ALCdevice_IncRef(device.get()); + DeviceList.insert(iter, DeviceRef{device.get()}); } TRACE("Created device %p\n", device.get()); diff --git a/Alc/alcontext.h b/Alc/alcontext.h index 0e3b864e..cf956079 100644 --- a/Alc/alcontext.h +++ b/Alc/alcontext.h @@ -182,8 +182,8 @@ public: operator bool() const noexcept { return mCtx != nullptr; } - ALCcontext* operator->() noexcept { return mCtx; } - ALCcontext* get() noexcept { return mCtx; } + ALCcontext* operator->() const noexcept { return mCtx; } + ALCcontext* get() const noexcept { return mCtx; } ALCcontext* release() noexcept { @@ -193,6 +193,13 @@ public: } }; +inline bool operator==(const ContextRef &lhs, const ALCcontext *rhs) noexcept +{ return lhs.get() == rhs; } +inline bool operator!=(const ContextRef &lhs, const ALCcontext *rhs) noexcept +{ return !(lhs == rhs); } +inline bool operator<(const ContextRef &lhs, const ALCcontext *rhs) noexcept +{ return lhs.get() < rhs; } + ContextRef GetContextRef(void); -- cgit v1.2.3 From 541a9383a734d528f4461af953efe9652203af00 Mon Sep 17 00:00:00 2001 From: Lopuska Date: Sun, 30 Jun 2019 23:17:13 +0200 Subject: avoid extra local member declaration --- Alc/effects/modulator.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index 131d275b..39f1aa04 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -142,16 +142,14 @@ void ModulatorState::update(const ALCcontext *context, const ALeffectslot *slot, void ModulatorState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) { - const ALsizei step{mStep}; - for(ALsizei base{0};base < samplesToDo;) { alignas(16) ALfloat modsamples[MAX_UPDATE_SAMPLES]; ALsizei td = mini(MAX_UPDATE_SAMPLES, samplesToDo-base); ALsizei c, i; - mGetSamples(modsamples, mIndex, step, td); - mIndex += (step*td) & WAVEFORM_FRACMASK; + mGetSamples(modsamples, mIndex, mStep, td); + mIndex += (mStep*td) & WAVEFORM_FRACMASK; mIndex &= WAVEFORM_FRACMASK; ASSUME(numInput > 0); -- cgit v1.2.3 From 689f70ce6d6b27ea2ccf7463e79dfefe5ce35899 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2019 11:21:29 -0700 Subject: Add a simple optional<> implementation --- CMakeLists.txt | 1 + common/aloptional.h | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 common/aloptional.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 37b55e28..13a714ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -635,6 +635,7 @@ SET(COMMON_OBJS common/almalloc.cpp common/almalloc.h common/alnumeric.h + common/aloptional.h common/alspan.h common/atomic.h common/math_defs.h diff --git a/common/aloptional.h b/common/aloptional.h new file mode 100644 index 00000000..75891329 --- /dev/null +++ b/common/aloptional.h @@ -0,0 +1,112 @@ +#ifndef AL_OPTIONAL_H +#define AL_OPTIONAL_H + +#include + +namespace al { + +#define REQUIRES(...) bool _rt=true, typename std::enable_if<_rt && (__VA_ARGS__),int>::type = 0 + +struct nullopt_t { }; +struct in_place_t { }; + +constexpr nullopt_t nullopt{}; +constexpr in_place_t in_place{}; + +template +class optional { +public: + using value_type = T; + + optional() noexcept = default; + optional(nullopt_t) noexcept { } + template::value)> + optional(const optional &rhs) : mHasValue{rhs.mHasValue} + { + if(mHasValue) + new (&mValue) T{*rhs}; + } + template::value)> + optional(optional&& rhs) : mHasValue{rhs.mHasValue} + { + if(mHasValue) + new (&mValue) T{std::move(*rhs)}; + } + template + explicit optional(in_place_t, Args&& ...args) + : mHasValue{true}, mValue{std::forward(args)...} + { } + template::value)> + optional(const optional&) noexcept = delete; + ~optional() { reset(); } + + optional& operator=(nullopt_t) noexcept { reset(); } + template::value && std::is_copy_assignable::value)> + optional& operator=(const optional &rhs) + { + if(!rhs) + reset(); + else + { + mValue = *rhs; + mHasValue = true; + } + return *this; + } + template::value && std::is_move_assignable::value)> + optional& operator=(optional&& rhs) + { + if(!rhs) + reset(); + else + { + mValue = std::move(*rhs); + mHasValue = true; + } + return *this; + } + template::value || !std::is_copy_assignable::value)> + optional& operator=(const optional&) = delete; + + const T* operator->() const { return &mValue; } + T* operator->() { return &mValue; } + const T& operator*() const& { return mValue; } + T& operator*() & { return mValue; } + const T&& operator*() const&& { return std::move(mValue); } + T&& operator*() && { return std::move(mValue); } + + operator bool() const noexcept { return mHasValue; } + bool has_value() const noexcept { return mHasValue; } + + T& value() & { return mValue; } + const T& value() const& { return mValue; } + T&& value() && { return std::move(mValue); } + const T&& value() const&& { return std::move(mValue); } + + template + T value_or(U&& defval) const& + { return bool{*this} ? **this : static_cast(std::forward(defval)); } + template + T value_or(U&& defval) && + { return bool{*this} ? std::move(**this) : static_cast(std::forward(defval)); } + + void reset() noexcept + { + if(mHasValue) + mValue.~T(); + mHasValue = false; + } + +private: + bool mHasValue{false}; + union { + char mDummy[sizeof(T)]{}; + T mValue; + }; +}; + +#undef REQUIRES + +} // namespace al + +#endif /* AL_SPAN_H */ -- cgit v1.2.3 From 51f53afe12719513b3736a1c73e7de98d7e301ca Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2019 12:00:10 -0700 Subject: Use an optional for ConfigValueInt --- Alc/alc.cpp | 33 +++++++++++++++------------------ Alc/alconfig.cpp | 7 +++---- Alc/alconfig.h | 3 ++- Alc/backends/portaudio.cpp | 12 ++++++------ Alc/panning.cpp | 22 ++++++++++++---------- 5 files changed, 38 insertions(+), 39 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index fb6e15e4..2863b4c7 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1061,11 +1061,12 @@ void alc_initconfig(void) FillCPUCaps(capfilter); #ifdef _WIN32 - RTPrioLevel = 1; +#define DEF_MIXER_PRIO 1 #else - RTPrioLevel = 0; +#define DEF_MIXER_PRIO 0 #endif - ConfigValueInt(nullptr, nullptr, "rt-prio", &RTPrioLevel); + RTPrioLevel = ConfigValueInt(nullptr, nullptr, "rt-prio").value_or(DEF_MIXER_PRIO); +#undef DEF_MIXER_PRIO aluInit(); aluInitMixer(); @@ -1864,10 +1865,10 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(numMono > INT_MAX-numStereo) numMono = INT_MAX-numStereo; numMono += numStereo; - if(ConfigValueInt(devname, nullptr, "sources", &numMono)) + if(auto srcsopt = ConfigValueInt(devname, nullptr, "sources")) { - if(numMono <= 0) - numMono = 256; + if(*srcsopt <= 0) numMono = 256; + else numMono = *srcsopt; } else numMono = maxi(numMono, 256); @@ -1878,8 +1879,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->NumMonoSources = numMono; device->NumStereoSources = numStereo; - if(ConfigValueInt(devname, nullptr, "sends", &new_sends)) - new_sends = mini(numSends, clampi(new_sends, 0, MAX_SENDS)); + if(auto sendsopt = ConfigValueInt(devname, nullptr, "sends")) + new_sends = mini(numSends, clampi(*sendsopt, 0, MAX_SENDS)); else new_sends = numSends; } @@ -2075,8 +2076,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(GetConfigValueBool(device->DeviceName.c_str(), nullptr, "dither", 1)) { - ALint depth = 0; - ConfigValueInt(device->DeviceName.c_str(), nullptr, "dither-depth", &depth); + ALint depth{ + ConfigValueInt(device->DeviceName.c_str(), nullptr, "dither-depth").value_or(0)}; if(depth <= 0) { switch(device->FmtType) @@ -3834,10 +3835,8 @@ START_API_FUNC if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 64; else device->AuxiliaryEffectSlotMax = minu(device->AuxiliaryEffectSlotMax, INT_MAX); - if(ConfigValueInt(deviceName, nullptr, "sends", &device->NumAuxSends)) - device->NumAuxSends = clampi( - DEFAULT_SENDS, 0, clampi(device->NumAuxSends, 0, MAX_SENDS) - ); + if(auto sendsopt = ConfigValueInt(deviceName, nullptr, "sends")) + device->NumAuxSends = clampi(DEFAULT_SENDS, 0, clampi(*sendsopt, 0, MAX_SENDS)); device->NumStereoSources = 1; device->NumMonoSources = device->SourcesMax - device->NumStereoSources; @@ -4141,10 +4140,8 @@ START_API_FUNC if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 64; else device->AuxiliaryEffectSlotMax = minu(device->AuxiliaryEffectSlotMax, INT_MAX); - if(ConfigValueInt(nullptr, nullptr, "sends", &device->NumAuxSends)) - device->NumAuxSends = clampi( - DEFAULT_SENDS, 0, clampi(device->NumAuxSends, 0, MAX_SENDS) - ); + if(auto sendsopt = ConfigValueInt(nullptr, nullptr, "sends")) + device->NumAuxSends = clampi(DEFAULT_SENDS, 0, clampi(*sendsopt, 0, MAX_SENDS)); device->NumStereoSources = 1; device->NumMonoSources = device->SourcesMax - device->NumStereoSources; diff --git a/Alc/alconfig.cpp b/Alc/alconfig.cpp index 710c790c..00643043 100644 --- a/Alc/alconfig.cpp +++ b/Alc/alconfig.cpp @@ -501,13 +501,12 @@ int ConfigValueStr(const char *devName, const char *blockName, const char *keyNa return 1; } -int ConfigValueInt(const char *devName, const char *blockName, const char *keyName, int *ret) +al::optional ConfigValueInt(const char *devName, const char *blockName, const char *keyName) { const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return 0; + if(!val[0]) return al::nullopt; - *ret = std::strtol(val, nullptr, 0); - return 1; + return al::optional{al::in_place, static_cast(std::strtol(val, nullptr, 0))}; } int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret) diff --git a/Alc/alconfig.h b/Alc/alconfig.h index 290172a8..e6977101 100644 --- a/Alc/alconfig.h +++ b/Alc/alconfig.h @@ -1,6 +1,7 @@ #ifndef ALCONFIG_H #define ALCONFIG_H +#include "aloptional.h" void ReadALConfig(); @@ -9,7 +10,7 @@ const char *GetConfigValue(const char *devName, const char *blockName, const cha int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def); int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret); -int ConfigValueInt(const char *devName, const char *blockName, const char *keyName, int *ret); +al::optional ConfigValueInt(const char *devName, const char *blockName, const char *keyName); int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret); int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret); int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret); diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index 990fcbf6..5277f36b 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -129,9 +129,9 @@ ALCenum PortPlayback::open(const ALCchar *name) mUpdateSize = mDevice->UpdateSize; - mParams.device = -1; - if(!ConfigValueInt(nullptr, "port", "device", &mParams.device) || mParams.device < 0) - mParams.device = Pa_GetDefaultOutputDevice(); + auto devidopt = ConfigValueInt(nullptr, "port", "device"); + if(devidopt && *devidopt >= 0) mParams.device = *devidopt; + else mParams.device = Pa_GetDefaultOutputDevice(); mParams.suggestedLatency = mDevice->BufferSize / static_cast(mDevice->Frequency); mParams.hostApiSpecificStreamInfo = nullptr; @@ -298,9 +298,9 @@ ALCenum PortCapture::open(const ALCchar *name) mRing = CreateRingBuffer(samples, frame_size, false); if(!mRing) return ALC_INVALID_VALUE; - mParams.device = -1; - if(!ConfigValueInt(nullptr, "port", "capture", &mParams.device) || mParams.device < 0) - mParams.device = Pa_GetDefaultInputDevice(); + auto devidopt = ConfigValueInt(nullptr, "port", "capture"); + if(devidopt && *devidopt >= 0) mParams.device = *devidopt; + else mParams.device = Pa_GetDefaultOutputDevice(); mParams.suggestedLatency = 0.0f; mParams.hostApiSpecificStreamInfo = nullptr; diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 41e827ef..864d7f28 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -900,18 +900,20 @@ no_hrtf: device->mRenderMode = StereoPair; - int bs2blevel{((headphones && hrtf_appreq != Hrtf_Disable) || - (hrtf_appreq == Hrtf_Enable)) ? 5 : 0}; if(device->Type != Loopback) - ConfigValueInt(device->DeviceName.c_str(), nullptr, "cf_level", &bs2blevel); - if(bs2blevel > 0 && bs2blevel <= 6) { - device->Bs2b = al::make_unique(); - bs2b_set_params(device->Bs2b.get(), bs2blevel, device->Frequency); - TRACE("BS2B enabled\n"); - InitPanning(device); - device->PostProcess = ProcessBs2b; - return; + if(auto cflevopt = ConfigValueInt(device->DeviceName.c_str(), nullptr, "cf_level")) + { + if(*cflevopt > 0 && *cflevopt <= 6) + { + device->Bs2b = al::make_unique(); + bs2b_set_params(device->Bs2b.get(), *cflevopt, device->Frequency); + TRACE("BS2B enabled\n"); + InitPanning(device); + device->PostProcess = ProcessBs2b; + return; + } + } } const char *mode; -- cgit v1.2.3 From 0fc30151f2053346005ce9f15da38363a9e62313 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2019 13:04:23 -0700 Subject: Use an optional for ConfigValueUInt --- Alc/alc.cpp | 51 ++++++++++++++++++++++++++++----------------------- Alc/alconfig.cpp | 8 ++++---- Alc/alconfig.h | 2 +- Alc/backends/jack.cpp | 12 ++++++------ 4 files changed, 39 insertions(+), 34 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 2863b4c7..ec9953fe 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1824,7 +1824,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->UpdateSize = DEFAULT_UPDATE_SIZE; device->Frequency = DEFAULT_OUTPUT_RATE; - ConfigValueUInt(devname, nullptr, "frequency", &freq); + freq = ConfigValueUInt(devname, nullptr, "frequency").value_or(freq); if(freq < 1) device->Flags.unset(); else @@ -1840,12 +1840,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->Flags.set(); } - ConfigValueUInt(devname, nullptr, "period_size", &device->UpdateSize); - device->UpdateSize = clampu(device->UpdateSize, 64, 8192); + if(auto persizeopt = ConfigValueUInt(devname, nullptr, "period_size")) + device->UpdateSize = clampu(*persizeopt, 64, 8192); - ALuint periods{}; - if(ConfigValueUInt(devname, nullptr, "periods", &periods)) - device->BufferSize = device->UpdateSize * clampu(periods, 2, 16); + if(auto peropt = ConfigValueUInt(devname, nullptr, "periods")) + device->BufferSize = device->UpdateSize * clampu(*peropt, 2, 16); else device->BufferSize = maxu(device->BufferSize, device->UpdateSize*2); } @@ -3805,8 +3804,7 @@ START_API_FUNC } } - ALuint freq{}; - if(ConfigValueUInt(deviceName, nullptr, "frequency", &freq) && freq > 0) + if(ALuint freq{ConfigValueUInt(deviceName, nullptr, "frequency").value_or(0)}) { if(freq < MIN_OUTPUT_RATE) { @@ -3819,21 +3817,24 @@ START_API_FUNC device->Flags.set(); } - ConfigValueUInt(deviceName, nullptr, "period_size", &device->UpdateSize); - device->UpdateSize = clampu(device->UpdateSize, 64, 8192); + if(auto persizeopt = ConfigValueUInt(deviceName, nullptr, "period_size")) + device->UpdateSize = clampu(*persizeopt, 64, 8192); - ALuint periods{}; - if(ConfigValueUInt(deviceName, nullptr, "periods", &periods)) - device->BufferSize = device->UpdateSize * clampu(periods, 2, 16); + if(auto peropt = ConfigValueUInt(deviceName, nullptr, "periods")) + device->BufferSize = device->UpdateSize * clampu(*peropt, 2, 16); else device->BufferSize = maxu(device->BufferSize, device->UpdateSize*2); - ConfigValueUInt(deviceName, nullptr, "sources", &device->SourcesMax); - if(device->SourcesMax == 0) device->SourcesMax = 256; + if(auto srcsopt = ConfigValueUInt(deviceName, nullptr, "sources")) + { + if(*srcsopt > 0) device->SourcesMax = *srcsopt; + } - ConfigValueUInt(deviceName, nullptr, "slots", &device->AuxiliaryEffectSlotMax); - if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 64; - else device->AuxiliaryEffectSlotMax = minu(device->AuxiliaryEffectSlotMax, INT_MAX); + if(auto slotsopt = ConfigValueUInt(deviceName, nullptr, "slots")) + { + if(*slotsopt > 0) + device->AuxiliaryEffectSlotMax = minu(*slotsopt, INT_MAX); + } if(auto sendsopt = ConfigValueInt(deviceName, nullptr, "sends")) device->NumAuxSends = clampi(DEFAULT_SENDS, 0, clampi(*sendsopt, 0, MAX_SENDS)); @@ -4133,12 +4134,16 @@ START_API_FUNC device->FmtChans = DevFmtChannelsDefault; device->FmtType = DevFmtTypeDefault; - ConfigValueUInt(nullptr, nullptr, "sources", &device->SourcesMax); - if(device->SourcesMax == 0) device->SourcesMax = 256; + if(auto srcsopt = ConfigValueUInt(nullptr, nullptr, "sources")) + { + if(*srcsopt > 0) device->SourcesMax = *srcsopt; + } - ConfigValueUInt(nullptr, nullptr, "slots", &device->AuxiliaryEffectSlotMax); - if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 64; - else device->AuxiliaryEffectSlotMax = minu(device->AuxiliaryEffectSlotMax, INT_MAX); + if(auto slotsopt = ConfigValueUInt(nullptr, nullptr, "slots")) + { + if(*slotsopt > 0) + device->AuxiliaryEffectSlotMax = minu(*slotsopt, INT_MAX); + } if(auto sendsopt = ConfigValueInt(nullptr, nullptr, "sends")) device->NumAuxSends = clampi(DEFAULT_SENDS, 0, clampi(*sendsopt, 0, MAX_SENDS)); diff --git a/Alc/alconfig.cpp b/Alc/alconfig.cpp index 00643043..8b299afc 100644 --- a/Alc/alconfig.cpp +++ b/Alc/alconfig.cpp @@ -509,13 +509,13 @@ al::optional ConfigValueInt(const char *devName, const char *blockName, con return al::optional{al::in_place, static_cast(std::strtol(val, nullptr, 0))}; } -int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret) +al::optional ConfigValueUInt(const char *devName, const char *blockName, const char *keyName) { const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return 0; + if(!val[0]) return al::nullopt; - *ret = std::strtoul(val, nullptr, 0); - return 1; + return al::optional{al::in_place, + static_cast(std::strtoul(val, nullptr, 0))}; } int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret) diff --git a/Alc/alconfig.h b/Alc/alconfig.h index e6977101..275fed75 100644 --- a/Alc/alconfig.h +++ b/Alc/alconfig.h @@ -11,7 +11,7 @@ int GetConfigValueBool(const char *devName, const char *blockName, const char *k int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret); al::optional ConfigValueInt(const char *devName, const char *blockName, const char *keyName); -int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret); +al::optional ConfigValueUInt(const char *devName, const char *blockName, const char *keyName); int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret); int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret); diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index c58f73bc..99e9019b 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -203,9 +203,9 @@ int JackPlayback::bufferSizeNotify(jack_nframes_t numframes) mDevice->UpdateSize = numframes; mDevice->BufferSize = numframes*2; - ALuint bufsize{mDevice->UpdateSize}; - if(ConfigValueUInt(mDevice->DeviceName.c_str(), "jack", "buffer-size", &bufsize)) - bufsize = maxu(NextPowerOf2(bufsize), mDevice->UpdateSize); + const char *devname{mDevice->DeviceName.c_str()}; + ALuint bufsize{ConfigValueUInt(devname, "jack", "buffer-size").value_or(mDevice->UpdateSize)}; + bufsize = maxu(NextPowerOf2(bufsize), mDevice->UpdateSize); mDevice->BufferSize = bufsize + mDevice->UpdateSize; TRACE("%u / %u buffer\n", mDevice->UpdateSize, mDevice->BufferSize); @@ -374,9 +374,9 @@ ALCboolean JackPlayback::reset() mDevice->UpdateSize = jack_get_buffer_size(mClient); mDevice->BufferSize = mDevice->UpdateSize * 2; - ALuint bufsize{mDevice->UpdateSize}; - if(ConfigValueUInt(mDevice->DeviceName.c_str(), "jack", "buffer-size", &bufsize)) - bufsize = maxu(NextPowerOf2(bufsize), mDevice->UpdateSize); + const char *devname{mDevice->DeviceName.c_str()}; + ALuint bufsize{ConfigValueUInt(devname, "jack", "buffer-size").value_or(mDevice->UpdateSize)}; + bufsize = maxu(NextPowerOf2(bufsize), mDevice->UpdateSize); mDevice->BufferSize = bufsize + mDevice->UpdateSize; /* Force 32-bit float output. */ -- cgit v1.2.3 From db026454f28f93fe7c38dc84a79813a59afeb1d0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2019 16:12:43 -0700 Subject: Fix Y channel offset for the UHJ encoder --- Alc/uhjfilter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/uhjfilter.cpp b/Alc/uhjfilter.cpp index c2657f9f..55999647 100644 --- a/Alc/uhjfilter.cpp +++ b/Alc/uhjfilter.cpp @@ -75,7 +75,7 @@ void Uhj2Encoder::encode(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, Fl ASSUME(todo > 0); /* D = 0.6554516*Y */ - std::transform(yinput+base, yinput+todo, std::begin(temp), + std::transform(yinput, yinput+todo, std::begin(temp), [](const float y) noexcept -> float { return 0.6554516f*y; }); allpass_process(&mFilter1_Y[0], temp, temp, Filter1CoeffSqr[0], todo); allpass_process(&mFilter1_Y[1], temp, temp, Filter1CoeffSqr[1], todo); -- cgit v1.2.3 From 3658dafdcbbd114caaf81cb27cf6ccc07045b0aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2019 16:15:15 -0700 Subject: Use an optional for ConfigValueStr --- Alc/alc.cpp | 41 +++++++++++++++++++++++++---------------- Alc/alconfig.cpp | 7 +++---- Alc/alconfig.h | 4 +++- Alc/backends/alsa.cpp | 29 +++++++++++------------------ Alc/backends/oss.cpp | 25 +++++++++++-------------- Alc/backends/solaris.cpp | 11 ++++++----- Alc/hrtf.cpp | 30 ++++++++++++++++-------------- Alc/mixvoice.cpp | 5 ++--- Alc/panning.cpp | 19 +++++++++---------- 9 files changed, 86 insertions(+), 85 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index ec9953fe..7cf28ed3 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1024,8 +1024,9 @@ void alc_initconfig(void) #ifdef HAVE_NEON capfilter |= CPU_CAP_NEON; #endif - if(ConfigValueStr(nullptr, nullptr, "disable-cpu-exts", &str)) + if(auto cpuopt = ConfigValueStr(nullptr, nullptr, "disable-cpu-exts")) { + str = cpuopt->c_str(); if(strcasecmp(str, "all") == 0) capfilter = 0; else @@ -1094,15 +1095,20 @@ void alc_initconfig(void) if(ConfigValueFloat(nullptr, "reverb", "boost", &valf)) ReverbBoost *= std::pow(10.0f, valf / 20.0f); - const char *devs{getenv("ALSOFT_DRIVERS")}; - if((devs && devs[0]) || ConfigValueStr(nullptr, nullptr, "drivers", &devs)) + auto devopt = ConfigValueStr(nullptr, nullptr, "drivers"); + if(const char *devs{getenv("ALSOFT_DRIVERS")}) + { + if(devs[0]) + devopt = al::optional{al::in_place, devs}; + } + if(devopt) { auto backendlist_cur = std::begin(BackendList); bool endlist{true}; - const char *next = devs; + const char *next{devopt->c_str()}; do { - devs = next; + const char *devs{next}; while(isspace(devs[0])) devs++; next = strchr(devs, ','); @@ -1182,9 +1188,9 @@ void alc_initconfig(void) if(!CaptureFactory) WARN("No capture backend available!\n"); - if(ConfigValueStr(nullptr, nullptr, "excludefx", &str)) + if(auto exclopt = ConfigValueStr(nullptr, nullptr, "excludefx")) { - const char *next = str; + const char *next{exclopt->c_str()}; do { str = next; next = strchr(str, ','); @@ -1203,9 +1209,10 @@ void alc_initconfig(void) } InitEffect(&DefaultEffect); - str = getenv("ALSOFT_DEFAULT_REVERB"); - if((str && str[0]) || ConfigValueStr(nullptr, nullptr, "default-reverb", &str)) - LoadReverbPreset(str, &DefaultEffect); + auto defrevopt = ConfigValueStr(nullptr, nullptr, "default-reverb"); + if((str=getenv("ALSOFT_DEFAULT_REVERB")) && str[0]) + defrevopt = al::optional{al::in_place, str}; + if(defrevopt) LoadReverbPreset(defrevopt->c_str(), &DefaultEffect); } #define DO_INITCONFIG() std::call_once(alc_config_once, [](){alc_initconfig();}) @@ -1919,9 +1926,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->HrtfStatus = ALC_HRTF_DISABLED_SOFT; if(device->Type != Loopback) { - const char *hrtf; - if(ConfigValueStr(device->DeviceName.c_str(), nullptr, "hrtf", &hrtf)) + if(auto hrtfopt = ConfigValueStr(device->DeviceName.c_str(), nullptr, "hrtf")) { + const char *hrtf{hrtfopt->c_str()}; if(strcasecmp(hrtf, "true") == 0) hrtf_userreq = Hrtf_Enable; else if(strcasecmp(hrtf, "false") == 0) @@ -3743,8 +3750,7 @@ START_API_FUNC } deviceName = device->DeviceName.c_str(); - const ALCchar *fmt{}; - if(ConfigValueStr(deviceName, nullptr, "channels", &fmt)) + if(auto chanopt = ConfigValueStr(deviceName, nullptr, "channels")) { static constexpr struct ChannelMap { const char name[16]; @@ -3763,6 +3769,7 @@ START_API_FUNC { "ambi3", DevFmtAmbi3D, 3 }, }; + const ALCchar *fmt{chanopt->c_str()}; auto iter = std::find_if(std::begin(chanlist), std::end(chanlist), [fmt](const ChannelMap &entry) -> bool { return strcasecmp(entry.name, fmt) == 0; } @@ -3776,7 +3783,7 @@ START_API_FUNC device->Flags.set(); } } - if(ConfigValueStr(deviceName, nullptr, "sample-type", &fmt)) + if(auto typeopt = ConfigValueStr(deviceName, nullptr, "sample-type")) { static constexpr struct TypeMap { const char name[16]; @@ -3791,6 +3798,7 @@ START_API_FUNC { "float32", DevFmtFloat }, }; + const ALCchar *fmt{typeopt->c_str()}; auto iter = std::find_if(std::begin(typelist), std::end(typelist), [fmt](const TypeMap &entry) -> bool { return strcasecmp(entry.name, fmt) == 0; } @@ -3842,8 +3850,9 @@ START_API_FUNC device->NumStereoSources = 1; device->NumMonoSources = device->SourcesMax - device->NumStereoSources; - if(ConfigValueStr(deviceName, nullptr, "ambi-format", &fmt)) + if(auto ambiopt = ConfigValueStr(deviceName, nullptr, "ambi-format")) { + const ALCchar *fmt{ambiopt->c_str()}; if(strcasecmp(fmt, "fuma") == 0) { if(device->mAmbiOrder > 3) diff --git a/Alc/alconfig.cpp b/Alc/alconfig.cpp index 8b299afc..c5abd6ab 100644 --- a/Alc/alconfig.cpp +++ b/Alc/alconfig.cpp @@ -492,13 +492,12 @@ int ConfigValueExists(const char *devName, const char *blockName, const char *ke return val[0] != 0; } -int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret) +al::optional ConfigValueStr(const char *devName, const char *blockName, const char *keyName) { const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return 0; + if(!val[0]) return al::nullopt; - *ret = val; - return 1; + return al::optional{al::in_place, val}; } al::optional ConfigValueInt(const char *devName, const char *blockName, const char *keyName) diff --git a/Alc/alconfig.h b/Alc/alconfig.h index 275fed75..9b1c09aa 100644 --- a/Alc/alconfig.h +++ b/Alc/alconfig.h @@ -1,6 +1,8 @@ #ifndef ALCONFIG_H #define ALCONFIG_H +#include + #include "aloptional.h" void ReadALConfig(); @@ -9,7 +11,7 @@ int ConfigValueExists(const char *devName, const char *blockName, const char *ke const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def); int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def); -int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret); +al::optional ConfigValueStr(const char *devName, const char *blockName, const char *keyName); al::optional ConfigValueInt(const char *devName, const char *blockName, const char *keyName); al::optional ConfigValueUInt(const char *devName, const char *blockName, const char *keyName); int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret); diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index ebdc6129..aeb38585 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -207,11 +207,6 @@ ALSA_FUNCS(MAKE_FUNC); struct DevMap { std::string name; std::string device_name; - - template - DevMap(StrT0&& name_, StrT1&& devname_) - : name{std::forward(name_)}, device_name{std::forward(devname_)} - { } }; al::vector PlaybackDevices; @@ -233,10 +228,9 @@ al::vector probe_devices(snd_pcm_stream_t stream) snd_pcm_info_t *pcminfo; snd_pcm_info_malloc(&pcminfo); - devlist.emplace_back(alsaDevice, + devlist.emplace_back(DevMap{alsaDevice, GetConfigValue(nullptr, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ? "device" : "capture", - "default") - ); + "default")}); if(stream == SND_PCM_STREAM_PLAYBACK) { @@ -254,15 +248,15 @@ al::vector probe_devices(snd_pcm_stream_t stream) } const char *oldsep{sep++}; - devlist.emplace_back(std::string(customdevs, oldsep), - next ? std::string(sep, next++) : std::string(sep)); + devlist.emplace_back(DevMap{std::string(customdevs, oldsep), + next ? std::string(sep, next++) : std::string(sep)}); const auto &entry = devlist.back(); TRACE("Got device \"%s\", \"%s\"\n", entry.name.c_str(), entry.device_name.c_str()); } } - const char *main_prefix{"plughw:"}; - ConfigValueStr(nullptr, "alsa", prefix_name(stream), &main_prefix); + const std::string main_prefix{ + ConfigValueStr(nullptr, "alsa", prefix_name(stream)).value_or("plughw:")}; int card{-1}; int err{snd_card_next(&card)}; @@ -288,9 +282,8 @@ al::vector probe_devices(snd_pcm_stream_t stream) name = prefix_name(stream); name += '-'; name += cardid; - - const char *card_prefix{main_prefix}; - ConfigValueStr(nullptr, "alsa", name.c_str(), &card_prefix); + const std::string card_prefix{ + ConfigValueStr(nullptr, "alsa", name.c_str()).value_or(main_prefix)}; int dev{-1}; while(1) @@ -315,8 +308,8 @@ al::vector probe_devices(snd_pcm_stream_t stream) name += cardid; name += '-'; name += std::to_string(dev); - const char *device_prefix{card_prefix}; - ConfigValueStr(nullptr, "alsa", name.c_str(), &device_prefix); + const std::string device_prefix{ + ConfigValueStr(nullptr, "alsa", name.c_str()).value_or(card_prefix)}; /* "CardName, PcmName (CARD=cardid,DEV=dev)" */ name = cardname; @@ -335,7 +328,7 @@ al::vector probe_devices(snd_pcm_stream_t stream) device += ",DEV="; device += std::to_string(dev); - devlist.emplace_back(std::move(name), std::move(device)); + devlist.emplace_back(DevMap{std::move(name), std::move(device)}); const auto &entry = devlist.back(); TRACE("Got device \"%s\", \"%s\"\n", entry.name.c_str(), entry.device_name.c_str()); } diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 0a28fcd8..e5b74334 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -80,17 +80,12 @@ namespace { constexpr char DefaultName[] = "OSS Default"; -const char *DefaultPlayback{"/dev/dsp"}; -const char *DefaultCapture{"/dev/dsp"}; +std::string DefaultPlayback{"/dev/dsp"}; +std::string DefaultCapture{"/dev/dsp"}; struct DevMap { std::string name; std::string device_name; - - template - DevMap(StrT0&& name_, StrT1&& devname_) - : name{std::forward(name_)}, device_name{std::forward(devname_)} - { } }; bool checkName(const al::vector &list, const std::string &name) @@ -111,7 +106,7 @@ al::vector CaptureDevices; #define DSP_CAP_INPUT 0x00010000 void ALCossListPopulate(al::vector *devlist, int type) { - devlist->emplace_back(DefaultName, (type==DSP_CAP_INPUT) ? DefaultCapture : DefaultPlayback); + devlist->emplace_back(DevMap{DefaultName, (type==DSP_CAP_INPUT) ? DefaultCapture : DefaultPlayback}); } #else @@ -156,7 +151,7 @@ void ALCossListAppend(al::vector *list, const char *handle, size_t hlen, newname += std::to_string(++count); } - list->emplace_back(std::move(newname), std::move(devname)); + list->emplace_back(DevMap{std::move(newname), std::move(devname)}); const DevMap &entry = list->back(); TRACE("Got device \"%s\", \"%s\"\n", entry.name.c_str(), entry.device_name.c_str()); @@ -212,7 +207,7 @@ done: close(fd); fd = -1; - const char *defdev{(type_flag==DSP_CAP_INPUT) ? DefaultCapture : DefaultPlayback}; + const char *defdev{((type_flag==DSP_CAP_INPUT) ? DefaultCapture : DefaultPlayback).c_str()}; auto iter = std::find_if(devlist->cbegin(), devlist->cend(), [defdev](const DevMap &entry) -> bool { return entry.device_name == defdev; } @@ -331,7 +326,7 @@ int OSSPlayback::mixerProc() ALCenum OSSPlayback::open(const ALCchar *name) { - const char *devname{DefaultPlayback}; + const char *devname{DefaultPlayback.c_str()}; if(!name) name = DefaultName; else @@ -548,7 +543,7 @@ int OSScapture::recordProc() ALCenum OSScapture::open(const ALCchar *name) { - const char *devname{DefaultCapture}; + const char *devname{DefaultCapture.c_str()}; if(!name) name = DefaultName; else @@ -700,8 +695,10 @@ BackendFactory &OSSBackendFactory::getFactory() bool OSSBackendFactory::init() { - ConfigValueStr(nullptr, "oss", "device", &DefaultPlayback); - ConfigValueStr(nullptr, "oss", "capture", &DefaultCapture); + if(auto devopt = ConfigValueStr(nullptr, "oss", "device")) + DefaultPlayback = std::move(*devopt); + if(auto capopt = ConfigValueStr(nullptr, "oss", "capture")) + DefaultCapture = std::move(*capopt); return true; } diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index 5c378bff..5c12ad72 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -52,7 +52,7 @@ namespace { constexpr ALCchar solaris_device[] = "Solaris Default"; -const char *solaris_driver = "/dev/audio"; +std::string solaris_driver{"/dev/audio"}; struct SolarisBackend final : public BackendBase { @@ -149,10 +149,10 @@ ALCenum SolarisBackend::open(const ALCchar *name) else if(strcmp(name, solaris_device) != 0) return ALC_INVALID_VALUE; - mFd = ::open(solaris_driver, O_WRONLY); + mFd = ::open(solaris_driver.c_str(), O_WRONLY); if(mFd == -1) { - ERR("Could not open %s: %s\n", solaris_driver, strerror(errno)); + ERR("Could not open %s: %s\n", solaris_driver.c_str(), strerror(errno)); return ALC_INVALID_VALUE; } @@ -267,7 +267,8 @@ BackendFactory &SolarisBackendFactory::getFactory() bool SolarisBackendFactory::init() { - ConfigValueStr(nullptr, "solaris", "device", &solaris_driver); + if(auto devopt = ConfigValueStr(nullptr, "solaris", "device")) + solaris_driver = std::move(*devopt); return true; } @@ -282,7 +283,7 @@ void SolarisBackendFactory::probe(DevProbe type, std::string *outnames) { #ifdef HAVE_STAT struct stat buf; - if(stat(solaris_driver, &buf) == 0) + if(stat(solaris_driver.c_str(), &buf) == 0) #endif outnames->append(solaris_device, sizeof(solaris_device)); } diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 6b3edd9f..d86c4ecf 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -1214,9 +1214,9 @@ al::vector EnumerateHrtf(const char *devname) al::vector list; bool usedefaults{true}; - const char *pathlist{""}; - if(ConfigValueStr(devname, nullptr, "hrtf-paths", &pathlist)) + if(auto pathopt = ConfigValueStr(devname, nullptr, "hrtf-paths")) { + const char *pathlist{pathopt->c_str()}; while(pathlist && *pathlist) { const char *next, *end; @@ -1262,20 +1262,22 @@ al::vector EnumerateHrtf(const char *devname) AddBuiltInEntry(list, "Built-In 48000hz", IDR_DEFAULT_48000_MHR); } - const char *defaulthrtf{""}; - if(!list.empty() && ConfigValueStr(devname, nullptr, "default-hrtf", &defaulthrtf)) + if(!list.empty()) { - auto iter = std::find_if(list.begin(), list.end(), - [defaulthrtf](const EnumeratedHrtf &entry) -> bool - { return entry.name == defaulthrtf; } - ); - if(iter == list.end()) - WARN("Failed to find default HRTF \"%s\"\n", defaulthrtf); - else if(iter != list.begin()) + if(auto defhrtfopt = ConfigValueStr(devname, nullptr, "default-hrtf")) { - EnumeratedHrtf entry{*iter}; - list.erase(iter); - list.insert(list.begin(), entry); + auto iter = std::find_if(list.begin(), list.end(), + [&defhrtfopt](const EnumeratedHrtf &entry) -> bool + { return entry.name == *defhrtfopt; } + ); + if(iter == list.end()) + WARN("Failed to find default HRTF \"%s\"\n", defhrtfopt->c_str()); + else if(iter != list.begin()) + { + EnumeratedHrtf entry{std::move(*iter)}; + list.erase(iter); + list.insert(list.begin(), std::move(entry)); + } } } diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 9408d096..9b0196d9 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -155,10 +155,9 @@ ResamplerFunc SelectResampler(Resampler resampler) void aluInitMixer() { - const char *str; - - if(ConfigValueStr(nullptr, nullptr, "resampler", &str)) + if(auto resopt = ConfigValueStr(nullptr, nullptr, "resampler")) { + const char *str{resopt->c_str()}; if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0) ResamplerDefault = PointResampler; else if(strcasecmp(str, "linear") == 0) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 864d7f28..aa290821 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -553,9 +553,9 @@ void InitHrtfPanning(ALCdevice *device) */ device->mRenderMode = HrtfRender; ALsizei ambi_order{1}; - const char *mode; - if(ConfigValueStr(device->DeviceName.c_str(), nullptr, "hrtf-mode", &mode)) + if(auto modeopt = ConfigValueStr(device->DeviceName.c_str(), nullptr, "hrtf-mode")) { + const char *mode{modeopt->c_str()}; if(strcasecmp(mode, "basic") == 0) { ERR("HRTF mode \"%s\" deprecated, substituting \"%s\"\n", mode, "ambi2"); @@ -783,11 +783,10 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr AmbDecConf conf{}; if(layout) { - const char *fname; - if(ConfigValueStr(devname, "decoder", layout, &fname)) + if(auto decopt = ConfigValueStr(devname, "decoder", layout)) { - if(!conf.load(fname)) - ERR("Failed to load layout file %s\n", fname); + if(!conf.load(decopt->c_str())) + ERR("Failed to load layout file %s\n", decopt->c_str()); else if(conf.Speakers.size() > MAX_OUTPUT_CHANNELS) ERR("Unsupported speaker count %zu (max %d)\n", conf.Speakers.size(), MAX_OUTPUT_CHANNELS); @@ -814,9 +813,9 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr bool headphones{device->IsHeadphones != AL_FALSE}; if(device->Type != Loopback) { - const char *mode; - if(ConfigValueStr(device->DeviceName.c_str(), nullptr, "stereo-mode", &mode)) + if(auto modeopt = ConfigValueStr(device->DeviceName.c_str(), nullptr, "stereo-mode")) { + const char *mode{modeopt->c_str()}; if(strcasecmp(mode, "headphones") == 0) headphones = true; else if(strcasecmp(mode, "speakers") == 0) @@ -916,9 +915,9 @@ no_hrtf: } } - const char *mode; - if(ConfigValueStr(device->DeviceName.c_str(), nullptr, "stereo-encoding", &mode)) + if(auto encopt = ConfigValueStr(device->DeviceName.c_str(), nullptr, "stereo-encoding")) { + const char *mode{encopt->c_str()}; if(strcasecmp(mode, "uhj") == 0) device->mRenderMode = NormalRender; else if(strcasecmp(mode, "panpot") != 0) -- cgit v1.2.3 From 49ceae681b4889ed9500fa9c15b21cca7eb08fc3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2019 16:38:25 -0700 Subject: Return optionals from the remaining ConfigValue* methods --- Alc/alc.cpp | 17 +++++++++-------- Alc/alconfig.cpp | 17 ++++++++--------- Alc/alconfig.h | 4 ++-- Alc/panning.cpp | 8 ++++---- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 7cf28ed3..014998bc 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1091,9 +1091,11 @@ void alc_initconfig(void) TrapALCError = !!GetConfigValueBool(nullptr, nullptr, "trap-alc-error", TrapALCError); } - float valf{}; - if(ConfigValueFloat(nullptr, "reverb", "boost", &valf)) + if(auto boostopt = ConfigValueFloat(nullptr, "reverb", "boost")) + { + const float valf{std::isfinite(*boostopt) ? clampf(*boostopt, -24.0f, 24.0f) : 0.0f}; ReverbBoost *= std::pow(10.0f, valf / 20.0f); + } auto devopt = ConfigValueStr(nullptr, nullptr, "drivers"); if(const char *devs{getenv("ALSOFT_DRIVERS")}) @@ -1675,7 +1677,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ALboolean update_failed; ALCsizei hrtf_id = -1; ALCuint oldFreq; - int val; if((!attrList || !attrList[0]) && device->Type == Loopback) { @@ -2116,8 +2117,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->DitherDepth); device->LimiterState = gainLimiter; - if(ConfigValueBool(device->DeviceName.c_str(), nullptr, "output-limiter", &val)) - gainLimiter = val ? ALC_TRUE : ALC_FALSE; + if(auto limopt = ConfigValueBool(device->DeviceName.c_str(), nullptr, "output-limiter")) + gainLimiter = *limopt ? ALC_TRUE : ALC_FALSE; /* Valid values for gainLimiter are ALC_DONT_CARE_SOFT, ALC_TRUE, and * ALC_FALSE. For ALC_DONT_CARE_SOFT, use the limiter for integer-based @@ -3487,14 +3488,14 @@ START_API_FUNC InitContext(context.get()); - ALfloat valf{}; - if(ConfigValueFloat(dev->DeviceName.c_str(), nullptr, "volume-adjust", &valf)) + if(auto volopt = ConfigValueFloat(dev->DeviceName.c_str(), nullptr, "volume-adjust")) { + const ALfloat valf{*volopt}; if(!std::isfinite(valf)) ERR("volume-adjust must be finite: %f\n", valf); else { - ALfloat db = clampf(valf, -24.0f, 24.0f); + const ALfloat db{clampf(valf, -24.0f, 24.0f)}; if(db != valf) WARN("volume-adjust clamped: %f, range: +/-%f\n", valf, 24.0f); context->GainBoost = std::pow(10.0f, db/20.0f); diff --git a/Alc/alconfig.cpp b/Alc/alconfig.cpp index c5abd6ab..36aac48d 100644 --- a/Alc/alconfig.cpp +++ b/Alc/alconfig.cpp @@ -517,23 +517,22 @@ al::optional ConfigValueUInt(const char *devName, const char *bloc static_cast(std::strtoul(val, nullptr, 0))}; } -int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret) +al::optional ConfigValueFloat(const char *devName, const char *blockName, const char *keyName) { const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return 0; + if(!val[0]) return al::nullopt; - *ret = std::strtof(val, nullptr); - return 1; + return al::optional{al::in_place, std::strtof(val, nullptr)}; } -int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret) +al::optional ConfigValueBool(const char *devName, const char *blockName, const char *keyName) { const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return 0; + if(!val[0]) return al::nullopt; - *ret = (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || - strcasecmp(val, "on") == 0 || atoi(val) != 0); - return 1; + return al::optional{al::in_place, + strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || + strcasecmp(val, "on") == 0 || atoi(val) != 0}; } int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def) diff --git a/Alc/alconfig.h b/Alc/alconfig.h index 9b1c09aa..ffc7adad 100644 --- a/Alc/alconfig.h +++ b/Alc/alconfig.h @@ -14,7 +14,7 @@ int GetConfigValueBool(const char *devName, const char *blockName, const char *k al::optional ConfigValueStr(const char *devName, const char *blockName, const char *keyName); al::optional ConfigValueInt(const char *devName, const char *blockName, const char *keyName); al::optional ConfigValueUInt(const char *devName, const char *blockName, const char *keyName); -int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret); -int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret); +al::optional ConfigValueFloat(const char *devName, const char *blockName, const char *keyName); +al::optional ConfigValueBool(const char *devName, const char *blockName, const char *keyName); #endif /* ALCONFIG_H */ diff --git a/Alc/panning.cpp b/Alc/panning.cpp index aa290821..0a3e89fc 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -382,13 +382,13 @@ void InitPanning(ALCdevice *device) ); device->Dry.NumChannels = static_cast(count); - ALfloat nfc_delay{0.0f}; - if(ConfigValueFloat(devname, "decoder", "nfc-ref-delay", &nfc_delay) && nfc_delay > 0.0f) + ALfloat nfc_delay{ConfigValueFloat(devname, "decoder", "nfc-ref-delay").value_or(0.0f)}; + if(nfc_delay > 0.0f) { static constexpr ALuint chans_per_order[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; nfc_delay = clampf(nfc_delay, 0.001f, 1000.0f); - InitNearFieldCtrl(device, nfc_delay * SPEEDOFSOUNDMETRESPERSEC, - device->mAmbiOrder, chans_per_order); + InitNearFieldCtrl(device, nfc_delay * SPEEDOFSOUNDMETRESPERSEC, device->mAmbiOrder, + chans_per_order); } device->RealOut.NumChannels = 0; -- cgit v1.2.3 From f45864223767ac6543e8f432384dcf984d325eea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2019 16:57:10 -0700 Subject: Use optionals where methods may not return a valid value --- Alc/alc.cpp | 19 ++++++++++--------- OpenAL32/alBuffer.cpp | 45 ++++++++++++++++----------------------------- 2 files changed, 26 insertions(+), 38 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 014998bc..5b88043e 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1337,7 +1337,8 @@ ALsizei ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept return 0; } -static ALboolean DecomposeDevFormat(ALenum format, DevFmtChannels *chans, DevFmtType *type) +struct DevFmtPair { DevFmtChannels chans; DevFmtType type; }; +static al::optional DecomposeDevFormat(ALenum format) { static const struct { ALenum format; @@ -1372,14 +1373,10 @@ static ALboolean DecomposeDevFormat(ALenum format, DevFmtChannels *chans, DevFmt for(const auto &item : list) { if(item.format == format) - { - *chans = item.channels; - *type = item.type; - return AL_TRUE; - } + return al::optional{al::in_place, DevFmtPair{item.channels, item.type}}; } - return AL_FALSE; + return al::nullopt; } static ALCboolean IsValidALCType(ALCenum type) @@ -3975,12 +3972,16 @@ START_API_FUNC DeviceRef device{new ALCdevice{Capture}}; - device->Frequency = frequency; - if(DecomposeDevFormat(format, &device->FmtChans, &device->FmtType) == AL_FALSE) + auto decompfmt = DecomposeDevFormat(format); + if(!decompfmt) { alcSetError(nullptr, ALC_INVALID_ENUM); return nullptr; } + + device->Frequency = frequency; + device->FmtChans = decompfmt->chans; + device->FmtType = decompfmt->type; device->Flags.set(); device->UpdateSize = samples; diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index ec733ae1..3f1020bb 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -40,6 +40,7 @@ #include "alBuffer.h" #include "sample_cvt.h" #include "alexcpt.h" +#include "aloptional.h" namespace { @@ -332,8 +333,8 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U ALBuf->LoopEnd = ALBuf->SampleLen; } -using DecompResult = std::tuple; -DecompResult DecomposeUserFormat(ALenum format) +struct DecompResult { UserFmtChannels channels; UserFmtType type; }; +al::optional DecomposeUserFormat(ALenum format) { struct FormatMap { ALenum format; @@ -398,18 +399,12 @@ DecompResult DecomposeUserFormat(ALenum format) { AL_FORMAT_BFORMAT3D_MULAW, UserFmtBFormat3D, UserFmtMulaw }, }}; - DecompResult ret{}; for(const auto &fmt : UserFmtList) { if(fmt.format == format) - { - std::get<0>(ret) = true; - std::get<1>(ret) = fmt.channels; - std::get<2>(ret) = fmt.type; - break; - } + return al::optional{al::in_place, DecompResult{fmt.channels, fmt.type}}; } - return ret; + return al::nullopt; } } // namespace @@ -551,15 +546,11 @@ START_API_FUNC "Declaring persistently mapped storage without read or write access"); else { - UserFmtType srctype{UserFmtUByte}; - UserFmtChannels srcchannels{UserFmtMono}; - bool success; - - std::tie(success, srcchannels, srctype) = DecomposeUserFormat(format); - if(UNLIKELY(!success)) + auto usrfmt = DecomposeUserFormat(format); + if(UNLIKELY(!usrfmt)) alSetError(context.get(), AL_INVALID_ENUM, "Invalid format 0x%04x", format); else - LoadData(context.get(), albuf, freq, size, srcchannels, srctype, + LoadData(context.get(), albuf, freq, size, usrfmt->channels, usrfmt->type, static_cast(data), flags); } } @@ -688,23 +679,19 @@ START_API_FUNC return; } - UserFmtType srctype{UserFmtUByte}; - UserFmtChannels srcchannels{UserFmtMono}; - bool success; - std::tie(success, srcchannels, srctype) = DecomposeUserFormat(format); - if(UNLIKELY(!success)) + auto usrfmt = DecomposeUserFormat(format); + if(UNLIKELY(!usrfmt)) { alSetError(context.get(), AL_INVALID_ENUM, "Invalid format 0x%04x", format); return; } ALsizei unpack_align{albuf->UnpackAlign.load()}; - ALsizei align{SanitizeAlignment(srctype, unpack_align)}; + ALsizei align{SanitizeAlignment(usrfmt->type, unpack_align)}; if(UNLIKELY(align < 1)) alSetError(context.get(), AL_INVALID_VALUE, "Invalid unpack alignment %d", unpack_align); - else if (UNLIKELY(static_cast(srcchannels) != - static_cast(albuf->mFmtChannels) || - srctype != albuf->OriginalType)) + else if(UNLIKELY(long{usrfmt->channels} != long{albuf->mFmtChannels} || + usrfmt->type != albuf->OriginalType)) alSetError(context.get(), AL_INVALID_ENUM, "Unpacking data with mismatched format"); else if(UNLIKELY(align != albuf->OriginalAlign)) @@ -743,15 +730,15 @@ START_API_FUNC length = length/byte_align * align; void *dst = albuf->mData.data() + offset; - if(srctype == UserFmtIMA4 && albuf->mFmtType == FmtShort) + if(usrfmt->type == UserFmtIMA4 && albuf->mFmtType == FmtShort) Convert_ALshort_ALima4(static_cast(dst), static_cast(data), num_chans, length, align); - else if(srctype == UserFmtMSADPCM && albuf->mFmtType == FmtShort) + else if(usrfmt->type == UserFmtMSADPCM && albuf->mFmtType == FmtShort) Convert_ALshort_ALmsadpcm(static_cast(dst), static_cast(data), num_chans, length, align); else { - assert(static_cast(srctype) == static_cast(albuf->mFmtType)); + assert(long{usrfmt->type} == static_cast(albuf->mFmtType)); memcpy(dst, data, length * frame_size); } } -- cgit v1.2.3 From c21b7e2461739e8b162f736bd9dfc6df4b48a667 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2019 17:41:43 -0700 Subject: Use explicit storage types for some enums --- OpenAL32/Include/alBuffer.h | 8 ++++---- OpenAL32/Include/alMain.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 1919dd5a..92655784 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -12,7 +12,7 @@ /* User formats */ -enum UserFmtType { +enum UserFmtType : unsigned char { UserFmtUByte, UserFmtShort, UserFmtFloat, @@ -22,7 +22,7 @@ enum UserFmtType { UserFmtIMA4, UserFmtMSADPCM, }; -enum UserFmtChannels { +enum UserFmtChannels : unsigned char { UserFmtMono, UserFmtStereo, UserFmtRear, @@ -41,7 +41,7 @@ inline ALsizei FrameSizeFromUserFmt(UserFmtChannels chans, UserFmtType type) /* Storable formats */ -enum FmtType { +enum FmtType : unsigned char { FmtUByte = UserFmtUByte, FmtShort = UserFmtShort, FmtFloat = UserFmtFloat, @@ -49,7 +49,7 @@ enum FmtType { FmtMulaw = UserFmtMulaw, FmtAlaw = UserFmtAlaw, }; -enum FmtChannels { +enum FmtChannels : unsigned char { FmtMono = UserFmtMono, FmtStereo = UserFmtStereo, FmtRear = UserFmtRear, diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 016cc535..3008aeca 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -124,7 +124,7 @@ enum Channel { /* Device formats */ -enum DevFmtType { +enum DevFmtType : ALenum { DevFmtByte = ALC_BYTE_SOFT, DevFmtUByte = ALC_UNSIGNED_BYTE_SOFT, DevFmtShort = ALC_SHORT_SOFT, @@ -135,7 +135,7 @@ enum DevFmtType { DevFmtTypeDefault = DevFmtFloat }; -enum DevFmtChannels { +enum DevFmtChannels : ALenum { DevFmtMono = ALC_MONO_SOFT, DevFmtStereo = ALC_STEREO_SOFT, DevFmtQuad = ALC_QUAD_SOFT, @@ -145,7 +145,7 @@ enum DevFmtChannels { DevFmtAmbi3D = ALC_BFORMAT3D_SOFT, /* Similar to 5.1, except using rear channels instead of sides */ - DevFmtX51Rear = 0x80000000, + DevFmtX51Rear = 0x70000000, DevFmtChannelsDefault = DevFmtStereo }; -- cgit v1.2.3 From e9bf7e4b15460139c0474a97b9619c9e9fb3177f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2019 18:17:23 -0700 Subject: Add an option to disable video in alffplay --- examples/alffplay.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 6298cb43..8016fd00 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -102,6 +102,7 @@ const std::string AppName{"alffplay"}; bool EnableDirectOut{false}; bool EnableWideStereo{false}; +bool DisableVideo{false}; LPALGETSOURCEI64VSOFT alGetSourcei64vSOFT; LPALCGETINTEGER64VSOFT alcGetInteger64vSOFT; @@ -1572,7 +1573,7 @@ int MovieState::parse_handler() for(unsigned int i = 0;i < mFormatCtx->nb_streams;i++) { auto codecpar = mFormatCtx->streams[i]->codecpar; - if(codecpar->codec_type == AVMEDIA_TYPE_VIDEO && video_index < 0) + if(codecpar->codec_type == AVMEDIA_TYPE_VIDEO && !DisableVideo && video_index < 0) video_index = streamComponentOpen(i); else if(codecpar->codec_type == AVMEDIA_TYPE_AUDIO && audio_index < 0) audio_index = streamComponentOpen(i); @@ -1859,6 +1860,8 @@ int main(int argc, char *argv[]) EnableWideStereo = true; } } + else if(strcmp(argv[fileidx], "-novideo") == 0) + DisableVideo = false; else break; } -- cgit v1.2.3 From 7affe3d78d5473027104cb3b3008d5afb7ac47ea Mon Sep 17 00:00:00 2001 From: Philip Muzzall Date: Sun, 30 Jun 2019 22:01:04 -0700 Subject: Added rc scripts for dll (#306) * Added rc scripts for dll * Reverted numbering scheme in CMakeLists --- CMakeLists.txt | 7 ++++++- resources/openal32.rc | Bin 0 -> 4134 bytes resources/resource.h | 15 +++++++++++++++ resources/router.rc | Bin 0 -> 4108 bytes resources/soft_oal.rc | Bin 0 -> 4134 bytes version.h.in | 1 + 6 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 resources/openal32.rc create mode 100644 resources/resource.h create mode 100644 resources/router.rc create mode 100644 resources/soft_oal.rc diff --git a/CMakeLists.txt b/CMakeLists.txt index 13a714ac..a2150846 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,6 +109,7 @@ SET(LIB_MAJOR_VERSION "1") SET(LIB_MINOR_VERSION "19") SET(LIB_REVISION "1") SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_REVISION}") +SET(LIB_VERSION_NUM ${LIB_MAJOR_VERSION},${LIB_MINOR_VERSION},${LIB_REVISION},0) SET(EXPORT_DECL "") @@ -1131,6 +1132,7 @@ IF(GIT_FOUND AND EXISTS "${OpenAL_SOURCE_DIR}/.git") ADD_CUSTOM_TARGET(build_version ${CMAKE_COMMAND} -D GIT_EXECUTABLE=${GIT_EXECUTABLE} -D LIB_VERSION=${LIB_VERSION} + -D LIB_VERSION_NUM=${LIB_VERSION_NUM} -D SRC=${OpenAL_SOURCE_DIR}/version.h.in -D DST=${OpenAL_BINARY_DIR}/version.h -P ${OpenAL_SOURCE_DIR}/version.cmake @@ -1283,8 +1285,10 @@ ELSE() ENDIF() ENDIF() + SET(RC_CONFIG resources/openal32.rc) IF(WIN32 AND ALSOFT_BUILD_ROUTER) ADD_LIBRARY(OpenAL SHARED + resources/router.rc router/router.cpp router/router.h router/alc.cpp @@ -1312,9 +1316,10 @@ ELSE() SET(LIBNAME "soft_oal") SET(IMPL_TARGET soft_oal) + SET(RC_CONFIG resources/soft_oal.rc) ENDIF() - ADD_LIBRARY(${IMPL_TARGET} SHARED ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS}) + ADD_LIBRARY(${IMPL_TARGET} SHARED ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS} ${RC_CONFIG}) IF(WIN32) SET_TARGET_PROPERTIES(${IMPL_TARGET} PROPERTIES PREFIX "") ENDIF() diff --git a/resources/openal32.rc b/resources/openal32.rc new file mode 100644 index 00000000..28475185 Binary files /dev/null and b/resources/openal32.rc differ diff --git a/resources/resource.h b/resources/resource.h new file mode 100644 index 00000000..287c9113 --- /dev/null +++ b/resources/resource.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by openal32.rc, router.rc, soft_oal.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/resources/router.rc b/resources/router.rc new file mode 100644 index 00000000..71205f8f Binary files /dev/null and b/resources/router.rc differ diff --git a/resources/soft_oal.rc b/resources/soft_oal.rc new file mode 100644 index 00000000..c29cfb3d Binary files /dev/null and b/resources/soft_oal.rc differ diff --git a/version.h.in b/version.h.in index 56f738a3..9bb439d8 100644 --- a/version.h.in +++ b/version.h.in @@ -1,5 +1,6 @@ /* Define to the library version */ #define ALSOFT_VERSION "${LIB_VERSION}" +#define ALSOFT_VERSION_NUM ${LIB_VERSION_NUM} /* Define the branch being built */ #define ALSOFT_GIT_BRANCH "${GIT_BRANCH}" -- cgit v1.2.3 From 0aeaf061736e28a803fb46d25860a07b3d45bb05 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2019 20:43:19 -0700 Subject: Properly set DisableVideo to true --- examples/alffplay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 8016fd00..f4d50d52 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -1861,7 +1861,7 @@ int main(int argc, char *argv[]) } } else if(strcmp(argv[fileidx], "-novideo") == 0) - DisableVideo = false; + DisableVideo = true; else break; } -- cgit v1.2.3 From 01300d9735c732d4e9beef960a8758c2d056a5fd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2019 22:29:21 -0700 Subject: Convert rc files to UTF-8 MinGW chokes on them being UTF-16 --- resources/openal32.rc | Bin 4134 -> 2069 bytes resources/router.rc | Bin 4108 -> 2056 bytes resources/soft_oal.rc | Bin 4134 -> 2069 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/resources/openal32.rc b/resources/openal32.rc index 28475185..56b9020a 100644 Binary files a/resources/openal32.rc and b/resources/openal32.rc differ diff --git a/resources/router.rc b/resources/router.rc index 71205f8f..5b725b88 100644 Binary files a/resources/router.rc and b/resources/router.rc differ diff --git a/resources/soft_oal.rc b/resources/soft_oal.rc index c29cfb3d..61e4848b 100644 Binary files a/resources/soft_oal.rc and b/resources/soft_oal.rc differ -- cgit v1.2.3 From 90b1bc7b7a009113932b15208e3bdfbed2b3b65b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2019 23:32:09 -0700 Subject: Make sure a variable is set before use --- examples/alrecord.c | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/alrecord.c b/examples/alrecord.c index 30f5f792..c4984f99 100644 --- a/examples/alrecord.c +++ b/examples/alrecord.c @@ -317,6 +317,7 @@ int main(int argc, char **argv) recorder.mRecTime, (recorder.mRecTime != 1.0f) ? "s" : "" ); + err = ALC_NO_ERROR; alcCaptureStart(recorder.mDevice); while((double)recorder.mDataSize/(double)recorder.mSampleRate < recorder.mRecTime && (err=alcGetError(recorder.mDevice)) == ALC_NO_ERROR && !ferror(recorder.mFile)) -- cgit v1.2.3 From 0c2edd10dd9de6432d0e2b970fbc71a45b93110b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 1 Jul 2019 00:28:06 -0700 Subject: Remove BOM markers and set UTF-8 codepage for rc files --- resources/openal32.rc | 3 ++- resources/router.rc | 3 ++- resources/soft_oal.rc | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/resources/openal32.rc b/resources/openal32.rc index 56b9020a..0c59ede9 100644 --- a/resources/openal32.rc +++ b/resources/openal32.rc @@ -1,4 +1,5 @@ -// Microsoft Visual C++ generated resource script. +#pragma code_page(65001) +// Microsoft Visual C++ generated resource script. // #include #include "resource.h" diff --git a/resources/router.rc b/resources/router.rc index 5b725b88..00713141 100644 --- a/resources/router.rc +++ b/resources/router.rc @@ -1,4 +1,5 @@ -// Microsoft Visual C++ generated resource script. +#pragma code_page(65001) +// Microsoft Visual C++ generated resource script. // #include #include "resource.h" diff --git a/resources/soft_oal.rc b/resources/soft_oal.rc index 61e4848b..09bca3be 100644 --- a/resources/soft_oal.rc +++ b/resources/soft_oal.rc @@ -1,4 +1,5 @@ -// Microsoft Visual C++ generated resource script. +#pragma code_page(65001) +// Microsoft Visual C++ generated resource script. // #include #include "resource.h" -- cgit v1.2.3 From a5197177beb62bfdc6f70c6f1294b588089b64ec Mon Sep 17 00:00:00 2001 From: Lopuska Date: Mon, 1 Jul 2019 14:58:32 +0200 Subject: Corrected old naming --- Alc/effects/modulator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index 39f1aa04..12974faa 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -121,7 +121,7 @@ void ModulatorState::update(const ALCcontext *context, const ALeffectslot *slot, mGetSamples = Modulate; else if(props->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) mGetSamples = Modulate; - else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/ + else /*if(props->Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/ mGetSamples = Modulate; ALfloat f0norm{props->Modulator.HighPassCutoff / static_cast(device->Frequency)}; -- cgit v1.2.3 From 0066ac26f0c2fa42ba31fdda208bdca961d582a8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 1 Jul 2019 01:08:53 -0700 Subject: Add a missing return --- common/aloptional.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/aloptional.h b/common/aloptional.h index 75891329..207c299e 100644 --- a/common/aloptional.h +++ b/common/aloptional.h @@ -40,7 +40,7 @@ public: optional(const optional&) noexcept = delete; ~optional() { reset(); } - optional& operator=(nullopt_t) noexcept { reset(); } + optional& operator=(nullopt_t) noexcept { reset(); return *this; } template::value && std::is_copy_assignable::value)> optional& operator=(const optional &rhs) { -- cgit v1.2.3 From 871257b69efa9d98876c6d29fc6493af2ad06626 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 1 Jul 2019 01:28:33 -0700 Subject: Some cleanup for optional --- common/aloptional.h | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/common/aloptional.h b/common/aloptional.h index 207c299e..6843a8cd 100644 --- a/common/aloptional.h +++ b/common/aloptional.h @@ -3,6 +3,8 @@ #include +#include "almalloc.h" + namespace al { #define REQUIRES(...) bool _rt=true, typename std::enable_if<_rt && (__VA_ARGS__),int>::type = 0 @@ -24,13 +26,13 @@ public: optional(const optional &rhs) : mHasValue{rhs.mHasValue} { if(mHasValue) - new (&mValue) T{*rhs}; + new (std::addressof(mValue)) T{*rhs}; } template::value)> optional(optional&& rhs) : mHasValue{rhs.mHasValue} { if(mHasValue) - new (&mValue) T{std::move(*rhs)}; + new (std::addressof(mValue)) T{std::move(*rhs)}; } template explicit optional(in_place_t, Args&& ...args) @@ -46,9 +48,11 @@ public: { if(!rhs) reset(); + else if(*this) + mValue = *rhs; else { - mValue = *rhs; + new (std::addressof(mValue)) T{*rhs}; mHasValue = true; } return *this; @@ -58,9 +62,11 @@ public: { if(!rhs) reset(); + else if(*this) + mValue = std::move(*rhs); else { - mValue = std::move(*rhs); + new (std::addressof(mValue)) T{std::move(*rhs)}; mHasValue = true; } return *this; @@ -68,8 +74,8 @@ public: template::value || !std::is_copy_assignable::value)> optional& operator=(const optional&) = delete; - const T* operator->() const { return &mValue; } - T* operator->() { return &mValue; } + const T* operator->() const { return std::addressof(mValue); } + T* operator->() { return std::addressof(mValue); } const T& operator*() const& { return mValue; } T& operator*() & { return mValue; } const T&& operator*() const&& { return std::move(mValue); } @@ -93,7 +99,7 @@ public: void reset() noexcept { if(mHasValue) - mValue.~T(); + al::destroy_at(std::addressof(mValue)); mHasValue = false; } -- cgit v1.2.3 From e9b41d9b90407285dd5fc74165051af907608d7e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 1 Jul 2019 11:13:23 -0700 Subject: Don't unnecessarily force the output limiter on --- Alc/alc.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 5b88043e..5c760387 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -3723,7 +3723,6 @@ START_API_FUNC device->Frequency = DEFAULT_OUTPUT_RATE; device->UpdateSize = DEFAULT_UPDATE_SIZE; device->BufferSize = DEFAULT_UPDATE_SIZE * DEFAULT_NUM_UPDATES; - device->LimiterState = ALC_TRUE; device->SourcesMax = 256; device->AuxiliaryEffectSlotMax = 64; -- cgit v1.2.3 From c9ffa9d466f5d0a24c9f51f430b19410abdf868f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 1 Jul 2019 12:33:39 -0700 Subject: Add C++17-like uninitialized_move methods --- common/almalloc.h | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/common/almalloc.h b/common/almalloc.h index 23f9edce..801df1d8 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -144,6 +144,49 @@ inline T uninitialized_default_construct_n(T first, N count) } +template +inline T1 uninitialized_move(T0 first, const T0 last, const T1 output) +{ + using ValueT = typename std::iterator_traits::value_type; + T1 current{output}; + try { + while(first != last) + { + ::new (static_cast(std::addressof(*current))) ValueT{std::move(*first)}; + ++current; + ++first; + } + } + catch(...) { + destroy(output, current); + throw; + } + return current; +} + +template::value)> +inline T1 uninitialized_move_n(T0 first, N count, const T1 output) +{ + using ValueT = typename std::iterator_traits::value_type; + T1 current{output}; + if(count != 0) + { + try { + do { + ::new (static_cast(std::addressof(*current))) ValueT{std::move(*first)}; + ++current; + ++first; + } while(--count); + } + catch(...) { + destroy(output, current); + throw; + } + } + return current; +} + + /* std::make_unique was added with C++14, so until we rely on that, make our * own version. */ -- cgit v1.2.3 From 143ad160518fed792f7616c2c93ab8101d130736 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 1 Jul 2019 12:34:24 -0700 Subject: Use uninitialized_copy/move for optionals --- common/aloptional.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/common/aloptional.h b/common/aloptional.h index 6843a8cd..443da0b4 100644 --- a/common/aloptional.h +++ b/common/aloptional.h @@ -26,20 +26,18 @@ public: optional(const optional &rhs) : mHasValue{rhs.mHasValue} { if(mHasValue) - new (std::addressof(mValue)) T{*rhs}; + std::uninitialized_copy_n(std::addressof(*rhs), 1, std::addressof(mValue)); } template::value)> optional(optional&& rhs) : mHasValue{rhs.mHasValue} { if(mHasValue) - new (std::addressof(mValue)) T{std::move(*rhs)}; + al::uninitialized_move_n(std::addressof(*rhs), 1, std::addressof(mValue)); } template explicit optional(in_place_t, Args&& ...args) : mHasValue{true}, mValue{std::forward(args)...} { } - template::value)> - optional(const optional&) noexcept = delete; ~optional() { reset(); } optional& operator=(nullopt_t) noexcept { reset(); return *this; } @@ -52,7 +50,7 @@ public: mValue = *rhs; else { - new (std::addressof(mValue)) T{*rhs}; + std::uninitialized_copy_n(std::addressof(*rhs), 1, std::addressof(mValue)); mHasValue = true; } return *this; @@ -66,13 +64,11 @@ public: mValue = std::move(*rhs); else { - new (std::addressof(mValue)) T{std::move(*rhs)}; + al::uninitialized_move_n(std::addressof(*rhs), 1, std::addressof(mValue)); mHasValue = true; } return *this; } - template::value || !std::is_copy_assignable::value)> - optional& operator=(const optional&) = delete; const T* operator->() const { return std::addressof(mValue); } T* operator->() { return std::addressof(mValue); } -- cgit v1.2.3 From eb701714334ce3ced479204e93a3ed4894a4af50 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 1 Jul 2019 16:27:49 -0700 Subject: Add a few more constructor and assignment operators for optional --- common/aloptional.h | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/common/aloptional.h b/common/aloptional.h index 443da0b4..a4b37212 100644 --- a/common/aloptional.h +++ b/common/aloptional.h @@ -34,9 +34,25 @@ public: if(mHasValue) al::uninitialized_move_n(std::addressof(*rhs), 1, std::addressof(mValue)); } - template - explicit optional(in_place_t, Args&& ...args) - : mHasValue{true}, mValue{std::forward(args)...} + template::value)> + explicit optional(in_place_t, Args&& ...args) : mHasValue{true} + , mValue{std::forward(args)...} + { } + template&, Args...>::value)> + explicit optional(in_place_t, std::initializer_list il, Args&& ...args) + : mHasValue{true}, mValue{il, std::forward(args)...} + { } + template::value && + !std::is_same::type, in_place_t>::value && + !std::is_same::type, optional>::value && + std::is_constructible::value)> + constexpr explicit optional(U&& value) : mHasValue{true}, mValue{std::forward(value)} + { } + template::value && + !std::is_same::type, in_place_t>::value && + !std::is_same::type, optional>::value && + !std::is_constructible::value)> + constexpr optional(U&& value) : mHasValue{true}, mValue{std::forward(value)} { } ~optional() { reset(); } @@ -69,6 +85,22 @@ public: } return *this; } + template::value && + std::is_assignable::value && + !std::is_same::type, optional>::value && + (!std::is_same::type, T>::value || + !std::is_scalar::value))> + optional& operator=(U&& rhs) + { + if(*this) + mValue = std::forward(rhs); + else + { + ::new (std::addressof(mValue)) T{std::forward(rhs)}; + mHasValue = true; + } + return *this; + } const T* operator->() const { return std::addressof(mValue); } T* operator->() { return std::addressof(mValue); } -- cgit v1.2.3 From 53c13de5ce6467f15cc12c855418ed2589a8508a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 1 Jul 2019 16:28:51 -0700 Subject: Simplify some optional usage --- Alc/alc.cpp | 6 +++--- Alc/alconfig.cpp | 11 +++++------ OpenAL32/alBuffer.cpp | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 5c760387..521da6bc 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1101,7 +1101,7 @@ void alc_initconfig(void) if(const char *devs{getenv("ALSOFT_DRIVERS")}) { if(devs[0]) - devopt = al::optional{al::in_place, devs}; + devopt = devs; } if(devopt) { @@ -1213,7 +1213,7 @@ void alc_initconfig(void) InitEffect(&DefaultEffect); auto defrevopt = ConfigValueStr(nullptr, nullptr, "default-reverb"); if((str=getenv("ALSOFT_DEFAULT_REVERB")) && str[0]) - defrevopt = al::optional{al::in_place, str}; + defrevopt = str; if(defrevopt) LoadReverbPreset(defrevopt->c_str(), &DefaultEffect); } #define DO_INITCONFIG() std::call_once(alc_config_once, [](){alc_initconfig();}) @@ -1373,7 +1373,7 @@ static al::optional DecomposeDevFormat(ALenum format) for(const auto &item : list) { if(item.format == format) - return al::optional{al::in_place, DevFmtPair{item.channels, item.type}}; + return al::optional{{item.channels, item.type}}; } return al::nullopt; diff --git a/Alc/alconfig.cpp b/Alc/alconfig.cpp index 36aac48d..b6e406fd 100644 --- a/Alc/alconfig.cpp +++ b/Alc/alconfig.cpp @@ -497,7 +497,7 @@ al::optional ConfigValueStr(const char *devName, const char *blockN const char *val = GetConfigValue(devName, blockName, keyName, ""); if(!val[0]) return al::nullopt; - return al::optional{al::in_place, val}; + return al::optional{val}; } al::optional ConfigValueInt(const char *devName, const char *blockName, const char *keyName) @@ -505,7 +505,7 @@ al::optional ConfigValueInt(const char *devName, const char *blockName, con const char *val = GetConfigValue(devName, blockName, keyName, ""); if(!val[0]) return al::nullopt; - return al::optional{al::in_place, static_cast(std::strtol(val, nullptr, 0))}; + return al::optional{static_cast(std::strtol(val, nullptr, 0))}; } al::optional ConfigValueUInt(const char *devName, const char *blockName, const char *keyName) @@ -513,8 +513,7 @@ al::optional ConfigValueUInt(const char *devName, const char *bloc const char *val = GetConfigValue(devName, blockName, keyName, ""); if(!val[0]) return al::nullopt; - return al::optional{al::in_place, - static_cast(std::strtoul(val, nullptr, 0))}; + return al::optional{static_cast(std::strtoul(val, nullptr, 0))}; } al::optional ConfigValueFloat(const char *devName, const char *blockName, const char *keyName) @@ -522,7 +521,7 @@ al::optional ConfigValueFloat(const char *devName, const char *blockName, const char *val = GetConfigValue(devName, blockName, keyName, ""); if(!val[0]) return al::nullopt; - return al::optional{al::in_place, std::strtof(val, nullptr)}; + return al::optional{std::strtof(val, nullptr)}; } al::optional ConfigValueBool(const char *devName, const char *blockName, const char *keyName) @@ -530,7 +529,7 @@ al::optional ConfigValueBool(const char *devName, const char *blockName, c const char *val = GetConfigValue(devName, blockName, keyName, ""); if(!val[0]) return al::nullopt; - return al::optional{al::in_place, + return al::optional{ strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || strcasecmp(val, "on") == 0 || atoi(val) != 0}; } diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index 3f1020bb..8b081b78 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -402,7 +402,7 @@ al::optional DecomposeUserFormat(ALenum format) for(const auto &fmt : UserFmtList) { if(fmt.format == format) - return al::optional{al::in_place, DecompResult{fmt.channels, fmt.type}}; + return al::optional{{fmt.channels, fmt.type}}; } return al::nullopt; } -- cgit v1.2.3 From 6bb0edf0a57bdb95c017db986f76eddbc80857e1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 1 Jul 2019 17:25:58 -0700 Subject: Create and use a make_optional method --- Alc/alc.cpp | 2 +- Alc/alconfig.cpp | 12 ++++++------ OpenAL32/alBuffer.cpp | 2 +- common/aloptional.h | 12 ++++++++++++ 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 521da6bc..df272c2a 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1373,7 +1373,7 @@ static al::optional DecomposeDevFormat(ALenum format) for(const auto &item : list) { if(item.format == format) - return al::optional{{item.channels, item.type}}; + return al::make_optional(DevFmtPair{item.channels, item.type}); } return al::nullopt; diff --git a/Alc/alconfig.cpp b/Alc/alconfig.cpp index b6e406fd..5f5f9149 100644 --- a/Alc/alconfig.cpp +++ b/Alc/alconfig.cpp @@ -497,7 +497,7 @@ al::optional ConfigValueStr(const char *devName, const char *blockN const char *val = GetConfigValue(devName, blockName, keyName, ""); if(!val[0]) return al::nullopt; - return al::optional{val}; + return al::make_optional(val); } al::optional ConfigValueInt(const char *devName, const char *blockName, const char *keyName) @@ -505,7 +505,7 @@ al::optional ConfigValueInt(const char *devName, const char *blockName, con const char *val = GetConfigValue(devName, blockName, keyName, ""); if(!val[0]) return al::nullopt; - return al::optional{static_cast(std::strtol(val, nullptr, 0))}; + return al::make_optional(static_cast(std::strtol(val, nullptr, 0))); } al::optional ConfigValueUInt(const char *devName, const char *blockName, const char *keyName) @@ -513,7 +513,7 @@ al::optional ConfigValueUInt(const char *devName, const char *bloc const char *val = GetConfigValue(devName, blockName, keyName, ""); if(!val[0]) return al::nullopt; - return al::optional{static_cast(std::strtoul(val, nullptr, 0))}; + return al::make_optional(static_cast(std::strtoul(val, nullptr, 0))); } al::optional ConfigValueFloat(const char *devName, const char *blockName, const char *keyName) @@ -521,7 +521,7 @@ al::optional ConfigValueFloat(const char *devName, const char *blockName, const char *val = GetConfigValue(devName, blockName, keyName, ""); if(!val[0]) return al::nullopt; - return al::optional{std::strtof(val, nullptr)}; + return al::make_optional(std::strtof(val, nullptr)); } al::optional ConfigValueBool(const char *devName, const char *blockName, const char *keyName) @@ -529,9 +529,9 @@ al::optional ConfigValueBool(const char *devName, const char *blockName, c const char *val = GetConfigValue(devName, blockName, keyName, ""); if(!val[0]) return al::nullopt; - return al::optional{ + return al::make_optional( strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || - strcasecmp(val, "on") == 0 || atoi(val) != 0}; + strcasecmp(val, "on") == 0 || atoi(val) != 0); } int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def) diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index 8b081b78..a6ed98cc 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -402,7 +402,7 @@ al::optional DecomposeUserFormat(ALenum format) for(const auto &fmt : UserFmtList) { if(fmt.format == format) - return al::optional{{fmt.channels, fmt.type}}; + return al::make_optional(DecompResult{fmt.channels, fmt.type}); } return al::nullopt; } diff --git a/common/aloptional.h b/common/aloptional.h index a4b37212..8524a2e2 100644 --- a/common/aloptional.h +++ b/common/aloptional.h @@ -139,6 +139,18 @@ private: }; }; +template +inline optional::type> make_optional(T&& arg) +{ return optional::type>{in_place, std::forward(arg)}; } + +template +inline optional make_optional(Args&& ...args) +{ return optional{in_place, std::forward(args)...}; } + +template +inline optional make_optional(std::initializer_list il, Args&& ...args) +{ return optional{in_place, il, std::forward(args)...}; } + #undef REQUIRES } // namespace al -- cgit v1.2.3 From bc1d058d2d37bc67e93e30080e8d4d4c2be38edd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 1 Jul 2019 17:34:02 -0700 Subject: Add a helper to construct the optional value --- common/aloptional.h | 47 ++++++++++++++++++----------------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/common/aloptional.h b/common/aloptional.h index 8524a2e2..2ed882e4 100644 --- a/common/aloptional.h +++ b/common/aloptional.h @@ -17,23 +17,28 @@ constexpr in_place_t in_place{}; template class optional { + bool mHasValue{false}; + union { + char mDummy[sizeof(T)]{}; + T mValue; + }; + + template + void DoConstruct(Args&& ...args) + { + ::new (std::addressof(mValue)) T{std::forward(args)...}; + mHasValue = true; + } + public: using value_type = T; optional() noexcept = default; optional(nullopt_t) noexcept { } template::value)> - optional(const optional &rhs) : mHasValue{rhs.mHasValue} - { - if(mHasValue) - std::uninitialized_copy_n(std::addressof(*rhs), 1, std::addressof(mValue)); - } + optional(const optional &rhs) { if(rhs) DoConstruct(*rhs); } template::value)> - optional(optional&& rhs) : mHasValue{rhs.mHasValue} - { - if(mHasValue) - al::uninitialized_move_n(std::addressof(*rhs), 1, std::addressof(mValue)); - } + optional(optional&& rhs) { if(rhs) DoConstruct(std::move(*rhs)); } template::value)> explicit optional(in_place_t, Args&& ...args) : mHasValue{true} , mValue{std::forward(args)...} @@ -65,10 +70,7 @@ public: else if(*this) mValue = *rhs; else - { - std::uninitialized_copy_n(std::addressof(*rhs), 1, std::addressof(mValue)); - mHasValue = true; - } + DoConstruct(*rhs); return *this; } template::value && std::is_move_assignable::value)> @@ -79,10 +81,7 @@ public: else if(*this) mValue = std::move(*rhs); else - { - al::uninitialized_move_n(std::addressof(*rhs), 1, std::addressof(mValue)); - mHasValue = true; - } + DoConstruct(std::move(*rhs)); return *this; } template::value && @@ -95,10 +94,7 @@ public: if(*this) mValue = std::forward(rhs); else - { - ::new (std::addressof(mValue)) T{std::forward(rhs)}; - mHasValue = true; - } + DoConstruct(std::forward(rhs)); return *this; } @@ -130,13 +126,6 @@ public: al::destroy_at(std::addressof(mValue)); mHasValue = false; } - -private: - bool mHasValue{false}; - union { - char mDummy[sizeof(T)]{}; - T mValue; - }; }; template -- cgit v1.2.3 From cee8100f1917ce21052b9cf255eeefdc839ae550 Mon Sep 17 00:00:00 2001 From: Minmin Gong Date: Mon, 1 Jul 2019 22:42:21 -0700 Subject: Remove noexcept from sampler functions to match the signature of SamplerT (#309) This change fixes compilation problems on gcc 9.1 with -std=c++17. --- Alc/mixer/mixer_c.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/mixer/mixer_c.cpp b/Alc/mixer/mixer_c.cpp index 80942eab..86a9e438 100644 --- a/Alc/mixer/mixer_c.cpp +++ b/Alc/mixer/mixer_c.cpp @@ -14,13 +14,13 @@ namespace { -inline ALfloat do_point(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei) noexcept +inline ALfloat do_point(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei) { return vals[0]; } -inline ALfloat do_lerp(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei frac) noexcept +inline ALfloat do_lerp(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei frac) { return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); } -inline ALfloat do_cubic(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei frac) noexcept +inline ALfloat do_cubic(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei frac) { return cubic(vals[0], vals[1], vals[2], vals[3], frac * (1.0f/FRACTIONONE)); } -inline ALfloat do_bsinc(const InterpState &istate, const ALfloat *RESTRICT vals, const ALsizei frac) noexcept +inline ALfloat do_bsinc(const InterpState &istate, const ALfloat *RESTRICT vals, const ALsizei frac) { ASSUME(istate.bsinc.m > 0); -- cgit v1.2.3 From 61ba455edd5605ff9919cf5e93e075732312b92f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 2 Jul 2019 01:56:59 -0700 Subject: Don't warn about non-multiple-of-4 update sizes It's not always possible to do anything about it, especially for backends that aren't restricted to the period size, and it's not really a problem anyway (still getting SIMD benefits for the vast majority of samples). --- Alc/alc.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index df272c2a..f624d971 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1999,18 +1999,10 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } if(device->Frequency != oldFreq && device->Flags.get()) { - ERR("Failed to set %uhz, got %uhz instead\n", oldFreq, device->Frequency); + WARN("Failed to set %uhz, got %uhz instead\n", oldFreq, device->Frequency); device->Flags.unset(); } - if((device->UpdateSize&3) != 0) - { - if((CPUCapFlags&CPU_CAP_SSE)) - WARN("SSE performs best with multiple of 4 update sizes (%u)\n", device->UpdateSize); - if((CPUCapFlags&CPU_CAP_NEON)) - WARN("NEON performs best with multiple of 4 update sizes (%u)\n", device->UpdateSize); - } - TRACE("Post-reset: %s, %s, %uhz, %u / %u buffer\n", DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), device->Frequency, device->UpdateSize, device->BufferSize); -- cgit v1.2.3 From 0a0704071a74bb2350bc2735c0b7c554e2bf3a9a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Jul 2019 22:32:39 -0700 Subject: Allocate device buffer when setting the channel counts --- Alc/alc.cpp | 18 ------------------ Alc/panning.cpp | 50 +++++++++++++++++++++++++++++++++----------------- 2 files changed, 33 insertions(+), 35 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index f624d971..d61d8233 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2008,24 +2008,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->Frequency, device->UpdateSize, device->BufferSize); aluInitRenderer(device, hrtf_id, hrtf_appreq, hrtf_userreq); - TRACE("Channel config, Main: %u, Real: %u\n", device->Dry.NumChannels, - device->RealOut.NumChannels); - - /* Allocate extra channels for any post-filter output. */ - const ALuint num_chans{device->Dry.NumChannels + device->RealOut.NumChannels}; - - TRACE("Allocating %u channels, %zu bytes\n", num_chans, - num_chans*sizeof(device->MixBuffer[0])); - device->MixBuffer.resize(num_chans); - - device->Dry.Buffer = device->MixBuffer.data(); - if(device->RealOut.NumChannels != 0) - device->RealOut.Buffer = device->Dry.Buffer + device->Dry.NumChannels; - else - { - device->RealOut.Buffer = device->Dry.Buffer; - device->RealOut.NumChannels = device->Dry.NumChannels; - } device->NumAuxSends = new_sends; TRACE("Max sources: %d (%d + %d), effect slots: %d, sends: %d\n", diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 0a3e89fc..13114c5f 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -106,6 +106,32 @@ inline const char *GetLabelFromChannel(Channel channel) } +void AllocChannels(ALCdevice *device, const ALuint main_chans, const ALuint real_chans) +{ + TRACE("Channel config, Main: %u, Real: %u\n", main_chans, real_chans); + + /* Allocate extra channels for any post-filter output. */ + const ALuint num_chans{main_chans + real_chans}; + + TRACE("Allocating %u channels, %zu bytes\n", num_chans, + num_chans*sizeof(device->MixBuffer[0])); + device->MixBuffer.resize(num_chans); + + device->Dry.Buffer = device->MixBuffer.data(); + device->Dry.NumChannels = main_chans; + if(real_chans != 0) + { + device->RealOut.Buffer = device->Dry.Buffer + device->Dry.NumChannels; + device->RealOut.NumChannels = real_chans; + } + else + { + device->RealOut.Buffer = device->Dry.Buffer; + device->RealOut.NumChannels = device->Dry.NumChannels; + } +} + + struct ChannelMap { Channel ChanName; ALfloat Config[MAX_AMBI2D_CHANNELS]; @@ -380,7 +406,7 @@ void InitPanning(ALCdevice *device) [&n3dscale](const ALsizei &acn) noexcept -> BFChannelConfig { return BFChannelConfig{1.0f/n3dscale[acn], acn}; } ); - device->Dry.NumChannels = static_cast(count); + AllocChannels(device, static_cast(count), 0); ALfloat nfc_delay{ConfigValueFloat(devname, "decoder", "nfc-ref-delay").value_or(0.0f)}; if(nfc_delay > 0.0f) @@ -390,8 +416,6 @@ void InitPanning(ALCdevice *device) InitNearFieldCtrl(device, nfc_delay * SPEEDOFSOUNDMETRESPERSEC, device->mAmbiOrder, chans_per_order); } - - device->RealOut.NumChannels = 0; } else { @@ -420,7 +444,7 @@ void InitPanning(ALCdevice *device) std::begin(device->Dry.AmbiMap), [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } ); - device->Dry.NumChannels = coeffcount; + AllocChannels(device, coeffcount, device->channelsFromFmt()); TRACE("Enabling %s-order%s ambisonic decoder\n", (coeffcount > 5) ? "third" : @@ -429,8 +453,6 @@ void InitPanning(ALCdevice *device) ); device->AmbiDecoder = al::make_unique(coeffcount, static_cast(chanmap.size()), chancoeffs, idxmap); - - device->RealOut.NumChannels = device->channelsFromFmt(); } } @@ -464,7 +486,7 @@ void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, co [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } ); } - device->Dry.NumChannels = count; + AllocChannels(device, count, device->channelsFromFmt()); TRACE("Enabling %s-band %s-order%s ambisonic decoder\n", (!hqdec || conf->FreqBands == 1) ? "single" : "dual", @@ -475,8 +497,6 @@ void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, co device->AmbiDecoder = al::make_unique(conf, hqdec, count, device->Frequency, speakermap); - device->RealOut.NumChannels = device->channelsFromFmt(); - auto accum_spkr_dist = std::bind(std::plus{}, _1, std::bind(std::mem_fn(&AmbDecConf::SpeakerConf::Distance), _2)); const ALfloat avg_dist{ @@ -604,12 +624,10 @@ void InitHrtfPanning(ALCdevice *device) std::begin(device->Dry.AmbiMap), [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } ); - device->Dry.NumChannels = static_cast(count); + AllocChannels(device, static_cast(count), device->channelsFromFmt()); - device->RealOut.NumChannels = device->channelsFromFmt(); - - BuildBFormatHrtf(device->mHrtf, device->mHrtfState.get(), device->Dry.NumChannels, AmbiPoints, - AmbiMatrix, al::size(AmbiPoints), AmbiOrderHFGain); + BuildBFormatHrtf(device->mHrtf, device->mHrtfState.get(), static_cast(count), + AmbiPoints, AmbiMatrix, al::size(AmbiPoints), AmbiOrderHFGain); HrtfEntry *Hrtf{device->mHrtf}; InitNearFieldCtrl(device, Hrtf->field[0].distance, ambi_order, ChansPerOrder); @@ -627,9 +645,7 @@ void InitUhjPanning(ALCdevice *device) [](const ALsizei &acn) noexcept -> BFChannelConfig { return BFChannelConfig{1.0f/AmbiScale::FromFuMa[acn], acn}; } ); - device->Dry.NumChannels = count; - - device->RealOut.NumChannels = device->channelsFromFmt(); + AllocChannels(device, ALuint{count}, device->channelsFromFmt()); } } // namespace -- cgit v1.2.3 From 9a51ca0a782764c97c5c393b799ff76b7b6fb75f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Jul 2019 22:59:29 -0700 Subject: Pass a span to BFormatDec::process --- Alc/alu.cpp | 4 ++-- Alc/bformatdec.cpp | 33 ++++++++++++++++++--------------- Alc/bformatdec.h | 4 ++-- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 094f0dc6..b57a304d 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -147,7 +147,7 @@ void ProcessHrtf(ALCdevice *device, const ALsizei SamplesToDo) void ProcessAmbiDec(ALCdevice *device, const ALsizei SamplesToDo) { BFormatDec *ambidec{device->AmbiDecoder.get()}; - ambidec->process(device->RealOut.Buffer, device->RealOut.NumChannels, device->Dry.Buffer, + ambidec->process({device->RealOut.Buffer, device->RealOut.NumChannels}, device->Dry.Buffer, SamplesToDo); } @@ -168,7 +168,7 @@ void ProcessBs2b(ALCdevice *device, const ALsizei SamplesToDo) { /* First, decode the ambisonic mix to the "real" output. */ BFormatDec *ambidec{device->AmbiDecoder.get()}; - ambidec->process(device->RealOut.Buffer, device->RealOut.NumChannels, device->Dry.Buffer, + ambidec->process({device->RealOut.Buffer, device->RealOut.NumChannels}, device->Dry.Buffer, SamplesToDo); /* BS2B is stereo output only. */ diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 9c0c72ec..6ef398ec 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -146,12 +146,9 @@ BFormatDec::BFormatDec(const ALuint inchans, const ALsizei chancount, } -void BFormatDec::process(FloatBufferLine *OutBuffer, const ALuint OutChannels, +void BFormatDec::process(const al::span OutBuffer, const FloatBufferLine *InSamples, const ALsizei SamplesToDo) { - ASSUME(OutChannels > 0); - ASSUME(mNumChannels > 0); - if(mDualBand) { for(ALuint i{0};i < mNumChannels;i++) @@ -160,24 +157,30 @@ void BFormatDec::process(FloatBufferLine *OutBuffer, const ALuint OutChannels, const al::span hfsamples{mSamplesHF, mNumChannels}; const al::span lfsamples{mSamplesLF, mNumChannels}; - for(ALuint chan{0};chan < OutChannels;chan++) + ALfloat (*mixmtx)[sNumBands][MAX_AMBI_CHANNELS]{mMatrix.Dual}; + ALuint enabled{mEnabled}; + for(FloatBufferLine &outbuf : OutBuffer) { - if(UNLIKELY(!(mEnabled&(1<>= 1; } } else { const al::span insamples{InSamples, mNumChannels}; - for(ALuint chan{0};chan < OutChannels;chan++) + ALfloat (*mixmtx)[MAX_AMBI_CHANNELS]{mMatrix.Single}; + ALuint enabled{mEnabled}; + for(FloatBufferLine &outbuf : OutBuffer) { - if(UNLIKELY(!(mEnabled&(1<>= 1; } } } diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 47723815..1ec4a1bb 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -43,8 +43,8 @@ public: const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]); /* Decodes the ambisonic input to the given output channels. */ - void process(FloatBufferLine *OutBuffer, const ALuint OutChannels, - const FloatBufferLine *InSamples, const ALsizei SamplesToDo); + void process(const al::span OutBuffer, const FloatBufferLine *InSamples, + const ALsizei SamplesToDo); /* Retrieves per-order HF scaling factors for "upsampling" ambisonic data. */ static std::array GetHFOrderScales(const ALsizei in_order, -- cgit v1.2.3 From 949507c891035a4b14d6c06ab5bee1f56e6c24cb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Jul 2019 23:26:33 -0700 Subject: Use a span for RealMixParams --- Alc/alc.cpp | 9 ++++----- Alc/alu.cpp | 23 ++++++++++------------- Alc/effects/dedicated.cpp | 4 ++-- Alc/panning.cpp | 10 ++-------- OpenAL32/Include/alMain.h | 3 +-- 5 files changed, 19 insertions(+), 30 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index d61d8233..866bc4d9 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1637,9 +1637,9 @@ static void alcSetError(ALCdevice *device, ALCenum errorCode) static std::unique_ptr CreateDeviceLimiter(const ALCdevice *device, const ALfloat threshold) { - return CompressorInit(device->RealOut.NumChannels, device->Frequency, - AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, 0.001f, 0.002f, - 0.0f, 0.0f, threshold, INFINITY, 0.0f, 0.020f, 0.200f); + return CompressorInit(static_cast(device->RealOut.Buffer.size()), device->Frequency, + AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, 0.001f, 0.002f, 0.0f, 0.0f, threshold, + INFINITY, 0.0f, 0.020f, 0.200f); } /* UpdateClockBase @@ -1907,8 +1907,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->Dry.NumChannels = 0; std::fill(std::begin(device->NumChannelsPerOrder), std::end(device->NumChannelsPerOrder), 0u); device->RealOut.ChannelIndex.fill(-1); - device->RealOut.Buffer = nullptr; - device->RealOut.NumChannels = 0; + device->RealOut.Buffer = {}; device->MixBuffer.clear(); device->MixBuffer.shrink_to_fit(); diff --git a/Alc/alu.cpp b/Alc/alu.cpp index b57a304d..b447fce8 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -147,8 +147,7 @@ void ProcessHrtf(ALCdevice *device, const ALsizei SamplesToDo) void ProcessAmbiDec(ALCdevice *device, const ALsizei SamplesToDo) { BFormatDec *ambidec{device->AmbiDecoder.get()}; - ambidec->process({device->RealOut.Buffer, device->RealOut.NumChannels}, device->Dry.Buffer, - SamplesToDo); + ambidec->process(device->RealOut.Buffer, device->Dry.Buffer, SamplesToDo); } void ProcessUhj(ALCdevice *device, const ALsizei SamplesToDo) @@ -168,8 +167,7 @@ void ProcessBs2b(ALCdevice *device, const ALsizei SamplesToDo) { /* First, decode the ambisonic mix to the "real" output. */ BFormatDec *ambidec{device->AmbiDecoder.get()}; - ambidec->process({device->RealOut.Buffer, device->RealOut.NumChannels}, device->Dry.Buffer, - SamplesToDo); + ambidec->process(device->RealOut.Buffer, device->Dry.Buffer, SamplesToDo); /* BS2B is stereo output only. */ const int lidx{device->RealOut.ChannelIndex[FrontLeft]}; @@ -666,7 +664,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo /* Direct source channels always play local. Skip the virtual channels * and write inputs to the matching real outputs. */ - voice->mDirect.Buffer = {Device->RealOut.Buffer, Device->RealOut.NumChannels}; + voice->mDirect.Buffer = Device->RealOut.Buffer; for(ALsizei c{0};c < num_channels;c++) { @@ -695,7 +693,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo /* Full HRTF rendering. Skip the virtual channels and render to the * real outputs. */ - voice->mDirect.Buffer = {Device->RealOut.Buffer, Device->RealOut.NumChannels}; + voice->mDirect.Buffer = Device->RealOut.Buffer; if(Distance > std::numeric_limits::epsilon()) { @@ -813,7 +811,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo /* Special-case LFE */ if(chans[c].channel == LFE) { - if(Device->Dry.Buffer == Device->RealOut.Buffer) + if(Device->Dry.Buffer == Device->RealOut.Buffer.data()) { int idx = GetChannelIdxByName(Device->RealOut, chans[c].channel); if(idx != -1) voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain; @@ -860,7 +858,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo /* Special-case LFE */ if(chans[c].channel == LFE) { - if(Device->Dry.Buffer == Device->RealOut.Buffer) + if(Device->Dry.Buffer == Device->RealOut.Buffer.data()) { int idx = GetChannelIdxByName(Device->RealOut, chans[c].channel); if(idx != -1) voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain; @@ -1678,6 +1676,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) */ if(LIKELY(device->PostProcess)) device->PostProcess(device, SamplesToDo); + const al::span RealOut{device->RealOut.Buffer}; /* Apply front image stablization for surround sound, if applicable. */ if(device->Stablizer) @@ -1687,16 +1686,14 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) const int cidx{GetChannelIdxByName(device->RealOut, FrontCenter)}; assert(lidx >= 0 && ridx >= 0 && cidx >= 0); - ApplyStablizer(device->Stablizer.get(), device->RealOut.Buffer, lidx, ridx, cidx, - SamplesToDo, device->RealOut.NumChannels); + ApplyStablizer(device->Stablizer.get(), RealOut.data(), lidx, ridx, cidx, SamplesToDo, + static_cast(RealOut.size())); } /* Apply compression, limiting sample amplitude if needed or desired. */ if(Compressor *comp{device->Limiter.get()}) - comp->process(SamplesToDo, device->RealOut.Buffer); + comp->process(SamplesToDo, RealOut.data()); - const al::span RealOut{device->RealOut.Buffer, - device->RealOut.NumChannels}; /* Apply delays and attenuation for mismatched speaker distances. */ ApplyDistanceComp(RealOut, SamplesToDo, device->ChannelDelay.as_span().cbegin()); diff --git a/Alc/effects/dedicated.cpp b/Alc/effects/dedicated.cpp index eb4076b2..12040af9 100644 --- a/Alc/effects/dedicated.cpp +++ b/Alc/effects/dedicated.cpp @@ -62,7 +62,7 @@ void DedicatedState::update(const ALCcontext* UNUSED(context), const ALeffectslo const int idx{!target.RealOut ? -1 : GetChannelIdxByName(*target.RealOut, LFE)}; if(idx != -1) { - mOutTarget = {target.RealOut->Buffer, target.RealOut->NumChannels}; + mOutTarget = target.RealOut->Buffer; mTargetGains[idx] = Gain; } } @@ -73,7 +73,7 @@ void DedicatedState::update(const ALCcontext* UNUSED(context), const ALeffectslo const int idx{!target.RealOut ? -1 : GetChannelIdxByName(*target.RealOut, FrontCenter)}; if(idx != -1) { - mOutTarget = {target.RealOut->Buffer, target.RealOut->NumChannels}; + mOutTarget = target.RealOut->Buffer; mTargetGains[idx] = Gain; } else diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 13114c5f..ba0b76ec 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -120,15 +120,9 @@ void AllocChannels(ALCdevice *device, const ALuint main_chans, const ALuint real device->Dry.Buffer = device->MixBuffer.data(); device->Dry.NumChannels = main_chans; if(real_chans != 0) - { - device->RealOut.Buffer = device->Dry.Buffer + device->Dry.NumChannels; - device->RealOut.NumChannels = real_chans; - } + device->RealOut.Buffer = {device->Dry.Buffer+device->Dry.NumChannels, real_chans}; else - { - device->RealOut.Buffer = device->Dry.Buffer; - device->RealOut.NumChannels = device->Dry.NumChannels; - } + device->RealOut.Buffer = {device->Dry.Buffer, device->Dry.NumChannels}; } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 3008aeca..d7c22546 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -317,8 +317,7 @@ struct MixParams { struct RealMixParams { std::array ChannelIndex{}; - FloatBufferLine *Buffer{nullptr}; - ALuint NumChannels{0u}; + al::span Buffer; }; using POSTPROCESS = void(*)(ALCdevice *device, const ALsizei SamplesToDo); -- cgit v1.2.3 From 729ffe02d6ab05dc8c62e8332ef1878bbfbdf756 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 Jul 2019 14:03:27 -0700 Subject: Reorder some methods for better placement --- Alc/panning.cpp | 219 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 109 insertions(+), 110 deletions(-) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index ba0b76ec..44b6053a 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -644,116 +644,6 @@ void InitUhjPanning(ALCdevice *device) } // namespace - -void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread, - ALfloat (&coeffs)[MAX_AMBI_CHANNELS]) -{ - /* Zeroth-order */ - coeffs[0] = 1.0f; /* ACN 0 = 1 */ - /* First-order */ - coeffs[1] = 1.732050808f * y; /* ACN 1 = sqrt(3) * Y */ - coeffs[2] = 1.732050808f * z; /* ACN 2 = sqrt(3) * Z */ - coeffs[3] = 1.732050808f * x; /* ACN 3 = sqrt(3) * X */ - /* Second-order */ - coeffs[4] = 3.872983346f * x * y; /* ACN 4 = sqrt(15) * X * Y */ - coeffs[5] = 3.872983346f * y * z; /* ACN 5 = sqrt(15) * Y * Z */ - coeffs[6] = 1.118033989f * (z*z*3.0f - 1.0f); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */ - coeffs[7] = 3.872983346f * x * z; /* ACN 7 = sqrt(15) * X * Z */ - coeffs[8] = 1.936491673f * (x*x - y*y); /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */ - /* Third-order */ - coeffs[9] = 2.091650066f * y * (x*x*3.0f - y*y); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */ - coeffs[10] = 10.246950766f * z * x * y; /* ACN 10 = sqrt(105) * Z * X * Y */ - coeffs[11] = 1.620185175f * y * (z*z*5.0f - 1.0f); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */ - coeffs[12] = 1.322875656f * z * (z*z*5.0f - 3.0f); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */ - coeffs[13] = 1.620185175f * x * (z*z*5.0f - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */ - coeffs[14] = 5.123475383f * z * (x*x - y*y); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */ - coeffs[15] = 2.091650066f * x * (x*x - y*y*3.0f); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */ - /* Fourth-order */ - /* ACN 16 = sqrt(35)*3/2 * X * Y * (X*X - Y*Y) */ - /* ACN 17 = sqrt(35/2)*3/2 * (3*X*X - Y*Y) * Y * Z */ - /* ACN 18 = sqrt(5)*3/2 * X * Y * (7*Z*Z - 1) */ - /* ACN 19 = sqrt(5/2)*3/2 * Y * Z * (7*Z*Z - 3) */ - /* ACN 20 = 3/8 * (35*Z*Z*Z*Z - 30*Z*Z + 3) */ - /* ACN 21 = sqrt(5/2)*3/2 * X * Z * (7*Z*Z - 3) */ - /* ACN 22 = sqrt(5)*3/4 * (X*X - Y*Y) * (7*Z*Z - 1) */ - /* ACN 23 = sqrt(35/2)*3/2 * (X*X - 3*Y*Y) * X * Z */ - /* ACN 24 = sqrt(35)*3/8 * (X*X*X*X - 6*X*X*Y*Y + Y*Y*Y*Y) */ - - if(spread > 0.0f) - { - /* Implement the spread by using a spherical source that subtends the - * angle spread. See: - * http://www.ppsloan.org/publications/StupidSH36.pdf - Appendix A3 - * - * When adjusted for N3D normalization instead of SN3D, these - * calculations are: - * - * ZH0 = -sqrt(pi) * (-1+ca); - * ZH1 = 0.5*sqrt(pi) * sa*sa; - * ZH2 = -0.5*sqrt(pi) * ca*(-1+ca)*(ca+1); - * ZH3 = -0.125*sqrt(pi) * (-1+ca)*(ca+1)*(5*ca*ca - 1); - * ZH4 = -0.125*sqrt(pi) * ca*(-1+ca)*(ca+1)*(7*ca*ca - 3); - * ZH5 = -0.0625*sqrt(pi) * (-1+ca)*(ca+1)*(21*ca*ca*ca*ca - 14*ca*ca + 1); - * - * The gain of the source is compensated for size, so that the - * loudness doesn't depend on the spread. Thus: - * - * ZH0 = 1.0f; - * ZH1 = 0.5f * (ca+1.0f); - * ZH2 = 0.5f * (ca+1.0f)*ca; - * ZH3 = 0.125f * (ca+1.0f)*(5.0f*ca*ca - 1.0f); - * ZH4 = 0.125f * (ca+1.0f)*(7.0f*ca*ca - 3.0f)*ca; - * ZH5 = 0.0625f * (ca+1.0f)*(21.0f*ca*ca*ca*ca - 14.0f*ca*ca + 1.0f); - */ - ALfloat ca = std::cos(spread * 0.5f); - /* Increase the source volume by up to +3dB for a full spread. */ - ALfloat scale = std::sqrt(1.0f + spread/al::MathDefs::Tau()); - - ALfloat ZH0_norm = scale; - ALfloat ZH1_norm = 0.5f * (ca+1.f) * scale; - ALfloat ZH2_norm = 0.5f * (ca+1.f)*ca * scale; - ALfloat ZH3_norm = 0.125f * (ca+1.f)*(5.f*ca*ca-1.f) * scale; - - /* Zeroth-order */ - coeffs[0] *= ZH0_norm; - /* First-order */ - coeffs[1] *= ZH1_norm; - coeffs[2] *= ZH1_norm; - coeffs[3] *= ZH1_norm; - /* Second-order */ - coeffs[4] *= ZH2_norm; - coeffs[5] *= ZH2_norm; - coeffs[6] *= ZH2_norm; - coeffs[7] *= ZH2_norm; - coeffs[8] *= ZH2_norm; - /* Third-order */ - coeffs[9] *= ZH3_norm; - coeffs[10] *= ZH3_norm; - coeffs[11] *= ZH3_norm; - coeffs[12] *= ZH3_norm; - coeffs[13] *= ZH3_norm; - coeffs[14] *= ZH3_norm; - coeffs[15] *= ZH3_norm; - } -} - -void ComputePanGains(const MixParams *mix, const ALfloat *RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) -{ - auto ambimap = mix->AmbiMap.cbegin(); - const ALuint numchans{mix->NumChannels}; - - ASSUME(numchans > 0); - auto iter = std::transform(ambimap, ambimap+numchans, std::begin(gains), - [coeffs,ingain](const BFChannelConfig &chanmap) noexcept -> ALfloat - { - ASSUME(chanmap.Index >= 0); - return chanmap.Scale * coeffs[chanmap.Index] * ingain; - } - ); - std::fill(iter, std::end(gains), 0.0f); -} - - void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appreq, HrtfRequestMode hrtf_userreq) { /* Hold the HRTF the device last used, in case it's used again. */ @@ -963,3 +853,112 @@ void aluInitEffectPanning(ALeffectslot *slot, ALCdevice *device) slot->Wet.Buffer = slot->MixBuffer.data(); slot->Wet.NumChannels = static_cast(count); } + + +void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread, + ALfloat (&coeffs)[MAX_AMBI_CHANNELS]) +{ + /* Zeroth-order */ + coeffs[0] = 1.0f; /* ACN 0 = 1 */ + /* First-order */ + coeffs[1] = 1.732050808f * y; /* ACN 1 = sqrt(3) * Y */ + coeffs[2] = 1.732050808f * z; /* ACN 2 = sqrt(3) * Z */ + coeffs[3] = 1.732050808f * x; /* ACN 3 = sqrt(3) * X */ + /* Second-order */ + coeffs[4] = 3.872983346f * x * y; /* ACN 4 = sqrt(15) * X * Y */ + coeffs[5] = 3.872983346f * y * z; /* ACN 5 = sqrt(15) * Y * Z */ + coeffs[6] = 1.118033989f * (z*z*3.0f - 1.0f); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */ + coeffs[7] = 3.872983346f * x * z; /* ACN 7 = sqrt(15) * X * Z */ + coeffs[8] = 1.936491673f * (x*x - y*y); /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */ + /* Third-order */ + coeffs[9] = 2.091650066f * y * (x*x*3.0f - y*y); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */ + coeffs[10] = 10.246950766f * z * x * y; /* ACN 10 = sqrt(105) * Z * X * Y */ + coeffs[11] = 1.620185175f * y * (z*z*5.0f - 1.0f); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */ + coeffs[12] = 1.322875656f * z * (z*z*5.0f - 3.0f); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */ + coeffs[13] = 1.620185175f * x * (z*z*5.0f - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */ + coeffs[14] = 5.123475383f * z * (x*x - y*y); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */ + coeffs[15] = 2.091650066f * x * (x*x - y*y*3.0f); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */ + /* Fourth-order */ + /* ACN 16 = sqrt(35)*3/2 * X * Y * (X*X - Y*Y) */ + /* ACN 17 = sqrt(35/2)*3/2 * (3*X*X - Y*Y) * Y * Z */ + /* ACN 18 = sqrt(5)*3/2 * X * Y * (7*Z*Z - 1) */ + /* ACN 19 = sqrt(5/2)*3/2 * Y * Z * (7*Z*Z - 3) */ + /* ACN 20 = 3/8 * (35*Z*Z*Z*Z - 30*Z*Z + 3) */ + /* ACN 21 = sqrt(5/2)*3/2 * X * Z * (7*Z*Z - 3) */ + /* ACN 22 = sqrt(5)*3/4 * (X*X - Y*Y) * (7*Z*Z - 1) */ + /* ACN 23 = sqrt(35/2)*3/2 * (X*X - 3*Y*Y) * X * Z */ + /* ACN 24 = sqrt(35)*3/8 * (X*X*X*X - 6*X*X*Y*Y + Y*Y*Y*Y) */ + + if(spread > 0.0f) + { + /* Implement the spread by using a spherical source that subtends the + * angle spread. See: + * http://www.ppsloan.org/publications/StupidSH36.pdf - Appendix A3 + * + * When adjusted for N3D normalization instead of SN3D, these + * calculations are: + * + * ZH0 = -sqrt(pi) * (-1+ca); + * ZH1 = 0.5*sqrt(pi) * sa*sa; + * ZH2 = -0.5*sqrt(pi) * ca*(-1+ca)*(ca+1); + * ZH3 = -0.125*sqrt(pi) * (-1+ca)*(ca+1)*(5*ca*ca - 1); + * ZH4 = -0.125*sqrt(pi) * ca*(-1+ca)*(ca+1)*(7*ca*ca - 3); + * ZH5 = -0.0625*sqrt(pi) * (-1+ca)*(ca+1)*(21*ca*ca*ca*ca - 14*ca*ca + 1); + * + * The gain of the source is compensated for size, so that the + * loudness doesn't depend on the spread. Thus: + * + * ZH0 = 1.0f; + * ZH1 = 0.5f * (ca+1.0f); + * ZH2 = 0.5f * (ca+1.0f)*ca; + * ZH3 = 0.125f * (ca+1.0f)*(5.0f*ca*ca - 1.0f); + * ZH4 = 0.125f * (ca+1.0f)*(7.0f*ca*ca - 3.0f)*ca; + * ZH5 = 0.0625f * (ca+1.0f)*(21.0f*ca*ca*ca*ca - 14.0f*ca*ca + 1.0f); + */ + ALfloat ca = std::cos(spread * 0.5f); + /* Increase the source volume by up to +3dB for a full spread. */ + ALfloat scale = std::sqrt(1.0f + spread/al::MathDefs::Tau()); + + ALfloat ZH0_norm = scale; + ALfloat ZH1_norm = 0.5f * (ca+1.f) * scale; + ALfloat ZH2_norm = 0.5f * (ca+1.f)*ca * scale; + ALfloat ZH3_norm = 0.125f * (ca+1.f)*(5.f*ca*ca-1.f) * scale; + + /* Zeroth-order */ + coeffs[0] *= ZH0_norm; + /* First-order */ + coeffs[1] *= ZH1_norm; + coeffs[2] *= ZH1_norm; + coeffs[3] *= ZH1_norm; + /* Second-order */ + coeffs[4] *= ZH2_norm; + coeffs[5] *= ZH2_norm; + coeffs[6] *= ZH2_norm; + coeffs[7] *= ZH2_norm; + coeffs[8] *= ZH2_norm; + /* Third-order */ + coeffs[9] *= ZH3_norm; + coeffs[10] *= ZH3_norm; + coeffs[11] *= ZH3_norm; + coeffs[12] *= ZH3_norm; + coeffs[13] *= ZH3_norm; + coeffs[14] *= ZH3_norm; + coeffs[15] *= ZH3_norm; + } +} + +void ComputePanGains(const MixParams *mix, const ALfloat *RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) +{ + auto ambimap = mix->AmbiMap.cbegin(); + const ALuint numchans{mix->NumChannels}; + + ASSUME(numchans > 0); + auto iter = std::transform(ambimap, ambimap+numchans, std::begin(gains), + [coeffs,ingain](const BFChannelConfig &chanmap) noexcept -> ALfloat + { + ASSUME(chanmap.Index >= 0); + return chanmap.Scale * coeffs[chanmap.Index] * ingain; + } + ); + std::fill(iter, std::end(gains), 0.0f); +} -- cgit v1.2.3 From 3fe5ef272f436db82beeeee3ad123029e4d219b6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 Jul 2019 15:02:12 -0700 Subject: Use a span for MixParams --- Alc/alc.cpp | 7 +++---- Alc/alu.cpp | 28 +++++++++++++--------------- Alc/effects/autowah.cpp | 4 ++-- Alc/effects/chorus.cpp | 2 +- Alc/effects/compressor.cpp | 4 ++-- Alc/effects/dedicated.cpp | 2 +- Alc/effects/distortion.cpp | 2 +- Alc/effects/echo.cpp | 2 +- Alc/effects/equalizer.cpp | 6 +++--- Alc/effects/fshifter.cpp | 2 +- Alc/effects/modulator.cpp | 6 +++--- Alc/effects/pshifter.cpp | 2 +- Alc/effects/reverb.cpp | 2 +- Alc/panning.cpp | 19 ++++++++++--------- OpenAL32/Include/alMain.h | 5 ++--- OpenAL32/alAuxEffectSlot.cpp | 2 +- 16 files changed, 46 insertions(+), 49 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 866bc4d9..5d2b2020 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1903,8 +1903,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->ChannelDelay.clear(); device->Dry.AmbiMap.fill(BFChannelConfig{}); - device->Dry.Buffer = nullptr; - device->Dry.NumChannels = 0; + device->Dry.Buffer = {}; std::fill(std::begin(device->NumChannelsPerOrder), std::end(device->NumChannelsPerOrder), 0u); device->RealOut.ChannelIndex.fill(-1); device->RealOut.Buffer = {}; @@ -2158,7 +2157,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) aluInitEffectPanning(slot, device); EffectState *state{slot->Effect.State}; - state->mOutTarget = {device->Dry.Buffer, device->Dry.NumChannels}; + state->mOutTarget = device->Dry.Buffer; if(state->deviceUpdate(device) == AL_FALSE) update_failed = AL_TRUE; else @@ -2180,7 +2179,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) aluInitEffectPanning(slot, device); EffectState *state{slot->Effect.State}; - state->mOutTarget = {device->Dry.Buffer, device->Dry.NumChannels}; + state->mOutTarget = device->Dry.Buffer; if(state->deviceUpdate(device) == AL_FALSE) update_failed = AL_TRUE; else diff --git a/Alc/alu.cpp b/Alc/alu.cpp index b447fce8..b12559d7 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -140,14 +140,14 @@ void ProcessHrtf(ALCdevice *device, const ALsizei SamplesToDo) ASSUME(lidx >= 0 && ridx >= 0); DirectHrtfState *state{device->mHrtfState.get()}; - MixDirectHrtf(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], - {device->Dry.Buffer, device->Dry.NumChannels}, device->HrtfAccumData, state, SamplesToDo); + MixDirectHrtf(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], device->Dry.Buffer, + device->HrtfAccumData, state, SamplesToDo); } void ProcessAmbiDec(ALCdevice *device, const ALsizei SamplesToDo) { BFormatDec *ambidec{device->AmbiDecoder.get()}; - ambidec->process(device->RealOut.Buffer, device->Dry.Buffer, SamplesToDo); + ambidec->process(device->RealOut.Buffer, device->Dry.Buffer.data(), SamplesToDo); } void ProcessUhj(ALCdevice *device, const ALsizei SamplesToDo) @@ -160,14 +160,14 @@ void ProcessUhj(ALCdevice *device, const ALsizei SamplesToDo) /* Encode to stereo-compatible 2-channel UHJ output. */ Uhj2Encoder *uhj2enc{device->Uhj_Encoder.get()}; uhj2enc->encode(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], - device->Dry.Buffer, SamplesToDo); + device->Dry.Buffer.data(), SamplesToDo); } void ProcessBs2b(ALCdevice *device, const ALsizei SamplesToDo) { /* First, decode the ambisonic mix to the "real" output. */ BFormatDec *ambidec{device->AmbiDecoder.get()}; - ambidec->process(device->RealOut.Buffer, device->Dry.Buffer, SamplesToDo); + ambidec->process(device->RealOut.Buffer, device->Dry.Buffer.data(), SamplesToDo); /* BS2B is stereo output only. */ const int lidx{device->RealOut.ChannelIndex[FrontLeft]}; @@ -811,7 +811,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo /* Special-case LFE */ if(chans[c].channel == LFE) { - if(Device->Dry.Buffer == Device->RealOut.Buffer.data()) + if(Device->Dry.Buffer.data() == Device->RealOut.Buffer.data()) { int idx = GetChannelIdxByName(Device->RealOut, chans[c].channel); if(idx != -1) voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain; @@ -858,7 +858,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo /* Special-case LFE */ if(chans[c].channel == LFE) { - if(Device->Dry.Buffer == Device->RealOut.Buffer.data()) + if(Device->Dry.Buffer.data() == Device->RealOut.Buffer.data()) { int idx = GetChannelIdxByName(Device->RealOut, chans[c].channel); if(idx != -1) voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain; @@ -936,7 +936,7 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons const ALCdevice *Device{ALContext->Device}; ALeffectslot *SendSlots[MAX_SENDS]; - voice->mDirect.Buffer = {Device->Dry.Buffer, static_cast(Device->Dry.NumChannels)}; + voice->mDirect.Buffer = Device->Dry.Buffer; for(ALsizei i{0};i < Device->NumAuxSends;i++) { SendSlots[i] = props->Send[i].Slot; @@ -948,9 +948,7 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons voice->mSend[i].Buffer = {}; } else - { - voice->mSend[i].Buffer = {SendSlots[i]->Wet.Buffer, SendSlots[i]->Wet.NumChannels}; - } + voice->mSend[i].Buffer = SendSlots[i]->Wet.Buffer; } /* Calculate the stepping value */ @@ -994,7 +992,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A const ALlistener &Listener = ALContext->Listener; /* Set mixing buffers and get send parameters. */ - voice->mDirect.Buffer = {Device->Dry.Buffer, Device->Dry.NumChannels}; + voice->mDirect.Buffer = Device->Dry.Buffer; ALeffectslot *SendSlots[MAX_SENDS]; ALfloat RoomRolloff[MAX_SENDS]; ALfloat DecayDistance[MAX_SENDS]; @@ -1051,7 +1049,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A if(!SendSlots[i]) voice->mSend[i].Buffer = {}; else - voice->mSend[i].Buffer = {SendSlots[i]->Wet.Buffer, SendSlots[i]->Wet.NumChannels}; + voice->mSend[i].Buffer = SendSlots[i]->Wet.Buffer; } /* Transform source to listener space (convert to head relative) */ @@ -1424,8 +1422,8 @@ void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) [SamplesToDo](const ALeffectslot *slot) -> void { EffectState *state{slot->Params.mEffectState}; - state->process(SamplesToDo, slot->Wet.Buffer, slot->Wet.NumChannels, - state->mOutTarget); + state->process(SamplesToDo, slot->Wet.Buffer.data(), + static_cast(slot->Wet.Buffer.size()), state->mOutTarget); } ); } diff --git a/Alc/effects/autowah.cpp b/Alc/effects/autowah.cpp index 90af6134..f1160804 100644 --- a/Alc/effects/autowah.cpp +++ b/Alc/effects/autowah.cpp @@ -119,8 +119,8 @@ void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, mFreqMinNorm = MIN_FREQ / device->Frequency; mBandwidthNorm = (MAX_FREQ-MIN_FREQ) / device->Frequency; - mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; - for(ALuint i{0u};i < slot->Wet.NumChannels;++i) + mOutTarget = target.Main->Buffer; + for(size_t i{0u};i < slot->Wet.Buffer.size();++i) { auto coeffs = GetAmbiIdentityRow(i); ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mChans[i].TargetGains); diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp index b77c3439..a2a34008 100644 --- a/Alc/effects/chorus.cpp +++ b/Alc/effects/chorus.cpp @@ -159,7 +159,7 @@ void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, co CalcDirectionCoeffs({-1.0f, 0.0f, 0.0f}, 0.0f, coeffs[0]); CalcDirectionCoeffs({ 1.0f, 0.0f, 0.0f}, 0.0f, coeffs[1]); - mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; + mOutTarget = target.Main->Buffer; ComputePanGains(target.Main, coeffs[0], Slot->Params.Gain, mGains[0].Target); ComputePanGains(target.Main, coeffs[1], Slot->Params.Gain, mGains[1].Target); diff --git a/Alc/effects/compressor.cpp b/Alc/effects/compressor.cpp index 883488cb..542ef684 100644 --- a/Alc/effects/compressor.cpp +++ b/Alc/effects/compressor.cpp @@ -78,8 +78,8 @@ void CompressorState::update(const ALCcontext* UNUSED(context), const ALeffectsl { mEnabled = props->Compressor.OnOff; - mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; - for(ALuint i{0u};i < slot->Wet.NumChannels;++i) + mOutTarget = target.Main->Buffer; + for(size_t i{0u};i < slot->Wet.Buffer.size();++i) { auto coeffs = GetAmbiIdentityRow(i); ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mGain[i]); diff --git a/Alc/effects/dedicated.cpp b/Alc/effects/dedicated.cpp index 12040af9..b5fdb626 100644 --- a/Alc/effects/dedicated.cpp +++ b/Alc/effects/dedicated.cpp @@ -81,7 +81,7 @@ void DedicatedState::update(const ALCcontext* UNUSED(context), const ALeffectslo ALfloat coeffs[MAX_AMBI_CHANNELS]; CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); - mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; + mOutTarget = target.Main->Buffer; ComputePanGains(target.Main, coeffs, Gain, mTargetGains); } } diff --git a/Alc/effects/distortion.cpp b/Alc/effects/distortion.cpp index 3b8b73b7..a58ac5a6 100644 --- a/Alc/effects/distortion.cpp +++ b/Alc/effects/distortion.cpp @@ -90,7 +90,7 @@ void DistortionState::update(const ALCcontext *context, const ALeffectslot *slot ALfloat coeffs[MAX_AMBI_CHANNELS]; CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); - mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; + mOutTarget = target.Main->Buffer; ComputePanGains(target.Main, coeffs, slot->Params.Gain*props->Distortion.Gain, mGain); } diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index 594d2a7c..0211520b 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -113,7 +113,7 @@ void EchoState::update(const ALCcontext *context, const ALeffectslot *slot, cons CalcAngleCoeffs(-angle, 0.0f, 0.0f, coeffs[0]); CalcAngleCoeffs( angle, 0.0f, 0.0f, coeffs[1]); - mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; + mOutTarget = target.Main->Buffer; ComputePanGains(target.Main, coeffs[0], slot->Params.Gain, mGains[0].Target); ComputePanGains(target.Main, coeffs[1], slot->Params.Gain, mGains[1].Target); } diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index 14013aad..995f03df 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -141,7 +141,7 @@ void EqualizerState::update(const ALCcontext *context, const ALeffectslot *slot, BiquadFilter::rcpQFromSlope(gain, 0.75f)); /* Copy the filter coefficients for the other input channels. */ - for(ALuint i{1u};i < slot->Wet.NumChannels;++i) + for(size_t i{1u};i < slot->Wet.Buffer.size();++i) { mChans[i].filter[0].copyParamsFrom(mChans[0].filter[0]); mChans[i].filter[1].copyParamsFrom(mChans[0].filter[1]); @@ -149,8 +149,8 @@ void EqualizerState::update(const ALCcontext *context, const ALeffectslot *slot, mChans[i].filter[3].copyParamsFrom(mChans[0].filter[3]); } - mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; - for(ALuint i{0u};i < slot->Wet.NumChannels;++i) + mOutTarget = target.Main->Buffer; + for(size_t i{0u};i < slot->Wet.Buffer.size();++i) { auto coeffs = GetAmbiIdentityRow(i); ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mChans[i].TargetGains); diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp index 0bbcc859..6378db89 100644 --- a/Alc/effects/fshifter.cpp +++ b/Alc/effects/fshifter.cpp @@ -133,7 +133,7 @@ void FshifterState::update(const ALCcontext *context, const ALeffectslot *slot, ALfloat coeffs[MAX_AMBI_CHANNELS]; CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); - mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; + mOutTarget = target.Main->Buffer; ComputePanGains(target.Main, coeffs, slot->Params.Gain, mTargetGains); } diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index 12974faa..46d17d1c 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -129,11 +129,11 @@ void ModulatorState::update(const ALCcontext *context, const ALeffectslot *slot, /* Bandwidth value is constant in octaves. */ mChans[0].Filter.setParams(BiquadType::HighPass, 1.0f, f0norm, BiquadFilter::rcpQFromBandwidth(f0norm, 0.75f)); - for(ALuint i{1u};i < slot->Wet.NumChannels;++i) + for(size_t i{1u};i < slot->Wet.Buffer.size();++i) mChans[i].Filter.copyParamsFrom(mChans[0].Filter); - mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; - for(ALuint i{0u};i < slot->Wet.NumChannels;++i) + mOutTarget = target.Main->Buffer; + for(size_t i{0u};i < slot->Wet.Buffer.size();++i) { auto coeffs = GetAmbiIdentityRow(i); ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mChans[i].TargetGains); diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp index 619bde34..5a1e3817 100644 --- a/Alc/effects/pshifter.cpp +++ b/Alc/effects/pshifter.cpp @@ -192,7 +192,7 @@ void PshifterState::update(const ALCcontext* UNUSED(context), const ALeffectslot ALfloat coeffs[MAX_AMBI_CHANNELS]; CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); - mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; + mOutTarget = target.Main->Buffer; ComputePanGains(target.Main, coeffs, slot->Params.Gain, mTargetGains); } diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index da8be835..01f5c476 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -889,7 +889,7 @@ void ReverbState::update3DPanning(const ALfloat *ReflectionsPan, const ALfloat * const alu::Matrix earlymat{GetTransformFromVector(ReflectionsPan)}; const alu::Matrix latemat{GetTransformFromVector(LateReverbPan)}; - mOutTarget = {target.Main->Buffer, target.Main->NumChannels}; + mOutTarget = target.Main->Buffer; for(ALsizei i{0};i < NUM_LINES;i++) { const ALfloat coeffs[MAX_AMBI_CHANNELS]{earlymat[0][i], earlymat[1][i], earlymat[2][i], diff --git a/Alc/panning.cpp b/Alc/panning.cpp index 44b6053a..d1add5d5 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -116,13 +116,17 @@ void AllocChannels(ALCdevice *device, const ALuint main_chans, const ALuint real TRACE("Allocating %u channels, %zu bytes\n", num_chans, num_chans*sizeof(device->MixBuffer[0])); device->MixBuffer.resize(num_chans); + al::span buffer{device->MixBuffer.data(), device->MixBuffer.size()}; - device->Dry.Buffer = device->MixBuffer.data(); - device->Dry.NumChannels = main_chans; + device->Dry.Buffer = buffer.first(main_chans); + buffer = buffer.subspan(main_chans); if(real_chans != 0) - device->RealOut.Buffer = {device->Dry.Buffer+device->Dry.NumChannels, real_chans}; + { + device->RealOut.Buffer = buffer.first(real_chans); + buffer = buffer.subspan(real_chans); + } else - device->RealOut.Buffer = {device->Dry.Buffer, device->Dry.NumChannels}; + device->RealOut.Buffer = device->Dry.Buffer; } @@ -850,8 +854,7 @@ void aluInitEffectPanning(ALeffectslot *slot, ALCdevice *device) { return BFChannelConfig{1.0f, acn}; } ); std::fill(iter, slot->Wet.AmbiMap.end(), BFChannelConfig{}); - slot->Wet.Buffer = slot->MixBuffer.data(); - slot->Wet.NumChannels = static_cast(count); + slot->Wet.Buffer = {slot->MixBuffer.data(), slot->MixBuffer.size()}; } @@ -950,10 +953,8 @@ void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALf void ComputePanGains(const MixParams *mix, const ALfloat *RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) { auto ambimap = mix->AmbiMap.cbegin(); - const ALuint numchans{mix->NumChannels}; - ASSUME(numchans > 0); - auto iter = std::transform(ambimap, ambimap+numchans, std::begin(gains), + auto iter = std::transform(ambimap, ambimap+mix->Buffer.size(), std::begin(gains), [coeffs,ingain](const BFChannelConfig &chanmap) noexcept -> ALfloat { ASSUME(chanmap.Index >= 0); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index d7c22546..2237d3c8 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -308,10 +308,9 @@ using FloatBufferLine = std::array; struct MixParams { /* Coefficient channel mapping for mixing to the buffer. */ - std::array AmbiMap; + std::array AmbiMap{}; - FloatBufferLine *Buffer{nullptr}; - ALuint NumChannels{0u}; + al::span Buffer; }; struct RealMixParams { diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index 249f7cf3..55fbc622 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -643,7 +643,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect FPUCtl mixer_mode{}; ALCdevice *Device{Context->Device}; std::unique_lock statelock{Device->StateLock}; - State->mOutTarget = {Device->Dry.Buffer, Device->Dry.NumChannels}; + State->mOutTarget = Device->Dry.Buffer; if(State->deviceUpdate(Device) == AL_FALSE) { statelock.unlock(); -- cgit v1.2.3 From 474073955bd76f868d97a4fb587ec4c37b29f7f7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 Jul 2019 17:00:01 -0700 Subject: Pass a span to ApplyStablizer --- Alc/alu.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Alc/alu.cpp b/Alc/alu.cpp index b12559d7..f5c3b842 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -1429,16 +1429,16 @@ void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) } -void ApplyStablizer(FrontStablizer *Stablizer, FloatBufferLine *Buffer, const ALuint lidx, - const ALuint ridx, const ALuint cidx, const ALsizei SamplesToDo, const ALuint NumChannels) +void ApplyStablizer(FrontStablizer *Stablizer, const al::span Buffer, + const ALuint lidx, const ALuint ridx, const ALuint cidx, const ALsizei SamplesToDo) { ASSUME(SamplesToDo > 0); - ASSUME(NumChannels > 0); /* Apply a delay to all channels, except the front-left and front-right, so * they maintain correct timing. */ - for(ALuint i{0};i < NumChannels;i++) + const size_t NumChannels{Buffer.size()}; + for(size_t i{0u};i < NumChannels;i++) { if(i == lidx || i == ridx) continue; @@ -1684,8 +1684,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) const int cidx{GetChannelIdxByName(device->RealOut, FrontCenter)}; assert(lidx >= 0 && ridx >= 0 && cidx >= 0); - ApplyStablizer(device->Stablizer.get(), RealOut.data(), lidx, ridx, cidx, SamplesToDo, - static_cast(RealOut.size())); + ApplyStablizer(device->Stablizer.get(), RealOut, lidx, ridx, cidx, SamplesToDo); } /* Apply compression, limiting sample amplitude if needed or desired. */ -- cgit v1.2.3 From 3edbeefdb73b650d466b76583c8dac664d4d6ee0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 Jul 2019 22:59:12 -0700 Subject: Add a setting for hrtf-mode to alsoft-config --- utils/alsoft-config/mainwindow.cpp | 37 ++++++++++++++++++++ utils/alsoft-config/mainwindow.h | 1 + utils/alsoft-config/mainwindow.ui | 71 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 4e2b2464..687f9134 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -123,6 +123,14 @@ static const struct NameValuePair { { "ACN, N3D", "acn+n3d" }, { "Furse-Malham", "fuma" }, + { "", "" } +}, hrtfModeList[] = { + { "1st Order Ambisonic", "ambi1" }, + { "2nd Order Ambisonic", "ambi2" }, + { "3rd Order Ambisonic", "ambi3" }, + { "Default (Full)", "" }, + { "Full", "full" }, + { "", "" } }; @@ -267,6 +275,9 @@ MainWindow::MainWindow(QWidget *parent) : } ui->resamplerSlider->setRange(0, count-1); + for(count = 0;hrtfModeList[count].name[0];count++) { + } + ui->hrtfqualitySlider->setRange(0, count-1); ui->hrtfStateComboBox->adjustSize(); #if !defined(HAVE_NEON) && !defined(HAVE_SSE) @@ -367,6 +378,8 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->preferredHrtfComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); connect(ui->hrtfStateComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); + connect(ui->hrtfqualitySlider, SIGNAL(valueChanged(int)), this, SLOT(updateHrtfModeLabel(int))); + connect(ui->hrtfAddButton, SIGNAL(clicked()), this, SLOT(addHrtfFile())); connect(ui->hrtfRemoveButton, SIGNAL(clicked()), this, SLOT(removeHrtfFile())); connect(ui->hrtfFileList, SIGNAL(itemSelectionChanged()), this, SLOT(updateHrtfRemoveButton())); @@ -725,6 +738,21 @@ void MainWindow::loadConfig(const QString &fname) ui->enableSSE41CheckBox->setChecked(!disabledCpuExts.contains("sse4.1", Qt::CaseInsensitive)); ui->enableNeonCheckBox->setChecked(!disabledCpuExts.contains("neon", Qt::CaseInsensitive)); + QString hrtfmode = settings.value("hrtf-mode").toString().trimmed(); + ui->hrtfqualitySlider->setValue(3); + ui->hrtfqualityLabel->setText(hrtfModeList[3].name); + /* The "basic" mode name is no longer supported. Use "ambi2" instead. */ + if(hrtfmode == "basic") hrtfmode = "ambi2"; + for(int i = 0;hrtfModeList[i].name[0];i++) + { + if(hrtfmode == hrtfModeList[i].value) + { + ui->hrtfqualitySlider->setValue(i); + ui->hrtfqualityLabel->setText(hrtfModeList[i].name); + break; + } + } + QStringList hrtf_paths = settings.value("hrtf-paths").toStringList(); if(hrtf_paths.size() == 1) hrtf_paths = hrtf_paths[0].split(QChar(',')); @@ -973,6 +1001,8 @@ void MainWindow::saveConfig(const QString &fname) const strlist.append("neon"); settings.setValue("disable-cpu-exts", strlist.join(QChar(','))); + settings.setValue("hrtf-mode", hrtfModeList[ui->hrtfqualitySlider->value()].value); + if(ui->hrtfStateComboBox->currentIndex() == 1) settings.setValue("hrtf", "true"); else if(ui->hrtfStateComboBox->currentIndex() == 2) @@ -1208,6 +1238,13 @@ void MainWindow::updateJackBufferSizeSlider() } +void MainWindow::updateHrtfModeLabel(int num) +{ + ui->hrtfqualityLabel->setText(hrtfModeList[num].name); + enableApplyButton(); +} + + void MainWindow::addHrtfFile() { QString path = QFileDialog::getExistingDirectory(this, tr("Select HRTF Path")); diff --git a/utils/alsoft-config/mainwindow.h b/utils/alsoft-config/mainwindow.h index 8b763845..ca53582b 100644 --- a/utils/alsoft-config/mainwindow.h +++ b/utils/alsoft-config/mainwindow.h @@ -43,6 +43,7 @@ private slots: void updateJackBufferSizeEdit(int size); void updateJackBufferSizeSlider(); + void updateHrtfModeLabel(int num); void addHrtfFile(); void removeHrtfFile(); diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 46d1b7a8..7ab27c09 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -1122,6 +1122,77 @@ application or system to determine if it should be used. The default HRTF to use if the application doesn't request one. + + + + 50 + 90 + 441 + 81 + + + + HRTF Quality + + + + + 20 + 30 + 51 + 21 + + + + Speed + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 340 + 30 + 51 + 21 + + + + Quality + + + + + + 80 + 30 + 251 + 21 + + + + Qt::Horizontal + + + + + + 50 + 50 + 321 + 21 + + + + Default + + + Qt::AlignCenter + + + -- cgit v1.2.3 From fa032368aeb02d88d86f575977f57057796ca51a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Jul 2019 12:27:58 -0700 Subject: Rename HRTF Quality title to HRTF Render Method --- utils/alsoft-config/mainwindow.cpp | 16 ++++++++-------- utils/alsoft-config/mainwindow.ui | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 687f9134..64178922 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -277,7 +277,7 @@ MainWindow::MainWindow(QWidget *parent) : for(count = 0;hrtfModeList[count].name[0];count++) { } - ui->hrtfqualitySlider->setRange(0, count-1); + ui->hrtfmodeSlider->setRange(0, count-1); ui->hrtfStateComboBox->adjustSize(); #if !defined(HAVE_NEON) && !defined(HAVE_SSE) @@ -378,7 +378,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->preferredHrtfComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); connect(ui->hrtfStateComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); - connect(ui->hrtfqualitySlider, SIGNAL(valueChanged(int)), this, SLOT(updateHrtfModeLabel(int))); + connect(ui->hrtfmodeSlider, SIGNAL(valueChanged(int)), this, SLOT(updateHrtfModeLabel(int))); connect(ui->hrtfAddButton, SIGNAL(clicked()), this, SLOT(addHrtfFile())); connect(ui->hrtfRemoveButton, SIGNAL(clicked()), this, SLOT(removeHrtfFile())); @@ -739,16 +739,16 @@ void MainWindow::loadConfig(const QString &fname) ui->enableNeonCheckBox->setChecked(!disabledCpuExts.contains("neon", Qt::CaseInsensitive)); QString hrtfmode = settings.value("hrtf-mode").toString().trimmed(); - ui->hrtfqualitySlider->setValue(3); - ui->hrtfqualityLabel->setText(hrtfModeList[3].name); + ui->hrtfmodeSlider->setValue(3); + ui->hrtfmodeLabel->setText(hrtfModeList[3].name); /* The "basic" mode name is no longer supported. Use "ambi2" instead. */ if(hrtfmode == "basic") hrtfmode = "ambi2"; for(int i = 0;hrtfModeList[i].name[0];i++) { if(hrtfmode == hrtfModeList[i].value) { - ui->hrtfqualitySlider->setValue(i); - ui->hrtfqualityLabel->setText(hrtfModeList[i].name); + ui->hrtfmodeSlider->setValue(i); + ui->hrtfmodeLabel->setText(hrtfModeList[i].name); break; } } @@ -1001,7 +1001,7 @@ void MainWindow::saveConfig(const QString &fname) const strlist.append("neon"); settings.setValue("disable-cpu-exts", strlist.join(QChar(','))); - settings.setValue("hrtf-mode", hrtfModeList[ui->hrtfqualitySlider->value()].value); + settings.setValue("hrtf-mode", hrtfModeList[ui->hrtfmodeSlider->value()].value); if(ui->hrtfStateComboBox->currentIndex() == 1) settings.setValue("hrtf", "true"); @@ -1240,7 +1240,7 @@ void MainWindow::updateJackBufferSizeSlider() void MainWindow::updateHrtfModeLabel(int num) { - ui->hrtfqualityLabel->setText(hrtfModeList[num].name); + ui->hrtfmodeLabel->setText(hrtfModeList[num].name); enableApplyButton(); } diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 7ab27c09..54844226 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -1132,7 +1132,7 @@ application or system to determine if it should be used. - HRTF Quality + HRTF Render Method @@ -1163,7 +1163,7 @@ application or system to determine if it should be used. Quality - + 80 @@ -1176,7 +1176,7 @@ application or system to determine if it should be used. Qt::Horizontal - + 50 -- cgit v1.2.3 From aeb7fe52f1405c3f70489cc5561ef76f469e5fe9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Jul 2019 00:19:48 -0700 Subject: Use unsigned more consistently for source counts --- Alc/alc.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 5d2b2020..c3ec614a 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1705,9 +1705,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->Flags.unset(); } - auto numMono = static_cast(device->NumMonoSources); - auto numStereo = static_cast(device->NumStereoSources); - auto numSends = ALsizei{old_sends}; + ALuint numMono{device->NumMonoSources}; + ALuint numStereo{device->NumStereoSources}; + ALsizei numSends{old_sends}; #define TRACE_ATTR(a, v) TRACE("%s = %d\n", #a, v) while(attrList[attrIdx]) @@ -1747,13 +1747,13 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) case ALC_MONO_SOURCES: numMono = attrList[attrIdx + 1]; TRACE_ATTR(ALC_MONO_SOURCES, numMono); - numMono = maxi(numMono, 0); + if(numMono > INT_MAX) numMono = 0; break; case ALC_STEREO_SOURCES: numStereo = attrList[attrIdx + 1]; TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); - numStereo = maxi(numStereo, 0); + if(numStereo > INT_MAX) numStereo = 0; break; case ALC_MAX_AUXILIARY_SENDS: @@ -1869,14 +1869,14 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(numMono > INT_MAX-numStereo) numMono = INT_MAX-numStereo; numMono += numStereo; - if(auto srcsopt = ConfigValueInt(devname, nullptr, "sources")) + if(auto srcsopt = ConfigValueUInt(devname, nullptr, "sources")) { if(*srcsopt <= 0) numMono = 256; else numMono = *srcsopt; } else - numMono = maxi(numMono, 256); - numStereo = mini(numStereo, numMono); + numMono = maxu(numMono, 256); + numStereo = minu(numStereo, numMono); numMono -= numStereo; device->SourcesMax = numMono + numStereo; @@ -2024,10 +2024,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(GetConfigValueBool(device->DeviceName.c_str(), nullptr, "front-stablizer", 0)) { auto stablizer = al::make_unique(); - /* Initialize band-splitting filters for the front-left and - * front-right channels, with a crossover at 5khz (could be - * higher). - */ + /* Initialize band-splitting filters for the front-left and front- + * right channels, with a crossover at 5khz (could be higher). + */ const ALfloat scale{static_cast(5000.0 / device->Frequency)}; stablizer->LFilter.init(scale); -- cgit v1.2.3 From 47246e5205ee9d033b25dc37b19741e84237c86c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Jul 2019 13:20:21 -0700 Subject: Don't stop the device before going over the attributes --- Alc/alc.cpp | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index c3ec614a..7efa8514 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -1684,26 +1684,13 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) // Check for attributes if(attrList && attrList[0]) { - ALCenum alayout = AL_NONE; - ALCenum ascale = AL_NONE; - ALCenum schans = AL_NONE; - ALCenum stype = AL_NONE; - ALCsizei attrIdx = 0; - ALCsizei aorder = 0; - ALCuint freq = 0; - - const char *devname{nullptr}; - const bool loopback{device->Type == Loopback}; - if(!loopback) - { - devname = device->DeviceName.c_str(); - /* If a context is already running on the device, stop playback so - * the device attributes can be updated. - */ - if(device->Flags.get()) - device->Backend->stop(); - device->Flags.unset(); - } + ALCenum alayout{AL_NONE}; + ALCenum ascale{AL_NONE}; + ALCenum schans{AL_NONE}; + ALCenum stype{AL_NONE}; + ALCsizei attrIdx{0}; + ALCsizei aorder{0}; + ALCuint freq{0u}; ALuint numMono{device->NumMonoSources}; ALuint numStereo{device->NumStereoSources}; @@ -1792,6 +1779,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } #undef TRACE_ATTR + const bool loopback{device->Type == Loopback}; if(loopback) { if(!schans || !stype || !freq) @@ -1817,14 +1805,20 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } } + /* If a context is already running on the device, stop playback so the + * device attributes can be updated. + */ if(device->Flags.get()) device->Backend->stop(); device->Flags.unset(); UpdateClockBase(device); + const char *devname{nullptr}; if(!loopback) { + devname = device->DeviceName.c_str(); + device->BufferSize = DEFAULT_UPDATE_SIZE * DEFAULT_NUM_UPDATES; device->UpdateSize = DEFAULT_UPDATE_SIZE; device->Frequency = DEFAULT_OUTPUT_RATE; -- cgit v1.2.3 From c9f6f9652a4684c6a3dbc7696f7c0c88d9b42e9d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Jul 2019 14:59:26 -0700 Subject: Avoid looking up source IDs multiple times --- OpenAL32/alSource.cpp | 89 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 28 deletions(-) diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 3404cbf2..c3866d1f 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -2746,17 +2746,22 @@ START_API_FUNC SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Playing %d sources", n); if(n == 0) return; + al::vector extra_sources; + std::array source_storage; + ALsource **srchandles{source_storage.data()}; + if(UNLIKELY(static_cast(n) > source_storage.size())) + { + extra_sources.resize(n); + srchandles = extra_sources.data(); + } + std::lock_guard _{context->SourceLock}; - auto sources_end = sources+n; - auto bad_sid = std::find_if_not(sources, sources_end, - [&context](ALuint sid) -> bool - { - ALsource *source{LookupSource(context.get(), sid)}; - return LIKELY(source != nullptr); - } - ); - if(UNLIKELY(bad_sid != sources+n)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", *bad_sid); + for(ALsizei i{0};i < n;i++) + { + srchandles[i] = LookupSource(context.get(), sources[i]); + if(!srchandles[i]) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); + } ALCdevice *device{context->Device}; BackendLockGuard __{*device->Backend}; @@ -2764,10 +2769,9 @@ START_API_FUNC if(UNLIKELY(!device->Connected.load(std::memory_order_acquire))) { /* TODO: Send state change event? */ - std::for_each(sources, sources_end, - [&context](ALuint sid) -> void + std::for_each(srchandles, srchandles+n, + [&context](ALsource *source) -> void { - ALsource *source{LookupSource(context.get(), sid)}; source->OffsetType = AL_NONE; source->Offset = 0.0; source->state = AL_STOPPED; @@ -2811,9 +2815,8 @@ START_API_FUNC context->VoiceCount.fetch_add(need_voices, std::memory_order_relaxed); } - auto start_source = [&context,device](ALuint sid) -> void + auto start_source = [&context,device](ALsource *source) -> void { - ALsource *source{LookupSource(context.get(), sid)}; /* Check that there is a queue containing at least one valid, non zero * length buffer. */ @@ -2985,7 +2988,7 @@ START_API_FUNC SendStateChangeEvent(context.get(), source->id, AL_PLAYING); }; - std::for_each(sources, sources_end, start_source); + std::for_each(srchandles, srchandles+n, start_source); } END_API_FUNC @@ -3005,18 +3008,27 @@ START_API_FUNC SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Pausing %d sources", n); if(n == 0) return; + al::vector extra_sources; + std::array source_storage; + ALsource **srchandles{source_storage.data()}; + if(UNLIKELY(static_cast(n) > source_storage.size())) + { + extra_sources.resize(n); + srchandles = extra_sources.data(); + } + std::lock_guard _{context->SourceLock}; for(ALsizei i{0};i < n;i++) { - if(!LookupSource(context.get(), sources[i])) + srchandles[i] = LookupSource(context.get(), sources[i]); + if(!srchandles[i]) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } ALCdevice *device{context->Device}; BackendLockGuard __{*device->Backend}; - for(ALsizei i{0};i < n;i++) + auto pause_source = [&context](ALsource *source) -> void { - ALsource *source{LookupSource(context.get(), sources[i])}; ALvoice *voice{GetSourceVoice(source, context.get())}; if(voice) { @@ -3030,7 +3042,8 @@ START_API_FUNC source->state = AL_PAUSED; SendStateChangeEvent(context.get(), source->id, AL_PAUSED); } - } + }; + std::for_each(srchandles, srchandles+n, pause_source); } END_API_FUNC @@ -3050,18 +3063,27 @@ START_API_FUNC SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Stopping %d sources", n); if(n == 0) return; + al::vector extra_sources; + std::array source_storage; + ALsource **srchandles{source_storage.data()}; + if(UNLIKELY(static_cast(n) > source_storage.size())) + { + extra_sources.resize(n); + srchandles = extra_sources.data(); + } + std::lock_guard _{context->SourceLock}; for(ALsizei i{0};i < n;i++) { - if(!LookupSource(context.get(), sources[i])) + srchandles[i] = LookupSource(context.get(), sources[i]); + if(!srchandles[i]) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } ALCdevice *device{context->Device}; BackendLockGuard __{*device->Backend}; - for(ALsizei i{0};i < n;i++) + auto stop_source = [&context](ALsource *source) -> void { - ALsource *source{LookupSource(context.get(), sources[i])}; ALvoice *voice{GetSourceVoice(source, context.get())}; if(voice != nullptr) { @@ -3082,7 +3104,8 @@ START_API_FUNC } source->OffsetType = AL_NONE; source->Offset = 0.0; - } + }; + std::for_each(srchandles, srchandles+n, stop_source); } END_API_FUNC @@ -3102,18 +3125,27 @@ START_API_FUNC SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Rewinding %d sources", n); if(n == 0) return; + al::vector extra_sources; + std::array source_storage; + ALsource **srchandles{source_storage.data()}; + if(UNLIKELY(static_cast(n) > source_storage.size())) + { + extra_sources.resize(n); + srchandles = extra_sources.data(); + } + std::lock_guard _{context->SourceLock}; for(ALsizei i{0};i < n;i++) { - if(!LookupSource(context.get(), sources[i])) + srchandles[i] = LookupSource(context.get(), sources[i]); + if(!srchandles[i]) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } ALCdevice *device{context->Device}; BackendLockGuard __{*device->Backend}; - for(ALsizei i{0};i < n;i++) + auto rewind_source = [&context](ALsource *source) -> void { - ALsource *source{LookupSource(context.get(), sources[i])}; ALvoice *voice{GetSourceVoice(source, context.get())}; if(voice != nullptr) { @@ -3133,7 +3165,8 @@ START_API_FUNC } source->OffsetType = AL_NONE; source->Offset = 0.0; - } + }; + std::for_each(srchandles, srchandles+n, rewind_source); } END_API_FUNC -- cgit v1.2.3 From b95bf8d7c1d2d2aa30edc58fdd5c9bbf71fc8200 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Jul 2019 18:39:26 -0700 Subject: Update a comment about the speaker distance --- OpenAL32/Include/alMain.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 2237d3c8..3487d42e 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -394,8 +394,8 @@ struct ALCdevice { /* Rendering mode. */ RenderMode mRenderMode{NormalRender}; - /* The average speaker distance as determined by the ambdec configuration - * (or alternatively, by the NFC-HOA reference delay). Only used for NFC. + /* The average speaker distance as determined by the ambdec configuration, + * HRTF data set, or the NFC-HOA reference delay. Only used for NFC. */ ALfloat AvgSpeakerDist{0.0f}; -- cgit v1.2.3 From c2305548512db20a266528097dd0985e329f119b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Jul 2019 19:09:26 -0700 Subject: Clamp NFC reference distance between 0.1m and 10m --- Alc/panning.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Alc/panning.cpp b/Alc/panning.cpp index d1add5d5..e8f80069 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -258,17 +258,17 @@ constexpr ChannelMap MonoCfg[1] = { }; void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, - const ALuint *RESTRICT chans_per_order) + const al::span chans_per_order) { /* NFC is only used when AvgSpeakerDist is greater than 0. */ const char *devname{device->DeviceName.c_str()}; if(!GetConfigValueBool(devname, "decoder", "nfc", 0) || !(ctrl_dist > 0.0f)) return; - device->AvgSpeakerDist = minf(ctrl_dist, 10.0f); + device->AvgSpeakerDist = clampf(ctrl_dist, 0.1f, 10.0f); TRACE("Using near-field reference distance: %.2f meters\n", device->AvgSpeakerDist); - auto iter = std::copy(chans_per_order, chans_per_order+order+1, + auto iter = std::copy(chans_per_order.begin(), chans_per_order.begin()+order+1, std::begin(device->NumChannelsPerOrder)); std::fill(iter, std::end(device->NumChannelsPerOrder), 0u); } @@ -410,7 +410,6 @@ void InitPanning(ALCdevice *device) if(nfc_delay > 0.0f) { static constexpr ALuint chans_per_order[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; - nfc_delay = clampf(nfc_delay, 0.001f, 1000.0f); InitNearFieldCtrl(device, nfc_delay * SPEEDOFSOUNDMETRESPERSEC, device->mAmbiOrder, chans_per_order); } -- cgit v1.2.3 From 2783b4c04b92d949178e9acd4d3407b2315efe16 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Jul 2019 22:18:52 -0700 Subject: Somewhat simplify alffplay playback timing --- examples/alffplay.cpp | 78 +++++++++++++++++++-------------------------------- 1 file changed, 29 insertions(+), 49 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index f4d50d52..21b3f9c8 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -265,7 +265,6 @@ struct AudioState { std::mutex mSrcMutex; std::condition_variable mSrcCond; std::atomic_flag mConnected; - std::atomic mPrepared{false}; ALuint mSource{0}; std::vector mBuffers; ALsizei mBufferIdx{0}; @@ -295,7 +294,6 @@ struct AudioState { return getClockNoLock(); } - bool isBufferFilled() const { return mPrepared.load(); } void startPlayback(); int getSync(); @@ -350,7 +348,6 @@ struct VideoState { VideoState(MovieState &movie) : mMovie(movie) { } nanoseconds getClock(); - bool isBufferFilled(); static Uint32 SDLCALL sdl_refresh_timer_cb(Uint32 interval, void *opaque); void schedRefresh(milliseconds delay); @@ -368,7 +365,6 @@ struct MovieState { SyncMaster mAVSyncType{SyncMaster::Default}; microseconds mClockBase{0}; - std::atomic mPlaying{false}; std::mutex mSendMtx; std::condition_variable mSendCond; @@ -430,7 +426,7 @@ nanoseconds AudioState::getClockNoLock() // The clock is simply the current device time relative to the recorded // start time. We can also subtract the latency to get more a accurate // position of where the audio device actually is in the output stream. - std::max(device_time - mDeviceStartTime - latency, nanoseconds::zero()); + return device_time - mDeviceStartTime - latency; } /* The source-based clock is based on 4 components: @@ -532,8 +528,7 @@ int AudioState::getSync() return 0; /* Constrain the per-update difference to avoid exceedingly large skips */ - diff = std::min(std::max(diff, -AudioSampleCorrectionMax), - AudioSampleCorrectionMax); + diff = std::min(diff, AudioSampleCorrectionMax); return static_cast(std::chrono::duration_cast(diff*mCodecCtx->sample_rate).count()); } @@ -991,6 +986,13 @@ int AudioState::handler() #endif samples = av_malloc(buffer_len); + { + int64_t devtime{}; + alcGetInteger64vSOFT(alcGetContextsDevice(alcGetCurrentContext()), ALC_DEVICE_CLOCK_SOFT, + 1, &devtime); + mDeviceStartTime = nanoseconds{devtime} - mCurrentPts; + } + while(alGetError() == AL_NO_ERROR && !mMovie.mQuit.load(std::memory_order_relaxed) && mConnected.test_and_set(std::memory_order_relaxed)) { @@ -1000,9 +1002,9 @@ int AudioState::handler() while(processed > 0) { std::array bids; - alSourceUnqueueBuffers(mSource, std::min(bids.size(), processed), - bids.data()); - processed -= std::min(bids.size(), processed); + const ALsizei todq{std::min(bids.size(), processed)}; + alSourceUnqueueBuffers(mSource, todq, bids.data()); + processed -= todq; } /* Refill the buffer queue. */ @@ -1011,19 +1013,23 @@ int AudioState::handler() while(static_cast(queued) < mBuffers.size()) { ALuint bufid = mBuffers[mBufferIdx]; - - uint8_t *ptr = reinterpret_cast(samples + uint8_t *ptr = static_cast(samples); #ifdef AL_SOFT_map_buffer - ? samples : alMapBufferSOFT(bufid, 0, buffer_len, AL_MAP_WRITE_BIT_SOFT) + bool mapped{false}; + if(!ptr) + { + ptr = static_cast(alMapBufferSOFT(bufid, 0, buffer_len, + AL_MAP_WRITE_BIT_SOFT)); + if(!ptr) break; + mapped = true; + } #endif - ); - if(!ptr) break; /* Read the next chunk of data, filling the buffer, and queue it on * the source */ bool got_audio = readAudio(ptr, buffer_len); #ifdef AL_SOFT_map_buffer - if(!samples) alUnmapBufferSOFT(bufid); + if(mapped) alUnmapBufferSOFT(bufid); #endif if(!got_audio) break; @@ -1063,12 +1069,7 @@ int AudioState::handler() /* (re)start the source if needed, and wait for a buffer to finish */ if(state != AL_PLAYING && state != AL_PAUSED) - { - if(mMovie.mPlaying.load(std::memory_order_relaxed)) - startPlayback(); - else - mPrepared.store(true); - } + startPlayback(); mSrcCond.wait_for(srclock, sleep_time); } @@ -1099,12 +1100,6 @@ nanoseconds VideoState::getClock() return mCurrentPts + delta; } -bool VideoState::isBufferFilled() -{ - std::unique_lock lock(mPictQMutex); - return mPictQSize >= mPictQ.size(); -} - Uint32 SDLCALL VideoState::sdl_refresh_timer_cb(Uint32 /*interval*/, void *opaque) { SDL_Event evt{}; @@ -1177,11 +1172,6 @@ void VideoState::refreshTimer(SDL_Window *screen, SDL_Renderer *renderer) schedRefresh(milliseconds(100)); return; } - if(!mMovie.mPlaying.load(std::memory_order_relaxed)) - { - schedRefresh(milliseconds(1)); - return; - } std::unique_lock lock(mPictQMutex); retry: @@ -1498,8 +1488,6 @@ void MovieState::setTitle(SDL_Window *window) nanoseconds MovieState::getClock() { - if(!mPlaying.load(std::memory_order_relaxed)) - return nanoseconds::zero(); return get_avtime() - mClockBase; } @@ -1569,6 +1557,11 @@ int MovieState::parse_handler() /* Dump information about file onto standard error */ av_dump_format(mFormatCtx.get(), 0, mFilename.c_str(), 0); + /* Set the base time 500ms ahead of the current av time. */ + mClockBase = get_avtime() + milliseconds{500}; + mVideo.mCurrentPtsTime = mClockBase; + mVideo.mFrameTimer = mVideo.mCurrentPtsTime; + /* Find the first video and audio streams */ for(unsigned int i = 0;i < mFormatCtx->nb_streams;i++) { @@ -1635,23 +1628,10 @@ int MovieState::parse_handler() if(queue_size == 0 || (queue_size < MAX_QUEUE_SIZE && !input_finished)) break; - if(!mPlaying.load(std::memory_order_relaxed)) - { - if((!mAudio.mCodecCtx || mAudio.isBufferFilled()) && - (!mVideo.mCodecCtx || mVideo.isBufferFilled())) - { - /* Set the base time 50ms ahead of the current av time. */ - mClockBase = get_avtime() + milliseconds(50); - mVideo.mCurrentPtsTime = mClockBase; - mVideo.mFrameTimer = mVideo.mCurrentPtsTime; - mAudio.startPlayback(); - mPlaying.store(std::memory_order_release); - } - } /* Nothing to send or get for now, wait a bit and try again. */ { std::unique_lock lock(mSendMtx); if(mSendDataGood.test_and_set(std::memory_order_relaxed)) - mSendCond.wait_for(lock, milliseconds(10)); + mSendCond.wait_for(lock, milliseconds{10}); } } while(!mQuit.load(std::memory_order_relaxed)); } -- cgit v1.2.3 From 3ffb6867a3bac856bacebf25dfbcf48b4482d50f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 8 Jul 2019 13:18:10 -0700 Subject: Rework packet handling in alffplay Turns out avcodec_send_packet is what can invoke the decode for serialized codecs, so don't call that in the parse handler thread. The packet queue is used to get the compressed data from the parse handler to the audio/video threads. Additionally, don't serialize the video frame preparation with the decode thread. --- examples/alffplay.cpp | 398 +++++++++++++++++++++----------------------------- 1 file changed, 170 insertions(+), 228 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 21b3f9c8..f6bf6863 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -119,7 +119,7 @@ LPALEVENTCALLBACKSOFT alEventCallbackSOFT; const seconds AVNoSyncThreshold{10}; -const milliseconds VideoSyncThreshold(10); +const milliseconds VideoSyncThreshold{10}; #define VIDEO_PICTURE_QUEUE_SIZE 16 const seconds_d64 AudioSyncThreshold{0.03}; @@ -132,8 +132,6 @@ const milliseconds AudioBufferTime{20}; /* Buffer total size, in time (should be divisible by the buffer time) */ const milliseconds AudioBufferTotalTime{800}; -#define MAX_QUEUE_SIZE (15 * 1024 * 1024) /* Bytes of compressed data to keep queued */ - enum { FF_UPDATE_EVENT = SDL_USEREVENT, FF_REFRESH_EVENT, @@ -184,27 +182,58 @@ struct SwsContextDeleter { using SwsContextPtr = std::unique_ptr; +template class PacketQueue { + std::mutex mMutex; + std::condition_variable mCondVar; std::deque mPackets; size_t mTotalSize{0}; + bool mFinished{false}; public: - ~PacketQueue() { clear(); } + ~PacketQueue() + { + for(AVPacket &pkt : mPackets) + av_packet_unref(&pkt); + mPackets.clear(); + mTotalSize = 0; + } - bool empty() const noexcept { return mPackets.empty(); } - size_t totalSize() const noexcept { return mTotalSize; } + void setFinished() + { + { + std::lock_guard _{mMutex}; + mFinished = true; + } + mCondVar.notify_one(); + } - void put(const AVPacket *pkt) + AVPacket *getPacket(std::unique_lock &lock) { - mPackets.push_back(AVPacket{}); - if(av_packet_ref(&mPackets.back(), pkt) != 0) - mPackets.pop_back(); - else - mTotalSize += mPackets.back().size; + while(mPackets.empty() && !mFinished) + mCondVar.wait(lock); + return mPackets.empty() ? nullptr : &mPackets.front(); } - AVPacket *front() noexcept - { return &mPackets.front(); } + bool put(const AVPacket *pkt) + { + { + std::unique_lock lock{mMutex}; + if(mTotalSize >= SizeLimit) + return false; + + mPackets.push_back(AVPacket{}); + if(av_packet_ref(&mPackets.back(), pkt) != 0) + { + mPackets.pop_back(); + return true; + } + + mTotalSize += mPackets.back().size; + } + mCondVar.notify_one(); + return true; + } void pop() { @@ -214,13 +243,7 @@ public: mPackets.pop_front(); } - void clear() - { - for(AVPacket &pkt : mPackets) - av_packet_unref(&pkt); - mPackets.clear(); - mTotalSize = 0; - } + std::mutex &getMutex() noexcept { return mMutex; } }; @@ -232,8 +255,7 @@ struct AudioState { AVStream *mStream{nullptr}; AVCodecCtxPtr mCodecCtx; - std::mutex mQueueMtx; - std::condition_variable mQueueCond; + PacketQueue<2*1024*1024> mPackets; /* Used for clock difference average computation */ seconds_d64 mClockDiffAvg{0}; @@ -309,8 +331,7 @@ struct VideoState { AVStream *mStream{nullptr}; AVCodecCtxPtr mCodecCtx; - std::mutex mQueueMtx; - std::condition_variable mQueueCond; + PacketQueue<14*1024*1024> mPackets; nanoseconds mClock{0}; nanoseconds mFrameTimer{0}; @@ -320,14 +341,13 @@ struct VideoState { /* time (av_gettime) at which we updated mCurrentPts - used to have running video pts */ microseconds mCurrentPtsTime{0}; - /* Decompressed video frame, and swscale context for conversion */ - AVFramePtr mDecodedFrame; + /* Swscale context for format conversion */ SwsContextPtr mSwscaleCtx; struct Picture { SDL_Texture *mImage{nullptr}; int mWidth{0}, mHeight{0}; /* Logical image size (actual size may be larger) */ - std::atomic mUpdated{false}; + AVFramePtr mFrame{av_frame_alloc()}; nanoseconds mPts{0}; ~Picture() @@ -339,6 +359,7 @@ struct VideoState { }; std::array mPictQ; size_t mPictQSize{0}, mPictQRead{0}, mPictQWrite{0}; + size_t mPictQPrepSize{0}, mPictQPrep{0}; std::mutex mPictQMutex; std::condition_variable mPictQCond; bool mFirstUpdate{true}; @@ -354,7 +375,7 @@ struct VideoState { void display(SDL_Window *screen, SDL_Renderer *renderer); void refreshTimer(SDL_Window *screen, SDL_Renderer *renderer); void updatePicture(SDL_Window *screen, SDL_Renderer *renderer); - int queuePicture(nanoseconds pts); + bool queuePicture(nanoseconds pts, AVFrame *frame); int handler(); }; @@ -366,11 +387,6 @@ struct MovieState { microseconds mClockBase{0}; - std::mutex mSendMtx; - std::condition_variable mSendCond; - /* NOTE: false/clear = need data, true/set = no data needed */ - std::atomic_flag mSendDataGood; - std::atomic mQuit{false}; AudioState mAudio; @@ -536,22 +552,20 @@ int AudioState::decodeFrame() { while(!mMovie.mQuit.load(std::memory_order_relaxed)) { - std::unique_lock lock(mQueueMtx); - int ret = avcodec_receive_frame(mCodecCtx.get(), mDecodedFrame.get()); - if(ret == AVERROR(EAGAIN)) { - mMovie.mSendDataGood.clear(std::memory_order_relaxed); - std::unique_lock(mMovie.mSendMtx).unlock(); - mMovie.mSendCond.notify_one(); - do { - mQueueCond.wait(lock); - ret = avcodec_receive_frame(mCodecCtx.get(), mDecodedFrame.get()); - } while(ret == AVERROR(EAGAIN)); + std::unique_lock lock{mPackets.getMutex()}; + AVPacket *lastpkt{}; + while((lastpkt=mPackets.getPacket(lock)) != nullptr) + { + int ret{avcodec_send_packet(mCodecCtx.get(), lastpkt)}; + if(ret == AVERROR(EAGAIN)) break; + mPackets.pop(); + } + if(!lastpkt) + avcodec_send_packet(mCodecCtx.get(), nullptr); } - lock.unlock(); + int ret{avcodec_receive_frame(mCodecCtx.get(), mDecodedFrame.get())}; if(ret == AVERROR_EOF) break; - mMovie.mSendDataGood.clear(std::memory_order_relaxed); - mMovie.mSendCond.notify_one(); if(ret < 0) { std::cerr<< "Failed to decode frame: "<best_effort_timestamp != AV_NOPTS_VALUE) mCurrentPts = std::chrono::duration_cast( - seconds_d64(av_q2d(mStream->time_base)*mDecodedFrame->best_effort_timestamp) + seconds_d64{av_q2d(mStream->time_base)*mDecodedFrame->best_effort_timestamp} ); if(mDecodedFrame->nb_samples > mSamplesMax) @@ -639,7 +653,7 @@ bool AudioState::readAudio(uint8_t *samples, int length) // Adjust the device start time and current pts by the amount we're // skipping/duplicating, so that the clock remains correct for the // current stream position. - auto skip = nanoseconds(seconds(mSamplesPos)) / mCodecCtx->sample_rate; + auto skip = nanoseconds{seconds{mSamplesPos}} / mCodecCtx->sample_rate; mDeviceStartTime -= skip; mCurrentPts += skip; continue; @@ -692,7 +706,7 @@ void AL_APIENTRY AudioState::EventCallback(ALenum eventType, ALuint object, ALui ALsizei length, const ALchar *message, void *userParam) { - AudioState *self = reinterpret_cast(userParam); + AudioState *self = static_cast(userParam); if(eventType == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT) { @@ -719,7 +733,7 @@ void AL_APIENTRY AudioState::EventCallback(ALenum eventType, ALuint object, ALui std::cout<< "\n" "Object ID: "<(length)}<<"\n----"<< std::endl; if(eventType == AL_EVENT_TYPE_DISCONNECTED_SOFT) @@ -727,7 +741,6 @@ void AL_APIENTRY AudioState::EventCallback(ALenum eventType, ALuint object, ALui { std::lock_guard lock(self->mSrcMutex); self->mConnected.clear(std::memory_order_release); } - std::unique_lock(self->mSrcMutex).unlock(); self->mSrcCond.notify_one(); } } @@ -903,7 +916,7 @@ int AudioState::handler() mFormat = AL_FORMAT_STEREO16; } } - void *samples = nullptr; + void *samples{nullptr}; ALsizei buffer_len = std::chrono::duration_cast>( mCodecCtx->sample_rate * AudioBufferTime).count() * mFrameSize; @@ -1012,29 +1025,26 @@ int AudioState::handler() alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); while(static_cast(queued) < mBuffers.size()) { - ALuint bufid = mBuffers[mBufferIdx]; - uint8_t *ptr = static_cast(samples); + const ALuint bufid{mBuffers[mBufferIdx]}; + /* Read the next chunk of data, filling the buffer, and queue it on + * the source. + */ #ifdef AL_SOFT_map_buffer - bool mapped{false}; - if(!ptr) + if(!samples) { - ptr = static_cast(alMapBufferSOFT(bufid, 0, buffer_len, + auto ptr = static_cast(alMapBufferSOFT(bufid, 0, buffer_len, AL_MAP_WRITE_BIT_SOFT)); - if(!ptr) break; - mapped = true; + bool got_audio{readAudio(ptr, buffer_len)}; + alUnmapBufferSOFT(bufid); + if(!got_audio) break; } + else #endif - - /* Read the next chunk of data, filling the buffer, and queue it on - * the source */ - bool got_audio = readAudio(ptr, buffer_len); -#ifdef AL_SOFT_map_buffer - if(mapped) alUnmapBufferSOFT(bufid); -#endif - if(!got_audio) break; - - if(samples) + { + if(!readAudio(static_cast(samples), buffer_len)) + break; alBufferData(bufid, mFormat, samples, buffer_len, mCodecCtx->sample_rate); + } alSourceQueueBuffers(mSource, 1, &bufid); mBufferIdx = (mBufferIdx+1) % mBuffers.size(); @@ -1169,18 +1179,18 @@ void VideoState::refreshTimer(SDL_Window *screen, SDL_Renderer *renderer) mPictQCond.notify_all(); return; } - schedRefresh(milliseconds(100)); + schedRefresh(milliseconds{100}); return; } - std::unique_lock lock(mPictQMutex); + std::unique_lock lock{mPictQMutex}; retry: - if(mPictQSize == 0) + if(mPictQPrepSize == 0 || mMovie.mQuit.load(std::memory_order_relaxed)) { if(mEOS) mFinalUpdate = true; else - schedRefresh(milliseconds(1)); + schedRefresh(milliseconds{10}); lock.unlock(); mPictQCond.notify_all(); return; @@ -1192,7 +1202,7 @@ retry: /* Get delay using the frame pts and the pts from last frame. */ auto delay = vp->mPts - mFrameLastPts; - if(delay <= seconds::zero() || delay >= seconds(1)) + if(delay <= seconds::zero() || delay >= seconds{1}) { /* If incorrect delay, use previous one. */ delay = mFrameLastDelay; @@ -1200,6 +1210,7 @@ retry: /* Save for next frame. */ mFrameLastDelay = delay; mFrameLastPts = vp->mPts; + lock.unlock(); /* Update delay to sync to clock if not master source. */ if(mMovie.mAVSyncType != SyncMaster::Video) @@ -1224,8 +1235,10 @@ retry: if(!(actual_delay >= VideoSyncThreshold)) { /* We don't have time to handle this picture, just skip to the next one. */ + lock.lock(); mPictQRead = (mPictQRead+1)%mPictQ.size(); - mPictQSize--; + --mPictQSize; --mPictQPrepSize; + mPictQCond.notify_all(); goto retry; } schedRefresh(std::chrono::duration_cast(actual_delay)); @@ -1234,8 +1247,9 @@ retry: display(screen, renderer); /* Update queue for next picture. */ + lock.lock(); mPictQRead = (mPictQRead+1)%mPictQ.size(); - mPictQSize--; + --mPictQSize; --mPictQPrepSize; lock.unlock(); mPictQCond.notify_all(); } @@ -1245,7 +1259,10 @@ retry: */ void VideoState::updatePicture(SDL_Window *screen, SDL_Renderer *renderer) { - Picture *vp = &mPictQ[mPictQWrite]; + if(mMovie.mQuit.load(std::memory_order_relaxed)) + return; + + Picture *vp = &mPictQ[mPictQPrep]; bool fmt_updated = false; /* allocate or resize the buffer! */ @@ -1282,11 +1299,11 @@ void VideoState::updatePicture(SDL_Window *screen, SDL_Renderer *renderer) } } + AVFrame *frame{vp->mFrame.get()}; if(vp->mImage) { - AVFrame *frame = mDecodedFrame.get(); - void *pixels = nullptr; - int pitch = 0; + void *pixels{nullptr}; + int pitch{0}; if(mCodecCtx->pix_fmt == AV_PIX_FMT_YUV420P) SDL_UpdateYUVTexture(vp->mImage, nullptr, @@ -1299,10 +1316,10 @@ void VideoState::updatePicture(SDL_Window *screen, SDL_Renderer *renderer) else { // Convert the image into YUV format that SDL uses - int coded_w = mCodecCtx->coded_width; - int coded_h = mCodecCtx->coded_height; - int w = mCodecCtx->width; - int h = mCodecCtx->height; + int coded_w{mCodecCtx->coded_width}; + int coded_h{mCodecCtx->coded_height}; + int w{mCodecCtx->width}; + int h{mCodecCtx->height}; if(!mSwscaleCtx || fmt_updated) { mSwscaleCtx.reset(sws_getContext( @@ -1323,78 +1340,64 @@ void VideoState::updatePicture(SDL_Window *screen, SDL_Renderer *renderer) pict_linesize[1] = pitch / 2; pict_linesize[2] = pitch / 2; - sws_scale(mSwscaleCtx.get(), reinterpret_cast(frame->data), - frame->linesize, 0, h, pict_data, pict_linesize); + sws_scale(mSwscaleCtx.get(), reinterpret_cast(frame->data), frame->linesize, + 0, h, pict_data, pict_linesize); SDL_UnlockTexture(vp->mImage); } } + av_frame_unref(frame); - vp->mUpdated.store(true, std::memory_order_release); - std::unique_lock(mPictQMutex).unlock(); - mPictQCond.notify_one(); + mPictQPrep = (mPictQPrep+1)%mPictQ.size(); + ++mPictQPrepSize; } -int VideoState::queuePicture(nanoseconds pts) +bool VideoState::queuePicture(nanoseconds pts, AVFrame *frame) { /* Wait until we have space for a new pic */ - std::unique_lock lock(mPictQMutex); + std::unique_lock lock{mPictQMutex}; while(mPictQSize >= mPictQ.size() && !mMovie.mQuit.load(std::memory_order_relaxed)) mPictQCond.wait(lock); - lock.unlock(); if(mMovie.mQuit.load(std::memory_order_relaxed)) - return -1; + return false; - Picture *vp = &mPictQ[mPictQWrite]; + Picture *vp{&mPictQ[mPictQWrite]}; + av_frame_move_ref(vp->mFrame.get(), frame); + vp->mPts = pts; + + mPictQWrite = (mPictQWrite+1)%mPictQ.size(); + ++mPictQSize; + lock.unlock(); /* We have to create/update the picture in the main thread */ - vp->mUpdated.store(false, std::memory_order_relaxed); SDL_Event evt{}; evt.user.type = FF_UPDATE_EVENT; evt.user.data1 = this; SDL_PushEvent(&evt); - /* Wait until the picture is updated. */ - lock.lock(); - while(!vp->mUpdated.load(std::memory_order_relaxed)) - { - if(mMovie.mQuit.load(std::memory_order_relaxed)) - return -1; - mPictQCond.wait(lock); - } - if(mMovie.mQuit.load(std::memory_order_relaxed)) - return -1; - vp->mPts = pts; - - mPictQWrite = (mPictQWrite+1)%mPictQ.size(); - mPictQSize++; - lock.unlock(); - - return 0; + return true; } int VideoState::handler() { - mDecodedFrame.reset(av_frame_alloc()); + AVFramePtr decoded_frame{av_frame_alloc()}; while(!mMovie.mQuit.load(std::memory_order_relaxed)) { - std::unique_lock lock(mQueueMtx); - /* Decode video frame */ - int ret = avcodec_receive_frame(mCodecCtx.get(), mDecodedFrame.get()); - if(ret == AVERROR(EAGAIN)) { - mMovie.mSendDataGood.clear(std::memory_order_relaxed); - std::unique_lock(mMovie.mSendMtx).unlock(); - mMovie.mSendCond.notify_one(); - do { - mQueueCond.wait(lock); - ret = avcodec_receive_frame(mCodecCtx.get(), mDecodedFrame.get()); - } while(ret == AVERROR(EAGAIN)); + std::unique_lock lock{mPackets.getMutex()}; + AVPacket *lastpkt{}; + while((lastpkt=mPackets.getPacket(lock)) != nullptr) + { + int ret{avcodec_send_packet(mCodecCtx.get(), lastpkt)}; + if(ret == AVERROR(EAGAIN)) break; + mPackets.pop(); + } + if(!lastpkt) + avcodec_send_packet(mCodecCtx.get(), nullptr); } - lock.unlock(); + /* Decode video frame */ + int ret = avcodec_receive_frame(mCodecCtx.get(), decoded_frame.get()); if(ret == AVERROR_EOF) break; - mMovie.mSendDataGood.clear(std::memory_order_relaxed); - mMovie.mSendCond.notify_one(); if(ret < 0) { std::cerr<< "Failed to decode frame: "<best_effort_timestamp != AV_NOPTS_VALUE) + if(decoded_frame->best_effort_timestamp != AV_NOPTS_VALUE) mClock = std::chrono::duration_cast( - seconds_d64(av_q2d(mStream->time_base)*mDecodedFrame->best_effort_timestamp) - ); - pts = mClock; + seconds_d64{av_q2d(mStream->time_base)*decoded_frame->best_effort_timestamp}); + nanoseconds pts{mClock}; /* Update the video clock to the next expected PTS. */ auto frame_delay = av_q2d(mCodecCtx->time_base); - frame_delay += mDecodedFrame->repeat_pict * (frame_delay * 0.5); - mClock += std::chrono::duration_cast(seconds_d64(frame_delay)); + frame_delay += decoded_frame->repeat_pict * (frame_delay * 0.5); + mClock += std::chrono::duration_cast(seconds_d64{frame_delay}); - if(queuePicture(pts) < 0) + if(!queuePicture(pts, decoded_frame.get())) break; - av_frame_unref(mDecodedFrame.get()); } mEOS = true; std::unique_lock lock(mPictQMutex); - if(mMovie.mQuit.load(std::memory_order_relaxed)) - { - mPictQRead = 0; - mPictQWrite = 0; - mPictQSize = 0; - } while(!mFinalUpdate) mPictQCond.wait(lock); @@ -1436,7 +1430,7 @@ int VideoState::handler() int MovieState::decode_interrupt_cb(void *ctx) { - return reinterpret_cast(ctx)->mQuit.load(std::memory_order_relaxed); + return static_cast(ctx)->mQuit.load(std::memory_order_relaxed); } bool MovieState::prepare() @@ -1531,15 +1525,11 @@ int MovieState::streamComponentOpen(int stream_index) case AVMEDIA_TYPE_AUDIO: mAudio.mStream = mFormatCtx->streams[stream_index]; mAudio.mCodecCtx = std::move(avctx); - - mAudioThread = std::thread(std::mem_fn(&AudioState::handler), &mAudio); break; case AVMEDIA_TYPE_VIDEO: mVideo.mStream = mFormatCtx->streams[stream_index]; mVideo.mCodecCtx = std::move(avctx); - - mVideoThread = std::thread(std::mem_fn(&VideoState::handler), &mVideo); break; default: @@ -1551,17 +1541,15 @@ int MovieState::streamComponentOpen(int stream_index) int MovieState::parse_handler() { - int video_index = -1; - int audio_index = -1; + auto &audio_queue = mAudio.mPackets; + auto &video_queue = mVideo.mPackets; + + int video_index{-1}; + int audio_index{-1}; /* Dump information about file onto standard error */ av_dump_format(mFormatCtx.get(), 0, mFilename.c_str(), 0); - /* Set the base time 500ms ahead of the current av time. */ - mClockBase = get_avtime() + milliseconds{500}; - mVideo.mCurrentPtsTime = mClockBase; - mVideo.mFrameTimer = mVideo.mCurrentPtsTime; - /* Find the first video and audio streams */ for(unsigned int i = 0;i < mFormatCtx->nb_streams;i++) { @@ -1578,82 +1566,40 @@ int MovieState::parse_handler() mQuit = true; } - PacketQueue audio_queue, video_queue; - bool input_finished = false; + /* Set the base time 500ms ahead of the current av time. */ + mClockBase = get_avtime() + milliseconds{500}; + mVideo.mCurrentPtsTime = mClockBase; + mVideo.mFrameTimer = mVideo.mCurrentPtsTime; + + if(audio_index >= 0) + mAudioThread = std::thread{std::mem_fn(&AudioState::handler), &mAudio}; + if(video_index >= 0) + mVideoThread = std::thread{std::mem_fn(&VideoState::handler), &mVideo}; /* Main packet reading/dispatching loop */ - while(!mQuit.load(std::memory_order_relaxed) && !input_finished) + while(!mQuit.load(std::memory_order_relaxed)) { AVPacket packet; if(av_read_frame(mFormatCtx.get(), &packet) < 0) - input_finished = true; - else - { - /* Copy the packet into the queue it's meant for. */ - if(packet.stream_index == video_index) - video_queue.put(&packet); - else if(packet.stream_index == audio_index) - audio_queue.put(&packet); - av_packet_unref(&packet); - } - - do { - /* Send whatever queued packets we have. */ - if(!audio_queue.empty()) - { - std::unique_lock lock(mAudio.mQueueMtx); - int ret; - do { - ret = avcodec_send_packet(mAudio.mCodecCtx.get(), audio_queue.front()); - if(ret != AVERROR(EAGAIN)) audio_queue.pop(); - } while(ret != AVERROR(EAGAIN) && !audio_queue.empty()); - lock.unlock(); - mAudio.mQueueCond.notify_one(); - } - if(!video_queue.empty()) - { - std::unique_lock lock(mVideo.mQueueMtx); - int ret; - do { - ret = avcodec_send_packet(mVideo.mCodecCtx.get(), video_queue.front()); - if(ret != AVERROR(EAGAIN)) video_queue.pop(); - } while(ret != AVERROR(EAGAIN) && !video_queue.empty()); - lock.unlock(); - mVideo.mQueueCond.notify_one(); - } - /* If the queues are completely empty, or it's not full and there's - * more input to read, go get more. - */ - size_t queue_size = audio_queue.totalSize() + video_queue.totalSize(); - if(queue_size == 0 || (queue_size < MAX_QUEUE_SIZE && !input_finished)) - break; + break; - /* Nothing to send or get for now, wait a bit and try again. */ - { std::unique_lock lock(mSendMtx); - if(mSendDataGood.test_and_set(std::memory_order_relaxed)) - mSendCond.wait_for(lock, milliseconds{10}); - } - } while(!mQuit.load(std::memory_order_relaxed)); - } - /* Pass a null packet to finish the send buffers (the receive functions - * will get AVERROR_EOF when emptied). - */ - if(mVideo.mCodecCtx) - { - { std::lock_guard lock(mVideo.mQueueMtx); - avcodec_send_packet(mVideo.mCodecCtx.get(), nullptr); + /* Copy the packet into the queue it's meant for. */ + if(packet.stream_index == video_index) + { + while(!mQuit.load(std::memory_order_acquire) && !video_queue.put(&packet)) + std::this_thread::sleep_for(milliseconds{50}); } - mVideo.mQueueCond.notify_one(); - } - if(mAudio.mCodecCtx) - { - { std::lock_guard lock(mAudio.mQueueMtx); - avcodec_send_packet(mAudio.mCodecCtx.get(), nullptr); + else if(packet.stream_index == audio_index) + { + while(!mQuit.load(std::memory_order_acquire) && !audio_queue.put(&packet)) + std::this_thread::sleep_for(milliseconds{50}); } - mAudio.mQueueCond.notify_one(); + + av_packet_unref(&packet); } - video_queue.clear(); - audio_queue.clear(); + /* Finish the queues so the receivers know nothing more is coming. */ + if(mVideo.mCodecCtx) video_queue.setFinished(); + if(mAudio.mCodecCtx) audio_queue.setFinished(); /* all done - wait for it */ if(mVideoThread.joinable()) @@ -1916,15 +1862,11 @@ int main(int argc, char *argv[]) break; case FF_UPDATE_EVENT: - reinterpret_cast(event.user.data1)->updatePicture( - screen, renderer - ); + static_cast(event.user.data1)->updatePicture(screen, renderer); break; case FF_REFRESH_EVENT: - reinterpret_cast(event.user.data1)->refreshTimer( - screen, renderer - ); + static_cast(event.user.data1)->refreshTimer(screen, renderer); break; case FF_MOVIE_DONE_EVENT: -- cgit v1.2.3 From 4a33bbb14d6b5f7673fe0371004236bac8f5bb2a Mon Sep 17 00:00:00 2001 From: Lopuska Date: Wed, 10 Jul 2019 07:14:31 +0200 Subject: vocal morpher implementation (#312) * vocal morpher implementation * compile fix for GCC --- Alc/alc.cpp | 2 - Alc/effects/base.h | 10 + Alc/effects/vmorpher.cpp | 490 ++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 1 + OpenAL32/Include/alEffect.h | 3 +- OpenAL32/alEffect.cpp | 4 +- 6 files changed, 506 insertions(+), 4 deletions(-) create mode 100644 Alc/effects/vmorpher.cpp diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 7efa8514..3e176957 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -617,9 +617,7 @@ constexpr struct { DECL(AL_EFFECT_FLANGER), DECL(AL_EFFECT_PITCH_SHIFTER), DECL(AL_EFFECT_FREQUENCY_SHIFTER), -#if 0 DECL(AL_EFFECT_VOCAL_MORPHER), -#endif DECL(AL_EFFECT_RING_MODULATOR), DECL(AL_EFFECT_AUTOWAH), DECL(AL_EFFECT_COMPRESSOR), diff --git a/Alc/effects/base.h b/Alc/effects/base.h index c2848f37..2b067f11 100644 --- a/Alc/effects/base.h +++ b/Alc/effects/base.h @@ -109,6 +109,15 @@ union EffectProps { ALint FineTune; } Pshifter; + struct { + ALfloat Rate; + ALint PhonemeA; + ALint PhonemeB; + ALint PhonemeACoarseTuning; + ALint PhonemeBCoarseTuning; + ALint Waveform; + } Vmorpher; + struct { ALfloat Gain; } Dedicated; @@ -180,6 +189,7 @@ EffectStateFactory *FlangerStateFactory_getFactory(void); EffectStateFactory *FshifterStateFactory_getFactory(void); EffectStateFactory *ModulatorStateFactory_getFactory(void); EffectStateFactory *PshifterStateFactory_getFactory(void); +EffectStateFactory* VmorpherStateFactory_getFactory(void); EffectStateFactory *DedicatedStateFactory_getFactory(void); diff --git a/Alc/effects/vmorpher.cpp b/Alc/effects/vmorpher.cpp new file mode 100644 index 00000000..c656a14e --- /dev/null +++ b/Alc/effects/vmorpher.cpp @@ -0,0 +1,490 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2019 by Anis A. Hireche + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include +#include + +#include "alMain.h" +#include "alcontext.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" +#include "vecmat.h" + + +namespace { + +#define MAX_UPDATE_SAMPLES 128 +#define Q_FACTOR 5.0f +#define NUM_FORMANTS 4 + +#define WAVEFORM_FRACBITS 24 +#define WAVEFORM_FRACONE (1<(index) * + (al::MathDefs::Tau() / ALfloat{WAVEFORM_FRACONE})))*0.5f+0.5f; +} + +inline ALfloat Saw(ALsizei index) +{ + return (static_cast(index)*(2.0f/WAVEFORM_FRACONE) - 1.0f)*0.5f+0.5f; +} + +inline ALfloat Triangle(ALsizei index) +{ + return (std::fabs(static_cast(index) * (al::MathDefs::Tau() / WAVEFORM_FRACONE) - + al::MathDefs::Pi()) / al::MathDefs::Pi())*0.5f+0.5f; +} + +inline ALfloat Half(ALsizei UNUSED(index)) +{ + return 0.5f; +} + +template +void Oscillate(ALfloat *RESTRICT dst, ALsizei index, const ALsizei step, ALsizei todo) +{ + for(ALsizei i{0};i < todo;i++) + { + index += step; + index &= WAVEFORM_FRACMASK; + dst[i] = func(index); + } +} + +struct FormantFilter +{ + inline void process(const ALfloat* samplesIn, ALfloat* samplesOut, const ALsizei numInput) + { + const float g = std::tan(al::MathDefs::Pi() * f0norm); + const float h = 1.0f / (1 + (g / Q_FACTOR) + (g * g)); + + for (ALsizei i{0};i < numInput;i++) + { + const float H = h * (samplesIn[i] - (1.0f / Q_FACTOR + g) * s1 - s2); + const float B = g * H + s1; + const float L = g * B + s2; + + s1 = g * H + B; + s2 = g * B + L; + + // Apply peak and accumulate samples. + samplesOut[i] += B * fGain; + } + } + + inline void clear() + { + s1 = 0.0f; + s2 = 0.0f; + } + + float f0norm; + float fGain; + float s1; + float s2; +}; + +struct VmorpherState final : public EffectState { + struct { + /* Effect parameters */ + FormantFilter FormantsA[NUM_FORMANTS]; + FormantFilter FormantsB[NUM_FORMANTS]; + + /* Effect gains for each channel */ + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]{}; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]{}; + } mChans[MAX_AMBI_CHANNELS]; + + void (*mGetSamples)(ALfloat* RESTRICT, ALsizei, const ALsizei, ALsizei) {}; + + ALsizei mIndex{0}; + ALsizei mStep{1}; + + ALfloat mSampleBufferA[MAX_UPDATE_SAMPLES]{}; + ALfloat mSampleBufferB[MAX_UPDATE_SAMPLES]{}; + + ALboolean deviceUpdate(const ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + + DEF_NEWDEL(VmorpherState) +}; + +ALboolean VmorpherState::deviceUpdate(const ALCdevice *UNUSED(device)) +{ + for(auto &e : mChans) + { + std::for_each(std::begin(e.FormantsA), std::end(e.FormantsA), + std::mem_fn(&FormantFilter::clear)); + std::for_each(std::begin(e.FormantsB), std::end(e.FormantsB), + std::mem_fn(&FormantFilter::clear)); + std::fill(std::begin(e.CurrentGains), std::end(e.CurrentGains), 0.0f); + } + return AL_TRUE; +} + +void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) +{ + const ALCdevice *device = context->Device; + const ALfloat frequency = static_cast(device->Frequency); + + const float step{props->Vmorpher.Rate / static_cast(device->Frequency)}; + mStep = fastf2i(clampf(step*WAVEFORM_FRACONE, 0.0f, ALfloat{WAVEFORM_FRACONE-1})); + + if(mStep == 0) + mGetSamples = Oscillate; + else if(props->Vmorpher.Waveform == AL_VOCAL_MORPHER_WAVEFORM_SINUSOID) + mGetSamples = Oscillate; + else if(props->Vmorpher.Waveform == AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH) + mGetSamples = Oscillate; + else /*if(props->Vmorpher.Waveform == AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE)*/ + mGetSamples = Oscillate; + + /* Using soprano formant set of values to better match mid-range frequency space. + * See: https://www.classes.cs.uchicago.edu/archive/1999/spring/CS295/Computing_Resources/Csound/CsManual3.48b1.HTML/Appendices/table3.html + */ + switch(props->Vmorpher.PhonemeA) + { + case AL_VOCAL_MORPHER_PHONEME_A: + mChans[0].FormantsA[0].f0norm = 800 / frequency; + mChans[0].FormantsA[1].f0norm = 1150 / frequency; + mChans[0].FormantsA[2].f0norm = 2900 / frequency; + mChans[0].FormantsA[3].f0norm = 3900 / frequency; + + mChans[0].FormantsA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ + mChans[0].FormantsA[1].fGain = 0.501187f; /* std::pow(10.0f, -6 / 20.0f); */ + mChans[0].FormantsA[2].fGain = 0.025118f; /* std::pow(10.0f, -32 / 20.0f); */ + mChans[0].FormantsA[3].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ + break; + case AL_VOCAL_MORPHER_PHONEME_E: + mChans[0].FormantsA[0].f0norm = 350 / frequency; + mChans[0].FormantsA[1].f0norm = 2000 / frequency; + mChans[0].FormantsA[2].f0norm = 2800 / frequency; + mChans[0].FormantsA[3].f0norm = 3600 / frequency; + + mChans[0].FormantsA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ + mChans[0].FormantsA[1].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ + mChans[0].FormantsA[2].fGain = 0.177827f; /* std::pow(10.0f, -15 / 20.0f); */ + mChans[0].FormantsA[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ + break; + case AL_VOCAL_MORPHER_PHONEME_I: + mChans[0].FormantsA[0].f0norm = 270 / frequency; + mChans[0].FormantsA[1].f0norm = 2140 / frequency; + mChans[0].FormantsA[2].f0norm = 2950 / frequency; + mChans[0].FormantsA[3].f0norm = 3900 / frequency; + + mChans[0].FormantsA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ + mChans[0].FormantsA[1].fGain = 0.251188f; /* std::pow(10.0f, -12 / 20.0f); */ + mChans[0].FormantsA[2].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ + mChans[0].FormantsA[3].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ + break; + case AL_VOCAL_MORPHER_PHONEME_O: + mChans[0].FormantsA[0].f0norm = 450 / frequency; + mChans[0].FormantsA[1].f0norm = 800 / frequency; + mChans[0].FormantsA[2].f0norm = 2830 / frequency; + mChans[0].FormantsA[3].f0norm = 3800 / frequency; + + mChans[0].FormantsA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ + mChans[0].FormantsA[1].fGain = 0.281838f; /* std::pow(10.0f, -11 / 20.0f); */ + mChans[0].FormantsA[2].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ + mChans[0].FormantsA[3].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ + break; + case AL_VOCAL_MORPHER_PHONEME_U: + mChans[0].FormantsA[0].f0norm = 325 / frequency; + mChans[0].FormantsA[1].f0norm = 700 / frequency; + mChans[0].FormantsA[2].f0norm = 2700 / frequency; + mChans[0].FormantsA[3].f0norm = 3800 / frequency; + + mChans[0].FormantsA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ + mChans[0].FormantsA[1].fGain = 0.158489f; /* std::pow(10.0f, -16 / 20.0f); */ + mChans[0].FormantsA[2].fGain = 0.017782f; /* std::pow(10.0f, -35 / 20.0f); */ + mChans[0].FormantsA[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ + break; + } + + switch(props->Vmorpher.PhonemeB) + { + case AL_VOCAL_MORPHER_PHONEME_A: + mChans[0].FormantsB[0].f0norm = 800 / frequency; + mChans[0].FormantsB[1].f0norm = 1150 / frequency; + mChans[0].FormantsB[2].f0norm = 2900 / frequency; + mChans[0].FormantsB[3].f0norm = 3900 / frequency; + + mChans[0].FormantsB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ + mChans[0].FormantsB[1].fGain = 0.501187f; /* std::pow(10.0f, -6 / 20.0f); */ + mChans[0].FormantsB[2].fGain = 0.025118f; /* std::pow(10.0f, -32 / 20.0f); */ + mChans[0].FormantsB[3].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ + break; + case AL_VOCAL_MORPHER_PHONEME_E: + mChans[0].FormantsB[0].f0norm = 350 / frequency; + mChans[0].FormantsB[1].f0norm = 2000 / frequency; + mChans[0].FormantsB[2].f0norm = 2800 / frequency; + mChans[0].FormantsB[3].f0norm = 3600 / frequency; + + mChans[0].FormantsB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ + mChans[0].FormantsB[1].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ + mChans[0].FormantsB[2].fGain = 0.177827f; /* std::pow(10.0f, -15 / 20.0f); */ + mChans[0].FormantsB[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ + break; + case AL_VOCAL_MORPHER_PHONEME_I: + mChans[0].FormantsB[0].f0norm = 270 / frequency; + mChans[0].FormantsB[1].f0norm = 2140 / frequency; + mChans[0].FormantsB[2].f0norm = 2950 / frequency; + mChans[0].FormantsB[3].f0norm = 3900 / frequency; + + mChans[0].FormantsB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ + mChans[0].FormantsB[1].fGain = 0.251188f; /* std::pow(10.0f, -12 / 20.0f); */ + mChans[0].FormantsB[2].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ + mChans[0].FormantsB[3].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ + break; + case AL_VOCAL_MORPHER_PHONEME_O: + mChans[0].FormantsB[0].f0norm = 450 / frequency; + mChans[0].FormantsB[1].f0norm = 800 / frequency; + mChans[0].FormantsB[2].f0norm = 2830 / frequency; + mChans[0].FormantsB[3].f0norm = 3800 / frequency; + + mChans[0].FormantsB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ + mChans[0].FormantsB[1].fGain = 0.281838f; /* std::pow(10.0f, -11 / 20.0f); */ + mChans[0].FormantsB[2].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ + mChans[0].FormantsB[3].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ + break; + case AL_VOCAL_MORPHER_PHONEME_U: + mChans[0].FormantsB[0].f0norm = 325 / frequency; + mChans[0].FormantsB[1].f0norm = 700 / frequency; + mChans[0].FormantsB[2].f0norm = 2700 / frequency; + mChans[0].FormantsB[3].f0norm = 3800 / frequency; + + mChans[0].FormantsB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ + mChans[0].FormantsB[1].fGain = 0.158489f; /* std::pow(10.0f, -16 / 20.0f); */ + mChans[0].FormantsB[2].fGain = 0.017782f; /* std::pow(10.0f, -35 / 20.0f); */ + mChans[0].FormantsB[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ + break; + } + + /* Copy the filter coefficients for the other input channels. */ + for(ALuint i{1u};i < slot->Wet.Buffer.size();++i) + { + mChans[i].FormantsA[0] = mChans[0].FormantsA[0]; + mChans[i].FormantsA[1] = mChans[0].FormantsA[0]; + mChans[i].FormantsA[2] = mChans[0].FormantsA[0]; + mChans[i].FormantsA[3] = mChans[0].FormantsA[0]; + + mChans[i].FormantsB[0] = mChans[0].FormantsB[0]; + mChans[i].FormantsB[1] = mChans[0].FormantsB[0]; + mChans[i].FormantsB[2] = mChans[0].FormantsB[0]; + mChans[i].FormantsB[3] = mChans[0].FormantsB[0]; + } + + mOutTarget = target.Main->Buffer; + for(ALuint i{0u};i < slot->Wet.Buffer.size();++i) + { + auto coeffs = GetAmbiIdentityRow(i); + ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mChans[i].TargetGains); + } +} + +void VmorpherState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) +{ + /* Following the EFX specification for a conformant implementation which describes + * the effect as a pair of 4-band formant filters blended together using an LFO. + */ + for(ALsizei base{0};base < samplesToDo;) + { + alignas(16) ALfloat lfo[MAX_UPDATE_SAMPLES]; + const ALsizei td = mini(MAX_UPDATE_SAMPLES, samplesToDo-base); + + mGetSamples(lfo, mIndex, mStep, td); + mIndex += (mStep * td) & WAVEFORM_FRACMASK; + mIndex &= WAVEFORM_FRACMASK; + + ASSUME(numInput > 0); + for(ALsizei c{0};c < numInput;c++) + { + for (ALsizei i{0};i < td;i++) + { + mSampleBufferA[i] = 0.0f; + mSampleBufferB[i] = 0.0f; + } + + /* Process first vowel. */ + mChans[c].FormantsA[0].process(&samplesIn[c][base], mSampleBufferA, td); + mChans[c].FormantsA[1].process(&samplesIn[c][base], mSampleBufferA, td); + mChans[c].FormantsA[2].process(&samplesIn[c][base], mSampleBufferA, td); + mChans[c].FormantsA[3].process(&samplesIn[c][base], mSampleBufferA, td); + + /* Process second vowel. */ + mChans[c].FormantsB[0].process(&samplesIn[c][base], mSampleBufferB, td); + mChans[c].FormantsB[1].process(&samplesIn[c][base], mSampleBufferB, td); + mChans[c].FormantsB[2].process(&samplesIn[c][base], mSampleBufferB, td); + mChans[c].FormantsB[3].process(&samplesIn[c][base], mSampleBufferB, td); + + alignas(16) ALfloat samplesBlended[MAX_UPDATE_SAMPLES]; + + for (ALsizei i{0};i < td;i++) + samplesBlended[i] = lerp(mSampleBufferA[i], mSampleBufferB[i], lfo[i]); + + MixSamples(samplesBlended, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, + samplesToDo-base, base, td); + } + + base += td; + } +} + + +void Vmorpher_setParami(EffectProps* props, ALCcontext *context, ALenum param, ALint val) +{ + switch(param) + { + case AL_VOCAL_MORPHER_WAVEFORM: + if(val < AL_VOCAL_MORPHER_MIN_WAVEFORM || val > AL_VOCAL_MORPHER_MAX_WAVEFORM) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher waveform out of range"); + props->Vmorpher.Waveform = val; + break; + + case AL_VOCAL_MORPHER_PHONEMEA: + if(val < AL_VOCAL_MORPHER_MIN_PHONEMEA || val > AL_VOCAL_MORPHER_MAX_PHONEMEA) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher phoneme-a out of range"); + props->Vmorpher.PhonemeA = val; + break; + + case AL_VOCAL_MORPHER_PHONEMEB: + if(val < AL_VOCAL_MORPHER_MIN_PHONEMEB || val > AL_VOCAL_MORPHER_MAX_PHONEMEB) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher phoneme-b out of range"); + props->Vmorpher.PhonemeB = val; + break; + + case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING: + if(val < AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING || val > AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher phoneme-a coarse tuning out of range"); + props->Vmorpher.PhonemeACoarseTuning = val; + break; + + case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING: + if(val < AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING || val > AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher phoneme-b coarse tuning out of range"); + props->Vmorpher.PhonemeBCoarseTuning = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x", param); + } +} +void Vmorpher_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x", param); } +void Vmorpher_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_VOCAL_MORPHER_RATE: + if(val < AL_VOCAL_MORPHER_MIN_RATE || val > AL_VOCAL_MORPHER_MAX_RATE) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher rate out of range"); + props->Vmorpher.Rate = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x", param); + } +} +void Vmorpher_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) +{ Vmorpher_setParamf(props, context, param, vals[0]); } + +void Vmorpher_getParami(const EffectProps* props, ALCcontext *context, ALenum param, ALint* val) +{ + switch(param) + { + case AL_VOCAL_MORPHER_PHONEMEA: + *val = props->Vmorpher.PhonemeA; + break; + + case AL_VOCAL_MORPHER_PHONEMEB: + *val = props->Vmorpher.PhonemeB; + break; + + case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING: + *val = props->Vmorpher.PhonemeACoarseTuning; + break; + + case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING: + *val = props->Vmorpher.PhonemeBCoarseTuning; + break; + + case AL_VOCAL_MORPHER_WAVEFORM: + *val = props->Vmorpher.Waveform; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x", param); + } +} +void Vmorpher_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x", param); } +void Vmorpher_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_VOCAL_MORPHER_RATE: + *val = props->Vmorpher.Rate; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x", param); + } +} +void Vmorpher_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) +{ Vmorpher_getParamf(props, context, param, vals); } + +DEFINE_ALEFFECT_VTABLE(Vmorpher); + + +struct VmorpherStateFactory final : public EffectStateFactory { + EffectState *create() override { return new VmorpherState{}; } + EffectProps getDefaultProps() const noexcept override; + const EffectVtable *getEffectVtable() const noexcept override { return &Vmorpher_vtable; } +}; + +EffectProps VmorpherStateFactory::getDefaultProps() const noexcept +{ + EffectProps props{}; + props.Vmorpher.Rate = AL_VOCAL_MORPHER_DEFAULT_RATE; + props.Vmorpher.PhonemeA = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA; + props.Vmorpher.PhonemeB = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB; + props.Vmorpher.PhonemeACoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING; + props.Vmorpher.PhonemeBCoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING; + props.Vmorpher.Waveform = AL_VOCAL_MORPHER_DEFAULT_WAVEFORM; + return props; +} + +} // namespace + +EffectStateFactory *VmorpherStateFactory_getFactory() +{ + static VmorpherStateFactory VmorpherFactory{}; + return &VmorpherFactory; +} diff --git a/CMakeLists.txt b/CMakeLists.txt index a2150846..3614ec29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -697,6 +697,7 @@ SET(ALC_OBJS Alc/effects/modulator.cpp Alc/effects/null.cpp Alc/effects/pshifter.cpp + Alc/effects/vmorpher.cpp Alc/effects/reverb.cpp Alc/filters/biquad.h Alc/filters/biquad.cpp diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index 51d6a24f..d94317a4 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -18,6 +18,7 @@ enum { FSHIFTER_EFFECT, MODULATOR_EFFECT, PSHIFTER_EFFECT, + VMORPHER_EFFECT, DEDICATED_EFFECT, MAX_EFFECTS @@ -31,7 +32,7 @@ struct EffectList { int type; ALenum val; }; -extern const EffectList gEffectList[14]; +extern const EffectList gEffectList[15]; struct ALeffect { diff --git a/OpenAL32/alEffect.cpp b/OpenAL32/alEffect.cpp index a2a40ac5..0c4f9e72 100644 --- a/OpenAL32/alEffect.cpp +++ b/OpenAL32/alEffect.cpp @@ -38,7 +38,7 @@ #include "effects/base.h" -const EffectList gEffectList[14]{ +const EffectList gEffectList[15]{ { "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB }, { "reverb", REVERB_EFFECT, AL_EFFECT_REVERB }, { "autowah", AUTOWAH_EFFECT, AL_EFFECT_AUTOWAH }, @@ -51,6 +51,7 @@ const EffectList gEffectList[14]{ { "fshifter", FSHIFTER_EFFECT, AL_EFFECT_FREQUENCY_SHIFTER }, { "modulator", MODULATOR_EFFECT, AL_EFFECT_RING_MODULATOR }, { "pshifter", PSHIFTER_EFFECT, AL_EFFECT_PITCH_SHIFTER }, + { "vmorpher", VMORPHER_EFFECT, AL_EFFECT_VOCAL_MORPHER }, { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT }, { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_DIALOGUE }, }; @@ -76,6 +77,7 @@ constexpr struct FactoryItem { { AL_EFFECT_FREQUENCY_SHIFTER, FshifterStateFactory_getFactory }, { AL_EFFECT_RING_MODULATOR, ModulatorStateFactory_getFactory }, { AL_EFFECT_PITCH_SHIFTER, PshifterStateFactory_getFactory}, + { AL_EFFECT_VOCAL_MORPHER, VmorpherStateFactory_getFactory}, { AL_EFFECT_DEDICATED_DIALOGUE, DedicatedStateFactory_getFactory }, { AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedStateFactory_getFactory } }; -- cgit v1.2.3 From 159024acc997540a812fb2fb1197864f46da1dec Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 9 Jul 2019 17:14:15 -0700 Subject: Improve alffplay video clock timing --- examples/alffplay.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index f6bf6863..4deda33a 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -372,7 +372,7 @@ struct VideoState { static Uint32 SDLCALL sdl_refresh_timer_cb(Uint32 interval, void *opaque); void schedRefresh(milliseconds delay); - void display(SDL_Window *screen, SDL_Renderer *renderer); + void display(SDL_Window *screen, SDL_Renderer *renderer, Picture *vp); void refreshTimer(SDL_Window *screen, SDL_Renderer *renderer); void updatePicture(SDL_Window *screen, SDL_Renderer *renderer); bool queuePicture(nanoseconds pts, AVFrame *frame); @@ -1106,6 +1106,7 @@ finish: nanoseconds VideoState::getClock() { /* NOTE: This returns incorrect times while not playing. */ + std::lock_guard _{mPictQMutex}; auto delta = get_avtime() - mCurrentPtsTime; return mCurrentPts + delta; } @@ -1126,10 +1127,8 @@ void VideoState::schedRefresh(milliseconds delay) } /* Called by VideoState::refreshTimer to display the next video frame. */ -void VideoState::display(SDL_Window *screen, SDL_Renderer *renderer) +void VideoState::display(SDL_Window *screen, SDL_Renderer *renderer, Picture *vp) { - Picture *vp = &mPictQ[mPictQRead]; - if(!vp->mImage) return; @@ -1197,8 +1196,6 @@ retry: } Picture *vp = &mPictQ[mPictQRead]; - mCurrentPts = vp->mPts; - mCurrentPtsTime = get_avtime(); /* Get delay using the frame pts and the pts from last frame. */ auto delay = vp->mPts - mFrameLastPts; @@ -1236,6 +1233,9 @@ retry: { /* We don't have time to handle this picture, just skip to the next one. */ lock.lock(); + mCurrentPts = vp->mPts; + mCurrentPtsTime = get_avtime(); + mPictQRead = (mPictQRead+1)%mPictQ.size(); --mPictQSize; --mPictQPrepSize; mPictQCond.notify_all(); @@ -1244,10 +1244,13 @@ retry: schedRefresh(std::chrono::duration_cast(actual_delay)); /* Show the picture! */ - display(screen, renderer); + display(screen, renderer, vp); /* Update queue for next picture. */ lock.lock(); + mCurrentPts = vp->mPts; + mCurrentPtsTime = get_avtime(); + mPictQRead = (mPictQRead+1)%mPictQ.size(); --mPictQSize; --mPictQPrepSize; lock.unlock(); @@ -1662,7 +1665,9 @@ int main(int argc, char *argv[]) return 1; } /* Register all formats and codecs */ +#if !(LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(58, 9, 100)) av_register_all(); +#endif /* Initialize networking protocols */ avformat_network_init(); -- cgit v1.2.3 From 426c4587ccc78ee9a3d36c7120596fbb037b3ff8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Jul 2019 02:13:28 -0700 Subject: Some clean up to use uniform initialization --- examples/alffplay.cpp | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 4deda33a..21ebce77 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -1399,7 +1399,7 @@ int VideoState::handler() avcodec_send_packet(mCodecCtx.get(), nullptr); } /* Decode video frame */ - int ret = avcodec_receive_frame(mCodecCtx.get(), decoded_frame.get()); + int ret{avcodec_receive_frame(mCodecCtx.get(), decoded_frame.get())}; if(ret == AVERROR_EOF) break; if(ret < 0) { @@ -1438,8 +1438,8 @@ int MovieState::decode_interrupt_cb(void *ctx) bool MovieState::prepare() { - AVIOContext *avioctx = nullptr; - AVIOInterruptCB intcb = { decode_interrupt_cb, this }; + AVIOContext *avioctx{nullptr}; + AVIOInterruptCB intcb{decode_interrupt_cb, this}; if(avio_open2(&avioctx, mFilename.c_str(), AVIO_FLAG_READ, &intcb, nullptr)) { std::cerr<< "Failed to open "<pb = mIOContext.get(); fmtctx->interrupt_callback = intcb; if(avformat_open_input(&fmtctx, mFilename.c_str(), nullptr, nullptr) != 0) @@ -1467,9 +1467,9 @@ bool MovieState::prepare() return false; } - mVideo.schedRefresh(milliseconds(40)); + mVideo.schedRefresh(milliseconds{40}); - mParseThread = std::thread(std::mem_fn(&MovieState::parse_handler), this); + mParseThread = std::thread{std::mem_fn(&MovieState::parse_handler), this}; return true; } @@ -1508,17 +1508,17 @@ int MovieState::streamComponentOpen(int stream_index) /* Get a pointer to the codec context for the stream, and open the * associated codec. */ - AVCodecCtxPtr avctx(avcodec_alloc_context3(nullptr)); + AVCodecCtxPtr avctx{avcodec_alloc_context3(nullptr)}; if(!avctx) return -1; if(avcodec_parameters_to_context(avctx.get(), mFormatCtx->streams[stream_index]->codecpar)) return -1; - AVCodec *codec = avcodec_find_decoder(avctx->codec_id); + AVCodec *codec{avcodec_find_decoder(avctx->codec_id)}; if(!codec || avcodec_open2(avctx.get(), codec, nullptr) < 0) { std::cerr<< "Unsupported codec: "<codec_id) - << " (0x"<codec_id<codec_id<nb_streams;i++) + for(unsigned int i{0u};i < mFormatCtx->nb_streams;i++) { auto codecpar = mFormatCtx->streams[i]->codecpar; if(codecpar->codec_type == AVMEDIA_TYPE_VIDEO && !DisableVideo && video_index < 0) @@ -1611,7 +1611,7 @@ int MovieState::parse_handler() mAudioThread.join(); mVideo.mEOS = true; - std::unique_lock lock(mVideo.mPictQMutex); + std::unique_lock lock{mVideo.mPictQMutex}; while(!mVideo.mFinalUpdate) mVideo.mPictQCond.wait(lock); lock.unlock(); @@ -1642,7 +1642,7 @@ inline std::ostream &operator<<(std::ostream &os, const PrettyTime &rhs) } // Only handle up to hour formatting - if(t >= hours(1)) + if(t >= hours{1}) os << duration_cast(t).count() << 'h' << std::setfill('0') << std::setw(2) << (duration_cast(t).count() % 60) << 'm'; else @@ -1678,25 +1678,25 @@ int main(int argc, char *argv[]) } /* Make a window to put our video */ - SDL_Window *screen = SDL_CreateWindow(AppName.c_str(), 0, 0, 640, 480, SDL_WINDOW_RESIZABLE); + SDL_Window *screen{SDL_CreateWindow(AppName.c_str(), 0, 0, 640, 480, SDL_WINDOW_RESIZABLE)}; if(!screen) { std::cerr<< "SDL: could not set video mode - exiting" <(new MovieState(argv[fileidx++])); + movState = std::unique_ptr{new MovieState{argv[fileidx++]}}; if(!movState->prepare()) movState = nullptr; } if(!movState) @@ -1812,12 +1812,12 @@ int main(int argc, char *argv[]) /* Default to going to the next movie at the end of one. */ enum class EomAction { Next, Quit - } eom_action = EomAction::Next; - seconds last_time(-1); - SDL_Event event; + } eom_action{EomAction::Next}; + seconds last_time{-1}; + SDL_Event event{}; while(1) { - int have_evt = SDL_WaitEventTimeout(&event, 10); + int have_evt{SDL_WaitEventTimeout(&event, 10)}; auto cur_time = std::chrono::duration_cast(movState->getMasterClock()); if(cur_time != last_time) @@ -1882,7 +1882,7 @@ int main(int argc, char *argv[]) movState = nullptr; while(fileidx < argc && !movState) { - movState = std::unique_ptr(new MovieState(argv[fileidx++])); + movState = std::unique_ptr{new MovieState{argv[fileidx++]}}; if(!movState->prepare()) movState = nullptr; } if(movState) -- cgit v1.2.3 From ac28b7d0f2110ea36c559edb627c8e02fa49a38f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Jul 2019 18:54:43 -0700 Subject: Use a find module for OpenSL --- CMakeLists.txt | 20 +++++++--------- cmake/FindOpenSL.cmake | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 11 deletions(-) create mode 100644 cmake/FindOpenSL.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 3614ec29..01baa040 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1080,17 +1080,15 @@ ENDIF() # Check for OpenSL (Android) backend OPTION(ALSOFT_REQUIRE_OPENSL "Require OpenSL backend" OFF) -CHECK_INCLUDE_FILES("SLES/OpenSLES.h;SLES/OpenSLES_Android.h" HAVE_SLES_OPENSLES_ANDROID_H) -IF(HAVE_SLES_OPENSLES_ANDROID_H) - CHECK_SHARED_FUNCTION_EXISTS(slCreateEngine "SLES/OpenSLES.h" OpenSLES "" HAVE_LIBOPENSLES) - IF(HAVE_LIBOPENSLES) - OPTION(ALSOFT_BACKEND_OPENSL "Enable OpenSL backend" ON) - IF(ALSOFT_BACKEND_OPENSL) - SET(HAVE_OPENSL 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/opensl.cpp Alc/backends/opensl.h) - SET(BACKENDS "${BACKENDS} OpenSL,") - SET(EXTRA_LIBS OpenSLES ${EXTRA_LIBS}) - ENDIF() +FIND_PACKAGE(OpenSL) +IF(OPENSL_FOUND) + OPTION(ALSOFT_BACKEND_OPENSL "Enable OpenSL backend" ON) + IF(ALSOFT_BACKEND_OPENSL) + SET(HAVE_OPENSL 1) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/opensl.cpp Alc/backends/opensl.h) + SET(BACKENDS "${BACKENDS} OpenSL,") + SET(EXTRA_LIBS ${OPENSL_LIBRARIES} ${EXTRA_LIBS}) + SET(INC_PATHS ${INC_PATHS} ${OPENSL_INCLUDE_DIRS}) ENDIF() ENDIF() IF(ALSOFT_REQUIRE_OPENSL AND NOT HAVE_OPENSL) diff --git a/cmake/FindOpenSL.cmake b/cmake/FindOpenSL.cmake new file mode 100644 index 00000000..1bd72d10 --- /dev/null +++ b/cmake/FindOpenSL.cmake @@ -0,0 +1,64 @@ +# - Find OpenSL +# Find the OpenSL libraries +# +# This module defines the following variables: +# OPENSL_FOUND - True if OPENSL_INCLUDE_DIR & OPENSL_LIBRARY are set +# OPENSL_INCLUDE_DIRS - where to find SLES/OpenSLES.h, etc. +# OPENSL_LIBRARIES - the OpenSL library +# + +#============================================================================= +# Copyright 2009-2011 Kitware, Inc. +# Copyright 2009-2011 Philip Lowman +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * The names of Kitware, Inc., the Insight Consortium, or the names of +# any consortium members, or of any contributors, may not be used to +# endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#============================================================================= + +find_path(OPENSL_INCLUDE_DIR NAMES SLES/OpenSLES.h + DOC "The OpenSL include directory" +) +find_path(OPENSL_ANDROID_INCLUDE_DIR NAMES SLES/OpenSLES_Android.h + DOC "The OpenSL Android include directory" +) + +find_library(OPENSL_LIBRARY NAMES OpenSL + DOC "The OpenSL library" +) + +# handle the QUIETLY and REQUIRED arguments and set OPENSL_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(OPENSL REQUIRED_VARS OPENSL_LIBRARY OPENSL_INCLUDE_DIR + OPENSL_ANDROID_INCLUDE_DIR) + +if(OPENSL_FOUND) + set(OPENSL_LIBRARIES ${OPENSL_LIBRARY}) + set(OPENSL_INCLUDE_DIRS ${OPENSL_INCLUDE_DIR} ${OPENSL_ANDROID_INCLUDE_DIR}) +endif() + +mark_as_advanced(OPENSL_INCLUDE_DIR OPENSL_ANDROID_INCLUDE_DIR OPENSL_LIBRARY) -- cgit v1.2.3 From e2f2b74d6a9021d4cc2eff9e8a28543ff3ddb5c0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Jul 2019 19:32:26 -0700 Subject: Get rid of the custom CHECK_SHARED_FUNCTION_EXISTS function --- CMakeLists.txt | 21 ++++---- cmake/CheckSharedFunctionExists.cmake | 92 ----------------------------------- 2 files changed, 9 insertions(+), 104 deletions(-) delete mode 100644 cmake/CheckSharedFunctionExists.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 01baa040..21846be1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,6 @@ SET(CMAKE_MODULE_PATH "${OpenAL_SOURCE_DIR}/cmake") INCLUDE(CheckFunctionExists) INCLUDE(CheckLibraryExists) -INCLUDE(CheckSharedFunctionExists) INCLUDE(CheckIncludeFile) INCLUDE(CheckIncludeFiles) INCLUDE(CheckSymbolExists) @@ -697,8 +696,8 @@ SET(ALC_OBJS Alc/effects/modulator.cpp Alc/effects/null.cpp Alc/effects/pshifter.cpp - Alc/effects/vmorpher.cpp Alc/effects/reverb.cpp + Alc/effects/vmorpher.cpp Alc/filters/biquad.h Alc/filters/biquad.cpp Alc/filters/nfc.cpp @@ -944,16 +943,14 @@ IF(HAVE_WINDOWS_H) # Check MMSystem backend CHECK_INCLUDE_FILES("windows.h;mmsystem.h" HAVE_MMSYSTEM_H) - IF(HAVE_MMSYSTEM_H) - CHECK_SHARED_FUNCTION_EXISTS(waveOutOpen "windows.h;mmsystem.h" winmm "" HAVE_LIBWINMM) - IF(HAVE_LIBWINMM) - OPTION(ALSOFT_BACKEND_WINMM "Enable Windows Multimedia backend" ON) - IF(ALSOFT_BACKEND_WINMM) - SET(HAVE_WINMM 1) - SET(BACKENDS "${BACKENDS} WinMM,") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/winmm.cpp Alc/backends/winmm.h) - SET(EXTRA_LIBS winmm ${EXTRA_LIBS}) - ENDIF() + FIND_LIBRARY(WINMM_LIBRARY NAMES winmm) + IF(HAVE_MMSYSTEM_H AND WINMM_LIBRARY) + OPTION(ALSOFT_BACKEND_WINMM "Enable Windows Multimedia backend" ON) + IF(ALSOFT_BACKEND_WINMM) + SET(HAVE_WINMM 1) + SET(BACKENDS "${BACKENDS} WinMM,") + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/winmm.cpp Alc/backends/winmm.h) + SET(EXTRA_LIBS ${WINMM_LIBRARY} ${EXTRA_LIBS}) ENDIF() ENDIF() diff --git a/cmake/CheckSharedFunctionExists.cmake b/cmake/CheckSharedFunctionExists.cmake deleted file mode 100644 index c691fa9c..00000000 --- a/cmake/CheckSharedFunctionExists.cmake +++ /dev/null @@ -1,92 +0,0 @@ -# - Check if a symbol exists as a function, variable, or macro -# CHECK_SYMBOL_EXISTS( ) -# -# Check that the is available after including given header -# and store the result in a . Specify the list -# of files in one argument as a semicolon-separated list. -# -# If the header files define the symbol as a macro it is considered -# available and assumed to work. If the header files declare the -# symbol as a function or variable then the symbol must also be -# available for linking. If the symbol is a type or enum value -# it will not be recognized (consider using CheckTypeSize or -# CheckCSourceCompiles). -# -# The following variables may be set before calling this macro to -# modify the way the check is run: -# -# CMAKE_REQUIRED_FLAGS = string of compile command line flags -# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) -# CMAKE_REQUIRED_INCLUDES = list of include directories -# CMAKE_REQUIRED_LIBRARIES = list of libraries to link - -#============================================================================= -# Copyright 2003-2011 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -MACRO(CHECK_SHARED_FUNCTION_EXISTS SYMBOL FILES LIBRARY LOCATION VARIABLE) - IF(NOT DEFINED "${VARIABLE}" OR "x${${VARIABLE}}" STREQUAL "x${VARIABLE}") - SET(CMAKE_CONFIGURABLE_FILE_CONTENT "/* */\n") - SET(MACRO_CHECK_SYMBOL_EXISTS_FLAGS ${CMAKE_REQUIRED_FLAGS}) - IF(CMAKE_REQUIRED_LIBRARIES) - SET(CHECK_SYMBOL_EXISTS_LIBS - "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES};${LIBRARY}") - ELSE(CMAKE_REQUIRED_LIBRARIES) - SET(CHECK_SYMBOL_EXISTS_LIBS - "-DLINK_LIBRARIES:STRING=${LIBRARY}") - ENDIF(CMAKE_REQUIRED_LIBRARIES) - IF(CMAKE_REQUIRED_INCLUDES) - SET(CMAKE_SYMBOL_EXISTS_INCLUDES - "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") - ELSE(CMAKE_REQUIRED_INCLUDES) - SET(CMAKE_SYMBOL_EXISTS_INCLUDES) - ENDIF(CMAKE_REQUIRED_INCLUDES) - FOREACH(FILE ${FILES}) - SET(CMAKE_CONFIGURABLE_FILE_CONTENT - "${CMAKE_CONFIGURABLE_FILE_CONTENT}#include <${FILE}>\n") - ENDFOREACH(FILE) - SET(CMAKE_CONFIGURABLE_FILE_CONTENT - "${CMAKE_CONFIGURABLE_FILE_CONTENT}\nvoid cmakeRequireSymbol(int dummy,...){(void)dummy;}\nint main()\n{\n cmakeRequireSymbol(0,&${SYMBOL});\n return 0;\n}\n") - - CONFIGURE_FILE("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in" - "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c" @ONLY) - - MESSAGE(STATUS "Looking for ${SYMBOL} in ${LIBRARY}") - TRY_COMPILE(${VARIABLE} - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c - COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} - CMAKE_FLAGS - -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_SYMBOL_EXISTS_FLAGS} - -DLINK_DIRECTORIES:STRING=${LOCATION} - "${CHECK_SYMBOL_EXISTS_LIBS}" - "${CMAKE_SYMBOL_EXISTS_INCLUDES}" - OUTPUT_VARIABLE OUTPUT) - IF(${VARIABLE}) - MESSAGE(STATUS "Looking for ${SYMBOL} in ${LIBRARY} - found") - SET(${VARIABLE} 1 CACHE INTERNAL "Have symbol ${SYMBOL} in ${LIBRARY}") - FILE(APPEND ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log - "Determining if the ${SYMBOL} " - "exist in ${LIBRARY} passed with the following output:\n" - "${OUTPUT}\nFile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n" - "${CMAKE_CONFIGURABLE_FILE_CONTENT}\n") - ELSE(${VARIABLE}) - MESSAGE(STATUS "Looking for ${SYMBOL} in ${LIBRARY} - not found.") - SET(${VARIABLE} "" CACHE INTERNAL "Have symbol ${SYMBOL} in ${LIBRARY}") - FILE(APPEND ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "Determining if the ${SYMBOL} " - "exist in ${LIBRARY} failed with the following output:\n" - "${OUTPUT}\nFile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n" - "${CMAKE_CONFIGURABLE_FILE_CONTENT}\n") - ENDIF(${VARIABLE}) - ENDIF(NOT DEFINED "${VARIABLE}" OR "x${${VARIABLE}}" STREQUAL "x${VARIABLE}") -ENDMACRO(CHECK_SHARED_FUNCTION_EXISTS) -- cgit v1.2.3 From 93d0c8993d22f5944efdca64b1b1905a479a19dc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Jul 2019 19:55:14 -0700 Subject: Fix OpenSL library name --- cmake/FindOpenSL.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/FindOpenSL.cmake b/cmake/FindOpenSL.cmake index 1bd72d10..41c68fde 100644 --- a/cmake/FindOpenSL.cmake +++ b/cmake/FindOpenSL.cmake @@ -46,7 +46,7 @@ find_path(OPENSL_ANDROID_INCLUDE_DIR NAMES SLES/OpenSLES_Android.h DOC "The OpenSL Android include directory" ) -find_library(OPENSL_LIBRARY NAMES OpenSL +find_library(OPENSL_LIBRARY NAMES OpenSLES DOC "The OpenSL library" ) -- cgit v1.2.3 From 99b55bc2301d04bd7b078d78a60c628ef5964fa0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Jul 2019 20:06:50 -0700 Subject: Add the Windows SDK for the winmm library path --- CMakeLists.txt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 21846be1..cf10bc20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -938,12 +938,22 @@ OPTION(ALSOFT_REQUIRE_WINMM "Require Windows Multimedia backend" OFF) OPTION(ALSOFT_REQUIRE_DSOUND "Require DirectSound backend" OFF) OPTION(ALSOFT_REQUIRE_WASAPI "Require WASAPI backend" OFF) IF(HAVE_WINDOWS_H) + SET(WINSDK_LIB_DIRS ) + SET(WINSDK_INCLUDE_DIRS ) + FIND_PACKAGE(WindowsSDK) + IF(WINDOWSSDK_FOUND) + get_windowssdk_library_dirs(${WINDOWSSDK_PREFERRED_DIR} WINSDK_LIB_DIRS) + get_windowssdk_include_dirs(${WINDOWSSDK_PREFERRED_DIR} WINSDK_INCLUDE_DIRS) + ENDIF() + SET(OLD_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}) SET(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_WIN32_WINNT=0x0502) # Check MMSystem backend CHECK_INCLUDE_FILES("windows.h;mmsystem.h" HAVE_MMSYSTEM_H) - FIND_LIBRARY(WINMM_LIBRARY NAMES winmm) + FIND_LIBRARY(WINMM_LIBRARY NAMES winmm + PATHS ${WINSDK_LIB_DIRS} + PATH_SUFFIXES lib lib/x86 lib/x64) IF(HAVE_MMSYSTEM_H AND WINMM_LIBRARY) OPTION(ALSOFT_BACKEND_WINMM "Enable Windows Multimedia backend" ON) IF(ALSOFT_BACKEND_WINMM) -- cgit v1.2.3 From 2e6c7808b014de6e15c16aa58506192a0b141cd2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jul 2019 03:54:26 -0700 Subject: Try to improve alffplay timing again --- examples/alffplay.cpp | 63 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 21ebce77..eecaaeff 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -322,7 +322,7 @@ struct AudioState { int decodeFrame(); bool readAudio(uint8_t *samples, int length); - int handler(); + int handler(const milliseconds start_delay); }; struct VideoState { @@ -339,7 +339,7 @@ struct VideoState { nanoseconds mFrameLastDelay{0}; nanoseconds mCurrentPts{0}; /* time (av_gettime) at which we updated mCurrentPts - used to have running video pts */ - microseconds mCurrentPtsTime{0}; + microseconds mCurrentPtsTime{microseconds::min()}; /* Swscale context for format conversion */ SwsContextPtr mSwscaleCtx; @@ -376,7 +376,7 @@ struct VideoState { void refreshTimer(SDL_Window *screen, SDL_Renderer *renderer); void updatePicture(SDL_Window *screen, SDL_Renderer *renderer); bool queuePicture(nanoseconds pts, AVFrame *frame); - int handler(); + int handler(const milliseconds start_delay); }; struct MovieState { @@ -385,7 +385,7 @@ struct MovieState { SyncMaster mAVSyncType{SyncMaster::Default}; - microseconds mClockBase{0}; + microseconds mClockBase{microseconds::min()}; std::atomic mQuit{false}; @@ -706,14 +706,14 @@ void AL_APIENTRY AudioState::EventCallback(ALenum eventType, ALuint object, ALui ALsizei length, const ALchar *message, void *userParam) { - AudioState *self = static_cast(userParam); + auto self = static_cast(userParam); if(eventType == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT) { /* Temporarily lock the source mutex to ensure it's not between * checking the processed count and going to sleep. */ - std::unique_lock(self->mSrcMutex).unlock(); + std::unique_lock{self->mSrcMutex}.unlock(); self->mSrcCond.notify_one(); return; } @@ -738,7 +738,8 @@ void AL_APIENTRY AudioState::EventCallback(ALenum eventType, ALuint object, ALui if(eventType == AL_EVENT_TYPE_DISCONNECTED_SOFT) { - { std::lock_guard lock(self->mSrcMutex); + { + std::lock_guard lock{self->mSrcMutex}; self->mConnected.clear(std::memory_order_release); } self->mSrcCond.notify_one(); @@ -746,12 +747,21 @@ void AL_APIENTRY AudioState::EventCallback(ALenum eventType, ALuint object, ALui } #endif -int AudioState::handler() +int AudioState::handler(const milliseconds /*start_delay*/) { - std::unique_lock srclock(mSrcMutex); - milliseconds sleep_time = AudioBufferTime / 3; + std::unique_lock srclock{mSrcMutex}; + milliseconds sleep_time{AudioBufferTime / 3}; ALenum fmt; + if(alcGetInteger64vSOFT) + { + int64_t devtime{}; + alcGetInteger64vSOFT(alcGetContextsDevice(alcGetCurrentContext()), ALC_DEVICE_CLOCK_SOFT, + 1, &devtime); + mDeviceStartTime = nanoseconds{devtime} - mCurrentPts; + } + srclock.unlock(); + #ifdef AL_SOFT_events const std::array evt_types{{ AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, @@ -999,13 +1009,7 @@ int AudioState::handler() #endif samples = av_malloc(buffer_len); - { - int64_t devtime{}; - alcGetInteger64vSOFT(alcGetContextsDevice(alcGetCurrentContext()), ALC_DEVICE_CLOCK_SOFT, - 1, &devtime); - mDeviceStartTime = nanoseconds{devtime} - mCurrentPts; - } - + srclock.lock(); while(alGetError() == AL_NO_ERROR && !mMovie.mQuit.load(std::memory_order_relaxed) && mConnected.test_and_set(std::memory_order_relaxed)) { @@ -1086,10 +1090,10 @@ int AudioState::handler() alSourceRewind(mSource); alSourcei(mSource, AL_BUFFER, 0); + srclock.unlock(); finish: av_freep(&samples); - srclock.unlock(); #ifdef AL_SOFT_events if(alEventControlSOFT) @@ -1107,6 +1111,8 @@ nanoseconds VideoState::getClock() { /* NOTE: This returns incorrect times while not playing. */ std::lock_guard _{mPictQMutex}; + if(mCurrentPtsTime == microseconds::min()) + return nanoseconds::zero(); auto delta = get_avtime() - mCurrentPtsTime; return mCurrentPts + delta; } @@ -1217,7 +1223,7 @@ retry: /* Skip or repeat the frame. Take delay into account. */ auto sync_threshold = std::min(delay, VideoSyncThreshold); - if(!(diff < AVNoSyncThreshold && diff > -AVNoSyncThreshold)) + if(diff < AVNoSyncThreshold && diff > -AVNoSyncThreshold) { if(diff <= -sync_threshold) delay = nanoseconds::zero(); @@ -1381,8 +1387,14 @@ bool VideoState::queuePicture(nanoseconds pts, AVFrame *frame) return true; } -int VideoState::handler() +int VideoState::handler(const milliseconds start_delay) { + { + std::lock_guard _{mPictQMutex}; + mCurrentPtsTime = get_avtime(); + mFrameTimer = mCurrentPtsTime + start_delay; + } + AVFramePtr decoded_frame{av_frame_alloc()}; while(!mMovie.mQuit.load(std::memory_order_relaxed)) { @@ -1485,6 +1497,8 @@ void MovieState::setTitle(SDL_Window *window) nanoseconds MovieState::getClock() { + if(mClockBase == microseconds::min()) + return nanoseconds::zero(); return get_avtime() - mClockBase; } @@ -1570,14 +1584,13 @@ int MovieState::parse_handler() } /* Set the base time 500ms ahead of the current av time. */ - mClockBase = get_avtime() + milliseconds{500}; - mVideo.mCurrentPtsTime = mClockBase; - mVideo.mFrameTimer = mVideo.mCurrentPtsTime; + constexpr milliseconds start_delay{500}; + mClockBase = get_avtime() + start_delay; if(audio_index >= 0) - mAudioThread = std::thread{std::mem_fn(&AudioState::handler), &mAudio}; + mAudioThread = std::thread{std::mem_fn(&AudioState::handler), &mAudio, start_delay}; if(video_index >= 0) - mVideoThread = std::thread{std::mem_fn(&VideoState::handler), &mVideo}; + mVideoThread = std::thread{std::mem_fn(&VideoState::handler), &mVideo, start_delay}; /* Main packet reading/dispatching loop */ while(!mQuit.load(std::memory_order_relaxed)) -- cgit v1.2.3 From 79d572cf72788f417f00f5d63ed0598c523d4871 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 12 Jul 2019 22:13:19 -0700 Subject: Properly comment out the sample config's options --- alsoftrc.sample | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/alsoftrc.sample b/alsoftrc.sample index 93f70cc1..0128008c 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -272,7 +272,7 @@ # configuration files for the appropriate speaker configuration you intend to # use (see the quad, surround51, etc options below). Currently, up to third- # order decoding is supported. -hq-mode = false +#hq-mode = false ## distance-comp: # Enables compensation for the speakers' relative distances to the listener. @@ -280,7 +280,7 @@ hq-mode = false # behave as though they are all equidistant, which is important for proper # playback of 3D sound rendering. Requires the proper distances to be # specified in the decoder configuration file. -distance-comp = true +#distance-comp = true ## nfc: # Enables near-field control filters. This simulates and compensates for low- @@ -289,7 +289,7 @@ distance-comp = true # may be stronger or weaker than intended if the application doesn't use or # specify an appropriate unit scale, or if incorrect speaker distances are set # in the decoder configuration file. -nfc = false +#nfc = false ## nfc-ref-delay # Specifies the reference delay value for ambisonic output when NFC filters @@ -300,29 +300,29 @@ nfc = false # designed for higher-order ambisonics, this also applies to first-order # output. When left unset, normal output is created with no near-field # simulation. Requires the nfc option to also be enabled. -nfc-ref-delay = +#nfc-ref-delay = ## quad: # Decoder configuration file for Quadraphonic channel output. See # docs/ambdec.txt for a description of the file format. -quad = +#quad = ## surround51: # Decoder configuration file for 5.1 Surround (Side and Rear) channel output. # See docs/ambdec.txt for a description of the file format. -surround51 = +#surround51 = ## surround61: # Decoder configuration file for 6.1 Surround channel output. See # docs/ambdec.txt for a description of the file format. -surround61 = +#surround61 = ## surround71: # Decoder configuration file for 7.1 Surround channel output. See # docs/ambdec.txt for a description of the file format. Note: This can be used # to enable 3D7.1 with the appropriate configuration and speaker placement, # see docs/3D7.1.txt. -surround71 = +#surround71 = ## ## Reverb effect stuff (includes EAX reverb) -- cgit v1.2.3 From f99474c913109dba9a4824979d6ea6f41f150831 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 12 Jul 2019 23:34:21 -0700 Subject: Handle alffplay video using continuous rendering --- examples/alffplay.cpp | 527 ++++++++++++++++++++++---------------------------- 1 file changed, 236 insertions(+), 291 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index eecaaeff..0b80e20f 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -133,9 +133,7 @@ const milliseconds AudioBufferTime{20}; const milliseconds AudioBufferTotalTime{800}; enum { - FF_UPDATE_EVENT = SDL_USEREVENT, - FF_REFRESH_EVENT, - FF_MOVIE_DONE_EVENT + FF_MOVIE_DONE_EVENT = SDL_USEREVENT }; enum class SyncMaster { @@ -322,7 +320,7 @@ struct AudioState { int decodeFrame(); bool readAudio(uint8_t *samples, int length); - int handler(const milliseconds start_delay); + int handler(); }; struct VideoState { @@ -333,13 +331,13 @@ struct VideoState { PacketQueue<14*1024*1024> mPackets; - nanoseconds mClock{0}; - nanoseconds mFrameTimer{0}; - nanoseconds mFrameLastPts{0}; - nanoseconds mFrameLastDelay{0}; + /* The expected pts of the next frame to decode. */ nanoseconds mCurrentPts{0}; - /* time (av_gettime) at which we updated mCurrentPts - used to have running video pts */ - microseconds mCurrentPtsTime{microseconds::min()}; + /* The pts of the currently displayed frame, and the time (av_gettime) it + * was last updated - used to have running video pts + */ + nanoseconds mDisplayPts{0}; + microseconds mDisplayPtsTime{microseconds::min()}; /* Swscale context for format conversion */ SwsContextPtr mSwscaleCtx; @@ -347,19 +345,23 @@ struct VideoState { struct Picture { SDL_Texture *mImage{nullptr}; int mWidth{0}, mHeight{0}; /* Logical image size (actual size may be larger) */ - AVFramePtr mFrame{av_frame_alloc()}; - nanoseconds mPts{0}; + AVFramePtr mFrame{}; + nanoseconds mPts{nanoseconds::min()}; + bool mUpdated{false}; + Picture() = default; + Picture(Picture&&) = delete; ~Picture() { if(mImage) SDL_DestroyTexture(mImage); mImage = nullptr; } + Picture& operator=(Picture&&) = delete; }; std::array mPictQ; - size_t mPictQSize{0}, mPictQRead{0}, mPictQWrite{0}; - size_t mPictQPrepSize{0}, mPictQPrep{0}; + size_t mPictQSize{0u}, mPictQRead{0u}, mPictQWrite{1u}; + size_t mPictQPrepSize{0u}, mPictQPrep{1u}; std::mutex mPictQMutex; std::condition_variable mPictQCond; bool mFirstUpdate{true}; @@ -370,13 +372,10 @@ struct VideoState { nanoseconds getClock(); - static Uint32 SDLCALL sdl_refresh_timer_cb(Uint32 interval, void *opaque); - void schedRefresh(milliseconds delay); void display(SDL_Window *screen, SDL_Renderer *renderer, Picture *vp); - void refreshTimer(SDL_Window *screen, SDL_Renderer *renderer); - void updatePicture(SDL_Window *screen, SDL_Renderer *renderer); + void updateVideo(SDL_Window *screen, SDL_Renderer *renderer); bool queuePicture(nanoseconds pts, AVFrame *frame); - int handler(const milliseconds start_delay); + int handler(); }; struct MovieState { @@ -747,7 +746,7 @@ void AL_APIENTRY AudioState::EventCallback(ALenum eventType, ALuint object, ALui } #endif -int AudioState::handler(const milliseconds /*start_delay*/) +int AudioState::handler() { std::unique_lock srclock{mSrcMutex}; milliseconds sleep_time{AudioBufferTime / 3}; @@ -1111,28 +1110,13 @@ nanoseconds VideoState::getClock() { /* NOTE: This returns incorrect times while not playing. */ std::lock_guard _{mPictQMutex}; - if(mCurrentPtsTime == microseconds::min()) + if(mDisplayPtsTime == microseconds::min()) return nanoseconds::zero(); - auto delta = get_avtime() - mCurrentPtsTime; - return mCurrentPts + delta; -} - -Uint32 SDLCALL VideoState::sdl_refresh_timer_cb(Uint32 /*interval*/, void *opaque) -{ - SDL_Event evt{}; - evt.user.type = FF_REFRESH_EVENT; - evt.user.data1 = opaque; - SDL_PushEvent(&evt); - return 0; /* 0 means stop timer */ -} - -/* Schedules an FF_REFRESH_EVENT event to occur in 'delay' ms. */ -void VideoState::schedRefresh(milliseconds delay) -{ - SDL_AddTimer(delay.count(), sdl_refresh_timer_cb, this); + auto delta = get_avtime() - mDisplayPtsTime; + return mDisplayPts + delta; } -/* Called by VideoState::refreshTimer to display the next video frame. */ +/* Called by VideoState::updateVideo to display the next video frame. */ void VideoState::display(SDL_Window *screen, SDL_Renderer *renderer, Picture *vp) { if(!vp->mImage) @@ -1169,232 +1153,201 @@ void VideoState::display(SDL_Window *screen, SDL_Renderer *renderer, Picture *vp SDL_RenderPresent(renderer); } -/* FF_REFRESH_EVENT handler called on the main thread where the SDL_Renderer - * was created. It handles the display of the next decoded video frame (if not - * falling behind), and sets up the timer for the following video frame. +/* Called regularly on the main thread where the SDL_Renderer was created. It + * handles updating the textures of decoded frames and displaying the latest + * frame. */ -void VideoState::refreshTimer(SDL_Window *screen, SDL_Renderer *renderer) +void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer) { - if(!mStream) - { - if(mEOS) - { - mFinalUpdate = true; - std::unique_lock(mPictQMutex).unlock(); - mPictQCond.notify_all(); - return; - } - schedRefresh(milliseconds{100}); - return; - } - std::unique_lock lock{mPictQMutex}; -retry: - if(mPictQPrepSize == 0 || mMovie.mQuit.load(std::memory_order_relaxed)) + while(mPictQPrep != mPictQWrite && !mMovie.mQuit.load(std::memory_order_relaxed)) { - if(mEOS) - mFinalUpdate = true; - else - schedRefresh(milliseconds{10}); + Picture *vp{&mPictQ[mPictQPrep]}; + bool fmt_updated{false}; lock.unlock(); - mPictQCond.notify_all(); - return; - } - Picture *vp = &mPictQ[mPictQRead]; + /* allocate or resize the buffer! */ + if(!vp->mImage || vp->mWidth != mCodecCtx->width || vp->mHeight != mCodecCtx->height) + { + fmt_updated = true; + if(vp->mImage) + SDL_DestroyTexture(vp->mImage); + vp->mImage = SDL_CreateTexture( + renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, + mCodecCtx->coded_width, mCodecCtx->coded_height + ); + if(!vp->mImage) + std::cerr<< "Failed to create YV12 texture!" <mWidth = mCodecCtx->width; + vp->mHeight = mCodecCtx->height; - /* Get delay using the frame pts and the pts from last frame. */ - auto delay = vp->mPts - mFrameLastPts; - if(delay <= seconds::zero() || delay >= seconds{1}) - { - /* If incorrect delay, use previous one. */ - delay = mFrameLastDelay; - } - /* Save for next frame. */ - mFrameLastDelay = delay; - mFrameLastPts = vp->mPts; - lock.unlock(); + if(mFirstUpdate && vp->mWidth > 0 && vp->mHeight > 0) + { + /* For the first update, set the window size to the video size. */ + mFirstUpdate = false; - /* Update delay to sync to clock if not master source. */ - if(mMovie.mAVSyncType != SyncMaster::Video) - { - auto ref_clock = mMovie.getMasterClock(); - auto diff = vp->mPts - ref_clock; + int w = vp->mWidth; + int h = vp->mHeight; + if(mCodecCtx->sample_aspect_ratio.den != 0) + { + double aspect_ratio = av_q2d(mCodecCtx->sample_aspect_ratio); + if(aspect_ratio >= 1.0) + w = static_cast(w*aspect_ratio + 0.5); + else if(aspect_ratio > 0.0) + h = static_cast(h/aspect_ratio + 0.5); + } + SDL_SetWindowSize(screen, w, h); + } + } - /* Skip or repeat the frame. Take delay into account. */ - auto sync_threshold = std::min(delay, VideoSyncThreshold); - if(diff < AVNoSyncThreshold && diff > -AVNoSyncThreshold) + if(vp->mImage) { - if(diff <= -sync_threshold) - delay = nanoseconds::zero(); - else if(diff >= sync_threshold) - delay *= 2; + AVFrame *frame{vp->mFrame.get()}; + void *pixels{nullptr}; + int pitch{0}; + + if(mCodecCtx->pix_fmt == AV_PIX_FMT_YUV420P) + SDL_UpdateYUVTexture(vp->mImage, nullptr, + frame->data[0], frame->linesize[0], + frame->data[1], frame->linesize[1], + frame->data[2], frame->linesize[2] + ); + else if(SDL_LockTexture(vp->mImage, nullptr, &pixels, &pitch) != 0) + std::cerr<< "Failed to lock texture" <coded_width}; + int coded_h{mCodecCtx->coded_height}; + int w{mCodecCtx->width}; + int h{mCodecCtx->height}; + if(!mSwscaleCtx || fmt_updated) + { + mSwscaleCtx.reset(sws_getContext( + w, h, mCodecCtx->pix_fmt, + w, h, AV_PIX_FMT_YUV420P, 0, + nullptr, nullptr, nullptr + )); + } + + /* point pict at the queue */ + uint8_t *pict_data[3]; + pict_data[0] = static_cast(pixels); + pict_data[1] = pict_data[0] + coded_w*coded_h; + pict_data[2] = pict_data[1] + coded_w*coded_h/4; + + int pict_linesize[3]; + pict_linesize[0] = pitch; + pict_linesize[1] = pitch / 2; + pict_linesize[2] = pitch / 2; + + sws_scale(mSwscaleCtx.get(), reinterpret_cast(frame->data), frame->linesize, + 0, h, pict_data, pict_linesize); + SDL_UnlockTexture(vp->mImage); + } } - } + vp->mUpdated = true; + av_frame_unref(vp->mFrame.get()); - mFrameTimer += delay; - /* Compute the REAL delay. */ - auto actual_delay = mFrameTimer - get_avtime(); - if(!(actual_delay >= VideoSyncThreshold)) - { - /* We don't have time to handle this picture, just skip to the next one. */ - lock.lock(); - mCurrentPts = vp->mPts; - mCurrentPtsTime = get_avtime(); + mPictQPrep = (mPictQPrep+1)%mPictQ.size(); + ++mPictQPrepSize; - mPictQRead = (mPictQRead+1)%mPictQ.size(); - --mPictQSize; --mPictQPrepSize; - mPictQCond.notify_all(); - goto retry; + lock.lock(); } - schedRefresh(std::chrono::duration_cast(actual_delay)); - /* Show the picture! */ - display(screen, renderer, vp); + Picture *vp{&mPictQ[mPictQRead]}; + auto clocktime = mMovie.getMasterClock(); - /* Update queue for next picture. */ - lock.lock(); - mCurrentPts = vp->mPts; - mCurrentPtsTime = get_avtime(); + bool updated{false}; + while(mPictQPrepSize > 0 && !mMovie.mQuit.load(std::memory_order_relaxed)) + { + size_t nextIdx{(mPictQRead+1)%mPictQ.size()}; + Picture *newvp{&mPictQ[nextIdx]}; + if(clocktime < newvp->mPts || !newvp->mUpdated) + break; - mPictQRead = (mPictQRead+1)%mPictQ.size(); - --mPictQSize; --mPictQPrepSize; - lock.unlock(); - mPictQCond.notify_all(); -} + newvp->mUpdated = false; + if(!newvp->mImage) + std::swap(vp->mImage, newvp->mImage); + vp = newvp; + updated = true; -/* FF_UPDATE_EVENT handler, updates the picture's texture. It's called on the - * main thread where the renderer was created. - */ -void VideoState::updatePicture(SDL_Window *screen, SDL_Renderer *renderer) -{ + mPictQRead = nextIdx; + --mPictQSize; --mPictQPrepSize; + } if(mMovie.mQuit.load(std::memory_order_relaxed)) + { + if(mEOS) + mFinalUpdate = true; + lock.unlock(); + mPictQCond.notify_all(); return; + } + lock.unlock(); + if(updated) + mPictQCond.notify_all(); - Picture *vp = &mPictQ[mPictQPrep]; - bool fmt_updated = false; + /* Show the picture! */ + display(screen, renderer, vp); - /* allocate or resize the buffer! */ - if(!vp->mImage || vp->mWidth != mCodecCtx->width || vp->mHeight != mCodecCtx->height) + if(updated) { - fmt_updated = true; - if(vp->mImage) - SDL_DestroyTexture(vp->mImage); - vp->mImage = SDL_CreateTexture( - renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, - mCodecCtx->coded_width, mCodecCtx->coded_height - ); - if(!vp->mImage) - std::cerr<< "Failed to create YV12 texture!" <mWidth = mCodecCtx->width; - vp->mHeight = mCodecCtx->height; - - if(mFirstUpdate && vp->mWidth > 0 && vp->mHeight > 0) + lock.lock(); + mDisplayPts = vp->mPts; + mDisplayPtsTime = get_avtime(); + if(mEOS.load(std::memory_order_acquire) && mPictQSize == 0) { - /* For the first update, set the window size to the video size. */ - mFirstUpdate = false; - - int w = vp->mWidth; - int h = vp->mHeight; - if(mCodecCtx->sample_aspect_ratio.den != 0) - { - double aspect_ratio = av_q2d(mCodecCtx->sample_aspect_ratio); - if(aspect_ratio >= 1.0) - w = static_cast(w*aspect_ratio + 0.5); - else if(aspect_ratio > 0.0) - h = static_cast(h/aspect_ratio + 0.5); - } - SDL_SetWindowSize(screen, w, h); + mFinalUpdate = true; + mPictQCond.notify_all(); } + lock.unlock(); } - - AVFrame *frame{vp->mFrame.get()}; - if(vp->mImage) + else if(mEOS.load(std::memory_order_acquire)) { - void *pixels{nullptr}; - int pitch{0}; - - if(mCodecCtx->pix_fmt == AV_PIX_FMT_YUV420P) - SDL_UpdateYUVTexture(vp->mImage, nullptr, - frame->data[0], frame->linesize[0], - frame->data[1], frame->linesize[1], - frame->data[2], frame->linesize[2] - ); - else if(SDL_LockTexture(vp->mImage, nullptr, &pixels, &pitch) != 0) - std::cerr<< "Failed to lock texture" <coded_width}; - int coded_h{mCodecCtx->coded_height}; - int w{mCodecCtx->width}; - int h{mCodecCtx->height}; - if(!mSwscaleCtx || fmt_updated) - { - mSwscaleCtx.reset(sws_getContext( - w, h, mCodecCtx->pix_fmt, - w, h, AV_PIX_FMT_YUV420P, 0, - nullptr, nullptr, nullptr - )); - } - - /* point pict at the queue */ - uint8_t *pict_data[3]; - pict_data[0] = reinterpret_cast(pixels); - pict_data[1] = pict_data[0] + coded_w*coded_h; - pict_data[2] = pict_data[1] + coded_w*coded_h/4; - - int pict_linesize[3]; - pict_linesize[0] = pitch; - pict_linesize[1] = pitch / 2; - pict_linesize[2] = pitch / 2; - - sws_scale(mSwscaleCtx.get(), reinterpret_cast(frame->data), frame->linesize, - 0, h, pict_data, pict_linesize); - SDL_UnlockTexture(vp->mImage); + mFinalUpdate = true; + mPictQCond.notify_all(); } + lock.unlock(); } - av_frame_unref(frame); - - mPictQPrep = (mPictQPrep+1)%mPictQ.size(); - ++mPictQPrepSize; } bool VideoState::queuePicture(nanoseconds pts, AVFrame *frame) { /* Wait until we have space for a new pic */ std::unique_lock lock{mPictQMutex}; - while(mPictQSize >= mPictQ.size() && !mMovie.mQuit.load(std::memory_order_relaxed)) + while(mPictQSize >= (mPictQ.size()-1) && !mMovie.mQuit.load(std::memory_order_relaxed)) mPictQCond.wait(lock); if(mMovie.mQuit.load(std::memory_order_relaxed)) return false; + /* Put the frame in the queue to be loaded into a texture (and eventually + * displayed) by the rendering thread. + */ Picture *vp{&mPictQ[mPictQWrite]}; av_frame_move_ref(vp->mFrame.get(), frame); vp->mPts = pts; mPictQWrite = (mPictQWrite+1)%mPictQ.size(); ++mPictQSize; - lock.unlock(); - - /* We have to create/update the picture in the main thread */ - SDL_Event evt{}; - evt.user.type = FF_UPDATE_EVENT; - evt.user.data1 = this; - SDL_PushEvent(&evt); return true; } -int VideoState::handler(const milliseconds start_delay) +int VideoState::handler() { { std::lock_guard _{mPictQMutex}; - mCurrentPtsTime = get_avtime(); - mFrameTimer = mCurrentPtsTime + start_delay; + mDisplayPtsTime = get_avtime(); } + std::for_each(mPictQ.begin(), mPictQ.end(), + [](Picture &pict) -> void + { pict.mFrame = AVFramePtr{av_frame_alloc()}; }); + AVFramePtr decoded_frame{av_frame_alloc()}; while(!mMovie.mQuit.load(std::memory_order_relaxed)) { @@ -1421,14 +1374,14 @@ int VideoState::handler(const milliseconds start_delay) /* Get the PTS for this frame. */ if(decoded_frame->best_effort_timestamp != AV_NOPTS_VALUE) - mClock = std::chrono::duration_cast( + mCurrentPts = std::chrono::duration_cast( seconds_d64{av_q2d(mStream->time_base)*decoded_frame->best_effort_timestamp}); - nanoseconds pts{mClock}; + nanoseconds pts{mCurrentPts}; /* Update the video clock to the next expected PTS. */ auto frame_delay = av_q2d(mCodecCtx->time_base); frame_delay += decoded_frame->repeat_pict * (frame_delay * 0.5); - mClock += std::chrono::duration_cast(seconds_d64{frame_delay}); + mCurrentPts += std::chrono::duration_cast(seconds_d64{frame_delay}); if(!queuePicture(pts, decoded_frame.get())) break; @@ -1479,8 +1432,6 @@ bool MovieState::prepare() return false; } - mVideo.schedRefresh(milliseconds{40}); - mParseThread = std::thread{std::mem_fn(&MovieState::parse_handler), this}; return true; } @@ -1584,13 +1535,12 @@ int MovieState::parse_handler() } /* Set the base time 500ms ahead of the current av time. */ - constexpr milliseconds start_delay{500}; - mClockBase = get_avtime() + start_delay; + mClockBase = get_avtime() + milliseconds{500}; if(audio_index >= 0) - mAudioThread = std::thread{std::mem_fn(&AudioState::handler), &mAudio, start_delay}; + mAudioThread = std::thread{std::mem_fn(&AudioState::handler), &mAudio}; if(video_index >= 0) - mVideoThread = std::thread{std::mem_fn(&VideoState::handler), &mVideo, start_delay}; + mVideoThread = std::thread{std::mem_fn(&VideoState::handler), &mVideo}; /* Main packet reading/dispatching loop */ while(!mQuit.load(std::memory_order_relaxed)) @@ -1641,13 +1591,13 @@ int MovieState::parse_handler() struct PrettyTime { seconds mTime; }; -inline std::ostream &operator<<(std::ostream &os, const PrettyTime &rhs) +std::ostream &operator<<(std::ostream &os, const PrettyTime &rhs) { using hours = std::chrono::hours; using minutes = std::chrono::minutes; using std::chrono::duration_cast; - seconds t = rhs.mTime; + seconds t{rhs.mTime}; if(t.count() < 0) { os << '-'; @@ -1827,9 +1777,9 @@ int main(int argc, char *argv[]) Next, Quit } eom_action{EomAction::Next}; seconds last_time{-1}; - SDL_Event event{}; while(1) { + SDL_Event event{}; int have_evt{SDL_WaitEventTimeout(&event, 10)}; auto cur_time = std::chrono::duration_cast(movState->getMasterClock()); @@ -1839,88 +1789,83 @@ int main(int argc, char *argv[]) std::cout<< "\r "<mQuit = true; - eom_action = EomAction::Quit; - break; - - case SDLK_n: - movState->mQuit = true; - eom_action = EomAction::Next; - break; - - default: - break; - } - break; - - case SDL_WINDOWEVENT: - switch(event.window.event) - { - case SDL_WINDOWEVENT_RESIZED: - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - SDL_RenderFillRect(renderer, nullptr); - break; - default: - break; - } - break; + if(have_evt) do { + switch(event.type) + { + case SDL_KEYDOWN: + switch(event.key.keysym.sym) + { + case SDLK_ESCAPE: + movState->mQuit = true; + eom_action = EomAction::Quit; + break; + + case SDLK_n: + movState->mQuit = true; + eom_action = EomAction::Next; + break; + + default: + break; + } + break; - case SDL_QUIT: - movState->mQuit = true; - eom_action = EomAction::Quit; - break; + case SDL_WINDOWEVENT: + switch(event.window.event) + { + case SDL_WINDOWEVENT_RESIZED: + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderFillRect(renderer, nullptr); + break; - case FF_UPDATE_EVENT: - static_cast(event.user.data1)->updatePicture(screen, renderer); - break; + default: + break; + } + break; - case FF_REFRESH_EVENT: - static_cast(event.user.data1)->refreshTimer(screen, renderer); - break; + case SDL_QUIT: + movState->mQuit = true; + eom_action = EomAction::Quit; + break; - case FF_MOVIE_DONE_EVENT: - std::cout<<'\n'; - last_time = seconds(-1); - if(eom_action != EomAction::Quit) - { - movState = nullptr; - while(fileidx < argc && !movState) + case FF_MOVIE_DONE_EVENT: + std::cout<<'\n'; + last_time = seconds(-1); + if(eom_action != EomAction::Quit) { - movState = std::unique_ptr{new MovieState{argv[fileidx++]}}; - if(!movState->prepare()) movState = nullptr; + movState = nullptr; + while(fileidx < argc && !movState) + { + movState = std::unique_ptr{new MovieState{argv[fileidx++]}}; + if(!movState->prepare()) movState = nullptr; + } + if(movState) + { + movState->setTitle(screen); + break; + } } - if(movState) - { - movState->setTitle(screen); - break; - } - } - /* Nothing more to play. Shut everything down and quit. */ - movState = nullptr; + /* Nothing more to play. Shut everything down and quit. */ + movState = nullptr; - CloseAL(); + CloseAL(); - SDL_DestroyRenderer(renderer); - renderer = nullptr; - SDL_DestroyWindow(screen); - screen = nullptr; + SDL_DestroyRenderer(renderer); + renderer = nullptr; + SDL_DestroyWindow(screen); + screen = nullptr; - SDL_Quit(); - exit(0); + SDL_Quit(); + exit(0); - default: - break; - } + default: + break; + } + } while(SDL_PollEvent(&event)); + + movState->mVideo.updateVideo(screen, renderer); } std::cerr<< "SDL_WaitEvent error - "< Date: Sat, 13 Jul 2019 16:51:19 -0700 Subject: MSVC doesn't like parenthesized type initialization --- utils/makemhr/loadsofa.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/utils/makemhr/loadsofa.cpp b/utils/makemhr/loadsofa.cpp index b6dd66d9..7fb169e2 100644 --- a/utils/makemhr/loadsofa.cpp +++ b/utils/makemhr/loadsofa.cpp @@ -170,9 +170,8 @@ static bool PrepareLayout(const uint m, const float *xyzs, HrirDataT *hData) mysofa_c2s(&aers[i]); } - const uint fdCount{GetUniquelySortedElems(m, aers.data(), 2, - (const double*[3]){ nullptr, nullptr, nullptr }, (const double[3]){ 0.1, 0.1, 0.001 }, - elems.data())}; + const uint fdCount{GetUniquelySortedElems(m, aers.data(), 2, { nullptr, nullptr, nullptr }, + { 0.1, 0.1, 0.001 }, elems.data())}; if(fdCount > MAX_FD_COUNT) { fprintf(stdout, "Incompatible layout (inumerable radii).\n"); @@ -181,7 +180,6 @@ static bool PrepareLayout(const uint m, const float *xyzs, HrirDataT *hData) double distances[MAX_FD_COUNT]{}; uint evCounts[MAX_FD_COUNT]{}; - uint evStarts[MAX_FD_COUNT]{}; auto azCounts = std::vector(MAX_FD_COUNT * MAX_EV_COUNT); for(uint fi{0u};fi < fdCount;fi++) { @@ -201,9 +199,8 @@ static bool PrepareLayout(const uint m, const float *xyzs, HrirDataT *hData) for(uint fi{0u};fi < fdCount;fi++) { const double dist{distances[fi]}; - uint evCount{GetUniquelySortedElems(m, aers.data(), 1, - (const double*[3]){ nullptr, nullptr, &dist }, (const double[3]){ 0.1, 0.1, 0.001 }, - elems.data())}; + uint evCount{GetUniquelySortedElems(m, aers.data(), 1, { nullptr, nullptr, &dist }, + { 0.1, 0.1, 0.001 }, elems.data())}; if(evCount > MAX_EV_COUNT) { @@ -239,14 +236,12 @@ static bool PrepareLayout(const uint m, const float *xyzs, HrirDataT *hData) } evCounts[fi] = evCount; - evStarts[fi] = evStart; for(uint ei{evStart};ei < evCount;ei++) { const double ev{-90.0 + ei*180.0/(evCount - 1)}; - const uint azCount{GetUniquelySortedElems(m, aers.data(), 0, - (const double*[3]){ nullptr, &ev, &dist }, (const double[3]){ 0.1, 0.1, 0.001 }, - elems.data())}; + const uint azCount{GetUniquelySortedElems(m, aers.data(), 0, { nullptr, &ev, &dist }, + { 0.1, 0.1, 0.001 }, elems.data())}; if(azCount > MAX_AZ_COUNT) { -- cgit v1.2.3 From 313549c76d6049a9c36922a6b13724522b8aad58 Mon Sep 17 00:00:00 2001 From: Penguin Date: Sun, 14 Jul 2019 18:03:32 +0900 Subject: Add missing header. --- utils/makemhr/loaddef.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/makemhr/loaddef.cpp b/utils/makemhr/loaddef.cpp index d3962c16..28f2e1b0 100644 --- a/utils/makemhr/loaddef.cpp +++ b/utils/makemhr/loaddef.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include "mysofa.h" -- cgit v1.2.3 From 4027664fc2d73656d7ec223fb3946d501baa433f Mon Sep 17 00:00:00 2001 From: Penguin Date: Sun, 14 Jul 2019 18:03:49 +0900 Subject: Fixed MSVC error. --- utils/sofa-info.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/utils/sofa-info.cpp b/utils/sofa-info.cpp index e31ca654..c7c7a8f7 100644 --- a/utils/sofa-info.cpp +++ b/utils/sofa-info.cpp @@ -207,9 +207,7 @@ static void PrintCompatibleLayout(const uint m, const float *xyzs) mysofa_c2s(&aers[i]); } - uint fdCount{GetUniquelySortedElems(m, aers.data(), 2, - (const float*[3]){ nullptr, nullptr, nullptr }, (const float[3]){ 0.1f, 0.1f, 0.001f }, - elems.data())}; + uint fdCount{GetUniquelySortedElems(m, aers.data(), 2, { nullptr, nullptr, nullptr }, { 0.1f, 0.1f, 0.001f }, elems.data())}; if(fdCount > (m / 3)) { fprintf(stdout, "Incompatible layout (inumerable radii).\n"); @@ -223,9 +221,7 @@ static void PrintCompatibleLayout(const uint m, const float *xyzs) for(uint fi{0u};fi < fdCount;fi++) { float dist{fds[fi].mDistance}; - uint evCount{GetUniquelySortedElems(m, aers.data(), 1, - (const float*[3]){ nullptr, nullptr, &dist }, (const float[3]){ 0.1f, 0.1f, 0.001f }, - elems.data())}; + uint evCount{GetUniquelySortedElems(m, aers.data(), 1, { nullptr, nullptr, &dist }, { 0.1f, 0.1f, 0.001f }, elems.data())}; if(evCount > (m / 3)) { @@ -268,9 +264,7 @@ static void PrintCompatibleLayout(const uint m, const float *xyzs) for(uint ei{evStart};ei < evCount;ei++) { float ev{-90.0f + ei * 180.0f / (evCount - 1)}; - uint azCount{GetUniquelySortedElems(m, aers.data(), 0, - (const float*[3]){ nullptr, &ev, &dist }, (const float[3]){ 0.1f, 0.1f, 0.001f }, - elems.data())}; + uint azCount{GetUniquelySortedElems(m, aers.data(), 0, { nullptr, &ev, &dist }, { 0.1f, 0.1f, 0.001f }, elems.data())}; if(azCount > (m / 3)) { -- cgit v1.2.3 From e7e734f8b986faf936faa677242af64afa51a752 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Jul 2019 19:27:28 -0700 Subject: Don't use one texture per picture in alffplay --- examples/alffplay.cpp | 139 ++++++++++++++++++++++---------------------------- 1 file changed, 60 insertions(+), 79 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 0b80e20f..c42e1aeb 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -343,36 +343,32 @@ struct VideoState { SwsContextPtr mSwscaleCtx; struct Picture { - SDL_Texture *mImage{nullptr}; - int mWidth{0}, mHeight{0}; /* Logical image size (actual size may be larger) */ AVFramePtr mFrame{}; nanoseconds mPts{nanoseconds::min()}; - bool mUpdated{false}; - - Picture() = default; - Picture(Picture&&) = delete; - ~Picture() - { - if(mImage) - SDL_DestroyTexture(mImage); - mImage = nullptr; - } - Picture& operator=(Picture&&) = delete; }; std::array mPictQ; size_t mPictQSize{0u}, mPictQRead{0u}, mPictQWrite{1u}; - size_t mPictQPrepSize{0u}, mPictQPrep{1u}; std::mutex mPictQMutex; std::condition_variable mPictQCond; + + SDL_Texture *mImage{nullptr}; + int mWidth{0}, mHeight{0}; /* Logical image size (actual size may be larger) */ + bool mFirstUpdate{true}; std::atomic mEOS{false}; std::atomic mFinalUpdate{false}; VideoState(MovieState &movie) : mMovie(movie) { } + ~VideoState() + { + if(mImage) + SDL_DestroyTexture(mImage); + mImage = nullptr; + } nanoseconds getClock(); - void display(SDL_Window *screen, SDL_Renderer *renderer, Picture *vp); + void display(SDL_Window *screen, SDL_Renderer *renderer); void updateVideo(SDL_Window *screen, SDL_Renderer *renderer); bool queuePicture(nanoseconds pts, AVFrame *frame); int handler(); @@ -1117,9 +1113,9 @@ nanoseconds VideoState::getClock() } /* Called by VideoState::updateVideo to display the next video frame. */ -void VideoState::display(SDL_Window *screen, SDL_Renderer *renderer, Picture *vp) +void VideoState::display(SDL_Window *screen, SDL_Renderer *renderer) { - if(!vp->mImage) + if(!mImage) return; float aspect_ratio; @@ -1147,9 +1143,9 @@ void VideoState::display(SDL_Window *screen, SDL_Renderer *renderer, Picture *vp x = (win_w - w) / 2; y = (win_h - h) / 2; - SDL_Rect src_rect{ 0, 0, vp->mWidth, vp->mHeight }; + SDL_Rect src_rect{ 0, 0, mWidth, mHeight }; SDL_Rect dst_rect{ x, y, w, h }; - SDL_RenderCopy(renderer, vp->mImage, &src_rect, &dst_rect); + SDL_RenderCopy(renderer, mImage, &src_rect, &dst_rect); SDL_RenderPresent(renderer); } @@ -1160,34 +1156,57 @@ void VideoState::display(SDL_Window *screen, SDL_Renderer *renderer, Picture *vp void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer) { std::unique_lock lock{mPictQMutex}; - while(mPictQPrep != mPictQWrite && !mMovie.mQuit.load(std::memory_order_relaxed)) + Picture *vp{&mPictQ[mPictQRead]}; + auto clocktime = mMovie.getMasterClock(); + + bool updated{false}; + while(mPictQSize > 0) { - Picture *vp{&mPictQ[mPictQPrep]}; - bool fmt_updated{false}; + size_t nextIdx{(mPictQRead+1)%mPictQ.size()}; + Picture *newvp{&mPictQ[nextIdx]}; + if(clocktime < newvp->mPts) + break; + + vp = newvp; + updated = true; + + mPictQRead = nextIdx; + --mPictQSize; + } + if(mMovie.mQuit.load(std::memory_order_relaxed)) + { + if(mEOS) + mFinalUpdate = true; lock.unlock(); + mPictQCond.notify_all(); + return; + } + lock.unlock(); + if(updated) + { + mPictQCond.notify_all(); /* allocate or resize the buffer! */ - if(!vp->mImage || vp->mWidth != mCodecCtx->width || vp->mHeight != mCodecCtx->height) + bool fmt_updated{false}; + if(!mImage || mWidth != mCodecCtx->width || mHeight != mCodecCtx->height) { fmt_updated = true; - if(vp->mImage) - SDL_DestroyTexture(vp->mImage); - vp->mImage = SDL_CreateTexture( - renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, - mCodecCtx->coded_width, mCodecCtx->coded_height - ); - if(!vp->mImage) + if(mImage) + SDL_DestroyTexture(mImage); + mImage = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, + mCodecCtx->coded_width, mCodecCtx->coded_height); + if(!mImage) std::cerr<< "Failed to create YV12 texture!" <mWidth = mCodecCtx->width; - vp->mHeight = mCodecCtx->height; + mWidth = mCodecCtx->width; + mHeight = mCodecCtx->height; - if(mFirstUpdate && vp->mWidth > 0 && vp->mHeight > 0) + if(mFirstUpdate && mWidth > 0 && mHeight > 0) { /* For the first update, set the window size to the video size. */ mFirstUpdate = false; - int w = vp->mWidth; - int h = vp->mHeight; + int w{mWidth}; + int h{mHeight}; if(mCodecCtx->sample_aspect_ratio.den != 0) { double aspect_ratio = av_q2d(mCodecCtx->sample_aspect_ratio); @@ -1200,19 +1219,19 @@ void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer) } } - if(vp->mImage) + if(mImage) { AVFrame *frame{vp->mFrame.get()}; void *pixels{nullptr}; int pitch{0}; if(mCodecCtx->pix_fmt == AV_PIX_FMT_YUV420P) - SDL_UpdateYUVTexture(vp->mImage, nullptr, + SDL_UpdateYUVTexture(mImage, nullptr, frame->data[0], frame->linesize[0], frame->data[1], frame->linesize[1], frame->data[2], frame->linesize[2] ); - else if(SDL_LockTexture(vp->mImage, nullptr, &pixels, &pitch) != 0) + else if(SDL_LockTexture(mImage, nullptr, &pixels, &pitch) != 0) std::cerr<< "Failed to lock texture" <(frame->data), frame->linesize, 0, h, pict_data, pict_linesize); - SDL_UnlockTexture(vp->mImage); + SDL_UnlockTexture(mImage); } } - vp->mUpdated = true; av_frame_unref(vp->mFrame.get()); - - mPictQPrep = (mPictQPrep+1)%mPictQ.size(); - ++mPictQPrepSize; - - lock.lock(); } - Picture *vp{&mPictQ[mPictQRead]}; - auto clocktime = mMovie.getMasterClock(); - - bool updated{false}; - while(mPictQPrepSize > 0 && !mMovie.mQuit.load(std::memory_order_relaxed)) - { - size_t nextIdx{(mPictQRead+1)%mPictQ.size()}; - Picture *newvp{&mPictQ[nextIdx]}; - if(clocktime < newvp->mPts || !newvp->mUpdated) - break; - - newvp->mUpdated = false; - if(!newvp->mImage) - std::swap(vp->mImage, newvp->mImage); - vp = newvp; - updated = true; - - mPictQRead = nextIdx; - --mPictQSize; --mPictQPrepSize; - } - if(mMovie.mQuit.load(std::memory_order_relaxed)) - { - if(mEOS) - mFinalUpdate = true; - lock.unlock(); - mPictQCond.notify_all(); - return; - } - lock.unlock(); - if(updated) - mPictQCond.notify_all(); - /* Show the picture! */ - display(screen, renderer, vp); + display(screen, renderer); if(updated) { @@ -1634,7 +1615,7 @@ int main(int argc, char *argv[]) /* Initialize networking protocols */ avformat_network_init(); - if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER)) + if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) { std::cerr<< "Could not initialize SDL - <<"< Date: Sat, 13 Jul 2019 21:58:08 -0700 Subject: Receive frames directly into the picture's AVFrame --- examples/alffplay.cpp | 53 ++++++++++++++++++--------------------------------- 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index c42e1aeb..1a509c92 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -370,7 +370,6 @@ struct VideoState { void display(SDL_Window *screen, SDL_Renderer *renderer); void updateVideo(SDL_Window *screen, SDL_Renderer *renderer); - bool queuePicture(nanoseconds pts, AVFrame *frame); int handler(); }; @@ -1295,29 +1294,6 @@ void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer) } } -bool VideoState::queuePicture(nanoseconds pts, AVFrame *frame) -{ - /* Wait until we have space for a new pic */ - std::unique_lock lock{mPictQMutex}; - while(mPictQSize >= (mPictQ.size()-1) && !mMovie.mQuit.load(std::memory_order_relaxed)) - mPictQCond.wait(lock); - - if(mMovie.mQuit.load(std::memory_order_relaxed)) - return false; - - /* Put the frame in the queue to be loaded into a texture (and eventually - * displayed) by the rendering thread. - */ - Picture *vp{&mPictQ[mPictQWrite]}; - av_frame_move_ref(vp->mFrame.get(), frame); - vp->mPts = pts; - - mPictQWrite = (mPictQWrite+1)%mPictQ.size(); - ++mPictQSize; - - return true; -} - int VideoState::handler() { { @@ -1329,9 +1305,9 @@ int VideoState::handler() [](Picture &pict) -> void { pict.mFrame = AVFramePtr{av_frame_alloc()}; }); - AVFramePtr decoded_frame{av_frame_alloc()}; while(!mMovie.mQuit.load(std::memory_order_relaxed)) { + Picture *vp{&mPictQ[mPictQWrite]}; { std::unique_lock lock{mPackets.getMutex()}; AVPacket *lastpkt{}; @@ -1345,7 +1321,8 @@ int VideoState::handler() avcodec_send_packet(mCodecCtx.get(), nullptr); } /* Decode video frame */ - int ret{avcodec_receive_frame(mCodecCtx.get(), decoded_frame.get())}; + AVFrame *decoded_frame{vp->mFrame.get()}; + int ret{avcodec_receive_frame(mCodecCtx.get(), decoded_frame)}; if(ret == AVERROR_EOF) break; if(ret < 0) { @@ -1357,19 +1334,27 @@ int VideoState::handler() if(decoded_frame->best_effort_timestamp != AV_NOPTS_VALUE) mCurrentPts = std::chrono::duration_cast( seconds_d64{av_q2d(mStream->time_base)*decoded_frame->best_effort_timestamp}); - nanoseconds pts{mCurrentPts}; + vp->mPts = mCurrentPts; /* Update the video clock to the next expected PTS. */ auto frame_delay = av_q2d(mCodecCtx->time_base); frame_delay += decoded_frame->repeat_pict * (frame_delay * 0.5); mCurrentPts += std::chrono::duration_cast(seconds_d64{frame_delay}); - if(!queuePicture(pts, decoded_frame.get())) - break; + /* Put the frame in the queue to be loaded into a texture and displayed + * by the rendering thread. + */ + std::unique_lock lock{mPictQMutex}; + mPictQWrite = (mPictQWrite+1)%mPictQ.size(); + ++mPictQSize; + + /* Wait until we have space for a new pic */ + while(mPictQSize >= (mPictQ.size()-1) && !mMovie.mQuit.load(std::memory_order_relaxed)) + mPictQCond.wait(lock); } mEOS = true; - std::unique_lock lock(mPictQMutex); + std::unique_lock lock{mPictQMutex}; while(!mFinalUpdate) mPictQCond.wait(lock); @@ -1515,8 +1500,8 @@ int MovieState::parse_handler() mQuit = true; } - /* Set the base time 500ms ahead of the current av time. */ - mClockBase = get_avtime() + milliseconds{500}; + /* Set the base time 750ms ahead of the current av time. */ + mClockBase = get_avtime() + milliseconds{750}; if(audio_index >= 0) mAudioThread = std::thread{std::mem_fn(&AudioState::handler), &mAudio}; @@ -1534,12 +1519,12 @@ int MovieState::parse_handler() if(packet.stream_index == video_index) { while(!mQuit.load(std::memory_order_acquire) && !video_queue.put(&packet)) - std::this_thread::sleep_for(milliseconds{50}); + std::this_thread::sleep_for(milliseconds{100}); } else if(packet.stream_index == audio_index) { while(!mQuit.load(std::memory_order_acquire) && !audio_queue.put(&packet)) - std::this_thread::sleep_for(milliseconds{50}); + std::this_thread::sleep_for(milliseconds{100}); } av_packet_unref(&packet); -- cgit v1.2.3 From ac7eeeae7997b6e75ec82dce610b524df33d6f8b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Jul 2019 22:50:14 -0700 Subject: Don't use the same mutex for the video clock --- examples/alffplay.cpp | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 1a509c92..625c63a6 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -338,6 +338,7 @@ struct VideoState { */ nanoseconds mDisplayPts{0}; microseconds mDisplayPtsTime{microseconds::min()}; + std::mutex mDispPtsMutex; /* Swscale context for format conversion */ SwsContextPtr mSwscaleCtx; @@ -1104,7 +1105,7 @@ finish: nanoseconds VideoState::getClock() { /* NOTE: This returns incorrect times while not playing. */ - std::lock_guard _{mPictQMutex}; + std::lock_guard _{mDispPtsMutex}; if(mDisplayPtsTime == microseconds::min()) return nanoseconds::zero(); auto delta = get_avtime() - mDisplayPtsTime; @@ -1154,19 +1155,20 @@ void VideoState::display(SDL_Window *screen, SDL_Renderer *renderer) */ void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer) { - std::unique_lock lock{mPictQMutex}; Picture *vp{&mPictQ[mPictQRead]}; + + std::unique_lock lock{mPictQMutex}; auto clocktime = mMovie.getMasterClock(); bool updated{false}; while(mPictQSize > 0) { size_t nextIdx{(mPictQRead+1)%mPictQ.size()}; - Picture *newvp{&mPictQ[nextIdx]}; - if(clocktime < newvp->mPts) + Picture *nextvp{&mPictQ[nextIdx]}; + if(clocktime < nextvp->mPts) break; - vp = newvp; + vp = nextvp; updated = true; mPictQRead = nextIdx; @@ -1181,6 +1183,7 @@ void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer) return; } lock.unlock(); + if(updated) { mPictQCond.notify_all(); @@ -1264,7 +1267,6 @@ void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer) SDL_UnlockTexture(mImage); } } - av_frame_unref(vp->mFrame.get()); } /* Show the picture! */ @@ -1272,17 +1274,13 @@ void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer) if(updated) { - lock.lock(); + auto disp_time = get_avtime(); + + std::lock_guard _{mDispPtsMutex}; mDisplayPts = vp->mPts; - mDisplayPtsTime = get_avtime(); - if(mEOS.load(std::memory_order_acquire) && mPictQSize == 0) - { - mFinalUpdate = true; - mPictQCond.notify_all(); - } - lock.unlock(); + mDisplayPtsTime = disp_time; } - else if(mEOS.load(std::memory_order_acquire)) + if(mEOS.load(std::memory_order_acquire)) { lock.lock(); if(mPictQSize == 0) @@ -1297,7 +1295,7 @@ void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer) int VideoState::handler() { { - std::lock_guard _{mPictQMutex}; + std::lock_guard _{mDispPtsMutex}; mDisplayPtsTime = get_avtime(); } -- cgit v1.2.3 From 4ff7bfd2d8c5e94e61fbbb7afe57f98037a5383e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Jul 2019 01:05:54 -0700 Subject: Use atomics for the picture queue --- examples/alffplay.cpp | 64 ++++++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 625c63a6..ccdfd51f 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -348,14 +348,14 @@ struct VideoState { nanoseconds mPts{nanoseconds::min()}; }; std::array mPictQ; - size_t mPictQSize{0u}, mPictQRead{0u}, mPictQWrite{1u}; + std::atomic mPictQRead{0u}, mPictQWrite{1u}; std::mutex mPictQMutex; std::condition_variable mPictQCond; SDL_Texture *mImage{nullptr}; int mWidth{0}, mHeight{0}; /* Logical image size (actual size may be larger) */ - bool mFirstUpdate{true}; + std::atomic mEOS{false}; std::atomic mFinalUpdate{false}; @@ -1155,37 +1155,38 @@ void VideoState::display(SDL_Window *screen, SDL_Renderer *renderer) */ void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer) { - Picture *vp{&mPictQ[mPictQRead]}; + size_t read_idx{mPictQRead.load(std::memory_order_relaxed)}; + Picture *vp{&mPictQ[read_idx]}; - std::unique_lock lock{mPictQMutex}; auto clocktime = mMovie.getMasterClock(); - bool updated{false}; - while(mPictQSize > 0) + while(1) { - size_t nextIdx{(mPictQRead+1)%mPictQ.size()}; - Picture *nextvp{&mPictQ[nextIdx]}; + size_t next_idx{(read_idx+1)%mPictQ.size()}; + if(next_idx == mPictQWrite.load(std::memory_order_acquire)) + break; + Picture *nextvp{&mPictQ[next_idx]}; if(clocktime < nextvp->mPts) break; vp = nextvp; updated = true; - - mPictQRead = nextIdx; - --mPictQSize; + read_idx = next_idx; } if(mMovie.mQuit.load(std::memory_order_relaxed)) { if(mEOS) mFinalUpdate = true; - lock.unlock(); + mPictQRead.store(read_idx, std::memory_order_release); + std::unique_lock{mPictQMutex}.unlock(); mPictQCond.notify_all(); return; } - lock.unlock(); if(updated) { + mPictQRead.store(read_idx, std::memory_order_release); + std::unique_lock{mPictQMutex}.unlock(); mPictQCond.notify_all(); /* allocate or resize the buffer! */ @@ -1282,13 +1283,12 @@ void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer) } if(mEOS.load(std::memory_order_acquire)) { - lock.lock(); - if(mPictQSize == 0) + if((read_idx+1)%mPictQ.size() == mPictQWrite.load(std::memory_order_acquire)) { mFinalUpdate = true; + std::unique_lock{mPictQMutex}.unlock(); mPictQCond.notify_all(); } - lock.unlock(); } } @@ -1305,7 +1305,9 @@ int VideoState::handler() while(!mMovie.mQuit.load(std::memory_order_relaxed)) { - Picture *vp{&mPictQ[mPictQWrite]}; + size_t write_idx{mPictQWrite.load(std::memory_order_relaxed)}; + Picture *vp{&mPictQ[write_idx]}; + { std::unique_lock lock{mPackets.getMutex()}; AVPacket *lastpkt{}; @@ -1342,19 +1344,22 @@ int VideoState::handler() /* Put the frame in the queue to be loaded into a texture and displayed * by the rendering thread. */ - std::unique_lock lock{mPictQMutex}; - mPictQWrite = (mPictQWrite+1)%mPictQ.size(); - ++mPictQSize; + write_idx = (write_idx+1)%mPictQ.size(); + mPictQWrite.store(write_idx, std::memory_order_release); - /* Wait until we have space for a new pic */ - while(mPictQSize >= (mPictQ.size()-1) && !mMovie.mQuit.load(std::memory_order_relaxed)) - mPictQCond.wait(lock); + if(write_idx == mPictQRead.load(std::memory_order_acquire)) + { + /* Wait until we have space for a new pic */ + std::unique_lock lock{mPictQMutex}; + while(write_idx == mPictQRead.load(std::memory_order_acquire) && + !mMovie.mQuit.load(std::memory_order_relaxed)) + mPictQCond.wait(lock); + } } mEOS = true; std::unique_lock lock{mPictQMutex}; - while(!mFinalUpdate) - mPictQCond.wait(lock); + while(!mFinalUpdate) mPictQCond.wait(lock); return 0; } @@ -1655,7 +1660,8 @@ int main(int argc, char *argv[]) return 1; } - { auto device = alcGetContextsDevice(alcGetCurrentContext()); + { + auto device = alcGetContextsDevice(alcGetCurrentContext()); if(alcIsExtensionPresent(device, "ALC_SOFT_device_clock")) { std::cout<< "Found ALC_SOFT_device_clock" <(movState->getDuration()); - std::cout<< "\r "< Date: Sun, 14 Jul 2019 04:05:08 -0700 Subject: Properly include getopt.h --- utils/makemhr/makemhr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/makemhr/makemhr.cpp b/utils/makemhr/makemhr.cpp index f6e28937..70ddbe5a 100644 --- a/utils/makemhr/makemhr.cpp +++ b/utils/makemhr/makemhr.cpp @@ -77,7 +77,7 @@ #ifdef HAVE_GETOPT #include #else -#include "getopt.h" +#include "../getopt.h" #endif #include -- cgit v1.2.3 From 28f07d2d5edd3578434088a681986ca303728fe3 Mon Sep 17 00:00:00 2001 From: Philip Muzzall Date: Sun, 14 Jul 2019 17:39:45 -0700 Subject: Misc fixes (#315) * Added rc scripts for dll * Reverted numbering scheme in CMakeLists * Misc fixes --- Alc/alc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 3e176957..a7b53c6b 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -2019,7 +2019,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) /* Initialize band-splitting filters for the front-left and front- * right channels, with a crossover at 5khz (could be higher). */ - const ALfloat scale{static_cast(5000.0 / device->Frequency)}; + const ALfloat scale{5000.0f / static_cast(device->Frequency)}; stablizer->LFilter.init(scale); stablizer->RFilter = stablizer->LFilter; -- cgit v1.2.3 From ee013521ee7894485e2e2a0e507de939abc38c00 Mon Sep 17 00:00:00 2001 From: Anis Date: Tue, 16 Jul 2019 17:40:18 +0200 Subject: misc fixes and improvements for Vocal Morpher --- Alc/effects/vmorpher.cpp | 258 +++++++++++++++++++++++++---------------------- 1 file changed, 136 insertions(+), 122 deletions(-) diff --git a/Alc/effects/vmorpher.cpp b/Alc/effects/vmorpher.cpp index c656a14e..72dc6aeb 100644 --- a/Alc/effects/vmorpher.cpp +++ b/Alc/effects/vmorpher.cpp @@ -22,7 +22,6 @@ #include #include - #include #include @@ -33,7 +32,6 @@ #include "alu.h" #include "vecmat.h" - namespace { #define MAX_UPDATE_SAMPLES 128 @@ -81,6 +79,9 @@ struct FormantFilter { inline void process(const ALfloat* samplesIn, ALfloat* samplesOut, const ALsizei numInput) { + /* A state variable filter from a topology-preserving transform. + * Based on a talk given by Ivan Cohen: https://www.youtube.com/watch?v=esjHXGPyrhg + */ const float g = std::tan(al::MathDefs::Pi() * f0norm); const float h = 1.0f / (1 + (g / Q_FACTOR) + (g * g)); @@ -110,11 +111,13 @@ struct FormantFilter float s2; }; + struct VmorpherState final : public EffectState { struct { - /* Effect parameters */ - FormantFilter FormantsA[NUM_FORMANTS]; - FormantFilter FormantsB[NUM_FORMANTS]; + struct { + /* Effect parameters */ + FormantFilter Formants[NUM_FORMANTS]; + } Filters[2]; /* Effect gains for each channel */ ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]{}; @@ -126,6 +129,7 @@ struct VmorpherState final : public EffectState { ALsizei mIndex{0}; ALsizei mStep{1}; + /* Effects buffers */ ALfloat mSampleBufferA[MAX_UPDATE_SAMPLES]{}; ALfloat mSampleBufferB[MAX_UPDATE_SAMPLES]{}; @@ -136,16 +140,17 @@ struct VmorpherState final : public EffectState { DEF_NEWDEL(VmorpherState) }; -ALboolean VmorpherState::deviceUpdate(const ALCdevice *UNUSED(device)) +ALboolean VmorpherState::deviceUpdate(const ALCdevice *device) { for(auto &e : mChans) { - std::for_each(std::begin(e.FormantsA), std::end(e.FormantsA), + std::for_each(std::begin(e.Filters[0].Formants), std::end(e.Filters[0].Formants), std::mem_fn(&FormantFilter::clear)); - std::for_each(std::begin(e.FormantsB), std::end(e.FormantsB), + std::for_each(std::begin(e.Filters[1].Formants), std::end(e.Filters[1].Formants), std::mem_fn(&FormantFilter::clear)); std::fill(std::begin(e.CurrentGains), std::end(e.CurrentGains), 0.0f); } + return AL_TRUE; } @@ -166,139 +171,144 @@ void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, else /*if(props->Vmorpher.Waveform == AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE)*/ mGetSamples = Oscillate; - /* Using soprano formant set of values to better match mid-range frequency space. + auto& vowelA = mChans[0].Filters[0].Formants; + auto& vowelB = mChans[0].Filters[1].Formants; + + /* Using soprano formant set of values to + * better match mid-range frequency space. + * * See: https://www.classes.cs.uchicago.edu/archive/1999/spring/CS295/Computing_Resources/Csound/CsManual3.48b1.HTML/Appendices/table3.html */ switch(props->Vmorpher.PhonemeA) { case AL_VOCAL_MORPHER_PHONEME_A: - mChans[0].FormantsA[0].f0norm = 800 / frequency; - mChans[0].FormantsA[1].f0norm = 1150 / frequency; - mChans[0].FormantsA[2].f0norm = 2900 / frequency; - mChans[0].FormantsA[3].f0norm = 3900 / frequency; - - mChans[0].FormantsA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - mChans[0].FormantsA[1].fGain = 0.501187f; /* std::pow(10.0f, -6 / 20.0f); */ - mChans[0].FormantsA[2].fGain = 0.025118f; /* std::pow(10.0f, -32 / 20.0f); */ - mChans[0].FormantsA[3].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ + vowelA[0].f0norm = 800 / frequency; + vowelA[1].f0norm = 1150 / frequency; + vowelA[2].f0norm = 2900 / frequency; + vowelA[3].f0norm = 3900 / frequency; + + vowelA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ + vowelA[1].fGain = 0.501187f; /* std::pow(10.0f, -6 / 20.0f); */ + vowelA[2].fGain = 0.025118f; /* std::pow(10.0f, -32 / 20.0f); */ + vowelA[3].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ break; case AL_VOCAL_MORPHER_PHONEME_E: - mChans[0].FormantsA[0].f0norm = 350 / frequency; - mChans[0].FormantsA[1].f0norm = 2000 / frequency; - mChans[0].FormantsA[2].f0norm = 2800 / frequency; - mChans[0].FormantsA[3].f0norm = 3600 / frequency; - - mChans[0].FormantsA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - mChans[0].FormantsA[1].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ - mChans[0].FormantsA[2].fGain = 0.177827f; /* std::pow(10.0f, -15 / 20.0f); */ - mChans[0].FormantsA[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ + vowelA[0].f0norm = 350 / frequency; + vowelA[1].f0norm = 2000 / frequency; + vowelA[2].f0norm = 2800 / frequency; + vowelA[3].f0norm = 3600 / frequency; + + vowelA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ + vowelA[1].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ + vowelA[2].fGain = 0.177827f; /* std::pow(10.0f, -15 / 20.0f); */ + vowelA[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ break; case AL_VOCAL_MORPHER_PHONEME_I: - mChans[0].FormantsA[0].f0norm = 270 / frequency; - mChans[0].FormantsA[1].f0norm = 2140 / frequency; - mChans[0].FormantsA[2].f0norm = 2950 / frequency; - mChans[0].FormantsA[3].f0norm = 3900 / frequency; - - mChans[0].FormantsA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - mChans[0].FormantsA[1].fGain = 0.251188f; /* std::pow(10.0f, -12 / 20.0f); */ - mChans[0].FormantsA[2].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ - mChans[0].FormantsA[3].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ + vowelA[0].f0norm = 270 / frequency; + vowelA[1].f0norm = 2140 / frequency; + vowelA[2].f0norm = 2950 / frequency; + vowelA[3].f0norm = 3900 / frequency; + + vowelA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ + vowelA[1].fGain = 0.251188f; /* std::pow(10.0f, -12 / 20.0f); */ + vowelA[2].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ + vowelA[3].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ break; case AL_VOCAL_MORPHER_PHONEME_O: - mChans[0].FormantsA[0].f0norm = 450 / frequency; - mChans[0].FormantsA[1].f0norm = 800 / frequency; - mChans[0].FormantsA[2].f0norm = 2830 / frequency; - mChans[0].FormantsA[3].f0norm = 3800 / frequency; - - mChans[0].FormantsA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - mChans[0].FormantsA[1].fGain = 0.281838f; /* std::pow(10.0f, -11 / 20.0f); */ - mChans[0].FormantsA[2].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ - mChans[0].FormantsA[3].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ + vowelA[0].f0norm = 450 / frequency; + vowelA[1].f0norm = 800 / frequency; + vowelA[2].f0norm = 2830 / frequency; + vowelA[3].f0norm = 3800 / frequency; + + vowelA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ + vowelA[1].fGain = 0.281838f; /* std::pow(10.0f, -11 / 20.0f); */ + vowelA[2].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ + vowelA[3].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ break; case AL_VOCAL_MORPHER_PHONEME_U: - mChans[0].FormantsA[0].f0norm = 325 / frequency; - mChans[0].FormantsA[1].f0norm = 700 / frequency; - mChans[0].FormantsA[2].f0norm = 2700 / frequency; - mChans[0].FormantsA[3].f0norm = 3800 / frequency; - - mChans[0].FormantsA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - mChans[0].FormantsA[1].fGain = 0.158489f; /* std::pow(10.0f, -16 / 20.0f); */ - mChans[0].FormantsA[2].fGain = 0.017782f; /* std::pow(10.0f, -35 / 20.0f); */ - mChans[0].FormantsA[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ + vowelA[0].f0norm = 325 / frequency; + vowelA[1].f0norm = 700 / frequency; + vowelA[2].f0norm = 2700 / frequency; + vowelA[3].f0norm = 3800 / frequency; + + vowelA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ + vowelA[1].fGain = 0.158489f; /* std::pow(10.0f, -16 / 20.0f); */ + vowelA[2].fGain = 0.017782f; /* std::pow(10.0f, -35 / 20.0f); */ + vowelA[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ break; } switch(props->Vmorpher.PhonemeB) { case AL_VOCAL_MORPHER_PHONEME_A: - mChans[0].FormantsB[0].f0norm = 800 / frequency; - mChans[0].FormantsB[1].f0norm = 1150 / frequency; - mChans[0].FormantsB[2].f0norm = 2900 / frequency; - mChans[0].FormantsB[3].f0norm = 3900 / frequency; - - mChans[0].FormantsB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - mChans[0].FormantsB[1].fGain = 0.501187f; /* std::pow(10.0f, -6 / 20.0f); */ - mChans[0].FormantsB[2].fGain = 0.025118f; /* std::pow(10.0f, -32 / 20.0f); */ - mChans[0].FormantsB[3].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ + vowelB[0].f0norm = 800 / frequency; + vowelB[1].f0norm = 1150 / frequency; + vowelB[2].f0norm = 2900 / frequency; + vowelB[3].f0norm = 3900 / frequency; + + vowelB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ + vowelB[1].fGain = 0.501187f; /* std::pow(10.0f, -6 / 20.0f); */ + vowelB[2].fGain = 0.025118f; /* std::pow(10.0f, -32 / 20.0f); */ + vowelB[3].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ break; case AL_VOCAL_MORPHER_PHONEME_E: - mChans[0].FormantsB[0].f0norm = 350 / frequency; - mChans[0].FormantsB[1].f0norm = 2000 / frequency; - mChans[0].FormantsB[2].f0norm = 2800 / frequency; - mChans[0].FormantsB[3].f0norm = 3600 / frequency; - - mChans[0].FormantsB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - mChans[0].FormantsB[1].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ - mChans[0].FormantsB[2].fGain = 0.177827f; /* std::pow(10.0f, -15 / 20.0f); */ - mChans[0].FormantsB[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ + vowelB[0].f0norm = 350 / frequency; + vowelB[1].f0norm = 2000 / frequency; + vowelB[2].f0norm = 2800 / frequency; + vowelB[3].f0norm = 3600 / frequency; + + vowelB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ + vowelB[1].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ + vowelB[2].fGain = 0.177827f; /* std::pow(10.0f, -15 / 20.0f); */ + vowelB[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ break; case AL_VOCAL_MORPHER_PHONEME_I: - mChans[0].FormantsB[0].f0norm = 270 / frequency; - mChans[0].FormantsB[1].f0norm = 2140 / frequency; - mChans[0].FormantsB[2].f0norm = 2950 / frequency; - mChans[0].FormantsB[3].f0norm = 3900 / frequency; - - mChans[0].FormantsB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - mChans[0].FormantsB[1].fGain = 0.251188f; /* std::pow(10.0f, -12 / 20.0f); */ - mChans[0].FormantsB[2].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ - mChans[0].FormantsB[3].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ + vowelB[0].f0norm = 270 / frequency; + vowelB[1].f0norm = 2140 / frequency; + vowelB[2].f0norm = 2950 / frequency; + vowelB[3].f0norm = 3900 / frequency; + + vowelB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ + vowelB[1].fGain = 0.251188f; /* std::pow(10.0f, -12 / 20.0f); */ + vowelB[2].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ + vowelB[3].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ break; case AL_VOCAL_MORPHER_PHONEME_O: - mChans[0].FormantsB[0].f0norm = 450 / frequency; - mChans[0].FormantsB[1].f0norm = 800 / frequency; - mChans[0].FormantsB[2].f0norm = 2830 / frequency; - mChans[0].FormantsB[3].f0norm = 3800 / frequency; - - mChans[0].FormantsB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - mChans[0].FormantsB[1].fGain = 0.281838f; /* std::pow(10.0f, -11 / 20.0f); */ - mChans[0].FormantsB[2].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ - mChans[0].FormantsB[3].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ + vowelB[0].f0norm = 450 / frequency; + vowelB[1].f0norm = 800 / frequency; + vowelB[2].f0norm = 2830 / frequency; + vowelB[3].f0norm = 3800 / frequency; + + vowelB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ + vowelB[1].fGain = 0.281838f; /* std::pow(10.0f, -11 / 20.0f); */ + vowelB[2].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ + vowelB[3].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ break; case AL_VOCAL_MORPHER_PHONEME_U: - mChans[0].FormantsB[0].f0norm = 325 / frequency; - mChans[0].FormantsB[1].f0norm = 700 / frequency; - mChans[0].FormantsB[2].f0norm = 2700 / frequency; - mChans[0].FormantsB[3].f0norm = 3800 / frequency; - - mChans[0].FormantsB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - mChans[0].FormantsB[1].fGain = 0.158489f; /* std::pow(10.0f, -16 / 20.0f); */ - mChans[0].FormantsB[2].fGain = 0.017782f; /* std::pow(10.0f, -35 / 20.0f); */ - mChans[0].FormantsB[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ + vowelB[0].f0norm = 325 / frequency; + vowelB[1].f0norm = 700 / frequency; + vowelB[2].f0norm = 2700 / frequency; + vowelB[3].f0norm = 3800 / frequency; + + vowelB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ + vowelB[1].fGain = 0.158489f; /* std::pow(10.0f, -16 / 20.0f); */ + vowelB[2].fGain = 0.017782f; /* std::pow(10.0f, -35 / 20.0f); */ + vowelB[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ break; } /* Copy the filter coefficients for the other input channels. */ for(ALuint i{1u};i < slot->Wet.Buffer.size();++i) { - mChans[i].FormantsA[0] = mChans[0].FormantsA[0]; - mChans[i].FormantsA[1] = mChans[0].FormantsA[0]; - mChans[i].FormantsA[2] = mChans[0].FormantsA[0]; - mChans[i].FormantsA[3] = mChans[0].FormantsA[0]; - - mChans[i].FormantsB[0] = mChans[0].FormantsB[0]; - mChans[i].FormantsB[1] = mChans[0].FormantsB[0]; - mChans[i].FormantsB[2] = mChans[0].FormantsB[0]; - mChans[i].FormantsB[3] = mChans[0].FormantsB[0]; + mChans[i].Filters[0].Formants[0] = vowelA[0]; + mChans[i].Filters[0].Formants[1] = vowelA[1]; + mChans[i].Filters[0].Formants[2] = vowelA[2]; + mChans[i].Filters[0].Formants[3] = vowelA[3]; + + mChans[i].Filters[1].Formants[0] = vowelB[0]; + mChans[i].Filters[1].Formants[1] = vowelB[1]; + mChans[i].Filters[1].Formants[2] = vowelB[2]; + mChans[i].Filters[1].Formants[3] = vowelB[3]; } mOutTarget = target.Main->Buffer; @@ -332,23 +342,27 @@ void VmorpherState::process(const ALsizei samplesToDo, const FloatBufferLine *RE mSampleBufferB[i] = 0.0f; } + auto& vowelA = mChans[c].Filters[0].Formants; + auto& vowelB = mChans[c].Filters[1].Formants; + /* Process first vowel. */ - mChans[c].FormantsA[0].process(&samplesIn[c][base], mSampleBufferA, td); - mChans[c].FormantsA[1].process(&samplesIn[c][base], mSampleBufferA, td); - mChans[c].FormantsA[2].process(&samplesIn[c][base], mSampleBufferA, td); - mChans[c].FormantsA[3].process(&samplesIn[c][base], mSampleBufferA, td); + vowelA[0].process(&samplesIn[c][base], mSampleBufferA, td); + vowelA[1].process(&samplesIn[c][base], mSampleBufferA, td); + vowelA[2].process(&samplesIn[c][base], mSampleBufferA, td); + vowelA[3].process(&samplesIn[c][base], mSampleBufferA, td); /* Process second vowel. */ - mChans[c].FormantsB[0].process(&samplesIn[c][base], mSampleBufferB, td); - mChans[c].FormantsB[1].process(&samplesIn[c][base], mSampleBufferB, td); - mChans[c].FormantsB[2].process(&samplesIn[c][base], mSampleBufferB, td); - mChans[c].FormantsB[3].process(&samplesIn[c][base], mSampleBufferB, td); + vowelB[0].process(&samplesIn[c][base], mSampleBufferB, td); + vowelB[1].process(&samplesIn[c][base], mSampleBufferB, td); + vowelB[2].process(&samplesIn[c][base], mSampleBufferB, td); + vowelB[3].process(&samplesIn[c][base], mSampleBufferB, td); alignas(16) ALfloat samplesBlended[MAX_UPDATE_SAMPLES]; for (ALsizei i{0};i < td;i++) samplesBlended[i] = lerp(mSampleBufferA[i], mSampleBufferB[i], lfo[i]); + /* Now, mix the processed sound data to the output. */ MixSamples(samplesBlended, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, samplesToDo-base, base, td); } @@ -363,31 +377,31 @@ void Vmorpher_setParami(EffectProps* props, ALCcontext *context, ALenum param, A switch(param) { case AL_VOCAL_MORPHER_WAVEFORM: - if(val < AL_VOCAL_MORPHER_MIN_WAVEFORM || val > AL_VOCAL_MORPHER_MAX_WAVEFORM) + if(!(val >= AL_VOCAL_MORPHER_MIN_WAVEFORM && val <= AL_VOCAL_MORPHER_MAX_WAVEFORM)) SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher waveform out of range"); props->Vmorpher.Waveform = val; break; case AL_VOCAL_MORPHER_PHONEMEA: - if(val < AL_VOCAL_MORPHER_MIN_PHONEMEA || val > AL_VOCAL_MORPHER_MAX_PHONEMEA) + if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEA && val <= AL_VOCAL_MORPHER_MAX_PHONEMEA)) SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher phoneme-a out of range"); props->Vmorpher.PhonemeA = val; break; case AL_VOCAL_MORPHER_PHONEMEB: - if(val < AL_VOCAL_MORPHER_MIN_PHONEMEB || val > AL_VOCAL_MORPHER_MAX_PHONEMEB) + if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEB && val <= AL_VOCAL_MORPHER_MAX_PHONEMEB)) SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher phoneme-b out of range"); props->Vmorpher.PhonemeB = val; break; case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING: - if(val < AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING || val > AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING) + if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING)) SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher phoneme-a coarse tuning out of range"); props->Vmorpher.PhonemeACoarseTuning = val; break; case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING: - if(val < AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING || val > AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING) + if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING)) SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher phoneme-b coarse tuning out of range"); props->Vmorpher.PhonemeBCoarseTuning = val; break; @@ -403,7 +417,7 @@ void Vmorpher_setParamf(EffectProps *props, ALCcontext *context, ALenum param, A switch(param) { case AL_VOCAL_MORPHER_RATE: - if(val < AL_VOCAL_MORPHER_MIN_RATE || val > AL_VOCAL_MORPHER_MAX_RATE) + if(!(val >= AL_VOCAL_MORPHER_MIN_RATE && val <= AL_VOCAL_MORPHER_MAX_RATE)) SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher rate out of range"); props->Vmorpher.Rate = val; break; -- cgit v1.2.3 From ffc7258cbcce7db603dcc5978020f042d3f7ebf7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 Jul 2019 06:03:35 -0700 Subject: Remove an unused lambda capture --- OpenAL32/alSource.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index c3866d1f..498875bf 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -2770,7 +2770,7 @@ START_API_FUNC { /* TODO: Send state change event? */ std::for_each(srchandles, srchandles+n, - [&context](ALsource *source) -> void + [](ALsource *source) -> void { source->OffsetType = AL_NONE; source->Offset = 0.0; -- cgit v1.2.3 From 101e6412887c539b7409fdb016012900c18f5daf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Jul 2019 16:19:51 -0700 Subject: Fix an unused parameter warning --- Alc/effects/vmorpher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/effects/vmorpher.cpp b/Alc/effects/vmorpher.cpp index 72dc6aeb..b6b13f0d 100644 --- a/Alc/effects/vmorpher.cpp +++ b/Alc/effects/vmorpher.cpp @@ -140,7 +140,7 @@ struct VmorpherState final : public EffectState { DEF_NEWDEL(VmorpherState) }; -ALboolean VmorpherState::deviceUpdate(const ALCdevice *device) +ALboolean VmorpherState::deviceUpdate(const ALCdevice* /*device*/) { for(auto &e : mChans) { -- cgit v1.2.3 From 2b21a08f89bbf5ccff935ada6b5bbe42501f18c4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Jul 2019 20:20:25 -0700 Subject: Receive video frames in a loop --- examples/alffplay.cpp | 90 ++++++++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 40 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index ccdfd51f..466c4576 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -552,19 +552,21 @@ int AudioState::decodeFrame() AVPacket *lastpkt{}; while((lastpkt=mPackets.getPacket(lock)) != nullptr) { - int ret{avcodec_send_packet(mCodecCtx.get(), lastpkt)}; + const int ret{avcodec_send_packet(mCodecCtx.get(), lastpkt)}; if(ret == AVERROR(EAGAIN)) break; + if(ret < 0) + std::cerr<< "Failed to send packet: "<nb_samples <= 0) @@ -1179,7 +1181,7 @@ void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer) mFinalUpdate = true; mPictQRead.store(read_idx, std::memory_order_release); std::unique_lock{mPictQMutex}.unlock(); - mPictQCond.notify_all(); + mPictQCond.notify_one(); return; } @@ -1187,7 +1189,7 @@ void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer) { mPictQRead.store(read_idx, std::memory_order_release); std::unique_lock{mPictQMutex}.unlock(); - mPictQCond.notify_all(); + mPictQCond.notify_one(); /* allocate or resize the buffer! */ bool fmt_updated{false}; @@ -1287,7 +1289,7 @@ void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer) { mFinalUpdate = true; std::unique_lock{mPictQMutex}.unlock(); - mPictQCond.notify_all(); + mPictQCond.notify_one(); } } } @@ -1305,57 +1307,65 @@ int VideoState::handler() while(!mMovie.mQuit.load(std::memory_order_relaxed)) { - size_t write_idx{mPictQWrite.load(std::memory_order_relaxed)}; - Picture *vp{&mPictQ[write_idx]}; - { std::unique_lock lock{mPackets.getMutex()}; AVPacket *lastpkt{}; while((lastpkt=mPackets.getPacket(lock)) != nullptr) { - int ret{avcodec_send_packet(mCodecCtx.get(), lastpkt)}; + const int ret{avcodec_send_packet(mCodecCtx.get(), lastpkt)}; if(ret == AVERROR(EAGAIN)) break; + if(ret < 0) + std::cerr<< "Failed to send packet: "<mFrame.get()}; - int ret{avcodec_receive_frame(mCodecCtx.get(), decoded_frame)}; - if(ret == AVERROR_EOF) break; - if(ret < 0) + + while(!mMovie.mQuit.load(std::memory_order_relaxed)) { - std::cerr<< "Failed to decode frame: "<mFrame.get()}; + const int ret{avcodec_receive_frame(mCodecCtx.get(), decoded_frame)}; + if(ret == AVERROR_EOF) goto finished; + if(ret == AVERROR(EAGAIN)) break; + if(ret < 0) + { + std::cerr<< "Failed to receive frame: "<best_effort_timestamp != AV_NOPTS_VALUE) - mCurrentPts = std::chrono::duration_cast( - seconds_d64{av_q2d(mStream->time_base)*decoded_frame->best_effort_timestamp}); - vp->mPts = mCurrentPts; + /* Get the PTS for this frame. */ + if(decoded_frame->best_effort_timestamp != AV_NOPTS_VALUE) + mCurrentPts = std::chrono::duration_cast( + seconds_d64{av_q2d(mStream->time_base)*decoded_frame->best_effort_timestamp}); + vp->mPts = mCurrentPts; - /* Update the video clock to the next expected PTS. */ - auto frame_delay = av_q2d(mCodecCtx->time_base); - frame_delay += decoded_frame->repeat_pict * (frame_delay * 0.5); - mCurrentPts += std::chrono::duration_cast(seconds_d64{frame_delay}); + /* Update the video clock to the next expected PTS. */ + auto frame_delay = av_q2d(mCodecCtx->time_base); + frame_delay += decoded_frame->repeat_pict * (frame_delay * 0.5); + mCurrentPts += std::chrono::duration_cast(seconds_d64{frame_delay}); - /* Put the frame in the queue to be loaded into a texture and displayed - * by the rendering thread. - */ - write_idx = (write_idx+1)%mPictQ.size(); - mPictQWrite.store(write_idx, std::memory_order_release); + /* Put the frame in the queue to be loaded into a texture and + * displayed by the rendering thread. + */ + write_idx = (write_idx+1)%mPictQ.size(); + mPictQWrite.store(write_idx, std::memory_order_release); - if(write_idx == mPictQRead.load(std::memory_order_acquire)) - { - /* Wait until we have space for a new pic */ - std::unique_lock lock{mPictQMutex}; - while(write_idx == mPictQRead.load(std::memory_order_acquire) && - !mMovie.mQuit.load(std::memory_order_relaxed)) - mPictQCond.wait(lock); + if(write_idx == mPictQRead.load(std::memory_order_acquire)) + { + /* Wait until we have space for a new pic */ + std::unique_lock lock{mPictQMutex}; + while(write_idx == mPictQRead.load(std::memory_order_acquire) && + !mMovie.mQuit.load(std::memory_order_relaxed)) + mPictQCond.wait(lock); + } } } +finished: mEOS = true; std::unique_lock lock{mPictQMutex}; -- cgit v1.2.3 From 31055f48d68820b6db53917c60aed99a29856891 Mon Sep 17 00:00:00 2001 From: Anis Date: Thu, 18 Jul 2019 21:42:59 +0200 Subject: pitch shift for formant filters --- Alc/effects/vmorpher.cpp | 161 ++++++++++++++++++++++++----------------------- 1 file changed, 82 insertions(+), 79 deletions(-) diff --git a/Alc/effects/vmorpher.cpp b/Alc/effects/vmorpher.cpp index b6b13f0d..5fb7a269 100644 --- a/Alc/effects/vmorpher.cpp +++ b/Alc/effects/vmorpher.cpp @@ -30,13 +30,16 @@ #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" -#include "vecmat.h" namespace { #define MAX_UPDATE_SAMPLES 128 -#define Q_FACTOR 5.0f -#define NUM_FORMANTS 4 +#define NUM_FORMANTS 4 +#define NUM_FILTERS 2 +#define Q_FACTOR 5.0f + +#define VOWEL_A_INDEX 0 +#define VOWEL_B_INDEX 1 #define WAVEFORM_FRACBITS 24 #define WAVEFORM_FRACONE (1<::Pi() * f0norm); - const float h = 1.0f / (1 + (g / Q_FACTOR) + (g * g)); + const ALfloat g = std::tan(al::MathDefs::Pi() * f0norm); + const ALfloat h = 1.0f / (1 + (g / Q_FACTOR) + (g * g)); for (ALsizei i{0};i < numInput;i++) { - const float H = h * (samplesIn[i] - (1.0f / Q_FACTOR + g) * s1 - s2); - const float B = g * H + s1; - const float L = g * B + s2; + const ALfloat H = h * (samplesIn[i] - (1.0f / Q_FACTOR + g) * s1 - s2); + const ALfloat B = g * H + s1; + const ALfloat L = g * B + s2; s1 = g * H + B; s2 = g * B + L; @@ -105,19 +108,17 @@ struct FormantFilter s2 = 0.0f; } - float f0norm; - float fGain; - float s1; - float s2; + ALfloat f0norm; + ALfloat fGain; + ALfloat s1; + ALfloat s2; }; struct VmorpherState final : public EffectState { struct { - struct { - /* Effect parameters */ - FormantFilter Formants[NUM_FORMANTS]; - } Filters[2]; + /* Effect parameters */ + FormantFilter Formants[NUM_FILTERS][NUM_FORMANTS]; /* Effect gains for each channel */ ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]{}; @@ -144,9 +145,9 @@ ALboolean VmorpherState::deviceUpdate(const ALCdevice* /*device*/) { for(auto &e : mChans) { - std::for_each(std::begin(e.Filters[0].Formants), std::end(e.Filters[0].Formants), + std::for_each(std::begin(e.Formants[VOWEL_A_INDEX]), std::end(e.Formants[VOWEL_A_INDEX]), std::mem_fn(&FormantFilter::clear)); - std::for_each(std::begin(e.Filters[1].Formants), std::end(e.Filters[1].Formants), + std::for_each(std::begin(e.Formants[VOWEL_B_INDEX]), std::end(e.Formants[VOWEL_B_INDEX]), std::mem_fn(&FormantFilter::clear)); std::fill(std::begin(e.CurrentGains), std::end(e.CurrentGains), 0.0f); } @@ -156,10 +157,9 @@ ALboolean VmorpherState::deviceUpdate(const ALCdevice* /*device*/) void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { - const ALCdevice *device = context->Device; - const ALfloat frequency = static_cast(device->Frequency); - - const float step{props->Vmorpher.Rate / static_cast(device->Frequency)}; + const ALCdevice *device{context->Device}; + const ALfloat frequency{static_cast(device->Frequency)}; + const ALfloat step{props->Vmorpher.Rate / static_cast(device->Frequency)}; mStep = fastf2i(clampf(step*WAVEFORM_FRACONE, 0.0f, ALfloat{WAVEFORM_FRACONE-1})); if(mStep == 0) @@ -171,8 +171,11 @@ void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, else /*if(props->Vmorpher.Waveform == AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE)*/ mGetSamples = Oscillate; - auto& vowelA = mChans[0].Filters[0].Formants; - auto& vowelB = mChans[0].Filters[1].Formants; + auto& vowelA = mChans[0].Formants[VOWEL_A_INDEX]; + auto& vowelB = mChans[0].Formants[VOWEL_B_INDEX]; + + const ALfloat pitchA{fastf2i(std::pow(2.0f, props->Vmorpher.PhonemeACoarseTuning*100.0f / 2400.0f)*FRACTIONONE) * (1.0f/FRACTIONONE)}; + const ALfloat pitchB{fastf2i(std::pow(2.0f, props->Vmorpher.PhonemeBCoarseTuning*100.0f / 2400.0f)*FRACTIONONE) * (1.0f/FRACTIONONE)}; /* Using soprano formant set of values to * better match mid-range frequency space. @@ -182,10 +185,10 @@ void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, switch(props->Vmorpher.PhonemeA) { case AL_VOCAL_MORPHER_PHONEME_A: - vowelA[0].f0norm = 800 / frequency; - vowelA[1].f0norm = 1150 / frequency; - vowelA[2].f0norm = 2900 / frequency; - vowelA[3].f0norm = 3900 / frequency; + vowelA[0].f0norm = (800 * pitchA) / frequency; + vowelA[1].f0norm = (1150 * pitchA) / frequency; + vowelA[2].f0norm = (2900 * pitchA) / frequency; + vowelA[3].f0norm = (3900 * pitchA) / frequency; vowelA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ vowelA[1].fGain = 0.501187f; /* std::pow(10.0f, -6 / 20.0f); */ @@ -193,10 +196,10 @@ void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, vowelA[3].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ break; case AL_VOCAL_MORPHER_PHONEME_E: - vowelA[0].f0norm = 350 / frequency; - vowelA[1].f0norm = 2000 / frequency; - vowelA[2].f0norm = 2800 / frequency; - vowelA[3].f0norm = 3600 / frequency; + vowelA[0].f0norm = (350 * pitchA) / frequency; + vowelA[1].f0norm = (2000 * pitchA) / frequency; + vowelA[2].f0norm = (2800 * pitchA) / frequency; + vowelA[3].f0norm = (3600 * pitchA) / frequency; vowelA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ vowelA[1].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ @@ -204,10 +207,10 @@ void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, vowelA[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ break; case AL_VOCAL_MORPHER_PHONEME_I: - vowelA[0].f0norm = 270 / frequency; - vowelA[1].f0norm = 2140 / frequency; - vowelA[2].f0norm = 2950 / frequency; - vowelA[3].f0norm = 3900 / frequency; + vowelA[0].f0norm = (270 * pitchA) / frequency; + vowelA[1].f0norm = (2140 * pitchA) / frequency; + vowelA[2].f0norm = (2950 * pitchA) / frequency; + vowelA[3].f0norm = (3900 * pitchA) / frequency; vowelA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ vowelA[1].fGain = 0.251188f; /* std::pow(10.0f, -12 / 20.0f); */ @@ -215,10 +218,10 @@ void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, vowelA[3].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ break; case AL_VOCAL_MORPHER_PHONEME_O: - vowelA[0].f0norm = 450 / frequency; - vowelA[1].f0norm = 800 / frequency; - vowelA[2].f0norm = 2830 / frequency; - vowelA[3].f0norm = 3800 / frequency; + vowelA[0].f0norm = (450 * pitchA) / frequency; + vowelA[1].f0norm = (800 * pitchA) / frequency; + vowelA[2].f0norm = (2830 * pitchA) / frequency; + vowelA[3].f0norm = (3800 * pitchA) / frequency; vowelA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ vowelA[1].fGain = 0.281838f; /* std::pow(10.0f, -11 / 20.0f); */ @@ -226,10 +229,10 @@ void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, vowelA[3].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ break; case AL_VOCAL_MORPHER_PHONEME_U: - vowelA[0].f0norm = 325 / frequency; - vowelA[1].f0norm = 700 / frequency; - vowelA[2].f0norm = 2700 / frequency; - vowelA[3].f0norm = 3800 / frequency; + vowelA[0].f0norm = (325 * pitchA) / frequency; + vowelA[1].f0norm = (700 * pitchA) / frequency; + vowelA[2].f0norm = (2700 * pitchA) / frequency; + vowelA[3].f0norm = (3800 * pitchA) / frequency; vowelA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ vowelA[1].fGain = 0.158489f; /* std::pow(10.0f, -16 / 20.0f); */ @@ -241,10 +244,10 @@ void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, switch(props->Vmorpher.PhonemeB) { case AL_VOCAL_MORPHER_PHONEME_A: - vowelB[0].f0norm = 800 / frequency; - vowelB[1].f0norm = 1150 / frequency; - vowelB[2].f0norm = 2900 / frequency; - vowelB[3].f0norm = 3900 / frequency; + vowelB[0].f0norm = (800 * pitchB) / frequency; + vowelB[1].f0norm = (1150 * pitchB) / frequency; + vowelB[2].f0norm = (2900 * pitchB) / frequency; + vowelB[3].f0norm = (3900 * pitchB) / frequency; vowelB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ vowelB[1].fGain = 0.501187f; /* std::pow(10.0f, -6 / 20.0f); */ @@ -252,10 +255,10 @@ void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, vowelB[3].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ break; case AL_VOCAL_MORPHER_PHONEME_E: - vowelB[0].f0norm = 350 / frequency; - vowelB[1].f0norm = 2000 / frequency; - vowelB[2].f0norm = 2800 / frequency; - vowelB[3].f0norm = 3600 / frequency; + vowelB[0].f0norm = (350 * pitchB) / frequency; + vowelB[1].f0norm = (2000 * pitchB) / frequency; + vowelB[2].f0norm = (2800 * pitchB) / frequency; + vowelB[3].f0norm = (3600 * pitchB) / frequency; vowelB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ vowelB[1].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ @@ -263,10 +266,10 @@ void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, vowelB[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ break; case AL_VOCAL_MORPHER_PHONEME_I: - vowelB[0].f0norm = 270 / frequency; - vowelB[1].f0norm = 2140 / frequency; - vowelB[2].f0norm = 2950 / frequency; - vowelB[3].f0norm = 3900 / frequency; + vowelB[0].f0norm = (270 * pitchB) / frequency; + vowelB[1].f0norm = (2140 * pitchB) / frequency; + vowelB[2].f0norm = (2950 * pitchB) / frequency; + vowelB[3].f0norm = (3900 * pitchB) / frequency; vowelB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ vowelB[1].fGain = 0.251188f; /* std::pow(10.0f, -12 / 20.0f); */ @@ -274,10 +277,10 @@ void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, vowelB[3].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ break; case AL_VOCAL_MORPHER_PHONEME_O: - vowelB[0].f0norm = 450 / frequency; - vowelB[1].f0norm = 800 / frequency; - vowelB[2].f0norm = 2830 / frequency; - vowelB[3].f0norm = 3800 / frequency; + vowelB[0].f0norm = (450 * pitchB) / frequency; + vowelB[1].f0norm = (800 * pitchB) / frequency; + vowelB[2].f0norm = (2830 * pitchB) / frequency; + vowelB[3].f0norm = (3800 * pitchB) / frequency; vowelB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ vowelB[1].fGain = 0.281838f; /* std::pow(10.0f, -11 / 20.0f); */ @@ -285,10 +288,10 @@ void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, vowelB[3].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ break; case AL_VOCAL_MORPHER_PHONEME_U: - vowelB[0].f0norm = 325 / frequency; - vowelB[1].f0norm = 700 / frequency; - vowelB[2].f0norm = 2700 / frequency; - vowelB[3].f0norm = 3800 / frequency; + vowelB[0].f0norm = (325 * pitchB) / frequency; + vowelB[1].f0norm = (700 * pitchB) / frequency; + vowelB[2].f0norm = (2700 * pitchB) / frequency; + vowelB[3].f0norm = (3800 * pitchB) / frequency; vowelB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ vowelB[1].fGain = 0.158489f; /* std::pow(10.0f, -16 / 20.0f); */ @@ -300,15 +303,15 @@ void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, /* Copy the filter coefficients for the other input channels. */ for(ALuint i{1u};i < slot->Wet.Buffer.size();++i) { - mChans[i].Filters[0].Formants[0] = vowelA[0]; - mChans[i].Filters[0].Formants[1] = vowelA[1]; - mChans[i].Filters[0].Formants[2] = vowelA[2]; - mChans[i].Filters[0].Formants[3] = vowelA[3]; - - mChans[i].Filters[1].Formants[0] = vowelB[0]; - mChans[i].Filters[1].Formants[1] = vowelB[1]; - mChans[i].Filters[1].Formants[2] = vowelB[2]; - mChans[i].Filters[1].Formants[3] = vowelB[3]; + mChans[i].Formants[VOWEL_A_INDEX][0] = vowelA[0]; + mChans[i].Formants[VOWEL_A_INDEX][1] = vowelA[1]; + mChans[i].Formants[VOWEL_A_INDEX][2] = vowelA[2]; + mChans[i].Formants[VOWEL_A_INDEX][3] = vowelA[3]; + + mChans[i].Formants[VOWEL_B_INDEX][0] = vowelB[0]; + mChans[i].Formants[VOWEL_B_INDEX][1] = vowelB[1]; + mChans[i].Formants[VOWEL_B_INDEX][2] = vowelB[2]; + mChans[i].Formants[VOWEL_B_INDEX][3] = vowelB[3]; } mOutTarget = target.Main->Buffer; @@ -342,8 +345,8 @@ void VmorpherState::process(const ALsizei samplesToDo, const FloatBufferLine *RE mSampleBufferB[i] = 0.0f; } - auto& vowelA = mChans[c].Filters[0].Formants; - auto& vowelB = mChans[c].Filters[1].Formants; + auto& vowelA = mChans[c].Formants[VOWEL_A_INDEX]; + auto& vowelB = mChans[c].Formants[VOWEL_B_INDEX]; /* Process first vowel. */ vowelA[0].process(&samplesIn[c][base], mSampleBufferA, td); @@ -486,12 +489,12 @@ struct VmorpherStateFactory final : public EffectStateFactory { EffectProps VmorpherStateFactory::getDefaultProps() const noexcept { EffectProps props{}; - props.Vmorpher.Rate = AL_VOCAL_MORPHER_DEFAULT_RATE; - props.Vmorpher.PhonemeA = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA; - props.Vmorpher.PhonemeB = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB; + props.Vmorpher.Rate = AL_VOCAL_MORPHER_DEFAULT_RATE; + props.Vmorpher.PhonemeA = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA; + props.Vmorpher.PhonemeB = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB; props.Vmorpher.PhonemeACoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING; props.Vmorpher.PhonemeBCoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING; - props.Vmorpher.Waveform = AL_VOCAL_MORPHER_DEFAULT_WAVEFORM; + props.Vmorpher.Waveform = AL_VOCAL_MORPHER_DEFAULT_WAVEFORM; return props; } -- cgit v1.2.3 From 29cf87f34d67cf73307d0ec5d61c14b520fcdc1c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 18 Jul 2019 16:04:45 -0700 Subject: Combine duplicate code into a function --- Alc/effects/vmorpher.cpp | 208 +++++++++++++++-------------------------------- 1 file changed, 66 insertions(+), 142 deletions(-) diff --git a/Alc/effects/vmorpher.cpp b/Alc/effects/vmorpher.cpp index 5fb7a269..dc402aaf 100644 --- a/Alc/effects/vmorpher.cpp +++ b/Alc/effects/vmorpher.cpp @@ -80,6 +80,14 @@ void Oscillate(ALfloat *RESTRICT dst, ALsizei index, const ALsizei step, ALsizei struct FormantFilter { + ALfloat f0norm{0.0f}; + ALfloat fGain{1.0f}; + ALfloat s1{0.0f}; + ALfloat s2{0.0f}; + + FormantFilter() = default; + FormantFilter(ALfloat f0norm_, ALfloat gain) : f0norm{f0norm_}, fGain{gain} { } + inline void process(const ALfloat* samplesIn, ALfloat* samplesOut, const ALsizei numInput) { /* A state variable filter from a topology-preserving transform. @@ -107,11 +115,6 @@ struct FormantFilter s1 = 0.0f; s2 = 0.0f; } - - ALfloat f0norm; - ALfloat fGain; - ALfloat s1; - ALfloat s2; }; @@ -138,9 +141,60 @@ struct VmorpherState final : public EffectState { void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + static std::array getFiltersByPhoneme(ALenum phoneme, ALfloat frequency, ALfloat pitch); + DEF_NEWDEL(VmorpherState) }; +std::array VmorpherState::getFiltersByPhoneme(ALenum phoneme, ALfloat frequency, ALfloat pitch) +{ + /* Using soprano formant set of values to + * better match mid-range frequency space. + * + * See: https://www.classes.cs.uchicago.edu/archive/1999/spring/CS295/Computing_Resources/Csound/CsManual3.48b1.HTML/Appendices/table3.html + */ + switch(phoneme) + { + case AL_VOCAL_MORPHER_PHONEME_A: + return {{ + {( 800 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ + {(1150 * pitch) / frequency, 0.501187f}, /* std::pow(10.0f, -6 / 20.0f); */ + {(2900 * pitch) / frequency, 0.025118f}, /* std::pow(10.0f, -32 / 20.0f); */ + {(3900 * pitch) / frequency, 0.100000f} /* std::pow(10.0f, -20 / 20.0f); */ + }}; + case AL_VOCAL_MORPHER_PHONEME_E: + return {{ + {( 350 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ + {(2000 * pitch) / frequency, 0.100000f}, /* std::pow(10.0f, -20 / 20.0f); */ + {(2800 * pitch) / frequency, 0.177827f}, /* std::pow(10.0f, -15 / 20.0f); */ + {(3600 * pitch) / frequency, 0.009999f} /* std::pow(10.0f, -40 / 20.0f); */ + }}; + case AL_VOCAL_MORPHER_PHONEME_I: + return {{ + {( 270 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ + {(2140 * pitch) / frequency, 0.251188f}, /* std::pow(10.0f, -12 / 20.0f); */ + {(2950 * pitch) / frequency, 0.050118f}, /* std::pow(10.0f, -26 / 20.0f); */ + {(3900 * pitch) / frequency, 0.050118f} /* std::pow(10.0f, -26 / 20.0f); */ + }}; + case AL_VOCAL_MORPHER_PHONEME_O: + return {{ + {( 450 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ + {( 800 * pitch) / frequency, 0.281838f}, /* std::pow(10.0f, -11 / 20.0f); */ + {(2830 * pitch) / frequency, 0.079432f}, /* std::pow(10.0f, -22 / 20.0f); */ + {(3800 * pitch) / frequency, 0.079432f} /* std::pow(10.0f, -22 / 20.0f); */ + }}; + case AL_VOCAL_MORPHER_PHONEME_U: + return {{ + {( 325 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ + {( 700 * pitch) / frequency, 0.158489f}, /* std::pow(10.0f, -16 / 20.0f); */ + {(2700 * pitch) / frequency, 0.017782f}, /* std::pow(10.0f, -35 / 20.0f); */ + {(3800 * pitch) / frequency, 0.009999f} /* std::pow(10.0f, -40 / 20.0f); */ + }}; + } + return {}; +} + + ALboolean VmorpherState::deviceUpdate(const ALCdevice* /*device*/) { for(auto &e : mChans) @@ -171,151 +225,21 @@ void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, else /*if(props->Vmorpher.Waveform == AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE)*/ mGetSamples = Oscillate; - auto& vowelA = mChans[0].Formants[VOWEL_A_INDEX]; - auto& vowelB = mChans[0].Formants[VOWEL_B_INDEX]; - const ALfloat pitchA{fastf2i(std::pow(2.0f, props->Vmorpher.PhonemeACoarseTuning*100.0f / 2400.0f)*FRACTIONONE) * (1.0f/FRACTIONONE)}; const ALfloat pitchB{fastf2i(std::pow(2.0f, props->Vmorpher.PhonemeBCoarseTuning*100.0f / 2400.0f)*FRACTIONONE) * (1.0f/FRACTIONONE)}; - /* Using soprano formant set of values to - * better match mid-range frequency space. - * - * See: https://www.classes.cs.uchicago.edu/archive/1999/spring/CS295/Computing_Resources/Csound/CsManual3.48b1.HTML/Appendices/table3.html - */ - switch(props->Vmorpher.PhonemeA) - { - case AL_VOCAL_MORPHER_PHONEME_A: - vowelA[0].f0norm = (800 * pitchA) / frequency; - vowelA[1].f0norm = (1150 * pitchA) / frequency; - vowelA[2].f0norm = (2900 * pitchA) / frequency; - vowelA[3].f0norm = (3900 * pitchA) / frequency; - - vowelA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - vowelA[1].fGain = 0.501187f; /* std::pow(10.0f, -6 / 20.0f); */ - vowelA[2].fGain = 0.025118f; /* std::pow(10.0f, -32 / 20.0f); */ - vowelA[3].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ - break; - case AL_VOCAL_MORPHER_PHONEME_E: - vowelA[0].f0norm = (350 * pitchA) / frequency; - vowelA[1].f0norm = (2000 * pitchA) / frequency; - vowelA[2].f0norm = (2800 * pitchA) / frequency; - vowelA[3].f0norm = (3600 * pitchA) / frequency; - - vowelA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - vowelA[1].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ - vowelA[2].fGain = 0.177827f; /* std::pow(10.0f, -15 / 20.0f); */ - vowelA[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ - break; - case AL_VOCAL_MORPHER_PHONEME_I: - vowelA[0].f0norm = (270 * pitchA) / frequency; - vowelA[1].f0norm = (2140 * pitchA) / frequency; - vowelA[2].f0norm = (2950 * pitchA) / frequency; - vowelA[3].f0norm = (3900 * pitchA) / frequency; - - vowelA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - vowelA[1].fGain = 0.251188f; /* std::pow(10.0f, -12 / 20.0f); */ - vowelA[2].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ - vowelA[3].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ - break; - case AL_VOCAL_MORPHER_PHONEME_O: - vowelA[0].f0norm = (450 * pitchA) / frequency; - vowelA[1].f0norm = (800 * pitchA) / frequency; - vowelA[2].f0norm = (2830 * pitchA) / frequency; - vowelA[3].f0norm = (3800 * pitchA) / frequency; - - vowelA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - vowelA[1].fGain = 0.281838f; /* std::pow(10.0f, -11 / 20.0f); */ - vowelA[2].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ - vowelA[3].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ - break; - case AL_VOCAL_MORPHER_PHONEME_U: - vowelA[0].f0norm = (325 * pitchA) / frequency; - vowelA[1].f0norm = (700 * pitchA) / frequency; - vowelA[2].f0norm = (2700 * pitchA) / frequency; - vowelA[3].f0norm = (3800 * pitchA) / frequency; - - vowelA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - vowelA[1].fGain = 0.158489f; /* std::pow(10.0f, -16 / 20.0f); */ - vowelA[2].fGain = 0.017782f; /* std::pow(10.0f, -35 / 20.0f); */ - vowelA[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ - break; - } - - switch(props->Vmorpher.PhonemeB) - { - case AL_VOCAL_MORPHER_PHONEME_A: - vowelB[0].f0norm = (800 * pitchB) / frequency; - vowelB[1].f0norm = (1150 * pitchB) / frequency; - vowelB[2].f0norm = (2900 * pitchB) / frequency; - vowelB[3].f0norm = (3900 * pitchB) / frequency; - - vowelB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - vowelB[1].fGain = 0.501187f; /* std::pow(10.0f, -6 / 20.0f); */ - vowelB[2].fGain = 0.025118f; /* std::pow(10.0f, -32 / 20.0f); */ - vowelB[3].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ - break; - case AL_VOCAL_MORPHER_PHONEME_E: - vowelB[0].f0norm = (350 * pitchB) / frequency; - vowelB[1].f0norm = (2000 * pitchB) / frequency; - vowelB[2].f0norm = (2800 * pitchB) / frequency; - vowelB[3].f0norm = (3600 * pitchB) / frequency; - - vowelB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - vowelB[1].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ - vowelB[2].fGain = 0.177827f; /* std::pow(10.0f, -15 / 20.0f); */ - vowelB[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ - break; - case AL_VOCAL_MORPHER_PHONEME_I: - vowelB[0].f0norm = (270 * pitchB) / frequency; - vowelB[1].f0norm = (2140 * pitchB) / frequency; - vowelB[2].f0norm = (2950 * pitchB) / frequency; - vowelB[3].f0norm = (3900 * pitchB) / frequency; - - vowelB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - vowelB[1].fGain = 0.251188f; /* std::pow(10.0f, -12 / 20.0f); */ - vowelB[2].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ - vowelB[3].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ - break; - case AL_VOCAL_MORPHER_PHONEME_O: - vowelB[0].f0norm = (450 * pitchB) / frequency; - vowelB[1].f0norm = (800 * pitchB) / frequency; - vowelB[2].f0norm = (2830 * pitchB) / frequency; - vowelB[3].f0norm = (3800 * pitchB) / frequency; - - vowelB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - vowelB[1].fGain = 0.281838f; /* std::pow(10.0f, -11 / 20.0f); */ - vowelB[2].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ - vowelB[3].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ - break; - case AL_VOCAL_MORPHER_PHONEME_U: - vowelB[0].f0norm = (325 * pitchB) / frequency; - vowelB[1].f0norm = (700 * pitchB) / frequency; - vowelB[2].f0norm = (2700 * pitchB) / frequency; - vowelB[3].f0norm = (3800 * pitchB) / frequency; - - vowelB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - vowelB[1].fGain = 0.158489f; /* std::pow(10.0f, -16 / 20.0f); */ - vowelB[2].fGain = 0.017782f; /* std::pow(10.0f, -35 / 20.0f); */ - vowelB[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ - break; - } + auto vowelA = getFiltersByPhoneme(props->Vmorpher.PhonemeA, frequency, pitchA); + auto vowelB = getFiltersByPhoneme(props->Vmorpher.PhonemeB, frequency, pitchB); - /* Copy the filter coefficients for the other input channels. */ - for(ALuint i{1u};i < slot->Wet.Buffer.size();++i) + /* Copy the filter coefficients to the input channels. */ + for(size_t i{0u};i < slot->Wet.Buffer.size();++i) { - mChans[i].Formants[VOWEL_A_INDEX][0] = vowelA[0]; - mChans[i].Formants[VOWEL_A_INDEX][1] = vowelA[1]; - mChans[i].Formants[VOWEL_A_INDEX][2] = vowelA[2]; - mChans[i].Formants[VOWEL_A_INDEX][3] = vowelA[3]; - - mChans[i].Formants[VOWEL_B_INDEX][0] = vowelB[0]; - mChans[i].Formants[VOWEL_B_INDEX][1] = vowelB[1]; - mChans[i].Formants[VOWEL_B_INDEX][2] = vowelB[2]; - mChans[i].Formants[VOWEL_B_INDEX][3] = vowelB[3]; + std::copy(vowelA.begin(), vowelA.end(), std::begin(mChans[i].Formants[VOWEL_A_INDEX])); + std::copy(vowelB.begin(), vowelB.end(), std::begin(mChans[i].Formants[VOWEL_B_INDEX])); } mOutTarget = target.Main->Buffer; - for(ALuint i{0u};i < slot->Wet.Buffer.size();++i) + for(size_t i{0u};i < slot->Wet.Buffer.size();++i) { auto coeffs = GetAmbiIdentityRow(i); ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mChans[i].TargetGains); -- cgit v1.2.3 From 9959d661a02b8d140dfc43b2aa1c6bfa40a5af18 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 19 Jul 2019 22:55:20 -0700 Subject: Restructure codec send/receive calls In particular, after an initial fill of the codec's internal buffer, each receive_frame call is followed by one or more send_packet calls. For asynchronous codecs, this has the effect of letting the codec work while the handler thread is waiting for an AVFrame structure to become available or waiting for more decoded data to be needed. For synchronous codecs, this makes the send_packet calls use up time that would be spent waiting. --- examples/alffplay.cpp | 139 +++++++++++++++++++++++--------------------------- 1 file changed, 64 insertions(+), 75 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 466c4576..1f2c7d6c 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -188,6 +188,21 @@ class PacketQueue { size_t mTotalSize{0}; bool mFinished{false}; + AVPacket *getPacket(std::unique_lock &lock) + { + while(mPackets.empty() && !mFinished) + mCondVar.wait(lock); + return mPackets.empty() ? nullptr : &mPackets.front(); + } + + void pop() + { + AVPacket *pkt = &mPackets.front(); + mTotalSize -= pkt->size; + av_packet_unref(pkt); + mPackets.pop_front(); + } + public: ~PacketQueue() { @@ -197,6 +212,22 @@ public: mTotalSize = 0; } + void sendTo(AVCodecContext *codecctx) + { + std::unique_lock lock{mMutex}; + AVPacket *lastpkt{}; + while((lastpkt=getPacket(lock)) != nullptr) + { + const int ret{avcodec_send_packet(codecctx, lastpkt)}; + if(ret == AVERROR(EAGAIN)) return; + if(ret < 0) + std::cerr<< "Failed to send packet: "< &lock) - { - while(mPackets.empty() && !mFinished) - mCondVar.wait(lock); - return mPackets.empty() ? nullptr : &mPackets.front(); - } - bool put(const AVPacket *pkt) { { @@ -232,16 +256,6 @@ public: mCondVar.notify_one(); return true; } - - void pop() - { - AVPacket *pkt = &mPackets.front(); - mTotalSize -= pkt->size; - av_packet_unref(pkt); - mPackets.pop_front(); - } - - std::mutex &getMutex() noexcept { return mMutex; } }; @@ -547,33 +561,21 @@ int AudioState::decodeFrame() { while(!mMovie.mQuit.load(std::memory_order_relaxed)) { - { - std::unique_lock lock{mPackets.getMutex()}; - AVPacket *lastpkt{}; - while((lastpkt=mPackets.getPacket(lock)) != nullptr) - { - const int ret{avcodec_send_packet(mCodecCtx.get(), lastpkt)}; - if(ret == AVERROR(EAGAIN)) break; - if(ret < 0) - std::cerr<< "Failed to send packet: "<nb_samples <= 0) - { - av_frame_unref(mDecodedFrame.get()); continue; - } /* If provided, update w/ pts */ if(mDecodedFrame->best_effort_timestamp != AV_NOPTS_VALUE) @@ -1006,6 +1008,9 @@ int AudioState::handler() #endif samples = av_malloc(buffer_len); + /* Prefill the codec buffer. */ + mPackets.sendTo(mCodecCtx.get()); + srclock.lock(); while(alGetError() == AL_NO_ERROR && !mMovie.mQuit.load(std::memory_order_relaxed) && mConnected.test_and_set(std::memory_order_relaxed)) @@ -1305,39 +1310,20 @@ int VideoState::handler() [](Picture &pict) -> void { pict.mFrame = AVFramePtr{av_frame_alloc()}; }); + /* Prefill the codec buffer. */ + mPackets.sendTo(mCodecCtx.get()); + while(!mMovie.mQuit.load(std::memory_order_relaxed)) { - { - std::unique_lock lock{mPackets.getMutex()}; - AVPacket *lastpkt{}; - while((lastpkt=mPackets.getPacket(lock)) != nullptr) - { - const int ret{avcodec_send_packet(mCodecCtx.get(), lastpkt)}; - if(ret == AVERROR(EAGAIN)) break; - if(ret < 0) - std::cerr<< "Failed to send packet: "<mFrame.get()}; + const int ret{avcodec_receive_frame(mCodecCtx.get(), decoded_frame)}; + if(ret == AVERROR_EOF) break; + if(ret == 0) { - size_t write_idx{mPictQWrite.load(std::memory_order_relaxed)}; - Picture *vp{&mPictQ[write_idx]}; - - /* Decode video frame. */ - AVFrame *decoded_frame{vp->mFrame.get()}; - const int ret{avcodec_receive_frame(mCodecCtx.get(), decoded_frame)}; - if(ret == AVERROR_EOF) goto finished; - if(ret == AVERROR(EAGAIN)) break; - if(ret < 0) - { - std::cerr<< "Failed to receive frame: "<best_effort_timestamp != AV_NOPTS_VALUE) mCurrentPts = std::chrono::duration_cast( @@ -1354,18 +1340,21 @@ int VideoState::handler() */ write_idx = (write_idx+1)%mPictQ.size(); mPictQWrite.store(write_idx, std::memory_order_release); + } + else if(ret != AVERROR(EAGAIN)) + std::cerr<< "Failed to receive frame: "< lock{mPictQMutex}; - while(write_idx == mPictQRead.load(std::memory_order_acquire) && - !mMovie.mQuit.load(std::memory_order_relaxed)) - mPictQCond.wait(lock); - } + mPackets.sendTo(mCodecCtx.get()); + + if(write_idx == mPictQRead.load(std::memory_order_acquire)) + { + /* Wait until we have space for a new pic */ + std::unique_lock lock{mPictQMutex}; + while(write_idx == mPictQRead.load(std::memory_order_acquire) && + !mMovie.mQuit.load(std::memory_order_relaxed)) + mPictQCond.wait(lock); } } -finished: mEOS = true; std::unique_lock lock{mPictQMutex}; -- cgit v1.2.3 From f0ed35d3d0fb35a9ff0dbcecc90d5c75a7618ca1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 20 Jul 2019 01:10:14 -0700 Subject: Set the initial clock time closer to starting playback --- examples/alffplay.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 1f2c7d6c..063ea157 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -748,19 +748,10 @@ void AL_APIENTRY AudioState::EventCallback(ALenum eventType, ALuint object, ALui int AudioState::handler() { - std::unique_lock srclock{mSrcMutex}; + std::unique_lock srclock{mSrcMutex, std::defer_lock}; milliseconds sleep_time{AudioBufferTime / 3}; ALenum fmt; - if(alcGetInteger64vSOFT) - { - int64_t devtime{}; - alcGetInteger64vSOFT(alcGetContextsDevice(alcGetCurrentContext()), ALC_DEVICE_CLOCK_SOFT, - 1, &devtime); - mDeviceStartTime = nanoseconds{devtime} - mCurrentPts; - } - srclock.unlock(); - #ifdef AL_SOFT_events const std::array evt_types{{ AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, @@ -1012,6 +1003,13 @@ int AudioState::handler() mPackets.sendTo(mCodecCtx.get()); srclock.lock(); + if(alcGetInteger64vSOFT) + { + int64_t devtime{}; + alcGetInteger64vSOFT(alcGetContextsDevice(alcGetCurrentContext()), ALC_DEVICE_CLOCK_SOFT, + 1, &devtime); + mDeviceStartTime = nanoseconds{devtime} - mCurrentPts; + } while(alGetError() == AL_NO_ERROR && !mMovie.mQuit.load(std::memory_order_relaxed) && mConnected.test_and_set(std::memory_order_relaxed)) { @@ -1301,11 +1299,6 @@ void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer) int VideoState::handler() { - { - std::lock_guard _{mDispPtsMutex}; - mDisplayPtsTime = get_avtime(); - } - std::for_each(mPictQ.begin(), mPictQ.end(), [](Picture &pict) -> void { pict.mFrame = AVFramePtr{av_frame_alloc()}; }); @@ -1313,6 +1306,11 @@ int VideoState::handler() /* Prefill the codec buffer. */ mPackets.sendTo(mCodecCtx.get()); + { + std::lock_guard _{mDispPtsMutex}; + mDisplayPtsTime = get_avtime(); + } + while(!mMovie.mQuit.load(std::memory_order_relaxed)) { size_t write_idx{mPictQWrite.load(std::memory_order_relaxed)}; -- cgit v1.2.3 From 8a9434c6238344e676e6defb74cea6bf6d62d401 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 20 Jul 2019 18:46:43 -0700 Subject: Use a local variable to track the decoded pts --- examples/alffplay.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 063ea157..62c1a908 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -345,8 +345,6 @@ struct VideoState { PacketQueue<14*1024*1024> mPackets; - /* The expected pts of the next frame to decode. */ - nanoseconds mCurrentPts{0}; /* The pts of the currently displayed frame, and the time (av_gettime) it * was last updated - used to have running video pts */ @@ -1311,12 +1309,13 @@ int VideoState::handler() mDisplayPtsTime = get_avtime(); } + auto current_pts = nanoseconds::zero(); while(!mMovie.mQuit.load(std::memory_order_relaxed)) { size_t write_idx{mPictQWrite.load(std::memory_order_relaxed)}; Picture *vp{&mPictQ[write_idx]}; - /* Decode video frame. */ + /* Retrieve video frame. */ AVFrame *decoded_frame{vp->mFrame.get()}; const int ret{avcodec_receive_frame(mCodecCtx.get(), decoded_frame)}; if(ret == AVERROR_EOF) break; @@ -1324,14 +1323,14 @@ int VideoState::handler() { /* Get the PTS for this frame. */ if(decoded_frame->best_effort_timestamp != AV_NOPTS_VALUE) - mCurrentPts = std::chrono::duration_cast( + current_pts = std::chrono::duration_cast( seconds_d64{av_q2d(mStream->time_base)*decoded_frame->best_effort_timestamp}); - vp->mPts = mCurrentPts; + vp->mPts = current_pts; /* Update the video clock to the next expected PTS. */ auto frame_delay = av_q2d(mCodecCtx->time_base); frame_delay += decoded_frame->repeat_pict * (frame_delay * 0.5); - mCurrentPts += std::chrono::duration_cast(seconds_d64{frame_delay}); + current_pts += std::chrono::duration_cast(seconds_d64{frame_delay}); /* Put the frame in the queue to be loaded into a texture and * displayed by the rendering thread. -- cgit v1.2.3 From b8ac4b79e43d3ae60926f5aad7125d10b2d78ea7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Jul 2019 02:19:02 -0700 Subject: Only send packets as needed --- examples/alffplay.cpp | 88 ++++++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 39 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 62c1a908..fbbbdf89 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -212,20 +212,21 @@ public: mTotalSize = 0; } - void sendTo(AVCodecContext *codecctx) + int sendTo(AVCodecContext *codecctx) { std::unique_lock lock{mMutex}; - AVPacket *lastpkt{}; - while((lastpkt=getPacket(lock)) != nullptr) + + AVPacket *pkt{getPacket(lock)}; + if(!pkt) return avcodec_send_packet(codecctx, nullptr); + + const int ret{avcodec_send_packet(codecctx, pkt)}; + if(ret != AVERROR(EAGAIN)) { - const int ret{avcodec_send_packet(codecctx, lastpkt)}; - if(ret == AVERROR(EAGAIN)) return; if(ret < 0) std::cerr<< "Failed to send packet: "<nb_samples <= 0) continue; @@ -998,7 +996,11 @@ int AudioState::handler() samples = av_malloc(buffer_len); /* Prefill the codec buffer. */ - mPackets.sendTo(mCodecCtx.get()); + do { + const int ret{mPackets.sendTo(mCodecCtx.get())}; + if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + break; + } while(1); srclock.lock(); if(alcGetInteger64vSOFT) @@ -1302,7 +1304,11 @@ int VideoState::handler() { pict.mFrame = AVFramePtr{av_frame_alloc()}; }); /* Prefill the codec buffer. */ - mPackets.sendTo(mCodecCtx.get()); + do { + const int ret{mPackets.sendTo(mCodecCtx.get())}; + if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + break; + } while(1); { std::lock_guard _{mDispPtsMutex}; @@ -1317,30 +1323,34 @@ int VideoState::handler() /* Retrieve video frame. */ AVFrame *decoded_frame{vp->mFrame.get()}; - const int ret{avcodec_receive_frame(mCodecCtx.get(), decoded_frame)}; - if(ret == AVERROR_EOF) break; - if(ret == 0) + int ret; + while((ret=avcodec_receive_frame(mCodecCtx.get(), decoded_frame)) == AVERROR(EAGAIN)) + mPackets.sendTo(mCodecCtx.get()); + if(ret != 0) { - /* Get the PTS for this frame. */ - if(decoded_frame->best_effort_timestamp != AV_NOPTS_VALUE) - current_pts = std::chrono::duration_cast( - seconds_d64{av_q2d(mStream->time_base)*decoded_frame->best_effort_timestamp}); - vp->mPts = current_pts; - - /* Update the video clock to the next expected PTS. */ - auto frame_delay = av_q2d(mCodecCtx->time_base); - frame_delay += decoded_frame->repeat_pict * (frame_delay * 0.5); - current_pts += std::chrono::duration_cast(seconds_d64{frame_delay}); - - /* Put the frame in the queue to be loaded into a texture and - * displayed by the rendering thread. - */ - write_idx = (write_idx+1)%mPictQ.size(); - mPictQWrite.store(write_idx, std::memory_order_release); - } - else if(ret != AVERROR(EAGAIN)) + if(ret == AVERROR_EOF) break; std::cerr<< "Failed to receive frame: "<best_effort_timestamp != AV_NOPTS_VALUE) + current_pts = std::chrono::duration_cast( + seconds_d64{av_q2d(mStream->time_base)*decoded_frame->best_effort_timestamp}); + vp->mPts = current_pts; + + /* Update the video clock to the next expected PTS. */ + auto frame_delay = av_q2d(mCodecCtx->time_base); + frame_delay += decoded_frame->repeat_pict * (frame_delay * 0.5); + current_pts += std::chrono::duration_cast(seconds_d64{frame_delay}); + + /* Put the frame in the queue to be loaded into a texture and displayed + * by the rendering thread. + */ + write_idx = (write_idx+1)%mPictQ.size(); + mPictQWrite.store(write_idx, std::memory_order_release); + /* Send a packet now so it's hopefully ready by the time it's needed. */ mPackets.sendTo(mCodecCtx.get()); if(write_idx == mPictQRead.load(std::memory_order_acquire)) -- cgit v1.2.3 From 18f1139de86a5e961e65ae562b0a1106828b21ab Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Jul 2019 12:51:14 -0700 Subject: Only redraw the image when necessary --- examples/alffplay.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index fbbbdf89..b532d8cd 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -383,7 +383,7 @@ struct VideoState { nanoseconds getClock(); void display(SDL_Window *screen, SDL_Renderer *renderer); - void updateVideo(SDL_Window *screen, SDL_Renderer *renderer); + void updateVideo(SDL_Window *screen, SDL_Renderer *renderer, bool redraw); int handler(); }; @@ -1158,7 +1158,7 @@ void VideoState::display(SDL_Window *screen, SDL_Renderer *renderer) * handles updating the textures of decoded frames and displaying the latest * frame. */ -void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer) +void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer, bool redraw) { size_t read_idx{mPictQRead.load(std::memory_order_relaxed)}; Picture *vp{&mPictQ[read_idx]}; @@ -1273,10 +1273,15 @@ void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer) SDL_UnlockTexture(mImage); } } + + redraw = true; } - /* Show the picture! */ - display(screen, renderer); + if(redraw) + { + /* Show the picture! */ + display(screen, renderer); + } if(updated) { @@ -1766,6 +1771,7 @@ int main(int argc, char *argv[]) last_time = cur_time; } + bool force_redraw{false}; if(have_evt) do { switch(event.type) { @@ -1793,6 +1799,11 @@ int main(int argc, char *argv[]) case SDL_WINDOWEVENT_RESIZED: SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderFillRect(renderer, nullptr); + force_redraw = true; + break; + + case SDL_WINDOWEVENT_EXPOSED: + force_redraw = true; break; default: @@ -1841,7 +1852,7 @@ int main(int argc, char *argv[]) } } while(SDL_PollEvent(&event)); - movState->mVideo.updateVideo(screen, renderer); + movState->mVideo.updateVideo(screen, renderer, force_redraw); } std::cerr<< "SDL_WaitEvent error - "< Date: Fri, 26 Jul 2019 03:44:46 -0700 Subject: Increase the video picture queue size to 24 --- examples/alffplay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index b532d8cd..eb5004c6 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -120,7 +120,7 @@ LPALEVENTCALLBACKSOFT alEventCallbackSOFT; const seconds AVNoSyncThreshold{10}; const milliseconds VideoSyncThreshold{10}; -#define VIDEO_PICTURE_QUEUE_SIZE 16 +#define VIDEO_PICTURE_QUEUE_SIZE 24 const seconds_d64 AudioSyncThreshold{0.03}; const milliseconds AudioSampleCorrectionMax{50}; -- cgit v1.2.3 From 7cfb353334c725b3f57a4a2951b4ff9e352fc956 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 26 Jul 2019 14:02:14 -0700 Subject: Don't explicitly check for standard functions --- CMakeLists.txt | 1 - common/almalloc.cpp | 6 ++++-- config.h.in | 3 --- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cf10bc20..60528515 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -486,7 +486,6 @@ IF(HAVE_INTRIN_H) ENDIF() CHECK_SYMBOL_EXISTS(sysconf unistd.h HAVE_SYSCONF) -CHECK_SYMBOL_EXISTS(aligned_alloc stdlib.h HAVE_ALIGNED_ALLOC) CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN) CHECK_SYMBOL_EXISTS(_aligned_malloc malloc.h HAVE__ALIGNED_MALLOC) CHECK_SYMBOL_EXISTS(proc_pidpath libproc.h HAVE_PROC_PIDPATH) diff --git a/common/almalloc.cpp b/common/almalloc.cpp index f94ae8bc..2902a087 100644 --- a/common/almalloc.cpp +++ b/common/almalloc.cpp @@ -17,12 +17,14 @@ #endif +#define ALIGNED_ALLOC_AVAILABLE (__STDC_VERSION__ >= 201112L || __cplusplus >= 201703L) + void *al_malloc(size_t alignment, size_t size) { assert((alignment & (alignment-1)) == 0); alignment = std::max(alignment, alignof(std::max_align_t)); -#if defined(HAVE_ALIGNED_ALLOC) +#if ALIGNED_ALLOC_AVAILABLE size = (size+(alignment-1))&~(alignment-1); return aligned_alloc(alignment, size); #elif defined(HAVE_POSIX_MEMALIGN) @@ -53,7 +55,7 @@ void *al_calloc(size_t alignment, size_t size) void al_free(void *ptr) noexcept { -#if defined(HAVE_ALIGNED_ALLOC) || defined(HAVE_POSIX_MEMALIGN) +#if ALIGNED_ALLOC_AVAILABLE || defined(HAVE_POSIX_MEMALIGN) free(ptr); #elif defined(HAVE__ALIGNED_MALLOC) _aligned_free(ptr); diff --git a/config.h.in b/config.h.in index a98faff8..5dd4311a 100644 --- a/config.h.in +++ b/config.h.in @@ -11,9 +11,6 @@ /* Define if we have the sysconf function */ #cmakedefine HAVE_SYSCONF -/* Define if we have the C11 aligned_alloc function */ -#cmakedefine HAVE_ALIGNED_ALLOC - /* Define if we have the posix_memalign function */ #cmakedefine HAVE_POSIX_MEMALIGN -- cgit v1.2.3 From 659b6d4245b92a7dba3a1b1693db6de8ddf999eb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Jul 2019 18:58:19 -0700 Subject: Use more proper cmake to set the C/C++ standard version --- CMakeLists.txt | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 60528515..258a05af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,20 +117,13 @@ CHECK_TYPE_SIZE("long" SIZEOF_LONG) CHECK_TYPE_SIZE("long long" SIZEOF_LONG_LONG) -CHECK_C_COMPILER_FLAG(-std=c11 HAVE_STD_C11) -IF(HAVE_STD_C11) - SET(CMAKE_C_FLAGS "-std=c11 ${CMAKE_C_FLAGS}") -ELSE() - CHECK_C_COMPILER_FLAG(-std=c99 HAVE_STD_C99) - IF(HAVE_STD_C99) - SET(CMAKE_C_FLAGS "-std=c99 ${CMAKE_C_FLAGS}") - ENDIF() -ENDIF() +# Require C++11 +SET(CMAKE_CXX_STANDARD 11) +SET(CMAKE_CXX_STANDARD_REQUIRED TRUE) + +# Prefer C11, but support C99 and C90 too. +SET(CMAKE_C_STANDARD 11) -CHECK_CXX_COMPILER_FLAG(-std=c++11 HAVE_STD_CXX11) -IF(HAVE_STD_CXX11) - SET(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") -ENDIF() if(NOT WIN32) # Check if _POSIX_C_SOURCE and _XOPEN_SOURCE needs to be set for POSIX functions -- cgit v1.2.3 From 5428d6acc37e33802b0b66b2f9cdc0a37dd36429 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Jul 2019 11:28:36 -0700 Subject: Clean up includes a bit Trying out the IWYU tool to only include what's necessary in a given file. Seems to work decently (it'll miss some headers, suggest unnecessary ones, and make nonsense suggestions for some things, but overall gives a good starting point), and helps clean out some headers. --- Alc/alc.cpp | 86 ++++++++++++++++++++++++++++++----------------- Alc/alu.cpp | 62 ++++++++++++++++++++++++---------- Alc/backends/alsa.cpp | 31 +++++++++++------ Alc/backends/dsound.cpp | 5 +++ Alc/backends/null.cpp | 15 +++++---- Alc/backends/oss.cpp | 37 +++++++++++--------- Alc/backends/wasapi.cpp | 4 +++ Alc/backends/wave.cpp | 22 ++++++++---- Alc/bformatdec.cpp | 21 +++++------- Alc/bformatdec.h | 18 ++++++---- Alc/effects/chorus.cpp | 21 +++++++++--- Alc/filters/biquad.cpp | 10 +++--- Alc/filters/biquad.h | 1 - Alc/helpers.cpp | 35 ++++++------------- Alc/hrtf.cpp | 35 +++++++++++-------- Alc/hrtf.h | 10 +++--- Alc/mixvoice.cpp | 43 ++++++++++++++++-------- OpenAL32/Include/alMain.h | 58 ++++++++++++-------------------- OpenAL32/Include/alu.h | 43 ++++++++++-------------- OpenAL32/alBuffer.cpp | 38 ++++++++++++++------- OpenAL32/alEffect.cpp | 25 +++++++++----- OpenAL32/alError.cpp | 15 ++++++++- OpenAL32/alSource.cpp | 55 ++++++++++++++++++++---------- OpenAL32/alState.cpp | 19 ++++++++--- OpenAL32/event.cpp | 22 +++++++++--- include/AL/efx.h | 1 + 26 files changed, 446 insertions(+), 286 deletions(-) diff --git a/Alc/alc.cpp b/Alc/alc.cpp index a7b53c6b..0bc099b4 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -22,47 +22,71 @@ #include "version.h" -#include -#include -#include -#include -#include - -#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include +#include #include -#include -#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" +#include "AL/efx.h" -#include "alMain.h" -#include "alcontext.h" -#include "alSource.h" -#include "alListener.h" -#include "alSource.h" -#include "alBuffer.h" -#include "alFilter.h" -#include "alEffect.h" #include "alAuxEffectSlot.h" +#include "alEffect.h" #include "alError.h" -#include "mastering.h" -#include "bformatdec.h" -#include "uhjfilter.h" -#include "alu.h" +#include "alFilter.h" +#include "alListener.h" +#include "alMain.h" +#include "alSource.h" +#include "albyte.h" #include "alconfig.h" -#include "ringbuffer.h" -#include "filters/splitter.h" +#include "alcontext.h" +#include "alexcpt.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "aloptional.h" +#include "alspan.h" +#include "alu.h" +#include "ambidefs.h" +#include "atomic.h" +#include "bformatdec.h" #include "bs2b.h" - -#include "fpu_modes.h" -#include "cpu_caps.h" #include "compat.h" +#include "cpu_caps.h" +#include "effects/base.h" +#include "filters/nfc.h" +#include "filters/splitter.h" +#include "fpu_modes.h" +#include "hrtf.h" +#include "inprogext.h" +#include "logging.h" +#include "mastering.h" +#include "opthelpers.h" +#include "ringbuffer.h" #include "threads.h" -#include "alexcpt.h" -#include "almalloc.h" +#include "uhjfilter.h" +#include "vecmat.h" +#include "vector.h" #include "backends/base.h" #include "backends/null.h" diff --git a/Alc/alu.cpp b/Alc/alu.cpp index f5c3b842..666cbb27 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -20,36 +20,62 @@ #include "config.h" -#include -#include -#include -#include -#include +#include "alu.h" +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include #include +#include +#include #include -#include -#include +#include -#include "alMain.h" -#include "alcontext.h" -#include "alSource.h" +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/efx.h" + +#include "alAuxEffectSlot.h" #include "alBuffer.h" +#include "alEffect.h" #include "alListener.h" -#include "alAuxEffectSlot.h" -#include "alu.h" +#include "alMain.h" +#include "alcontext.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "alspan.h" +#include "ambidefs.h" +#include "atomic.h" +#include "bformatdec.h" #include "bs2b.h" +#include "cpu_caps.h" +#include "effects/base.h" +#include "filters/biquad.h" +#include "filters/nfc.h" +#include "filters/splitter.h" +#include "fpu_modes.h" #include "hrtf.h" +#include "inprogext.h" #include "mastering.h" -#include "uhjfilter.h" -#include "bformatdec.h" +#include "math_defs.h" +#include "mixer/defs.h" +#include "opthelpers.h" #include "ringbuffer.h" -#include "filters/splitter.h" +#include "threads.h" +#include "uhjfilter.h" +#include "vecmat.h" +#include "vector.h" -#include "mixer/defs.h" -#include "fpu_modes.h" -#include "cpu_caps.h" #include "bsinc_inc.h" diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index aeb38585..698a4088 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -22,22 +22,33 @@ #include "backends/alsa.h" -#include -#include -#include - -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include + +#include "AL/al.h" #include "alMain.h" -#include "alu.h" +#include "albyte.h" #include "alconfig.h" -#include "ringbuffer.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "aloptional.h" +#include "alu.h" #include "compat.h" +#include "logging.h" +#include "ringbuffer.h" +#include "threads.h" +#include "vector.h" #include diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 93de3135..5c77df60 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -22,6 +22,9 @@ #include "backends/dsound.h" +#define WIN32_LEAN_AND_MEAN +#include + #include #include #include @@ -34,6 +37,7 @@ #endif #include +#include #include #include #include @@ -44,6 +48,7 @@ #include "alu.h" #include "ringbuffer.h" #include "compat.h" +#include "threads.h" /* MinGW-w64 needs this for some unknown reason now. */ using LPCWAVEFORMATEX = const WAVEFORMATEX*; diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 121d7700..00a37fda 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -22,18 +22,19 @@ #include "backends/null.h" -#include -#ifdef HAVE_WINDOWS_H -#include -#endif - +#include +#include #include -#include +#include +#include #include +#include #include "alMain.h" +#include "almalloc.h" #include "alu.h" -#include "compat.h" +#include "logging.h" +#include "threads.h" namespace { diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index e5b74334..33075890 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -22,32 +22,37 @@ #include "backends/oss.h" +#include +#include #include -#include -#include #include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include + +#include "AL/al.h" #include "alMain.h" -#include "alu.h" #include "alconfig.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "aloptional.h" +#include "alu.h" +#include "logging.h" #include "ringbuffer.h" -#include "compat.h" +#include "threads.h" +#include "vector.h" #include diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index db4b5e4e..384aaba8 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -22,6 +22,9 @@ #include "backends/wasapi.h" +#define WIN32_LEAN_AND_MEAN +#include + #include #include #include @@ -56,6 +59,7 @@ #include "ringbuffer.h" #include "compat.h" #include "converter.h" +#include "threads.h" /* Some headers seem to define these as macros for __uuidof, which is annoying diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index d06f36d7..77692686 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -22,20 +22,28 @@ #include "backends/wave.h" -#include -#include -#include +#include +#include #include - #include -#include -#include +#include +#include +#include +#include #include +#include + +#include "AL/al.h" #include "alMain.h" -#include "alu.h" #include "alconfig.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "alu.h" #include "compat.h" +#include "logging.h" +#include "threads.h" +#include "vector.h" namespace { diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp index 6ef398ec..889bbf3a 100644 --- a/Alc/bformatdec.cpp +++ b/Alc/bformatdec.cpp @@ -1,27 +1,24 @@ #include "config.h" -#include +#include "bformatdec.h" + +#include #include -#include +#include +#include +#include #include -#include -#include -#include "bformatdec.h" +#include "almalloc.h" +#include "alu.h" #include "ambdec.h" #include "filters/splitter.h" -#include "alu.h" - -#include "threads.h" -#include "almalloc.h" +#include "opthelpers.h" namespace { -using namespace std::placeholders; - - constexpr ALfloat Ambi3DDecoderHFScale[MAX_AMBI_ORDER+1] = { 1.00000000e+00f, 1.00000000e+00f }; diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 1ec4a1bb..31abc4fe 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -1,11 +1,17 @@ #ifndef BFORMATDEC_H #define BFORMATDEC_H +#include +#include + +#include "AL/al.h" + #include "alMain.h" -#include "filters/splitter.h" -#include "ambidefs.h" #include "almalloc.h" - +#include "alspan.h" +#include "ambidefs.h" +#include "filters/splitter.h" +#include "vector.h" struct AmbDecConf; @@ -27,10 +33,10 @@ class BFormatDec { /* NOTE: BandSplitter filters are unused with single-band decoding */ BandSplitter mXOver[MAX_AMBI_CHANNELS]; - al::vector, 16> mSamples; + al::vector mSamples; /* These two alias into Samples */ - std::array *mSamplesHF{nullptr}; - std::array *mSamplesLF{nullptr}; + FloatBufferLine *mSamplesHF{nullptr}; + FloatBufferLine *mSamplesLF{nullptr}; ALuint mNumChannels{0u}; bool mDualBand{false}; diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp index a2a34008..b9bf3f4c 100644 --- a/Alc/effects/chorus.cpp +++ b/Alc/effects/chorus.cpp @@ -20,17 +20,28 @@ #include "config.h" +#include +#include +#include #include +#include -#include -#include +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/efx.h" -#include "alMain.h" -#include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" +#include "alMain.h" +#include "alcontext.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "alspan.h" #include "alu.h" -#include "filters/biquad.h" +#include "ambidefs.h" +#include "effects/base.h" +#include "math_defs.h" +#include "opthelpers.h" #include "vector.h" diff --git a/Alc/filters/biquad.cpp b/Alc/filters/biquad.cpp index e4b7bec0..6a3cef64 100644 --- a/Alc/filters/biquad.cpp +++ b/Alc/filters/biquad.cpp @@ -1,13 +1,13 @@ #include "config.h" -#include +#include "biquad.h" -#include "AL/alc.h" -#include "AL/al.h" +#include +#include +#include -#include "alMain.h" -#include "biquad.h" +#include "opthelpers.h" template diff --git a/Alc/filters/biquad.h b/Alc/filters/biquad.h index eb4cf82a..893a69a9 100644 --- a/Alc/filters/biquad.h +++ b/Alc/filters/biquad.h @@ -4,7 +4,6 @@ #include #include -#include "AL/al.h" #include "math_defs.h" diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index ee0bb2dc..9f6283a3 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -28,14 +28,15 @@ #include "config.h" -#include -#include +#include #include #include -#include -#ifdef HAVE_MALLOC_H -#include -#endif +#include +#include +#include +#include +#include + #ifdef HAVE_DIRENT_H #include #endif @@ -95,35 +96,19 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x #ifdef HAVE_SYS_SYSCONF_H #include #endif -#ifdef HAVE_FLOAT_H -#include -#endif -#ifdef HAVE_IEEEFP_H -#include -#endif #ifndef _WIN32 -#include -#include -#include -#include #include #elif defined(_WIN32_IE) #include #endif -#include -#include -#include -#include - #include "alMain.h" -#include "alu.h" +#include "almalloc.h" +#include "compat.h" #include "cpu_caps.h" #include "fpu_modes.h" -#include "vector.h" -#include "compat.h" -#include "threads.h" +#include "logging.h" #if defined(HAVE_GCC_GET_CPUID) && (defined(__i386__) || defined(__x86_64__) || \ diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index d86c4ecf..5561ebfd 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -20,30 +20,37 @@ #include "config.h" -#include -#include +#include "hrtf.h" -#include +#include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include +#include +#include #include -#include -#include +#include #include "AL/al.h" -#include "AL/alc.h" + #include "alMain.h" -#include "alSource.h" -#include "alu.h" -#include "hrtf.h" #include "alconfig.h" -#include "filters/splitter.h" - -#include "compat.h" #include "almalloc.h" +#include "alnumeric.h" +#include "aloptional.h" #include "alspan.h" +#include "compat.h" +#include "filters/splitter.h" +#include "logging.h" +#include "math_defs.h" +#include "opthelpers.h" struct HrtfHandle { diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 72533cc1..6c41cb82 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -2,15 +2,19 @@ #define ALC_HRTF_H #include +#include #include #include #include "AL/al.h" -#include "AL/alc.h" -#include "vector.h" #include "almalloc.h" +#include "ambidefs.h" +#include "atomic.h" +#include "vector.h" + +struct HrtfHandle; #define HRTF_HISTORY_BITS (6) #define HRTF_HISTORY_LENGTH (1< +#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include - +#include +#include +#include #include -#include +#include +#include #include "AL/al.h" #include "AL/alc.h" +#include "alBuffer.h" #include "alMain.h" -#include "alcontext.h" #include "alSource.h" -#include "alBuffer.h" -#include "alListener.h" -#include "alAuxEffectSlot.h" -#include "sample_cvt.h" -#include "alu.h" +#include "albyte.h" #include "alconfig.h" -#include "ringbuffer.h" +#include "alcontext.h" +#include "alnumeric.h" +#include "aloptional.h" +#include "alspan.h" +#include "alu.h" #include "cpu_caps.h" +#include "filters/biquad.h" +#include "filters/nfc.h" +#include "filters/splitter.h" +#include "hrtf.h" +#include "inprogext.h" +#include "logging.h" #include "mixer/defs.h" - -#include "alspan.h" +#include "opthelpers.h" +#include "ringbuffer.h" +#include "threads.h" +#include "vector.h" static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 3487d42e..33b2fc39 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -1,38 +1,41 @@ #ifndef AL_MAIN_H #define AL_MAIN_H -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_STRINGS_H -#include -#endif - +#include #include -#include -#include +#include #include -#include +#include +#include +#include +#include +#include +#include #include "AL/al.h" #include "AL/alc.h" #include "AL/alext.h" -#include "inprogext.h" -#include "atomic.h" -#include "vector.h" #include "albyte.h" #include "almalloc.h" #include "alnumeric.h" #include "alspan.h" -#include "threads.h" #include "ambidefs.h" +#include "atomic.h" #include "hrtf.h" +#include "inprogext.h" +#include "vector.h" + +class BFormatDec; +struct ALbuffer; +struct ALeffect; +struct ALfilter; +struct BackendBase; +struct Compressor; +struct EffectState; +struct FrontStablizer; +struct Uhj2Encoder; +struct bs2b; #ifndef UNUSED @@ -59,23 +62,6 @@ static const union { #endif -struct HrtfEntry; -struct HrtfHandle; -struct EnumeratedHrtf; -struct DirectHrtfState; -struct FrontStablizer; -struct Compressor; -struct BackendBase; -struct ALbuffer; -struct ALeffect; -struct ALfilter; -struct EffectState; -struct Uhj2Encoder; -class BFormatDec; -class AmbiUpsampler; -struct bs2b; - - #define MIN_OUTPUT_RATE 8000 #define DEFAULT_OUTPUT_RATE 44100 #define DEFAULT_UPDATE_SIZE 882 /* 20ms */ diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 8abfe15f..841e5c03 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -1,31 +1,29 @@ #ifndef _ALU_H_ #define _ALU_H_ -#include -#include -#ifdef HAVE_FLOAT_H -#include -#endif -#ifdef HAVE_IEEEFP_H -#include -#endif - -#include #include +#include +#include +#include -#include "alMain.h" -#include "alBuffer.h" +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" -#include "hrtf.h" -#include "logging.h" -#include "math_defs.h" +#include "alBuffer.h" +#include "alMain.h" +#include "almalloc.h" +#include "alspan.h" +#include "ambidefs.h" #include "filters/biquad.h" -#include "filters/splitter.h" #include "filters/nfc.h" +#include "filters/splitter.h" +#include "hrtf.h" +#include "logging.h" -#include "almalloc.h" -#include "alnumeric.h" -#include "alspan.h" +struct ALbufferlistitem; +struct ALeffectslot; +struct BSincTable; enum class DistanceModel; @@ -34,13 +32,6 @@ enum class DistanceModel; #define MAX_SENDS 16 -struct BSincTable; -struct ALsource; -struct ALbufferlistitem; -struct ALvoice; -struct ALeffectslot; - - #define DITHER_RNG_SEED 22222 diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index a6ed98cc..f20b0aee 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -20,27 +20,39 @@ #include "config.h" -#include -#include -#include -#ifdef HAVE_MALLOC_H -#include -#endif +#include "alBuffer.h" -#include +#include #include -#include +#include +#include +#include +#include +#include +#include #include -#include +#include +#include +#include +#include +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" + +#include "alError.h" #include "alMain.h" +#include "albyte.h" #include "alcontext.h" -#include "alu.h" -#include "alError.h" -#include "alBuffer.h" -#include "sample_cvt.h" #include "alexcpt.h" +#include "almalloc.h" +#include "alnumeric.h" #include "aloptional.h" +#include "atomic.h" +#include "inprogext.h" +#include "opthelpers.h" +#include "sample_cvt.h" +#include "vector.h" namespace { diff --git a/OpenAL32/alEffect.cpp b/OpenAL32/alEffect.cpp index 0c4f9e72..2de61019 100644 --- a/OpenAL32/alEffect.cpp +++ b/OpenAL32/alEffect.cpp @@ -20,22 +20,33 @@ #include "config.h" -#include -#include -#include +#include "alEffect.h" #include +#include +#include +#include +#include +#include +#include +#include #include "AL/al.h" #include "AL/alc.h" +#include "AL/alext.h" +#include "AL/efx-presets.h" +#include "AL/efx.h" +#include "alError.h" #include "alMain.h" #include "alcontext.h" -#include "alEffect.h" -#include "alError.h" #include "alexcpt.h" - +#include "almalloc.h" +#include "alnumeric.h" #include "effects/base.h" +#include "logging.h" +#include "opthelpers.h" +#include "vector.h" const EffectList gEffectList[15]{ @@ -539,8 +550,6 @@ EffectStateFactory *getFactoryByType(ALenum type) } -#include "AL/efx-presets.h" - #define DECL(x) { #x, EFX_REVERB_PRESET_##x } static const struct { const char name[32]; diff --git a/OpenAL32/alError.cpp b/OpenAL32/alError.cpp index a7895fb9..092784c9 100644 --- a/OpenAL32/alError.cpp +++ b/OpenAL32/alError.cpp @@ -20,19 +20,32 @@ #include "config.h" +#include "alError.h" + +#include #include #include #include +#include +#include #ifdef HAVE_WINDOWS_H #define WIN32_LEAN_AND_MEAN #include #endif +#include "AL/al.h" +#include "AL/alc.h" + #include "alMain.h" #include "alcontext.h" -#include "alError.h" #include "alexcpt.h" +#include "almalloc.h" +#include "inprogext.h" +#include "logging.h" +#include "opthelpers.h" +#include "vector.h" + bool TrapALError{false}; diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 498875bf..22c9e2d2 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -20,35 +20,56 @@ #include "config.h" -#include -#include -#include +#include "alSource.h" +#include +#include +#include +#include +#include +#include #include -#include +#include +#include +#include +#include #include +#include +#include +#include #include -#include -#include +#include +#include +#include #include "AL/al.h" #include "AL/alc.h" +#include "AL/alext.h" +#include "AL/efx.h" -#include "alMain.h" -#include "alcontext.h" -#include "alError.h" -#include "alSource.h" +#include "alAuxEffectSlot.h" #include "alBuffer.h" +#include "alError.h" #include "alFilter.h" -#include "alAuxEffectSlot.h" -#include "ringbuffer.h" -#include "bformatdec.h" - -#include "backends/base.h" - -#include "threads.h" +#include "alMain.h" +#include "alcontext.h" #include "alexcpt.h" #include "almalloc.h" +#include "alnumeric.h" +#include "alu.h" +#include "ambidefs.h" +#include "atomic.h" +#include "backends/base.h" +#include "bformatdec.h" +#include "filters/nfc.h" +#include "filters/splitter.h" +#include "inprogext.h" +#include "logging.h" +#include "math_defs.h" +#include "opthelpers.h" +#include "ringbuffer.h" +#include "threads.h" +#include "vector.h" namespace { diff --git a/OpenAL32/alState.cpp b/OpenAL32/alState.cpp index 0c447645..f2c38bb2 100644 --- a/OpenAL32/alState.cpp +++ b/OpenAL32/alState.cpp @@ -22,17 +22,26 @@ #include "version.h" -#include +#include #include +#include +#include +#include +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" + +#include "alError.h" #include "alMain.h" #include "alcontext.h" -#include "alu.h" -#include "alError.h" #include "alexcpt.h" +#include "almalloc.h" #include "alspan.h" - -#include "backends/base.h" +#include "alu.h" +#include "atomic.h" +#include "inprogext.h" +#include "opthelpers.h" namespace { diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index 2ee296b0..dfffea9f 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -2,18 +2,30 @@ #include "config.h" #include +#include +#include +#include +#include +#include +#include +#include +#include -#include "AL/alc.h" #include "AL/al.h" -#include "AL/alext.h" +#include "AL/alc.h" +#include "alError.h" #include "alMain.h" +#include "albyte.h" #include "alcontext.h" -#include "alError.h" -#include "alAuxEffectSlot.h" +#include "alexcpt.h" +#include "almalloc.h" +#include "effects/base.h" +#include "inprogext.h" +#include "logging.h" +#include "opthelpers.h" #include "ringbuffer.h" #include "threads.h" -#include "alexcpt.h" static int EventThread(ALCcontext *context) diff --git a/include/AL/efx.h b/include/AL/efx.h index 57766983..34085651 100644 --- a/include/AL/efx.h +++ b/include/AL/efx.h @@ -1,6 +1,7 @@ #ifndef AL_EFX_H #define AL_EFX_H +#include #include "alc.h" #include "al.h" -- cgit v1.2.3 From e0a795d9d2c5696d7f7c79d3e219af84c25a7776 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Jul 2019 14:55:02 -0700 Subject: Clean up some more headers --- utils/makemhr/makemhr.cpp | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/utils/makemhr/makemhr.cpp b/utils/makemhr/makemhr.cpp index 70ddbe5a..e480277e 100644 --- a/utils/makemhr/makemhr.cpp +++ b/utils/makemhr/makemhr.cpp @@ -59,45 +59,40 @@ * 1999 */ +#define _UNICODE #include "config.h" -#define _UNICODE +#include "makemhr.h" + +#include +#include +#include +#include +#include +#include #include #include -#include -#include #include -#include -#include -#include -#include -#ifdef HAVE_STRINGS_H -#include -#endif +#include +#include +#include +#include +#include +#include +#include + #ifdef HAVE_GETOPT #include #else #include "../getopt.h" #endif -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mysofa.h" - -#include "makemhr.h" #include "loaddef.h" #include "loadsofa.h" #include "win_main_utf8.h" + namespace { using namespace std::placeholders; -- cgit v1.2.3 From 585d965c921453e9097ada09ec63c67149aa6d72 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Jul 2019 15:16:13 -0700 Subject: Remove a couple unnecessary includes --- OpenAL32/alError.cpp | 2 +- common/almalloc.cpp | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/OpenAL32/alError.cpp b/OpenAL32/alError.cpp index 092784c9..5f98ae1d 100644 --- a/OpenAL32/alError.cpp +++ b/OpenAL32/alError.cpp @@ -29,7 +29,7 @@ #include #include -#ifdef HAVE_WINDOWS_H +#ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #endif diff --git a/common/almalloc.cpp b/common/almalloc.cpp index 2902a087..8ab48248 100644 --- a/common/almalloc.cpp +++ b/common/almalloc.cpp @@ -10,11 +10,6 @@ #ifdef HAVE_MALLOC_H #include #endif -#ifdef HAVE_WINDOWS_H -#include -#else -#include -#endif #define ALIGNED_ALLOC_AVAILABLE (__STDC_VERSION__ >= 201112L || __cplusplus >= 201703L) -- cgit v1.2.3 From 12e179d53952f2820250049ee4f87495944e714e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Jul 2019 15:22:58 -0700 Subject: Remove some unnecessary header checks --- CMakeLists.txt | 24 +++++------------------- config.h.in | 18 ------------------ 2 files changed, 5 insertions(+), 37 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 258a05af..5d274626 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -414,13 +414,9 @@ CHECK_C_SOURCE_COMPILES("int foo(const char *str, ...) __attribute__((format(pri CHECK_INCLUDE_FILE(malloc.h HAVE_MALLOC_H) CHECK_INCLUDE_FILE(dirent.h HAVE_DIRENT_H) -CHECK_INCLUDE_FILE(strings.h HAVE_STRINGS_H) CHECK_INCLUDE_FILE(cpuid.h HAVE_CPUID_H) CHECK_INCLUDE_FILE(intrin.h HAVE_INTRIN_H) CHECK_INCLUDE_FILE(sys/sysconf.h HAVE_SYS_SYSCONF_H) -CHECK_INCLUDE_FILE(fenv.h HAVE_FENV_H) -CHECK_INCLUDE_FILE(float.h HAVE_FLOAT_H) -CHECK_INCLUDE_FILE(ieeefp.h HAVE_IEEEFP_H) CHECK_INCLUDE_FILE(guiddef.h HAVE_GUIDDEF_H) IF(NOT HAVE_GUIDDEF_H) CHECK_INCLUDE_FILE(initguid.h HAVE_INITGUID_H) @@ -505,14 +501,7 @@ IF(NOT HAVE_STRNCASECMP) ENDIF() -# Check if we have Windows headers -SET(OLD_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}) -SET(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_WIN32_WINNT=0x0502) -CHECK_INCLUDE_FILE(windows.h HAVE_WINDOWS_H) -SET(CMAKE_REQUIRED_DEFINITIONS ${OLD_REQUIRED_DEFINITIONS}) -UNSET(OLD_REQUIRED_DEFINITIONS) - -IF(NOT HAVE_WINDOWS_H) +IF(NOT WIN32) CHECK_SYMBOL_EXISTS(gettimeofday sys/time.h HAVE_GETTIMEOFDAY) IF(NOT HAVE_GETTIMEOFDAY) MESSAGE(FATAL_ERROR "No timing function found!") @@ -606,12 +595,9 @@ ENDIF() CHECK_SYMBOL_EXISTS(getopt unistd.h HAVE_GETOPT) # Check for a 64-bit type -CHECK_INCLUDE_FILE(stdint.h HAVE_STDINT_H) -IF(NOT HAVE_STDINT_H) - IF(NOT SIZEOF_LONG MATCHES "8") - IF(NOT SIZEOF_LONG_LONG MATCHES "8") - MESSAGE(FATAL_ERROR "No 64-bit types found, please report!") - ENDIF() +IF(NOT SIZEOF_LONG MATCHES "8") + IF(NOT SIZEOF_LONG_LONG MATCHES "8") + MESSAGE(FATAL_ERROR "No 64-bit type found, please report!") ENDIF() ENDIF() @@ -929,7 +915,7 @@ ENDIF() OPTION(ALSOFT_REQUIRE_WINMM "Require Windows Multimedia backend" OFF) OPTION(ALSOFT_REQUIRE_DSOUND "Require DirectSound backend" OFF) OPTION(ALSOFT_REQUIRE_WASAPI "Require WASAPI backend" OFF) -IF(HAVE_WINDOWS_H) +IF(WIN32) SET(WINSDK_LIB_DIRS ) SET(WINSDK_INCLUDE_DIRS ) FIND_PACKAGE(WindowsSDK) diff --git a/config.h.in b/config.h.in index 5dd4311a..dbf35eda 100644 --- a/config.h.in +++ b/config.h.in @@ -92,12 +92,6 @@ /* Define if we have GCC's format attribute */ #cmakedefine HAVE_GCC_FORMAT -/* Define if we have stdint.h */ -#cmakedefine HAVE_STDINT_H - -/* Define if we have windows.h */ -#cmakedefine HAVE_WINDOWS_H - /* Define if we have dlfcn.h */ #cmakedefine HAVE_DLFCN_H @@ -110,9 +104,6 @@ /* Define if we have dirent.h */ #cmakedefine HAVE_DIRENT_H -/* Define if we have strings.h */ -#cmakedefine HAVE_STRINGS_H - /* Define if we have cpuid.h */ #cmakedefine HAVE_CPUID_H @@ -128,15 +119,6 @@ /* Define if we have initguid.h */ #cmakedefine HAVE_INITGUID_H -/* Define if we have ieeefp.h */ -#cmakedefine HAVE_IEEEFP_H - -/* Define if we have float.h */ -#cmakedefine HAVE_FLOAT_H - -/* Define if we have fenv.h */ -#cmakedefine HAVE_FENV_H - /* Define if we have GCC's __get_cpuid() */ #cmakedefine HAVE_GCC_GET_CPUID -- cgit v1.2.3 From c8bbd75bf9a6f0170ec95b130b3eb17cd8cdd5ad Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Jul 2019 15:37:12 -0700 Subject: Remove a couple more cmake checks --- CMakeLists.txt | 4 ---- config.h.in | 6 ------ 2 files changed, 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d274626..53361f0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -243,9 +243,6 @@ ELSE() SET(C_FLAGS ${C_FLAGS} -fno-math-errno) ENDIF() - CHECK_C_SOURCE_COMPILES("int foo() __attribute__((destructor)); - int main() {return 0;}" HAVE_GCC_DESTRUCTOR) - option(ALSOFT_STATIC_LIBGCC "Force -static-libgcc for static GCC runtimes" OFF) if(ALSOFT_STATIC_LIBGCC) set(OLD_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) @@ -474,7 +471,6 @@ IF(HAVE_INTRIN_H) }" HAVE_BITSCANFORWARD_INTRINSIC) ENDIF() -CHECK_SYMBOL_EXISTS(sysconf unistd.h HAVE_SYSCONF) CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN) CHECK_SYMBOL_EXISTS(_aligned_malloc malloc.h HAVE__ALIGNED_MALLOC) CHECK_SYMBOL_EXISTS(proc_pidpath libproc.h HAVE_PROC_PIDPATH) diff --git a/config.h.in b/config.h.in index dbf35eda..9305e2a9 100644 --- a/config.h.in +++ b/config.h.in @@ -8,9 +8,6 @@ /* Define if HRTF data is embedded in the library */ #cmakedefine ALSOFT_EMBED_HRTF_DATA -/* Define if we have the sysconf function */ -#cmakedefine HAVE_SYSCONF - /* Define if we have the posix_memalign function */ #cmakedefine HAVE_POSIX_MEMALIGN @@ -86,9 +83,6 @@ /* Define to the size of a long long int type */ #cmakedefine SIZEOF_LONG_LONG ${SIZEOF_LONG_LONG} -/* Define if we have GCC's destructor attribute */ -#cmakedefine HAVE_GCC_DESTRUCTOR - /* Define if we have GCC's format attribute */ #cmakedefine HAVE_GCC_FORMAT -- cgit v1.2.3 From b4d56d3fdff4243ae2a3fc64934ced2af3187690 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Jul 2019 17:15:34 -0700 Subject: Remove the UNUSED macro --- Alc/backends/base.cpp | 2 +- Alc/backends/coreaudio.cpp | 11 +++++------ Alc/backends/dsound.cpp | 2 +- Alc/backends/loopback.cpp | 4 ++-- Alc/backends/opensl.cpp | 4 ++-- Alc/backends/portaudio.cpp | 12 ++++++------ Alc/backends/pulseaudio.cpp | 10 +++++----- Alc/backends/winmm.cpp | 6 ++---- Alc/effects/autowah.cpp | 2 +- Alc/effects/compressor.cpp | 2 +- Alc/effects/dedicated.cpp | 4 ++-- Alc/effects/distortion.cpp | 2 +- Alc/effects/equalizer.cpp | 2 +- Alc/effects/fshifter.cpp | 2 +- Alc/effects/modulator.cpp | 4 ++-- Alc/effects/null.cpp | 23 +++++++++++++---------- Alc/effects/pshifter.cpp | 2 +- Alc/effects/vmorpher.cpp | 11 +++++------ Alc/hrtf.cpp | 2 +- Alc/mixer/mixer_c.cpp | 5 ++--- Alc/mixer/mixer_neon.cpp | 5 ++--- Alc/mixer/mixer_sse2.cpp | 5 ++--- Alc/mixer/mixer_sse41.cpp | 5 ++--- OpenAL32/Include/alMain.h | 13 ------------- OpenAL32/alBuffer.cpp | 26 +++++++++++++------------- OpenAL32/alFilter.cpp | 40 ++++++++++++++++++++-------------------- OpenAL32/alListener.cpp | 2 +- router/router.cpp | 2 +- router/router.h | 12 ------------ 29 files changed, 96 insertions(+), 126 deletions(-) diff --git a/Alc/backends/base.cpp b/Alc/backends/base.cpp index 5239ae5b..5748975e 100644 --- a/Alc/backends/base.cpp +++ b/Alc/backends/base.cpp @@ -29,7 +29,7 @@ BackendBase::~BackendBase() = default; ALCboolean BackendBase::reset() { return ALC_FALSE; } -ALCenum BackendBase::captureSamples(void* UNUSED(buffer), ALCuint UNUSED(samples)) +ALCenum BackendBase::captureSamples(void*, ALCuint) { return ALC_INVALID_DEVICE; } ALCuint BackendBase::availableSamples() diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index a776cb9e..c6978505 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -81,9 +81,8 @@ OSStatus CoreAudioPlayback::MixerProcC(void *inRefCon, inBusNumber, inNumberFrames, ioData); } -OSStatus CoreAudioPlayback::MixerProc(AudioUnitRenderActionFlags* UNUSED(ioActionFlags), - const AudioTimeStamp* UNUSED(inTimeStamp), UInt32 UNUSED(inBusNumber), - UInt32 UNUSED(inNumberFrames), AudioBufferList *ioData) +OSStatus CoreAudioPlayback::MixerProc(AudioUnitRenderActionFlags*, + const AudioTimeStamp*, UInt32, UInt32, AudioBufferList *ioData) { lock(); aluMixData(mDevice, ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize/mFrameSize); @@ -347,9 +346,9 @@ OSStatus CoreAudioCapture::RecordProcC(void *inRefCon, inBusNumber, inNumberFrames, ioData); } -OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags* UNUSED(ioActionFlags), - const AudioTimeStamp *inTimeStamp, UInt32 UNUSED(inBusNumber), UInt32 inNumberFrames, - AudioBufferList* UNUSED(ioData)) +OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags*, + const AudioTimeStamp *inTimeStamp, UInt32, UInt32 inNumberFrames, + AudioBufferList*) { AudioUnitRenderActionFlags flags = 0; union { diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index 5c77df60..d4c1033c 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -127,7 +127,7 @@ bool checkName(const al::vector &list, const std::string &name) ) != list.cend(); } -BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR* UNUSED(drvname), void *data) +BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR*, void *data) { if(!guid) return TRUE; diff --git a/Alc/backends/loopback.cpp b/Alc/backends/loopback.cpp index 5d133d8e..77606b89 100644 --- a/Alc/backends/loopback.cpp +++ b/Alc/backends/loopback.cpp @@ -64,13 +64,13 @@ void LoopbackBackend::stop() bool LoopbackBackendFactory::init() { return true; } -bool LoopbackBackendFactory::querySupport(BackendType UNUSED(type)) +bool LoopbackBackendFactory::querySupport(BackendType) { return true; } void LoopbackBackendFactory::probe(DevProbe, std::string*) { } -BackendPtr LoopbackBackendFactory::createBackend(ALCdevice *device, BackendType UNUSED(type)) +BackendPtr LoopbackBackendFactory::createBackend(ALCdevice *device, BackendType) { return BackendPtr{new LoopbackBackend{device}}; } BackendFactory &LoopbackBackendFactory::getFactory() diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index be483338..452028ea 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -198,7 +198,7 @@ OpenSLPlayback::~OpenSLPlayback() void OpenSLPlayback::processC(SLAndroidSimpleBufferQueueItf bq, void *context) { static_cast(context)->process(bq); } -void OpenSLPlayback::process(SLAndroidSimpleBufferQueueItf UNUSED(bq)) +void OpenSLPlayback::process(SLAndroidSimpleBufferQueueItf) { /* A note on the ringbuffer usage: The buffer queue seems to hold on to the * pointer passed to the Enqueue method, rather than copying the audio. @@ -650,7 +650,7 @@ OpenSLCapture::~OpenSLCapture() void OpenSLCapture::processC(SLAndroidSimpleBufferQueueItf bq, void *context) { static_cast(context)->process(bq); } -void OpenSLCapture::process(SLAndroidSimpleBufferQueueItf UNUSED(bq)) +void OpenSLCapture::process(SLAndroidSimpleBufferQueueItf) { /* A new chunk has been written into the ring buffer, advance it. */ mRing->writeAdvance(1); diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index 5277f36b..10c8261b 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -109,9 +109,9 @@ int PortPlayback::writeCallbackC(const void *inputBuffer, void *outputBuffer, framesPerBuffer, timeInfo, statusFlags); } -int PortPlayback::writeCallback(const void* UNUSED(inputBuffer), void *outputBuffer, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* UNUSED(timeInfo), - const PaStreamCallbackFlags UNUSED(statusFlags)) +int PortPlayback::writeCallback(const void*, void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo*, + const PaStreamCallbackFlags) { lock(); aluMixData(mDevice, outputBuffer, framesPerBuffer); @@ -275,9 +275,9 @@ int PortCapture::readCallbackC(const void *inputBuffer, void *outputBuffer, framesPerBuffer, timeInfo, statusFlags); } -int PortCapture::readCallback(const void *inputBuffer, void *UNUSED(outputBuffer), - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo), - const PaStreamCallbackFlags UNUSED(statusFlags)) +int PortCapture::readCallback(const void *inputBuffer, void*, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo*, + const PaStreamCallbackFlags) { mRing->write(inputBuffer, framesPerBuffer); return 0; diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index a19663eb..97736253 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -496,7 +496,7 @@ pa_stream *pulse_connect_stream(const char *device_name, std::unique_lock(pdata)->sinkInfoCallback(context, info, eol); } -void PulsePlayback::sinkInfoCallback(pa_context* UNUSED(context), const pa_sink_info *info, int eol) +void PulsePlayback::sinkInfoCallback(pa_context*, const pa_sink_info *info, int eol) { struct ChannelMap { DevFmtChannels chans; @@ -798,7 +798,7 @@ void PulsePlayback::sinkInfoCallback(pa_context* UNUSED(context), const pa_sink_ void PulsePlayback::sinkNameCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata) { static_cast(pdata)->sinkNameCallback(context, info, eol); } -void PulsePlayback::sinkNameCallback(pa_context* UNUSED(context), const pa_sink_info *info, int eol) +void PulsePlayback::sinkNameCallback(pa_context*, const pa_sink_info *info, int eol) { if(eol) { @@ -1171,7 +1171,7 @@ void PulseCapture::streamStateCallback(pa_stream *stream) void PulseCapture::sourceNameCallbackC(pa_context *context, const pa_source_info *info, int eol, void *pdata) { static_cast(pdata)->sourceNameCallback(context, info, eol); } -void PulseCapture::sourceNameCallback(pa_context* UNUSED(context), const pa_source_info *info, int eol) +void PulseCapture::sourceNameCallback(pa_context*, const pa_source_info *info, int eol) { if(eol) { diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index f23ac53c..57abee06 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -169,8 +169,7 @@ void CALLBACK WinMMPlayback::waveOutProcC(HWAVEOUT device, UINT msg, DWORD_PTR i * Posts a message to 'WinMMPlayback::mixerProc' everytime a WaveOut Buffer is * completed and returns to the application (for more data) */ -void CALLBACK WinMMPlayback::waveOutProc(HWAVEOUT UNUSED(device), UINT msg, - DWORD_PTR UNUSED(param1), DWORD_PTR UNUSED(param2)) +void CALLBACK WinMMPlayback::waveOutProc(HWAVEOUT, UINT msg, DWORD_PTR, DWORD_PTR) { if(msg != WOM_DONE) return; mWritable.fetch_add(1, std::memory_order_acq_rel); @@ -414,8 +413,7 @@ void CALLBACK WinMMCapture::waveInProcC(HWAVEIN device, UINT msg, DWORD_PTR inst * Posts a message to 'WinMMCapture::captureProc' everytime a WaveIn Buffer is * completed and returns to the application (with more data). */ -void CALLBACK WinMMCapture::waveInProc(HWAVEIN UNUSED(device), UINT msg, - DWORD_PTR UNUSED(param1), DWORD_PTR UNUSED(param2)) +void CALLBACK WinMMCapture::waveInProc(HWAVEIN, UINT msg, DWORD_PTR, DWORD_PTR) { if(msg != WIM_DATA) return; mReadable.fetch_add(1, std::memory_order_acq_rel); diff --git a/Alc/effects/autowah.cpp b/Alc/effects/autowah.cpp index f1160804..8545de1f 100644 --- a/Alc/effects/autowah.cpp +++ b/Alc/effects/autowah.cpp @@ -77,7 +77,7 @@ struct ALautowahState final : public EffectState { DEF_NEWDEL(ALautowahState) }; -ALboolean ALautowahState::deviceUpdate(const ALCdevice *UNUSED(device)) +ALboolean ALautowahState::deviceUpdate(const ALCdevice*) { /* (Re-)initializing parameters and clear the buffers. */ diff --git a/Alc/effects/compressor.cpp b/Alc/effects/compressor.cpp index 542ef684..82f70317 100644 --- a/Alc/effects/compressor.cpp +++ b/Alc/effects/compressor.cpp @@ -74,7 +74,7 @@ ALboolean CompressorState::deviceUpdate(const ALCdevice *device) return AL_TRUE; } -void CompressorState::update(const ALCcontext* UNUSED(context), const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) +void CompressorState::update(const ALCcontext*, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { mEnabled = props->Compressor.OnOff; diff --git a/Alc/effects/dedicated.cpp b/Alc/effects/dedicated.cpp index b5fdb626..f31cc903 100644 --- a/Alc/effects/dedicated.cpp +++ b/Alc/effects/dedicated.cpp @@ -45,13 +45,13 @@ struct DedicatedState final : public EffectState { DEF_NEWDEL(DedicatedState) }; -ALboolean DedicatedState::deviceUpdate(const ALCdevice *UNUSED(device)) +ALboolean DedicatedState::deviceUpdate(const ALCdevice*) { std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f); return AL_TRUE; } -void DedicatedState::update(const ALCcontext* UNUSED(context), const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) +void DedicatedState::update(const ALCcontext*, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f); diff --git a/Alc/effects/distortion.cpp b/Alc/effects/distortion.cpp index a58ac5a6..94af9e11 100644 --- a/Alc/effects/distortion.cpp +++ b/Alc/effects/distortion.cpp @@ -55,7 +55,7 @@ struct DistortionState final : public EffectState { DEF_NEWDEL(DistortionState) }; -ALboolean DistortionState::deviceUpdate(const ALCdevice *UNUSED(device)) +ALboolean DistortionState::deviceUpdate(const ALCdevice*) { mLowpass.clear(); mBandpass.clear(); diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index 995f03df..961ae8fc 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -99,7 +99,7 @@ struct EqualizerState final : public EffectState { DEF_NEWDEL(EqualizerState) }; -ALboolean EqualizerState::deviceUpdate(const ALCdevice *UNUSED(device)) +ALboolean EqualizerState::deviceUpdate(const ALCdevice*) { for(auto &e : mChans) { diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp index 6378db89..68e10cba 100644 --- a/Alc/effects/fshifter.cpp +++ b/Alc/effects/fshifter.cpp @@ -88,7 +88,7 @@ struct FshifterState final : public EffectState { DEF_NEWDEL(FshifterState) }; -ALboolean FshifterState::deviceUpdate(const ALCdevice *UNUSED(device)) +ALboolean FshifterState::deviceUpdate(const ALCdevice*) { /* (Re-)initializing parameters and clear the buffers. */ mCount = FIFO_LATENCY; diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index 46d17d1c..8377aefe 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -59,7 +59,7 @@ inline ALfloat Square(ALsizei index) return static_cast(((index>>(WAVEFORM_FRACBITS-2))&2) - 1); } -inline ALfloat One(ALsizei UNUSED(index)) +inline ALfloat One(ALsizei) { return 1.0f; } @@ -98,7 +98,7 @@ struct ModulatorState final : public EffectState { DEF_NEWDEL(ModulatorState) }; -ALboolean ModulatorState::deviceUpdate(const ALCdevice *UNUSED(device)) +ALboolean ModulatorState::deviceUpdate(const ALCdevice*) { for(auto &e : mChans) { diff --git a/Alc/effects/null.cpp b/Alc/effects/null.cpp index 6076a2d9..3c27bae0 100644 --- a/Alc/effects/null.cpp +++ b/Alc/effects/null.cpp @@ -34,20 +34,21 @@ NullState::NullState() = default; */ NullState::~NullState() = default; -/* This updates the device-dependant effect state. This is called on +/* This updates the device-dependant effect state. This is called on state * initialization and any time the device parameters (e.g. playback frequency, * format) have been changed. Will always be followed by a call to the update * method, if successful. */ -ALboolean NullState::deviceUpdate(const ALCdevice* UNUSED(device)) +ALboolean NullState::deviceUpdate(const ALCdevice* /*device*/) { return AL_TRUE; } -/* This updates the effect state. This is called any time the effect is - * (re)loaded into a slot. +/* This updates the effect state with new properties. This is called any time + * the effect is (re)loaded into a slot. */ -void NullState::update(const ALCcontext* UNUSED(context), const ALeffectslot* UNUSED(slot), const EffectProps* UNUSED(props), const EffectTarget UNUSED(target)) +void NullState::update(const ALCcontext* /*context*/, const ALeffectslot* /*slot*/, + const EffectProps* /*props*/, const EffectTarget /*target*/) { } @@ -55,12 +56,14 @@ void NullState::update(const ALCcontext* UNUSED(context), const ALeffectslot* UN * input to the output buffer. The result should be added to the output buffer, * not replace it. */ -void NullState::process(const ALsizei /*samplesToDo*/, const FloatBufferLine *RESTRICT /*samplesIn*/, const ALsizei /*numInput*/, const al::span /*samplesOut*/) +void NullState::process(const ALsizei /*samplesToDo*/, + const FloatBufferLine *RESTRICT /*samplesIn*/, const ALsizei /*numInput*/, + const al::span /*samplesOut*/) { } -void NullEffect_setParami(EffectProps *UNUSED(props), ALCcontext *context, ALenum param, ALint UNUSED(val)) +void NullEffect_setParami(EffectProps* /*props*/, ALCcontext *context, ALenum param, ALint /*val*/) { switch(param) { @@ -76,7 +79,7 @@ void NullEffect_setParamiv(EffectProps *props, ALCcontext *context, ALenum param NullEffect_setParami(props, context, param, vals[0]); } } -void NullEffect_setParamf(EffectProps *UNUSED(props), ALCcontext *context, ALenum param, ALfloat UNUSED(val)) +void NullEffect_setParamf(EffectProps* /*props*/, ALCcontext *context, ALenum param, ALfloat /*val*/) { switch(param) { @@ -93,7 +96,7 @@ void NullEffect_setParamfv(EffectProps *props, ALCcontext *context, ALenum param } } -void NullEffect_getParami(const EffectProps *UNUSED(props), ALCcontext *context, ALenum param, ALint* UNUSED(val)) +void NullEffect_getParami(const EffectProps* /*props*/, ALCcontext *context, ALenum param, ALint* /*val*/) { switch(param) { @@ -109,7 +112,7 @@ void NullEffect_getParamiv(const EffectProps *props, ALCcontext *context, ALenum NullEffect_getParami(props, context, param, vals); } } -void NullEffect_getParamf(const EffectProps *UNUSED(props), ALCcontext *context, ALenum param, ALfloat* UNUSED(val)) +void NullEffect_getParamf(const EffectProps* /*props*/, ALCcontext *context, ALenum param, ALfloat* /*val*/) { switch(param) { diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp index 5a1e3817..bade81e6 100644 --- a/Alc/effects/pshifter.cpp +++ b/Alc/effects/pshifter.cpp @@ -181,7 +181,7 @@ ALboolean PshifterState::deviceUpdate(const ALCdevice *device) return AL_TRUE; } -void PshifterState::update(const ALCcontext* UNUSED(context), const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) +void PshifterState::update(const ALCcontext*, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { const float pitch{std::pow(2.0f, static_cast(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f diff --git a/Alc/effects/vmorpher.cpp b/Alc/effects/vmorpher.cpp index dc402aaf..6f7e22ae 100644 --- a/Alc/effects/vmorpher.cpp +++ b/Alc/effects/vmorpher.cpp @@ -47,22 +47,21 @@ namespace { inline ALfloat Sin(ALsizei index) { - return (std::sin(static_cast(index) * - (al::MathDefs::Tau() / ALfloat{WAVEFORM_FRACONE})))*0.5f+0.5f; + constexpr ALfloat scale{al::MathDefs::Tau() / ALfloat{WAVEFORM_FRACONE}}; + return std::sin(static_cast(index) * scale)*0.5f + 0.5f; } inline ALfloat Saw(ALsizei index) { - return (static_cast(index)*(2.0f/WAVEFORM_FRACONE) - 1.0f)*0.5f+0.5f; + return static_cast(index) / ALfloat{WAVEFORM_FRACONE}; } inline ALfloat Triangle(ALsizei index) { - return (std::fabs(static_cast(index) * (al::MathDefs::Tau() / WAVEFORM_FRACONE) - - al::MathDefs::Pi()) / al::MathDefs::Pi())*0.5f+0.5f; + return std::fabs(static_cast(index)*(2.0f/WAVEFORM_FRACONE) - 1.0f); } -inline ALfloat Half(ALsizei UNUSED(index)) +inline ALfloat Half(ALsizei) { return 0.5f; } diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 5561ebfd..73cdc24e 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -1195,7 +1195,7 @@ void AddBuiltInEntry(al::vector &list, const std::string &filena using ResData = al::span; #ifndef ALSOFT_EMBED_HRTF_DATA -ResData GetResource(int UNUSED(name)) +ResData GetResource(int /*name*/) { return ResData{}; } #else diff --git a/Alc/mixer/mixer_c.cpp b/Alc/mixer/mixer_c.cpp index 86a9e438..b9d51c9c 100644 --- a/Alc/mixer/mixer_c.cpp +++ b/Alc/mixer/mixer_c.cpp @@ -70,9 +70,8 @@ const ALfloat *DoResample(const InterpState *state, const ALfloat *RESTRICT src, } // namespace template<> -const ALfloat *Resample_(const InterpState* UNUSED(state), - const ALfloat *RESTRICT src, ALsizei UNUSED(frac), ALint UNUSED(increment), - ALfloat *RESTRICT dst, ALsizei dstlen) +const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, ALsizei, + ALint, ALfloat *RESTRICT dst, ALsizei dstlen) { ASSUME(dstlen > 0); #if defined(HAVE_SSE) || defined(HAVE_NEON) diff --git a/Alc/mixer/mixer_neon.cpp b/Alc/mixer/mixer_neon.cpp index c30e9861..81d0ff67 100644 --- a/Alc/mixer/mixer_neon.cpp +++ b/Alc/mixer/mixer_neon.cpp @@ -15,9 +15,8 @@ template<> -const ALfloat *Resample_(const InterpState* UNUSED(state), - const ALfloat *RESTRICT src, ALsizei frac, ALint increment, - ALfloat *RESTRICT dst, ALsizei dstlen) +const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) { const int32x4_t increment4 = vdupq_n_s32(increment*4); const float32x4_t fracOne4 = vdupq_n_f32(1.0f/FRACTIONONE); diff --git a/Alc/mixer/mixer_sse2.cpp b/Alc/mixer/mixer_sse2.cpp index 2b594d90..b5d00106 100644 --- a/Alc/mixer/mixer_sse2.cpp +++ b/Alc/mixer/mixer_sse2.cpp @@ -28,9 +28,8 @@ template<> -const ALfloat *Resample_(const InterpState* UNUSED(state), - const ALfloat *RESTRICT src, ALsizei frac, ALint increment, - ALfloat *RESTRICT dst, ALsizei dstlen) +const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) { const __m128i increment4{_mm_set1_epi32(increment*4)}; const __m128 fracOne4{_mm_set1_ps(1.0f/FRACTIONONE)}; diff --git a/Alc/mixer/mixer_sse41.cpp b/Alc/mixer/mixer_sse41.cpp index 55639f11..7efbda7b 100644 --- a/Alc/mixer/mixer_sse41.cpp +++ b/Alc/mixer/mixer_sse41.cpp @@ -29,9 +29,8 @@ template<> -const ALfloat *Resample_(const InterpState* UNUSED(state), - const ALfloat *RESTRICT src, ALsizei frac, ALint increment, - ALfloat *RESTRICT dst, ALsizei dstlen) +const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) { const __m128i increment4{_mm_set1_epi32(increment*4)}; const __m128 fracOne4{_mm_set1_ps(1.0f/FRACTIONONE)}; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 33b2fc39..85bc9cbc 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -38,19 +38,6 @@ struct Uhj2Encoder; struct bs2b; -#ifndef UNUSED -#if defined(__cplusplus) -#define UNUSED(x) -#elif defined(__GNUC__) -#define UNUSED(x) UNUSED_##x __attribute__((unused)) -#elif defined(__LCLINT__) -#define UNUSED(x) /*@unused@*/ x -#else -#define UNUSED(x) x -#endif -#endif - - #if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) #define IS_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) #else diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index f20b0aee..843d4e76 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -759,9 +759,9 @@ START_API_FUNC END_API_FUNC -AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint UNUSED(buffer), - ALuint UNUSED(samplerate), ALenum UNUSED(internalformat), ALsizei UNUSED(samples), - ALenum UNUSED(channels), ALenum UNUSED(type), const ALvoid *UNUSED(data)) +AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint /*buffer*/, ALuint /*samplerate*/, + ALenum /*internalformat*/, ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, + const ALvoid* /*data*/) START_API_FUNC { ContextRef context{GetContextRef()}; @@ -771,9 +771,8 @@ START_API_FUNC } END_API_FUNC -AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint UNUSED(buffer), - ALsizei UNUSED(offset), ALsizei UNUSED(samples), - ALenum UNUSED(channels), ALenum UNUSED(type), const ALvoid *UNUSED(data)) +AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint /*buffer*/, ALsizei /*offset*/, + ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, const ALvoid* /*data*/) START_API_FUNC { ContextRef context{GetContextRef()}; @@ -783,9 +782,8 @@ START_API_FUNC } END_API_FUNC -AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint UNUSED(buffer), - ALsizei UNUSED(offset), ALsizei UNUSED(samples), - ALenum UNUSED(channels), ALenum UNUSED(type), ALvoid *UNUSED(data)) +AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint /*buffer*/, ALsizei /*offset*/, + ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, ALvoid* /*data*/) START_API_FUNC { ContextRef context{GetContextRef()}; @@ -795,7 +793,7 @@ START_API_FUNC } END_API_FUNC -AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum UNUSED(format)) +AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum /*format*/) START_API_FUNC { ContextRef context{GetContextRef()}; @@ -807,7 +805,7 @@ START_API_FUNC END_API_FUNC -AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(value)) +AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat /*value*/) START_API_FUNC { ContextRef context{GetContextRef()}; @@ -826,7 +824,8 @@ START_API_FUNC } END_API_FUNC -AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat UNUSED(value1), ALfloat UNUSED(value2), ALfloat UNUSED(value3)) +AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, + ALfloat /*value1*/, ALfloat /*value2*/, ALfloat /*value3*/) START_API_FUNC { ContextRef context{GetContextRef()}; @@ -901,7 +900,8 @@ START_API_FUNC } END_API_FUNC -AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint UNUSED(value1), ALint UNUSED(value2), ALint UNUSED(value3)) +AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, + ALint /*value1*/, ALint /*value2*/, ALint /*value3*/) START_API_FUNC { ContextRef context{GetContextRef()}; diff --git a/OpenAL32/alFilter.cpp b/OpenAL32/alFilter.cpp index d7826b6f..209ddc87 100644 --- a/OpenAL32/alFilter.cpp +++ b/OpenAL32/alFilter.cpp @@ -37,9 +37,9 @@ namespace { #define FILTER_MIN_GAIN 0.0f #define FILTER_MAX_GAIN 4.0f /* +12dB */ -void ALlowpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) +void ALlowpass_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) { alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } -void ALlowpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +void ALlowpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) { alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } void ALlowpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) { @@ -64,9 +64,9 @@ void ALlowpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, AL void ALlowpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) { ALlowpass_setParamf(filter, context, param, vals[0]); } -void ALlowpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +void ALlowpass_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) { alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } -void ALlowpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +void ALlowpass_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) { alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) { @@ -90,9 +90,9 @@ void ALlowpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, A DEFINE_ALFILTER_VTABLE(ALlowpass); -void ALhighpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) +void ALhighpass_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) { alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } -void ALhighpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +void ALhighpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) { alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) { @@ -117,9 +117,9 @@ void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, A void ALhighpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) { ALhighpass_setParamf(filter, context, param, vals[0]); } -void ALhighpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +void ALhighpass_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) { alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } -void ALhighpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +void ALhighpass_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) { alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) { @@ -143,9 +143,9 @@ void ALhighpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, DEFINE_ALFILTER_VTABLE(ALhighpass); -void ALbandpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) +void ALbandpass_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) { alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } -void ALbandpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +void ALbandpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) { alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) { @@ -176,9 +176,9 @@ void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, A void ALbandpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) { ALbandpass_setParamf(filter, context, param, vals[0]); } -void ALbandpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +void ALbandpass_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) { alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } -void ALbandpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +void ALbandpass_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) { alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) { @@ -206,22 +206,22 @@ void ALbandpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, DEFINE_ALFILTER_VTABLE(ALbandpass); -void ALnullfilter_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) +void ALnullfilter_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -void ALnullfilter_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +void ALnullfilter_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -void ALnullfilter_setParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat UNUSED(val)) +void ALnullfilter_setParamf(ALfilter*, ALCcontext *context, ALenum param, ALfloat) { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -void ALnullfilter_setParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALfloat *UNUSED(vals)) +void ALnullfilter_setParamfv(ALfilter*, ALCcontext *context, ALenum param, const ALfloat*) { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -void ALnullfilter_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +void ALnullfilter_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -void ALnullfilter_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +void ALnullfilter_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -void ALnullfilter_getParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat *UNUSED(val)) +void ALnullfilter_getParamf(ALfilter*, ALCcontext *context, ALenum param, ALfloat*) { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -void ALnullfilter_getParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat *UNUSED(vals)) +void ALnullfilter_getParamfv(ALfilter*, ALCcontext *context, ALenum param, ALfloat*) { alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } DEFINE_ALFILTER_VTABLE(ALnullfilter); diff --git a/OpenAL32/alListener.cpp b/OpenAL32/alListener.cpp index 232aba33..419e38ad 100644 --- a/OpenAL32/alListener.cpp +++ b/OpenAL32/alListener.cpp @@ -154,7 +154,7 @@ START_API_FUNC END_API_FUNC -AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value)) +AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint /*value*/) START_API_FUNC { ContextRef context{GetContextRef()}; diff --git a/router/router.cpp b/router/router.cpp index 5b976e95..e9173a22 100644 --- a/router/router.cpp +++ b/router/router.cpp @@ -25,7 +25,7 @@ FILE *LogFile; static void LoadDriverList(void); -BOOL APIENTRY DllMain(HINSTANCE UNUSED(module), DWORD reason, void* UNUSED(reserved)) +BOOL APIENTRY DllMain(HINSTANCE, DWORD reason, void*) { const char *str; diff --git a/router/router.h b/router/router.h index d2574e74..007b6a16 100644 --- a/router/router.h +++ b/router/router.h @@ -17,18 +17,6 @@ #include "AL/alext.h" -#ifndef UNUSED -#if defined(__cplusplus) -#define UNUSED(x) -#elif defined(__GNUC__) -#define UNUSED(x) UNUSED_##x __attribute__((unused)) -#elif defined(__LCLINT__) -#define UNUSED(x) /*@unused@*/ x -#else -#define UNUSED(x) x -#endif -#endif - #define MAKE_ALC_VER(major, minor) (((major)<<8) | (minor)) struct DriverIface { -- cgit v1.2.3 From bb0062625f13bd64c9f83f8c482eae119009a48f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Jul 2019 17:22:00 -0700 Subject: Move the ADPCM decoders to alBuffer.cpp --- CMakeLists.txt | 2 - OpenAL32/Include/sample_cvt.h | 13 --- OpenAL32/alBuffer.cpp | 184 ++++++++++++++++++++++++++++++++++++++- OpenAL32/sample_cvt.cpp | 195 ------------------------------------------ 4 files changed, 183 insertions(+), 211 deletions(-) delete mode 100644 OpenAL32/Include/sample_cvt.h delete mode 100644 OpenAL32/sample_cvt.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 53361f0b..0a9d04ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -639,8 +639,6 @@ SET(OPENAL_OBJS OpenAL32/alSource.cpp OpenAL32/alState.cpp OpenAL32/event.cpp - OpenAL32/Include/sample_cvt.h - OpenAL32/sample_cvt.cpp ) SET(ALC_OBJS Alc/alc.cpp diff --git a/OpenAL32/Include/sample_cvt.h b/OpenAL32/Include/sample_cvt.h deleted file mode 100644 index c8c1ad23..00000000 --- a/OpenAL32/Include/sample_cvt.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef SAMPLE_CVT_H -#define SAMPLE_CVT_H - -#include "AL/al.h" -#include "albyte.h" - - -void Convert_ALshort_ALima4(ALshort *dst, const al::byte *src, ALsizei numchans, ALsizei len, - ALsizei align); -void Convert_ALshort_ALmsadpcm(ALshort *dst, const al::byte *src, ALsizei numchans, ALsizei len, - ALsizei align); - -#endif /* SAMPLE_CVT_H */ diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index 843d4e76..c9a9d9f6 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -51,12 +51,194 @@ #include "atomic.h" #include "inprogext.h" #include "opthelpers.h" -#include "sample_cvt.h" #include "vector.h" namespace { +/* IMA ADPCM Stepsize table */ +constexpr int IMAStep_size[89] = { + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, + 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, + 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, + 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, + 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, + 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, + 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493,10442, + 11487,12635,13899,15289,16818,18500,20350,22358,24633,27086,29794, + 32767 +}; + +/* IMA4 ADPCM Codeword decode table */ +constexpr int IMA4Codeword[16] = { + 1, 3, 5, 7, 9, 11, 13, 15, + -1,-3,-5,-7,-9,-11,-13,-15, +}; + +/* IMA4 ADPCM Step index adjust decode table */ +constexpr int IMA4Index_adjust[16] = { + -1,-1,-1,-1, 2, 4, 6, 8, + -1,-1,-1,-1, 2, 4, 6, 8 +}; + + +/* MSADPCM Adaption table */ +constexpr int MSADPCMAdaption[16] = { + 230, 230, 230, 230, 307, 409, 512, 614, + 768, 614, 512, 409, 307, 230, 230, 230 +}; + +/* MSADPCM Adaption Coefficient tables */ +constexpr int MSADPCMAdaptionCoeff[7][2] = { + { 256, 0 }, + { 512, -256 }, + { 0, 0 }, + { 192, 64 }, + { 240, 0 }, + { 460, -208 }, + { 392, -232 } +}; + + +void DecodeIMA4Block(ALshort *dst, const al::byte *src, ALint numchans, ALsizei align) +{ + ALint sample[MAX_INPUT_CHANNELS]{}; + ALint index[MAX_INPUT_CHANNELS]{}; + ALuint code[MAX_INPUT_CHANNELS]{}; + + for(int c{0};c < numchans;c++) + { + sample[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + sample[c] = (sample[c]^0x8000) - 32768; + src += 2; + index[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + index[c] = clampi((index[c]^0x8000) - 32768, 0, 88); + src += 2; + + *(dst++) = sample[c]; + } + + for(int i{1};i < align;i++) + { + if((i&7) == 1) + { + for(int c{0};c < numchans;c++) + { + code[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<< 8) | + (al::to_integer(src[2])<<16) | (al::to_integer(src[3])<<24); + src += 4; + } + } + + for(int c{0};c < numchans;c++) + { + const ALuint nibble{code[c]&0xf}; + code[c] >>= 4; + + sample[c] += IMA4Codeword[nibble] * IMAStep_size[index[c]] / 8; + sample[c] = clampi(sample[c], -32768, 32767); + + index[c] += IMA4Index_adjust[nibble]; + index[c] = clampi(index[c], 0, 88); + + *(dst++) = sample[c]; + } + } +} + +void DecodeMSADPCMBlock(ALshort *dst, const al::byte *src, ALint numchans, ALsizei align) +{ + ALubyte blockpred[MAX_INPUT_CHANNELS]{}; + ALint delta[MAX_INPUT_CHANNELS]{}; + ALshort samples[MAX_INPUT_CHANNELS][2]{}; + + for(int c{0};c < numchans;c++) + { + blockpred[c] = minu(al::to_integer(src[0]), 6); + ++src; + } + for(int c{0};c < numchans;c++) + { + delta[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + delta[c] = (delta[c]^0x8000) - 32768; + src += 2; + } + for(int c{0};c < numchans;c++) + { + samples[c][0] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + samples[c][0] = (samples[c][0]^0x8000) - 32768; + src += 2; + } + for(int c{0};c < numchans;c++) + { + samples[c][1] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + samples[c][1] = (samples[c][1]^0x8000) - 32768; + src += 2; + } + + /* Second sample is written first. */ + for(int c{0};c < numchans;c++) + *(dst++) = samples[c][1]; + for(int c{0};c < numchans;c++) + *(dst++) = samples[c][0]; + + int num{0}; + for(int i{2};i < align;i++) + { + for(int c{0};c < numchans;c++) + { + /* Read the nibble (first is in the upper bits). */ + al::byte nibble; + if(!(num++ & 1)) + nibble = *src >> 4; + else + nibble = *(src++) & 0x0f; + + ALint pred{(samples[c][0]*MSADPCMAdaptionCoeff[blockpred[c]][0] + + samples[c][1]*MSADPCMAdaptionCoeff[blockpred[c]][1]) / 256}; + pred += (al::to_integer(nibble^0x08) - 0x08) * delta[c]; + pred = clampi(pred, -32768, 32767); + + samples[c][1] = samples[c][0]; + samples[c][0] = pred; + + delta[c] = (MSADPCMAdaption[al::to_integer(nibble)] * delta[c]) / 256; + delta[c] = maxi(16, delta[c]); + + *(dst++) = pred; + } + } +} + +void Convert_ALshort_ALima4(ALshort *dst, const al::byte *src, ALsizei numchans, ALsizei len, + ALsizei align) +{ + const ALsizei byte_align{((align-1)/2 + 4) * numchans}; + + len /= align; + while(len--) + { + DecodeIMA4Block(dst, src, numchans, align); + src += byte_align; + dst += align*numchans; + } +} + +void Convert_ALshort_ALmsadpcm(ALshort *dst, const al::byte *src, ALsizei numchans, ALsizei len, + ALsizei align) +{ + const ALsizei byte_align{((align-2)/2 + 7) * numchans}; + + len /= align; + while(len--) + { + DecodeMSADPCMBlock(dst, src, numchans, align); + src += byte_align; + dst += align*numchans; + } +} + + constexpr ALbitfieldSOFT INVALID_STORAGE_MASK{~unsigned(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT)}; constexpr ALbitfieldSOFT MAP_READ_WRITE_FLAGS{AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT}; diff --git a/OpenAL32/sample_cvt.cpp b/OpenAL32/sample_cvt.cpp deleted file mode 100644 index 79d0d1c5..00000000 --- a/OpenAL32/sample_cvt.cpp +++ /dev/null @@ -1,195 +0,0 @@ - -#include "config.h" - -#include "sample_cvt.h" - -#include "AL/al.h" -#include "alu.h" -#include "alBuffer.h" - - -namespace { - -/* IMA ADPCM Stepsize table */ -constexpr int IMAStep_size[89] = { - 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, - 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, - 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, - 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, - 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, - 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, - 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493,10442, - 11487,12635,13899,15289,16818,18500,20350,22358,24633,27086,29794, - 32767 -}; - -/* IMA4 ADPCM Codeword decode table */ -constexpr int IMA4Codeword[16] = { - 1, 3, 5, 7, 9, 11, 13, 15, - -1,-3,-5,-7,-9,-11,-13,-15, -}; - -/* IMA4 ADPCM Step index adjust decode table */ -constexpr int IMA4Index_adjust[16] = { - -1,-1,-1,-1, 2, 4, 6, 8, - -1,-1,-1,-1, 2, 4, 6, 8 -}; - - -/* MSADPCM Adaption table */ -constexpr int MSADPCMAdaption[16] = { - 230, 230, 230, 230, 307, 409, 512, 614, - 768, 614, 512, 409, 307, 230, 230, 230 -}; - -/* MSADPCM Adaption Coefficient tables */ -constexpr int MSADPCMAdaptionCoeff[7][2] = { - { 256, 0 }, - { 512, -256 }, - { 0, 0 }, - { 192, 64 }, - { 240, 0 }, - { 460, -208 }, - { 392, -232 } -}; - - -void DecodeIMA4Block(ALshort *dst, const al::byte *src, ALint numchans, ALsizei align) -{ - ALint sample[MAX_INPUT_CHANNELS]{}; - ALint index[MAX_INPUT_CHANNELS]{}; - ALuint code[MAX_INPUT_CHANNELS]{}; - - for(int c{0};c < numchans;c++) - { - sample[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); - sample[c] = (sample[c]^0x8000) - 32768; - src += 2; - index[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); - index[c] = clampi((index[c]^0x8000) - 32768, 0, 88); - src += 2; - - *(dst++) = sample[c]; - } - - for(int i{1};i < align;i++) - { - if((i&7) == 1) - { - for(int c{0};c < numchans;c++) - { - code[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<< 8) | - (al::to_integer(src[2])<<16) | (al::to_integer(src[3])<<24); - src += 4; - } - } - - for(int c{0};c < numchans;c++) - { - const ALuint nibble{code[c]&0xf}; - code[c] >>= 4; - - sample[c] += IMA4Codeword[nibble] * IMAStep_size[index[c]] / 8; - sample[c] = clampi(sample[c], -32768, 32767); - - index[c] += IMA4Index_adjust[nibble]; - index[c] = clampi(index[c], 0, 88); - - *(dst++) = sample[c]; - } - } -} - -void DecodeMSADPCMBlock(ALshort *dst, const al::byte *src, ALint numchans, ALsizei align) -{ - ALubyte blockpred[MAX_INPUT_CHANNELS]{}; - ALint delta[MAX_INPUT_CHANNELS]{}; - ALshort samples[MAX_INPUT_CHANNELS][2]{}; - - for(int c{0};c < numchans;c++) - { - blockpred[c] = minu(al::to_integer(src[0]), 6); - ++src; - } - for(int c{0};c < numchans;c++) - { - delta[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); - delta[c] = (delta[c]^0x8000) - 32768; - src += 2; - } - for(int c{0};c < numchans;c++) - { - samples[c][0] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); - samples[c][0] = (samples[c][0]^0x8000) - 32768; - src += 2; - } - for(int c{0};c < numchans;c++) - { - samples[c][1] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); - samples[c][1] = (samples[c][1]^0x8000) - 32768; - src += 2; - } - - /* Second sample is written first. */ - for(int c{0};c < numchans;c++) - *(dst++) = samples[c][1]; - for(int c{0};c < numchans;c++) - *(dst++) = samples[c][0]; - - int num{0}; - for(int i{2};i < align;i++) - { - for(int c{0};c < numchans;c++) - { - /* Read the nibble (first is in the upper bits). */ - al::byte nibble; - if(!(num++ & 1)) - nibble = *src >> 4; - else - nibble = *(src++) & 0x0f; - - ALint pred{(samples[c][0]*MSADPCMAdaptionCoeff[blockpred[c]][0] + - samples[c][1]*MSADPCMAdaptionCoeff[blockpred[c]][1]) / 256}; - pred += (al::to_integer(nibble^0x08) - 0x08) * delta[c]; - pred = clampi(pred, -32768, 32767); - - samples[c][1] = samples[c][0]; - samples[c][0] = pred; - - delta[c] = (MSADPCMAdaption[al::to_integer(nibble)] * delta[c]) / 256; - delta[c] = maxi(16, delta[c]); - - *(dst++) = pred; - } - } -} - -} // namespace - -void Convert_ALshort_ALima4(ALshort *dst, const al::byte *src, ALsizei numchans, ALsizei len, - ALsizei align) -{ - const ALsizei byte_align{((align-1)/2 + 4) * numchans}; - - len /= align; - while(len--) - { - DecodeIMA4Block(dst, src, numchans, align); - src += byte_align; - dst += align*numchans; - } -} - -void Convert_ALshort_ALmsadpcm(ALshort *dst, const al::byte *src, ALsizei numchans, ALsizei len, - ALsizei align) -{ - const ALsizei byte_align{((align-2)/2 + 7) * numchans}; - - len /= align; - while(len--) - { - DecodeMSADPCMBlock(dst, src, numchans, align); - src += byte_align; - dst += align*numchans; - } -} -- cgit v1.2.3 From 93e60919c8f387c36c267ca9faa1ac653254aea6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Jul 2019 18:33:29 -0700 Subject: Rename alMain.h to alcmain.h And move it and alu.h to Alc/. --- Alc/alc.cpp | 2 +- Alc/alcmain.h | 534 +++++++++++++++++++++++++++++++++++++ Alc/alconfig.cpp | 5 +- Alc/alu.cpp | 2 +- Alc/alu.h | 466 ++++++++++++++++++++++++++++++++ Alc/backends/alsa.cpp | 2 +- Alc/backends/base.cpp | 2 +- Alc/backends/base.h | 2 +- Alc/backends/coreaudio.cpp | 2 +- Alc/backends/dsound.cpp | 2 +- Alc/backends/jack.cpp | 2 +- Alc/backends/loopback.cpp | 2 +- Alc/backends/null.cpp | 2 +- Alc/backends/opensl.cpp | 2 +- Alc/backends/oss.cpp | 2 +- Alc/backends/portaudio.cpp | 2 +- Alc/backends/pulseaudio.cpp | 2 +- Alc/backends/qsa.cpp | 2 +- Alc/backends/sdl2.cpp | 2 +- Alc/backends/sndio.cpp | 2 +- Alc/backends/solaris.cpp | 2 +- Alc/backends/wasapi.cpp | 2 +- Alc/backends/wave.cpp | 2 +- Alc/backends/winmm.cpp | 2 +- Alc/bformatdec.h | 2 +- Alc/converter.h | 2 +- Alc/effects/autowah.cpp | 2 +- Alc/effects/base.h | 3 +- Alc/effects/chorus.cpp | 2 +- Alc/effects/compressor.cpp | 2 +- Alc/effects/dedicated.cpp | 2 +- Alc/effects/distortion.cpp | 2 +- Alc/effects/echo.cpp | 2 +- Alc/effects/equalizer.cpp | 2 +- Alc/effects/fshifter.cpp | 2 +- Alc/effects/modulator.cpp | 2 +- Alc/effects/null.cpp | 2 +- Alc/effects/pshifter.cpp | 2 +- Alc/effects/reverb.cpp | 2 +- Alc/effects/vmorpher.cpp | 2 +- Alc/filters/nfc.cpp | 2 +- Alc/filters/splitter.h | 2 +- Alc/helpers.cpp | 2 +- Alc/hrtf.cpp | 2 +- Alc/mastering.h | 2 +- Alc/mixer/defs.h | 4 +- Alc/mixer/mixer_c.cpp | 2 +- Alc/mixer/mixer_neon.cpp | 2 +- Alc/mixer/mixer_sse.cpp | 2 +- Alc/mixvoice.cpp | 2 +- Alc/panning.cpp | 2 +- Alc/uhjfilter.h | 2 +- CMakeLists.txt | 5 +- OpenAL32/Include/alAuxEffectSlot.h | 2 +- OpenAL32/Include/alEffect.h | 2 +- OpenAL32/Include/alError.h | 2 +- OpenAL32/Include/alMain.h | 534 ------------------------------------- OpenAL32/Include/alSource.h | 2 +- OpenAL32/Include/alu.h | 466 -------------------------------- OpenAL32/alAuxEffectSlot.cpp | 2 +- OpenAL32/alBuffer.cpp | 2 +- OpenAL32/alEffect.cpp | 2 +- OpenAL32/alError.cpp | 2 +- OpenAL32/alExtension.cpp | 2 +- OpenAL32/alFilter.cpp | 2 +- OpenAL32/alListener.cpp | 2 +- OpenAL32/alSource.cpp | 2 +- OpenAL32/alState.cpp | 2 +- OpenAL32/event.cpp | 2 +- 69 files changed, 1069 insertions(+), 1070 deletions(-) create mode 100644 Alc/alcmain.h create mode 100644 Alc/alu.h delete mode 100644 OpenAL32/Include/alMain.h delete mode 100644 OpenAL32/Include/alu.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp index 0bc099b4..00f90d91 100644 --- a/Alc/alc.cpp +++ b/Alc/alc.cpp @@ -52,11 +52,11 @@ #include "AL/efx.h" #include "alAuxEffectSlot.h" +#include "alcmain.h" #include "alEffect.h" #include "alError.h" #include "alFilter.h" #include "alListener.h" -#include "alMain.h" #include "alSource.h" #include "albyte.h" #include "alconfig.h" diff --git a/Alc/alcmain.h b/Alc/alcmain.h new file mode 100644 index 00000000..a22e0e81 --- /dev/null +++ b/Alc/alcmain.h @@ -0,0 +1,534 @@ +#ifndef ALC_MAIN_H +#define ALC_MAIN_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" + +#include "albyte.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "alspan.h" +#include "ambidefs.h" +#include "atomic.h" +#include "hrtf.h" +#include "inprogext.h" +#include "vector.h" + +class BFormatDec; +struct ALbuffer; +struct ALeffect; +struct ALfilter; +struct BackendBase; +struct Compressor; +struct EffectState; +struct FrontStablizer; +struct Uhj2Encoder; +struct bs2b; + + +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) +#define IS_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#else +static const union { + ALuint u; + ALubyte b[sizeof(ALuint)]; +} EndianTest = { 1 }; +#define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1) +#endif + + +#define MIN_OUTPUT_RATE 8000 +#define DEFAULT_OUTPUT_RATE 44100 +#define DEFAULT_UPDATE_SIZE 882 /* 20ms */ +#define DEFAULT_NUM_UPDATES 3 + + +enum Channel { + FrontLeft = 0, + FrontRight, + FrontCenter, + LFE, + BackLeft, + BackRight, + BackCenter, + SideLeft, + SideRight, + + UpperFrontLeft, + UpperFrontRight, + UpperBackLeft, + UpperBackRight, + LowerFrontLeft, + LowerFrontRight, + LowerBackLeft, + LowerBackRight, + + Aux0, + Aux1, + Aux2, + Aux3, + Aux4, + Aux5, + Aux6, + Aux7, + Aux8, + Aux9, + Aux10, + Aux11, + Aux12, + Aux13, + Aux14, + Aux15, + + MaxChannels +}; + + +/* Device formats */ +enum DevFmtType : ALenum { + DevFmtByte = ALC_BYTE_SOFT, + DevFmtUByte = ALC_UNSIGNED_BYTE_SOFT, + DevFmtShort = ALC_SHORT_SOFT, + DevFmtUShort = ALC_UNSIGNED_SHORT_SOFT, + DevFmtInt = ALC_INT_SOFT, + DevFmtUInt = ALC_UNSIGNED_INT_SOFT, + DevFmtFloat = ALC_FLOAT_SOFT, + + DevFmtTypeDefault = DevFmtFloat +}; +enum DevFmtChannels : ALenum { + DevFmtMono = ALC_MONO_SOFT, + DevFmtStereo = ALC_STEREO_SOFT, + DevFmtQuad = ALC_QUAD_SOFT, + DevFmtX51 = ALC_5POINT1_SOFT, + DevFmtX61 = ALC_6POINT1_SOFT, + DevFmtX71 = ALC_7POINT1_SOFT, + DevFmtAmbi3D = ALC_BFORMAT3D_SOFT, + + /* Similar to 5.1, except using rear channels instead of sides */ + DevFmtX51Rear = 0x70000000, + + DevFmtChannelsDefault = DevFmtStereo +}; +#define MAX_OUTPUT_CHANNELS (16) + +/* DevFmtType traits, providing the type, etc given a DevFmtType. */ +template +struct DevFmtTypeTraits { }; + +template<> +struct DevFmtTypeTraits { using Type = ALbyte; }; +template<> +struct DevFmtTypeTraits { using Type = ALubyte; }; +template<> +struct DevFmtTypeTraits { using Type = ALshort; }; +template<> +struct DevFmtTypeTraits { using Type = ALushort; }; +template<> +struct DevFmtTypeTraits { using Type = ALint; }; +template<> +struct DevFmtTypeTraits { using Type = ALuint; }; +template<> +struct DevFmtTypeTraits { using Type = ALfloat; }; + + +ALsizei BytesFromDevFmt(DevFmtType type) noexcept; +ALsizei ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept; +inline ALsizei FrameSizeFromDevFmt(DevFmtChannels chans, DevFmtType type, ALsizei ambiorder) noexcept +{ return ChannelsFromDevFmt(chans, ambiorder) * BytesFromDevFmt(type); } + +enum class AmbiLayout { + FuMa = ALC_FUMA_SOFT, /* FuMa channel order */ + ACN = ALC_ACN_SOFT, /* ACN channel order */ + + Default = ACN +}; + +enum class AmbiNorm { + FuMa = ALC_FUMA_SOFT, /* FuMa normalization */ + SN3D = ALC_SN3D_SOFT, /* SN3D normalization */ + N3D = ALC_N3D_SOFT, /* N3D normalization */ + + Default = SN3D +}; + + +enum DeviceType { + Playback, + Capture, + Loopback +}; + + +enum RenderMode { + NormalRender, + StereoPair, + HrtfRender +}; + + +struct BufferSubList { + uint64_t FreeMask{~0_u64}; + ALbuffer *Buffers{nullptr}; /* 64 */ + + BufferSubList() noexcept = default; + BufferSubList(const BufferSubList&) = delete; + BufferSubList(BufferSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Buffers{rhs.Buffers} + { rhs.FreeMask = ~0_u64; rhs.Buffers = nullptr; } + ~BufferSubList(); + + BufferSubList& operator=(const BufferSubList&) = delete; + BufferSubList& operator=(BufferSubList&& rhs) noexcept + { std::swap(FreeMask, rhs.FreeMask); std::swap(Buffers, rhs.Buffers); return *this; } +}; + +struct EffectSubList { + uint64_t FreeMask{~0_u64}; + ALeffect *Effects{nullptr}; /* 64 */ + + EffectSubList() noexcept = default; + EffectSubList(const EffectSubList&) = delete; + EffectSubList(EffectSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Effects{rhs.Effects} + { rhs.FreeMask = ~0_u64; rhs.Effects = nullptr; } + ~EffectSubList(); + + EffectSubList& operator=(const EffectSubList&) = delete; + EffectSubList& operator=(EffectSubList&& rhs) noexcept + { std::swap(FreeMask, rhs.FreeMask); std::swap(Effects, rhs.Effects); return *this; } +}; + +struct FilterSubList { + uint64_t FreeMask{~0_u64}; + ALfilter *Filters{nullptr}; /* 64 */ + + FilterSubList() noexcept = default; + FilterSubList(const FilterSubList&) = delete; + FilterSubList(FilterSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Filters{rhs.Filters} + { rhs.FreeMask = ~0_u64; rhs.Filters = nullptr; } + ~FilterSubList(); + + FilterSubList& operator=(const FilterSubList&) = delete; + FilterSubList& operator=(FilterSubList&& rhs) noexcept + { std::swap(FreeMask, rhs.FreeMask); std::swap(Filters, rhs.Filters); return *this; } +}; + + +/* Maximum delay in samples for speaker distance compensation. */ +#define MAX_DELAY_LENGTH 1024 + +class DistanceComp { +public: + struct DistData { + ALfloat Gain{1.0f}; + ALsizei Length{0}; /* Valid range is [0...MAX_DELAY_LENGTH). */ + ALfloat *Buffer{nullptr}; + }; + +private: + std::array mChannels; + al::vector mSamples; + +public: + void setSampleCount(size_t new_size) { mSamples.resize(new_size); } + void clear() noexcept + { + for(auto &chan : mChannels) + { + chan.Gain = 1.0f; + chan.Length = 0; + chan.Buffer = nullptr; + } + using SampleVecT = decltype(mSamples); + SampleVecT{}.swap(mSamples); + } + + ALfloat *getSamples() noexcept { return mSamples.data(); } + + al::span as_span() { return mChannels; } +}; + +struct BFChannelConfig { + ALfloat Scale; + ALsizei Index; +}; + +/* Size for temporary storage of buffer data, in ALfloats. Larger values need + * more memory, while smaller values may need more iterations. The value needs + * to be a sensible size, however, as it constrains the max stepping value used + * for mixing, as well as the maximum number of samples per mixing iteration. + */ +#define BUFFERSIZE 1024 + +using FloatBufferLine = std::array; + +/* Maximum number of samples to pad on either end of a buffer for resampling. + * Note that both the beginning and end need padding! + */ +#define MAX_RESAMPLE_PADDING 24 + + +struct MixParams { + /* Coefficient channel mapping for mixing to the buffer. */ + std::array AmbiMap{}; + + al::span Buffer; +}; + +struct RealMixParams { + std::array ChannelIndex{}; + + al::span Buffer; +}; + +using POSTPROCESS = void(*)(ALCdevice *device, const ALsizei SamplesToDo); + +enum { + // Frequency was requested by the app or config file + FrequencyRequest, + // Channel configuration was requested by the config file + ChannelsRequest, + // Sample type was requested by the config file + SampleTypeRequest, + + // Specifies if the DSP is paused at user request + DevicePaused, + // Specifies if the device is currently running + DeviceRunning, + + DeviceFlagsCount +}; + +struct ALCdevice { + RefCount ref{1u}; + + std::atomic Connected{true}; + const DeviceType Type{}; + + ALuint Frequency{}; + ALuint UpdateSize{}; + ALuint BufferSize{}; + + DevFmtChannels FmtChans{}; + DevFmtType FmtType{}; + ALboolean IsHeadphones{AL_FALSE}; + ALsizei mAmbiOrder{0}; + /* For DevFmtAmbi* output only, specifies the channel order and + * normalization. + */ + AmbiLayout mAmbiLayout{AmbiLayout::Default}; + AmbiNorm mAmbiScale{AmbiNorm::Default}; + + ALCenum LimiterState{ALC_DONT_CARE_SOFT}; + + std::string DeviceName; + + // Device flags + al::bitfield Flags{}; + + std::string HrtfName; + al::vector HrtfList; + ALCenum HrtfStatus{ALC_FALSE}; + + std::atomic LastError{ALC_NO_ERROR}; + + // Maximum number of sources that can be created + ALuint SourcesMax{}; + // Maximum number of slots that can be created + ALuint AuxiliaryEffectSlotMax{}; + + ALCuint NumMonoSources{}; + ALCuint NumStereoSources{}; + ALsizei NumAuxSends{}; + + // Map of Buffers for this device + std::mutex BufferLock; + al::vector BufferList; + + // Map of Effects for this device + std::mutex EffectLock; + al::vector EffectList; + + // Map of Filters for this device + std::mutex FilterLock; + al::vector FilterList; + + /* Rendering mode. */ + RenderMode mRenderMode{NormalRender}; + + /* The average speaker distance as determined by the ambdec configuration, + * HRTF data set, or the NFC-HOA reference delay. Only used for NFC. + */ + ALfloat AvgSpeakerDist{0.0f}; + + ALuint SamplesDone{0u}; + std::chrono::nanoseconds ClockBase{0}; + std::chrono::nanoseconds FixedLatency{0}; + + /* Temp storage used for mixer processing. */ + alignas(16) ALfloat SourceData[BUFFERSIZE + MAX_RESAMPLE_PADDING*2]; + alignas(16) ALfloat ResampledData[BUFFERSIZE]; + alignas(16) ALfloat FilteredData[BUFFERSIZE]; + union { + alignas(16) ALfloat HrtfSourceData[BUFFERSIZE + HRTF_HISTORY_LENGTH]; + alignas(16) ALfloat NfcSampleData[BUFFERSIZE]; + }; + alignas(16) float2 HrtfAccumData[BUFFERSIZE + HRIR_LENGTH]; + + /* Mixing buffer used by the Dry mix and Real output. */ + al::vector MixBuffer; + + /* The "dry" path corresponds to the main output. */ + MixParams Dry; + ALuint NumChannelsPerOrder[MAX_AMBI_ORDER+1]{}; + + /* "Real" output, which will be written to the device buffer. May alias the + * dry buffer. + */ + RealMixParams RealOut; + + /* HRTF state and info */ + std::unique_ptr mHrtfState; + HrtfEntry *mHrtf{nullptr}; + + /* Ambisonic-to-UHJ encoder */ + std::unique_ptr Uhj_Encoder; + + /* Ambisonic decoder for speakers */ + std::unique_ptr AmbiDecoder; + + /* Stereo-to-binaural filter */ + std::unique_ptr Bs2b; + + POSTPROCESS PostProcess{}; + + std::unique_ptr Stablizer; + + std::unique_ptr Limiter; + + /* Delay buffers used to compensate for speaker distances. */ + DistanceComp ChannelDelay; + + /* Dithering control. */ + ALfloat DitherDepth{0.0f}; + ALuint DitherSeed{0u}; + + /* Running count of the mixer invocations, in 31.1 fixed point. This + * actually increments *twice* when mixing, first at the start and then at + * the end, so the bottom bit indicates if the device is currently mixing + * and the upper bits indicates how many mixes have been done. + */ + RefCount MixCount{0u}; + + // Contexts created on this device + std::atomic*> mContexts{nullptr}; + + /* This lock protects the device state (format, update size, etc) from + * being from being changed in multiple threads, or being accessed while + * being changed. It's also used to serialize calls to the backend. + */ + std::mutex StateLock; + std::unique_ptr Backend; + + + ALCdevice(DeviceType type); + ALCdevice(const ALCdevice&) = delete; + ALCdevice& operator=(const ALCdevice&) = delete; + ~ALCdevice(); + + ALsizei bytesFromFmt() const noexcept { return BytesFromDevFmt(FmtType); } + ALsizei channelsFromFmt() const noexcept { return ChannelsFromDevFmt(FmtChans, mAmbiOrder); } + ALsizei frameSizeFromFmt() const noexcept { return bytesFromFmt() * channelsFromFmt(); } + + DEF_NEWDEL(ALCdevice) +}; + +/* Must be less than 15 characters (16 including terminating null) for + * compatibility with pthread_setname_np limitations. */ +#define MIXER_THREAD_NAME "alsoft-mixer" + +#define RECORD_THREAD_NAME "alsoft-record" + + +enum { + /* End event thread processing. */ + EventType_KillThread = 0, + + /* User event types. */ + EventType_SourceStateChange = 1<<0, + EventType_BufferCompleted = 1<<1, + EventType_Error = 1<<2, + EventType_Performance = 1<<3, + EventType_Deprecated = 1<<4, + EventType_Disconnected = 1<<5, + + /* Internal events. */ + EventType_ReleaseEffectState = 65536, +}; + +struct AsyncEvent { + unsigned int EnumType{0u}; + union { + char dummy; + struct { + ALuint id; + ALenum state; + } srcstate; + struct { + ALuint id; + ALsizei count; + } bufcomp; + struct { + ALenum type; + ALuint id; + ALuint param; + ALchar msg[1008]; + } user; + EffectState *mEffectState; + } u{}; + + AsyncEvent() noexcept = default; + constexpr AsyncEvent(unsigned int type) noexcept : EnumType{type} { } +}; + + +void AllocateVoices(ALCcontext *context, size_t num_voices); + + +extern ALint RTPrioLevel; +void SetRTPriority(void); + +void SetDefaultChannelOrder(ALCdevice *device); +void SetDefaultWFXChannelOrder(ALCdevice *device); + +const ALCchar *DevFmtTypeString(DevFmtType type) noexcept; +const ALCchar *DevFmtChannelsString(DevFmtChannels chans) noexcept; + +/** + * GetChannelIdxByName + * + * Returns the index for the given channel name (e.g. FrontCenter), or -1 if it + * doesn't exist. + */ +inline ALint GetChannelIdxByName(const RealMixParams &real, Channel chan) noexcept +{ return real.ChannelIndex[chan]; } + + +void StartEventThrd(ALCcontext *ctx); +void StopEventThrd(ALCcontext *ctx); + + +al::vector SearchDataFiles(const char *match, const char *subdir); + +#endif diff --git a/Alc/alconfig.cpp b/Alc/alconfig.cpp index 5f5f9149..b246a91d 100644 --- a/Alc/alconfig.cpp +++ b/Alc/alconfig.cpp @@ -28,6 +28,8 @@ #include "config.h" +#include "alconfig.h" + #include #include #include @@ -43,8 +45,7 @@ #include #include -#include "alMain.h" -#include "alconfig.h" +#include "alcmain.h" #include "logging.h" #include "compat.h" diff --git a/Alc/alu.cpp b/Alc/alu.cpp index 666cbb27..cc1a5a98 100644 --- a/Alc/alu.cpp +++ b/Alc/alu.cpp @@ -47,9 +47,9 @@ #include "alAuxEffectSlot.h" #include "alBuffer.h" +#include "alcmain.h" #include "alEffect.h" #include "alListener.h" -#include "alMain.h" #include "alcontext.h" #include "almalloc.h" #include "alnumeric.h" diff --git a/Alc/alu.h b/Alc/alu.h new file mode 100644 index 00000000..9acf904a --- /dev/null +++ b/Alc/alu.h @@ -0,0 +1,466 @@ +#ifndef _ALU_H_ +#define _ALU_H_ + +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" + +#include "alBuffer.h" +#include "alcmain.h" +#include "almalloc.h" +#include "alspan.h" +#include "ambidefs.h" +#include "filters/biquad.h" +#include "filters/nfc.h" +#include "filters/splitter.h" +#include "hrtf.h" +#include "logging.h" + +struct ALbufferlistitem; +struct ALeffectslot; +struct BSincTable; + + +enum class DistanceModel; + +#define MAX_PITCH 255 +#define MAX_SENDS 16 + + +#define DITHER_RNG_SEED 22222 + + +enum SpatializeMode { + SpatializeOff = AL_FALSE, + SpatializeOn = AL_TRUE, + SpatializeAuto = AL_AUTO_SOFT +}; + +enum Resampler { + PointResampler, + LinearResampler, + FIR4Resampler, + BSinc12Resampler, + BSinc24Resampler, + + ResamplerMax = BSinc24Resampler +}; +extern Resampler ResamplerDefault; + +/* The number of distinct scale and phase intervals within the bsinc filter + * table. + */ +#define BSINC_SCALE_BITS 4 +#define BSINC_SCALE_COUNT (1< *Coeffs; + ALsizei Delay[2]; + ALfloat Gain; + ALfloat GainStep; +}; + + +struct DirectParams { + BiquadFilter LowPass; + BiquadFilter HighPass; + + NfcFilter NFCtrlFilter; + + struct { + HrtfFilter Old; + HrtfFilter Target; + HrtfState State; + } Hrtf; + + struct { + ALfloat Current[MAX_OUTPUT_CHANNELS]; + ALfloat Target[MAX_OUTPUT_CHANNELS]; + } Gains; +}; + +struct SendParams { + BiquadFilter LowPass; + BiquadFilter HighPass; + + struct { + ALfloat Current[MAX_OUTPUT_CHANNELS]; + ALfloat Target[MAX_OUTPUT_CHANNELS]; + } Gains; +}; + + +struct ALvoicePropsBase { + ALfloat Pitch; + ALfloat Gain; + ALfloat OuterGain; + ALfloat MinGain; + ALfloat MaxGain; + ALfloat InnerAngle; + ALfloat OuterAngle; + ALfloat RefDistance; + ALfloat MaxDistance; + ALfloat RolloffFactor; + std::array Position; + std::array Velocity; + std::array Direction; + std::array OrientAt; + std::array OrientUp; + ALboolean HeadRelative; + DistanceModel mDistanceModel; + Resampler mResampler; + ALboolean DirectChannels; + SpatializeMode mSpatializeMode; + + ALboolean DryGainHFAuto; + ALboolean WetGainAuto; + ALboolean WetGainHFAuto; + ALfloat OuterGainHF; + + ALfloat AirAbsorptionFactor; + ALfloat RoomRolloffFactor; + ALfloat DopplerFactor; + + std::array StereoPan; + + ALfloat Radius; + + /** Direct filter and auxiliary send info. */ + struct { + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; + } Direct; + struct SendData { + ALeffectslot *Slot; + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; + } Send[MAX_SENDS]; +}; + +struct ALvoiceProps : public ALvoicePropsBase { + std::atomic next{nullptr}; + + DEF_NEWDEL(ALvoiceProps) +}; + +#define VOICE_IS_STATIC (1u<<0) +#define VOICE_IS_FADING (1u<<1) /* Fading sources use gain stepping for smooth transitions. */ +#define VOICE_IS_AMBISONIC (1u<<2) /* Voice needs HF scaling for ambisonic upsampling. */ +#define VOICE_HAS_HRTF (1u<<3) +#define VOICE_HAS_NFC (1u<<4) + +struct ALvoice { + enum State { + Stopped = 0, + Playing = 1, + Stopping = 2 + }; + + std::atomic mUpdate{nullptr}; + + std::atomic mSourceID{0u}; + std::atomic mPlayState{Stopped}; + + ALvoicePropsBase mProps; + + /** + * Source offset in samples, relative to the currently playing buffer, NOT + * the whole queue. + */ + std::atomic mPosition; + /** Fractional (fixed-point) offset to the next sample. */ + std::atomic mPositionFrac; + + /* Current buffer queue item being played. */ + std::atomic mCurrentBuffer; + + /* Buffer queue item to loop to at end of queue (will be NULL for non- + * looping voices). + */ + std::atomic mLoopBuffer; + + /* Properties for the attached buffer(s). */ + FmtChannels mFmtChannels; + ALuint mFrequency; + ALsizei mNumChannels; + ALsizei mSampleSize; + + /** Current target parameters used for mixing. */ + ALint mStep; + + ResamplerFunc mResampler; + + InterpState mResampleState; + + ALuint mFlags; + + struct DirectData { + int FilterType; + al::span Buffer; + }; + DirectData mDirect; + + struct SendData { + int FilterType; + al::span Buffer; + }; + std::array mSend; + + struct ChannelData { + alignas(16) std::array mPrevSamples; + + ALfloat mAmbiScale; + BandSplitter mAmbiSplitter; + + DirectParams mDryParams; + std::array mWetParams; + }; + std::array mChans; + + ALvoice() = default; + ALvoice(const ALvoice&) = delete; + ~ALvoice() { delete mUpdate.exchange(nullptr, std::memory_order_acq_rel); } + ALvoice& operator=(const ALvoice&) = delete; + ALvoice& operator=(ALvoice&& rhs) noexcept + { + ALvoiceProps *old_update{mUpdate.load(std::memory_order_relaxed)}; + mUpdate.store(rhs.mUpdate.exchange(old_update, std::memory_order_relaxed), + std::memory_order_relaxed); + + mSourceID.store(rhs.mSourceID.load(std::memory_order_relaxed), std::memory_order_relaxed); + mPlayState.store(rhs.mPlayState.load(std::memory_order_relaxed), + std::memory_order_relaxed); + + mProps = rhs.mProps; + + mPosition.store(rhs.mPosition.load(std::memory_order_relaxed), std::memory_order_relaxed); + mPositionFrac.store(rhs.mPositionFrac.load(std::memory_order_relaxed), + std::memory_order_relaxed); + + mCurrentBuffer.store(rhs.mCurrentBuffer.load(std::memory_order_relaxed), + std::memory_order_relaxed); + mLoopBuffer.store(rhs.mLoopBuffer.load(std::memory_order_relaxed), + std::memory_order_relaxed); + + mFmtChannels = rhs.mFmtChannels; + mFrequency = rhs.mFrequency; + mNumChannels = rhs.mNumChannels; + mSampleSize = rhs.mSampleSize; + + mStep = rhs.mStep; + mResampler = rhs.mResampler; + + mResampleState = rhs.mResampleState; + + mFlags = rhs.mFlags; + + mDirect = rhs.mDirect; + mSend = rhs.mSend; + mChans = rhs.mChans; + + return *this; + } +}; + + +using MixerFunc = void(*)(const ALfloat *data, const al::span OutBuffer, + ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, + const ALsizei BufferSize); +using RowMixerFunc = void(*)(FloatBufferLine &OutBuffer, const ALfloat *gains, + const al::span InSamples, const ALsizei InPos, + const ALsizei BufferSize); +using HrtfMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, + MixHrtfFilter *hrtfparams, const ALsizei BufferSize); +using HrtfMixerBlendFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, + const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize); +using HrtfDirectMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, + const ALsizei BufferSize); + + +#define GAIN_MIX_MAX (1000.0f) /* +60dB */ + +#define GAIN_SILENCE_THRESHOLD (0.00001f) /* -100dB */ + +#define SPEEDOFSOUNDMETRESPERSEC (343.3f) +#define AIRABSORBGAINHF (0.99426f) /* -0.05dB */ + +/* Target gain for the reverb decay feedback reaching the decay time. */ +#define REVERB_DECAY_GAIN (0.001f) /* -60 dB */ + +#define FRACTIONBITS (12) +#define FRACTIONONE (1< GetAmbiIdentityRow(size_t i) noexcept +{ + std::array ret{}; + ret[i] = 1.0f; + return ret; +} + + +void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCcontext *Context, const ALsizei SamplesToDo); + +void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples); +/* Caller must lock the device state, and the mixer must not be running. */ +void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) DECL_FORMAT(printf, 2, 3); + +extern MixerFunc MixSamples; +extern RowMixerFunc MixRowSamples; + +extern const ALfloat ConeScale; +extern const ALfloat ZScale; +extern const ALboolean OverrideReverbSpeedOfSound; + +#endif diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp index 698a4088..c133df68 100644 --- a/Alc/backends/alsa.cpp +++ b/Alc/backends/alsa.cpp @@ -37,8 +37,8 @@ #include "AL/al.h" -#include "alMain.h" #include "albyte.h" +#include "alcmain.h" #include "alconfig.h" #include "almalloc.h" #include "alnumeric.h" diff --git a/Alc/backends/base.cpp b/Alc/backends/base.cpp index 5748975e..a7d47c6d 100644 --- a/Alc/backends/base.cpp +++ b/Alc/backends/base.cpp @@ -5,7 +5,7 @@ #include -#include "alMain.h" +#include "alcmain.h" #include "alu.h" #include "backends/base.h" diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 7a9232a6..437e31d9 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -6,7 +6,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" struct ClockLatency { diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp index c6978505..b4b46382 100644 --- a/Alc/backends/coreaudio.cpp +++ b/Alc/backends/coreaudio.cpp @@ -26,7 +26,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" #include "alu.h" #include "ringbuffer.h" #include "converter.h" diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp index d4c1033c..5a156d54 100644 --- a/Alc/backends/dsound.cpp +++ b/Alc/backends/dsound.cpp @@ -44,7 +44,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" #include "alu.h" #include "ringbuffer.h" #include "compat.h" diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp index 99e9019b..3f81d08c 100644 --- a/Alc/backends/jack.cpp +++ b/Alc/backends/jack.cpp @@ -29,7 +29,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" #include "alu.h" #include "alconfig.h" #include "ringbuffer.h" diff --git a/Alc/backends/loopback.cpp b/Alc/backends/loopback.cpp index 77606b89..4a1c641a 100644 --- a/Alc/backends/loopback.cpp +++ b/Alc/backends/loopback.cpp @@ -22,7 +22,7 @@ #include "backends/loopback.h" -#include "alMain.h" +#include "alcmain.h" #include "alu.h" diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp index 00a37fda..ae58cb8b 100644 --- a/Alc/backends/null.cpp +++ b/Alc/backends/null.cpp @@ -30,7 +30,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" #include "almalloc.h" #include "alu.h" #include "logging.h" diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp index 452028ea..b34dc0cb 100644 --- a/Alc/backends/opensl.cpp +++ b/Alc/backends/opensl.cpp @@ -31,7 +31,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" #include "alu.h" #include "ringbuffer.h" #include "threads.h" diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp index 33075890..8cfe9e96 100644 --- a/Alc/backends/oss.cpp +++ b/Alc/backends/oss.cpp @@ -43,7 +43,7 @@ #include "AL/al.h" -#include "alMain.h" +#include "alcmain.h" #include "alconfig.h" #include "almalloc.h" #include "alnumeric.h" diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp index 10c8261b..73e972c5 100644 --- a/Alc/backends/portaudio.cpp +++ b/Alc/backends/portaudio.cpp @@ -26,7 +26,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" #include "alu.h" #include "alconfig.h" #include "ringbuffer.h" diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp index 97736253..da209c8d 100644 --- a/Alc/backends/pulseaudio.cpp +++ b/Alc/backends/pulseaudio.cpp @@ -34,7 +34,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" #include "alu.h" #include "alconfig.h" #include "compat.h" diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp index 074430ca..64ed53aa 100644 --- a/Alc/backends/qsa.cpp +++ b/Alc/backends/qsa.cpp @@ -33,7 +33,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" #include "alu.h" #include "threads.h" diff --git a/Alc/backends/sdl2.cpp b/Alc/backends/sdl2.cpp index a7a1752e..97547959 100644 --- a/Alc/backends/sdl2.cpp +++ b/Alc/backends/sdl2.cpp @@ -27,7 +27,7 @@ #include -#include "alMain.h" +#include "alcmain.h" #include "alu.h" #include "threads.h" #include "compat.h" diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp index e696cf55..587f67bb 100644 --- a/Alc/backends/sndio.cpp +++ b/Alc/backends/sndio.cpp @@ -29,7 +29,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" #include "alu.h" #include "threads.h" #include "vector.h" diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp index 5c12ad72..584f6e66 100644 --- a/Alc/backends/solaris.cpp +++ b/Alc/backends/solaris.cpp @@ -38,7 +38,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" #include "alu.h" #include "alconfig.h" #include "threads.h" diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp index 384aaba8..bd009463 100644 --- a/Alc/backends/wasapi.cpp +++ b/Alc/backends/wasapi.cpp @@ -54,7 +54,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" #include "alu.h" #include "ringbuffer.h" #include "compat.h" diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp index 77692686..67ed7e79 100644 --- a/Alc/backends/wave.cpp +++ b/Alc/backends/wave.cpp @@ -35,7 +35,7 @@ #include "AL/al.h" -#include "alMain.h" +#include "alcmain.h" #include "alconfig.h" #include "almalloc.h" #include "alnumeric.h" diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp index 57abee06..cd32e95b 100644 --- a/Alc/backends/winmm.cpp +++ b/Alc/backends/winmm.cpp @@ -37,7 +37,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" #include "alu.h" #include "ringbuffer.h" #include "threads.h" diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 31abc4fe..06974651 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -6,7 +6,7 @@ #include "AL/al.h" -#include "alMain.h" +#include "alcmain.h" #include "almalloc.h" #include "alspan.h" #include "ambidefs.h" diff --git a/Alc/converter.h b/Alc/converter.h index 04d94833..033e4d3f 100644 --- a/Alc/converter.h +++ b/Alc/converter.h @@ -3,7 +3,7 @@ #include -#include "alMain.h" +#include "alcmain.h" #include "alu.h" #include "almalloc.h" diff --git a/Alc/effects/autowah.cpp b/Alc/effects/autowah.cpp index 8545de1f..96292636 100644 --- a/Alc/effects/autowah.cpp +++ b/Alc/effects/autowah.cpp @@ -25,7 +25,7 @@ #include -#include "alMain.h" +#include "alcmain.h" #include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" diff --git a/Alc/effects/base.h b/Alc/effects/base.h index 2b067f11..4f48de22 100644 --- a/Alc/effects/base.h +++ b/Alc/effects/base.h @@ -1,8 +1,7 @@ #ifndef EFFECTS_BASE_H #define EFFECTS_BASE_H -#include "alMain.h" - +#include "alcmain.h" #include "almalloc.h" #include "alspan.h" #include "atomic.h" diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp index b9bf3f4c..d475b57a 100644 --- a/Alc/effects/chorus.cpp +++ b/Alc/effects/chorus.cpp @@ -31,8 +31,8 @@ #include "AL/efx.h" #include "alAuxEffectSlot.h" +#include "alcmain.h" #include "alError.h" -#include "alMain.h" #include "alcontext.h" #include "almalloc.h" #include "alnumeric.h" diff --git a/Alc/effects/compressor.cpp b/Alc/effects/compressor.cpp index 82f70317..4a487097 100644 --- a/Alc/effects/compressor.cpp +++ b/Alc/effects/compressor.cpp @@ -22,7 +22,7 @@ #include -#include "alMain.h" +#include "alcmain.h" #include "alcontext.h" #include "alu.h" #include "alAuxEffectSlot.h" diff --git a/Alc/effects/dedicated.cpp b/Alc/effects/dedicated.cpp index f31cc903..b31b3750 100644 --- a/Alc/effects/dedicated.cpp +++ b/Alc/effects/dedicated.cpp @@ -24,7 +24,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" #include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" diff --git a/Alc/effects/distortion.cpp b/Alc/effects/distortion.cpp index 94af9e11..59557395 100644 --- a/Alc/effects/distortion.cpp +++ b/Alc/effects/distortion.cpp @@ -25,7 +25,7 @@ #include -#include "alMain.h" +#include "alcmain.h" #include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp index 0211520b..c10f2eb2 100644 --- a/Alc/effects/echo.cpp +++ b/Alc/effects/echo.cpp @@ -25,7 +25,7 @@ #include -#include "alMain.h" +#include "alcmain.h" #include "alcontext.h" #include "alFilter.h" #include "alAuxEffectSlot.h" diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp index 961ae8fc..69ab5021 100644 --- a/Alc/effects/equalizer.cpp +++ b/Alc/effects/equalizer.cpp @@ -26,7 +26,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" #include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp index 68e10cba..b47aa00e 100644 --- a/Alc/effects/fshifter.cpp +++ b/Alc/effects/fshifter.cpp @@ -26,7 +26,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" #include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp index 8377aefe..086482d7 100644 --- a/Alc/effects/modulator.cpp +++ b/Alc/effects/modulator.cpp @@ -26,7 +26,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" #include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" diff --git a/Alc/effects/null.cpp b/Alc/effects/null.cpp index 3c27bae0..e55c8699 100644 --- a/Alc/effects/null.cpp +++ b/Alc/effects/null.cpp @@ -5,7 +5,7 @@ #include "AL/al.h" #include "AL/alc.h" -#include "alMain.h" +#include "alcmain.h" #include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp index bade81e6..39d3cf1a 100644 --- a/Alc/effects/pshifter.cpp +++ b/Alc/effects/pshifter.cpp @@ -30,7 +30,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" #include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp index 01f5c476..ac996b3f 100644 --- a/Alc/effects/reverb.cpp +++ b/Alc/effects/reverb.cpp @@ -29,7 +29,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" #include "alcontext.h" #include "alu.h" #include "alAuxEffectSlot.h" diff --git a/Alc/effects/vmorpher.cpp b/Alc/effects/vmorpher.cpp index 6f7e22ae..eebba3f1 100644 --- a/Alc/effects/vmorpher.cpp +++ b/Alc/effects/vmorpher.cpp @@ -25,7 +25,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" #include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" diff --git a/Alc/filters/nfc.cpp b/Alc/filters/nfc.cpp index e607dd56..1a567f2c 100644 --- a/Alc/filters/nfc.cpp +++ b/Alc/filters/nfc.cpp @@ -5,7 +5,7 @@ #include -#include "alMain.h" +#include "alcmain.h" /* Near-field control filters are the basis for handling the near-field effect. diff --git a/Alc/filters/splitter.h b/Alc/filters/splitter.h index 70fddd9e..927c4d17 100644 --- a/Alc/filters/splitter.h +++ b/Alc/filters/splitter.h @@ -1,7 +1,7 @@ #ifndef FILTER_SPLITTER_H #define FILTER_SPLITTER_H -#include "alMain.h" +#include "alcmain.h" #include "almalloc.h" diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp index 9f6283a3..e86af6ce 100644 --- a/Alc/helpers.cpp +++ b/Alc/helpers.cpp @@ -103,7 +103,7 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x #include #endif -#include "alMain.h" +#include "alcmain.h" #include "almalloc.h" #include "compat.h" #include "cpu_caps.h" diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp index 73cdc24e..786c4c5d 100644 --- a/Alc/hrtf.cpp +++ b/Alc/hrtf.cpp @@ -40,7 +40,7 @@ #include "AL/al.h" -#include "alMain.h" +#include "alcmain.h" #include "alconfig.h" #include "almalloc.h" #include "alnumeric.h" diff --git a/Alc/mastering.h b/Alc/mastering.h index 1003fa6c..34dc8dcb 100644 --- a/Alc/mastering.h +++ b/Alc/mastering.h @@ -7,7 +7,7 @@ #include "almalloc.h" /* For FloatBufferLine/BUFFERSIZE. */ -#include "alMain.h" +#include "alcmain.h" struct SlidingHold; diff --git a/Alc/mixer/defs.h b/Alc/mixer/defs.h index 0e91e30e..3e5d1125 100644 --- a/Alc/mixer/defs.h +++ b/Alc/mixer/defs.h @@ -3,9 +3,9 @@ #include "AL/alc.h" #include "AL/al.h" -#include "alMain.h" -#include "alu.h" +#include "alcmain.h" +#include "alu.h" #include "alspan.h" diff --git a/Alc/mixer/mixer_c.cpp b/Alc/mixer/mixer_c.cpp index b9d51c9c..47c4a6f4 100644 --- a/Alc/mixer/mixer_c.cpp +++ b/Alc/mixer/mixer_c.cpp @@ -4,7 +4,7 @@ #include -#include "alMain.h" +#include "alcmain.h" #include "alu.h" #include "alSource.h" #include "alAuxEffectSlot.h" diff --git a/Alc/mixer/mixer_neon.cpp b/Alc/mixer/mixer_neon.cpp index 81d0ff67..fa487d97 100644 --- a/Alc/mixer/mixer_neon.cpp +++ b/Alc/mixer/mixer_neon.cpp @@ -6,7 +6,7 @@ #include "AL/al.h" #include "AL/alc.h" -#include "alMain.h" +#include "alcmain.h" #include "alu.h" #include "hrtf.h" #include "defs.h" diff --git a/Alc/mixer/mixer_sse.cpp b/Alc/mixer/mixer_sse.cpp index f407ac14..b763fdbd 100644 --- a/Alc/mixer/mixer_sse.cpp +++ b/Alc/mixer/mixer_sse.cpp @@ -6,7 +6,7 @@ #include "AL/al.h" #include "AL/alc.h" -#include "alMain.h" +#include "alcmain.h" #include "alu.h" #include "alSource.h" diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp index 1020cc74..be872f6d 100644 --- a/Alc/mixvoice.cpp +++ b/Alc/mixvoice.cpp @@ -40,7 +40,7 @@ #include "AL/alc.h" #include "alBuffer.h" -#include "alMain.h" +#include "alcmain.h" #include "alSource.h" #include "albyte.h" #include "alconfig.h" diff --git a/Alc/panning.cpp b/Alc/panning.cpp index e8f80069..3a67e33a 100644 --- a/Alc/panning.cpp +++ b/Alc/panning.cpp @@ -32,7 +32,7 @@ #include #include -#include "alMain.h" +#include "alcmain.h" #include "alAuxEffectSlot.h" #include "alu.h" #include "alconfig.h" diff --git a/Alc/uhjfilter.h b/Alc/uhjfilter.h index 181e036a..53e4f89e 100644 --- a/Alc/uhjfilter.h +++ b/Alc/uhjfilter.h @@ -3,7 +3,7 @@ #include "AL/al.h" -#include "alMain.h" +#include "alcmain.h" #include "almalloc.h" diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a9d04ea..0bedc4f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -619,9 +619,6 @@ SET(COMMON_OBJS common/vecmat.h ) SET(OPENAL_OBJS - OpenAL32/Include/alMain.h - OpenAL32/Include/alu.h - OpenAL32/Include/alAuxEffectSlot.h OpenAL32/alAuxEffectSlot.cpp OpenAL32/Include/alBuffer.h @@ -642,7 +639,9 @@ SET(OPENAL_OBJS ) SET(ALC_OBJS Alc/alc.cpp + Alc/alcmain.h Alc/alu.cpp + Alc/alu.h Alc/alconfig.cpp Alc/alconfig.h Alc/alcontext.h diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 9956c432..b6976d13 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -3,7 +3,7 @@ #include -#include "alMain.h" +#include "alcmain.h" #include "alEffect.h" #include "ambidefs.h" #include "effects/base.h" diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index d94317a4..d43aa206 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -1,7 +1,7 @@ #ifndef _AL_EFFECT_H_ #define _AL_EFFECT_H_ -#include "alMain.h" +#include "alcmain.h" #include "effects/base.h" diff --git a/OpenAL32/Include/alError.h b/OpenAL32/Include/alError.h index 7b64b302..0abd6b26 100644 --- a/OpenAL32/Include/alError.h +++ b/OpenAL32/Include/alError.h @@ -1,7 +1,7 @@ #ifndef _AL_ERROR_H_ #define _AL_ERROR_H_ -#include "alMain.h" +#include "alcmain.h" #include "logging.h" diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h deleted file mode 100644 index 85bc9cbc..00000000 --- a/OpenAL32/Include/alMain.h +++ /dev/null @@ -1,534 +0,0 @@ -#ifndef AL_MAIN_H -#define AL_MAIN_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" - -#include "albyte.h" -#include "almalloc.h" -#include "alnumeric.h" -#include "alspan.h" -#include "ambidefs.h" -#include "atomic.h" -#include "hrtf.h" -#include "inprogext.h" -#include "vector.h" - -class BFormatDec; -struct ALbuffer; -struct ALeffect; -struct ALfilter; -struct BackendBase; -struct Compressor; -struct EffectState; -struct FrontStablizer; -struct Uhj2Encoder; -struct bs2b; - - -#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) -#define IS_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) -#else -static const union { - ALuint u; - ALubyte b[sizeof(ALuint)]; -} EndianTest = { 1 }; -#define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1) -#endif - - -#define MIN_OUTPUT_RATE 8000 -#define DEFAULT_OUTPUT_RATE 44100 -#define DEFAULT_UPDATE_SIZE 882 /* 20ms */ -#define DEFAULT_NUM_UPDATES 3 - - -enum Channel { - FrontLeft = 0, - FrontRight, - FrontCenter, - LFE, - BackLeft, - BackRight, - BackCenter, - SideLeft, - SideRight, - - UpperFrontLeft, - UpperFrontRight, - UpperBackLeft, - UpperBackRight, - LowerFrontLeft, - LowerFrontRight, - LowerBackLeft, - LowerBackRight, - - Aux0, - Aux1, - Aux2, - Aux3, - Aux4, - Aux5, - Aux6, - Aux7, - Aux8, - Aux9, - Aux10, - Aux11, - Aux12, - Aux13, - Aux14, - Aux15, - - MaxChannels -}; - - -/* Device formats */ -enum DevFmtType : ALenum { - DevFmtByte = ALC_BYTE_SOFT, - DevFmtUByte = ALC_UNSIGNED_BYTE_SOFT, - DevFmtShort = ALC_SHORT_SOFT, - DevFmtUShort = ALC_UNSIGNED_SHORT_SOFT, - DevFmtInt = ALC_INT_SOFT, - DevFmtUInt = ALC_UNSIGNED_INT_SOFT, - DevFmtFloat = ALC_FLOAT_SOFT, - - DevFmtTypeDefault = DevFmtFloat -}; -enum DevFmtChannels : ALenum { - DevFmtMono = ALC_MONO_SOFT, - DevFmtStereo = ALC_STEREO_SOFT, - DevFmtQuad = ALC_QUAD_SOFT, - DevFmtX51 = ALC_5POINT1_SOFT, - DevFmtX61 = ALC_6POINT1_SOFT, - DevFmtX71 = ALC_7POINT1_SOFT, - DevFmtAmbi3D = ALC_BFORMAT3D_SOFT, - - /* Similar to 5.1, except using rear channels instead of sides */ - DevFmtX51Rear = 0x70000000, - - DevFmtChannelsDefault = DevFmtStereo -}; -#define MAX_OUTPUT_CHANNELS (16) - -/* DevFmtType traits, providing the type, etc given a DevFmtType. */ -template -struct DevFmtTypeTraits { }; - -template<> -struct DevFmtTypeTraits { using Type = ALbyte; }; -template<> -struct DevFmtTypeTraits { using Type = ALubyte; }; -template<> -struct DevFmtTypeTraits { using Type = ALshort; }; -template<> -struct DevFmtTypeTraits { using Type = ALushort; }; -template<> -struct DevFmtTypeTraits { using Type = ALint; }; -template<> -struct DevFmtTypeTraits { using Type = ALuint; }; -template<> -struct DevFmtTypeTraits { using Type = ALfloat; }; - - -ALsizei BytesFromDevFmt(DevFmtType type) noexcept; -ALsizei ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept; -inline ALsizei FrameSizeFromDevFmt(DevFmtChannels chans, DevFmtType type, ALsizei ambiorder) noexcept -{ return ChannelsFromDevFmt(chans, ambiorder) * BytesFromDevFmt(type); } - -enum class AmbiLayout { - FuMa = ALC_FUMA_SOFT, /* FuMa channel order */ - ACN = ALC_ACN_SOFT, /* ACN channel order */ - - Default = ACN -}; - -enum class AmbiNorm { - FuMa = ALC_FUMA_SOFT, /* FuMa normalization */ - SN3D = ALC_SN3D_SOFT, /* SN3D normalization */ - N3D = ALC_N3D_SOFT, /* N3D normalization */ - - Default = SN3D -}; - - -enum DeviceType { - Playback, - Capture, - Loopback -}; - - -enum RenderMode { - NormalRender, - StereoPair, - HrtfRender -}; - - -struct BufferSubList { - uint64_t FreeMask{~0_u64}; - ALbuffer *Buffers{nullptr}; /* 64 */ - - BufferSubList() noexcept = default; - BufferSubList(const BufferSubList&) = delete; - BufferSubList(BufferSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Buffers{rhs.Buffers} - { rhs.FreeMask = ~0_u64; rhs.Buffers = nullptr; } - ~BufferSubList(); - - BufferSubList& operator=(const BufferSubList&) = delete; - BufferSubList& operator=(BufferSubList&& rhs) noexcept - { std::swap(FreeMask, rhs.FreeMask); std::swap(Buffers, rhs.Buffers); return *this; } -}; - -struct EffectSubList { - uint64_t FreeMask{~0_u64}; - ALeffect *Effects{nullptr}; /* 64 */ - - EffectSubList() noexcept = default; - EffectSubList(const EffectSubList&) = delete; - EffectSubList(EffectSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Effects{rhs.Effects} - { rhs.FreeMask = ~0_u64; rhs.Effects = nullptr; } - ~EffectSubList(); - - EffectSubList& operator=(const EffectSubList&) = delete; - EffectSubList& operator=(EffectSubList&& rhs) noexcept - { std::swap(FreeMask, rhs.FreeMask); std::swap(Effects, rhs.Effects); return *this; } -}; - -struct FilterSubList { - uint64_t FreeMask{~0_u64}; - ALfilter *Filters{nullptr}; /* 64 */ - - FilterSubList() noexcept = default; - FilterSubList(const FilterSubList&) = delete; - FilterSubList(FilterSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Filters{rhs.Filters} - { rhs.FreeMask = ~0_u64; rhs.Filters = nullptr; } - ~FilterSubList(); - - FilterSubList& operator=(const FilterSubList&) = delete; - FilterSubList& operator=(FilterSubList&& rhs) noexcept - { std::swap(FreeMask, rhs.FreeMask); std::swap(Filters, rhs.Filters); return *this; } -}; - - -/* Maximum delay in samples for speaker distance compensation. */ -#define MAX_DELAY_LENGTH 1024 - -class DistanceComp { -public: - struct DistData { - ALfloat Gain{1.0f}; - ALsizei Length{0}; /* Valid range is [0...MAX_DELAY_LENGTH). */ - ALfloat *Buffer{nullptr}; - }; - -private: - std::array mChannels; - al::vector mSamples; - -public: - void setSampleCount(size_t new_size) { mSamples.resize(new_size); } - void clear() noexcept - { - for(auto &chan : mChannels) - { - chan.Gain = 1.0f; - chan.Length = 0; - chan.Buffer = nullptr; - } - using SampleVecT = decltype(mSamples); - SampleVecT{}.swap(mSamples); - } - - ALfloat *getSamples() noexcept { return mSamples.data(); } - - al::span as_span() { return mChannels; } -}; - -struct BFChannelConfig { - ALfloat Scale; - ALsizei Index; -}; - -/* Size for temporary storage of buffer data, in ALfloats. Larger values need - * more memory, while smaller values may need more iterations. The value needs - * to be a sensible size, however, as it constrains the max stepping value used - * for mixing, as well as the maximum number of samples per mixing iteration. - */ -#define BUFFERSIZE 1024 - -using FloatBufferLine = std::array; - -/* Maximum number of samples to pad on either end of a buffer for resampling. - * Note that both the beginning and end need padding! - */ -#define MAX_RESAMPLE_PADDING 24 - - -struct MixParams { - /* Coefficient channel mapping for mixing to the buffer. */ - std::array AmbiMap{}; - - al::span Buffer; -}; - -struct RealMixParams { - std::array ChannelIndex{}; - - al::span Buffer; -}; - -using POSTPROCESS = void(*)(ALCdevice *device, const ALsizei SamplesToDo); - -enum { - // Frequency was requested by the app or config file - FrequencyRequest, - // Channel configuration was requested by the config file - ChannelsRequest, - // Sample type was requested by the config file - SampleTypeRequest, - - // Specifies if the DSP is paused at user request - DevicePaused, - // Specifies if the device is currently running - DeviceRunning, - - DeviceFlagsCount -}; - -struct ALCdevice { - RefCount ref{1u}; - - std::atomic Connected{true}; - const DeviceType Type{}; - - ALuint Frequency{}; - ALuint UpdateSize{}; - ALuint BufferSize{}; - - DevFmtChannels FmtChans{}; - DevFmtType FmtType{}; - ALboolean IsHeadphones{AL_FALSE}; - ALsizei mAmbiOrder{0}; - /* For DevFmtAmbi* output only, specifies the channel order and - * normalization. - */ - AmbiLayout mAmbiLayout{AmbiLayout::Default}; - AmbiNorm mAmbiScale{AmbiNorm::Default}; - - ALCenum LimiterState{ALC_DONT_CARE_SOFT}; - - std::string DeviceName; - - // Device flags - al::bitfield Flags{}; - - std::string HrtfName; - al::vector HrtfList; - ALCenum HrtfStatus{ALC_FALSE}; - - std::atomic LastError{ALC_NO_ERROR}; - - // Maximum number of sources that can be created - ALuint SourcesMax{}; - // Maximum number of slots that can be created - ALuint AuxiliaryEffectSlotMax{}; - - ALCuint NumMonoSources{}; - ALCuint NumStereoSources{}; - ALsizei NumAuxSends{}; - - // Map of Buffers for this device - std::mutex BufferLock; - al::vector BufferList; - - // Map of Effects for this device - std::mutex EffectLock; - al::vector EffectList; - - // Map of Filters for this device - std::mutex FilterLock; - al::vector FilterList; - - /* Rendering mode. */ - RenderMode mRenderMode{NormalRender}; - - /* The average speaker distance as determined by the ambdec configuration, - * HRTF data set, or the NFC-HOA reference delay. Only used for NFC. - */ - ALfloat AvgSpeakerDist{0.0f}; - - ALuint SamplesDone{0u}; - std::chrono::nanoseconds ClockBase{0}; - std::chrono::nanoseconds FixedLatency{0}; - - /* Temp storage used for mixer processing. */ - alignas(16) ALfloat SourceData[BUFFERSIZE + MAX_RESAMPLE_PADDING*2]; - alignas(16) ALfloat ResampledData[BUFFERSIZE]; - alignas(16) ALfloat FilteredData[BUFFERSIZE]; - union { - alignas(16) ALfloat HrtfSourceData[BUFFERSIZE + HRTF_HISTORY_LENGTH]; - alignas(16) ALfloat NfcSampleData[BUFFERSIZE]; - }; - alignas(16) float2 HrtfAccumData[BUFFERSIZE + HRIR_LENGTH]; - - /* Mixing buffer used by the Dry mix and Real output. */ - al::vector MixBuffer; - - /* The "dry" path corresponds to the main output. */ - MixParams Dry; - ALuint NumChannelsPerOrder[MAX_AMBI_ORDER+1]{}; - - /* "Real" output, which will be written to the device buffer. May alias the - * dry buffer. - */ - RealMixParams RealOut; - - /* HRTF state and info */ - std::unique_ptr mHrtfState; - HrtfEntry *mHrtf{nullptr}; - - /* Ambisonic-to-UHJ encoder */ - std::unique_ptr Uhj_Encoder; - - /* Ambisonic decoder for speakers */ - std::unique_ptr AmbiDecoder; - - /* Stereo-to-binaural filter */ - std::unique_ptr Bs2b; - - POSTPROCESS PostProcess{}; - - std::unique_ptr Stablizer; - - std::unique_ptr Limiter; - - /* Delay buffers used to compensate for speaker distances. */ - DistanceComp ChannelDelay; - - /* Dithering control. */ - ALfloat DitherDepth{0.0f}; - ALuint DitherSeed{0u}; - - /* Running count of the mixer invocations, in 31.1 fixed point. This - * actually increments *twice* when mixing, first at the start and then at - * the end, so the bottom bit indicates if the device is currently mixing - * and the upper bits indicates how many mixes have been done. - */ - RefCount MixCount{0u}; - - // Contexts created on this device - std::atomic*> mContexts{nullptr}; - - /* This lock protects the device state (format, update size, etc) from - * being from being changed in multiple threads, or being accessed while - * being changed. It's also used to serialize calls to the backend. - */ - std::mutex StateLock; - std::unique_ptr Backend; - - - ALCdevice(DeviceType type); - ALCdevice(const ALCdevice&) = delete; - ALCdevice& operator=(const ALCdevice&) = delete; - ~ALCdevice(); - - ALsizei bytesFromFmt() const noexcept { return BytesFromDevFmt(FmtType); } - ALsizei channelsFromFmt() const noexcept { return ChannelsFromDevFmt(FmtChans, mAmbiOrder); } - ALsizei frameSizeFromFmt() const noexcept { return bytesFromFmt() * channelsFromFmt(); } - - DEF_NEWDEL(ALCdevice) -}; - -/* Must be less than 15 characters (16 including terminating null) for - * compatibility with pthread_setname_np limitations. */ -#define MIXER_THREAD_NAME "alsoft-mixer" - -#define RECORD_THREAD_NAME "alsoft-record" - - -enum { - /* End event thread processing. */ - EventType_KillThread = 0, - - /* User event types. */ - EventType_SourceStateChange = 1<<0, - EventType_BufferCompleted = 1<<1, - EventType_Error = 1<<2, - EventType_Performance = 1<<3, - EventType_Deprecated = 1<<4, - EventType_Disconnected = 1<<5, - - /* Internal events. */ - EventType_ReleaseEffectState = 65536, -}; - -struct AsyncEvent { - unsigned int EnumType{0u}; - union { - char dummy; - struct { - ALuint id; - ALenum state; - } srcstate; - struct { - ALuint id; - ALsizei count; - } bufcomp; - struct { - ALenum type; - ALuint id; - ALuint param; - ALchar msg[1008]; - } user; - EffectState *mEffectState; - } u{}; - - AsyncEvent() noexcept = default; - constexpr AsyncEvent(unsigned int type) noexcept : EnumType{type} { } -}; - - -void AllocateVoices(ALCcontext *context, size_t num_voices); - - -extern ALint RTPrioLevel; -void SetRTPriority(void); - -void SetDefaultChannelOrder(ALCdevice *device); -void SetDefaultWFXChannelOrder(ALCdevice *device); - -const ALCchar *DevFmtTypeString(DevFmtType type) noexcept; -const ALCchar *DevFmtChannelsString(DevFmtChannels chans) noexcept; - -/** - * GetChannelIdxByName - * - * Returns the index for the given channel name (e.g. FrontCenter), or -1 if it - * doesn't exist. - */ -inline ALint GetChannelIdxByName(const RealMixParams &real, Channel chan) noexcept -{ return real.ChannelIndex[chan]; } - - -void StartEventThrd(ALCcontext *ctx); -void StopEventThrd(ALCcontext *ctx); - - -al::vector SearchDataFiles(const char *match, const char *subdir); - -#endif diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 0343a943..330bb9f4 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -3,7 +3,7 @@ #include -#include "alMain.h" +#include "alcmain.h" #include "alu.h" #include "hrtf.h" #include "almalloc.h" diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h deleted file mode 100644 index 841e5c03..00000000 --- a/OpenAL32/Include/alu.h +++ /dev/null @@ -1,466 +0,0 @@ -#ifndef _ALU_H_ -#define _ALU_H_ - -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" - -#include "alBuffer.h" -#include "alMain.h" -#include "almalloc.h" -#include "alspan.h" -#include "ambidefs.h" -#include "filters/biquad.h" -#include "filters/nfc.h" -#include "filters/splitter.h" -#include "hrtf.h" -#include "logging.h" - -struct ALbufferlistitem; -struct ALeffectslot; -struct BSincTable; - - -enum class DistanceModel; - -#define MAX_PITCH 255 -#define MAX_SENDS 16 - - -#define DITHER_RNG_SEED 22222 - - -enum SpatializeMode { - SpatializeOff = AL_FALSE, - SpatializeOn = AL_TRUE, - SpatializeAuto = AL_AUTO_SOFT -}; - -enum Resampler { - PointResampler, - LinearResampler, - FIR4Resampler, - BSinc12Resampler, - BSinc24Resampler, - - ResamplerMax = BSinc24Resampler -}; -extern Resampler ResamplerDefault; - -/* The number of distinct scale and phase intervals within the bsinc filter - * table. - */ -#define BSINC_SCALE_BITS 4 -#define BSINC_SCALE_COUNT (1< *Coeffs; - ALsizei Delay[2]; - ALfloat Gain; - ALfloat GainStep; -}; - - -struct DirectParams { - BiquadFilter LowPass; - BiquadFilter HighPass; - - NfcFilter NFCtrlFilter; - - struct { - HrtfFilter Old; - HrtfFilter Target; - HrtfState State; - } Hrtf; - - struct { - ALfloat Current[MAX_OUTPUT_CHANNELS]; - ALfloat Target[MAX_OUTPUT_CHANNELS]; - } Gains; -}; - -struct SendParams { - BiquadFilter LowPass; - BiquadFilter HighPass; - - struct { - ALfloat Current[MAX_OUTPUT_CHANNELS]; - ALfloat Target[MAX_OUTPUT_CHANNELS]; - } Gains; -}; - - -struct ALvoicePropsBase { - ALfloat Pitch; - ALfloat Gain; - ALfloat OuterGain; - ALfloat MinGain; - ALfloat MaxGain; - ALfloat InnerAngle; - ALfloat OuterAngle; - ALfloat RefDistance; - ALfloat MaxDistance; - ALfloat RolloffFactor; - std::array Position; - std::array Velocity; - std::array Direction; - std::array OrientAt; - std::array OrientUp; - ALboolean HeadRelative; - DistanceModel mDistanceModel; - Resampler mResampler; - ALboolean DirectChannels; - SpatializeMode mSpatializeMode; - - ALboolean DryGainHFAuto; - ALboolean WetGainAuto; - ALboolean WetGainHFAuto; - ALfloat OuterGainHF; - - ALfloat AirAbsorptionFactor; - ALfloat RoomRolloffFactor; - ALfloat DopplerFactor; - - std::array StereoPan; - - ALfloat Radius; - - /** Direct filter and auxiliary send info. */ - struct { - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - } Direct; - struct SendData { - ALeffectslot *Slot; - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - } Send[MAX_SENDS]; -}; - -struct ALvoiceProps : public ALvoicePropsBase { - std::atomic next{nullptr}; - - DEF_NEWDEL(ALvoiceProps) -}; - -#define VOICE_IS_STATIC (1u<<0) -#define VOICE_IS_FADING (1u<<1) /* Fading sources use gain stepping for smooth transitions. */ -#define VOICE_IS_AMBISONIC (1u<<2) /* Voice needs HF scaling for ambisonic upsampling. */ -#define VOICE_HAS_HRTF (1u<<3) -#define VOICE_HAS_NFC (1u<<4) - -struct ALvoice { - enum State { - Stopped = 0, - Playing = 1, - Stopping = 2 - }; - - std::atomic mUpdate{nullptr}; - - std::atomic mSourceID{0u}; - std::atomic mPlayState{Stopped}; - - ALvoicePropsBase mProps; - - /** - * Source offset in samples, relative to the currently playing buffer, NOT - * the whole queue. - */ - std::atomic mPosition; - /** Fractional (fixed-point) offset to the next sample. */ - std::atomic mPositionFrac; - - /* Current buffer queue item being played. */ - std::atomic mCurrentBuffer; - - /* Buffer queue item to loop to at end of queue (will be NULL for non- - * looping voices). - */ - std::atomic mLoopBuffer; - - /* Properties for the attached buffer(s). */ - FmtChannels mFmtChannels; - ALuint mFrequency; - ALsizei mNumChannels; - ALsizei mSampleSize; - - /** Current target parameters used for mixing. */ - ALint mStep; - - ResamplerFunc mResampler; - - InterpState mResampleState; - - ALuint mFlags; - - struct DirectData { - int FilterType; - al::span Buffer; - }; - DirectData mDirect; - - struct SendData { - int FilterType; - al::span Buffer; - }; - std::array mSend; - - struct ChannelData { - alignas(16) std::array mPrevSamples; - - ALfloat mAmbiScale; - BandSplitter mAmbiSplitter; - - DirectParams mDryParams; - std::array mWetParams; - }; - std::array mChans; - - ALvoice() = default; - ALvoice(const ALvoice&) = delete; - ~ALvoice() { delete mUpdate.exchange(nullptr, std::memory_order_acq_rel); } - ALvoice& operator=(const ALvoice&) = delete; - ALvoice& operator=(ALvoice&& rhs) noexcept - { - ALvoiceProps *old_update{mUpdate.load(std::memory_order_relaxed)}; - mUpdate.store(rhs.mUpdate.exchange(old_update, std::memory_order_relaxed), - std::memory_order_relaxed); - - mSourceID.store(rhs.mSourceID.load(std::memory_order_relaxed), std::memory_order_relaxed); - mPlayState.store(rhs.mPlayState.load(std::memory_order_relaxed), - std::memory_order_relaxed); - - mProps = rhs.mProps; - - mPosition.store(rhs.mPosition.load(std::memory_order_relaxed), std::memory_order_relaxed); - mPositionFrac.store(rhs.mPositionFrac.load(std::memory_order_relaxed), - std::memory_order_relaxed); - - mCurrentBuffer.store(rhs.mCurrentBuffer.load(std::memory_order_relaxed), - std::memory_order_relaxed); - mLoopBuffer.store(rhs.mLoopBuffer.load(std::memory_order_relaxed), - std::memory_order_relaxed); - - mFmtChannels = rhs.mFmtChannels; - mFrequency = rhs.mFrequency; - mNumChannels = rhs.mNumChannels; - mSampleSize = rhs.mSampleSize; - - mStep = rhs.mStep; - mResampler = rhs.mResampler; - - mResampleState = rhs.mResampleState; - - mFlags = rhs.mFlags; - - mDirect = rhs.mDirect; - mSend = rhs.mSend; - mChans = rhs.mChans; - - return *this; - } -}; - - -using MixerFunc = void(*)(const ALfloat *data, const al::span OutBuffer, - ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, - const ALsizei BufferSize); -using RowMixerFunc = void(*)(FloatBufferLine &OutBuffer, const ALfloat *gains, - const al::span InSamples, const ALsizei InPos, - const ALsizei BufferSize); -using HrtfMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - MixHrtfFilter *hrtfparams, const ALsizei BufferSize); -using HrtfMixerBlendFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize); -using HrtfDirectMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, - const ALsizei BufferSize); - - -#define GAIN_MIX_MAX (1000.0f) /* +60dB */ - -#define GAIN_SILENCE_THRESHOLD (0.00001f) /* -100dB */ - -#define SPEEDOFSOUNDMETRESPERSEC (343.3f) -#define AIRABSORBGAINHF (0.99426f) /* -0.05dB */ - -/* Target gain for the reverb decay feedback reaching the decay time. */ -#define REVERB_DECAY_GAIN (0.001f) /* -60 dB */ - -#define FRACTIONBITS (12) -#define FRACTIONONE (1< GetAmbiIdentityRow(size_t i) noexcept -{ - std::array ret{}; - ret[i] = 1.0f; - return ret; -} - - -void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCcontext *Context, const ALsizei SamplesToDo); - -void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples); -/* Caller must lock the device state, and the mixer must not be running. */ -void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) DECL_FORMAT(printf, 2, 3); - -extern MixerFunc MixSamples; -extern RowMixerFunc MixRowSamples; - -extern const ALfloat ConeScale; -extern const ALfloat ZScale; -extern const ALboolean OverrideReverbSpeedOfSound; - -#endif diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index 55fbc622..cc2893c3 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -29,7 +29,7 @@ #include "AL/al.h" #include "AL/alc.h" -#include "alMain.h" +#include "alcmain.h" #include "alcontext.h" #include "alAuxEffectSlot.h" #include "alError.h" diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index c9a9d9f6..597f98cb 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -40,8 +40,8 @@ #include "AL/alc.h" #include "AL/alext.h" +#include "alcmain.h" #include "alError.h" -#include "alMain.h" #include "albyte.h" #include "alcontext.h" #include "alexcpt.h" diff --git a/OpenAL32/alEffect.cpp b/OpenAL32/alEffect.cpp index 2de61019..14353d1c 100644 --- a/OpenAL32/alEffect.cpp +++ b/OpenAL32/alEffect.cpp @@ -37,8 +37,8 @@ #include "AL/efx-presets.h" #include "AL/efx.h" +#include "alcmain.h" #include "alError.h" -#include "alMain.h" #include "alcontext.h" #include "alexcpt.h" #include "almalloc.h" diff --git a/OpenAL32/alError.cpp b/OpenAL32/alError.cpp index 5f98ae1d..782e10ec 100644 --- a/OpenAL32/alError.cpp +++ b/OpenAL32/alError.cpp @@ -37,7 +37,7 @@ #include "AL/al.h" #include "AL/alc.h" -#include "alMain.h" +#include "alcmain.h" #include "alcontext.h" #include "alexcpt.h" #include "almalloc.h" diff --git a/OpenAL32/alExtension.cpp b/OpenAL32/alExtension.cpp index dda2a628..5abcf1cf 100644 --- a/OpenAL32/alExtension.cpp +++ b/OpenAL32/alExtension.cpp @@ -27,7 +27,7 @@ #include "AL/al.h" #include "AL/alc.h" -#include "alMain.h" +#include "alcmain.h" #include "alcontext.h" #include "alError.h" #include "alexcpt.h" diff --git a/OpenAL32/alFilter.cpp b/OpenAL32/alFilter.cpp index 209ddc87..cac12581 100644 --- a/OpenAL32/alFilter.cpp +++ b/OpenAL32/alFilter.cpp @@ -24,7 +24,7 @@ #include -#include "alMain.h" +#include "alcmain.h" #include "alcontext.h" #include "alu.h" #include "alFilter.h" diff --git a/OpenAL32/alListener.cpp b/OpenAL32/alListener.cpp index 419e38ad..067c0f55 100644 --- a/OpenAL32/alListener.cpp +++ b/OpenAL32/alListener.cpp @@ -22,7 +22,7 @@ #include -#include "alMain.h" +#include "alcmain.h" #include "alcontext.h" #include "alu.h" #include "alError.h" diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index 22c9e2d2..b080f874 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -51,7 +51,7 @@ #include "alBuffer.h" #include "alError.h" #include "alFilter.h" -#include "alMain.h" +#include "alcmain.h" #include "alcontext.h" #include "alexcpt.h" #include "almalloc.h" diff --git a/OpenAL32/alState.cpp b/OpenAL32/alState.cpp index f2c38bb2..ee8d3a1c 100644 --- a/OpenAL32/alState.cpp +++ b/OpenAL32/alState.cpp @@ -33,7 +33,7 @@ #include "AL/alext.h" #include "alError.h" -#include "alMain.h" +#include "alcmain.h" #include "alcontext.h" #include "alexcpt.h" #include "almalloc.h" diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp index dfffea9f..d50cef2e 100644 --- a/OpenAL32/event.cpp +++ b/OpenAL32/event.cpp @@ -15,8 +15,8 @@ #include "AL/alc.h" #include "alError.h" -#include "alMain.h" #include "albyte.h" +#include "alcmain.h" #include "alcontext.h" #include "alexcpt.h" #include "almalloc.h" -- cgit v1.2.3 From cb3e96e75640730b9391f0d2d922eecd9ee2ce79 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Jul 2019 18:56:04 -0700 Subject: Rename Alc to alc --- Alc/alc.cpp | 4342 ------------------------------------------- Alc/alcmain.h | 534 ------ Alc/alconfig.cpp | 545 ------ Alc/alconfig.h | 20 - Alc/alcontext.h | 217 --- Alc/alu.cpp | 1798 ------------------ Alc/alu.h | 466 ----- Alc/ambdec.cpp | 436 ----- Alc/ambdec.h | 48 - Alc/ambidefs.h | 119 -- Alc/backends/alsa.cpp | 1288 ------------- Alc/backends/alsa.h | 19 - Alc/backends/base.cpp | 58 - Alc/backends/base.h | 78 - Alc/backends/coreaudio.cpp | 709 ------- Alc/backends/coreaudio.h | 19 - Alc/backends/dsound.cpp | 938 ---------- Alc/backends/dsound.h | 19 - Alc/backends/jack.cpp | 562 ------ Alc/backends/jack.h | 19 - Alc/backends/loopback.cpp | 80 - Alc/backends/loopback.h | 19 - Alc/backends/null.cpp | 184 -- Alc/backends/null.h | 19 - Alc/backends/opensl.cpp | 936 ---------- Alc/backends/opensl.h | 19 - Alc/backends/oss.cpp | 751 -------- Alc/backends/oss.h | 19 - Alc/backends/portaudio.cpp | 463 ----- Alc/backends/portaudio.h | 19 - Alc/backends/pulseaudio.cpp | 1532 --------------- Alc/backends/pulseaudio.h | 19 - Alc/backends/qsa.cpp | 953 ---------- Alc/backends/qsa.h | 19 - Alc/backends/sdl2.cpp | 223 --- Alc/backends/sdl2.h | 19 - Alc/backends/sndio.cpp | 495 ----- Alc/backends/sndio.h | 19 - Alc/backends/solaris.cpp | 302 --- Alc/backends/solaris.h | 19 - Alc/backends/wasapi.cpp | 1763 ------------------ Alc/backends/wasapi.h | 19 - Alc/backends/wave.cpp | 402 ---- Alc/backends/wave.h | 19 - Alc/backends/winmm.cpp | 640 ------- Alc/backends/winmm.h | 19 - Alc/bformatdec.cpp | 200 -- Alc/bformatdec.h | 62 - Alc/bs2b.cpp | 188 -- Alc/bs2b.h | 90 - Alc/compat.h | 121 -- Alc/converter.cpp | 367 ---- Alc/converter.h | 70 - Alc/cpu_caps.h | 16 - Alc/effects/autowah.cpp | 298 --- Alc/effects/base.h | 196 -- Alc/effects/chorus.cpp | 538 ------ Alc/effects/compressor.cpp | 222 --- Alc/effects/dedicated.cpp | 159 -- Alc/effects/distortion.cpp | 269 --- Alc/effects/echo.cpp | 271 --- Alc/effects/equalizer.cpp | 337 ---- Alc/effects/fshifter.cpp | 301 --- Alc/effects/modulator.cpp | 279 --- Alc/effects/null.cpp | 164 -- Alc/effects/pshifter.cpp | 405 ---- Alc/effects/reverb.cpp | 2102 --------------------- Alc/effects/vmorpher.cpp | 430 ----- Alc/filters/biquad.cpp | 127 -- Alc/filters/biquad.h | 113 -- Alc/filters/nfc.cpp | 391 ---- Alc/filters/nfc.h | 58 - Alc/filters/splitter.cpp | 115 -- Alc/filters/splitter.h | 50 - Alc/fpu_modes.h | 25 - Alc/helpers.cpp | 851 --------- Alc/hrtf.cpp | 1400 -------------- Alc/hrtf.h | 124 -- Alc/inprogext.h | 92 - Alc/logging.h | 64 - Alc/mastering.cpp | 479 ----- Alc/mastering.h | 104 -- Alc/mixer/defs.h | 59 - Alc/mixer/hrtfbase.h | 138 -- Alc/mixer/mixer_c.cpp | 208 --- Alc/mixer/mixer_neon.cpp | 307 --- Alc/mixer/mixer_sse.cpp | 262 --- Alc/mixer/mixer_sse2.cpp | 84 - Alc/mixer/mixer_sse3.cpp | 0 Alc/mixer/mixer_sse41.cpp | 85 - Alc/mixvoice.cpp | 954 ---------- Alc/panning.cpp | 964 ---------- Alc/ringbuffer.cpp | 253 --- Alc/ringbuffer.h | 99 - Alc/uhjfilter.cpp | 131 -- Alc/uhjfilter.h | 54 - Alc/vector.h | 15 - CMakeLists.txt | 172 +- alc/alc.cpp | 4342 +++++++++++++++++++++++++++++++++++++++++++ alc/alcmain.h | 534 ++++++ alc/alconfig.cpp | 545 ++++++ alc/alconfig.h | 20 + alc/alcontext.h | 217 +++ alc/alu.cpp | 1798 ++++++++++++++++++ alc/alu.h | 466 +++++ alc/ambdec.cpp | 436 +++++ alc/ambdec.h | 48 + alc/ambidefs.h | 119 ++ alc/backends/alsa.cpp | 1288 +++++++++++++ alc/backends/alsa.h | 19 + alc/backends/base.cpp | 58 + alc/backends/base.h | 78 + alc/backends/coreaudio.cpp | 709 +++++++ alc/backends/coreaudio.h | 19 + alc/backends/dsound.cpp | 938 ++++++++++ alc/backends/dsound.h | 19 + alc/backends/jack.cpp | 562 ++++++ alc/backends/jack.h | 19 + alc/backends/loopback.cpp | 80 + alc/backends/loopback.h | 19 + alc/backends/null.cpp | 184 ++ alc/backends/null.h | 19 + alc/backends/opensl.cpp | 936 ++++++++++ alc/backends/opensl.h | 19 + alc/backends/oss.cpp | 751 ++++++++ alc/backends/oss.h | 19 + alc/backends/portaudio.cpp | 463 +++++ alc/backends/portaudio.h | 19 + alc/backends/pulseaudio.cpp | 1532 +++++++++++++++ alc/backends/pulseaudio.h | 19 + alc/backends/qsa.cpp | 953 ++++++++++ alc/backends/qsa.h | 19 + alc/backends/sdl2.cpp | 227 +++ alc/backends/sdl2.h | 19 + alc/backends/sndio.cpp | 495 +++++ alc/backends/sndio.h | 19 + alc/backends/solaris.cpp | 302 +++ alc/backends/solaris.h | 19 + alc/backends/wasapi.cpp | 1763 ++++++++++++++++++ alc/backends/wasapi.h | 19 + alc/backends/wave.cpp | 402 ++++ alc/backends/wave.h | 19 + alc/backends/winmm.cpp | 640 +++++++ alc/backends/winmm.h | 19 + alc/bformatdec.cpp | 200 ++ alc/bformatdec.h | 62 + alc/bs2b.cpp | 188 ++ alc/bs2b.h | 90 + alc/compat.h | 121 ++ alc/converter.cpp | 367 ++++ alc/converter.h | 70 + alc/cpu_caps.h | 16 + alc/effects/autowah.cpp | 298 +++ alc/effects/base.h | 196 ++ alc/effects/chorus.cpp | 538 ++++++ alc/effects/compressor.cpp | 222 +++ alc/effects/dedicated.cpp | 159 ++ alc/effects/distortion.cpp | 269 +++ alc/effects/echo.cpp | 271 +++ alc/effects/equalizer.cpp | 337 ++++ alc/effects/fshifter.cpp | 301 +++ alc/effects/modulator.cpp | 279 +++ alc/effects/null.cpp | 164 ++ alc/effects/pshifter.cpp | 405 ++++ alc/effects/reverb.cpp | 2102 +++++++++++++++++++++ alc/effects/vmorpher.cpp | 430 +++++ alc/filters/biquad.cpp | 127 ++ alc/filters/biquad.h | 113 ++ alc/filters/nfc.cpp | 391 ++++ alc/filters/nfc.h | 58 + alc/filters/splitter.cpp | 115 ++ alc/filters/splitter.h | 50 + alc/fpu_modes.h | 25 + alc/helpers.cpp | 851 +++++++++ alc/hrtf.cpp | 1400 ++++++++++++++ alc/hrtf.h | 124 ++ alc/inprogext.h | 92 + alc/logging.h | 64 + alc/mastering.cpp | 479 +++++ alc/mastering.h | 104 ++ alc/mixer/defs.h | 59 + alc/mixer/hrtfbase.h | 138 ++ alc/mixer/mixer_c.cpp | 208 +++ alc/mixer/mixer_neon.cpp | 307 +++ alc/mixer/mixer_sse.cpp | 262 +++ alc/mixer/mixer_sse2.cpp | 84 + alc/mixer/mixer_sse3.cpp | 0 alc/mixer/mixer_sse41.cpp | 85 + alc/mixvoice.cpp | 954 ++++++++++ alc/panning.cpp | 964 ++++++++++ alc/ringbuffer.cpp | 253 +++ alc/ringbuffer.h | 99 + alc/uhjfilter.cpp | 131 ++ alc/uhjfilter.h | 54 + alc/vector.h | 15 + 195 files changed, 35986 insertions(+), 35982 deletions(-) delete mode 100644 Alc/alc.cpp delete mode 100644 Alc/alcmain.h delete mode 100644 Alc/alconfig.cpp delete mode 100644 Alc/alconfig.h delete mode 100644 Alc/alcontext.h delete mode 100644 Alc/alu.cpp delete mode 100644 Alc/alu.h delete mode 100644 Alc/ambdec.cpp delete mode 100644 Alc/ambdec.h delete mode 100644 Alc/ambidefs.h delete mode 100644 Alc/backends/alsa.cpp delete mode 100644 Alc/backends/alsa.h delete mode 100644 Alc/backends/base.cpp delete mode 100644 Alc/backends/base.h delete mode 100644 Alc/backends/coreaudio.cpp delete mode 100644 Alc/backends/coreaudio.h delete mode 100644 Alc/backends/dsound.cpp delete mode 100644 Alc/backends/dsound.h delete mode 100644 Alc/backends/jack.cpp delete mode 100644 Alc/backends/jack.h delete mode 100644 Alc/backends/loopback.cpp delete mode 100644 Alc/backends/loopback.h delete mode 100644 Alc/backends/null.cpp delete mode 100644 Alc/backends/null.h delete mode 100644 Alc/backends/opensl.cpp delete mode 100644 Alc/backends/opensl.h delete mode 100644 Alc/backends/oss.cpp delete mode 100644 Alc/backends/oss.h delete mode 100644 Alc/backends/portaudio.cpp delete mode 100644 Alc/backends/portaudio.h delete mode 100644 Alc/backends/pulseaudio.cpp delete mode 100644 Alc/backends/pulseaudio.h delete mode 100644 Alc/backends/qsa.cpp delete mode 100644 Alc/backends/qsa.h delete mode 100644 Alc/backends/sdl2.cpp delete mode 100644 Alc/backends/sdl2.h delete mode 100644 Alc/backends/sndio.cpp delete mode 100644 Alc/backends/sndio.h delete mode 100644 Alc/backends/solaris.cpp delete mode 100644 Alc/backends/solaris.h delete mode 100644 Alc/backends/wasapi.cpp delete mode 100644 Alc/backends/wasapi.h delete mode 100644 Alc/backends/wave.cpp delete mode 100644 Alc/backends/wave.h delete mode 100644 Alc/backends/winmm.cpp delete mode 100644 Alc/backends/winmm.h delete mode 100644 Alc/bformatdec.cpp delete mode 100644 Alc/bformatdec.h delete mode 100644 Alc/bs2b.cpp delete mode 100644 Alc/bs2b.h delete mode 100644 Alc/compat.h delete mode 100644 Alc/converter.cpp delete mode 100644 Alc/converter.h delete mode 100644 Alc/cpu_caps.h delete mode 100644 Alc/effects/autowah.cpp delete mode 100644 Alc/effects/base.h delete mode 100644 Alc/effects/chorus.cpp delete mode 100644 Alc/effects/compressor.cpp delete mode 100644 Alc/effects/dedicated.cpp delete mode 100644 Alc/effects/distortion.cpp delete mode 100644 Alc/effects/echo.cpp delete mode 100644 Alc/effects/equalizer.cpp delete mode 100644 Alc/effects/fshifter.cpp delete mode 100644 Alc/effects/modulator.cpp delete mode 100644 Alc/effects/null.cpp delete mode 100644 Alc/effects/pshifter.cpp delete mode 100644 Alc/effects/reverb.cpp delete mode 100644 Alc/effects/vmorpher.cpp delete mode 100644 Alc/filters/biquad.cpp delete mode 100644 Alc/filters/biquad.h delete mode 100644 Alc/filters/nfc.cpp delete mode 100644 Alc/filters/nfc.h delete mode 100644 Alc/filters/splitter.cpp delete mode 100644 Alc/filters/splitter.h delete mode 100644 Alc/fpu_modes.h delete mode 100644 Alc/helpers.cpp delete mode 100644 Alc/hrtf.cpp delete mode 100644 Alc/hrtf.h delete mode 100644 Alc/inprogext.h delete mode 100644 Alc/logging.h delete mode 100644 Alc/mastering.cpp delete mode 100644 Alc/mastering.h delete mode 100644 Alc/mixer/defs.h delete mode 100644 Alc/mixer/hrtfbase.h delete mode 100644 Alc/mixer/mixer_c.cpp delete mode 100644 Alc/mixer/mixer_neon.cpp delete mode 100644 Alc/mixer/mixer_sse.cpp delete mode 100644 Alc/mixer/mixer_sse2.cpp delete mode 100644 Alc/mixer/mixer_sse3.cpp delete mode 100644 Alc/mixer/mixer_sse41.cpp delete mode 100644 Alc/mixvoice.cpp delete mode 100644 Alc/panning.cpp delete mode 100644 Alc/ringbuffer.cpp delete mode 100644 Alc/ringbuffer.h delete mode 100644 Alc/uhjfilter.cpp delete mode 100644 Alc/uhjfilter.h delete mode 100644 Alc/vector.h create mode 100644 alc/alc.cpp create mode 100644 alc/alcmain.h create mode 100644 alc/alconfig.cpp create mode 100644 alc/alconfig.h create mode 100644 alc/alcontext.h create mode 100644 alc/alu.cpp create mode 100644 alc/alu.h create mode 100644 alc/ambdec.cpp create mode 100644 alc/ambdec.h create mode 100644 alc/ambidefs.h create mode 100644 alc/backends/alsa.cpp create mode 100644 alc/backends/alsa.h create mode 100644 alc/backends/base.cpp create mode 100644 alc/backends/base.h create mode 100644 alc/backends/coreaudio.cpp create mode 100644 alc/backends/coreaudio.h create mode 100644 alc/backends/dsound.cpp create mode 100644 alc/backends/dsound.h create mode 100644 alc/backends/jack.cpp create mode 100644 alc/backends/jack.h create mode 100644 alc/backends/loopback.cpp create mode 100644 alc/backends/loopback.h create mode 100644 alc/backends/null.cpp create mode 100644 alc/backends/null.h create mode 100644 alc/backends/opensl.cpp create mode 100644 alc/backends/opensl.h create mode 100644 alc/backends/oss.cpp create mode 100644 alc/backends/oss.h create mode 100644 alc/backends/portaudio.cpp create mode 100644 alc/backends/portaudio.h create mode 100644 alc/backends/pulseaudio.cpp create mode 100644 alc/backends/pulseaudio.h create mode 100644 alc/backends/qsa.cpp create mode 100644 alc/backends/qsa.h create mode 100644 alc/backends/sdl2.cpp create mode 100644 alc/backends/sdl2.h create mode 100644 alc/backends/sndio.cpp create mode 100644 alc/backends/sndio.h create mode 100644 alc/backends/solaris.cpp create mode 100644 alc/backends/solaris.h create mode 100644 alc/backends/wasapi.cpp create mode 100644 alc/backends/wasapi.h create mode 100644 alc/backends/wave.cpp create mode 100644 alc/backends/wave.h create mode 100644 alc/backends/winmm.cpp create mode 100644 alc/backends/winmm.h create mode 100644 alc/bformatdec.cpp create mode 100644 alc/bformatdec.h create mode 100644 alc/bs2b.cpp create mode 100644 alc/bs2b.h create mode 100644 alc/compat.h create mode 100644 alc/converter.cpp create mode 100644 alc/converter.h create mode 100644 alc/cpu_caps.h create mode 100644 alc/effects/autowah.cpp create mode 100644 alc/effects/base.h create mode 100644 alc/effects/chorus.cpp create mode 100644 alc/effects/compressor.cpp create mode 100644 alc/effects/dedicated.cpp create mode 100644 alc/effects/distortion.cpp create mode 100644 alc/effects/echo.cpp create mode 100644 alc/effects/equalizer.cpp create mode 100644 alc/effects/fshifter.cpp create mode 100644 alc/effects/modulator.cpp create mode 100644 alc/effects/null.cpp create mode 100644 alc/effects/pshifter.cpp create mode 100644 alc/effects/reverb.cpp create mode 100644 alc/effects/vmorpher.cpp create mode 100644 alc/filters/biquad.cpp create mode 100644 alc/filters/biquad.h create mode 100644 alc/filters/nfc.cpp create mode 100644 alc/filters/nfc.h create mode 100644 alc/filters/splitter.cpp create mode 100644 alc/filters/splitter.h create mode 100644 alc/fpu_modes.h create mode 100644 alc/helpers.cpp create mode 100644 alc/hrtf.cpp create mode 100644 alc/hrtf.h create mode 100644 alc/inprogext.h create mode 100644 alc/logging.h create mode 100644 alc/mastering.cpp create mode 100644 alc/mastering.h create mode 100644 alc/mixer/defs.h create mode 100644 alc/mixer/hrtfbase.h create mode 100644 alc/mixer/mixer_c.cpp create mode 100644 alc/mixer/mixer_neon.cpp create mode 100644 alc/mixer/mixer_sse.cpp create mode 100644 alc/mixer/mixer_sse2.cpp create mode 100644 alc/mixer/mixer_sse3.cpp create mode 100644 alc/mixer/mixer_sse41.cpp create mode 100644 alc/mixvoice.cpp create mode 100644 alc/panning.cpp create mode 100644 alc/ringbuffer.cpp create mode 100644 alc/ringbuffer.h create mode 100644 alc/uhjfilter.cpp create mode 100644 alc/uhjfilter.h create mode 100644 alc/vector.h diff --git a/Alc/alc.cpp b/Alc/alc.cpp deleted file mode 100644 index 00f90d91..00000000 --- a/Alc/alc.cpp +++ /dev/null @@ -1,4342 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "version.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" -#include "AL/efx.h" - -#include "alAuxEffectSlot.h" -#include "alcmain.h" -#include "alEffect.h" -#include "alError.h" -#include "alFilter.h" -#include "alListener.h" -#include "alSource.h" -#include "albyte.h" -#include "alconfig.h" -#include "alcontext.h" -#include "alexcpt.h" -#include "almalloc.h" -#include "alnumeric.h" -#include "aloptional.h" -#include "alspan.h" -#include "alu.h" -#include "ambidefs.h" -#include "atomic.h" -#include "bformatdec.h" -#include "bs2b.h" -#include "compat.h" -#include "cpu_caps.h" -#include "effects/base.h" -#include "filters/nfc.h" -#include "filters/splitter.h" -#include "fpu_modes.h" -#include "hrtf.h" -#include "inprogext.h" -#include "logging.h" -#include "mastering.h" -#include "opthelpers.h" -#include "ringbuffer.h" -#include "threads.h" -#include "uhjfilter.h" -#include "vecmat.h" -#include "vector.h" - -#include "backends/base.h" -#include "backends/null.h" -#include "backends/loopback.h" -#ifdef HAVE_JACK -#include "backends/jack.h" -#endif -#ifdef HAVE_PULSEAUDIO -#include "backends/pulseaudio.h" -#endif -#ifdef HAVE_ALSA -#include "backends/alsa.h" -#endif -#ifdef HAVE_WASAPI -#include "backends/wasapi.h" -#endif -#ifdef HAVE_COREAUDIO -#include "backends/coreaudio.h" -#endif -#ifdef HAVE_OPENSL -#include "backends/opensl.h" -#endif -#ifdef HAVE_SOLARIS -#include "backends/solaris.h" -#endif -#ifdef HAVE_SNDIO -#include "backends/sndio.h" -#endif -#ifdef HAVE_OSS -#include "backends/oss.h" -#endif -#ifdef HAVE_QSA -#include "backends/qsa.h" -#endif -#ifdef HAVE_DSOUND -#include "backends/dsound.h" -#endif -#ifdef HAVE_WINMM -#include "backends/winmm.h" -#endif -#ifdef HAVE_PORTAUDIO -#include "backends/portaudio.h" -#endif -#ifdef HAVE_SDL2 -#include "backends/sdl2.h" -#endif -#ifdef HAVE_WAVE -#include "backends/wave.h" -#endif - - -namespace { - -using namespace std::placeholders; -using std::chrono::seconds; -using std::chrono::nanoseconds; - - -/************************************************ - * Backends - ************************************************/ -struct BackendInfo { - const char *name; - BackendFactory& (*getFactory)(void); -}; - -BackendInfo BackendList[] = { -#ifdef HAVE_JACK - { "jack", JackBackendFactory::getFactory }, -#endif -#ifdef HAVE_PULSEAUDIO - { "pulse", PulseBackendFactory::getFactory }, -#endif -#ifdef HAVE_ALSA - { "alsa", AlsaBackendFactory::getFactory }, -#endif -#ifdef HAVE_WASAPI - { "wasapi", WasapiBackendFactory::getFactory }, -#endif -#ifdef HAVE_COREAUDIO - { "core", CoreAudioBackendFactory::getFactory }, -#endif -#ifdef HAVE_OPENSL - { "opensl", OSLBackendFactory::getFactory }, -#endif -#ifdef HAVE_SOLARIS - { "solaris", SolarisBackendFactory::getFactory }, -#endif -#ifdef HAVE_SNDIO - { "sndio", SndIOBackendFactory::getFactory }, -#endif -#ifdef HAVE_OSS - { "oss", OSSBackendFactory::getFactory }, -#endif -#ifdef HAVE_QSA - { "qsa", QSABackendFactory::getFactory }, -#endif -#ifdef HAVE_DSOUND - { "dsound", DSoundBackendFactory::getFactory }, -#endif -#ifdef HAVE_WINMM - { "winmm", WinMMBackendFactory::getFactory }, -#endif -#ifdef HAVE_PORTAUDIO - { "port", PortBackendFactory::getFactory }, -#endif -#ifdef HAVE_SDL2 - { "sdl2", SDL2BackendFactory::getFactory }, -#endif - - { "null", NullBackendFactory::getFactory }, -#ifdef HAVE_WAVE - { "wave", WaveBackendFactory::getFactory }, -#endif -}; -auto BackendListEnd = std::end(BackendList); - -BackendFactory *PlaybackFactory{}; -BackendFactory *CaptureFactory{}; - - -/************************************************ - * Functions, enums, and errors - ************************************************/ -#define DECL(x) { #x, (ALCvoid*)(x) } -const struct { - const ALCchar *funcName; - ALCvoid *address; -} alcFunctions[] = { - DECL(alcCreateContext), - DECL(alcMakeContextCurrent), - DECL(alcProcessContext), - DECL(alcSuspendContext), - DECL(alcDestroyContext), - DECL(alcGetCurrentContext), - DECL(alcGetContextsDevice), - DECL(alcOpenDevice), - DECL(alcCloseDevice), - DECL(alcGetError), - DECL(alcIsExtensionPresent), - DECL(alcGetProcAddress), - DECL(alcGetEnumValue), - DECL(alcGetString), - DECL(alcGetIntegerv), - DECL(alcCaptureOpenDevice), - DECL(alcCaptureCloseDevice), - DECL(alcCaptureStart), - DECL(alcCaptureStop), - DECL(alcCaptureSamples), - - DECL(alcSetThreadContext), - DECL(alcGetThreadContext), - - DECL(alcLoopbackOpenDeviceSOFT), - DECL(alcIsRenderFormatSupportedSOFT), - DECL(alcRenderSamplesSOFT), - - DECL(alcDevicePauseSOFT), - DECL(alcDeviceResumeSOFT), - - DECL(alcGetStringiSOFT), - DECL(alcResetDeviceSOFT), - - DECL(alcGetInteger64vSOFT), - - DECL(alEnable), - DECL(alDisable), - DECL(alIsEnabled), - DECL(alGetString), - DECL(alGetBooleanv), - DECL(alGetIntegerv), - DECL(alGetFloatv), - DECL(alGetDoublev), - DECL(alGetBoolean), - DECL(alGetInteger), - DECL(alGetFloat), - DECL(alGetDouble), - DECL(alGetError), - DECL(alIsExtensionPresent), - DECL(alGetProcAddress), - DECL(alGetEnumValue), - DECL(alListenerf), - DECL(alListener3f), - DECL(alListenerfv), - DECL(alListeneri), - DECL(alListener3i), - DECL(alListeneriv), - DECL(alGetListenerf), - DECL(alGetListener3f), - DECL(alGetListenerfv), - DECL(alGetListeneri), - DECL(alGetListener3i), - DECL(alGetListeneriv), - DECL(alGenSources), - DECL(alDeleteSources), - DECL(alIsSource), - DECL(alSourcef), - DECL(alSource3f), - DECL(alSourcefv), - DECL(alSourcei), - DECL(alSource3i), - DECL(alSourceiv), - DECL(alGetSourcef), - DECL(alGetSource3f), - DECL(alGetSourcefv), - DECL(alGetSourcei), - DECL(alGetSource3i), - DECL(alGetSourceiv), - DECL(alSourcePlayv), - DECL(alSourceStopv), - DECL(alSourceRewindv), - DECL(alSourcePausev), - DECL(alSourcePlay), - DECL(alSourceStop), - DECL(alSourceRewind), - DECL(alSourcePause), - DECL(alSourceQueueBuffers), - DECL(alSourceUnqueueBuffers), - DECL(alGenBuffers), - DECL(alDeleteBuffers), - DECL(alIsBuffer), - DECL(alBufferData), - DECL(alBufferf), - DECL(alBuffer3f), - DECL(alBufferfv), - DECL(alBufferi), - DECL(alBuffer3i), - DECL(alBufferiv), - DECL(alGetBufferf), - DECL(alGetBuffer3f), - DECL(alGetBufferfv), - DECL(alGetBufferi), - DECL(alGetBuffer3i), - DECL(alGetBufferiv), - DECL(alDopplerFactor), - DECL(alDopplerVelocity), - DECL(alSpeedOfSound), - DECL(alDistanceModel), - - DECL(alGenFilters), - DECL(alDeleteFilters), - DECL(alIsFilter), - DECL(alFilteri), - DECL(alFilteriv), - DECL(alFilterf), - DECL(alFilterfv), - DECL(alGetFilteri), - DECL(alGetFilteriv), - DECL(alGetFilterf), - DECL(alGetFilterfv), - DECL(alGenEffects), - DECL(alDeleteEffects), - DECL(alIsEffect), - DECL(alEffecti), - DECL(alEffectiv), - DECL(alEffectf), - DECL(alEffectfv), - DECL(alGetEffecti), - DECL(alGetEffectiv), - DECL(alGetEffectf), - DECL(alGetEffectfv), - DECL(alGenAuxiliaryEffectSlots), - DECL(alDeleteAuxiliaryEffectSlots), - DECL(alIsAuxiliaryEffectSlot), - DECL(alAuxiliaryEffectSloti), - DECL(alAuxiliaryEffectSlotiv), - DECL(alAuxiliaryEffectSlotf), - DECL(alAuxiliaryEffectSlotfv), - DECL(alGetAuxiliaryEffectSloti), - DECL(alGetAuxiliaryEffectSlotiv), - DECL(alGetAuxiliaryEffectSlotf), - DECL(alGetAuxiliaryEffectSlotfv), - - DECL(alDeferUpdatesSOFT), - DECL(alProcessUpdatesSOFT), - - DECL(alSourcedSOFT), - DECL(alSource3dSOFT), - DECL(alSourcedvSOFT), - DECL(alGetSourcedSOFT), - DECL(alGetSource3dSOFT), - DECL(alGetSourcedvSOFT), - DECL(alSourcei64SOFT), - DECL(alSource3i64SOFT), - DECL(alSourcei64vSOFT), - DECL(alGetSourcei64SOFT), - DECL(alGetSource3i64SOFT), - DECL(alGetSourcei64vSOFT), - - DECL(alGetStringiSOFT), - - DECL(alBufferStorageSOFT), - DECL(alMapBufferSOFT), - DECL(alUnmapBufferSOFT), - DECL(alFlushMappedBufferSOFT), - - DECL(alEventControlSOFT), - DECL(alEventCallbackSOFT), - DECL(alGetPointerSOFT), - DECL(alGetPointervSOFT), -}; -#undef DECL - -#define DECL(x) { #x, (x) } -constexpr struct { - const ALCchar *enumName; - ALCenum value; -} alcEnumerations[] = { - DECL(ALC_INVALID), - DECL(ALC_FALSE), - DECL(ALC_TRUE), - - DECL(ALC_MAJOR_VERSION), - DECL(ALC_MINOR_VERSION), - DECL(ALC_ATTRIBUTES_SIZE), - DECL(ALC_ALL_ATTRIBUTES), - DECL(ALC_DEFAULT_DEVICE_SPECIFIER), - DECL(ALC_DEVICE_SPECIFIER), - DECL(ALC_ALL_DEVICES_SPECIFIER), - DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER), - DECL(ALC_EXTENSIONS), - DECL(ALC_FREQUENCY), - DECL(ALC_REFRESH), - DECL(ALC_SYNC), - DECL(ALC_MONO_SOURCES), - DECL(ALC_STEREO_SOURCES), - DECL(ALC_CAPTURE_DEVICE_SPECIFIER), - DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER), - DECL(ALC_CAPTURE_SAMPLES), - DECL(ALC_CONNECTED), - - DECL(ALC_EFX_MAJOR_VERSION), - DECL(ALC_EFX_MINOR_VERSION), - DECL(ALC_MAX_AUXILIARY_SENDS), - - DECL(ALC_FORMAT_CHANNELS_SOFT), - DECL(ALC_FORMAT_TYPE_SOFT), - - DECL(ALC_MONO_SOFT), - DECL(ALC_STEREO_SOFT), - DECL(ALC_QUAD_SOFT), - DECL(ALC_5POINT1_SOFT), - DECL(ALC_6POINT1_SOFT), - DECL(ALC_7POINT1_SOFT), - DECL(ALC_BFORMAT3D_SOFT), - - DECL(ALC_BYTE_SOFT), - DECL(ALC_UNSIGNED_BYTE_SOFT), - DECL(ALC_SHORT_SOFT), - DECL(ALC_UNSIGNED_SHORT_SOFT), - DECL(ALC_INT_SOFT), - DECL(ALC_UNSIGNED_INT_SOFT), - DECL(ALC_FLOAT_SOFT), - - DECL(ALC_HRTF_SOFT), - DECL(ALC_DONT_CARE_SOFT), - DECL(ALC_HRTF_STATUS_SOFT), - DECL(ALC_HRTF_DISABLED_SOFT), - DECL(ALC_HRTF_ENABLED_SOFT), - DECL(ALC_HRTF_DENIED_SOFT), - DECL(ALC_HRTF_REQUIRED_SOFT), - DECL(ALC_HRTF_HEADPHONES_DETECTED_SOFT), - DECL(ALC_HRTF_UNSUPPORTED_FORMAT_SOFT), - DECL(ALC_NUM_HRTF_SPECIFIERS_SOFT), - DECL(ALC_HRTF_SPECIFIER_SOFT), - DECL(ALC_HRTF_ID_SOFT), - - DECL(ALC_AMBISONIC_LAYOUT_SOFT), - DECL(ALC_AMBISONIC_SCALING_SOFT), - DECL(ALC_AMBISONIC_ORDER_SOFT), - DECL(ALC_ACN_SOFT), - DECL(ALC_FUMA_SOFT), - DECL(ALC_N3D_SOFT), - DECL(ALC_SN3D_SOFT), - - DECL(ALC_OUTPUT_LIMITER_SOFT), - - DECL(ALC_NO_ERROR), - DECL(ALC_INVALID_DEVICE), - DECL(ALC_INVALID_CONTEXT), - DECL(ALC_INVALID_ENUM), - DECL(ALC_INVALID_VALUE), - DECL(ALC_OUT_OF_MEMORY), - - - DECL(AL_INVALID), - DECL(AL_NONE), - DECL(AL_FALSE), - DECL(AL_TRUE), - - DECL(AL_SOURCE_RELATIVE), - DECL(AL_CONE_INNER_ANGLE), - DECL(AL_CONE_OUTER_ANGLE), - DECL(AL_PITCH), - DECL(AL_POSITION), - DECL(AL_DIRECTION), - DECL(AL_VELOCITY), - DECL(AL_LOOPING), - DECL(AL_BUFFER), - DECL(AL_GAIN), - DECL(AL_MIN_GAIN), - DECL(AL_MAX_GAIN), - DECL(AL_ORIENTATION), - DECL(AL_REFERENCE_DISTANCE), - DECL(AL_ROLLOFF_FACTOR), - DECL(AL_CONE_OUTER_GAIN), - DECL(AL_MAX_DISTANCE), - DECL(AL_SEC_OFFSET), - DECL(AL_SAMPLE_OFFSET), - DECL(AL_BYTE_OFFSET), - DECL(AL_SOURCE_TYPE), - DECL(AL_STATIC), - DECL(AL_STREAMING), - DECL(AL_UNDETERMINED), - DECL(AL_METERS_PER_UNIT), - DECL(AL_LOOP_POINTS_SOFT), - DECL(AL_DIRECT_CHANNELS_SOFT), - - DECL(AL_DIRECT_FILTER), - DECL(AL_AUXILIARY_SEND_FILTER), - DECL(AL_AIR_ABSORPTION_FACTOR), - DECL(AL_ROOM_ROLLOFF_FACTOR), - DECL(AL_CONE_OUTER_GAINHF), - DECL(AL_DIRECT_FILTER_GAINHF_AUTO), - DECL(AL_AUXILIARY_SEND_FILTER_GAIN_AUTO), - DECL(AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO), - - DECL(AL_SOURCE_STATE), - DECL(AL_INITIAL), - DECL(AL_PLAYING), - DECL(AL_PAUSED), - DECL(AL_STOPPED), - - DECL(AL_BUFFERS_QUEUED), - DECL(AL_BUFFERS_PROCESSED), - - DECL(AL_FORMAT_MONO8), - DECL(AL_FORMAT_MONO16), - DECL(AL_FORMAT_MONO_FLOAT32), - DECL(AL_FORMAT_MONO_DOUBLE_EXT), - DECL(AL_FORMAT_STEREO8), - DECL(AL_FORMAT_STEREO16), - DECL(AL_FORMAT_STEREO_FLOAT32), - 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), - DECL(AL_FORMAT_QUAD16), - DECL(AL_FORMAT_QUAD32), - DECL(AL_FORMAT_51CHN8), - DECL(AL_FORMAT_51CHN16), - DECL(AL_FORMAT_51CHN32), - DECL(AL_FORMAT_61CHN8), - DECL(AL_FORMAT_61CHN16), - DECL(AL_FORMAT_61CHN32), - DECL(AL_FORMAT_71CHN8), - DECL(AL_FORMAT_71CHN16), - DECL(AL_FORMAT_71CHN32), - DECL(AL_FORMAT_REAR8), - DECL(AL_FORMAT_REAR16), - DECL(AL_FORMAT_REAR32), - DECL(AL_FORMAT_MONO_MULAW), - DECL(AL_FORMAT_MONO_MULAW_EXT), - DECL(AL_FORMAT_STEREO_MULAW), - DECL(AL_FORMAT_STEREO_MULAW_EXT), - DECL(AL_FORMAT_QUAD_MULAW), - DECL(AL_FORMAT_51CHN_MULAW), - DECL(AL_FORMAT_61CHN_MULAW), - DECL(AL_FORMAT_71CHN_MULAW), - DECL(AL_FORMAT_REAR_MULAW), - DECL(AL_FORMAT_MONO_ALAW_EXT), - DECL(AL_FORMAT_STEREO_ALAW_EXT), - - DECL(AL_FORMAT_BFORMAT2D_8), - DECL(AL_FORMAT_BFORMAT2D_16), - DECL(AL_FORMAT_BFORMAT2D_FLOAT32), - DECL(AL_FORMAT_BFORMAT2D_MULAW), - DECL(AL_FORMAT_BFORMAT3D_8), - DECL(AL_FORMAT_BFORMAT3D_16), - DECL(AL_FORMAT_BFORMAT3D_FLOAT32), - DECL(AL_FORMAT_BFORMAT3D_MULAW), - - DECL(AL_FREQUENCY), - DECL(AL_BITS), - DECL(AL_CHANNELS), - DECL(AL_SIZE), - DECL(AL_UNPACK_BLOCK_ALIGNMENT_SOFT), - DECL(AL_PACK_BLOCK_ALIGNMENT_SOFT), - - DECL(AL_SOURCE_RADIUS), - - DECL(AL_STEREO_ANGLES), - - DECL(AL_UNUSED), - DECL(AL_PENDING), - DECL(AL_PROCESSED), - - DECL(AL_NO_ERROR), - DECL(AL_INVALID_NAME), - DECL(AL_INVALID_ENUM), - DECL(AL_INVALID_VALUE), - DECL(AL_INVALID_OPERATION), - DECL(AL_OUT_OF_MEMORY), - - DECL(AL_VENDOR), - DECL(AL_VERSION), - DECL(AL_RENDERER), - DECL(AL_EXTENSIONS), - - DECL(AL_DOPPLER_FACTOR), - DECL(AL_DOPPLER_VELOCITY), - DECL(AL_DISTANCE_MODEL), - DECL(AL_SPEED_OF_SOUND), - DECL(AL_SOURCE_DISTANCE_MODEL), - DECL(AL_DEFERRED_UPDATES_SOFT), - DECL(AL_GAIN_LIMIT_SOFT), - - DECL(AL_INVERSE_DISTANCE), - DECL(AL_INVERSE_DISTANCE_CLAMPED), - DECL(AL_LINEAR_DISTANCE), - DECL(AL_LINEAR_DISTANCE_CLAMPED), - DECL(AL_EXPONENT_DISTANCE), - DECL(AL_EXPONENT_DISTANCE_CLAMPED), - - DECL(AL_FILTER_TYPE), - DECL(AL_FILTER_NULL), - DECL(AL_FILTER_LOWPASS), - DECL(AL_FILTER_HIGHPASS), - DECL(AL_FILTER_BANDPASS), - - 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), - DECL(AL_EFFECT_EAXREVERB), - DECL(AL_EFFECT_CHORUS), - DECL(AL_EFFECT_DISTORTION), - DECL(AL_EFFECT_ECHO), - DECL(AL_EFFECT_FLANGER), - DECL(AL_EFFECT_PITCH_SHIFTER), - DECL(AL_EFFECT_FREQUENCY_SHIFTER), - DECL(AL_EFFECT_VOCAL_MORPHER), - DECL(AL_EFFECT_RING_MODULATOR), - DECL(AL_EFFECT_AUTOWAH), - DECL(AL_EFFECT_COMPRESSOR), - DECL(AL_EFFECT_EQUALIZER), - DECL(AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT), - DECL(AL_EFFECT_DEDICATED_DIALOGUE), - - DECL(AL_EFFECTSLOT_EFFECT), - DECL(AL_EFFECTSLOT_GAIN), - DECL(AL_EFFECTSLOT_AUXILIARY_SEND_AUTO), - DECL(AL_EFFECTSLOT_NULL), - - DECL(AL_EAXREVERB_DENSITY), - DECL(AL_EAXREVERB_DIFFUSION), - DECL(AL_EAXREVERB_GAIN), - DECL(AL_EAXREVERB_GAINHF), - DECL(AL_EAXREVERB_GAINLF), - DECL(AL_EAXREVERB_DECAY_TIME), - DECL(AL_EAXREVERB_DECAY_HFRATIO), - DECL(AL_EAXREVERB_DECAY_LFRATIO), - DECL(AL_EAXREVERB_REFLECTIONS_GAIN), - DECL(AL_EAXREVERB_REFLECTIONS_DELAY), - DECL(AL_EAXREVERB_REFLECTIONS_PAN), - DECL(AL_EAXREVERB_LATE_REVERB_GAIN), - DECL(AL_EAXREVERB_LATE_REVERB_DELAY), - DECL(AL_EAXREVERB_LATE_REVERB_PAN), - DECL(AL_EAXREVERB_ECHO_TIME), - DECL(AL_EAXREVERB_ECHO_DEPTH), - DECL(AL_EAXREVERB_MODULATION_TIME), - DECL(AL_EAXREVERB_MODULATION_DEPTH), - DECL(AL_EAXREVERB_AIR_ABSORPTION_GAINHF), - DECL(AL_EAXREVERB_HFREFERENCE), - DECL(AL_EAXREVERB_LFREFERENCE), - DECL(AL_EAXREVERB_ROOM_ROLLOFF_FACTOR), - DECL(AL_EAXREVERB_DECAY_HFLIMIT), - - DECL(AL_REVERB_DENSITY), - DECL(AL_REVERB_DIFFUSION), - DECL(AL_REVERB_GAIN), - DECL(AL_REVERB_GAINHF), - DECL(AL_REVERB_DECAY_TIME), - DECL(AL_REVERB_DECAY_HFRATIO), - DECL(AL_REVERB_REFLECTIONS_GAIN), - DECL(AL_REVERB_REFLECTIONS_DELAY), - DECL(AL_REVERB_LATE_REVERB_GAIN), - DECL(AL_REVERB_LATE_REVERB_DELAY), - DECL(AL_REVERB_AIR_ABSORPTION_GAINHF), - DECL(AL_REVERB_ROOM_ROLLOFF_FACTOR), - DECL(AL_REVERB_DECAY_HFLIMIT), - - DECL(AL_CHORUS_WAVEFORM), - DECL(AL_CHORUS_PHASE), - DECL(AL_CHORUS_RATE), - DECL(AL_CHORUS_DEPTH), - DECL(AL_CHORUS_FEEDBACK), - DECL(AL_CHORUS_DELAY), - - DECL(AL_DISTORTION_EDGE), - DECL(AL_DISTORTION_GAIN), - DECL(AL_DISTORTION_LOWPASS_CUTOFF), - DECL(AL_DISTORTION_EQCENTER), - DECL(AL_DISTORTION_EQBANDWIDTH), - - DECL(AL_ECHO_DELAY), - DECL(AL_ECHO_LRDELAY), - DECL(AL_ECHO_DAMPING), - DECL(AL_ECHO_FEEDBACK), - DECL(AL_ECHO_SPREAD), - - DECL(AL_FLANGER_WAVEFORM), - DECL(AL_FLANGER_PHASE), - DECL(AL_FLANGER_RATE), - DECL(AL_FLANGER_DEPTH), - DECL(AL_FLANGER_FEEDBACK), - DECL(AL_FLANGER_DELAY), - - DECL(AL_FREQUENCY_SHIFTER_FREQUENCY), - DECL(AL_FREQUENCY_SHIFTER_LEFT_DIRECTION), - DECL(AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION), - - DECL(AL_RING_MODULATOR_FREQUENCY), - DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF), - DECL(AL_RING_MODULATOR_WAVEFORM), - - DECL(AL_PITCH_SHIFTER_COARSE_TUNE), - DECL(AL_PITCH_SHIFTER_FINE_TUNE), - - DECL(AL_COMPRESSOR_ONOFF), - - DECL(AL_EQUALIZER_LOW_GAIN), - DECL(AL_EQUALIZER_LOW_CUTOFF), - DECL(AL_EQUALIZER_MID1_GAIN), - DECL(AL_EQUALIZER_MID1_CENTER), - DECL(AL_EQUALIZER_MID1_WIDTH), - DECL(AL_EQUALIZER_MID2_GAIN), - DECL(AL_EQUALIZER_MID2_CENTER), - DECL(AL_EQUALIZER_MID2_WIDTH), - DECL(AL_EQUALIZER_HIGH_GAIN), - DECL(AL_EQUALIZER_HIGH_CUTOFF), - - DECL(AL_DEDICATED_GAIN), - - DECL(AL_AUTOWAH_ATTACK_TIME), - DECL(AL_AUTOWAH_RELEASE_TIME), - DECL(AL_AUTOWAH_RESONANCE), - DECL(AL_AUTOWAH_PEAK_GAIN), - - DECL(AL_NUM_RESAMPLERS_SOFT), - DECL(AL_DEFAULT_RESAMPLER_SOFT), - DECL(AL_SOURCE_RESAMPLER_SOFT), - DECL(AL_RESAMPLER_NAME_SOFT), - - DECL(AL_SOURCE_SPATIALIZE_SOFT), - DECL(AL_AUTO_SOFT), - - DECL(AL_MAP_READ_BIT_SOFT), - DECL(AL_MAP_WRITE_BIT_SOFT), - DECL(AL_MAP_PERSISTENT_BIT_SOFT), - DECL(AL_PRESERVE_DATA_BIT_SOFT), - - DECL(AL_EVENT_CALLBACK_FUNCTION_SOFT), - DECL(AL_EVENT_CALLBACK_USER_PARAM_SOFT), - DECL(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT), - DECL(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT), - DECL(AL_EVENT_TYPE_ERROR_SOFT), - DECL(AL_EVENT_TYPE_PERFORMANCE_SOFT), - DECL(AL_EVENT_TYPE_DEPRECATED_SOFT), -}; -#undef DECL - -constexpr ALCchar alcNoError[] = "No Error"; -constexpr ALCchar alcErrInvalidDevice[] = "Invalid Device"; -constexpr ALCchar alcErrInvalidContext[] = "Invalid Context"; -constexpr ALCchar alcErrInvalidEnum[] = "Invalid Enum"; -constexpr ALCchar alcErrInvalidValue[] = "Invalid Value"; -constexpr ALCchar alcErrOutOfMemory[] = "Out of Memory"; - - -/************************************************ - * Global variables - ************************************************/ - -/* Enumerated device names */ -constexpr ALCchar alcDefaultName[] = "OpenAL Soft\0"; - -std::string alcAllDevicesList; -std::string alcCaptureDeviceList; - -/* Default is always the first in the list */ -std::string alcDefaultAllDevicesSpecifier; -std::string alcCaptureDefaultDeviceSpecifier; - -/* Default context extensions */ -constexpr ALchar alExtList[] = - "AL_EXT_ALAW " - "AL_EXT_BFORMAT " - "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_BFORMAT " - "AL_EXT_MULAW_MCFORMATS " - "AL_EXT_OFFSET " - "AL_EXT_source_distance_model " - "AL_EXT_SOURCE_RADIUS " - "AL_EXT_STEREO_ANGLES " - "AL_LOKI_quadriphonic " - "AL_SOFT_block_alignment " - "AL_SOFT_deferred_updates " - "AL_SOFT_direct_channels " - "AL_SOFTX_effect_chain " - "AL_SOFTX_events " - "AL_SOFTX_filter_gain_ex " - "AL_SOFT_gain_clamp_ex " - "AL_SOFT_loop_points " - "AL_SOFTX_map_buffer " - "AL_SOFT_MSADPCM " - "AL_SOFT_source_latency " - "AL_SOFT_source_length " - "AL_SOFT_source_resampler " - "AL_SOFT_source_spatialize"; - -std::atomic LastNullDeviceError{ALC_NO_ERROR}; - -/* Thread-local current context */ -void ReleaseThreadCtx(ALCcontext *context) -{ - auto ref = DecrementRef(&context->ref); - TRACEREF("ALCcontext %p decreasing refcount to %u\n", context, ref); - ERR("Context %p current for thread being destroyed, possible leak!\n", context); -} - -std::atomic ThreadCtxProc{ReleaseThreadCtx}; -class ThreadCtx { - ALCcontext *ctx{nullptr}; - -public: - ~ThreadCtx() - { - auto destruct = ThreadCtxProc.load(); - if(destruct && ctx) - destruct(ctx); - ctx = nullptr; - } - - ALCcontext *get() const noexcept { return ctx; } - void set(ALCcontext *ctx_) noexcept { ctx = ctx_; } -}; -thread_local ThreadCtx LocalContext; -/* Process-wide current context */ -std::atomic GlobalContext{nullptr}; - -/* Flag to trap ALC device errors */ -bool TrapALCError{false}; - -/* One-time configuration init control */ -std::once_flag alc_config_once{}; - -/* Default effect that applies to sources that don't have an effect on send 0 */ -ALeffect DefaultEffect; - -/* Flag to specify if alcSuspendContext/alcProcessContext should defer/process - * updates. - */ -bool SuspendDefers{true}; - - -/************************************************ - * ALC information - ************************************************/ -constexpr ALCchar alcNoDeviceExtList[] = - "ALC_ENUMERATE_ALL_EXT " - "ALC_ENUMERATION_EXT " - "ALC_EXT_CAPTURE " - "ALC_EXT_thread_local_context " - "ALC_SOFT_loopback"; -constexpr ALCchar alcExtensionList[] = - "ALC_ENUMERATE_ALL_EXT " - "ALC_ENUMERATION_EXT " - "ALC_EXT_CAPTURE " - "ALC_EXT_DEDICATED " - "ALC_EXT_disconnect " - "ALC_EXT_EFX " - "ALC_EXT_thread_local_context " - "ALC_SOFT_device_clock " - "ALC_SOFT_HRTF " - "ALC_SOFT_loopback " - "ALC_SOFT_output_limiter " - "ALC_SOFT_pause_device"; -constexpr ALCint alcMajorVersion = 1; -constexpr ALCint alcMinorVersion = 1; - -constexpr ALCint alcEFXMajorVersion = 1; -constexpr ALCint alcEFXMinorVersion = 0; - - -/* To avoid extraneous allocations, a 0-sized FlexArray is defined - * globally as a sharable object. - */ -al::FlexArray EmptyContextArray{0u}; - - -void ALCdevice_IncRef(ALCdevice *device) -{ - auto ref = IncrementRef(&device->ref); - TRACEREF("ALCdevice %p increasing refcount to %u\n", device, ref); -} - -void ALCdevice_DecRef(ALCdevice *device) -{ - auto ref = DecrementRef(&device->ref); - TRACEREF("ALCdevice %p decreasing refcount to %u\n", device, ref); - if(UNLIKELY(ref == 0)) delete device; -} - -/* Simple RAII device reference. Takes the reference of the provided ALCdevice, - * and decrements it when leaving scope. Movable (transfer reference) but not - * copyable (no new references). - */ -class DeviceRef { - ALCdevice *mDev{nullptr}; - - void reset() noexcept - { - if(mDev) - ALCdevice_DecRef(mDev); - mDev = nullptr; - } - -public: - DeviceRef() noexcept = default; - DeviceRef(DeviceRef&& rhs) noexcept : mDev{rhs.mDev} - { rhs.mDev = nullptr; } - explicit DeviceRef(ALCdevice *dev) noexcept : mDev(dev) { } - ~DeviceRef() { reset(); } - - DeviceRef& operator=(const DeviceRef&) = delete; - DeviceRef& operator=(DeviceRef&& rhs) noexcept - { - std::swap(mDev, rhs.mDev); - return *this; - } - - operator bool() const noexcept { return mDev != nullptr; } - - ALCdevice* operator->() const noexcept { return mDev; } - ALCdevice* get() const noexcept { return mDev; } - - ALCdevice* release() noexcept - { - ALCdevice *ret{mDev}; - mDev = nullptr; - return ret; - } -}; - -inline bool operator==(const DeviceRef &lhs, const ALCdevice *rhs) noexcept -{ return lhs.get() == rhs; } -inline bool operator!=(const DeviceRef &lhs, const ALCdevice *rhs) noexcept -{ return !(lhs == rhs); } -inline bool operator<(const DeviceRef &lhs, const ALCdevice *rhs) noexcept -{ return lhs.get() < rhs; } - - -/************************************************ - * Device lists - ************************************************/ -al::vector DeviceList; -al::vector ContextList; - -std::recursive_mutex ListLock; - - -void alc_initconfig(void) -{ - const char *str{getenv("ALSOFT_LOGLEVEL")}; - if(str) - { - long lvl = strtol(str, nullptr, 0); - if(lvl >= NoLog && lvl <= LogRef) - gLogLevel = static_cast(lvl); - } - - str = getenv("ALSOFT_LOGFILE"); - if(str && str[0]) - { -#ifdef _WIN32 - std::wstring wname{utf8_to_wstr(str)}; - FILE *logfile = _wfopen(wname.c_str(), L"wt"); -#else - FILE *logfile = fopen(str, "wt"); -#endif - if(logfile) gLogFile = logfile; - else ERR("Failed to open log file '%s'\n", str); - } - - TRACE("Initializing library v%s-%s %s\n", ALSOFT_VERSION, ALSOFT_GIT_COMMIT_HASH, - ALSOFT_GIT_BRANCH); - { - std::string names; - if(std::begin(BackendList) == BackendListEnd) - names += "(none)"; - else - { - const al::span infos{std::begin(BackendList), BackendListEnd}; - names += infos[0].name; - for(const auto &backend : infos.subspan(1)) - { - names += ", "; - names += backend.name; - } - } - TRACE("Supported backends: %s\n", names.c_str()); - } - ReadALConfig(); - - str = getenv("__ALSOFT_SUSPEND_CONTEXT"); - if(str && *str) - { - if(strcasecmp(str, "ignore") == 0) - { - SuspendDefers = false; - TRACE("Selected context suspend behavior, \"ignore\"\n"); - } - else - ERR("Unhandled context suspend behavior setting: \"%s\"\n", str); - } - - int capfilter{0}; -#if defined(HAVE_SSE4_1) - capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1; -#elif defined(HAVE_SSE3) - capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3; -#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; -#endif - if(auto cpuopt = ConfigValueStr(nullptr, nullptr, "disable-cpu-exts")) - { - str = cpuopt->c_str(); - if(strcasecmp(str, "all") == 0) - capfilter = 0; - else - { - const char *next = str; - do { - str = next; - while(isspace(str[0])) - str++; - next = strchr(str, ','); - - if(!str[0] || str[0] == ',') - continue; - - size_t len{next ? static_cast(next-str) : strlen(str)}; - while(len > 0 && isspace(str[len-1])) - len--; - if(len == 3 && strncasecmp(str, "sse", len) == 0) - capfilter &= ~CPU_CAP_SSE; - else if(len == 4 && strncasecmp(str, "sse2", len) == 0) - capfilter &= ~CPU_CAP_SSE2; - else if(len == 4 && strncasecmp(str, "sse3", len) == 0) - capfilter &= ~CPU_CAP_SSE3; - 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 - WARN("Invalid CPU extension \"%s\"\n", str); - } while(next++); - } - } - FillCPUCaps(capfilter); - -#ifdef _WIN32 -#define DEF_MIXER_PRIO 1 -#else -#define DEF_MIXER_PRIO 0 -#endif - RTPrioLevel = ConfigValueInt(nullptr, nullptr, "rt-prio").value_or(DEF_MIXER_PRIO); -#undef DEF_MIXER_PRIO - - aluInit(); - aluInitMixer(); - - str = getenv("ALSOFT_TRAP_ERROR"); - if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) - { - TrapALError = true; - TrapALCError = true; - } - else - { - str = getenv("ALSOFT_TRAP_AL_ERROR"); - if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) - TrapALError = true; - TrapALError = !!GetConfigValueBool(nullptr, nullptr, "trap-al-error", TrapALError); - - str = getenv("ALSOFT_TRAP_ALC_ERROR"); - if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) - TrapALCError = true; - TrapALCError = !!GetConfigValueBool(nullptr, nullptr, "trap-alc-error", TrapALCError); - } - - if(auto boostopt = ConfigValueFloat(nullptr, "reverb", "boost")) - { - const float valf{std::isfinite(*boostopt) ? clampf(*boostopt, -24.0f, 24.0f) : 0.0f}; - ReverbBoost *= std::pow(10.0f, valf / 20.0f); - } - - auto devopt = ConfigValueStr(nullptr, nullptr, "drivers"); - if(const char *devs{getenv("ALSOFT_DRIVERS")}) - { - if(devs[0]) - devopt = devs; - } - if(devopt) - { - auto backendlist_cur = std::begin(BackendList); - - bool endlist{true}; - const char *next{devopt->c_str()}; - do { - const char *devs{next}; - while(isspace(devs[0])) - devs++; - next = strchr(devs, ','); - - const bool delitem{devs[0] == '-'}; - if(devs[0] == '-') devs++; - - if(!devs[0] || devs[0] == ',') - { - endlist = false; - continue; - } - endlist = true; - - size_t len{next ? (static_cast(next-devs)) : strlen(devs)}; - while(len > 0 && isspace(devs[len-1])) --len; -#ifdef HAVE_WASAPI - /* HACK: For backwards compatibility, convert backend references of - * mmdevapi to wasapi. This should eventually be removed. - */ - if(len == 8 && strncmp(devs, "mmdevapi", len) == 0) - { - devs = "wasapi"; - len = 6; - } -#endif - - auto find_backend = [devs,len](const BackendInfo &backend) -> bool - { return len == strlen(backend.name) && strncmp(backend.name, devs, len) == 0; }; - auto this_backend = std::find_if(std::begin(BackendList), BackendListEnd, - find_backend); - - if(this_backend == BackendListEnd) - continue; - - if(delitem) - BackendListEnd = std::move(this_backend+1, BackendListEnd, this_backend); - else - backendlist_cur = std::rotate(backendlist_cur, this_backend, this_backend+1); - } while(next++); - - if(endlist) - BackendListEnd = backendlist_cur; - } - - auto init_backend = [](BackendInfo &backend) -> bool - { - if(PlaybackFactory && CaptureFactory) - return true; - - BackendFactory &factory = backend.getFactory(); - if(!factory.init()) - { - WARN("Failed to initialize backend \"%s\"\n", backend.name); - return true; - } - - TRACE("Initialized backend \"%s\"\n", backend.name); - if(!PlaybackFactory && factory.querySupport(BackendType::Playback)) - { - PlaybackFactory = &factory; - TRACE("Added \"%s\" for playback\n", backend.name); - } - if(!CaptureFactory && factory.querySupport(BackendType::Capture)) - { - CaptureFactory = &factory; - TRACE("Added \"%s\" for capture\n", backend.name); - } - return false; - }; - BackendListEnd = std::remove_if(std::begin(BackendList), BackendListEnd, init_backend); - - LoopbackBackendFactory::getFactory().init(); - - if(!PlaybackFactory) - WARN("No playback backend available!\n"); - if(!CaptureFactory) - WARN("No capture backend available!\n"); - - if(auto exclopt = ConfigValueStr(nullptr, nullptr, "excludefx")) - { - const char *next{exclopt->c_str()}; - do { - str = next; - next = strchr(str, ','); - - if(!str[0] || next == str) - continue; - - size_t len{next ? static_cast(next-str) : strlen(str)}; - for(const EffectList &effectitem : gEffectList) - { - if(len == strlen(effectitem.name) && - strncmp(effectitem.name, str, len) == 0) - DisabledEffects[effectitem.type] = AL_TRUE; - } - } while(next++); - } - - InitEffect(&DefaultEffect); - auto defrevopt = ConfigValueStr(nullptr, nullptr, "default-reverb"); - if((str=getenv("ALSOFT_DEFAULT_REVERB")) && str[0]) - defrevopt = str; - if(defrevopt) LoadReverbPreset(defrevopt->c_str(), &DefaultEffect); -} -#define DO_INITCONFIG() std::call_once(alc_config_once, [](){alc_initconfig();}) - - -/************************************************ - * Device enumeration - ************************************************/ -void ProbeAllDevicesList() -{ - DO_INITCONFIG(); - - std::lock_guard _{ListLock}; - alcAllDevicesList.clear(); - if(PlaybackFactory) - PlaybackFactory->probe(DevProbe::Playback, &alcAllDevicesList); -} -void ProbeCaptureDeviceList() -{ - DO_INITCONFIG(); - - std::lock_guard _{ListLock}; - alcCaptureDeviceList.clear(); - if(CaptureFactory) - CaptureFactory->probe(DevProbe::Capture, &alcCaptureDeviceList); -} - -} // namespace - -/* Mixing thread piority level */ -ALint RTPrioLevel; - -FILE *gLogFile{stderr}; -#ifdef _DEBUG -LogLevel gLogLevel{LogWarning}; -#else -LogLevel gLogLevel{LogError}; -#endif - -/************************************************ - * Library initialization - ************************************************/ -#if defined(_WIN32) && !defined(AL_LIBTYPE_STATIC) -BOOL APIENTRY DllMain(HINSTANCE module, DWORD reason, LPVOID /*reserved*/) -{ - 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*)module, &module); - break; - - case DLL_PROCESS_DETACH: - break; - } - return TRUE; -} -#endif - -/************************************************ - * Device format information - ************************************************/ -const ALCchar *DevFmtTypeString(DevFmtType type) noexcept -{ - switch(type) - { - case DevFmtByte: return "Signed Byte"; - case DevFmtUByte: return "Unsigned Byte"; - case DevFmtShort: return "Signed Short"; - case DevFmtUShort: return "Unsigned Short"; - case DevFmtInt: return "Signed Int"; - case DevFmtUInt: return "Unsigned Int"; - case DevFmtFloat: return "Float"; - } - return "(unknown type)"; -} -const ALCchar *DevFmtChannelsString(DevFmtChannels chans) noexcept -{ - switch(chans) - { - case DevFmtMono: return "Mono"; - case DevFmtStereo: return "Stereo"; - case DevFmtQuad: return "Quadraphonic"; - case DevFmtX51: return "5.1 Surround"; - case DevFmtX51Rear: return "5.1 Surround (Rear)"; - case DevFmtX61: return "6.1 Surround"; - case DevFmtX71: return "7.1 Surround"; - case DevFmtAmbi3D: return "Ambisonic 3D"; - } - return "(unknown channels)"; -} - -ALsizei BytesFromDevFmt(DevFmtType type) noexcept -{ - switch(type) - { - case DevFmtByte: return sizeof(ALbyte); - case DevFmtUByte: return sizeof(ALubyte); - case DevFmtShort: return sizeof(ALshort); - case DevFmtUShort: return sizeof(ALushort); - case DevFmtInt: return sizeof(ALint); - case DevFmtUInt: return sizeof(ALuint); - case DevFmtFloat: return sizeof(ALfloat); - } - return 0; -} -ALsizei ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept -{ - switch(chans) - { - case DevFmtMono: return 1; - case DevFmtStereo: return 2; - case DevFmtQuad: return 4; - case DevFmtX51: return 6; - case DevFmtX51Rear: return 6; - case DevFmtX61: return 7; - case DevFmtX71: return 8; - case DevFmtAmbi3D: return (ambiorder+1) * (ambiorder+1); - } - return 0; -} - -struct DevFmtPair { DevFmtChannels chans; DevFmtType type; }; -static al::optional DecomposeDevFormat(ALenum format) -{ - static const struct { - ALenum format; - DevFmtChannels channels; - DevFmtType type; - } list[] = { - { AL_FORMAT_MONO8, DevFmtMono, DevFmtUByte }, - { AL_FORMAT_MONO16, DevFmtMono, DevFmtShort }, - { AL_FORMAT_MONO_FLOAT32, DevFmtMono, DevFmtFloat }, - - { AL_FORMAT_STEREO8, DevFmtStereo, DevFmtUByte }, - { AL_FORMAT_STEREO16, DevFmtStereo, DevFmtShort }, - { AL_FORMAT_STEREO_FLOAT32, DevFmtStereo, DevFmtFloat }, - - { AL_FORMAT_QUAD8, DevFmtQuad, DevFmtUByte }, - { AL_FORMAT_QUAD16, DevFmtQuad, DevFmtShort }, - { AL_FORMAT_QUAD32, DevFmtQuad, DevFmtFloat }, - - { AL_FORMAT_51CHN8, DevFmtX51, DevFmtUByte }, - { AL_FORMAT_51CHN16, DevFmtX51, DevFmtShort }, - { AL_FORMAT_51CHN32, DevFmtX51, DevFmtFloat }, - - { AL_FORMAT_61CHN8, DevFmtX61, DevFmtUByte }, - { AL_FORMAT_61CHN16, DevFmtX61, DevFmtShort }, - { AL_FORMAT_61CHN32, DevFmtX61, DevFmtFloat }, - - { AL_FORMAT_71CHN8, DevFmtX71, DevFmtUByte }, - { AL_FORMAT_71CHN16, DevFmtX71, DevFmtShort }, - { AL_FORMAT_71CHN32, DevFmtX71, DevFmtFloat }, - }; - - for(const auto &item : list) - { - if(item.format == format) - return al::make_optional(DevFmtPair{item.channels, item.type}); - } - - return al::nullopt; -} - -static ALCboolean IsValidALCType(ALCenum type) -{ - switch(type) - { - case ALC_BYTE_SOFT: - case ALC_UNSIGNED_BYTE_SOFT: - case ALC_SHORT_SOFT: - case ALC_UNSIGNED_SHORT_SOFT: - case ALC_INT_SOFT: - case ALC_UNSIGNED_INT_SOFT: - case ALC_FLOAT_SOFT: - return ALC_TRUE; - } - return ALC_FALSE; -} - -static ALCboolean IsValidALCChannels(ALCenum channels) -{ - switch(channels) - { - case ALC_MONO_SOFT: - case ALC_STEREO_SOFT: - case ALC_QUAD_SOFT: - case ALC_5POINT1_SOFT: - case ALC_6POINT1_SOFT: - case ALC_7POINT1_SOFT: - case ALC_BFORMAT3D_SOFT: - return ALC_TRUE; - } - return ALC_FALSE; -} - -static ALCboolean IsValidAmbiLayout(ALCenum layout) -{ - switch(layout) - { - case ALC_ACN_SOFT: - case ALC_FUMA_SOFT: - return ALC_TRUE; - } - return ALC_FALSE; -} - -static ALCboolean IsValidAmbiScaling(ALCenum scaling) -{ - switch(scaling) - { - case ALC_N3D_SOFT: - case ALC_SN3D_SOFT: - case ALC_FUMA_SOFT: - return ALC_TRUE; - } - return ALC_FALSE; -} - -/************************************************ - * Miscellaneous ALC helpers - ************************************************/ - -/* SetDefaultWFXChannelOrder - * - * Sets the default channel order used by WaveFormatEx. - */ -void SetDefaultWFXChannelOrder(ALCdevice *device) -{ - device->RealOut.ChannelIndex.fill(-1); - - switch(device->FmtChans) - { - case DevFmtMono: - device->RealOut.ChannelIndex[FrontCenter] = 0; - break; - case DevFmtStereo: - device->RealOut.ChannelIndex[FrontLeft] = 0; - device->RealOut.ChannelIndex[FrontRight] = 1; - break; - case DevFmtQuad: - device->RealOut.ChannelIndex[FrontLeft] = 0; - device->RealOut.ChannelIndex[FrontRight] = 1; - device->RealOut.ChannelIndex[BackLeft] = 2; - device->RealOut.ChannelIndex[BackRight] = 3; - break; - case DevFmtX51: - device->RealOut.ChannelIndex[FrontLeft] = 0; - device->RealOut.ChannelIndex[FrontRight] = 1; - device->RealOut.ChannelIndex[FrontCenter] = 2; - device->RealOut.ChannelIndex[LFE] = 3; - device->RealOut.ChannelIndex[SideLeft] = 4; - device->RealOut.ChannelIndex[SideRight] = 5; - break; - case DevFmtX51Rear: - device->RealOut.ChannelIndex[FrontLeft] = 0; - device->RealOut.ChannelIndex[FrontRight] = 1; - device->RealOut.ChannelIndex[FrontCenter] = 2; - device->RealOut.ChannelIndex[LFE] = 3; - device->RealOut.ChannelIndex[BackLeft] = 4; - device->RealOut.ChannelIndex[BackRight] = 5; - break; - case DevFmtX61: - device->RealOut.ChannelIndex[FrontLeft] = 0; - device->RealOut.ChannelIndex[FrontRight] = 1; - device->RealOut.ChannelIndex[FrontCenter] = 2; - device->RealOut.ChannelIndex[LFE] = 3; - device->RealOut.ChannelIndex[BackCenter] = 4; - device->RealOut.ChannelIndex[SideLeft] = 5; - device->RealOut.ChannelIndex[SideRight] = 6; - break; - case DevFmtX71: - device->RealOut.ChannelIndex[FrontLeft] = 0; - device->RealOut.ChannelIndex[FrontRight] = 1; - device->RealOut.ChannelIndex[FrontCenter] = 2; - device->RealOut.ChannelIndex[LFE] = 3; - device->RealOut.ChannelIndex[BackLeft] = 4; - device->RealOut.ChannelIndex[BackRight] = 5; - device->RealOut.ChannelIndex[SideLeft] = 6; - device->RealOut.ChannelIndex[SideRight] = 7; - break; - case DevFmtAmbi3D: - device->RealOut.ChannelIndex[Aux0] = 0; - if(device->mAmbiOrder > 0) - { - device->RealOut.ChannelIndex[Aux1] = 1; - device->RealOut.ChannelIndex[Aux2] = 2; - device->RealOut.ChannelIndex[Aux3] = 3; - } - if(device->mAmbiOrder > 1) - { - device->RealOut.ChannelIndex[Aux4] = 4; - device->RealOut.ChannelIndex[Aux5] = 5; - device->RealOut.ChannelIndex[Aux6] = 6; - device->RealOut.ChannelIndex[Aux7] = 7; - device->RealOut.ChannelIndex[Aux8] = 8; - } - if(device->mAmbiOrder > 2) - { - device->RealOut.ChannelIndex[Aux9] = 9; - device->RealOut.ChannelIndex[Aux10] = 10; - device->RealOut.ChannelIndex[Aux11] = 11; - device->RealOut.ChannelIndex[Aux12] = 12; - device->RealOut.ChannelIndex[Aux13] = 13; - device->RealOut.ChannelIndex[Aux14] = 14; - device->RealOut.ChannelIndex[Aux15] = 15; - } - break; - } -} - -/* SetDefaultChannelOrder - * - * Sets the default channel order used by most non-WaveFormatEx-based APIs. - */ -void SetDefaultChannelOrder(ALCdevice *device) -{ - device->RealOut.ChannelIndex.fill(-1); - - switch(device->FmtChans) - { - case DevFmtX51Rear: - device->RealOut.ChannelIndex[FrontLeft] = 0; - device->RealOut.ChannelIndex[FrontRight] = 1; - device->RealOut.ChannelIndex[BackLeft] = 2; - device->RealOut.ChannelIndex[BackRight] = 3; - device->RealOut.ChannelIndex[FrontCenter] = 4; - device->RealOut.ChannelIndex[LFE] = 5; - return; - case DevFmtX71: - device->RealOut.ChannelIndex[FrontLeft] = 0; - device->RealOut.ChannelIndex[FrontRight] = 1; - device->RealOut.ChannelIndex[BackLeft] = 2; - device->RealOut.ChannelIndex[BackRight] = 3; - device->RealOut.ChannelIndex[FrontCenter] = 4; - device->RealOut.ChannelIndex[LFE] = 5; - device->RealOut.ChannelIndex[SideLeft] = 6; - device->RealOut.ChannelIndex[SideRight] = 7; - return; - - /* Same as WFX order */ - case DevFmtMono: - case DevFmtStereo: - case DevFmtQuad: - case DevFmtX51: - case DevFmtX61: - case DevFmtAmbi3D: - SetDefaultWFXChannelOrder(device); - break; - } -} - - -/* ALCcontext_DeferUpdates - * - * Defers/suspends updates for the given context's listener and sources. This - * does *NOT* stop mixing, but rather prevents certain property changes from - * taking effect. - */ -void ALCcontext_DeferUpdates(ALCcontext *context) -{ - context->DeferUpdates.store(true); -} - -/* ALCcontext_ProcessUpdates - * - * Resumes update processing after being deferred. - */ -void ALCcontext_ProcessUpdates(ALCcontext *context) -{ - std::lock_guard _{context->PropLock}; - if(context->DeferUpdates.exchange(false)) - { - /* Tell the mixer to stop applying updates, then wait for any active - * updating to finish, before providing updates. - */ - context->HoldUpdates.store(true, std::memory_order_release); - while((context->UpdateCount.load(std::memory_order_acquire)&1) != 0) - std::this_thread::yield(); - - if(!context->PropsClean.test_and_set(std::memory_order_acq_rel)) - UpdateContextProps(context); - if(!context->Listener.PropsClean.test_and_set(std::memory_order_acq_rel)) - UpdateListenerProps(context); - UpdateAllEffectSlotProps(context); - UpdateAllSourceProps(context); - - /* Now with all updates declared, let the mixer continue applying them - * so they all happen at once. - */ - context->HoldUpdates.store(false, std::memory_order_release); - } -} - - -/* alcSetError - * - * Stores the latest ALC device error - */ -static void alcSetError(ALCdevice *device, ALCenum errorCode) -{ - WARN("Error generated on device %p, code 0x%04x\n", device, errorCode); - if(TrapALCError) - { -#ifdef _WIN32 - /* DebugBreak() will cause an exception if there is no debugger */ - if(IsDebuggerPresent()) - DebugBreak(); -#elif defined(SIGTRAP) - raise(SIGTRAP); -#endif - } - - if(device) - device->LastError.store(errorCode); - else - LastNullDeviceError.store(errorCode); -} - - -static std::unique_ptr CreateDeviceLimiter(const ALCdevice *device, const ALfloat threshold) -{ - return CompressorInit(static_cast(device->RealOut.Buffer.size()), device->Frequency, - AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, 0.001f, 0.002f, 0.0f, 0.0f, threshold, - INFINITY, 0.0f, 0.020f, 0.200f); -} - -/* UpdateClockBase - * - * Updates the device's base clock time with however many samples have been - * done. This is used so frequency changes on the device don't cause the time - * to jump forward or back. Must not be called while the device is running/ - * mixing. - */ -static inline void UpdateClockBase(ALCdevice *device) -{ - IncrementRef(&device->MixCount); - device->ClockBase += nanoseconds{seconds{device->SamplesDone}} / device->Frequency; - device->SamplesDone = 0; - IncrementRef(&device->MixCount); -} - -/* UpdateDeviceParams - * - * Updates device parameters according to the attribute list (caller is - * responsible for holding the list lock). - */ -static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) -{ - HrtfRequestMode hrtf_userreq = Hrtf_Default; - HrtfRequestMode hrtf_appreq = Hrtf_Default; - ALCenum gainLimiter = device->LimiterState; - const ALsizei old_sends = device->NumAuxSends; - ALsizei new_sends = device->NumAuxSends; - DevFmtChannels oldChans; - DevFmtType oldType; - ALboolean update_failed; - ALCsizei hrtf_id = -1; - ALCuint oldFreq; - - if((!attrList || !attrList[0]) && device->Type == Loopback) - { - WARN("Missing attributes for loopback device\n"); - return ALC_INVALID_VALUE; - } - - // Check for attributes - if(attrList && attrList[0]) - { - ALCenum alayout{AL_NONE}; - ALCenum ascale{AL_NONE}; - ALCenum schans{AL_NONE}; - ALCenum stype{AL_NONE}; - ALCsizei attrIdx{0}; - ALCsizei aorder{0}; - ALCuint freq{0u}; - - ALuint numMono{device->NumMonoSources}; - ALuint numStereo{device->NumStereoSources}; - ALsizei numSends{old_sends}; - -#define TRACE_ATTR(a, v) TRACE("%s = %d\n", #a, v) - while(attrList[attrIdx]) - { - switch(attrList[attrIdx]) - { - case ALC_FORMAT_CHANNELS_SOFT: - schans = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_FORMAT_CHANNELS_SOFT, schans); - break; - - case ALC_FORMAT_TYPE_SOFT: - stype = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_FORMAT_TYPE_SOFT, stype); - break; - - case ALC_FREQUENCY: - freq = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_FREQUENCY, freq); - break; - - case ALC_AMBISONIC_LAYOUT_SOFT: - alayout = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_AMBISONIC_LAYOUT_SOFT, alayout); - break; - - case ALC_AMBISONIC_SCALING_SOFT: - ascale = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_AMBISONIC_SCALING_SOFT, ascale); - break; - - case ALC_AMBISONIC_ORDER_SOFT: - aorder = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_AMBISONIC_ORDER_SOFT, aorder); - break; - - case ALC_MONO_SOURCES: - numMono = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_MONO_SOURCES, numMono); - if(numMono > INT_MAX) numMono = 0; - break; - - case ALC_STEREO_SOURCES: - numStereo = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); - if(numStereo > INT_MAX) numStereo = 0; - break; - - case ALC_MAX_AUXILIARY_SENDS: - numSends = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_MAX_AUXILIARY_SENDS, numSends); - numSends = clampi(numSends, 0, MAX_SENDS); - break; - - case ALC_HRTF_SOFT: - TRACE_ATTR(ALC_HRTF_SOFT, attrList[attrIdx + 1]); - if(attrList[attrIdx + 1] == ALC_FALSE) - hrtf_appreq = Hrtf_Disable; - else if(attrList[attrIdx + 1] == ALC_TRUE) - hrtf_appreq = Hrtf_Enable; - else - hrtf_appreq = Hrtf_Default; - break; - - case ALC_HRTF_ID_SOFT: - hrtf_id = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_HRTF_ID_SOFT, hrtf_id); - break; - - case ALC_OUTPUT_LIMITER_SOFT: - gainLimiter = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_OUTPUT_LIMITER_SOFT, gainLimiter); - break; - - default: - TRACE("0x%04X = %d (0x%x)\n", attrList[attrIdx], - attrList[attrIdx + 1], attrList[attrIdx + 1]); - break; - } - - attrIdx += 2; - } -#undef TRACE_ATTR - - const bool loopback{device->Type == Loopback}; - if(loopback) - { - if(!schans || !stype || !freq) - { - WARN("Missing format for loopback device\n"); - return ALC_INVALID_VALUE; - } - if(!IsValidALCChannels(schans) || !IsValidALCType(stype) || freq < MIN_OUTPUT_RATE) - return ALC_INVALID_VALUE; - if(schans == ALC_BFORMAT3D_SOFT) - { - if(!alayout || !ascale || !aorder) - { - WARN("Missing ambisonic info for loopback device\n"); - return ALC_INVALID_VALUE; - } - if(!IsValidAmbiLayout(alayout) || !IsValidAmbiScaling(ascale)) - return ALC_INVALID_VALUE; - if(aorder < 1 || aorder > MAX_AMBI_ORDER) - return ALC_INVALID_VALUE; - if((alayout == ALC_FUMA_SOFT || ascale == ALC_FUMA_SOFT) && aorder > 3) - return ALC_INVALID_VALUE; - } - } - - /* If a context is already running on the device, stop playback so the - * device attributes can be updated. - */ - if(device->Flags.get()) - device->Backend->stop(); - device->Flags.unset(); - - UpdateClockBase(device); - - const char *devname{nullptr}; - if(!loopback) - { - devname = device->DeviceName.c_str(); - - device->BufferSize = DEFAULT_UPDATE_SIZE * DEFAULT_NUM_UPDATES; - device->UpdateSize = DEFAULT_UPDATE_SIZE; - device->Frequency = DEFAULT_OUTPUT_RATE; - - freq = ConfigValueUInt(devname, nullptr, "frequency").value_or(freq); - if(freq < 1) - device->Flags.unset(); - else - { - freq = maxi(freq, MIN_OUTPUT_RATE); - - device->UpdateSize = (device->UpdateSize*freq + device->Frequency/2) / - device->Frequency; - device->BufferSize = (device->BufferSize*freq + device->Frequency/2) / - device->Frequency; - - device->Frequency = freq; - device->Flags.set(); - } - - if(auto persizeopt = ConfigValueUInt(devname, nullptr, "period_size")) - device->UpdateSize = clampu(*persizeopt, 64, 8192); - - if(auto peropt = ConfigValueUInt(devname, nullptr, "periods")) - device->BufferSize = device->UpdateSize * clampu(*peropt, 2, 16); - else - device->BufferSize = maxu(device->BufferSize, device->UpdateSize*2); - } - else - { - device->Frequency = freq; - device->FmtChans = static_cast(schans); - device->FmtType = static_cast(stype); - if(schans == ALC_BFORMAT3D_SOFT) - { - device->mAmbiOrder = aorder; - device->mAmbiLayout = static_cast(alayout); - device->mAmbiScale = static_cast(ascale); - } - } - - if(numMono > INT_MAX-numStereo) - numMono = INT_MAX-numStereo; - numMono += numStereo; - if(auto srcsopt = ConfigValueUInt(devname, nullptr, "sources")) - { - if(*srcsopt <= 0) numMono = 256; - else numMono = *srcsopt; - } - else - numMono = maxu(numMono, 256); - numStereo = minu(numStereo, numMono); - numMono -= numStereo; - device->SourcesMax = numMono + numStereo; - - device->NumMonoSources = numMono; - device->NumStereoSources = numStereo; - - if(auto sendsopt = ConfigValueInt(devname, nullptr, "sends")) - new_sends = mini(numSends, clampi(*sendsopt, 0, MAX_SENDS)); - else - new_sends = numSends; - } - - if(device->Flags.get()) - return ALC_NO_ERROR; - - device->AvgSpeakerDist = 0.0f; - device->Uhj_Encoder = nullptr; - device->AmbiDecoder = nullptr; - device->Bs2b = nullptr; - device->PostProcess = nullptr; - - device->Stablizer = nullptr; - device->Limiter = nullptr; - device->ChannelDelay.clear(); - - device->Dry.AmbiMap.fill(BFChannelConfig{}); - device->Dry.Buffer = {}; - std::fill(std::begin(device->NumChannelsPerOrder), std::end(device->NumChannelsPerOrder), 0u); - device->RealOut.ChannelIndex.fill(-1); - device->RealOut.Buffer = {}; - device->MixBuffer.clear(); - device->MixBuffer.shrink_to_fit(); - - UpdateClockBase(device); - device->FixedLatency = nanoseconds::zero(); - - device->DitherDepth = 0.0f; - device->DitherSeed = DITHER_RNG_SEED; - - /************************************************************************* - * Update device format request if HRTF is requested - */ - device->HrtfStatus = ALC_HRTF_DISABLED_SOFT; - if(device->Type != Loopback) - { - if(auto hrtfopt = ConfigValueStr(device->DeviceName.c_str(), nullptr, "hrtf")) - { - const char *hrtf{hrtfopt->c_str()}; - if(strcasecmp(hrtf, "true") == 0) - hrtf_userreq = Hrtf_Enable; - else if(strcasecmp(hrtf, "false") == 0) - hrtf_userreq = Hrtf_Disable; - else if(strcasecmp(hrtf, "auto") != 0) - ERR("Unexpected hrtf value: %s\n", hrtf); - } - - if(hrtf_userreq == Hrtf_Enable || (hrtf_userreq != Hrtf_Disable && hrtf_appreq == Hrtf_Enable)) - { - HrtfEntry *hrtf{nullptr}; - if(device->HrtfList.empty()) - device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); - if(!device->HrtfList.empty()) - { - if(hrtf_id >= 0 && static_cast(hrtf_id) < device->HrtfList.size()) - hrtf = GetLoadedHrtf(device->HrtfList[hrtf_id].hrtf); - else - hrtf = GetLoadedHrtf(device->HrtfList.front().hrtf); - } - - if(hrtf) - { - device->FmtChans = DevFmtStereo; - device->Frequency = hrtf->sampleRate; - device->Flags.set(); - if(HrtfEntry *oldhrtf{device->mHrtf}) - oldhrtf->DecRef(); - device->mHrtf = hrtf; - } - else - { - hrtf_userreq = Hrtf_Default; - hrtf_appreq = Hrtf_Disable; - device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; - } - } - } - - oldFreq = device->Frequency; - oldChans = device->FmtChans; - oldType = device->FmtType; - - TRACE("Pre-reset: %s%s, %s%s, %s%uhz, %u / %u buffer\n", - device->Flags.get()?"*":"", DevFmtChannelsString(device->FmtChans), - device->Flags.get()?"*":"", DevFmtTypeString(device->FmtType), - device->Flags.get()?"*":"", device->Frequency, - device->UpdateSize, device->BufferSize); - - try { - if(device->Backend->reset() == ALC_FALSE) - return ALC_INVALID_DEVICE; - } - catch(std::exception &e) { - ERR("Device reset failed: %s\n", e.what()); - return ALC_INVALID_DEVICE; - } - - if(device->FmtChans != oldChans && device->Flags.get()) - { - ERR("Failed to set %s, got %s instead\n", DevFmtChannelsString(oldChans), - DevFmtChannelsString(device->FmtChans)); - device->Flags.unset(); - } - if(device->FmtType != oldType && device->Flags.get()) - { - ERR("Failed to set %s, got %s instead\n", DevFmtTypeString(oldType), - DevFmtTypeString(device->FmtType)); - device->Flags.unset(); - } - if(device->Frequency != oldFreq && device->Flags.get()) - { - WARN("Failed to set %uhz, got %uhz instead\n", oldFreq, device->Frequency); - device->Flags.unset(); - } - - TRACE("Post-reset: %s, %s, %uhz, %u / %u buffer\n", - DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), - device->Frequency, device->UpdateSize, device->BufferSize); - - aluInitRenderer(device, hrtf_id, hrtf_appreq, hrtf_userreq); - - device->NumAuxSends = new_sends; - TRACE("Max sources: %d (%d + %d), effect slots: %d, sends: %d\n", - device->SourcesMax, device->NumMonoSources, device->NumStereoSources, - device->AuxiliaryEffectSlotMax, device->NumAuxSends); - - /* Enable the stablizer only for formats that have front-left, front-right, - * and front-center outputs. - */ - switch(device->FmtChans) - { - case DevFmtX51: - case DevFmtX51Rear: - case DevFmtX61: - case DevFmtX71: - if(GetConfigValueBool(device->DeviceName.c_str(), nullptr, "front-stablizer", 0)) - { - auto stablizer = al::make_unique(); - /* Initialize band-splitting filters for the front-left and front- - * right channels, with a crossover at 5khz (could be higher). - */ - const ALfloat scale{5000.0f / static_cast(device->Frequency)}; - - stablizer->LFilter.init(scale); - stablizer->RFilter = stablizer->LFilter; - - device->Stablizer = std::move(stablizer); - /* NOTE: Don't know why this has to be "copied" into a local static - * constexpr variable to avoid a reference on - * FrontStablizer::DelayLength... - */ - static constexpr size_t StablizerDelay{FrontStablizer::DelayLength}; - device->FixedLatency += nanoseconds{seconds{StablizerDelay}} / device->Frequency; - } - break; - case DevFmtMono: - case DevFmtStereo: - case DevFmtQuad: - case DevFmtAmbi3D: - break; - } - TRACE("Front stablizer %s\n", device->Stablizer ? "enabled" : "disabled"); - - if(GetConfigValueBool(device->DeviceName.c_str(), nullptr, "dither", 1)) - { - ALint depth{ - ConfigValueInt(device->DeviceName.c_str(), nullptr, "dither-depth").value_or(0)}; - if(depth <= 0) - { - switch(device->FmtType) - { - case DevFmtByte: - case DevFmtUByte: - depth = 8; - break; - case DevFmtShort: - case DevFmtUShort: - depth = 16; - break; - case DevFmtInt: - case DevFmtUInt: - case DevFmtFloat: - break; - } - } - - if(depth > 0) - { - depth = clampi(depth, 2, 24); - device->DitherDepth = std::pow(2.0f, static_cast(depth-1)); - } - } - if(!(device->DitherDepth > 0.0f)) - TRACE("Dithering disabled\n"); - else - TRACE("Dithering enabled (%d-bit, %g)\n", float2int(std::log2(device->DitherDepth)+0.5f)+1, - device->DitherDepth); - - device->LimiterState = gainLimiter; - if(auto limopt = ConfigValueBool(device->DeviceName.c_str(), nullptr, "output-limiter")) - gainLimiter = *limopt ? ALC_TRUE : ALC_FALSE; - - /* Valid values for gainLimiter are ALC_DONT_CARE_SOFT, ALC_TRUE, and - * ALC_FALSE. For ALC_DONT_CARE_SOFT, use the limiter for integer-based - * output (where samples must be clamped), and don't for floating-point - * (which can take unclamped samples). - */ - if(gainLimiter == ALC_DONT_CARE_SOFT) - { - switch(device->FmtType) - { - case DevFmtByte: - case DevFmtUByte: - case DevFmtShort: - case DevFmtUShort: - case DevFmtInt: - case DevFmtUInt: - gainLimiter = ALC_TRUE; - break; - case DevFmtFloat: - gainLimiter = ALC_FALSE; - break; - } - } - if(gainLimiter == ALC_FALSE) - TRACE("Output limiter disabled\n"); - else - { - ALfloat thrshld = 1.0f; - switch(device->FmtType) - { - case DevFmtByte: - case DevFmtUByte: - thrshld = 127.0f / 128.0f; - break; - case DevFmtShort: - case DevFmtUShort: - thrshld = 32767.0f / 32768.0f; - break; - case DevFmtInt: - case DevFmtUInt: - case DevFmtFloat: - break; - } - if(device->DitherDepth > 0.0f) - thrshld -= 1.0f / device->DitherDepth; - - const float thrshld_dB{std::log10(thrshld) * 20.0f}; - auto limiter = CreateDeviceLimiter(device, thrshld_dB); - /* Convert the lookahead from samples to nanosamples to nanoseconds. */ - device->FixedLatency += nanoseconds{seconds{limiter->getLookAhead()}} / device->Frequency; - device->Limiter = std::move(limiter); - TRACE("Output limiter enabled, %.4fdB limit\n", thrshld_dB); - } - - TRACE("Fixed device latency: %ldns\n", (long)device->FixedLatency.count()); - - /* Need to delay returning failure until replacement Send arrays have been - * allocated with the appropriate size. - */ - update_failed = AL_FALSE; - FPUCtl mixer_mode{}; - for(ALCcontext *context : *device->mContexts.load()) - { - if(context->DefaultSlot) - { - ALeffectslot *slot = context->DefaultSlot.get(); - aluInitEffectPanning(slot, device); - - EffectState *state{slot->Effect.State}; - state->mOutTarget = device->Dry.Buffer; - if(state->deviceUpdate(device) == AL_FALSE) - update_failed = AL_TRUE; - else - UpdateEffectSlotProps(slot, context); - } - - std::unique_lock proplock{context->PropLock}; - std::unique_lock slotlock{context->EffectSlotLock}; - for(auto &sublist : context->EffectSlotList) - { - uint64_t usemask = ~sublist.FreeMask; - while(usemask) - { - ALsizei idx = CTZ64(usemask); - ALeffectslot *slot = sublist.EffectSlots + idx; - - usemask &= ~(1_u64 << idx); - - aluInitEffectPanning(slot, device); - - EffectState *state{slot->Effect.State}; - state->mOutTarget = device->Dry.Buffer; - if(state->deviceUpdate(device) == AL_FALSE) - update_failed = AL_TRUE; - else - UpdateEffectSlotProps(slot, context); - } - } - slotlock.unlock(); - - std::unique_lock srclock{context->SourceLock}; - for(auto &sublist : context->SourceList) - { - uint64_t usemask = ~sublist.FreeMask; - while(usemask) - { - ALsizei idx = CTZ64(usemask); - ALsource *source = sublist.Sources + idx; - - usemask &= ~(1_u64 << idx); - - if(old_sends != device->NumAuxSends) - { - ALsizei s; - for(s = device->NumAuxSends;s < old_sends;s++) - { - if(source->Send[s].Slot) - DecrementRef(&source->Send[s].Slot->ref); - source->Send[s].Slot = nullptr; - } - source->Send.resize(device->NumAuxSends); - source->Send.shrink_to_fit(); - for(s = old_sends;s < device->NumAuxSends;s++) - { - source->Send[s].Slot = nullptr; - source->Send[s].Gain = 1.0f; - source->Send[s].GainHF = 1.0f; - source->Send[s].HFReference = LOWPASSFREQREF; - source->Send[s].GainLF = 1.0f; - source->Send[s].LFReference = HIGHPASSFREQREF; - } - } - - source->PropsClean.clear(std::memory_order_release); - } - } - - /* Clear any pre-existing voice property structs, in case the number of - * auxiliary sends is changing. Active sources will have updates - * respecified in UpdateAllSourceProps. - */ - ALvoiceProps *vprops{context->FreeVoiceProps.exchange(nullptr, std::memory_order_acq_rel)}; - while(vprops) - { - ALvoiceProps *next = vprops->next.load(std::memory_order_relaxed); - delete vprops; - vprops = next; - } - - auto voices = context->Voices.get(); - auto voices_end = voices->begin() + context->VoiceCount.load(std::memory_order_relaxed); - if(device->NumAuxSends < old_sends) - { - const ALsizei num_sends{device->NumAuxSends}; - /* Clear extraneous property set sends. */ - auto clear_sends = [num_sends](ALvoice &voice) -> void - { - std::fill(std::begin(voice.mProps.Send)+num_sends, std::end(voice.mProps.Send), - ALvoiceProps::SendData{}); - - std::fill(voice.mSend.begin()+num_sends, voice.mSend.end(), ALvoice::SendData{}); - auto clear_chan_sends = [num_sends](ALvoice::ChannelData &chandata) -> void - { - std::fill(chandata.mWetParams.begin()+num_sends, chandata.mWetParams.end(), - SendParams{}); - }; - std::for_each(voice.mChans.begin(), voice.mChans.end(), clear_chan_sends); - }; - std::for_each(voices->begin(), voices_end, clear_sends); - } - std::for_each(voices->begin(), voices_end, - [device](ALvoice &voice) -> void - { - delete voice.mUpdate.exchange(nullptr, std::memory_order_acq_rel); - - /* Force the voice to stopped if it was stopping. */ - ALvoice::State vstate{ALvoice::Stopping}; - voice.mPlayState.compare_exchange_strong(vstate, ALvoice::Stopped, - std::memory_order_acquire, std::memory_order_acquire); - if(voice.mSourceID.load(std::memory_order_relaxed) == 0u) - return; - - if(device->AvgSpeakerDist > 0.0f) - { - /* Reinitialize the NFC filters for new parameters. */ - const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC / - (device->AvgSpeakerDist * device->Frequency)}; - auto init_nfc = [w1](ALvoice::ChannelData &chandata) -> void - { chandata.mDryParams.NFCtrlFilter.init(w1); }; - std::for_each(voice.mChans.begin(), voice.mChans.begin()+voice.mNumChannels, - init_nfc); - } - } - ); - srclock.unlock(); - - context->PropsClean.test_and_set(std::memory_order_release); - UpdateContextProps(context); - context->Listener.PropsClean.test_and_set(std::memory_order_release); - UpdateListenerProps(context); - UpdateAllSourceProps(context); - } - mixer_mode.leave(); - if(update_failed) - return ALC_INVALID_DEVICE; - - if(!device->Flags.get()) - { - if(device->Backend->start() == ALC_FALSE) - return ALC_INVALID_DEVICE; - device->Flags.set(); - } - - return ALC_NO_ERROR; -} - - -ALCdevice::ALCdevice(DeviceType type) : Type{type}, mContexts{&EmptyContextArray} -{ -} - -/* ALCdevice::~ALCdevice - * - * Frees the device structure, and destroys any objects the app failed to - * delete. Called once there's no more references on the device. - */ -ALCdevice::~ALCdevice() -{ - TRACE("Freeing device %p\n", this); - - Backend = nullptr; - - size_t count{std::accumulate(BufferList.cbegin(), BufferList.cend(), size_t{0u}, - [](size_t cur, const BufferSubList &sublist) noexcept -> size_t - { return cur + POPCNT64(~sublist.FreeMask); } - )}; - if(count > 0) - WARN("%zu Buffer%s not deleted\n", count, (count==1)?"":"s"); - - count = std::accumulate(EffectList.cbegin(), EffectList.cend(), size_t{0u}, - [](size_t cur, const EffectSubList &sublist) noexcept -> size_t - { return cur + POPCNT64(~sublist.FreeMask); } - ); - if(count > 0) - WARN("%zu Effect%s not deleted\n", count, (count==1)?"":"s"); - - count = std::accumulate(FilterList.cbegin(), FilterList.cend(), size_t{0u}, - [](size_t cur, const FilterSubList &sublist) noexcept -> size_t - { return cur + POPCNT64(~sublist.FreeMask); } - ); - if(count > 0) - WARN("%zu Filter%s not deleted\n", count, (count==1)?"":"s"); - - if(mHrtf) - mHrtf->DecRef(); - mHrtf = nullptr; - - auto *oldarray = mContexts.exchange(nullptr, std::memory_order_relaxed); - if(oldarray != &EmptyContextArray) delete oldarray; -} - - -/* VerifyDevice - * - * Checks if the device handle is valid, and returns a new reference if so. - */ -static DeviceRef VerifyDevice(ALCdevice *device) -{ - std::lock_guard _{ListLock}; - auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device); - if(iter != DeviceList.cend() && *iter == device) - { - ALCdevice_IncRef(iter->get()); - return DeviceRef{iter->get()}; - } - return DeviceRef{}; -} - - -ALCcontext::ALCcontext(ALCdevice *device) : Device{device} -{ - PropsClean.test_and_set(std::memory_order_relaxed); -} - -/* InitContext - * - * Initializes context fields - */ -static ALvoid InitContext(ALCcontext *Context) -{ - ALlistener &listener = Context->Listener; - ALeffectslotArray *auxslots; - - //Validate Context - if(!Context->DefaultSlot) - auxslots = ALeffectslot::CreatePtrArray(0); - else - { - auxslots = ALeffectslot::CreatePtrArray(1); - (*auxslots)[0] = Context->DefaultSlot.get(); - } - Context->ActiveAuxSlots.store(auxslots, std::memory_order_relaxed); - - //Set globals - Context->mDistanceModel = DistanceModel::Default; - Context->SourceDistanceModel = AL_FALSE; - Context->DopplerFactor = 1.0f; - Context->DopplerVelocity = 1.0f; - Context->SpeedOfSound = SPEEDOFSOUNDMETRESPERSEC; - Context->MetersPerUnit = AL_DEFAULT_METERS_PER_UNIT; - - Context->ExtensionList = alExtList; - - - listener.Params.Matrix = alu::Matrix::Identity(); - listener.Params.Velocity = alu::Vector{}; - listener.Params.Gain = listener.Gain; - listener.Params.MetersPerUnit = Context->MetersPerUnit; - listener.Params.DopplerFactor = Context->DopplerFactor; - listener.Params.SpeedOfSound = Context->SpeedOfSound * Context->DopplerVelocity; - listener.Params.ReverbSpeedOfSound = listener.Params.SpeedOfSound * - listener.Params.MetersPerUnit; - listener.Params.SourceDistanceModel = Context->SourceDistanceModel; - listener.Params.mDistanceModel = Context->mDistanceModel; - - - Context->AsyncEvents = CreateRingBuffer(511, sizeof(AsyncEvent), false); - StartEventThrd(Context); -} - - -/* ALCcontext::~ALCcontext() - * - * Cleans up the context, and destroys any remaining objects the app failed to - * delete. Called once there's no more references on the context. - */ -ALCcontext::~ALCcontext() -{ - TRACE("Freeing context %p\n", this); - - ALcontextProps *cprops{Update.exchange(nullptr, std::memory_order_relaxed)}; - if(cprops) - { - TRACE("Freed unapplied context update %p\n", cprops); - al_free(cprops); - } - size_t count{0}; - cprops = FreeContextProps.exchange(nullptr, std::memory_order_acquire); - while(cprops) - { - ALcontextProps *next{cprops->next.load(std::memory_order_relaxed)}; - al_free(cprops); - cprops = next; - ++count; - } - TRACE("Freed %zu context property object%s\n", count, (count==1)?"":"s"); - - count = std::accumulate(SourceList.cbegin(), SourceList.cend(), size_t{0u}, - [](size_t cur, const SourceSubList &sublist) noexcept -> size_t - { return cur + POPCNT64(~sublist.FreeMask); } - ); - if(count > 0) - WARN("%zu Source%s not deleted\n", count, (count==1)?"":"s"); - SourceList.clear(); - NumSources = 0; - - count = 0; - ALeffectslotProps *eprops{FreeEffectslotProps.exchange(nullptr, std::memory_order_acquire)}; - while(eprops) - { - ALeffectslotProps *next{eprops->next.load(std::memory_order_relaxed)}; - if(eprops->State) eprops->State->DecRef(); - al_free(eprops); - eprops = next; - ++count; - } - TRACE("Freed %zu AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s"); - - delete ActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed); - DefaultSlot = nullptr; - - count = std::accumulate(EffectSlotList.cbegin(), EffectSlotList.cend(), size_t{0u}, - [](size_t cur, const EffectSlotSubList &sublist) noexcept -> size_t - { return cur + POPCNT64(~sublist.FreeMask); } - ); - if(count > 0) - WARN("%zu AuxiliaryEffectSlot%s not deleted\n", count, (count==1)?"":"s"); - EffectSlotList.clear(); - NumEffectSlots = 0; - - count = 0; - ALvoiceProps *vprops{FreeVoiceProps.exchange(nullptr, std::memory_order_acquire)}; - while(vprops) - { - ALvoiceProps *next{vprops->next.load(std::memory_order_relaxed)}; - delete vprops; - vprops = next; - ++count; - } - TRACE("Freed %zu voice property object%s\n", count, (count==1)?"":"s"); - - Voices = nullptr; - VoiceCount.store(0, std::memory_order_relaxed); - - ALlistenerProps *lprops{Listener.Update.exchange(nullptr, std::memory_order_relaxed)}; - if(lprops) - { - TRACE("Freed unapplied listener update %p\n", lprops); - al_free(lprops); - } - count = 0; - lprops = FreeListenerProps.exchange(nullptr, std::memory_order_acquire); - while(lprops) - { - ALlistenerProps *next{lprops->next.load(std::memory_order_relaxed)}; - al_free(lprops); - lprops = next; - ++count; - } - TRACE("Freed %zu listener property object%s\n", count, (count==1)?"":"s"); - - if(AsyncEvents) - { - count = 0; - auto evt_vec = AsyncEvents->getReadVector(); - if(evt_vec.first.len > 0) - { - al::destroy_n(reinterpret_cast(evt_vec.first.buf), evt_vec.first.len); - count += evt_vec.first.len; - } - if(evt_vec.second.len > 0) - { - al::destroy_n(reinterpret_cast(evt_vec.second.buf), evt_vec.second.len); - count += evt_vec.second.len; - } - if(count > 0) - TRACE("Destructed %zu orphaned event%s\n", count, (count==1)?"":"s"); - AsyncEvents->readAdvance(count); - } - - ALCdevice_DecRef(Device); -} - -/* ReleaseContext - * - * Removes the context reference from the given device and removes it from - * being current on the running thread or globally. Returns true if other - * contexts still exist on the device. - */ -static bool ReleaseContext(ALCcontext *context, ALCdevice *device) -{ - if(LocalContext.get() == context) - { - WARN("%p released while current on thread\n", context); - LocalContext.set(nullptr); - ALCcontext_DecRef(context); - } - - ALCcontext *origctx{context}; - if(GlobalContext.compare_exchange_strong(origctx, nullptr)) - ALCcontext_DecRef(context); - - bool ret{}; - { - using ContextArray = al::FlexArray; - - /* First make sure this context exists in the device's list. */ - auto *oldarray = device->mContexts.load(std::memory_order_acquire); - if(auto toremove = std::count(oldarray->begin(), oldarray->end(), context)) - { - auto alloc_ctx_array = [](const size_t count) -> ContextArray* - { - if(count == 0) return &EmptyContextArray; - void *ptr{al_calloc(alignof(ContextArray), ContextArray::Sizeof(count))}; - return new (ptr) ContextArray{count}; - }; - auto *newarray = alloc_ctx_array(oldarray->size() - toremove); - - /* Copy the current/old context handles to the new array, excluding - * the given context. - */ - std::copy_if(oldarray->begin(), oldarray->end(), newarray->begin(), - std::bind(std::not_equal_to{}, _1, context)); - - /* Store the new context array in the device. Wait for any current - * mix to finish before deleting the old array. - */ - device->mContexts.store(newarray); - if(oldarray != &EmptyContextArray) - { - while((device->MixCount.load(std::memory_order_acquire)&1)) - std::this_thread::yield(); - delete oldarray; - } - - ret = !newarray->empty(); - } - else - ret = !oldarray->empty(); - } - - StopEventThrd(context); - - return ret; -} - -static void ALCcontext_IncRef(ALCcontext *context) -{ - auto ref = IncrementRef(&context->ref); - TRACEREF("ALCcontext %p increasing refcount to %u\n", context, ref); -} - -void ALCcontext_DecRef(ALCcontext *context) -{ - auto ref = DecrementRef(&context->ref); - TRACEREF("ALCcontext %p decreasing refcount to %u\n", context, ref); - if(UNLIKELY(ref == 0)) delete context; -} - -/* VerifyContext - * - * Checks if the given context is valid, returning a new reference to it if so. - */ -static ContextRef VerifyContext(ALCcontext *context) -{ - std::lock_guard _{ListLock}; - auto iter = std::lower_bound(ContextList.cbegin(), ContextList.cend(), context); - if(iter != ContextList.cend() && *iter == context) - { - ALCcontext_IncRef(iter->get()); - return ContextRef{iter->get()}; - } - return ContextRef{}; -} - - -/* GetContextRef - * - * Returns a new reference to the currently active context for this thread. - */ -ContextRef GetContextRef(void) -{ - ALCcontext *context{LocalContext.get()}; - if(context) - ALCcontext_IncRef(context); - else - { - std::lock_guard _{ListLock}; - context = GlobalContext.load(std::memory_order_acquire); - if(context) ALCcontext_IncRef(context); - } - return ContextRef{context}; -} - - -void AllocateVoices(ALCcontext *context, size_t num_voices) -{ - ALCdevice *device{context->Device}; - const ALsizei num_sends{device->NumAuxSends}; - - if(context->Voices && num_voices == context->Voices->size()) - return; - - std::unique_ptr> voices; - { - void *ptr{al_calloc(16, al::FlexArray::Sizeof(num_voices))}; - voices.reset(new (ptr) al::FlexArray{num_voices}); - } - - const size_t v_count{minz(context->VoiceCount.load(std::memory_order_relaxed), num_voices)}; - if(context->Voices) - { - /* Copy the old voice data to the new storage. */ - auto viter = std::move(context->Voices->begin(), context->Voices->begin()+v_count, - voices->begin()); - - /* Clear extraneous property set sends. */ - auto clear_sends = [num_sends](ALvoice &voice) -> void - { - std::fill(std::begin(voice.mProps.Send)+num_sends, std::end(voice.mProps.Send), - ALvoiceProps::SendData{}); - - std::fill(voice.mSend.begin()+num_sends, voice.mSend.end(), ALvoice::SendData{}); - auto clear_chan_sends = [num_sends](ALvoice::ChannelData &chandata) -> void - { - std::fill(chandata.mWetParams.begin()+num_sends, chandata.mWetParams.end(), - SendParams{}); - }; - std::for_each(voice.mChans.begin(), voice.mChans.end(), clear_chan_sends); - }; - std::for_each(voices->begin(), viter, clear_sends); - } - - context->Voices = std::move(voices); - context->VoiceCount.store(static_cast(v_count), std::memory_order_relaxed); -} - - -/************************************************ - * Standard ALC functions - ************************************************/ - -/* alcGetError - * - * Return last ALC generated error code for the given device - */ -ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) -START_API_FUNC -{ - DeviceRef dev{VerifyDevice(device)}; - if(dev) return dev->LastError.exchange(ALC_NO_ERROR); - return LastNullDeviceError.exchange(ALC_NO_ERROR); -} -END_API_FUNC - - -/* alcSuspendContext - * - * Suspends updates for the given context - */ -ALC_API ALCvoid ALC_APIENTRY alcSuspendContext(ALCcontext *context) -START_API_FUNC -{ - if(!SuspendDefers) - return; - - ContextRef ctx{VerifyContext(context)}; - if(!ctx) - alcSetError(nullptr, ALC_INVALID_CONTEXT); - else - ALCcontext_DeferUpdates(ctx.get()); -} -END_API_FUNC - -/* alcProcessContext - * - * Resumes processing updates for the given context - */ -ALC_API ALCvoid ALC_APIENTRY alcProcessContext(ALCcontext *context) -START_API_FUNC -{ - if(!SuspendDefers) - return; - - ContextRef ctx{VerifyContext(context)}; - if(!ctx) - alcSetError(nullptr, ALC_INVALID_CONTEXT); - else - ALCcontext_ProcessUpdates(ctx.get()); -} -END_API_FUNC - - -/* alcGetString - * - * Returns information about the device, and error strings - */ -ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum param) -START_API_FUNC -{ - const ALCchar *value = nullptr; - - switch(param) - { - case ALC_NO_ERROR: - value = alcNoError; - break; - - case ALC_INVALID_ENUM: - value = alcErrInvalidEnum; - break; - - case ALC_INVALID_VALUE: - value = alcErrInvalidValue; - break; - - case ALC_INVALID_DEVICE: - value = alcErrInvalidDevice; - break; - - case ALC_INVALID_CONTEXT: - value = alcErrInvalidContext; - break; - - case ALC_OUT_OF_MEMORY: - value = alcErrOutOfMemory; - break; - - case ALC_DEVICE_SPECIFIER: - value = alcDefaultName; - break; - - case ALC_ALL_DEVICES_SPECIFIER: - if(DeviceRef dev{VerifyDevice(Device)}) - value = dev->DeviceName.c_str(); - else - { - ProbeAllDevicesList(); - value = alcAllDevicesList.c_str(); - } - break; - - case ALC_CAPTURE_DEVICE_SPECIFIER: - if(DeviceRef dev{VerifyDevice(Device)}) - value = dev->DeviceName.c_str(); - else - { - ProbeCaptureDeviceList(); - value = alcCaptureDeviceList.c_str(); - } - break; - - /* Default devices are always first in the list */ - case ALC_DEFAULT_DEVICE_SPECIFIER: - value = alcDefaultName; - break; - - case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: - if(alcAllDevicesList.empty()) - ProbeAllDevicesList(); - - /* Copy first entry as default. */ - alcDefaultAllDevicesSpecifier = alcAllDevicesList.c_str(); - value = alcDefaultAllDevicesSpecifier.c_str(); - break; - - case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: - if(alcCaptureDeviceList.empty()) - ProbeCaptureDeviceList(); - - /* Copy first entry as default. */ - alcCaptureDefaultDeviceSpecifier = alcCaptureDeviceList.c_str(); - value = alcCaptureDefaultDeviceSpecifier.c_str(); - break; - - case ALC_EXTENSIONS: - if(VerifyDevice(Device)) - value = alcExtensionList; - else - value = alcNoDeviceExtList; - break; - - case ALC_HRTF_SPECIFIER_SOFT: - if(DeviceRef dev{VerifyDevice(Device)}) - { - std::lock_guard _{dev->StateLock}; - value = (dev->mHrtf ? dev->HrtfName.c_str() : ""); - } - else - alcSetError(nullptr, ALC_INVALID_DEVICE); - break; - - default: - alcSetError(VerifyDevice(Device).get(), ALC_INVALID_ENUM); - break; - } - - return value; -} -END_API_FUNC - - -static inline ALCsizei NumAttrsForDevice(ALCdevice *device) -{ - if(device->Type == Capture) return 9; - if(device->Type != Loopback) return 29; - if(device->FmtChans == DevFmtAmbi3D) - return 35; - return 29; -} - -static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, const al::span values) -{ - ALCsizei i; - - if(values.empty()) - { - alcSetError(device, ALC_INVALID_VALUE); - return 0; - } - - if(!device) - { - switch(param) - { - case ALC_MAJOR_VERSION: - values[0] = alcMajorVersion; - return 1; - case ALC_MINOR_VERSION: - values[0] = alcMinorVersion; - return 1; - - case ALC_ATTRIBUTES_SIZE: - case ALC_ALL_ATTRIBUTES: - case ALC_FREQUENCY: - case ALC_REFRESH: - case ALC_SYNC: - case ALC_MONO_SOURCES: - case ALC_STEREO_SOURCES: - case ALC_CAPTURE_SAMPLES: - case ALC_FORMAT_CHANNELS_SOFT: - case ALC_FORMAT_TYPE_SOFT: - case ALC_AMBISONIC_LAYOUT_SOFT: - case ALC_AMBISONIC_SCALING_SOFT: - case ALC_AMBISONIC_ORDER_SOFT: - case ALC_MAX_AMBISONIC_ORDER_SOFT: - alcSetError(nullptr, ALC_INVALID_DEVICE); - return 0; - - default: - alcSetError(nullptr, ALC_INVALID_ENUM); - return 0; - } - return 0; - } - - if(device->Type == Capture) - { - switch(param) - { - case ALC_ATTRIBUTES_SIZE: - values[0] = NumAttrsForDevice(device); - return 1; - - case ALC_ALL_ATTRIBUTES: - i = 0; - if(values.size() < static_cast(NumAttrsForDevice(device))) - alcSetError(device, ALC_INVALID_VALUE); - else - { - std::lock_guard _{device->StateLock}; - values[i++] = ALC_MAJOR_VERSION; - values[i++] = alcMajorVersion; - values[i++] = ALC_MINOR_VERSION; - values[i++] = alcMinorVersion; - values[i++] = ALC_CAPTURE_SAMPLES; - values[i++] = device->Backend->availableSamples(); - values[i++] = ALC_CONNECTED; - values[i++] = device->Connected.load(std::memory_order_relaxed); - values[i++] = 0; - } - return i; - - case ALC_MAJOR_VERSION: - values[0] = alcMajorVersion; - return 1; - case ALC_MINOR_VERSION: - values[0] = alcMinorVersion; - return 1; - - case ALC_CAPTURE_SAMPLES: - { std::lock_guard _{device->StateLock}; - values[0] = device->Backend->availableSamples(); - } - return 1; - - case ALC_CONNECTED: - { std::lock_guard _{device->StateLock}; - values[0] = device->Connected.load(std::memory_order_acquire); - } - return 1; - - default: - alcSetError(device, ALC_INVALID_ENUM); - return 0; - } - return 0; - } - - /* render device */ - switch(param) - { - case ALC_ATTRIBUTES_SIZE: - values[0] = NumAttrsForDevice(device); - return 1; - - case ALC_ALL_ATTRIBUTES: - i = 0; - if(values.size() < static_cast(NumAttrsForDevice(device))) - alcSetError(device, ALC_INVALID_VALUE); - else - { - std::lock_guard _{device->StateLock}; - values[i++] = ALC_MAJOR_VERSION; - values[i++] = alcMajorVersion; - values[i++] = ALC_MINOR_VERSION; - values[i++] = alcMinorVersion; - values[i++] = ALC_EFX_MAJOR_VERSION; - values[i++] = alcEFXMajorVersion; - values[i++] = ALC_EFX_MINOR_VERSION; - values[i++] = alcEFXMinorVersion; - - values[i++] = ALC_FREQUENCY; - values[i++] = device->Frequency; - if(device->Type != Loopback) - { - values[i++] = ALC_REFRESH; - values[i++] = device->Frequency / device->UpdateSize; - - values[i++] = ALC_SYNC; - values[i++] = ALC_FALSE; - } - else - { - if(device->FmtChans == DevFmtAmbi3D) - { - values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; - values[i++] = static_cast(device->mAmbiLayout); - - values[i++] = ALC_AMBISONIC_SCALING_SOFT; - values[i++] = static_cast(device->mAmbiScale); - - values[i++] = ALC_AMBISONIC_ORDER_SOFT; - values[i++] = device->mAmbiOrder; - } - - values[i++] = ALC_FORMAT_CHANNELS_SOFT; - values[i++] = device->FmtChans; - - values[i++] = ALC_FORMAT_TYPE_SOFT; - values[i++] = device->FmtType; - } - - values[i++] = ALC_MONO_SOURCES; - values[i++] = device->NumMonoSources; - - values[i++] = ALC_STEREO_SOURCES; - values[i++] = device->NumStereoSources; - - values[i++] = ALC_MAX_AUXILIARY_SENDS; - values[i++] = device->NumAuxSends; - - values[i++] = ALC_HRTF_SOFT; - values[i++] = (device->mHrtf ? ALC_TRUE : ALC_FALSE); - - values[i++] = ALC_HRTF_STATUS_SOFT; - values[i++] = device->HrtfStatus; - - values[i++] = ALC_OUTPUT_LIMITER_SOFT; - values[i++] = device->Limiter ? ALC_TRUE : ALC_FALSE; - - values[i++] = ALC_MAX_AMBISONIC_ORDER_SOFT; - values[i++] = MAX_AMBI_ORDER; - - values[i++] = 0; - } - return i; - - case ALC_MAJOR_VERSION: - values[0] = alcMajorVersion; - return 1; - - case ALC_MINOR_VERSION: - values[0] = alcMinorVersion; - return 1; - - case ALC_EFX_MAJOR_VERSION: - values[0] = alcEFXMajorVersion; - return 1; - - case ALC_EFX_MINOR_VERSION: - values[0] = alcEFXMinorVersion; - return 1; - - case ALC_FREQUENCY: - values[0] = device->Frequency; - return 1; - - case ALC_REFRESH: - if(device->Type == Loopback) - { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; - } - { std::lock_guard _{device->StateLock}; - values[0] = device->Frequency / device->UpdateSize; - } - return 1; - - case ALC_SYNC: - if(device->Type == Loopback) - { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; - } - values[0] = ALC_FALSE; - return 1; - - case ALC_FORMAT_CHANNELS_SOFT: - if(device->Type != Loopback) - { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; - } - values[0] = device->FmtChans; - return 1; - - case ALC_FORMAT_TYPE_SOFT: - if(device->Type != Loopback) - { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; - } - values[0] = device->FmtType; - return 1; - - case ALC_AMBISONIC_LAYOUT_SOFT: - if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) - { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; - } - values[0] = static_cast(device->mAmbiLayout); - return 1; - - case ALC_AMBISONIC_SCALING_SOFT: - if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) - { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; - } - values[0] = static_cast(device->mAmbiScale); - return 1; - - case ALC_AMBISONIC_ORDER_SOFT: - if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) - { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; - } - values[0] = device->mAmbiOrder; - return 1; - - case ALC_MONO_SOURCES: - values[0] = device->NumMonoSources; - return 1; - - case ALC_STEREO_SOURCES: - values[0] = device->NumStereoSources; - return 1; - - case ALC_MAX_AUXILIARY_SENDS: - values[0] = device->NumAuxSends; - return 1; - - case ALC_CONNECTED: - { std::lock_guard _{device->StateLock}; - values[0] = device->Connected.load(std::memory_order_acquire); - } - return 1; - - case ALC_HRTF_SOFT: - values[0] = (device->mHrtf ? ALC_TRUE : ALC_FALSE); - return 1; - - case ALC_HRTF_STATUS_SOFT: - values[0] = device->HrtfStatus; - return 1; - - case ALC_NUM_HRTF_SPECIFIERS_SOFT: - { std::lock_guard _{device->StateLock}; - device->HrtfList.clear(); - device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); - values[0] = static_cast(minz(device->HrtfList.size(), - std::numeric_limits::max())); - } - return 1; - - case ALC_OUTPUT_LIMITER_SOFT: - values[0] = device->Limiter ? ALC_TRUE : ALC_FALSE; - return 1; - - case ALC_MAX_AMBISONIC_ORDER_SOFT: - values[0] = MAX_AMBI_ORDER; - return 1; - - default: - alcSetError(device, ALC_INVALID_ENUM); - return 0; - } - return 0; -} - -/* alcGetIntegerv - * - * Returns information about the device and the version of OpenAL - */ -ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) -START_API_FUNC -{ - DeviceRef dev{VerifyDevice(device)}; - if(size <= 0 || values == nullptr) - alcSetError(dev.get(), ALC_INVALID_VALUE); - else - GetIntegerv(dev.get(), param, {values, values+size}); -} -END_API_FUNC - -ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALCsizei size, ALCint64SOFT *values) -START_API_FUNC -{ - DeviceRef dev{VerifyDevice(device)}; - if(size <= 0 || values == nullptr) - alcSetError(dev.get(), ALC_INVALID_VALUE); - else if(!dev || dev->Type == Capture) - { - auto ivals = al::vector(size); - size = GetIntegerv(dev.get(), pname, {ivals.data(), ivals.size()}); - std::copy(ivals.begin(), ivals.begin()+size, values); - } - else /* render device */ - { - switch(pname) - { - case ALC_ATTRIBUTES_SIZE: - *values = NumAttrsForDevice(dev.get())+4; - break; - - case ALC_ALL_ATTRIBUTES: - if(size < NumAttrsForDevice(dev.get())+4) - alcSetError(dev.get(), ALC_INVALID_VALUE); - else - { - ALsizei i{0}; - std::lock_guard _{dev->StateLock}; - values[i++] = ALC_FREQUENCY; - values[i++] = dev->Frequency; - - if(dev->Type != Loopback) - { - values[i++] = ALC_REFRESH; - values[i++] = dev->Frequency / dev->UpdateSize; - - values[i++] = ALC_SYNC; - values[i++] = ALC_FALSE; - } - else - { - if(dev->FmtChans == DevFmtAmbi3D) - { - values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; - values[i++] = static_cast(dev->mAmbiLayout); - - values[i++] = ALC_AMBISONIC_SCALING_SOFT; - values[i++] = static_cast(dev->mAmbiScale); - - values[i++] = ALC_AMBISONIC_ORDER_SOFT; - values[i++] = dev->mAmbiOrder; - } - - values[i++] = ALC_FORMAT_CHANNELS_SOFT; - values[i++] = dev->FmtChans; - - values[i++] = ALC_FORMAT_TYPE_SOFT; - values[i++] = dev->FmtType; - } - - values[i++] = ALC_MONO_SOURCES; - values[i++] = dev->NumMonoSources; - - values[i++] = ALC_STEREO_SOURCES; - values[i++] = dev->NumStereoSources; - - values[i++] = ALC_MAX_AUXILIARY_SENDS; - values[i++] = dev->NumAuxSends; - - values[i++] = ALC_HRTF_SOFT; - values[i++] = (dev->mHrtf ? ALC_TRUE : ALC_FALSE); - - values[i++] = ALC_HRTF_STATUS_SOFT; - values[i++] = dev->HrtfStatus; - - values[i++] = ALC_OUTPUT_LIMITER_SOFT; - values[i++] = dev->Limiter ? ALC_TRUE : ALC_FALSE; - - ClockLatency clock{GetClockLatency(dev.get())}; - values[i++] = ALC_DEVICE_CLOCK_SOFT; - values[i++] = clock.ClockTime.count(); - - values[i++] = ALC_DEVICE_LATENCY_SOFT; - values[i++] = clock.Latency.count(); - - values[i++] = 0; - } - break; - - case ALC_DEVICE_CLOCK_SOFT: - { std::lock_guard _{dev->StateLock}; - nanoseconds basecount; - ALuint samplecount; - ALuint refcount; - do { - while(((refcount=ReadRef(&dev->MixCount))&1) != 0) - std::this_thread::yield(); - basecount = dev->ClockBase; - samplecount = dev->SamplesDone; - } while(refcount != ReadRef(&dev->MixCount)); - basecount += nanoseconds{seconds{samplecount}} / dev->Frequency; - *values = basecount.count(); - } - break; - - case ALC_DEVICE_LATENCY_SOFT: - { std::lock_guard _{dev->StateLock}; - ClockLatency clock{GetClockLatency(dev.get())}; - *values = clock.Latency.count(); - } - break; - - case ALC_DEVICE_CLOCK_LATENCY_SOFT: - if(size < 2) - alcSetError(dev.get(), ALC_INVALID_VALUE); - else - { - std::lock_guard _{dev->StateLock}; - ClockLatency clock{GetClockLatency(dev.get())}; - values[0] = clock.ClockTime.count(); - values[1] = clock.Latency.count(); - } - break; - - default: - auto ivals = al::vector(size); - size = GetIntegerv(dev.get(), pname, {ivals.data(), ivals.size()}); - std::copy(ivals.begin(), ivals.begin()+size, values); - break; - } - } -} -END_API_FUNC - - -/* alcIsExtensionPresent - * - * Determines if there is support for a particular extension - */ -ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extName) -START_API_FUNC -{ - DeviceRef dev{VerifyDevice(device)}; - if(!extName) - alcSetError(dev.get(), ALC_INVALID_VALUE); - else - { - size_t len = strlen(extName); - const char *ptr = (dev ? alcExtensionList : alcNoDeviceExtList); - while(ptr && *ptr) - { - if(strncasecmp(ptr, extName, len) == 0 && - (ptr[len] == '\0' || isspace(ptr[len]))) - return ALC_TRUE; - - if((ptr=strchr(ptr, ' ')) != nullptr) - { - do { - ++ptr; - } while(isspace(*ptr)); - } - } - } - return ALC_FALSE; -} -END_API_FUNC - - -/* alcGetProcAddress - * - * Retrieves the function address for a particular extension function - */ -ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcName) -START_API_FUNC -{ - if(!funcName) - { - DeviceRef dev{VerifyDevice(device)}; - alcSetError(dev.get(), ALC_INVALID_VALUE); - } - else - { - for(const auto &func : alcFunctions) - { - if(strcmp(func.funcName, funcName) == 0) - return func.address; - } - } - return nullptr; -} -END_API_FUNC - - -/* alcGetEnumValue - * - * Get the value for a particular ALC enumeration name - */ -ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumName) -START_API_FUNC -{ - if(!enumName) - { - DeviceRef dev{VerifyDevice(device)}; - alcSetError(dev.get(), ALC_INVALID_VALUE); - } - else - { - for(const auto &enm : alcEnumerations) - { - if(strcmp(enm.enumName, enumName) == 0) - return enm.value; - } - } - return 0; -} -END_API_FUNC - - -/* alcCreateContext - * - * Create and attach a context to the given device. - */ -ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrList) -START_API_FUNC -{ - /* Explicitly hold the list lock while taking the StateLock in case the - * device is asynchronously destroyed, to ensure this new context is - * properly cleaned up after being made. - */ - std::unique_lock listlock{ListLock}; - DeviceRef dev{VerifyDevice(device)}; - if(!dev || dev->Type == Capture || !dev->Connected.load(std::memory_order_relaxed)) - { - listlock.unlock(); - alcSetError(dev.get(), ALC_INVALID_DEVICE); - return nullptr; - } - std::unique_lock statelock{dev->StateLock}; - listlock.unlock(); - - dev->LastError.store(ALC_NO_ERROR); - - ContextRef context{new ALCcontext{dev.get()}}; - ALCdevice_IncRef(context->Device); - - ALCenum err{UpdateDeviceParams(dev.get(), attrList)}; - if(err != ALC_NO_ERROR) - { - alcSetError(dev.get(), err); - if(err == ALC_INVALID_DEVICE) - aluHandleDisconnect(dev.get(), "Device update failure"); - statelock.unlock(); - - return nullptr; - } - AllocateVoices(context.get(), 256); - - if(DefaultEffect.type != AL_EFFECT_NULL && dev->Type == Playback) - { - void *ptr{al_calloc(16, sizeof(ALeffectslot))}; - context->DefaultSlot = std::unique_ptr{new (ptr) ALeffectslot{}}; - if(InitEffectSlot(context->DefaultSlot.get()) == AL_NO_ERROR) - aluInitEffectPanning(context->DefaultSlot.get(), dev.get()); - else - { - context->DefaultSlot = nullptr; - ERR("Failed to initialize the default effect slot\n"); - } - } - - InitContext(context.get()); - - if(auto volopt = ConfigValueFloat(dev->DeviceName.c_str(), nullptr, "volume-adjust")) - { - const ALfloat valf{*volopt}; - if(!std::isfinite(valf)) - ERR("volume-adjust must be finite: %f\n", valf); - else - { - const ALfloat db{clampf(valf, -24.0f, 24.0f)}; - if(db != valf) - WARN("volume-adjust clamped: %f, range: +/-%f\n", valf, 24.0f); - context->GainBoost = std::pow(10.0f, db/20.0f); - TRACE("volume-adjust gain: %f\n", context->GainBoost); - } - } - UpdateListenerProps(context.get()); - - { - using ContextArray = al::FlexArray; - - /* Allocate a new context array, which holds 1 more than the current/ - * old array. - */ - auto *oldarray = device->mContexts.load(); - const size_t newcount{oldarray->size()+1}; - void *ptr{al_calloc(alignof(ContextArray), ContextArray::Sizeof(newcount))}; - auto *newarray = new (ptr) ContextArray{newcount}; - - /* Copy the current/old context handles to the new array, appending the - * new context. - */ - auto iter = std::copy(oldarray->begin(), oldarray->end(), newarray->begin()); - *iter = context.get(); - - /* Store the new context array in the device. Wait for any current mix - * to finish before deleting the old array. - */ - dev->mContexts.store(newarray); - if(oldarray != &EmptyContextArray) - { - while((dev->MixCount.load(std::memory_order_acquire)&1)) - std::this_thread::yield(); - delete oldarray; - } - } - statelock.unlock(); - - { - std::lock_guard _{ListLock}; - auto iter = std::lower_bound(ContextList.cbegin(), ContextList.cend(), context.get()); - ALCcontext_IncRef(context.get()); - ContextList.insert(iter, ContextRef{context.get()}); - } - - if(context->DefaultSlot) - { - if(InitializeEffect(context.get(), context->DefaultSlot.get(), &DefaultEffect) == AL_NO_ERROR) - UpdateEffectSlotProps(context->DefaultSlot.get(), context.get()); - else - ERR("Failed to initialize the default effect\n"); - } - - TRACE("Created context %p\n", context.get()); - return context.get(); -} -END_API_FUNC - -/* alcDestroyContext - * - * Remove a context from its device - */ -ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) -START_API_FUNC -{ - std::unique_lock listlock{ListLock}; - auto iter = std::lower_bound(ContextList.begin(), ContextList.end(), context); - if(iter == ContextList.end() || *iter != context) - { - listlock.unlock(); - alcSetError(nullptr, ALC_INVALID_CONTEXT); - return; - } - /* Hold an extra reference to this context so it remains valid until the - * ListLock is released. - */ - ContextRef ctx{std::move(*iter)}; - ContextList.erase(iter); - - ALCdevice *Device{ctx->Device}; - - std::lock_guard _{Device->StateLock}; - if(!ReleaseContext(ctx.get(), Device) && Device->Flags.get()) - { - Device->Backend->stop(); - Device->Flags.unset(); - } -} -END_API_FUNC - - -/* alcGetCurrentContext - * - * Returns the currently active context on the calling thread - */ -ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) -START_API_FUNC -{ - ALCcontext *Context{LocalContext.get()}; - if(!Context) Context = GlobalContext.load(); - return Context; -} -END_API_FUNC - -/* alcGetThreadContext - * - * Returns the currently active thread-local context - */ -ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) -START_API_FUNC -{ return LocalContext.get(); } -END_API_FUNC - -/* alcMakeContextCurrent - * - * Makes the given context the active process-wide context, and removes the - * thread-local context for the calling thread. - */ -ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) -START_API_FUNC -{ - /* context must be valid or nullptr */ - ContextRef ctx; - if(context) - { - ctx = VerifyContext(context); - if(!ctx) - { - alcSetError(nullptr, ALC_INVALID_CONTEXT); - return ALC_FALSE; - } - } - /* Release this reference (if any) to store it in the GlobalContext - * pointer. Take ownership of the reference (if any) that was previously - * stored there. - */ - ctx = ContextRef{GlobalContext.exchange(ctx.release())}; - - /* Reset (decrement) the previous global reference by replacing it with the - * thread-local context. Take ownership of the thread-local context - * reference (if any), clearing the storage to null. - */ - ctx = ContextRef{LocalContext.get()}; - if(ctx) LocalContext.set(nullptr); - /* Reset (decrement) the previous thread-local reference. */ - - return ALC_TRUE; -} -END_API_FUNC - -/* alcSetThreadContext - * - * Makes the given context the active context for the current thread - */ -ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) -START_API_FUNC -{ - /* context must be valid or nullptr */ - ContextRef ctx; - if(context) - { - ctx = VerifyContext(context); - if(!ctx) - { - alcSetError(nullptr, ALC_INVALID_CONTEXT); - return ALC_FALSE; - } - } - /* context's reference count is already incremented */ - ContextRef old{LocalContext.get()}; - LocalContext.set(ctx.release()); - - return ALC_TRUE; -} -END_API_FUNC - - -/* alcGetContextsDevice - * - * Returns the device that a particular context is attached to - */ -ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *Context) -START_API_FUNC -{ - ContextRef ctx{VerifyContext(Context)}; - if(!ctx) - { - alcSetError(nullptr, ALC_INVALID_CONTEXT); - return nullptr; - } - return ctx->Device; -} -END_API_FUNC - - -/* alcOpenDevice - * - * Opens the named device. - */ -ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) -START_API_FUNC -{ - DO_INITCONFIG(); - - if(!PlaybackFactory) - { - alcSetError(nullptr, ALC_INVALID_VALUE); - return nullptr; - } - - if(deviceName && (!deviceName[0] || strcasecmp(deviceName, alcDefaultName) == 0 || strcasecmp(deviceName, "openal-soft") == 0 -#ifdef _WIN32 - /* Some old Windows apps hardcode these expecting OpenAL to use a - * specific audio API, even when they're not enumerated. Creative's - * router effectively ignores them too. - */ - || strcasecmp(deviceName, "DirectSound3D") == 0 || strcasecmp(deviceName, "DirectSound") == 0 - || strcasecmp(deviceName, "MMSYSTEM") == 0 -#endif - )) - deviceName = nullptr; - - DeviceRef device{new ALCdevice{Playback}}; - - /* Set output format */ - device->FmtChans = DevFmtChannelsDefault; - device->FmtType = DevFmtTypeDefault; - device->Frequency = DEFAULT_OUTPUT_RATE; - device->UpdateSize = DEFAULT_UPDATE_SIZE; - device->BufferSize = DEFAULT_UPDATE_SIZE * DEFAULT_NUM_UPDATES; - - device->SourcesMax = 256; - device->AuxiliaryEffectSlotMax = 64; - device->NumAuxSends = DEFAULT_SENDS; - - try { - /* Create the device backend. */ - device->Backend = PlaybackFactory->createBackend(device.get(), BackendType::Playback); - - /* Find a playback device to open */ - ALCenum err{device->Backend->open(deviceName)}; - if(err != ALC_NO_ERROR) - { - alcSetError(nullptr, err); - return nullptr; - } - } - catch(al::backend_exception &e) { - WARN("Failed to open playback device: %s\n", e.what()); - alcSetError(nullptr, e.errorCode()); - return nullptr; - } - - deviceName = device->DeviceName.c_str(); - if(auto chanopt = ConfigValueStr(deviceName, nullptr, "channels")) - { - static constexpr struct ChannelMap { - const char name[16]; - DevFmtChannels chans; - ALsizei order; - } chanlist[] = { - { "mono", DevFmtMono, 0 }, - { "stereo", DevFmtStereo, 0 }, - { "quad", DevFmtQuad, 0 }, - { "surround51", DevFmtX51, 0 }, - { "surround61", DevFmtX61, 0 }, - { "surround71", DevFmtX71, 0 }, - { "surround51rear", DevFmtX51Rear, 0 }, - { "ambi1", DevFmtAmbi3D, 1 }, - { "ambi2", DevFmtAmbi3D, 2 }, - { "ambi3", DevFmtAmbi3D, 3 }, - }; - - const ALCchar *fmt{chanopt->c_str()}; - auto iter = std::find_if(std::begin(chanlist), std::end(chanlist), - [fmt](const ChannelMap &entry) -> bool - { return strcasecmp(entry.name, fmt) == 0; } - ); - if(iter == std::end(chanlist)) - ERR("Unsupported channels: %s\n", fmt); - else - { - device->FmtChans = iter->chans; - device->mAmbiOrder = iter->order; - device->Flags.set(); - } - } - if(auto typeopt = ConfigValueStr(deviceName, nullptr, "sample-type")) - { - static constexpr struct TypeMap { - const char name[16]; - DevFmtType type; - } typelist[] = { - { "int8", DevFmtByte }, - { "uint8", DevFmtUByte }, - { "int16", DevFmtShort }, - { "uint16", DevFmtUShort }, - { "int32", DevFmtInt }, - { "uint32", DevFmtUInt }, - { "float32", DevFmtFloat }, - }; - - const ALCchar *fmt{typeopt->c_str()}; - auto iter = std::find_if(std::begin(typelist), std::end(typelist), - [fmt](const TypeMap &entry) -> bool - { return strcasecmp(entry.name, fmt) == 0; } - ); - if(iter == std::end(typelist)) - ERR("Unsupported sample-type: %s\n", fmt); - else - { - device->FmtType = iter->type; - device->Flags.set(); - } - } - - if(ALuint freq{ConfigValueUInt(deviceName, nullptr, "frequency").value_or(0)}) - { - if(freq < MIN_OUTPUT_RATE) - { - ERR("%uhz request clamped to %uhz minimum\n", freq, MIN_OUTPUT_RATE); - freq = MIN_OUTPUT_RATE; - } - device->UpdateSize = (device->UpdateSize*freq + device->Frequency/2) / device->Frequency; - device->BufferSize = (device->BufferSize*freq + device->Frequency/2) / device->Frequency; - device->Frequency = freq; - device->Flags.set(); - } - - if(auto persizeopt = ConfigValueUInt(deviceName, nullptr, "period_size")) - device->UpdateSize = clampu(*persizeopt, 64, 8192); - - if(auto peropt = ConfigValueUInt(deviceName, nullptr, "periods")) - device->BufferSize = device->UpdateSize * clampu(*peropt, 2, 16); - else - device->BufferSize = maxu(device->BufferSize, device->UpdateSize*2); - - if(auto srcsopt = ConfigValueUInt(deviceName, nullptr, "sources")) - { - if(*srcsopt > 0) device->SourcesMax = *srcsopt; - } - - if(auto slotsopt = ConfigValueUInt(deviceName, nullptr, "slots")) - { - if(*slotsopt > 0) - device->AuxiliaryEffectSlotMax = minu(*slotsopt, INT_MAX); - } - - if(auto sendsopt = ConfigValueInt(deviceName, nullptr, "sends")) - device->NumAuxSends = clampi(DEFAULT_SENDS, 0, clampi(*sendsopt, 0, MAX_SENDS)); - - device->NumStereoSources = 1; - device->NumMonoSources = device->SourcesMax - device->NumStereoSources; - - if(auto ambiopt = ConfigValueStr(deviceName, nullptr, "ambi-format")) - { - const ALCchar *fmt{ambiopt->c_str()}; - if(strcasecmp(fmt, "fuma") == 0) - { - if(device->mAmbiOrder > 3) - ERR("FuMa is incompatible with %d%s order ambisonics (up to third-order only)\n", - device->mAmbiOrder, - (((device->mAmbiOrder%100)/10) == 1) ? "th" : - ((device->mAmbiOrder%10) == 1) ? "st" : - ((device->mAmbiOrder%10) == 2) ? "nd" : - ((device->mAmbiOrder%10) == 3) ? "rd" : "th"); - else - { - device->mAmbiLayout = AmbiLayout::FuMa; - device->mAmbiScale = AmbiNorm::FuMa; - } - } - else if(strcasecmp(fmt, "ambix") == 0 || strcasecmp(fmt, "acn+sn3d") == 0) - { - device->mAmbiLayout = AmbiLayout::ACN; - device->mAmbiScale = AmbiNorm::SN3D; - } - else if(strcasecmp(fmt, "acn+n3d") == 0) - { - device->mAmbiLayout = AmbiLayout::ACN; - device->mAmbiScale = AmbiNorm::N3D; - } - else - ERR("Unsupported ambi-format: %s\n", fmt); - } - - { - std::lock_guard _{ListLock}; - auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get()); - ALCdevice_IncRef(device.get()); - DeviceList.insert(iter, DeviceRef{device.get()}); - } - - TRACE("Created device %p, \"%s\"\n", device.get(), device->DeviceName.c_str()); - return device.get(); -} -END_API_FUNC - -/* alcCloseDevice - * - * Closes the given device. - */ -ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) -START_API_FUNC -{ - std::unique_lock listlock{ListLock}; - auto iter = std::lower_bound(DeviceList.begin(), DeviceList.end(), device); - if(iter == DeviceList.end() || *iter != device) - { - alcSetError(nullptr, ALC_INVALID_DEVICE); - return ALC_FALSE; - } - if((*iter)->Type == Capture) - { - alcSetError(iter->get(), ALC_INVALID_DEVICE); - return ALC_FALSE; - } - - /* Erase the device, and any remaining contexts left on it, from their - * respective lists. - */ - DeviceRef dev{std::move(*iter)}; - DeviceList.erase(iter); - - std::unique_lock statelock{dev->StateLock}; - al::vector orphanctxs; - for(ALCcontext *ctx : *dev->mContexts.load()) - { - auto iter = std::lower_bound(ContextList.begin(), ContextList.end(), ctx); - if(iter != ContextList.end() && *iter == ctx) - { - orphanctxs.emplace_back(std::move(*iter)); - ContextList.erase(iter); - } - } - listlock.unlock(); - - for(ContextRef &context : orphanctxs) - { - WARN("Releasing context %p\n", context.get()); - ReleaseContext(context.get(), dev.get()); - } - orphanctxs.clear(); - - if(dev->Flags.get()) - dev->Backend->stop(); - dev->Flags.unset(); - - return ALC_TRUE; -} -END_API_FUNC - - -/************************************************ - * ALC capture functions - ************************************************/ -ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei samples) -START_API_FUNC -{ - DO_INITCONFIG(); - - if(!CaptureFactory) - { - alcSetError(nullptr, ALC_INVALID_VALUE); - return nullptr; - } - - if(samples <= 0) - { - alcSetError(nullptr, ALC_INVALID_VALUE); - return nullptr; - } - - if(deviceName && (!deviceName[0] || strcasecmp(deviceName, alcDefaultName) == 0 || strcasecmp(deviceName, "openal-soft") == 0)) - deviceName = nullptr; - - DeviceRef device{new ALCdevice{Capture}}; - - auto decompfmt = DecomposeDevFormat(format); - if(!decompfmt) - { - alcSetError(nullptr, ALC_INVALID_ENUM); - return nullptr; - } - - device->Frequency = frequency; - device->FmtChans = decompfmt->chans; - device->FmtType = decompfmt->type; - device->Flags.set(); - - device->UpdateSize = samples; - device->BufferSize = samples; - - try { - device->Backend = CaptureFactory->createBackend(device.get(), BackendType::Capture); - - TRACE("Capture format: %s, %s, %uhz, %u / %u buffer\n", - DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), - device->Frequency, device->UpdateSize, device->BufferSize); - ALCenum err{device->Backend->open(deviceName)}; - if(err != ALC_NO_ERROR) - { - alcSetError(nullptr, err); - return nullptr; - } - } - catch(al::backend_exception &e) { - WARN("Failed to open capture device: %s\n", e.what()); - alcSetError(nullptr, e.errorCode()); - return nullptr; - } - - { - std::lock_guard _{ListLock}; - auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get()); - ALCdevice_IncRef(device.get()); - DeviceList.insert(iter, DeviceRef{device.get()}); - } - - TRACE("Created device %p, \"%s\"\n", device.get(), device->DeviceName.c_str()); - return device.get(); -} -END_API_FUNC - -ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) -START_API_FUNC -{ - std::unique_lock listlock{ListLock}; - auto iter = std::lower_bound(DeviceList.begin(), DeviceList.end(), device); - if(iter == DeviceList.end() || *iter != device) - { - alcSetError(nullptr, ALC_INVALID_DEVICE); - return ALC_FALSE; - } - if((*iter)->Type != Capture) - { - alcSetError(iter->get(), ALC_INVALID_DEVICE); - return ALC_FALSE; - } - - DeviceRef dev{std::move(*iter)}; - DeviceList.erase(iter); - listlock.unlock(); - - std::lock_guard _{dev->StateLock}; - if(dev->Flags.get()) - dev->Backend->stop(); - dev->Flags.unset(); - - return ALC_TRUE; -} -END_API_FUNC - -ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) -START_API_FUNC -{ - DeviceRef dev{VerifyDevice(device)}; - if(!dev || dev->Type != Capture) - { - alcSetError(dev.get(), ALC_INVALID_DEVICE); - return; - } - - std::lock_guard _{dev->StateLock}; - if(!dev->Connected.load(std::memory_order_acquire)) - alcSetError(dev.get(), ALC_INVALID_DEVICE); - else if(!dev->Flags.get()) - { - if(dev->Backend->start()) - dev->Flags.set(); - else - { - aluHandleDisconnect(dev.get(), "Device start failure"); - alcSetError(dev.get(), ALC_INVALID_DEVICE); - } - } -} -END_API_FUNC - -ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) -START_API_FUNC -{ - DeviceRef dev{VerifyDevice(device)}; - if(!dev || dev->Type != Capture) - alcSetError(dev.get(), ALC_INVALID_DEVICE); - else - { - std::lock_guard _{dev->StateLock}; - if(dev->Flags.get()) - dev->Backend->stop(); - dev->Flags.unset(); - } -} -END_API_FUNC - -ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) -START_API_FUNC -{ - DeviceRef dev{VerifyDevice(device)}; - if(!dev || dev->Type != Capture) - { - alcSetError(dev.get(), ALC_INVALID_DEVICE); - return; - } - - ALCenum err{ALC_INVALID_VALUE}; - { std::lock_guard _{dev->StateLock}; - BackendBase *backend{dev->Backend.get()}; - if(samples >= 0 && backend->availableSamples() >= static_cast(samples)) - err = backend->captureSamples(buffer, samples); - } - if(err != ALC_NO_ERROR) - alcSetError(dev.get(), err); -} -END_API_FUNC - - -/************************************************ - * ALC loopback functions - ************************************************/ - -/* alcLoopbackOpenDeviceSOFT - * - * Open a loopback device, for manual rendering. - */ -ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName) -START_API_FUNC -{ - DO_INITCONFIG(); - - /* Make sure the device name, if specified, is us. */ - if(deviceName && strcmp(deviceName, alcDefaultName) != 0) - { - alcSetError(nullptr, ALC_INVALID_VALUE); - return nullptr; - } - - DeviceRef device{new ALCdevice{Loopback}}; - - device->SourcesMax = 256; - device->AuxiliaryEffectSlotMax = 64; - device->NumAuxSends = DEFAULT_SENDS; - - //Set output format - device->BufferSize = 0; - device->UpdateSize = 0; - - device->Frequency = DEFAULT_OUTPUT_RATE; - device->FmtChans = DevFmtChannelsDefault; - device->FmtType = DevFmtTypeDefault; - - if(auto srcsopt = ConfigValueUInt(nullptr, nullptr, "sources")) - { - if(*srcsopt > 0) device->SourcesMax = *srcsopt; - } - - if(auto slotsopt = ConfigValueUInt(nullptr, nullptr, "slots")) - { - if(*slotsopt > 0) - device->AuxiliaryEffectSlotMax = minu(*slotsopt, INT_MAX); - } - - if(auto sendsopt = ConfigValueInt(nullptr, nullptr, "sends")) - device->NumAuxSends = clampi(DEFAULT_SENDS, 0, clampi(*sendsopt, 0, MAX_SENDS)); - - device->NumStereoSources = 1; - device->NumMonoSources = device->SourcesMax - device->NumStereoSources; - - try { - device->Backend = LoopbackBackendFactory::getFactory().createBackend(device.get(), - BackendType::Playback); - - // Open the "backend" - device->Backend->open("Loopback"); - } - catch(al::backend_exception &e) { - WARN("Failed to open loopback device: %s\n", e.what()); - alcSetError(nullptr, e.errorCode()); - return nullptr; - } - - { - std::lock_guard _{ListLock}; - auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get()); - ALCdevice_IncRef(device.get()); - DeviceList.insert(iter, DeviceRef{device.get()}); - } - - TRACE("Created device %p\n", device.get()); - return device.get(); -} -END_API_FUNC - -/* alcIsRenderFormatSupportedSOFT - * - * Determines if the loopback device supports the given format for rendering. - */ -ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type) -START_API_FUNC -{ - DeviceRef dev{VerifyDevice(device)}; - if(!dev || dev->Type != Loopback) - alcSetError(dev.get(), ALC_INVALID_DEVICE); - else if(freq <= 0) - alcSetError(dev.get(), ALC_INVALID_VALUE); - else - { - if(IsValidALCType(type) && IsValidALCChannels(channels) && freq >= MIN_OUTPUT_RATE) - return ALC_TRUE; - } - - return ALC_FALSE; -} -END_API_FUNC - -/* alcRenderSamplesSOFT - * - * Renders some samples into a buffer, using the format last set by the - * attributes given to alcCreateContext. - */ -FORCE_ALIGN ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) -START_API_FUNC -{ - DeviceRef dev{VerifyDevice(device)}; - if(!dev || dev->Type != Loopback) - alcSetError(dev.get(), ALC_INVALID_DEVICE); - else if(samples < 0 || (samples > 0 && buffer == nullptr)) - alcSetError(dev.get(), ALC_INVALID_VALUE); - else - { - BackendLockGuard _{*device->Backend}; - aluMixData(dev.get(), buffer, samples); - } -} -END_API_FUNC - - -/************************************************ - * ALC DSP pause/resume functions - ************************************************/ - -/* alcDevicePauseSOFT - * - * Pause the DSP to stop audio processing. - */ -ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device) -START_API_FUNC -{ - DeviceRef dev{VerifyDevice(device)}; - if(!dev || dev->Type != Playback) - alcSetError(dev.get(), ALC_INVALID_DEVICE); - else - { - std::lock_guard _{dev->StateLock}; - if(dev->Flags.get()) - dev->Backend->stop(); - dev->Flags.unset(); - dev->Flags.set(); - } -} -END_API_FUNC - -/* alcDeviceResumeSOFT - * - * Resume the DSP to restart audio processing. - */ -ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) -START_API_FUNC -{ - DeviceRef dev{VerifyDevice(device)}; - if(!dev || dev->Type != Playback) - { - alcSetError(dev.get(), ALC_INVALID_DEVICE); - return; - } - - std::lock_guard _{dev->StateLock}; - if(!dev->Flags.get()) - return; - dev->Flags.unset(); - if(dev->mContexts.load()->empty()) - return; - - if(dev->Backend->start() == ALC_FALSE) - { - aluHandleDisconnect(dev.get(), "Device start failure"); - alcSetError(dev.get(), ALC_INVALID_DEVICE); - return; - } - dev->Flags.set(); -} -END_API_FUNC - - -/************************************************ - * ALC HRTF functions - ************************************************/ - -/* alcGetStringiSOFT - * - * Gets a string parameter at the given index. - */ -ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index) -START_API_FUNC -{ - DeviceRef dev{VerifyDevice(device)}; - if(!dev || dev->Type == Capture) - alcSetError(dev.get(), ALC_INVALID_DEVICE); - else switch(paramName) - { - case ALC_HRTF_SPECIFIER_SOFT: - if(index >= 0 && static_cast(index) < dev->HrtfList.size()) - return dev->HrtfList[index].name.c_str(); - alcSetError(dev.get(), ALC_INVALID_VALUE); - break; - - default: - alcSetError(dev.get(), ALC_INVALID_ENUM); - break; - } - - return nullptr; -} -END_API_FUNC - -/* alcResetDeviceSOFT - * - * Resets the given device output, using the specified attribute list. - */ -ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs) -START_API_FUNC -{ - std::unique_lock listlock{ListLock}; - DeviceRef dev{VerifyDevice(device)}; - if(!dev || dev->Type == Capture) - { - listlock.unlock(); - alcSetError(dev.get(), ALC_INVALID_DEVICE); - return ALC_FALSE; - } - std::lock_guard _{dev->StateLock}; - listlock.unlock(); - - /* Force the backend to stop mixing first since we're resetting. Also reset - * the connected state so lost devices can attempt recover. - */ - if(dev->Flags.get()) - dev->Backend->stop(); - dev->Flags.unset(); - device->Connected.store(true); - - ALCenum err{UpdateDeviceParams(dev.get(), attribs)}; - if(LIKELY(err == ALC_NO_ERROR)) return ALC_TRUE; - - alcSetError(dev.get(), err); - if(err == ALC_INVALID_DEVICE) - aluHandleDisconnect(dev.get(), "Device start failure"); - return ALC_FALSE; -} -END_API_FUNC diff --git a/Alc/alcmain.h b/Alc/alcmain.h deleted file mode 100644 index a22e0e81..00000000 --- a/Alc/alcmain.h +++ /dev/null @@ -1,534 +0,0 @@ -#ifndef ALC_MAIN_H -#define ALC_MAIN_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" - -#include "albyte.h" -#include "almalloc.h" -#include "alnumeric.h" -#include "alspan.h" -#include "ambidefs.h" -#include "atomic.h" -#include "hrtf.h" -#include "inprogext.h" -#include "vector.h" - -class BFormatDec; -struct ALbuffer; -struct ALeffect; -struct ALfilter; -struct BackendBase; -struct Compressor; -struct EffectState; -struct FrontStablizer; -struct Uhj2Encoder; -struct bs2b; - - -#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) -#define IS_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) -#else -static const union { - ALuint u; - ALubyte b[sizeof(ALuint)]; -} EndianTest = { 1 }; -#define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1) -#endif - - -#define MIN_OUTPUT_RATE 8000 -#define DEFAULT_OUTPUT_RATE 44100 -#define DEFAULT_UPDATE_SIZE 882 /* 20ms */ -#define DEFAULT_NUM_UPDATES 3 - - -enum Channel { - FrontLeft = 0, - FrontRight, - FrontCenter, - LFE, - BackLeft, - BackRight, - BackCenter, - SideLeft, - SideRight, - - UpperFrontLeft, - UpperFrontRight, - UpperBackLeft, - UpperBackRight, - LowerFrontLeft, - LowerFrontRight, - LowerBackLeft, - LowerBackRight, - - Aux0, - Aux1, - Aux2, - Aux3, - Aux4, - Aux5, - Aux6, - Aux7, - Aux8, - Aux9, - Aux10, - Aux11, - Aux12, - Aux13, - Aux14, - Aux15, - - MaxChannels -}; - - -/* Device formats */ -enum DevFmtType : ALenum { - DevFmtByte = ALC_BYTE_SOFT, - DevFmtUByte = ALC_UNSIGNED_BYTE_SOFT, - DevFmtShort = ALC_SHORT_SOFT, - DevFmtUShort = ALC_UNSIGNED_SHORT_SOFT, - DevFmtInt = ALC_INT_SOFT, - DevFmtUInt = ALC_UNSIGNED_INT_SOFT, - DevFmtFloat = ALC_FLOAT_SOFT, - - DevFmtTypeDefault = DevFmtFloat -}; -enum DevFmtChannels : ALenum { - DevFmtMono = ALC_MONO_SOFT, - DevFmtStereo = ALC_STEREO_SOFT, - DevFmtQuad = ALC_QUAD_SOFT, - DevFmtX51 = ALC_5POINT1_SOFT, - DevFmtX61 = ALC_6POINT1_SOFT, - DevFmtX71 = ALC_7POINT1_SOFT, - DevFmtAmbi3D = ALC_BFORMAT3D_SOFT, - - /* Similar to 5.1, except using rear channels instead of sides */ - DevFmtX51Rear = 0x70000000, - - DevFmtChannelsDefault = DevFmtStereo -}; -#define MAX_OUTPUT_CHANNELS (16) - -/* DevFmtType traits, providing the type, etc given a DevFmtType. */ -template -struct DevFmtTypeTraits { }; - -template<> -struct DevFmtTypeTraits { using Type = ALbyte; }; -template<> -struct DevFmtTypeTraits { using Type = ALubyte; }; -template<> -struct DevFmtTypeTraits { using Type = ALshort; }; -template<> -struct DevFmtTypeTraits { using Type = ALushort; }; -template<> -struct DevFmtTypeTraits { using Type = ALint; }; -template<> -struct DevFmtTypeTraits { using Type = ALuint; }; -template<> -struct DevFmtTypeTraits { using Type = ALfloat; }; - - -ALsizei BytesFromDevFmt(DevFmtType type) noexcept; -ALsizei ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept; -inline ALsizei FrameSizeFromDevFmt(DevFmtChannels chans, DevFmtType type, ALsizei ambiorder) noexcept -{ return ChannelsFromDevFmt(chans, ambiorder) * BytesFromDevFmt(type); } - -enum class AmbiLayout { - FuMa = ALC_FUMA_SOFT, /* FuMa channel order */ - ACN = ALC_ACN_SOFT, /* ACN channel order */ - - Default = ACN -}; - -enum class AmbiNorm { - FuMa = ALC_FUMA_SOFT, /* FuMa normalization */ - SN3D = ALC_SN3D_SOFT, /* SN3D normalization */ - N3D = ALC_N3D_SOFT, /* N3D normalization */ - - Default = SN3D -}; - - -enum DeviceType { - Playback, - Capture, - Loopback -}; - - -enum RenderMode { - NormalRender, - StereoPair, - HrtfRender -}; - - -struct BufferSubList { - uint64_t FreeMask{~0_u64}; - ALbuffer *Buffers{nullptr}; /* 64 */ - - BufferSubList() noexcept = default; - BufferSubList(const BufferSubList&) = delete; - BufferSubList(BufferSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Buffers{rhs.Buffers} - { rhs.FreeMask = ~0_u64; rhs.Buffers = nullptr; } - ~BufferSubList(); - - BufferSubList& operator=(const BufferSubList&) = delete; - BufferSubList& operator=(BufferSubList&& rhs) noexcept - { std::swap(FreeMask, rhs.FreeMask); std::swap(Buffers, rhs.Buffers); return *this; } -}; - -struct EffectSubList { - uint64_t FreeMask{~0_u64}; - ALeffect *Effects{nullptr}; /* 64 */ - - EffectSubList() noexcept = default; - EffectSubList(const EffectSubList&) = delete; - EffectSubList(EffectSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Effects{rhs.Effects} - { rhs.FreeMask = ~0_u64; rhs.Effects = nullptr; } - ~EffectSubList(); - - EffectSubList& operator=(const EffectSubList&) = delete; - EffectSubList& operator=(EffectSubList&& rhs) noexcept - { std::swap(FreeMask, rhs.FreeMask); std::swap(Effects, rhs.Effects); return *this; } -}; - -struct FilterSubList { - uint64_t FreeMask{~0_u64}; - ALfilter *Filters{nullptr}; /* 64 */ - - FilterSubList() noexcept = default; - FilterSubList(const FilterSubList&) = delete; - FilterSubList(FilterSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Filters{rhs.Filters} - { rhs.FreeMask = ~0_u64; rhs.Filters = nullptr; } - ~FilterSubList(); - - FilterSubList& operator=(const FilterSubList&) = delete; - FilterSubList& operator=(FilterSubList&& rhs) noexcept - { std::swap(FreeMask, rhs.FreeMask); std::swap(Filters, rhs.Filters); return *this; } -}; - - -/* Maximum delay in samples for speaker distance compensation. */ -#define MAX_DELAY_LENGTH 1024 - -class DistanceComp { -public: - struct DistData { - ALfloat Gain{1.0f}; - ALsizei Length{0}; /* Valid range is [0...MAX_DELAY_LENGTH). */ - ALfloat *Buffer{nullptr}; - }; - -private: - std::array mChannels; - al::vector mSamples; - -public: - void setSampleCount(size_t new_size) { mSamples.resize(new_size); } - void clear() noexcept - { - for(auto &chan : mChannels) - { - chan.Gain = 1.0f; - chan.Length = 0; - chan.Buffer = nullptr; - } - using SampleVecT = decltype(mSamples); - SampleVecT{}.swap(mSamples); - } - - ALfloat *getSamples() noexcept { return mSamples.data(); } - - al::span as_span() { return mChannels; } -}; - -struct BFChannelConfig { - ALfloat Scale; - ALsizei Index; -}; - -/* Size for temporary storage of buffer data, in ALfloats. Larger values need - * more memory, while smaller values may need more iterations. The value needs - * to be a sensible size, however, as it constrains the max stepping value used - * for mixing, as well as the maximum number of samples per mixing iteration. - */ -#define BUFFERSIZE 1024 - -using FloatBufferLine = std::array; - -/* Maximum number of samples to pad on either end of a buffer for resampling. - * Note that both the beginning and end need padding! - */ -#define MAX_RESAMPLE_PADDING 24 - - -struct MixParams { - /* Coefficient channel mapping for mixing to the buffer. */ - std::array AmbiMap{}; - - al::span Buffer; -}; - -struct RealMixParams { - std::array ChannelIndex{}; - - al::span Buffer; -}; - -using POSTPROCESS = void(*)(ALCdevice *device, const ALsizei SamplesToDo); - -enum { - // Frequency was requested by the app or config file - FrequencyRequest, - // Channel configuration was requested by the config file - ChannelsRequest, - // Sample type was requested by the config file - SampleTypeRequest, - - // Specifies if the DSP is paused at user request - DevicePaused, - // Specifies if the device is currently running - DeviceRunning, - - DeviceFlagsCount -}; - -struct ALCdevice { - RefCount ref{1u}; - - std::atomic Connected{true}; - const DeviceType Type{}; - - ALuint Frequency{}; - ALuint UpdateSize{}; - ALuint BufferSize{}; - - DevFmtChannels FmtChans{}; - DevFmtType FmtType{}; - ALboolean IsHeadphones{AL_FALSE}; - ALsizei mAmbiOrder{0}; - /* For DevFmtAmbi* output only, specifies the channel order and - * normalization. - */ - AmbiLayout mAmbiLayout{AmbiLayout::Default}; - AmbiNorm mAmbiScale{AmbiNorm::Default}; - - ALCenum LimiterState{ALC_DONT_CARE_SOFT}; - - std::string DeviceName; - - // Device flags - al::bitfield Flags{}; - - std::string HrtfName; - al::vector HrtfList; - ALCenum HrtfStatus{ALC_FALSE}; - - std::atomic LastError{ALC_NO_ERROR}; - - // Maximum number of sources that can be created - ALuint SourcesMax{}; - // Maximum number of slots that can be created - ALuint AuxiliaryEffectSlotMax{}; - - ALCuint NumMonoSources{}; - ALCuint NumStereoSources{}; - ALsizei NumAuxSends{}; - - // Map of Buffers for this device - std::mutex BufferLock; - al::vector BufferList; - - // Map of Effects for this device - std::mutex EffectLock; - al::vector EffectList; - - // Map of Filters for this device - std::mutex FilterLock; - al::vector FilterList; - - /* Rendering mode. */ - RenderMode mRenderMode{NormalRender}; - - /* The average speaker distance as determined by the ambdec configuration, - * HRTF data set, or the NFC-HOA reference delay. Only used for NFC. - */ - ALfloat AvgSpeakerDist{0.0f}; - - ALuint SamplesDone{0u}; - std::chrono::nanoseconds ClockBase{0}; - std::chrono::nanoseconds FixedLatency{0}; - - /* Temp storage used for mixer processing. */ - alignas(16) ALfloat SourceData[BUFFERSIZE + MAX_RESAMPLE_PADDING*2]; - alignas(16) ALfloat ResampledData[BUFFERSIZE]; - alignas(16) ALfloat FilteredData[BUFFERSIZE]; - union { - alignas(16) ALfloat HrtfSourceData[BUFFERSIZE + HRTF_HISTORY_LENGTH]; - alignas(16) ALfloat NfcSampleData[BUFFERSIZE]; - }; - alignas(16) float2 HrtfAccumData[BUFFERSIZE + HRIR_LENGTH]; - - /* Mixing buffer used by the Dry mix and Real output. */ - al::vector MixBuffer; - - /* The "dry" path corresponds to the main output. */ - MixParams Dry; - ALuint NumChannelsPerOrder[MAX_AMBI_ORDER+1]{}; - - /* "Real" output, which will be written to the device buffer. May alias the - * dry buffer. - */ - RealMixParams RealOut; - - /* HRTF state and info */ - std::unique_ptr mHrtfState; - HrtfEntry *mHrtf{nullptr}; - - /* Ambisonic-to-UHJ encoder */ - std::unique_ptr Uhj_Encoder; - - /* Ambisonic decoder for speakers */ - std::unique_ptr AmbiDecoder; - - /* Stereo-to-binaural filter */ - std::unique_ptr Bs2b; - - POSTPROCESS PostProcess{}; - - std::unique_ptr Stablizer; - - std::unique_ptr Limiter; - - /* Delay buffers used to compensate for speaker distances. */ - DistanceComp ChannelDelay; - - /* Dithering control. */ - ALfloat DitherDepth{0.0f}; - ALuint DitherSeed{0u}; - - /* Running count of the mixer invocations, in 31.1 fixed point. This - * actually increments *twice* when mixing, first at the start and then at - * the end, so the bottom bit indicates if the device is currently mixing - * and the upper bits indicates how many mixes have been done. - */ - RefCount MixCount{0u}; - - // Contexts created on this device - std::atomic*> mContexts{nullptr}; - - /* This lock protects the device state (format, update size, etc) from - * being from being changed in multiple threads, or being accessed while - * being changed. It's also used to serialize calls to the backend. - */ - std::mutex StateLock; - std::unique_ptr Backend; - - - ALCdevice(DeviceType type); - ALCdevice(const ALCdevice&) = delete; - ALCdevice& operator=(const ALCdevice&) = delete; - ~ALCdevice(); - - ALsizei bytesFromFmt() const noexcept { return BytesFromDevFmt(FmtType); } - ALsizei channelsFromFmt() const noexcept { return ChannelsFromDevFmt(FmtChans, mAmbiOrder); } - ALsizei frameSizeFromFmt() const noexcept { return bytesFromFmt() * channelsFromFmt(); } - - DEF_NEWDEL(ALCdevice) -}; - -/* Must be less than 15 characters (16 including terminating null) for - * compatibility with pthread_setname_np limitations. */ -#define MIXER_THREAD_NAME "alsoft-mixer" - -#define RECORD_THREAD_NAME "alsoft-record" - - -enum { - /* End event thread processing. */ - EventType_KillThread = 0, - - /* User event types. */ - EventType_SourceStateChange = 1<<0, - EventType_BufferCompleted = 1<<1, - EventType_Error = 1<<2, - EventType_Performance = 1<<3, - EventType_Deprecated = 1<<4, - EventType_Disconnected = 1<<5, - - /* Internal events. */ - EventType_ReleaseEffectState = 65536, -}; - -struct AsyncEvent { - unsigned int EnumType{0u}; - union { - char dummy; - struct { - ALuint id; - ALenum state; - } srcstate; - struct { - ALuint id; - ALsizei count; - } bufcomp; - struct { - ALenum type; - ALuint id; - ALuint param; - ALchar msg[1008]; - } user; - EffectState *mEffectState; - } u{}; - - AsyncEvent() noexcept = default; - constexpr AsyncEvent(unsigned int type) noexcept : EnumType{type} { } -}; - - -void AllocateVoices(ALCcontext *context, size_t num_voices); - - -extern ALint RTPrioLevel; -void SetRTPriority(void); - -void SetDefaultChannelOrder(ALCdevice *device); -void SetDefaultWFXChannelOrder(ALCdevice *device); - -const ALCchar *DevFmtTypeString(DevFmtType type) noexcept; -const ALCchar *DevFmtChannelsString(DevFmtChannels chans) noexcept; - -/** - * GetChannelIdxByName - * - * Returns the index for the given channel name (e.g. FrontCenter), or -1 if it - * doesn't exist. - */ -inline ALint GetChannelIdxByName(const RealMixParams &real, Channel chan) noexcept -{ return real.ChannelIndex[chan]; } - - -void StartEventThrd(ALCcontext *ctx); -void StopEventThrd(ALCcontext *ctx); - - -al::vector SearchDataFiles(const char *match, const char *subdir); - -#endif diff --git a/Alc/alconfig.cpp b/Alc/alconfig.cpp deleted file mode 100644 index b246a91d..00000000 --- a/Alc/alconfig.cpp +++ /dev/null @@ -1,545 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * 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 "alconfig.h" - -#include -#include -#include -#ifdef _WIN32_IE -#include -#include -#endif -#ifdef __APPLE__ -#include -#endif - -#include -#include -#include - -#include "alcmain.h" -#include "logging.h" -#include "compat.h" - - -namespace { - -struct ConfigEntry { - std::string key; - std::string value; -}; -al::vector ConfOpts; - - -std::string &lstrip(std::string &line) -{ - size_t pos{0}; - while(pos < line.length() && std::isspace(line[pos])) - ++pos; - line.erase(0, pos); - return line; -} - -bool readline(std::istream &f, std::string &output) -{ - while(f.good() && f.peek() == '\n') - f.ignore(); - - return std::getline(f, output) && !output.empty(); -} - -std:: string expdup(const char *str) -{ - std::string output; - - while(*str != '\0') - { - const char *addstr; - size_t addstrlen; - - if(str[0] != '$') - { - const char *next = std::strchr(str, '$'); - addstr = str; - addstrlen = next ? static_cast(next-str) : std::strlen(str); - - str += addstrlen; - } - else - { - str++; - if(*str == '$') - { - const char *next = std::strchr(str+1, '$'); - addstr = str; - addstrlen = next ? static_cast(next-str) : std::strlen(str); - - str += addstrlen; - } - else - { - bool hasbraces{(*str == '{')}; - if(hasbraces) str++; - - std::string envname; - while((std::isalnum(*str) || *str == '_')) - envname += *(str++); - - if(hasbraces && *str != '}') - continue; - - if(hasbraces) str++; - if((addstr=std::getenv(envname.c_str())) == nullptr) - continue; - addstrlen = std::strlen(addstr); - } - } - if(addstrlen == 0) - continue; - - output.append(addstr, addstrlen); - } - - return output; -} - -void LoadConfigFromFile(std::istream &f) -{ - std::string curSection; - std::string buffer; - - while(readline(f, buffer)) - { - while(!buffer.empty() && std::isspace(buffer.back())) - buffer.pop_back(); - if(lstrip(buffer).empty()) - continue; - - buffer.push_back(0); - char *line{&buffer[0]}; - - if(line[0] == '[') - { - char *section = line+1; - char *endsection; - - endsection = std::strchr(section, ']'); - if(!endsection || section == endsection) - { - ERR("config parse error: bad line \"%s\"\n", line); - continue; - } - if(endsection[1] != 0) - { - char *end = endsection+1; - while(std::isspace(*end)) - ++end; - if(*end != 0 && *end != '#') - { - ERR("config parse error: bad line \"%s\"\n", line); - continue; - } - } - *endsection = 0; - - curSection.clear(); - if(strcasecmp(section, "general") != 0) - { - do { - char *nextp = std::strchr(section, '%'); - if(!nextp) - { - curSection += section; - break; - } - - curSection.append(section, nextp); - section = nextp; - - if(((section[1] >= '0' && section[1] <= '9') || - (section[1] >= 'a' && section[1] <= 'f') || - (section[1] >= 'A' && section[1] <= 'F')) && - ((section[2] >= '0' && section[2] <= '9') || - (section[2] >= 'a' && section[2] <= 'f') || - (section[2] >= 'A' && section[2] <= 'F'))) - { - unsigned char b = 0; - if(section[1] >= '0' && section[1] <= '9') - b = (section[1]-'0') << 4; - else if(section[1] >= 'a' && section[1] <= 'f') - b = (section[1]-'a'+0xa) << 4; - else if(section[1] >= 'A' && section[1] <= 'F') - b = (section[1]-'A'+0x0a) << 4; - if(section[2] >= '0' && section[2] <= '9') - b |= (section[2]-'0'); - else if(section[2] >= 'a' && section[2] <= 'f') - b |= (section[2]-'a'+0xa); - else if(section[2] >= 'A' && section[2] <= 'F') - b |= (section[2]-'A'+0x0a); - curSection += static_cast(b); - section += 3; - } - else if(section[1] == '%') - { - curSection += '%'; - section += 2; - } - else - { - curSection += '%'; - section += 1; - } - } while(*section != 0); - } - - continue; - } - - char *comment{std::strchr(line, '#')}; - if(comment) *(comment++) = 0; - if(!line[0]) continue; - - char key[256]{}; - char value[256]{}; - if(std::sscanf(line, "%255[^=] = \"%255[^\"]\"", key, value) == 2 || - std::sscanf(line, "%255[^=] = '%255[^\']'", key, value) == 2 || - std::sscanf(line, "%255[^=] = %255[^\n]", key, value) == 2) - { - /* sscanf doesn't handle '' or "" as empty values, so clip it - * manually. */ - if(std::strcmp(value, "\"\"") == 0 || std::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; - } - - std::string fullKey; - if(!curSection.empty()) - { - fullKey += curSection; - fullKey += '/'; - } - fullKey += key; - while(!fullKey.empty() && std::isspace(fullKey.back())) - fullKey.pop_back(); - - /* Check if we already have this option set */ - auto ent = std::find_if(ConfOpts.begin(), ConfOpts.end(), - [&fullKey](const ConfigEntry &entry) -> bool - { return entry.key == fullKey; } - ); - if(ent != ConfOpts.end()) - ent->value = expdup(value); - else - { - ConfOpts.emplace_back(ConfigEntry{std::move(fullKey), expdup(value)}); - ent = ConfOpts.end()-1; - } - - TRACE("found '%s' = '%s'\n", ent->key.c_str(), ent->value.c_str()); - } - ConfOpts.shrink_to_fit(); -} - -} // namespace - - -#ifdef _WIN32 -void ReadALConfig() -{ - WCHAR buffer[MAX_PATH]; - if(SHGetSpecialFolderPathW(nullptr, buffer, CSIDL_APPDATA, FALSE) != FALSE) - { - std::string filepath{wstr_to_utf8(buffer)}; - filepath += "\\alsoft.ini"; - - TRACE("Loading config %s...\n", filepath.c_str()); - al::ifstream f{filepath}; - if(f.is_open()) - LoadConfigFromFile(f); - } - - std::string ppath{GetProcBinary().path}; - if(!ppath.empty()) - { - ppath += "\\alsoft.ini"; - TRACE("Loading config %s...\n", ppath.c_str()); - al::ifstream f{ppath}; - if(f.is_open()) - LoadConfigFromFile(f); - } - - const WCHAR *str{_wgetenv(L"ALSOFT_CONF")}; - if(str != nullptr && *str) - { - std::string filepath{wstr_to_utf8(str)}; - - TRACE("Loading config %s...\n", filepath.c_str()); - al::ifstream f{filepath}; - if(f.is_open()) - LoadConfigFromFile(f); - } -} -#else -void ReadALConfig() -{ - const char *str{"/etc/openal/alsoft.conf"}; - - TRACE("Loading config %s...\n", str); - al::ifstream f{str}; - if(f.is_open()) - LoadConfigFromFile(f); - f.close(); - - if(!(str=getenv("XDG_CONFIG_DIRS")) || str[0] == 0) - str = "/etc/xdg"; - std::string confpaths = str; - /* Go through the list in reverse, since "the order of base directories - * denotes their importance; the first directory listed is the most - * important". Ergo, we need to load the settings from the later dirs - * first so that the settings in the earlier dirs override them. - */ - std::string fname; - while(!confpaths.empty()) - { - auto next = confpaths.find_last_of(':'); - if(next < confpaths.length()) - { - fname = confpaths.substr(next+1); - confpaths.erase(next); - } - else - { - fname = confpaths; - confpaths.clear(); - } - - if(fname.empty() || fname.front() != '/') - WARN("Ignoring XDG config dir: %s\n", fname.c_str()); - else - { - if(fname.back() != '/') fname += "/alsoft.conf"; - else fname += "alsoft.conf"; - - TRACE("Loading config %s...\n", fname.c_str()); - al::ifstream f{fname}; - if(f.is_open()) - LoadConfigFromFile(f); - } - fname.clear(); - } - -#ifdef __APPLE__ - CFBundleRef mainBundle = CFBundleGetMainBundle(); - if(mainBundle) - { - unsigned char fileName[PATH_MAX]; - CFURLRef configURL; - - if((configURL=CFBundleCopyResourceURL(mainBundle, CFSTR(".alsoftrc"), CFSTR(""), nullptr)) && - CFURLGetFileSystemRepresentation(configURL, true, fileName, sizeof(fileName))) - { - al::ifstream f{reinterpret_cast(fileName)}; - if(f.is_open()) - LoadConfigFromFile(f); - } - } -#endif - - if((str=getenv("HOME")) != nullptr && *str) - { - fname = str; - if(fname.back() != '/') fname += "/.alsoftrc"; - else fname += ".alsoftrc"; - - TRACE("Loading config %s...\n", fname.c_str()); - al::ifstream f{fname}; - if(f.is_open()) - LoadConfigFromFile(f); - } - - if((str=getenv("XDG_CONFIG_HOME")) != nullptr && str[0] != 0) - { - fname = str; - if(fname.back() != '/') fname += "/alsoft.conf"; - else fname += "alsoft.conf"; - } - else - { - fname.clear(); - if((str=getenv("HOME")) != nullptr && str[0] != 0) - { - fname = str; - if(fname.back() != '/') fname += "/.config/alsoft.conf"; - else fname += ".config/alsoft.conf"; - } - } - if(!fname.empty()) - { - TRACE("Loading config %s...\n", fname.c_str()); - al::ifstream f{fname}; - if(f.is_open()) - LoadConfigFromFile(f); - } - - std::string ppath{GetProcBinary().path}; - if(!ppath.empty()) - { - if(ppath.back() != '/') ppath += "/alsoft.conf"; - else ppath += "alsoft.conf"; - - TRACE("Loading config %s...\n", ppath.c_str()); - al::ifstream f{ppath}; - if(f.is_open()) - LoadConfigFromFile(f); - } - - if((str=getenv("ALSOFT_CONF")) != nullptr && *str) - { - TRACE("Loading config %s...\n", str); - al::ifstream f{str}; - if(f.is_open()) - LoadConfigFromFile(f); - } -} -#endif - -const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def) -{ - if(!keyName) - return def; - - std::string key; - if(blockName && strcasecmp(blockName, "general") != 0) - { - key = blockName; - if(devName) - { - key += '/'; - key += devName; - } - key += '/'; - key += keyName; - } - else - { - if(devName) - { - key = devName; - key += '/'; - } - key += keyName; - } - - auto iter = std::find_if(ConfOpts.cbegin(), ConfOpts.cend(), - [&key](const ConfigEntry &entry) -> bool - { return entry.key == key; } - ); - if(iter != ConfOpts.cend()) - { - TRACE("Found %s = \"%s\"\n", key.c_str(), iter->value.c_str()); - if(!iter->value.empty()) - return iter->value.c_str(); - return def; - } - - if(!devName) - { - TRACE("Key %s not found\n", key.c_str()); - return def; - } - return GetConfigValue(nullptr, blockName, keyName, def); -} - -int ConfigValueExists(const char *devName, const char *blockName, const char *keyName) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - return val[0] != 0; -} - -al::optional ConfigValueStr(const char *devName, const char *blockName, const char *keyName) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return al::nullopt; - - return al::make_optional(val); -} - -al::optional ConfigValueInt(const char *devName, const char *blockName, const char *keyName) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return al::nullopt; - - return al::make_optional(static_cast(std::strtol(val, nullptr, 0))); -} - -al::optional ConfigValueUInt(const char *devName, const char *blockName, const char *keyName) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return al::nullopt; - - return al::make_optional(static_cast(std::strtoul(val, nullptr, 0))); -} - -al::optional ConfigValueFloat(const char *devName, const char *blockName, const char *keyName) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return al::nullopt; - - return al::make_optional(std::strtof(val, nullptr)); -} - -al::optional ConfigValueBool(const char *devName, const char *blockName, const char *keyName) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return al::nullopt; - - return al::make_optional( - strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || - strcasecmp(val, "on") == 0 || atoi(val) != 0); -} - -int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - - if(!val[0]) return def != 0; - return (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || - strcasecmp(val, "on") == 0 || atoi(val) != 0); -} diff --git a/Alc/alconfig.h b/Alc/alconfig.h deleted file mode 100644 index ffc7adad..00000000 --- a/Alc/alconfig.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef ALCONFIG_H -#define ALCONFIG_H - -#include - -#include "aloptional.h" - -void ReadALConfig(); - -int ConfigValueExists(const char *devName, const char *blockName, const char *keyName); -const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def); -int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def); - -al::optional ConfigValueStr(const char *devName, const char *blockName, const char *keyName); -al::optional ConfigValueInt(const char *devName, const char *blockName, const char *keyName); -al::optional ConfigValueUInt(const char *devName, const char *blockName, const char *keyName); -al::optional ConfigValueFloat(const char *devName, const char *blockName, const char *keyName); -al::optional ConfigValueBool(const char *devName, const char *blockName, const char *keyName); - -#endif /* ALCONFIG_H */ diff --git a/Alc/alcontext.h b/Alc/alcontext.h deleted file mode 100644 index cf956079..00000000 --- a/Alc/alcontext.h +++ /dev/null @@ -1,217 +0,0 @@ -#ifndef ALCONTEXT_H -#define ALCONTEXT_H - -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" -#include "inprogext.h" - -#include "atomic.h" -#include "vector.h" -#include "threads.h" -#include "almalloc.h" -#include "alnumeric.h" - -#include "alListener.h" -#include "alu.h" - - -struct ALsource; -struct ALeffectslot; -struct ALcontextProps; -struct ALlistenerProps; -struct ALvoiceProps; -struct ALeffectslotProps; -struct RingBuffer; - -enum class DistanceModel { - InverseClamped = AL_INVERSE_DISTANCE_CLAMPED, - LinearClamped = AL_LINEAR_DISTANCE_CLAMPED, - ExponentClamped = AL_EXPONENT_DISTANCE_CLAMPED, - Inverse = AL_INVERSE_DISTANCE, - Linear = AL_LINEAR_DISTANCE, - Exponent = AL_EXPONENT_DISTANCE, - Disable = AL_NONE, - - Default = InverseClamped -}; - -struct SourceSubList { - uint64_t FreeMask{~0_u64}; - ALsource *Sources{nullptr}; /* 64 */ - - SourceSubList() noexcept = default; - SourceSubList(const SourceSubList&) = delete; - SourceSubList(SourceSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Sources{rhs.Sources} - { rhs.FreeMask = ~0_u64; rhs.Sources = nullptr; } - ~SourceSubList(); - - SourceSubList& operator=(const SourceSubList&) = delete; - SourceSubList& operator=(SourceSubList&& rhs) noexcept - { std::swap(FreeMask, rhs.FreeMask); std::swap(Sources, rhs.Sources); return *this; } -}; - -struct EffectSlotSubList { - uint64_t FreeMask{~0_u64}; - ALeffectslot *EffectSlots{nullptr}; /* 64 */ - - EffectSlotSubList() noexcept = default; - EffectSlotSubList(const EffectSlotSubList&) = delete; - EffectSlotSubList(EffectSlotSubList&& rhs) noexcept - : FreeMask{rhs.FreeMask}, EffectSlots{rhs.EffectSlots} - { rhs.FreeMask = ~0_u64; rhs.EffectSlots = nullptr; } - ~EffectSlotSubList(); - - EffectSlotSubList& operator=(const EffectSlotSubList&) = delete; - EffectSlotSubList& operator=(EffectSlotSubList&& rhs) noexcept - { std::swap(FreeMask, rhs.FreeMask); std::swap(EffectSlots, rhs.EffectSlots); return *this; } -}; - -struct ALCcontext { - RefCount ref{1u}; - - al::vector SourceList; - ALuint NumSources{0}; - std::mutex SourceLock; - - al::vector EffectSlotList; - ALuint NumEffectSlots{0u}; - std::mutex EffectSlotLock; - - std::atomic LastError{AL_NO_ERROR}; - - DistanceModel mDistanceModel{DistanceModel::Default}; - ALboolean SourceDistanceModel{AL_FALSE}; - - ALfloat DopplerFactor{1.0f}; - ALfloat DopplerVelocity{1.0f}; - ALfloat SpeedOfSound{}; - ALfloat MetersPerUnit{1.0f}; - - std::atomic_flag PropsClean; - std::atomic DeferUpdates{false}; - - std::mutex PropLock; - - /* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit - * indicates if updates are currently happening). - */ - RefCount UpdateCount{0u}; - std::atomic HoldUpdates{false}; - - ALfloat GainBoost{1.0f}; - - std::atomic Update{nullptr}; - - /* Linked lists of unused property containers, free to use for future - * updates. - */ - std::atomic FreeContextProps{nullptr}; - std::atomic FreeListenerProps{nullptr}; - std::atomic FreeVoiceProps{nullptr}; - std::atomic FreeEffectslotProps{nullptr}; - - std::unique_ptr> Voices{nullptr}; - std::atomic VoiceCount{0u}; - - using ALeffectslotArray = al::FlexArray; - std::atomic ActiveAuxSlots{nullptr}; - - std::thread EventThread; - al::semaphore EventSem; - std::unique_ptr AsyncEvents; - std::atomic EnabledEvts{0u}; - std::mutex EventCbLock; - ALEVENTPROCSOFT EventCb{}; - void *EventParam{nullptr}; - - /* Default effect slot */ - std::unique_ptr DefaultSlot; - - ALCdevice *const Device; - const ALCchar *ExtensionList{nullptr}; - - ALlistener Listener{}; - - - ALCcontext(ALCdevice *device); - ALCcontext(const ALCcontext&) = delete; - ALCcontext& operator=(const ALCcontext&) = delete; - ~ALCcontext(); - - DEF_NEWDEL(ALCcontext) -}; - -void ALCcontext_DecRef(ALCcontext *context); - -void UpdateContextProps(ALCcontext *context); - -void ALCcontext_DeferUpdates(ALCcontext *context); -void ALCcontext_ProcessUpdates(ALCcontext *context); - - -/* Simple RAII context reference. Takes the reference of the provided - * ALCcontext, and decrements it when leaving scope. Movable (transfer - * reference) but not copyable (no new references). - */ -class ContextRef { - ALCcontext *mCtx{nullptr}; - - void reset() noexcept - { - if(mCtx) - ALCcontext_DecRef(mCtx); - mCtx = nullptr; - } - -public: - ContextRef() noexcept = default; - ContextRef(ContextRef&& rhs) noexcept : mCtx{rhs.mCtx} - { rhs.mCtx = nullptr; } - explicit ContextRef(ALCcontext *ctx) noexcept : mCtx(ctx) { } - ~ContextRef() { reset(); } - - ContextRef& operator=(const ContextRef&) = delete; - ContextRef& operator=(ContextRef&& rhs) noexcept - { std::swap(mCtx, rhs.mCtx); return *this; } - - operator bool() const noexcept { return mCtx != nullptr; } - - ALCcontext* operator->() const noexcept { return mCtx; } - ALCcontext* get() const noexcept { return mCtx; } - - ALCcontext* release() noexcept - { - ALCcontext *ret{mCtx}; - mCtx = nullptr; - return ret; - } -}; - -inline bool operator==(const ContextRef &lhs, const ALCcontext *rhs) noexcept -{ return lhs.get() == rhs; } -inline bool operator!=(const ContextRef &lhs, const ALCcontext *rhs) noexcept -{ return !(lhs == rhs); } -inline bool operator<(const ContextRef &lhs, const ALCcontext *rhs) noexcept -{ return lhs.get() < rhs; } - -ContextRef GetContextRef(void); - - -struct ALcontextProps { - ALfloat DopplerFactor; - ALfloat DopplerVelocity; - ALfloat SpeedOfSound; - ALboolean SourceDistanceModel; - DistanceModel mDistanceModel; - ALfloat MetersPerUnit; - - std::atomic next; -}; - -#endif /* ALCONTEXT_H */ diff --git a/Alc/alu.cpp b/Alc/alu.cpp deleted file mode 100644 index cc1a5a98..00000000 --- a/Alc/alu.cpp +++ /dev/null @@ -1,1798 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "alu.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/efx.h" - -#include "alAuxEffectSlot.h" -#include "alBuffer.h" -#include "alcmain.h" -#include "alEffect.h" -#include "alListener.h" -#include "alcontext.h" -#include "almalloc.h" -#include "alnumeric.h" -#include "alspan.h" -#include "ambidefs.h" -#include "atomic.h" -#include "bformatdec.h" -#include "bs2b.h" -#include "cpu_caps.h" -#include "effects/base.h" -#include "filters/biquad.h" -#include "filters/nfc.h" -#include "filters/splitter.h" -#include "fpu_modes.h" -#include "hrtf.h" -#include "inprogext.h" -#include "mastering.h" -#include "math_defs.h" -#include "mixer/defs.h" -#include "opthelpers.h" -#include "ringbuffer.h" -#include "threads.h" -#include "uhjfilter.h" -#include "vecmat.h" -#include "vector.h" - -#include "bsinc_inc.h" - - -namespace { - -using namespace std::placeholders; - -ALfloat InitConeScale() -{ - ALfloat ret{1.0f}; - const char *str{getenv("__ALSOFT_HALF_ANGLE_CONES")}; - if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) - ret *= 0.5f; - return ret; -} - -ALfloat InitZScale() -{ - ALfloat ret{1.0f}; - const char *str{getenv("__ALSOFT_REVERSE_Z")}; - if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) - ret *= -1.0f; - return ret; -} - -ALboolean InitReverbSOS() -{ - ALboolean ret{AL_FALSE}; - const char *str{getenv("__ALSOFT_REVERB_IGNORES_SOUND_SPEED")}; - if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) - ret = AL_TRUE; - return ret; -} - -} // namespace - -/* Cone scalar */ -const ALfloat ConeScale{InitConeScale()}; - -/* Localized Z scalar for mono sources */ -const ALfloat ZScale{InitZScale()}; - -/* Force default speed of sound for distance-related reverb decay. */ -const ALboolean OverrideReverbSpeedOfSound{InitReverbSOS()}; - - -namespace { - -void ClearArray(ALfloat (&f)[MAX_OUTPUT_CHANNELS]) -{ - std::fill(std::begin(f), std::end(f), 0.0f); -} - -struct ChanMap { - Channel channel; - ALfloat angle; - ALfloat elevation; -}; - -HrtfDirectMixerFunc MixDirectHrtf = MixDirectHrtf_; -inline HrtfDirectMixerFunc SelectHrtfMixer(void) -{ -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return MixDirectHrtf_; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return MixDirectHrtf_; -#endif - - return MixDirectHrtf_; -} - -} // namespace - -void aluInit(void) -{ - MixDirectHrtf = SelectHrtfMixer(); -} - - -void ProcessHrtf(ALCdevice *device, const ALsizei SamplesToDo) -{ - /* HRTF is stereo output only. */ - const int lidx{device->RealOut.ChannelIndex[FrontLeft]}; - const int ridx{device->RealOut.ChannelIndex[FrontRight]}; - ASSUME(lidx >= 0 && ridx >= 0); - - DirectHrtfState *state{device->mHrtfState.get()}; - MixDirectHrtf(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], device->Dry.Buffer, - device->HrtfAccumData, state, SamplesToDo); -} - -void ProcessAmbiDec(ALCdevice *device, const ALsizei SamplesToDo) -{ - BFormatDec *ambidec{device->AmbiDecoder.get()}; - ambidec->process(device->RealOut.Buffer, device->Dry.Buffer.data(), SamplesToDo); -} - -void ProcessUhj(ALCdevice *device, const ALsizei SamplesToDo) -{ - /* UHJ is stereo output only. */ - const int lidx{device->RealOut.ChannelIndex[FrontLeft]}; - const int ridx{device->RealOut.ChannelIndex[FrontRight]}; - ASSUME(lidx >= 0 && ridx >= 0); - - /* Encode to stereo-compatible 2-channel UHJ output. */ - Uhj2Encoder *uhj2enc{device->Uhj_Encoder.get()}; - uhj2enc->encode(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], - device->Dry.Buffer.data(), SamplesToDo); -} - -void ProcessBs2b(ALCdevice *device, const ALsizei SamplesToDo) -{ - /* First, decode the ambisonic mix to the "real" output. */ - BFormatDec *ambidec{device->AmbiDecoder.get()}; - ambidec->process(device->RealOut.Buffer, device->Dry.Buffer.data(), SamplesToDo); - - /* BS2B is stereo output only. */ - const int lidx{device->RealOut.ChannelIndex[FrontLeft]}; - const int ridx{device->RealOut.ChannelIndex[FrontRight]}; - ASSUME(lidx >= 0 && ridx >= 0); - - /* Now apply the BS2B binaural/crossfeed filter. */ - bs2b_cross_feed(device->Bs2b.get(), device->RealOut.Buffer[lidx].data(), - device->RealOut.Buffer[ridx].data(), SamplesToDo); -} - - -/* Prepares the interpolator for a given rate (determined by increment). - * - * With a bit of work, and a trade of memory for CPU cost, this could be - * modified for use with an interpolated increment for buttery-smooth pitch - * changes. - */ -void BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *table) -{ - ALsizei si{BSINC_SCALE_COUNT - 1}; - ALfloat sf{0.0f}; - - if(increment > FRACTIONONE) - { - sf = static_castFRACTIONONE / increment; - sf = maxf(0.0f, (BSINC_SCALE_COUNT-1) * (sf-table->scaleBase) * table->scaleRange); - si = float2int(sf); - /* The interpolation factor is fit to this diagonally-symmetric curve - * to reduce the transition ripple caused by interpolating different - * scales of the sinc function. - */ - sf = 1.0f - std::cos(std::asin(sf - si)); - } - - state->sf = sf; - state->m = table->m[si]; - state->l = (state->m/2) - 1; - state->filter = table->Tab + table->filterOffset[si]; -} - - -namespace { - -/* This RNG method was created based on the math found in opusdec. It's quick, - * and starting with a seed value of 22222, is suitable for generating - * whitenoise. - */ -inline ALuint dither_rng(ALuint *seed) noexcept -{ - *seed = (*seed * 96314165) + 907633515; - return *seed; -} - - -inline alu::Vector aluCrossproduct(const alu::Vector &in1, const alu::Vector &in2) -{ - return alu::Vector{ - in1[1]*in2[2] - in1[2]*in2[1], - in1[2]*in2[0] - in1[0]*in2[2], - in1[0]*in2[1] - in1[1]*in2[0], - 0.0f - }; -} - -inline ALfloat aluDotproduct(const alu::Vector &vec1, const alu::Vector &vec2) -{ - return vec1[0]*vec2[0] + vec1[1]*vec2[1] + vec1[2]*vec2[2]; -} - - -alu::Vector operator*(const alu::Matrix &mtx, const alu::Vector &vec) noexcept -{ - return alu::Vector{ - vec[0]*mtx[0][0] + vec[1]*mtx[1][0] + vec[2]*mtx[2][0] + vec[3]*mtx[3][0], - vec[0]*mtx[0][1] + vec[1]*mtx[1][1] + vec[2]*mtx[2][1] + vec[3]*mtx[3][1], - vec[0]*mtx[0][2] + vec[1]*mtx[1][2] + vec[2]*mtx[2][2] + vec[3]*mtx[3][2], - vec[0]*mtx[0][3] + vec[1]*mtx[1][3] + vec[2]*mtx[2][3] + vec[3]*mtx[3][3] - }; -} - - -bool CalcContextParams(ALCcontext *Context) -{ - ALcontextProps *props{Context->Update.exchange(nullptr, std::memory_order_acq_rel)}; - if(!props) return false; - - ALlistener &Listener = Context->Listener; - Listener.Params.MetersPerUnit = props->MetersPerUnit; - - Listener.Params.DopplerFactor = props->DopplerFactor; - Listener.Params.SpeedOfSound = props->SpeedOfSound * props->DopplerVelocity; - if(!OverrideReverbSpeedOfSound) - Listener.Params.ReverbSpeedOfSound = Listener.Params.SpeedOfSound * - Listener.Params.MetersPerUnit; - - Listener.Params.SourceDistanceModel = props->SourceDistanceModel; - Listener.Params.mDistanceModel = props->mDistanceModel; - - AtomicReplaceHead(Context->FreeContextProps, props); - return true; -} - -bool CalcListenerParams(ALCcontext *Context) -{ - ALlistener &Listener = Context->Listener; - - ALlistenerProps *props{Listener.Update.exchange(nullptr, std::memory_order_acq_rel)}; - if(!props) return false; - - /* AT then UP */ - alu::Vector N{props->OrientAt[0], props->OrientAt[1], props->OrientAt[2], 0.0f}; - N.normalize(); - alu::Vector V{props->OrientUp[0], props->OrientUp[1], props->OrientUp[2], 0.0f}; - V.normalize(); - /* Build and normalize right-vector */ - alu::Vector U{aluCrossproduct(N, V)}; - U.normalize(); - - Listener.Params.Matrix = alu::Matrix{ - U[0], V[0], -N[0], 0.0f, - U[1], V[1], -N[1], 0.0f, - U[2], V[2], -N[2], 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - }; - - const alu::Vector P{Listener.Params.Matrix * - alu::Vector{props->Position[0], props->Position[1], props->Position[2], 1.0f}}; - Listener.Params.Matrix.setRow(3, -P[0], -P[1], -P[2], 1.0f); - - const alu::Vector vel{props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f}; - Listener.Params.Velocity = Listener.Params.Matrix * vel; - - Listener.Params.Gain = props->Gain * Context->GainBoost; - - AtomicReplaceHead(Context->FreeListenerProps, props); - return true; -} - -bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) -{ - ALeffectslotProps *props{slot->Update.exchange(nullptr, std::memory_order_acq_rel)}; - if(!props && !force) return false; - - EffectState *state; - if(!props) - state = slot->Params.mEffectState; - else - { - slot->Params.Gain = props->Gain; - slot->Params.AuxSendAuto = props->AuxSendAuto; - slot->Params.Target = props->Target; - slot->Params.EffectType = props->Type; - slot->Params.mEffectProps = props->Props; - if(IsReverbEffect(props->Type)) - { - slot->Params.RoomRolloff = props->Props.Reverb.RoomRolloffFactor; - slot->Params.DecayTime = props->Props.Reverb.DecayTime; - slot->Params.DecayLFRatio = props->Props.Reverb.DecayLFRatio; - slot->Params.DecayHFRatio = props->Props.Reverb.DecayHFRatio; - slot->Params.DecayHFLimit = props->Props.Reverb.DecayHFLimit; - slot->Params.AirAbsorptionGainHF = props->Props.Reverb.AirAbsorptionGainHF; - } - else - { - slot->Params.RoomRolloff = 0.0f; - slot->Params.DecayTime = 0.0f; - slot->Params.DecayLFRatio = 0.0f; - slot->Params.DecayHFRatio = 0.0f; - slot->Params.DecayHFLimit = AL_FALSE; - slot->Params.AirAbsorptionGainHF = 1.0f; - } - - state = props->State; - props->State = nullptr; - EffectState *oldstate{slot->Params.mEffectState}; - slot->Params.mEffectState = state; - - /* Manually decrement the old effect state's refcount if it's greater - * than 1. We need to be a bit clever here to avoid the refcount - * reaching 0 since it can't be deleted in the mixer. - */ - ALuint oldval{oldstate->mRef.load(std::memory_order_acquire)}; - while(oldval > 1 && !oldstate->mRef.compare_exchange_weak(oldval, oldval-1, - std::memory_order_acq_rel, std::memory_order_acquire)) - { - /* oldval was updated with the current value on failure, so just - * try again. - */ - } - - if(oldval < 2) - { - /* Otherwise, if it would be deleted, send it off with a release - * event. - */ - RingBuffer *ring{context->AsyncEvents.get()}; - auto evt_vec = ring->getWriteVector(); - if(LIKELY(evt_vec.first.len > 0)) - { - AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_ReleaseEffectState}}; - evt->u.mEffectState = oldstate; - ring->writeAdvance(1); - context->EventSem.post(); - } - else - { - /* If writing the event failed, the queue was probably full. - * Store the old state in the property object where it can - * eventually be cleaned up sometime later (not ideal, but - * better than blocking or leaking). - */ - props->State = oldstate; - } - } - - AtomicReplaceHead(context->FreeEffectslotProps, props); - } - - EffectTarget output; - if(ALeffectslot *target{slot->Params.Target}) - output = EffectTarget{&target->Wet, nullptr}; - else - { - ALCdevice *device{context->Device}; - output = EffectTarget{&device->Dry, &device->RealOut}; - } - state->update(context, slot, &slot->Params.mEffectProps, output); - return true; -} - - -/* Scales the given azimuth toward the side (+/- pi/2 radians) for positions in - * front. - */ -inline float ScaleAzimuthFront(float azimuth, float scale) -{ - const ALfloat abs_azi{std::fabs(azimuth)}; - if(!(abs_azi > al::MathDefs::Pi()*0.5f)) - return minf(abs_azi*scale, al::MathDefs::Pi()*0.5f) * std::copysign(1.0f, azimuth); - return azimuth; -} - -void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypos, - const ALfloat zpos, const ALfloat Distance, const ALfloat Spread, const ALfloat DryGain, - const ALfloat DryGainHF, const ALfloat DryGainLF, const ALfloat (&WetGain)[MAX_SENDS], - const ALfloat (&WetGainLF)[MAX_SENDS], const ALfloat (&WetGainHF)[MAX_SENDS], - ALeffectslot *(&SendSlots)[MAX_SENDS], const ALvoicePropsBase *props, - const ALlistener &Listener, const ALCdevice *Device) -{ - static constexpr ChanMap MonoMap[1]{ - { FrontCenter, 0.0f, 0.0f } - }, RearMap[2]{ - { BackLeft, Deg2Rad(-150.0f), Deg2Rad(0.0f) }, - { BackRight, Deg2Rad( 150.0f), Deg2Rad(0.0f) } - }, QuadMap[4]{ - { FrontLeft, Deg2Rad( -45.0f), Deg2Rad(0.0f) }, - { FrontRight, Deg2Rad( 45.0f), Deg2Rad(0.0f) }, - { BackLeft, Deg2Rad(-135.0f), Deg2Rad(0.0f) }, - { BackRight, Deg2Rad( 135.0f), Deg2Rad(0.0f) } - }, X51Map[6]{ - { FrontLeft, Deg2Rad( -30.0f), Deg2Rad(0.0f) }, - { FrontRight, Deg2Rad( 30.0f), Deg2Rad(0.0f) }, - { FrontCenter, Deg2Rad( 0.0f), Deg2Rad(0.0f) }, - { LFE, 0.0f, 0.0f }, - { SideLeft, Deg2Rad(-110.0f), Deg2Rad(0.0f) }, - { SideRight, Deg2Rad( 110.0f), Deg2Rad(0.0f) } - }, X61Map[7]{ - { FrontLeft, Deg2Rad(-30.0f), Deg2Rad(0.0f) }, - { FrontRight, Deg2Rad( 30.0f), Deg2Rad(0.0f) }, - { FrontCenter, Deg2Rad( 0.0f), Deg2Rad(0.0f) }, - { LFE, 0.0f, 0.0f }, - { BackCenter, Deg2Rad(180.0f), Deg2Rad(0.0f) }, - { SideLeft, Deg2Rad(-90.0f), Deg2Rad(0.0f) }, - { SideRight, Deg2Rad( 90.0f), Deg2Rad(0.0f) } - }, X71Map[8]{ - { FrontLeft, Deg2Rad( -30.0f), Deg2Rad(0.0f) }, - { FrontRight, Deg2Rad( 30.0f), Deg2Rad(0.0f) }, - { FrontCenter, Deg2Rad( 0.0f), Deg2Rad(0.0f) }, - { LFE, 0.0f, 0.0f }, - { BackLeft, Deg2Rad(-150.0f), Deg2Rad(0.0f) }, - { BackRight, Deg2Rad( 150.0f), Deg2Rad(0.0f) }, - { SideLeft, Deg2Rad( -90.0f), Deg2Rad(0.0f) }, - { SideRight, Deg2Rad( 90.0f), Deg2Rad(0.0f) } - }; - - ChanMap StereoMap[2]{ - { FrontLeft, Deg2Rad(-30.0f), Deg2Rad(0.0f) }, - { FrontRight, Deg2Rad( 30.0f), Deg2Rad(0.0f) } - }; - - const auto Frequency = static_cast(Device->Frequency); - const ALsizei NumSends{Device->NumAuxSends}; - ASSUME(NumSends >= 0); - - bool DirectChannels{props->DirectChannels != AL_FALSE}; - const ChanMap *chans{nullptr}; - ALsizei num_channels{0}; - bool isbformat{false}; - ALfloat downmix_gain{1.0f}; - switch(voice->mFmtChannels) - { - case FmtMono: - chans = MonoMap; - num_channels = 1; - /* Mono buffers are never played direct. */ - DirectChannels = false; - break; - - case FmtStereo: - /* Convert counter-clockwise to clockwise. */ - StereoMap[0].angle = -props->StereoPan[0]; - StereoMap[1].angle = -props->StereoPan[1]; - - chans = StereoMap; - num_channels = 2; - downmix_gain = 1.0f / 2.0f; - break; - - case FmtRear: - chans = RearMap; - num_channels = 2; - downmix_gain = 1.0f / 2.0f; - break; - - case FmtQuad: - chans = QuadMap; - num_channels = 4; - downmix_gain = 1.0f / 4.0f; - break; - - case FmtX51: - chans = X51Map; - num_channels = 6; - /* NOTE: Excludes LFE. */ - downmix_gain = 1.0f / 5.0f; - break; - - case FmtX61: - chans = X61Map; - num_channels = 7; - /* NOTE: Excludes LFE. */ - downmix_gain = 1.0f / 6.0f; - break; - - case FmtX71: - chans = X71Map; - num_channels = 8; - /* NOTE: Excludes LFE. */ - downmix_gain = 1.0f / 7.0f; - break; - - case FmtBFormat2D: - num_channels = 3; - isbformat = true; - DirectChannels = false; - break; - - case FmtBFormat3D: - num_channels = 4; - isbformat = true; - DirectChannels = false; - break; - } - ASSUME(num_channels > 0); - - std::for_each(voice->mChans.begin(), voice->mChans.begin()+num_channels, - [NumSends](ALvoice::ChannelData &chandata) -> void - { - chandata.mDryParams.Hrtf.Target = HrtfFilter{}; - ClearArray(chandata.mDryParams.Gains.Target); - std::for_each(chandata.mWetParams.begin(), chandata.mWetParams.begin()+NumSends, - [](SendParams ¶ms) -> void { ClearArray(params.Gains.Target); }); - }); - - voice->mFlags &= ~(VOICE_HAS_HRTF | VOICE_HAS_NFC); - if(isbformat) - { - /* Special handling for B-Format sources. */ - - if(Distance > std::numeric_limits::epsilon()) - { - /* Panning a B-Format sound toward some direction is easy. Just pan - * the first (W) channel as a normal mono sound and silence the - * others. - */ - - if(Device->AvgSpeakerDist > 0.0f) - { - /* Clamp the distance for really close sources, to prevent - * excessive bass. - */ - const ALfloat mdist{maxf(Distance, Device->AvgSpeakerDist/4.0f)}; - const ALfloat w0{SPEEDOFSOUNDMETRESPERSEC / (mdist * Frequency)}; - - /* Only need to adjust the first channel of a B-Format source. */ - voice->mChans[0].mDryParams.NFCtrlFilter.adjust(w0); - - voice->mFlags |= VOICE_HAS_NFC; - } - - ALfloat coeffs[MAX_AMBI_CHANNELS]; - if(Device->mRenderMode != StereoPair) - CalcDirectionCoeffs({xpos, ypos, zpos}, Spread, coeffs); - else - { - /* Clamp Y, in case rounding errors caused it to end up outside - * of -1...+1. - */ - const ALfloat ev{std::asin(clampf(ypos, -1.0f, 1.0f))}; - /* Negate Z for right-handed coords with -Z in front. */ - const ALfloat az{std::atan2(xpos, -zpos)}; - - /* A scalar of 1.5 for plain stereo results in +/-60 degrees - * being moved to +/-90 degrees for direct right and left - * speaker responses. - */ - CalcAngleCoeffs(ScaleAzimuthFront(az, 1.5f), ev, Spread, coeffs); - } - - /* NOTE: W needs to be scaled due to FuMa normalization. */ - const ALfloat &scale0 = AmbiScale::FromFuMa[0]; - ComputePanGains(&Device->Dry, coeffs, DryGain*scale0, - voice->mChans[0].mDryParams.Gains.Target); - for(ALsizei i{0};i < NumSends;i++) - { - if(const ALeffectslot *Slot{SendSlots[i]}) - ComputePanGains(&Slot->Wet, coeffs, WetGain[i]*scale0, - voice->mChans[0].mWetParams[i].Gains.Target); - } - } - else - { - if(Device->AvgSpeakerDist > 0.0f) - { - /* NOTE: The NFCtrlFilters were created with a w0 of 0, which - * is what we want for FOA input. The first channel may have - * been previously re-adjusted if panned, so reset it. - */ - voice->mChans[0].mDryParams.NFCtrlFilter.adjust(0.0f); - - voice->mFlags |= VOICE_HAS_NFC; - } - - /* Local B-Format sources have their XYZ channels rotated according - * to the orientation. - */ - /* AT then UP */ - alu::Vector N{props->OrientAt[0], props->OrientAt[1], props->OrientAt[2], 0.0f}; - N.normalize(); - alu::Vector V{props->OrientUp[0], props->OrientUp[1], props->OrientUp[2], 0.0f}; - V.normalize(); - if(!props->HeadRelative) - { - N = Listener.Params.Matrix * N; - V = Listener.Params.Matrix * V; - } - /* Build and normalize right-vector */ - alu::Vector U{aluCrossproduct(N, V)}; - U.normalize(); - - /* Build a rotate + conversion matrix (FuMa -> ACN+N3D). NOTE: This - * matrix is transposed, for the inputs to align on the rows and - * outputs on the columns. - */ - const ALfloat &wscale = AmbiScale::FromFuMa[0]; - const ALfloat &yscale = AmbiScale::FromFuMa[1]; - const ALfloat &zscale = AmbiScale::FromFuMa[2]; - const ALfloat &xscale = AmbiScale::FromFuMa[3]; - const ALfloat matrix[4][MAX_AMBI_CHANNELS]{ - // ACN0 ACN1 ACN2 ACN3 - { wscale, 0.0f, 0.0f, 0.0f }, // FuMa W - { 0.0f, -N[0]*xscale, N[1]*xscale, -N[2]*xscale }, // FuMa X - { 0.0f, U[0]*yscale, -U[1]*yscale, U[2]*yscale }, // FuMa Y - { 0.0f, -V[0]*zscale, V[1]*zscale, -V[2]*zscale } // FuMa Z - }; - - for(ALsizei c{0};c < num_channels;c++) - { - ComputePanGains(&Device->Dry, matrix[c], DryGain, - voice->mChans[c].mDryParams.Gains.Target); - - for(ALsizei i{0};i < NumSends;i++) - { - if(const ALeffectslot *Slot{SendSlots[i]}) - ComputePanGains(&Slot->Wet, matrix[c], WetGain[i], - voice->mChans[c].mWetParams[i].Gains.Target); - } - } - } - } - else if(DirectChannels) - { - /* Direct source channels always play local. Skip the virtual channels - * and write inputs to the matching real outputs. - */ - voice->mDirect.Buffer = Device->RealOut.Buffer; - - for(ALsizei c{0};c < num_channels;c++) - { - int idx{GetChannelIdxByName(Device->RealOut, chans[c].channel)}; - if(idx != -1) voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain; - } - - /* Auxiliary sends still use normal channel panning since they mix to - * B-Format, which can't channel-match. - */ - for(ALsizei c{0};c < num_channels;c++) - { - ALfloat coeffs[MAX_AMBI_CHANNELS]; - CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); - - for(ALsizei i{0};i < NumSends;i++) - { - if(const ALeffectslot *Slot{SendSlots[i]}) - ComputePanGains(&Slot->Wet, coeffs, WetGain[i], - voice->mChans[c].mWetParams[i].Gains.Target); - } - } - } - else if(Device->mRenderMode == HrtfRender) - { - /* Full HRTF rendering. Skip the virtual channels and render to the - * real outputs. - */ - voice->mDirect.Buffer = Device->RealOut.Buffer; - - if(Distance > std::numeric_limits::epsilon()) - { - const ALfloat ev{std::asin(clampf(ypos, -1.0f, 1.0f))}; - const ALfloat az{std::atan2(xpos, -zpos)}; - - /* Get the HRIR coefficients and delays just once, for the given - * source direction. - */ - GetHrtfCoeffs(Device->mHrtf, ev, az, Distance, Spread, - voice->mChans[0].mDryParams.Hrtf.Target.Coeffs, - voice->mChans[0].mDryParams.Hrtf.Target.Delay); - voice->mChans[0].mDryParams.Hrtf.Target.Gain = DryGain * downmix_gain; - - /* Remaining channels use the same results as the first. */ - for(ALsizei c{1};c < num_channels;c++) - { - /* Skip LFE */ - if(chans[c].channel == LFE) continue; - voice->mChans[c].mDryParams.Hrtf.Target = voice->mChans[0].mDryParams.Hrtf.Target; - } - - /* Calculate the directional coefficients once, which apply to all - * input channels of the source sends. - */ - ALfloat coeffs[MAX_AMBI_CHANNELS]; - CalcDirectionCoeffs({xpos, ypos, zpos}, Spread, coeffs); - - for(ALsizei c{0};c < num_channels;c++) - { - /* Skip LFE */ - if(chans[c].channel == LFE) - continue; - for(ALsizei i{0};i < NumSends;i++) - { - if(const ALeffectslot *Slot{SendSlots[i]}) - ComputePanGains(&Slot->Wet, coeffs, WetGain[i] * downmix_gain, - voice->mChans[c].mWetParams[i].Gains.Target); - } - } - } - else - { - /* Local sources on HRTF play with each channel panned to its - * relative location around the listener, providing "virtual - * speaker" responses. - */ - for(ALsizei c{0};c < num_channels;c++) - { - /* Skip LFE */ - if(chans[c].channel == LFE) - continue; - - /* Get the HRIR coefficients and delays for this channel - * position. - */ - GetHrtfCoeffs(Device->mHrtf, chans[c].elevation, chans[c].angle, - std::numeric_limits::infinity(), Spread, - voice->mChans[c].mDryParams.Hrtf.Target.Coeffs, - voice->mChans[c].mDryParams.Hrtf.Target.Delay); - voice->mChans[c].mDryParams.Hrtf.Target.Gain = DryGain; - - /* Normal panning for auxiliary sends. */ - ALfloat coeffs[MAX_AMBI_CHANNELS]; - CalcAngleCoeffs(chans[c].angle, chans[c].elevation, Spread, coeffs); - - for(ALsizei i{0};i < NumSends;i++) - { - if(const ALeffectslot *Slot{SendSlots[i]}) - ComputePanGains(&Slot->Wet, coeffs, WetGain[i], - voice->mChans[c].mWetParams[i].Gains.Target); - } - } - } - - voice->mFlags |= VOICE_HAS_HRTF; - } - else - { - /* Non-HRTF rendering. Use normal panning to the output. */ - - if(Distance > std::numeric_limits::epsilon()) - { - /* Calculate NFC filter coefficient if needed. */ - if(Device->AvgSpeakerDist > 0.0f) - { - /* Clamp the distance for really close sources, to prevent - * excessive bass. - */ - const ALfloat mdist{maxf(Distance, Device->AvgSpeakerDist/4.0f)}; - const ALfloat w0{SPEEDOFSOUNDMETRESPERSEC / (mdist * Frequency)}; - - /* Adjust NFC filters. */ - for(ALsizei c{0};c < num_channels;c++) - voice->mChans[c].mDryParams.NFCtrlFilter.adjust(w0); - - voice->mFlags |= VOICE_HAS_NFC; - } - - /* Calculate the directional coefficients once, which apply to all - * input channels. - */ - ALfloat coeffs[MAX_AMBI_CHANNELS]; - if(Device->mRenderMode != StereoPair) - CalcDirectionCoeffs({xpos, ypos, zpos}, Spread, coeffs); - else - { - const ALfloat ev{std::asin(clampf(ypos, -1.0f, 1.0f))}; - const ALfloat az{std::atan2(xpos, -zpos)}; - CalcAngleCoeffs(ScaleAzimuthFront(az, 1.5f), ev, Spread, coeffs); - } - - for(ALsizei c{0};c < num_channels;c++) - { - /* Special-case LFE */ - if(chans[c].channel == LFE) - { - if(Device->Dry.Buffer.data() == Device->RealOut.Buffer.data()) - { - int idx = GetChannelIdxByName(Device->RealOut, chans[c].channel); - if(idx != -1) voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain; - } - continue; - } - - ComputePanGains(&Device->Dry, coeffs, DryGain * downmix_gain, - voice->mChans[c].mDryParams.Gains.Target); - } - - for(ALsizei c{0};c < num_channels;c++) - { - /* Skip LFE */ - if(chans[c].channel == LFE) - continue; - for(ALsizei i{0};i < NumSends;i++) - { - if(const ALeffectslot *Slot{SendSlots[i]}) - ComputePanGains(&Slot->Wet, coeffs, WetGain[i] * downmix_gain, - voice->mChans[c].mWetParams[i].Gains.Target); - } - } - } - else - { - if(Device->AvgSpeakerDist > 0.0f) - { - /* If the source distance is 0, set w0 to w1 to act as a pass- - * through. We still want to pass the signal through the - * filters so they keep an appropriate history, in case the - * source moves away from the listener. - */ - const ALfloat w0{SPEEDOFSOUNDMETRESPERSEC / (Device->AvgSpeakerDist * Frequency)}; - - for(ALsizei c{0};c < num_channels;c++) - voice->mChans[c].mDryParams.NFCtrlFilter.adjust(w0); - - voice->mFlags |= VOICE_HAS_NFC; - } - - for(ALsizei c{0};c < num_channels;c++) - { - /* Special-case LFE */ - if(chans[c].channel == LFE) - { - if(Device->Dry.Buffer.data() == Device->RealOut.Buffer.data()) - { - int idx = GetChannelIdxByName(Device->RealOut, chans[c].channel); - if(idx != -1) voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain; - } - continue; - } - - ALfloat coeffs[MAX_AMBI_CHANNELS]; - CalcAngleCoeffs( - (Device->mRenderMode==StereoPair) ? ScaleAzimuthFront(chans[c].angle, 3.0f) - : chans[c].angle, - chans[c].elevation, Spread, coeffs - ); - - ComputePanGains(&Device->Dry, coeffs, DryGain, - voice->mChans[c].mDryParams.Gains.Target); - for(ALsizei i{0};i < NumSends;i++) - { - if(const ALeffectslot *Slot{SendSlots[i]}) - ComputePanGains(&Slot->Wet, coeffs, WetGain[i], - voice->mChans[c].mWetParams[i].Gains.Target); - } - } - } - } - - { - const ALfloat hfScale{props->Direct.HFReference / Frequency}; - const ALfloat lfScale{props->Direct.LFReference / Frequency}; - const ALfloat gainHF{maxf(DryGainHF, 0.001f)}; /* Limit -60dB */ - const ALfloat gainLF{maxf(DryGainLF, 0.001f)}; - - voice->mDirect.FilterType = AF_None; - if(gainHF != 1.0f) voice->mDirect.FilterType |= AF_LowPass; - if(gainLF != 1.0f) voice->mDirect.FilterType |= AF_HighPass; - auto &lowpass = voice->mChans[0].mDryParams.LowPass; - auto &highpass = voice->mChans[0].mDryParams.HighPass; - lowpass.setParams(BiquadType::HighShelf, gainHF, hfScale, - lowpass.rcpQFromSlope(gainHF, 1.0f)); - highpass.setParams(BiquadType::LowShelf, gainLF, lfScale, - highpass.rcpQFromSlope(gainLF, 1.0f)); - for(ALsizei c{1};c < num_channels;c++) - { - voice->mChans[c].mDryParams.LowPass.copyParamsFrom(lowpass); - voice->mChans[c].mDryParams.HighPass.copyParamsFrom(highpass); - } - } - for(ALsizei i{0};i < NumSends;i++) - { - const ALfloat hfScale{props->Send[i].HFReference / Frequency}; - const ALfloat lfScale{props->Send[i].LFReference / Frequency}; - const ALfloat gainHF{maxf(WetGainHF[i], 0.001f)}; - const ALfloat gainLF{maxf(WetGainLF[i], 0.001f)}; - - voice->mSend[i].FilterType = AF_None; - if(gainHF != 1.0f) voice->mSend[i].FilterType |= AF_LowPass; - if(gainLF != 1.0f) voice->mSend[i].FilterType |= AF_HighPass; - - auto &lowpass = voice->mChans[0].mWetParams[i].LowPass; - auto &highpass = voice->mChans[0].mWetParams[i].HighPass; - lowpass.setParams(BiquadType::HighShelf, gainHF, hfScale, - lowpass.rcpQFromSlope(gainHF, 1.0f)); - highpass.setParams(BiquadType::LowShelf, gainLF, lfScale, - highpass.rcpQFromSlope(gainLF, 1.0f)); - for(ALsizei c{1};c < num_channels;c++) - { - voice->mChans[c].mWetParams[i].LowPass.copyParamsFrom(lowpass); - voice->mChans[c].mWetParams[i].HighPass.copyParamsFrom(highpass); - } - } -} - -void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const ALCcontext *ALContext) -{ - const ALCdevice *Device{ALContext->Device}; - ALeffectslot *SendSlots[MAX_SENDS]; - - voice->mDirect.Buffer = Device->Dry.Buffer; - for(ALsizei i{0};i < Device->NumAuxSends;i++) - { - SendSlots[i] = props->Send[i].Slot; - if(!SendSlots[i] && i == 0) - SendSlots[i] = ALContext->DefaultSlot.get(); - if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) - { - SendSlots[i] = nullptr; - voice->mSend[i].Buffer = {}; - } - else - voice->mSend[i].Buffer = SendSlots[i]->Wet.Buffer; - } - - /* Calculate the stepping value */ - const auto Pitch = static_cast(voice->mFrequency) / - static_cast(Device->Frequency) * props->Pitch; - if(Pitch > static_cast(MAX_PITCH)) - voice->mStep = MAX_PITCH<mStep = maxi(fastf2i(Pitch * FRACTIONONE), 1); - if(props->mResampler == BSinc24Resampler) - BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc24); - else if(props->mResampler == BSinc12Resampler) - BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc12); - voice->mResampler = SelectResampler(props->mResampler); - - /* Calculate gains */ - const ALlistener &Listener = ALContext->Listener; - ALfloat DryGain{clampf(props->Gain, props->MinGain, props->MaxGain)}; - DryGain *= props->Direct.Gain * Listener.Params.Gain; - DryGain = minf(DryGain, GAIN_MIX_MAX); - ALfloat DryGainHF{props->Direct.GainHF}; - ALfloat DryGainLF{props->Direct.GainLF}; - ALfloat WetGain[MAX_SENDS], WetGainHF[MAX_SENDS], WetGainLF[MAX_SENDS]; - for(ALsizei i{0};i < Device->NumAuxSends;i++) - { - WetGain[i] = clampf(props->Gain, props->MinGain, props->MaxGain); - WetGain[i] *= props->Send[i].Gain * Listener.Params.Gain; - WetGain[i] = minf(WetGain[i], GAIN_MIX_MAX); - WetGainHF[i] = props->Send[i].GainHF; - WetGainLF[i] = props->Send[i].GainLF; - } - - CalcPanningAndFilters(voice, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, DryGain, DryGainHF, DryGainLF, - WetGain, WetGainLF, WetGainHF, SendSlots, props, Listener, Device); -} - -void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const ALCcontext *ALContext) -{ - const ALCdevice *Device{ALContext->Device}; - const ALsizei NumSends{Device->NumAuxSends}; - const ALlistener &Listener = ALContext->Listener; - - /* Set mixing buffers and get send parameters. */ - voice->mDirect.Buffer = Device->Dry.Buffer; - ALeffectslot *SendSlots[MAX_SENDS]; - ALfloat RoomRolloff[MAX_SENDS]; - ALfloat DecayDistance[MAX_SENDS]; - ALfloat DecayLFDistance[MAX_SENDS]; - ALfloat DecayHFDistance[MAX_SENDS]; - for(ALsizei i{0};i < NumSends;i++) - { - SendSlots[i] = props->Send[i].Slot; - if(!SendSlots[i] && i == 0) - SendSlots[i] = ALContext->DefaultSlot.get(); - if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) - { - SendSlots[i] = nullptr; - RoomRolloff[i] = 0.0f; - DecayDistance[i] = 0.0f; - DecayLFDistance[i] = 0.0f; - DecayHFDistance[i] = 0.0f; - } - else if(SendSlots[i]->Params.AuxSendAuto) - { - RoomRolloff[i] = SendSlots[i]->Params.RoomRolloff + props->RoomRolloffFactor; - /* Calculate the distances to where this effect's decay reaches - * -60dB. - */ - DecayDistance[i] = SendSlots[i]->Params.DecayTime * - Listener.Params.ReverbSpeedOfSound; - DecayLFDistance[i] = DecayDistance[i] * SendSlots[i]->Params.DecayLFRatio; - DecayHFDistance[i] = DecayDistance[i] * SendSlots[i]->Params.DecayHFRatio; - if(SendSlots[i]->Params.DecayHFLimit) - { - ALfloat airAbsorption{SendSlots[i]->Params.AirAbsorptionGainHF}; - if(airAbsorption < 1.0f) - { - /* Calculate the distance to where this effect's air - * absorption reaches -60dB, and limit the effect's HF - * decay distance (so it doesn't take any longer to decay - * than the air would allow). - */ - ALfloat absorb_dist{std::log10(REVERB_DECAY_GAIN) / std::log10(airAbsorption)}; - DecayHFDistance[i] = minf(absorb_dist, DecayHFDistance[i]); - } - } - } - else - { - /* If the slot's auxiliary send auto is off, the data sent to the - * effect slot is the same as the dry path, sans filter effects */ - RoomRolloff[i] = props->RolloffFactor; - DecayDistance[i] = 0.0f; - DecayLFDistance[i] = 0.0f; - DecayHFDistance[i] = 0.0f; - } - - if(!SendSlots[i]) - voice->mSend[i].Buffer = {}; - else - voice->mSend[i].Buffer = SendSlots[i]->Wet.Buffer; - } - - /* Transform source to listener space (convert to head relative) */ - alu::Vector Position{props->Position[0], props->Position[1], props->Position[2], 1.0f}; - alu::Vector Velocity{props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f}; - alu::Vector Direction{props->Direction[0], props->Direction[1], props->Direction[2], 0.0f}; - if(props->HeadRelative == AL_FALSE) - { - /* Transform source vectors */ - Position = Listener.Params.Matrix * Position; - Velocity = Listener.Params.Matrix * Velocity; - Direction = Listener.Params.Matrix * Direction; - } - else - { - /* Offset the source velocity to be relative of the listener velocity */ - Velocity += Listener.Params.Velocity; - } - - const bool directional{Direction.normalize() > 0.0f}; - alu::Vector ToSource{Position[0], Position[1], Position[2], 0.0f}; - const ALfloat Distance{ToSource.normalize()}; - - /* Initial source gain */ - ALfloat DryGain{props->Gain}; - ALfloat DryGainHF{1.0f}; - ALfloat DryGainLF{1.0f}; - ALfloat WetGain[MAX_SENDS], WetGainHF[MAX_SENDS], WetGainLF[MAX_SENDS]; - for(ALsizei i{0};i < NumSends;i++) - { - WetGain[i] = props->Gain; - WetGainHF[i] = 1.0f; - WetGainLF[i] = 1.0f; - } - - /* Calculate distance attenuation */ - ALfloat ClampedDist{Distance}; - - switch(Listener.Params.SourceDistanceModel ? - props->mDistanceModel : Listener.Params.mDistanceModel) - { - case DistanceModel::InverseClamped: - ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); - if(props->MaxDistance < props->RefDistance) break; - /*fall-through*/ - case DistanceModel::Inverse: - if(!(props->RefDistance > 0.0f)) - ClampedDist = props->RefDistance; - else - { - ALfloat dist = lerp(props->RefDistance, ClampedDist, props->RolloffFactor); - if(dist > 0.0f) DryGain *= props->RefDistance / dist; - for(ALsizei i{0};i < NumSends;i++) - { - dist = lerp(props->RefDistance, ClampedDist, RoomRolloff[i]); - if(dist > 0.0f) WetGain[i] *= props->RefDistance / dist; - } - } - break; - - case DistanceModel::LinearClamped: - ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); - if(props->MaxDistance < props->RefDistance) break; - /*fall-through*/ - case DistanceModel::Linear: - if(!(props->MaxDistance != props->RefDistance)) - ClampedDist = props->RefDistance; - else - { - ALfloat attn = props->RolloffFactor * (ClampedDist-props->RefDistance) / - (props->MaxDistance-props->RefDistance); - DryGain *= maxf(1.0f - attn, 0.0f); - for(ALsizei i{0};i < NumSends;i++) - { - attn = RoomRolloff[i] * (ClampedDist-props->RefDistance) / - (props->MaxDistance-props->RefDistance); - WetGain[i] *= maxf(1.0f - attn, 0.0f); - } - } - break; - - case DistanceModel::ExponentClamped: - ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); - if(props->MaxDistance < props->RefDistance) break; - /*fall-through*/ - case DistanceModel::Exponent: - if(!(ClampedDist > 0.0f && props->RefDistance > 0.0f)) - ClampedDist = props->RefDistance; - else - { - DryGain *= std::pow(ClampedDist/props->RefDistance, -props->RolloffFactor); - for(ALsizei i{0};i < NumSends;i++) - WetGain[i] *= std::pow(ClampedDist/props->RefDistance, -RoomRolloff[i]); - } - break; - - case DistanceModel::Disable: - ClampedDist = props->RefDistance; - break; - } - - /* Calculate directional soundcones */ - if(directional && props->InnerAngle < 360.0f) - { - const ALfloat Angle{Rad2Deg(std::acos(-aluDotproduct(Direction, ToSource)) * - ConeScale * 2.0f)}; - - ALfloat ConeVolume, ConeHF; - if(!(Angle > props->InnerAngle)) - { - ConeVolume = 1.0f; - ConeHF = 1.0f; - } - else if(Angle < props->OuterAngle) - { - ALfloat scale = ( Angle-props->InnerAngle) / - (props->OuterAngle-props->InnerAngle); - ConeVolume = lerp(1.0f, props->OuterGain, scale); - ConeHF = lerp(1.0f, props->OuterGainHF, scale); - } - else - { - ConeVolume = props->OuterGain; - ConeHF = props->OuterGainHF; - } - - DryGain *= ConeVolume; - if(props->DryGainHFAuto) - DryGainHF *= ConeHF; - if(props->WetGainAuto) - std::transform(std::begin(WetGain), std::begin(WetGain)+NumSends, std::begin(WetGain), - [ConeVolume](ALfloat gain) noexcept -> ALfloat { return gain * ConeVolume; } - ); - if(props->WetGainHFAuto) - std::transform(std::begin(WetGainHF), std::begin(WetGainHF)+NumSends, - std::begin(WetGainHF), - [ConeHF](ALfloat gain) noexcept -> ALfloat { return gain * ConeHF; } - ); - } - - /* Apply gain and frequency filters */ - DryGain = clampf(DryGain, props->MinGain, props->MaxGain); - DryGain = minf(DryGain*props->Direct.Gain*Listener.Params.Gain, GAIN_MIX_MAX); - DryGainHF *= props->Direct.GainHF; - DryGainLF *= props->Direct.GainLF; - for(ALsizei i{0};i < NumSends;i++) - { - WetGain[i] = clampf(WetGain[i], props->MinGain, props->MaxGain); - WetGain[i] = minf(WetGain[i]*props->Send[i].Gain*Listener.Params.Gain, GAIN_MIX_MAX); - WetGainHF[i] *= props->Send[i].GainHF; - WetGainLF[i] *= props->Send[i].GainLF; - } - - /* Distance-based air absorption and initial send decay. */ - if(ClampedDist > props->RefDistance && props->RolloffFactor > 0.0f) - { - ALfloat meters_base{(ClampedDist-props->RefDistance) * props->RolloffFactor * - Listener.Params.MetersPerUnit}; - if(props->AirAbsorptionFactor > 0.0f) - { - ALfloat hfattn{std::pow(AIRABSORBGAINHF, meters_base * props->AirAbsorptionFactor)}; - DryGainHF *= hfattn; - std::transform(std::begin(WetGainHF), std::begin(WetGainHF)+NumSends, - std::begin(WetGainHF), - [hfattn](ALfloat gain) noexcept -> ALfloat { return gain * hfattn; } - ); - } - - if(props->WetGainAuto) - { - /* Apply a decay-time transformation to the wet path, based on the - * source distance in meters. The initial decay of the reverb - * effect is calculated and applied to the wet path. - */ - for(ALsizei i{0};i < NumSends;i++) - { - if(!(DecayDistance[i] > 0.0f)) - continue; - - const ALfloat gain{std::pow(REVERB_DECAY_GAIN, meters_base/DecayDistance[i])}; - WetGain[i] *= gain; - /* Yes, the wet path's air absorption is applied with - * WetGainAuto on, rather than WetGainHFAuto. - */ - if(gain > 0.0f) - { - ALfloat gainhf{std::pow(REVERB_DECAY_GAIN, meters_base/DecayHFDistance[i])}; - WetGainHF[i] *= minf(gainhf / gain, 1.0f); - ALfloat gainlf{std::pow(REVERB_DECAY_GAIN, meters_base/DecayLFDistance[i])}; - WetGainLF[i] *= minf(gainlf / gain, 1.0f); - } - } - } - } - - - /* Initial source pitch */ - ALfloat Pitch{props->Pitch}; - - /* Calculate velocity-based doppler effect */ - ALfloat DopplerFactor{props->DopplerFactor * Listener.Params.DopplerFactor}; - if(DopplerFactor > 0.0f) - { - const alu::Vector &lvelocity = Listener.Params.Velocity; - ALfloat vss{aluDotproduct(Velocity, ToSource) * -DopplerFactor}; - ALfloat vls{aluDotproduct(lvelocity, ToSource) * -DopplerFactor}; - - const ALfloat SpeedOfSound{Listener.Params.SpeedOfSound}; - if(!(vls < SpeedOfSound)) - { - /* Listener moving away from the source at the speed of sound. - * Sound waves can't catch it. - */ - Pitch = 0.0f; - } - else if(!(vss < SpeedOfSound)) - { - /* Source moving toward the listener at the speed of sound. Sound - * waves bunch up to extreme frequencies. - */ - Pitch = std::numeric_limits::infinity(); - } - else - { - /* Source and listener movement is nominal. Calculate the proper - * doppler shift. - */ - Pitch *= (SpeedOfSound-vls) / (SpeedOfSound-vss); - } - } - - /* Adjust pitch based on the buffer and output frequencies, and calculate - * fixed-point stepping value. - */ - Pitch *= static_cast(voice->mFrequency)/static_cast(Device->Frequency); - if(Pitch > static_cast(MAX_PITCH)) - voice->mStep = MAX_PITCH<mStep = maxi(fastf2i(Pitch * FRACTIONONE), 1); - if(props->mResampler == BSinc24Resampler) - BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc24); - else if(props->mResampler == BSinc12Resampler) - BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc12); - voice->mResampler = SelectResampler(props->mResampler); - - ALfloat spread{0.0f}; - if(props->Radius > Distance) - spread = al::MathDefs::Tau() - Distance/props->Radius*al::MathDefs::Pi(); - else if(Distance > 0.0f) - spread = std::asin(props->Radius/Distance) * 2.0f; - - CalcPanningAndFilters(voice, ToSource[0], ToSource[1], ToSource[2]*ZScale, - Distance*Listener.Params.MetersPerUnit, spread, DryGain, DryGainHF, DryGainLF, WetGain, - WetGainLF, WetGainHF, SendSlots, props, Listener, Device); -} - -void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) -{ - ALvoiceProps *props{voice->mUpdate.exchange(nullptr, std::memory_order_acq_rel)}; - if(!props && !force) return; - - if(props) - { - voice->mProps = *props; - - AtomicReplaceHead(context->FreeVoiceProps, props); - } - - if((voice->mProps.mSpatializeMode == SpatializeAuto && voice->mFmtChannels == FmtMono) || - voice->mProps.mSpatializeMode == SpatializeOn) - CalcAttnSourceParams(voice, &voice->mProps, context); - else - CalcNonAttnSourceParams(voice, &voice->mProps, context); -} - - -void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray *slots) -{ - IncrementRef(&ctx->UpdateCount); - if(LIKELY(!ctx->HoldUpdates.load(std::memory_order_acquire))) - { - bool cforce{CalcContextParams(ctx)}; - bool force{CalcListenerParams(ctx) || cforce}; - force = std::accumulate(slots->begin(), slots->end(), force, - [ctx,cforce](bool force, ALeffectslot *slot) -> bool - { return CalcEffectSlotParams(slot, ctx, cforce) | force; } - ); - - std::for_each(ctx->Voices->begin(), - ctx->Voices->begin() + ctx->VoiceCount.load(std::memory_order_acquire), - [ctx,force](ALvoice &voice) -> void - { - ALuint sid{voice.mSourceID.load(std::memory_order_acquire)}; - if(sid) CalcSourceParams(&voice, ctx, force); - } - ); - } - IncrementRef(&ctx->UpdateCount); -} - -void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) -{ - ASSUME(SamplesToDo > 0); - - const ALeffectslotArray *auxslots{ctx->ActiveAuxSlots.load(std::memory_order_acquire)}; - - /* Process pending propery updates for objects on the context. */ - ProcessParamUpdates(ctx, auxslots); - - /* Clear auxiliary effect slot mixing buffers. */ - std::for_each(auxslots->begin(), auxslots->end(), - [SamplesToDo](ALeffectslot *slot) -> void - { - for(auto &buffer : slot->MixBuffer) - std::fill_n(buffer.begin(), SamplesToDo, 0.0f); - } - ); - - /* Process voices that have a playing source. */ - std::for_each(ctx->Voices->begin(), - ctx->Voices->begin() + ctx->VoiceCount.load(std::memory_order_acquire), - [SamplesToDo,ctx](ALvoice &voice) -> void - { - const ALvoice::State vstate{voice.mPlayState.load(std::memory_order_acquire)}; - if(vstate == ALvoice::Stopped) return; - const ALuint sid{voice.mSourceID.load(std::memory_order_relaxed)}; - if(voice.mStep < 1) return; - - MixVoice(&voice, vstate, sid, ctx, SamplesToDo); - } - ); - - /* Process effects. */ - if(auxslots->size() < 1) return; - auto slots = auxslots->data(); - auto slots_end = slots + auxslots->size(); - - /* First sort the slots into scratch storage, so that effects come before - * their effect target (or their targets' target). - */ - auto sorted_slots = const_cast(slots_end); - auto sorted_slots_end = sorted_slots; - auto in_chain = [](const ALeffectslot *slot1, const ALeffectslot *slot2) noexcept -> bool - { - while((slot1=slot1->Params.Target) != nullptr) { - if(slot1 == slot2) return true; - } - return false; - }; - - *sorted_slots_end = *slots; - ++sorted_slots_end; - while(++slots != slots_end) - { - /* If this effect slot targets an effect slot already in the list (i.e. - * slots outputs to something in sorted_slots), directly or indirectly, - * insert it prior to that element. - */ - auto checker = sorted_slots; - do { - if(in_chain(*slots, *checker)) break; - } while(++checker != sorted_slots_end); - - checker = std::move_backward(checker, sorted_slots_end, sorted_slots_end+1); - *--checker = *slots; - ++sorted_slots_end; - } - - std::for_each(sorted_slots, sorted_slots_end, - [SamplesToDo](const ALeffectslot *slot) -> void - { - EffectState *state{slot->Params.mEffectState}; - state->process(SamplesToDo, slot->Wet.Buffer.data(), - static_cast(slot->Wet.Buffer.size()), state->mOutTarget); - } - ); -} - - -void ApplyStablizer(FrontStablizer *Stablizer, const al::span Buffer, - const ALuint lidx, const ALuint ridx, const ALuint cidx, const ALsizei SamplesToDo) -{ - ASSUME(SamplesToDo > 0); - - /* Apply a delay to all channels, except the front-left and front-right, so - * they maintain correct timing. - */ - const size_t NumChannels{Buffer.size()}; - for(size_t i{0u};i < NumChannels;i++) - { - if(i == lidx || i == ridx) - continue; - - auto &DelayBuf = Stablizer->DelayBuf[i]; - auto buffer_end = Buffer[i].begin() + SamplesToDo; - if(LIKELY(SamplesToDo >= ALsizei{FrontStablizer::DelayLength})) - { - auto delay_end = std::rotate(Buffer[i].begin(), - buffer_end - FrontStablizer::DelayLength, buffer_end); - std::swap_ranges(Buffer[i].begin(), delay_end, std::begin(DelayBuf)); - } - else - { - auto delay_start = std::swap_ranges(Buffer[i].begin(), buffer_end, - std::begin(DelayBuf)); - std::rotate(std::begin(DelayBuf), delay_start, std::end(DelayBuf)); - } - } - - ALfloat (&lsplit)[2][BUFFERSIZE] = Stablizer->LSplit; - ALfloat (&rsplit)[2][BUFFERSIZE] = Stablizer->RSplit; - auto &tmpbuf = Stablizer->TempBuf; - - /* This applies the band-splitter, preserving phase at the cost of some - * delay. The shorter the delay, the more error seeps into the result. - */ - auto apply_splitter = [&tmpbuf,SamplesToDo](const FloatBufferLine &Buffer, - ALfloat (&DelayBuf)[FrontStablizer::DelayLength], BandSplitter &Filter, - ALfloat (&splitbuf)[2][BUFFERSIZE]) -> void - { - /* Combine the delayed samples and the input samples into the temp - * buffer, in reverse. Then copy the final samples back into the delay - * buffer for next time. Note that the delay buffer's samples are - * stored backwards here. - */ - auto tmpbuf_end = std::begin(tmpbuf) + SamplesToDo; - std::copy_n(std::begin(DelayBuf), FrontStablizer::DelayLength, tmpbuf_end); - std::reverse_copy(Buffer.begin(), Buffer.begin()+SamplesToDo, std::begin(tmpbuf)); - std::copy_n(std::begin(tmpbuf), FrontStablizer::DelayLength, std::begin(DelayBuf)); - - /* Apply an all-pass on the reversed signal, then reverse the samples - * to get the forward signal with a reversed phase shift. - */ - Filter.applyAllpass(tmpbuf, SamplesToDo+FrontStablizer::DelayLength); - std::reverse(std::begin(tmpbuf), tmpbuf_end+FrontStablizer::DelayLength); - - /* Now apply the band-splitter, combining its phase shift with the - * reversed phase shift, restoring the original phase on the split - * signal. - */ - Filter.process(splitbuf[1], splitbuf[0], tmpbuf, SamplesToDo); - }; - apply_splitter(Buffer[lidx], Stablizer->DelayBuf[lidx], Stablizer->LFilter, lsplit); - apply_splitter(Buffer[ridx], Stablizer->DelayBuf[ridx], Stablizer->RFilter, rsplit); - - for(ALsizei i{0};i < SamplesToDo;i++) - { - ALfloat lfsum{lsplit[0][i] + rsplit[0][i]}; - ALfloat hfsum{lsplit[1][i] + rsplit[1][i]}; - ALfloat s{lsplit[0][i] + lsplit[1][i] - rsplit[0][i] - rsplit[1][i]}; - - /* This pans the separate low- and high-frequency sums between being on - * the center channel and the left/right channels. The low-frequency - * sum is 1/3rd toward center (2/3rds on left/right) and the high- - * frequency sum is 1/4th toward center (3/4ths on left/right). These - * values can be tweaked. - */ - ALfloat m{lfsum*std::cos(1.0f/3.0f * (al::MathDefs::Pi()*0.5f)) + - hfsum*std::cos(1.0f/4.0f * (al::MathDefs::Pi()*0.5f))}; - ALfloat c{lfsum*std::sin(1.0f/3.0f * (al::MathDefs::Pi()*0.5f)) + - hfsum*std::sin(1.0f/4.0f * (al::MathDefs::Pi()*0.5f))}; - - /* The generated center channel signal adds to the existing signal, - * while the modified left and right channels replace. - */ - Buffer[lidx][i] = (m + s) * 0.5f; - Buffer[ridx][i] = (m - s) * 0.5f; - Buffer[cidx][i] += c * 0.5f; - } -} - -void ApplyDistanceComp(const al::span Samples, const ALsizei SamplesToDo, - const DistanceComp::DistData *distcomp) -{ - ASSUME(SamplesToDo > 0); - - for(auto &chanbuffer : Samples) - { - const ALfloat gain{distcomp->Gain}; - const ALsizei base{distcomp->Length}; - ALfloat *distbuf{al::assume_aligned<16>(distcomp->Buffer)}; - ++distcomp; - - if(base < 1) - continue; - - ALfloat *inout{al::assume_aligned<16>(chanbuffer.data())}; - auto inout_end = inout + SamplesToDo; - if(LIKELY(SamplesToDo >= base)) - { - auto delay_end = std::rotate(inout, inout_end - base, inout_end); - std::swap_ranges(inout, delay_end, distbuf); - } - else - { - auto delay_start = std::swap_ranges(inout, inout_end, distbuf); - std::rotate(distbuf, delay_start, distbuf + base); - } - std::transform(inout, inout_end, inout, std::bind(std::multiplies{}, _1, gain)); - } -} - -void ApplyDither(const al::span Samples, ALuint *dither_seed, - const ALfloat quant_scale, const ALsizei SamplesToDo) -{ - /* Dithering. Generate whitenoise (uniform distribution of random values - * between -1 and +1) and add it to the sample values, after scaling up to - * the desired quantization depth amd before rounding. - */ - const ALfloat invscale{1.0f / quant_scale}; - ALuint seed{*dither_seed}; - auto dither_channel = [&seed,invscale,quant_scale,SamplesToDo](FloatBufferLine &input) -> void - { - ASSUME(SamplesToDo > 0); - auto dither_sample = [&seed,invscale,quant_scale](const ALfloat sample) noexcept -> ALfloat - { - ALfloat val{sample * quant_scale}; - ALuint rng0{dither_rng(&seed)}; - ALuint rng1{dither_rng(&seed)}; - val += static_cast(rng0*(1.0/UINT_MAX) - rng1*(1.0/UINT_MAX)); - return fast_roundf(val) * invscale; - }; - std::transform(input.begin(), input.begin()+SamplesToDo, input.begin(), dither_sample); - }; - std::for_each(Samples.begin(), Samples.end(), dither_channel); - *dither_seed = seed; -} - - -/* Base template left undefined. Should be marked =delete, but Clang 3.8.1 - * chokes on that given the inline specializations. - */ -template -inline T SampleConv(ALfloat) noexcept; - -template<> inline ALfloat SampleConv(ALfloat val) noexcept -{ return val; } -template<> inline ALint SampleConv(ALfloat val) noexcept -{ - /* Floats have a 23-bit mantissa, plus an implied 1 bit and a sign bit. - * This means a normalized float has at most 25 bits of signed precision. - * When scaling and clamping for a signed 32-bit integer, these following - * values are the best a float can give. - */ - return fastf2i(clampf(val*2147483648.0f, -2147483648.0f, 2147483520.0f)); -} -template<> inline ALshort SampleConv(ALfloat val) noexcept -{ return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); } -template<> inline ALbyte SampleConv(ALfloat val) noexcept -{ return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); } - -/* Define unsigned output variations. */ -template<> inline ALuint SampleConv(ALfloat val) noexcept -{ return SampleConv(val) + 2147483648u; } -template<> inline ALushort SampleConv(ALfloat val) noexcept -{ return SampleConv(val) + 32768; } -template<> inline ALubyte SampleConv(ALfloat val) noexcept -{ return SampleConv(val) + 128; } - -template -void Write(const al::span InBuffer, ALvoid *OutBuffer, const size_t Offset, - const ALsizei SamplesToDo) -{ - using SampleType = typename DevFmtTypeTraits::Type; - - const size_t numchans{InBuffer.size()}; - ASSUME(numchans > 0); - - SampleType *outbase = static_cast(OutBuffer) + Offset*numchans; - auto conv_channel = [&outbase,SamplesToDo,numchans](const FloatBufferLine &inbuf) -> void - { - ASSUME(SamplesToDo > 0); - SampleType *out{outbase++}; - auto conv_sample = [numchans,&out](const ALfloat s) noexcept -> void - { - *out = SampleConv(s); - out += numchans; - }; - std::for_each(inbuf.begin(), inbuf.begin()+SamplesToDo, conv_sample); - }; - std::for_each(InBuffer.cbegin(), InBuffer.cend(), conv_channel); -} - -} // namespace - -void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) -{ - FPUCtl mixer_mode{}; - for(ALsizei SamplesDone{0};SamplesDone < NumSamples;) - { - const ALsizei SamplesToDo{mini(NumSamples-SamplesDone, BUFFERSIZE)}; - - /* Clear main mixing buffers. */ - std::for_each(device->MixBuffer.begin(), device->MixBuffer.end(), - [SamplesToDo](std::array &buffer) -> void - { std::fill_n(buffer.begin(), SamplesToDo, 0.0f); } - ); - - /* Increment the mix count at the start (lsb should now be 1). */ - IncrementRef(&device->MixCount); - - /* For each context on this device, process and mix its sources and - * effects. - */ - for(ALCcontext *ctx : *device->mContexts.load(std::memory_order_acquire)) - ProcessContext(ctx, SamplesToDo); - - /* Increment the clock time. Every second's worth of samples is - * converted and added to clock base so that large sample counts don't - * overflow during conversion. This also guarantees a stable - * conversion. - */ - device->SamplesDone += SamplesToDo; - device->ClockBase += std::chrono::seconds{device->SamplesDone / device->Frequency}; - device->SamplesDone %= device->Frequency; - - /* Increment the mix count at the end (lsb should now be 0). */ - IncrementRef(&device->MixCount); - - /* Apply any needed post-process for finalizing the Dry mix to the - * RealOut (Ambisonic decode, UHJ encode, etc). - */ - if(LIKELY(device->PostProcess)) - device->PostProcess(device, SamplesToDo); - const al::span RealOut{device->RealOut.Buffer}; - - /* Apply front image stablization for surround sound, if applicable. */ - if(device->Stablizer) - { - const int lidx{GetChannelIdxByName(device->RealOut, FrontLeft)}; - const int ridx{GetChannelIdxByName(device->RealOut, FrontRight)}; - const int cidx{GetChannelIdxByName(device->RealOut, FrontCenter)}; - assert(lidx >= 0 && ridx >= 0 && cidx >= 0); - - ApplyStablizer(device->Stablizer.get(), RealOut, lidx, ridx, cidx, SamplesToDo); - } - - /* Apply compression, limiting sample amplitude if needed or desired. */ - if(Compressor *comp{device->Limiter.get()}) - comp->process(SamplesToDo, RealOut.data()); - - /* Apply delays and attenuation for mismatched speaker distances. */ - ApplyDistanceComp(RealOut, SamplesToDo, device->ChannelDelay.as_span().cbegin()); - - /* Apply dithering. The compressor should have left enough headroom for - * the dither noise to not saturate. - */ - if(device->DitherDepth > 0.0f) - ApplyDither(RealOut, &device->DitherSeed, device->DitherDepth, SamplesToDo); - - if(LIKELY(OutBuffer)) - { - /* Finally, interleave and convert samples, writing to the device's - * output buffer. - */ - switch(device->FmtType) - { -#define HANDLE_WRITE(T) case T: \ - Write(RealOut, OutBuffer, SamplesDone, SamplesToDo); break; - HANDLE_WRITE(DevFmtByte) - HANDLE_WRITE(DevFmtUByte) - HANDLE_WRITE(DevFmtShort) - HANDLE_WRITE(DevFmtUShort) - HANDLE_WRITE(DevFmtInt) - HANDLE_WRITE(DevFmtUInt) - HANDLE_WRITE(DevFmtFloat) -#undef HANDLE_WRITE - } - } - - SamplesDone += SamplesToDo; - } -} - - -void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) -{ - if(!device->Connected.exchange(false, std::memory_order_acq_rel)) - return; - - AsyncEvent evt{EventType_Disconnected}; - evt.u.user.type = AL_EVENT_TYPE_DISCONNECTED_SOFT; - evt.u.user.id = 0; - evt.u.user.param = 0; - - va_list args; - va_start(args, msg); - int msglen{vsnprintf(evt.u.user.msg, sizeof(evt.u.user.msg), msg, args)}; - va_end(args); - - if(msglen < 0 || static_cast(msglen) >= sizeof(evt.u.user.msg)) - evt.u.user.msg[sizeof(evt.u.user.msg)-1] = 0; - - for(ALCcontext *ctx : *device->mContexts.load()) - { - const ALbitfieldSOFT enabledevt{ctx->EnabledEvts.load(std::memory_order_acquire)}; - if((enabledevt&EventType_Disconnected)) - { - RingBuffer *ring{ctx->AsyncEvents.get()}; - auto evt_data = ring->getWriteVector().first; - if(evt_data.len > 0) - { - new (evt_data.buf) AsyncEvent{evt}; - ring->writeAdvance(1); - ctx->EventSem.post(); - } - } - - auto stop_voice = [](ALvoice &voice) -> void - { - voice.mCurrentBuffer.store(nullptr, std::memory_order_relaxed); - voice.mLoopBuffer.store(nullptr, std::memory_order_relaxed); - voice.mSourceID.store(0u, std::memory_order_relaxed); - voice.mPlayState.store(ALvoice::Stopped, std::memory_order_release); - }; - std::for_each(ctx->Voices->begin(), - ctx->Voices->begin() + ctx->VoiceCount.load(std::memory_order_acquire), - stop_voice); - } -} diff --git a/Alc/alu.h b/Alc/alu.h deleted file mode 100644 index 9acf904a..00000000 --- a/Alc/alu.h +++ /dev/null @@ -1,466 +0,0 @@ -#ifndef _ALU_H_ -#define _ALU_H_ - -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" - -#include "alBuffer.h" -#include "alcmain.h" -#include "almalloc.h" -#include "alspan.h" -#include "ambidefs.h" -#include "filters/biquad.h" -#include "filters/nfc.h" -#include "filters/splitter.h" -#include "hrtf.h" -#include "logging.h" - -struct ALbufferlistitem; -struct ALeffectslot; -struct BSincTable; - - -enum class DistanceModel; - -#define MAX_PITCH 255 -#define MAX_SENDS 16 - - -#define DITHER_RNG_SEED 22222 - - -enum SpatializeMode { - SpatializeOff = AL_FALSE, - SpatializeOn = AL_TRUE, - SpatializeAuto = AL_AUTO_SOFT -}; - -enum Resampler { - PointResampler, - LinearResampler, - FIR4Resampler, - BSinc12Resampler, - BSinc24Resampler, - - ResamplerMax = BSinc24Resampler -}; -extern Resampler ResamplerDefault; - -/* The number of distinct scale and phase intervals within the bsinc filter - * table. - */ -#define BSINC_SCALE_BITS 4 -#define BSINC_SCALE_COUNT (1< *Coeffs; - ALsizei Delay[2]; - ALfloat Gain; - ALfloat GainStep; -}; - - -struct DirectParams { - BiquadFilter LowPass; - BiquadFilter HighPass; - - NfcFilter NFCtrlFilter; - - struct { - HrtfFilter Old; - HrtfFilter Target; - HrtfState State; - } Hrtf; - - struct { - ALfloat Current[MAX_OUTPUT_CHANNELS]; - ALfloat Target[MAX_OUTPUT_CHANNELS]; - } Gains; -}; - -struct SendParams { - BiquadFilter LowPass; - BiquadFilter HighPass; - - struct { - ALfloat Current[MAX_OUTPUT_CHANNELS]; - ALfloat Target[MAX_OUTPUT_CHANNELS]; - } Gains; -}; - - -struct ALvoicePropsBase { - ALfloat Pitch; - ALfloat Gain; - ALfloat OuterGain; - ALfloat MinGain; - ALfloat MaxGain; - ALfloat InnerAngle; - ALfloat OuterAngle; - ALfloat RefDistance; - ALfloat MaxDistance; - ALfloat RolloffFactor; - std::array Position; - std::array Velocity; - std::array Direction; - std::array OrientAt; - std::array OrientUp; - ALboolean HeadRelative; - DistanceModel mDistanceModel; - Resampler mResampler; - ALboolean DirectChannels; - SpatializeMode mSpatializeMode; - - ALboolean DryGainHFAuto; - ALboolean WetGainAuto; - ALboolean WetGainHFAuto; - ALfloat OuterGainHF; - - ALfloat AirAbsorptionFactor; - ALfloat RoomRolloffFactor; - ALfloat DopplerFactor; - - std::array StereoPan; - - ALfloat Radius; - - /** Direct filter and auxiliary send info. */ - struct { - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - } Direct; - struct SendData { - ALeffectslot *Slot; - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - } Send[MAX_SENDS]; -}; - -struct ALvoiceProps : public ALvoicePropsBase { - std::atomic next{nullptr}; - - DEF_NEWDEL(ALvoiceProps) -}; - -#define VOICE_IS_STATIC (1u<<0) -#define VOICE_IS_FADING (1u<<1) /* Fading sources use gain stepping for smooth transitions. */ -#define VOICE_IS_AMBISONIC (1u<<2) /* Voice needs HF scaling for ambisonic upsampling. */ -#define VOICE_HAS_HRTF (1u<<3) -#define VOICE_HAS_NFC (1u<<4) - -struct ALvoice { - enum State { - Stopped = 0, - Playing = 1, - Stopping = 2 - }; - - std::atomic mUpdate{nullptr}; - - std::atomic mSourceID{0u}; - std::atomic mPlayState{Stopped}; - - ALvoicePropsBase mProps; - - /** - * Source offset in samples, relative to the currently playing buffer, NOT - * the whole queue. - */ - std::atomic mPosition; - /** Fractional (fixed-point) offset to the next sample. */ - std::atomic mPositionFrac; - - /* Current buffer queue item being played. */ - std::atomic mCurrentBuffer; - - /* Buffer queue item to loop to at end of queue (will be NULL for non- - * looping voices). - */ - std::atomic mLoopBuffer; - - /* Properties for the attached buffer(s). */ - FmtChannels mFmtChannels; - ALuint mFrequency; - ALsizei mNumChannels; - ALsizei mSampleSize; - - /** Current target parameters used for mixing. */ - ALint mStep; - - ResamplerFunc mResampler; - - InterpState mResampleState; - - ALuint mFlags; - - struct DirectData { - int FilterType; - al::span Buffer; - }; - DirectData mDirect; - - struct SendData { - int FilterType; - al::span Buffer; - }; - std::array mSend; - - struct ChannelData { - alignas(16) std::array mPrevSamples; - - ALfloat mAmbiScale; - BandSplitter mAmbiSplitter; - - DirectParams mDryParams; - std::array mWetParams; - }; - std::array mChans; - - ALvoice() = default; - ALvoice(const ALvoice&) = delete; - ~ALvoice() { delete mUpdate.exchange(nullptr, std::memory_order_acq_rel); } - ALvoice& operator=(const ALvoice&) = delete; - ALvoice& operator=(ALvoice&& rhs) noexcept - { - ALvoiceProps *old_update{mUpdate.load(std::memory_order_relaxed)}; - mUpdate.store(rhs.mUpdate.exchange(old_update, std::memory_order_relaxed), - std::memory_order_relaxed); - - mSourceID.store(rhs.mSourceID.load(std::memory_order_relaxed), std::memory_order_relaxed); - mPlayState.store(rhs.mPlayState.load(std::memory_order_relaxed), - std::memory_order_relaxed); - - mProps = rhs.mProps; - - mPosition.store(rhs.mPosition.load(std::memory_order_relaxed), std::memory_order_relaxed); - mPositionFrac.store(rhs.mPositionFrac.load(std::memory_order_relaxed), - std::memory_order_relaxed); - - mCurrentBuffer.store(rhs.mCurrentBuffer.load(std::memory_order_relaxed), - std::memory_order_relaxed); - mLoopBuffer.store(rhs.mLoopBuffer.load(std::memory_order_relaxed), - std::memory_order_relaxed); - - mFmtChannels = rhs.mFmtChannels; - mFrequency = rhs.mFrequency; - mNumChannels = rhs.mNumChannels; - mSampleSize = rhs.mSampleSize; - - mStep = rhs.mStep; - mResampler = rhs.mResampler; - - mResampleState = rhs.mResampleState; - - mFlags = rhs.mFlags; - - mDirect = rhs.mDirect; - mSend = rhs.mSend; - mChans = rhs.mChans; - - return *this; - } -}; - - -using MixerFunc = void(*)(const ALfloat *data, const al::span OutBuffer, - ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, - const ALsizei BufferSize); -using RowMixerFunc = void(*)(FloatBufferLine &OutBuffer, const ALfloat *gains, - const al::span InSamples, const ALsizei InPos, - const ALsizei BufferSize); -using HrtfMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - MixHrtfFilter *hrtfparams, const ALsizei BufferSize); -using HrtfMixerBlendFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize); -using HrtfDirectMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, - const ALsizei BufferSize); - - -#define GAIN_MIX_MAX (1000.0f) /* +60dB */ - -#define GAIN_SILENCE_THRESHOLD (0.00001f) /* -100dB */ - -#define SPEEDOFSOUNDMETRESPERSEC (343.3f) -#define AIRABSORBGAINHF (0.99426f) /* -0.05dB */ - -/* Target gain for the reverb decay feedback reaching the decay time. */ -#define REVERB_DECAY_GAIN (0.001f) /* -60 dB */ - -#define FRACTIONBITS (12) -#define FRACTIONONE (1< GetAmbiIdentityRow(size_t i) noexcept -{ - std::array ret{}; - ret[i] = 1.0f; - return ret; -} - - -void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCcontext *Context, const ALsizei SamplesToDo); - -void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples); -/* Caller must lock the device state, and the mixer must not be running. */ -void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) DECL_FORMAT(printf, 2, 3); - -extern MixerFunc MixSamples; -extern RowMixerFunc MixRowSamples; - -extern const ALfloat ConeScale; -extern const ALfloat ZScale; -extern const ALboolean OverrideReverbSpeedOfSound; - -#endif diff --git a/Alc/ambdec.cpp b/Alc/ambdec.cpp deleted file mode 100644 index 0991cfc5..00000000 --- a/Alc/ambdec.cpp +++ /dev/null @@ -1,436 +0,0 @@ - -#include "config.h" - -#include "ambdec.h" - -#include -#include -#include - -#include -#include -#include -#include - -#include "logging.h" -#include "compat.h" - - -namespace { - -template -constexpr inline std::size_t size(const T(&)[N]) noexcept -{ return N; } - -int readline(std::istream &f, std::string &output) -{ - while(f.good() && f.peek() == '\n') - f.ignore(); - - return std::getline(f, output) && !output.empty(); -} - -bool read_clipped_line(std::istream &f, std::string &buffer) -{ - while(readline(f, buffer)) - { - std::size_t pos{0}; - while(pos < buffer.length() && std::isspace(buffer[pos])) - pos++; - buffer.erase(0, pos); - - std::size_t cmtpos{buffer.find_first_of('#')}; - if(cmtpos < buffer.length()) - buffer.resize(cmtpos); - while(!buffer.empty() && std::isspace(buffer.back())) - buffer.pop_back(); - - if(!buffer.empty()) - return true; - } - return false; -} - - -std::string read_word(std::istream &f) -{ - std::string ret; - f >> ret; - return ret; -} - -bool is_at_end(const std::string &buffer, std::size_t endpos) -{ - while(endpos < buffer.length() && std::isspace(buffer[endpos])) - ++endpos; - return !(endpos < buffer.length()); -} - - -bool load_ambdec_speakers(al::vector &spkrs, const std::size_t num_speakers, std::istream &f, std::string &buffer) -{ - while(spkrs.size() < num_speakers) - { - std::istringstream istr{buffer}; - - std::string cmd{read_word(istr)}; - if(cmd.empty()) - { - if(!read_clipped_line(f, buffer)) - { - ERR("Unexpected end of file\n"); - return false; - } - continue; - } - - if(cmd == "add_spkr") - { - spkrs.emplace_back(); - AmbDecConf::SpeakerConf &spkr = spkrs.back(); - const size_t spkr_num{spkrs.size()}; - - istr >> spkr.Name; - if(istr.fail()) WARN("Name not specified for speaker %zu\n", spkr_num); - istr >> spkr.Distance; - if(istr.fail()) WARN("Distance not specified for speaker %zu\n", spkr_num); - istr >> spkr.Azimuth; - if(istr.fail()) WARN("Azimuth not specified for speaker %zu\n", spkr_num); - istr >> spkr.Elevation; - if(istr.fail()) WARN("Elevation not specified for speaker %zu\n", spkr_num); - istr >> spkr.Connection; - if(istr.fail()) TRACE("Connection not specified for speaker %zu\n", spkr_num); - } - else - { - ERR("Unexpected speakers command: %s\n", cmd.c_str()); - return false; - } - - istr.clear(); - const auto endpos = static_cast(istr.tellg()); - if(!is_at_end(buffer, endpos)) - { - ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); - return false; - } - buffer.clear(); - } - - return true; -} - -bool load_ambdec_matrix(float (&gains)[MAX_AMBI_ORDER+1], al::vector &matrix, const std::size_t maxrow, std::istream &f, std::string &buffer) -{ - bool gotgains{false}; - std::size_t cur{0u}; - while(cur < maxrow) - { - std::istringstream istr{buffer}; - - std::string cmd{read_word(istr)}; - if(cmd.empty()) - { - if(!read_clipped_line(f, buffer)) - { - ERR("Unexpected end of file\n"); - return false; - } - continue; - } - - if(cmd == "order_gain") - { - std::size_t curgain{0u}; - float value; - while(istr.good()) - { - istr >> value; - if(istr.fail()) break; - if(!istr.eof() && !std::isspace(istr.peek())) - { - ERR("Extra junk on gain %zu: %s\n", curgain+1, - buffer.c_str()+static_cast(istr.tellg())); - return false; - } - if(curgain < size(gains)) - gains[curgain++] = value; - } - std::fill(std::begin(gains)+curgain, std::end(gains), 0.0f); - gotgains = true; - } - else if(cmd == "add_row") - { - matrix.emplace_back(); - AmbDecConf::CoeffArray &mtxrow = matrix.back(); - std::size_t curidx{0u}; - float value{}; - while(istr.good()) - { - istr >> value; - if(istr.fail()) break; - if(!istr.eof() && !std::isspace(istr.peek())) - { - ERR("Extra junk on matrix element %zux%zu: %s\n", curidx, - matrix.size(), buffer.c_str()+static_cast(istr.tellg())); - matrix.pop_back(); - return false; - } - if(curidx < mtxrow.size()) - mtxrow[curidx++] = value; - } - std::fill(mtxrow.begin()+curidx, mtxrow.end(), 0.0f); - cur++; - } - else - { - ERR("Unexpected matrix command: %s\n", cmd.c_str()); - return false; - } - - istr.clear(); - const auto endpos = static_cast(istr.tellg()); - if(!is_at_end(buffer, endpos)) - { - ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); - return false; - } - buffer.clear(); - } - - if(!gotgains) - { - ERR("Matrix order_gain not specified\n"); - return false; - } - - return true; -} - -} // namespace - -int AmbDecConf::load(const char *fname) noexcept -{ - al::ifstream f{fname}; - if(!f.is_open()) - { - ERR("Failed to open: %s\n", fname); - return 0; - } - - std::size_t num_speakers{0u}; - std::string buffer; - while(read_clipped_line(f, buffer)) - { - std::istringstream istr{buffer}; - - std::string command{read_word(istr)}; - if(command.empty()) - { - ERR("Malformed line: %s\n", buffer.c_str()); - return 0; - } - - if(command == "/description") - istr >> Description; - else if(command == "/version") - { - istr >> Version; - if(!istr.eof() && !std::isspace(istr.peek())) - { - ERR("Extra junk after version: %s\n", - buffer.c_str()+static_cast(istr.tellg())); - return 0; - } - if(Version != 3) - { - ERR("Unsupported version: %u\n", Version); - return 0; - } - } - else if(command == "/dec/chan_mask") - { - istr >> std::hex >> ChanMask >> std::dec; - if(!istr.eof() && !std::isspace(istr.peek())) - { - ERR("Extra junk after mask: %s\n", - buffer.c_str()+static_cast(istr.tellg())); - return 0; - } - } - else if(command == "/dec/freq_bands") - { - istr >> FreqBands; - if(!istr.eof() && !std::isspace(istr.peek())) - { - ERR("Extra junk after freq_bands: %s\n", - buffer.c_str()+static_cast(istr.tellg())); - return 0; - } - if(FreqBands != 1 && FreqBands != 2) - { - ERR("Invalid freq_bands value: %u\n", FreqBands); - return 0; - } - } - else if(command == "/dec/speakers") - { - istr >> num_speakers; - if(!istr.eof() && !std::isspace(istr.peek())) - { - ERR("Extra junk after speakers: %s\n", - buffer.c_str()+static_cast(istr.tellg())); - return 0; - } - Speakers.reserve(num_speakers); - LFMatrix.reserve(num_speakers); - HFMatrix.reserve(num_speakers); - } - else if(command == "/dec/coeff_scale") - { - std::string scale = read_word(istr); - if(scale == "n3d") CoeffScale = AmbDecScale::N3D; - else if(scale == "sn3d") CoeffScale = AmbDecScale::SN3D; - else if(scale == "fuma") CoeffScale = AmbDecScale::FuMa; - else - { - ERR("Unsupported coeff scale: %s\n", scale.c_str()); - return 0; - } - } - else if(command == "/opt/xover_freq") - { - istr >> XOverFreq; - if(!istr.eof() && !std::isspace(istr.peek())) - { - ERR("Extra junk after xover_freq: %s\n", - buffer.c_str()+static_cast(istr.tellg())); - return 0; - } - } - else if(command == "/opt/xover_ratio") - { - istr >> XOverRatio; - if(!istr.eof() && !std::isspace(istr.peek())) - { - ERR("Extra junk after xover_ratio: %s\n", - buffer.c_str()+static_cast(istr.tellg())); - return 0; - } - } - else if(command == "/opt/input_scale" || command == "/opt/nfeff_comp" || - command == "/opt/delay_comp" || command == "/opt/level_comp") - { - /* Unused */ - read_word(istr); - } - else if(command == "/speakers/{") - { - const auto endpos = static_cast(istr.tellg()); - if(!is_at_end(buffer, endpos)) - { - ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); - return 0; - } - buffer.clear(); - - if(!load_ambdec_speakers(Speakers, num_speakers, f, buffer)) - return 0; - - if(!read_clipped_line(f, buffer)) - { - ERR("Unexpected end of file\n"); - return 0; - } - std::istringstream istr2{buffer}; - std::string endmark{read_word(istr2)}; - if(endmark != "/}") - { - ERR("Expected /} after speaker definitions, got %s\n", endmark.c_str()); - return 0; - } - istr.swap(istr2); - } - else if(command == "/lfmatrix/{" || command == "/hfmatrix/{" || command == "/matrix/{") - { - const auto endpos = static_cast(istr.tellg()); - if(!is_at_end(buffer, endpos)) - { - ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); - return 0; - } - buffer.clear(); - - if(FreqBands == 1) - { - if(command != "/matrix/{") - { - ERR("Unexpected \"%s\" type for a single-band decoder\n", command.c_str()); - return 0; - } - if(!load_ambdec_matrix(HFOrderGain, HFMatrix, num_speakers, f, buffer)) - return 0; - } - else - { - if(command == "/lfmatrix/{") - { - if(!load_ambdec_matrix(LFOrderGain, LFMatrix, num_speakers, f, buffer)) - return 0; - } - else if(command == "/hfmatrix/{") - { - if(!load_ambdec_matrix(HFOrderGain, HFMatrix, num_speakers, f, buffer)) - return 0; - } - else - { - ERR("Unexpected \"%s\" type for a dual-band decoder\n", command.c_str()); - return 0; - } - } - - if(!read_clipped_line(f, buffer)) - { - ERR("Unexpected end of file\n"); - return 0; - } - std::istringstream istr2{buffer}; - std::string endmark{read_word(istr2)}; - if(endmark != "/}") - { - ERR("Expected /} after matrix definitions, got %s\n", endmark.c_str()); - return 0; - } - istr.swap(istr2); - } - else if(command == "/end") - { - const auto endpos = static_cast(istr.tellg()); - if(!is_at_end(buffer, endpos)) - { - ERR("Unexpected junk on end: %s\n", buffer.c_str()+endpos); - return 0; - } - - return 1; - } - else - { - ERR("Unexpected command: %s\n", command.c_str()); - return 0; - } - - istr.clear(); - const auto endpos = static_cast(istr.tellg()); - if(!is_at_end(buffer, endpos)) - { - ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); - return 0; - } - buffer.clear(); - } - ERR("Unexpected end of file\n"); - - return 0; -} diff --git a/Alc/ambdec.h b/Alc/ambdec.h deleted file mode 100644 index ff7b71ee..00000000 --- a/Alc/ambdec.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef AMBDEC_H -#define AMBDEC_H - -#include -#include - -#include "ambidefs.h" -#include "vector.h" - -/* Helpers to read .ambdec configuration files. */ - -enum class AmbDecScale { - N3D, - SN3D, - FuMa, -}; -struct AmbDecConf { - std::string Description; - int Version{0}; /* Must be 3 */ - - unsigned int ChanMask{0u}; - unsigned int FreqBands{0u}; /* Must be 1 or 2 */ - AmbDecScale CoeffScale{}; - - float XOverFreq{0.0f}; - float XOverRatio{0.0f}; - - struct SpeakerConf { - std::string Name; - float Distance{0.0f}; - float Azimuth{0.0f}; - float Elevation{0.0f}; - std::string Connection; - }; - al::vector Speakers; - - using CoeffArray = std::array; - /* Unused when FreqBands == 1 */ - float LFOrderGain[MAX_AMBI_ORDER+1]{}; - al::vector LFMatrix; - - float HFOrderGain[MAX_AMBI_ORDER+1]{}; - al::vector HFMatrix; - - int load(const char *fname) noexcept; -}; - -#endif /* AMBDEC_H */ diff --git a/Alc/ambidefs.h b/Alc/ambidefs.h deleted file mode 100644 index 17a9815b..00000000 --- a/Alc/ambidefs.h +++ /dev/null @@ -1,119 +0,0 @@ -#ifndef AMBIDEFS_H -#define AMBIDEFS_H - -#include - -/* The maximum number of Ambisonics channels. For a given order (o), the size - * needed will be (o+1)**2, thus zero-order has 1, first-order has 4, second- - * order has 9, third-order has 16, and fourth-order has 25. - */ -#define MAX_AMBI_ORDER 3 -constexpr inline size_t AmbiChannelsFromOrder(size_t order) noexcept -{ return (order+1) * (order+1); } -#define MAX_AMBI_CHANNELS AmbiChannelsFromOrder(MAX_AMBI_ORDER) - -/* A bitmask of ambisonic channels for 0 to 4th order. This only specifies up - * to 4th order, which is the highest order a 32-bit mask value can specify (a - * 64-bit mask could handle up to 7th order). - */ -#define AMBI_0ORDER_MASK 0x00000001 -#define AMBI_1ORDER_MASK 0x0000000f -#define AMBI_2ORDER_MASK 0x000001ff -#define AMBI_3ORDER_MASK 0x0000ffff -#define AMBI_4ORDER_MASK 0x01ffffff - -/* A bitmask of ambisonic channels with height information. If none of these - * channels are used/needed, there's no height (e.g. with most surround sound - * speaker setups). This is ACN ordering, with bit 0 being ACN 0, etc. - */ -#define AMBI_PERIPHONIC_MASK (0xfe7ce4) - -/* The maximum number of ambisonic channels for 2D (non-periphonic) - * representation. This is 2 per each order above zero-order, plus 1 for zero- - * order. Or simply, o*2 + 1. - */ -constexpr inline size_t Ambi2DChannelsFromOrder(size_t order) noexcept -{ return order*2 + 1; } -#define MAX_AMBI2D_CHANNELS Ambi2DChannelsFromOrder(MAX_AMBI_ORDER) - - -/* NOTE: These are scale factors as applied to Ambisonics content. Decoder - * coefficients should be divided by these values to get proper scalings. - */ -struct AmbiScale { - static constexpr std::array FromN3D{{ - 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f - }}; - static constexpr std::array FromSN3D{{ - 1.000000000f, /* ACN 0, sqrt(1) */ - 1.732050808f, /* ACN 1, sqrt(3) */ - 1.732050808f, /* ACN 2, sqrt(3) */ - 1.732050808f, /* ACN 3, sqrt(3) */ - 2.236067978f, /* ACN 4, sqrt(5) */ - 2.236067978f, /* ACN 5, sqrt(5) */ - 2.236067978f, /* ACN 6, sqrt(5) */ - 2.236067978f, /* ACN 7, sqrt(5) */ - 2.236067978f, /* ACN 8, sqrt(5) */ - 2.645751311f, /* ACN 9, sqrt(7) */ - 2.645751311f, /* ACN 10, sqrt(7) */ - 2.645751311f, /* ACN 11, sqrt(7) */ - 2.645751311f, /* ACN 12, sqrt(7) */ - 2.645751311f, /* ACN 13, sqrt(7) */ - 2.645751311f, /* ACN 14, sqrt(7) */ - 2.645751311f, /* ACN 15, sqrt(7) */ - }}; - static constexpr std::array FromFuMa{{ - 1.414213562f, /* ACN 0 (W), sqrt(2) */ - 1.732050808f, /* ACN 1 (Y), sqrt(3) */ - 1.732050808f, /* ACN 2 (Z), sqrt(3) */ - 1.732050808f, /* ACN 3 (X), sqrt(3) */ - 1.936491673f, /* ACN 4 (V), sqrt(15)/2 */ - 1.936491673f, /* ACN 5 (T), sqrt(15)/2 */ - 2.236067978f, /* ACN 6 (R), sqrt(5) */ - 1.936491673f, /* ACN 7 (S), sqrt(15)/2 */ - 1.936491673f, /* ACN 8 (U), sqrt(15)/2 */ - 2.091650066f, /* ACN 9 (Q), sqrt(35/8) */ - 1.972026594f, /* ACN 10 (O), sqrt(35)/3 */ - 2.231093404f, /* ACN 11 (M), sqrt(224/45) */ - 2.645751311f, /* ACN 12 (K), sqrt(7) */ - 2.231093404f, /* ACN 13 (L), sqrt(224/45) */ - 1.972026594f, /* ACN 14 (N), sqrt(35)/3 */ - 2.091650066f, /* ACN 15 (P), sqrt(35/8) */ - }}; -}; - -struct AmbiIndex { - static constexpr std::array FromFuMa{{ - 0, /* W */ - 3, /* X */ - 1, /* Y */ - 2, /* Z */ - 6, /* R */ - 7, /* S */ - 5, /* T */ - 8, /* U */ - 4, /* V */ - 12, /* K */ - 13, /* L */ - 11, /* M */ - 14, /* N */ - 10, /* O */ - 15, /* P */ - 9, /* Q */ - }}; - static constexpr std::array FromACN{{ - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15 - }}; - - static constexpr std::array From2D{{ - 0, 1,3, 4,8, 9,15 - }}; - static constexpr std::array From3D{{ - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15 - }}; -}; - -#endif /* AMBIDEFS_H */ diff --git a/Alc/backends/alsa.cpp b/Alc/backends/alsa.cpp deleted file mode 100644 index c133df68..00000000 --- a/Alc/backends/alsa.cpp +++ /dev/null @@ -1,1288 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "backends/alsa.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" - -#include "albyte.h" -#include "alcmain.h" -#include "alconfig.h" -#include "almalloc.h" -#include "alnumeric.h" -#include "aloptional.h" -#include "alu.h" -#include "compat.h" -#include "logging.h" -#include "ringbuffer.h" -#include "threads.h" -#include "vector.h" - -#include - - -namespace { - -constexpr ALCchar alsaDevice[] = "ALSA Default"; - - -#ifdef HAVE_DYNLOAD -#define ALSA_FUNCS(MAGIC) \ - MAGIC(snd_strerror); \ - MAGIC(snd_pcm_open); \ - MAGIC(snd_pcm_close); \ - MAGIC(snd_pcm_nonblock); \ - MAGIC(snd_pcm_frames_to_bytes); \ - MAGIC(snd_pcm_bytes_to_frames); \ - MAGIC(snd_pcm_hw_params_malloc); \ - MAGIC(snd_pcm_hw_params_free); \ - MAGIC(snd_pcm_hw_params_any); \ - MAGIC(snd_pcm_hw_params_current); \ - MAGIC(snd_pcm_hw_params_set_access); \ - MAGIC(snd_pcm_hw_params_set_format); \ - MAGIC(snd_pcm_hw_params_set_channels); \ - MAGIC(snd_pcm_hw_params_set_periods_near); \ - MAGIC(snd_pcm_hw_params_set_rate_near); \ - MAGIC(snd_pcm_hw_params_set_rate); \ - MAGIC(snd_pcm_hw_params_set_rate_resample); \ - MAGIC(snd_pcm_hw_params_set_buffer_time_near); \ - MAGIC(snd_pcm_hw_params_set_period_time_near); \ - MAGIC(snd_pcm_hw_params_set_buffer_size_near); \ - MAGIC(snd_pcm_hw_params_set_period_size_near); \ - MAGIC(snd_pcm_hw_params_set_buffer_size_min); \ - MAGIC(snd_pcm_hw_params_get_buffer_time_min); \ - MAGIC(snd_pcm_hw_params_get_buffer_time_max); \ - MAGIC(snd_pcm_hw_params_get_period_time_min); \ - MAGIC(snd_pcm_hw_params_get_period_time_max); \ - MAGIC(snd_pcm_hw_params_get_buffer_size); \ - MAGIC(snd_pcm_hw_params_get_period_size); \ - MAGIC(snd_pcm_hw_params_get_access); \ - MAGIC(snd_pcm_hw_params_get_periods); \ - MAGIC(snd_pcm_hw_params_test_format); \ - MAGIC(snd_pcm_hw_params_test_channels); \ - MAGIC(snd_pcm_hw_params); \ - MAGIC(snd_pcm_sw_params_malloc); \ - MAGIC(snd_pcm_sw_params_current); \ - MAGIC(snd_pcm_sw_params_set_avail_min); \ - MAGIC(snd_pcm_sw_params_set_stop_threshold); \ - MAGIC(snd_pcm_sw_params); \ - MAGIC(snd_pcm_sw_params_free); \ - MAGIC(snd_pcm_prepare); \ - MAGIC(snd_pcm_start); \ - MAGIC(snd_pcm_resume); \ - MAGIC(snd_pcm_reset); \ - MAGIC(snd_pcm_wait); \ - MAGIC(snd_pcm_delay); \ - MAGIC(snd_pcm_state); \ - MAGIC(snd_pcm_avail_update); \ - MAGIC(snd_pcm_areas_silence); \ - MAGIC(snd_pcm_mmap_begin); \ - MAGIC(snd_pcm_mmap_commit); \ - MAGIC(snd_pcm_readi); \ - MAGIC(snd_pcm_writei); \ - MAGIC(snd_pcm_drain); \ - MAGIC(snd_pcm_drop); \ - MAGIC(snd_pcm_recover); \ - MAGIC(snd_pcm_info_malloc); \ - MAGIC(snd_pcm_info_free); \ - MAGIC(snd_pcm_info_set_device); \ - MAGIC(snd_pcm_info_set_subdevice); \ - MAGIC(snd_pcm_info_set_stream); \ - MAGIC(snd_pcm_info_get_name); \ - MAGIC(snd_ctl_pcm_next_device); \ - MAGIC(snd_ctl_pcm_info); \ - MAGIC(snd_ctl_open); \ - MAGIC(snd_ctl_close); \ - MAGIC(snd_ctl_card_info_malloc); \ - MAGIC(snd_ctl_card_info_free); \ - MAGIC(snd_ctl_card_info); \ - MAGIC(snd_ctl_card_info_get_name); \ - MAGIC(snd_ctl_card_info_get_id); \ - MAGIC(snd_card_next); \ - MAGIC(snd_config_update_free_global) - -static void *alsa_handle; -#define MAKE_FUNC(f) decltype(f) * p##f -ALSA_FUNCS(MAKE_FUNC); -#undef MAKE_FUNC - -#ifndef IN_IDE_PARSER -#define snd_strerror psnd_strerror -#define snd_pcm_open psnd_pcm_open -#define snd_pcm_close psnd_pcm_close -#define snd_pcm_nonblock psnd_pcm_nonblock -#define snd_pcm_frames_to_bytes psnd_pcm_frames_to_bytes -#define snd_pcm_bytes_to_frames psnd_pcm_bytes_to_frames -#define snd_pcm_hw_params_malloc psnd_pcm_hw_params_malloc -#define snd_pcm_hw_params_free psnd_pcm_hw_params_free -#define snd_pcm_hw_params_any psnd_pcm_hw_params_any -#define snd_pcm_hw_params_current psnd_pcm_hw_params_current -#define snd_pcm_hw_params_set_access psnd_pcm_hw_params_set_access -#define snd_pcm_hw_params_set_format psnd_pcm_hw_params_set_format -#define snd_pcm_hw_params_set_channels psnd_pcm_hw_params_set_channels -#define snd_pcm_hw_params_set_periods_near psnd_pcm_hw_params_set_periods_near -#define snd_pcm_hw_params_set_rate_near psnd_pcm_hw_params_set_rate_near -#define snd_pcm_hw_params_set_rate psnd_pcm_hw_params_set_rate -#define snd_pcm_hw_params_set_rate_resample psnd_pcm_hw_params_set_rate_resample -#define snd_pcm_hw_params_set_buffer_time_near psnd_pcm_hw_params_set_buffer_time_near -#define snd_pcm_hw_params_set_period_time_near psnd_pcm_hw_params_set_period_time_near -#define snd_pcm_hw_params_set_buffer_size_near psnd_pcm_hw_params_set_buffer_size_near -#define snd_pcm_hw_params_set_period_size_near psnd_pcm_hw_params_set_period_size_near -#define snd_pcm_hw_params_set_buffer_size_min psnd_pcm_hw_params_set_buffer_size_min -#define snd_pcm_hw_params_get_buffer_time_min psnd_pcm_hw_params_get_buffer_time_min -#define snd_pcm_hw_params_get_buffer_time_max psnd_pcm_hw_params_get_buffer_time_max -#define snd_pcm_hw_params_get_period_time_min psnd_pcm_hw_params_get_period_time_min -#define snd_pcm_hw_params_get_period_time_max psnd_pcm_hw_params_get_period_time_max -#define snd_pcm_hw_params_get_buffer_size psnd_pcm_hw_params_get_buffer_size -#define snd_pcm_hw_params_get_period_size psnd_pcm_hw_params_get_period_size -#define snd_pcm_hw_params_get_access psnd_pcm_hw_params_get_access -#define snd_pcm_hw_params_get_periods psnd_pcm_hw_params_get_periods -#define snd_pcm_hw_params_test_format psnd_pcm_hw_params_test_format -#define snd_pcm_hw_params_test_channels psnd_pcm_hw_params_test_channels -#define snd_pcm_hw_params psnd_pcm_hw_params -#define snd_pcm_sw_params_malloc psnd_pcm_sw_params_malloc -#define snd_pcm_sw_params_current psnd_pcm_sw_params_current -#define snd_pcm_sw_params_set_avail_min psnd_pcm_sw_params_set_avail_min -#define snd_pcm_sw_params_set_stop_threshold psnd_pcm_sw_params_set_stop_threshold -#define snd_pcm_sw_params psnd_pcm_sw_params -#define snd_pcm_sw_params_free psnd_pcm_sw_params_free -#define snd_pcm_prepare psnd_pcm_prepare -#define snd_pcm_start psnd_pcm_start -#define snd_pcm_resume psnd_pcm_resume -#define snd_pcm_reset psnd_pcm_reset -#define snd_pcm_wait psnd_pcm_wait -#define snd_pcm_delay psnd_pcm_delay -#define snd_pcm_state psnd_pcm_state -#define snd_pcm_avail_update psnd_pcm_avail_update -#define snd_pcm_areas_silence psnd_pcm_areas_silence -#define snd_pcm_mmap_begin psnd_pcm_mmap_begin -#define snd_pcm_mmap_commit psnd_pcm_mmap_commit -#define snd_pcm_readi psnd_pcm_readi -#define snd_pcm_writei psnd_pcm_writei -#define snd_pcm_drain psnd_pcm_drain -#define snd_pcm_drop psnd_pcm_drop -#define snd_pcm_recover psnd_pcm_recover -#define snd_pcm_info_malloc psnd_pcm_info_malloc -#define snd_pcm_info_free psnd_pcm_info_free -#define snd_pcm_info_set_device psnd_pcm_info_set_device -#define snd_pcm_info_set_subdevice psnd_pcm_info_set_subdevice -#define snd_pcm_info_set_stream psnd_pcm_info_set_stream -#define snd_pcm_info_get_name psnd_pcm_info_get_name -#define snd_ctl_pcm_next_device psnd_ctl_pcm_next_device -#define snd_ctl_pcm_info psnd_ctl_pcm_info -#define snd_ctl_open psnd_ctl_open -#define snd_ctl_close psnd_ctl_close -#define snd_ctl_card_info_malloc psnd_ctl_card_info_malloc -#define snd_ctl_card_info_free psnd_ctl_card_info_free -#define snd_ctl_card_info psnd_ctl_card_info -#define snd_ctl_card_info_get_name psnd_ctl_card_info_get_name -#define snd_ctl_card_info_get_id psnd_ctl_card_info_get_id -#define snd_card_next psnd_card_next -#define snd_config_update_free_global psnd_config_update_free_global -#endif -#endif - - -struct DevMap { - std::string name; - std::string device_name; -}; - -al::vector PlaybackDevices; -al::vector CaptureDevices; - - -const char *prefix_name(snd_pcm_stream_t stream) -{ - assert(stream == SND_PCM_STREAM_PLAYBACK || stream == SND_PCM_STREAM_CAPTURE); - return (stream==SND_PCM_STREAM_PLAYBACK) ? "device-prefix" : "capture-prefix"; -} - -al::vector probe_devices(snd_pcm_stream_t stream) -{ - al::vector devlist; - - snd_ctl_card_info_t *info; - snd_ctl_card_info_malloc(&info); - snd_pcm_info_t *pcminfo; - snd_pcm_info_malloc(&pcminfo); - - devlist.emplace_back(DevMap{alsaDevice, - GetConfigValue(nullptr, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ? "device" : "capture", - "default")}); - - if(stream == SND_PCM_STREAM_PLAYBACK) - { - const char *customdevs; - const char *next{GetConfigValue(nullptr, "alsa", "custom-devices", "")}; - while((customdevs=next) != nullptr && customdevs[0]) - { - next = strchr(customdevs, ';'); - const char *sep{strchr(customdevs, '=')}; - if(!sep) - { - std::string spec{next ? std::string(customdevs, next++) : std::string(customdevs)}; - ERR("Invalid ALSA device specification \"%s\"\n", spec.c_str()); - continue; - } - - const char *oldsep{sep++}; - devlist.emplace_back(DevMap{std::string(customdevs, oldsep), - next ? std::string(sep, next++) : std::string(sep)}); - const auto &entry = devlist.back(); - TRACE("Got device \"%s\", \"%s\"\n", entry.name.c_str(), entry.device_name.c_str()); - } - } - - const std::string main_prefix{ - ConfigValueStr(nullptr, "alsa", prefix_name(stream)).value_or("plughw:")}; - - int card{-1}; - int err{snd_card_next(&card)}; - for(;err >= 0 && card >= 0;err = snd_card_next(&card)) - { - std::string name{"hw:" + std::to_string(card)}; - - snd_ctl_t *handle; - if((err=snd_ctl_open(&handle, name.c_str(), 0)) < 0) - { - ERR("control open (hw:%d): %s\n", card, snd_strerror(err)); - continue; - } - if((err=snd_ctl_card_info(handle, info)) < 0) - { - ERR("control hardware info (hw:%d): %s\n", card, snd_strerror(err)); - snd_ctl_close(handle); - continue; - } - - const char *cardname{snd_ctl_card_info_get_name(info)}; - const char *cardid{snd_ctl_card_info_get_id(info)}; - name = prefix_name(stream); - name += '-'; - name += cardid; - const std::string card_prefix{ - ConfigValueStr(nullptr, "alsa", name.c_str()).value_or(main_prefix)}; - - int dev{-1}; - while(1) - { - if(snd_ctl_pcm_next_device(handle, &dev) < 0) - ERR("snd_ctl_pcm_next_device failed\n"); - if(dev < 0) break; - - snd_pcm_info_set_device(pcminfo, dev); - snd_pcm_info_set_subdevice(pcminfo, 0); - snd_pcm_info_set_stream(pcminfo, stream); - if((err=snd_ctl_pcm_info(handle, pcminfo)) < 0) - { - if(err != -ENOENT) - ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err)); - continue; - } - - /* "prefix-cardid-dev" */ - name = prefix_name(stream); - name += '-'; - name += cardid; - name += '-'; - name += std::to_string(dev); - const std::string device_prefix{ - ConfigValueStr(nullptr, "alsa", name.c_str()).value_or(card_prefix)}; - - /* "CardName, PcmName (CARD=cardid,DEV=dev)" */ - name = cardname; - name += ", "; - name += snd_pcm_info_get_name(pcminfo); - name += " (CARD="; - name += cardid; - name += ",DEV="; - name += std::to_string(dev); - name += ')'; - - /* "devprefixCARD=cardid,DEV=dev" */ - std::string device{device_prefix}; - device += "CARD="; - device += cardid; - device += ",DEV="; - device += std::to_string(dev); - - devlist.emplace_back(DevMap{std::move(name), std::move(device)}); - const auto &entry = devlist.back(); - TRACE("Got device \"%s\", \"%s\"\n", entry.name.c_str(), entry.device_name.c_str()); - } - snd_ctl_close(handle); - } - if(err < 0) - ERR("snd_card_next failed: %s\n", snd_strerror(err)); - - snd_pcm_info_free(pcminfo); - snd_ctl_card_info_free(info); - - return devlist; -} - - -int verify_state(snd_pcm_t *handle) -{ - snd_pcm_state_t state{snd_pcm_state(handle)}; - - int err; - switch(state) - { - case SND_PCM_STATE_OPEN: - case SND_PCM_STATE_SETUP: - case SND_PCM_STATE_PREPARED: - case SND_PCM_STATE_RUNNING: - case SND_PCM_STATE_DRAINING: - case SND_PCM_STATE_PAUSED: - /* All Okay */ - break; - - case SND_PCM_STATE_XRUN: - if((err=snd_pcm_recover(handle, -EPIPE, 1)) < 0) - return err; - break; - case SND_PCM_STATE_SUSPENDED: - if((err=snd_pcm_recover(handle, -ESTRPIPE, 1)) < 0) - return err; - break; - case SND_PCM_STATE_DISCONNECTED: - return -ENODEV; - } - - return state; -} - - -struct AlsaPlayback final : public BackendBase { - AlsaPlayback(ALCdevice *device) noexcept : BackendBase{device} { } - ~AlsaPlayback() override; - - int mixerProc(); - int mixerNoMMapProc(); - - ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; - void stop() override; - - ClockLatency getClockLatency() override; - - snd_pcm_t *mPcmHandle{nullptr}; - - al::vector mBuffer; - - std::atomic mKillNow{true}; - std::thread mThread; - - DEF_NEWDEL(AlsaPlayback) -}; - -AlsaPlayback::~AlsaPlayback() -{ - if(mPcmHandle) - snd_pcm_close(mPcmHandle); - mPcmHandle = nullptr; -} - - -int AlsaPlayback::mixerProc() -{ - SetRTPriority(); - althrd_setname(MIXER_THREAD_NAME); - - const snd_pcm_uframes_t update_size{mDevice->UpdateSize}; - const snd_pcm_uframes_t num_updates{mDevice->BufferSize / update_size}; - while(!mKillNow.load(std::memory_order_acquire)) - { - int state{verify_state(mPcmHandle)}; - if(state < 0) - { - ERR("Invalid state detected: %s\n", snd_strerror(state)); - aluHandleDisconnect(mDevice, "Bad state: %s", snd_strerror(state)); - break; - } - - snd_pcm_sframes_t avail{snd_pcm_avail_update(mPcmHandle)}; - if(avail < 0) - { - ERR("available update failed: %s\n", snd_strerror(avail)); - continue; - } - - if(static_cast(avail) > update_size*(num_updates+1)) - { - WARN("available samples exceeds the buffer size\n"); - snd_pcm_reset(mPcmHandle); - continue; - } - - // make sure there's frames to process - if(static_cast(avail) < update_size) - { - if(state != SND_PCM_STATE_RUNNING) - { - int err{snd_pcm_start(mPcmHandle)}; - if(err < 0) - { - ERR("start failed: %s\n", snd_strerror(err)); - continue; - } - } - if(snd_pcm_wait(mPcmHandle, 1000) == 0) - ERR("Wait timeout... buffer size too low?\n"); - continue; - } - avail -= avail%update_size; - - // it is possible that contiguous areas are smaller, thus we use a loop - lock(); - while(avail > 0) - { - snd_pcm_uframes_t frames{static_cast(avail)}; - - const snd_pcm_channel_area_t *areas{}; - snd_pcm_uframes_t offset{}; - int err{snd_pcm_mmap_begin(mPcmHandle, &areas, &offset, &frames)}; - if(err < 0) - { - ERR("mmap begin error: %s\n", snd_strerror(err)); - break; - } - - char *WritePtr{static_cast(areas->addr) + (offset * areas->step / 8)}; - aluMixData(mDevice, WritePtr, frames); - - snd_pcm_sframes_t commitres{snd_pcm_mmap_commit(mPcmHandle, offset, frames)}; - if(commitres < 0 || (commitres-frames) != 0) - { - ERR("mmap commit error: %s\n", - snd_strerror(commitres >= 0 ? -EPIPE : commitres)); - break; - } - - avail -= frames; - } - unlock(); - } - - return 0; -} - -int AlsaPlayback::mixerNoMMapProc() -{ - SetRTPriority(); - althrd_setname(MIXER_THREAD_NAME); - - const snd_pcm_uframes_t update_size{mDevice->UpdateSize}; - const snd_pcm_uframes_t buffer_size{mDevice->BufferSize}; - while(!mKillNow.load(std::memory_order_acquire)) - { - int state{verify_state(mPcmHandle)}; - if(state < 0) - { - ERR("Invalid state detected: %s\n", snd_strerror(state)); - aluHandleDisconnect(mDevice, "Bad state: %s", snd_strerror(state)); - break; - } - - snd_pcm_sframes_t avail{snd_pcm_avail_update(mPcmHandle)}; - if(avail < 0) - { - ERR("available update failed: %s\n", snd_strerror(avail)); - continue; - } - - if(static_cast(avail) > buffer_size) - { - WARN("available samples exceeds the buffer size\n"); - snd_pcm_reset(mPcmHandle); - continue; - } - - if(static_cast(avail) < update_size) - { - if(state != SND_PCM_STATE_RUNNING) - { - int err{snd_pcm_start(mPcmHandle)}; - if(err < 0) - { - ERR("start failed: %s\n", snd_strerror(err)); - continue; - } - } - if(snd_pcm_wait(mPcmHandle, 1000) == 0) - ERR("Wait timeout... buffer size too low?\n"); - continue; - } - - lock(); - char *WritePtr{mBuffer.data()}; - avail = snd_pcm_bytes_to_frames(mPcmHandle, mBuffer.size()); - aluMixData(mDevice, WritePtr, avail); - while(avail > 0) - { - snd_pcm_sframes_t ret{snd_pcm_writei(mPcmHandle, WritePtr, avail)}; - switch(ret) - { - case -EAGAIN: - continue; -#if ESTRPIPE != EPIPE - case -ESTRPIPE: -#endif - case -EPIPE: - case -EINTR: - ret = snd_pcm_recover(mPcmHandle, ret, 1); - if(ret < 0) - avail = 0; - break; - default: - if(ret >= 0) - { - WritePtr += snd_pcm_frames_to_bytes(mPcmHandle, ret); - avail -= ret; - } - break; - } - if(ret < 0) - { - ret = snd_pcm_prepare(mPcmHandle); - if(ret < 0) break; - } - } - unlock(); - } - - return 0; -} - - -ALCenum AlsaPlayback::open(const ALCchar *name) -{ - const char *driver{}; - if(name) - { - if(PlaybackDevices.empty()) - PlaybackDevices = probe_devices(SND_PCM_STREAM_PLAYBACK); - - auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), - [name](const DevMap &entry) -> bool - { return entry.name == name; } - ); - if(iter == PlaybackDevices.cend()) - return ALC_INVALID_VALUE; - driver = iter->device_name.c_str(); - } - else - { - name = alsaDevice; - driver = GetConfigValue(nullptr, "alsa", "device", "default"); - } - - TRACE("Opening device \"%s\"\n", driver); - int err{snd_pcm_open(&mPcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)}; - if(err < 0) - { - ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(err)); - return ALC_OUT_OF_MEMORY; - } - - /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */ - snd_config_update_free_global(); - - mDevice->DeviceName = name; - - return ALC_NO_ERROR; -} - -ALCboolean AlsaPlayback::reset() -{ - snd_pcm_format_t format{SND_PCM_FORMAT_UNKNOWN}; - switch(mDevice->FmtType) - { - case DevFmtByte: - format = SND_PCM_FORMAT_S8; - break; - case DevFmtUByte: - format = SND_PCM_FORMAT_U8; - break; - case DevFmtShort: - format = SND_PCM_FORMAT_S16; - break; - case DevFmtUShort: - format = SND_PCM_FORMAT_U16; - break; - case DevFmtInt: - format = SND_PCM_FORMAT_S32; - break; - case DevFmtUInt: - format = SND_PCM_FORMAT_U32; - break; - case DevFmtFloat: - format = SND_PCM_FORMAT_FLOAT; - break; - } - - bool allowmmap{!!GetConfigValueBool(mDevice->DeviceName.c_str(), "alsa", "mmap", 1)}; - ALuint periodLen{static_cast(mDevice->UpdateSize * 1000000_u64 / mDevice->Frequency)}; - ALuint bufferLen{static_cast(mDevice->BufferSize * 1000000_u64 / mDevice->Frequency)}; - ALuint rate{mDevice->Frequency}; - - snd_pcm_uframes_t periodSizeInFrames{}; - snd_pcm_uframes_t bufferSizeInFrames{}; - snd_pcm_sw_params_t *sp{}; - snd_pcm_hw_params_t *hp{}; - snd_pcm_access_t access{}; - const char *funcerr{}; - int err{}; - - snd_pcm_hw_params_malloc(&hp); -#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error - CHECK(snd_pcm_hw_params_any(mPcmHandle, hp)); - /* set interleaved access */ - if(!allowmmap || snd_pcm_hw_params_set_access(mPcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) - { - /* No mmap */ - CHECK(snd_pcm_hw_params_set_access(mPcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); - } - /* test and set format (implicitly sets sample bits) */ - if(snd_pcm_hw_params_test_format(mPcmHandle, hp, format) < 0) - { - static const struct { - snd_pcm_format_t format; - DevFmtType fmttype; - } formatlist[] = { - { SND_PCM_FORMAT_FLOAT, DevFmtFloat }, - { SND_PCM_FORMAT_S32, DevFmtInt }, - { SND_PCM_FORMAT_U32, DevFmtUInt }, - { SND_PCM_FORMAT_S16, DevFmtShort }, - { SND_PCM_FORMAT_U16, DevFmtUShort }, - { SND_PCM_FORMAT_S8, DevFmtByte }, - { SND_PCM_FORMAT_U8, DevFmtUByte }, - }; - - for(const auto &fmt : formatlist) - { - format = fmt.format; - if(snd_pcm_hw_params_test_format(mPcmHandle, hp, format) >= 0) - { - mDevice->FmtType = fmt.fmttype; - break; - } - } - } - CHECK(snd_pcm_hw_params_set_format(mPcmHandle, hp, format)); - /* test and set channels (implicitly sets frame bits) */ - if(snd_pcm_hw_params_test_channels(mPcmHandle, hp, mDevice->channelsFromFmt()) < 0) - { - static const DevFmtChannels channellist[] = { - DevFmtStereo, - DevFmtQuad, - DevFmtX51, - DevFmtX71, - DevFmtMono, - }; - - for(const auto &chan : channellist) - { - if(snd_pcm_hw_params_test_channels(mPcmHandle, hp, ChannelsFromDevFmt(chan, 0)) >= 0) - { - mDevice->FmtChans = chan; - mDevice->mAmbiOrder = 0; - break; - } - } - } - CHECK(snd_pcm_hw_params_set_channels(mPcmHandle, hp, mDevice->channelsFromFmt())); - /* set rate (implicitly constrains period/buffer parameters) */ - if(!GetConfigValueBool(mDevice->DeviceName.c_str(), "alsa", "allow-resampler", 0) || - !mDevice->Flags.get()) - { - if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp, 0) < 0) - ERR("Failed to disable ALSA resampler\n"); - } - else if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp, 1) < 0) - ERR("Failed to enable ALSA resampler\n"); - CHECK(snd_pcm_hw_params_set_rate_near(mPcmHandle, hp, &rate, nullptr)); - /* set period time (implicitly constrains period/buffer parameters) */ - if((err=snd_pcm_hw_params_set_period_time_near(mPcmHandle, hp, &periodLen, nullptr)) < 0) - ERR("snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err)); - /* set buffer time (implicitly sets buffer size/bytes/time and period size/bytes) */ - if((err=snd_pcm_hw_params_set_buffer_time_near(mPcmHandle, hp, &bufferLen, nullptr)) < 0) - ERR("snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err)); - /* install and prepare hardware configuration */ - CHECK(snd_pcm_hw_params(mPcmHandle, hp)); - - /* retrieve configuration info */ - CHECK(snd_pcm_hw_params_get_access(hp, &access)); - CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, nullptr)); - CHECK(snd_pcm_hw_params_get_buffer_size(hp, &bufferSizeInFrames)); - snd_pcm_hw_params_free(hp); - hp = nullptr; - - snd_pcm_sw_params_malloc(&sp); - CHECK(snd_pcm_sw_params_current(mPcmHandle, sp)); - CHECK(snd_pcm_sw_params_set_avail_min(mPcmHandle, sp, periodSizeInFrames)); - CHECK(snd_pcm_sw_params_set_stop_threshold(mPcmHandle, sp, bufferSizeInFrames)); - CHECK(snd_pcm_sw_params(mPcmHandle, sp)); -#undef CHECK - snd_pcm_sw_params_free(sp); - sp = nullptr; - - mDevice->BufferSize = bufferSizeInFrames; - mDevice->UpdateSize = periodSizeInFrames; - mDevice->Frequency = rate; - - SetDefaultChannelOrder(mDevice); - - return ALC_TRUE; - -error: - ERR("%s failed: %s\n", funcerr, snd_strerror(err)); - if(hp) snd_pcm_hw_params_free(hp); - if(sp) snd_pcm_sw_params_free(sp); - return ALC_FALSE; -} - -ALCboolean AlsaPlayback::start() -{ - snd_pcm_hw_params_t *hp{}; - snd_pcm_access_t access; - const char *funcerr; - int err; - - snd_pcm_hw_params_malloc(&hp); -#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error - CHECK(snd_pcm_hw_params_current(mPcmHandle, hp)); - /* retrieve configuration info */ - CHECK(snd_pcm_hw_params_get_access(hp, &access)); -#undef CHECK - if(0) - { - error: - ERR("%s failed: %s\n", funcerr, snd_strerror(err)); - if(hp) snd_pcm_hw_params_free(hp); - return ALC_FALSE; - } - snd_pcm_hw_params_free(hp); - hp = nullptr; - - int (AlsaPlayback::*thread_func)(){}; - if(access == SND_PCM_ACCESS_RW_INTERLEAVED) - { - mBuffer.resize(snd_pcm_frames_to_bytes(mPcmHandle, mDevice->UpdateSize)); - thread_func = &AlsaPlayback::mixerNoMMapProc; - } - else - { - err = snd_pcm_prepare(mPcmHandle); - if(err < 0) - { - ERR("snd_pcm_prepare(data->mPcmHandle) failed: %s\n", snd_strerror(err)); - return ALC_FALSE; - } - thread_func = &AlsaPlayback::mixerProc; - } - - try { - mKillNow.store(false, std::memory_order_release); - mThread = std::thread{std::mem_fn(thread_func), this}; - return ALC_TRUE; - } - catch(std::exception& e) { - ERR("Could not create playback thread: %s\n", e.what()); - } - catch(...) { - } - mBuffer.clear(); - return ALC_FALSE; -} - -void AlsaPlayback::stop() -{ - if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) - return; - mThread.join(); - - mBuffer.clear(); -} - -ClockLatency AlsaPlayback::getClockLatency() -{ - ClockLatency ret; - - lock(); - ret.ClockTime = GetDeviceClockTime(mDevice); - snd_pcm_sframes_t delay{}; - int err{snd_pcm_delay(mPcmHandle, &delay)}; - if(err < 0) - { - ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); - delay = 0; - } - ret.Latency = std::chrono::seconds{std::max(0, delay)}; - ret.Latency /= mDevice->Frequency; - unlock(); - - return ret; -} - - -struct AlsaCapture final : public BackendBase { - AlsaCapture(ALCdevice *device) noexcept : BackendBase{device} { } - ~AlsaCapture() override; - - ALCenum open(const ALCchar *name) override; - ALCboolean start() override; - void stop() override; - ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override; - ALCuint availableSamples() override; - ClockLatency getClockLatency() override; - - snd_pcm_t *mPcmHandle{nullptr}; - - al::vector mBuffer; - - bool mDoCapture{false}; - RingBufferPtr mRing{nullptr}; - - snd_pcm_sframes_t mLastAvail{0}; - - DEF_NEWDEL(AlsaCapture) -}; - -AlsaCapture::~AlsaCapture() -{ - if(mPcmHandle) - snd_pcm_close(mPcmHandle); - mPcmHandle = nullptr; -} - - -ALCenum AlsaCapture::open(const ALCchar *name) -{ - const char *driver{}; - if(name) - { - if(CaptureDevices.empty()) - CaptureDevices = probe_devices(SND_PCM_STREAM_CAPTURE); - - auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), - [name](const DevMap &entry) -> bool - { return entry.name == name; } - ); - if(iter == CaptureDevices.cend()) - return ALC_INVALID_VALUE; - driver = iter->device_name.c_str(); - } - else - { - name = alsaDevice; - driver = GetConfigValue(nullptr, "alsa", "capture", "default"); - } - - TRACE("Opening device \"%s\"\n", driver); - int err{snd_pcm_open(&mPcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)}; - if(err < 0) - { - ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err)); - return ALC_INVALID_VALUE; - } - - /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */ - snd_config_update_free_global(); - - snd_pcm_format_t format{SND_PCM_FORMAT_UNKNOWN}; - switch(mDevice->FmtType) - { - case DevFmtByte: - format = SND_PCM_FORMAT_S8; - break; - case DevFmtUByte: - format = SND_PCM_FORMAT_U8; - break; - case DevFmtShort: - format = SND_PCM_FORMAT_S16; - break; - case DevFmtUShort: - format = SND_PCM_FORMAT_U16; - break; - case DevFmtInt: - format = SND_PCM_FORMAT_S32; - break; - case DevFmtUInt: - format = SND_PCM_FORMAT_U32; - break; - case DevFmtFloat: - format = SND_PCM_FORMAT_FLOAT; - break; - } - - snd_pcm_uframes_t bufferSizeInFrames{maxu(mDevice->BufferSize, 100*mDevice->Frequency/1000)}; - snd_pcm_uframes_t periodSizeInFrames{minu(bufferSizeInFrames, 25*mDevice->Frequency/1000)}; - - bool needring{false}; - const char *funcerr{}; - snd_pcm_hw_params_t *hp{}; - snd_pcm_hw_params_malloc(&hp); -#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error - CHECK(snd_pcm_hw_params_any(mPcmHandle, hp)); - /* set interleaved access */ - CHECK(snd_pcm_hw_params_set_access(mPcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); - /* set format (implicitly sets sample bits) */ - CHECK(snd_pcm_hw_params_set_format(mPcmHandle, hp, format)); - /* set channels (implicitly sets frame bits) */ - CHECK(snd_pcm_hw_params_set_channels(mPcmHandle, hp, mDevice->channelsFromFmt())); - /* set rate (implicitly constrains period/buffer parameters) */ - CHECK(snd_pcm_hw_params_set_rate(mPcmHandle, hp, mDevice->Frequency, 0)); - /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ - if(snd_pcm_hw_params_set_buffer_size_min(mPcmHandle, hp, &bufferSizeInFrames) < 0) - { - TRACE("Buffer too large, using intermediate ring buffer\n"); - needring = true; - CHECK(snd_pcm_hw_params_set_buffer_size_near(mPcmHandle, hp, &bufferSizeInFrames)); - } - /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ - CHECK(snd_pcm_hw_params_set_period_size_near(mPcmHandle, hp, &periodSizeInFrames, nullptr)); - /* install and prepare hardware configuration */ - CHECK(snd_pcm_hw_params(mPcmHandle, hp)); - /* retrieve configuration info */ - CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, nullptr)); -#undef CHECK - snd_pcm_hw_params_free(hp); - hp = nullptr; - - if(needring) - { - mRing = CreateRingBuffer(mDevice->BufferSize, mDevice->frameSizeFromFmt(), false); - if(!mRing) - { - ERR("ring buffer create failed\n"); - goto error2; - } - } - - mDevice->DeviceName = name; - - return ALC_NO_ERROR; - -error: - ERR("%s failed: %s\n", funcerr, snd_strerror(err)); - if(hp) snd_pcm_hw_params_free(hp); - -error2: - mRing = nullptr; - snd_pcm_close(mPcmHandle); - mPcmHandle = nullptr; - - return ALC_INVALID_VALUE; -} - - -ALCboolean AlsaCapture::start() -{ - int err{snd_pcm_prepare(mPcmHandle)}; - if(err < 0) - ERR("prepare failed: %s\n", snd_strerror(err)); - else - { - err = snd_pcm_start(mPcmHandle); - if(err < 0) - ERR("start failed: %s\n", snd_strerror(err)); - } - if(err < 0) - { - aluHandleDisconnect(mDevice, "Capture state failure: %s", snd_strerror(err)); - return ALC_FALSE; - } - - mDoCapture = true; - return ALC_TRUE; -} - -void AlsaCapture::stop() -{ - /* OpenAL requires access to unread audio after stopping, but ALSA's - * snd_pcm_drain is unreliable and snd_pcm_drop drops it. Capture what's - * available now so it'll be available later after the drop. - */ - ALCuint avail{availableSamples()}; - if(!mRing && avail > 0) - { - /* The ring buffer implicitly captures when checking availability. - * Direct access needs to explicitly capture it into temp storage. */ - al::vector temp(snd_pcm_frames_to_bytes(mPcmHandle, avail)); - captureSamples(temp.data(), avail); - mBuffer = std::move(temp); - } - int err{snd_pcm_drop(mPcmHandle)}; - if(err < 0) - ERR("drop failed: %s\n", snd_strerror(err)); - mDoCapture = false; -} - -ALCenum AlsaCapture::captureSamples(ALCvoid *buffer, ALCuint samples) -{ - if(mRing) - { - mRing->read(buffer, samples); - return ALC_NO_ERROR; - } - - mLastAvail -= samples; - while(mDevice->Connected.load(std::memory_order_acquire) && samples > 0) - { - snd_pcm_sframes_t amt{0}; - - if(!mBuffer.empty()) - { - /* First get any data stored from the last stop */ - amt = snd_pcm_bytes_to_frames(mPcmHandle, mBuffer.size()); - if(static_cast(amt) > samples) amt = samples; - - amt = snd_pcm_frames_to_bytes(mPcmHandle, amt); - memcpy(buffer, mBuffer.data(), amt); - - mBuffer.erase(mBuffer.begin(), mBuffer.begin()+amt); - amt = snd_pcm_bytes_to_frames(mPcmHandle, amt); - } - else if(mDoCapture) - amt = snd_pcm_readi(mPcmHandle, buffer, samples); - if(amt < 0) - { - ERR("read error: %s\n", snd_strerror(amt)); - - if(amt == -EAGAIN) - continue; - if((amt=snd_pcm_recover(mPcmHandle, amt, 1)) >= 0) - { - amt = snd_pcm_start(mPcmHandle); - if(amt >= 0) - amt = snd_pcm_avail_update(mPcmHandle); - } - if(amt < 0) - { - ERR("restore error: %s\n", snd_strerror(amt)); - aluHandleDisconnect(mDevice, "Capture recovery failure: %s", snd_strerror(amt)); - break; - } - /* If the amount available is less than what's asked, we lost it - * during recovery. So just give silence instead. */ - if(static_cast(amt) < samples) - break; - continue; - } - - buffer = static_cast(buffer) + amt; - samples -= amt; - } - if(samples > 0) - memset(buffer, ((mDevice->FmtType == DevFmtUByte) ? 0x80 : 0), - snd_pcm_frames_to_bytes(mPcmHandle, samples)); - - return ALC_NO_ERROR; -} - -ALCuint AlsaCapture::availableSamples() -{ - snd_pcm_sframes_t avail{0}; - if(mDevice->Connected.load(std::memory_order_acquire) && mDoCapture) - avail = snd_pcm_avail_update(mPcmHandle); - if(avail < 0) - { - ERR("avail update failed: %s\n", snd_strerror(avail)); - - if((avail=snd_pcm_recover(mPcmHandle, avail, 1)) >= 0) - { - if(mDoCapture) - avail = snd_pcm_start(mPcmHandle); - if(avail >= 0) - avail = snd_pcm_avail_update(mPcmHandle); - } - if(avail < 0) - { - ERR("restore error: %s\n", snd_strerror(avail)); - aluHandleDisconnect(mDevice, "Capture recovery failure: %s", snd_strerror(avail)); - } - } - - if(!mRing) - { - if(avail < 0) avail = 0; - avail += snd_pcm_bytes_to_frames(mPcmHandle, mBuffer.size()); - if(avail > mLastAvail) mLastAvail = avail; - return mLastAvail; - } - - while(avail > 0) - { - auto vec = mRing->getWriteVector(); - if(vec.first.len == 0) break; - - snd_pcm_sframes_t amt{std::min(vec.first.len, avail)}; - amt = snd_pcm_readi(mPcmHandle, vec.first.buf, amt); - if(amt < 0) - { - ERR("read error: %s\n", snd_strerror(amt)); - - if(amt == -EAGAIN) - continue; - if((amt=snd_pcm_recover(mPcmHandle, amt, 1)) >= 0) - { - if(mDoCapture) - amt = snd_pcm_start(mPcmHandle); - if(amt >= 0) - amt = snd_pcm_avail_update(mPcmHandle); - } - if(amt < 0) - { - ERR("restore error: %s\n", snd_strerror(amt)); - aluHandleDisconnect(mDevice, "Capture recovery failure: %s", snd_strerror(amt)); - break; - } - avail = amt; - continue; - } - - mRing->writeAdvance(amt); - avail -= amt; - } - - return mRing->readSpace(); -} - -ClockLatency AlsaCapture::getClockLatency() -{ - ClockLatency ret; - - lock(); - ret.ClockTime = GetDeviceClockTime(mDevice); - snd_pcm_sframes_t delay{}; - int err{snd_pcm_delay(mPcmHandle, &delay)}; - if(err < 0) - { - ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); - delay = 0; - } - ret.Latency = std::chrono::seconds{std::max(0, delay)}; - ret.Latency /= mDevice->Frequency; - unlock(); - - return ret; -} - -} // namespace - - -bool AlsaBackendFactory::init() -{ - bool error{false}; - -#ifdef HAVE_DYNLOAD - if(!alsa_handle) - { - std::string missing_funcs; - - alsa_handle = LoadLib("libasound.so.2"); - if(!alsa_handle) - { - WARN("Failed to load %s\n", "libasound.so.2"); - return ALC_FALSE; - } - - error = ALC_FALSE; -#define LOAD_FUNC(f) do { \ - p##f = reinterpret_cast(GetSymbol(alsa_handle, #f)); \ - if(p##f == nullptr) { \ - error = true; \ - missing_funcs += "\n" #f; \ - } \ -} while(0) - ALSA_FUNCS(LOAD_FUNC); -#undef LOAD_FUNC - - if(error) - { - WARN("Missing expected functions:%s\n", missing_funcs.c_str()); - CloseLib(alsa_handle); - alsa_handle = nullptr; - } - } -#endif - - return !error; -} - -bool AlsaBackendFactory::querySupport(BackendType type) -{ return (type == BackendType::Playback || type == BackendType::Capture); } - -void AlsaBackendFactory::probe(DevProbe type, std::string *outnames) -{ - auto add_device = [outnames](const DevMap &entry) -> void - { - /* +1 to also append the null char (to ensure a null-separated list and - * double-null terminated list). - */ - outnames->append(entry.name.c_str(), entry.name.length()+1); - }; - switch(type) - { - case DevProbe::Playback: - PlaybackDevices = probe_devices(SND_PCM_STREAM_PLAYBACK); - std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); - break; - - case DevProbe::Capture: - CaptureDevices = probe_devices(SND_PCM_STREAM_CAPTURE); - std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); - break; - } -} - -BackendPtr AlsaBackendFactory::createBackend(ALCdevice *device, BackendType type) -{ - if(type == BackendType::Playback) - return BackendPtr{new AlsaPlayback{device}}; - if(type == BackendType::Capture) - return BackendPtr{new AlsaCapture{device}}; - return nullptr; -} - -BackendFactory &AlsaBackendFactory::getFactory() -{ - static AlsaBackendFactory factory{}; - return factory; -} diff --git a/Alc/backends/alsa.h b/Alc/backends/alsa.h deleted file mode 100644 index fb9de006..00000000 --- a/Alc/backends/alsa.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef BACKENDS_ALSA_H -#define BACKENDS_ALSA_H - -#include "backends/base.h" - -struct AlsaBackendFactory final : public BackendFactory { -public: - bool init() override; - - bool querySupport(BackendType type) override; - - void probe(DevProbe type, std::string *outnames) override; - - BackendPtr createBackend(ALCdevice *device, BackendType type) override; - - static BackendFactory &getFactory(); -}; - -#endif /* BACKENDS_ALSA_H */ diff --git a/Alc/backends/base.cpp b/Alc/backends/base.cpp deleted file mode 100644 index a7d47c6d..00000000 --- a/Alc/backends/base.cpp +++ /dev/null @@ -1,58 +0,0 @@ - -#include "config.h" - -#include - -#include - -#include "alcmain.h" -#include "alu.h" - -#include "backends/base.h" - - -ClockLatency GetClockLatency(ALCdevice *device) -{ - BackendBase *backend{device->Backend.get()}; - ClockLatency ret{backend->getClockLatency()}; - ret.Latency += device->FixedLatency; - return ret; -} - - -/* BackendBase method implementations. */ -BackendBase::BackendBase(ALCdevice *device) noexcept : mDevice{device} -{ } - -BackendBase::~BackendBase() = default; - -ALCboolean BackendBase::reset() -{ return ALC_FALSE; } - -ALCenum BackendBase::captureSamples(void*, ALCuint) -{ return ALC_INVALID_DEVICE; } - -ALCuint BackendBase::availableSamples() -{ return 0; } - -ClockLatency BackendBase::getClockLatency() -{ - ClockLatency ret; - - ALuint refcount; - do { - while(((refcount=mDevice->MixCount.load(std::memory_order_acquire))&1)) - std::this_thread::yield(); - ret.ClockTime = GetDeviceClockTime(mDevice); - std::atomic_thread_fence(std::memory_order_acquire); - } while(refcount != mDevice->MixCount.load(std::memory_order_relaxed)); - - /* NOTE: The device will generally have about all but one periods filled at - * any given time during playback. Without a more accurate measurement from - * the output, this is an okay approximation. - */ - ret.Latency = std::chrono::seconds{maxi(mDevice->BufferSize-mDevice->UpdateSize, 0)}; - ret.Latency /= mDevice->Frequency; - - return ret; -} diff --git a/Alc/backends/base.h b/Alc/backends/base.h deleted file mode 100644 index 437e31d9..00000000 --- a/Alc/backends/base.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef ALC_BACKENDS_BASE_H -#define ALC_BACKENDS_BASE_H - -#include -#include -#include -#include - -#include "alcmain.h" - - -struct ClockLatency { - std::chrono::nanoseconds ClockTime; - std::chrono::nanoseconds Latency; -}; - -/* Helper to get the current clock time from the device's ClockBase, and - * SamplesDone converted from the sample rate. - */ -inline std::chrono::nanoseconds GetDeviceClockTime(ALCdevice *device) -{ - using std::chrono::seconds; - using std::chrono::nanoseconds; - - auto ns = nanoseconds{seconds{device->SamplesDone}} / device->Frequency; - return device->ClockBase + ns; -} - -ClockLatency GetClockLatency(ALCdevice *device); - -struct BackendBase { - virtual ALCenum open(const ALCchar *name) = 0; - - virtual ALCboolean reset(); - virtual ALCboolean start() = 0; - virtual void stop() = 0; - - virtual ALCenum captureSamples(void *buffer, ALCuint samples); - virtual ALCuint availableSamples(); - - virtual ClockLatency getClockLatency(); - - virtual void lock() { mMutex.lock(); } - virtual void unlock() { mMutex.unlock(); } - - ALCdevice *mDevice; - - std::recursive_mutex mMutex; - - BackendBase(ALCdevice *device) noexcept; - virtual ~BackendBase(); -}; -using BackendPtr = std::unique_ptr; -using BackendUniqueLock = std::unique_lock; -using BackendLockGuard = std::lock_guard; - -enum class BackendType { - Playback, - Capture -}; - -enum class DevProbe { - Playback, - Capture -}; - - -struct BackendFactory { - virtual bool init() = 0; - - virtual bool querySupport(BackendType type) = 0; - - virtual void probe(DevProbe type, std::string *outnames) = 0; - - virtual BackendPtr createBackend(ALCdevice *device, BackendType type) = 0; -}; - -#endif /* ALC_BACKENDS_BASE_H */ diff --git a/Alc/backends/coreaudio.cpp b/Alc/backends/coreaudio.cpp deleted file mode 100644 index b4b46382..00000000 --- a/Alc/backends/coreaudio.cpp +++ /dev/null @@ -1,709 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "backends/coreaudio.h" - -#include -#include -#include - -#include "alcmain.h" -#include "alu.h" -#include "ringbuffer.h" -#include "converter.h" -#include "backends/base.h" - -#include -#include -#include - - -namespace { - -static const ALCchar ca_device[] = "CoreAudio Default"; - - -struct CoreAudioPlayback final : public BackendBase { - CoreAudioPlayback(ALCdevice *device) noexcept : BackendBase{device} { } - ~CoreAudioPlayback() override; - - static OSStatus MixerProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, - AudioBufferList *ioData); - OSStatus MixerProc(AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, - AudioBufferList *ioData); - - ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; - void stop() override; - - AudioUnit mAudioUnit; - - ALuint mFrameSize{0u}; - AudioStreamBasicDescription mFormat{}; // This is the OpenAL format as a CoreAudio ASBD - - DEF_NEWDEL(CoreAudioPlayback) -}; - -CoreAudioPlayback::~CoreAudioPlayback() -{ - AudioUnitUninitialize(mAudioUnit); - AudioComponentInstanceDispose(mAudioUnit); -} - - -OSStatus CoreAudioPlayback::MixerProcC(void *inRefCon, - AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) -{ - return static_cast(inRefCon)->MixerProc(ioActionFlags, inTimeStamp, - inBusNumber, inNumberFrames, ioData); -} - -OSStatus CoreAudioPlayback::MixerProc(AudioUnitRenderActionFlags*, - const AudioTimeStamp*, UInt32, UInt32, AudioBufferList *ioData) -{ - lock(); - aluMixData(mDevice, ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize/mFrameSize); - unlock(); - return noErr; -} - - -ALCenum CoreAudioPlayback::open(const ALCchar *name) -{ - if(!name) - name = ca_device; - else if(strcmp(name, ca_device) != 0) - return ALC_INVALID_VALUE; - - /* open the default output unit */ - AudioComponentDescription desc{}; - desc.componentType = kAudioUnitType_Output; -#if TARGET_OS_IOS - desc.componentSubType = kAudioUnitSubType_RemoteIO; -#else - desc.componentSubType = kAudioUnitSubType_DefaultOutput; -#endif - desc.componentManufacturer = kAudioUnitManufacturer_Apple; - desc.componentFlags = 0; - desc.componentFlagsMask = 0; - - AudioComponent comp{AudioComponentFindNext(NULL, &desc)}; - if(comp == nullptr) - { - ERR("AudioComponentFindNext failed\n"); - return ALC_INVALID_VALUE; - } - - OSStatus err{AudioComponentInstanceNew(comp, &mAudioUnit)}; - if(err != noErr) - { - ERR("AudioComponentInstanceNew failed\n"); - return ALC_INVALID_VALUE; - } - - /* init and start the default audio unit... */ - err = AudioUnitInitialize(mAudioUnit); - if(err != noErr) - { - ERR("AudioUnitInitialize failed\n"); - AudioComponentInstanceDispose(mAudioUnit); - return ALC_INVALID_VALUE; - } - - mDevice->DeviceName = name; - return ALC_NO_ERROR; -} - -ALCboolean CoreAudioPlayback::reset() -{ - OSStatus err{AudioUnitUninitialize(mAudioUnit)}; - if(err != noErr) - ERR("-- AudioUnitUninitialize failed.\n"); - - /* retrieve default output unit's properties (output side) */ - AudioStreamBasicDescription streamFormat{}; - auto size = static_cast(sizeof(AudioStreamBasicDescription)); - err = AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, - 0, &streamFormat, &size); - if(err != noErr || size != sizeof(AudioStreamBasicDescription)) - { - ERR("AudioUnitGetProperty failed\n"); - return ALC_FALSE; - } - -#if 0 - TRACE("Output streamFormat of default output unit -\n"); - TRACE(" streamFormat.mFramesPerPacket = %d\n", streamFormat.mFramesPerPacket); - TRACE(" streamFormat.mChannelsPerFrame = %d\n", streamFormat.mChannelsPerFrame); - TRACE(" streamFormat.mBitsPerChannel = %d\n", streamFormat.mBitsPerChannel); - TRACE(" streamFormat.mBytesPerPacket = %d\n", streamFormat.mBytesPerPacket); - TRACE(" streamFormat.mBytesPerFrame = %d\n", streamFormat.mBytesPerFrame); - TRACE(" streamFormat.mSampleRate = %5.0f\n", streamFormat.mSampleRate); -#endif - - /* set default output unit's input side to match output side */ - err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, - 0, &streamFormat, size); - if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); - return ALC_FALSE; - } - - if(mDevice->Frequency != streamFormat.mSampleRate) - { - mDevice->BufferSize = static_cast(uint64_t{mDevice->BufferSize} * - streamFormat.mSampleRate / mDevice->Frequency); - mDevice->Frequency = streamFormat.mSampleRate; - } - - /* FIXME: How to tell what channels are what in the output device, and how - * to specify what we're giving? eg, 6.0 vs 5.1 */ - switch(streamFormat.mChannelsPerFrame) - { - case 1: - mDevice->FmtChans = DevFmtMono; - break; - case 2: - mDevice->FmtChans = DevFmtStereo; - break; - case 4: - mDevice->FmtChans = DevFmtQuad; - break; - case 6: - mDevice->FmtChans = DevFmtX51; - break; - case 7: - mDevice->FmtChans = DevFmtX61; - break; - case 8: - mDevice->FmtChans = DevFmtX71; - break; - default: - ERR("Unhandled channel count (%d), using Stereo\n", streamFormat.mChannelsPerFrame); - mDevice->FmtChans = DevFmtStereo; - streamFormat.mChannelsPerFrame = 2; - break; - } - SetDefaultWFXChannelOrder(mDevice); - - /* use channel count and sample rate from the default output unit's current - * parameters, but reset everything else */ - streamFormat.mFramesPerPacket = 1; - streamFormat.mFormatFlags = 0; - switch(mDevice->FmtType) - { - case DevFmtUByte: - mDevice->FmtType = DevFmtByte; - /* fall-through */ - case DevFmtByte: - streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; - streamFormat.mBitsPerChannel = 8; - break; - case DevFmtUShort: - mDevice->FmtType = DevFmtShort; - /* fall-through */ - case DevFmtShort: - streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; - streamFormat.mBitsPerChannel = 16; - break; - case DevFmtUInt: - mDevice->FmtType = DevFmtInt; - /* fall-through */ - case DevFmtInt: - streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; - streamFormat.mBitsPerChannel = 32; - break; - case DevFmtFloat: - streamFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat; - streamFormat.mBitsPerChannel = 32; - break; - } - streamFormat.mBytesPerFrame = streamFormat.mChannelsPerFrame * - streamFormat.mBitsPerChannel / 8; - streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame; - streamFormat.mFormatID = kAudioFormatLinearPCM; - streamFormat.mFormatFlags |= kAudioFormatFlagsNativeEndian | - kLinearPCMFormatFlagIsPacked; - - err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, - 0, &streamFormat, sizeof(AudioStreamBasicDescription)); - if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); - return ALC_FALSE; - } - - /* setup callback */ - mFrameSize = mDevice->frameSizeFromFmt(); - AURenderCallbackStruct input{}; - input.inputProc = CoreAudioPlayback::MixerProcC; - input.inputProcRefCon = this; - - err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_SetRenderCallback, - kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct)); - if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); - return ALC_FALSE; - } - - /* init the default audio unit... */ - err = AudioUnitInitialize(mAudioUnit); - if(err != noErr) - { - ERR("AudioUnitInitialize failed\n"); - return ALC_FALSE; - } - - return ALC_TRUE; -} - -ALCboolean CoreAudioPlayback::start() -{ - OSStatus err{AudioOutputUnitStart(mAudioUnit)}; - if(err != noErr) - { - ERR("AudioOutputUnitStart failed\n"); - return ALC_FALSE; - } - return ALC_TRUE; -} - -void CoreAudioPlayback::stop() -{ - OSStatus err{AudioOutputUnitStop(mAudioUnit)}; - if(err != noErr) - ERR("AudioOutputUnitStop failed\n"); -} - - -struct CoreAudioCapture final : public BackendBase { - CoreAudioCapture(ALCdevice *device) noexcept : BackendBase{device} { } - ~CoreAudioCapture() override; - - static OSStatus RecordProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, - AudioBufferList *ioData); - OSStatus RecordProc(AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, - UInt32 inNumberFrames, AudioBufferList *ioData); - - ALCenum open(const ALCchar *name) override; - ALCboolean start() override; - void stop() override; - ALCenum captureSamples(void *buffer, ALCuint samples) override; - ALCuint availableSamples() override; - - AudioUnit mAudioUnit{0}; - - ALuint mFrameSize{0u}; - AudioStreamBasicDescription mFormat{}; // This is the OpenAL format as a CoreAudio ASBD - - SampleConverterPtr mConverter; - - RingBufferPtr mRing{nullptr}; - - DEF_NEWDEL(CoreAudioCapture) -}; - -CoreAudioCapture::~CoreAudioCapture() -{ - if(mAudioUnit) - AudioComponentInstanceDispose(mAudioUnit); - mAudioUnit = 0; -} - - -OSStatus CoreAudioCapture::RecordProcC(void *inRefCon, - AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) -{ - return static_cast(inRefCon)->RecordProc(ioActionFlags, inTimeStamp, - inBusNumber, inNumberFrames, ioData); -} - -OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags*, - const AudioTimeStamp *inTimeStamp, UInt32, UInt32 inNumberFrames, - AudioBufferList*) -{ - AudioUnitRenderActionFlags flags = 0; - union { - ALbyte _[sizeof(AudioBufferList) + sizeof(AudioBuffer)*2]; - AudioBufferList list; - } audiobuf = { { 0 } }; - - auto rec_vec = mRing->getWriteVector(); - inNumberFrames = minz(inNumberFrames, rec_vec.first.len+rec_vec.second.len); - - // Fill the ringbuffer's two segments with data from the input device - if(rec_vec.first.len >= inNumberFrames) - { - audiobuf.list.mNumberBuffers = 1; - audiobuf.list.mBuffers[0].mNumberChannels = mFormat.mChannelsPerFrame; - audiobuf.list.mBuffers[0].mData = rec_vec.first.buf; - audiobuf.list.mBuffers[0].mDataByteSize = inNumberFrames * mFormat.mBytesPerFrame; - } - else - { - const size_t remaining{inNumberFrames-rec_vec.first.len}; - audiobuf.list.mNumberBuffers = 2; - audiobuf.list.mBuffers[0].mNumberChannels = mFormat.mChannelsPerFrame; - audiobuf.list.mBuffers[0].mData = rec_vec.first.buf; - audiobuf.list.mBuffers[0].mDataByteSize = rec_vec.first.len * mFormat.mBytesPerFrame; - audiobuf.list.mBuffers[1].mNumberChannels = mFormat.mChannelsPerFrame; - audiobuf.list.mBuffers[1].mData = rec_vec.second.buf; - audiobuf.list.mBuffers[1].mDataByteSize = remaining * mFormat.mBytesPerFrame; - } - OSStatus err{AudioUnitRender(mAudioUnit, &flags, inTimeStamp, audiobuf.list.mNumberBuffers, - inNumberFrames, &audiobuf.list)}; - if(err != noErr) - { - ERR("AudioUnitRender error: %d\n", err); - return err; - } - - mRing->writeAdvance(inNumberFrames); - return noErr; -} - - -ALCenum CoreAudioCapture::open(const ALCchar *name) -{ - AudioStreamBasicDescription requestedFormat; // The application requested format - AudioStreamBasicDescription hardwareFormat; // The hardware format - AudioStreamBasicDescription outputFormat; // The AudioUnit output format - AURenderCallbackStruct input; - AudioComponentDescription desc; - UInt32 outputFrameCount; - UInt32 propertySize; - AudioObjectPropertyAddress propertyAddress; - UInt32 enableIO; - AudioComponent comp; - OSStatus err; - - if(!name) - name = ca_device; - else if(strcmp(name, ca_device) != 0) - return ALC_INVALID_VALUE; - - desc.componentType = kAudioUnitType_Output; -#if TARGET_OS_IOS - desc.componentSubType = kAudioUnitSubType_RemoteIO; -#else - desc.componentSubType = kAudioUnitSubType_HALOutput; -#endif - desc.componentManufacturer = kAudioUnitManufacturer_Apple; - desc.componentFlags = 0; - desc.componentFlagsMask = 0; - - // Search for component with given description - comp = AudioComponentFindNext(NULL, &desc); - if(comp == NULL) - { - ERR("AudioComponentFindNext failed\n"); - return ALC_INVALID_VALUE; - } - - // Open the component - err = AudioComponentInstanceNew(comp, &mAudioUnit); - if(err != noErr) - { - ERR("AudioComponentInstanceNew failed\n"); - return ALC_INVALID_VALUE; - } - - // Turn off AudioUnit output - enableIO = 0; - err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_EnableIO, - kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint)); - if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); - return ALC_INVALID_VALUE; - } - - // Turn on AudioUnit input - enableIO = 1; - err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_EnableIO, - kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint)); - if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); - return ALC_INVALID_VALUE; - } - -#if !TARGET_OS_IOS - { - // Get the default input device - AudioDeviceID inputDevice = kAudioDeviceUnknown; - - propertySize = sizeof(AudioDeviceID); - propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; - propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; - propertyAddress.mElement = kAudioObjectPropertyElementMaster; - - err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, &inputDevice); - if(err != noErr) - { - ERR("AudioObjectGetPropertyData failed\n"); - return ALC_INVALID_VALUE; - } - if(inputDevice == kAudioDeviceUnknown) - { - ERR("No input device found\n"); - return ALC_INVALID_VALUE; - } - - // Track the input device - err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_CurrentDevice, - kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID)); - if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); - return ALC_INVALID_VALUE; - } - } -#endif - - // set capture callback - input.inputProc = CoreAudioCapture::RecordProcC; - input.inputProcRefCon = this; - - err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_SetInputCallback, - kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct)); - if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); - return ALC_INVALID_VALUE; - } - - // Initialize the device - err = AudioUnitInitialize(mAudioUnit); - if(err != noErr) - { - ERR("AudioUnitInitialize failed\n"); - return ALC_INVALID_VALUE; - } - - // Get the hardware format - propertySize = sizeof(AudioStreamBasicDescription); - err = AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, - 1, &hardwareFormat, &propertySize); - if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription)) - { - ERR("AudioUnitGetProperty failed\n"); - return ALC_INVALID_VALUE; - } - - // Set up the requested format description - switch(mDevice->FmtType) - { - case DevFmtUByte: - requestedFormat.mBitsPerChannel = 8; - requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked; - break; - case DevFmtShort: - requestedFormat.mBitsPerChannel = 16; - requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; - break; - case DevFmtInt: - requestedFormat.mBitsPerChannel = 32; - requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; - break; - case DevFmtFloat: - requestedFormat.mBitsPerChannel = 32; - requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked; - break; - case DevFmtByte: - case DevFmtUShort: - case DevFmtUInt: - ERR("%s samples not supported\n", DevFmtTypeString(mDevice->FmtType)); - return ALC_INVALID_VALUE; - } - - switch(mDevice->FmtChans) - { - case DevFmtMono: - requestedFormat.mChannelsPerFrame = 1; - break; - case DevFmtStereo: - requestedFormat.mChannelsPerFrame = 2; - break; - - case DevFmtQuad: - case DevFmtX51: - case DevFmtX51Rear: - case DevFmtX61: - case DevFmtX71: - case DevFmtAmbi3D: - ERR("%s not supported\n", DevFmtChannelsString(mDevice->FmtChans)); - return ALC_INVALID_VALUE; - } - - requestedFormat.mBytesPerFrame = requestedFormat.mChannelsPerFrame * requestedFormat.mBitsPerChannel / 8; - requestedFormat.mBytesPerPacket = requestedFormat.mBytesPerFrame; - requestedFormat.mSampleRate = mDevice->Frequency; - requestedFormat.mFormatID = kAudioFormatLinearPCM; - requestedFormat.mReserved = 0; - requestedFormat.mFramesPerPacket = 1; - - // save requested format description for later use - mFormat = requestedFormat; - mFrameSize = mDevice->frameSizeFromFmt(); - - // Use intermediate format for sample rate conversion (outputFormat) - // Set sample rate to the same as hardware for resampling later - outputFormat = requestedFormat; - outputFormat.mSampleRate = hardwareFormat.mSampleRate; - - // The output format should be the requested format, but using the hardware sample rate - // This is because the AudioUnit will automatically scale other properties, except for sample rate - err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, - 1, (void*)&outputFormat, sizeof(outputFormat)); - if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); - return ALC_INVALID_VALUE; - } - - // Set the AudioUnit output format frame count - uint64_t FrameCount64{mDevice->UpdateSize}; - FrameCount64 = (FrameCount64*outputFormat.mSampleRate + mDevice->Frequency-1) / - mDevice->Frequency; - FrameCount64 += MAX_RESAMPLE_PADDING*2; - if(FrameCount64 > std::numeric_limits::max()/2) - { - ERR("FrameCount too large\n"); - return ALC_INVALID_VALUE; - } - - outputFrameCount = static_cast(FrameCount64); - err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_MaximumFramesPerSlice, - kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount)); - if(err != noErr) - { - ERR("AudioUnitSetProperty failed: %d\n", err); - return ALC_INVALID_VALUE; - } - - // Set up sample converter if needed - if(outputFormat.mSampleRate != mDevice->Frequency) - mConverter = CreateSampleConverter(mDevice->FmtType, mDevice->FmtType, - mFormat.mChannelsPerFrame, hardwareFormat.mSampleRate, mDevice->Frequency, - BSinc24Resampler); - - mRing = CreateRingBuffer(outputFrameCount, mFrameSize, false); - if(!mRing) return ALC_INVALID_VALUE; - - mDevice->DeviceName = name; - return ALC_NO_ERROR; -} - - -ALCboolean CoreAudioCapture::start() -{ - OSStatus err{AudioOutputUnitStart(mAudioUnit)}; - if(err != noErr) - { - ERR("AudioOutputUnitStart failed\n"); - return ALC_FALSE; - } - return ALC_TRUE; -} - -void CoreAudioCapture::stop() -{ - OSStatus err{AudioOutputUnitStop(mAudioUnit)}; - if(err != noErr) - ERR("AudioOutputUnitStop failed\n"); -} - -ALCenum CoreAudioCapture::captureSamples(void *buffer, ALCuint samples) -{ - if(!mConverter) - { - mRing->read(buffer, samples); - return ALC_NO_ERROR; - } - - auto rec_vec = mRing->getReadVector(); - const void *src0{rec_vec.first.buf}; - auto src0len = static_cast(rec_vec.first.len); - auto got = static_cast(mConverter->convert(&src0, &src0len, buffer, samples)); - size_t total_read{rec_vec.first.len - src0len}; - if(got < samples && !src0len && rec_vec.second.len > 0) - { - const void *src1{rec_vec.second.buf}; - auto src1len = static_cast(rec_vec.second.len); - got += static_cast(mConverter->convert(&src1, &src1len, - static_cast(buffer)+got, samples-got)); - total_read += rec_vec.second.len - src1len; - } - - mRing->readAdvance(total_read); - return ALC_NO_ERROR; -} - -ALCuint CoreAudioCapture::availableSamples() -{ - if(!mConverter) return mRing->readSpace(); - return mConverter->availableOut(mRing->readSpace()); -} - -} // namespace - -BackendFactory &CoreAudioBackendFactory::getFactory() -{ - static CoreAudioBackendFactory factory{}; - return factory; -} - -bool CoreAudioBackendFactory::init() { return true; } - -bool CoreAudioBackendFactory::querySupport(BackendType type) -{ return type == BackendType::Playback || type == BackendType::Capture; } - -void CoreAudioBackendFactory::probe(DevProbe type, std::string *outnames) -{ - switch(type) - { - case DevProbe::Playback: - case DevProbe::Capture: - /* Includes null char. */ - outnames->append(ca_device, sizeof(ca_device)); - break; - } -} - -BackendPtr CoreAudioBackendFactory::createBackend(ALCdevice *device, BackendType type) -{ - if(type == BackendType::Playback) - return BackendPtr{new CoreAudioPlayback{device}}; - if(type == BackendType::Capture) - return BackendPtr{new CoreAudioCapture{device}}; - return nullptr; -} diff --git a/Alc/backends/coreaudio.h b/Alc/backends/coreaudio.h deleted file mode 100644 index 37b9ebe5..00000000 --- a/Alc/backends/coreaudio.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef BACKENDS_COREAUDIO_H -#define BACKENDS_COREAUDIO_H - -#include "backends/base.h" - -struct CoreAudioBackendFactory final : public BackendFactory { -public: - bool init() override; - - bool querySupport(BackendType type) override; - - void probe(DevProbe type, std::string *outnames) override; - - BackendPtr createBackend(ALCdevice *device, BackendType type) override; - - static BackendFactory &getFactory(); -}; - -#endif /* BACKENDS_COREAUDIO_H */ diff --git a/Alc/backends/dsound.cpp b/Alc/backends/dsound.cpp deleted file mode 100644 index 5a156d54..00000000 --- a/Alc/backends/dsound.cpp +++ /dev/null @@ -1,938 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "backends/dsound.h" - -#define WIN32_LEAN_AND_MEAN -#include - -#include -#include -#include - -#include -#include -#ifndef _WAVEFORMATEXTENSIBLE_ -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "alcmain.h" -#include "alu.h" -#include "ringbuffer.h" -#include "compat.h" -#include "threads.h" - -/* MinGW-w64 needs this for some unknown reason now. */ -using LPCWAVEFORMATEX = const WAVEFORMATEX*; -#include - - -#ifndef DSSPEAKER_5POINT1 -# define DSSPEAKER_5POINT1 0x00000006 -#endif -#ifndef DSSPEAKER_5POINT1_BACK -# define DSSPEAKER_5POINT1_BACK 0x00000006 -#endif -#ifndef DSSPEAKER_7POINT1 -# define DSSPEAKER_7POINT1 0x00000007 -#endif -#ifndef DSSPEAKER_7POINT1_SURROUND -# define DSSPEAKER_7POINT1_SURROUND 0x00000008 -#endif -#ifndef DSSPEAKER_5POINT1_SURROUND -# define DSSPEAKER_5POINT1_SURROUND 0x00000009 -#endif - - -/* Some headers seem to define these as macros for __uuidof, which is annoying - * since some headers don't declare them at all. Hopefully the ifdef is enough - * to tell if they need to be declared. - */ -#ifndef KSDATAFORMAT_SUBTYPE_PCM -DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); -#endif -#ifndef KSDATAFORMAT_SUBTYPE_IEEE_FLOAT -DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); -#endif - -namespace { - -#define DEVNAME_HEAD "OpenAL Soft on " - - -#ifdef HAVE_DYNLOAD -void *ds_handle; -HRESULT (WINAPI *pDirectSoundCreate)(const GUID *pcGuidDevice, IDirectSound **ppDS, IUnknown *pUnkOuter); -HRESULT (WINAPI *pDirectSoundEnumerateW)(LPDSENUMCALLBACKW pDSEnumCallback, void *pContext); -HRESULT (WINAPI *pDirectSoundCaptureCreate)(const GUID *pcGuidDevice, IDirectSoundCapture **ppDSC, IUnknown *pUnkOuter); -HRESULT (WINAPI *pDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW pDSEnumCallback, void *pContext); - -#ifndef IN_IDE_PARSER -#define DirectSoundCreate pDirectSoundCreate -#define DirectSoundEnumerateW pDirectSoundEnumerateW -#define DirectSoundCaptureCreate pDirectSoundCaptureCreate -#define DirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW -#endif -#endif - - -#define MAX_UPDATES 128 - -struct DevMap { - std::string name; - GUID guid; - - template - DevMap(T0&& name_, T1&& guid_) - : name{std::forward(name_)}, guid{std::forward(guid_)} - { } -}; - -al::vector PlaybackDevices; -al::vector CaptureDevices; - -bool checkName(const al::vector &list, const std::string &name) -{ - return std::find_if(list.cbegin(), list.cend(), - [&name](const DevMap &entry) -> bool - { return entry.name == name; } - ) != list.cend(); -} - -BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR*, void *data) -{ - if(!guid) - return TRUE; - - auto& devices = *static_cast*>(data); - const std::string basename{DEVNAME_HEAD + wstr_to_utf8(desc)}; - - int count{1}; - std::string newname{basename}; - while(checkName(devices, newname)) - { - newname = basename; - newname += " #"; - newname += std::to_string(++count); - } - devices.emplace_back(std::move(newname), *guid); - const DevMap &newentry = devices.back(); - - OLECHAR *guidstr{nullptr}; - HRESULT hr{StringFromCLSID(*guid, &guidstr)}; - if(SUCCEEDED(hr)) - { - TRACE("Got device \"%s\", GUID \"%ls\"\n", newentry.name.c_str(), guidstr); - CoTaskMemFree(guidstr); - } - - return TRUE; -} - - -struct DSoundPlayback final : public BackendBase { - DSoundPlayback(ALCdevice *device) noexcept : BackendBase{device} { } - ~DSoundPlayback() override; - - int mixerProc(); - - ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; - void stop() override; - - IDirectSound *mDS{nullptr}; - IDirectSoundBuffer *mPrimaryBuffer{nullptr}; - IDirectSoundBuffer *mBuffer{nullptr}; - IDirectSoundNotify *mNotifies{nullptr}; - HANDLE mNotifyEvent{nullptr}; - - std::atomic mKillNow{true}; - std::thread mThread; - - DEF_NEWDEL(DSoundPlayback) -}; - -DSoundPlayback::~DSoundPlayback() -{ - if(mNotifies) - mNotifies->Release(); - mNotifies = nullptr; - if(mBuffer) - mBuffer->Release(); - mBuffer = nullptr; - if(mPrimaryBuffer) - mPrimaryBuffer->Release(); - mPrimaryBuffer = nullptr; - - if(mDS) - mDS->Release(); - mDS = nullptr; - if(mNotifyEvent) - CloseHandle(mNotifyEvent); - mNotifyEvent = nullptr; -} - - -FORCE_ALIGN int DSoundPlayback::mixerProc() -{ - SetRTPriority(); - althrd_setname(MIXER_THREAD_NAME); - - DSBCAPS DSBCaps{}; - DSBCaps.dwSize = sizeof(DSBCaps); - HRESULT err{mBuffer->GetCaps(&DSBCaps)}; - if(FAILED(err)) - { - ERR("Failed to get buffer caps: 0x%lx\n", err); - aluHandleDisconnect(mDevice, "Failure retrieving playback buffer info: 0x%lx", err); - return 1; - } - - ALsizei FrameSize{mDevice->frameSizeFromFmt()}; - DWORD FragSize{mDevice->UpdateSize * FrameSize}; - - bool Playing{false}; - DWORD LastCursor{0u}; - mBuffer->GetCurrentPosition(&LastCursor, nullptr); - while(!mKillNow.load(std::memory_order_acquire) && - mDevice->Connected.load(std::memory_order_acquire)) - { - // Get current play cursor - DWORD PlayCursor; - mBuffer->GetCurrentPosition(&PlayCursor, nullptr); - DWORD avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes; - - if(avail < FragSize) - { - if(!Playing) - { - err = mBuffer->Play(0, 0, DSBPLAY_LOOPING); - if(FAILED(err)) - { - ERR("Failed to play buffer: 0x%lx\n", err); - aluHandleDisconnect(mDevice, "Failure starting playback: 0x%lx", err); - return 1; - } - Playing = true; - } - - avail = WaitForSingleObjectEx(mNotifyEvent, 2000, FALSE); - if(avail != WAIT_OBJECT_0) - ERR("WaitForSingleObjectEx error: 0x%lx\n", avail); - continue; - } - avail -= avail%FragSize; - - // Lock output buffer - void *WritePtr1, *WritePtr2; - DWORD WriteCnt1{0u}, WriteCnt2{0u}; - err = mBuffer->Lock(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 = mBuffer->Restore(); - if(SUCCEEDED(err)) - { - Playing = false; - LastCursor = 0; - err = mBuffer->Lock(0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, - &WritePtr2, &WriteCnt2, 0); - } - } - - if(SUCCEEDED(err)) - { - lock(); - aluMixData(mDevice, WritePtr1, WriteCnt1/FrameSize); - if(WriteCnt2 > 0) - aluMixData(mDevice, WritePtr2, WriteCnt2/FrameSize); - unlock(); - - mBuffer->Unlock(WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); - } - else - { - ERR("Buffer lock error: %#lx\n", err); - aluHandleDisconnect(mDevice, "Failed to lock output buffer: 0x%lx", err); - return 1; - } - - // Update old write cursor location - LastCursor += WriteCnt1+WriteCnt2; - LastCursor %= DSBCaps.dwBufferBytes; - } - - return 0; -} - -ALCenum DSoundPlayback::open(const ALCchar *name) -{ - HRESULT hr; - if(PlaybackDevices.empty()) - { - /* Initialize COM to prevent name truncation */ - HRESULT hrcom{CoInitialize(nullptr)}; - hr = DirectSoundEnumerateW(DSoundEnumDevices, &PlaybackDevices); - if(FAILED(hr)) - ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr); - if(SUCCEEDED(hrcom)) - CoUninitialize(); - } - - const GUID *guid{nullptr}; - if(!name && !PlaybackDevices.empty()) - { - name = PlaybackDevices[0].name.c_str(); - guid = &PlaybackDevices[0].guid; - } - else - { - auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), - [name](const DevMap &entry) -> bool - { return entry.name == name; } - ); - if(iter == PlaybackDevices.cend()) - return ALC_INVALID_VALUE; - guid = &iter->guid; - } - - hr = DS_OK; - mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - if(!mNotifyEvent) hr = E_FAIL; - - //DirectSound Init code - if(SUCCEEDED(hr)) - hr = DirectSoundCreate(guid, &mDS, nullptr); - if(SUCCEEDED(hr)) - hr = mDS->SetCooperativeLevel(GetForegroundWindow(), DSSCL_PRIORITY); - if(FAILED(hr)) - { - ERR("Device init failed: 0x%08lx\n", hr); - return ALC_INVALID_VALUE; - } - - mDevice->DeviceName = name; - return ALC_NO_ERROR; -} - -ALCboolean DSoundPlayback::reset() -{ - if(mNotifies) - mNotifies->Release(); - mNotifies = nullptr; - if(mBuffer) - mBuffer->Release(); - mBuffer = nullptr; - if(mPrimaryBuffer) - mPrimaryBuffer->Release(); - mPrimaryBuffer = nullptr; - - switch(mDevice->FmtType) - { - case DevFmtByte: - mDevice->FmtType = DevFmtUByte; - break; - case DevFmtFloat: - if(mDevice->Flags.get()) - break; - /* fall-through */ - case DevFmtUShort: - mDevice->FmtType = DevFmtShort; - break; - case DevFmtUInt: - mDevice->FmtType = DevFmtInt; - break; - case DevFmtUByte: - case DevFmtShort: - case DevFmtInt: - break; - } - - WAVEFORMATEXTENSIBLE OutputType{}; - DWORD speakers; - HRESULT hr{mDS->GetSpeakerConfig(&speakers)}; - if(SUCCEEDED(hr)) - { - speakers = DSSPEAKER_CONFIG(speakers); - if(!mDevice->Flags.get()) - { - if(speakers == DSSPEAKER_MONO) - mDevice->FmtChans = DevFmtMono; - else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE) - mDevice->FmtChans = DevFmtStereo; - else if(speakers == DSSPEAKER_QUAD) - mDevice->FmtChans = DevFmtQuad; - else if(speakers == DSSPEAKER_5POINT1_SURROUND) - mDevice->FmtChans = DevFmtX51; - else if(speakers == DSSPEAKER_5POINT1_BACK) - mDevice->FmtChans = DevFmtX51Rear; - else if(speakers == DSSPEAKER_7POINT1 || speakers == DSSPEAKER_7POINT1_SURROUND) - mDevice->FmtChans = DevFmtX71; - else - ERR("Unknown system speaker config: 0x%lx\n", speakers); - } - mDevice->IsHeadphones = (mDevice->FmtChans == DevFmtStereo && - speakers == DSSPEAKER_HEADPHONE); - - switch(mDevice->FmtChans) - { - case DevFmtMono: - OutputType.dwChannelMask = SPEAKER_FRONT_CENTER; - break; - case DevFmtAmbi3D: - mDevice->FmtChans = DevFmtStereo; - /*fall-through*/ - case DevFmtStereo: - OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT; - break; - case DevFmtQuad: - OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_BACK_LEFT | - SPEAKER_BACK_RIGHT; - break; - case DevFmtX51: - OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_SIDE_LEFT | - SPEAKER_SIDE_RIGHT; - break; - case DevFmtX51Rear: - OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_BACK_LEFT | - SPEAKER_BACK_RIGHT; - break; - case DevFmtX61: - OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_BACK_CENTER | - SPEAKER_SIDE_LEFT | - SPEAKER_SIDE_RIGHT; - break; - case DevFmtX71: - OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_BACK_LEFT | - SPEAKER_BACK_RIGHT | - SPEAKER_SIDE_LEFT | - SPEAKER_SIDE_RIGHT; - break; - } - -retry_open: - hr = S_OK; - OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; - OutputType.Format.nChannels = mDevice->channelsFromFmt(); - OutputType.Format.wBitsPerSample = mDevice->bytesFromFmt() * 8; - OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8; - OutputType.Format.nSamplesPerSec = mDevice->Frequency; - OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign; - OutputType.Format.cbSize = 0; - } - - if(OutputType.Format.nChannels > 2 || mDevice->FmtType == DevFmtFloat) - { - OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; - OutputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); - if(mDevice->FmtType == DevFmtFloat) - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - else - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - - if(mPrimaryBuffer) - mPrimaryBuffer->Release(); - mPrimaryBuffer = nullptr; - } - else - { - if(SUCCEEDED(hr) && !mPrimaryBuffer) - { - DSBUFFERDESC DSBDescription{}; - DSBDescription.dwSize = sizeof(DSBDescription); - DSBDescription.dwFlags = DSBCAPS_PRIMARYBUFFER; - hr = mDS->CreateSoundBuffer(&DSBDescription, &mPrimaryBuffer, nullptr); - } - if(SUCCEEDED(hr)) - hr = mPrimaryBuffer->SetFormat(&OutputType.Format); - } - - if(SUCCEEDED(hr)) - { - ALuint num_updates{mDevice->BufferSize / mDevice->UpdateSize}; - if(num_updates > MAX_UPDATES) - num_updates = MAX_UPDATES; - mDevice->BufferSize = mDevice->UpdateSize * num_updates; - - DSBUFFERDESC DSBDescription{}; - DSBDescription.dwSize = sizeof(DSBDescription); - DSBDescription.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2 | - DSBCAPS_GLOBALFOCUS; - DSBDescription.dwBufferBytes = mDevice->BufferSize * OutputType.Format.nBlockAlign; - DSBDescription.lpwfxFormat = &OutputType.Format; - - hr = mDS->CreateSoundBuffer(&DSBDescription, &mBuffer, nullptr); - if(FAILED(hr) && mDevice->FmtType == DevFmtFloat) - { - mDevice->FmtType = DevFmtShort; - goto retry_open; - } - } - - if(SUCCEEDED(hr)) - { - void *ptr; - hr = mBuffer->QueryInterface(IID_IDirectSoundNotify, &ptr); - if(SUCCEEDED(hr)) - { - auto Notifies = static_cast(ptr); - mNotifies = Notifies; - - ALuint num_updates{mDevice->BufferSize / mDevice->UpdateSize}; - assert(num_updates <= MAX_UPDATES); - - std::array nots; - for(ALuint i{0};i < num_updates;++i) - { - nots[i].dwOffset = i * mDevice->UpdateSize * OutputType.Format.nBlockAlign; - nots[i].hEventNotify = mNotifyEvent; - } - if(Notifies->SetNotificationPositions(num_updates, nots.data()) != DS_OK) - hr = E_FAIL; - } - } - - if(FAILED(hr)) - { - if(mNotifies) - mNotifies->Release(); - mNotifies = nullptr; - if(mBuffer) - mBuffer->Release(); - mBuffer = nullptr; - if(mPrimaryBuffer) - mPrimaryBuffer->Release(); - mPrimaryBuffer = nullptr; - return ALC_FALSE; - } - - ResetEvent(mNotifyEvent); - SetDefaultWFXChannelOrder(mDevice); - - return ALC_TRUE; -} - -ALCboolean DSoundPlayback::start() -{ - try { - mKillNow.store(false, std::memory_order_release); - mThread = std::thread{std::mem_fn(&DSoundPlayback::mixerProc), this}; - return ALC_TRUE; - } - catch(std::exception& e) { - ERR("Failed to start mixing thread: %s\n", e.what()); - } - catch(...) { - } - return ALC_FALSE; -} - -void DSoundPlayback::stop() -{ - if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) - return; - mThread.join(); - - mBuffer->Stop(); -} - - -struct DSoundCapture final : public BackendBase { - DSoundCapture(ALCdevice *device) noexcept : BackendBase{device} { } - ~DSoundCapture() override; - - ALCenum open(const ALCchar *name) override; - ALCboolean start() override; - void stop() override; - ALCenum captureSamples(void *buffer, ALCuint samples) override; - ALCuint availableSamples() override; - - IDirectSoundCapture *mDSC{nullptr}; - IDirectSoundCaptureBuffer *mDSCbuffer{nullptr}; - DWORD mBufferBytes{0u}; - DWORD mCursor{0u}; - - RingBufferPtr mRing; - - DEF_NEWDEL(DSoundCapture) -}; - -DSoundCapture::~DSoundCapture() -{ - if(mDSCbuffer) - { - mDSCbuffer->Stop(); - mDSCbuffer->Release(); - mDSCbuffer = nullptr; - } - - if(mDSC) - mDSC->Release(); - mDSC = nullptr; -} - - -ALCenum DSoundCapture::open(const ALCchar *name) -{ - HRESULT hr; - if(CaptureDevices.empty()) - { - /* Initialize COM to prevent name truncation */ - HRESULT hrcom{CoInitialize(nullptr)}; - hr = DirectSoundCaptureEnumerateW(DSoundEnumDevices, &CaptureDevices); - if(FAILED(hr)) - ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr); - if(SUCCEEDED(hrcom)) - CoUninitialize(); - } - - const GUID *guid{nullptr}; - if(!name && !CaptureDevices.empty()) - { - name = CaptureDevices[0].name.c_str(); - guid = &CaptureDevices[0].guid; - } - else - { - auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), - [name](const DevMap &entry) -> bool - { return entry.name == name; } - ); - if(iter == CaptureDevices.cend()) - return ALC_INVALID_VALUE; - guid = &iter->guid; - } - - switch(mDevice->FmtType) - { - case DevFmtByte: - case DevFmtUShort: - case DevFmtUInt: - WARN("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); - return ALC_INVALID_ENUM; - - case DevFmtUByte: - case DevFmtShort: - case DevFmtInt: - case DevFmtFloat: - break; - } - - WAVEFORMATEXTENSIBLE InputType{}; - switch(mDevice->FmtChans) - { - case DevFmtMono: - InputType.dwChannelMask = SPEAKER_FRONT_CENTER; - break; - case DevFmtStereo: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT; - break; - case DevFmtQuad: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_BACK_LEFT | - SPEAKER_BACK_RIGHT; - break; - case DevFmtX51: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_SIDE_LEFT | - SPEAKER_SIDE_RIGHT; - break; - case DevFmtX51Rear: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_BACK_LEFT | - SPEAKER_BACK_RIGHT; - break; - case DevFmtX61: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_BACK_CENTER | - SPEAKER_SIDE_LEFT | - SPEAKER_SIDE_RIGHT; - break; - case DevFmtX71: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_BACK_LEFT | - SPEAKER_BACK_RIGHT | - SPEAKER_SIDE_LEFT | - SPEAKER_SIDE_RIGHT; - break; - case DevFmtAmbi3D: - WARN("%s capture not supported\n", DevFmtChannelsString(mDevice->FmtChans)); - return ALC_INVALID_ENUM; - } - - InputType.Format.wFormatTag = WAVE_FORMAT_PCM; - InputType.Format.nChannels = mDevice->channelsFromFmt(); - InputType.Format.wBitsPerSample = mDevice->bytesFromFmt() * 8; - InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8; - InputType.Format.nSamplesPerSec = mDevice->Frequency; - InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign; - InputType.Format.cbSize = 0; - InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample; - if(mDevice->FmtType == DevFmtFloat) - InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - else - InputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - - if(InputType.Format.nChannels > 2 || mDevice->FmtType == DevFmtFloat) - { - InputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); - } - - ALuint samples{mDevice->BufferSize}; - samples = maxu(samples, 100 * mDevice->Frequency / 1000); - - DSCBUFFERDESC DSCBDescription{}; - DSCBDescription.dwSize = sizeof(DSCBDescription); - DSCBDescription.dwFlags = 0; - DSCBDescription.dwBufferBytes = samples * InputType.Format.nBlockAlign; - DSCBDescription.lpwfxFormat = &InputType.Format; - - //DirectSoundCapture Init code - hr = DirectSoundCaptureCreate(guid, &mDSC, nullptr); - if(SUCCEEDED(hr)) - mDSC->CreateCaptureBuffer(&DSCBDescription, &mDSCbuffer, nullptr); - if(SUCCEEDED(hr)) - { - mRing = CreateRingBuffer(mDevice->BufferSize, InputType.Format.nBlockAlign, false); - if(!mRing) hr = DSERR_OUTOFMEMORY; - } - - if(FAILED(hr)) - { - ERR("Device init failed: 0x%08lx\n", hr); - - mRing = nullptr; - if(mDSCbuffer) - mDSCbuffer->Release(); - mDSCbuffer = nullptr; - if(mDSC) - mDSC->Release(); - mDSC = nullptr; - - return ALC_INVALID_VALUE; - } - - mBufferBytes = DSCBDescription.dwBufferBytes; - SetDefaultWFXChannelOrder(mDevice); - - mDevice->DeviceName = name; - return ALC_NO_ERROR; -} - -ALCboolean DSoundCapture::start() -{ - HRESULT hr{mDSCbuffer->Start(DSCBSTART_LOOPING)}; - if(FAILED(hr)) - { - ERR("start failed: 0x%08lx\n", hr); - aluHandleDisconnect(mDevice, "Failure starting capture: 0x%lx", hr); - return ALC_FALSE; - } - return ALC_TRUE; -} - -void DSoundCapture::stop() -{ - HRESULT hr{mDSCbuffer->Stop()}; - if(FAILED(hr)) - { - ERR("stop failed: 0x%08lx\n", hr); - aluHandleDisconnect(mDevice, "Failure stopping capture: 0x%lx", hr); - } -} - -ALCenum DSoundCapture::captureSamples(void *buffer, ALCuint samples) -{ - mRing->read(buffer, samples); - return ALC_NO_ERROR; -} - -ALCuint DSoundCapture::availableSamples() -{ - if(!mDevice->Connected.load(std::memory_order_acquire)) - return static_cast(mRing->readSpace()); - - ALsizei FrameSize{mDevice->frameSizeFromFmt()}; - DWORD BufferBytes{mBufferBytes}; - DWORD LastCursor{mCursor}; - - DWORD ReadCursor; - void *ReadPtr1, *ReadPtr2; - DWORD ReadCnt1, ReadCnt2; - HRESULT hr{mDSCbuffer->GetCurrentPosition(nullptr, &ReadCursor)}; - if(SUCCEEDED(hr)) - { - DWORD NumBytes{(ReadCursor-LastCursor + BufferBytes) % BufferBytes}; - if(!NumBytes) return static_cast(mRing->readSpace()); - hr = mDSCbuffer->Lock(LastCursor, NumBytes, &ReadPtr1, &ReadCnt1, &ReadPtr2, &ReadCnt2, 0); - } - if(SUCCEEDED(hr)) - { - mRing->write(ReadPtr1, ReadCnt1/FrameSize); - if(ReadPtr2 != nullptr && ReadCnt2 > 0) - mRing->write(ReadPtr2, ReadCnt2/FrameSize); - hr = mDSCbuffer->Unlock(ReadPtr1, ReadCnt1, ReadPtr2, ReadCnt2); - mCursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes; - } - - if(FAILED(hr)) - { - ERR("update failed: 0x%08lx\n", hr); - aluHandleDisconnect(mDevice, "Failure retrieving capture data: 0x%lx", hr); - } - - return static_cast(mRing->readSpace()); -} - -} // namespace - - -BackendFactory &DSoundBackendFactory::getFactory() -{ - static DSoundBackendFactory factory{}; - return factory; -} - -bool DSoundBackendFactory::init() -{ -#ifdef HAVE_DYNLOAD - if(!ds_handle) - { - ds_handle = LoadLib("dsound.dll"); - if(!ds_handle) - { - ERR("Failed to load dsound.dll\n"); - return false; - } - -#define LOAD_FUNC(f) do { \ - p##f = reinterpret_cast(GetSymbol(ds_handle, #f)); \ - if(!p##f) \ - { \ - CloseLib(ds_handle); \ - ds_handle = nullptr; \ - return false; \ - } \ -} while(0) - LOAD_FUNC(DirectSoundCreate); - LOAD_FUNC(DirectSoundEnumerateW); - LOAD_FUNC(DirectSoundCaptureCreate); - LOAD_FUNC(DirectSoundCaptureEnumerateW); -#undef LOAD_FUNC - } -#endif - return true; -} - -bool DSoundBackendFactory::querySupport(BackendType type) -{ return (type == BackendType::Playback || type == BackendType::Capture); } - -void DSoundBackendFactory::probe(DevProbe type, std::string *outnames) -{ - auto add_device = [outnames](const DevMap &entry) -> void - { - /* +1 to also append the null char (to ensure a null-separated list and - * double-null terminated list). - */ - outnames->append(entry.name.c_str(), entry.name.length()+1); - }; - - /* Initialize COM to prevent name truncation */ - HRESULT hr; - HRESULT hrcom{CoInitialize(nullptr)}; - switch(type) - { - case DevProbe::Playback: - PlaybackDevices.clear(); - hr = DirectSoundEnumerateW(DSoundEnumDevices, &PlaybackDevices); - if(FAILED(hr)) - ERR("Error enumerating DirectSound playback devices (0x%lx)!\n", hr); - std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); - break; - - case DevProbe::Capture: - CaptureDevices.clear(); - hr = DirectSoundCaptureEnumerateW(DSoundEnumDevices, &CaptureDevices); - if(FAILED(hr)) - ERR("Error enumerating DirectSound capture devices (0x%lx)!\n", hr); - std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); - break; - } - if(SUCCEEDED(hrcom)) - CoUninitialize(); -} - -BackendPtr DSoundBackendFactory::createBackend(ALCdevice *device, BackendType type) -{ - if(type == BackendType::Playback) - return BackendPtr{new DSoundPlayback{device}}; - if(type == BackendType::Capture) - return BackendPtr{new DSoundCapture{device}}; - return nullptr; -} diff --git a/Alc/backends/dsound.h b/Alc/backends/dsound.h deleted file mode 100644 index 6bef0bfc..00000000 --- a/Alc/backends/dsound.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef BACKENDS_DSOUND_H -#define BACKENDS_DSOUND_H - -#include "backends/base.h" - -struct DSoundBackendFactory final : public BackendFactory { -public: - bool init() override; - - bool querySupport(BackendType type) override; - - void probe(DevProbe type, std::string *outnames) override; - - BackendPtr createBackend(ALCdevice *device, BackendType type) override; - - static BackendFactory &getFactory(); -}; - -#endif /* BACKENDS_DSOUND_H */ diff --git a/Alc/backends/jack.cpp b/Alc/backends/jack.cpp deleted file mode 100644 index 3f81d08c..00000000 --- a/Alc/backends/jack.cpp +++ /dev/null @@ -1,562 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "backends/jack.h" - -#include -#include -#include - -#include -#include - -#include "alcmain.h" -#include "alu.h" -#include "alconfig.h" -#include "ringbuffer.h" -#include "threads.h" -#include "compat.h" - -#include -#include - - -namespace { - -constexpr ALCchar jackDevice[] = "JACK Default"; - - -#ifdef HAVE_DYNLOAD -#define JACK_FUNCS(MAGIC) \ - MAGIC(jack_client_open); \ - MAGIC(jack_client_close); \ - MAGIC(jack_client_name_size); \ - MAGIC(jack_get_client_name); \ - MAGIC(jack_connect); \ - MAGIC(jack_activate); \ - MAGIC(jack_deactivate); \ - MAGIC(jack_port_register); \ - MAGIC(jack_port_unregister); \ - MAGIC(jack_port_get_buffer); \ - MAGIC(jack_port_name); \ - MAGIC(jack_get_ports); \ - MAGIC(jack_free); \ - MAGIC(jack_get_sample_rate); \ - MAGIC(jack_set_error_function); \ - MAGIC(jack_set_process_callback); \ - MAGIC(jack_set_buffer_size_callback); \ - MAGIC(jack_set_buffer_size); \ - MAGIC(jack_get_buffer_size); - -void *jack_handle; -#define MAKE_FUNC(f) decltype(f) * p##f -JACK_FUNCS(MAKE_FUNC); -decltype(jack_error_callback) * pjack_error_callback; -#undef MAKE_FUNC - -#ifndef IN_IDE_PARSER -#define jack_client_open pjack_client_open -#define jack_client_close pjack_client_close -#define jack_client_name_size pjack_client_name_size -#define jack_get_client_name pjack_get_client_name -#define jack_connect pjack_connect -#define jack_activate pjack_activate -#define jack_deactivate pjack_deactivate -#define jack_port_register pjack_port_register -#define jack_port_unregister pjack_port_unregister -#define jack_port_get_buffer pjack_port_get_buffer -#define jack_port_name pjack_port_name -#define jack_get_ports pjack_get_ports -#define jack_free pjack_free -#define jack_get_sample_rate pjack_get_sample_rate -#define jack_set_error_function pjack_set_error_function -#define jack_set_process_callback pjack_set_process_callback -#define jack_set_buffer_size_callback pjack_set_buffer_size_callback -#define jack_set_buffer_size pjack_set_buffer_size -#define jack_get_buffer_size pjack_get_buffer_size -#define jack_error_callback (*pjack_error_callback) -#endif -#endif - - -jack_options_t ClientOptions = JackNullOption; - -ALCboolean jack_load() -{ - ALCboolean error = ALC_FALSE; - -#ifdef HAVE_DYNLOAD - if(!jack_handle) - { - std::string missing_funcs; - -#ifdef _WIN32 -#define JACKLIB "libjack.dll" -#else -#define JACKLIB "libjack.so.0" -#endif - jack_handle = LoadLib(JACKLIB); - if(!jack_handle) - { - WARN("Failed to load %s\n", JACKLIB); - return ALC_FALSE; - } - - error = ALC_FALSE; -#define LOAD_FUNC(f) do { \ - p##f = reinterpret_cast(GetSymbol(jack_handle, #f)); \ - if(p##f == nullptr) { \ - error = ALC_TRUE; \ - missing_funcs += "\n" #f; \ - } \ -} while(0) - JACK_FUNCS(LOAD_FUNC); -#undef LOAD_FUNC - /* Optional symbols. These don't exist in all versions of JACK. */ -#define LOAD_SYM(f) p##f = reinterpret_cast(GetSymbol(jack_handle, #f)) - LOAD_SYM(jack_error_callback); -#undef LOAD_SYM - - if(error) - { - WARN("Missing expected functions:%s\n", missing_funcs.c_str()); - CloseLib(jack_handle); - jack_handle = nullptr; - } - } -#endif - - return !error; -} - - -struct JackPlayback final : public BackendBase { - JackPlayback(ALCdevice *device) noexcept : BackendBase{device} { } - ~JackPlayback() override; - - static int bufferSizeNotifyC(jack_nframes_t numframes, void *arg); - int bufferSizeNotify(jack_nframes_t numframes); - - static int processC(jack_nframes_t numframes, void *arg); - int process(jack_nframes_t numframes); - - int mixerProc(); - - ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; - void stop() override; - ClockLatency getClockLatency() override; - - jack_client_t *mClient{nullptr}; - jack_port_t *mPort[MAX_OUTPUT_CHANNELS]{}; - - RingBufferPtr mRing; - al::semaphore mSem; - - std::atomic mKillNow{true}; - std::thread mThread; - - DEF_NEWDEL(JackPlayback) -}; - -JackPlayback::~JackPlayback() -{ - if(!mClient) - return; - - std::for_each(std::begin(mPort), std::end(mPort), - [this](jack_port_t *port) -> void - { if(port) jack_port_unregister(mClient, port); } - ); - std::fill(std::begin(mPort), std::end(mPort), nullptr); - jack_client_close(mClient); - mClient = nullptr; -} - - -int JackPlayback::bufferSizeNotifyC(jack_nframes_t numframes, void *arg) -{ return static_cast(arg)->bufferSizeNotify(numframes); } - -int JackPlayback::bufferSizeNotify(jack_nframes_t numframes) -{ - std::lock_guard _{mDevice->StateLock}; - mDevice->UpdateSize = numframes; - mDevice->BufferSize = numframes*2; - - const char *devname{mDevice->DeviceName.c_str()}; - ALuint bufsize{ConfigValueUInt(devname, "jack", "buffer-size").value_or(mDevice->UpdateSize)}; - bufsize = maxu(NextPowerOf2(bufsize), mDevice->UpdateSize); - mDevice->BufferSize = bufsize + mDevice->UpdateSize; - - TRACE("%u / %u buffer\n", mDevice->UpdateSize, mDevice->BufferSize); - - mRing = nullptr; - mRing = CreateRingBuffer(bufsize, mDevice->frameSizeFromFmt(), true); - if(!mRing) - { - ERR("Failed to reallocate ringbuffer\n"); - aluHandleDisconnect(mDevice, "Failed to reallocate %u-sample buffer", bufsize); - } - return 0; -} - - -int JackPlayback::processC(jack_nframes_t numframes, void *arg) -{ return static_cast(arg)->process(numframes); } - -int JackPlayback::process(jack_nframes_t numframes) -{ - jack_default_audio_sample_t *out[MAX_OUTPUT_CHANNELS]; - ALsizei numchans{0}; - for(auto port : mPort) - { - if(!port) break; - out[numchans++] = static_cast(jack_port_get_buffer(port, numframes)); - } - - auto data = mRing->getReadVector(); - jack_nframes_t todo{minu(numframes, data.first.len)}; - std::transform(out, out+numchans, out, - [&data,numchans,todo](ALfloat *outbuf) -> ALfloat* - { - const ALfloat *RESTRICT in = reinterpret_cast(data.first.buf); - std::generate_n(outbuf, todo, - [&in,numchans]() noexcept -> ALfloat - { - ALfloat ret{*in}; - in += numchans; - return ret; - } - ); - data.first.buf += sizeof(ALfloat); - return outbuf + todo; - } - ); - jack_nframes_t total{todo}; - - todo = minu(numframes-total, data.second.len); - if(todo > 0) - { - std::transform(out, out+numchans, out, - [&data,numchans,todo](ALfloat *outbuf) -> ALfloat* - { - const ALfloat *RESTRICT in = reinterpret_cast(data.second.buf); - std::generate_n(outbuf, todo, - [&in,numchans]() noexcept -> ALfloat - { - ALfloat ret{*in}; - in += numchans; - return ret; - } - ); - data.second.buf += sizeof(ALfloat); - return outbuf + todo; - } - ); - total += todo; - } - - mRing->readAdvance(total); - mSem.post(); - - if(numframes > total) - { - todo = numframes-total; - std::transform(out, out+numchans, out, - [todo](ALfloat *outbuf) -> ALfloat* - { - std::fill_n(outbuf, todo, 0.0f); - return outbuf + todo; - } - ); - } - - return 0; -} - -int JackPlayback::mixerProc() -{ - SetRTPriority(); - althrd_setname(MIXER_THREAD_NAME); - - lock(); - while(!mKillNow.load(std::memory_order_acquire) && - mDevice->Connected.load(std::memory_order_acquire)) - { - if(mRing->writeSpace() < mDevice->UpdateSize) - { - unlock(); - mSem.wait(); - lock(); - continue; - } - - auto data = mRing->getWriteVector(); - auto todo = static_cast(data.first.len + data.second.len); - todo -= todo%mDevice->UpdateSize; - - ALuint len1{minu(data.first.len, todo)}; - ALuint len2{minu(data.second.len, todo-len1)}; - - aluMixData(mDevice, data.first.buf, len1); - if(len2 > 0) - aluMixData(mDevice, data.second.buf, len2); - mRing->writeAdvance(todo); - } - unlock(); - - return 0; -} - - -ALCenum JackPlayback::open(const ALCchar *name) -{ - if(!name) - name = jackDevice; - else if(strcmp(name, jackDevice) != 0) - return ALC_INVALID_VALUE; - - const char *client_name{"alsoft"}; - jack_status_t status; - mClient = jack_client_open(client_name, ClientOptions, &status, nullptr); - if(mClient == nullptr) - { - ERR("jack_client_open() failed, status = 0x%02x\n", status); - return ALC_INVALID_VALUE; - } - if((status&JackServerStarted)) - TRACE("JACK server started\n"); - if((status&JackNameNotUnique)) - { - client_name = jack_get_client_name(mClient); - TRACE("Client name not unique, got `%s' instead\n", client_name); - } - - jack_set_process_callback(mClient, &JackPlayback::processC, this); - jack_set_buffer_size_callback(mClient, &JackPlayback::bufferSizeNotifyC, this); - - mDevice->DeviceName = name; - return ALC_NO_ERROR; -} - -ALCboolean JackPlayback::reset() -{ - std::for_each(std::begin(mPort), std::end(mPort), - [this](jack_port_t *port) -> void - { if(port) jack_port_unregister(mClient, port); } - ); - std::fill(std::begin(mPort), std::end(mPort), nullptr); - - /* Ignore the requested buffer metrics and just keep one JACK-sized buffer - * ready for when requested. - */ - mDevice->Frequency = jack_get_sample_rate(mClient); - mDevice->UpdateSize = jack_get_buffer_size(mClient); - mDevice->BufferSize = mDevice->UpdateSize * 2; - - const char *devname{mDevice->DeviceName.c_str()}; - ALuint bufsize{ConfigValueUInt(devname, "jack", "buffer-size").value_or(mDevice->UpdateSize)}; - bufsize = maxu(NextPowerOf2(bufsize), mDevice->UpdateSize); - mDevice->BufferSize = bufsize + mDevice->UpdateSize; - - /* Force 32-bit float output. */ - mDevice->FmtType = DevFmtFloat; - - ALsizei numchans{mDevice->channelsFromFmt()}; - auto ports_end = std::begin(mPort) + numchans; - auto bad_port = std::find_if_not(std::begin(mPort), ports_end, - [this](jack_port_t *&port) -> bool - { - std::string name{"channel_" + std::to_string(&port - mPort + 1)}; - port = jack_port_register(mClient, name.c_str(), JACK_DEFAULT_AUDIO_TYPE, - JackPortIsOutput, 0); - return port != nullptr; - } - ); - if(bad_port != ports_end) - { - ERR("Not enough JACK ports available for %s output\n", DevFmtChannelsString(mDevice->FmtChans)); - if(bad_port == std::begin(mPort)) return ALC_FALSE; - - if(bad_port == std::begin(mPort)+1) - mDevice->FmtChans = DevFmtMono; - else - { - ports_end = mPort+2; - while(bad_port != ports_end) - { - jack_port_unregister(mClient, *(--bad_port)); - *bad_port = nullptr; - } - mDevice->FmtChans = DevFmtStereo; - } - numchans = std::distance(std::begin(mPort), bad_port); - } - - mRing = nullptr; - mRing = CreateRingBuffer(bufsize, mDevice->frameSizeFromFmt(), true); - if(!mRing) - { - ERR("Failed to allocate ringbuffer\n"); - return ALC_FALSE; - } - - SetDefaultChannelOrder(mDevice); - - return ALC_TRUE; -} - -ALCboolean JackPlayback::start() -{ - if(jack_activate(mClient)) - { - ERR("Failed to activate client\n"); - return ALC_FALSE; - } - - const char **ports{jack_get_ports(mClient, nullptr, nullptr, - JackPortIsPhysical|JackPortIsInput)}; - if(ports == nullptr) - { - ERR("No physical playback ports found\n"); - jack_deactivate(mClient); - return ALC_FALSE; - } - std::mismatch(std::begin(mPort), std::end(mPort), ports, - [this](const jack_port_t *port, const char *pname) -> bool - { - if(!port) return false; - if(!pname) - { - ERR("No physical playback port for \"%s\"\n", jack_port_name(port)); - return false; - } - if(jack_connect(mClient, jack_port_name(port), pname)) - ERR("Failed to connect output port \"%s\" to \"%s\"\n", jack_port_name(port), - pname); - return true; - } - ); - jack_free(ports); - - try { - mKillNow.store(false, std::memory_order_release); - mThread = std::thread{std::mem_fn(&JackPlayback::mixerProc), this}; - return ALC_TRUE; - } - catch(std::exception& e) { - ERR("Could not create playback thread: %s\n", e.what()); - } - catch(...) { - } - jack_deactivate(mClient); - return ALC_FALSE; -} - -void JackPlayback::stop() -{ - if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) - return; - - mSem.post(); - mThread.join(); - - jack_deactivate(mClient); -} - - -ClockLatency JackPlayback::getClockLatency() -{ - ClockLatency ret; - - lock(); - ret.ClockTime = GetDeviceClockTime(mDevice); - ret.Latency = std::chrono::seconds{mRing->readSpace()}; - ret.Latency /= mDevice->Frequency; - unlock(); - - return ret; -} - - -void jack_msg_handler(const char *message) -{ - WARN("%s\n", message); -} - -} // namespace - -bool JackBackendFactory::init() -{ - if(!jack_load()) - return false; - - if(!GetConfigValueBool(nullptr, "jack", "spawn-server", 0)) - ClientOptions = static_cast(ClientOptions | JackNoStartServer); - - void (*old_error_cb)(const char*){&jack_error_callback ? jack_error_callback : nullptr}; - jack_set_error_function(jack_msg_handler); - jack_status_t status; - jack_client_t *client{jack_client_open("alsoft", ClientOptions, &status, nullptr)}; - jack_set_error_function(old_error_cb); - if(!client) - { - WARN("jack_client_open() failed, 0x%02x\n", status); - if((status&JackServerFailed) && !(ClientOptions&JackNoStartServer)) - ERR("Unable to connect to JACK server\n"); - return false; - } - - jack_client_close(client); - return true; -} - -bool JackBackendFactory::querySupport(BackendType type) -{ return (type == BackendType::Playback); } - -void JackBackendFactory::probe(DevProbe type, std::string *outnames) -{ - switch(type) - { - case DevProbe::Playback: - /* Includes null char. */ - outnames->append(jackDevice, sizeof(jackDevice)); - break; - - case DevProbe::Capture: - break; - } -} - -BackendPtr JackBackendFactory::createBackend(ALCdevice *device, BackendType type) -{ - if(type == BackendType::Playback) - return BackendPtr{new JackPlayback{device}}; - return nullptr; -} - -BackendFactory &JackBackendFactory::getFactory() -{ - static JackBackendFactory factory{}; - return factory; -} diff --git a/Alc/backends/jack.h b/Alc/backends/jack.h deleted file mode 100644 index 10beebfb..00000000 --- a/Alc/backends/jack.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef BACKENDS_JACK_H -#define BACKENDS_JACK_H - -#include "backends/base.h" - -struct JackBackendFactory final : public BackendFactory { -public: - bool init() override; - - bool querySupport(BackendType type) override; - - void probe(DevProbe type, std::string *outnames) override; - - BackendPtr createBackend(ALCdevice *device, BackendType type) override; - - static BackendFactory &getFactory(); -}; - -#endif /* BACKENDS_JACK_H */ diff --git a/Alc/backends/loopback.cpp b/Alc/backends/loopback.cpp deleted file mode 100644 index 4a1c641a..00000000 --- a/Alc/backends/loopback.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2011 by Chris Robinson - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "backends/loopback.h" - -#include "alcmain.h" -#include "alu.h" - - -namespace { - -struct LoopbackBackend final : public BackendBase { - LoopbackBackend(ALCdevice *device) noexcept : BackendBase{device} { } - - ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; - void stop() override; - - DEF_NEWDEL(LoopbackBackend) -}; - - -ALCenum LoopbackBackend::open(const ALCchar *name) -{ - mDevice->DeviceName = name; - return ALC_NO_ERROR; -} - -ALCboolean LoopbackBackend::reset() -{ - SetDefaultWFXChannelOrder(mDevice); - return ALC_TRUE; -} - -ALCboolean LoopbackBackend::start() -{ return ALC_TRUE; } - -void LoopbackBackend::stop() -{ } - -} // namespace - - -bool LoopbackBackendFactory::init() -{ return true; } - -bool LoopbackBackendFactory::querySupport(BackendType) -{ return true; } - -void LoopbackBackendFactory::probe(DevProbe, std::string*) -{ } - -BackendPtr LoopbackBackendFactory::createBackend(ALCdevice *device, BackendType) -{ return BackendPtr{new LoopbackBackend{device}}; } - -BackendFactory &LoopbackBackendFactory::getFactory() -{ - static LoopbackBackendFactory factory{}; - return factory; -} diff --git a/Alc/backends/loopback.h b/Alc/backends/loopback.h deleted file mode 100644 index 09c085b8..00000000 --- a/Alc/backends/loopback.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef BACKENDS_LOOPBACK_H -#define BACKENDS_LOOPBACK_H - -#include "backends/base.h" - -struct LoopbackBackendFactory final : public BackendFactory { -public: - bool init() override; - - bool querySupport(BackendType type) override; - - void probe(DevProbe type, std::string *outnames) override; - - BackendPtr createBackend(ALCdevice *device, BackendType type) override; - - static BackendFactory &getFactory(); -}; - -#endif /* BACKENDS_LOOPBACK_H */ diff --git a/Alc/backends/null.cpp b/Alc/backends/null.cpp deleted file mode 100644 index ae58cb8b..00000000 --- a/Alc/backends/null.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2010 by Chris Robinson - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "backends/null.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "alcmain.h" -#include "almalloc.h" -#include "alu.h" -#include "logging.h" -#include "threads.h" - - -namespace { - -using std::chrono::seconds; -using std::chrono::milliseconds; -using std::chrono::nanoseconds; - -constexpr ALCchar nullDevice[] = "No Output"; - - -struct NullBackend final : public BackendBase { - NullBackend(ALCdevice *device) noexcept : BackendBase{device} { } - - int mixerProc(); - - ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; - void stop() override; - - std::atomic mKillNow{true}; - std::thread mThread; - - DEF_NEWDEL(NullBackend) -}; - -int NullBackend::mixerProc() -{ - const milliseconds restTime{mDevice->UpdateSize*1000/mDevice->Frequency / 2}; - - SetRTPriority(); - althrd_setname(MIXER_THREAD_NAME); - - int64_t done{0}; - auto start = std::chrono::steady_clock::now(); - while(!mKillNow.load(std::memory_order_acquire) && - mDevice->Connected.load(std::memory_order_acquire)) - { - auto now = std::chrono::steady_clock::now(); - - /* This converts from nanoseconds to nanosamples, then to samples. */ - int64_t avail{std::chrono::duration_cast((now-start) * mDevice->Frequency).count()}; - if(avail-done < mDevice->UpdateSize) - { - std::this_thread::sleep_for(restTime); - continue; - } - while(avail-done >= mDevice->UpdateSize) - { - lock(); - aluMixData(mDevice, nullptr, mDevice->UpdateSize); - unlock(); - done += mDevice->UpdateSize; - } - - /* For every completed second, increment the start time and reduce the - * samples done. This prevents the difference between the start time - * and current time from growing too large, while maintaining the - * correct number of samples to render. - */ - if(done >= mDevice->Frequency) - { - seconds s{done/mDevice->Frequency}; - start += s; - done -= mDevice->Frequency*s.count(); - } - } - - return 0; -} - - -ALCenum NullBackend::open(const ALCchar *name) -{ - if(!name) - name = nullDevice; - else if(strcmp(name, nullDevice) != 0) - return ALC_INVALID_VALUE; - - mDevice->DeviceName = name; - - return ALC_NO_ERROR; -} - -ALCboolean NullBackend::reset() -{ - SetDefaultWFXChannelOrder(mDevice); - return ALC_TRUE; -} - -ALCboolean NullBackend::start() -{ - try { - mKillNow.store(false, std::memory_order_release); - mThread = std::thread{std::mem_fn(&NullBackend::mixerProc), this}; - return ALC_TRUE; - } - catch(std::exception& e) { - ERR("Failed to start mixing thread: %s\n", e.what()); - } - catch(...) { - } - return ALC_FALSE; -} - -void NullBackend::stop() -{ - if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) - return; - mThread.join(); -} - -} // namespace - - -bool NullBackendFactory::init() -{ return true; } - -bool NullBackendFactory::querySupport(BackendType type) -{ return (type == BackendType::Playback); } - -void NullBackendFactory::probe(DevProbe type, std::string *outnames) -{ - switch(type) - { - case DevProbe::Playback: - /* Includes null char. */ - outnames->append(nullDevice, sizeof(nullDevice)); - break; - case DevProbe::Capture: - break; - } -} - -BackendPtr NullBackendFactory::createBackend(ALCdevice *device, BackendType type) -{ - if(type == BackendType::Playback) - return BackendPtr{new NullBackend{device}}; - return nullptr; -} - -BackendFactory &NullBackendFactory::getFactory() -{ - static NullBackendFactory factory{}; - return factory; -} diff --git a/Alc/backends/null.h b/Alc/backends/null.h deleted file mode 100644 index f19d5b4d..00000000 --- a/Alc/backends/null.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef BACKENDS_NULL_H -#define BACKENDS_NULL_H - -#include "backends/base.h" - -struct NullBackendFactory final : public BackendFactory { -public: - bool init() override; - - bool querySupport(BackendType type) override; - - void probe(DevProbe type, std::string *outnames) override; - - BackendPtr createBackend(ALCdevice *device, BackendType type) override; - - static BackendFactory &getFactory(); -}; - -#endif /* BACKENDS_NULL_H */ diff --git a/Alc/backends/opensl.cpp b/Alc/backends/opensl.cpp deleted file mode 100644 index b34dc0cb..00000000 --- a/Alc/backends/opensl.cpp +++ /dev/null @@ -1,936 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* This is an OpenAL backend for Android using the native audio APIs based on - * OpenSL ES 1.0.1. It is based on source code for the native-audio sample app - * bundled with NDK. - */ - -#include "config.h" - -#include "backends/opensl.h" - -#include -#include - -#include -#include -#include -#include - -#include "alcmain.h" -#include "alu.h" -#include "ringbuffer.h" -#include "threads.h" -#include "compat.h" - -#include -#include -#include - - -namespace { - -/* Helper macros */ -#define EXTRACT_VCALL_ARGS(...) __VA_ARGS__)) -#define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS -#define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS - - -constexpr ALCchar opensl_device[] = "OpenSL"; - - -SLuint32 GetChannelMask(DevFmtChannels chans) -{ - switch(chans) - { - case DevFmtMono: return SL_SPEAKER_FRONT_CENTER; - case DevFmtStereo: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT; - case DevFmtQuad: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; - case DevFmtX51: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; - case DevFmtX51Rear: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; - case DevFmtX61: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_BACK_CENTER| - SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; - case DevFmtX71: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT| - SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; - case DevFmtAmbi3D: - break; - } - return 0; -} - -#ifdef SL_ANDROID_DATAFORMAT_PCM_EX -SLuint32 GetTypeRepresentation(DevFmtType type) -{ - switch(type) - { - case DevFmtUByte: - case DevFmtUShort: - case DevFmtUInt: - return SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT; - case DevFmtByte: - case DevFmtShort: - case DevFmtInt: - return SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT; - case DevFmtFloat: - return SL_ANDROID_PCM_REPRESENTATION_FLOAT; - } - return 0; -} -#endif - -const char *res_str(SLresult result) -{ - switch(result) - { - case SL_RESULT_SUCCESS: return "Success"; - case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated"; - case SL_RESULT_PARAMETER_INVALID: return "Parameter invalid"; - case SL_RESULT_MEMORY_FAILURE: return "Memory failure"; - case SL_RESULT_RESOURCE_ERROR: return "Resource error"; - case SL_RESULT_RESOURCE_LOST: return "Resource lost"; - case SL_RESULT_IO_ERROR: return "I/O error"; - case SL_RESULT_BUFFER_INSUFFICIENT: return "Buffer insufficient"; - case SL_RESULT_CONTENT_CORRUPTED: return "Content corrupted"; - case SL_RESULT_CONTENT_UNSUPPORTED: return "Content unsupported"; - case SL_RESULT_CONTENT_NOT_FOUND: return "Content not found"; - case SL_RESULT_PERMISSION_DENIED: return "Permission denied"; - case SL_RESULT_FEATURE_UNSUPPORTED: return "Feature unsupported"; - case SL_RESULT_INTERNAL_ERROR: return "Internal error"; - case SL_RESULT_UNKNOWN_ERROR: return "Unknown error"; - case SL_RESULT_OPERATION_ABORTED: return "Operation aborted"; - case SL_RESULT_CONTROL_LOST: return "Control lost"; -#ifdef SL_RESULT_READONLY - case SL_RESULT_READONLY: return "ReadOnly"; -#endif -#ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED - case SL_RESULT_ENGINEOPTION_UNSUPPORTED: return "Engine option unsupported"; -#endif -#ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE - case SL_RESULT_SOURCE_SINK_INCOMPATIBLE: return "Source/Sink incompatible"; -#endif - } - return "Unknown error code"; -} - -#define PRINTERR(x, s) do { \ - if(UNLIKELY((x) != SL_RESULT_SUCCESS)) \ - ERR("%s: %s\n", (s), res_str((x))); \ -} while(0) - - -struct OpenSLPlayback final : public BackendBase { - OpenSLPlayback(ALCdevice *device) noexcept : BackendBase{device} { } - ~OpenSLPlayback() override; - - static void processC(SLAndroidSimpleBufferQueueItf bq, void *context); - void process(SLAndroidSimpleBufferQueueItf bq); - - int mixerProc(); - - ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; - void stop() override; - ClockLatency getClockLatency() override; - - /* engine interfaces */ - SLObjectItf mEngineObj{nullptr}; - SLEngineItf mEngine{nullptr}; - - /* output mix interfaces */ - SLObjectItf mOutputMix{nullptr}; - - /* buffer queue player interfaces */ - SLObjectItf mBufferQueueObj{nullptr}; - - RingBufferPtr mRing{nullptr}; - al::semaphore mSem; - - ALsizei mFrameSize{0}; - - std::atomic mKillNow{true}; - std::thread mThread; - - DEF_NEWDEL(OpenSLPlayback) -}; - -OpenSLPlayback::~OpenSLPlayback() -{ - if(mBufferQueueObj) - VCALL0(mBufferQueueObj,Destroy)(); - mBufferQueueObj = nullptr; - - if(mOutputMix) - VCALL0(mOutputMix,Destroy)(); - mOutputMix = nullptr; - - if(mEngineObj) - VCALL0(mEngineObj,Destroy)(); - mEngineObj = nullptr; - mEngine = nullptr; -} - - -/* this callback handler is called every time a buffer finishes playing */ -void OpenSLPlayback::processC(SLAndroidSimpleBufferQueueItf bq, void *context) -{ static_cast(context)->process(bq); } - -void OpenSLPlayback::process(SLAndroidSimpleBufferQueueItf) -{ - /* A note on the ringbuffer usage: The buffer queue seems to hold on to the - * pointer passed to the Enqueue method, rather than copying the audio. - * Consequently, the ringbuffer contains the audio that is currently queued - * and waiting to play. This process() callback is called when a buffer is - * finished, so we simply move the read pointer up to indicate the space is - * available for writing again, and wake up the mixer thread to mix and - * queue more audio. - */ - mRing->readAdvance(1); - - mSem.post(); -} - -int OpenSLPlayback::mixerProc() -{ - SetRTPriority(); - althrd_setname(MIXER_THREAD_NAME); - - SLPlayItf player; - SLAndroidSimpleBufferQueueItf bufferQueue; - SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue)}; - PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player); - PRINTERR(result, "bufferQueue->GetInterface SL_IID_PLAY"); - } - - lock(); - if(SL_RESULT_SUCCESS != result) - aluHandleDisconnect(mDevice, "Failed to get playback buffer: 0x%08x", result); - - while(SL_RESULT_SUCCESS == result && !mKillNow.load(std::memory_order_acquire) && - mDevice->Connected.load(std::memory_order_acquire)) - { - if(mRing->writeSpace() == 0) - { - SLuint32 state{0}; - - result = VCALL(player,GetPlayState)(&state); - PRINTERR(result, "player->GetPlayState"); - if(SL_RESULT_SUCCESS == result && state != SL_PLAYSTATE_PLAYING) - { - result = VCALL(player,SetPlayState)(SL_PLAYSTATE_PLAYING); - PRINTERR(result, "player->SetPlayState"); - } - if(SL_RESULT_SUCCESS != result) - { - aluHandleDisconnect(mDevice, "Failed to start platback: 0x%08x", result); - break; - } - - if(mRing->writeSpace() == 0) - { - unlock(); - mSem.wait(); - lock(); - continue; - } - } - - auto data = mRing->getWriteVector(); - aluMixData(mDevice, data.first.buf, data.first.len*mDevice->UpdateSize); - if(data.second.len > 0) - aluMixData(mDevice, data.second.buf, data.second.len*mDevice->UpdateSize); - - size_t todo{data.first.len + data.second.len}; - mRing->writeAdvance(todo); - - for(size_t i{0};i < todo;i++) - { - if(!data.first.len) - { - data.first = data.second; - data.second.buf = nullptr; - data.second.len = 0; - } - - result = VCALL(bufferQueue,Enqueue)(data.first.buf, mDevice->UpdateSize*mFrameSize); - PRINTERR(result, "bufferQueue->Enqueue"); - if(SL_RESULT_SUCCESS != result) - { - aluHandleDisconnect(mDevice, "Failed to queue audio: 0x%08x", result); - break; - } - - data.first.len--; - data.first.buf += mDevice->UpdateSize*mFrameSize; - } - } - unlock(); - - return 0; -} - - -ALCenum OpenSLPlayback::open(const ALCchar *name) -{ - if(!name) - name = opensl_device; - else if(strcmp(name, opensl_device) != 0) - return ALC_INVALID_VALUE; - - // create engine - SLresult result{slCreateEngine(&mEngineObj, 0, nullptr, 0, nullptr, nullptr)}; - PRINTERR(result, "slCreateEngine"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(mEngineObj,Realize)(SL_BOOLEAN_FALSE); - PRINTERR(result, "engine->Realize"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(mEngineObj,GetInterface)(SL_IID_ENGINE, &mEngine); - PRINTERR(result, "engine->GetInterface"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(mEngine,CreateOutputMix)(&mOutputMix, 0, nullptr, nullptr); - PRINTERR(result, "engine->CreateOutputMix"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(mOutputMix,Realize)(SL_BOOLEAN_FALSE); - PRINTERR(result, "outputMix->Realize"); - } - - if(SL_RESULT_SUCCESS != result) - { - if(mOutputMix) - VCALL0(mOutputMix,Destroy)(); - mOutputMix = nullptr; - - if(mEngineObj) - VCALL0(mEngineObj,Destroy)(); - mEngineObj = nullptr; - mEngine = nullptr; - - return ALC_INVALID_VALUE; - } - - mDevice->DeviceName = name; - return ALC_NO_ERROR; -} - -ALCboolean OpenSLPlayback::reset() -{ - SLDataLocator_AndroidSimpleBufferQueue loc_bufq; - SLDataLocator_OutputMix loc_outmix; - SLDataSource audioSrc; - SLDataSink audioSnk; - SLresult result; - - if(mBufferQueueObj) - VCALL0(mBufferQueueObj,Destroy)(); - mBufferQueueObj = nullptr; - - mRing = nullptr; - -#if 0 - if(!mDevice->Flags.get()) - { - /* FIXME: Disabled until I figure out how to get the Context needed for - * the getSystemService call. - */ - JNIEnv *env = Android_GetJNIEnv(); - jobject jctx = Android_GetContext(); - - /* Get necessary stuff for using java.lang.Integer, - * android.content.Context, and android.media.AudioManager. - */ - jclass int_cls = JCALL(env,FindClass)("java/lang/Integer"); - jmethodID int_parseint = JCALL(env,GetStaticMethodID)(int_cls, - "parseInt", "(Ljava/lang/String;)I" - ); - TRACE("Integer: %p, parseInt: %p\n", int_cls, int_parseint); - - jclass ctx_cls = JCALL(env,FindClass)("android/content/Context"); - jfieldID ctx_audsvc = JCALL(env,GetStaticFieldID)(ctx_cls, - "AUDIO_SERVICE", "Ljava/lang/String;" - ); - jmethodID ctx_getSysSvc = JCALL(env,GetMethodID)(ctx_cls, - "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;" - ); - TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n", - ctx_cls, ctx_audsvc, ctx_getSysSvc); - - jclass audmgr_cls = JCALL(env,FindClass)("android/media/AudioManager"); - jfieldID audmgr_prop_out_srate = JCALL(env,GetStaticFieldID)(audmgr_cls, - "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;" - ); - jmethodID audmgr_getproperty = JCALL(env,GetMethodID)(audmgr_cls, - "getProperty", "(Ljava/lang/String;)Ljava/lang/String;" - ); - TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n", - audmgr_cls, audmgr_prop_out_srate, audmgr_getproperty); - - const char *strchars; - jstring strobj; - - /* Now make the calls. */ - //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE); - strobj = JCALL(env,GetStaticObjectField)(ctx_cls, ctx_audsvc); - jobject audMgr = JCALL(env,CallObjectMethod)(jctx, ctx_getSysSvc, strobj); - strchars = JCALL(env,GetStringUTFChars)(strobj, nullptr); - TRACE("Context.getSystemService(%s) = %p\n", strchars, audMgr); - JCALL(env,ReleaseStringUTFChars)(strobj, strchars); - - //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE); - strobj = JCALL(env,GetStaticObjectField)(audmgr_cls, audmgr_prop_out_srate); - jstring srateStr = JCALL(env,CallObjectMethod)(audMgr, audmgr_getproperty, strobj); - strchars = JCALL(env,GetStringUTFChars)(strobj, nullptr); - TRACE("audMgr.getProperty(%s) = %p\n", strchars, srateStr); - JCALL(env,ReleaseStringUTFChars)(strobj, strchars); - - //int sampleRate = Integer.parseInt(srateStr); - sampleRate = JCALL(env,CallStaticIntMethod)(int_cls, int_parseint, srateStr); - - strchars = JCALL(env,GetStringUTFChars)(srateStr, nullptr); - TRACE("Got system sample rate %uhz (%s)\n", sampleRate, strchars); - JCALL(env,ReleaseStringUTFChars)(srateStr, strchars); - - if(!sampleRate) sampleRate = device->Frequency; - else sampleRate = maxu(sampleRate, MIN_OUTPUT_RATE); - } -#endif - - mDevice->FmtChans = DevFmtStereo; - mDevice->FmtType = DevFmtShort; - - SetDefaultWFXChannelOrder(mDevice); - mFrameSize = mDevice->frameSizeFromFmt(); - - - const std::array ids{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }}; - const std::array reqs{{ SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }}; - - loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; - loc_bufq.numBuffers = mDevice->BufferSize / mDevice->UpdateSize; - -#ifdef SL_ANDROID_DATAFORMAT_PCM_EX - SLAndroidDataFormat_PCM_EX format_pcm{}; - format_pcm.formatType = SL_ANDROID_DATAFORMAT_PCM_EX; - format_pcm.numChannels = mDevice->channelsFromFmt(); - format_pcm.sampleRate = mDevice->Frequency * 1000; - format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; - format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); - format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : - SL_BYTEORDER_BIGENDIAN; - format_pcm.representation = GetTypeRepresentation(mDevice->FmtType); -#else - SLDataFormat_PCM format_pcm{}; - format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = mDevice->channelsFromFmt(); - format_pcm.samplesPerSec = mDevice->Frequency * 1000; - format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; - format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); - format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : - SL_BYTEORDER_BIGENDIAN; -#endif - - audioSrc.pLocator = &loc_bufq; - audioSrc.pFormat = &format_pcm; - - loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; - loc_outmix.outputMix = mOutputMix; - audioSnk.pLocator = &loc_outmix; - audioSnk.pFormat = nullptr; - - - result = VCALL(mEngine,CreateAudioPlayer)(&mBufferQueueObj, &audioSrc, &audioSnk, ids.size(), - ids.data(), reqs.data()); - PRINTERR(result, "engine->CreateAudioPlayer"); - if(SL_RESULT_SUCCESS == result) - { - /* Set the stream type to "media" (games, music, etc), if possible. */ - SLAndroidConfigurationItf config; - result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config); - PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION"); - if(SL_RESULT_SUCCESS == result) - { - SLint32 streamType = SL_ANDROID_STREAM_MEDIA; - result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_STREAM_TYPE, &streamType, - sizeof(streamType)); - PRINTERR(result, "config->SetConfiguration"); - } - - /* Clear any error since this was optional. */ - result = SL_RESULT_SUCCESS; - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(mBufferQueueObj,Realize)(SL_BOOLEAN_FALSE); - PRINTERR(result, "bufferQueue->Realize"); - } - if(SL_RESULT_SUCCESS == result) - { - const ALuint num_updates{mDevice->BufferSize / mDevice->UpdateSize}; - try { - mRing = CreateRingBuffer(num_updates, mFrameSize*mDevice->UpdateSize, true); - } - catch(std::exception& e) { - ERR("Failed allocating ring buffer %ux%ux%u: %s\n", mDevice->UpdateSize, - num_updates, mFrameSize, e.what()); - result = SL_RESULT_MEMORY_FAILURE; - } - } - - if(SL_RESULT_SUCCESS != result) - { - if(mBufferQueueObj) - VCALL0(mBufferQueueObj,Destroy)(); - mBufferQueueObj = nullptr; - - return ALC_FALSE; - } - - return ALC_TRUE; -} - -ALCboolean OpenSLPlayback::start() -{ - mRing->reset(); - - SLAndroidSimpleBufferQueueItf bufferQueue; - SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue)}; - PRINTERR(result, "bufferQueue->GetInterface"); - if(SL_RESULT_SUCCESS != result) - return ALC_FALSE; - - result = VCALL(bufferQueue,RegisterCallback)(&OpenSLPlayback::processC, this); - PRINTERR(result, "bufferQueue->RegisterCallback"); - if(SL_RESULT_SUCCESS != result) return ALC_FALSE; - - try { - mKillNow.store(false, std::memory_order_release); - mThread = std::thread(std::mem_fn(&OpenSLPlayback::mixerProc), this); - return ALC_TRUE; - } - catch(std::exception& e) { - ERR("Could not create playback thread: %s\n", e.what()); - } - catch(...) { - } - return ALC_FALSE; -} - -void OpenSLPlayback::stop() -{ - if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) - return; - - mSem.post(); - mThread.join(); - - SLPlayItf player; - SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player)}; - PRINTERR(result, "bufferQueue->GetInterface"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(player,SetPlayState)(SL_PLAYSTATE_STOPPED); - PRINTERR(result, "player->SetPlayState"); - } - - SLAndroidSimpleBufferQueueItf bufferQueue; - result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); - PRINTERR(result, "bufferQueue->GetInterface"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL0(bufferQueue,Clear)(); - PRINTERR(result, "bufferQueue->Clear"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(bufferQueue,RegisterCallback)(nullptr, nullptr); - PRINTERR(result, "bufferQueue->RegisterCallback"); - } - if(SL_RESULT_SUCCESS == result) - { - SLAndroidSimpleBufferQueueState state; - do { - std::this_thread::yield(); - result = VCALL(bufferQueue,GetState)(&state); - } while(SL_RESULT_SUCCESS == result && state.count > 0); - PRINTERR(result, "bufferQueue->GetState"); - } -} - -ClockLatency OpenSLPlayback::getClockLatency() -{ - ClockLatency ret; - - lock(); - ret.ClockTime = GetDeviceClockTime(mDevice); - ret.Latency = std::chrono::seconds{mRing->readSpace() * mDevice->UpdateSize}; - ret.Latency /= mDevice->Frequency; - unlock(); - - return ret; -} - - -struct OpenSLCapture final : public BackendBase { - OpenSLCapture(ALCdevice *device) noexcept : BackendBase{device} { } - ~OpenSLCapture() override; - - static void processC(SLAndroidSimpleBufferQueueItf bq, void *context); - void process(SLAndroidSimpleBufferQueueItf bq); - - ALCenum open(const ALCchar *name) override; - ALCboolean start() override; - void stop() override; - ALCenum captureSamples(void *buffer, ALCuint samples) override; - ALCuint availableSamples() override; - - /* engine interfaces */ - SLObjectItf mEngineObj{nullptr}; - SLEngineItf mEngine; - - /* recording interfaces */ - SLObjectItf mRecordObj{nullptr}; - - RingBufferPtr mRing{nullptr}; - ALCuint mSplOffset{0u}; - - ALsizei mFrameSize{0}; - - DEF_NEWDEL(OpenSLCapture) -}; - -OpenSLCapture::~OpenSLCapture() -{ - if(mRecordObj) - VCALL0(mRecordObj,Destroy)(); - mRecordObj = nullptr; - - if(mEngineObj) - VCALL0(mEngineObj,Destroy)(); - mEngineObj = nullptr; - mEngine = nullptr; -} - - -void OpenSLCapture::processC(SLAndroidSimpleBufferQueueItf bq, void *context) -{ static_cast(context)->process(bq); } - -void OpenSLCapture::process(SLAndroidSimpleBufferQueueItf) -{ - /* A new chunk has been written into the ring buffer, advance it. */ - mRing->writeAdvance(1); -} - - -ALCenum OpenSLCapture::open(const ALCchar* name) -{ - if(!name) - name = opensl_device; - else if(strcmp(name, opensl_device) != 0) - return ALC_INVALID_VALUE; - - SLresult result{slCreateEngine(&mEngineObj, 0, nullptr, 0, nullptr, nullptr)}; - PRINTERR(result, "slCreateEngine"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(mEngineObj,Realize)(SL_BOOLEAN_FALSE); - PRINTERR(result, "engine->Realize"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(mEngineObj,GetInterface)(SL_IID_ENGINE, &mEngine); - PRINTERR(result, "engine->GetInterface"); - } - if(SL_RESULT_SUCCESS == result) - { - mFrameSize = mDevice->frameSizeFromFmt(); - /* Ensure the total length is at least 100ms */ - ALsizei length{maxi(mDevice->BufferSize, mDevice->Frequency/10)}; - /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */ - ALsizei update_len{clampi(mDevice->BufferSize/3, mDevice->Frequency/100, - mDevice->Frequency/100*5)}; - ALsizei num_updates{(length+update_len-1) / update_len}; - - try { - mRing = CreateRingBuffer(num_updates, update_len*mFrameSize, false); - - mDevice->UpdateSize = update_len; - mDevice->BufferSize = mRing->writeSpace() * update_len; - } - catch(std::exception& e) { - ERR("Failed to allocate ring buffer: %s\n", e.what()); - result = SL_RESULT_MEMORY_FAILURE; - } - } - if(SL_RESULT_SUCCESS == result) - { - const std::array ids{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }}; - const std::array reqs{{ SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }}; - - SLDataLocator_IODevice loc_dev{}; - loc_dev.locatorType = SL_DATALOCATOR_IODEVICE; - loc_dev.deviceType = SL_IODEVICE_AUDIOINPUT; - loc_dev.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT; - loc_dev.device = nullptr; - - SLDataSource audioSrc{}; - audioSrc.pLocator = &loc_dev; - audioSrc.pFormat = nullptr; - - SLDataLocator_AndroidSimpleBufferQueue loc_bq{}; - loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; - loc_bq.numBuffers = mDevice->BufferSize / mDevice->UpdateSize; - -#ifdef SL_ANDROID_DATAFORMAT_PCM_EX - SLAndroidDataFormat_PCM_EX format_pcm{}; - format_pcm.formatType = SL_ANDROID_DATAFORMAT_PCM_EX; - format_pcm.numChannels = mDevice->channelsFromFmt(); - format_pcm.sampleRate = mDevice->Frequency * 1000; - format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; - format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); - format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; - format_pcm.representation = GetTypeRepresentation(mDevice->FmtType); -#else - SLDataFormat_PCM format_pcm{}; - format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = mDevice->channelsFromFmt(); - format_pcm.samplesPerSec = mDevice->Frequency * 1000; - format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; - format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); - format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; -#endif - - SLDataSink audioSnk{}; - audioSnk.pLocator = &loc_bq; - audioSnk.pFormat = &format_pcm; - - result = VCALL(mEngine,CreateAudioRecorder)(&mRecordObj, &audioSrc, &audioSnk, - ids.size(), ids.data(), reqs.data()); - PRINTERR(result, "engine->CreateAudioRecorder"); - } - if(SL_RESULT_SUCCESS == result) - { - /* Set the record preset to "generic", if possible. */ - SLAndroidConfigurationItf config; - result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config); - PRINTERR(result, "recordObj->GetInterface SL_IID_ANDROIDCONFIGURATION"); - if(SL_RESULT_SUCCESS == result) - { - SLuint32 preset = SL_ANDROID_RECORDING_PRESET_GENERIC; - result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_RECORDING_PRESET, &preset, - sizeof(preset)); - PRINTERR(result, "config->SetConfiguration"); - } - - /* Clear any error since this was optional. */ - result = SL_RESULT_SUCCESS; - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(mRecordObj,Realize)(SL_BOOLEAN_FALSE); - PRINTERR(result, "recordObj->Realize"); - } - - SLAndroidSimpleBufferQueueItf bufferQueue; - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); - PRINTERR(result, "recordObj->GetInterface"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(bufferQueue,RegisterCallback)(&OpenSLCapture::processC, this); - PRINTERR(result, "bufferQueue->RegisterCallback"); - } - if(SL_RESULT_SUCCESS == result) - { - const ALuint chunk_size{mDevice->UpdateSize * mFrameSize}; - - auto data = mRing->getWriteVector(); - for(size_t i{0u};i < data.first.len && SL_RESULT_SUCCESS == result;i++) - { - result = VCALL(bufferQueue,Enqueue)(data.first.buf + chunk_size*i, chunk_size); - PRINTERR(result, "bufferQueue->Enqueue"); - } - for(size_t i{0u};i < data.second.len && SL_RESULT_SUCCESS == result;i++) - { - result = VCALL(bufferQueue,Enqueue)(data.second.buf + chunk_size*i, chunk_size); - PRINTERR(result, "bufferQueue->Enqueue"); - } - } - - if(SL_RESULT_SUCCESS != result) - { - if(mRecordObj) - VCALL0(mRecordObj,Destroy)(); - mRecordObj = nullptr; - - if(mEngineObj) - VCALL0(mEngineObj,Destroy)(); - mEngineObj = nullptr; - mEngine = nullptr; - - return ALC_INVALID_VALUE; - } - - mDevice->DeviceName = name; - return ALC_NO_ERROR; -} - -ALCboolean OpenSLCapture::start() -{ - SLRecordItf record; - SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_RECORD, &record)}; - PRINTERR(result, "recordObj->GetInterface"); - - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(record,SetRecordState)(SL_RECORDSTATE_RECORDING); - PRINTERR(result, "record->SetRecordState"); - } - - if(SL_RESULT_SUCCESS != result) - { - aluHandleDisconnect(mDevice, "Failed to start capture: 0x%08x", result); - return ALC_FALSE; - } - - return ALC_TRUE; -} - -void OpenSLCapture::stop() -{ - SLRecordItf record; - SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_RECORD, &record)}; - PRINTERR(result, "recordObj->GetInterface"); - - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(record,SetRecordState)(SL_RECORDSTATE_PAUSED); - PRINTERR(result, "record->SetRecordState"); - } -} - -ALCenum OpenSLCapture::captureSamples(void* buffer, ALCuint samples) -{ - ALsizei chunk_size = mDevice->UpdateSize * mFrameSize; - SLAndroidSimpleBufferQueueItf bufferQueue; - SLresult result; - ALCuint i; - - result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); - PRINTERR(result, "recordObj->GetInterface"); - - /* Read the desired samples from the ring buffer then advance its read - * pointer. - */ - auto data = mRing->getReadVector(); - for(i = 0;i < samples;) - { - ALCuint rem{minu(samples - i, mDevice->UpdateSize - mSplOffset)}; - memcpy((ALCbyte*)buffer + i*mFrameSize, data.first.buf + mSplOffset*mFrameSize, - rem * mFrameSize); - - mSplOffset += rem; - if(mSplOffset == mDevice->UpdateSize) - { - /* Finished a chunk, reset the offset and advance the read pointer. */ - mSplOffset = 0; - - mRing->readAdvance(1); - result = VCALL(bufferQueue,Enqueue)(data.first.buf, chunk_size); - PRINTERR(result, "bufferQueue->Enqueue"); - if(SL_RESULT_SUCCESS != result) break; - - data.first.len--; - if(!data.first.len) - data.first = data.second; - else - data.first.buf += chunk_size; - } - - i += rem; - } - - if(SL_RESULT_SUCCESS != result) - { - aluHandleDisconnect(mDevice, "Failed to update capture buffer: 0x%08x", result); - return ALC_INVALID_DEVICE; - } - - return ALC_NO_ERROR; -} - -ALCuint OpenSLCapture::availableSamples() -{ return mRing->readSpace()*mDevice->UpdateSize - mSplOffset; } - -} // namespace - -bool OSLBackendFactory::init() { return true; } - -bool OSLBackendFactory::querySupport(BackendType type) -{ return (type == BackendType::Playback || type == BackendType::Capture); } - -void OSLBackendFactory::probe(DevProbe type, std::string *outnames) -{ - switch(type) - { - case DevProbe::Playback: - case DevProbe::Capture: - /* Includes null char. */ - outnames->append(opensl_device, sizeof(opensl_device)); - break; - } -} - -BackendPtr OSLBackendFactory::createBackend(ALCdevice *device, BackendType type) -{ - if(type == BackendType::Playback) - return BackendPtr{new OpenSLPlayback{device}}; - if(type == BackendType::Capture) - return BackendPtr{new OpenSLCapture{device}}; - return nullptr; -} - -BackendFactory &OSLBackendFactory::getFactory() -{ - static OSLBackendFactory factory{}; - return factory; -} diff --git a/Alc/backends/opensl.h b/Alc/backends/opensl.h deleted file mode 100644 index 809aa339..00000000 --- a/Alc/backends/opensl.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef BACKENDS_OSL_H -#define BACKENDS_OSL_H - -#include "backends/base.h" - -struct OSLBackendFactory final : public BackendFactory { -public: - bool init() override; - - bool querySupport(BackendType type) override; - - void probe(DevProbe type, std::string *outnames) override; - - BackendPtr createBackend(ALCdevice *device, BackendType type) override; - - static BackendFactory &getFactory(); -}; - -#endif /* BACKENDS_OSL_H */ diff --git a/Alc/backends/oss.cpp b/Alc/backends/oss.cpp deleted file mode 100644 index 8cfe9e96..00000000 --- a/Alc/backends/oss.cpp +++ /dev/null @@ -1,751 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "backends/oss.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" - -#include "alcmain.h" -#include "alconfig.h" -#include "almalloc.h" -#include "alnumeric.h" -#include "aloptional.h" -#include "alu.h" -#include "logging.h" -#include "ringbuffer.h" -#include "threads.h" -#include "vector.h" - -#include - -/* - * The OSS documentation talks about SOUND_MIXER_READ, but the header - * only contains MIXER_READ. Play safe. Same for WRITE. - */ -#ifndef SOUND_MIXER_READ -#define SOUND_MIXER_READ MIXER_READ -#endif -#ifndef SOUND_MIXER_WRITE -#define SOUND_MIXER_WRITE MIXER_WRITE -#endif - -#if defined(SOUND_VERSION) && (SOUND_VERSION < 0x040000) -#define ALC_OSS_COMPAT -#endif -#ifndef SNDCTL_AUDIOINFO -#define ALC_OSS_COMPAT -#endif - -/* - * FreeBSD strongly discourages the use of specific devices, - * such as those returned in oss_audioinfo.devnode - */ -#ifdef __FreeBSD__ -#define ALC_OSS_DEVNODE_TRUC -#endif - -namespace { - -constexpr char DefaultName[] = "OSS Default"; -std::string DefaultPlayback{"/dev/dsp"}; -std::string DefaultCapture{"/dev/dsp"}; - -struct DevMap { - std::string name; - std::string device_name; -}; - -bool checkName(const al::vector &list, const std::string &name) -{ - return std::find_if(list.cbegin(), list.cend(), - [&name](const DevMap &entry) -> bool - { return entry.name == name; } - ) != list.cend(); -} - -al::vector PlaybackDevices; -al::vector CaptureDevices; - - -#ifdef ALC_OSS_COMPAT - -#define DSP_CAP_OUTPUT 0x00020000 -#define DSP_CAP_INPUT 0x00010000 -void ALCossListPopulate(al::vector *devlist, int type) -{ - devlist->emplace_back(DevMap{DefaultName, (type==DSP_CAP_INPUT) ? DefaultCapture : DefaultPlayback}); -} - -#else - -void ALCossListAppend(al::vector *list, const char *handle, size_t hlen, const char *path, size_t plen) -{ -#ifdef ALC_OSS_DEVNODE_TRUC - for(size_t i{0};i < plen;i++) - { - if(path[i] == '.') - { - if(strncmp(path + i, handle + hlen + i - plen, plen - i) == 0) - hlen = hlen + i - plen; - plen = i; - } - } -#endif - if(handle[0] == '\0') - { - handle = path; - hlen = plen; - } - - std::string basename{handle, hlen}; - basename.erase(std::find(basename.begin(), basename.end(), '\0'), basename.end()); - std::string devname{path, plen}; - devname.erase(std::find(devname.begin(), devname.end(), '\0'), devname.end()); - - auto iter = std::find_if(list->cbegin(), list->cend(), - [&devname](const DevMap &entry) -> bool - { return entry.device_name == devname; } - ); - if(iter != list->cend()) - return; - - int count{1}; - std::string newname{basename}; - while(checkName(PlaybackDevices, newname)) - { - newname = basename; - newname += " #"; - newname += std::to_string(++count); - } - - list->emplace_back(DevMap{std::move(newname), std::move(devname)}); - const DevMap &entry = list->back(); - - TRACE("Got device \"%s\", \"%s\"\n", entry.name.c_str(), entry.device_name.c_str()); -} - -void ALCossListPopulate(al::vector *devlist, int type_flag) -{ - int fd{open("/dev/mixer", O_RDONLY)}; - if(fd < 0) - { - TRACE("Could not open /dev/mixer: %s\n", strerror(errno)); - goto done; - } - - oss_sysinfo si; - if(ioctl(fd, SNDCTL_SYSINFO, &si) == -1) - { - TRACE("SNDCTL_SYSINFO failed: %s\n", strerror(errno)); - goto done; - } - - for(int i{0};i < si.numaudios;i++) - { - oss_audioinfo ai; - ai.dev = i; - if(ioctl(fd, SNDCTL_AUDIOINFO, &ai) == -1) - { - ERR("SNDCTL_AUDIOINFO (%d) failed: %s\n", i, strerror(errno)); - continue; - } - if(!(ai.caps&type_flag) || ai.devnode[0] == '\0') - continue; - - const char *handle; - size_t len; - if(ai.handle[0] != '\0') - { - len = strnlen(ai.handle, sizeof(ai.handle)); - handle = ai.handle; - } - else - { - len = strnlen(ai.name, sizeof(ai.name)); - handle = ai.name; - } - - ALCossListAppend(devlist, handle, len, ai.devnode, - strnlen(ai.devnode, sizeof(ai.devnode))); - } - -done: - if(fd >= 0) - close(fd); - fd = -1; - - const char *defdev{((type_flag==DSP_CAP_INPUT) ? DefaultCapture : DefaultPlayback).c_str()}; - auto iter = std::find_if(devlist->cbegin(), devlist->cend(), - [defdev](const DevMap &entry) -> bool - { return entry.device_name == defdev; } - ); - if(iter == devlist->cend()) - devlist->insert(devlist->begin(), DevMap{DefaultName, defdev}); - else - { - DevMap entry{std::move(*iter)}; - devlist->erase(iter); - devlist->insert(devlist->begin(), std::move(entry)); - } - devlist->shrink_to_fit(); -} - -#endif - -int log2i(ALCuint x) -{ - int y = 0; - while (x > 1) - { - x >>= 1; - y++; - } - return y; -} - - -struct OSSPlayback final : public BackendBase { - OSSPlayback(ALCdevice *device) noexcept : BackendBase{device} { } - ~OSSPlayback() override; - - int mixerProc(); - - ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; - void stop() override; - - int mFd{-1}; - - al::vector mMixData; - - std::atomic mKillNow{true}; - std::thread mThread; - - DEF_NEWDEL(OSSPlayback) -}; - -OSSPlayback::~OSSPlayback() -{ - if(mFd != -1) - close(mFd); - mFd = -1; -} - - -int OSSPlayback::mixerProc() -{ - SetRTPriority(); - althrd_setname(MIXER_THREAD_NAME); - - const int frame_size{mDevice->frameSizeFromFmt()}; - - lock(); - while(!mKillNow.load(std::memory_order_acquire) && - mDevice->Connected.load(std::memory_order_acquire)) - { - pollfd pollitem{}; - pollitem.fd = mFd; - pollitem.events = POLLOUT; - - unlock(); - int pret{poll(&pollitem, 1, 1000)}; - lock(); - if(pret < 0) - { - if(errno == EINTR || errno == EAGAIN) - continue; - ERR("poll failed: %s\n", strerror(errno)); - aluHandleDisconnect(mDevice, "Failed waiting for playback buffer: %s", strerror(errno)); - break; - } - else if(pret == 0) - { - WARN("poll timeout\n"); - continue; - } - - ALubyte *write_ptr{mMixData.data()}; - size_t to_write{mMixData.size()}; - aluMixData(mDevice, write_ptr, to_write/frame_size); - while(to_write > 0 && !mKillNow.load(std::memory_order_acquire)) - { - ssize_t wrote{write(mFd, write_ptr, to_write)}; - if(wrote < 0) - { - if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) - continue; - ERR("write failed: %s\n", strerror(errno)); - aluHandleDisconnect(mDevice, "Failed writing playback samples: %s", - strerror(errno)); - break; - } - - to_write -= wrote; - write_ptr += wrote; - } - } - unlock(); - - return 0; -} - - -ALCenum OSSPlayback::open(const ALCchar *name) -{ - const char *devname{DefaultPlayback.c_str()}; - if(!name) - name = DefaultName; - else - { - if(PlaybackDevices.empty()) - ALCossListPopulate(&PlaybackDevices, DSP_CAP_OUTPUT); - - auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), - [&name](const DevMap &entry) -> bool - { return entry.name == name; } - ); - if(iter == PlaybackDevices.cend()) - return ALC_INVALID_VALUE; - devname = iter->device_name.c_str(); - } - - mFd = ::open(devname, O_WRONLY); - if(mFd == -1) - { - ERR("Could not open %s: %s\n", devname, strerror(errno)); - return ALC_INVALID_VALUE; - } - - mDevice->DeviceName = name; - return ALC_NO_ERROR; -} - -ALCboolean OSSPlayback::reset() -{ - int numFragmentsLogSize; - int log2FragmentSize; - unsigned int periods; - audio_buf_info info; - ALuint frameSize; - int numChannels; - int ossFormat; - int ossSpeed; - const char *err; - - switch(mDevice->FmtType) - { - case DevFmtByte: - ossFormat = AFMT_S8; - break; - case DevFmtUByte: - ossFormat = AFMT_U8; - break; - case DevFmtUShort: - case DevFmtInt: - case DevFmtUInt: - case DevFmtFloat: - mDevice->FmtType = DevFmtShort; - /* fall-through */ - case DevFmtShort: - ossFormat = AFMT_S16_NE; - break; - } - - periods = mDevice->BufferSize / mDevice->UpdateSize; - numChannels = mDevice->channelsFromFmt(); - ossSpeed = mDevice->Frequency; - frameSize = numChannels * mDevice->bytesFromFmt(); - /* According to the OSS spec, 16 bytes (log2(16)) is the minimum. */ - log2FragmentSize = maxi(log2i(mDevice->UpdateSize*frameSize), 4); - numFragmentsLogSize = (periods << 16) | log2FragmentSize; - -#define CHECKERR(func) if((func) < 0) { \ - err = #func; \ - goto err; \ -} - /* Don't fail if SETFRAGMENT fails. We can handle just about anything - * that's reported back via GETOSPACE */ - ioctl(mFd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize); - CHECKERR(ioctl(mFd, SNDCTL_DSP_SETFMT, &ossFormat)); - CHECKERR(ioctl(mFd, SNDCTL_DSP_CHANNELS, &numChannels)); - CHECKERR(ioctl(mFd, SNDCTL_DSP_SPEED, &ossSpeed)); - CHECKERR(ioctl(mFd, SNDCTL_DSP_GETOSPACE, &info)); - if(0) - { - err: - ERR("%s failed: %s\n", err, strerror(errno)); - return ALC_FALSE; - } -#undef CHECKERR - - if(mDevice->channelsFromFmt() != numChannels) - { - ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(mDevice->FmtChans), - numChannels); - return ALC_FALSE; - } - - if(!((ossFormat == AFMT_S8 && mDevice->FmtType == DevFmtByte) || - (ossFormat == AFMT_U8 && mDevice->FmtType == DevFmtUByte) || - (ossFormat == AFMT_S16_NE && mDevice->FmtType == DevFmtShort))) - { - ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(mDevice->FmtType), - ossFormat); - return ALC_FALSE; - } - - mDevice->Frequency = ossSpeed; - mDevice->UpdateSize = info.fragsize / frameSize; - mDevice->BufferSize = info.fragments * mDevice->UpdateSize; - - SetDefaultChannelOrder(mDevice); - - mMixData.resize(mDevice->UpdateSize * mDevice->frameSizeFromFmt()); - - return ALC_TRUE; -} - -ALCboolean OSSPlayback::start() -{ - try { - mKillNow.store(false, std::memory_order_release); - mThread = std::thread{std::mem_fn(&OSSPlayback::mixerProc), this}; - return ALC_TRUE; - } - catch(std::exception& e) { - ERR("Could not create playback thread: %s\n", e.what()); - } - catch(...) { - } - return ALC_FALSE; -} - -void OSSPlayback::stop() -{ - if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) - return; - mThread.join(); - - if(ioctl(mFd, SNDCTL_DSP_RESET) != 0) - ERR("Error resetting device: %s\n", strerror(errno)); -} - - -struct OSScapture final : public BackendBase { - OSScapture(ALCdevice *device) noexcept : BackendBase{device} { } - ~OSScapture() override; - - int recordProc(); - - ALCenum open(const ALCchar *name) override; - ALCboolean start() override; - void stop() override; - ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override; - ALCuint availableSamples() override; - - int mFd{-1}; - - RingBufferPtr mRing{nullptr}; - - std::atomic mKillNow{true}; - std::thread mThread; - - DEF_NEWDEL(OSScapture) -}; - -OSScapture::~OSScapture() -{ - if(mFd != -1) - close(mFd); - mFd = -1; -} - - -int OSScapture::recordProc() -{ - SetRTPriority(); - althrd_setname(RECORD_THREAD_NAME); - - const int frame_size{mDevice->frameSizeFromFmt()}; - while(!mKillNow.load(std::memory_order_acquire)) - { - pollfd pollitem{}; - pollitem.fd = mFd; - pollitem.events = POLLIN; - - int sret{poll(&pollitem, 1, 1000)}; - if(sret < 0) - { - if(errno == EINTR || errno == EAGAIN) - continue; - ERR("poll failed: %s\n", strerror(errno)); - aluHandleDisconnect(mDevice, "Failed to check capture samples: %s", strerror(errno)); - break; - } - else if(sret == 0) - { - WARN("poll timeout\n"); - continue; - } - - auto vec = mRing->getWriteVector(); - if(vec.first.len > 0) - { - ssize_t amt{read(mFd, vec.first.buf, vec.first.len*frame_size)}; - if(amt < 0) - { - ERR("read failed: %s\n", strerror(errno)); - aluHandleDisconnect(mDevice, "Failed reading capture samples: %s", - strerror(errno)); - break; - } - mRing->writeAdvance(amt/frame_size); - } - } - - return 0; -} - - -ALCenum OSScapture::open(const ALCchar *name) -{ - const char *devname{DefaultCapture.c_str()}; - if(!name) - name = DefaultName; - else - { - if(CaptureDevices.empty()) - ALCossListPopulate(&CaptureDevices, DSP_CAP_INPUT); - - auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), - [&name](const DevMap &entry) -> bool - { return entry.name == name; } - ); - if(iter == CaptureDevices.cend()) - return ALC_INVALID_VALUE; - devname = iter->device_name.c_str(); - } - - mFd = ::open(devname, O_RDONLY); - if(mFd == -1) - { - ERR("Could not open %s: %s\n", devname, strerror(errno)); - return ALC_INVALID_VALUE; - } - - int ossFormat{}; - switch(mDevice->FmtType) - { - case DevFmtByte: - ossFormat = AFMT_S8; - break; - case DevFmtUByte: - ossFormat = AFMT_U8; - break; - case DevFmtShort: - ossFormat = AFMT_S16_NE; - break; - case DevFmtUShort: - case DevFmtInt: - case DevFmtUInt: - case DevFmtFloat: - ERR("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); - return ALC_INVALID_VALUE; - } - - int periods{4}; - int numChannels{mDevice->channelsFromFmt()}; - int frameSize{numChannels * mDevice->bytesFromFmt()}; - int ossSpeed{static_cast(mDevice->Frequency)}; - int log2FragmentSize{log2i(mDevice->BufferSize * frameSize / periods)}; - - /* according to the OSS spec, 16 bytes are the minimum */ - log2FragmentSize = std::max(log2FragmentSize, 4); - int numFragmentsLogSize{(periods << 16) | log2FragmentSize}; - - audio_buf_info info; - const char *err; -#define CHECKERR(func) if((func) < 0) { \ - err = #func; \ - goto err; \ -} - CHECKERR(ioctl(mFd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize)); - CHECKERR(ioctl(mFd, SNDCTL_DSP_SETFMT, &ossFormat)); - CHECKERR(ioctl(mFd, SNDCTL_DSP_CHANNELS, &numChannels)); - CHECKERR(ioctl(mFd, SNDCTL_DSP_SPEED, &ossSpeed)); - CHECKERR(ioctl(mFd, SNDCTL_DSP_GETISPACE, &info)); - if(0) - { - err: - ERR("%s failed: %s\n", err, strerror(errno)); - close(mFd); - mFd = -1; - return ALC_INVALID_VALUE; - } -#undef CHECKERR - - if(mDevice->channelsFromFmt() != numChannels) - { - ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(mDevice->FmtChans), - numChannels); - close(mFd); - mFd = -1; - return ALC_INVALID_VALUE; - } - - if(!((ossFormat == AFMT_S8 && mDevice->FmtType == DevFmtByte) || - (ossFormat == AFMT_U8 && mDevice->FmtType == DevFmtUByte) || - (ossFormat == AFMT_S16_NE && mDevice->FmtType == DevFmtShort))) - { - ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(mDevice->FmtType), ossFormat); - close(mFd); - mFd = -1; - return ALC_INVALID_VALUE; - } - - mRing = CreateRingBuffer(mDevice->BufferSize, frameSize, false); - if(!mRing) - { - ERR("Ring buffer create failed\n"); - close(mFd); - mFd = -1; - return ALC_OUT_OF_MEMORY; - } - - mDevice->DeviceName = name; - return ALC_NO_ERROR; -} - -ALCboolean OSScapture::start() -{ - try { - mKillNow.store(false, std::memory_order_release); - mThread = std::thread{std::mem_fn(&OSScapture::recordProc), this}; - return ALC_TRUE; - } - catch(std::exception& e) { - ERR("Could not create record thread: %s\n", e.what()); - } - catch(...) { - } - return ALC_FALSE; -} - -void OSScapture::stop() -{ - if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) - return; - mThread.join(); - - if(ioctl(mFd, SNDCTL_DSP_RESET) != 0) - ERR("Error resetting device: %s\n", strerror(errno)); -} - -ALCenum OSScapture::captureSamples(ALCvoid *buffer, ALCuint samples) -{ - mRing->read(buffer, samples); - return ALC_NO_ERROR; -} - -ALCuint OSScapture::availableSamples() -{ return mRing->readSpace(); } - -} // namespace - - -BackendFactory &OSSBackendFactory::getFactory() -{ - static OSSBackendFactory factory{}; - return factory; -} - -bool OSSBackendFactory::init() -{ - if(auto devopt = ConfigValueStr(nullptr, "oss", "device")) - DefaultPlayback = std::move(*devopt); - if(auto capopt = ConfigValueStr(nullptr, "oss", "capture")) - DefaultCapture = std::move(*capopt); - - return true; -} - -bool OSSBackendFactory::querySupport(BackendType type) -{ return (type == BackendType::Playback || type == BackendType::Capture); } - -void OSSBackendFactory::probe(DevProbe type, std::string *outnames) -{ - auto add_device = [outnames](const DevMap &entry) -> void - { -#ifdef HAVE_STAT - struct stat buf; - if(stat(entry.device_name.c_str(), &buf) == 0) -#endif - { - /* Includes null char. */ - outnames->append(entry.name.c_str(), entry.name.length()+1); - } - }; - - switch(type) - { - case DevProbe::Playback: - PlaybackDevices.clear(); - ALCossListPopulate(&PlaybackDevices, DSP_CAP_OUTPUT); - std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); - break; - - case DevProbe::Capture: - CaptureDevices.clear(); - ALCossListPopulate(&CaptureDevices, DSP_CAP_INPUT); - std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); - break; - } -} - -BackendPtr OSSBackendFactory::createBackend(ALCdevice *device, BackendType type) -{ - if(type == BackendType::Playback) - return BackendPtr{new OSSPlayback{device}}; - if(type == BackendType::Capture) - return BackendPtr{new OSScapture{device}}; - return nullptr; -} diff --git a/Alc/backends/oss.h b/Alc/backends/oss.h deleted file mode 100644 index 9e63d7b6..00000000 --- a/Alc/backends/oss.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef BACKENDS_OSS_H -#define BACKENDS_OSS_H - -#include "backends/base.h" - -struct OSSBackendFactory final : public BackendFactory { -public: - bool init() override; - - bool querySupport(BackendType type) override; - - void probe(DevProbe type, std::string *outnames) override; - - BackendPtr createBackend(ALCdevice *device, BackendType type) override; - - static BackendFactory &getFactory(); -}; - -#endif /* BACKENDS_OSS_H */ diff --git a/Alc/backends/portaudio.cpp b/Alc/backends/portaudio.cpp deleted file mode 100644 index 73e972c5..00000000 --- a/Alc/backends/portaudio.cpp +++ /dev/null @@ -1,463 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "backends/portaudio.h" - -#include -#include -#include - -#include "alcmain.h" -#include "alu.h" -#include "alconfig.h" -#include "ringbuffer.h" -#include "compat.h" - -#include - - -namespace { - -constexpr ALCchar pa_device[] = "PortAudio Default"; - - -#ifdef HAVE_DYNLOAD -void *pa_handle; -#define MAKE_FUNC(x) decltype(x) * p##x -MAKE_FUNC(Pa_Initialize); -MAKE_FUNC(Pa_Terminate); -MAKE_FUNC(Pa_GetErrorText); -MAKE_FUNC(Pa_StartStream); -MAKE_FUNC(Pa_StopStream); -MAKE_FUNC(Pa_OpenStream); -MAKE_FUNC(Pa_CloseStream); -MAKE_FUNC(Pa_GetDefaultOutputDevice); -MAKE_FUNC(Pa_GetDefaultInputDevice); -MAKE_FUNC(Pa_GetStreamInfo); -#undef MAKE_FUNC - -#ifndef IN_IDE_PARSER -#define Pa_Initialize pPa_Initialize -#define Pa_Terminate pPa_Terminate -#define Pa_GetErrorText pPa_GetErrorText -#define Pa_StartStream pPa_StartStream -#define Pa_StopStream pPa_StopStream -#define Pa_OpenStream pPa_OpenStream -#define Pa_CloseStream pPa_CloseStream -#define Pa_GetDefaultOutputDevice pPa_GetDefaultOutputDevice -#define Pa_GetDefaultInputDevice pPa_GetDefaultInputDevice -#define Pa_GetStreamInfo pPa_GetStreamInfo -#endif -#endif - - -struct PortPlayback final : public BackendBase { - PortPlayback(ALCdevice *device) noexcept : BackendBase{device} { } - ~PortPlayback() override; - - static int writeCallbackC(const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, - const PaStreamCallbackFlags statusFlags, void *userData); - int writeCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags); - - ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; - void stop() override; - - PaStream *mStream{nullptr}; - PaStreamParameters mParams{}; - ALuint mUpdateSize{0u}; - - DEF_NEWDEL(PortPlayback) -}; - -PortPlayback::~PortPlayback() -{ - PaError err{mStream ? Pa_CloseStream(mStream) : paNoError}; - if(err != paNoError) - ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); - mStream = nullptr; -} - - -int PortPlayback::writeCallbackC(const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, - const PaStreamCallbackFlags statusFlags, void *userData) -{ - return static_cast(userData)->writeCallback(inputBuffer, outputBuffer, - framesPerBuffer, timeInfo, statusFlags); -} - -int PortPlayback::writeCallback(const void*, void *outputBuffer, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo*, - const PaStreamCallbackFlags) -{ - lock(); - aluMixData(mDevice, outputBuffer, framesPerBuffer); - unlock(); - return 0; -} - - -ALCenum PortPlayback::open(const ALCchar *name) -{ - if(!name) - name = pa_device; - else if(strcmp(name, pa_device) != 0) - return ALC_INVALID_VALUE; - - mUpdateSize = mDevice->UpdateSize; - - auto devidopt = ConfigValueInt(nullptr, "port", "device"); - if(devidopt && *devidopt >= 0) mParams.device = *devidopt; - else mParams.device = Pa_GetDefaultOutputDevice(); - mParams.suggestedLatency = mDevice->BufferSize / static_cast(mDevice->Frequency); - mParams.hostApiSpecificStreamInfo = nullptr; - - mParams.channelCount = ((mDevice->FmtChans == DevFmtMono) ? 1 : 2); - - switch(mDevice->FmtType) - { - case DevFmtByte: - mParams.sampleFormat = paInt8; - break; - case DevFmtUByte: - mParams.sampleFormat = paUInt8; - break; - case DevFmtUShort: - /* fall-through */ - case DevFmtShort: - mParams.sampleFormat = paInt16; - break; - case DevFmtUInt: - /* fall-through */ - case DevFmtInt: - mParams.sampleFormat = paInt32; - break; - case DevFmtFloat: - mParams.sampleFormat = paFloat32; - break; - } - -retry_open: - PaError err{Pa_OpenStream(&mStream, nullptr, &mParams, mDevice->Frequency, mDevice->UpdateSize, - paNoFlag, &PortPlayback::writeCallbackC, this)}; - if(err != paNoError) - { - if(mParams.sampleFormat == paFloat32) - { - mParams.sampleFormat = paInt16; - goto retry_open; - } - ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); - return ALC_INVALID_VALUE; - } - - mDevice->DeviceName = name; - return ALC_NO_ERROR; - -} - -ALCboolean PortPlayback::reset() -{ - const PaStreamInfo *streamInfo{Pa_GetStreamInfo(mStream)}; - mDevice->Frequency = streamInfo->sampleRate; - mDevice->UpdateSize = mUpdateSize; - - if(mParams.sampleFormat == paInt8) - mDevice->FmtType = DevFmtByte; - else if(mParams.sampleFormat == paUInt8) - mDevice->FmtType = DevFmtUByte; - else if(mParams.sampleFormat == paInt16) - mDevice->FmtType = DevFmtShort; - else if(mParams.sampleFormat == paInt32) - mDevice->FmtType = DevFmtInt; - else if(mParams.sampleFormat == paFloat32) - mDevice->FmtType = DevFmtFloat; - else - { - ERR("Unexpected sample format: 0x%lx\n", mParams.sampleFormat); - return ALC_FALSE; - } - - if(mParams.channelCount == 2) - mDevice->FmtChans = DevFmtStereo; - else if(mParams.channelCount == 1) - mDevice->FmtChans = DevFmtMono; - else - { - ERR("Unexpected channel count: %u\n", mParams.channelCount); - return ALC_FALSE; - } - SetDefaultChannelOrder(mDevice); - - return ALC_TRUE; -} - -ALCboolean PortPlayback::start() -{ - PaError err{Pa_StartStream(mStream)}; - if(err != paNoError) - { - ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err)); - return ALC_FALSE; - } - return ALC_TRUE; -} - -void PortPlayback::stop() -{ - PaError err{Pa_StopStream(mStream)}; - if(err != paNoError) - ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); -} - - -struct PortCapture final : public BackendBase { - PortCapture(ALCdevice *device) noexcept : BackendBase{device} { } - ~PortCapture() override; - - static int readCallbackC(const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, - const PaStreamCallbackFlags statusFlags, void *userData); - int readCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags); - - ALCenum open(const ALCchar *name) override; - ALCboolean start() override; - void stop() override; - ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override; - ALCuint availableSamples() override; - - PaStream *mStream{nullptr}; - PaStreamParameters mParams; - - RingBufferPtr mRing{nullptr}; - - DEF_NEWDEL(PortCapture) -}; - -PortCapture::~PortCapture() -{ - PaError err{mStream ? Pa_CloseStream(mStream) : paNoError}; - if(err != paNoError) - ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); - mStream = nullptr; -} - - -int PortCapture::readCallbackC(const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, - const PaStreamCallbackFlags statusFlags, void* userData) -{ - return static_cast(userData)->readCallback(inputBuffer, outputBuffer, - framesPerBuffer, timeInfo, statusFlags); -} - -int PortCapture::readCallback(const void *inputBuffer, void*, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo*, - const PaStreamCallbackFlags) -{ - mRing->write(inputBuffer, framesPerBuffer); - return 0; -} - - -ALCenum PortCapture::open(const ALCchar *name) -{ - if(!name) - name = pa_device; - else if(strcmp(name, pa_device) != 0) - return ALC_INVALID_VALUE; - - ALuint samples{mDevice->BufferSize}; - samples = maxu(samples, 100 * mDevice->Frequency / 1000); - ALsizei frame_size{mDevice->frameSizeFromFmt()}; - - mRing = CreateRingBuffer(samples, frame_size, false); - if(!mRing) return ALC_INVALID_VALUE; - - auto devidopt = ConfigValueInt(nullptr, "port", "capture"); - if(devidopt && *devidopt >= 0) mParams.device = *devidopt; - else mParams.device = Pa_GetDefaultOutputDevice(); - mParams.suggestedLatency = 0.0f; - mParams.hostApiSpecificStreamInfo = nullptr; - - switch(mDevice->FmtType) - { - case DevFmtByte: - mParams.sampleFormat = paInt8; - break; - case DevFmtUByte: - mParams.sampleFormat = paUInt8; - break; - case DevFmtShort: - mParams.sampleFormat = paInt16; - break; - case DevFmtInt: - mParams.sampleFormat = paInt32; - break; - case DevFmtFloat: - mParams.sampleFormat = paFloat32; - break; - case DevFmtUInt: - case DevFmtUShort: - ERR("%s samples not supported\n", DevFmtTypeString(mDevice->FmtType)); - return ALC_INVALID_VALUE; - } - mParams.channelCount = mDevice->channelsFromFmt(); - - PaError err{Pa_OpenStream(&mStream, &mParams, nullptr, mDevice->Frequency, - paFramesPerBufferUnspecified, paNoFlag, &PortCapture::readCallbackC, this)}; - if(err != paNoError) - { - ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); - return ALC_INVALID_VALUE; - } - - mDevice->DeviceName = name; - return ALC_NO_ERROR; -} - - -ALCboolean PortCapture::start() -{ - PaError err{Pa_StartStream(mStream)}; - if(err != paNoError) - { - ERR("Error starting stream: %s\n", Pa_GetErrorText(err)); - return ALC_FALSE; - } - return ALC_TRUE; -} - -void PortCapture::stop() -{ - PaError err{Pa_StopStream(mStream)}; - if(err != paNoError) - ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); -} - - -ALCuint PortCapture::availableSamples() -{ return mRing->readSpace(); } - -ALCenum PortCapture::captureSamples(ALCvoid *buffer, ALCuint samples) -{ - mRing->read(buffer, samples); - return ALC_NO_ERROR; -} - -} // namespace - - -bool PortBackendFactory::init() -{ - PaError err; - -#ifdef HAVE_DYNLOAD - if(!pa_handle) - { -#ifdef _WIN32 -# define PALIB "portaudio.dll" -#elif defined(__APPLE__) && defined(__MACH__) -# define PALIB "libportaudio.2.dylib" -#elif defined(__OpenBSD__) -# define PALIB "libportaudio.so" -#else -# define PALIB "libportaudio.so.2" -#endif - - pa_handle = LoadLib(PALIB); - if(!pa_handle) - return false; - -#define LOAD_FUNC(f) do { \ - p##f = reinterpret_cast(GetSymbol(pa_handle, #f)); \ - if(p##f == nullptr) \ - { \ - CloseLib(pa_handle); \ - pa_handle = nullptr; \ - return false; \ - } \ -} while(0) - LOAD_FUNC(Pa_Initialize); - LOAD_FUNC(Pa_Terminate); - LOAD_FUNC(Pa_GetErrorText); - LOAD_FUNC(Pa_StartStream); - LOAD_FUNC(Pa_StopStream); - LOAD_FUNC(Pa_OpenStream); - LOAD_FUNC(Pa_CloseStream); - LOAD_FUNC(Pa_GetDefaultOutputDevice); - LOAD_FUNC(Pa_GetDefaultInputDevice); - LOAD_FUNC(Pa_GetStreamInfo); -#undef LOAD_FUNC - - if((err=Pa_Initialize()) != paNoError) - { - ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err)); - CloseLib(pa_handle); - pa_handle = nullptr; - return false; - } - } -#else - if((err=Pa_Initialize()) != paNoError) - { - ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err)); - return false; - } -#endif - return true; -} - -bool PortBackendFactory::querySupport(BackendType type) -{ return (type == BackendType::Playback || type == BackendType::Capture); } - -void PortBackendFactory::probe(DevProbe type, std::string *outnames) -{ - switch(type) - { - case DevProbe::Playback: - case DevProbe::Capture: - /* Includes null char. */ - outnames->append(pa_device, sizeof(pa_device)); - break; - } -} - -BackendPtr PortBackendFactory::createBackend(ALCdevice *device, BackendType type) -{ - if(type == BackendType::Playback) - return BackendPtr{new PortPlayback{device}}; - if(type == BackendType::Capture) - return BackendPtr{new PortCapture{device}}; - return nullptr; -} - -BackendFactory &PortBackendFactory::getFactory() -{ - static PortBackendFactory factory{}; - return factory; -} diff --git a/Alc/backends/portaudio.h b/Alc/backends/portaudio.h deleted file mode 100644 index 082e9020..00000000 --- a/Alc/backends/portaudio.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef BACKENDS_PORTAUDIO_H -#define BACKENDS_PORTAUDIO_H - -#include "backends/base.h" - -struct PortBackendFactory final : public BackendFactory { -public: - bool init() override; - - bool querySupport(BackendType type) override; - - void probe(DevProbe type, std::string *outnames) override; - - BackendPtr createBackend(ALCdevice *device, BackendType type) override; - - static BackendFactory &getFactory(); -}; - -#endif /* BACKENDS_PORTAUDIO_H */ diff --git a/Alc/backends/pulseaudio.cpp b/Alc/backends/pulseaudio.cpp deleted file mode 100644 index da209c8d..00000000 --- a/Alc/backends/pulseaudio.cpp +++ /dev/null @@ -1,1532 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2009 by Konstantinos Natsakis - * Copyright (C) 2010 by Chris Robinson - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "backends/pulseaudio.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "alcmain.h" -#include "alu.h" -#include "alconfig.h" -#include "compat.h" -#include "alexcpt.h" - -#include - - -namespace { - -#ifdef HAVE_DYNLOAD -#define PULSE_FUNCS(MAGIC) \ - MAGIC(pa_mainloop_new); \ - MAGIC(pa_mainloop_free); \ - MAGIC(pa_mainloop_set_poll_func); \ - MAGIC(pa_mainloop_run); \ - MAGIC(pa_mainloop_get_api); \ - MAGIC(pa_context_new); \ - MAGIC(pa_context_unref); \ - MAGIC(pa_context_get_state); \ - MAGIC(pa_context_disconnect); \ - MAGIC(pa_context_set_state_callback); \ - MAGIC(pa_context_errno); \ - MAGIC(pa_context_connect); \ - MAGIC(pa_context_get_server_info); \ - MAGIC(pa_context_get_sink_info_by_name); \ - MAGIC(pa_context_get_sink_info_list); \ - MAGIC(pa_context_get_source_info_by_name); \ - MAGIC(pa_context_get_source_info_list); \ - MAGIC(pa_stream_new); \ - MAGIC(pa_stream_unref); \ - MAGIC(pa_stream_drop); \ - MAGIC(pa_stream_get_state); \ - MAGIC(pa_stream_peek); \ - MAGIC(pa_stream_write); \ - MAGIC(pa_stream_connect_record); \ - MAGIC(pa_stream_connect_playback); \ - MAGIC(pa_stream_readable_size); \ - MAGIC(pa_stream_writable_size); \ - MAGIC(pa_stream_is_corked); \ - MAGIC(pa_stream_cork); \ - MAGIC(pa_stream_is_suspended); \ - MAGIC(pa_stream_get_device_name); \ - MAGIC(pa_stream_get_latency); \ - MAGIC(pa_stream_set_write_callback); \ - MAGIC(pa_stream_set_buffer_attr); \ - MAGIC(pa_stream_get_buffer_attr); \ - MAGIC(pa_stream_get_sample_spec); \ - MAGIC(pa_stream_get_time); \ - MAGIC(pa_stream_set_read_callback); \ - MAGIC(pa_stream_set_state_callback); \ - MAGIC(pa_stream_set_moved_callback); \ - MAGIC(pa_stream_set_underflow_callback); \ - MAGIC(pa_stream_new_with_proplist); \ - MAGIC(pa_stream_disconnect); \ - MAGIC(pa_stream_set_buffer_attr_callback); \ - MAGIC(pa_stream_begin_write); \ - MAGIC(pa_channel_map_init_auto); \ - MAGIC(pa_channel_map_parse); \ - MAGIC(pa_channel_map_snprint); \ - MAGIC(pa_channel_map_equal); \ - MAGIC(pa_channel_map_superset); \ - MAGIC(pa_operation_get_state); \ - MAGIC(pa_operation_unref); \ - MAGIC(pa_sample_spec_valid); \ - MAGIC(pa_frame_size); \ - MAGIC(pa_strerror); \ - MAGIC(pa_path_get_filename); \ - MAGIC(pa_get_binary_name); \ - MAGIC(pa_xmalloc); \ - MAGIC(pa_xfree); - -void *pulse_handle; -#define MAKE_FUNC(x) decltype(x) * p##x -PULSE_FUNCS(MAKE_FUNC) -#undef MAKE_FUNC - -#ifndef IN_IDE_PARSER -#define pa_mainloop_new ppa_mainloop_new -#define pa_mainloop_free ppa_mainloop_free -#define pa_mainloop_set_poll_func ppa_mainloop_set_poll_func -#define pa_mainloop_run ppa_mainloop_run -#define pa_mainloop_get_api ppa_mainloop_get_api -#define pa_context_new ppa_context_new -#define pa_context_unref ppa_context_unref -#define pa_context_get_state ppa_context_get_state -#define pa_context_disconnect ppa_context_disconnect -#define pa_context_set_state_callback ppa_context_set_state_callback -#define pa_context_errno ppa_context_errno -#define pa_context_connect ppa_context_connect -#define pa_context_get_server_info ppa_context_get_server_info -#define pa_context_get_sink_info_by_name ppa_context_get_sink_info_by_name -#define pa_context_get_sink_info_list ppa_context_get_sink_info_list -#define pa_context_get_source_info_by_name ppa_context_get_source_info_by_name -#define pa_context_get_source_info_list ppa_context_get_source_info_list -#define pa_stream_new ppa_stream_new -#define pa_stream_unref ppa_stream_unref -#define pa_stream_disconnect ppa_stream_disconnect -#define pa_stream_drop ppa_stream_drop -#define pa_stream_set_write_callback ppa_stream_set_write_callback -#define pa_stream_set_buffer_attr ppa_stream_set_buffer_attr -#define pa_stream_get_buffer_attr ppa_stream_get_buffer_attr -#define pa_stream_get_sample_spec ppa_stream_get_sample_spec -#define pa_stream_get_time ppa_stream_get_time -#define pa_stream_set_read_callback ppa_stream_set_read_callback -#define pa_stream_set_state_callback ppa_stream_set_state_callback -#define pa_stream_set_moved_callback ppa_stream_set_moved_callback -#define pa_stream_set_underflow_callback ppa_stream_set_underflow_callback -#define pa_stream_connect_record ppa_stream_connect_record -#define pa_stream_connect_playback ppa_stream_connect_playback -#define pa_stream_readable_size ppa_stream_readable_size -#define pa_stream_writable_size ppa_stream_writable_size -#define pa_stream_is_corked ppa_stream_is_corked -#define pa_stream_cork ppa_stream_cork -#define pa_stream_is_suspended ppa_stream_is_suspended -#define pa_stream_get_device_name ppa_stream_get_device_name -#define pa_stream_get_latency ppa_stream_get_latency -#define pa_stream_set_buffer_attr_callback ppa_stream_set_buffer_attr_callback -#define pa_stream_begin_write ppa_stream_begin_write*/ -#define pa_channel_map_init_auto ppa_channel_map_init_auto -#define pa_channel_map_parse ppa_channel_map_parse -#define pa_channel_map_snprint ppa_channel_map_snprint -#define pa_channel_map_equal ppa_channel_map_equal -#define pa_channel_map_superset ppa_channel_map_superset -#define pa_operation_get_state ppa_operation_get_state -#define pa_operation_unref ppa_operation_unref -#define pa_sample_spec_valid ppa_sample_spec_valid -#define pa_frame_size ppa_frame_size -#define pa_strerror ppa_strerror -#define pa_stream_get_state ppa_stream_get_state -#define pa_stream_peek ppa_stream_peek -#define pa_stream_write ppa_stream_write -#define pa_xfree ppa_xfree -#define pa_path_get_filename ppa_path_get_filename -#define pa_get_binary_name ppa_get_binary_name -#define pa_xmalloc ppa_xmalloc -#endif /* IN_IDE_PARSER */ - -#endif - - -constexpr pa_channel_map MonoChanMap{ - 1, {PA_CHANNEL_POSITION_MONO} -}, StereoChanMap{ - 2, {PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT} -}, QuadChanMap{ - 4, { - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT - } -}, X51ChanMap{ - 6, { - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, - PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT - } -}, X51RearChanMap{ - 6, { - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, - PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT - } -}, X61ChanMap{ - 7, { - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, - PA_CHANNEL_POSITION_REAR_CENTER, - PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT - } -}, X71ChanMap{ - 8, { - PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, - PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, - PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT - } -}; - -size_t ChannelFromPulse(pa_channel_position_t chan) -{ - switch(chan) - { - case PA_CHANNEL_POSITION_INVALID: break; - case PA_CHANNEL_POSITION_MONO: return FrontCenter; - case PA_CHANNEL_POSITION_FRONT_LEFT: return FrontLeft; - case PA_CHANNEL_POSITION_FRONT_RIGHT: return FrontRight; - case PA_CHANNEL_POSITION_FRONT_CENTER: return FrontCenter; - case PA_CHANNEL_POSITION_REAR_CENTER: return BackCenter; - case PA_CHANNEL_POSITION_REAR_LEFT: return BackLeft; - case PA_CHANNEL_POSITION_REAR_RIGHT: return BackRight; - case PA_CHANNEL_POSITION_LFE: return LFE; - case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER: break; - case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER: break; - case PA_CHANNEL_POSITION_SIDE_LEFT: return SideLeft; - case PA_CHANNEL_POSITION_SIDE_RIGHT: return SideRight; - case PA_CHANNEL_POSITION_AUX0: return Aux0; - case PA_CHANNEL_POSITION_AUX1: return Aux1; - case PA_CHANNEL_POSITION_AUX2: return Aux2; - case PA_CHANNEL_POSITION_AUX3: return Aux3; - case PA_CHANNEL_POSITION_AUX4: return Aux4; - case PA_CHANNEL_POSITION_AUX5: return Aux5; - case PA_CHANNEL_POSITION_AUX6: return Aux6; - case PA_CHANNEL_POSITION_AUX7: return Aux7; - case PA_CHANNEL_POSITION_AUX8: return Aux8; - case PA_CHANNEL_POSITION_AUX9: return Aux9; - case PA_CHANNEL_POSITION_AUX10: return Aux10; - case PA_CHANNEL_POSITION_AUX11: return Aux11; - case PA_CHANNEL_POSITION_AUX12: return Aux12; - case PA_CHANNEL_POSITION_AUX13: return Aux13; - case PA_CHANNEL_POSITION_AUX14: return Aux14; - case PA_CHANNEL_POSITION_AUX15: return Aux15; - case PA_CHANNEL_POSITION_AUX16: break; - case PA_CHANNEL_POSITION_AUX17: break; - case PA_CHANNEL_POSITION_AUX18: break; - case PA_CHANNEL_POSITION_AUX19: break; - case PA_CHANNEL_POSITION_AUX20: break; - case PA_CHANNEL_POSITION_AUX21: break; - case PA_CHANNEL_POSITION_AUX22: break; - case PA_CHANNEL_POSITION_AUX23: break; - case PA_CHANNEL_POSITION_AUX24: break; - case PA_CHANNEL_POSITION_AUX25: break; - case PA_CHANNEL_POSITION_AUX26: break; - case PA_CHANNEL_POSITION_AUX27: break; - case PA_CHANNEL_POSITION_AUX28: break; - case PA_CHANNEL_POSITION_AUX29: break; - case PA_CHANNEL_POSITION_AUX30: break; - case PA_CHANNEL_POSITION_AUX31: break; - case PA_CHANNEL_POSITION_TOP_CENTER: break; - case PA_CHANNEL_POSITION_TOP_FRONT_LEFT: return UpperFrontLeft; - case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT: return UpperFrontRight; - case PA_CHANNEL_POSITION_TOP_FRONT_CENTER: break; - case PA_CHANNEL_POSITION_TOP_REAR_LEFT: return UpperBackLeft; - case PA_CHANNEL_POSITION_TOP_REAR_RIGHT: return UpperBackRight; - case PA_CHANNEL_POSITION_TOP_REAR_CENTER: break; - case PA_CHANNEL_POSITION_MAX: break; - } - throw al::backend_exception{ALC_INVALID_VALUE, "Unexpected channel enum %d", chan}; -} - -void SetChannelOrderFromMap(ALCdevice *device, const pa_channel_map &chanmap) -{ - device->RealOut.ChannelIndex.fill(-1); - for(int i{0};i < chanmap.channels;++i) - device->RealOut.ChannelIndex[ChannelFromPulse(chanmap.map[i])] = i; -} - - -/* *grumble* Don't use enums for bitflags. */ -inline pa_stream_flags_t operator|(pa_stream_flags_t lhs, pa_stream_flags_t rhs) -{ return pa_stream_flags_t(int(lhs) | int(rhs)); } -inline pa_stream_flags_t& operator|=(pa_stream_flags_t &lhs, pa_stream_flags_t rhs) -{ - lhs = pa_stream_flags_t(int(lhs) | int(rhs)); - return lhs; -} -inline pa_context_flags_t& operator|=(pa_context_flags_t &lhs, pa_context_flags_t rhs) -{ - lhs = pa_context_flags_t(int(lhs) | int(rhs)); - return lhs; -} - -inline pa_stream_flags_t& operator&=(pa_stream_flags_t &lhs, int rhs) -{ - lhs = pa_stream_flags_t(int(lhs) & rhs); - return lhs; -} - - -/* Global flags and properties */ -pa_context_flags_t pulse_ctx_flags; - -pa_mainloop *pulse_mainloop{nullptr}; - -std::mutex pulse_lock; -std::condition_variable pulse_condvar; - -int pulse_poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) -{ - auto plock = static_cast*>(userdata); - plock->unlock(); - int r{poll(ufds, nfds, timeout)}; - plock->lock(); - return r; -} - -int pulse_mainloop_thread() -{ - SetRTPriority(); - - std::unique_lock plock{pulse_lock}; - pulse_mainloop = pa_mainloop_new(); - - pa_mainloop_set_poll_func(pulse_mainloop, pulse_poll_func, &plock); - pulse_condvar.notify_all(); - - int ret{}; - pa_mainloop_run(pulse_mainloop, &ret); - - pa_mainloop_free(pulse_mainloop); - pulse_mainloop = nullptr; - - return ret; -} - - -/* PulseAudio Event Callbacks */ -void context_state_callback(pa_context *context, void* /*pdata*/) -{ - pa_context_state_t state{pa_context_get_state(context)}; - if(state == PA_CONTEXT_READY || !PA_CONTEXT_IS_GOOD(state)) - pulse_condvar.notify_all(); -} - -void stream_state_callback(pa_stream *stream, void* /*pdata*/) -{ - pa_stream_state_t state{pa_stream_get_state(stream)}; - if(state == PA_STREAM_READY || !PA_STREAM_IS_GOOD(state)) - pulse_condvar.notify_all(); -} - -void stream_success_callback(pa_stream* /*stream*/, int /*success*/, void* /*pdata*/) -{ - pulse_condvar.notify_all(); -} - -void wait_for_operation(pa_operation *op, std::unique_lock &plock) -{ - if(op) - { - while(pa_operation_get_state(op) == PA_OPERATION_RUNNING) - pulse_condvar.wait(plock); - pa_operation_unref(op); - } -} - - -pa_context *connect_context(std::unique_lock &plock) -{ - const char *name{"OpenAL Soft"}; - - const PathNamePair &binname = GetProcBinary(); - if(!binname.fname.empty()) - name = binname.fname.c_str(); - - if(UNLIKELY(!pulse_mainloop)) - { - std::thread{pulse_mainloop_thread}.detach(); - while(!pulse_mainloop) - pulse_condvar.wait(plock); - } - - pa_context *context{pa_context_new(pa_mainloop_get_api(pulse_mainloop), name)}; - if(!context) throw al::backend_exception{ALC_OUT_OF_MEMORY, "pa_context_new() failed"}; - - pa_context_set_state_callback(context, context_state_callback, nullptr); - - int err; - if((err=pa_context_connect(context, nullptr, pulse_ctx_flags, nullptr)) >= 0) - { - pa_context_state_t state; - while((state=pa_context_get_state(context)) != PA_CONTEXT_READY) - { - if(!PA_CONTEXT_IS_GOOD(state)) - { - err = pa_context_errno(context); - if(err > 0) err = -err; - break; - } - - pulse_condvar.wait(plock); - } - } - pa_context_set_state_callback(context, nullptr, nullptr); - - if(err < 0) - { - pa_context_unref(context); - throw al::backend_exception{ALC_INVALID_VALUE, "Context did not connect (%s)", - pa_strerror(err)}; - } - - return context; -} - - -void pulse_close(pa_context *context, pa_stream *stream) -{ - std::lock_guard _{pulse_lock}; - if(stream) - { - pa_stream_set_state_callback(stream, nullptr, nullptr); - pa_stream_set_moved_callback(stream, nullptr, nullptr); - pa_stream_set_write_callback(stream, nullptr, nullptr); - pa_stream_set_buffer_attr_callback(stream, nullptr, nullptr); - pa_stream_disconnect(stream); - pa_stream_unref(stream); - } - - pa_context_disconnect(context); - pa_context_unref(context); -} - - -struct DevMap { - std::string name; - std::string device_name; -}; - -bool checkName(const al::vector &list, const std::string &name) -{ - return std::find_if(list.cbegin(), list.cend(), - [&name](const DevMap &entry) -> bool - { return entry.name == name; } - ) != list.cend(); -} - -al::vector PlaybackDevices; -al::vector CaptureDevices; - - -pa_stream *pulse_connect_stream(const char *device_name, std::unique_lock &plock, - pa_context *context, pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, - pa_channel_map *chanmap, BackendType type) -{ - const char *stream_id{(type==BackendType::Playback) ? "Playback Stream" : "Capture Stream"}; - pa_stream *stream{pa_stream_new(context, stream_id, spec, chanmap)}; - if(!stream) - throw al::backend_exception{ALC_OUT_OF_MEMORY, "pa_stream_new() failed (%s)", - pa_strerror(pa_context_errno(context))}; - - pa_stream_set_state_callback(stream, stream_state_callback, nullptr); - - int err{(type==BackendType::Playback) ? - pa_stream_connect_playback(stream, device_name, attr, flags, nullptr, nullptr) : - pa_stream_connect_record(stream, device_name, attr, flags)}; - if(err < 0) - { - pa_stream_unref(stream); - throw al::backend_exception{ALC_INVALID_VALUE, "%s did not connect (%s)", stream_id, - pa_strerror(err)}; - } - - pa_stream_state_t state; - while((state=pa_stream_get_state(stream)) != PA_STREAM_READY) - { - if(!PA_STREAM_IS_GOOD(state)) - { - int err{pa_context_errno(context)}; - pa_stream_unref(stream); - throw al::backend_exception{ALC_INVALID_VALUE, "%s did not get ready (%s)", stream_id, - pa_strerror(err)}; - } - - pulse_condvar.wait(plock); - } - pa_stream_set_state_callback(stream, nullptr, nullptr); - - return stream; -} - - -void device_sink_callback(pa_context*, const pa_sink_info *info, int eol, void*) -{ - if(eol) - { - pulse_condvar.notify_all(); - return; - } - - /* Skip this device is if it's already in the list. */ - if(std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), - [info](const DevMap &entry) -> bool - { return entry.device_name == info->name; } - ) != PlaybackDevices.cend()) - return; - - /* Make sure the display name (description) is unique. Append a number - * counter as needed. - */ - int count{1}; - std::string newname{info->description}; - while(checkName(PlaybackDevices, newname)) - { - newname = info->description; - newname += " #"; - newname += std::to_string(++count); - } - PlaybackDevices.emplace_back(DevMap{std::move(newname), info->name}); - DevMap &newentry = PlaybackDevices.back(); - - TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str()); -} - -void probePlaybackDevices() -{ - PlaybackDevices.clear(); - - try { - std::unique_lock plock{pulse_lock}; - - pa_context *context{connect_context(plock)}; - - const pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | - PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE}; - - pa_sample_spec spec{}; - spec.format = PA_SAMPLE_S16NE; - spec.rate = 44100; - spec.channels = 2; - - pa_stream *stream{pulse_connect_stream(nullptr, plock, context, flags, nullptr, &spec, - nullptr, BackendType::Playback)}; - pa_operation *op{pa_context_get_sink_info_by_name(context, - pa_stream_get_device_name(stream), device_sink_callback, nullptr)}; - wait_for_operation(op, plock); - - pa_stream_disconnect(stream); - pa_stream_unref(stream); - stream = nullptr; - - op = pa_context_get_sink_info_list(context, device_sink_callback, nullptr); - wait_for_operation(op, plock); - - pa_context_disconnect(context); - pa_context_unref(context); - } - catch(std::exception &e) { - ERR("Error enumerating devices: %s\n", e.what()); - } -} - - -void device_source_callback(pa_context*, const pa_source_info *info, int eol, void*) -{ - if(eol) - { - pulse_condvar.notify_all(); - return; - } - - /* Skip this device is if it's already in the list. */ - if(std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), - [info](const DevMap &entry) -> bool - { return entry.device_name == info->name; } - ) != CaptureDevices.cend()) - return; - - /* Make sure the display name (description) is unique. Append a number - * counter as needed. - */ - int count{1}; - std::string newname{info->description}; - while(checkName(CaptureDevices, newname)) - { - newname = info->description; - newname += " #"; - newname += std::to_string(++count); - } - CaptureDevices.emplace_back(DevMap{std::move(newname), info->name}); - DevMap &newentry = CaptureDevices.back(); - - TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str()); -} - -void probeCaptureDevices() -{ - CaptureDevices.clear(); - - try { - std::unique_lock plock{pulse_lock}; - - pa_context *context{connect_context(plock)}; - - const pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | - PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE}; - - pa_sample_spec spec{}; - spec.format = PA_SAMPLE_S16NE; - spec.rate = 44100; - spec.channels = 1; - - pa_stream *stream{pulse_connect_stream(nullptr, plock, context, flags, nullptr, &spec, nullptr, - BackendType::Capture)}; - pa_operation *op{pa_context_get_source_info_by_name(context, - pa_stream_get_device_name(stream), device_source_callback, nullptr)}; - wait_for_operation(op, plock); - - pa_stream_disconnect(stream); - pa_stream_unref(stream); - stream = nullptr; - - op = pa_context_get_source_info_list(context, device_source_callback, nullptr); - wait_for_operation(op, plock); - - pa_context_disconnect(context); - pa_context_unref(context); - } - catch(std::exception &e) { - ERR("Error enumerating devices: %s\n", e.what()); - } -} - - -struct PulsePlayback final : public BackendBase { - PulsePlayback(ALCdevice *device) noexcept : BackendBase{device} { } - ~PulsePlayback() override; - - static void bufferAttrCallbackC(pa_stream *stream, void *pdata); - void bufferAttrCallback(pa_stream *stream); - - static void contextStateCallbackC(pa_context *context, void *pdata); - void contextStateCallback(pa_context *context); - - static void streamStateCallbackC(pa_stream *stream, void *pdata); - void streamStateCallback(pa_stream *stream); - - static void streamWriteCallbackC(pa_stream *stream, size_t nbytes, void *pdata); - void streamWriteCallback(pa_stream *stream, size_t nbytes); - - static void sinkInfoCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata); - void sinkInfoCallback(pa_context *context, const pa_sink_info *info, int eol); - - static void sinkNameCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata); - void sinkNameCallback(pa_context *context, const pa_sink_info *info, int eol); - - static void streamMovedCallbackC(pa_stream *stream, void *pdata); - void streamMovedCallback(pa_stream *stream); - - ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; - void stop() override; - ClockLatency getClockLatency() override; - void lock() override; - void unlock() override; - - std::string mDeviceName; - - pa_buffer_attr mAttr; - pa_sample_spec mSpec; - - pa_stream *mStream{nullptr}; - pa_context *mContext{nullptr}; - - ALuint mFrameSize{0u}; - - DEF_NEWDEL(PulsePlayback) -}; - -PulsePlayback::~PulsePlayback() -{ - if(!mContext) - return; - - pulse_close(mContext, mStream); - mContext = nullptr; - mStream = nullptr; -} - - -void PulsePlayback::bufferAttrCallbackC(pa_stream *stream, void *pdata) -{ static_cast(pdata)->bufferAttrCallback(stream); } - -void PulsePlayback::bufferAttrCallback(pa_stream *stream) -{ - /* FIXME: Update the device's UpdateSize (and/or BufferSize) using the new - * buffer attributes? Changing UpdateSize will change the ALC_REFRESH - * property, which probably shouldn't change between device resets. But - * leaving it alone means ALC_REFRESH will be off. - */ - mAttr = *(pa_stream_get_buffer_attr(stream)); - TRACE("minreq=%d, tlength=%d, prebuf=%d\n", mAttr.minreq, mAttr.tlength, mAttr.prebuf); -} - -void PulsePlayback::contextStateCallbackC(pa_context *context, void *pdata) -{ static_cast(pdata)->contextStateCallback(context); } - -void PulsePlayback::contextStateCallback(pa_context *context) -{ - if(pa_context_get_state(context) == PA_CONTEXT_FAILED) - { - ERR("Received context failure!\n"); - aluHandleDisconnect(mDevice, "Playback state failure"); - } - pulse_condvar.notify_all(); -} - -void PulsePlayback::streamStateCallbackC(pa_stream *stream, void *pdata) -{ static_cast(pdata)->streamStateCallback(stream); } - -void PulsePlayback::streamStateCallback(pa_stream *stream) -{ - if(pa_stream_get_state(stream) == PA_STREAM_FAILED) - { - ERR("Received stream failure!\n"); - aluHandleDisconnect(mDevice, "Playback stream failure"); - } - pulse_condvar.notify_all(); -} - -void PulsePlayback::streamWriteCallbackC(pa_stream *stream, size_t nbytes, void *pdata) -{ static_cast(pdata)->streamWriteCallback(stream, nbytes); } - -void PulsePlayback::streamWriteCallback(pa_stream *stream, size_t nbytes) -{ - void *buf{pa_xmalloc(nbytes)}; - aluMixData(mDevice, buf, nbytes/mFrameSize); - - int ret{pa_stream_write(stream, buf, nbytes, pa_xfree, 0, PA_SEEK_RELATIVE)}; - if(UNLIKELY(ret != PA_OK)) - ERR("Failed to write to stream: %d, %s\n", ret, pa_strerror(ret)); -} - -void PulsePlayback::sinkInfoCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata) -{ static_cast(pdata)->sinkInfoCallback(context, info, eol); } - -void PulsePlayback::sinkInfoCallback(pa_context*, const pa_sink_info *info, int eol) -{ - struct ChannelMap { - DevFmtChannels chans; - pa_channel_map map; - }; - static constexpr std::array chanmaps{{ - { DevFmtX71, X71ChanMap }, - { DevFmtX61, X61ChanMap }, - { DevFmtX51, X51ChanMap }, - { DevFmtX51Rear, X51RearChanMap }, - { DevFmtQuad, QuadChanMap }, - { DevFmtStereo, StereoChanMap }, - { DevFmtMono, MonoChanMap } - }}; - - if(eol) - { - pulse_condvar.notify_all(); - return; - } - - auto chanmap = std::find_if(chanmaps.cbegin(), chanmaps.cend(), - [info](const ChannelMap &chanmap) -> bool - { return pa_channel_map_superset(&info->channel_map, &chanmap.map); } - ); - if(chanmap != chanmaps.cend()) - { - if(!mDevice->Flags.get()) - mDevice->FmtChans = chanmap->chans; - } - else - { - char chanmap_str[PA_CHANNEL_MAP_SNPRINT_MAX]{}; - pa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map); - WARN("Failed to find format for channel map:\n %s\n", chanmap_str); - } - - if(info->active_port) - TRACE("Active port: %s (%s)\n", info->active_port->name, info->active_port->description); - mDevice->IsHeadphones = (mDevice->FmtChans == DevFmtStereo && - info->active_port && strcmp(info->active_port->name, "analog-output-headphones") == 0); -} - -void PulsePlayback::sinkNameCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata) -{ static_cast(pdata)->sinkNameCallback(context, info, eol); } - -void PulsePlayback::sinkNameCallback(pa_context*, const pa_sink_info *info, int eol) -{ - if(eol) - { - pulse_condvar.notify_all(); - return; - } - mDevice->DeviceName = info->description; -} - -void PulsePlayback::streamMovedCallbackC(pa_stream *stream, void *pdata) -{ static_cast(pdata)->streamMovedCallback(stream); } - -void PulsePlayback::streamMovedCallback(pa_stream *stream) -{ - mDeviceName = pa_stream_get_device_name(stream); - TRACE("Stream moved to %s\n", mDeviceName.c_str()); -} - - -ALCenum PulsePlayback::open(const ALCchar *name) -{ - const char *pulse_name{nullptr}; - const char *dev_name{nullptr}; - - if(name) - { - if(PlaybackDevices.empty()) - probePlaybackDevices(); - - auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), - [name](const DevMap &entry) -> bool - { return entry.name == name; } - ); - if(iter == PlaybackDevices.cend()) - throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; - pulse_name = iter->device_name.c_str(); - dev_name = iter->name.c_str(); - } - - std::unique_lock plock{pulse_lock}; - - mContext = connect_context(plock); - pa_context_set_state_callback(mContext, &PulsePlayback::contextStateCallbackC, this); - - pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS}; - if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 1)) - flags |= PA_STREAM_DONT_MOVE; - - pa_sample_spec spec{}; - spec.format = PA_SAMPLE_S16NE; - spec.rate = 44100; - spec.channels = 2; - - if(!pulse_name) - { - pulse_name = getenv("ALSOFT_PULSE_DEFAULT"); - if(pulse_name && !pulse_name[0]) pulse_name = nullptr; - } - TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); - mStream = pulse_connect_stream(pulse_name, plock, mContext, flags, nullptr, &spec, nullptr, - BackendType::Playback); - - pa_stream_set_moved_callback(mStream, &PulsePlayback::streamMovedCallbackC, this); - mFrameSize = pa_frame_size(pa_stream_get_sample_spec(mStream)); - - mDeviceName = pa_stream_get_device_name(mStream); - if(!dev_name) - { - pa_operation *op{pa_context_get_sink_info_by_name(mContext, mDeviceName.c_str(), - &PulsePlayback::sinkNameCallbackC, this)}; - wait_for_operation(op, plock); - } - else - mDevice->DeviceName = dev_name; - - return ALC_NO_ERROR; -} - -ALCboolean PulsePlayback::reset() -{ - std::unique_lock plock{pulse_lock}; - - if(mStream) - { - pa_stream_set_state_callback(mStream, nullptr, nullptr); - pa_stream_set_moved_callback(mStream, nullptr, nullptr); - pa_stream_set_write_callback(mStream, nullptr, nullptr); - pa_stream_set_buffer_attr_callback(mStream, nullptr, nullptr); - pa_stream_disconnect(mStream); - pa_stream_unref(mStream); - mStream = nullptr; - } - - pa_operation *op{pa_context_get_sink_info_by_name(mContext, mDeviceName.c_str(), - &PulsePlayback::sinkInfoCallbackC, this)}; - wait_for_operation(op, plock); - - pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | - PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_EARLY_REQUESTS}; - if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 1)) - flags |= PA_STREAM_DONT_MOVE; - if(GetConfigValueBool(mDevice->DeviceName.c_str(), "pulse", "adjust-latency", 0)) - { - /* ADJUST_LATENCY can't be specified with EARLY_REQUESTS, for some - * reason. So if the user wants to adjust the overall device latency, - * we can't ask to get write signals as soon as minreq is reached. - */ - flags &= ~PA_STREAM_EARLY_REQUESTS; - flags |= PA_STREAM_ADJUST_LATENCY; - } - if(GetConfigValueBool(mDevice->DeviceName.c_str(), "pulse", "fix-rate", 0) || - !mDevice->Flags.get()) - flags |= PA_STREAM_FIX_RATE; - - pa_channel_map chanmap{}; - switch(mDevice->FmtChans) - { - case DevFmtMono: - chanmap = MonoChanMap; - break; - case DevFmtAmbi3D: - mDevice->FmtChans = DevFmtStereo; - /*fall-through*/ - case DevFmtStereo: - chanmap = StereoChanMap; - break; - case DevFmtQuad: - chanmap = QuadChanMap; - break; - case DevFmtX51: - chanmap = X51ChanMap; - break; - case DevFmtX51Rear: - chanmap = X51RearChanMap; - break; - case DevFmtX61: - chanmap = X61ChanMap; - break; - case DevFmtX71: - chanmap = X71ChanMap; - break; - } - SetChannelOrderFromMap(mDevice, chanmap); - - switch(mDevice->FmtType) - { - case DevFmtByte: - mDevice->FmtType = DevFmtUByte; - /* fall-through */ - case DevFmtUByte: - mSpec.format = PA_SAMPLE_U8; - break; - case DevFmtUShort: - mDevice->FmtType = DevFmtShort; - /* fall-through */ - case DevFmtShort: - mSpec.format = PA_SAMPLE_S16NE; - break; - case DevFmtUInt: - mDevice->FmtType = DevFmtInt; - /* fall-through */ - case DevFmtInt: - mSpec.format = PA_SAMPLE_S32NE; - break; - case DevFmtFloat: - mSpec.format = PA_SAMPLE_FLOAT32NE; - break; - } - mSpec.rate = mDevice->Frequency; - mSpec.channels = mDevice->channelsFromFmt(); - if(pa_sample_spec_valid(&mSpec) == 0) - throw al::backend_exception{ALC_INVALID_VALUE, "Invalid sample spec"}; - - mAttr.maxlength = -1; - mAttr.tlength = mDevice->BufferSize * pa_frame_size(&mSpec); - mAttr.prebuf = 0; - mAttr.minreq = mDevice->UpdateSize * pa_frame_size(&mSpec); - mAttr.fragsize = -1; - - mStream = pulse_connect_stream(mDeviceName.c_str(), plock, mContext, flags, &mAttr, &mSpec, - &chanmap, BackendType::Playback); - - pa_stream_set_state_callback(mStream, &PulsePlayback::streamStateCallbackC, this); - pa_stream_set_moved_callback(mStream, &PulsePlayback::streamMovedCallbackC, this); - - mSpec = *(pa_stream_get_sample_spec(mStream)); - mFrameSize = pa_frame_size(&mSpec); - - if(mDevice->Frequency != mSpec.rate) - { - /* Server updated our playback rate, so modify the buffer attribs - * accordingly. - */ - const auto scale = static_cast(mSpec.rate) / mDevice->Frequency; - const ALuint perlen{static_cast(clampd(scale*mDevice->UpdateSize + 0.5, 64.0, - 8192.0))}; - const ALuint buflen{static_cast(clampd(scale*mDevice->BufferSize + 0.5, perlen*2, - std::numeric_limits::max()/mFrameSize))}; - - mAttr.maxlength = -1; - mAttr.tlength = buflen * mFrameSize; - mAttr.prebuf = 0; - mAttr.minreq = perlen * mFrameSize; - - op = pa_stream_set_buffer_attr(mStream, &mAttr, stream_success_callback, nullptr); - wait_for_operation(op, plock); - - mDevice->Frequency = mSpec.rate; - } - - pa_stream_set_buffer_attr_callback(mStream, &PulsePlayback::bufferAttrCallbackC, this); - bufferAttrCallback(mStream); - - mDevice->BufferSize = mAttr.tlength / mFrameSize; - mDevice->UpdateSize = mAttr.minreq / mFrameSize; - - /* HACK: prebuf should be 0 as that's what we set it to. However on some - * systems it comes back as non-0, so we have to make sure the device will - * write enough audio to start playback. The lack of manual start control - * may have unintended consequences, but it's better than not starting at - * all. - */ - if(mAttr.prebuf != 0) - { - ALuint len{mAttr.prebuf / mFrameSize}; - if(len <= mDevice->BufferSize) - ERR("Non-0 prebuf, %u samples (%u bytes), device has %u samples\n", - len, mAttr.prebuf, mDevice->BufferSize); - } - - return ALC_TRUE; -} - -ALCboolean PulsePlayback::start() -{ - std::unique_lock plock{pulse_lock}; - - pa_stream_set_write_callback(mStream, &PulsePlayback::streamWriteCallbackC, this); - pa_operation *op{pa_stream_cork(mStream, 0, stream_success_callback, nullptr)}; - wait_for_operation(op, plock); - - return ALC_TRUE; -} - -void PulsePlayback::stop() -{ - std::unique_lock plock{pulse_lock}; - - pa_stream_set_write_callback(mStream, nullptr, nullptr); - pa_operation *op{pa_stream_cork(mStream, 1, stream_success_callback, nullptr)}; - wait_for_operation(op, plock); -} - - -ClockLatency PulsePlayback::getClockLatency() -{ - ClockLatency ret; - pa_usec_t latency; - int neg, err; - - { std::lock_guard _{pulse_lock}; - ret.ClockTime = GetDeviceClockTime(mDevice); - err = pa_stream_get_latency(mStream, &latency, &neg); - } - - if(UNLIKELY(err != 0)) - { - /* 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); - latency = 0; - neg = 0; - } - else if(UNLIKELY(neg)) - latency = 0; - ret.Latency = std::chrono::microseconds{latency}; - - return ret; -} - - -void PulsePlayback::lock() -{ pulse_lock.lock(); } - -void PulsePlayback::unlock() -{ pulse_lock.unlock(); } - - -struct PulseCapture final : public BackendBase { - PulseCapture(ALCdevice *device) noexcept : BackendBase{device} { } - ~PulseCapture() override; - - static void contextStateCallbackC(pa_context *context, void *pdata); - void contextStateCallback(pa_context *context); - - static void streamStateCallbackC(pa_stream *stream, void *pdata); - void streamStateCallback(pa_stream *stream); - - static void sourceNameCallbackC(pa_context *context, const pa_source_info *info, int eol, void *pdata); - void sourceNameCallback(pa_context *context, const pa_source_info *info, int eol); - - static void streamMovedCallbackC(pa_stream *stream, void *pdata); - void streamMovedCallback(pa_stream *stream); - - ALCenum open(const ALCchar *name) override; - ALCboolean start() override; - void stop() override; - ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override; - ALCuint availableSamples() override; - ClockLatency getClockLatency() override; - void lock() override; - void unlock() override; - - std::string mDeviceName; - - ALCuint mLastReadable{0u}; - al::byte mSilentVal{}; - - al::span mCapBuffer; - ssize_t mCapLen{0}; - - pa_buffer_attr mAttr{}; - pa_sample_spec mSpec{}; - - pa_stream *mStream{nullptr}; - pa_context *mContext{nullptr}; - - DEF_NEWDEL(PulseCapture) -}; - -PulseCapture::~PulseCapture() -{ - if(!mContext) - return; - - pulse_close(mContext, mStream); - mContext = nullptr; - mStream = nullptr; -} - -void PulseCapture::contextStateCallbackC(pa_context *context, void *pdata) -{ static_cast(pdata)->contextStateCallback(context); } - -void PulseCapture::contextStateCallback(pa_context *context) -{ - if(pa_context_get_state(context) == PA_CONTEXT_FAILED) - { - ERR("Received context failure!\n"); - aluHandleDisconnect(mDevice, "Capture state failure"); - } - pulse_condvar.notify_all(); -} - -void PulseCapture::streamStateCallbackC(pa_stream *stream, void *pdata) -{ static_cast(pdata)->streamStateCallback(stream); } - -void PulseCapture::streamStateCallback(pa_stream *stream) -{ - if(pa_stream_get_state(stream) == PA_STREAM_FAILED) - { - ERR("Received stream failure!\n"); - aluHandleDisconnect(mDevice, "Capture stream failure"); - } - pulse_condvar.notify_all(); -} - -void PulseCapture::sourceNameCallbackC(pa_context *context, const pa_source_info *info, int eol, void *pdata) -{ static_cast(pdata)->sourceNameCallback(context, info, eol); } - -void PulseCapture::sourceNameCallback(pa_context*, const pa_source_info *info, int eol) -{ - if(eol) - { - pulse_condvar.notify_all(); - return; - } - mDevice->DeviceName = info->description; -} - -void PulseCapture::streamMovedCallbackC(pa_stream *stream, void *pdata) -{ static_cast(pdata)->streamMovedCallback(stream); } - -void PulseCapture::streamMovedCallback(pa_stream *stream) -{ - mDeviceName = pa_stream_get_device_name(stream); - TRACE("Stream moved to %s\n", mDeviceName.c_str()); -} - - -ALCenum PulseCapture::open(const ALCchar *name) -{ - const char *pulse_name{nullptr}; - if(name) - { - if(CaptureDevices.empty()) - probeCaptureDevices(); - - auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), - [name](const DevMap &entry) -> bool - { return entry.name == name; } - ); - if(iter == CaptureDevices.cend()) - throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; - pulse_name = iter->device_name.c_str(); - mDevice->DeviceName = iter->name; - } - - std::unique_lock plock{pulse_lock}; - - mContext = connect_context(plock); - pa_context_set_state_callback(mContext, &PulseCapture::contextStateCallbackC, this); - - pa_channel_map chanmap{}; - switch(mDevice->FmtChans) - { - case DevFmtMono: - chanmap = MonoChanMap; - break; - case DevFmtStereo: - chanmap = StereoChanMap; - break; - case DevFmtQuad: - chanmap = QuadChanMap; - break; - case DevFmtX51: - chanmap = X51ChanMap; - break; - case DevFmtX51Rear: - chanmap = X51RearChanMap; - break; - case DevFmtX61: - chanmap = X61ChanMap; - break; - case DevFmtX71: - chanmap = X71ChanMap; - break; - case DevFmtAmbi3D: - throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", - DevFmtChannelsString(mDevice->FmtChans)}; - } - SetChannelOrderFromMap(mDevice, chanmap); - - switch(mDevice->FmtType) - { - case DevFmtUByte: - mSilentVal = al::byte(0x80); - mSpec.format = PA_SAMPLE_U8; - break; - case DevFmtShort: - mSpec.format = PA_SAMPLE_S16NE; - break; - case DevFmtInt: - mSpec.format = PA_SAMPLE_S32NE; - break; - case DevFmtFloat: - mSpec.format = PA_SAMPLE_FLOAT32NE; - break; - case DevFmtByte: - case DevFmtUShort: - case DevFmtUInt: - throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", - DevFmtTypeString(mDevice->FmtType)}; - } - mSpec.rate = mDevice->Frequency; - mSpec.channels = mDevice->channelsFromFmt(); - if(pa_sample_spec_valid(&mSpec) == 0) - throw al::backend_exception{ALC_INVALID_VALUE, "Invalid sample format"}; - - ALuint samples{mDevice->BufferSize}; - samples = maxu(samples, 100 * mDevice->Frequency / 1000); - - mAttr.minreq = -1; - mAttr.prebuf = -1; - mAttr.maxlength = samples * pa_frame_size(&mSpec); - mAttr.tlength = -1; - mAttr.fragsize = minu(samples, 50*mDevice->Frequency/1000) * pa_frame_size(&mSpec); - - pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_ADJUST_LATENCY}; - if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 1)) - flags |= PA_STREAM_DONT_MOVE; - - TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); - mStream = pulse_connect_stream(pulse_name, plock, mContext, flags, &mAttr, &mSpec, &chanmap, - BackendType::Capture); - - pa_stream_set_moved_callback(mStream, &PulseCapture::streamMovedCallbackC, this); - pa_stream_set_state_callback(mStream, &PulseCapture::streamStateCallbackC, this); - - mDeviceName = pa_stream_get_device_name(mStream); - if(mDevice->DeviceName.empty()) - { - pa_operation *op{pa_context_get_source_info_by_name(mContext, mDeviceName.c_str(), - &PulseCapture::sourceNameCallbackC, this)}; - wait_for_operation(op, plock); - } - - return ALC_NO_ERROR; -} - -ALCboolean PulseCapture::start() -{ - std::unique_lock plock{pulse_lock}; - pa_operation *op{pa_stream_cork(mStream, 0, stream_success_callback, nullptr)}; - wait_for_operation(op, plock); - return ALC_TRUE; -} - -void PulseCapture::stop() -{ - std::unique_lock plock{pulse_lock}; - pa_operation *op{pa_stream_cork(mStream, 1, stream_success_callback, nullptr)}; - wait_for_operation(op, plock); -} - -ALCenum PulseCapture::captureSamples(ALCvoid *buffer, ALCuint samples) -{ - al::span dstbuf{static_cast(buffer), samples * pa_frame_size(&mSpec)}; - - /* Capture is done in fragment-sized chunks, so we loop until we get all - * that's available */ - mLastReadable -= dstbuf.size(); - std::lock_guard _{pulse_lock}; - while(!dstbuf.empty()) - { - if(mCapBuffer.empty()) - { - if(UNLIKELY(!mDevice->Connected.load(std::memory_order_acquire))) - break; - const pa_stream_state_t state{pa_stream_get_state(mStream)}; - if(UNLIKELY(!PA_STREAM_IS_GOOD(state))) - { - aluHandleDisconnect(mDevice, "Bad capture state: %u", state); - break; - } - const void *capbuf; - size_t caplen; - if(UNLIKELY(pa_stream_peek(mStream, &capbuf, &caplen) < 0)) - { - aluHandleDisconnect(mDevice, "Failed retrieving capture samples: %s", - pa_strerror(pa_context_errno(mContext))); - break; - } - if(caplen == 0) break; - if(UNLIKELY(!capbuf)) - mCapLen = -static_cast(caplen); - else - mCapLen = static_cast(caplen); - mCapBuffer = {static_cast(capbuf), caplen}; - } - - const size_t rem{minz(dstbuf.size(), mCapBuffer.size())}; - if(UNLIKELY(mCapLen < 0)) - std::fill_n(dstbuf.begin(), rem, mSilentVal); - else - std::copy_n(mCapBuffer.begin(), rem, dstbuf.begin()); - dstbuf = dstbuf.subspan(rem); - mCapBuffer = mCapBuffer.subspan(rem); - - if(mCapBuffer.empty()) - { - pa_stream_drop(mStream); - mCapLen = 0; - } - } - if(!dstbuf.empty()) - std::fill(dstbuf.begin(), dstbuf.end(), mSilentVal); - - return ALC_NO_ERROR; -} - -ALCuint PulseCapture::availableSamples() -{ - size_t readable{mCapBuffer.size()}; - - if(mDevice->Connected.load(std::memory_order_acquire)) - { - std::lock_guard _{pulse_lock}; - size_t got{pa_stream_readable_size(mStream)}; - if(static_cast(got) < 0) - { - ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got)); - aluHandleDisconnect(mDevice, "Failed getting readable size: %s", pa_strerror(got)); - } - else - { - const auto caplen = static_cast(std::abs(mCapLen)); - if(got > caplen) readable += got - caplen; - } - } - - readable = std::min(readable, std::numeric_limits::max()); - mLastReadable = std::max(mLastReadable, static_cast(readable)); - return mLastReadable / pa_frame_size(&mSpec); -} - - -ClockLatency PulseCapture::getClockLatency() -{ - ClockLatency ret; - pa_usec_t latency; - int neg, err; - - { std::lock_guard _{pulse_lock}; - ret.ClockTime = GetDeviceClockTime(mDevice); - err = pa_stream_get_latency(mStream, &latency, &neg); - } - - if(UNLIKELY(err != 0)) - { - ERR("Failed to get stream latency: 0x%x\n", err); - latency = 0; - neg = 0; - } - else if(UNLIKELY(neg)) - latency = 0; - ret.Latency = std::chrono::microseconds{latency}; - - return ret; -} - - -void PulseCapture::lock() -{ pulse_lock.lock(); } - -void PulseCapture::unlock() -{ pulse_lock.unlock(); } - -} // namespace - - -bool PulseBackendFactory::init() -{ -#ifdef HAVE_DYNLOAD - if(!pulse_handle) - { - bool ret{true}; - std::string missing_funcs; - -#ifdef _WIN32 -#define PALIB "libpulse-0.dll" -#elif defined(__APPLE__) && defined(__MACH__) -#define PALIB "libpulse.0.dylib" -#else -#define PALIB "libpulse.so.0" -#endif - pulse_handle = LoadLib(PALIB); - if(!pulse_handle) - { - WARN("Failed to load %s\n", PALIB); - return false; - } - -#define LOAD_FUNC(x) do { \ - p##x = reinterpret_cast(GetSymbol(pulse_handle, #x)); \ - if(!(p##x)) { \ - ret = false; \ - missing_funcs += "\n" #x; \ - } \ -} while(0) - PULSE_FUNCS(LOAD_FUNC) -#undef LOAD_FUNC - - if(!ret) - { - WARN("Missing expected functions:%s\n", missing_funcs.c_str()); - CloseLib(pulse_handle); - pulse_handle = nullptr; - return false; - } - } -#endif /* HAVE_DYNLOAD */ - - pulse_ctx_flags = PA_CONTEXT_NOFLAGS; - if(!GetConfigValueBool(nullptr, "pulse", "spawn-server", 1)) - pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN; - - try { - std::unique_lock plock{pulse_lock}; - pa_context *context{connect_context(plock)}; - pa_context_disconnect(context); - pa_context_unref(context); - return true; - } - catch(...) { - return false; - } -} - -bool PulseBackendFactory::querySupport(BackendType type) -{ return type == BackendType::Playback || type == BackendType::Capture; } - -void PulseBackendFactory::probe(DevProbe type, std::string *outnames) -{ - auto add_device = [outnames](const DevMap &entry) -> void - { - /* +1 to also append the null char (to ensure a null-separated list and - * double-null terminated list). - */ - outnames->append(entry.name.c_str(), entry.name.length()+1); - }; - switch(type) - { - case DevProbe::Playback: - probePlaybackDevices(); - std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); - break; - - case DevProbe::Capture: - probeCaptureDevices(); - std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); - break; - } -} - -BackendPtr PulseBackendFactory::createBackend(ALCdevice *device, BackendType type) -{ - if(type == BackendType::Playback) - return BackendPtr{new PulsePlayback{device}}; - if(type == BackendType::Capture) - return BackendPtr{new PulseCapture{device}}; - return nullptr; -} - -BackendFactory &PulseBackendFactory::getFactory() -{ - static PulseBackendFactory factory{}; - return factory; -} diff --git a/Alc/backends/pulseaudio.h b/Alc/backends/pulseaudio.h deleted file mode 100644 index 40f3e305..00000000 --- a/Alc/backends/pulseaudio.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef BACKENDS_PULSEAUDIO_H -#define BACKENDS_PULSEAUDIO_H - -#include "backends/base.h" - -class PulseBackendFactory final : public BackendFactory { -public: - bool init() override; - - bool querySupport(BackendType type) override; - - void probe(DevProbe type, std::string *outnames) override; - - BackendPtr createBackend(ALCdevice *device, BackendType type) override; - - static BackendFactory &getFactory(); -}; - -#endif /* BACKENDS_PULSEAUDIO_H */ diff --git a/Alc/backends/qsa.cpp b/Alc/backends/qsa.cpp deleted file mode 100644 index 64ed53aa..00000000 --- a/Alc/backends/qsa.cpp +++ /dev/null @@ -1,953 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2011-2013 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "backends/qsa.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "alcmain.h" -#include "alu.h" -#include "threads.h" - -#include -#include - - -namespace { - -struct qsa_data { - snd_pcm_t* pcmHandle{nullptr}; - int audio_fd{-1}; - - snd_pcm_channel_setup_t csetup{}; - snd_pcm_channel_params_t cparams{}; - - ALvoid* buffer{nullptr}; - ALsizei size{0}; - - std::atomic mKillNow{AL_TRUE}; - std::thread mThread; -}; - -struct DevMap { - ALCchar* name; - int card; - int dev; -}; - -al::vector DeviceNameMap; -al::vector CaptureNameMap; - -constexpr ALCchar qsaDevice[] = "QSA Default"; - -constexpr struct { - int32_t format; -} formatlist[] = { - {SND_PCM_SFMT_FLOAT_LE}, - {SND_PCM_SFMT_S32_LE}, - {SND_PCM_SFMT_U32_LE}, - {SND_PCM_SFMT_S16_LE}, - {SND_PCM_SFMT_U16_LE}, - {SND_PCM_SFMT_S8}, - {SND_PCM_SFMT_U8}, - {0}, -}; - -constexpr struct { - int32_t rate; -} ratelist[] = { - {192000}, - {176400}, - {96000}, - {88200}, - {48000}, - {44100}, - {32000}, - {24000}, - {22050}, - {16000}, - {12000}, - {11025}, - {8000}, - {0}, -}; - -constexpr struct { - int32_t channels; -} channellist[] = { - {8}, - {7}, - {6}, - {4}, - {2}, - {1}, - {0}, -}; - -void deviceList(int type, al::vector *devmap) -{ - snd_ctl_t* handle; - snd_pcm_info_t pcminfo; - int max_cards, card, err, dev; - DevMap entry; - char name[1024]; - snd_ctl_hw_info info; - - max_cards = snd_cards(); - if(max_cards < 0) - return; - - std::for_each(devmap->begin(), devmap->end(), - [](const DevMap &entry) -> void - { free(entry.name); } - ); - devmap->clear(); - - entry.name = strdup(qsaDevice); - entry.card = 0; - entry.dev = 0; - devmap->push_back(entry); - - for(card = 0;card < max_cards;card++) - { - if((err=snd_ctl_open(&handle, card)) < 0) - continue; - - if((err=snd_ctl_hw_info(handle, &info)) < 0) - { - snd_ctl_close(handle); - continue; - } - - for(dev = 0;dev < (int)info.pcmdevs;dev++) - { - if((err=snd_ctl_pcm_info(handle, dev, &pcminfo)) < 0) - continue; - - if((type==SND_PCM_CHANNEL_PLAYBACK && (pcminfo.flags&SND_PCM_INFO_PLAYBACK)) || - (type==SND_PCM_CHANNEL_CAPTURE && (pcminfo.flags&SND_PCM_INFO_CAPTURE))) - { - snprintf(name, sizeof(name), "%s [%s] (hw:%d,%d)", info.name, pcminfo.name, card, dev); - entry.name = strdup(name); - entry.card = card; - entry.dev = dev; - - devmap->push_back(entry); - TRACE("Got device \"%s\", card %d, dev %d\n", name, card, dev); - } - } - snd_ctl_close(handle); - } -} - - -/* Wrappers to use an old-style backend with the new interface. */ -struct PlaybackWrapper final : public BackendBase { - PlaybackWrapper(ALCdevice *device) noexcept : BackendBase{device} { } - ~PlaybackWrapper() override; - - ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; - void stop() override; - - std::unique_ptr mExtraData; - - DEF_NEWDEL(PlaybackWrapper) -}; - - -FORCE_ALIGN static int qsa_proc_playback(void *ptr) -{ - PlaybackWrapper *self = static_cast(ptr); - ALCdevice *device = self->mDevice; - qsa_data *data = self->mExtraData.get(); - snd_pcm_channel_status_t status; - sched_param param; - char* write_ptr; - ALint len; - int sret; - - SetRTPriority(); - althrd_setname(MIXER_THREAD_NAME); - - /* Increase default 10 priority to 11 to avoid jerky sound */ - SchedGet(0, 0, ¶m); - param.sched_priority=param.sched_curpriority+1; - SchedSet(0, 0, SCHED_NOCHANGE, ¶m); - - const ALint frame_size = device->frameSizeFromFmt(); - - self->lock(); - while(!data->mKillNow.load(std::memory_order_acquire)) - { - pollfd pollitem{}; - pollitem.fd = data->audio_fd; - pollitem.events = POLLOUT; - - /* Select also works like time slice to OS */ - self->unlock(); - sret = poll(&pollitem, 1, 2000); - self->lock(); - if(sret == -1) - { - if(errno == EINTR || errno == EAGAIN) - continue; - ERR("poll error: %s\n", strerror(errno)); - aluHandleDisconnect(device, "Failed waiting for playback buffer: %s", strerror(errno)); - break; - } - if(sret == 0) - { - ERR("poll timeout\n"); - continue; - } - - len = data->size; - write_ptr = static_cast(data->buffer); - aluMixData(device, write_ptr, len/frame_size); - while(len>0 && !data->mKillNow.load(std::memory_order_acquire)) - { - int wrote = snd_pcm_plugin_write(data->pcmHandle, write_ptr, len); - if(wrote <= 0) - { - if(errno==EAGAIN || errno==EWOULDBLOCK) - continue; - - memset(&status, 0, sizeof(status)); - status.channel = SND_PCM_CHANNEL_PLAYBACK; - - snd_pcm_plugin_status(data->pcmHandle, &status); - - /* we need to reinitialize the sound channel if we've underrun the buffer */ - if(status.status == SND_PCM_STATUS_UNDERRUN || - status.status == SND_PCM_STATUS_READY) - { - if(snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK) < 0) - { - aluHandleDisconnect(device, "Playback recovery failed"); - break; - } - } - } - else - { - write_ptr += wrote; - len -= wrote; - } - } - } - self->unlock(); - - return 0; -} - -/************/ -/* Playback */ -/************/ - -static ALCenum qsa_open_playback(PlaybackWrapper *self, const ALCchar* deviceName) -{ - ALCdevice *device = self->mDevice; - int card, dev; - int status; - - std::unique_ptr data{new qsa_data{}}; - data->mKillNow.store(AL_TRUE, std::memory_order_relaxed); - - if(!deviceName) - deviceName = qsaDevice; - - if(strcmp(deviceName, qsaDevice) == 0) - status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_PLAYBACK); - else - { - if(DeviceNameMap.empty()) - deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap); - - auto iter = std::find_if(DeviceNameMap.begin(), DeviceNameMap.end(), - [deviceName](const DevMap &entry) -> bool - { return entry.name && strcmp(deviceName, entry.name) == 0; } - ); - if(iter == DeviceNameMap.cend()) - return ALC_INVALID_DEVICE; - - status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_PLAYBACK); - } - - if(status < 0) - return ALC_INVALID_DEVICE; - - data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK); - if(data->audio_fd < 0) - { - snd_pcm_close(data->pcmHandle); - return ALC_INVALID_DEVICE; - } - - device->DeviceName = deviceName; - self->mExtraData = std::move(data); - - return ALC_NO_ERROR; -} - -static void qsa_close_playback(PlaybackWrapper *self) -{ - qsa_data *data = self->mExtraData.get(); - - if (data->buffer!=NULL) - { - free(data->buffer); - data->buffer=NULL; - } - - snd_pcm_close(data->pcmHandle); - - self->mExtraData = nullptr; -} - -static ALCboolean qsa_reset_playback(PlaybackWrapper *self) -{ - ALCdevice *device = self->mDevice; - qsa_data *data = self->mExtraData.get(); - int32_t format=-1; - - switch(device->FmtType) - { - case DevFmtByte: - format=SND_PCM_SFMT_S8; - break; - case DevFmtUByte: - format=SND_PCM_SFMT_U8; - break; - case DevFmtShort: - format=SND_PCM_SFMT_S16_LE; - break; - case DevFmtUShort: - format=SND_PCM_SFMT_U16_LE; - break; - case DevFmtInt: - format=SND_PCM_SFMT_S32_LE; - break; - case DevFmtUInt: - format=SND_PCM_SFMT_U32_LE; - break; - case DevFmtFloat: - format=SND_PCM_SFMT_FLOAT_LE; - break; - } - - /* we actually don't want to block on writes */ - snd_pcm_nonblock_mode(data->pcmHandle, 1); - /* Disable mmap to control data transfer to the audio device */ - snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_MMAP); - snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_BUFFER_PARTIAL_BLOCKS); - - // configure a sound channel - memset(&data->cparams, 0, sizeof(data->cparams)); - data->cparams.channel=SND_PCM_CHANNEL_PLAYBACK; - data->cparams.mode=SND_PCM_MODE_BLOCK; - data->cparams.start_mode=SND_PCM_START_FULL; - data->cparams.stop_mode=SND_PCM_STOP_STOP; - - data->cparams.buf.block.frag_size=device->UpdateSize * device->frameSizeFromFmt(); - data->cparams.buf.block.frags_max=device->BufferSize / device->UpdateSize; - data->cparams.buf.block.frags_min=data->cparams.buf.block.frags_max; - - data->cparams.format.interleave=1; - data->cparams.format.rate=device->Frequency; - data->cparams.format.voices=device->channelsFromFmt(); - data->cparams.format.format=format; - - if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0) - { - int original_rate=data->cparams.format.rate; - int original_voices=data->cparams.format.voices; - int original_format=data->cparams.format.format; - int it; - int jt; - - for (it=0; it<1; it++) - { - /* Check for second pass */ - if (it==1) - { - original_rate=ratelist[0].rate; - original_voices=channellist[0].channels; - original_format=formatlist[0].format; - } - - do { - /* At first downgrade sample format */ - jt=0; - do { - if (formatlist[jt].format==data->cparams.format.format) - { - data->cparams.format.format=formatlist[jt+1].format; - break; - } - if (formatlist[jt].format==0) - { - data->cparams.format.format=0; - break; - } - jt++; - } while(1); - - if (data->cparams.format.format==0) - { - data->cparams.format.format=original_format; - - /* At secod downgrade sample rate */ - jt=0; - do { - if (ratelist[jt].rate==data->cparams.format.rate) - { - data->cparams.format.rate=ratelist[jt+1].rate; - break; - } - if (ratelist[jt].rate==0) - { - data->cparams.format.rate=0; - break; - } - jt++; - } while(1); - - if (data->cparams.format.rate==0) - { - data->cparams.format.rate=original_rate; - data->cparams.format.format=original_format; - - /* At third downgrade channels number */ - jt=0; - do { - if(channellist[jt].channels==data->cparams.format.voices) - { - data->cparams.format.voices=channellist[jt+1].channels; - break; - } - if (channellist[jt].channels==0) - { - data->cparams.format.voices=0; - break; - } - jt++; - } while(1); - } - - if (data->cparams.format.voices==0) - { - break; - } - } - - data->cparams.buf.block.frag_size=device->UpdateSize* - data->cparams.format.voices* - snd_pcm_format_width(data->cparams.format.format)/8; - data->cparams.buf.block.frags_max=device->NumUpdates; - data->cparams.buf.block.frags_min=device->NumUpdates; - if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0) - { - continue; - } - else - { - break; - } - } while(1); - - if (data->cparams.format.voices!=0) - { - break; - } - } - - if (data->cparams.format.voices==0) - { - return ALC_FALSE; - } - } - - if ((snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK))<0) - { - return ALC_FALSE; - } - - memset(&data->csetup, 0, sizeof(data->csetup)); - data->csetup.channel=SND_PCM_CHANNEL_PLAYBACK; - if (snd_pcm_plugin_setup(data->pcmHandle, &data->csetup)<0) - { - return ALC_FALSE; - } - - /* now fill back to the our AL device */ - device->Frequency=data->cparams.format.rate; - - switch (data->cparams.format.voices) - { - case 1: - device->FmtChans=DevFmtMono; - break; - case 2: - device->FmtChans=DevFmtStereo; - break; - case 4: - device->FmtChans=DevFmtQuad; - break; - case 6: - device->FmtChans=DevFmtX51; - break; - case 7: - device->FmtChans=DevFmtX61; - break; - case 8: - device->FmtChans=DevFmtX71; - break; - default: - device->FmtChans=DevFmtMono; - break; - } - - switch (data->cparams.format.format) - { - case SND_PCM_SFMT_S8: - device->FmtType=DevFmtByte; - break; - case SND_PCM_SFMT_U8: - device->FmtType=DevFmtUByte; - break; - case SND_PCM_SFMT_S16_LE: - device->FmtType=DevFmtShort; - break; - case SND_PCM_SFMT_U16_LE: - device->FmtType=DevFmtUShort; - break; - case SND_PCM_SFMT_S32_LE: - device->FmtType=DevFmtInt; - break; - case SND_PCM_SFMT_U32_LE: - device->FmtType=DevFmtUInt; - break; - case SND_PCM_SFMT_FLOAT_LE: - device->FmtType=DevFmtFloat; - break; - default: - device->FmtType=DevFmtShort; - break; - } - - SetDefaultChannelOrder(device); - - device->UpdateSize=data->csetup.buf.block.frag_size / device->frameSizeFromFmt(); - device->NumUpdates=data->csetup.buf.block.frags; - - data->size=data->csetup.buf.block.frag_size; - data->buffer=malloc(data->size); - if (!data->buffer) - { - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static ALCboolean qsa_start_playback(PlaybackWrapper *self) -{ - qsa_data *data = self->mExtraData.get(); - - try { - data->mKillNow.store(AL_FALSE, std::memory_order_release); - data->mThread = std::thread(qsa_proc_playback, self); - return ALC_TRUE; - } - catch(std::exception& e) { - ERR("Could not create playback thread: %s\n", e.what()); - } - catch(...) { - } - return ALC_FALSE; -} - -static void qsa_stop_playback(PlaybackWrapper *self) -{ - qsa_data *data = self->mExtraData.get(); - - if(data->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !data->mThread.joinable()) - return; - data->mThread.join(); -} - - -PlaybackWrapper::~PlaybackWrapper() -{ - if(mExtraData) - qsa_close_playback(this); -} - -ALCenum PlaybackWrapper::open(const ALCchar *name) -{ return qsa_open_playback(this, name); } - -ALCboolean PlaybackWrapper::reset() -{ return qsa_reset_playback(this); } - -ALCboolean PlaybackWrapper::start() -{ return qsa_start_playback(this); } - -void PlaybackWrapper::stop() -{ qsa_stop_playback(this); } - - -/***********/ -/* Capture */ -/***********/ - -struct CaptureWrapper final : public BackendBase { - CaptureWrapper(ALCdevice *device) noexcept : BackendBase{device} { } - ~CaptureWrapper() override; - - ALCenum open(const ALCchar *name) override; - ALCboolean start() override; - void stop() override; - ALCenum captureSamples(void *buffer, ALCuint samples) override; - ALCuint availableSamples() override; - - std::unique_ptr mExtraData; - - DEF_NEWDEL(CaptureWrapper) -}; - -static ALCenum qsa_open_capture(CaptureWrapper *self, const ALCchar *deviceName) -{ - ALCdevice *device = self->mDevice; - int card, dev; - int format=-1; - int status; - - std::unique_ptr data{new qsa_data{}}; - - if(!deviceName) - deviceName = qsaDevice; - - if(strcmp(deviceName, qsaDevice) == 0) - status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_CAPTURE); - else - { - if(CaptureNameMap.empty()) - deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap); - - auto iter = std::find_if(CaptureNameMap.cbegin(), CaptureNameMap.cend(), - [deviceName](const DevMap &entry) -> bool - { return entry.name && strcmp(deviceName, entry.name) == 0; } - ); - if(iter == CaptureNameMap.cend()) - return ALC_INVALID_DEVICE; - - status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_CAPTURE); - } - - if(status < 0) - return ALC_INVALID_DEVICE; - - data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE); - if(data->audio_fd < 0) - { - snd_pcm_close(data->pcmHandle); - return ALC_INVALID_DEVICE; - } - - device->DeviceName = deviceName; - - switch (device->FmtType) - { - case DevFmtByte: - format=SND_PCM_SFMT_S8; - break; - case DevFmtUByte: - format=SND_PCM_SFMT_U8; - break; - case DevFmtShort: - format=SND_PCM_SFMT_S16_LE; - break; - case DevFmtUShort: - format=SND_PCM_SFMT_U16_LE; - break; - case DevFmtInt: - format=SND_PCM_SFMT_S32_LE; - break; - case DevFmtUInt: - format=SND_PCM_SFMT_U32_LE; - break; - case DevFmtFloat: - format=SND_PCM_SFMT_FLOAT_LE; - break; - } - - /* we actually don't want to block on reads */ - snd_pcm_nonblock_mode(data->pcmHandle, 1); - /* Disable mmap to control data transfer to the audio device */ - snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_MMAP); - - /* configure a sound channel */ - memset(&data->cparams, 0, sizeof(data->cparams)); - data->cparams.mode=SND_PCM_MODE_BLOCK; - data->cparams.channel=SND_PCM_CHANNEL_CAPTURE; - data->cparams.start_mode=SND_PCM_START_GO; - data->cparams.stop_mode=SND_PCM_STOP_STOP; - - data->cparams.buf.block.frag_size=device->UpdateSize * device->frameSizeFromFmt(); - data->cparams.buf.block.frags_max=device->NumUpdates; - data->cparams.buf.block.frags_min=device->NumUpdates; - - data->cparams.format.interleave=1; - data->cparams.format.rate=device->Frequency; - data->cparams.format.voices=device->channelsFromFmt(); - data->cparams.format.format=format; - - if(snd_pcm_plugin_params(data->pcmHandle, &data->cparams) < 0) - { - snd_pcm_close(data->pcmHandle); - return ALC_INVALID_VALUE; - } - - self->mExtraData = std::move(data); - - return ALC_NO_ERROR; -} - -static void qsa_close_capture(CaptureWrapper *self) -{ - qsa_data *data = self->mExtraData.get(); - - if (data->pcmHandle!=nullptr) - snd_pcm_close(data->pcmHandle); - data->pcmHandle = nullptr; - - self->mExtraData = nullptr; -} - -static void qsa_start_capture(CaptureWrapper *self) -{ - qsa_data *data = self->mExtraData.get(); - int rstatus; - - if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0) - { - ERR("capture prepare failed: %s\n", snd_strerror(rstatus)); - return; - } - - memset(&data->csetup, 0, sizeof(data->csetup)); - data->csetup.channel=SND_PCM_CHANNEL_CAPTURE; - if ((rstatus=snd_pcm_plugin_setup(data->pcmHandle, &data->csetup))<0) - { - ERR("capture setup failed: %s\n", snd_strerror(rstatus)); - return; - } - - snd_pcm_capture_go(data->pcmHandle); -} - -static void qsa_stop_capture(CaptureWrapper *self) -{ - qsa_data *data = self->mExtraData.get(); - snd_pcm_capture_flush(data->pcmHandle); -} - -static ALCuint qsa_available_samples(CaptureWrapper *self) -{ - ALCdevice *device = self->mDevice; - qsa_data *data = self->mExtraData.get(); - snd_pcm_channel_status_t status; - ALint frame_size = device->frameSizeFromFmt(); - ALint free_size; - int rstatus; - - memset(&status, 0, sizeof (status)); - status.channel=SND_PCM_CHANNEL_CAPTURE; - snd_pcm_plugin_status(data->pcmHandle, &status); - if ((status.status==SND_PCM_STATUS_OVERRUN) || - (status.status==SND_PCM_STATUS_READY)) - { - if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0) - { - ERR("capture prepare failed: %s\n", snd_strerror(rstatus)); - aluHandleDisconnect(device, "Failed capture recovery: %s", snd_strerror(rstatus)); - return 0; - } - - snd_pcm_capture_go(data->pcmHandle); - return 0; - } - - free_size=data->csetup.buf.block.frag_size*data->csetup.buf.block.frags; - free_size-=status.free; - - return free_size/frame_size; -} - -static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuint samples) -{ - ALCdevice *device = self->mDevice; - qsa_data *data = self->mExtraData.get(); - char* read_ptr; - snd_pcm_channel_status_t status; - int selectret; - int bytes_read; - ALint frame_size=device->frameSizeFromFmt(); - ALint len=samples*frame_size; - int rstatus; - - read_ptr = static_cast(buffer); - - while (len>0) - { - pollfd pollitem{}; - pollitem.fd = data->audio_fd; - pollitem.events = POLLOUT; - - /* Select also works like time slice to OS */ - bytes_read=0; - selectret = poll(&pollitem, 1, 2000); - switch (selectret) - { - case -1: - aluHandleDisconnect(device, "Failed to check capture samples"); - return ALC_INVALID_DEVICE; - case 0: - break; - default: - bytes_read=snd_pcm_plugin_read(data->pcmHandle, read_ptr, len); - break; - } - - if (bytes_read<=0) - { - if ((errno==EAGAIN) || (errno==EWOULDBLOCK)) - { - continue; - } - - memset(&status, 0, sizeof (status)); - status.channel=SND_PCM_CHANNEL_CAPTURE; - snd_pcm_plugin_status(data->pcmHandle, &status); - - /* we need to reinitialize the sound channel if we've overrun the buffer */ - if ((status.status==SND_PCM_STATUS_OVERRUN) || - (status.status==SND_PCM_STATUS_READY)) - { - if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0) - { - ERR("capture prepare failed: %s\n", snd_strerror(rstatus)); - aluHandleDisconnect(device, "Failed capture recovery: %s", - snd_strerror(rstatus)); - return ALC_INVALID_DEVICE; - } - snd_pcm_capture_go(data->pcmHandle); - } - } - else - { - read_ptr+=bytes_read; - len-=bytes_read; - } - } - - return ALC_NO_ERROR; -} - - -CaptureWrapper::~CaptureWrapper() -{ - if(mExtraData) - qsa_close_capture(this); -} - -ALCenum CaptureWrapper::open(const ALCchar *name) -{ return qsa_open_capture(this, name); } - -ALCboolean CaptureWrapper::start() -{ qsa_start_capture(this); return ALC_TRUE; } - -void CaptureWrapper::stop() -{ qsa_stop_capture(this); } - -ALCenum CaptureWrapper::captureSamples(void *buffer, ALCuint samples) -{ return qsa_capture_samples(this, buffer, samples); } - -ALCuint CaptureWrapper::availableSamples() -{ return qsa_available_samples(this); } - -} // namespace - - -bool QSABackendFactory::init() -{ return true; } - -bool QSABackendFactory::querySupport(BackendType type) -{ return (type == BackendType::Playback || type == BackendType::Capture); } - -void QSABackendFactory::probe(DevProbe type, std::string *outnames) -{ - auto add_device = [outnames](const DevMap &entry) -> void - { - const char *n = entry.name; - if(n && n[0]) - outnames->append(n, strlen(n)+1); - }; - - switch (type) - { - case DevProbe::Playback: - deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap); - std::for_each(DeviceNameMap.cbegin(), DeviceNameMap.cend(), add_device); - break; - case DevProbe::Capture: - deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap); - std::for_each(CaptureNameMap.cbegin(), CaptureNameMap.cend(), add_device); - break; - } -} - -BackendPtr QSABackendFactory::createBackend(ALCdevice *device, BackendType type) -{ - if(type == BackendType::Playback) - return BackendPtr{new PlaybackWrapper{device}}; - if(type == BackendType::Capture) - return BackendPtr{new CaptureWrapper{device}}; - return nullptr; -} - -BackendFactory &QSABackendFactory::getFactory() -{ - static QSABackendFactory factory{}; - return factory; -} diff --git a/Alc/backends/qsa.h b/Alc/backends/qsa.h deleted file mode 100644 index da548bba..00000000 --- a/Alc/backends/qsa.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef BACKENDS_QSA_H -#define BACKENDS_QSA_H - -#include "backends/base.h" - -struct QSABackendFactory final : public BackendFactory { -public: - bool init() override; - - bool querySupport(BackendType type) override; - - void probe(DevProbe type, std::string *outnames) override; - - BackendPtr createBackend(ALCdevice *device, BackendType type) override; - - static BackendFactory &getFactory(); -}; - -#endif /* BACKENDS_QSA_H */ diff --git a/Alc/backends/sdl2.cpp b/Alc/backends/sdl2.cpp deleted file mode 100644 index 97547959..00000000 --- a/Alc/backends/sdl2.cpp +++ /dev/null @@ -1,223 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2018 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "backends/sdl2.h" - -#include -#include - -#include - -#include "alcmain.h" -#include "alu.h" -#include "threads.h" -#include "compat.h" - - -namespace { - -#ifdef _WIN32 -#define DEVNAME_PREFIX "OpenAL Soft on " -#else -#define DEVNAME_PREFIX "" -#endif - -constexpr ALCchar defaultDeviceName[] = DEVNAME_PREFIX "Default Device"; - -struct Sdl2Backend final : public BackendBase { - Sdl2Backend(ALCdevice *device) noexcept : BackendBase{device} { } - ~Sdl2Backend() override; - - static void audioCallbackC(void *ptr, Uint8 *stream, int len); - void audioCallback(Uint8 *stream, int len); - - ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; - void stop() override; - void lock() override; - void unlock() override; - - SDL_AudioDeviceID mDeviceID{0u}; - ALsizei mFrameSize{0}; - - ALuint mFrequency{0u}; - DevFmtChannels mFmtChans{}; - DevFmtType mFmtType{}; - ALuint mUpdateSize{0u}; - - DEF_NEWDEL(Sdl2Backend) -}; - -Sdl2Backend::~Sdl2Backend() -{ - if(mDeviceID) - SDL_CloseAudioDevice(mDeviceID); - mDeviceID = 0; -} - -void Sdl2Backend::audioCallbackC(void *ptr, Uint8 *stream, int len) -{ static_cast(ptr)->audioCallback(stream, len); } - -void Sdl2Backend::audioCallback(Uint8 *stream, int len) -{ - assert((len % mFrameSize) == 0); - aluMixData(mDevice, stream, len / mFrameSize); -} - -ALCenum Sdl2Backend::open(const ALCchar *name) -{ - SDL_AudioSpec want{}, have{}; - want.freq = mDevice->Frequency; - switch(mDevice->FmtType) - { - case DevFmtUByte: want.format = AUDIO_U8; break; - case DevFmtByte: want.format = AUDIO_S8; break; - case DevFmtUShort: want.format = AUDIO_U16SYS; break; - case DevFmtShort: want.format = AUDIO_S16SYS; break; - case DevFmtUInt: /* fall-through */ - case DevFmtInt: want.format = AUDIO_S32SYS; break; - case DevFmtFloat: want.format = AUDIO_F32; break; - } - want.channels = (mDevice->FmtChans == DevFmtMono) ? 1 : 2; - want.samples = mDevice->UpdateSize; - want.callback = &Sdl2Backend::audioCallbackC; - want.userdata = this; - - /* Passing nullptr to SDL_OpenAudioDevice opens a default, which isn't - * necessarily the first in the list. - */ - if(!name || strcmp(name, defaultDeviceName) == 0) - mDeviceID = SDL_OpenAudioDevice(nullptr, SDL_FALSE, &want, &have, - SDL_AUDIO_ALLOW_ANY_CHANGE); - else - { - const size_t prefix_len = strlen(DEVNAME_PREFIX); - if(strncmp(name, DEVNAME_PREFIX, prefix_len) == 0) - mDeviceID = SDL_OpenAudioDevice(name+prefix_len, SDL_FALSE, &want, &have, - SDL_AUDIO_ALLOW_ANY_CHANGE); - else - mDeviceID = SDL_OpenAudioDevice(name, SDL_FALSE, &want, &have, - SDL_AUDIO_ALLOW_ANY_CHANGE); - } - if(mDeviceID == 0) - return ALC_INVALID_VALUE; - - mDevice->Frequency = have.freq; - if(have.channels == 1) - mDevice->FmtChans = DevFmtMono; - else if(have.channels == 2) - mDevice->FmtChans = DevFmtStereo; - else - { - ERR("Got unhandled SDL channel count: %d\n", (int)have.channels); - return ALC_INVALID_VALUE; - } - switch(have.format) - { - case AUDIO_U8: mDevice->FmtType = DevFmtUByte; break; - case AUDIO_S8: mDevice->FmtType = DevFmtByte; break; - case AUDIO_U16SYS: mDevice->FmtType = DevFmtUShort; break; - case AUDIO_S16SYS: mDevice->FmtType = DevFmtShort; break; - case AUDIO_S32SYS: mDevice->FmtType = DevFmtInt; break; - case AUDIO_F32SYS: mDevice->FmtType = DevFmtFloat; break; - default: - ERR("Got unsupported SDL format: 0x%04x\n", have.format); - return ALC_INVALID_VALUE; - } - mDevice->UpdateSize = have.samples; - mDevice->BufferSize = have.samples * 2; /* SDL always (tries to) use two periods. */ - - mFrameSize = mDevice->frameSizeFromFmt(); - mFrequency = mDevice->Frequency; - mFmtChans = mDevice->FmtChans; - mFmtType = mDevice->FmtType; - mUpdateSize = mDevice->UpdateSize; - - mDevice->DeviceName = name ? name : defaultDeviceName; - return ALC_NO_ERROR; -} - -ALCboolean Sdl2Backend::reset() -{ - mDevice->Frequency = mFrequency; - mDevice->FmtChans = mFmtChans; - mDevice->FmtType = mFmtType; - mDevice->UpdateSize = mUpdateSize; - mDevice->BufferSize = mUpdateSize * 2; - SetDefaultWFXChannelOrder(mDevice); - return ALC_TRUE; -} - -ALCboolean Sdl2Backend::start() -{ - SDL_PauseAudioDevice(mDeviceID, 0); - return ALC_TRUE; -} - -void Sdl2Backend::stop() -{ SDL_PauseAudioDevice(mDeviceID, 1); } - -void Sdl2Backend::lock() -{ SDL_LockAudioDevice(mDeviceID); } - -void Sdl2Backend::unlock() -{ SDL_UnlockAudioDevice(mDeviceID); } - -} // namespace - -BackendFactory &SDL2BackendFactory::getFactory() -{ - static SDL2BackendFactory factory{}; - return factory; -} - -bool SDL2BackendFactory::init() -{ return (SDL_InitSubSystem(SDL_INIT_AUDIO) == 0); } - -bool SDL2BackendFactory::querySupport(BackendType type) -{ return type == BackendType::Playback; } - -void SDL2BackendFactory::probe(DevProbe type, std::string *outnames) -{ - if(type != DevProbe::Playback) - return; - - int num_devices{SDL_GetNumAudioDevices(SDL_FALSE)}; - - /* Includes null char. */ - outnames->append(defaultDeviceName, sizeof(defaultDeviceName)); - for(int i{0};i < num_devices;++i) - { - std::string name{DEVNAME_PREFIX}; - name += SDL_GetAudioDeviceName(i, SDL_FALSE); - if(!name.empty()) - outnames->append(name.c_str(), name.length()+1); - } -} - -BackendPtr SDL2BackendFactory::createBackend(ALCdevice *device, BackendType type) -{ - if(type == BackendType::Playback) - return BackendPtr{new Sdl2Backend{device}}; - return nullptr; -} diff --git a/Alc/backends/sdl2.h b/Alc/backends/sdl2.h deleted file mode 100644 index 041d47ee..00000000 --- a/Alc/backends/sdl2.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef BACKENDS_SDL2_H -#define BACKENDS_SDL2_H - -#include "backends/base.h" - -struct SDL2BackendFactory final : public BackendFactory { -public: - bool init() override; - - bool querySupport(BackendType type) override; - - void probe(DevProbe type, std::string *outnames) override; - - BackendPtr createBackend(ALCdevice *device, BackendType type) override; - - static BackendFactory &getFactory(); -}; - -#endif /* BACKENDS_SDL2_H */ diff --git a/Alc/backends/sndio.cpp b/Alc/backends/sndio.cpp deleted file mode 100644 index 587f67bb..00000000 --- a/Alc/backends/sndio.cpp +++ /dev/null @@ -1,495 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "backends/sndio.h" - -#include -#include -#include - -#include -#include - -#include "alcmain.h" -#include "alu.h" -#include "threads.h" -#include "vector.h" -#include "ringbuffer.h" - -#include - - -namespace { - -static const ALCchar sndio_device[] = "SndIO Default"; - - -struct SndioPlayback final : public BackendBase { - SndioPlayback(ALCdevice *device) noexcept : BackendBase{device} { } - ~SndioPlayback() override; - - int mixerProc(); - - ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; - void stop() override; - - sio_hdl *mSndHandle{nullptr}; - - al::vector mBuffer; - - std::atomic mKillNow{true}; - std::thread mThread; - - DEF_NEWDEL(SndioPlayback) -}; - -SndioPlayback::~SndioPlayback() -{ - if(mSndHandle) - sio_close(mSndHandle); - mSndHandle = nullptr; -} - -int SndioPlayback::mixerProc() -{ - SetRTPriority(); - althrd_setname(MIXER_THREAD_NAME); - - const ALsizei frameSize{mDevice->frameSizeFromFmt()}; - - while(!mKillNow.load(std::memory_order_acquire) && - mDevice->Connected.load(std::memory_order_acquire)) - { - auto WritePtr = static_cast(mBuffer.data()); - size_t len{mBuffer.size()}; - - lock(); - aluMixData(mDevice, WritePtr, len/frameSize); - unlock(); - while(len > 0 && !mKillNow.load(std::memory_order_acquire)) - { - size_t wrote{sio_write(mSndHandle, WritePtr, len)}; - if(wrote == 0) - { - ERR("sio_write failed\n"); - aluHandleDisconnect(mDevice, "Failed to write playback samples"); - break; - } - - len -= wrote; - WritePtr += wrote; - } - } - - return 0; -} - - -ALCenum SndioPlayback::open(const ALCchar *name) -{ - if(!name) - name = sndio_device; - else if(strcmp(name, sndio_device) != 0) - return ALC_INVALID_VALUE; - - mSndHandle = sio_open(nullptr, SIO_PLAY, 0); - if(mSndHandle == nullptr) - { - ERR("Could not open device\n"); - return ALC_INVALID_VALUE; - } - - mDevice->DeviceName = name; - return ALC_NO_ERROR; -} - -ALCboolean SndioPlayback::reset() -{ - sio_par par; - sio_initpar(&par); - - par.rate = mDevice->Frequency; - par.pchan = ((mDevice->FmtChans != DevFmtMono) ? 2 : 1); - - switch(mDevice->FmtType) - { - case DevFmtByte: - par.bits = 8; - par.sig = 1; - break; - case DevFmtUByte: - par.bits = 8; - par.sig = 0; - break; - case DevFmtFloat: - case DevFmtShort: - par.bits = 16; - par.sig = 1; - break; - case DevFmtUShort: - par.bits = 16; - par.sig = 0; - break; - case DevFmtInt: - par.bits = 32; - par.sig = 1; - break; - case DevFmtUInt: - par.bits = 32; - par.sig = 0; - break; - } - par.le = SIO_LE_NATIVE; - - par.round = mDevice->UpdateSize; - par.appbufsz = mDevice->BufferSize - mDevice->UpdateSize; - if(!par.appbufsz) par.appbufsz = mDevice->UpdateSize; - - if(!sio_setpar(mSndHandle, &par) || !sio_getpar(mSndHandle, &par)) - { - ERR("Failed to set device parameters\n"); - return ALC_FALSE; - } - - if(par.bits != par.bps*8) - { - ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8); - return ALC_FALSE; - } - - mDevice->Frequency = par.rate; - mDevice->FmtChans = ((par.pchan==1) ? DevFmtMono : DevFmtStereo); - - if(par.bits == 8 && par.sig == 1) - mDevice->FmtType = DevFmtByte; - else if(par.bits == 8 && par.sig == 0) - mDevice->FmtType = DevFmtUByte; - else if(par.bits == 16 && par.sig == 1) - mDevice->FmtType = DevFmtShort; - else if(par.bits == 16 && par.sig == 0) - mDevice->FmtType = DevFmtUShort; - else if(par.bits == 32 && par.sig == 1) - mDevice->FmtType = DevFmtInt; - else if(par.bits == 32 && par.sig == 0) - mDevice->FmtType = DevFmtUInt; - else - { - ERR("Unhandled sample format: %s %u-bit\n", (par.sig?"signed":"unsigned"), par.bits); - return ALC_FALSE; - } - - SetDefaultChannelOrder(mDevice); - - mDevice->UpdateSize = par.round; - mDevice->BufferSize = par.bufsz + par.round; - - mBuffer.resize(mDevice->UpdateSize * mDevice->frameSizeFromFmt()); - std::fill(mBuffer.begin(), mBuffer.end(), 0); - - return ALC_TRUE; -} - -ALCboolean SndioPlayback::start() -{ - if(!sio_start(mSndHandle)) - { - ERR("Error starting playback\n"); - return ALC_FALSE; - } - - try { - mKillNow.store(false, std::memory_order_release); - mThread = std::thread{std::mem_fn(&SndioPlayback::mixerProc), this}; - return ALC_TRUE; - } - catch(std::exception& e) { - ERR("Could not create playback thread: %s\n", e.what()); - } - catch(...) { - } - sio_stop(mSndHandle); - return ALC_FALSE; -} - -void SndioPlayback::stop() -{ - if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) - return; - mThread.join(); - - if(!sio_stop(mSndHandle)) - ERR("Error stopping device\n"); -} - - -struct SndioCapture final : public BackendBase { - SndioCapture(ALCdevice *device) noexcept : BackendBase{device} { } - ~SndioCapture() override; - - int recordProc(); - - ALCenum open(const ALCchar *name) override; - ALCboolean start() override; - void stop() override; - ALCenum captureSamples(void *buffer, ALCuint samples) override; - ALCuint availableSamples() override; - - sio_hdl *mSndHandle{nullptr}; - - RingBufferPtr mRing; - - std::atomic mKillNow{true}; - std::thread mThread; - - DEF_NEWDEL(SndioCapture) -}; - -SndioCapture::~SndioCapture() -{ - if(mSndHandle) - sio_close(mSndHandle); - mSndHandle = nullptr; -} - -int SndioCapture::recordProc() -{ - SetRTPriority(); - althrd_setname(RECORD_THREAD_NAME); - - const ALsizei frameSize{mDevice->frameSizeFromFmt()}; - - while(!mKillNow.load(std::memory_order_acquire) && - mDevice->Connected.load(std::memory_order_acquire)) - { - auto data = mRing->getWriteVector(); - size_t todo{data.first.len + data.second.len}; - if(todo == 0) - { - static char junk[4096]; - sio_read(mSndHandle, junk, - minz(sizeof(junk)/frameSize, mDevice->UpdateSize)*frameSize); - continue; - } - - size_t total{0u}; - data.first.len *= frameSize; - data.second.len *= frameSize; - todo = minz(todo, mDevice->UpdateSize) * frameSize; - while(total < todo) - { - if(!data.first.len) - data.first = data.second; - - size_t got{sio_read(mSndHandle, data.first.buf, minz(todo-total, data.first.len))}; - if(!got) - { - aluHandleDisconnect(mDevice, "Failed to read capture samples"); - break; - } - - data.first.buf += got; - data.first.len -= got; - total += got; - } - mRing->writeAdvance(total / frameSize); - } - - return 0; -} - - -ALCenum SndioCapture::open(const ALCchar *name) -{ - if(!name) - name = sndio_device; - else if(strcmp(name, sndio_device) != 0) - return ALC_INVALID_VALUE; - - mSndHandle = sio_open(nullptr, SIO_REC, 0); - if(mSndHandle == nullptr) - { - ERR("Could not open device\n"); - return ALC_INVALID_VALUE; - } - - sio_par par; - sio_initpar(&par); - - switch(mDevice->FmtType) - { - case DevFmtByte: - par.bps = 1; - par.sig = 1; - break; - case DevFmtUByte: - par.bps = 1; - par.sig = 0; - break; - case DevFmtShort: - par.bps = 2; - par.sig = 1; - break; - case DevFmtUShort: - par.bps = 2; - par.sig = 0; - break; - case DevFmtInt: - par.bps = 4; - par.sig = 1; - break; - case DevFmtUInt: - par.bps = 4; - par.sig = 0; - break; - case DevFmtFloat: - ERR("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); - return ALC_INVALID_VALUE; - } - par.bits = par.bps * 8; - par.le = SIO_LE_NATIVE; - par.msb = SIO_LE_NATIVE ? 0 : 1; - par.rchan = mDevice->channelsFromFmt(); - par.rate = mDevice->Frequency; - - par.appbufsz = maxu(mDevice->BufferSize, mDevice->Frequency/10); - par.round = minu(par.appbufsz, mDevice->Frequency/40); - - mDevice->UpdateSize = par.round; - mDevice->BufferSize = par.appbufsz; - - if(!sio_setpar(mSndHandle, &par) || !sio_getpar(mSndHandle, &par)) - { - ERR("Failed to set device parameters\n"); - return ALC_INVALID_VALUE; - } - - if(par.bits != par.bps*8) - { - ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8); - return ALC_INVALID_VALUE; - } - - if(!((mDevice->FmtType == DevFmtByte && par.bits == 8 && par.sig != 0) || - (mDevice->FmtType == DevFmtUByte && par.bits == 8 && par.sig == 0) || - (mDevice->FmtType == DevFmtShort && par.bits == 16 && par.sig != 0) || - (mDevice->FmtType == DevFmtUShort && par.bits == 16 && par.sig == 0) || - (mDevice->FmtType == DevFmtInt && par.bits == 32 && par.sig != 0) || - (mDevice->FmtType == DevFmtUInt && par.bits == 32 && par.sig == 0)) || - mDevice->channelsFromFmt() != (ALsizei)par.rchan || - mDevice->Frequency != par.rate) - { - ERR("Failed to set format %s %s %uhz, got %c%u %u-channel %uhz instead\n", - DevFmtTypeString(mDevice->FmtType), DevFmtChannelsString(mDevice->FmtChans), - mDevice->Frequency, par.sig?'s':'u', par.bits, par.rchan, par.rate); - return ALC_INVALID_VALUE; - } - - mRing = CreateRingBuffer(mDevice->BufferSize, par.bps*par.rchan, false); - if(!mRing) - { - ERR("Failed to allocate %u-byte ringbuffer\n", mDevice->BufferSize*par.bps*par.rchan); - return ALC_OUT_OF_MEMORY; - } - - SetDefaultChannelOrder(mDevice); - - mDevice->DeviceName = name; - return ALC_NO_ERROR; -} - -ALCboolean SndioCapture::start() -{ - if(!sio_start(mSndHandle)) - { - ERR("Error starting playback\n"); - return ALC_FALSE; - } - - try { - mKillNow.store(false, std::memory_order_release); - mThread = std::thread{std::mem_fn(&SndioCapture::recordProc), this}; - return ALC_TRUE; - } - catch(std::exception& e) { - ERR("Could not create record thread: %s\n", e.what()); - } - catch(...) { - } - sio_stop(mSndHandle); - return ALC_FALSE; -} - -void SndioCapture::stop() -{ - if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) - return; - mThread.join(); - - if(!sio_stop(mSndHandle)) - ERR("Error stopping device\n"); -} - -ALCenum SndioCapture::captureSamples(void *buffer, ALCuint samples) -{ - mRing->read(buffer, samples); - return ALC_NO_ERROR; -} - -ALCuint SndioCapture::availableSamples() -{ return mRing->readSpace(); } - -} // namespace - -BackendFactory &SndIOBackendFactory::getFactory() -{ - static SndIOBackendFactory factory{}; - return factory; -} - -bool SndIOBackendFactory::init() -{ return true; } - -bool SndIOBackendFactory::querySupport(BackendType type) -{ return (type == BackendType::Playback || type == BackendType::Capture); } - -void SndIOBackendFactory::probe(DevProbe type, std::string *outnames) -{ - switch(type) - { - case DevProbe::Playback: - case DevProbe::Capture: - /* Includes null char. */ - outnames->append(sndio_device, sizeof(sndio_device)); - break; - } -} - -BackendPtr SndIOBackendFactory::createBackend(ALCdevice *device, BackendType type) -{ - if(type == BackendType::Playback) - return BackendPtr{new SndioPlayback{device}}; - if(type == BackendType::Capture) - return BackendPtr{new SndioCapture{device}}; - return nullptr; -} diff --git a/Alc/backends/sndio.h b/Alc/backends/sndio.h deleted file mode 100644 index 1ed63d5e..00000000 --- a/Alc/backends/sndio.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef BACKENDS_SNDIO_H -#define BACKENDS_SNDIO_H - -#include "backends/base.h" - -struct SndIOBackendFactory final : public BackendFactory { -public: - bool init() override; - - bool querySupport(BackendType type) override; - - void probe(DevProbe type, std::string *outnames) override; - - BackendPtr createBackend(ALCdevice *device, BackendType type) override; - - static BackendFactory &getFactory(); -}; - -#endif /* BACKENDS_SNDIO_H */ diff --git a/Alc/backends/solaris.cpp b/Alc/backends/solaris.cpp deleted file mode 100644 index 584f6e66..00000000 --- a/Alc/backends/solaris.cpp +++ /dev/null @@ -1,302 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "backends/solaris.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "alcmain.h" -#include "alu.h" -#include "alconfig.h" -#include "threads.h" -#include "vector.h" -#include "compat.h" - -#include - - -namespace { - -constexpr ALCchar solaris_device[] = "Solaris Default"; - -std::string solaris_driver{"/dev/audio"}; - - -struct SolarisBackend final : public BackendBase { - SolarisBackend(ALCdevice *device) noexcept : BackendBase{device} { } - ~SolarisBackend() override; - - int mixerProc(); - - ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; - void stop() override; - - int mFd{-1}; - - al::vector mBuffer; - - std::atomic mKillNow{true}; - std::thread mThread; - - DEF_NEWDEL(SolarisBackend) -}; - -SolarisBackend::~SolarisBackend() -{ - if(mFd != -1) - close(mFd); - mFd = -1; -} - -int SolarisBackend::mixerProc() -{ - SetRTPriority(); - althrd_setname(MIXER_THREAD_NAME); - - const int frame_size{mDevice->frameSizeFromFmt()}; - - lock(); - while(!mKillNow.load(std::memory_order_acquire) && - mDevice->Connected.load(std::memory_order_acquire)) - { - pollfd pollitem{}; - pollitem.fd = mFd; - pollitem.events = POLLOUT; - - unlock(); - int pret{poll(&pollitem, 1, 1000)}; - lock(); - if(pret < 0) - { - if(errno == EINTR || errno == EAGAIN) - continue; - ERR("poll failed: %s\n", strerror(errno)); - aluHandleDisconnect(mDevice, "Failed to wait for playback buffer: %s", - strerror(errno)); - break; - } - else if(pret == 0) - { - WARN("poll timeout\n"); - continue; - } - - ALubyte *write_ptr{mBuffer.data()}; - size_t to_write{mBuffer.size()}; - aluMixData(mDevice, write_ptr, to_write/frame_size); - while(to_write > 0 && !mKillNow.load(std::memory_order_acquire)) - { - ssize_t wrote{write(mFd, write_ptr, to_write)}; - if(wrote < 0) - { - if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) - continue; - ERR("write failed: %s\n", strerror(errno)); - aluHandleDisconnect(mDevice, "Failed to write playback samples: %s", - strerror(errno)); - break; - } - - to_write -= wrote; - write_ptr += wrote; - } - } - unlock(); - - return 0; -} - - -ALCenum SolarisBackend::open(const ALCchar *name) -{ - if(!name) - name = solaris_device; - else if(strcmp(name, solaris_device) != 0) - return ALC_INVALID_VALUE; - - mFd = ::open(solaris_driver.c_str(), O_WRONLY); - if(mFd == -1) - { - ERR("Could not open %s: %s\n", solaris_driver.c_str(), strerror(errno)); - return ALC_INVALID_VALUE; - } - - mDevice->DeviceName = name; - return ALC_NO_ERROR; -} - -ALCboolean SolarisBackend::reset() -{ - audio_info_t info; - AUDIO_INITINFO(&info); - - info.play.sample_rate = mDevice->Frequency; - - if(mDevice->FmtChans != DevFmtMono) - mDevice->FmtChans = DevFmtStereo; - ALsizei numChannels{mDevice->channelsFromFmt()}; - info.play.channels = numChannels; - - switch(mDevice->FmtType) - { - case DevFmtByte: - info.play.precision = 8; - info.play.encoding = AUDIO_ENCODING_LINEAR; - break; - case DevFmtUByte: - info.play.precision = 8; - info.play.encoding = AUDIO_ENCODING_LINEAR8; - break; - case DevFmtUShort: - case DevFmtInt: - case DevFmtUInt: - case DevFmtFloat: - mDevice->FmtType = DevFmtShort; - /* fall-through */ - case DevFmtShort: - info.play.precision = 16; - info.play.encoding = AUDIO_ENCODING_LINEAR; - break; - } - - ALsizei frameSize{numChannels * mDevice->bytesFromFmt()}; - info.play.buffer_size = mDevice->BufferSize * frameSize; - - if(ioctl(mFd, AUDIO_SETINFO, &info) < 0) - { - ERR("ioctl failed: %s\n", strerror(errno)); - return ALC_FALSE; - } - - if(mDevice->channelsFromFmt() != (ALsizei)info.play.channels) - { - ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(mDevice->FmtChans), - info.play.channels); - return ALC_FALSE; - } - - if(!((info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR8 && mDevice->FmtType == DevFmtUByte) || - (info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR && mDevice->FmtType == DevFmtByte) || - (info.play.precision == 16 && info.play.encoding == AUDIO_ENCODING_LINEAR && mDevice->FmtType == DevFmtShort) || - (info.play.precision == 32 && info.play.encoding == AUDIO_ENCODING_LINEAR && mDevice->FmtType == DevFmtInt))) - { - ERR("Could not set %s samples, got %d (0x%x)\n", DevFmtTypeString(mDevice->FmtType), - info.play.precision, info.play.encoding); - return ALC_FALSE; - } - - mDevice->Frequency = info.play.sample_rate; - mDevice->BufferSize = info.play.buffer_size / frameSize; - mDevice->UpdateSize = mDevice->BufferSize / 2; - - SetDefaultChannelOrder(mDevice); - - mBuffer.resize(mDevice->UpdateSize * mDevice->frameSizeFromFmt()); - std::fill(mBuffer.begin(), mBuffer.end(), 0); - - return ALC_TRUE; -} - -ALCboolean SolarisBackend::start() -{ - try { - mKillNow.store(false, std::memory_order_release); - mThread = std::thread{std::mem_fn(&SolarisBackend::mixerProc), this}; - return ALC_TRUE; - } - catch(std::exception& e) { - ERR("Could not create playback thread: %s\n", e.what()); - } - catch(...) { - } - return ALC_FALSE; -} - -void SolarisBackend::stop() -{ - if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) - return; - mThread.join(); - - if(ioctl(mFd, AUDIO_DRAIN) < 0) - ERR("Error draining device: %s\n", strerror(errno)); -} - -} // namespace - -BackendFactory &SolarisBackendFactory::getFactory() -{ - static SolarisBackendFactory factory{}; - return factory; -} - -bool SolarisBackendFactory::init() -{ - if(auto devopt = ConfigValueStr(nullptr, "solaris", "device")) - solaris_driver = std::move(*devopt); - return true; -} - -bool SolarisBackendFactory::querySupport(BackendType type) -{ return type == BackendType::Playback; } - -void SolarisBackendFactory::probe(DevProbe type, std::string *outnames) -{ - switch(type) - { - case DevProbe::Playback: - { -#ifdef HAVE_STAT - struct stat buf; - if(stat(solaris_driver.c_str(), &buf) == 0) -#endif - outnames->append(solaris_device, sizeof(solaris_device)); - } - break; - - case DevProbe::Capture: - break; - } -} - -BackendPtr SolarisBackendFactory::createBackend(ALCdevice *device, BackendType type) -{ - if(type == BackendType::Playback) - return BackendPtr{new SolarisBackend{device}}; - return nullptr; -} diff --git a/Alc/backends/solaris.h b/Alc/backends/solaris.h deleted file mode 100644 index 98b10593..00000000 --- a/Alc/backends/solaris.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef BACKENDS_SOLARIS_H -#define BACKENDS_SOLARIS_H - -#include "backends/base.h" - -struct SolarisBackendFactory final : public BackendFactory { -public: - bool init() override; - - bool querySupport(BackendType type) override; - - void probe(DevProbe type, std::string *outnames) override; - - BackendPtr createBackend(ALCdevice *device, BackendType type) override; - - static BackendFactory &getFactory(); -}; - -#endif /* BACKENDS_SOLARIS_H */ diff --git a/Alc/backends/wasapi.cpp b/Alc/backends/wasapi.cpp deleted file mode 100644 index bd009463..00000000 --- a/Alc/backends/wasapi.cpp +++ /dev/null @@ -1,1763 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2011 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "backends/wasapi.h" - -#define WIN32_LEAN_AND_MEAN -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef _WAVEFORMATEXTENSIBLE_ -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "alcmain.h" -#include "alu.h" -#include "ringbuffer.h" -#include "compat.h" -#include "converter.h" -#include "threads.h" - - -/* Some headers seem to define these as macros for __uuidof, which is annoying - * since some headers don't declare them at all. Hopefully the ifdef is enough - * to tell if they need to be declared. - */ -#ifndef KSDATAFORMAT_SUBTYPE_PCM -DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); -#endif -#ifndef KSDATAFORMAT_SUBTYPE_IEEE_FLOAT -DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); -#endif - -DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); -DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); -DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23,0xe0, 0xc0,0xff,0xee,0x7f,0x0e, 4 ); - - -namespace { - -#define MONO SPEAKER_FRONT_CENTER -#define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT) -#define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT) -#define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) -#define X5DOT1REAR (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT) -#define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) -#define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) -#define X7DOT1_WIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_FRONT_LEFT_OF_CENTER|SPEAKER_FRONT_RIGHT_OF_CENTER) - -#define REFTIME_PER_SEC ((REFERENCE_TIME)10000000) - -#define DEVNAME_HEAD "OpenAL Soft on " - - -/* Scales the given value using 64-bit integer math, ceiling the result. */ -inline int64_t ScaleCeil(int64_t val, int64_t new_scale, int64_t old_scale) -{ - return (val*new_scale + old_scale-1) / old_scale; -} - - -struct PropVariant { - PROPVARIANT mProp; - -public: - PropVariant() { PropVariantInit(&mProp); } - ~PropVariant() { clear(); } - - void clear() { PropVariantClear(&mProp); } - - PROPVARIANT* get() noexcept { return &mProp; } - - PROPVARIANT& operator*() noexcept { return mProp; } - const PROPVARIANT& operator*() const noexcept { return mProp; } - - PROPVARIANT* operator->() noexcept { return &mProp; } - const PROPVARIANT* operator->() const noexcept { return &mProp; } -}; - -struct DevMap { - std::string name; - std::string endpoint_guid; // obtained from PKEY_AudioEndpoint_GUID , set to "Unknown device GUID" if absent. - std::wstring devid; - - template - DevMap(T0&& name_, T1&& guid_, T2&& devid_) - : name{std::forward(name_)} - , endpoint_guid{std::forward(guid_)} - , devid{std::forward(devid_)} - { } -}; - -bool checkName(const al::vector &list, const std::string &name) -{ - return std::find_if(list.cbegin(), list.cend(), - [&name](const DevMap &entry) -> bool - { return entry.name == name; } - ) != list.cend(); -} - -al::vector PlaybackDevices; -al::vector CaptureDevices; - - -using NameGUIDPair = std::pair; -NameGUIDPair get_device_name_and_guid(IMMDevice *device) -{ - std::string name{DEVNAME_HEAD}; - std::string guid; - - IPropertyStore *ps; - HRESULT hr = device->OpenPropertyStore(STGM_READ, &ps); - if(FAILED(hr)) - { - WARN("OpenPropertyStore failed: 0x%08lx\n", hr); - return { name+"Unknown Device Name", "Unknown Device GUID" }; - } - - PropVariant pvprop; - hr = ps->GetValue(reinterpret_cast(DEVPKEY_Device_FriendlyName), pvprop.get()); - if(FAILED(hr)) - { - WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr); - name += "Unknown Device Name"; - } - else if(pvprop->vt == VT_LPWSTR) - name += wstr_to_utf8(pvprop->pwszVal); - else - { - WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvprop->vt); - name += "Unknown Device Name"; - } - - pvprop.clear(); - hr = ps->GetValue(reinterpret_cast(PKEY_AudioEndpoint_GUID), pvprop.get()); - if(FAILED(hr)) - { - WARN("GetValue AudioEndpoint_GUID failed: 0x%08lx\n", hr); - guid = "Unknown Device GUID"; - } - else if(pvprop->vt == VT_LPWSTR) - guid = wstr_to_utf8(pvprop->pwszVal); - else - { - WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvprop->vt); - guid = "Unknown Device GUID"; - } - - ps->Release(); - - return {name, guid}; -} - -void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfactor) -{ - IPropertyStore *ps; - HRESULT hr = device->OpenPropertyStore(STGM_READ, &ps); - if(FAILED(hr)) - { - WARN("OpenPropertyStore failed: 0x%08lx\n", hr); - return; - } - - PropVariant pvform; - hr = ps->GetValue(reinterpret_cast(PKEY_AudioEndpoint_FormFactor), pvform.get()); - if(FAILED(hr)) - WARN("GetValue AudioEndpoint_FormFactor failed: 0x%08lx\n", hr); - else if(pvform->vt == VT_UI4) - *formfactor = static_cast(pvform->ulVal); - else if(pvform->vt == VT_EMPTY) - *formfactor = UnknownFormFactor; - else - WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvform->vt); - - ps->Release(); -} - - -void add_device(IMMDevice *device, const WCHAR *devid, al::vector &list) -{ - std::string basename, guidstr; - std::tie(basename, guidstr) = get_device_name_and_guid(device); - - int count{1}; - std::string newname{basename}; - while(checkName(list, newname)) - { - newname = basename; - newname += " #"; - newname += std::to_string(++count); - } - list.emplace_back(std::move(newname), std::move(guidstr), devid); - const DevMap &newentry = list.back(); - - TRACE("Got device \"%s\", \"%s\", \"%ls\"\n", newentry.name.c_str(), - newentry.endpoint_guid.c_str(), newentry.devid.c_str()); -} - -WCHAR *get_device_id(IMMDevice *device) -{ - WCHAR *devid; - - HRESULT hr = device->GetId(&devid); - if(FAILED(hr)) - { - ERR("Failed to get device id: %lx\n", hr); - return nullptr; - } - - return devid; -} - -HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, al::vector &list) -{ - IMMDeviceCollection *coll; - HRESULT hr{devenum->EnumAudioEndpoints(flowdir, DEVICE_STATE_ACTIVE, &coll)}; - if(FAILED(hr)) - { - ERR("Failed to enumerate audio endpoints: 0x%08lx\n", hr); - return hr; - } - - IMMDevice *defdev{nullptr}; - WCHAR *defdevid{nullptr}; - UINT count{0}; - hr = coll->GetCount(&count); - if(SUCCEEDED(hr) && count > 0) - { - list.clear(); - list.reserve(count); - - hr = devenum->GetDefaultAudioEndpoint(flowdir, eMultimedia, &defdev); - } - if(SUCCEEDED(hr) && defdev != nullptr) - { - defdevid = get_device_id(defdev); - if(defdevid) - add_device(defdev, defdevid, list); - } - - for(UINT i{0};i < count;++i) - { - IMMDevice *device; - hr = coll->Item(i, &device); - if(FAILED(hr)) continue; - - WCHAR *devid{get_device_id(device)}; - if(devid) - { - if(!defdevid || wcscmp(devid, defdevid) != 0) - add_device(device, devid, list); - CoTaskMemFree(devid); - } - device->Release(); - } - - if(defdev) defdev->Release(); - if(defdevid) CoTaskMemFree(defdevid); - coll->Release(); - - return S_OK; -} - - -bool MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) -{ - *out = WAVEFORMATEXTENSIBLE{}; - if(in->wFormatTag == WAVE_FORMAT_EXTENSIBLE) - { - *out = *CONTAINING_RECORD(in, const WAVEFORMATEXTENSIBLE, Format); - out->Format.cbSize = sizeof(*out) - sizeof(out->Format); - } - else if(in->wFormatTag == WAVE_FORMAT_PCM) - { - out->Format = *in; - out->Format.cbSize = 0; - out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample; - if(out->Format.nChannels == 1) - out->dwChannelMask = MONO; - else if(out->Format.nChannels == 2) - out->dwChannelMask = STEREO; - else - ERR("Unhandled PCM channel count: %d\n", out->Format.nChannels); - out->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - } - else if(in->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) - { - out->Format = *in; - out->Format.cbSize = 0; - out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample; - if(out->Format.nChannels == 1) - out->dwChannelMask = MONO; - else if(out->Format.nChannels == 2) - out->dwChannelMask = STEREO; - else - ERR("Unhandled IEEE float channel count: %d\n", out->Format.nChannels); - out->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - } - else - { - ERR("Unhandled format tag: 0x%04x\n", in->wFormatTag); - return false; - } - return true; -} - -void TraceFormat(const char *msg, const WAVEFORMATEX *format) -{ - constexpr size_t fmtex_extra_size{sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX)}; - if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE && format->cbSize >= fmtex_extra_size) - { - class GuidPrinter { - char mMsg[64]; - - public: - GuidPrinter(const GUID &guid) - { - std::snprintf(mMsg, al::size(mMsg), - "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", - DWORD{guid.Data1}, guid.Data2, guid.Data3, - guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], - guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); - } - const char *c_str() const { return mMsg; } - }; - - const WAVEFORMATEXTENSIBLE *fmtex{ - CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format)}; - TRACE("%s:\n" - " FormatTag = 0x%04x\n" - " Channels = %d\n" - " SamplesPerSec = %lu\n" - " AvgBytesPerSec = %lu\n" - " BlockAlign = %d\n" - " BitsPerSample = %d\n" - " Size = %d\n" - " Samples = %d\n" - " ChannelMask = 0x%lx\n" - " SubFormat = %s\n", - msg, fmtex->Format.wFormatTag, fmtex->Format.nChannels, fmtex->Format.nSamplesPerSec, - fmtex->Format.nAvgBytesPerSec, fmtex->Format.nBlockAlign, fmtex->Format.wBitsPerSample, - fmtex->Format.cbSize, fmtex->Samples.wReserved, fmtex->dwChannelMask, - GuidPrinter{fmtex->SubFormat}.c_str()); - } - else - TRACE("%s:\n" - " FormatTag = 0x%04x\n" - " Channels = %d\n" - " SamplesPerSec = %lu\n" - " AvgBytesPerSec = %lu\n" - " BlockAlign = %d\n" - " BitsPerSample = %d\n" - " Size = %d\n", - msg, format->wFormatTag, format->nChannels, format->nSamplesPerSec, - format->nAvgBytesPerSec, format->nBlockAlign, format->wBitsPerSample, format->cbSize); -} - - -enum class MsgType : unsigned int { - OpenDevice, - ResetDevice, - StartDevice, - StopDevice, - CloseDevice, - EnumeratePlayback, - EnumerateCapture, - QuitThread, - - Count -}; - -constexpr char MessageStr[static_cast(MsgType::Count)][20]{ - "Open Device", - "Reset Device", - "Start Device", - "Stop Device", - "Close Device", - "Enumerate Playback", - "Enumerate Capture", - "Quit" -}; - - -/* Proxy interface used by the message handler. */ -struct WasapiProxy { - virtual HRESULT openProxy() = 0; - virtual void closeProxy() = 0; - - virtual HRESULT resetProxy() = 0; - virtual HRESULT startProxy() = 0; - virtual void stopProxy() = 0; - - struct Msg { - MsgType mType; - WasapiProxy *mProxy; - std::promise mPromise; - }; - static std::deque mMsgQueue; - static std::mutex mMsgQueueLock; - static std::condition_variable mMsgQueueCond; - - std::future pushMessage(MsgType type) - { - std::promise promise; - std::future future{promise.get_future()}; - { std::lock_guard _{mMsgQueueLock}; - mMsgQueue.emplace_back(Msg{type, this, std::move(promise)}); - } - mMsgQueueCond.notify_one(); - return future; - } - - static std::future pushMessageStatic(MsgType type) - { - std::promise promise; - std::future future{promise.get_future()}; - { std::lock_guard _{mMsgQueueLock}; - mMsgQueue.emplace_back(Msg{type, nullptr, std::move(promise)}); - } - mMsgQueueCond.notify_one(); - return future; - } - - static bool popMessage(Msg &msg) - { - std::unique_lock lock{mMsgQueueLock}; - while(mMsgQueue.empty()) - mMsgQueueCond.wait(lock); - msg = std::move(mMsgQueue.front()); - mMsgQueue.pop_front(); - return msg.mType != MsgType::QuitThread; - } - - static int messageHandler(std::promise *promise); -}; -std::deque WasapiProxy::mMsgQueue; -std::mutex WasapiProxy::mMsgQueueLock; -std::condition_variable WasapiProxy::mMsgQueueCond; - -int WasapiProxy::messageHandler(std::promise *promise) -{ - TRACE("Starting message thread\n"); - - HRESULT cohr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); - if(FAILED(cohr)) - { - WARN("Failed to initialize COM: 0x%08lx\n", cohr); - promise->set_value(cohr); - return 0; - } - - void *ptr{}; - HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, - IID_IMMDeviceEnumerator, &ptr)}; - if(FAILED(hr)) - { - WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr); - promise->set_value(hr); - CoUninitialize(); - return 0; - } - auto Enumerator = static_cast(ptr); - Enumerator->Release(); - Enumerator = nullptr; - CoUninitialize(); - - TRACE("Message thread initialization complete\n"); - promise->set_value(S_OK); - promise = nullptr; - - TRACE("Starting message loop\n"); - ALuint deviceCount{0}; - Msg msg; - while(popMessage(msg)) - { - TRACE("Got message \"%s\" (0x%04x, this=%p)\n", - MessageStr[static_cast(msg.mType)], static_cast(msg.mType), - msg.mProxy); - - switch(msg.mType) - { - case MsgType::OpenDevice: - hr = cohr = S_OK; - if(++deviceCount == 1) - hr = cohr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); - if(SUCCEEDED(hr)) - hr = msg.mProxy->openProxy(); - msg.mPromise.set_value(hr); - - if(FAILED(hr)) - { - if(--deviceCount == 0 && SUCCEEDED(cohr)) - CoUninitialize(); - } - continue; - - case MsgType::ResetDevice: - hr = msg.mProxy->resetProxy(); - msg.mPromise.set_value(hr); - continue; - - case MsgType::StartDevice: - hr = msg.mProxy->startProxy(); - msg.mPromise.set_value(hr); - continue; - - case MsgType::StopDevice: - msg.mProxy->stopProxy(); - msg.mPromise.set_value(S_OK); - continue; - - case MsgType::CloseDevice: - msg.mProxy->closeProxy(); - msg.mPromise.set_value(S_OK); - - if(--deviceCount == 0) - CoUninitialize(); - continue; - - case MsgType::EnumeratePlayback: - case MsgType::EnumerateCapture: - hr = cohr = S_OK; - if(++deviceCount == 1) - hr = cohr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); - if(SUCCEEDED(hr)) - hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, &ptr); - if(FAILED(hr)) - msg.mPromise.set_value(hr); - else - { - Enumerator = static_cast(ptr); - - if(msg.mType == MsgType::EnumeratePlayback) - hr = probe_devices(Enumerator, eRender, PlaybackDevices); - else if(msg.mType == MsgType::EnumerateCapture) - hr = probe_devices(Enumerator, eCapture, CaptureDevices); - msg.mPromise.set_value(hr); - - Enumerator->Release(); - Enumerator = nullptr; - } - - if(--deviceCount == 0 && SUCCEEDED(cohr)) - CoUninitialize(); - continue; - - default: - ERR("Unexpected message: %u\n", static_cast(msg.mType)); - msg.mPromise.set_value(E_FAIL); - continue; - } - } - TRACE("Message loop finished\n"); - - return 0; -} - - -struct WasapiPlayback final : public BackendBase, WasapiProxy { - WasapiPlayback(ALCdevice *device) noexcept : BackendBase{device} { } - ~WasapiPlayback() override; - - int mixerProc(); - - ALCenum open(const ALCchar *name) override; - HRESULT openProxy() override; - void closeProxy() override; - - ALCboolean reset() override; - HRESULT resetProxy() override; - ALCboolean start() override; - HRESULT startProxy() override; - void stop() override; - void stopProxy() override; - - ClockLatency getClockLatency() override; - - std::wstring mDevId; - - IMMDevice *mMMDev{nullptr}; - IAudioClient *mClient{nullptr}; - IAudioRenderClient *mRender{nullptr}; - HANDLE mNotifyEvent{nullptr}; - - std::atomic mPadding{0u}; - - std::atomic mKillNow{true}; - std::thread mThread; - - DEF_NEWDEL(WasapiPlayback) -}; - -WasapiPlayback::~WasapiPlayback() -{ - pushMessage(MsgType::CloseDevice).wait(); - - if(mNotifyEvent != nullptr) - CloseHandle(mNotifyEvent); - mNotifyEvent = nullptr; -} - - -FORCE_ALIGN int WasapiPlayback::mixerProc() -{ - HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); - if(FAILED(hr)) - { - ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); - aluHandleDisconnect(mDevice, "COM init failed: 0x%08lx", hr); - return 1; - } - - SetRTPriority(); - althrd_setname(MIXER_THREAD_NAME); - - const ALuint update_size{mDevice->UpdateSize}; - const UINT32 buffer_len{mDevice->BufferSize}; - while(!mKillNow.load(std::memory_order_relaxed)) - { - UINT32 written; - hr = mClient->GetCurrentPadding(&written); - if(FAILED(hr)) - { - ERR("Failed to get padding: 0x%08lx\n", hr); - aluHandleDisconnect(mDevice, "Failed to retrieve buffer padding: 0x%08lx", hr); - break; - } - mPadding.store(written, std::memory_order_relaxed); - - ALuint len{buffer_len - written}; - if(len < update_size) - { - DWORD res{WaitForSingleObjectEx(mNotifyEvent, 2000, FALSE)}; - if(res != WAIT_OBJECT_0) - ERR("WaitForSingleObjectEx error: 0x%lx\n", res); - continue; - } - - BYTE *buffer; - hr = mRender->GetBuffer(len, &buffer); - if(SUCCEEDED(hr)) - { - lock(); - aluMixData(mDevice, buffer, len); - mPadding.store(written + len, std::memory_order_relaxed); - unlock(); - hr = mRender->ReleaseBuffer(len, 0); - } - if(FAILED(hr)) - { - ERR("Failed to buffer data: 0x%08lx\n", hr); - aluHandleDisconnect(mDevice, "Failed to send playback samples: 0x%08lx", hr); - break; - } - } - mPadding.store(0u, std::memory_order_release); - - CoUninitialize(); - return 0; -} - - -ALCenum WasapiPlayback::open(const ALCchar *name) -{ - HRESULT hr{S_OK}; - - mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - if(mNotifyEvent == nullptr) - { - ERR("Failed to create notify events: %lu\n", GetLastError()); - hr = E_FAIL; - } - - if(SUCCEEDED(hr)) - { - if(name) - { - if(PlaybackDevices.empty()) - pushMessage(MsgType::EnumeratePlayback).wait(); - - hr = E_FAIL; - auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), - [name](const DevMap &entry) -> bool - { return entry.name == name || entry.endpoint_guid == name; } - ); - if(iter == PlaybackDevices.cend()) - { - std::wstring wname{utf8_to_wstr(name)}; - iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), - [&wname](const DevMap &entry) -> bool - { return entry.devid == wname; } - ); - } - if(iter == PlaybackDevices.cend()) - WARN("Failed to find device name matching \"%s\"\n", name); - else - { - mDevId = iter->devid; - mDevice->DeviceName = iter->name; - hr = S_OK; - } - } - } - - if(SUCCEEDED(hr)) - hr = pushMessage(MsgType::OpenDevice).get(); - - if(FAILED(hr)) - { - if(mNotifyEvent != nullptr) - CloseHandle(mNotifyEvent); - mNotifyEvent = nullptr; - - mDevId.clear(); - - ERR("Device init failed: 0x%08lx\n", hr); - return ALC_INVALID_VALUE; - } - - return ALC_NO_ERROR; -} - -HRESULT WasapiPlayback::openProxy() -{ - void *ptr; - HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, &ptr)}; - if(SUCCEEDED(hr)) - { - auto Enumerator = static_cast(ptr); - if(mDevId.empty()) - hr = Enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &mMMDev); - else - hr = Enumerator->GetDevice(mDevId.c_str(), &mMMDev); - Enumerator->Release(); - } - if(SUCCEEDED(hr)) - hr = mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); - if(SUCCEEDED(hr)) - { - mClient = static_cast(ptr); - if(mDevice->DeviceName.empty()) - mDevice->DeviceName = get_device_name_and_guid(mMMDev).first; - } - - if(FAILED(hr)) - { - if(mMMDev) - mMMDev->Release(); - mMMDev = nullptr; - } - - return hr; -} - -void WasapiPlayback::closeProxy() -{ - if(mClient) - mClient->Release(); - mClient = nullptr; - - if(mMMDev) - mMMDev->Release(); - mMMDev = nullptr; -} - - -ALCboolean WasapiPlayback::reset() -{ - HRESULT hr{pushMessage(MsgType::ResetDevice).get()}; - return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; -} - -HRESULT WasapiPlayback::resetProxy() -{ - if(mClient) - mClient->Release(); - mClient = nullptr; - - void *ptr; - HRESULT hr = mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); - if(FAILED(hr)) - { - ERR("Failed to reactivate audio client: 0x%08lx\n", hr); - return hr; - } - mClient = static_cast(ptr); - - WAVEFORMATEX *wfx; - hr = mClient->GetMixFormat(&wfx); - if(FAILED(hr)) - { - ERR("Failed to get mix format: 0x%08lx\n", hr); - return hr; - } - - WAVEFORMATEXTENSIBLE OutputType; - if(!MakeExtensible(&OutputType, wfx)) - { - CoTaskMemFree(wfx); - return E_FAIL; - } - CoTaskMemFree(wfx); - wfx = nullptr; - - const REFERENCE_TIME per_time{mDevice->UpdateSize * REFTIME_PER_SEC / mDevice->Frequency}; - const REFERENCE_TIME buf_time{mDevice->BufferSize * REFTIME_PER_SEC / mDevice->Frequency}; - - if(!mDevice->Flags.get()) - mDevice->Frequency = OutputType.Format.nSamplesPerSec; - if(!mDevice->Flags.get()) - { - if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) - mDevice->FmtChans = DevFmtMono; - else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO) - mDevice->FmtChans = DevFmtStereo; - else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD) - mDevice->FmtChans = DevFmtQuad; - else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1) - mDevice->FmtChans = DevFmtX51; - else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR) - mDevice->FmtChans = DevFmtX51Rear; - else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1) - mDevice->FmtChans = DevFmtX61; - else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE)) - mDevice->FmtChans = DevFmtX71; - else - ERR("Unhandled channel config: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask); - } - - OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - switch(mDevice->FmtChans) - { - case DevFmtMono: - OutputType.Format.nChannels = 1; - OutputType.dwChannelMask = MONO; - break; - case DevFmtAmbi3D: - mDevice->FmtChans = DevFmtStereo; - /*fall-through*/ - case DevFmtStereo: - OutputType.Format.nChannels = 2; - OutputType.dwChannelMask = STEREO; - break; - case DevFmtQuad: - OutputType.Format.nChannels = 4; - OutputType.dwChannelMask = QUAD; - break; - case DevFmtX51: - OutputType.Format.nChannels = 6; - OutputType.dwChannelMask = X5DOT1; - break; - case DevFmtX51Rear: - OutputType.Format.nChannels = 6; - OutputType.dwChannelMask = X5DOT1REAR; - break; - case DevFmtX61: - OutputType.Format.nChannels = 7; - OutputType.dwChannelMask = X6DOT1; - break; - case DevFmtX71: - OutputType.Format.nChannels = 8; - OutputType.dwChannelMask = X7DOT1; - break; - } - switch(mDevice->FmtType) - { - case DevFmtByte: - mDevice->FmtType = DevFmtUByte; - /* fall-through */ - case DevFmtUByte: - OutputType.Format.wBitsPerSample = 8; - OutputType.Samples.wValidBitsPerSample = 8; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - break; - case DevFmtUShort: - mDevice->FmtType = DevFmtShort; - /* fall-through */ - case DevFmtShort: - OutputType.Format.wBitsPerSample = 16; - OutputType.Samples.wValidBitsPerSample = 16; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - break; - case DevFmtUInt: - mDevice->FmtType = DevFmtInt; - /* fall-through */ - case DevFmtInt: - OutputType.Format.wBitsPerSample = 32; - OutputType.Samples.wValidBitsPerSample = 32; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - break; - case DevFmtFloat: - OutputType.Format.wBitsPerSample = 32; - OutputType.Samples.wValidBitsPerSample = 32; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - break; - } - OutputType.Format.nSamplesPerSec = mDevice->Frequency; - - OutputType.Format.nBlockAlign = OutputType.Format.nChannels * - OutputType.Format.wBitsPerSample / 8; - OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * - OutputType.Format.nBlockAlign; - - TraceFormat("Requesting playback format", &OutputType.Format); - hr = mClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); - if(FAILED(hr)) - { - ERR("Failed to check format support: 0x%08lx\n", hr); - hr = mClient->GetMixFormat(&wfx); - } - if(FAILED(hr)) - { - ERR("Failed to find a supported format: 0x%08lx\n", hr); - return hr; - } - - if(wfx != nullptr) - { - TraceFormat("Got playback format", wfx); - if(!MakeExtensible(&OutputType, wfx)) - { - CoTaskMemFree(wfx); - return E_FAIL; - } - CoTaskMemFree(wfx); - wfx = nullptr; - - mDevice->Frequency = OutputType.Format.nSamplesPerSec; - if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) - mDevice->FmtChans = DevFmtMono; - else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO) - mDevice->FmtChans = DevFmtStereo; - else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD) - mDevice->FmtChans = DevFmtQuad; - else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1) - mDevice->FmtChans = DevFmtX51; - else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR) - mDevice->FmtChans = DevFmtX51Rear; - else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1) - mDevice->FmtChans = DevFmtX61; - else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE)) - mDevice->FmtChans = DevFmtX71; - else - { - ERR("Unhandled extensible channels: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask); - mDevice->FmtChans = DevFmtStereo; - OutputType.Format.nChannels = 2; - OutputType.dwChannelMask = STEREO; - } - - if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_PCM)) - { - if(OutputType.Format.wBitsPerSample == 8) - mDevice->FmtType = DevFmtUByte; - else if(OutputType.Format.wBitsPerSample == 16) - mDevice->FmtType = DevFmtShort; - else if(OutputType.Format.wBitsPerSample == 32) - mDevice->FmtType = DevFmtInt; - else - { - mDevice->FmtType = DevFmtShort; - OutputType.Format.wBitsPerSample = 16; - } - } - else if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) - { - mDevice->FmtType = DevFmtFloat; - OutputType.Format.wBitsPerSample = 32; - } - else - { - ERR("Unhandled format sub-type\n"); - mDevice->FmtType = DevFmtShort; - if(OutputType.Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE) - OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; - OutputType.Format.wBitsPerSample = 16; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - } - OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; - } - - EndpointFormFactor formfactor = UnknownFormFactor; - get_device_formfactor(mMMDev, &formfactor); - mDevice->IsHeadphones = (mDevice->FmtChans == DevFmtStereo && - (formfactor == Headphones || formfactor == Headset)); - - SetDefaultWFXChannelOrder(mDevice); - - hr = mClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, buf_time, - 0, &OutputType.Format, nullptr); - if(FAILED(hr)) - { - ERR("Failed to initialize audio client: 0x%08lx\n", hr); - return hr; - } - - UINT32 buffer_len, min_len; - REFERENCE_TIME min_per; - hr = mClient->GetDevicePeriod(&min_per, nullptr); - if(SUCCEEDED(hr)) - hr = mClient->GetBufferSize(&buffer_len); - if(FAILED(hr)) - { - ERR("Failed to get audio buffer info: 0x%08lx\n", hr); - return hr; - } - - /* Find the nearest multiple of the period size to the update size */ - if(min_per < per_time) - min_per *= maxi64((per_time + min_per/2) / min_per, 1); - min_len = (UINT32)ScaleCeil(min_per, mDevice->Frequency, REFTIME_PER_SEC); - min_len = minu(min_len, buffer_len/2); - - mDevice->UpdateSize = min_len; - mDevice->BufferSize = buffer_len; - - hr = mClient->SetEventHandle(mNotifyEvent); - if(FAILED(hr)) - { - ERR("Failed to set event handle: 0x%08lx\n", hr); - return hr; - } - - return hr; -} - - -ALCboolean WasapiPlayback::start() -{ - HRESULT hr{pushMessage(MsgType::StartDevice).get()}; - return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; -} - -HRESULT WasapiPlayback::startProxy() -{ - ResetEvent(mNotifyEvent); - - HRESULT hr = mClient->Start(); - if(FAILED(hr)) - { - ERR("Failed to start audio client: 0x%08lx\n", hr); - return hr; - } - - void *ptr; - hr = mClient->GetService(IID_IAudioRenderClient, &ptr); - if(SUCCEEDED(hr)) - { - mRender = static_cast(ptr); - try { - mKillNow.store(false, std::memory_order_release); - mThread = std::thread{std::mem_fn(&WasapiPlayback::mixerProc), this}; - } - catch(...) { - mRender->Release(); - mRender = nullptr; - ERR("Failed to start thread\n"); - hr = E_FAIL; - } - } - - if(FAILED(hr)) - mClient->Stop(); - - return hr; -} - - -void WasapiPlayback::stop() -{ pushMessage(MsgType::StopDevice).wait(); } - -void WasapiPlayback::stopProxy() -{ - if(!mRender || !mThread.joinable()) - return; - - mKillNow.store(true, std::memory_order_release); - mThread.join(); - - mRender->Release(); - mRender = nullptr; - mClient->Stop(); -} - - -ClockLatency WasapiPlayback::getClockLatency() -{ - ClockLatency ret; - - lock(); - ret.ClockTime = GetDeviceClockTime(mDevice); - ret.Latency = std::chrono::seconds{mPadding.load(std::memory_order_relaxed)}; - ret.Latency /= mDevice->Frequency; - unlock(); - - return ret; -} - - -struct WasapiCapture final : public BackendBase, WasapiProxy { - WasapiCapture(ALCdevice *device) noexcept : BackendBase{device} { } - ~WasapiCapture() override; - - int recordProc(); - - ALCenum open(const ALCchar *name) override; - HRESULT openProxy() override; - void closeProxy() override; - - HRESULT resetProxy() override; - ALCboolean start() override; - HRESULT startProxy() override; - void stop() override; - void stopProxy() override; - - ALCenum captureSamples(void *buffer, ALCuint samples) override; - ALCuint availableSamples() override; - - std::wstring mDevId; - - IMMDevice *mMMDev{nullptr}; - IAudioClient *mClient{nullptr}; - IAudioCaptureClient *mCapture{nullptr}; - HANDLE mNotifyEvent{nullptr}; - - ChannelConverterPtr mChannelConv; - SampleConverterPtr mSampleConv; - RingBufferPtr mRing; - - std::atomic mKillNow{true}; - std::thread mThread; - - DEF_NEWDEL(WasapiCapture) -}; - -WasapiCapture::~WasapiCapture() -{ - pushMessage(MsgType::CloseDevice).wait(); - - if(mNotifyEvent != nullptr) - CloseHandle(mNotifyEvent); - mNotifyEvent = nullptr; -} - - -FORCE_ALIGN int WasapiCapture::recordProc() -{ - HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); - if(FAILED(hr)) - { - ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); - aluHandleDisconnect(mDevice, "COM init failed: 0x%08lx", hr); - return 1; - } - - althrd_setname(RECORD_THREAD_NAME); - - al::vector samples; - while(!mKillNow.load(std::memory_order_relaxed)) - { - UINT32 avail; - hr = mCapture->GetNextPacketSize(&avail); - if(FAILED(hr)) - ERR("Failed to get next packet size: 0x%08lx\n", hr); - else if(avail > 0) - { - UINT32 numsamples; - DWORD flags; - BYTE *rdata; - - hr = mCapture->GetBuffer(&rdata, &numsamples, &flags, nullptr, nullptr); - if(FAILED(hr)) - ERR("Failed to get capture buffer: 0x%08lx\n", hr); - else - { - if(mChannelConv) - { - samples.resize(numsamples*2); - mChannelConv->convert(rdata, samples.data(), numsamples); - rdata = reinterpret_cast(samples.data()); - } - - auto data = mRing->getWriteVector(); - - size_t dstframes; - if(mSampleConv) - { - const ALvoid *srcdata{rdata}; - auto srcframes = static_cast(numsamples); - - dstframes = mSampleConv->convert(&srcdata, &srcframes, data.first.buf, - static_cast(minz(data.first.len, INT_MAX))); - if(srcframes > 0 && dstframes == data.first.len && data.second.len > 0) - { - /* If some source samples remain, all of the first dest - * block was filled, and there's space in the second - * dest block, do another run for the second block. - */ - dstframes += mSampleConv->convert(&srcdata, &srcframes, data.second.buf, - static_cast(minz(data.second.len, INT_MAX))); - } - } - else - { - const auto framesize = static_cast(mDevice->frameSizeFromFmt()); - size_t len1 = minz(data.first.len, numsamples); - size_t len2 = minz(data.second.len, numsamples-len1); - - memcpy(data.first.buf, rdata, len1*framesize); - if(len2 > 0) - memcpy(data.second.buf, rdata+len1*framesize, len2*framesize); - dstframes = len1 + len2; - } - - mRing->writeAdvance(dstframes); - - hr = mCapture->ReleaseBuffer(numsamples); - if(FAILED(hr)) ERR("Failed to release capture buffer: 0x%08lx\n", hr); - } - } - - if(FAILED(hr)) - { - aluHandleDisconnect(mDevice, "Failed to capture samples: 0x%08lx", hr); - break; - } - - DWORD res{WaitForSingleObjectEx(mNotifyEvent, 2000, FALSE)}; - if(res != WAIT_OBJECT_0) - ERR("WaitForSingleObjectEx error: 0x%lx\n", res); - } - - CoUninitialize(); - return 0; -} - - -ALCenum WasapiCapture::open(const ALCchar *name) -{ - HRESULT hr{S_OK}; - - mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); - if(mNotifyEvent == nullptr) - { - ERR("Failed to create notify event: %lu\n", GetLastError()); - hr = E_FAIL; - } - - if(SUCCEEDED(hr)) - { - if(name) - { - if(CaptureDevices.empty()) - pushMessage(MsgType::EnumerateCapture).wait(); - - hr = E_FAIL; - auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), - [name](const DevMap &entry) -> bool - { return entry.name == name || entry.endpoint_guid == name; } - ); - if(iter == CaptureDevices.cend()) - { - std::wstring wname{utf8_to_wstr(name)}; - iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), - [&wname](const DevMap &entry) -> bool - { return entry.devid == wname; } - ); - } - if(iter == CaptureDevices.cend()) - WARN("Failed to find device name matching \"%s\"\n", name); - else - { - mDevId = iter->devid; - mDevice->DeviceName = iter->name; - hr = S_OK; - } - } - } - - if(SUCCEEDED(hr)) - hr = pushMessage(MsgType::OpenDevice).get(); - - if(FAILED(hr)) - { - if(mNotifyEvent != nullptr) - CloseHandle(mNotifyEvent); - mNotifyEvent = nullptr; - - mDevId.clear(); - - ERR("Device init failed: 0x%08lx\n", hr); - return ALC_INVALID_VALUE; - } - - hr = pushMessage(MsgType::ResetDevice).get(); - if(FAILED(hr)) - { - if(hr == E_OUTOFMEMORY) - return ALC_OUT_OF_MEMORY; - return ALC_INVALID_VALUE; - } - - return ALC_NO_ERROR; -} - -HRESULT WasapiCapture::openProxy() -{ - void *ptr; - HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, - IID_IMMDeviceEnumerator, &ptr)}; - if(SUCCEEDED(hr)) - { - auto Enumerator = static_cast(ptr); - if(mDevId.empty()) - hr = Enumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, &mMMDev); - else - hr = Enumerator->GetDevice(mDevId.c_str(), &mMMDev); - Enumerator->Release(); - } - if(SUCCEEDED(hr)) - hr = mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); - if(SUCCEEDED(hr)) - { - mClient = static_cast(ptr); - if(mDevice->DeviceName.empty()) - mDevice->DeviceName = get_device_name_and_guid(mMMDev).first; - } - - if(FAILED(hr)) - { - if(mMMDev) - mMMDev->Release(); - mMMDev = nullptr; - } - - return hr; -} - -void WasapiCapture::closeProxy() -{ - if(mClient) - mClient->Release(); - mClient = nullptr; - - if(mMMDev) - mMMDev->Release(); - mMMDev = nullptr; -} - -HRESULT WasapiCapture::resetProxy() -{ - if(mClient) - mClient->Release(); - mClient = nullptr; - - void *ptr; - HRESULT hr{mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr)}; - if(FAILED(hr)) - { - ERR("Failed to reactivate audio client: 0x%08lx\n", hr); - return hr; - } - mClient = static_cast(ptr); - - // Make sure buffer is at least 100ms in size - REFERENCE_TIME buf_time{mDevice->BufferSize * REFTIME_PER_SEC / mDevice->Frequency}; - buf_time = maxu64(buf_time, REFTIME_PER_SEC/10); - - WAVEFORMATEXTENSIBLE OutputType; - OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - switch(mDevice->FmtChans) - { - case DevFmtMono: - OutputType.Format.nChannels = 1; - OutputType.dwChannelMask = MONO; - break; - case DevFmtStereo: - OutputType.Format.nChannels = 2; - OutputType.dwChannelMask = STEREO; - break; - case DevFmtQuad: - OutputType.Format.nChannels = 4; - OutputType.dwChannelMask = QUAD; - break; - case DevFmtX51: - OutputType.Format.nChannels = 6; - OutputType.dwChannelMask = X5DOT1; - break; - case DevFmtX51Rear: - OutputType.Format.nChannels = 6; - OutputType.dwChannelMask = X5DOT1REAR; - break; - case DevFmtX61: - OutputType.Format.nChannels = 7; - OutputType.dwChannelMask = X6DOT1; - break; - case DevFmtX71: - OutputType.Format.nChannels = 8; - OutputType.dwChannelMask = X7DOT1; - break; - - case DevFmtAmbi3D: - return E_FAIL; - } - switch(mDevice->FmtType) - { - /* NOTE: Signedness doesn't matter, the converter will handle it. */ - case DevFmtByte: - case DevFmtUByte: - OutputType.Format.wBitsPerSample = 8; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - break; - case DevFmtShort: - case DevFmtUShort: - OutputType.Format.wBitsPerSample = 16; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - break; - case DevFmtInt: - case DevFmtUInt: - OutputType.Format.wBitsPerSample = 32; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - break; - case DevFmtFloat: - OutputType.Format.wBitsPerSample = 32; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - break; - } - OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; - OutputType.Format.nSamplesPerSec = mDevice->Frequency; - - OutputType.Format.nBlockAlign = OutputType.Format.nChannels * - OutputType.Format.wBitsPerSample / 8; - OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * - OutputType.Format.nBlockAlign; - OutputType.Format.cbSize = sizeof(OutputType) - sizeof(OutputType.Format); - - TraceFormat("Requesting capture format", &OutputType.Format); - WAVEFORMATEX *wfx; - hr = mClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); - if(FAILED(hr)) - { - ERR("Failed to check format support: 0x%08lx\n", hr); - return hr; - } - - mSampleConv = nullptr; - mChannelConv = nullptr; - - if(wfx != nullptr) - { - TraceFormat("Got capture format", wfx); - if(!(wfx->nChannels == OutputType.Format.nChannels || - (wfx->nChannels == 1 && OutputType.Format.nChannels == 2) || - (wfx->nChannels == 2 && OutputType.Format.nChannels == 1))) - { - ERR("Failed to get matching format, wanted: %s %s %uhz, got: %d channel%s %d-bit %luhz\n", - DevFmtChannelsString(mDevice->FmtChans), DevFmtTypeString(mDevice->FmtType), - mDevice->Frequency, wfx->nChannels, (wfx->nChannels==1)?"":"s", wfx->wBitsPerSample, - wfx->nSamplesPerSec); - CoTaskMemFree(wfx); - return E_FAIL; - } - - if(!MakeExtensible(&OutputType, wfx)) - { - CoTaskMemFree(wfx); - return E_FAIL; - } - CoTaskMemFree(wfx); - wfx = nullptr; - } - - DevFmtType srcType; - if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_PCM)) - { - if(OutputType.Format.wBitsPerSample == 8) - srcType = DevFmtUByte; - else if(OutputType.Format.wBitsPerSample == 16) - srcType = DevFmtShort; - else if(OutputType.Format.wBitsPerSample == 32) - srcType = DevFmtInt; - else - { - ERR("Unhandled integer bit depth: %d\n", OutputType.Format.wBitsPerSample); - return E_FAIL; - } - } - else if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) - { - if(OutputType.Format.wBitsPerSample == 32) - srcType = DevFmtFloat; - else - { - ERR("Unhandled float bit depth: %d\n", OutputType.Format.wBitsPerSample); - return E_FAIL; - } - } - else - { - ERR("Unhandled format sub-type\n"); - return E_FAIL; - } - - if(mDevice->FmtChans == DevFmtMono && OutputType.Format.nChannels == 2) - { - mChannelConv = CreateChannelConverter(srcType, DevFmtStereo, mDevice->FmtChans); - if(!mChannelConv) - { - ERR("Failed to create %s stereo-to-mono converter\n", DevFmtTypeString(srcType)); - return E_FAIL; - } - TRACE("Created %s stereo-to-mono converter\n", DevFmtTypeString(srcType)); - /* The channel converter always outputs float, so change the input type - * for the resampler/type-converter. - */ - srcType = DevFmtFloat; - } - else if(mDevice->FmtChans == DevFmtStereo && OutputType.Format.nChannels == 1) - { - mChannelConv = CreateChannelConverter(srcType, DevFmtMono, mDevice->FmtChans); - if(!mChannelConv) - { - ERR("Failed to create %s mono-to-stereo converter\n", DevFmtTypeString(srcType)); - return E_FAIL; - } - TRACE("Created %s mono-to-stereo converter\n", DevFmtTypeString(srcType)); - srcType = DevFmtFloat; - } - - if(mDevice->Frequency != OutputType.Format.nSamplesPerSec || mDevice->FmtType != srcType) - { - mSampleConv = CreateSampleConverter(srcType, mDevice->FmtType, mDevice->channelsFromFmt(), - OutputType.Format.nSamplesPerSec, mDevice->Frequency, BSinc24Resampler); - if(!mSampleConv) - { - ERR("Failed to create converter for %s format, dst: %s %uhz, src: %s %luhz\n", - DevFmtChannelsString(mDevice->FmtChans), DevFmtTypeString(mDevice->FmtType), - mDevice->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec); - return E_FAIL; - } - TRACE("Created converter for %s format, dst: %s %uhz, src: %s %luhz\n", - DevFmtChannelsString(mDevice->FmtChans), DevFmtTypeString(mDevice->FmtType), - mDevice->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec); - } - - hr = mClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, buf_time, - 0, &OutputType.Format, nullptr); - if(FAILED(hr)) - { - ERR("Failed to initialize audio client: 0x%08lx\n", hr); - return hr; - } - - UINT32 buffer_len; - REFERENCE_TIME min_per; - hr = mClient->GetDevicePeriod(&min_per, nullptr); - if(SUCCEEDED(hr)) - hr = mClient->GetBufferSize(&buffer_len); - if(FAILED(hr)) - { - ERR("Failed to get buffer size: 0x%08lx\n", hr); - return hr; - } - mDevice->UpdateSize = static_cast(ScaleCeil(min_per, mDevice->Frequency, - REFTIME_PER_SEC)); - mDevice->BufferSize = buffer_len; - - buffer_len = maxu(mDevice->BufferSize, buffer_len); - mRing = CreateRingBuffer(buffer_len, mDevice->frameSizeFromFmt(), false); - if(!mRing) - { - ERR("Failed to allocate capture ring buffer\n"); - return E_OUTOFMEMORY; - } - - hr = mClient->SetEventHandle(mNotifyEvent); - if(FAILED(hr)) - { - ERR("Failed to set event handle: 0x%08lx\n", hr); - return hr; - } - - return hr; -} - - -ALCboolean WasapiCapture::start() -{ - HRESULT hr{pushMessage(MsgType::StartDevice).get()}; - return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; -} - -HRESULT WasapiCapture::startProxy() -{ - ResetEvent(mNotifyEvent); - - HRESULT hr{mClient->Start()}; - if(FAILED(hr)) - { - ERR("Failed to start audio client: 0x%08lx\n", hr); - return hr; - } - - void *ptr; - hr = mClient->GetService(IID_IAudioCaptureClient, &ptr); - if(SUCCEEDED(hr)) - { - mCapture = static_cast(ptr); - try { - mKillNow.store(false, std::memory_order_release); - mThread = std::thread{std::mem_fn(&WasapiCapture::recordProc), this}; - } - catch(...) { - mCapture->Release(); - mCapture = nullptr; - ERR("Failed to start thread\n"); - hr = E_FAIL; - } - } - - if(FAILED(hr)) - { - mClient->Stop(); - mClient->Reset(); - } - - return hr; -} - - -void WasapiCapture::stop() -{ pushMessage(MsgType::StopDevice).wait(); } - -void WasapiCapture::stopProxy() -{ - if(!mCapture || !mThread.joinable()) - return; - - mKillNow.store(true, std::memory_order_release); - mThread.join(); - - mCapture->Release(); - mCapture = nullptr; - mClient->Stop(); - mClient->Reset(); -} - - -ALCuint WasapiCapture::availableSamples() -{ return (ALCuint)mRing->readSpace(); } - -ALCenum WasapiCapture::captureSamples(void *buffer, ALCuint samples) -{ - mRing->read(buffer, samples); - return ALC_NO_ERROR; -} - -} // namespace - - -bool WasapiBackendFactory::init() -{ - static HRESULT InitResult{E_FAIL}; - - if(FAILED(InitResult)) try - { - std::promise promise; - auto future = promise.get_future(); - - std::thread{&WasapiProxy::messageHandler, &promise}.detach(); - InitResult = future.get(); - } - catch(...) { - } - - return SUCCEEDED(InitResult) ? ALC_TRUE : ALC_FALSE; -} - -bool WasapiBackendFactory::querySupport(BackendType type) -{ return type == BackendType::Playback || type == BackendType::Capture; } - -void WasapiBackendFactory::probe(DevProbe type, std::string *outnames) -{ - auto add_device = [outnames](const DevMap &entry) -> void - { - /* +1 to also append the null char (to ensure a null-separated list and - * double-null terminated list). - */ - outnames->append(entry.name.c_str(), entry.name.length()+1); - }; - HRESULT hr{}; - switch(type) - { - case DevProbe::Playback: - hr = WasapiProxy::pushMessageStatic(MsgType::EnumeratePlayback).get(); - if(SUCCEEDED(hr)) - std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); - break; - - case DevProbe::Capture: - hr = WasapiProxy::pushMessageStatic(MsgType::EnumerateCapture).get(); - if(SUCCEEDED(hr)) - std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); - break; - } -} - -BackendPtr WasapiBackendFactory::createBackend(ALCdevice *device, BackendType type) -{ - if(type == BackendType::Playback) - return BackendPtr{new WasapiPlayback{device}}; - if(type == BackendType::Capture) - return BackendPtr{new WasapiCapture{device}}; - return nullptr; -} - -BackendFactory &WasapiBackendFactory::getFactory() -{ - static WasapiBackendFactory factory{}; - return factory; -} diff --git a/Alc/backends/wasapi.h b/Alc/backends/wasapi.h deleted file mode 100644 index 067dd259..00000000 --- a/Alc/backends/wasapi.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef BACKENDS_WASAPI_H -#define BACKENDS_WASAPI_H - -#include "backends/base.h" - -struct WasapiBackendFactory final : public BackendFactory { -public: - bool init() override; - - bool querySupport(BackendType type) override; - - void probe(DevProbe type, std::string *outnames) override; - - BackendPtr createBackend(ALCdevice *device, BackendType type) override; - - static BackendFactory &getFactory(); -}; - -#endif /* BACKENDS_WASAPI_H */ diff --git a/Alc/backends/wave.cpp b/Alc/backends/wave.cpp deleted file mode 100644 index 67ed7e79..00000000 --- a/Alc/backends/wave.cpp +++ /dev/null @@ -1,402 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "backends/wave.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" - -#include "alcmain.h" -#include "alconfig.h" -#include "almalloc.h" -#include "alnumeric.h" -#include "alu.h" -#include "compat.h" -#include "logging.h" -#include "threads.h" -#include "vector.h" - - -namespace { - -using std::chrono::seconds; -using std::chrono::milliseconds; -using std::chrono::nanoseconds; - -constexpr ALCchar waveDevice[] = "Wave File Writer"; - -constexpr ALubyte SUBTYPE_PCM[]{ - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, - 0x00, 0x38, 0x9b, 0x71 -}; -constexpr ALubyte SUBTYPE_FLOAT[]{ - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, - 0x00, 0x38, 0x9b, 0x71 -}; - -constexpr ALubyte SUBTYPE_BFORMAT_PCM[]{ - 0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1, - 0xca, 0x00, 0x00, 0x00 -}; - -constexpr ALubyte SUBTYPE_BFORMAT_FLOAT[]{ - 0x03, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1, - 0xca, 0x00, 0x00, 0x00 -}; - -void fwrite16le(ALushort val, FILE *f) -{ - ALubyte data[2]{ static_cast(val&0xff), static_cast((val>>8)&0xff) }; - fwrite(data, 1, 2, f); -} - -void fwrite32le(ALuint val, FILE *f) -{ - ALubyte data[4]{ static_cast(val&0xff), static_cast((val>>8)&0xff), - static_cast((val>>16)&0xff), static_cast((val>>24)&0xff) }; - fwrite(data, 1, 4, f); -} - - -struct WaveBackend final : public BackendBase { - WaveBackend(ALCdevice *device) noexcept : BackendBase{device} { } - ~WaveBackend() override; - - int mixerProc(); - - ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; - void stop() override; - - FILE *mFile{nullptr}; - long mDataStart{-1}; - - al::vector mBuffer; - - std::atomic mKillNow{true}; - std::thread mThread; - - DEF_NEWDEL(WaveBackend) -}; - -WaveBackend::~WaveBackend() -{ - if(mFile) - fclose(mFile); - mFile = nullptr; -} - -int WaveBackend::mixerProc() -{ - const milliseconds restTime{mDevice->UpdateSize*1000/mDevice->Frequency / 2}; - - althrd_setname(MIXER_THREAD_NAME); - - const ALsizei frameSize{mDevice->frameSizeFromFmt()}; - - int64_t done{0}; - auto start = std::chrono::steady_clock::now(); - while(!mKillNow.load(std::memory_order_acquire) && - mDevice->Connected.load(std::memory_order_acquire)) - { - auto now = std::chrono::steady_clock::now(); - - /* This converts from nanoseconds to nanosamples, then to samples. */ - int64_t avail{std::chrono::duration_cast((now-start) * - mDevice->Frequency).count()}; - if(avail-done < mDevice->UpdateSize) - { - std::this_thread::sleep_for(restTime); - continue; - } - while(avail-done >= mDevice->UpdateSize) - { - lock(); - aluMixData(mDevice, mBuffer.data(), mDevice->UpdateSize); - unlock(); - done += mDevice->UpdateSize; - - if(!IS_LITTLE_ENDIAN) - { - const ALsizei bytesize{mDevice->bytesFromFmt()}; - ALsizei i; - - if(bytesize == 2) - { - ALushort *samples = reinterpret_cast(mBuffer.data()); - const auto len = static_cast(mBuffer.size() / 2); - for(i = 0;i < len;i++) - { - ALushort samp = samples[i]; - samples[i] = (samp>>8) | (samp<<8); - } - } - else if(bytesize == 4) - { - ALuint *samples = reinterpret_cast(mBuffer.data()); - const auto len = static_cast(mBuffer.size() / 4); - for(i = 0;i < len;i++) - { - ALuint samp = samples[i]; - samples[i] = (samp>>24) | ((samp>>8)&0x0000ff00) | - ((samp<<8)&0x00ff0000) | (samp<<24); - } - } - } - - size_t fs{fwrite(mBuffer.data(), frameSize, mDevice->UpdateSize, mFile)}; - (void)fs; - if(ferror(mFile)) - { - ERR("Error writing to file\n"); - aluHandleDisconnect(mDevice, "Failed to write playback samples"); - break; - } - } - - /* For every completed second, increment the start time and reduce the - * samples done. This prevents the difference between the start time - * and current time from growing too large, while maintaining the - * correct number of samples to render. - */ - if(done >= mDevice->Frequency) - { - seconds s{done/mDevice->Frequency}; - start += s; - done -= mDevice->Frequency*s.count(); - } - } - - return 0; -} - -ALCenum WaveBackend::open(const ALCchar *name) -{ - const char *fname{GetConfigValue(nullptr, "wave", "file", "")}; - if(!fname[0]) return ALC_INVALID_VALUE; - - if(!name) - name = waveDevice; - else if(strcmp(name, waveDevice) != 0) - return ALC_INVALID_VALUE; - -#ifdef _WIN32 - { - std::wstring wname = utf8_to_wstr(fname); - mFile = _wfopen(wname.c_str(), L"wb"); - } -#else - mFile = fopen(fname, "wb"); -#endif - if(!mFile) - { - ERR("Could not open file '%s': %s\n", fname, strerror(errno)); - return ALC_INVALID_VALUE; - } - - mDevice->DeviceName = name; - - return ALC_NO_ERROR; -} - -ALCboolean WaveBackend::reset() -{ - ALuint channels=0, bytes=0, chanmask=0; - int isbformat = 0; - size_t val; - - fseek(mFile, 0, SEEK_SET); - clearerr(mFile); - - if(GetConfigValueBool(nullptr, "wave", "bformat", 0)) - { - mDevice->FmtChans = DevFmtAmbi3D; - mDevice->mAmbiOrder = 1; - } - - switch(mDevice->FmtType) - { - case DevFmtByte: - mDevice->FmtType = DevFmtUByte; - break; - case DevFmtUShort: - mDevice->FmtType = DevFmtShort; - break; - case DevFmtUInt: - mDevice->FmtType = DevFmtInt; - break; - case DevFmtUByte: - case DevFmtShort: - case DevFmtInt: - case DevFmtFloat: - break; - } - switch(mDevice->FmtChans) - { - case DevFmtMono: chanmask = 0x04; break; - case DevFmtStereo: chanmask = 0x01 | 0x02; break; - case DevFmtQuad: chanmask = 0x01 | 0x02 | 0x10 | 0x20; break; - case DevFmtX51: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x200 | 0x400; break; - case DevFmtX51Rear: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020; break; - case DevFmtX61: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400; break; - case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break; - case DevFmtAmbi3D: - /* .amb output requires FuMa */ - mDevice->mAmbiOrder = mini(mDevice->mAmbiOrder, 3); - mDevice->mAmbiLayout = AmbiLayout::FuMa; - mDevice->mAmbiScale = AmbiNorm::FuMa; - isbformat = 1; - chanmask = 0; - break; - } - bytes = mDevice->bytesFromFmt(); - channels = mDevice->channelsFromFmt(); - - rewind(mFile); - - fputs("RIFF", mFile); - fwrite32le(0xFFFFFFFF, mFile); // 'RIFF' header len; filled in at close - - fputs("WAVE", mFile); - - fputs("fmt ", mFile); - fwrite32le(40, mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE - - // 16-bit val, format type id (extensible: 0xFFFE) - fwrite16le(0xFFFE, mFile); - // 16-bit val, channel count - fwrite16le(channels, mFile); - // 32-bit val, frequency - fwrite32le(mDevice->Frequency, mFile); - // 32-bit val, bytes per second - fwrite32le(mDevice->Frequency * channels * bytes, mFile); - // 16-bit val, frame size - fwrite16le(channels * bytes, mFile); - // 16-bit val, bits per sample - fwrite16le(bytes * 8, mFile); - // 16-bit val, extra byte count - fwrite16le(22, mFile); - // 16-bit val, valid bits per sample - fwrite16le(bytes * 8, mFile); - // 32-bit val, channel mask - fwrite32le(chanmask, mFile); - // 16 byte GUID, sub-type format - val = fwrite((mDevice->FmtType == DevFmtFloat) ? - (isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) : - (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM), 1, 16, mFile); - (void)val; - - fputs("data", mFile); - fwrite32le(0xFFFFFFFF, mFile); // 'data' header len; filled in at close - - if(ferror(mFile)) - { - ERR("Error writing header: %s\n", strerror(errno)); - return ALC_FALSE; - } - mDataStart = ftell(mFile); - - SetDefaultWFXChannelOrder(mDevice); - - const ALuint bufsize{mDevice->frameSizeFromFmt() * mDevice->UpdateSize}; - mBuffer.resize(bufsize); - - return ALC_TRUE; -} - -ALCboolean WaveBackend::start() -{ - try { - mKillNow.store(false, std::memory_order_release); - mThread = std::thread{std::mem_fn(&WaveBackend::mixerProc), this}; - return ALC_TRUE; - } - catch(std::exception& e) { - ERR("Failed to start mixing thread: %s\n", e.what()); - } - catch(...) { - } - return ALC_FALSE; -} - -void WaveBackend::stop() -{ - if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) - return; - mThread.join(); - - long size{ftell(mFile)}; - if(size > 0) - { - long dataLen{size - mDataStart}; - if(fseek(mFile, mDataStart-4, SEEK_SET) == 0) - fwrite32le(dataLen, mFile); // 'data' header len - if(fseek(mFile, 4, SEEK_SET) == 0) - fwrite32le(size-8, mFile); // 'WAVE' header len - } -} - -} // namespace - - -bool WaveBackendFactory::init() -{ return true; } - -bool WaveBackendFactory::querySupport(BackendType type) -{ return type == BackendType::Playback; } - -void WaveBackendFactory::probe(DevProbe type, std::string *outnames) -{ - switch(type) - { - case DevProbe::Playback: - /* Includes null char. */ - outnames->append(waveDevice, sizeof(waveDevice)); - break; - case DevProbe::Capture: - break; - } -} - -BackendPtr WaveBackendFactory::createBackend(ALCdevice *device, BackendType type) -{ - if(type == BackendType::Playback) - return BackendPtr{new WaveBackend{device}}; - return nullptr; -} - -BackendFactory &WaveBackendFactory::getFactory() -{ - static WaveBackendFactory factory{}; - return factory; -} diff --git a/Alc/backends/wave.h b/Alc/backends/wave.h deleted file mode 100644 index b9b62d7f..00000000 --- a/Alc/backends/wave.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef BACKENDS_WAVE_H -#define BACKENDS_WAVE_H - -#include "backends/base.h" - -struct WaveBackendFactory final : public BackendFactory { -public: - bool init() override; - - bool querySupport(BackendType type) override; - - void probe(DevProbe type, std::string *outnames) override; - - BackendPtr createBackend(ALCdevice *device, BackendType type) override; - - static BackendFactory &getFactory(); -}; - -#endif /* BACKENDS_WAVE_H */ diff --git a/Alc/backends/winmm.cpp b/Alc/backends/winmm.cpp deleted file mode 100644 index cd32e95b..00000000 --- a/Alc/backends/winmm.cpp +++ /dev/null @@ -1,640 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "backends/winmm.h" - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "alcmain.h" -#include "alu.h" -#include "ringbuffer.h" -#include "threads.h" -#include "compat.h" - -#ifndef WAVE_FORMAT_IEEE_FLOAT -#define WAVE_FORMAT_IEEE_FLOAT 0x0003 -#endif - -namespace { - -#define DEVNAME_HEAD "OpenAL Soft on " - - -al::vector PlaybackDevices; -al::vector CaptureDevices; - -bool checkName(const al::vector &list, const std::string &name) -{ return std::find(list.cbegin(), list.cend(), name) != list.cend(); } - -void ProbePlaybackDevices(void) -{ - PlaybackDevices.clear(); - - ALuint numdevs{waveOutGetNumDevs()}; - PlaybackDevices.reserve(numdevs); - for(ALuint i{0};i < numdevs;i++) - { - std::string dname; - - WAVEOUTCAPSW WaveCaps{}; - if(waveOutGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR) - { - const std::string basename{DEVNAME_HEAD + wstr_to_utf8(WaveCaps.szPname)}; - - int count{1}; - std::string newname{basename}; - while(checkName(PlaybackDevices, newname)) - { - newname = basename; - newname += " #"; - newname += std::to_string(++count); - } - dname = std::move(newname); - - TRACE("Got device \"%s\", ID %u\n", dname.c_str(), i); - } - PlaybackDevices.emplace_back(std::move(dname)); - } -} - -void ProbeCaptureDevices(void) -{ - CaptureDevices.clear(); - - ALuint numdevs{waveInGetNumDevs()}; - CaptureDevices.reserve(numdevs); - for(ALuint i{0};i < numdevs;i++) - { - std::string dname; - - WAVEINCAPSW WaveCaps{}; - if(waveInGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR) - { - const std::string basename{DEVNAME_HEAD + wstr_to_utf8(WaveCaps.szPname)}; - - int count{1}; - std::string newname{basename}; - while(checkName(CaptureDevices, newname)) - { - newname = basename; - newname += " #"; - newname += std::to_string(++count); - } - dname = std::move(newname); - - TRACE("Got device \"%s\", ID %u\n", dname.c_str(), i); - } - CaptureDevices.emplace_back(std::move(dname)); - } -} - - -struct WinMMPlayback final : public BackendBase { - WinMMPlayback(ALCdevice *device) noexcept : BackendBase{device} { } - ~WinMMPlayback() override; - - static void CALLBACK waveOutProcC(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); - void CALLBACK waveOutProc(HWAVEOUT device, UINT msg, DWORD_PTR param1, DWORD_PTR param2); - - int mixerProc(); - - ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; - void stop() override; - - std::atomic mWritable{0u}; - al::semaphore mSem; - int mIdx{0}; - std::array mWaveBuffer{}; - - HWAVEOUT mOutHdl{nullptr}; - - WAVEFORMATEX mFormat{}; - - std::atomic mKillNow{true}; - std::thread mThread; - - DEF_NEWDEL(WinMMPlayback) -}; - -WinMMPlayback::~WinMMPlayback() -{ - if(mOutHdl) - waveOutClose(mOutHdl); - mOutHdl = nullptr; - - al_free(mWaveBuffer[0].lpData); - std::fill(mWaveBuffer.begin(), mWaveBuffer.end(), WAVEHDR{}); -} - - -void CALLBACK WinMMPlayback::waveOutProcC(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2) -{ reinterpret_cast(instance)->waveOutProc(device, msg, param1, param2); } - -/* WinMMPlayback::waveOutProc - * - * Posts a message to 'WinMMPlayback::mixerProc' everytime a WaveOut Buffer is - * completed and returns to the application (for more data) - */ -void CALLBACK WinMMPlayback::waveOutProc(HWAVEOUT, UINT msg, DWORD_PTR, DWORD_PTR) -{ - if(msg != WOM_DONE) return; - mWritable.fetch_add(1, std::memory_order_acq_rel); - mSem.post(); -} - -FORCE_ALIGN int WinMMPlayback::mixerProc() -{ - SetRTPriority(); - althrd_setname(MIXER_THREAD_NAME); - - lock(); - while(!mKillNow.load(std::memory_order_acquire) && - mDevice->Connected.load(std::memory_order_acquire)) - { - ALsizei todo = mWritable.load(std::memory_order_acquire); - if(todo < 1) - { - unlock(); - mSem.wait(); - lock(); - continue; - } - - int widx{mIdx}; - do { - WAVEHDR &waveHdr = mWaveBuffer[widx]; - widx = (widx+1) % mWaveBuffer.size(); - - aluMixData(mDevice, waveHdr.lpData, mDevice->UpdateSize); - mWritable.fetch_sub(1, std::memory_order_acq_rel); - waveOutWrite(mOutHdl, &waveHdr, sizeof(WAVEHDR)); - } while(--todo); - mIdx = widx; - } - unlock(); - - return 0; -} - - -ALCenum WinMMPlayback::open(const ALCchar *name) -{ - if(PlaybackDevices.empty()) - ProbePlaybackDevices(); - - // Find the Device ID matching the deviceName if valid - auto iter = name ? - std::find(PlaybackDevices.cbegin(), PlaybackDevices.cend(), name) : - PlaybackDevices.cbegin(); - if(iter == PlaybackDevices.cend()) return ALC_INVALID_VALUE; - auto DeviceID = static_cast(std::distance(PlaybackDevices.cbegin(), iter)); - -retry_open: - mFormat = WAVEFORMATEX{}; - if(mDevice->FmtType == DevFmtFloat) - { - mFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; - mFormat.wBitsPerSample = 32; - } - else - { - mFormat.wFormatTag = WAVE_FORMAT_PCM; - if(mDevice->FmtType == DevFmtUByte || mDevice->FmtType == DevFmtByte) - mFormat.wBitsPerSample = 8; - else - mFormat.wBitsPerSample = 16; - } - mFormat.nChannels = ((mDevice->FmtChans == DevFmtMono) ? 1 : 2); - mFormat.nBlockAlign = mFormat.wBitsPerSample * mFormat.nChannels / 8; - mFormat.nSamplesPerSec = mDevice->Frequency; - mFormat.nAvgBytesPerSec = mFormat.nSamplesPerSec * mFormat.nBlockAlign; - mFormat.cbSize = 0; - - MMRESULT res{waveOutOpen(&mOutHdl, DeviceID, &mFormat, (DWORD_PTR)&WinMMPlayback::waveOutProcC, - reinterpret_cast(this), CALLBACK_FUNCTION)}; - if(res != MMSYSERR_NOERROR) - { - if(mDevice->FmtType == DevFmtFloat) - { - mDevice->FmtType = DevFmtShort; - goto retry_open; - } - ERR("waveOutOpen failed: %u\n", res); - return ALC_INVALID_VALUE; - } - - mDevice->DeviceName = PlaybackDevices[DeviceID]; - return ALC_NO_ERROR; -} - -ALCboolean WinMMPlayback::reset() -{ - mDevice->BufferSize = static_cast(uint64_t{mDevice->BufferSize} * - mFormat.nSamplesPerSec / mDevice->Frequency); - mDevice->BufferSize = (mDevice->BufferSize+3) & ~0x3; - mDevice->UpdateSize = mDevice->BufferSize / 4; - mDevice->Frequency = mFormat.nSamplesPerSec; - - if(mFormat.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) - { - if(mFormat.wBitsPerSample == 32) - mDevice->FmtType = DevFmtFloat; - else - { - ERR("Unhandled IEEE float sample depth: %d\n", mFormat.wBitsPerSample); - return ALC_FALSE; - } - } - else if(mFormat.wFormatTag == WAVE_FORMAT_PCM) - { - if(mFormat.wBitsPerSample == 16) - mDevice->FmtType = DevFmtShort; - else if(mFormat.wBitsPerSample == 8) - mDevice->FmtType = DevFmtUByte; - else - { - ERR("Unhandled PCM sample depth: %d\n", mFormat.wBitsPerSample); - return ALC_FALSE; - } - } - else - { - ERR("Unhandled format tag: 0x%04x\n", mFormat.wFormatTag); - return ALC_FALSE; - } - - if(mFormat.nChannels == 2) - mDevice->FmtChans = DevFmtStereo; - else if(mFormat.nChannels == 1) - mDevice->FmtChans = DevFmtMono; - else - { - ERR("Unhandled channel count: %d\n", mFormat.nChannels); - return ALC_FALSE; - } - SetDefaultWFXChannelOrder(mDevice); - - ALuint BufferSize{mDevice->UpdateSize * mDevice->frameSizeFromFmt()}; - - al_free(mWaveBuffer[0].lpData); - mWaveBuffer[0] = WAVEHDR{}; - mWaveBuffer[0].lpData = static_cast(al_calloc(16, BufferSize * mWaveBuffer.size())); - mWaveBuffer[0].dwBufferLength = BufferSize; - for(size_t i{1};i < mWaveBuffer.size();i++) - { - mWaveBuffer[i] = WAVEHDR{}; - mWaveBuffer[i].lpData = mWaveBuffer[i-1].lpData + mWaveBuffer[i-1].dwBufferLength; - mWaveBuffer[i].dwBufferLength = BufferSize; - } - mIdx = 0; - - return ALC_TRUE; -} - -ALCboolean WinMMPlayback::start() -{ - try { - std::for_each(mWaveBuffer.begin(), mWaveBuffer.end(), - [this](WAVEHDR &waveHdr) -> void - { waveOutPrepareHeader(mOutHdl, &waveHdr, static_cast(sizeof(WAVEHDR))); } - ); - mWritable.store(static_cast(mWaveBuffer.size()), std::memory_order_release); - - mKillNow.store(false, std::memory_order_release); - mThread = std::thread{std::mem_fn(&WinMMPlayback::mixerProc), this}; - return ALC_TRUE; - } - catch(std::exception& e) { - ERR("Failed to start mixing thread: %s\n", e.what()); - } - catch(...) { - } - return ALC_FALSE; -} - -void WinMMPlayback::stop() -{ - if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) - return; - mThread.join(); - - while(mWritable.load(std::memory_order_acquire) < mWaveBuffer.size()) - mSem.wait(); - std::for_each(mWaveBuffer.begin(), mWaveBuffer.end(), - [this](WAVEHDR &waveHdr) -> void - { waveOutUnprepareHeader(mOutHdl, &waveHdr, sizeof(WAVEHDR)); } - ); - mWritable.store(0, std::memory_order_release); -} - - -struct WinMMCapture final : public BackendBase { - WinMMCapture(ALCdevice *device) noexcept : BackendBase{device} { } - ~WinMMCapture() override; - - static void CALLBACK waveInProcC(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); - void CALLBACK waveInProc(HWAVEIN device, UINT msg, DWORD_PTR param1, DWORD_PTR param2); - - int captureProc(); - - ALCenum open(const ALCchar *name) override; - ALCboolean start() override; - void stop() override; - ALCenum captureSamples(void *buffer, ALCuint samples) override; - ALCuint availableSamples() override; - - std::atomic mReadable{0u}; - al::semaphore mSem; - int mIdx{0}; - std::array mWaveBuffer{}; - - HWAVEIN mInHdl{nullptr}; - - RingBufferPtr mRing{nullptr}; - - WAVEFORMATEX mFormat{}; - - std::atomic mKillNow{true}; - std::thread mThread; - - DEF_NEWDEL(WinMMCapture) -}; - -WinMMCapture::~WinMMCapture() -{ - // Close the Wave device - if(mInHdl) - waveInClose(mInHdl); - mInHdl = nullptr; - - al_free(mWaveBuffer[0].lpData); - std::fill(mWaveBuffer.begin(), mWaveBuffer.end(), WAVEHDR{}); -} - -void CALLBACK WinMMCapture::waveInProcC(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2) -{ reinterpret_cast(instance)->waveInProc(device, msg, param1, param2); } - -/* WinMMCapture::waveInProc - * - * Posts a message to 'WinMMCapture::captureProc' everytime a WaveIn Buffer is - * completed and returns to the application (with more data). - */ -void CALLBACK WinMMCapture::waveInProc(HWAVEIN, UINT msg, DWORD_PTR, DWORD_PTR) -{ - if(msg != WIM_DATA) return; - mReadable.fetch_add(1, std::memory_order_acq_rel); - mSem.post(); -} - -int WinMMCapture::captureProc() -{ - althrd_setname(RECORD_THREAD_NAME); - - lock(); - while(!mKillNow.load(std::memory_order_acquire) && - mDevice->Connected.load(std::memory_order_acquire)) - { - ALuint todo{mReadable.load(std::memory_order_acquire)}; - if(todo < 1) - { - unlock(); - mSem.wait(); - lock(); - continue; - } - - int widx{mIdx}; - do { - WAVEHDR &waveHdr = mWaveBuffer[widx]; - widx = (widx+1) % mWaveBuffer.size(); - - mRing->write(waveHdr.lpData, waveHdr.dwBytesRecorded / mFormat.nBlockAlign); - mReadable.fetch_sub(1, std::memory_order_acq_rel); - waveInAddBuffer(mInHdl, &waveHdr, sizeof(WAVEHDR)); - } while(--todo); - mIdx = widx; - } - unlock(); - - return 0; -} - - -ALCenum WinMMCapture::open(const ALCchar *name) -{ - if(CaptureDevices.empty()) - ProbeCaptureDevices(); - - // Find the Device ID matching the deviceName if valid - auto iter = name ? - std::find(CaptureDevices.cbegin(), CaptureDevices.cend(), name) : - CaptureDevices.cbegin(); - if(iter == CaptureDevices.cend()) return ALC_INVALID_VALUE; - auto DeviceID = static_cast(std::distance(CaptureDevices.cbegin(), iter)); - - switch(mDevice->FmtChans) - { - case DevFmtMono: - case DevFmtStereo: - break; - - case DevFmtQuad: - case DevFmtX51: - case DevFmtX51Rear: - case DevFmtX61: - case DevFmtX71: - case DevFmtAmbi3D: - return ALC_INVALID_ENUM; - } - - switch(mDevice->FmtType) - { - case DevFmtUByte: - case DevFmtShort: - case DevFmtInt: - case DevFmtFloat: - break; - - case DevFmtByte: - case DevFmtUShort: - case DevFmtUInt: - return ALC_INVALID_ENUM; - } - - mFormat = WAVEFORMATEX{}; - mFormat.wFormatTag = (mDevice->FmtType == DevFmtFloat) ? - WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM; - mFormat.nChannels = mDevice->channelsFromFmt(); - mFormat.wBitsPerSample = mDevice->bytesFromFmt() * 8; - mFormat.nBlockAlign = mFormat.wBitsPerSample * mFormat.nChannels / 8; - mFormat.nSamplesPerSec = mDevice->Frequency; - mFormat.nAvgBytesPerSec = mFormat.nSamplesPerSec * mFormat.nBlockAlign; - mFormat.cbSize = 0; - - MMRESULT res{waveInOpen(&mInHdl, DeviceID, &mFormat, (DWORD_PTR)&WinMMCapture::waveInProcC, - reinterpret_cast(this), CALLBACK_FUNCTION)}; - if(res != MMSYSERR_NOERROR) - { - ERR("waveInOpen failed: %u\n", res); - return ALC_INVALID_VALUE; - } - - // Ensure each buffer is 50ms each - DWORD BufferSize{mFormat.nAvgBytesPerSec / 20u}; - BufferSize -= (BufferSize % mFormat.nBlockAlign); - - // Allocate circular memory buffer for the captured audio - // Make sure circular buffer is at least 100ms in size - ALuint CapturedDataSize{mDevice->BufferSize}; - CapturedDataSize = static_cast(maxz(CapturedDataSize, BufferSize*mWaveBuffer.size())); - - mRing = CreateRingBuffer(CapturedDataSize, mFormat.nBlockAlign, false); - if(!mRing) return ALC_INVALID_VALUE; - - al_free(mWaveBuffer[0].lpData); - mWaveBuffer[0] = WAVEHDR{}; - mWaveBuffer[0].lpData = static_cast(al_calloc(16, BufferSize*4)); - mWaveBuffer[0].dwBufferLength = BufferSize; - for(size_t i{1};i < mWaveBuffer.size();++i) - { - mWaveBuffer[i] = WAVEHDR{}; - mWaveBuffer[i].lpData = mWaveBuffer[i-1].lpData + mWaveBuffer[i-1].dwBufferLength; - mWaveBuffer[i].dwBufferLength = mWaveBuffer[i-1].dwBufferLength; - } - - mDevice->DeviceName = CaptureDevices[DeviceID]; - return ALC_NO_ERROR; -} - -ALCboolean WinMMCapture::start() -{ - try { - for(size_t i{0};i < mWaveBuffer.size();++i) - { - waveInPrepareHeader(mInHdl, &mWaveBuffer[i], sizeof(WAVEHDR)); - waveInAddBuffer(mInHdl, &mWaveBuffer[i], sizeof(WAVEHDR)); - } - - mKillNow.store(false, std::memory_order_release); - mThread = std::thread{std::mem_fn(&WinMMCapture::captureProc), this}; - - waveInStart(mInHdl); - return ALC_TRUE; - } - catch(std::exception& e) { - ERR("Failed to start mixing thread: %s\n", e.what()); - } - catch(...) { - } - return ALC_FALSE; -} - -void WinMMCapture::stop() -{ - waveInStop(mInHdl); - - mKillNow.store(true, std::memory_order_release); - if(mThread.joinable()) - { - mSem.post(); - mThread.join(); - } - - waveInReset(mInHdl); - for(size_t i{0};i < mWaveBuffer.size();++i) - waveInUnprepareHeader(mInHdl, &mWaveBuffer[i], sizeof(WAVEHDR)); - - mReadable.store(0, std::memory_order_release); - mIdx = 0; -} - -ALCenum WinMMCapture::captureSamples(void *buffer, ALCuint samples) -{ - mRing->read(buffer, samples); - return ALC_NO_ERROR; -} - -ALCuint WinMMCapture::availableSamples() -{ return (ALCuint)mRing->readSpace(); } - -} // namespace - - -bool WinMMBackendFactory::init() -{ return true; } - -bool WinMMBackendFactory::querySupport(BackendType type) -{ return type == BackendType::Playback || type == BackendType::Capture; } - -void WinMMBackendFactory::probe(DevProbe type, std::string *outnames) -{ - auto add_device = [outnames](const std::string &dname) -> void - { - /* +1 to also append the null char (to ensure a null-separated list and - * double-null terminated list). - */ - if(!dname.empty()) - outnames->append(dname.c_str(), dname.length()+1); - }; - switch(type) - { - case DevProbe::Playback: - ProbePlaybackDevices(); - std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); - break; - - case DevProbe::Capture: - ProbeCaptureDevices(); - std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); - break; - } -} - -BackendPtr WinMMBackendFactory::createBackend(ALCdevice *device, BackendType type) -{ - if(type == BackendType::Playback) - return BackendPtr{new WinMMPlayback{device}}; - if(type == BackendType::Capture) - return BackendPtr{new WinMMCapture{device}}; - return nullptr; -} - -BackendFactory &WinMMBackendFactory::getFactory() -{ - static WinMMBackendFactory factory{}; - return factory; -} diff --git a/Alc/backends/winmm.h b/Alc/backends/winmm.h deleted file mode 100644 index e357ec19..00000000 --- a/Alc/backends/winmm.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef BACKENDS_WINMM_H -#define BACKENDS_WINMM_H - -#include "backends/base.h" - -struct WinMMBackendFactory final : public BackendFactory { -public: - bool init() override; - - bool querySupport(BackendType type) override; - - void probe(DevProbe type, std::string *outnames) override; - - BackendPtr createBackend(ALCdevice *device, BackendType type) override; - - static BackendFactory &getFactory(); -}; - -#endif /* BACKENDS_WINMM_H */ diff --git a/Alc/bformatdec.cpp b/Alc/bformatdec.cpp deleted file mode 100644 index 889bbf3a..00000000 --- a/Alc/bformatdec.cpp +++ /dev/null @@ -1,200 +0,0 @@ - -#include "config.h" - -#include "bformatdec.h" - -#include -#include -#include -#include -#include -#include - -#include "almalloc.h" -#include "alu.h" -#include "ambdec.h" -#include "filters/splitter.h" -#include "opthelpers.h" - - -namespace { - -constexpr ALfloat Ambi3DDecoderHFScale[MAX_AMBI_ORDER+1] = { - 1.00000000e+00f, 1.00000000e+00f -}; -constexpr ALfloat Ambi3DDecoderHFScale2O[MAX_AMBI_ORDER+1] = { - 7.45355990e-01f, 1.00000000e+00f -}; -constexpr ALfloat Ambi3DDecoderHFScale3O[MAX_AMBI_ORDER+1] = { - 5.89792205e-01f, 8.79693856e-01f -}; - -inline auto GetDecoderHFScales(ALsizei order) noexcept -> const ALfloat(&)[MAX_AMBI_ORDER+1] -{ - if(order >= 3) return Ambi3DDecoderHFScale3O; - if(order == 2) return Ambi3DDecoderHFScale2O; - return Ambi3DDecoderHFScale; -} - -inline auto GetAmbiScales(AmbDecScale scaletype) noexcept -> const std::array& -{ - if(scaletype == AmbDecScale::FuMa) return AmbiScale::FromFuMa; - if(scaletype == AmbDecScale::SN3D) return AmbiScale::FromSN3D; - return AmbiScale::FromN3D; -} - -} // namespace - - -BFormatDec::BFormatDec(const AmbDecConf *conf, const bool allow_2band, const ALuint inchans, - const ALuint srate, const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]) -{ - mDualBand = allow_2band && (conf->FreqBands == 2); - if(!mDualBand) - mSamples.resize(2); - else - { - ASSUME(inchans > 0); - mSamples.resize(inchans * 2); - mSamplesHF = mSamples.data(); - mSamplesLF = mSamplesHF + inchans; - } - mNumChannels = inchans; - - mEnabled = std::accumulate(std::begin(chanmap), std::begin(chanmap)+conf->Speakers.size(), 0u, - [](ALuint mask, const ALsizei &chan) noexcept -> ALuint - { return mask | (1 << chan); } - ); - - const ALfloat xover_norm{conf->XOverFreq / static_cast(srate)}; - - const bool periphonic{(conf->ChanMask&AMBI_PERIPHONIC_MASK) != 0}; - const std::array &coeff_scale = GetAmbiScales(conf->CoeffScale); - const size_t coeff_count{periphonic ? MAX_AMBI_CHANNELS : MAX_AMBI2D_CHANNELS}; - - if(!mDualBand) - { - for(size_t i{0u};i < conf->Speakers.size();i++) - { - ALfloat (&mtx)[MAX_AMBI_CHANNELS] = mMatrix.Single[chanmap[i]]; - for(size_t j{0},k{0};j < coeff_count;j++) - { - const size_t l{periphonic ? j : AmbiIndex::From2D[j]}; - if(!(conf->ChanMask&(1u<HFMatrix[i][k] / coeff_scale[l] * - ((l>=9) ? conf->HFOrderGain[3] : - (l>=4) ? conf->HFOrderGain[2] : - (l>=1) ? conf->HFOrderGain[1] : conf->HFOrderGain[0]); - ++k; - } - } - } - else - { - mXOver[0].init(xover_norm); - std::fill(std::begin(mXOver)+1, std::end(mXOver), mXOver[0]); - - const float ratio{std::pow(10.0f, conf->XOverRatio / 40.0f)}; - for(size_t i{0u};i < conf->Speakers.size();i++) - { - ALfloat (&mtx)[sNumBands][MAX_AMBI_CHANNELS] = mMatrix.Dual[chanmap[i]]; - for(size_t j{0},k{0};j < coeff_count;j++) - { - const size_t l{periphonic ? j : AmbiIndex::From2D[j]}; - if(!(conf->ChanMask&(1u<HFMatrix[i][k] / coeff_scale[l] * - ((l>=9) ? conf->HFOrderGain[3] : - (l>=4) ? conf->HFOrderGain[2] : - (l>=1) ? conf->HFOrderGain[1] : conf->HFOrderGain[0]) * ratio; - mtx[sLFBand][j] = conf->LFMatrix[i][k] / coeff_scale[l] * - ((l>=9) ? conf->LFOrderGain[3] : - (l>=4) ? conf->LFOrderGain[2] : - (l>=1) ? conf->LFOrderGain[1] : conf->LFOrderGain[0]) / ratio; - ++k; - } - } - } -} - -BFormatDec::BFormatDec(const ALuint inchans, const ALsizei chancount, - const ChannelDec (&chancoeffs)[MAX_OUTPUT_CHANNELS], - const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]) -{ - mSamples.resize(2); - mNumChannels = inchans; - - ASSUME(chancount > 0); - mEnabled = std::accumulate(std::begin(chanmap), std::begin(chanmap)+chancount, 0u, - [](ALuint mask, const ALsizei &chan) noexcept -> ALuint - { return mask | (1 << chan); } - ); - - const ChannelDec *incoeffs{chancoeffs}; - auto set_coeffs = [this,inchans,&incoeffs](const ALsizei chanidx) noexcept -> void - { - ASSUME(chanidx >= 0); - ALfloat (&mtx)[MAX_AMBI_CHANNELS] = mMatrix.Single[chanidx]; - const ALfloat (&coeffs)[MAX_AMBI_CHANNELS] = *(incoeffs++); - - ASSUME(inchans > 0); - std::copy_n(std::begin(coeffs), inchans, std::begin(mtx)); - }; - std::for_each(chanmap, chanmap+chancount, set_coeffs); -} - - -void BFormatDec::process(const al::span OutBuffer, - const FloatBufferLine *InSamples, const ALsizei SamplesToDo) -{ - if(mDualBand) - { - for(ALuint i{0};i < mNumChannels;i++) - mXOver[i].process(mSamplesHF[i].data(), mSamplesLF[i].data(), InSamples[i].data(), - SamplesToDo); - - const al::span hfsamples{mSamplesHF, mNumChannels}; - const al::span lfsamples{mSamplesLF, mNumChannels}; - ALfloat (*mixmtx)[sNumBands][MAX_AMBI_CHANNELS]{mMatrix.Dual}; - ALuint enabled{mEnabled}; - for(FloatBufferLine &outbuf : OutBuffer) - { - if(LIKELY(enabled&1)) - { - MixRowSamples(outbuf, (*mixmtx)[sHFBand], hfsamples, 0, SamplesToDo); - MixRowSamples(outbuf, (*mixmtx)[sLFBand], lfsamples, 0, SamplesToDo); - } - ++mixmtx; - enabled >>= 1; - } - } - else - { - const al::span insamples{InSamples, mNumChannels}; - ALfloat (*mixmtx)[MAX_AMBI_CHANNELS]{mMatrix.Single}; - ALuint enabled{mEnabled}; - for(FloatBufferLine &outbuf : OutBuffer) - { - if(LIKELY(enabled&1)) - MixRowSamples(outbuf, *mixmtx, insamples, 0, SamplesToDo); - ++mixmtx; - enabled >>= 1; - } - } -} - - -std::array BFormatDec::GetHFOrderScales(const ALsizei in_order, const ALsizei out_order) noexcept -{ - std::array ret{}; - - assert(out_order >= in_order); - ASSUME(out_order >= in_order); - - const ALfloat (&target)[MAX_AMBI_ORDER+1] = GetDecoderHFScales(out_order); - const ALfloat (&input)[MAX_AMBI_ORDER+1] = GetDecoderHFScales(in_order); - - for(ALsizei i{0};i < in_order+1;++i) - ret[i] = input[i] / target[i]; - - return ret; -} diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h deleted file mode 100644 index 06974651..00000000 --- a/Alc/bformatdec.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef BFORMATDEC_H -#define BFORMATDEC_H - -#include -#include - -#include "AL/al.h" - -#include "alcmain.h" -#include "almalloc.h" -#include "alspan.h" -#include "ambidefs.h" -#include "filters/splitter.h" -#include "vector.h" - -struct AmbDecConf; - - -using ChannelDec = ALfloat[MAX_AMBI_CHANNELS]; - -class BFormatDec { - static constexpr size_t sHFBand{0}; - static constexpr size_t sLFBand{1}; - static constexpr size_t sNumBands{2}; - - ALuint mEnabled{0u}; /* Bitfield of enabled channels. */ - - union MatrixU { - ALfloat Dual[MAX_OUTPUT_CHANNELS][sNumBands][MAX_AMBI_CHANNELS]; - ALfloat Single[MAX_OUTPUT_CHANNELS][MAX_AMBI_CHANNELS]; - } mMatrix{}; - - /* NOTE: BandSplitter filters are unused with single-band decoding */ - BandSplitter mXOver[MAX_AMBI_CHANNELS]; - - al::vector mSamples; - /* These two alias into Samples */ - FloatBufferLine *mSamplesHF{nullptr}; - FloatBufferLine *mSamplesLF{nullptr}; - - ALuint mNumChannels{0u}; - bool mDualBand{false}; - -public: - BFormatDec(const AmbDecConf *conf, const bool allow_2band, const ALuint inchans, - const ALuint srate, const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]); - BFormatDec(const ALuint inchans, const ALsizei chancount, - const ChannelDec (&chancoeffs)[MAX_OUTPUT_CHANNELS], - const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]); - - /* Decodes the ambisonic input to the given output channels. */ - void process(const al::span OutBuffer, const FloatBufferLine *InSamples, - const ALsizei SamplesToDo); - - /* Retrieves per-order HF scaling factors for "upsampling" ambisonic data. */ - static std::array GetHFOrderScales(const ALsizei in_order, - const ALsizei out_order) noexcept; - - DEF_NEWDEL(BFormatDec) -}; - -#endif /* BFORMATDEC_H */ diff --git a/Alc/bs2b.cpp b/Alc/bs2b.cpp deleted file mode 100644 index 2d1b96aa..00000000 --- a/Alc/bs2b.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/*- - * Copyright (c) 2005 Boris Mikhaylov - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "config.h" - -#include -#include -#include - -#include "bs2b.h" -#include "math_defs.h" - - -/* Set up all data. */ -static void init(struct bs2b *bs2b) -{ - float Fc_lo, Fc_hi; - float G_lo, G_hi; - float x, g; - - switch(bs2b->level) - { - case BS2B_LOW_CLEVEL: /* Low crossfeed level */ - Fc_lo = 360.0f; - Fc_hi = 501.0f; - G_lo = 0.398107170553497f; - G_hi = 0.205671765275719f; - break; - - case BS2B_MIDDLE_CLEVEL: /* Middle crossfeed level */ - Fc_lo = 500.0f; - Fc_hi = 711.0f; - G_lo = 0.459726988530872f; - G_hi = 0.228208484414988f; - break; - - case BS2B_HIGH_CLEVEL: /* High crossfeed level (virtual speakers are closer to itself) */ - Fc_lo = 700.0f; - Fc_hi = 1021.0f; - G_lo = 0.530884444230988f; - G_hi = 0.250105790667544f; - break; - - case BS2B_LOW_ECLEVEL: /* Low easy crossfeed level */ - Fc_lo = 360.0f; - Fc_hi = 494.0f; - G_lo = 0.316227766016838f; - G_hi = 0.168236228897329f; - break; - - case BS2B_MIDDLE_ECLEVEL: /* Middle easy crossfeed level */ - Fc_lo = 500.0f; - Fc_hi = 689.0f; - G_lo = 0.354813389233575f; - G_hi = 0.187169483835901f; - break; - - default: /* High easy crossfeed level */ - bs2b->level = BS2B_HIGH_ECLEVEL; - - Fc_lo = 700.0f; - Fc_hi = 975.0f; - G_lo = 0.398107170553497f; - G_hi = 0.205671765275719f; - break; - } /* switch */ - - g = 1.0f / (1.0f - G_hi + G_lo); - - /* $fc = $Fc / $s; - * $d = 1 / 2 / pi / $fc; - * $x = exp(-1 / $d); - */ - x = std::exp(-al::MathDefs::Tau() * Fc_lo / bs2b->srate); - bs2b->b1_lo = x; - bs2b->a0_lo = G_lo * (1.0f - x) * g; - - x = std::exp(-al::MathDefs::Tau() * Fc_hi / bs2b->srate); - bs2b->b1_hi = x; - bs2b->a0_hi = (1.0f - G_hi * (1.0f - x)) * g; - bs2b->a1_hi = -x * g; -} /* init */ - - -/* Exported functions. - * See descriptions in "bs2b.h" - */ - -void bs2b_set_params(struct bs2b *bs2b, int level, int srate) -{ - if(srate <= 0) srate = 1; - - bs2b->level = level; - bs2b->srate = srate; - init(bs2b); -} /* bs2b_set_params */ - -int bs2b_get_level(struct bs2b *bs2b) -{ - return bs2b->level; -} /* bs2b_get_level */ - -int bs2b_get_srate(struct bs2b *bs2b) -{ - return bs2b->srate; -} /* bs2b_get_srate */ - -void bs2b_clear(struct bs2b *bs2b) -{ - std::fill(std::begin(bs2b->last_sample), std::end(bs2b->last_sample), bs2b::t_last_sample{}); -} /* bs2b_clear */ - -void bs2b_cross_feed(struct bs2b *bs2b, float *RESTRICT Left, float *RESTRICT Right, int SamplesToDo) -{ - float lsamples[128][2]; - float rsamples[128][2]; - int base; - - for(base = 0;base < SamplesToDo;) - { - int todo = std::min(128, SamplesToDo-base); - int i; - - /* Process left input */ - lsamples[0][0] = bs2b->a0_lo*Left[0] + - bs2b->b1_lo*bs2b->last_sample[0].lo; - lsamples[0][1] = bs2b->a0_hi*Left[0] + - bs2b->a1_hi*bs2b->last_sample[0].asis + - bs2b->b1_hi*bs2b->last_sample[0].hi; - for(i = 1;i < todo;i++) - { - lsamples[i][0] = bs2b->a0_lo*Left[i] + - bs2b->b1_lo*lsamples[i-1][0]; - lsamples[i][1] = bs2b->a0_hi*Left[i] + - bs2b->a1_hi*Left[i-1] + - bs2b->b1_hi*lsamples[i-1][1]; - } - bs2b->last_sample[0].asis = Left[i-1]; - bs2b->last_sample[0].lo = lsamples[i-1][0]; - bs2b->last_sample[0].hi = lsamples[i-1][1]; - - /* Process right input */ - rsamples[0][0] = bs2b->a0_lo*Right[0] + - bs2b->b1_lo*bs2b->last_sample[1].lo; - rsamples[0][1] = bs2b->a0_hi*Right[0] + - bs2b->a1_hi*bs2b->last_sample[1].asis + - bs2b->b1_hi*bs2b->last_sample[1].hi; - for(i = 1;i < todo;i++) - { - rsamples[i][0] = bs2b->a0_lo*Right[i] + - bs2b->b1_lo*rsamples[i-1][0]; - rsamples[i][1] = bs2b->a0_hi*Right[i] + - bs2b->a1_hi*Right[i-1] + - bs2b->b1_hi*rsamples[i-1][1]; - } - bs2b->last_sample[1].asis = Right[i-1]; - bs2b->last_sample[1].lo = rsamples[i-1][0]; - bs2b->last_sample[1].hi = rsamples[i-1][1]; - - /* Crossfeed */ - for(i = 0;i < todo;i++) - *(Left++) = lsamples[i][1] + rsamples[i][0]; - for(i = 0;i < todo;i++) - *(Right++) = rsamples[i][1] + lsamples[i][0]; - - base += todo; - } -} /* bs2b_cross_feed */ diff --git a/Alc/bs2b.h b/Alc/bs2b.h deleted file mode 100644 index e235e765..00000000 --- a/Alc/bs2b.h +++ /dev/null @@ -1,90 +0,0 @@ -/*- - * Copyright (c) 2005 Boris Mikhaylov - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef BS2B_H -#define BS2B_H - -#include "almalloc.h" - -/* Number of crossfeed levels */ -#define BS2B_CLEVELS 3 - -/* Normal crossfeed levels */ -#define BS2B_HIGH_CLEVEL 3 -#define BS2B_MIDDLE_CLEVEL 2 -#define BS2B_LOW_CLEVEL 1 - -/* Easy crossfeed levels */ -#define BS2B_HIGH_ECLEVEL BS2B_HIGH_CLEVEL + BS2B_CLEVELS -#define BS2B_MIDDLE_ECLEVEL BS2B_MIDDLE_CLEVEL + BS2B_CLEVELS -#define BS2B_LOW_ECLEVEL BS2B_LOW_CLEVEL + BS2B_CLEVELS - -/* Default crossfeed levels */ -#define BS2B_DEFAULT_CLEVEL BS2B_HIGH_ECLEVEL -/* Default sample rate (Hz) */ -#define BS2B_DEFAULT_SRATE 44100 - -struct bs2b { - int level; /* Crossfeed level */ - int srate; /* Sample rate (Hz) */ - - /* Lowpass IIR filter coefficients */ - float a0_lo; - float b1_lo; - - /* Highboost IIR filter coefficients */ - float a0_hi; - float a1_hi; - float b1_hi; - - /* Buffer of last filtered sample. - * [0] - first channel, [1] - second channel - */ - struct t_last_sample { - float asis; - float lo; - float hi; - } last_sample[2]; - - DEF_NEWDEL(bs2b) -}; - -/* Clear buffers and set new coefficients with new crossfeed level and sample - * rate values. - * level - crossfeed level of *LEVEL values. - * srate - sample rate by Hz. - */ -void bs2b_set_params(bs2b *bs2b, int level, int srate); - -/* Return current crossfeed level value */ -int bs2b_get_level(bs2b *bs2b); - -/* Return current sample rate value */ -int bs2b_get_srate(bs2b *bs2b); - -/* Clear buffer */ -void bs2b_clear(bs2b *bs2b); - -void bs2b_cross_feed(bs2b *bs2b, float *RESTRICT Left, float *RESTRICT Right, int SamplesToDo); - -#endif /* BS2B_H */ diff --git a/Alc/compat.h b/Alc/compat.h deleted file mode 100644 index 4ffc40bf..00000000 --- a/Alc/compat.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef AL_COMPAT_H -#define AL_COMPAT_H - -#ifdef __cplusplus - -#ifdef _WIN32 - -#define WIN32_LEAN_AND_MEAN -#include - -#include -#include -#include - -inline std::string wstr_to_utf8(const WCHAR *wstr) -{ - std::string ret; - - int len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr); - if(len > 0) - { - ret.resize(len); - WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &ret[0], len, nullptr, nullptr); - ret.pop_back(); - } - - return ret; -} - -inline std::wstring utf8_to_wstr(const char *str) -{ - std::wstring ret; - - int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); - if(len > 0) - { - ret.resize(len); - MultiByteToWideChar(CP_UTF8, 0, str, -1, &ret[0], len); - ret.pop_back(); - } - - return ret; -} - - -namespace al { - -// Windows' std::ifstream fails with non-ANSI paths since the standard only -// specifies names using const char* (or std::string). MSVC has a non-standard -// extension using const wchar_t* (or std::wstring?) to handle Unicode paths, -// but not all Windows compilers support it. So we have to make our own istream -// that accepts UTF-8 paths and forwards to Unicode-aware I/O functions. -class filebuf final : public std::streambuf { - std::array mBuffer; - HANDLE mFile{INVALID_HANDLE_VALUE}; - - int_type underflow() override; - pos_type seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) override; - pos_type seekpos(pos_type pos, std::ios_base::openmode mode) override; - -public: - filebuf() = default; - ~filebuf() override; - - bool open(const wchar_t *filename, std::ios_base::openmode mode); - bool open(const char *filename, std::ios_base::openmode mode); - - bool is_open() const noexcept { return mFile != INVALID_HANDLE_VALUE; } -}; - -// Inherit from std::istream to use our custom streambuf -class ifstream final : public std::istream { - filebuf mStreamBuf; - -public: - ifstream(const wchar_t *filename, std::ios_base::openmode mode = std::ios_base::in); - ifstream(const std::wstring &filename, std::ios_base::openmode mode = std::ios_base::in) - : ifstream(filename.c_str(), mode) { } - ifstream(const char *filename, std::ios_base::openmode mode = std::ios_base::in); - ifstream(const std::string &filename, std::ios_base::openmode mode = std::ios_base::in) - : ifstream(filename.c_str(), mode) { } - ~ifstream() override; - - bool is_open() const noexcept { return mStreamBuf.is_open(); } -}; - -} // namespace al - -#define HAVE_DYNLOAD 1 - -#else /* _WIN32 */ - -#include - -namespace al { - -using filebuf = std::filebuf; -using ifstream = std::ifstream; - -} // namespace al - -#if defined(HAVE_DLFCN_H) -#define HAVE_DYNLOAD 1 -#endif - -#endif /* _WIN32 */ - -#include - -struct PathNamePair { std::string path, fname; }; -const PathNamePair &GetProcBinary(void); - -#ifdef HAVE_DYNLOAD -void *LoadLib(const char *name); -void CloseLib(void *handle); -void *GetSymbol(void *handle, const char *name); -#endif - -#endif /* __cplusplus */ - -#endif /* AL_COMPAT_H */ diff --git a/Alc/converter.cpp b/Alc/converter.cpp deleted file mode 100644 index 0f8e8941..00000000 --- a/Alc/converter.cpp +++ /dev/null @@ -1,367 +0,0 @@ - -#include "config.h" - -#include "converter.h" - -#include - -#include "fpu_modes.h" -#include "mixer/defs.h" - - -namespace { - -/* Base template left undefined. Should be marked =delete, but Clang 3.8.1 - * chokes on that given the inline specializations. - */ -template -inline ALfloat LoadSample(typename DevFmtTypeTraits::Type val) noexcept; - -template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept -{ return val * (1.0f/128.0f); } -template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept -{ return val * (1.0f/32768.0f); } -template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept -{ return val * (1.0f/2147483648.0f); } -template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept -{ return val; } - -template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept -{ return LoadSample(val - 128); } -template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept -{ return LoadSample(val - 32768); } -template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept -{ return LoadSample(val - 2147483648u); } - - -template -inline void LoadSampleArray(ALfloat *RESTRICT dst, const void *src, const size_t srcstep, - const ALsizei samples) noexcept -{ - using SampleType = typename DevFmtTypeTraits::Type; - - const SampleType *ssrc = static_cast(src); - for(ALsizei i{0};i < samples;i++) - dst[i] = LoadSample(ssrc[i*srcstep]); -} - -void LoadSamples(ALfloat *dst, const ALvoid *src, const size_t srcstep, const DevFmtType srctype, - const ALsizei samples) noexcept -{ -#define HANDLE_FMT(T) \ - case T: LoadSampleArray(dst, src, srcstep, samples); break - switch(srctype) - { - HANDLE_FMT(DevFmtByte); - HANDLE_FMT(DevFmtUByte); - HANDLE_FMT(DevFmtShort); - HANDLE_FMT(DevFmtUShort); - HANDLE_FMT(DevFmtInt); - HANDLE_FMT(DevFmtUInt); - HANDLE_FMT(DevFmtFloat); - } -#undef HANDLE_FMT -} - - -template -inline typename DevFmtTypeTraits::Type StoreSample(ALfloat) noexcept; - -template<> inline ALfloat StoreSample(ALfloat val) noexcept -{ return val; } -template<> inline ALint StoreSample(ALfloat val) noexcept -{ return fastf2i(clampf(val*2147483648.0f, -2147483648.0f, 2147483520.0f)); } -template<> inline ALshort StoreSample(ALfloat val) noexcept -{ return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); } -template<> inline ALbyte StoreSample(ALfloat val) noexcept -{ return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); } - -/* Define unsigned output variations. */ -template<> inline ALuint StoreSample(ALfloat val) noexcept -{ return StoreSample(val) + 2147483648u; } -template<> inline ALushort StoreSample(ALfloat val) noexcept -{ return StoreSample(val) + 32768; } -template<> inline ALubyte StoreSample(ALfloat val) noexcept -{ return StoreSample(val) + 128; } - -template -inline void StoreSampleArray(void *dst, const ALfloat *RESTRICT src, const size_t dststep, - const ALsizei samples) noexcept -{ - using SampleType = typename DevFmtTypeTraits::Type; - - SampleType *sdst = static_cast(dst); - for(ALsizei i{0};i < samples;i++) - sdst[i*dststep] = StoreSample(src[i]); -} - - -void StoreSamples(ALvoid *dst, const ALfloat *src, const size_t dststep, const DevFmtType dsttype, - const ALsizei samples) noexcept -{ -#define HANDLE_FMT(T) \ - case T: StoreSampleArray(dst, src, dststep, samples); break - switch(dsttype) - { - HANDLE_FMT(DevFmtByte); - HANDLE_FMT(DevFmtUByte); - HANDLE_FMT(DevFmtShort); - HANDLE_FMT(DevFmtUShort); - HANDLE_FMT(DevFmtInt); - HANDLE_FMT(DevFmtUInt); - HANDLE_FMT(DevFmtFloat); - } -#undef HANDLE_FMT -} - - -template -void Mono2Stereo(ALfloat *RESTRICT dst, const void *src, const ALsizei frames) noexcept -{ - using SampleType = typename DevFmtTypeTraits::Type; - - const SampleType *ssrc = static_cast(src); - for(ALsizei i{0};i < frames;i++) - dst[i*2 + 1] = dst[i*2 + 0] = LoadSample(ssrc[i]) * 0.707106781187f; -} - -template -void Stereo2Mono(ALfloat *RESTRICT dst, const void *src, const ALsizei frames) noexcept -{ - using SampleType = typename DevFmtTypeTraits::Type; - - const SampleType *ssrc = static_cast(src); - for(ALsizei i{0};i < frames;i++) - dst[i] = (LoadSample(ssrc[i*2 + 0])+LoadSample(ssrc[i*2 + 1])) * - 0.707106781187f; -} - -} // namespace - -SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, ALsizei numchans, - ALsizei srcRate, ALsizei dstRate, Resampler resampler) -{ - if(numchans <= 0 || srcRate <= 0 || dstRate <= 0) - return nullptr; - - void *ptr{al_calloc(16, SampleConverter::Sizeof(numchans))}; - SampleConverterPtr converter{new (ptr) SampleConverter{static_cast(numchans)}}; - converter->mSrcType = srcType; - converter->mDstType = dstType; - converter->mSrcTypeSize = BytesFromDevFmt(srcType); - converter->mDstTypeSize = BytesFromDevFmt(dstType); - - converter->mSrcPrepCount = 0; - converter->mFracOffset = 0; - - /* Have to set the mixer FPU mode since that's what the resampler code expects. */ - FPUCtl mixer_mode{}; - auto step = static_cast( - mind(static_cast(srcRate)/dstRate*FRACTIONONE + 0.5, MAX_PITCH*FRACTIONONE)); - converter->mIncrement = maxi(step, 1); - if(converter->mIncrement == FRACTIONONE) - converter->mResample = Resample_; - else - { - if(resampler == BSinc24Resampler) - BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc24); - else if(resampler == BSinc12Resampler) - BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc12); - converter->mResample = SelectResampler(resampler); - } - - return converter; -} - -ALsizei SampleConverter::availableOut(ALsizei srcframes) const -{ - ALint prepcount{mSrcPrepCount}; - if(prepcount < 0) - { - /* Negative prepcount means we need to skip that many input samples. */ - if(-prepcount >= srcframes) - return 0; - srcframes += prepcount; - prepcount = 0; - } - - if(srcframes < 1) - { - /* No output samples if there's no input samples. */ - return 0; - } - - if(prepcount < MAX_RESAMPLE_PADDING*2 && - MAX_RESAMPLE_PADDING*2 - prepcount >= srcframes) - { - /* Not enough input samples to generate an output sample. */ - return 0; - } - - auto DataSize64 = static_cast(prepcount); - DataSize64 += srcframes; - DataSize64 -= MAX_RESAMPLE_PADDING*2; - DataSize64 <<= FRACTIONBITS; - DataSize64 -= mFracOffset; - - /* If we have a full prep, we can generate at least one sample. */ - return static_cast(clampu64((DataSize64 + mIncrement-1)/mIncrement, 1, BUFFERSIZE)); -} - -ALsizei SampleConverter::convert(const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes) -{ - const ALsizei SrcFrameSize{static_cast(mChan.size()) * mSrcTypeSize}; - const ALsizei DstFrameSize{static_cast(mChan.size()) * mDstTypeSize}; - const ALsizei increment{mIncrement}; - auto SamplesIn = static_cast(*src); - ALsizei NumSrcSamples{*srcframes}; - - FPUCtl mixer_mode{}; - ALsizei pos{0}; - while(pos < dstframes && NumSrcSamples > 0) - { - ALint prepcount{mSrcPrepCount}; - if(prepcount < 0) - { - /* Negative prepcount means we need to skip that many input samples. */ - if(-prepcount >= NumSrcSamples) - { - mSrcPrepCount = prepcount + NumSrcSamples; - NumSrcSamples = 0; - break; - } - SamplesIn += SrcFrameSize*-prepcount; - NumSrcSamples += prepcount; - mSrcPrepCount = 0; - continue; - } - ALint toread{mini(NumSrcSamples, BUFFERSIZE - MAX_RESAMPLE_PADDING*2)}; - - if(prepcount < MAX_RESAMPLE_PADDING*2 && - MAX_RESAMPLE_PADDING*2 - prepcount >= toread) - { - /* Not enough input samples to generate an output sample. Store - * what we're given for later. - */ - for(size_t chan{0u};chan < mChan.size();chan++) - LoadSamples(&mChan[chan].PrevSamples[prepcount], SamplesIn + mSrcTypeSize*chan, - mChan.size(), mSrcType, toread); - - mSrcPrepCount = prepcount + toread; - NumSrcSamples = 0; - break; - } - - ALfloat *RESTRICT SrcData{mSrcSamples}; - ALfloat *RESTRICT DstData{mDstSamples}; - ALsizei DataPosFrac{mFracOffset}; - auto DataSize64 = static_cast(prepcount); - DataSize64 += toread; - DataSize64 -= MAX_RESAMPLE_PADDING*2; - DataSize64 <<= FRACTIONBITS; - DataSize64 -= DataPosFrac; - - /* If we have a full prep, we can generate at least one sample. */ - auto DstSize = static_cast( - clampu64((DataSize64 + increment-1)/increment, 1, BUFFERSIZE)); - DstSize = mini(DstSize, dstframes-pos); - - for(size_t chan{0u};chan < mChan.size();chan++) - { - const al::byte *SrcSamples{SamplesIn + mSrcTypeSize*chan}; - al::byte *DstSamples = static_cast(dst) + mDstTypeSize*chan; - - /* Load the previous samples into the source data first, then the - * new samples from the input buffer. - */ - std::copy_n(mChan[chan].PrevSamples, prepcount, SrcData); - LoadSamples(SrcData + prepcount, SrcSamples, mChan.size(), mSrcType, toread); - - /* Store as many prep samples for next time as possible, given the - * number of output samples being generated. - */ - ALsizei SrcDataEnd{(DstSize*increment + DataPosFrac)>>FRACTIONBITS}; - if(SrcDataEnd >= prepcount+toread) - std::fill(std::begin(mChan[chan].PrevSamples), - std::end(mChan[chan].PrevSamples), 0.0f); - else - { - size_t len = mini(MAX_RESAMPLE_PADDING*2, prepcount+toread-SrcDataEnd); - std::copy_n(SrcData+SrcDataEnd, len, mChan[chan].PrevSamples); - std::fill(std::begin(mChan[chan].PrevSamples)+len, - std::end(mChan[chan].PrevSamples), 0.0f); - } - - /* Now resample, and store the result in the output buffer. */ - const ALfloat *ResampledData{mResample(&mState, SrcData+MAX_RESAMPLE_PADDING, - DataPosFrac, increment, DstData, DstSize)}; - - StoreSamples(DstSamples, ResampledData, mChan.size(), mDstType, DstSize); - } - - /* Update the number of prep samples still available, as well as the - * fractional offset. - */ - DataPosFrac += increment*DstSize; - mSrcPrepCount = mini(prepcount + toread - (DataPosFrac>>FRACTIONBITS), - MAX_RESAMPLE_PADDING*2); - mFracOffset = DataPosFrac & FRACTIONMASK; - - /* Update the src and dst pointers in case there's still more to do. */ - SamplesIn += SrcFrameSize*(DataPosFrac>>FRACTIONBITS); - NumSrcSamples -= mini(NumSrcSamples, (DataPosFrac>>FRACTIONBITS)); - - dst = static_cast(dst) + DstFrameSize*DstSize; - pos += DstSize; - } - - *src = SamplesIn; - *srcframes = NumSrcSamples; - - return pos; -} - - -ChannelConverterPtr CreateChannelConverter(DevFmtType srcType, DevFmtChannels srcChans, DevFmtChannels dstChans) -{ - if(srcChans != dstChans && !((srcChans == DevFmtMono && dstChans == DevFmtStereo) || - (srcChans == DevFmtStereo && dstChans == DevFmtMono))) - return nullptr; - return al::make_unique(srcType, srcChans, dstChans); -} - -void ChannelConverter::convert(const ALvoid *src, ALfloat *dst, ALsizei frames) const -{ - if(mSrcChans == DevFmtStereo && mDstChans == DevFmtMono) - { - switch(mSrcType) - { -#define HANDLE_FMT(T) case T: Stereo2Mono(dst, src, frames); break - HANDLE_FMT(DevFmtByte); - HANDLE_FMT(DevFmtUByte); - HANDLE_FMT(DevFmtShort); - HANDLE_FMT(DevFmtUShort); - HANDLE_FMT(DevFmtInt); - HANDLE_FMT(DevFmtUInt); - HANDLE_FMT(DevFmtFloat); -#undef HANDLE_FMT - } - } - else if(mSrcChans == DevFmtMono && mDstChans == DevFmtStereo) - { - switch(mSrcType) - { -#define HANDLE_FMT(T) case T: Mono2Stereo(dst, src, frames); break - HANDLE_FMT(DevFmtByte); - HANDLE_FMT(DevFmtUByte); - HANDLE_FMT(DevFmtShort); - HANDLE_FMT(DevFmtUShort); - HANDLE_FMT(DevFmtInt); - HANDLE_FMT(DevFmtUInt); - HANDLE_FMT(DevFmtFloat); -#undef HANDLE_FMT - } - } - else - LoadSamples(dst, src, 1u, mSrcType, frames*ChannelsFromDevFmt(mSrcChans, 0)); -} diff --git a/Alc/converter.h b/Alc/converter.h deleted file mode 100644 index 033e4d3f..00000000 --- a/Alc/converter.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef CONVERTER_H -#define CONVERTER_H - -#include - -#include "alcmain.h" -#include "alu.h" -#include "almalloc.h" - -struct SampleConverter { - DevFmtType mSrcType{}; - DevFmtType mDstType{}; - ALsizei mSrcTypeSize{}; - ALsizei mDstTypeSize{}; - - ALint mSrcPrepCount{}; - - ALsizei mFracOffset{}; - ALsizei mIncrement{}; - InterpState mState{}; - ResamplerFunc mResample{}; - - alignas(16) ALfloat mSrcSamples[BUFFERSIZE]{}; - alignas(16) ALfloat mDstSamples[BUFFERSIZE]{}; - - struct ChanSamples { - alignas(16) ALfloat PrevSamples[MAX_RESAMPLE_PADDING*2]; - }; - al::FlexArray mChan; - - SampleConverter(size_t numchans) : mChan{numchans} { } - SampleConverter(const SampleConverter&) = delete; - SampleConverter& operator=(const SampleConverter&) = delete; - - ALsizei convert(const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes); - ALsizei availableOut(ALsizei srcframes) const; - - static constexpr size_t Sizeof(size_t length) noexcept - { - return maxz(sizeof(SampleConverter), - al::FlexArray::Sizeof(length, offsetof(SampleConverter, mChan))); - } - - DEF_PLACE_NEWDEL() -}; -using SampleConverterPtr = std::unique_ptr; - -SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, ALsizei numchans, - ALsizei srcRate, ALsizei dstRate, Resampler resampler); - - -struct ChannelConverter { - DevFmtType mSrcType; - DevFmtChannels mSrcChans; - DevFmtChannels mDstChans; - - ChannelConverter(DevFmtType srctype, DevFmtChannels srcchans, DevFmtChannels dstchans) - : mSrcType(srctype), mSrcChans(srcchans), mDstChans(dstchans) - { } - - void convert(const ALvoid *src, ALfloat *dst, ALsizei frames) const; - - DEF_NEWDEL(ChannelConverter) -}; -using ChannelConverterPtr = std::unique_ptr; - -ChannelConverterPtr CreateChannelConverter(DevFmtType srcType, DevFmtChannels srcChans, - DevFmtChannels dstChans); - -#endif /* CONVERTER_H */ diff --git a/Alc/cpu_caps.h b/Alc/cpu_caps.h deleted file mode 100644 index 64a4ee45..00000000 --- a/Alc/cpu_caps.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef CPU_CAPS_H -#define CPU_CAPS_H - - -extern int CPUCapFlags; -enum { - CPU_CAP_SSE = 1<<0, - CPU_CAP_SSE2 = 1<<1, - CPU_CAP_SSE3 = 1<<2, - CPU_CAP_SSE4_1 = 1<<3, - CPU_CAP_NEON = 1<<4, -}; - -void FillCPUCaps(int capfilter); - -#endif /* CPU_CAPS_H */ diff --git a/Alc/effects/autowah.cpp b/Alc/effects/autowah.cpp deleted file mode 100644 index 96292636..00000000 --- a/Alc/effects/autowah.cpp +++ /dev/null @@ -1,298 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2018 by Raul Herraiz. - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include - -#include "alcmain.h" -#include "alcontext.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" -#include "filters/biquad.h" -#include "vecmat.h" - -namespace { - -#define MIN_FREQ 20.0f -#define MAX_FREQ 2500.0f -#define Q_FACTOR 5.0f - -struct ALautowahState final : public EffectState { - /* Effect parameters */ - ALfloat mAttackRate; - ALfloat mReleaseRate; - ALfloat mResonanceGain; - ALfloat mPeakGain; - ALfloat mFreqMinNorm; - ALfloat mBandwidthNorm; - ALfloat mEnvDelay; - - /* Filter components derived from the envelope. */ - struct { - ALfloat cos_w0; - ALfloat alpha; - } mEnv[BUFFERSIZE]; - - struct { - /* Effect filters' history. */ - struct { - ALfloat z1, z2; - } Filter; - - /* Effect gains for each output channel */ - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; - } mChans[MAX_AMBI_CHANNELS]; - - /* Effects buffers */ - alignas(16) ALfloat mBufferOut[BUFFERSIZE]; - - - ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; - - DEF_NEWDEL(ALautowahState) -}; - -ALboolean ALautowahState::deviceUpdate(const ALCdevice*) -{ - /* (Re-)initializing parameters and clear the buffers. */ - - mAttackRate = 1.0f; - mReleaseRate = 1.0f; - mResonanceGain = 10.0f; - mPeakGain = 4.5f; - mFreqMinNorm = 4.5e-4f; - mBandwidthNorm = 0.05f; - mEnvDelay = 0.0f; - - for(auto &e : mEnv) - { - e.cos_w0 = 0.0f; - e.alpha = 0.0f; - } - - for(auto &chan : mChans) - { - std::fill(std::begin(chan.CurrentGains), std::end(chan.CurrentGains), 0.0f); - chan.Filter.z1 = 0.0f; - chan.Filter.z2 = 0.0f; - } - - return AL_TRUE; -} - -void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) -{ - const ALCdevice *device{context->Device}; - - const ALfloat ReleaseTime{clampf(props->Autowah.ReleaseTime, 0.001f, 1.0f)}; - - mAttackRate = expf(-1.0f / (props->Autowah.AttackTime*device->Frequency)); - mReleaseRate = expf(-1.0f / (ReleaseTime*device->Frequency)); - /* 0-20dB Resonance Peak gain */ - mResonanceGain = std::sqrt(std::log10(props->Autowah.Resonance)*10.0f / 3.0f); - mPeakGain = 1.0f - std::log10(props->Autowah.PeakGain/AL_AUTOWAH_MAX_PEAK_GAIN); - mFreqMinNorm = MIN_FREQ / device->Frequency; - mBandwidthNorm = (MAX_FREQ-MIN_FREQ) / device->Frequency; - - mOutTarget = target.Main->Buffer; - for(size_t i{0u};i < slot->Wet.Buffer.size();++i) - { - auto coeffs = GetAmbiIdentityRow(i); - ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mChans[i].TargetGains); - } -} - -void ALautowahState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) -{ - const ALfloat attack_rate = mAttackRate; - const ALfloat release_rate = mReleaseRate; - const ALfloat res_gain = mResonanceGain; - const ALfloat peak_gain = mPeakGain; - const ALfloat freq_min = mFreqMinNorm; - const ALfloat bandwidth = mBandwidthNorm; - - ALfloat env_delay{mEnvDelay}; - for(ALsizei i{0};i < samplesToDo;i++) - { - ALfloat w0, sample, a; - - /* Envelope follower described on the book: Audio Effects, Theory, - * Implementation and Application. - */ - sample = peak_gain * std::fabs(samplesIn[0][i]); - a = (sample > env_delay) ? attack_rate : release_rate; - env_delay = lerp(sample, env_delay, a); - - /* Calculate the cos and alpha components for this sample's filter. */ - w0 = minf((bandwidth*env_delay + freq_min), 0.46f) * al::MathDefs::Tau(); - mEnv[i].cos_w0 = cosf(w0); - mEnv[i].alpha = sinf(w0)/(2.0f * Q_FACTOR); - } - mEnvDelay = env_delay; - - ASSUME(numInput > 0); - for(ALsizei c{0};c < numInput;++c) - { - /* This effectively inlines BiquadFilter_setParams for a peaking - * filter and BiquadFilter_processC. The alpha and cosine components - * for the filter coefficients were previously calculated with the - * envelope. Because the filter changes for each sample, the - * coefficients are transient and don't need to be held. - */ - ALfloat z1{mChans[c].Filter.z1}; - ALfloat z2{mChans[c].Filter.z2}; - - for(ALsizei i{0};i < samplesToDo;i++) - { - const ALfloat alpha = mEnv[i].alpha; - const ALfloat cos_w0 = mEnv[i].cos_w0; - ALfloat input, output; - ALfloat a[3], b[3]; - - b[0] = 1.0f + alpha*res_gain; - b[1] = -2.0f * cos_w0; - b[2] = 1.0f - alpha*res_gain; - a[0] = 1.0f + alpha/res_gain; - a[1] = -2.0f * cos_w0; - a[2] = 1.0f - alpha/res_gain; - - input = samplesIn[c][i]; - output = input*(b[0]/a[0]) + z1; - z1 = input*(b[1]/a[0]) - output*(a[1]/a[0]) + z2; - z2 = input*(b[2]/a[0]) - output*(a[2]/a[0]); - mBufferOut[i] = output; - } - mChans[c].Filter.z1 = z1; - mChans[c].Filter.z2 = z2; - - /* Now, mix the processed sound data to the output. */ - MixSamples(mBufferOut, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, - samplesToDo, 0, samplesToDo); - } -} - - -void ALautowah_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_AUTOWAH_ATTACK_TIME: - if(!(val >= AL_AUTOWAH_MIN_ATTACK_TIME && val <= AL_AUTOWAH_MAX_ATTACK_TIME)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Autowah attack time out of range"); - props->Autowah.AttackTime = val; - break; - - case AL_AUTOWAH_RELEASE_TIME: - if(!(val >= AL_AUTOWAH_MIN_RELEASE_TIME && val <= AL_AUTOWAH_MAX_RELEASE_TIME)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Autowah release time out of range"); - props->Autowah.ReleaseTime = val; - break; - - case AL_AUTOWAH_RESONANCE: - if(!(val >= AL_AUTOWAH_MIN_RESONANCE && val <= AL_AUTOWAH_MAX_RESONANCE)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Autowah resonance out of range"); - props->Autowah.Resonance = val; - break; - - case AL_AUTOWAH_PEAK_GAIN: - if(!(val >= AL_AUTOWAH_MIN_PEAK_GAIN && val <= AL_AUTOWAH_MAX_PEAK_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Autowah peak gain out of range"); - props->Autowah.PeakGain = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param); - } -} -void ALautowah_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) -{ ALautowah_setParamf(props, context, param, vals[0]); } - -void ALautowah_setParami(EffectProps*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param); } -void ALautowah_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x", param); } - -void ALautowah_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_AUTOWAH_ATTACK_TIME: - *val = props->Autowah.AttackTime; - break; - - case AL_AUTOWAH_RELEASE_TIME: - *val = props->Autowah.ReleaseTime; - break; - - case AL_AUTOWAH_RESONANCE: - *val = props->Autowah.Resonance; - break; - - case AL_AUTOWAH_PEAK_GAIN: - *val = props->Autowah.PeakGain; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param); - } - -} -void ALautowah_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) -{ ALautowah_getParamf(props, context, param, vals); } - -void ALautowah_getParami(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param); } -void ALautowah_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x", param); } - -DEFINE_ALEFFECT_VTABLE(ALautowah); - - -struct AutowahStateFactory final : public EffectStateFactory { - EffectState *create() override { return new ALautowahState{}; } - EffectProps getDefaultProps() const noexcept override; - const EffectVtable *getEffectVtable() const noexcept override { return &ALautowah_vtable; } -}; - -EffectProps AutowahStateFactory::getDefaultProps() const noexcept -{ - EffectProps props{}; - props.Autowah.AttackTime = AL_AUTOWAH_DEFAULT_ATTACK_TIME; - props.Autowah.ReleaseTime = AL_AUTOWAH_DEFAULT_RELEASE_TIME; - props.Autowah.Resonance = AL_AUTOWAH_DEFAULT_RESONANCE; - props.Autowah.PeakGain = AL_AUTOWAH_DEFAULT_PEAK_GAIN; - return props; -} - -} // namespace - -EffectStateFactory *AutowahStateFactory_getFactory() -{ - static AutowahStateFactory AutowahFactory{}; - return &AutowahFactory; -} diff --git a/Alc/effects/base.h b/Alc/effects/base.h deleted file mode 100644 index 4f48de22..00000000 --- a/Alc/effects/base.h +++ /dev/null @@ -1,196 +0,0 @@ -#ifndef EFFECTS_BASE_H -#define EFFECTS_BASE_H - -#include "alcmain.h" -#include "almalloc.h" -#include "alspan.h" -#include "atomic.h" - - -struct ALeffectslot; - - -union EffectProps { - struct { - // Shared Reverb Properties - ALfloat Density; - ALfloat Diffusion; - ALfloat Gain; - ALfloat GainHF; - ALfloat DecayTime; - ALfloat DecayHFRatio; - ALfloat ReflectionsGain; - ALfloat ReflectionsDelay; - ALfloat LateReverbGain; - ALfloat LateReverbDelay; - ALfloat AirAbsorptionGainHF; - ALfloat RoomRolloffFactor; - ALboolean DecayHFLimit; - - // Additional EAX Reverb Properties - ALfloat GainLF; - ALfloat DecayLFRatio; - ALfloat ReflectionsPan[3]; - ALfloat LateReverbPan[3]; - ALfloat EchoTime; - ALfloat EchoDepth; - ALfloat ModulationTime; - ALfloat ModulationDepth; - ALfloat HFReference; - ALfloat LFReference; - } Reverb; - - struct { - ALfloat AttackTime; - ALfloat ReleaseTime; - ALfloat Resonance; - ALfloat PeakGain; - } Autowah; - - struct { - ALint Waveform; - ALint Phase; - ALfloat Rate; - ALfloat Depth; - ALfloat Feedback; - ALfloat Delay; - } Chorus; /* Also Flanger */ - - struct { - ALboolean OnOff; - } Compressor; - - struct { - ALfloat Edge; - ALfloat Gain; - ALfloat LowpassCutoff; - ALfloat EQCenter; - ALfloat EQBandwidth; - } Distortion; - - struct { - ALfloat Delay; - ALfloat LRDelay; - - ALfloat Damping; - ALfloat Feedback; - - ALfloat Spread; - } Echo; - - struct { - ALfloat LowCutoff; - ALfloat LowGain; - ALfloat Mid1Center; - ALfloat Mid1Gain; - ALfloat Mid1Width; - ALfloat Mid2Center; - ALfloat Mid2Gain; - ALfloat Mid2Width; - ALfloat HighCutoff; - ALfloat HighGain; - } Equalizer; - - struct { - ALfloat Frequency; - ALint LeftDirection; - ALint RightDirection; - } Fshifter; - - struct { - ALfloat Frequency; - ALfloat HighPassCutoff; - ALint Waveform; - } Modulator; - - struct { - ALint CoarseTune; - ALint FineTune; - } Pshifter; - - struct { - ALfloat Rate; - ALint PhonemeA; - ALint PhonemeB; - ALint PhonemeACoarseTuning; - ALint PhonemeBCoarseTuning; - ALint Waveform; - } Vmorpher; - - struct { - ALfloat Gain; - } Dedicated; -}; - - -struct EffectVtable { - void (*const setParami)(EffectProps *props, ALCcontext *context, ALenum param, ALint val); - void (*const setParamiv)(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals); - void (*const setParamf)(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val); - void (*const setParamfv)(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals); - - void (*const getParami)(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val); - void (*const getParamiv)(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals); - void (*const getParamf)(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val); - void (*const getParamfv)(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals); -}; - -#define DEFINE_ALEFFECT_VTABLE(T) \ -const EffectVtable T##_vtable = { \ - T##_setParami, T##_setParamiv, \ - T##_setParamf, T##_setParamfv, \ - T##_getParami, T##_getParamiv, \ - T##_getParamf, T##_getParamfv, \ -} - - -struct EffectTarget { - MixParams *Main; - RealMixParams *RealOut; -}; - -struct EffectState { - RefCount mRef{1u}; - - al::span mOutTarget; - - - virtual ~EffectState() = default; - - virtual ALboolean deviceUpdate(const ALCdevice *device) = 0; - virtual void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) = 0; - virtual void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) = 0; - - void IncRef() noexcept; - void DecRef() noexcept; -}; - - -struct EffectStateFactory { - virtual ~EffectStateFactory() { } - - virtual EffectState *create() = 0; - virtual EffectProps getDefaultProps() const noexcept = 0; - virtual const EffectVtable *getEffectVtable() const noexcept = 0; -}; - - -EffectStateFactory *NullStateFactory_getFactory(void); -EffectStateFactory *ReverbStateFactory_getFactory(void); -EffectStateFactory *StdReverbStateFactory_getFactory(void); -EffectStateFactory *AutowahStateFactory_getFactory(void); -EffectStateFactory *ChorusStateFactory_getFactory(void); -EffectStateFactory *CompressorStateFactory_getFactory(void); -EffectStateFactory *DistortionStateFactory_getFactory(void); -EffectStateFactory *EchoStateFactory_getFactory(void); -EffectStateFactory *EqualizerStateFactory_getFactory(void); -EffectStateFactory *FlangerStateFactory_getFactory(void); -EffectStateFactory *FshifterStateFactory_getFactory(void); -EffectStateFactory *ModulatorStateFactory_getFactory(void); -EffectStateFactory *PshifterStateFactory_getFactory(void); -EffectStateFactory* VmorpherStateFactory_getFactory(void); - -EffectStateFactory *DedicatedStateFactory_getFactory(void); - - -#endif /* EFFECTS_BASE_H */ diff --git a/Alc/effects/chorus.cpp b/Alc/effects/chorus.cpp deleted file mode 100644 index d475b57a..00000000 --- a/Alc/effects/chorus.cpp +++ /dev/null @@ -1,538 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2013 by Mike Gorchak - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/efx.h" - -#include "alAuxEffectSlot.h" -#include "alcmain.h" -#include "alError.h" -#include "alcontext.h" -#include "almalloc.h" -#include "alnumeric.h" -#include "alspan.h" -#include "alu.h" -#include "ambidefs.h" -#include "effects/base.h" -#include "math_defs.h" -#include "opthelpers.h" -#include "vector.h" - - -namespace { - -static_assert(AL_CHORUS_WAVEFORM_SINUSOID == AL_FLANGER_WAVEFORM_SINUSOID, "Chorus/Flanger waveform value mismatch"); -static_assert(AL_CHORUS_WAVEFORM_TRIANGLE == AL_FLANGER_WAVEFORM_TRIANGLE, "Chorus/Flanger waveform value mismatch"); - -enum class WaveForm { - Sinusoid, - Triangle -}; - -void GetTriangleDelays(ALint *delays, const ALsizei start_offset, const ALsizei lfo_range, - const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, const ALsizei todo) -{ - ASSUME(start_offset >= 0); - ASSUME(lfo_range > 0); - ASSUME(todo > 0); - - ALsizei offset{start_offset}; - auto gen_lfo = [&offset,lfo_range,lfo_scale,depth,delay]() -> ALint - { - offset = (offset+1)%lfo_range; - return fastf2i((1.0f - std::abs(2.0f - lfo_scale*offset)) * depth) + delay; - }; - std::generate_n(delays, todo, gen_lfo); -} - -void GetSinusoidDelays(ALint *delays, const ALsizei start_offset, const ALsizei lfo_range, - const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, const ALsizei todo) -{ - ASSUME(start_offset >= 0); - ASSUME(lfo_range > 0); - ASSUME(todo > 0); - - ALsizei offset{start_offset}; - auto gen_lfo = [&offset,lfo_range,lfo_scale,depth,delay]() -> ALint - { - ASSUME(delay >= 0); - offset = (offset+1)%lfo_range; - return fastf2i(std::sin(lfo_scale*offset) * depth) + delay; - }; - std::generate_n(delays, todo, gen_lfo); -} - -struct ChorusState final : public EffectState { - al::vector mSampleBuffer; - ALsizei mOffset{0}; - - ALsizei mLfoOffset{0}; - ALsizei mLfoRange{1}; - ALfloat mLfoScale{0.0f}; - ALint mLfoDisp{0}; - - /* Gains for left and right sides */ - struct { - ALfloat Current[MAX_OUTPUT_CHANNELS]{}; - ALfloat Target[MAX_OUTPUT_CHANNELS]{}; - } mGains[2]; - - /* effect parameters */ - WaveForm mWaveform{}; - ALint mDelay{0}; - ALfloat mDepth{0.0f}; - ALfloat mFeedback{0.0f}; - - - ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; - - DEF_NEWDEL(ChorusState) -}; - -ALboolean ChorusState::deviceUpdate(const ALCdevice *Device) -{ - const ALfloat max_delay = maxf(AL_CHORUS_MAX_DELAY, AL_FLANGER_MAX_DELAY); - size_t maxlen; - - maxlen = NextPowerOf2(float2int(max_delay*2.0f*Device->Frequency) + 1u); - if(maxlen <= 0) return AL_FALSE; - - if(maxlen != mSampleBuffer.size()) - { - mSampleBuffer.resize(maxlen); - mSampleBuffer.shrink_to_fit(); - } - - std::fill(mSampleBuffer.begin(), mSampleBuffer.end(), 0.0f); - for(auto &e : mGains) - { - std::fill(std::begin(e.Current), std::end(e.Current), 0.0f); - std::fill(std::begin(e.Target), std::end(e.Target), 0.0f); - } - - return AL_TRUE; -} - -void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, const EffectProps *props, const EffectTarget target) -{ - static constexpr ALsizei mindelay = MAX_RESAMPLE_PADDING << FRACTIONBITS; - - switch(props->Chorus.Waveform) - { - case AL_CHORUS_WAVEFORM_TRIANGLE: - mWaveform = WaveForm::Triangle; - break; - case AL_CHORUS_WAVEFORM_SINUSOID: - mWaveform = WaveForm::Sinusoid; - break; - } - - /* The LFO depth is scaled to be relative to the sample delay. Clamp the - * delay and depth to allow enough padding for resampling. - */ - const ALCdevice *device{Context->Device}; - const auto frequency = static_cast(device->Frequency); - mDelay = maxi(float2int(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f), mindelay); - mDepth = minf(props->Chorus.Depth * mDelay, static_cast(mDelay - mindelay)); - - mFeedback = props->Chorus.Feedback; - - /* Gains for left and right sides */ - ALfloat coeffs[2][MAX_AMBI_CHANNELS]; - CalcDirectionCoeffs({-1.0f, 0.0f, 0.0f}, 0.0f, coeffs[0]); - CalcDirectionCoeffs({ 1.0f, 0.0f, 0.0f}, 0.0f, coeffs[1]); - - mOutTarget = target.Main->Buffer; - ComputePanGains(target.Main, coeffs[0], Slot->Params.Gain, mGains[0].Target); - ComputePanGains(target.Main, coeffs[1], Slot->Params.Gain, mGains[1].Target); - - ALfloat rate{props->Chorus.Rate}; - if(!(rate > 0.0f)) - { - mLfoOffset = 0; - mLfoRange = 1; - mLfoScale = 0.0f; - mLfoDisp = 0; - } - else - { - /* Calculate LFO coefficient (number of samples per cycle). Limit the - * max range to avoid overflow when calculating the displacement. - */ - ALsizei lfo_range = float2int(minf(frequency/rate + 0.5f, static_cast(INT_MAX/360 - 180))); - - mLfoOffset = float2int(static_cast(mLfoOffset)/mLfoRange*lfo_range + 0.5f) % lfo_range; - mLfoRange = lfo_range; - switch(mWaveform) - { - case WaveForm::Triangle: - mLfoScale = 4.0f / mLfoRange; - break; - case WaveForm::Sinusoid: - mLfoScale = al::MathDefs::Tau() / mLfoRange; - break; - } - - /* Calculate lfo phase displacement */ - ALint phase{props->Chorus.Phase}; - if(phase < 0) phase = 360 + phase; - mLfoDisp = (mLfoRange*phase + 180) / 360; - } -} - -void ChorusState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) -{ - const auto bufmask = static_cast(mSampleBuffer.size()-1); - const ALfloat feedback{mFeedback}; - const ALsizei avgdelay{(mDelay + (FRACTIONONE>>1)) >> FRACTIONBITS}; - ALfloat *RESTRICT delaybuf{mSampleBuffer.data()}; - ALsizei offset{mOffset}; - - for(ALsizei base{0};base < samplesToDo;) - { - const ALsizei todo = mini(256, samplesToDo-base); - ALint moddelays[2][256]; - alignas(16) ALfloat temps[2][256]; - - if(mWaveform == WaveForm::Sinusoid) - { - GetSinusoidDelays(moddelays[0], mLfoOffset, mLfoRange, mLfoScale, mDepth, mDelay, - todo); - GetSinusoidDelays(moddelays[1], (mLfoOffset+mLfoDisp)%mLfoRange, mLfoRange, mLfoScale, - mDepth, mDelay, todo); - } - else /*if(mWaveform == WaveForm::Triangle)*/ - { - GetTriangleDelays(moddelays[0], mLfoOffset, mLfoRange, mLfoScale, mDepth, mDelay, - todo); - GetTriangleDelays(moddelays[1], (mLfoOffset+mLfoDisp)%mLfoRange, mLfoRange, mLfoScale, - mDepth, mDelay, todo); - } - mLfoOffset = (mLfoOffset+todo) % mLfoRange; - - for(ALsizei i{0};i < todo;i++) - { - // Feed the buffer's input first (necessary for delays < 1). - delaybuf[offset&bufmask] = samplesIn[0][base+i]; - - // Tap for the left output. - ALint delay{offset - (moddelays[0][i]>>FRACTIONBITS)}; - ALfloat mu{(moddelays[0][i]&FRACTIONMASK) * (1.0f/FRACTIONONE)}; - temps[0][i] = cubic(delaybuf[(delay+1) & bufmask], delaybuf[(delay ) & bufmask], - delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask], - mu); - - // Tap for the right output. - delay = offset - (moddelays[1][i]>>FRACTIONBITS); - mu = (moddelays[1][i]&FRACTIONMASK) * (1.0f/FRACTIONONE); - temps[1][i] = cubic(delaybuf[(delay+1) & bufmask], delaybuf[(delay ) & bufmask], - delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask], - mu); - - // Accumulate feedback from the average delay of the taps. - delaybuf[offset&bufmask] += delaybuf[(offset-avgdelay) & bufmask] * feedback; - offset++; - } - - for(ALsizei c{0};c < 2;c++) - MixSamples(temps[c], samplesOut, mGains[c].Current, mGains[c].Target, samplesToDo-base, - base, todo); - - base += todo; - } - - mOffset = offset; -} - - -void Chorus_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val) -{ - switch(param) - { - case AL_CHORUS_WAVEFORM: - if(!(val >= AL_CHORUS_MIN_WAVEFORM && val <= AL_CHORUS_MAX_WAVEFORM)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid chorus waveform"); - props->Chorus.Waveform = val; - break; - - case AL_CHORUS_PHASE: - if(!(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus phase out of range"); - props->Chorus.Phase = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param); - } -} -void Chorus_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) -{ Chorus_setParami(props, context, param, vals[0]); } -void Chorus_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_CHORUS_RATE: - if(!(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus rate out of range"); - props->Chorus.Rate = val; - break; - - case AL_CHORUS_DEPTH: - if(!(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus depth out of range"); - props->Chorus.Depth = val; - break; - - case AL_CHORUS_FEEDBACK: - if(!(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus feedback out of range"); - props->Chorus.Feedback = val; - break; - - case AL_CHORUS_DELAY: - if(!(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus delay out of range"); - props->Chorus.Delay = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param); - } -} -void Chorus_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) -{ Chorus_setParamf(props, context, param, vals[0]); } - -void Chorus_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val) -{ - switch(param) - { - case AL_CHORUS_WAVEFORM: - *val = props->Chorus.Waveform; - break; - - case AL_CHORUS_PHASE: - *val = props->Chorus.Phase; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param); - } -} -void Chorus_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) -{ Chorus_getParami(props, context, param, vals); } -void Chorus_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_CHORUS_RATE: - *val = props->Chorus.Rate; - break; - - case AL_CHORUS_DEPTH: - *val = props->Chorus.Depth; - break; - - case AL_CHORUS_FEEDBACK: - *val = props->Chorus.Feedback; - break; - - case AL_CHORUS_DELAY: - *val = props->Chorus.Delay; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param); - } -} -void Chorus_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) -{ Chorus_getParamf(props, context, param, vals); } - -DEFINE_ALEFFECT_VTABLE(Chorus); - - -struct ChorusStateFactory final : public EffectStateFactory { - EffectState *create() override { return new ChorusState{}; } - EffectProps getDefaultProps() const noexcept override; - const EffectVtable *getEffectVtable() const noexcept override { return &Chorus_vtable; } -}; - -EffectProps ChorusStateFactory::getDefaultProps() const noexcept -{ - EffectProps props{}; - props.Chorus.Waveform = AL_CHORUS_DEFAULT_WAVEFORM; - props.Chorus.Phase = AL_CHORUS_DEFAULT_PHASE; - props.Chorus.Rate = AL_CHORUS_DEFAULT_RATE; - props.Chorus.Depth = AL_CHORUS_DEFAULT_DEPTH; - props.Chorus.Feedback = AL_CHORUS_DEFAULT_FEEDBACK; - props.Chorus.Delay = AL_CHORUS_DEFAULT_DELAY; - return props; -} - - -void Flanger_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val) -{ - switch(param) - { - case AL_FLANGER_WAVEFORM: - if(!(val >= AL_FLANGER_MIN_WAVEFORM && val <= AL_FLANGER_MAX_WAVEFORM)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid flanger waveform"); - props->Chorus.Waveform = val; - break; - - case AL_FLANGER_PHASE: - if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger phase out of range"); - props->Chorus.Phase = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param); - } -} -void Flanger_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) -{ Flanger_setParami(props, context, param, vals[0]); } -void Flanger_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_FLANGER_RATE: - if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger rate out of range"); - props->Chorus.Rate = val; - break; - - case AL_FLANGER_DEPTH: - if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger depth out of range"); - props->Chorus.Depth = val; - break; - - case AL_FLANGER_FEEDBACK: - if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger feedback out of range"); - props->Chorus.Feedback = val; - break; - - case AL_FLANGER_DELAY: - if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger delay out of range"); - props->Chorus.Delay = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param); - } -} -void Flanger_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) -{ Flanger_setParamf(props, context, param, vals[0]); } - -void Flanger_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val) -{ - switch(param) - { - case AL_FLANGER_WAVEFORM: - *val = props->Chorus.Waveform; - break; - - case AL_FLANGER_PHASE: - *val = props->Chorus.Phase; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param); - } -} -void Flanger_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) -{ Flanger_getParami(props, context, param, vals); } -void Flanger_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_FLANGER_RATE: - *val = props->Chorus.Rate; - break; - - case AL_FLANGER_DEPTH: - *val = props->Chorus.Depth; - break; - - case AL_FLANGER_FEEDBACK: - *val = props->Chorus.Feedback; - break; - - case AL_FLANGER_DELAY: - *val = props->Chorus.Delay; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param); - } -} -void Flanger_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) -{ Flanger_getParamf(props, context, param, vals); } - -DEFINE_ALEFFECT_VTABLE(Flanger); - - -/* Flanger is basically a chorus with a really short delay. They can both use - * the same processing functions, so piggyback flanger on the chorus functions. - */ -struct FlangerStateFactory final : public EffectStateFactory { - EffectState *create() override { return new ChorusState{}; } - EffectProps getDefaultProps() const noexcept override; - const EffectVtable *getEffectVtable() const noexcept override { return &Flanger_vtable; } -}; - -EffectProps FlangerStateFactory::getDefaultProps() const noexcept -{ - EffectProps props{}; - props.Chorus.Waveform = AL_FLANGER_DEFAULT_WAVEFORM; - props.Chorus.Phase = AL_FLANGER_DEFAULT_PHASE; - props.Chorus.Rate = AL_FLANGER_DEFAULT_RATE; - props.Chorus.Depth = AL_FLANGER_DEFAULT_DEPTH; - props.Chorus.Feedback = AL_FLANGER_DEFAULT_FEEDBACK; - props.Chorus.Delay = AL_FLANGER_DEFAULT_DELAY; - return props; -} - -} // namespace - -EffectStateFactory *ChorusStateFactory_getFactory() -{ - static ChorusStateFactory ChorusFactory{}; - return &ChorusFactory; -} - -EffectStateFactory *FlangerStateFactory_getFactory() -{ - static FlangerStateFactory FlangerFactory{}; - return &FlangerFactory; -} diff --git a/Alc/effects/compressor.cpp b/Alc/effects/compressor.cpp deleted file mode 100644 index 4a487097..00000000 --- a/Alc/effects/compressor.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2013 by Anis A. Hireche - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include - -#include "alcmain.h" -#include "alcontext.h" -#include "alu.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "vecmat.h" - - -namespace { - -#define AMP_ENVELOPE_MIN 0.5f -#define AMP_ENVELOPE_MAX 2.0f - -#define ATTACK_TIME 0.1f /* 100ms to rise from min to max */ -#define RELEASE_TIME 0.2f /* 200ms to drop from max to min */ - - -struct CompressorState final : public EffectState { - /* Effect gains for each channel */ - ALfloat mGain[MAX_AMBI_CHANNELS][MAX_OUTPUT_CHANNELS]{}; - - /* Effect parameters */ - ALboolean mEnabled{AL_TRUE}; - ALfloat mAttackMult{1.0f}; - ALfloat mReleaseMult{1.0f}; - ALfloat mEnvFollower{1.0f}; - - - ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; - - DEF_NEWDEL(CompressorState) -}; - -ALboolean CompressorState::deviceUpdate(const ALCdevice *device) -{ - /* Number of samples to do a full attack and release (non-integer sample - * counts are okay). - */ - const ALfloat attackCount = static_cast(device->Frequency) * ATTACK_TIME; - const ALfloat releaseCount = static_cast(device->Frequency) * RELEASE_TIME; - - /* Calculate per-sample multipliers to attack and release at the desired - * rates. - */ - mAttackMult = std::pow(AMP_ENVELOPE_MAX/AMP_ENVELOPE_MIN, 1.0f/attackCount); - mReleaseMult = std::pow(AMP_ENVELOPE_MIN/AMP_ENVELOPE_MAX, 1.0f/releaseCount); - - return AL_TRUE; -} - -void CompressorState::update(const ALCcontext*, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) -{ - mEnabled = props->Compressor.OnOff; - - mOutTarget = target.Main->Buffer; - for(size_t i{0u};i < slot->Wet.Buffer.size();++i) - { - auto coeffs = GetAmbiIdentityRow(i); - ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mGain[i]); - } -} - -void CompressorState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) -{ - for(ALsizei base{0};base < samplesToDo;) - { - ALfloat gains[256]; - const ALsizei td{mini(256, samplesToDo-base)}; - - /* Generate the per-sample gains from the signal envelope. */ - ALfloat env{mEnvFollower}; - if(mEnabled) - { - for(ALsizei i{0};i < td;++i) - { - /* Clamp the absolute amplitude to the defined envelope limits, - * then attack or release the envelope to reach it. - */ - const ALfloat amplitude{clampf(std::fabs(samplesIn[0][base+i]), AMP_ENVELOPE_MIN, - AMP_ENVELOPE_MAX)}; - if(amplitude > env) - env = minf(env*mAttackMult, amplitude); - else if(amplitude < env) - env = maxf(env*mReleaseMult, amplitude); - - /* Apply the reciprocal of the envelope to normalize the volume - * (compress the dynamic range). - */ - gains[i] = 1.0f / env; - } - } - else - { - /* Same as above, except the amplitude is forced to 1. This helps - * ensure smooth gain changes when the compressor is turned on and - * off. - */ - for(ALsizei i{0};i < td;++i) - { - const ALfloat amplitude{1.0f}; - if(amplitude > env) - env = minf(env*mAttackMult, amplitude); - else if(amplitude < env) - env = maxf(env*mReleaseMult, amplitude); - - gains[i] = 1.0f / env; - } - } - mEnvFollower = env; - - /* Now compress the signal amplitude to output. */ - ASSUME(numInput > 0); - for(ALsizei j{0};j < numInput;j++) - { - const ALfloat *outgains{mGain[j]}; - for(FloatBufferLine &output : samplesOut) - { - const ALfloat gain{*(outgains++)}; - if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - for(ALsizei i{0};i < td;i++) - output[base+i] += samplesIn[j][base+i] * gains[i] * gain; - } - } - - base += td; - } -} - - -void Compressor_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val) -{ - switch(param) - { - case AL_COMPRESSOR_ONOFF: - if(!(val >= AL_COMPRESSOR_MIN_ONOFF && val <= AL_COMPRESSOR_MAX_ONOFF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Compressor state out of range"); - props->Compressor.OnOff = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid compressor integer property 0x%04x", - param); - } -} -void Compressor_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) -{ Compressor_setParami(props, context, param, vals[0]); } -void Compressor_setParamf(EffectProps*, ALCcontext *context, ALenum param, ALfloat) -{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param); } -void Compressor_setParamfv(EffectProps*, ALCcontext *context, ALenum param, const ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float-vector property 0x%04x", param); } - -void Compressor_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val) -{ - switch(param) - { - case AL_COMPRESSOR_ONOFF: - *val = props->Compressor.OnOff; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid compressor integer property 0x%04x", - param); - } -} -void Compressor_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) -{ Compressor_getParami(props, context, param, vals); } -void Compressor_getParamf(const EffectProps*, ALCcontext *context, ALenum param, ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param); } -void Compressor_getParamfv(const EffectProps*, ALCcontext *context, ALenum param, ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float-vector property 0x%04x", param); } - -DEFINE_ALEFFECT_VTABLE(Compressor); - - -struct CompressorStateFactory final : public EffectStateFactory { - EffectState *create() override { return new CompressorState{}; } - EffectProps getDefaultProps() const noexcept override; - const EffectVtable *getEffectVtable() const noexcept override { return &Compressor_vtable; } -}; - -EffectProps CompressorStateFactory::getDefaultProps() const noexcept -{ - EffectProps props{}; - props.Compressor.OnOff = AL_COMPRESSOR_DEFAULT_ONOFF; - return props; -} - -} // namespace - -EffectStateFactory *CompressorStateFactory_getFactory() -{ - static CompressorStateFactory CompressorFactory{}; - return &CompressorFactory; -} diff --git a/Alc/effects/dedicated.cpp b/Alc/effects/dedicated.cpp deleted file mode 100644 index b31b3750..00000000 --- a/Alc/effects/dedicated.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2011 by Chris Robinson. - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include "alcmain.h" -#include "alcontext.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" - - -namespace { - -struct DedicatedState final : public EffectState { - ALfloat mCurrentGains[MAX_OUTPUT_CHANNELS]; - ALfloat mTargetGains[MAX_OUTPUT_CHANNELS]; - - - ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; - - DEF_NEWDEL(DedicatedState) -}; - -ALboolean DedicatedState::deviceUpdate(const ALCdevice*) -{ - std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f); - return AL_TRUE; -} - -void DedicatedState::update(const ALCcontext*, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) -{ - std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f); - - const ALfloat Gain{slot->Params.Gain * props->Dedicated.Gain}; - - if(slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) - { - const int idx{!target.RealOut ? -1 : GetChannelIdxByName(*target.RealOut, LFE)}; - if(idx != -1) - { - mOutTarget = target.RealOut->Buffer; - mTargetGains[idx] = Gain; - } - } - else if(slot->Params.EffectType == AL_EFFECT_DEDICATED_DIALOGUE) - { - /* Dialog goes to the front-center speaker if it exists, otherwise it - * plays from the front-center location. */ - const int idx{!target.RealOut ? -1 : GetChannelIdxByName(*target.RealOut, FrontCenter)}; - if(idx != -1) - { - mOutTarget = target.RealOut->Buffer; - mTargetGains[idx] = Gain; - } - else - { - ALfloat coeffs[MAX_AMBI_CHANNELS]; - CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); - - mOutTarget = target.Main->Buffer; - ComputePanGains(target.Main, coeffs, Gain, mTargetGains); - } - } -} - -void DedicatedState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) -{ - MixSamples(samplesIn[0].data(), samplesOut, mCurrentGains, mTargetGains, samplesToDo, 0, - samplesToDo); -} - - -void Dedicated_setParami(EffectProps*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param); } -void Dedicated_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x", param); } -void Dedicated_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_DEDICATED_GAIN: - if(!(val >= 0.0f && std::isfinite(val))) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Dedicated gain out of range"); - props->Dedicated.Gain = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param); - } -} -void Dedicated_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) -{ Dedicated_setParamf(props, context, param, vals[0]); } - -void Dedicated_getParami(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param); } -void Dedicated_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x", param); } -void Dedicated_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_DEDICATED_GAIN: - *val = props->Dedicated.Gain; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param); - } -} -void Dedicated_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) -{ Dedicated_getParamf(props, context, param, vals); } - -DEFINE_ALEFFECT_VTABLE(Dedicated); - - -struct DedicatedStateFactory final : public EffectStateFactory { - EffectState *create() override { return new DedicatedState{}; } - EffectProps getDefaultProps() const noexcept override; - const EffectVtable *getEffectVtable() const noexcept override { return &Dedicated_vtable; } -}; - -EffectProps DedicatedStateFactory::getDefaultProps() const noexcept -{ - EffectProps props{}; - props.Dedicated.Gain = 1.0f; - return props; -} - -} // namespace - -EffectStateFactory *DedicatedStateFactory_getFactory() -{ - static DedicatedStateFactory DedicatedFactory{}; - return &DedicatedFactory; -} diff --git a/Alc/effects/distortion.cpp b/Alc/effects/distortion.cpp deleted file mode 100644 index 59557395..00000000 --- a/Alc/effects/distortion.cpp +++ /dev/null @@ -1,269 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2013 by Mike Gorchak - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include - -#include "alcmain.h" -#include "alcontext.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" -#include "filters/biquad.h" - - -namespace { - -struct DistortionState final : public EffectState { - /* Effect gains for each channel */ - ALfloat mGain[MAX_OUTPUT_CHANNELS]{}; - - /* Effect parameters */ - BiquadFilter mLowpass; - BiquadFilter mBandpass; - ALfloat mAttenuation{}; - ALfloat mEdgeCoeff{}; - - ALfloat mBuffer[2][BUFFERSIZE]{}; - - - ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; - - DEF_NEWDEL(DistortionState) -}; - -ALboolean DistortionState::deviceUpdate(const ALCdevice*) -{ - mLowpass.clear(); - mBandpass.clear(); - return AL_TRUE; -} - -void DistortionState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) -{ - const ALCdevice *device{context->Device}; - - /* Store waveshaper edge settings. */ - const ALfloat edge{ - minf(std::sin(al::MathDefs::Pi()*0.5f * props->Distortion.Edge), 0.99f)}; - mEdgeCoeff = 2.0f * edge / (1.0f-edge); - - ALfloat cutoff{props->Distortion.LowpassCutoff}; - /* Bandwidth value is constant in octaves. */ - ALfloat bandwidth{(cutoff / 2.0f) / (cutoff * 0.67f)}; - /* Multiply sampling frequency by the amount of oversampling done during - * processing. - */ - auto frequency = static_cast(device->Frequency); - mLowpass.setParams(BiquadType::LowPass, 1.0f, cutoff / (frequency*4.0f), - mLowpass.rcpQFromBandwidth(cutoff / (frequency*4.0f), bandwidth)); - - cutoff = props->Distortion.EQCenter; - /* Convert bandwidth in Hz to octaves. */ - bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f); - mBandpass.setParams(BiquadType::BandPass, 1.0f, cutoff / (frequency*4.0f), - mBandpass.rcpQFromBandwidth(cutoff / (frequency*4.0f), bandwidth)); - - ALfloat coeffs[MAX_AMBI_CHANNELS]; - CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); - - mOutTarget = target.Main->Buffer; - ComputePanGains(target.Main, coeffs, slot->Params.Gain*props->Distortion.Gain, mGain); -} - -void DistortionState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) -{ - const ALfloat fc{mEdgeCoeff}; - for(ALsizei base{0};base < samplesToDo;) - { - /* Perform 4x oversampling to avoid aliasing. Oversampling greatly - * improves distortion quality and allows to implement lowpass and - * bandpass filters using high frequencies, at which classic IIR - * filters became unstable. - */ - ALsizei todo{mini(BUFFERSIZE, (samplesToDo-base) * 4)}; - - /* Fill oversample buffer using zero stuffing. Multiply the sample by - * the amount of oversampling to maintain the signal's power. - */ - for(ALsizei i{0};i < todo;i++) - mBuffer[0][i] = !(i&3) ? samplesIn[0][(i>>2)+base] * 4.0f : 0.0f; - - /* First step, do lowpass filtering of original signal. Additionally - * perform buffer interpolation and lowpass cutoff for oversampling - * (which is fortunately first step of distortion). So combine three - * operations into the one. - */ - mLowpass.process(mBuffer[1], mBuffer[0], todo); - - /* Second step, do distortion using waveshaper function to emulate - * signal processing during tube overdriving. Three steps of - * waveshaping are intended to modify waveform without boost/clipping/ - * attenuation process. - */ - for(ALsizei i{0};i < todo;i++) - { - ALfloat smp{mBuffer[1][i]}; - - smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)); - smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)) * -1.0f; - smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)); - - mBuffer[0][i] = smp; - } - - /* Third step, do bandpass filtering of distorted signal. */ - mBandpass.process(mBuffer[1], mBuffer[0], todo); - - todo >>= 2; - const ALfloat *outgains{mGain}; - for(FloatBufferLine &output : samplesOut) - { - /* Fourth step, final, do attenuation and perform decimation, - * storing only one sample out of four. - */ - const ALfloat gain{*(outgains++)}; - if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - for(ALsizei i{0};i < todo;i++) - output[base+i] += gain * mBuffer[1][i*4]; - } - - base += todo; - } -} - - -void Distortion_setParami(EffectProps*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param); } -void Distortion_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x", param); } -void Distortion_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_DISTORTION_EDGE: - if(!(val >= AL_DISTORTION_MIN_EDGE && val <= AL_DISTORTION_MAX_EDGE)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion edge out of range"); - props->Distortion.Edge = val; - break; - - case AL_DISTORTION_GAIN: - if(!(val >= AL_DISTORTION_MIN_GAIN && val <= AL_DISTORTION_MAX_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion gain out of range"); - props->Distortion.Gain = val; - break; - - case AL_DISTORTION_LOWPASS_CUTOFF: - if(!(val >= AL_DISTORTION_MIN_LOWPASS_CUTOFF && val <= AL_DISTORTION_MAX_LOWPASS_CUTOFF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion low-pass cutoff out of range"); - props->Distortion.LowpassCutoff = val; - break; - - case AL_DISTORTION_EQCENTER: - if(!(val >= AL_DISTORTION_MIN_EQCENTER && val <= AL_DISTORTION_MAX_EQCENTER)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion EQ center out of range"); - props->Distortion.EQCenter = val; - break; - - case AL_DISTORTION_EQBANDWIDTH: - if(!(val >= AL_DISTORTION_MIN_EQBANDWIDTH && val <= AL_DISTORTION_MAX_EQBANDWIDTH)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion EQ bandwidth out of range"); - props->Distortion.EQBandwidth = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", - param); - } -} -void Distortion_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) -{ Distortion_setParamf(props, context, param, vals[0]); } - -void Distortion_getParami(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param); } -void Distortion_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x", param); } -void Distortion_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_DISTORTION_EDGE: - *val = props->Distortion.Edge; - break; - - case AL_DISTORTION_GAIN: - *val = props->Distortion.Gain; - break; - - case AL_DISTORTION_LOWPASS_CUTOFF: - *val = props->Distortion.LowpassCutoff; - break; - - case AL_DISTORTION_EQCENTER: - *val = props->Distortion.EQCenter; - break; - - case AL_DISTORTION_EQBANDWIDTH: - *val = props->Distortion.EQBandwidth; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", - param); - } -} -void Distortion_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) -{ Distortion_getParamf(props, context, param, vals); } - -DEFINE_ALEFFECT_VTABLE(Distortion); - - -struct DistortionStateFactory final : public EffectStateFactory { - EffectState *create() override { return new DistortionState{}; } - EffectProps getDefaultProps() const noexcept override; - const EffectVtable *getEffectVtable() const noexcept override { return &Distortion_vtable; } -}; - -EffectProps DistortionStateFactory::getDefaultProps() const noexcept -{ - EffectProps props{}; - props.Distortion.Edge = AL_DISTORTION_DEFAULT_EDGE; - props.Distortion.Gain = AL_DISTORTION_DEFAULT_GAIN; - props.Distortion.LowpassCutoff = AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF; - props.Distortion.EQCenter = AL_DISTORTION_DEFAULT_EQCENTER; - props.Distortion.EQBandwidth = AL_DISTORTION_DEFAULT_EQBANDWIDTH; - return props; -} - -} // namespace - -EffectStateFactory *DistortionStateFactory_getFactory() -{ - static DistortionStateFactory DistortionFactory{}; - return &DistortionFactory; -} diff --git a/Alc/effects/echo.cpp b/Alc/effects/echo.cpp deleted file mode 100644 index c10f2eb2..00000000 --- a/Alc/effects/echo.cpp +++ /dev/null @@ -1,271 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2009 by Chris Robinson. - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include - -#include "alcmain.h" -#include "alcontext.h" -#include "alFilter.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" -#include "filters/biquad.h" -#include "vector.h" - - -namespace { - -struct EchoState final : public EffectState { - al::vector mSampleBuffer; - - // The echo is two tap. The delay is the number of samples from before the - // current offset - struct { - ALsizei delay{0}; - } mTap[2]; - ALsizei mOffset{0}; - - /* The panning gains for the two taps */ - struct { - ALfloat Current[MAX_OUTPUT_CHANNELS]{}; - ALfloat Target[MAX_OUTPUT_CHANNELS]{}; - } mGains[2]; - - BiquadFilter mFilter; - ALfloat mFeedGain{0.0f}; - - alignas(16) ALfloat mTempBuffer[2][BUFFERSIZE]; - - ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; - - DEF_NEWDEL(EchoState) -}; - -ALboolean EchoState::deviceUpdate(const ALCdevice *Device) -{ - ALuint maxlen; - - // Use the next power of 2 for the buffer length, so the tap offsets can be - // wrapped using a mask instead of a modulo - maxlen = float2int(AL_ECHO_MAX_DELAY*Device->Frequency + 0.5f) + - float2int(AL_ECHO_MAX_LRDELAY*Device->Frequency + 0.5f); - maxlen = NextPowerOf2(maxlen); - if(maxlen <= 0) return AL_FALSE; - - if(maxlen != mSampleBuffer.size()) - { - mSampleBuffer.resize(maxlen); - mSampleBuffer.shrink_to_fit(); - } - - std::fill(mSampleBuffer.begin(), mSampleBuffer.end(), 0.0f); - for(auto &e : mGains) - { - std::fill(std::begin(e.Current), std::end(e.Current), 0.0f); - std::fill(std::begin(e.Target), std::end(e.Target), 0.0f); - } - - return AL_TRUE; -} - -void EchoState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) -{ - const ALCdevice *device = context->Device; - const auto frequency = static_cast(device->Frequency); - - mTap[0].delay = maxi(float2int(props->Echo.Delay*frequency + 0.5f), 1); - mTap[1].delay = float2int(props->Echo.LRDelay*frequency + 0.5f) + mTap[0].delay; - - const ALfloat gainhf{maxf(1.0f - props->Echo.Damping, 0.0625f)}; /* Limit -24dB */ - mFilter.setParams(BiquadType::HighShelf, gainhf, LOWPASSFREQREF/frequency, - mFilter.rcpQFromSlope(gainhf, 1.0f)); - - mFeedGain = props->Echo.Feedback; - - /* Convert echo spread (where 0 = center, +/-1 = sides) to angle. */ - const ALfloat angle{std::asin(props->Echo.Spread)}; - - ALfloat coeffs[2][MAX_AMBI_CHANNELS]; - CalcAngleCoeffs(-angle, 0.0f, 0.0f, coeffs[0]); - CalcAngleCoeffs( angle, 0.0f, 0.0f, coeffs[1]); - - mOutTarget = target.Main->Buffer; - ComputePanGains(target.Main, coeffs[0], slot->Params.Gain, mGains[0].Target); - ComputePanGains(target.Main, coeffs[1], slot->Params.Gain, mGains[1].Target); -} - -void EchoState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) -{ - const auto mask = static_cast(mSampleBuffer.size()-1); - ALfloat *RESTRICT delaybuf{mSampleBuffer.data()}; - ALsizei offset{mOffset}; - ALsizei tap1{offset - mTap[0].delay}; - ALsizei tap2{offset - mTap[1].delay}; - ALfloat z1, z2; - - ASSUME(samplesToDo > 0); - ASSUME(mask > 0); - - std::tie(z1, z2) = mFilter.getComponents(); - for(ALsizei i{0};i < samplesToDo;) - { - offset &= mask; - tap1 &= mask; - tap2 &= mask; - - ALsizei td{mini(mask+1 - maxi(offset, maxi(tap1, tap2)), samplesToDo-i)}; - do { - /* Feed the delay buffer's input first. */ - delaybuf[offset] = samplesIn[0][i]; - - /* Get delayed output from the first and second taps. Use the - * second tap for feedback. - */ - mTempBuffer[0][i] = delaybuf[tap1++]; - mTempBuffer[1][i] = delaybuf[tap2++]; - const float feedb{mTempBuffer[1][i++]}; - - /* Add feedback to the delay buffer with damping and attenuation. */ - delaybuf[offset++] += mFilter.processOne(feedb, z1, z2) * mFeedGain; - } while(--td); - } - mFilter.setComponents(z1, z2); - mOffset = offset; - - for(ALsizei c{0};c < 2;c++) - MixSamples(mTempBuffer[c], samplesOut, mGains[c].Current, mGains[c].Target, samplesToDo, 0, - samplesToDo); -} - - -void Echo_setParami(EffectProps*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param); } -void Echo_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param); } -void Echo_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_ECHO_DELAY: - if(!(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo delay out of range"); - props->Echo.Delay = val; - break; - - case AL_ECHO_LRDELAY: - if(!(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo LR delay out of range"); - props->Echo.LRDelay = val; - break; - - case AL_ECHO_DAMPING: - if(!(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo damping out of range"); - props->Echo.Damping = val; - break; - - case AL_ECHO_FEEDBACK: - if(!(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo feedback out of range"); - props->Echo.Feedback = val; - break; - - case AL_ECHO_SPREAD: - if(!(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo spread out of range"); - props->Echo.Spread = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param); - } -} -void Echo_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) -{ Echo_setParamf(props, context, param, vals[0]); } - -void Echo_getParami(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param); } -void Echo_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param); } -void Echo_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_ECHO_DELAY: - *val = props->Echo.Delay; - break; - - case AL_ECHO_LRDELAY: - *val = props->Echo.LRDelay; - break; - - case AL_ECHO_DAMPING: - *val = props->Echo.Damping; - break; - - case AL_ECHO_FEEDBACK: - *val = props->Echo.Feedback; - break; - - case AL_ECHO_SPREAD: - *val = props->Echo.Spread; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param); - } -} -void Echo_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) -{ Echo_getParamf(props, context, param, vals); } - -DEFINE_ALEFFECT_VTABLE(Echo); - - -struct EchoStateFactory final : public EffectStateFactory { - EffectState *create() override { return new EchoState{}; } - EffectProps getDefaultProps() const noexcept override; - const EffectVtable *getEffectVtable() const noexcept override { return &Echo_vtable; } -}; - -EffectProps EchoStateFactory::getDefaultProps() const noexcept -{ - EffectProps props{}; - props.Echo.Delay = AL_ECHO_DEFAULT_DELAY; - props.Echo.LRDelay = AL_ECHO_DEFAULT_LRDELAY; - props.Echo.Damping = AL_ECHO_DEFAULT_DAMPING; - props.Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK; - props.Echo.Spread = AL_ECHO_DEFAULT_SPREAD; - return props; -} - -} // namespace - -EffectStateFactory *EchoStateFactory_getFactory() -{ - static EchoStateFactory EchoFactory{}; - return &EchoFactory; -} diff --git a/Alc/effects/equalizer.cpp b/Alc/effects/equalizer.cpp deleted file mode 100644 index 69ab5021..00000000 --- a/Alc/effects/equalizer.cpp +++ /dev/null @@ -1,337 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2013 by Mike Gorchak - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include -#include - -#include "alcmain.h" -#include "alcontext.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" -#include "filters/biquad.h" -#include "vecmat.h" - - -namespace { - -/* The document "Effects Extension Guide.pdf" says that low and high * - * frequencies are cutoff frequencies. This is not fully correct, they * - * are corner frequencies for low and high shelf filters. If they were * - * just cutoff frequencies, there would be no need in cutoff frequency * - * gains, which are present. Documentation for "Creative Proteus X2" * - * software describes 4-band equalizer functionality in a much better * - * way. This equalizer seems to be a predecessor of OpenAL 4-band * - * equalizer. With low and high shelf filters we are able to cutoff * - * frequencies below and/or above corner frequencies using attenuation * - * gains (below 1.0) and amplify all low and/or high frequencies using * - * gains above 1.0. * - * * - * Low-shelf Low Mid Band High Mid Band High-shelf * - * corner center center corner * - * frequency frequency frequency frequency * - * 50Hz..800Hz 200Hz..3000Hz 1000Hz..8000Hz 4000Hz..16000Hz * - * * - * | | | | * - * | | | | * - * B -----+ /--+--\ /--+--\ +----- * - * O |\ | | | | | | /| * - * O | \ - | - - | - / | * - * S + | \ | | | | | | / | * - * T | | | | | | | | | | * - * ---------+---------------+------------------+---------------+-------- * - * C | | | | | | | | | | * - * U - | / | | | | | | \ | * - * T | / - | - - | - \ | * - * O |/ | | | | | | \| * - * F -----+ \--+--/ \--+--/ +----- * - * F | | | | * - * | | | | * - * * - * Gains vary from 0.126 up to 7.943, which means from -18dB attenuation * - * up to +18dB amplification. Band width varies from 0.01 up to 1.0 in * - * octaves for two mid bands. * - * * - * Implementation is based on the "Cookbook formulae for audio EQ biquad * - * filter coefficients" by Robert Bristow-Johnson * - * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */ - - -struct EqualizerState final : public EffectState { - struct { - /* Effect parameters */ - BiquadFilter filter[4]; - - /* Effect gains for each channel */ - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]{}; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]{}; - } mChans[MAX_AMBI_CHANNELS]; - - ALfloat mSampleBuffer[BUFFERSIZE]{}; - - - ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; - - DEF_NEWDEL(EqualizerState) -}; - -ALboolean EqualizerState::deviceUpdate(const ALCdevice*) -{ - for(auto &e : mChans) - { - std::for_each(std::begin(e.filter), std::end(e.filter), - std::mem_fn(&BiquadFilter::clear)); - std::fill(std::begin(e.CurrentGains), std::end(e.CurrentGains), 0.0f); - } - return AL_TRUE; -} - -void EqualizerState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) -{ - const ALCdevice *device = context->Device; - auto frequency = static_cast(device->Frequency); - ALfloat gain, f0norm; - - /* Calculate coefficients for the each type of filter. Note that the shelf - * filters' gain is for the reference frequency, which is the centerpoint - * of the transition band. - */ - gain = maxf(sqrtf(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */ - f0norm = props->Equalizer.LowCutoff/frequency; - mChans[0].filter[0].setParams(BiquadType::LowShelf, gain, f0norm, - BiquadFilter::rcpQFromSlope(gain, 0.75f)); - - gain = maxf(props->Equalizer.Mid1Gain, 0.0625f); - f0norm = props->Equalizer.Mid1Center/frequency; - mChans[0].filter[1].setParams(BiquadType::Peaking, gain, f0norm, - BiquadFilter::rcpQFromBandwidth(f0norm, props->Equalizer.Mid1Width)); - - gain = maxf(props->Equalizer.Mid2Gain, 0.0625f); - f0norm = props->Equalizer.Mid2Center/frequency; - mChans[0].filter[2].setParams(BiquadType::Peaking, gain, f0norm, - BiquadFilter::rcpQFromBandwidth(f0norm, props->Equalizer.Mid2Width)); - - gain = maxf(sqrtf(props->Equalizer.HighGain), 0.0625f); - f0norm = props->Equalizer.HighCutoff/frequency; - mChans[0].filter[3].setParams(BiquadType::HighShelf, gain, f0norm, - BiquadFilter::rcpQFromSlope(gain, 0.75f)); - - /* Copy the filter coefficients for the other input channels. */ - for(size_t i{1u};i < slot->Wet.Buffer.size();++i) - { - mChans[i].filter[0].copyParamsFrom(mChans[0].filter[0]); - mChans[i].filter[1].copyParamsFrom(mChans[0].filter[1]); - mChans[i].filter[2].copyParamsFrom(mChans[0].filter[2]); - mChans[i].filter[3].copyParamsFrom(mChans[0].filter[3]); - } - - mOutTarget = target.Main->Buffer; - for(size_t i{0u};i < slot->Wet.Buffer.size();++i) - { - auto coeffs = GetAmbiIdentityRow(i); - ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mChans[i].TargetGains); - } -} - -void EqualizerState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) -{ - ASSUME(numInput > 0); - for(ALsizei c{0};c < numInput;c++) - { - mChans[c].filter[0].process(mSampleBuffer, samplesIn[c].data(), samplesToDo); - mChans[c].filter[1].process(mSampleBuffer, mSampleBuffer, samplesToDo); - mChans[c].filter[2].process(mSampleBuffer, mSampleBuffer, samplesToDo); - mChans[c].filter[3].process(mSampleBuffer, mSampleBuffer, samplesToDo); - - MixSamples(mSampleBuffer, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, - samplesToDo, 0, samplesToDo); - } -} - - -void Equalizer_setParami(EffectProps*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param); } -void Equalizer_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x", param); } -void Equalizer_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_EQUALIZER_LOW_GAIN: - if(!(val >= AL_EQUALIZER_MIN_LOW_GAIN && val <= AL_EQUALIZER_MAX_LOW_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer low-band gain out of range"); - props->Equalizer.LowGain = val; - break; - - case AL_EQUALIZER_LOW_CUTOFF: - if(!(val >= AL_EQUALIZER_MIN_LOW_CUTOFF && val <= AL_EQUALIZER_MAX_LOW_CUTOFF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer low-band cutoff out of range"); - props->Equalizer.LowCutoff = val; - break; - - case AL_EQUALIZER_MID1_GAIN: - if(!(val >= AL_EQUALIZER_MIN_MID1_GAIN && val <= AL_EQUALIZER_MAX_MID1_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band gain out of range"); - props->Equalizer.Mid1Gain = val; - break; - - case AL_EQUALIZER_MID1_CENTER: - if(!(val >= AL_EQUALIZER_MIN_MID1_CENTER && val <= AL_EQUALIZER_MAX_MID1_CENTER)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band center out of range"); - props->Equalizer.Mid1Center = val; - break; - - case AL_EQUALIZER_MID1_WIDTH: - if(!(val >= AL_EQUALIZER_MIN_MID1_WIDTH && val <= AL_EQUALIZER_MAX_MID1_WIDTH)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band width out of range"); - props->Equalizer.Mid1Width = val; - break; - - case AL_EQUALIZER_MID2_GAIN: - if(!(val >= AL_EQUALIZER_MIN_MID2_GAIN && val <= AL_EQUALIZER_MAX_MID2_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band gain out of range"); - props->Equalizer.Mid2Gain = val; - break; - - case AL_EQUALIZER_MID2_CENTER: - if(!(val >= AL_EQUALIZER_MIN_MID2_CENTER && val <= AL_EQUALIZER_MAX_MID2_CENTER)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band center out of range"); - props->Equalizer.Mid2Center = val; - break; - - case AL_EQUALIZER_MID2_WIDTH: - if(!(val >= AL_EQUALIZER_MIN_MID2_WIDTH && val <= AL_EQUALIZER_MAX_MID2_WIDTH)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band width out of range"); - props->Equalizer.Mid2Width = val; - break; - - case AL_EQUALIZER_HIGH_GAIN: - if(!(val >= AL_EQUALIZER_MIN_HIGH_GAIN && val <= AL_EQUALIZER_MAX_HIGH_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer high-band gain out of range"); - props->Equalizer.HighGain = val; - break; - - case AL_EQUALIZER_HIGH_CUTOFF: - if(!(val >= AL_EQUALIZER_MIN_HIGH_CUTOFF && val <= AL_EQUALIZER_MAX_HIGH_CUTOFF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer high-band cutoff out of range"); - props->Equalizer.HighCutoff = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param); - } -} -void Equalizer_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) -{ Equalizer_setParamf(props, context, param, vals[0]); } - -void Equalizer_getParami(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param); } -void Equalizer_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x", param); } -void Equalizer_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_EQUALIZER_LOW_GAIN: - *val = props->Equalizer.LowGain; - break; - - case AL_EQUALIZER_LOW_CUTOFF: - *val = props->Equalizer.LowCutoff; - break; - - case AL_EQUALIZER_MID1_GAIN: - *val = props->Equalizer.Mid1Gain; - break; - - case AL_EQUALIZER_MID1_CENTER: - *val = props->Equalizer.Mid1Center; - break; - - case AL_EQUALIZER_MID1_WIDTH: - *val = props->Equalizer.Mid1Width; - break; - - case AL_EQUALIZER_MID2_GAIN: - *val = props->Equalizer.Mid2Gain; - break; - - case AL_EQUALIZER_MID2_CENTER: - *val = props->Equalizer.Mid2Center; - break; - - case AL_EQUALIZER_MID2_WIDTH: - *val = props->Equalizer.Mid2Width; - break; - - case AL_EQUALIZER_HIGH_GAIN: - *val = props->Equalizer.HighGain; - break; - - case AL_EQUALIZER_HIGH_CUTOFF: - *val = props->Equalizer.HighCutoff; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param); - } -} -void Equalizer_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) -{ Equalizer_getParamf(props, context, param, vals); } - -DEFINE_ALEFFECT_VTABLE(Equalizer); - - -struct EqualizerStateFactory final : public EffectStateFactory { - EffectState *create() override { return new EqualizerState{}; } - EffectProps getDefaultProps() const noexcept override; - const EffectVtable *getEffectVtable() const noexcept override { return &Equalizer_vtable; } -}; - -EffectProps EqualizerStateFactory::getDefaultProps() const noexcept -{ - EffectProps props{}; - props.Equalizer.LowCutoff = AL_EQUALIZER_DEFAULT_LOW_CUTOFF; - props.Equalizer.LowGain = AL_EQUALIZER_DEFAULT_LOW_GAIN; - props.Equalizer.Mid1Center = AL_EQUALIZER_DEFAULT_MID1_CENTER; - props.Equalizer.Mid1Gain = AL_EQUALIZER_DEFAULT_MID1_GAIN; - props.Equalizer.Mid1Width = AL_EQUALIZER_DEFAULT_MID1_WIDTH; - props.Equalizer.Mid2Center = AL_EQUALIZER_DEFAULT_MID2_CENTER; - props.Equalizer.Mid2Gain = AL_EQUALIZER_DEFAULT_MID2_GAIN; - props.Equalizer.Mid2Width = AL_EQUALIZER_DEFAULT_MID2_WIDTH; - props.Equalizer.HighCutoff = AL_EQUALIZER_DEFAULT_HIGH_CUTOFF; - props.Equalizer.HighGain = AL_EQUALIZER_DEFAULT_HIGH_GAIN; - return props; -} - -} // namespace - -EffectStateFactory *EqualizerStateFactory_getFactory() -{ - static EqualizerStateFactory EqualizerFactory{}; - return &EqualizerFactory; -} diff --git a/Alc/effects/fshifter.cpp b/Alc/effects/fshifter.cpp deleted file mode 100644 index b47aa00e..00000000 --- a/Alc/effects/fshifter.cpp +++ /dev/null @@ -1,301 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2018 by Raul Herraiz. - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "alcmain.h" -#include "alcontext.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" - -#include "alcomplex.h" - -namespace { - -using complex_d = std::complex; - -#define HIL_SIZE 1024 -#define OVERSAMP (1<<2) - -#define HIL_STEP (HIL_SIZE / OVERSAMP) -#define FIFO_LATENCY (HIL_STEP * (OVERSAMP-1)) - -/* Define a Hann window, used to filter the HIL input and output. */ -/* Making this constexpr seems to require C++14. */ -std::array InitHannWindow() -{ - std::array ret; - /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */ - for(ALsizei i{0};i < HIL_SIZE>>1;i++) - { - ALdouble val = std::sin(al::MathDefs::Pi() * i / ALdouble{HIL_SIZE-1}); - ret[i] = ret[HIL_SIZE-1-i] = val * val; - } - return ret; -} -alignas(16) const std::array HannWindow = InitHannWindow(); - - -struct FshifterState final : public EffectState { - /* Effect parameters */ - ALsizei mCount{}; - ALsizei mPhaseStep{}; - ALsizei mPhase{}; - ALdouble mLdSign{}; - - /*Effects buffers*/ - ALfloat mInFIFO[HIL_SIZE]{}; - complex_d mOutFIFO[HIL_SIZE]{}; - complex_d mOutputAccum[HIL_SIZE]{}; - complex_d mAnalytic[HIL_SIZE]{}; - complex_d mOutdata[BUFFERSIZE]{}; - - alignas(16) ALfloat mBufferOut[BUFFERSIZE]{}; - - /* Effect gains for each output channel */ - ALfloat mCurrentGains[MAX_OUTPUT_CHANNELS]{}; - ALfloat mTargetGains[MAX_OUTPUT_CHANNELS]{}; - - - ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; - - DEF_NEWDEL(FshifterState) -}; - -ALboolean FshifterState::deviceUpdate(const ALCdevice*) -{ - /* (Re-)initializing parameters and clear the buffers. */ - mCount = FIFO_LATENCY; - mPhaseStep = 0; - mPhase = 0; - mLdSign = 1.0; - - std::fill(std::begin(mInFIFO), std::end(mInFIFO), 0.0f); - std::fill(std::begin(mOutFIFO), std::end(mOutFIFO), complex_d{}); - std::fill(std::begin(mOutputAccum), std::end(mOutputAccum), complex_d{}); - std::fill(std::begin(mAnalytic), std::end(mAnalytic), complex_d{}); - - std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f); - std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f); - - return AL_TRUE; -} - -void FshifterState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) -{ - const ALCdevice *device{context->Device}; - - ALfloat step{props->Fshifter.Frequency / static_cast(device->Frequency)}; - mPhaseStep = fastf2i(minf(step, 0.5f) * FRACTIONONE); - - switch(props->Fshifter.LeftDirection) - { - case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: - mLdSign = -1.0; - break; - - case AL_FREQUENCY_SHIFTER_DIRECTION_UP: - mLdSign = 1.0; - break; - - case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: - mPhase = 0; - mPhaseStep = 0; - break; - } - - ALfloat coeffs[MAX_AMBI_CHANNELS]; - CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); - - mOutTarget = target.Main->Buffer; - ComputePanGains(target.Main, coeffs, slot->Params.Gain, mTargetGains); -} - -void FshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) -{ - static constexpr complex_d complex_zero{0.0, 0.0}; - ALfloat *RESTRICT BufferOut = mBufferOut; - ALsizei j, k, base; - - for(base = 0;base < samplesToDo;) - { - const ALsizei todo{mini(HIL_SIZE-mCount, samplesToDo-base)}; - - ASSUME(todo > 0); - - /* Fill FIFO buffer with samples data */ - k = mCount; - for(j = 0;j < todo;j++,k++) - { - mInFIFO[k] = samplesIn[0][base+j]; - mOutdata[base+j] = mOutFIFO[k-FIFO_LATENCY]; - } - mCount += todo; - base += todo; - - /* Check whether FIFO buffer is filled */ - if(mCount < HIL_SIZE) continue; - mCount = FIFO_LATENCY; - - /* Real signal windowing and store in Analytic buffer */ - for(k = 0;k < HIL_SIZE;k++) - { - mAnalytic[k].real(mInFIFO[k] * HannWindow[k]); - mAnalytic[k].imag(0.0); - } - - /* Processing signal by Discrete Hilbert Transform (analytical signal). */ - complex_hilbert(mAnalytic); - - /* Windowing and add to output accumulator */ - for(k = 0;k < HIL_SIZE;k++) - mOutputAccum[k] += 2.0/OVERSAMP*HannWindow[k]*mAnalytic[k]; - - /* Shift accumulator, input & output FIFO */ - for(k = 0;k < HIL_STEP;k++) mOutFIFO[k] = mOutputAccum[k]; - for(j = 0;k < HIL_SIZE;k++,j++) mOutputAccum[j] = mOutputAccum[k]; - for(;j < HIL_SIZE;j++) mOutputAccum[j] = complex_zero; - for(k = 0;k < FIFO_LATENCY;k++) - mInFIFO[k] = mInFIFO[k+HIL_STEP]; - } - - /* Process frequency shifter using the analytic signal obtained. */ - for(k = 0;k < samplesToDo;k++) - { - double phase = mPhase * ((1.0/FRACTIONONE) * al::MathDefs::Tau()); - BufferOut[k] = static_cast(mOutdata[k].real()*std::cos(phase) + - mOutdata[k].imag()*std::sin(phase)*mLdSign); - - mPhase += mPhaseStep; - mPhase &= FRACTIONMASK; - } - - /* Now, mix the processed sound data to the output. */ - MixSamples(BufferOut, samplesOut, mCurrentGains, mTargetGains, maxi(samplesToDo, 512), 0, - samplesToDo); -} - - -void Fshifter_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_FREQUENCY_SHIFTER_FREQUENCY: - if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter frequency out of range"); - props->Fshifter.Frequency = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); - } -} -void Fshifter_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) -{ Fshifter_setParamf(props, context, param, vals[0]); } - -void Fshifter_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val) -{ - switch(param) - { - case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: - if(!(val >= AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter left direction out of range"); - props->Fshifter.LeftDirection = val; - break; - - case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: - if(!(val >= AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter right direction out of range"); - props->Fshifter.RightDirection = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); - } -} -void Fshifter_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) -{ Fshifter_setParami(props, context, param, vals[0]); } - -void Fshifter_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val) -{ - switch(param) - { - case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: - *val = props->Fshifter.LeftDirection; - break; - case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: - *val = props->Fshifter.RightDirection; - break; - default: - alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); - } -} -void Fshifter_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) -{ Fshifter_getParami(props, context, param, vals); } - -void Fshifter_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_FREQUENCY_SHIFTER_FREQUENCY: - *val = props->Fshifter.Frequency; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); - } -} -void Fshifter_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) -{ Fshifter_getParamf(props, context, param, vals); } - -DEFINE_ALEFFECT_VTABLE(Fshifter); - - -struct FshifterStateFactory final : public EffectStateFactory { - EffectState *create() override { return new FshifterState{}; } - EffectProps getDefaultProps() const noexcept override; - const EffectVtable *getEffectVtable() const noexcept override { return &Fshifter_vtable; } -}; - -EffectProps FshifterStateFactory::getDefaultProps() const noexcept -{ - EffectProps props{}; - props.Fshifter.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY; - props.Fshifter.LeftDirection = AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION; - props.Fshifter.RightDirection = AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION; - return props; -} - -} // namespace - -EffectStateFactory *FshifterStateFactory_getFactory() -{ - static FshifterStateFactory FshifterFactory{}; - return &FshifterFactory; -} diff --git a/Alc/effects/modulator.cpp b/Alc/effects/modulator.cpp deleted file mode 100644 index 086482d7..00000000 --- a/Alc/effects/modulator.cpp +++ /dev/null @@ -1,279 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2009 by Chris Robinson. - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include -#include - -#include "alcmain.h" -#include "alcontext.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" -#include "filters/biquad.h" -#include "vecmat.h" - - -namespace { - -#define MAX_UPDATE_SAMPLES 128 - -#define WAVEFORM_FRACBITS 24 -#define WAVEFORM_FRACONE (1<(index) * - (al::MathDefs::Tau() / ALfloat{WAVEFORM_FRACONE})); -} - -inline ALfloat Saw(ALsizei index) -{ - return static_cast(index)*(2.0f/WAVEFORM_FRACONE) - 1.0f; -} - -inline ALfloat Square(ALsizei index) -{ - return static_cast(((index>>(WAVEFORM_FRACBITS-2))&2) - 1); -} - -inline ALfloat One(ALsizei) -{ - return 1.0f; -} - -template -void Modulate(ALfloat *RESTRICT dst, ALsizei index, const ALsizei step, ALsizei todo) -{ - ALsizei i; - for(i = 0;i < todo;i++) - { - index += step; - index &= WAVEFORM_FRACMASK; - dst[i] = func(index); - } -} - - -struct ModulatorState final : public EffectState { - void (*mGetSamples)(ALfloat*RESTRICT, ALsizei, const ALsizei, ALsizei){}; - - ALsizei mIndex{0}; - ALsizei mStep{1}; - - struct { - BiquadFilter Filter; - - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]{}; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]{}; - } mChans[MAX_AMBI_CHANNELS]; - - - ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; - - DEF_NEWDEL(ModulatorState) -}; - -ALboolean ModulatorState::deviceUpdate(const ALCdevice*) -{ - for(auto &e : mChans) - { - e.Filter.clear(); - std::fill(std::begin(e.CurrentGains), std::end(e.CurrentGains), 0.0f); - } - return AL_TRUE; -} - -void ModulatorState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) -{ - const ALCdevice *device{context->Device}; - - const float step{props->Modulator.Frequency / static_cast(device->Frequency)}; - mStep = fastf2i(clampf(step*WAVEFORM_FRACONE, 0.0f, ALfloat{WAVEFORM_FRACONE-1})); - - if(mStep == 0) - mGetSamples = Modulate; - else if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) - mGetSamples = Modulate; - else if(props->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) - mGetSamples = Modulate; - else /*if(props->Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/ - mGetSamples = Modulate; - - ALfloat f0norm{props->Modulator.HighPassCutoff / static_cast(device->Frequency)}; - f0norm = clampf(f0norm, 1.0f/512.0f, 0.49f); - /* Bandwidth value is constant in octaves. */ - mChans[0].Filter.setParams(BiquadType::HighPass, 1.0f, f0norm, - BiquadFilter::rcpQFromBandwidth(f0norm, 0.75f)); - for(size_t i{1u};i < slot->Wet.Buffer.size();++i) - mChans[i].Filter.copyParamsFrom(mChans[0].Filter); - - mOutTarget = target.Main->Buffer; - for(size_t i{0u};i < slot->Wet.Buffer.size();++i) - { - auto coeffs = GetAmbiIdentityRow(i); - ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mChans[i].TargetGains); - } -} - -void ModulatorState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) -{ - for(ALsizei base{0};base < samplesToDo;) - { - alignas(16) ALfloat modsamples[MAX_UPDATE_SAMPLES]; - ALsizei td = mini(MAX_UPDATE_SAMPLES, samplesToDo-base); - ALsizei c, i; - - mGetSamples(modsamples, mIndex, mStep, td); - mIndex += (mStep*td) & WAVEFORM_FRACMASK; - mIndex &= WAVEFORM_FRACMASK; - - ASSUME(numInput > 0); - for(c = 0;c < numInput;c++) - { - alignas(16) ALfloat temps[MAX_UPDATE_SAMPLES]; - - mChans[c].Filter.process(temps, &samplesIn[c][base], td); - for(i = 0;i < td;i++) - temps[i] *= modsamples[i]; - - MixSamples(temps, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, - samplesToDo-base, base, td); - } - - base += td; - } -} - - -void Modulator_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_RING_MODULATOR_FREQUENCY: - if(!(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Modulator frequency out of range"); - props->Modulator.Frequency = val; - break; - - case AL_RING_MODULATOR_HIGHPASS_CUTOFF: - if(!(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Modulator high-pass cutoff out of range"); - props->Modulator.HighPassCutoff = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param); - } -} -void Modulator_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) -{ Modulator_setParamf(props, context, param, vals[0]); } -void Modulator_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val) -{ - switch(param) - { - case AL_RING_MODULATOR_FREQUENCY: - case AL_RING_MODULATOR_HIGHPASS_CUTOFF: - Modulator_setParamf(props, context, param, static_cast(val)); - break; - - case AL_RING_MODULATOR_WAVEFORM: - if(!(val >= AL_RING_MODULATOR_MIN_WAVEFORM && val <= AL_RING_MODULATOR_MAX_WAVEFORM)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid modulator waveform"); - props->Modulator.Waveform = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x", param); - } -} -void Modulator_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) -{ Modulator_setParami(props, context, param, vals[0]); } - -void Modulator_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val) -{ - switch(param) - { - case AL_RING_MODULATOR_FREQUENCY: - *val = static_cast(props->Modulator.Frequency); - break; - case AL_RING_MODULATOR_HIGHPASS_CUTOFF: - *val = static_cast(props->Modulator.HighPassCutoff); - break; - case AL_RING_MODULATOR_WAVEFORM: - *val = props->Modulator.Waveform; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x", param); - } -} -void Modulator_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) -{ Modulator_getParami(props, context, param, vals); } -void Modulator_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_RING_MODULATOR_FREQUENCY: - *val = props->Modulator.Frequency; - break; - case AL_RING_MODULATOR_HIGHPASS_CUTOFF: - *val = props->Modulator.HighPassCutoff; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param); - } -} -void Modulator_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) -{ Modulator_getParamf(props, context, param, vals); } - -DEFINE_ALEFFECT_VTABLE(Modulator); - - -struct ModulatorStateFactory final : public EffectStateFactory { - EffectState *create() override { return new ModulatorState{}; } - EffectProps getDefaultProps() const noexcept override; - const EffectVtable *getEffectVtable() const noexcept override { return &Modulator_vtable; } -}; - -EffectProps ModulatorStateFactory::getDefaultProps() const noexcept -{ - EffectProps props{}; - props.Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY; - props.Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF; - props.Modulator.Waveform = AL_RING_MODULATOR_DEFAULT_WAVEFORM; - return props; -} - -} // namespace - -EffectStateFactory *ModulatorStateFactory_getFactory() -{ - static ModulatorStateFactory ModulatorFactory{}; - return &ModulatorFactory; -} diff --git a/Alc/effects/null.cpp b/Alc/effects/null.cpp deleted file mode 100644 index e55c8699..00000000 --- a/Alc/effects/null.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include "config.h" - -#include - -#include "AL/al.h" -#include "AL/alc.h" - -#include "alcmain.h" -#include "alcontext.h" -#include "alAuxEffectSlot.h" -#include "alError.h" - - -namespace { - -struct NullState final : public EffectState { - NullState(); - ~NullState() override; - - ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; - - DEF_NEWDEL(NullState) -}; - -/* This constructs the effect state. It's called when the object is first - * created. - */ -NullState::NullState() = default; - -/* This destructs the effect state. It's called only when the effect instance - * is no longer used. - */ -NullState::~NullState() = default; - -/* This updates the device-dependant effect state. This is called on state - * initialization and any time the device parameters (e.g. playback frequency, - * format) have been changed. Will always be followed by a call to the update - * method, if successful. - */ -ALboolean NullState::deviceUpdate(const ALCdevice* /*device*/) -{ - return AL_TRUE; -} - -/* This updates the effect state with new properties. This is called any time - * the effect is (re)loaded into a slot. - */ -void NullState::update(const ALCcontext* /*context*/, const ALeffectslot* /*slot*/, - const EffectProps* /*props*/, const EffectTarget /*target*/) -{ -} - -/* This processes the effect state, for the given number of samples from the - * input to the output buffer. The result should be added to the output buffer, - * not replace it. - */ -void NullState::process(const ALsizei /*samplesToDo*/, - const FloatBufferLine *RESTRICT /*samplesIn*/, const ALsizei /*numInput*/, - const al::span /*samplesOut*/) -{ -} - - -void NullEffect_setParami(EffectProps* /*props*/, ALCcontext *context, ALenum param, ALint /*val*/) -{ - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x", param); - } -} -void NullEffect_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) -{ - switch(param) - { - default: - NullEffect_setParami(props, context, param, vals[0]); - } -} -void NullEffect_setParamf(EffectProps* /*props*/, ALCcontext *context, ALenum param, ALfloat /*val*/) -{ - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid null effect float property 0x%04x", param); - } -} -void NullEffect_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - switch(param) - { - default: - NullEffect_setParamf(props, context, param, vals[0]); - } -} - -void NullEffect_getParami(const EffectProps* /*props*/, ALCcontext *context, ALenum param, ALint* /*val*/) -{ - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x", param); - } -} -void NullEffect_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) -{ - switch(param) - { - default: - NullEffect_getParami(props, context, param, vals); - } -} -void NullEffect_getParamf(const EffectProps* /*props*/, ALCcontext *context, ALenum param, ALfloat* /*val*/) -{ - switch(param) - { - default: - alSetError(context, AL_INVALID_ENUM, "Invalid null effect float property 0x%04x", param); - } -} -void NullEffect_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) -{ - switch(param) - { - default: - NullEffect_getParamf(props, context, param, vals); - } -} - -DEFINE_ALEFFECT_VTABLE(NullEffect); - - -struct NullStateFactory final : public EffectStateFactory { - EffectState *create() override; - EffectProps getDefaultProps() const noexcept override; - const EffectVtable *getEffectVtable() const noexcept override; -}; - -/* Creates EffectState objects of the appropriate type. */ -EffectState *NullStateFactory::create() -{ return new NullState{}; } - -/* Returns an ALeffectProps initialized with this effect type's default - * property values. - */ -EffectProps NullStateFactory::getDefaultProps() const noexcept -{ - EffectProps props{}; - return props; -} - -/* Returns a pointer to this effect type's global set/get vtable. */ -const EffectVtable *NullStateFactory::getEffectVtable() const noexcept -{ return &NullEffect_vtable; } - -} // namespace - -EffectStateFactory *NullStateFactory_getFactory() -{ - static NullStateFactory NullFactory{}; - return &NullFactory; -} diff --git a/Alc/effects/pshifter.cpp b/Alc/effects/pshifter.cpp deleted file mode 100644 index 39d3cf1a..00000000 --- a/Alc/effects/pshifter.cpp +++ /dev/null @@ -1,405 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2018 by Raul Herraiz. - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#ifdef HAVE_SSE_INTRINSICS -#include -#endif - -#include -#include -#include -#include -#include - -#include "alcmain.h" -#include "alcontext.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" - -#include "alcomplex.h" - - -namespace { - -using complex_d = std::complex; - -#define STFT_SIZE 1024 -#define STFT_HALF_SIZE (STFT_SIZE>>1) -#define OVERSAMP (1<<2) - -#define STFT_STEP (STFT_SIZE / OVERSAMP) -#define FIFO_LATENCY (STFT_STEP * (OVERSAMP-1)) - -inline int double2int(double d) -{ -#if defined(HAVE_SSE_INTRINSICS) - return _mm_cvttsd_si32(_mm_set_sd(d)); - -#elif ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) && \ - !defined(__SSE2_MATH__)) || (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP < 2) - - int sign, shift; - int64_t mant; - union { - double d; - int64_t i64; - } conv; - - conv.d = d; - sign = (conv.i64>>63) | 1; - shift = ((conv.i64>>52)&0x7ff) - (1023+52); - - /* Over/underflow */ - if(UNLIKELY(shift >= 63 || shift < -52)) - return 0; - - mant = (conv.i64&0xfffffffffffff_i64) | 0x10000000000000_i64; - if(LIKELY(shift < 0)) - return (int)(mant >> -shift) * sign; - return (int)(mant << shift) * sign; - -#else - - return static_cast(d); -#endif -} - -/* Define a Hann window, used to filter the STFT input and output. */ -/* Making this constexpr seems to require C++14. */ -std::array InitHannWindow() -{ - std::array ret; - /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */ - for(ALsizei i{0};i < STFT_SIZE>>1;i++) - { - ALdouble val = std::sin(al::MathDefs::Pi() * i / ALdouble{STFT_SIZE-1}); - ret[i] = ret[STFT_SIZE-1-i] = val * val; - } - return ret; -} -alignas(16) const std::array HannWindow = InitHannWindow(); - - -struct ALphasor { - ALdouble Amplitude; - ALdouble Phase; -}; - -struct ALfrequencyDomain { - ALdouble Amplitude; - ALdouble Frequency; -}; - - -/* Converts complex to ALphasor */ -inline ALphasor rect2polar(const complex_d &number) -{ - ALphasor polar; - polar.Amplitude = std::abs(number); - polar.Phase = std::arg(number); - return polar; -} - -/* Converts ALphasor to complex */ -inline complex_d polar2rect(const ALphasor &number) -{ return std::polar(number.Amplitude, number.Phase); } - - -struct PshifterState final : public EffectState { - /* Effect parameters */ - ALsizei mCount; - ALsizei mPitchShiftI; - ALfloat mPitchShift; - ALfloat mFreqPerBin; - - /* Effects buffers */ - ALfloat mInFIFO[STFT_SIZE]; - ALfloat mOutFIFO[STFT_STEP]; - ALdouble mLastPhase[STFT_HALF_SIZE+1]; - ALdouble mSumPhase[STFT_HALF_SIZE+1]; - ALdouble mOutputAccum[STFT_SIZE]; - - complex_d mFFTbuffer[STFT_SIZE]; - - ALfrequencyDomain mAnalysis_buffer[STFT_HALF_SIZE+1]; - ALfrequencyDomain mSyntesis_buffer[STFT_HALF_SIZE+1]; - - alignas(16) ALfloat mBufferOut[BUFFERSIZE]; - - /* Effect gains for each output channel */ - ALfloat mCurrentGains[MAX_OUTPUT_CHANNELS]; - ALfloat mTargetGains[MAX_OUTPUT_CHANNELS]; - - - ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; - - DEF_NEWDEL(PshifterState) -}; - -ALboolean PshifterState::deviceUpdate(const ALCdevice *device) -{ - /* (Re-)initializing parameters and clear the buffers. */ - mCount = FIFO_LATENCY; - mPitchShiftI = FRACTIONONE; - mPitchShift = 1.0f; - mFreqPerBin = device->Frequency / static_cast(STFT_SIZE); - - std::fill(std::begin(mInFIFO), std::end(mInFIFO), 0.0f); - std::fill(std::begin(mOutFIFO), std::end(mOutFIFO), 0.0f); - std::fill(std::begin(mLastPhase), std::end(mLastPhase), 0.0); - std::fill(std::begin(mSumPhase), std::end(mSumPhase), 0.0); - std::fill(std::begin(mOutputAccum), std::end(mOutputAccum), 0.0); - std::fill(std::begin(mFFTbuffer), std::end(mFFTbuffer), complex_d{}); - std::fill(std::begin(mAnalysis_buffer), std::end(mAnalysis_buffer), ALfrequencyDomain{}); - std::fill(std::begin(mSyntesis_buffer), std::end(mSyntesis_buffer), ALfrequencyDomain{}); - - std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f); - std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f); - - return AL_TRUE; -} - -void PshifterState::update(const ALCcontext*, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) -{ - const float pitch{std::pow(2.0f, - static_cast(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f - )}; - mPitchShiftI = fastf2i(pitch*FRACTIONONE); - mPitchShift = mPitchShiftI * (1.0f/FRACTIONONE); - - ALfloat coeffs[MAX_AMBI_CHANNELS]; - CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); - - mOutTarget = target.Main->Buffer; - ComputePanGains(target.Main, coeffs, slot->Params.Gain, mTargetGains); -} - -void PshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) -{ - /* Pitch shifter engine based on the work of Stephan Bernsee. - * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/ - */ - - static constexpr ALdouble expected{al::MathDefs::Tau() / OVERSAMP}; - const ALdouble freq_per_bin{mFreqPerBin}; - ALfloat *RESTRICT bufferOut{mBufferOut}; - ALsizei count{mCount}; - - for(ALsizei i{0};i < samplesToDo;) - { - do { - /* Fill FIFO buffer with samples data */ - mInFIFO[count] = samplesIn[0][i]; - bufferOut[i] = mOutFIFO[count - FIFO_LATENCY]; - - count++; - } while(++i < samplesToDo && count < STFT_SIZE); - - /* Check whether FIFO buffer is filled */ - if(count < STFT_SIZE) break; - count = FIFO_LATENCY; - - /* Real signal windowing and store in FFTbuffer */ - for(ALsizei k{0};k < STFT_SIZE;k++) - { - mFFTbuffer[k].real(mInFIFO[k] * HannWindow[k]); - mFFTbuffer[k].imag(0.0); - } - - /* ANALYSIS */ - /* Apply FFT to FFTbuffer data */ - complex_fft(mFFTbuffer, -1.0); - - /* Analyze the obtained data. Since the real FFT is symmetric, only - * STFT_HALF_SIZE+1 samples are needed. - */ - for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) - { - /* Compute amplitude and phase */ - ALphasor component{rect2polar(mFFTbuffer[k])}; - - /* Compute phase difference and subtract expected phase difference */ - double tmp{(component.Phase - mLastPhase[k]) - k*expected}; - - /* Map delta phase into +/- Pi interval */ - int qpd{double2int(tmp / al::MathDefs::Pi())}; - tmp -= al::MathDefs::Pi() * (qpd + (qpd%2)); - - /* Get deviation from bin frequency from the +/- Pi interval */ - tmp /= expected; - - /* Compute the k-th partials' true frequency, twice the amplitude - * for maintain the gain (because half of bins are used) and store - * amplitude and true frequency in analysis buffer. - */ - mAnalysis_buffer[k].Amplitude = 2.0 * component.Amplitude; - mAnalysis_buffer[k].Frequency = (k + tmp) * freq_per_bin; - - /* Store actual phase[k] for the calculations in the next frame*/ - mLastPhase[k] = component.Phase; - } - - /* PROCESSING */ - /* pitch shifting */ - for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) - { - mSyntesis_buffer[k].Amplitude = 0.0; - mSyntesis_buffer[k].Frequency = 0.0; - } - - for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) - { - ALsizei j{(k*mPitchShiftI) >> FRACTIONBITS}; - if(j >= STFT_HALF_SIZE+1) break; - - mSyntesis_buffer[j].Amplitude += mAnalysis_buffer[k].Amplitude; - mSyntesis_buffer[j].Frequency = mAnalysis_buffer[k].Frequency * mPitchShift; - } - - /* SYNTHESIS */ - /* Synthesis the processing data */ - for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) - { - ALphasor component; - ALdouble tmp; - - /* Compute bin deviation from scaled freq */ - tmp = mSyntesis_buffer[k].Frequency/freq_per_bin - k; - - /* Calculate actual delta phase and accumulate it to get bin phase */ - mSumPhase[k] += (k + tmp) * expected; - - component.Amplitude = mSyntesis_buffer[k].Amplitude; - component.Phase = mSumPhase[k]; - - /* Compute phasor component to cartesian complex number and storage it into FFTbuffer*/ - mFFTbuffer[k] = polar2rect(component); - } - /* zero negative frequencies for recontruct a real signal */ - for(ALsizei k{STFT_HALF_SIZE+1};k < STFT_SIZE;k++) - mFFTbuffer[k] = complex_d{}; - - /* Apply iFFT to buffer data */ - complex_fft(mFFTbuffer, 1.0); - - /* Windowing and add to output */ - for(ALsizei k{0};k < STFT_SIZE;k++) - mOutputAccum[k] += HannWindow[k] * mFFTbuffer[k].real() / - (0.5 * STFT_HALF_SIZE * OVERSAMP); - - /* Shift accumulator, input & output FIFO */ - ALsizei j, k; - for(k = 0;k < STFT_STEP;k++) mOutFIFO[k] = static_cast(mOutputAccum[k]); - for(j = 0;k < STFT_SIZE;k++,j++) mOutputAccum[j] = mOutputAccum[k]; - for(;j < STFT_SIZE;j++) mOutputAccum[j] = 0.0; - for(k = 0;k < FIFO_LATENCY;k++) - mInFIFO[k] = mInFIFO[k+STFT_STEP]; - } - mCount = count; - - /* Now, mix the processed sound data to the output. */ - MixSamples(bufferOut, samplesOut, mCurrentGains, mTargetGains, maxi(samplesToDo, 512), 0, - samplesToDo); -} - - -void Pshifter_setParamf(EffectProps*, ALCcontext *context, ALenum param, ALfloat) -{ alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param); } -void Pshifter_setParamfv(EffectProps*, ALCcontext *context, ALenum param, const ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float-vector property 0x%04x", param); } - -void Pshifter_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val) -{ - switch(param) - { - case AL_PITCH_SHIFTER_COARSE_TUNE: - if(!(val >= AL_PITCH_SHIFTER_MIN_COARSE_TUNE && val <= AL_PITCH_SHIFTER_MAX_COARSE_TUNE)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Pitch shifter coarse tune out of range"); - props->Pshifter.CoarseTune = val; - break; - - case AL_PITCH_SHIFTER_FINE_TUNE: - if(!(val >= AL_PITCH_SHIFTER_MIN_FINE_TUNE && val <= AL_PITCH_SHIFTER_MAX_FINE_TUNE)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Pitch shifter fine tune out of range"); - props->Pshifter.FineTune = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x", param); - } -} -void Pshifter_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) -{ Pshifter_setParami(props, context, param, vals[0]); } - -void Pshifter_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val) -{ - switch(param) - { - case AL_PITCH_SHIFTER_COARSE_TUNE: - *val = props->Pshifter.CoarseTune; - break; - case AL_PITCH_SHIFTER_FINE_TUNE: - *val = props->Pshifter.FineTune; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x", param); - } -} -void Pshifter_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) -{ Pshifter_getParami(props, context, param, vals); } - -void Pshifter_getParamf(const EffectProps*, ALCcontext *context, ALenum param, ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param); } -void Pshifter_getParamfv(const EffectProps*, ALCcontext *context, ALenum param, ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float vector-property 0x%04x", param); } - -DEFINE_ALEFFECT_VTABLE(Pshifter); - - -struct PshifterStateFactory final : public EffectStateFactory { - EffectState *create() override; - EffectProps getDefaultProps() const noexcept override; - const EffectVtable *getEffectVtable() const noexcept override { return &Pshifter_vtable; } -}; - -EffectState *PshifterStateFactory::create() -{ return new PshifterState{}; } - -EffectProps PshifterStateFactory::getDefaultProps() const noexcept -{ - EffectProps props{}; - props.Pshifter.CoarseTune = AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE; - props.Pshifter.FineTune = AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE; - return props; -} - -} // namespace - -EffectStateFactory *PshifterStateFactory_getFactory() -{ - static PshifterStateFactory PshifterFactory{}; - return &PshifterFactory; -} diff --git a/Alc/effects/reverb.cpp b/Alc/effects/reverb.cpp deleted file mode 100644 index ac996b3f..00000000 --- a/Alc/effects/reverb.cpp +++ /dev/null @@ -1,2102 +0,0 @@ -/** - * Ambisonic reverb engine for the OpenAL cross platform audio library - * Copyright (C) 2008-2017 by Chris Robinson and Christopher Fitzgerald. - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include -#include -#include -#include - -#include "alcmain.h" -#include "alcontext.h" -#include "alu.h" -#include "alAuxEffectSlot.h" -#include "alListener.h" -#include "alError.h" -#include "bformatdec.h" -#include "filters/biquad.h" -#include "vector.h" -#include "vecmat.h" - -/* This is a user config option for modifying the overall output of the reverb - * effect. - */ -ALfloat ReverbBoost = 1.0f; - -namespace { - -using namespace std::placeholders; - -/* The number of samples used for cross-faded delay lines. This can be used - * to balance the compensation for abrupt line changes and attenuation due to - * minimally lengthed recursive lines. Try to keep this below the device - * update size. - */ -constexpr int FADE_SAMPLES{128}; - -/* The number of spatialized lines or channels to process. Four channels allows - * for a 3D A-Format response. NOTE: This can't be changed without taking care - * of the conversion matrices, and a few places where the length arrays are - * assumed to have 4 elements. - */ -constexpr int NUM_LINES{4}; - - -/* The B-Format to A-Format conversion matrix. The arrangement of rows is - * deliberately chosen to align the resulting lines to their spatial opposites - * (0:above front left <-> 3:above back right, 1:below front right <-> 2:below - * back left). It's not quite opposite, since the A-Format results in a - * tetrahedron, but it's close enough. Should the model be extended to 8-lines - * in the future, true opposites can be used. - */ -alignas(16) constexpr ALfloat B2A[NUM_LINES][MAX_AMBI_CHANNELS]{ - { 0.288675134595f, 0.288675134595f, 0.288675134595f, 0.288675134595f }, - { 0.288675134595f, -0.288675134595f, -0.288675134595f, 0.288675134595f }, - { 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f }, - { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f } -}; - -/* Converts A-Format to B-Format. */ -alignas(16) constexpr ALfloat A2B[NUM_LINES][NUM_LINES]{ - { 0.866025403785f, 0.866025403785f, 0.866025403785f, 0.866025403785f }, - { 0.866025403785f, -0.866025403785f, 0.866025403785f, -0.866025403785f }, - { 0.866025403785f, -0.866025403785f, -0.866025403785f, 0.866025403785f }, - { 0.866025403785f, 0.866025403785f, -0.866025403785f, -0.866025403785f } -}; - - -constexpr ALfloat FadeStep{1.0f / FADE_SAMPLES}; - -/* The all-pass and delay lines have a variable length dependent on the - * effect's density parameter, which helps alter the perceived environment - * size. The size-to-density conversion is a cubed scale: - * - * density = min(1.0, pow(size, 3.0) / DENSITY_SCALE); - * - * The line lengths scale linearly with room size, so the inverse density - * conversion is needed, taking the cube root of the re-scaled density to - * calculate the line length multiplier: - * - * length_mult = max(5.0, cbrt(density*DENSITY_SCALE)); - * - * The density scale below will result in a max line multiplier of 50, for an - * effective size range of 5m to 50m. - */ -constexpr ALfloat DENSITY_SCALE{125000.0f}; - -/* All delay line lengths are specified in seconds. - * - * To approximate early reflections, we break them up into primary (those - * arriving from the same direction as the source) and secondary (those - * arriving from the opposite direction). - * - * The early taps decorrelate the 4-channel signal to approximate an average - * room response for the primary reflections after the initial early delay. - * - * Given an average room dimension (d_a) and the speed of sound (c) we can - * calculate the average reflection delay (r_a) regardless of listener and - * source positions as: - * - * r_a = d_a / c - * c = 343.3 - * - * This can extended to finding the average difference (r_d) between the - * maximum (r_1) and minimum (r_0) reflection delays: - * - * r_0 = 2 / 3 r_a - * = r_a - r_d / 2 - * = r_d - * r_1 = 4 / 3 r_a - * = r_a + r_d / 2 - * = 2 r_d - * r_d = 2 / 3 r_a - * = r_1 - r_0 - * - * As can be determined by integrating the 1D model with a source (s) and - * listener (l) positioned across the dimension of length (d_a): - * - * r_d = int_(l=0)^d_a (int_(s=0)^d_a |2 d_a - 2 (l + s)| ds) dl / c - * - * The initial taps (T_(i=0)^N) are then specified by taking a power series - * that ranges between r_0 and half of r_1 less r_0: - * - * R_i = 2^(i / (2 N - 1)) r_d - * = r_0 + (2^(i / (2 N - 1)) - 1) r_d - * = r_0 + T_i - * T_i = R_i - r_0 - * = (2^(i / (2 N - 1)) - 1) r_d - * - * Assuming an average of 1m, we get the following taps: - */ -constexpr std::array EARLY_TAP_LENGTHS{{ - 0.0000000e+0f, 2.0213520e-4f, 4.2531060e-4f, 6.7171600e-4f -}}; - -/* The early all-pass filter lengths are based on the early tap lengths: - * - * A_i = R_i / a - * - * Where a is the approximate maximum all-pass cycle limit (20). - */ -constexpr std::array EARLY_ALLPASS_LENGTHS{{ - 9.7096800e-5f, 1.0720356e-4f, 1.1836234e-4f, 1.3068260e-4f -}}; - -/* The early delay lines are used to transform the primary reflections into - * the secondary reflections. The A-format is arranged in such a way that - * the channels/lines are spatially opposite: - * - * C_i is opposite C_(N-i-1) - * - * The delays of the two opposing reflections (R_i and O_i) from a source - * anywhere along a particular dimension always sum to twice its full delay: - * - * 2 r_a = R_i + O_i - * - * With that in mind we can determine the delay between the two reflections - * and thus specify our early line lengths (L_(i=0)^N) using: - * - * O_i = 2 r_a - R_(N-i-1) - * L_i = O_i - R_(N-i-1) - * = 2 (r_a - R_(N-i-1)) - * = 2 (r_a - T_(N-i-1) - r_0) - * = 2 r_a (1 - (2 / 3) 2^((N - i - 1) / (2 N - 1))) - * - * Using an average dimension of 1m, we get: - */ -constexpr std::array EARLY_LINE_LENGTHS{{ - 5.9850400e-4f, 1.0913150e-3f, 1.5376658e-3f, 1.9419362e-3f -}}; - -/* The late all-pass filter lengths are based on the late line lengths: - * - * A_i = (5 / 3) L_i / r_1 - */ -constexpr std::array LATE_ALLPASS_LENGTHS{{ - 1.6182800e-4f, 2.0389060e-4f, 2.8159360e-4f, 3.2365600e-4f -}}; -constexpr auto LATE_ALLPASS_LENGTHS_size = LATE_ALLPASS_LENGTHS.size(); - -/* The late lines are used to approximate the decaying cycle of recursive - * late reflections. - * - * Splitting the lines in half, we start with the shortest reflection paths - * (L_(i=0)^(N/2)): - * - * L_i = 2^(i / (N - 1)) r_d - * - * Then for the opposite (longest) reflection paths (L_(i=N/2)^N): - * - * L_i = 2 r_a - L_(i-N/2) - * = 2 r_a - 2^((i - N / 2) / (N - 1)) r_d - * - * For our 1m average room, we get: - */ -constexpr std::array LATE_LINE_LENGTHS{{ - 1.9419362e-3f, 2.4466860e-3f, 3.3791220e-3f, 3.8838720e-3f -}}; -constexpr auto LATE_LINE_LENGTHS_size = LATE_LINE_LENGTHS.size(); - - -struct DelayLineI { - /* The delay lines use interleaved samples, with the lengths being powers - * of 2 to allow the use of bit-masking instead of a modulus for wrapping. - */ - ALsizei Mask{0}; - ALfloat (*Line)[NUM_LINES]{nullptr}; - - - void write(ALsizei offset, const ALsizei c, const ALfloat *RESTRICT in, const ALsizei count) const noexcept - { - ASSUME(count > 0); - for(ALsizei i{0};i < count;) - { - offset &= Mask; - ALsizei td{mini(Mask+1 - offset, count - i)}; - do { - Line[offset++][c] = in[i++]; - } while(--td); - } - } -}; - -struct VecAllpass { - DelayLineI Delay; - ALfloat Coeff{0.0f}; - ALsizei Offset[NUM_LINES][2]{}; - - void processFaded(const al::span samples, ALsizei offset, - const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, const ALsizei todo); - void processUnfaded(const al::span samples, ALsizei offset, - const ALfloat xCoeff, const ALfloat yCoeff, const ALsizei todo); -}; - -struct T60Filter { - /* Two filters are used to adjust the signal. One to control the low - * frequencies, and one to control the high frequencies. - */ - ALfloat MidGain[2]{0.0f, 0.0f}; - BiquadFilter HFFilter, LFFilter; - - void calcCoeffs(const ALfloat length, const ALfloat lfDecayTime, const ALfloat mfDecayTime, - const ALfloat hfDecayTime, const ALfloat lf0norm, const ALfloat hf0norm); - - /* Applies the two T60 damping filter sections. */ - void process(ALfloat *samples, const ALsizei todo) - { - HFFilter.process(samples, samples, todo); - LFFilter.process(samples, samples, todo); - } -}; - -struct EarlyReflections { - /* A Gerzon vector all-pass filter is used to simulate initial diffusion. - * The spread from this filter also helps smooth out the reverb tail. - */ - VecAllpass VecAp; - - /* An echo line is used to complete the second half of the early - * reflections. - */ - DelayLineI Delay; - ALsizei Offset[NUM_LINES][2]{}; - ALfloat Coeff[NUM_LINES][2]{}; - - /* The gain for each output channel based on 3D panning. */ - ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]{}; - ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]{}; - - void updateLines(const ALfloat density, const ALfloat diffusion, const ALfloat decayTime, - const ALfloat frequency); -}; - -struct LateReverb { - /* A recursive delay line is used fill in the reverb tail. */ - DelayLineI Delay; - ALsizei Offset[NUM_LINES][2]{}; - - /* Attenuation to compensate for the modal density and decay rate of the - * late lines. - */ - ALfloat DensityGain[2]{0.0f, 0.0f}; - - /* T60 decay filters are used to simulate absorption. */ - T60Filter T60[NUM_LINES]; - - /* A Gerzon vector all-pass filter is used to simulate diffusion. */ - VecAllpass VecAp; - - /* The gain for each output channel based on 3D panning. */ - ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]{}; - ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]{}; - - void updateLines(const ALfloat density, const ALfloat diffusion, const ALfloat lfDecayTime, - const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lf0norm, - const ALfloat hf0norm, const ALfloat frequency); -}; - -struct ReverbState final : public EffectState { - /* All delay lines are allocated as a single buffer to reduce memory - * fragmentation and management code. - */ - al::vector mSampleBuffer; - - struct { - /* Calculated parameters which indicate if cross-fading is needed after - * an update. - */ - ALfloat Density{AL_EAXREVERB_DEFAULT_DENSITY}; - ALfloat Diffusion{AL_EAXREVERB_DEFAULT_DIFFUSION}; - ALfloat DecayTime{AL_EAXREVERB_DEFAULT_DECAY_TIME}; - ALfloat HFDecayTime{AL_EAXREVERB_DEFAULT_DECAY_HFRATIO * AL_EAXREVERB_DEFAULT_DECAY_TIME}; - ALfloat LFDecayTime{AL_EAXREVERB_DEFAULT_DECAY_LFRATIO * AL_EAXREVERB_DEFAULT_DECAY_TIME}; - ALfloat HFReference{AL_EAXREVERB_DEFAULT_HFREFERENCE}; - ALfloat LFReference{AL_EAXREVERB_DEFAULT_LFREFERENCE}; - } mParams; - - /* Master effect filters */ - struct { - BiquadFilter Lp; - BiquadFilter Hp; - } mFilter[NUM_LINES]; - - /* Core delay line (early reflections and late reverb tap from this). */ - DelayLineI mDelay; - - /* Tap points for early reflection delay. */ - ALsizei mEarlyDelayTap[NUM_LINES][2]{}; - ALfloat mEarlyDelayCoeff[NUM_LINES][2]{}; - - /* Tap points for late reverb feed and delay. */ - ALsizei mLateFeedTap{}; - ALsizei mLateDelayTap[NUM_LINES][2]{}; - - /* Coefficients for the all-pass and line scattering matrices. */ - ALfloat mMixX{0.0f}; - ALfloat mMixY{0.0f}; - - EarlyReflections mEarly; - - LateReverb mLate; - - /* Indicates the cross-fade point for delay line reads [0,FADE_SAMPLES]. */ - ALsizei mFadeCount{0}; - - /* Maximum number of samples to process at once. */ - ALsizei mMaxUpdate[2]{BUFFERSIZE, BUFFERSIZE}; - - /* The current write offset for all delay lines. */ - ALsizei mOffset{0}; - - /* Temporary storage used when processing. */ - alignas(16) std::array mTempSamples{}; - alignas(16) std::array mEarlyBuffer{}; - alignas(16) std::array mLateBuffer{}; - - using MixOutT = void (ReverbState::*)(const al::span samplesOut, - const ALsizei todo); - - MixOutT mMixOut{&ReverbState::MixOutPlain}; - std::array mOrderScales{}; - std::array,2> mAmbiSplitter; - - - void MixOutPlain(const al::span samplesOut, const ALsizei todo) - { - ASSUME(todo > 0); - - /* Convert back to B-Format, and mix the results to output. */ - for(ALsizei c{0};c < NUM_LINES;c++) - { - std::fill_n(mTempSamples[0].begin(), todo, 0.0f); - MixRowSamples(mTempSamples[0], A2B[c], mEarlyBuffer, 0, todo); - MixSamples(mTempSamples[0].data(), samplesOut, mEarly.CurrentGain[c], - mEarly.PanGain[c], todo, 0, todo); - } - - for(ALsizei c{0};c < NUM_LINES;c++) - { - std::fill_n(mTempSamples[0].begin(), todo, 0.0f); - MixRowSamples(mTempSamples[0], A2B[c], mLateBuffer, 0, todo); - MixSamples(mTempSamples[0].data(), samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], - todo, 0, todo); - } - } - - void MixOutAmbiUp(const al::span samplesOut, const ALsizei todo) - { - ASSUME(todo > 0); - - for(ALsizei c{0};c < NUM_LINES;c++) - { - std::fill_n(mTempSamples[0].begin(), todo, 0.0f); - MixRowSamples(mTempSamples[0], A2B[c], mEarlyBuffer, 0, todo); - - /* Apply scaling to the B-Format's HF response to "upsample" it to - * higher-order output. - */ - const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; - mAmbiSplitter[0][c].applyHfScale(mTempSamples[0].data(), hfscale, todo); - - MixSamples(mTempSamples[0].data(), samplesOut, mEarly.CurrentGain[c], - mEarly.PanGain[c], todo, 0, todo); - } - - for(ALsizei c{0};c < NUM_LINES;c++) - { - std::fill_n(mTempSamples[0].begin(), todo, 0.0f); - MixRowSamples(mTempSamples[0], A2B[c], mLateBuffer, 0, todo); - - const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; - mAmbiSplitter[1][c].applyHfScale(mTempSamples[0].data(), hfscale, todo); - - MixSamples(mTempSamples[0].data(), samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], - todo, 0, todo); - } - } - - bool allocLines(const ALfloat frequency); - - void updateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, const ALfloat density, - const ALfloat decayTime, const ALfloat frequency); - void update3DPanning(const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, - const ALfloat earlyGain, const ALfloat lateGain, const EffectTarget &target); - - ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; - - DEF_NEWDEL(ReverbState) -}; - -/************************************** - * Device Update * - **************************************/ - -inline ALfloat CalcDelayLengthMult(ALfloat density) -{ return maxf(5.0f, std::cbrt(density*DENSITY_SCALE)); } - -/* Given the allocated sample buffer, this function updates each delay line - * offset. - */ -inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLineI *Delay) -{ - union { - ALfloat *f; - ALfloat (*f4)[NUM_LINES]; - } u; - u.f = &sampleBuffer[reinterpret_cast(Delay->Line) * NUM_LINES]; - Delay->Line = u.f4; -} - -/* Calculate the length of a delay line and store its mask and offset. */ -ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const ALfloat frequency, - const ALuint extra, DelayLineI *Delay) -{ - /* All line lengths are powers of 2, calculated from their lengths in - * seconds, rounded up. - */ - auto samples = static_cast(float2int(std::ceil(length*frequency))); - samples = NextPowerOf2(samples + extra); - - /* All lines share a single sample buffer. */ - Delay->Mask = samples - 1; - Delay->Line = reinterpret_cast(offset); - - /* Return the sample count for accumulation. */ - return samples; -} - -/* Calculates the delay line metrics and allocates the shared sample buffer - * for all lines given the sample rate (frequency). If an allocation failure - * occurs, it returns AL_FALSE. - */ -bool ReverbState::allocLines(const ALfloat frequency) -{ - /* All delay line lengths are calculated to accomodate the full range of - * lengths given their respective paramters. - */ - ALuint totalSamples{0u}; - - /* Multiplier for the maximum density value, i.e. density=1, which is - * actually the least density... - */ - ALfloat multiplier{CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY)}; - - /* The main delay length includes the maximum early reflection delay, the - * largest early tap width, the maximum late reverb delay, and the - * largest late tap width. Finally, it must also be extended by the - * update size (BUFFERSIZE) for block processing. - */ - ALfloat length{AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS.back()*multiplier + - AL_EAXREVERB_MAX_LATE_REVERB_DELAY + - (LATE_LINE_LENGTHS.back() - LATE_LINE_LENGTHS.front())/float{LATE_LINE_LENGTHS_size}*multiplier}; - totalSamples += CalcLineLength(length, totalSamples, frequency, BUFFERSIZE, &mDelay); - - /* The early vector all-pass line. */ - length = EARLY_ALLPASS_LENGTHS.back() * multiplier; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &mEarly.VecAp.Delay); - - /* The early reflection line. */ - length = EARLY_LINE_LENGTHS.back() * multiplier; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &mEarly.Delay); - - /* The late vector all-pass line. */ - length = LATE_ALLPASS_LENGTHS.back() * multiplier; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &mLate.VecAp.Delay); - - /* The late delay lines are calculated from the largest maximum density - * line length. - */ - length = LATE_LINE_LENGTHS.back() * multiplier; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &mLate.Delay); - - totalSamples *= NUM_LINES; - if(totalSamples != mSampleBuffer.size()) - { - mSampleBuffer.resize(totalSamples); - mSampleBuffer.shrink_to_fit(); - } - - /* Clear the sample buffer. */ - std::fill(mSampleBuffer.begin(), mSampleBuffer.end(), 0.0f); - - /* Update all delays to reflect the new sample buffer. */ - RealizeLineOffset(mSampleBuffer.data(), &mDelay); - RealizeLineOffset(mSampleBuffer.data(), &mEarly.VecAp.Delay); - RealizeLineOffset(mSampleBuffer.data(), &mEarly.Delay); - RealizeLineOffset(mSampleBuffer.data(), &mLate.VecAp.Delay); - RealizeLineOffset(mSampleBuffer.data(), &mLate.Delay); - - return true; -} - -ALboolean ReverbState::deviceUpdate(const ALCdevice *device) -{ - const auto frequency = static_cast(device->Frequency); - - /* Allocate the delay lines. */ - if(!allocLines(frequency)) - return AL_FALSE; - - const ALfloat multiplier{CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY)}; - - /* The late feed taps are set a fixed position past the latest delay tap. */ - mLateFeedTap = float2int( - (AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS.back()*multiplier) * frequency); - - /* Clear filters and gain coefficients since the delay lines were all just - * cleared (if not reallocated). - */ - for(auto &filter : mFilter) - { - filter.Lp.clear(); - filter.Hp.clear(); - } - - for(auto &coeff : mEarlyDelayCoeff) - std::fill(std::begin(coeff), std::end(coeff), 0.0f); - for(auto &coeff : mEarly.Coeff) - std::fill(std::begin(coeff), std::end(coeff), 0.0f); - - mLate.DensityGain[0] = 0.0f; - mLate.DensityGain[1] = 0.0f; - for(auto &t60 : mLate.T60) - { - t60.MidGain[0] = 0.0f; - t60.MidGain[1] = 0.0f; - t60.HFFilter.clear(); - t60.LFFilter.clear(); - } - - for(auto &gains : mEarly.CurrentGain) - std::fill(std::begin(gains), std::end(gains), 0.0f); - for(auto &gains : mEarly.PanGain) - std::fill(std::begin(gains), std::end(gains), 0.0f); - for(auto &gains : mLate.CurrentGain) - std::fill(std::begin(gains), std::end(gains), 0.0f); - for(auto &gains : mLate.PanGain) - std::fill(std::begin(gains), std::end(gains), 0.0f); - - /* Reset counters and offset base. */ - mFadeCount = 0; - std::fill(std::begin(mMaxUpdate), std::end(mMaxUpdate), BUFFERSIZE); - mOffset = 0; - - if(device->mAmbiOrder > 1) - { - mMixOut = &ReverbState::MixOutAmbiUp; - mOrderScales = BFormatDec::GetHFOrderScales(1, device->mAmbiOrder); - } - else - { - mMixOut = &ReverbState::MixOutPlain; - mOrderScales.fill(1.0f); - } - mAmbiSplitter[0][0].init(400.0f / frequency); - std::fill(mAmbiSplitter[0].begin()+1, mAmbiSplitter[0].end(), mAmbiSplitter[0][0]); - std::fill(mAmbiSplitter[1].begin(), mAmbiSplitter[1].end(), mAmbiSplitter[0][0]); - - return AL_TRUE; -} - -/************************************** - * Effect Update * - **************************************/ - -/* Calculate a decay coefficient given the length of each cycle and the time - * until the decay reaches -60 dB. - */ -inline ALfloat CalcDecayCoeff(const ALfloat length, const ALfloat decayTime) -{ return std::pow(REVERB_DECAY_GAIN, length/decayTime); } - -/* Calculate a decay length from a coefficient and the time until the decay - * reaches -60 dB. - */ -inline ALfloat CalcDecayLength(const ALfloat coeff, const ALfloat decayTime) -{ return std::log10(coeff) * decayTime / std::log10(REVERB_DECAY_GAIN); } - -/* Calculate an attenuation to be applied to the input of any echo models to - * compensate for modal density and decay time. - */ -inline ALfloat CalcDensityGain(const ALfloat a) -{ - /* The energy of a signal can be obtained by finding the area under the - * squared signal. This takes the form of Sum(x_n^2), where x is the - * amplitude for the sample n. - * - * Decaying feedback matches exponential decay of the form Sum(a^n), - * where a is the attenuation coefficient, and n is the sample. The area - * under this decay curve can be calculated as: 1 / (1 - a). - * - * Modifying the above equation to find the area under the squared curve - * (for energy) yields: 1 / (1 - a^2). Input attenuation can then be - * calculated by inverting the square root of this approximation, - * yielding: 1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2). - */ - return std::sqrt(1.0f - a*a); -} - -/* Calculate the scattering matrix coefficients given a diffusion factor. */ -inline ALvoid CalcMatrixCoeffs(const ALfloat diffusion, ALfloat *x, ALfloat *y) -{ - /* The matrix is of order 4, so n is sqrt(4 - 1). */ - ALfloat n{std::sqrt(3.0f)}; - ALfloat t{diffusion * std::atan(n)}; - - /* Calculate the first mixing matrix coefficient. */ - *x = std::cos(t); - /* Calculate the second mixing matrix coefficient. */ - *y = std::sin(t) / n; -} - -/* Calculate the limited HF ratio for use with the late reverb low-pass - * filters. - */ -ALfloat CalcLimitedHfRatio(const ALfloat hfRatio, const ALfloat airAbsorptionGainHF, - const ALfloat decayTime, const ALfloat SpeedOfSound) -{ - /* Find the attenuation due to air absorption in dB (converting delay - * time to meters using the speed of sound). Then reversing the decay - * equation, solve for HF ratio. The delay length is cancelled out of - * the equation, so it can be calculated once for all lines. - */ - ALfloat limitRatio{1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) * SpeedOfSound)}; - - /* Using the limit calculated above, apply the upper bound to the HF ratio. - */ - return minf(limitRatio, hfRatio); -} - - -/* Calculates the 3-band T60 damping coefficients for a particular delay line - * of specified length, using a combination of two shelf filter sections given - * decay times for each band split at two reference frequencies. - */ -void T60Filter::calcCoeffs(const ALfloat length, const ALfloat lfDecayTime, - const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lf0norm, - const ALfloat hf0norm) -{ - const ALfloat mfGain{CalcDecayCoeff(length, mfDecayTime)}; - const ALfloat lfGain{maxf(CalcDecayCoeff(length, lfDecayTime)/mfGain, 0.001f)}; - const ALfloat hfGain{maxf(CalcDecayCoeff(length, hfDecayTime)/mfGain, 0.001f)}; - - MidGain[1] = mfGain; - LFFilter.setParams(BiquadType::LowShelf, lfGain, lf0norm, - LFFilter.rcpQFromSlope(lfGain, 1.0f)); - HFFilter.setParams(BiquadType::HighShelf, hfGain, hf0norm, - HFFilter.rcpQFromSlope(hfGain, 1.0f)); -} - -/* Update the early reflection line lengths and gain coefficients. */ -void EarlyReflections::updateLines(const ALfloat density, const ALfloat diffusion, - const ALfloat decayTime, const ALfloat frequency) -{ - const ALfloat multiplier{CalcDelayLengthMult(density)}; - - /* Calculate the all-pass feed-back/forward coefficient. */ - VecAp.Coeff = std::sqrt(0.5f) * std::pow(diffusion, 2.0f); - - for(ALsizei i{0};i < NUM_LINES;i++) - { - /* Calculate the length (in seconds) of each all-pass line. */ - ALfloat length{EARLY_ALLPASS_LENGTHS[i] * multiplier}; - - /* Calculate the delay offset for each all-pass line. */ - VecAp.Offset[i][1] = float2int(length * frequency); - - /* Calculate the length (in seconds) of each delay line. */ - length = EARLY_LINE_LENGTHS[i] * multiplier; - - /* Calculate the delay offset for each delay line. */ - Offset[i][1] = float2int(length * frequency); - - /* Calculate the gain (coefficient) for each line. */ - Coeff[i][1] = CalcDecayCoeff(length, decayTime); - } -} - -/* Update the late reverb line lengths and T60 coefficients. */ -void LateReverb::updateLines(const ALfloat density, const ALfloat diffusion, - const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, - const ALfloat lf0norm, const ALfloat hf0norm, const ALfloat frequency) -{ - /* Scaling factor to convert the normalized reference frequencies from - * representing 0...freq to 0...max_reference. - */ - const ALfloat norm_weight_factor{frequency / AL_EAXREVERB_MAX_HFREFERENCE}; - - const ALfloat late_allpass_avg{ - std::accumulate(LATE_ALLPASS_LENGTHS.begin(), LATE_ALLPASS_LENGTHS.end(), 0.0f) / - float{LATE_ALLPASS_LENGTHS_size}}; - - /* To compensate for changes in modal density and decay time of the late - * reverb signal, the input is attenuated based on the maximal energy of - * the outgoing signal. This approximation is used to keep the apparent - * energy of the signal equal for all ranges of density and decay time. - * - * The average length of the delay lines is used to calculate the - * attenuation coefficient. - */ - const ALfloat multiplier{CalcDelayLengthMult(density)}; - ALfloat length{std::accumulate(LATE_LINE_LENGTHS.begin(), LATE_LINE_LENGTHS.end(), 0.0f) / - float{LATE_LINE_LENGTHS_size} * multiplier}; - length += late_allpass_avg * multiplier; - /* The density gain calculation uses an average decay time weighted by - * approximate bandwidth. This attempts to compensate for losses of energy - * that reduce decay time due to scattering into highly attenuated bands. - */ - const ALfloat bandWeights[3]{ - lf0norm*norm_weight_factor, - hf0norm*norm_weight_factor - lf0norm*norm_weight_factor, - 1.0f - hf0norm*norm_weight_factor}; - DensityGain[1] = CalcDensityGain( - CalcDecayCoeff(length, - bandWeights[0]*lfDecayTime + bandWeights[1]*mfDecayTime + bandWeights[2]*hfDecayTime - ) - ); - - /* Calculate the all-pass feed-back/forward coefficient. */ - VecAp.Coeff = std::sqrt(0.5f) * std::pow(diffusion, 2.0f); - - for(ALsizei i{0};i < NUM_LINES;i++) - { - /* Calculate the length (in seconds) of each all-pass line. */ - length = LATE_ALLPASS_LENGTHS[i] * multiplier; - - /* Calculate the delay offset for each all-pass line. */ - VecAp.Offset[i][1] = float2int(length * frequency); - - /* Calculate the length (in seconds) of each delay line. */ - length = LATE_LINE_LENGTHS[i] * multiplier; - - /* Calculate the delay offset for each delay line. */ - Offset[i][1] = float2int(length*frequency + 0.5f); - - /* Approximate the absorption that the vector all-pass would exhibit - * given the current diffusion so we don't have to process a full T60 - * filter for each of its four lines. - */ - length += lerp(LATE_ALLPASS_LENGTHS[i], late_allpass_avg, diffusion) * multiplier; - - /* Calculate the T60 damping coefficients for each line. */ - T60[i].calcCoeffs(length, lfDecayTime, mfDecayTime, hfDecayTime, lf0norm, hf0norm); - } -} - - -/* Update the offsets for the main effect delay line. */ -void ReverbState::updateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, - const ALfloat density, const ALfloat decayTime, const ALfloat frequency) -{ - const ALfloat multiplier{CalcDelayLengthMult(density)}; - - /* Early reflection taps are decorrelated by means of an average room - * reflection approximation described above the definition of the taps. - * This approximation is linear and so the above density multiplier can - * be applied to adjust the width of the taps. A single-band decay - * coefficient is applied to simulate initial attenuation and absorption. - * - * Late reverb taps are based on the late line lengths to allow a zero- - * delay path and offsets that would continue the propagation naturally - * into the late lines. - */ - for(ALsizei i{0};i < NUM_LINES;i++) - { - ALfloat length{earlyDelay + EARLY_TAP_LENGTHS[i]*multiplier}; - mEarlyDelayTap[i][1] = float2int(length * frequency); - - length = EARLY_TAP_LENGTHS[i]*multiplier; - mEarlyDelayCoeff[i][1] = CalcDecayCoeff(length, decayTime); - - length = lateDelay + (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS.front()) / - float{LATE_LINE_LENGTHS_size} * multiplier; - mLateDelayTap[i][1] = mLateFeedTap + float2int(length * frequency); - } -} - -/* Creates a transform matrix given a reverb vector. The vector pans the reverb - * reflections toward the given direction, using its magnitude (up to 1) as a - * focal strength. This function results in a B-Format transformation matrix - * that spatially focuses the signal in the desired direction. - */ -alu::Matrix GetTransformFromVector(const ALfloat *vec) -{ - /* Normalize the panning vector according to the N3D scale, which has an - * extra sqrt(3) term on the directional components. Converting from OpenAL - * to B-Format also requires negating X (ACN 1) and Z (ACN 3). Note however - * that the reverb panning vectors use left-handed coordinates, unlike the - * rest of OpenAL which use right-handed. This is fixed by negating Z, - * which cancels out with the B-Format Z negation. - */ - ALfloat norm[3]; - ALfloat mag{std::sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2])}; - if(mag > 1.0f) - { - norm[0] = vec[0] / mag * -al::MathDefs::Sqrt3(); - norm[1] = vec[1] / mag * al::MathDefs::Sqrt3(); - norm[2] = vec[2] / mag * al::MathDefs::Sqrt3(); - mag = 1.0f; - } - else - { - /* If the magnitude is less than or equal to 1, just apply the sqrt(3) - * term. There's no need to renormalize the magnitude since it would - * just be reapplied in the matrix. - */ - norm[0] = vec[0] * -al::MathDefs::Sqrt3(); - norm[1] = vec[1] * al::MathDefs::Sqrt3(); - norm[2] = vec[2] * al::MathDefs::Sqrt3(); - } - - return alu::Matrix{ - 1.0f, 0.0f, 0.0f, 0.0f, - norm[0], 1.0f-mag, 0.0f, 0.0f, - norm[1], 0.0f, 1.0f-mag, 0.0f, - norm[2], 0.0f, 0.0f, 1.0f-mag - }; -} - -/* Update the early and late 3D panning gains. */ -void ReverbState::update3DPanning(const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, - const ALfloat earlyGain, const ALfloat lateGain, const EffectTarget &target) -{ - /* Create matrices that transform a B-Format signal according to the - * panning vectors. - */ - const alu::Matrix earlymat{GetTransformFromVector(ReflectionsPan)}; - const alu::Matrix latemat{GetTransformFromVector(LateReverbPan)}; - - mOutTarget = target.Main->Buffer; - for(ALsizei i{0};i < NUM_LINES;i++) - { - const ALfloat coeffs[MAX_AMBI_CHANNELS]{earlymat[0][i], earlymat[1][i], earlymat[2][i], - earlymat[3][i]}; - ComputePanGains(target.Main, coeffs, earlyGain, mEarly.PanGain[i]); - } - for(ALsizei i{0};i < NUM_LINES;i++) - { - const ALfloat coeffs[MAX_AMBI_CHANNELS]{latemat[0][i], latemat[1][i], latemat[2][i], - latemat[3][i]}; - ComputePanGains(target.Main, coeffs, lateGain, mLate.PanGain[i]); - } -} - -void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, const EffectProps *props, const EffectTarget target) -{ - const ALCdevice *Device{Context->Device}; - const ALlistener &Listener = Context->Listener; - const auto frequency = static_cast(Device->Frequency); - - /* Calculate the master filters */ - ALfloat hf0norm{minf(props->Reverb.HFReference / frequency, 0.49f)}; - /* Restrict the filter gains from going below -60dB to keep the filter from - * killing most of the signal. - */ - ALfloat gainhf{maxf(props->Reverb.GainHF, 0.001f)}; - mFilter[0].Lp.setParams(BiquadType::HighShelf, gainhf, hf0norm, - mFilter[0].Lp.rcpQFromSlope(gainhf, 1.0f)); - ALfloat lf0norm{minf(props->Reverb.LFReference / frequency, 0.49f)}; - ALfloat gainlf{maxf(props->Reverb.GainLF, 0.001f)}; - mFilter[0].Hp.setParams(BiquadType::LowShelf, gainlf, lf0norm, - mFilter[0].Hp.rcpQFromSlope(gainlf, 1.0f)); - for(ALsizei i{1};i < NUM_LINES;i++) - { - mFilter[i].Lp.copyParamsFrom(mFilter[0].Lp); - mFilter[i].Hp.copyParamsFrom(mFilter[0].Hp); - } - - /* Update the main effect delay and associated taps. */ - updateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay, - props->Reverb.Density, props->Reverb.DecayTime, frequency); - - /* Update the early lines. */ - mEarly.updateLines(props->Reverb.Density, props->Reverb.Diffusion, props->Reverb.DecayTime, - frequency); - - /* Get the mixing matrix coefficients. */ - CalcMatrixCoeffs(props->Reverb.Diffusion, &mMixX, &mMixY); - - /* If the HF limit parameter is flagged, calculate an appropriate limit - * based on the air absorption parameter. - */ - ALfloat hfRatio{props->Reverb.DecayHFRatio}; - if(props->Reverb.DecayHFLimit && props->Reverb.AirAbsorptionGainHF < 1.0f) - hfRatio = CalcLimitedHfRatio(hfRatio, props->Reverb.AirAbsorptionGainHF, - props->Reverb.DecayTime, Listener.Params.ReverbSpeedOfSound - ); - - /* Calculate the LF/HF decay times. */ - const ALfloat lfDecayTime{clampf(props->Reverb.DecayTime * props->Reverb.DecayLFRatio, - AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME)}; - const ALfloat hfDecayTime{clampf(props->Reverb.DecayTime * hfRatio, - AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME)}; - - /* Update the late lines. */ - mLate.updateLines(props->Reverb.Density, props->Reverb.Diffusion, lfDecayTime, - props->Reverb.DecayTime, hfDecayTime, lf0norm, hf0norm, frequency); - - /* Update early and late 3D panning. */ - const ALfloat gain{props->Reverb.Gain * Slot->Params.Gain * ReverbBoost}; - update3DPanning(props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, - props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain, target); - - /* Calculate the max update size from the smallest relevant delay. */ - mMaxUpdate[1] = mini(BUFFERSIZE, mini(mEarly.Offset[0][1], mLate.Offset[0][1])); - - /* Determine if delay-line cross-fading is required. Density is essentially - * a master control for the feedback delays, so changes the offsets of many - * delay lines. - */ - if(mParams.Density != props->Reverb.Density || - /* Diffusion and decay times influences the decay rate (gain) of the - * late reverb T60 filter. - */ - mParams.Diffusion != props->Reverb.Diffusion || - mParams.DecayTime != props->Reverb.DecayTime || - mParams.HFDecayTime != hfDecayTime || - mParams.LFDecayTime != lfDecayTime || - /* HF/LF References control the weighting used to calculate the density - * gain. - */ - mParams.HFReference != props->Reverb.HFReference || - mParams.LFReference != props->Reverb.LFReference) - mFadeCount = 0; - mParams.Density = props->Reverb.Density; - mParams.Diffusion = props->Reverb.Diffusion; - mParams.DecayTime = props->Reverb.DecayTime; - mParams.HFDecayTime = hfDecayTime; - mParams.LFDecayTime = lfDecayTime; - mParams.HFReference = props->Reverb.HFReference; - mParams.LFReference = props->Reverb.LFReference; -} - - -/************************************** - * Effect Processing * - **************************************/ - -/* Applies a scattering matrix to the 4-line (vector) input. This is used - * for both the below vector all-pass model and to perform modal feed-back - * delay network (FDN) mixing. - * - * The matrix is derived from a skew-symmetric matrix to form a 4D rotation - * matrix with a single unitary rotational parameter: - * - * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2 - * [ -a, d, c, -b ] - * [ -b, -c, d, a ] - * [ -c, b, -a, d ] - * - * The rotation is constructed from the effect's diffusion parameter, - * yielding: - * - * 1 = x^2 + 3 y^2 - * - * Where a, b, and c are the coefficient y with differing signs, and d is the - * coefficient x. The final matrix is thus: - * - * [ x, y, -y, y ] n = sqrt(matrix_order - 1) - * [ -y, x, y, y ] t = diffusion_parameter * atan(n) - * [ y, -y, x, y ] x = cos(t) - * [ -y, -y, -y, x ] y = sin(t) / n - * - * Any square orthogonal matrix with an order that is a power of two will - * work (where ^T is transpose, ^-1 is inverse): - * - * M^T = M^-1 - * - * Using that knowledge, finding an appropriate matrix can be accomplished - * naively by searching all combinations of: - * - * M = D + S - S^T - * - * Where D is a diagonal matrix (of x), and S is a triangular matrix (of y) - * whose combination of signs are being iterated. - */ -inline void VectorPartialScatter(ALfloat *RESTRICT out, const ALfloat *RESTRICT in, - const ALfloat xCoeff, const ALfloat yCoeff) -{ - out[0] = xCoeff*in[0] + yCoeff*( in[1] + -in[2] + in[3]); - out[1] = xCoeff*in[1] + yCoeff*(-in[0] + in[2] + in[3]); - out[2] = xCoeff*in[2] + yCoeff*( in[0] + -in[1] + in[3]); - out[3] = xCoeff*in[3] + yCoeff*(-in[0] + -in[1] + -in[2] ); -} - -/* Utilizes the above, but reverses the input channels. */ -void VectorScatterRevDelayIn(const DelayLineI delay, ALint offset, const ALfloat xCoeff, - const ALfloat yCoeff, const ALsizei base, const al::span in, - const ALsizei count) -{ - ASSUME(base >= 0); - ASSUME(count > 0); - - for(ALsizei i{0};i < count;) - { - offset &= delay.Mask; - ALsizei td{mini(delay.Mask+1 - offset, count-i)}; - do { - ALfloat f[NUM_LINES]; - for(ALsizei j{0};j < NUM_LINES;j++) - f[NUM_LINES-1-j] = in[j][base+i]; - ++i; - - VectorPartialScatter(delay.Line[offset++], f, xCoeff, yCoeff); - } while(--td); - } -} - -/* This applies a Gerzon multiple-in/multiple-out (MIMO) vector all-pass - * filter to the 4-line input. - * - * It works by vectorizing a regular all-pass filter and replacing the delay - * element with a scattering matrix (like the one above) and a diagonal - * matrix of delay elements. - * - * Two static specializations are used for transitional (cross-faded) delay - * line processing and non-transitional processing. - */ -void VecAllpass::processUnfaded(const al::span samples, ALsizei offset, - const ALfloat xCoeff, const ALfloat yCoeff, const ALsizei todo) -{ - const DelayLineI delay{Delay}; - const ALfloat feedCoeff{Coeff}; - - ASSUME(todo > 0); - - ALsizei vap_offset[NUM_LINES]; - for(ALsizei j{0};j < NUM_LINES;j++) - vap_offset[j] = offset - Offset[j][0]; - for(ALsizei i{0};i < todo;) - { - for(ALsizei j{0};j < NUM_LINES;j++) - vap_offset[j] &= delay.Mask; - offset &= delay.Mask; - - ALsizei maxoff{offset}; - for(ALsizei j{0};j < NUM_LINES;j++) - maxoff = maxi(maxoff, vap_offset[j]); - ALsizei td{mini(delay.Mask+1 - maxoff, todo - i)}; - - do { - ALfloat f[NUM_LINES]; - for(ALsizei j{0};j < NUM_LINES;j++) - { - const ALfloat input{samples[j][i]}; - const ALfloat out{delay.Line[vap_offset[j]++][j] - feedCoeff*input}; - f[j] = input + feedCoeff*out; - - samples[j][i] = out; - } - ++i; - - VectorPartialScatter(delay.Line[offset++], f, xCoeff, yCoeff); - } while(--td); - } -} -void VecAllpass::processFaded(const al::span samples, ALsizei offset, - const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, const ALsizei todo) -{ - const DelayLineI delay{Delay}; - const ALfloat feedCoeff{Coeff}; - - ASSUME(todo > 0); - - fade *= 1.0f/FADE_SAMPLES; - ALsizei vap_offset[NUM_LINES][2]; - for(ALsizei j{0};j < NUM_LINES;j++) - { - vap_offset[j][0] = offset - Offset[j][0]; - vap_offset[j][1] = offset - Offset[j][1]; - } - for(ALsizei i{0};i < todo;) - { - for(ALsizei j{0};j < NUM_LINES;j++) - { - vap_offset[j][0] &= delay.Mask; - vap_offset[j][1] &= delay.Mask; - } - offset &= delay.Mask; - - ALsizei maxoff{offset}; - for(ALsizei j{0};j < NUM_LINES;j++) - maxoff = maxi(maxoff, maxi(vap_offset[j][0], vap_offset[j][1])); - ALsizei td{mini(delay.Mask+1 - maxoff, todo - i)}; - - do { - fade += FadeStep; - ALfloat f[NUM_LINES]; - for(ALsizei j{0};j < NUM_LINES;j++) - f[j] = delay.Line[vap_offset[j][0]++][j]*(1.0f-fade) + - delay.Line[vap_offset[j][1]++][j]*fade; - - for(ALsizei j{0};j < NUM_LINES;j++) - { - const ALfloat input{samples[j][i]}; - const ALfloat out{f[j] - feedCoeff*input}; - f[j] = input + feedCoeff*out; - - samples[j][i] = out; - } - ++i; - - VectorPartialScatter(delay.Line[offset++], f, xCoeff, yCoeff); - } while(--td); - } -} - -/* This generates early reflections. - * - * This is done by obtaining the primary reflections (those arriving from the - * same direction as the source) from the main delay line. These are - * attenuated and all-pass filtered (based on the diffusion parameter). - * - * The early lines are then fed in reverse (according to the approximately - * opposite spatial location of the A-Format lines) to create the secondary - * reflections (those arriving from the opposite direction as the source). - * - * The early response is then completed by combining the primary reflections - * with the delayed and attenuated output from the early lines. - * - * Finally, the early response is reversed, scattered (based on diffusion), - * and fed into the late reverb section of the main delay line. - * - * Two static specializations are used for transitional (cross-faded) delay - * line processing and non-transitional processing. - */ -void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei todo, - const ALsizei base, const al::span out) -{ - const al::span temps{State->mTempSamples}; - const DelayLineI early_delay{State->mEarly.Delay}; - const DelayLineI main_delay{State->mDelay}; - const ALfloat mixX{State->mMixX}; - const ALfloat mixY{State->mMixY}; - - ASSUME(todo > 0); - - /* First, load decorrelated samples from the main delay line as the primary - * reflections. - */ - for(ALsizei j{0};j < NUM_LINES;j++) - { - ALsizei early_delay_tap{offset - State->mEarlyDelayTap[j][0]}; - const ALfloat coeff{State->mEarlyDelayCoeff[j][0]}; - for(ALsizei i{0};i < todo;) - { - early_delay_tap &= main_delay.Mask; - ALsizei td{mini(main_delay.Mask+1 - early_delay_tap, todo - i)}; - do { - temps[j][i++] = main_delay.Line[early_delay_tap++][j] * coeff; - } while(--td); - } - } - - /* Apply a vector all-pass, to help color the initial reflections based on - * the diffusion strength. - */ - State->mEarly.VecAp.processUnfaded(temps, offset, mixX, mixY, todo); - - /* Apply a delay and bounce to generate secondary reflections, combine with - * the primary reflections and write out the result for mixing. - */ - for(ALsizei j{0};j < NUM_LINES;j++) - { - ALint feedb_tap{offset - State->mEarly.Offset[j][0]}; - const ALfloat feedb_coeff{State->mEarly.Coeff[j][0]}; - - ASSUME(base >= 0); - for(ALsizei i{0};i < todo;) - { - feedb_tap &= early_delay.Mask; - ALsizei td{mini(early_delay.Mask+1 - feedb_tap, todo - i)}; - do { - out[j][base+i] = temps[j][i] + early_delay.Line[feedb_tap++][j]*feedb_coeff; - ++i; - } while(--td); - } - } - for(ALsizei j{0};j < NUM_LINES;j++) - early_delay.write(offset, NUM_LINES-1-j, temps[j].data(), todo); - - /* Also write the result back to the main delay line for the late reverb - * stage to pick up at the appropriate time, appplying a scatter and - * bounce to improve the initial diffusion in the late reverb. - */ - const ALsizei late_feed_tap{offset - State->mLateFeedTap}; - VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, - {out.cbegin(), out.cend()}, todo); -} -void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, - const ALfloat fade, const ALsizei base, const al::span out) -{ - const al::span temps{State->mTempSamples}; - const DelayLineI early_delay{State->mEarly.Delay}; - const DelayLineI main_delay{State->mDelay}; - const ALfloat mixX{State->mMixX}; - const ALfloat mixY{State->mMixY}; - - ASSUME(todo > 0); - - for(ALsizei j{0};j < NUM_LINES;j++) - { - ALsizei early_delay_tap0{offset - State->mEarlyDelayTap[j][0]}; - ALsizei early_delay_tap1{offset - State->mEarlyDelayTap[j][1]}; - const ALfloat oldCoeff{State->mEarlyDelayCoeff[j][0]}; - const ALfloat oldCoeffStep{-oldCoeff / FADE_SAMPLES}; - const ALfloat newCoeffStep{State->mEarlyDelayCoeff[j][1] / FADE_SAMPLES}; - ALfloat fadeCount{fade}; - - for(ALsizei i{0};i < todo;) - { - early_delay_tap0 &= main_delay.Mask; - early_delay_tap1 &= main_delay.Mask; - ALsizei td{mini(main_delay.Mask+1 - maxi(early_delay_tap0, early_delay_tap1), todo-i)}; - do { - fadeCount += 1.0f; - const ALfloat fade0{oldCoeff + oldCoeffStep*fadeCount}; - const ALfloat fade1{newCoeffStep*fadeCount}; - temps[j][i++] = - main_delay.Line[early_delay_tap0++][j]*fade0 + - main_delay.Line[early_delay_tap1++][j]*fade1; - } while(--td); - } - } - - State->mEarly.VecAp.processFaded(temps, offset, mixX, mixY, fade, todo); - - for(ALsizei j{0};j < NUM_LINES;j++) - { - ALint feedb_tap0{offset - State->mEarly.Offset[j][0]}; - ALint feedb_tap1{offset - State->mEarly.Offset[j][1]}; - const ALfloat feedb_oldCoeff{State->mEarly.Coeff[j][0]}; - const ALfloat feedb_oldCoeffStep{-feedb_oldCoeff / FADE_SAMPLES}; - const ALfloat feedb_newCoeffStep{State->mEarly.Coeff[j][1] / FADE_SAMPLES}; - ALfloat fadeCount{fade}; - - ASSUME(base >= 0); - for(ALsizei i{0};i < todo;) - { - feedb_tap0 &= early_delay.Mask; - feedb_tap1 &= early_delay.Mask; - ALsizei td{mini(early_delay.Mask+1 - maxi(feedb_tap0, feedb_tap1), todo - i)}; - - do { - fadeCount += 1.0f; - const ALfloat fade0{feedb_oldCoeff + feedb_oldCoeffStep*fadeCount}; - const ALfloat fade1{feedb_newCoeffStep*fadeCount}; - out[j][base+i] = temps[j][i] + - early_delay.Line[feedb_tap0++][j]*fade0 + - early_delay.Line[feedb_tap1++][j]*fade1; - ++i; - } while(--td); - } - } - for(ALsizei j{0};j < NUM_LINES;j++) - early_delay.write(offset, NUM_LINES-1-j, temps[j].data(), todo); - - const ALsizei late_feed_tap{offset - State->mLateFeedTap}; - VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, - {out.cbegin(), out.cend()}, todo); -} - -/* This generates the reverb tail using a modified feed-back delay network - * (FDN). - * - * Results from the early reflections are mixed with the output from the late - * delay lines. - * - * The late response is then completed by T60 and all-pass filtering the mix. - * - * Finally, the lines are reversed (so they feed their opposite directions) - * and scattered with the FDN matrix before re-feeding the delay lines. - * - * Two variations are made, one for for transitional (cross-faded) delay line - * processing and one for non-transitional processing. - */ -void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei todo, - const ALsizei base, const al::span out) -{ - const al::span temps{State->mTempSamples}; - const DelayLineI late_delay{State->mLate.Delay}; - const DelayLineI main_delay{State->mDelay}; - const ALfloat mixX{State->mMixX}; - const ALfloat mixY{State->mMixY}; - - ASSUME(todo > 0); - - /* First, load decorrelated samples from the main and feedback delay lines. - * Filter the signal to apply its frequency-dependent decay. - */ - for(ALsizei j{0};j < NUM_LINES;j++) - { - ALsizei late_delay_tap{offset - State->mLateDelayTap[j][0]}; - ALsizei late_feedb_tap{offset - State->mLate.Offset[j][0]}; - const ALfloat midGain{State->mLate.T60[j].MidGain[0]}; - const ALfloat densityGain{State->mLate.DensityGain[0] * midGain}; - for(ALsizei i{0};i < todo;) - { - late_delay_tap &= main_delay.Mask; - late_feedb_tap &= late_delay.Mask; - ALsizei td{mini( - mini(main_delay.Mask+1 - late_delay_tap, late_delay.Mask+1 - late_feedb_tap), - todo - i)}; - do { - temps[j][i++] = - main_delay.Line[late_delay_tap++][j]*densityGain + - late_delay.Line[late_feedb_tap++][j]*midGain; - } while(--td); - } - State->mLate.T60[j].process(temps[j].data(), todo); - } - - /* Apply a vector all-pass to improve micro-surface diffusion, and write - * out the results for mixing. - */ - State->mLate.VecAp.processUnfaded(temps, offset, mixX, mixY, todo); - - for(ALsizei j{0};j < NUM_LINES;j++) - std::copy_n(temps[j].begin(), todo, out[j].begin()+base); - - /* Finally, scatter and bounce the results to refeed the feedback buffer. */ - VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, - {out.cbegin(), out.cend()}, todo); -} -void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, - const ALfloat fade, const ALsizei base, const al::span out) -{ - const al::span temps{State->mTempSamples}; - const DelayLineI late_delay{State->mLate.Delay}; - const DelayLineI main_delay{State->mDelay}; - const ALfloat mixX{State->mMixX}; - const ALfloat mixY{State->mMixY}; - - ASSUME(todo > 0); - - for(ALsizei j{0};j < NUM_LINES;j++) - { - const ALfloat oldMidGain{State->mLate.T60[j].MidGain[0]}; - const ALfloat midGain{State->mLate.T60[j].MidGain[1]}; - const ALfloat oldMidStep{-oldMidGain / FADE_SAMPLES}; - const ALfloat midStep{midGain / FADE_SAMPLES}; - const ALfloat oldDensityGain{State->mLate.DensityGain[0] * oldMidGain}; - const ALfloat densityGain{State->mLate.DensityGain[1] * midGain}; - const ALfloat oldDensityStep{-oldDensityGain / FADE_SAMPLES}; - const ALfloat densityStep{densityGain / FADE_SAMPLES}; - ALsizei late_delay_tap0{offset - State->mLateDelayTap[j][0]}; - ALsizei late_delay_tap1{offset - State->mLateDelayTap[j][1]}; - ALsizei late_feedb_tap0{offset - State->mLate.Offset[j][0]}; - ALsizei late_feedb_tap1{offset - State->mLate.Offset[j][1]}; - ALfloat fadeCount{fade}; - - for(ALsizei i{0};i < todo;) - { - late_delay_tap0 &= main_delay.Mask; - late_delay_tap1 &= main_delay.Mask; - late_feedb_tap0 &= late_delay.Mask; - late_feedb_tap1 &= late_delay.Mask; - ALsizei td{mini( - mini(main_delay.Mask+1 - maxi(late_delay_tap0, late_delay_tap1), - late_delay.Mask+1 - maxi(late_feedb_tap0, late_feedb_tap1)), - todo - i)}; - do { - fadeCount += 1.0f; - const ALfloat fade0{oldDensityGain + oldDensityStep*fadeCount}; - const ALfloat fade1{densityStep*fadeCount}; - const ALfloat gfade0{oldMidGain + oldMidStep*fadeCount}; - const ALfloat gfade1{midStep*fadeCount}; - temps[j][i++] = - main_delay.Line[late_delay_tap0++][j]*fade0 + - main_delay.Line[late_delay_tap1++][j]*fade1 + - late_delay.Line[late_feedb_tap0++][j]*gfade0 + - late_delay.Line[late_feedb_tap1++][j]*gfade1; - } while(--td); - } - State->mLate.T60[j].process(temps[j].data(), todo); - } - - State->mLate.VecAp.processFaded(temps, offset, mixX, mixY, fade, todo); - - for(ALsizei j{0};j < NUM_LINES;j++) - std::copy_n(temps[j].begin(), todo, out[j].begin()+base); - - VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, - {out.cbegin(), out.cend()}, todo); -} - -void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) -{ - ALsizei fadeCount{mFadeCount}; - - ASSUME(samplesToDo > 0); - - /* Convert B-Format to A-Format for processing. */ - const al::span afmt{mTempSamples}; - for(ALsizei c{0};c < NUM_LINES;c++) - { - std::fill_n(afmt[c].begin(), samplesToDo, 0.0f); - MixRowSamples(afmt[c], B2A[c], {samplesIn, samplesIn+numInput}, 0, samplesToDo); - - /* Band-pass the incoming samples. */ - mFilter[c].Lp.process(afmt[c].data(), afmt[c].data(), samplesToDo); - mFilter[c].Hp.process(afmt[c].data(), afmt[c].data(), samplesToDo); - } - - /* Process reverb for these samples. */ - for(ALsizei base{0};base < samplesToDo;) - { - ALsizei todo{samplesToDo - base}; - /* If cross-fading, don't do more samples than there are to fade. */ - if(FADE_SAMPLES-fadeCount > 0) - { - todo = mini(todo, FADE_SAMPLES-fadeCount); - todo = mini(todo, mMaxUpdate[0]); - } - todo = mini(todo, mMaxUpdate[1]); - ASSUME(todo > 0 && todo <= BUFFERSIZE); - - const ALsizei offset{mOffset + base}; - ASSUME(offset >= 0); - - /* Feed the initial delay line. */ - for(ALsizei c{0};c < NUM_LINES;c++) - mDelay.write(offset, c, afmt[c].data()+base, todo); - - /* Process the samples for reverb. */ - if(UNLIKELY(fadeCount < FADE_SAMPLES)) - { - auto fade = static_cast(fadeCount); - - /* Generate early reflections and late reverb. */ - EarlyReflection_Faded(this, offset, todo, fade, base, mEarlyBuffer); - - LateReverb_Faded(this, offset, todo, fade, base, mLateBuffer); - - /* Step fading forward. */ - fadeCount += todo; - if(fadeCount >= FADE_SAMPLES) - { - /* Update the cross-fading delay line taps. */ - fadeCount = FADE_SAMPLES; - for(ALsizei c{0};c < NUM_LINES;c++) - { - mEarlyDelayTap[c][0] = mEarlyDelayTap[c][1]; - mEarlyDelayCoeff[c][0] = mEarlyDelayCoeff[c][1]; - mEarly.VecAp.Offset[c][0] = mEarly.VecAp.Offset[c][1]; - mEarly.Offset[c][0] = mEarly.Offset[c][1]; - mEarly.Coeff[c][0] = mEarly.Coeff[c][1]; - mLateDelayTap[c][0] = mLateDelayTap[c][1]; - mLate.VecAp.Offset[c][0] = mLate.VecAp.Offset[c][1]; - mLate.Offset[c][0] = mLate.Offset[c][1]; - mLate.T60[c].MidGain[0] = mLate.T60[c].MidGain[1]; - } - mLate.DensityGain[0] = mLate.DensityGain[1]; - mMaxUpdate[0] = mMaxUpdate[1]; - } - } - else - { - /* Generate early reflections and late reverb. */ - EarlyReflection_Unfaded(this, offset, todo, base, mEarlyBuffer); - - LateReverb_Unfaded(this, offset, todo, base, mLateBuffer); - } - - base += todo; - } - mOffset = (mOffset+samplesToDo) & 0x3fffffff; - mFadeCount = fadeCount; - - /* Finally, mix early reflections and late reverb. */ - (this->*mMixOut)(samplesOut, samplesToDo); -} - - -void EAXReverb_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val) -{ - switch(param) - { - case AL_EAXREVERB_DECAY_HFLIMIT: - if(!(val >= AL_EAXREVERB_MIN_DECAY_HFLIMIT && val <= AL_EAXREVERB_MAX_DECAY_HFLIMIT)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay hflimit out of range"); - props->Reverb.DecayHFLimit = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb integer property 0x%04x", - param); - } -} -void EAXReverb_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) -{ EAXReverb_setParami(props, context, param, vals[0]); } -void EAXReverb_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_EAXREVERB_DENSITY: - if(!(val >= AL_EAXREVERB_MIN_DENSITY && val <= AL_EAXREVERB_MAX_DENSITY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb density out of range"); - props->Reverb.Density = val; - break; - - case AL_EAXREVERB_DIFFUSION: - if(!(val >= AL_EAXREVERB_MIN_DIFFUSION && val <= AL_EAXREVERB_MAX_DIFFUSION)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb diffusion out of range"); - props->Reverb.Diffusion = val; - break; - - case AL_EAXREVERB_GAIN: - if(!(val >= AL_EAXREVERB_MIN_GAIN && val <= AL_EAXREVERB_MAX_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb gain out of range"); - props->Reverb.Gain = val; - break; - - case AL_EAXREVERB_GAINHF: - if(!(val >= AL_EAXREVERB_MIN_GAINHF && val <= AL_EAXREVERB_MAX_GAINHF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb gainhf out of range"); - props->Reverb.GainHF = val; - break; - - case AL_EAXREVERB_GAINLF: - if(!(val >= AL_EAXREVERB_MIN_GAINLF && val <= AL_EAXREVERB_MAX_GAINLF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb gainlf out of range"); - props->Reverb.GainLF = val; - break; - - case AL_EAXREVERB_DECAY_TIME: - if(!(val >= AL_EAXREVERB_MIN_DECAY_TIME && val <= AL_EAXREVERB_MAX_DECAY_TIME)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay time out of range"); - props->Reverb.DecayTime = val; - break; - - case AL_EAXREVERB_DECAY_HFRATIO: - if(!(val >= AL_EAXREVERB_MIN_DECAY_HFRATIO && val <= AL_EAXREVERB_MAX_DECAY_HFRATIO)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay hfratio out of range"); - props->Reverb.DecayHFRatio = val; - break; - - case AL_EAXREVERB_DECAY_LFRATIO: - if(!(val >= AL_EAXREVERB_MIN_DECAY_LFRATIO && val <= AL_EAXREVERB_MAX_DECAY_LFRATIO)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay lfratio out of range"); - props->Reverb.DecayLFRatio = val; - break; - - case AL_EAXREVERB_REFLECTIONS_GAIN: - if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_GAIN && val <= AL_EAXREVERB_MAX_REFLECTIONS_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb reflections gain out of range"); - props->Reverb.ReflectionsGain = val; - break; - - case AL_EAXREVERB_REFLECTIONS_DELAY: - if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_DELAY && val <= AL_EAXREVERB_MAX_REFLECTIONS_DELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb reflections delay out of range"); - props->Reverb.ReflectionsDelay = val; - break; - - case AL_EAXREVERB_LATE_REVERB_GAIN: - if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_GAIN && val <= AL_EAXREVERB_MAX_LATE_REVERB_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb late reverb gain out of range"); - props->Reverb.LateReverbGain = val; - break; - - case AL_EAXREVERB_LATE_REVERB_DELAY: - if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_DELAY && val <= AL_EAXREVERB_MAX_LATE_REVERB_DELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb late reverb delay out of range"); - props->Reverb.LateReverbDelay = val; - break; - - case AL_EAXREVERB_AIR_ABSORPTION_GAINHF: - if(!(val >= AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb air absorption gainhf out of range"); - props->Reverb.AirAbsorptionGainHF = val; - break; - - case AL_EAXREVERB_ECHO_TIME: - if(!(val >= AL_EAXREVERB_MIN_ECHO_TIME && val <= AL_EAXREVERB_MAX_ECHO_TIME)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb echo time out of range"); - props->Reverb.EchoTime = val; - break; - - case AL_EAXREVERB_ECHO_DEPTH: - if(!(val >= AL_EAXREVERB_MIN_ECHO_DEPTH && val <= AL_EAXREVERB_MAX_ECHO_DEPTH)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb echo depth out of range"); - props->Reverb.EchoDepth = val; - break; - - case AL_EAXREVERB_MODULATION_TIME: - if(!(val >= AL_EAXREVERB_MIN_MODULATION_TIME && val <= AL_EAXREVERB_MAX_MODULATION_TIME)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb modulation time out of range"); - props->Reverb.ModulationTime = val; - break; - - case AL_EAXREVERB_MODULATION_DEPTH: - if(!(val >= AL_EAXREVERB_MIN_MODULATION_DEPTH && val <= AL_EAXREVERB_MAX_MODULATION_DEPTH)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb modulation depth out of range"); - props->Reverb.ModulationDepth = val; - break; - - case AL_EAXREVERB_HFREFERENCE: - if(!(val >= AL_EAXREVERB_MIN_HFREFERENCE && val <= AL_EAXREVERB_MAX_HFREFERENCE)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb hfreference out of range"); - props->Reverb.HFReference = val; - break; - - case AL_EAXREVERB_LFREFERENCE: - if(!(val >= AL_EAXREVERB_MIN_LFREFERENCE && val <= AL_EAXREVERB_MAX_LFREFERENCE)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb lfreference out of range"); - props->Reverb.LFReference = val; - break; - - case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR: - if(!(val >= AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb room rolloff factor out of range"); - props->Reverb.RoomRolloffFactor = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", - param); - } -} -void EAXReverb_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - switch(param) - { - case AL_EAXREVERB_REFLECTIONS_PAN: - if(!(std::isfinite(vals[0]) && std::isfinite(vals[1]) && std::isfinite(vals[2]))) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb reflections pan out of range"); - props->Reverb.ReflectionsPan[0] = vals[0]; - props->Reverb.ReflectionsPan[1] = vals[1]; - props->Reverb.ReflectionsPan[2] = vals[2]; - break; - case AL_EAXREVERB_LATE_REVERB_PAN: - if(!(std::isfinite(vals[0]) && std::isfinite(vals[1]) && std::isfinite(vals[2]))) - SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb late reverb pan out of range"); - props->Reverb.LateReverbPan[0] = vals[0]; - props->Reverb.LateReverbPan[1] = vals[1]; - props->Reverb.LateReverbPan[2] = vals[2]; - break; - - default: - EAXReverb_setParamf(props, context, param, vals[0]); - break; - } -} - -void EAXReverb_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val) -{ - switch(param) - { - case AL_EAXREVERB_DECAY_HFLIMIT: - *val = props->Reverb.DecayHFLimit; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb integer property 0x%04x", - param); - } -} -void EAXReverb_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) -{ EAXReverb_getParami(props, context, param, vals); } -void EAXReverb_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_EAXREVERB_DENSITY: - *val = props->Reverb.Density; - break; - - case AL_EAXREVERB_DIFFUSION: - *val = props->Reverb.Diffusion; - break; - - case AL_EAXREVERB_GAIN: - *val = props->Reverb.Gain; - break; - - case AL_EAXREVERB_GAINHF: - *val = props->Reverb.GainHF; - break; - - case AL_EAXREVERB_GAINLF: - *val = props->Reverb.GainLF; - break; - - case AL_EAXREVERB_DECAY_TIME: - *val = props->Reverb.DecayTime; - break; - - case AL_EAXREVERB_DECAY_HFRATIO: - *val = props->Reverb.DecayHFRatio; - break; - - case AL_EAXREVERB_DECAY_LFRATIO: - *val = props->Reverb.DecayLFRatio; - break; - - case AL_EAXREVERB_REFLECTIONS_GAIN: - *val = props->Reverb.ReflectionsGain; - break; - - case AL_EAXREVERB_REFLECTIONS_DELAY: - *val = props->Reverb.ReflectionsDelay; - break; - - case AL_EAXREVERB_LATE_REVERB_GAIN: - *val = props->Reverb.LateReverbGain; - break; - - case AL_EAXREVERB_LATE_REVERB_DELAY: - *val = props->Reverb.LateReverbDelay; - break; - - case AL_EAXREVERB_AIR_ABSORPTION_GAINHF: - *val = props->Reverb.AirAbsorptionGainHF; - break; - - case AL_EAXREVERB_ECHO_TIME: - *val = props->Reverb.EchoTime; - break; - - case AL_EAXREVERB_ECHO_DEPTH: - *val = props->Reverb.EchoDepth; - break; - - case AL_EAXREVERB_MODULATION_TIME: - *val = props->Reverb.ModulationTime; - break; - - case AL_EAXREVERB_MODULATION_DEPTH: - *val = props->Reverb.ModulationDepth; - break; - - case AL_EAXREVERB_HFREFERENCE: - *val = props->Reverb.HFReference; - break; - - case AL_EAXREVERB_LFREFERENCE: - *val = props->Reverb.LFReference; - break; - - case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR: - *val = props->Reverb.RoomRolloffFactor; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", - param); - } -} -void EAXReverb_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) -{ - switch(param) - { - case AL_EAXREVERB_REFLECTIONS_PAN: - vals[0] = props->Reverb.ReflectionsPan[0]; - vals[1] = props->Reverb.ReflectionsPan[1]; - vals[2] = props->Reverb.ReflectionsPan[2]; - break; - case AL_EAXREVERB_LATE_REVERB_PAN: - vals[0] = props->Reverb.LateReverbPan[0]; - vals[1] = props->Reverb.LateReverbPan[1]; - vals[2] = props->Reverb.LateReverbPan[2]; - break; - - default: - EAXReverb_getParamf(props, context, param, vals); - break; - } -} - -DEFINE_ALEFFECT_VTABLE(EAXReverb); - - -struct ReverbStateFactory final : public EffectStateFactory { - EffectState *create() override { return new ReverbState{}; } - EffectProps getDefaultProps() const noexcept override; - const EffectVtable *getEffectVtable() const noexcept override { return &EAXReverb_vtable; } -}; - -EffectProps ReverbStateFactory::getDefaultProps() const noexcept -{ - EffectProps props{}; - props.Reverb.Density = AL_EAXREVERB_DEFAULT_DENSITY; - props.Reverb.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION; - props.Reverb.Gain = AL_EAXREVERB_DEFAULT_GAIN; - props.Reverb.GainHF = AL_EAXREVERB_DEFAULT_GAINHF; - props.Reverb.GainLF = AL_EAXREVERB_DEFAULT_GAINLF; - props.Reverb.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME; - props.Reverb.DecayHFRatio = AL_EAXREVERB_DEFAULT_DECAY_HFRATIO; - props.Reverb.DecayLFRatio = AL_EAXREVERB_DEFAULT_DECAY_LFRATIO; - props.Reverb.ReflectionsGain = AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN; - props.Reverb.ReflectionsDelay = AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY; - props.Reverb.ReflectionsPan[0] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; - props.Reverb.ReflectionsPan[1] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; - props.Reverb.ReflectionsPan[2] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; - props.Reverb.LateReverbGain = AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN; - props.Reverb.LateReverbDelay = AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY; - props.Reverb.LateReverbPan[0] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; - props.Reverb.LateReverbPan[1] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; - props.Reverb.LateReverbPan[2] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; - props.Reverb.EchoTime = AL_EAXREVERB_DEFAULT_ECHO_TIME; - props.Reverb.EchoDepth = AL_EAXREVERB_DEFAULT_ECHO_DEPTH; - props.Reverb.ModulationTime = AL_EAXREVERB_DEFAULT_MODULATION_TIME; - props.Reverb.ModulationDepth = AL_EAXREVERB_DEFAULT_MODULATION_DEPTH; - props.Reverb.AirAbsorptionGainHF = AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF; - props.Reverb.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE; - props.Reverb.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE; - props.Reverb.RoomRolloffFactor = AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; - props.Reverb.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT; - return props; -} - - -void StdReverb_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val) -{ - switch(param) - { - case AL_REVERB_DECAY_HFLIMIT: - if(!(val >= AL_REVERB_MIN_DECAY_HFLIMIT && val <= AL_REVERB_MAX_DECAY_HFLIMIT)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb decay hflimit out of range"); - props->Reverb.DecayHFLimit = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid reverb integer property 0x%04x", param); - } -} -void StdReverb_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) -{ StdReverb_setParami(props, context, param, vals[0]); } -void StdReverb_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_REVERB_DENSITY: - if(!(val >= AL_REVERB_MIN_DENSITY && val <= AL_REVERB_MAX_DENSITY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb density out of range"); - props->Reverb.Density = val; - break; - - case AL_REVERB_DIFFUSION: - if(!(val >= AL_REVERB_MIN_DIFFUSION && val <= AL_REVERB_MAX_DIFFUSION)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb diffusion out of range"); - props->Reverb.Diffusion = val; - break; - - case AL_REVERB_GAIN: - if(!(val >= AL_REVERB_MIN_GAIN && val <= AL_REVERB_MAX_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb gain out of range"); - props->Reverb.Gain = val; - break; - - case AL_REVERB_GAINHF: - if(!(val >= AL_REVERB_MIN_GAINHF && val <= AL_REVERB_MAX_GAINHF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb gainhf out of range"); - props->Reverb.GainHF = val; - break; - - case AL_REVERB_DECAY_TIME: - if(!(val >= AL_REVERB_MIN_DECAY_TIME && val <= AL_REVERB_MAX_DECAY_TIME)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb decay time out of range"); - props->Reverb.DecayTime = val; - break; - - case AL_REVERB_DECAY_HFRATIO: - if(!(val >= AL_REVERB_MIN_DECAY_HFRATIO && val <= AL_REVERB_MAX_DECAY_HFRATIO)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb decay hfratio out of range"); - props->Reverb.DecayHFRatio = val; - break; - - case AL_REVERB_REFLECTIONS_GAIN: - if(!(val >= AL_REVERB_MIN_REFLECTIONS_GAIN && val <= AL_REVERB_MAX_REFLECTIONS_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb reflections gain out of range"); - props->Reverb.ReflectionsGain = val; - break; - - case AL_REVERB_REFLECTIONS_DELAY: - if(!(val >= AL_REVERB_MIN_REFLECTIONS_DELAY && val <= AL_REVERB_MAX_REFLECTIONS_DELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb reflections delay out of range"); - props->Reverb.ReflectionsDelay = val; - break; - - case AL_REVERB_LATE_REVERB_GAIN: - if(!(val >= AL_REVERB_MIN_LATE_REVERB_GAIN && val <= AL_REVERB_MAX_LATE_REVERB_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb late reverb gain out of range"); - props->Reverb.LateReverbGain = val; - break; - - case AL_REVERB_LATE_REVERB_DELAY: - if(!(val >= AL_REVERB_MIN_LATE_REVERB_DELAY && val <= AL_REVERB_MAX_LATE_REVERB_DELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb late reverb delay out of range"); - props->Reverb.LateReverbDelay = val; - break; - - case AL_REVERB_AIR_ABSORPTION_GAINHF: - if(!(val >= AL_REVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_REVERB_MAX_AIR_ABSORPTION_GAINHF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb air absorption gainhf out of range"); - props->Reverb.AirAbsorptionGainHF = val; - break; - - case AL_REVERB_ROOM_ROLLOFF_FACTOR: - if(!(val >= AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb room rolloff factor out of range"); - props->Reverb.RoomRolloffFactor = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid reverb float property 0x%04x", param); - } -} -void StdReverb_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) -{ StdReverb_setParamf(props, context, param, vals[0]); } - -void StdReverb_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val) -{ - switch(param) - { - case AL_REVERB_DECAY_HFLIMIT: - *val = props->Reverb.DecayHFLimit; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid reverb integer property 0x%04x", param); - } -} -void StdReverb_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) -{ StdReverb_getParami(props, context, param, vals); } -void StdReverb_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_REVERB_DENSITY: - *val = props->Reverb.Density; - break; - - case AL_REVERB_DIFFUSION: - *val = props->Reverb.Diffusion; - break; - - case AL_REVERB_GAIN: - *val = props->Reverb.Gain; - break; - - case AL_REVERB_GAINHF: - *val = props->Reverb.GainHF; - break; - - case AL_REVERB_DECAY_TIME: - *val = props->Reverb.DecayTime; - break; - - case AL_REVERB_DECAY_HFRATIO: - *val = props->Reverb.DecayHFRatio; - break; - - case AL_REVERB_REFLECTIONS_GAIN: - *val = props->Reverb.ReflectionsGain; - break; - - case AL_REVERB_REFLECTIONS_DELAY: - *val = props->Reverb.ReflectionsDelay; - break; - - case AL_REVERB_LATE_REVERB_GAIN: - *val = props->Reverb.LateReverbGain; - break; - - case AL_REVERB_LATE_REVERB_DELAY: - *val = props->Reverb.LateReverbDelay; - break; - - case AL_REVERB_AIR_ABSORPTION_GAINHF: - *val = props->Reverb.AirAbsorptionGainHF; - break; - - case AL_REVERB_ROOM_ROLLOFF_FACTOR: - *val = props->Reverb.RoomRolloffFactor; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid reverb float property 0x%04x", param); - } -} -void StdReverb_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) -{ StdReverb_getParamf(props, context, param, vals); } - -DEFINE_ALEFFECT_VTABLE(StdReverb); - - -struct StdReverbStateFactory final : public EffectStateFactory { - EffectState *create() override { return new ReverbState{}; } - EffectProps getDefaultProps() const noexcept override; - const EffectVtable *getEffectVtable() const noexcept override { return &StdReverb_vtable; } -}; - -EffectProps StdReverbStateFactory::getDefaultProps() const noexcept -{ - EffectProps props{}; - props.Reverb.Density = AL_REVERB_DEFAULT_DENSITY; - props.Reverb.Diffusion = AL_REVERB_DEFAULT_DIFFUSION; - props.Reverb.Gain = AL_REVERB_DEFAULT_GAIN; - props.Reverb.GainHF = AL_REVERB_DEFAULT_GAINHF; - props.Reverb.GainLF = 1.0f; - props.Reverb.DecayTime = AL_REVERB_DEFAULT_DECAY_TIME; - props.Reverb.DecayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO; - props.Reverb.DecayLFRatio = 1.0f; - props.Reverb.ReflectionsGain = AL_REVERB_DEFAULT_REFLECTIONS_GAIN; - props.Reverb.ReflectionsDelay = AL_REVERB_DEFAULT_REFLECTIONS_DELAY; - props.Reverb.ReflectionsPan[0] = 0.0f; - props.Reverb.ReflectionsPan[1] = 0.0f; - props.Reverb.ReflectionsPan[2] = 0.0f; - props.Reverb.LateReverbGain = AL_REVERB_DEFAULT_LATE_REVERB_GAIN; - props.Reverb.LateReverbDelay = AL_REVERB_DEFAULT_LATE_REVERB_DELAY; - props.Reverb.LateReverbPan[0] = 0.0f; - props.Reverb.LateReverbPan[1] = 0.0f; - props.Reverb.LateReverbPan[2] = 0.0f; - props.Reverb.EchoTime = 0.25f; - props.Reverb.EchoDepth = 0.0f; - props.Reverb.ModulationTime = 0.25f; - props.Reverb.ModulationDepth = 0.0f; - props.Reverb.AirAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF; - props.Reverb.HFReference = 5000.0f; - props.Reverb.LFReference = 250.0f; - props.Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; - props.Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT; - return props; -} - -} // namespace - -EffectStateFactory *ReverbStateFactory_getFactory() -{ - static ReverbStateFactory ReverbFactory{}; - return &ReverbFactory; -} - -EffectStateFactory *StdReverbStateFactory_getFactory() -{ - static StdReverbStateFactory ReverbFactory{}; - return &ReverbFactory; -} diff --git a/Alc/effects/vmorpher.cpp b/Alc/effects/vmorpher.cpp deleted file mode 100644 index eebba3f1..00000000 --- a/Alc/effects/vmorpher.cpp +++ /dev/null @@ -1,430 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2019 by Anis A. Hireche - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include -#include - -#include "alcmain.h" -#include "alcontext.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" - -namespace { - -#define MAX_UPDATE_SAMPLES 128 -#define NUM_FORMANTS 4 -#define NUM_FILTERS 2 -#define Q_FACTOR 5.0f - -#define VOWEL_A_INDEX 0 -#define VOWEL_B_INDEX 1 - -#define WAVEFORM_FRACBITS 24 -#define WAVEFORM_FRACONE (1<::Tau() / ALfloat{WAVEFORM_FRACONE}}; - return std::sin(static_cast(index) * scale)*0.5f + 0.5f; -} - -inline ALfloat Saw(ALsizei index) -{ - return static_cast(index) / ALfloat{WAVEFORM_FRACONE}; -} - -inline ALfloat Triangle(ALsizei index) -{ - return std::fabs(static_cast(index)*(2.0f/WAVEFORM_FRACONE) - 1.0f); -} - -inline ALfloat Half(ALsizei) -{ - return 0.5f; -} - -template -void Oscillate(ALfloat *RESTRICT dst, ALsizei index, const ALsizei step, ALsizei todo) -{ - for(ALsizei i{0};i < todo;i++) - { - index += step; - index &= WAVEFORM_FRACMASK; - dst[i] = func(index); - } -} - -struct FormantFilter -{ - ALfloat f0norm{0.0f}; - ALfloat fGain{1.0f}; - ALfloat s1{0.0f}; - ALfloat s2{0.0f}; - - FormantFilter() = default; - FormantFilter(ALfloat f0norm_, ALfloat gain) : f0norm{f0norm_}, fGain{gain} { } - - inline void process(const ALfloat* samplesIn, ALfloat* samplesOut, const ALsizei numInput) - { - /* A state variable filter from a topology-preserving transform. - * Based on a talk given by Ivan Cohen: https://www.youtube.com/watch?v=esjHXGPyrhg - */ - const ALfloat g = std::tan(al::MathDefs::Pi() * f0norm); - const ALfloat h = 1.0f / (1 + (g / Q_FACTOR) + (g * g)); - - for (ALsizei i{0};i < numInput;i++) - { - const ALfloat H = h * (samplesIn[i] - (1.0f / Q_FACTOR + g) * s1 - s2); - const ALfloat B = g * H + s1; - const ALfloat L = g * B + s2; - - s1 = g * H + B; - s2 = g * B + L; - - // Apply peak and accumulate samples. - samplesOut[i] += B * fGain; - } - } - - inline void clear() - { - s1 = 0.0f; - s2 = 0.0f; - } -}; - - -struct VmorpherState final : public EffectState { - struct { - /* Effect parameters */ - FormantFilter Formants[NUM_FILTERS][NUM_FORMANTS]; - - /* Effect gains for each channel */ - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]{}; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]{}; - } mChans[MAX_AMBI_CHANNELS]; - - void (*mGetSamples)(ALfloat* RESTRICT, ALsizei, const ALsizei, ALsizei) {}; - - ALsizei mIndex{0}; - ALsizei mStep{1}; - - /* Effects buffers */ - ALfloat mSampleBufferA[MAX_UPDATE_SAMPLES]{}; - ALfloat mSampleBufferB[MAX_UPDATE_SAMPLES]{}; - - ALboolean deviceUpdate(const ALCdevice *device) override; - void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; - - static std::array getFiltersByPhoneme(ALenum phoneme, ALfloat frequency, ALfloat pitch); - - DEF_NEWDEL(VmorpherState) -}; - -std::array VmorpherState::getFiltersByPhoneme(ALenum phoneme, ALfloat frequency, ALfloat pitch) -{ - /* Using soprano formant set of values to - * better match mid-range frequency space. - * - * See: https://www.classes.cs.uchicago.edu/archive/1999/spring/CS295/Computing_Resources/Csound/CsManual3.48b1.HTML/Appendices/table3.html - */ - switch(phoneme) - { - case AL_VOCAL_MORPHER_PHONEME_A: - return {{ - {( 800 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ - {(1150 * pitch) / frequency, 0.501187f}, /* std::pow(10.0f, -6 / 20.0f); */ - {(2900 * pitch) / frequency, 0.025118f}, /* std::pow(10.0f, -32 / 20.0f); */ - {(3900 * pitch) / frequency, 0.100000f} /* std::pow(10.0f, -20 / 20.0f); */ - }}; - case AL_VOCAL_MORPHER_PHONEME_E: - return {{ - {( 350 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ - {(2000 * pitch) / frequency, 0.100000f}, /* std::pow(10.0f, -20 / 20.0f); */ - {(2800 * pitch) / frequency, 0.177827f}, /* std::pow(10.0f, -15 / 20.0f); */ - {(3600 * pitch) / frequency, 0.009999f} /* std::pow(10.0f, -40 / 20.0f); */ - }}; - case AL_VOCAL_MORPHER_PHONEME_I: - return {{ - {( 270 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ - {(2140 * pitch) / frequency, 0.251188f}, /* std::pow(10.0f, -12 / 20.0f); */ - {(2950 * pitch) / frequency, 0.050118f}, /* std::pow(10.0f, -26 / 20.0f); */ - {(3900 * pitch) / frequency, 0.050118f} /* std::pow(10.0f, -26 / 20.0f); */ - }}; - case AL_VOCAL_MORPHER_PHONEME_O: - return {{ - {( 450 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ - {( 800 * pitch) / frequency, 0.281838f}, /* std::pow(10.0f, -11 / 20.0f); */ - {(2830 * pitch) / frequency, 0.079432f}, /* std::pow(10.0f, -22 / 20.0f); */ - {(3800 * pitch) / frequency, 0.079432f} /* std::pow(10.0f, -22 / 20.0f); */ - }}; - case AL_VOCAL_MORPHER_PHONEME_U: - return {{ - {( 325 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ - {( 700 * pitch) / frequency, 0.158489f}, /* std::pow(10.0f, -16 / 20.0f); */ - {(2700 * pitch) / frequency, 0.017782f}, /* std::pow(10.0f, -35 / 20.0f); */ - {(3800 * pitch) / frequency, 0.009999f} /* std::pow(10.0f, -40 / 20.0f); */ - }}; - } - return {}; -} - - -ALboolean VmorpherState::deviceUpdate(const ALCdevice* /*device*/) -{ - for(auto &e : mChans) - { - std::for_each(std::begin(e.Formants[VOWEL_A_INDEX]), std::end(e.Formants[VOWEL_A_INDEX]), - std::mem_fn(&FormantFilter::clear)); - std::for_each(std::begin(e.Formants[VOWEL_B_INDEX]), std::end(e.Formants[VOWEL_B_INDEX]), - std::mem_fn(&FormantFilter::clear)); - std::fill(std::begin(e.CurrentGains), std::end(e.CurrentGains), 0.0f); - } - - return AL_TRUE; -} - -void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) -{ - const ALCdevice *device{context->Device}; - const ALfloat frequency{static_cast(device->Frequency)}; - const ALfloat step{props->Vmorpher.Rate / static_cast(device->Frequency)}; - mStep = fastf2i(clampf(step*WAVEFORM_FRACONE, 0.0f, ALfloat{WAVEFORM_FRACONE-1})); - - if(mStep == 0) - mGetSamples = Oscillate; - else if(props->Vmorpher.Waveform == AL_VOCAL_MORPHER_WAVEFORM_SINUSOID) - mGetSamples = Oscillate; - else if(props->Vmorpher.Waveform == AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH) - mGetSamples = Oscillate; - else /*if(props->Vmorpher.Waveform == AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE)*/ - mGetSamples = Oscillate; - - const ALfloat pitchA{fastf2i(std::pow(2.0f, props->Vmorpher.PhonemeACoarseTuning*100.0f / 2400.0f)*FRACTIONONE) * (1.0f/FRACTIONONE)}; - const ALfloat pitchB{fastf2i(std::pow(2.0f, props->Vmorpher.PhonemeBCoarseTuning*100.0f / 2400.0f)*FRACTIONONE) * (1.0f/FRACTIONONE)}; - - auto vowelA = getFiltersByPhoneme(props->Vmorpher.PhonemeA, frequency, pitchA); - auto vowelB = getFiltersByPhoneme(props->Vmorpher.PhonemeB, frequency, pitchB); - - /* Copy the filter coefficients to the input channels. */ - for(size_t i{0u};i < slot->Wet.Buffer.size();++i) - { - std::copy(vowelA.begin(), vowelA.end(), std::begin(mChans[i].Formants[VOWEL_A_INDEX])); - std::copy(vowelB.begin(), vowelB.end(), std::begin(mChans[i].Formants[VOWEL_B_INDEX])); - } - - mOutTarget = target.Main->Buffer; - for(size_t i{0u};i < slot->Wet.Buffer.size();++i) - { - auto coeffs = GetAmbiIdentityRow(i); - ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mChans[i].TargetGains); - } -} - -void VmorpherState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) -{ - /* Following the EFX specification for a conformant implementation which describes - * the effect as a pair of 4-band formant filters blended together using an LFO. - */ - for(ALsizei base{0};base < samplesToDo;) - { - alignas(16) ALfloat lfo[MAX_UPDATE_SAMPLES]; - const ALsizei td = mini(MAX_UPDATE_SAMPLES, samplesToDo-base); - - mGetSamples(lfo, mIndex, mStep, td); - mIndex += (mStep * td) & WAVEFORM_FRACMASK; - mIndex &= WAVEFORM_FRACMASK; - - ASSUME(numInput > 0); - for(ALsizei c{0};c < numInput;c++) - { - for (ALsizei i{0};i < td;i++) - { - mSampleBufferA[i] = 0.0f; - mSampleBufferB[i] = 0.0f; - } - - auto& vowelA = mChans[c].Formants[VOWEL_A_INDEX]; - auto& vowelB = mChans[c].Formants[VOWEL_B_INDEX]; - - /* Process first vowel. */ - vowelA[0].process(&samplesIn[c][base], mSampleBufferA, td); - vowelA[1].process(&samplesIn[c][base], mSampleBufferA, td); - vowelA[2].process(&samplesIn[c][base], mSampleBufferA, td); - vowelA[3].process(&samplesIn[c][base], mSampleBufferA, td); - - /* Process second vowel. */ - vowelB[0].process(&samplesIn[c][base], mSampleBufferB, td); - vowelB[1].process(&samplesIn[c][base], mSampleBufferB, td); - vowelB[2].process(&samplesIn[c][base], mSampleBufferB, td); - vowelB[3].process(&samplesIn[c][base], mSampleBufferB, td); - - alignas(16) ALfloat samplesBlended[MAX_UPDATE_SAMPLES]; - - for (ALsizei i{0};i < td;i++) - samplesBlended[i] = lerp(mSampleBufferA[i], mSampleBufferB[i], lfo[i]); - - /* Now, mix the processed sound data to the output. */ - MixSamples(samplesBlended, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, - samplesToDo-base, base, td); - } - - base += td; - } -} - - -void Vmorpher_setParami(EffectProps* props, ALCcontext *context, ALenum param, ALint val) -{ - switch(param) - { - case AL_VOCAL_MORPHER_WAVEFORM: - if(!(val >= AL_VOCAL_MORPHER_MIN_WAVEFORM && val <= AL_VOCAL_MORPHER_MAX_WAVEFORM)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher waveform out of range"); - props->Vmorpher.Waveform = val; - break; - - case AL_VOCAL_MORPHER_PHONEMEA: - if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEA && val <= AL_VOCAL_MORPHER_MAX_PHONEMEA)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher phoneme-a out of range"); - props->Vmorpher.PhonemeA = val; - break; - - case AL_VOCAL_MORPHER_PHONEMEB: - if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEB && val <= AL_VOCAL_MORPHER_MAX_PHONEMEB)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher phoneme-b out of range"); - props->Vmorpher.PhonemeB = val; - break; - - case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING: - if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher phoneme-a coarse tuning out of range"); - props->Vmorpher.PhonemeACoarseTuning = val; - break; - - case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING: - if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher phoneme-b coarse tuning out of range"); - props->Vmorpher.PhonemeBCoarseTuning = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x", param); - } -} -void Vmorpher_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x", param); } -void Vmorpher_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_VOCAL_MORPHER_RATE: - if(!(val >= AL_VOCAL_MORPHER_MIN_RATE && val <= AL_VOCAL_MORPHER_MAX_RATE)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher rate out of range"); - props->Vmorpher.Rate = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x", param); - } -} -void Vmorpher_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) -{ Vmorpher_setParamf(props, context, param, vals[0]); } - -void Vmorpher_getParami(const EffectProps* props, ALCcontext *context, ALenum param, ALint* val) -{ - switch(param) - { - case AL_VOCAL_MORPHER_PHONEMEA: - *val = props->Vmorpher.PhonemeA; - break; - - case AL_VOCAL_MORPHER_PHONEMEB: - *val = props->Vmorpher.PhonemeB; - break; - - case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING: - *val = props->Vmorpher.PhonemeACoarseTuning; - break; - - case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING: - *val = props->Vmorpher.PhonemeBCoarseTuning; - break; - - case AL_VOCAL_MORPHER_WAVEFORM: - *val = props->Vmorpher.Waveform; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x", param); - } -} -void Vmorpher_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x", param); } -void Vmorpher_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_VOCAL_MORPHER_RATE: - *val = props->Vmorpher.Rate; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x", param); - } -} -void Vmorpher_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) -{ Vmorpher_getParamf(props, context, param, vals); } - -DEFINE_ALEFFECT_VTABLE(Vmorpher); - - -struct VmorpherStateFactory final : public EffectStateFactory { - EffectState *create() override { return new VmorpherState{}; } - EffectProps getDefaultProps() const noexcept override; - const EffectVtable *getEffectVtable() const noexcept override { return &Vmorpher_vtable; } -}; - -EffectProps VmorpherStateFactory::getDefaultProps() const noexcept -{ - EffectProps props{}; - props.Vmorpher.Rate = AL_VOCAL_MORPHER_DEFAULT_RATE; - props.Vmorpher.PhonemeA = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA; - props.Vmorpher.PhonemeB = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB; - props.Vmorpher.PhonemeACoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING; - props.Vmorpher.PhonemeBCoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING; - props.Vmorpher.Waveform = AL_VOCAL_MORPHER_DEFAULT_WAVEFORM; - return props; -} - -} // namespace - -EffectStateFactory *VmorpherStateFactory_getFactory() -{ - static VmorpherStateFactory VmorpherFactory{}; - return &VmorpherFactory; -} diff --git a/Alc/filters/biquad.cpp b/Alc/filters/biquad.cpp deleted file mode 100644 index 6a3cef64..00000000 --- a/Alc/filters/biquad.cpp +++ /dev/null @@ -1,127 +0,0 @@ - -#include "config.h" - -#include "biquad.h" - -#include -#include -#include - -#include "opthelpers.h" - - -template -void BiquadFilterR::setParams(BiquadType type, Real gain, Real f0norm, Real rcpQ) -{ - // Limit gain to -100dB - assert(gain > 0.00001f); - - const Real w0{al::MathDefs::Tau() * f0norm}; - const Real sin_w0{std::sin(w0)}; - const Real cos_w0{std::cos(w0)}; - const Real alpha{sin_w0/2.0f * rcpQ}; - - Real sqrtgain_alpha_2; - Real a[3]{ 1.0f, 0.0f, 0.0f }; - Real b[3]{ 1.0f, 0.0f, 0.0f }; - - /* Calculate filter coefficients depending on filter type */ - switch(type) - { - case BiquadType::HighShelf: - sqrtgain_alpha_2 = 2.0f * std::sqrt(gain) * alpha; - b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); - b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 ); - b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); - a[0] = (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; - a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 ); - a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; - break; - case BiquadType::LowShelf: - sqrtgain_alpha_2 = 2.0f * std::sqrt(gain) * alpha; - b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); - b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 ); - b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); - a[0] = (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; - a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 ); - a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; - break; - case BiquadType::Peaking: - gain = std::sqrt(gain); - b[0] = 1.0f + alpha * gain; - b[1] = -2.0f * cos_w0; - b[2] = 1.0f - alpha * gain; - a[0] = 1.0f + alpha / gain; - a[1] = -2.0f * cos_w0; - a[2] = 1.0f - alpha / gain; - break; - - case BiquadType::LowPass: - b[0] = (1.0f - cos_w0) / 2.0f; - b[1] = 1.0f - cos_w0; - b[2] = (1.0f - cos_w0) / 2.0f; - a[0] = 1.0f + alpha; - a[1] = -2.0f * cos_w0; - a[2] = 1.0f - alpha; - break; - case BiquadType::HighPass: - b[0] = (1.0f + cos_w0) / 2.0f; - b[1] = -(1.0f + cos_w0); - b[2] = (1.0f + cos_w0) / 2.0f; - a[0] = 1.0f + alpha; - a[1] = -2.0f * cos_w0; - a[2] = 1.0f - alpha; - break; - case BiquadType::BandPass: - b[0] = alpha; - b[1] = 0.0f; - b[2] = -alpha; - a[0] = 1.0f + alpha; - a[1] = -2.0f * cos_w0; - a[2] = 1.0f - alpha; - break; - } - - a1 = a[1] / a[0]; - a2 = a[2] / a[0]; - b0 = b[0] / a[0]; - b1 = b[1] / a[0]; - b2 = b[2] / a[0]; -} - -template -void BiquadFilterR::process(Real *dst, const Real *src, int numsamples) -{ - ASSUME(numsamples > 0); - - const Real b0{this->b0}; - const Real b1{this->b1}; - const Real b2{this->b2}; - const Real a1{this->a1}; - const Real a2{this->a2}; - Real z1{this->z1}; - Real z2{this->z2}; - - /* Processing loop is Transposed Direct Form II. This requires less storage - * compared to Direct Form I (only two delay components, instead of a four- - * sample history; the last two inputs and outputs), and works better for - * floating-point which favors summing similarly-sized values while being - * less bothered by overflow. - * - * See: http://www.earlevel.com/main/2003/02/28/biquads/ - */ - auto proc_sample = [b0,b1,b2,a1,a2,&z1,&z2](Real input) noexcept -> Real - { - Real output = input*b0 + z1; - z1 = input*b1 - output*a1 + z2; - z2 = input*b2 - output*a2; - return output; - }; - std::transform(src, src+numsamples, dst, proc_sample); - - this->z1 = z1; - this->z2 = z2; -} - -template class BiquadFilterR; -template class BiquadFilterR; diff --git a/Alc/filters/biquad.h b/Alc/filters/biquad.h deleted file mode 100644 index 893a69a9..00000000 --- a/Alc/filters/biquad.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef FILTERS_BIQUAD_H -#define FILTERS_BIQUAD_H - -#include -#include - -#include "math_defs.h" - - -/* Filters implementation is based on the "Cookbook formulae for audio - * EQ biquad filter coefficients" by Robert Bristow-Johnson - * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt - */ -/* Implementation note: For the shelf filters, the specified gain is for the - * reference frequency, which is the centerpoint of the transition band. This - * better matches EFX filter design. To set the gain for the shelf itself, use - * the square root of the desired linear gain (or halve the dB gain). - */ - -enum class BiquadType { - /** EFX-style low-pass filter, specifying a gain and reference frequency. */ - HighShelf, - /** EFX-style high-pass filter, specifying a gain and reference frequency. */ - LowShelf, - /** Peaking filter, specifying a gain and reference frequency. */ - Peaking, - - /** Low-pass cut-off filter, specifying a cut-off frequency. */ - LowPass, - /** High-pass cut-off filter, specifying a cut-off frequency. */ - HighPass, - /** Band-pass filter, specifying a center frequency. */ - BandPass, -}; - -template -class BiquadFilterR { - /* Last two delayed components for direct form II. */ - Real z1{0.0f}, z2{0.0f}; - /* Transfer function coefficients "b" (numerator) */ - Real b0{1.0f}, b1{0.0f}, b2{0.0f}; - /* Transfer function coefficients "a" (denominator; a0 is pre-applied). */ - Real a1{0.0f}, a2{0.0f}; - -public: - void clear() noexcept { z1 = z2 = 0.0f; } - - /** - * Sets the filter state for the specified filter type and its parameters. - * - * \param type The type of filter to apply. - * \param gain The gain for the reference frequency response. Only used by - * the Shelf and Peaking filter types. - * \param f0norm The reference frequency normal (ref_freq / sample_rate). - * This is the center point for the Shelf, Peaking, and - * BandPass filter types, or the cutoff frequency for the - * LowPass and HighPass filter types. - * \param rcpQ The reciprocal of the Q coefficient for the filter's - * transition band. Can be generated from rcpQFromSlope or - * rcpQFromBandwidth as needed. - */ - void setParams(BiquadType type, Real gain, Real f0norm, Real rcpQ); - - void copyParamsFrom(const BiquadFilterR &other) - { - b0 = other.b0; - b1 = other.b1; - b2 = other.b2; - a1 = other.a1; - a2 = other.a2; - } - - - void process(Real *dst, const Real *src, int numsamples); - - /* Rather hacky. It's just here to support "manual" processing. */ - std::pair getComponents() const noexcept - { return {z1, z2}; } - void setComponents(Real z1_, Real z2_) noexcept - { z1 = z1_; z2 = z2_; } - Real processOne(const Real in, Real &z1_, Real &z2_) const noexcept - { - Real out{in*b0 + z1_}; - z1_ = in*b1 - out*a1 + z2_; - z2_ = in*b2 - out*a2; - return out; - } - - /** - * Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using - * the reference gain and shelf slope parameter. - * \param gain 0 < gain - * \param slope 0 < slope <= 1 - */ - static Real rcpQFromSlope(Real gain, Real slope) - { return std::sqrt((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f); } - - /** - * Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the - * normalized reference frequency and bandwidth. - * \param f0norm 0 < f0norm < 0.5. - * \param bandwidth 0 < bandwidth - */ - static Real rcpQFromBandwidth(Real f0norm, Real bandwidth) - { - const Real w0{al::MathDefs::Tau() * f0norm}; - return 2.0f*std::sinh(std::log(Real{2.0f})/2.0f*bandwidth*w0/std::sin(w0)); - } -}; - -using BiquadFilter = BiquadFilterR; - -#endif /* FILTERS_BIQUAD_H */ diff --git a/Alc/filters/nfc.cpp b/Alc/filters/nfc.cpp deleted file mode 100644 index 1a567f2c..00000000 --- a/Alc/filters/nfc.cpp +++ /dev/null @@ -1,391 +0,0 @@ - -#include "config.h" - -#include "nfc.h" - -#include - -#include "alcmain.h" - - -/* Near-field control filters are the basis for handling the near-field effect. - * The near-field effect is a bass-boost present in the directional components - * of a recorded signal, created as a result of the wavefront curvature (itself - * a function of sound distance). Proper reproduction dictates this be - * compensated for using a bass-cut given the playback speaker distance, to - * avoid excessive bass in the playback. - * - * For real-time rendered audio, emulating the near-field effect based on the - * sound source's distance, and subsequently compensating for it at output - * based on the speaker distances, can create a more realistic perception of - * sound distance beyond a simple 1/r attenuation. - * - * These filters do just that. Each one applies a low-shelf filter, created as - * the combination of a bass-boost for a given sound source distance (near- - * field emulation) along with a bass-cut for a given control/speaker distance - * (near-field compensation). - * - * Note that it is necessary to apply a cut along with the boost, since the - * boost alone is unstable in higher-order ambisonics as it causes an infinite - * DC gain (even first-order ambisonics requires there to be no DC offset for - * the boost to work). Consequently, ambisonics requires a control parameter to - * be used to avoid an unstable boost-only filter. NFC-HOA defines this control - * as a reference delay, calculated with: - * - * reference_delay = control_distance / speed_of_sound - * - * This means w0 (for input) or w1 (for output) should be set to: - * - * wN = 1 / (reference_delay * sample_rate) - * - * when dealing with NFC-HOA content. For FOA input content, which does not - * specify a reference_delay variable, w0 should be set to 0 to apply only - * near-field compensation for output. It's important that w1 be a finite, - * positive, non-0 value or else the bass-boost will become unstable again. - * Also, w0 should not be too large compared to w1, to avoid excessively loud - * low frequencies. - */ - -namespace { - -constexpr float B[5][4] = { - { 0.0f }, - { 1.0f }, - { 3.0f, 3.0f }, - { 3.6778f, 6.4595f, 2.3222f }, - { 4.2076f, 11.4877f, 5.7924f, 9.1401f } -}; - -NfcFilter1 NfcFilterCreate1(const float w0, const float w1) noexcept -{ - NfcFilter1 nfc{}; - float b_00, g_0; - float r; - - nfc.base_gain = 1.0f; - nfc.gain = 1.0f; - - /* Calculate bass-boost coefficients. */ - r = 0.5f * w0; - b_00 = B[1][0] * r; - g_0 = 1.0f + b_00; - - nfc.gain *= g_0; - nfc.b1 = 2.0f * b_00 / g_0; - - /* Calculate bass-cut coefficients. */ - r = 0.5f * w1; - b_00 = B[1][0] * r; - g_0 = 1.0f + b_00; - - nfc.base_gain /= g_0; - nfc.gain /= g_0; - nfc.a1 = 2.0f * b_00 / g_0; - - return nfc; -} - -void NfcFilterAdjust1(NfcFilter1 *nfc, const float w0) noexcept -{ - const float r{0.5f * w0}; - const float b_00{B[1][0] * r}; - const float g_0{1.0f + b_00}; - - nfc->gain = nfc->base_gain * g_0; - nfc->b1 = 2.0f * b_00 / g_0; -} - - -NfcFilter2 NfcFilterCreate2(const float w0, const float w1) noexcept -{ - NfcFilter2 nfc{}; - float b_10, b_11, g_1; - float r; - - nfc.base_gain = 1.0f; - nfc.gain = 1.0f; - - /* Calculate bass-boost coefficients. */ - r = 0.5f * w0; - b_10 = B[2][0] * r; - b_11 = B[2][1] * r * r; - g_1 = 1.0f + b_10 + b_11; - - nfc.gain *= g_1; - nfc.b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; - nfc.b2 = 4.0f * b_11 / g_1; - - /* Calculate bass-cut coefficients. */ - r = 0.5f * w1; - b_10 = B[2][0] * r; - b_11 = B[2][1] * r * r; - g_1 = 1.0f + b_10 + b_11; - - nfc.base_gain /= g_1; - nfc.gain /= g_1; - nfc.a1 = (2.0f*b_10 + 4.0f*b_11) / g_1; - nfc.a2 = 4.0f * b_11 / g_1; - - return nfc; -} - -void NfcFilterAdjust2(NfcFilter2 *nfc, const float w0) noexcept -{ - const float r{0.5f * w0}; - const float b_10{B[2][0] * r}; - const float b_11{B[2][1] * r * r}; - const float g_1{1.0f + b_10 + b_11}; - - nfc->gain = nfc->base_gain * g_1; - nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; - nfc->b2 = 4.0f * b_11 / g_1; -} - - -NfcFilter3 NfcFilterCreate3(const float w0, const float w1) noexcept -{ - NfcFilter3 nfc{}; - float b_10, b_11, g_1; - float b_00, g_0; - float r; - - nfc.base_gain = 1.0f; - nfc.gain = 1.0f; - - /* Calculate bass-boost coefficients. */ - r = 0.5f * w0; - b_10 = B[3][0] * r; - b_11 = B[3][1] * r * r; - b_00 = B[3][2] * r; - g_1 = 1.0f + b_10 + b_11; - g_0 = 1.0f + b_00; - - nfc.gain *= g_1 * g_0; - nfc.b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; - nfc.b2 = 4.0f * b_11 / g_1; - nfc.b3 = 2.0f * b_00 / g_0; - - /* Calculate bass-cut coefficients. */ - r = 0.5f * w1; - b_10 = B[3][0] * r; - b_11 = B[3][1] * r * r; - b_00 = B[3][2] * r; - g_1 = 1.0f + b_10 + b_11; - g_0 = 1.0f + b_00; - - nfc.base_gain /= g_1 * g_0; - nfc.gain /= g_1 * g_0; - nfc.a1 = (2.0f*b_10 + 4.0f*b_11) / g_1; - nfc.a2 = 4.0f * b_11 / g_1; - nfc.a3 = 2.0f * b_00 / g_0; - - return nfc; -} - -void NfcFilterAdjust3(NfcFilter3 *nfc, const float w0) noexcept -{ - const float r{0.5f * w0}; - const float b_10{B[3][0] * r}; - const float b_11{B[3][1] * r * r}; - const float b_00{B[3][2] * r}; - const float g_1{1.0f + b_10 + b_11}; - const float g_0{1.0f + b_00}; - - nfc->gain = nfc->base_gain * g_1 * g_0; - nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; - nfc->b2 = 4.0f * b_11 / g_1; - nfc->b3 = 2.0f * b_00 / g_0; -} - - -NfcFilter4 NfcFilterCreate4(const float w0, const float w1) noexcept -{ - NfcFilter4 nfc{}; - float b_10, b_11, g_1; - float b_00, b_01, g_0; - float r; - - nfc.base_gain = 1.0f; - nfc.gain = 1.0f; - - /* Calculate bass-boost coefficients. */ - r = 0.5f * w0; - b_10 = B[4][0] * r; - b_11 = B[4][1] * r * r; - b_00 = B[4][2] * r; - b_01 = B[4][3] * r * r; - g_1 = 1.0f + b_10 + b_11; - g_0 = 1.0f + b_00 + b_01; - - nfc.gain *= g_1 * g_0; - nfc.b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; - nfc.b2 = 4.0f * b_11 / g_1; - nfc.b3 = (2.0f*b_00 + 4.0f*b_01) / g_0; - nfc.b4 = 4.0f * b_01 / g_0; - - /* Calculate bass-cut coefficients. */ - r = 0.5f * w1; - b_10 = B[4][0] * r; - b_11 = B[4][1] * r * r; - b_00 = B[4][2] * r; - b_01 = B[4][3] * r * r; - g_1 = 1.0f + b_10 + b_11; - g_0 = 1.0f + b_00 + b_01; - - nfc.base_gain /= g_1 * g_0; - nfc.gain /= g_1 * g_0; - nfc.a1 = (2.0f*b_10 + 4.0f*b_11) / g_1; - nfc.a2 = 4.0f * b_11 / g_1; - nfc.a3 = (2.0f*b_00 + 4.0f*b_01) / g_0; - nfc.a4 = 4.0f * b_01 / g_0; - - return nfc; -} - -void NfcFilterAdjust4(NfcFilter4 *nfc, const float w0) noexcept -{ - const float r{0.5f * w0}; - const float b_10{B[4][0] * r}; - const float b_11{B[4][1] * r * r}; - const float b_00{B[4][2] * r}; - const float b_01{B[4][3] * r * r}; - const float g_1{1.0f + b_10 + b_11}; - const float g_0{1.0f + b_00 + b_01}; - - nfc->gain = nfc->base_gain * g_1 * g_0; - nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; - nfc->b2 = 4.0f * b_11 / g_1; - nfc->b3 = (2.0f*b_00 + 4.0f*b_01) / g_0; - nfc->b4 = 4.0f * b_01 / g_0; -} - -} // namespace - -void NfcFilter::init(const float w1) noexcept -{ - first = NfcFilterCreate1(0.0f, w1); - second = NfcFilterCreate2(0.0f, w1); - third = NfcFilterCreate3(0.0f, w1); - fourth = NfcFilterCreate4(0.0f, w1); -} - -void NfcFilter::adjust(const float w0) noexcept -{ - NfcFilterAdjust1(&first, w0); - NfcFilterAdjust2(&second, w0); - NfcFilterAdjust3(&third, w0); - NfcFilterAdjust4(&fourth, w0); -} - - -void NfcFilter::process1(float *RESTRICT dst, const float *RESTRICT src, const int count) -{ - ASSUME(count > 0); - - const float gain{first.gain}; - const float b1{first.b1}; - const float a1{first.a1}; - float z1{first.z[0]}; - auto proc_sample = [gain,b1,a1,&z1](const float in) noexcept -> float - { - const float y{in*gain - a1*z1}; - const float out{y + b1*z1}; - z1 += y; - return out; - }; - std::transform(src, src+count, dst, proc_sample); - first.z[0] = z1; -} - -void NfcFilter::process2(float *RESTRICT dst, const float *RESTRICT src, const int count) -{ - ASSUME(count > 0); - - const float gain{second.gain}; - const float b1{second.b1}; - const float b2{second.b2}; - const float a1{second.a1}; - const float a2{second.a2}; - float z1{second.z[0]}; - float z2{second.z[1]}; - auto proc_sample = [gain,b1,b2,a1,a2,&z1,&z2](const float in) noexcept -> float - { - const float y{in*gain - a1*z1 - a2*z2}; - const float out{y + b1*z1 + b2*z2}; - z2 += z1; - z1 += y; - return out; - }; - std::transform(src, src+count, dst, proc_sample); - second.z[0] = z1; - second.z[1] = z2; -} - -void NfcFilter::process3(float *RESTRICT dst, const float *RESTRICT src, const int count) -{ - ASSUME(count > 0); - - const float gain{third.gain}; - const float b1{third.b1}; - const float b2{third.b2}; - const float b3{third.b3}; - const float a1{third.a1}; - const float a2{third.a2}; - const float a3{third.a3}; - float z1{third.z[0]}; - float z2{third.z[1]}; - float z3{third.z[2]}; - auto proc_sample = [gain,b1,b2,b3,a1,a2,a3,&z1,&z2,&z3](const float in) noexcept -> float - { - float y{in*gain - a1*z1 - a2*z2}; - float out{y + b1*z1 + b2*z2}; - z2 += z1; - z1 += y; - - y = out - a3*z3; - out = y + b3*z3; - z3 += y; - return out; - }; - std::transform(src, src+count, dst, proc_sample); - third.z[0] = z1; - third.z[1] = z2; - third.z[2] = z3; -} - -void NfcFilter::process4(float *RESTRICT dst, const float *RESTRICT src, const int count) -{ - ASSUME(count > 0); - - const float gain{fourth.gain}; - const float b1{fourth.b1}; - const float b2{fourth.b2}; - const float b3{fourth.b3}; - const float b4{fourth.b4}; - const float a1{fourth.a1}; - const float a2{fourth.a2}; - const float a3{fourth.a3}; - const float a4{fourth.a4}; - float z1{fourth.z[0]}; - float z2{fourth.z[1]}; - float z3{fourth.z[2]}; - float z4{fourth.z[3]}; - auto proc_sample = [gain,b1,b2,b3,b4,a1,a2,a3,a4,&z1,&z2,&z3,&z4](const float in) noexcept -> float - { - float y{in*gain - a1*z1 - a2*z2}; - float out{y + b1*z1 + b2*z2}; - z2 += z1; - z1 += y; - - y = out - a3*z3 - a4*z4; - out = y + b3*z3 + b4*z4; - z4 += z3; - z3 += y; - return out; - }; - std::transform(src, src+count, dst, proc_sample); - fourth.z[0] = z1; - fourth.z[1] = z2; - fourth.z[2] = z3; - fourth.z[3] = z4; -} diff --git a/Alc/filters/nfc.h b/Alc/filters/nfc.h deleted file mode 100644 index b656850a..00000000 --- a/Alc/filters/nfc.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef FILTER_NFC_H -#define FILTER_NFC_H - -struct NfcFilter1 { - float base_gain, gain; - float b1, a1; - float z[1]; -}; -struct NfcFilter2 { - float base_gain, gain; - float b1, b2, a1, a2; - float z[2]; -}; -struct NfcFilter3 { - float base_gain, gain; - float b1, b2, b3, a1, a2, a3; - float z[3]; -}; -struct NfcFilter4 { - float base_gain, gain; - float b1, b2, b3, b4, a1, a2, a3, a4; - float z[4]; -}; - -class NfcFilter { - NfcFilter1 first; - NfcFilter2 second; - NfcFilter3 third; - NfcFilter4 fourth; - -public: - /* NOTE: - * w0 = speed_of_sound / (source_distance * sample_rate); - * w1 = speed_of_sound / (control_distance * sample_rate); - * - * Generally speaking, the control distance should be approximately the - * average speaker distance, or based on the reference delay if outputing - * NFC-HOA. It must not be negative, 0, or infinite. The source distance - * should not be too small relative to the control distance. - */ - - void init(const float w1) noexcept; - void adjust(const float w0) noexcept; - - /* Near-field control filter for first-order ambisonic channels (1-3). */ - void process1(float *RESTRICT dst, const float *RESTRICT src, const int count); - - /* Near-field control filter for second-order ambisonic channels (4-8). */ - void process2(float *RESTRICT dst, const float *RESTRICT src, const int count); - - /* Near-field control filter for third-order ambisonic channels (9-15). */ - void process3(float *RESTRICT dst, const float *RESTRICT src, const int count); - - /* Near-field control filter for fourth-order ambisonic channels (16-24). */ - void process4(float *RESTRICT dst, const float *RESTRICT src, const int count); -}; - -#endif /* FILTER_NFC_H */ diff --git a/Alc/filters/splitter.cpp b/Alc/filters/splitter.cpp deleted file mode 100644 index 09e7bfe8..00000000 --- a/Alc/filters/splitter.cpp +++ /dev/null @@ -1,115 +0,0 @@ - -#include "config.h" - -#include "splitter.h" - -#include -#include -#include - -#include "math_defs.h" - -template -void BandSplitterR::init(Real f0norm) -{ - const Real w{f0norm * al::MathDefs::Tau()}; - const Real cw{std::cos(w)}; - if(cw > std::numeric_limits::epsilon()) - coeff = (std::sin(w) - 1.0f) / cw; - else - coeff = cw * -0.5f; - - lp_z1 = 0.0f; - lp_z2 = 0.0f; - ap_z1 = 0.0f; -} - -template -void BandSplitterR::process(Real *hpout, Real *lpout, const Real *input, const int count) -{ - ASSUME(count > 0); - - const Real ap_coeff{this->coeff}; - const Real lp_coeff{this->coeff*0.5f + 0.5f}; - Real lp_z1{this->lp_z1}; - Real lp_z2{this->lp_z2}; - Real ap_z1{this->ap_z1}; - auto proc_sample = [ap_coeff,lp_coeff,&lp_z1,&lp_z2,&ap_z1,&lpout](const Real in) noexcept -> Real - { - /* Low-pass sample processing. */ - Real d{(in - lp_z1) * lp_coeff}; - Real lp_y{lp_z1 + d}; - lp_z1 = lp_y + d; - - d = (lp_y - lp_z2) * lp_coeff; - lp_y = lp_z2 + d; - lp_z2 = lp_y + d; - - *(lpout++) = lp_y; - - /* All-pass sample processing. */ - Real ap_y{in*ap_coeff + ap_z1}; - ap_z1 = in - ap_y*ap_coeff; - - /* High-pass generated from removing low-passed output. */ - return ap_y - lp_y; - }; - std::transform(input, input+count, hpout, proc_sample); - this->lp_z1 = lp_z1; - this->lp_z2 = lp_z2; - this->ap_z1 = ap_z1; -} - -template -void BandSplitterR::applyHfScale(Real *samples, const Real hfscale, const int count) -{ - ASSUME(count > 0); - - const Real ap_coeff{this->coeff}; - const Real lp_coeff{this->coeff*0.5f + 0.5f}; - Real lp_z1{this->lp_z1}; - Real lp_z2{this->lp_z2}; - Real ap_z1{this->ap_z1}; - auto proc_sample = [hfscale,ap_coeff,lp_coeff,&lp_z1,&lp_z2,&ap_z1](const Real in) noexcept -> Real - { - /* Low-pass sample processing. */ - Real d{(in - lp_z1) * lp_coeff}; - Real lp_y{lp_z1 + d}; - lp_z1 = lp_y + d; - - d = (lp_y - lp_z2) * lp_coeff; - lp_y = lp_z2 + d; - lp_z2 = lp_y + d; - - /* All-pass sample processing. */ - Real ap_y{in*ap_coeff + ap_z1}; - ap_z1 = in - ap_y*ap_coeff; - - /* High-pass generated from removing low-passed output. */ - return (ap_y-lp_y)*hfscale + lp_y; - }; - std::transform(samples, samples+count, samples, proc_sample); - this->lp_z1 = lp_z1; - this->lp_z2 = lp_z2; - this->ap_z1 = ap_z1; -} - -template -void BandSplitterR::applyAllpass(Real *samples, const int count) const -{ - ASSUME(count > 0); - - const Real coeff{this->coeff}; - Real z1{0.0f}; - auto proc_sample = [coeff,&z1](const Real in) noexcept -> Real - { - const Real out{in*coeff + z1}; - z1 = in - out*coeff; - return out; - }; - std::transform(samples, samples+count, samples, proc_sample); -} - - -template class BandSplitterR; -template class BandSplitterR; diff --git a/Alc/filters/splitter.h b/Alc/filters/splitter.h deleted file mode 100644 index 927c4d17..00000000 --- a/Alc/filters/splitter.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef FILTER_SPLITTER_H -#define FILTER_SPLITTER_H - -#include "alcmain.h" -#include "almalloc.h" - - -/* Band splitter. Splits a signal into two phase-matching frequency bands. */ -template -class BandSplitterR { - Real coeff{0.0f}; - Real lp_z1{0.0f}; - Real lp_z2{0.0f}; - Real ap_z1{0.0f}; - -public: - BandSplitterR() = default; - BandSplitterR(const BandSplitterR&) = default; - BandSplitterR(Real f0norm) { init(f0norm); } - - void init(Real f0norm); - void clear() noexcept { lp_z1 = lp_z2 = ap_z1 = 0.0f; } - void process(Real *hpout, Real *lpout, const Real *input, const int count); - - void applyHfScale(Real *samples, const Real hfscale, const int count); - - /* The all-pass portion of the band splitter. Applies the same phase shift - * without splitting the signal. Note that each use of this method is - * indepedent, it does not track history between calls. - */ - void applyAllpass(Real *samples, const int count) const; -}; -using BandSplitter = BandSplitterR; - - -struct FrontStablizer { - static constexpr size_t DelayLength{256u}; - - alignas(16) float DelayBuf[MAX_OUTPUT_CHANNELS][DelayLength]; - - BandSplitter LFilter, RFilter; - alignas(16) float LSplit[2][BUFFERSIZE]; - alignas(16) float RSplit[2][BUFFERSIZE]; - - alignas(16) float TempBuf[BUFFERSIZE + DelayLength]; - - DEF_NEWDEL(FrontStablizer) -}; - -#endif /* FILTER_SPLITTER_H */ diff --git a/Alc/fpu_modes.h b/Alc/fpu_modes.h deleted file mode 100644 index 5465e9cf..00000000 --- a/Alc/fpu_modes.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef FPU_MODES_H -#define FPU_MODES_H - -class FPUCtl { -#if defined(HAVE_SSE_INTRINSICS) || (defined(__GNUC__) && defined(HAVE_SSE)) - unsigned int sse_state{}; -#endif - bool in_mode{}; - -public: - FPUCtl(); - /* HACK: 32-bit targets for GCC seem to have a problem here with certain - * noexcept methods (which destructors are) causing an internal compiler - * error. No idea why it's these methods specifically, but this is needed - * to get it to compile. - */ - ~FPUCtl() noexcept(false) { leave(); } - - FPUCtl(const FPUCtl&) = delete; - FPUCtl& operator=(const FPUCtl&) = delete; - - void leave(); -}; - -#endif /* FPU_MODES_H */ diff --git a/Alc/helpers.cpp b/Alc/helpers.cpp deleted file mode 100644 index e86af6ce..00000000 --- a/Alc/helpers.cpp +++ /dev/null @@ -1,851 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2011 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * 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 -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_DIRENT_H -#include -#endif -#ifdef HAVE_PROC_PIDPATH -#include -#endif - -#ifdef __FreeBSD__ -#include -#include -#endif - -#ifndef AL_NO_UID_DEFS -#if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H) -#define INITGUID -#include -#ifdef HAVE_GUIDDEF_H -#include -#else -#include -#endif - -DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71); -DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71); - -DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf,0x08, 0x00,0xa0,0xc9,0x25,0xcd,0x16); - -DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e,0x3d, 0xc4,0x57,0x92,0x91,0x69,0x2e); -DEFINE_GUID(IID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6); -DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2); -DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2); -DEFINE_GUID(IID_IAudioCaptureClient, 0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x18,0x5c,0x39,0x5c,0xd3,0x17); - -#ifdef HAVE_WASAPI -#include -#include -#include -DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); -DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); -DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23,0xe0, 0xc0,0xff,0xee,0x7f,0x0e, 4 ); -#endif -#endif -#endif /* AL_NO_UID_DEFS */ - -#ifdef HAVE_DLFCN_H -#include -#endif -#ifdef HAVE_INTRIN_H -#include -#endif -#ifdef HAVE_CPUID_H -#include -#endif -#ifdef HAVE_SSE_INTRINSICS -#include -#endif -#ifdef HAVE_SYS_SYSCONF_H -#include -#endif - -#ifndef _WIN32 -#include -#elif defined(_WIN32_IE) -#include -#endif - -#include "alcmain.h" -#include "almalloc.h" -#include "compat.h" -#include "cpu_caps.h" -#include "fpu_modes.h" -#include "logging.h" - - -#if defined(HAVE_GCC_GET_CPUID) && (defined(__i386__) || defined(__x86_64__) || \ - defined(_M_IX86) || defined(_M_X64)) -using reg_type = unsigned int; -static inline void get_cpuid(int f, reg_type *regs) -{ __get_cpuid(f, ®s[0], ®s[1], ®s[2], ®s[3]); } -#define CAN_GET_CPUID -#elif defined(HAVE_CPUID_INTRINSIC) && (defined(__i386__) || defined(__x86_64__) || \ - defined(_M_IX86) || defined(_M_X64)) -using reg_type = int; -static inline void get_cpuid(int f, reg_type *regs) -{ (__cpuid)(regs, f); } -#define CAN_GET_CPUID -#endif - -int CPUCapFlags = 0; - -void FillCPUCaps(int capfilter) -{ - int caps = 0; - -/* FIXME: We really should get this for all available CPUs in case different - * CPUs have different caps (is that possible on one machine?). */ -#ifdef CAN_GET_CPUID - union { - reg_type regs[4]; - char str[sizeof(reg_type[4])]; - } cpuinf[3] = {{ { 0, 0, 0, 0 } }}; - - get_cpuid(0, cpuinf[0].regs); - if(cpuinf[0].regs[0] == 0) - ERR("Failed to get CPUID\n"); - else - { - unsigned int maxfunc = cpuinf[0].regs[0]; - unsigned int maxextfunc; - - get_cpuid(0x80000000, cpuinf[0].regs); - maxextfunc = cpuinf[0].regs[0]; - - TRACE("Detected max CPUID function: 0x%x (ext. 0x%x)\n", maxfunc, maxextfunc); - - TRACE("Vendor ID: \"%.4s%.4s%.4s\"\n", cpuinf[0].str+4, cpuinf[0].str+12, cpuinf[0].str+8); - if(maxextfunc >= 0x80000004) - { - get_cpuid(0x80000002, cpuinf[0].regs); - get_cpuid(0x80000003, cpuinf[1].regs); - get_cpuid(0x80000004, cpuinf[2].regs); - TRACE("Name: \"%.16s%.16s%.16s\"\n", cpuinf[0].str, cpuinf[1].str, cpuinf[2].str); - } - - if(maxfunc >= 1) - { - get_cpuid(1, cpuinf[0].regs); - if((cpuinf[0].regs[3]&(1<<25))) - caps |= CPU_CAP_SSE; - if((caps&CPU_CAP_SSE) && (cpuinf[0].regs[3]&(1<<26))) - caps |= CPU_CAP_SSE2; - if((caps&CPU_CAP_SSE2) && (cpuinf[0].regs[2]&(1<<0))) - caps |= CPU_CAP_SSE3; - if((caps&CPU_CAP_SSE3) && (cpuinf[0].regs[2]&(1<<19))) - caps |= CPU_CAP_SSE4_1; - } - } -#else - /* Assume support for whatever's supported if we can't check for it */ -#if defined(HAVE_SSE4_1) -#warning "Assuming SSE 4.1 run-time support!" - caps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1; -#elif defined(HAVE_SSE3) -#warning "Assuming SSE 3 run-time support!" - caps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3; -#elif defined(HAVE_SSE2) -#warning "Assuming SSE 2 run-time support!" - caps |= CPU_CAP_SSE | CPU_CAP_SSE2; -#elif defined(HAVE_SSE) -#warning "Assuming SSE run-time support!" - caps |= CPU_CAP_SSE; -#endif -#endif -#ifdef HAVE_NEON - al::ifstream file{"/proc/cpuinfo"}; - if(!file.is_open()) - ERR("Failed to open /proc/cpuinfo, cannot check for NEON support\n"); - else - { - std::string features; - - auto getline = [](std::istream &f, std::string &output) -> bool - { - while(f.good() && f.peek() == '\n') - f.ignore(); - return std::getline(f, output) && !output.empty(); - - }; - while(getline(file, features)) - { - if(features.compare(0, 10, "Features\t:", 10) == 0) - break; - } - file.close(); - - size_t extpos{9}; - while((extpos=features.find("neon", extpos+1)) != std::string::npos) - { - if((extpos == 0 || std::isspace(features[extpos-1])) && - (extpos+4 == features.length() || std::isspace(features[extpos+4]))) - { - caps |= CPU_CAP_NEON; - break; - } - } - } -#endif - - TRACE("Extensions:%s%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_SSE3) ? ((caps&CPU_CAP_SSE3) ? " +SSE3" : " -SSE3") : ""), - ((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; -} - - -FPUCtl::FPUCtl() -{ -#if defined(HAVE_SSE_INTRINSICS) - this->sse_state = _mm_getcsr(); - unsigned int sseState = this->sse_state; - sseState |= 0x8000; /* set flush-to-zero */ - sseState |= 0x0040; /* set denormals-are-zero */ - _mm_setcsr(sseState); - -#elif defined(__GNUC__) && defined(HAVE_SSE) - - if((CPUCapFlags&CPU_CAP_SSE)) - { - __asm__ __volatile__("stmxcsr %0" : "=m" (*&this->sse_state)); - unsigned int sseState = this->sse_state; - sseState |= 0x8000; /* set flush-to-zero */ - if((CPUCapFlags&CPU_CAP_SSE2)) - sseState |= 0x0040; /* set denormals-are-zero */ - __asm__ __volatile__("ldmxcsr %0" : : "m" (*&sseState)); - } -#endif - - this->in_mode = true; -} - -void FPUCtl::leave() -{ - if(!this->in_mode) return; - -#if defined(HAVE_SSE_INTRINSICS) - _mm_setcsr(this->sse_state); - -#elif defined(__GNUC__) && defined(HAVE_SSE) - - if((CPUCapFlags&CPU_CAP_SSE)) - __asm__ __volatile__("ldmxcsr %0" : : "m" (*&this->sse_state)); -#endif - this->in_mode = false; -} - - -#ifdef _WIN32 - -namespace al { - -auto filebuf::underflow() -> int_type -{ - if(mFile != INVALID_HANDLE_VALUE && gptr() == egptr()) - { - // Read in the next chunk of data, and set the pointers on success - DWORD got{}; - if(ReadFile(mFile, mBuffer.data(), (DWORD)mBuffer.size(), &got, nullptr)) - setg(mBuffer.data(), mBuffer.data(), mBuffer.data()+got); - } - if(gptr() == egptr()) - return traits_type::eof(); - return traits_type::to_int_type(*gptr()); -} - -auto filebuf::seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) -> pos_type -{ - if(mFile == INVALID_HANDLE_VALUE || (mode&std::ios_base::out) || !(mode&std::ios_base::in)) - return traits_type::eof(); - - LARGE_INTEGER fpos{}; - switch(whence) - { - case std::ios_base::beg: - fpos.QuadPart = offset; - if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_BEGIN)) - return traits_type::eof(); - break; - - case std::ios_base::cur: - // If the offset remains in the current buffer range, just - // update the pointer. - if((offset >= 0 && offset < off_type(egptr()-gptr())) || - (offset < 0 && -offset <= off_type(gptr()-eback()))) - { - // Get the current file offset to report the correct read - // offset. - fpos.QuadPart = 0; - if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_CURRENT)) - return traits_type::eof(); - setg(eback(), gptr()+offset, egptr()); - return fpos.QuadPart - off_type(egptr()-gptr()); - } - // Need to offset for the file offset being at egptr() while - // the requested offset is relative to gptr(). - offset -= off_type(egptr()-gptr()); - fpos.QuadPart = offset; - if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_CURRENT)) - return traits_type::eof(); - break; - - case std::ios_base::end: - fpos.QuadPart = offset; - if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_END)) - return traits_type::eof(); - break; - - default: - return traits_type::eof(); - } - setg(nullptr, nullptr, nullptr); - return fpos.QuadPart; -} - -auto filebuf::seekpos(pos_type pos, std::ios_base::openmode mode) -> pos_type -{ - // Simplified version of seekoff - if(mFile == INVALID_HANDLE_VALUE || (mode&std::ios_base::out) || !(mode&std::ios_base::in)) - return traits_type::eof(); - - LARGE_INTEGER fpos{}; - fpos.QuadPart = pos; - if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_BEGIN)) - return traits_type::eof(); - - setg(nullptr, nullptr, nullptr); - return fpos.QuadPart; -} - -filebuf::~filebuf() -{ - if(mFile != INVALID_HANDLE_VALUE) - CloseHandle(mFile); - mFile = INVALID_HANDLE_VALUE; -} - -bool filebuf::open(const wchar_t *filename, std::ios_base::openmode mode) -{ - if((mode&std::ios_base::out) || !(mode&std::ios_base::in)) - return false; - HANDLE f{CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, nullptr)}; - if(f == INVALID_HANDLE_VALUE) return false; - - if(mFile != INVALID_HANDLE_VALUE) - CloseHandle(mFile); - mFile = f; - - setg(nullptr, nullptr, nullptr); - return true; -} -bool filebuf::open(const char *filename, std::ios_base::openmode mode) -{ - std::wstring wname{utf8_to_wstr(filename)}; - return open(wname.c_str(), mode); -} - - -ifstream::ifstream(const wchar_t *filename, std::ios_base::openmode mode) - : std::istream{nullptr} -{ - init(&mStreamBuf); - - // Set the failbit if the file failed to open. - if((mode&std::ios_base::out) || !mStreamBuf.open(filename, mode|std::ios_base::in)) - clear(failbit); -} - -ifstream::ifstream(const char *filename, std::ios_base::openmode mode) - : std::istream{nullptr} -{ - init(&mStreamBuf); - - // Set the failbit if the file failed to open. - if((mode&std::ios_base::out) || !mStreamBuf.open(filename, mode|std::ios_base::in)) - clear(failbit); -} - -/* This is only here to ensure the compiler doesn't define an implicit - * destructor, which it tries to automatically inline and subsequently complain - * it can't inline without excessive code growth. - */ -ifstream::~ifstream() { } - -} // namespace al - -const PathNamePair &GetProcBinary() -{ - static PathNamePair ret; - if(!ret.fname.empty() || !ret.path.empty()) - return ret; - - al::vector fullpath(256); - DWORD len; - while((len=GetModuleFileNameW(nullptr, fullpath.data(), static_cast(fullpath.size()))) == fullpath.size()) - fullpath.resize(fullpath.size() << 1); - if(len == 0) - { - ERR("Failed to get process name: error %lu\n", GetLastError()); - return ret; - } - - fullpath.resize(len); - if(fullpath.back() != 0) - fullpath.push_back(0); - - auto sep = std::find(fullpath.rbegin()+1, fullpath.rend(), '\\'); - sep = std::find(fullpath.rbegin()+1, sep, '/'); - if(sep != fullpath.rend()) - { - *sep = 0; - ret.fname = wstr_to_utf8(&*sep + 1); - ret.path = wstr_to_utf8(fullpath.data()); - } - else - ret.fname = wstr_to_utf8(fullpath.data()); - - TRACE("Got binary: %s, %s\n", ret.path.c_str(), ret.fname.c_str()); - return ret; -} - - -void *LoadLib(const char *name) -{ - std::wstring wname{utf8_to_wstr(name)}; - return LoadLibraryW(wname.c_str()); -} -void CloseLib(void *handle) -{ FreeLibrary(static_cast(handle)); } -void *GetSymbol(void *handle, const char *name) -{ - void *ret{reinterpret_cast(GetProcAddress(static_cast(handle), name))}; - if(!ret) ERR("Failed to load %s\n", name); - return ret; -} - - -void al_print(FILE *logfile, const char *fmt, ...) -{ - al::vector dynmsg; - char stcmsg[256]; - char *str{stcmsg}; - - va_list args, args2; - va_start(args, fmt); - va_copy(args2, args); - int msglen{std::vsnprintf(str, sizeof(stcmsg), fmt, args)}; - if(UNLIKELY(msglen >= 0 && static_cast(msglen) >= sizeof(stcmsg))) - { - dynmsg.resize(static_cast(msglen) + 1u); - str = dynmsg.data(); - msglen = std::vsnprintf(str, dynmsg.size(), fmt, args2); - } - va_end(args2); - va_end(args); - - std::wstring wstr{utf8_to_wstr(str)}; - fprintf(logfile, "%ls", wstr.c_str()); - fflush(logfile); -} - - -static inline int is_slash(int c) -{ return (c == '\\' || c == '/'); } - -static void DirectorySearch(const char *path, const char *ext, al::vector *const results) -{ - std::string pathstr{path}; - pathstr += "\\*"; - pathstr += ext; - TRACE("Searching %s\n", pathstr.c_str()); - - std::wstring wpath{utf8_to_wstr(pathstr.c_str())}; - WIN32_FIND_DATAW fdata; - HANDLE hdl{FindFirstFileW(wpath.c_str(), &fdata)}; - if(hdl != INVALID_HANDLE_VALUE) - { - size_t base = results->size(); - do { - results->emplace_back(); - std::string &str = results->back(); - str = path; - str += '\\'; - str += wstr_to_utf8(fdata.cFileName); - TRACE("Got result %s\n", str.c_str()); - } while(FindNextFileW(hdl, &fdata)); - FindClose(hdl); - - std::sort(results->begin()+base, results->end()); - } -} - -al::vector SearchDataFiles(const char *ext, const char *subdir) -{ - static std::mutex search_lock; - std::lock_guard _{search_lock}; - - /* If the path is absolute, use it directly. */ - al::vector results; - if(isalpha(subdir[0]) && subdir[1] == ':' && is_slash(subdir[2])) - { - std::string path{subdir}; - std::replace(path.begin(), path.end(), '/', '\\'); - DirectorySearch(path.c_str(), ext, &results); - return results; - } - if(subdir[0] == '\\' && subdir[1] == '\\' && subdir[2] == '?' && subdir[3] == '\\') - { - DirectorySearch(subdir, ext, &results); - return results; - } - - std::string path; - - /* Search the app-local directory. */ - WCHAR *cwdbuf{_wgetenv(L"ALSOFT_LOCAL_PATH")}; - if(cwdbuf && *cwdbuf != '\0') - { - path = wstr_to_utf8(cwdbuf); - if(is_slash(path.back())) - path.pop_back(); - } - else if(!(cwdbuf=_wgetcwd(nullptr, 0))) - path = "."; - else - { - path = wstr_to_utf8(cwdbuf); - if(is_slash(path.back())) - path.pop_back(); - free(cwdbuf); - } - std::replace(path.begin(), path.end(), '/', '\\'); - DirectorySearch(path.c_str(), ext, &results); - - /* Search the local and global data dirs. */ - static constexpr int ids[2]{ CSIDL_APPDATA, CSIDL_COMMON_APPDATA }; - for(int id : ids) - { - WCHAR buffer[MAX_PATH]; - if(SHGetSpecialFolderPathW(nullptr, buffer, id, FALSE) == FALSE) - continue; - - path = wstr_to_utf8(buffer); - if(!is_slash(path.back())) - path += '\\'; - path += subdir; - std::replace(path.begin(), path.end(), '/', '\\'); - - DirectorySearch(path.c_str(), ext, &results); - } - - return results; -} - -void SetRTPriority(void) -{ - bool failed = false; - if(RTPrioLevel > 0) - failed = !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); - if(failed) ERR("Failed to set priority level for thread\n"); -} - -#else - -const PathNamePair &GetProcBinary() -{ - static PathNamePair ret; - if(!ret.fname.empty() || !ret.path.empty()) - return ret; - - al::vector pathname; -#ifdef __FreeBSD__ - size_t pathlen; - int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; - if(sysctl(mib, 4, nullptr, &pathlen, nullptr, 0) == -1) - WARN("Failed to sysctl kern.proc.pathname: %s\n", strerror(errno)); - else - { - pathname.resize(pathlen + 1); - sysctl(mib, 4, pathname.data(), &pathlen, nullptr, 0); - pathname.resize(pathlen); - } -#endif -#ifdef HAVE_PROC_PIDPATH - if(pathname.empty()) - { - char procpath[PROC_PIDPATHINFO_MAXSIZE]{}; - const pid_t pid{getpid()}; - if(proc_pidpath(pid, procpath, sizeof(procpath)) < 1) - ERR("proc_pidpath(%d, ...) failed: %s\n", pid, strerror(errno)); - else - pathname.insert(pathname.end(), procpath, procpath+strlen(procpath)); - } -#endif - if(pathname.empty()) - { - pathname.resize(256); - - const char *selfname{"/proc/self/exe"}; - ssize_t len{readlink(selfname, pathname.data(), pathname.size())}; - if(len == -1 && errno == ENOENT) - { - selfname = "/proc/self/file"; - len = readlink(selfname, pathname.data(), pathname.size()); - } - if(len == -1 && errno == ENOENT) - { - selfname = "/proc/curproc/exe"; - len = readlink(selfname, pathname.data(), pathname.size()); - } - if(len == -1 && errno == ENOENT) - { - selfname = "/proc/curproc/file"; - len = readlink(selfname, pathname.data(), pathname.size()); - } - - while(len > 0 && static_cast(len) == pathname.size()) - { - pathname.resize(pathname.size() << 1); - len = readlink(selfname, pathname.data(), pathname.size()); - } - if(len <= 0) - { - WARN("Failed to readlink %s: %s\n", selfname, strerror(errno)); - return ret; - } - - pathname.resize(len); - } - while(!pathname.empty() && pathname.back() == 0) - pathname.pop_back(); - - auto sep = std::find(pathname.crbegin(), pathname.crend(), '/'); - if(sep != pathname.crend()) - { - ret.path = std::string(pathname.cbegin(), sep.base()-1); - ret.fname = std::string(sep.base(), pathname.cend()); - } - else - ret.fname = std::string(pathname.cbegin(), pathname.cend()); - - TRACE("Got binary: %s, %s\n", ret.path.c_str(), ret.fname.c_str()); - return ret; -} - - -#ifdef HAVE_DLFCN_H - -void *LoadLib(const char *name) -{ - dlerror(); - void *handle{dlopen(name, RTLD_NOW)}; - const char *err{dlerror()}; - if(err) handle = nullptr; - return handle; -} -void CloseLib(void *handle) -{ dlclose(handle); } -void *GetSymbol(void *handle, const char *name) -{ - dlerror(); - void *sym{dlsym(handle, name)}; - const char *err{dlerror()}; - if(err) - { - WARN("Failed to load %s: %s\n", name, err); - sym = nullptr; - } - return sym; -} - -#endif /* HAVE_DLFCN_H */ - -void al_print(FILE *logfile, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vfprintf(logfile, fmt, ap); - va_end(ap); - - fflush(logfile); -} - - -static void DirectorySearch(const char *path, const char *ext, al::vector *const results) -{ - TRACE("Searching %s for *%s\n", path, ext); - DIR *dir{opendir(path)}; - if(dir != nullptr) - { - const size_t extlen = strlen(ext); - size_t base = results->size(); - - struct dirent *dirent; - while((dirent=readdir(dir)) != nullptr) - { - if(strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) - continue; - - size_t len{strlen(dirent->d_name)}; - if(len <= extlen) continue; - if(strcasecmp(dirent->d_name+len-extlen, ext) != 0) - continue; - - results->emplace_back(); - std::string &str = results->back(); - str = path; - if(str.back() != '/') - str.push_back('/'); - str += dirent->d_name; - TRACE("Got result %s\n", str.c_str()); - } - closedir(dir); - - std::sort(results->begin()+base, results->end()); - } -} - -al::vector SearchDataFiles(const char *ext, const char *subdir) -{ - static std::mutex search_lock; - std::lock_guard _{search_lock}; - - al::vector results; - if(subdir[0] == '/') - { - DirectorySearch(subdir, ext, &results); - return results; - } - - /* Search the app-local directory. */ - const char *str{getenv("ALSOFT_LOCAL_PATH")}; - if(str && *str != '\0') - DirectorySearch(str, ext, &results); - else - { - al::vector cwdbuf(256); - while(!getcwd(cwdbuf.data(), cwdbuf.size())) - { - if(errno != ERANGE) - { - cwdbuf.clear(); - break; - } - cwdbuf.resize(cwdbuf.size() << 1); - } - if(cwdbuf.empty()) - DirectorySearch(".", ext, &results); - else - { - DirectorySearch(cwdbuf.data(), ext, &results); - cwdbuf.clear(); - } - } - - // Search local data dir - if((str=getenv("XDG_DATA_HOME")) != nullptr && str[0] != '\0') - { - std::string path{str}; - if(path.back() != '/') - path += '/'; - path += subdir; - DirectorySearch(path.c_str(), ext, &results); - } - else if((str=getenv("HOME")) != nullptr && str[0] != '\0') - { - std::string path{str}; - if(path.back() == '/') - path.pop_back(); - path += "/.local/share/"; - path += subdir; - DirectorySearch(path.c_str(), ext, &results); - } - - // Search global data dirs - if((str=getenv("XDG_DATA_DIRS")) == nullptr || str[0] == '\0') - str = "/usr/local/share/:/usr/share/"; - - const char *next{str}; - while((str=next) != nullptr && str[0] != '\0') - { - next = strchr(str, ':'); - - std::string path = (next ? std::string(str, next++) : std::string(str)); - if(path.empty()) continue; - - if(path.back() != '/') - path += '/'; - path += subdir; - - DirectorySearch(path.c_str(), ext, &results); - } - - return results; -} - -void SetRTPriority() -{ - bool failed = false; -#if defined(HAVE_PTHREAD_SETSCHEDPARAM) && !defined(__OpenBSD__) - if(RTPrioLevel > 0) - { - struct sched_param param; - /* Use the minimum real-time priority possible for now (on Linux this - * should be 1 for SCHED_RR) */ - param.sched_priority = sched_get_priority_min(SCHED_RR); - failed = !!pthread_setschedparam(pthread_self(), SCHED_RR, ¶m); - } -#else - /* Real-time priority not available */ - failed = (RTPrioLevel>0); -#endif - if(failed) - ERR("Failed to set priority level for thread\n"); -} - -#endif diff --git a/Alc/hrtf.cpp b/Alc/hrtf.cpp deleted file mode 100644 index 786c4c5d..00000000 --- a/Alc/hrtf.cpp +++ /dev/null @@ -1,1400 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2011 by Chris Robinson - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "hrtf.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" - -#include "alcmain.h" -#include "alconfig.h" -#include "almalloc.h" -#include "alnumeric.h" -#include "aloptional.h" -#include "alspan.h" -#include "compat.h" -#include "filters/splitter.h" -#include "logging.h" -#include "math_defs.h" -#include "opthelpers.h" - - -struct HrtfHandle { - std::unique_ptr entry; - al::FlexArray filename; - - HrtfHandle(size_t fname_len) : filename{fname_len} { } - HrtfHandle(const HrtfHandle&) = delete; - HrtfHandle& operator=(const HrtfHandle&) = delete; - - static std::unique_ptr Create(size_t fname_len); - static constexpr size_t Sizeof(size_t length) noexcept - { - return maxz(sizeof(HrtfHandle), - al::FlexArray::Sizeof(length, offsetof(HrtfHandle, filename))); - } - - DEF_PLACE_NEWDEL() -}; - -std::unique_ptr HrtfHandle::Create(size_t fname_len) -{ - void *ptr{al_calloc(alignof(HrtfHandle), HrtfHandle::Sizeof(fname_len))}; - return std::unique_ptr{new (ptr) HrtfHandle{fname_len}}; -} - -namespace { - -using namespace std::placeholders; - -using HrtfHandlePtr = std::unique_ptr; - -/* Data set limits must be the same as or more flexible than those defined in - * the makemhr utility. - */ -#define MIN_IR_SIZE (8) -#define MAX_IR_SIZE (512) -#define MOD_IR_SIZE (2) - -#define MIN_FD_COUNT (1) -#define MAX_FD_COUNT (16) - -#define MIN_FD_DISTANCE (0.05f) -#define MAX_FD_DISTANCE (2.5f) - -#define MIN_EV_COUNT (5) -#define MAX_EV_COUNT (128) - -#define MIN_AZ_COUNT (1) -#define MAX_AZ_COUNT (128) - -#define MAX_HRIR_DELAY (HRTF_HISTORY_LENGTH-1) - -constexpr ALchar magicMarker00[8]{'M','i','n','P','H','R','0','0'}; -constexpr ALchar magicMarker01[8]{'M','i','n','P','H','R','0','1'}; -constexpr ALchar magicMarker02[8]{'M','i','n','P','H','R','0','2'}; - -/* First value for pass-through coefficients (remaining are 0), used for omni- - * directional sounds. */ -constexpr ALfloat PassthruCoeff{0.707106781187f/*sqrt(0.5)*/}; - -std::mutex LoadedHrtfLock; -al::vector LoadedHrtfs; - - -class databuf final : public std::streambuf { - int_type underflow() override - { return traits_type::eof(); } - - pos_type seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) override - { - if((mode&std::ios_base::out) || !(mode&std::ios_base::in)) - return traits_type::eof(); - - char_type *cur; - switch(whence) - { - case std::ios_base::beg: - if(offset < 0 || offset > egptr()-eback()) - return traits_type::eof(); - cur = eback() + offset; - break; - - case std::ios_base::cur: - if((offset >= 0 && offset > egptr()-gptr()) || - (offset < 0 && -offset > gptr()-eback())) - return traits_type::eof(); - cur = gptr() + offset; - break; - - case std::ios_base::end: - if(offset > 0 || -offset > egptr()-eback()) - return traits_type::eof(); - cur = egptr() + offset; - break; - - default: - return traits_type::eof(); - } - - setg(eback(), cur, egptr()); - return cur - eback(); - } - - pos_type seekpos(pos_type pos, std::ios_base::openmode mode) override - { - // Simplified version of seekoff - if((mode&std::ios_base::out) || !(mode&std::ios_base::in)) - return traits_type::eof(); - - if(pos < 0 || pos > egptr()-eback()) - return traits_type::eof(); - - setg(eback(), eback() + static_cast(pos), egptr()); - return pos; - } - -public: - databuf(const char_type *start, const char_type *end) noexcept - { - setg(const_cast(start), const_cast(start), - const_cast(end)); - } -}; - -class idstream final : public std::istream { - databuf mStreamBuf; - -public: - idstream(const char *start, const char *end) - : std::istream{nullptr}, mStreamBuf{start, end} - { init(&mStreamBuf); } -}; - - -struct IdxBlend { ALsizei idx; ALfloat blend; }; -/* Calculate the elevation index given the polar elevation in radians. This - * will return an index between 0 and (evcount - 1). - */ -IdxBlend CalcEvIndex(ALsizei evcount, ALfloat ev) -{ - ev = (al::MathDefs::Pi()*0.5f + ev) * (evcount-1) / al::MathDefs::Pi(); - ALsizei idx{float2int(ev)}; - - return IdxBlend{mini(idx, evcount-1), ev-idx}; -} - -/* Calculate the azimuth index given the polar azimuth in radians. This will - * return an index between 0 and (azcount - 1). - */ -IdxBlend CalcAzIndex(ALsizei azcount, ALfloat az) -{ - az = (al::MathDefs::Tau()+az) * azcount / al::MathDefs::Tau(); - ALsizei idx{float2int(az)}; - - return IdxBlend{idx%azcount, az-idx}; -} - -} // namespace - - -/* Calculates static HRIR coefficients and delays for the given polar elevation - * and azimuth in radians. The coefficients are normalized. - */ -void GetHrtfCoeffs(const HrtfEntry *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat distance, - ALfloat spread, HrirArray &coeffs, ALsizei (&delays)[2]) -{ - const ALfloat dirfact{1.0f - (spread / al::MathDefs::Tau())}; - - const auto *field = Hrtf->field; - const auto *field_end = field + Hrtf->fdCount-1; - ALsizei ebase{0}; - while(distance < field->distance && field != field_end) - { - ebase += field->evCount; - ++field; - } - - /* Claculate the elevation indinces. */ - const auto elev0 = CalcEvIndex(field->evCount, elevation); - const ALsizei elev1_idx{mini(elev0.idx+1, field->evCount-1)}; - const ALsizei ir0offset{Hrtf->elev[ebase + elev0.idx].irOffset}; - const ALsizei ir1offset{Hrtf->elev[ebase + elev1_idx].irOffset}; - - /* Calculate azimuth indices. */ - const auto az0 = CalcAzIndex(Hrtf->elev[ebase + elev0.idx].azCount, azimuth); - const auto az1 = CalcAzIndex(Hrtf->elev[ebase + elev1_idx].azCount, azimuth); - - /* Calculate the HRIR indices to blend. */ - ALsizei idx[4]{ - ir0offset + az0.idx, - ir0offset + ((az0.idx+1) % Hrtf->elev[ebase + elev0.idx].azCount), - ir1offset + az1.idx, - ir1offset + ((az1.idx+1) % Hrtf->elev[ebase + elev1_idx].azCount) - }; - - /* Calculate bilinear blending weights, attenuated according to the - * directional panning factor. - */ - const ALfloat blend[4]{ - (1.0f-elev0.blend) * (1.0f-az0.blend) * dirfact, - (1.0f-elev0.blend) * ( az0.blend) * dirfact, - ( elev0.blend) * (1.0f-az1.blend) * dirfact, - ( elev0.blend) * ( az1.blend) * dirfact - }; - - /* Calculate the blended HRIR delays. */ - delays[0] = fastf2i( - Hrtf->delays[idx[0]][0]*blend[0] + Hrtf->delays[idx[1]][0]*blend[1] + - Hrtf->delays[idx[2]][0]*blend[2] + Hrtf->delays[idx[3]][0]*blend[3] - ); - delays[1] = fastf2i( - Hrtf->delays[idx[0]][1]*blend[0] + Hrtf->delays[idx[1]][1]*blend[1] + - Hrtf->delays[idx[2]][1]*blend[2] + Hrtf->delays[idx[3]][1]*blend[3] - ); - - const ALsizei irSize{Hrtf->irSize}; - ASSUME(irSize >= MIN_IR_SIZE); - - /* Calculate the sample offsets for the HRIR indices. */ - idx[0] *= irSize; - idx[1] *= irSize; - idx[2] *= irSize; - idx[3] *= irSize; - - /* Calculate the blended HRIR coefficients. */ - ALfloat *coeffout{al::assume_aligned<16>(&coeffs[0][0])}; - coeffout[0] = PassthruCoeff * (1.0f-dirfact); - coeffout[1] = PassthruCoeff * (1.0f-dirfact); - std::fill(coeffout+2, coeffout + irSize*2, 0.0f); - for(ALsizei c{0};c < 4;c++) - { - const ALfloat *srccoeffs{al::assume_aligned<16>(Hrtf->coeffs[idx[c]])}; - const ALfloat mult{blend[c]}; - auto blend_coeffs = [mult](const ALfloat src, const ALfloat coeff) noexcept -> ALfloat - { return src*mult + coeff; }; - std::transform(srccoeffs, srccoeffs + irSize*2, coeffout, coeffout, blend_coeffs); - } -} - - -std::unique_ptr DirectHrtfState::Create(size_t num_chans) -{ - void *ptr{al_calloc(16, DirectHrtfState::Sizeof(num_chans))}; - return std::unique_ptr{new (ptr) DirectHrtfState{num_chans}}; -} - -void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuint NumChannels, - const AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_CHANNELS], - const size_t AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain) -{ - static constexpr int OrderFromChan[MAX_AMBI_CHANNELS]{ - 0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3, - }; - /* Set this to true for dual-band HRTF processing. May require better - * calculation of the new IR length to deal with the head and tail - * generated by the HF scaling. - */ - static constexpr bool DualBand{true}; - - ASSUME(NumChannels > 0); - ASSUME(AmbiCount > 0); - - auto &field = Hrtf->field[0]; - ALsizei min_delay{HRTF_HISTORY_LENGTH}; - ALsizei max_delay{0}; - auto idx = al::vector(AmbiCount); - auto calc_idxs = [Hrtf,&field,&max_delay,&min_delay](const AngularPoint &pt) noexcept -> ALsizei - { - /* Calculate elevation index. */ - const auto evidx = clampi( - static_cast((90.0f+pt.Elev)*(field.evCount-1)/180.0f + 0.5f), - 0, field.evCount-1); - - const ALsizei azcount{Hrtf->elev[evidx].azCount}; - const ALsizei iroffset{Hrtf->elev[evidx].irOffset}; - - /* Calculate azimuth index for this elevation. */ - const auto azidx = static_cast((360.0f+pt.Azim)*azcount/360.0f + 0.5f) % azcount; - - /* Calculate the index for the impulse response. */ - ALsizei idx{iroffset + azidx}; - - min_delay = mini(min_delay, mini(Hrtf->delays[idx][0], Hrtf->delays[idx][1])); - max_delay = maxi(max_delay, maxi(Hrtf->delays[idx][0], Hrtf->delays[idx][1])); - - return idx; - }; - std::transform(AmbiPoints, AmbiPoints+AmbiCount, idx.begin(), calc_idxs); - - /* For dual-band processing, add a 16-sample delay to compensate for the HF - * scale on the minimum-phase response. - */ - static constexpr ALsizei base_delay{DualBand ? 16 : 0}; - const ALdouble xover_norm{400.0 / Hrtf->sampleRate}; - BandSplitterR splitter{xover_norm}; - - auto tmpres = al::vector>(NumChannels); - auto tmpfilt = al::vector>(3); - for(size_t c{0u};c < AmbiCount;++c) - { - const ALfloat (*fir)[2]{&Hrtf->coeffs[idx[c] * Hrtf->irSize]}; - const ALsizei ldelay{Hrtf->delays[idx[c]][0] - min_delay + base_delay}; - const ALsizei rdelay{Hrtf->delays[idx[c]][1] - min_delay + base_delay}; - - if(!DualBand) - { - /* For single-band decoding, apply the HF scale to the response. */ - for(ALuint i{0u};i < NumChannels;++i) - { - const ALdouble mult{ALdouble{AmbiOrderHFGain[OrderFromChan[i]]} * - AmbiMatrix[c][i]}; - const ALsizei numirs{mini(Hrtf->irSize, HRIR_LENGTH-maxi(ldelay, rdelay))}; - ALsizei lidx{ldelay}, ridx{rdelay}; - for(ALsizei j{0};j < numirs;++j) - { - tmpres[i][lidx++][0] += fir[j][0] * mult; - tmpres[i][ridx++][1] += fir[j][1] * mult; - } - } - continue; - } - - /* For dual-band processing, the HRIR needs to be split into low and - * high frequency responses. The band-splitter alone creates frequency- - * dependent phase-shifts, which is not ideal. To counteract it, - * combine it with a backwards phase-shift. - */ - - /* Load the (left) HRIR backwards, into a temp buffer with padding. */ - std::fill(tmpfilt[2].begin(), tmpfilt[2].end(), 0.0); - std::transform(fir, fir+Hrtf->irSize, tmpfilt[2].rbegin() + HRIR_LENGTH*3, - [](const ALfloat (&ir)[2]) noexcept -> ALdouble { return ir[0]; }); - - /* Apply the all-pass on the reversed signal and reverse the resulting - * sample array. This produces the forward response with a backwards - * phase-shift (+n degrees becomes -n degrees). - */ - splitter.applyAllpass(tmpfilt[2].data(), static_cast(tmpfilt[2].size())); - std::reverse(tmpfilt[2].begin(), tmpfilt[2].end()); - - /* Now apply the band-splitter. This applies the normal phase-shift, - * which cancels out with the backwards phase-shift to get the original - * phase on the split signal. - */ - splitter.clear(); - splitter.process(tmpfilt[0].data(), tmpfilt[1].data(), tmpfilt[2].data(), - static_cast(tmpfilt[2].size())); - - /* Apply left ear response with delay and HF scale. */ - for(ALuint i{0u};i < NumChannels;++i) - { - const ALdouble mult{AmbiMatrix[c][i]}; - const ALdouble hfgain{AmbiOrderHFGain[OrderFromChan[i]]}; - ALsizei j{HRIR_LENGTH*3 - ldelay}; - for(ALsizei lidx{0};lidx < HRIR_LENGTH;++lidx,++j) - tmpres[i][lidx][0] += (tmpfilt[0][j]*hfgain + tmpfilt[1][j]) * mult; - } - - /* Now run the same process on the right HRIR. */ - std::fill(tmpfilt[2].begin(), tmpfilt[2].end(), 0.0); - std::transform(fir, fir+Hrtf->irSize, tmpfilt[2].rbegin() + HRIR_LENGTH*3, - [](const ALfloat (&ir)[2]) noexcept -> ALdouble { return ir[1]; }); - - splitter.applyAllpass(tmpfilt[2].data(), static_cast(tmpfilt[2].size())); - std::reverse(tmpfilt[2].begin(), tmpfilt[2].end()); - - splitter.clear(); - splitter.process(tmpfilt[0].data(), tmpfilt[1].data(), tmpfilt[2].data(), - static_cast(tmpfilt[2].size())); - - for(ALuint i{0u};i < NumChannels;++i) - { - const ALdouble mult{AmbiMatrix[c][i]}; - const ALdouble hfgain{AmbiOrderHFGain[OrderFromChan[i]]}; - ALsizei j{HRIR_LENGTH*3 - rdelay}; - for(ALsizei ridx{0};ridx < HRIR_LENGTH;++ridx,++j) - tmpres[i][ridx][1] += (tmpfilt[0][j]*hfgain + tmpfilt[1][j]) * mult; - } - } - tmpfilt.clear(); - idx.clear(); - - for(ALuint i{0u};i < NumChannels;++i) - { - auto copy_arr = [](const std::array &in) noexcept -> std::array - { return std::array{{static_cast(in[0]), static_cast(in[1])}}; }; - std::transform(tmpres[i].begin(), tmpres[i].end(), state->Chan[i].Coeffs.begin(), - copy_arr); - } - tmpres.clear(); - - ALsizei max_length{HRIR_LENGTH}; - /* Increase the IR size by double the base delay with dual-band processing - * to account for the head and tail from the HF response scale. - */ - const ALsizei irsize{mini(Hrtf->irSize + base_delay*2, max_length)}; - max_length = mini(max_delay-min_delay + irsize, max_length); - - /* Round up to the next IR size multiple. */ - max_length += MOD_IR_SIZE-1; - max_length -= max_length%MOD_IR_SIZE; - - TRACE("Skipped delay: %d, max delay: %d, new FIR length: %d\n", - min_delay, max_delay-min_delay, max_length); - state->IrSize = max_length; -} - - -namespace { - -std::unique_ptr CreateHrtfStore(ALuint rate, ALsizei irSize, const ALsizei fdCount, - const ALubyte *evCount, const ALfloat *distance, const ALushort *azCount, - const ALushort *irOffset, ALsizei irCount, const ALfloat (*coeffs)[2], - const ALubyte (*delays)[2], const char *filename) -{ - std::unique_ptr Hrtf; - - ALsizei evTotal{std::accumulate(evCount, evCount+fdCount, 0)}; - size_t total{sizeof(HrtfEntry)}; - total = RoundUp(total, alignof(HrtfEntry::Field)); /* Align for field infos */ - total += sizeof(HrtfEntry::Field)*fdCount; - total = RoundUp(total, alignof(HrtfEntry::Elevation)); /* Align for elevation infos */ - total += sizeof(Hrtf->elev[0])*evTotal; - total = RoundUp(total, 16); /* Align for coefficients using SIMD */ - total += sizeof(Hrtf->coeffs[0])*irSize*irCount; - total += sizeof(Hrtf->delays[0])*irCount; - - Hrtf.reset(new (al_calloc(16, total)) HrtfEntry{}); - if(!Hrtf) - ERR("Out of memory allocating storage for %s.\n", filename); - else - { - InitRef(&Hrtf->ref, 1u); - Hrtf->sampleRate = rate; - Hrtf->irSize = irSize; - Hrtf->fdCount = fdCount; - - /* Set up pointers to storage following the main HRTF struct. */ - char *base = reinterpret_cast(Hrtf.get()); - uintptr_t offset = sizeof(HrtfEntry); - - offset = RoundUp(offset, alignof(HrtfEntry::Field)); /* Align for field infos */ - auto field_ = reinterpret_cast(base + offset); - offset += sizeof(field_[0])*fdCount; - - offset = RoundUp(offset, alignof(HrtfEntry::Elevation)); /* Align for elevation infos */ - auto elev_ = reinterpret_cast(base + offset); - offset += sizeof(elev_[0])*evTotal; - - offset = RoundUp(offset, 16); /* Align for coefficients using SIMD */ - auto coeffs_ = reinterpret_cast(base + offset); - offset += sizeof(coeffs_[0])*irSize*irCount; - - auto delays_ = reinterpret_cast(base + offset); - offset += sizeof(delays_[0])*irCount; - - assert(offset == total); - - /* Copy input data to storage. */ - for(ALsizei i{0};i < fdCount;i++) - { - field_[i].distance = distance[i]; - field_[i].evCount = evCount[i]; - } - for(ALsizei i{0};i < evTotal;i++) - { - elev_[i].azCount = azCount[i]; - elev_[i].irOffset = irOffset[i]; - } - for(ALsizei i{0};i < irSize*irCount;i++) - { - coeffs_[i][0] = coeffs[i][0]; - coeffs_[i][1] = coeffs[i][1]; - } - for(ALsizei i{0};i < irCount;i++) - { - delays_[i][0] = delays[i][0]; - delays_[i][1] = delays[i][1]; - } - - /* Finally, assign the storage pointers. */ - Hrtf->field = field_; - Hrtf->elev = elev_; - Hrtf->coeffs = coeffs_; - Hrtf->delays = delays_; - } - - return Hrtf; -} - -ALubyte GetLE_ALubyte(std::istream &data) -{ - return static_cast(data.get()); -} - -ALshort GetLE_ALshort(std::istream &data) -{ - int ret = data.get(); - ret |= data.get() << 8; - return static_cast((ret^32768) - 32768); -} - -ALushort GetLE_ALushort(std::istream &data) -{ - int ret = data.get(); - ret |= data.get() << 8; - return static_cast(ret); -} - -ALint GetLE_ALint24(std::istream &data) -{ - int ret = data.get(); - ret |= data.get() << 8; - ret |= data.get() << 16; - return (ret^8388608) - 8388608; -} - -ALuint GetLE_ALuint(std::istream &data) -{ - int ret = data.get(); - ret |= data.get() << 8; - ret |= data.get() << 16; - ret |= data.get() << 24; - return ret; -} - -std::unique_ptr LoadHrtf00(std::istream &data, const char *filename) -{ - ALuint rate{GetLE_ALuint(data)}; - ALushort irCount{GetLE_ALushort(data)}; - ALushort irSize{GetLE_ALushort(data)}; - ALubyte evCount{GetLE_ALubyte(data)}; - if(!data || data.eof()) - { - ERR("Failed reading %s\n", filename); - return nullptr; - } - - ALboolean failed{AL_FALSE}; - if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) - { - ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", - irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE); - failed = AL_TRUE; - } - if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT) - { - ERR("Unsupported elevation count: evCount=%d (%d to %d)\n", - evCount, MIN_EV_COUNT, MAX_EV_COUNT); - failed = AL_TRUE; - } - if(failed) - return nullptr; - - al::vector evOffset(evCount); - for(auto &val : evOffset) - val = GetLE_ALushort(data); - if(!data || data.eof()) - { - ERR("Failed reading %s\n", filename); - return nullptr; - } - for(ALsizei i{1};i < evCount;i++) - { - if(evOffset[i] <= evOffset[i-1]) - { - ERR("Invalid evOffset: evOffset[%d]=%d (last=%d)\n", - i, evOffset[i], evOffset[i-1]); - failed = AL_TRUE; - } - } - if(irCount <= evOffset.back()) - { - ERR("Invalid evOffset: evOffset[%zu]=%d (irCount=%d)\n", - evOffset.size()-1, evOffset.back(), irCount); - failed = AL_TRUE; - } - if(failed) - return nullptr; - - al::vector azCount(evCount); - for(ALsizei i{1};i < evCount;i++) - { - azCount[i-1] = evOffset[i] - evOffset[i-1]; - if(azCount[i-1] < MIN_AZ_COUNT || azCount[i-1] > MAX_AZ_COUNT) - { - ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", - i-1, azCount[i-1], MIN_AZ_COUNT, MAX_AZ_COUNT); - failed = AL_TRUE; - } - } - azCount.back() = irCount - evOffset.back(); - if(azCount.back() < MIN_AZ_COUNT || azCount.back() > MAX_AZ_COUNT) - { - ERR("Unsupported azimuth count: azCount[%zu]=%d (%d to %d)\n", - azCount.size()-1, azCount.back(), MIN_AZ_COUNT, MAX_AZ_COUNT); - failed = AL_TRUE; - } - if(failed) - return nullptr; - - al::vector> coeffs(irSize*irCount); - al::vector> delays(irCount); - for(auto &val : coeffs) - val[0] = GetLE_ALshort(data) / 32768.0f; - for(auto &val : delays) - val[0] = GetLE_ALubyte(data); - if(!data || data.eof()) - { - ERR("Failed reading %s\n", filename); - return nullptr; - } - for(ALsizei i{0};i < irCount;i++) - { - if(delays[i][0] > MAX_HRIR_DELAY) - { - ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); - failed = AL_TRUE; - } - } - if(failed) - return nullptr; - - /* Mirror the left ear responses to the right ear. */ - for(ALsizei i{0};i < evCount;i++) - { - const ALushort evoffset{evOffset[i]}; - const ALushort azcount{azCount[i]}; - for(ALsizei j{0};j < azcount;j++) - { - const ALsizei lidx{evoffset + j}; - const ALsizei ridx{evoffset + ((azcount-j) % azcount)}; - - for(ALsizei k{0};k < irSize;k++) - coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; - delays[ridx][1] = delays[lidx][0]; - } - } - - static constexpr ALfloat distance{0.0f}; - return CreateHrtfStore(rate, irSize, 1, &evCount, &distance, azCount.data(), evOffset.data(), - irCount, &reinterpret_cast(coeffs[0]), - &reinterpret_cast(delays[0]), filename); -} - -std::unique_ptr LoadHrtf01(std::istream &data, const char *filename) -{ - ALuint rate{GetLE_ALuint(data)}; - ALushort irSize{GetLE_ALubyte(data)}; - ALubyte evCount{GetLE_ALubyte(data)}; - if(!data || data.eof()) - { - ERR("Failed reading %s\n", filename); - return nullptr; - } - - ALboolean failed{AL_FALSE}; - if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) - { - ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", - irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE); - failed = AL_TRUE; - } - if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT) - { - ERR("Unsupported elevation count: evCount=%d (%d to %d)\n", - evCount, MIN_EV_COUNT, MAX_EV_COUNT); - failed = AL_TRUE; - } - if(failed) - return nullptr; - - al::vector azCount(evCount); - std::generate(azCount.begin(), azCount.end(), std::bind(GetLE_ALubyte, std::ref(data))); - if(!data || data.eof()) - { - ERR("Failed reading %s\n", filename); - return nullptr; - } - for(ALsizei i{0};i < evCount;++i) - { - if(azCount[i] < MIN_AZ_COUNT || azCount[i] > MAX_AZ_COUNT) - { - ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", - i, azCount[i], MIN_AZ_COUNT, MAX_AZ_COUNT); - failed = AL_TRUE; - } - } - if(failed) - return nullptr; - - al::vector evOffset(evCount); - evOffset[0] = 0; - ALushort irCount{azCount[0]}; - for(ALsizei i{1};i < evCount;i++) - { - evOffset[i] = evOffset[i-1] + azCount[i-1]; - irCount += azCount[i]; - } - - al::vector> coeffs(irSize*irCount); - al::vector> delays(irCount); - for(auto &val : coeffs) - val[0] = GetLE_ALshort(data) / 32768.0f; - for(auto &val : delays) - val[0] = GetLE_ALubyte(data); - if(!data || data.eof()) - { - ERR("Failed reading %s\n", filename); - return nullptr; - } - for(ALsizei i{0};i < irCount;i++) - { - if(delays[i][0] > MAX_HRIR_DELAY) - { - ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); - failed = AL_TRUE; - } - } - if(failed) - return nullptr; - - /* Mirror the left ear responses to the right ear. */ - for(ALsizei i{0};i < evCount;i++) - { - const ALushort evoffset{evOffset[i]}; - const ALushort azcount{azCount[i]}; - for(ALsizei j{0};j < azcount;j++) - { - const ALsizei lidx{evoffset + j}; - const ALsizei ridx{evoffset + ((azcount-j) % azcount)}; - - for(ALsizei k{0};k < irSize;k++) - coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; - delays[ridx][1] = delays[lidx][0]; - } - } - - static constexpr ALfloat distance{0.0f}; - return CreateHrtfStore(rate, irSize, 1, &evCount, &distance, azCount.data(), evOffset.data(), - irCount, &reinterpret_cast(coeffs[0]), - &reinterpret_cast(delays[0]), filename); -} - -#define SAMPLETYPE_S16 0 -#define SAMPLETYPE_S24 1 - -#define CHANTYPE_LEFTONLY 0 -#define CHANTYPE_LEFTRIGHT 1 - -std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) -{ - ALuint rate{GetLE_ALuint(data)}; - ALubyte sampleType{GetLE_ALubyte(data)}; - ALubyte channelType{GetLE_ALubyte(data)}; - ALushort irSize{GetLE_ALubyte(data)}; - ALubyte fdCount{GetLE_ALubyte(data)}; - if(!data || data.eof()) - { - ERR("Failed reading %s\n", filename); - return nullptr; - } - - ALboolean failed{AL_FALSE}; - if(sampleType > SAMPLETYPE_S24) - { - ERR("Unsupported sample type: %d\n", sampleType); - failed = AL_TRUE; - } - if(channelType > CHANTYPE_LEFTRIGHT) - { - ERR("Unsupported channel type: %d\n", channelType); - failed = AL_TRUE; - } - - if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) - { - ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", - irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE); - failed = AL_TRUE; - } - if(fdCount < 1 || fdCount > MAX_FD_COUNT) - { - ERR("Multiple field-depths not supported: fdCount=%d (%d to %d)\n", - fdCount, MIN_FD_COUNT, MAX_FD_COUNT); - failed = AL_TRUE; - } - if(failed) - return nullptr; - - al::vector distance(fdCount); - al::vector evCount(fdCount); - al::vector azCount; - for(ALsizei f{0};f < fdCount;f++) - { - distance[f] = GetLE_ALushort(data) / 1000.0f; - evCount[f] = GetLE_ALubyte(data); - if(!data || data.eof()) - { - ERR("Failed reading %s\n", filename); - return nullptr; - } - - if(distance[f] < MIN_FD_DISTANCE || distance[f] > MAX_FD_DISTANCE) - { - ERR("Unsupported field distance[%d]=%f (%f to %f meters)\n", f, - distance[f], MIN_FD_DISTANCE, MAX_FD_DISTANCE); - failed = AL_TRUE; - } - if(f > 0 && distance[f] <= distance[f-1]) - { - ERR("Field distance[%d] is not after previous (%f > %f)\n", f, distance[f], - distance[f-1]); - failed = AL_TRUE; - } - if(evCount[f] < MIN_EV_COUNT || evCount[f] > MAX_EV_COUNT) - { - ERR("Unsupported elevation count: evCount[%d]=%d (%d to %d)\n", f, - evCount[f], MIN_EV_COUNT, MAX_EV_COUNT); - failed = AL_TRUE; - } - if(failed) - return nullptr; - - size_t ebase{azCount.size()}; - azCount.resize(ebase + evCount[f]); - std::generate(azCount.begin()+ebase, azCount.end(), - std::bind(GetLE_ALubyte, std::ref(data))); - if(!data || data.eof()) - { - ERR("Failed reading %s\n", filename); - return nullptr; - } - - for(ALsizei e{0};e < evCount[f];e++) - { - if(azCount[ebase+e] < MIN_AZ_COUNT || azCount[ebase+e] > MAX_AZ_COUNT) - { - ERR("Unsupported azimuth count: azCount[%d][%d]=%d (%d to %d)\n", f, e, - azCount[ebase+e], MIN_AZ_COUNT, MAX_AZ_COUNT); - failed = AL_TRUE; - } - } - if(failed) - return nullptr; - } - - al::vector evOffset(azCount.size()); - evOffset[0] = 0; - std::partial_sum(azCount.cbegin(), azCount.cend()-1, evOffset.begin()+1); - const ALsizei irTotal{evOffset.back() + azCount.back()}; - - al::vector> coeffs(irSize*irTotal); - al::vector> delays(irTotal); - if(channelType == CHANTYPE_LEFTONLY) - { - if(sampleType == SAMPLETYPE_S16) - { - for(auto &val : coeffs) - val[0] = GetLE_ALshort(data) / 32768.0f; - } - else if(sampleType == SAMPLETYPE_S24) - { - for(auto &val : coeffs) - val[0] = GetLE_ALint24(data) / 8388608.0f; - } - for(auto &val : delays) - val[0] = GetLE_ALubyte(data); - if(!data || data.eof()) - { - ERR("Failed reading %s\n", filename); - return nullptr; - } - for(ALsizei i{0};i < irTotal;++i) - { - if(delays[i][0] > MAX_HRIR_DELAY) - { - ERR("Invalid delays[%d][0]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); - failed = AL_TRUE; - } - } - } - else if(channelType == CHANTYPE_LEFTRIGHT) - { - if(sampleType == SAMPLETYPE_S16) - { - for(auto &val : coeffs) - { - val[0] = GetLE_ALshort(data) / 32768.0f; - val[1] = GetLE_ALshort(data) / 32768.0f; - } - } - else if(sampleType == SAMPLETYPE_S24) - { - for(auto &val : coeffs) - { - val[0] = GetLE_ALint24(data) / 8388608.0f; - val[1] = GetLE_ALint24(data) / 8388608.0f; - } - } - for(auto &val : delays) - { - val[0] = GetLE_ALubyte(data); - val[1] = GetLE_ALubyte(data); - } - if(!data || data.eof()) - { - ERR("Failed reading %s\n", filename); - return nullptr; - } - - for(ALsizei i{0};i < irTotal;++i) - { - if(delays[i][0] > MAX_HRIR_DELAY) - { - ERR("Invalid delays[%d][0]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); - failed = AL_TRUE; - } - if(delays[i][1] > MAX_HRIR_DELAY) - { - ERR("Invalid delays[%d][1]: %d (%d)\n", i, delays[i][1], MAX_HRIR_DELAY); - failed = AL_TRUE; - } - } - } - if(failed) - return nullptr; - - if(channelType == CHANTYPE_LEFTONLY) - { - /* Mirror the left ear responses to the right ear. */ - ALsizei ebase{0}; - for(ALsizei f{0};f < fdCount;f++) - { - for(ALsizei e{0};e < evCount[f];e++) - { - const ALushort evoffset{evOffset[ebase+e]}; - const ALushort azcount{azCount[ebase+e]}; - for(ALsizei a{0};a < azcount;a++) - { - const ALsizei lidx{evoffset + a}; - const ALsizei ridx{evoffset + ((azcount-a) % azcount)}; - - for(ALsizei k{0};k < irSize;k++) - coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; - delays[ridx][1] = delays[lidx][0]; - } - } - ebase += evCount[f]; - } - } - - if(fdCount > 1) - { - auto distance_ = al::vector(distance.size()); - auto evCount_ = al::vector(evCount.size()); - auto azCount_ = al::vector(azCount.size()); - auto evOffset_ = al::vector(evOffset.size()); - auto coeffs_ = al::vector(coeffs.size()); - auto delays_ = al::vector>(delays.size()); - - /* Simple reverse for the per-field elements. */ - std::reverse_copy(distance.cbegin(), distance.cend(), distance_.begin()); - std::reverse_copy(evCount.cbegin(), evCount.cend(), evCount_.begin()); - - /* Each field has a group of elevations, which each have an azimuth - * count. Reverse the order of the groups, keeping the relative order - * of per-group azimuth counts. - */ - auto azcnt_end = azCount_.end(); - auto copy_azs = [&azCount,&azcnt_end](const size_t ebase, const ALubyte num_evs) -> size_t - { - auto azcnt_src = azCount.begin()+ebase; - azcnt_end = std::copy_backward(azcnt_src, azcnt_src+num_evs, azcnt_end); - return ebase + num_evs; - }; - std::accumulate(evCount.cbegin(), evCount.cend(), size_t{0u}, copy_azs); - assert(azCount_.begin() == azcnt_end); - - /* Reestablish the IR offset for each elevation index, given the new - * ordering of elevations. - */ - evOffset_[0] = 0; - std::partial_sum(azCount_.cbegin(), azCount_.cend()-1, evOffset_.begin()+1); - - /* Reverse the order of each field's group of IRs. */ - auto coeffs_end = coeffs_.end(); - auto delays_end = delays_.end(); - auto copy_irs = [irSize,&azCount,&coeffs,&delays,&coeffs_end,&delays_end](const size_t ebase, const ALubyte num_evs) -> size_t - { - const ALsizei abase{std::accumulate(azCount.cbegin(), azCount.cbegin()+ebase, 0)}; - const ALsizei num_azs{std::accumulate(azCount.cbegin()+ebase, - azCount.cbegin() + (ebase+num_evs), 0)}; - - coeffs_end = std::copy_backward(coeffs.cbegin() + abase*irSize, - coeffs.cbegin() + (abase+num_azs)*irSize, coeffs_end); - delays_end = std::copy_backward(delays.cbegin() + abase, - delays.cbegin() + (abase+num_azs), delays_end); - - return ebase + num_evs; - }; - std::accumulate(evCount.cbegin(), evCount.cend(), size_t{0u}, copy_irs); - assert(coeffs_.begin() == coeffs_end); - assert(delays_.begin() == delays_end); - - distance = std::move(distance_); - evCount = std::move(evCount_); - azCount = std::move(azCount_); - evOffset = std::move(evOffset_); - coeffs = std::move(coeffs_); - delays = std::move(delays_); - } - - return CreateHrtfStore(rate, irSize, fdCount, evCount.data(), distance.data(), azCount.data(), - evOffset.data(), irTotal, &reinterpret_cast(coeffs[0]), - &reinterpret_cast(delays[0]), filename); -} - - -bool checkName(al::vector &list, const std::string &name) -{ - return std::find_if(list.cbegin(), list.cend(), - [&name](const EnumeratedHrtf &entry) - { return name == entry.name; } - ) != list.cend(); -} - -void AddFileEntry(al::vector &list, const std::string &filename) -{ - /* Check if this file has already been loaded globally. */ - auto loaded_entry = LoadedHrtfs.begin(); - for(;loaded_entry != LoadedHrtfs.end();++loaded_entry) - { - if(filename != (*loaded_entry)->filename.data()) - continue; - - /* Check if this entry has already been added to the list. */ - auto iter = std::find_if(list.cbegin(), list.cend(), - [loaded_entry](const EnumeratedHrtf &entry) -> bool - { return loaded_entry->get() == entry.hrtf; } - ); - if(iter != list.cend()) - { - TRACE("Skipping duplicate file entry %s\n", filename.c_str()); - return; - } - - break; - } - - if(loaded_entry == LoadedHrtfs.end()) - { - TRACE("Got new file \"%s\"\n", filename.c_str()); - - LoadedHrtfs.emplace_back(HrtfHandle::Create(filename.length()+1)); - loaded_entry = LoadedHrtfs.end()-1; - std::copy(filename.begin(), filename.end(), (*loaded_entry)->filename.begin()); - (*loaded_entry)->filename.back() = '\0'; - } - - /* TODO: Get a human-readable name from the HRTF data (possibly coming in a - * format update). */ - size_t namepos = filename.find_last_of('/')+1; - if(!namepos) namepos = filename.find_last_of('\\')+1; - - size_t extpos{filename.find_last_of('.')}; - if(extpos <= namepos) extpos = std::string::npos; - - const std::string basename{(extpos == std::string::npos) ? - filename.substr(namepos) : filename.substr(namepos, extpos-namepos)}; - std::string newname{basename}; - int count{1}; - while(checkName(list, newname)) - { - newname = basename; - newname += " #"; - newname += std::to_string(++count); - } - list.emplace_back(EnumeratedHrtf{newname, loaded_entry->get()}); - const EnumeratedHrtf &entry = list.back(); - - TRACE("Adding file entry \"%s\"\n", entry.name.c_str()); -} - -/* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer - * for input instead of opening the given filename. - */ -void AddBuiltInEntry(al::vector &list, const std::string &filename, ALuint residx) -{ - auto loaded_entry = LoadedHrtfs.begin(); - for(;loaded_entry != LoadedHrtfs.end();++loaded_entry) - { - if(filename != (*loaded_entry)->filename.data()) - continue; - - /* Check if this entry has already been added to the list. */ - auto iter = std::find_if(list.cbegin(), list.cend(), - [loaded_entry](const EnumeratedHrtf &entry) -> bool - { return loaded_entry->get() == entry.hrtf; } - ); - if(iter != list.cend()) - { - TRACE("Skipping duplicate file entry %s\n", filename.c_str()); - return; - } - - break; - } - - if(loaded_entry == LoadedHrtfs.end()) - { - TRACE("Got new file \"%s\"\n", filename.c_str()); - - LoadedHrtfs.emplace_back(HrtfHandle::Create(filename.length()+32)); - loaded_entry = LoadedHrtfs.end()-1; - snprintf((*loaded_entry)->filename.data(), (*loaded_entry)->filename.size(), "!%u_%s", - residx, filename.c_str()); - } - - /* TODO: Get a human-readable name from the HRTF data (possibly coming in a - * format update). */ - - std::string newname{filename}; - int count{1}; - while(checkName(list, newname)) - { - newname = filename; - newname += " #"; - newname += std::to_string(++count); - } - list.emplace_back(EnumeratedHrtf{newname, loaded_entry->get()}); - const EnumeratedHrtf &entry = list.back(); - - TRACE("Adding built-in entry \"%s\"\n", entry.name.c_str()); -} - - -#define IDR_DEFAULT_44100_MHR 1 -#define IDR_DEFAULT_48000_MHR 2 - -using ResData = al::span; -#ifndef ALSOFT_EMBED_HRTF_DATA - -ResData GetResource(int /*name*/) -{ return ResData{}; } - -#else - -#include "default-44100.mhr.h" -#include "default-48000.mhr.h" - -ResData GetResource(int name) -{ - if(name == IDR_DEFAULT_44100_MHR) - return {reinterpret_cast(hrtf_default_44100), sizeof(hrtf_default_44100)}; - if(name == IDR_DEFAULT_48000_MHR) - return {reinterpret_cast(hrtf_default_48000), sizeof(hrtf_default_48000)}; - return ResData{}; -} -#endif - -} // namespace - - -al::vector EnumerateHrtf(const char *devname) -{ - al::vector list; - - bool usedefaults{true}; - if(auto pathopt = ConfigValueStr(devname, nullptr, "hrtf-paths")) - { - const char *pathlist{pathopt->c_str()}; - while(pathlist && *pathlist) - { - const char *next, *end; - - while(isspace(*pathlist) || *pathlist == ',') - pathlist++; - if(*pathlist == '\0') - continue; - - next = strchr(pathlist, ','); - if(next) - end = next++; - else - { - end = pathlist + strlen(pathlist); - usedefaults = false; - } - - while(end != pathlist && isspace(*(end-1))) - --end; - if(end != pathlist) - { - const std::string pname{pathlist, end}; - for(const auto &fname : SearchDataFiles(".mhr", pname.c_str())) - AddFileEntry(list, fname); - } - - pathlist = next; - } - } - else if(ConfigValueExists(devname, nullptr, "hrtf_tables")) - ERR("The hrtf_tables option is deprecated, please use hrtf-paths instead.\n"); - - if(usedefaults) - { - for(const auto &fname : SearchDataFiles(".mhr", "openal/hrtf")) - AddFileEntry(list, fname); - - if(!GetResource(IDR_DEFAULT_44100_MHR).empty()) - AddBuiltInEntry(list, "Built-In 44100hz", IDR_DEFAULT_44100_MHR); - - if(!GetResource(IDR_DEFAULT_48000_MHR).empty()) - AddBuiltInEntry(list, "Built-In 48000hz", IDR_DEFAULT_48000_MHR); - } - - if(!list.empty()) - { - if(auto defhrtfopt = ConfigValueStr(devname, nullptr, "default-hrtf")) - { - auto iter = std::find_if(list.begin(), list.end(), - [&defhrtfopt](const EnumeratedHrtf &entry) -> bool - { return entry.name == *defhrtfopt; } - ); - if(iter == list.end()) - WARN("Failed to find default HRTF \"%s\"\n", defhrtfopt->c_str()); - else if(iter != list.begin()) - { - EnumeratedHrtf entry{std::move(*iter)}; - list.erase(iter); - list.insert(list.begin(), std::move(entry)); - } - } - } - - return list; -} - -HrtfEntry *GetLoadedHrtf(HrtfHandle *handle) -{ - std::lock_guard _{LoadedHrtfLock}; - - if(handle->entry) - { - HrtfEntry *hrtf{handle->entry.get()}; - hrtf->IncRef(); - return hrtf; - } - - std::unique_ptr stream; - const char *name{""}; - ALuint residx{}; - char ch{}; - if(sscanf(handle->filename.data(), "!%u%c", &residx, &ch) == 2 && ch == '_') - { - name = strchr(handle->filename.data(), ch)+1; - - TRACE("Loading %s...\n", name); - ResData res{GetResource(residx)}; - if(res.empty()) - { - ERR("Could not get resource %u, %s\n", residx, name); - return nullptr; - } - stream = al::make_unique(res.begin(), res.end()); - } - else - { - name = handle->filename.data(); - - TRACE("Loading %s...\n", handle->filename.data()); - auto fstr = al::make_unique(handle->filename.data(), std::ios::binary); - if(!fstr->is_open()) - { - ERR("Could not open %s\n", handle->filename.data()); - return nullptr; - } - stream = std::move(fstr); - } - - std::unique_ptr hrtf; - char magic[sizeof(magicMarker02)]; - stream->read(magic, sizeof(magic)); - if(stream->gcount() < static_cast(sizeof(magicMarker02))) - ERR("%s data is too short (%zu bytes)\n", name, stream->gcount()); - else if(memcmp(magic, magicMarker02, sizeof(magicMarker02)) == 0) - { - TRACE("Detected data set format v2\n"); - hrtf = LoadHrtf02(*stream, name); - } - else if(memcmp(magic, magicMarker01, sizeof(magicMarker01)) == 0) - { - TRACE("Detected data set format v1\n"); - hrtf = LoadHrtf01(*stream, name); - } - else if(memcmp(magic, magicMarker00, sizeof(magicMarker00)) == 0) - { - TRACE("Detected data set format v0\n"); - hrtf = LoadHrtf00(*stream, name); - } - else - ERR("Invalid header in %s: \"%.8s\"\n", name, magic); - stream.reset(); - - if(!hrtf) - { - ERR("Failed to load %s\n", name); - return nullptr; - } - - TRACE("Loaded HRTF support for format: %s %uhz\n", - DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); - handle->entry = std::move(hrtf); - - return handle->entry.get(); -} - - -void HrtfEntry::IncRef() -{ - auto ref = IncrementRef(&this->ref); - TRACEREF("HrtfEntry %p increasing refcount to %u\n", this, ref); -} - -void HrtfEntry::DecRef() -{ - auto ref = DecrementRef(&this->ref); - TRACEREF("HrtfEntry %p decreasing refcount to %u\n", this, ref); - if(ref == 0) - { - std::lock_guard _{LoadedHrtfLock}; - - /* Go through and clear all unused HRTFs. */ - auto delete_unused = [](HrtfHandlePtr &handle) -> void - { - HrtfEntry *entry{handle->entry.get()}; - if(entry && ReadRef(&entry->ref) == 0) - { - TRACE("Unloading unused HRTF %s\n", handle->filename.data()); - handle->entry = nullptr; - } - }; - std::for_each(LoadedHrtfs.begin(), LoadedHrtfs.end(), delete_unused); - } -} diff --git a/Alc/hrtf.h b/Alc/hrtf.h deleted file mode 100644 index 6c41cb82..00000000 --- a/Alc/hrtf.h +++ /dev/null @@ -1,124 +0,0 @@ -#ifndef ALC_HRTF_H -#define ALC_HRTF_H - -#include -#include -#include -#include - -#include "AL/al.h" - -#include "almalloc.h" -#include "ambidefs.h" -#include "atomic.h" -#include "vector.h" - - -struct HrtfHandle; - -#define HRTF_HISTORY_BITS (6) -#define HRTF_HISTORY_LENGTH (1<; - -template -using HrirArray = std::array,HRIR_LENGTH>; - -struct HrtfState { - alignas(16) std::array History; - alignas(16) HrirArray Values; -}; - -struct HrtfFilter { - alignas(16) HrirArray Coeffs; - ALsizei Delay[2]; - ALfloat Gain; -}; - -struct DirectHrtfState { - /* HRTF filter state for dry buffer content */ - ALsizei IrSize{0}; - struct ChanData { - alignas(16) HrirArray Values; - alignas(16) HrirArray Coeffs; - }; - al::FlexArray Chan; - - DirectHrtfState(size_t numchans) : Chan{numchans} { } - DirectHrtfState(const DirectHrtfState&) = delete; - DirectHrtfState& operator=(const DirectHrtfState&) = delete; - - static std::unique_ptr Create(size_t num_chans); - static constexpr size_t Sizeof(size_t numchans) noexcept - { return al::FlexArray::Sizeof(numchans, offsetof(DirectHrtfState, Chan)); } - - DEF_PLACE_NEWDEL() -}; - -struct AngularPoint { - ALfloat Elev; - ALfloat Azim; -}; - - -al::vector EnumerateHrtf(const char *devname); -HrtfEntry *GetLoadedHrtf(HrtfHandle *handle); - -void GetHrtfCoeffs(const HrtfEntry *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat distance, - ALfloat spread, HrirArray &coeffs, ALsizei (&delays)[2]); - -/** - * Produces HRTF filter coefficients for decoding B-Format, given a set of - * virtual speaker positions, a matching decoding matrix, and per-order high- - * frequency gains for the decoder. The calculated impulse responses are - * ordered and scaled according to the matrix input. Note the specified virtual - * positions should be in degrees, not radians! - */ -void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuint NumChannels, - const AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_CHANNELS], - const size_t AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain); - -#endif /* ALC_HRTF_H */ diff --git a/Alc/inprogext.h b/Alc/inprogext.h deleted file mode 100644 index 15881b59..00000000 --- a/Alc/inprogext.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef INPROGEXT_H -#define INPROGEXT_H - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef ALC_SOFT_loopback_bformat -#define ALC_SOFT_loopback_bformat 1 -#define ALC_AMBISONIC_LAYOUT_SOFT 0x1997 -#define ALC_AMBISONIC_SCALING_SOFT 0x1998 -#define ALC_AMBISONIC_ORDER_SOFT 0x1999 -#define ALC_MAX_AMBISONIC_ORDER_SOFT 0x199B - -#define ALC_BFORMAT3D_SOFT 0x1508 - -/* Ambisonic layouts */ -#define ALC_FUMA_SOFT 0x0000 -#define ALC_ACN_SOFT 0x0001 - -/* Ambisonic scalings (normalization) */ -/*#define ALC_FUMA_SOFT*/ -#define ALC_SN3D_SOFT 0x0001 -#define ALC_N3D_SOFT 0x0002 -#endif - -#ifndef AL_SOFT_map_buffer -#define AL_SOFT_map_buffer 1 -typedef unsigned int ALbitfieldSOFT; -#define AL_MAP_READ_BIT_SOFT 0x00000001 -#define AL_MAP_WRITE_BIT_SOFT 0x00000002 -#define AL_MAP_PERSISTENT_BIT_SOFT 0x00000004 -#define AL_PRESERVE_DATA_BIT_SOFT 0x00000008 -typedef void (AL_APIENTRY*LPALBUFFERSTORAGESOFT)(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags); -typedef void* (AL_APIENTRY*LPALMAPBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); -typedef void (AL_APIENTRY*LPALUNMAPBUFFERSOFT)(ALuint buffer); -typedef void (AL_APIENTRY*LPALFLUSHMAPPEDBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length); -#ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags); -AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); -AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer); -AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length); -#endif -#endif - -#ifndef AL_SOFT_events -#define AL_SOFT_events 1 -#define AL_EVENT_CALLBACK_FUNCTION_SOFT 0x1220 -#define AL_EVENT_CALLBACK_USER_PARAM_SOFT 0x1221 -#define AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT 0x1222 -#define AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT 0x1223 -#define AL_EVENT_TYPE_ERROR_SOFT 0x1224 -#define AL_EVENT_TYPE_PERFORMANCE_SOFT 0x1225 -#define AL_EVENT_TYPE_DEPRECATED_SOFT 0x1226 -#define AL_EVENT_TYPE_DISCONNECTED_SOFT 0x1227 -typedef void (AL_APIENTRY*ALEVENTPROCSOFT)(ALenum eventType, ALuint object, ALuint param, - ALsizei length, const ALchar *message, - void *userParam); -typedef void (AL_APIENTRY*LPALEVENTCONTROLSOFT)(ALsizei count, const ALenum *types, ALboolean enable); -typedef void (AL_APIENTRY*LPALEVENTCALLBACKSOFT)(ALEVENTPROCSOFT callback, void *userParam); -typedef void* (AL_APIENTRY*LPALGETPOINTERSOFT)(ALenum pname); -typedef void (AL_APIENTRY*LPALGETPOINTERVSOFT)(ALenum pname, void **values); -#ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable); -AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam); -AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname); -AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values); -#endif -#endif - -#ifndef AL_SOFT_buffer_layers -#define AL_SOFT_buffer_layers -typedef void (AL_APIENTRY*LPALSOURCEQUEUEBUFFERLAYERSSOFT)(ALuint src, ALsizei nb, const ALuint *buffers); -#ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers); -#endif -#endif - -#ifndef AL_SOFT_effect_chain -#define AL_SOFT_effect_chain -#define AL_EFFECTSLOT_TARGET_SOFT 0xf000 -#endif - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* INPROGEXT_H */ diff --git a/Alc/logging.h b/Alc/logging.h deleted file mode 100644 index 0bb0c87b..00000000 --- a/Alc/logging.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef LOGGING_H -#define LOGGING_H - -#include - -#include "opthelpers.h" - - -#ifdef __GNUC__ -#define DECL_FORMAT(x, y, z) __attribute__((format(x, (y), (z)))) -#else -#define DECL_FORMAT(x, y, z) -#endif - - -extern FILE *gLogFile; - -void al_print(FILE *logfile, const char *fmt, ...) DECL_FORMAT(printf, 2,3); -#if !defined(_WIN32) -#define AL_PRINT(T, ...) fprintf(gLogFile, "AL lib: " T " " __VA_ARGS__) -#else -#define AL_PRINT(T, ...) al_print(gLogFile, "AL lib: " T " " __VA_ARGS__) -#endif - -#ifdef __ANDROID__ -#include -#define LOG_ANDROID(T, ...) __android_log_print(T, "openal", "AL lib: " __VA_ARGS__) -#else -#define LOG_ANDROID(T, ...) ((void)0) -#endif - -enum LogLevel { - NoLog, - LogError, - LogWarning, - LogTrace, - LogRef -}; -extern LogLevel gLogLevel; - -#define TRACEREF(...) do { \ - if(UNLIKELY(gLogLevel >= LogRef)) \ - AL_PRINT("(--)", __VA_ARGS__); \ -} while(0) - -#define TRACE(...) do { \ - if(UNLIKELY(gLogLevel >= LogTrace)) \ - AL_PRINT("(II)", __VA_ARGS__); \ - LOG_ANDROID(ANDROID_LOG_DEBUG, __VA_ARGS__); \ -} while(0) - -#define WARN(...) do { \ - if(UNLIKELY(gLogLevel >= LogWarning)) \ - AL_PRINT("(WW)", __VA_ARGS__); \ - LOG_ANDROID(ANDROID_LOG_WARN, __VA_ARGS__); \ -} while(0) - -#define ERR(...) do { \ - if(UNLIKELY(gLogLevel >= LogError)) \ - AL_PRINT("(EE)", __VA_ARGS__); \ - LOG_ANDROID(ANDROID_LOG_ERROR, __VA_ARGS__); \ -} while(0) - -#endif /* LOGGING_H */ diff --git a/Alc/mastering.cpp b/Alc/mastering.cpp deleted file mode 100644 index 551fdcdf..00000000 --- a/Alc/mastering.cpp +++ /dev/null @@ -1,479 +0,0 @@ -#include "config.h" - -#include -#include -#include -#include - -#include "mastering.h" -#include "alu.h" -#include "almalloc.h" -#include "math_defs.h" - - -/* These structures assume BUFFERSIZE is a power of 2. */ -static_assert((BUFFERSIZE & (BUFFERSIZE-1)) == 0, "BUFFERSIZE is not a power of 2"); - -struct SlidingHold { - alignas(16) ALfloat mValues[BUFFERSIZE]; - ALsizei mExpiries[BUFFERSIZE]; - ALsizei mLowerIndex; - ALsizei mUpperIndex; - ALsizei mLength; -}; - - -namespace { - -using namespace std::placeholders; - -/* This sliding hold follows the input level with an instant attack and a - * fixed duration hold before an instant release to the next highest level. - * It is a sliding window maximum (descending maxima) implementation based on - * Richard Harter's ascending minima algorithm available at: - * - * http://www.richardhartersworld.com/cri/2001/slidingmin.html - */ -ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALfloat in) -{ - static constexpr ALsizei mask{BUFFERSIZE - 1}; - const ALsizei length{Hold->mLength}; - ALfloat (&values)[BUFFERSIZE] = Hold->mValues; - ALsizei (&expiries)[BUFFERSIZE] = Hold->mExpiries; - ALsizei lowerIndex{Hold->mLowerIndex}; - ALsizei upperIndex{Hold->mUpperIndex}; - - ASSUME(upperIndex >= 0); - ASSUME(lowerIndex >= 0); - - if(i >= expiries[upperIndex]) - upperIndex = (upperIndex + 1) & mask; - - if(in >= values[upperIndex]) - { - values[upperIndex] = in; - expiries[upperIndex] = i + length; - lowerIndex = upperIndex; - } - else - { - do { - do { - if(!(in >= values[lowerIndex])) - goto found_place; - } while(lowerIndex--); - lowerIndex = mask; - } while(1); - found_place: - - lowerIndex = (lowerIndex + 1) & mask; - values[lowerIndex] = in; - expiries[lowerIndex] = i + length; - } - - Hold->mLowerIndex = lowerIndex; - Hold->mUpperIndex = upperIndex; - - return values[upperIndex]; -} - -void ShiftSlidingHold(SlidingHold *Hold, const ALsizei n) -{ - ASSUME(Hold->mUpperIndex >= 0); - ASSUME(Hold->mLowerIndex >= 0); - - auto exp_begin = std::begin(Hold->mExpiries) + Hold->mUpperIndex; - auto exp_last = std::begin(Hold->mExpiries) + Hold->mLowerIndex; - if(exp_last < exp_begin) - { - std::transform(exp_begin, std::end(Hold->mExpiries), exp_begin, - std::bind(std::minus{}, _1, n)); - exp_begin = std::begin(Hold->mExpiries); - } - std::transform(exp_begin, exp_last+1, exp_begin, std::bind(std::minus{}, _1, n)); -} - - -/* Multichannel compression is linked via the absolute maximum of all - * channels. - */ -void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, const FloatBufferLine *OutBuffer) -{ - const ALsizei index{Comp->mLookAhead}; - const ALuint numChans{Comp->mNumChans}; - - ASSUME(SamplesToDo > 0); - ASSUME(numChans > 0); - ASSUME(index >= 0); - - auto side_begin = std::begin(Comp->mSideChain) + index; - std::fill(side_begin, side_begin+SamplesToDo, 0.0f); - - auto fill_max = [SamplesToDo,side_begin](const FloatBufferLine &input) -> void - { - const ALfloat *RESTRICT buffer{al::assume_aligned<16>(input.data())}; - auto max_abs = std::bind(maxf, _1, std::bind(static_cast(std::fabs), _2)); - std::transform(side_begin, side_begin+SamplesToDo, buffer, side_begin, max_abs); - }; - std::for_each(OutBuffer, OutBuffer+numChans, fill_max); -} - -/* This calculates the squared crest factor of the control signal for the - * basic automation of the attack/release times. As suggested by the paper, - * it uses an instantaneous squared peak detector and a squared RMS detector - * both with 200ms release times. - */ -static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo) -{ - const ALfloat a_crest{Comp->mCrestCoeff}; - const ALsizei index{Comp->mLookAhead}; - ALfloat y2_peak{Comp->mLastPeakSq}; - ALfloat y2_rms{Comp->mLastRmsSq}; - - ASSUME(SamplesToDo > 0); - ASSUME(index >= 0); - - auto calc_crest = [&y2_rms,&y2_peak,a_crest](const ALfloat x_abs) noexcept -> ALfloat - { - ALfloat x2 = maxf(0.000001f, x_abs * x_abs); - - y2_peak = maxf(x2, lerp(x2, y2_peak, a_crest)); - y2_rms = lerp(x2, y2_rms, a_crest); - return y2_peak / y2_rms; - }; - auto side_begin = std::begin(Comp->mSideChain) + index; - std::transform(side_begin, side_begin+SamplesToDo, std::begin(Comp->mCrestFactor), calc_crest); - - Comp->mLastPeakSq = y2_peak; - Comp->mLastRmsSq = y2_rms; -} - -/* The side-chain starts with a simple peak detector (based on the absolute - * value of the incoming signal) and performs most of its operations in the - * log domain. - */ -void PeakDetector(Compressor *Comp, const ALsizei SamplesToDo) -{ - const ALsizei index{Comp->mLookAhead}; - - ASSUME(SamplesToDo > 0); - ASSUME(index >= 0); - - /* Clamp the minimum amplitude to near-zero and convert to logarithm. */ - auto side_begin = std::begin(Comp->mSideChain) + index; - std::transform(side_begin, side_begin+SamplesToDo, side_begin, - std::bind(static_cast(std::log), std::bind(maxf, 0.000001f, _1))); -} - -/* An optional hold can be used to extend the peak detector so it can more - * solidly detect fast transients. This is best used when operating as a - * limiter. - */ -void PeakHoldDetector(Compressor *Comp, const ALsizei SamplesToDo) -{ - const ALsizei index{Comp->mLookAhead}; - - ASSUME(SamplesToDo > 0); - ASSUME(index >= 0); - - SlidingHold *hold{Comp->mHold}; - ALsizei i{0}; - auto detect_peak = [&i,hold](const ALfloat x_abs) -> ALfloat - { - const ALfloat x_G{std::log(maxf(0.000001f, x_abs))}; - return UpdateSlidingHold(hold, i++, x_G); - }; - auto side_begin = std::begin(Comp->mSideChain) + index; - std::transform(side_begin, side_begin+SamplesToDo, side_begin, detect_peak); - - ShiftSlidingHold(hold, SamplesToDo); -} - -/* This is the heart of the feed-forward compressor. It operates in the log - * domain (to better match human hearing) and can apply some basic automation - * to knee width, attack/release times, make-up/post gain, and clipping - * reduction. - */ -void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) -{ - const bool autoKnee{Comp->mAuto.Knee}; - const bool autoAttack{Comp->mAuto.Attack}; - const bool autoRelease{Comp->mAuto.Release}; - const bool autoPostGain{Comp->mAuto.PostGain}; - const bool autoDeclip{Comp->mAuto.Declip}; - const ALsizei lookAhead{Comp->mLookAhead}; - const ALfloat threshold{Comp->mThreshold}; - const ALfloat slope{Comp->mSlope}; - const ALfloat attack{Comp->mAttack}; - const ALfloat release{Comp->mRelease}; - const ALfloat c_est{Comp->mGainEstimate}; - const ALfloat a_adp{Comp->mAdaptCoeff}; - const ALfloat (&crestFactor)[BUFFERSIZE] = Comp->mCrestFactor; - ALfloat (&sideChain)[BUFFERSIZE*2] = Comp->mSideChain; - ALfloat postGain{Comp->mPostGain}; - ALfloat knee{Comp->mKnee}; - ALfloat t_att{attack}; - ALfloat t_rel{release - attack}; - ALfloat a_att{std::exp(-1.0f / t_att)}; - ALfloat a_rel{std::exp(-1.0f / t_rel)}; - ALfloat y_1{Comp->mLastRelease}; - ALfloat y_L{Comp->mLastAttack}; - ALfloat c_dev{Comp->mLastGainDev}; - - ASSUME(SamplesToDo > 0); - ASSUME(lookAhead >= 0); - - for(ALsizei i{0};i < SamplesToDo;i++) - { - if(autoKnee) - knee = maxf(0.0f, 2.5f * (c_dev + c_est)); - const ALfloat knee_h{0.5f * knee}; - - /* This is the gain computer. It applies a static compression curve - * to the control signal. - */ - const ALfloat x_over{sideChain[lookAhead+i] - threshold}; - const ALfloat y_G{ - (x_over <= -knee_h) ? 0.0f : - (std::fabs(x_over) < knee_h) ? (x_over + knee_h) * (x_over + knee_h) / (2.0f * knee) : - x_over - }; - - const ALfloat y2_crest{crestFactor[i]}; - if(autoAttack) - { - t_att = 2.0f*attack/y2_crest; - a_att = std::exp(-1.0f / t_att); - } - if(autoRelease) - { - t_rel = 2.0f*release/y2_crest - t_att; - a_rel = std::exp(-1.0f / t_rel); - } - - /* Gain smoothing (ballistics) is done via a smooth decoupled peak - * detector. The attack time is subtracted from the release time - * above to compensate for the chained operating mode. - */ - const ALfloat x_L{-slope * y_G}; - y_1 = maxf(x_L, lerp(x_L, y_1, a_rel)); - y_L = lerp(y_1, y_L, a_att); - - /* Knee width and make-up gain automation make use of a smoothed - * measurement of deviation between the control signal and estimate. - * The estimate is also used to bias the measurement to hot-start its - * average. - */ - c_dev = lerp(-(y_L+c_est), c_dev, a_adp); - - if(autoPostGain) - { - /* Clipping reduction is only viable when make-up gain is being - * automated. It modifies the deviation to further attenuate the - * control signal when clipping is detected. The adaptation time - * is sufficiently long enough to suppress further clipping at the - * same output level. - */ - if(autoDeclip) - c_dev = maxf(c_dev, sideChain[i] - y_L - threshold - c_est); - - postGain = -(c_dev + c_est); - } - - sideChain[i] = std::exp(postGain - y_L); - } - - Comp->mLastRelease = y_1; - Comp->mLastAttack = y_L; - Comp->mLastGainDev = c_dev; -} - -/* Combined with the hold time, a look-ahead delay can improve handling of - * fast transients by allowing the envelope time to converge prior to - * reaching the offending impulse. This is best used when operating as a - * limiter. - */ -void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, FloatBufferLine *OutBuffer) -{ - const ALuint numChans{Comp->mNumChans}; - const ALsizei lookAhead{Comp->mLookAhead}; - - ASSUME(SamplesToDo > 0); - ASSUME(numChans > 0); - ASSUME(lookAhead > 0); - - for(ALuint c{0};c < numChans;c++) - { - ALfloat *inout{al::assume_aligned<16>(OutBuffer[c].data())}; - ALfloat *delaybuf{al::assume_aligned<16>(Comp->mDelay[c].data())}; - - auto inout_end = inout + SamplesToDo; - if(LIKELY(SamplesToDo >= lookAhead)) - { - auto delay_end = std::rotate(inout, inout_end - lookAhead, inout_end); - std::swap_ranges(inout, delay_end, delaybuf); - } - else - { - auto delay_start = std::swap_ranges(inout, inout_end, delaybuf); - std::rotate(delaybuf, delay_start, delaybuf + lookAhead); - } - } -} - -} // namespace - -/* The compressor is initialized with the following settings: - * - * NumChans - Number of channels to process. - * SampleRate - Sample rate to process. - * AutoKnee - Whether to automate the knee width parameter. - * AutoAttack - Whether to automate the attack time parameter. - * AutoRelease - Whether to automate the release time parameter. - * AutoPostGain - Whether to automate the make-up (post) gain parameter. - * AutoDeclip - Whether to automate clipping reduction. Ignored when - * not automating make-up gain. - * LookAheadTime - Look-ahead time (in seconds). - * HoldTime - Peak hold-time (in seconds). - * PreGainDb - Gain applied before detection (in dB). - * PostGainDb - Make-up gain applied after compression (in dB). - * ThresholdDb - Triggering threshold (in dB). - * Ratio - Compression ratio (x:1). Set to INFINITY for true - * limiting. Ignored when automating knee width. - * KneeDb - Knee width (in dB). Ignored when automating knee - * width. - * AttackTimeMin - Attack time (in seconds). Acts as a maximum when - * automating attack time. - * ReleaseTimeMin - Release time (in seconds). Acts as a maximum when - * automating release time. - */ -std::unique_ptr CompressorInit(const ALuint NumChans, const ALuint SampleRate, - const ALboolean AutoKnee, const ALboolean AutoAttack, const ALboolean AutoRelease, - const ALboolean AutoPostGain, const ALboolean AutoDeclip, const ALfloat LookAheadTime, - const ALfloat HoldTime, const ALfloat PreGainDb, const ALfloat PostGainDb, - const ALfloat ThresholdDb, const ALfloat Ratio, const ALfloat KneeDb, const ALfloat AttackTime, - const ALfloat ReleaseTime) -{ - const auto lookAhead = static_cast( - clampf(std::round(LookAheadTime*SampleRate), 0.0f, BUFFERSIZE-1)); - const auto hold = static_cast( - clampf(std::round(HoldTime*SampleRate), 0.0f, BUFFERSIZE-1)); - - size_t size{sizeof(Compressor)}; - if(lookAhead > 0) - { - size += sizeof(*Compressor::mDelay) * NumChans; - /* The sliding hold implementation doesn't handle a length of 1. A 1- - * sample hold is useless anyway, it would only ever give back what was - * just given to it. - */ - if(hold > 1) - size += sizeof(*Compressor::mHold); - } - - auto Comp = std::unique_ptr{new (al_calloc(16, size)) Compressor{}}; - Comp->mNumChans = NumChans; - Comp->mSampleRate = SampleRate; - Comp->mAuto.Knee = AutoKnee != AL_FALSE; - Comp->mAuto.Attack = AutoAttack != AL_FALSE; - Comp->mAuto.Release = AutoRelease != AL_FALSE; - Comp->mAuto.PostGain = AutoPostGain != AL_FALSE; - Comp->mAuto.Declip = AutoPostGain && AutoDeclip; - Comp->mLookAhead = lookAhead; - Comp->mPreGain = std::pow(10.0f, PreGainDb / 20.0f); - Comp->mPostGain = PostGainDb * std::log(10.0f) / 20.0f; - Comp->mThreshold = ThresholdDb * std::log(10.0f) / 20.0f; - Comp->mSlope = 1.0f / maxf(1.0f, Ratio) - 1.0f; - Comp->mKnee = maxf(0.0f, KneeDb * std::log(10.0f) / 20.0f); - Comp->mAttack = maxf(1.0f, AttackTime * SampleRate); - Comp->mRelease = maxf(1.0f, ReleaseTime * SampleRate); - - /* Knee width automation actually treats the compressor as a limiter. By - * varying the knee width, it can effectively be seen as applying - * compression over a wide range of ratios. - */ - if(AutoKnee) - Comp->mSlope = -1.0f; - - if(lookAhead > 0) - { - if(hold > 1) - { - Comp->mHold = ::new (static_cast(Comp.get() + 1)) SlidingHold{}; - Comp->mHold->mValues[0] = -std::numeric_limits::infinity(); - Comp->mHold->mExpiries[0] = hold; - Comp->mHold->mLength = hold; - Comp->mDelay = ::new (static_cast(Comp->mHold + 1)) FloatBufferLine[NumChans]; - } - else - { - Comp->mDelay = ::new (static_cast(Comp.get() + 1)) FloatBufferLine[NumChans]; - } - } - - Comp->mCrestCoeff = std::exp(-1.0f / (0.200f * SampleRate)); // 200ms - Comp->mGainEstimate = Comp->mThreshold * -0.5f * Comp->mSlope; - Comp->mAdaptCoeff = std::exp(-1.0f / (2.0f * SampleRate)); // 2s - - return Comp; -} - -Compressor::~Compressor() -{ - if(mHold) - al::destroy_at(mHold); - mHold = nullptr; - if(mDelay) - al::destroy_n(mDelay, mNumChans); - mDelay = nullptr; -} - - -void Compressor::process(const ALsizei SamplesToDo, FloatBufferLine *OutBuffer) -{ - const ALuint numChans{mNumChans}; - - ASSUME(SamplesToDo > 0); - ASSUME(numChans > 0); - - const ALfloat preGain{mPreGain}; - if(preGain != 1.0f) - { - auto apply_gain = [SamplesToDo,preGain](FloatBufferLine &input) noexcept -> void - { - ALfloat *buffer{al::assume_aligned<16>(input.data())}; - std::transform(buffer, buffer+SamplesToDo, buffer, - std::bind(std::multiplies{}, _1, preGain)); - }; - std::for_each(OutBuffer, OutBuffer+numChans, apply_gain); - } - - LinkChannels(this, SamplesToDo, OutBuffer); - - if(mAuto.Attack || mAuto.Release) - CrestDetector(this, SamplesToDo); - - if(mHold) - PeakHoldDetector(this, SamplesToDo); - else - PeakDetector(this, SamplesToDo); - - GainCompressor(this, SamplesToDo); - - if(mDelay) - SignalDelay(this, SamplesToDo, OutBuffer); - - const ALfloat (&sideChain)[BUFFERSIZE*2] = mSideChain; - auto apply_comp = [SamplesToDo,&sideChain](FloatBufferLine &input) noexcept -> void - { - ALfloat *buffer{al::assume_aligned<16>(input.data())}; - const ALfloat *gains{al::assume_aligned<16>(&sideChain[0])}; - std::transform(gains, gains+SamplesToDo, buffer, buffer, - std::bind(std::multiplies{}, _1, _2)); - }; - std::for_each(OutBuffer, OutBuffer+numChans, apply_comp); - - ASSUME(mLookAhead >= 0); - auto side_begin = std::begin(mSideChain) + SamplesToDo; - std::copy(side_begin, side_begin+mLookAhead, std::begin(mSideChain)); -} diff --git a/Alc/mastering.h b/Alc/mastering.h deleted file mode 100644 index 34dc8dcb..00000000 --- a/Alc/mastering.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef MASTERING_H -#define MASTERING_H - -#include - -#include "AL/al.h" - -#include "almalloc.h" -/* For FloatBufferLine/BUFFERSIZE. */ -#include "alcmain.h" - - -struct SlidingHold; - -/* General topology and basic automation was based on the following paper: - * - * D. Giannoulis, M. Massberg and J. D. Reiss, - * "Parameter Automation in a Dynamic Range Compressor," - * Journal of the Audio Engineering Society, v61 (10), Oct. 2013 - * - * Available (along with supplemental reading) at: - * - * http://c4dm.eecs.qmul.ac.uk/audioengineering/compressors/ - */ -struct Compressor { - ALuint mNumChans{0u}; - ALuint mSampleRate{0u}; - - struct { - bool Knee : 1; - bool Attack : 1; - bool Release : 1; - bool PostGain : 1; - bool Declip : 1; - } mAuto{}; - - ALsizei mLookAhead{0}; - - ALfloat mPreGain{0.0f}; - ALfloat mPostGain{0.0f}; - - ALfloat mThreshold{0.0f}; - ALfloat mSlope{0.0f}; - ALfloat mKnee{0.0f}; - - ALfloat mAttack{0.0f}; - ALfloat mRelease{0.0f}; - - alignas(16) ALfloat mSideChain[2*BUFFERSIZE]{}; - alignas(16) ALfloat mCrestFactor[BUFFERSIZE]{}; - - SlidingHold *mHold{nullptr}; - FloatBufferLine *mDelay{nullptr}; - - ALfloat mCrestCoeff{0.0f}; - ALfloat mGainEstimate{0.0f}; - ALfloat mAdaptCoeff{0.0f}; - - ALfloat mLastPeakSq{0.0f}; - ALfloat mLastRmsSq{0.0f}; - ALfloat mLastRelease{0.0f}; - ALfloat mLastAttack{0.0f}; - ALfloat mLastGainDev{0.0f}; - - - ~Compressor(); - void process(const ALsizei SamplesToDo, FloatBufferLine *OutBuffer); - ALsizei getLookAhead() const noexcept { return mLookAhead; } - - DEF_PLACE_NEWDEL() -}; - -/* The compressor is initialized with the following settings: - * - * NumChans - Number of channels to process. - * SampleRate - Sample rate to process. - * AutoKnee - Whether to automate the knee width parameter. - * AutoAttack - Whether to automate the attack time parameter. - * AutoRelease - Whether to automate the release time parameter. - * AutoPostGain - Whether to automate the make-up (post) gain parameter. - * AutoDeclip - Whether to automate clipping reduction. Ignored when - * not automating make-up gain. - * LookAheadTime - Look-ahead time (in seconds). - * HoldTime - Peak hold-time (in seconds). - * PreGainDb - Gain applied before detection (in dB). - * PostGainDb - Make-up gain applied after compression (in dB). - * ThresholdDb - Triggering threshold (in dB). - * Ratio - Compression ratio (x:1). Set to INFINIFTY for true - * limiting. Ignored when automating knee width. - * KneeDb - Knee width (in dB). Ignored when automating knee - * width. - * AttackTimeMin - Attack time (in seconds). Acts as a maximum when - * automating attack time. - * ReleaseTimeMin - Release time (in seconds). Acts as a maximum when - * automating release time. - */ -std::unique_ptr CompressorInit(const ALuint NumChans, const ALuint SampleRate, - const ALboolean AutoKnee, const ALboolean AutoAttack, const ALboolean AutoRelease, - const ALboolean AutoPostGain, const ALboolean AutoDeclip, const ALfloat LookAheadTime, - const ALfloat HoldTime, const ALfloat PreGainDb, const ALfloat PostGainDb, - const ALfloat ThresholdDb, const ALfloat Ratio, const ALfloat KneeDb, const ALfloat AttackTime, - const ALfloat ReleaseTime); - -#endif /* MASTERING_H */ diff --git a/Alc/mixer/defs.h b/Alc/mixer/defs.h deleted file mode 100644 index 3e5d1125..00000000 --- a/Alc/mixer/defs.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef MIXER_DEFS_H -#define MIXER_DEFS_H - -#include "AL/alc.h" -#include "AL/al.h" - -#include "alcmain.h" -#include "alu.h" -#include "alspan.h" - - -struct MixGains; -struct MixHrtfFilter; -struct HrtfState; -struct DirectHrtfState; - - -struct CTag { }; -struct SSETag { }; -struct SSE2Tag { }; -struct SSE3Tag { }; -struct SSE4Tag { }; -struct NEONTag { }; - -struct CopyTag { }; -struct PointTag { }; -struct LerpTag { }; -struct CubicTag { }; -struct BSincTag { }; - -template -const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen); - -template -void Mix_(const ALfloat *data, const al::span OutBuffer, ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize); -template -void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize); - -template -void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfFilter *hrtfparams, const ALsizei BufferSize); -template -void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize); -template -void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, const ALsizei BufferSize); - -/* Vectorized resampler helpers */ -inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *RESTRICT frac_arr, ALsizei *RESTRICT pos_arr, ALsizei size) -{ - pos_arr[0] = 0; - frac_arr[0] = frac; - for(ALsizei i{1};i < size;i++) - { - ALint frac_tmp = frac_arr[i-1] + increment; - pos_arr[i] = pos_arr[i-1] + (frac_tmp>>FRACTIONBITS); - frac_arr[i] = frac_tmp&FRACTIONMASK; - } -} - -#endif /* MIXER_DEFS_H */ diff --git a/Alc/mixer/hrtfbase.h b/Alc/mixer/hrtfbase.h deleted file mode 100644 index a76bd62e..00000000 --- a/Alc/mixer/hrtfbase.h +++ /dev/null @@ -1,138 +0,0 @@ -#ifndef MIXER_HRTFBASE_H -#define MIXER_HRTFBASE_H - -#include - -#include "alu.h" -#include "../hrtf.h" -#include "opthelpers.h" - - -using ApplyCoeffsT = void(ALsizei Offset, float2 *RESTRICT Values, const ALsizei irSize, - const HrirArray &Coeffs, const ALfloat left, const ALfloat right); - -template -inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *RESTRICT AccumSamples, const ALsizei OutPos, - const ALsizei IrSize, MixHrtfFilter *hrtfparams, const ALsizei BufferSize) -{ - ASSUME(OutPos >= 0); - ASSUME(IrSize >= 4); - ASSUME(BufferSize > 0); - - const auto &Coeffs = *hrtfparams->Coeffs; - const ALfloat gainstep{hrtfparams->GainStep}; - const ALfloat gain{hrtfparams->Gain}; - - ALsizei Delay[2]{ - HRTF_HISTORY_LENGTH - hrtfparams->Delay[0], - HRTF_HISTORY_LENGTH - hrtfparams->Delay[1] }; - ASSUME(Delay[0] >= 0 && Delay[1] >= 0); - ALfloat stepcount{0.0f}; - for(ALsizei i{0};i < BufferSize;++i) - { - const ALfloat g{gain + gainstep*stepcount}; - const ALfloat left{InSamples[Delay[0]++] * g}; - const ALfloat right{InSamples[Delay[1]++] * g}; - ApplyCoeffs(i, AccumSamples+i, IrSize, Coeffs, left, right); - - stepcount += 1.0f; - } - - for(ALsizei i{0};i < BufferSize;++i) - LeftOut[OutPos+i] += AccumSamples[i][0]; - for(ALsizei i{0};i < BufferSize;++i) - RightOut[OutPos+i] += AccumSamples[i][1]; - - hrtfparams->Gain = gain + gainstep*stepcount; -} - -template -inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *RESTRICT AccumSamples, const ALsizei OutPos, - const ALsizei IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, - const ALsizei BufferSize) -{ - const auto &OldCoeffs = oldparams->Coeffs; - const ALfloat oldGain{oldparams->Gain}; - const ALfloat oldGainStep{-oldGain / static_cast(BufferSize)}; - const auto &NewCoeffs = *newparams->Coeffs; - const ALfloat newGainStep{newparams->GainStep}; - - ASSUME(OutPos >= 0); - ASSUME(IrSize >= 4); - ASSUME(BufferSize > 0); - - ALsizei Delay[2]{ - HRTF_HISTORY_LENGTH - oldparams->Delay[0], - HRTF_HISTORY_LENGTH - oldparams->Delay[1] }; - ASSUME(Delay[0] >= 0 && Delay[1] >= 0); - ALfloat stepcount{0.0f}; - for(ALsizei i{0};i < BufferSize;++i) - { - const ALfloat g{oldGain + oldGainStep*stepcount}; - const ALfloat left{InSamples[Delay[0]++] * g}; - const ALfloat right{InSamples[Delay[1]++] * g}; - ApplyCoeffs(i, AccumSamples+i, IrSize, OldCoeffs, left, right); - - stepcount += 1.0f; - } - - Delay[0] = HRTF_HISTORY_LENGTH - newparams->Delay[0]; - Delay[1] = HRTF_HISTORY_LENGTH - newparams->Delay[1]; - ASSUME(Delay[0] >= 0 && Delay[1] >= 0); - stepcount = 0.0f; - for(ALsizei i{0};i < BufferSize;++i) - { - const ALfloat g{newGainStep*stepcount}; - const ALfloat left{InSamples[Delay[0]++] * g}; - const ALfloat right{InSamples[Delay[1]++] * g}; - ApplyCoeffs(i, AccumSamples+i, IrSize, NewCoeffs, left, right); - - stepcount += 1.0f; - } - - for(ALsizei i{0};i < BufferSize;++i) - LeftOut[OutPos+i] += AccumSamples[i][0]; - for(ALsizei i{0};i < BufferSize;++i) - RightOut[OutPos+i] += AccumSamples[i][1]; - - newparams->Gain = newGainStep*stepcount; -} - -template -inline void MixDirectHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const al::span InSamples, float2 *RESTRICT AccumSamples, - DirectHrtfState *State, const ALsizei BufferSize) -{ - ASSUME(BufferSize > 0); - - const ALsizei IrSize{State->IrSize}; - ASSUME(IrSize >= 4); - - auto chanstate = State->Chan.begin(); - for(const FloatBufferLine &input : InSamples) - { - const auto &Coeffs = chanstate->Coeffs; - - auto accum_iter = std::copy_n(chanstate->Values.begin(), - chanstate->Values.size(), AccumSamples); - std::fill_n(accum_iter, BufferSize, float2{}); - - for(ALsizei i{0};i < BufferSize;++i) - { - const ALfloat insample{input[i]}; - ApplyCoeffs(i, AccumSamples+i, IrSize, Coeffs, insample, insample); - } - for(ALsizei i{0};i < BufferSize;++i) - LeftOut[i] += AccumSamples[i][0]; - for(ALsizei i{0};i < BufferSize;++i) - RightOut[i] += AccumSamples[i][1]; - - std::copy_n(AccumSamples + BufferSize, chanstate->Values.size(), - chanstate->Values.begin()); - ++chanstate; - } -} - -#endif /* MIXER_HRTFBASE_H */ diff --git a/Alc/mixer/mixer_c.cpp b/Alc/mixer/mixer_c.cpp deleted file mode 100644 index 47c4a6f4..00000000 --- a/Alc/mixer/mixer_c.cpp +++ /dev/null @@ -1,208 +0,0 @@ -#include "config.h" - -#include - -#include - -#include "alcmain.h" -#include "alu.h" -#include "alSource.h" -#include "alAuxEffectSlot.h" -#include "defs.h" -#include "hrtfbase.h" - - -namespace { - -inline ALfloat do_point(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei) -{ return vals[0]; } -inline ALfloat do_lerp(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei frac) -{ return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); } -inline ALfloat do_cubic(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei frac) -{ return cubic(vals[0], vals[1], vals[2], vals[3], frac * (1.0f/FRACTIONONE)); } -inline ALfloat do_bsinc(const InterpState &istate, const ALfloat *RESTRICT vals, const ALsizei frac) -{ - ASSUME(istate.bsinc.m > 0); - - // Calculate the phase index and factor. -#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) - const ALsizei pi{frac >> FRAC_PHASE_BITDIFF}; - const ALfloat pf{(frac & ((1< -const ALfloat *DoResample(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei numsamples) -{ - ASSUME(numsamples > 0); - ASSUME(increment > 0); - ASSUME(frac >= 0); - - const InterpState istate{*state}; - auto proc_sample = [&src,&frac,istate,increment]() -> ALfloat - { - const ALfloat ret{Sampler(istate, src, frac)}; - - frac += increment; - src += frac>>FRACTIONBITS; - frac &= FRACTIONMASK; - - return ret; - }; - std::generate_n(dst, numsamples, proc_sample); - - return dst; -} - -} // namespace - -template<> -const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, ALsizei, - ALint, ALfloat *RESTRICT dst, ALsizei dstlen) -{ - ASSUME(dstlen > 0); -#if defined(HAVE_SSE) || defined(HAVE_NEON) - /* Avoid copying the source data if it's aligned like the destination. */ - if((reinterpret_cast(src)&15) == (reinterpret_cast(dst)&15)) - return src; -#endif - std::copy_n(src, dstlen, dst); - return dst; -} - -template<> -const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) -{ return DoResample(state, src, frac, increment, dst, dstlen); } - -template<> -const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) -{ return DoResample(state, src, frac, increment, dst, dstlen); } - -template<> -const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) -{ return DoResample(state, src-1, frac, increment, dst, dstlen); } - -template<> -const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) -{ return DoResample(state, src-state->bsinc.l, frac, increment, dst, dstlen); } - - -static inline void ApplyCoeffs(ALsizei /*Offset*/, float2 *RESTRICT Values, const ALsizei IrSize, - const HrirArray &Coeffs, const ALfloat left, const ALfloat right) -{ - ASSUME(IrSize >= 2); - for(ALsizei c{0};c < IrSize;++c) - { - Values[c][0] += Coeffs[c][0] * left; - Values[c][1] += Coeffs[c][1] * right; - } -} - -template<> -void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - MixHrtfFilter *hrtfparams, const ALsizei BufferSize) -{ - MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, - hrtfparams, BufferSize); -} - -template<> -void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize) -{ - MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, - oldparams, newparams, BufferSize); -} - -template<> -void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, - const ALsizei BufferSize) -{ - MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, BufferSize); -} - - -template<> -void Mix_(const ALfloat *data, const al::span OutBuffer, - ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, - const ALsizei BufferSize) -{ - ASSUME(BufferSize > 0); - - const ALfloat delta{(Counter > 0) ? 1.0f / static_cast(Counter) : 0.0f}; - for(FloatBufferLine &output : OutBuffer) - { - ALfloat *RESTRICT dst{output.data()+OutPos}; - ALfloat gain{*CurrentGains}; - const ALfloat diff{*TargetGains - gain}; - - ALsizei pos{0}; - if(std::fabs(diff) > std::numeric_limits::epsilon()) - { - ALsizei minsize{mini(BufferSize, Counter)}; - const ALfloat step{diff * delta}; - ALfloat step_count{0.0f}; - for(;pos < minsize;pos++) - { - dst[pos] += data[pos] * (gain + step*step_count); - step_count += 1.0f; - } - if(pos == Counter) - gain = *TargetGains; - else - gain += step*step_count; - *CurrentGains = gain; - } - ++CurrentGains; - ++TargetGains; - - if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - for(;pos < BufferSize;pos++) - dst[pos] += data[pos]*gain; - } -} - -/* Basically the inverse of the above. Rather than one input going to multiple - * outputs (each with its own gain), it's multiple inputs (each with its own - * gain) going to one output. This applies one row (vs one column) of a matrix - * transform. And as the matrices are more or less static once set up, no - * stepping is necessary. - */ -template<> -void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, - const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize) -{ - ASSUME(BufferSize > 0); - - for(const FloatBufferLine &input : InSamples) - { - const ALfloat *RESTRICT src{input.data()+InPos}; - const ALfloat gain{*(Gains++)}; - if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - for(ALsizei i{0};i < BufferSize;i++) - OutBuffer[i] += src[i] * gain; - } -} diff --git a/Alc/mixer/mixer_neon.cpp b/Alc/mixer/mixer_neon.cpp deleted file mode 100644 index fa487d97..00000000 --- a/Alc/mixer/mixer_neon.cpp +++ /dev/null @@ -1,307 +0,0 @@ -#include "config.h" - -#include - -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "alcmain.h" -#include "alu.h" -#include "hrtf.h" -#include "defs.h" -#include "hrtfbase.h" - - - -template<> -const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) -{ - const int32x4_t increment4 = vdupq_n_s32(increment*4); - const float32x4_t fracOne4 = vdupq_n_f32(1.0f/FRACTIONONE); - const int32x4_t fracMask4 = vdupq_n_s32(FRACTIONMASK); - alignas(16) ALsizei pos_[4], frac_[4]; - int32x4_t pos4, frac4; - ALsizei todo, pos, i; - - ASSUME(frac >= 0); - ASSUME(increment > 0); - ASSUME(dstlen > 0); - - InitiatePositionArrays(frac, increment, frac_, pos_, 4); - frac4 = vld1q_s32(frac_); - pos4 = vld1q_s32(pos_); - - todo = dstlen & ~3; - for(i = 0;i < todo;i += 4) - { - const int pos0 = vgetq_lane_s32(pos4, 0); - const int pos1 = vgetq_lane_s32(pos4, 1); - const int pos2 = vgetq_lane_s32(pos4, 2); - const int pos3 = vgetq_lane_s32(pos4, 3); - const float32x4_t val1 = (float32x4_t){src[pos0], src[pos1], src[pos2], src[pos3]}; - const float32x4_t val2 = (float32x4_t){src[pos0+1], src[pos1+1], src[pos2+1], src[pos3+1]}; - - /* val1 + (val2-val1)*mu */ - const float32x4_t r0 = vsubq_f32(val2, val1); - const float32x4_t mu = vmulq_f32(vcvtq_f32_s32(frac4), fracOne4); - const float32x4_t out = vmlaq_f32(val1, mu, r0); - - vst1q_f32(&dst[i], out); - - frac4 = vaddq_s32(frac4, increment4); - pos4 = vaddq_s32(pos4, vshrq_n_s32(frac4, FRACTIONBITS)); - frac4 = vandq_s32(frac4, fracMask4); - } - - /* NOTE: These four elements represent the position *after* the last four - * samples, so the lowest element is the next position to resample. - */ - pos = vgetq_lane_s32(pos4, 0); - frac = vgetq_lane_s32(frac4, 0); - - for(;i < dstlen;++i) - { - dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); - - frac += increment; - pos += frac>>FRACTIONBITS; - frac &= FRACTIONMASK; - } - return dst; -} - -template<> -const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) -{ - const ALfloat *const filter = state->bsinc.filter; - const float32x4_t sf4 = vdupq_n_f32(state->bsinc.sf); - const ALsizei m = state->bsinc.m; - const float32x4_t *fil, *scd, *phd, *spd; - ALsizei pi, i, j, offset; - float32x4_t r4; - ALfloat pf; - - ASSUME(m > 0); - ASSUME(dstlen > 0); - ASSUME(increment > 0); - ASSUME(frac >= 0); - - src -= state->bsinc.l; - for(i = 0;i < dstlen;i++) - { - // Calculate the phase index and factor. -#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) - pi = frac >> FRAC_PHASE_BITDIFF; - pf = (frac & ((1<> 2; - const float32x4_t pf4 = vdupq_n_f32(pf); - - ASSUME(count > 0); - - for(j = 0;j < count;j++) - { - /* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */ - const float32x4_t f4 = vmlaq_f32( - vmlaq_f32(fil[j], sf4, scd[j]), - pf4, vmlaq_f32(phd[j], sf4, spd[j]) - ); - /* r += f*src */ - r4 = vmlaq_f32(r4, f4, vld1q_f32(&src[j*4])); - } - } - r4 = vaddq_f32(r4, vcombine_f32(vrev64_f32(vget_high_f32(r4)), - vrev64_f32(vget_low_f32(r4)))); - dst[i] = vget_lane_f32(vadd_f32(vget_low_f32(r4), vget_high_f32(r4)), 0); - - frac += increment; - src += frac>>FRACTIONBITS; - frac &= FRACTIONMASK; - } - return dst; -} - - -static inline void ApplyCoeffs(ALsizei /*Offset*/, float2 *RESTRICT Values, const ALsizei IrSize, - const HrirArray &Coeffs, const ALfloat left, const ALfloat right) -{ - ASSUME(IrSize >= 2); - - 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(ALsizei c{0};c < IrSize;c += 2) - { - float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[c ][0]), - vld1_f32((float32_t*)&Values[c+1][0])); - float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]); - - vals = vmlaq_f32(vals, coefs, leftright4); - - vst1_f32((float32_t*)&Values[c ][0], vget_low_f32(vals)); - vst1_f32((float32_t*)&Values[c+1][0], vget_high_f32(vals)); - } -} - -template<> -void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - MixHrtfFilter *hrtfparams, const ALsizei BufferSize) -{ - MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, - hrtfparams, BufferSize); -} - -template<> -void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize) -{ - MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, - oldparams, newparams, BufferSize); -} - -template<> -void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, - const ALsizei BufferSize) -{ - MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, BufferSize); -} - - -template<> -void Mix_(const ALfloat *data, const al::span OutBuffer, - ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, - const ALsizei BufferSize) -{ - ASSUME(BufferSize > 0); - - const ALfloat delta{(Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f}; - for(FloatBufferLine &output : OutBuffer) - { - ALfloat *RESTRICT dst{al::assume_aligned<16>(output.data()+OutPos)}; - ALfloat gain{*CurrentGains}; - const ALfloat diff{*TargetGains - gain}; - - ALsizei pos{0}; - if(std::fabs(diff) > std::numeric_limits::epsilon()) - { - ALsizei minsize{mini(BufferSize, Counter)}; - const ALfloat step{diff * delta}; - ALfloat step_count{0.0f}; - /* Mix with applying gain steps in aligned multiples of 4. */ - if(LIKELY(minsize > 3)) - { - const float32x4_t four4{vdupq_n_f32(4.0f)}; - const float32x4_t step4{vdupq_n_f32(step)}; - const float32x4_t gain4{vdupq_n_f32(gain)}; - float32x4_t step_count4{vsetq_lane_f32(0.0f, - vsetq_lane_f32(1.0f, - vsetq_lane_f32(2.0f, - vsetq_lane_f32(3.0f, vdupq_n_f32(0.0f), 3), - 2), 1), 0 - )}; - ALsizei todo{minsize >> 2}; - - do { - const float32x4_t val4 = vld1q_f32(&data[pos]); - float32x4_t dry4 = vld1q_f32(&dst[pos]); - dry4 = vmlaq_f32(dry4, val4, vmlaq_f32(gain4, step4, step_count4)); - step_count4 = vaddq_f32(step_count4, four4); - vst1q_f32(&dst[pos], dry4); - pos += 4; - } while(--todo); - /* NOTE: step_count4 now represents the next four counts after - * the last four mixed samples, so the lowest element - * represents the next step count to apply. - */ - step_count = vgetq_lane_f32(step_count4, 0); - } - /* Mix with applying left over gain steps that aren't aligned multiples of 4. */ - for(;pos < minsize;pos++) - { - dst[pos] += data[pos]*(gain + step*step_count); - step_count += 1.0f; - } - if(pos == Counter) - gain = *TargetGains; - else - gain += step*step_count; - *CurrentGains = gain; - - /* Mix until pos is aligned with 4 or the mix is done. */ - minsize = mini(BufferSize, (pos+3)&~3); - for(;pos < minsize;pos++) - dst[pos] += data[pos]*gain; - } - ++CurrentGains; - ++TargetGains; - - if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - if(LIKELY(BufferSize-pos > 3)) - { - ALsizei todo{(BufferSize-pos) >> 2}; - const float32x4_t gain4 = vdupq_n_f32(gain); - do { - const float32x4_t val4 = vld1q_f32(&data[pos]); - float32x4_t dry4 = vld1q_f32(&dst[pos]); - dry4 = vmlaq_f32(dry4, val4, gain4); - vst1q_f32(&dst[pos], dry4); - pos += 4; - } while(--todo); - } - for(;pos < BufferSize;pos++) - dst[pos] += data[pos]*gain; - } -} - -template<> -void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, - const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize) -{ - ASSUME(BufferSize > 0); - - for(const FloatBufferLine &input : InSamples) - { - const ALfloat *RESTRICT src{al::assume_aligned<16>(input.data()+InPos)}; - const ALfloat gain{*(Gains++)}; - if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - ALsizei pos{0}; - if(LIKELY(BufferSize > 3)) - { - ALsizei todo{BufferSize >> 2}; - float32x4_t gain4{vdupq_n_f32(gain)}; - do { - const float32x4_t val4 = vld1q_f32(&src[pos]); - float32x4_t dry4 = vld1q_f32(&OutBuffer[pos]); - dry4 = vmlaq_f32(dry4, val4, gain4); - vst1q_f32(&OutBuffer[pos], dry4); - pos += 4; - } while(--todo); - } - for(;pos < BufferSize;pos++) - OutBuffer[pos] += src[pos]*gain; - } -} diff --git a/Alc/mixer/mixer_sse.cpp b/Alc/mixer/mixer_sse.cpp deleted file mode 100644 index b763fdbd..00000000 --- a/Alc/mixer/mixer_sse.cpp +++ /dev/null @@ -1,262 +0,0 @@ -#include "config.h" - -#include - -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "alcmain.h" -#include "alu.h" - -#include "alSource.h" -#include "alAuxEffectSlot.h" -#include "defs.h" -#include "hrtfbase.h" - - -template<> -const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) -{ - const ALfloat *const filter{state->bsinc.filter}; - const __m128 sf4{_mm_set1_ps(state->bsinc.sf)}; - const ALsizei m{state->bsinc.m}; - - ASSUME(m > 0); - ASSUME(dstlen > 0); - ASSUME(increment > 0); - ASSUME(frac >= 0); - - src -= state->bsinc.l; - for(ALsizei i{0};i < dstlen;i++) - { - // Calculate the phase index and factor. -#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) - const ALsizei pi{frac >> FRAC_PHASE_BITDIFF}; - const ALfloat pf{(frac & ((1<(filter + offset)}; offset += m; - const __m128 *scd{reinterpret_cast(filter + offset)}; offset += m; - const __m128 *phd{reinterpret_cast(filter + offset)}; offset += m; - const __m128 *spd{reinterpret_cast(filter + offset)}; - - // Apply the scale and phase interpolated filter. - __m128 r4{_mm_setzero_ps()}; - { - const ALsizei count{m >> 2}; - const __m128 pf4{_mm_set1_ps(pf)}; - - ASSUME(count > 0); - -#define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z)) - for(ALsizei j{0};j < count;j++) - { - /* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */ - const __m128 f4 = MLA4( - MLA4(fil[j], sf4, scd[j]), - pf4, MLA4(phd[j], sf4, spd[j]) - ); - /* r += f*src */ - r4 = MLA4(r4, f4, _mm_loadu_ps(&src[j*4])); - } -#undef MLA4 - } - r4 = _mm_add_ps(r4, _mm_shuffle_ps(r4, r4, _MM_SHUFFLE(0, 1, 2, 3))); - r4 = _mm_add_ps(r4, _mm_movehl_ps(r4, r4)); - dst[i] = _mm_cvtss_f32(r4); - - frac += increment; - src += frac>>FRACTIONBITS; - frac &= FRACTIONMASK; - } - return dst; -} - - -static inline void ApplyCoeffs(ALsizei Offset, float2 *RESTRICT Values, const ALsizei IrSize, - const HrirArray &Coeffs, const ALfloat left, const ALfloat right) -{ - const __m128 lrlr{_mm_setr_ps(left, right, left, right)}; - - ASSUME(IrSize >= 2); - - if((Offset&1)) - { - __m128 imp0, imp1; - __m128 coeffs{_mm_load_ps(&Coeffs[0][0])}; - __m128 vals{_mm_loadl_pi(_mm_setzero_ps(), reinterpret_cast<__m64*>(&Values[0][0]))}; - imp0 = _mm_mul_ps(lrlr, coeffs); - vals = _mm_add_ps(imp0, vals); - _mm_storel_pi(reinterpret_cast<__m64*>(&Values[0][0]), vals); - ALsizei i{1}; - for(;i < IrSize-1;i += 2) - { - coeffs = _mm_load_ps(&Coeffs[i+1][0]); - vals = _mm_load_ps(&Values[i][0]); - imp1 = _mm_mul_ps(lrlr, coeffs); - imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2)); - vals = _mm_add_ps(imp0, vals); - _mm_store_ps(&Values[i][0], vals); - imp0 = imp1; - } - vals = _mm_loadl_pi(vals, reinterpret_cast<__m64*>(&Values[i][0])); - imp0 = _mm_movehl_ps(imp0, imp0); - vals = _mm_add_ps(imp0, vals); - _mm_storel_pi(reinterpret_cast<__m64*>(&Values[i][0]), vals); - } - else - { - for(ALsizei i{0};i < IrSize;i += 2) - { - __m128 coeffs{_mm_load_ps(&Coeffs[i][0])}; - __m128 vals{_mm_load_ps(&Values[i][0])}; - vals = _mm_add_ps(vals, _mm_mul_ps(lrlr, coeffs)); - _mm_store_ps(&Values[i][0], vals); - } - } -} - -template<> -void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - MixHrtfFilter *hrtfparams, const ALsizei BufferSize) -{ - MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, - hrtfparams, BufferSize); -} - -template<> -void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize) -{ - MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, - oldparams, newparams, BufferSize); -} - -template<> -void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, - const ALsizei BufferSize) -{ - MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, BufferSize); -} - - -template<> -void Mix_(const ALfloat *data, const al::span OutBuffer, - ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, - const ALsizei BufferSize) -{ - ASSUME(BufferSize > 0); - - const ALfloat delta{(Counter > 0) ? 1.0f / static_cast(Counter) : 0.0f}; - for(FloatBufferLine &output : OutBuffer) - { - ALfloat *RESTRICT dst{al::assume_aligned<16>(output.data()+OutPos)}; - ALfloat gain{*CurrentGains}; - const ALfloat diff{*TargetGains - gain}; - - ALsizei pos{0}; - if(std::fabs(diff) > std::numeric_limits::epsilon()) - { - ALsizei minsize{mini(BufferSize, Counter)}; - const ALfloat step{diff * delta}; - ALfloat step_count{0.0f}; - /* Mix with applying gain steps in aligned multiples of 4. */ - if(LIKELY(minsize > 3)) - { - const __m128 four4{_mm_set1_ps(4.0f)}; - const __m128 step4{_mm_set1_ps(step)}; - const __m128 gain4{_mm_set1_ps(gain)}; - __m128 step_count4{_mm_setr_ps(0.0f, 1.0f, 2.0f, 3.0f)}; - ALsizei todo{minsize >> 2}; - do { - const __m128 val4{_mm_load_ps(&data[pos])}; - __m128 dry4{_mm_load_ps(&dst[pos])}; -#define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z)) - /* dry += val * (gain + step*step_count) */ - dry4 = MLA4(dry4, val4, MLA4(gain4, step4, step_count4)); -#undef MLA4 - _mm_store_ps(&dst[pos], dry4); - step_count4 = _mm_add_ps(step_count4, four4); - pos += 4; - } while(--todo); - /* NOTE: step_count4 now represents the next four counts after - * the last four mixed samples, so the lowest element - * represents the next step count to apply. - */ - step_count = _mm_cvtss_f32(step_count4); - } - /* Mix with applying left over gain steps that aren't aligned multiples of 4. */ - for(;pos < minsize;pos++) - { - dst[pos] += data[pos]*(gain + step*step_count); - step_count += 1.0f; - } - if(pos == Counter) - gain = *TargetGains; - else - gain += step*step_count; - *CurrentGains = gain; - - /* Mix until pos is aligned with 4 or the mix is done. */ - minsize = mini(BufferSize, (pos+3)&~3); - for(;pos < minsize;pos++) - dst[pos] += data[pos]*gain; - } - ++CurrentGains; - ++TargetGains; - - if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - if(LIKELY(BufferSize-pos > 3)) - { - ALsizei todo{(BufferSize-pos) >> 2}; - const __m128 gain4{_mm_set1_ps(gain)}; - do { - const __m128 val4{_mm_load_ps(&data[pos])}; - __m128 dry4{_mm_load_ps(&dst[pos])}; - dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); - _mm_store_ps(&dst[pos], dry4); - pos += 4; - } while(--todo); - } - for(;pos < BufferSize;pos++) - dst[pos] += data[pos]*gain; - } -} - -template<> -void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, - const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize) -{ - ASSUME(BufferSize > 0); - - for(const FloatBufferLine &input : InSamples) - { - const ALfloat *RESTRICT src{al::assume_aligned<16>(input.data()+InPos)}; - const ALfloat gain{*(Gains++)}; - if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - ALsizei pos{0}; - if(LIKELY(BufferSize > 3)) - { - ALsizei todo{BufferSize >> 2}; - const __m128 gain4 = _mm_set1_ps(gain); - do { - const __m128 val4{_mm_load_ps(&src[pos])}; - __m128 dry4{_mm_load_ps(&OutBuffer[pos])}; - dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); - _mm_store_ps(&OutBuffer[pos], dry4); - pos += 4; - } while(--todo); - } - for(;pos < BufferSize;pos++) - OutBuffer[pos] += src[pos]*gain; - } -} diff --git a/Alc/mixer/mixer_sse2.cpp b/Alc/mixer/mixer_sse2.cpp deleted file mode 100644 index b5d00106..00000000 --- a/Alc/mixer/mixer_sse2.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2014 by Timothy Arceri . - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alu.h" -#include "defs.h" - - -template<> -const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) -{ - const __m128i increment4{_mm_set1_epi32(increment*4)}; - const __m128 fracOne4{_mm_set1_ps(1.0f/FRACTIONONE)}; - const __m128i fracMask4{_mm_set1_epi32(FRACTIONMASK)}; - - ASSUME(frac > 0); - ASSUME(increment > 0); - ASSUME(dstlen >= 0); - - alignas(16) ALsizei pos_[4], frac_[4]; - InitiatePositionArrays(frac, increment, frac_, pos_, 4); - __m128i frac4{_mm_setr_epi32(frac_[0], frac_[1], frac_[2], frac_[3])}; - __m128i pos4{_mm_setr_epi32(pos_[0], pos_[1], pos_[2], pos_[3])}; - - const ALsizei todo{dstlen & ~3}; - for(ALsizei i{0};i < todo;i += 4) - { - const int pos0{_mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(0, 0, 0, 0)))}; - const int pos1{_mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(1, 1, 1, 1)))}; - const int pos2{_mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(2, 2, 2, 2)))}; - const int pos3{_mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(3, 3, 3, 3)))}; - const __m128 val1{_mm_setr_ps(src[pos0 ], src[pos1 ], src[pos2 ], src[pos3 ])}; - const __m128 val2{_mm_setr_ps(src[pos0+1], src[pos1+1], src[pos2+1], src[pos3+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); - } - - /* NOTE: These four elements represent the position *after* the last four - * samples, so the lowest element is the next position to resample. - */ - ALsizei pos{_mm_cvtsi128_si32(pos4)}; - frac = _mm_cvtsi128_si32(frac4); - - for(ALsizei i{todo};i < dstlen;++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/mixer_sse3.cpp b/Alc/mixer/mixer_sse3.cpp deleted file mode 100644 index e69de29b..00000000 diff --git a/Alc/mixer/mixer_sse41.cpp b/Alc/mixer/mixer_sse41.cpp deleted file mode 100644 index 7efbda7b..00000000 --- a/Alc/mixer/mixer_sse41.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2014 by Timothy Arceri . - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include "alu.h" -#include "defs.h" - - -template<> -const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) -{ - const __m128i increment4{_mm_set1_epi32(increment*4)}; - const __m128 fracOne4{_mm_set1_ps(1.0f/FRACTIONONE)}; - const __m128i fracMask4{_mm_set1_epi32(FRACTIONMASK)}; - - ASSUME(frac > 0); - ASSUME(increment > 0); - ASSUME(dstlen >= 0); - - alignas(16) ALsizei pos_[4], frac_[4]; - InitiatePositionArrays(frac, increment, frac_, pos_, 4); - __m128i frac4{_mm_setr_epi32(frac_[0], frac_[1], frac_[2], frac_[3])}; - __m128i pos4{_mm_setr_epi32(pos_[0], pos_[1], pos_[2], pos_[3])}; - - const ALsizei todo{dstlen & ~3}; - for(ALsizei i{0};i < todo;i += 4) - { - const int pos0{_mm_extract_epi32(pos4, 0)}; - const int pos1{_mm_extract_epi32(pos4, 1)}; - const int pos2{_mm_extract_epi32(pos4, 2)}; - const int pos3{_mm_extract_epi32(pos4, 3)}; - const __m128 val1{_mm_setr_ps(src[pos0 ], src[pos1 ], src[pos2 ], src[pos3 ])}; - const __m128 val2{_mm_setr_ps(src[pos0+1], src[pos1+1], src[pos2+1], src[pos3+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); - } - - /* NOTE: These four elements represent the position *after* the last four - * samples, so the lowest element is the next position to resample. - */ - ALsizei pos{_mm_cvtsi128_si32(pos4)}; - frac = _mm_cvtsi128_si32(frac4); - - for(ALsizei i{todo};i < dstlen;++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/mixvoice.cpp b/Alc/mixvoice.cpp deleted file mode 100644 index be872f6d..00000000 --- a/Alc/mixvoice.cpp +++ /dev/null @@ -1,954 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" - -#include "alBuffer.h" -#include "alcmain.h" -#include "alSource.h" -#include "albyte.h" -#include "alconfig.h" -#include "alcontext.h" -#include "alnumeric.h" -#include "aloptional.h" -#include "alspan.h" -#include "alu.h" -#include "cpu_caps.h" -#include "filters/biquad.h" -#include "filters/nfc.h" -#include "filters/splitter.h" -#include "hrtf.h" -#include "inprogext.h" -#include "logging.h" -#include "mixer/defs.h" -#include "opthelpers.h" -#include "ringbuffer.h" -#include "threads.h" -#include "vector.h" - - -static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, - "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!"); - -/* BSinc24 requires up to 23 extra samples before the current position, and 24 after. */ -static_assert(MAX_RESAMPLE_PADDING >= 24, "MAX_RESAMPLE_PADDING must be at least 24!"); - - -Resampler ResamplerDefault = LinearResampler; - -MixerFunc MixSamples = Mix_; -RowMixerFunc MixRowSamples = MixRow_; -static HrtfMixerFunc MixHrtfSamples = MixHrtf_; -static HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_; - -static MixerFunc SelectMixer() -{ -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return Mix_; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return Mix_; -#endif - return Mix_; -} - -static RowMixerFunc SelectRowMixer() -{ -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return MixRow_; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return MixRow_; -#endif - return MixRow_; -} - -static inline HrtfMixerFunc SelectHrtfMixer() -{ -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return MixHrtf_; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return MixHrtf_; -#endif - return MixHrtf_; -} - -static inline HrtfMixerBlendFunc SelectHrtfBlendMixer() -{ -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return MixHrtfBlend_; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return MixHrtfBlend_; -#endif - return MixHrtfBlend_; -} - -ResamplerFunc SelectResampler(Resampler resampler) -{ - switch(resampler) - { - case PointResampler: - return Resample_; - case LinearResampler: -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return Resample_; -#endif -#ifdef HAVE_SSE4_1 - if((CPUCapFlags&CPU_CAP_SSE4_1)) - return Resample_; -#endif -#ifdef HAVE_SSE2 - if((CPUCapFlags&CPU_CAP_SSE2)) - return Resample_; -#endif - return Resample_; - case FIR4Resampler: - return Resample_; - case BSinc12Resampler: - case BSinc24Resampler: -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return Resample_; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return Resample_; -#endif - return Resample_; - } - - return Resample_; -} - - -void aluInitMixer() -{ - if(auto resopt = ConfigValueStr(nullptr, nullptr, "resampler")) - { - const char *str{resopt->c_str()}; - if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0) - ResamplerDefault = PointResampler; - else if(strcasecmp(str, "linear") == 0) - ResamplerDefault = LinearResampler; - else if(strcasecmp(str, "cubic") == 0) - ResamplerDefault = FIR4Resampler; - else if(strcasecmp(str, "bsinc12") == 0) - ResamplerDefault = BSinc12Resampler; - else if(strcasecmp(str, "bsinc24") == 0) - ResamplerDefault = BSinc24Resampler; - else if(strcasecmp(str, "bsinc") == 0) - { - WARN("Resampler option \"%s\" is deprecated, using bsinc12\n", str); - ResamplerDefault = BSinc12Resampler; - } - else if(strcasecmp(str, "sinc4") == 0 || strcasecmp(str, "sinc8") == 0) - { - WARN("Resampler option \"%s\" is deprecated, using cubic\n", str); - ResamplerDefault = FIR4Resampler; - } - else - { - char *end; - long n = strtol(str, &end, 0); - if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == FIR4Resampler)) - ResamplerDefault = static_cast(n); - else - WARN("Invalid resampler: %s\n", str); - } - } - - MixHrtfBlendSamples = SelectHrtfBlendMixer(); - MixHrtfSamples = SelectHrtfMixer(); - MixSamples = SelectMixer(); - MixRowSamples = SelectRowMixer(); -} - - -namespace { - -/* A quick'n'dirty lookup table to decode a muLaw-encoded byte sample into a - * signed 16-bit sample */ -constexpr ALshort muLawDecompressionTable[256] = { - -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956, - -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764, - -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412, - -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316, - -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, - -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, - -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, - -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, - -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, - -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, - -876, -844, -812, -780, -748, -716, -684, -652, - -620, -588, -556, -524, -492, -460, -428, -396, - -372, -356, -340, -324, -308, -292, -276, -260, - -244, -228, -212, -196, -180, -164, -148, -132, - -120, -112, -104, -96, -88, -80, -72, -64, - -56, -48, -40, -32, -24, -16, -8, 0, - 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, - 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, - 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, - 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, - 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, - 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, - 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, - 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, - 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, - 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, - 876, 844, 812, 780, 748, 716, 684, 652, - 620, 588, 556, 524, 492, 460, 428, 396, - 372, 356, 340, 324, 308, 292, 276, 260, - 244, 228, 212, 196, 180, 164, 148, 132, - 120, 112, 104, 96, 88, 80, 72, 64, - 56, 48, 40, 32, 24, 16, 8, 0 -}; - -/* A quick'n'dirty lookup table to decode an aLaw-encoded byte sample into a - * signed 16-bit sample */ -constexpr ALshort aLawDecompressionTable[256] = { - -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, - -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, - -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, - -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, - -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944, - -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136, - -11008,-10496,-12032,-11520, -8960, -8448, -9984, -9472, - -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568, - -344, -328, -376, -360, -280, -264, -312, -296, - -472, -456, -504, -488, -408, -392, -440, -424, - -88, -72, -120, -104, -24, -8, -56, -40, - -216, -200, -248, -232, -152, -136, -184, -168, - -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, - -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, - -688, -656, -752, -720, -560, -528, -624, -592, - -944, -912, -1008, -976, -816, -784, -880, -848, - 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, - 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, - 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, - 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, - 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, - 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, - 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, - 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, - 344, 328, 376, 360, 280, 264, 312, 296, - 472, 456, 504, 488, 408, 392, 440, 424, - 88, 72, 120, 104, 24, 8, 56, 40, - 216, 200, 248, 232, 152, 136, 184, 168, - 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, - 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, - 688, 656, 752, 720, 560, 528, 624, 592, - 944, 912, 1008, 976, 816, 784, 880, 848 -}; - - -void SendSourceStoppedEvent(ALCcontext *context, ALuint id) -{ - ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)}; - if(!(enabledevt&EventType_SourceStateChange)) return; - - RingBuffer *ring{context->AsyncEvents.get()}; - auto evt_vec = ring->getWriteVector(); - if(evt_vec.first.len < 1) return; - - AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_SourceStateChange}}; - evt->u.srcstate.id = id; - evt->u.srcstate.state = AL_STOPPED; - - ring->writeAdvance(1); - context->EventSem.post(); -} - - -const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, ALfloat *dst, - const ALfloat *src, ALsizei numsamples, int type) -{ - switch(type) - { - case AF_None: - lpfilter->clear(); - hpfilter->clear(); - break; - - case AF_LowPass: - lpfilter->process(dst, src, numsamples); - hpfilter->clear(); - return dst; - case AF_HighPass: - lpfilter->clear(); - hpfilter->process(dst, src, numsamples); - return dst; - - case AF_BandPass: - lpfilter->process(dst, src, numsamples); - hpfilter->process(dst, dst, numsamples); - return dst; - } - return src; -} - - -/* Base template left undefined. Should be marked =delete, but Clang 3.8.1 - * chokes on that given the inline specializations. - */ -template -inline ALfloat LoadSample(typename FmtTypeTraits::Type val); - -template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) -{ return (val-128) * (1.0f/128.0f); } -template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) -{ return val * (1.0f/32768.0f); } -template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) -{ return val; } -template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) -{ return static_cast(val); } -template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) -{ return muLawDecompressionTable[val] * (1.0f/32768.0f); } -template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) -{ return aLawDecompressionTable[val] * (1.0f/32768.0f); } - -template -inline void LoadSampleArray(ALfloat *RESTRICT dst, const al::byte *src, ALint srcstep, - const ptrdiff_t samples) -{ - using SampleType = typename FmtTypeTraits::Type; - - const SampleType *RESTRICT ssrc{reinterpret_cast(src)}; - for(ALsizei i{0};i < samples;i++) - dst[i] += LoadSample(ssrc[i*srcstep]); -} - -void LoadSamples(ALfloat *RESTRICT dst, const al::byte *src, ALint srcstep, FmtType srctype, - const ptrdiff_t samples) -{ -#define HANDLE_FMT(T) case T: LoadSampleArray(dst, src, srcstep, samples); break - switch(srctype) - { - HANDLE_FMT(FmtUByte); - HANDLE_FMT(FmtShort); - HANDLE_FMT(FmtFloat); - HANDLE_FMT(FmtDouble); - HANDLE_FMT(FmtMulaw); - HANDLE_FMT(FmtAlaw); - } -#undef HANDLE_FMT -} - -ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&BufferLoopItem, - const ALsizei NumChannels, const ALsizei SampleSize, const ALsizei chan, ALsizei DataPosInt, - al::span SrcBuffer) -{ - /* TODO: For static sources, loop points are taken from the first buffer - * (should be adjusted by any buffer offset, to possibly be added later). - */ - const ALbuffer *Buffer0{BufferListItem->buffers[0]}; - const ALsizei LoopStart{Buffer0->LoopStart}; - const ALsizei LoopEnd{Buffer0->LoopEnd}; - ASSUME(LoopStart >= 0); - ASSUME(LoopEnd > LoopStart); - - /* If current pos is beyond the loop range, do not loop */ - if(!BufferLoopItem || DataPosInt >= LoopEnd) - { - BufferLoopItem = nullptr; - - auto load_buffer = [DataPosInt,NumChannels,SampleSize,chan,SrcBuffer](size_t CompLen, const ALbuffer *buffer) -> size_t - { - if(DataPosInt >= buffer->SampleLen) - return CompLen; - - /* Load what's left to play from the buffer */ - const size_t DataSize{std::min(SrcBuffer.size(), - buffer->SampleLen - DataPosInt)}; - CompLen = std::max(CompLen, DataSize); - - const al::byte *Data{buffer->mData.data()}; - Data += (DataPosInt*NumChannels + chan)*SampleSize; - - LoadSamples(SrcBuffer.data(), Data, NumChannels, buffer->mFmtType, DataSize); - return CompLen; - }; - /* It's impossible to have a buffer list item with no entries. */ - ASSUME(BufferListItem->num_buffers > 0); - auto buffers_end = BufferListItem->buffers + BufferListItem->num_buffers; - SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->buffers, buffers_end, - size_t{0u}, load_buffer)); - } - else - { - const al::span SrcData{SrcBuffer.first( - std::min(SrcBuffer.size(), LoopEnd - DataPosInt))}; - - auto load_buffer = [DataPosInt,NumChannels,SampleSize,chan,SrcData](size_t CompLen, const ALbuffer *buffer) -> size_t - { - if(DataPosInt >= buffer->SampleLen) - return CompLen; - - /* Load what's left of this loop iteration */ - const size_t DataSize{std::min(SrcData.size(), - buffer->SampleLen - DataPosInt)}; - CompLen = std::max(CompLen, DataSize); - - const al::byte *Data{buffer->mData.data()}; - Data += (DataPosInt*NumChannels + chan)*SampleSize; - - LoadSamples(SrcData.data(), Data, NumChannels, buffer->mFmtType, DataSize); - return CompLen; - }; - ASSUME(BufferListItem->num_buffers > 0); - auto buffers_end = BufferListItem->buffers + BufferListItem->num_buffers; - SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->buffers, buffers_end, - size_t{0u}, load_buffer)); - - const auto LoopSize = static_cast(LoopEnd - LoopStart); - while(!SrcBuffer.empty()) - { - const al::span SrcData{SrcBuffer.first( - std::min(SrcBuffer.size(), LoopSize))}; - - auto load_buffer_loop = [LoopStart,NumChannels,SampleSize,chan,SrcData](size_t CompLen, const ALbuffer *buffer) -> size_t - { - if(LoopStart >= buffer->SampleLen) - return CompLen; - - const size_t DataSize{std::min(SrcData.size(), - buffer->SampleLen-LoopStart)}; - CompLen = std::max(CompLen, DataSize); - - const al::byte *Data{buffer->mData.data()}; - Data += (LoopStart*NumChannels + chan)*SampleSize; - - LoadSamples(SrcData.data(), Data, NumChannels, buffer->mFmtType, DataSize); - return CompLen; - }; - SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->buffers, buffers_end, - size_t{0u}, load_buffer_loop)); - } - } - return SrcBuffer.begin(); -} - -ALfloat *LoadBufferQueue(ALbufferlistitem *BufferListItem, ALbufferlistitem *BufferLoopItem, - const ALsizei NumChannels, const ALsizei SampleSize, const ALsizei chan, ALsizei DataPosInt, - al::span SrcBuffer) -{ - /* Crawl the buffer queue to fill in the temp buffer */ - while(BufferListItem && !SrcBuffer.empty()) - { - if(DataPosInt >= BufferListItem->max_samples) - { - DataPosInt -= BufferListItem->max_samples; - BufferListItem = BufferListItem->next.load(std::memory_order_acquire); - if(!BufferListItem) BufferListItem = BufferLoopItem; - continue; - } - - auto load_buffer = [DataPosInt,NumChannels,SampleSize,chan,SrcBuffer](size_t CompLen, const ALbuffer *buffer) -> size_t - { - if(!buffer) return CompLen; - if(DataPosInt >= buffer->SampleLen) - return CompLen; - - const size_t DataSize{std::min(SrcBuffer.size(), buffer->SampleLen-DataPosInt)}; - CompLen = std::max(CompLen, DataSize); - - const al::byte *Data{buffer->mData.data()}; - Data += (DataPosInt*NumChannels + chan)*SampleSize; - - LoadSamples(SrcBuffer.data(), Data, NumChannels, buffer->mFmtType, DataSize); - return CompLen; - }; - ASSUME(BufferListItem->num_buffers > 0); - auto buffers_end = BufferListItem->buffers + BufferListItem->num_buffers; - SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->buffers, buffers_end, - size_t{0u}, load_buffer)); - - if(SrcBuffer.empty()) - break; - DataPosInt = 0; - BufferListItem = BufferListItem->next.load(std::memory_order_acquire); - if(!BufferListItem) BufferListItem = BufferLoopItem; - } - - return SrcBuffer.begin(); -} - -} // namespace - -void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCcontext *Context, const ALsizei SamplesToDo) -{ - static constexpr ALfloat SilentTarget[MAX_OUTPUT_CHANNELS]{}; - - ASSUME(SamplesToDo > 0); - - /* Get voice info */ - const bool isstatic{(voice->mFlags&VOICE_IS_STATIC) != 0}; - ALsizei DataPosInt{static_cast(voice->mPosition.load(std::memory_order_relaxed))}; - ALsizei DataPosFrac{voice->mPositionFrac.load(std::memory_order_relaxed)}; - ALbufferlistitem *BufferListItem{voice->mCurrentBuffer.load(std::memory_order_relaxed)}; - ALbufferlistitem *BufferLoopItem{voice->mLoopBuffer.load(std::memory_order_relaxed)}; - const ALsizei NumChannels{voice->mNumChannels}; - const ALsizei SampleSize{voice->mSampleSize}; - const ALint increment{voice->mStep}; - - ASSUME(DataPosInt >= 0); - ASSUME(DataPosFrac >= 0); - ASSUME(NumChannels > 0); - ASSUME(SampleSize > 0); - ASSUME(increment > 0); - - ALCdevice *Device{Context->Device}; - const ALsizei NumSends{Device->NumAuxSends}; - const ALsizei IrSize{Device->mHrtf ? Device->mHrtf->irSize : 0}; - - ASSUME(NumSends >= 0); - ASSUME(IrSize >= 0); - - ResamplerFunc Resample{(increment == FRACTIONONE && DataPosFrac == 0) ? - Resample_ : voice->mResampler}; - - ALsizei Counter{(voice->mFlags&VOICE_IS_FADING) ? SamplesToDo : 0}; - if(!Counter) - { - /* No fading, just overwrite the old/current params. */ - for(ALsizei chan{0};chan < NumChannels;chan++) - { - ALvoice::ChannelData &chandata = voice->mChans[chan]; - DirectParams &parms = chandata.mDryParams; - if(!(voice->mFlags&VOICE_HAS_HRTF)) - std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target), - std::begin(parms.Gains.Current)); - else - parms.Hrtf.Old = parms.Hrtf.Target; - for(ALsizei send{0};send < NumSends;++send) - { - if(voice->mSend[send].Buffer.empty()) - continue; - - SendParams &parms = chandata.mWetParams[send]; - std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target), - std::begin(parms.Gains.Current)); - } - } - } - else if((voice->mFlags&VOICE_HAS_HRTF)) - { - for(ALsizei chan{0};chan < NumChannels;chan++) - { - DirectParams &parms = voice->mChans[chan].mDryParams; - if(!(parms.Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD)) - { - /* The old HRTF params are silent, so overwrite the old - * coefficients with the new, and reset the old gain to 0. The - * future mix will then fade from silence. - */ - parms.Hrtf.Old = parms.Hrtf.Target; - parms.Hrtf.Old.Gain = 0.0f; - } - } - } - - ALsizei buffers_done{0}; - ALsizei OutPos{0}; - do { - /* Figure out how many buffer samples will be needed */ - ALsizei DstBufferSize{SamplesToDo - OutPos}; - - /* Calculate the last written dst sample pos. */ - int64_t DataSize64{DstBufferSize - 1}; - /* Calculate the last read src sample pos. */ - DataSize64 = (DataSize64*increment + DataPosFrac) >> FRACTIONBITS; - /* +1 to get the src sample count, include padding. */ - DataSize64 += 1 + MAX_RESAMPLE_PADDING*2; - - auto SrcBufferSize = static_cast( - mini64(DataSize64, BUFFERSIZE + MAX_RESAMPLE_PADDING*2 + 1)); - if(SrcBufferSize > BUFFERSIZE + MAX_RESAMPLE_PADDING*2) - { - SrcBufferSize = BUFFERSIZE + MAX_RESAMPLE_PADDING*2; - /* If the source buffer got saturated, we can't fill the desired - * dst size. Figure out how many samples we can actually mix from - * this. - */ - DataSize64 = SrcBufferSize - MAX_RESAMPLE_PADDING*2; - DataSize64 = ((DataSize64<(mini64(DataSize64, DstBufferSize)); - - /* Some mixers like having a multiple of 4, so try to give that - * unless this is the last update. - */ - if(DstBufferSize < SamplesToDo-OutPos) - DstBufferSize &= ~3; - } - - for(ALsizei chan{0};chan < NumChannels;chan++) - { - ALvoice::ChannelData &chandata = voice->mChans[chan]; - const al::span SrcData{Device->SourceData, SrcBufferSize}; - - /* Load the previous samples into the source data first, and clear the rest. */ - auto srciter = std::copy_n(chandata.mPrevSamples.begin(), MAX_RESAMPLE_PADDING, - SrcData.begin()); - std::fill(srciter, SrcData.end(), 0.0f); - - if(UNLIKELY(!BufferListItem)) - srciter = std::copy(chandata.mPrevSamples.begin()+MAX_RESAMPLE_PADDING, - chandata.mPrevSamples.end(), srciter); - else if(isstatic) - srciter = LoadBufferStatic(BufferListItem, BufferLoopItem, NumChannels, - SampleSize, chan, DataPosInt, {srciter, SrcData.end()}); - else - srciter = LoadBufferQueue(BufferListItem, BufferLoopItem, NumChannels, - SampleSize, chan, DataPosInt, {srciter, SrcData.end()}); - - if(UNLIKELY(srciter != SrcData.end())) - { - /* If the source buffer wasn't filled, copy the last sample for - * the remaining buffer. Ideally it should have ended with - * silence, but if not the gain fading should help avoid clicks - * from sudden amplitude changes. - */ - const ALfloat sample{*(srciter-1)}; - std::fill(srciter, SrcData.end(), sample); - } - - /* Store the last source samples used for next time. */ - std::copy_n(&SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS], - chandata.mPrevSamples.size(), chandata.mPrevSamples.begin()); - - /* Resample, then apply ambisonic upsampling as needed. */ - const ALfloat *ResampledData{Resample(&voice->mResampleState, - &SrcData[MAX_RESAMPLE_PADDING], DataPosFrac, increment, - Device->ResampledData, DstBufferSize)}; - if((voice->mFlags&VOICE_IS_AMBISONIC)) - { - const ALfloat hfscale{chandata.mAmbiScale}; - /* Beware the evil const_cast. It's safe since it's pointing to - * either SourceData or ResampledData (both non-const), but the - * resample method takes the source as const float* and may - * return it without copying to output, making it currently - * unavoidable. - */ - chandata.mAmbiSplitter.applyHfScale(const_cast(ResampledData), hfscale, - DstBufferSize); - } - - /* Now filter and mix to the appropriate outputs. */ - { - DirectParams &parms = chandata.mDryParams; - const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, - Device->FilteredData, ResampledData, DstBufferSize, - voice->mDirect.FilterType)}; - - if((voice->mFlags&VOICE_HAS_HRTF)) - { - const int OutLIdx{GetChannelIdxByName(Device->RealOut, FrontLeft)}; - const int OutRIdx{GetChannelIdxByName(Device->RealOut, FrontRight)}; - ASSUME(OutLIdx >= 0 && OutRIdx >= 0); - - auto &HrtfSamples = Device->HrtfSourceData; - auto &AccumSamples = Device->HrtfAccumData; - const ALfloat TargetGain{UNLIKELY(vstate == ALvoice::Stopping) ? 0.0f : - parms.Hrtf.Target.Gain}; - ALsizei fademix{0}; - - /* Copy the HRTF history and new input samples into a temp - * buffer. - */ - auto src_iter = std::copy(parms.Hrtf.State.History.begin(), - parms.Hrtf.State.History.end(), std::begin(HrtfSamples)); - std::copy_n(samples, DstBufferSize, src_iter); - /* Copy the last used samples back into the history buffer - * for later. - */ - std::copy_n(std::begin(HrtfSamples) + DstBufferSize, - parms.Hrtf.State.History.size(), parms.Hrtf.State.History.begin()); - - /* Copy the current filtered values being accumulated into - * the temp buffer. - */ - auto accum_iter = std::copy_n(parms.Hrtf.State.Values.begin(), - parms.Hrtf.State.Values.size(), std::begin(AccumSamples)); - - /* Clear the accumulation buffer that will start getting - * filled in. - */ - std::fill_n(accum_iter, DstBufferSize, float2{}); - - /* If fading, the old gain is not silence, and this is the - * first mixing pass, fade between the IRs. - */ - if(Counter && (parms.Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD) && OutPos == 0) - { - fademix = mini(DstBufferSize, 128); - - ALfloat gain{TargetGain}; - - /* The new coefficients need to fade in completely - * since they're replacing the old ones. To keep the - * gain fading consistent, interpolate between the old - * and new target gains given how much of the fade time - * this mix handles. - */ - if(LIKELY(Counter > fademix)) - { - const ALfloat a{static_cast(fademix) / - static_cast(Counter)}; - gain = lerp(parms.Hrtf.Old.Gain, TargetGain, a); - } - MixHrtfFilter hrtfparams; - hrtfparams.Coeffs = &parms.Hrtf.Target.Coeffs; - hrtfparams.Delay[0] = parms.Hrtf.Target.Delay[0]; - hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1]; - hrtfparams.Gain = 0.0f; - hrtfparams.GainStep = gain / static_cast(fademix); - - MixHrtfBlendSamples(voice->mDirect.Buffer[OutLIdx], - voice->mDirect.Buffer[OutRIdx], HrtfSamples, AccumSamples, OutPos, - IrSize, &parms.Hrtf.Old, &hrtfparams, fademix); - /* Update the old parameters with the result. */ - parms.Hrtf.Old = parms.Hrtf.Target; - if(fademix < Counter) - parms.Hrtf.Old.Gain = hrtfparams.Gain; - else - parms.Hrtf.Old.Gain = TargetGain; - } - - if(LIKELY(fademix < DstBufferSize)) - { - const ALsizei todo{DstBufferSize - fademix}; - ALfloat gain{TargetGain}; - - /* Interpolate the target gain if the gain fading lasts - * longer than this mix. - */ - if(Counter > DstBufferSize) - { - const ALfloat a{static_cast(todo) / - static_cast(Counter-fademix)}; - gain = lerp(parms.Hrtf.Old.Gain, TargetGain, a); - } - - MixHrtfFilter hrtfparams; - hrtfparams.Coeffs = &parms.Hrtf.Target.Coeffs; - hrtfparams.Delay[0] = parms.Hrtf.Target.Delay[0]; - hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1]; - hrtfparams.Gain = parms.Hrtf.Old.Gain; - hrtfparams.GainStep = (gain - parms.Hrtf.Old.Gain) / - static_cast(todo); - MixHrtfSamples(voice->mDirect.Buffer[OutLIdx], - voice->mDirect.Buffer[OutRIdx], HrtfSamples+fademix, - AccumSamples+fademix, OutPos+fademix, IrSize, &hrtfparams, todo); - /* Store the interpolated gain or the final target gain - * depending if the fade is done. - */ - if(DstBufferSize < Counter) - parms.Hrtf.Old.Gain = gain; - else - parms.Hrtf.Old.Gain = TargetGain; - } - - /* Copy the new in-progress accumulation values back for - * the next mix. - */ - std::copy_n(std::begin(AccumSamples) + DstBufferSize, - parms.Hrtf.State.Values.size(), parms.Hrtf.State.Values.begin()); - } - else if((voice->mFlags&VOICE_HAS_NFC)) - { - const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? - SilentTarget : parms.Gains.Target}; - - const size_t outcount{Device->NumChannelsPerOrder[0]}; - MixSamples(samples, voice->mDirect.Buffer.first(outcount), parms.Gains.Current, - TargetGains, Counter, OutPos, DstBufferSize); - - ALfloat (&nfcsamples)[BUFFERSIZE] = Device->NfcSampleData; - size_t chanoffset{outcount}; - using FilterProc = void (NfcFilter::*)(float*,const float*,int); - auto apply_nfc = [voice,&parms,samples,TargetGains,DstBufferSize,Counter,OutPos,&chanoffset,&nfcsamples](const FilterProc process, const size_t outcount) -> void - { - if(outcount < 1) return; - (parms.NFCtrlFilter.*process)(nfcsamples, samples, DstBufferSize); - MixSamples(nfcsamples, voice->mDirect.Buffer.subspan(chanoffset, outcount), - parms.Gains.Current+chanoffset, TargetGains+chanoffset, Counter, - OutPos, DstBufferSize); - chanoffset += outcount; - }; - apply_nfc(&NfcFilter::process1, Device->NumChannelsPerOrder[1]); - apply_nfc(&NfcFilter::process2, Device->NumChannelsPerOrder[2]); - apply_nfc(&NfcFilter::process3, Device->NumChannelsPerOrder[3]); - } - else - { - const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? - SilentTarget : parms.Gains.Target}; - MixSamples(samples, voice->mDirect.Buffer, parms.Gains.Current, TargetGains, - Counter, OutPos, DstBufferSize); - } - } - - ALfloat (&FilterBuf)[BUFFERSIZE] = Device->FilteredData; - for(ALsizei send{0};send < NumSends;++send) - { - if(voice->mSend[send].Buffer.empty()) - continue; - - SendParams &parms = chandata.mWetParams[send]; - const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, - FilterBuf, ResampledData, DstBufferSize, voice->mSend[send].FilterType)}; - - const ALfloat *TargetGains{UNLIKELY(vstate==ALvoice::Stopping) ? SilentTarget : - parms.Gains.Target}; - MixSamples(samples, voice->mSend[send].Buffer, parms.Gains.Current, TargetGains, - Counter, OutPos, DstBufferSize); - }; - } - /* Update positions */ - DataPosFrac += increment*DstBufferSize; - DataPosInt += DataPosFrac>>FRACTIONBITS; - DataPosFrac &= FRACTIONMASK; - - OutPos += DstBufferSize; - Counter = maxi(DstBufferSize, Counter) - DstBufferSize; - - if(UNLIKELY(!BufferListItem)) - { - /* Do nothing extra when there's no buffers. */ - } - else if(isstatic) - { - if(BufferLoopItem) - { - /* Handle looping static source */ - const ALbuffer *Buffer{BufferListItem->buffers[0]}; - const ALsizei LoopStart{Buffer->LoopStart}; - const ALsizei LoopEnd{Buffer->LoopEnd}; - if(DataPosInt >= LoopEnd) - { - assert(LoopEnd > LoopStart); - DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart; - } - } - else - { - /* Handle non-looping static source */ - if(DataPosInt >= BufferListItem->max_samples) - { - if(LIKELY(vstate == ALvoice::Playing)) - vstate = ALvoice::Stopped; - BufferListItem = nullptr; - break; - } - } - } - else while(1) - { - /* Handle streaming source */ - if(BufferListItem->max_samples > DataPosInt) - break; - - DataPosInt -= BufferListItem->max_samples; - - buffers_done += BufferListItem->num_buffers; - BufferListItem = BufferListItem->next.load(std::memory_order_relaxed); - if(!BufferListItem && !(BufferListItem=BufferLoopItem)) - { - if(LIKELY(vstate == ALvoice::Playing)) - vstate = ALvoice::Stopped; - break; - } - } - } while(OutPos < SamplesToDo); - - voice->mFlags |= VOICE_IS_FADING; - - /* Don't update positions and buffers if we were stopping. */ - if(UNLIKELY(vstate == ALvoice::Stopping)) - { - voice->mPlayState.store(ALvoice::Stopped, std::memory_order_release); - return; - } - - /* Update voice info */ - voice->mPosition.store(DataPosInt, std::memory_order_relaxed); - voice->mPositionFrac.store(DataPosFrac, std::memory_order_relaxed); - voice->mCurrentBuffer.store(BufferListItem, std::memory_order_relaxed); - if(vstate == ALvoice::Stopped) - { - voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); - voice->mSourceID.store(0u, std::memory_order_relaxed); - } - std::atomic_thread_fence(std::memory_order_release); - - /* Send any events now, after the position/buffer info was updated. */ - ALbitfieldSOFT enabledevt{Context->EnabledEvts.load(std::memory_order_acquire)}; - if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) - { - RingBuffer *ring{Context->AsyncEvents.get()}; - auto evt_vec = ring->getWriteVector(); - if(evt_vec.first.len > 0) - { - AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_BufferCompleted}}; - evt->u.bufcomp.id = SourceID; - evt->u.bufcomp.count = buffers_done; - ring->writeAdvance(1); - Context->EventSem.post(); - } - } - - if(vstate == ALvoice::Stopped) - { - /* If the voice just ended, set it to Stopping so the next render - * ensures any residual noise fades to 0 amplitude. - */ - voice->mPlayState.store(ALvoice::Stopping, std::memory_order_release); - SendSourceStoppedEvent(Context, SourceID); - } -} diff --git a/Alc/panning.cpp b/Alc/panning.cpp deleted file mode 100644 index 3a67e33a..00000000 --- a/Alc/panning.cpp +++ /dev/null @@ -1,964 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2010 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "alcmain.h" -#include "alAuxEffectSlot.h" -#include "alu.h" -#include "alconfig.h" -#include "ambdec.h" -#include "bformatdec.h" -#include "filters/splitter.h" -#include "uhjfilter.h" -#include "bs2b.h" - -#include "alspan.h" - - -constexpr std::array AmbiScale::FromN3D; -constexpr std::array AmbiScale::FromSN3D; -constexpr std::array AmbiScale::FromFuMa; -constexpr std::array AmbiIndex::FromFuMa; -constexpr std::array AmbiIndex::FromACN; -constexpr std::array AmbiIndex::From2D; -constexpr std::array AmbiIndex::From3D; - - -namespace { - -using namespace std::placeholders; -using std::chrono::seconds; -using std::chrono::nanoseconds; - -inline const char *GetLabelFromChannel(Channel channel) -{ - switch(channel) - { - case FrontLeft: return "front-left"; - case FrontRight: return "front-right"; - case FrontCenter: return "front-center"; - case LFE: return "lfe"; - case BackLeft: return "back-left"; - case BackRight: return "back-right"; - case BackCenter: return "back-center"; - case SideLeft: return "side-left"; - case SideRight: return "side-right"; - - case UpperFrontLeft: return "upper-front-left"; - case UpperFrontRight: return "upper-front-right"; - case UpperBackLeft: return "upper-back-left"; - case UpperBackRight: return "upper-back-right"; - case LowerFrontLeft: return "lower-front-left"; - case LowerFrontRight: return "lower-front-right"; - case LowerBackLeft: return "lower-back-left"; - case LowerBackRight: return "lower-back-right"; - - case Aux0: return "aux-0"; - case Aux1: return "aux-1"; - case Aux2: return "aux-2"; - case Aux3: return "aux-3"; - case Aux4: return "aux-4"; - case Aux5: return "aux-5"; - case Aux6: return "aux-6"; - case Aux7: return "aux-7"; - case Aux8: return "aux-8"; - case Aux9: return "aux-9"; - case Aux10: return "aux-10"; - case Aux11: return "aux-11"; - case Aux12: return "aux-12"; - case Aux13: return "aux-13"; - case Aux14: return "aux-14"; - case Aux15: return "aux-15"; - - case MaxChannels: break; - } - return "(unknown)"; -} - - -void AllocChannels(ALCdevice *device, const ALuint main_chans, const ALuint real_chans) -{ - TRACE("Channel config, Main: %u, Real: %u\n", main_chans, real_chans); - - /* Allocate extra channels for any post-filter output. */ - const ALuint num_chans{main_chans + real_chans}; - - TRACE("Allocating %u channels, %zu bytes\n", num_chans, - num_chans*sizeof(device->MixBuffer[0])); - device->MixBuffer.resize(num_chans); - al::span buffer{device->MixBuffer.data(), device->MixBuffer.size()}; - - device->Dry.Buffer = buffer.first(main_chans); - buffer = buffer.subspan(main_chans); - if(real_chans != 0) - { - device->RealOut.Buffer = buffer.first(real_chans); - buffer = buffer.subspan(real_chans); - } - else - device->RealOut.Buffer = device->Dry.Buffer; -} - - -struct ChannelMap { - Channel ChanName; - ALfloat Config[MAX_AMBI2D_CHANNELS]; -}; - -bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) -{ - auto map_spkr = [device](const AmbDecConf::SpeakerConf &speaker) -> ALsizei - { - /* NOTE: AmbDec does not define any standard speaker names, however - * for this to work we have to by able to find the output channel - * the speaker definition corresponds to. Therefore, OpenAL Soft - * requires these channel labels to be recognized: - * - * LF = Front left - * RF = Front right - * LS = Side left - * RS = Side right - * LB = Back left - * RB = Back right - * CE = Front center - * CB = Back center - * - * Additionally, surround51 will acknowledge back speakers for side - * channels, and surround51rear will acknowledge side speakers for - * back channels, to avoid issues with an ambdec expecting 5.1 to - * use the side channels when the device is configured for back, - * and vice-versa. - */ - Channel ch{}; - if(speaker.Name == "LF") - ch = FrontLeft; - else if(speaker.Name == "RF") - ch = FrontRight; - else if(speaker.Name == "CE") - ch = FrontCenter; - else if(speaker.Name == "LS") - { - if(device->FmtChans == DevFmtX51Rear) - ch = BackLeft; - else - ch = SideLeft; - } - else if(speaker.Name == "RS") - { - if(device->FmtChans == DevFmtX51Rear) - ch = BackRight; - else - ch = SideRight; - } - else if(speaker.Name == "LB") - { - if(device->FmtChans == DevFmtX51) - ch = SideLeft; - else - ch = BackLeft; - } - else if(speaker.Name == "RB") - { - if(device->FmtChans == DevFmtX51) - ch = SideRight; - else - ch = BackRight; - } - else if(speaker.Name == "CB") - ch = BackCenter; - else - { - const char *name{speaker.Name.c_str()}; - unsigned int n; - char c; - - if(sscanf(name, "AUX%u%c", &n, &c) == 1 && n < 16) - ch = static_cast(Aux0+n); - else - { - ERR("AmbDec speaker label \"%s\" not recognized\n", name); - return -1; - } - } - const int chidx{GetChannelIdxByName(device->RealOut, ch)}; - if(chidx == -1) - ERR("Failed to lookup AmbDec speaker label %s\n", speaker.Name.c_str()); - return chidx; - }; - std::transform(conf->Speakers.begin(), conf->Speakers.end(), std::begin(speakermap), map_spkr); - /* Return success if no invalid entries are found. */ - auto speakermap_end = std::begin(speakermap) + conf->Speakers.size(); - return std::find(std::begin(speakermap), speakermap_end, -1) == speakermap_end; -} - - -constexpr ChannelMap MonoCfg[1] = { - { FrontCenter, { 1.0f } }, -}, StereoCfg[2] = { - { FrontLeft, { 5.00000000e-1f, 2.88675135e-1f, 5.52305643e-2f } }, - { FrontRight, { 5.00000000e-1f, -2.88675135e-1f, 5.52305643e-2f } }, -}, QuadCfg[4] = { - { BackLeft, { 3.53553391e-1f, 2.04124145e-1f, -2.04124145e-1f } }, - { FrontLeft, { 3.53553391e-1f, 2.04124145e-1f, 2.04124145e-1f } }, - { FrontRight, { 3.53553391e-1f, -2.04124145e-1f, 2.04124145e-1f } }, - { BackRight, { 3.53553391e-1f, -2.04124145e-1f, -2.04124145e-1f } }, -}, X51SideCfg[4] = { - { SideLeft, { 3.33000782e-1f, 1.89084803e-1f, -2.00042375e-1f, -2.12307769e-2f, -1.14579885e-2f } }, - { FrontLeft, { 1.88542860e-1f, 1.27709292e-1f, 1.66295695e-1f, 7.30571517e-2f, 2.10901184e-2f } }, - { FrontRight, { 1.88542860e-1f, -1.27709292e-1f, 1.66295695e-1f, -7.30571517e-2f, 2.10901184e-2f } }, - { SideRight, { 3.33000782e-1f, -1.89084803e-1f, -2.00042375e-1f, 2.12307769e-2f, -1.14579885e-2f } }, -}, X51RearCfg[4] = { - { BackLeft, { 3.33000782e-1f, 1.89084803e-1f, -2.00042375e-1f, -2.12307769e-2f, -1.14579885e-2f } }, - { FrontLeft, { 1.88542860e-1f, 1.27709292e-1f, 1.66295695e-1f, 7.30571517e-2f, 2.10901184e-2f } }, - { FrontRight, { 1.88542860e-1f, -1.27709292e-1f, 1.66295695e-1f, -7.30571517e-2f, 2.10901184e-2f } }, - { BackRight, { 3.33000782e-1f, -1.89084803e-1f, -2.00042375e-1f, 2.12307769e-2f, -1.14579885e-2f } }, -}, X61Cfg[6] = { - { SideLeft, { 2.04460341e-1f, 2.17177926e-1f, -4.39996780e-2f, -2.60790269e-2f, -6.87239792e-2f } }, - { FrontLeft, { 1.58923161e-1f, 9.21772680e-2f, 1.59658796e-1f, 6.66278083e-2f, 3.84686854e-2f } }, - { FrontRight, { 1.58923161e-1f, -9.21772680e-2f, 1.59658796e-1f, -6.66278083e-2f, 3.84686854e-2f } }, - { SideRight, { 2.04460341e-1f, -2.17177926e-1f, -4.39996780e-2f, 2.60790269e-2f, -6.87239792e-2f } }, - { BackCenter, { 2.50001688e-1f, 0.00000000e+0f, -2.50000094e-1f, 0.00000000e+0f, 6.05133395e-2f } }, -}, X71Cfg[6] = { - { BackLeft, { 2.04124145e-1f, 1.08880247e-1f, -1.88586120e-1f, -1.29099444e-1f, 7.45355993e-2f, 3.73460789e-2f, 0.00000000e+0f } }, - { SideLeft, { 2.04124145e-1f, 2.17760495e-1f, 0.00000000e+0f, 0.00000000e+0f, -1.49071198e-1f, -3.73460789e-2f, 0.00000000e+0f } }, - { FrontLeft, { 2.04124145e-1f, 1.08880247e-1f, 1.88586120e-1f, 1.29099444e-1f, 7.45355993e-2f, 3.73460789e-2f, 0.00000000e+0f } }, - { FrontRight, { 2.04124145e-1f, -1.08880247e-1f, 1.88586120e-1f, -1.29099444e-1f, 7.45355993e-2f, -3.73460789e-2f, 0.00000000e+0f } }, - { SideRight, { 2.04124145e-1f, -2.17760495e-1f, 0.00000000e+0f, 0.00000000e+0f, -1.49071198e-1f, 3.73460789e-2f, 0.00000000e+0f } }, - { BackRight, { 2.04124145e-1f, -1.08880247e-1f, -1.88586120e-1f, 1.29099444e-1f, 7.45355993e-2f, -3.73460789e-2f, 0.00000000e+0f } }, -}; - -void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, - const al::span chans_per_order) -{ - /* NFC is only used when AvgSpeakerDist is greater than 0. */ - const char *devname{device->DeviceName.c_str()}; - if(!GetConfigValueBool(devname, "decoder", "nfc", 0) || !(ctrl_dist > 0.0f)) - return; - - device->AvgSpeakerDist = clampf(ctrl_dist, 0.1f, 10.0f); - TRACE("Using near-field reference distance: %.2f meters\n", device->AvgSpeakerDist); - - auto iter = std::copy(chans_per_order.begin(), chans_per_order.begin()+order+1, - std::begin(device->NumChannelsPerOrder)); - std::fill(iter, std::end(device->NumChannelsPerOrder), 0u); -} - -void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) -{ - auto get_max = std::bind(maxf, _1, - std::bind(std::mem_fn(&AmbDecConf::SpeakerConf::Distance), _2)); - const ALfloat maxdist{ - std::accumulate(conf->Speakers.begin(), conf->Speakers.end(), float{0.0f}, get_max)}; - - const char *devname{device->DeviceName.c_str()}; - if(!GetConfigValueBool(devname, "decoder", "distance-comp", 1) || !(maxdist > 0.0f)) - return; - - const auto distSampleScale = static_cast(device->Frequency)/SPEEDOFSOUNDMETRESPERSEC; - const auto ChanDelay = device->ChannelDelay.as_span(); - size_t total{0u}; - for(size_t i{0u};i < conf->Speakers.size();i++) - { - const AmbDecConf::SpeakerConf &speaker = conf->Speakers[i]; - const ALsizei chan{speakermap[i]}; - - /* Distance compensation only delays in steps of the sample rate. This - * is a bit less accurate since the delay time falls to the nearest - * sample time, but it's far simpler as it doesn't have to deal with - * phase offsets. This means at 48khz, for instance, the distance delay - * will be in steps of about 7 millimeters. - */ - ALfloat delay{std::floor((maxdist - speaker.Distance)*distSampleScale + 0.5f)}; - if(delay > ALfloat{MAX_DELAY_LENGTH-1}) - { - ERR("Delay for speaker \"%s\" exceeds buffer length (%f > %d)\n", - speaker.Name.c_str(), delay, MAX_DELAY_LENGTH-1); - delay = ALfloat{MAX_DELAY_LENGTH-1}; - } - - ChanDelay[chan].Length = static_cast(delay); - ChanDelay[chan].Gain = speaker.Distance / maxdist; - TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan, - speaker.Name.c_str(), ChanDelay[chan].Length, ChanDelay[chan].Gain); - - /* Round up to the next 4th sample, so each channel buffer starts - * 16-byte aligned. - */ - total += RoundUp(ChanDelay[chan].Length, 4); - } - - if(total > 0) - { - device->ChannelDelay.setSampleCount(total); - ChanDelay[0].Buffer = device->ChannelDelay.getSamples(); - auto set_bufptr = [](const DistanceComp::DistData &last, const DistanceComp::DistData &cur) -> DistanceComp::DistData - { - DistanceComp::DistData ret{cur}; - ret.Buffer = last.Buffer + RoundUp(last.Length, 4); - return ret; - }; - std::partial_sum(ChanDelay.begin(), ChanDelay.end(), ChanDelay.begin(), set_bufptr); - } -} - - -auto GetAmbiScales(AmbiNorm scaletype) noexcept -> const std::array& -{ - if(scaletype == AmbiNorm::FuMa) return AmbiScale::FromFuMa; - if(scaletype == AmbiNorm::SN3D) return AmbiScale::FromSN3D; - return AmbiScale::FromN3D; -} - -auto GetAmbiLayout(AmbiLayout layouttype) noexcept -> const std::array& -{ - if(layouttype == AmbiLayout::FuMa) return AmbiIndex::FromFuMa; - return AmbiIndex::FromACN; -} - - -void InitPanning(ALCdevice *device) -{ - al::span chanmap; - ALuint coeffcount{}; - - switch(device->FmtChans) - { - case DevFmtMono: - chanmap = MonoCfg; - coeffcount = 1; - break; - - case DevFmtStereo: - chanmap = StereoCfg; - coeffcount = 3; - break; - - case DevFmtQuad: - chanmap = QuadCfg; - coeffcount = 3; - break; - - case DevFmtX51: - chanmap = X51SideCfg; - coeffcount = 5; - break; - - case DevFmtX51Rear: - chanmap = X51RearCfg; - coeffcount = 5; - break; - - case DevFmtX61: - chanmap = X61Cfg; - coeffcount = 5; - break; - - case DevFmtX71: - chanmap = X71Cfg; - coeffcount = 7; - break; - - case DevFmtAmbi3D: - break; - } - - if(device->FmtChans == DevFmtAmbi3D) - { - const char *devname{device->DeviceName.c_str()}; - const std::array &acnmap = GetAmbiLayout(device->mAmbiLayout); - const std::array &n3dscale = GetAmbiScales(device->mAmbiScale); - - /* For DevFmtAmbi3D, the ambisonic order is already set. */ - const size_t count{AmbiChannelsFromOrder(device->mAmbiOrder)}; - std::transform(acnmap.begin(), acnmap.begin()+count, std::begin(device->Dry.AmbiMap), - [&n3dscale](const ALsizei &acn) noexcept -> BFChannelConfig - { return BFChannelConfig{1.0f/n3dscale[acn], acn}; } - ); - AllocChannels(device, static_cast(count), 0); - - ALfloat nfc_delay{ConfigValueFloat(devname, "decoder", "nfc-ref-delay").value_or(0.0f)}; - if(nfc_delay > 0.0f) - { - static constexpr ALuint chans_per_order[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; - InitNearFieldCtrl(device, nfc_delay * SPEEDOFSOUNDMETRESPERSEC, device->mAmbiOrder, - chans_per_order); - } - } - else - { - ChannelDec chancoeffs[MAX_OUTPUT_CHANNELS]{}; - ALsizei idxmap[MAX_OUTPUT_CHANNELS]{}; - for(size_t i{0u};i < chanmap.size();++i) - { - const ALint idx{GetChannelIdxByName(device->RealOut, chanmap[i].ChanName)}; - if(idx < 0) - { - ERR("Failed to find %s channel in device\n", - GetLabelFromChannel(chanmap[i].ChanName)); - continue; - } - idxmap[i] = idx; - std::copy_n(chanmap[i].Config, coeffcount, chancoeffs[i]); - } - - /* For non-DevFmtAmbi3D, set the ambisonic order given the mixing - * channel count. Built-in speaker decoders are always 2D, so just - * reverse that calculation. - */ - device->mAmbiOrder = static_cast((coeffcount-1) / 2); - - std::transform(AmbiIndex::From2D.begin(), AmbiIndex::From2D.begin()+coeffcount, - std::begin(device->Dry.AmbiMap), - [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } - ); - AllocChannels(device, coeffcount, device->channelsFromFmt()); - - TRACE("Enabling %s-order%s ambisonic decoder\n", - (coeffcount > 5) ? "third" : - (coeffcount > 3) ? "second" : "first", - "" - ); - device->AmbiDecoder = al::make_unique(coeffcount, - static_cast(chanmap.size()), chancoeffs, idxmap); - } -} - -void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) -{ - static constexpr ALuint chans_per_order2d[MAX_AMBI_ORDER+1] = { 1, 2, 2, 2 }; - static constexpr ALuint chans_per_order3d[MAX_AMBI_ORDER+1] = { 1, 3, 5, 7 }; - - if(!hqdec && conf->FreqBands != 1) - ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n", - conf->XOverFreq); - - ALsizei order{(conf->ChanMask > AMBI_2ORDER_MASK) ? 3 : - (conf->ChanMask > AMBI_1ORDER_MASK) ? 2 : 1}; - device->mAmbiOrder = order; - - ALuint count; - if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) - { - count = static_cast(AmbiChannelsFromOrder(order)); - std::transform(AmbiIndex::From3D.begin(), AmbiIndex::From3D.begin()+count, - std::begin(device->Dry.AmbiMap), - [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } - ); - } - else - { - count = static_cast(Ambi2DChannelsFromOrder(order)); - std::transform(AmbiIndex::From2D.begin(), AmbiIndex::From2D.begin()+count, - std::begin(device->Dry.AmbiMap), - [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } - ); - } - AllocChannels(device, count, device->channelsFromFmt()); - - TRACE("Enabling %s-band %s-order%s ambisonic decoder\n", - (!hqdec || conf->FreqBands == 1) ? "single" : "dual", - (conf->ChanMask > AMBI_2ORDER_MASK) ? "third" : - (conf->ChanMask > AMBI_1ORDER_MASK) ? "second" : "first", - (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? " periphonic" : "" - ); - device->AmbiDecoder = al::make_unique(conf, hqdec, count, device->Frequency, - speakermap); - - auto accum_spkr_dist = std::bind(std::plus{}, _1, - std::bind(std::mem_fn(&AmbDecConf::SpeakerConf::Distance), _2)); - const ALfloat avg_dist{ - std::accumulate(conf->Speakers.begin(), conf->Speakers.end(), float{0.0f}, - accum_spkr_dist) / static_cast(conf->Speakers.size()) - }; - InitNearFieldCtrl(device, avg_dist, order, - (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? chans_per_order3d : chans_per_order2d); - - InitDistanceComp(device, conf, speakermap); -} - -void InitHrtfPanning(ALCdevice *device) -{ - /* NOTE: In degrees, and azimuth goes clockwise. */ - static constexpr AngularPoint AmbiPoints[]{ - { 35.264390f, -45.000000f }, - { 35.264390f, 45.000000f }, - { 35.264390f, 135.000000f }, - { 35.264390f, -135.000000f }, - { -35.264390f, -45.000000f }, - { -35.264390f, 45.000000f }, - { -35.264390f, 135.000000f }, - { -35.264390f, -135.000000f }, - { 0.000000f, -20.905157f }, - { 0.000000f, 20.905157f }, - { 0.000000f, 159.094843f }, - { 0.000000f, -159.094843f }, - { 20.905157f, -90.000000f }, - { -20.905157f, -90.000000f }, - { -20.905157f, 90.000000f }, - { 20.905157f, 90.000000f }, - { 69.094843f, 0.000000f }, - { -69.094843f, 0.000000f }, - { -69.094843f, 180.000000f }, - { 69.094843f, 180.000000f }, - }; - static constexpr ALfloat AmbiMatrix[][MAX_AMBI_CHANNELS]{ - { 5.00000000e-02f, 5.00000000e-02f, 5.00000000e-02f, 5.00000000e-02f, 6.45497224e-02f, 6.45497224e-02f, 0.00000000e+00f, 6.45497224e-02f, 0.00000000e+00f, 1.48264644e-02f, 6.33865691e-02f, 1.01126676e-01f, -7.36485380e-02f, -1.09260065e-02f, 7.08683387e-02f, -1.01622099e-01f }, - { 5.00000000e-02f, -5.00000000e-02f, 5.00000000e-02f, 5.00000000e-02f, -6.45497224e-02f, -6.45497224e-02f, 0.00000000e+00f, 6.45497224e-02f, 0.00000000e+00f, -1.48264644e-02f, -6.33865691e-02f, -1.01126676e-01f, -7.36485380e-02f, -1.09260065e-02f, 7.08683387e-02f, -1.01622099e-01f }, - { 5.00000000e-02f, -5.00000000e-02f, 5.00000000e-02f, -5.00000000e-02f, 6.45497224e-02f, -6.45497224e-02f, 0.00000000e+00f, -6.45497224e-02f, 0.00000000e+00f, -1.48264644e-02f, 6.33865691e-02f, -1.01126676e-01f, -7.36485380e-02f, 1.09260065e-02f, 7.08683387e-02f, 1.01622099e-01f }, - { 5.00000000e-02f, 5.00000000e-02f, 5.00000000e-02f, -5.00000000e-02f, -6.45497224e-02f, 6.45497224e-02f, 0.00000000e+00f, -6.45497224e-02f, 0.00000000e+00f, 1.48264644e-02f, -6.33865691e-02f, 1.01126676e-01f, -7.36485380e-02f, 1.09260065e-02f, 7.08683387e-02f, 1.01622099e-01f }, - { 5.00000000e-02f, 5.00000000e-02f, -5.00000000e-02f, 5.00000000e-02f, 6.45497224e-02f, -6.45497224e-02f, 0.00000000e+00f, -6.45497224e-02f, 0.00000000e+00f, 1.48264644e-02f, -6.33865691e-02f, 1.01126676e-01f, 7.36485380e-02f, -1.09260065e-02f, -7.08683387e-02f, -1.01622099e-01f }, - { 5.00000000e-02f, -5.00000000e-02f, -5.00000000e-02f, 5.00000000e-02f, -6.45497224e-02f, 6.45497224e-02f, 0.00000000e+00f, -6.45497224e-02f, 0.00000000e+00f, -1.48264644e-02f, 6.33865691e-02f, -1.01126676e-01f, 7.36485380e-02f, -1.09260065e-02f, -7.08683387e-02f, -1.01622099e-01f }, - { 5.00000000e-02f, -5.00000000e-02f, -5.00000000e-02f, -5.00000000e-02f, 6.45497224e-02f, 6.45497224e-02f, 0.00000000e+00f, 6.45497224e-02f, 0.00000000e+00f, -1.48264644e-02f, -6.33865691e-02f, -1.01126676e-01f, 7.36485380e-02f, 1.09260065e-02f, -7.08683387e-02f, 1.01622099e-01f }, - { 5.00000000e-02f, 5.00000000e-02f, -5.00000000e-02f, -5.00000000e-02f, -6.45497224e-02f, -6.45497224e-02f, 0.00000000e+00f, 6.45497224e-02f, 0.00000000e+00f, 1.48264644e-02f, 6.33865691e-02f, 1.01126676e-01f, 7.36485380e-02f, 1.09260065e-02f, -7.08683387e-02f, 1.01622099e-01f }, - { 5.00000000e-02f, 3.09016994e-02f, 0.00000000e+00f, 8.09016994e-02f, 6.45497224e-02f, 0.00000000e+00f, -5.59016994e-02f, 0.00000000e+00f, 7.21687836e-02f, 7.76323754e-02f, 0.00000000e+00f, -1.49775925e-01f, 0.00000000e+00f, -2.95083663e-02f, 0.00000000e+00f, 7.76323754e-02f }, - { 5.00000000e-02f, -3.09016994e-02f, 0.00000000e+00f, 8.09016994e-02f, -6.45497224e-02f, 0.00000000e+00f, -5.59016994e-02f, 0.00000000e+00f, 7.21687836e-02f, -7.76323754e-02f, 0.00000000e+00f, 1.49775925e-01f, 0.00000000e+00f, -2.95083663e-02f, 0.00000000e+00f, 7.76323754e-02f }, - { 5.00000000e-02f, -3.09016994e-02f, 0.00000000e+00f, -8.09016994e-02f, 6.45497224e-02f, 0.00000000e+00f, -5.59016994e-02f, 0.00000000e+00f, 7.21687836e-02f, -7.76323754e-02f, 0.00000000e+00f, 1.49775925e-01f, 0.00000000e+00f, 2.95083663e-02f, 0.00000000e+00f, -7.76323754e-02f }, - { 5.00000000e-02f, 3.09016994e-02f, 0.00000000e+00f, -8.09016994e-02f, -6.45497224e-02f, 0.00000000e+00f, -5.59016994e-02f, 0.00000000e+00f, 7.21687836e-02f, 7.76323754e-02f, 0.00000000e+00f, -1.49775925e-01f, 0.00000000e+00f, 2.95083663e-02f, 0.00000000e+00f, -7.76323754e-02f }, - { 5.00000000e-02f, 8.09016994e-02f, 3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 6.45497224e-02f, -3.45491503e-02f, 0.00000000e+00f, -8.44966837e-02f, -4.79794466e-02f, 0.00000000e+00f, -6.77901327e-02f, 3.03448665e-02f, 0.00000000e+00f, -1.65948192e-01f, 0.00000000e+00f }, - { 5.00000000e-02f, 8.09016994e-02f, -3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, -6.45497224e-02f, -3.45491503e-02f, 0.00000000e+00f, -8.44966837e-02f, -4.79794466e-02f, 0.00000000e+00f, -6.77901327e-02f, -3.03448665e-02f, 0.00000000e+00f, 1.65948192e-01f, 0.00000000e+00f }, - { 5.00000000e-02f, -8.09016994e-02f, -3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 6.45497224e-02f, -3.45491503e-02f, 0.00000000e+00f, -8.44966837e-02f, 4.79794466e-02f, 0.00000000e+00f, 6.77901327e-02f, -3.03448665e-02f, 0.00000000e+00f, 1.65948192e-01f, 0.00000000e+00f }, - { 5.00000000e-02f, -8.09016994e-02f, 3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, -6.45497224e-02f, -3.45491503e-02f, 0.00000000e+00f, -8.44966837e-02f, 4.79794466e-02f, 0.00000000e+00f, 6.77901327e-02f, 3.03448665e-02f, 0.00000000e+00f, -1.65948192e-01f, 0.00000000e+00f }, - { 5.00000000e-02f, 0.00000000e+00f, 8.09016994e-02f, 3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 9.04508497e-02f, 6.45497224e-02f, 1.23279000e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 7.94438918e-02f, 1.12611206e-01f, -2.42115150e-02f, 1.25611822e-01f }, - { 5.00000000e-02f, 0.00000000e+00f, -8.09016994e-02f, 3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 9.04508497e-02f, -6.45497224e-02f, 1.23279000e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -7.94438918e-02f, 1.12611206e-01f, 2.42115150e-02f, 1.25611822e-01f }, - { 5.00000000e-02f, 0.00000000e+00f, -8.09016994e-02f, -3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 9.04508497e-02f, 6.45497224e-02f, 1.23279000e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -7.94438918e-02f, -1.12611206e-01f, 2.42115150e-02f, -1.25611822e-01f }, - { 5.00000000e-02f, 0.00000000e+00f, 8.09016994e-02f, -3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 9.04508497e-02f, -6.45497224e-02f, 1.23279000e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 7.94438918e-02f, -1.12611206e-01f, -2.42115150e-02f, -1.25611822e-01f } - }; - static constexpr ALfloat AmbiOrderHFGain1O[MAX_AMBI_ORDER+1]{ - 3.16227766e+00f, 1.82574186e+00f - }, AmbiOrderHFGain2O[MAX_AMBI_ORDER+1]{ - 2.35702260e+00f, 1.82574186e+00f, 9.42809042e-01f - }, AmbiOrderHFGain3O[MAX_AMBI_ORDER+1]{ - 1.86508671e+00f, 1.60609389e+00f, 1.14205530e+00f, 5.68379553e-01f - }; - static constexpr ALuint ChansPerOrder[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; - const ALfloat *AmbiOrderHFGain{AmbiOrderHFGain1O}; - - static_assert(al::size(AmbiPoints) == al::size(AmbiMatrix), "Ambisonic HRTF mismatch"); - - /* Don't bother with HOA when using full HRTF rendering. Nothing needs it, - * and it eases the CPU/memory load. - */ - device->mRenderMode = HrtfRender; - ALsizei ambi_order{1}; - if(auto modeopt = ConfigValueStr(device->DeviceName.c_str(), nullptr, "hrtf-mode")) - { - const char *mode{modeopt->c_str()}; - if(strcasecmp(mode, "basic") == 0) - { - ERR("HRTF mode \"%s\" deprecated, substituting \"%s\"\n", mode, "ambi2"); - mode = "ambi2"; - } - - if(strcasecmp(mode, "full") == 0) - device->mRenderMode = HrtfRender; - else if(strcasecmp(mode, "ambi1") == 0) - { - device->mRenderMode = NormalRender; - ambi_order = 1; - } - else if(strcasecmp(mode, "ambi2") == 0) - { - device->mRenderMode = NormalRender; - ambi_order = 2; - } - else if(strcasecmp(mode, "ambi3") == 0) - { - device->mRenderMode = NormalRender; - ambi_order = 3; - } - else - ERR("Unexpected hrtf-mode: %s\n", mode); - } - TRACE("%s HRTF rendering enabled, using \"%s\"\n", - (device->mRenderMode == HrtfRender) ? "Full" : - (ambi_order >= 3) ? "Third-Order" : - (ambi_order == 2) ? "Second-Order" : - (ambi_order == 1) ? "First-Order" : "Unknown", - device->HrtfName.c_str()); - - if(ambi_order >= 3) - AmbiOrderHFGain = AmbiOrderHFGain3O; - else if(ambi_order == 2) - AmbiOrderHFGain = AmbiOrderHFGain2O; - else if(ambi_order == 1) - AmbiOrderHFGain = AmbiOrderHFGain1O; - device->mAmbiOrder = ambi_order; - - const size_t count{AmbiChannelsFromOrder(ambi_order)}; - device->mHrtfState = DirectHrtfState::Create(count); - - std::transform(AmbiIndex::From3D.begin(), AmbiIndex::From3D.begin()+count, - std::begin(device->Dry.AmbiMap), - [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } - ); - AllocChannels(device, static_cast(count), device->channelsFromFmt()); - - BuildBFormatHrtf(device->mHrtf, device->mHrtfState.get(), static_cast(count), - AmbiPoints, AmbiMatrix, al::size(AmbiPoints), AmbiOrderHFGain); - - HrtfEntry *Hrtf{device->mHrtf}; - InitNearFieldCtrl(device, Hrtf->field[0].distance, ambi_order, ChansPerOrder); -} - -void InitUhjPanning(ALCdevice *device) -{ - /* UHJ is always 2D first-order. */ - static constexpr size_t count{Ambi2DChannelsFromOrder(1)}; - - device->mAmbiOrder = 1; - - auto acnmap_end = AmbiIndex::FromFuMa.begin() + count; - std::transform(AmbiIndex::FromFuMa.begin(), acnmap_end, std::begin(device->Dry.AmbiMap), - [](const ALsizei &acn) noexcept -> BFChannelConfig - { return BFChannelConfig{1.0f/AmbiScale::FromFuMa[acn], acn}; } - ); - AllocChannels(device, ALuint{count}, device->channelsFromFmt()); -} - -} // namespace - -void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appreq, HrtfRequestMode hrtf_userreq) -{ - /* Hold the HRTF the device last used, in case it's used again. */ - HrtfEntry *old_hrtf{device->mHrtf}; - - device->mHrtfState = nullptr; - device->mHrtf = nullptr; - device->HrtfName.clear(); - device->mRenderMode = NormalRender; - - if(device->FmtChans != DevFmtStereo) - { - if(old_hrtf) - old_hrtf->DecRef(); - old_hrtf = nullptr; - if(hrtf_appreq == Hrtf_Enable) - device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; - - const char *layout{nullptr}; - switch(device->FmtChans) - { - case DevFmtQuad: layout = "quad"; break; - case DevFmtX51: /* fall-through */ - case DevFmtX51Rear: layout = "surround51"; break; - case DevFmtX61: layout = "surround61"; break; - case DevFmtX71: layout = "surround71"; break; - /* Mono, Stereo, and Ambisonics output don't use custom decoders. */ - case DevFmtMono: - case DevFmtStereo: - case DevFmtAmbi3D: - break; - } - - const char *devname{device->DeviceName.c_str()}; - ALsizei speakermap[MAX_OUTPUT_CHANNELS]; - AmbDecConf *pconf{nullptr}; - AmbDecConf conf{}; - if(layout) - { - if(auto decopt = ConfigValueStr(devname, "decoder", layout)) - { - if(!conf.load(decopt->c_str())) - ERR("Failed to load layout file %s\n", decopt->c_str()); - else if(conf.Speakers.size() > MAX_OUTPUT_CHANNELS) - ERR("Unsupported speaker count %zu (max %d)\n", conf.Speakers.size(), - MAX_OUTPUT_CHANNELS); - else if(conf.ChanMask > AMBI_3ORDER_MASK) - ERR("Unsupported channel mask 0x%04x (max 0x%x)\n", conf.ChanMask, - AMBI_3ORDER_MASK); - else if(MakeSpeakerMap(device, &conf, speakermap)) - pconf = &conf; - } - } - - if(!pconf) - InitPanning(device); - else - { - int hqdec{GetConfigValueBool(devname, "decoder", "hq-mode", 0)}; - InitCustomPanning(device, !!hqdec, pconf, speakermap); - } - if(device->AmbiDecoder) - device->PostProcess = ProcessAmbiDec; - return; - } - - bool headphones{device->IsHeadphones != AL_FALSE}; - if(device->Type != Loopback) - { - if(auto modeopt = ConfigValueStr(device->DeviceName.c_str(), nullptr, "stereo-mode")) - { - const char *mode{modeopt->c_str()}; - if(strcasecmp(mode, "headphones") == 0) - headphones = true; - else if(strcasecmp(mode, "speakers") == 0) - headphones = false; - else if(strcasecmp(mode, "auto") != 0) - ERR("Unexpected stereo-mode: %s\n", mode); - } - } - - if(hrtf_userreq == Hrtf_Default) - { - bool usehrtf = (headphones && hrtf_appreq != Hrtf_Disable) || - (hrtf_appreq == Hrtf_Enable); - if(!usehrtf) goto no_hrtf; - - device->HrtfStatus = ALC_HRTF_ENABLED_SOFT; - if(headphones && hrtf_appreq != Hrtf_Disable) - device->HrtfStatus = ALC_HRTF_HEADPHONES_DETECTED_SOFT; - } - else - { - if(hrtf_userreq != Hrtf_Enable) - { - if(hrtf_appreq == Hrtf_Enable) - device->HrtfStatus = ALC_HRTF_DENIED_SOFT; - goto no_hrtf; - } - device->HrtfStatus = ALC_HRTF_REQUIRED_SOFT; - } - - if(device->HrtfList.empty()) - device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); - - if(hrtf_id >= 0 && static_cast(hrtf_id) < device->HrtfList.size()) - { - const EnumeratedHrtf &entry = device->HrtfList[hrtf_id]; - HrtfEntry *hrtf{GetLoadedHrtf(entry.hrtf)}; - if(hrtf && hrtf->sampleRate == device->Frequency) - { - device->mHrtf = hrtf; - device->HrtfName = entry.name; - } - else if(hrtf) - hrtf->DecRef(); - } - - if(!device->mHrtf) - { - auto find_hrtf = [device](const EnumeratedHrtf &entry) -> bool - { - HrtfEntry *hrtf{GetLoadedHrtf(entry.hrtf)}; - if(!hrtf) return false; - if(hrtf->sampleRate != device->Frequency) - { - hrtf->DecRef(); - return false; - } - device->mHrtf = hrtf; - device->HrtfName = entry.name; - return true; - }; - std::find_if(device->HrtfList.cbegin(), device->HrtfList.cend(), find_hrtf); - } - - if(device->mHrtf) - { - if(old_hrtf) - old_hrtf->DecRef(); - old_hrtf = nullptr; - - InitHrtfPanning(device); - device->PostProcess = ProcessHrtf; - return; - } - device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; - -no_hrtf: - if(old_hrtf) - old_hrtf->DecRef(); - old_hrtf = nullptr; - - device->mRenderMode = StereoPair; - - if(device->Type != Loopback) - { - if(auto cflevopt = ConfigValueInt(device->DeviceName.c_str(), nullptr, "cf_level")) - { - if(*cflevopt > 0 && *cflevopt <= 6) - { - device->Bs2b = al::make_unique(); - bs2b_set_params(device->Bs2b.get(), *cflevopt, device->Frequency); - TRACE("BS2B enabled\n"); - InitPanning(device); - device->PostProcess = ProcessBs2b; - return; - } - } - } - - if(auto encopt = ConfigValueStr(device->DeviceName.c_str(), nullptr, "stereo-encoding")) - { - const char *mode{encopt->c_str()}; - if(strcasecmp(mode, "uhj") == 0) - device->mRenderMode = NormalRender; - else if(strcasecmp(mode, "panpot") != 0) - ERR("Unexpected stereo-encoding: %s\n", mode); - } - if(device->mRenderMode == NormalRender) - { - device->Uhj_Encoder = al::make_unique(); - TRACE("UHJ enabled\n"); - InitUhjPanning(device); - device->PostProcess = ProcessUhj; - return; - } - - TRACE("Stereo rendering\n"); - InitPanning(device); - device->PostProcess = ProcessAmbiDec; -} - - -void aluInitEffectPanning(ALeffectslot *slot, ALCdevice *device) -{ - const size_t count{AmbiChannelsFromOrder(device->mAmbiOrder)}; - slot->MixBuffer.resize(count); - slot->MixBuffer.shrink_to_fit(); - - auto acnmap_end = AmbiIndex::From3D.begin() + count; - auto iter = std::transform(AmbiIndex::From3D.begin(), acnmap_end, slot->Wet.AmbiMap.begin(), - [](const ALsizei &acn) noexcept -> BFChannelConfig - { return BFChannelConfig{1.0f, acn}; } - ); - std::fill(iter, slot->Wet.AmbiMap.end(), BFChannelConfig{}); - slot->Wet.Buffer = {slot->MixBuffer.data(), slot->MixBuffer.size()}; -} - - -void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread, - ALfloat (&coeffs)[MAX_AMBI_CHANNELS]) -{ - /* Zeroth-order */ - coeffs[0] = 1.0f; /* ACN 0 = 1 */ - /* First-order */ - coeffs[1] = 1.732050808f * y; /* ACN 1 = sqrt(3) * Y */ - coeffs[2] = 1.732050808f * z; /* ACN 2 = sqrt(3) * Z */ - coeffs[3] = 1.732050808f * x; /* ACN 3 = sqrt(3) * X */ - /* Second-order */ - coeffs[4] = 3.872983346f * x * y; /* ACN 4 = sqrt(15) * X * Y */ - coeffs[5] = 3.872983346f * y * z; /* ACN 5 = sqrt(15) * Y * Z */ - coeffs[6] = 1.118033989f * (z*z*3.0f - 1.0f); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */ - coeffs[7] = 3.872983346f * x * z; /* ACN 7 = sqrt(15) * X * Z */ - coeffs[8] = 1.936491673f * (x*x - y*y); /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */ - /* Third-order */ - coeffs[9] = 2.091650066f * y * (x*x*3.0f - y*y); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */ - coeffs[10] = 10.246950766f * z * x * y; /* ACN 10 = sqrt(105) * Z * X * Y */ - coeffs[11] = 1.620185175f * y * (z*z*5.0f - 1.0f); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */ - coeffs[12] = 1.322875656f * z * (z*z*5.0f - 3.0f); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */ - coeffs[13] = 1.620185175f * x * (z*z*5.0f - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */ - coeffs[14] = 5.123475383f * z * (x*x - y*y); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */ - coeffs[15] = 2.091650066f * x * (x*x - y*y*3.0f); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */ - /* Fourth-order */ - /* ACN 16 = sqrt(35)*3/2 * X * Y * (X*X - Y*Y) */ - /* ACN 17 = sqrt(35/2)*3/2 * (3*X*X - Y*Y) * Y * Z */ - /* ACN 18 = sqrt(5)*3/2 * X * Y * (7*Z*Z - 1) */ - /* ACN 19 = sqrt(5/2)*3/2 * Y * Z * (7*Z*Z - 3) */ - /* ACN 20 = 3/8 * (35*Z*Z*Z*Z - 30*Z*Z + 3) */ - /* ACN 21 = sqrt(5/2)*3/2 * X * Z * (7*Z*Z - 3) */ - /* ACN 22 = sqrt(5)*3/4 * (X*X - Y*Y) * (7*Z*Z - 1) */ - /* ACN 23 = sqrt(35/2)*3/2 * (X*X - 3*Y*Y) * X * Z */ - /* ACN 24 = sqrt(35)*3/8 * (X*X*X*X - 6*X*X*Y*Y + Y*Y*Y*Y) */ - - if(spread > 0.0f) - { - /* Implement the spread by using a spherical source that subtends the - * angle spread. See: - * http://www.ppsloan.org/publications/StupidSH36.pdf - Appendix A3 - * - * When adjusted for N3D normalization instead of SN3D, these - * calculations are: - * - * ZH0 = -sqrt(pi) * (-1+ca); - * ZH1 = 0.5*sqrt(pi) * sa*sa; - * ZH2 = -0.5*sqrt(pi) * ca*(-1+ca)*(ca+1); - * ZH3 = -0.125*sqrt(pi) * (-1+ca)*(ca+1)*(5*ca*ca - 1); - * ZH4 = -0.125*sqrt(pi) * ca*(-1+ca)*(ca+1)*(7*ca*ca - 3); - * ZH5 = -0.0625*sqrt(pi) * (-1+ca)*(ca+1)*(21*ca*ca*ca*ca - 14*ca*ca + 1); - * - * The gain of the source is compensated for size, so that the - * loudness doesn't depend on the spread. Thus: - * - * ZH0 = 1.0f; - * ZH1 = 0.5f * (ca+1.0f); - * ZH2 = 0.5f * (ca+1.0f)*ca; - * ZH3 = 0.125f * (ca+1.0f)*(5.0f*ca*ca - 1.0f); - * ZH4 = 0.125f * (ca+1.0f)*(7.0f*ca*ca - 3.0f)*ca; - * ZH5 = 0.0625f * (ca+1.0f)*(21.0f*ca*ca*ca*ca - 14.0f*ca*ca + 1.0f); - */ - ALfloat ca = std::cos(spread * 0.5f); - /* Increase the source volume by up to +3dB for a full spread. */ - ALfloat scale = std::sqrt(1.0f + spread/al::MathDefs::Tau()); - - ALfloat ZH0_norm = scale; - ALfloat ZH1_norm = 0.5f * (ca+1.f) * scale; - ALfloat ZH2_norm = 0.5f * (ca+1.f)*ca * scale; - ALfloat ZH3_norm = 0.125f * (ca+1.f)*(5.f*ca*ca-1.f) * scale; - - /* Zeroth-order */ - coeffs[0] *= ZH0_norm; - /* First-order */ - coeffs[1] *= ZH1_norm; - coeffs[2] *= ZH1_norm; - coeffs[3] *= ZH1_norm; - /* Second-order */ - coeffs[4] *= ZH2_norm; - coeffs[5] *= ZH2_norm; - coeffs[6] *= ZH2_norm; - coeffs[7] *= ZH2_norm; - coeffs[8] *= ZH2_norm; - /* Third-order */ - coeffs[9] *= ZH3_norm; - coeffs[10] *= ZH3_norm; - coeffs[11] *= ZH3_norm; - coeffs[12] *= ZH3_norm; - coeffs[13] *= ZH3_norm; - coeffs[14] *= ZH3_norm; - coeffs[15] *= ZH3_norm; - } -} - -void ComputePanGains(const MixParams *mix, const ALfloat *RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) -{ - auto ambimap = mix->AmbiMap.cbegin(); - - auto iter = std::transform(ambimap, ambimap+mix->Buffer.size(), std::begin(gains), - [coeffs,ingain](const BFChannelConfig &chanmap) noexcept -> ALfloat - { - ASSUME(chanmap.Index >= 0); - return chanmap.Scale * coeffs[chanmap.Index] * ingain; - } - ); - std::fill(iter, std::end(gains), 0.0f); -} diff --git a/Alc/ringbuffer.cpp b/Alc/ringbuffer.cpp deleted file mode 100644 index 6ef576a5..00000000 --- a/Alc/ringbuffer.cpp +++ /dev/null @@ -1,253 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include - -#include "ringbuffer.h" -#include "atomic.h" -#include "threads.h" -#include "almalloc.h" -#include "compat.h" - - -RingBufferPtr CreateRingBuffer(size_t sz, size_t elem_sz, int limit_writes) -{ - size_t power_of_two{0u}; - if(sz > 0) - { - power_of_two = sz; - power_of_two |= power_of_two>>1; - power_of_two |= power_of_two>>2; - power_of_two |= power_of_two>>4; - power_of_two |= power_of_two>>8; - power_of_two |= power_of_two>>16; -#if SIZE_MAX > UINT_MAX - power_of_two |= power_of_two>>32; -#endif - } - ++power_of_two; - if(power_of_two < sz) return nullptr; - - const size_t bufbytes{power_of_two * elem_sz}; - RingBufferPtr rb{new (al_calloc(16, sizeof(*rb) + bufbytes)) RingBuffer{bufbytes}}; - rb->mWriteSize = limit_writes ? sz : (power_of_two-1); - rb->mSizeMask = power_of_two - 1; - rb->mElemSize = elem_sz; - - return rb; -} - -void RingBuffer::reset() noexcept -{ - mWritePtr.store(0, std::memory_order_relaxed); - mReadPtr.store(0, std::memory_order_relaxed); - std::fill_n(mBuffer.begin(), (mSizeMask+1)*mElemSize, al::byte{}); -} - - -size_t RingBuffer::readSpace() const noexcept -{ - size_t w = mWritePtr.load(std::memory_order_acquire); - size_t r = mReadPtr.load(std::memory_order_acquire); - return (w-r) & mSizeMask; -} - -size_t RingBuffer::writeSpace() const noexcept -{ - size_t w = mWritePtr.load(std::memory_order_acquire); - size_t r = mReadPtr.load(std::memory_order_acquire) + mWriteSize - mSizeMask; - return (r-w-1) & mSizeMask; -} - - -size_t RingBuffer::read(void *dest, size_t cnt) noexcept -{ - const size_t free_cnt{readSpace()}; - if(free_cnt == 0) return 0; - - const size_t to_read{std::min(cnt, free_cnt)}; - size_t read_ptr{mReadPtr.load(std::memory_order_relaxed) & mSizeMask}; - - size_t n1, n2; - const size_t cnt2{read_ptr + to_read}; - if(cnt2 > mSizeMask+1) - { - n1 = mSizeMask+1 - read_ptr; - n2 = cnt2 & mSizeMask; - } - else - { - n1 = to_read; - n2 = 0; - } - - auto outiter = std::copy_n(mBuffer.begin() + read_ptr*mElemSize, n1*mElemSize, - static_cast(dest)); - read_ptr += n1; - if(n2 > 0) - { - std::copy_n(mBuffer.begin(), n2*mElemSize, outiter); - read_ptr += n2; - } - mReadPtr.store(read_ptr, std::memory_order_release); - return to_read; -} - -size_t RingBuffer::peek(void *dest, size_t cnt) const noexcept -{ - const size_t free_cnt{readSpace()}; - if(free_cnt == 0) return 0; - - const size_t to_read{std::min(cnt, free_cnt)}; - size_t read_ptr{mReadPtr.load(std::memory_order_relaxed) & mSizeMask}; - - size_t n1, n2; - const size_t cnt2{read_ptr + to_read}; - if(cnt2 > mSizeMask+1) - { - n1 = mSizeMask+1 - read_ptr; - n2 = cnt2 & mSizeMask; - } - else - { - n1 = to_read; - n2 = 0; - } - - auto outiter = std::copy_n(mBuffer.begin() + read_ptr*mElemSize, n1*mElemSize, - static_cast(dest)); - if(n2 > 0) - std::copy_n(mBuffer.begin(), n2*mElemSize, outiter); - return to_read; -} - -size_t RingBuffer::write(const void *src, size_t cnt) noexcept -{ - const size_t free_cnt{writeSpace()}; - if(free_cnt == 0) return 0; - - const size_t to_write{std::min(cnt, free_cnt)}; - size_t write_ptr{mWritePtr.load(std::memory_order_relaxed) & mSizeMask}; - - size_t n1, n2; - const size_t cnt2{write_ptr + to_write}; - if(cnt2 > mSizeMask+1) - { - n1 = mSizeMask+1 - write_ptr; - n2 = cnt2 & mSizeMask; - } - else - { - n1 = to_write; - n2 = 0; - } - - auto srcbytes = static_cast(src); - std::copy_n(srcbytes, n1*mElemSize, mBuffer.begin() + write_ptr*mElemSize); - write_ptr += n1; - if(n2 > 0) - { - std::copy_n(srcbytes + n1*mElemSize, n2*mElemSize, mBuffer.begin()); - write_ptr += n2; - } - mWritePtr.store(write_ptr, std::memory_order_release); - return to_write; -} - - -void RingBuffer::readAdvance(size_t cnt) noexcept -{ - mReadPtr.fetch_add(cnt, std::memory_order_acq_rel); -} - -void RingBuffer::writeAdvance(size_t cnt) noexcept -{ - mWritePtr.fetch_add(cnt, std::memory_order_acq_rel); -} - - -ll_ringbuffer_data_pair RingBuffer::getReadVector() const noexcept -{ - ll_ringbuffer_data_pair ret; - - size_t w{mWritePtr.load(std::memory_order_acquire)}; - size_t r{mReadPtr.load(std::memory_order_acquire)}; - w &= mSizeMask; - r &= mSizeMask; - const size_t free_cnt{(w-r) & mSizeMask}; - - const size_t cnt2{r + free_cnt}; - if(cnt2 > mSizeMask+1) - { - /* Two part vector: the rest of the buffer after the current read ptr, - * plus some from the start of the buffer. */ - ret.first.buf = const_cast(mBuffer.data() + r*mElemSize); - ret.first.len = mSizeMask+1 - r; - ret.second.buf = const_cast(mBuffer.data()); - ret.second.len = cnt2 & mSizeMask; - } - else - { - /* Single part vector: just the rest of the buffer */ - ret.first.buf = const_cast(mBuffer.data() + r*mElemSize); - ret.first.len = free_cnt; - ret.second.buf = nullptr; - ret.second.len = 0; - } - - return ret; -} - -ll_ringbuffer_data_pair RingBuffer::getWriteVector() const noexcept -{ - ll_ringbuffer_data_pair ret; - - size_t w{mWritePtr.load(std::memory_order_acquire)}; - size_t r{mReadPtr.load(std::memory_order_acquire) + mWriteSize - mSizeMask}; - w &= mSizeMask; - r &= mSizeMask; - const size_t free_cnt{(r-w-1) & mSizeMask}; - - const size_t cnt2{w + free_cnt}; - if(cnt2 > mSizeMask+1) - { - /* Two part vector: the rest of the buffer after the current write ptr, - * plus some from the start of the buffer. */ - ret.first.buf = const_cast(mBuffer.data() + w*mElemSize); - ret.first.len = mSizeMask+1 - w; - ret.second.buf = const_cast(mBuffer.data()); - ret.second.len = cnt2 & mSizeMask; - } - else - { - ret.first.buf = const_cast(mBuffer.data() + w*mElemSize); - ret.first.len = free_cnt; - ret.second.buf = nullptr; - ret.second.len = 0; - } - - return ret; -} diff --git a/Alc/ringbuffer.h b/Alc/ringbuffer.h deleted file mode 100644 index 84139b66..00000000 --- a/Alc/ringbuffer.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef RINGBUFFER_H -#define RINGBUFFER_H - -#include - -#include -#include -#include - -#include "albyte.h" -#include "almalloc.h" - - -/* NOTE: This lockless ringbuffer implementation is copied from JACK, extended - * to include an element size. Consequently, parameters and return values for a - * size or count is in 'elements', not bytes. Additionally, it only supports - * single-consumer/single-provider operation. - */ - -struct ll_ringbuffer_data { - al::byte *buf; - size_t len; -}; -using ll_ringbuffer_data_pair = std::pair; - - -struct RingBuffer { - std::atomic mWritePtr{0u}; - std::atomic mReadPtr{0u}; - size_t mWriteSize{0u}; - size_t mSizeMask{0u}; - size_t mElemSize{0u}; - - al::FlexArray mBuffer; - - RingBuffer(const size_t count) : mBuffer{count} { } - RingBuffer(const RingBuffer&) = delete; - RingBuffer& operator=(const RingBuffer&) = delete; - - /** Reset the read and write pointers to zero. This is not thread safe. */ - void reset() noexcept; - - /** - * The non-copying data reader. Returns two ringbuffer data pointers that - * hold the current readable data. If the readable data is in one segment - * the second segment has zero length. - */ - ll_ringbuffer_data_pair getReadVector() const noexcept; - /** - * The non-copying data writer. Returns two ringbuffer data pointers that - * hold the current writeable data. If the writeable data is in one segment - * the second segment has zero length. - */ - ll_ringbuffer_data_pair getWriteVector() const noexcept; - - /** - * Return the number of elements available for reading. This is the number - * of elements in front of the read pointer and behind the write pointer. - */ - size_t readSpace() const noexcept; - /** - * The copying data reader. Copy at most `cnt' elements into `dest'. - * Returns the actual number of elements copied. - */ - size_t read(void *dest, size_t cnt) noexcept; - /** - * The copying data reader w/o read pointer advance. Copy at most `cnt' - * elements into `dest'. Returns the actual number of elements copied. - */ - size_t peek(void *dest, size_t cnt) const noexcept; - /** Advance the read pointer `cnt' places. */ - void readAdvance(size_t cnt) noexcept; - - /** - * Return the number of elements available for writing. This is the number - * of elements in front of the write pointer and behind the read pointer. - */ - size_t writeSpace() const noexcept; - /** - * The copying data writer. Copy at most `cnt' elements from `src'. Returns - * the actual number of elements copied. - */ - size_t write(const void *src, size_t cnt) noexcept; - /** Advance the write pointer `cnt' places. */ - void writeAdvance(size_t cnt) noexcept; - - DEF_PLACE_NEWDEL() -}; -using RingBufferPtr = std::unique_ptr; - - -/** - * Create a new ringbuffer to hold at least `sz' elements of `elem_sz' bytes. - * The number of elements is rounded up to the next power of two (even if it is - * already a power of two, to ensure the requested amount can be written). - */ -RingBufferPtr CreateRingBuffer(size_t sz, size_t elem_sz, int limit_writes); - -#endif /* RINGBUFFER_H */ diff --git a/Alc/uhjfilter.cpp b/Alc/uhjfilter.cpp deleted file mode 100644 index 55999647..00000000 --- a/Alc/uhjfilter.cpp +++ /dev/null @@ -1,131 +0,0 @@ - -#include "config.h" - -#include "uhjfilter.h" - -#include - -#include "alu.h" - -namespace { - -/* This is the maximum number of samples processed for each inner loop - * iteration. */ -#define MAX_UPDATE_SAMPLES 128 - - -constexpr ALfloat Filter1CoeffSqr[4] = { - 0.479400865589f, 0.876218493539f, 0.976597589508f, 0.997499255936f -}; -constexpr ALfloat Filter2CoeffSqr[4] = { - 0.161758498368f, 0.733028932341f, 0.945349700329f, 0.990599156685f -}; - -void allpass_process(AllPassState *state, ALfloat *dst, const ALfloat *src, const ALfloat aa, ALsizei todo) -{ - ALfloat z1{state->z[0]}; - ALfloat z2{state->z[1]}; - auto proc_sample = [aa,&z1,&z2](ALfloat input) noexcept -> ALfloat - { - ALfloat output = input*aa + z1; - z1 = z2; z2 = output*aa - input; - return output; - }; - std::transform(src, src+todo, dst, proc_sample); - state->z[0] = z1; - state->z[1] = z2; -} - -} // namespace - - -/* NOTE: There seems to be a bit of an inconsistency in how this encoding is - * supposed to work. Some references, such as - * - * http://members.tripod.com/martin_leese/Ambisonic/UHJ_file_format.html - * - * specify a pre-scaling of sqrt(2) on the W channel input, while other - * references, such as - * - * https://en.wikipedia.org/wiki/Ambisonic_UHJ_format#Encoding.5B1.5D - * and - * https://wiki.xiph.org/Ambisonics#UHJ_format - * - * do not. The sqrt(2) scaling is in line with B-Format decoder coefficients - * which include such a scaling for the W channel input, however the original - * source for this equation is a 1985 paper by Michael Gerzon, which does not - * apparently include the scaling. Applying the extra scaling creates a louder - * result with a narrower stereo image compared to not scaling, and I don't - * know which is the intended result. - */ - -void Uhj2Encoder::encode(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, FloatBufferLine *InSamples, const ALsizei SamplesToDo) -{ - alignas(16) ALfloat D[MAX_UPDATE_SAMPLES], S[MAX_UPDATE_SAMPLES]; - alignas(16) ALfloat temp[MAX_UPDATE_SAMPLES]; - - ASSUME(SamplesToDo > 0); - - auto winput = InSamples[0].cbegin(); - auto xinput = InSamples[1].cbegin(); - auto yinput = InSamples[2].cbegin(); - for(ALsizei base{0};base < SamplesToDo;) - { - const ALsizei todo{mini(SamplesToDo - base, MAX_UPDATE_SAMPLES)}; - ASSUME(todo > 0); - - /* D = 0.6554516*Y */ - std::transform(yinput, yinput+todo, std::begin(temp), - [](const float y) noexcept -> float { return 0.6554516f*y; }); - allpass_process(&mFilter1_Y[0], temp, temp, Filter1CoeffSqr[0], todo); - allpass_process(&mFilter1_Y[1], temp, temp, Filter1CoeffSqr[1], todo); - allpass_process(&mFilter1_Y[2], temp, temp, Filter1CoeffSqr[2], todo); - allpass_process(&mFilter1_Y[3], temp, temp, Filter1CoeffSqr[3], todo); - /* NOTE: Filter1 requires a 1 sample delay for the final output, so - * take the last processed sample from the previous run as the first - * output sample. - */ - D[0] = mLastY; - for(ALsizei i{1};i < todo;i++) - D[i] = temp[i-1]; - mLastY = temp[todo-1]; - - /* D += j(-0.3420201*W + 0.5098604*X) */ - std::transform(winput, winput+todo, xinput, std::begin(temp), - [](const float w, const float x) noexcept -> float - { return -0.3420201f*w + 0.5098604f*x; }); - allpass_process(&mFilter2_WX[0], temp, temp, Filter2CoeffSqr[0], todo); - allpass_process(&mFilter2_WX[1], temp, temp, Filter2CoeffSqr[1], todo); - allpass_process(&mFilter2_WX[2], temp, temp, Filter2CoeffSqr[2], todo); - allpass_process(&mFilter2_WX[3], temp, temp, Filter2CoeffSqr[3], todo); - for(ALsizei i{0};i < todo;i++) - D[i] += temp[i]; - - /* S = 0.9396926*W + 0.1855740*X */ - std::transform(winput, winput+todo, xinput, std::begin(temp), - [](const float w, const float x) noexcept -> float - { return 0.9396926f*w + 0.1855740f*x; }); - allpass_process(&mFilter1_WX[0], temp, temp, Filter1CoeffSqr[0], todo); - allpass_process(&mFilter1_WX[1], temp, temp, Filter1CoeffSqr[1], todo); - allpass_process(&mFilter1_WX[2], temp, temp, Filter1CoeffSqr[2], todo); - allpass_process(&mFilter1_WX[3], temp, temp, Filter1CoeffSqr[3], todo); - S[0] = mLastWX; - for(ALsizei i{1};i < todo;i++) - S[i] = temp[i-1]; - mLastWX = temp[todo-1]; - - /* Left = (S + D)/2.0 */ - ALfloat *RESTRICT left = al::assume_aligned<16>(LeftOut.data()+base); - for(ALsizei i{0};i < todo;i++) - left[i] += (S[i] + D[i]) * 0.5f; - /* Right = (S - D)/2.0 */ - ALfloat *RESTRICT right = al::assume_aligned<16>(RightOut.data()+base); - for(ALsizei i{0};i < todo;i++) - right[i] += (S[i] - D[i]) * 0.5f; - - winput += todo; - xinput += todo; - yinput += todo; - base += todo; - } -} diff --git a/Alc/uhjfilter.h b/Alc/uhjfilter.h deleted file mode 100644 index 53e4f89e..00000000 --- a/Alc/uhjfilter.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef UHJFILTER_H -#define UHJFILTER_H - -#include "AL/al.h" - -#include "alcmain.h" -#include "almalloc.h" - - -struct AllPassState { - ALfloat z[2]{0.0f, 0.0f}; -}; - -/* Encoding 2-channel UHJ from B-Format is done as: - * - * S = 0.9396926*W + 0.1855740*X - * D = j(-0.3420201*W + 0.5098604*X) + 0.6554516*Y - * - * Left = (S + D)/2.0 - * Right = (S - D)/2.0 - * - * where j is a wide-band +90 degree phase shift. - * - * The phase shift is done using a Hilbert transform, described here: - * https://web.archive.org/web/20060708031958/http://www.biochem.oulu.fi/~oniemita/dsp/hilbert/ - * It works using 2 sets of 4 chained filters. The first filter chain produces - * a phase shift of varying magnitude over a wide range of frequencies, while - * the second filter chain produces a phase shift 90 degrees ahead of the - * first over the same range. - * - * Combining these two stages requires the use of three filter chains. S- - * channel output uses a Filter1 chain on the W and X channel mix, while the D- - * channel output uses a Filter1 chain on the Y channel plus a Filter2 chain on - * the W and X channel mix. This results in the W and X input mix on the D- - * channel output having the required +90 degree phase shift relative to the - * other inputs. - */ - -struct Uhj2Encoder { - AllPassState mFilter1_Y[4]; - AllPassState mFilter2_WX[4]; - AllPassState mFilter1_WX[4]; - ALfloat mLastY{0.0f}, mLastWX{0.0f}; - - /* Encodes a 2-channel UHJ (stereo-compatible) signal from a B-Format input - * signal. The input must use FuMa channel ordering and scaling. - */ - void encode(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, FloatBufferLine *InSamples, - const ALsizei SamplesToDo); - - DEF_NEWDEL(Uhj2Encoder) -}; - -#endif /* UHJFILTER_H */ diff --git a/Alc/vector.h b/Alc/vector.h deleted file mode 100644 index 1b69d6a7..00000000 --- a/Alc/vector.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef AL_VECTOR_H -#define AL_VECTOR_H - -#include - -#include "almalloc.h" - -namespace al { - -template -using vector = std::vector>; - -} // namespace al - -#endif /* AL_VECTOR_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 0bedc4f3..190692c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -638,62 +638,62 @@ SET(OPENAL_OBJS OpenAL32/event.cpp ) SET(ALC_OBJS - Alc/alc.cpp - Alc/alcmain.h - Alc/alu.cpp - Alc/alu.h - Alc/alconfig.cpp - Alc/alconfig.h - Alc/alcontext.h - Alc/ambidefs.h - Alc/bs2b.cpp - Alc/bs2b.h - Alc/converter.cpp - Alc/converter.h - Alc/inprogext.h - Alc/mastering.cpp - Alc/mastering.h - Alc/ringbuffer.cpp - Alc/ringbuffer.h - Alc/effects/base.h - Alc/effects/autowah.cpp - Alc/effects/chorus.cpp - Alc/effects/compressor.cpp - Alc/effects/dedicated.cpp - Alc/effects/distortion.cpp - Alc/effects/echo.cpp - Alc/effects/equalizer.cpp - Alc/effects/fshifter.cpp - Alc/effects/modulator.cpp - Alc/effects/null.cpp - Alc/effects/pshifter.cpp - Alc/effects/reverb.cpp - Alc/effects/vmorpher.cpp - Alc/filters/biquad.h - Alc/filters/biquad.cpp - Alc/filters/nfc.cpp - Alc/filters/nfc.h - Alc/filters/splitter.cpp - Alc/filters/splitter.h - Alc/helpers.cpp - Alc/compat.h - Alc/cpu_caps.h - Alc/fpu_modes.h - Alc/logging.h - Alc/vector.h - Alc/hrtf.cpp - Alc/hrtf.h - Alc/uhjfilter.cpp - Alc/uhjfilter.h - Alc/ambdec.cpp - Alc/ambdec.h - Alc/bformatdec.cpp - Alc/bformatdec.h - Alc/panning.cpp - Alc/mixvoice.cpp - Alc/mixer/defs.h - Alc/mixer/hrtfbase.h - Alc/mixer/mixer_c.cpp + alc/alc.cpp + alc/alcmain.h + alc/alu.cpp + alc/alu.h + alc/alconfig.cpp + alc/alconfig.h + alc/alcontext.h + alc/ambidefs.h + alc/bs2b.cpp + alc/bs2b.h + alc/converter.cpp + alc/converter.h + alc/inprogext.h + alc/mastering.cpp + alc/mastering.h + alc/ringbuffer.cpp + alc/ringbuffer.h + alc/effects/base.h + alc/effects/autowah.cpp + alc/effects/chorus.cpp + alc/effects/compressor.cpp + alc/effects/dedicated.cpp + alc/effects/distortion.cpp + alc/effects/echo.cpp + alc/effects/equalizer.cpp + alc/effects/fshifter.cpp + alc/effects/modulator.cpp + alc/effects/null.cpp + alc/effects/pshifter.cpp + alc/effects/reverb.cpp + alc/effects/vmorpher.cpp + alc/filters/biquad.h + alc/filters/biquad.cpp + alc/filters/nfc.cpp + alc/filters/nfc.h + alc/filters/splitter.cpp + alc/filters/splitter.h + alc/helpers.cpp + alc/compat.h + alc/cpu_caps.h + alc/fpu_modes.h + alc/logging.h + alc/vector.h + alc/hrtf.cpp + alc/hrtf.h + alc/uhjfilter.cpp + alc/uhjfilter.h + alc/ambdec.cpp + alc/ambdec.h + alc/bformatdec.cpp + alc/bformatdec.h + alc/panning.cpp + alc/mixvoice.cpp + alc/mixer/defs.h + alc/mixer/hrtfbase.h + alc/mixer/mixer_c.cpp ) @@ -713,9 +713,9 @@ IF(HAVE_XMMINTRIN_H AND HAVE_EMMINTRIN_H) IF(ALSOFT_CPUEXT_SSE AND ALSOFT_CPUEXT_SSE2) SET(HAVE_SSE 1) SET(HAVE_SSE2 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse.cpp Alc/mixer/mixer_sse2.cpp) + SET(ALC_OBJS ${ALC_OBJS} alc/mixer/mixer_sse.cpp alc/mixer/mixer_sse2.cpp) IF(SSE2_SWITCH) - SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse.cpp Alc/mixer/mixer_sse2.cpp + SET_SOURCE_FILES_PROPERTIES(alc/mixer/mixer_sse.cpp alc/mixer/mixer_sse2.cpp PROPERTIES COMPILE_FLAGS "${SSE2_SWITCH}") ENDIF() SET(CPU_EXTS "${CPU_EXTS}, SSE, SSE2") @@ -733,9 +733,9 @@ IF(HAVE_EMMINTRIN_H) OPTION(ALSOFT_CPUEXT_SSE3 "Enable SSE3 support" ON) IF(HAVE_SSE2 AND ALSOFT_CPUEXT_SSE3) SET(HAVE_SSE3 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse3.cpp) + SET(ALC_OBJS ${ALC_OBJS} alc/mixer/mixer_sse3.cpp) IF(SSE2_SWITCH) - SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse3.cpp PROPERTIES + SET_SOURCE_FILES_PROPERTIES(alc/mixer/mixer_sse3.cpp PROPERTIES COMPILE_FLAGS "${SSE3_SWITCH}") ENDIF() SET(CPU_EXTS "${CPU_EXTS}, SSE3") @@ -750,9 +750,9 @@ IF(HAVE_SMMINTRIN_H) OPTION(ALSOFT_CPUEXT_SSE4_1 "Enable SSE4.1 support" ON) IF(HAVE_SSE3 AND ALSOFT_CPUEXT_SSE4_1) SET(HAVE_SSE4_1 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse41.cpp) + SET(ALC_OBJS ${ALC_OBJS} alc/mixer/mixer_sse41.cpp) IF(SSE4_1_SWITCH) - SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse41.cpp PROPERTIES + SET_SOURCE_FILES_PROPERTIES(alc/mixer/mixer_sse41.cpp PROPERTIES COMPILE_FLAGS "${SSE4_1_SWITCH}") ENDIF() SET(CPU_EXTS "${CPU_EXTS}, SSE4.1") @@ -768,9 +768,9 @@ IF(HAVE_ARM_NEON_H) OPTION(ALSOFT_CPUEXT_NEON "Enable ARM Neon support" ON) IF(ALSOFT_CPUEXT_NEON) SET(HAVE_NEON 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_neon.cpp) + SET(ALC_OBJS ${ALC_OBJS} alc/mixer/mixer_neon.cpp) IF(FPU_NEON_SWITCH) - SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_neon.cpp PROPERTIES + SET_SOURCE_FILES_PROPERTIES(alc/mixer/mixer_neon.cpp PROPERTIES COMPILE_FLAGS "${FPU_NEON_SWITCH}") ENDIF() SET(CPU_EXTS "${CPU_EXTS}, Neon") @@ -809,13 +809,13 @@ ENDIF() SET(BACKENDS "") SET(ALC_OBJS ${ALC_OBJS} - Alc/backends/base.cpp - Alc/backends/base.h + alc/backends/base.cpp + alc/backends/base.h # Default backends, always available - Alc/backends/loopback.cpp - Alc/backends/loopback.h - Alc/backends/null.cpp - Alc/backends/null.h + alc/backends/loopback.cpp + alc/backends/loopback.h + alc/backends/null.cpp + alc/backends/null.h ) # Check ALSA backend @@ -826,7 +826,7 @@ IF(ALSA_FOUND) IF(ALSOFT_BACKEND_ALSA) SET(HAVE_ALSA 1) SET(BACKENDS "${BACKENDS} ALSA${IS_LINKED},") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/alsa.cpp Alc/backends/alsa.h) + SET(ALC_OBJS ${ALC_OBJS} alc/backends/alsa.cpp alc/backends/alsa.h) ADD_BACKEND_LIBS(${ALSA_LIBRARIES}) SET(INC_PATHS ${INC_PATHS} ${ALSA_INCLUDE_DIRS}) ENDIF() @@ -843,7 +843,7 @@ IF(OSS_FOUND) IF(ALSOFT_BACKEND_OSS) SET(HAVE_OSS 1) SET(BACKENDS "${BACKENDS} OSS,") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/oss.cpp Alc/backends/oss.h) + SET(ALC_OBJS ${ALC_OBJS} alc/backends/oss.cpp alc/backends/oss.h) IF(OSS_LIBRARIES) SET(EXTRA_LIBS ${OSS_LIBRARIES} ${EXTRA_LIBS}) ENDIF() @@ -862,7 +862,7 @@ IF(AUDIOIO_FOUND) IF(ALSOFT_BACKEND_SOLARIS) SET(HAVE_SOLARIS 1) SET(BACKENDS "${BACKENDS} Solaris,") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/solaris.cpp Alc/backends/solaris.h) + SET(ALC_OBJS ${ALC_OBJS} alc/backends/solaris.cpp alc/backends/solaris.h) SET(INC_PATHS ${INC_PATHS} ${AUDIOIO_INCLUDE_DIRS}) ENDIF() ENDIF() @@ -878,7 +878,7 @@ IF(SOUNDIO_FOUND) IF(ALSOFT_BACKEND_SNDIO) SET(HAVE_SNDIO 1) SET(BACKENDS "${BACKENDS} SndIO (linked),") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/sndio.cpp Alc/backends/sndio.h) + SET(ALC_OBJS ${ALC_OBJS} alc/backends/sndio.cpp alc/backends/sndio.h) SET(EXTRA_LIBS ${SOUNDIO_LIBRARIES} ${EXTRA_LIBS}) SET(INC_PATHS ${INC_PATHS} ${SOUNDIO_INCLUDE_DIRS}) ENDIF() @@ -895,7 +895,7 @@ IF(QSA_FOUND) IF(ALSOFT_BACKEND_QSA) SET(HAVE_QSA 1) SET(BACKENDS "${BACKENDS} QSA (linked),") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/qsa.cpp Alc/backends/qsa.h) + SET(ALC_OBJS ${ALC_OBJS} alc/backends/qsa.cpp alc/backends/qsa.h) SET(EXTRA_LIBS ${QSA_LIBRARIES} ${EXTRA_LIBS}) SET(INC_PATHS ${INC_PATHS} ${QSA_INCLUDE_DIRS}) ENDIF() @@ -930,7 +930,7 @@ IF(WIN32) IF(ALSOFT_BACKEND_WINMM) SET(HAVE_WINMM 1) SET(BACKENDS "${BACKENDS} WinMM,") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/winmm.cpp Alc/backends/winmm.h) + SET(ALC_OBJS ${ALC_OBJS} alc/backends/winmm.cpp alc/backends/winmm.h) SET(EXTRA_LIBS ${WINMM_LIBRARY} ${EXTRA_LIBS}) ENDIF() ENDIF() @@ -942,7 +942,7 @@ IF(WIN32) IF(ALSOFT_BACKEND_DSOUND) SET(HAVE_DSOUND 1) SET(BACKENDS "${BACKENDS} DirectSound${IS_LINKED},") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/dsound.cpp Alc/backends/dsound.h) + SET(ALC_OBJS ${ALC_OBJS} alc/backends/dsound.cpp alc/backends/dsound.h) ADD_BACKEND_LIBS(${DSOUND_LIBRARIES}) SET(INC_PATHS ${INC_PATHS} ${DSOUND_INCLUDE_DIRS}) ENDIF() @@ -955,7 +955,7 @@ IF(WIN32) IF(ALSOFT_BACKEND_WASAPI) SET(HAVE_WASAPI 1) SET(BACKENDS "${BACKENDS} WASAPI,") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/wasapi.cpp Alc/backends/wasapi.h) + SET(ALC_OBJS ${ALC_OBJS} alc/backends/wasapi.cpp alc/backends/wasapi.h) ENDIF() ENDIF() @@ -980,7 +980,7 @@ IF(PORTAUDIO_FOUND) IF(ALSOFT_BACKEND_PORTAUDIO) SET(HAVE_PORTAUDIO 1) SET(BACKENDS "${BACKENDS} PortAudio${IS_LINKED},") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/portaudio.cpp Alc/backends/portaudio.h) + SET(ALC_OBJS ${ALC_OBJS} alc/backends/portaudio.cpp alc/backends/portaudio.h) ADD_BACKEND_LIBS(${PORTAUDIO_LIBRARIES}) SET(INC_PATHS ${INC_PATHS} ${PORTAUDIO_INCLUDE_DIRS}) ENDIF() @@ -997,7 +997,7 @@ IF(PULSEAUDIO_FOUND) IF(ALSOFT_BACKEND_PULSEAUDIO) SET(HAVE_PULSEAUDIO 1) SET(BACKENDS "${BACKENDS} PulseAudio${IS_LINKED},") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/pulseaudio.cpp Alc/backends/pulseaudio.h) + SET(ALC_OBJS ${ALC_OBJS} alc/backends/pulseaudio.cpp alc/backends/pulseaudio.h) ADD_BACKEND_LIBS(${PULSEAUDIO_LIBRARIES}) SET(INC_PATHS ${INC_PATHS} ${PULSEAUDIO_INCLUDE_DIRS}) ENDIF() @@ -1014,7 +1014,7 @@ IF(JACK_FOUND) IF(ALSOFT_BACKEND_JACK) SET(HAVE_JACK 1) SET(BACKENDS "${BACKENDS} JACK${IS_LINKED},") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/jack.cpp Alc/backends/jack.h) + SET(ALC_OBJS ${ALC_OBJS} alc/backends/jack.cpp alc/backends/jack.h) ADD_BACKEND_LIBS(${JACK_LIBRARIES}) SET(INC_PATHS ${INC_PATHS} ${JACK_INCLUDE_DIRS}) ENDIF() @@ -1033,7 +1033,7 @@ IF(COREAUDIO_FRAMEWORK) OPTION(ALSOFT_BACKEND_COREAUDIO "Enable CoreAudio backend" ON) IF(ALSOFT_BACKEND_COREAUDIO) SET(HAVE_COREAUDIO 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/coreaudio.cpp Alc/backends/coreaudio.h) + SET(ALC_OBJS ${ALC_OBJS} alc/backends/coreaudio.cpp alc/backends/coreaudio.h) SET(BACKENDS "${BACKENDS} CoreAudio,") SET(EXTRA_LIBS ${COREAUDIO_FRAMEWORK} ${EXTRA_LIBS}) SET(EXTRA_LIBS /System/Library/Frameworks/AudioUnit.framework ${EXTRA_LIBS}) @@ -1063,7 +1063,7 @@ IF(OPENSL_FOUND) OPTION(ALSOFT_BACKEND_OPENSL "Enable OpenSL backend" ON) IF(ALSOFT_BACKEND_OPENSL) SET(HAVE_OPENSL 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/opensl.cpp Alc/backends/opensl.h) + SET(ALC_OBJS ${ALC_OBJS} alc/backends/opensl.cpp alc/backends/opensl.h) SET(BACKENDS "${BACKENDS} OpenSL,") SET(EXTRA_LIBS ${OPENSL_LIBRARIES} ${EXTRA_LIBS}) SET(INC_PATHS ${INC_PATHS} ${OPENSL_INCLUDE_DIRS}) @@ -1081,7 +1081,7 @@ IF(SDL2_FOUND) OPTION(ALSOFT_BACKEND_SDL2 "Enable SDL2 backend" OFF) IF(ALSOFT_BACKEND_SDL2) SET(HAVE_SDL2 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/sdl2.cpp Alc/backends/sdl2.h) + SET(ALC_OBJS ${ALC_OBJS} alc/backends/sdl2.cpp alc/backends/sdl2.h) SET(BACKENDS "${BACKENDS} SDL2,") SET(EXTRA_LIBS ${SDL2_LIBRARY} ${EXTRA_LIBS}) SET(INC_PATHS ${INC_PATHS} ${SDL2_INCLUDE_DIR}) @@ -1095,7 +1095,7 @@ ENDIF() OPTION(ALSOFT_BACKEND_WAVE "Enable Wave Writer backend" ON) IF(ALSOFT_BACKEND_WAVE) SET(HAVE_WAVE 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/wave.cpp Alc/backends/wave.h) + SET(ALC_OBJS ${ALC_OBJS} alc/backends/wave.cpp alc/backends/wave.h) SET(BACKENDS "${BACKENDS} WaveFile,") ENDIF() @@ -1312,7 +1312,7 @@ TARGET_INCLUDE_DIRECTORIES(${IMPL_TARGET} PRIVATE ${INC_PATHS} ${OpenAL_BINARY_DIR} - ${OpenAL_SOURCE_DIR}/Alc + ${OpenAL_SOURCE_DIR}/alc ${OpenAL_SOURCE_DIR}/OpenAL32/Include ${OpenAL_SOURCE_DIR}/common ) diff --git a/alc/alc.cpp b/alc/alc.cpp new file mode 100644 index 00000000..00f90d91 --- /dev/null +++ b/alc/alc.cpp @@ -0,0 +1,4342 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "version.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" +#include "AL/efx.h" + +#include "alAuxEffectSlot.h" +#include "alcmain.h" +#include "alEffect.h" +#include "alError.h" +#include "alFilter.h" +#include "alListener.h" +#include "alSource.h" +#include "albyte.h" +#include "alconfig.h" +#include "alcontext.h" +#include "alexcpt.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "aloptional.h" +#include "alspan.h" +#include "alu.h" +#include "ambidefs.h" +#include "atomic.h" +#include "bformatdec.h" +#include "bs2b.h" +#include "compat.h" +#include "cpu_caps.h" +#include "effects/base.h" +#include "filters/nfc.h" +#include "filters/splitter.h" +#include "fpu_modes.h" +#include "hrtf.h" +#include "inprogext.h" +#include "logging.h" +#include "mastering.h" +#include "opthelpers.h" +#include "ringbuffer.h" +#include "threads.h" +#include "uhjfilter.h" +#include "vecmat.h" +#include "vector.h" + +#include "backends/base.h" +#include "backends/null.h" +#include "backends/loopback.h" +#ifdef HAVE_JACK +#include "backends/jack.h" +#endif +#ifdef HAVE_PULSEAUDIO +#include "backends/pulseaudio.h" +#endif +#ifdef HAVE_ALSA +#include "backends/alsa.h" +#endif +#ifdef HAVE_WASAPI +#include "backends/wasapi.h" +#endif +#ifdef HAVE_COREAUDIO +#include "backends/coreaudio.h" +#endif +#ifdef HAVE_OPENSL +#include "backends/opensl.h" +#endif +#ifdef HAVE_SOLARIS +#include "backends/solaris.h" +#endif +#ifdef HAVE_SNDIO +#include "backends/sndio.h" +#endif +#ifdef HAVE_OSS +#include "backends/oss.h" +#endif +#ifdef HAVE_QSA +#include "backends/qsa.h" +#endif +#ifdef HAVE_DSOUND +#include "backends/dsound.h" +#endif +#ifdef HAVE_WINMM +#include "backends/winmm.h" +#endif +#ifdef HAVE_PORTAUDIO +#include "backends/portaudio.h" +#endif +#ifdef HAVE_SDL2 +#include "backends/sdl2.h" +#endif +#ifdef HAVE_WAVE +#include "backends/wave.h" +#endif + + +namespace { + +using namespace std::placeholders; +using std::chrono::seconds; +using std::chrono::nanoseconds; + + +/************************************************ + * Backends + ************************************************/ +struct BackendInfo { + const char *name; + BackendFactory& (*getFactory)(void); +}; + +BackendInfo BackendList[] = { +#ifdef HAVE_JACK + { "jack", JackBackendFactory::getFactory }, +#endif +#ifdef HAVE_PULSEAUDIO + { "pulse", PulseBackendFactory::getFactory }, +#endif +#ifdef HAVE_ALSA + { "alsa", AlsaBackendFactory::getFactory }, +#endif +#ifdef HAVE_WASAPI + { "wasapi", WasapiBackendFactory::getFactory }, +#endif +#ifdef HAVE_COREAUDIO + { "core", CoreAudioBackendFactory::getFactory }, +#endif +#ifdef HAVE_OPENSL + { "opensl", OSLBackendFactory::getFactory }, +#endif +#ifdef HAVE_SOLARIS + { "solaris", SolarisBackendFactory::getFactory }, +#endif +#ifdef HAVE_SNDIO + { "sndio", SndIOBackendFactory::getFactory }, +#endif +#ifdef HAVE_OSS + { "oss", OSSBackendFactory::getFactory }, +#endif +#ifdef HAVE_QSA + { "qsa", QSABackendFactory::getFactory }, +#endif +#ifdef HAVE_DSOUND + { "dsound", DSoundBackendFactory::getFactory }, +#endif +#ifdef HAVE_WINMM + { "winmm", WinMMBackendFactory::getFactory }, +#endif +#ifdef HAVE_PORTAUDIO + { "port", PortBackendFactory::getFactory }, +#endif +#ifdef HAVE_SDL2 + { "sdl2", SDL2BackendFactory::getFactory }, +#endif + + { "null", NullBackendFactory::getFactory }, +#ifdef HAVE_WAVE + { "wave", WaveBackendFactory::getFactory }, +#endif +}; +auto BackendListEnd = std::end(BackendList); + +BackendFactory *PlaybackFactory{}; +BackendFactory *CaptureFactory{}; + + +/************************************************ + * Functions, enums, and errors + ************************************************/ +#define DECL(x) { #x, (ALCvoid*)(x) } +const struct { + const ALCchar *funcName; + ALCvoid *address; +} alcFunctions[] = { + DECL(alcCreateContext), + DECL(alcMakeContextCurrent), + DECL(alcProcessContext), + DECL(alcSuspendContext), + DECL(alcDestroyContext), + DECL(alcGetCurrentContext), + DECL(alcGetContextsDevice), + DECL(alcOpenDevice), + DECL(alcCloseDevice), + DECL(alcGetError), + DECL(alcIsExtensionPresent), + DECL(alcGetProcAddress), + DECL(alcGetEnumValue), + DECL(alcGetString), + DECL(alcGetIntegerv), + DECL(alcCaptureOpenDevice), + DECL(alcCaptureCloseDevice), + DECL(alcCaptureStart), + DECL(alcCaptureStop), + DECL(alcCaptureSamples), + + DECL(alcSetThreadContext), + DECL(alcGetThreadContext), + + DECL(alcLoopbackOpenDeviceSOFT), + DECL(alcIsRenderFormatSupportedSOFT), + DECL(alcRenderSamplesSOFT), + + DECL(alcDevicePauseSOFT), + DECL(alcDeviceResumeSOFT), + + DECL(alcGetStringiSOFT), + DECL(alcResetDeviceSOFT), + + DECL(alcGetInteger64vSOFT), + + DECL(alEnable), + DECL(alDisable), + DECL(alIsEnabled), + DECL(alGetString), + DECL(alGetBooleanv), + DECL(alGetIntegerv), + DECL(alGetFloatv), + DECL(alGetDoublev), + DECL(alGetBoolean), + DECL(alGetInteger), + DECL(alGetFloat), + DECL(alGetDouble), + DECL(alGetError), + DECL(alIsExtensionPresent), + DECL(alGetProcAddress), + DECL(alGetEnumValue), + DECL(alListenerf), + DECL(alListener3f), + DECL(alListenerfv), + DECL(alListeneri), + DECL(alListener3i), + DECL(alListeneriv), + DECL(alGetListenerf), + DECL(alGetListener3f), + DECL(alGetListenerfv), + DECL(alGetListeneri), + DECL(alGetListener3i), + DECL(alGetListeneriv), + DECL(alGenSources), + DECL(alDeleteSources), + DECL(alIsSource), + DECL(alSourcef), + DECL(alSource3f), + DECL(alSourcefv), + DECL(alSourcei), + DECL(alSource3i), + DECL(alSourceiv), + DECL(alGetSourcef), + DECL(alGetSource3f), + DECL(alGetSourcefv), + DECL(alGetSourcei), + DECL(alGetSource3i), + DECL(alGetSourceiv), + DECL(alSourcePlayv), + DECL(alSourceStopv), + DECL(alSourceRewindv), + DECL(alSourcePausev), + DECL(alSourcePlay), + DECL(alSourceStop), + DECL(alSourceRewind), + DECL(alSourcePause), + DECL(alSourceQueueBuffers), + DECL(alSourceUnqueueBuffers), + DECL(alGenBuffers), + DECL(alDeleteBuffers), + DECL(alIsBuffer), + DECL(alBufferData), + DECL(alBufferf), + DECL(alBuffer3f), + DECL(alBufferfv), + DECL(alBufferi), + DECL(alBuffer3i), + DECL(alBufferiv), + DECL(alGetBufferf), + DECL(alGetBuffer3f), + DECL(alGetBufferfv), + DECL(alGetBufferi), + DECL(alGetBuffer3i), + DECL(alGetBufferiv), + DECL(alDopplerFactor), + DECL(alDopplerVelocity), + DECL(alSpeedOfSound), + DECL(alDistanceModel), + + DECL(alGenFilters), + DECL(alDeleteFilters), + DECL(alIsFilter), + DECL(alFilteri), + DECL(alFilteriv), + DECL(alFilterf), + DECL(alFilterfv), + DECL(alGetFilteri), + DECL(alGetFilteriv), + DECL(alGetFilterf), + DECL(alGetFilterfv), + DECL(alGenEffects), + DECL(alDeleteEffects), + DECL(alIsEffect), + DECL(alEffecti), + DECL(alEffectiv), + DECL(alEffectf), + DECL(alEffectfv), + DECL(alGetEffecti), + DECL(alGetEffectiv), + DECL(alGetEffectf), + DECL(alGetEffectfv), + DECL(alGenAuxiliaryEffectSlots), + DECL(alDeleteAuxiliaryEffectSlots), + DECL(alIsAuxiliaryEffectSlot), + DECL(alAuxiliaryEffectSloti), + DECL(alAuxiliaryEffectSlotiv), + DECL(alAuxiliaryEffectSlotf), + DECL(alAuxiliaryEffectSlotfv), + DECL(alGetAuxiliaryEffectSloti), + DECL(alGetAuxiliaryEffectSlotiv), + DECL(alGetAuxiliaryEffectSlotf), + DECL(alGetAuxiliaryEffectSlotfv), + + DECL(alDeferUpdatesSOFT), + DECL(alProcessUpdatesSOFT), + + DECL(alSourcedSOFT), + DECL(alSource3dSOFT), + DECL(alSourcedvSOFT), + DECL(alGetSourcedSOFT), + DECL(alGetSource3dSOFT), + DECL(alGetSourcedvSOFT), + DECL(alSourcei64SOFT), + DECL(alSource3i64SOFT), + DECL(alSourcei64vSOFT), + DECL(alGetSourcei64SOFT), + DECL(alGetSource3i64SOFT), + DECL(alGetSourcei64vSOFT), + + DECL(alGetStringiSOFT), + + DECL(alBufferStorageSOFT), + DECL(alMapBufferSOFT), + DECL(alUnmapBufferSOFT), + DECL(alFlushMappedBufferSOFT), + + DECL(alEventControlSOFT), + DECL(alEventCallbackSOFT), + DECL(alGetPointerSOFT), + DECL(alGetPointervSOFT), +}; +#undef DECL + +#define DECL(x) { #x, (x) } +constexpr struct { + const ALCchar *enumName; + ALCenum value; +} alcEnumerations[] = { + DECL(ALC_INVALID), + DECL(ALC_FALSE), + DECL(ALC_TRUE), + + DECL(ALC_MAJOR_VERSION), + DECL(ALC_MINOR_VERSION), + DECL(ALC_ATTRIBUTES_SIZE), + DECL(ALC_ALL_ATTRIBUTES), + DECL(ALC_DEFAULT_DEVICE_SPECIFIER), + DECL(ALC_DEVICE_SPECIFIER), + DECL(ALC_ALL_DEVICES_SPECIFIER), + DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER), + DECL(ALC_EXTENSIONS), + DECL(ALC_FREQUENCY), + DECL(ALC_REFRESH), + DECL(ALC_SYNC), + DECL(ALC_MONO_SOURCES), + DECL(ALC_STEREO_SOURCES), + DECL(ALC_CAPTURE_DEVICE_SPECIFIER), + DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER), + DECL(ALC_CAPTURE_SAMPLES), + DECL(ALC_CONNECTED), + + DECL(ALC_EFX_MAJOR_VERSION), + DECL(ALC_EFX_MINOR_VERSION), + DECL(ALC_MAX_AUXILIARY_SENDS), + + DECL(ALC_FORMAT_CHANNELS_SOFT), + DECL(ALC_FORMAT_TYPE_SOFT), + + DECL(ALC_MONO_SOFT), + DECL(ALC_STEREO_SOFT), + DECL(ALC_QUAD_SOFT), + DECL(ALC_5POINT1_SOFT), + DECL(ALC_6POINT1_SOFT), + DECL(ALC_7POINT1_SOFT), + DECL(ALC_BFORMAT3D_SOFT), + + DECL(ALC_BYTE_SOFT), + DECL(ALC_UNSIGNED_BYTE_SOFT), + DECL(ALC_SHORT_SOFT), + DECL(ALC_UNSIGNED_SHORT_SOFT), + DECL(ALC_INT_SOFT), + DECL(ALC_UNSIGNED_INT_SOFT), + DECL(ALC_FLOAT_SOFT), + + DECL(ALC_HRTF_SOFT), + DECL(ALC_DONT_CARE_SOFT), + DECL(ALC_HRTF_STATUS_SOFT), + DECL(ALC_HRTF_DISABLED_SOFT), + DECL(ALC_HRTF_ENABLED_SOFT), + DECL(ALC_HRTF_DENIED_SOFT), + DECL(ALC_HRTF_REQUIRED_SOFT), + DECL(ALC_HRTF_HEADPHONES_DETECTED_SOFT), + DECL(ALC_HRTF_UNSUPPORTED_FORMAT_SOFT), + DECL(ALC_NUM_HRTF_SPECIFIERS_SOFT), + DECL(ALC_HRTF_SPECIFIER_SOFT), + DECL(ALC_HRTF_ID_SOFT), + + DECL(ALC_AMBISONIC_LAYOUT_SOFT), + DECL(ALC_AMBISONIC_SCALING_SOFT), + DECL(ALC_AMBISONIC_ORDER_SOFT), + DECL(ALC_ACN_SOFT), + DECL(ALC_FUMA_SOFT), + DECL(ALC_N3D_SOFT), + DECL(ALC_SN3D_SOFT), + + DECL(ALC_OUTPUT_LIMITER_SOFT), + + DECL(ALC_NO_ERROR), + DECL(ALC_INVALID_DEVICE), + DECL(ALC_INVALID_CONTEXT), + DECL(ALC_INVALID_ENUM), + DECL(ALC_INVALID_VALUE), + DECL(ALC_OUT_OF_MEMORY), + + + DECL(AL_INVALID), + DECL(AL_NONE), + DECL(AL_FALSE), + DECL(AL_TRUE), + + DECL(AL_SOURCE_RELATIVE), + DECL(AL_CONE_INNER_ANGLE), + DECL(AL_CONE_OUTER_ANGLE), + DECL(AL_PITCH), + DECL(AL_POSITION), + DECL(AL_DIRECTION), + DECL(AL_VELOCITY), + DECL(AL_LOOPING), + DECL(AL_BUFFER), + DECL(AL_GAIN), + DECL(AL_MIN_GAIN), + DECL(AL_MAX_GAIN), + DECL(AL_ORIENTATION), + DECL(AL_REFERENCE_DISTANCE), + DECL(AL_ROLLOFF_FACTOR), + DECL(AL_CONE_OUTER_GAIN), + DECL(AL_MAX_DISTANCE), + DECL(AL_SEC_OFFSET), + DECL(AL_SAMPLE_OFFSET), + DECL(AL_BYTE_OFFSET), + DECL(AL_SOURCE_TYPE), + DECL(AL_STATIC), + DECL(AL_STREAMING), + DECL(AL_UNDETERMINED), + DECL(AL_METERS_PER_UNIT), + DECL(AL_LOOP_POINTS_SOFT), + DECL(AL_DIRECT_CHANNELS_SOFT), + + DECL(AL_DIRECT_FILTER), + DECL(AL_AUXILIARY_SEND_FILTER), + DECL(AL_AIR_ABSORPTION_FACTOR), + DECL(AL_ROOM_ROLLOFF_FACTOR), + DECL(AL_CONE_OUTER_GAINHF), + DECL(AL_DIRECT_FILTER_GAINHF_AUTO), + DECL(AL_AUXILIARY_SEND_FILTER_GAIN_AUTO), + DECL(AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO), + + DECL(AL_SOURCE_STATE), + DECL(AL_INITIAL), + DECL(AL_PLAYING), + DECL(AL_PAUSED), + DECL(AL_STOPPED), + + DECL(AL_BUFFERS_QUEUED), + DECL(AL_BUFFERS_PROCESSED), + + DECL(AL_FORMAT_MONO8), + DECL(AL_FORMAT_MONO16), + DECL(AL_FORMAT_MONO_FLOAT32), + DECL(AL_FORMAT_MONO_DOUBLE_EXT), + DECL(AL_FORMAT_STEREO8), + DECL(AL_FORMAT_STEREO16), + DECL(AL_FORMAT_STEREO_FLOAT32), + 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), + DECL(AL_FORMAT_QUAD16), + DECL(AL_FORMAT_QUAD32), + DECL(AL_FORMAT_51CHN8), + DECL(AL_FORMAT_51CHN16), + DECL(AL_FORMAT_51CHN32), + DECL(AL_FORMAT_61CHN8), + DECL(AL_FORMAT_61CHN16), + DECL(AL_FORMAT_61CHN32), + DECL(AL_FORMAT_71CHN8), + DECL(AL_FORMAT_71CHN16), + DECL(AL_FORMAT_71CHN32), + DECL(AL_FORMAT_REAR8), + DECL(AL_FORMAT_REAR16), + DECL(AL_FORMAT_REAR32), + DECL(AL_FORMAT_MONO_MULAW), + DECL(AL_FORMAT_MONO_MULAW_EXT), + DECL(AL_FORMAT_STEREO_MULAW), + DECL(AL_FORMAT_STEREO_MULAW_EXT), + DECL(AL_FORMAT_QUAD_MULAW), + DECL(AL_FORMAT_51CHN_MULAW), + DECL(AL_FORMAT_61CHN_MULAW), + DECL(AL_FORMAT_71CHN_MULAW), + DECL(AL_FORMAT_REAR_MULAW), + DECL(AL_FORMAT_MONO_ALAW_EXT), + DECL(AL_FORMAT_STEREO_ALAW_EXT), + + DECL(AL_FORMAT_BFORMAT2D_8), + DECL(AL_FORMAT_BFORMAT2D_16), + DECL(AL_FORMAT_BFORMAT2D_FLOAT32), + DECL(AL_FORMAT_BFORMAT2D_MULAW), + DECL(AL_FORMAT_BFORMAT3D_8), + DECL(AL_FORMAT_BFORMAT3D_16), + DECL(AL_FORMAT_BFORMAT3D_FLOAT32), + DECL(AL_FORMAT_BFORMAT3D_MULAW), + + DECL(AL_FREQUENCY), + DECL(AL_BITS), + DECL(AL_CHANNELS), + DECL(AL_SIZE), + DECL(AL_UNPACK_BLOCK_ALIGNMENT_SOFT), + DECL(AL_PACK_BLOCK_ALIGNMENT_SOFT), + + DECL(AL_SOURCE_RADIUS), + + DECL(AL_STEREO_ANGLES), + + DECL(AL_UNUSED), + DECL(AL_PENDING), + DECL(AL_PROCESSED), + + DECL(AL_NO_ERROR), + DECL(AL_INVALID_NAME), + DECL(AL_INVALID_ENUM), + DECL(AL_INVALID_VALUE), + DECL(AL_INVALID_OPERATION), + DECL(AL_OUT_OF_MEMORY), + + DECL(AL_VENDOR), + DECL(AL_VERSION), + DECL(AL_RENDERER), + DECL(AL_EXTENSIONS), + + DECL(AL_DOPPLER_FACTOR), + DECL(AL_DOPPLER_VELOCITY), + DECL(AL_DISTANCE_MODEL), + DECL(AL_SPEED_OF_SOUND), + DECL(AL_SOURCE_DISTANCE_MODEL), + DECL(AL_DEFERRED_UPDATES_SOFT), + DECL(AL_GAIN_LIMIT_SOFT), + + DECL(AL_INVERSE_DISTANCE), + DECL(AL_INVERSE_DISTANCE_CLAMPED), + DECL(AL_LINEAR_DISTANCE), + DECL(AL_LINEAR_DISTANCE_CLAMPED), + DECL(AL_EXPONENT_DISTANCE), + DECL(AL_EXPONENT_DISTANCE_CLAMPED), + + DECL(AL_FILTER_TYPE), + DECL(AL_FILTER_NULL), + DECL(AL_FILTER_LOWPASS), + DECL(AL_FILTER_HIGHPASS), + DECL(AL_FILTER_BANDPASS), + + 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), + DECL(AL_EFFECT_EAXREVERB), + DECL(AL_EFFECT_CHORUS), + DECL(AL_EFFECT_DISTORTION), + DECL(AL_EFFECT_ECHO), + DECL(AL_EFFECT_FLANGER), + DECL(AL_EFFECT_PITCH_SHIFTER), + DECL(AL_EFFECT_FREQUENCY_SHIFTER), + DECL(AL_EFFECT_VOCAL_MORPHER), + DECL(AL_EFFECT_RING_MODULATOR), + DECL(AL_EFFECT_AUTOWAH), + DECL(AL_EFFECT_COMPRESSOR), + DECL(AL_EFFECT_EQUALIZER), + DECL(AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT), + DECL(AL_EFFECT_DEDICATED_DIALOGUE), + + DECL(AL_EFFECTSLOT_EFFECT), + DECL(AL_EFFECTSLOT_GAIN), + DECL(AL_EFFECTSLOT_AUXILIARY_SEND_AUTO), + DECL(AL_EFFECTSLOT_NULL), + + DECL(AL_EAXREVERB_DENSITY), + DECL(AL_EAXREVERB_DIFFUSION), + DECL(AL_EAXREVERB_GAIN), + DECL(AL_EAXREVERB_GAINHF), + DECL(AL_EAXREVERB_GAINLF), + DECL(AL_EAXREVERB_DECAY_TIME), + DECL(AL_EAXREVERB_DECAY_HFRATIO), + DECL(AL_EAXREVERB_DECAY_LFRATIO), + DECL(AL_EAXREVERB_REFLECTIONS_GAIN), + DECL(AL_EAXREVERB_REFLECTIONS_DELAY), + DECL(AL_EAXREVERB_REFLECTIONS_PAN), + DECL(AL_EAXREVERB_LATE_REVERB_GAIN), + DECL(AL_EAXREVERB_LATE_REVERB_DELAY), + DECL(AL_EAXREVERB_LATE_REVERB_PAN), + DECL(AL_EAXREVERB_ECHO_TIME), + DECL(AL_EAXREVERB_ECHO_DEPTH), + DECL(AL_EAXREVERB_MODULATION_TIME), + DECL(AL_EAXREVERB_MODULATION_DEPTH), + DECL(AL_EAXREVERB_AIR_ABSORPTION_GAINHF), + DECL(AL_EAXREVERB_HFREFERENCE), + DECL(AL_EAXREVERB_LFREFERENCE), + DECL(AL_EAXREVERB_ROOM_ROLLOFF_FACTOR), + DECL(AL_EAXREVERB_DECAY_HFLIMIT), + + DECL(AL_REVERB_DENSITY), + DECL(AL_REVERB_DIFFUSION), + DECL(AL_REVERB_GAIN), + DECL(AL_REVERB_GAINHF), + DECL(AL_REVERB_DECAY_TIME), + DECL(AL_REVERB_DECAY_HFRATIO), + DECL(AL_REVERB_REFLECTIONS_GAIN), + DECL(AL_REVERB_REFLECTIONS_DELAY), + DECL(AL_REVERB_LATE_REVERB_GAIN), + DECL(AL_REVERB_LATE_REVERB_DELAY), + DECL(AL_REVERB_AIR_ABSORPTION_GAINHF), + DECL(AL_REVERB_ROOM_ROLLOFF_FACTOR), + DECL(AL_REVERB_DECAY_HFLIMIT), + + DECL(AL_CHORUS_WAVEFORM), + DECL(AL_CHORUS_PHASE), + DECL(AL_CHORUS_RATE), + DECL(AL_CHORUS_DEPTH), + DECL(AL_CHORUS_FEEDBACK), + DECL(AL_CHORUS_DELAY), + + DECL(AL_DISTORTION_EDGE), + DECL(AL_DISTORTION_GAIN), + DECL(AL_DISTORTION_LOWPASS_CUTOFF), + DECL(AL_DISTORTION_EQCENTER), + DECL(AL_DISTORTION_EQBANDWIDTH), + + DECL(AL_ECHO_DELAY), + DECL(AL_ECHO_LRDELAY), + DECL(AL_ECHO_DAMPING), + DECL(AL_ECHO_FEEDBACK), + DECL(AL_ECHO_SPREAD), + + DECL(AL_FLANGER_WAVEFORM), + DECL(AL_FLANGER_PHASE), + DECL(AL_FLANGER_RATE), + DECL(AL_FLANGER_DEPTH), + DECL(AL_FLANGER_FEEDBACK), + DECL(AL_FLANGER_DELAY), + + DECL(AL_FREQUENCY_SHIFTER_FREQUENCY), + DECL(AL_FREQUENCY_SHIFTER_LEFT_DIRECTION), + DECL(AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION), + + DECL(AL_RING_MODULATOR_FREQUENCY), + DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF), + DECL(AL_RING_MODULATOR_WAVEFORM), + + DECL(AL_PITCH_SHIFTER_COARSE_TUNE), + DECL(AL_PITCH_SHIFTER_FINE_TUNE), + + DECL(AL_COMPRESSOR_ONOFF), + + DECL(AL_EQUALIZER_LOW_GAIN), + DECL(AL_EQUALIZER_LOW_CUTOFF), + DECL(AL_EQUALIZER_MID1_GAIN), + DECL(AL_EQUALIZER_MID1_CENTER), + DECL(AL_EQUALIZER_MID1_WIDTH), + DECL(AL_EQUALIZER_MID2_GAIN), + DECL(AL_EQUALIZER_MID2_CENTER), + DECL(AL_EQUALIZER_MID2_WIDTH), + DECL(AL_EQUALIZER_HIGH_GAIN), + DECL(AL_EQUALIZER_HIGH_CUTOFF), + + DECL(AL_DEDICATED_GAIN), + + DECL(AL_AUTOWAH_ATTACK_TIME), + DECL(AL_AUTOWAH_RELEASE_TIME), + DECL(AL_AUTOWAH_RESONANCE), + DECL(AL_AUTOWAH_PEAK_GAIN), + + DECL(AL_NUM_RESAMPLERS_SOFT), + DECL(AL_DEFAULT_RESAMPLER_SOFT), + DECL(AL_SOURCE_RESAMPLER_SOFT), + DECL(AL_RESAMPLER_NAME_SOFT), + + DECL(AL_SOURCE_SPATIALIZE_SOFT), + DECL(AL_AUTO_SOFT), + + DECL(AL_MAP_READ_BIT_SOFT), + DECL(AL_MAP_WRITE_BIT_SOFT), + DECL(AL_MAP_PERSISTENT_BIT_SOFT), + DECL(AL_PRESERVE_DATA_BIT_SOFT), + + DECL(AL_EVENT_CALLBACK_FUNCTION_SOFT), + DECL(AL_EVENT_CALLBACK_USER_PARAM_SOFT), + DECL(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT), + DECL(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT), + DECL(AL_EVENT_TYPE_ERROR_SOFT), + DECL(AL_EVENT_TYPE_PERFORMANCE_SOFT), + DECL(AL_EVENT_TYPE_DEPRECATED_SOFT), +}; +#undef DECL + +constexpr ALCchar alcNoError[] = "No Error"; +constexpr ALCchar alcErrInvalidDevice[] = "Invalid Device"; +constexpr ALCchar alcErrInvalidContext[] = "Invalid Context"; +constexpr ALCchar alcErrInvalidEnum[] = "Invalid Enum"; +constexpr ALCchar alcErrInvalidValue[] = "Invalid Value"; +constexpr ALCchar alcErrOutOfMemory[] = "Out of Memory"; + + +/************************************************ + * Global variables + ************************************************/ + +/* Enumerated device names */ +constexpr ALCchar alcDefaultName[] = "OpenAL Soft\0"; + +std::string alcAllDevicesList; +std::string alcCaptureDeviceList; + +/* Default is always the first in the list */ +std::string alcDefaultAllDevicesSpecifier; +std::string alcCaptureDefaultDeviceSpecifier; + +/* Default context extensions */ +constexpr ALchar alExtList[] = + "AL_EXT_ALAW " + "AL_EXT_BFORMAT " + "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_BFORMAT " + "AL_EXT_MULAW_MCFORMATS " + "AL_EXT_OFFSET " + "AL_EXT_source_distance_model " + "AL_EXT_SOURCE_RADIUS " + "AL_EXT_STEREO_ANGLES " + "AL_LOKI_quadriphonic " + "AL_SOFT_block_alignment " + "AL_SOFT_deferred_updates " + "AL_SOFT_direct_channels " + "AL_SOFTX_effect_chain " + "AL_SOFTX_events " + "AL_SOFTX_filter_gain_ex " + "AL_SOFT_gain_clamp_ex " + "AL_SOFT_loop_points " + "AL_SOFTX_map_buffer " + "AL_SOFT_MSADPCM " + "AL_SOFT_source_latency " + "AL_SOFT_source_length " + "AL_SOFT_source_resampler " + "AL_SOFT_source_spatialize"; + +std::atomic LastNullDeviceError{ALC_NO_ERROR}; + +/* Thread-local current context */ +void ReleaseThreadCtx(ALCcontext *context) +{ + auto ref = DecrementRef(&context->ref); + TRACEREF("ALCcontext %p decreasing refcount to %u\n", context, ref); + ERR("Context %p current for thread being destroyed, possible leak!\n", context); +} + +std::atomic ThreadCtxProc{ReleaseThreadCtx}; +class ThreadCtx { + ALCcontext *ctx{nullptr}; + +public: + ~ThreadCtx() + { + auto destruct = ThreadCtxProc.load(); + if(destruct && ctx) + destruct(ctx); + ctx = nullptr; + } + + ALCcontext *get() const noexcept { return ctx; } + void set(ALCcontext *ctx_) noexcept { ctx = ctx_; } +}; +thread_local ThreadCtx LocalContext; +/* Process-wide current context */ +std::atomic GlobalContext{nullptr}; + +/* Flag to trap ALC device errors */ +bool TrapALCError{false}; + +/* One-time configuration init control */ +std::once_flag alc_config_once{}; + +/* Default effect that applies to sources that don't have an effect on send 0 */ +ALeffect DefaultEffect; + +/* Flag to specify if alcSuspendContext/alcProcessContext should defer/process + * updates. + */ +bool SuspendDefers{true}; + + +/************************************************ + * ALC information + ************************************************/ +constexpr ALCchar alcNoDeviceExtList[] = + "ALC_ENUMERATE_ALL_EXT " + "ALC_ENUMERATION_EXT " + "ALC_EXT_CAPTURE " + "ALC_EXT_thread_local_context " + "ALC_SOFT_loopback"; +constexpr ALCchar alcExtensionList[] = + "ALC_ENUMERATE_ALL_EXT " + "ALC_ENUMERATION_EXT " + "ALC_EXT_CAPTURE " + "ALC_EXT_DEDICATED " + "ALC_EXT_disconnect " + "ALC_EXT_EFX " + "ALC_EXT_thread_local_context " + "ALC_SOFT_device_clock " + "ALC_SOFT_HRTF " + "ALC_SOFT_loopback " + "ALC_SOFT_output_limiter " + "ALC_SOFT_pause_device"; +constexpr ALCint alcMajorVersion = 1; +constexpr ALCint alcMinorVersion = 1; + +constexpr ALCint alcEFXMajorVersion = 1; +constexpr ALCint alcEFXMinorVersion = 0; + + +/* To avoid extraneous allocations, a 0-sized FlexArray is defined + * globally as a sharable object. + */ +al::FlexArray EmptyContextArray{0u}; + + +void ALCdevice_IncRef(ALCdevice *device) +{ + auto ref = IncrementRef(&device->ref); + TRACEREF("ALCdevice %p increasing refcount to %u\n", device, ref); +} + +void ALCdevice_DecRef(ALCdevice *device) +{ + auto ref = DecrementRef(&device->ref); + TRACEREF("ALCdevice %p decreasing refcount to %u\n", device, ref); + if(UNLIKELY(ref == 0)) delete device; +} + +/* Simple RAII device reference. Takes the reference of the provided ALCdevice, + * and decrements it when leaving scope. Movable (transfer reference) but not + * copyable (no new references). + */ +class DeviceRef { + ALCdevice *mDev{nullptr}; + + void reset() noexcept + { + if(mDev) + ALCdevice_DecRef(mDev); + mDev = nullptr; + } + +public: + DeviceRef() noexcept = default; + DeviceRef(DeviceRef&& rhs) noexcept : mDev{rhs.mDev} + { rhs.mDev = nullptr; } + explicit DeviceRef(ALCdevice *dev) noexcept : mDev(dev) { } + ~DeviceRef() { reset(); } + + DeviceRef& operator=(const DeviceRef&) = delete; + DeviceRef& operator=(DeviceRef&& rhs) noexcept + { + std::swap(mDev, rhs.mDev); + return *this; + } + + operator bool() const noexcept { return mDev != nullptr; } + + ALCdevice* operator->() const noexcept { return mDev; } + ALCdevice* get() const noexcept { return mDev; } + + ALCdevice* release() noexcept + { + ALCdevice *ret{mDev}; + mDev = nullptr; + return ret; + } +}; + +inline bool operator==(const DeviceRef &lhs, const ALCdevice *rhs) noexcept +{ return lhs.get() == rhs; } +inline bool operator!=(const DeviceRef &lhs, const ALCdevice *rhs) noexcept +{ return !(lhs == rhs); } +inline bool operator<(const DeviceRef &lhs, const ALCdevice *rhs) noexcept +{ return lhs.get() < rhs; } + + +/************************************************ + * Device lists + ************************************************/ +al::vector DeviceList; +al::vector ContextList; + +std::recursive_mutex ListLock; + + +void alc_initconfig(void) +{ + const char *str{getenv("ALSOFT_LOGLEVEL")}; + if(str) + { + long lvl = strtol(str, nullptr, 0); + if(lvl >= NoLog && lvl <= LogRef) + gLogLevel = static_cast(lvl); + } + + str = getenv("ALSOFT_LOGFILE"); + if(str && str[0]) + { +#ifdef _WIN32 + std::wstring wname{utf8_to_wstr(str)}; + FILE *logfile = _wfopen(wname.c_str(), L"wt"); +#else + FILE *logfile = fopen(str, "wt"); +#endif + if(logfile) gLogFile = logfile; + else ERR("Failed to open log file '%s'\n", str); + } + + TRACE("Initializing library v%s-%s %s\n", ALSOFT_VERSION, ALSOFT_GIT_COMMIT_HASH, + ALSOFT_GIT_BRANCH); + { + std::string names; + if(std::begin(BackendList) == BackendListEnd) + names += "(none)"; + else + { + const al::span infos{std::begin(BackendList), BackendListEnd}; + names += infos[0].name; + for(const auto &backend : infos.subspan(1)) + { + names += ", "; + names += backend.name; + } + } + TRACE("Supported backends: %s\n", names.c_str()); + } + ReadALConfig(); + + str = getenv("__ALSOFT_SUSPEND_CONTEXT"); + if(str && *str) + { + if(strcasecmp(str, "ignore") == 0) + { + SuspendDefers = false; + TRACE("Selected context suspend behavior, \"ignore\"\n"); + } + else + ERR("Unhandled context suspend behavior setting: \"%s\"\n", str); + } + + int capfilter{0}; +#if defined(HAVE_SSE4_1) + capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1; +#elif defined(HAVE_SSE3) + capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3; +#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; +#endif + if(auto cpuopt = ConfigValueStr(nullptr, nullptr, "disable-cpu-exts")) + { + str = cpuopt->c_str(); + if(strcasecmp(str, "all") == 0) + capfilter = 0; + else + { + const char *next = str; + do { + str = next; + while(isspace(str[0])) + str++; + next = strchr(str, ','); + + if(!str[0] || str[0] == ',') + continue; + + size_t len{next ? static_cast(next-str) : strlen(str)}; + while(len > 0 && isspace(str[len-1])) + len--; + if(len == 3 && strncasecmp(str, "sse", len) == 0) + capfilter &= ~CPU_CAP_SSE; + else if(len == 4 && strncasecmp(str, "sse2", len) == 0) + capfilter &= ~CPU_CAP_SSE2; + else if(len == 4 && strncasecmp(str, "sse3", len) == 0) + capfilter &= ~CPU_CAP_SSE3; + 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 + WARN("Invalid CPU extension \"%s\"\n", str); + } while(next++); + } + } + FillCPUCaps(capfilter); + +#ifdef _WIN32 +#define DEF_MIXER_PRIO 1 +#else +#define DEF_MIXER_PRIO 0 +#endif + RTPrioLevel = ConfigValueInt(nullptr, nullptr, "rt-prio").value_or(DEF_MIXER_PRIO); +#undef DEF_MIXER_PRIO + + aluInit(); + aluInitMixer(); + + str = getenv("ALSOFT_TRAP_ERROR"); + if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) + { + TrapALError = true; + TrapALCError = true; + } + else + { + str = getenv("ALSOFT_TRAP_AL_ERROR"); + if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) + TrapALError = true; + TrapALError = !!GetConfigValueBool(nullptr, nullptr, "trap-al-error", TrapALError); + + str = getenv("ALSOFT_TRAP_ALC_ERROR"); + if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) + TrapALCError = true; + TrapALCError = !!GetConfigValueBool(nullptr, nullptr, "trap-alc-error", TrapALCError); + } + + if(auto boostopt = ConfigValueFloat(nullptr, "reverb", "boost")) + { + const float valf{std::isfinite(*boostopt) ? clampf(*boostopt, -24.0f, 24.0f) : 0.0f}; + ReverbBoost *= std::pow(10.0f, valf / 20.0f); + } + + auto devopt = ConfigValueStr(nullptr, nullptr, "drivers"); + if(const char *devs{getenv("ALSOFT_DRIVERS")}) + { + if(devs[0]) + devopt = devs; + } + if(devopt) + { + auto backendlist_cur = std::begin(BackendList); + + bool endlist{true}; + const char *next{devopt->c_str()}; + do { + const char *devs{next}; + while(isspace(devs[0])) + devs++; + next = strchr(devs, ','); + + const bool delitem{devs[0] == '-'}; + if(devs[0] == '-') devs++; + + if(!devs[0] || devs[0] == ',') + { + endlist = false; + continue; + } + endlist = true; + + size_t len{next ? (static_cast(next-devs)) : strlen(devs)}; + while(len > 0 && isspace(devs[len-1])) --len; +#ifdef HAVE_WASAPI + /* HACK: For backwards compatibility, convert backend references of + * mmdevapi to wasapi. This should eventually be removed. + */ + if(len == 8 && strncmp(devs, "mmdevapi", len) == 0) + { + devs = "wasapi"; + len = 6; + } +#endif + + auto find_backend = [devs,len](const BackendInfo &backend) -> bool + { return len == strlen(backend.name) && strncmp(backend.name, devs, len) == 0; }; + auto this_backend = std::find_if(std::begin(BackendList), BackendListEnd, + find_backend); + + if(this_backend == BackendListEnd) + continue; + + if(delitem) + BackendListEnd = std::move(this_backend+1, BackendListEnd, this_backend); + else + backendlist_cur = std::rotate(backendlist_cur, this_backend, this_backend+1); + } while(next++); + + if(endlist) + BackendListEnd = backendlist_cur; + } + + auto init_backend = [](BackendInfo &backend) -> bool + { + if(PlaybackFactory && CaptureFactory) + return true; + + BackendFactory &factory = backend.getFactory(); + if(!factory.init()) + { + WARN("Failed to initialize backend \"%s\"\n", backend.name); + return true; + } + + TRACE("Initialized backend \"%s\"\n", backend.name); + if(!PlaybackFactory && factory.querySupport(BackendType::Playback)) + { + PlaybackFactory = &factory; + TRACE("Added \"%s\" for playback\n", backend.name); + } + if(!CaptureFactory && factory.querySupport(BackendType::Capture)) + { + CaptureFactory = &factory; + TRACE("Added \"%s\" for capture\n", backend.name); + } + return false; + }; + BackendListEnd = std::remove_if(std::begin(BackendList), BackendListEnd, init_backend); + + LoopbackBackendFactory::getFactory().init(); + + if(!PlaybackFactory) + WARN("No playback backend available!\n"); + if(!CaptureFactory) + WARN("No capture backend available!\n"); + + if(auto exclopt = ConfigValueStr(nullptr, nullptr, "excludefx")) + { + const char *next{exclopt->c_str()}; + do { + str = next; + next = strchr(str, ','); + + if(!str[0] || next == str) + continue; + + size_t len{next ? static_cast(next-str) : strlen(str)}; + for(const EffectList &effectitem : gEffectList) + { + if(len == strlen(effectitem.name) && + strncmp(effectitem.name, str, len) == 0) + DisabledEffects[effectitem.type] = AL_TRUE; + } + } while(next++); + } + + InitEffect(&DefaultEffect); + auto defrevopt = ConfigValueStr(nullptr, nullptr, "default-reverb"); + if((str=getenv("ALSOFT_DEFAULT_REVERB")) && str[0]) + defrevopt = str; + if(defrevopt) LoadReverbPreset(defrevopt->c_str(), &DefaultEffect); +} +#define DO_INITCONFIG() std::call_once(alc_config_once, [](){alc_initconfig();}) + + +/************************************************ + * Device enumeration + ************************************************/ +void ProbeAllDevicesList() +{ + DO_INITCONFIG(); + + std::lock_guard _{ListLock}; + alcAllDevicesList.clear(); + if(PlaybackFactory) + PlaybackFactory->probe(DevProbe::Playback, &alcAllDevicesList); +} +void ProbeCaptureDeviceList() +{ + DO_INITCONFIG(); + + std::lock_guard _{ListLock}; + alcCaptureDeviceList.clear(); + if(CaptureFactory) + CaptureFactory->probe(DevProbe::Capture, &alcCaptureDeviceList); +} + +} // namespace + +/* Mixing thread piority level */ +ALint RTPrioLevel; + +FILE *gLogFile{stderr}; +#ifdef _DEBUG +LogLevel gLogLevel{LogWarning}; +#else +LogLevel gLogLevel{LogError}; +#endif + +/************************************************ + * Library initialization + ************************************************/ +#if defined(_WIN32) && !defined(AL_LIBTYPE_STATIC) +BOOL APIENTRY DllMain(HINSTANCE module, DWORD reason, LPVOID /*reserved*/) +{ + 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*)module, &module); + break; + + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} +#endif + +/************************************************ + * Device format information + ************************************************/ +const ALCchar *DevFmtTypeString(DevFmtType type) noexcept +{ + switch(type) + { + case DevFmtByte: return "Signed Byte"; + case DevFmtUByte: return "Unsigned Byte"; + case DevFmtShort: return "Signed Short"; + case DevFmtUShort: return "Unsigned Short"; + case DevFmtInt: return "Signed Int"; + case DevFmtUInt: return "Unsigned Int"; + case DevFmtFloat: return "Float"; + } + return "(unknown type)"; +} +const ALCchar *DevFmtChannelsString(DevFmtChannels chans) noexcept +{ + switch(chans) + { + case DevFmtMono: return "Mono"; + case DevFmtStereo: return "Stereo"; + case DevFmtQuad: return "Quadraphonic"; + case DevFmtX51: return "5.1 Surround"; + case DevFmtX51Rear: return "5.1 Surround (Rear)"; + case DevFmtX61: return "6.1 Surround"; + case DevFmtX71: return "7.1 Surround"; + case DevFmtAmbi3D: return "Ambisonic 3D"; + } + return "(unknown channels)"; +} + +ALsizei BytesFromDevFmt(DevFmtType type) noexcept +{ + switch(type) + { + case DevFmtByte: return sizeof(ALbyte); + case DevFmtUByte: return sizeof(ALubyte); + case DevFmtShort: return sizeof(ALshort); + case DevFmtUShort: return sizeof(ALushort); + case DevFmtInt: return sizeof(ALint); + case DevFmtUInt: return sizeof(ALuint); + case DevFmtFloat: return sizeof(ALfloat); + } + return 0; +} +ALsizei ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept +{ + switch(chans) + { + case DevFmtMono: return 1; + case DevFmtStereo: return 2; + case DevFmtQuad: return 4; + case DevFmtX51: return 6; + case DevFmtX51Rear: return 6; + case DevFmtX61: return 7; + case DevFmtX71: return 8; + case DevFmtAmbi3D: return (ambiorder+1) * (ambiorder+1); + } + return 0; +} + +struct DevFmtPair { DevFmtChannels chans; DevFmtType type; }; +static al::optional DecomposeDevFormat(ALenum format) +{ + static const struct { + ALenum format; + DevFmtChannels channels; + DevFmtType type; + } list[] = { + { AL_FORMAT_MONO8, DevFmtMono, DevFmtUByte }, + { AL_FORMAT_MONO16, DevFmtMono, DevFmtShort }, + { AL_FORMAT_MONO_FLOAT32, DevFmtMono, DevFmtFloat }, + + { AL_FORMAT_STEREO8, DevFmtStereo, DevFmtUByte }, + { AL_FORMAT_STEREO16, DevFmtStereo, DevFmtShort }, + { AL_FORMAT_STEREO_FLOAT32, DevFmtStereo, DevFmtFloat }, + + { AL_FORMAT_QUAD8, DevFmtQuad, DevFmtUByte }, + { AL_FORMAT_QUAD16, DevFmtQuad, DevFmtShort }, + { AL_FORMAT_QUAD32, DevFmtQuad, DevFmtFloat }, + + { AL_FORMAT_51CHN8, DevFmtX51, DevFmtUByte }, + { AL_FORMAT_51CHN16, DevFmtX51, DevFmtShort }, + { AL_FORMAT_51CHN32, DevFmtX51, DevFmtFloat }, + + { AL_FORMAT_61CHN8, DevFmtX61, DevFmtUByte }, + { AL_FORMAT_61CHN16, DevFmtX61, DevFmtShort }, + { AL_FORMAT_61CHN32, DevFmtX61, DevFmtFloat }, + + { AL_FORMAT_71CHN8, DevFmtX71, DevFmtUByte }, + { AL_FORMAT_71CHN16, DevFmtX71, DevFmtShort }, + { AL_FORMAT_71CHN32, DevFmtX71, DevFmtFloat }, + }; + + for(const auto &item : list) + { + if(item.format == format) + return al::make_optional(DevFmtPair{item.channels, item.type}); + } + + return al::nullopt; +} + +static ALCboolean IsValidALCType(ALCenum type) +{ + switch(type) + { + case ALC_BYTE_SOFT: + case ALC_UNSIGNED_BYTE_SOFT: + case ALC_SHORT_SOFT: + case ALC_UNSIGNED_SHORT_SOFT: + case ALC_INT_SOFT: + case ALC_UNSIGNED_INT_SOFT: + case ALC_FLOAT_SOFT: + return ALC_TRUE; + } + return ALC_FALSE; +} + +static ALCboolean IsValidALCChannels(ALCenum channels) +{ + switch(channels) + { + case ALC_MONO_SOFT: + case ALC_STEREO_SOFT: + case ALC_QUAD_SOFT: + case ALC_5POINT1_SOFT: + case ALC_6POINT1_SOFT: + case ALC_7POINT1_SOFT: + case ALC_BFORMAT3D_SOFT: + return ALC_TRUE; + } + return ALC_FALSE; +} + +static ALCboolean IsValidAmbiLayout(ALCenum layout) +{ + switch(layout) + { + case ALC_ACN_SOFT: + case ALC_FUMA_SOFT: + return ALC_TRUE; + } + return ALC_FALSE; +} + +static ALCboolean IsValidAmbiScaling(ALCenum scaling) +{ + switch(scaling) + { + case ALC_N3D_SOFT: + case ALC_SN3D_SOFT: + case ALC_FUMA_SOFT: + return ALC_TRUE; + } + return ALC_FALSE; +} + +/************************************************ + * Miscellaneous ALC helpers + ************************************************/ + +/* SetDefaultWFXChannelOrder + * + * Sets the default channel order used by WaveFormatEx. + */ +void SetDefaultWFXChannelOrder(ALCdevice *device) +{ + device->RealOut.ChannelIndex.fill(-1); + + switch(device->FmtChans) + { + case DevFmtMono: + device->RealOut.ChannelIndex[FrontCenter] = 0; + break; + case DevFmtStereo: + device->RealOut.ChannelIndex[FrontLeft] = 0; + device->RealOut.ChannelIndex[FrontRight] = 1; + break; + case DevFmtQuad: + device->RealOut.ChannelIndex[FrontLeft] = 0; + device->RealOut.ChannelIndex[FrontRight] = 1; + device->RealOut.ChannelIndex[BackLeft] = 2; + device->RealOut.ChannelIndex[BackRight] = 3; + break; + case DevFmtX51: + device->RealOut.ChannelIndex[FrontLeft] = 0; + device->RealOut.ChannelIndex[FrontRight] = 1; + device->RealOut.ChannelIndex[FrontCenter] = 2; + device->RealOut.ChannelIndex[LFE] = 3; + device->RealOut.ChannelIndex[SideLeft] = 4; + device->RealOut.ChannelIndex[SideRight] = 5; + break; + case DevFmtX51Rear: + device->RealOut.ChannelIndex[FrontLeft] = 0; + device->RealOut.ChannelIndex[FrontRight] = 1; + device->RealOut.ChannelIndex[FrontCenter] = 2; + device->RealOut.ChannelIndex[LFE] = 3; + device->RealOut.ChannelIndex[BackLeft] = 4; + device->RealOut.ChannelIndex[BackRight] = 5; + break; + case DevFmtX61: + device->RealOut.ChannelIndex[FrontLeft] = 0; + device->RealOut.ChannelIndex[FrontRight] = 1; + device->RealOut.ChannelIndex[FrontCenter] = 2; + device->RealOut.ChannelIndex[LFE] = 3; + device->RealOut.ChannelIndex[BackCenter] = 4; + device->RealOut.ChannelIndex[SideLeft] = 5; + device->RealOut.ChannelIndex[SideRight] = 6; + break; + case DevFmtX71: + device->RealOut.ChannelIndex[FrontLeft] = 0; + device->RealOut.ChannelIndex[FrontRight] = 1; + device->RealOut.ChannelIndex[FrontCenter] = 2; + device->RealOut.ChannelIndex[LFE] = 3; + device->RealOut.ChannelIndex[BackLeft] = 4; + device->RealOut.ChannelIndex[BackRight] = 5; + device->RealOut.ChannelIndex[SideLeft] = 6; + device->RealOut.ChannelIndex[SideRight] = 7; + break; + case DevFmtAmbi3D: + device->RealOut.ChannelIndex[Aux0] = 0; + if(device->mAmbiOrder > 0) + { + device->RealOut.ChannelIndex[Aux1] = 1; + device->RealOut.ChannelIndex[Aux2] = 2; + device->RealOut.ChannelIndex[Aux3] = 3; + } + if(device->mAmbiOrder > 1) + { + device->RealOut.ChannelIndex[Aux4] = 4; + device->RealOut.ChannelIndex[Aux5] = 5; + device->RealOut.ChannelIndex[Aux6] = 6; + device->RealOut.ChannelIndex[Aux7] = 7; + device->RealOut.ChannelIndex[Aux8] = 8; + } + if(device->mAmbiOrder > 2) + { + device->RealOut.ChannelIndex[Aux9] = 9; + device->RealOut.ChannelIndex[Aux10] = 10; + device->RealOut.ChannelIndex[Aux11] = 11; + device->RealOut.ChannelIndex[Aux12] = 12; + device->RealOut.ChannelIndex[Aux13] = 13; + device->RealOut.ChannelIndex[Aux14] = 14; + device->RealOut.ChannelIndex[Aux15] = 15; + } + break; + } +} + +/* SetDefaultChannelOrder + * + * Sets the default channel order used by most non-WaveFormatEx-based APIs. + */ +void SetDefaultChannelOrder(ALCdevice *device) +{ + device->RealOut.ChannelIndex.fill(-1); + + switch(device->FmtChans) + { + case DevFmtX51Rear: + device->RealOut.ChannelIndex[FrontLeft] = 0; + device->RealOut.ChannelIndex[FrontRight] = 1; + device->RealOut.ChannelIndex[BackLeft] = 2; + device->RealOut.ChannelIndex[BackRight] = 3; + device->RealOut.ChannelIndex[FrontCenter] = 4; + device->RealOut.ChannelIndex[LFE] = 5; + return; + case DevFmtX71: + device->RealOut.ChannelIndex[FrontLeft] = 0; + device->RealOut.ChannelIndex[FrontRight] = 1; + device->RealOut.ChannelIndex[BackLeft] = 2; + device->RealOut.ChannelIndex[BackRight] = 3; + device->RealOut.ChannelIndex[FrontCenter] = 4; + device->RealOut.ChannelIndex[LFE] = 5; + device->RealOut.ChannelIndex[SideLeft] = 6; + device->RealOut.ChannelIndex[SideRight] = 7; + return; + + /* Same as WFX order */ + case DevFmtMono: + case DevFmtStereo: + case DevFmtQuad: + case DevFmtX51: + case DevFmtX61: + case DevFmtAmbi3D: + SetDefaultWFXChannelOrder(device); + break; + } +} + + +/* ALCcontext_DeferUpdates + * + * Defers/suspends updates for the given context's listener and sources. This + * does *NOT* stop mixing, but rather prevents certain property changes from + * taking effect. + */ +void ALCcontext_DeferUpdates(ALCcontext *context) +{ + context->DeferUpdates.store(true); +} + +/* ALCcontext_ProcessUpdates + * + * Resumes update processing after being deferred. + */ +void ALCcontext_ProcessUpdates(ALCcontext *context) +{ + std::lock_guard _{context->PropLock}; + if(context->DeferUpdates.exchange(false)) + { + /* Tell the mixer to stop applying updates, then wait for any active + * updating to finish, before providing updates. + */ + context->HoldUpdates.store(true, std::memory_order_release); + while((context->UpdateCount.load(std::memory_order_acquire)&1) != 0) + std::this_thread::yield(); + + if(!context->PropsClean.test_and_set(std::memory_order_acq_rel)) + UpdateContextProps(context); + if(!context->Listener.PropsClean.test_and_set(std::memory_order_acq_rel)) + UpdateListenerProps(context); + UpdateAllEffectSlotProps(context); + UpdateAllSourceProps(context); + + /* Now with all updates declared, let the mixer continue applying them + * so they all happen at once. + */ + context->HoldUpdates.store(false, std::memory_order_release); + } +} + + +/* alcSetError + * + * Stores the latest ALC device error + */ +static void alcSetError(ALCdevice *device, ALCenum errorCode) +{ + WARN("Error generated on device %p, code 0x%04x\n", device, errorCode); + if(TrapALCError) + { +#ifdef _WIN32 + /* DebugBreak() will cause an exception if there is no debugger */ + if(IsDebuggerPresent()) + DebugBreak(); +#elif defined(SIGTRAP) + raise(SIGTRAP); +#endif + } + + if(device) + device->LastError.store(errorCode); + else + LastNullDeviceError.store(errorCode); +} + + +static std::unique_ptr CreateDeviceLimiter(const ALCdevice *device, const ALfloat threshold) +{ + return CompressorInit(static_cast(device->RealOut.Buffer.size()), device->Frequency, + AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, 0.001f, 0.002f, 0.0f, 0.0f, threshold, + INFINITY, 0.0f, 0.020f, 0.200f); +} + +/* UpdateClockBase + * + * Updates the device's base clock time with however many samples have been + * done. This is used so frequency changes on the device don't cause the time + * to jump forward or back. Must not be called while the device is running/ + * mixing. + */ +static inline void UpdateClockBase(ALCdevice *device) +{ + IncrementRef(&device->MixCount); + device->ClockBase += nanoseconds{seconds{device->SamplesDone}} / device->Frequency; + device->SamplesDone = 0; + IncrementRef(&device->MixCount); +} + +/* UpdateDeviceParams + * + * Updates device parameters according to the attribute list (caller is + * responsible for holding the list lock). + */ +static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) +{ + HrtfRequestMode hrtf_userreq = Hrtf_Default; + HrtfRequestMode hrtf_appreq = Hrtf_Default; + ALCenum gainLimiter = device->LimiterState; + const ALsizei old_sends = device->NumAuxSends; + ALsizei new_sends = device->NumAuxSends; + DevFmtChannels oldChans; + DevFmtType oldType; + ALboolean update_failed; + ALCsizei hrtf_id = -1; + ALCuint oldFreq; + + if((!attrList || !attrList[0]) && device->Type == Loopback) + { + WARN("Missing attributes for loopback device\n"); + return ALC_INVALID_VALUE; + } + + // Check for attributes + if(attrList && attrList[0]) + { + ALCenum alayout{AL_NONE}; + ALCenum ascale{AL_NONE}; + ALCenum schans{AL_NONE}; + ALCenum stype{AL_NONE}; + ALCsizei attrIdx{0}; + ALCsizei aorder{0}; + ALCuint freq{0u}; + + ALuint numMono{device->NumMonoSources}; + ALuint numStereo{device->NumStereoSources}; + ALsizei numSends{old_sends}; + +#define TRACE_ATTR(a, v) TRACE("%s = %d\n", #a, v) + while(attrList[attrIdx]) + { + switch(attrList[attrIdx]) + { + case ALC_FORMAT_CHANNELS_SOFT: + schans = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_FORMAT_CHANNELS_SOFT, schans); + break; + + case ALC_FORMAT_TYPE_SOFT: + stype = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_FORMAT_TYPE_SOFT, stype); + break; + + case ALC_FREQUENCY: + freq = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_FREQUENCY, freq); + break; + + case ALC_AMBISONIC_LAYOUT_SOFT: + alayout = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_AMBISONIC_LAYOUT_SOFT, alayout); + break; + + case ALC_AMBISONIC_SCALING_SOFT: + ascale = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_AMBISONIC_SCALING_SOFT, ascale); + break; + + case ALC_AMBISONIC_ORDER_SOFT: + aorder = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_AMBISONIC_ORDER_SOFT, aorder); + break; + + case ALC_MONO_SOURCES: + numMono = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_MONO_SOURCES, numMono); + if(numMono > INT_MAX) numMono = 0; + break; + + case ALC_STEREO_SOURCES: + numStereo = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); + if(numStereo > INT_MAX) numStereo = 0; + break; + + case ALC_MAX_AUXILIARY_SENDS: + numSends = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_MAX_AUXILIARY_SENDS, numSends); + numSends = clampi(numSends, 0, MAX_SENDS); + break; + + case ALC_HRTF_SOFT: + TRACE_ATTR(ALC_HRTF_SOFT, attrList[attrIdx + 1]); + if(attrList[attrIdx + 1] == ALC_FALSE) + hrtf_appreq = Hrtf_Disable; + else if(attrList[attrIdx + 1] == ALC_TRUE) + hrtf_appreq = Hrtf_Enable; + else + hrtf_appreq = Hrtf_Default; + break; + + case ALC_HRTF_ID_SOFT: + hrtf_id = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_HRTF_ID_SOFT, hrtf_id); + break; + + case ALC_OUTPUT_LIMITER_SOFT: + gainLimiter = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_OUTPUT_LIMITER_SOFT, gainLimiter); + break; + + default: + TRACE("0x%04X = %d (0x%x)\n", attrList[attrIdx], + attrList[attrIdx + 1], attrList[attrIdx + 1]); + break; + } + + attrIdx += 2; + } +#undef TRACE_ATTR + + const bool loopback{device->Type == Loopback}; + if(loopback) + { + if(!schans || !stype || !freq) + { + WARN("Missing format for loopback device\n"); + return ALC_INVALID_VALUE; + } + if(!IsValidALCChannels(schans) || !IsValidALCType(stype) || freq < MIN_OUTPUT_RATE) + return ALC_INVALID_VALUE; + if(schans == ALC_BFORMAT3D_SOFT) + { + if(!alayout || !ascale || !aorder) + { + WARN("Missing ambisonic info for loopback device\n"); + return ALC_INVALID_VALUE; + } + if(!IsValidAmbiLayout(alayout) || !IsValidAmbiScaling(ascale)) + return ALC_INVALID_VALUE; + if(aorder < 1 || aorder > MAX_AMBI_ORDER) + return ALC_INVALID_VALUE; + if((alayout == ALC_FUMA_SOFT || ascale == ALC_FUMA_SOFT) && aorder > 3) + return ALC_INVALID_VALUE; + } + } + + /* If a context is already running on the device, stop playback so the + * device attributes can be updated. + */ + if(device->Flags.get()) + device->Backend->stop(); + device->Flags.unset(); + + UpdateClockBase(device); + + const char *devname{nullptr}; + if(!loopback) + { + devname = device->DeviceName.c_str(); + + device->BufferSize = DEFAULT_UPDATE_SIZE * DEFAULT_NUM_UPDATES; + device->UpdateSize = DEFAULT_UPDATE_SIZE; + device->Frequency = DEFAULT_OUTPUT_RATE; + + freq = ConfigValueUInt(devname, nullptr, "frequency").value_or(freq); + if(freq < 1) + device->Flags.unset(); + else + { + freq = maxi(freq, MIN_OUTPUT_RATE); + + device->UpdateSize = (device->UpdateSize*freq + device->Frequency/2) / + device->Frequency; + device->BufferSize = (device->BufferSize*freq + device->Frequency/2) / + device->Frequency; + + device->Frequency = freq; + device->Flags.set(); + } + + if(auto persizeopt = ConfigValueUInt(devname, nullptr, "period_size")) + device->UpdateSize = clampu(*persizeopt, 64, 8192); + + if(auto peropt = ConfigValueUInt(devname, nullptr, "periods")) + device->BufferSize = device->UpdateSize * clampu(*peropt, 2, 16); + else + device->BufferSize = maxu(device->BufferSize, device->UpdateSize*2); + } + else + { + device->Frequency = freq; + device->FmtChans = static_cast(schans); + device->FmtType = static_cast(stype); + if(schans == ALC_BFORMAT3D_SOFT) + { + device->mAmbiOrder = aorder; + device->mAmbiLayout = static_cast(alayout); + device->mAmbiScale = static_cast(ascale); + } + } + + if(numMono > INT_MAX-numStereo) + numMono = INT_MAX-numStereo; + numMono += numStereo; + if(auto srcsopt = ConfigValueUInt(devname, nullptr, "sources")) + { + if(*srcsopt <= 0) numMono = 256; + else numMono = *srcsopt; + } + else + numMono = maxu(numMono, 256); + numStereo = minu(numStereo, numMono); + numMono -= numStereo; + device->SourcesMax = numMono + numStereo; + + device->NumMonoSources = numMono; + device->NumStereoSources = numStereo; + + if(auto sendsopt = ConfigValueInt(devname, nullptr, "sends")) + new_sends = mini(numSends, clampi(*sendsopt, 0, MAX_SENDS)); + else + new_sends = numSends; + } + + if(device->Flags.get()) + return ALC_NO_ERROR; + + device->AvgSpeakerDist = 0.0f; + device->Uhj_Encoder = nullptr; + device->AmbiDecoder = nullptr; + device->Bs2b = nullptr; + device->PostProcess = nullptr; + + device->Stablizer = nullptr; + device->Limiter = nullptr; + device->ChannelDelay.clear(); + + device->Dry.AmbiMap.fill(BFChannelConfig{}); + device->Dry.Buffer = {}; + std::fill(std::begin(device->NumChannelsPerOrder), std::end(device->NumChannelsPerOrder), 0u); + device->RealOut.ChannelIndex.fill(-1); + device->RealOut.Buffer = {}; + device->MixBuffer.clear(); + device->MixBuffer.shrink_to_fit(); + + UpdateClockBase(device); + device->FixedLatency = nanoseconds::zero(); + + device->DitherDepth = 0.0f; + device->DitherSeed = DITHER_RNG_SEED; + + /************************************************************************* + * Update device format request if HRTF is requested + */ + device->HrtfStatus = ALC_HRTF_DISABLED_SOFT; + if(device->Type != Loopback) + { + if(auto hrtfopt = ConfigValueStr(device->DeviceName.c_str(), nullptr, "hrtf")) + { + const char *hrtf{hrtfopt->c_str()}; + if(strcasecmp(hrtf, "true") == 0) + hrtf_userreq = Hrtf_Enable; + else if(strcasecmp(hrtf, "false") == 0) + hrtf_userreq = Hrtf_Disable; + else if(strcasecmp(hrtf, "auto") != 0) + ERR("Unexpected hrtf value: %s\n", hrtf); + } + + if(hrtf_userreq == Hrtf_Enable || (hrtf_userreq != Hrtf_Disable && hrtf_appreq == Hrtf_Enable)) + { + HrtfEntry *hrtf{nullptr}; + if(device->HrtfList.empty()) + device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); + if(!device->HrtfList.empty()) + { + if(hrtf_id >= 0 && static_cast(hrtf_id) < device->HrtfList.size()) + hrtf = GetLoadedHrtf(device->HrtfList[hrtf_id].hrtf); + else + hrtf = GetLoadedHrtf(device->HrtfList.front().hrtf); + } + + if(hrtf) + { + device->FmtChans = DevFmtStereo; + device->Frequency = hrtf->sampleRate; + device->Flags.set(); + if(HrtfEntry *oldhrtf{device->mHrtf}) + oldhrtf->DecRef(); + device->mHrtf = hrtf; + } + else + { + hrtf_userreq = Hrtf_Default; + hrtf_appreq = Hrtf_Disable; + device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + } + } + } + + oldFreq = device->Frequency; + oldChans = device->FmtChans; + oldType = device->FmtType; + + TRACE("Pre-reset: %s%s, %s%s, %s%uhz, %u / %u buffer\n", + device->Flags.get()?"*":"", DevFmtChannelsString(device->FmtChans), + device->Flags.get()?"*":"", DevFmtTypeString(device->FmtType), + device->Flags.get()?"*":"", device->Frequency, + device->UpdateSize, device->BufferSize); + + try { + if(device->Backend->reset() == ALC_FALSE) + return ALC_INVALID_DEVICE; + } + catch(std::exception &e) { + ERR("Device reset failed: %s\n", e.what()); + return ALC_INVALID_DEVICE; + } + + if(device->FmtChans != oldChans && device->Flags.get()) + { + ERR("Failed to set %s, got %s instead\n", DevFmtChannelsString(oldChans), + DevFmtChannelsString(device->FmtChans)); + device->Flags.unset(); + } + if(device->FmtType != oldType && device->Flags.get()) + { + ERR("Failed to set %s, got %s instead\n", DevFmtTypeString(oldType), + DevFmtTypeString(device->FmtType)); + device->Flags.unset(); + } + if(device->Frequency != oldFreq && device->Flags.get()) + { + WARN("Failed to set %uhz, got %uhz instead\n", oldFreq, device->Frequency); + device->Flags.unset(); + } + + TRACE("Post-reset: %s, %s, %uhz, %u / %u buffer\n", + DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), + device->Frequency, device->UpdateSize, device->BufferSize); + + aluInitRenderer(device, hrtf_id, hrtf_appreq, hrtf_userreq); + + device->NumAuxSends = new_sends; + TRACE("Max sources: %d (%d + %d), effect slots: %d, sends: %d\n", + device->SourcesMax, device->NumMonoSources, device->NumStereoSources, + device->AuxiliaryEffectSlotMax, device->NumAuxSends); + + /* Enable the stablizer only for formats that have front-left, front-right, + * and front-center outputs. + */ + switch(device->FmtChans) + { + case DevFmtX51: + case DevFmtX51Rear: + case DevFmtX61: + case DevFmtX71: + if(GetConfigValueBool(device->DeviceName.c_str(), nullptr, "front-stablizer", 0)) + { + auto stablizer = al::make_unique(); + /* Initialize band-splitting filters for the front-left and front- + * right channels, with a crossover at 5khz (could be higher). + */ + const ALfloat scale{5000.0f / static_cast(device->Frequency)}; + + stablizer->LFilter.init(scale); + stablizer->RFilter = stablizer->LFilter; + + device->Stablizer = std::move(stablizer); + /* NOTE: Don't know why this has to be "copied" into a local static + * constexpr variable to avoid a reference on + * FrontStablizer::DelayLength... + */ + static constexpr size_t StablizerDelay{FrontStablizer::DelayLength}; + device->FixedLatency += nanoseconds{seconds{StablizerDelay}} / device->Frequency; + } + break; + case DevFmtMono: + case DevFmtStereo: + case DevFmtQuad: + case DevFmtAmbi3D: + break; + } + TRACE("Front stablizer %s\n", device->Stablizer ? "enabled" : "disabled"); + + if(GetConfigValueBool(device->DeviceName.c_str(), nullptr, "dither", 1)) + { + ALint depth{ + ConfigValueInt(device->DeviceName.c_str(), nullptr, "dither-depth").value_or(0)}; + if(depth <= 0) + { + switch(device->FmtType) + { + case DevFmtByte: + case DevFmtUByte: + depth = 8; + break; + case DevFmtShort: + case DevFmtUShort: + depth = 16; + break; + case DevFmtInt: + case DevFmtUInt: + case DevFmtFloat: + break; + } + } + + if(depth > 0) + { + depth = clampi(depth, 2, 24); + device->DitherDepth = std::pow(2.0f, static_cast(depth-1)); + } + } + if(!(device->DitherDepth > 0.0f)) + TRACE("Dithering disabled\n"); + else + TRACE("Dithering enabled (%d-bit, %g)\n", float2int(std::log2(device->DitherDepth)+0.5f)+1, + device->DitherDepth); + + device->LimiterState = gainLimiter; + if(auto limopt = ConfigValueBool(device->DeviceName.c_str(), nullptr, "output-limiter")) + gainLimiter = *limopt ? ALC_TRUE : ALC_FALSE; + + /* Valid values for gainLimiter are ALC_DONT_CARE_SOFT, ALC_TRUE, and + * ALC_FALSE. For ALC_DONT_CARE_SOFT, use the limiter for integer-based + * output (where samples must be clamped), and don't for floating-point + * (which can take unclamped samples). + */ + if(gainLimiter == ALC_DONT_CARE_SOFT) + { + switch(device->FmtType) + { + case DevFmtByte: + case DevFmtUByte: + case DevFmtShort: + case DevFmtUShort: + case DevFmtInt: + case DevFmtUInt: + gainLimiter = ALC_TRUE; + break; + case DevFmtFloat: + gainLimiter = ALC_FALSE; + break; + } + } + if(gainLimiter == ALC_FALSE) + TRACE("Output limiter disabled\n"); + else + { + ALfloat thrshld = 1.0f; + switch(device->FmtType) + { + case DevFmtByte: + case DevFmtUByte: + thrshld = 127.0f / 128.0f; + break; + case DevFmtShort: + case DevFmtUShort: + thrshld = 32767.0f / 32768.0f; + break; + case DevFmtInt: + case DevFmtUInt: + case DevFmtFloat: + break; + } + if(device->DitherDepth > 0.0f) + thrshld -= 1.0f / device->DitherDepth; + + const float thrshld_dB{std::log10(thrshld) * 20.0f}; + auto limiter = CreateDeviceLimiter(device, thrshld_dB); + /* Convert the lookahead from samples to nanosamples to nanoseconds. */ + device->FixedLatency += nanoseconds{seconds{limiter->getLookAhead()}} / device->Frequency; + device->Limiter = std::move(limiter); + TRACE("Output limiter enabled, %.4fdB limit\n", thrshld_dB); + } + + TRACE("Fixed device latency: %ldns\n", (long)device->FixedLatency.count()); + + /* Need to delay returning failure until replacement Send arrays have been + * allocated with the appropriate size. + */ + update_failed = AL_FALSE; + FPUCtl mixer_mode{}; + for(ALCcontext *context : *device->mContexts.load()) + { + if(context->DefaultSlot) + { + ALeffectslot *slot = context->DefaultSlot.get(); + aluInitEffectPanning(slot, device); + + EffectState *state{slot->Effect.State}; + state->mOutTarget = device->Dry.Buffer; + if(state->deviceUpdate(device) == AL_FALSE) + update_failed = AL_TRUE; + else + UpdateEffectSlotProps(slot, context); + } + + std::unique_lock proplock{context->PropLock}; + std::unique_lock slotlock{context->EffectSlotLock}; + for(auto &sublist : context->EffectSlotList) + { + uint64_t usemask = ~sublist.FreeMask; + while(usemask) + { + ALsizei idx = CTZ64(usemask); + ALeffectslot *slot = sublist.EffectSlots + idx; + + usemask &= ~(1_u64 << idx); + + aluInitEffectPanning(slot, device); + + EffectState *state{slot->Effect.State}; + state->mOutTarget = device->Dry.Buffer; + if(state->deviceUpdate(device) == AL_FALSE) + update_failed = AL_TRUE; + else + UpdateEffectSlotProps(slot, context); + } + } + slotlock.unlock(); + + std::unique_lock srclock{context->SourceLock}; + for(auto &sublist : context->SourceList) + { + uint64_t usemask = ~sublist.FreeMask; + while(usemask) + { + ALsizei idx = CTZ64(usemask); + ALsource *source = sublist.Sources + idx; + + usemask &= ~(1_u64 << idx); + + if(old_sends != device->NumAuxSends) + { + ALsizei s; + for(s = device->NumAuxSends;s < old_sends;s++) + { + if(source->Send[s].Slot) + DecrementRef(&source->Send[s].Slot->ref); + source->Send[s].Slot = nullptr; + } + source->Send.resize(device->NumAuxSends); + source->Send.shrink_to_fit(); + for(s = old_sends;s < device->NumAuxSends;s++) + { + source->Send[s].Slot = nullptr; + source->Send[s].Gain = 1.0f; + source->Send[s].GainHF = 1.0f; + source->Send[s].HFReference = LOWPASSFREQREF; + source->Send[s].GainLF = 1.0f; + source->Send[s].LFReference = HIGHPASSFREQREF; + } + } + + source->PropsClean.clear(std::memory_order_release); + } + } + + /* Clear any pre-existing voice property structs, in case the number of + * auxiliary sends is changing. Active sources will have updates + * respecified in UpdateAllSourceProps. + */ + ALvoiceProps *vprops{context->FreeVoiceProps.exchange(nullptr, std::memory_order_acq_rel)}; + while(vprops) + { + ALvoiceProps *next = vprops->next.load(std::memory_order_relaxed); + delete vprops; + vprops = next; + } + + auto voices = context->Voices.get(); + auto voices_end = voices->begin() + context->VoiceCount.load(std::memory_order_relaxed); + if(device->NumAuxSends < old_sends) + { + const ALsizei num_sends{device->NumAuxSends}; + /* Clear extraneous property set sends. */ + auto clear_sends = [num_sends](ALvoice &voice) -> void + { + std::fill(std::begin(voice.mProps.Send)+num_sends, std::end(voice.mProps.Send), + ALvoiceProps::SendData{}); + + std::fill(voice.mSend.begin()+num_sends, voice.mSend.end(), ALvoice::SendData{}); + auto clear_chan_sends = [num_sends](ALvoice::ChannelData &chandata) -> void + { + std::fill(chandata.mWetParams.begin()+num_sends, chandata.mWetParams.end(), + SendParams{}); + }; + std::for_each(voice.mChans.begin(), voice.mChans.end(), clear_chan_sends); + }; + std::for_each(voices->begin(), voices_end, clear_sends); + } + std::for_each(voices->begin(), voices_end, + [device](ALvoice &voice) -> void + { + delete voice.mUpdate.exchange(nullptr, std::memory_order_acq_rel); + + /* Force the voice to stopped if it was stopping. */ + ALvoice::State vstate{ALvoice::Stopping}; + voice.mPlayState.compare_exchange_strong(vstate, ALvoice::Stopped, + std::memory_order_acquire, std::memory_order_acquire); + if(voice.mSourceID.load(std::memory_order_relaxed) == 0u) + return; + + if(device->AvgSpeakerDist > 0.0f) + { + /* Reinitialize the NFC filters for new parameters. */ + const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC / + (device->AvgSpeakerDist * device->Frequency)}; + auto init_nfc = [w1](ALvoice::ChannelData &chandata) -> void + { chandata.mDryParams.NFCtrlFilter.init(w1); }; + std::for_each(voice.mChans.begin(), voice.mChans.begin()+voice.mNumChannels, + init_nfc); + } + } + ); + srclock.unlock(); + + context->PropsClean.test_and_set(std::memory_order_release); + UpdateContextProps(context); + context->Listener.PropsClean.test_and_set(std::memory_order_release); + UpdateListenerProps(context); + UpdateAllSourceProps(context); + } + mixer_mode.leave(); + if(update_failed) + return ALC_INVALID_DEVICE; + + if(!device->Flags.get()) + { + if(device->Backend->start() == ALC_FALSE) + return ALC_INVALID_DEVICE; + device->Flags.set(); + } + + return ALC_NO_ERROR; +} + + +ALCdevice::ALCdevice(DeviceType type) : Type{type}, mContexts{&EmptyContextArray} +{ +} + +/* ALCdevice::~ALCdevice + * + * Frees the device structure, and destroys any objects the app failed to + * delete. Called once there's no more references on the device. + */ +ALCdevice::~ALCdevice() +{ + TRACE("Freeing device %p\n", this); + + Backend = nullptr; + + size_t count{std::accumulate(BufferList.cbegin(), BufferList.cend(), size_t{0u}, + [](size_t cur, const BufferSubList &sublist) noexcept -> size_t + { return cur + POPCNT64(~sublist.FreeMask); } + )}; + if(count > 0) + WARN("%zu Buffer%s not deleted\n", count, (count==1)?"":"s"); + + count = std::accumulate(EffectList.cbegin(), EffectList.cend(), size_t{0u}, + [](size_t cur, const EffectSubList &sublist) noexcept -> size_t + { return cur + POPCNT64(~sublist.FreeMask); } + ); + if(count > 0) + WARN("%zu Effect%s not deleted\n", count, (count==1)?"":"s"); + + count = std::accumulate(FilterList.cbegin(), FilterList.cend(), size_t{0u}, + [](size_t cur, const FilterSubList &sublist) noexcept -> size_t + { return cur + POPCNT64(~sublist.FreeMask); } + ); + if(count > 0) + WARN("%zu Filter%s not deleted\n", count, (count==1)?"":"s"); + + if(mHrtf) + mHrtf->DecRef(); + mHrtf = nullptr; + + auto *oldarray = mContexts.exchange(nullptr, std::memory_order_relaxed); + if(oldarray != &EmptyContextArray) delete oldarray; +} + + +/* VerifyDevice + * + * Checks if the device handle is valid, and returns a new reference if so. + */ +static DeviceRef VerifyDevice(ALCdevice *device) +{ + std::lock_guard _{ListLock}; + auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device); + if(iter != DeviceList.cend() && *iter == device) + { + ALCdevice_IncRef(iter->get()); + return DeviceRef{iter->get()}; + } + return DeviceRef{}; +} + + +ALCcontext::ALCcontext(ALCdevice *device) : Device{device} +{ + PropsClean.test_and_set(std::memory_order_relaxed); +} + +/* InitContext + * + * Initializes context fields + */ +static ALvoid InitContext(ALCcontext *Context) +{ + ALlistener &listener = Context->Listener; + ALeffectslotArray *auxslots; + + //Validate Context + if(!Context->DefaultSlot) + auxslots = ALeffectslot::CreatePtrArray(0); + else + { + auxslots = ALeffectslot::CreatePtrArray(1); + (*auxslots)[0] = Context->DefaultSlot.get(); + } + Context->ActiveAuxSlots.store(auxslots, std::memory_order_relaxed); + + //Set globals + Context->mDistanceModel = DistanceModel::Default; + Context->SourceDistanceModel = AL_FALSE; + Context->DopplerFactor = 1.0f; + Context->DopplerVelocity = 1.0f; + Context->SpeedOfSound = SPEEDOFSOUNDMETRESPERSEC; + Context->MetersPerUnit = AL_DEFAULT_METERS_PER_UNIT; + + Context->ExtensionList = alExtList; + + + listener.Params.Matrix = alu::Matrix::Identity(); + listener.Params.Velocity = alu::Vector{}; + listener.Params.Gain = listener.Gain; + listener.Params.MetersPerUnit = Context->MetersPerUnit; + listener.Params.DopplerFactor = Context->DopplerFactor; + listener.Params.SpeedOfSound = Context->SpeedOfSound * Context->DopplerVelocity; + listener.Params.ReverbSpeedOfSound = listener.Params.SpeedOfSound * + listener.Params.MetersPerUnit; + listener.Params.SourceDistanceModel = Context->SourceDistanceModel; + listener.Params.mDistanceModel = Context->mDistanceModel; + + + Context->AsyncEvents = CreateRingBuffer(511, sizeof(AsyncEvent), false); + StartEventThrd(Context); +} + + +/* ALCcontext::~ALCcontext() + * + * Cleans up the context, and destroys any remaining objects the app failed to + * delete. Called once there's no more references on the context. + */ +ALCcontext::~ALCcontext() +{ + TRACE("Freeing context %p\n", this); + + ALcontextProps *cprops{Update.exchange(nullptr, std::memory_order_relaxed)}; + if(cprops) + { + TRACE("Freed unapplied context update %p\n", cprops); + al_free(cprops); + } + size_t count{0}; + cprops = FreeContextProps.exchange(nullptr, std::memory_order_acquire); + while(cprops) + { + ALcontextProps *next{cprops->next.load(std::memory_order_relaxed)}; + al_free(cprops); + cprops = next; + ++count; + } + TRACE("Freed %zu context property object%s\n", count, (count==1)?"":"s"); + + count = std::accumulate(SourceList.cbegin(), SourceList.cend(), size_t{0u}, + [](size_t cur, const SourceSubList &sublist) noexcept -> size_t + { return cur + POPCNT64(~sublist.FreeMask); } + ); + if(count > 0) + WARN("%zu Source%s not deleted\n", count, (count==1)?"":"s"); + SourceList.clear(); + NumSources = 0; + + count = 0; + ALeffectslotProps *eprops{FreeEffectslotProps.exchange(nullptr, std::memory_order_acquire)}; + while(eprops) + { + ALeffectslotProps *next{eprops->next.load(std::memory_order_relaxed)}; + if(eprops->State) eprops->State->DecRef(); + al_free(eprops); + eprops = next; + ++count; + } + TRACE("Freed %zu AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s"); + + delete ActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed); + DefaultSlot = nullptr; + + count = std::accumulate(EffectSlotList.cbegin(), EffectSlotList.cend(), size_t{0u}, + [](size_t cur, const EffectSlotSubList &sublist) noexcept -> size_t + { return cur + POPCNT64(~sublist.FreeMask); } + ); + if(count > 0) + WARN("%zu AuxiliaryEffectSlot%s not deleted\n", count, (count==1)?"":"s"); + EffectSlotList.clear(); + NumEffectSlots = 0; + + count = 0; + ALvoiceProps *vprops{FreeVoiceProps.exchange(nullptr, std::memory_order_acquire)}; + while(vprops) + { + ALvoiceProps *next{vprops->next.load(std::memory_order_relaxed)}; + delete vprops; + vprops = next; + ++count; + } + TRACE("Freed %zu voice property object%s\n", count, (count==1)?"":"s"); + + Voices = nullptr; + VoiceCount.store(0, std::memory_order_relaxed); + + ALlistenerProps *lprops{Listener.Update.exchange(nullptr, std::memory_order_relaxed)}; + if(lprops) + { + TRACE("Freed unapplied listener update %p\n", lprops); + al_free(lprops); + } + count = 0; + lprops = FreeListenerProps.exchange(nullptr, std::memory_order_acquire); + while(lprops) + { + ALlistenerProps *next{lprops->next.load(std::memory_order_relaxed)}; + al_free(lprops); + lprops = next; + ++count; + } + TRACE("Freed %zu listener property object%s\n", count, (count==1)?"":"s"); + + if(AsyncEvents) + { + count = 0; + auto evt_vec = AsyncEvents->getReadVector(); + if(evt_vec.first.len > 0) + { + al::destroy_n(reinterpret_cast(evt_vec.first.buf), evt_vec.first.len); + count += evt_vec.first.len; + } + if(evt_vec.second.len > 0) + { + al::destroy_n(reinterpret_cast(evt_vec.second.buf), evt_vec.second.len); + count += evt_vec.second.len; + } + if(count > 0) + TRACE("Destructed %zu orphaned event%s\n", count, (count==1)?"":"s"); + AsyncEvents->readAdvance(count); + } + + ALCdevice_DecRef(Device); +} + +/* ReleaseContext + * + * Removes the context reference from the given device and removes it from + * being current on the running thread or globally. Returns true if other + * contexts still exist on the device. + */ +static bool ReleaseContext(ALCcontext *context, ALCdevice *device) +{ + if(LocalContext.get() == context) + { + WARN("%p released while current on thread\n", context); + LocalContext.set(nullptr); + ALCcontext_DecRef(context); + } + + ALCcontext *origctx{context}; + if(GlobalContext.compare_exchange_strong(origctx, nullptr)) + ALCcontext_DecRef(context); + + bool ret{}; + { + using ContextArray = al::FlexArray; + + /* First make sure this context exists in the device's list. */ + auto *oldarray = device->mContexts.load(std::memory_order_acquire); + if(auto toremove = std::count(oldarray->begin(), oldarray->end(), context)) + { + auto alloc_ctx_array = [](const size_t count) -> ContextArray* + { + if(count == 0) return &EmptyContextArray; + void *ptr{al_calloc(alignof(ContextArray), ContextArray::Sizeof(count))}; + return new (ptr) ContextArray{count}; + }; + auto *newarray = alloc_ctx_array(oldarray->size() - toremove); + + /* Copy the current/old context handles to the new array, excluding + * the given context. + */ + std::copy_if(oldarray->begin(), oldarray->end(), newarray->begin(), + std::bind(std::not_equal_to{}, _1, context)); + + /* Store the new context array in the device. Wait for any current + * mix to finish before deleting the old array. + */ + device->mContexts.store(newarray); + if(oldarray != &EmptyContextArray) + { + while((device->MixCount.load(std::memory_order_acquire)&1)) + std::this_thread::yield(); + delete oldarray; + } + + ret = !newarray->empty(); + } + else + ret = !oldarray->empty(); + } + + StopEventThrd(context); + + return ret; +} + +static void ALCcontext_IncRef(ALCcontext *context) +{ + auto ref = IncrementRef(&context->ref); + TRACEREF("ALCcontext %p increasing refcount to %u\n", context, ref); +} + +void ALCcontext_DecRef(ALCcontext *context) +{ + auto ref = DecrementRef(&context->ref); + TRACEREF("ALCcontext %p decreasing refcount to %u\n", context, ref); + if(UNLIKELY(ref == 0)) delete context; +} + +/* VerifyContext + * + * Checks if the given context is valid, returning a new reference to it if so. + */ +static ContextRef VerifyContext(ALCcontext *context) +{ + std::lock_guard _{ListLock}; + auto iter = std::lower_bound(ContextList.cbegin(), ContextList.cend(), context); + if(iter != ContextList.cend() && *iter == context) + { + ALCcontext_IncRef(iter->get()); + return ContextRef{iter->get()}; + } + return ContextRef{}; +} + + +/* GetContextRef + * + * Returns a new reference to the currently active context for this thread. + */ +ContextRef GetContextRef(void) +{ + ALCcontext *context{LocalContext.get()}; + if(context) + ALCcontext_IncRef(context); + else + { + std::lock_guard _{ListLock}; + context = GlobalContext.load(std::memory_order_acquire); + if(context) ALCcontext_IncRef(context); + } + return ContextRef{context}; +} + + +void AllocateVoices(ALCcontext *context, size_t num_voices) +{ + ALCdevice *device{context->Device}; + const ALsizei num_sends{device->NumAuxSends}; + + if(context->Voices && num_voices == context->Voices->size()) + return; + + std::unique_ptr> voices; + { + void *ptr{al_calloc(16, al::FlexArray::Sizeof(num_voices))}; + voices.reset(new (ptr) al::FlexArray{num_voices}); + } + + const size_t v_count{minz(context->VoiceCount.load(std::memory_order_relaxed), num_voices)}; + if(context->Voices) + { + /* Copy the old voice data to the new storage. */ + auto viter = std::move(context->Voices->begin(), context->Voices->begin()+v_count, + voices->begin()); + + /* Clear extraneous property set sends. */ + auto clear_sends = [num_sends](ALvoice &voice) -> void + { + std::fill(std::begin(voice.mProps.Send)+num_sends, std::end(voice.mProps.Send), + ALvoiceProps::SendData{}); + + std::fill(voice.mSend.begin()+num_sends, voice.mSend.end(), ALvoice::SendData{}); + auto clear_chan_sends = [num_sends](ALvoice::ChannelData &chandata) -> void + { + std::fill(chandata.mWetParams.begin()+num_sends, chandata.mWetParams.end(), + SendParams{}); + }; + std::for_each(voice.mChans.begin(), voice.mChans.end(), clear_chan_sends); + }; + std::for_each(voices->begin(), viter, clear_sends); + } + + context->Voices = std::move(voices); + context->VoiceCount.store(static_cast(v_count), std::memory_order_relaxed); +} + + +/************************************************ + * Standard ALC functions + ************************************************/ + +/* alcGetError + * + * Return last ALC generated error code for the given device + */ +ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) +START_API_FUNC +{ + DeviceRef dev{VerifyDevice(device)}; + if(dev) return dev->LastError.exchange(ALC_NO_ERROR); + return LastNullDeviceError.exchange(ALC_NO_ERROR); +} +END_API_FUNC + + +/* alcSuspendContext + * + * Suspends updates for the given context + */ +ALC_API ALCvoid ALC_APIENTRY alcSuspendContext(ALCcontext *context) +START_API_FUNC +{ + if(!SuspendDefers) + return; + + ContextRef ctx{VerifyContext(context)}; + if(!ctx) + alcSetError(nullptr, ALC_INVALID_CONTEXT); + else + ALCcontext_DeferUpdates(ctx.get()); +} +END_API_FUNC + +/* alcProcessContext + * + * Resumes processing updates for the given context + */ +ALC_API ALCvoid ALC_APIENTRY alcProcessContext(ALCcontext *context) +START_API_FUNC +{ + if(!SuspendDefers) + return; + + ContextRef ctx{VerifyContext(context)}; + if(!ctx) + alcSetError(nullptr, ALC_INVALID_CONTEXT); + else + ALCcontext_ProcessUpdates(ctx.get()); +} +END_API_FUNC + + +/* alcGetString + * + * Returns information about the device, and error strings + */ +ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum param) +START_API_FUNC +{ + const ALCchar *value = nullptr; + + switch(param) + { + case ALC_NO_ERROR: + value = alcNoError; + break; + + case ALC_INVALID_ENUM: + value = alcErrInvalidEnum; + break; + + case ALC_INVALID_VALUE: + value = alcErrInvalidValue; + break; + + case ALC_INVALID_DEVICE: + value = alcErrInvalidDevice; + break; + + case ALC_INVALID_CONTEXT: + value = alcErrInvalidContext; + break; + + case ALC_OUT_OF_MEMORY: + value = alcErrOutOfMemory; + break; + + case ALC_DEVICE_SPECIFIER: + value = alcDefaultName; + break; + + case ALC_ALL_DEVICES_SPECIFIER: + if(DeviceRef dev{VerifyDevice(Device)}) + value = dev->DeviceName.c_str(); + else + { + ProbeAllDevicesList(); + value = alcAllDevicesList.c_str(); + } + break; + + case ALC_CAPTURE_DEVICE_SPECIFIER: + if(DeviceRef dev{VerifyDevice(Device)}) + value = dev->DeviceName.c_str(); + else + { + ProbeCaptureDeviceList(); + value = alcCaptureDeviceList.c_str(); + } + break; + + /* Default devices are always first in the list */ + case ALC_DEFAULT_DEVICE_SPECIFIER: + value = alcDefaultName; + break; + + case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: + if(alcAllDevicesList.empty()) + ProbeAllDevicesList(); + + /* Copy first entry as default. */ + alcDefaultAllDevicesSpecifier = alcAllDevicesList.c_str(); + value = alcDefaultAllDevicesSpecifier.c_str(); + break; + + case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: + if(alcCaptureDeviceList.empty()) + ProbeCaptureDeviceList(); + + /* Copy first entry as default. */ + alcCaptureDefaultDeviceSpecifier = alcCaptureDeviceList.c_str(); + value = alcCaptureDefaultDeviceSpecifier.c_str(); + break; + + case ALC_EXTENSIONS: + if(VerifyDevice(Device)) + value = alcExtensionList; + else + value = alcNoDeviceExtList; + break; + + case ALC_HRTF_SPECIFIER_SOFT: + if(DeviceRef dev{VerifyDevice(Device)}) + { + std::lock_guard _{dev->StateLock}; + value = (dev->mHrtf ? dev->HrtfName.c_str() : ""); + } + else + alcSetError(nullptr, ALC_INVALID_DEVICE); + break; + + default: + alcSetError(VerifyDevice(Device).get(), ALC_INVALID_ENUM); + break; + } + + return value; +} +END_API_FUNC + + +static inline ALCsizei NumAttrsForDevice(ALCdevice *device) +{ + if(device->Type == Capture) return 9; + if(device->Type != Loopback) return 29; + if(device->FmtChans == DevFmtAmbi3D) + return 35; + return 29; +} + +static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, const al::span values) +{ + ALCsizei i; + + if(values.empty()) + { + alcSetError(device, ALC_INVALID_VALUE); + return 0; + } + + if(!device) + { + switch(param) + { + case ALC_MAJOR_VERSION: + values[0] = alcMajorVersion; + return 1; + case ALC_MINOR_VERSION: + values[0] = alcMinorVersion; + return 1; + + case ALC_ATTRIBUTES_SIZE: + case ALC_ALL_ATTRIBUTES: + case ALC_FREQUENCY: + case ALC_REFRESH: + case ALC_SYNC: + case ALC_MONO_SOURCES: + case ALC_STEREO_SOURCES: + case ALC_CAPTURE_SAMPLES: + case ALC_FORMAT_CHANNELS_SOFT: + case ALC_FORMAT_TYPE_SOFT: + case ALC_AMBISONIC_LAYOUT_SOFT: + case ALC_AMBISONIC_SCALING_SOFT: + case ALC_AMBISONIC_ORDER_SOFT: + case ALC_MAX_AMBISONIC_ORDER_SOFT: + alcSetError(nullptr, ALC_INVALID_DEVICE); + return 0; + + default: + alcSetError(nullptr, ALC_INVALID_ENUM); + return 0; + } + return 0; + } + + if(device->Type == Capture) + { + switch(param) + { + case ALC_ATTRIBUTES_SIZE: + values[0] = NumAttrsForDevice(device); + return 1; + + case ALC_ALL_ATTRIBUTES: + i = 0; + if(values.size() < static_cast(NumAttrsForDevice(device))) + alcSetError(device, ALC_INVALID_VALUE); + else + { + std::lock_guard _{device->StateLock}; + values[i++] = ALC_MAJOR_VERSION; + values[i++] = alcMajorVersion; + values[i++] = ALC_MINOR_VERSION; + values[i++] = alcMinorVersion; + values[i++] = ALC_CAPTURE_SAMPLES; + values[i++] = device->Backend->availableSamples(); + values[i++] = ALC_CONNECTED; + values[i++] = device->Connected.load(std::memory_order_relaxed); + values[i++] = 0; + } + return i; + + case ALC_MAJOR_VERSION: + values[0] = alcMajorVersion; + return 1; + case ALC_MINOR_VERSION: + values[0] = alcMinorVersion; + return 1; + + case ALC_CAPTURE_SAMPLES: + { std::lock_guard _{device->StateLock}; + values[0] = device->Backend->availableSamples(); + } + return 1; + + case ALC_CONNECTED: + { std::lock_guard _{device->StateLock}; + values[0] = device->Connected.load(std::memory_order_acquire); + } + return 1; + + default: + alcSetError(device, ALC_INVALID_ENUM); + return 0; + } + return 0; + } + + /* render device */ + switch(param) + { + case ALC_ATTRIBUTES_SIZE: + values[0] = NumAttrsForDevice(device); + return 1; + + case ALC_ALL_ATTRIBUTES: + i = 0; + if(values.size() < static_cast(NumAttrsForDevice(device))) + alcSetError(device, ALC_INVALID_VALUE); + else + { + std::lock_guard _{device->StateLock}; + values[i++] = ALC_MAJOR_VERSION; + values[i++] = alcMajorVersion; + values[i++] = ALC_MINOR_VERSION; + values[i++] = alcMinorVersion; + values[i++] = ALC_EFX_MAJOR_VERSION; + values[i++] = alcEFXMajorVersion; + values[i++] = ALC_EFX_MINOR_VERSION; + values[i++] = alcEFXMinorVersion; + + values[i++] = ALC_FREQUENCY; + values[i++] = device->Frequency; + if(device->Type != Loopback) + { + values[i++] = ALC_REFRESH; + values[i++] = device->Frequency / device->UpdateSize; + + values[i++] = ALC_SYNC; + values[i++] = ALC_FALSE; + } + else + { + if(device->FmtChans == DevFmtAmbi3D) + { + values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; + values[i++] = static_cast(device->mAmbiLayout); + + values[i++] = ALC_AMBISONIC_SCALING_SOFT; + values[i++] = static_cast(device->mAmbiScale); + + values[i++] = ALC_AMBISONIC_ORDER_SOFT; + values[i++] = device->mAmbiOrder; + } + + values[i++] = ALC_FORMAT_CHANNELS_SOFT; + values[i++] = device->FmtChans; + + values[i++] = ALC_FORMAT_TYPE_SOFT; + values[i++] = device->FmtType; + } + + values[i++] = ALC_MONO_SOURCES; + values[i++] = device->NumMonoSources; + + values[i++] = ALC_STEREO_SOURCES; + values[i++] = device->NumStereoSources; + + values[i++] = ALC_MAX_AUXILIARY_SENDS; + values[i++] = device->NumAuxSends; + + values[i++] = ALC_HRTF_SOFT; + values[i++] = (device->mHrtf ? ALC_TRUE : ALC_FALSE); + + values[i++] = ALC_HRTF_STATUS_SOFT; + values[i++] = device->HrtfStatus; + + values[i++] = ALC_OUTPUT_LIMITER_SOFT; + values[i++] = device->Limiter ? ALC_TRUE : ALC_FALSE; + + values[i++] = ALC_MAX_AMBISONIC_ORDER_SOFT; + values[i++] = MAX_AMBI_ORDER; + + values[i++] = 0; + } + return i; + + case ALC_MAJOR_VERSION: + values[0] = alcMajorVersion; + return 1; + + case ALC_MINOR_VERSION: + values[0] = alcMinorVersion; + return 1; + + case ALC_EFX_MAJOR_VERSION: + values[0] = alcEFXMajorVersion; + return 1; + + case ALC_EFX_MINOR_VERSION: + values[0] = alcEFXMinorVersion; + return 1; + + case ALC_FREQUENCY: + values[0] = device->Frequency; + return 1; + + case ALC_REFRESH: + if(device->Type == Loopback) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + { std::lock_guard _{device->StateLock}; + values[0] = device->Frequency / device->UpdateSize; + } + return 1; + + case ALC_SYNC: + if(device->Type == Loopback) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = ALC_FALSE; + return 1; + + case ALC_FORMAT_CHANNELS_SOFT: + if(device->Type != Loopback) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = device->FmtChans; + return 1; + + case ALC_FORMAT_TYPE_SOFT: + if(device->Type != Loopback) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = device->FmtType; + return 1; + + case ALC_AMBISONIC_LAYOUT_SOFT: + if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = static_cast(device->mAmbiLayout); + return 1; + + case ALC_AMBISONIC_SCALING_SOFT: + if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = static_cast(device->mAmbiScale); + return 1; + + case ALC_AMBISONIC_ORDER_SOFT: + if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = device->mAmbiOrder; + return 1; + + case ALC_MONO_SOURCES: + values[0] = device->NumMonoSources; + return 1; + + case ALC_STEREO_SOURCES: + values[0] = device->NumStereoSources; + return 1; + + case ALC_MAX_AUXILIARY_SENDS: + values[0] = device->NumAuxSends; + return 1; + + case ALC_CONNECTED: + { std::lock_guard _{device->StateLock}; + values[0] = device->Connected.load(std::memory_order_acquire); + } + return 1; + + case ALC_HRTF_SOFT: + values[0] = (device->mHrtf ? ALC_TRUE : ALC_FALSE); + return 1; + + case ALC_HRTF_STATUS_SOFT: + values[0] = device->HrtfStatus; + return 1; + + case ALC_NUM_HRTF_SPECIFIERS_SOFT: + { std::lock_guard _{device->StateLock}; + device->HrtfList.clear(); + device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); + values[0] = static_cast(minz(device->HrtfList.size(), + std::numeric_limits::max())); + } + return 1; + + case ALC_OUTPUT_LIMITER_SOFT: + values[0] = device->Limiter ? ALC_TRUE : ALC_FALSE; + return 1; + + case ALC_MAX_AMBISONIC_ORDER_SOFT: + values[0] = MAX_AMBI_ORDER; + return 1; + + default: + alcSetError(device, ALC_INVALID_ENUM); + return 0; + } + return 0; +} + +/* alcGetIntegerv + * + * Returns information about the device and the version of OpenAL + */ +ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) +START_API_FUNC +{ + DeviceRef dev{VerifyDevice(device)}; + if(size <= 0 || values == nullptr) + alcSetError(dev.get(), ALC_INVALID_VALUE); + else + GetIntegerv(dev.get(), param, {values, values+size}); +} +END_API_FUNC + +ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALCsizei size, ALCint64SOFT *values) +START_API_FUNC +{ + DeviceRef dev{VerifyDevice(device)}; + if(size <= 0 || values == nullptr) + alcSetError(dev.get(), ALC_INVALID_VALUE); + else if(!dev || dev->Type == Capture) + { + auto ivals = al::vector(size); + size = GetIntegerv(dev.get(), pname, {ivals.data(), ivals.size()}); + std::copy(ivals.begin(), ivals.begin()+size, values); + } + else /* render device */ + { + switch(pname) + { + case ALC_ATTRIBUTES_SIZE: + *values = NumAttrsForDevice(dev.get())+4; + break; + + case ALC_ALL_ATTRIBUTES: + if(size < NumAttrsForDevice(dev.get())+4) + alcSetError(dev.get(), ALC_INVALID_VALUE); + else + { + ALsizei i{0}; + std::lock_guard _{dev->StateLock}; + values[i++] = ALC_FREQUENCY; + values[i++] = dev->Frequency; + + if(dev->Type != Loopback) + { + values[i++] = ALC_REFRESH; + values[i++] = dev->Frequency / dev->UpdateSize; + + values[i++] = ALC_SYNC; + values[i++] = ALC_FALSE; + } + else + { + if(dev->FmtChans == DevFmtAmbi3D) + { + values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; + values[i++] = static_cast(dev->mAmbiLayout); + + values[i++] = ALC_AMBISONIC_SCALING_SOFT; + values[i++] = static_cast(dev->mAmbiScale); + + values[i++] = ALC_AMBISONIC_ORDER_SOFT; + values[i++] = dev->mAmbiOrder; + } + + values[i++] = ALC_FORMAT_CHANNELS_SOFT; + values[i++] = dev->FmtChans; + + values[i++] = ALC_FORMAT_TYPE_SOFT; + values[i++] = dev->FmtType; + } + + values[i++] = ALC_MONO_SOURCES; + values[i++] = dev->NumMonoSources; + + values[i++] = ALC_STEREO_SOURCES; + values[i++] = dev->NumStereoSources; + + values[i++] = ALC_MAX_AUXILIARY_SENDS; + values[i++] = dev->NumAuxSends; + + values[i++] = ALC_HRTF_SOFT; + values[i++] = (dev->mHrtf ? ALC_TRUE : ALC_FALSE); + + values[i++] = ALC_HRTF_STATUS_SOFT; + values[i++] = dev->HrtfStatus; + + values[i++] = ALC_OUTPUT_LIMITER_SOFT; + values[i++] = dev->Limiter ? ALC_TRUE : ALC_FALSE; + + ClockLatency clock{GetClockLatency(dev.get())}; + values[i++] = ALC_DEVICE_CLOCK_SOFT; + values[i++] = clock.ClockTime.count(); + + values[i++] = ALC_DEVICE_LATENCY_SOFT; + values[i++] = clock.Latency.count(); + + values[i++] = 0; + } + break; + + case ALC_DEVICE_CLOCK_SOFT: + { std::lock_guard _{dev->StateLock}; + nanoseconds basecount; + ALuint samplecount; + ALuint refcount; + do { + while(((refcount=ReadRef(&dev->MixCount))&1) != 0) + std::this_thread::yield(); + basecount = dev->ClockBase; + samplecount = dev->SamplesDone; + } while(refcount != ReadRef(&dev->MixCount)); + basecount += nanoseconds{seconds{samplecount}} / dev->Frequency; + *values = basecount.count(); + } + break; + + case ALC_DEVICE_LATENCY_SOFT: + { std::lock_guard _{dev->StateLock}; + ClockLatency clock{GetClockLatency(dev.get())}; + *values = clock.Latency.count(); + } + break; + + case ALC_DEVICE_CLOCK_LATENCY_SOFT: + if(size < 2) + alcSetError(dev.get(), ALC_INVALID_VALUE); + else + { + std::lock_guard _{dev->StateLock}; + ClockLatency clock{GetClockLatency(dev.get())}; + values[0] = clock.ClockTime.count(); + values[1] = clock.Latency.count(); + } + break; + + default: + auto ivals = al::vector(size); + size = GetIntegerv(dev.get(), pname, {ivals.data(), ivals.size()}); + std::copy(ivals.begin(), ivals.begin()+size, values); + break; + } + } +} +END_API_FUNC + + +/* alcIsExtensionPresent + * + * Determines if there is support for a particular extension + */ +ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extName) +START_API_FUNC +{ + DeviceRef dev{VerifyDevice(device)}; + if(!extName) + alcSetError(dev.get(), ALC_INVALID_VALUE); + else + { + size_t len = strlen(extName); + const char *ptr = (dev ? alcExtensionList : alcNoDeviceExtList); + while(ptr && *ptr) + { + if(strncasecmp(ptr, extName, len) == 0 && + (ptr[len] == '\0' || isspace(ptr[len]))) + return ALC_TRUE; + + if((ptr=strchr(ptr, ' ')) != nullptr) + { + do { + ++ptr; + } while(isspace(*ptr)); + } + } + } + return ALC_FALSE; +} +END_API_FUNC + + +/* alcGetProcAddress + * + * Retrieves the function address for a particular extension function + */ +ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcName) +START_API_FUNC +{ + if(!funcName) + { + DeviceRef dev{VerifyDevice(device)}; + alcSetError(dev.get(), ALC_INVALID_VALUE); + } + else + { + for(const auto &func : alcFunctions) + { + if(strcmp(func.funcName, funcName) == 0) + return func.address; + } + } + return nullptr; +} +END_API_FUNC + + +/* alcGetEnumValue + * + * Get the value for a particular ALC enumeration name + */ +ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumName) +START_API_FUNC +{ + if(!enumName) + { + DeviceRef dev{VerifyDevice(device)}; + alcSetError(dev.get(), ALC_INVALID_VALUE); + } + else + { + for(const auto &enm : alcEnumerations) + { + if(strcmp(enm.enumName, enumName) == 0) + return enm.value; + } + } + return 0; +} +END_API_FUNC + + +/* alcCreateContext + * + * Create and attach a context to the given device. + */ +ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrList) +START_API_FUNC +{ + /* Explicitly hold the list lock while taking the StateLock in case the + * device is asynchronously destroyed, to ensure this new context is + * properly cleaned up after being made. + */ + std::unique_lock listlock{ListLock}; + DeviceRef dev{VerifyDevice(device)}; + if(!dev || dev->Type == Capture || !dev->Connected.load(std::memory_order_relaxed)) + { + listlock.unlock(); + alcSetError(dev.get(), ALC_INVALID_DEVICE); + return nullptr; + } + std::unique_lock statelock{dev->StateLock}; + listlock.unlock(); + + dev->LastError.store(ALC_NO_ERROR); + + ContextRef context{new ALCcontext{dev.get()}}; + ALCdevice_IncRef(context->Device); + + ALCenum err{UpdateDeviceParams(dev.get(), attrList)}; + if(err != ALC_NO_ERROR) + { + alcSetError(dev.get(), err); + if(err == ALC_INVALID_DEVICE) + aluHandleDisconnect(dev.get(), "Device update failure"); + statelock.unlock(); + + return nullptr; + } + AllocateVoices(context.get(), 256); + + if(DefaultEffect.type != AL_EFFECT_NULL && dev->Type == Playback) + { + void *ptr{al_calloc(16, sizeof(ALeffectslot))}; + context->DefaultSlot = std::unique_ptr{new (ptr) ALeffectslot{}}; + if(InitEffectSlot(context->DefaultSlot.get()) == AL_NO_ERROR) + aluInitEffectPanning(context->DefaultSlot.get(), dev.get()); + else + { + context->DefaultSlot = nullptr; + ERR("Failed to initialize the default effect slot\n"); + } + } + + InitContext(context.get()); + + if(auto volopt = ConfigValueFloat(dev->DeviceName.c_str(), nullptr, "volume-adjust")) + { + const ALfloat valf{*volopt}; + if(!std::isfinite(valf)) + ERR("volume-adjust must be finite: %f\n", valf); + else + { + const ALfloat db{clampf(valf, -24.0f, 24.0f)}; + if(db != valf) + WARN("volume-adjust clamped: %f, range: +/-%f\n", valf, 24.0f); + context->GainBoost = std::pow(10.0f, db/20.0f); + TRACE("volume-adjust gain: %f\n", context->GainBoost); + } + } + UpdateListenerProps(context.get()); + + { + using ContextArray = al::FlexArray; + + /* Allocate a new context array, which holds 1 more than the current/ + * old array. + */ + auto *oldarray = device->mContexts.load(); + const size_t newcount{oldarray->size()+1}; + void *ptr{al_calloc(alignof(ContextArray), ContextArray::Sizeof(newcount))}; + auto *newarray = new (ptr) ContextArray{newcount}; + + /* Copy the current/old context handles to the new array, appending the + * new context. + */ + auto iter = std::copy(oldarray->begin(), oldarray->end(), newarray->begin()); + *iter = context.get(); + + /* Store the new context array in the device. Wait for any current mix + * to finish before deleting the old array. + */ + dev->mContexts.store(newarray); + if(oldarray != &EmptyContextArray) + { + while((dev->MixCount.load(std::memory_order_acquire)&1)) + std::this_thread::yield(); + delete oldarray; + } + } + statelock.unlock(); + + { + std::lock_guard _{ListLock}; + auto iter = std::lower_bound(ContextList.cbegin(), ContextList.cend(), context.get()); + ALCcontext_IncRef(context.get()); + ContextList.insert(iter, ContextRef{context.get()}); + } + + if(context->DefaultSlot) + { + if(InitializeEffect(context.get(), context->DefaultSlot.get(), &DefaultEffect) == AL_NO_ERROR) + UpdateEffectSlotProps(context->DefaultSlot.get(), context.get()); + else + ERR("Failed to initialize the default effect\n"); + } + + TRACE("Created context %p\n", context.get()); + return context.get(); +} +END_API_FUNC + +/* alcDestroyContext + * + * Remove a context from its device + */ +ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) +START_API_FUNC +{ + std::unique_lock listlock{ListLock}; + auto iter = std::lower_bound(ContextList.begin(), ContextList.end(), context); + if(iter == ContextList.end() || *iter != context) + { + listlock.unlock(); + alcSetError(nullptr, ALC_INVALID_CONTEXT); + return; + } + /* Hold an extra reference to this context so it remains valid until the + * ListLock is released. + */ + ContextRef ctx{std::move(*iter)}; + ContextList.erase(iter); + + ALCdevice *Device{ctx->Device}; + + std::lock_guard _{Device->StateLock}; + if(!ReleaseContext(ctx.get(), Device) && Device->Flags.get()) + { + Device->Backend->stop(); + Device->Flags.unset(); + } +} +END_API_FUNC + + +/* alcGetCurrentContext + * + * Returns the currently active context on the calling thread + */ +ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) +START_API_FUNC +{ + ALCcontext *Context{LocalContext.get()}; + if(!Context) Context = GlobalContext.load(); + return Context; +} +END_API_FUNC + +/* alcGetThreadContext + * + * Returns the currently active thread-local context + */ +ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) +START_API_FUNC +{ return LocalContext.get(); } +END_API_FUNC + +/* alcMakeContextCurrent + * + * Makes the given context the active process-wide context, and removes the + * thread-local context for the calling thread. + */ +ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) +START_API_FUNC +{ + /* context must be valid or nullptr */ + ContextRef ctx; + if(context) + { + ctx = VerifyContext(context); + if(!ctx) + { + alcSetError(nullptr, ALC_INVALID_CONTEXT); + return ALC_FALSE; + } + } + /* Release this reference (if any) to store it in the GlobalContext + * pointer. Take ownership of the reference (if any) that was previously + * stored there. + */ + ctx = ContextRef{GlobalContext.exchange(ctx.release())}; + + /* Reset (decrement) the previous global reference by replacing it with the + * thread-local context. Take ownership of the thread-local context + * reference (if any), clearing the storage to null. + */ + ctx = ContextRef{LocalContext.get()}; + if(ctx) LocalContext.set(nullptr); + /* Reset (decrement) the previous thread-local reference. */ + + return ALC_TRUE; +} +END_API_FUNC + +/* alcSetThreadContext + * + * Makes the given context the active context for the current thread + */ +ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) +START_API_FUNC +{ + /* context must be valid or nullptr */ + ContextRef ctx; + if(context) + { + ctx = VerifyContext(context); + if(!ctx) + { + alcSetError(nullptr, ALC_INVALID_CONTEXT); + return ALC_FALSE; + } + } + /* context's reference count is already incremented */ + ContextRef old{LocalContext.get()}; + LocalContext.set(ctx.release()); + + return ALC_TRUE; +} +END_API_FUNC + + +/* alcGetContextsDevice + * + * Returns the device that a particular context is attached to + */ +ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *Context) +START_API_FUNC +{ + ContextRef ctx{VerifyContext(Context)}; + if(!ctx) + { + alcSetError(nullptr, ALC_INVALID_CONTEXT); + return nullptr; + } + return ctx->Device; +} +END_API_FUNC + + +/* alcOpenDevice + * + * Opens the named device. + */ +ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) +START_API_FUNC +{ + DO_INITCONFIG(); + + if(!PlaybackFactory) + { + alcSetError(nullptr, ALC_INVALID_VALUE); + return nullptr; + } + + if(deviceName && (!deviceName[0] || strcasecmp(deviceName, alcDefaultName) == 0 || strcasecmp(deviceName, "openal-soft") == 0 +#ifdef _WIN32 + /* Some old Windows apps hardcode these expecting OpenAL to use a + * specific audio API, even when they're not enumerated. Creative's + * router effectively ignores them too. + */ + || strcasecmp(deviceName, "DirectSound3D") == 0 || strcasecmp(deviceName, "DirectSound") == 0 + || strcasecmp(deviceName, "MMSYSTEM") == 0 +#endif + )) + deviceName = nullptr; + + DeviceRef device{new ALCdevice{Playback}}; + + /* Set output format */ + device->FmtChans = DevFmtChannelsDefault; + device->FmtType = DevFmtTypeDefault; + device->Frequency = DEFAULT_OUTPUT_RATE; + device->UpdateSize = DEFAULT_UPDATE_SIZE; + device->BufferSize = DEFAULT_UPDATE_SIZE * DEFAULT_NUM_UPDATES; + + device->SourcesMax = 256; + device->AuxiliaryEffectSlotMax = 64; + device->NumAuxSends = DEFAULT_SENDS; + + try { + /* Create the device backend. */ + device->Backend = PlaybackFactory->createBackend(device.get(), BackendType::Playback); + + /* Find a playback device to open */ + ALCenum err{device->Backend->open(deviceName)}; + if(err != ALC_NO_ERROR) + { + alcSetError(nullptr, err); + return nullptr; + } + } + catch(al::backend_exception &e) { + WARN("Failed to open playback device: %s\n", e.what()); + alcSetError(nullptr, e.errorCode()); + return nullptr; + } + + deviceName = device->DeviceName.c_str(); + if(auto chanopt = ConfigValueStr(deviceName, nullptr, "channels")) + { + static constexpr struct ChannelMap { + const char name[16]; + DevFmtChannels chans; + ALsizei order; + } chanlist[] = { + { "mono", DevFmtMono, 0 }, + { "stereo", DevFmtStereo, 0 }, + { "quad", DevFmtQuad, 0 }, + { "surround51", DevFmtX51, 0 }, + { "surround61", DevFmtX61, 0 }, + { "surround71", DevFmtX71, 0 }, + { "surround51rear", DevFmtX51Rear, 0 }, + { "ambi1", DevFmtAmbi3D, 1 }, + { "ambi2", DevFmtAmbi3D, 2 }, + { "ambi3", DevFmtAmbi3D, 3 }, + }; + + const ALCchar *fmt{chanopt->c_str()}; + auto iter = std::find_if(std::begin(chanlist), std::end(chanlist), + [fmt](const ChannelMap &entry) -> bool + { return strcasecmp(entry.name, fmt) == 0; } + ); + if(iter == std::end(chanlist)) + ERR("Unsupported channels: %s\n", fmt); + else + { + device->FmtChans = iter->chans; + device->mAmbiOrder = iter->order; + device->Flags.set(); + } + } + if(auto typeopt = ConfigValueStr(deviceName, nullptr, "sample-type")) + { + static constexpr struct TypeMap { + const char name[16]; + DevFmtType type; + } typelist[] = { + { "int8", DevFmtByte }, + { "uint8", DevFmtUByte }, + { "int16", DevFmtShort }, + { "uint16", DevFmtUShort }, + { "int32", DevFmtInt }, + { "uint32", DevFmtUInt }, + { "float32", DevFmtFloat }, + }; + + const ALCchar *fmt{typeopt->c_str()}; + auto iter = std::find_if(std::begin(typelist), std::end(typelist), + [fmt](const TypeMap &entry) -> bool + { return strcasecmp(entry.name, fmt) == 0; } + ); + if(iter == std::end(typelist)) + ERR("Unsupported sample-type: %s\n", fmt); + else + { + device->FmtType = iter->type; + device->Flags.set(); + } + } + + if(ALuint freq{ConfigValueUInt(deviceName, nullptr, "frequency").value_or(0)}) + { + if(freq < MIN_OUTPUT_RATE) + { + ERR("%uhz request clamped to %uhz minimum\n", freq, MIN_OUTPUT_RATE); + freq = MIN_OUTPUT_RATE; + } + device->UpdateSize = (device->UpdateSize*freq + device->Frequency/2) / device->Frequency; + device->BufferSize = (device->BufferSize*freq + device->Frequency/2) / device->Frequency; + device->Frequency = freq; + device->Flags.set(); + } + + if(auto persizeopt = ConfigValueUInt(deviceName, nullptr, "period_size")) + device->UpdateSize = clampu(*persizeopt, 64, 8192); + + if(auto peropt = ConfigValueUInt(deviceName, nullptr, "periods")) + device->BufferSize = device->UpdateSize * clampu(*peropt, 2, 16); + else + device->BufferSize = maxu(device->BufferSize, device->UpdateSize*2); + + if(auto srcsopt = ConfigValueUInt(deviceName, nullptr, "sources")) + { + if(*srcsopt > 0) device->SourcesMax = *srcsopt; + } + + if(auto slotsopt = ConfigValueUInt(deviceName, nullptr, "slots")) + { + if(*slotsopt > 0) + device->AuxiliaryEffectSlotMax = minu(*slotsopt, INT_MAX); + } + + if(auto sendsopt = ConfigValueInt(deviceName, nullptr, "sends")) + device->NumAuxSends = clampi(DEFAULT_SENDS, 0, clampi(*sendsopt, 0, MAX_SENDS)); + + device->NumStereoSources = 1; + device->NumMonoSources = device->SourcesMax - device->NumStereoSources; + + if(auto ambiopt = ConfigValueStr(deviceName, nullptr, "ambi-format")) + { + const ALCchar *fmt{ambiopt->c_str()}; + if(strcasecmp(fmt, "fuma") == 0) + { + if(device->mAmbiOrder > 3) + ERR("FuMa is incompatible with %d%s order ambisonics (up to third-order only)\n", + device->mAmbiOrder, + (((device->mAmbiOrder%100)/10) == 1) ? "th" : + ((device->mAmbiOrder%10) == 1) ? "st" : + ((device->mAmbiOrder%10) == 2) ? "nd" : + ((device->mAmbiOrder%10) == 3) ? "rd" : "th"); + else + { + device->mAmbiLayout = AmbiLayout::FuMa; + device->mAmbiScale = AmbiNorm::FuMa; + } + } + else if(strcasecmp(fmt, "ambix") == 0 || strcasecmp(fmt, "acn+sn3d") == 0) + { + device->mAmbiLayout = AmbiLayout::ACN; + device->mAmbiScale = AmbiNorm::SN3D; + } + else if(strcasecmp(fmt, "acn+n3d") == 0) + { + device->mAmbiLayout = AmbiLayout::ACN; + device->mAmbiScale = AmbiNorm::N3D; + } + else + ERR("Unsupported ambi-format: %s\n", fmt); + } + + { + std::lock_guard _{ListLock}; + auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get()); + ALCdevice_IncRef(device.get()); + DeviceList.insert(iter, DeviceRef{device.get()}); + } + + TRACE("Created device %p, \"%s\"\n", device.get(), device->DeviceName.c_str()); + return device.get(); +} +END_API_FUNC + +/* alcCloseDevice + * + * Closes the given device. + */ +ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) +START_API_FUNC +{ + std::unique_lock listlock{ListLock}; + auto iter = std::lower_bound(DeviceList.begin(), DeviceList.end(), device); + if(iter == DeviceList.end() || *iter != device) + { + alcSetError(nullptr, ALC_INVALID_DEVICE); + return ALC_FALSE; + } + if((*iter)->Type == Capture) + { + alcSetError(iter->get(), ALC_INVALID_DEVICE); + return ALC_FALSE; + } + + /* Erase the device, and any remaining contexts left on it, from their + * respective lists. + */ + DeviceRef dev{std::move(*iter)}; + DeviceList.erase(iter); + + std::unique_lock statelock{dev->StateLock}; + al::vector orphanctxs; + for(ALCcontext *ctx : *dev->mContexts.load()) + { + auto iter = std::lower_bound(ContextList.begin(), ContextList.end(), ctx); + if(iter != ContextList.end() && *iter == ctx) + { + orphanctxs.emplace_back(std::move(*iter)); + ContextList.erase(iter); + } + } + listlock.unlock(); + + for(ContextRef &context : orphanctxs) + { + WARN("Releasing context %p\n", context.get()); + ReleaseContext(context.get(), dev.get()); + } + orphanctxs.clear(); + + if(dev->Flags.get()) + dev->Backend->stop(); + dev->Flags.unset(); + + return ALC_TRUE; +} +END_API_FUNC + + +/************************************************ + * ALC capture functions + ************************************************/ +ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei samples) +START_API_FUNC +{ + DO_INITCONFIG(); + + if(!CaptureFactory) + { + alcSetError(nullptr, ALC_INVALID_VALUE); + return nullptr; + } + + if(samples <= 0) + { + alcSetError(nullptr, ALC_INVALID_VALUE); + return nullptr; + } + + if(deviceName && (!deviceName[0] || strcasecmp(deviceName, alcDefaultName) == 0 || strcasecmp(deviceName, "openal-soft") == 0)) + deviceName = nullptr; + + DeviceRef device{new ALCdevice{Capture}}; + + auto decompfmt = DecomposeDevFormat(format); + if(!decompfmt) + { + alcSetError(nullptr, ALC_INVALID_ENUM); + return nullptr; + } + + device->Frequency = frequency; + device->FmtChans = decompfmt->chans; + device->FmtType = decompfmt->type; + device->Flags.set(); + + device->UpdateSize = samples; + device->BufferSize = samples; + + try { + device->Backend = CaptureFactory->createBackend(device.get(), BackendType::Capture); + + TRACE("Capture format: %s, %s, %uhz, %u / %u buffer\n", + DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), + device->Frequency, device->UpdateSize, device->BufferSize); + ALCenum err{device->Backend->open(deviceName)}; + if(err != ALC_NO_ERROR) + { + alcSetError(nullptr, err); + return nullptr; + } + } + catch(al::backend_exception &e) { + WARN("Failed to open capture device: %s\n", e.what()); + alcSetError(nullptr, e.errorCode()); + return nullptr; + } + + { + std::lock_guard _{ListLock}; + auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get()); + ALCdevice_IncRef(device.get()); + DeviceList.insert(iter, DeviceRef{device.get()}); + } + + TRACE("Created device %p, \"%s\"\n", device.get(), device->DeviceName.c_str()); + return device.get(); +} +END_API_FUNC + +ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) +START_API_FUNC +{ + std::unique_lock listlock{ListLock}; + auto iter = std::lower_bound(DeviceList.begin(), DeviceList.end(), device); + if(iter == DeviceList.end() || *iter != device) + { + alcSetError(nullptr, ALC_INVALID_DEVICE); + return ALC_FALSE; + } + if((*iter)->Type != Capture) + { + alcSetError(iter->get(), ALC_INVALID_DEVICE); + return ALC_FALSE; + } + + DeviceRef dev{std::move(*iter)}; + DeviceList.erase(iter); + listlock.unlock(); + + std::lock_guard _{dev->StateLock}; + if(dev->Flags.get()) + dev->Backend->stop(); + dev->Flags.unset(); + + return ALC_TRUE; +} +END_API_FUNC + +ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) +START_API_FUNC +{ + DeviceRef dev{VerifyDevice(device)}; + if(!dev || dev->Type != Capture) + { + alcSetError(dev.get(), ALC_INVALID_DEVICE); + return; + } + + std::lock_guard _{dev->StateLock}; + if(!dev->Connected.load(std::memory_order_acquire)) + alcSetError(dev.get(), ALC_INVALID_DEVICE); + else if(!dev->Flags.get()) + { + if(dev->Backend->start()) + dev->Flags.set(); + else + { + aluHandleDisconnect(dev.get(), "Device start failure"); + alcSetError(dev.get(), ALC_INVALID_DEVICE); + } + } +} +END_API_FUNC + +ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) +START_API_FUNC +{ + DeviceRef dev{VerifyDevice(device)}; + if(!dev || dev->Type != Capture) + alcSetError(dev.get(), ALC_INVALID_DEVICE); + else + { + std::lock_guard _{dev->StateLock}; + if(dev->Flags.get()) + dev->Backend->stop(); + dev->Flags.unset(); + } +} +END_API_FUNC + +ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) +START_API_FUNC +{ + DeviceRef dev{VerifyDevice(device)}; + if(!dev || dev->Type != Capture) + { + alcSetError(dev.get(), ALC_INVALID_DEVICE); + return; + } + + ALCenum err{ALC_INVALID_VALUE}; + { std::lock_guard _{dev->StateLock}; + BackendBase *backend{dev->Backend.get()}; + if(samples >= 0 && backend->availableSamples() >= static_cast(samples)) + err = backend->captureSamples(buffer, samples); + } + if(err != ALC_NO_ERROR) + alcSetError(dev.get(), err); +} +END_API_FUNC + + +/************************************************ + * ALC loopback functions + ************************************************/ + +/* alcLoopbackOpenDeviceSOFT + * + * Open a loopback device, for manual rendering. + */ +ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName) +START_API_FUNC +{ + DO_INITCONFIG(); + + /* Make sure the device name, if specified, is us. */ + if(deviceName && strcmp(deviceName, alcDefaultName) != 0) + { + alcSetError(nullptr, ALC_INVALID_VALUE); + return nullptr; + } + + DeviceRef device{new ALCdevice{Loopback}}; + + device->SourcesMax = 256; + device->AuxiliaryEffectSlotMax = 64; + device->NumAuxSends = DEFAULT_SENDS; + + //Set output format + device->BufferSize = 0; + device->UpdateSize = 0; + + device->Frequency = DEFAULT_OUTPUT_RATE; + device->FmtChans = DevFmtChannelsDefault; + device->FmtType = DevFmtTypeDefault; + + if(auto srcsopt = ConfigValueUInt(nullptr, nullptr, "sources")) + { + if(*srcsopt > 0) device->SourcesMax = *srcsopt; + } + + if(auto slotsopt = ConfigValueUInt(nullptr, nullptr, "slots")) + { + if(*slotsopt > 0) + device->AuxiliaryEffectSlotMax = minu(*slotsopt, INT_MAX); + } + + if(auto sendsopt = ConfigValueInt(nullptr, nullptr, "sends")) + device->NumAuxSends = clampi(DEFAULT_SENDS, 0, clampi(*sendsopt, 0, MAX_SENDS)); + + device->NumStereoSources = 1; + device->NumMonoSources = device->SourcesMax - device->NumStereoSources; + + try { + device->Backend = LoopbackBackendFactory::getFactory().createBackend(device.get(), + BackendType::Playback); + + // Open the "backend" + device->Backend->open("Loopback"); + } + catch(al::backend_exception &e) { + WARN("Failed to open loopback device: %s\n", e.what()); + alcSetError(nullptr, e.errorCode()); + return nullptr; + } + + { + std::lock_guard _{ListLock}; + auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get()); + ALCdevice_IncRef(device.get()); + DeviceList.insert(iter, DeviceRef{device.get()}); + } + + TRACE("Created device %p\n", device.get()); + return device.get(); +} +END_API_FUNC + +/* alcIsRenderFormatSupportedSOFT + * + * Determines if the loopback device supports the given format for rendering. + */ +ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type) +START_API_FUNC +{ + DeviceRef dev{VerifyDevice(device)}; + if(!dev || dev->Type != Loopback) + alcSetError(dev.get(), ALC_INVALID_DEVICE); + else if(freq <= 0) + alcSetError(dev.get(), ALC_INVALID_VALUE); + else + { + if(IsValidALCType(type) && IsValidALCChannels(channels) && freq >= MIN_OUTPUT_RATE) + return ALC_TRUE; + } + + return ALC_FALSE; +} +END_API_FUNC + +/* alcRenderSamplesSOFT + * + * Renders some samples into a buffer, using the format last set by the + * attributes given to alcCreateContext. + */ +FORCE_ALIGN ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) +START_API_FUNC +{ + DeviceRef dev{VerifyDevice(device)}; + if(!dev || dev->Type != Loopback) + alcSetError(dev.get(), ALC_INVALID_DEVICE); + else if(samples < 0 || (samples > 0 && buffer == nullptr)) + alcSetError(dev.get(), ALC_INVALID_VALUE); + else + { + BackendLockGuard _{*device->Backend}; + aluMixData(dev.get(), buffer, samples); + } +} +END_API_FUNC + + +/************************************************ + * ALC DSP pause/resume functions + ************************************************/ + +/* alcDevicePauseSOFT + * + * Pause the DSP to stop audio processing. + */ +ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device) +START_API_FUNC +{ + DeviceRef dev{VerifyDevice(device)}; + if(!dev || dev->Type != Playback) + alcSetError(dev.get(), ALC_INVALID_DEVICE); + else + { + std::lock_guard _{dev->StateLock}; + if(dev->Flags.get()) + dev->Backend->stop(); + dev->Flags.unset(); + dev->Flags.set(); + } +} +END_API_FUNC + +/* alcDeviceResumeSOFT + * + * Resume the DSP to restart audio processing. + */ +ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) +START_API_FUNC +{ + DeviceRef dev{VerifyDevice(device)}; + if(!dev || dev->Type != Playback) + { + alcSetError(dev.get(), ALC_INVALID_DEVICE); + return; + } + + std::lock_guard _{dev->StateLock}; + if(!dev->Flags.get()) + return; + dev->Flags.unset(); + if(dev->mContexts.load()->empty()) + return; + + if(dev->Backend->start() == ALC_FALSE) + { + aluHandleDisconnect(dev.get(), "Device start failure"); + alcSetError(dev.get(), ALC_INVALID_DEVICE); + return; + } + dev->Flags.set(); +} +END_API_FUNC + + +/************************************************ + * ALC HRTF functions + ************************************************/ + +/* alcGetStringiSOFT + * + * Gets a string parameter at the given index. + */ +ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index) +START_API_FUNC +{ + DeviceRef dev{VerifyDevice(device)}; + if(!dev || dev->Type == Capture) + alcSetError(dev.get(), ALC_INVALID_DEVICE); + else switch(paramName) + { + case ALC_HRTF_SPECIFIER_SOFT: + if(index >= 0 && static_cast(index) < dev->HrtfList.size()) + return dev->HrtfList[index].name.c_str(); + alcSetError(dev.get(), ALC_INVALID_VALUE); + break; + + default: + alcSetError(dev.get(), ALC_INVALID_ENUM); + break; + } + + return nullptr; +} +END_API_FUNC + +/* alcResetDeviceSOFT + * + * Resets the given device output, using the specified attribute list. + */ +ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs) +START_API_FUNC +{ + std::unique_lock listlock{ListLock}; + DeviceRef dev{VerifyDevice(device)}; + if(!dev || dev->Type == Capture) + { + listlock.unlock(); + alcSetError(dev.get(), ALC_INVALID_DEVICE); + return ALC_FALSE; + } + std::lock_guard _{dev->StateLock}; + listlock.unlock(); + + /* Force the backend to stop mixing first since we're resetting. Also reset + * the connected state so lost devices can attempt recover. + */ + if(dev->Flags.get()) + dev->Backend->stop(); + dev->Flags.unset(); + device->Connected.store(true); + + ALCenum err{UpdateDeviceParams(dev.get(), attribs)}; + if(LIKELY(err == ALC_NO_ERROR)) return ALC_TRUE; + + alcSetError(dev.get(), err); + if(err == ALC_INVALID_DEVICE) + aluHandleDisconnect(dev.get(), "Device start failure"); + return ALC_FALSE; +} +END_API_FUNC diff --git a/alc/alcmain.h b/alc/alcmain.h new file mode 100644 index 00000000..a22e0e81 --- /dev/null +++ b/alc/alcmain.h @@ -0,0 +1,534 @@ +#ifndef ALC_MAIN_H +#define ALC_MAIN_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" + +#include "albyte.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "alspan.h" +#include "ambidefs.h" +#include "atomic.h" +#include "hrtf.h" +#include "inprogext.h" +#include "vector.h" + +class BFormatDec; +struct ALbuffer; +struct ALeffect; +struct ALfilter; +struct BackendBase; +struct Compressor; +struct EffectState; +struct FrontStablizer; +struct Uhj2Encoder; +struct bs2b; + + +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) +#define IS_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#else +static const union { + ALuint u; + ALubyte b[sizeof(ALuint)]; +} EndianTest = { 1 }; +#define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1) +#endif + + +#define MIN_OUTPUT_RATE 8000 +#define DEFAULT_OUTPUT_RATE 44100 +#define DEFAULT_UPDATE_SIZE 882 /* 20ms */ +#define DEFAULT_NUM_UPDATES 3 + + +enum Channel { + FrontLeft = 0, + FrontRight, + FrontCenter, + LFE, + BackLeft, + BackRight, + BackCenter, + SideLeft, + SideRight, + + UpperFrontLeft, + UpperFrontRight, + UpperBackLeft, + UpperBackRight, + LowerFrontLeft, + LowerFrontRight, + LowerBackLeft, + LowerBackRight, + + Aux0, + Aux1, + Aux2, + Aux3, + Aux4, + Aux5, + Aux6, + Aux7, + Aux8, + Aux9, + Aux10, + Aux11, + Aux12, + Aux13, + Aux14, + Aux15, + + MaxChannels +}; + + +/* Device formats */ +enum DevFmtType : ALenum { + DevFmtByte = ALC_BYTE_SOFT, + DevFmtUByte = ALC_UNSIGNED_BYTE_SOFT, + DevFmtShort = ALC_SHORT_SOFT, + DevFmtUShort = ALC_UNSIGNED_SHORT_SOFT, + DevFmtInt = ALC_INT_SOFT, + DevFmtUInt = ALC_UNSIGNED_INT_SOFT, + DevFmtFloat = ALC_FLOAT_SOFT, + + DevFmtTypeDefault = DevFmtFloat +}; +enum DevFmtChannels : ALenum { + DevFmtMono = ALC_MONO_SOFT, + DevFmtStereo = ALC_STEREO_SOFT, + DevFmtQuad = ALC_QUAD_SOFT, + DevFmtX51 = ALC_5POINT1_SOFT, + DevFmtX61 = ALC_6POINT1_SOFT, + DevFmtX71 = ALC_7POINT1_SOFT, + DevFmtAmbi3D = ALC_BFORMAT3D_SOFT, + + /* Similar to 5.1, except using rear channels instead of sides */ + DevFmtX51Rear = 0x70000000, + + DevFmtChannelsDefault = DevFmtStereo +}; +#define MAX_OUTPUT_CHANNELS (16) + +/* DevFmtType traits, providing the type, etc given a DevFmtType. */ +template +struct DevFmtTypeTraits { }; + +template<> +struct DevFmtTypeTraits { using Type = ALbyte; }; +template<> +struct DevFmtTypeTraits { using Type = ALubyte; }; +template<> +struct DevFmtTypeTraits { using Type = ALshort; }; +template<> +struct DevFmtTypeTraits { using Type = ALushort; }; +template<> +struct DevFmtTypeTraits { using Type = ALint; }; +template<> +struct DevFmtTypeTraits { using Type = ALuint; }; +template<> +struct DevFmtTypeTraits { using Type = ALfloat; }; + + +ALsizei BytesFromDevFmt(DevFmtType type) noexcept; +ALsizei ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept; +inline ALsizei FrameSizeFromDevFmt(DevFmtChannels chans, DevFmtType type, ALsizei ambiorder) noexcept +{ return ChannelsFromDevFmt(chans, ambiorder) * BytesFromDevFmt(type); } + +enum class AmbiLayout { + FuMa = ALC_FUMA_SOFT, /* FuMa channel order */ + ACN = ALC_ACN_SOFT, /* ACN channel order */ + + Default = ACN +}; + +enum class AmbiNorm { + FuMa = ALC_FUMA_SOFT, /* FuMa normalization */ + SN3D = ALC_SN3D_SOFT, /* SN3D normalization */ + N3D = ALC_N3D_SOFT, /* N3D normalization */ + + Default = SN3D +}; + + +enum DeviceType { + Playback, + Capture, + Loopback +}; + + +enum RenderMode { + NormalRender, + StereoPair, + HrtfRender +}; + + +struct BufferSubList { + uint64_t FreeMask{~0_u64}; + ALbuffer *Buffers{nullptr}; /* 64 */ + + BufferSubList() noexcept = default; + BufferSubList(const BufferSubList&) = delete; + BufferSubList(BufferSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Buffers{rhs.Buffers} + { rhs.FreeMask = ~0_u64; rhs.Buffers = nullptr; } + ~BufferSubList(); + + BufferSubList& operator=(const BufferSubList&) = delete; + BufferSubList& operator=(BufferSubList&& rhs) noexcept + { std::swap(FreeMask, rhs.FreeMask); std::swap(Buffers, rhs.Buffers); return *this; } +}; + +struct EffectSubList { + uint64_t FreeMask{~0_u64}; + ALeffect *Effects{nullptr}; /* 64 */ + + EffectSubList() noexcept = default; + EffectSubList(const EffectSubList&) = delete; + EffectSubList(EffectSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Effects{rhs.Effects} + { rhs.FreeMask = ~0_u64; rhs.Effects = nullptr; } + ~EffectSubList(); + + EffectSubList& operator=(const EffectSubList&) = delete; + EffectSubList& operator=(EffectSubList&& rhs) noexcept + { std::swap(FreeMask, rhs.FreeMask); std::swap(Effects, rhs.Effects); return *this; } +}; + +struct FilterSubList { + uint64_t FreeMask{~0_u64}; + ALfilter *Filters{nullptr}; /* 64 */ + + FilterSubList() noexcept = default; + FilterSubList(const FilterSubList&) = delete; + FilterSubList(FilterSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Filters{rhs.Filters} + { rhs.FreeMask = ~0_u64; rhs.Filters = nullptr; } + ~FilterSubList(); + + FilterSubList& operator=(const FilterSubList&) = delete; + FilterSubList& operator=(FilterSubList&& rhs) noexcept + { std::swap(FreeMask, rhs.FreeMask); std::swap(Filters, rhs.Filters); return *this; } +}; + + +/* Maximum delay in samples for speaker distance compensation. */ +#define MAX_DELAY_LENGTH 1024 + +class DistanceComp { +public: + struct DistData { + ALfloat Gain{1.0f}; + ALsizei Length{0}; /* Valid range is [0...MAX_DELAY_LENGTH). */ + ALfloat *Buffer{nullptr}; + }; + +private: + std::array mChannels; + al::vector mSamples; + +public: + void setSampleCount(size_t new_size) { mSamples.resize(new_size); } + void clear() noexcept + { + for(auto &chan : mChannels) + { + chan.Gain = 1.0f; + chan.Length = 0; + chan.Buffer = nullptr; + } + using SampleVecT = decltype(mSamples); + SampleVecT{}.swap(mSamples); + } + + ALfloat *getSamples() noexcept { return mSamples.data(); } + + al::span as_span() { return mChannels; } +}; + +struct BFChannelConfig { + ALfloat Scale; + ALsizei Index; +}; + +/* Size for temporary storage of buffer data, in ALfloats. Larger values need + * more memory, while smaller values may need more iterations. The value needs + * to be a sensible size, however, as it constrains the max stepping value used + * for mixing, as well as the maximum number of samples per mixing iteration. + */ +#define BUFFERSIZE 1024 + +using FloatBufferLine = std::array; + +/* Maximum number of samples to pad on either end of a buffer for resampling. + * Note that both the beginning and end need padding! + */ +#define MAX_RESAMPLE_PADDING 24 + + +struct MixParams { + /* Coefficient channel mapping for mixing to the buffer. */ + std::array AmbiMap{}; + + al::span Buffer; +}; + +struct RealMixParams { + std::array ChannelIndex{}; + + al::span Buffer; +}; + +using POSTPROCESS = void(*)(ALCdevice *device, const ALsizei SamplesToDo); + +enum { + // Frequency was requested by the app or config file + FrequencyRequest, + // Channel configuration was requested by the config file + ChannelsRequest, + // Sample type was requested by the config file + SampleTypeRequest, + + // Specifies if the DSP is paused at user request + DevicePaused, + // Specifies if the device is currently running + DeviceRunning, + + DeviceFlagsCount +}; + +struct ALCdevice { + RefCount ref{1u}; + + std::atomic Connected{true}; + const DeviceType Type{}; + + ALuint Frequency{}; + ALuint UpdateSize{}; + ALuint BufferSize{}; + + DevFmtChannels FmtChans{}; + DevFmtType FmtType{}; + ALboolean IsHeadphones{AL_FALSE}; + ALsizei mAmbiOrder{0}; + /* For DevFmtAmbi* output only, specifies the channel order and + * normalization. + */ + AmbiLayout mAmbiLayout{AmbiLayout::Default}; + AmbiNorm mAmbiScale{AmbiNorm::Default}; + + ALCenum LimiterState{ALC_DONT_CARE_SOFT}; + + std::string DeviceName; + + // Device flags + al::bitfield Flags{}; + + std::string HrtfName; + al::vector HrtfList; + ALCenum HrtfStatus{ALC_FALSE}; + + std::atomic LastError{ALC_NO_ERROR}; + + // Maximum number of sources that can be created + ALuint SourcesMax{}; + // Maximum number of slots that can be created + ALuint AuxiliaryEffectSlotMax{}; + + ALCuint NumMonoSources{}; + ALCuint NumStereoSources{}; + ALsizei NumAuxSends{}; + + // Map of Buffers for this device + std::mutex BufferLock; + al::vector BufferList; + + // Map of Effects for this device + std::mutex EffectLock; + al::vector EffectList; + + // Map of Filters for this device + std::mutex FilterLock; + al::vector FilterList; + + /* Rendering mode. */ + RenderMode mRenderMode{NormalRender}; + + /* The average speaker distance as determined by the ambdec configuration, + * HRTF data set, or the NFC-HOA reference delay. Only used for NFC. + */ + ALfloat AvgSpeakerDist{0.0f}; + + ALuint SamplesDone{0u}; + std::chrono::nanoseconds ClockBase{0}; + std::chrono::nanoseconds FixedLatency{0}; + + /* Temp storage used for mixer processing. */ + alignas(16) ALfloat SourceData[BUFFERSIZE + MAX_RESAMPLE_PADDING*2]; + alignas(16) ALfloat ResampledData[BUFFERSIZE]; + alignas(16) ALfloat FilteredData[BUFFERSIZE]; + union { + alignas(16) ALfloat HrtfSourceData[BUFFERSIZE + HRTF_HISTORY_LENGTH]; + alignas(16) ALfloat NfcSampleData[BUFFERSIZE]; + }; + alignas(16) float2 HrtfAccumData[BUFFERSIZE + HRIR_LENGTH]; + + /* Mixing buffer used by the Dry mix and Real output. */ + al::vector MixBuffer; + + /* The "dry" path corresponds to the main output. */ + MixParams Dry; + ALuint NumChannelsPerOrder[MAX_AMBI_ORDER+1]{}; + + /* "Real" output, which will be written to the device buffer. May alias the + * dry buffer. + */ + RealMixParams RealOut; + + /* HRTF state and info */ + std::unique_ptr mHrtfState; + HrtfEntry *mHrtf{nullptr}; + + /* Ambisonic-to-UHJ encoder */ + std::unique_ptr Uhj_Encoder; + + /* Ambisonic decoder for speakers */ + std::unique_ptr AmbiDecoder; + + /* Stereo-to-binaural filter */ + std::unique_ptr Bs2b; + + POSTPROCESS PostProcess{}; + + std::unique_ptr Stablizer; + + std::unique_ptr Limiter; + + /* Delay buffers used to compensate for speaker distances. */ + DistanceComp ChannelDelay; + + /* Dithering control. */ + ALfloat DitherDepth{0.0f}; + ALuint DitherSeed{0u}; + + /* Running count of the mixer invocations, in 31.1 fixed point. This + * actually increments *twice* when mixing, first at the start and then at + * the end, so the bottom bit indicates if the device is currently mixing + * and the upper bits indicates how many mixes have been done. + */ + RefCount MixCount{0u}; + + // Contexts created on this device + std::atomic*> mContexts{nullptr}; + + /* This lock protects the device state (format, update size, etc) from + * being from being changed in multiple threads, or being accessed while + * being changed. It's also used to serialize calls to the backend. + */ + std::mutex StateLock; + std::unique_ptr Backend; + + + ALCdevice(DeviceType type); + ALCdevice(const ALCdevice&) = delete; + ALCdevice& operator=(const ALCdevice&) = delete; + ~ALCdevice(); + + ALsizei bytesFromFmt() const noexcept { return BytesFromDevFmt(FmtType); } + ALsizei channelsFromFmt() const noexcept { return ChannelsFromDevFmt(FmtChans, mAmbiOrder); } + ALsizei frameSizeFromFmt() const noexcept { return bytesFromFmt() * channelsFromFmt(); } + + DEF_NEWDEL(ALCdevice) +}; + +/* Must be less than 15 characters (16 including terminating null) for + * compatibility with pthread_setname_np limitations. */ +#define MIXER_THREAD_NAME "alsoft-mixer" + +#define RECORD_THREAD_NAME "alsoft-record" + + +enum { + /* End event thread processing. */ + EventType_KillThread = 0, + + /* User event types. */ + EventType_SourceStateChange = 1<<0, + EventType_BufferCompleted = 1<<1, + EventType_Error = 1<<2, + EventType_Performance = 1<<3, + EventType_Deprecated = 1<<4, + EventType_Disconnected = 1<<5, + + /* Internal events. */ + EventType_ReleaseEffectState = 65536, +}; + +struct AsyncEvent { + unsigned int EnumType{0u}; + union { + char dummy; + struct { + ALuint id; + ALenum state; + } srcstate; + struct { + ALuint id; + ALsizei count; + } bufcomp; + struct { + ALenum type; + ALuint id; + ALuint param; + ALchar msg[1008]; + } user; + EffectState *mEffectState; + } u{}; + + AsyncEvent() noexcept = default; + constexpr AsyncEvent(unsigned int type) noexcept : EnumType{type} { } +}; + + +void AllocateVoices(ALCcontext *context, size_t num_voices); + + +extern ALint RTPrioLevel; +void SetRTPriority(void); + +void SetDefaultChannelOrder(ALCdevice *device); +void SetDefaultWFXChannelOrder(ALCdevice *device); + +const ALCchar *DevFmtTypeString(DevFmtType type) noexcept; +const ALCchar *DevFmtChannelsString(DevFmtChannels chans) noexcept; + +/** + * GetChannelIdxByName + * + * Returns the index for the given channel name (e.g. FrontCenter), or -1 if it + * doesn't exist. + */ +inline ALint GetChannelIdxByName(const RealMixParams &real, Channel chan) noexcept +{ return real.ChannelIndex[chan]; } + + +void StartEventThrd(ALCcontext *ctx); +void StopEventThrd(ALCcontext *ctx); + + +al::vector SearchDataFiles(const char *match, const char *subdir); + +#endif diff --git a/alc/alconfig.cpp b/alc/alconfig.cpp new file mode 100644 index 00000000..b246a91d --- /dev/null +++ b/alc/alconfig.cpp @@ -0,0 +1,545 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * 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 "alconfig.h" + +#include +#include +#include +#ifdef _WIN32_IE +#include +#include +#endif +#ifdef __APPLE__ +#include +#endif + +#include +#include +#include + +#include "alcmain.h" +#include "logging.h" +#include "compat.h" + + +namespace { + +struct ConfigEntry { + std::string key; + std::string value; +}; +al::vector ConfOpts; + + +std::string &lstrip(std::string &line) +{ + size_t pos{0}; + while(pos < line.length() && std::isspace(line[pos])) + ++pos; + line.erase(0, pos); + return line; +} + +bool readline(std::istream &f, std::string &output) +{ + while(f.good() && f.peek() == '\n') + f.ignore(); + + return std::getline(f, output) && !output.empty(); +} + +std:: string expdup(const char *str) +{ + std::string output; + + while(*str != '\0') + { + const char *addstr; + size_t addstrlen; + + if(str[0] != '$') + { + const char *next = std::strchr(str, '$'); + addstr = str; + addstrlen = next ? static_cast(next-str) : std::strlen(str); + + str += addstrlen; + } + else + { + str++; + if(*str == '$') + { + const char *next = std::strchr(str+1, '$'); + addstr = str; + addstrlen = next ? static_cast(next-str) : std::strlen(str); + + str += addstrlen; + } + else + { + bool hasbraces{(*str == '{')}; + if(hasbraces) str++; + + std::string envname; + while((std::isalnum(*str) || *str == '_')) + envname += *(str++); + + if(hasbraces && *str != '}') + continue; + + if(hasbraces) str++; + if((addstr=std::getenv(envname.c_str())) == nullptr) + continue; + addstrlen = std::strlen(addstr); + } + } + if(addstrlen == 0) + continue; + + output.append(addstr, addstrlen); + } + + return output; +} + +void LoadConfigFromFile(std::istream &f) +{ + std::string curSection; + std::string buffer; + + while(readline(f, buffer)) + { + while(!buffer.empty() && std::isspace(buffer.back())) + buffer.pop_back(); + if(lstrip(buffer).empty()) + continue; + + buffer.push_back(0); + char *line{&buffer[0]}; + + if(line[0] == '[') + { + char *section = line+1; + char *endsection; + + endsection = std::strchr(section, ']'); + if(!endsection || section == endsection) + { + ERR("config parse error: bad line \"%s\"\n", line); + continue; + } + if(endsection[1] != 0) + { + char *end = endsection+1; + while(std::isspace(*end)) + ++end; + if(*end != 0 && *end != '#') + { + ERR("config parse error: bad line \"%s\"\n", line); + continue; + } + } + *endsection = 0; + + curSection.clear(); + if(strcasecmp(section, "general") != 0) + { + do { + char *nextp = std::strchr(section, '%'); + if(!nextp) + { + curSection += section; + break; + } + + curSection.append(section, nextp); + section = nextp; + + if(((section[1] >= '0' && section[1] <= '9') || + (section[1] >= 'a' && section[1] <= 'f') || + (section[1] >= 'A' && section[1] <= 'F')) && + ((section[2] >= '0' && section[2] <= '9') || + (section[2] >= 'a' && section[2] <= 'f') || + (section[2] >= 'A' && section[2] <= 'F'))) + { + unsigned char b = 0; + if(section[1] >= '0' && section[1] <= '9') + b = (section[1]-'0') << 4; + else if(section[1] >= 'a' && section[1] <= 'f') + b = (section[1]-'a'+0xa) << 4; + else if(section[1] >= 'A' && section[1] <= 'F') + b = (section[1]-'A'+0x0a) << 4; + if(section[2] >= '0' && section[2] <= '9') + b |= (section[2]-'0'); + else if(section[2] >= 'a' && section[2] <= 'f') + b |= (section[2]-'a'+0xa); + else if(section[2] >= 'A' && section[2] <= 'F') + b |= (section[2]-'A'+0x0a); + curSection += static_cast(b); + section += 3; + } + else if(section[1] == '%') + { + curSection += '%'; + section += 2; + } + else + { + curSection += '%'; + section += 1; + } + } while(*section != 0); + } + + continue; + } + + char *comment{std::strchr(line, '#')}; + if(comment) *(comment++) = 0; + if(!line[0]) continue; + + char key[256]{}; + char value[256]{}; + if(std::sscanf(line, "%255[^=] = \"%255[^\"]\"", key, value) == 2 || + std::sscanf(line, "%255[^=] = '%255[^\']'", key, value) == 2 || + std::sscanf(line, "%255[^=] = %255[^\n]", key, value) == 2) + { + /* sscanf doesn't handle '' or "" as empty values, so clip it + * manually. */ + if(std::strcmp(value, "\"\"") == 0 || std::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; + } + + std::string fullKey; + if(!curSection.empty()) + { + fullKey += curSection; + fullKey += '/'; + } + fullKey += key; + while(!fullKey.empty() && std::isspace(fullKey.back())) + fullKey.pop_back(); + + /* Check if we already have this option set */ + auto ent = std::find_if(ConfOpts.begin(), ConfOpts.end(), + [&fullKey](const ConfigEntry &entry) -> bool + { return entry.key == fullKey; } + ); + if(ent != ConfOpts.end()) + ent->value = expdup(value); + else + { + ConfOpts.emplace_back(ConfigEntry{std::move(fullKey), expdup(value)}); + ent = ConfOpts.end()-1; + } + + TRACE("found '%s' = '%s'\n", ent->key.c_str(), ent->value.c_str()); + } + ConfOpts.shrink_to_fit(); +} + +} // namespace + + +#ifdef _WIN32 +void ReadALConfig() +{ + WCHAR buffer[MAX_PATH]; + if(SHGetSpecialFolderPathW(nullptr, buffer, CSIDL_APPDATA, FALSE) != FALSE) + { + std::string filepath{wstr_to_utf8(buffer)}; + filepath += "\\alsoft.ini"; + + TRACE("Loading config %s...\n", filepath.c_str()); + al::ifstream f{filepath}; + if(f.is_open()) + LoadConfigFromFile(f); + } + + std::string ppath{GetProcBinary().path}; + if(!ppath.empty()) + { + ppath += "\\alsoft.ini"; + TRACE("Loading config %s...\n", ppath.c_str()); + al::ifstream f{ppath}; + if(f.is_open()) + LoadConfigFromFile(f); + } + + const WCHAR *str{_wgetenv(L"ALSOFT_CONF")}; + if(str != nullptr && *str) + { + std::string filepath{wstr_to_utf8(str)}; + + TRACE("Loading config %s...\n", filepath.c_str()); + al::ifstream f{filepath}; + if(f.is_open()) + LoadConfigFromFile(f); + } +} +#else +void ReadALConfig() +{ + const char *str{"/etc/openal/alsoft.conf"}; + + TRACE("Loading config %s...\n", str); + al::ifstream f{str}; + if(f.is_open()) + LoadConfigFromFile(f); + f.close(); + + if(!(str=getenv("XDG_CONFIG_DIRS")) || str[0] == 0) + str = "/etc/xdg"; + std::string confpaths = str; + /* Go through the list in reverse, since "the order of base directories + * denotes their importance; the first directory listed is the most + * important". Ergo, we need to load the settings from the later dirs + * first so that the settings in the earlier dirs override them. + */ + std::string fname; + while(!confpaths.empty()) + { + auto next = confpaths.find_last_of(':'); + if(next < confpaths.length()) + { + fname = confpaths.substr(next+1); + confpaths.erase(next); + } + else + { + fname = confpaths; + confpaths.clear(); + } + + if(fname.empty() || fname.front() != '/') + WARN("Ignoring XDG config dir: %s\n", fname.c_str()); + else + { + if(fname.back() != '/') fname += "/alsoft.conf"; + else fname += "alsoft.conf"; + + TRACE("Loading config %s...\n", fname.c_str()); + al::ifstream f{fname}; + if(f.is_open()) + LoadConfigFromFile(f); + } + fname.clear(); + } + +#ifdef __APPLE__ + CFBundleRef mainBundle = CFBundleGetMainBundle(); + if(mainBundle) + { + unsigned char fileName[PATH_MAX]; + CFURLRef configURL; + + if((configURL=CFBundleCopyResourceURL(mainBundle, CFSTR(".alsoftrc"), CFSTR(""), nullptr)) && + CFURLGetFileSystemRepresentation(configURL, true, fileName, sizeof(fileName))) + { + al::ifstream f{reinterpret_cast(fileName)}; + if(f.is_open()) + LoadConfigFromFile(f); + } + } +#endif + + if((str=getenv("HOME")) != nullptr && *str) + { + fname = str; + if(fname.back() != '/') fname += "/.alsoftrc"; + else fname += ".alsoftrc"; + + TRACE("Loading config %s...\n", fname.c_str()); + al::ifstream f{fname}; + if(f.is_open()) + LoadConfigFromFile(f); + } + + if((str=getenv("XDG_CONFIG_HOME")) != nullptr && str[0] != 0) + { + fname = str; + if(fname.back() != '/') fname += "/alsoft.conf"; + else fname += "alsoft.conf"; + } + else + { + fname.clear(); + if((str=getenv("HOME")) != nullptr && str[0] != 0) + { + fname = str; + if(fname.back() != '/') fname += "/.config/alsoft.conf"; + else fname += ".config/alsoft.conf"; + } + } + if(!fname.empty()) + { + TRACE("Loading config %s...\n", fname.c_str()); + al::ifstream f{fname}; + if(f.is_open()) + LoadConfigFromFile(f); + } + + std::string ppath{GetProcBinary().path}; + if(!ppath.empty()) + { + if(ppath.back() != '/') ppath += "/alsoft.conf"; + else ppath += "alsoft.conf"; + + TRACE("Loading config %s...\n", ppath.c_str()); + al::ifstream f{ppath}; + if(f.is_open()) + LoadConfigFromFile(f); + } + + if((str=getenv("ALSOFT_CONF")) != nullptr && *str) + { + TRACE("Loading config %s...\n", str); + al::ifstream f{str}; + if(f.is_open()) + LoadConfigFromFile(f); + } +} +#endif + +const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def) +{ + if(!keyName) + return def; + + std::string key; + if(blockName && strcasecmp(blockName, "general") != 0) + { + key = blockName; + if(devName) + { + key += '/'; + key += devName; + } + key += '/'; + key += keyName; + } + else + { + if(devName) + { + key = devName; + key += '/'; + } + key += keyName; + } + + auto iter = std::find_if(ConfOpts.cbegin(), ConfOpts.cend(), + [&key](const ConfigEntry &entry) -> bool + { return entry.key == key; } + ); + if(iter != ConfOpts.cend()) + { + TRACE("Found %s = \"%s\"\n", key.c_str(), iter->value.c_str()); + if(!iter->value.empty()) + return iter->value.c_str(); + return def; + } + + if(!devName) + { + TRACE("Key %s not found\n", key.c_str()); + return def; + } + return GetConfigValue(nullptr, blockName, keyName, def); +} + +int ConfigValueExists(const char *devName, const char *blockName, const char *keyName) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + return val[0] != 0; +} + +al::optional ConfigValueStr(const char *devName, const char *blockName, const char *keyName) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + if(!val[0]) return al::nullopt; + + return al::make_optional(val); +} + +al::optional ConfigValueInt(const char *devName, const char *blockName, const char *keyName) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + if(!val[0]) return al::nullopt; + + return al::make_optional(static_cast(std::strtol(val, nullptr, 0))); +} + +al::optional ConfigValueUInt(const char *devName, const char *blockName, const char *keyName) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + if(!val[0]) return al::nullopt; + + return al::make_optional(static_cast(std::strtoul(val, nullptr, 0))); +} + +al::optional ConfigValueFloat(const char *devName, const char *blockName, const char *keyName) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + if(!val[0]) return al::nullopt; + + return al::make_optional(std::strtof(val, nullptr)); +} + +al::optional ConfigValueBool(const char *devName, const char *blockName, const char *keyName) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + if(!val[0]) return al::nullopt; + + return al::make_optional( + strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || + strcasecmp(val, "on") == 0 || atoi(val) != 0); +} + +int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + + if(!val[0]) return def != 0; + return (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || + strcasecmp(val, "on") == 0 || atoi(val) != 0); +} diff --git a/alc/alconfig.h b/alc/alconfig.h new file mode 100644 index 00000000..ffc7adad --- /dev/null +++ b/alc/alconfig.h @@ -0,0 +1,20 @@ +#ifndef ALCONFIG_H +#define ALCONFIG_H + +#include + +#include "aloptional.h" + +void ReadALConfig(); + +int ConfigValueExists(const char *devName, const char *blockName, const char *keyName); +const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def); +int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def); + +al::optional ConfigValueStr(const char *devName, const char *blockName, const char *keyName); +al::optional ConfigValueInt(const char *devName, const char *blockName, const char *keyName); +al::optional ConfigValueUInt(const char *devName, const char *blockName, const char *keyName); +al::optional ConfigValueFloat(const char *devName, const char *blockName, const char *keyName); +al::optional ConfigValueBool(const char *devName, const char *blockName, const char *keyName); + +#endif /* ALCONFIG_H */ diff --git a/alc/alcontext.h b/alc/alcontext.h new file mode 100644 index 00000000..cf956079 --- /dev/null +++ b/alc/alcontext.h @@ -0,0 +1,217 @@ +#ifndef ALCONTEXT_H +#define ALCONTEXT_H + +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" +#include "inprogext.h" + +#include "atomic.h" +#include "vector.h" +#include "threads.h" +#include "almalloc.h" +#include "alnumeric.h" + +#include "alListener.h" +#include "alu.h" + + +struct ALsource; +struct ALeffectslot; +struct ALcontextProps; +struct ALlistenerProps; +struct ALvoiceProps; +struct ALeffectslotProps; +struct RingBuffer; + +enum class DistanceModel { + InverseClamped = AL_INVERSE_DISTANCE_CLAMPED, + LinearClamped = AL_LINEAR_DISTANCE_CLAMPED, + ExponentClamped = AL_EXPONENT_DISTANCE_CLAMPED, + Inverse = AL_INVERSE_DISTANCE, + Linear = AL_LINEAR_DISTANCE, + Exponent = AL_EXPONENT_DISTANCE, + Disable = AL_NONE, + + Default = InverseClamped +}; + +struct SourceSubList { + uint64_t FreeMask{~0_u64}; + ALsource *Sources{nullptr}; /* 64 */ + + SourceSubList() noexcept = default; + SourceSubList(const SourceSubList&) = delete; + SourceSubList(SourceSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Sources{rhs.Sources} + { rhs.FreeMask = ~0_u64; rhs.Sources = nullptr; } + ~SourceSubList(); + + SourceSubList& operator=(const SourceSubList&) = delete; + SourceSubList& operator=(SourceSubList&& rhs) noexcept + { std::swap(FreeMask, rhs.FreeMask); std::swap(Sources, rhs.Sources); return *this; } +}; + +struct EffectSlotSubList { + uint64_t FreeMask{~0_u64}; + ALeffectslot *EffectSlots{nullptr}; /* 64 */ + + EffectSlotSubList() noexcept = default; + EffectSlotSubList(const EffectSlotSubList&) = delete; + EffectSlotSubList(EffectSlotSubList&& rhs) noexcept + : FreeMask{rhs.FreeMask}, EffectSlots{rhs.EffectSlots} + { rhs.FreeMask = ~0_u64; rhs.EffectSlots = nullptr; } + ~EffectSlotSubList(); + + EffectSlotSubList& operator=(const EffectSlotSubList&) = delete; + EffectSlotSubList& operator=(EffectSlotSubList&& rhs) noexcept + { std::swap(FreeMask, rhs.FreeMask); std::swap(EffectSlots, rhs.EffectSlots); return *this; } +}; + +struct ALCcontext { + RefCount ref{1u}; + + al::vector SourceList; + ALuint NumSources{0}; + std::mutex SourceLock; + + al::vector EffectSlotList; + ALuint NumEffectSlots{0u}; + std::mutex EffectSlotLock; + + std::atomic LastError{AL_NO_ERROR}; + + DistanceModel mDistanceModel{DistanceModel::Default}; + ALboolean SourceDistanceModel{AL_FALSE}; + + ALfloat DopplerFactor{1.0f}; + ALfloat DopplerVelocity{1.0f}; + ALfloat SpeedOfSound{}; + ALfloat MetersPerUnit{1.0f}; + + std::atomic_flag PropsClean; + std::atomic DeferUpdates{false}; + + std::mutex PropLock; + + /* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit + * indicates if updates are currently happening). + */ + RefCount UpdateCount{0u}; + std::atomic HoldUpdates{false}; + + ALfloat GainBoost{1.0f}; + + std::atomic Update{nullptr}; + + /* Linked lists of unused property containers, free to use for future + * updates. + */ + std::atomic FreeContextProps{nullptr}; + std::atomic FreeListenerProps{nullptr}; + std::atomic FreeVoiceProps{nullptr}; + std::atomic FreeEffectslotProps{nullptr}; + + std::unique_ptr> Voices{nullptr}; + std::atomic VoiceCount{0u}; + + using ALeffectslotArray = al::FlexArray; + std::atomic ActiveAuxSlots{nullptr}; + + std::thread EventThread; + al::semaphore EventSem; + std::unique_ptr AsyncEvents; + std::atomic EnabledEvts{0u}; + std::mutex EventCbLock; + ALEVENTPROCSOFT EventCb{}; + void *EventParam{nullptr}; + + /* Default effect slot */ + std::unique_ptr DefaultSlot; + + ALCdevice *const Device; + const ALCchar *ExtensionList{nullptr}; + + ALlistener Listener{}; + + + ALCcontext(ALCdevice *device); + ALCcontext(const ALCcontext&) = delete; + ALCcontext& operator=(const ALCcontext&) = delete; + ~ALCcontext(); + + DEF_NEWDEL(ALCcontext) +}; + +void ALCcontext_DecRef(ALCcontext *context); + +void UpdateContextProps(ALCcontext *context); + +void ALCcontext_DeferUpdates(ALCcontext *context); +void ALCcontext_ProcessUpdates(ALCcontext *context); + + +/* Simple RAII context reference. Takes the reference of the provided + * ALCcontext, and decrements it when leaving scope. Movable (transfer + * reference) but not copyable (no new references). + */ +class ContextRef { + ALCcontext *mCtx{nullptr}; + + void reset() noexcept + { + if(mCtx) + ALCcontext_DecRef(mCtx); + mCtx = nullptr; + } + +public: + ContextRef() noexcept = default; + ContextRef(ContextRef&& rhs) noexcept : mCtx{rhs.mCtx} + { rhs.mCtx = nullptr; } + explicit ContextRef(ALCcontext *ctx) noexcept : mCtx(ctx) { } + ~ContextRef() { reset(); } + + ContextRef& operator=(const ContextRef&) = delete; + ContextRef& operator=(ContextRef&& rhs) noexcept + { std::swap(mCtx, rhs.mCtx); return *this; } + + operator bool() const noexcept { return mCtx != nullptr; } + + ALCcontext* operator->() const noexcept { return mCtx; } + ALCcontext* get() const noexcept { return mCtx; } + + ALCcontext* release() noexcept + { + ALCcontext *ret{mCtx}; + mCtx = nullptr; + return ret; + } +}; + +inline bool operator==(const ContextRef &lhs, const ALCcontext *rhs) noexcept +{ return lhs.get() == rhs; } +inline bool operator!=(const ContextRef &lhs, const ALCcontext *rhs) noexcept +{ return !(lhs == rhs); } +inline bool operator<(const ContextRef &lhs, const ALCcontext *rhs) noexcept +{ return lhs.get() < rhs; } + +ContextRef GetContextRef(void); + + +struct ALcontextProps { + ALfloat DopplerFactor; + ALfloat DopplerVelocity; + ALfloat SpeedOfSound; + ALboolean SourceDistanceModel; + DistanceModel mDistanceModel; + ALfloat MetersPerUnit; + + std::atomic next; +}; + +#endif /* ALCONTEXT_H */ diff --git a/alc/alu.cpp b/alc/alu.cpp new file mode 100644 index 00000000..cc1a5a98 --- /dev/null +++ b/alc/alu.cpp @@ -0,0 +1,1798 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "alu.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/efx.h" + +#include "alAuxEffectSlot.h" +#include "alBuffer.h" +#include "alcmain.h" +#include "alEffect.h" +#include "alListener.h" +#include "alcontext.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "alspan.h" +#include "ambidefs.h" +#include "atomic.h" +#include "bformatdec.h" +#include "bs2b.h" +#include "cpu_caps.h" +#include "effects/base.h" +#include "filters/biquad.h" +#include "filters/nfc.h" +#include "filters/splitter.h" +#include "fpu_modes.h" +#include "hrtf.h" +#include "inprogext.h" +#include "mastering.h" +#include "math_defs.h" +#include "mixer/defs.h" +#include "opthelpers.h" +#include "ringbuffer.h" +#include "threads.h" +#include "uhjfilter.h" +#include "vecmat.h" +#include "vector.h" + +#include "bsinc_inc.h" + + +namespace { + +using namespace std::placeholders; + +ALfloat InitConeScale() +{ + ALfloat ret{1.0f}; + const char *str{getenv("__ALSOFT_HALF_ANGLE_CONES")}; + if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) + ret *= 0.5f; + return ret; +} + +ALfloat InitZScale() +{ + ALfloat ret{1.0f}; + const char *str{getenv("__ALSOFT_REVERSE_Z")}; + if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) + ret *= -1.0f; + return ret; +} + +ALboolean InitReverbSOS() +{ + ALboolean ret{AL_FALSE}; + const char *str{getenv("__ALSOFT_REVERB_IGNORES_SOUND_SPEED")}; + if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) + ret = AL_TRUE; + return ret; +} + +} // namespace + +/* Cone scalar */ +const ALfloat ConeScale{InitConeScale()}; + +/* Localized Z scalar for mono sources */ +const ALfloat ZScale{InitZScale()}; + +/* Force default speed of sound for distance-related reverb decay. */ +const ALboolean OverrideReverbSpeedOfSound{InitReverbSOS()}; + + +namespace { + +void ClearArray(ALfloat (&f)[MAX_OUTPUT_CHANNELS]) +{ + std::fill(std::begin(f), std::end(f), 0.0f); +} + +struct ChanMap { + Channel channel; + ALfloat angle; + ALfloat elevation; +}; + +HrtfDirectMixerFunc MixDirectHrtf = MixDirectHrtf_; +inline HrtfDirectMixerFunc SelectHrtfMixer(void) +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return MixDirectHrtf_; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixDirectHrtf_; +#endif + + return MixDirectHrtf_; +} + +} // namespace + +void aluInit(void) +{ + MixDirectHrtf = SelectHrtfMixer(); +} + + +void ProcessHrtf(ALCdevice *device, const ALsizei SamplesToDo) +{ + /* HRTF is stereo output only. */ + const int lidx{device->RealOut.ChannelIndex[FrontLeft]}; + const int ridx{device->RealOut.ChannelIndex[FrontRight]}; + ASSUME(lidx >= 0 && ridx >= 0); + + DirectHrtfState *state{device->mHrtfState.get()}; + MixDirectHrtf(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], device->Dry.Buffer, + device->HrtfAccumData, state, SamplesToDo); +} + +void ProcessAmbiDec(ALCdevice *device, const ALsizei SamplesToDo) +{ + BFormatDec *ambidec{device->AmbiDecoder.get()}; + ambidec->process(device->RealOut.Buffer, device->Dry.Buffer.data(), SamplesToDo); +} + +void ProcessUhj(ALCdevice *device, const ALsizei SamplesToDo) +{ + /* UHJ is stereo output only. */ + const int lidx{device->RealOut.ChannelIndex[FrontLeft]}; + const int ridx{device->RealOut.ChannelIndex[FrontRight]}; + ASSUME(lidx >= 0 && ridx >= 0); + + /* Encode to stereo-compatible 2-channel UHJ output. */ + Uhj2Encoder *uhj2enc{device->Uhj_Encoder.get()}; + uhj2enc->encode(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], + device->Dry.Buffer.data(), SamplesToDo); +} + +void ProcessBs2b(ALCdevice *device, const ALsizei SamplesToDo) +{ + /* First, decode the ambisonic mix to the "real" output. */ + BFormatDec *ambidec{device->AmbiDecoder.get()}; + ambidec->process(device->RealOut.Buffer, device->Dry.Buffer.data(), SamplesToDo); + + /* BS2B is stereo output only. */ + const int lidx{device->RealOut.ChannelIndex[FrontLeft]}; + const int ridx{device->RealOut.ChannelIndex[FrontRight]}; + ASSUME(lidx >= 0 && ridx >= 0); + + /* Now apply the BS2B binaural/crossfeed filter. */ + bs2b_cross_feed(device->Bs2b.get(), device->RealOut.Buffer[lidx].data(), + device->RealOut.Buffer[ridx].data(), SamplesToDo); +} + + +/* Prepares the interpolator for a given rate (determined by increment). + * + * With a bit of work, and a trade of memory for CPU cost, this could be + * modified for use with an interpolated increment for buttery-smooth pitch + * changes. + */ +void BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *table) +{ + ALsizei si{BSINC_SCALE_COUNT - 1}; + ALfloat sf{0.0f}; + + if(increment > FRACTIONONE) + { + sf = static_castFRACTIONONE / increment; + sf = maxf(0.0f, (BSINC_SCALE_COUNT-1) * (sf-table->scaleBase) * table->scaleRange); + si = float2int(sf); + /* The interpolation factor is fit to this diagonally-symmetric curve + * to reduce the transition ripple caused by interpolating different + * scales of the sinc function. + */ + sf = 1.0f - std::cos(std::asin(sf - si)); + } + + state->sf = sf; + state->m = table->m[si]; + state->l = (state->m/2) - 1; + state->filter = table->Tab + table->filterOffset[si]; +} + + +namespace { + +/* This RNG method was created based on the math found in opusdec. It's quick, + * and starting with a seed value of 22222, is suitable for generating + * whitenoise. + */ +inline ALuint dither_rng(ALuint *seed) noexcept +{ + *seed = (*seed * 96314165) + 907633515; + return *seed; +} + + +inline alu::Vector aluCrossproduct(const alu::Vector &in1, const alu::Vector &in2) +{ + return alu::Vector{ + in1[1]*in2[2] - in1[2]*in2[1], + in1[2]*in2[0] - in1[0]*in2[2], + in1[0]*in2[1] - in1[1]*in2[0], + 0.0f + }; +} + +inline ALfloat aluDotproduct(const alu::Vector &vec1, const alu::Vector &vec2) +{ + return vec1[0]*vec2[0] + vec1[1]*vec2[1] + vec1[2]*vec2[2]; +} + + +alu::Vector operator*(const alu::Matrix &mtx, const alu::Vector &vec) noexcept +{ + return alu::Vector{ + vec[0]*mtx[0][0] + vec[1]*mtx[1][0] + vec[2]*mtx[2][0] + vec[3]*mtx[3][0], + vec[0]*mtx[0][1] + vec[1]*mtx[1][1] + vec[2]*mtx[2][1] + vec[3]*mtx[3][1], + vec[0]*mtx[0][2] + vec[1]*mtx[1][2] + vec[2]*mtx[2][2] + vec[3]*mtx[3][2], + vec[0]*mtx[0][3] + vec[1]*mtx[1][3] + vec[2]*mtx[2][3] + vec[3]*mtx[3][3] + }; +} + + +bool CalcContextParams(ALCcontext *Context) +{ + ALcontextProps *props{Context->Update.exchange(nullptr, std::memory_order_acq_rel)}; + if(!props) return false; + + ALlistener &Listener = Context->Listener; + Listener.Params.MetersPerUnit = props->MetersPerUnit; + + Listener.Params.DopplerFactor = props->DopplerFactor; + Listener.Params.SpeedOfSound = props->SpeedOfSound * props->DopplerVelocity; + if(!OverrideReverbSpeedOfSound) + Listener.Params.ReverbSpeedOfSound = Listener.Params.SpeedOfSound * + Listener.Params.MetersPerUnit; + + Listener.Params.SourceDistanceModel = props->SourceDistanceModel; + Listener.Params.mDistanceModel = props->mDistanceModel; + + AtomicReplaceHead(Context->FreeContextProps, props); + return true; +} + +bool CalcListenerParams(ALCcontext *Context) +{ + ALlistener &Listener = Context->Listener; + + ALlistenerProps *props{Listener.Update.exchange(nullptr, std::memory_order_acq_rel)}; + if(!props) return false; + + /* AT then UP */ + alu::Vector N{props->OrientAt[0], props->OrientAt[1], props->OrientAt[2], 0.0f}; + N.normalize(); + alu::Vector V{props->OrientUp[0], props->OrientUp[1], props->OrientUp[2], 0.0f}; + V.normalize(); + /* Build and normalize right-vector */ + alu::Vector U{aluCrossproduct(N, V)}; + U.normalize(); + + Listener.Params.Matrix = alu::Matrix{ + U[0], V[0], -N[0], 0.0f, + U[1], V[1], -N[1], 0.0f, + U[2], V[2], -N[2], 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + + const alu::Vector P{Listener.Params.Matrix * + alu::Vector{props->Position[0], props->Position[1], props->Position[2], 1.0f}}; + Listener.Params.Matrix.setRow(3, -P[0], -P[1], -P[2], 1.0f); + + const alu::Vector vel{props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f}; + Listener.Params.Velocity = Listener.Params.Matrix * vel; + + Listener.Params.Gain = props->Gain * Context->GainBoost; + + AtomicReplaceHead(Context->FreeListenerProps, props); + return true; +} + +bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) +{ + ALeffectslotProps *props{slot->Update.exchange(nullptr, std::memory_order_acq_rel)}; + if(!props && !force) return false; + + EffectState *state; + if(!props) + state = slot->Params.mEffectState; + else + { + slot->Params.Gain = props->Gain; + slot->Params.AuxSendAuto = props->AuxSendAuto; + slot->Params.Target = props->Target; + slot->Params.EffectType = props->Type; + slot->Params.mEffectProps = props->Props; + if(IsReverbEffect(props->Type)) + { + slot->Params.RoomRolloff = props->Props.Reverb.RoomRolloffFactor; + slot->Params.DecayTime = props->Props.Reverb.DecayTime; + slot->Params.DecayLFRatio = props->Props.Reverb.DecayLFRatio; + slot->Params.DecayHFRatio = props->Props.Reverb.DecayHFRatio; + slot->Params.DecayHFLimit = props->Props.Reverb.DecayHFLimit; + slot->Params.AirAbsorptionGainHF = props->Props.Reverb.AirAbsorptionGainHF; + } + else + { + slot->Params.RoomRolloff = 0.0f; + slot->Params.DecayTime = 0.0f; + slot->Params.DecayLFRatio = 0.0f; + slot->Params.DecayHFRatio = 0.0f; + slot->Params.DecayHFLimit = AL_FALSE; + slot->Params.AirAbsorptionGainHF = 1.0f; + } + + state = props->State; + props->State = nullptr; + EffectState *oldstate{slot->Params.mEffectState}; + slot->Params.mEffectState = state; + + /* Manually decrement the old effect state's refcount if it's greater + * than 1. We need to be a bit clever here to avoid the refcount + * reaching 0 since it can't be deleted in the mixer. + */ + ALuint oldval{oldstate->mRef.load(std::memory_order_acquire)}; + while(oldval > 1 && !oldstate->mRef.compare_exchange_weak(oldval, oldval-1, + std::memory_order_acq_rel, std::memory_order_acquire)) + { + /* oldval was updated with the current value on failure, so just + * try again. + */ + } + + if(oldval < 2) + { + /* Otherwise, if it would be deleted, send it off with a release + * event. + */ + RingBuffer *ring{context->AsyncEvents.get()}; + auto evt_vec = ring->getWriteVector(); + if(LIKELY(evt_vec.first.len > 0)) + { + AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_ReleaseEffectState}}; + evt->u.mEffectState = oldstate; + ring->writeAdvance(1); + context->EventSem.post(); + } + else + { + /* If writing the event failed, the queue was probably full. + * Store the old state in the property object where it can + * eventually be cleaned up sometime later (not ideal, but + * better than blocking or leaking). + */ + props->State = oldstate; + } + } + + AtomicReplaceHead(context->FreeEffectslotProps, props); + } + + EffectTarget output; + if(ALeffectslot *target{slot->Params.Target}) + output = EffectTarget{&target->Wet, nullptr}; + else + { + ALCdevice *device{context->Device}; + output = EffectTarget{&device->Dry, &device->RealOut}; + } + state->update(context, slot, &slot->Params.mEffectProps, output); + return true; +} + + +/* Scales the given azimuth toward the side (+/- pi/2 radians) for positions in + * front. + */ +inline float ScaleAzimuthFront(float azimuth, float scale) +{ + const ALfloat abs_azi{std::fabs(azimuth)}; + if(!(abs_azi > al::MathDefs::Pi()*0.5f)) + return minf(abs_azi*scale, al::MathDefs::Pi()*0.5f) * std::copysign(1.0f, azimuth); + return azimuth; +} + +void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypos, + const ALfloat zpos, const ALfloat Distance, const ALfloat Spread, const ALfloat DryGain, + const ALfloat DryGainHF, const ALfloat DryGainLF, const ALfloat (&WetGain)[MAX_SENDS], + const ALfloat (&WetGainLF)[MAX_SENDS], const ALfloat (&WetGainHF)[MAX_SENDS], + ALeffectslot *(&SendSlots)[MAX_SENDS], const ALvoicePropsBase *props, + const ALlistener &Listener, const ALCdevice *Device) +{ + static constexpr ChanMap MonoMap[1]{ + { FrontCenter, 0.0f, 0.0f } + }, RearMap[2]{ + { BackLeft, Deg2Rad(-150.0f), Deg2Rad(0.0f) }, + { BackRight, Deg2Rad( 150.0f), Deg2Rad(0.0f) } + }, QuadMap[4]{ + { FrontLeft, Deg2Rad( -45.0f), Deg2Rad(0.0f) }, + { FrontRight, Deg2Rad( 45.0f), Deg2Rad(0.0f) }, + { BackLeft, Deg2Rad(-135.0f), Deg2Rad(0.0f) }, + { BackRight, Deg2Rad( 135.0f), Deg2Rad(0.0f) } + }, X51Map[6]{ + { FrontLeft, Deg2Rad( -30.0f), Deg2Rad(0.0f) }, + { FrontRight, Deg2Rad( 30.0f), Deg2Rad(0.0f) }, + { FrontCenter, Deg2Rad( 0.0f), Deg2Rad(0.0f) }, + { LFE, 0.0f, 0.0f }, + { SideLeft, Deg2Rad(-110.0f), Deg2Rad(0.0f) }, + { SideRight, Deg2Rad( 110.0f), Deg2Rad(0.0f) } + }, X61Map[7]{ + { FrontLeft, Deg2Rad(-30.0f), Deg2Rad(0.0f) }, + { FrontRight, Deg2Rad( 30.0f), Deg2Rad(0.0f) }, + { FrontCenter, Deg2Rad( 0.0f), Deg2Rad(0.0f) }, + { LFE, 0.0f, 0.0f }, + { BackCenter, Deg2Rad(180.0f), Deg2Rad(0.0f) }, + { SideLeft, Deg2Rad(-90.0f), Deg2Rad(0.0f) }, + { SideRight, Deg2Rad( 90.0f), Deg2Rad(0.0f) } + }, X71Map[8]{ + { FrontLeft, Deg2Rad( -30.0f), Deg2Rad(0.0f) }, + { FrontRight, Deg2Rad( 30.0f), Deg2Rad(0.0f) }, + { FrontCenter, Deg2Rad( 0.0f), Deg2Rad(0.0f) }, + { LFE, 0.0f, 0.0f }, + { BackLeft, Deg2Rad(-150.0f), Deg2Rad(0.0f) }, + { BackRight, Deg2Rad( 150.0f), Deg2Rad(0.0f) }, + { SideLeft, Deg2Rad( -90.0f), Deg2Rad(0.0f) }, + { SideRight, Deg2Rad( 90.0f), Deg2Rad(0.0f) } + }; + + ChanMap StereoMap[2]{ + { FrontLeft, Deg2Rad(-30.0f), Deg2Rad(0.0f) }, + { FrontRight, Deg2Rad( 30.0f), Deg2Rad(0.0f) } + }; + + const auto Frequency = static_cast(Device->Frequency); + const ALsizei NumSends{Device->NumAuxSends}; + ASSUME(NumSends >= 0); + + bool DirectChannels{props->DirectChannels != AL_FALSE}; + const ChanMap *chans{nullptr}; + ALsizei num_channels{0}; + bool isbformat{false}; + ALfloat downmix_gain{1.0f}; + switch(voice->mFmtChannels) + { + case FmtMono: + chans = MonoMap; + num_channels = 1; + /* Mono buffers are never played direct. */ + DirectChannels = false; + break; + + case FmtStereo: + /* Convert counter-clockwise to clockwise. */ + StereoMap[0].angle = -props->StereoPan[0]; + StereoMap[1].angle = -props->StereoPan[1]; + + chans = StereoMap; + num_channels = 2; + downmix_gain = 1.0f / 2.0f; + break; + + case FmtRear: + chans = RearMap; + num_channels = 2; + downmix_gain = 1.0f / 2.0f; + break; + + case FmtQuad: + chans = QuadMap; + num_channels = 4; + downmix_gain = 1.0f / 4.0f; + break; + + case FmtX51: + chans = X51Map; + num_channels = 6; + /* NOTE: Excludes LFE. */ + downmix_gain = 1.0f / 5.0f; + break; + + case FmtX61: + chans = X61Map; + num_channels = 7; + /* NOTE: Excludes LFE. */ + downmix_gain = 1.0f / 6.0f; + break; + + case FmtX71: + chans = X71Map; + num_channels = 8; + /* NOTE: Excludes LFE. */ + downmix_gain = 1.0f / 7.0f; + break; + + case FmtBFormat2D: + num_channels = 3; + isbformat = true; + DirectChannels = false; + break; + + case FmtBFormat3D: + num_channels = 4; + isbformat = true; + DirectChannels = false; + break; + } + ASSUME(num_channels > 0); + + std::for_each(voice->mChans.begin(), voice->mChans.begin()+num_channels, + [NumSends](ALvoice::ChannelData &chandata) -> void + { + chandata.mDryParams.Hrtf.Target = HrtfFilter{}; + ClearArray(chandata.mDryParams.Gains.Target); + std::for_each(chandata.mWetParams.begin(), chandata.mWetParams.begin()+NumSends, + [](SendParams ¶ms) -> void { ClearArray(params.Gains.Target); }); + }); + + voice->mFlags &= ~(VOICE_HAS_HRTF | VOICE_HAS_NFC); + if(isbformat) + { + /* Special handling for B-Format sources. */ + + if(Distance > std::numeric_limits::epsilon()) + { + /* Panning a B-Format sound toward some direction is easy. Just pan + * the first (W) channel as a normal mono sound and silence the + * others. + */ + + if(Device->AvgSpeakerDist > 0.0f) + { + /* Clamp the distance for really close sources, to prevent + * excessive bass. + */ + const ALfloat mdist{maxf(Distance, Device->AvgSpeakerDist/4.0f)}; + const ALfloat w0{SPEEDOFSOUNDMETRESPERSEC / (mdist * Frequency)}; + + /* Only need to adjust the first channel of a B-Format source. */ + voice->mChans[0].mDryParams.NFCtrlFilter.adjust(w0); + + voice->mFlags |= VOICE_HAS_NFC; + } + + ALfloat coeffs[MAX_AMBI_CHANNELS]; + if(Device->mRenderMode != StereoPair) + CalcDirectionCoeffs({xpos, ypos, zpos}, Spread, coeffs); + else + { + /* Clamp Y, in case rounding errors caused it to end up outside + * of -1...+1. + */ + const ALfloat ev{std::asin(clampf(ypos, -1.0f, 1.0f))}; + /* Negate Z for right-handed coords with -Z in front. */ + const ALfloat az{std::atan2(xpos, -zpos)}; + + /* A scalar of 1.5 for plain stereo results in +/-60 degrees + * being moved to +/-90 degrees for direct right and left + * speaker responses. + */ + CalcAngleCoeffs(ScaleAzimuthFront(az, 1.5f), ev, Spread, coeffs); + } + + /* NOTE: W needs to be scaled due to FuMa normalization. */ + const ALfloat &scale0 = AmbiScale::FromFuMa[0]; + ComputePanGains(&Device->Dry, coeffs, DryGain*scale0, + voice->mChans[0].mDryParams.Gains.Target); + for(ALsizei i{0};i < NumSends;i++) + { + if(const ALeffectslot *Slot{SendSlots[i]}) + ComputePanGains(&Slot->Wet, coeffs, WetGain[i]*scale0, + voice->mChans[0].mWetParams[i].Gains.Target); + } + } + else + { + if(Device->AvgSpeakerDist > 0.0f) + { + /* NOTE: The NFCtrlFilters were created with a w0 of 0, which + * is what we want for FOA input. The first channel may have + * been previously re-adjusted if panned, so reset it. + */ + voice->mChans[0].mDryParams.NFCtrlFilter.adjust(0.0f); + + voice->mFlags |= VOICE_HAS_NFC; + } + + /* Local B-Format sources have their XYZ channels rotated according + * to the orientation. + */ + /* AT then UP */ + alu::Vector N{props->OrientAt[0], props->OrientAt[1], props->OrientAt[2], 0.0f}; + N.normalize(); + alu::Vector V{props->OrientUp[0], props->OrientUp[1], props->OrientUp[2], 0.0f}; + V.normalize(); + if(!props->HeadRelative) + { + N = Listener.Params.Matrix * N; + V = Listener.Params.Matrix * V; + } + /* Build and normalize right-vector */ + alu::Vector U{aluCrossproduct(N, V)}; + U.normalize(); + + /* Build a rotate + conversion matrix (FuMa -> ACN+N3D). NOTE: This + * matrix is transposed, for the inputs to align on the rows and + * outputs on the columns. + */ + const ALfloat &wscale = AmbiScale::FromFuMa[0]; + const ALfloat &yscale = AmbiScale::FromFuMa[1]; + const ALfloat &zscale = AmbiScale::FromFuMa[2]; + const ALfloat &xscale = AmbiScale::FromFuMa[3]; + const ALfloat matrix[4][MAX_AMBI_CHANNELS]{ + // ACN0 ACN1 ACN2 ACN3 + { wscale, 0.0f, 0.0f, 0.0f }, // FuMa W + { 0.0f, -N[0]*xscale, N[1]*xscale, -N[2]*xscale }, // FuMa X + { 0.0f, U[0]*yscale, -U[1]*yscale, U[2]*yscale }, // FuMa Y + { 0.0f, -V[0]*zscale, V[1]*zscale, -V[2]*zscale } // FuMa Z + }; + + for(ALsizei c{0};c < num_channels;c++) + { + ComputePanGains(&Device->Dry, matrix[c], DryGain, + voice->mChans[c].mDryParams.Gains.Target); + + for(ALsizei i{0};i < NumSends;i++) + { + if(const ALeffectslot *Slot{SendSlots[i]}) + ComputePanGains(&Slot->Wet, matrix[c], WetGain[i], + voice->mChans[c].mWetParams[i].Gains.Target); + } + } + } + } + else if(DirectChannels) + { + /* Direct source channels always play local. Skip the virtual channels + * and write inputs to the matching real outputs. + */ + voice->mDirect.Buffer = Device->RealOut.Buffer; + + for(ALsizei c{0};c < num_channels;c++) + { + int idx{GetChannelIdxByName(Device->RealOut, chans[c].channel)}; + if(idx != -1) voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain; + } + + /* Auxiliary sends still use normal channel panning since they mix to + * B-Format, which can't channel-match. + */ + for(ALsizei c{0};c < num_channels;c++) + { + ALfloat coeffs[MAX_AMBI_CHANNELS]; + CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); + + for(ALsizei i{0};i < NumSends;i++) + { + if(const ALeffectslot *Slot{SendSlots[i]}) + ComputePanGains(&Slot->Wet, coeffs, WetGain[i], + voice->mChans[c].mWetParams[i].Gains.Target); + } + } + } + else if(Device->mRenderMode == HrtfRender) + { + /* Full HRTF rendering. Skip the virtual channels and render to the + * real outputs. + */ + voice->mDirect.Buffer = Device->RealOut.Buffer; + + if(Distance > std::numeric_limits::epsilon()) + { + const ALfloat ev{std::asin(clampf(ypos, -1.0f, 1.0f))}; + const ALfloat az{std::atan2(xpos, -zpos)}; + + /* Get the HRIR coefficients and delays just once, for the given + * source direction. + */ + GetHrtfCoeffs(Device->mHrtf, ev, az, Distance, Spread, + voice->mChans[0].mDryParams.Hrtf.Target.Coeffs, + voice->mChans[0].mDryParams.Hrtf.Target.Delay); + voice->mChans[0].mDryParams.Hrtf.Target.Gain = DryGain * downmix_gain; + + /* Remaining channels use the same results as the first. */ + for(ALsizei c{1};c < num_channels;c++) + { + /* Skip LFE */ + if(chans[c].channel == LFE) continue; + voice->mChans[c].mDryParams.Hrtf.Target = voice->mChans[0].mDryParams.Hrtf.Target; + } + + /* Calculate the directional coefficients once, which apply to all + * input channels of the source sends. + */ + ALfloat coeffs[MAX_AMBI_CHANNELS]; + CalcDirectionCoeffs({xpos, ypos, zpos}, Spread, coeffs); + + for(ALsizei c{0};c < num_channels;c++) + { + /* Skip LFE */ + if(chans[c].channel == LFE) + continue; + for(ALsizei i{0};i < NumSends;i++) + { + if(const ALeffectslot *Slot{SendSlots[i]}) + ComputePanGains(&Slot->Wet, coeffs, WetGain[i] * downmix_gain, + voice->mChans[c].mWetParams[i].Gains.Target); + } + } + } + else + { + /* Local sources on HRTF play with each channel panned to its + * relative location around the listener, providing "virtual + * speaker" responses. + */ + for(ALsizei c{0};c < num_channels;c++) + { + /* Skip LFE */ + if(chans[c].channel == LFE) + continue; + + /* Get the HRIR coefficients and delays for this channel + * position. + */ + GetHrtfCoeffs(Device->mHrtf, chans[c].elevation, chans[c].angle, + std::numeric_limits::infinity(), Spread, + voice->mChans[c].mDryParams.Hrtf.Target.Coeffs, + voice->mChans[c].mDryParams.Hrtf.Target.Delay); + voice->mChans[c].mDryParams.Hrtf.Target.Gain = DryGain; + + /* Normal panning for auxiliary sends. */ + ALfloat coeffs[MAX_AMBI_CHANNELS]; + CalcAngleCoeffs(chans[c].angle, chans[c].elevation, Spread, coeffs); + + for(ALsizei i{0};i < NumSends;i++) + { + if(const ALeffectslot *Slot{SendSlots[i]}) + ComputePanGains(&Slot->Wet, coeffs, WetGain[i], + voice->mChans[c].mWetParams[i].Gains.Target); + } + } + } + + voice->mFlags |= VOICE_HAS_HRTF; + } + else + { + /* Non-HRTF rendering. Use normal panning to the output. */ + + if(Distance > std::numeric_limits::epsilon()) + { + /* Calculate NFC filter coefficient if needed. */ + if(Device->AvgSpeakerDist > 0.0f) + { + /* Clamp the distance for really close sources, to prevent + * excessive bass. + */ + const ALfloat mdist{maxf(Distance, Device->AvgSpeakerDist/4.0f)}; + const ALfloat w0{SPEEDOFSOUNDMETRESPERSEC / (mdist * Frequency)}; + + /* Adjust NFC filters. */ + for(ALsizei c{0};c < num_channels;c++) + voice->mChans[c].mDryParams.NFCtrlFilter.adjust(w0); + + voice->mFlags |= VOICE_HAS_NFC; + } + + /* Calculate the directional coefficients once, which apply to all + * input channels. + */ + ALfloat coeffs[MAX_AMBI_CHANNELS]; + if(Device->mRenderMode != StereoPair) + CalcDirectionCoeffs({xpos, ypos, zpos}, Spread, coeffs); + else + { + const ALfloat ev{std::asin(clampf(ypos, -1.0f, 1.0f))}; + const ALfloat az{std::atan2(xpos, -zpos)}; + CalcAngleCoeffs(ScaleAzimuthFront(az, 1.5f), ev, Spread, coeffs); + } + + for(ALsizei c{0};c < num_channels;c++) + { + /* Special-case LFE */ + if(chans[c].channel == LFE) + { + if(Device->Dry.Buffer.data() == Device->RealOut.Buffer.data()) + { + int idx = GetChannelIdxByName(Device->RealOut, chans[c].channel); + if(idx != -1) voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain; + } + continue; + } + + ComputePanGains(&Device->Dry, coeffs, DryGain * downmix_gain, + voice->mChans[c].mDryParams.Gains.Target); + } + + for(ALsizei c{0};c < num_channels;c++) + { + /* Skip LFE */ + if(chans[c].channel == LFE) + continue; + for(ALsizei i{0};i < NumSends;i++) + { + if(const ALeffectslot *Slot{SendSlots[i]}) + ComputePanGains(&Slot->Wet, coeffs, WetGain[i] * downmix_gain, + voice->mChans[c].mWetParams[i].Gains.Target); + } + } + } + else + { + if(Device->AvgSpeakerDist > 0.0f) + { + /* If the source distance is 0, set w0 to w1 to act as a pass- + * through. We still want to pass the signal through the + * filters so they keep an appropriate history, in case the + * source moves away from the listener. + */ + const ALfloat w0{SPEEDOFSOUNDMETRESPERSEC / (Device->AvgSpeakerDist * Frequency)}; + + for(ALsizei c{0};c < num_channels;c++) + voice->mChans[c].mDryParams.NFCtrlFilter.adjust(w0); + + voice->mFlags |= VOICE_HAS_NFC; + } + + for(ALsizei c{0};c < num_channels;c++) + { + /* Special-case LFE */ + if(chans[c].channel == LFE) + { + if(Device->Dry.Buffer.data() == Device->RealOut.Buffer.data()) + { + int idx = GetChannelIdxByName(Device->RealOut, chans[c].channel); + if(idx != -1) voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain; + } + continue; + } + + ALfloat coeffs[MAX_AMBI_CHANNELS]; + CalcAngleCoeffs( + (Device->mRenderMode==StereoPair) ? ScaleAzimuthFront(chans[c].angle, 3.0f) + : chans[c].angle, + chans[c].elevation, Spread, coeffs + ); + + ComputePanGains(&Device->Dry, coeffs, DryGain, + voice->mChans[c].mDryParams.Gains.Target); + for(ALsizei i{0};i < NumSends;i++) + { + if(const ALeffectslot *Slot{SendSlots[i]}) + ComputePanGains(&Slot->Wet, coeffs, WetGain[i], + voice->mChans[c].mWetParams[i].Gains.Target); + } + } + } + } + + { + const ALfloat hfScale{props->Direct.HFReference / Frequency}; + const ALfloat lfScale{props->Direct.LFReference / Frequency}; + const ALfloat gainHF{maxf(DryGainHF, 0.001f)}; /* Limit -60dB */ + const ALfloat gainLF{maxf(DryGainLF, 0.001f)}; + + voice->mDirect.FilterType = AF_None; + if(gainHF != 1.0f) voice->mDirect.FilterType |= AF_LowPass; + if(gainLF != 1.0f) voice->mDirect.FilterType |= AF_HighPass; + auto &lowpass = voice->mChans[0].mDryParams.LowPass; + auto &highpass = voice->mChans[0].mDryParams.HighPass; + lowpass.setParams(BiquadType::HighShelf, gainHF, hfScale, + lowpass.rcpQFromSlope(gainHF, 1.0f)); + highpass.setParams(BiquadType::LowShelf, gainLF, lfScale, + highpass.rcpQFromSlope(gainLF, 1.0f)); + for(ALsizei c{1};c < num_channels;c++) + { + voice->mChans[c].mDryParams.LowPass.copyParamsFrom(lowpass); + voice->mChans[c].mDryParams.HighPass.copyParamsFrom(highpass); + } + } + for(ALsizei i{0};i < NumSends;i++) + { + const ALfloat hfScale{props->Send[i].HFReference / Frequency}; + const ALfloat lfScale{props->Send[i].LFReference / Frequency}; + const ALfloat gainHF{maxf(WetGainHF[i], 0.001f)}; + const ALfloat gainLF{maxf(WetGainLF[i], 0.001f)}; + + voice->mSend[i].FilterType = AF_None; + if(gainHF != 1.0f) voice->mSend[i].FilterType |= AF_LowPass; + if(gainLF != 1.0f) voice->mSend[i].FilterType |= AF_HighPass; + + auto &lowpass = voice->mChans[0].mWetParams[i].LowPass; + auto &highpass = voice->mChans[0].mWetParams[i].HighPass; + lowpass.setParams(BiquadType::HighShelf, gainHF, hfScale, + lowpass.rcpQFromSlope(gainHF, 1.0f)); + highpass.setParams(BiquadType::LowShelf, gainLF, lfScale, + highpass.rcpQFromSlope(gainLF, 1.0f)); + for(ALsizei c{1};c < num_channels;c++) + { + voice->mChans[c].mWetParams[i].LowPass.copyParamsFrom(lowpass); + voice->mChans[c].mWetParams[i].HighPass.copyParamsFrom(highpass); + } + } +} + +void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const ALCcontext *ALContext) +{ + const ALCdevice *Device{ALContext->Device}; + ALeffectslot *SendSlots[MAX_SENDS]; + + voice->mDirect.Buffer = Device->Dry.Buffer; + for(ALsizei i{0};i < Device->NumAuxSends;i++) + { + SendSlots[i] = props->Send[i].Slot; + if(!SendSlots[i] && i == 0) + SendSlots[i] = ALContext->DefaultSlot.get(); + if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) + { + SendSlots[i] = nullptr; + voice->mSend[i].Buffer = {}; + } + else + voice->mSend[i].Buffer = SendSlots[i]->Wet.Buffer; + } + + /* Calculate the stepping value */ + const auto Pitch = static_cast(voice->mFrequency) / + static_cast(Device->Frequency) * props->Pitch; + if(Pitch > static_cast(MAX_PITCH)) + voice->mStep = MAX_PITCH<mStep = maxi(fastf2i(Pitch * FRACTIONONE), 1); + if(props->mResampler == BSinc24Resampler) + BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc24); + else if(props->mResampler == BSinc12Resampler) + BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc12); + voice->mResampler = SelectResampler(props->mResampler); + + /* Calculate gains */ + const ALlistener &Listener = ALContext->Listener; + ALfloat DryGain{clampf(props->Gain, props->MinGain, props->MaxGain)}; + DryGain *= props->Direct.Gain * Listener.Params.Gain; + DryGain = minf(DryGain, GAIN_MIX_MAX); + ALfloat DryGainHF{props->Direct.GainHF}; + ALfloat DryGainLF{props->Direct.GainLF}; + ALfloat WetGain[MAX_SENDS], WetGainHF[MAX_SENDS], WetGainLF[MAX_SENDS]; + for(ALsizei i{0};i < Device->NumAuxSends;i++) + { + WetGain[i] = clampf(props->Gain, props->MinGain, props->MaxGain); + WetGain[i] *= props->Send[i].Gain * Listener.Params.Gain; + WetGain[i] = minf(WetGain[i], GAIN_MIX_MAX); + WetGainHF[i] = props->Send[i].GainHF; + WetGainLF[i] = props->Send[i].GainLF; + } + + CalcPanningAndFilters(voice, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, DryGain, DryGainHF, DryGainLF, + WetGain, WetGainLF, WetGainHF, SendSlots, props, Listener, Device); +} + +void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const ALCcontext *ALContext) +{ + const ALCdevice *Device{ALContext->Device}; + const ALsizei NumSends{Device->NumAuxSends}; + const ALlistener &Listener = ALContext->Listener; + + /* Set mixing buffers and get send parameters. */ + voice->mDirect.Buffer = Device->Dry.Buffer; + ALeffectslot *SendSlots[MAX_SENDS]; + ALfloat RoomRolloff[MAX_SENDS]; + ALfloat DecayDistance[MAX_SENDS]; + ALfloat DecayLFDistance[MAX_SENDS]; + ALfloat DecayHFDistance[MAX_SENDS]; + for(ALsizei i{0};i < NumSends;i++) + { + SendSlots[i] = props->Send[i].Slot; + if(!SendSlots[i] && i == 0) + SendSlots[i] = ALContext->DefaultSlot.get(); + if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) + { + SendSlots[i] = nullptr; + RoomRolloff[i] = 0.0f; + DecayDistance[i] = 0.0f; + DecayLFDistance[i] = 0.0f; + DecayHFDistance[i] = 0.0f; + } + else if(SendSlots[i]->Params.AuxSendAuto) + { + RoomRolloff[i] = SendSlots[i]->Params.RoomRolloff + props->RoomRolloffFactor; + /* Calculate the distances to where this effect's decay reaches + * -60dB. + */ + DecayDistance[i] = SendSlots[i]->Params.DecayTime * + Listener.Params.ReverbSpeedOfSound; + DecayLFDistance[i] = DecayDistance[i] * SendSlots[i]->Params.DecayLFRatio; + DecayHFDistance[i] = DecayDistance[i] * SendSlots[i]->Params.DecayHFRatio; + if(SendSlots[i]->Params.DecayHFLimit) + { + ALfloat airAbsorption{SendSlots[i]->Params.AirAbsorptionGainHF}; + if(airAbsorption < 1.0f) + { + /* Calculate the distance to where this effect's air + * absorption reaches -60dB, and limit the effect's HF + * decay distance (so it doesn't take any longer to decay + * than the air would allow). + */ + ALfloat absorb_dist{std::log10(REVERB_DECAY_GAIN) / std::log10(airAbsorption)}; + DecayHFDistance[i] = minf(absorb_dist, DecayHFDistance[i]); + } + } + } + else + { + /* If the slot's auxiliary send auto is off, the data sent to the + * effect slot is the same as the dry path, sans filter effects */ + RoomRolloff[i] = props->RolloffFactor; + DecayDistance[i] = 0.0f; + DecayLFDistance[i] = 0.0f; + DecayHFDistance[i] = 0.0f; + } + + if(!SendSlots[i]) + voice->mSend[i].Buffer = {}; + else + voice->mSend[i].Buffer = SendSlots[i]->Wet.Buffer; + } + + /* Transform source to listener space (convert to head relative) */ + alu::Vector Position{props->Position[0], props->Position[1], props->Position[2], 1.0f}; + alu::Vector Velocity{props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f}; + alu::Vector Direction{props->Direction[0], props->Direction[1], props->Direction[2], 0.0f}; + if(props->HeadRelative == AL_FALSE) + { + /* Transform source vectors */ + Position = Listener.Params.Matrix * Position; + Velocity = Listener.Params.Matrix * Velocity; + Direction = Listener.Params.Matrix * Direction; + } + else + { + /* Offset the source velocity to be relative of the listener velocity */ + Velocity += Listener.Params.Velocity; + } + + const bool directional{Direction.normalize() > 0.0f}; + alu::Vector ToSource{Position[0], Position[1], Position[2], 0.0f}; + const ALfloat Distance{ToSource.normalize()}; + + /* Initial source gain */ + ALfloat DryGain{props->Gain}; + ALfloat DryGainHF{1.0f}; + ALfloat DryGainLF{1.0f}; + ALfloat WetGain[MAX_SENDS], WetGainHF[MAX_SENDS], WetGainLF[MAX_SENDS]; + for(ALsizei i{0};i < NumSends;i++) + { + WetGain[i] = props->Gain; + WetGainHF[i] = 1.0f; + WetGainLF[i] = 1.0f; + } + + /* Calculate distance attenuation */ + ALfloat ClampedDist{Distance}; + + switch(Listener.Params.SourceDistanceModel ? + props->mDistanceModel : Listener.Params.mDistanceModel) + { + case DistanceModel::InverseClamped: + ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); + if(props->MaxDistance < props->RefDistance) break; + /*fall-through*/ + case DistanceModel::Inverse: + if(!(props->RefDistance > 0.0f)) + ClampedDist = props->RefDistance; + else + { + ALfloat dist = lerp(props->RefDistance, ClampedDist, props->RolloffFactor); + if(dist > 0.0f) DryGain *= props->RefDistance / dist; + for(ALsizei i{0};i < NumSends;i++) + { + dist = lerp(props->RefDistance, ClampedDist, RoomRolloff[i]); + if(dist > 0.0f) WetGain[i] *= props->RefDistance / dist; + } + } + break; + + case DistanceModel::LinearClamped: + ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); + if(props->MaxDistance < props->RefDistance) break; + /*fall-through*/ + case DistanceModel::Linear: + if(!(props->MaxDistance != props->RefDistance)) + ClampedDist = props->RefDistance; + else + { + ALfloat attn = props->RolloffFactor * (ClampedDist-props->RefDistance) / + (props->MaxDistance-props->RefDistance); + DryGain *= maxf(1.0f - attn, 0.0f); + for(ALsizei i{0};i < NumSends;i++) + { + attn = RoomRolloff[i] * (ClampedDist-props->RefDistance) / + (props->MaxDistance-props->RefDistance); + WetGain[i] *= maxf(1.0f - attn, 0.0f); + } + } + break; + + case DistanceModel::ExponentClamped: + ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); + if(props->MaxDistance < props->RefDistance) break; + /*fall-through*/ + case DistanceModel::Exponent: + if(!(ClampedDist > 0.0f && props->RefDistance > 0.0f)) + ClampedDist = props->RefDistance; + else + { + DryGain *= std::pow(ClampedDist/props->RefDistance, -props->RolloffFactor); + for(ALsizei i{0};i < NumSends;i++) + WetGain[i] *= std::pow(ClampedDist/props->RefDistance, -RoomRolloff[i]); + } + break; + + case DistanceModel::Disable: + ClampedDist = props->RefDistance; + break; + } + + /* Calculate directional soundcones */ + if(directional && props->InnerAngle < 360.0f) + { + const ALfloat Angle{Rad2Deg(std::acos(-aluDotproduct(Direction, ToSource)) * + ConeScale * 2.0f)}; + + ALfloat ConeVolume, ConeHF; + if(!(Angle > props->InnerAngle)) + { + ConeVolume = 1.0f; + ConeHF = 1.0f; + } + else if(Angle < props->OuterAngle) + { + ALfloat scale = ( Angle-props->InnerAngle) / + (props->OuterAngle-props->InnerAngle); + ConeVolume = lerp(1.0f, props->OuterGain, scale); + ConeHF = lerp(1.0f, props->OuterGainHF, scale); + } + else + { + ConeVolume = props->OuterGain; + ConeHF = props->OuterGainHF; + } + + DryGain *= ConeVolume; + if(props->DryGainHFAuto) + DryGainHF *= ConeHF; + if(props->WetGainAuto) + std::transform(std::begin(WetGain), std::begin(WetGain)+NumSends, std::begin(WetGain), + [ConeVolume](ALfloat gain) noexcept -> ALfloat { return gain * ConeVolume; } + ); + if(props->WetGainHFAuto) + std::transform(std::begin(WetGainHF), std::begin(WetGainHF)+NumSends, + std::begin(WetGainHF), + [ConeHF](ALfloat gain) noexcept -> ALfloat { return gain * ConeHF; } + ); + } + + /* Apply gain and frequency filters */ + DryGain = clampf(DryGain, props->MinGain, props->MaxGain); + DryGain = minf(DryGain*props->Direct.Gain*Listener.Params.Gain, GAIN_MIX_MAX); + DryGainHF *= props->Direct.GainHF; + DryGainLF *= props->Direct.GainLF; + for(ALsizei i{0};i < NumSends;i++) + { + WetGain[i] = clampf(WetGain[i], props->MinGain, props->MaxGain); + WetGain[i] = minf(WetGain[i]*props->Send[i].Gain*Listener.Params.Gain, GAIN_MIX_MAX); + WetGainHF[i] *= props->Send[i].GainHF; + WetGainLF[i] *= props->Send[i].GainLF; + } + + /* Distance-based air absorption and initial send decay. */ + if(ClampedDist > props->RefDistance && props->RolloffFactor > 0.0f) + { + ALfloat meters_base{(ClampedDist-props->RefDistance) * props->RolloffFactor * + Listener.Params.MetersPerUnit}; + if(props->AirAbsorptionFactor > 0.0f) + { + ALfloat hfattn{std::pow(AIRABSORBGAINHF, meters_base * props->AirAbsorptionFactor)}; + DryGainHF *= hfattn; + std::transform(std::begin(WetGainHF), std::begin(WetGainHF)+NumSends, + std::begin(WetGainHF), + [hfattn](ALfloat gain) noexcept -> ALfloat { return gain * hfattn; } + ); + } + + if(props->WetGainAuto) + { + /* Apply a decay-time transformation to the wet path, based on the + * source distance in meters. The initial decay of the reverb + * effect is calculated and applied to the wet path. + */ + for(ALsizei i{0};i < NumSends;i++) + { + if(!(DecayDistance[i] > 0.0f)) + continue; + + const ALfloat gain{std::pow(REVERB_DECAY_GAIN, meters_base/DecayDistance[i])}; + WetGain[i] *= gain; + /* Yes, the wet path's air absorption is applied with + * WetGainAuto on, rather than WetGainHFAuto. + */ + if(gain > 0.0f) + { + ALfloat gainhf{std::pow(REVERB_DECAY_GAIN, meters_base/DecayHFDistance[i])}; + WetGainHF[i] *= minf(gainhf / gain, 1.0f); + ALfloat gainlf{std::pow(REVERB_DECAY_GAIN, meters_base/DecayLFDistance[i])}; + WetGainLF[i] *= minf(gainlf / gain, 1.0f); + } + } + } + } + + + /* Initial source pitch */ + ALfloat Pitch{props->Pitch}; + + /* Calculate velocity-based doppler effect */ + ALfloat DopplerFactor{props->DopplerFactor * Listener.Params.DopplerFactor}; + if(DopplerFactor > 0.0f) + { + const alu::Vector &lvelocity = Listener.Params.Velocity; + ALfloat vss{aluDotproduct(Velocity, ToSource) * -DopplerFactor}; + ALfloat vls{aluDotproduct(lvelocity, ToSource) * -DopplerFactor}; + + const ALfloat SpeedOfSound{Listener.Params.SpeedOfSound}; + if(!(vls < SpeedOfSound)) + { + /* Listener moving away from the source at the speed of sound. + * Sound waves can't catch it. + */ + Pitch = 0.0f; + } + else if(!(vss < SpeedOfSound)) + { + /* Source moving toward the listener at the speed of sound. Sound + * waves bunch up to extreme frequencies. + */ + Pitch = std::numeric_limits::infinity(); + } + else + { + /* Source and listener movement is nominal. Calculate the proper + * doppler shift. + */ + Pitch *= (SpeedOfSound-vls) / (SpeedOfSound-vss); + } + } + + /* Adjust pitch based on the buffer and output frequencies, and calculate + * fixed-point stepping value. + */ + Pitch *= static_cast(voice->mFrequency)/static_cast(Device->Frequency); + if(Pitch > static_cast(MAX_PITCH)) + voice->mStep = MAX_PITCH<mStep = maxi(fastf2i(Pitch * FRACTIONONE), 1); + if(props->mResampler == BSinc24Resampler) + BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc24); + else if(props->mResampler == BSinc12Resampler) + BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc12); + voice->mResampler = SelectResampler(props->mResampler); + + ALfloat spread{0.0f}; + if(props->Radius > Distance) + spread = al::MathDefs::Tau() - Distance/props->Radius*al::MathDefs::Pi(); + else if(Distance > 0.0f) + spread = std::asin(props->Radius/Distance) * 2.0f; + + CalcPanningAndFilters(voice, ToSource[0], ToSource[1], ToSource[2]*ZScale, + Distance*Listener.Params.MetersPerUnit, spread, DryGain, DryGainHF, DryGainLF, WetGain, + WetGainLF, WetGainHF, SendSlots, props, Listener, Device); +} + +void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) +{ + ALvoiceProps *props{voice->mUpdate.exchange(nullptr, std::memory_order_acq_rel)}; + if(!props && !force) return; + + if(props) + { + voice->mProps = *props; + + AtomicReplaceHead(context->FreeVoiceProps, props); + } + + if((voice->mProps.mSpatializeMode == SpatializeAuto && voice->mFmtChannels == FmtMono) || + voice->mProps.mSpatializeMode == SpatializeOn) + CalcAttnSourceParams(voice, &voice->mProps, context); + else + CalcNonAttnSourceParams(voice, &voice->mProps, context); +} + + +void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray *slots) +{ + IncrementRef(&ctx->UpdateCount); + if(LIKELY(!ctx->HoldUpdates.load(std::memory_order_acquire))) + { + bool cforce{CalcContextParams(ctx)}; + bool force{CalcListenerParams(ctx) || cforce}; + force = std::accumulate(slots->begin(), slots->end(), force, + [ctx,cforce](bool force, ALeffectslot *slot) -> bool + { return CalcEffectSlotParams(slot, ctx, cforce) | force; } + ); + + std::for_each(ctx->Voices->begin(), + ctx->Voices->begin() + ctx->VoiceCount.load(std::memory_order_acquire), + [ctx,force](ALvoice &voice) -> void + { + ALuint sid{voice.mSourceID.load(std::memory_order_acquire)}; + if(sid) CalcSourceParams(&voice, ctx, force); + } + ); + } + IncrementRef(&ctx->UpdateCount); +} + +void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) +{ + ASSUME(SamplesToDo > 0); + + const ALeffectslotArray *auxslots{ctx->ActiveAuxSlots.load(std::memory_order_acquire)}; + + /* Process pending propery updates for objects on the context. */ + ProcessParamUpdates(ctx, auxslots); + + /* Clear auxiliary effect slot mixing buffers. */ + std::for_each(auxslots->begin(), auxslots->end(), + [SamplesToDo](ALeffectslot *slot) -> void + { + for(auto &buffer : slot->MixBuffer) + std::fill_n(buffer.begin(), SamplesToDo, 0.0f); + } + ); + + /* Process voices that have a playing source. */ + std::for_each(ctx->Voices->begin(), + ctx->Voices->begin() + ctx->VoiceCount.load(std::memory_order_acquire), + [SamplesToDo,ctx](ALvoice &voice) -> void + { + const ALvoice::State vstate{voice.mPlayState.load(std::memory_order_acquire)}; + if(vstate == ALvoice::Stopped) return; + const ALuint sid{voice.mSourceID.load(std::memory_order_relaxed)}; + if(voice.mStep < 1) return; + + MixVoice(&voice, vstate, sid, ctx, SamplesToDo); + } + ); + + /* Process effects. */ + if(auxslots->size() < 1) return; + auto slots = auxslots->data(); + auto slots_end = slots + auxslots->size(); + + /* First sort the slots into scratch storage, so that effects come before + * their effect target (or their targets' target). + */ + auto sorted_slots = const_cast(slots_end); + auto sorted_slots_end = sorted_slots; + auto in_chain = [](const ALeffectslot *slot1, const ALeffectslot *slot2) noexcept -> bool + { + while((slot1=slot1->Params.Target) != nullptr) { + if(slot1 == slot2) return true; + } + return false; + }; + + *sorted_slots_end = *slots; + ++sorted_slots_end; + while(++slots != slots_end) + { + /* If this effect slot targets an effect slot already in the list (i.e. + * slots outputs to something in sorted_slots), directly or indirectly, + * insert it prior to that element. + */ + auto checker = sorted_slots; + do { + if(in_chain(*slots, *checker)) break; + } while(++checker != sorted_slots_end); + + checker = std::move_backward(checker, sorted_slots_end, sorted_slots_end+1); + *--checker = *slots; + ++sorted_slots_end; + } + + std::for_each(sorted_slots, sorted_slots_end, + [SamplesToDo](const ALeffectslot *slot) -> void + { + EffectState *state{slot->Params.mEffectState}; + state->process(SamplesToDo, slot->Wet.Buffer.data(), + static_cast(slot->Wet.Buffer.size()), state->mOutTarget); + } + ); +} + + +void ApplyStablizer(FrontStablizer *Stablizer, const al::span Buffer, + const ALuint lidx, const ALuint ridx, const ALuint cidx, const ALsizei SamplesToDo) +{ + ASSUME(SamplesToDo > 0); + + /* Apply a delay to all channels, except the front-left and front-right, so + * they maintain correct timing. + */ + const size_t NumChannels{Buffer.size()}; + for(size_t i{0u};i < NumChannels;i++) + { + if(i == lidx || i == ridx) + continue; + + auto &DelayBuf = Stablizer->DelayBuf[i]; + auto buffer_end = Buffer[i].begin() + SamplesToDo; + if(LIKELY(SamplesToDo >= ALsizei{FrontStablizer::DelayLength})) + { + auto delay_end = std::rotate(Buffer[i].begin(), + buffer_end - FrontStablizer::DelayLength, buffer_end); + std::swap_ranges(Buffer[i].begin(), delay_end, std::begin(DelayBuf)); + } + else + { + auto delay_start = std::swap_ranges(Buffer[i].begin(), buffer_end, + std::begin(DelayBuf)); + std::rotate(std::begin(DelayBuf), delay_start, std::end(DelayBuf)); + } + } + + ALfloat (&lsplit)[2][BUFFERSIZE] = Stablizer->LSplit; + ALfloat (&rsplit)[2][BUFFERSIZE] = Stablizer->RSplit; + auto &tmpbuf = Stablizer->TempBuf; + + /* This applies the band-splitter, preserving phase at the cost of some + * delay. The shorter the delay, the more error seeps into the result. + */ + auto apply_splitter = [&tmpbuf,SamplesToDo](const FloatBufferLine &Buffer, + ALfloat (&DelayBuf)[FrontStablizer::DelayLength], BandSplitter &Filter, + ALfloat (&splitbuf)[2][BUFFERSIZE]) -> void + { + /* Combine the delayed samples and the input samples into the temp + * buffer, in reverse. Then copy the final samples back into the delay + * buffer for next time. Note that the delay buffer's samples are + * stored backwards here. + */ + auto tmpbuf_end = std::begin(tmpbuf) + SamplesToDo; + std::copy_n(std::begin(DelayBuf), FrontStablizer::DelayLength, tmpbuf_end); + std::reverse_copy(Buffer.begin(), Buffer.begin()+SamplesToDo, std::begin(tmpbuf)); + std::copy_n(std::begin(tmpbuf), FrontStablizer::DelayLength, std::begin(DelayBuf)); + + /* Apply an all-pass on the reversed signal, then reverse the samples + * to get the forward signal with a reversed phase shift. + */ + Filter.applyAllpass(tmpbuf, SamplesToDo+FrontStablizer::DelayLength); + std::reverse(std::begin(tmpbuf), tmpbuf_end+FrontStablizer::DelayLength); + + /* Now apply the band-splitter, combining its phase shift with the + * reversed phase shift, restoring the original phase on the split + * signal. + */ + Filter.process(splitbuf[1], splitbuf[0], tmpbuf, SamplesToDo); + }; + apply_splitter(Buffer[lidx], Stablizer->DelayBuf[lidx], Stablizer->LFilter, lsplit); + apply_splitter(Buffer[ridx], Stablizer->DelayBuf[ridx], Stablizer->RFilter, rsplit); + + for(ALsizei i{0};i < SamplesToDo;i++) + { + ALfloat lfsum{lsplit[0][i] + rsplit[0][i]}; + ALfloat hfsum{lsplit[1][i] + rsplit[1][i]}; + ALfloat s{lsplit[0][i] + lsplit[1][i] - rsplit[0][i] - rsplit[1][i]}; + + /* This pans the separate low- and high-frequency sums between being on + * the center channel and the left/right channels. The low-frequency + * sum is 1/3rd toward center (2/3rds on left/right) and the high- + * frequency sum is 1/4th toward center (3/4ths on left/right). These + * values can be tweaked. + */ + ALfloat m{lfsum*std::cos(1.0f/3.0f * (al::MathDefs::Pi()*0.5f)) + + hfsum*std::cos(1.0f/4.0f * (al::MathDefs::Pi()*0.5f))}; + ALfloat c{lfsum*std::sin(1.0f/3.0f * (al::MathDefs::Pi()*0.5f)) + + hfsum*std::sin(1.0f/4.0f * (al::MathDefs::Pi()*0.5f))}; + + /* The generated center channel signal adds to the existing signal, + * while the modified left and right channels replace. + */ + Buffer[lidx][i] = (m + s) * 0.5f; + Buffer[ridx][i] = (m - s) * 0.5f; + Buffer[cidx][i] += c * 0.5f; + } +} + +void ApplyDistanceComp(const al::span Samples, const ALsizei SamplesToDo, + const DistanceComp::DistData *distcomp) +{ + ASSUME(SamplesToDo > 0); + + for(auto &chanbuffer : Samples) + { + const ALfloat gain{distcomp->Gain}; + const ALsizei base{distcomp->Length}; + ALfloat *distbuf{al::assume_aligned<16>(distcomp->Buffer)}; + ++distcomp; + + if(base < 1) + continue; + + ALfloat *inout{al::assume_aligned<16>(chanbuffer.data())}; + auto inout_end = inout + SamplesToDo; + if(LIKELY(SamplesToDo >= base)) + { + auto delay_end = std::rotate(inout, inout_end - base, inout_end); + std::swap_ranges(inout, delay_end, distbuf); + } + else + { + auto delay_start = std::swap_ranges(inout, inout_end, distbuf); + std::rotate(distbuf, delay_start, distbuf + base); + } + std::transform(inout, inout_end, inout, std::bind(std::multiplies{}, _1, gain)); + } +} + +void ApplyDither(const al::span Samples, ALuint *dither_seed, + const ALfloat quant_scale, const ALsizei SamplesToDo) +{ + /* Dithering. Generate whitenoise (uniform distribution of random values + * between -1 and +1) and add it to the sample values, after scaling up to + * the desired quantization depth amd before rounding. + */ + const ALfloat invscale{1.0f / quant_scale}; + ALuint seed{*dither_seed}; + auto dither_channel = [&seed,invscale,quant_scale,SamplesToDo](FloatBufferLine &input) -> void + { + ASSUME(SamplesToDo > 0); + auto dither_sample = [&seed,invscale,quant_scale](const ALfloat sample) noexcept -> ALfloat + { + ALfloat val{sample * quant_scale}; + ALuint rng0{dither_rng(&seed)}; + ALuint rng1{dither_rng(&seed)}; + val += static_cast(rng0*(1.0/UINT_MAX) - rng1*(1.0/UINT_MAX)); + return fast_roundf(val) * invscale; + }; + std::transform(input.begin(), input.begin()+SamplesToDo, input.begin(), dither_sample); + }; + std::for_each(Samples.begin(), Samples.end(), dither_channel); + *dither_seed = seed; +} + + +/* Base template left undefined. Should be marked =delete, but Clang 3.8.1 + * chokes on that given the inline specializations. + */ +template +inline T SampleConv(ALfloat) noexcept; + +template<> inline ALfloat SampleConv(ALfloat val) noexcept +{ return val; } +template<> inline ALint SampleConv(ALfloat val) noexcept +{ + /* Floats have a 23-bit mantissa, plus an implied 1 bit and a sign bit. + * This means a normalized float has at most 25 bits of signed precision. + * When scaling and clamping for a signed 32-bit integer, these following + * values are the best a float can give. + */ + return fastf2i(clampf(val*2147483648.0f, -2147483648.0f, 2147483520.0f)); +} +template<> inline ALshort SampleConv(ALfloat val) noexcept +{ return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); } +template<> inline ALbyte SampleConv(ALfloat val) noexcept +{ return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); } + +/* Define unsigned output variations. */ +template<> inline ALuint SampleConv(ALfloat val) noexcept +{ return SampleConv(val) + 2147483648u; } +template<> inline ALushort SampleConv(ALfloat val) noexcept +{ return SampleConv(val) + 32768; } +template<> inline ALubyte SampleConv(ALfloat val) noexcept +{ return SampleConv(val) + 128; } + +template +void Write(const al::span InBuffer, ALvoid *OutBuffer, const size_t Offset, + const ALsizei SamplesToDo) +{ + using SampleType = typename DevFmtTypeTraits::Type; + + const size_t numchans{InBuffer.size()}; + ASSUME(numchans > 0); + + SampleType *outbase = static_cast(OutBuffer) + Offset*numchans; + auto conv_channel = [&outbase,SamplesToDo,numchans](const FloatBufferLine &inbuf) -> void + { + ASSUME(SamplesToDo > 0); + SampleType *out{outbase++}; + auto conv_sample = [numchans,&out](const ALfloat s) noexcept -> void + { + *out = SampleConv(s); + out += numchans; + }; + std::for_each(inbuf.begin(), inbuf.begin()+SamplesToDo, conv_sample); + }; + std::for_each(InBuffer.cbegin(), InBuffer.cend(), conv_channel); +} + +} // namespace + +void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) +{ + FPUCtl mixer_mode{}; + for(ALsizei SamplesDone{0};SamplesDone < NumSamples;) + { + const ALsizei SamplesToDo{mini(NumSamples-SamplesDone, BUFFERSIZE)}; + + /* Clear main mixing buffers. */ + std::for_each(device->MixBuffer.begin(), device->MixBuffer.end(), + [SamplesToDo](std::array &buffer) -> void + { std::fill_n(buffer.begin(), SamplesToDo, 0.0f); } + ); + + /* Increment the mix count at the start (lsb should now be 1). */ + IncrementRef(&device->MixCount); + + /* For each context on this device, process and mix its sources and + * effects. + */ + for(ALCcontext *ctx : *device->mContexts.load(std::memory_order_acquire)) + ProcessContext(ctx, SamplesToDo); + + /* Increment the clock time. Every second's worth of samples is + * converted and added to clock base so that large sample counts don't + * overflow during conversion. This also guarantees a stable + * conversion. + */ + device->SamplesDone += SamplesToDo; + device->ClockBase += std::chrono::seconds{device->SamplesDone / device->Frequency}; + device->SamplesDone %= device->Frequency; + + /* Increment the mix count at the end (lsb should now be 0). */ + IncrementRef(&device->MixCount); + + /* Apply any needed post-process for finalizing the Dry mix to the + * RealOut (Ambisonic decode, UHJ encode, etc). + */ + if(LIKELY(device->PostProcess)) + device->PostProcess(device, SamplesToDo); + const al::span RealOut{device->RealOut.Buffer}; + + /* Apply front image stablization for surround sound, if applicable. */ + if(device->Stablizer) + { + const int lidx{GetChannelIdxByName(device->RealOut, FrontLeft)}; + const int ridx{GetChannelIdxByName(device->RealOut, FrontRight)}; + const int cidx{GetChannelIdxByName(device->RealOut, FrontCenter)}; + assert(lidx >= 0 && ridx >= 0 && cidx >= 0); + + ApplyStablizer(device->Stablizer.get(), RealOut, lidx, ridx, cidx, SamplesToDo); + } + + /* Apply compression, limiting sample amplitude if needed or desired. */ + if(Compressor *comp{device->Limiter.get()}) + comp->process(SamplesToDo, RealOut.data()); + + /* Apply delays and attenuation for mismatched speaker distances. */ + ApplyDistanceComp(RealOut, SamplesToDo, device->ChannelDelay.as_span().cbegin()); + + /* Apply dithering. The compressor should have left enough headroom for + * the dither noise to not saturate. + */ + if(device->DitherDepth > 0.0f) + ApplyDither(RealOut, &device->DitherSeed, device->DitherDepth, SamplesToDo); + + if(LIKELY(OutBuffer)) + { + /* Finally, interleave and convert samples, writing to the device's + * output buffer. + */ + switch(device->FmtType) + { +#define HANDLE_WRITE(T) case T: \ + Write(RealOut, OutBuffer, SamplesDone, SamplesToDo); break; + HANDLE_WRITE(DevFmtByte) + HANDLE_WRITE(DevFmtUByte) + HANDLE_WRITE(DevFmtShort) + HANDLE_WRITE(DevFmtUShort) + HANDLE_WRITE(DevFmtInt) + HANDLE_WRITE(DevFmtUInt) + HANDLE_WRITE(DevFmtFloat) +#undef HANDLE_WRITE + } + } + + SamplesDone += SamplesToDo; + } +} + + +void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) +{ + if(!device->Connected.exchange(false, std::memory_order_acq_rel)) + return; + + AsyncEvent evt{EventType_Disconnected}; + evt.u.user.type = AL_EVENT_TYPE_DISCONNECTED_SOFT; + evt.u.user.id = 0; + evt.u.user.param = 0; + + va_list args; + va_start(args, msg); + int msglen{vsnprintf(evt.u.user.msg, sizeof(evt.u.user.msg), msg, args)}; + va_end(args); + + if(msglen < 0 || static_cast(msglen) >= sizeof(evt.u.user.msg)) + evt.u.user.msg[sizeof(evt.u.user.msg)-1] = 0; + + for(ALCcontext *ctx : *device->mContexts.load()) + { + const ALbitfieldSOFT enabledevt{ctx->EnabledEvts.load(std::memory_order_acquire)}; + if((enabledevt&EventType_Disconnected)) + { + RingBuffer *ring{ctx->AsyncEvents.get()}; + auto evt_data = ring->getWriteVector().first; + if(evt_data.len > 0) + { + new (evt_data.buf) AsyncEvent{evt}; + ring->writeAdvance(1); + ctx->EventSem.post(); + } + } + + auto stop_voice = [](ALvoice &voice) -> void + { + voice.mCurrentBuffer.store(nullptr, std::memory_order_relaxed); + voice.mLoopBuffer.store(nullptr, std::memory_order_relaxed); + voice.mSourceID.store(0u, std::memory_order_relaxed); + voice.mPlayState.store(ALvoice::Stopped, std::memory_order_release); + }; + std::for_each(ctx->Voices->begin(), + ctx->Voices->begin() + ctx->VoiceCount.load(std::memory_order_acquire), + stop_voice); + } +} diff --git a/alc/alu.h b/alc/alu.h new file mode 100644 index 00000000..9acf904a --- /dev/null +++ b/alc/alu.h @@ -0,0 +1,466 @@ +#ifndef _ALU_H_ +#define _ALU_H_ + +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" + +#include "alBuffer.h" +#include "alcmain.h" +#include "almalloc.h" +#include "alspan.h" +#include "ambidefs.h" +#include "filters/biquad.h" +#include "filters/nfc.h" +#include "filters/splitter.h" +#include "hrtf.h" +#include "logging.h" + +struct ALbufferlistitem; +struct ALeffectslot; +struct BSincTable; + + +enum class DistanceModel; + +#define MAX_PITCH 255 +#define MAX_SENDS 16 + + +#define DITHER_RNG_SEED 22222 + + +enum SpatializeMode { + SpatializeOff = AL_FALSE, + SpatializeOn = AL_TRUE, + SpatializeAuto = AL_AUTO_SOFT +}; + +enum Resampler { + PointResampler, + LinearResampler, + FIR4Resampler, + BSinc12Resampler, + BSinc24Resampler, + + ResamplerMax = BSinc24Resampler +}; +extern Resampler ResamplerDefault; + +/* The number of distinct scale and phase intervals within the bsinc filter + * table. + */ +#define BSINC_SCALE_BITS 4 +#define BSINC_SCALE_COUNT (1< *Coeffs; + ALsizei Delay[2]; + ALfloat Gain; + ALfloat GainStep; +}; + + +struct DirectParams { + BiquadFilter LowPass; + BiquadFilter HighPass; + + NfcFilter NFCtrlFilter; + + struct { + HrtfFilter Old; + HrtfFilter Target; + HrtfState State; + } Hrtf; + + struct { + ALfloat Current[MAX_OUTPUT_CHANNELS]; + ALfloat Target[MAX_OUTPUT_CHANNELS]; + } Gains; +}; + +struct SendParams { + BiquadFilter LowPass; + BiquadFilter HighPass; + + struct { + ALfloat Current[MAX_OUTPUT_CHANNELS]; + ALfloat Target[MAX_OUTPUT_CHANNELS]; + } Gains; +}; + + +struct ALvoicePropsBase { + ALfloat Pitch; + ALfloat Gain; + ALfloat OuterGain; + ALfloat MinGain; + ALfloat MaxGain; + ALfloat InnerAngle; + ALfloat OuterAngle; + ALfloat RefDistance; + ALfloat MaxDistance; + ALfloat RolloffFactor; + std::array Position; + std::array Velocity; + std::array Direction; + std::array OrientAt; + std::array OrientUp; + ALboolean HeadRelative; + DistanceModel mDistanceModel; + Resampler mResampler; + ALboolean DirectChannels; + SpatializeMode mSpatializeMode; + + ALboolean DryGainHFAuto; + ALboolean WetGainAuto; + ALboolean WetGainHFAuto; + ALfloat OuterGainHF; + + ALfloat AirAbsorptionFactor; + ALfloat RoomRolloffFactor; + ALfloat DopplerFactor; + + std::array StereoPan; + + ALfloat Radius; + + /** Direct filter and auxiliary send info. */ + struct { + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; + } Direct; + struct SendData { + ALeffectslot *Slot; + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; + } Send[MAX_SENDS]; +}; + +struct ALvoiceProps : public ALvoicePropsBase { + std::atomic next{nullptr}; + + DEF_NEWDEL(ALvoiceProps) +}; + +#define VOICE_IS_STATIC (1u<<0) +#define VOICE_IS_FADING (1u<<1) /* Fading sources use gain stepping for smooth transitions. */ +#define VOICE_IS_AMBISONIC (1u<<2) /* Voice needs HF scaling for ambisonic upsampling. */ +#define VOICE_HAS_HRTF (1u<<3) +#define VOICE_HAS_NFC (1u<<4) + +struct ALvoice { + enum State { + Stopped = 0, + Playing = 1, + Stopping = 2 + }; + + std::atomic mUpdate{nullptr}; + + std::atomic mSourceID{0u}; + std::atomic mPlayState{Stopped}; + + ALvoicePropsBase mProps; + + /** + * Source offset in samples, relative to the currently playing buffer, NOT + * the whole queue. + */ + std::atomic mPosition; + /** Fractional (fixed-point) offset to the next sample. */ + std::atomic mPositionFrac; + + /* Current buffer queue item being played. */ + std::atomic mCurrentBuffer; + + /* Buffer queue item to loop to at end of queue (will be NULL for non- + * looping voices). + */ + std::atomic mLoopBuffer; + + /* Properties for the attached buffer(s). */ + FmtChannels mFmtChannels; + ALuint mFrequency; + ALsizei mNumChannels; + ALsizei mSampleSize; + + /** Current target parameters used for mixing. */ + ALint mStep; + + ResamplerFunc mResampler; + + InterpState mResampleState; + + ALuint mFlags; + + struct DirectData { + int FilterType; + al::span Buffer; + }; + DirectData mDirect; + + struct SendData { + int FilterType; + al::span Buffer; + }; + std::array mSend; + + struct ChannelData { + alignas(16) std::array mPrevSamples; + + ALfloat mAmbiScale; + BandSplitter mAmbiSplitter; + + DirectParams mDryParams; + std::array mWetParams; + }; + std::array mChans; + + ALvoice() = default; + ALvoice(const ALvoice&) = delete; + ~ALvoice() { delete mUpdate.exchange(nullptr, std::memory_order_acq_rel); } + ALvoice& operator=(const ALvoice&) = delete; + ALvoice& operator=(ALvoice&& rhs) noexcept + { + ALvoiceProps *old_update{mUpdate.load(std::memory_order_relaxed)}; + mUpdate.store(rhs.mUpdate.exchange(old_update, std::memory_order_relaxed), + std::memory_order_relaxed); + + mSourceID.store(rhs.mSourceID.load(std::memory_order_relaxed), std::memory_order_relaxed); + mPlayState.store(rhs.mPlayState.load(std::memory_order_relaxed), + std::memory_order_relaxed); + + mProps = rhs.mProps; + + mPosition.store(rhs.mPosition.load(std::memory_order_relaxed), std::memory_order_relaxed); + mPositionFrac.store(rhs.mPositionFrac.load(std::memory_order_relaxed), + std::memory_order_relaxed); + + mCurrentBuffer.store(rhs.mCurrentBuffer.load(std::memory_order_relaxed), + std::memory_order_relaxed); + mLoopBuffer.store(rhs.mLoopBuffer.load(std::memory_order_relaxed), + std::memory_order_relaxed); + + mFmtChannels = rhs.mFmtChannels; + mFrequency = rhs.mFrequency; + mNumChannels = rhs.mNumChannels; + mSampleSize = rhs.mSampleSize; + + mStep = rhs.mStep; + mResampler = rhs.mResampler; + + mResampleState = rhs.mResampleState; + + mFlags = rhs.mFlags; + + mDirect = rhs.mDirect; + mSend = rhs.mSend; + mChans = rhs.mChans; + + return *this; + } +}; + + +using MixerFunc = void(*)(const ALfloat *data, const al::span OutBuffer, + ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, + const ALsizei BufferSize); +using RowMixerFunc = void(*)(FloatBufferLine &OutBuffer, const ALfloat *gains, + const al::span InSamples, const ALsizei InPos, + const ALsizei BufferSize); +using HrtfMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, + MixHrtfFilter *hrtfparams, const ALsizei BufferSize); +using HrtfMixerBlendFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, + const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize); +using HrtfDirectMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, + const ALsizei BufferSize); + + +#define GAIN_MIX_MAX (1000.0f) /* +60dB */ + +#define GAIN_SILENCE_THRESHOLD (0.00001f) /* -100dB */ + +#define SPEEDOFSOUNDMETRESPERSEC (343.3f) +#define AIRABSORBGAINHF (0.99426f) /* -0.05dB */ + +/* Target gain for the reverb decay feedback reaching the decay time. */ +#define REVERB_DECAY_GAIN (0.001f) /* -60 dB */ + +#define FRACTIONBITS (12) +#define FRACTIONONE (1< GetAmbiIdentityRow(size_t i) noexcept +{ + std::array ret{}; + ret[i] = 1.0f; + return ret; +} + + +void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCcontext *Context, const ALsizei SamplesToDo); + +void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples); +/* Caller must lock the device state, and the mixer must not be running. */ +void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) DECL_FORMAT(printf, 2, 3); + +extern MixerFunc MixSamples; +extern RowMixerFunc MixRowSamples; + +extern const ALfloat ConeScale; +extern const ALfloat ZScale; +extern const ALboolean OverrideReverbSpeedOfSound; + +#endif diff --git a/alc/ambdec.cpp b/alc/ambdec.cpp new file mode 100644 index 00000000..0991cfc5 --- /dev/null +++ b/alc/ambdec.cpp @@ -0,0 +1,436 @@ + +#include "config.h" + +#include "ambdec.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "logging.h" +#include "compat.h" + + +namespace { + +template +constexpr inline std::size_t size(const T(&)[N]) noexcept +{ return N; } + +int readline(std::istream &f, std::string &output) +{ + while(f.good() && f.peek() == '\n') + f.ignore(); + + return std::getline(f, output) && !output.empty(); +} + +bool read_clipped_line(std::istream &f, std::string &buffer) +{ + while(readline(f, buffer)) + { + std::size_t pos{0}; + while(pos < buffer.length() && std::isspace(buffer[pos])) + pos++; + buffer.erase(0, pos); + + std::size_t cmtpos{buffer.find_first_of('#')}; + if(cmtpos < buffer.length()) + buffer.resize(cmtpos); + while(!buffer.empty() && std::isspace(buffer.back())) + buffer.pop_back(); + + if(!buffer.empty()) + return true; + } + return false; +} + + +std::string read_word(std::istream &f) +{ + std::string ret; + f >> ret; + return ret; +} + +bool is_at_end(const std::string &buffer, std::size_t endpos) +{ + while(endpos < buffer.length() && std::isspace(buffer[endpos])) + ++endpos; + return !(endpos < buffer.length()); +} + + +bool load_ambdec_speakers(al::vector &spkrs, const std::size_t num_speakers, std::istream &f, std::string &buffer) +{ + while(spkrs.size() < num_speakers) + { + std::istringstream istr{buffer}; + + std::string cmd{read_word(istr)}; + if(cmd.empty()) + { + if(!read_clipped_line(f, buffer)) + { + ERR("Unexpected end of file\n"); + return false; + } + continue; + } + + if(cmd == "add_spkr") + { + spkrs.emplace_back(); + AmbDecConf::SpeakerConf &spkr = spkrs.back(); + const size_t spkr_num{spkrs.size()}; + + istr >> spkr.Name; + if(istr.fail()) WARN("Name not specified for speaker %zu\n", spkr_num); + istr >> spkr.Distance; + if(istr.fail()) WARN("Distance not specified for speaker %zu\n", spkr_num); + istr >> spkr.Azimuth; + if(istr.fail()) WARN("Azimuth not specified for speaker %zu\n", spkr_num); + istr >> spkr.Elevation; + if(istr.fail()) WARN("Elevation not specified for speaker %zu\n", spkr_num); + istr >> spkr.Connection; + if(istr.fail()) TRACE("Connection not specified for speaker %zu\n", spkr_num); + } + else + { + ERR("Unexpected speakers command: %s\n", cmd.c_str()); + return false; + } + + istr.clear(); + const auto endpos = static_cast(istr.tellg()); + if(!is_at_end(buffer, endpos)) + { + ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); + return false; + } + buffer.clear(); + } + + return true; +} + +bool load_ambdec_matrix(float (&gains)[MAX_AMBI_ORDER+1], al::vector &matrix, const std::size_t maxrow, std::istream &f, std::string &buffer) +{ + bool gotgains{false}; + std::size_t cur{0u}; + while(cur < maxrow) + { + std::istringstream istr{buffer}; + + std::string cmd{read_word(istr)}; + if(cmd.empty()) + { + if(!read_clipped_line(f, buffer)) + { + ERR("Unexpected end of file\n"); + return false; + } + continue; + } + + if(cmd == "order_gain") + { + std::size_t curgain{0u}; + float value; + while(istr.good()) + { + istr >> value; + if(istr.fail()) break; + if(!istr.eof() && !std::isspace(istr.peek())) + { + ERR("Extra junk on gain %zu: %s\n", curgain+1, + buffer.c_str()+static_cast(istr.tellg())); + return false; + } + if(curgain < size(gains)) + gains[curgain++] = value; + } + std::fill(std::begin(gains)+curgain, std::end(gains), 0.0f); + gotgains = true; + } + else if(cmd == "add_row") + { + matrix.emplace_back(); + AmbDecConf::CoeffArray &mtxrow = matrix.back(); + std::size_t curidx{0u}; + float value{}; + while(istr.good()) + { + istr >> value; + if(istr.fail()) break; + if(!istr.eof() && !std::isspace(istr.peek())) + { + ERR("Extra junk on matrix element %zux%zu: %s\n", curidx, + matrix.size(), buffer.c_str()+static_cast(istr.tellg())); + matrix.pop_back(); + return false; + } + if(curidx < mtxrow.size()) + mtxrow[curidx++] = value; + } + std::fill(mtxrow.begin()+curidx, mtxrow.end(), 0.0f); + cur++; + } + else + { + ERR("Unexpected matrix command: %s\n", cmd.c_str()); + return false; + } + + istr.clear(); + const auto endpos = static_cast(istr.tellg()); + if(!is_at_end(buffer, endpos)) + { + ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); + return false; + } + buffer.clear(); + } + + if(!gotgains) + { + ERR("Matrix order_gain not specified\n"); + return false; + } + + return true; +} + +} // namespace + +int AmbDecConf::load(const char *fname) noexcept +{ + al::ifstream f{fname}; + if(!f.is_open()) + { + ERR("Failed to open: %s\n", fname); + return 0; + } + + std::size_t num_speakers{0u}; + std::string buffer; + while(read_clipped_line(f, buffer)) + { + std::istringstream istr{buffer}; + + std::string command{read_word(istr)}; + if(command.empty()) + { + ERR("Malformed line: %s\n", buffer.c_str()); + return 0; + } + + if(command == "/description") + istr >> Description; + else if(command == "/version") + { + istr >> Version; + if(!istr.eof() && !std::isspace(istr.peek())) + { + ERR("Extra junk after version: %s\n", + buffer.c_str()+static_cast(istr.tellg())); + return 0; + } + if(Version != 3) + { + ERR("Unsupported version: %u\n", Version); + return 0; + } + } + else if(command == "/dec/chan_mask") + { + istr >> std::hex >> ChanMask >> std::dec; + if(!istr.eof() && !std::isspace(istr.peek())) + { + ERR("Extra junk after mask: %s\n", + buffer.c_str()+static_cast(istr.tellg())); + return 0; + } + } + else if(command == "/dec/freq_bands") + { + istr >> FreqBands; + if(!istr.eof() && !std::isspace(istr.peek())) + { + ERR("Extra junk after freq_bands: %s\n", + buffer.c_str()+static_cast(istr.tellg())); + return 0; + } + if(FreqBands != 1 && FreqBands != 2) + { + ERR("Invalid freq_bands value: %u\n", FreqBands); + return 0; + } + } + else if(command == "/dec/speakers") + { + istr >> num_speakers; + if(!istr.eof() && !std::isspace(istr.peek())) + { + ERR("Extra junk after speakers: %s\n", + buffer.c_str()+static_cast(istr.tellg())); + return 0; + } + Speakers.reserve(num_speakers); + LFMatrix.reserve(num_speakers); + HFMatrix.reserve(num_speakers); + } + else if(command == "/dec/coeff_scale") + { + std::string scale = read_word(istr); + if(scale == "n3d") CoeffScale = AmbDecScale::N3D; + else if(scale == "sn3d") CoeffScale = AmbDecScale::SN3D; + else if(scale == "fuma") CoeffScale = AmbDecScale::FuMa; + else + { + ERR("Unsupported coeff scale: %s\n", scale.c_str()); + return 0; + } + } + else if(command == "/opt/xover_freq") + { + istr >> XOverFreq; + if(!istr.eof() && !std::isspace(istr.peek())) + { + ERR("Extra junk after xover_freq: %s\n", + buffer.c_str()+static_cast(istr.tellg())); + return 0; + } + } + else if(command == "/opt/xover_ratio") + { + istr >> XOverRatio; + if(!istr.eof() && !std::isspace(istr.peek())) + { + ERR("Extra junk after xover_ratio: %s\n", + buffer.c_str()+static_cast(istr.tellg())); + return 0; + } + } + else if(command == "/opt/input_scale" || command == "/opt/nfeff_comp" || + command == "/opt/delay_comp" || command == "/opt/level_comp") + { + /* Unused */ + read_word(istr); + } + else if(command == "/speakers/{") + { + const auto endpos = static_cast(istr.tellg()); + if(!is_at_end(buffer, endpos)) + { + ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); + return 0; + } + buffer.clear(); + + if(!load_ambdec_speakers(Speakers, num_speakers, f, buffer)) + return 0; + + if(!read_clipped_line(f, buffer)) + { + ERR("Unexpected end of file\n"); + return 0; + } + std::istringstream istr2{buffer}; + std::string endmark{read_word(istr2)}; + if(endmark != "/}") + { + ERR("Expected /} after speaker definitions, got %s\n", endmark.c_str()); + return 0; + } + istr.swap(istr2); + } + else if(command == "/lfmatrix/{" || command == "/hfmatrix/{" || command == "/matrix/{") + { + const auto endpos = static_cast(istr.tellg()); + if(!is_at_end(buffer, endpos)) + { + ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); + return 0; + } + buffer.clear(); + + if(FreqBands == 1) + { + if(command != "/matrix/{") + { + ERR("Unexpected \"%s\" type for a single-band decoder\n", command.c_str()); + return 0; + } + if(!load_ambdec_matrix(HFOrderGain, HFMatrix, num_speakers, f, buffer)) + return 0; + } + else + { + if(command == "/lfmatrix/{") + { + if(!load_ambdec_matrix(LFOrderGain, LFMatrix, num_speakers, f, buffer)) + return 0; + } + else if(command == "/hfmatrix/{") + { + if(!load_ambdec_matrix(HFOrderGain, HFMatrix, num_speakers, f, buffer)) + return 0; + } + else + { + ERR("Unexpected \"%s\" type for a dual-band decoder\n", command.c_str()); + return 0; + } + } + + if(!read_clipped_line(f, buffer)) + { + ERR("Unexpected end of file\n"); + return 0; + } + std::istringstream istr2{buffer}; + std::string endmark{read_word(istr2)}; + if(endmark != "/}") + { + ERR("Expected /} after matrix definitions, got %s\n", endmark.c_str()); + return 0; + } + istr.swap(istr2); + } + else if(command == "/end") + { + const auto endpos = static_cast(istr.tellg()); + if(!is_at_end(buffer, endpos)) + { + ERR("Unexpected junk on end: %s\n", buffer.c_str()+endpos); + return 0; + } + + return 1; + } + else + { + ERR("Unexpected command: %s\n", command.c_str()); + return 0; + } + + istr.clear(); + const auto endpos = static_cast(istr.tellg()); + if(!is_at_end(buffer, endpos)) + { + ERR("Unexpected junk on line: %s\n", buffer.c_str()+endpos); + return 0; + } + buffer.clear(); + } + ERR("Unexpected end of file\n"); + + return 0; +} diff --git a/alc/ambdec.h b/alc/ambdec.h new file mode 100644 index 00000000..ff7b71ee --- /dev/null +++ b/alc/ambdec.h @@ -0,0 +1,48 @@ +#ifndef AMBDEC_H +#define AMBDEC_H + +#include +#include + +#include "ambidefs.h" +#include "vector.h" + +/* Helpers to read .ambdec configuration files. */ + +enum class AmbDecScale { + N3D, + SN3D, + FuMa, +}; +struct AmbDecConf { + std::string Description; + int Version{0}; /* Must be 3 */ + + unsigned int ChanMask{0u}; + unsigned int FreqBands{0u}; /* Must be 1 or 2 */ + AmbDecScale CoeffScale{}; + + float XOverFreq{0.0f}; + float XOverRatio{0.0f}; + + struct SpeakerConf { + std::string Name; + float Distance{0.0f}; + float Azimuth{0.0f}; + float Elevation{0.0f}; + std::string Connection; + }; + al::vector Speakers; + + using CoeffArray = std::array; + /* Unused when FreqBands == 1 */ + float LFOrderGain[MAX_AMBI_ORDER+1]{}; + al::vector LFMatrix; + + float HFOrderGain[MAX_AMBI_ORDER+1]{}; + al::vector HFMatrix; + + int load(const char *fname) noexcept; +}; + +#endif /* AMBDEC_H */ diff --git a/alc/ambidefs.h b/alc/ambidefs.h new file mode 100644 index 00000000..17a9815b --- /dev/null +++ b/alc/ambidefs.h @@ -0,0 +1,119 @@ +#ifndef AMBIDEFS_H +#define AMBIDEFS_H + +#include + +/* The maximum number of Ambisonics channels. For a given order (o), the size + * needed will be (o+1)**2, thus zero-order has 1, first-order has 4, second- + * order has 9, third-order has 16, and fourth-order has 25. + */ +#define MAX_AMBI_ORDER 3 +constexpr inline size_t AmbiChannelsFromOrder(size_t order) noexcept +{ return (order+1) * (order+1); } +#define MAX_AMBI_CHANNELS AmbiChannelsFromOrder(MAX_AMBI_ORDER) + +/* A bitmask of ambisonic channels for 0 to 4th order. This only specifies up + * to 4th order, which is the highest order a 32-bit mask value can specify (a + * 64-bit mask could handle up to 7th order). + */ +#define AMBI_0ORDER_MASK 0x00000001 +#define AMBI_1ORDER_MASK 0x0000000f +#define AMBI_2ORDER_MASK 0x000001ff +#define AMBI_3ORDER_MASK 0x0000ffff +#define AMBI_4ORDER_MASK 0x01ffffff + +/* A bitmask of ambisonic channels with height information. If none of these + * channels are used/needed, there's no height (e.g. with most surround sound + * speaker setups). This is ACN ordering, with bit 0 being ACN 0, etc. + */ +#define AMBI_PERIPHONIC_MASK (0xfe7ce4) + +/* The maximum number of ambisonic channels for 2D (non-periphonic) + * representation. This is 2 per each order above zero-order, plus 1 for zero- + * order. Or simply, o*2 + 1. + */ +constexpr inline size_t Ambi2DChannelsFromOrder(size_t order) noexcept +{ return order*2 + 1; } +#define MAX_AMBI2D_CHANNELS Ambi2DChannelsFromOrder(MAX_AMBI_ORDER) + + +/* NOTE: These are scale factors as applied to Ambisonics content. Decoder + * coefficients should be divided by these values to get proper scalings. + */ +struct AmbiScale { + static constexpr std::array FromN3D{{ + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f + }}; + static constexpr std::array FromSN3D{{ + 1.000000000f, /* ACN 0, sqrt(1) */ + 1.732050808f, /* ACN 1, sqrt(3) */ + 1.732050808f, /* ACN 2, sqrt(3) */ + 1.732050808f, /* ACN 3, sqrt(3) */ + 2.236067978f, /* ACN 4, sqrt(5) */ + 2.236067978f, /* ACN 5, sqrt(5) */ + 2.236067978f, /* ACN 6, sqrt(5) */ + 2.236067978f, /* ACN 7, sqrt(5) */ + 2.236067978f, /* ACN 8, sqrt(5) */ + 2.645751311f, /* ACN 9, sqrt(7) */ + 2.645751311f, /* ACN 10, sqrt(7) */ + 2.645751311f, /* ACN 11, sqrt(7) */ + 2.645751311f, /* ACN 12, sqrt(7) */ + 2.645751311f, /* ACN 13, sqrt(7) */ + 2.645751311f, /* ACN 14, sqrt(7) */ + 2.645751311f, /* ACN 15, sqrt(7) */ + }}; + static constexpr std::array FromFuMa{{ + 1.414213562f, /* ACN 0 (W), sqrt(2) */ + 1.732050808f, /* ACN 1 (Y), sqrt(3) */ + 1.732050808f, /* ACN 2 (Z), sqrt(3) */ + 1.732050808f, /* ACN 3 (X), sqrt(3) */ + 1.936491673f, /* ACN 4 (V), sqrt(15)/2 */ + 1.936491673f, /* ACN 5 (T), sqrt(15)/2 */ + 2.236067978f, /* ACN 6 (R), sqrt(5) */ + 1.936491673f, /* ACN 7 (S), sqrt(15)/2 */ + 1.936491673f, /* ACN 8 (U), sqrt(15)/2 */ + 2.091650066f, /* ACN 9 (Q), sqrt(35/8) */ + 1.972026594f, /* ACN 10 (O), sqrt(35)/3 */ + 2.231093404f, /* ACN 11 (M), sqrt(224/45) */ + 2.645751311f, /* ACN 12 (K), sqrt(7) */ + 2.231093404f, /* ACN 13 (L), sqrt(224/45) */ + 1.972026594f, /* ACN 14 (N), sqrt(35)/3 */ + 2.091650066f, /* ACN 15 (P), sqrt(35/8) */ + }}; +}; + +struct AmbiIndex { + static constexpr std::array FromFuMa{{ + 0, /* W */ + 3, /* X */ + 1, /* Y */ + 2, /* Z */ + 6, /* R */ + 7, /* S */ + 5, /* T */ + 8, /* U */ + 4, /* V */ + 12, /* K */ + 13, /* L */ + 11, /* M */ + 14, /* N */ + 10, /* O */ + 15, /* P */ + 9, /* Q */ + }}; + static constexpr std::array FromACN{{ + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 + }}; + + static constexpr std::array From2D{{ + 0, 1,3, 4,8, 9,15 + }}; + static constexpr std::array From3D{{ + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 + }}; +}; + +#endif /* AMBIDEFS_H */ diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp new file mode 100644 index 00000000..c133df68 --- /dev/null +++ b/alc/backends/alsa.cpp @@ -0,0 +1,1288 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "backends/alsa.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" + +#include "albyte.h" +#include "alcmain.h" +#include "alconfig.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "aloptional.h" +#include "alu.h" +#include "compat.h" +#include "logging.h" +#include "ringbuffer.h" +#include "threads.h" +#include "vector.h" + +#include + + +namespace { + +constexpr ALCchar alsaDevice[] = "ALSA Default"; + + +#ifdef HAVE_DYNLOAD +#define ALSA_FUNCS(MAGIC) \ + MAGIC(snd_strerror); \ + MAGIC(snd_pcm_open); \ + MAGIC(snd_pcm_close); \ + MAGIC(snd_pcm_nonblock); \ + MAGIC(snd_pcm_frames_to_bytes); \ + MAGIC(snd_pcm_bytes_to_frames); \ + MAGIC(snd_pcm_hw_params_malloc); \ + MAGIC(snd_pcm_hw_params_free); \ + MAGIC(snd_pcm_hw_params_any); \ + MAGIC(snd_pcm_hw_params_current); \ + MAGIC(snd_pcm_hw_params_set_access); \ + MAGIC(snd_pcm_hw_params_set_format); \ + MAGIC(snd_pcm_hw_params_set_channels); \ + MAGIC(snd_pcm_hw_params_set_periods_near); \ + MAGIC(snd_pcm_hw_params_set_rate_near); \ + MAGIC(snd_pcm_hw_params_set_rate); \ + MAGIC(snd_pcm_hw_params_set_rate_resample); \ + MAGIC(snd_pcm_hw_params_set_buffer_time_near); \ + MAGIC(snd_pcm_hw_params_set_period_time_near); \ + MAGIC(snd_pcm_hw_params_set_buffer_size_near); \ + MAGIC(snd_pcm_hw_params_set_period_size_near); \ + MAGIC(snd_pcm_hw_params_set_buffer_size_min); \ + MAGIC(snd_pcm_hw_params_get_buffer_time_min); \ + MAGIC(snd_pcm_hw_params_get_buffer_time_max); \ + MAGIC(snd_pcm_hw_params_get_period_time_min); \ + MAGIC(snd_pcm_hw_params_get_period_time_max); \ + MAGIC(snd_pcm_hw_params_get_buffer_size); \ + MAGIC(snd_pcm_hw_params_get_period_size); \ + MAGIC(snd_pcm_hw_params_get_access); \ + MAGIC(snd_pcm_hw_params_get_periods); \ + MAGIC(snd_pcm_hw_params_test_format); \ + MAGIC(snd_pcm_hw_params_test_channels); \ + MAGIC(snd_pcm_hw_params); \ + MAGIC(snd_pcm_sw_params_malloc); \ + MAGIC(snd_pcm_sw_params_current); \ + MAGIC(snd_pcm_sw_params_set_avail_min); \ + MAGIC(snd_pcm_sw_params_set_stop_threshold); \ + MAGIC(snd_pcm_sw_params); \ + MAGIC(snd_pcm_sw_params_free); \ + MAGIC(snd_pcm_prepare); \ + MAGIC(snd_pcm_start); \ + MAGIC(snd_pcm_resume); \ + MAGIC(snd_pcm_reset); \ + MAGIC(snd_pcm_wait); \ + MAGIC(snd_pcm_delay); \ + MAGIC(snd_pcm_state); \ + MAGIC(snd_pcm_avail_update); \ + MAGIC(snd_pcm_areas_silence); \ + MAGIC(snd_pcm_mmap_begin); \ + MAGIC(snd_pcm_mmap_commit); \ + MAGIC(snd_pcm_readi); \ + MAGIC(snd_pcm_writei); \ + MAGIC(snd_pcm_drain); \ + MAGIC(snd_pcm_drop); \ + MAGIC(snd_pcm_recover); \ + MAGIC(snd_pcm_info_malloc); \ + MAGIC(snd_pcm_info_free); \ + MAGIC(snd_pcm_info_set_device); \ + MAGIC(snd_pcm_info_set_subdevice); \ + MAGIC(snd_pcm_info_set_stream); \ + MAGIC(snd_pcm_info_get_name); \ + MAGIC(snd_ctl_pcm_next_device); \ + MAGIC(snd_ctl_pcm_info); \ + MAGIC(snd_ctl_open); \ + MAGIC(snd_ctl_close); \ + MAGIC(snd_ctl_card_info_malloc); \ + MAGIC(snd_ctl_card_info_free); \ + MAGIC(snd_ctl_card_info); \ + MAGIC(snd_ctl_card_info_get_name); \ + MAGIC(snd_ctl_card_info_get_id); \ + MAGIC(snd_card_next); \ + MAGIC(snd_config_update_free_global) + +static void *alsa_handle; +#define MAKE_FUNC(f) decltype(f) * p##f +ALSA_FUNCS(MAKE_FUNC); +#undef MAKE_FUNC + +#ifndef IN_IDE_PARSER +#define snd_strerror psnd_strerror +#define snd_pcm_open psnd_pcm_open +#define snd_pcm_close psnd_pcm_close +#define snd_pcm_nonblock psnd_pcm_nonblock +#define snd_pcm_frames_to_bytes psnd_pcm_frames_to_bytes +#define snd_pcm_bytes_to_frames psnd_pcm_bytes_to_frames +#define snd_pcm_hw_params_malloc psnd_pcm_hw_params_malloc +#define snd_pcm_hw_params_free psnd_pcm_hw_params_free +#define snd_pcm_hw_params_any psnd_pcm_hw_params_any +#define snd_pcm_hw_params_current psnd_pcm_hw_params_current +#define snd_pcm_hw_params_set_access psnd_pcm_hw_params_set_access +#define snd_pcm_hw_params_set_format psnd_pcm_hw_params_set_format +#define snd_pcm_hw_params_set_channels psnd_pcm_hw_params_set_channels +#define snd_pcm_hw_params_set_periods_near psnd_pcm_hw_params_set_periods_near +#define snd_pcm_hw_params_set_rate_near psnd_pcm_hw_params_set_rate_near +#define snd_pcm_hw_params_set_rate psnd_pcm_hw_params_set_rate +#define snd_pcm_hw_params_set_rate_resample psnd_pcm_hw_params_set_rate_resample +#define snd_pcm_hw_params_set_buffer_time_near psnd_pcm_hw_params_set_buffer_time_near +#define snd_pcm_hw_params_set_period_time_near psnd_pcm_hw_params_set_period_time_near +#define snd_pcm_hw_params_set_buffer_size_near psnd_pcm_hw_params_set_buffer_size_near +#define snd_pcm_hw_params_set_period_size_near psnd_pcm_hw_params_set_period_size_near +#define snd_pcm_hw_params_set_buffer_size_min psnd_pcm_hw_params_set_buffer_size_min +#define snd_pcm_hw_params_get_buffer_time_min psnd_pcm_hw_params_get_buffer_time_min +#define snd_pcm_hw_params_get_buffer_time_max psnd_pcm_hw_params_get_buffer_time_max +#define snd_pcm_hw_params_get_period_time_min psnd_pcm_hw_params_get_period_time_min +#define snd_pcm_hw_params_get_period_time_max psnd_pcm_hw_params_get_period_time_max +#define snd_pcm_hw_params_get_buffer_size psnd_pcm_hw_params_get_buffer_size +#define snd_pcm_hw_params_get_period_size psnd_pcm_hw_params_get_period_size +#define snd_pcm_hw_params_get_access psnd_pcm_hw_params_get_access +#define snd_pcm_hw_params_get_periods psnd_pcm_hw_params_get_periods +#define snd_pcm_hw_params_test_format psnd_pcm_hw_params_test_format +#define snd_pcm_hw_params_test_channels psnd_pcm_hw_params_test_channels +#define snd_pcm_hw_params psnd_pcm_hw_params +#define snd_pcm_sw_params_malloc psnd_pcm_sw_params_malloc +#define snd_pcm_sw_params_current psnd_pcm_sw_params_current +#define snd_pcm_sw_params_set_avail_min psnd_pcm_sw_params_set_avail_min +#define snd_pcm_sw_params_set_stop_threshold psnd_pcm_sw_params_set_stop_threshold +#define snd_pcm_sw_params psnd_pcm_sw_params +#define snd_pcm_sw_params_free psnd_pcm_sw_params_free +#define snd_pcm_prepare psnd_pcm_prepare +#define snd_pcm_start psnd_pcm_start +#define snd_pcm_resume psnd_pcm_resume +#define snd_pcm_reset psnd_pcm_reset +#define snd_pcm_wait psnd_pcm_wait +#define snd_pcm_delay psnd_pcm_delay +#define snd_pcm_state psnd_pcm_state +#define snd_pcm_avail_update psnd_pcm_avail_update +#define snd_pcm_areas_silence psnd_pcm_areas_silence +#define snd_pcm_mmap_begin psnd_pcm_mmap_begin +#define snd_pcm_mmap_commit psnd_pcm_mmap_commit +#define snd_pcm_readi psnd_pcm_readi +#define snd_pcm_writei psnd_pcm_writei +#define snd_pcm_drain psnd_pcm_drain +#define snd_pcm_drop psnd_pcm_drop +#define snd_pcm_recover psnd_pcm_recover +#define snd_pcm_info_malloc psnd_pcm_info_malloc +#define snd_pcm_info_free psnd_pcm_info_free +#define snd_pcm_info_set_device psnd_pcm_info_set_device +#define snd_pcm_info_set_subdevice psnd_pcm_info_set_subdevice +#define snd_pcm_info_set_stream psnd_pcm_info_set_stream +#define snd_pcm_info_get_name psnd_pcm_info_get_name +#define snd_ctl_pcm_next_device psnd_ctl_pcm_next_device +#define snd_ctl_pcm_info psnd_ctl_pcm_info +#define snd_ctl_open psnd_ctl_open +#define snd_ctl_close psnd_ctl_close +#define snd_ctl_card_info_malloc psnd_ctl_card_info_malloc +#define snd_ctl_card_info_free psnd_ctl_card_info_free +#define snd_ctl_card_info psnd_ctl_card_info +#define snd_ctl_card_info_get_name psnd_ctl_card_info_get_name +#define snd_ctl_card_info_get_id psnd_ctl_card_info_get_id +#define snd_card_next psnd_card_next +#define snd_config_update_free_global psnd_config_update_free_global +#endif +#endif + + +struct DevMap { + std::string name; + std::string device_name; +}; + +al::vector PlaybackDevices; +al::vector CaptureDevices; + + +const char *prefix_name(snd_pcm_stream_t stream) +{ + assert(stream == SND_PCM_STREAM_PLAYBACK || stream == SND_PCM_STREAM_CAPTURE); + return (stream==SND_PCM_STREAM_PLAYBACK) ? "device-prefix" : "capture-prefix"; +} + +al::vector probe_devices(snd_pcm_stream_t stream) +{ + al::vector devlist; + + snd_ctl_card_info_t *info; + snd_ctl_card_info_malloc(&info); + snd_pcm_info_t *pcminfo; + snd_pcm_info_malloc(&pcminfo); + + devlist.emplace_back(DevMap{alsaDevice, + GetConfigValue(nullptr, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ? "device" : "capture", + "default")}); + + if(stream == SND_PCM_STREAM_PLAYBACK) + { + const char *customdevs; + const char *next{GetConfigValue(nullptr, "alsa", "custom-devices", "")}; + while((customdevs=next) != nullptr && customdevs[0]) + { + next = strchr(customdevs, ';'); + const char *sep{strchr(customdevs, '=')}; + if(!sep) + { + std::string spec{next ? std::string(customdevs, next++) : std::string(customdevs)}; + ERR("Invalid ALSA device specification \"%s\"\n", spec.c_str()); + continue; + } + + const char *oldsep{sep++}; + devlist.emplace_back(DevMap{std::string(customdevs, oldsep), + next ? std::string(sep, next++) : std::string(sep)}); + const auto &entry = devlist.back(); + TRACE("Got device \"%s\", \"%s\"\n", entry.name.c_str(), entry.device_name.c_str()); + } + } + + const std::string main_prefix{ + ConfigValueStr(nullptr, "alsa", prefix_name(stream)).value_or("plughw:")}; + + int card{-1}; + int err{snd_card_next(&card)}; + for(;err >= 0 && card >= 0;err = snd_card_next(&card)) + { + std::string name{"hw:" + std::to_string(card)}; + + snd_ctl_t *handle; + if((err=snd_ctl_open(&handle, name.c_str(), 0)) < 0) + { + ERR("control open (hw:%d): %s\n", card, snd_strerror(err)); + continue; + } + if((err=snd_ctl_card_info(handle, info)) < 0) + { + ERR("control hardware info (hw:%d): %s\n", card, snd_strerror(err)); + snd_ctl_close(handle); + continue; + } + + const char *cardname{snd_ctl_card_info_get_name(info)}; + const char *cardid{snd_ctl_card_info_get_id(info)}; + name = prefix_name(stream); + name += '-'; + name += cardid; + const std::string card_prefix{ + ConfigValueStr(nullptr, "alsa", name.c_str()).value_or(main_prefix)}; + + int dev{-1}; + while(1) + { + if(snd_ctl_pcm_next_device(handle, &dev) < 0) + ERR("snd_ctl_pcm_next_device failed\n"); + if(dev < 0) break; + + snd_pcm_info_set_device(pcminfo, dev); + snd_pcm_info_set_subdevice(pcminfo, 0); + snd_pcm_info_set_stream(pcminfo, stream); + if((err=snd_ctl_pcm_info(handle, pcminfo)) < 0) + { + if(err != -ENOENT) + ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err)); + continue; + } + + /* "prefix-cardid-dev" */ + name = prefix_name(stream); + name += '-'; + name += cardid; + name += '-'; + name += std::to_string(dev); + const std::string device_prefix{ + ConfigValueStr(nullptr, "alsa", name.c_str()).value_or(card_prefix)}; + + /* "CardName, PcmName (CARD=cardid,DEV=dev)" */ + name = cardname; + name += ", "; + name += snd_pcm_info_get_name(pcminfo); + name += " (CARD="; + name += cardid; + name += ",DEV="; + name += std::to_string(dev); + name += ')'; + + /* "devprefixCARD=cardid,DEV=dev" */ + std::string device{device_prefix}; + device += "CARD="; + device += cardid; + device += ",DEV="; + device += std::to_string(dev); + + devlist.emplace_back(DevMap{std::move(name), std::move(device)}); + const auto &entry = devlist.back(); + TRACE("Got device \"%s\", \"%s\"\n", entry.name.c_str(), entry.device_name.c_str()); + } + snd_ctl_close(handle); + } + if(err < 0) + ERR("snd_card_next failed: %s\n", snd_strerror(err)); + + snd_pcm_info_free(pcminfo); + snd_ctl_card_info_free(info); + + return devlist; +} + + +int verify_state(snd_pcm_t *handle) +{ + snd_pcm_state_t state{snd_pcm_state(handle)}; + + int err; + switch(state) + { + case SND_PCM_STATE_OPEN: + case SND_PCM_STATE_SETUP: + case SND_PCM_STATE_PREPARED: + case SND_PCM_STATE_RUNNING: + case SND_PCM_STATE_DRAINING: + case SND_PCM_STATE_PAUSED: + /* All Okay */ + break; + + case SND_PCM_STATE_XRUN: + if((err=snd_pcm_recover(handle, -EPIPE, 1)) < 0) + return err; + break; + case SND_PCM_STATE_SUSPENDED: + if((err=snd_pcm_recover(handle, -ESTRPIPE, 1)) < 0) + return err; + break; + case SND_PCM_STATE_DISCONNECTED: + return -ENODEV; + } + + return state; +} + + +struct AlsaPlayback final : public BackendBase { + AlsaPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~AlsaPlayback() override; + + int mixerProc(); + int mixerNoMMapProc(); + + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + + ClockLatency getClockLatency() override; + + snd_pcm_t *mPcmHandle{nullptr}; + + al::vector mBuffer; + + std::atomic mKillNow{true}; + std::thread mThread; + + DEF_NEWDEL(AlsaPlayback) +}; + +AlsaPlayback::~AlsaPlayback() +{ + if(mPcmHandle) + snd_pcm_close(mPcmHandle); + mPcmHandle = nullptr; +} + + +int AlsaPlayback::mixerProc() +{ + SetRTPriority(); + althrd_setname(MIXER_THREAD_NAME); + + const snd_pcm_uframes_t update_size{mDevice->UpdateSize}; + const snd_pcm_uframes_t num_updates{mDevice->BufferSize / update_size}; + while(!mKillNow.load(std::memory_order_acquire)) + { + int state{verify_state(mPcmHandle)}; + if(state < 0) + { + ERR("Invalid state detected: %s\n", snd_strerror(state)); + aluHandleDisconnect(mDevice, "Bad state: %s", snd_strerror(state)); + break; + } + + snd_pcm_sframes_t avail{snd_pcm_avail_update(mPcmHandle)}; + if(avail < 0) + { + ERR("available update failed: %s\n", snd_strerror(avail)); + continue; + } + + if(static_cast(avail) > update_size*(num_updates+1)) + { + WARN("available samples exceeds the buffer size\n"); + snd_pcm_reset(mPcmHandle); + continue; + } + + // make sure there's frames to process + if(static_cast(avail) < update_size) + { + if(state != SND_PCM_STATE_RUNNING) + { + int err{snd_pcm_start(mPcmHandle)}; + if(err < 0) + { + ERR("start failed: %s\n", snd_strerror(err)); + continue; + } + } + if(snd_pcm_wait(mPcmHandle, 1000) == 0) + ERR("Wait timeout... buffer size too low?\n"); + continue; + } + avail -= avail%update_size; + + // it is possible that contiguous areas are smaller, thus we use a loop + lock(); + while(avail > 0) + { + snd_pcm_uframes_t frames{static_cast(avail)}; + + const snd_pcm_channel_area_t *areas{}; + snd_pcm_uframes_t offset{}; + int err{snd_pcm_mmap_begin(mPcmHandle, &areas, &offset, &frames)}; + if(err < 0) + { + ERR("mmap begin error: %s\n", snd_strerror(err)); + break; + } + + char *WritePtr{static_cast(areas->addr) + (offset * areas->step / 8)}; + aluMixData(mDevice, WritePtr, frames); + + snd_pcm_sframes_t commitres{snd_pcm_mmap_commit(mPcmHandle, offset, frames)}; + if(commitres < 0 || (commitres-frames) != 0) + { + ERR("mmap commit error: %s\n", + snd_strerror(commitres >= 0 ? -EPIPE : commitres)); + break; + } + + avail -= frames; + } + unlock(); + } + + return 0; +} + +int AlsaPlayback::mixerNoMMapProc() +{ + SetRTPriority(); + althrd_setname(MIXER_THREAD_NAME); + + const snd_pcm_uframes_t update_size{mDevice->UpdateSize}; + const snd_pcm_uframes_t buffer_size{mDevice->BufferSize}; + while(!mKillNow.load(std::memory_order_acquire)) + { + int state{verify_state(mPcmHandle)}; + if(state < 0) + { + ERR("Invalid state detected: %s\n", snd_strerror(state)); + aluHandleDisconnect(mDevice, "Bad state: %s", snd_strerror(state)); + break; + } + + snd_pcm_sframes_t avail{snd_pcm_avail_update(mPcmHandle)}; + if(avail < 0) + { + ERR("available update failed: %s\n", snd_strerror(avail)); + continue; + } + + if(static_cast(avail) > buffer_size) + { + WARN("available samples exceeds the buffer size\n"); + snd_pcm_reset(mPcmHandle); + continue; + } + + if(static_cast(avail) < update_size) + { + if(state != SND_PCM_STATE_RUNNING) + { + int err{snd_pcm_start(mPcmHandle)}; + if(err < 0) + { + ERR("start failed: %s\n", snd_strerror(err)); + continue; + } + } + if(snd_pcm_wait(mPcmHandle, 1000) == 0) + ERR("Wait timeout... buffer size too low?\n"); + continue; + } + + lock(); + char *WritePtr{mBuffer.data()}; + avail = snd_pcm_bytes_to_frames(mPcmHandle, mBuffer.size()); + aluMixData(mDevice, WritePtr, avail); + while(avail > 0) + { + snd_pcm_sframes_t ret{snd_pcm_writei(mPcmHandle, WritePtr, avail)}; + switch(ret) + { + case -EAGAIN: + continue; +#if ESTRPIPE != EPIPE + case -ESTRPIPE: +#endif + case -EPIPE: + case -EINTR: + ret = snd_pcm_recover(mPcmHandle, ret, 1); + if(ret < 0) + avail = 0; + break; + default: + if(ret >= 0) + { + WritePtr += snd_pcm_frames_to_bytes(mPcmHandle, ret); + avail -= ret; + } + break; + } + if(ret < 0) + { + ret = snd_pcm_prepare(mPcmHandle); + if(ret < 0) break; + } + } + unlock(); + } + + return 0; +} + + +ALCenum AlsaPlayback::open(const ALCchar *name) +{ + const char *driver{}; + if(name) + { + if(PlaybackDevices.empty()) + PlaybackDevices = probe_devices(SND_PCM_STREAM_PLAYBACK); + + auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + [name](const DevMap &entry) -> bool + { return entry.name == name; } + ); + if(iter == PlaybackDevices.cend()) + return ALC_INVALID_VALUE; + driver = iter->device_name.c_str(); + } + else + { + name = alsaDevice; + driver = GetConfigValue(nullptr, "alsa", "device", "default"); + } + + TRACE("Opening device \"%s\"\n", driver); + int err{snd_pcm_open(&mPcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)}; + if(err < 0) + { + ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(err)); + return ALC_OUT_OF_MEMORY; + } + + /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */ + snd_config_update_free_global(); + + mDevice->DeviceName = name; + + return ALC_NO_ERROR; +} + +ALCboolean AlsaPlayback::reset() +{ + snd_pcm_format_t format{SND_PCM_FORMAT_UNKNOWN}; + switch(mDevice->FmtType) + { + case DevFmtByte: + format = SND_PCM_FORMAT_S8; + break; + case DevFmtUByte: + format = SND_PCM_FORMAT_U8; + break; + case DevFmtShort: + format = SND_PCM_FORMAT_S16; + break; + case DevFmtUShort: + format = SND_PCM_FORMAT_U16; + break; + case DevFmtInt: + format = SND_PCM_FORMAT_S32; + break; + case DevFmtUInt: + format = SND_PCM_FORMAT_U32; + break; + case DevFmtFloat: + format = SND_PCM_FORMAT_FLOAT; + break; + } + + bool allowmmap{!!GetConfigValueBool(mDevice->DeviceName.c_str(), "alsa", "mmap", 1)}; + ALuint periodLen{static_cast(mDevice->UpdateSize * 1000000_u64 / mDevice->Frequency)}; + ALuint bufferLen{static_cast(mDevice->BufferSize * 1000000_u64 / mDevice->Frequency)}; + ALuint rate{mDevice->Frequency}; + + snd_pcm_uframes_t periodSizeInFrames{}; + snd_pcm_uframes_t bufferSizeInFrames{}; + snd_pcm_sw_params_t *sp{}; + snd_pcm_hw_params_t *hp{}; + snd_pcm_access_t access{}; + const char *funcerr{}; + int err{}; + + snd_pcm_hw_params_malloc(&hp); +#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error + CHECK(snd_pcm_hw_params_any(mPcmHandle, hp)); + /* set interleaved access */ + if(!allowmmap || snd_pcm_hw_params_set_access(mPcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) + { + /* No mmap */ + CHECK(snd_pcm_hw_params_set_access(mPcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); + } + /* test and set format (implicitly sets sample bits) */ + if(snd_pcm_hw_params_test_format(mPcmHandle, hp, format) < 0) + { + static const struct { + snd_pcm_format_t format; + DevFmtType fmttype; + } formatlist[] = { + { SND_PCM_FORMAT_FLOAT, DevFmtFloat }, + { SND_PCM_FORMAT_S32, DevFmtInt }, + { SND_PCM_FORMAT_U32, DevFmtUInt }, + { SND_PCM_FORMAT_S16, DevFmtShort }, + { SND_PCM_FORMAT_U16, DevFmtUShort }, + { SND_PCM_FORMAT_S8, DevFmtByte }, + { SND_PCM_FORMAT_U8, DevFmtUByte }, + }; + + for(const auto &fmt : formatlist) + { + format = fmt.format; + if(snd_pcm_hw_params_test_format(mPcmHandle, hp, format) >= 0) + { + mDevice->FmtType = fmt.fmttype; + break; + } + } + } + CHECK(snd_pcm_hw_params_set_format(mPcmHandle, hp, format)); + /* test and set channels (implicitly sets frame bits) */ + if(snd_pcm_hw_params_test_channels(mPcmHandle, hp, mDevice->channelsFromFmt()) < 0) + { + static const DevFmtChannels channellist[] = { + DevFmtStereo, + DevFmtQuad, + DevFmtX51, + DevFmtX71, + DevFmtMono, + }; + + for(const auto &chan : channellist) + { + if(snd_pcm_hw_params_test_channels(mPcmHandle, hp, ChannelsFromDevFmt(chan, 0)) >= 0) + { + mDevice->FmtChans = chan; + mDevice->mAmbiOrder = 0; + break; + } + } + } + CHECK(snd_pcm_hw_params_set_channels(mPcmHandle, hp, mDevice->channelsFromFmt())); + /* set rate (implicitly constrains period/buffer parameters) */ + if(!GetConfigValueBool(mDevice->DeviceName.c_str(), "alsa", "allow-resampler", 0) || + !mDevice->Flags.get()) + { + if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp, 0) < 0) + ERR("Failed to disable ALSA resampler\n"); + } + else if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp, 1) < 0) + ERR("Failed to enable ALSA resampler\n"); + CHECK(snd_pcm_hw_params_set_rate_near(mPcmHandle, hp, &rate, nullptr)); + /* set period time (implicitly constrains period/buffer parameters) */ + if((err=snd_pcm_hw_params_set_period_time_near(mPcmHandle, hp, &periodLen, nullptr)) < 0) + ERR("snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err)); + /* set buffer time (implicitly sets buffer size/bytes/time and period size/bytes) */ + if((err=snd_pcm_hw_params_set_buffer_time_near(mPcmHandle, hp, &bufferLen, nullptr)) < 0) + ERR("snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err)); + /* install and prepare hardware configuration */ + CHECK(snd_pcm_hw_params(mPcmHandle, hp)); + + /* retrieve configuration info */ + CHECK(snd_pcm_hw_params_get_access(hp, &access)); + CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, nullptr)); + CHECK(snd_pcm_hw_params_get_buffer_size(hp, &bufferSizeInFrames)); + snd_pcm_hw_params_free(hp); + hp = nullptr; + + snd_pcm_sw_params_malloc(&sp); + CHECK(snd_pcm_sw_params_current(mPcmHandle, sp)); + CHECK(snd_pcm_sw_params_set_avail_min(mPcmHandle, sp, periodSizeInFrames)); + CHECK(snd_pcm_sw_params_set_stop_threshold(mPcmHandle, sp, bufferSizeInFrames)); + CHECK(snd_pcm_sw_params(mPcmHandle, sp)); +#undef CHECK + snd_pcm_sw_params_free(sp); + sp = nullptr; + + mDevice->BufferSize = bufferSizeInFrames; + mDevice->UpdateSize = periodSizeInFrames; + mDevice->Frequency = rate; + + SetDefaultChannelOrder(mDevice); + + return ALC_TRUE; + +error: + ERR("%s failed: %s\n", funcerr, snd_strerror(err)); + if(hp) snd_pcm_hw_params_free(hp); + if(sp) snd_pcm_sw_params_free(sp); + return ALC_FALSE; +} + +ALCboolean AlsaPlayback::start() +{ + snd_pcm_hw_params_t *hp{}; + snd_pcm_access_t access; + const char *funcerr; + int err; + + snd_pcm_hw_params_malloc(&hp); +#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error + CHECK(snd_pcm_hw_params_current(mPcmHandle, hp)); + /* retrieve configuration info */ + CHECK(snd_pcm_hw_params_get_access(hp, &access)); +#undef CHECK + if(0) + { + error: + ERR("%s failed: %s\n", funcerr, snd_strerror(err)); + if(hp) snd_pcm_hw_params_free(hp); + return ALC_FALSE; + } + snd_pcm_hw_params_free(hp); + hp = nullptr; + + int (AlsaPlayback::*thread_func)(){}; + if(access == SND_PCM_ACCESS_RW_INTERLEAVED) + { + mBuffer.resize(snd_pcm_frames_to_bytes(mPcmHandle, mDevice->UpdateSize)); + thread_func = &AlsaPlayback::mixerNoMMapProc; + } + else + { + err = snd_pcm_prepare(mPcmHandle); + if(err < 0) + { + ERR("snd_pcm_prepare(data->mPcmHandle) failed: %s\n", snd_strerror(err)); + return ALC_FALSE; + } + thread_func = &AlsaPlayback::mixerProc; + } + + try { + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(thread_func), this}; + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Could not create playback thread: %s\n", e.what()); + } + catch(...) { + } + mBuffer.clear(); + return ALC_FALSE; +} + +void AlsaPlayback::stop() +{ + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) + return; + mThread.join(); + + mBuffer.clear(); +} + +ClockLatency AlsaPlayback::getClockLatency() +{ + ClockLatency ret; + + lock(); + ret.ClockTime = GetDeviceClockTime(mDevice); + snd_pcm_sframes_t delay{}; + int err{snd_pcm_delay(mPcmHandle, &delay)}; + if(err < 0) + { + ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); + delay = 0; + } + ret.Latency = std::chrono::seconds{std::max(0, delay)}; + ret.Latency /= mDevice->Frequency; + unlock(); + + return ret; +} + + +struct AlsaCapture final : public BackendBase { + AlsaCapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~AlsaCapture() override; + + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + ClockLatency getClockLatency() override; + + snd_pcm_t *mPcmHandle{nullptr}; + + al::vector mBuffer; + + bool mDoCapture{false}; + RingBufferPtr mRing{nullptr}; + + snd_pcm_sframes_t mLastAvail{0}; + + DEF_NEWDEL(AlsaCapture) +}; + +AlsaCapture::~AlsaCapture() +{ + if(mPcmHandle) + snd_pcm_close(mPcmHandle); + mPcmHandle = nullptr; +} + + +ALCenum AlsaCapture::open(const ALCchar *name) +{ + const char *driver{}; + if(name) + { + if(CaptureDevices.empty()) + CaptureDevices = probe_devices(SND_PCM_STREAM_CAPTURE); + + auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), + [name](const DevMap &entry) -> bool + { return entry.name == name; } + ); + if(iter == CaptureDevices.cend()) + return ALC_INVALID_VALUE; + driver = iter->device_name.c_str(); + } + else + { + name = alsaDevice; + driver = GetConfigValue(nullptr, "alsa", "capture", "default"); + } + + TRACE("Opening device \"%s\"\n", driver); + int err{snd_pcm_open(&mPcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)}; + if(err < 0) + { + ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err)); + return ALC_INVALID_VALUE; + } + + /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */ + snd_config_update_free_global(); + + snd_pcm_format_t format{SND_PCM_FORMAT_UNKNOWN}; + switch(mDevice->FmtType) + { + case DevFmtByte: + format = SND_PCM_FORMAT_S8; + break; + case DevFmtUByte: + format = SND_PCM_FORMAT_U8; + break; + case DevFmtShort: + format = SND_PCM_FORMAT_S16; + break; + case DevFmtUShort: + format = SND_PCM_FORMAT_U16; + break; + case DevFmtInt: + format = SND_PCM_FORMAT_S32; + break; + case DevFmtUInt: + format = SND_PCM_FORMAT_U32; + break; + case DevFmtFloat: + format = SND_PCM_FORMAT_FLOAT; + break; + } + + snd_pcm_uframes_t bufferSizeInFrames{maxu(mDevice->BufferSize, 100*mDevice->Frequency/1000)}; + snd_pcm_uframes_t periodSizeInFrames{minu(bufferSizeInFrames, 25*mDevice->Frequency/1000)}; + + bool needring{false}; + const char *funcerr{}; + snd_pcm_hw_params_t *hp{}; + snd_pcm_hw_params_malloc(&hp); +#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error + CHECK(snd_pcm_hw_params_any(mPcmHandle, hp)); + /* set interleaved access */ + CHECK(snd_pcm_hw_params_set_access(mPcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); + /* set format (implicitly sets sample bits) */ + CHECK(snd_pcm_hw_params_set_format(mPcmHandle, hp, format)); + /* set channels (implicitly sets frame bits) */ + CHECK(snd_pcm_hw_params_set_channels(mPcmHandle, hp, mDevice->channelsFromFmt())); + /* set rate (implicitly constrains period/buffer parameters) */ + CHECK(snd_pcm_hw_params_set_rate(mPcmHandle, hp, mDevice->Frequency, 0)); + /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ + if(snd_pcm_hw_params_set_buffer_size_min(mPcmHandle, hp, &bufferSizeInFrames) < 0) + { + TRACE("Buffer too large, using intermediate ring buffer\n"); + needring = true; + CHECK(snd_pcm_hw_params_set_buffer_size_near(mPcmHandle, hp, &bufferSizeInFrames)); + } + /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ + CHECK(snd_pcm_hw_params_set_period_size_near(mPcmHandle, hp, &periodSizeInFrames, nullptr)); + /* install and prepare hardware configuration */ + CHECK(snd_pcm_hw_params(mPcmHandle, hp)); + /* retrieve configuration info */ + CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, nullptr)); +#undef CHECK + snd_pcm_hw_params_free(hp); + hp = nullptr; + + if(needring) + { + mRing = CreateRingBuffer(mDevice->BufferSize, mDevice->frameSizeFromFmt(), false); + if(!mRing) + { + ERR("ring buffer create failed\n"); + goto error2; + } + } + + mDevice->DeviceName = name; + + return ALC_NO_ERROR; + +error: + ERR("%s failed: %s\n", funcerr, snd_strerror(err)); + if(hp) snd_pcm_hw_params_free(hp); + +error2: + mRing = nullptr; + snd_pcm_close(mPcmHandle); + mPcmHandle = nullptr; + + return ALC_INVALID_VALUE; +} + + +ALCboolean AlsaCapture::start() +{ + int err{snd_pcm_prepare(mPcmHandle)}; + if(err < 0) + ERR("prepare failed: %s\n", snd_strerror(err)); + else + { + err = snd_pcm_start(mPcmHandle); + if(err < 0) + ERR("start failed: %s\n", snd_strerror(err)); + } + if(err < 0) + { + aluHandleDisconnect(mDevice, "Capture state failure: %s", snd_strerror(err)); + return ALC_FALSE; + } + + mDoCapture = true; + return ALC_TRUE; +} + +void AlsaCapture::stop() +{ + /* OpenAL requires access to unread audio after stopping, but ALSA's + * snd_pcm_drain is unreliable and snd_pcm_drop drops it. Capture what's + * available now so it'll be available later after the drop. + */ + ALCuint avail{availableSamples()}; + if(!mRing && avail > 0) + { + /* The ring buffer implicitly captures when checking availability. + * Direct access needs to explicitly capture it into temp storage. */ + al::vector temp(snd_pcm_frames_to_bytes(mPcmHandle, avail)); + captureSamples(temp.data(), avail); + mBuffer = std::move(temp); + } + int err{snd_pcm_drop(mPcmHandle)}; + if(err < 0) + ERR("drop failed: %s\n", snd_strerror(err)); + mDoCapture = false; +} + +ALCenum AlsaCapture::captureSamples(ALCvoid *buffer, ALCuint samples) +{ + if(mRing) + { + mRing->read(buffer, samples); + return ALC_NO_ERROR; + } + + mLastAvail -= samples; + while(mDevice->Connected.load(std::memory_order_acquire) && samples > 0) + { + snd_pcm_sframes_t amt{0}; + + if(!mBuffer.empty()) + { + /* First get any data stored from the last stop */ + amt = snd_pcm_bytes_to_frames(mPcmHandle, mBuffer.size()); + if(static_cast(amt) > samples) amt = samples; + + amt = snd_pcm_frames_to_bytes(mPcmHandle, amt); + memcpy(buffer, mBuffer.data(), amt); + + mBuffer.erase(mBuffer.begin(), mBuffer.begin()+amt); + amt = snd_pcm_bytes_to_frames(mPcmHandle, amt); + } + else if(mDoCapture) + amt = snd_pcm_readi(mPcmHandle, buffer, samples); + if(amt < 0) + { + ERR("read error: %s\n", snd_strerror(amt)); + + if(amt == -EAGAIN) + continue; + if((amt=snd_pcm_recover(mPcmHandle, amt, 1)) >= 0) + { + amt = snd_pcm_start(mPcmHandle); + if(amt >= 0) + amt = snd_pcm_avail_update(mPcmHandle); + } + if(amt < 0) + { + ERR("restore error: %s\n", snd_strerror(amt)); + aluHandleDisconnect(mDevice, "Capture recovery failure: %s", snd_strerror(amt)); + break; + } + /* If the amount available is less than what's asked, we lost it + * during recovery. So just give silence instead. */ + if(static_cast(amt) < samples) + break; + continue; + } + + buffer = static_cast(buffer) + amt; + samples -= amt; + } + if(samples > 0) + memset(buffer, ((mDevice->FmtType == DevFmtUByte) ? 0x80 : 0), + snd_pcm_frames_to_bytes(mPcmHandle, samples)); + + return ALC_NO_ERROR; +} + +ALCuint AlsaCapture::availableSamples() +{ + snd_pcm_sframes_t avail{0}; + if(mDevice->Connected.load(std::memory_order_acquire) && mDoCapture) + avail = snd_pcm_avail_update(mPcmHandle); + if(avail < 0) + { + ERR("avail update failed: %s\n", snd_strerror(avail)); + + if((avail=snd_pcm_recover(mPcmHandle, avail, 1)) >= 0) + { + if(mDoCapture) + avail = snd_pcm_start(mPcmHandle); + if(avail >= 0) + avail = snd_pcm_avail_update(mPcmHandle); + } + if(avail < 0) + { + ERR("restore error: %s\n", snd_strerror(avail)); + aluHandleDisconnect(mDevice, "Capture recovery failure: %s", snd_strerror(avail)); + } + } + + if(!mRing) + { + if(avail < 0) avail = 0; + avail += snd_pcm_bytes_to_frames(mPcmHandle, mBuffer.size()); + if(avail > mLastAvail) mLastAvail = avail; + return mLastAvail; + } + + while(avail > 0) + { + auto vec = mRing->getWriteVector(); + if(vec.first.len == 0) break; + + snd_pcm_sframes_t amt{std::min(vec.first.len, avail)}; + amt = snd_pcm_readi(mPcmHandle, vec.first.buf, amt); + if(amt < 0) + { + ERR("read error: %s\n", snd_strerror(amt)); + + if(amt == -EAGAIN) + continue; + if((amt=snd_pcm_recover(mPcmHandle, amt, 1)) >= 0) + { + if(mDoCapture) + amt = snd_pcm_start(mPcmHandle); + if(amt >= 0) + amt = snd_pcm_avail_update(mPcmHandle); + } + if(amt < 0) + { + ERR("restore error: %s\n", snd_strerror(amt)); + aluHandleDisconnect(mDevice, "Capture recovery failure: %s", snd_strerror(amt)); + break; + } + avail = amt; + continue; + } + + mRing->writeAdvance(amt); + avail -= amt; + } + + return mRing->readSpace(); +} + +ClockLatency AlsaCapture::getClockLatency() +{ + ClockLatency ret; + + lock(); + ret.ClockTime = GetDeviceClockTime(mDevice); + snd_pcm_sframes_t delay{}; + int err{snd_pcm_delay(mPcmHandle, &delay)}; + if(err < 0) + { + ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); + delay = 0; + } + ret.Latency = std::chrono::seconds{std::max(0, delay)}; + ret.Latency /= mDevice->Frequency; + unlock(); + + return ret; +} + +} // namespace + + +bool AlsaBackendFactory::init() +{ + bool error{false}; + +#ifdef HAVE_DYNLOAD + if(!alsa_handle) + { + std::string missing_funcs; + + alsa_handle = LoadLib("libasound.so.2"); + if(!alsa_handle) + { + WARN("Failed to load %s\n", "libasound.so.2"); + return ALC_FALSE; + } + + error = ALC_FALSE; +#define LOAD_FUNC(f) do { \ + p##f = reinterpret_cast(GetSymbol(alsa_handle, #f)); \ + if(p##f == nullptr) { \ + error = true; \ + missing_funcs += "\n" #f; \ + } \ +} while(0) + ALSA_FUNCS(LOAD_FUNC); +#undef LOAD_FUNC + + if(error) + { + WARN("Missing expected functions:%s\n", missing_funcs.c_str()); + CloseLib(alsa_handle); + alsa_handle = nullptr; + } + } +#endif + + return !error; +} + +bool AlsaBackendFactory::querySupport(BackendType type) +{ return (type == BackendType::Playback || type == BackendType::Capture); } + +void AlsaBackendFactory::probe(DevProbe type, std::string *outnames) +{ + auto add_device = [outnames](const DevMap &entry) -> void + { + /* +1 to also append the null char (to ensure a null-separated list and + * double-null terminated list). + */ + outnames->append(entry.name.c_str(), entry.name.length()+1); + }; + switch(type) + { + case DevProbe::Playback: + PlaybackDevices = probe_devices(SND_PCM_STREAM_PLAYBACK); + std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); + break; + + case DevProbe::Capture: + CaptureDevices = probe_devices(SND_PCM_STREAM_CAPTURE); + std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); + break; + } +} + +BackendPtr AlsaBackendFactory::createBackend(ALCdevice *device, BackendType type) +{ + if(type == BackendType::Playback) + return BackendPtr{new AlsaPlayback{device}}; + if(type == BackendType::Capture) + return BackendPtr{new AlsaCapture{device}}; + return nullptr; +} + +BackendFactory &AlsaBackendFactory::getFactory() +{ + static AlsaBackendFactory factory{}; + return factory; +} diff --git a/alc/backends/alsa.h b/alc/backends/alsa.h new file mode 100644 index 00000000..fb9de006 --- /dev/null +++ b/alc/backends/alsa.h @@ -0,0 +1,19 @@ +#ifndef BACKENDS_ALSA_H +#define BACKENDS_ALSA_H + +#include "backends/base.h" + +struct AlsaBackendFactory final : public BackendFactory { +public: + bool init() override; + + bool querySupport(BackendType type) override; + + void probe(DevProbe type, std::string *outnames) override; + + BackendPtr createBackend(ALCdevice *device, BackendType type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_ALSA_H */ diff --git a/alc/backends/base.cpp b/alc/backends/base.cpp new file mode 100644 index 00000000..a7d47c6d --- /dev/null +++ b/alc/backends/base.cpp @@ -0,0 +1,58 @@ + +#include "config.h" + +#include + +#include + +#include "alcmain.h" +#include "alu.h" + +#include "backends/base.h" + + +ClockLatency GetClockLatency(ALCdevice *device) +{ + BackendBase *backend{device->Backend.get()}; + ClockLatency ret{backend->getClockLatency()}; + ret.Latency += device->FixedLatency; + return ret; +} + + +/* BackendBase method implementations. */ +BackendBase::BackendBase(ALCdevice *device) noexcept : mDevice{device} +{ } + +BackendBase::~BackendBase() = default; + +ALCboolean BackendBase::reset() +{ return ALC_FALSE; } + +ALCenum BackendBase::captureSamples(void*, ALCuint) +{ return ALC_INVALID_DEVICE; } + +ALCuint BackendBase::availableSamples() +{ return 0; } + +ClockLatency BackendBase::getClockLatency() +{ + ClockLatency ret; + + ALuint refcount; + do { + while(((refcount=mDevice->MixCount.load(std::memory_order_acquire))&1)) + std::this_thread::yield(); + ret.ClockTime = GetDeviceClockTime(mDevice); + std::atomic_thread_fence(std::memory_order_acquire); + } while(refcount != mDevice->MixCount.load(std::memory_order_relaxed)); + + /* NOTE: The device will generally have about all but one periods filled at + * any given time during playback. Without a more accurate measurement from + * the output, this is an okay approximation. + */ + ret.Latency = std::chrono::seconds{maxi(mDevice->BufferSize-mDevice->UpdateSize, 0)}; + ret.Latency /= mDevice->Frequency; + + return ret; +} diff --git a/alc/backends/base.h b/alc/backends/base.h new file mode 100644 index 00000000..437e31d9 --- /dev/null +++ b/alc/backends/base.h @@ -0,0 +1,78 @@ +#ifndef ALC_BACKENDS_BASE_H +#define ALC_BACKENDS_BASE_H + +#include +#include +#include +#include + +#include "alcmain.h" + + +struct ClockLatency { + std::chrono::nanoseconds ClockTime; + std::chrono::nanoseconds Latency; +}; + +/* Helper to get the current clock time from the device's ClockBase, and + * SamplesDone converted from the sample rate. + */ +inline std::chrono::nanoseconds GetDeviceClockTime(ALCdevice *device) +{ + using std::chrono::seconds; + using std::chrono::nanoseconds; + + auto ns = nanoseconds{seconds{device->SamplesDone}} / device->Frequency; + return device->ClockBase + ns; +} + +ClockLatency GetClockLatency(ALCdevice *device); + +struct BackendBase { + virtual ALCenum open(const ALCchar *name) = 0; + + virtual ALCboolean reset(); + virtual ALCboolean start() = 0; + virtual void stop() = 0; + + virtual ALCenum captureSamples(void *buffer, ALCuint samples); + virtual ALCuint availableSamples(); + + virtual ClockLatency getClockLatency(); + + virtual void lock() { mMutex.lock(); } + virtual void unlock() { mMutex.unlock(); } + + ALCdevice *mDevice; + + std::recursive_mutex mMutex; + + BackendBase(ALCdevice *device) noexcept; + virtual ~BackendBase(); +}; +using BackendPtr = std::unique_ptr; +using BackendUniqueLock = std::unique_lock; +using BackendLockGuard = std::lock_guard; + +enum class BackendType { + Playback, + Capture +}; + +enum class DevProbe { + Playback, + Capture +}; + + +struct BackendFactory { + virtual bool init() = 0; + + virtual bool querySupport(BackendType type) = 0; + + virtual void probe(DevProbe type, std::string *outnames) = 0; + + virtual BackendPtr createBackend(ALCdevice *device, BackendType type) = 0; +}; + +#endif /* ALC_BACKENDS_BASE_H */ diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp new file mode 100644 index 00000000..b4b46382 --- /dev/null +++ b/alc/backends/coreaudio.cpp @@ -0,0 +1,709 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "backends/coreaudio.h" + +#include +#include +#include + +#include "alcmain.h" +#include "alu.h" +#include "ringbuffer.h" +#include "converter.h" +#include "backends/base.h" + +#include +#include +#include + + +namespace { + +static const ALCchar ca_device[] = "CoreAudio Default"; + + +struct CoreAudioPlayback final : public BackendBase { + CoreAudioPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~CoreAudioPlayback() override; + + static OSStatus MixerProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, + AudioBufferList *ioData); + OSStatus MixerProc(AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, + AudioBufferList *ioData); + + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + + AudioUnit mAudioUnit; + + ALuint mFrameSize{0u}; + AudioStreamBasicDescription mFormat{}; // This is the OpenAL format as a CoreAudio ASBD + + DEF_NEWDEL(CoreAudioPlayback) +}; + +CoreAudioPlayback::~CoreAudioPlayback() +{ + AudioUnitUninitialize(mAudioUnit); + AudioComponentInstanceDispose(mAudioUnit); +} + + +OSStatus CoreAudioPlayback::MixerProcC(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) +{ + return static_cast(inRefCon)->MixerProc(ioActionFlags, inTimeStamp, + inBusNumber, inNumberFrames, ioData); +} + +OSStatus CoreAudioPlayback::MixerProc(AudioUnitRenderActionFlags*, + const AudioTimeStamp*, UInt32, UInt32, AudioBufferList *ioData) +{ + lock(); + aluMixData(mDevice, ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize/mFrameSize); + unlock(); + return noErr; +} + + +ALCenum CoreAudioPlayback::open(const ALCchar *name) +{ + if(!name) + name = ca_device; + else if(strcmp(name, ca_device) != 0) + return ALC_INVALID_VALUE; + + /* open the default output unit */ + AudioComponentDescription desc{}; + desc.componentType = kAudioUnitType_Output; +#if TARGET_OS_IOS + desc.componentSubType = kAudioUnitSubType_RemoteIO; +#else + desc.componentSubType = kAudioUnitSubType_DefaultOutput; +#endif + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + AudioComponent comp{AudioComponentFindNext(NULL, &desc)}; + if(comp == nullptr) + { + ERR("AudioComponentFindNext failed\n"); + return ALC_INVALID_VALUE; + } + + OSStatus err{AudioComponentInstanceNew(comp, &mAudioUnit)}; + if(err != noErr) + { + ERR("AudioComponentInstanceNew failed\n"); + return ALC_INVALID_VALUE; + } + + /* init and start the default audio unit... */ + err = AudioUnitInitialize(mAudioUnit); + if(err != noErr) + { + ERR("AudioUnitInitialize failed\n"); + AudioComponentInstanceDispose(mAudioUnit); + return ALC_INVALID_VALUE; + } + + mDevice->DeviceName = name; + return ALC_NO_ERROR; +} + +ALCboolean CoreAudioPlayback::reset() +{ + OSStatus err{AudioUnitUninitialize(mAudioUnit)}; + if(err != noErr) + ERR("-- AudioUnitUninitialize failed.\n"); + + /* retrieve default output unit's properties (output side) */ + AudioStreamBasicDescription streamFormat{}; + auto size = static_cast(sizeof(AudioStreamBasicDescription)); + err = AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, + 0, &streamFormat, &size); + if(err != noErr || size != sizeof(AudioStreamBasicDescription)) + { + ERR("AudioUnitGetProperty failed\n"); + return ALC_FALSE; + } + +#if 0 + TRACE("Output streamFormat of default output unit -\n"); + TRACE(" streamFormat.mFramesPerPacket = %d\n", streamFormat.mFramesPerPacket); + TRACE(" streamFormat.mChannelsPerFrame = %d\n", streamFormat.mChannelsPerFrame); + TRACE(" streamFormat.mBitsPerChannel = %d\n", streamFormat.mBitsPerChannel); + TRACE(" streamFormat.mBytesPerPacket = %d\n", streamFormat.mBytesPerPacket); + TRACE(" streamFormat.mBytesPerFrame = %d\n", streamFormat.mBytesPerFrame); + TRACE(" streamFormat.mSampleRate = %5.0f\n", streamFormat.mSampleRate); +#endif + + /* set default output unit's input side to match output side */ + err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, + 0, &streamFormat, size); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + return ALC_FALSE; + } + + if(mDevice->Frequency != streamFormat.mSampleRate) + { + mDevice->BufferSize = static_cast(uint64_t{mDevice->BufferSize} * + streamFormat.mSampleRate / mDevice->Frequency); + mDevice->Frequency = streamFormat.mSampleRate; + } + + /* FIXME: How to tell what channels are what in the output device, and how + * to specify what we're giving? eg, 6.0 vs 5.1 */ + switch(streamFormat.mChannelsPerFrame) + { + case 1: + mDevice->FmtChans = DevFmtMono; + break; + case 2: + mDevice->FmtChans = DevFmtStereo; + break; + case 4: + mDevice->FmtChans = DevFmtQuad; + break; + case 6: + mDevice->FmtChans = DevFmtX51; + break; + case 7: + mDevice->FmtChans = DevFmtX61; + break; + case 8: + mDevice->FmtChans = DevFmtX71; + break; + default: + ERR("Unhandled channel count (%d), using Stereo\n", streamFormat.mChannelsPerFrame); + mDevice->FmtChans = DevFmtStereo; + streamFormat.mChannelsPerFrame = 2; + break; + } + SetDefaultWFXChannelOrder(mDevice); + + /* use channel count and sample rate from the default output unit's current + * parameters, but reset everything else */ + streamFormat.mFramesPerPacket = 1; + streamFormat.mFormatFlags = 0; + switch(mDevice->FmtType) + { + case DevFmtUByte: + mDevice->FmtType = DevFmtByte; + /* fall-through */ + case DevFmtByte: + streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; + streamFormat.mBitsPerChannel = 8; + break; + case DevFmtUShort: + mDevice->FmtType = DevFmtShort; + /* fall-through */ + case DevFmtShort: + streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; + streamFormat.mBitsPerChannel = 16; + break; + case DevFmtUInt: + mDevice->FmtType = DevFmtInt; + /* fall-through */ + case DevFmtInt: + streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; + streamFormat.mBitsPerChannel = 32; + break; + case DevFmtFloat: + streamFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat; + streamFormat.mBitsPerChannel = 32; + break; + } + streamFormat.mBytesPerFrame = streamFormat.mChannelsPerFrame * + streamFormat.mBitsPerChannel / 8; + streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame; + streamFormat.mFormatID = kAudioFormatLinearPCM; + streamFormat.mFormatFlags |= kAudioFormatFlagsNativeEndian | + kLinearPCMFormatFlagIsPacked; + + err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, + 0, &streamFormat, sizeof(AudioStreamBasicDescription)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + return ALC_FALSE; + } + + /* setup callback */ + mFrameSize = mDevice->frameSizeFromFmt(); + AURenderCallbackStruct input{}; + input.inputProc = CoreAudioPlayback::MixerProcC; + input.inputProcRefCon = this; + + err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + return ALC_FALSE; + } + + /* init the default audio unit... */ + err = AudioUnitInitialize(mAudioUnit); + if(err != noErr) + { + ERR("AudioUnitInitialize failed\n"); + return ALC_FALSE; + } + + return ALC_TRUE; +} + +ALCboolean CoreAudioPlayback::start() +{ + OSStatus err{AudioOutputUnitStart(mAudioUnit)}; + if(err != noErr) + { + ERR("AudioOutputUnitStart failed\n"); + return ALC_FALSE; + } + return ALC_TRUE; +} + +void CoreAudioPlayback::stop() +{ + OSStatus err{AudioOutputUnitStop(mAudioUnit)}; + if(err != noErr) + ERR("AudioOutputUnitStop failed\n"); +} + + +struct CoreAudioCapture final : public BackendBase { + CoreAudioCapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~CoreAudioCapture() override; + + static OSStatus RecordProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, + AudioBufferList *ioData); + OSStatus RecordProc(AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, + UInt32 inNumberFrames, AudioBufferList *ioData); + + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + + AudioUnit mAudioUnit{0}; + + ALuint mFrameSize{0u}; + AudioStreamBasicDescription mFormat{}; // This is the OpenAL format as a CoreAudio ASBD + + SampleConverterPtr mConverter; + + RingBufferPtr mRing{nullptr}; + + DEF_NEWDEL(CoreAudioCapture) +}; + +CoreAudioCapture::~CoreAudioCapture() +{ + if(mAudioUnit) + AudioComponentInstanceDispose(mAudioUnit); + mAudioUnit = 0; +} + + +OSStatus CoreAudioCapture::RecordProcC(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) +{ + return static_cast(inRefCon)->RecordProc(ioActionFlags, inTimeStamp, + inBusNumber, inNumberFrames, ioData); +} + +OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags*, + const AudioTimeStamp *inTimeStamp, UInt32, UInt32 inNumberFrames, + AudioBufferList*) +{ + AudioUnitRenderActionFlags flags = 0; + union { + ALbyte _[sizeof(AudioBufferList) + sizeof(AudioBuffer)*2]; + AudioBufferList list; + } audiobuf = { { 0 } }; + + auto rec_vec = mRing->getWriteVector(); + inNumberFrames = minz(inNumberFrames, rec_vec.first.len+rec_vec.second.len); + + // Fill the ringbuffer's two segments with data from the input device + if(rec_vec.first.len >= inNumberFrames) + { + audiobuf.list.mNumberBuffers = 1; + audiobuf.list.mBuffers[0].mNumberChannels = mFormat.mChannelsPerFrame; + audiobuf.list.mBuffers[0].mData = rec_vec.first.buf; + audiobuf.list.mBuffers[0].mDataByteSize = inNumberFrames * mFormat.mBytesPerFrame; + } + else + { + const size_t remaining{inNumberFrames-rec_vec.first.len}; + audiobuf.list.mNumberBuffers = 2; + audiobuf.list.mBuffers[0].mNumberChannels = mFormat.mChannelsPerFrame; + audiobuf.list.mBuffers[0].mData = rec_vec.first.buf; + audiobuf.list.mBuffers[0].mDataByteSize = rec_vec.first.len * mFormat.mBytesPerFrame; + audiobuf.list.mBuffers[1].mNumberChannels = mFormat.mChannelsPerFrame; + audiobuf.list.mBuffers[1].mData = rec_vec.second.buf; + audiobuf.list.mBuffers[1].mDataByteSize = remaining * mFormat.mBytesPerFrame; + } + OSStatus err{AudioUnitRender(mAudioUnit, &flags, inTimeStamp, audiobuf.list.mNumberBuffers, + inNumberFrames, &audiobuf.list)}; + if(err != noErr) + { + ERR("AudioUnitRender error: %d\n", err); + return err; + } + + mRing->writeAdvance(inNumberFrames); + return noErr; +} + + +ALCenum CoreAudioCapture::open(const ALCchar *name) +{ + AudioStreamBasicDescription requestedFormat; // The application requested format + AudioStreamBasicDescription hardwareFormat; // The hardware format + AudioStreamBasicDescription outputFormat; // The AudioUnit output format + AURenderCallbackStruct input; + AudioComponentDescription desc; + UInt32 outputFrameCount; + UInt32 propertySize; + AudioObjectPropertyAddress propertyAddress; + UInt32 enableIO; + AudioComponent comp; + OSStatus err; + + if(!name) + name = ca_device; + else if(strcmp(name, ca_device) != 0) + return ALC_INVALID_VALUE; + + desc.componentType = kAudioUnitType_Output; +#if TARGET_OS_IOS + desc.componentSubType = kAudioUnitSubType_RemoteIO; +#else + desc.componentSubType = kAudioUnitSubType_HALOutput; +#endif + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + // Search for component with given description + comp = AudioComponentFindNext(NULL, &desc); + if(comp == NULL) + { + ERR("AudioComponentFindNext failed\n"); + return ALC_INVALID_VALUE; + } + + // Open the component + err = AudioComponentInstanceNew(comp, &mAudioUnit); + if(err != noErr) + { + ERR("AudioComponentInstanceNew failed\n"); + return ALC_INVALID_VALUE; + } + + // Turn off AudioUnit output + enableIO = 0; + err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + return ALC_INVALID_VALUE; + } + + // Turn on AudioUnit input + enableIO = 1; + err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + return ALC_INVALID_VALUE; + } + +#if !TARGET_OS_IOS + { + // Get the default input device + AudioDeviceID inputDevice = kAudioDeviceUnknown; + + propertySize = sizeof(AudioDeviceID); + propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; + propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; + propertyAddress.mElement = kAudioObjectPropertyElementMaster; + + err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, &inputDevice); + if(err != noErr) + { + ERR("AudioObjectGetPropertyData failed\n"); + return ALC_INVALID_VALUE; + } + if(inputDevice == kAudioDeviceUnknown) + { + ERR("No input device found\n"); + return ALC_INVALID_VALUE; + } + + // Track the input device + err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + return ALC_INVALID_VALUE; + } + } +#endif + + // set capture callback + input.inputProc = CoreAudioCapture::RecordProcC; + input.inputProcRefCon = this; + + err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_SetInputCallback, + kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + return ALC_INVALID_VALUE; + } + + // Initialize the device + err = AudioUnitInitialize(mAudioUnit); + if(err != noErr) + { + ERR("AudioUnitInitialize failed\n"); + return ALC_INVALID_VALUE; + } + + // Get the hardware format + propertySize = sizeof(AudioStreamBasicDescription); + err = AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, + 1, &hardwareFormat, &propertySize); + if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription)) + { + ERR("AudioUnitGetProperty failed\n"); + return ALC_INVALID_VALUE; + } + + // Set up the requested format description + switch(mDevice->FmtType) + { + case DevFmtUByte: + requestedFormat.mBitsPerChannel = 8; + requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked; + break; + case DevFmtShort: + requestedFormat.mBitsPerChannel = 16; + requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; + break; + case DevFmtInt: + requestedFormat.mBitsPerChannel = 32; + requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; + break; + case DevFmtFloat: + requestedFormat.mBitsPerChannel = 32; + requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked; + break; + case DevFmtByte: + case DevFmtUShort: + case DevFmtUInt: + ERR("%s samples not supported\n", DevFmtTypeString(mDevice->FmtType)); + return ALC_INVALID_VALUE; + } + + switch(mDevice->FmtChans) + { + case DevFmtMono: + requestedFormat.mChannelsPerFrame = 1; + break; + case DevFmtStereo: + requestedFormat.mChannelsPerFrame = 2; + break; + + case DevFmtQuad: + case DevFmtX51: + case DevFmtX51Rear: + case DevFmtX61: + case DevFmtX71: + case DevFmtAmbi3D: + ERR("%s not supported\n", DevFmtChannelsString(mDevice->FmtChans)); + return ALC_INVALID_VALUE; + } + + requestedFormat.mBytesPerFrame = requestedFormat.mChannelsPerFrame * requestedFormat.mBitsPerChannel / 8; + requestedFormat.mBytesPerPacket = requestedFormat.mBytesPerFrame; + requestedFormat.mSampleRate = mDevice->Frequency; + requestedFormat.mFormatID = kAudioFormatLinearPCM; + requestedFormat.mReserved = 0; + requestedFormat.mFramesPerPacket = 1; + + // save requested format description for later use + mFormat = requestedFormat; + mFrameSize = mDevice->frameSizeFromFmt(); + + // Use intermediate format for sample rate conversion (outputFormat) + // Set sample rate to the same as hardware for resampling later + outputFormat = requestedFormat; + outputFormat.mSampleRate = hardwareFormat.mSampleRate; + + // The output format should be the requested format, but using the hardware sample rate + // This is because the AudioUnit will automatically scale other properties, except for sample rate + err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, + 1, (void*)&outputFormat, sizeof(outputFormat)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + return ALC_INVALID_VALUE; + } + + // Set the AudioUnit output format frame count + uint64_t FrameCount64{mDevice->UpdateSize}; + FrameCount64 = (FrameCount64*outputFormat.mSampleRate + mDevice->Frequency-1) / + mDevice->Frequency; + FrameCount64 += MAX_RESAMPLE_PADDING*2; + if(FrameCount64 > std::numeric_limits::max()/2) + { + ERR("FrameCount too large\n"); + return ALC_INVALID_VALUE; + } + + outputFrameCount = static_cast(FrameCount64); + err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_MaximumFramesPerSlice, + kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed: %d\n", err); + return ALC_INVALID_VALUE; + } + + // Set up sample converter if needed + if(outputFormat.mSampleRate != mDevice->Frequency) + mConverter = CreateSampleConverter(mDevice->FmtType, mDevice->FmtType, + mFormat.mChannelsPerFrame, hardwareFormat.mSampleRate, mDevice->Frequency, + BSinc24Resampler); + + mRing = CreateRingBuffer(outputFrameCount, mFrameSize, false); + if(!mRing) return ALC_INVALID_VALUE; + + mDevice->DeviceName = name; + return ALC_NO_ERROR; +} + + +ALCboolean CoreAudioCapture::start() +{ + OSStatus err{AudioOutputUnitStart(mAudioUnit)}; + if(err != noErr) + { + ERR("AudioOutputUnitStart failed\n"); + return ALC_FALSE; + } + return ALC_TRUE; +} + +void CoreAudioCapture::stop() +{ + OSStatus err{AudioOutputUnitStop(mAudioUnit)}; + if(err != noErr) + ERR("AudioOutputUnitStop failed\n"); +} + +ALCenum CoreAudioCapture::captureSamples(void *buffer, ALCuint samples) +{ + if(!mConverter) + { + mRing->read(buffer, samples); + return ALC_NO_ERROR; + } + + auto rec_vec = mRing->getReadVector(); + const void *src0{rec_vec.first.buf}; + auto src0len = static_cast(rec_vec.first.len); + auto got = static_cast(mConverter->convert(&src0, &src0len, buffer, samples)); + size_t total_read{rec_vec.first.len - src0len}; + if(got < samples && !src0len && rec_vec.second.len > 0) + { + const void *src1{rec_vec.second.buf}; + auto src1len = static_cast(rec_vec.second.len); + got += static_cast(mConverter->convert(&src1, &src1len, + static_cast(buffer)+got, samples-got)); + total_read += rec_vec.second.len - src1len; + } + + mRing->readAdvance(total_read); + return ALC_NO_ERROR; +} + +ALCuint CoreAudioCapture::availableSamples() +{ + if(!mConverter) return mRing->readSpace(); + return mConverter->availableOut(mRing->readSpace()); +} + +} // namespace + +BackendFactory &CoreAudioBackendFactory::getFactory() +{ + static CoreAudioBackendFactory factory{}; + return factory; +} + +bool CoreAudioBackendFactory::init() { return true; } + +bool CoreAudioBackendFactory::querySupport(BackendType type) +{ return type == BackendType::Playback || type == BackendType::Capture; } + +void CoreAudioBackendFactory::probe(DevProbe type, std::string *outnames) +{ + switch(type) + { + case DevProbe::Playback: + case DevProbe::Capture: + /* Includes null char. */ + outnames->append(ca_device, sizeof(ca_device)); + break; + } +} + +BackendPtr CoreAudioBackendFactory::createBackend(ALCdevice *device, BackendType type) +{ + if(type == BackendType::Playback) + return BackendPtr{new CoreAudioPlayback{device}}; + if(type == BackendType::Capture) + return BackendPtr{new CoreAudioCapture{device}}; + return nullptr; +} diff --git a/alc/backends/coreaudio.h b/alc/backends/coreaudio.h new file mode 100644 index 00000000..37b9ebe5 --- /dev/null +++ b/alc/backends/coreaudio.h @@ -0,0 +1,19 @@ +#ifndef BACKENDS_COREAUDIO_H +#define BACKENDS_COREAUDIO_H + +#include "backends/base.h" + +struct CoreAudioBackendFactory final : public BackendFactory { +public: + bool init() override; + + bool querySupport(BackendType type) override; + + void probe(DevProbe type, std::string *outnames) override; + + BackendPtr createBackend(ALCdevice *device, BackendType type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_COREAUDIO_H */ diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp new file mode 100644 index 00000000..5a156d54 --- /dev/null +++ b/alc/backends/dsound.cpp @@ -0,0 +1,938 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "backends/dsound.h" + +#define WIN32_LEAN_AND_MEAN +#include + +#include +#include +#include + +#include +#include +#ifndef _WAVEFORMATEXTENSIBLE_ +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "alcmain.h" +#include "alu.h" +#include "ringbuffer.h" +#include "compat.h" +#include "threads.h" + +/* MinGW-w64 needs this for some unknown reason now. */ +using LPCWAVEFORMATEX = const WAVEFORMATEX*; +#include + + +#ifndef DSSPEAKER_5POINT1 +# define DSSPEAKER_5POINT1 0x00000006 +#endif +#ifndef DSSPEAKER_5POINT1_BACK +# define DSSPEAKER_5POINT1_BACK 0x00000006 +#endif +#ifndef DSSPEAKER_7POINT1 +# define DSSPEAKER_7POINT1 0x00000007 +#endif +#ifndef DSSPEAKER_7POINT1_SURROUND +# define DSSPEAKER_7POINT1_SURROUND 0x00000008 +#endif +#ifndef DSSPEAKER_5POINT1_SURROUND +# define DSSPEAKER_5POINT1_SURROUND 0x00000009 +#endif + + +/* Some headers seem to define these as macros for __uuidof, which is annoying + * since some headers don't declare them at all. Hopefully the ifdef is enough + * to tell if they need to be declared. + */ +#ifndef KSDATAFORMAT_SUBTYPE_PCM +DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +#endif +#ifndef KSDATAFORMAT_SUBTYPE_IEEE_FLOAT +DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +#endif + +namespace { + +#define DEVNAME_HEAD "OpenAL Soft on " + + +#ifdef HAVE_DYNLOAD +void *ds_handle; +HRESULT (WINAPI *pDirectSoundCreate)(const GUID *pcGuidDevice, IDirectSound **ppDS, IUnknown *pUnkOuter); +HRESULT (WINAPI *pDirectSoundEnumerateW)(LPDSENUMCALLBACKW pDSEnumCallback, void *pContext); +HRESULT (WINAPI *pDirectSoundCaptureCreate)(const GUID *pcGuidDevice, IDirectSoundCapture **ppDSC, IUnknown *pUnkOuter); +HRESULT (WINAPI *pDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW pDSEnumCallback, void *pContext); + +#ifndef IN_IDE_PARSER +#define DirectSoundCreate pDirectSoundCreate +#define DirectSoundEnumerateW pDirectSoundEnumerateW +#define DirectSoundCaptureCreate pDirectSoundCaptureCreate +#define DirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW +#endif +#endif + + +#define MAX_UPDATES 128 + +struct DevMap { + std::string name; + GUID guid; + + template + DevMap(T0&& name_, T1&& guid_) + : name{std::forward(name_)}, guid{std::forward(guid_)} + { } +}; + +al::vector PlaybackDevices; +al::vector CaptureDevices; + +bool checkName(const al::vector &list, const std::string &name) +{ + return std::find_if(list.cbegin(), list.cend(), + [&name](const DevMap &entry) -> bool + { return entry.name == name; } + ) != list.cend(); +} + +BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR*, void *data) +{ + if(!guid) + return TRUE; + + auto& devices = *static_cast*>(data); + const std::string basename{DEVNAME_HEAD + wstr_to_utf8(desc)}; + + int count{1}; + std::string newname{basename}; + while(checkName(devices, newname)) + { + newname = basename; + newname += " #"; + newname += std::to_string(++count); + } + devices.emplace_back(std::move(newname), *guid); + const DevMap &newentry = devices.back(); + + OLECHAR *guidstr{nullptr}; + HRESULT hr{StringFromCLSID(*guid, &guidstr)}; + if(SUCCEEDED(hr)) + { + TRACE("Got device \"%s\", GUID \"%ls\"\n", newentry.name.c_str(), guidstr); + CoTaskMemFree(guidstr); + } + + return TRUE; +} + + +struct DSoundPlayback final : public BackendBase { + DSoundPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~DSoundPlayback() override; + + int mixerProc(); + + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + + IDirectSound *mDS{nullptr}; + IDirectSoundBuffer *mPrimaryBuffer{nullptr}; + IDirectSoundBuffer *mBuffer{nullptr}; + IDirectSoundNotify *mNotifies{nullptr}; + HANDLE mNotifyEvent{nullptr}; + + std::atomic mKillNow{true}; + std::thread mThread; + + DEF_NEWDEL(DSoundPlayback) +}; + +DSoundPlayback::~DSoundPlayback() +{ + if(mNotifies) + mNotifies->Release(); + mNotifies = nullptr; + if(mBuffer) + mBuffer->Release(); + mBuffer = nullptr; + if(mPrimaryBuffer) + mPrimaryBuffer->Release(); + mPrimaryBuffer = nullptr; + + if(mDS) + mDS->Release(); + mDS = nullptr; + if(mNotifyEvent) + CloseHandle(mNotifyEvent); + mNotifyEvent = nullptr; +} + + +FORCE_ALIGN int DSoundPlayback::mixerProc() +{ + SetRTPriority(); + althrd_setname(MIXER_THREAD_NAME); + + DSBCAPS DSBCaps{}; + DSBCaps.dwSize = sizeof(DSBCaps); + HRESULT err{mBuffer->GetCaps(&DSBCaps)}; + if(FAILED(err)) + { + ERR("Failed to get buffer caps: 0x%lx\n", err); + aluHandleDisconnect(mDevice, "Failure retrieving playback buffer info: 0x%lx", err); + return 1; + } + + ALsizei FrameSize{mDevice->frameSizeFromFmt()}; + DWORD FragSize{mDevice->UpdateSize * FrameSize}; + + bool Playing{false}; + DWORD LastCursor{0u}; + mBuffer->GetCurrentPosition(&LastCursor, nullptr); + while(!mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) + { + // Get current play cursor + DWORD PlayCursor; + mBuffer->GetCurrentPosition(&PlayCursor, nullptr); + DWORD avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes; + + if(avail < FragSize) + { + if(!Playing) + { + err = mBuffer->Play(0, 0, DSBPLAY_LOOPING); + if(FAILED(err)) + { + ERR("Failed to play buffer: 0x%lx\n", err); + aluHandleDisconnect(mDevice, "Failure starting playback: 0x%lx", err); + return 1; + } + Playing = true; + } + + avail = WaitForSingleObjectEx(mNotifyEvent, 2000, FALSE); + if(avail != WAIT_OBJECT_0) + ERR("WaitForSingleObjectEx error: 0x%lx\n", avail); + continue; + } + avail -= avail%FragSize; + + // Lock output buffer + void *WritePtr1, *WritePtr2; + DWORD WriteCnt1{0u}, WriteCnt2{0u}; + err = mBuffer->Lock(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 = mBuffer->Restore(); + if(SUCCEEDED(err)) + { + Playing = false; + LastCursor = 0; + err = mBuffer->Lock(0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, + &WritePtr2, &WriteCnt2, 0); + } + } + + if(SUCCEEDED(err)) + { + lock(); + aluMixData(mDevice, WritePtr1, WriteCnt1/FrameSize); + if(WriteCnt2 > 0) + aluMixData(mDevice, WritePtr2, WriteCnt2/FrameSize); + unlock(); + + mBuffer->Unlock(WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); + } + else + { + ERR("Buffer lock error: %#lx\n", err); + aluHandleDisconnect(mDevice, "Failed to lock output buffer: 0x%lx", err); + return 1; + } + + // Update old write cursor location + LastCursor += WriteCnt1+WriteCnt2; + LastCursor %= DSBCaps.dwBufferBytes; + } + + return 0; +} + +ALCenum DSoundPlayback::open(const ALCchar *name) +{ + HRESULT hr; + if(PlaybackDevices.empty()) + { + /* Initialize COM to prevent name truncation */ + HRESULT hrcom{CoInitialize(nullptr)}; + hr = DirectSoundEnumerateW(DSoundEnumDevices, &PlaybackDevices); + if(FAILED(hr)) + ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr); + if(SUCCEEDED(hrcom)) + CoUninitialize(); + } + + const GUID *guid{nullptr}; + if(!name && !PlaybackDevices.empty()) + { + name = PlaybackDevices[0].name.c_str(); + guid = &PlaybackDevices[0].guid; + } + else + { + auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + [name](const DevMap &entry) -> bool + { return entry.name == name; } + ); + if(iter == PlaybackDevices.cend()) + return ALC_INVALID_VALUE; + guid = &iter->guid; + } + + hr = DS_OK; + mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + if(!mNotifyEvent) hr = E_FAIL; + + //DirectSound Init code + if(SUCCEEDED(hr)) + hr = DirectSoundCreate(guid, &mDS, nullptr); + if(SUCCEEDED(hr)) + hr = mDS->SetCooperativeLevel(GetForegroundWindow(), DSSCL_PRIORITY); + if(FAILED(hr)) + { + ERR("Device init failed: 0x%08lx\n", hr); + return ALC_INVALID_VALUE; + } + + mDevice->DeviceName = name; + return ALC_NO_ERROR; +} + +ALCboolean DSoundPlayback::reset() +{ + if(mNotifies) + mNotifies->Release(); + mNotifies = nullptr; + if(mBuffer) + mBuffer->Release(); + mBuffer = nullptr; + if(mPrimaryBuffer) + mPrimaryBuffer->Release(); + mPrimaryBuffer = nullptr; + + switch(mDevice->FmtType) + { + case DevFmtByte: + mDevice->FmtType = DevFmtUByte; + break; + case DevFmtFloat: + if(mDevice->Flags.get()) + break; + /* fall-through */ + case DevFmtUShort: + mDevice->FmtType = DevFmtShort; + break; + case DevFmtUInt: + mDevice->FmtType = DevFmtInt; + break; + case DevFmtUByte: + case DevFmtShort: + case DevFmtInt: + break; + } + + WAVEFORMATEXTENSIBLE OutputType{}; + DWORD speakers; + HRESULT hr{mDS->GetSpeakerConfig(&speakers)}; + if(SUCCEEDED(hr)) + { + speakers = DSSPEAKER_CONFIG(speakers); + if(!mDevice->Flags.get()) + { + if(speakers == DSSPEAKER_MONO) + mDevice->FmtChans = DevFmtMono; + else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE) + mDevice->FmtChans = DevFmtStereo; + else if(speakers == DSSPEAKER_QUAD) + mDevice->FmtChans = DevFmtQuad; + else if(speakers == DSSPEAKER_5POINT1_SURROUND) + mDevice->FmtChans = DevFmtX51; + else if(speakers == DSSPEAKER_5POINT1_BACK) + mDevice->FmtChans = DevFmtX51Rear; + else if(speakers == DSSPEAKER_7POINT1 || speakers == DSSPEAKER_7POINT1_SURROUND) + mDevice->FmtChans = DevFmtX71; + else + ERR("Unknown system speaker config: 0x%lx\n", speakers); + } + mDevice->IsHeadphones = (mDevice->FmtChans == DevFmtStereo && + speakers == DSSPEAKER_HEADPHONE); + + switch(mDevice->FmtChans) + { + case DevFmtMono: + OutputType.dwChannelMask = SPEAKER_FRONT_CENTER; + break; + case DevFmtAmbi3D: + mDevice->FmtChans = DevFmtStereo; + /*fall-through*/ + case DevFmtStereo: + OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT; + break; + case DevFmtQuad: + OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT; + break; + case DevFmtX51: + OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + break; + case DevFmtX51Rear: + OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT; + break; + case DevFmtX61: + OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_CENTER | + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + break; + case DevFmtX71: + OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT | + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + break; + } + +retry_open: + hr = S_OK; + OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; + OutputType.Format.nChannels = mDevice->channelsFromFmt(); + OutputType.Format.wBitsPerSample = mDevice->bytesFromFmt() * 8; + OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8; + OutputType.Format.nSamplesPerSec = mDevice->Frequency; + OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign; + OutputType.Format.cbSize = 0; + } + + if(OutputType.Format.nChannels > 2 || mDevice->FmtType == DevFmtFloat) + { + OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; + OutputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); + if(mDevice->FmtType == DevFmtFloat) + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + else + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + + if(mPrimaryBuffer) + mPrimaryBuffer->Release(); + mPrimaryBuffer = nullptr; + } + else + { + if(SUCCEEDED(hr) && !mPrimaryBuffer) + { + DSBUFFERDESC DSBDescription{}; + DSBDescription.dwSize = sizeof(DSBDescription); + DSBDescription.dwFlags = DSBCAPS_PRIMARYBUFFER; + hr = mDS->CreateSoundBuffer(&DSBDescription, &mPrimaryBuffer, nullptr); + } + if(SUCCEEDED(hr)) + hr = mPrimaryBuffer->SetFormat(&OutputType.Format); + } + + if(SUCCEEDED(hr)) + { + ALuint num_updates{mDevice->BufferSize / mDevice->UpdateSize}; + if(num_updates > MAX_UPDATES) + num_updates = MAX_UPDATES; + mDevice->BufferSize = mDevice->UpdateSize * num_updates; + + DSBUFFERDESC DSBDescription{}; + DSBDescription.dwSize = sizeof(DSBDescription); + DSBDescription.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2 | + DSBCAPS_GLOBALFOCUS; + DSBDescription.dwBufferBytes = mDevice->BufferSize * OutputType.Format.nBlockAlign; + DSBDescription.lpwfxFormat = &OutputType.Format; + + hr = mDS->CreateSoundBuffer(&DSBDescription, &mBuffer, nullptr); + if(FAILED(hr) && mDevice->FmtType == DevFmtFloat) + { + mDevice->FmtType = DevFmtShort; + goto retry_open; + } + } + + if(SUCCEEDED(hr)) + { + void *ptr; + hr = mBuffer->QueryInterface(IID_IDirectSoundNotify, &ptr); + if(SUCCEEDED(hr)) + { + auto Notifies = static_cast(ptr); + mNotifies = Notifies; + + ALuint num_updates{mDevice->BufferSize / mDevice->UpdateSize}; + assert(num_updates <= MAX_UPDATES); + + std::array nots; + for(ALuint i{0};i < num_updates;++i) + { + nots[i].dwOffset = i * mDevice->UpdateSize * OutputType.Format.nBlockAlign; + nots[i].hEventNotify = mNotifyEvent; + } + if(Notifies->SetNotificationPositions(num_updates, nots.data()) != DS_OK) + hr = E_FAIL; + } + } + + if(FAILED(hr)) + { + if(mNotifies) + mNotifies->Release(); + mNotifies = nullptr; + if(mBuffer) + mBuffer->Release(); + mBuffer = nullptr; + if(mPrimaryBuffer) + mPrimaryBuffer->Release(); + mPrimaryBuffer = nullptr; + return ALC_FALSE; + } + + ResetEvent(mNotifyEvent); + SetDefaultWFXChannelOrder(mDevice); + + return ALC_TRUE; +} + +ALCboolean DSoundPlayback::start() +{ + try { + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&DSoundPlayback::mixerProc), this}; + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Failed to start mixing thread: %s\n", e.what()); + } + catch(...) { + } + return ALC_FALSE; +} + +void DSoundPlayback::stop() +{ + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) + return; + mThread.join(); + + mBuffer->Stop(); +} + + +struct DSoundCapture final : public BackendBase { + DSoundCapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~DSoundCapture() override; + + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + + IDirectSoundCapture *mDSC{nullptr}; + IDirectSoundCaptureBuffer *mDSCbuffer{nullptr}; + DWORD mBufferBytes{0u}; + DWORD mCursor{0u}; + + RingBufferPtr mRing; + + DEF_NEWDEL(DSoundCapture) +}; + +DSoundCapture::~DSoundCapture() +{ + if(mDSCbuffer) + { + mDSCbuffer->Stop(); + mDSCbuffer->Release(); + mDSCbuffer = nullptr; + } + + if(mDSC) + mDSC->Release(); + mDSC = nullptr; +} + + +ALCenum DSoundCapture::open(const ALCchar *name) +{ + HRESULT hr; + if(CaptureDevices.empty()) + { + /* Initialize COM to prevent name truncation */ + HRESULT hrcom{CoInitialize(nullptr)}; + hr = DirectSoundCaptureEnumerateW(DSoundEnumDevices, &CaptureDevices); + if(FAILED(hr)) + ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr); + if(SUCCEEDED(hrcom)) + CoUninitialize(); + } + + const GUID *guid{nullptr}; + if(!name && !CaptureDevices.empty()) + { + name = CaptureDevices[0].name.c_str(); + guid = &CaptureDevices[0].guid; + } + else + { + auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), + [name](const DevMap &entry) -> bool + { return entry.name == name; } + ); + if(iter == CaptureDevices.cend()) + return ALC_INVALID_VALUE; + guid = &iter->guid; + } + + switch(mDevice->FmtType) + { + case DevFmtByte: + case DevFmtUShort: + case DevFmtUInt: + WARN("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); + return ALC_INVALID_ENUM; + + case DevFmtUByte: + case DevFmtShort: + case DevFmtInt: + case DevFmtFloat: + break; + } + + WAVEFORMATEXTENSIBLE InputType{}; + switch(mDevice->FmtChans) + { + case DevFmtMono: + InputType.dwChannelMask = SPEAKER_FRONT_CENTER; + break; + case DevFmtStereo: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT; + break; + case DevFmtQuad: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT; + break; + case DevFmtX51: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + break; + case DevFmtX51Rear: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT; + break; + case DevFmtX61: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_CENTER | + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + break; + case DevFmtX71: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT | + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + break; + case DevFmtAmbi3D: + WARN("%s capture not supported\n", DevFmtChannelsString(mDevice->FmtChans)); + return ALC_INVALID_ENUM; + } + + InputType.Format.wFormatTag = WAVE_FORMAT_PCM; + InputType.Format.nChannels = mDevice->channelsFromFmt(); + InputType.Format.wBitsPerSample = mDevice->bytesFromFmt() * 8; + InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8; + InputType.Format.nSamplesPerSec = mDevice->Frequency; + InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign; + InputType.Format.cbSize = 0; + InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample; + if(mDevice->FmtType == DevFmtFloat) + InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + else + InputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + + if(InputType.Format.nChannels > 2 || mDevice->FmtType == DevFmtFloat) + { + InputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); + } + + ALuint samples{mDevice->BufferSize}; + samples = maxu(samples, 100 * mDevice->Frequency / 1000); + + DSCBUFFERDESC DSCBDescription{}; + DSCBDescription.dwSize = sizeof(DSCBDescription); + DSCBDescription.dwFlags = 0; + DSCBDescription.dwBufferBytes = samples * InputType.Format.nBlockAlign; + DSCBDescription.lpwfxFormat = &InputType.Format; + + //DirectSoundCapture Init code + hr = DirectSoundCaptureCreate(guid, &mDSC, nullptr); + if(SUCCEEDED(hr)) + mDSC->CreateCaptureBuffer(&DSCBDescription, &mDSCbuffer, nullptr); + if(SUCCEEDED(hr)) + { + mRing = CreateRingBuffer(mDevice->BufferSize, InputType.Format.nBlockAlign, false); + if(!mRing) hr = DSERR_OUTOFMEMORY; + } + + if(FAILED(hr)) + { + ERR("Device init failed: 0x%08lx\n", hr); + + mRing = nullptr; + if(mDSCbuffer) + mDSCbuffer->Release(); + mDSCbuffer = nullptr; + if(mDSC) + mDSC->Release(); + mDSC = nullptr; + + return ALC_INVALID_VALUE; + } + + mBufferBytes = DSCBDescription.dwBufferBytes; + SetDefaultWFXChannelOrder(mDevice); + + mDevice->DeviceName = name; + return ALC_NO_ERROR; +} + +ALCboolean DSoundCapture::start() +{ + HRESULT hr{mDSCbuffer->Start(DSCBSTART_LOOPING)}; + if(FAILED(hr)) + { + ERR("start failed: 0x%08lx\n", hr); + aluHandleDisconnect(mDevice, "Failure starting capture: 0x%lx", hr); + return ALC_FALSE; + } + return ALC_TRUE; +} + +void DSoundCapture::stop() +{ + HRESULT hr{mDSCbuffer->Stop()}; + if(FAILED(hr)) + { + ERR("stop failed: 0x%08lx\n", hr); + aluHandleDisconnect(mDevice, "Failure stopping capture: 0x%lx", hr); + } +} + +ALCenum DSoundCapture::captureSamples(void *buffer, ALCuint samples) +{ + mRing->read(buffer, samples); + return ALC_NO_ERROR; +} + +ALCuint DSoundCapture::availableSamples() +{ + if(!mDevice->Connected.load(std::memory_order_acquire)) + return static_cast(mRing->readSpace()); + + ALsizei FrameSize{mDevice->frameSizeFromFmt()}; + DWORD BufferBytes{mBufferBytes}; + DWORD LastCursor{mCursor}; + + DWORD ReadCursor; + void *ReadPtr1, *ReadPtr2; + DWORD ReadCnt1, ReadCnt2; + HRESULT hr{mDSCbuffer->GetCurrentPosition(nullptr, &ReadCursor)}; + if(SUCCEEDED(hr)) + { + DWORD NumBytes{(ReadCursor-LastCursor + BufferBytes) % BufferBytes}; + if(!NumBytes) return static_cast(mRing->readSpace()); + hr = mDSCbuffer->Lock(LastCursor, NumBytes, &ReadPtr1, &ReadCnt1, &ReadPtr2, &ReadCnt2, 0); + } + if(SUCCEEDED(hr)) + { + mRing->write(ReadPtr1, ReadCnt1/FrameSize); + if(ReadPtr2 != nullptr && ReadCnt2 > 0) + mRing->write(ReadPtr2, ReadCnt2/FrameSize); + hr = mDSCbuffer->Unlock(ReadPtr1, ReadCnt1, ReadPtr2, ReadCnt2); + mCursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes; + } + + if(FAILED(hr)) + { + ERR("update failed: 0x%08lx\n", hr); + aluHandleDisconnect(mDevice, "Failure retrieving capture data: 0x%lx", hr); + } + + return static_cast(mRing->readSpace()); +} + +} // namespace + + +BackendFactory &DSoundBackendFactory::getFactory() +{ + static DSoundBackendFactory factory{}; + return factory; +} + +bool DSoundBackendFactory::init() +{ +#ifdef HAVE_DYNLOAD + if(!ds_handle) + { + ds_handle = LoadLib("dsound.dll"); + if(!ds_handle) + { + ERR("Failed to load dsound.dll\n"); + return false; + } + +#define LOAD_FUNC(f) do { \ + p##f = reinterpret_cast(GetSymbol(ds_handle, #f)); \ + if(!p##f) \ + { \ + CloseLib(ds_handle); \ + ds_handle = nullptr; \ + return false; \ + } \ +} while(0) + LOAD_FUNC(DirectSoundCreate); + LOAD_FUNC(DirectSoundEnumerateW); + LOAD_FUNC(DirectSoundCaptureCreate); + LOAD_FUNC(DirectSoundCaptureEnumerateW); +#undef LOAD_FUNC + } +#endif + return true; +} + +bool DSoundBackendFactory::querySupport(BackendType type) +{ return (type == BackendType::Playback || type == BackendType::Capture); } + +void DSoundBackendFactory::probe(DevProbe type, std::string *outnames) +{ + auto add_device = [outnames](const DevMap &entry) -> void + { + /* +1 to also append the null char (to ensure a null-separated list and + * double-null terminated list). + */ + outnames->append(entry.name.c_str(), entry.name.length()+1); + }; + + /* Initialize COM to prevent name truncation */ + HRESULT hr; + HRESULT hrcom{CoInitialize(nullptr)}; + switch(type) + { + case DevProbe::Playback: + PlaybackDevices.clear(); + hr = DirectSoundEnumerateW(DSoundEnumDevices, &PlaybackDevices); + if(FAILED(hr)) + ERR("Error enumerating DirectSound playback devices (0x%lx)!\n", hr); + std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); + break; + + case DevProbe::Capture: + CaptureDevices.clear(); + hr = DirectSoundCaptureEnumerateW(DSoundEnumDevices, &CaptureDevices); + if(FAILED(hr)) + ERR("Error enumerating DirectSound capture devices (0x%lx)!\n", hr); + std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); + break; + } + if(SUCCEEDED(hrcom)) + CoUninitialize(); +} + +BackendPtr DSoundBackendFactory::createBackend(ALCdevice *device, BackendType type) +{ + if(type == BackendType::Playback) + return BackendPtr{new DSoundPlayback{device}}; + if(type == BackendType::Capture) + return BackendPtr{new DSoundCapture{device}}; + return nullptr; +} diff --git a/alc/backends/dsound.h b/alc/backends/dsound.h new file mode 100644 index 00000000..6bef0bfc --- /dev/null +++ b/alc/backends/dsound.h @@ -0,0 +1,19 @@ +#ifndef BACKENDS_DSOUND_H +#define BACKENDS_DSOUND_H + +#include "backends/base.h" + +struct DSoundBackendFactory final : public BackendFactory { +public: + bool init() override; + + bool querySupport(BackendType type) override; + + void probe(DevProbe type, std::string *outnames) override; + + BackendPtr createBackend(ALCdevice *device, BackendType type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_DSOUND_H */ diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp new file mode 100644 index 00000000..3f81d08c --- /dev/null +++ b/alc/backends/jack.cpp @@ -0,0 +1,562 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "backends/jack.h" + +#include +#include +#include + +#include +#include + +#include "alcmain.h" +#include "alu.h" +#include "alconfig.h" +#include "ringbuffer.h" +#include "threads.h" +#include "compat.h" + +#include +#include + + +namespace { + +constexpr ALCchar jackDevice[] = "JACK Default"; + + +#ifdef HAVE_DYNLOAD +#define JACK_FUNCS(MAGIC) \ + MAGIC(jack_client_open); \ + MAGIC(jack_client_close); \ + MAGIC(jack_client_name_size); \ + MAGIC(jack_get_client_name); \ + MAGIC(jack_connect); \ + MAGIC(jack_activate); \ + MAGIC(jack_deactivate); \ + MAGIC(jack_port_register); \ + MAGIC(jack_port_unregister); \ + MAGIC(jack_port_get_buffer); \ + MAGIC(jack_port_name); \ + MAGIC(jack_get_ports); \ + MAGIC(jack_free); \ + MAGIC(jack_get_sample_rate); \ + MAGIC(jack_set_error_function); \ + MAGIC(jack_set_process_callback); \ + MAGIC(jack_set_buffer_size_callback); \ + MAGIC(jack_set_buffer_size); \ + MAGIC(jack_get_buffer_size); + +void *jack_handle; +#define MAKE_FUNC(f) decltype(f) * p##f +JACK_FUNCS(MAKE_FUNC); +decltype(jack_error_callback) * pjack_error_callback; +#undef MAKE_FUNC + +#ifndef IN_IDE_PARSER +#define jack_client_open pjack_client_open +#define jack_client_close pjack_client_close +#define jack_client_name_size pjack_client_name_size +#define jack_get_client_name pjack_get_client_name +#define jack_connect pjack_connect +#define jack_activate pjack_activate +#define jack_deactivate pjack_deactivate +#define jack_port_register pjack_port_register +#define jack_port_unregister pjack_port_unregister +#define jack_port_get_buffer pjack_port_get_buffer +#define jack_port_name pjack_port_name +#define jack_get_ports pjack_get_ports +#define jack_free pjack_free +#define jack_get_sample_rate pjack_get_sample_rate +#define jack_set_error_function pjack_set_error_function +#define jack_set_process_callback pjack_set_process_callback +#define jack_set_buffer_size_callback pjack_set_buffer_size_callback +#define jack_set_buffer_size pjack_set_buffer_size +#define jack_get_buffer_size pjack_get_buffer_size +#define jack_error_callback (*pjack_error_callback) +#endif +#endif + + +jack_options_t ClientOptions = JackNullOption; + +ALCboolean jack_load() +{ + ALCboolean error = ALC_FALSE; + +#ifdef HAVE_DYNLOAD + if(!jack_handle) + { + std::string missing_funcs; + +#ifdef _WIN32 +#define JACKLIB "libjack.dll" +#else +#define JACKLIB "libjack.so.0" +#endif + jack_handle = LoadLib(JACKLIB); + if(!jack_handle) + { + WARN("Failed to load %s\n", JACKLIB); + return ALC_FALSE; + } + + error = ALC_FALSE; +#define LOAD_FUNC(f) do { \ + p##f = reinterpret_cast(GetSymbol(jack_handle, #f)); \ + if(p##f == nullptr) { \ + error = ALC_TRUE; \ + missing_funcs += "\n" #f; \ + } \ +} while(0) + JACK_FUNCS(LOAD_FUNC); +#undef LOAD_FUNC + /* Optional symbols. These don't exist in all versions of JACK. */ +#define LOAD_SYM(f) p##f = reinterpret_cast(GetSymbol(jack_handle, #f)) + LOAD_SYM(jack_error_callback); +#undef LOAD_SYM + + if(error) + { + WARN("Missing expected functions:%s\n", missing_funcs.c_str()); + CloseLib(jack_handle); + jack_handle = nullptr; + } + } +#endif + + return !error; +} + + +struct JackPlayback final : public BackendBase { + JackPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~JackPlayback() override; + + static int bufferSizeNotifyC(jack_nframes_t numframes, void *arg); + int bufferSizeNotify(jack_nframes_t numframes); + + static int processC(jack_nframes_t numframes, void *arg); + int process(jack_nframes_t numframes); + + int mixerProc(); + + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + ClockLatency getClockLatency() override; + + jack_client_t *mClient{nullptr}; + jack_port_t *mPort[MAX_OUTPUT_CHANNELS]{}; + + RingBufferPtr mRing; + al::semaphore mSem; + + std::atomic mKillNow{true}; + std::thread mThread; + + DEF_NEWDEL(JackPlayback) +}; + +JackPlayback::~JackPlayback() +{ + if(!mClient) + return; + + std::for_each(std::begin(mPort), std::end(mPort), + [this](jack_port_t *port) -> void + { if(port) jack_port_unregister(mClient, port); } + ); + std::fill(std::begin(mPort), std::end(mPort), nullptr); + jack_client_close(mClient); + mClient = nullptr; +} + + +int JackPlayback::bufferSizeNotifyC(jack_nframes_t numframes, void *arg) +{ return static_cast(arg)->bufferSizeNotify(numframes); } + +int JackPlayback::bufferSizeNotify(jack_nframes_t numframes) +{ + std::lock_guard _{mDevice->StateLock}; + mDevice->UpdateSize = numframes; + mDevice->BufferSize = numframes*2; + + const char *devname{mDevice->DeviceName.c_str()}; + ALuint bufsize{ConfigValueUInt(devname, "jack", "buffer-size").value_or(mDevice->UpdateSize)}; + bufsize = maxu(NextPowerOf2(bufsize), mDevice->UpdateSize); + mDevice->BufferSize = bufsize + mDevice->UpdateSize; + + TRACE("%u / %u buffer\n", mDevice->UpdateSize, mDevice->BufferSize); + + mRing = nullptr; + mRing = CreateRingBuffer(bufsize, mDevice->frameSizeFromFmt(), true); + if(!mRing) + { + ERR("Failed to reallocate ringbuffer\n"); + aluHandleDisconnect(mDevice, "Failed to reallocate %u-sample buffer", bufsize); + } + return 0; +} + + +int JackPlayback::processC(jack_nframes_t numframes, void *arg) +{ return static_cast(arg)->process(numframes); } + +int JackPlayback::process(jack_nframes_t numframes) +{ + jack_default_audio_sample_t *out[MAX_OUTPUT_CHANNELS]; + ALsizei numchans{0}; + for(auto port : mPort) + { + if(!port) break; + out[numchans++] = static_cast(jack_port_get_buffer(port, numframes)); + } + + auto data = mRing->getReadVector(); + jack_nframes_t todo{minu(numframes, data.first.len)}; + std::transform(out, out+numchans, out, + [&data,numchans,todo](ALfloat *outbuf) -> ALfloat* + { + const ALfloat *RESTRICT in = reinterpret_cast(data.first.buf); + std::generate_n(outbuf, todo, + [&in,numchans]() noexcept -> ALfloat + { + ALfloat ret{*in}; + in += numchans; + return ret; + } + ); + data.first.buf += sizeof(ALfloat); + return outbuf + todo; + } + ); + jack_nframes_t total{todo}; + + todo = minu(numframes-total, data.second.len); + if(todo > 0) + { + std::transform(out, out+numchans, out, + [&data,numchans,todo](ALfloat *outbuf) -> ALfloat* + { + const ALfloat *RESTRICT in = reinterpret_cast(data.second.buf); + std::generate_n(outbuf, todo, + [&in,numchans]() noexcept -> ALfloat + { + ALfloat ret{*in}; + in += numchans; + return ret; + } + ); + data.second.buf += sizeof(ALfloat); + return outbuf + todo; + } + ); + total += todo; + } + + mRing->readAdvance(total); + mSem.post(); + + if(numframes > total) + { + todo = numframes-total; + std::transform(out, out+numchans, out, + [todo](ALfloat *outbuf) -> ALfloat* + { + std::fill_n(outbuf, todo, 0.0f); + return outbuf + todo; + } + ); + } + + return 0; +} + +int JackPlayback::mixerProc() +{ + SetRTPriority(); + althrd_setname(MIXER_THREAD_NAME); + + lock(); + while(!mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) + { + if(mRing->writeSpace() < mDevice->UpdateSize) + { + unlock(); + mSem.wait(); + lock(); + continue; + } + + auto data = mRing->getWriteVector(); + auto todo = static_cast(data.first.len + data.second.len); + todo -= todo%mDevice->UpdateSize; + + ALuint len1{minu(data.first.len, todo)}; + ALuint len2{minu(data.second.len, todo-len1)}; + + aluMixData(mDevice, data.first.buf, len1); + if(len2 > 0) + aluMixData(mDevice, data.second.buf, len2); + mRing->writeAdvance(todo); + } + unlock(); + + return 0; +} + + +ALCenum JackPlayback::open(const ALCchar *name) +{ + if(!name) + name = jackDevice; + else if(strcmp(name, jackDevice) != 0) + return ALC_INVALID_VALUE; + + const char *client_name{"alsoft"}; + jack_status_t status; + mClient = jack_client_open(client_name, ClientOptions, &status, nullptr); + if(mClient == nullptr) + { + ERR("jack_client_open() failed, status = 0x%02x\n", status); + return ALC_INVALID_VALUE; + } + if((status&JackServerStarted)) + TRACE("JACK server started\n"); + if((status&JackNameNotUnique)) + { + client_name = jack_get_client_name(mClient); + TRACE("Client name not unique, got `%s' instead\n", client_name); + } + + jack_set_process_callback(mClient, &JackPlayback::processC, this); + jack_set_buffer_size_callback(mClient, &JackPlayback::bufferSizeNotifyC, this); + + mDevice->DeviceName = name; + return ALC_NO_ERROR; +} + +ALCboolean JackPlayback::reset() +{ + std::for_each(std::begin(mPort), std::end(mPort), + [this](jack_port_t *port) -> void + { if(port) jack_port_unregister(mClient, port); } + ); + std::fill(std::begin(mPort), std::end(mPort), nullptr); + + /* Ignore the requested buffer metrics and just keep one JACK-sized buffer + * ready for when requested. + */ + mDevice->Frequency = jack_get_sample_rate(mClient); + mDevice->UpdateSize = jack_get_buffer_size(mClient); + mDevice->BufferSize = mDevice->UpdateSize * 2; + + const char *devname{mDevice->DeviceName.c_str()}; + ALuint bufsize{ConfigValueUInt(devname, "jack", "buffer-size").value_or(mDevice->UpdateSize)}; + bufsize = maxu(NextPowerOf2(bufsize), mDevice->UpdateSize); + mDevice->BufferSize = bufsize + mDevice->UpdateSize; + + /* Force 32-bit float output. */ + mDevice->FmtType = DevFmtFloat; + + ALsizei numchans{mDevice->channelsFromFmt()}; + auto ports_end = std::begin(mPort) + numchans; + auto bad_port = std::find_if_not(std::begin(mPort), ports_end, + [this](jack_port_t *&port) -> bool + { + std::string name{"channel_" + std::to_string(&port - mPort + 1)}; + port = jack_port_register(mClient, name.c_str(), JACK_DEFAULT_AUDIO_TYPE, + JackPortIsOutput, 0); + return port != nullptr; + } + ); + if(bad_port != ports_end) + { + ERR("Not enough JACK ports available for %s output\n", DevFmtChannelsString(mDevice->FmtChans)); + if(bad_port == std::begin(mPort)) return ALC_FALSE; + + if(bad_port == std::begin(mPort)+1) + mDevice->FmtChans = DevFmtMono; + else + { + ports_end = mPort+2; + while(bad_port != ports_end) + { + jack_port_unregister(mClient, *(--bad_port)); + *bad_port = nullptr; + } + mDevice->FmtChans = DevFmtStereo; + } + numchans = std::distance(std::begin(mPort), bad_port); + } + + mRing = nullptr; + mRing = CreateRingBuffer(bufsize, mDevice->frameSizeFromFmt(), true); + if(!mRing) + { + ERR("Failed to allocate ringbuffer\n"); + return ALC_FALSE; + } + + SetDefaultChannelOrder(mDevice); + + return ALC_TRUE; +} + +ALCboolean JackPlayback::start() +{ + if(jack_activate(mClient)) + { + ERR("Failed to activate client\n"); + return ALC_FALSE; + } + + const char **ports{jack_get_ports(mClient, nullptr, nullptr, + JackPortIsPhysical|JackPortIsInput)}; + if(ports == nullptr) + { + ERR("No physical playback ports found\n"); + jack_deactivate(mClient); + return ALC_FALSE; + } + std::mismatch(std::begin(mPort), std::end(mPort), ports, + [this](const jack_port_t *port, const char *pname) -> bool + { + if(!port) return false; + if(!pname) + { + ERR("No physical playback port for \"%s\"\n", jack_port_name(port)); + return false; + } + if(jack_connect(mClient, jack_port_name(port), pname)) + ERR("Failed to connect output port \"%s\" to \"%s\"\n", jack_port_name(port), + pname); + return true; + } + ); + jack_free(ports); + + try { + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&JackPlayback::mixerProc), this}; + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Could not create playback thread: %s\n", e.what()); + } + catch(...) { + } + jack_deactivate(mClient); + return ALC_FALSE; +} + +void JackPlayback::stop() +{ + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) + return; + + mSem.post(); + mThread.join(); + + jack_deactivate(mClient); +} + + +ClockLatency JackPlayback::getClockLatency() +{ + ClockLatency ret; + + lock(); + ret.ClockTime = GetDeviceClockTime(mDevice); + ret.Latency = std::chrono::seconds{mRing->readSpace()}; + ret.Latency /= mDevice->Frequency; + unlock(); + + return ret; +} + + +void jack_msg_handler(const char *message) +{ + WARN("%s\n", message); +} + +} // namespace + +bool JackBackendFactory::init() +{ + if(!jack_load()) + return false; + + if(!GetConfigValueBool(nullptr, "jack", "spawn-server", 0)) + ClientOptions = static_cast(ClientOptions | JackNoStartServer); + + void (*old_error_cb)(const char*){&jack_error_callback ? jack_error_callback : nullptr}; + jack_set_error_function(jack_msg_handler); + jack_status_t status; + jack_client_t *client{jack_client_open("alsoft", ClientOptions, &status, nullptr)}; + jack_set_error_function(old_error_cb); + if(!client) + { + WARN("jack_client_open() failed, 0x%02x\n", status); + if((status&JackServerFailed) && !(ClientOptions&JackNoStartServer)) + ERR("Unable to connect to JACK server\n"); + return false; + } + + jack_client_close(client); + return true; +} + +bool JackBackendFactory::querySupport(BackendType type) +{ return (type == BackendType::Playback); } + +void JackBackendFactory::probe(DevProbe type, std::string *outnames) +{ + switch(type) + { + case DevProbe::Playback: + /* Includes null char. */ + outnames->append(jackDevice, sizeof(jackDevice)); + break; + + case DevProbe::Capture: + break; + } +} + +BackendPtr JackBackendFactory::createBackend(ALCdevice *device, BackendType type) +{ + if(type == BackendType::Playback) + return BackendPtr{new JackPlayback{device}}; + return nullptr; +} + +BackendFactory &JackBackendFactory::getFactory() +{ + static JackBackendFactory factory{}; + return factory; +} diff --git a/alc/backends/jack.h b/alc/backends/jack.h new file mode 100644 index 00000000..10beebfb --- /dev/null +++ b/alc/backends/jack.h @@ -0,0 +1,19 @@ +#ifndef BACKENDS_JACK_H +#define BACKENDS_JACK_H + +#include "backends/base.h" + +struct JackBackendFactory final : public BackendFactory { +public: + bool init() override; + + bool querySupport(BackendType type) override; + + void probe(DevProbe type, std::string *outnames) override; + + BackendPtr createBackend(ALCdevice *device, BackendType type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_JACK_H */ diff --git a/alc/backends/loopback.cpp b/alc/backends/loopback.cpp new file mode 100644 index 00000000..4a1c641a --- /dev/null +++ b/alc/backends/loopback.cpp @@ -0,0 +1,80 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2011 by Chris Robinson + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "backends/loopback.h" + +#include "alcmain.h" +#include "alu.h" + + +namespace { + +struct LoopbackBackend final : public BackendBase { + LoopbackBackend(ALCdevice *device) noexcept : BackendBase{device} { } + + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + + DEF_NEWDEL(LoopbackBackend) +}; + + +ALCenum LoopbackBackend::open(const ALCchar *name) +{ + mDevice->DeviceName = name; + return ALC_NO_ERROR; +} + +ALCboolean LoopbackBackend::reset() +{ + SetDefaultWFXChannelOrder(mDevice); + return ALC_TRUE; +} + +ALCboolean LoopbackBackend::start() +{ return ALC_TRUE; } + +void LoopbackBackend::stop() +{ } + +} // namespace + + +bool LoopbackBackendFactory::init() +{ return true; } + +bool LoopbackBackendFactory::querySupport(BackendType) +{ return true; } + +void LoopbackBackendFactory::probe(DevProbe, std::string*) +{ } + +BackendPtr LoopbackBackendFactory::createBackend(ALCdevice *device, BackendType) +{ return BackendPtr{new LoopbackBackend{device}}; } + +BackendFactory &LoopbackBackendFactory::getFactory() +{ + static LoopbackBackendFactory factory{}; + return factory; +} diff --git a/alc/backends/loopback.h b/alc/backends/loopback.h new file mode 100644 index 00000000..09c085b8 --- /dev/null +++ b/alc/backends/loopback.h @@ -0,0 +1,19 @@ +#ifndef BACKENDS_LOOPBACK_H +#define BACKENDS_LOOPBACK_H + +#include "backends/base.h" + +struct LoopbackBackendFactory final : public BackendFactory { +public: + bool init() override; + + bool querySupport(BackendType type) override; + + void probe(DevProbe type, std::string *outnames) override; + + BackendPtr createBackend(ALCdevice *device, BackendType type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_LOOPBACK_H */ diff --git a/alc/backends/null.cpp b/alc/backends/null.cpp new file mode 100644 index 00000000..ae58cb8b --- /dev/null +++ b/alc/backends/null.cpp @@ -0,0 +1,184 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2010 by Chris Robinson + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "backends/null.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "alcmain.h" +#include "almalloc.h" +#include "alu.h" +#include "logging.h" +#include "threads.h" + + +namespace { + +using std::chrono::seconds; +using std::chrono::milliseconds; +using std::chrono::nanoseconds; + +constexpr ALCchar nullDevice[] = "No Output"; + + +struct NullBackend final : public BackendBase { + NullBackend(ALCdevice *device) noexcept : BackendBase{device} { } + + int mixerProc(); + + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + + std::atomic mKillNow{true}; + std::thread mThread; + + DEF_NEWDEL(NullBackend) +}; + +int NullBackend::mixerProc() +{ + const milliseconds restTime{mDevice->UpdateSize*1000/mDevice->Frequency / 2}; + + SetRTPriority(); + althrd_setname(MIXER_THREAD_NAME); + + int64_t done{0}; + auto start = std::chrono::steady_clock::now(); + while(!mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) + { + auto now = std::chrono::steady_clock::now(); + + /* This converts from nanoseconds to nanosamples, then to samples. */ + int64_t avail{std::chrono::duration_cast((now-start) * mDevice->Frequency).count()}; + if(avail-done < mDevice->UpdateSize) + { + std::this_thread::sleep_for(restTime); + continue; + } + while(avail-done >= mDevice->UpdateSize) + { + lock(); + aluMixData(mDevice, nullptr, mDevice->UpdateSize); + unlock(); + done += mDevice->UpdateSize; + } + + /* For every completed second, increment the start time and reduce the + * samples done. This prevents the difference between the start time + * and current time from growing too large, while maintaining the + * correct number of samples to render. + */ + if(done >= mDevice->Frequency) + { + seconds s{done/mDevice->Frequency}; + start += s; + done -= mDevice->Frequency*s.count(); + } + } + + return 0; +} + + +ALCenum NullBackend::open(const ALCchar *name) +{ + if(!name) + name = nullDevice; + else if(strcmp(name, nullDevice) != 0) + return ALC_INVALID_VALUE; + + mDevice->DeviceName = name; + + return ALC_NO_ERROR; +} + +ALCboolean NullBackend::reset() +{ + SetDefaultWFXChannelOrder(mDevice); + return ALC_TRUE; +} + +ALCboolean NullBackend::start() +{ + try { + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&NullBackend::mixerProc), this}; + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Failed to start mixing thread: %s\n", e.what()); + } + catch(...) { + } + return ALC_FALSE; +} + +void NullBackend::stop() +{ + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) + return; + mThread.join(); +} + +} // namespace + + +bool NullBackendFactory::init() +{ return true; } + +bool NullBackendFactory::querySupport(BackendType type) +{ return (type == BackendType::Playback); } + +void NullBackendFactory::probe(DevProbe type, std::string *outnames) +{ + switch(type) + { + case DevProbe::Playback: + /* Includes null char. */ + outnames->append(nullDevice, sizeof(nullDevice)); + break; + case DevProbe::Capture: + break; + } +} + +BackendPtr NullBackendFactory::createBackend(ALCdevice *device, BackendType type) +{ + if(type == BackendType::Playback) + return BackendPtr{new NullBackend{device}}; + return nullptr; +} + +BackendFactory &NullBackendFactory::getFactory() +{ + static NullBackendFactory factory{}; + return factory; +} diff --git a/alc/backends/null.h b/alc/backends/null.h new file mode 100644 index 00000000..f19d5b4d --- /dev/null +++ b/alc/backends/null.h @@ -0,0 +1,19 @@ +#ifndef BACKENDS_NULL_H +#define BACKENDS_NULL_H + +#include "backends/base.h" + +struct NullBackendFactory final : public BackendFactory { +public: + bool init() override; + + bool querySupport(BackendType type) override; + + void probe(DevProbe type, std::string *outnames) override; + + BackendPtr createBackend(ALCdevice *device, BackendType type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_NULL_H */ diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp new file mode 100644 index 00000000..b34dc0cb --- /dev/null +++ b/alc/backends/opensl.cpp @@ -0,0 +1,936 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* This is an OpenAL backend for Android using the native audio APIs based on + * OpenSL ES 1.0.1. It is based on source code for the native-audio sample app + * bundled with NDK. + */ + +#include "config.h" + +#include "backends/opensl.h" + +#include +#include + +#include +#include +#include +#include + +#include "alcmain.h" +#include "alu.h" +#include "ringbuffer.h" +#include "threads.h" +#include "compat.h" + +#include +#include +#include + + +namespace { + +/* Helper macros */ +#define EXTRACT_VCALL_ARGS(...) __VA_ARGS__)) +#define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS +#define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS + + +constexpr ALCchar opensl_device[] = "OpenSL"; + + +SLuint32 GetChannelMask(DevFmtChannels chans) +{ + switch(chans) + { + case DevFmtMono: return SL_SPEAKER_FRONT_CENTER; + case DevFmtStereo: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT; + case DevFmtQuad: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| + SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; + case DevFmtX51: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| + SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| + SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; + case DevFmtX51Rear: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| + SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| + SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; + case DevFmtX61: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| + SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| + SL_SPEAKER_BACK_CENTER| + SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; + case DevFmtX71: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| + SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| + SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT| + SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; + case DevFmtAmbi3D: + break; + } + return 0; +} + +#ifdef SL_ANDROID_DATAFORMAT_PCM_EX +SLuint32 GetTypeRepresentation(DevFmtType type) +{ + switch(type) + { + case DevFmtUByte: + case DevFmtUShort: + case DevFmtUInt: + return SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT; + case DevFmtByte: + case DevFmtShort: + case DevFmtInt: + return SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT; + case DevFmtFloat: + return SL_ANDROID_PCM_REPRESENTATION_FLOAT; + } + return 0; +} +#endif + +const char *res_str(SLresult result) +{ + switch(result) + { + case SL_RESULT_SUCCESS: return "Success"; + case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated"; + case SL_RESULT_PARAMETER_INVALID: return "Parameter invalid"; + case SL_RESULT_MEMORY_FAILURE: return "Memory failure"; + case SL_RESULT_RESOURCE_ERROR: return "Resource error"; + case SL_RESULT_RESOURCE_LOST: return "Resource lost"; + case SL_RESULT_IO_ERROR: return "I/O error"; + case SL_RESULT_BUFFER_INSUFFICIENT: return "Buffer insufficient"; + case SL_RESULT_CONTENT_CORRUPTED: return "Content corrupted"; + case SL_RESULT_CONTENT_UNSUPPORTED: return "Content unsupported"; + case SL_RESULT_CONTENT_NOT_FOUND: return "Content not found"; + case SL_RESULT_PERMISSION_DENIED: return "Permission denied"; + case SL_RESULT_FEATURE_UNSUPPORTED: return "Feature unsupported"; + case SL_RESULT_INTERNAL_ERROR: return "Internal error"; + case SL_RESULT_UNKNOWN_ERROR: return "Unknown error"; + case SL_RESULT_OPERATION_ABORTED: return "Operation aborted"; + case SL_RESULT_CONTROL_LOST: return "Control lost"; +#ifdef SL_RESULT_READONLY + case SL_RESULT_READONLY: return "ReadOnly"; +#endif +#ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED + case SL_RESULT_ENGINEOPTION_UNSUPPORTED: return "Engine option unsupported"; +#endif +#ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE + case SL_RESULT_SOURCE_SINK_INCOMPATIBLE: return "Source/Sink incompatible"; +#endif + } + return "Unknown error code"; +} + +#define PRINTERR(x, s) do { \ + if(UNLIKELY((x) != SL_RESULT_SUCCESS)) \ + ERR("%s: %s\n", (s), res_str((x))); \ +} while(0) + + +struct OpenSLPlayback final : public BackendBase { + OpenSLPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~OpenSLPlayback() override; + + static void processC(SLAndroidSimpleBufferQueueItf bq, void *context); + void process(SLAndroidSimpleBufferQueueItf bq); + + int mixerProc(); + + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + ClockLatency getClockLatency() override; + + /* engine interfaces */ + SLObjectItf mEngineObj{nullptr}; + SLEngineItf mEngine{nullptr}; + + /* output mix interfaces */ + SLObjectItf mOutputMix{nullptr}; + + /* buffer queue player interfaces */ + SLObjectItf mBufferQueueObj{nullptr}; + + RingBufferPtr mRing{nullptr}; + al::semaphore mSem; + + ALsizei mFrameSize{0}; + + std::atomic mKillNow{true}; + std::thread mThread; + + DEF_NEWDEL(OpenSLPlayback) +}; + +OpenSLPlayback::~OpenSLPlayback() +{ + if(mBufferQueueObj) + VCALL0(mBufferQueueObj,Destroy)(); + mBufferQueueObj = nullptr; + + if(mOutputMix) + VCALL0(mOutputMix,Destroy)(); + mOutputMix = nullptr; + + if(mEngineObj) + VCALL0(mEngineObj,Destroy)(); + mEngineObj = nullptr; + mEngine = nullptr; +} + + +/* this callback handler is called every time a buffer finishes playing */ +void OpenSLPlayback::processC(SLAndroidSimpleBufferQueueItf bq, void *context) +{ static_cast(context)->process(bq); } + +void OpenSLPlayback::process(SLAndroidSimpleBufferQueueItf) +{ + /* A note on the ringbuffer usage: The buffer queue seems to hold on to the + * pointer passed to the Enqueue method, rather than copying the audio. + * Consequently, the ringbuffer contains the audio that is currently queued + * and waiting to play. This process() callback is called when a buffer is + * finished, so we simply move the read pointer up to indicate the space is + * available for writing again, and wake up the mixer thread to mix and + * queue more audio. + */ + mRing->readAdvance(1); + + mSem.post(); +} + +int OpenSLPlayback::mixerProc() +{ + SetRTPriority(); + althrd_setname(MIXER_THREAD_NAME); + + SLPlayItf player; + SLAndroidSimpleBufferQueueItf bufferQueue; + SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &bufferQueue)}; + PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE"); + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player); + PRINTERR(result, "bufferQueue->GetInterface SL_IID_PLAY"); + } + + lock(); + if(SL_RESULT_SUCCESS != result) + aluHandleDisconnect(mDevice, "Failed to get playback buffer: 0x%08x", result); + + while(SL_RESULT_SUCCESS == result && !mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) + { + if(mRing->writeSpace() == 0) + { + SLuint32 state{0}; + + result = VCALL(player,GetPlayState)(&state); + PRINTERR(result, "player->GetPlayState"); + if(SL_RESULT_SUCCESS == result && state != SL_PLAYSTATE_PLAYING) + { + result = VCALL(player,SetPlayState)(SL_PLAYSTATE_PLAYING); + PRINTERR(result, "player->SetPlayState"); + } + if(SL_RESULT_SUCCESS != result) + { + aluHandleDisconnect(mDevice, "Failed to start platback: 0x%08x", result); + break; + } + + if(mRing->writeSpace() == 0) + { + unlock(); + mSem.wait(); + lock(); + continue; + } + } + + auto data = mRing->getWriteVector(); + aluMixData(mDevice, data.first.buf, data.first.len*mDevice->UpdateSize); + if(data.second.len > 0) + aluMixData(mDevice, data.second.buf, data.second.len*mDevice->UpdateSize); + + size_t todo{data.first.len + data.second.len}; + mRing->writeAdvance(todo); + + for(size_t i{0};i < todo;i++) + { + if(!data.first.len) + { + data.first = data.second; + data.second.buf = nullptr; + data.second.len = 0; + } + + result = VCALL(bufferQueue,Enqueue)(data.first.buf, mDevice->UpdateSize*mFrameSize); + PRINTERR(result, "bufferQueue->Enqueue"); + if(SL_RESULT_SUCCESS != result) + { + aluHandleDisconnect(mDevice, "Failed to queue audio: 0x%08x", result); + break; + } + + data.first.len--; + data.first.buf += mDevice->UpdateSize*mFrameSize; + } + } + unlock(); + + return 0; +} + + +ALCenum OpenSLPlayback::open(const ALCchar *name) +{ + if(!name) + name = opensl_device; + else if(strcmp(name, opensl_device) != 0) + return ALC_INVALID_VALUE; + + // create engine + SLresult result{slCreateEngine(&mEngineObj, 0, nullptr, 0, nullptr, nullptr)}; + PRINTERR(result, "slCreateEngine"); + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(mEngineObj,Realize)(SL_BOOLEAN_FALSE); + PRINTERR(result, "engine->Realize"); + } + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(mEngineObj,GetInterface)(SL_IID_ENGINE, &mEngine); + PRINTERR(result, "engine->GetInterface"); + } + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(mEngine,CreateOutputMix)(&mOutputMix, 0, nullptr, nullptr); + PRINTERR(result, "engine->CreateOutputMix"); + } + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(mOutputMix,Realize)(SL_BOOLEAN_FALSE); + PRINTERR(result, "outputMix->Realize"); + } + + if(SL_RESULT_SUCCESS != result) + { + if(mOutputMix) + VCALL0(mOutputMix,Destroy)(); + mOutputMix = nullptr; + + if(mEngineObj) + VCALL0(mEngineObj,Destroy)(); + mEngineObj = nullptr; + mEngine = nullptr; + + return ALC_INVALID_VALUE; + } + + mDevice->DeviceName = name; + return ALC_NO_ERROR; +} + +ALCboolean OpenSLPlayback::reset() +{ + SLDataLocator_AndroidSimpleBufferQueue loc_bufq; + SLDataLocator_OutputMix loc_outmix; + SLDataSource audioSrc; + SLDataSink audioSnk; + SLresult result; + + if(mBufferQueueObj) + VCALL0(mBufferQueueObj,Destroy)(); + mBufferQueueObj = nullptr; + + mRing = nullptr; + +#if 0 + if(!mDevice->Flags.get()) + { + /* FIXME: Disabled until I figure out how to get the Context needed for + * the getSystemService call. + */ + JNIEnv *env = Android_GetJNIEnv(); + jobject jctx = Android_GetContext(); + + /* Get necessary stuff for using java.lang.Integer, + * android.content.Context, and android.media.AudioManager. + */ + jclass int_cls = JCALL(env,FindClass)("java/lang/Integer"); + jmethodID int_parseint = JCALL(env,GetStaticMethodID)(int_cls, + "parseInt", "(Ljava/lang/String;)I" + ); + TRACE("Integer: %p, parseInt: %p\n", int_cls, int_parseint); + + jclass ctx_cls = JCALL(env,FindClass)("android/content/Context"); + jfieldID ctx_audsvc = JCALL(env,GetStaticFieldID)(ctx_cls, + "AUDIO_SERVICE", "Ljava/lang/String;" + ); + jmethodID ctx_getSysSvc = JCALL(env,GetMethodID)(ctx_cls, + "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;" + ); + TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n", + ctx_cls, ctx_audsvc, ctx_getSysSvc); + + jclass audmgr_cls = JCALL(env,FindClass)("android/media/AudioManager"); + jfieldID audmgr_prop_out_srate = JCALL(env,GetStaticFieldID)(audmgr_cls, + "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;" + ); + jmethodID audmgr_getproperty = JCALL(env,GetMethodID)(audmgr_cls, + "getProperty", "(Ljava/lang/String;)Ljava/lang/String;" + ); + TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n", + audmgr_cls, audmgr_prop_out_srate, audmgr_getproperty); + + const char *strchars; + jstring strobj; + + /* Now make the calls. */ + //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE); + strobj = JCALL(env,GetStaticObjectField)(ctx_cls, ctx_audsvc); + jobject audMgr = JCALL(env,CallObjectMethod)(jctx, ctx_getSysSvc, strobj); + strchars = JCALL(env,GetStringUTFChars)(strobj, nullptr); + TRACE("Context.getSystemService(%s) = %p\n", strchars, audMgr); + JCALL(env,ReleaseStringUTFChars)(strobj, strchars); + + //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE); + strobj = JCALL(env,GetStaticObjectField)(audmgr_cls, audmgr_prop_out_srate); + jstring srateStr = JCALL(env,CallObjectMethod)(audMgr, audmgr_getproperty, strobj); + strchars = JCALL(env,GetStringUTFChars)(strobj, nullptr); + TRACE("audMgr.getProperty(%s) = %p\n", strchars, srateStr); + JCALL(env,ReleaseStringUTFChars)(strobj, strchars); + + //int sampleRate = Integer.parseInt(srateStr); + sampleRate = JCALL(env,CallStaticIntMethod)(int_cls, int_parseint, srateStr); + + strchars = JCALL(env,GetStringUTFChars)(srateStr, nullptr); + TRACE("Got system sample rate %uhz (%s)\n", sampleRate, strchars); + JCALL(env,ReleaseStringUTFChars)(srateStr, strchars); + + if(!sampleRate) sampleRate = device->Frequency; + else sampleRate = maxu(sampleRate, MIN_OUTPUT_RATE); + } +#endif + + mDevice->FmtChans = DevFmtStereo; + mDevice->FmtType = DevFmtShort; + + SetDefaultWFXChannelOrder(mDevice); + mFrameSize = mDevice->frameSizeFromFmt(); + + + const std::array ids{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }}; + const std::array reqs{{ SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }}; + + loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; + loc_bufq.numBuffers = mDevice->BufferSize / mDevice->UpdateSize; + +#ifdef SL_ANDROID_DATAFORMAT_PCM_EX + SLAndroidDataFormat_PCM_EX format_pcm{}; + format_pcm.formatType = SL_ANDROID_DATAFORMAT_PCM_EX; + format_pcm.numChannels = mDevice->channelsFromFmt(); + format_pcm.sampleRate = mDevice->Frequency * 1000; + format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; + format_pcm.containerSize = format_pcm.bitsPerSample; + format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); + format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : + SL_BYTEORDER_BIGENDIAN; + format_pcm.representation = GetTypeRepresentation(mDevice->FmtType); +#else + SLDataFormat_PCM format_pcm{}; + format_pcm.formatType = SL_DATAFORMAT_PCM; + format_pcm.numChannels = mDevice->channelsFromFmt(); + format_pcm.samplesPerSec = mDevice->Frequency * 1000; + format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; + format_pcm.containerSize = format_pcm.bitsPerSample; + format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); + format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : + SL_BYTEORDER_BIGENDIAN; +#endif + + audioSrc.pLocator = &loc_bufq; + audioSrc.pFormat = &format_pcm; + + loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; + loc_outmix.outputMix = mOutputMix; + audioSnk.pLocator = &loc_outmix; + audioSnk.pFormat = nullptr; + + + result = VCALL(mEngine,CreateAudioPlayer)(&mBufferQueueObj, &audioSrc, &audioSnk, ids.size(), + ids.data(), reqs.data()); + PRINTERR(result, "engine->CreateAudioPlayer"); + if(SL_RESULT_SUCCESS == result) + { + /* Set the stream type to "media" (games, music, etc), if possible. */ + SLAndroidConfigurationItf config; + result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config); + PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION"); + if(SL_RESULT_SUCCESS == result) + { + SLint32 streamType = SL_ANDROID_STREAM_MEDIA; + result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_STREAM_TYPE, &streamType, + sizeof(streamType)); + PRINTERR(result, "config->SetConfiguration"); + } + + /* Clear any error since this was optional. */ + result = SL_RESULT_SUCCESS; + } + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(mBufferQueueObj,Realize)(SL_BOOLEAN_FALSE); + PRINTERR(result, "bufferQueue->Realize"); + } + if(SL_RESULT_SUCCESS == result) + { + const ALuint num_updates{mDevice->BufferSize / mDevice->UpdateSize}; + try { + mRing = CreateRingBuffer(num_updates, mFrameSize*mDevice->UpdateSize, true); + } + catch(std::exception& e) { + ERR("Failed allocating ring buffer %ux%ux%u: %s\n", mDevice->UpdateSize, + num_updates, mFrameSize, e.what()); + result = SL_RESULT_MEMORY_FAILURE; + } + } + + if(SL_RESULT_SUCCESS != result) + { + if(mBufferQueueObj) + VCALL0(mBufferQueueObj,Destroy)(); + mBufferQueueObj = nullptr; + + return ALC_FALSE; + } + + return ALC_TRUE; +} + +ALCboolean OpenSLPlayback::start() +{ + mRing->reset(); + + SLAndroidSimpleBufferQueueItf bufferQueue; + SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &bufferQueue)}; + PRINTERR(result, "bufferQueue->GetInterface"); + if(SL_RESULT_SUCCESS != result) + return ALC_FALSE; + + result = VCALL(bufferQueue,RegisterCallback)(&OpenSLPlayback::processC, this); + PRINTERR(result, "bufferQueue->RegisterCallback"); + if(SL_RESULT_SUCCESS != result) return ALC_FALSE; + + try { + mKillNow.store(false, std::memory_order_release); + mThread = std::thread(std::mem_fn(&OpenSLPlayback::mixerProc), this); + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Could not create playback thread: %s\n", e.what()); + } + catch(...) { + } + return ALC_FALSE; +} + +void OpenSLPlayback::stop() +{ + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) + return; + + mSem.post(); + mThread.join(); + + SLPlayItf player; + SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player)}; + PRINTERR(result, "bufferQueue->GetInterface"); + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(player,SetPlayState)(SL_PLAYSTATE_STOPPED); + PRINTERR(result, "player->SetPlayState"); + } + + SLAndroidSimpleBufferQueueItf bufferQueue; + result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); + PRINTERR(result, "bufferQueue->GetInterface"); + if(SL_RESULT_SUCCESS == result) + { + result = VCALL0(bufferQueue,Clear)(); + PRINTERR(result, "bufferQueue->Clear"); + } + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(bufferQueue,RegisterCallback)(nullptr, nullptr); + PRINTERR(result, "bufferQueue->RegisterCallback"); + } + if(SL_RESULT_SUCCESS == result) + { + SLAndroidSimpleBufferQueueState state; + do { + std::this_thread::yield(); + result = VCALL(bufferQueue,GetState)(&state); + } while(SL_RESULT_SUCCESS == result && state.count > 0); + PRINTERR(result, "bufferQueue->GetState"); + } +} + +ClockLatency OpenSLPlayback::getClockLatency() +{ + ClockLatency ret; + + lock(); + ret.ClockTime = GetDeviceClockTime(mDevice); + ret.Latency = std::chrono::seconds{mRing->readSpace() * mDevice->UpdateSize}; + ret.Latency /= mDevice->Frequency; + unlock(); + + return ret; +} + + +struct OpenSLCapture final : public BackendBase { + OpenSLCapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~OpenSLCapture() override; + + static void processC(SLAndroidSimpleBufferQueueItf bq, void *context); + void process(SLAndroidSimpleBufferQueueItf bq); + + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + + /* engine interfaces */ + SLObjectItf mEngineObj{nullptr}; + SLEngineItf mEngine; + + /* recording interfaces */ + SLObjectItf mRecordObj{nullptr}; + + RingBufferPtr mRing{nullptr}; + ALCuint mSplOffset{0u}; + + ALsizei mFrameSize{0}; + + DEF_NEWDEL(OpenSLCapture) +}; + +OpenSLCapture::~OpenSLCapture() +{ + if(mRecordObj) + VCALL0(mRecordObj,Destroy)(); + mRecordObj = nullptr; + + if(mEngineObj) + VCALL0(mEngineObj,Destroy)(); + mEngineObj = nullptr; + mEngine = nullptr; +} + + +void OpenSLCapture::processC(SLAndroidSimpleBufferQueueItf bq, void *context) +{ static_cast(context)->process(bq); } + +void OpenSLCapture::process(SLAndroidSimpleBufferQueueItf) +{ + /* A new chunk has been written into the ring buffer, advance it. */ + mRing->writeAdvance(1); +} + + +ALCenum OpenSLCapture::open(const ALCchar* name) +{ + if(!name) + name = opensl_device; + else if(strcmp(name, opensl_device) != 0) + return ALC_INVALID_VALUE; + + SLresult result{slCreateEngine(&mEngineObj, 0, nullptr, 0, nullptr, nullptr)}; + PRINTERR(result, "slCreateEngine"); + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(mEngineObj,Realize)(SL_BOOLEAN_FALSE); + PRINTERR(result, "engine->Realize"); + } + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(mEngineObj,GetInterface)(SL_IID_ENGINE, &mEngine); + PRINTERR(result, "engine->GetInterface"); + } + if(SL_RESULT_SUCCESS == result) + { + mFrameSize = mDevice->frameSizeFromFmt(); + /* Ensure the total length is at least 100ms */ + ALsizei length{maxi(mDevice->BufferSize, mDevice->Frequency/10)}; + /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */ + ALsizei update_len{clampi(mDevice->BufferSize/3, mDevice->Frequency/100, + mDevice->Frequency/100*5)}; + ALsizei num_updates{(length+update_len-1) / update_len}; + + try { + mRing = CreateRingBuffer(num_updates, update_len*mFrameSize, false); + + mDevice->UpdateSize = update_len; + mDevice->BufferSize = mRing->writeSpace() * update_len; + } + catch(std::exception& e) { + ERR("Failed to allocate ring buffer: %s\n", e.what()); + result = SL_RESULT_MEMORY_FAILURE; + } + } + if(SL_RESULT_SUCCESS == result) + { + const std::array ids{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }}; + const std::array reqs{{ SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }}; + + SLDataLocator_IODevice loc_dev{}; + loc_dev.locatorType = SL_DATALOCATOR_IODEVICE; + loc_dev.deviceType = SL_IODEVICE_AUDIOINPUT; + loc_dev.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT; + loc_dev.device = nullptr; + + SLDataSource audioSrc{}; + audioSrc.pLocator = &loc_dev; + audioSrc.pFormat = nullptr; + + SLDataLocator_AndroidSimpleBufferQueue loc_bq{}; + loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; + loc_bq.numBuffers = mDevice->BufferSize / mDevice->UpdateSize; + +#ifdef SL_ANDROID_DATAFORMAT_PCM_EX + SLAndroidDataFormat_PCM_EX format_pcm{}; + format_pcm.formatType = SL_ANDROID_DATAFORMAT_PCM_EX; + format_pcm.numChannels = mDevice->channelsFromFmt(); + format_pcm.sampleRate = mDevice->Frequency * 1000; + format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; + format_pcm.containerSize = format_pcm.bitsPerSample; + format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); + format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; + format_pcm.representation = GetTypeRepresentation(mDevice->FmtType); +#else + SLDataFormat_PCM format_pcm{}; + format_pcm.formatType = SL_DATAFORMAT_PCM; + format_pcm.numChannels = mDevice->channelsFromFmt(); + format_pcm.samplesPerSec = mDevice->Frequency * 1000; + format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; + format_pcm.containerSize = format_pcm.bitsPerSample; + format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); + format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; +#endif + + SLDataSink audioSnk{}; + audioSnk.pLocator = &loc_bq; + audioSnk.pFormat = &format_pcm; + + result = VCALL(mEngine,CreateAudioRecorder)(&mRecordObj, &audioSrc, &audioSnk, + ids.size(), ids.data(), reqs.data()); + PRINTERR(result, "engine->CreateAudioRecorder"); + } + if(SL_RESULT_SUCCESS == result) + { + /* Set the record preset to "generic", if possible. */ + SLAndroidConfigurationItf config; + result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config); + PRINTERR(result, "recordObj->GetInterface SL_IID_ANDROIDCONFIGURATION"); + if(SL_RESULT_SUCCESS == result) + { + SLuint32 preset = SL_ANDROID_RECORDING_PRESET_GENERIC; + result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_RECORDING_PRESET, &preset, + sizeof(preset)); + PRINTERR(result, "config->SetConfiguration"); + } + + /* Clear any error since this was optional. */ + result = SL_RESULT_SUCCESS; + } + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(mRecordObj,Realize)(SL_BOOLEAN_FALSE); + PRINTERR(result, "recordObj->Realize"); + } + + SLAndroidSimpleBufferQueueItf bufferQueue; + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); + PRINTERR(result, "recordObj->GetInterface"); + } + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(bufferQueue,RegisterCallback)(&OpenSLCapture::processC, this); + PRINTERR(result, "bufferQueue->RegisterCallback"); + } + if(SL_RESULT_SUCCESS == result) + { + const ALuint chunk_size{mDevice->UpdateSize * mFrameSize}; + + auto data = mRing->getWriteVector(); + for(size_t i{0u};i < data.first.len && SL_RESULT_SUCCESS == result;i++) + { + result = VCALL(bufferQueue,Enqueue)(data.first.buf + chunk_size*i, chunk_size); + PRINTERR(result, "bufferQueue->Enqueue"); + } + for(size_t i{0u};i < data.second.len && SL_RESULT_SUCCESS == result;i++) + { + result = VCALL(bufferQueue,Enqueue)(data.second.buf + chunk_size*i, chunk_size); + PRINTERR(result, "bufferQueue->Enqueue"); + } + } + + if(SL_RESULT_SUCCESS != result) + { + if(mRecordObj) + VCALL0(mRecordObj,Destroy)(); + mRecordObj = nullptr; + + if(mEngineObj) + VCALL0(mEngineObj,Destroy)(); + mEngineObj = nullptr; + mEngine = nullptr; + + return ALC_INVALID_VALUE; + } + + mDevice->DeviceName = name; + return ALC_NO_ERROR; +} + +ALCboolean OpenSLCapture::start() +{ + SLRecordItf record; + SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_RECORD, &record)}; + PRINTERR(result, "recordObj->GetInterface"); + + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(record,SetRecordState)(SL_RECORDSTATE_RECORDING); + PRINTERR(result, "record->SetRecordState"); + } + + if(SL_RESULT_SUCCESS != result) + { + aluHandleDisconnect(mDevice, "Failed to start capture: 0x%08x", result); + return ALC_FALSE; + } + + return ALC_TRUE; +} + +void OpenSLCapture::stop() +{ + SLRecordItf record; + SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_RECORD, &record)}; + PRINTERR(result, "recordObj->GetInterface"); + + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(record,SetRecordState)(SL_RECORDSTATE_PAUSED); + PRINTERR(result, "record->SetRecordState"); + } +} + +ALCenum OpenSLCapture::captureSamples(void* buffer, ALCuint samples) +{ + ALsizei chunk_size = mDevice->UpdateSize * mFrameSize; + SLAndroidSimpleBufferQueueItf bufferQueue; + SLresult result; + ALCuint i; + + result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); + PRINTERR(result, "recordObj->GetInterface"); + + /* Read the desired samples from the ring buffer then advance its read + * pointer. + */ + auto data = mRing->getReadVector(); + for(i = 0;i < samples;) + { + ALCuint rem{minu(samples - i, mDevice->UpdateSize - mSplOffset)}; + memcpy((ALCbyte*)buffer + i*mFrameSize, data.first.buf + mSplOffset*mFrameSize, + rem * mFrameSize); + + mSplOffset += rem; + if(mSplOffset == mDevice->UpdateSize) + { + /* Finished a chunk, reset the offset and advance the read pointer. */ + mSplOffset = 0; + + mRing->readAdvance(1); + result = VCALL(bufferQueue,Enqueue)(data.first.buf, chunk_size); + PRINTERR(result, "bufferQueue->Enqueue"); + if(SL_RESULT_SUCCESS != result) break; + + data.first.len--; + if(!data.first.len) + data.first = data.second; + else + data.first.buf += chunk_size; + } + + i += rem; + } + + if(SL_RESULT_SUCCESS != result) + { + aluHandleDisconnect(mDevice, "Failed to update capture buffer: 0x%08x", result); + return ALC_INVALID_DEVICE; + } + + return ALC_NO_ERROR; +} + +ALCuint OpenSLCapture::availableSamples() +{ return mRing->readSpace()*mDevice->UpdateSize - mSplOffset; } + +} // namespace + +bool OSLBackendFactory::init() { return true; } + +bool OSLBackendFactory::querySupport(BackendType type) +{ return (type == BackendType::Playback || type == BackendType::Capture); } + +void OSLBackendFactory::probe(DevProbe type, std::string *outnames) +{ + switch(type) + { + case DevProbe::Playback: + case DevProbe::Capture: + /* Includes null char. */ + outnames->append(opensl_device, sizeof(opensl_device)); + break; + } +} + +BackendPtr OSLBackendFactory::createBackend(ALCdevice *device, BackendType type) +{ + if(type == BackendType::Playback) + return BackendPtr{new OpenSLPlayback{device}}; + if(type == BackendType::Capture) + return BackendPtr{new OpenSLCapture{device}}; + return nullptr; +} + +BackendFactory &OSLBackendFactory::getFactory() +{ + static OSLBackendFactory factory{}; + return factory; +} diff --git a/alc/backends/opensl.h b/alc/backends/opensl.h new file mode 100644 index 00000000..809aa339 --- /dev/null +++ b/alc/backends/opensl.h @@ -0,0 +1,19 @@ +#ifndef BACKENDS_OSL_H +#define BACKENDS_OSL_H + +#include "backends/base.h" + +struct OSLBackendFactory final : public BackendFactory { +public: + bool init() override; + + bool querySupport(BackendType type) override; + + void probe(DevProbe type, std::string *outnames) override; + + BackendPtr createBackend(ALCdevice *device, BackendType type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_OSL_H */ diff --git a/alc/backends/oss.cpp b/alc/backends/oss.cpp new file mode 100644 index 00000000..8cfe9e96 --- /dev/null +++ b/alc/backends/oss.cpp @@ -0,0 +1,751 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "backends/oss.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" + +#include "alcmain.h" +#include "alconfig.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "aloptional.h" +#include "alu.h" +#include "logging.h" +#include "ringbuffer.h" +#include "threads.h" +#include "vector.h" + +#include + +/* + * The OSS documentation talks about SOUND_MIXER_READ, but the header + * only contains MIXER_READ. Play safe. Same for WRITE. + */ +#ifndef SOUND_MIXER_READ +#define SOUND_MIXER_READ MIXER_READ +#endif +#ifndef SOUND_MIXER_WRITE +#define SOUND_MIXER_WRITE MIXER_WRITE +#endif + +#if defined(SOUND_VERSION) && (SOUND_VERSION < 0x040000) +#define ALC_OSS_COMPAT +#endif +#ifndef SNDCTL_AUDIOINFO +#define ALC_OSS_COMPAT +#endif + +/* + * FreeBSD strongly discourages the use of specific devices, + * such as those returned in oss_audioinfo.devnode + */ +#ifdef __FreeBSD__ +#define ALC_OSS_DEVNODE_TRUC +#endif + +namespace { + +constexpr char DefaultName[] = "OSS Default"; +std::string DefaultPlayback{"/dev/dsp"}; +std::string DefaultCapture{"/dev/dsp"}; + +struct DevMap { + std::string name; + std::string device_name; +}; + +bool checkName(const al::vector &list, const std::string &name) +{ + return std::find_if(list.cbegin(), list.cend(), + [&name](const DevMap &entry) -> bool + { return entry.name == name; } + ) != list.cend(); +} + +al::vector PlaybackDevices; +al::vector CaptureDevices; + + +#ifdef ALC_OSS_COMPAT + +#define DSP_CAP_OUTPUT 0x00020000 +#define DSP_CAP_INPUT 0x00010000 +void ALCossListPopulate(al::vector *devlist, int type) +{ + devlist->emplace_back(DevMap{DefaultName, (type==DSP_CAP_INPUT) ? DefaultCapture : DefaultPlayback}); +} + +#else + +void ALCossListAppend(al::vector *list, const char *handle, size_t hlen, const char *path, size_t plen) +{ +#ifdef ALC_OSS_DEVNODE_TRUC + for(size_t i{0};i < plen;i++) + { + if(path[i] == '.') + { + if(strncmp(path + i, handle + hlen + i - plen, plen - i) == 0) + hlen = hlen + i - plen; + plen = i; + } + } +#endif + if(handle[0] == '\0') + { + handle = path; + hlen = plen; + } + + std::string basename{handle, hlen}; + basename.erase(std::find(basename.begin(), basename.end(), '\0'), basename.end()); + std::string devname{path, plen}; + devname.erase(std::find(devname.begin(), devname.end(), '\0'), devname.end()); + + auto iter = std::find_if(list->cbegin(), list->cend(), + [&devname](const DevMap &entry) -> bool + { return entry.device_name == devname; } + ); + if(iter != list->cend()) + return; + + int count{1}; + std::string newname{basename}; + while(checkName(PlaybackDevices, newname)) + { + newname = basename; + newname += " #"; + newname += std::to_string(++count); + } + + list->emplace_back(DevMap{std::move(newname), std::move(devname)}); + const DevMap &entry = list->back(); + + TRACE("Got device \"%s\", \"%s\"\n", entry.name.c_str(), entry.device_name.c_str()); +} + +void ALCossListPopulate(al::vector *devlist, int type_flag) +{ + int fd{open("/dev/mixer", O_RDONLY)}; + if(fd < 0) + { + TRACE("Could not open /dev/mixer: %s\n", strerror(errno)); + goto done; + } + + oss_sysinfo si; + if(ioctl(fd, SNDCTL_SYSINFO, &si) == -1) + { + TRACE("SNDCTL_SYSINFO failed: %s\n", strerror(errno)); + goto done; + } + + for(int i{0};i < si.numaudios;i++) + { + oss_audioinfo ai; + ai.dev = i; + if(ioctl(fd, SNDCTL_AUDIOINFO, &ai) == -1) + { + ERR("SNDCTL_AUDIOINFO (%d) failed: %s\n", i, strerror(errno)); + continue; + } + if(!(ai.caps&type_flag) || ai.devnode[0] == '\0') + continue; + + const char *handle; + size_t len; + if(ai.handle[0] != '\0') + { + len = strnlen(ai.handle, sizeof(ai.handle)); + handle = ai.handle; + } + else + { + len = strnlen(ai.name, sizeof(ai.name)); + handle = ai.name; + } + + ALCossListAppend(devlist, handle, len, ai.devnode, + strnlen(ai.devnode, sizeof(ai.devnode))); + } + +done: + if(fd >= 0) + close(fd); + fd = -1; + + const char *defdev{((type_flag==DSP_CAP_INPUT) ? DefaultCapture : DefaultPlayback).c_str()}; + auto iter = std::find_if(devlist->cbegin(), devlist->cend(), + [defdev](const DevMap &entry) -> bool + { return entry.device_name == defdev; } + ); + if(iter == devlist->cend()) + devlist->insert(devlist->begin(), DevMap{DefaultName, defdev}); + else + { + DevMap entry{std::move(*iter)}; + devlist->erase(iter); + devlist->insert(devlist->begin(), std::move(entry)); + } + devlist->shrink_to_fit(); +} + +#endif + +int log2i(ALCuint x) +{ + int y = 0; + while (x > 1) + { + x >>= 1; + y++; + } + return y; +} + + +struct OSSPlayback final : public BackendBase { + OSSPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~OSSPlayback() override; + + int mixerProc(); + + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + + int mFd{-1}; + + al::vector mMixData; + + std::atomic mKillNow{true}; + std::thread mThread; + + DEF_NEWDEL(OSSPlayback) +}; + +OSSPlayback::~OSSPlayback() +{ + if(mFd != -1) + close(mFd); + mFd = -1; +} + + +int OSSPlayback::mixerProc() +{ + SetRTPriority(); + althrd_setname(MIXER_THREAD_NAME); + + const int frame_size{mDevice->frameSizeFromFmt()}; + + lock(); + while(!mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) + { + pollfd pollitem{}; + pollitem.fd = mFd; + pollitem.events = POLLOUT; + + unlock(); + int pret{poll(&pollitem, 1, 1000)}; + lock(); + if(pret < 0) + { + if(errno == EINTR || errno == EAGAIN) + continue; + ERR("poll failed: %s\n", strerror(errno)); + aluHandleDisconnect(mDevice, "Failed waiting for playback buffer: %s", strerror(errno)); + break; + } + else if(pret == 0) + { + WARN("poll timeout\n"); + continue; + } + + ALubyte *write_ptr{mMixData.data()}; + size_t to_write{mMixData.size()}; + aluMixData(mDevice, write_ptr, to_write/frame_size); + while(to_write > 0 && !mKillNow.load(std::memory_order_acquire)) + { + ssize_t wrote{write(mFd, write_ptr, to_write)}; + if(wrote < 0) + { + if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) + continue; + ERR("write failed: %s\n", strerror(errno)); + aluHandleDisconnect(mDevice, "Failed writing playback samples: %s", + strerror(errno)); + break; + } + + to_write -= wrote; + write_ptr += wrote; + } + } + unlock(); + + return 0; +} + + +ALCenum OSSPlayback::open(const ALCchar *name) +{ + const char *devname{DefaultPlayback.c_str()}; + if(!name) + name = DefaultName; + else + { + if(PlaybackDevices.empty()) + ALCossListPopulate(&PlaybackDevices, DSP_CAP_OUTPUT); + + auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + [&name](const DevMap &entry) -> bool + { return entry.name == name; } + ); + if(iter == PlaybackDevices.cend()) + return ALC_INVALID_VALUE; + devname = iter->device_name.c_str(); + } + + mFd = ::open(devname, O_WRONLY); + if(mFd == -1) + { + ERR("Could not open %s: %s\n", devname, strerror(errno)); + return ALC_INVALID_VALUE; + } + + mDevice->DeviceName = name; + return ALC_NO_ERROR; +} + +ALCboolean OSSPlayback::reset() +{ + int numFragmentsLogSize; + int log2FragmentSize; + unsigned int periods; + audio_buf_info info; + ALuint frameSize; + int numChannels; + int ossFormat; + int ossSpeed; + const char *err; + + switch(mDevice->FmtType) + { + case DevFmtByte: + ossFormat = AFMT_S8; + break; + case DevFmtUByte: + ossFormat = AFMT_U8; + break; + case DevFmtUShort: + case DevFmtInt: + case DevFmtUInt: + case DevFmtFloat: + mDevice->FmtType = DevFmtShort; + /* fall-through */ + case DevFmtShort: + ossFormat = AFMT_S16_NE; + break; + } + + periods = mDevice->BufferSize / mDevice->UpdateSize; + numChannels = mDevice->channelsFromFmt(); + ossSpeed = mDevice->Frequency; + frameSize = numChannels * mDevice->bytesFromFmt(); + /* According to the OSS spec, 16 bytes (log2(16)) is the minimum. */ + log2FragmentSize = maxi(log2i(mDevice->UpdateSize*frameSize), 4); + numFragmentsLogSize = (periods << 16) | log2FragmentSize; + +#define CHECKERR(func) if((func) < 0) { \ + err = #func; \ + goto err; \ +} + /* Don't fail if SETFRAGMENT fails. We can handle just about anything + * that's reported back via GETOSPACE */ + ioctl(mFd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize); + CHECKERR(ioctl(mFd, SNDCTL_DSP_SETFMT, &ossFormat)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_CHANNELS, &numChannels)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_SPEED, &ossSpeed)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_GETOSPACE, &info)); + if(0) + { + err: + ERR("%s failed: %s\n", err, strerror(errno)); + return ALC_FALSE; + } +#undef CHECKERR + + if(mDevice->channelsFromFmt() != numChannels) + { + ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(mDevice->FmtChans), + numChannels); + return ALC_FALSE; + } + + if(!((ossFormat == AFMT_S8 && mDevice->FmtType == DevFmtByte) || + (ossFormat == AFMT_U8 && mDevice->FmtType == DevFmtUByte) || + (ossFormat == AFMT_S16_NE && mDevice->FmtType == DevFmtShort))) + { + ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(mDevice->FmtType), + ossFormat); + return ALC_FALSE; + } + + mDevice->Frequency = ossSpeed; + mDevice->UpdateSize = info.fragsize / frameSize; + mDevice->BufferSize = info.fragments * mDevice->UpdateSize; + + SetDefaultChannelOrder(mDevice); + + mMixData.resize(mDevice->UpdateSize * mDevice->frameSizeFromFmt()); + + return ALC_TRUE; +} + +ALCboolean OSSPlayback::start() +{ + try { + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&OSSPlayback::mixerProc), this}; + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Could not create playback thread: %s\n", e.what()); + } + catch(...) { + } + return ALC_FALSE; +} + +void OSSPlayback::stop() +{ + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) + return; + mThread.join(); + + if(ioctl(mFd, SNDCTL_DSP_RESET) != 0) + ERR("Error resetting device: %s\n", strerror(errno)); +} + + +struct OSScapture final : public BackendBase { + OSScapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~OSScapture() override; + + int recordProc(); + + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + + int mFd{-1}; + + RingBufferPtr mRing{nullptr}; + + std::atomic mKillNow{true}; + std::thread mThread; + + DEF_NEWDEL(OSScapture) +}; + +OSScapture::~OSScapture() +{ + if(mFd != -1) + close(mFd); + mFd = -1; +} + + +int OSScapture::recordProc() +{ + SetRTPriority(); + althrd_setname(RECORD_THREAD_NAME); + + const int frame_size{mDevice->frameSizeFromFmt()}; + while(!mKillNow.load(std::memory_order_acquire)) + { + pollfd pollitem{}; + pollitem.fd = mFd; + pollitem.events = POLLIN; + + int sret{poll(&pollitem, 1, 1000)}; + if(sret < 0) + { + if(errno == EINTR || errno == EAGAIN) + continue; + ERR("poll failed: %s\n", strerror(errno)); + aluHandleDisconnect(mDevice, "Failed to check capture samples: %s", strerror(errno)); + break; + } + else if(sret == 0) + { + WARN("poll timeout\n"); + continue; + } + + auto vec = mRing->getWriteVector(); + if(vec.first.len > 0) + { + ssize_t amt{read(mFd, vec.first.buf, vec.first.len*frame_size)}; + if(amt < 0) + { + ERR("read failed: %s\n", strerror(errno)); + aluHandleDisconnect(mDevice, "Failed reading capture samples: %s", + strerror(errno)); + break; + } + mRing->writeAdvance(amt/frame_size); + } + } + + return 0; +} + + +ALCenum OSScapture::open(const ALCchar *name) +{ + const char *devname{DefaultCapture.c_str()}; + if(!name) + name = DefaultName; + else + { + if(CaptureDevices.empty()) + ALCossListPopulate(&CaptureDevices, DSP_CAP_INPUT); + + auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), + [&name](const DevMap &entry) -> bool + { return entry.name == name; } + ); + if(iter == CaptureDevices.cend()) + return ALC_INVALID_VALUE; + devname = iter->device_name.c_str(); + } + + mFd = ::open(devname, O_RDONLY); + if(mFd == -1) + { + ERR("Could not open %s: %s\n", devname, strerror(errno)); + return ALC_INVALID_VALUE; + } + + int ossFormat{}; + switch(mDevice->FmtType) + { + case DevFmtByte: + ossFormat = AFMT_S8; + break; + case DevFmtUByte: + ossFormat = AFMT_U8; + break; + case DevFmtShort: + ossFormat = AFMT_S16_NE; + break; + case DevFmtUShort: + case DevFmtInt: + case DevFmtUInt: + case DevFmtFloat: + ERR("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); + return ALC_INVALID_VALUE; + } + + int periods{4}; + int numChannels{mDevice->channelsFromFmt()}; + int frameSize{numChannels * mDevice->bytesFromFmt()}; + int ossSpeed{static_cast(mDevice->Frequency)}; + int log2FragmentSize{log2i(mDevice->BufferSize * frameSize / periods)}; + + /* according to the OSS spec, 16 bytes are the minimum */ + log2FragmentSize = std::max(log2FragmentSize, 4); + int numFragmentsLogSize{(periods << 16) | log2FragmentSize}; + + audio_buf_info info; + const char *err; +#define CHECKERR(func) if((func) < 0) { \ + err = #func; \ + goto err; \ +} + CHECKERR(ioctl(mFd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_SETFMT, &ossFormat)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_CHANNELS, &numChannels)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_SPEED, &ossSpeed)); + CHECKERR(ioctl(mFd, SNDCTL_DSP_GETISPACE, &info)); + if(0) + { + err: + ERR("%s failed: %s\n", err, strerror(errno)); + close(mFd); + mFd = -1; + return ALC_INVALID_VALUE; + } +#undef CHECKERR + + if(mDevice->channelsFromFmt() != numChannels) + { + ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(mDevice->FmtChans), + numChannels); + close(mFd); + mFd = -1; + return ALC_INVALID_VALUE; + } + + if(!((ossFormat == AFMT_S8 && mDevice->FmtType == DevFmtByte) || + (ossFormat == AFMT_U8 && mDevice->FmtType == DevFmtUByte) || + (ossFormat == AFMT_S16_NE && mDevice->FmtType == DevFmtShort))) + { + ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(mDevice->FmtType), ossFormat); + close(mFd); + mFd = -1; + return ALC_INVALID_VALUE; + } + + mRing = CreateRingBuffer(mDevice->BufferSize, frameSize, false); + if(!mRing) + { + ERR("Ring buffer create failed\n"); + close(mFd); + mFd = -1; + return ALC_OUT_OF_MEMORY; + } + + mDevice->DeviceName = name; + return ALC_NO_ERROR; +} + +ALCboolean OSScapture::start() +{ + try { + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&OSScapture::recordProc), this}; + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Could not create record thread: %s\n", e.what()); + } + catch(...) { + } + return ALC_FALSE; +} + +void OSScapture::stop() +{ + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) + return; + mThread.join(); + + if(ioctl(mFd, SNDCTL_DSP_RESET) != 0) + ERR("Error resetting device: %s\n", strerror(errno)); +} + +ALCenum OSScapture::captureSamples(ALCvoid *buffer, ALCuint samples) +{ + mRing->read(buffer, samples); + return ALC_NO_ERROR; +} + +ALCuint OSScapture::availableSamples() +{ return mRing->readSpace(); } + +} // namespace + + +BackendFactory &OSSBackendFactory::getFactory() +{ + static OSSBackendFactory factory{}; + return factory; +} + +bool OSSBackendFactory::init() +{ + if(auto devopt = ConfigValueStr(nullptr, "oss", "device")) + DefaultPlayback = std::move(*devopt); + if(auto capopt = ConfigValueStr(nullptr, "oss", "capture")) + DefaultCapture = std::move(*capopt); + + return true; +} + +bool OSSBackendFactory::querySupport(BackendType type) +{ return (type == BackendType::Playback || type == BackendType::Capture); } + +void OSSBackendFactory::probe(DevProbe type, std::string *outnames) +{ + auto add_device = [outnames](const DevMap &entry) -> void + { +#ifdef HAVE_STAT + struct stat buf; + if(stat(entry.device_name.c_str(), &buf) == 0) +#endif + { + /* Includes null char. */ + outnames->append(entry.name.c_str(), entry.name.length()+1); + } + }; + + switch(type) + { + case DevProbe::Playback: + PlaybackDevices.clear(); + ALCossListPopulate(&PlaybackDevices, DSP_CAP_OUTPUT); + std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); + break; + + case DevProbe::Capture: + CaptureDevices.clear(); + ALCossListPopulate(&CaptureDevices, DSP_CAP_INPUT); + std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); + break; + } +} + +BackendPtr OSSBackendFactory::createBackend(ALCdevice *device, BackendType type) +{ + if(type == BackendType::Playback) + return BackendPtr{new OSSPlayback{device}}; + if(type == BackendType::Capture) + return BackendPtr{new OSScapture{device}}; + return nullptr; +} diff --git a/alc/backends/oss.h b/alc/backends/oss.h new file mode 100644 index 00000000..9e63d7b6 --- /dev/null +++ b/alc/backends/oss.h @@ -0,0 +1,19 @@ +#ifndef BACKENDS_OSS_H +#define BACKENDS_OSS_H + +#include "backends/base.h" + +struct OSSBackendFactory final : public BackendFactory { +public: + bool init() override; + + bool querySupport(BackendType type) override; + + void probe(DevProbe type, std::string *outnames) override; + + BackendPtr createBackend(ALCdevice *device, BackendType type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_OSS_H */ diff --git a/alc/backends/portaudio.cpp b/alc/backends/portaudio.cpp new file mode 100644 index 00000000..73e972c5 --- /dev/null +++ b/alc/backends/portaudio.cpp @@ -0,0 +1,463 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "backends/portaudio.h" + +#include +#include +#include + +#include "alcmain.h" +#include "alu.h" +#include "alconfig.h" +#include "ringbuffer.h" +#include "compat.h" + +#include + + +namespace { + +constexpr ALCchar pa_device[] = "PortAudio Default"; + + +#ifdef HAVE_DYNLOAD +void *pa_handle; +#define MAKE_FUNC(x) decltype(x) * p##x +MAKE_FUNC(Pa_Initialize); +MAKE_FUNC(Pa_Terminate); +MAKE_FUNC(Pa_GetErrorText); +MAKE_FUNC(Pa_StartStream); +MAKE_FUNC(Pa_StopStream); +MAKE_FUNC(Pa_OpenStream); +MAKE_FUNC(Pa_CloseStream); +MAKE_FUNC(Pa_GetDefaultOutputDevice); +MAKE_FUNC(Pa_GetDefaultInputDevice); +MAKE_FUNC(Pa_GetStreamInfo); +#undef MAKE_FUNC + +#ifndef IN_IDE_PARSER +#define Pa_Initialize pPa_Initialize +#define Pa_Terminate pPa_Terminate +#define Pa_GetErrorText pPa_GetErrorText +#define Pa_StartStream pPa_StartStream +#define Pa_StopStream pPa_StopStream +#define Pa_OpenStream pPa_OpenStream +#define Pa_CloseStream pPa_CloseStream +#define Pa_GetDefaultOutputDevice pPa_GetDefaultOutputDevice +#define Pa_GetDefaultInputDevice pPa_GetDefaultInputDevice +#define Pa_GetStreamInfo pPa_GetStreamInfo +#endif +#endif + + +struct PortPlayback final : public BackendBase { + PortPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~PortPlayback() override; + + static int writeCallbackC(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, + const PaStreamCallbackFlags statusFlags, void *userData); + int writeCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags); + + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + + PaStream *mStream{nullptr}; + PaStreamParameters mParams{}; + ALuint mUpdateSize{0u}; + + DEF_NEWDEL(PortPlayback) +}; + +PortPlayback::~PortPlayback() +{ + PaError err{mStream ? Pa_CloseStream(mStream) : paNoError}; + if(err != paNoError) + ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); + mStream = nullptr; +} + + +int PortPlayback::writeCallbackC(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, + const PaStreamCallbackFlags statusFlags, void *userData) +{ + return static_cast(userData)->writeCallback(inputBuffer, outputBuffer, + framesPerBuffer, timeInfo, statusFlags); +} + +int PortPlayback::writeCallback(const void*, void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo*, + const PaStreamCallbackFlags) +{ + lock(); + aluMixData(mDevice, outputBuffer, framesPerBuffer); + unlock(); + return 0; +} + + +ALCenum PortPlayback::open(const ALCchar *name) +{ + if(!name) + name = pa_device; + else if(strcmp(name, pa_device) != 0) + return ALC_INVALID_VALUE; + + mUpdateSize = mDevice->UpdateSize; + + auto devidopt = ConfigValueInt(nullptr, "port", "device"); + if(devidopt && *devidopt >= 0) mParams.device = *devidopt; + else mParams.device = Pa_GetDefaultOutputDevice(); + mParams.suggestedLatency = mDevice->BufferSize / static_cast(mDevice->Frequency); + mParams.hostApiSpecificStreamInfo = nullptr; + + mParams.channelCount = ((mDevice->FmtChans == DevFmtMono) ? 1 : 2); + + switch(mDevice->FmtType) + { + case DevFmtByte: + mParams.sampleFormat = paInt8; + break; + case DevFmtUByte: + mParams.sampleFormat = paUInt8; + break; + case DevFmtUShort: + /* fall-through */ + case DevFmtShort: + mParams.sampleFormat = paInt16; + break; + case DevFmtUInt: + /* fall-through */ + case DevFmtInt: + mParams.sampleFormat = paInt32; + break; + case DevFmtFloat: + mParams.sampleFormat = paFloat32; + break; + } + +retry_open: + PaError err{Pa_OpenStream(&mStream, nullptr, &mParams, mDevice->Frequency, mDevice->UpdateSize, + paNoFlag, &PortPlayback::writeCallbackC, this)}; + if(err != paNoError) + { + if(mParams.sampleFormat == paFloat32) + { + mParams.sampleFormat = paInt16; + goto retry_open; + } + ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); + return ALC_INVALID_VALUE; + } + + mDevice->DeviceName = name; + return ALC_NO_ERROR; + +} + +ALCboolean PortPlayback::reset() +{ + const PaStreamInfo *streamInfo{Pa_GetStreamInfo(mStream)}; + mDevice->Frequency = streamInfo->sampleRate; + mDevice->UpdateSize = mUpdateSize; + + if(mParams.sampleFormat == paInt8) + mDevice->FmtType = DevFmtByte; + else if(mParams.sampleFormat == paUInt8) + mDevice->FmtType = DevFmtUByte; + else if(mParams.sampleFormat == paInt16) + mDevice->FmtType = DevFmtShort; + else if(mParams.sampleFormat == paInt32) + mDevice->FmtType = DevFmtInt; + else if(mParams.sampleFormat == paFloat32) + mDevice->FmtType = DevFmtFloat; + else + { + ERR("Unexpected sample format: 0x%lx\n", mParams.sampleFormat); + return ALC_FALSE; + } + + if(mParams.channelCount == 2) + mDevice->FmtChans = DevFmtStereo; + else if(mParams.channelCount == 1) + mDevice->FmtChans = DevFmtMono; + else + { + ERR("Unexpected channel count: %u\n", mParams.channelCount); + return ALC_FALSE; + } + SetDefaultChannelOrder(mDevice); + + return ALC_TRUE; +} + +ALCboolean PortPlayback::start() +{ + PaError err{Pa_StartStream(mStream)}; + if(err != paNoError) + { + ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err)); + return ALC_FALSE; + } + return ALC_TRUE; +} + +void PortPlayback::stop() +{ + PaError err{Pa_StopStream(mStream)}; + if(err != paNoError) + ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); +} + + +struct PortCapture final : public BackendBase { + PortCapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~PortCapture() override; + + static int readCallbackC(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, + const PaStreamCallbackFlags statusFlags, void *userData); + int readCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags); + + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + + PaStream *mStream{nullptr}; + PaStreamParameters mParams; + + RingBufferPtr mRing{nullptr}; + + DEF_NEWDEL(PortCapture) +}; + +PortCapture::~PortCapture() +{ + PaError err{mStream ? Pa_CloseStream(mStream) : paNoError}; + if(err != paNoError) + ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); + mStream = nullptr; +} + + +int PortCapture::readCallbackC(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, + const PaStreamCallbackFlags statusFlags, void* userData) +{ + return static_cast(userData)->readCallback(inputBuffer, outputBuffer, + framesPerBuffer, timeInfo, statusFlags); +} + +int PortCapture::readCallback(const void *inputBuffer, void*, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo*, + const PaStreamCallbackFlags) +{ + mRing->write(inputBuffer, framesPerBuffer); + return 0; +} + + +ALCenum PortCapture::open(const ALCchar *name) +{ + if(!name) + name = pa_device; + else if(strcmp(name, pa_device) != 0) + return ALC_INVALID_VALUE; + + ALuint samples{mDevice->BufferSize}; + samples = maxu(samples, 100 * mDevice->Frequency / 1000); + ALsizei frame_size{mDevice->frameSizeFromFmt()}; + + mRing = CreateRingBuffer(samples, frame_size, false); + if(!mRing) return ALC_INVALID_VALUE; + + auto devidopt = ConfigValueInt(nullptr, "port", "capture"); + if(devidopt && *devidopt >= 0) mParams.device = *devidopt; + else mParams.device = Pa_GetDefaultOutputDevice(); + mParams.suggestedLatency = 0.0f; + mParams.hostApiSpecificStreamInfo = nullptr; + + switch(mDevice->FmtType) + { + case DevFmtByte: + mParams.sampleFormat = paInt8; + break; + case DevFmtUByte: + mParams.sampleFormat = paUInt8; + break; + case DevFmtShort: + mParams.sampleFormat = paInt16; + break; + case DevFmtInt: + mParams.sampleFormat = paInt32; + break; + case DevFmtFloat: + mParams.sampleFormat = paFloat32; + break; + case DevFmtUInt: + case DevFmtUShort: + ERR("%s samples not supported\n", DevFmtTypeString(mDevice->FmtType)); + return ALC_INVALID_VALUE; + } + mParams.channelCount = mDevice->channelsFromFmt(); + + PaError err{Pa_OpenStream(&mStream, &mParams, nullptr, mDevice->Frequency, + paFramesPerBufferUnspecified, paNoFlag, &PortCapture::readCallbackC, this)}; + if(err != paNoError) + { + ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); + return ALC_INVALID_VALUE; + } + + mDevice->DeviceName = name; + return ALC_NO_ERROR; +} + + +ALCboolean PortCapture::start() +{ + PaError err{Pa_StartStream(mStream)}; + if(err != paNoError) + { + ERR("Error starting stream: %s\n", Pa_GetErrorText(err)); + return ALC_FALSE; + } + return ALC_TRUE; +} + +void PortCapture::stop() +{ + PaError err{Pa_StopStream(mStream)}; + if(err != paNoError) + ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); +} + + +ALCuint PortCapture::availableSamples() +{ return mRing->readSpace(); } + +ALCenum PortCapture::captureSamples(ALCvoid *buffer, ALCuint samples) +{ + mRing->read(buffer, samples); + return ALC_NO_ERROR; +} + +} // namespace + + +bool PortBackendFactory::init() +{ + PaError err; + +#ifdef HAVE_DYNLOAD + if(!pa_handle) + { +#ifdef _WIN32 +# define PALIB "portaudio.dll" +#elif defined(__APPLE__) && defined(__MACH__) +# define PALIB "libportaudio.2.dylib" +#elif defined(__OpenBSD__) +# define PALIB "libportaudio.so" +#else +# define PALIB "libportaudio.so.2" +#endif + + pa_handle = LoadLib(PALIB); + if(!pa_handle) + return false; + +#define LOAD_FUNC(f) do { \ + p##f = reinterpret_cast(GetSymbol(pa_handle, #f)); \ + if(p##f == nullptr) \ + { \ + CloseLib(pa_handle); \ + pa_handle = nullptr; \ + return false; \ + } \ +} while(0) + LOAD_FUNC(Pa_Initialize); + LOAD_FUNC(Pa_Terminate); + LOAD_FUNC(Pa_GetErrorText); + LOAD_FUNC(Pa_StartStream); + LOAD_FUNC(Pa_StopStream); + LOAD_FUNC(Pa_OpenStream); + LOAD_FUNC(Pa_CloseStream); + LOAD_FUNC(Pa_GetDefaultOutputDevice); + LOAD_FUNC(Pa_GetDefaultInputDevice); + LOAD_FUNC(Pa_GetStreamInfo); +#undef LOAD_FUNC + + if((err=Pa_Initialize()) != paNoError) + { + ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err)); + CloseLib(pa_handle); + pa_handle = nullptr; + return false; + } + } +#else + if((err=Pa_Initialize()) != paNoError) + { + ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err)); + return false; + } +#endif + return true; +} + +bool PortBackendFactory::querySupport(BackendType type) +{ return (type == BackendType::Playback || type == BackendType::Capture); } + +void PortBackendFactory::probe(DevProbe type, std::string *outnames) +{ + switch(type) + { + case DevProbe::Playback: + case DevProbe::Capture: + /* Includes null char. */ + outnames->append(pa_device, sizeof(pa_device)); + break; + } +} + +BackendPtr PortBackendFactory::createBackend(ALCdevice *device, BackendType type) +{ + if(type == BackendType::Playback) + return BackendPtr{new PortPlayback{device}}; + if(type == BackendType::Capture) + return BackendPtr{new PortCapture{device}}; + return nullptr; +} + +BackendFactory &PortBackendFactory::getFactory() +{ + static PortBackendFactory factory{}; + return factory; +} diff --git a/alc/backends/portaudio.h b/alc/backends/portaudio.h new file mode 100644 index 00000000..082e9020 --- /dev/null +++ b/alc/backends/portaudio.h @@ -0,0 +1,19 @@ +#ifndef BACKENDS_PORTAUDIO_H +#define BACKENDS_PORTAUDIO_H + +#include "backends/base.h" + +struct PortBackendFactory final : public BackendFactory { +public: + bool init() override; + + bool querySupport(BackendType type) override; + + void probe(DevProbe type, std::string *outnames) override; + + BackendPtr createBackend(ALCdevice *device, BackendType type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_PORTAUDIO_H */ diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp new file mode 100644 index 00000000..da209c8d --- /dev/null +++ b/alc/backends/pulseaudio.cpp @@ -0,0 +1,1532 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2009 by Konstantinos Natsakis + * Copyright (C) 2010 by Chris Robinson + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "backends/pulseaudio.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "alcmain.h" +#include "alu.h" +#include "alconfig.h" +#include "compat.h" +#include "alexcpt.h" + +#include + + +namespace { + +#ifdef HAVE_DYNLOAD +#define PULSE_FUNCS(MAGIC) \ + MAGIC(pa_mainloop_new); \ + MAGIC(pa_mainloop_free); \ + MAGIC(pa_mainloop_set_poll_func); \ + MAGIC(pa_mainloop_run); \ + MAGIC(pa_mainloop_get_api); \ + MAGIC(pa_context_new); \ + MAGIC(pa_context_unref); \ + MAGIC(pa_context_get_state); \ + MAGIC(pa_context_disconnect); \ + MAGIC(pa_context_set_state_callback); \ + MAGIC(pa_context_errno); \ + MAGIC(pa_context_connect); \ + MAGIC(pa_context_get_server_info); \ + MAGIC(pa_context_get_sink_info_by_name); \ + MAGIC(pa_context_get_sink_info_list); \ + MAGIC(pa_context_get_source_info_by_name); \ + MAGIC(pa_context_get_source_info_list); \ + MAGIC(pa_stream_new); \ + MAGIC(pa_stream_unref); \ + MAGIC(pa_stream_drop); \ + MAGIC(pa_stream_get_state); \ + MAGIC(pa_stream_peek); \ + MAGIC(pa_stream_write); \ + MAGIC(pa_stream_connect_record); \ + MAGIC(pa_stream_connect_playback); \ + MAGIC(pa_stream_readable_size); \ + MAGIC(pa_stream_writable_size); \ + MAGIC(pa_stream_is_corked); \ + MAGIC(pa_stream_cork); \ + MAGIC(pa_stream_is_suspended); \ + MAGIC(pa_stream_get_device_name); \ + MAGIC(pa_stream_get_latency); \ + MAGIC(pa_stream_set_write_callback); \ + MAGIC(pa_stream_set_buffer_attr); \ + MAGIC(pa_stream_get_buffer_attr); \ + MAGIC(pa_stream_get_sample_spec); \ + MAGIC(pa_stream_get_time); \ + MAGIC(pa_stream_set_read_callback); \ + MAGIC(pa_stream_set_state_callback); \ + MAGIC(pa_stream_set_moved_callback); \ + MAGIC(pa_stream_set_underflow_callback); \ + MAGIC(pa_stream_new_with_proplist); \ + MAGIC(pa_stream_disconnect); \ + MAGIC(pa_stream_set_buffer_attr_callback); \ + MAGIC(pa_stream_begin_write); \ + MAGIC(pa_channel_map_init_auto); \ + MAGIC(pa_channel_map_parse); \ + MAGIC(pa_channel_map_snprint); \ + MAGIC(pa_channel_map_equal); \ + MAGIC(pa_channel_map_superset); \ + MAGIC(pa_operation_get_state); \ + MAGIC(pa_operation_unref); \ + MAGIC(pa_sample_spec_valid); \ + MAGIC(pa_frame_size); \ + MAGIC(pa_strerror); \ + MAGIC(pa_path_get_filename); \ + MAGIC(pa_get_binary_name); \ + MAGIC(pa_xmalloc); \ + MAGIC(pa_xfree); + +void *pulse_handle; +#define MAKE_FUNC(x) decltype(x) * p##x +PULSE_FUNCS(MAKE_FUNC) +#undef MAKE_FUNC + +#ifndef IN_IDE_PARSER +#define pa_mainloop_new ppa_mainloop_new +#define pa_mainloop_free ppa_mainloop_free +#define pa_mainloop_set_poll_func ppa_mainloop_set_poll_func +#define pa_mainloop_run ppa_mainloop_run +#define pa_mainloop_get_api ppa_mainloop_get_api +#define pa_context_new ppa_context_new +#define pa_context_unref ppa_context_unref +#define pa_context_get_state ppa_context_get_state +#define pa_context_disconnect ppa_context_disconnect +#define pa_context_set_state_callback ppa_context_set_state_callback +#define pa_context_errno ppa_context_errno +#define pa_context_connect ppa_context_connect +#define pa_context_get_server_info ppa_context_get_server_info +#define pa_context_get_sink_info_by_name ppa_context_get_sink_info_by_name +#define pa_context_get_sink_info_list ppa_context_get_sink_info_list +#define pa_context_get_source_info_by_name ppa_context_get_source_info_by_name +#define pa_context_get_source_info_list ppa_context_get_source_info_list +#define pa_stream_new ppa_stream_new +#define pa_stream_unref ppa_stream_unref +#define pa_stream_disconnect ppa_stream_disconnect +#define pa_stream_drop ppa_stream_drop +#define pa_stream_set_write_callback ppa_stream_set_write_callback +#define pa_stream_set_buffer_attr ppa_stream_set_buffer_attr +#define pa_stream_get_buffer_attr ppa_stream_get_buffer_attr +#define pa_stream_get_sample_spec ppa_stream_get_sample_spec +#define pa_stream_get_time ppa_stream_get_time +#define pa_stream_set_read_callback ppa_stream_set_read_callback +#define pa_stream_set_state_callback ppa_stream_set_state_callback +#define pa_stream_set_moved_callback ppa_stream_set_moved_callback +#define pa_stream_set_underflow_callback ppa_stream_set_underflow_callback +#define pa_stream_connect_record ppa_stream_connect_record +#define pa_stream_connect_playback ppa_stream_connect_playback +#define pa_stream_readable_size ppa_stream_readable_size +#define pa_stream_writable_size ppa_stream_writable_size +#define pa_stream_is_corked ppa_stream_is_corked +#define pa_stream_cork ppa_stream_cork +#define pa_stream_is_suspended ppa_stream_is_suspended +#define pa_stream_get_device_name ppa_stream_get_device_name +#define pa_stream_get_latency ppa_stream_get_latency +#define pa_stream_set_buffer_attr_callback ppa_stream_set_buffer_attr_callback +#define pa_stream_begin_write ppa_stream_begin_write*/ +#define pa_channel_map_init_auto ppa_channel_map_init_auto +#define pa_channel_map_parse ppa_channel_map_parse +#define pa_channel_map_snprint ppa_channel_map_snprint +#define pa_channel_map_equal ppa_channel_map_equal +#define pa_channel_map_superset ppa_channel_map_superset +#define pa_operation_get_state ppa_operation_get_state +#define pa_operation_unref ppa_operation_unref +#define pa_sample_spec_valid ppa_sample_spec_valid +#define pa_frame_size ppa_frame_size +#define pa_strerror ppa_strerror +#define pa_stream_get_state ppa_stream_get_state +#define pa_stream_peek ppa_stream_peek +#define pa_stream_write ppa_stream_write +#define pa_xfree ppa_xfree +#define pa_path_get_filename ppa_path_get_filename +#define pa_get_binary_name ppa_get_binary_name +#define pa_xmalloc ppa_xmalloc +#endif /* IN_IDE_PARSER */ + +#endif + + +constexpr pa_channel_map MonoChanMap{ + 1, {PA_CHANNEL_POSITION_MONO} +}, StereoChanMap{ + 2, {PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT} +}, QuadChanMap{ + 4, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT + } +}, X51ChanMap{ + 6, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT + } +}, X51RearChanMap{ + 6, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT + } +}, X61ChanMap{ + 7, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_REAR_CENTER, + PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT + } +}, X71ChanMap{ + 8, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, + PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT + } +}; + +size_t ChannelFromPulse(pa_channel_position_t chan) +{ + switch(chan) + { + case PA_CHANNEL_POSITION_INVALID: break; + case PA_CHANNEL_POSITION_MONO: return FrontCenter; + case PA_CHANNEL_POSITION_FRONT_LEFT: return FrontLeft; + case PA_CHANNEL_POSITION_FRONT_RIGHT: return FrontRight; + case PA_CHANNEL_POSITION_FRONT_CENTER: return FrontCenter; + case PA_CHANNEL_POSITION_REAR_CENTER: return BackCenter; + case PA_CHANNEL_POSITION_REAR_LEFT: return BackLeft; + case PA_CHANNEL_POSITION_REAR_RIGHT: return BackRight; + case PA_CHANNEL_POSITION_LFE: return LFE; + case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER: break; + case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER: break; + case PA_CHANNEL_POSITION_SIDE_LEFT: return SideLeft; + case PA_CHANNEL_POSITION_SIDE_RIGHT: return SideRight; + case PA_CHANNEL_POSITION_AUX0: return Aux0; + case PA_CHANNEL_POSITION_AUX1: return Aux1; + case PA_CHANNEL_POSITION_AUX2: return Aux2; + case PA_CHANNEL_POSITION_AUX3: return Aux3; + case PA_CHANNEL_POSITION_AUX4: return Aux4; + case PA_CHANNEL_POSITION_AUX5: return Aux5; + case PA_CHANNEL_POSITION_AUX6: return Aux6; + case PA_CHANNEL_POSITION_AUX7: return Aux7; + case PA_CHANNEL_POSITION_AUX8: return Aux8; + case PA_CHANNEL_POSITION_AUX9: return Aux9; + case PA_CHANNEL_POSITION_AUX10: return Aux10; + case PA_CHANNEL_POSITION_AUX11: return Aux11; + case PA_CHANNEL_POSITION_AUX12: return Aux12; + case PA_CHANNEL_POSITION_AUX13: return Aux13; + case PA_CHANNEL_POSITION_AUX14: return Aux14; + case PA_CHANNEL_POSITION_AUX15: return Aux15; + case PA_CHANNEL_POSITION_AUX16: break; + case PA_CHANNEL_POSITION_AUX17: break; + case PA_CHANNEL_POSITION_AUX18: break; + case PA_CHANNEL_POSITION_AUX19: break; + case PA_CHANNEL_POSITION_AUX20: break; + case PA_CHANNEL_POSITION_AUX21: break; + case PA_CHANNEL_POSITION_AUX22: break; + case PA_CHANNEL_POSITION_AUX23: break; + case PA_CHANNEL_POSITION_AUX24: break; + case PA_CHANNEL_POSITION_AUX25: break; + case PA_CHANNEL_POSITION_AUX26: break; + case PA_CHANNEL_POSITION_AUX27: break; + case PA_CHANNEL_POSITION_AUX28: break; + case PA_CHANNEL_POSITION_AUX29: break; + case PA_CHANNEL_POSITION_AUX30: break; + case PA_CHANNEL_POSITION_AUX31: break; + case PA_CHANNEL_POSITION_TOP_CENTER: break; + case PA_CHANNEL_POSITION_TOP_FRONT_LEFT: return UpperFrontLeft; + case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT: return UpperFrontRight; + case PA_CHANNEL_POSITION_TOP_FRONT_CENTER: break; + case PA_CHANNEL_POSITION_TOP_REAR_LEFT: return UpperBackLeft; + case PA_CHANNEL_POSITION_TOP_REAR_RIGHT: return UpperBackRight; + case PA_CHANNEL_POSITION_TOP_REAR_CENTER: break; + case PA_CHANNEL_POSITION_MAX: break; + } + throw al::backend_exception{ALC_INVALID_VALUE, "Unexpected channel enum %d", chan}; +} + +void SetChannelOrderFromMap(ALCdevice *device, const pa_channel_map &chanmap) +{ + device->RealOut.ChannelIndex.fill(-1); + for(int i{0};i < chanmap.channels;++i) + device->RealOut.ChannelIndex[ChannelFromPulse(chanmap.map[i])] = i; +} + + +/* *grumble* Don't use enums for bitflags. */ +inline pa_stream_flags_t operator|(pa_stream_flags_t lhs, pa_stream_flags_t rhs) +{ return pa_stream_flags_t(int(lhs) | int(rhs)); } +inline pa_stream_flags_t& operator|=(pa_stream_flags_t &lhs, pa_stream_flags_t rhs) +{ + lhs = pa_stream_flags_t(int(lhs) | int(rhs)); + return lhs; +} +inline pa_context_flags_t& operator|=(pa_context_flags_t &lhs, pa_context_flags_t rhs) +{ + lhs = pa_context_flags_t(int(lhs) | int(rhs)); + return lhs; +} + +inline pa_stream_flags_t& operator&=(pa_stream_flags_t &lhs, int rhs) +{ + lhs = pa_stream_flags_t(int(lhs) & rhs); + return lhs; +} + + +/* Global flags and properties */ +pa_context_flags_t pulse_ctx_flags; + +pa_mainloop *pulse_mainloop{nullptr}; + +std::mutex pulse_lock; +std::condition_variable pulse_condvar; + +int pulse_poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) +{ + auto plock = static_cast*>(userdata); + plock->unlock(); + int r{poll(ufds, nfds, timeout)}; + plock->lock(); + return r; +} + +int pulse_mainloop_thread() +{ + SetRTPriority(); + + std::unique_lock plock{pulse_lock}; + pulse_mainloop = pa_mainloop_new(); + + pa_mainloop_set_poll_func(pulse_mainloop, pulse_poll_func, &plock); + pulse_condvar.notify_all(); + + int ret{}; + pa_mainloop_run(pulse_mainloop, &ret); + + pa_mainloop_free(pulse_mainloop); + pulse_mainloop = nullptr; + + return ret; +} + + +/* PulseAudio Event Callbacks */ +void context_state_callback(pa_context *context, void* /*pdata*/) +{ + pa_context_state_t state{pa_context_get_state(context)}; + if(state == PA_CONTEXT_READY || !PA_CONTEXT_IS_GOOD(state)) + pulse_condvar.notify_all(); +} + +void stream_state_callback(pa_stream *stream, void* /*pdata*/) +{ + pa_stream_state_t state{pa_stream_get_state(stream)}; + if(state == PA_STREAM_READY || !PA_STREAM_IS_GOOD(state)) + pulse_condvar.notify_all(); +} + +void stream_success_callback(pa_stream* /*stream*/, int /*success*/, void* /*pdata*/) +{ + pulse_condvar.notify_all(); +} + +void wait_for_operation(pa_operation *op, std::unique_lock &plock) +{ + if(op) + { + while(pa_operation_get_state(op) == PA_OPERATION_RUNNING) + pulse_condvar.wait(plock); + pa_operation_unref(op); + } +} + + +pa_context *connect_context(std::unique_lock &plock) +{ + const char *name{"OpenAL Soft"}; + + const PathNamePair &binname = GetProcBinary(); + if(!binname.fname.empty()) + name = binname.fname.c_str(); + + if(UNLIKELY(!pulse_mainloop)) + { + std::thread{pulse_mainloop_thread}.detach(); + while(!pulse_mainloop) + pulse_condvar.wait(plock); + } + + pa_context *context{pa_context_new(pa_mainloop_get_api(pulse_mainloop), name)}; + if(!context) throw al::backend_exception{ALC_OUT_OF_MEMORY, "pa_context_new() failed"}; + + pa_context_set_state_callback(context, context_state_callback, nullptr); + + int err; + if((err=pa_context_connect(context, nullptr, pulse_ctx_flags, nullptr)) >= 0) + { + pa_context_state_t state; + while((state=pa_context_get_state(context)) != PA_CONTEXT_READY) + { + if(!PA_CONTEXT_IS_GOOD(state)) + { + err = pa_context_errno(context); + if(err > 0) err = -err; + break; + } + + pulse_condvar.wait(plock); + } + } + pa_context_set_state_callback(context, nullptr, nullptr); + + if(err < 0) + { + pa_context_unref(context); + throw al::backend_exception{ALC_INVALID_VALUE, "Context did not connect (%s)", + pa_strerror(err)}; + } + + return context; +} + + +void pulse_close(pa_context *context, pa_stream *stream) +{ + std::lock_guard _{pulse_lock}; + if(stream) + { + pa_stream_set_state_callback(stream, nullptr, nullptr); + pa_stream_set_moved_callback(stream, nullptr, nullptr); + pa_stream_set_write_callback(stream, nullptr, nullptr); + pa_stream_set_buffer_attr_callback(stream, nullptr, nullptr); + pa_stream_disconnect(stream); + pa_stream_unref(stream); + } + + pa_context_disconnect(context); + pa_context_unref(context); +} + + +struct DevMap { + std::string name; + std::string device_name; +}; + +bool checkName(const al::vector &list, const std::string &name) +{ + return std::find_if(list.cbegin(), list.cend(), + [&name](const DevMap &entry) -> bool + { return entry.name == name; } + ) != list.cend(); +} + +al::vector PlaybackDevices; +al::vector CaptureDevices; + + +pa_stream *pulse_connect_stream(const char *device_name, std::unique_lock &plock, + pa_context *context, pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, + pa_channel_map *chanmap, BackendType type) +{ + const char *stream_id{(type==BackendType::Playback) ? "Playback Stream" : "Capture Stream"}; + pa_stream *stream{pa_stream_new(context, stream_id, spec, chanmap)}; + if(!stream) + throw al::backend_exception{ALC_OUT_OF_MEMORY, "pa_stream_new() failed (%s)", + pa_strerror(pa_context_errno(context))}; + + pa_stream_set_state_callback(stream, stream_state_callback, nullptr); + + int err{(type==BackendType::Playback) ? + pa_stream_connect_playback(stream, device_name, attr, flags, nullptr, nullptr) : + pa_stream_connect_record(stream, device_name, attr, flags)}; + if(err < 0) + { + pa_stream_unref(stream); + throw al::backend_exception{ALC_INVALID_VALUE, "%s did not connect (%s)", stream_id, + pa_strerror(err)}; + } + + pa_stream_state_t state; + while((state=pa_stream_get_state(stream)) != PA_STREAM_READY) + { + if(!PA_STREAM_IS_GOOD(state)) + { + int err{pa_context_errno(context)}; + pa_stream_unref(stream); + throw al::backend_exception{ALC_INVALID_VALUE, "%s did not get ready (%s)", stream_id, + pa_strerror(err)}; + } + + pulse_condvar.wait(plock); + } + pa_stream_set_state_callback(stream, nullptr, nullptr); + + return stream; +} + + +void device_sink_callback(pa_context*, const pa_sink_info *info, int eol, void*) +{ + if(eol) + { + pulse_condvar.notify_all(); + return; + } + + /* Skip this device is if it's already in the list. */ + if(std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + [info](const DevMap &entry) -> bool + { return entry.device_name == info->name; } + ) != PlaybackDevices.cend()) + return; + + /* Make sure the display name (description) is unique. Append a number + * counter as needed. + */ + int count{1}; + std::string newname{info->description}; + while(checkName(PlaybackDevices, newname)) + { + newname = info->description; + newname += " #"; + newname += std::to_string(++count); + } + PlaybackDevices.emplace_back(DevMap{std::move(newname), info->name}); + DevMap &newentry = PlaybackDevices.back(); + + TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str()); +} + +void probePlaybackDevices() +{ + PlaybackDevices.clear(); + + try { + std::unique_lock plock{pulse_lock}; + + pa_context *context{connect_context(plock)}; + + const pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | + PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE}; + + pa_sample_spec spec{}; + spec.format = PA_SAMPLE_S16NE; + spec.rate = 44100; + spec.channels = 2; + + pa_stream *stream{pulse_connect_stream(nullptr, plock, context, flags, nullptr, &spec, + nullptr, BackendType::Playback)}; + pa_operation *op{pa_context_get_sink_info_by_name(context, + pa_stream_get_device_name(stream), device_sink_callback, nullptr)}; + wait_for_operation(op, plock); + + pa_stream_disconnect(stream); + pa_stream_unref(stream); + stream = nullptr; + + op = pa_context_get_sink_info_list(context, device_sink_callback, nullptr); + wait_for_operation(op, plock); + + pa_context_disconnect(context); + pa_context_unref(context); + } + catch(std::exception &e) { + ERR("Error enumerating devices: %s\n", e.what()); + } +} + + +void device_source_callback(pa_context*, const pa_source_info *info, int eol, void*) +{ + if(eol) + { + pulse_condvar.notify_all(); + return; + } + + /* Skip this device is if it's already in the list. */ + if(std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), + [info](const DevMap &entry) -> bool + { return entry.device_name == info->name; } + ) != CaptureDevices.cend()) + return; + + /* Make sure the display name (description) is unique. Append a number + * counter as needed. + */ + int count{1}; + std::string newname{info->description}; + while(checkName(CaptureDevices, newname)) + { + newname = info->description; + newname += " #"; + newname += std::to_string(++count); + } + CaptureDevices.emplace_back(DevMap{std::move(newname), info->name}); + DevMap &newentry = CaptureDevices.back(); + + TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str()); +} + +void probeCaptureDevices() +{ + CaptureDevices.clear(); + + try { + std::unique_lock plock{pulse_lock}; + + pa_context *context{connect_context(plock)}; + + const pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | + PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE}; + + pa_sample_spec spec{}; + spec.format = PA_SAMPLE_S16NE; + spec.rate = 44100; + spec.channels = 1; + + pa_stream *stream{pulse_connect_stream(nullptr, plock, context, flags, nullptr, &spec, nullptr, + BackendType::Capture)}; + pa_operation *op{pa_context_get_source_info_by_name(context, + pa_stream_get_device_name(stream), device_source_callback, nullptr)}; + wait_for_operation(op, plock); + + pa_stream_disconnect(stream); + pa_stream_unref(stream); + stream = nullptr; + + op = pa_context_get_source_info_list(context, device_source_callback, nullptr); + wait_for_operation(op, plock); + + pa_context_disconnect(context); + pa_context_unref(context); + } + catch(std::exception &e) { + ERR("Error enumerating devices: %s\n", e.what()); + } +} + + +struct PulsePlayback final : public BackendBase { + PulsePlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~PulsePlayback() override; + + static void bufferAttrCallbackC(pa_stream *stream, void *pdata); + void bufferAttrCallback(pa_stream *stream); + + static void contextStateCallbackC(pa_context *context, void *pdata); + void contextStateCallback(pa_context *context); + + static void streamStateCallbackC(pa_stream *stream, void *pdata); + void streamStateCallback(pa_stream *stream); + + static void streamWriteCallbackC(pa_stream *stream, size_t nbytes, void *pdata); + void streamWriteCallback(pa_stream *stream, size_t nbytes); + + static void sinkInfoCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata); + void sinkInfoCallback(pa_context *context, const pa_sink_info *info, int eol); + + static void sinkNameCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata); + void sinkNameCallback(pa_context *context, const pa_sink_info *info, int eol); + + static void streamMovedCallbackC(pa_stream *stream, void *pdata); + void streamMovedCallback(pa_stream *stream); + + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + ClockLatency getClockLatency() override; + void lock() override; + void unlock() override; + + std::string mDeviceName; + + pa_buffer_attr mAttr; + pa_sample_spec mSpec; + + pa_stream *mStream{nullptr}; + pa_context *mContext{nullptr}; + + ALuint mFrameSize{0u}; + + DEF_NEWDEL(PulsePlayback) +}; + +PulsePlayback::~PulsePlayback() +{ + if(!mContext) + return; + + pulse_close(mContext, mStream); + mContext = nullptr; + mStream = nullptr; +} + + +void PulsePlayback::bufferAttrCallbackC(pa_stream *stream, void *pdata) +{ static_cast(pdata)->bufferAttrCallback(stream); } + +void PulsePlayback::bufferAttrCallback(pa_stream *stream) +{ + /* FIXME: Update the device's UpdateSize (and/or BufferSize) using the new + * buffer attributes? Changing UpdateSize will change the ALC_REFRESH + * property, which probably shouldn't change between device resets. But + * leaving it alone means ALC_REFRESH will be off. + */ + mAttr = *(pa_stream_get_buffer_attr(stream)); + TRACE("minreq=%d, tlength=%d, prebuf=%d\n", mAttr.minreq, mAttr.tlength, mAttr.prebuf); +} + +void PulsePlayback::contextStateCallbackC(pa_context *context, void *pdata) +{ static_cast(pdata)->contextStateCallback(context); } + +void PulsePlayback::contextStateCallback(pa_context *context) +{ + if(pa_context_get_state(context) == PA_CONTEXT_FAILED) + { + ERR("Received context failure!\n"); + aluHandleDisconnect(mDevice, "Playback state failure"); + } + pulse_condvar.notify_all(); +} + +void PulsePlayback::streamStateCallbackC(pa_stream *stream, void *pdata) +{ static_cast(pdata)->streamStateCallback(stream); } + +void PulsePlayback::streamStateCallback(pa_stream *stream) +{ + if(pa_stream_get_state(stream) == PA_STREAM_FAILED) + { + ERR("Received stream failure!\n"); + aluHandleDisconnect(mDevice, "Playback stream failure"); + } + pulse_condvar.notify_all(); +} + +void PulsePlayback::streamWriteCallbackC(pa_stream *stream, size_t nbytes, void *pdata) +{ static_cast(pdata)->streamWriteCallback(stream, nbytes); } + +void PulsePlayback::streamWriteCallback(pa_stream *stream, size_t nbytes) +{ + void *buf{pa_xmalloc(nbytes)}; + aluMixData(mDevice, buf, nbytes/mFrameSize); + + int ret{pa_stream_write(stream, buf, nbytes, pa_xfree, 0, PA_SEEK_RELATIVE)}; + if(UNLIKELY(ret != PA_OK)) + ERR("Failed to write to stream: %d, %s\n", ret, pa_strerror(ret)); +} + +void PulsePlayback::sinkInfoCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata) +{ static_cast(pdata)->sinkInfoCallback(context, info, eol); } + +void PulsePlayback::sinkInfoCallback(pa_context*, const pa_sink_info *info, int eol) +{ + struct ChannelMap { + DevFmtChannels chans; + pa_channel_map map; + }; + static constexpr std::array chanmaps{{ + { DevFmtX71, X71ChanMap }, + { DevFmtX61, X61ChanMap }, + { DevFmtX51, X51ChanMap }, + { DevFmtX51Rear, X51RearChanMap }, + { DevFmtQuad, QuadChanMap }, + { DevFmtStereo, StereoChanMap }, + { DevFmtMono, MonoChanMap } + }}; + + if(eol) + { + pulse_condvar.notify_all(); + return; + } + + auto chanmap = std::find_if(chanmaps.cbegin(), chanmaps.cend(), + [info](const ChannelMap &chanmap) -> bool + { return pa_channel_map_superset(&info->channel_map, &chanmap.map); } + ); + if(chanmap != chanmaps.cend()) + { + if(!mDevice->Flags.get()) + mDevice->FmtChans = chanmap->chans; + } + else + { + char chanmap_str[PA_CHANNEL_MAP_SNPRINT_MAX]{}; + pa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map); + WARN("Failed to find format for channel map:\n %s\n", chanmap_str); + } + + if(info->active_port) + TRACE("Active port: %s (%s)\n", info->active_port->name, info->active_port->description); + mDevice->IsHeadphones = (mDevice->FmtChans == DevFmtStereo && + info->active_port && strcmp(info->active_port->name, "analog-output-headphones") == 0); +} + +void PulsePlayback::sinkNameCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata) +{ static_cast(pdata)->sinkNameCallback(context, info, eol); } + +void PulsePlayback::sinkNameCallback(pa_context*, const pa_sink_info *info, int eol) +{ + if(eol) + { + pulse_condvar.notify_all(); + return; + } + mDevice->DeviceName = info->description; +} + +void PulsePlayback::streamMovedCallbackC(pa_stream *stream, void *pdata) +{ static_cast(pdata)->streamMovedCallback(stream); } + +void PulsePlayback::streamMovedCallback(pa_stream *stream) +{ + mDeviceName = pa_stream_get_device_name(stream); + TRACE("Stream moved to %s\n", mDeviceName.c_str()); +} + + +ALCenum PulsePlayback::open(const ALCchar *name) +{ + const char *pulse_name{nullptr}; + const char *dev_name{nullptr}; + + if(name) + { + if(PlaybackDevices.empty()) + probePlaybackDevices(); + + auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + [name](const DevMap &entry) -> bool + { return entry.name == name; } + ); + if(iter == PlaybackDevices.cend()) + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; + pulse_name = iter->device_name.c_str(); + dev_name = iter->name.c_str(); + } + + std::unique_lock plock{pulse_lock}; + + mContext = connect_context(plock); + pa_context_set_state_callback(mContext, &PulsePlayback::contextStateCallbackC, this); + + pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS}; + if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 1)) + flags |= PA_STREAM_DONT_MOVE; + + pa_sample_spec spec{}; + spec.format = PA_SAMPLE_S16NE; + spec.rate = 44100; + spec.channels = 2; + + if(!pulse_name) + { + pulse_name = getenv("ALSOFT_PULSE_DEFAULT"); + if(pulse_name && !pulse_name[0]) pulse_name = nullptr; + } + TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); + mStream = pulse_connect_stream(pulse_name, plock, mContext, flags, nullptr, &spec, nullptr, + BackendType::Playback); + + pa_stream_set_moved_callback(mStream, &PulsePlayback::streamMovedCallbackC, this); + mFrameSize = pa_frame_size(pa_stream_get_sample_spec(mStream)); + + mDeviceName = pa_stream_get_device_name(mStream); + if(!dev_name) + { + pa_operation *op{pa_context_get_sink_info_by_name(mContext, mDeviceName.c_str(), + &PulsePlayback::sinkNameCallbackC, this)}; + wait_for_operation(op, plock); + } + else + mDevice->DeviceName = dev_name; + + return ALC_NO_ERROR; +} + +ALCboolean PulsePlayback::reset() +{ + std::unique_lock plock{pulse_lock}; + + if(mStream) + { + pa_stream_set_state_callback(mStream, nullptr, nullptr); + pa_stream_set_moved_callback(mStream, nullptr, nullptr); + pa_stream_set_write_callback(mStream, nullptr, nullptr); + pa_stream_set_buffer_attr_callback(mStream, nullptr, nullptr); + pa_stream_disconnect(mStream); + pa_stream_unref(mStream); + mStream = nullptr; + } + + pa_operation *op{pa_context_get_sink_info_by_name(mContext, mDeviceName.c_str(), + &PulsePlayback::sinkInfoCallbackC, this)}; + wait_for_operation(op, plock); + + pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | + PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_EARLY_REQUESTS}; + if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 1)) + flags |= PA_STREAM_DONT_MOVE; + if(GetConfigValueBool(mDevice->DeviceName.c_str(), "pulse", "adjust-latency", 0)) + { + /* ADJUST_LATENCY can't be specified with EARLY_REQUESTS, for some + * reason. So if the user wants to adjust the overall device latency, + * we can't ask to get write signals as soon as minreq is reached. + */ + flags &= ~PA_STREAM_EARLY_REQUESTS; + flags |= PA_STREAM_ADJUST_LATENCY; + } + if(GetConfigValueBool(mDevice->DeviceName.c_str(), "pulse", "fix-rate", 0) || + !mDevice->Flags.get()) + flags |= PA_STREAM_FIX_RATE; + + pa_channel_map chanmap{}; + switch(mDevice->FmtChans) + { + case DevFmtMono: + chanmap = MonoChanMap; + break; + case DevFmtAmbi3D: + mDevice->FmtChans = DevFmtStereo; + /*fall-through*/ + case DevFmtStereo: + chanmap = StereoChanMap; + break; + case DevFmtQuad: + chanmap = QuadChanMap; + break; + case DevFmtX51: + chanmap = X51ChanMap; + break; + case DevFmtX51Rear: + chanmap = X51RearChanMap; + break; + case DevFmtX61: + chanmap = X61ChanMap; + break; + case DevFmtX71: + chanmap = X71ChanMap; + break; + } + SetChannelOrderFromMap(mDevice, chanmap); + + switch(mDevice->FmtType) + { + case DevFmtByte: + mDevice->FmtType = DevFmtUByte; + /* fall-through */ + case DevFmtUByte: + mSpec.format = PA_SAMPLE_U8; + break; + case DevFmtUShort: + mDevice->FmtType = DevFmtShort; + /* fall-through */ + case DevFmtShort: + mSpec.format = PA_SAMPLE_S16NE; + break; + case DevFmtUInt: + mDevice->FmtType = DevFmtInt; + /* fall-through */ + case DevFmtInt: + mSpec.format = PA_SAMPLE_S32NE; + break; + case DevFmtFloat: + mSpec.format = PA_SAMPLE_FLOAT32NE; + break; + } + mSpec.rate = mDevice->Frequency; + mSpec.channels = mDevice->channelsFromFmt(); + if(pa_sample_spec_valid(&mSpec) == 0) + throw al::backend_exception{ALC_INVALID_VALUE, "Invalid sample spec"}; + + mAttr.maxlength = -1; + mAttr.tlength = mDevice->BufferSize * pa_frame_size(&mSpec); + mAttr.prebuf = 0; + mAttr.minreq = mDevice->UpdateSize * pa_frame_size(&mSpec); + mAttr.fragsize = -1; + + mStream = pulse_connect_stream(mDeviceName.c_str(), plock, mContext, flags, &mAttr, &mSpec, + &chanmap, BackendType::Playback); + + pa_stream_set_state_callback(mStream, &PulsePlayback::streamStateCallbackC, this); + pa_stream_set_moved_callback(mStream, &PulsePlayback::streamMovedCallbackC, this); + + mSpec = *(pa_stream_get_sample_spec(mStream)); + mFrameSize = pa_frame_size(&mSpec); + + if(mDevice->Frequency != mSpec.rate) + { + /* Server updated our playback rate, so modify the buffer attribs + * accordingly. + */ + const auto scale = static_cast(mSpec.rate) / mDevice->Frequency; + const ALuint perlen{static_cast(clampd(scale*mDevice->UpdateSize + 0.5, 64.0, + 8192.0))}; + const ALuint buflen{static_cast(clampd(scale*mDevice->BufferSize + 0.5, perlen*2, + std::numeric_limits::max()/mFrameSize))}; + + mAttr.maxlength = -1; + mAttr.tlength = buflen * mFrameSize; + mAttr.prebuf = 0; + mAttr.minreq = perlen * mFrameSize; + + op = pa_stream_set_buffer_attr(mStream, &mAttr, stream_success_callback, nullptr); + wait_for_operation(op, plock); + + mDevice->Frequency = mSpec.rate; + } + + pa_stream_set_buffer_attr_callback(mStream, &PulsePlayback::bufferAttrCallbackC, this); + bufferAttrCallback(mStream); + + mDevice->BufferSize = mAttr.tlength / mFrameSize; + mDevice->UpdateSize = mAttr.minreq / mFrameSize; + + /* HACK: prebuf should be 0 as that's what we set it to. However on some + * systems it comes back as non-0, so we have to make sure the device will + * write enough audio to start playback. The lack of manual start control + * may have unintended consequences, but it's better than not starting at + * all. + */ + if(mAttr.prebuf != 0) + { + ALuint len{mAttr.prebuf / mFrameSize}; + if(len <= mDevice->BufferSize) + ERR("Non-0 prebuf, %u samples (%u bytes), device has %u samples\n", + len, mAttr.prebuf, mDevice->BufferSize); + } + + return ALC_TRUE; +} + +ALCboolean PulsePlayback::start() +{ + std::unique_lock plock{pulse_lock}; + + pa_stream_set_write_callback(mStream, &PulsePlayback::streamWriteCallbackC, this); + pa_operation *op{pa_stream_cork(mStream, 0, stream_success_callback, nullptr)}; + wait_for_operation(op, plock); + + return ALC_TRUE; +} + +void PulsePlayback::stop() +{ + std::unique_lock plock{pulse_lock}; + + pa_stream_set_write_callback(mStream, nullptr, nullptr); + pa_operation *op{pa_stream_cork(mStream, 1, stream_success_callback, nullptr)}; + wait_for_operation(op, plock); +} + + +ClockLatency PulsePlayback::getClockLatency() +{ + ClockLatency ret; + pa_usec_t latency; + int neg, err; + + { std::lock_guard _{pulse_lock}; + ret.ClockTime = GetDeviceClockTime(mDevice); + err = pa_stream_get_latency(mStream, &latency, &neg); + } + + if(UNLIKELY(err != 0)) + { + /* 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); + latency = 0; + neg = 0; + } + else if(UNLIKELY(neg)) + latency = 0; + ret.Latency = std::chrono::microseconds{latency}; + + return ret; +} + + +void PulsePlayback::lock() +{ pulse_lock.lock(); } + +void PulsePlayback::unlock() +{ pulse_lock.unlock(); } + + +struct PulseCapture final : public BackendBase { + PulseCapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~PulseCapture() override; + + static void contextStateCallbackC(pa_context *context, void *pdata); + void contextStateCallback(pa_context *context); + + static void streamStateCallbackC(pa_stream *stream, void *pdata); + void streamStateCallback(pa_stream *stream); + + static void sourceNameCallbackC(pa_context *context, const pa_source_info *info, int eol, void *pdata); + void sourceNameCallback(pa_context *context, const pa_source_info *info, int eol); + + static void streamMovedCallbackC(pa_stream *stream, void *pdata); + void streamMovedCallback(pa_stream *stream); + + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + ClockLatency getClockLatency() override; + void lock() override; + void unlock() override; + + std::string mDeviceName; + + ALCuint mLastReadable{0u}; + al::byte mSilentVal{}; + + al::span mCapBuffer; + ssize_t mCapLen{0}; + + pa_buffer_attr mAttr{}; + pa_sample_spec mSpec{}; + + pa_stream *mStream{nullptr}; + pa_context *mContext{nullptr}; + + DEF_NEWDEL(PulseCapture) +}; + +PulseCapture::~PulseCapture() +{ + if(!mContext) + return; + + pulse_close(mContext, mStream); + mContext = nullptr; + mStream = nullptr; +} + +void PulseCapture::contextStateCallbackC(pa_context *context, void *pdata) +{ static_cast(pdata)->contextStateCallback(context); } + +void PulseCapture::contextStateCallback(pa_context *context) +{ + if(pa_context_get_state(context) == PA_CONTEXT_FAILED) + { + ERR("Received context failure!\n"); + aluHandleDisconnect(mDevice, "Capture state failure"); + } + pulse_condvar.notify_all(); +} + +void PulseCapture::streamStateCallbackC(pa_stream *stream, void *pdata) +{ static_cast(pdata)->streamStateCallback(stream); } + +void PulseCapture::streamStateCallback(pa_stream *stream) +{ + if(pa_stream_get_state(stream) == PA_STREAM_FAILED) + { + ERR("Received stream failure!\n"); + aluHandleDisconnect(mDevice, "Capture stream failure"); + } + pulse_condvar.notify_all(); +} + +void PulseCapture::sourceNameCallbackC(pa_context *context, const pa_source_info *info, int eol, void *pdata) +{ static_cast(pdata)->sourceNameCallback(context, info, eol); } + +void PulseCapture::sourceNameCallback(pa_context*, const pa_source_info *info, int eol) +{ + if(eol) + { + pulse_condvar.notify_all(); + return; + } + mDevice->DeviceName = info->description; +} + +void PulseCapture::streamMovedCallbackC(pa_stream *stream, void *pdata) +{ static_cast(pdata)->streamMovedCallback(stream); } + +void PulseCapture::streamMovedCallback(pa_stream *stream) +{ + mDeviceName = pa_stream_get_device_name(stream); + TRACE("Stream moved to %s\n", mDeviceName.c_str()); +} + + +ALCenum PulseCapture::open(const ALCchar *name) +{ + const char *pulse_name{nullptr}; + if(name) + { + if(CaptureDevices.empty()) + probeCaptureDevices(); + + auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), + [name](const DevMap &entry) -> bool + { return entry.name == name; } + ); + if(iter == CaptureDevices.cend()) + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; + pulse_name = iter->device_name.c_str(); + mDevice->DeviceName = iter->name; + } + + std::unique_lock plock{pulse_lock}; + + mContext = connect_context(plock); + pa_context_set_state_callback(mContext, &PulseCapture::contextStateCallbackC, this); + + pa_channel_map chanmap{}; + switch(mDevice->FmtChans) + { + case DevFmtMono: + chanmap = MonoChanMap; + break; + case DevFmtStereo: + chanmap = StereoChanMap; + break; + case DevFmtQuad: + chanmap = QuadChanMap; + break; + case DevFmtX51: + chanmap = X51ChanMap; + break; + case DevFmtX51Rear: + chanmap = X51RearChanMap; + break; + case DevFmtX61: + chanmap = X61ChanMap; + break; + case DevFmtX71: + chanmap = X71ChanMap; + break; + case DevFmtAmbi3D: + throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", + DevFmtChannelsString(mDevice->FmtChans)}; + } + SetChannelOrderFromMap(mDevice, chanmap); + + switch(mDevice->FmtType) + { + case DevFmtUByte: + mSilentVal = al::byte(0x80); + mSpec.format = PA_SAMPLE_U8; + break; + case DevFmtShort: + mSpec.format = PA_SAMPLE_S16NE; + break; + case DevFmtInt: + mSpec.format = PA_SAMPLE_S32NE; + break; + case DevFmtFloat: + mSpec.format = PA_SAMPLE_FLOAT32NE; + break; + case DevFmtByte: + case DevFmtUShort: + case DevFmtUInt: + throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", + DevFmtTypeString(mDevice->FmtType)}; + } + mSpec.rate = mDevice->Frequency; + mSpec.channels = mDevice->channelsFromFmt(); + if(pa_sample_spec_valid(&mSpec) == 0) + throw al::backend_exception{ALC_INVALID_VALUE, "Invalid sample format"}; + + ALuint samples{mDevice->BufferSize}; + samples = maxu(samples, 100 * mDevice->Frequency / 1000); + + mAttr.minreq = -1; + mAttr.prebuf = -1; + mAttr.maxlength = samples * pa_frame_size(&mSpec); + mAttr.tlength = -1; + mAttr.fragsize = minu(samples, 50*mDevice->Frequency/1000) * pa_frame_size(&mSpec); + + pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_ADJUST_LATENCY}; + if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 1)) + flags |= PA_STREAM_DONT_MOVE; + + TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); + mStream = pulse_connect_stream(pulse_name, plock, mContext, flags, &mAttr, &mSpec, &chanmap, + BackendType::Capture); + + pa_stream_set_moved_callback(mStream, &PulseCapture::streamMovedCallbackC, this); + pa_stream_set_state_callback(mStream, &PulseCapture::streamStateCallbackC, this); + + mDeviceName = pa_stream_get_device_name(mStream); + if(mDevice->DeviceName.empty()) + { + pa_operation *op{pa_context_get_source_info_by_name(mContext, mDeviceName.c_str(), + &PulseCapture::sourceNameCallbackC, this)}; + wait_for_operation(op, plock); + } + + return ALC_NO_ERROR; +} + +ALCboolean PulseCapture::start() +{ + std::unique_lock plock{pulse_lock}; + pa_operation *op{pa_stream_cork(mStream, 0, stream_success_callback, nullptr)}; + wait_for_operation(op, plock); + return ALC_TRUE; +} + +void PulseCapture::stop() +{ + std::unique_lock plock{pulse_lock}; + pa_operation *op{pa_stream_cork(mStream, 1, stream_success_callback, nullptr)}; + wait_for_operation(op, plock); +} + +ALCenum PulseCapture::captureSamples(ALCvoid *buffer, ALCuint samples) +{ + al::span dstbuf{static_cast(buffer), samples * pa_frame_size(&mSpec)}; + + /* Capture is done in fragment-sized chunks, so we loop until we get all + * that's available */ + mLastReadable -= dstbuf.size(); + std::lock_guard _{pulse_lock}; + while(!dstbuf.empty()) + { + if(mCapBuffer.empty()) + { + if(UNLIKELY(!mDevice->Connected.load(std::memory_order_acquire))) + break; + const pa_stream_state_t state{pa_stream_get_state(mStream)}; + if(UNLIKELY(!PA_STREAM_IS_GOOD(state))) + { + aluHandleDisconnect(mDevice, "Bad capture state: %u", state); + break; + } + const void *capbuf; + size_t caplen; + if(UNLIKELY(pa_stream_peek(mStream, &capbuf, &caplen) < 0)) + { + aluHandleDisconnect(mDevice, "Failed retrieving capture samples: %s", + pa_strerror(pa_context_errno(mContext))); + break; + } + if(caplen == 0) break; + if(UNLIKELY(!capbuf)) + mCapLen = -static_cast(caplen); + else + mCapLen = static_cast(caplen); + mCapBuffer = {static_cast(capbuf), caplen}; + } + + const size_t rem{minz(dstbuf.size(), mCapBuffer.size())}; + if(UNLIKELY(mCapLen < 0)) + std::fill_n(dstbuf.begin(), rem, mSilentVal); + else + std::copy_n(mCapBuffer.begin(), rem, dstbuf.begin()); + dstbuf = dstbuf.subspan(rem); + mCapBuffer = mCapBuffer.subspan(rem); + + if(mCapBuffer.empty()) + { + pa_stream_drop(mStream); + mCapLen = 0; + } + } + if(!dstbuf.empty()) + std::fill(dstbuf.begin(), dstbuf.end(), mSilentVal); + + return ALC_NO_ERROR; +} + +ALCuint PulseCapture::availableSamples() +{ + size_t readable{mCapBuffer.size()}; + + if(mDevice->Connected.load(std::memory_order_acquire)) + { + std::lock_guard _{pulse_lock}; + size_t got{pa_stream_readable_size(mStream)}; + if(static_cast(got) < 0) + { + ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got)); + aluHandleDisconnect(mDevice, "Failed getting readable size: %s", pa_strerror(got)); + } + else + { + const auto caplen = static_cast(std::abs(mCapLen)); + if(got > caplen) readable += got - caplen; + } + } + + readable = std::min(readable, std::numeric_limits::max()); + mLastReadable = std::max(mLastReadable, static_cast(readable)); + return mLastReadable / pa_frame_size(&mSpec); +} + + +ClockLatency PulseCapture::getClockLatency() +{ + ClockLatency ret; + pa_usec_t latency; + int neg, err; + + { std::lock_guard _{pulse_lock}; + ret.ClockTime = GetDeviceClockTime(mDevice); + err = pa_stream_get_latency(mStream, &latency, &neg); + } + + if(UNLIKELY(err != 0)) + { + ERR("Failed to get stream latency: 0x%x\n", err); + latency = 0; + neg = 0; + } + else if(UNLIKELY(neg)) + latency = 0; + ret.Latency = std::chrono::microseconds{latency}; + + return ret; +} + + +void PulseCapture::lock() +{ pulse_lock.lock(); } + +void PulseCapture::unlock() +{ pulse_lock.unlock(); } + +} // namespace + + +bool PulseBackendFactory::init() +{ +#ifdef HAVE_DYNLOAD + if(!pulse_handle) + { + bool ret{true}; + std::string missing_funcs; + +#ifdef _WIN32 +#define PALIB "libpulse-0.dll" +#elif defined(__APPLE__) && defined(__MACH__) +#define PALIB "libpulse.0.dylib" +#else +#define PALIB "libpulse.so.0" +#endif + pulse_handle = LoadLib(PALIB); + if(!pulse_handle) + { + WARN("Failed to load %s\n", PALIB); + return false; + } + +#define LOAD_FUNC(x) do { \ + p##x = reinterpret_cast(GetSymbol(pulse_handle, #x)); \ + if(!(p##x)) { \ + ret = false; \ + missing_funcs += "\n" #x; \ + } \ +} while(0) + PULSE_FUNCS(LOAD_FUNC) +#undef LOAD_FUNC + + if(!ret) + { + WARN("Missing expected functions:%s\n", missing_funcs.c_str()); + CloseLib(pulse_handle); + pulse_handle = nullptr; + return false; + } + } +#endif /* HAVE_DYNLOAD */ + + pulse_ctx_flags = PA_CONTEXT_NOFLAGS; + if(!GetConfigValueBool(nullptr, "pulse", "spawn-server", 1)) + pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN; + + try { + std::unique_lock plock{pulse_lock}; + pa_context *context{connect_context(plock)}; + pa_context_disconnect(context); + pa_context_unref(context); + return true; + } + catch(...) { + return false; + } +} + +bool PulseBackendFactory::querySupport(BackendType type) +{ return type == BackendType::Playback || type == BackendType::Capture; } + +void PulseBackendFactory::probe(DevProbe type, std::string *outnames) +{ + auto add_device = [outnames](const DevMap &entry) -> void + { + /* +1 to also append the null char (to ensure a null-separated list and + * double-null terminated list). + */ + outnames->append(entry.name.c_str(), entry.name.length()+1); + }; + switch(type) + { + case DevProbe::Playback: + probePlaybackDevices(); + std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); + break; + + case DevProbe::Capture: + probeCaptureDevices(); + std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); + break; + } +} + +BackendPtr PulseBackendFactory::createBackend(ALCdevice *device, BackendType type) +{ + if(type == BackendType::Playback) + return BackendPtr{new PulsePlayback{device}}; + if(type == BackendType::Capture) + return BackendPtr{new PulseCapture{device}}; + return nullptr; +} + +BackendFactory &PulseBackendFactory::getFactory() +{ + static PulseBackendFactory factory{}; + return factory; +} diff --git a/alc/backends/pulseaudio.h b/alc/backends/pulseaudio.h new file mode 100644 index 00000000..40f3e305 --- /dev/null +++ b/alc/backends/pulseaudio.h @@ -0,0 +1,19 @@ +#ifndef BACKENDS_PULSEAUDIO_H +#define BACKENDS_PULSEAUDIO_H + +#include "backends/base.h" + +class PulseBackendFactory final : public BackendFactory { +public: + bool init() override; + + bool querySupport(BackendType type) override; + + void probe(DevProbe type, std::string *outnames) override; + + BackendPtr createBackend(ALCdevice *device, BackendType type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_PULSEAUDIO_H */ diff --git a/alc/backends/qsa.cpp b/alc/backends/qsa.cpp new file mode 100644 index 00000000..64ed53aa --- /dev/null +++ b/alc/backends/qsa.cpp @@ -0,0 +1,953 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2011-2013 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "backends/qsa.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "alcmain.h" +#include "alu.h" +#include "threads.h" + +#include +#include + + +namespace { + +struct qsa_data { + snd_pcm_t* pcmHandle{nullptr}; + int audio_fd{-1}; + + snd_pcm_channel_setup_t csetup{}; + snd_pcm_channel_params_t cparams{}; + + ALvoid* buffer{nullptr}; + ALsizei size{0}; + + std::atomic mKillNow{AL_TRUE}; + std::thread mThread; +}; + +struct DevMap { + ALCchar* name; + int card; + int dev; +}; + +al::vector DeviceNameMap; +al::vector CaptureNameMap; + +constexpr ALCchar qsaDevice[] = "QSA Default"; + +constexpr struct { + int32_t format; +} formatlist[] = { + {SND_PCM_SFMT_FLOAT_LE}, + {SND_PCM_SFMT_S32_LE}, + {SND_PCM_SFMT_U32_LE}, + {SND_PCM_SFMT_S16_LE}, + {SND_PCM_SFMT_U16_LE}, + {SND_PCM_SFMT_S8}, + {SND_PCM_SFMT_U8}, + {0}, +}; + +constexpr struct { + int32_t rate; +} ratelist[] = { + {192000}, + {176400}, + {96000}, + {88200}, + {48000}, + {44100}, + {32000}, + {24000}, + {22050}, + {16000}, + {12000}, + {11025}, + {8000}, + {0}, +}; + +constexpr struct { + int32_t channels; +} channellist[] = { + {8}, + {7}, + {6}, + {4}, + {2}, + {1}, + {0}, +}; + +void deviceList(int type, al::vector *devmap) +{ + snd_ctl_t* handle; + snd_pcm_info_t pcminfo; + int max_cards, card, err, dev; + DevMap entry; + char name[1024]; + snd_ctl_hw_info info; + + max_cards = snd_cards(); + if(max_cards < 0) + return; + + std::for_each(devmap->begin(), devmap->end(), + [](const DevMap &entry) -> void + { free(entry.name); } + ); + devmap->clear(); + + entry.name = strdup(qsaDevice); + entry.card = 0; + entry.dev = 0; + devmap->push_back(entry); + + for(card = 0;card < max_cards;card++) + { + if((err=snd_ctl_open(&handle, card)) < 0) + continue; + + if((err=snd_ctl_hw_info(handle, &info)) < 0) + { + snd_ctl_close(handle); + continue; + } + + for(dev = 0;dev < (int)info.pcmdevs;dev++) + { + if((err=snd_ctl_pcm_info(handle, dev, &pcminfo)) < 0) + continue; + + if((type==SND_PCM_CHANNEL_PLAYBACK && (pcminfo.flags&SND_PCM_INFO_PLAYBACK)) || + (type==SND_PCM_CHANNEL_CAPTURE && (pcminfo.flags&SND_PCM_INFO_CAPTURE))) + { + snprintf(name, sizeof(name), "%s [%s] (hw:%d,%d)", info.name, pcminfo.name, card, dev); + entry.name = strdup(name); + entry.card = card; + entry.dev = dev; + + devmap->push_back(entry); + TRACE("Got device \"%s\", card %d, dev %d\n", name, card, dev); + } + } + snd_ctl_close(handle); + } +} + + +/* Wrappers to use an old-style backend with the new interface. */ +struct PlaybackWrapper final : public BackendBase { + PlaybackWrapper(ALCdevice *device) noexcept : BackendBase{device} { } + ~PlaybackWrapper() override; + + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + + std::unique_ptr mExtraData; + + DEF_NEWDEL(PlaybackWrapper) +}; + + +FORCE_ALIGN static int qsa_proc_playback(void *ptr) +{ + PlaybackWrapper *self = static_cast(ptr); + ALCdevice *device = self->mDevice; + qsa_data *data = self->mExtraData.get(); + snd_pcm_channel_status_t status; + sched_param param; + char* write_ptr; + ALint len; + int sret; + + SetRTPriority(); + althrd_setname(MIXER_THREAD_NAME); + + /* Increase default 10 priority to 11 to avoid jerky sound */ + SchedGet(0, 0, ¶m); + param.sched_priority=param.sched_curpriority+1; + SchedSet(0, 0, SCHED_NOCHANGE, ¶m); + + const ALint frame_size = device->frameSizeFromFmt(); + + self->lock(); + while(!data->mKillNow.load(std::memory_order_acquire)) + { + pollfd pollitem{}; + pollitem.fd = data->audio_fd; + pollitem.events = POLLOUT; + + /* Select also works like time slice to OS */ + self->unlock(); + sret = poll(&pollitem, 1, 2000); + self->lock(); + if(sret == -1) + { + if(errno == EINTR || errno == EAGAIN) + continue; + ERR("poll error: %s\n", strerror(errno)); + aluHandleDisconnect(device, "Failed waiting for playback buffer: %s", strerror(errno)); + break; + } + if(sret == 0) + { + ERR("poll timeout\n"); + continue; + } + + len = data->size; + write_ptr = static_cast(data->buffer); + aluMixData(device, write_ptr, len/frame_size); + while(len>0 && !data->mKillNow.load(std::memory_order_acquire)) + { + int wrote = snd_pcm_plugin_write(data->pcmHandle, write_ptr, len); + if(wrote <= 0) + { + if(errno==EAGAIN || errno==EWOULDBLOCK) + continue; + + memset(&status, 0, sizeof(status)); + status.channel = SND_PCM_CHANNEL_PLAYBACK; + + snd_pcm_plugin_status(data->pcmHandle, &status); + + /* we need to reinitialize the sound channel if we've underrun the buffer */ + if(status.status == SND_PCM_STATUS_UNDERRUN || + status.status == SND_PCM_STATUS_READY) + { + if(snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK) < 0) + { + aluHandleDisconnect(device, "Playback recovery failed"); + break; + } + } + } + else + { + write_ptr += wrote; + len -= wrote; + } + } + } + self->unlock(); + + return 0; +} + +/************/ +/* Playback */ +/************/ + +static ALCenum qsa_open_playback(PlaybackWrapper *self, const ALCchar* deviceName) +{ + ALCdevice *device = self->mDevice; + int card, dev; + int status; + + std::unique_ptr data{new qsa_data{}}; + data->mKillNow.store(AL_TRUE, std::memory_order_relaxed); + + if(!deviceName) + deviceName = qsaDevice; + + if(strcmp(deviceName, qsaDevice) == 0) + status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_PLAYBACK); + else + { + if(DeviceNameMap.empty()) + deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap); + + auto iter = std::find_if(DeviceNameMap.begin(), DeviceNameMap.end(), + [deviceName](const DevMap &entry) -> bool + { return entry.name && strcmp(deviceName, entry.name) == 0; } + ); + if(iter == DeviceNameMap.cend()) + return ALC_INVALID_DEVICE; + + status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_PLAYBACK); + } + + if(status < 0) + return ALC_INVALID_DEVICE; + + data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK); + if(data->audio_fd < 0) + { + snd_pcm_close(data->pcmHandle); + return ALC_INVALID_DEVICE; + } + + device->DeviceName = deviceName; + self->mExtraData = std::move(data); + + return ALC_NO_ERROR; +} + +static void qsa_close_playback(PlaybackWrapper *self) +{ + qsa_data *data = self->mExtraData.get(); + + if (data->buffer!=NULL) + { + free(data->buffer); + data->buffer=NULL; + } + + snd_pcm_close(data->pcmHandle); + + self->mExtraData = nullptr; +} + +static ALCboolean qsa_reset_playback(PlaybackWrapper *self) +{ + ALCdevice *device = self->mDevice; + qsa_data *data = self->mExtraData.get(); + int32_t format=-1; + + switch(device->FmtType) + { + case DevFmtByte: + format=SND_PCM_SFMT_S8; + break; + case DevFmtUByte: + format=SND_PCM_SFMT_U8; + break; + case DevFmtShort: + format=SND_PCM_SFMT_S16_LE; + break; + case DevFmtUShort: + format=SND_PCM_SFMT_U16_LE; + break; + case DevFmtInt: + format=SND_PCM_SFMT_S32_LE; + break; + case DevFmtUInt: + format=SND_PCM_SFMT_U32_LE; + break; + case DevFmtFloat: + format=SND_PCM_SFMT_FLOAT_LE; + break; + } + + /* we actually don't want to block on writes */ + snd_pcm_nonblock_mode(data->pcmHandle, 1); + /* Disable mmap to control data transfer to the audio device */ + snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_MMAP); + snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_BUFFER_PARTIAL_BLOCKS); + + // configure a sound channel + memset(&data->cparams, 0, sizeof(data->cparams)); + data->cparams.channel=SND_PCM_CHANNEL_PLAYBACK; + data->cparams.mode=SND_PCM_MODE_BLOCK; + data->cparams.start_mode=SND_PCM_START_FULL; + data->cparams.stop_mode=SND_PCM_STOP_STOP; + + data->cparams.buf.block.frag_size=device->UpdateSize * device->frameSizeFromFmt(); + data->cparams.buf.block.frags_max=device->BufferSize / device->UpdateSize; + data->cparams.buf.block.frags_min=data->cparams.buf.block.frags_max; + + data->cparams.format.interleave=1; + data->cparams.format.rate=device->Frequency; + data->cparams.format.voices=device->channelsFromFmt(); + data->cparams.format.format=format; + + if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0) + { + int original_rate=data->cparams.format.rate; + int original_voices=data->cparams.format.voices; + int original_format=data->cparams.format.format; + int it; + int jt; + + for (it=0; it<1; it++) + { + /* Check for second pass */ + if (it==1) + { + original_rate=ratelist[0].rate; + original_voices=channellist[0].channels; + original_format=formatlist[0].format; + } + + do { + /* At first downgrade sample format */ + jt=0; + do { + if (formatlist[jt].format==data->cparams.format.format) + { + data->cparams.format.format=formatlist[jt+1].format; + break; + } + if (formatlist[jt].format==0) + { + data->cparams.format.format=0; + break; + } + jt++; + } while(1); + + if (data->cparams.format.format==0) + { + data->cparams.format.format=original_format; + + /* At secod downgrade sample rate */ + jt=0; + do { + if (ratelist[jt].rate==data->cparams.format.rate) + { + data->cparams.format.rate=ratelist[jt+1].rate; + break; + } + if (ratelist[jt].rate==0) + { + data->cparams.format.rate=0; + break; + } + jt++; + } while(1); + + if (data->cparams.format.rate==0) + { + data->cparams.format.rate=original_rate; + data->cparams.format.format=original_format; + + /* At third downgrade channels number */ + jt=0; + do { + if(channellist[jt].channels==data->cparams.format.voices) + { + data->cparams.format.voices=channellist[jt+1].channels; + break; + } + if (channellist[jt].channels==0) + { + data->cparams.format.voices=0; + break; + } + jt++; + } while(1); + } + + if (data->cparams.format.voices==0) + { + break; + } + } + + data->cparams.buf.block.frag_size=device->UpdateSize* + data->cparams.format.voices* + snd_pcm_format_width(data->cparams.format.format)/8; + data->cparams.buf.block.frags_max=device->NumUpdates; + data->cparams.buf.block.frags_min=device->NumUpdates; + if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0) + { + continue; + } + else + { + break; + } + } while(1); + + if (data->cparams.format.voices!=0) + { + break; + } + } + + if (data->cparams.format.voices==0) + { + return ALC_FALSE; + } + } + + if ((snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK))<0) + { + return ALC_FALSE; + } + + memset(&data->csetup, 0, sizeof(data->csetup)); + data->csetup.channel=SND_PCM_CHANNEL_PLAYBACK; + if (snd_pcm_plugin_setup(data->pcmHandle, &data->csetup)<0) + { + return ALC_FALSE; + } + + /* now fill back to the our AL device */ + device->Frequency=data->cparams.format.rate; + + switch (data->cparams.format.voices) + { + case 1: + device->FmtChans=DevFmtMono; + break; + case 2: + device->FmtChans=DevFmtStereo; + break; + case 4: + device->FmtChans=DevFmtQuad; + break; + case 6: + device->FmtChans=DevFmtX51; + break; + case 7: + device->FmtChans=DevFmtX61; + break; + case 8: + device->FmtChans=DevFmtX71; + break; + default: + device->FmtChans=DevFmtMono; + break; + } + + switch (data->cparams.format.format) + { + case SND_PCM_SFMT_S8: + device->FmtType=DevFmtByte; + break; + case SND_PCM_SFMT_U8: + device->FmtType=DevFmtUByte; + break; + case SND_PCM_SFMT_S16_LE: + device->FmtType=DevFmtShort; + break; + case SND_PCM_SFMT_U16_LE: + device->FmtType=DevFmtUShort; + break; + case SND_PCM_SFMT_S32_LE: + device->FmtType=DevFmtInt; + break; + case SND_PCM_SFMT_U32_LE: + device->FmtType=DevFmtUInt; + break; + case SND_PCM_SFMT_FLOAT_LE: + device->FmtType=DevFmtFloat; + break; + default: + device->FmtType=DevFmtShort; + break; + } + + SetDefaultChannelOrder(device); + + device->UpdateSize=data->csetup.buf.block.frag_size / device->frameSizeFromFmt(); + device->NumUpdates=data->csetup.buf.block.frags; + + data->size=data->csetup.buf.block.frag_size; + data->buffer=malloc(data->size); + if (!data->buffer) + { + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static ALCboolean qsa_start_playback(PlaybackWrapper *self) +{ + qsa_data *data = self->mExtraData.get(); + + try { + data->mKillNow.store(AL_FALSE, std::memory_order_release); + data->mThread = std::thread(qsa_proc_playback, self); + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Could not create playback thread: %s\n", e.what()); + } + catch(...) { + } + return ALC_FALSE; +} + +static void qsa_stop_playback(PlaybackWrapper *self) +{ + qsa_data *data = self->mExtraData.get(); + + if(data->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !data->mThread.joinable()) + return; + data->mThread.join(); +} + + +PlaybackWrapper::~PlaybackWrapper() +{ + if(mExtraData) + qsa_close_playback(this); +} + +ALCenum PlaybackWrapper::open(const ALCchar *name) +{ return qsa_open_playback(this, name); } + +ALCboolean PlaybackWrapper::reset() +{ return qsa_reset_playback(this); } + +ALCboolean PlaybackWrapper::start() +{ return qsa_start_playback(this); } + +void PlaybackWrapper::stop() +{ qsa_stop_playback(this); } + + +/***********/ +/* Capture */ +/***********/ + +struct CaptureWrapper final : public BackendBase { + CaptureWrapper(ALCdevice *device) noexcept : BackendBase{device} { } + ~CaptureWrapper() override; + + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + + std::unique_ptr mExtraData; + + DEF_NEWDEL(CaptureWrapper) +}; + +static ALCenum qsa_open_capture(CaptureWrapper *self, const ALCchar *deviceName) +{ + ALCdevice *device = self->mDevice; + int card, dev; + int format=-1; + int status; + + std::unique_ptr data{new qsa_data{}}; + + if(!deviceName) + deviceName = qsaDevice; + + if(strcmp(deviceName, qsaDevice) == 0) + status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_CAPTURE); + else + { + if(CaptureNameMap.empty()) + deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap); + + auto iter = std::find_if(CaptureNameMap.cbegin(), CaptureNameMap.cend(), + [deviceName](const DevMap &entry) -> bool + { return entry.name && strcmp(deviceName, entry.name) == 0; } + ); + if(iter == CaptureNameMap.cend()) + return ALC_INVALID_DEVICE; + + status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_CAPTURE); + } + + if(status < 0) + return ALC_INVALID_DEVICE; + + data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE); + if(data->audio_fd < 0) + { + snd_pcm_close(data->pcmHandle); + return ALC_INVALID_DEVICE; + } + + device->DeviceName = deviceName; + + switch (device->FmtType) + { + case DevFmtByte: + format=SND_PCM_SFMT_S8; + break; + case DevFmtUByte: + format=SND_PCM_SFMT_U8; + break; + case DevFmtShort: + format=SND_PCM_SFMT_S16_LE; + break; + case DevFmtUShort: + format=SND_PCM_SFMT_U16_LE; + break; + case DevFmtInt: + format=SND_PCM_SFMT_S32_LE; + break; + case DevFmtUInt: + format=SND_PCM_SFMT_U32_LE; + break; + case DevFmtFloat: + format=SND_PCM_SFMT_FLOAT_LE; + break; + } + + /* we actually don't want to block on reads */ + snd_pcm_nonblock_mode(data->pcmHandle, 1); + /* Disable mmap to control data transfer to the audio device */ + snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_MMAP); + + /* configure a sound channel */ + memset(&data->cparams, 0, sizeof(data->cparams)); + data->cparams.mode=SND_PCM_MODE_BLOCK; + data->cparams.channel=SND_PCM_CHANNEL_CAPTURE; + data->cparams.start_mode=SND_PCM_START_GO; + data->cparams.stop_mode=SND_PCM_STOP_STOP; + + data->cparams.buf.block.frag_size=device->UpdateSize * device->frameSizeFromFmt(); + data->cparams.buf.block.frags_max=device->NumUpdates; + data->cparams.buf.block.frags_min=device->NumUpdates; + + data->cparams.format.interleave=1; + data->cparams.format.rate=device->Frequency; + data->cparams.format.voices=device->channelsFromFmt(); + data->cparams.format.format=format; + + if(snd_pcm_plugin_params(data->pcmHandle, &data->cparams) < 0) + { + snd_pcm_close(data->pcmHandle); + return ALC_INVALID_VALUE; + } + + self->mExtraData = std::move(data); + + return ALC_NO_ERROR; +} + +static void qsa_close_capture(CaptureWrapper *self) +{ + qsa_data *data = self->mExtraData.get(); + + if (data->pcmHandle!=nullptr) + snd_pcm_close(data->pcmHandle); + data->pcmHandle = nullptr; + + self->mExtraData = nullptr; +} + +static void qsa_start_capture(CaptureWrapper *self) +{ + qsa_data *data = self->mExtraData.get(); + int rstatus; + + if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0) + { + ERR("capture prepare failed: %s\n", snd_strerror(rstatus)); + return; + } + + memset(&data->csetup, 0, sizeof(data->csetup)); + data->csetup.channel=SND_PCM_CHANNEL_CAPTURE; + if ((rstatus=snd_pcm_plugin_setup(data->pcmHandle, &data->csetup))<0) + { + ERR("capture setup failed: %s\n", snd_strerror(rstatus)); + return; + } + + snd_pcm_capture_go(data->pcmHandle); +} + +static void qsa_stop_capture(CaptureWrapper *self) +{ + qsa_data *data = self->mExtraData.get(); + snd_pcm_capture_flush(data->pcmHandle); +} + +static ALCuint qsa_available_samples(CaptureWrapper *self) +{ + ALCdevice *device = self->mDevice; + qsa_data *data = self->mExtraData.get(); + snd_pcm_channel_status_t status; + ALint frame_size = device->frameSizeFromFmt(); + ALint free_size; + int rstatus; + + memset(&status, 0, sizeof (status)); + status.channel=SND_PCM_CHANNEL_CAPTURE; + snd_pcm_plugin_status(data->pcmHandle, &status); + if ((status.status==SND_PCM_STATUS_OVERRUN) || + (status.status==SND_PCM_STATUS_READY)) + { + if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0) + { + ERR("capture prepare failed: %s\n", snd_strerror(rstatus)); + aluHandleDisconnect(device, "Failed capture recovery: %s", snd_strerror(rstatus)); + return 0; + } + + snd_pcm_capture_go(data->pcmHandle); + return 0; + } + + free_size=data->csetup.buf.block.frag_size*data->csetup.buf.block.frags; + free_size-=status.free; + + return free_size/frame_size; +} + +static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuint samples) +{ + ALCdevice *device = self->mDevice; + qsa_data *data = self->mExtraData.get(); + char* read_ptr; + snd_pcm_channel_status_t status; + int selectret; + int bytes_read; + ALint frame_size=device->frameSizeFromFmt(); + ALint len=samples*frame_size; + int rstatus; + + read_ptr = static_cast(buffer); + + while (len>0) + { + pollfd pollitem{}; + pollitem.fd = data->audio_fd; + pollitem.events = POLLOUT; + + /* Select also works like time slice to OS */ + bytes_read=0; + selectret = poll(&pollitem, 1, 2000); + switch (selectret) + { + case -1: + aluHandleDisconnect(device, "Failed to check capture samples"); + return ALC_INVALID_DEVICE; + case 0: + break; + default: + bytes_read=snd_pcm_plugin_read(data->pcmHandle, read_ptr, len); + break; + } + + if (bytes_read<=0) + { + if ((errno==EAGAIN) || (errno==EWOULDBLOCK)) + { + continue; + } + + memset(&status, 0, sizeof (status)); + status.channel=SND_PCM_CHANNEL_CAPTURE; + snd_pcm_plugin_status(data->pcmHandle, &status); + + /* we need to reinitialize the sound channel if we've overrun the buffer */ + if ((status.status==SND_PCM_STATUS_OVERRUN) || + (status.status==SND_PCM_STATUS_READY)) + { + if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0) + { + ERR("capture prepare failed: %s\n", snd_strerror(rstatus)); + aluHandleDisconnect(device, "Failed capture recovery: %s", + snd_strerror(rstatus)); + return ALC_INVALID_DEVICE; + } + snd_pcm_capture_go(data->pcmHandle); + } + } + else + { + read_ptr+=bytes_read; + len-=bytes_read; + } + } + + return ALC_NO_ERROR; +} + + +CaptureWrapper::~CaptureWrapper() +{ + if(mExtraData) + qsa_close_capture(this); +} + +ALCenum CaptureWrapper::open(const ALCchar *name) +{ return qsa_open_capture(this, name); } + +ALCboolean CaptureWrapper::start() +{ qsa_start_capture(this); return ALC_TRUE; } + +void CaptureWrapper::stop() +{ qsa_stop_capture(this); } + +ALCenum CaptureWrapper::captureSamples(void *buffer, ALCuint samples) +{ return qsa_capture_samples(this, buffer, samples); } + +ALCuint CaptureWrapper::availableSamples() +{ return qsa_available_samples(this); } + +} // namespace + + +bool QSABackendFactory::init() +{ return true; } + +bool QSABackendFactory::querySupport(BackendType type) +{ return (type == BackendType::Playback || type == BackendType::Capture); } + +void QSABackendFactory::probe(DevProbe type, std::string *outnames) +{ + auto add_device = [outnames](const DevMap &entry) -> void + { + const char *n = entry.name; + if(n && n[0]) + outnames->append(n, strlen(n)+1); + }; + + switch (type) + { + case DevProbe::Playback: + deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap); + std::for_each(DeviceNameMap.cbegin(), DeviceNameMap.cend(), add_device); + break; + case DevProbe::Capture: + deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap); + std::for_each(CaptureNameMap.cbegin(), CaptureNameMap.cend(), add_device); + break; + } +} + +BackendPtr QSABackendFactory::createBackend(ALCdevice *device, BackendType type) +{ + if(type == BackendType::Playback) + return BackendPtr{new PlaybackWrapper{device}}; + if(type == BackendType::Capture) + return BackendPtr{new CaptureWrapper{device}}; + return nullptr; +} + +BackendFactory &QSABackendFactory::getFactory() +{ + static QSABackendFactory factory{}; + return factory; +} diff --git a/alc/backends/qsa.h b/alc/backends/qsa.h new file mode 100644 index 00000000..da548bba --- /dev/null +++ b/alc/backends/qsa.h @@ -0,0 +1,19 @@ +#ifndef BACKENDS_QSA_H +#define BACKENDS_QSA_H + +#include "backends/base.h" + +struct QSABackendFactory final : public BackendFactory { +public: + bool init() override; + + bool querySupport(BackendType type) override; + + void probe(DevProbe type, std::string *outnames) override; + + BackendPtr createBackend(ALCdevice *device, BackendType type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_QSA_H */ diff --git a/alc/backends/sdl2.cpp b/alc/backends/sdl2.cpp new file mode 100644 index 00000000..29d27c05 --- /dev/null +++ b/alc/backends/sdl2.cpp @@ -0,0 +1,227 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2018 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "backends/sdl2.h" + +#include +#include +#include +#include + +#include "AL/al.h" + +#include "alcmain.h" +#include "almalloc.h" +#include "alu.h" +#include "logging.h" + +#include + + +namespace { + +#ifdef _WIN32 +#define DEVNAME_PREFIX "OpenAL Soft on " +#else +#define DEVNAME_PREFIX "" +#endif + +constexpr ALCchar defaultDeviceName[] = DEVNAME_PREFIX "Default Device"; + +struct Sdl2Backend final : public BackendBase { + Sdl2Backend(ALCdevice *device) noexcept : BackendBase{device} { } + ~Sdl2Backend() override; + + static void audioCallbackC(void *ptr, Uint8 *stream, int len); + void audioCallback(Uint8 *stream, int len); + + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + void lock() override; + void unlock() override; + + SDL_AudioDeviceID mDeviceID{0u}; + ALsizei mFrameSize{0}; + + ALuint mFrequency{0u}; + DevFmtChannels mFmtChans{}; + DevFmtType mFmtType{}; + ALuint mUpdateSize{0u}; + + DEF_NEWDEL(Sdl2Backend) +}; + +Sdl2Backend::~Sdl2Backend() +{ + if(mDeviceID) + SDL_CloseAudioDevice(mDeviceID); + mDeviceID = 0; +} + +void Sdl2Backend::audioCallbackC(void *ptr, Uint8 *stream, int len) +{ static_cast(ptr)->audioCallback(stream, len); } + +void Sdl2Backend::audioCallback(Uint8 *stream, int len) +{ + assert((len % mFrameSize) == 0); + aluMixData(mDevice, stream, len / mFrameSize); +} + +ALCenum Sdl2Backend::open(const ALCchar *name) +{ + SDL_AudioSpec want{}, have{}; + want.freq = mDevice->Frequency; + switch(mDevice->FmtType) + { + case DevFmtUByte: want.format = AUDIO_U8; break; + case DevFmtByte: want.format = AUDIO_S8; break; + case DevFmtUShort: want.format = AUDIO_U16SYS; break; + case DevFmtShort: want.format = AUDIO_S16SYS; break; + case DevFmtUInt: /* fall-through */ + case DevFmtInt: want.format = AUDIO_S32SYS; break; + case DevFmtFloat: want.format = AUDIO_F32; break; + } + want.channels = (mDevice->FmtChans == DevFmtMono) ? 1 : 2; + want.samples = mDevice->UpdateSize; + want.callback = &Sdl2Backend::audioCallbackC; + want.userdata = this; + + /* Passing nullptr to SDL_OpenAudioDevice opens a default, which isn't + * necessarily the first in the list. + */ + if(!name || strcmp(name, defaultDeviceName) == 0) + mDeviceID = SDL_OpenAudioDevice(nullptr, SDL_FALSE, &want, &have, + SDL_AUDIO_ALLOW_ANY_CHANGE); + else + { + const size_t prefix_len = strlen(DEVNAME_PREFIX); + if(strncmp(name, DEVNAME_PREFIX, prefix_len) == 0) + mDeviceID = SDL_OpenAudioDevice(name+prefix_len, SDL_FALSE, &want, &have, + SDL_AUDIO_ALLOW_ANY_CHANGE); + else + mDeviceID = SDL_OpenAudioDevice(name, SDL_FALSE, &want, &have, + SDL_AUDIO_ALLOW_ANY_CHANGE); + } + if(mDeviceID == 0) + return ALC_INVALID_VALUE; + + mDevice->Frequency = have.freq; + if(have.channels == 1) + mDevice->FmtChans = DevFmtMono; + else if(have.channels == 2) + mDevice->FmtChans = DevFmtStereo; + else + { + ERR("Got unhandled SDL channel count: %d\n", (int)have.channels); + return ALC_INVALID_VALUE; + } + switch(have.format) + { + case AUDIO_U8: mDevice->FmtType = DevFmtUByte; break; + case AUDIO_S8: mDevice->FmtType = DevFmtByte; break; + case AUDIO_U16SYS: mDevice->FmtType = DevFmtUShort; break; + case AUDIO_S16SYS: mDevice->FmtType = DevFmtShort; break; + case AUDIO_S32SYS: mDevice->FmtType = DevFmtInt; break; + case AUDIO_F32SYS: mDevice->FmtType = DevFmtFloat; break; + default: + ERR("Got unsupported SDL format: 0x%04x\n", have.format); + return ALC_INVALID_VALUE; + } + mDevice->UpdateSize = have.samples; + mDevice->BufferSize = have.samples * 2; /* SDL always (tries to) use two periods. */ + + mFrameSize = mDevice->frameSizeFromFmt(); + mFrequency = mDevice->Frequency; + mFmtChans = mDevice->FmtChans; + mFmtType = mDevice->FmtType; + mUpdateSize = mDevice->UpdateSize; + + mDevice->DeviceName = name ? name : defaultDeviceName; + return ALC_NO_ERROR; +} + +ALCboolean Sdl2Backend::reset() +{ + mDevice->Frequency = mFrequency; + mDevice->FmtChans = mFmtChans; + mDevice->FmtType = mFmtType; + mDevice->UpdateSize = mUpdateSize; + mDevice->BufferSize = mUpdateSize * 2; + SetDefaultWFXChannelOrder(mDevice); + return ALC_TRUE; +} + +ALCboolean Sdl2Backend::start() +{ + SDL_PauseAudioDevice(mDeviceID, 0); + return ALC_TRUE; +} + +void Sdl2Backend::stop() +{ SDL_PauseAudioDevice(mDeviceID, 1); } + +void Sdl2Backend::lock() +{ SDL_LockAudioDevice(mDeviceID); } + +void Sdl2Backend::unlock() +{ SDL_UnlockAudioDevice(mDeviceID); } + +} // namespace + +BackendFactory &SDL2BackendFactory::getFactory() +{ + static SDL2BackendFactory factory{}; + return factory; +} + +bool SDL2BackendFactory::init() +{ return (SDL_InitSubSystem(SDL_INIT_AUDIO) == 0); } + +bool SDL2BackendFactory::querySupport(BackendType type) +{ return type == BackendType::Playback; } + +void SDL2BackendFactory::probe(DevProbe type, std::string *outnames) +{ + if(type != DevProbe::Playback) + return; + + int num_devices{SDL_GetNumAudioDevices(SDL_FALSE)}; + + /* Includes null char. */ + outnames->append(defaultDeviceName, sizeof(defaultDeviceName)); + for(int i{0};i < num_devices;++i) + { + std::string name{DEVNAME_PREFIX}; + name += SDL_GetAudioDeviceName(i, SDL_FALSE); + if(!name.empty()) + outnames->append(name.c_str(), name.length()+1); + } +} + +BackendPtr SDL2BackendFactory::createBackend(ALCdevice *device, BackendType type) +{ + if(type == BackendType::Playback) + return BackendPtr{new Sdl2Backend{device}}; + return nullptr; +} diff --git a/alc/backends/sdl2.h b/alc/backends/sdl2.h new file mode 100644 index 00000000..041d47ee --- /dev/null +++ b/alc/backends/sdl2.h @@ -0,0 +1,19 @@ +#ifndef BACKENDS_SDL2_H +#define BACKENDS_SDL2_H + +#include "backends/base.h" + +struct SDL2BackendFactory final : public BackendFactory { +public: + bool init() override; + + bool querySupport(BackendType type) override; + + void probe(DevProbe type, std::string *outnames) override; + + BackendPtr createBackend(ALCdevice *device, BackendType type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_SDL2_H */ diff --git a/alc/backends/sndio.cpp b/alc/backends/sndio.cpp new file mode 100644 index 00000000..587f67bb --- /dev/null +++ b/alc/backends/sndio.cpp @@ -0,0 +1,495 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "backends/sndio.h" + +#include +#include +#include + +#include +#include + +#include "alcmain.h" +#include "alu.h" +#include "threads.h" +#include "vector.h" +#include "ringbuffer.h" + +#include + + +namespace { + +static const ALCchar sndio_device[] = "SndIO Default"; + + +struct SndioPlayback final : public BackendBase { + SndioPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~SndioPlayback() override; + + int mixerProc(); + + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + + sio_hdl *mSndHandle{nullptr}; + + al::vector mBuffer; + + std::atomic mKillNow{true}; + std::thread mThread; + + DEF_NEWDEL(SndioPlayback) +}; + +SndioPlayback::~SndioPlayback() +{ + if(mSndHandle) + sio_close(mSndHandle); + mSndHandle = nullptr; +} + +int SndioPlayback::mixerProc() +{ + SetRTPriority(); + althrd_setname(MIXER_THREAD_NAME); + + const ALsizei frameSize{mDevice->frameSizeFromFmt()}; + + while(!mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) + { + auto WritePtr = static_cast(mBuffer.data()); + size_t len{mBuffer.size()}; + + lock(); + aluMixData(mDevice, WritePtr, len/frameSize); + unlock(); + while(len > 0 && !mKillNow.load(std::memory_order_acquire)) + { + size_t wrote{sio_write(mSndHandle, WritePtr, len)}; + if(wrote == 0) + { + ERR("sio_write failed\n"); + aluHandleDisconnect(mDevice, "Failed to write playback samples"); + break; + } + + len -= wrote; + WritePtr += wrote; + } + } + + return 0; +} + + +ALCenum SndioPlayback::open(const ALCchar *name) +{ + if(!name) + name = sndio_device; + else if(strcmp(name, sndio_device) != 0) + return ALC_INVALID_VALUE; + + mSndHandle = sio_open(nullptr, SIO_PLAY, 0); + if(mSndHandle == nullptr) + { + ERR("Could not open device\n"); + return ALC_INVALID_VALUE; + } + + mDevice->DeviceName = name; + return ALC_NO_ERROR; +} + +ALCboolean SndioPlayback::reset() +{ + sio_par par; + sio_initpar(&par); + + par.rate = mDevice->Frequency; + par.pchan = ((mDevice->FmtChans != DevFmtMono) ? 2 : 1); + + switch(mDevice->FmtType) + { + case DevFmtByte: + par.bits = 8; + par.sig = 1; + break; + case DevFmtUByte: + par.bits = 8; + par.sig = 0; + break; + case DevFmtFloat: + case DevFmtShort: + par.bits = 16; + par.sig = 1; + break; + case DevFmtUShort: + par.bits = 16; + par.sig = 0; + break; + case DevFmtInt: + par.bits = 32; + par.sig = 1; + break; + case DevFmtUInt: + par.bits = 32; + par.sig = 0; + break; + } + par.le = SIO_LE_NATIVE; + + par.round = mDevice->UpdateSize; + par.appbufsz = mDevice->BufferSize - mDevice->UpdateSize; + if(!par.appbufsz) par.appbufsz = mDevice->UpdateSize; + + if(!sio_setpar(mSndHandle, &par) || !sio_getpar(mSndHandle, &par)) + { + ERR("Failed to set device parameters\n"); + return ALC_FALSE; + } + + if(par.bits != par.bps*8) + { + ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8); + return ALC_FALSE; + } + + mDevice->Frequency = par.rate; + mDevice->FmtChans = ((par.pchan==1) ? DevFmtMono : DevFmtStereo); + + if(par.bits == 8 && par.sig == 1) + mDevice->FmtType = DevFmtByte; + else if(par.bits == 8 && par.sig == 0) + mDevice->FmtType = DevFmtUByte; + else if(par.bits == 16 && par.sig == 1) + mDevice->FmtType = DevFmtShort; + else if(par.bits == 16 && par.sig == 0) + mDevice->FmtType = DevFmtUShort; + else if(par.bits == 32 && par.sig == 1) + mDevice->FmtType = DevFmtInt; + else if(par.bits == 32 && par.sig == 0) + mDevice->FmtType = DevFmtUInt; + else + { + ERR("Unhandled sample format: %s %u-bit\n", (par.sig?"signed":"unsigned"), par.bits); + return ALC_FALSE; + } + + SetDefaultChannelOrder(mDevice); + + mDevice->UpdateSize = par.round; + mDevice->BufferSize = par.bufsz + par.round; + + mBuffer.resize(mDevice->UpdateSize * mDevice->frameSizeFromFmt()); + std::fill(mBuffer.begin(), mBuffer.end(), 0); + + return ALC_TRUE; +} + +ALCboolean SndioPlayback::start() +{ + if(!sio_start(mSndHandle)) + { + ERR("Error starting playback\n"); + return ALC_FALSE; + } + + try { + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&SndioPlayback::mixerProc), this}; + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Could not create playback thread: %s\n", e.what()); + } + catch(...) { + } + sio_stop(mSndHandle); + return ALC_FALSE; +} + +void SndioPlayback::stop() +{ + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) + return; + mThread.join(); + + if(!sio_stop(mSndHandle)) + ERR("Error stopping device\n"); +} + + +struct SndioCapture final : public BackendBase { + SndioCapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~SndioCapture() override; + + int recordProc(); + + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + + sio_hdl *mSndHandle{nullptr}; + + RingBufferPtr mRing; + + std::atomic mKillNow{true}; + std::thread mThread; + + DEF_NEWDEL(SndioCapture) +}; + +SndioCapture::~SndioCapture() +{ + if(mSndHandle) + sio_close(mSndHandle); + mSndHandle = nullptr; +} + +int SndioCapture::recordProc() +{ + SetRTPriority(); + althrd_setname(RECORD_THREAD_NAME); + + const ALsizei frameSize{mDevice->frameSizeFromFmt()}; + + while(!mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) + { + auto data = mRing->getWriteVector(); + size_t todo{data.first.len + data.second.len}; + if(todo == 0) + { + static char junk[4096]; + sio_read(mSndHandle, junk, + minz(sizeof(junk)/frameSize, mDevice->UpdateSize)*frameSize); + continue; + } + + size_t total{0u}; + data.first.len *= frameSize; + data.second.len *= frameSize; + todo = minz(todo, mDevice->UpdateSize) * frameSize; + while(total < todo) + { + if(!data.first.len) + data.first = data.second; + + size_t got{sio_read(mSndHandle, data.first.buf, minz(todo-total, data.first.len))}; + if(!got) + { + aluHandleDisconnect(mDevice, "Failed to read capture samples"); + break; + } + + data.first.buf += got; + data.first.len -= got; + total += got; + } + mRing->writeAdvance(total / frameSize); + } + + return 0; +} + + +ALCenum SndioCapture::open(const ALCchar *name) +{ + if(!name) + name = sndio_device; + else if(strcmp(name, sndio_device) != 0) + return ALC_INVALID_VALUE; + + mSndHandle = sio_open(nullptr, SIO_REC, 0); + if(mSndHandle == nullptr) + { + ERR("Could not open device\n"); + return ALC_INVALID_VALUE; + } + + sio_par par; + sio_initpar(&par); + + switch(mDevice->FmtType) + { + case DevFmtByte: + par.bps = 1; + par.sig = 1; + break; + case DevFmtUByte: + par.bps = 1; + par.sig = 0; + break; + case DevFmtShort: + par.bps = 2; + par.sig = 1; + break; + case DevFmtUShort: + par.bps = 2; + par.sig = 0; + break; + case DevFmtInt: + par.bps = 4; + par.sig = 1; + break; + case DevFmtUInt: + par.bps = 4; + par.sig = 0; + break; + case DevFmtFloat: + ERR("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); + return ALC_INVALID_VALUE; + } + par.bits = par.bps * 8; + par.le = SIO_LE_NATIVE; + par.msb = SIO_LE_NATIVE ? 0 : 1; + par.rchan = mDevice->channelsFromFmt(); + par.rate = mDevice->Frequency; + + par.appbufsz = maxu(mDevice->BufferSize, mDevice->Frequency/10); + par.round = minu(par.appbufsz, mDevice->Frequency/40); + + mDevice->UpdateSize = par.round; + mDevice->BufferSize = par.appbufsz; + + if(!sio_setpar(mSndHandle, &par) || !sio_getpar(mSndHandle, &par)) + { + ERR("Failed to set device parameters\n"); + return ALC_INVALID_VALUE; + } + + if(par.bits != par.bps*8) + { + ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8); + return ALC_INVALID_VALUE; + } + + if(!((mDevice->FmtType == DevFmtByte && par.bits == 8 && par.sig != 0) || + (mDevice->FmtType == DevFmtUByte && par.bits == 8 && par.sig == 0) || + (mDevice->FmtType == DevFmtShort && par.bits == 16 && par.sig != 0) || + (mDevice->FmtType == DevFmtUShort && par.bits == 16 && par.sig == 0) || + (mDevice->FmtType == DevFmtInt && par.bits == 32 && par.sig != 0) || + (mDevice->FmtType == DevFmtUInt && par.bits == 32 && par.sig == 0)) || + mDevice->channelsFromFmt() != (ALsizei)par.rchan || + mDevice->Frequency != par.rate) + { + ERR("Failed to set format %s %s %uhz, got %c%u %u-channel %uhz instead\n", + DevFmtTypeString(mDevice->FmtType), DevFmtChannelsString(mDevice->FmtChans), + mDevice->Frequency, par.sig?'s':'u', par.bits, par.rchan, par.rate); + return ALC_INVALID_VALUE; + } + + mRing = CreateRingBuffer(mDevice->BufferSize, par.bps*par.rchan, false); + if(!mRing) + { + ERR("Failed to allocate %u-byte ringbuffer\n", mDevice->BufferSize*par.bps*par.rchan); + return ALC_OUT_OF_MEMORY; + } + + SetDefaultChannelOrder(mDevice); + + mDevice->DeviceName = name; + return ALC_NO_ERROR; +} + +ALCboolean SndioCapture::start() +{ + if(!sio_start(mSndHandle)) + { + ERR("Error starting playback\n"); + return ALC_FALSE; + } + + try { + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&SndioCapture::recordProc), this}; + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Could not create record thread: %s\n", e.what()); + } + catch(...) { + } + sio_stop(mSndHandle); + return ALC_FALSE; +} + +void SndioCapture::stop() +{ + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) + return; + mThread.join(); + + if(!sio_stop(mSndHandle)) + ERR("Error stopping device\n"); +} + +ALCenum SndioCapture::captureSamples(void *buffer, ALCuint samples) +{ + mRing->read(buffer, samples); + return ALC_NO_ERROR; +} + +ALCuint SndioCapture::availableSamples() +{ return mRing->readSpace(); } + +} // namespace + +BackendFactory &SndIOBackendFactory::getFactory() +{ + static SndIOBackendFactory factory{}; + return factory; +} + +bool SndIOBackendFactory::init() +{ return true; } + +bool SndIOBackendFactory::querySupport(BackendType type) +{ return (type == BackendType::Playback || type == BackendType::Capture); } + +void SndIOBackendFactory::probe(DevProbe type, std::string *outnames) +{ + switch(type) + { + case DevProbe::Playback: + case DevProbe::Capture: + /* Includes null char. */ + outnames->append(sndio_device, sizeof(sndio_device)); + break; + } +} + +BackendPtr SndIOBackendFactory::createBackend(ALCdevice *device, BackendType type) +{ + if(type == BackendType::Playback) + return BackendPtr{new SndioPlayback{device}}; + if(type == BackendType::Capture) + return BackendPtr{new SndioCapture{device}}; + return nullptr; +} diff --git a/alc/backends/sndio.h b/alc/backends/sndio.h new file mode 100644 index 00000000..1ed63d5e --- /dev/null +++ b/alc/backends/sndio.h @@ -0,0 +1,19 @@ +#ifndef BACKENDS_SNDIO_H +#define BACKENDS_SNDIO_H + +#include "backends/base.h" + +struct SndIOBackendFactory final : public BackendFactory { +public: + bool init() override; + + bool querySupport(BackendType type) override; + + void probe(DevProbe type, std::string *outnames) override; + + BackendPtr createBackend(ALCdevice *device, BackendType type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_SNDIO_H */ diff --git a/alc/backends/solaris.cpp b/alc/backends/solaris.cpp new file mode 100644 index 00000000..584f6e66 --- /dev/null +++ b/alc/backends/solaris.cpp @@ -0,0 +1,302 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "backends/solaris.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "alcmain.h" +#include "alu.h" +#include "alconfig.h" +#include "threads.h" +#include "vector.h" +#include "compat.h" + +#include + + +namespace { + +constexpr ALCchar solaris_device[] = "Solaris Default"; + +std::string solaris_driver{"/dev/audio"}; + + +struct SolarisBackend final : public BackendBase { + SolarisBackend(ALCdevice *device) noexcept : BackendBase{device} { } + ~SolarisBackend() override; + + int mixerProc(); + + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + + int mFd{-1}; + + al::vector mBuffer; + + std::atomic mKillNow{true}; + std::thread mThread; + + DEF_NEWDEL(SolarisBackend) +}; + +SolarisBackend::~SolarisBackend() +{ + if(mFd != -1) + close(mFd); + mFd = -1; +} + +int SolarisBackend::mixerProc() +{ + SetRTPriority(); + althrd_setname(MIXER_THREAD_NAME); + + const int frame_size{mDevice->frameSizeFromFmt()}; + + lock(); + while(!mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) + { + pollfd pollitem{}; + pollitem.fd = mFd; + pollitem.events = POLLOUT; + + unlock(); + int pret{poll(&pollitem, 1, 1000)}; + lock(); + if(pret < 0) + { + if(errno == EINTR || errno == EAGAIN) + continue; + ERR("poll failed: %s\n", strerror(errno)); + aluHandleDisconnect(mDevice, "Failed to wait for playback buffer: %s", + strerror(errno)); + break; + } + else if(pret == 0) + { + WARN("poll timeout\n"); + continue; + } + + ALubyte *write_ptr{mBuffer.data()}; + size_t to_write{mBuffer.size()}; + aluMixData(mDevice, write_ptr, to_write/frame_size); + while(to_write > 0 && !mKillNow.load(std::memory_order_acquire)) + { + ssize_t wrote{write(mFd, write_ptr, to_write)}; + if(wrote < 0) + { + if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) + continue; + ERR("write failed: %s\n", strerror(errno)); + aluHandleDisconnect(mDevice, "Failed to write playback samples: %s", + strerror(errno)); + break; + } + + to_write -= wrote; + write_ptr += wrote; + } + } + unlock(); + + return 0; +} + + +ALCenum SolarisBackend::open(const ALCchar *name) +{ + if(!name) + name = solaris_device; + else if(strcmp(name, solaris_device) != 0) + return ALC_INVALID_VALUE; + + mFd = ::open(solaris_driver.c_str(), O_WRONLY); + if(mFd == -1) + { + ERR("Could not open %s: %s\n", solaris_driver.c_str(), strerror(errno)); + return ALC_INVALID_VALUE; + } + + mDevice->DeviceName = name; + return ALC_NO_ERROR; +} + +ALCboolean SolarisBackend::reset() +{ + audio_info_t info; + AUDIO_INITINFO(&info); + + info.play.sample_rate = mDevice->Frequency; + + if(mDevice->FmtChans != DevFmtMono) + mDevice->FmtChans = DevFmtStereo; + ALsizei numChannels{mDevice->channelsFromFmt()}; + info.play.channels = numChannels; + + switch(mDevice->FmtType) + { + case DevFmtByte: + info.play.precision = 8; + info.play.encoding = AUDIO_ENCODING_LINEAR; + break; + case DevFmtUByte: + info.play.precision = 8; + info.play.encoding = AUDIO_ENCODING_LINEAR8; + break; + case DevFmtUShort: + case DevFmtInt: + case DevFmtUInt: + case DevFmtFloat: + mDevice->FmtType = DevFmtShort; + /* fall-through */ + case DevFmtShort: + info.play.precision = 16; + info.play.encoding = AUDIO_ENCODING_LINEAR; + break; + } + + ALsizei frameSize{numChannels * mDevice->bytesFromFmt()}; + info.play.buffer_size = mDevice->BufferSize * frameSize; + + if(ioctl(mFd, AUDIO_SETINFO, &info) < 0) + { + ERR("ioctl failed: %s\n", strerror(errno)); + return ALC_FALSE; + } + + if(mDevice->channelsFromFmt() != (ALsizei)info.play.channels) + { + ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(mDevice->FmtChans), + info.play.channels); + return ALC_FALSE; + } + + if(!((info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR8 && mDevice->FmtType == DevFmtUByte) || + (info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR && mDevice->FmtType == DevFmtByte) || + (info.play.precision == 16 && info.play.encoding == AUDIO_ENCODING_LINEAR && mDevice->FmtType == DevFmtShort) || + (info.play.precision == 32 && info.play.encoding == AUDIO_ENCODING_LINEAR && mDevice->FmtType == DevFmtInt))) + { + ERR("Could not set %s samples, got %d (0x%x)\n", DevFmtTypeString(mDevice->FmtType), + info.play.precision, info.play.encoding); + return ALC_FALSE; + } + + mDevice->Frequency = info.play.sample_rate; + mDevice->BufferSize = info.play.buffer_size / frameSize; + mDevice->UpdateSize = mDevice->BufferSize / 2; + + SetDefaultChannelOrder(mDevice); + + mBuffer.resize(mDevice->UpdateSize * mDevice->frameSizeFromFmt()); + std::fill(mBuffer.begin(), mBuffer.end(), 0); + + return ALC_TRUE; +} + +ALCboolean SolarisBackend::start() +{ + try { + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&SolarisBackend::mixerProc), this}; + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Could not create playback thread: %s\n", e.what()); + } + catch(...) { + } + return ALC_FALSE; +} + +void SolarisBackend::stop() +{ + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) + return; + mThread.join(); + + if(ioctl(mFd, AUDIO_DRAIN) < 0) + ERR("Error draining device: %s\n", strerror(errno)); +} + +} // namespace + +BackendFactory &SolarisBackendFactory::getFactory() +{ + static SolarisBackendFactory factory{}; + return factory; +} + +bool SolarisBackendFactory::init() +{ + if(auto devopt = ConfigValueStr(nullptr, "solaris", "device")) + solaris_driver = std::move(*devopt); + return true; +} + +bool SolarisBackendFactory::querySupport(BackendType type) +{ return type == BackendType::Playback; } + +void SolarisBackendFactory::probe(DevProbe type, std::string *outnames) +{ + switch(type) + { + case DevProbe::Playback: + { +#ifdef HAVE_STAT + struct stat buf; + if(stat(solaris_driver.c_str(), &buf) == 0) +#endif + outnames->append(solaris_device, sizeof(solaris_device)); + } + break; + + case DevProbe::Capture: + break; + } +} + +BackendPtr SolarisBackendFactory::createBackend(ALCdevice *device, BackendType type) +{ + if(type == BackendType::Playback) + return BackendPtr{new SolarisBackend{device}}; + return nullptr; +} diff --git a/alc/backends/solaris.h b/alc/backends/solaris.h new file mode 100644 index 00000000..98b10593 --- /dev/null +++ b/alc/backends/solaris.h @@ -0,0 +1,19 @@ +#ifndef BACKENDS_SOLARIS_H +#define BACKENDS_SOLARIS_H + +#include "backends/base.h" + +struct SolarisBackendFactory final : public BackendFactory { +public: + bool init() override; + + bool querySupport(BackendType type) override; + + void probe(DevProbe type, std::string *outnames) override; + + BackendPtr createBackend(ALCdevice *device, BackendType type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_SOLARIS_H */ diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp new file mode 100644 index 00000000..bd009463 --- /dev/null +++ b/alc/backends/wasapi.cpp @@ -0,0 +1,1763 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2011 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "backends/wasapi.h" + +#define WIN32_LEAN_AND_MEAN +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef _WAVEFORMATEXTENSIBLE_ +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "alcmain.h" +#include "alu.h" +#include "ringbuffer.h" +#include "compat.h" +#include "converter.h" +#include "threads.h" + + +/* Some headers seem to define these as macros for __uuidof, which is annoying + * since some headers don't declare them at all. Hopefully the ifdef is enough + * to tell if they need to be declared. + */ +#ifndef KSDATAFORMAT_SUBTYPE_PCM +DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +#endif +#ifndef KSDATAFORMAT_SUBTYPE_IEEE_FLOAT +DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +#endif + +DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23,0xe0, 0xc0,0xff,0xee,0x7f,0x0e, 4 ); + + +namespace { + +#define MONO SPEAKER_FRONT_CENTER +#define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT) +#define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT) +#define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) +#define X5DOT1REAR (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT) +#define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) +#define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) +#define X7DOT1_WIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_FRONT_LEFT_OF_CENTER|SPEAKER_FRONT_RIGHT_OF_CENTER) + +#define REFTIME_PER_SEC ((REFERENCE_TIME)10000000) + +#define DEVNAME_HEAD "OpenAL Soft on " + + +/* Scales the given value using 64-bit integer math, ceiling the result. */ +inline int64_t ScaleCeil(int64_t val, int64_t new_scale, int64_t old_scale) +{ + return (val*new_scale + old_scale-1) / old_scale; +} + + +struct PropVariant { + PROPVARIANT mProp; + +public: + PropVariant() { PropVariantInit(&mProp); } + ~PropVariant() { clear(); } + + void clear() { PropVariantClear(&mProp); } + + PROPVARIANT* get() noexcept { return &mProp; } + + PROPVARIANT& operator*() noexcept { return mProp; } + const PROPVARIANT& operator*() const noexcept { return mProp; } + + PROPVARIANT* operator->() noexcept { return &mProp; } + const PROPVARIANT* operator->() const noexcept { return &mProp; } +}; + +struct DevMap { + std::string name; + std::string endpoint_guid; // obtained from PKEY_AudioEndpoint_GUID , set to "Unknown device GUID" if absent. + std::wstring devid; + + template + DevMap(T0&& name_, T1&& guid_, T2&& devid_) + : name{std::forward(name_)} + , endpoint_guid{std::forward(guid_)} + , devid{std::forward(devid_)} + { } +}; + +bool checkName(const al::vector &list, const std::string &name) +{ + return std::find_if(list.cbegin(), list.cend(), + [&name](const DevMap &entry) -> bool + { return entry.name == name; } + ) != list.cend(); +} + +al::vector PlaybackDevices; +al::vector CaptureDevices; + + +using NameGUIDPair = std::pair; +NameGUIDPair get_device_name_and_guid(IMMDevice *device) +{ + std::string name{DEVNAME_HEAD}; + std::string guid; + + IPropertyStore *ps; + HRESULT hr = device->OpenPropertyStore(STGM_READ, &ps); + if(FAILED(hr)) + { + WARN("OpenPropertyStore failed: 0x%08lx\n", hr); + return { name+"Unknown Device Name", "Unknown Device GUID" }; + } + + PropVariant pvprop; + hr = ps->GetValue(reinterpret_cast(DEVPKEY_Device_FriendlyName), pvprop.get()); + if(FAILED(hr)) + { + WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr); + name += "Unknown Device Name"; + } + else if(pvprop->vt == VT_LPWSTR) + name += wstr_to_utf8(pvprop->pwszVal); + else + { + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvprop->vt); + name += "Unknown Device Name"; + } + + pvprop.clear(); + hr = ps->GetValue(reinterpret_cast(PKEY_AudioEndpoint_GUID), pvprop.get()); + if(FAILED(hr)) + { + WARN("GetValue AudioEndpoint_GUID failed: 0x%08lx\n", hr); + guid = "Unknown Device GUID"; + } + else if(pvprop->vt == VT_LPWSTR) + guid = wstr_to_utf8(pvprop->pwszVal); + else + { + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvprop->vt); + guid = "Unknown Device GUID"; + } + + ps->Release(); + + return {name, guid}; +} + +void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfactor) +{ + IPropertyStore *ps; + HRESULT hr = device->OpenPropertyStore(STGM_READ, &ps); + if(FAILED(hr)) + { + WARN("OpenPropertyStore failed: 0x%08lx\n", hr); + return; + } + + PropVariant pvform; + hr = ps->GetValue(reinterpret_cast(PKEY_AudioEndpoint_FormFactor), pvform.get()); + if(FAILED(hr)) + WARN("GetValue AudioEndpoint_FormFactor failed: 0x%08lx\n", hr); + else if(pvform->vt == VT_UI4) + *formfactor = static_cast(pvform->ulVal); + else if(pvform->vt == VT_EMPTY) + *formfactor = UnknownFormFactor; + else + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvform->vt); + + ps->Release(); +} + + +void add_device(IMMDevice *device, const WCHAR *devid, al::vector &list) +{ + std::string basename, guidstr; + std::tie(basename, guidstr) = get_device_name_and_guid(device); + + int count{1}; + std::string newname{basename}; + while(checkName(list, newname)) + { + newname = basename; + newname += " #"; + newname += std::to_string(++count); + } + list.emplace_back(std::move(newname), std::move(guidstr), devid); + const DevMap &newentry = list.back(); + + TRACE("Got device \"%s\", \"%s\", \"%ls\"\n", newentry.name.c_str(), + newentry.endpoint_guid.c_str(), newentry.devid.c_str()); +} + +WCHAR *get_device_id(IMMDevice *device) +{ + WCHAR *devid; + + HRESULT hr = device->GetId(&devid); + if(FAILED(hr)) + { + ERR("Failed to get device id: %lx\n", hr); + return nullptr; + } + + return devid; +} + +HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, al::vector &list) +{ + IMMDeviceCollection *coll; + HRESULT hr{devenum->EnumAudioEndpoints(flowdir, DEVICE_STATE_ACTIVE, &coll)}; + if(FAILED(hr)) + { + ERR("Failed to enumerate audio endpoints: 0x%08lx\n", hr); + return hr; + } + + IMMDevice *defdev{nullptr}; + WCHAR *defdevid{nullptr}; + UINT count{0}; + hr = coll->GetCount(&count); + if(SUCCEEDED(hr) && count > 0) + { + list.clear(); + list.reserve(count); + + hr = devenum->GetDefaultAudioEndpoint(flowdir, eMultimedia, &defdev); + } + if(SUCCEEDED(hr) && defdev != nullptr) + { + defdevid = get_device_id(defdev); + if(defdevid) + add_device(defdev, defdevid, list); + } + + for(UINT i{0};i < count;++i) + { + IMMDevice *device; + hr = coll->Item(i, &device); + if(FAILED(hr)) continue; + + WCHAR *devid{get_device_id(device)}; + if(devid) + { + if(!defdevid || wcscmp(devid, defdevid) != 0) + add_device(device, devid, list); + CoTaskMemFree(devid); + } + device->Release(); + } + + if(defdev) defdev->Release(); + if(defdevid) CoTaskMemFree(defdevid); + coll->Release(); + + return S_OK; +} + + +bool MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) +{ + *out = WAVEFORMATEXTENSIBLE{}; + if(in->wFormatTag == WAVE_FORMAT_EXTENSIBLE) + { + *out = *CONTAINING_RECORD(in, const WAVEFORMATEXTENSIBLE, Format); + out->Format.cbSize = sizeof(*out) - sizeof(out->Format); + } + else if(in->wFormatTag == WAVE_FORMAT_PCM) + { + out->Format = *in; + out->Format.cbSize = 0; + out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample; + if(out->Format.nChannels == 1) + out->dwChannelMask = MONO; + else if(out->Format.nChannels == 2) + out->dwChannelMask = STEREO; + else + ERR("Unhandled PCM channel count: %d\n", out->Format.nChannels); + out->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + } + else if(in->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) + { + out->Format = *in; + out->Format.cbSize = 0; + out->Samples.wValidBitsPerSample = out->Format.wBitsPerSample; + if(out->Format.nChannels == 1) + out->dwChannelMask = MONO; + else if(out->Format.nChannels == 2) + out->dwChannelMask = STEREO; + else + ERR("Unhandled IEEE float channel count: %d\n", out->Format.nChannels); + out->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + } + else + { + ERR("Unhandled format tag: 0x%04x\n", in->wFormatTag); + return false; + } + return true; +} + +void TraceFormat(const char *msg, const WAVEFORMATEX *format) +{ + constexpr size_t fmtex_extra_size{sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX)}; + if(format->wFormatTag == WAVE_FORMAT_EXTENSIBLE && format->cbSize >= fmtex_extra_size) + { + class GuidPrinter { + char mMsg[64]; + + public: + GuidPrinter(const GUID &guid) + { + std::snprintf(mMsg, al::size(mMsg), + "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + DWORD{guid.Data1}, guid.Data2, guid.Data3, + guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], + guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); + } + const char *c_str() const { return mMsg; } + }; + + const WAVEFORMATEXTENSIBLE *fmtex{ + CONTAINING_RECORD(format, const WAVEFORMATEXTENSIBLE, Format)}; + TRACE("%s:\n" + " FormatTag = 0x%04x\n" + " Channels = %d\n" + " SamplesPerSec = %lu\n" + " AvgBytesPerSec = %lu\n" + " BlockAlign = %d\n" + " BitsPerSample = %d\n" + " Size = %d\n" + " Samples = %d\n" + " ChannelMask = 0x%lx\n" + " SubFormat = %s\n", + msg, fmtex->Format.wFormatTag, fmtex->Format.nChannels, fmtex->Format.nSamplesPerSec, + fmtex->Format.nAvgBytesPerSec, fmtex->Format.nBlockAlign, fmtex->Format.wBitsPerSample, + fmtex->Format.cbSize, fmtex->Samples.wReserved, fmtex->dwChannelMask, + GuidPrinter{fmtex->SubFormat}.c_str()); + } + else + TRACE("%s:\n" + " FormatTag = 0x%04x\n" + " Channels = %d\n" + " SamplesPerSec = %lu\n" + " AvgBytesPerSec = %lu\n" + " BlockAlign = %d\n" + " BitsPerSample = %d\n" + " Size = %d\n", + msg, format->wFormatTag, format->nChannels, format->nSamplesPerSec, + format->nAvgBytesPerSec, format->nBlockAlign, format->wBitsPerSample, format->cbSize); +} + + +enum class MsgType : unsigned int { + OpenDevice, + ResetDevice, + StartDevice, + StopDevice, + CloseDevice, + EnumeratePlayback, + EnumerateCapture, + QuitThread, + + Count +}; + +constexpr char MessageStr[static_cast(MsgType::Count)][20]{ + "Open Device", + "Reset Device", + "Start Device", + "Stop Device", + "Close Device", + "Enumerate Playback", + "Enumerate Capture", + "Quit" +}; + + +/* Proxy interface used by the message handler. */ +struct WasapiProxy { + virtual HRESULT openProxy() = 0; + virtual void closeProxy() = 0; + + virtual HRESULT resetProxy() = 0; + virtual HRESULT startProxy() = 0; + virtual void stopProxy() = 0; + + struct Msg { + MsgType mType; + WasapiProxy *mProxy; + std::promise mPromise; + }; + static std::deque mMsgQueue; + static std::mutex mMsgQueueLock; + static std::condition_variable mMsgQueueCond; + + std::future pushMessage(MsgType type) + { + std::promise promise; + std::future future{promise.get_future()}; + { std::lock_guard _{mMsgQueueLock}; + mMsgQueue.emplace_back(Msg{type, this, std::move(promise)}); + } + mMsgQueueCond.notify_one(); + return future; + } + + static std::future pushMessageStatic(MsgType type) + { + std::promise promise; + std::future future{promise.get_future()}; + { std::lock_guard _{mMsgQueueLock}; + mMsgQueue.emplace_back(Msg{type, nullptr, std::move(promise)}); + } + mMsgQueueCond.notify_one(); + return future; + } + + static bool popMessage(Msg &msg) + { + std::unique_lock lock{mMsgQueueLock}; + while(mMsgQueue.empty()) + mMsgQueueCond.wait(lock); + msg = std::move(mMsgQueue.front()); + mMsgQueue.pop_front(); + return msg.mType != MsgType::QuitThread; + } + + static int messageHandler(std::promise *promise); +}; +std::deque WasapiProxy::mMsgQueue; +std::mutex WasapiProxy::mMsgQueueLock; +std::condition_variable WasapiProxy::mMsgQueueCond; + +int WasapiProxy::messageHandler(std::promise *promise) +{ + TRACE("Starting message thread\n"); + + HRESULT cohr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + if(FAILED(cohr)) + { + WARN("Failed to initialize COM: 0x%08lx\n", cohr); + promise->set_value(cohr); + return 0; + } + + void *ptr{}; + HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, + IID_IMMDeviceEnumerator, &ptr)}; + if(FAILED(hr)) + { + WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr); + promise->set_value(hr); + CoUninitialize(); + return 0; + } + auto Enumerator = static_cast(ptr); + Enumerator->Release(); + Enumerator = nullptr; + CoUninitialize(); + + TRACE("Message thread initialization complete\n"); + promise->set_value(S_OK); + promise = nullptr; + + TRACE("Starting message loop\n"); + ALuint deviceCount{0}; + Msg msg; + while(popMessage(msg)) + { + TRACE("Got message \"%s\" (0x%04x, this=%p)\n", + MessageStr[static_cast(msg.mType)], static_cast(msg.mType), + msg.mProxy); + + switch(msg.mType) + { + case MsgType::OpenDevice: + hr = cohr = S_OK; + if(++deviceCount == 1) + hr = cohr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + if(SUCCEEDED(hr)) + hr = msg.mProxy->openProxy(); + msg.mPromise.set_value(hr); + + if(FAILED(hr)) + { + if(--deviceCount == 0 && SUCCEEDED(cohr)) + CoUninitialize(); + } + continue; + + case MsgType::ResetDevice: + hr = msg.mProxy->resetProxy(); + msg.mPromise.set_value(hr); + continue; + + case MsgType::StartDevice: + hr = msg.mProxy->startProxy(); + msg.mPromise.set_value(hr); + continue; + + case MsgType::StopDevice: + msg.mProxy->stopProxy(); + msg.mPromise.set_value(S_OK); + continue; + + case MsgType::CloseDevice: + msg.mProxy->closeProxy(); + msg.mPromise.set_value(S_OK); + + if(--deviceCount == 0) + CoUninitialize(); + continue; + + case MsgType::EnumeratePlayback: + case MsgType::EnumerateCapture: + hr = cohr = S_OK; + if(++deviceCount == 1) + hr = cohr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + if(SUCCEEDED(hr)) + hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, &ptr); + if(FAILED(hr)) + msg.mPromise.set_value(hr); + else + { + Enumerator = static_cast(ptr); + + if(msg.mType == MsgType::EnumeratePlayback) + hr = probe_devices(Enumerator, eRender, PlaybackDevices); + else if(msg.mType == MsgType::EnumerateCapture) + hr = probe_devices(Enumerator, eCapture, CaptureDevices); + msg.mPromise.set_value(hr); + + Enumerator->Release(); + Enumerator = nullptr; + } + + if(--deviceCount == 0 && SUCCEEDED(cohr)) + CoUninitialize(); + continue; + + default: + ERR("Unexpected message: %u\n", static_cast(msg.mType)); + msg.mPromise.set_value(E_FAIL); + continue; + } + } + TRACE("Message loop finished\n"); + + return 0; +} + + +struct WasapiPlayback final : public BackendBase, WasapiProxy { + WasapiPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~WasapiPlayback() override; + + int mixerProc(); + + ALCenum open(const ALCchar *name) override; + HRESULT openProxy() override; + void closeProxy() override; + + ALCboolean reset() override; + HRESULT resetProxy() override; + ALCboolean start() override; + HRESULT startProxy() override; + void stop() override; + void stopProxy() override; + + ClockLatency getClockLatency() override; + + std::wstring mDevId; + + IMMDevice *mMMDev{nullptr}; + IAudioClient *mClient{nullptr}; + IAudioRenderClient *mRender{nullptr}; + HANDLE mNotifyEvent{nullptr}; + + std::atomic mPadding{0u}; + + std::atomic mKillNow{true}; + std::thread mThread; + + DEF_NEWDEL(WasapiPlayback) +}; + +WasapiPlayback::~WasapiPlayback() +{ + pushMessage(MsgType::CloseDevice).wait(); + + if(mNotifyEvent != nullptr) + CloseHandle(mNotifyEvent); + mNotifyEvent = nullptr; +} + + +FORCE_ALIGN int WasapiPlayback::mixerProc() +{ + HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + if(FAILED(hr)) + { + ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); + aluHandleDisconnect(mDevice, "COM init failed: 0x%08lx", hr); + return 1; + } + + SetRTPriority(); + althrd_setname(MIXER_THREAD_NAME); + + const ALuint update_size{mDevice->UpdateSize}; + const UINT32 buffer_len{mDevice->BufferSize}; + while(!mKillNow.load(std::memory_order_relaxed)) + { + UINT32 written; + hr = mClient->GetCurrentPadding(&written); + if(FAILED(hr)) + { + ERR("Failed to get padding: 0x%08lx\n", hr); + aluHandleDisconnect(mDevice, "Failed to retrieve buffer padding: 0x%08lx", hr); + break; + } + mPadding.store(written, std::memory_order_relaxed); + + ALuint len{buffer_len - written}; + if(len < update_size) + { + DWORD res{WaitForSingleObjectEx(mNotifyEvent, 2000, FALSE)}; + if(res != WAIT_OBJECT_0) + ERR("WaitForSingleObjectEx error: 0x%lx\n", res); + continue; + } + + BYTE *buffer; + hr = mRender->GetBuffer(len, &buffer); + if(SUCCEEDED(hr)) + { + lock(); + aluMixData(mDevice, buffer, len); + mPadding.store(written + len, std::memory_order_relaxed); + unlock(); + hr = mRender->ReleaseBuffer(len, 0); + } + if(FAILED(hr)) + { + ERR("Failed to buffer data: 0x%08lx\n", hr); + aluHandleDisconnect(mDevice, "Failed to send playback samples: 0x%08lx", hr); + break; + } + } + mPadding.store(0u, std::memory_order_release); + + CoUninitialize(); + return 0; +} + + +ALCenum WasapiPlayback::open(const ALCchar *name) +{ + HRESULT hr{S_OK}; + + mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + if(mNotifyEvent == nullptr) + { + ERR("Failed to create notify events: %lu\n", GetLastError()); + hr = E_FAIL; + } + + if(SUCCEEDED(hr)) + { + if(name) + { + if(PlaybackDevices.empty()) + pushMessage(MsgType::EnumeratePlayback).wait(); + + hr = E_FAIL; + auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + [name](const DevMap &entry) -> bool + { return entry.name == name || entry.endpoint_guid == name; } + ); + if(iter == PlaybackDevices.cend()) + { + std::wstring wname{utf8_to_wstr(name)}; + iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), + [&wname](const DevMap &entry) -> bool + { return entry.devid == wname; } + ); + } + if(iter == PlaybackDevices.cend()) + WARN("Failed to find device name matching \"%s\"\n", name); + else + { + mDevId = iter->devid; + mDevice->DeviceName = iter->name; + hr = S_OK; + } + } + } + + if(SUCCEEDED(hr)) + hr = pushMessage(MsgType::OpenDevice).get(); + + if(FAILED(hr)) + { + if(mNotifyEvent != nullptr) + CloseHandle(mNotifyEvent); + mNotifyEvent = nullptr; + + mDevId.clear(); + + ERR("Device init failed: 0x%08lx\n", hr); + return ALC_INVALID_VALUE; + } + + return ALC_NO_ERROR; +} + +HRESULT WasapiPlayback::openProxy() +{ + void *ptr; + HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, &ptr)}; + if(SUCCEEDED(hr)) + { + auto Enumerator = static_cast(ptr); + if(mDevId.empty()) + hr = Enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &mMMDev); + else + hr = Enumerator->GetDevice(mDevId.c_str(), &mMMDev); + Enumerator->Release(); + } + if(SUCCEEDED(hr)) + hr = mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); + if(SUCCEEDED(hr)) + { + mClient = static_cast(ptr); + if(mDevice->DeviceName.empty()) + mDevice->DeviceName = get_device_name_and_guid(mMMDev).first; + } + + if(FAILED(hr)) + { + if(mMMDev) + mMMDev->Release(); + mMMDev = nullptr; + } + + return hr; +} + +void WasapiPlayback::closeProxy() +{ + if(mClient) + mClient->Release(); + mClient = nullptr; + + if(mMMDev) + mMMDev->Release(); + mMMDev = nullptr; +} + + +ALCboolean WasapiPlayback::reset() +{ + HRESULT hr{pushMessage(MsgType::ResetDevice).get()}; + return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; +} + +HRESULT WasapiPlayback::resetProxy() +{ + if(mClient) + mClient->Release(); + mClient = nullptr; + + void *ptr; + HRESULT hr = mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); + if(FAILED(hr)) + { + ERR("Failed to reactivate audio client: 0x%08lx\n", hr); + return hr; + } + mClient = static_cast(ptr); + + WAVEFORMATEX *wfx; + hr = mClient->GetMixFormat(&wfx); + if(FAILED(hr)) + { + ERR("Failed to get mix format: 0x%08lx\n", hr); + return hr; + } + + WAVEFORMATEXTENSIBLE OutputType; + if(!MakeExtensible(&OutputType, wfx)) + { + CoTaskMemFree(wfx); + return E_FAIL; + } + CoTaskMemFree(wfx); + wfx = nullptr; + + const REFERENCE_TIME per_time{mDevice->UpdateSize * REFTIME_PER_SEC / mDevice->Frequency}; + const REFERENCE_TIME buf_time{mDevice->BufferSize * REFTIME_PER_SEC / mDevice->Frequency}; + + if(!mDevice->Flags.get()) + mDevice->Frequency = OutputType.Format.nSamplesPerSec; + if(!mDevice->Flags.get()) + { + if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) + mDevice->FmtChans = DevFmtMono; + else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO) + mDevice->FmtChans = DevFmtStereo; + else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD) + mDevice->FmtChans = DevFmtQuad; + else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1) + mDevice->FmtChans = DevFmtX51; + else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR) + mDevice->FmtChans = DevFmtX51Rear; + else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1) + mDevice->FmtChans = DevFmtX61; + else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE)) + mDevice->FmtChans = DevFmtX71; + else + ERR("Unhandled channel config: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask); + } + + OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + switch(mDevice->FmtChans) + { + case DevFmtMono: + OutputType.Format.nChannels = 1; + OutputType.dwChannelMask = MONO; + break; + case DevFmtAmbi3D: + mDevice->FmtChans = DevFmtStereo; + /*fall-through*/ + case DevFmtStereo: + OutputType.Format.nChannels = 2; + OutputType.dwChannelMask = STEREO; + break; + case DevFmtQuad: + OutputType.Format.nChannels = 4; + OutputType.dwChannelMask = QUAD; + break; + case DevFmtX51: + OutputType.Format.nChannels = 6; + OutputType.dwChannelMask = X5DOT1; + break; + case DevFmtX51Rear: + OutputType.Format.nChannels = 6; + OutputType.dwChannelMask = X5DOT1REAR; + break; + case DevFmtX61: + OutputType.Format.nChannels = 7; + OutputType.dwChannelMask = X6DOT1; + break; + case DevFmtX71: + OutputType.Format.nChannels = 8; + OutputType.dwChannelMask = X7DOT1; + break; + } + switch(mDevice->FmtType) + { + case DevFmtByte: + mDevice->FmtType = DevFmtUByte; + /* fall-through */ + case DevFmtUByte: + OutputType.Format.wBitsPerSample = 8; + OutputType.Samples.wValidBitsPerSample = 8; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtUShort: + mDevice->FmtType = DevFmtShort; + /* fall-through */ + case DevFmtShort: + OutputType.Format.wBitsPerSample = 16; + OutputType.Samples.wValidBitsPerSample = 16; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtUInt: + mDevice->FmtType = DevFmtInt; + /* fall-through */ + case DevFmtInt: + OutputType.Format.wBitsPerSample = 32; + OutputType.Samples.wValidBitsPerSample = 32; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtFloat: + OutputType.Format.wBitsPerSample = 32; + OutputType.Samples.wValidBitsPerSample = 32; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + break; + } + OutputType.Format.nSamplesPerSec = mDevice->Frequency; + + OutputType.Format.nBlockAlign = OutputType.Format.nChannels * + OutputType.Format.wBitsPerSample / 8; + OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * + OutputType.Format.nBlockAlign; + + TraceFormat("Requesting playback format", &OutputType.Format); + hr = mClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); + if(FAILED(hr)) + { + ERR("Failed to check format support: 0x%08lx\n", hr); + hr = mClient->GetMixFormat(&wfx); + } + if(FAILED(hr)) + { + ERR("Failed to find a supported format: 0x%08lx\n", hr); + return hr; + } + + if(wfx != nullptr) + { + TraceFormat("Got playback format", wfx); + if(!MakeExtensible(&OutputType, wfx)) + { + CoTaskMemFree(wfx); + return E_FAIL; + } + CoTaskMemFree(wfx); + wfx = nullptr; + + mDevice->Frequency = OutputType.Format.nSamplesPerSec; + if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) + mDevice->FmtChans = DevFmtMono; + else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO) + mDevice->FmtChans = DevFmtStereo; + else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD) + mDevice->FmtChans = DevFmtQuad; + else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1) + mDevice->FmtChans = DevFmtX51; + else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR) + mDevice->FmtChans = DevFmtX51Rear; + else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1) + mDevice->FmtChans = DevFmtX61; + else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE)) + mDevice->FmtChans = DevFmtX71; + else + { + ERR("Unhandled extensible channels: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask); + mDevice->FmtChans = DevFmtStereo; + OutputType.Format.nChannels = 2; + OutputType.dwChannelMask = STEREO; + } + + if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_PCM)) + { + if(OutputType.Format.wBitsPerSample == 8) + mDevice->FmtType = DevFmtUByte; + else if(OutputType.Format.wBitsPerSample == 16) + mDevice->FmtType = DevFmtShort; + else if(OutputType.Format.wBitsPerSample == 32) + mDevice->FmtType = DevFmtInt; + else + { + mDevice->FmtType = DevFmtShort; + OutputType.Format.wBitsPerSample = 16; + } + } + else if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) + { + mDevice->FmtType = DevFmtFloat; + OutputType.Format.wBitsPerSample = 32; + } + else + { + ERR("Unhandled format sub-type\n"); + mDevice->FmtType = DevFmtShort; + if(OutputType.Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE) + OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; + OutputType.Format.wBitsPerSample = 16; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + } + OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; + } + + EndpointFormFactor formfactor = UnknownFormFactor; + get_device_formfactor(mMMDev, &formfactor); + mDevice->IsHeadphones = (mDevice->FmtChans == DevFmtStereo && + (formfactor == Headphones || formfactor == Headset)); + + SetDefaultWFXChannelOrder(mDevice); + + hr = mClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, buf_time, + 0, &OutputType.Format, nullptr); + if(FAILED(hr)) + { + ERR("Failed to initialize audio client: 0x%08lx\n", hr); + return hr; + } + + UINT32 buffer_len, min_len; + REFERENCE_TIME min_per; + hr = mClient->GetDevicePeriod(&min_per, nullptr); + if(SUCCEEDED(hr)) + hr = mClient->GetBufferSize(&buffer_len); + if(FAILED(hr)) + { + ERR("Failed to get audio buffer info: 0x%08lx\n", hr); + return hr; + } + + /* Find the nearest multiple of the period size to the update size */ + if(min_per < per_time) + min_per *= maxi64((per_time + min_per/2) / min_per, 1); + min_len = (UINT32)ScaleCeil(min_per, mDevice->Frequency, REFTIME_PER_SEC); + min_len = minu(min_len, buffer_len/2); + + mDevice->UpdateSize = min_len; + mDevice->BufferSize = buffer_len; + + hr = mClient->SetEventHandle(mNotifyEvent); + if(FAILED(hr)) + { + ERR("Failed to set event handle: 0x%08lx\n", hr); + return hr; + } + + return hr; +} + + +ALCboolean WasapiPlayback::start() +{ + HRESULT hr{pushMessage(MsgType::StartDevice).get()}; + return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; +} + +HRESULT WasapiPlayback::startProxy() +{ + ResetEvent(mNotifyEvent); + + HRESULT hr = mClient->Start(); + if(FAILED(hr)) + { + ERR("Failed to start audio client: 0x%08lx\n", hr); + return hr; + } + + void *ptr; + hr = mClient->GetService(IID_IAudioRenderClient, &ptr); + if(SUCCEEDED(hr)) + { + mRender = static_cast(ptr); + try { + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&WasapiPlayback::mixerProc), this}; + } + catch(...) { + mRender->Release(); + mRender = nullptr; + ERR("Failed to start thread\n"); + hr = E_FAIL; + } + } + + if(FAILED(hr)) + mClient->Stop(); + + return hr; +} + + +void WasapiPlayback::stop() +{ pushMessage(MsgType::StopDevice).wait(); } + +void WasapiPlayback::stopProxy() +{ + if(!mRender || !mThread.joinable()) + return; + + mKillNow.store(true, std::memory_order_release); + mThread.join(); + + mRender->Release(); + mRender = nullptr; + mClient->Stop(); +} + + +ClockLatency WasapiPlayback::getClockLatency() +{ + ClockLatency ret; + + lock(); + ret.ClockTime = GetDeviceClockTime(mDevice); + ret.Latency = std::chrono::seconds{mPadding.load(std::memory_order_relaxed)}; + ret.Latency /= mDevice->Frequency; + unlock(); + + return ret; +} + + +struct WasapiCapture final : public BackendBase, WasapiProxy { + WasapiCapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~WasapiCapture() override; + + int recordProc(); + + ALCenum open(const ALCchar *name) override; + HRESULT openProxy() override; + void closeProxy() override; + + HRESULT resetProxy() override; + ALCboolean start() override; + HRESULT startProxy() override; + void stop() override; + void stopProxy() override; + + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + + std::wstring mDevId; + + IMMDevice *mMMDev{nullptr}; + IAudioClient *mClient{nullptr}; + IAudioCaptureClient *mCapture{nullptr}; + HANDLE mNotifyEvent{nullptr}; + + ChannelConverterPtr mChannelConv; + SampleConverterPtr mSampleConv; + RingBufferPtr mRing; + + std::atomic mKillNow{true}; + std::thread mThread; + + DEF_NEWDEL(WasapiCapture) +}; + +WasapiCapture::~WasapiCapture() +{ + pushMessage(MsgType::CloseDevice).wait(); + + if(mNotifyEvent != nullptr) + CloseHandle(mNotifyEvent); + mNotifyEvent = nullptr; +} + + +FORCE_ALIGN int WasapiCapture::recordProc() +{ + HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + if(FAILED(hr)) + { + ERR("CoInitializeEx(nullptr, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); + aluHandleDisconnect(mDevice, "COM init failed: 0x%08lx", hr); + return 1; + } + + althrd_setname(RECORD_THREAD_NAME); + + al::vector samples; + while(!mKillNow.load(std::memory_order_relaxed)) + { + UINT32 avail; + hr = mCapture->GetNextPacketSize(&avail); + if(FAILED(hr)) + ERR("Failed to get next packet size: 0x%08lx\n", hr); + else if(avail > 0) + { + UINT32 numsamples; + DWORD flags; + BYTE *rdata; + + hr = mCapture->GetBuffer(&rdata, &numsamples, &flags, nullptr, nullptr); + if(FAILED(hr)) + ERR("Failed to get capture buffer: 0x%08lx\n", hr); + else + { + if(mChannelConv) + { + samples.resize(numsamples*2); + mChannelConv->convert(rdata, samples.data(), numsamples); + rdata = reinterpret_cast(samples.data()); + } + + auto data = mRing->getWriteVector(); + + size_t dstframes; + if(mSampleConv) + { + const ALvoid *srcdata{rdata}; + auto srcframes = static_cast(numsamples); + + dstframes = mSampleConv->convert(&srcdata, &srcframes, data.first.buf, + static_cast(minz(data.first.len, INT_MAX))); + if(srcframes > 0 && dstframes == data.first.len && data.second.len > 0) + { + /* If some source samples remain, all of the first dest + * block was filled, and there's space in the second + * dest block, do another run for the second block. + */ + dstframes += mSampleConv->convert(&srcdata, &srcframes, data.second.buf, + static_cast(minz(data.second.len, INT_MAX))); + } + } + else + { + const auto framesize = static_cast(mDevice->frameSizeFromFmt()); + size_t len1 = minz(data.first.len, numsamples); + size_t len2 = minz(data.second.len, numsamples-len1); + + memcpy(data.first.buf, rdata, len1*framesize); + if(len2 > 0) + memcpy(data.second.buf, rdata+len1*framesize, len2*framesize); + dstframes = len1 + len2; + } + + mRing->writeAdvance(dstframes); + + hr = mCapture->ReleaseBuffer(numsamples); + if(FAILED(hr)) ERR("Failed to release capture buffer: 0x%08lx\n", hr); + } + } + + if(FAILED(hr)) + { + aluHandleDisconnect(mDevice, "Failed to capture samples: 0x%08lx", hr); + break; + } + + DWORD res{WaitForSingleObjectEx(mNotifyEvent, 2000, FALSE)}; + if(res != WAIT_OBJECT_0) + ERR("WaitForSingleObjectEx error: 0x%lx\n", res); + } + + CoUninitialize(); + return 0; +} + + +ALCenum WasapiCapture::open(const ALCchar *name) +{ + HRESULT hr{S_OK}; + + mNotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + if(mNotifyEvent == nullptr) + { + ERR("Failed to create notify event: %lu\n", GetLastError()); + hr = E_FAIL; + } + + if(SUCCEEDED(hr)) + { + if(name) + { + if(CaptureDevices.empty()) + pushMessage(MsgType::EnumerateCapture).wait(); + + hr = E_FAIL; + auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), + [name](const DevMap &entry) -> bool + { return entry.name == name || entry.endpoint_guid == name; } + ); + if(iter == CaptureDevices.cend()) + { + std::wstring wname{utf8_to_wstr(name)}; + iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), + [&wname](const DevMap &entry) -> bool + { return entry.devid == wname; } + ); + } + if(iter == CaptureDevices.cend()) + WARN("Failed to find device name matching \"%s\"\n", name); + else + { + mDevId = iter->devid; + mDevice->DeviceName = iter->name; + hr = S_OK; + } + } + } + + if(SUCCEEDED(hr)) + hr = pushMessage(MsgType::OpenDevice).get(); + + if(FAILED(hr)) + { + if(mNotifyEvent != nullptr) + CloseHandle(mNotifyEvent); + mNotifyEvent = nullptr; + + mDevId.clear(); + + ERR("Device init failed: 0x%08lx\n", hr); + return ALC_INVALID_VALUE; + } + + hr = pushMessage(MsgType::ResetDevice).get(); + if(FAILED(hr)) + { + if(hr == E_OUTOFMEMORY) + return ALC_OUT_OF_MEMORY; + return ALC_INVALID_VALUE; + } + + return ALC_NO_ERROR; +} + +HRESULT WasapiCapture::openProxy() +{ + void *ptr; + HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, + IID_IMMDeviceEnumerator, &ptr)}; + if(SUCCEEDED(hr)) + { + auto Enumerator = static_cast(ptr); + if(mDevId.empty()) + hr = Enumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, &mMMDev); + else + hr = Enumerator->GetDevice(mDevId.c_str(), &mMMDev); + Enumerator->Release(); + } + if(SUCCEEDED(hr)) + hr = mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); + if(SUCCEEDED(hr)) + { + mClient = static_cast(ptr); + if(mDevice->DeviceName.empty()) + mDevice->DeviceName = get_device_name_and_guid(mMMDev).first; + } + + if(FAILED(hr)) + { + if(mMMDev) + mMMDev->Release(); + mMMDev = nullptr; + } + + return hr; +} + +void WasapiCapture::closeProxy() +{ + if(mClient) + mClient->Release(); + mClient = nullptr; + + if(mMMDev) + mMMDev->Release(); + mMMDev = nullptr; +} + +HRESULT WasapiCapture::resetProxy() +{ + if(mClient) + mClient->Release(); + mClient = nullptr; + + void *ptr; + HRESULT hr{mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr)}; + if(FAILED(hr)) + { + ERR("Failed to reactivate audio client: 0x%08lx\n", hr); + return hr; + } + mClient = static_cast(ptr); + + // Make sure buffer is at least 100ms in size + REFERENCE_TIME buf_time{mDevice->BufferSize * REFTIME_PER_SEC / mDevice->Frequency}; + buf_time = maxu64(buf_time, REFTIME_PER_SEC/10); + + WAVEFORMATEXTENSIBLE OutputType; + OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + switch(mDevice->FmtChans) + { + case DevFmtMono: + OutputType.Format.nChannels = 1; + OutputType.dwChannelMask = MONO; + break; + case DevFmtStereo: + OutputType.Format.nChannels = 2; + OutputType.dwChannelMask = STEREO; + break; + case DevFmtQuad: + OutputType.Format.nChannels = 4; + OutputType.dwChannelMask = QUAD; + break; + case DevFmtX51: + OutputType.Format.nChannels = 6; + OutputType.dwChannelMask = X5DOT1; + break; + case DevFmtX51Rear: + OutputType.Format.nChannels = 6; + OutputType.dwChannelMask = X5DOT1REAR; + break; + case DevFmtX61: + OutputType.Format.nChannels = 7; + OutputType.dwChannelMask = X6DOT1; + break; + case DevFmtX71: + OutputType.Format.nChannels = 8; + OutputType.dwChannelMask = X7DOT1; + break; + + case DevFmtAmbi3D: + return E_FAIL; + } + switch(mDevice->FmtType) + { + /* NOTE: Signedness doesn't matter, the converter will handle it. */ + case DevFmtByte: + case DevFmtUByte: + OutputType.Format.wBitsPerSample = 8; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtShort: + case DevFmtUShort: + OutputType.Format.wBitsPerSample = 16; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtInt: + case DevFmtUInt: + OutputType.Format.wBitsPerSample = 32; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtFloat: + OutputType.Format.wBitsPerSample = 32; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + break; + } + OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; + OutputType.Format.nSamplesPerSec = mDevice->Frequency; + + OutputType.Format.nBlockAlign = OutputType.Format.nChannels * + OutputType.Format.wBitsPerSample / 8; + OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * + OutputType.Format.nBlockAlign; + OutputType.Format.cbSize = sizeof(OutputType) - sizeof(OutputType.Format); + + TraceFormat("Requesting capture format", &OutputType.Format); + WAVEFORMATEX *wfx; + hr = mClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); + if(FAILED(hr)) + { + ERR("Failed to check format support: 0x%08lx\n", hr); + return hr; + } + + mSampleConv = nullptr; + mChannelConv = nullptr; + + if(wfx != nullptr) + { + TraceFormat("Got capture format", wfx); + if(!(wfx->nChannels == OutputType.Format.nChannels || + (wfx->nChannels == 1 && OutputType.Format.nChannels == 2) || + (wfx->nChannels == 2 && OutputType.Format.nChannels == 1))) + { + ERR("Failed to get matching format, wanted: %s %s %uhz, got: %d channel%s %d-bit %luhz\n", + DevFmtChannelsString(mDevice->FmtChans), DevFmtTypeString(mDevice->FmtType), + mDevice->Frequency, wfx->nChannels, (wfx->nChannels==1)?"":"s", wfx->wBitsPerSample, + wfx->nSamplesPerSec); + CoTaskMemFree(wfx); + return E_FAIL; + } + + if(!MakeExtensible(&OutputType, wfx)) + { + CoTaskMemFree(wfx); + return E_FAIL; + } + CoTaskMemFree(wfx); + wfx = nullptr; + } + + DevFmtType srcType; + if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_PCM)) + { + if(OutputType.Format.wBitsPerSample == 8) + srcType = DevFmtUByte; + else if(OutputType.Format.wBitsPerSample == 16) + srcType = DevFmtShort; + else if(OutputType.Format.wBitsPerSample == 32) + srcType = DevFmtInt; + else + { + ERR("Unhandled integer bit depth: %d\n", OutputType.Format.wBitsPerSample); + return E_FAIL; + } + } + else if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) + { + if(OutputType.Format.wBitsPerSample == 32) + srcType = DevFmtFloat; + else + { + ERR("Unhandled float bit depth: %d\n", OutputType.Format.wBitsPerSample); + return E_FAIL; + } + } + else + { + ERR("Unhandled format sub-type\n"); + return E_FAIL; + } + + if(mDevice->FmtChans == DevFmtMono && OutputType.Format.nChannels == 2) + { + mChannelConv = CreateChannelConverter(srcType, DevFmtStereo, mDevice->FmtChans); + if(!mChannelConv) + { + ERR("Failed to create %s stereo-to-mono converter\n", DevFmtTypeString(srcType)); + return E_FAIL; + } + TRACE("Created %s stereo-to-mono converter\n", DevFmtTypeString(srcType)); + /* The channel converter always outputs float, so change the input type + * for the resampler/type-converter. + */ + srcType = DevFmtFloat; + } + else if(mDevice->FmtChans == DevFmtStereo && OutputType.Format.nChannels == 1) + { + mChannelConv = CreateChannelConverter(srcType, DevFmtMono, mDevice->FmtChans); + if(!mChannelConv) + { + ERR("Failed to create %s mono-to-stereo converter\n", DevFmtTypeString(srcType)); + return E_FAIL; + } + TRACE("Created %s mono-to-stereo converter\n", DevFmtTypeString(srcType)); + srcType = DevFmtFloat; + } + + if(mDevice->Frequency != OutputType.Format.nSamplesPerSec || mDevice->FmtType != srcType) + { + mSampleConv = CreateSampleConverter(srcType, mDevice->FmtType, mDevice->channelsFromFmt(), + OutputType.Format.nSamplesPerSec, mDevice->Frequency, BSinc24Resampler); + if(!mSampleConv) + { + ERR("Failed to create converter for %s format, dst: %s %uhz, src: %s %luhz\n", + DevFmtChannelsString(mDevice->FmtChans), DevFmtTypeString(mDevice->FmtType), + mDevice->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec); + return E_FAIL; + } + TRACE("Created converter for %s format, dst: %s %uhz, src: %s %luhz\n", + DevFmtChannelsString(mDevice->FmtChans), DevFmtTypeString(mDevice->FmtType), + mDevice->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec); + } + + hr = mClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, buf_time, + 0, &OutputType.Format, nullptr); + if(FAILED(hr)) + { + ERR("Failed to initialize audio client: 0x%08lx\n", hr); + return hr; + } + + UINT32 buffer_len; + REFERENCE_TIME min_per; + hr = mClient->GetDevicePeriod(&min_per, nullptr); + if(SUCCEEDED(hr)) + hr = mClient->GetBufferSize(&buffer_len); + if(FAILED(hr)) + { + ERR("Failed to get buffer size: 0x%08lx\n", hr); + return hr; + } + mDevice->UpdateSize = static_cast(ScaleCeil(min_per, mDevice->Frequency, + REFTIME_PER_SEC)); + mDevice->BufferSize = buffer_len; + + buffer_len = maxu(mDevice->BufferSize, buffer_len); + mRing = CreateRingBuffer(buffer_len, mDevice->frameSizeFromFmt(), false); + if(!mRing) + { + ERR("Failed to allocate capture ring buffer\n"); + return E_OUTOFMEMORY; + } + + hr = mClient->SetEventHandle(mNotifyEvent); + if(FAILED(hr)) + { + ERR("Failed to set event handle: 0x%08lx\n", hr); + return hr; + } + + return hr; +} + + +ALCboolean WasapiCapture::start() +{ + HRESULT hr{pushMessage(MsgType::StartDevice).get()}; + return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; +} + +HRESULT WasapiCapture::startProxy() +{ + ResetEvent(mNotifyEvent); + + HRESULT hr{mClient->Start()}; + if(FAILED(hr)) + { + ERR("Failed to start audio client: 0x%08lx\n", hr); + return hr; + } + + void *ptr; + hr = mClient->GetService(IID_IAudioCaptureClient, &ptr); + if(SUCCEEDED(hr)) + { + mCapture = static_cast(ptr); + try { + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&WasapiCapture::recordProc), this}; + } + catch(...) { + mCapture->Release(); + mCapture = nullptr; + ERR("Failed to start thread\n"); + hr = E_FAIL; + } + } + + if(FAILED(hr)) + { + mClient->Stop(); + mClient->Reset(); + } + + return hr; +} + + +void WasapiCapture::stop() +{ pushMessage(MsgType::StopDevice).wait(); } + +void WasapiCapture::stopProxy() +{ + if(!mCapture || !mThread.joinable()) + return; + + mKillNow.store(true, std::memory_order_release); + mThread.join(); + + mCapture->Release(); + mCapture = nullptr; + mClient->Stop(); + mClient->Reset(); +} + + +ALCuint WasapiCapture::availableSamples() +{ return (ALCuint)mRing->readSpace(); } + +ALCenum WasapiCapture::captureSamples(void *buffer, ALCuint samples) +{ + mRing->read(buffer, samples); + return ALC_NO_ERROR; +} + +} // namespace + + +bool WasapiBackendFactory::init() +{ + static HRESULT InitResult{E_FAIL}; + + if(FAILED(InitResult)) try + { + std::promise promise; + auto future = promise.get_future(); + + std::thread{&WasapiProxy::messageHandler, &promise}.detach(); + InitResult = future.get(); + } + catch(...) { + } + + return SUCCEEDED(InitResult) ? ALC_TRUE : ALC_FALSE; +} + +bool WasapiBackendFactory::querySupport(BackendType type) +{ return type == BackendType::Playback || type == BackendType::Capture; } + +void WasapiBackendFactory::probe(DevProbe type, std::string *outnames) +{ + auto add_device = [outnames](const DevMap &entry) -> void + { + /* +1 to also append the null char (to ensure a null-separated list and + * double-null terminated list). + */ + outnames->append(entry.name.c_str(), entry.name.length()+1); + }; + HRESULT hr{}; + switch(type) + { + case DevProbe::Playback: + hr = WasapiProxy::pushMessageStatic(MsgType::EnumeratePlayback).get(); + if(SUCCEEDED(hr)) + std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); + break; + + case DevProbe::Capture: + hr = WasapiProxy::pushMessageStatic(MsgType::EnumerateCapture).get(); + if(SUCCEEDED(hr)) + std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); + break; + } +} + +BackendPtr WasapiBackendFactory::createBackend(ALCdevice *device, BackendType type) +{ + if(type == BackendType::Playback) + return BackendPtr{new WasapiPlayback{device}}; + if(type == BackendType::Capture) + return BackendPtr{new WasapiCapture{device}}; + return nullptr; +} + +BackendFactory &WasapiBackendFactory::getFactory() +{ + static WasapiBackendFactory factory{}; + return factory; +} diff --git a/alc/backends/wasapi.h b/alc/backends/wasapi.h new file mode 100644 index 00000000..067dd259 --- /dev/null +++ b/alc/backends/wasapi.h @@ -0,0 +1,19 @@ +#ifndef BACKENDS_WASAPI_H +#define BACKENDS_WASAPI_H + +#include "backends/base.h" + +struct WasapiBackendFactory final : public BackendFactory { +public: + bool init() override; + + bool querySupport(BackendType type) override; + + void probe(DevProbe type, std::string *outnames) override; + + BackendPtr createBackend(ALCdevice *device, BackendType type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_WASAPI_H */ diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp new file mode 100644 index 00000000..67ed7e79 --- /dev/null +++ b/alc/backends/wave.cpp @@ -0,0 +1,402 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "backends/wave.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" + +#include "alcmain.h" +#include "alconfig.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "alu.h" +#include "compat.h" +#include "logging.h" +#include "threads.h" +#include "vector.h" + + +namespace { + +using std::chrono::seconds; +using std::chrono::milliseconds; +using std::chrono::nanoseconds; + +constexpr ALCchar waveDevice[] = "Wave File Writer"; + +constexpr ALubyte SUBTYPE_PCM[]{ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, + 0x00, 0x38, 0x9b, 0x71 +}; +constexpr ALubyte SUBTYPE_FLOAT[]{ + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, + 0x00, 0x38, 0x9b, 0x71 +}; + +constexpr ALubyte SUBTYPE_BFORMAT_PCM[]{ + 0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1, + 0xca, 0x00, 0x00, 0x00 +}; + +constexpr ALubyte SUBTYPE_BFORMAT_FLOAT[]{ + 0x03, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1, + 0xca, 0x00, 0x00, 0x00 +}; + +void fwrite16le(ALushort val, FILE *f) +{ + ALubyte data[2]{ static_cast(val&0xff), static_cast((val>>8)&0xff) }; + fwrite(data, 1, 2, f); +} + +void fwrite32le(ALuint val, FILE *f) +{ + ALubyte data[4]{ static_cast(val&0xff), static_cast((val>>8)&0xff), + static_cast((val>>16)&0xff), static_cast((val>>24)&0xff) }; + fwrite(data, 1, 4, f); +} + + +struct WaveBackend final : public BackendBase { + WaveBackend(ALCdevice *device) noexcept : BackendBase{device} { } + ~WaveBackend() override; + + int mixerProc(); + + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + + FILE *mFile{nullptr}; + long mDataStart{-1}; + + al::vector mBuffer; + + std::atomic mKillNow{true}; + std::thread mThread; + + DEF_NEWDEL(WaveBackend) +}; + +WaveBackend::~WaveBackend() +{ + if(mFile) + fclose(mFile); + mFile = nullptr; +} + +int WaveBackend::mixerProc() +{ + const milliseconds restTime{mDevice->UpdateSize*1000/mDevice->Frequency / 2}; + + althrd_setname(MIXER_THREAD_NAME); + + const ALsizei frameSize{mDevice->frameSizeFromFmt()}; + + int64_t done{0}; + auto start = std::chrono::steady_clock::now(); + while(!mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) + { + auto now = std::chrono::steady_clock::now(); + + /* This converts from nanoseconds to nanosamples, then to samples. */ + int64_t avail{std::chrono::duration_cast((now-start) * + mDevice->Frequency).count()}; + if(avail-done < mDevice->UpdateSize) + { + std::this_thread::sleep_for(restTime); + continue; + } + while(avail-done >= mDevice->UpdateSize) + { + lock(); + aluMixData(mDevice, mBuffer.data(), mDevice->UpdateSize); + unlock(); + done += mDevice->UpdateSize; + + if(!IS_LITTLE_ENDIAN) + { + const ALsizei bytesize{mDevice->bytesFromFmt()}; + ALsizei i; + + if(bytesize == 2) + { + ALushort *samples = reinterpret_cast(mBuffer.data()); + const auto len = static_cast(mBuffer.size() / 2); + for(i = 0;i < len;i++) + { + ALushort samp = samples[i]; + samples[i] = (samp>>8) | (samp<<8); + } + } + else if(bytesize == 4) + { + ALuint *samples = reinterpret_cast(mBuffer.data()); + const auto len = static_cast(mBuffer.size() / 4); + for(i = 0;i < len;i++) + { + ALuint samp = samples[i]; + samples[i] = (samp>>24) | ((samp>>8)&0x0000ff00) | + ((samp<<8)&0x00ff0000) | (samp<<24); + } + } + } + + size_t fs{fwrite(mBuffer.data(), frameSize, mDevice->UpdateSize, mFile)}; + (void)fs; + if(ferror(mFile)) + { + ERR("Error writing to file\n"); + aluHandleDisconnect(mDevice, "Failed to write playback samples"); + break; + } + } + + /* For every completed second, increment the start time and reduce the + * samples done. This prevents the difference between the start time + * and current time from growing too large, while maintaining the + * correct number of samples to render. + */ + if(done >= mDevice->Frequency) + { + seconds s{done/mDevice->Frequency}; + start += s; + done -= mDevice->Frequency*s.count(); + } + } + + return 0; +} + +ALCenum WaveBackend::open(const ALCchar *name) +{ + const char *fname{GetConfigValue(nullptr, "wave", "file", "")}; + if(!fname[0]) return ALC_INVALID_VALUE; + + if(!name) + name = waveDevice; + else if(strcmp(name, waveDevice) != 0) + return ALC_INVALID_VALUE; + +#ifdef _WIN32 + { + std::wstring wname = utf8_to_wstr(fname); + mFile = _wfopen(wname.c_str(), L"wb"); + } +#else + mFile = fopen(fname, "wb"); +#endif + if(!mFile) + { + ERR("Could not open file '%s': %s\n", fname, strerror(errno)); + return ALC_INVALID_VALUE; + } + + mDevice->DeviceName = name; + + return ALC_NO_ERROR; +} + +ALCboolean WaveBackend::reset() +{ + ALuint channels=0, bytes=0, chanmask=0; + int isbformat = 0; + size_t val; + + fseek(mFile, 0, SEEK_SET); + clearerr(mFile); + + if(GetConfigValueBool(nullptr, "wave", "bformat", 0)) + { + mDevice->FmtChans = DevFmtAmbi3D; + mDevice->mAmbiOrder = 1; + } + + switch(mDevice->FmtType) + { + case DevFmtByte: + mDevice->FmtType = DevFmtUByte; + break; + case DevFmtUShort: + mDevice->FmtType = DevFmtShort; + break; + case DevFmtUInt: + mDevice->FmtType = DevFmtInt; + break; + case DevFmtUByte: + case DevFmtShort: + case DevFmtInt: + case DevFmtFloat: + break; + } + switch(mDevice->FmtChans) + { + case DevFmtMono: chanmask = 0x04; break; + case DevFmtStereo: chanmask = 0x01 | 0x02; break; + case DevFmtQuad: chanmask = 0x01 | 0x02 | 0x10 | 0x20; break; + case DevFmtX51: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x200 | 0x400; break; + case DevFmtX51Rear: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020; break; + case DevFmtX61: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400; break; + case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break; + case DevFmtAmbi3D: + /* .amb output requires FuMa */ + mDevice->mAmbiOrder = mini(mDevice->mAmbiOrder, 3); + mDevice->mAmbiLayout = AmbiLayout::FuMa; + mDevice->mAmbiScale = AmbiNorm::FuMa; + isbformat = 1; + chanmask = 0; + break; + } + bytes = mDevice->bytesFromFmt(); + channels = mDevice->channelsFromFmt(); + + rewind(mFile); + + fputs("RIFF", mFile); + fwrite32le(0xFFFFFFFF, mFile); // 'RIFF' header len; filled in at close + + fputs("WAVE", mFile); + + fputs("fmt ", mFile); + fwrite32le(40, mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE + + // 16-bit val, format type id (extensible: 0xFFFE) + fwrite16le(0xFFFE, mFile); + // 16-bit val, channel count + fwrite16le(channels, mFile); + // 32-bit val, frequency + fwrite32le(mDevice->Frequency, mFile); + // 32-bit val, bytes per second + fwrite32le(mDevice->Frequency * channels * bytes, mFile); + // 16-bit val, frame size + fwrite16le(channels * bytes, mFile); + // 16-bit val, bits per sample + fwrite16le(bytes * 8, mFile); + // 16-bit val, extra byte count + fwrite16le(22, mFile); + // 16-bit val, valid bits per sample + fwrite16le(bytes * 8, mFile); + // 32-bit val, channel mask + fwrite32le(chanmask, mFile); + // 16 byte GUID, sub-type format + val = fwrite((mDevice->FmtType == DevFmtFloat) ? + (isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) : + (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM), 1, 16, mFile); + (void)val; + + fputs("data", mFile); + fwrite32le(0xFFFFFFFF, mFile); // 'data' header len; filled in at close + + if(ferror(mFile)) + { + ERR("Error writing header: %s\n", strerror(errno)); + return ALC_FALSE; + } + mDataStart = ftell(mFile); + + SetDefaultWFXChannelOrder(mDevice); + + const ALuint bufsize{mDevice->frameSizeFromFmt() * mDevice->UpdateSize}; + mBuffer.resize(bufsize); + + return ALC_TRUE; +} + +ALCboolean WaveBackend::start() +{ + try { + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&WaveBackend::mixerProc), this}; + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Failed to start mixing thread: %s\n", e.what()); + } + catch(...) { + } + return ALC_FALSE; +} + +void WaveBackend::stop() +{ + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) + return; + mThread.join(); + + long size{ftell(mFile)}; + if(size > 0) + { + long dataLen{size - mDataStart}; + if(fseek(mFile, mDataStart-4, SEEK_SET) == 0) + fwrite32le(dataLen, mFile); // 'data' header len + if(fseek(mFile, 4, SEEK_SET) == 0) + fwrite32le(size-8, mFile); // 'WAVE' header len + } +} + +} // namespace + + +bool WaveBackendFactory::init() +{ return true; } + +bool WaveBackendFactory::querySupport(BackendType type) +{ return type == BackendType::Playback; } + +void WaveBackendFactory::probe(DevProbe type, std::string *outnames) +{ + switch(type) + { + case DevProbe::Playback: + /* Includes null char. */ + outnames->append(waveDevice, sizeof(waveDevice)); + break; + case DevProbe::Capture: + break; + } +} + +BackendPtr WaveBackendFactory::createBackend(ALCdevice *device, BackendType type) +{ + if(type == BackendType::Playback) + return BackendPtr{new WaveBackend{device}}; + return nullptr; +} + +BackendFactory &WaveBackendFactory::getFactory() +{ + static WaveBackendFactory factory{}; + return factory; +} diff --git a/alc/backends/wave.h b/alc/backends/wave.h new file mode 100644 index 00000000..b9b62d7f --- /dev/null +++ b/alc/backends/wave.h @@ -0,0 +1,19 @@ +#ifndef BACKENDS_WAVE_H +#define BACKENDS_WAVE_H + +#include "backends/base.h" + +struct WaveBackendFactory final : public BackendFactory { +public: + bool init() override; + + bool querySupport(BackendType type) override; + + void probe(DevProbe type, std::string *outnames) override; + + BackendPtr createBackend(ALCdevice *device, BackendType type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_WAVE_H */ diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp new file mode 100644 index 00000000..cd32e95b --- /dev/null +++ b/alc/backends/winmm.cpp @@ -0,0 +1,640 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "backends/winmm.h" + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "alcmain.h" +#include "alu.h" +#include "ringbuffer.h" +#include "threads.h" +#include "compat.h" + +#ifndef WAVE_FORMAT_IEEE_FLOAT +#define WAVE_FORMAT_IEEE_FLOAT 0x0003 +#endif + +namespace { + +#define DEVNAME_HEAD "OpenAL Soft on " + + +al::vector PlaybackDevices; +al::vector CaptureDevices; + +bool checkName(const al::vector &list, const std::string &name) +{ return std::find(list.cbegin(), list.cend(), name) != list.cend(); } + +void ProbePlaybackDevices(void) +{ + PlaybackDevices.clear(); + + ALuint numdevs{waveOutGetNumDevs()}; + PlaybackDevices.reserve(numdevs); + for(ALuint i{0};i < numdevs;i++) + { + std::string dname; + + WAVEOUTCAPSW WaveCaps{}; + if(waveOutGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR) + { + const std::string basename{DEVNAME_HEAD + wstr_to_utf8(WaveCaps.szPname)}; + + int count{1}; + std::string newname{basename}; + while(checkName(PlaybackDevices, newname)) + { + newname = basename; + newname += " #"; + newname += std::to_string(++count); + } + dname = std::move(newname); + + TRACE("Got device \"%s\", ID %u\n", dname.c_str(), i); + } + PlaybackDevices.emplace_back(std::move(dname)); + } +} + +void ProbeCaptureDevices(void) +{ + CaptureDevices.clear(); + + ALuint numdevs{waveInGetNumDevs()}; + CaptureDevices.reserve(numdevs); + for(ALuint i{0};i < numdevs;i++) + { + std::string dname; + + WAVEINCAPSW WaveCaps{}; + if(waveInGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR) + { + const std::string basename{DEVNAME_HEAD + wstr_to_utf8(WaveCaps.szPname)}; + + int count{1}; + std::string newname{basename}; + while(checkName(CaptureDevices, newname)) + { + newname = basename; + newname += " #"; + newname += std::to_string(++count); + } + dname = std::move(newname); + + TRACE("Got device \"%s\", ID %u\n", dname.c_str(), i); + } + CaptureDevices.emplace_back(std::move(dname)); + } +} + + +struct WinMMPlayback final : public BackendBase { + WinMMPlayback(ALCdevice *device) noexcept : BackendBase{device} { } + ~WinMMPlayback() override; + + static void CALLBACK waveOutProcC(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); + void CALLBACK waveOutProc(HWAVEOUT device, UINT msg, DWORD_PTR param1, DWORD_PTR param2); + + int mixerProc(); + + ALCenum open(const ALCchar *name) override; + ALCboolean reset() override; + ALCboolean start() override; + void stop() override; + + std::atomic mWritable{0u}; + al::semaphore mSem; + int mIdx{0}; + std::array mWaveBuffer{}; + + HWAVEOUT mOutHdl{nullptr}; + + WAVEFORMATEX mFormat{}; + + std::atomic mKillNow{true}; + std::thread mThread; + + DEF_NEWDEL(WinMMPlayback) +}; + +WinMMPlayback::~WinMMPlayback() +{ + if(mOutHdl) + waveOutClose(mOutHdl); + mOutHdl = nullptr; + + al_free(mWaveBuffer[0].lpData); + std::fill(mWaveBuffer.begin(), mWaveBuffer.end(), WAVEHDR{}); +} + + +void CALLBACK WinMMPlayback::waveOutProcC(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2) +{ reinterpret_cast(instance)->waveOutProc(device, msg, param1, param2); } + +/* WinMMPlayback::waveOutProc + * + * Posts a message to 'WinMMPlayback::mixerProc' everytime a WaveOut Buffer is + * completed and returns to the application (for more data) + */ +void CALLBACK WinMMPlayback::waveOutProc(HWAVEOUT, UINT msg, DWORD_PTR, DWORD_PTR) +{ + if(msg != WOM_DONE) return; + mWritable.fetch_add(1, std::memory_order_acq_rel); + mSem.post(); +} + +FORCE_ALIGN int WinMMPlayback::mixerProc() +{ + SetRTPriority(); + althrd_setname(MIXER_THREAD_NAME); + + lock(); + while(!mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) + { + ALsizei todo = mWritable.load(std::memory_order_acquire); + if(todo < 1) + { + unlock(); + mSem.wait(); + lock(); + continue; + } + + int widx{mIdx}; + do { + WAVEHDR &waveHdr = mWaveBuffer[widx]; + widx = (widx+1) % mWaveBuffer.size(); + + aluMixData(mDevice, waveHdr.lpData, mDevice->UpdateSize); + mWritable.fetch_sub(1, std::memory_order_acq_rel); + waveOutWrite(mOutHdl, &waveHdr, sizeof(WAVEHDR)); + } while(--todo); + mIdx = widx; + } + unlock(); + + return 0; +} + + +ALCenum WinMMPlayback::open(const ALCchar *name) +{ + if(PlaybackDevices.empty()) + ProbePlaybackDevices(); + + // Find the Device ID matching the deviceName if valid + auto iter = name ? + std::find(PlaybackDevices.cbegin(), PlaybackDevices.cend(), name) : + PlaybackDevices.cbegin(); + if(iter == PlaybackDevices.cend()) return ALC_INVALID_VALUE; + auto DeviceID = static_cast(std::distance(PlaybackDevices.cbegin(), iter)); + +retry_open: + mFormat = WAVEFORMATEX{}; + if(mDevice->FmtType == DevFmtFloat) + { + mFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + mFormat.wBitsPerSample = 32; + } + else + { + mFormat.wFormatTag = WAVE_FORMAT_PCM; + if(mDevice->FmtType == DevFmtUByte || mDevice->FmtType == DevFmtByte) + mFormat.wBitsPerSample = 8; + else + mFormat.wBitsPerSample = 16; + } + mFormat.nChannels = ((mDevice->FmtChans == DevFmtMono) ? 1 : 2); + mFormat.nBlockAlign = mFormat.wBitsPerSample * mFormat.nChannels / 8; + mFormat.nSamplesPerSec = mDevice->Frequency; + mFormat.nAvgBytesPerSec = mFormat.nSamplesPerSec * mFormat.nBlockAlign; + mFormat.cbSize = 0; + + MMRESULT res{waveOutOpen(&mOutHdl, DeviceID, &mFormat, (DWORD_PTR)&WinMMPlayback::waveOutProcC, + reinterpret_cast(this), CALLBACK_FUNCTION)}; + if(res != MMSYSERR_NOERROR) + { + if(mDevice->FmtType == DevFmtFloat) + { + mDevice->FmtType = DevFmtShort; + goto retry_open; + } + ERR("waveOutOpen failed: %u\n", res); + return ALC_INVALID_VALUE; + } + + mDevice->DeviceName = PlaybackDevices[DeviceID]; + return ALC_NO_ERROR; +} + +ALCboolean WinMMPlayback::reset() +{ + mDevice->BufferSize = static_cast(uint64_t{mDevice->BufferSize} * + mFormat.nSamplesPerSec / mDevice->Frequency); + mDevice->BufferSize = (mDevice->BufferSize+3) & ~0x3; + mDevice->UpdateSize = mDevice->BufferSize / 4; + mDevice->Frequency = mFormat.nSamplesPerSec; + + if(mFormat.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) + { + if(mFormat.wBitsPerSample == 32) + mDevice->FmtType = DevFmtFloat; + else + { + ERR("Unhandled IEEE float sample depth: %d\n", mFormat.wBitsPerSample); + return ALC_FALSE; + } + } + else if(mFormat.wFormatTag == WAVE_FORMAT_PCM) + { + if(mFormat.wBitsPerSample == 16) + mDevice->FmtType = DevFmtShort; + else if(mFormat.wBitsPerSample == 8) + mDevice->FmtType = DevFmtUByte; + else + { + ERR("Unhandled PCM sample depth: %d\n", mFormat.wBitsPerSample); + return ALC_FALSE; + } + } + else + { + ERR("Unhandled format tag: 0x%04x\n", mFormat.wFormatTag); + return ALC_FALSE; + } + + if(mFormat.nChannels == 2) + mDevice->FmtChans = DevFmtStereo; + else if(mFormat.nChannels == 1) + mDevice->FmtChans = DevFmtMono; + else + { + ERR("Unhandled channel count: %d\n", mFormat.nChannels); + return ALC_FALSE; + } + SetDefaultWFXChannelOrder(mDevice); + + ALuint BufferSize{mDevice->UpdateSize * mDevice->frameSizeFromFmt()}; + + al_free(mWaveBuffer[0].lpData); + mWaveBuffer[0] = WAVEHDR{}; + mWaveBuffer[0].lpData = static_cast(al_calloc(16, BufferSize * mWaveBuffer.size())); + mWaveBuffer[0].dwBufferLength = BufferSize; + for(size_t i{1};i < mWaveBuffer.size();i++) + { + mWaveBuffer[i] = WAVEHDR{}; + mWaveBuffer[i].lpData = mWaveBuffer[i-1].lpData + mWaveBuffer[i-1].dwBufferLength; + mWaveBuffer[i].dwBufferLength = BufferSize; + } + mIdx = 0; + + return ALC_TRUE; +} + +ALCboolean WinMMPlayback::start() +{ + try { + std::for_each(mWaveBuffer.begin(), mWaveBuffer.end(), + [this](WAVEHDR &waveHdr) -> void + { waveOutPrepareHeader(mOutHdl, &waveHdr, static_cast(sizeof(WAVEHDR))); } + ); + mWritable.store(static_cast(mWaveBuffer.size()), std::memory_order_release); + + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&WinMMPlayback::mixerProc), this}; + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Failed to start mixing thread: %s\n", e.what()); + } + catch(...) { + } + return ALC_FALSE; +} + +void WinMMPlayback::stop() +{ + if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable()) + return; + mThread.join(); + + while(mWritable.load(std::memory_order_acquire) < mWaveBuffer.size()) + mSem.wait(); + std::for_each(mWaveBuffer.begin(), mWaveBuffer.end(), + [this](WAVEHDR &waveHdr) -> void + { waveOutUnprepareHeader(mOutHdl, &waveHdr, sizeof(WAVEHDR)); } + ); + mWritable.store(0, std::memory_order_release); +} + + +struct WinMMCapture final : public BackendBase { + WinMMCapture(ALCdevice *device) noexcept : BackendBase{device} { } + ~WinMMCapture() override; + + static void CALLBACK waveInProcC(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); + void CALLBACK waveInProc(HWAVEIN device, UINT msg, DWORD_PTR param1, DWORD_PTR param2); + + int captureProc(); + + ALCenum open(const ALCchar *name) override; + ALCboolean start() override; + void stop() override; + ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCuint availableSamples() override; + + std::atomic mReadable{0u}; + al::semaphore mSem; + int mIdx{0}; + std::array mWaveBuffer{}; + + HWAVEIN mInHdl{nullptr}; + + RingBufferPtr mRing{nullptr}; + + WAVEFORMATEX mFormat{}; + + std::atomic mKillNow{true}; + std::thread mThread; + + DEF_NEWDEL(WinMMCapture) +}; + +WinMMCapture::~WinMMCapture() +{ + // Close the Wave device + if(mInHdl) + waveInClose(mInHdl); + mInHdl = nullptr; + + al_free(mWaveBuffer[0].lpData); + std::fill(mWaveBuffer.begin(), mWaveBuffer.end(), WAVEHDR{}); +} + +void CALLBACK WinMMCapture::waveInProcC(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2) +{ reinterpret_cast(instance)->waveInProc(device, msg, param1, param2); } + +/* WinMMCapture::waveInProc + * + * Posts a message to 'WinMMCapture::captureProc' everytime a WaveIn Buffer is + * completed and returns to the application (with more data). + */ +void CALLBACK WinMMCapture::waveInProc(HWAVEIN, UINT msg, DWORD_PTR, DWORD_PTR) +{ + if(msg != WIM_DATA) return; + mReadable.fetch_add(1, std::memory_order_acq_rel); + mSem.post(); +} + +int WinMMCapture::captureProc() +{ + althrd_setname(RECORD_THREAD_NAME); + + lock(); + while(!mKillNow.load(std::memory_order_acquire) && + mDevice->Connected.load(std::memory_order_acquire)) + { + ALuint todo{mReadable.load(std::memory_order_acquire)}; + if(todo < 1) + { + unlock(); + mSem.wait(); + lock(); + continue; + } + + int widx{mIdx}; + do { + WAVEHDR &waveHdr = mWaveBuffer[widx]; + widx = (widx+1) % mWaveBuffer.size(); + + mRing->write(waveHdr.lpData, waveHdr.dwBytesRecorded / mFormat.nBlockAlign); + mReadable.fetch_sub(1, std::memory_order_acq_rel); + waveInAddBuffer(mInHdl, &waveHdr, sizeof(WAVEHDR)); + } while(--todo); + mIdx = widx; + } + unlock(); + + return 0; +} + + +ALCenum WinMMCapture::open(const ALCchar *name) +{ + if(CaptureDevices.empty()) + ProbeCaptureDevices(); + + // Find the Device ID matching the deviceName if valid + auto iter = name ? + std::find(CaptureDevices.cbegin(), CaptureDevices.cend(), name) : + CaptureDevices.cbegin(); + if(iter == CaptureDevices.cend()) return ALC_INVALID_VALUE; + auto DeviceID = static_cast(std::distance(CaptureDevices.cbegin(), iter)); + + switch(mDevice->FmtChans) + { + case DevFmtMono: + case DevFmtStereo: + break; + + case DevFmtQuad: + case DevFmtX51: + case DevFmtX51Rear: + case DevFmtX61: + case DevFmtX71: + case DevFmtAmbi3D: + return ALC_INVALID_ENUM; + } + + switch(mDevice->FmtType) + { + case DevFmtUByte: + case DevFmtShort: + case DevFmtInt: + case DevFmtFloat: + break; + + case DevFmtByte: + case DevFmtUShort: + case DevFmtUInt: + return ALC_INVALID_ENUM; + } + + mFormat = WAVEFORMATEX{}; + mFormat.wFormatTag = (mDevice->FmtType == DevFmtFloat) ? + WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM; + mFormat.nChannels = mDevice->channelsFromFmt(); + mFormat.wBitsPerSample = mDevice->bytesFromFmt() * 8; + mFormat.nBlockAlign = mFormat.wBitsPerSample * mFormat.nChannels / 8; + mFormat.nSamplesPerSec = mDevice->Frequency; + mFormat.nAvgBytesPerSec = mFormat.nSamplesPerSec * mFormat.nBlockAlign; + mFormat.cbSize = 0; + + MMRESULT res{waveInOpen(&mInHdl, DeviceID, &mFormat, (DWORD_PTR)&WinMMCapture::waveInProcC, + reinterpret_cast(this), CALLBACK_FUNCTION)}; + if(res != MMSYSERR_NOERROR) + { + ERR("waveInOpen failed: %u\n", res); + return ALC_INVALID_VALUE; + } + + // Ensure each buffer is 50ms each + DWORD BufferSize{mFormat.nAvgBytesPerSec / 20u}; + BufferSize -= (BufferSize % mFormat.nBlockAlign); + + // Allocate circular memory buffer for the captured audio + // Make sure circular buffer is at least 100ms in size + ALuint CapturedDataSize{mDevice->BufferSize}; + CapturedDataSize = static_cast(maxz(CapturedDataSize, BufferSize*mWaveBuffer.size())); + + mRing = CreateRingBuffer(CapturedDataSize, mFormat.nBlockAlign, false); + if(!mRing) return ALC_INVALID_VALUE; + + al_free(mWaveBuffer[0].lpData); + mWaveBuffer[0] = WAVEHDR{}; + mWaveBuffer[0].lpData = static_cast(al_calloc(16, BufferSize*4)); + mWaveBuffer[0].dwBufferLength = BufferSize; + for(size_t i{1};i < mWaveBuffer.size();++i) + { + mWaveBuffer[i] = WAVEHDR{}; + mWaveBuffer[i].lpData = mWaveBuffer[i-1].lpData + mWaveBuffer[i-1].dwBufferLength; + mWaveBuffer[i].dwBufferLength = mWaveBuffer[i-1].dwBufferLength; + } + + mDevice->DeviceName = CaptureDevices[DeviceID]; + return ALC_NO_ERROR; +} + +ALCboolean WinMMCapture::start() +{ + try { + for(size_t i{0};i < mWaveBuffer.size();++i) + { + waveInPrepareHeader(mInHdl, &mWaveBuffer[i], sizeof(WAVEHDR)); + waveInAddBuffer(mInHdl, &mWaveBuffer[i], sizeof(WAVEHDR)); + } + + mKillNow.store(false, std::memory_order_release); + mThread = std::thread{std::mem_fn(&WinMMCapture::captureProc), this}; + + waveInStart(mInHdl); + return ALC_TRUE; + } + catch(std::exception& e) { + ERR("Failed to start mixing thread: %s\n", e.what()); + } + catch(...) { + } + return ALC_FALSE; +} + +void WinMMCapture::stop() +{ + waveInStop(mInHdl); + + mKillNow.store(true, std::memory_order_release); + if(mThread.joinable()) + { + mSem.post(); + mThread.join(); + } + + waveInReset(mInHdl); + for(size_t i{0};i < mWaveBuffer.size();++i) + waveInUnprepareHeader(mInHdl, &mWaveBuffer[i], sizeof(WAVEHDR)); + + mReadable.store(0, std::memory_order_release); + mIdx = 0; +} + +ALCenum WinMMCapture::captureSamples(void *buffer, ALCuint samples) +{ + mRing->read(buffer, samples); + return ALC_NO_ERROR; +} + +ALCuint WinMMCapture::availableSamples() +{ return (ALCuint)mRing->readSpace(); } + +} // namespace + + +bool WinMMBackendFactory::init() +{ return true; } + +bool WinMMBackendFactory::querySupport(BackendType type) +{ return type == BackendType::Playback || type == BackendType::Capture; } + +void WinMMBackendFactory::probe(DevProbe type, std::string *outnames) +{ + auto add_device = [outnames](const std::string &dname) -> void + { + /* +1 to also append the null char (to ensure a null-separated list and + * double-null terminated list). + */ + if(!dname.empty()) + outnames->append(dname.c_str(), dname.length()+1); + }; + switch(type) + { + case DevProbe::Playback: + ProbePlaybackDevices(); + std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); + break; + + case DevProbe::Capture: + ProbeCaptureDevices(); + std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); + break; + } +} + +BackendPtr WinMMBackendFactory::createBackend(ALCdevice *device, BackendType type) +{ + if(type == BackendType::Playback) + return BackendPtr{new WinMMPlayback{device}}; + if(type == BackendType::Capture) + return BackendPtr{new WinMMCapture{device}}; + return nullptr; +} + +BackendFactory &WinMMBackendFactory::getFactory() +{ + static WinMMBackendFactory factory{}; + return factory; +} diff --git a/alc/backends/winmm.h b/alc/backends/winmm.h new file mode 100644 index 00000000..e357ec19 --- /dev/null +++ b/alc/backends/winmm.h @@ -0,0 +1,19 @@ +#ifndef BACKENDS_WINMM_H +#define BACKENDS_WINMM_H + +#include "backends/base.h" + +struct WinMMBackendFactory final : public BackendFactory { +public: + bool init() override; + + bool querySupport(BackendType type) override; + + void probe(DevProbe type, std::string *outnames) override; + + BackendPtr createBackend(ALCdevice *device, BackendType type) override; + + static BackendFactory &getFactory(); +}; + +#endif /* BACKENDS_WINMM_H */ diff --git a/alc/bformatdec.cpp b/alc/bformatdec.cpp new file mode 100644 index 00000000..889bbf3a --- /dev/null +++ b/alc/bformatdec.cpp @@ -0,0 +1,200 @@ + +#include "config.h" + +#include "bformatdec.h" + +#include +#include +#include +#include +#include +#include + +#include "almalloc.h" +#include "alu.h" +#include "ambdec.h" +#include "filters/splitter.h" +#include "opthelpers.h" + + +namespace { + +constexpr ALfloat Ambi3DDecoderHFScale[MAX_AMBI_ORDER+1] = { + 1.00000000e+00f, 1.00000000e+00f +}; +constexpr ALfloat Ambi3DDecoderHFScale2O[MAX_AMBI_ORDER+1] = { + 7.45355990e-01f, 1.00000000e+00f +}; +constexpr ALfloat Ambi3DDecoderHFScale3O[MAX_AMBI_ORDER+1] = { + 5.89792205e-01f, 8.79693856e-01f +}; + +inline auto GetDecoderHFScales(ALsizei order) noexcept -> const ALfloat(&)[MAX_AMBI_ORDER+1] +{ + if(order >= 3) return Ambi3DDecoderHFScale3O; + if(order == 2) return Ambi3DDecoderHFScale2O; + return Ambi3DDecoderHFScale; +} + +inline auto GetAmbiScales(AmbDecScale scaletype) noexcept -> const std::array& +{ + if(scaletype == AmbDecScale::FuMa) return AmbiScale::FromFuMa; + if(scaletype == AmbDecScale::SN3D) return AmbiScale::FromSN3D; + return AmbiScale::FromN3D; +} + +} // namespace + + +BFormatDec::BFormatDec(const AmbDecConf *conf, const bool allow_2band, const ALuint inchans, + const ALuint srate, const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]) +{ + mDualBand = allow_2band && (conf->FreqBands == 2); + if(!mDualBand) + mSamples.resize(2); + else + { + ASSUME(inchans > 0); + mSamples.resize(inchans * 2); + mSamplesHF = mSamples.data(); + mSamplesLF = mSamplesHF + inchans; + } + mNumChannels = inchans; + + mEnabled = std::accumulate(std::begin(chanmap), std::begin(chanmap)+conf->Speakers.size(), 0u, + [](ALuint mask, const ALsizei &chan) noexcept -> ALuint + { return mask | (1 << chan); } + ); + + const ALfloat xover_norm{conf->XOverFreq / static_cast(srate)}; + + const bool periphonic{(conf->ChanMask&AMBI_PERIPHONIC_MASK) != 0}; + const std::array &coeff_scale = GetAmbiScales(conf->CoeffScale); + const size_t coeff_count{periphonic ? MAX_AMBI_CHANNELS : MAX_AMBI2D_CHANNELS}; + + if(!mDualBand) + { + for(size_t i{0u};i < conf->Speakers.size();i++) + { + ALfloat (&mtx)[MAX_AMBI_CHANNELS] = mMatrix.Single[chanmap[i]]; + for(size_t j{0},k{0};j < coeff_count;j++) + { + const size_t l{periphonic ? j : AmbiIndex::From2D[j]}; + if(!(conf->ChanMask&(1u<HFMatrix[i][k] / coeff_scale[l] * + ((l>=9) ? conf->HFOrderGain[3] : + (l>=4) ? conf->HFOrderGain[2] : + (l>=1) ? conf->HFOrderGain[1] : conf->HFOrderGain[0]); + ++k; + } + } + } + else + { + mXOver[0].init(xover_norm); + std::fill(std::begin(mXOver)+1, std::end(mXOver), mXOver[0]); + + const float ratio{std::pow(10.0f, conf->XOverRatio / 40.0f)}; + for(size_t i{0u};i < conf->Speakers.size();i++) + { + ALfloat (&mtx)[sNumBands][MAX_AMBI_CHANNELS] = mMatrix.Dual[chanmap[i]]; + for(size_t j{0},k{0};j < coeff_count;j++) + { + const size_t l{periphonic ? j : AmbiIndex::From2D[j]}; + if(!(conf->ChanMask&(1u<HFMatrix[i][k] / coeff_scale[l] * + ((l>=9) ? conf->HFOrderGain[3] : + (l>=4) ? conf->HFOrderGain[2] : + (l>=1) ? conf->HFOrderGain[1] : conf->HFOrderGain[0]) * ratio; + mtx[sLFBand][j] = conf->LFMatrix[i][k] / coeff_scale[l] * + ((l>=9) ? conf->LFOrderGain[3] : + (l>=4) ? conf->LFOrderGain[2] : + (l>=1) ? conf->LFOrderGain[1] : conf->LFOrderGain[0]) / ratio; + ++k; + } + } + } +} + +BFormatDec::BFormatDec(const ALuint inchans, const ALsizei chancount, + const ChannelDec (&chancoeffs)[MAX_OUTPUT_CHANNELS], + const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]) +{ + mSamples.resize(2); + mNumChannels = inchans; + + ASSUME(chancount > 0); + mEnabled = std::accumulate(std::begin(chanmap), std::begin(chanmap)+chancount, 0u, + [](ALuint mask, const ALsizei &chan) noexcept -> ALuint + { return mask | (1 << chan); } + ); + + const ChannelDec *incoeffs{chancoeffs}; + auto set_coeffs = [this,inchans,&incoeffs](const ALsizei chanidx) noexcept -> void + { + ASSUME(chanidx >= 0); + ALfloat (&mtx)[MAX_AMBI_CHANNELS] = mMatrix.Single[chanidx]; + const ALfloat (&coeffs)[MAX_AMBI_CHANNELS] = *(incoeffs++); + + ASSUME(inchans > 0); + std::copy_n(std::begin(coeffs), inchans, std::begin(mtx)); + }; + std::for_each(chanmap, chanmap+chancount, set_coeffs); +} + + +void BFormatDec::process(const al::span OutBuffer, + const FloatBufferLine *InSamples, const ALsizei SamplesToDo) +{ + if(mDualBand) + { + for(ALuint i{0};i < mNumChannels;i++) + mXOver[i].process(mSamplesHF[i].data(), mSamplesLF[i].data(), InSamples[i].data(), + SamplesToDo); + + const al::span hfsamples{mSamplesHF, mNumChannels}; + const al::span lfsamples{mSamplesLF, mNumChannels}; + ALfloat (*mixmtx)[sNumBands][MAX_AMBI_CHANNELS]{mMatrix.Dual}; + ALuint enabled{mEnabled}; + for(FloatBufferLine &outbuf : OutBuffer) + { + if(LIKELY(enabled&1)) + { + MixRowSamples(outbuf, (*mixmtx)[sHFBand], hfsamples, 0, SamplesToDo); + MixRowSamples(outbuf, (*mixmtx)[sLFBand], lfsamples, 0, SamplesToDo); + } + ++mixmtx; + enabled >>= 1; + } + } + else + { + const al::span insamples{InSamples, mNumChannels}; + ALfloat (*mixmtx)[MAX_AMBI_CHANNELS]{mMatrix.Single}; + ALuint enabled{mEnabled}; + for(FloatBufferLine &outbuf : OutBuffer) + { + if(LIKELY(enabled&1)) + MixRowSamples(outbuf, *mixmtx, insamples, 0, SamplesToDo); + ++mixmtx; + enabled >>= 1; + } + } +} + + +std::array BFormatDec::GetHFOrderScales(const ALsizei in_order, const ALsizei out_order) noexcept +{ + std::array ret{}; + + assert(out_order >= in_order); + ASSUME(out_order >= in_order); + + const ALfloat (&target)[MAX_AMBI_ORDER+1] = GetDecoderHFScales(out_order); + const ALfloat (&input)[MAX_AMBI_ORDER+1] = GetDecoderHFScales(in_order); + + for(ALsizei i{0};i < in_order+1;++i) + ret[i] = input[i] / target[i]; + + return ret; +} diff --git a/alc/bformatdec.h b/alc/bformatdec.h new file mode 100644 index 00000000..06974651 --- /dev/null +++ b/alc/bformatdec.h @@ -0,0 +1,62 @@ +#ifndef BFORMATDEC_H +#define BFORMATDEC_H + +#include +#include + +#include "AL/al.h" + +#include "alcmain.h" +#include "almalloc.h" +#include "alspan.h" +#include "ambidefs.h" +#include "filters/splitter.h" +#include "vector.h" + +struct AmbDecConf; + + +using ChannelDec = ALfloat[MAX_AMBI_CHANNELS]; + +class BFormatDec { + static constexpr size_t sHFBand{0}; + static constexpr size_t sLFBand{1}; + static constexpr size_t sNumBands{2}; + + ALuint mEnabled{0u}; /* Bitfield of enabled channels. */ + + union MatrixU { + ALfloat Dual[MAX_OUTPUT_CHANNELS][sNumBands][MAX_AMBI_CHANNELS]; + ALfloat Single[MAX_OUTPUT_CHANNELS][MAX_AMBI_CHANNELS]; + } mMatrix{}; + + /* NOTE: BandSplitter filters are unused with single-band decoding */ + BandSplitter mXOver[MAX_AMBI_CHANNELS]; + + al::vector mSamples; + /* These two alias into Samples */ + FloatBufferLine *mSamplesHF{nullptr}; + FloatBufferLine *mSamplesLF{nullptr}; + + ALuint mNumChannels{0u}; + bool mDualBand{false}; + +public: + BFormatDec(const AmbDecConf *conf, const bool allow_2band, const ALuint inchans, + const ALuint srate, const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]); + BFormatDec(const ALuint inchans, const ALsizei chancount, + const ChannelDec (&chancoeffs)[MAX_OUTPUT_CHANNELS], + const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]); + + /* Decodes the ambisonic input to the given output channels. */ + void process(const al::span OutBuffer, const FloatBufferLine *InSamples, + const ALsizei SamplesToDo); + + /* Retrieves per-order HF scaling factors for "upsampling" ambisonic data. */ + static std::array GetHFOrderScales(const ALsizei in_order, + const ALsizei out_order) noexcept; + + DEF_NEWDEL(BFormatDec) +}; + +#endif /* BFORMATDEC_H */ diff --git a/alc/bs2b.cpp b/alc/bs2b.cpp new file mode 100644 index 00000000..2d1b96aa --- /dev/null +++ b/alc/bs2b.cpp @@ -0,0 +1,188 @@ +/*- + * Copyright (c) 2005 Boris Mikhaylov + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include +#include +#include + +#include "bs2b.h" +#include "math_defs.h" + + +/* Set up all data. */ +static void init(struct bs2b *bs2b) +{ + float Fc_lo, Fc_hi; + float G_lo, G_hi; + float x, g; + + switch(bs2b->level) + { + case BS2B_LOW_CLEVEL: /* Low crossfeed level */ + Fc_lo = 360.0f; + Fc_hi = 501.0f; + G_lo = 0.398107170553497f; + G_hi = 0.205671765275719f; + break; + + case BS2B_MIDDLE_CLEVEL: /* Middle crossfeed level */ + Fc_lo = 500.0f; + Fc_hi = 711.0f; + G_lo = 0.459726988530872f; + G_hi = 0.228208484414988f; + break; + + case BS2B_HIGH_CLEVEL: /* High crossfeed level (virtual speakers are closer to itself) */ + Fc_lo = 700.0f; + Fc_hi = 1021.0f; + G_lo = 0.530884444230988f; + G_hi = 0.250105790667544f; + break; + + case BS2B_LOW_ECLEVEL: /* Low easy crossfeed level */ + Fc_lo = 360.0f; + Fc_hi = 494.0f; + G_lo = 0.316227766016838f; + G_hi = 0.168236228897329f; + break; + + case BS2B_MIDDLE_ECLEVEL: /* Middle easy crossfeed level */ + Fc_lo = 500.0f; + Fc_hi = 689.0f; + G_lo = 0.354813389233575f; + G_hi = 0.187169483835901f; + break; + + default: /* High easy crossfeed level */ + bs2b->level = BS2B_HIGH_ECLEVEL; + + Fc_lo = 700.0f; + Fc_hi = 975.0f; + G_lo = 0.398107170553497f; + G_hi = 0.205671765275719f; + break; + } /* switch */ + + g = 1.0f / (1.0f - G_hi + G_lo); + + /* $fc = $Fc / $s; + * $d = 1 / 2 / pi / $fc; + * $x = exp(-1 / $d); + */ + x = std::exp(-al::MathDefs::Tau() * Fc_lo / bs2b->srate); + bs2b->b1_lo = x; + bs2b->a0_lo = G_lo * (1.0f - x) * g; + + x = std::exp(-al::MathDefs::Tau() * Fc_hi / bs2b->srate); + bs2b->b1_hi = x; + bs2b->a0_hi = (1.0f - G_hi * (1.0f - x)) * g; + bs2b->a1_hi = -x * g; +} /* init */ + + +/* Exported functions. + * See descriptions in "bs2b.h" + */ + +void bs2b_set_params(struct bs2b *bs2b, int level, int srate) +{ + if(srate <= 0) srate = 1; + + bs2b->level = level; + bs2b->srate = srate; + init(bs2b); +} /* bs2b_set_params */ + +int bs2b_get_level(struct bs2b *bs2b) +{ + return bs2b->level; +} /* bs2b_get_level */ + +int bs2b_get_srate(struct bs2b *bs2b) +{ + return bs2b->srate; +} /* bs2b_get_srate */ + +void bs2b_clear(struct bs2b *bs2b) +{ + std::fill(std::begin(bs2b->last_sample), std::end(bs2b->last_sample), bs2b::t_last_sample{}); +} /* bs2b_clear */ + +void bs2b_cross_feed(struct bs2b *bs2b, float *RESTRICT Left, float *RESTRICT Right, int SamplesToDo) +{ + float lsamples[128][2]; + float rsamples[128][2]; + int base; + + for(base = 0;base < SamplesToDo;) + { + int todo = std::min(128, SamplesToDo-base); + int i; + + /* Process left input */ + lsamples[0][0] = bs2b->a0_lo*Left[0] + + bs2b->b1_lo*bs2b->last_sample[0].lo; + lsamples[0][1] = bs2b->a0_hi*Left[0] + + bs2b->a1_hi*bs2b->last_sample[0].asis + + bs2b->b1_hi*bs2b->last_sample[0].hi; + for(i = 1;i < todo;i++) + { + lsamples[i][0] = bs2b->a0_lo*Left[i] + + bs2b->b1_lo*lsamples[i-1][0]; + lsamples[i][1] = bs2b->a0_hi*Left[i] + + bs2b->a1_hi*Left[i-1] + + bs2b->b1_hi*lsamples[i-1][1]; + } + bs2b->last_sample[0].asis = Left[i-1]; + bs2b->last_sample[0].lo = lsamples[i-1][0]; + bs2b->last_sample[0].hi = lsamples[i-1][1]; + + /* Process right input */ + rsamples[0][0] = bs2b->a0_lo*Right[0] + + bs2b->b1_lo*bs2b->last_sample[1].lo; + rsamples[0][1] = bs2b->a0_hi*Right[0] + + bs2b->a1_hi*bs2b->last_sample[1].asis + + bs2b->b1_hi*bs2b->last_sample[1].hi; + for(i = 1;i < todo;i++) + { + rsamples[i][0] = bs2b->a0_lo*Right[i] + + bs2b->b1_lo*rsamples[i-1][0]; + rsamples[i][1] = bs2b->a0_hi*Right[i] + + bs2b->a1_hi*Right[i-1] + + bs2b->b1_hi*rsamples[i-1][1]; + } + bs2b->last_sample[1].asis = Right[i-1]; + bs2b->last_sample[1].lo = rsamples[i-1][0]; + bs2b->last_sample[1].hi = rsamples[i-1][1]; + + /* Crossfeed */ + for(i = 0;i < todo;i++) + *(Left++) = lsamples[i][1] + rsamples[i][0]; + for(i = 0;i < todo;i++) + *(Right++) = rsamples[i][1] + lsamples[i][0]; + + base += todo; + } +} /* bs2b_cross_feed */ diff --git a/alc/bs2b.h b/alc/bs2b.h new file mode 100644 index 00000000..e235e765 --- /dev/null +++ b/alc/bs2b.h @@ -0,0 +1,90 @@ +/*- + * Copyright (c) 2005 Boris Mikhaylov + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef BS2B_H +#define BS2B_H + +#include "almalloc.h" + +/* Number of crossfeed levels */ +#define BS2B_CLEVELS 3 + +/* Normal crossfeed levels */ +#define BS2B_HIGH_CLEVEL 3 +#define BS2B_MIDDLE_CLEVEL 2 +#define BS2B_LOW_CLEVEL 1 + +/* Easy crossfeed levels */ +#define BS2B_HIGH_ECLEVEL BS2B_HIGH_CLEVEL + BS2B_CLEVELS +#define BS2B_MIDDLE_ECLEVEL BS2B_MIDDLE_CLEVEL + BS2B_CLEVELS +#define BS2B_LOW_ECLEVEL BS2B_LOW_CLEVEL + BS2B_CLEVELS + +/* Default crossfeed levels */ +#define BS2B_DEFAULT_CLEVEL BS2B_HIGH_ECLEVEL +/* Default sample rate (Hz) */ +#define BS2B_DEFAULT_SRATE 44100 + +struct bs2b { + int level; /* Crossfeed level */ + int srate; /* Sample rate (Hz) */ + + /* Lowpass IIR filter coefficients */ + float a0_lo; + float b1_lo; + + /* Highboost IIR filter coefficients */ + float a0_hi; + float a1_hi; + float b1_hi; + + /* Buffer of last filtered sample. + * [0] - first channel, [1] - second channel + */ + struct t_last_sample { + float asis; + float lo; + float hi; + } last_sample[2]; + + DEF_NEWDEL(bs2b) +}; + +/* Clear buffers and set new coefficients with new crossfeed level and sample + * rate values. + * level - crossfeed level of *LEVEL values. + * srate - sample rate by Hz. + */ +void bs2b_set_params(bs2b *bs2b, int level, int srate); + +/* Return current crossfeed level value */ +int bs2b_get_level(bs2b *bs2b); + +/* Return current sample rate value */ +int bs2b_get_srate(bs2b *bs2b); + +/* Clear buffer */ +void bs2b_clear(bs2b *bs2b); + +void bs2b_cross_feed(bs2b *bs2b, float *RESTRICT Left, float *RESTRICT Right, int SamplesToDo); + +#endif /* BS2B_H */ diff --git a/alc/compat.h b/alc/compat.h new file mode 100644 index 00000000..4ffc40bf --- /dev/null +++ b/alc/compat.h @@ -0,0 +1,121 @@ +#ifndef AL_COMPAT_H +#define AL_COMPAT_H + +#ifdef __cplusplus + +#ifdef _WIN32 + +#define WIN32_LEAN_AND_MEAN +#include + +#include +#include +#include + +inline std::string wstr_to_utf8(const WCHAR *wstr) +{ + std::string ret; + + int len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr); + if(len > 0) + { + ret.resize(len); + WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &ret[0], len, nullptr, nullptr); + ret.pop_back(); + } + + return ret; +} + +inline std::wstring utf8_to_wstr(const char *str) +{ + std::wstring ret; + + int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + if(len > 0) + { + ret.resize(len); + MultiByteToWideChar(CP_UTF8, 0, str, -1, &ret[0], len); + ret.pop_back(); + } + + return ret; +} + + +namespace al { + +// Windows' std::ifstream fails with non-ANSI paths since the standard only +// specifies names using const char* (or std::string). MSVC has a non-standard +// extension using const wchar_t* (or std::wstring?) to handle Unicode paths, +// but not all Windows compilers support it. So we have to make our own istream +// that accepts UTF-8 paths and forwards to Unicode-aware I/O functions. +class filebuf final : public std::streambuf { + std::array mBuffer; + HANDLE mFile{INVALID_HANDLE_VALUE}; + + int_type underflow() override; + pos_type seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) override; + pos_type seekpos(pos_type pos, std::ios_base::openmode mode) override; + +public: + filebuf() = default; + ~filebuf() override; + + bool open(const wchar_t *filename, std::ios_base::openmode mode); + bool open(const char *filename, std::ios_base::openmode mode); + + bool is_open() const noexcept { return mFile != INVALID_HANDLE_VALUE; } +}; + +// Inherit from std::istream to use our custom streambuf +class ifstream final : public std::istream { + filebuf mStreamBuf; + +public: + ifstream(const wchar_t *filename, std::ios_base::openmode mode = std::ios_base::in); + ifstream(const std::wstring &filename, std::ios_base::openmode mode = std::ios_base::in) + : ifstream(filename.c_str(), mode) { } + ifstream(const char *filename, std::ios_base::openmode mode = std::ios_base::in); + ifstream(const std::string &filename, std::ios_base::openmode mode = std::ios_base::in) + : ifstream(filename.c_str(), mode) { } + ~ifstream() override; + + bool is_open() const noexcept { return mStreamBuf.is_open(); } +}; + +} // namespace al + +#define HAVE_DYNLOAD 1 + +#else /* _WIN32 */ + +#include + +namespace al { + +using filebuf = std::filebuf; +using ifstream = std::ifstream; + +} // namespace al + +#if defined(HAVE_DLFCN_H) +#define HAVE_DYNLOAD 1 +#endif + +#endif /* _WIN32 */ + +#include + +struct PathNamePair { std::string path, fname; }; +const PathNamePair &GetProcBinary(void); + +#ifdef HAVE_DYNLOAD +void *LoadLib(const char *name); +void CloseLib(void *handle); +void *GetSymbol(void *handle, const char *name); +#endif + +#endif /* __cplusplus */ + +#endif /* AL_COMPAT_H */ diff --git a/alc/converter.cpp b/alc/converter.cpp new file mode 100644 index 00000000..0f8e8941 --- /dev/null +++ b/alc/converter.cpp @@ -0,0 +1,367 @@ + +#include "config.h" + +#include "converter.h" + +#include + +#include "fpu_modes.h" +#include "mixer/defs.h" + + +namespace { + +/* Base template left undefined. Should be marked =delete, but Clang 3.8.1 + * chokes on that given the inline specializations. + */ +template +inline ALfloat LoadSample(typename DevFmtTypeTraits::Type val) noexcept; + +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept +{ return val * (1.0f/128.0f); } +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept +{ return val * (1.0f/32768.0f); } +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept +{ return val * (1.0f/2147483648.0f); } +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept +{ return val; } + +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept +{ return LoadSample(val - 128); } +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept +{ return LoadSample(val - 32768); } +template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept +{ return LoadSample(val - 2147483648u); } + + +template +inline void LoadSampleArray(ALfloat *RESTRICT dst, const void *src, const size_t srcstep, + const ALsizei samples) noexcept +{ + using SampleType = typename DevFmtTypeTraits::Type; + + const SampleType *ssrc = static_cast(src); + for(ALsizei i{0};i < samples;i++) + dst[i] = LoadSample(ssrc[i*srcstep]); +} + +void LoadSamples(ALfloat *dst, const ALvoid *src, const size_t srcstep, const DevFmtType srctype, + const ALsizei samples) noexcept +{ +#define HANDLE_FMT(T) \ + case T: LoadSampleArray(dst, src, srcstep, samples); break + switch(srctype) + { + HANDLE_FMT(DevFmtByte); + HANDLE_FMT(DevFmtUByte); + HANDLE_FMT(DevFmtShort); + HANDLE_FMT(DevFmtUShort); + HANDLE_FMT(DevFmtInt); + HANDLE_FMT(DevFmtUInt); + HANDLE_FMT(DevFmtFloat); + } +#undef HANDLE_FMT +} + + +template +inline typename DevFmtTypeTraits::Type StoreSample(ALfloat) noexcept; + +template<> inline ALfloat StoreSample(ALfloat val) noexcept +{ return val; } +template<> inline ALint StoreSample(ALfloat val) noexcept +{ return fastf2i(clampf(val*2147483648.0f, -2147483648.0f, 2147483520.0f)); } +template<> inline ALshort StoreSample(ALfloat val) noexcept +{ return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); } +template<> inline ALbyte StoreSample(ALfloat val) noexcept +{ return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); } + +/* Define unsigned output variations. */ +template<> inline ALuint StoreSample(ALfloat val) noexcept +{ return StoreSample(val) + 2147483648u; } +template<> inline ALushort StoreSample(ALfloat val) noexcept +{ return StoreSample(val) + 32768; } +template<> inline ALubyte StoreSample(ALfloat val) noexcept +{ return StoreSample(val) + 128; } + +template +inline void StoreSampleArray(void *dst, const ALfloat *RESTRICT src, const size_t dststep, + const ALsizei samples) noexcept +{ + using SampleType = typename DevFmtTypeTraits::Type; + + SampleType *sdst = static_cast(dst); + for(ALsizei i{0};i < samples;i++) + sdst[i*dststep] = StoreSample(src[i]); +} + + +void StoreSamples(ALvoid *dst, const ALfloat *src, const size_t dststep, const DevFmtType dsttype, + const ALsizei samples) noexcept +{ +#define HANDLE_FMT(T) \ + case T: StoreSampleArray(dst, src, dststep, samples); break + switch(dsttype) + { + HANDLE_FMT(DevFmtByte); + HANDLE_FMT(DevFmtUByte); + HANDLE_FMT(DevFmtShort); + HANDLE_FMT(DevFmtUShort); + HANDLE_FMT(DevFmtInt); + HANDLE_FMT(DevFmtUInt); + HANDLE_FMT(DevFmtFloat); + } +#undef HANDLE_FMT +} + + +template +void Mono2Stereo(ALfloat *RESTRICT dst, const void *src, const ALsizei frames) noexcept +{ + using SampleType = typename DevFmtTypeTraits::Type; + + const SampleType *ssrc = static_cast(src); + for(ALsizei i{0};i < frames;i++) + dst[i*2 + 1] = dst[i*2 + 0] = LoadSample(ssrc[i]) * 0.707106781187f; +} + +template +void Stereo2Mono(ALfloat *RESTRICT dst, const void *src, const ALsizei frames) noexcept +{ + using SampleType = typename DevFmtTypeTraits::Type; + + const SampleType *ssrc = static_cast(src); + for(ALsizei i{0};i < frames;i++) + dst[i] = (LoadSample(ssrc[i*2 + 0])+LoadSample(ssrc[i*2 + 1])) * + 0.707106781187f; +} + +} // namespace + +SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, ALsizei numchans, + ALsizei srcRate, ALsizei dstRate, Resampler resampler) +{ + if(numchans <= 0 || srcRate <= 0 || dstRate <= 0) + return nullptr; + + void *ptr{al_calloc(16, SampleConverter::Sizeof(numchans))}; + SampleConverterPtr converter{new (ptr) SampleConverter{static_cast(numchans)}}; + converter->mSrcType = srcType; + converter->mDstType = dstType; + converter->mSrcTypeSize = BytesFromDevFmt(srcType); + converter->mDstTypeSize = BytesFromDevFmt(dstType); + + converter->mSrcPrepCount = 0; + converter->mFracOffset = 0; + + /* Have to set the mixer FPU mode since that's what the resampler code expects. */ + FPUCtl mixer_mode{}; + auto step = static_cast( + mind(static_cast(srcRate)/dstRate*FRACTIONONE + 0.5, MAX_PITCH*FRACTIONONE)); + converter->mIncrement = maxi(step, 1); + if(converter->mIncrement == FRACTIONONE) + converter->mResample = Resample_; + else + { + if(resampler == BSinc24Resampler) + BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc24); + else if(resampler == BSinc12Resampler) + BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc12); + converter->mResample = SelectResampler(resampler); + } + + return converter; +} + +ALsizei SampleConverter::availableOut(ALsizei srcframes) const +{ + ALint prepcount{mSrcPrepCount}; + if(prepcount < 0) + { + /* Negative prepcount means we need to skip that many input samples. */ + if(-prepcount >= srcframes) + return 0; + srcframes += prepcount; + prepcount = 0; + } + + if(srcframes < 1) + { + /* No output samples if there's no input samples. */ + return 0; + } + + if(prepcount < MAX_RESAMPLE_PADDING*2 && + MAX_RESAMPLE_PADDING*2 - prepcount >= srcframes) + { + /* Not enough input samples to generate an output sample. */ + return 0; + } + + auto DataSize64 = static_cast(prepcount); + DataSize64 += srcframes; + DataSize64 -= MAX_RESAMPLE_PADDING*2; + DataSize64 <<= FRACTIONBITS; + DataSize64 -= mFracOffset; + + /* If we have a full prep, we can generate at least one sample. */ + return static_cast(clampu64((DataSize64 + mIncrement-1)/mIncrement, 1, BUFFERSIZE)); +} + +ALsizei SampleConverter::convert(const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes) +{ + const ALsizei SrcFrameSize{static_cast(mChan.size()) * mSrcTypeSize}; + const ALsizei DstFrameSize{static_cast(mChan.size()) * mDstTypeSize}; + const ALsizei increment{mIncrement}; + auto SamplesIn = static_cast(*src); + ALsizei NumSrcSamples{*srcframes}; + + FPUCtl mixer_mode{}; + ALsizei pos{0}; + while(pos < dstframes && NumSrcSamples > 0) + { + ALint prepcount{mSrcPrepCount}; + if(prepcount < 0) + { + /* Negative prepcount means we need to skip that many input samples. */ + if(-prepcount >= NumSrcSamples) + { + mSrcPrepCount = prepcount + NumSrcSamples; + NumSrcSamples = 0; + break; + } + SamplesIn += SrcFrameSize*-prepcount; + NumSrcSamples += prepcount; + mSrcPrepCount = 0; + continue; + } + ALint toread{mini(NumSrcSamples, BUFFERSIZE - MAX_RESAMPLE_PADDING*2)}; + + if(prepcount < MAX_RESAMPLE_PADDING*2 && + MAX_RESAMPLE_PADDING*2 - prepcount >= toread) + { + /* Not enough input samples to generate an output sample. Store + * what we're given for later. + */ + for(size_t chan{0u};chan < mChan.size();chan++) + LoadSamples(&mChan[chan].PrevSamples[prepcount], SamplesIn + mSrcTypeSize*chan, + mChan.size(), mSrcType, toread); + + mSrcPrepCount = prepcount + toread; + NumSrcSamples = 0; + break; + } + + ALfloat *RESTRICT SrcData{mSrcSamples}; + ALfloat *RESTRICT DstData{mDstSamples}; + ALsizei DataPosFrac{mFracOffset}; + auto DataSize64 = static_cast(prepcount); + DataSize64 += toread; + DataSize64 -= MAX_RESAMPLE_PADDING*2; + DataSize64 <<= FRACTIONBITS; + DataSize64 -= DataPosFrac; + + /* If we have a full prep, we can generate at least one sample. */ + auto DstSize = static_cast( + clampu64((DataSize64 + increment-1)/increment, 1, BUFFERSIZE)); + DstSize = mini(DstSize, dstframes-pos); + + for(size_t chan{0u};chan < mChan.size();chan++) + { + const al::byte *SrcSamples{SamplesIn + mSrcTypeSize*chan}; + al::byte *DstSamples = static_cast(dst) + mDstTypeSize*chan; + + /* Load the previous samples into the source data first, then the + * new samples from the input buffer. + */ + std::copy_n(mChan[chan].PrevSamples, prepcount, SrcData); + LoadSamples(SrcData + prepcount, SrcSamples, mChan.size(), mSrcType, toread); + + /* Store as many prep samples for next time as possible, given the + * number of output samples being generated. + */ + ALsizei SrcDataEnd{(DstSize*increment + DataPosFrac)>>FRACTIONBITS}; + if(SrcDataEnd >= prepcount+toread) + std::fill(std::begin(mChan[chan].PrevSamples), + std::end(mChan[chan].PrevSamples), 0.0f); + else + { + size_t len = mini(MAX_RESAMPLE_PADDING*2, prepcount+toread-SrcDataEnd); + std::copy_n(SrcData+SrcDataEnd, len, mChan[chan].PrevSamples); + std::fill(std::begin(mChan[chan].PrevSamples)+len, + std::end(mChan[chan].PrevSamples), 0.0f); + } + + /* Now resample, and store the result in the output buffer. */ + const ALfloat *ResampledData{mResample(&mState, SrcData+MAX_RESAMPLE_PADDING, + DataPosFrac, increment, DstData, DstSize)}; + + StoreSamples(DstSamples, ResampledData, mChan.size(), mDstType, DstSize); + } + + /* Update the number of prep samples still available, as well as the + * fractional offset. + */ + DataPosFrac += increment*DstSize; + mSrcPrepCount = mini(prepcount + toread - (DataPosFrac>>FRACTIONBITS), + MAX_RESAMPLE_PADDING*2); + mFracOffset = DataPosFrac & FRACTIONMASK; + + /* Update the src and dst pointers in case there's still more to do. */ + SamplesIn += SrcFrameSize*(DataPosFrac>>FRACTIONBITS); + NumSrcSamples -= mini(NumSrcSamples, (DataPosFrac>>FRACTIONBITS)); + + dst = static_cast(dst) + DstFrameSize*DstSize; + pos += DstSize; + } + + *src = SamplesIn; + *srcframes = NumSrcSamples; + + return pos; +} + + +ChannelConverterPtr CreateChannelConverter(DevFmtType srcType, DevFmtChannels srcChans, DevFmtChannels dstChans) +{ + if(srcChans != dstChans && !((srcChans == DevFmtMono && dstChans == DevFmtStereo) || + (srcChans == DevFmtStereo && dstChans == DevFmtMono))) + return nullptr; + return al::make_unique(srcType, srcChans, dstChans); +} + +void ChannelConverter::convert(const ALvoid *src, ALfloat *dst, ALsizei frames) const +{ + if(mSrcChans == DevFmtStereo && mDstChans == DevFmtMono) + { + switch(mSrcType) + { +#define HANDLE_FMT(T) case T: Stereo2Mono(dst, src, frames); break + HANDLE_FMT(DevFmtByte); + HANDLE_FMT(DevFmtUByte); + HANDLE_FMT(DevFmtShort); + HANDLE_FMT(DevFmtUShort); + HANDLE_FMT(DevFmtInt); + HANDLE_FMT(DevFmtUInt); + HANDLE_FMT(DevFmtFloat); +#undef HANDLE_FMT + } + } + else if(mSrcChans == DevFmtMono && mDstChans == DevFmtStereo) + { + switch(mSrcType) + { +#define HANDLE_FMT(T) case T: Mono2Stereo(dst, src, frames); break + HANDLE_FMT(DevFmtByte); + HANDLE_FMT(DevFmtUByte); + HANDLE_FMT(DevFmtShort); + HANDLE_FMT(DevFmtUShort); + HANDLE_FMT(DevFmtInt); + HANDLE_FMT(DevFmtUInt); + HANDLE_FMT(DevFmtFloat); +#undef HANDLE_FMT + } + } + else + LoadSamples(dst, src, 1u, mSrcType, frames*ChannelsFromDevFmt(mSrcChans, 0)); +} diff --git a/alc/converter.h b/alc/converter.h new file mode 100644 index 00000000..033e4d3f --- /dev/null +++ b/alc/converter.h @@ -0,0 +1,70 @@ +#ifndef CONVERTER_H +#define CONVERTER_H + +#include + +#include "alcmain.h" +#include "alu.h" +#include "almalloc.h" + +struct SampleConverter { + DevFmtType mSrcType{}; + DevFmtType mDstType{}; + ALsizei mSrcTypeSize{}; + ALsizei mDstTypeSize{}; + + ALint mSrcPrepCount{}; + + ALsizei mFracOffset{}; + ALsizei mIncrement{}; + InterpState mState{}; + ResamplerFunc mResample{}; + + alignas(16) ALfloat mSrcSamples[BUFFERSIZE]{}; + alignas(16) ALfloat mDstSamples[BUFFERSIZE]{}; + + struct ChanSamples { + alignas(16) ALfloat PrevSamples[MAX_RESAMPLE_PADDING*2]; + }; + al::FlexArray mChan; + + SampleConverter(size_t numchans) : mChan{numchans} { } + SampleConverter(const SampleConverter&) = delete; + SampleConverter& operator=(const SampleConverter&) = delete; + + ALsizei convert(const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes); + ALsizei availableOut(ALsizei srcframes) const; + + static constexpr size_t Sizeof(size_t length) noexcept + { + return maxz(sizeof(SampleConverter), + al::FlexArray::Sizeof(length, offsetof(SampleConverter, mChan))); + } + + DEF_PLACE_NEWDEL() +}; +using SampleConverterPtr = std::unique_ptr; + +SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, ALsizei numchans, + ALsizei srcRate, ALsizei dstRate, Resampler resampler); + + +struct ChannelConverter { + DevFmtType mSrcType; + DevFmtChannels mSrcChans; + DevFmtChannels mDstChans; + + ChannelConverter(DevFmtType srctype, DevFmtChannels srcchans, DevFmtChannels dstchans) + : mSrcType(srctype), mSrcChans(srcchans), mDstChans(dstchans) + { } + + void convert(const ALvoid *src, ALfloat *dst, ALsizei frames) const; + + DEF_NEWDEL(ChannelConverter) +}; +using ChannelConverterPtr = std::unique_ptr; + +ChannelConverterPtr CreateChannelConverter(DevFmtType srcType, DevFmtChannels srcChans, + DevFmtChannels dstChans); + +#endif /* CONVERTER_H */ diff --git a/alc/cpu_caps.h b/alc/cpu_caps.h new file mode 100644 index 00000000..64a4ee45 --- /dev/null +++ b/alc/cpu_caps.h @@ -0,0 +1,16 @@ +#ifndef CPU_CAPS_H +#define CPU_CAPS_H + + +extern int CPUCapFlags; +enum { + CPU_CAP_SSE = 1<<0, + CPU_CAP_SSE2 = 1<<1, + CPU_CAP_SSE3 = 1<<2, + CPU_CAP_SSE4_1 = 1<<3, + CPU_CAP_NEON = 1<<4, +}; + +void FillCPUCaps(int capfilter); + +#endif /* CPU_CAPS_H */ diff --git a/alc/effects/autowah.cpp b/alc/effects/autowah.cpp new file mode 100644 index 00000000..96292636 --- /dev/null +++ b/alc/effects/autowah.cpp @@ -0,0 +1,298 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2018 by Raul Herraiz. + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include + +#include "alcmain.h" +#include "alcontext.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" +#include "filters/biquad.h" +#include "vecmat.h" + +namespace { + +#define MIN_FREQ 20.0f +#define MAX_FREQ 2500.0f +#define Q_FACTOR 5.0f + +struct ALautowahState final : public EffectState { + /* Effect parameters */ + ALfloat mAttackRate; + ALfloat mReleaseRate; + ALfloat mResonanceGain; + ALfloat mPeakGain; + ALfloat mFreqMinNorm; + ALfloat mBandwidthNorm; + ALfloat mEnvDelay; + + /* Filter components derived from the envelope. */ + struct { + ALfloat cos_w0; + ALfloat alpha; + } mEnv[BUFFERSIZE]; + + struct { + /* Effect filters' history. */ + struct { + ALfloat z1, z2; + } Filter; + + /* Effect gains for each output channel */ + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; + } mChans[MAX_AMBI_CHANNELS]; + + /* Effects buffers */ + alignas(16) ALfloat mBufferOut[BUFFERSIZE]; + + + ALboolean deviceUpdate(const ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + + DEF_NEWDEL(ALautowahState) +}; + +ALboolean ALautowahState::deviceUpdate(const ALCdevice*) +{ + /* (Re-)initializing parameters and clear the buffers. */ + + mAttackRate = 1.0f; + mReleaseRate = 1.0f; + mResonanceGain = 10.0f; + mPeakGain = 4.5f; + mFreqMinNorm = 4.5e-4f; + mBandwidthNorm = 0.05f; + mEnvDelay = 0.0f; + + for(auto &e : mEnv) + { + e.cos_w0 = 0.0f; + e.alpha = 0.0f; + } + + for(auto &chan : mChans) + { + std::fill(std::begin(chan.CurrentGains), std::end(chan.CurrentGains), 0.0f); + chan.Filter.z1 = 0.0f; + chan.Filter.z2 = 0.0f; + } + + return AL_TRUE; +} + +void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) +{ + const ALCdevice *device{context->Device}; + + const ALfloat ReleaseTime{clampf(props->Autowah.ReleaseTime, 0.001f, 1.0f)}; + + mAttackRate = expf(-1.0f / (props->Autowah.AttackTime*device->Frequency)); + mReleaseRate = expf(-1.0f / (ReleaseTime*device->Frequency)); + /* 0-20dB Resonance Peak gain */ + mResonanceGain = std::sqrt(std::log10(props->Autowah.Resonance)*10.0f / 3.0f); + mPeakGain = 1.0f - std::log10(props->Autowah.PeakGain/AL_AUTOWAH_MAX_PEAK_GAIN); + mFreqMinNorm = MIN_FREQ / device->Frequency; + mBandwidthNorm = (MAX_FREQ-MIN_FREQ) / device->Frequency; + + mOutTarget = target.Main->Buffer; + for(size_t i{0u};i < slot->Wet.Buffer.size();++i) + { + auto coeffs = GetAmbiIdentityRow(i); + ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mChans[i].TargetGains); + } +} + +void ALautowahState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) +{ + const ALfloat attack_rate = mAttackRate; + const ALfloat release_rate = mReleaseRate; + const ALfloat res_gain = mResonanceGain; + const ALfloat peak_gain = mPeakGain; + const ALfloat freq_min = mFreqMinNorm; + const ALfloat bandwidth = mBandwidthNorm; + + ALfloat env_delay{mEnvDelay}; + for(ALsizei i{0};i < samplesToDo;i++) + { + ALfloat w0, sample, a; + + /* Envelope follower described on the book: Audio Effects, Theory, + * Implementation and Application. + */ + sample = peak_gain * std::fabs(samplesIn[0][i]); + a = (sample > env_delay) ? attack_rate : release_rate; + env_delay = lerp(sample, env_delay, a); + + /* Calculate the cos and alpha components for this sample's filter. */ + w0 = minf((bandwidth*env_delay + freq_min), 0.46f) * al::MathDefs::Tau(); + mEnv[i].cos_w0 = cosf(w0); + mEnv[i].alpha = sinf(w0)/(2.0f * Q_FACTOR); + } + mEnvDelay = env_delay; + + ASSUME(numInput > 0); + for(ALsizei c{0};c < numInput;++c) + { + /* This effectively inlines BiquadFilter_setParams for a peaking + * filter and BiquadFilter_processC. The alpha and cosine components + * for the filter coefficients were previously calculated with the + * envelope. Because the filter changes for each sample, the + * coefficients are transient and don't need to be held. + */ + ALfloat z1{mChans[c].Filter.z1}; + ALfloat z2{mChans[c].Filter.z2}; + + for(ALsizei i{0};i < samplesToDo;i++) + { + const ALfloat alpha = mEnv[i].alpha; + const ALfloat cos_w0 = mEnv[i].cos_w0; + ALfloat input, output; + ALfloat a[3], b[3]; + + b[0] = 1.0f + alpha*res_gain; + b[1] = -2.0f * cos_w0; + b[2] = 1.0f - alpha*res_gain; + a[0] = 1.0f + alpha/res_gain; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha/res_gain; + + input = samplesIn[c][i]; + output = input*(b[0]/a[0]) + z1; + z1 = input*(b[1]/a[0]) - output*(a[1]/a[0]) + z2; + z2 = input*(b[2]/a[0]) - output*(a[2]/a[0]); + mBufferOut[i] = output; + } + mChans[c].Filter.z1 = z1; + mChans[c].Filter.z2 = z2; + + /* Now, mix the processed sound data to the output. */ + MixSamples(mBufferOut, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, + samplesToDo, 0, samplesToDo); + } +} + + +void ALautowah_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_AUTOWAH_ATTACK_TIME: + if(!(val >= AL_AUTOWAH_MIN_ATTACK_TIME && val <= AL_AUTOWAH_MAX_ATTACK_TIME)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Autowah attack time out of range"); + props->Autowah.AttackTime = val; + break; + + case AL_AUTOWAH_RELEASE_TIME: + if(!(val >= AL_AUTOWAH_MIN_RELEASE_TIME && val <= AL_AUTOWAH_MAX_RELEASE_TIME)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Autowah release time out of range"); + props->Autowah.ReleaseTime = val; + break; + + case AL_AUTOWAH_RESONANCE: + if(!(val >= AL_AUTOWAH_MIN_RESONANCE && val <= AL_AUTOWAH_MAX_RESONANCE)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Autowah resonance out of range"); + props->Autowah.Resonance = val; + break; + + case AL_AUTOWAH_PEAK_GAIN: + if(!(val >= AL_AUTOWAH_MIN_PEAK_GAIN && val <= AL_AUTOWAH_MAX_PEAK_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Autowah peak gain out of range"); + props->Autowah.PeakGain = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param); + } +} +void ALautowah_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALautowah_setParamf(props, context, param, vals[0]); } + +void ALautowah_setParami(EffectProps*, ALCcontext *context, ALenum param, ALint) +{ alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param); } +void ALautowah_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x", param); } + +void ALautowah_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_AUTOWAH_ATTACK_TIME: + *val = props->Autowah.AttackTime; + break; + + case AL_AUTOWAH_RELEASE_TIME: + *val = props->Autowah.ReleaseTime; + break; + + case AL_AUTOWAH_RESONANCE: + *val = props->Autowah.Resonance; + break; + + case AL_AUTOWAH_PEAK_GAIN: + *val = props->Autowah.PeakGain; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param); + } + +} +void ALautowah_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALautowah_getParamf(props, context, param, vals); } + +void ALautowah_getParami(const EffectProps*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param); } +void ALautowah_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x", param); } + +DEFINE_ALEFFECT_VTABLE(ALautowah); + + +struct AutowahStateFactory final : public EffectStateFactory { + EffectState *create() override { return new ALautowahState{}; } + EffectProps getDefaultProps() const noexcept override; + const EffectVtable *getEffectVtable() const noexcept override { return &ALautowah_vtable; } +}; + +EffectProps AutowahStateFactory::getDefaultProps() const noexcept +{ + EffectProps props{}; + props.Autowah.AttackTime = AL_AUTOWAH_DEFAULT_ATTACK_TIME; + props.Autowah.ReleaseTime = AL_AUTOWAH_DEFAULT_RELEASE_TIME; + props.Autowah.Resonance = AL_AUTOWAH_DEFAULT_RESONANCE; + props.Autowah.PeakGain = AL_AUTOWAH_DEFAULT_PEAK_GAIN; + return props; +} + +} // namespace + +EffectStateFactory *AutowahStateFactory_getFactory() +{ + static AutowahStateFactory AutowahFactory{}; + return &AutowahFactory; +} diff --git a/alc/effects/base.h b/alc/effects/base.h new file mode 100644 index 00000000..4f48de22 --- /dev/null +++ b/alc/effects/base.h @@ -0,0 +1,196 @@ +#ifndef EFFECTS_BASE_H +#define EFFECTS_BASE_H + +#include "alcmain.h" +#include "almalloc.h" +#include "alspan.h" +#include "atomic.h" + + +struct ALeffectslot; + + +union EffectProps { + struct { + // Shared Reverb Properties + ALfloat Density; + ALfloat Diffusion; + ALfloat Gain; + ALfloat GainHF; + ALfloat DecayTime; + ALfloat DecayHFRatio; + ALfloat ReflectionsGain; + ALfloat ReflectionsDelay; + ALfloat LateReverbGain; + ALfloat LateReverbDelay; + ALfloat AirAbsorptionGainHF; + ALfloat RoomRolloffFactor; + ALboolean DecayHFLimit; + + // Additional EAX Reverb Properties + ALfloat GainLF; + ALfloat DecayLFRatio; + ALfloat ReflectionsPan[3]; + ALfloat LateReverbPan[3]; + ALfloat EchoTime; + ALfloat EchoDepth; + ALfloat ModulationTime; + ALfloat ModulationDepth; + ALfloat HFReference; + ALfloat LFReference; + } Reverb; + + struct { + ALfloat AttackTime; + ALfloat ReleaseTime; + ALfloat Resonance; + ALfloat PeakGain; + } Autowah; + + struct { + ALint Waveform; + ALint Phase; + ALfloat Rate; + ALfloat Depth; + ALfloat Feedback; + ALfloat Delay; + } Chorus; /* Also Flanger */ + + struct { + ALboolean OnOff; + } Compressor; + + struct { + ALfloat Edge; + ALfloat Gain; + ALfloat LowpassCutoff; + ALfloat EQCenter; + ALfloat EQBandwidth; + } Distortion; + + struct { + ALfloat Delay; + ALfloat LRDelay; + + ALfloat Damping; + ALfloat Feedback; + + ALfloat Spread; + } Echo; + + struct { + ALfloat LowCutoff; + ALfloat LowGain; + ALfloat Mid1Center; + ALfloat Mid1Gain; + ALfloat Mid1Width; + ALfloat Mid2Center; + ALfloat Mid2Gain; + ALfloat Mid2Width; + ALfloat HighCutoff; + ALfloat HighGain; + } Equalizer; + + struct { + ALfloat Frequency; + ALint LeftDirection; + ALint RightDirection; + } Fshifter; + + struct { + ALfloat Frequency; + ALfloat HighPassCutoff; + ALint Waveform; + } Modulator; + + struct { + ALint CoarseTune; + ALint FineTune; + } Pshifter; + + struct { + ALfloat Rate; + ALint PhonemeA; + ALint PhonemeB; + ALint PhonemeACoarseTuning; + ALint PhonemeBCoarseTuning; + ALint Waveform; + } Vmorpher; + + struct { + ALfloat Gain; + } Dedicated; +}; + + +struct EffectVtable { + void (*const setParami)(EffectProps *props, ALCcontext *context, ALenum param, ALint val); + void (*const setParamiv)(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals); + void (*const setParamf)(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val); + void (*const setParamfv)(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals); + + void (*const getParami)(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val); + void (*const getParamiv)(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals); + void (*const getParamf)(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val); + void (*const getParamfv)(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals); +}; + +#define DEFINE_ALEFFECT_VTABLE(T) \ +const EffectVtable T##_vtable = { \ + T##_setParami, T##_setParamiv, \ + T##_setParamf, T##_setParamfv, \ + T##_getParami, T##_getParamiv, \ + T##_getParamf, T##_getParamfv, \ +} + + +struct EffectTarget { + MixParams *Main; + RealMixParams *RealOut; +}; + +struct EffectState { + RefCount mRef{1u}; + + al::span mOutTarget; + + + virtual ~EffectState() = default; + + virtual ALboolean deviceUpdate(const ALCdevice *device) = 0; + virtual void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) = 0; + virtual void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) = 0; + + void IncRef() noexcept; + void DecRef() noexcept; +}; + + +struct EffectStateFactory { + virtual ~EffectStateFactory() { } + + virtual EffectState *create() = 0; + virtual EffectProps getDefaultProps() const noexcept = 0; + virtual const EffectVtable *getEffectVtable() const noexcept = 0; +}; + + +EffectStateFactory *NullStateFactory_getFactory(void); +EffectStateFactory *ReverbStateFactory_getFactory(void); +EffectStateFactory *StdReverbStateFactory_getFactory(void); +EffectStateFactory *AutowahStateFactory_getFactory(void); +EffectStateFactory *ChorusStateFactory_getFactory(void); +EffectStateFactory *CompressorStateFactory_getFactory(void); +EffectStateFactory *DistortionStateFactory_getFactory(void); +EffectStateFactory *EchoStateFactory_getFactory(void); +EffectStateFactory *EqualizerStateFactory_getFactory(void); +EffectStateFactory *FlangerStateFactory_getFactory(void); +EffectStateFactory *FshifterStateFactory_getFactory(void); +EffectStateFactory *ModulatorStateFactory_getFactory(void); +EffectStateFactory *PshifterStateFactory_getFactory(void); +EffectStateFactory* VmorpherStateFactory_getFactory(void); + +EffectStateFactory *DedicatedStateFactory_getFactory(void); + + +#endif /* EFFECTS_BASE_H */ diff --git a/alc/effects/chorus.cpp b/alc/effects/chorus.cpp new file mode 100644 index 00000000..d475b57a --- /dev/null +++ b/alc/effects/chorus.cpp @@ -0,0 +1,538 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2013 by Mike Gorchak + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/efx.h" + +#include "alAuxEffectSlot.h" +#include "alcmain.h" +#include "alError.h" +#include "alcontext.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "alspan.h" +#include "alu.h" +#include "ambidefs.h" +#include "effects/base.h" +#include "math_defs.h" +#include "opthelpers.h" +#include "vector.h" + + +namespace { + +static_assert(AL_CHORUS_WAVEFORM_SINUSOID == AL_FLANGER_WAVEFORM_SINUSOID, "Chorus/Flanger waveform value mismatch"); +static_assert(AL_CHORUS_WAVEFORM_TRIANGLE == AL_FLANGER_WAVEFORM_TRIANGLE, "Chorus/Flanger waveform value mismatch"); + +enum class WaveForm { + Sinusoid, + Triangle +}; + +void GetTriangleDelays(ALint *delays, const ALsizei start_offset, const ALsizei lfo_range, + const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, const ALsizei todo) +{ + ASSUME(start_offset >= 0); + ASSUME(lfo_range > 0); + ASSUME(todo > 0); + + ALsizei offset{start_offset}; + auto gen_lfo = [&offset,lfo_range,lfo_scale,depth,delay]() -> ALint + { + offset = (offset+1)%lfo_range; + return fastf2i((1.0f - std::abs(2.0f - lfo_scale*offset)) * depth) + delay; + }; + std::generate_n(delays, todo, gen_lfo); +} + +void GetSinusoidDelays(ALint *delays, const ALsizei start_offset, const ALsizei lfo_range, + const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, const ALsizei todo) +{ + ASSUME(start_offset >= 0); + ASSUME(lfo_range > 0); + ASSUME(todo > 0); + + ALsizei offset{start_offset}; + auto gen_lfo = [&offset,lfo_range,lfo_scale,depth,delay]() -> ALint + { + ASSUME(delay >= 0); + offset = (offset+1)%lfo_range; + return fastf2i(std::sin(lfo_scale*offset) * depth) + delay; + }; + std::generate_n(delays, todo, gen_lfo); +} + +struct ChorusState final : public EffectState { + al::vector mSampleBuffer; + ALsizei mOffset{0}; + + ALsizei mLfoOffset{0}; + ALsizei mLfoRange{1}; + ALfloat mLfoScale{0.0f}; + ALint mLfoDisp{0}; + + /* Gains for left and right sides */ + struct { + ALfloat Current[MAX_OUTPUT_CHANNELS]{}; + ALfloat Target[MAX_OUTPUT_CHANNELS]{}; + } mGains[2]; + + /* effect parameters */ + WaveForm mWaveform{}; + ALint mDelay{0}; + ALfloat mDepth{0.0f}; + ALfloat mFeedback{0.0f}; + + + ALboolean deviceUpdate(const ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + + DEF_NEWDEL(ChorusState) +}; + +ALboolean ChorusState::deviceUpdate(const ALCdevice *Device) +{ + const ALfloat max_delay = maxf(AL_CHORUS_MAX_DELAY, AL_FLANGER_MAX_DELAY); + size_t maxlen; + + maxlen = NextPowerOf2(float2int(max_delay*2.0f*Device->Frequency) + 1u); + if(maxlen <= 0) return AL_FALSE; + + if(maxlen != mSampleBuffer.size()) + { + mSampleBuffer.resize(maxlen); + mSampleBuffer.shrink_to_fit(); + } + + std::fill(mSampleBuffer.begin(), mSampleBuffer.end(), 0.0f); + for(auto &e : mGains) + { + std::fill(std::begin(e.Current), std::end(e.Current), 0.0f); + std::fill(std::begin(e.Target), std::end(e.Target), 0.0f); + } + + return AL_TRUE; +} + +void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, const EffectProps *props, const EffectTarget target) +{ + static constexpr ALsizei mindelay = MAX_RESAMPLE_PADDING << FRACTIONBITS; + + switch(props->Chorus.Waveform) + { + case AL_CHORUS_WAVEFORM_TRIANGLE: + mWaveform = WaveForm::Triangle; + break; + case AL_CHORUS_WAVEFORM_SINUSOID: + mWaveform = WaveForm::Sinusoid; + break; + } + + /* The LFO depth is scaled to be relative to the sample delay. Clamp the + * delay and depth to allow enough padding for resampling. + */ + const ALCdevice *device{Context->Device}; + const auto frequency = static_cast(device->Frequency); + mDelay = maxi(float2int(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f), mindelay); + mDepth = minf(props->Chorus.Depth * mDelay, static_cast(mDelay - mindelay)); + + mFeedback = props->Chorus.Feedback; + + /* Gains for left and right sides */ + ALfloat coeffs[2][MAX_AMBI_CHANNELS]; + CalcDirectionCoeffs({-1.0f, 0.0f, 0.0f}, 0.0f, coeffs[0]); + CalcDirectionCoeffs({ 1.0f, 0.0f, 0.0f}, 0.0f, coeffs[1]); + + mOutTarget = target.Main->Buffer; + ComputePanGains(target.Main, coeffs[0], Slot->Params.Gain, mGains[0].Target); + ComputePanGains(target.Main, coeffs[1], Slot->Params.Gain, mGains[1].Target); + + ALfloat rate{props->Chorus.Rate}; + if(!(rate > 0.0f)) + { + mLfoOffset = 0; + mLfoRange = 1; + mLfoScale = 0.0f; + mLfoDisp = 0; + } + else + { + /* Calculate LFO coefficient (number of samples per cycle). Limit the + * max range to avoid overflow when calculating the displacement. + */ + ALsizei lfo_range = float2int(minf(frequency/rate + 0.5f, static_cast(INT_MAX/360 - 180))); + + mLfoOffset = float2int(static_cast(mLfoOffset)/mLfoRange*lfo_range + 0.5f) % lfo_range; + mLfoRange = lfo_range; + switch(mWaveform) + { + case WaveForm::Triangle: + mLfoScale = 4.0f / mLfoRange; + break; + case WaveForm::Sinusoid: + mLfoScale = al::MathDefs::Tau() / mLfoRange; + break; + } + + /* Calculate lfo phase displacement */ + ALint phase{props->Chorus.Phase}; + if(phase < 0) phase = 360 + phase; + mLfoDisp = (mLfoRange*phase + 180) / 360; + } +} + +void ChorusState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) +{ + const auto bufmask = static_cast(mSampleBuffer.size()-1); + const ALfloat feedback{mFeedback}; + const ALsizei avgdelay{(mDelay + (FRACTIONONE>>1)) >> FRACTIONBITS}; + ALfloat *RESTRICT delaybuf{mSampleBuffer.data()}; + ALsizei offset{mOffset}; + + for(ALsizei base{0};base < samplesToDo;) + { + const ALsizei todo = mini(256, samplesToDo-base); + ALint moddelays[2][256]; + alignas(16) ALfloat temps[2][256]; + + if(mWaveform == WaveForm::Sinusoid) + { + GetSinusoidDelays(moddelays[0], mLfoOffset, mLfoRange, mLfoScale, mDepth, mDelay, + todo); + GetSinusoidDelays(moddelays[1], (mLfoOffset+mLfoDisp)%mLfoRange, mLfoRange, mLfoScale, + mDepth, mDelay, todo); + } + else /*if(mWaveform == WaveForm::Triangle)*/ + { + GetTriangleDelays(moddelays[0], mLfoOffset, mLfoRange, mLfoScale, mDepth, mDelay, + todo); + GetTriangleDelays(moddelays[1], (mLfoOffset+mLfoDisp)%mLfoRange, mLfoRange, mLfoScale, + mDepth, mDelay, todo); + } + mLfoOffset = (mLfoOffset+todo) % mLfoRange; + + for(ALsizei i{0};i < todo;i++) + { + // Feed the buffer's input first (necessary for delays < 1). + delaybuf[offset&bufmask] = samplesIn[0][base+i]; + + // Tap for the left output. + ALint delay{offset - (moddelays[0][i]>>FRACTIONBITS)}; + ALfloat mu{(moddelays[0][i]&FRACTIONMASK) * (1.0f/FRACTIONONE)}; + temps[0][i] = cubic(delaybuf[(delay+1) & bufmask], delaybuf[(delay ) & bufmask], + delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask], + mu); + + // Tap for the right output. + delay = offset - (moddelays[1][i]>>FRACTIONBITS); + mu = (moddelays[1][i]&FRACTIONMASK) * (1.0f/FRACTIONONE); + temps[1][i] = cubic(delaybuf[(delay+1) & bufmask], delaybuf[(delay ) & bufmask], + delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask], + mu); + + // Accumulate feedback from the average delay of the taps. + delaybuf[offset&bufmask] += delaybuf[(offset-avgdelay) & bufmask] * feedback; + offset++; + } + + for(ALsizei c{0};c < 2;c++) + MixSamples(temps[c], samplesOut, mGains[c].Current, mGains[c].Target, samplesToDo-base, + base, todo); + + base += todo; + } + + mOffset = offset; +} + + +void Chorus_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val) +{ + switch(param) + { + case AL_CHORUS_WAVEFORM: + if(!(val >= AL_CHORUS_MIN_WAVEFORM && val <= AL_CHORUS_MAX_WAVEFORM)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid chorus waveform"); + props->Chorus.Waveform = val; + break; + + case AL_CHORUS_PHASE: + if(!(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus phase out of range"); + props->Chorus.Phase = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param); + } +} +void Chorus_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) +{ Chorus_setParami(props, context, param, vals[0]); } +void Chorus_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_CHORUS_RATE: + if(!(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus rate out of range"); + props->Chorus.Rate = val; + break; + + case AL_CHORUS_DEPTH: + if(!(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus depth out of range"); + props->Chorus.Depth = val; + break; + + case AL_CHORUS_FEEDBACK: + if(!(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus feedback out of range"); + props->Chorus.Feedback = val; + break; + + case AL_CHORUS_DELAY: + if(!(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus delay out of range"); + props->Chorus.Delay = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param); + } +} +void Chorus_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) +{ Chorus_setParamf(props, context, param, vals[0]); } + +void Chorus_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val) +{ + switch(param) + { + case AL_CHORUS_WAVEFORM: + *val = props->Chorus.Waveform; + break; + + case AL_CHORUS_PHASE: + *val = props->Chorus.Phase; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param); + } +} +void Chorus_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) +{ Chorus_getParami(props, context, param, vals); } +void Chorus_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_CHORUS_RATE: + *val = props->Chorus.Rate; + break; + + case AL_CHORUS_DEPTH: + *val = props->Chorus.Depth; + break; + + case AL_CHORUS_FEEDBACK: + *val = props->Chorus.Feedback; + break; + + case AL_CHORUS_DELAY: + *val = props->Chorus.Delay; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param); + } +} +void Chorus_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) +{ Chorus_getParamf(props, context, param, vals); } + +DEFINE_ALEFFECT_VTABLE(Chorus); + + +struct ChorusStateFactory final : public EffectStateFactory { + EffectState *create() override { return new ChorusState{}; } + EffectProps getDefaultProps() const noexcept override; + const EffectVtable *getEffectVtable() const noexcept override { return &Chorus_vtable; } +}; + +EffectProps ChorusStateFactory::getDefaultProps() const noexcept +{ + EffectProps props{}; + props.Chorus.Waveform = AL_CHORUS_DEFAULT_WAVEFORM; + props.Chorus.Phase = AL_CHORUS_DEFAULT_PHASE; + props.Chorus.Rate = AL_CHORUS_DEFAULT_RATE; + props.Chorus.Depth = AL_CHORUS_DEFAULT_DEPTH; + props.Chorus.Feedback = AL_CHORUS_DEFAULT_FEEDBACK; + props.Chorus.Delay = AL_CHORUS_DEFAULT_DELAY; + return props; +} + + +void Flanger_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val) +{ + switch(param) + { + case AL_FLANGER_WAVEFORM: + if(!(val >= AL_FLANGER_MIN_WAVEFORM && val <= AL_FLANGER_MAX_WAVEFORM)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid flanger waveform"); + props->Chorus.Waveform = val; + break; + + case AL_FLANGER_PHASE: + if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger phase out of range"); + props->Chorus.Phase = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param); + } +} +void Flanger_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) +{ Flanger_setParami(props, context, param, vals[0]); } +void Flanger_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_FLANGER_RATE: + if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger rate out of range"); + props->Chorus.Rate = val; + break; + + case AL_FLANGER_DEPTH: + if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger depth out of range"); + props->Chorus.Depth = val; + break; + + case AL_FLANGER_FEEDBACK: + if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger feedback out of range"); + props->Chorus.Feedback = val; + break; + + case AL_FLANGER_DELAY: + if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger delay out of range"); + props->Chorus.Delay = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param); + } +} +void Flanger_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) +{ Flanger_setParamf(props, context, param, vals[0]); } + +void Flanger_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val) +{ + switch(param) + { + case AL_FLANGER_WAVEFORM: + *val = props->Chorus.Waveform; + break; + + case AL_FLANGER_PHASE: + *val = props->Chorus.Phase; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param); + } +} +void Flanger_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) +{ Flanger_getParami(props, context, param, vals); } +void Flanger_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_FLANGER_RATE: + *val = props->Chorus.Rate; + break; + + case AL_FLANGER_DEPTH: + *val = props->Chorus.Depth; + break; + + case AL_FLANGER_FEEDBACK: + *val = props->Chorus.Feedback; + break; + + case AL_FLANGER_DELAY: + *val = props->Chorus.Delay; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param); + } +} +void Flanger_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) +{ Flanger_getParamf(props, context, param, vals); } + +DEFINE_ALEFFECT_VTABLE(Flanger); + + +/* Flanger is basically a chorus with a really short delay. They can both use + * the same processing functions, so piggyback flanger on the chorus functions. + */ +struct FlangerStateFactory final : public EffectStateFactory { + EffectState *create() override { return new ChorusState{}; } + EffectProps getDefaultProps() const noexcept override; + const EffectVtable *getEffectVtable() const noexcept override { return &Flanger_vtable; } +}; + +EffectProps FlangerStateFactory::getDefaultProps() const noexcept +{ + EffectProps props{}; + props.Chorus.Waveform = AL_FLANGER_DEFAULT_WAVEFORM; + props.Chorus.Phase = AL_FLANGER_DEFAULT_PHASE; + props.Chorus.Rate = AL_FLANGER_DEFAULT_RATE; + props.Chorus.Depth = AL_FLANGER_DEFAULT_DEPTH; + props.Chorus.Feedback = AL_FLANGER_DEFAULT_FEEDBACK; + props.Chorus.Delay = AL_FLANGER_DEFAULT_DELAY; + return props; +} + +} // namespace + +EffectStateFactory *ChorusStateFactory_getFactory() +{ + static ChorusStateFactory ChorusFactory{}; + return &ChorusFactory; +} + +EffectStateFactory *FlangerStateFactory_getFactory() +{ + static FlangerStateFactory FlangerFactory{}; + return &FlangerFactory; +} diff --git a/alc/effects/compressor.cpp b/alc/effects/compressor.cpp new file mode 100644 index 00000000..4a487097 --- /dev/null +++ b/alc/effects/compressor.cpp @@ -0,0 +1,222 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2013 by Anis A. Hireche + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include + +#include "alcmain.h" +#include "alcontext.h" +#include "alu.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "vecmat.h" + + +namespace { + +#define AMP_ENVELOPE_MIN 0.5f +#define AMP_ENVELOPE_MAX 2.0f + +#define ATTACK_TIME 0.1f /* 100ms to rise from min to max */ +#define RELEASE_TIME 0.2f /* 200ms to drop from max to min */ + + +struct CompressorState final : public EffectState { + /* Effect gains for each channel */ + ALfloat mGain[MAX_AMBI_CHANNELS][MAX_OUTPUT_CHANNELS]{}; + + /* Effect parameters */ + ALboolean mEnabled{AL_TRUE}; + ALfloat mAttackMult{1.0f}; + ALfloat mReleaseMult{1.0f}; + ALfloat mEnvFollower{1.0f}; + + + ALboolean deviceUpdate(const ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + + DEF_NEWDEL(CompressorState) +}; + +ALboolean CompressorState::deviceUpdate(const ALCdevice *device) +{ + /* Number of samples to do a full attack and release (non-integer sample + * counts are okay). + */ + const ALfloat attackCount = static_cast(device->Frequency) * ATTACK_TIME; + const ALfloat releaseCount = static_cast(device->Frequency) * RELEASE_TIME; + + /* Calculate per-sample multipliers to attack and release at the desired + * rates. + */ + mAttackMult = std::pow(AMP_ENVELOPE_MAX/AMP_ENVELOPE_MIN, 1.0f/attackCount); + mReleaseMult = std::pow(AMP_ENVELOPE_MIN/AMP_ENVELOPE_MAX, 1.0f/releaseCount); + + return AL_TRUE; +} + +void CompressorState::update(const ALCcontext*, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) +{ + mEnabled = props->Compressor.OnOff; + + mOutTarget = target.Main->Buffer; + for(size_t i{0u};i < slot->Wet.Buffer.size();++i) + { + auto coeffs = GetAmbiIdentityRow(i); + ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mGain[i]); + } +} + +void CompressorState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) +{ + for(ALsizei base{0};base < samplesToDo;) + { + ALfloat gains[256]; + const ALsizei td{mini(256, samplesToDo-base)}; + + /* Generate the per-sample gains from the signal envelope. */ + ALfloat env{mEnvFollower}; + if(mEnabled) + { + for(ALsizei i{0};i < td;++i) + { + /* Clamp the absolute amplitude to the defined envelope limits, + * then attack or release the envelope to reach it. + */ + const ALfloat amplitude{clampf(std::fabs(samplesIn[0][base+i]), AMP_ENVELOPE_MIN, + AMP_ENVELOPE_MAX)}; + if(amplitude > env) + env = minf(env*mAttackMult, amplitude); + else if(amplitude < env) + env = maxf(env*mReleaseMult, amplitude); + + /* Apply the reciprocal of the envelope to normalize the volume + * (compress the dynamic range). + */ + gains[i] = 1.0f / env; + } + } + else + { + /* Same as above, except the amplitude is forced to 1. This helps + * ensure smooth gain changes when the compressor is turned on and + * off. + */ + for(ALsizei i{0};i < td;++i) + { + const ALfloat amplitude{1.0f}; + if(amplitude > env) + env = minf(env*mAttackMult, amplitude); + else if(amplitude < env) + env = maxf(env*mReleaseMult, amplitude); + + gains[i] = 1.0f / env; + } + } + mEnvFollower = env; + + /* Now compress the signal amplitude to output. */ + ASSUME(numInput > 0); + for(ALsizei j{0};j < numInput;j++) + { + const ALfloat *outgains{mGain[j]}; + for(FloatBufferLine &output : samplesOut) + { + const ALfloat gain{*(outgains++)}; + if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + for(ALsizei i{0};i < td;i++) + output[base+i] += samplesIn[j][base+i] * gains[i] * gain; + } + } + + base += td; + } +} + + +void Compressor_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val) +{ + switch(param) + { + case AL_COMPRESSOR_ONOFF: + if(!(val >= AL_COMPRESSOR_MIN_ONOFF && val <= AL_COMPRESSOR_MAX_ONOFF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Compressor state out of range"); + props->Compressor.OnOff = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid compressor integer property 0x%04x", + param); + } +} +void Compressor_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) +{ Compressor_setParami(props, context, param, vals[0]); } +void Compressor_setParamf(EffectProps*, ALCcontext *context, ALenum param, ALfloat) +{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param); } +void Compressor_setParamfv(EffectProps*, ALCcontext *context, ALenum param, const ALfloat*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float-vector property 0x%04x", param); } + +void Compressor_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val) +{ + switch(param) + { + case AL_COMPRESSOR_ONOFF: + *val = props->Compressor.OnOff; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid compressor integer property 0x%04x", + param); + } +} +void Compressor_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) +{ Compressor_getParami(props, context, param, vals); } +void Compressor_getParamf(const EffectProps*, ALCcontext *context, ALenum param, ALfloat*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param); } +void Compressor_getParamfv(const EffectProps*, ALCcontext *context, ALenum param, ALfloat*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float-vector property 0x%04x", param); } + +DEFINE_ALEFFECT_VTABLE(Compressor); + + +struct CompressorStateFactory final : public EffectStateFactory { + EffectState *create() override { return new CompressorState{}; } + EffectProps getDefaultProps() const noexcept override; + const EffectVtable *getEffectVtable() const noexcept override { return &Compressor_vtable; } +}; + +EffectProps CompressorStateFactory::getDefaultProps() const noexcept +{ + EffectProps props{}; + props.Compressor.OnOff = AL_COMPRESSOR_DEFAULT_ONOFF; + return props; +} + +} // namespace + +EffectStateFactory *CompressorStateFactory_getFactory() +{ + static CompressorStateFactory CompressorFactory{}; + return &CompressorFactory; +} diff --git a/alc/effects/dedicated.cpp b/alc/effects/dedicated.cpp new file mode 100644 index 00000000..b31b3750 --- /dev/null +++ b/alc/effects/dedicated.cpp @@ -0,0 +1,159 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2011 by Chris Robinson. + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include "alcmain.h" +#include "alcontext.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" + + +namespace { + +struct DedicatedState final : public EffectState { + ALfloat mCurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat mTargetGains[MAX_OUTPUT_CHANNELS]; + + + ALboolean deviceUpdate(const ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + + DEF_NEWDEL(DedicatedState) +}; + +ALboolean DedicatedState::deviceUpdate(const ALCdevice*) +{ + std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f); + return AL_TRUE; +} + +void DedicatedState::update(const ALCcontext*, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) +{ + std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f); + + const ALfloat Gain{slot->Params.Gain * props->Dedicated.Gain}; + + if(slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) + { + const int idx{!target.RealOut ? -1 : GetChannelIdxByName(*target.RealOut, LFE)}; + if(idx != -1) + { + mOutTarget = target.RealOut->Buffer; + mTargetGains[idx] = Gain; + } + } + else if(slot->Params.EffectType == AL_EFFECT_DEDICATED_DIALOGUE) + { + /* Dialog goes to the front-center speaker if it exists, otherwise it + * plays from the front-center location. */ + const int idx{!target.RealOut ? -1 : GetChannelIdxByName(*target.RealOut, FrontCenter)}; + if(idx != -1) + { + mOutTarget = target.RealOut->Buffer; + mTargetGains[idx] = Gain; + } + else + { + ALfloat coeffs[MAX_AMBI_CHANNELS]; + CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); + + mOutTarget = target.Main->Buffer; + ComputePanGains(target.Main, coeffs, Gain, mTargetGains); + } + } +} + +void DedicatedState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) +{ + MixSamples(samplesIn[0].data(), samplesOut, mCurrentGains, mTargetGains, samplesToDo, 0, + samplesToDo); +} + + +void Dedicated_setParami(EffectProps*, ALCcontext *context, ALenum param, ALint) +{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param); } +void Dedicated_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x", param); } +void Dedicated_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_DEDICATED_GAIN: + if(!(val >= 0.0f && std::isfinite(val))) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Dedicated gain out of range"); + props->Dedicated.Gain = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param); + } +} +void Dedicated_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) +{ Dedicated_setParamf(props, context, param, vals[0]); } + +void Dedicated_getParami(const EffectProps*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param); } +void Dedicated_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x", param); } +void Dedicated_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_DEDICATED_GAIN: + *val = props->Dedicated.Gain; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param); + } +} +void Dedicated_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) +{ Dedicated_getParamf(props, context, param, vals); } + +DEFINE_ALEFFECT_VTABLE(Dedicated); + + +struct DedicatedStateFactory final : public EffectStateFactory { + EffectState *create() override { return new DedicatedState{}; } + EffectProps getDefaultProps() const noexcept override; + const EffectVtable *getEffectVtable() const noexcept override { return &Dedicated_vtable; } +}; + +EffectProps DedicatedStateFactory::getDefaultProps() const noexcept +{ + EffectProps props{}; + props.Dedicated.Gain = 1.0f; + return props; +} + +} // namespace + +EffectStateFactory *DedicatedStateFactory_getFactory() +{ + static DedicatedStateFactory DedicatedFactory{}; + return &DedicatedFactory; +} diff --git a/alc/effects/distortion.cpp b/alc/effects/distortion.cpp new file mode 100644 index 00000000..59557395 --- /dev/null +++ b/alc/effects/distortion.cpp @@ -0,0 +1,269 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2013 by Mike Gorchak + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include + +#include "alcmain.h" +#include "alcontext.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" +#include "filters/biquad.h" + + +namespace { + +struct DistortionState final : public EffectState { + /* Effect gains for each channel */ + ALfloat mGain[MAX_OUTPUT_CHANNELS]{}; + + /* Effect parameters */ + BiquadFilter mLowpass; + BiquadFilter mBandpass; + ALfloat mAttenuation{}; + ALfloat mEdgeCoeff{}; + + ALfloat mBuffer[2][BUFFERSIZE]{}; + + + ALboolean deviceUpdate(const ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + + DEF_NEWDEL(DistortionState) +}; + +ALboolean DistortionState::deviceUpdate(const ALCdevice*) +{ + mLowpass.clear(); + mBandpass.clear(); + return AL_TRUE; +} + +void DistortionState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) +{ + const ALCdevice *device{context->Device}; + + /* Store waveshaper edge settings. */ + const ALfloat edge{ + minf(std::sin(al::MathDefs::Pi()*0.5f * props->Distortion.Edge), 0.99f)}; + mEdgeCoeff = 2.0f * edge / (1.0f-edge); + + ALfloat cutoff{props->Distortion.LowpassCutoff}; + /* Bandwidth value is constant in octaves. */ + ALfloat bandwidth{(cutoff / 2.0f) / (cutoff * 0.67f)}; + /* Multiply sampling frequency by the amount of oversampling done during + * processing. + */ + auto frequency = static_cast(device->Frequency); + mLowpass.setParams(BiquadType::LowPass, 1.0f, cutoff / (frequency*4.0f), + mLowpass.rcpQFromBandwidth(cutoff / (frequency*4.0f), bandwidth)); + + cutoff = props->Distortion.EQCenter; + /* Convert bandwidth in Hz to octaves. */ + bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f); + mBandpass.setParams(BiquadType::BandPass, 1.0f, cutoff / (frequency*4.0f), + mBandpass.rcpQFromBandwidth(cutoff / (frequency*4.0f), bandwidth)); + + ALfloat coeffs[MAX_AMBI_CHANNELS]; + CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); + + mOutTarget = target.Main->Buffer; + ComputePanGains(target.Main, coeffs, slot->Params.Gain*props->Distortion.Gain, mGain); +} + +void DistortionState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) +{ + const ALfloat fc{mEdgeCoeff}; + for(ALsizei base{0};base < samplesToDo;) + { + /* Perform 4x oversampling to avoid aliasing. Oversampling greatly + * improves distortion quality and allows to implement lowpass and + * bandpass filters using high frequencies, at which classic IIR + * filters became unstable. + */ + ALsizei todo{mini(BUFFERSIZE, (samplesToDo-base) * 4)}; + + /* Fill oversample buffer using zero stuffing. Multiply the sample by + * the amount of oversampling to maintain the signal's power. + */ + for(ALsizei i{0};i < todo;i++) + mBuffer[0][i] = !(i&3) ? samplesIn[0][(i>>2)+base] * 4.0f : 0.0f; + + /* First step, do lowpass filtering of original signal. Additionally + * perform buffer interpolation and lowpass cutoff for oversampling + * (which is fortunately first step of distortion). So combine three + * operations into the one. + */ + mLowpass.process(mBuffer[1], mBuffer[0], todo); + + /* Second step, do distortion using waveshaper function to emulate + * signal processing during tube overdriving. Three steps of + * waveshaping are intended to modify waveform without boost/clipping/ + * attenuation process. + */ + for(ALsizei i{0};i < todo;i++) + { + ALfloat smp{mBuffer[1][i]}; + + smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)); + smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)) * -1.0f; + smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)); + + mBuffer[0][i] = smp; + } + + /* Third step, do bandpass filtering of distorted signal. */ + mBandpass.process(mBuffer[1], mBuffer[0], todo); + + todo >>= 2; + const ALfloat *outgains{mGain}; + for(FloatBufferLine &output : samplesOut) + { + /* Fourth step, final, do attenuation and perform decimation, + * storing only one sample out of four. + */ + const ALfloat gain{*(outgains++)}; + if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + for(ALsizei i{0};i < todo;i++) + output[base+i] += gain * mBuffer[1][i*4]; + } + + base += todo; + } +} + + +void Distortion_setParami(EffectProps*, ALCcontext *context, ALenum param, ALint) +{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param); } +void Distortion_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x", param); } +void Distortion_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_DISTORTION_EDGE: + if(!(val >= AL_DISTORTION_MIN_EDGE && val <= AL_DISTORTION_MAX_EDGE)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion edge out of range"); + props->Distortion.Edge = val; + break; + + case AL_DISTORTION_GAIN: + if(!(val >= AL_DISTORTION_MIN_GAIN && val <= AL_DISTORTION_MAX_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion gain out of range"); + props->Distortion.Gain = val; + break; + + case AL_DISTORTION_LOWPASS_CUTOFF: + if(!(val >= AL_DISTORTION_MIN_LOWPASS_CUTOFF && val <= AL_DISTORTION_MAX_LOWPASS_CUTOFF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion low-pass cutoff out of range"); + props->Distortion.LowpassCutoff = val; + break; + + case AL_DISTORTION_EQCENTER: + if(!(val >= AL_DISTORTION_MIN_EQCENTER && val <= AL_DISTORTION_MAX_EQCENTER)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion EQ center out of range"); + props->Distortion.EQCenter = val; + break; + + case AL_DISTORTION_EQBANDWIDTH: + if(!(val >= AL_DISTORTION_MIN_EQBANDWIDTH && val <= AL_DISTORTION_MAX_EQBANDWIDTH)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion EQ bandwidth out of range"); + props->Distortion.EQBandwidth = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", + param); + } +} +void Distortion_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) +{ Distortion_setParamf(props, context, param, vals[0]); } + +void Distortion_getParami(const EffectProps*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param); } +void Distortion_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x", param); } +void Distortion_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_DISTORTION_EDGE: + *val = props->Distortion.Edge; + break; + + case AL_DISTORTION_GAIN: + *val = props->Distortion.Gain; + break; + + case AL_DISTORTION_LOWPASS_CUTOFF: + *val = props->Distortion.LowpassCutoff; + break; + + case AL_DISTORTION_EQCENTER: + *val = props->Distortion.EQCenter; + break; + + case AL_DISTORTION_EQBANDWIDTH: + *val = props->Distortion.EQBandwidth; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", + param); + } +} +void Distortion_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) +{ Distortion_getParamf(props, context, param, vals); } + +DEFINE_ALEFFECT_VTABLE(Distortion); + + +struct DistortionStateFactory final : public EffectStateFactory { + EffectState *create() override { return new DistortionState{}; } + EffectProps getDefaultProps() const noexcept override; + const EffectVtable *getEffectVtable() const noexcept override { return &Distortion_vtable; } +}; + +EffectProps DistortionStateFactory::getDefaultProps() const noexcept +{ + EffectProps props{}; + props.Distortion.Edge = AL_DISTORTION_DEFAULT_EDGE; + props.Distortion.Gain = AL_DISTORTION_DEFAULT_GAIN; + props.Distortion.LowpassCutoff = AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF; + props.Distortion.EQCenter = AL_DISTORTION_DEFAULT_EQCENTER; + props.Distortion.EQBandwidth = AL_DISTORTION_DEFAULT_EQBANDWIDTH; + return props; +} + +} // namespace + +EffectStateFactory *DistortionStateFactory_getFactory() +{ + static DistortionStateFactory DistortionFactory{}; + return &DistortionFactory; +} diff --git a/alc/effects/echo.cpp b/alc/effects/echo.cpp new file mode 100644 index 00000000..c10f2eb2 --- /dev/null +++ b/alc/effects/echo.cpp @@ -0,0 +1,271 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2009 by Chris Robinson. + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include + +#include "alcmain.h" +#include "alcontext.h" +#include "alFilter.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" +#include "filters/biquad.h" +#include "vector.h" + + +namespace { + +struct EchoState final : public EffectState { + al::vector mSampleBuffer; + + // The echo is two tap. The delay is the number of samples from before the + // current offset + struct { + ALsizei delay{0}; + } mTap[2]; + ALsizei mOffset{0}; + + /* The panning gains for the two taps */ + struct { + ALfloat Current[MAX_OUTPUT_CHANNELS]{}; + ALfloat Target[MAX_OUTPUT_CHANNELS]{}; + } mGains[2]; + + BiquadFilter mFilter; + ALfloat mFeedGain{0.0f}; + + alignas(16) ALfloat mTempBuffer[2][BUFFERSIZE]; + + ALboolean deviceUpdate(const ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + + DEF_NEWDEL(EchoState) +}; + +ALboolean EchoState::deviceUpdate(const ALCdevice *Device) +{ + ALuint maxlen; + + // Use the next power of 2 for the buffer length, so the tap offsets can be + // wrapped using a mask instead of a modulo + maxlen = float2int(AL_ECHO_MAX_DELAY*Device->Frequency + 0.5f) + + float2int(AL_ECHO_MAX_LRDELAY*Device->Frequency + 0.5f); + maxlen = NextPowerOf2(maxlen); + if(maxlen <= 0) return AL_FALSE; + + if(maxlen != mSampleBuffer.size()) + { + mSampleBuffer.resize(maxlen); + mSampleBuffer.shrink_to_fit(); + } + + std::fill(mSampleBuffer.begin(), mSampleBuffer.end(), 0.0f); + for(auto &e : mGains) + { + std::fill(std::begin(e.Current), std::end(e.Current), 0.0f); + std::fill(std::begin(e.Target), std::end(e.Target), 0.0f); + } + + return AL_TRUE; +} + +void EchoState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) +{ + const ALCdevice *device = context->Device; + const auto frequency = static_cast(device->Frequency); + + mTap[0].delay = maxi(float2int(props->Echo.Delay*frequency + 0.5f), 1); + mTap[1].delay = float2int(props->Echo.LRDelay*frequency + 0.5f) + mTap[0].delay; + + const ALfloat gainhf{maxf(1.0f - props->Echo.Damping, 0.0625f)}; /* Limit -24dB */ + mFilter.setParams(BiquadType::HighShelf, gainhf, LOWPASSFREQREF/frequency, + mFilter.rcpQFromSlope(gainhf, 1.0f)); + + mFeedGain = props->Echo.Feedback; + + /* Convert echo spread (where 0 = center, +/-1 = sides) to angle. */ + const ALfloat angle{std::asin(props->Echo.Spread)}; + + ALfloat coeffs[2][MAX_AMBI_CHANNELS]; + CalcAngleCoeffs(-angle, 0.0f, 0.0f, coeffs[0]); + CalcAngleCoeffs( angle, 0.0f, 0.0f, coeffs[1]); + + mOutTarget = target.Main->Buffer; + ComputePanGains(target.Main, coeffs[0], slot->Params.Gain, mGains[0].Target); + ComputePanGains(target.Main, coeffs[1], slot->Params.Gain, mGains[1].Target); +} + +void EchoState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) +{ + const auto mask = static_cast(mSampleBuffer.size()-1); + ALfloat *RESTRICT delaybuf{mSampleBuffer.data()}; + ALsizei offset{mOffset}; + ALsizei tap1{offset - mTap[0].delay}; + ALsizei tap2{offset - mTap[1].delay}; + ALfloat z1, z2; + + ASSUME(samplesToDo > 0); + ASSUME(mask > 0); + + std::tie(z1, z2) = mFilter.getComponents(); + for(ALsizei i{0};i < samplesToDo;) + { + offset &= mask; + tap1 &= mask; + tap2 &= mask; + + ALsizei td{mini(mask+1 - maxi(offset, maxi(tap1, tap2)), samplesToDo-i)}; + do { + /* Feed the delay buffer's input first. */ + delaybuf[offset] = samplesIn[0][i]; + + /* Get delayed output from the first and second taps. Use the + * second tap for feedback. + */ + mTempBuffer[0][i] = delaybuf[tap1++]; + mTempBuffer[1][i] = delaybuf[tap2++]; + const float feedb{mTempBuffer[1][i++]}; + + /* Add feedback to the delay buffer with damping and attenuation. */ + delaybuf[offset++] += mFilter.processOne(feedb, z1, z2) * mFeedGain; + } while(--td); + } + mFilter.setComponents(z1, z2); + mOffset = offset; + + for(ALsizei c{0};c < 2;c++) + MixSamples(mTempBuffer[c], samplesOut, mGains[c].Current, mGains[c].Target, samplesToDo, 0, + samplesToDo); +} + + +void Echo_setParami(EffectProps*, ALCcontext *context, ALenum param, ALint) +{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param); } +void Echo_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param); } +void Echo_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_ECHO_DELAY: + if(!(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo delay out of range"); + props->Echo.Delay = val; + break; + + case AL_ECHO_LRDELAY: + if(!(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo LR delay out of range"); + props->Echo.LRDelay = val; + break; + + case AL_ECHO_DAMPING: + if(!(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo damping out of range"); + props->Echo.Damping = val; + break; + + case AL_ECHO_FEEDBACK: + if(!(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo feedback out of range"); + props->Echo.Feedback = val; + break; + + case AL_ECHO_SPREAD: + if(!(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo spread out of range"); + props->Echo.Spread = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param); + } +} +void Echo_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) +{ Echo_setParamf(props, context, param, vals[0]); } + +void Echo_getParami(const EffectProps*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param); } +void Echo_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param); } +void Echo_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_ECHO_DELAY: + *val = props->Echo.Delay; + break; + + case AL_ECHO_LRDELAY: + *val = props->Echo.LRDelay; + break; + + case AL_ECHO_DAMPING: + *val = props->Echo.Damping; + break; + + case AL_ECHO_FEEDBACK: + *val = props->Echo.Feedback; + break; + + case AL_ECHO_SPREAD: + *val = props->Echo.Spread; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param); + } +} +void Echo_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) +{ Echo_getParamf(props, context, param, vals); } + +DEFINE_ALEFFECT_VTABLE(Echo); + + +struct EchoStateFactory final : public EffectStateFactory { + EffectState *create() override { return new EchoState{}; } + EffectProps getDefaultProps() const noexcept override; + const EffectVtable *getEffectVtable() const noexcept override { return &Echo_vtable; } +}; + +EffectProps EchoStateFactory::getDefaultProps() const noexcept +{ + EffectProps props{}; + props.Echo.Delay = AL_ECHO_DEFAULT_DELAY; + props.Echo.LRDelay = AL_ECHO_DEFAULT_LRDELAY; + props.Echo.Damping = AL_ECHO_DEFAULT_DAMPING; + props.Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK; + props.Echo.Spread = AL_ECHO_DEFAULT_SPREAD; + return props; +} + +} // namespace + +EffectStateFactory *EchoStateFactory_getFactory() +{ + static EchoStateFactory EchoFactory{}; + return &EchoFactory; +} diff --git a/alc/effects/equalizer.cpp b/alc/effects/equalizer.cpp new file mode 100644 index 00000000..69ab5021 --- /dev/null +++ b/alc/effects/equalizer.cpp @@ -0,0 +1,337 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2013 by Mike Gorchak + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include +#include + +#include "alcmain.h" +#include "alcontext.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" +#include "filters/biquad.h" +#include "vecmat.h" + + +namespace { + +/* The document "Effects Extension Guide.pdf" says that low and high * + * frequencies are cutoff frequencies. This is not fully correct, they * + * are corner frequencies for low and high shelf filters. If they were * + * just cutoff frequencies, there would be no need in cutoff frequency * + * gains, which are present. Documentation for "Creative Proteus X2" * + * software describes 4-band equalizer functionality in a much better * + * way. This equalizer seems to be a predecessor of OpenAL 4-band * + * equalizer. With low and high shelf filters we are able to cutoff * + * frequencies below and/or above corner frequencies using attenuation * + * gains (below 1.0) and amplify all low and/or high frequencies using * + * gains above 1.0. * + * * + * Low-shelf Low Mid Band High Mid Band High-shelf * + * corner center center corner * + * frequency frequency frequency frequency * + * 50Hz..800Hz 200Hz..3000Hz 1000Hz..8000Hz 4000Hz..16000Hz * + * * + * | | | | * + * | | | | * + * B -----+ /--+--\ /--+--\ +----- * + * O |\ | | | | | | /| * + * O | \ - | - - | - / | * + * S + | \ | | | | | | / | * + * T | | | | | | | | | | * + * ---------+---------------+------------------+---------------+-------- * + * C | | | | | | | | | | * + * U - | / | | | | | | \ | * + * T | / - | - - | - \ | * + * O |/ | | | | | | \| * + * F -----+ \--+--/ \--+--/ +----- * + * F | | | | * + * | | | | * + * * + * Gains vary from 0.126 up to 7.943, which means from -18dB attenuation * + * up to +18dB amplification. Band width varies from 0.01 up to 1.0 in * + * octaves for two mid bands. * + * * + * Implementation is based on the "Cookbook formulae for audio EQ biquad * + * filter coefficients" by Robert Bristow-Johnson * + * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */ + + +struct EqualizerState final : public EffectState { + struct { + /* Effect parameters */ + BiquadFilter filter[4]; + + /* Effect gains for each channel */ + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]{}; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]{}; + } mChans[MAX_AMBI_CHANNELS]; + + ALfloat mSampleBuffer[BUFFERSIZE]{}; + + + ALboolean deviceUpdate(const ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + + DEF_NEWDEL(EqualizerState) +}; + +ALboolean EqualizerState::deviceUpdate(const ALCdevice*) +{ + for(auto &e : mChans) + { + std::for_each(std::begin(e.filter), std::end(e.filter), + std::mem_fn(&BiquadFilter::clear)); + std::fill(std::begin(e.CurrentGains), std::end(e.CurrentGains), 0.0f); + } + return AL_TRUE; +} + +void EqualizerState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) +{ + const ALCdevice *device = context->Device; + auto frequency = static_cast(device->Frequency); + ALfloat gain, f0norm; + + /* Calculate coefficients for the each type of filter. Note that the shelf + * filters' gain is for the reference frequency, which is the centerpoint + * of the transition band. + */ + gain = maxf(sqrtf(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */ + f0norm = props->Equalizer.LowCutoff/frequency; + mChans[0].filter[0].setParams(BiquadType::LowShelf, gain, f0norm, + BiquadFilter::rcpQFromSlope(gain, 0.75f)); + + gain = maxf(props->Equalizer.Mid1Gain, 0.0625f); + f0norm = props->Equalizer.Mid1Center/frequency; + mChans[0].filter[1].setParams(BiquadType::Peaking, gain, f0norm, + BiquadFilter::rcpQFromBandwidth(f0norm, props->Equalizer.Mid1Width)); + + gain = maxf(props->Equalizer.Mid2Gain, 0.0625f); + f0norm = props->Equalizer.Mid2Center/frequency; + mChans[0].filter[2].setParams(BiquadType::Peaking, gain, f0norm, + BiquadFilter::rcpQFromBandwidth(f0norm, props->Equalizer.Mid2Width)); + + gain = maxf(sqrtf(props->Equalizer.HighGain), 0.0625f); + f0norm = props->Equalizer.HighCutoff/frequency; + mChans[0].filter[3].setParams(BiquadType::HighShelf, gain, f0norm, + BiquadFilter::rcpQFromSlope(gain, 0.75f)); + + /* Copy the filter coefficients for the other input channels. */ + for(size_t i{1u};i < slot->Wet.Buffer.size();++i) + { + mChans[i].filter[0].copyParamsFrom(mChans[0].filter[0]); + mChans[i].filter[1].copyParamsFrom(mChans[0].filter[1]); + mChans[i].filter[2].copyParamsFrom(mChans[0].filter[2]); + mChans[i].filter[3].copyParamsFrom(mChans[0].filter[3]); + } + + mOutTarget = target.Main->Buffer; + for(size_t i{0u};i < slot->Wet.Buffer.size();++i) + { + auto coeffs = GetAmbiIdentityRow(i); + ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mChans[i].TargetGains); + } +} + +void EqualizerState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) +{ + ASSUME(numInput > 0); + for(ALsizei c{0};c < numInput;c++) + { + mChans[c].filter[0].process(mSampleBuffer, samplesIn[c].data(), samplesToDo); + mChans[c].filter[1].process(mSampleBuffer, mSampleBuffer, samplesToDo); + mChans[c].filter[2].process(mSampleBuffer, mSampleBuffer, samplesToDo); + mChans[c].filter[3].process(mSampleBuffer, mSampleBuffer, samplesToDo); + + MixSamples(mSampleBuffer, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, + samplesToDo, 0, samplesToDo); + } +} + + +void Equalizer_setParami(EffectProps*, ALCcontext *context, ALenum param, ALint) +{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param); } +void Equalizer_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x", param); } +void Equalizer_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_EQUALIZER_LOW_GAIN: + if(!(val >= AL_EQUALIZER_MIN_LOW_GAIN && val <= AL_EQUALIZER_MAX_LOW_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer low-band gain out of range"); + props->Equalizer.LowGain = val; + break; + + case AL_EQUALIZER_LOW_CUTOFF: + if(!(val >= AL_EQUALIZER_MIN_LOW_CUTOFF && val <= AL_EQUALIZER_MAX_LOW_CUTOFF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer low-band cutoff out of range"); + props->Equalizer.LowCutoff = val; + break; + + case AL_EQUALIZER_MID1_GAIN: + if(!(val >= AL_EQUALIZER_MIN_MID1_GAIN && val <= AL_EQUALIZER_MAX_MID1_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band gain out of range"); + props->Equalizer.Mid1Gain = val; + break; + + case AL_EQUALIZER_MID1_CENTER: + if(!(val >= AL_EQUALIZER_MIN_MID1_CENTER && val <= AL_EQUALIZER_MAX_MID1_CENTER)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band center out of range"); + props->Equalizer.Mid1Center = val; + break; + + case AL_EQUALIZER_MID1_WIDTH: + if(!(val >= AL_EQUALIZER_MIN_MID1_WIDTH && val <= AL_EQUALIZER_MAX_MID1_WIDTH)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band width out of range"); + props->Equalizer.Mid1Width = val; + break; + + case AL_EQUALIZER_MID2_GAIN: + if(!(val >= AL_EQUALIZER_MIN_MID2_GAIN && val <= AL_EQUALIZER_MAX_MID2_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band gain out of range"); + props->Equalizer.Mid2Gain = val; + break; + + case AL_EQUALIZER_MID2_CENTER: + if(!(val >= AL_EQUALIZER_MIN_MID2_CENTER && val <= AL_EQUALIZER_MAX_MID2_CENTER)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band center out of range"); + props->Equalizer.Mid2Center = val; + break; + + case AL_EQUALIZER_MID2_WIDTH: + if(!(val >= AL_EQUALIZER_MIN_MID2_WIDTH && val <= AL_EQUALIZER_MAX_MID2_WIDTH)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band width out of range"); + props->Equalizer.Mid2Width = val; + break; + + case AL_EQUALIZER_HIGH_GAIN: + if(!(val >= AL_EQUALIZER_MIN_HIGH_GAIN && val <= AL_EQUALIZER_MAX_HIGH_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer high-band gain out of range"); + props->Equalizer.HighGain = val; + break; + + case AL_EQUALIZER_HIGH_CUTOFF: + if(!(val >= AL_EQUALIZER_MIN_HIGH_CUTOFF && val <= AL_EQUALIZER_MAX_HIGH_CUTOFF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer high-band cutoff out of range"); + props->Equalizer.HighCutoff = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param); + } +} +void Equalizer_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) +{ Equalizer_setParamf(props, context, param, vals[0]); } + +void Equalizer_getParami(const EffectProps*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param); } +void Equalizer_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x", param); } +void Equalizer_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_EQUALIZER_LOW_GAIN: + *val = props->Equalizer.LowGain; + break; + + case AL_EQUALIZER_LOW_CUTOFF: + *val = props->Equalizer.LowCutoff; + break; + + case AL_EQUALIZER_MID1_GAIN: + *val = props->Equalizer.Mid1Gain; + break; + + case AL_EQUALIZER_MID1_CENTER: + *val = props->Equalizer.Mid1Center; + break; + + case AL_EQUALIZER_MID1_WIDTH: + *val = props->Equalizer.Mid1Width; + break; + + case AL_EQUALIZER_MID2_GAIN: + *val = props->Equalizer.Mid2Gain; + break; + + case AL_EQUALIZER_MID2_CENTER: + *val = props->Equalizer.Mid2Center; + break; + + case AL_EQUALIZER_MID2_WIDTH: + *val = props->Equalizer.Mid2Width; + break; + + case AL_EQUALIZER_HIGH_GAIN: + *val = props->Equalizer.HighGain; + break; + + case AL_EQUALIZER_HIGH_CUTOFF: + *val = props->Equalizer.HighCutoff; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param); + } +} +void Equalizer_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) +{ Equalizer_getParamf(props, context, param, vals); } + +DEFINE_ALEFFECT_VTABLE(Equalizer); + + +struct EqualizerStateFactory final : public EffectStateFactory { + EffectState *create() override { return new EqualizerState{}; } + EffectProps getDefaultProps() const noexcept override; + const EffectVtable *getEffectVtable() const noexcept override { return &Equalizer_vtable; } +}; + +EffectProps EqualizerStateFactory::getDefaultProps() const noexcept +{ + EffectProps props{}; + props.Equalizer.LowCutoff = AL_EQUALIZER_DEFAULT_LOW_CUTOFF; + props.Equalizer.LowGain = AL_EQUALIZER_DEFAULT_LOW_GAIN; + props.Equalizer.Mid1Center = AL_EQUALIZER_DEFAULT_MID1_CENTER; + props.Equalizer.Mid1Gain = AL_EQUALIZER_DEFAULT_MID1_GAIN; + props.Equalizer.Mid1Width = AL_EQUALIZER_DEFAULT_MID1_WIDTH; + props.Equalizer.Mid2Center = AL_EQUALIZER_DEFAULT_MID2_CENTER; + props.Equalizer.Mid2Gain = AL_EQUALIZER_DEFAULT_MID2_GAIN; + props.Equalizer.Mid2Width = AL_EQUALIZER_DEFAULT_MID2_WIDTH; + props.Equalizer.HighCutoff = AL_EQUALIZER_DEFAULT_HIGH_CUTOFF; + props.Equalizer.HighGain = AL_EQUALIZER_DEFAULT_HIGH_GAIN; + return props; +} + +} // namespace + +EffectStateFactory *EqualizerStateFactory_getFactory() +{ + static EqualizerStateFactory EqualizerFactory{}; + return &EqualizerFactory; +} diff --git a/alc/effects/fshifter.cpp b/alc/effects/fshifter.cpp new file mode 100644 index 00000000..b47aa00e --- /dev/null +++ b/alc/effects/fshifter.cpp @@ -0,0 +1,301 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2018 by Raul Herraiz. + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "alcmain.h" +#include "alcontext.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" + +#include "alcomplex.h" + +namespace { + +using complex_d = std::complex; + +#define HIL_SIZE 1024 +#define OVERSAMP (1<<2) + +#define HIL_STEP (HIL_SIZE / OVERSAMP) +#define FIFO_LATENCY (HIL_STEP * (OVERSAMP-1)) + +/* Define a Hann window, used to filter the HIL input and output. */ +/* Making this constexpr seems to require C++14. */ +std::array InitHannWindow() +{ + std::array ret; + /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */ + for(ALsizei i{0};i < HIL_SIZE>>1;i++) + { + ALdouble val = std::sin(al::MathDefs::Pi() * i / ALdouble{HIL_SIZE-1}); + ret[i] = ret[HIL_SIZE-1-i] = val * val; + } + return ret; +} +alignas(16) const std::array HannWindow = InitHannWindow(); + + +struct FshifterState final : public EffectState { + /* Effect parameters */ + ALsizei mCount{}; + ALsizei mPhaseStep{}; + ALsizei mPhase{}; + ALdouble mLdSign{}; + + /*Effects buffers*/ + ALfloat mInFIFO[HIL_SIZE]{}; + complex_d mOutFIFO[HIL_SIZE]{}; + complex_d mOutputAccum[HIL_SIZE]{}; + complex_d mAnalytic[HIL_SIZE]{}; + complex_d mOutdata[BUFFERSIZE]{}; + + alignas(16) ALfloat mBufferOut[BUFFERSIZE]{}; + + /* Effect gains for each output channel */ + ALfloat mCurrentGains[MAX_OUTPUT_CHANNELS]{}; + ALfloat mTargetGains[MAX_OUTPUT_CHANNELS]{}; + + + ALboolean deviceUpdate(const ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + + DEF_NEWDEL(FshifterState) +}; + +ALboolean FshifterState::deviceUpdate(const ALCdevice*) +{ + /* (Re-)initializing parameters and clear the buffers. */ + mCount = FIFO_LATENCY; + mPhaseStep = 0; + mPhase = 0; + mLdSign = 1.0; + + std::fill(std::begin(mInFIFO), std::end(mInFIFO), 0.0f); + std::fill(std::begin(mOutFIFO), std::end(mOutFIFO), complex_d{}); + std::fill(std::begin(mOutputAccum), std::end(mOutputAccum), complex_d{}); + std::fill(std::begin(mAnalytic), std::end(mAnalytic), complex_d{}); + + std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f); + std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f); + + return AL_TRUE; +} + +void FshifterState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) +{ + const ALCdevice *device{context->Device}; + + ALfloat step{props->Fshifter.Frequency / static_cast(device->Frequency)}; + mPhaseStep = fastf2i(minf(step, 0.5f) * FRACTIONONE); + + switch(props->Fshifter.LeftDirection) + { + case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: + mLdSign = -1.0; + break; + + case AL_FREQUENCY_SHIFTER_DIRECTION_UP: + mLdSign = 1.0; + break; + + case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: + mPhase = 0; + mPhaseStep = 0; + break; + } + + ALfloat coeffs[MAX_AMBI_CHANNELS]; + CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); + + mOutTarget = target.Main->Buffer; + ComputePanGains(target.Main, coeffs, slot->Params.Gain, mTargetGains); +} + +void FshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) +{ + static constexpr complex_d complex_zero{0.0, 0.0}; + ALfloat *RESTRICT BufferOut = mBufferOut; + ALsizei j, k, base; + + for(base = 0;base < samplesToDo;) + { + const ALsizei todo{mini(HIL_SIZE-mCount, samplesToDo-base)}; + + ASSUME(todo > 0); + + /* Fill FIFO buffer with samples data */ + k = mCount; + for(j = 0;j < todo;j++,k++) + { + mInFIFO[k] = samplesIn[0][base+j]; + mOutdata[base+j] = mOutFIFO[k-FIFO_LATENCY]; + } + mCount += todo; + base += todo; + + /* Check whether FIFO buffer is filled */ + if(mCount < HIL_SIZE) continue; + mCount = FIFO_LATENCY; + + /* Real signal windowing and store in Analytic buffer */ + for(k = 0;k < HIL_SIZE;k++) + { + mAnalytic[k].real(mInFIFO[k] * HannWindow[k]); + mAnalytic[k].imag(0.0); + } + + /* Processing signal by Discrete Hilbert Transform (analytical signal). */ + complex_hilbert(mAnalytic); + + /* Windowing and add to output accumulator */ + for(k = 0;k < HIL_SIZE;k++) + mOutputAccum[k] += 2.0/OVERSAMP*HannWindow[k]*mAnalytic[k]; + + /* Shift accumulator, input & output FIFO */ + for(k = 0;k < HIL_STEP;k++) mOutFIFO[k] = mOutputAccum[k]; + for(j = 0;k < HIL_SIZE;k++,j++) mOutputAccum[j] = mOutputAccum[k]; + for(;j < HIL_SIZE;j++) mOutputAccum[j] = complex_zero; + for(k = 0;k < FIFO_LATENCY;k++) + mInFIFO[k] = mInFIFO[k+HIL_STEP]; + } + + /* Process frequency shifter using the analytic signal obtained. */ + for(k = 0;k < samplesToDo;k++) + { + double phase = mPhase * ((1.0/FRACTIONONE) * al::MathDefs::Tau()); + BufferOut[k] = static_cast(mOutdata[k].real()*std::cos(phase) + + mOutdata[k].imag()*std::sin(phase)*mLdSign); + + mPhase += mPhaseStep; + mPhase &= FRACTIONMASK; + } + + /* Now, mix the processed sound data to the output. */ + MixSamples(BufferOut, samplesOut, mCurrentGains, mTargetGains, maxi(samplesToDo, 512), 0, + samplesToDo); +} + + +void Fshifter_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_FREQUENCY_SHIFTER_FREQUENCY: + if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter frequency out of range"); + props->Fshifter.Frequency = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); + } +} +void Fshifter_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) +{ Fshifter_setParamf(props, context, param, vals[0]); } + +void Fshifter_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val) +{ + switch(param) + { + case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: + if(!(val >= AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter left direction out of range"); + props->Fshifter.LeftDirection = val; + break; + + case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: + if(!(val >= AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter right direction out of range"); + props->Fshifter.RightDirection = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); + } +} +void Fshifter_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) +{ Fshifter_setParami(props, context, param, vals[0]); } + +void Fshifter_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val) +{ + switch(param) + { + case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: + *val = props->Fshifter.LeftDirection; + break; + case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: + *val = props->Fshifter.RightDirection; + break; + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); + } +} +void Fshifter_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) +{ Fshifter_getParami(props, context, param, vals); } + +void Fshifter_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_FREQUENCY_SHIFTER_FREQUENCY: + *val = props->Fshifter.Frequency; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); + } +} +void Fshifter_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) +{ Fshifter_getParamf(props, context, param, vals); } + +DEFINE_ALEFFECT_VTABLE(Fshifter); + + +struct FshifterStateFactory final : public EffectStateFactory { + EffectState *create() override { return new FshifterState{}; } + EffectProps getDefaultProps() const noexcept override; + const EffectVtable *getEffectVtable() const noexcept override { return &Fshifter_vtable; } +}; + +EffectProps FshifterStateFactory::getDefaultProps() const noexcept +{ + EffectProps props{}; + props.Fshifter.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY; + props.Fshifter.LeftDirection = AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION; + props.Fshifter.RightDirection = AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION; + return props; +} + +} // namespace + +EffectStateFactory *FshifterStateFactory_getFactory() +{ + static FshifterStateFactory FshifterFactory{}; + return &FshifterFactory; +} diff --git a/alc/effects/modulator.cpp b/alc/effects/modulator.cpp new file mode 100644 index 00000000..086482d7 --- /dev/null +++ b/alc/effects/modulator.cpp @@ -0,0 +1,279 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2009 by Chris Robinson. + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include +#include + +#include "alcmain.h" +#include "alcontext.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" +#include "filters/biquad.h" +#include "vecmat.h" + + +namespace { + +#define MAX_UPDATE_SAMPLES 128 + +#define WAVEFORM_FRACBITS 24 +#define WAVEFORM_FRACONE (1<(index) * + (al::MathDefs::Tau() / ALfloat{WAVEFORM_FRACONE})); +} + +inline ALfloat Saw(ALsizei index) +{ + return static_cast(index)*(2.0f/WAVEFORM_FRACONE) - 1.0f; +} + +inline ALfloat Square(ALsizei index) +{ + return static_cast(((index>>(WAVEFORM_FRACBITS-2))&2) - 1); +} + +inline ALfloat One(ALsizei) +{ + return 1.0f; +} + +template +void Modulate(ALfloat *RESTRICT dst, ALsizei index, const ALsizei step, ALsizei todo) +{ + ALsizei i; + for(i = 0;i < todo;i++) + { + index += step; + index &= WAVEFORM_FRACMASK; + dst[i] = func(index); + } +} + + +struct ModulatorState final : public EffectState { + void (*mGetSamples)(ALfloat*RESTRICT, ALsizei, const ALsizei, ALsizei){}; + + ALsizei mIndex{0}; + ALsizei mStep{1}; + + struct { + BiquadFilter Filter; + + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]{}; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]{}; + } mChans[MAX_AMBI_CHANNELS]; + + + ALboolean deviceUpdate(const ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + + DEF_NEWDEL(ModulatorState) +}; + +ALboolean ModulatorState::deviceUpdate(const ALCdevice*) +{ + for(auto &e : mChans) + { + e.Filter.clear(); + std::fill(std::begin(e.CurrentGains), std::end(e.CurrentGains), 0.0f); + } + return AL_TRUE; +} + +void ModulatorState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) +{ + const ALCdevice *device{context->Device}; + + const float step{props->Modulator.Frequency / static_cast(device->Frequency)}; + mStep = fastf2i(clampf(step*WAVEFORM_FRACONE, 0.0f, ALfloat{WAVEFORM_FRACONE-1})); + + if(mStep == 0) + mGetSamples = Modulate; + else if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) + mGetSamples = Modulate; + else if(props->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) + mGetSamples = Modulate; + else /*if(props->Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/ + mGetSamples = Modulate; + + ALfloat f0norm{props->Modulator.HighPassCutoff / static_cast(device->Frequency)}; + f0norm = clampf(f0norm, 1.0f/512.0f, 0.49f); + /* Bandwidth value is constant in octaves. */ + mChans[0].Filter.setParams(BiquadType::HighPass, 1.0f, f0norm, + BiquadFilter::rcpQFromBandwidth(f0norm, 0.75f)); + for(size_t i{1u};i < slot->Wet.Buffer.size();++i) + mChans[i].Filter.copyParamsFrom(mChans[0].Filter); + + mOutTarget = target.Main->Buffer; + for(size_t i{0u};i < slot->Wet.Buffer.size();++i) + { + auto coeffs = GetAmbiIdentityRow(i); + ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mChans[i].TargetGains); + } +} + +void ModulatorState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) +{ + for(ALsizei base{0};base < samplesToDo;) + { + alignas(16) ALfloat modsamples[MAX_UPDATE_SAMPLES]; + ALsizei td = mini(MAX_UPDATE_SAMPLES, samplesToDo-base); + ALsizei c, i; + + mGetSamples(modsamples, mIndex, mStep, td); + mIndex += (mStep*td) & WAVEFORM_FRACMASK; + mIndex &= WAVEFORM_FRACMASK; + + ASSUME(numInput > 0); + for(c = 0;c < numInput;c++) + { + alignas(16) ALfloat temps[MAX_UPDATE_SAMPLES]; + + mChans[c].Filter.process(temps, &samplesIn[c][base], td); + for(i = 0;i < td;i++) + temps[i] *= modsamples[i]; + + MixSamples(temps, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, + samplesToDo-base, base, td); + } + + base += td; + } +} + + +void Modulator_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + if(!(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Modulator frequency out of range"); + props->Modulator.Frequency = val; + break; + + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + if(!(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Modulator high-pass cutoff out of range"); + props->Modulator.HighPassCutoff = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param); + } +} +void Modulator_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) +{ Modulator_setParamf(props, context, param, vals[0]); } +void Modulator_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val) +{ + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + Modulator_setParamf(props, context, param, static_cast(val)); + break; + + case AL_RING_MODULATOR_WAVEFORM: + if(!(val >= AL_RING_MODULATOR_MIN_WAVEFORM && val <= AL_RING_MODULATOR_MAX_WAVEFORM)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid modulator waveform"); + props->Modulator.Waveform = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x", param); + } +} +void Modulator_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) +{ Modulator_setParami(props, context, param, vals[0]); } + +void Modulator_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val) +{ + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + *val = static_cast(props->Modulator.Frequency); + break; + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + *val = static_cast(props->Modulator.HighPassCutoff); + break; + case AL_RING_MODULATOR_WAVEFORM: + *val = props->Modulator.Waveform; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x", param); + } +} +void Modulator_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) +{ Modulator_getParami(props, context, param, vals); } +void Modulator_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + *val = props->Modulator.Frequency; + break; + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + *val = props->Modulator.HighPassCutoff; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param); + } +} +void Modulator_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) +{ Modulator_getParamf(props, context, param, vals); } + +DEFINE_ALEFFECT_VTABLE(Modulator); + + +struct ModulatorStateFactory final : public EffectStateFactory { + EffectState *create() override { return new ModulatorState{}; } + EffectProps getDefaultProps() const noexcept override; + const EffectVtable *getEffectVtable() const noexcept override { return &Modulator_vtable; } +}; + +EffectProps ModulatorStateFactory::getDefaultProps() const noexcept +{ + EffectProps props{}; + props.Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY; + props.Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF; + props.Modulator.Waveform = AL_RING_MODULATOR_DEFAULT_WAVEFORM; + return props; +} + +} // namespace + +EffectStateFactory *ModulatorStateFactory_getFactory() +{ + static ModulatorStateFactory ModulatorFactory{}; + return &ModulatorFactory; +} diff --git a/alc/effects/null.cpp b/alc/effects/null.cpp new file mode 100644 index 00000000..e55c8699 --- /dev/null +++ b/alc/effects/null.cpp @@ -0,0 +1,164 @@ +#include "config.h" + +#include + +#include "AL/al.h" +#include "AL/alc.h" + +#include "alcmain.h" +#include "alcontext.h" +#include "alAuxEffectSlot.h" +#include "alError.h" + + +namespace { + +struct NullState final : public EffectState { + NullState(); + ~NullState() override; + + ALboolean deviceUpdate(const ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + + DEF_NEWDEL(NullState) +}; + +/* This constructs the effect state. It's called when the object is first + * created. + */ +NullState::NullState() = default; + +/* This destructs the effect state. It's called only when the effect instance + * is no longer used. + */ +NullState::~NullState() = default; + +/* This updates the device-dependant effect state. This is called on state + * initialization and any time the device parameters (e.g. playback frequency, + * format) have been changed. Will always be followed by a call to the update + * method, if successful. + */ +ALboolean NullState::deviceUpdate(const ALCdevice* /*device*/) +{ + return AL_TRUE; +} + +/* This updates the effect state with new properties. This is called any time + * the effect is (re)loaded into a slot. + */ +void NullState::update(const ALCcontext* /*context*/, const ALeffectslot* /*slot*/, + const EffectProps* /*props*/, const EffectTarget /*target*/) +{ +} + +/* This processes the effect state, for the given number of samples from the + * input to the output buffer. The result should be added to the output buffer, + * not replace it. + */ +void NullState::process(const ALsizei /*samplesToDo*/, + const FloatBufferLine *RESTRICT /*samplesIn*/, const ALsizei /*numInput*/, + const al::span /*samplesOut*/) +{ +} + + +void NullEffect_setParami(EffectProps* /*props*/, ALCcontext *context, ALenum param, ALint /*val*/) +{ + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x", param); + } +} +void NullEffect_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) +{ + switch(param) + { + default: + NullEffect_setParami(props, context, param, vals[0]); + } +} +void NullEffect_setParamf(EffectProps* /*props*/, ALCcontext *context, ALenum param, ALfloat /*val*/) +{ + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM, "Invalid null effect float property 0x%04x", param); + } +} +void NullEffect_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + switch(param) + { + default: + NullEffect_setParamf(props, context, param, vals[0]); + } +} + +void NullEffect_getParami(const EffectProps* /*props*/, ALCcontext *context, ALenum param, ALint* /*val*/) +{ + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x", param); + } +} +void NullEffect_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) +{ + switch(param) + { + default: + NullEffect_getParami(props, context, param, vals); + } +} +void NullEffect_getParamf(const EffectProps* /*props*/, ALCcontext *context, ALenum param, ALfloat* /*val*/) +{ + switch(param) + { + default: + alSetError(context, AL_INVALID_ENUM, "Invalid null effect float property 0x%04x", param); + } +} +void NullEffect_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) +{ + switch(param) + { + default: + NullEffect_getParamf(props, context, param, vals); + } +} + +DEFINE_ALEFFECT_VTABLE(NullEffect); + + +struct NullStateFactory final : public EffectStateFactory { + EffectState *create() override; + EffectProps getDefaultProps() const noexcept override; + const EffectVtable *getEffectVtable() const noexcept override; +}; + +/* Creates EffectState objects of the appropriate type. */ +EffectState *NullStateFactory::create() +{ return new NullState{}; } + +/* Returns an ALeffectProps initialized with this effect type's default + * property values. + */ +EffectProps NullStateFactory::getDefaultProps() const noexcept +{ + EffectProps props{}; + return props; +} + +/* Returns a pointer to this effect type's global set/get vtable. */ +const EffectVtable *NullStateFactory::getEffectVtable() const noexcept +{ return &NullEffect_vtable; } + +} // namespace + +EffectStateFactory *NullStateFactory_getFactory() +{ + static NullStateFactory NullFactory{}; + return &NullFactory; +} diff --git a/alc/effects/pshifter.cpp b/alc/effects/pshifter.cpp new file mode 100644 index 00000000..39d3cf1a --- /dev/null +++ b/alc/effects/pshifter.cpp @@ -0,0 +1,405 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2018 by Raul Herraiz. + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#ifdef HAVE_SSE_INTRINSICS +#include +#endif + +#include +#include +#include +#include +#include + +#include "alcmain.h" +#include "alcontext.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" + +#include "alcomplex.h" + + +namespace { + +using complex_d = std::complex; + +#define STFT_SIZE 1024 +#define STFT_HALF_SIZE (STFT_SIZE>>1) +#define OVERSAMP (1<<2) + +#define STFT_STEP (STFT_SIZE / OVERSAMP) +#define FIFO_LATENCY (STFT_STEP * (OVERSAMP-1)) + +inline int double2int(double d) +{ +#if defined(HAVE_SSE_INTRINSICS) + return _mm_cvttsd_si32(_mm_set_sd(d)); + +#elif ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) && \ + !defined(__SSE2_MATH__)) || (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP < 2) + + int sign, shift; + int64_t mant; + union { + double d; + int64_t i64; + } conv; + + conv.d = d; + sign = (conv.i64>>63) | 1; + shift = ((conv.i64>>52)&0x7ff) - (1023+52); + + /* Over/underflow */ + if(UNLIKELY(shift >= 63 || shift < -52)) + return 0; + + mant = (conv.i64&0xfffffffffffff_i64) | 0x10000000000000_i64; + if(LIKELY(shift < 0)) + return (int)(mant >> -shift) * sign; + return (int)(mant << shift) * sign; + +#else + + return static_cast(d); +#endif +} + +/* Define a Hann window, used to filter the STFT input and output. */ +/* Making this constexpr seems to require C++14. */ +std::array InitHannWindow() +{ + std::array ret; + /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */ + for(ALsizei i{0};i < STFT_SIZE>>1;i++) + { + ALdouble val = std::sin(al::MathDefs::Pi() * i / ALdouble{STFT_SIZE-1}); + ret[i] = ret[STFT_SIZE-1-i] = val * val; + } + return ret; +} +alignas(16) const std::array HannWindow = InitHannWindow(); + + +struct ALphasor { + ALdouble Amplitude; + ALdouble Phase; +}; + +struct ALfrequencyDomain { + ALdouble Amplitude; + ALdouble Frequency; +}; + + +/* Converts complex to ALphasor */ +inline ALphasor rect2polar(const complex_d &number) +{ + ALphasor polar; + polar.Amplitude = std::abs(number); + polar.Phase = std::arg(number); + return polar; +} + +/* Converts ALphasor to complex */ +inline complex_d polar2rect(const ALphasor &number) +{ return std::polar(number.Amplitude, number.Phase); } + + +struct PshifterState final : public EffectState { + /* Effect parameters */ + ALsizei mCount; + ALsizei mPitchShiftI; + ALfloat mPitchShift; + ALfloat mFreqPerBin; + + /* Effects buffers */ + ALfloat mInFIFO[STFT_SIZE]; + ALfloat mOutFIFO[STFT_STEP]; + ALdouble mLastPhase[STFT_HALF_SIZE+1]; + ALdouble mSumPhase[STFT_HALF_SIZE+1]; + ALdouble mOutputAccum[STFT_SIZE]; + + complex_d mFFTbuffer[STFT_SIZE]; + + ALfrequencyDomain mAnalysis_buffer[STFT_HALF_SIZE+1]; + ALfrequencyDomain mSyntesis_buffer[STFT_HALF_SIZE+1]; + + alignas(16) ALfloat mBufferOut[BUFFERSIZE]; + + /* Effect gains for each output channel */ + ALfloat mCurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat mTargetGains[MAX_OUTPUT_CHANNELS]; + + + ALboolean deviceUpdate(const ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + + DEF_NEWDEL(PshifterState) +}; + +ALboolean PshifterState::deviceUpdate(const ALCdevice *device) +{ + /* (Re-)initializing parameters and clear the buffers. */ + mCount = FIFO_LATENCY; + mPitchShiftI = FRACTIONONE; + mPitchShift = 1.0f; + mFreqPerBin = device->Frequency / static_cast(STFT_SIZE); + + std::fill(std::begin(mInFIFO), std::end(mInFIFO), 0.0f); + std::fill(std::begin(mOutFIFO), std::end(mOutFIFO), 0.0f); + std::fill(std::begin(mLastPhase), std::end(mLastPhase), 0.0); + std::fill(std::begin(mSumPhase), std::end(mSumPhase), 0.0); + std::fill(std::begin(mOutputAccum), std::end(mOutputAccum), 0.0); + std::fill(std::begin(mFFTbuffer), std::end(mFFTbuffer), complex_d{}); + std::fill(std::begin(mAnalysis_buffer), std::end(mAnalysis_buffer), ALfrequencyDomain{}); + std::fill(std::begin(mSyntesis_buffer), std::end(mSyntesis_buffer), ALfrequencyDomain{}); + + std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f); + std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f); + + return AL_TRUE; +} + +void PshifterState::update(const ALCcontext*, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) +{ + const float pitch{std::pow(2.0f, + static_cast(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f + )}; + mPitchShiftI = fastf2i(pitch*FRACTIONONE); + mPitchShift = mPitchShiftI * (1.0f/FRACTIONONE); + + ALfloat coeffs[MAX_AMBI_CHANNELS]; + CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); + + mOutTarget = target.Main->Buffer; + ComputePanGains(target.Main, coeffs, slot->Params.Gain, mTargetGains); +} + +void PshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) +{ + /* Pitch shifter engine based on the work of Stephan Bernsee. + * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/ + */ + + static constexpr ALdouble expected{al::MathDefs::Tau() / OVERSAMP}; + const ALdouble freq_per_bin{mFreqPerBin}; + ALfloat *RESTRICT bufferOut{mBufferOut}; + ALsizei count{mCount}; + + for(ALsizei i{0};i < samplesToDo;) + { + do { + /* Fill FIFO buffer with samples data */ + mInFIFO[count] = samplesIn[0][i]; + bufferOut[i] = mOutFIFO[count - FIFO_LATENCY]; + + count++; + } while(++i < samplesToDo && count < STFT_SIZE); + + /* Check whether FIFO buffer is filled */ + if(count < STFT_SIZE) break; + count = FIFO_LATENCY; + + /* Real signal windowing and store in FFTbuffer */ + for(ALsizei k{0};k < STFT_SIZE;k++) + { + mFFTbuffer[k].real(mInFIFO[k] * HannWindow[k]); + mFFTbuffer[k].imag(0.0); + } + + /* ANALYSIS */ + /* Apply FFT to FFTbuffer data */ + complex_fft(mFFTbuffer, -1.0); + + /* Analyze the obtained data. Since the real FFT is symmetric, only + * STFT_HALF_SIZE+1 samples are needed. + */ + for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) + { + /* Compute amplitude and phase */ + ALphasor component{rect2polar(mFFTbuffer[k])}; + + /* Compute phase difference and subtract expected phase difference */ + double tmp{(component.Phase - mLastPhase[k]) - k*expected}; + + /* Map delta phase into +/- Pi interval */ + int qpd{double2int(tmp / al::MathDefs::Pi())}; + tmp -= al::MathDefs::Pi() * (qpd + (qpd%2)); + + /* Get deviation from bin frequency from the +/- Pi interval */ + tmp /= expected; + + /* Compute the k-th partials' true frequency, twice the amplitude + * for maintain the gain (because half of bins are used) and store + * amplitude and true frequency in analysis buffer. + */ + mAnalysis_buffer[k].Amplitude = 2.0 * component.Amplitude; + mAnalysis_buffer[k].Frequency = (k + tmp) * freq_per_bin; + + /* Store actual phase[k] for the calculations in the next frame*/ + mLastPhase[k] = component.Phase; + } + + /* PROCESSING */ + /* pitch shifting */ + for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) + { + mSyntesis_buffer[k].Amplitude = 0.0; + mSyntesis_buffer[k].Frequency = 0.0; + } + + for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) + { + ALsizei j{(k*mPitchShiftI) >> FRACTIONBITS}; + if(j >= STFT_HALF_SIZE+1) break; + + mSyntesis_buffer[j].Amplitude += mAnalysis_buffer[k].Amplitude; + mSyntesis_buffer[j].Frequency = mAnalysis_buffer[k].Frequency * mPitchShift; + } + + /* SYNTHESIS */ + /* Synthesis the processing data */ + for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) + { + ALphasor component; + ALdouble tmp; + + /* Compute bin deviation from scaled freq */ + tmp = mSyntesis_buffer[k].Frequency/freq_per_bin - k; + + /* Calculate actual delta phase and accumulate it to get bin phase */ + mSumPhase[k] += (k + tmp) * expected; + + component.Amplitude = mSyntesis_buffer[k].Amplitude; + component.Phase = mSumPhase[k]; + + /* Compute phasor component to cartesian complex number and storage it into FFTbuffer*/ + mFFTbuffer[k] = polar2rect(component); + } + /* zero negative frequencies for recontruct a real signal */ + for(ALsizei k{STFT_HALF_SIZE+1};k < STFT_SIZE;k++) + mFFTbuffer[k] = complex_d{}; + + /* Apply iFFT to buffer data */ + complex_fft(mFFTbuffer, 1.0); + + /* Windowing and add to output */ + for(ALsizei k{0};k < STFT_SIZE;k++) + mOutputAccum[k] += HannWindow[k] * mFFTbuffer[k].real() / + (0.5 * STFT_HALF_SIZE * OVERSAMP); + + /* Shift accumulator, input & output FIFO */ + ALsizei j, k; + for(k = 0;k < STFT_STEP;k++) mOutFIFO[k] = static_cast(mOutputAccum[k]); + for(j = 0;k < STFT_SIZE;k++,j++) mOutputAccum[j] = mOutputAccum[k]; + for(;j < STFT_SIZE;j++) mOutputAccum[j] = 0.0; + for(k = 0;k < FIFO_LATENCY;k++) + mInFIFO[k] = mInFIFO[k+STFT_STEP]; + } + mCount = count; + + /* Now, mix the processed sound data to the output. */ + MixSamples(bufferOut, samplesOut, mCurrentGains, mTargetGains, maxi(samplesToDo, 512), 0, + samplesToDo); +} + + +void Pshifter_setParamf(EffectProps*, ALCcontext *context, ALenum param, ALfloat) +{ alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param); } +void Pshifter_setParamfv(EffectProps*, ALCcontext *context, ALenum param, const ALfloat*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float-vector property 0x%04x", param); } + +void Pshifter_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val) +{ + switch(param) + { + case AL_PITCH_SHIFTER_COARSE_TUNE: + if(!(val >= AL_PITCH_SHIFTER_MIN_COARSE_TUNE && val <= AL_PITCH_SHIFTER_MAX_COARSE_TUNE)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Pitch shifter coarse tune out of range"); + props->Pshifter.CoarseTune = val; + break; + + case AL_PITCH_SHIFTER_FINE_TUNE: + if(!(val >= AL_PITCH_SHIFTER_MIN_FINE_TUNE && val <= AL_PITCH_SHIFTER_MAX_FINE_TUNE)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Pitch shifter fine tune out of range"); + props->Pshifter.FineTune = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x", param); + } +} +void Pshifter_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) +{ Pshifter_setParami(props, context, param, vals[0]); } + +void Pshifter_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val) +{ + switch(param) + { + case AL_PITCH_SHIFTER_COARSE_TUNE: + *val = props->Pshifter.CoarseTune; + break; + case AL_PITCH_SHIFTER_FINE_TUNE: + *val = props->Pshifter.FineTune; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x", param); + } +} +void Pshifter_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) +{ Pshifter_getParami(props, context, param, vals); } + +void Pshifter_getParamf(const EffectProps*, ALCcontext *context, ALenum param, ALfloat*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param); } +void Pshifter_getParamfv(const EffectProps*, ALCcontext *context, ALenum param, ALfloat*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float vector-property 0x%04x", param); } + +DEFINE_ALEFFECT_VTABLE(Pshifter); + + +struct PshifterStateFactory final : public EffectStateFactory { + EffectState *create() override; + EffectProps getDefaultProps() const noexcept override; + const EffectVtable *getEffectVtable() const noexcept override { return &Pshifter_vtable; } +}; + +EffectState *PshifterStateFactory::create() +{ return new PshifterState{}; } + +EffectProps PshifterStateFactory::getDefaultProps() const noexcept +{ + EffectProps props{}; + props.Pshifter.CoarseTune = AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE; + props.Pshifter.FineTune = AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE; + return props; +} + +} // namespace + +EffectStateFactory *PshifterStateFactory_getFactory() +{ + static PshifterStateFactory PshifterFactory{}; + return &PshifterFactory; +} diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp new file mode 100644 index 00000000..ac996b3f --- /dev/null +++ b/alc/effects/reverb.cpp @@ -0,0 +1,2102 @@ +/** + * Ambisonic reverb engine for the OpenAL cross platform audio library + * Copyright (C) 2008-2017 by Chris Robinson and Christopher Fitzgerald. + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "alcmain.h" +#include "alcontext.h" +#include "alu.h" +#include "alAuxEffectSlot.h" +#include "alListener.h" +#include "alError.h" +#include "bformatdec.h" +#include "filters/biquad.h" +#include "vector.h" +#include "vecmat.h" + +/* This is a user config option for modifying the overall output of the reverb + * effect. + */ +ALfloat ReverbBoost = 1.0f; + +namespace { + +using namespace std::placeholders; + +/* The number of samples used for cross-faded delay lines. This can be used + * to balance the compensation for abrupt line changes and attenuation due to + * minimally lengthed recursive lines. Try to keep this below the device + * update size. + */ +constexpr int FADE_SAMPLES{128}; + +/* The number of spatialized lines or channels to process. Four channels allows + * for a 3D A-Format response. NOTE: This can't be changed without taking care + * of the conversion matrices, and a few places where the length arrays are + * assumed to have 4 elements. + */ +constexpr int NUM_LINES{4}; + + +/* The B-Format to A-Format conversion matrix. The arrangement of rows is + * deliberately chosen to align the resulting lines to their spatial opposites + * (0:above front left <-> 3:above back right, 1:below front right <-> 2:below + * back left). It's not quite opposite, since the A-Format results in a + * tetrahedron, but it's close enough. Should the model be extended to 8-lines + * in the future, true opposites can be used. + */ +alignas(16) constexpr ALfloat B2A[NUM_LINES][MAX_AMBI_CHANNELS]{ + { 0.288675134595f, 0.288675134595f, 0.288675134595f, 0.288675134595f }, + { 0.288675134595f, -0.288675134595f, -0.288675134595f, 0.288675134595f }, + { 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f }, + { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f } +}; + +/* Converts A-Format to B-Format. */ +alignas(16) constexpr ALfloat A2B[NUM_LINES][NUM_LINES]{ + { 0.866025403785f, 0.866025403785f, 0.866025403785f, 0.866025403785f }, + { 0.866025403785f, -0.866025403785f, 0.866025403785f, -0.866025403785f }, + { 0.866025403785f, -0.866025403785f, -0.866025403785f, 0.866025403785f }, + { 0.866025403785f, 0.866025403785f, -0.866025403785f, -0.866025403785f } +}; + + +constexpr ALfloat FadeStep{1.0f / FADE_SAMPLES}; + +/* The all-pass and delay lines have a variable length dependent on the + * effect's density parameter, which helps alter the perceived environment + * size. The size-to-density conversion is a cubed scale: + * + * density = min(1.0, pow(size, 3.0) / DENSITY_SCALE); + * + * The line lengths scale linearly with room size, so the inverse density + * conversion is needed, taking the cube root of the re-scaled density to + * calculate the line length multiplier: + * + * length_mult = max(5.0, cbrt(density*DENSITY_SCALE)); + * + * The density scale below will result in a max line multiplier of 50, for an + * effective size range of 5m to 50m. + */ +constexpr ALfloat DENSITY_SCALE{125000.0f}; + +/* All delay line lengths are specified in seconds. + * + * To approximate early reflections, we break them up into primary (those + * arriving from the same direction as the source) and secondary (those + * arriving from the opposite direction). + * + * The early taps decorrelate the 4-channel signal to approximate an average + * room response for the primary reflections after the initial early delay. + * + * Given an average room dimension (d_a) and the speed of sound (c) we can + * calculate the average reflection delay (r_a) regardless of listener and + * source positions as: + * + * r_a = d_a / c + * c = 343.3 + * + * This can extended to finding the average difference (r_d) between the + * maximum (r_1) and minimum (r_0) reflection delays: + * + * r_0 = 2 / 3 r_a + * = r_a - r_d / 2 + * = r_d + * r_1 = 4 / 3 r_a + * = r_a + r_d / 2 + * = 2 r_d + * r_d = 2 / 3 r_a + * = r_1 - r_0 + * + * As can be determined by integrating the 1D model with a source (s) and + * listener (l) positioned across the dimension of length (d_a): + * + * r_d = int_(l=0)^d_a (int_(s=0)^d_a |2 d_a - 2 (l + s)| ds) dl / c + * + * The initial taps (T_(i=0)^N) are then specified by taking a power series + * that ranges between r_0 and half of r_1 less r_0: + * + * R_i = 2^(i / (2 N - 1)) r_d + * = r_0 + (2^(i / (2 N - 1)) - 1) r_d + * = r_0 + T_i + * T_i = R_i - r_0 + * = (2^(i / (2 N - 1)) - 1) r_d + * + * Assuming an average of 1m, we get the following taps: + */ +constexpr std::array EARLY_TAP_LENGTHS{{ + 0.0000000e+0f, 2.0213520e-4f, 4.2531060e-4f, 6.7171600e-4f +}}; + +/* The early all-pass filter lengths are based on the early tap lengths: + * + * A_i = R_i / a + * + * Where a is the approximate maximum all-pass cycle limit (20). + */ +constexpr std::array EARLY_ALLPASS_LENGTHS{{ + 9.7096800e-5f, 1.0720356e-4f, 1.1836234e-4f, 1.3068260e-4f +}}; + +/* The early delay lines are used to transform the primary reflections into + * the secondary reflections. The A-format is arranged in such a way that + * the channels/lines are spatially opposite: + * + * C_i is opposite C_(N-i-1) + * + * The delays of the two opposing reflections (R_i and O_i) from a source + * anywhere along a particular dimension always sum to twice its full delay: + * + * 2 r_a = R_i + O_i + * + * With that in mind we can determine the delay between the two reflections + * and thus specify our early line lengths (L_(i=0)^N) using: + * + * O_i = 2 r_a - R_(N-i-1) + * L_i = O_i - R_(N-i-1) + * = 2 (r_a - R_(N-i-1)) + * = 2 (r_a - T_(N-i-1) - r_0) + * = 2 r_a (1 - (2 / 3) 2^((N - i - 1) / (2 N - 1))) + * + * Using an average dimension of 1m, we get: + */ +constexpr std::array EARLY_LINE_LENGTHS{{ + 5.9850400e-4f, 1.0913150e-3f, 1.5376658e-3f, 1.9419362e-3f +}}; + +/* The late all-pass filter lengths are based on the late line lengths: + * + * A_i = (5 / 3) L_i / r_1 + */ +constexpr std::array LATE_ALLPASS_LENGTHS{{ + 1.6182800e-4f, 2.0389060e-4f, 2.8159360e-4f, 3.2365600e-4f +}}; +constexpr auto LATE_ALLPASS_LENGTHS_size = LATE_ALLPASS_LENGTHS.size(); + +/* The late lines are used to approximate the decaying cycle of recursive + * late reflections. + * + * Splitting the lines in half, we start with the shortest reflection paths + * (L_(i=0)^(N/2)): + * + * L_i = 2^(i / (N - 1)) r_d + * + * Then for the opposite (longest) reflection paths (L_(i=N/2)^N): + * + * L_i = 2 r_a - L_(i-N/2) + * = 2 r_a - 2^((i - N / 2) / (N - 1)) r_d + * + * For our 1m average room, we get: + */ +constexpr std::array LATE_LINE_LENGTHS{{ + 1.9419362e-3f, 2.4466860e-3f, 3.3791220e-3f, 3.8838720e-3f +}}; +constexpr auto LATE_LINE_LENGTHS_size = LATE_LINE_LENGTHS.size(); + + +struct DelayLineI { + /* The delay lines use interleaved samples, with the lengths being powers + * of 2 to allow the use of bit-masking instead of a modulus for wrapping. + */ + ALsizei Mask{0}; + ALfloat (*Line)[NUM_LINES]{nullptr}; + + + void write(ALsizei offset, const ALsizei c, const ALfloat *RESTRICT in, const ALsizei count) const noexcept + { + ASSUME(count > 0); + for(ALsizei i{0};i < count;) + { + offset &= Mask; + ALsizei td{mini(Mask+1 - offset, count - i)}; + do { + Line[offset++][c] = in[i++]; + } while(--td); + } + } +}; + +struct VecAllpass { + DelayLineI Delay; + ALfloat Coeff{0.0f}; + ALsizei Offset[NUM_LINES][2]{}; + + void processFaded(const al::span samples, ALsizei offset, + const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, const ALsizei todo); + void processUnfaded(const al::span samples, ALsizei offset, + const ALfloat xCoeff, const ALfloat yCoeff, const ALsizei todo); +}; + +struct T60Filter { + /* Two filters are used to adjust the signal. One to control the low + * frequencies, and one to control the high frequencies. + */ + ALfloat MidGain[2]{0.0f, 0.0f}; + BiquadFilter HFFilter, LFFilter; + + void calcCoeffs(const ALfloat length, const ALfloat lfDecayTime, const ALfloat mfDecayTime, + const ALfloat hfDecayTime, const ALfloat lf0norm, const ALfloat hf0norm); + + /* Applies the two T60 damping filter sections. */ + void process(ALfloat *samples, const ALsizei todo) + { + HFFilter.process(samples, samples, todo); + LFFilter.process(samples, samples, todo); + } +}; + +struct EarlyReflections { + /* A Gerzon vector all-pass filter is used to simulate initial diffusion. + * The spread from this filter also helps smooth out the reverb tail. + */ + VecAllpass VecAp; + + /* An echo line is used to complete the second half of the early + * reflections. + */ + DelayLineI Delay; + ALsizei Offset[NUM_LINES][2]{}; + ALfloat Coeff[NUM_LINES][2]{}; + + /* The gain for each output channel based on 3D panning. */ + ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]{}; + ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]{}; + + void updateLines(const ALfloat density, const ALfloat diffusion, const ALfloat decayTime, + const ALfloat frequency); +}; + +struct LateReverb { + /* A recursive delay line is used fill in the reverb tail. */ + DelayLineI Delay; + ALsizei Offset[NUM_LINES][2]{}; + + /* Attenuation to compensate for the modal density and decay rate of the + * late lines. + */ + ALfloat DensityGain[2]{0.0f, 0.0f}; + + /* T60 decay filters are used to simulate absorption. */ + T60Filter T60[NUM_LINES]; + + /* A Gerzon vector all-pass filter is used to simulate diffusion. */ + VecAllpass VecAp; + + /* The gain for each output channel based on 3D panning. */ + ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]{}; + ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]{}; + + void updateLines(const ALfloat density, const ALfloat diffusion, const ALfloat lfDecayTime, + const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lf0norm, + const ALfloat hf0norm, const ALfloat frequency); +}; + +struct ReverbState final : public EffectState { + /* All delay lines are allocated as a single buffer to reduce memory + * fragmentation and management code. + */ + al::vector mSampleBuffer; + + struct { + /* Calculated parameters which indicate if cross-fading is needed after + * an update. + */ + ALfloat Density{AL_EAXREVERB_DEFAULT_DENSITY}; + ALfloat Diffusion{AL_EAXREVERB_DEFAULT_DIFFUSION}; + ALfloat DecayTime{AL_EAXREVERB_DEFAULT_DECAY_TIME}; + ALfloat HFDecayTime{AL_EAXREVERB_DEFAULT_DECAY_HFRATIO * AL_EAXREVERB_DEFAULT_DECAY_TIME}; + ALfloat LFDecayTime{AL_EAXREVERB_DEFAULT_DECAY_LFRATIO * AL_EAXREVERB_DEFAULT_DECAY_TIME}; + ALfloat HFReference{AL_EAXREVERB_DEFAULT_HFREFERENCE}; + ALfloat LFReference{AL_EAXREVERB_DEFAULT_LFREFERENCE}; + } mParams; + + /* Master effect filters */ + struct { + BiquadFilter Lp; + BiquadFilter Hp; + } mFilter[NUM_LINES]; + + /* Core delay line (early reflections and late reverb tap from this). */ + DelayLineI mDelay; + + /* Tap points for early reflection delay. */ + ALsizei mEarlyDelayTap[NUM_LINES][2]{}; + ALfloat mEarlyDelayCoeff[NUM_LINES][2]{}; + + /* Tap points for late reverb feed and delay. */ + ALsizei mLateFeedTap{}; + ALsizei mLateDelayTap[NUM_LINES][2]{}; + + /* Coefficients for the all-pass and line scattering matrices. */ + ALfloat mMixX{0.0f}; + ALfloat mMixY{0.0f}; + + EarlyReflections mEarly; + + LateReverb mLate; + + /* Indicates the cross-fade point for delay line reads [0,FADE_SAMPLES]. */ + ALsizei mFadeCount{0}; + + /* Maximum number of samples to process at once. */ + ALsizei mMaxUpdate[2]{BUFFERSIZE, BUFFERSIZE}; + + /* The current write offset for all delay lines. */ + ALsizei mOffset{0}; + + /* Temporary storage used when processing. */ + alignas(16) std::array mTempSamples{}; + alignas(16) std::array mEarlyBuffer{}; + alignas(16) std::array mLateBuffer{}; + + using MixOutT = void (ReverbState::*)(const al::span samplesOut, + const ALsizei todo); + + MixOutT mMixOut{&ReverbState::MixOutPlain}; + std::array mOrderScales{}; + std::array,2> mAmbiSplitter; + + + void MixOutPlain(const al::span samplesOut, const ALsizei todo) + { + ASSUME(todo > 0); + + /* Convert back to B-Format, and mix the results to output. */ + for(ALsizei c{0};c < NUM_LINES;c++) + { + std::fill_n(mTempSamples[0].begin(), todo, 0.0f); + MixRowSamples(mTempSamples[0], A2B[c], mEarlyBuffer, 0, todo); + MixSamples(mTempSamples[0].data(), samplesOut, mEarly.CurrentGain[c], + mEarly.PanGain[c], todo, 0, todo); + } + + for(ALsizei c{0};c < NUM_LINES;c++) + { + std::fill_n(mTempSamples[0].begin(), todo, 0.0f); + MixRowSamples(mTempSamples[0], A2B[c], mLateBuffer, 0, todo); + MixSamples(mTempSamples[0].data(), samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], + todo, 0, todo); + } + } + + void MixOutAmbiUp(const al::span samplesOut, const ALsizei todo) + { + ASSUME(todo > 0); + + for(ALsizei c{0};c < NUM_LINES;c++) + { + std::fill_n(mTempSamples[0].begin(), todo, 0.0f); + MixRowSamples(mTempSamples[0], A2B[c], mEarlyBuffer, 0, todo); + + /* Apply scaling to the B-Format's HF response to "upsample" it to + * higher-order output. + */ + const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; + mAmbiSplitter[0][c].applyHfScale(mTempSamples[0].data(), hfscale, todo); + + MixSamples(mTempSamples[0].data(), samplesOut, mEarly.CurrentGain[c], + mEarly.PanGain[c], todo, 0, todo); + } + + for(ALsizei c{0};c < NUM_LINES;c++) + { + std::fill_n(mTempSamples[0].begin(), todo, 0.0f); + MixRowSamples(mTempSamples[0], A2B[c], mLateBuffer, 0, todo); + + const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; + mAmbiSplitter[1][c].applyHfScale(mTempSamples[0].data(), hfscale, todo); + + MixSamples(mTempSamples[0].data(), samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], + todo, 0, todo); + } + } + + bool allocLines(const ALfloat frequency); + + void updateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, const ALfloat density, + const ALfloat decayTime, const ALfloat frequency); + void update3DPanning(const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, + const ALfloat earlyGain, const ALfloat lateGain, const EffectTarget &target); + + ALboolean deviceUpdate(const ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + + DEF_NEWDEL(ReverbState) +}; + +/************************************** + * Device Update * + **************************************/ + +inline ALfloat CalcDelayLengthMult(ALfloat density) +{ return maxf(5.0f, std::cbrt(density*DENSITY_SCALE)); } + +/* Given the allocated sample buffer, this function updates each delay line + * offset. + */ +inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLineI *Delay) +{ + union { + ALfloat *f; + ALfloat (*f4)[NUM_LINES]; + } u; + u.f = &sampleBuffer[reinterpret_cast(Delay->Line) * NUM_LINES]; + Delay->Line = u.f4; +} + +/* Calculate the length of a delay line and store its mask and offset. */ +ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const ALfloat frequency, + const ALuint extra, DelayLineI *Delay) +{ + /* All line lengths are powers of 2, calculated from their lengths in + * seconds, rounded up. + */ + auto samples = static_cast(float2int(std::ceil(length*frequency))); + samples = NextPowerOf2(samples + extra); + + /* All lines share a single sample buffer. */ + Delay->Mask = samples - 1; + Delay->Line = reinterpret_cast(offset); + + /* Return the sample count for accumulation. */ + return samples; +} + +/* Calculates the delay line metrics and allocates the shared sample buffer + * for all lines given the sample rate (frequency). If an allocation failure + * occurs, it returns AL_FALSE. + */ +bool ReverbState::allocLines(const ALfloat frequency) +{ + /* All delay line lengths are calculated to accomodate the full range of + * lengths given their respective paramters. + */ + ALuint totalSamples{0u}; + + /* Multiplier for the maximum density value, i.e. density=1, which is + * actually the least density... + */ + ALfloat multiplier{CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY)}; + + /* The main delay length includes the maximum early reflection delay, the + * largest early tap width, the maximum late reverb delay, and the + * largest late tap width. Finally, it must also be extended by the + * update size (BUFFERSIZE) for block processing. + */ + ALfloat length{AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS.back()*multiplier + + AL_EAXREVERB_MAX_LATE_REVERB_DELAY + + (LATE_LINE_LENGTHS.back() - LATE_LINE_LENGTHS.front())/float{LATE_LINE_LENGTHS_size}*multiplier}; + totalSamples += CalcLineLength(length, totalSamples, frequency, BUFFERSIZE, &mDelay); + + /* The early vector all-pass line. */ + length = EARLY_ALLPASS_LENGTHS.back() * multiplier; + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &mEarly.VecAp.Delay); + + /* The early reflection line. */ + length = EARLY_LINE_LENGTHS.back() * multiplier; + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &mEarly.Delay); + + /* The late vector all-pass line. */ + length = LATE_ALLPASS_LENGTHS.back() * multiplier; + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &mLate.VecAp.Delay); + + /* The late delay lines are calculated from the largest maximum density + * line length. + */ + length = LATE_LINE_LENGTHS.back() * multiplier; + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &mLate.Delay); + + totalSamples *= NUM_LINES; + if(totalSamples != mSampleBuffer.size()) + { + mSampleBuffer.resize(totalSamples); + mSampleBuffer.shrink_to_fit(); + } + + /* Clear the sample buffer. */ + std::fill(mSampleBuffer.begin(), mSampleBuffer.end(), 0.0f); + + /* Update all delays to reflect the new sample buffer. */ + RealizeLineOffset(mSampleBuffer.data(), &mDelay); + RealizeLineOffset(mSampleBuffer.data(), &mEarly.VecAp.Delay); + RealizeLineOffset(mSampleBuffer.data(), &mEarly.Delay); + RealizeLineOffset(mSampleBuffer.data(), &mLate.VecAp.Delay); + RealizeLineOffset(mSampleBuffer.data(), &mLate.Delay); + + return true; +} + +ALboolean ReverbState::deviceUpdate(const ALCdevice *device) +{ + const auto frequency = static_cast(device->Frequency); + + /* Allocate the delay lines. */ + if(!allocLines(frequency)) + return AL_FALSE; + + const ALfloat multiplier{CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY)}; + + /* The late feed taps are set a fixed position past the latest delay tap. */ + mLateFeedTap = float2int( + (AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS.back()*multiplier) * frequency); + + /* Clear filters and gain coefficients since the delay lines were all just + * cleared (if not reallocated). + */ + for(auto &filter : mFilter) + { + filter.Lp.clear(); + filter.Hp.clear(); + } + + for(auto &coeff : mEarlyDelayCoeff) + std::fill(std::begin(coeff), std::end(coeff), 0.0f); + for(auto &coeff : mEarly.Coeff) + std::fill(std::begin(coeff), std::end(coeff), 0.0f); + + mLate.DensityGain[0] = 0.0f; + mLate.DensityGain[1] = 0.0f; + for(auto &t60 : mLate.T60) + { + t60.MidGain[0] = 0.0f; + t60.MidGain[1] = 0.0f; + t60.HFFilter.clear(); + t60.LFFilter.clear(); + } + + for(auto &gains : mEarly.CurrentGain) + std::fill(std::begin(gains), std::end(gains), 0.0f); + for(auto &gains : mEarly.PanGain) + std::fill(std::begin(gains), std::end(gains), 0.0f); + for(auto &gains : mLate.CurrentGain) + std::fill(std::begin(gains), std::end(gains), 0.0f); + for(auto &gains : mLate.PanGain) + std::fill(std::begin(gains), std::end(gains), 0.0f); + + /* Reset counters and offset base. */ + mFadeCount = 0; + std::fill(std::begin(mMaxUpdate), std::end(mMaxUpdate), BUFFERSIZE); + mOffset = 0; + + if(device->mAmbiOrder > 1) + { + mMixOut = &ReverbState::MixOutAmbiUp; + mOrderScales = BFormatDec::GetHFOrderScales(1, device->mAmbiOrder); + } + else + { + mMixOut = &ReverbState::MixOutPlain; + mOrderScales.fill(1.0f); + } + mAmbiSplitter[0][0].init(400.0f / frequency); + std::fill(mAmbiSplitter[0].begin()+1, mAmbiSplitter[0].end(), mAmbiSplitter[0][0]); + std::fill(mAmbiSplitter[1].begin(), mAmbiSplitter[1].end(), mAmbiSplitter[0][0]); + + return AL_TRUE; +} + +/************************************** + * Effect Update * + **************************************/ + +/* Calculate a decay coefficient given the length of each cycle and the time + * until the decay reaches -60 dB. + */ +inline ALfloat CalcDecayCoeff(const ALfloat length, const ALfloat decayTime) +{ return std::pow(REVERB_DECAY_GAIN, length/decayTime); } + +/* Calculate a decay length from a coefficient and the time until the decay + * reaches -60 dB. + */ +inline ALfloat CalcDecayLength(const ALfloat coeff, const ALfloat decayTime) +{ return std::log10(coeff) * decayTime / std::log10(REVERB_DECAY_GAIN); } + +/* Calculate an attenuation to be applied to the input of any echo models to + * compensate for modal density and decay time. + */ +inline ALfloat CalcDensityGain(const ALfloat a) +{ + /* The energy of a signal can be obtained by finding the area under the + * squared signal. This takes the form of Sum(x_n^2), where x is the + * amplitude for the sample n. + * + * Decaying feedback matches exponential decay of the form Sum(a^n), + * where a is the attenuation coefficient, and n is the sample. The area + * under this decay curve can be calculated as: 1 / (1 - a). + * + * Modifying the above equation to find the area under the squared curve + * (for energy) yields: 1 / (1 - a^2). Input attenuation can then be + * calculated by inverting the square root of this approximation, + * yielding: 1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2). + */ + return std::sqrt(1.0f - a*a); +} + +/* Calculate the scattering matrix coefficients given a diffusion factor. */ +inline ALvoid CalcMatrixCoeffs(const ALfloat diffusion, ALfloat *x, ALfloat *y) +{ + /* The matrix is of order 4, so n is sqrt(4 - 1). */ + ALfloat n{std::sqrt(3.0f)}; + ALfloat t{diffusion * std::atan(n)}; + + /* Calculate the first mixing matrix coefficient. */ + *x = std::cos(t); + /* Calculate the second mixing matrix coefficient. */ + *y = std::sin(t) / n; +} + +/* Calculate the limited HF ratio for use with the late reverb low-pass + * filters. + */ +ALfloat CalcLimitedHfRatio(const ALfloat hfRatio, const ALfloat airAbsorptionGainHF, + const ALfloat decayTime, const ALfloat SpeedOfSound) +{ + /* Find the attenuation due to air absorption in dB (converting delay + * time to meters using the speed of sound). Then reversing the decay + * equation, solve for HF ratio. The delay length is cancelled out of + * the equation, so it can be calculated once for all lines. + */ + ALfloat limitRatio{1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) * SpeedOfSound)}; + + /* Using the limit calculated above, apply the upper bound to the HF ratio. + */ + return minf(limitRatio, hfRatio); +} + + +/* Calculates the 3-band T60 damping coefficients for a particular delay line + * of specified length, using a combination of two shelf filter sections given + * decay times for each band split at two reference frequencies. + */ +void T60Filter::calcCoeffs(const ALfloat length, const ALfloat lfDecayTime, + const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lf0norm, + const ALfloat hf0norm) +{ + const ALfloat mfGain{CalcDecayCoeff(length, mfDecayTime)}; + const ALfloat lfGain{maxf(CalcDecayCoeff(length, lfDecayTime)/mfGain, 0.001f)}; + const ALfloat hfGain{maxf(CalcDecayCoeff(length, hfDecayTime)/mfGain, 0.001f)}; + + MidGain[1] = mfGain; + LFFilter.setParams(BiquadType::LowShelf, lfGain, lf0norm, + LFFilter.rcpQFromSlope(lfGain, 1.0f)); + HFFilter.setParams(BiquadType::HighShelf, hfGain, hf0norm, + HFFilter.rcpQFromSlope(hfGain, 1.0f)); +} + +/* Update the early reflection line lengths and gain coefficients. */ +void EarlyReflections::updateLines(const ALfloat density, const ALfloat diffusion, + const ALfloat decayTime, const ALfloat frequency) +{ + const ALfloat multiplier{CalcDelayLengthMult(density)}; + + /* Calculate the all-pass feed-back/forward coefficient. */ + VecAp.Coeff = std::sqrt(0.5f) * std::pow(diffusion, 2.0f); + + for(ALsizei i{0};i < NUM_LINES;i++) + { + /* Calculate the length (in seconds) of each all-pass line. */ + ALfloat length{EARLY_ALLPASS_LENGTHS[i] * multiplier}; + + /* Calculate the delay offset for each all-pass line. */ + VecAp.Offset[i][1] = float2int(length * frequency); + + /* Calculate the length (in seconds) of each delay line. */ + length = EARLY_LINE_LENGTHS[i] * multiplier; + + /* Calculate the delay offset for each delay line. */ + Offset[i][1] = float2int(length * frequency); + + /* Calculate the gain (coefficient) for each line. */ + Coeff[i][1] = CalcDecayCoeff(length, decayTime); + } +} + +/* Update the late reverb line lengths and T60 coefficients. */ +void LateReverb::updateLines(const ALfloat density, const ALfloat diffusion, + const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, + const ALfloat lf0norm, const ALfloat hf0norm, const ALfloat frequency) +{ + /* Scaling factor to convert the normalized reference frequencies from + * representing 0...freq to 0...max_reference. + */ + const ALfloat norm_weight_factor{frequency / AL_EAXREVERB_MAX_HFREFERENCE}; + + const ALfloat late_allpass_avg{ + std::accumulate(LATE_ALLPASS_LENGTHS.begin(), LATE_ALLPASS_LENGTHS.end(), 0.0f) / + float{LATE_ALLPASS_LENGTHS_size}}; + + /* To compensate for changes in modal density and decay time of the late + * reverb signal, the input is attenuated based on the maximal energy of + * the outgoing signal. This approximation is used to keep the apparent + * energy of the signal equal for all ranges of density and decay time. + * + * The average length of the delay lines is used to calculate the + * attenuation coefficient. + */ + const ALfloat multiplier{CalcDelayLengthMult(density)}; + ALfloat length{std::accumulate(LATE_LINE_LENGTHS.begin(), LATE_LINE_LENGTHS.end(), 0.0f) / + float{LATE_LINE_LENGTHS_size} * multiplier}; + length += late_allpass_avg * multiplier; + /* The density gain calculation uses an average decay time weighted by + * approximate bandwidth. This attempts to compensate for losses of energy + * that reduce decay time due to scattering into highly attenuated bands. + */ + const ALfloat bandWeights[3]{ + lf0norm*norm_weight_factor, + hf0norm*norm_weight_factor - lf0norm*norm_weight_factor, + 1.0f - hf0norm*norm_weight_factor}; + DensityGain[1] = CalcDensityGain( + CalcDecayCoeff(length, + bandWeights[0]*lfDecayTime + bandWeights[1]*mfDecayTime + bandWeights[2]*hfDecayTime + ) + ); + + /* Calculate the all-pass feed-back/forward coefficient. */ + VecAp.Coeff = std::sqrt(0.5f) * std::pow(diffusion, 2.0f); + + for(ALsizei i{0};i < NUM_LINES;i++) + { + /* Calculate the length (in seconds) of each all-pass line. */ + length = LATE_ALLPASS_LENGTHS[i] * multiplier; + + /* Calculate the delay offset for each all-pass line. */ + VecAp.Offset[i][1] = float2int(length * frequency); + + /* Calculate the length (in seconds) of each delay line. */ + length = LATE_LINE_LENGTHS[i] * multiplier; + + /* Calculate the delay offset for each delay line. */ + Offset[i][1] = float2int(length*frequency + 0.5f); + + /* Approximate the absorption that the vector all-pass would exhibit + * given the current diffusion so we don't have to process a full T60 + * filter for each of its four lines. + */ + length += lerp(LATE_ALLPASS_LENGTHS[i], late_allpass_avg, diffusion) * multiplier; + + /* Calculate the T60 damping coefficients for each line. */ + T60[i].calcCoeffs(length, lfDecayTime, mfDecayTime, hfDecayTime, lf0norm, hf0norm); + } +} + + +/* Update the offsets for the main effect delay line. */ +void ReverbState::updateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, + const ALfloat density, const ALfloat decayTime, const ALfloat frequency) +{ + const ALfloat multiplier{CalcDelayLengthMult(density)}; + + /* Early reflection taps are decorrelated by means of an average room + * reflection approximation described above the definition of the taps. + * This approximation is linear and so the above density multiplier can + * be applied to adjust the width of the taps. A single-band decay + * coefficient is applied to simulate initial attenuation and absorption. + * + * Late reverb taps are based on the late line lengths to allow a zero- + * delay path and offsets that would continue the propagation naturally + * into the late lines. + */ + for(ALsizei i{0};i < NUM_LINES;i++) + { + ALfloat length{earlyDelay + EARLY_TAP_LENGTHS[i]*multiplier}; + mEarlyDelayTap[i][1] = float2int(length * frequency); + + length = EARLY_TAP_LENGTHS[i]*multiplier; + mEarlyDelayCoeff[i][1] = CalcDecayCoeff(length, decayTime); + + length = lateDelay + (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS.front()) / + float{LATE_LINE_LENGTHS_size} * multiplier; + mLateDelayTap[i][1] = mLateFeedTap + float2int(length * frequency); + } +} + +/* Creates a transform matrix given a reverb vector. The vector pans the reverb + * reflections toward the given direction, using its magnitude (up to 1) as a + * focal strength. This function results in a B-Format transformation matrix + * that spatially focuses the signal in the desired direction. + */ +alu::Matrix GetTransformFromVector(const ALfloat *vec) +{ + /* Normalize the panning vector according to the N3D scale, which has an + * extra sqrt(3) term on the directional components. Converting from OpenAL + * to B-Format also requires negating X (ACN 1) and Z (ACN 3). Note however + * that the reverb panning vectors use left-handed coordinates, unlike the + * rest of OpenAL which use right-handed. This is fixed by negating Z, + * which cancels out with the B-Format Z negation. + */ + ALfloat norm[3]; + ALfloat mag{std::sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2])}; + if(mag > 1.0f) + { + norm[0] = vec[0] / mag * -al::MathDefs::Sqrt3(); + norm[1] = vec[1] / mag * al::MathDefs::Sqrt3(); + norm[2] = vec[2] / mag * al::MathDefs::Sqrt3(); + mag = 1.0f; + } + else + { + /* If the magnitude is less than or equal to 1, just apply the sqrt(3) + * term. There's no need to renormalize the magnitude since it would + * just be reapplied in the matrix. + */ + norm[0] = vec[0] * -al::MathDefs::Sqrt3(); + norm[1] = vec[1] * al::MathDefs::Sqrt3(); + norm[2] = vec[2] * al::MathDefs::Sqrt3(); + } + + return alu::Matrix{ + 1.0f, 0.0f, 0.0f, 0.0f, + norm[0], 1.0f-mag, 0.0f, 0.0f, + norm[1], 0.0f, 1.0f-mag, 0.0f, + norm[2], 0.0f, 0.0f, 1.0f-mag + }; +} + +/* Update the early and late 3D panning gains. */ +void ReverbState::update3DPanning(const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, + const ALfloat earlyGain, const ALfloat lateGain, const EffectTarget &target) +{ + /* Create matrices that transform a B-Format signal according to the + * panning vectors. + */ + const alu::Matrix earlymat{GetTransformFromVector(ReflectionsPan)}; + const alu::Matrix latemat{GetTransformFromVector(LateReverbPan)}; + + mOutTarget = target.Main->Buffer; + for(ALsizei i{0};i < NUM_LINES;i++) + { + const ALfloat coeffs[MAX_AMBI_CHANNELS]{earlymat[0][i], earlymat[1][i], earlymat[2][i], + earlymat[3][i]}; + ComputePanGains(target.Main, coeffs, earlyGain, mEarly.PanGain[i]); + } + for(ALsizei i{0};i < NUM_LINES;i++) + { + const ALfloat coeffs[MAX_AMBI_CHANNELS]{latemat[0][i], latemat[1][i], latemat[2][i], + latemat[3][i]}; + ComputePanGains(target.Main, coeffs, lateGain, mLate.PanGain[i]); + } +} + +void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, const EffectProps *props, const EffectTarget target) +{ + const ALCdevice *Device{Context->Device}; + const ALlistener &Listener = Context->Listener; + const auto frequency = static_cast(Device->Frequency); + + /* Calculate the master filters */ + ALfloat hf0norm{minf(props->Reverb.HFReference / frequency, 0.49f)}; + /* Restrict the filter gains from going below -60dB to keep the filter from + * killing most of the signal. + */ + ALfloat gainhf{maxf(props->Reverb.GainHF, 0.001f)}; + mFilter[0].Lp.setParams(BiquadType::HighShelf, gainhf, hf0norm, + mFilter[0].Lp.rcpQFromSlope(gainhf, 1.0f)); + ALfloat lf0norm{minf(props->Reverb.LFReference / frequency, 0.49f)}; + ALfloat gainlf{maxf(props->Reverb.GainLF, 0.001f)}; + mFilter[0].Hp.setParams(BiquadType::LowShelf, gainlf, lf0norm, + mFilter[0].Hp.rcpQFromSlope(gainlf, 1.0f)); + for(ALsizei i{1};i < NUM_LINES;i++) + { + mFilter[i].Lp.copyParamsFrom(mFilter[0].Lp); + mFilter[i].Hp.copyParamsFrom(mFilter[0].Hp); + } + + /* Update the main effect delay and associated taps. */ + updateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay, + props->Reverb.Density, props->Reverb.DecayTime, frequency); + + /* Update the early lines. */ + mEarly.updateLines(props->Reverb.Density, props->Reverb.Diffusion, props->Reverb.DecayTime, + frequency); + + /* Get the mixing matrix coefficients. */ + CalcMatrixCoeffs(props->Reverb.Diffusion, &mMixX, &mMixY); + + /* If the HF limit parameter is flagged, calculate an appropriate limit + * based on the air absorption parameter. + */ + ALfloat hfRatio{props->Reverb.DecayHFRatio}; + if(props->Reverb.DecayHFLimit && props->Reverb.AirAbsorptionGainHF < 1.0f) + hfRatio = CalcLimitedHfRatio(hfRatio, props->Reverb.AirAbsorptionGainHF, + props->Reverb.DecayTime, Listener.Params.ReverbSpeedOfSound + ); + + /* Calculate the LF/HF decay times. */ + const ALfloat lfDecayTime{clampf(props->Reverb.DecayTime * props->Reverb.DecayLFRatio, + AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME)}; + const ALfloat hfDecayTime{clampf(props->Reverb.DecayTime * hfRatio, + AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME)}; + + /* Update the late lines. */ + mLate.updateLines(props->Reverb.Density, props->Reverb.Diffusion, lfDecayTime, + props->Reverb.DecayTime, hfDecayTime, lf0norm, hf0norm, frequency); + + /* Update early and late 3D panning. */ + const ALfloat gain{props->Reverb.Gain * Slot->Params.Gain * ReverbBoost}; + update3DPanning(props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, + props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain, target); + + /* Calculate the max update size from the smallest relevant delay. */ + mMaxUpdate[1] = mini(BUFFERSIZE, mini(mEarly.Offset[0][1], mLate.Offset[0][1])); + + /* Determine if delay-line cross-fading is required. Density is essentially + * a master control for the feedback delays, so changes the offsets of many + * delay lines. + */ + if(mParams.Density != props->Reverb.Density || + /* Diffusion and decay times influences the decay rate (gain) of the + * late reverb T60 filter. + */ + mParams.Diffusion != props->Reverb.Diffusion || + mParams.DecayTime != props->Reverb.DecayTime || + mParams.HFDecayTime != hfDecayTime || + mParams.LFDecayTime != lfDecayTime || + /* HF/LF References control the weighting used to calculate the density + * gain. + */ + mParams.HFReference != props->Reverb.HFReference || + mParams.LFReference != props->Reverb.LFReference) + mFadeCount = 0; + mParams.Density = props->Reverb.Density; + mParams.Diffusion = props->Reverb.Diffusion; + mParams.DecayTime = props->Reverb.DecayTime; + mParams.HFDecayTime = hfDecayTime; + mParams.LFDecayTime = lfDecayTime; + mParams.HFReference = props->Reverb.HFReference; + mParams.LFReference = props->Reverb.LFReference; +} + + +/************************************** + * Effect Processing * + **************************************/ + +/* Applies a scattering matrix to the 4-line (vector) input. This is used + * for both the below vector all-pass model and to perform modal feed-back + * delay network (FDN) mixing. + * + * The matrix is derived from a skew-symmetric matrix to form a 4D rotation + * matrix with a single unitary rotational parameter: + * + * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2 + * [ -a, d, c, -b ] + * [ -b, -c, d, a ] + * [ -c, b, -a, d ] + * + * The rotation is constructed from the effect's diffusion parameter, + * yielding: + * + * 1 = x^2 + 3 y^2 + * + * Where a, b, and c are the coefficient y with differing signs, and d is the + * coefficient x. The final matrix is thus: + * + * [ x, y, -y, y ] n = sqrt(matrix_order - 1) + * [ -y, x, y, y ] t = diffusion_parameter * atan(n) + * [ y, -y, x, y ] x = cos(t) + * [ -y, -y, -y, x ] y = sin(t) / n + * + * Any square orthogonal matrix with an order that is a power of two will + * work (where ^T is transpose, ^-1 is inverse): + * + * M^T = M^-1 + * + * Using that knowledge, finding an appropriate matrix can be accomplished + * naively by searching all combinations of: + * + * M = D + S - S^T + * + * Where D is a diagonal matrix (of x), and S is a triangular matrix (of y) + * whose combination of signs are being iterated. + */ +inline void VectorPartialScatter(ALfloat *RESTRICT out, const ALfloat *RESTRICT in, + const ALfloat xCoeff, const ALfloat yCoeff) +{ + out[0] = xCoeff*in[0] + yCoeff*( in[1] + -in[2] + in[3]); + out[1] = xCoeff*in[1] + yCoeff*(-in[0] + in[2] + in[3]); + out[2] = xCoeff*in[2] + yCoeff*( in[0] + -in[1] + in[3]); + out[3] = xCoeff*in[3] + yCoeff*(-in[0] + -in[1] + -in[2] ); +} + +/* Utilizes the above, but reverses the input channels. */ +void VectorScatterRevDelayIn(const DelayLineI delay, ALint offset, const ALfloat xCoeff, + const ALfloat yCoeff, const ALsizei base, const al::span in, + const ALsizei count) +{ + ASSUME(base >= 0); + ASSUME(count > 0); + + for(ALsizei i{0};i < count;) + { + offset &= delay.Mask; + ALsizei td{mini(delay.Mask+1 - offset, count-i)}; + do { + ALfloat f[NUM_LINES]; + for(ALsizei j{0};j < NUM_LINES;j++) + f[NUM_LINES-1-j] = in[j][base+i]; + ++i; + + VectorPartialScatter(delay.Line[offset++], f, xCoeff, yCoeff); + } while(--td); + } +} + +/* This applies a Gerzon multiple-in/multiple-out (MIMO) vector all-pass + * filter to the 4-line input. + * + * It works by vectorizing a regular all-pass filter and replacing the delay + * element with a scattering matrix (like the one above) and a diagonal + * matrix of delay elements. + * + * Two static specializations are used for transitional (cross-faded) delay + * line processing and non-transitional processing. + */ +void VecAllpass::processUnfaded(const al::span samples, ALsizei offset, + const ALfloat xCoeff, const ALfloat yCoeff, const ALsizei todo) +{ + const DelayLineI delay{Delay}; + const ALfloat feedCoeff{Coeff}; + + ASSUME(todo > 0); + + ALsizei vap_offset[NUM_LINES]; + for(ALsizei j{0};j < NUM_LINES;j++) + vap_offset[j] = offset - Offset[j][0]; + for(ALsizei i{0};i < todo;) + { + for(ALsizei j{0};j < NUM_LINES;j++) + vap_offset[j] &= delay.Mask; + offset &= delay.Mask; + + ALsizei maxoff{offset}; + for(ALsizei j{0};j < NUM_LINES;j++) + maxoff = maxi(maxoff, vap_offset[j]); + ALsizei td{mini(delay.Mask+1 - maxoff, todo - i)}; + + do { + ALfloat f[NUM_LINES]; + for(ALsizei j{0};j < NUM_LINES;j++) + { + const ALfloat input{samples[j][i]}; + const ALfloat out{delay.Line[vap_offset[j]++][j] - feedCoeff*input}; + f[j] = input + feedCoeff*out; + + samples[j][i] = out; + } + ++i; + + VectorPartialScatter(delay.Line[offset++], f, xCoeff, yCoeff); + } while(--td); + } +} +void VecAllpass::processFaded(const al::span samples, ALsizei offset, + const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, const ALsizei todo) +{ + const DelayLineI delay{Delay}; + const ALfloat feedCoeff{Coeff}; + + ASSUME(todo > 0); + + fade *= 1.0f/FADE_SAMPLES; + ALsizei vap_offset[NUM_LINES][2]; + for(ALsizei j{0};j < NUM_LINES;j++) + { + vap_offset[j][0] = offset - Offset[j][0]; + vap_offset[j][1] = offset - Offset[j][1]; + } + for(ALsizei i{0};i < todo;) + { + for(ALsizei j{0};j < NUM_LINES;j++) + { + vap_offset[j][0] &= delay.Mask; + vap_offset[j][1] &= delay.Mask; + } + offset &= delay.Mask; + + ALsizei maxoff{offset}; + for(ALsizei j{0};j < NUM_LINES;j++) + maxoff = maxi(maxoff, maxi(vap_offset[j][0], vap_offset[j][1])); + ALsizei td{mini(delay.Mask+1 - maxoff, todo - i)}; + + do { + fade += FadeStep; + ALfloat f[NUM_LINES]; + for(ALsizei j{0};j < NUM_LINES;j++) + f[j] = delay.Line[vap_offset[j][0]++][j]*(1.0f-fade) + + delay.Line[vap_offset[j][1]++][j]*fade; + + for(ALsizei j{0};j < NUM_LINES;j++) + { + const ALfloat input{samples[j][i]}; + const ALfloat out{f[j] - feedCoeff*input}; + f[j] = input + feedCoeff*out; + + samples[j][i] = out; + } + ++i; + + VectorPartialScatter(delay.Line[offset++], f, xCoeff, yCoeff); + } while(--td); + } +} + +/* This generates early reflections. + * + * This is done by obtaining the primary reflections (those arriving from the + * same direction as the source) from the main delay line. These are + * attenuated and all-pass filtered (based on the diffusion parameter). + * + * The early lines are then fed in reverse (according to the approximately + * opposite spatial location of the A-Format lines) to create the secondary + * reflections (those arriving from the opposite direction as the source). + * + * The early response is then completed by combining the primary reflections + * with the delayed and attenuated output from the early lines. + * + * Finally, the early response is reversed, scattered (based on diffusion), + * and fed into the late reverb section of the main delay line. + * + * Two static specializations are used for transitional (cross-faded) delay + * line processing and non-transitional processing. + */ +void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei todo, + const ALsizei base, const al::span out) +{ + const al::span temps{State->mTempSamples}; + const DelayLineI early_delay{State->mEarly.Delay}; + const DelayLineI main_delay{State->mDelay}; + const ALfloat mixX{State->mMixX}; + const ALfloat mixY{State->mMixY}; + + ASSUME(todo > 0); + + /* First, load decorrelated samples from the main delay line as the primary + * reflections. + */ + for(ALsizei j{0};j < NUM_LINES;j++) + { + ALsizei early_delay_tap{offset - State->mEarlyDelayTap[j][0]}; + const ALfloat coeff{State->mEarlyDelayCoeff[j][0]}; + for(ALsizei i{0};i < todo;) + { + early_delay_tap &= main_delay.Mask; + ALsizei td{mini(main_delay.Mask+1 - early_delay_tap, todo - i)}; + do { + temps[j][i++] = main_delay.Line[early_delay_tap++][j] * coeff; + } while(--td); + } + } + + /* Apply a vector all-pass, to help color the initial reflections based on + * the diffusion strength. + */ + State->mEarly.VecAp.processUnfaded(temps, offset, mixX, mixY, todo); + + /* Apply a delay and bounce to generate secondary reflections, combine with + * the primary reflections and write out the result for mixing. + */ + for(ALsizei j{0};j < NUM_LINES;j++) + { + ALint feedb_tap{offset - State->mEarly.Offset[j][0]}; + const ALfloat feedb_coeff{State->mEarly.Coeff[j][0]}; + + ASSUME(base >= 0); + for(ALsizei i{0};i < todo;) + { + feedb_tap &= early_delay.Mask; + ALsizei td{mini(early_delay.Mask+1 - feedb_tap, todo - i)}; + do { + out[j][base+i] = temps[j][i] + early_delay.Line[feedb_tap++][j]*feedb_coeff; + ++i; + } while(--td); + } + } + for(ALsizei j{0};j < NUM_LINES;j++) + early_delay.write(offset, NUM_LINES-1-j, temps[j].data(), todo); + + /* Also write the result back to the main delay line for the late reverb + * stage to pick up at the appropriate time, appplying a scatter and + * bounce to improve the initial diffusion in the late reverb. + */ + const ALsizei late_feed_tap{offset - State->mLateFeedTap}; + VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, + {out.cbegin(), out.cend()}, todo); +} +void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, + const ALfloat fade, const ALsizei base, const al::span out) +{ + const al::span temps{State->mTempSamples}; + const DelayLineI early_delay{State->mEarly.Delay}; + const DelayLineI main_delay{State->mDelay}; + const ALfloat mixX{State->mMixX}; + const ALfloat mixY{State->mMixY}; + + ASSUME(todo > 0); + + for(ALsizei j{0};j < NUM_LINES;j++) + { + ALsizei early_delay_tap0{offset - State->mEarlyDelayTap[j][0]}; + ALsizei early_delay_tap1{offset - State->mEarlyDelayTap[j][1]}; + const ALfloat oldCoeff{State->mEarlyDelayCoeff[j][0]}; + const ALfloat oldCoeffStep{-oldCoeff / FADE_SAMPLES}; + const ALfloat newCoeffStep{State->mEarlyDelayCoeff[j][1] / FADE_SAMPLES}; + ALfloat fadeCount{fade}; + + for(ALsizei i{0};i < todo;) + { + early_delay_tap0 &= main_delay.Mask; + early_delay_tap1 &= main_delay.Mask; + ALsizei td{mini(main_delay.Mask+1 - maxi(early_delay_tap0, early_delay_tap1), todo-i)}; + do { + fadeCount += 1.0f; + const ALfloat fade0{oldCoeff + oldCoeffStep*fadeCount}; + const ALfloat fade1{newCoeffStep*fadeCount}; + temps[j][i++] = + main_delay.Line[early_delay_tap0++][j]*fade0 + + main_delay.Line[early_delay_tap1++][j]*fade1; + } while(--td); + } + } + + State->mEarly.VecAp.processFaded(temps, offset, mixX, mixY, fade, todo); + + for(ALsizei j{0};j < NUM_LINES;j++) + { + ALint feedb_tap0{offset - State->mEarly.Offset[j][0]}; + ALint feedb_tap1{offset - State->mEarly.Offset[j][1]}; + const ALfloat feedb_oldCoeff{State->mEarly.Coeff[j][0]}; + const ALfloat feedb_oldCoeffStep{-feedb_oldCoeff / FADE_SAMPLES}; + const ALfloat feedb_newCoeffStep{State->mEarly.Coeff[j][1] / FADE_SAMPLES}; + ALfloat fadeCount{fade}; + + ASSUME(base >= 0); + for(ALsizei i{0};i < todo;) + { + feedb_tap0 &= early_delay.Mask; + feedb_tap1 &= early_delay.Mask; + ALsizei td{mini(early_delay.Mask+1 - maxi(feedb_tap0, feedb_tap1), todo - i)}; + + do { + fadeCount += 1.0f; + const ALfloat fade0{feedb_oldCoeff + feedb_oldCoeffStep*fadeCount}; + const ALfloat fade1{feedb_newCoeffStep*fadeCount}; + out[j][base+i] = temps[j][i] + + early_delay.Line[feedb_tap0++][j]*fade0 + + early_delay.Line[feedb_tap1++][j]*fade1; + ++i; + } while(--td); + } + } + for(ALsizei j{0};j < NUM_LINES;j++) + early_delay.write(offset, NUM_LINES-1-j, temps[j].data(), todo); + + const ALsizei late_feed_tap{offset - State->mLateFeedTap}; + VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, + {out.cbegin(), out.cend()}, todo); +} + +/* This generates the reverb tail using a modified feed-back delay network + * (FDN). + * + * Results from the early reflections are mixed with the output from the late + * delay lines. + * + * The late response is then completed by T60 and all-pass filtering the mix. + * + * Finally, the lines are reversed (so they feed their opposite directions) + * and scattered with the FDN matrix before re-feeding the delay lines. + * + * Two variations are made, one for for transitional (cross-faded) delay line + * processing and one for non-transitional processing. + */ +void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei todo, + const ALsizei base, const al::span out) +{ + const al::span temps{State->mTempSamples}; + const DelayLineI late_delay{State->mLate.Delay}; + const DelayLineI main_delay{State->mDelay}; + const ALfloat mixX{State->mMixX}; + const ALfloat mixY{State->mMixY}; + + ASSUME(todo > 0); + + /* First, load decorrelated samples from the main and feedback delay lines. + * Filter the signal to apply its frequency-dependent decay. + */ + for(ALsizei j{0};j < NUM_LINES;j++) + { + ALsizei late_delay_tap{offset - State->mLateDelayTap[j][0]}; + ALsizei late_feedb_tap{offset - State->mLate.Offset[j][0]}; + const ALfloat midGain{State->mLate.T60[j].MidGain[0]}; + const ALfloat densityGain{State->mLate.DensityGain[0] * midGain}; + for(ALsizei i{0};i < todo;) + { + late_delay_tap &= main_delay.Mask; + late_feedb_tap &= late_delay.Mask; + ALsizei td{mini( + mini(main_delay.Mask+1 - late_delay_tap, late_delay.Mask+1 - late_feedb_tap), + todo - i)}; + do { + temps[j][i++] = + main_delay.Line[late_delay_tap++][j]*densityGain + + late_delay.Line[late_feedb_tap++][j]*midGain; + } while(--td); + } + State->mLate.T60[j].process(temps[j].data(), todo); + } + + /* Apply a vector all-pass to improve micro-surface diffusion, and write + * out the results for mixing. + */ + State->mLate.VecAp.processUnfaded(temps, offset, mixX, mixY, todo); + + for(ALsizei j{0};j < NUM_LINES;j++) + std::copy_n(temps[j].begin(), todo, out[j].begin()+base); + + /* Finally, scatter and bounce the results to refeed the feedback buffer. */ + VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, + {out.cbegin(), out.cend()}, todo); +} +void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, + const ALfloat fade, const ALsizei base, const al::span out) +{ + const al::span temps{State->mTempSamples}; + const DelayLineI late_delay{State->mLate.Delay}; + const DelayLineI main_delay{State->mDelay}; + const ALfloat mixX{State->mMixX}; + const ALfloat mixY{State->mMixY}; + + ASSUME(todo > 0); + + for(ALsizei j{0};j < NUM_LINES;j++) + { + const ALfloat oldMidGain{State->mLate.T60[j].MidGain[0]}; + const ALfloat midGain{State->mLate.T60[j].MidGain[1]}; + const ALfloat oldMidStep{-oldMidGain / FADE_SAMPLES}; + const ALfloat midStep{midGain / FADE_SAMPLES}; + const ALfloat oldDensityGain{State->mLate.DensityGain[0] * oldMidGain}; + const ALfloat densityGain{State->mLate.DensityGain[1] * midGain}; + const ALfloat oldDensityStep{-oldDensityGain / FADE_SAMPLES}; + const ALfloat densityStep{densityGain / FADE_SAMPLES}; + ALsizei late_delay_tap0{offset - State->mLateDelayTap[j][0]}; + ALsizei late_delay_tap1{offset - State->mLateDelayTap[j][1]}; + ALsizei late_feedb_tap0{offset - State->mLate.Offset[j][0]}; + ALsizei late_feedb_tap1{offset - State->mLate.Offset[j][1]}; + ALfloat fadeCount{fade}; + + for(ALsizei i{0};i < todo;) + { + late_delay_tap0 &= main_delay.Mask; + late_delay_tap1 &= main_delay.Mask; + late_feedb_tap0 &= late_delay.Mask; + late_feedb_tap1 &= late_delay.Mask; + ALsizei td{mini( + mini(main_delay.Mask+1 - maxi(late_delay_tap0, late_delay_tap1), + late_delay.Mask+1 - maxi(late_feedb_tap0, late_feedb_tap1)), + todo - i)}; + do { + fadeCount += 1.0f; + const ALfloat fade0{oldDensityGain + oldDensityStep*fadeCount}; + const ALfloat fade1{densityStep*fadeCount}; + const ALfloat gfade0{oldMidGain + oldMidStep*fadeCount}; + const ALfloat gfade1{midStep*fadeCount}; + temps[j][i++] = + main_delay.Line[late_delay_tap0++][j]*fade0 + + main_delay.Line[late_delay_tap1++][j]*fade1 + + late_delay.Line[late_feedb_tap0++][j]*gfade0 + + late_delay.Line[late_feedb_tap1++][j]*gfade1; + } while(--td); + } + State->mLate.T60[j].process(temps[j].data(), todo); + } + + State->mLate.VecAp.processFaded(temps, offset, mixX, mixY, fade, todo); + + for(ALsizei j{0};j < NUM_LINES;j++) + std::copy_n(temps[j].begin(), todo, out[j].begin()+base); + + VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, + {out.cbegin(), out.cend()}, todo); +} + +void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) +{ + ALsizei fadeCount{mFadeCount}; + + ASSUME(samplesToDo > 0); + + /* Convert B-Format to A-Format for processing. */ + const al::span afmt{mTempSamples}; + for(ALsizei c{0};c < NUM_LINES;c++) + { + std::fill_n(afmt[c].begin(), samplesToDo, 0.0f); + MixRowSamples(afmt[c], B2A[c], {samplesIn, samplesIn+numInput}, 0, samplesToDo); + + /* Band-pass the incoming samples. */ + mFilter[c].Lp.process(afmt[c].data(), afmt[c].data(), samplesToDo); + mFilter[c].Hp.process(afmt[c].data(), afmt[c].data(), samplesToDo); + } + + /* Process reverb for these samples. */ + for(ALsizei base{0};base < samplesToDo;) + { + ALsizei todo{samplesToDo - base}; + /* If cross-fading, don't do more samples than there are to fade. */ + if(FADE_SAMPLES-fadeCount > 0) + { + todo = mini(todo, FADE_SAMPLES-fadeCount); + todo = mini(todo, mMaxUpdate[0]); + } + todo = mini(todo, mMaxUpdate[1]); + ASSUME(todo > 0 && todo <= BUFFERSIZE); + + const ALsizei offset{mOffset + base}; + ASSUME(offset >= 0); + + /* Feed the initial delay line. */ + for(ALsizei c{0};c < NUM_LINES;c++) + mDelay.write(offset, c, afmt[c].data()+base, todo); + + /* Process the samples for reverb. */ + if(UNLIKELY(fadeCount < FADE_SAMPLES)) + { + auto fade = static_cast(fadeCount); + + /* Generate early reflections and late reverb. */ + EarlyReflection_Faded(this, offset, todo, fade, base, mEarlyBuffer); + + LateReverb_Faded(this, offset, todo, fade, base, mLateBuffer); + + /* Step fading forward. */ + fadeCount += todo; + if(fadeCount >= FADE_SAMPLES) + { + /* Update the cross-fading delay line taps. */ + fadeCount = FADE_SAMPLES; + for(ALsizei c{0};c < NUM_LINES;c++) + { + mEarlyDelayTap[c][0] = mEarlyDelayTap[c][1]; + mEarlyDelayCoeff[c][0] = mEarlyDelayCoeff[c][1]; + mEarly.VecAp.Offset[c][0] = mEarly.VecAp.Offset[c][1]; + mEarly.Offset[c][0] = mEarly.Offset[c][1]; + mEarly.Coeff[c][0] = mEarly.Coeff[c][1]; + mLateDelayTap[c][0] = mLateDelayTap[c][1]; + mLate.VecAp.Offset[c][0] = mLate.VecAp.Offset[c][1]; + mLate.Offset[c][0] = mLate.Offset[c][1]; + mLate.T60[c].MidGain[0] = mLate.T60[c].MidGain[1]; + } + mLate.DensityGain[0] = mLate.DensityGain[1]; + mMaxUpdate[0] = mMaxUpdate[1]; + } + } + else + { + /* Generate early reflections and late reverb. */ + EarlyReflection_Unfaded(this, offset, todo, base, mEarlyBuffer); + + LateReverb_Unfaded(this, offset, todo, base, mLateBuffer); + } + + base += todo; + } + mOffset = (mOffset+samplesToDo) & 0x3fffffff; + mFadeCount = fadeCount; + + /* Finally, mix early reflections and late reverb. */ + (this->*mMixOut)(samplesOut, samplesToDo); +} + + +void EAXReverb_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val) +{ + switch(param) + { + case AL_EAXREVERB_DECAY_HFLIMIT: + if(!(val >= AL_EAXREVERB_MIN_DECAY_HFLIMIT && val <= AL_EAXREVERB_MAX_DECAY_HFLIMIT)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay hflimit out of range"); + props->Reverb.DecayHFLimit = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb integer property 0x%04x", + param); + } +} +void EAXReverb_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) +{ EAXReverb_setParami(props, context, param, vals[0]); } +void EAXReverb_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_EAXREVERB_DENSITY: + if(!(val >= AL_EAXREVERB_MIN_DENSITY && val <= AL_EAXREVERB_MAX_DENSITY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb density out of range"); + props->Reverb.Density = val; + break; + + case AL_EAXREVERB_DIFFUSION: + if(!(val >= AL_EAXREVERB_MIN_DIFFUSION && val <= AL_EAXREVERB_MAX_DIFFUSION)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb diffusion out of range"); + props->Reverb.Diffusion = val; + break; + + case AL_EAXREVERB_GAIN: + if(!(val >= AL_EAXREVERB_MIN_GAIN && val <= AL_EAXREVERB_MAX_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb gain out of range"); + props->Reverb.Gain = val; + break; + + case AL_EAXREVERB_GAINHF: + if(!(val >= AL_EAXREVERB_MIN_GAINHF && val <= AL_EAXREVERB_MAX_GAINHF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb gainhf out of range"); + props->Reverb.GainHF = val; + break; + + case AL_EAXREVERB_GAINLF: + if(!(val >= AL_EAXREVERB_MIN_GAINLF && val <= AL_EAXREVERB_MAX_GAINLF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb gainlf out of range"); + props->Reverb.GainLF = val; + break; + + case AL_EAXREVERB_DECAY_TIME: + if(!(val >= AL_EAXREVERB_MIN_DECAY_TIME && val <= AL_EAXREVERB_MAX_DECAY_TIME)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay time out of range"); + props->Reverb.DecayTime = val; + break; + + case AL_EAXREVERB_DECAY_HFRATIO: + if(!(val >= AL_EAXREVERB_MIN_DECAY_HFRATIO && val <= AL_EAXREVERB_MAX_DECAY_HFRATIO)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay hfratio out of range"); + props->Reverb.DecayHFRatio = val; + break; + + case AL_EAXREVERB_DECAY_LFRATIO: + if(!(val >= AL_EAXREVERB_MIN_DECAY_LFRATIO && val <= AL_EAXREVERB_MAX_DECAY_LFRATIO)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay lfratio out of range"); + props->Reverb.DecayLFRatio = val; + break; + + case AL_EAXREVERB_REFLECTIONS_GAIN: + if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_GAIN && val <= AL_EAXREVERB_MAX_REFLECTIONS_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb reflections gain out of range"); + props->Reverb.ReflectionsGain = val; + break; + + case AL_EAXREVERB_REFLECTIONS_DELAY: + if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_DELAY && val <= AL_EAXREVERB_MAX_REFLECTIONS_DELAY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb reflections delay out of range"); + props->Reverb.ReflectionsDelay = val; + break; + + case AL_EAXREVERB_LATE_REVERB_GAIN: + if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_GAIN && val <= AL_EAXREVERB_MAX_LATE_REVERB_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb late reverb gain out of range"); + props->Reverb.LateReverbGain = val; + break; + + case AL_EAXREVERB_LATE_REVERB_DELAY: + if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_DELAY && val <= AL_EAXREVERB_MAX_LATE_REVERB_DELAY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb late reverb delay out of range"); + props->Reverb.LateReverbDelay = val; + break; + + case AL_EAXREVERB_AIR_ABSORPTION_GAINHF: + if(!(val >= AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb air absorption gainhf out of range"); + props->Reverb.AirAbsorptionGainHF = val; + break; + + case AL_EAXREVERB_ECHO_TIME: + if(!(val >= AL_EAXREVERB_MIN_ECHO_TIME && val <= AL_EAXREVERB_MAX_ECHO_TIME)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb echo time out of range"); + props->Reverb.EchoTime = val; + break; + + case AL_EAXREVERB_ECHO_DEPTH: + if(!(val >= AL_EAXREVERB_MIN_ECHO_DEPTH && val <= AL_EAXREVERB_MAX_ECHO_DEPTH)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb echo depth out of range"); + props->Reverb.EchoDepth = val; + break; + + case AL_EAXREVERB_MODULATION_TIME: + if(!(val >= AL_EAXREVERB_MIN_MODULATION_TIME && val <= AL_EAXREVERB_MAX_MODULATION_TIME)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb modulation time out of range"); + props->Reverb.ModulationTime = val; + break; + + case AL_EAXREVERB_MODULATION_DEPTH: + if(!(val >= AL_EAXREVERB_MIN_MODULATION_DEPTH && val <= AL_EAXREVERB_MAX_MODULATION_DEPTH)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb modulation depth out of range"); + props->Reverb.ModulationDepth = val; + break; + + case AL_EAXREVERB_HFREFERENCE: + if(!(val >= AL_EAXREVERB_MIN_HFREFERENCE && val <= AL_EAXREVERB_MAX_HFREFERENCE)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb hfreference out of range"); + props->Reverb.HFReference = val; + break; + + case AL_EAXREVERB_LFREFERENCE: + if(!(val >= AL_EAXREVERB_MIN_LFREFERENCE && val <= AL_EAXREVERB_MAX_LFREFERENCE)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb lfreference out of range"); + props->Reverb.LFReference = val; + break; + + case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR: + if(!(val >= AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb room rolloff factor out of range"); + props->Reverb.RoomRolloffFactor = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", + param); + } +} +void EAXReverb_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + switch(param) + { + case AL_EAXREVERB_REFLECTIONS_PAN: + if(!(std::isfinite(vals[0]) && std::isfinite(vals[1]) && std::isfinite(vals[2]))) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb reflections pan out of range"); + props->Reverb.ReflectionsPan[0] = vals[0]; + props->Reverb.ReflectionsPan[1] = vals[1]; + props->Reverb.ReflectionsPan[2] = vals[2]; + break; + case AL_EAXREVERB_LATE_REVERB_PAN: + if(!(std::isfinite(vals[0]) && std::isfinite(vals[1]) && std::isfinite(vals[2]))) + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb late reverb pan out of range"); + props->Reverb.LateReverbPan[0] = vals[0]; + props->Reverb.LateReverbPan[1] = vals[1]; + props->Reverb.LateReverbPan[2] = vals[2]; + break; + + default: + EAXReverb_setParamf(props, context, param, vals[0]); + break; + } +} + +void EAXReverb_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val) +{ + switch(param) + { + case AL_EAXREVERB_DECAY_HFLIMIT: + *val = props->Reverb.DecayHFLimit; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb integer property 0x%04x", + param); + } +} +void EAXReverb_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) +{ EAXReverb_getParami(props, context, param, vals); } +void EAXReverb_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_EAXREVERB_DENSITY: + *val = props->Reverb.Density; + break; + + case AL_EAXREVERB_DIFFUSION: + *val = props->Reverb.Diffusion; + break; + + case AL_EAXREVERB_GAIN: + *val = props->Reverb.Gain; + break; + + case AL_EAXREVERB_GAINHF: + *val = props->Reverb.GainHF; + break; + + case AL_EAXREVERB_GAINLF: + *val = props->Reverb.GainLF; + break; + + case AL_EAXREVERB_DECAY_TIME: + *val = props->Reverb.DecayTime; + break; + + case AL_EAXREVERB_DECAY_HFRATIO: + *val = props->Reverb.DecayHFRatio; + break; + + case AL_EAXREVERB_DECAY_LFRATIO: + *val = props->Reverb.DecayLFRatio; + break; + + case AL_EAXREVERB_REFLECTIONS_GAIN: + *val = props->Reverb.ReflectionsGain; + break; + + case AL_EAXREVERB_REFLECTIONS_DELAY: + *val = props->Reverb.ReflectionsDelay; + break; + + case AL_EAXREVERB_LATE_REVERB_GAIN: + *val = props->Reverb.LateReverbGain; + break; + + case AL_EAXREVERB_LATE_REVERB_DELAY: + *val = props->Reverb.LateReverbDelay; + break; + + case AL_EAXREVERB_AIR_ABSORPTION_GAINHF: + *val = props->Reverb.AirAbsorptionGainHF; + break; + + case AL_EAXREVERB_ECHO_TIME: + *val = props->Reverb.EchoTime; + break; + + case AL_EAXREVERB_ECHO_DEPTH: + *val = props->Reverb.EchoDepth; + break; + + case AL_EAXREVERB_MODULATION_TIME: + *val = props->Reverb.ModulationTime; + break; + + case AL_EAXREVERB_MODULATION_DEPTH: + *val = props->Reverb.ModulationDepth; + break; + + case AL_EAXREVERB_HFREFERENCE: + *val = props->Reverb.HFReference; + break; + + case AL_EAXREVERB_LFREFERENCE: + *val = props->Reverb.LFReference; + break; + + case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR: + *val = props->Reverb.RoomRolloffFactor; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", + param); + } +} +void EAXReverb_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) +{ + switch(param) + { + case AL_EAXREVERB_REFLECTIONS_PAN: + vals[0] = props->Reverb.ReflectionsPan[0]; + vals[1] = props->Reverb.ReflectionsPan[1]; + vals[2] = props->Reverb.ReflectionsPan[2]; + break; + case AL_EAXREVERB_LATE_REVERB_PAN: + vals[0] = props->Reverb.LateReverbPan[0]; + vals[1] = props->Reverb.LateReverbPan[1]; + vals[2] = props->Reverb.LateReverbPan[2]; + break; + + default: + EAXReverb_getParamf(props, context, param, vals); + break; + } +} + +DEFINE_ALEFFECT_VTABLE(EAXReverb); + + +struct ReverbStateFactory final : public EffectStateFactory { + EffectState *create() override { return new ReverbState{}; } + EffectProps getDefaultProps() const noexcept override; + const EffectVtable *getEffectVtable() const noexcept override { return &EAXReverb_vtable; } +}; + +EffectProps ReverbStateFactory::getDefaultProps() const noexcept +{ + EffectProps props{}; + props.Reverb.Density = AL_EAXREVERB_DEFAULT_DENSITY; + props.Reverb.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION; + props.Reverb.Gain = AL_EAXREVERB_DEFAULT_GAIN; + props.Reverb.GainHF = AL_EAXREVERB_DEFAULT_GAINHF; + props.Reverb.GainLF = AL_EAXREVERB_DEFAULT_GAINLF; + props.Reverb.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME; + props.Reverb.DecayHFRatio = AL_EAXREVERB_DEFAULT_DECAY_HFRATIO; + props.Reverb.DecayLFRatio = AL_EAXREVERB_DEFAULT_DECAY_LFRATIO; + props.Reverb.ReflectionsGain = AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN; + props.Reverb.ReflectionsDelay = AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY; + props.Reverb.ReflectionsPan[0] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; + props.Reverb.ReflectionsPan[1] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; + props.Reverb.ReflectionsPan[2] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; + props.Reverb.LateReverbGain = AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN; + props.Reverb.LateReverbDelay = AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY; + props.Reverb.LateReverbPan[0] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; + props.Reverb.LateReverbPan[1] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; + props.Reverb.LateReverbPan[2] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; + props.Reverb.EchoTime = AL_EAXREVERB_DEFAULT_ECHO_TIME; + props.Reverb.EchoDepth = AL_EAXREVERB_DEFAULT_ECHO_DEPTH; + props.Reverb.ModulationTime = AL_EAXREVERB_DEFAULT_MODULATION_TIME; + props.Reverb.ModulationDepth = AL_EAXREVERB_DEFAULT_MODULATION_DEPTH; + props.Reverb.AirAbsorptionGainHF = AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF; + props.Reverb.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE; + props.Reverb.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE; + props.Reverb.RoomRolloffFactor = AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; + props.Reverb.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT; + return props; +} + + +void StdReverb_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val) +{ + switch(param) + { + case AL_REVERB_DECAY_HFLIMIT: + if(!(val >= AL_REVERB_MIN_DECAY_HFLIMIT && val <= AL_REVERB_MAX_DECAY_HFLIMIT)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb decay hflimit out of range"); + props->Reverb.DecayHFLimit = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid reverb integer property 0x%04x", param); + } +} +void StdReverb_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) +{ StdReverb_setParami(props, context, param, vals[0]); } +void StdReverb_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_REVERB_DENSITY: + if(!(val >= AL_REVERB_MIN_DENSITY && val <= AL_REVERB_MAX_DENSITY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb density out of range"); + props->Reverb.Density = val; + break; + + case AL_REVERB_DIFFUSION: + if(!(val >= AL_REVERB_MIN_DIFFUSION && val <= AL_REVERB_MAX_DIFFUSION)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb diffusion out of range"); + props->Reverb.Diffusion = val; + break; + + case AL_REVERB_GAIN: + if(!(val >= AL_REVERB_MIN_GAIN && val <= AL_REVERB_MAX_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb gain out of range"); + props->Reverb.Gain = val; + break; + + case AL_REVERB_GAINHF: + if(!(val >= AL_REVERB_MIN_GAINHF && val <= AL_REVERB_MAX_GAINHF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb gainhf out of range"); + props->Reverb.GainHF = val; + break; + + case AL_REVERB_DECAY_TIME: + if(!(val >= AL_REVERB_MIN_DECAY_TIME && val <= AL_REVERB_MAX_DECAY_TIME)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb decay time out of range"); + props->Reverb.DecayTime = val; + break; + + case AL_REVERB_DECAY_HFRATIO: + if(!(val >= AL_REVERB_MIN_DECAY_HFRATIO && val <= AL_REVERB_MAX_DECAY_HFRATIO)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb decay hfratio out of range"); + props->Reverb.DecayHFRatio = val; + break; + + case AL_REVERB_REFLECTIONS_GAIN: + if(!(val >= AL_REVERB_MIN_REFLECTIONS_GAIN && val <= AL_REVERB_MAX_REFLECTIONS_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb reflections gain out of range"); + props->Reverb.ReflectionsGain = val; + break; + + case AL_REVERB_REFLECTIONS_DELAY: + if(!(val >= AL_REVERB_MIN_REFLECTIONS_DELAY && val <= AL_REVERB_MAX_REFLECTIONS_DELAY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb reflections delay out of range"); + props->Reverb.ReflectionsDelay = val; + break; + + case AL_REVERB_LATE_REVERB_GAIN: + if(!(val >= AL_REVERB_MIN_LATE_REVERB_GAIN && val <= AL_REVERB_MAX_LATE_REVERB_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb late reverb gain out of range"); + props->Reverb.LateReverbGain = val; + break; + + case AL_REVERB_LATE_REVERB_DELAY: + if(!(val >= AL_REVERB_MIN_LATE_REVERB_DELAY && val <= AL_REVERB_MAX_LATE_REVERB_DELAY)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb late reverb delay out of range"); + props->Reverb.LateReverbDelay = val; + break; + + case AL_REVERB_AIR_ABSORPTION_GAINHF: + if(!(val >= AL_REVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_REVERB_MAX_AIR_ABSORPTION_GAINHF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb air absorption gainhf out of range"); + props->Reverb.AirAbsorptionGainHF = val; + break; + + case AL_REVERB_ROOM_ROLLOFF_FACTOR: + if(!(val >= AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb room rolloff factor out of range"); + props->Reverb.RoomRolloffFactor = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid reverb float property 0x%04x", param); + } +} +void StdReverb_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) +{ StdReverb_setParamf(props, context, param, vals[0]); } + +void StdReverb_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val) +{ + switch(param) + { + case AL_REVERB_DECAY_HFLIMIT: + *val = props->Reverb.DecayHFLimit; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid reverb integer property 0x%04x", param); + } +} +void StdReverb_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) +{ StdReverb_getParami(props, context, param, vals); } +void StdReverb_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_REVERB_DENSITY: + *val = props->Reverb.Density; + break; + + case AL_REVERB_DIFFUSION: + *val = props->Reverb.Diffusion; + break; + + case AL_REVERB_GAIN: + *val = props->Reverb.Gain; + break; + + case AL_REVERB_GAINHF: + *val = props->Reverb.GainHF; + break; + + case AL_REVERB_DECAY_TIME: + *val = props->Reverb.DecayTime; + break; + + case AL_REVERB_DECAY_HFRATIO: + *val = props->Reverb.DecayHFRatio; + break; + + case AL_REVERB_REFLECTIONS_GAIN: + *val = props->Reverb.ReflectionsGain; + break; + + case AL_REVERB_REFLECTIONS_DELAY: + *val = props->Reverb.ReflectionsDelay; + break; + + case AL_REVERB_LATE_REVERB_GAIN: + *val = props->Reverb.LateReverbGain; + break; + + case AL_REVERB_LATE_REVERB_DELAY: + *val = props->Reverb.LateReverbDelay; + break; + + case AL_REVERB_AIR_ABSORPTION_GAINHF: + *val = props->Reverb.AirAbsorptionGainHF; + break; + + case AL_REVERB_ROOM_ROLLOFF_FACTOR: + *val = props->Reverb.RoomRolloffFactor; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid reverb float property 0x%04x", param); + } +} +void StdReverb_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) +{ StdReverb_getParamf(props, context, param, vals); } + +DEFINE_ALEFFECT_VTABLE(StdReverb); + + +struct StdReverbStateFactory final : public EffectStateFactory { + EffectState *create() override { return new ReverbState{}; } + EffectProps getDefaultProps() const noexcept override; + const EffectVtable *getEffectVtable() const noexcept override { return &StdReverb_vtable; } +}; + +EffectProps StdReverbStateFactory::getDefaultProps() const noexcept +{ + EffectProps props{}; + props.Reverb.Density = AL_REVERB_DEFAULT_DENSITY; + props.Reverb.Diffusion = AL_REVERB_DEFAULT_DIFFUSION; + props.Reverb.Gain = AL_REVERB_DEFAULT_GAIN; + props.Reverb.GainHF = AL_REVERB_DEFAULT_GAINHF; + props.Reverb.GainLF = 1.0f; + props.Reverb.DecayTime = AL_REVERB_DEFAULT_DECAY_TIME; + props.Reverb.DecayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO; + props.Reverb.DecayLFRatio = 1.0f; + props.Reverb.ReflectionsGain = AL_REVERB_DEFAULT_REFLECTIONS_GAIN; + props.Reverb.ReflectionsDelay = AL_REVERB_DEFAULT_REFLECTIONS_DELAY; + props.Reverb.ReflectionsPan[0] = 0.0f; + props.Reverb.ReflectionsPan[1] = 0.0f; + props.Reverb.ReflectionsPan[2] = 0.0f; + props.Reverb.LateReverbGain = AL_REVERB_DEFAULT_LATE_REVERB_GAIN; + props.Reverb.LateReverbDelay = AL_REVERB_DEFAULT_LATE_REVERB_DELAY; + props.Reverb.LateReverbPan[0] = 0.0f; + props.Reverb.LateReverbPan[1] = 0.0f; + props.Reverb.LateReverbPan[2] = 0.0f; + props.Reverb.EchoTime = 0.25f; + props.Reverb.EchoDepth = 0.0f; + props.Reverb.ModulationTime = 0.25f; + props.Reverb.ModulationDepth = 0.0f; + props.Reverb.AirAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF; + props.Reverb.HFReference = 5000.0f; + props.Reverb.LFReference = 250.0f; + props.Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; + props.Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT; + return props; +} + +} // namespace + +EffectStateFactory *ReverbStateFactory_getFactory() +{ + static ReverbStateFactory ReverbFactory{}; + return &ReverbFactory; +} + +EffectStateFactory *StdReverbStateFactory_getFactory() +{ + static StdReverbStateFactory ReverbFactory{}; + return &ReverbFactory; +} diff --git a/alc/effects/vmorpher.cpp b/alc/effects/vmorpher.cpp new file mode 100644 index 00000000..eebba3f1 --- /dev/null +++ b/alc/effects/vmorpher.cpp @@ -0,0 +1,430 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2019 by Anis A. Hireche + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "alcmain.h" +#include "alcontext.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" + +namespace { + +#define MAX_UPDATE_SAMPLES 128 +#define NUM_FORMANTS 4 +#define NUM_FILTERS 2 +#define Q_FACTOR 5.0f + +#define VOWEL_A_INDEX 0 +#define VOWEL_B_INDEX 1 + +#define WAVEFORM_FRACBITS 24 +#define WAVEFORM_FRACONE (1<::Tau() / ALfloat{WAVEFORM_FRACONE}}; + return std::sin(static_cast(index) * scale)*0.5f + 0.5f; +} + +inline ALfloat Saw(ALsizei index) +{ + return static_cast(index) / ALfloat{WAVEFORM_FRACONE}; +} + +inline ALfloat Triangle(ALsizei index) +{ + return std::fabs(static_cast(index)*(2.0f/WAVEFORM_FRACONE) - 1.0f); +} + +inline ALfloat Half(ALsizei) +{ + return 0.5f; +} + +template +void Oscillate(ALfloat *RESTRICT dst, ALsizei index, const ALsizei step, ALsizei todo) +{ + for(ALsizei i{0};i < todo;i++) + { + index += step; + index &= WAVEFORM_FRACMASK; + dst[i] = func(index); + } +} + +struct FormantFilter +{ + ALfloat f0norm{0.0f}; + ALfloat fGain{1.0f}; + ALfloat s1{0.0f}; + ALfloat s2{0.0f}; + + FormantFilter() = default; + FormantFilter(ALfloat f0norm_, ALfloat gain) : f0norm{f0norm_}, fGain{gain} { } + + inline void process(const ALfloat* samplesIn, ALfloat* samplesOut, const ALsizei numInput) + { + /* A state variable filter from a topology-preserving transform. + * Based on a talk given by Ivan Cohen: https://www.youtube.com/watch?v=esjHXGPyrhg + */ + const ALfloat g = std::tan(al::MathDefs::Pi() * f0norm); + const ALfloat h = 1.0f / (1 + (g / Q_FACTOR) + (g * g)); + + for (ALsizei i{0};i < numInput;i++) + { + const ALfloat H = h * (samplesIn[i] - (1.0f / Q_FACTOR + g) * s1 - s2); + const ALfloat B = g * H + s1; + const ALfloat L = g * B + s2; + + s1 = g * H + B; + s2 = g * B + L; + + // Apply peak and accumulate samples. + samplesOut[i] += B * fGain; + } + } + + inline void clear() + { + s1 = 0.0f; + s2 = 0.0f; + } +}; + + +struct VmorpherState final : public EffectState { + struct { + /* Effect parameters */ + FormantFilter Formants[NUM_FILTERS][NUM_FORMANTS]; + + /* Effect gains for each channel */ + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]{}; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]{}; + } mChans[MAX_AMBI_CHANNELS]; + + void (*mGetSamples)(ALfloat* RESTRICT, ALsizei, const ALsizei, ALsizei) {}; + + ALsizei mIndex{0}; + ALsizei mStep{1}; + + /* Effects buffers */ + ALfloat mSampleBufferA[MAX_UPDATE_SAMPLES]{}; + ALfloat mSampleBufferB[MAX_UPDATE_SAMPLES]{}; + + ALboolean deviceUpdate(const ALCdevice *device) override; + void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; + void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + + static std::array getFiltersByPhoneme(ALenum phoneme, ALfloat frequency, ALfloat pitch); + + DEF_NEWDEL(VmorpherState) +}; + +std::array VmorpherState::getFiltersByPhoneme(ALenum phoneme, ALfloat frequency, ALfloat pitch) +{ + /* Using soprano formant set of values to + * better match mid-range frequency space. + * + * See: https://www.classes.cs.uchicago.edu/archive/1999/spring/CS295/Computing_Resources/Csound/CsManual3.48b1.HTML/Appendices/table3.html + */ + switch(phoneme) + { + case AL_VOCAL_MORPHER_PHONEME_A: + return {{ + {( 800 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ + {(1150 * pitch) / frequency, 0.501187f}, /* std::pow(10.0f, -6 / 20.0f); */ + {(2900 * pitch) / frequency, 0.025118f}, /* std::pow(10.0f, -32 / 20.0f); */ + {(3900 * pitch) / frequency, 0.100000f} /* std::pow(10.0f, -20 / 20.0f); */ + }}; + case AL_VOCAL_MORPHER_PHONEME_E: + return {{ + {( 350 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ + {(2000 * pitch) / frequency, 0.100000f}, /* std::pow(10.0f, -20 / 20.0f); */ + {(2800 * pitch) / frequency, 0.177827f}, /* std::pow(10.0f, -15 / 20.0f); */ + {(3600 * pitch) / frequency, 0.009999f} /* std::pow(10.0f, -40 / 20.0f); */ + }}; + case AL_VOCAL_MORPHER_PHONEME_I: + return {{ + {( 270 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ + {(2140 * pitch) / frequency, 0.251188f}, /* std::pow(10.0f, -12 / 20.0f); */ + {(2950 * pitch) / frequency, 0.050118f}, /* std::pow(10.0f, -26 / 20.0f); */ + {(3900 * pitch) / frequency, 0.050118f} /* std::pow(10.0f, -26 / 20.0f); */ + }}; + case AL_VOCAL_MORPHER_PHONEME_O: + return {{ + {( 450 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ + {( 800 * pitch) / frequency, 0.281838f}, /* std::pow(10.0f, -11 / 20.0f); */ + {(2830 * pitch) / frequency, 0.079432f}, /* std::pow(10.0f, -22 / 20.0f); */ + {(3800 * pitch) / frequency, 0.079432f} /* std::pow(10.0f, -22 / 20.0f); */ + }}; + case AL_VOCAL_MORPHER_PHONEME_U: + return {{ + {( 325 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ + {( 700 * pitch) / frequency, 0.158489f}, /* std::pow(10.0f, -16 / 20.0f); */ + {(2700 * pitch) / frequency, 0.017782f}, /* std::pow(10.0f, -35 / 20.0f); */ + {(3800 * pitch) / frequency, 0.009999f} /* std::pow(10.0f, -40 / 20.0f); */ + }}; + } + return {}; +} + + +ALboolean VmorpherState::deviceUpdate(const ALCdevice* /*device*/) +{ + for(auto &e : mChans) + { + std::for_each(std::begin(e.Formants[VOWEL_A_INDEX]), std::end(e.Formants[VOWEL_A_INDEX]), + std::mem_fn(&FormantFilter::clear)); + std::for_each(std::begin(e.Formants[VOWEL_B_INDEX]), std::end(e.Formants[VOWEL_B_INDEX]), + std::mem_fn(&FormantFilter::clear)); + std::fill(std::begin(e.CurrentGains), std::end(e.CurrentGains), 0.0f); + } + + return AL_TRUE; +} + +void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) +{ + const ALCdevice *device{context->Device}; + const ALfloat frequency{static_cast(device->Frequency)}; + const ALfloat step{props->Vmorpher.Rate / static_cast(device->Frequency)}; + mStep = fastf2i(clampf(step*WAVEFORM_FRACONE, 0.0f, ALfloat{WAVEFORM_FRACONE-1})); + + if(mStep == 0) + mGetSamples = Oscillate; + else if(props->Vmorpher.Waveform == AL_VOCAL_MORPHER_WAVEFORM_SINUSOID) + mGetSamples = Oscillate; + else if(props->Vmorpher.Waveform == AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH) + mGetSamples = Oscillate; + else /*if(props->Vmorpher.Waveform == AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE)*/ + mGetSamples = Oscillate; + + const ALfloat pitchA{fastf2i(std::pow(2.0f, props->Vmorpher.PhonemeACoarseTuning*100.0f / 2400.0f)*FRACTIONONE) * (1.0f/FRACTIONONE)}; + const ALfloat pitchB{fastf2i(std::pow(2.0f, props->Vmorpher.PhonemeBCoarseTuning*100.0f / 2400.0f)*FRACTIONONE) * (1.0f/FRACTIONONE)}; + + auto vowelA = getFiltersByPhoneme(props->Vmorpher.PhonemeA, frequency, pitchA); + auto vowelB = getFiltersByPhoneme(props->Vmorpher.PhonemeB, frequency, pitchB); + + /* Copy the filter coefficients to the input channels. */ + for(size_t i{0u};i < slot->Wet.Buffer.size();++i) + { + std::copy(vowelA.begin(), vowelA.end(), std::begin(mChans[i].Formants[VOWEL_A_INDEX])); + std::copy(vowelB.begin(), vowelB.end(), std::begin(mChans[i].Formants[VOWEL_B_INDEX])); + } + + mOutTarget = target.Main->Buffer; + for(size_t i{0u};i < slot->Wet.Buffer.size();++i) + { + auto coeffs = GetAmbiIdentityRow(i); + ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mChans[i].TargetGains); + } +} + +void VmorpherState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) +{ + /* Following the EFX specification for a conformant implementation which describes + * the effect as a pair of 4-band formant filters blended together using an LFO. + */ + for(ALsizei base{0};base < samplesToDo;) + { + alignas(16) ALfloat lfo[MAX_UPDATE_SAMPLES]; + const ALsizei td = mini(MAX_UPDATE_SAMPLES, samplesToDo-base); + + mGetSamples(lfo, mIndex, mStep, td); + mIndex += (mStep * td) & WAVEFORM_FRACMASK; + mIndex &= WAVEFORM_FRACMASK; + + ASSUME(numInput > 0); + for(ALsizei c{0};c < numInput;c++) + { + for (ALsizei i{0};i < td;i++) + { + mSampleBufferA[i] = 0.0f; + mSampleBufferB[i] = 0.0f; + } + + auto& vowelA = mChans[c].Formants[VOWEL_A_INDEX]; + auto& vowelB = mChans[c].Formants[VOWEL_B_INDEX]; + + /* Process first vowel. */ + vowelA[0].process(&samplesIn[c][base], mSampleBufferA, td); + vowelA[1].process(&samplesIn[c][base], mSampleBufferA, td); + vowelA[2].process(&samplesIn[c][base], mSampleBufferA, td); + vowelA[3].process(&samplesIn[c][base], mSampleBufferA, td); + + /* Process second vowel. */ + vowelB[0].process(&samplesIn[c][base], mSampleBufferB, td); + vowelB[1].process(&samplesIn[c][base], mSampleBufferB, td); + vowelB[2].process(&samplesIn[c][base], mSampleBufferB, td); + vowelB[3].process(&samplesIn[c][base], mSampleBufferB, td); + + alignas(16) ALfloat samplesBlended[MAX_UPDATE_SAMPLES]; + + for (ALsizei i{0};i < td;i++) + samplesBlended[i] = lerp(mSampleBufferA[i], mSampleBufferB[i], lfo[i]); + + /* Now, mix the processed sound data to the output. */ + MixSamples(samplesBlended, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, + samplesToDo-base, base, td); + } + + base += td; + } +} + + +void Vmorpher_setParami(EffectProps* props, ALCcontext *context, ALenum param, ALint val) +{ + switch(param) + { + case AL_VOCAL_MORPHER_WAVEFORM: + if(!(val >= AL_VOCAL_MORPHER_MIN_WAVEFORM && val <= AL_VOCAL_MORPHER_MAX_WAVEFORM)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher waveform out of range"); + props->Vmorpher.Waveform = val; + break; + + case AL_VOCAL_MORPHER_PHONEMEA: + if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEA && val <= AL_VOCAL_MORPHER_MAX_PHONEMEA)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher phoneme-a out of range"); + props->Vmorpher.PhonemeA = val; + break; + + case AL_VOCAL_MORPHER_PHONEMEB: + if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEB && val <= AL_VOCAL_MORPHER_MAX_PHONEMEB)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher phoneme-b out of range"); + props->Vmorpher.PhonemeB = val; + break; + + case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING: + if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher phoneme-a coarse tuning out of range"); + props->Vmorpher.PhonemeACoarseTuning = val; + break; + + case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING: + if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher phoneme-b coarse tuning out of range"); + props->Vmorpher.PhonemeBCoarseTuning = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x", param); + } +} +void Vmorpher_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x", param); } +void Vmorpher_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_VOCAL_MORPHER_RATE: + if(!(val >= AL_VOCAL_MORPHER_MIN_RATE && val <= AL_VOCAL_MORPHER_MAX_RATE)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Vocal morpher rate out of range"); + props->Vmorpher.Rate = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x", param); + } +} +void Vmorpher_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) +{ Vmorpher_setParamf(props, context, param, vals[0]); } + +void Vmorpher_getParami(const EffectProps* props, ALCcontext *context, ALenum param, ALint* val) +{ + switch(param) + { + case AL_VOCAL_MORPHER_PHONEMEA: + *val = props->Vmorpher.PhonemeA; + break; + + case AL_VOCAL_MORPHER_PHONEMEB: + *val = props->Vmorpher.PhonemeB; + break; + + case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING: + *val = props->Vmorpher.PhonemeACoarseTuning; + break; + + case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING: + *val = props->Vmorpher.PhonemeBCoarseTuning; + break; + + case AL_VOCAL_MORPHER_WAVEFORM: + *val = props->Vmorpher.Waveform; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x", param); + } +} +void Vmorpher_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x", param); } +void Vmorpher_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_VOCAL_MORPHER_RATE: + *val = props->Vmorpher.Rate; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x", param); + } +} +void Vmorpher_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) +{ Vmorpher_getParamf(props, context, param, vals); } + +DEFINE_ALEFFECT_VTABLE(Vmorpher); + + +struct VmorpherStateFactory final : public EffectStateFactory { + EffectState *create() override { return new VmorpherState{}; } + EffectProps getDefaultProps() const noexcept override; + const EffectVtable *getEffectVtable() const noexcept override { return &Vmorpher_vtable; } +}; + +EffectProps VmorpherStateFactory::getDefaultProps() const noexcept +{ + EffectProps props{}; + props.Vmorpher.Rate = AL_VOCAL_MORPHER_DEFAULT_RATE; + props.Vmorpher.PhonemeA = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA; + props.Vmorpher.PhonemeB = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB; + props.Vmorpher.PhonemeACoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING; + props.Vmorpher.PhonemeBCoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING; + props.Vmorpher.Waveform = AL_VOCAL_MORPHER_DEFAULT_WAVEFORM; + return props; +} + +} // namespace + +EffectStateFactory *VmorpherStateFactory_getFactory() +{ + static VmorpherStateFactory VmorpherFactory{}; + return &VmorpherFactory; +} diff --git a/alc/filters/biquad.cpp b/alc/filters/biquad.cpp new file mode 100644 index 00000000..6a3cef64 --- /dev/null +++ b/alc/filters/biquad.cpp @@ -0,0 +1,127 @@ + +#include "config.h" + +#include "biquad.h" + +#include +#include +#include + +#include "opthelpers.h" + + +template +void BiquadFilterR::setParams(BiquadType type, Real gain, Real f0norm, Real rcpQ) +{ + // Limit gain to -100dB + assert(gain > 0.00001f); + + const Real w0{al::MathDefs::Tau() * f0norm}; + const Real sin_w0{std::sin(w0)}; + const Real cos_w0{std::cos(w0)}; + const Real alpha{sin_w0/2.0f * rcpQ}; + + Real sqrtgain_alpha_2; + Real a[3]{ 1.0f, 0.0f, 0.0f }; + Real b[3]{ 1.0f, 0.0f, 0.0f }; + + /* Calculate filter coefficients depending on filter type */ + switch(type) + { + case BiquadType::HighShelf: + sqrtgain_alpha_2 = 2.0f * std::sqrt(gain) * alpha; + b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); + b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 ); + b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); + a[0] = (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; + a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 ); + a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; + break; + case BiquadType::LowShelf: + sqrtgain_alpha_2 = 2.0f * std::sqrt(gain) * alpha; + b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); + b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 ); + b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); + a[0] = (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; + a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 ); + a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; + break; + case BiquadType::Peaking: + gain = std::sqrt(gain); + b[0] = 1.0f + alpha * gain; + b[1] = -2.0f * cos_w0; + b[2] = 1.0f - alpha * gain; + a[0] = 1.0f + alpha / gain; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha / gain; + break; + + case BiquadType::LowPass: + b[0] = (1.0f - cos_w0) / 2.0f; + b[1] = 1.0f - cos_w0; + b[2] = (1.0f - cos_w0) / 2.0f; + a[0] = 1.0f + alpha; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha; + break; + case BiquadType::HighPass: + b[0] = (1.0f + cos_w0) / 2.0f; + b[1] = -(1.0f + cos_w0); + b[2] = (1.0f + cos_w0) / 2.0f; + a[0] = 1.0f + alpha; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha; + break; + case BiquadType::BandPass: + b[0] = alpha; + b[1] = 0.0f; + b[2] = -alpha; + a[0] = 1.0f + alpha; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha; + break; + } + + a1 = a[1] / a[0]; + a2 = a[2] / a[0]; + b0 = b[0] / a[0]; + b1 = b[1] / a[0]; + b2 = b[2] / a[0]; +} + +template +void BiquadFilterR::process(Real *dst, const Real *src, int numsamples) +{ + ASSUME(numsamples > 0); + + const Real b0{this->b0}; + const Real b1{this->b1}; + const Real b2{this->b2}; + const Real a1{this->a1}; + const Real a2{this->a2}; + Real z1{this->z1}; + Real z2{this->z2}; + + /* Processing loop is Transposed Direct Form II. This requires less storage + * compared to Direct Form I (only two delay components, instead of a four- + * sample history; the last two inputs and outputs), and works better for + * floating-point which favors summing similarly-sized values while being + * less bothered by overflow. + * + * See: http://www.earlevel.com/main/2003/02/28/biquads/ + */ + auto proc_sample = [b0,b1,b2,a1,a2,&z1,&z2](Real input) noexcept -> Real + { + Real output = input*b0 + z1; + z1 = input*b1 - output*a1 + z2; + z2 = input*b2 - output*a2; + return output; + }; + std::transform(src, src+numsamples, dst, proc_sample); + + this->z1 = z1; + this->z2 = z2; +} + +template class BiquadFilterR; +template class BiquadFilterR; diff --git a/alc/filters/biquad.h b/alc/filters/biquad.h new file mode 100644 index 00000000..893a69a9 --- /dev/null +++ b/alc/filters/biquad.h @@ -0,0 +1,113 @@ +#ifndef FILTERS_BIQUAD_H +#define FILTERS_BIQUAD_H + +#include +#include + +#include "math_defs.h" + + +/* Filters implementation is based on the "Cookbook formulae for audio + * EQ biquad filter coefficients" by Robert Bristow-Johnson + * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt + */ +/* Implementation note: For the shelf filters, the specified gain is for the + * reference frequency, which is the centerpoint of the transition band. This + * better matches EFX filter design. To set the gain for the shelf itself, use + * the square root of the desired linear gain (or halve the dB gain). + */ + +enum class BiquadType { + /** EFX-style low-pass filter, specifying a gain and reference frequency. */ + HighShelf, + /** EFX-style high-pass filter, specifying a gain and reference frequency. */ + LowShelf, + /** Peaking filter, specifying a gain and reference frequency. */ + Peaking, + + /** Low-pass cut-off filter, specifying a cut-off frequency. */ + LowPass, + /** High-pass cut-off filter, specifying a cut-off frequency. */ + HighPass, + /** Band-pass filter, specifying a center frequency. */ + BandPass, +}; + +template +class BiquadFilterR { + /* Last two delayed components for direct form II. */ + Real z1{0.0f}, z2{0.0f}; + /* Transfer function coefficients "b" (numerator) */ + Real b0{1.0f}, b1{0.0f}, b2{0.0f}; + /* Transfer function coefficients "a" (denominator; a0 is pre-applied). */ + Real a1{0.0f}, a2{0.0f}; + +public: + void clear() noexcept { z1 = z2 = 0.0f; } + + /** + * Sets the filter state for the specified filter type and its parameters. + * + * \param type The type of filter to apply. + * \param gain The gain for the reference frequency response. Only used by + * the Shelf and Peaking filter types. + * \param f0norm The reference frequency normal (ref_freq / sample_rate). + * This is the center point for the Shelf, Peaking, and + * BandPass filter types, or the cutoff frequency for the + * LowPass and HighPass filter types. + * \param rcpQ The reciprocal of the Q coefficient for the filter's + * transition band. Can be generated from rcpQFromSlope or + * rcpQFromBandwidth as needed. + */ + void setParams(BiquadType type, Real gain, Real f0norm, Real rcpQ); + + void copyParamsFrom(const BiquadFilterR &other) + { + b0 = other.b0; + b1 = other.b1; + b2 = other.b2; + a1 = other.a1; + a2 = other.a2; + } + + + void process(Real *dst, const Real *src, int numsamples); + + /* Rather hacky. It's just here to support "manual" processing. */ + std::pair getComponents() const noexcept + { return {z1, z2}; } + void setComponents(Real z1_, Real z2_) noexcept + { z1 = z1_; z2 = z2_; } + Real processOne(const Real in, Real &z1_, Real &z2_) const noexcept + { + Real out{in*b0 + z1_}; + z1_ = in*b1 - out*a1 + z2_; + z2_ = in*b2 - out*a2; + return out; + } + + /** + * Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using + * the reference gain and shelf slope parameter. + * \param gain 0 < gain + * \param slope 0 < slope <= 1 + */ + static Real rcpQFromSlope(Real gain, Real slope) + { return std::sqrt((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f); } + + /** + * Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the + * normalized reference frequency and bandwidth. + * \param f0norm 0 < f0norm < 0.5. + * \param bandwidth 0 < bandwidth + */ + static Real rcpQFromBandwidth(Real f0norm, Real bandwidth) + { + const Real w0{al::MathDefs::Tau() * f0norm}; + return 2.0f*std::sinh(std::log(Real{2.0f})/2.0f*bandwidth*w0/std::sin(w0)); + } +}; + +using BiquadFilter = BiquadFilterR; + +#endif /* FILTERS_BIQUAD_H */ diff --git a/alc/filters/nfc.cpp b/alc/filters/nfc.cpp new file mode 100644 index 00000000..1a567f2c --- /dev/null +++ b/alc/filters/nfc.cpp @@ -0,0 +1,391 @@ + +#include "config.h" + +#include "nfc.h" + +#include + +#include "alcmain.h" + + +/* Near-field control filters are the basis for handling the near-field effect. + * The near-field effect is a bass-boost present in the directional components + * of a recorded signal, created as a result of the wavefront curvature (itself + * a function of sound distance). Proper reproduction dictates this be + * compensated for using a bass-cut given the playback speaker distance, to + * avoid excessive bass in the playback. + * + * For real-time rendered audio, emulating the near-field effect based on the + * sound source's distance, and subsequently compensating for it at output + * based on the speaker distances, can create a more realistic perception of + * sound distance beyond a simple 1/r attenuation. + * + * These filters do just that. Each one applies a low-shelf filter, created as + * the combination of a bass-boost for a given sound source distance (near- + * field emulation) along with a bass-cut for a given control/speaker distance + * (near-field compensation). + * + * Note that it is necessary to apply a cut along with the boost, since the + * boost alone is unstable in higher-order ambisonics as it causes an infinite + * DC gain (even first-order ambisonics requires there to be no DC offset for + * the boost to work). Consequently, ambisonics requires a control parameter to + * be used to avoid an unstable boost-only filter. NFC-HOA defines this control + * as a reference delay, calculated with: + * + * reference_delay = control_distance / speed_of_sound + * + * This means w0 (for input) or w1 (for output) should be set to: + * + * wN = 1 / (reference_delay * sample_rate) + * + * when dealing with NFC-HOA content. For FOA input content, which does not + * specify a reference_delay variable, w0 should be set to 0 to apply only + * near-field compensation for output. It's important that w1 be a finite, + * positive, non-0 value or else the bass-boost will become unstable again. + * Also, w0 should not be too large compared to w1, to avoid excessively loud + * low frequencies. + */ + +namespace { + +constexpr float B[5][4] = { + { 0.0f }, + { 1.0f }, + { 3.0f, 3.0f }, + { 3.6778f, 6.4595f, 2.3222f }, + { 4.2076f, 11.4877f, 5.7924f, 9.1401f } +}; + +NfcFilter1 NfcFilterCreate1(const float w0, const float w1) noexcept +{ + NfcFilter1 nfc{}; + float b_00, g_0; + float r; + + nfc.base_gain = 1.0f; + nfc.gain = 1.0f; + + /* Calculate bass-boost coefficients. */ + r = 0.5f * w0; + b_00 = B[1][0] * r; + g_0 = 1.0f + b_00; + + nfc.gain *= g_0; + nfc.b1 = 2.0f * b_00 / g_0; + + /* Calculate bass-cut coefficients. */ + r = 0.5f * w1; + b_00 = B[1][0] * r; + g_0 = 1.0f + b_00; + + nfc.base_gain /= g_0; + nfc.gain /= g_0; + nfc.a1 = 2.0f * b_00 / g_0; + + return nfc; +} + +void NfcFilterAdjust1(NfcFilter1 *nfc, const float w0) noexcept +{ + const float r{0.5f * w0}; + const float b_00{B[1][0] * r}; + const float g_0{1.0f + b_00}; + + nfc->gain = nfc->base_gain * g_0; + nfc->b1 = 2.0f * b_00 / g_0; +} + + +NfcFilter2 NfcFilterCreate2(const float w0, const float w1) noexcept +{ + NfcFilter2 nfc{}; + float b_10, b_11, g_1; + float r; + + nfc.base_gain = 1.0f; + nfc.gain = 1.0f; + + /* Calculate bass-boost coefficients. */ + r = 0.5f * w0; + b_10 = B[2][0] * r; + b_11 = B[2][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc.gain *= g_1; + nfc.b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc.b2 = 4.0f * b_11 / g_1; + + /* Calculate bass-cut coefficients. */ + r = 0.5f * w1; + b_10 = B[2][0] * r; + b_11 = B[2][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc.base_gain /= g_1; + nfc.gain /= g_1; + nfc.a1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc.a2 = 4.0f * b_11 / g_1; + + return nfc; +} + +void NfcFilterAdjust2(NfcFilter2 *nfc, const float w0) noexcept +{ + const float r{0.5f * w0}; + const float b_10{B[2][0] * r}; + const float b_11{B[2][1] * r * r}; + const float g_1{1.0f + b_10 + b_11}; + + nfc->gain = nfc->base_gain * g_1; + nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc->b2 = 4.0f * b_11 / g_1; +} + + +NfcFilter3 NfcFilterCreate3(const float w0, const float w1) noexcept +{ + NfcFilter3 nfc{}; + float b_10, b_11, g_1; + float b_00, g_0; + float r; + + nfc.base_gain = 1.0f; + nfc.gain = 1.0f; + + /* Calculate bass-boost coefficients. */ + r = 0.5f * w0; + b_10 = B[3][0] * r; + b_11 = B[3][1] * r * r; + b_00 = B[3][2] * r; + g_1 = 1.0f + b_10 + b_11; + g_0 = 1.0f + b_00; + + nfc.gain *= g_1 * g_0; + nfc.b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc.b2 = 4.0f * b_11 / g_1; + nfc.b3 = 2.0f * b_00 / g_0; + + /* Calculate bass-cut coefficients. */ + r = 0.5f * w1; + b_10 = B[3][0] * r; + b_11 = B[3][1] * r * r; + b_00 = B[3][2] * r; + g_1 = 1.0f + b_10 + b_11; + g_0 = 1.0f + b_00; + + nfc.base_gain /= g_1 * g_0; + nfc.gain /= g_1 * g_0; + nfc.a1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc.a2 = 4.0f * b_11 / g_1; + nfc.a3 = 2.0f * b_00 / g_0; + + return nfc; +} + +void NfcFilterAdjust3(NfcFilter3 *nfc, const float w0) noexcept +{ + const float r{0.5f * w0}; + const float b_10{B[3][0] * r}; + const float b_11{B[3][1] * r * r}; + const float b_00{B[3][2] * r}; + const float g_1{1.0f + b_10 + b_11}; + const float g_0{1.0f + b_00}; + + nfc->gain = nfc->base_gain * g_1 * g_0; + nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc->b2 = 4.0f * b_11 / g_1; + nfc->b3 = 2.0f * b_00 / g_0; +} + + +NfcFilter4 NfcFilterCreate4(const float w0, const float w1) noexcept +{ + NfcFilter4 nfc{}; + float b_10, b_11, g_1; + float b_00, b_01, g_0; + float r; + + nfc.base_gain = 1.0f; + nfc.gain = 1.0f; + + /* Calculate bass-boost coefficients. */ + r = 0.5f * w0; + b_10 = B[4][0] * r; + b_11 = B[4][1] * r * r; + b_00 = B[4][2] * r; + b_01 = B[4][3] * r * r; + g_1 = 1.0f + b_10 + b_11; + g_0 = 1.0f + b_00 + b_01; + + nfc.gain *= g_1 * g_0; + nfc.b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc.b2 = 4.0f * b_11 / g_1; + nfc.b3 = (2.0f*b_00 + 4.0f*b_01) / g_0; + nfc.b4 = 4.0f * b_01 / g_0; + + /* Calculate bass-cut coefficients. */ + r = 0.5f * w1; + b_10 = B[4][0] * r; + b_11 = B[4][1] * r * r; + b_00 = B[4][2] * r; + b_01 = B[4][3] * r * r; + g_1 = 1.0f + b_10 + b_11; + g_0 = 1.0f + b_00 + b_01; + + nfc.base_gain /= g_1 * g_0; + nfc.gain /= g_1 * g_0; + nfc.a1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc.a2 = 4.0f * b_11 / g_1; + nfc.a3 = (2.0f*b_00 + 4.0f*b_01) / g_0; + nfc.a4 = 4.0f * b_01 / g_0; + + return nfc; +} + +void NfcFilterAdjust4(NfcFilter4 *nfc, const float w0) noexcept +{ + const float r{0.5f * w0}; + const float b_10{B[4][0] * r}; + const float b_11{B[4][1] * r * r}; + const float b_00{B[4][2] * r}; + const float b_01{B[4][3] * r * r}; + const float g_1{1.0f + b_10 + b_11}; + const float g_0{1.0f + b_00 + b_01}; + + nfc->gain = nfc->base_gain * g_1 * g_0; + nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc->b2 = 4.0f * b_11 / g_1; + nfc->b3 = (2.0f*b_00 + 4.0f*b_01) / g_0; + nfc->b4 = 4.0f * b_01 / g_0; +} + +} // namespace + +void NfcFilter::init(const float w1) noexcept +{ + first = NfcFilterCreate1(0.0f, w1); + second = NfcFilterCreate2(0.0f, w1); + third = NfcFilterCreate3(0.0f, w1); + fourth = NfcFilterCreate4(0.0f, w1); +} + +void NfcFilter::adjust(const float w0) noexcept +{ + NfcFilterAdjust1(&first, w0); + NfcFilterAdjust2(&second, w0); + NfcFilterAdjust3(&third, w0); + NfcFilterAdjust4(&fourth, w0); +} + + +void NfcFilter::process1(float *RESTRICT dst, const float *RESTRICT src, const int count) +{ + ASSUME(count > 0); + + const float gain{first.gain}; + const float b1{first.b1}; + const float a1{first.a1}; + float z1{first.z[0]}; + auto proc_sample = [gain,b1,a1,&z1](const float in) noexcept -> float + { + const float y{in*gain - a1*z1}; + const float out{y + b1*z1}; + z1 += y; + return out; + }; + std::transform(src, src+count, dst, proc_sample); + first.z[0] = z1; +} + +void NfcFilter::process2(float *RESTRICT dst, const float *RESTRICT src, const int count) +{ + ASSUME(count > 0); + + const float gain{second.gain}; + const float b1{second.b1}; + const float b2{second.b2}; + const float a1{second.a1}; + const float a2{second.a2}; + float z1{second.z[0]}; + float z2{second.z[1]}; + auto proc_sample = [gain,b1,b2,a1,a2,&z1,&z2](const float in) noexcept -> float + { + const float y{in*gain - a1*z1 - a2*z2}; + const float out{y + b1*z1 + b2*z2}; + z2 += z1; + z1 += y; + return out; + }; + std::transform(src, src+count, dst, proc_sample); + second.z[0] = z1; + second.z[1] = z2; +} + +void NfcFilter::process3(float *RESTRICT dst, const float *RESTRICT src, const int count) +{ + ASSUME(count > 0); + + const float gain{third.gain}; + const float b1{third.b1}; + const float b2{third.b2}; + const float b3{third.b3}; + const float a1{third.a1}; + const float a2{third.a2}; + const float a3{third.a3}; + float z1{third.z[0]}; + float z2{third.z[1]}; + float z3{third.z[2]}; + auto proc_sample = [gain,b1,b2,b3,a1,a2,a3,&z1,&z2,&z3](const float in) noexcept -> float + { + float y{in*gain - a1*z1 - a2*z2}; + float out{y + b1*z1 + b2*z2}; + z2 += z1; + z1 += y; + + y = out - a3*z3; + out = y + b3*z3; + z3 += y; + return out; + }; + std::transform(src, src+count, dst, proc_sample); + third.z[0] = z1; + third.z[1] = z2; + third.z[2] = z3; +} + +void NfcFilter::process4(float *RESTRICT dst, const float *RESTRICT src, const int count) +{ + ASSUME(count > 0); + + const float gain{fourth.gain}; + const float b1{fourth.b1}; + const float b2{fourth.b2}; + const float b3{fourth.b3}; + const float b4{fourth.b4}; + const float a1{fourth.a1}; + const float a2{fourth.a2}; + const float a3{fourth.a3}; + const float a4{fourth.a4}; + float z1{fourth.z[0]}; + float z2{fourth.z[1]}; + float z3{fourth.z[2]}; + float z4{fourth.z[3]}; + auto proc_sample = [gain,b1,b2,b3,b4,a1,a2,a3,a4,&z1,&z2,&z3,&z4](const float in) noexcept -> float + { + float y{in*gain - a1*z1 - a2*z2}; + float out{y + b1*z1 + b2*z2}; + z2 += z1; + z1 += y; + + y = out - a3*z3 - a4*z4; + out = y + b3*z3 + b4*z4; + z4 += z3; + z3 += y; + return out; + }; + std::transform(src, src+count, dst, proc_sample); + fourth.z[0] = z1; + fourth.z[1] = z2; + fourth.z[2] = z3; + fourth.z[3] = z4; +} diff --git a/alc/filters/nfc.h b/alc/filters/nfc.h new file mode 100644 index 00000000..b656850a --- /dev/null +++ b/alc/filters/nfc.h @@ -0,0 +1,58 @@ +#ifndef FILTER_NFC_H +#define FILTER_NFC_H + +struct NfcFilter1 { + float base_gain, gain; + float b1, a1; + float z[1]; +}; +struct NfcFilter2 { + float base_gain, gain; + float b1, b2, a1, a2; + float z[2]; +}; +struct NfcFilter3 { + float base_gain, gain; + float b1, b2, b3, a1, a2, a3; + float z[3]; +}; +struct NfcFilter4 { + float base_gain, gain; + float b1, b2, b3, b4, a1, a2, a3, a4; + float z[4]; +}; + +class NfcFilter { + NfcFilter1 first; + NfcFilter2 second; + NfcFilter3 third; + NfcFilter4 fourth; + +public: + /* NOTE: + * w0 = speed_of_sound / (source_distance * sample_rate); + * w1 = speed_of_sound / (control_distance * sample_rate); + * + * Generally speaking, the control distance should be approximately the + * average speaker distance, or based on the reference delay if outputing + * NFC-HOA. It must not be negative, 0, or infinite. The source distance + * should not be too small relative to the control distance. + */ + + void init(const float w1) noexcept; + void adjust(const float w0) noexcept; + + /* Near-field control filter for first-order ambisonic channels (1-3). */ + void process1(float *RESTRICT dst, const float *RESTRICT src, const int count); + + /* Near-field control filter for second-order ambisonic channels (4-8). */ + void process2(float *RESTRICT dst, const float *RESTRICT src, const int count); + + /* Near-field control filter for third-order ambisonic channels (9-15). */ + void process3(float *RESTRICT dst, const float *RESTRICT src, const int count); + + /* Near-field control filter for fourth-order ambisonic channels (16-24). */ + void process4(float *RESTRICT dst, const float *RESTRICT src, const int count); +}; + +#endif /* FILTER_NFC_H */ diff --git a/alc/filters/splitter.cpp b/alc/filters/splitter.cpp new file mode 100644 index 00000000..09e7bfe8 --- /dev/null +++ b/alc/filters/splitter.cpp @@ -0,0 +1,115 @@ + +#include "config.h" + +#include "splitter.h" + +#include +#include +#include + +#include "math_defs.h" + +template +void BandSplitterR::init(Real f0norm) +{ + const Real w{f0norm * al::MathDefs::Tau()}; + const Real cw{std::cos(w)}; + if(cw > std::numeric_limits::epsilon()) + coeff = (std::sin(w) - 1.0f) / cw; + else + coeff = cw * -0.5f; + + lp_z1 = 0.0f; + lp_z2 = 0.0f; + ap_z1 = 0.0f; +} + +template +void BandSplitterR::process(Real *hpout, Real *lpout, const Real *input, const int count) +{ + ASSUME(count > 0); + + const Real ap_coeff{this->coeff}; + const Real lp_coeff{this->coeff*0.5f + 0.5f}; + Real lp_z1{this->lp_z1}; + Real lp_z2{this->lp_z2}; + Real ap_z1{this->ap_z1}; + auto proc_sample = [ap_coeff,lp_coeff,&lp_z1,&lp_z2,&ap_z1,&lpout](const Real in) noexcept -> Real + { + /* Low-pass sample processing. */ + Real d{(in - lp_z1) * lp_coeff}; + Real lp_y{lp_z1 + d}; + lp_z1 = lp_y + d; + + d = (lp_y - lp_z2) * lp_coeff; + lp_y = lp_z2 + d; + lp_z2 = lp_y + d; + + *(lpout++) = lp_y; + + /* All-pass sample processing. */ + Real ap_y{in*ap_coeff + ap_z1}; + ap_z1 = in - ap_y*ap_coeff; + + /* High-pass generated from removing low-passed output. */ + return ap_y - lp_y; + }; + std::transform(input, input+count, hpout, proc_sample); + this->lp_z1 = lp_z1; + this->lp_z2 = lp_z2; + this->ap_z1 = ap_z1; +} + +template +void BandSplitterR::applyHfScale(Real *samples, const Real hfscale, const int count) +{ + ASSUME(count > 0); + + const Real ap_coeff{this->coeff}; + const Real lp_coeff{this->coeff*0.5f + 0.5f}; + Real lp_z1{this->lp_z1}; + Real lp_z2{this->lp_z2}; + Real ap_z1{this->ap_z1}; + auto proc_sample = [hfscale,ap_coeff,lp_coeff,&lp_z1,&lp_z2,&ap_z1](const Real in) noexcept -> Real + { + /* Low-pass sample processing. */ + Real d{(in - lp_z1) * lp_coeff}; + Real lp_y{lp_z1 + d}; + lp_z1 = lp_y + d; + + d = (lp_y - lp_z2) * lp_coeff; + lp_y = lp_z2 + d; + lp_z2 = lp_y + d; + + /* All-pass sample processing. */ + Real ap_y{in*ap_coeff + ap_z1}; + ap_z1 = in - ap_y*ap_coeff; + + /* High-pass generated from removing low-passed output. */ + return (ap_y-lp_y)*hfscale + lp_y; + }; + std::transform(samples, samples+count, samples, proc_sample); + this->lp_z1 = lp_z1; + this->lp_z2 = lp_z2; + this->ap_z1 = ap_z1; +} + +template +void BandSplitterR::applyAllpass(Real *samples, const int count) const +{ + ASSUME(count > 0); + + const Real coeff{this->coeff}; + Real z1{0.0f}; + auto proc_sample = [coeff,&z1](const Real in) noexcept -> Real + { + const Real out{in*coeff + z1}; + z1 = in - out*coeff; + return out; + }; + std::transform(samples, samples+count, samples, proc_sample); +} + + +template class BandSplitterR; +template class BandSplitterR; diff --git a/alc/filters/splitter.h b/alc/filters/splitter.h new file mode 100644 index 00000000..927c4d17 --- /dev/null +++ b/alc/filters/splitter.h @@ -0,0 +1,50 @@ +#ifndef FILTER_SPLITTER_H +#define FILTER_SPLITTER_H + +#include "alcmain.h" +#include "almalloc.h" + + +/* Band splitter. Splits a signal into two phase-matching frequency bands. */ +template +class BandSplitterR { + Real coeff{0.0f}; + Real lp_z1{0.0f}; + Real lp_z2{0.0f}; + Real ap_z1{0.0f}; + +public: + BandSplitterR() = default; + BandSplitterR(const BandSplitterR&) = default; + BandSplitterR(Real f0norm) { init(f0norm); } + + void init(Real f0norm); + void clear() noexcept { lp_z1 = lp_z2 = ap_z1 = 0.0f; } + void process(Real *hpout, Real *lpout, const Real *input, const int count); + + void applyHfScale(Real *samples, const Real hfscale, const int count); + + /* The all-pass portion of the band splitter. Applies the same phase shift + * without splitting the signal. Note that each use of this method is + * indepedent, it does not track history between calls. + */ + void applyAllpass(Real *samples, const int count) const; +}; +using BandSplitter = BandSplitterR; + + +struct FrontStablizer { + static constexpr size_t DelayLength{256u}; + + alignas(16) float DelayBuf[MAX_OUTPUT_CHANNELS][DelayLength]; + + BandSplitter LFilter, RFilter; + alignas(16) float LSplit[2][BUFFERSIZE]; + alignas(16) float RSplit[2][BUFFERSIZE]; + + alignas(16) float TempBuf[BUFFERSIZE + DelayLength]; + + DEF_NEWDEL(FrontStablizer) +}; + +#endif /* FILTER_SPLITTER_H */ diff --git a/alc/fpu_modes.h b/alc/fpu_modes.h new file mode 100644 index 00000000..5465e9cf --- /dev/null +++ b/alc/fpu_modes.h @@ -0,0 +1,25 @@ +#ifndef FPU_MODES_H +#define FPU_MODES_H + +class FPUCtl { +#if defined(HAVE_SSE_INTRINSICS) || (defined(__GNUC__) && defined(HAVE_SSE)) + unsigned int sse_state{}; +#endif + bool in_mode{}; + +public: + FPUCtl(); + /* HACK: 32-bit targets for GCC seem to have a problem here with certain + * noexcept methods (which destructors are) causing an internal compiler + * error. No idea why it's these methods specifically, but this is needed + * to get it to compile. + */ + ~FPUCtl() noexcept(false) { leave(); } + + FPUCtl(const FPUCtl&) = delete; + FPUCtl& operator=(const FPUCtl&) = delete; + + void leave(); +}; + +#endif /* FPU_MODES_H */ diff --git a/alc/helpers.cpp b/alc/helpers.cpp new file mode 100644 index 00000000..e86af6ce --- /dev/null +++ b/alc/helpers.cpp @@ -0,0 +1,851 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2011 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * 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 +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_DIRENT_H +#include +#endif +#ifdef HAVE_PROC_PIDPATH +#include +#endif + +#ifdef __FreeBSD__ +#include +#include +#endif + +#ifndef AL_NO_UID_DEFS +#if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H) +#define INITGUID +#include +#ifdef HAVE_GUIDDEF_H +#include +#else +#include +#endif + +DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71); +DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71); + +DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf,0x08, 0x00,0xa0,0xc9,0x25,0xcd,0x16); + +DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e,0x3d, 0xc4,0x57,0x92,0x91,0x69,0x2e); +DEFINE_GUID(IID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6); +DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2); +DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2); +DEFINE_GUID(IID_IAudioCaptureClient, 0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x18,0x5c,0x39,0x5c,0xd3,0x17); + +#ifdef HAVE_WASAPI +#include +#include +#include +DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23,0xe0, 0xc0,0xff,0xee,0x7f,0x0e, 4 ); +#endif +#endif +#endif /* AL_NO_UID_DEFS */ + +#ifdef HAVE_DLFCN_H +#include +#endif +#ifdef HAVE_INTRIN_H +#include +#endif +#ifdef HAVE_CPUID_H +#include +#endif +#ifdef HAVE_SSE_INTRINSICS +#include +#endif +#ifdef HAVE_SYS_SYSCONF_H +#include +#endif + +#ifndef _WIN32 +#include +#elif defined(_WIN32_IE) +#include +#endif + +#include "alcmain.h" +#include "almalloc.h" +#include "compat.h" +#include "cpu_caps.h" +#include "fpu_modes.h" +#include "logging.h" + + +#if defined(HAVE_GCC_GET_CPUID) && (defined(__i386__) || defined(__x86_64__) || \ + defined(_M_IX86) || defined(_M_X64)) +using reg_type = unsigned int; +static inline void get_cpuid(int f, reg_type *regs) +{ __get_cpuid(f, ®s[0], ®s[1], ®s[2], ®s[3]); } +#define CAN_GET_CPUID +#elif defined(HAVE_CPUID_INTRINSIC) && (defined(__i386__) || defined(__x86_64__) || \ + defined(_M_IX86) || defined(_M_X64)) +using reg_type = int; +static inline void get_cpuid(int f, reg_type *regs) +{ (__cpuid)(regs, f); } +#define CAN_GET_CPUID +#endif + +int CPUCapFlags = 0; + +void FillCPUCaps(int capfilter) +{ + int caps = 0; + +/* FIXME: We really should get this for all available CPUs in case different + * CPUs have different caps (is that possible on one machine?). */ +#ifdef CAN_GET_CPUID + union { + reg_type regs[4]; + char str[sizeof(reg_type[4])]; + } cpuinf[3] = {{ { 0, 0, 0, 0 } }}; + + get_cpuid(0, cpuinf[0].regs); + if(cpuinf[0].regs[0] == 0) + ERR("Failed to get CPUID\n"); + else + { + unsigned int maxfunc = cpuinf[0].regs[0]; + unsigned int maxextfunc; + + get_cpuid(0x80000000, cpuinf[0].regs); + maxextfunc = cpuinf[0].regs[0]; + + TRACE("Detected max CPUID function: 0x%x (ext. 0x%x)\n", maxfunc, maxextfunc); + + TRACE("Vendor ID: \"%.4s%.4s%.4s\"\n", cpuinf[0].str+4, cpuinf[0].str+12, cpuinf[0].str+8); + if(maxextfunc >= 0x80000004) + { + get_cpuid(0x80000002, cpuinf[0].regs); + get_cpuid(0x80000003, cpuinf[1].regs); + get_cpuid(0x80000004, cpuinf[2].regs); + TRACE("Name: \"%.16s%.16s%.16s\"\n", cpuinf[0].str, cpuinf[1].str, cpuinf[2].str); + } + + if(maxfunc >= 1) + { + get_cpuid(1, cpuinf[0].regs); + if((cpuinf[0].regs[3]&(1<<25))) + caps |= CPU_CAP_SSE; + if((caps&CPU_CAP_SSE) && (cpuinf[0].regs[3]&(1<<26))) + caps |= CPU_CAP_SSE2; + if((caps&CPU_CAP_SSE2) && (cpuinf[0].regs[2]&(1<<0))) + caps |= CPU_CAP_SSE3; + if((caps&CPU_CAP_SSE3) && (cpuinf[0].regs[2]&(1<<19))) + caps |= CPU_CAP_SSE4_1; + } + } +#else + /* Assume support for whatever's supported if we can't check for it */ +#if defined(HAVE_SSE4_1) +#warning "Assuming SSE 4.1 run-time support!" + caps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1; +#elif defined(HAVE_SSE3) +#warning "Assuming SSE 3 run-time support!" + caps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3; +#elif defined(HAVE_SSE2) +#warning "Assuming SSE 2 run-time support!" + caps |= CPU_CAP_SSE | CPU_CAP_SSE2; +#elif defined(HAVE_SSE) +#warning "Assuming SSE run-time support!" + caps |= CPU_CAP_SSE; +#endif +#endif +#ifdef HAVE_NEON + al::ifstream file{"/proc/cpuinfo"}; + if(!file.is_open()) + ERR("Failed to open /proc/cpuinfo, cannot check for NEON support\n"); + else + { + std::string features; + + auto getline = [](std::istream &f, std::string &output) -> bool + { + while(f.good() && f.peek() == '\n') + f.ignore(); + return std::getline(f, output) && !output.empty(); + + }; + while(getline(file, features)) + { + if(features.compare(0, 10, "Features\t:", 10) == 0) + break; + } + file.close(); + + size_t extpos{9}; + while((extpos=features.find("neon", extpos+1)) != std::string::npos) + { + if((extpos == 0 || std::isspace(features[extpos-1])) && + (extpos+4 == features.length() || std::isspace(features[extpos+4]))) + { + caps |= CPU_CAP_NEON; + break; + } + } + } +#endif + + TRACE("Extensions:%s%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_SSE3) ? ((caps&CPU_CAP_SSE3) ? " +SSE3" : " -SSE3") : ""), + ((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; +} + + +FPUCtl::FPUCtl() +{ +#if defined(HAVE_SSE_INTRINSICS) + this->sse_state = _mm_getcsr(); + unsigned int sseState = this->sse_state; + sseState |= 0x8000; /* set flush-to-zero */ + sseState |= 0x0040; /* set denormals-are-zero */ + _mm_setcsr(sseState); + +#elif defined(__GNUC__) && defined(HAVE_SSE) + + if((CPUCapFlags&CPU_CAP_SSE)) + { + __asm__ __volatile__("stmxcsr %0" : "=m" (*&this->sse_state)); + unsigned int sseState = this->sse_state; + sseState |= 0x8000; /* set flush-to-zero */ + if((CPUCapFlags&CPU_CAP_SSE2)) + sseState |= 0x0040; /* set denormals-are-zero */ + __asm__ __volatile__("ldmxcsr %0" : : "m" (*&sseState)); + } +#endif + + this->in_mode = true; +} + +void FPUCtl::leave() +{ + if(!this->in_mode) return; + +#if defined(HAVE_SSE_INTRINSICS) + _mm_setcsr(this->sse_state); + +#elif defined(__GNUC__) && defined(HAVE_SSE) + + if((CPUCapFlags&CPU_CAP_SSE)) + __asm__ __volatile__("ldmxcsr %0" : : "m" (*&this->sse_state)); +#endif + this->in_mode = false; +} + + +#ifdef _WIN32 + +namespace al { + +auto filebuf::underflow() -> int_type +{ + if(mFile != INVALID_HANDLE_VALUE && gptr() == egptr()) + { + // Read in the next chunk of data, and set the pointers on success + DWORD got{}; + if(ReadFile(mFile, mBuffer.data(), (DWORD)mBuffer.size(), &got, nullptr)) + setg(mBuffer.data(), mBuffer.data(), mBuffer.data()+got); + } + if(gptr() == egptr()) + return traits_type::eof(); + return traits_type::to_int_type(*gptr()); +} + +auto filebuf::seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) -> pos_type +{ + if(mFile == INVALID_HANDLE_VALUE || (mode&std::ios_base::out) || !(mode&std::ios_base::in)) + return traits_type::eof(); + + LARGE_INTEGER fpos{}; + switch(whence) + { + case std::ios_base::beg: + fpos.QuadPart = offset; + if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_BEGIN)) + return traits_type::eof(); + break; + + case std::ios_base::cur: + // If the offset remains in the current buffer range, just + // update the pointer. + if((offset >= 0 && offset < off_type(egptr()-gptr())) || + (offset < 0 && -offset <= off_type(gptr()-eback()))) + { + // Get the current file offset to report the correct read + // offset. + fpos.QuadPart = 0; + if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_CURRENT)) + return traits_type::eof(); + setg(eback(), gptr()+offset, egptr()); + return fpos.QuadPart - off_type(egptr()-gptr()); + } + // Need to offset for the file offset being at egptr() while + // the requested offset is relative to gptr(). + offset -= off_type(egptr()-gptr()); + fpos.QuadPart = offset; + if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_CURRENT)) + return traits_type::eof(); + break; + + case std::ios_base::end: + fpos.QuadPart = offset; + if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_END)) + return traits_type::eof(); + break; + + default: + return traits_type::eof(); + } + setg(nullptr, nullptr, nullptr); + return fpos.QuadPart; +} + +auto filebuf::seekpos(pos_type pos, std::ios_base::openmode mode) -> pos_type +{ + // Simplified version of seekoff + if(mFile == INVALID_HANDLE_VALUE || (mode&std::ios_base::out) || !(mode&std::ios_base::in)) + return traits_type::eof(); + + LARGE_INTEGER fpos{}; + fpos.QuadPart = pos; + if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_BEGIN)) + return traits_type::eof(); + + setg(nullptr, nullptr, nullptr); + return fpos.QuadPart; +} + +filebuf::~filebuf() +{ + if(mFile != INVALID_HANDLE_VALUE) + CloseHandle(mFile); + mFile = INVALID_HANDLE_VALUE; +} + +bool filebuf::open(const wchar_t *filename, std::ios_base::openmode mode) +{ + if((mode&std::ios_base::out) || !(mode&std::ios_base::in)) + return false; + HANDLE f{CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, nullptr)}; + if(f == INVALID_HANDLE_VALUE) return false; + + if(mFile != INVALID_HANDLE_VALUE) + CloseHandle(mFile); + mFile = f; + + setg(nullptr, nullptr, nullptr); + return true; +} +bool filebuf::open(const char *filename, std::ios_base::openmode mode) +{ + std::wstring wname{utf8_to_wstr(filename)}; + return open(wname.c_str(), mode); +} + + +ifstream::ifstream(const wchar_t *filename, std::ios_base::openmode mode) + : std::istream{nullptr} +{ + init(&mStreamBuf); + + // Set the failbit if the file failed to open. + if((mode&std::ios_base::out) || !mStreamBuf.open(filename, mode|std::ios_base::in)) + clear(failbit); +} + +ifstream::ifstream(const char *filename, std::ios_base::openmode mode) + : std::istream{nullptr} +{ + init(&mStreamBuf); + + // Set the failbit if the file failed to open. + if((mode&std::ios_base::out) || !mStreamBuf.open(filename, mode|std::ios_base::in)) + clear(failbit); +} + +/* This is only here to ensure the compiler doesn't define an implicit + * destructor, which it tries to automatically inline and subsequently complain + * it can't inline without excessive code growth. + */ +ifstream::~ifstream() { } + +} // namespace al + +const PathNamePair &GetProcBinary() +{ + static PathNamePair ret; + if(!ret.fname.empty() || !ret.path.empty()) + return ret; + + al::vector fullpath(256); + DWORD len; + while((len=GetModuleFileNameW(nullptr, fullpath.data(), static_cast(fullpath.size()))) == fullpath.size()) + fullpath.resize(fullpath.size() << 1); + if(len == 0) + { + ERR("Failed to get process name: error %lu\n", GetLastError()); + return ret; + } + + fullpath.resize(len); + if(fullpath.back() != 0) + fullpath.push_back(0); + + auto sep = std::find(fullpath.rbegin()+1, fullpath.rend(), '\\'); + sep = std::find(fullpath.rbegin()+1, sep, '/'); + if(sep != fullpath.rend()) + { + *sep = 0; + ret.fname = wstr_to_utf8(&*sep + 1); + ret.path = wstr_to_utf8(fullpath.data()); + } + else + ret.fname = wstr_to_utf8(fullpath.data()); + + TRACE("Got binary: %s, %s\n", ret.path.c_str(), ret.fname.c_str()); + return ret; +} + + +void *LoadLib(const char *name) +{ + std::wstring wname{utf8_to_wstr(name)}; + return LoadLibraryW(wname.c_str()); +} +void CloseLib(void *handle) +{ FreeLibrary(static_cast(handle)); } +void *GetSymbol(void *handle, const char *name) +{ + void *ret{reinterpret_cast(GetProcAddress(static_cast(handle), name))}; + if(!ret) ERR("Failed to load %s\n", name); + return ret; +} + + +void al_print(FILE *logfile, const char *fmt, ...) +{ + al::vector dynmsg; + char stcmsg[256]; + char *str{stcmsg}; + + va_list args, args2; + va_start(args, fmt); + va_copy(args2, args); + int msglen{std::vsnprintf(str, sizeof(stcmsg), fmt, args)}; + if(UNLIKELY(msglen >= 0 && static_cast(msglen) >= sizeof(stcmsg))) + { + dynmsg.resize(static_cast(msglen) + 1u); + str = dynmsg.data(); + msglen = std::vsnprintf(str, dynmsg.size(), fmt, args2); + } + va_end(args2); + va_end(args); + + std::wstring wstr{utf8_to_wstr(str)}; + fprintf(logfile, "%ls", wstr.c_str()); + fflush(logfile); +} + + +static inline int is_slash(int c) +{ return (c == '\\' || c == '/'); } + +static void DirectorySearch(const char *path, const char *ext, al::vector *const results) +{ + std::string pathstr{path}; + pathstr += "\\*"; + pathstr += ext; + TRACE("Searching %s\n", pathstr.c_str()); + + std::wstring wpath{utf8_to_wstr(pathstr.c_str())}; + WIN32_FIND_DATAW fdata; + HANDLE hdl{FindFirstFileW(wpath.c_str(), &fdata)}; + if(hdl != INVALID_HANDLE_VALUE) + { + size_t base = results->size(); + do { + results->emplace_back(); + std::string &str = results->back(); + str = path; + str += '\\'; + str += wstr_to_utf8(fdata.cFileName); + TRACE("Got result %s\n", str.c_str()); + } while(FindNextFileW(hdl, &fdata)); + FindClose(hdl); + + std::sort(results->begin()+base, results->end()); + } +} + +al::vector SearchDataFiles(const char *ext, const char *subdir) +{ + static std::mutex search_lock; + std::lock_guard _{search_lock}; + + /* If the path is absolute, use it directly. */ + al::vector results; + if(isalpha(subdir[0]) && subdir[1] == ':' && is_slash(subdir[2])) + { + std::string path{subdir}; + std::replace(path.begin(), path.end(), '/', '\\'); + DirectorySearch(path.c_str(), ext, &results); + return results; + } + if(subdir[0] == '\\' && subdir[1] == '\\' && subdir[2] == '?' && subdir[3] == '\\') + { + DirectorySearch(subdir, ext, &results); + return results; + } + + std::string path; + + /* Search the app-local directory. */ + WCHAR *cwdbuf{_wgetenv(L"ALSOFT_LOCAL_PATH")}; + if(cwdbuf && *cwdbuf != '\0') + { + path = wstr_to_utf8(cwdbuf); + if(is_slash(path.back())) + path.pop_back(); + } + else if(!(cwdbuf=_wgetcwd(nullptr, 0))) + path = "."; + else + { + path = wstr_to_utf8(cwdbuf); + if(is_slash(path.back())) + path.pop_back(); + free(cwdbuf); + } + std::replace(path.begin(), path.end(), '/', '\\'); + DirectorySearch(path.c_str(), ext, &results); + + /* Search the local and global data dirs. */ + static constexpr int ids[2]{ CSIDL_APPDATA, CSIDL_COMMON_APPDATA }; + for(int id : ids) + { + WCHAR buffer[MAX_PATH]; + if(SHGetSpecialFolderPathW(nullptr, buffer, id, FALSE) == FALSE) + continue; + + path = wstr_to_utf8(buffer); + if(!is_slash(path.back())) + path += '\\'; + path += subdir; + std::replace(path.begin(), path.end(), '/', '\\'); + + DirectorySearch(path.c_str(), ext, &results); + } + + return results; +} + +void SetRTPriority(void) +{ + bool failed = false; + if(RTPrioLevel > 0) + failed = !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); + if(failed) ERR("Failed to set priority level for thread\n"); +} + +#else + +const PathNamePair &GetProcBinary() +{ + static PathNamePair ret; + if(!ret.fname.empty() || !ret.path.empty()) + return ret; + + al::vector pathname; +#ifdef __FreeBSD__ + size_t pathlen; + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + if(sysctl(mib, 4, nullptr, &pathlen, nullptr, 0) == -1) + WARN("Failed to sysctl kern.proc.pathname: %s\n", strerror(errno)); + else + { + pathname.resize(pathlen + 1); + sysctl(mib, 4, pathname.data(), &pathlen, nullptr, 0); + pathname.resize(pathlen); + } +#endif +#ifdef HAVE_PROC_PIDPATH + if(pathname.empty()) + { + char procpath[PROC_PIDPATHINFO_MAXSIZE]{}; + const pid_t pid{getpid()}; + if(proc_pidpath(pid, procpath, sizeof(procpath)) < 1) + ERR("proc_pidpath(%d, ...) failed: %s\n", pid, strerror(errno)); + else + pathname.insert(pathname.end(), procpath, procpath+strlen(procpath)); + } +#endif + if(pathname.empty()) + { + pathname.resize(256); + + const char *selfname{"/proc/self/exe"}; + ssize_t len{readlink(selfname, pathname.data(), pathname.size())}; + if(len == -1 && errno == ENOENT) + { + selfname = "/proc/self/file"; + len = readlink(selfname, pathname.data(), pathname.size()); + } + if(len == -1 && errno == ENOENT) + { + selfname = "/proc/curproc/exe"; + len = readlink(selfname, pathname.data(), pathname.size()); + } + if(len == -1 && errno == ENOENT) + { + selfname = "/proc/curproc/file"; + len = readlink(selfname, pathname.data(), pathname.size()); + } + + while(len > 0 && static_cast(len) == pathname.size()) + { + pathname.resize(pathname.size() << 1); + len = readlink(selfname, pathname.data(), pathname.size()); + } + if(len <= 0) + { + WARN("Failed to readlink %s: %s\n", selfname, strerror(errno)); + return ret; + } + + pathname.resize(len); + } + while(!pathname.empty() && pathname.back() == 0) + pathname.pop_back(); + + auto sep = std::find(pathname.crbegin(), pathname.crend(), '/'); + if(sep != pathname.crend()) + { + ret.path = std::string(pathname.cbegin(), sep.base()-1); + ret.fname = std::string(sep.base(), pathname.cend()); + } + else + ret.fname = std::string(pathname.cbegin(), pathname.cend()); + + TRACE("Got binary: %s, %s\n", ret.path.c_str(), ret.fname.c_str()); + return ret; +} + + +#ifdef HAVE_DLFCN_H + +void *LoadLib(const char *name) +{ + dlerror(); + void *handle{dlopen(name, RTLD_NOW)}; + const char *err{dlerror()}; + if(err) handle = nullptr; + return handle; +} +void CloseLib(void *handle) +{ dlclose(handle); } +void *GetSymbol(void *handle, const char *name) +{ + dlerror(); + void *sym{dlsym(handle, name)}; + const char *err{dlerror()}; + if(err) + { + WARN("Failed to load %s: %s\n", name, err); + sym = nullptr; + } + return sym; +} + +#endif /* HAVE_DLFCN_H */ + +void al_print(FILE *logfile, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(logfile, fmt, ap); + va_end(ap); + + fflush(logfile); +} + + +static void DirectorySearch(const char *path, const char *ext, al::vector *const results) +{ + TRACE("Searching %s for *%s\n", path, ext); + DIR *dir{opendir(path)}; + if(dir != nullptr) + { + const size_t extlen = strlen(ext); + size_t base = results->size(); + + struct dirent *dirent; + while((dirent=readdir(dir)) != nullptr) + { + if(strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) + continue; + + size_t len{strlen(dirent->d_name)}; + if(len <= extlen) continue; + if(strcasecmp(dirent->d_name+len-extlen, ext) != 0) + continue; + + results->emplace_back(); + std::string &str = results->back(); + str = path; + if(str.back() != '/') + str.push_back('/'); + str += dirent->d_name; + TRACE("Got result %s\n", str.c_str()); + } + closedir(dir); + + std::sort(results->begin()+base, results->end()); + } +} + +al::vector SearchDataFiles(const char *ext, const char *subdir) +{ + static std::mutex search_lock; + std::lock_guard _{search_lock}; + + al::vector results; + if(subdir[0] == '/') + { + DirectorySearch(subdir, ext, &results); + return results; + } + + /* Search the app-local directory. */ + const char *str{getenv("ALSOFT_LOCAL_PATH")}; + if(str && *str != '\0') + DirectorySearch(str, ext, &results); + else + { + al::vector cwdbuf(256); + while(!getcwd(cwdbuf.data(), cwdbuf.size())) + { + if(errno != ERANGE) + { + cwdbuf.clear(); + break; + } + cwdbuf.resize(cwdbuf.size() << 1); + } + if(cwdbuf.empty()) + DirectorySearch(".", ext, &results); + else + { + DirectorySearch(cwdbuf.data(), ext, &results); + cwdbuf.clear(); + } + } + + // Search local data dir + if((str=getenv("XDG_DATA_HOME")) != nullptr && str[0] != '\0') + { + std::string path{str}; + if(path.back() != '/') + path += '/'; + path += subdir; + DirectorySearch(path.c_str(), ext, &results); + } + else if((str=getenv("HOME")) != nullptr && str[0] != '\0') + { + std::string path{str}; + if(path.back() == '/') + path.pop_back(); + path += "/.local/share/"; + path += subdir; + DirectorySearch(path.c_str(), ext, &results); + } + + // Search global data dirs + if((str=getenv("XDG_DATA_DIRS")) == nullptr || str[0] == '\0') + str = "/usr/local/share/:/usr/share/"; + + const char *next{str}; + while((str=next) != nullptr && str[0] != '\0') + { + next = strchr(str, ':'); + + std::string path = (next ? std::string(str, next++) : std::string(str)); + if(path.empty()) continue; + + if(path.back() != '/') + path += '/'; + path += subdir; + + DirectorySearch(path.c_str(), ext, &results); + } + + return results; +} + +void SetRTPriority() +{ + bool failed = false; +#if defined(HAVE_PTHREAD_SETSCHEDPARAM) && !defined(__OpenBSD__) + if(RTPrioLevel > 0) + { + struct sched_param param; + /* Use the minimum real-time priority possible for now (on Linux this + * should be 1 for SCHED_RR) */ + param.sched_priority = sched_get_priority_min(SCHED_RR); + failed = !!pthread_setschedparam(pthread_self(), SCHED_RR, ¶m); + } +#else + /* Real-time priority not available */ + failed = (RTPrioLevel>0); +#endif + if(failed) + ERR("Failed to set priority level for thread\n"); +} + +#endif diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp new file mode 100644 index 00000000..786c4c5d --- /dev/null +++ b/alc/hrtf.cpp @@ -0,0 +1,1400 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2011 by Chris Robinson + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "hrtf.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" + +#include "alcmain.h" +#include "alconfig.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "aloptional.h" +#include "alspan.h" +#include "compat.h" +#include "filters/splitter.h" +#include "logging.h" +#include "math_defs.h" +#include "opthelpers.h" + + +struct HrtfHandle { + std::unique_ptr entry; + al::FlexArray filename; + + HrtfHandle(size_t fname_len) : filename{fname_len} { } + HrtfHandle(const HrtfHandle&) = delete; + HrtfHandle& operator=(const HrtfHandle&) = delete; + + static std::unique_ptr Create(size_t fname_len); + static constexpr size_t Sizeof(size_t length) noexcept + { + return maxz(sizeof(HrtfHandle), + al::FlexArray::Sizeof(length, offsetof(HrtfHandle, filename))); + } + + DEF_PLACE_NEWDEL() +}; + +std::unique_ptr HrtfHandle::Create(size_t fname_len) +{ + void *ptr{al_calloc(alignof(HrtfHandle), HrtfHandle::Sizeof(fname_len))}; + return std::unique_ptr{new (ptr) HrtfHandle{fname_len}}; +} + +namespace { + +using namespace std::placeholders; + +using HrtfHandlePtr = std::unique_ptr; + +/* Data set limits must be the same as or more flexible than those defined in + * the makemhr utility. + */ +#define MIN_IR_SIZE (8) +#define MAX_IR_SIZE (512) +#define MOD_IR_SIZE (2) + +#define MIN_FD_COUNT (1) +#define MAX_FD_COUNT (16) + +#define MIN_FD_DISTANCE (0.05f) +#define MAX_FD_DISTANCE (2.5f) + +#define MIN_EV_COUNT (5) +#define MAX_EV_COUNT (128) + +#define MIN_AZ_COUNT (1) +#define MAX_AZ_COUNT (128) + +#define MAX_HRIR_DELAY (HRTF_HISTORY_LENGTH-1) + +constexpr ALchar magicMarker00[8]{'M','i','n','P','H','R','0','0'}; +constexpr ALchar magicMarker01[8]{'M','i','n','P','H','R','0','1'}; +constexpr ALchar magicMarker02[8]{'M','i','n','P','H','R','0','2'}; + +/* First value for pass-through coefficients (remaining are 0), used for omni- + * directional sounds. */ +constexpr ALfloat PassthruCoeff{0.707106781187f/*sqrt(0.5)*/}; + +std::mutex LoadedHrtfLock; +al::vector LoadedHrtfs; + + +class databuf final : public std::streambuf { + int_type underflow() override + { return traits_type::eof(); } + + pos_type seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) override + { + if((mode&std::ios_base::out) || !(mode&std::ios_base::in)) + return traits_type::eof(); + + char_type *cur; + switch(whence) + { + case std::ios_base::beg: + if(offset < 0 || offset > egptr()-eback()) + return traits_type::eof(); + cur = eback() + offset; + break; + + case std::ios_base::cur: + if((offset >= 0 && offset > egptr()-gptr()) || + (offset < 0 && -offset > gptr()-eback())) + return traits_type::eof(); + cur = gptr() + offset; + break; + + case std::ios_base::end: + if(offset > 0 || -offset > egptr()-eback()) + return traits_type::eof(); + cur = egptr() + offset; + break; + + default: + return traits_type::eof(); + } + + setg(eback(), cur, egptr()); + return cur - eback(); + } + + pos_type seekpos(pos_type pos, std::ios_base::openmode mode) override + { + // Simplified version of seekoff + if((mode&std::ios_base::out) || !(mode&std::ios_base::in)) + return traits_type::eof(); + + if(pos < 0 || pos > egptr()-eback()) + return traits_type::eof(); + + setg(eback(), eback() + static_cast(pos), egptr()); + return pos; + } + +public: + databuf(const char_type *start, const char_type *end) noexcept + { + setg(const_cast(start), const_cast(start), + const_cast(end)); + } +}; + +class idstream final : public std::istream { + databuf mStreamBuf; + +public: + idstream(const char *start, const char *end) + : std::istream{nullptr}, mStreamBuf{start, end} + { init(&mStreamBuf); } +}; + + +struct IdxBlend { ALsizei idx; ALfloat blend; }; +/* Calculate the elevation index given the polar elevation in radians. This + * will return an index between 0 and (evcount - 1). + */ +IdxBlend CalcEvIndex(ALsizei evcount, ALfloat ev) +{ + ev = (al::MathDefs::Pi()*0.5f + ev) * (evcount-1) / al::MathDefs::Pi(); + ALsizei idx{float2int(ev)}; + + return IdxBlend{mini(idx, evcount-1), ev-idx}; +} + +/* Calculate the azimuth index given the polar azimuth in radians. This will + * return an index between 0 and (azcount - 1). + */ +IdxBlend CalcAzIndex(ALsizei azcount, ALfloat az) +{ + az = (al::MathDefs::Tau()+az) * azcount / al::MathDefs::Tau(); + ALsizei idx{float2int(az)}; + + return IdxBlend{idx%azcount, az-idx}; +} + +} // namespace + + +/* Calculates static HRIR coefficients and delays for the given polar elevation + * and azimuth in radians. The coefficients are normalized. + */ +void GetHrtfCoeffs(const HrtfEntry *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat distance, + ALfloat spread, HrirArray &coeffs, ALsizei (&delays)[2]) +{ + const ALfloat dirfact{1.0f - (spread / al::MathDefs::Tau())}; + + const auto *field = Hrtf->field; + const auto *field_end = field + Hrtf->fdCount-1; + ALsizei ebase{0}; + while(distance < field->distance && field != field_end) + { + ebase += field->evCount; + ++field; + } + + /* Claculate the elevation indinces. */ + const auto elev0 = CalcEvIndex(field->evCount, elevation); + const ALsizei elev1_idx{mini(elev0.idx+1, field->evCount-1)}; + const ALsizei ir0offset{Hrtf->elev[ebase + elev0.idx].irOffset}; + const ALsizei ir1offset{Hrtf->elev[ebase + elev1_idx].irOffset}; + + /* Calculate azimuth indices. */ + const auto az0 = CalcAzIndex(Hrtf->elev[ebase + elev0.idx].azCount, azimuth); + const auto az1 = CalcAzIndex(Hrtf->elev[ebase + elev1_idx].azCount, azimuth); + + /* Calculate the HRIR indices to blend. */ + ALsizei idx[4]{ + ir0offset + az0.idx, + ir0offset + ((az0.idx+1) % Hrtf->elev[ebase + elev0.idx].azCount), + ir1offset + az1.idx, + ir1offset + ((az1.idx+1) % Hrtf->elev[ebase + elev1_idx].azCount) + }; + + /* Calculate bilinear blending weights, attenuated according to the + * directional panning factor. + */ + const ALfloat blend[4]{ + (1.0f-elev0.blend) * (1.0f-az0.blend) * dirfact, + (1.0f-elev0.blend) * ( az0.blend) * dirfact, + ( elev0.blend) * (1.0f-az1.blend) * dirfact, + ( elev0.blend) * ( az1.blend) * dirfact + }; + + /* Calculate the blended HRIR delays. */ + delays[0] = fastf2i( + Hrtf->delays[idx[0]][0]*blend[0] + Hrtf->delays[idx[1]][0]*blend[1] + + Hrtf->delays[idx[2]][0]*blend[2] + Hrtf->delays[idx[3]][0]*blend[3] + ); + delays[1] = fastf2i( + Hrtf->delays[idx[0]][1]*blend[0] + Hrtf->delays[idx[1]][1]*blend[1] + + Hrtf->delays[idx[2]][1]*blend[2] + Hrtf->delays[idx[3]][1]*blend[3] + ); + + const ALsizei irSize{Hrtf->irSize}; + ASSUME(irSize >= MIN_IR_SIZE); + + /* Calculate the sample offsets for the HRIR indices. */ + idx[0] *= irSize; + idx[1] *= irSize; + idx[2] *= irSize; + idx[3] *= irSize; + + /* Calculate the blended HRIR coefficients. */ + ALfloat *coeffout{al::assume_aligned<16>(&coeffs[0][0])}; + coeffout[0] = PassthruCoeff * (1.0f-dirfact); + coeffout[1] = PassthruCoeff * (1.0f-dirfact); + std::fill(coeffout+2, coeffout + irSize*2, 0.0f); + for(ALsizei c{0};c < 4;c++) + { + const ALfloat *srccoeffs{al::assume_aligned<16>(Hrtf->coeffs[idx[c]])}; + const ALfloat mult{blend[c]}; + auto blend_coeffs = [mult](const ALfloat src, const ALfloat coeff) noexcept -> ALfloat + { return src*mult + coeff; }; + std::transform(srccoeffs, srccoeffs + irSize*2, coeffout, coeffout, blend_coeffs); + } +} + + +std::unique_ptr DirectHrtfState::Create(size_t num_chans) +{ + void *ptr{al_calloc(16, DirectHrtfState::Sizeof(num_chans))}; + return std::unique_ptr{new (ptr) DirectHrtfState{num_chans}}; +} + +void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuint NumChannels, + const AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_CHANNELS], + const size_t AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain) +{ + static constexpr int OrderFromChan[MAX_AMBI_CHANNELS]{ + 0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3, + }; + /* Set this to true for dual-band HRTF processing. May require better + * calculation of the new IR length to deal with the head and tail + * generated by the HF scaling. + */ + static constexpr bool DualBand{true}; + + ASSUME(NumChannels > 0); + ASSUME(AmbiCount > 0); + + auto &field = Hrtf->field[0]; + ALsizei min_delay{HRTF_HISTORY_LENGTH}; + ALsizei max_delay{0}; + auto idx = al::vector(AmbiCount); + auto calc_idxs = [Hrtf,&field,&max_delay,&min_delay](const AngularPoint &pt) noexcept -> ALsizei + { + /* Calculate elevation index. */ + const auto evidx = clampi( + static_cast((90.0f+pt.Elev)*(field.evCount-1)/180.0f + 0.5f), + 0, field.evCount-1); + + const ALsizei azcount{Hrtf->elev[evidx].azCount}; + const ALsizei iroffset{Hrtf->elev[evidx].irOffset}; + + /* Calculate azimuth index for this elevation. */ + const auto azidx = static_cast((360.0f+pt.Azim)*azcount/360.0f + 0.5f) % azcount; + + /* Calculate the index for the impulse response. */ + ALsizei idx{iroffset + azidx}; + + min_delay = mini(min_delay, mini(Hrtf->delays[idx][0], Hrtf->delays[idx][1])); + max_delay = maxi(max_delay, maxi(Hrtf->delays[idx][0], Hrtf->delays[idx][1])); + + return idx; + }; + std::transform(AmbiPoints, AmbiPoints+AmbiCount, idx.begin(), calc_idxs); + + /* For dual-band processing, add a 16-sample delay to compensate for the HF + * scale on the minimum-phase response. + */ + static constexpr ALsizei base_delay{DualBand ? 16 : 0}; + const ALdouble xover_norm{400.0 / Hrtf->sampleRate}; + BandSplitterR splitter{xover_norm}; + + auto tmpres = al::vector>(NumChannels); + auto tmpfilt = al::vector>(3); + for(size_t c{0u};c < AmbiCount;++c) + { + const ALfloat (*fir)[2]{&Hrtf->coeffs[idx[c] * Hrtf->irSize]}; + const ALsizei ldelay{Hrtf->delays[idx[c]][0] - min_delay + base_delay}; + const ALsizei rdelay{Hrtf->delays[idx[c]][1] - min_delay + base_delay}; + + if(!DualBand) + { + /* For single-band decoding, apply the HF scale to the response. */ + for(ALuint i{0u};i < NumChannels;++i) + { + const ALdouble mult{ALdouble{AmbiOrderHFGain[OrderFromChan[i]]} * + AmbiMatrix[c][i]}; + const ALsizei numirs{mini(Hrtf->irSize, HRIR_LENGTH-maxi(ldelay, rdelay))}; + ALsizei lidx{ldelay}, ridx{rdelay}; + for(ALsizei j{0};j < numirs;++j) + { + tmpres[i][lidx++][0] += fir[j][0] * mult; + tmpres[i][ridx++][1] += fir[j][1] * mult; + } + } + continue; + } + + /* For dual-band processing, the HRIR needs to be split into low and + * high frequency responses. The band-splitter alone creates frequency- + * dependent phase-shifts, which is not ideal. To counteract it, + * combine it with a backwards phase-shift. + */ + + /* Load the (left) HRIR backwards, into a temp buffer with padding. */ + std::fill(tmpfilt[2].begin(), tmpfilt[2].end(), 0.0); + std::transform(fir, fir+Hrtf->irSize, tmpfilt[2].rbegin() + HRIR_LENGTH*3, + [](const ALfloat (&ir)[2]) noexcept -> ALdouble { return ir[0]; }); + + /* Apply the all-pass on the reversed signal and reverse the resulting + * sample array. This produces the forward response with a backwards + * phase-shift (+n degrees becomes -n degrees). + */ + splitter.applyAllpass(tmpfilt[2].data(), static_cast(tmpfilt[2].size())); + std::reverse(tmpfilt[2].begin(), tmpfilt[2].end()); + + /* Now apply the band-splitter. This applies the normal phase-shift, + * which cancels out with the backwards phase-shift to get the original + * phase on the split signal. + */ + splitter.clear(); + splitter.process(tmpfilt[0].data(), tmpfilt[1].data(), tmpfilt[2].data(), + static_cast(tmpfilt[2].size())); + + /* Apply left ear response with delay and HF scale. */ + for(ALuint i{0u};i < NumChannels;++i) + { + const ALdouble mult{AmbiMatrix[c][i]}; + const ALdouble hfgain{AmbiOrderHFGain[OrderFromChan[i]]}; + ALsizei j{HRIR_LENGTH*3 - ldelay}; + for(ALsizei lidx{0};lidx < HRIR_LENGTH;++lidx,++j) + tmpres[i][lidx][0] += (tmpfilt[0][j]*hfgain + tmpfilt[1][j]) * mult; + } + + /* Now run the same process on the right HRIR. */ + std::fill(tmpfilt[2].begin(), tmpfilt[2].end(), 0.0); + std::transform(fir, fir+Hrtf->irSize, tmpfilt[2].rbegin() + HRIR_LENGTH*3, + [](const ALfloat (&ir)[2]) noexcept -> ALdouble { return ir[1]; }); + + splitter.applyAllpass(tmpfilt[2].data(), static_cast(tmpfilt[2].size())); + std::reverse(tmpfilt[2].begin(), tmpfilt[2].end()); + + splitter.clear(); + splitter.process(tmpfilt[0].data(), tmpfilt[1].data(), tmpfilt[2].data(), + static_cast(tmpfilt[2].size())); + + for(ALuint i{0u};i < NumChannels;++i) + { + const ALdouble mult{AmbiMatrix[c][i]}; + const ALdouble hfgain{AmbiOrderHFGain[OrderFromChan[i]]}; + ALsizei j{HRIR_LENGTH*3 - rdelay}; + for(ALsizei ridx{0};ridx < HRIR_LENGTH;++ridx,++j) + tmpres[i][ridx][1] += (tmpfilt[0][j]*hfgain + tmpfilt[1][j]) * mult; + } + } + tmpfilt.clear(); + idx.clear(); + + for(ALuint i{0u};i < NumChannels;++i) + { + auto copy_arr = [](const std::array &in) noexcept -> std::array + { return std::array{{static_cast(in[0]), static_cast(in[1])}}; }; + std::transform(tmpres[i].begin(), tmpres[i].end(), state->Chan[i].Coeffs.begin(), + copy_arr); + } + tmpres.clear(); + + ALsizei max_length{HRIR_LENGTH}; + /* Increase the IR size by double the base delay with dual-band processing + * to account for the head and tail from the HF response scale. + */ + const ALsizei irsize{mini(Hrtf->irSize + base_delay*2, max_length)}; + max_length = mini(max_delay-min_delay + irsize, max_length); + + /* Round up to the next IR size multiple. */ + max_length += MOD_IR_SIZE-1; + max_length -= max_length%MOD_IR_SIZE; + + TRACE("Skipped delay: %d, max delay: %d, new FIR length: %d\n", + min_delay, max_delay-min_delay, max_length); + state->IrSize = max_length; +} + + +namespace { + +std::unique_ptr CreateHrtfStore(ALuint rate, ALsizei irSize, const ALsizei fdCount, + const ALubyte *evCount, const ALfloat *distance, const ALushort *azCount, + const ALushort *irOffset, ALsizei irCount, const ALfloat (*coeffs)[2], + const ALubyte (*delays)[2], const char *filename) +{ + std::unique_ptr Hrtf; + + ALsizei evTotal{std::accumulate(evCount, evCount+fdCount, 0)}; + size_t total{sizeof(HrtfEntry)}; + total = RoundUp(total, alignof(HrtfEntry::Field)); /* Align for field infos */ + total += sizeof(HrtfEntry::Field)*fdCount; + total = RoundUp(total, alignof(HrtfEntry::Elevation)); /* Align for elevation infos */ + total += sizeof(Hrtf->elev[0])*evTotal; + total = RoundUp(total, 16); /* Align for coefficients using SIMD */ + total += sizeof(Hrtf->coeffs[0])*irSize*irCount; + total += sizeof(Hrtf->delays[0])*irCount; + + Hrtf.reset(new (al_calloc(16, total)) HrtfEntry{}); + if(!Hrtf) + ERR("Out of memory allocating storage for %s.\n", filename); + else + { + InitRef(&Hrtf->ref, 1u); + Hrtf->sampleRate = rate; + Hrtf->irSize = irSize; + Hrtf->fdCount = fdCount; + + /* Set up pointers to storage following the main HRTF struct. */ + char *base = reinterpret_cast(Hrtf.get()); + uintptr_t offset = sizeof(HrtfEntry); + + offset = RoundUp(offset, alignof(HrtfEntry::Field)); /* Align for field infos */ + auto field_ = reinterpret_cast(base + offset); + offset += sizeof(field_[0])*fdCount; + + offset = RoundUp(offset, alignof(HrtfEntry::Elevation)); /* Align for elevation infos */ + auto elev_ = reinterpret_cast(base + offset); + offset += sizeof(elev_[0])*evTotal; + + offset = RoundUp(offset, 16); /* Align for coefficients using SIMD */ + auto coeffs_ = reinterpret_cast(base + offset); + offset += sizeof(coeffs_[0])*irSize*irCount; + + auto delays_ = reinterpret_cast(base + offset); + offset += sizeof(delays_[0])*irCount; + + assert(offset == total); + + /* Copy input data to storage. */ + for(ALsizei i{0};i < fdCount;i++) + { + field_[i].distance = distance[i]; + field_[i].evCount = evCount[i]; + } + for(ALsizei i{0};i < evTotal;i++) + { + elev_[i].azCount = azCount[i]; + elev_[i].irOffset = irOffset[i]; + } + for(ALsizei i{0};i < irSize*irCount;i++) + { + coeffs_[i][0] = coeffs[i][0]; + coeffs_[i][1] = coeffs[i][1]; + } + for(ALsizei i{0};i < irCount;i++) + { + delays_[i][0] = delays[i][0]; + delays_[i][1] = delays[i][1]; + } + + /* Finally, assign the storage pointers. */ + Hrtf->field = field_; + Hrtf->elev = elev_; + Hrtf->coeffs = coeffs_; + Hrtf->delays = delays_; + } + + return Hrtf; +} + +ALubyte GetLE_ALubyte(std::istream &data) +{ + return static_cast(data.get()); +} + +ALshort GetLE_ALshort(std::istream &data) +{ + int ret = data.get(); + ret |= data.get() << 8; + return static_cast((ret^32768) - 32768); +} + +ALushort GetLE_ALushort(std::istream &data) +{ + int ret = data.get(); + ret |= data.get() << 8; + return static_cast(ret); +} + +ALint GetLE_ALint24(std::istream &data) +{ + int ret = data.get(); + ret |= data.get() << 8; + ret |= data.get() << 16; + return (ret^8388608) - 8388608; +} + +ALuint GetLE_ALuint(std::istream &data) +{ + int ret = data.get(); + ret |= data.get() << 8; + ret |= data.get() << 16; + ret |= data.get() << 24; + return ret; +} + +std::unique_ptr LoadHrtf00(std::istream &data, const char *filename) +{ + ALuint rate{GetLE_ALuint(data)}; + ALushort irCount{GetLE_ALushort(data)}; + ALushort irSize{GetLE_ALushort(data)}; + ALubyte evCount{GetLE_ALubyte(data)}; + if(!data || data.eof()) + { + ERR("Failed reading %s\n", filename); + return nullptr; + } + + ALboolean failed{AL_FALSE}; + if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) + { + ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", + irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE); + failed = AL_TRUE; + } + if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT) + { + ERR("Unsupported elevation count: evCount=%d (%d to %d)\n", + evCount, MIN_EV_COUNT, MAX_EV_COUNT); + failed = AL_TRUE; + } + if(failed) + return nullptr; + + al::vector evOffset(evCount); + for(auto &val : evOffset) + val = GetLE_ALushort(data); + if(!data || data.eof()) + { + ERR("Failed reading %s\n", filename); + return nullptr; + } + for(ALsizei i{1};i < evCount;i++) + { + if(evOffset[i] <= evOffset[i-1]) + { + ERR("Invalid evOffset: evOffset[%d]=%d (last=%d)\n", + i, evOffset[i], evOffset[i-1]); + failed = AL_TRUE; + } + } + if(irCount <= evOffset.back()) + { + ERR("Invalid evOffset: evOffset[%zu]=%d (irCount=%d)\n", + evOffset.size()-1, evOffset.back(), irCount); + failed = AL_TRUE; + } + if(failed) + return nullptr; + + al::vector azCount(evCount); + for(ALsizei i{1};i < evCount;i++) + { + azCount[i-1] = evOffset[i] - evOffset[i-1]; + if(azCount[i-1] < MIN_AZ_COUNT || azCount[i-1] > MAX_AZ_COUNT) + { + ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", + i-1, azCount[i-1], MIN_AZ_COUNT, MAX_AZ_COUNT); + failed = AL_TRUE; + } + } + azCount.back() = irCount - evOffset.back(); + if(azCount.back() < MIN_AZ_COUNT || azCount.back() > MAX_AZ_COUNT) + { + ERR("Unsupported azimuth count: azCount[%zu]=%d (%d to %d)\n", + azCount.size()-1, azCount.back(), MIN_AZ_COUNT, MAX_AZ_COUNT); + failed = AL_TRUE; + } + if(failed) + return nullptr; + + al::vector> coeffs(irSize*irCount); + al::vector> delays(irCount); + for(auto &val : coeffs) + val[0] = GetLE_ALshort(data) / 32768.0f; + for(auto &val : delays) + val[0] = GetLE_ALubyte(data); + if(!data || data.eof()) + { + ERR("Failed reading %s\n", filename); + return nullptr; + } + for(ALsizei i{0};i < irCount;i++) + { + if(delays[i][0] > MAX_HRIR_DELAY) + { + ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); + failed = AL_TRUE; + } + } + if(failed) + return nullptr; + + /* Mirror the left ear responses to the right ear. */ + for(ALsizei i{0};i < evCount;i++) + { + const ALushort evoffset{evOffset[i]}; + const ALushort azcount{azCount[i]}; + for(ALsizei j{0};j < azcount;j++) + { + const ALsizei lidx{evoffset + j}; + const ALsizei ridx{evoffset + ((azcount-j) % azcount)}; + + for(ALsizei k{0};k < irSize;k++) + coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; + delays[ridx][1] = delays[lidx][0]; + } + } + + static constexpr ALfloat distance{0.0f}; + return CreateHrtfStore(rate, irSize, 1, &evCount, &distance, azCount.data(), evOffset.data(), + irCount, &reinterpret_cast(coeffs[0]), + &reinterpret_cast(delays[0]), filename); +} + +std::unique_ptr LoadHrtf01(std::istream &data, const char *filename) +{ + ALuint rate{GetLE_ALuint(data)}; + ALushort irSize{GetLE_ALubyte(data)}; + ALubyte evCount{GetLE_ALubyte(data)}; + if(!data || data.eof()) + { + ERR("Failed reading %s\n", filename); + return nullptr; + } + + ALboolean failed{AL_FALSE}; + if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) + { + ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", + irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE); + failed = AL_TRUE; + } + if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT) + { + ERR("Unsupported elevation count: evCount=%d (%d to %d)\n", + evCount, MIN_EV_COUNT, MAX_EV_COUNT); + failed = AL_TRUE; + } + if(failed) + return nullptr; + + al::vector azCount(evCount); + std::generate(azCount.begin(), azCount.end(), std::bind(GetLE_ALubyte, std::ref(data))); + if(!data || data.eof()) + { + ERR("Failed reading %s\n", filename); + return nullptr; + } + for(ALsizei i{0};i < evCount;++i) + { + if(azCount[i] < MIN_AZ_COUNT || azCount[i] > MAX_AZ_COUNT) + { + ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", + i, azCount[i], MIN_AZ_COUNT, MAX_AZ_COUNT); + failed = AL_TRUE; + } + } + if(failed) + return nullptr; + + al::vector evOffset(evCount); + evOffset[0] = 0; + ALushort irCount{azCount[0]}; + for(ALsizei i{1};i < evCount;i++) + { + evOffset[i] = evOffset[i-1] + azCount[i-1]; + irCount += azCount[i]; + } + + al::vector> coeffs(irSize*irCount); + al::vector> delays(irCount); + for(auto &val : coeffs) + val[0] = GetLE_ALshort(data) / 32768.0f; + for(auto &val : delays) + val[0] = GetLE_ALubyte(data); + if(!data || data.eof()) + { + ERR("Failed reading %s\n", filename); + return nullptr; + } + for(ALsizei i{0};i < irCount;i++) + { + if(delays[i][0] > MAX_HRIR_DELAY) + { + ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); + failed = AL_TRUE; + } + } + if(failed) + return nullptr; + + /* Mirror the left ear responses to the right ear. */ + for(ALsizei i{0};i < evCount;i++) + { + const ALushort evoffset{evOffset[i]}; + const ALushort azcount{azCount[i]}; + for(ALsizei j{0};j < azcount;j++) + { + const ALsizei lidx{evoffset + j}; + const ALsizei ridx{evoffset + ((azcount-j) % azcount)}; + + for(ALsizei k{0};k < irSize;k++) + coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; + delays[ridx][1] = delays[lidx][0]; + } + } + + static constexpr ALfloat distance{0.0f}; + return CreateHrtfStore(rate, irSize, 1, &evCount, &distance, azCount.data(), evOffset.data(), + irCount, &reinterpret_cast(coeffs[0]), + &reinterpret_cast(delays[0]), filename); +} + +#define SAMPLETYPE_S16 0 +#define SAMPLETYPE_S24 1 + +#define CHANTYPE_LEFTONLY 0 +#define CHANTYPE_LEFTRIGHT 1 + +std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) +{ + ALuint rate{GetLE_ALuint(data)}; + ALubyte sampleType{GetLE_ALubyte(data)}; + ALubyte channelType{GetLE_ALubyte(data)}; + ALushort irSize{GetLE_ALubyte(data)}; + ALubyte fdCount{GetLE_ALubyte(data)}; + if(!data || data.eof()) + { + ERR("Failed reading %s\n", filename); + return nullptr; + } + + ALboolean failed{AL_FALSE}; + if(sampleType > SAMPLETYPE_S24) + { + ERR("Unsupported sample type: %d\n", sampleType); + failed = AL_TRUE; + } + if(channelType > CHANTYPE_LEFTRIGHT) + { + ERR("Unsupported channel type: %d\n", channelType); + failed = AL_TRUE; + } + + if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) + { + ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", + irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE); + failed = AL_TRUE; + } + if(fdCount < 1 || fdCount > MAX_FD_COUNT) + { + ERR("Multiple field-depths not supported: fdCount=%d (%d to %d)\n", + fdCount, MIN_FD_COUNT, MAX_FD_COUNT); + failed = AL_TRUE; + } + if(failed) + return nullptr; + + al::vector distance(fdCount); + al::vector evCount(fdCount); + al::vector azCount; + for(ALsizei f{0};f < fdCount;f++) + { + distance[f] = GetLE_ALushort(data) / 1000.0f; + evCount[f] = GetLE_ALubyte(data); + if(!data || data.eof()) + { + ERR("Failed reading %s\n", filename); + return nullptr; + } + + if(distance[f] < MIN_FD_DISTANCE || distance[f] > MAX_FD_DISTANCE) + { + ERR("Unsupported field distance[%d]=%f (%f to %f meters)\n", f, + distance[f], MIN_FD_DISTANCE, MAX_FD_DISTANCE); + failed = AL_TRUE; + } + if(f > 0 && distance[f] <= distance[f-1]) + { + ERR("Field distance[%d] is not after previous (%f > %f)\n", f, distance[f], + distance[f-1]); + failed = AL_TRUE; + } + if(evCount[f] < MIN_EV_COUNT || evCount[f] > MAX_EV_COUNT) + { + ERR("Unsupported elevation count: evCount[%d]=%d (%d to %d)\n", f, + evCount[f], MIN_EV_COUNT, MAX_EV_COUNT); + failed = AL_TRUE; + } + if(failed) + return nullptr; + + size_t ebase{azCount.size()}; + azCount.resize(ebase + evCount[f]); + std::generate(azCount.begin()+ebase, azCount.end(), + std::bind(GetLE_ALubyte, std::ref(data))); + if(!data || data.eof()) + { + ERR("Failed reading %s\n", filename); + return nullptr; + } + + for(ALsizei e{0};e < evCount[f];e++) + { + if(azCount[ebase+e] < MIN_AZ_COUNT || azCount[ebase+e] > MAX_AZ_COUNT) + { + ERR("Unsupported azimuth count: azCount[%d][%d]=%d (%d to %d)\n", f, e, + azCount[ebase+e], MIN_AZ_COUNT, MAX_AZ_COUNT); + failed = AL_TRUE; + } + } + if(failed) + return nullptr; + } + + al::vector evOffset(azCount.size()); + evOffset[0] = 0; + std::partial_sum(azCount.cbegin(), azCount.cend()-1, evOffset.begin()+1); + const ALsizei irTotal{evOffset.back() + azCount.back()}; + + al::vector> coeffs(irSize*irTotal); + al::vector> delays(irTotal); + if(channelType == CHANTYPE_LEFTONLY) + { + if(sampleType == SAMPLETYPE_S16) + { + for(auto &val : coeffs) + val[0] = GetLE_ALshort(data) / 32768.0f; + } + else if(sampleType == SAMPLETYPE_S24) + { + for(auto &val : coeffs) + val[0] = GetLE_ALint24(data) / 8388608.0f; + } + for(auto &val : delays) + val[0] = GetLE_ALubyte(data); + if(!data || data.eof()) + { + ERR("Failed reading %s\n", filename); + return nullptr; + } + for(ALsizei i{0};i < irTotal;++i) + { + if(delays[i][0] > MAX_HRIR_DELAY) + { + ERR("Invalid delays[%d][0]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); + failed = AL_TRUE; + } + } + } + else if(channelType == CHANTYPE_LEFTRIGHT) + { + if(sampleType == SAMPLETYPE_S16) + { + for(auto &val : coeffs) + { + val[0] = GetLE_ALshort(data) / 32768.0f; + val[1] = GetLE_ALshort(data) / 32768.0f; + } + } + else if(sampleType == SAMPLETYPE_S24) + { + for(auto &val : coeffs) + { + val[0] = GetLE_ALint24(data) / 8388608.0f; + val[1] = GetLE_ALint24(data) / 8388608.0f; + } + } + for(auto &val : delays) + { + val[0] = GetLE_ALubyte(data); + val[1] = GetLE_ALubyte(data); + } + if(!data || data.eof()) + { + ERR("Failed reading %s\n", filename); + return nullptr; + } + + for(ALsizei i{0};i < irTotal;++i) + { + if(delays[i][0] > MAX_HRIR_DELAY) + { + ERR("Invalid delays[%d][0]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); + failed = AL_TRUE; + } + if(delays[i][1] > MAX_HRIR_DELAY) + { + ERR("Invalid delays[%d][1]: %d (%d)\n", i, delays[i][1], MAX_HRIR_DELAY); + failed = AL_TRUE; + } + } + } + if(failed) + return nullptr; + + if(channelType == CHANTYPE_LEFTONLY) + { + /* Mirror the left ear responses to the right ear. */ + ALsizei ebase{0}; + for(ALsizei f{0};f < fdCount;f++) + { + for(ALsizei e{0};e < evCount[f];e++) + { + const ALushort evoffset{evOffset[ebase+e]}; + const ALushort azcount{azCount[ebase+e]}; + for(ALsizei a{0};a < azcount;a++) + { + const ALsizei lidx{evoffset + a}; + const ALsizei ridx{evoffset + ((azcount-a) % azcount)}; + + for(ALsizei k{0};k < irSize;k++) + coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; + delays[ridx][1] = delays[lidx][0]; + } + } + ebase += evCount[f]; + } + } + + if(fdCount > 1) + { + auto distance_ = al::vector(distance.size()); + auto evCount_ = al::vector(evCount.size()); + auto azCount_ = al::vector(azCount.size()); + auto evOffset_ = al::vector(evOffset.size()); + auto coeffs_ = al::vector(coeffs.size()); + auto delays_ = al::vector>(delays.size()); + + /* Simple reverse for the per-field elements. */ + std::reverse_copy(distance.cbegin(), distance.cend(), distance_.begin()); + std::reverse_copy(evCount.cbegin(), evCount.cend(), evCount_.begin()); + + /* Each field has a group of elevations, which each have an azimuth + * count. Reverse the order of the groups, keeping the relative order + * of per-group azimuth counts. + */ + auto azcnt_end = azCount_.end(); + auto copy_azs = [&azCount,&azcnt_end](const size_t ebase, const ALubyte num_evs) -> size_t + { + auto azcnt_src = azCount.begin()+ebase; + azcnt_end = std::copy_backward(azcnt_src, azcnt_src+num_evs, azcnt_end); + return ebase + num_evs; + }; + std::accumulate(evCount.cbegin(), evCount.cend(), size_t{0u}, copy_azs); + assert(azCount_.begin() == azcnt_end); + + /* Reestablish the IR offset for each elevation index, given the new + * ordering of elevations. + */ + evOffset_[0] = 0; + std::partial_sum(azCount_.cbegin(), azCount_.cend()-1, evOffset_.begin()+1); + + /* Reverse the order of each field's group of IRs. */ + auto coeffs_end = coeffs_.end(); + auto delays_end = delays_.end(); + auto copy_irs = [irSize,&azCount,&coeffs,&delays,&coeffs_end,&delays_end](const size_t ebase, const ALubyte num_evs) -> size_t + { + const ALsizei abase{std::accumulate(azCount.cbegin(), azCount.cbegin()+ebase, 0)}; + const ALsizei num_azs{std::accumulate(azCount.cbegin()+ebase, + azCount.cbegin() + (ebase+num_evs), 0)}; + + coeffs_end = std::copy_backward(coeffs.cbegin() + abase*irSize, + coeffs.cbegin() + (abase+num_azs)*irSize, coeffs_end); + delays_end = std::copy_backward(delays.cbegin() + abase, + delays.cbegin() + (abase+num_azs), delays_end); + + return ebase + num_evs; + }; + std::accumulate(evCount.cbegin(), evCount.cend(), size_t{0u}, copy_irs); + assert(coeffs_.begin() == coeffs_end); + assert(delays_.begin() == delays_end); + + distance = std::move(distance_); + evCount = std::move(evCount_); + azCount = std::move(azCount_); + evOffset = std::move(evOffset_); + coeffs = std::move(coeffs_); + delays = std::move(delays_); + } + + return CreateHrtfStore(rate, irSize, fdCount, evCount.data(), distance.data(), azCount.data(), + evOffset.data(), irTotal, &reinterpret_cast(coeffs[0]), + &reinterpret_cast(delays[0]), filename); +} + + +bool checkName(al::vector &list, const std::string &name) +{ + return std::find_if(list.cbegin(), list.cend(), + [&name](const EnumeratedHrtf &entry) + { return name == entry.name; } + ) != list.cend(); +} + +void AddFileEntry(al::vector &list, const std::string &filename) +{ + /* Check if this file has already been loaded globally. */ + auto loaded_entry = LoadedHrtfs.begin(); + for(;loaded_entry != LoadedHrtfs.end();++loaded_entry) + { + if(filename != (*loaded_entry)->filename.data()) + continue; + + /* Check if this entry has already been added to the list. */ + auto iter = std::find_if(list.cbegin(), list.cend(), + [loaded_entry](const EnumeratedHrtf &entry) -> bool + { return loaded_entry->get() == entry.hrtf; } + ); + if(iter != list.cend()) + { + TRACE("Skipping duplicate file entry %s\n", filename.c_str()); + return; + } + + break; + } + + if(loaded_entry == LoadedHrtfs.end()) + { + TRACE("Got new file \"%s\"\n", filename.c_str()); + + LoadedHrtfs.emplace_back(HrtfHandle::Create(filename.length()+1)); + loaded_entry = LoadedHrtfs.end()-1; + std::copy(filename.begin(), filename.end(), (*loaded_entry)->filename.begin()); + (*loaded_entry)->filename.back() = '\0'; + } + + /* TODO: Get a human-readable name from the HRTF data (possibly coming in a + * format update). */ + size_t namepos = filename.find_last_of('/')+1; + if(!namepos) namepos = filename.find_last_of('\\')+1; + + size_t extpos{filename.find_last_of('.')}; + if(extpos <= namepos) extpos = std::string::npos; + + const std::string basename{(extpos == std::string::npos) ? + filename.substr(namepos) : filename.substr(namepos, extpos-namepos)}; + std::string newname{basename}; + int count{1}; + while(checkName(list, newname)) + { + newname = basename; + newname += " #"; + newname += std::to_string(++count); + } + list.emplace_back(EnumeratedHrtf{newname, loaded_entry->get()}); + const EnumeratedHrtf &entry = list.back(); + + TRACE("Adding file entry \"%s\"\n", entry.name.c_str()); +} + +/* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer + * for input instead of opening the given filename. + */ +void AddBuiltInEntry(al::vector &list, const std::string &filename, ALuint residx) +{ + auto loaded_entry = LoadedHrtfs.begin(); + for(;loaded_entry != LoadedHrtfs.end();++loaded_entry) + { + if(filename != (*loaded_entry)->filename.data()) + continue; + + /* Check if this entry has already been added to the list. */ + auto iter = std::find_if(list.cbegin(), list.cend(), + [loaded_entry](const EnumeratedHrtf &entry) -> bool + { return loaded_entry->get() == entry.hrtf; } + ); + if(iter != list.cend()) + { + TRACE("Skipping duplicate file entry %s\n", filename.c_str()); + return; + } + + break; + } + + if(loaded_entry == LoadedHrtfs.end()) + { + TRACE("Got new file \"%s\"\n", filename.c_str()); + + LoadedHrtfs.emplace_back(HrtfHandle::Create(filename.length()+32)); + loaded_entry = LoadedHrtfs.end()-1; + snprintf((*loaded_entry)->filename.data(), (*loaded_entry)->filename.size(), "!%u_%s", + residx, filename.c_str()); + } + + /* TODO: Get a human-readable name from the HRTF data (possibly coming in a + * format update). */ + + std::string newname{filename}; + int count{1}; + while(checkName(list, newname)) + { + newname = filename; + newname += " #"; + newname += std::to_string(++count); + } + list.emplace_back(EnumeratedHrtf{newname, loaded_entry->get()}); + const EnumeratedHrtf &entry = list.back(); + + TRACE("Adding built-in entry \"%s\"\n", entry.name.c_str()); +} + + +#define IDR_DEFAULT_44100_MHR 1 +#define IDR_DEFAULT_48000_MHR 2 + +using ResData = al::span; +#ifndef ALSOFT_EMBED_HRTF_DATA + +ResData GetResource(int /*name*/) +{ return ResData{}; } + +#else + +#include "default-44100.mhr.h" +#include "default-48000.mhr.h" + +ResData GetResource(int name) +{ + if(name == IDR_DEFAULT_44100_MHR) + return {reinterpret_cast(hrtf_default_44100), sizeof(hrtf_default_44100)}; + if(name == IDR_DEFAULT_48000_MHR) + return {reinterpret_cast(hrtf_default_48000), sizeof(hrtf_default_48000)}; + return ResData{}; +} +#endif + +} // namespace + + +al::vector EnumerateHrtf(const char *devname) +{ + al::vector list; + + bool usedefaults{true}; + if(auto pathopt = ConfigValueStr(devname, nullptr, "hrtf-paths")) + { + const char *pathlist{pathopt->c_str()}; + while(pathlist && *pathlist) + { + const char *next, *end; + + while(isspace(*pathlist) || *pathlist == ',') + pathlist++; + if(*pathlist == '\0') + continue; + + next = strchr(pathlist, ','); + if(next) + end = next++; + else + { + end = pathlist + strlen(pathlist); + usedefaults = false; + } + + while(end != pathlist && isspace(*(end-1))) + --end; + if(end != pathlist) + { + const std::string pname{pathlist, end}; + for(const auto &fname : SearchDataFiles(".mhr", pname.c_str())) + AddFileEntry(list, fname); + } + + pathlist = next; + } + } + else if(ConfigValueExists(devname, nullptr, "hrtf_tables")) + ERR("The hrtf_tables option is deprecated, please use hrtf-paths instead.\n"); + + if(usedefaults) + { + for(const auto &fname : SearchDataFiles(".mhr", "openal/hrtf")) + AddFileEntry(list, fname); + + if(!GetResource(IDR_DEFAULT_44100_MHR).empty()) + AddBuiltInEntry(list, "Built-In 44100hz", IDR_DEFAULT_44100_MHR); + + if(!GetResource(IDR_DEFAULT_48000_MHR).empty()) + AddBuiltInEntry(list, "Built-In 48000hz", IDR_DEFAULT_48000_MHR); + } + + if(!list.empty()) + { + if(auto defhrtfopt = ConfigValueStr(devname, nullptr, "default-hrtf")) + { + auto iter = std::find_if(list.begin(), list.end(), + [&defhrtfopt](const EnumeratedHrtf &entry) -> bool + { return entry.name == *defhrtfopt; } + ); + if(iter == list.end()) + WARN("Failed to find default HRTF \"%s\"\n", defhrtfopt->c_str()); + else if(iter != list.begin()) + { + EnumeratedHrtf entry{std::move(*iter)}; + list.erase(iter); + list.insert(list.begin(), std::move(entry)); + } + } + } + + return list; +} + +HrtfEntry *GetLoadedHrtf(HrtfHandle *handle) +{ + std::lock_guard _{LoadedHrtfLock}; + + if(handle->entry) + { + HrtfEntry *hrtf{handle->entry.get()}; + hrtf->IncRef(); + return hrtf; + } + + std::unique_ptr stream; + const char *name{""}; + ALuint residx{}; + char ch{}; + if(sscanf(handle->filename.data(), "!%u%c", &residx, &ch) == 2 && ch == '_') + { + name = strchr(handle->filename.data(), ch)+1; + + TRACE("Loading %s...\n", name); + ResData res{GetResource(residx)}; + if(res.empty()) + { + ERR("Could not get resource %u, %s\n", residx, name); + return nullptr; + } + stream = al::make_unique(res.begin(), res.end()); + } + else + { + name = handle->filename.data(); + + TRACE("Loading %s...\n", handle->filename.data()); + auto fstr = al::make_unique(handle->filename.data(), std::ios::binary); + if(!fstr->is_open()) + { + ERR("Could not open %s\n", handle->filename.data()); + return nullptr; + } + stream = std::move(fstr); + } + + std::unique_ptr hrtf; + char magic[sizeof(magicMarker02)]; + stream->read(magic, sizeof(magic)); + if(stream->gcount() < static_cast(sizeof(magicMarker02))) + ERR("%s data is too short (%zu bytes)\n", name, stream->gcount()); + else if(memcmp(magic, magicMarker02, sizeof(magicMarker02)) == 0) + { + TRACE("Detected data set format v2\n"); + hrtf = LoadHrtf02(*stream, name); + } + else if(memcmp(magic, magicMarker01, sizeof(magicMarker01)) == 0) + { + TRACE("Detected data set format v1\n"); + hrtf = LoadHrtf01(*stream, name); + } + else if(memcmp(magic, magicMarker00, sizeof(magicMarker00)) == 0) + { + TRACE("Detected data set format v0\n"); + hrtf = LoadHrtf00(*stream, name); + } + else + ERR("Invalid header in %s: \"%.8s\"\n", name, magic); + stream.reset(); + + if(!hrtf) + { + ERR("Failed to load %s\n", name); + return nullptr; + } + + TRACE("Loaded HRTF support for format: %s %uhz\n", + DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); + handle->entry = std::move(hrtf); + + return handle->entry.get(); +} + + +void HrtfEntry::IncRef() +{ + auto ref = IncrementRef(&this->ref); + TRACEREF("HrtfEntry %p increasing refcount to %u\n", this, ref); +} + +void HrtfEntry::DecRef() +{ + auto ref = DecrementRef(&this->ref); + TRACEREF("HrtfEntry %p decreasing refcount to %u\n", this, ref); + if(ref == 0) + { + std::lock_guard _{LoadedHrtfLock}; + + /* Go through and clear all unused HRTFs. */ + auto delete_unused = [](HrtfHandlePtr &handle) -> void + { + HrtfEntry *entry{handle->entry.get()}; + if(entry && ReadRef(&entry->ref) == 0) + { + TRACE("Unloading unused HRTF %s\n", handle->filename.data()); + handle->entry = nullptr; + } + }; + std::for_each(LoadedHrtfs.begin(), LoadedHrtfs.end(), delete_unused); + } +} diff --git a/alc/hrtf.h b/alc/hrtf.h new file mode 100644 index 00000000..6c41cb82 --- /dev/null +++ b/alc/hrtf.h @@ -0,0 +1,124 @@ +#ifndef ALC_HRTF_H +#define ALC_HRTF_H + +#include +#include +#include +#include + +#include "AL/al.h" + +#include "almalloc.h" +#include "ambidefs.h" +#include "atomic.h" +#include "vector.h" + + +struct HrtfHandle; + +#define HRTF_HISTORY_BITS (6) +#define HRTF_HISTORY_LENGTH (1<; + +template +using HrirArray = std::array,HRIR_LENGTH>; + +struct HrtfState { + alignas(16) std::array History; + alignas(16) HrirArray Values; +}; + +struct HrtfFilter { + alignas(16) HrirArray Coeffs; + ALsizei Delay[2]; + ALfloat Gain; +}; + +struct DirectHrtfState { + /* HRTF filter state for dry buffer content */ + ALsizei IrSize{0}; + struct ChanData { + alignas(16) HrirArray Values; + alignas(16) HrirArray Coeffs; + }; + al::FlexArray Chan; + + DirectHrtfState(size_t numchans) : Chan{numchans} { } + DirectHrtfState(const DirectHrtfState&) = delete; + DirectHrtfState& operator=(const DirectHrtfState&) = delete; + + static std::unique_ptr Create(size_t num_chans); + static constexpr size_t Sizeof(size_t numchans) noexcept + { return al::FlexArray::Sizeof(numchans, offsetof(DirectHrtfState, Chan)); } + + DEF_PLACE_NEWDEL() +}; + +struct AngularPoint { + ALfloat Elev; + ALfloat Azim; +}; + + +al::vector EnumerateHrtf(const char *devname); +HrtfEntry *GetLoadedHrtf(HrtfHandle *handle); + +void GetHrtfCoeffs(const HrtfEntry *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat distance, + ALfloat spread, HrirArray &coeffs, ALsizei (&delays)[2]); + +/** + * Produces HRTF filter coefficients for decoding B-Format, given a set of + * virtual speaker positions, a matching decoding matrix, and per-order high- + * frequency gains for the decoder. The calculated impulse responses are + * ordered and scaled according to the matrix input. Note the specified virtual + * positions should be in degrees, not radians! + */ +void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuint NumChannels, + const AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_CHANNELS], + const size_t AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain); + +#endif /* ALC_HRTF_H */ diff --git a/alc/inprogext.h b/alc/inprogext.h new file mode 100644 index 00000000..15881b59 --- /dev/null +++ b/alc/inprogext.h @@ -0,0 +1,92 @@ +#ifndef INPROGEXT_H +#define INPROGEXT_H + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ALC_SOFT_loopback_bformat +#define ALC_SOFT_loopback_bformat 1 +#define ALC_AMBISONIC_LAYOUT_SOFT 0x1997 +#define ALC_AMBISONIC_SCALING_SOFT 0x1998 +#define ALC_AMBISONIC_ORDER_SOFT 0x1999 +#define ALC_MAX_AMBISONIC_ORDER_SOFT 0x199B + +#define ALC_BFORMAT3D_SOFT 0x1508 + +/* Ambisonic layouts */ +#define ALC_FUMA_SOFT 0x0000 +#define ALC_ACN_SOFT 0x0001 + +/* Ambisonic scalings (normalization) */ +/*#define ALC_FUMA_SOFT*/ +#define ALC_SN3D_SOFT 0x0001 +#define ALC_N3D_SOFT 0x0002 +#endif + +#ifndef AL_SOFT_map_buffer +#define AL_SOFT_map_buffer 1 +typedef unsigned int ALbitfieldSOFT; +#define AL_MAP_READ_BIT_SOFT 0x00000001 +#define AL_MAP_WRITE_BIT_SOFT 0x00000002 +#define AL_MAP_PERSISTENT_BIT_SOFT 0x00000004 +#define AL_PRESERVE_DATA_BIT_SOFT 0x00000008 +typedef void (AL_APIENTRY*LPALBUFFERSTORAGESOFT)(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags); +typedef void* (AL_APIENTRY*LPALMAPBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); +typedef void (AL_APIENTRY*LPALUNMAPBUFFERSOFT)(ALuint buffer); +typedef void (AL_APIENTRY*LPALFLUSHMAPPEDBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags); +AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); +AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer); +AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length); +#endif +#endif + +#ifndef AL_SOFT_events +#define AL_SOFT_events 1 +#define AL_EVENT_CALLBACK_FUNCTION_SOFT 0x1220 +#define AL_EVENT_CALLBACK_USER_PARAM_SOFT 0x1221 +#define AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT 0x1222 +#define AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT 0x1223 +#define AL_EVENT_TYPE_ERROR_SOFT 0x1224 +#define AL_EVENT_TYPE_PERFORMANCE_SOFT 0x1225 +#define AL_EVENT_TYPE_DEPRECATED_SOFT 0x1226 +#define AL_EVENT_TYPE_DISCONNECTED_SOFT 0x1227 +typedef void (AL_APIENTRY*ALEVENTPROCSOFT)(ALenum eventType, ALuint object, ALuint param, + ALsizei length, const ALchar *message, + void *userParam); +typedef void (AL_APIENTRY*LPALEVENTCONTROLSOFT)(ALsizei count, const ALenum *types, ALboolean enable); +typedef void (AL_APIENTRY*LPALEVENTCALLBACKSOFT)(ALEVENTPROCSOFT callback, void *userParam); +typedef void* (AL_APIENTRY*LPALGETPOINTERSOFT)(ALenum pname); +typedef void (AL_APIENTRY*LPALGETPOINTERVSOFT)(ALenum pname, void **values); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable); +AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam); +AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname); +AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values); +#endif +#endif + +#ifndef AL_SOFT_buffer_layers +#define AL_SOFT_buffer_layers +typedef void (AL_APIENTRY*LPALSOURCEQUEUEBUFFERLAYERSSOFT)(ALuint src, ALsizei nb, const ALuint *buffers); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers); +#endif +#endif + +#ifndef AL_SOFT_effect_chain +#define AL_SOFT_effect_chain +#define AL_EFFECTSLOT_TARGET_SOFT 0xf000 +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* INPROGEXT_H */ diff --git a/alc/logging.h b/alc/logging.h new file mode 100644 index 00000000..0bb0c87b --- /dev/null +++ b/alc/logging.h @@ -0,0 +1,64 @@ +#ifndef LOGGING_H +#define LOGGING_H + +#include + +#include "opthelpers.h" + + +#ifdef __GNUC__ +#define DECL_FORMAT(x, y, z) __attribute__((format(x, (y), (z)))) +#else +#define DECL_FORMAT(x, y, z) +#endif + + +extern FILE *gLogFile; + +void al_print(FILE *logfile, const char *fmt, ...) DECL_FORMAT(printf, 2,3); +#if !defined(_WIN32) +#define AL_PRINT(T, ...) fprintf(gLogFile, "AL lib: " T " " __VA_ARGS__) +#else +#define AL_PRINT(T, ...) al_print(gLogFile, "AL lib: " T " " __VA_ARGS__) +#endif + +#ifdef __ANDROID__ +#include +#define LOG_ANDROID(T, ...) __android_log_print(T, "openal", "AL lib: " __VA_ARGS__) +#else +#define LOG_ANDROID(T, ...) ((void)0) +#endif + +enum LogLevel { + NoLog, + LogError, + LogWarning, + LogTrace, + LogRef +}; +extern LogLevel gLogLevel; + +#define TRACEREF(...) do { \ + if(UNLIKELY(gLogLevel >= LogRef)) \ + AL_PRINT("(--)", __VA_ARGS__); \ +} while(0) + +#define TRACE(...) do { \ + if(UNLIKELY(gLogLevel >= LogTrace)) \ + AL_PRINT("(II)", __VA_ARGS__); \ + LOG_ANDROID(ANDROID_LOG_DEBUG, __VA_ARGS__); \ +} while(0) + +#define WARN(...) do { \ + if(UNLIKELY(gLogLevel >= LogWarning)) \ + AL_PRINT("(WW)", __VA_ARGS__); \ + LOG_ANDROID(ANDROID_LOG_WARN, __VA_ARGS__); \ +} while(0) + +#define ERR(...) do { \ + if(UNLIKELY(gLogLevel >= LogError)) \ + AL_PRINT("(EE)", __VA_ARGS__); \ + LOG_ANDROID(ANDROID_LOG_ERROR, __VA_ARGS__); \ +} while(0) + +#endif /* LOGGING_H */ diff --git a/alc/mastering.cpp b/alc/mastering.cpp new file mode 100644 index 00000000..551fdcdf --- /dev/null +++ b/alc/mastering.cpp @@ -0,0 +1,479 @@ +#include "config.h" + +#include +#include +#include +#include + +#include "mastering.h" +#include "alu.h" +#include "almalloc.h" +#include "math_defs.h" + + +/* These structures assume BUFFERSIZE is a power of 2. */ +static_assert((BUFFERSIZE & (BUFFERSIZE-1)) == 0, "BUFFERSIZE is not a power of 2"); + +struct SlidingHold { + alignas(16) ALfloat mValues[BUFFERSIZE]; + ALsizei mExpiries[BUFFERSIZE]; + ALsizei mLowerIndex; + ALsizei mUpperIndex; + ALsizei mLength; +}; + + +namespace { + +using namespace std::placeholders; + +/* This sliding hold follows the input level with an instant attack and a + * fixed duration hold before an instant release to the next highest level. + * It is a sliding window maximum (descending maxima) implementation based on + * Richard Harter's ascending minima algorithm available at: + * + * http://www.richardhartersworld.com/cri/2001/slidingmin.html + */ +ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALfloat in) +{ + static constexpr ALsizei mask{BUFFERSIZE - 1}; + const ALsizei length{Hold->mLength}; + ALfloat (&values)[BUFFERSIZE] = Hold->mValues; + ALsizei (&expiries)[BUFFERSIZE] = Hold->mExpiries; + ALsizei lowerIndex{Hold->mLowerIndex}; + ALsizei upperIndex{Hold->mUpperIndex}; + + ASSUME(upperIndex >= 0); + ASSUME(lowerIndex >= 0); + + if(i >= expiries[upperIndex]) + upperIndex = (upperIndex + 1) & mask; + + if(in >= values[upperIndex]) + { + values[upperIndex] = in; + expiries[upperIndex] = i + length; + lowerIndex = upperIndex; + } + else + { + do { + do { + if(!(in >= values[lowerIndex])) + goto found_place; + } while(lowerIndex--); + lowerIndex = mask; + } while(1); + found_place: + + lowerIndex = (lowerIndex + 1) & mask; + values[lowerIndex] = in; + expiries[lowerIndex] = i + length; + } + + Hold->mLowerIndex = lowerIndex; + Hold->mUpperIndex = upperIndex; + + return values[upperIndex]; +} + +void ShiftSlidingHold(SlidingHold *Hold, const ALsizei n) +{ + ASSUME(Hold->mUpperIndex >= 0); + ASSUME(Hold->mLowerIndex >= 0); + + auto exp_begin = std::begin(Hold->mExpiries) + Hold->mUpperIndex; + auto exp_last = std::begin(Hold->mExpiries) + Hold->mLowerIndex; + if(exp_last < exp_begin) + { + std::transform(exp_begin, std::end(Hold->mExpiries), exp_begin, + std::bind(std::minus{}, _1, n)); + exp_begin = std::begin(Hold->mExpiries); + } + std::transform(exp_begin, exp_last+1, exp_begin, std::bind(std::minus{}, _1, n)); +} + + +/* Multichannel compression is linked via the absolute maximum of all + * channels. + */ +void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, const FloatBufferLine *OutBuffer) +{ + const ALsizei index{Comp->mLookAhead}; + const ALuint numChans{Comp->mNumChans}; + + ASSUME(SamplesToDo > 0); + ASSUME(numChans > 0); + ASSUME(index >= 0); + + auto side_begin = std::begin(Comp->mSideChain) + index; + std::fill(side_begin, side_begin+SamplesToDo, 0.0f); + + auto fill_max = [SamplesToDo,side_begin](const FloatBufferLine &input) -> void + { + const ALfloat *RESTRICT buffer{al::assume_aligned<16>(input.data())}; + auto max_abs = std::bind(maxf, _1, std::bind(static_cast(std::fabs), _2)); + std::transform(side_begin, side_begin+SamplesToDo, buffer, side_begin, max_abs); + }; + std::for_each(OutBuffer, OutBuffer+numChans, fill_max); +} + +/* This calculates the squared crest factor of the control signal for the + * basic automation of the attack/release times. As suggested by the paper, + * it uses an instantaneous squared peak detector and a squared RMS detector + * both with 200ms release times. + */ +static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo) +{ + const ALfloat a_crest{Comp->mCrestCoeff}; + const ALsizei index{Comp->mLookAhead}; + ALfloat y2_peak{Comp->mLastPeakSq}; + ALfloat y2_rms{Comp->mLastRmsSq}; + + ASSUME(SamplesToDo > 0); + ASSUME(index >= 0); + + auto calc_crest = [&y2_rms,&y2_peak,a_crest](const ALfloat x_abs) noexcept -> ALfloat + { + ALfloat x2 = maxf(0.000001f, x_abs * x_abs); + + y2_peak = maxf(x2, lerp(x2, y2_peak, a_crest)); + y2_rms = lerp(x2, y2_rms, a_crest); + return y2_peak / y2_rms; + }; + auto side_begin = std::begin(Comp->mSideChain) + index; + std::transform(side_begin, side_begin+SamplesToDo, std::begin(Comp->mCrestFactor), calc_crest); + + Comp->mLastPeakSq = y2_peak; + Comp->mLastRmsSq = y2_rms; +} + +/* The side-chain starts with a simple peak detector (based on the absolute + * value of the incoming signal) and performs most of its operations in the + * log domain. + */ +void PeakDetector(Compressor *Comp, const ALsizei SamplesToDo) +{ + const ALsizei index{Comp->mLookAhead}; + + ASSUME(SamplesToDo > 0); + ASSUME(index >= 0); + + /* Clamp the minimum amplitude to near-zero and convert to logarithm. */ + auto side_begin = std::begin(Comp->mSideChain) + index; + std::transform(side_begin, side_begin+SamplesToDo, side_begin, + std::bind(static_cast(std::log), std::bind(maxf, 0.000001f, _1))); +} + +/* An optional hold can be used to extend the peak detector so it can more + * solidly detect fast transients. This is best used when operating as a + * limiter. + */ +void PeakHoldDetector(Compressor *Comp, const ALsizei SamplesToDo) +{ + const ALsizei index{Comp->mLookAhead}; + + ASSUME(SamplesToDo > 0); + ASSUME(index >= 0); + + SlidingHold *hold{Comp->mHold}; + ALsizei i{0}; + auto detect_peak = [&i,hold](const ALfloat x_abs) -> ALfloat + { + const ALfloat x_G{std::log(maxf(0.000001f, x_abs))}; + return UpdateSlidingHold(hold, i++, x_G); + }; + auto side_begin = std::begin(Comp->mSideChain) + index; + std::transform(side_begin, side_begin+SamplesToDo, side_begin, detect_peak); + + ShiftSlidingHold(hold, SamplesToDo); +} + +/* This is the heart of the feed-forward compressor. It operates in the log + * domain (to better match human hearing) and can apply some basic automation + * to knee width, attack/release times, make-up/post gain, and clipping + * reduction. + */ +void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) +{ + const bool autoKnee{Comp->mAuto.Knee}; + const bool autoAttack{Comp->mAuto.Attack}; + const bool autoRelease{Comp->mAuto.Release}; + const bool autoPostGain{Comp->mAuto.PostGain}; + const bool autoDeclip{Comp->mAuto.Declip}; + const ALsizei lookAhead{Comp->mLookAhead}; + const ALfloat threshold{Comp->mThreshold}; + const ALfloat slope{Comp->mSlope}; + const ALfloat attack{Comp->mAttack}; + const ALfloat release{Comp->mRelease}; + const ALfloat c_est{Comp->mGainEstimate}; + const ALfloat a_adp{Comp->mAdaptCoeff}; + const ALfloat (&crestFactor)[BUFFERSIZE] = Comp->mCrestFactor; + ALfloat (&sideChain)[BUFFERSIZE*2] = Comp->mSideChain; + ALfloat postGain{Comp->mPostGain}; + ALfloat knee{Comp->mKnee}; + ALfloat t_att{attack}; + ALfloat t_rel{release - attack}; + ALfloat a_att{std::exp(-1.0f / t_att)}; + ALfloat a_rel{std::exp(-1.0f / t_rel)}; + ALfloat y_1{Comp->mLastRelease}; + ALfloat y_L{Comp->mLastAttack}; + ALfloat c_dev{Comp->mLastGainDev}; + + ASSUME(SamplesToDo > 0); + ASSUME(lookAhead >= 0); + + for(ALsizei i{0};i < SamplesToDo;i++) + { + if(autoKnee) + knee = maxf(0.0f, 2.5f * (c_dev + c_est)); + const ALfloat knee_h{0.5f * knee}; + + /* This is the gain computer. It applies a static compression curve + * to the control signal. + */ + const ALfloat x_over{sideChain[lookAhead+i] - threshold}; + const ALfloat y_G{ + (x_over <= -knee_h) ? 0.0f : + (std::fabs(x_over) < knee_h) ? (x_over + knee_h) * (x_over + knee_h) / (2.0f * knee) : + x_over + }; + + const ALfloat y2_crest{crestFactor[i]}; + if(autoAttack) + { + t_att = 2.0f*attack/y2_crest; + a_att = std::exp(-1.0f / t_att); + } + if(autoRelease) + { + t_rel = 2.0f*release/y2_crest - t_att; + a_rel = std::exp(-1.0f / t_rel); + } + + /* Gain smoothing (ballistics) is done via a smooth decoupled peak + * detector. The attack time is subtracted from the release time + * above to compensate for the chained operating mode. + */ + const ALfloat x_L{-slope * y_G}; + y_1 = maxf(x_L, lerp(x_L, y_1, a_rel)); + y_L = lerp(y_1, y_L, a_att); + + /* Knee width and make-up gain automation make use of a smoothed + * measurement of deviation between the control signal and estimate. + * The estimate is also used to bias the measurement to hot-start its + * average. + */ + c_dev = lerp(-(y_L+c_est), c_dev, a_adp); + + if(autoPostGain) + { + /* Clipping reduction is only viable when make-up gain is being + * automated. It modifies the deviation to further attenuate the + * control signal when clipping is detected. The adaptation time + * is sufficiently long enough to suppress further clipping at the + * same output level. + */ + if(autoDeclip) + c_dev = maxf(c_dev, sideChain[i] - y_L - threshold - c_est); + + postGain = -(c_dev + c_est); + } + + sideChain[i] = std::exp(postGain - y_L); + } + + Comp->mLastRelease = y_1; + Comp->mLastAttack = y_L; + Comp->mLastGainDev = c_dev; +} + +/* Combined with the hold time, a look-ahead delay can improve handling of + * fast transients by allowing the envelope time to converge prior to + * reaching the offending impulse. This is best used when operating as a + * limiter. + */ +void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, FloatBufferLine *OutBuffer) +{ + const ALuint numChans{Comp->mNumChans}; + const ALsizei lookAhead{Comp->mLookAhead}; + + ASSUME(SamplesToDo > 0); + ASSUME(numChans > 0); + ASSUME(lookAhead > 0); + + for(ALuint c{0};c < numChans;c++) + { + ALfloat *inout{al::assume_aligned<16>(OutBuffer[c].data())}; + ALfloat *delaybuf{al::assume_aligned<16>(Comp->mDelay[c].data())}; + + auto inout_end = inout + SamplesToDo; + if(LIKELY(SamplesToDo >= lookAhead)) + { + auto delay_end = std::rotate(inout, inout_end - lookAhead, inout_end); + std::swap_ranges(inout, delay_end, delaybuf); + } + else + { + auto delay_start = std::swap_ranges(inout, inout_end, delaybuf); + std::rotate(delaybuf, delay_start, delaybuf + lookAhead); + } + } +} + +} // namespace + +/* The compressor is initialized with the following settings: + * + * NumChans - Number of channels to process. + * SampleRate - Sample rate to process. + * AutoKnee - Whether to automate the knee width parameter. + * AutoAttack - Whether to automate the attack time parameter. + * AutoRelease - Whether to automate the release time parameter. + * AutoPostGain - Whether to automate the make-up (post) gain parameter. + * AutoDeclip - Whether to automate clipping reduction. Ignored when + * not automating make-up gain. + * LookAheadTime - Look-ahead time (in seconds). + * HoldTime - Peak hold-time (in seconds). + * PreGainDb - Gain applied before detection (in dB). + * PostGainDb - Make-up gain applied after compression (in dB). + * ThresholdDb - Triggering threshold (in dB). + * Ratio - Compression ratio (x:1). Set to INFINITY for true + * limiting. Ignored when automating knee width. + * KneeDb - Knee width (in dB). Ignored when automating knee + * width. + * AttackTimeMin - Attack time (in seconds). Acts as a maximum when + * automating attack time. + * ReleaseTimeMin - Release time (in seconds). Acts as a maximum when + * automating release time. + */ +std::unique_ptr CompressorInit(const ALuint NumChans, const ALuint SampleRate, + const ALboolean AutoKnee, const ALboolean AutoAttack, const ALboolean AutoRelease, + const ALboolean AutoPostGain, const ALboolean AutoDeclip, const ALfloat LookAheadTime, + const ALfloat HoldTime, const ALfloat PreGainDb, const ALfloat PostGainDb, + const ALfloat ThresholdDb, const ALfloat Ratio, const ALfloat KneeDb, const ALfloat AttackTime, + const ALfloat ReleaseTime) +{ + const auto lookAhead = static_cast( + clampf(std::round(LookAheadTime*SampleRate), 0.0f, BUFFERSIZE-1)); + const auto hold = static_cast( + clampf(std::round(HoldTime*SampleRate), 0.0f, BUFFERSIZE-1)); + + size_t size{sizeof(Compressor)}; + if(lookAhead > 0) + { + size += sizeof(*Compressor::mDelay) * NumChans; + /* The sliding hold implementation doesn't handle a length of 1. A 1- + * sample hold is useless anyway, it would only ever give back what was + * just given to it. + */ + if(hold > 1) + size += sizeof(*Compressor::mHold); + } + + auto Comp = std::unique_ptr{new (al_calloc(16, size)) Compressor{}}; + Comp->mNumChans = NumChans; + Comp->mSampleRate = SampleRate; + Comp->mAuto.Knee = AutoKnee != AL_FALSE; + Comp->mAuto.Attack = AutoAttack != AL_FALSE; + Comp->mAuto.Release = AutoRelease != AL_FALSE; + Comp->mAuto.PostGain = AutoPostGain != AL_FALSE; + Comp->mAuto.Declip = AutoPostGain && AutoDeclip; + Comp->mLookAhead = lookAhead; + Comp->mPreGain = std::pow(10.0f, PreGainDb / 20.0f); + Comp->mPostGain = PostGainDb * std::log(10.0f) / 20.0f; + Comp->mThreshold = ThresholdDb * std::log(10.0f) / 20.0f; + Comp->mSlope = 1.0f / maxf(1.0f, Ratio) - 1.0f; + Comp->mKnee = maxf(0.0f, KneeDb * std::log(10.0f) / 20.0f); + Comp->mAttack = maxf(1.0f, AttackTime * SampleRate); + Comp->mRelease = maxf(1.0f, ReleaseTime * SampleRate); + + /* Knee width automation actually treats the compressor as a limiter. By + * varying the knee width, it can effectively be seen as applying + * compression over a wide range of ratios. + */ + if(AutoKnee) + Comp->mSlope = -1.0f; + + if(lookAhead > 0) + { + if(hold > 1) + { + Comp->mHold = ::new (static_cast(Comp.get() + 1)) SlidingHold{}; + Comp->mHold->mValues[0] = -std::numeric_limits::infinity(); + Comp->mHold->mExpiries[0] = hold; + Comp->mHold->mLength = hold; + Comp->mDelay = ::new (static_cast(Comp->mHold + 1)) FloatBufferLine[NumChans]; + } + else + { + Comp->mDelay = ::new (static_cast(Comp.get() + 1)) FloatBufferLine[NumChans]; + } + } + + Comp->mCrestCoeff = std::exp(-1.0f / (0.200f * SampleRate)); // 200ms + Comp->mGainEstimate = Comp->mThreshold * -0.5f * Comp->mSlope; + Comp->mAdaptCoeff = std::exp(-1.0f / (2.0f * SampleRate)); // 2s + + return Comp; +} + +Compressor::~Compressor() +{ + if(mHold) + al::destroy_at(mHold); + mHold = nullptr; + if(mDelay) + al::destroy_n(mDelay, mNumChans); + mDelay = nullptr; +} + + +void Compressor::process(const ALsizei SamplesToDo, FloatBufferLine *OutBuffer) +{ + const ALuint numChans{mNumChans}; + + ASSUME(SamplesToDo > 0); + ASSUME(numChans > 0); + + const ALfloat preGain{mPreGain}; + if(preGain != 1.0f) + { + auto apply_gain = [SamplesToDo,preGain](FloatBufferLine &input) noexcept -> void + { + ALfloat *buffer{al::assume_aligned<16>(input.data())}; + std::transform(buffer, buffer+SamplesToDo, buffer, + std::bind(std::multiplies{}, _1, preGain)); + }; + std::for_each(OutBuffer, OutBuffer+numChans, apply_gain); + } + + LinkChannels(this, SamplesToDo, OutBuffer); + + if(mAuto.Attack || mAuto.Release) + CrestDetector(this, SamplesToDo); + + if(mHold) + PeakHoldDetector(this, SamplesToDo); + else + PeakDetector(this, SamplesToDo); + + GainCompressor(this, SamplesToDo); + + if(mDelay) + SignalDelay(this, SamplesToDo, OutBuffer); + + const ALfloat (&sideChain)[BUFFERSIZE*2] = mSideChain; + auto apply_comp = [SamplesToDo,&sideChain](FloatBufferLine &input) noexcept -> void + { + ALfloat *buffer{al::assume_aligned<16>(input.data())}; + const ALfloat *gains{al::assume_aligned<16>(&sideChain[0])}; + std::transform(gains, gains+SamplesToDo, buffer, buffer, + std::bind(std::multiplies{}, _1, _2)); + }; + std::for_each(OutBuffer, OutBuffer+numChans, apply_comp); + + ASSUME(mLookAhead >= 0); + auto side_begin = std::begin(mSideChain) + SamplesToDo; + std::copy(side_begin, side_begin+mLookAhead, std::begin(mSideChain)); +} diff --git a/alc/mastering.h b/alc/mastering.h new file mode 100644 index 00000000..34dc8dcb --- /dev/null +++ b/alc/mastering.h @@ -0,0 +1,104 @@ +#ifndef MASTERING_H +#define MASTERING_H + +#include + +#include "AL/al.h" + +#include "almalloc.h" +/* For FloatBufferLine/BUFFERSIZE. */ +#include "alcmain.h" + + +struct SlidingHold; + +/* General topology and basic automation was based on the following paper: + * + * D. Giannoulis, M. Massberg and J. D. Reiss, + * "Parameter Automation in a Dynamic Range Compressor," + * Journal of the Audio Engineering Society, v61 (10), Oct. 2013 + * + * Available (along with supplemental reading) at: + * + * http://c4dm.eecs.qmul.ac.uk/audioengineering/compressors/ + */ +struct Compressor { + ALuint mNumChans{0u}; + ALuint mSampleRate{0u}; + + struct { + bool Knee : 1; + bool Attack : 1; + bool Release : 1; + bool PostGain : 1; + bool Declip : 1; + } mAuto{}; + + ALsizei mLookAhead{0}; + + ALfloat mPreGain{0.0f}; + ALfloat mPostGain{0.0f}; + + ALfloat mThreshold{0.0f}; + ALfloat mSlope{0.0f}; + ALfloat mKnee{0.0f}; + + ALfloat mAttack{0.0f}; + ALfloat mRelease{0.0f}; + + alignas(16) ALfloat mSideChain[2*BUFFERSIZE]{}; + alignas(16) ALfloat mCrestFactor[BUFFERSIZE]{}; + + SlidingHold *mHold{nullptr}; + FloatBufferLine *mDelay{nullptr}; + + ALfloat mCrestCoeff{0.0f}; + ALfloat mGainEstimate{0.0f}; + ALfloat mAdaptCoeff{0.0f}; + + ALfloat mLastPeakSq{0.0f}; + ALfloat mLastRmsSq{0.0f}; + ALfloat mLastRelease{0.0f}; + ALfloat mLastAttack{0.0f}; + ALfloat mLastGainDev{0.0f}; + + + ~Compressor(); + void process(const ALsizei SamplesToDo, FloatBufferLine *OutBuffer); + ALsizei getLookAhead() const noexcept { return mLookAhead; } + + DEF_PLACE_NEWDEL() +}; + +/* The compressor is initialized with the following settings: + * + * NumChans - Number of channels to process. + * SampleRate - Sample rate to process. + * AutoKnee - Whether to automate the knee width parameter. + * AutoAttack - Whether to automate the attack time parameter. + * AutoRelease - Whether to automate the release time parameter. + * AutoPostGain - Whether to automate the make-up (post) gain parameter. + * AutoDeclip - Whether to automate clipping reduction. Ignored when + * not automating make-up gain. + * LookAheadTime - Look-ahead time (in seconds). + * HoldTime - Peak hold-time (in seconds). + * PreGainDb - Gain applied before detection (in dB). + * PostGainDb - Make-up gain applied after compression (in dB). + * ThresholdDb - Triggering threshold (in dB). + * Ratio - Compression ratio (x:1). Set to INFINIFTY for true + * limiting. Ignored when automating knee width. + * KneeDb - Knee width (in dB). Ignored when automating knee + * width. + * AttackTimeMin - Attack time (in seconds). Acts as a maximum when + * automating attack time. + * ReleaseTimeMin - Release time (in seconds). Acts as a maximum when + * automating release time. + */ +std::unique_ptr CompressorInit(const ALuint NumChans, const ALuint SampleRate, + const ALboolean AutoKnee, const ALboolean AutoAttack, const ALboolean AutoRelease, + const ALboolean AutoPostGain, const ALboolean AutoDeclip, const ALfloat LookAheadTime, + const ALfloat HoldTime, const ALfloat PreGainDb, const ALfloat PostGainDb, + const ALfloat ThresholdDb, const ALfloat Ratio, const ALfloat KneeDb, const ALfloat AttackTime, + const ALfloat ReleaseTime); + +#endif /* MASTERING_H */ diff --git a/alc/mixer/defs.h b/alc/mixer/defs.h new file mode 100644 index 00000000..3e5d1125 --- /dev/null +++ b/alc/mixer/defs.h @@ -0,0 +1,59 @@ +#ifndef MIXER_DEFS_H +#define MIXER_DEFS_H + +#include "AL/alc.h" +#include "AL/al.h" + +#include "alcmain.h" +#include "alu.h" +#include "alspan.h" + + +struct MixGains; +struct MixHrtfFilter; +struct HrtfState; +struct DirectHrtfState; + + +struct CTag { }; +struct SSETag { }; +struct SSE2Tag { }; +struct SSE3Tag { }; +struct SSE4Tag { }; +struct NEONTag { }; + +struct CopyTag { }; +struct PointTag { }; +struct LerpTag { }; +struct CubicTag { }; +struct BSincTag { }; + +template +const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen); + +template +void Mix_(const ALfloat *data, const al::span OutBuffer, ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize); +template +void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize); + +template +void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfFilter *hrtfparams, const ALsizei BufferSize); +template +void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize); +template +void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, const ALsizei BufferSize); + +/* Vectorized resampler helpers */ +inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *RESTRICT frac_arr, ALsizei *RESTRICT pos_arr, ALsizei size) +{ + pos_arr[0] = 0; + frac_arr[0] = frac; + for(ALsizei i{1};i < size;i++) + { + ALint frac_tmp = frac_arr[i-1] + increment; + pos_arr[i] = pos_arr[i-1] + (frac_tmp>>FRACTIONBITS); + frac_arr[i] = frac_tmp&FRACTIONMASK; + } +} + +#endif /* MIXER_DEFS_H */ diff --git a/alc/mixer/hrtfbase.h b/alc/mixer/hrtfbase.h new file mode 100644 index 00000000..a76bd62e --- /dev/null +++ b/alc/mixer/hrtfbase.h @@ -0,0 +1,138 @@ +#ifndef MIXER_HRTFBASE_H +#define MIXER_HRTFBASE_H + +#include + +#include "alu.h" +#include "../hrtf.h" +#include "opthelpers.h" + + +using ApplyCoeffsT = void(ALsizei Offset, float2 *RESTRICT Values, const ALsizei irSize, + const HrirArray &Coeffs, const ALfloat left, const ALfloat right); + +template +inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *RESTRICT AccumSamples, const ALsizei OutPos, + const ALsizei IrSize, MixHrtfFilter *hrtfparams, const ALsizei BufferSize) +{ + ASSUME(OutPos >= 0); + ASSUME(IrSize >= 4); + ASSUME(BufferSize > 0); + + const auto &Coeffs = *hrtfparams->Coeffs; + const ALfloat gainstep{hrtfparams->GainStep}; + const ALfloat gain{hrtfparams->Gain}; + + ALsizei Delay[2]{ + HRTF_HISTORY_LENGTH - hrtfparams->Delay[0], + HRTF_HISTORY_LENGTH - hrtfparams->Delay[1] }; + ASSUME(Delay[0] >= 0 && Delay[1] >= 0); + ALfloat stepcount{0.0f}; + for(ALsizei i{0};i < BufferSize;++i) + { + const ALfloat g{gain + gainstep*stepcount}; + const ALfloat left{InSamples[Delay[0]++] * g}; + const ALfloat right{InSamples[Delay[1]++] * g}; + ApplyCoeffs(i, AccumSamples+i, IrSize, Coeffs, left, right); + + stepcount += 1.0f; + } + + for(ALsizei i{0};i < BufferSize;++i) + LeftOut[OutPos+i] += AccumSamples[i][0]; + for(ALsizei i{0};i < BufferSize;++i) + RightOut[OutPos+i] += AccumSamples[i][1]; + + hrtfparams->Gain = gain + gainstep*stepcount; +} + +template +inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *RESTRICT AccumSamples, const ALsizei OutPos, + const ALsizei IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, + const ALsizei BufferSize) +{ + const auto &OldCoeffs = oldparams->Coeffs; + const ALfloat oldGain{oldparams->Gain}; + const ALfloat oldGainStep{-oldGain / static_cast(BufferSize)}; + const auto &NewCoeffs = *newparams->Coeffs; + const ALfloat newGainStep{newparams->GainStep}; + + ASSUME(OutPos >= 0); + ASSUME(IrSize >= 4); + ASSUME(BufferSize > 0); + + ALsizei Delay[2]{ + HRTF_HISTORY_LENGTH - oldparams->Delay[0], + HRTF_HISTORY_LENGTH - oldparams->Delay[1] }; + ASSUME(Delay[0] >= 0 && Delay[1] >= 0); + ALfloat stepcount{0.0f}; + for(ALsizei i{0};i < BufferSize;++i) + { + const ALfloat g{oldGain + oldGainStep*stepcount}; + const ALfloat left{InSamples[Delay[0]++] * g}; + const ALfloat right{InSamples[Delay[1]++] * g}; + ApplyCoeffs(i, AccumSamples+i, IrSize, OldCoeffs, left, right); + + stepcount += 1.0f; + } + + Delay[0] = HRTF_HISTORY_LENGTH - newparams->Delay[0]; + Delay[1] = HRTF_HISTORY_LENGTH - newparams->Delay[1]; + ASSUME(Delay[0] >= 0 && Delay[1] >= 0); + stepcount = 0.0f; + for(ALsizei i{0};i < BufferSize;++i) + { + const ALfloat g{newGainStep*stepcount}; + const ALfloat left{InSamples[Delay[0]++] * g}; + const ALfloat right{InSamples[Delay[1]++] * g}; + ApplyCoeffs(i, AccumSamples+i, IrSize, NewCoeffs, left, right); + + stepcount += 1.0f; + } + + for(ALsizei i{0};i < BufferSize;++i) + LeftOut[OutPos+i] += AccumSamples[i][0]; + for(ALsizei i{0};i < BufferSize;++i) + RightOut[OutPos+i] += AccumSamples[i][1]; + + newparams->Gain = newGainStep*stepcount; +} + +template +inline void MixDirectHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const al::span InSamples, float2 *RESTRICT AccumSamples, + DirectHrtfState *State, const ALsizei BufferSize) +{ + ASSUME(BufferSize > 0); + + const ALsizei IrSize{State->IrSize}; + ASSUME(IrSize >= 4); + + auto chanstate = State->Chan.begin(); + for(const FloatBufferLine &input : InSamples) + { + const auto &Coeffs = chanstate->Coeffs; + + auto accum_iter = std::copy_n(chanstate->Values.begin(), + chanstate->Values.size(), AccumSamples); + std::fill_n(accum_iter, BufferSize, float2{}); + + for(ALsizei i{0};i < BufferSize;++i) + { + const ALfloat insample{input[i]}; + ApplyCoeffs(i, AccumSamples+i, IrSize, Coeffs, insample, insample); + } + for(ALsizei i{0};i < BufferSize;++i) + LeftOut[i] += AccumSamples[i][0]; + for(ALsizei i{0};i < BufferSize;++i) + RightOut[i] += AccumSamples[i][1]; + + std::copy_n(AccumSamples + BufferSize, chanstate->Values.size(), + chanstate->Values.begin()); + ++chanstate; + } +} + +#endif /* MIXER_HRTFBASE_H */ diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp new file mode 100644 index 00000000..47c4a6f4 --- /dev/null +++ b/alc/mixer/mixer_c.cpp @@ -0,0 +1,208 @@ +#include "config.h" + +#include + +#include + +#include "alcmain.h" +#include "alu.h" +#include "alSource.h" +#include "alAuxEffectSlot.h" +#include "defs.h" +#include "hrtfbase.h" + + +namespace { + +inline ALfloat do_point(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei) +{ return vals[0]; } +inline ALfloat do_lerp(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei frac) +{ return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); } +inline ALfloat do_cubic(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei frac) +{ return cubic(vals[0], vals[1], vals[2], vals[3], frac * (1.0f/FRACTIONONE)); } +inline ALfloat do_bsinc(const InterpState &istate, const ALfloat *RESTRICT vals, const ALsizei frac) +{ + ASSUME(istate.bsinc.m > 0); + + // Calculate the phase index and factor. +#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) + const ALsizei pi{frac >> FRAC_PHASE_BITDIFF}; + const ALfloat pf{(frac & ((1< +const ALfloat *DoResample(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei numsamples) +{ + ASSUME(numsamples > 0); + ASSUME(increment > 0); + ASSUME(frac >= 0); + + const InterpState istate{*state}; + auto proc_sample = [&src,&frac,istate,increment]() -> ALfloat + { + const ALfloat ret{Sampler(istate, src, frac)}; + + frac += increment; + src += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + + return ret; + }; + std::generate_n(dst, numsamples, proc_sample); + + return dst; +} + +} // namespace + +template<> +const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, ALsizei, + ALint, ALfloat *RESTRICT dst, ALsizei dstlen) +{ + ASSUME(dstlen > 0); +#if defined(HAVE_SSE) || defined(HAVE_NEON) + /* Avoid copying the source data if it's aligned like the destination. */ + if((reinterpret_cast(src)&15) == (reinterpret_cast(dst)&15)) + return src; +#endif + std::copy_n(src, dstlen, dst); + return dst; +} + +template<> +const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) +{ return DoResample(state, src, frac, increment, dst, dstlen); } + +template<> +const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) +{ return DoResample(state, src, frac, increment, dst, dstlen); } + +template<> +const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) +{ return DoResample(state, src-1, frac, increment, dst, dstlen); } + +template<> +const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) +{ return DoResample(state, src-state->bsinc.l, frac, increment, dst, dstlen); } + + +static inline void ApplyCoeffs(ALsizei /*Offset*/, float2 *RESTRICT Values, const ALsizei IrSize, + const HrirArray &Coeffs, const ALfloat left, const ALfloat right) +{ + ASSUME(IrSize >= 2); + for(ALsizei c{0};c < IrSize;++c) + { + Values[c][0] += Coeffs[c][0] * left; + Values[c][1] += Coeffs[c][1] * right; + } +} + +template<> +void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, + MixHrtfFilter *hrtfparams, const ALsizei BufferSize) +{ + MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, + hrtfparams, BufferSize); +} + +template<> +void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, + const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize) +{ + MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, + oldparams, newparams, BufferSize); +} + +template<> +void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, + const ALsizei BufferSize) +{ + MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, BufferSize); +} + + +template<> +void Mix_(const ALfloat *data, const al::span OutBuffer, + ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, + const ALsizei BufferSize) +{ + ASSUME(BufferSize > 0); + + const ALfloat delta{(Counter > 0) ? 1.0f / static_cast(Counter) : 0.0f}; + for(FloatBufferLine &output : OutBuffer) + { + ALfloat *RESTRICT dst{output.data()+OutPos}; + ALfloat gain{*CurrentGains}; + const ALfloat diff{*TargetGains - gain}; + + ALsizei pos{0}; + if(std::fabs(diff) > std::numeric_limits::epsilon()) + { + ALsizei minsize{mini(BufferSize, Counter)}; + const ALfloat step{diff * delta}; + ALfloat step_count{0.0f}; + for(;pos < minsize;pos++) + { + dst[pos] += data[pos] * (gain + step*step_count); + step_count += 1.0f; + } + if(pos == Counter) + gain = *TargetGains; + else + gain += step*step_count; + *CurrentGains = gain; + } + ++CurrentGains; + ++TargetGains; + + if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + for(;pos < BufferSize;pos++) + dst[pos] += data[pos]*gain; + } +} + +/* Basically the inverse of the above. Rather than one input going to multiple + * outputs (each with its own gain), it's multiple inputs (each with its own + * gain) going to one output. This applies one row (vs one column) of a matrix + * transform. And as the matrices are more or less static once set up, no + * stepping is necessary. + */ +template<> +void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, + const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize) +{ + ASSUME(BufferSize > 0); + + for(const FloatBufferLine &input : InSamples) + { + const ALfloat *RESTRICT src{input.data()+InPos}; + const ALfloat gain{*(Gains++)}; + if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + for(ALsizei i{0};i < BufferSize;i++) + OutBuffer[i] += src[i] * gain; + } +} diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp new file mode 100644 index 00000000..fa487d97 --- /dev/null +++ b/alc/mixer/mixer_neon.cpp @@ -0,0 +1,307 @@ +#include "config.h" + +#include + +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "alcmain.h" +#include "alu.h" +#include "hrtf.h" +#include "defs.h" +#include "hrtfbase.h" + + + +template<> +const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) +{ + const int32x4_t increment4 = vdupq_n_s32(increment*4); + const float32x4_t fracOne4 = vdupq_n_f32(1.0f/FRACTIONONE); + const int32x4_t fracMask4 = vdupq_n_s32(FRACTIONMASK); + alignas(16) ALsizei pos_[4], frac_[4]; + int32x4_t pos4, frac4; + ALsizei todo, pos, i; + + ASSUME(frac >= 0); + ASSUME(increment > 0); + ASSUME(dstlen > 0); + + InitiatePositionArrays(frac, increment, frac_, pos_, 4); + frac4 = vld1q_s32(frac_); + pos4 = vld1q_s32(pos_); + + todo = dstlen & ~3; + for(i = 0;i < todo;i += 4) + { + const int pos0 = vgetq_lane_s32(pos4, 0); + const int pos1 = vgetq_lane_s32(pos4, 1); + const int pos2 = vgetq_lane_s32(pos4, 2); + const int pos3 = vgetq_lane_s32(pos4, 3); + const float32x4_t val1 = (float32x4_t){src[pos0], src[pos1], src[pos2], src[pos3]}; + const float32x4_t val2 = (float32x4_t){src[pos0+1], src[pos1+1], src[pos2+1], src[pos3+1]}; + + /* val1 + (val2-val1)*mu */ + const float32x4_t r0 = vsubq_f32(val2, val1); + const float32x4_t mu = vmulq_f32(vcvtq_f32_s32(frac4), fracOne4); + const float32x4_t out = vmlaq_f32(val1, mu, r0); + + vst1q_f32(&dst[i], out); + + frac4 = vaddq_s32(frac4, increment4); + pos4 = vaddq_s32(pos4, vshrq_n_s32(frac4, FRACTIONBITS)); + frac4 = vandq_s32(frac4, fracMask4); + } + + /* NOTE: These four elements represent the position *after* the last four + * samples, so the lowest element is the next position to resample. + */ + pos = vgetq_lane_s32(pos4, 0); + frac = vgetq_lane_s32(frac4, 0); + + for(;i < dstlen;++i) + { + dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); + + frac += increment; + pos += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } + return dst; +} + +template<> +const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) +{ + const ALfloat *const filter = state->bsinc.filter; + const float32x4_t sf4 = vdupq_n_f32(state->bsinc.sf); + const ALsizei m = state->bsinc.m; + const float32x4_t *fil, *scd, *phd, *spd; + ALsizei pi, i, j, offset; + float32x4_t r4; + ALfloat pf; + + ASSUME(m > 0); + ASSUME(dstlen > 0); + ASSUME(increment > 0); + ASSUME(frac >= 0); + + src -= state->bsinc.l; + for(i = 0;i < dstlen;i++) + { + // Calculate the phase index and factor. +#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) + pi = frac >> FRAC_PHASE_BITDIFF; + pf = (frac & ((1<> 2; + const float32x4_t pf4 = vdupq_n_f32(pf); + + ASSUME(count > 0); + + for(j = 0;j < count;j++) + { + /* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */ + const float32x4_t f4 = vmlaq_f32( + vmlaq_f32(fil[j], sf4, scd[j]), + pf4, vmlaq_f32(phd[j], sf4, spd[j]) + ); + /* r += f*src */ + r4 = vmlaq_f32(r4, f4, vld1q_f32(&src[j*4])); + } + } + r4 = vaddq_f32(r4, vcombine_f32(vrev64_f32(vget_high_f32(r4)), + vrev64_f32(vget_low_f32(r4)))); + dst[i] = vget_lane_f32(vadd_f32(vget_low_f32(r4), vget_high_f32(r4)), 0); + + frac += increment; + src += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } + return dst; +} + + +static inline void ApplyCoeffs(ALsizei /*Offset*/, float2 *RESTRICT Values, const ALsizei IrSize, + const HrirArray &Coeffs, const ALfloat left, const ALfloat right) +{ + ASSUME(IrSize >= 2); + + 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(ALsizei c{0};c < IrSize;c += 2) + { + float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[c ][0]), + vld1_f32((float32_t*)&Values[c+1][0])); + float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]); + + vals = vmlaq_f32(vals, coefs, leftright4); + + vst1_f32((float32_t*)&Values[c ][0], vget_low_f32(vals)); + vst1_f32((float32_t*)&Values[c+1][0], vget_high_f32(vals)); + } +} + +template<> +void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, + MixHrtfFilter *hrtfparams, const ALsizei BufferSize) +{ + MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, + hrtfparams, BufferSize); +} + +template<> +void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, + const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize) +{ + MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, + oldparams, newparams, BufferSize); +} + +template<> +void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, + const ALsizei BufferSize) +{ + MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, BufferSize); +} + + +template<> +void Mix_(const ALfloat *data, const al::span OutBuffer, + ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, + const ALsizei BufferSize) +{ + ASSUME(BufferSize > 0); + + const ALfloat delta{(Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f}; + for(FloatBufferLine &output : OutBuffer) + { + ALfloat *RESTRICT dst{al::assume_aligned<16>(output.data()+OutPos)}; + ALfloat gain{*CurrentGains}; + const ALfloat diff{*TargetGains - gain}; + + ALsizei pos{0}; + if(std::fabs(diff) > std::numeric_limits::epsilon()) + { + ALsizei minsize{mini(BufferSize, Counter)}; + const ALfloat step{diff * delta}; + ALfloat step_count{0.0f}; + /* Mix with applying gain steps in aligned multiples of 4. */ + if(LIKELY(minsize > 3)) + { + const float32x4_t four4{vdupq_n_f32(4.0f)}; + const float32x4_t step4{vdupq_n_f32(step)}; + const float32x4_t gain4{vdupq_n_f32(gain)}; + float32x4_t step_count4{vsetq_lane_f32(0.0f, + vsetq_lane_f32(1.0f, + vsetq_lane_f32(2.0f, + vsetq_lane_f32(3.0f, vdupq_n_f32(0.0f), 3), + 2), 1), 0 + )}; + ALsizei todo{minsize >> 2}; + + do { + const float32x4_t val4 = vld1q_f32(&data[pos]); + float32x4_t dry4 = vld1q_f32(&dst[pos]); + dry4 = vmlaq_f32(dry4, val4, vmlaq_f32(gain4, step4, step_count4)); + step_count4 = vaddq_f32(step_count4, four4); + vst1q_f32(&dst[pos], dry4); + pos += 4; + } while(--todo); + /* NOTE: step_count4 now represents the next four counts after + * the last four mixed samples, so the lowest element + * represents the next step count to apply. + */ + step_count = vgetq_lane_f32(step_count4, 0); + } + /* Mix with applying left over gain steps that aren't aligned multiples of 4. */ + for(;pos < minsize;pos++) + { + dst[pos] += data[pos]*(gain + step*step_count); + step_count += 1.0f; + } + if(pos == Counter) + gain = *TargetGains; + else + gain += step*step_count; + *CurrentGains = gain; + + /* Mix until pos is aligned with 4 or the mix is done. */ + minsize = mini(BufferSize, (pos+3)&~3); + for(;pos < minsize;pos++) + dst[pos] += data[pos]*gain; + } + ++CurrentGains; + ++TargetGains; + + if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + if(LIKELY(BufferSize-pos > 3)) + { + ALsizei todo{(BufferSize-pos) >> 2}; + const float32x4_t gain4 = vdupq_n_f32(gain); + do { + const float32x4_t val4 = vld1q_f32(&data[pos]); + float32x4_t dry4 = vld1q_f32(&dst[pos]); + dry4 = vmlaq_f32(dry4, val4, gain4); + vst1q_f32(&dst[pos], dry4); + pos += 4; + } while(--todo); + } + for(;pos < BufferSize;pos++) + dst[pos] += data[pos]*gain; + } +} + +template<> +void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, + const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize) +{ + ASSUME(BufferSize > 0); + + for(const FloatBufferLine &input : InSamples) + { + const ALfloat *RESTRICT src{al::assume_aligned<16>(input.data()+InPos)}; + const ALfloat gain{*(Gains++)}; + if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + ALsizei pos{0}; + if(LIKELY(BufferSize > 3)) + { + ALsizei todo{BufferSize >> 2}; + float32x4_t gain4{vdupq_n_f32(gain)}; + do { + const float32x4_t val4 = vld1q_f32(&src[pos]); + float32x4_t dry4 = vld1q_f32(&OutBuffer[pos]); + dry4 = vmlaq_f32(dry4, val4, gain4); + vst1q_f32(&OutBuffer[pos], dry4); + pos += 4; + } while(--todo); + } + for(;pos < BufferSize;pos++) + OutBuffer[pos] += src[pos]*gain; + } +} diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp new file mode 100644 index 00000000..b763fdbd --- /dev/null +++ b/alc/mixer/mixer_sse.cpp @@ -0,0 +1,262 @@ +#include "config.h" + +#include + +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "alcmain.h" +#include "alu.h" + +#include "alSource.h" +#include "alAuxEffectSlot.h" +#include "defs.h" +#include "hrtfbase.h" + + +template<> +const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) +{ + const ALfloat *const filter{state->bsinc.filter}; + const __m128 sf4{_mm_set1_ps(state->bsinc.sf)}; + const ALsizei m{state->bsinc.m}; + + ASSUME(m > 0); + ASSUME(dstlen > 0); + ASSUME(increment > 0); + ASSUME(frac >= 0); + + src -= state->bsinc.l; + for(ALsizei i{0};i < dstlen;i++) + { + // Calculate the phase index and factor. +#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) + const ALsizei pi{frac >> FRAC_PHASE_BITDIFF}; + const ALfloat pf{(frac & ((1<(filter + offset)}; offset += m; + const __m128 *scd{reinterpret_cast(filter + offset)}; offset += m; + const __m128 *phd{reinterpret_cast(filter + offset)}; offset += m; + const __m128 *spd{reinterpret_cast(filter + offset)}; + + // Apply the scale and phase interpolated filter. + __m128 r4{_mm_setzero_ps()}; + { + const ALsizei count{m >> 2}; + const __m128 pf4{_mm_set1_ps(pf)}; + + ASSUME(count > 0); + +#define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z)) + for(ALsizei j{0};j < count;j++) + { + /* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */ + const __m128 f4 = MLA4( + MLA4(fil[j], sf4, scd[j]), + pf4, MLA4(phd[j], sf4, spd[j]) + ); + /* r += f*src */ + r4 = MLA4(r4, f4, _mm_loadu_ps(&src[j*4])); + } +#undef MLA4 + } + r4 = _mm_add_ps(r4, _mm_shuffle_ps(r4, r4, _MM_SHUFFLE(0, 1, 2, 3))); + r4 = _mm_add_ps(r4, _mm_movehl_ps(r4, r4)); + dst[i] = _mm_cvtss_f32(r4); + + frac += increment; + src += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } + return dst; +} + + +static inline void ApplyCoeffs(ALsizei Offset, float2 *RESTRICT Values, const ALsizei IrSize, + const HrirArray &Coeffs, const ALfloat left, const ALfloat right) +{ + const __m128 lrlr{_mm_setr_ps(left, right, left, right)}; + + ASSUME(IrSize >= 2); + + if((Offset&1)) + { + __m128 imp0, imp1; + __m128 coeffs{_mm_load_ps(&Coeffs[0][0])}; + __m128 vals{_mm_loadl_pi(_mm_setzero_ps(), reinterpret_cast<__m64*>(&Values[0][0]))}; + imp0 = _mm_mul_ps(lrlr, coeffs); + vals = _mm_add_ps(imp0, vals); + _mm_storel_pi(reinterpret_cast<__m64*>(&Values[0][0]), vals); + ALsizei i{1}; + for(;i < IrSize-1;i += 2) + { + coeffs = _mm_load_ps(&Coeffs[i+1][0]); + vals = _mm_load_ps(&Values[i][0]); + imp1 = _mm_mul_ps(lrlr, coeffs); + imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2)); + vals = _mm_add_ps(imp0, vals); + _mm_store_ps(&Values[i][0], vals); + imp0 = imp1; + } + vals = _mm_loadl_pi(vals, reinterpret_cast<__m64*>(&Values[i][0])); + imp0 = _mm_movehl_ps(imp0, imp0); + vals = _mm_add_ps(imp0, vals); + _mm_storel_pi(reinterpret_cast<__m64*>(&Values[i][0]), vals); + } + else + { + for(ALsizei i{0};i < IrSize;i += 2) + { + __m128 coeffs{_mm_load_ps(&Coeffs[i][0])}; + __m128 vals{_mm_load_ps(&Values[i][0])}; + vals = _mm_add_ps(vals, _mm_mul_ps(lrlr, coeffs)); + _mm_store_ps(&Values[i][0], vals); + } + } +} + +template<> +void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, + MixHrtfFilter *hrtfparams, const ALsizei BufferSize) +{ + MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, + hrtfparams, BufferSize); +} + +template<> +void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, + const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize) +{ + MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, + oldparams, newparams, BufferSize); +} + +template<> +void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, + const ALsizei BufferSize) +{ + MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, BufferSize); +} + + +template<> +void Mix_(const ALfloat *data, const al::span OutBuffer, + ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, + const ALsizei BufferSize) +{ + ASSUME(BufferSize > 0); + + const ALfloat delta{(Counter > 0) ? 1.0f / static_cast(Counter) : 0.0f}; + for(FloatBufferLine &output : OutBuffer) + { + ALfloat *RESTRICT dst{al::assume_aligned<16>(output.data()+OutPos)}; + ALfloat gain{*CurrentGains}; + const ALfloat diff{*TargetGains - gain}; + + ALsizei pos{0}; + if(std::fabs(diff) > std::numeric_limits::epsilon()) + { + ALsizei minsize{mini(BufferSize, Counter)}; + const ALfloat step{diff * delta}; + ALfloat step_count{0.0f}; + /* Mix with applying gain steps in aligned multiples of 4. */ + if(LIKELY(minsize > 3)) + { + const __m128 four4{_mm_set1_ps(4.0f)}; + const __m128 step4{_mm_set1_ps(step)}; + const __m128 gain4{_mm_set1_ps(gain)}; + __m128 step_count4{_mm_setr_ps(0.0f, 1.0f, 2.0f, 3.0f)}; + ALsizei todo{minsize >> 2}; + do { + const __m128 val4{_mm_load_ps(&data[pos])}; + __m128 dry4{_mm_load_ps(&dst[pos])}; +#define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z)) + /* dry += val * (gain + step*step_count) */ + dry4 = MLA4(dry4, val4, MLA4(gain4, step4, step_count4)); +#undef MLA4 + _mm_store_ps(&dst[pos], dry4); + step_count4 = _mm_add_ps(step_count4, four4); + pos += 4; + } while(--todo); + /* NOTE: step_count4 now represents the next four counts after + * the last four mixed samples, so the lowest element + * represents the next step count to apply. + */ + step_count = _mm_cvtss_f32(step_count4); + } + /* Mix with applying left over gain steps that aren't aligned multiples of 4. */ + for(;pos < minsize;pos++) + { + dst[pos] += data[pos]*(gain + step*step_count); + step_count += 1.0f; + } + if(pos == Counter) + gain = *TargetGains; + else + gain += step*step_count; + *CurrentGains = gain; + + /* Mix until pos is aligned with 4 or the mix is done. */ + minsize = mini(BufferSize, (pos+3)&~3); + for(;pos < minsize;pos++) + dst[pos] += data[pos]*gain; + } + ++CurrentGains; + ++TargetGains; + + if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + if(LIKELY(BufferSize-pos > 3)) + { + ALsizei todo{(BufferSize-pos) >> 2}; + const __m128 gain4{_mm_set1_ps(gain)}; + do { + const __m128 val4{_mm_load_ps(&data[pos])}; + __m128 dry4{_mm_load_ps(&dst[pos])}; + dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); + _mm_store_ps(&dst[pos], dry4); + pos += 4; + } while(--todo); + } + for(;pos < BufferSize;pos++) + dst[pos] += data[pos]*gain; + } +} + +template<> +void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, + const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize) +{ + ASSUME(BufferSize > 0); + + for(const FloatBufferLine &input : InSamples) + { + const ALfloat *RESTRICT src{al::assume_aligned<16>(input.data()+InPos)}; + const ALfloat gain{*(Gains++)}; + if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + ALsizei pos{0}; + if(LIKELY(BufferSize > 3)) + { + ALsizei todo{BufferSize >> 2}; + const __m128 gain4 = _mm_set1_ps(gain); + do { + const __m128 val4{_mm_load_ps(&src[pos])}; + __m128 dry4{_mm_load_ps(&OutBuffer[pos])}; + dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); + _mm_store_ps(&OutBuffer[pos], dry4); + pos += 4; + } while(--todo); + } + for(;pos < BufferSize;pos++) + OutBuffer[pos] += src[pos]*gain; + } +} diff --git a/alc/mixer/mixer_sse2.cpp b/alc/mixer/mixer_sse2.cpp new file mode 100644 index 00000000..b5d00106 --- /dev/null +++ b/alc/mixer/mixer_sse2.cpp @@ -0,0 +1,84 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2014 by Timothy Arceri . + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alu.h" +#include "defs.h" + + +template<> +const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) +{ + const __m128i increment4{_mm_set1_epi32(increment*4)}; + const __m128 fracOne4{_mm_set1_ps(1.0f/FRACTIONONE)}; + const __m128i fracMask4{_mm_set1_epi32(FRACTIONMASK)}; + + ASSUME(frac > 0); + ASSUME(increment > 0); + ASSUME(dstlen >= 0); + + alignas(16) ALsizei pos_[4], frac_[4]; + InitiatePositionArrays(frac, increment, frac_, pos_, 4); + __m128i frac4{_mm_setr_epi32(frac_[0], frac_[1], frac_[2], frac_[3])}; + __m128i pos4{_mm_setr_epi32(pos_[0], pos_[1], pos_[2], pos_[3])}; + + const ALsizei todo{dstlen & ~3}; + for(ALsizei i{0};i < todo;i += 4) + { + const int pos0{_mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(0, 0, 0, 0)))}; + const int pos1{_mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(1, 1, 1, 1)))}; + const int pos2{_mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(2, 2, 2, 2)))}; + const int pos3{_mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(3, 3, 3, 3)))}; + const __m128 val1{_mm_setr_ps(src[pos0 ], src[pos1 ], src[pos2 ], src[pos3 ])}; + const __m128 val2{_mm_setr_ps(src[pos0+1], src[pos1+1], src[pos2+1], src[pos3+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); + } + + /* NOTE: These four elements represent the position *after* the last four + * samples, so the lowest element is the next position to resample. + */ + ALsizei pos{_mm_cvtsi128_si32(pos4)}; + frac = _mm_cvtsi128_si32(frac4); + + for(ALsizei i{todo};i < dstlen;++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/mixer_sse3.cpp b/alc/mixer/mixer_sse3.cpp new file mode 100644 index 00000000..e69de29b diff --git a/alc/mixer/mixer_sse41.cpp b/alc/mixer/mixer_sse41.cpp new file mode 100644 index 00000000..7efbda7b --- /dev/null +++ b/alc/mixer/mixer_sse41.cpp @@ -0,0 +1,85 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2014 by Timothy Arceri . + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include "alu.h" +#include "defs.h" + + +template<> +const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) +{ + const __m128i increment4{_mm_set1_epi32(increment*4)}; + const __m128 fracOne4{_mm_set1_ps(1.0f/FRACTIONONE)}; + const __m128i fracMask4{_mm_set1_epi32(FRACTIONMASK)}; + + ASSUME(frac > 0); + ASSUME(increment > 0); + ASSUME(dstlen >= 0); + + alignas(16) ALsizei pos_[4], frac_[4]; + InitiatePositionArrays(frac, increment, frac_, pos_, 4); + __m128i frac4{_mm_setr_epi32(frac_[0], frac_[1], frac_[2], frac_[3])}; + __m128i pos4{_mm_setr_epi32(pos_[0], pos_[1], pos_[2], pos_[3])}; + + const ALsizei todo{dstlen & ~3}; + for(ALsizei i{0};i < todo;i += 4) + { + const int pos0{_mm_extract_epi32(pos4, 0)}; + const int pos1{_mm_extract_epi32(pos4, 1)}; + const int pos2{_mm_extract_epi32(pos4, 2)}; + const int pos3{_mm_extract_epi32(pos4, 3)}; + const __m128 val1{_mm_setr_ps(src[pos0 ], src[pos1 ], src[pos2 ], src[pos3 ])}; + const __m128 val2{_mm_setr_ps(src[pos0+1], src[pos1+1], src[pos2+1], src[pos3+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); + } + + /* NOTE: These four elements represent the position *after* the last four + * samples, so the lowest element is the next position to resample. + */ + ALsizei pos{_mm_cvtsi128_si32(pos4)}; + frac = _mm_cvtsi128_si32(frac4); + + for(ALsizei i{todo};i < dstlen;++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/mixvoice.cpp b/alc/mixvoice.cpp new file mode 100644 index 00000000..be872f6d --- /dev/null +++ b/alc/mixvoice.cpp @@ -0,0 +1,954 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" + +#include "alBuffer.h" +#include "alcmain.h" +#include "alSource.h" +#include "albyte.h" +#include "alconfig.h" +#include "alcontext.h" +#include "alnumeric.h" +#include "aloptional.h" +#include "alspan.h" +#include "alu.h" +#include "cpu_caps.h" +#include "filters/biquad.h" +#include "filters/nfc.h" +#include "filters/splitter.h" +#include "hrtf.h" +#include "inprogext.h" +#include "logging.h" +#include "mixer/defs.h" +#include "opthelpers.h" +#include "ringbuffer.h" +#include "threads.h" +#include "vector.h" + + +static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, + "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!"); + +/* BSinc24 requires up to 23 extra samples before the current position, and 24 after. */ +static_assert(MAX_RESAMPLE_PADDING >= 24, "MAX_RESAMPLE_PADDING must be at least 24!"); + + +Resampler ResamplerDefault = LinearResampler; + +MixerFunc MixSamples = Mix_; +RowMixerFunc MixRowSamples = MixRow_; +static HrtfMixerFunc MixHrtfSamples = MixHrtf_; +static HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_; + +static MixerFunc SelectMixer() +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return Mix_; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return Mix_; +#endif + return Mix_; +} + +static RowMixerFunc SelectRowMixer() +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return MixRow_; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixRow_; +#endif + return MixRow_; +} + +static inline HrtfMixerFunc SelectHrtfMixer() +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return MixHrtf_; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixHrtf_; +#endif + return MixHrtf_; +} + +static inline HrtfMixerBlendFunc SelectHrtfBlendMixer() +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return MixHrtfBlend_; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixHrtfBlend_; +#endif + return MixHrtfBlend_; +} + +ResamplerFunc SelectResampler(Resampler resampler) +{ + switch(resampler) + { + case PointResampler: + return Resample_; + case LinearResampler: +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return Resample_; +#endif +#ifdef HAVE_SSE4_1 + if((CPUCapFlags&CPU_CAP_SSE4_1)) + return Resample_; +#endif +#ifdef HAVE_SSE2 + if((CPUCapFlags&CPU_CAP_SSE2)) + return Resample_; +#endif + return Resample_; + case FIR4Resampler: + return Resample_; + case BSinc12Resampler: + case BSinc24Resampler: +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return Resample_; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return Resample_; +#endif + return Resample_; + } + + return Resample_; +} + + +void aluInitMixer() +{ + if(auto resopt = ConfigValueStr(nullptr, nullptr, "resampler")) + { + const char *str{resopt->c_str()}; + if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0) + ResamplerDefault = PointResampler; + else if(strcasecmp(str, "linear") == 0) + ResamplerDefault = LinearResampler; + else if(strcasecmp(str, "cubic") == 0) + ResamplerDefault = FIR4Resampler; + else if(strcasecmp(str, "bsinc12") == 0) + ResamplerDefault = BSinc12Resampler; + else if(strcasecmp(str, "bsinc24") == 0) + ResamplerDefault = BSinc24Resampler; + else if(strcasecmp(str, "bsinc") == 0) + { + WARN("Resampler option \"%s\" is deprecated, using bsinc12\n", str); + ResamplerDefault = BSinc12Resampler; + } + else if(strcasecmp(str, "sinc4") == 0 || strcasecmp(str, "sinc8") == 0) + { + WARN("Resampler option \"%s\" is deprecated, using cubic\n", str); + ResamplerDefault = FIR4Resampler; + } + else + { + char *end; + long n = strtol(str, &end, 0); + if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == FIR4Resampler)) + ResamplerDefault = static_cast(n); + else + WARN("Invalid resampler: %s\n", str); + } + } + + MixHrtfBlendSamples = SelectHrtfBlendMixer(); + MixHrtfSamples = SelectHrtfMixer(); + MixSamples = SelectMixer(); + MixRowSamples = SelectRowMixer(); +} + + +namespace { + +/* A quick'n'dirty lookup table to decode a muLaw-encoded byte sample into a + * signed 16-bit sample */ +constexpr ALshort muLawDecompressionTable[256] = { + -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956, + -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764, + -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412, + -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316, + -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, + -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, + -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, + -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, + -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, + -876, -844, -812, -780, -748, -716, -684, -652, + -620, -588, -556, -524, -492, -460, -428, -396, + -372, -356, -340, -324, -308, -292, -276, -260, + -244, -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, -64, + -56, -48, -40, -32, -24, -16, -8, 0, + 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, + 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, + 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, + 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, + 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, + 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, + 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, + 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, + 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, + 876, 844, 812, 780, 748, 716, 684, 652, + 620, 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, 260, + 244, 228, 212, 196, 180, 164, 148, 132, + 120, 112, 104, 96, 88, 80, 72, 64, + 56, 48, 40, 32, 24, 16, 8, 0 +}; + +/* A quick'n'dirty lookup table to decode an aLaw-encoded byte sample into a + * signed 16-bit sample */ +constexpr ALshort aLawDecompressionTable[256] = { + -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, + -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, + -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, + -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, + -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944, + -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136, + -11008,-10496,-12032,-11520, -8960, -8448, -9984, -9472, + -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568, + -344, -328, -376, -360, -280, -264, -312, -296, + -472, -456, -504, -488, -408, -392, -440, -424, + -88, -72, -120, -104, -24, -8, -56, -40, + -216, -200, -248, -232, -152, -136, -184, -168, + -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, + -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, -592, + -944, -912, -1008, -976, -816, -784, -880, -848, + 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, + 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, + 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, + 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, + 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, + 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, + 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, + 344, 328, 376, 360, 280, 264, 312, 296, + 472, 456, 504, 488, 408, 392, 440, 424, + 88, 72, 120, 104, 24, 8, 56, 40, + 216, 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, + 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, + 688, 656, 752, 720, 560, 528, 624, 592, + 944, 912, 1008, 976, 816, 784, 880, 848 +}; + + +void SendSourceStoppedEvent(ALCcontext *context, ALuint id) +{ + ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)}; + if(!(enabledevt&EventType_SourceStateChange)) return; + + RingBuffer *ring{context->AsyncEvents.get()}; + auto evt_vec = ring->getWriteVector(); + if(evt_vec.first.len < 1) return; + + AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_SourceStateChange}}; + evt->u.srcstate.id = id; + evt->u.srcstate.state = AL_STOPPED; + + ring->writeAdvance(1); + context->EventSem.post(); +} + + +const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, ALfloat *dst, + const ALfloat *src, ALsizei numsamples, int type) +{ + switch(type) + { + case AF_None: + lpfilter->clear(); + hpfilter->clear(); + break; + + case AF_LowPass: + lpfilter->process(dst, src, numsamples); + hpfilter->clear(); + return dst; + case AF_HighPass: + lpfilter->clear(); + hpfilter->process(dst, src, numsamples); + return dst; + + case AF_BandPass: + lpfilter->process(dst, src, numsamples); + hpfilter->process(dst, dst, numsamples); + return dst; + } + return src; +} + + +/* Base template left undefined. Should be marked =delete, but Clang 3.8.1 + * chokes on that given the inline specializations. + */ +template +inline ALfloat LoadSample(typename FmtTypeTraits::Type val); + +template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) +{ return (val-128) * (1.0f/128.0f); } +template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) +{ return val * (1.0f/32768.0f); } +template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) +{ return val; } +template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) +{ return static_cast(val); } +template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) +{ return muLawDecompressionTable[val] * (1.0f/32768.0f); } +template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) +{ return aLawDecompressionTable[val] * (1.0f/32768.0f); } + +template +inline void LoadSampleArray(ALfloat *RESTRICT dst, const al::byte *src, ALint srcstep, + const ptrdiff_t samples) +{ + using SampleType = typename FmtTypeTraits::Type; + + const SampleType *RESTRICT ssrc{reinterpret_cast(src)}; + for(ALsizei i{0};i < samples;i++) + dst[i] += LoadSample(ssrc[i*srcstep]); +} + +void LoadSamples(ALfloat *RESTRICT dst, const al::byte *src, ALint srcstep, FmtType srctype, + const ptrdiff_t samples) +{ +#define HANDLE_FMT(T) case T: LoadSampleArray(dst, src, srcstep, samples); break + switch(srctype) + { + HANDLE_FMT(FmtUByte); + HANDLE_FMT(FmtShort); + HANDLE_FMT(FmtFloat); + HANDLE_FMT(FmtDouble); + HANDLE_FMT(FmtMulaw); + HANDLE_FMT(FmtAlaw); + } +#undef HANDLE_FMT +} + +ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&BufferLoopItem, + const ALsizei NumChannels, const ALsizei SampleSize, const ALsizei chan, ALsizei DataPosInt, + al::span SrcBuffer) +{ + /* TODO: For static sources, loop points are taken from the first buffer + * (should be adjusted by any buffer offset, to possibly be added later). + */ + const ALbuffer *Buffer0{BufferListItem->buffers[0]}; + const ALsizei LoopStart{Buffer0->LoopStart}; + const ALsizei LoopEnd{Buffer0->LoopEnd}; + ASSUME(LoopStart >= 0); + ASSUME(LoopEnd > LoopStart); + + /* If current pos is beyond the loop range, do not loop */ + if(!BufferLoopItem || DataPosInt >= LoopEnd) + { + BufferLoopItem = nullptr; + + auto load_buffer = [DataPosInt,NumChannels,SampleSize,chan,SrcBuffer](size_t CompLen, const ALbuffer *buffer) -> size_t + { + if(DataPosInt >= buffer->SampleLen) + return CompLen; + + /* Load what's left to play from the buffer */ + const size_t DataSize{std::min(SrcBuffer.size(), + buffer->SampleLen - DataPosInt)}; + CompLen = std::max(CompLen, DataSize); + + const al::byte *Data{buffer->mData.data()}; + Data += (DataPosInt*NumChannels + chan)*SampleSize; + + LoadSamples(SrcBuffer.data(), Data, NumChannels, buffer->mFmtType, DataSize); + return CompLen; + }; + /* It's impossible to have a buffer list item with no entries. */ + ASSUME(BufferListItem->num_buffers > 0); + auto buffers_end = BufferListItem->buffers + BufferListItem->num_buffers; + SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->buffers, buffers_end, + size_t{0u}, load_buffer)); + } + else + { + const al::span SrcData{SrcBuffer.first( + std::min(SrcBuffer.size(), LoopEnd - DataPosInt))}; + + auto load_buffer = [DataPosInt,NumChannels,SampleSize,chan,SrcData](size_t CompLen, const ALbuffer *buffer) -> size_t + { + if(DataPosInt >= buffer->SampleLen) + return CompLen; + + /* Load what's left of this loop iteration */ + const size_t DataSize{std::min(SrcData.size(), + buffer->SampleLen - DataPosInt)}; + CompLen = std::max(CompLen, DataSize); + + const al::byte *Data{buffer->mData.data()}; + Data += (DataPosInt*NumChannels + chan)*SampleSize; + + LoadSamples(SrcData.data(), Data, NumChannels, buffer->mFmtType, DataSize); + return CompLen; + }; + ASSUME(BufferListItem->num_buffers > 0); + auto buffers_end = BufferListItem->buffers + BufferListItem->num_buffers; + SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->buffers, buffers_end, + size_t{0u}, load_buffer)); + + const auto LoopSize = static_cast(LoopEnd - LoopStart); + while(!SrcBuffer.empty()) + { + const al::span SrcData{SrcBuffer.first( + std::min(SrcBuffer.size(), LoopSize))}; + + auto load_buffer_loop = [LoopStart,NumChannels,SampleSize,chan,SrcData](size_t CompLen, const ALbuffer *buffer) -> size_t + { + if(LoopStart >= buffer->SampleLen) + return CompLen; + + const size_t DataSize{std::min(SrcData.size(), + buffer->SampleLen-LoopStart)}; + CompLen = std::max(CompLen, DataSize); + + const al::byte *Data{buffer->mData.data()}; + Data += (LoopStart*NumChannels + chan)*SampleSize; + + LoadSamples(SrcData.data(), Data, NumChannels, buffer->mFmtType, DataSize); + return CompLen; + }; + SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->buffers, buffers_end, + size_t{0u}, load_buffer_loop)); + } + } + return SrcBuffer.begin(); +} + +ALfloat *LoadBufferQueue(ALbufferlistitem *BufferListItem, ALbufferlistitem *BufferLoopItem, + const ALsizei NumChannels, const ALsizei SampleSize, const ALsizei chan, ALsizei DataPosInt, + al::span SrcBuffer) +{ + /* Crawl the buffer queue to fill in the temp buffer */ + while(BufferListItem && !SrcBuffer.empty()) + { + if(DataPosInt >= BufferListItem->max_samples) + { + DataPosInt -= BufferListItem->max_samples; + BufferListItem = BufferListItem->next.load(std::memory_order_acquire); + if(!BufferListItem) BufferListItem = BufferLoopItem; + continue; + } + + auto load_buffer = [DataPosInt,NumChannels,SampleSize,chan,SrcBuffer](size_t CompLen, const ALbuffer *buffer) -> size_t + { + if(!buffer) return CompLen; + if(DataPosInt >= buffer->SampleLen) + return CompLen; + + const size_t DataSize{std::min(SrcBuffer.size(), buffer->SampleLen-DataPosInt)}; + CompLen = std::max(CompLen, DataSize); + + const al::byte *Data{buffer->mData.data()}; + Data += (DataPosInt*NumChannels + chan)*SampleSize; + + LoadSamples(SrcBuffer.data(), Data, NumChannels, buffer->mFmtType, DataSize); + return CompLen; + }; + ASSUME(BufferListItem->num_buffers > 0); + auto buffers_end = BufferListItem->buffers + BufferListItem->num_buffers; + SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->buffers, buffers_end, + size_t{0u}, load_buffer)); + + if(SrcBuffer.empty()) + break; + DataPosInt = 0; + BufferListItem = BufferListItem->next.load(std::memory_order_acquire); + if(!BufferListItem) BufferListItem = BufferLoopItem; + } + + return SrcBuffer.begin(); +} + +} // namespace + +void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCcontext *Context, const ALsizei SamplesToDo) +{ + static constexpr ALfloat SilentTarget[MAX_OUTPUT_CHANNELS]{}; + + ASSUME(SamplesToDo > 0); + + /* Get voice info */ + const bool isstatic{(voice->mFlags&VOICE_IS_STATIC) != 0}; + ALsizei DataPosInt{static_cast(voice->mPosition.load(std::memory_order_relaxed))}; + ALsizei DataPosFrac{voice->mPositionFrac.load(std::memory_order_relaxed)}; + ALbufferlistitem *BufferListItem{voice->mCurrentBuffer.load(std::memory_order_relaxed)}; + ALbufferlistitem *BufferLoopItem{voice->mLoopBuffer.load(std::memory_order_relaxed)}; + const ALsizei NumChannels{voice->mNumChannels}; + const ALsizei SampleSize{voice->mSampleSize}; + const ALint increment{voice->mStep}; + + ASSUME(DataPosInt >= 0); + ASSUME(DataPosFrac >= 0); + ASSUME(NumChannels > 0); + ASSUME(SampleSize > 0); + ASSUME(increment > 0); + + ALCdevice *Device{Context->Device}; + const ALsizei NumSends{Device->NumAuxSends}; + const ALsizei IrSize{Device->mHrtf ? Device->mHrtf->irSize : 0}; + + ASSUME(NumSends >= 0); + ASSUME(IrSize >= 0); + + ResamplerFunc Resample{(increment == FRACTIONONE && DataPosFrac == 0) ? + Resample_ : voice->mResampler}; + + ALsizei Counter{(voice->mFlags&VOICE_IS_FADING) ? SamplesToDo : 0}; + if(!Counter) + { + /* No fading, just overwrite the old/current params. */ + for(ALsizei chan{0};chan < NumChannels;chan++) + { + ALvoice::ChannelData &chandata = voice->mChans[chan]; + DirectParams &parms = chandata.mDryParams; + if(!(voice->mFlags&VOICE_HAS_HRTF)) + std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target), + std::begin(parms.Gains.Current)); + else + parms.Hrtf.Old = parms.Hrtf.Target; + for(ALsizei send{0};send < NumSends;++send) + { + if(voice->mSend[send].Buffer.empty()) + continue; + + SendParams &parms = chandata.mWetParams[send]; + std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target), + std::begin(parms.Gains.Current)); + } + } + } + else if((voice->mFlags&VOICE_HAS_HRTF)) + { + for(ALsizei chan{0};chan < NumChannels;chan++) + { + DirectParams &parms = voice->mChans[chan].mDryParams; + if(!(parms.Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD)) + { + /* The old HRTF params are silent, so overwrite the old + * coefficients with the new, and reset the old gain to 0. The + * future mix will then fade from silence. + */ + parms.Hrtf.Old = parms.Hrtf.Target; + parms.Hrtf.Old.Gain = 0.0f; + } + } + } + + ALsizei buffers_done{0}; + ALsizei OutPos{0}; + do { + /* Figure out how many buffer samples will be needed */ + ALsizei DstBufferSize{SamplesToDo - OutPos}; + + /* Calculate the last written dst sample pos. */ + int64_t DataSize64{DstBufferSize - 1}; + /* Calculate the last read src sample pos. */ + DataSize64 = (DataSize64*increment + DataPosFrac) >> FRACTIONBITS; + /* +1 to get the src sample count, include padding. */ + DataSize64 += 1 + MAX_RESAMPLE_PADDING*2; + + auto SrcBufferSize = static_cast( + mini64(DataSize64, BUFFERSIZE + MAX_RESAMPLE_PADDING*2 + 1)); + if(SrcBufferSize > BUFFERSIZE + MAX_RESAMPLE_PADDING*2) + { + SrcBufferSize = BUFFERSIZE + MAX_RESAMPLE_PADDING*2; + /* If the source buffer got saturated, we can't fill the desired + * dst size. Figure out how many samples we can actually mix from + * this. + */ + DataSize64 = SrcBufferSize - MAX_RESAMPLE_PADDING*2; + DataSize64 = ((DataSize64<(mini64(DataSize64, DstBufferSize)); + + /* Some mixers like having a multiple of 4, so try to give that + * unless this is the last update. + */ + if(DstBufferSize < SamplesToDo-OutPos) + DstBufferSize &= ~3; + } + + for(ALsizei chan{0};chan < NumChannels;chan++) + { + ALvoice::ChannelData &chandata = voice->mChans[chan]; + const al::span SrcData{Device->SourceData, SrcBufferSize}; + + /* Load the previous samples into the source data first, and clear the rest. */ + auto srciter = std::copy_n(chandata.mPrevSamples.begin(), MAX_RESAMPLE_PADDING, + SrcData.begin()); + std::fill(srciter, SrcData.end(), 0.0f); + + if(UNLIKELY(!BufferListItem)) + srciter = std::copy(chandata.mPrevSamples.begin()+MAX_RESAMPLE_PADDING, + chandata.mPrevSamples.end(), srciter); + else if(isstatic) + srciter = LoadBufferStatic(BufferListItem, BufferLoopItem, NumChannels, + SampleSize, chan, DataPosInt, {srciter, SrcData.end()}); + else + srciter = LoadBufferQueue(BufferListItem, BufferLoopItem, NumChannels, + SampleSize, chan, DataPosInt, {srciter, SrcData.end()}); + + if(UNLIKELY(srciter != SrcData.end())) + { + /* If the source buffer wasn't filled, copy the last sample for + * the remaining buffer. Ideally it should have ended with + * silence, but if not the gain fading should help avoid clicks + * from sudden amplitude changes. + */ + const ALfloat sample{*(srciter-1)}; + std::fill(srciter, SrcData.end(), sample); + } + + /* Store the last source samples used for next time. */ + std::copy_n(&SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS], + chandata.mPrevSamples.size(), chandata.mPrevSamples.begin()); + + /* Resample, then apply ambisonic upsampling as needed. */ + const ALfloat *ResampledData{Resample(&voice->mResampleState, + &SrcData[MAX_RESAMPLE_PADDING], DataPosFrac, increment, + Device->ResampledData, DstBufferSize)}; + if((voice->mFlags&VOICE_IS_AMBISONIC)) + { + const ALfloat hfscale{chandata.mAmbiScale}; + /* Beware the evil const_cast. It's safe since it's pointing to + * either SourceData or ResampledData (both non-const), but the + * resample method takes the source as const float* and may + * return it without copying to output, making it currently + * unavoidable. + */ + chandata.mAmbiSplitter.applyHfScale(const_cast(ResampledData), hfscale, + DstBufferSize); + } + + /* Now filter and mix to the appropriate outputs. */ + { + DirectParams &parms = chandata.mDryParams; + const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, + Device->FilteredData, ResampledData, DstBufferSize, + voice->mDirect.FilterType)}; + + if((voice->mFlags&VOICE_HAS_HRTF)) + { + const int OutLIdx{GetChannelIdxByName(Device->RealOut, FrontLeft)}; + const int OutRIdx{GetChannelIdxByName(Device->RealOut, FrontRight)}; + ASSUME(OutLIdx >= 0 && OutRIdx >= 0); + + auto &HrtfSamples = Device->HrtfSourceData; + auto &AccumSamples = Device->HrtfAccumData; + const ALfloat TargetGain{UNLIKELY(vstate == ALvoice::Stopping) ? 0.0f : + parms.Hrtf.Target.Gain}; + ALsizei fademix{0}; + + /* Copy the HRTF history and new input samples into a temp + * buffer. + */ + auto src_iter = std::copy(parms.Hrtf.State.History.begin(), + parms.Hrtf.State.History.end(), std::begin(HrtfSamples)); + std::copy_n(samples, DstBufferSize, src_iter); + /* Copy the last used samples back into the history buffer + * for later. + */ + std::copy_n(std::begin(HrtfSamples) + DstBufferSize, + parms.Hrtf.State.History.size(), parms.Hrtf.State.History.begin()); + + /* Copy the current filtered values being accumulated into + * the temp buffer. + */ + auto accum_iter = std::copy_n(parms.Hrtf.State.Values.begin(), + parms.Hrtf.State.Values.size(), std::begin(AccumSamples)); + + /* Clear the accumulation buffer that will start getting + * filled in. + */ + std::fill_n(accum_iter, DstBufferSize, float2{}); + + /* If fading, the old gain is not silence, and this is the + * first mixing pass, fade between the IRs. + */ + if(Counter && (parms.Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD) && OutPos == 0) + { + fademix = mini(DstBufferSize, 128); + + ALfloat gain{TargetGain}; + + /* The new coefficients need to fade in completely + * since they're replacing the old ones. To keep the + * gain fading consistent, interpolate between the old + * and new target gains given how much of the fade time + * this mix handles. + */ + if(LIKELY(Counter > fademix)) + { + const ALfloat a{static_cast(fademix) / + static_cast(Counter)}; + gain = lerp(parms.Hrtf.Old.Gain, TargetGain, a); + } + MixHrtfFilter hrtfparams; + hrtfparams.Coeffs = &parms.Hrtf.Target.Coeffs; + hrtfparams.Delay[0] = parms.Hrtf.Target.Delay[0]; + hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1]; + hrtfparams.Gain = 0.0f; + hrtfparams.GainStep = gain / static_cast(fademix); + + MixHrtfBlendSamples(voice->mDirect.Buffer[OutLIdx], + voice->mDirect.Buffer[OutRIdx], HrtfSamples, AccumSamples, OutPos, + IrSize, &parms.Hrtf.Old, &hrtfparams, fademix); + /* Update the old parameters with the result. */ + parms.Hrtf.Old = parms.Hrtf.Target; + if(fademix < Counter) + parms.Hrtf.Old.Gain = hrtfparams.Gain; + else + parms.Hrtf.Old.Gain = TargetGain; + } + + if(LIKELY(fademix < DstBufferSize)) + { + const ALsizei todo{DstBufferSize - fademix}; + ALfloat gain{TargetGain}; + + /* Interpolate the target gain if the gain fading lasts + * longer than this mix. + */ + if(Counter > DstBufferSize) + { + const ALfloat a{static_cast(todo) / + static_cast(Counter-fademix)}; + gain = lerp(parms.Hrtf.Old.Gain, TargetGain, a); + } + + MixHrtfFilter hrtfparams; + hrtfparams.Coeffs = &parms.Hrtf.Target.Coeffs; + hrtfparams.Delay[0] = parms.Hrtf.Target.Delay[0]; + hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1]; + hrtfparams.Gain = parms.Hrtf.Old.Gain; + hrtfparams.GainStep = (gain - parms.Hrtf.Old.Gain) / + static_cast(todo); + MixHrtfSamples(voice->mDirect.Buffer[OutLIdx], + voice->mDirect.Buffer[OutRIdx], HrtfSamples+fademix, + AccumSamples+fademix, OutPos+fademix, IrSize, &hrtfparams, todo); + /* Store the interpolated gain or the final target gain + * depending if the fade is done. + */ + if(DstBufferSize < Counter) + parms.Hrtf.Old.Gain = gain; + else + parms.Hrtf.Old.Gain = TargetGain; + } + + /* Copy the new in-progress accumulation values back for + * the next mix. + */ + std::copy_n(std::begin(AccumSamples) + DstBufferSize, + parms.Hrtf.State.Values.size(), parms.Hrtf.State.Values.begin()); + } + else if((voice->mFlags&VOICE_HAS_NFC)) + { + const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? + SilentTarget : parms.Gains.Target}; + + const size_t outcount{Device->NumChannelsPerOrder[0]}; + MixSamples(samples, voice->mDirect.Buffer.first(outcount), parms.Gains.Current, + TargetGains, Counter, OutPos, DstBufferSize); + + ALfloat (&nfcsamples)[BUFFERSIZE] = Device->NfcSampleData; + size_t chanoffset{outcount}; + using FilterProc = void (NfcFilter::*)(float*,const float*,int); + auto apply_nfc = [voice,&parms,samples,TargetGains,DstBufferSize,Counter,OutPos,&chanoffset,&nfcsamples](const FilterProc process, const size_t outcount) -> void + { + if(outcount < 1) return; + (parms.NFCtrlFilter.*process)(nfcsamples, samples, DstBufferSize); + MixSamples(nfcsamples, voice->mDirect.Buffer.subspan(chanoffset, outcount), + parms.Gains.Current+chanoffset, TargetGains+chanoffset, Counter, + OutPos, DstBufferSize); + chanoffset += outcount; + }; + apply_nfc(&NfcFilter::process1, Device->NumChannelsPerOrder[1]); + apply_nfc(&NfcFilter::process2, Device->NumChannelsPerOrder[2]); + apply_nfc(&NfcFilter::process3, Device->NumChannelsPerOrder[3]); + } + else + { + const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? + SilentTarget : parms.Gains.Target}; + MixSamples(samples, voice->mDirect.Buffer, parms.Gains.Current, TargetGains, + Counter, OutPos, DstBufferSize); + } + } + + ALfloat (&FilterBuf)[BUFFERSIZE] = Device->FilteredData; + for(ALsizei send{0};send < NumSends;++send) + { + if(voice->mSend[send].Buffer.empty()) + continue; + + SendParams &parms = chandata.mWetParams[send]; + const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, + FilterBuf, ResampledData, DstBufferSize, voice->mSend[send].FilterType)}; + + const ALfloat *TargetGains{UNLIKELY(vstate==ALvoice::Stopping) ? SilentTarget : + parms.Gains.Target}; + MixSamples(samples, voice->mSend[send].Buffer, parms.Gains.Current, TargetGains, + Counter, OutPos, DstBufferSize); + }; + } + /* Update positions */ + DataPosFrac += increment*DstBufferSize; + DataPosInt += DataPosFrac>>FRACTIONBITS; + DataPosFrac &= FRACTIONMASK; + + OutPos += DstBufferSize; + Counter = maxi(DstBufferSize, Counter) - DstBufferSize; + + if(UNLIKELY(!BufferListItem)) + { + /* Do nothing extra when there's no buffers. */ + } + else if(isstatic) + { + if(BufferLoopItem) + { + /* Handle looping static source */ + const ALbuffer *Buffer{BufferListItem->buffers[0]}; + const ALsizei LoopStart{Buffer->LoopStart}; + const ALsizei LoopEnd{Buffer->LoopEnd}; + if(DataPosInt >= LoopEnd) + { + assert(LoopEnd > LoopStart); + DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart; + } + } + else + { + /* Handle non-looping static source */ + if(DataPosInt >= BufferListItem->max_samples) + { + if(LIKELY(vstate == ALvoice::Playing)) + vstate = ALvoice::Stopped; + BufferListItem = nullptr; + break; + } + } + } + else while(1) + { + /* Handle streaming source */ + if(BufferListItem->max_samples > DataPosInt) + break; + + DataPosInt -= BufferListItem->max_samples; + + buffers_done += BufferListItem->num_buffers; + BufferListItem = BufferListItem->next.load(std::memory_order_relaxed); + if(!BufferListItem && !(BufferListItem=BufferLoopItem)) + { + if(LIKELY(vstate == ALvoice::Playing)) + vstate = ALvoice::Stopped; + break; + } + } + } while(OutPos < SamplesToDo); + + voice->mFlags |= VOICE_IS_FADING; + + /* Don't update positions and buffers if we were stopping. */ + if(UNLIKELY(vstate == ALvoice::Stopping)) + { + voice->mPlayState.store(ALvoice::Stopped, std::memory_order_release); + return; + } + + /* Update voice info */ + voice->mPosition.store(DataPosInt, std::memory_order_relaxed); + voice->mPositionFrac.store(DataPosFrac, std::memory_order_relaxed); + voice->mCurrentBuffer.store(BufferListItem, std::memory_order_relaxed); + if(vstate == ALvoice::Stopped) + { + voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); + voice->mSourceID.store(0u, std::memory_order_relaxed); + } + std::atomic_thread_fence(std::memory_order_release); + + /* Send any events now, after the position/buffer info was updated. */ + ALbitfieldSOFT enabledevt{Context->EnabledEvts.load(std::memory_order_acquire)}; + if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) + { + RingBuffer *ring{Context->AsyncEvents.get()}; + auto evt_vec = ring->getWriteVector(); + if(evt_vec.first.len > 0) + { + AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_BufferCompleted}}; + evt->u.bufcomp.id = SourceID; + evt->u.bufcomp.count = buffers_done; + ring->writeAdvance(1); + Context->EventSem.post(); + } + } + + if(vstate == ALvoice::Stopped) + { + /* If the voice just ended, set it to Stopping so the next render + * ensures any residual noise fades to 0 amplitude. + */ + voice->mPlayState.store(ALvoice::Stopping, std::memory_order_release); + SendSourceStoppedEvent(Context, SourceID); + } +} diff --git a/alc/panning.cpp b/alc/panning.cpp new file mode 100644 index 00000000..3a67e33a --- /dev/null +++ b/alc/panning.cpp @@ -0,0 +1,964 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2010 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "alcmain.h" +#include "alAuxEffectSlot.h" +#include "alu.h" +#include "alconfig.h" +#include "ambdec.h" +#include "bformatdec.h" +#include "filters/splitter.h" +#include "uhjfilter.h" +#include "bs2b.h" + +#include "alspan.h" + + +constexpr std::array AmbiScale::FromN3D; +constexpr std::array AmbiScale::FromSN3D; +constexpr std::array AmbiScale::FromFuMa; +constexpr std::array AmbiIndex::FromFuMa; +constexpr std::array AmbiIndex::FromACN; +constexpr std::array AmbiIndex::From2D; +constexpr std::array AmbiIndex::From3D; + + +namespace { + +using namespace std::placeholders; +using std::chrono::seconds; +using std::chrono::nanoseconds; + +inline const char *GetLabelFromChannel(Channel channel) +{ + switch(channel) + { + case FrontLeft: return "front-left"; + case FrontRight: return "front-right"; + case FrontCenter: return "front-center"; + case LFE: return "lfe"; + case BackLeft: return "back-left"; + case BackRight: return "back-right"; + case BackCenter: return "back-center"; + case SideLeft: return "side-left"; + case SideRight: return "side-right"; + + case UpperFrontLeft: return "upper-front-left"; + case UpperFrontRight: return "upper-front-right"; + case UpperBackLeft: return "upper-back-left"; + case UpperBackRight: return "upper-back-right"; + case LowerFrontLeft: return "lower-front-left"; + case LowerFrontRight: return "lower-front-right"; + case LowerBackLeft: return "lower-back-left"; + case LowerBackRight: return "lower-back-right"; + + case Aux0: return "aux-0"; + case Aux1: return "aux-1"; + case Aux2: return "aux-2"; + case Aux3: return "aux-3"; + case Aux4: return "aux-4"; + case Aux5: return "aux-5"; + case Aux6: return "aux-6"; + case Aux7: return "aux-7"; + case Aux8: return "aux-8"; + case Aux9: return "aux-9"; + case Aux10: return "aux-10"; + case Aux11: return "aux-11"; + case Aux12: return "aux-12"; + case Aux13: return "aux-13"; + case Aux14: return "aux-14"; + case Aux15: return "aux-15"; + + case MaxChannels: break; + } + return "(unknown)"; +} + + +void AllocChannels(ALCdevice *device, const ALuint main_chans, const ALuint real_chans) +{ + TRACE("Channel config, Main: %u, Real: %u\n", main_chans, real_chans); + + /* Allocate extra channels for any post-filter output. */ + const ALuint num_chans{main_chans + real_chans}; + + TRACE("Allocating %u channels, %zu bytes\n", num_chans, + num_chans*sizeof(device->MixBuffer[0])); + device->MixBuffer.resize(num_chans); + al::span buffer{device->MixBuffer.data(), device->MixBuffer.size()}; + + device->Dry.Buffer = buffer.first(main_chans); + buffer = buffer.subspan(main_chans); + if(real_chans != 0) + { + device->RealOut.Buffer = buffer.first(real_chans); + buffer = buffer.subspan(real_chans); + } + else + device->RealOut.Buffer = device->Dry.Buffer; +} + + +struct ChannelMap { + Channel ChanName; + ALfloat Config[MAX_AMBI2D_CHANNELS]; +}; + +bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) +{ + auto map_spkr = [device](const AmbDecConf::SpeakerConf &speaker) -> ALsizei + { + /* NOTE: AmbDec does not define any standard speaker names, however + * for this to work we have to by able to find the output channel + * the speaker definition corresponds to. Therefore, OpenAL Soft + * requires these channel labels to be recognized: + * + * LF = Front left + * RF = Front right + * LS = Side left + * RS = Side right + * LB = Back left + * RB = Back right + * CE = Front center + * CB = Back center + * + * Additionally, surround51 will acknowledge back speakers for side + * channels, and surround51rear will acknowledge side speakers for + * back channels, to avoid issues with an ambdec expecting 5.1 to + * use the side channels when the device is configured for back, + * and vice-versa. + */ + Channel ch{}; + if(speaker.Name == "LF") + ch = FrontLeft; + else if(speaker.Name == "RF") + ch = FrontRight; + else if(speaker.Name == "CE") + ch = FrontCenter; + else if(speaker.Name == "LS") + { + if(device->FmtChans == DevFmtX51Rear) + ch = BackLeft; + else + ch = SideLeft; + } + else if(speaker.Name == "RS") + { + if(device->FmtChans == DevFmtX51Rear) + ch = BackRight; + else + ch = SideRight; + } + else if(speaker.Name == "LB") + { + if(device->FmtChans == DevFmtX51) + ch = SideLeft; + else + ch = BackLeft; + } + else if(speaker.Name == "RB") + { + if(device->FmtChans == DevFmtX51) + ch = SideRight; + else + ch = BackRight; + } + else if(speaker.Name == "CB") + ch = BackCenter; + else + { + const char *name{speaker.Name.c_str()}; + unsigned int n; + char c; + + if(sscanf(name, "AUX%u%c", &n, &c) == 1 && n < 16) + ch = static_cast(Aux0+n); + else + { + ERR("AmbDec speaker label \"%s\" not recognized\n", name); + return -1; + } + } + const int chidx{GetChannelIdxByName(device->RealOut, ch)}; + if(chidx == -1) + ERR("Failed to lookup AmbDec speaker label %s\n", speaker.Name.c_str()); + return chidx; + }; + std::transform(conf->Speakers.begin(), conf->Speakers.end(), std::begin(speakermap), map_spkr); + /* Return success if no invalid entries are found. */ + auto speakermap_end = std::begin(speakermap) + conf->Speakers.size(); + return std::find(std::begin(speakermap), speakermap_end, -1) == speakermap_end; +} + + +constexpr ChannelMap MonoCfg[1] = { + { FrontCenter, { 1.0f } }, +}, StereoCfg[2] = { + { FrontLeft, { 5.00000000e-1f, 2.88675135e-1f, 5.52305643e-2f } }, + { FrontRight, { 5.00000000e-1f, -2.88675135e-1f, 5.52305643e-2f } }, +}, QuadCfg[4] = { + { BackLeft, { 3.53553391e-1f, 2.04124145e-1f, -2.04124145e-1f } }, + { FrontLeft, { 3.53553391e-1f, 2.04124145e-1f, 2.04124145e-1f } }, + { FrontRight, { 3.53553391e-1f, -2.04124145e-1f, 2.04124145e-1f } }, + { BackRight, { 3.53553391e-1f, -2.04124145e-1f, -2.04124145e-1f } }, +}, X51SideCfg[4] = { + { SideLeft, { 3.33000782e-1f, 1.89084803e-1f, -2.00042375e-1f, -2.12307769e-2f, -1.14579885e-2f } }, + { FrontLeft, { 1.88542860e-1f, 1.27709292e-1f, 1.66295695e-1f, 7.30571517e-2f, 2.10901184e-2f } }, + { FrontRight, { 1.88542860e-1f, -1.27709292e-1f, 1.66295695e-1f, -7.30571517e-2f, 2.10901184e-2f } }, + { SideRight, { 3.33000782e-1f, -1.89084803e-1f, -2.00042375e-1f, 2.12307769e-2f, -1.14579885e-2f } }, +}, X51RearCfg[4] = { + { BackLeft, { 3.33000782e-1f, 1.89084803e-1f, -2.00042375e-1f, -2.12307769e-2f, -1.14579885e-2f } }, + { FrontLeft, { 1.88542860e-1f, 1.27709292e-1f, 1.66295695e-1f, 7.30571517e-2f, 2.10901184e-2f } }, + { FrontRight, { 1.88542860e-1f, -1.27709292e-1f, 1.66295695e-1f, -7.30571517e-2f, 2.10901184e-2f } }, + { BackRight, { 3.33000782e-1f, -1.89084803e-1f, -2.00042375e-1f, 2.12307769e-2f, -1.14579885e-2f } }, +}, X61Cfg[6] = { + { SideLeft, { 2.04460341e-1f, 2.17177926e-1f, -4.39996780e-2f, -2.60790269e-2f, -6.87239792e-2f } }, + { FrontLeft, { 1.58923161e-1f, 9.21772680e-2f, 1.59658796e-1f, 6.66278083e-2f, 3.84686854e-2f } }, + { FrontRight, { 1.58923161e-1f, -9.21772680e-2f, 1.59658796e-1f, -6.66278083e-2f, 3.84686854e-2f } }, + { SideRight, { 2.04460341e-1f, -2.17177926e-1f, -4.39996780e-2f, 2.60790269e-2f, -6.87239792e-2f } }, + { BackCenter, { 2.50001688e-1f, 0.00000000e+0f, -2.50000094e-1f, 0.00000000e+0f, 6.05133395e-2f } }, +}, X71Cfg[6] = { + { BackLeft, { 2.04124145e-1f, 1.08880247e-1f, -1.88586120e-1f, -1.29099444e-1f, 7.45355993e-2f, 3.73460789e-2f, 0.00000000e+0f } }, + { SideLeft, { 2.04124145e-1f, 2.17760495e-1f, 0.00000000e+0f, 0.00000000e+0f, -1.49071198e-1f, -3.73460789e-2f, 0.00000000e+0f } }, + { FrontLeft, { 2.04124145e-1f, 1.08880247e-1f, 1.88586120e-1f, 1.29099444e-1f, 7.45355993e-2f, 3.73460789e-2f, 0.00000000e+0f } }, + { FrontRight, { 2.04124145e-1f, -1.08880247e-1f, 1.88586120e-1f, -1.29099444e-1f, 7.45355993e-2f, -3.73460789e-2f, 0.00000000e+0f } }, + { SideRight, { 2.04124145e-1f, -2.17760495e-1f, 0.00000000e+0f, 0.00000000e+0f, -1.49071198e-1f, 3.73460789e-2f, 0.00000000e+0f } }, + { BackRight, { 2.04124145e-1f, -1.08880247e-1f, -1.88586120e-1f, 1.29099444e-1f, 7.45355993e-2f, -3.73460789e-2f, 0.00000000e+0f } }, +}; + +void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, + const al::span chans_per_order) +{ + /* NFC is only used when AvgSpeakerDist is greater than 0. */ + const char *devname{device->DeviceName.c_str()}; + if(!GetConfigValueBool(devname, "decoder", "nfc", 0) || !(ctrl_dist > 0.0f)) + return; + + device->AvgSpeakerDist = clampf(ctrl_dist, 0.1f, 10.0f); + TRACE("Using near-field reference distance: %.2f meters\n", device->AvgSpeakerDist); + + auto iter = std::copy(chans_per_order.begin(), chans_per_order.begin()+order+1, + std::begin(device->NumChannelsPerOrder)); + std::fill(iter, std::end(device->NumChannelsPerOrder), 0u); +} + +void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) +{ + auto get_max = std::bind(maxf, _1, + std::bind(std::mem_fn(&AmbDecConf::SpeakerConf::Distance), _2)); + const ALfloat maxdist{ + std::accumulate(conf->Speakers.begin(), conf->Speakers.end(), float{0.0f}, get_max)}; + + const char *devname{device->DeviceName.c_str()}; + if(!GetConfigValueBool(devname, "decoder", "distance-comp", 1) || !(maxdist > 0.0f)) + return; + + const auto distSampleScale = static_cast(device->Frequency)/SPEEDOFSOUNDMETRESPERSEC; + const auto ChanDelay = device->ChannelDelay.as_span(); + size_t total{0u}; + for(size_t i{0u};i < conf->Speakers.size();i++) + { + const AmbDecConf::SpeakerConf &speaker = conf->Speakers[i]; + const ALsizei chan{speakermap[i]}; + + /* Distance compensation only delays in steps of the sample rate. This + * is a bit less accurate since the delay time falls to the nearest + * sample time, but it's far simpler as it doesn't have to deal with + * phase offsets. This means at 48khz, for instance, the distance delay + * will be in steps of about 7 millimeters. + */ + ALfloat delay{std::floor((maxdist - speaker.Distance)*distSampleScale + 0.5f)}; + if(delay > ALfloat{MAX_DELAY_LENGTH-1}) + { + ERR("Delay for speaker \"%s\" exceeds buffer length (%f > %d)\n", + speaker.Name.c_str(), delay, MAX_DELAY_LENGTH-1); + delay = ALfloat{MAX_DELAY_LENGTH-1}; + } + + ChanDelay[chan].Length = static_cast(delay); + ChanDelay[chan].Gain = speaker.Distance / maxdist; + TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan, + speaker.Name.c_str(), ChanDelay[chan].Length, ChanDelay[chan].Gain); + + /* Round up to the next 4th sample, so each channel buffer starts + * 16-byte aligned. + */ + total += RoundUp(ChanDelay[chan].Length, 4); + } + + if(total > 0) + { + device->ChannelDelay.setSampleCount(total); + ChanDelay[0].Buffer = device->ChannelDelay.getSamples(); + auto set_bufptr = [](const DistanceComp::DistData &last, const DistanceComp::DistData &cur) -> DistanceComp::DistData + { + DistanceComp::DistData ret{cur}; + ret.Buffer = last.Buffer + RoundUp(last.Length, 4); + return ret; + }; + std::partial_sum(ChanDelay.begin(), ChanDelay.end(), ChanDelay.begin(), set_bufptr); + } +} + + +auto GetAmbiScales(AmbiNorm scaletype) noexcept -> const std::array& +{ + if(scaletype == AmbiNorm::FuMa) return AmbiScale::FromFuMa; + if(scaletype == AmbiNorm::SN3D) return AmbiScale::FromSN3D; + return AmbiScale::FromN3D; +} + +auto GetAmbiLayout(AmbiLayout layouttype) noexcept -> const std::array& +{ + if(layouttype == AmbiLayout::FuMa) return AmbiIndex::FromFuMa; + return AmbiIndex::FromACN; +} + + +void InitPanning(ALCdevice *device) +{ + al::span chanmap; + ALuint coeffcount{}; + + switch(device->FmtChans) + { + case DevFmtMono: + chanmap = MonoCfg; + coeffcount = 1; + break; + + case DevFmtStereo: + chanmap = StereoCfg; + coeffcount = 3; + break; + + case DevFmtQuad: + chanmap = QuadCfg; + coeffcount = 3; + break; + + case DevFmtX51: + chanmap = X51SideCfg; + coeffcount = 5; + break; + + case DevFmtX51Rear: + chanmap = X51RearCfg; + coeffcount = 5; + break; + + case DevFmtX61: + chanmap = X61Cfg; + coeffcount = 5; + break; + + case DevFmtX71: + chanmap = X71Cfg; + coeffcount = 7; + break; + + case DevFmtAmbi3D: + break; + } + + if(device->FmtChans == DevFmtAmbi3D) + { + const char *devname{device->DeviceName.c_str()}; + const std::array &acnmap = GetAmbiLayout(device->mAmbiLayout); + const std::array &n3dscale = GetAmbiScales(device->mAmbiScale); + + /* For DevFmtAmbi3D, the ambisonic order is already set. */ + const size_t count{AmbiChannelsFromOrder(device->mAmbiOrder)}; + std::transform(acnmap.begin(), acnmap.begin()+count, std::begin(device->Dry.AmbiMap), + [&n3dscale](const ALsizei &acn) noexcept -> BFChannelConfig + { return BFChannelConfig{1.0f/n3dscale[acn], acn}; } + ); + AllocChannels(device, static_cast(count), 0); + + ALfloat nfc_delay{ConfigValueFloat(devname, "decoder", "nfc-ref-delay").value_or(0.0f)}; + if(nfc_delay > 0.0f) + { + static constexpr ALuint chans_per_order[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; + InitNearFieldCtrl(device, nfc_delay * SPEEDOFSOUNDMETRESPERSEC, device->mAmbiOrder, + chans_per_order); + } + } + else + { + ChannelDec chancoeffs[MAX_OUTPUT_CHANNELS]{}; + ALsizei idxmap[MAX_OUTPUT_CHANNELS]{}; + for(size_t i{0u};i < chanmap.size();++i) + { + const ALint idx{GetChannelIdxByName(device->RealOut, chanmap[i].ChanName)}; + if(idx < 0) + { + ERR("Failed to find %s channel in device\n", + GetLabelFromChannel(chanmap[i].ChanName)); + continue; + } + idxmap[i] = idx; + std::copy_n(chanmap[i].Config, coeffcount, chancoeffs[i]); + } + + /* For non-DevFmtAmbi3D, set the ambisonic order given the mixing + * channel count. Built-in speaker decoders are always 2D, so just + * reverse that calculation. + */ + device->mAmbiOrder = static_cast((coeffcount-1) / 2); + + std::transform(AmbiIndex::From2D.begin(), AmbiIndex::From2D.begin()+coeffcount, + std::begin(device->Dry.AmbiMap), + [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } + ); + AllocChannels(device, coeffcount, device->channelsFromFmt()); + + TRACE("Enabling %s-order%s ambisonic decoder\n", + (coeffcount > 5) ? "third" : + (coeffcount > 3) ? "second" : "first", + "" + ); + device->AmbiDecoder = al::make_unique(coeffcount, + static_cast(chanmap.size()), chancoeffs, idxmap); + } +} + +void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) +{ + static constexpr ALuint chans_per_order2d[MAX_AMBI_ORDER+1] = { 1, 2, 2, 2 }; + static constexpr ALuint chans_per_order3d[MAX_AMBI_ORDER+1] = { 1, 3, 5, 7 }; + + if(!hqdec && conf->FreqBands != 1) + ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n", + conf->XOverFreq); + + ALsizei order{(conf->ChanMask > AMBI_2ORDER_MASK) ? 3 : + (conf->ChanMask > AMBI_1ORDER_MASK) ? 2 : 1}; + device->mAmbiOrder = order; + + ALuint count; + if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) + { + count = static_cast(AmbiChannelsFromOrder(order)); + std::transform(AmbiIndex::From3D.begin(), AmbiIndex::From3D.begin()+count, + std::begin(device->Dry.AmbiMap), + [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } + ); + } + else + { + count = static_cast(Ambi2DChannelsFromOrder(order)); + std::transform(AmbiIndex::From2D.begin(), AmbiIndex::From2D.begin()+count, + std::begin(device->Dry.AmbiMap), + [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } + ); + } + AllocChannels(device, count, device->channelsFromFmt()); + + TRACE("Enabling %s-band %s-order%s ambisonic decoder\n", + (!hqdec || conf->FreqBands == 1) ? "single" : "dual", + (conf->ChanMask > AMBI_2ORDER_MASK) ? "third" : + (conf->ChanMask > AMBI_1ORDER_MASK) ? "second" : "first", + (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? " periphonic" : "" + ); + device->AmbiDecoder = al::make_unique(conf, hqdec, count, device->Frequency, + speakermap); + + auto accum_spkr_dist = std::bind(std::plus{}, _1, + std::bind(std::mem_fn(&AmbDecConf::SpeakerConf::Distance), _2)); + const ALfloat avg_dist{ + std::accumulate(conf->Speakers.begin(), conf->Speakers.end(), float{0.0f}, + accum_spkr_dist) / static_cast(conf->Speakers.size()) + }; + InitNearFieldCtrl(device, avg_dist, order, + (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? chans_per_order3d : chans_per_order2d); + + InitDistanceComp(device, conf, speakermap); +} + +void InitHrtfPanning(ALCdevice *device) +{ + /* NOTE: In degrees, and azimuth goes clockwise. */ + static constexpr AngularPoint AmbiPoints[]{ + { 35.264390f, -45.000000f }, + { 35.264390f, 45.000000f }, + { 35.264390f, 135.000000f }, + { 35.264390f, -135.000000f }, + { -35.264390f, -45.000000f }, + { -35.264390f, 45.000000f }, + { -35.264390f, 135.000000f }, + { -35.264390f, -135.000000f }, + { 0.000000f, -20.905157f }, + { 0.000000f, 20.905157f }, + { 0.000000f, 159.094843f }, + { 0.000000f, -159.094843f }, + { 20.905157f, -90.000000f }, + { -20.905157f, -90.000000f }, + { -20.905157f, 90.000000f }, + { 20.905157f, 90.000000f }, + { 69.094843f, 0.000000f }, + { -69.094843f, 0.000000f }, + { -69.094843f, 180.000000f }, + { 69.094843f, 180.000000f }, + }; + static constexpr ALfloat AmbiMatrix[][MAX_AMBI_CHANNELS]{ + { 5.00000000e-02f, 5.00000000e-02f, 5.00000000e-02f, 5.00000000e-02f, 6.45497224e-02f, 6.45497224e-02f, 0.00000000e+00f, 6.45497224e-02f, 0.00000000e+00f, 1.48264644e-02f, 6.33865691e-02f, 1.01126676e-01f, -7.36485380e-02f, -1.09260065e-02f, 7.08683387e-02f, -1.01622099e-01f }, + { 5.00000000e-02f, -5.00000000e-02f, 5.00000000e-02f, 5.00000000e-02f, -6.45497224e-02f, -6.45497224e-02f, 0.00000000e+00f, 6.45497224e-02f, 0.00000000e+00f, -1.48264644e-02f, -6.33865691e-02f, -1.01126676e-01f, -7.36485380e-02f, -1.09260065e-02f, 7.08683387e-02f, -1.01622099e-01f }, + { 5.00000000e-02f, -5.00000000e-02f, 5.00000000e-02f, -5.00000000e-02f, 6.45497224e-02f, -6.45497224e-02f, 0.00000000e+00f, -6.45497224e-02f, 0.00000000e+00f, -1.48264644e-02f, 6.33865691e-02f, -1.01126676e-01f, -7.36485380e-02f, 1.09260065e-02f, 7.08683387e-02f, 1.01622099e-01f }, + { 5.00000000e-02f, 5.00000000e-02f, 5.00000000e-02f, -5.00000000e-02f, -6.45497224e-02f, 6.45497224e-02f, 0.00000000e+00f, -6.45497224e-02f, 0.00000000e+00f, 1.48264644e-02f, -6.33865691e-02f, 1.01126676e-01f, -7.36485380e-02f, 1.09260065e-02f, 7.08683387e-02f, 1.01622099e-01f }, + { 5.00000000e-02f, 5.00000000e-02f, -5.00000000e-02f, 5.00000000e-02f, 6.45497224e-02f, -6.45497224e-02f, 0.00000000e+00f, -6.45497224e-02f, 0.00000000e+00f, 1.48264644e-02f, -6.33865691e-02f, 1.01126676e-01f, 7.36485380e-02f, -1.09260065e-02f, -7.08683387e-02f, -1.01622099e-01f }, + { 5.00000000e-02f, -5.00000000e-02f, -5.00000000e-02f, 5.00000000e-02f, -6.45497224e-02f, 6.45497224e-02f, 0.00000000e+00f, -6.45497224e-02f, 0.00000000e+00f, -1.48264644e-02f, 6.33865691e-02f, -1.01126676e-01f, 7.36485380e-02f, -1.09260065e-02f, -7.08683387e-02f, -1.01622099e-01f }, + { 5.00000000e-02f, -5.00000000e-02f, -5.00000000e-02f, -5.00000000e-02f, 6.45497224e-02f, 6.45497224e-02f, 0.00000000e+00f, 6.45497224e-02f, 0.00000000e+00f, -1.48264644e-02f, -6.33865691e-02f, -1.01126676e-01f, 7.36485380e-02f, 1.09260065e-02f, -7.08683387e-02f, 1.01622099e-01f }, + { 5.00000000e-02f, 5.00000000e-02f, -5.00000000e-02f, -5.00000000e-02f, -6.45497224e-02f, -6.45497224e-02f, 0.00000000e+00f, 6.45497224e-02f, 0.00000000e+00f, 1.48264644e-02f, 6.33865691e-02f, 1.01126676e-01f, 7.36485380e-02f, 1.09260065e-02f, -7.08683387e-02f, 1.01622099e-01f }, + { 5.00000000e-02f, 3.09016994e-02f, 0.00000000e+00f, 8.09016994e-02f, 6.45497224e-02f, 0.00000000e+00f, -5.59016994e-02f, 0.00000000e+00f, 7.21687836e-02f, 7.76323754e-02f, 0.00000000e+00f, -1.49775925e-01f, 0.00000000e+00f, -2.95083663e-02f, 0.00000000e+00f, 7.76323754e-02f }, + { 5.00000000e-02f, -3.09016994e-02f, 0.00000000e+00f, 8.09016994e-02f, -6.45497224e-02f, 0.00000000e+00f, -5.59016994e-02f, 0.00000000e+00f, 7.21687836e-02f, -7.76323754e-02f, 0.00000000e+00f, 1.49775925e-01f, 0.00000000e+00f, -2.95083663e-02f, 0.00000000e+00f, 7.76323754e-02f }, + { 5.00000000e-02f, -3.09016994e-02f, 0.00000000e+00f, -8.09016994e-02f, 6.45497224e-02f, 0.00000000e+00f, -5.59016994e-02f, 0.00000000e+00f, 7.21687836e-02f, -7.76323754e-02f, 0.00000000e+00f, 1.49775925e-01f, 0.00000000e+00f, 2.95083663e-02f, 0.00000000e+00f, -7.76323754e-02f }, + { 5.00000000e-02f, 3.09016994e-02f, 0.00000000e+00f, -8.09016994e-02f, -6.45497224e-02f, 0.00000000e+00f, -5.59016994e-02f, 0.00000000e+00f, 7.21687836e-02f, 7.76323754e-02f, 0.00000000e+00f, -1.49775925e-01f, 0.00000000e+00f, 2.95083663e-02f, 0.00000000e+00f, -7.76323754e-02f }, + { 5.00000000e-02f, 8.09016994e-02f, 3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 6.45497224e-02f, -3.45491503e-02f, 0.00000000e+00f, -8.44966837e-02f, -4.79794466e-02f, 0.00000000e+00f, -6.77901327e-02f, 3.03448665e-02f, 0.00000000e+00f, -1.65948192e-01f, 0.00000000e+00f }, + { 5.00000000e-02f, 8.09016994e-02f, -3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, -6.45497224e-02f, -3.45491503e-02f, 0.00000000e+00f, -8.44966837e-02f, -4.79794466e-02f, 0.00000000e+00f, -6.77901327e-02f, -3.03448665e-02f, 0.00000000e+00f, 1.65948192e-01f, 0.00000000e+00f }, + { 5.00000000e-02f, -8.09016994e-02f, -3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 6.45497224e-02f, -3.45491503e-02f, 0.00000000e+00f, -8.44966837e-02f, 4.79794466e-02f, 0.00000000e+00f, 6.77901327e-02f, -3.03448665e-02f, 0.00000000e+00f, 1.65948192e-01f, 0.00000000e+00f }, + { 5.00000000e-02f, -8.09016994e-02f, 3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, -6.45497224e-02f, -3.45491503e-02f, 0.00000000e+00f, -8.44966837e-02f, 4.79794466e-02f, 0.00000000e+00f, 6.77901327e-02f, 3.03448665e-02f, 0.00000000e+00f, -1.65948192e-01f, 0.00000000e+00f }, + { 5.00000000e-02f, 0.00000000e+00f, 8.09016994e-02f, 3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 9.04508497e-02f, 6.45497224e-02f, 1.23279000e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 7.94438918e-02f, 1.12611206e-01f, -2.42115150e-02f, 1.25611822e-01f }, + { 5.00000000e-02f, 0.00000000e+00f, -8.09016994e-02f, 3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 9.04508497e-02f, -6.45497224e-02f, 1.23279000e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -7.94438918e-02f, 1.12611206e-01f, 2.42115150e-02f, 1.25611822e-01f }, + { 5.00000000e-02f, 0.00000000e+00f, -8.09016994e-02f, -3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 9.04508497e-02f, 6.45497224e-02f, 1.23279000e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -7.94438918e-02f, -1.12611206e-01f, 2.42115150e-02f, -1.25611822e-01f }, + { 5.00000000e-02f, 0.00000000e+00f, 8.09016994e-02f, -3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 9.04508497e-02f, -6.45497224e-02f, 1.23279000e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 7.94438918e-02f, -1.12611206e-01f, -2.42115150e-02f, -1.25611822e-01f } + }; + static constexpr ALfloat AmbiOrderHFGain1O[MAX_AMBI_ORDER+1]{ + 3.16227766e+00f, 1.82574186e+00f + }, AmbiOrderHFGain2O[MAX_AMBI_ORDER+1]{ + 2.35702260e+00f, 1.82574186e+00f, 9.42809042e-01f + }, AmbiOrderHFGain3O[MAX_AMBI_ORDER+1]{ + 1.86508671e+00f, 1.60609389e+00f, 1.14205530e+00f, 5.68379553e-01f + }; + static constexpr ALuint ChansPerOrder[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; + const ALfloat *AmbiOrderHFGain{AmbiOrderHFGain1O}; + + static_assert(al::size(AmbiPoints) == al::size(AmbiMatrix), "Ambisonic HRTF mismatch"); + + /* Don't bother with HOA when using full HRTF rendering. Nothing needs it, + * and it eases the CPU/memory load. + */ + device->mRenderMode = HrtfRender; + ALsizei ambi_order{1}; + if(auto modeopt = ConfigValueStr(device->DeviceName.c_str(), nullptr, "hrtf-mode")) + { + const char *mode{modeopt->c_str()}; + if(strcasecmp(mode, "basic") == 0) + { + ERR("HRTF mode \"%s\" deprecated, substituting \"%s\"\n", mode, "ambi2"); + mode = "ambi2"; + } + + if(strcasecmp(mode, "full") == 0) + device->mRenderMode = HrtfRender; + else if(strcasecmp(mode, "ambi1") == 0) + { + device->mRenderMode = NormalRender; + ambi_order = 1; + } + else if(strcasecmp(mode, "ambi2") == 0) + { + device->mRenderMode = NormalRender; + ambi_order = 2; + } + else if(strcasecmp(mode, "ambi3") == 0) + { + device->mRenderMode = NormalRender; + ambi_order = 3; + } + else + ERR("Unexpected hrtf-mode: %s\n", mode); + } + TRACE("%s HRTF rendering enabled, using \"%s\"\n", + (device->mRenderMode == HrtfRender) ? "Full" : + (ambi_order >= 3) ? "Third-Order" : + (ambi_order == 2) ? "Second-Order" : + (ambi_order == 1) ? "First-Order" : "Unknown", + device->HrtfName.c_str()); + + if(ambi_order >= 3) + AmbiOrderHFGain = AmbiOrderHFGain3O; + else if(ambi_order == 2) + AmbiOrderHFGain = AmbiOrderHFGain2O; + else if(ambi_order == 1) + AmbiOrderHFGain = AmbiOrderHFGain1O; + device->mAmbiOrder = ambi_order; + + const size_t count{AmbiChannelsFromOrder(ambi_order)}; + device->mHrtfState = DirectHrtfState::Create(count); + + std::transform(AmbiIndex::From3D.begin(), AmbiIndex::From3D.begin()+count, + std::begin(device->Dry.AmbiMap), + [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } + ); + AllocChannels(device, static_cast(count), device->channelsFromFmt()); + + BuildBFormatHrtf(device->mHrtf, device->mHrtfState.get(), static_cast(count), + AmbiPoints, AmbiMatrix, al::size(AmbiPoints), AmbiOrderHFGain); + + HrtfEntry *Hrtf{device->mHrtf}; + InitNearFieldCtrl(device, Hrtf->field[0].distance, ambi_order, ChansPerOrder); +} + +void InitUhjPanning(ALCdevice *device) +{ + /* UHJ is always 2D first-order. */ + static constexpr size_t count{Ambi2DChannelsFromOrder(1)}; + + device->mAmbiOrder = 1; + + auto acnmap_end = AmbiIndex::FromFuMa.begin() + count; + std::transform(AmbiIndex::FromFuMa.begin(), acnmap_end, std::begin(device->Dry.AmbiMap), + [](const ALsizei &acn) noexcept -> BFChannelConfig + { return BFChannelConfig{1.0f/AmbiScale::FromFuMa[acn], acn}; } + ); + AllocChannels(device, ALuint{count}, device->channelsFromFmt()); +} + +} // namespace + +void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appreq, HrtfRequestMode hrtf_userreq) +{ + /* Hold the HRTF the device last used, in case it's used again. */ + HrtfEntry *old_hrtf{device->mHrtf}; + + device->mHrtfState = nullptr; + device->mHrtf = nullptr; + device->HrtfName.clear(); + device->mRenderMode = NormalRender; + + if(device->FmtChans != DevFmtStereo) + { + if(old_hrtf) + old_hrtf->DecRef(); + old_hrtf = nullptr; + if(hrtf_appreq == Hrtf_Enable) + device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + + const char *layout{nullptr}; + switch(device->FmtChans) + { + case DevFmtQuad: layout = "quad"; break; + case DevFmtX51: /* fall-through */ + case DevFmtX51Rear: layout = "surround51"; break; + case DevFmtX61: layout = "surround61"; break; + case DevFmtX71: layout = "surround71"; break; + /* Mono, Stereo, and Ambisonics output don't use custom decoders. */ + case DevFmtMono: + case DevFmtStereo: + case DevFmtAmbi3D: + break; + } + + const char *devname{device->DeviceName.c_str()}; + ALsizei speakermap[MAX_OUTPUT_CHANNELS]; + AmbDecConf *pconf{nullptr}; + AmbDecConf conf{}; + if(layout) + { + if(auto decopt = ConfigValueStr(devname, "decoder", layout)) + { + if(!conf.load(decopt->c_str())) + ERR("Failed to load layout file %s\n", decopt->c_str()); + else if(conf.Speakers.size() > MAX_OUTPUT_CHANNELS) + ERR("Unsupported speaker count %zu (max %d)\n", conf.Speakers.size(), + MAX_OUTPUT_CHANNELS); + else if(conf.ChanMask > AMBI_3ORDER_MASK) + ERR("Unsupported channel mask 0x%04x (max 0x%x)\n", conf.ChanMask, + AMBI_3ORDER_MASK); + else if(MakeSpeakerMap(device, &conf, speakermap)) + pconf = &conf; + } + } + + if(!pconf) + InitPanning(device); + else + { + int hqdec{GetConfigValueBool(devname, "decoder", "hq-mode", 0)}; + InitCustomPanning(device, !!hqdec, pconf, speakermap); + } + if(device->AmbiDecoder) + device->PostProcess = ProcessAmbiDec; + return; + } + + bool headphones{device->IsHeadphones != AL_FALSE}; + if(device->Type != Loopback) + { + if(auto modeopt = ConfigValueStr(device->DeviceName.c_str(), nullptr, "stereo-mode")) + { + const char *mode{modeopt->c_str()}; + if(strcasecmp(mode, "headphones") == 0) + headphones = true; + else if(strcasecmp(mode, "speakers") == 0) + headphones = false; + else if(strcasecmp(mode, "auto") != 0) + ERR("Unexpected stereo-mode: %s\n", mode); + } + } + + if(hrtf_userreq == Hrtf_Default) + { + bool usehrtf = (headphones && hrtf_appreq != Hrtf_Disable) || + (hrtf_appreq == Hrtf_Enable); + if(!usehrtf) goto no_hrtf; + + device->HrtfStatus = ALC_HRTF_ENABLED_SOFT; + if(headphones && hrtf_appreq != Hrtf_Disable) + device->HrtfStatus = ALC_HRTF_HEADPHONES_DETECTED_SOFT; + } + else + { + if(hrtf_userreq != Hrtf_Enable) + { + if(hrtf_appreq == Hrtf_Enable) + device->HrtfStatus = ALC_HRTF_DENIED_SOFT; + goto no_hrtf; + } + device->HrtfStatus = ALC_HRTF_REQUIRED_SOFT; + } + + if(device->HrtfList.empty()) + device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); + + if(hrtf_id >= 0 && static_cast(hrtf_id) < device->HrtfList.size()) + { + const EnumeratedHrtf &entry = device->HrtfList[hrtf_id]; + HrtfEntry *hrtf{GetLoadedHrtf(entry.hrtf)}; + if(hrtf && hrtf->sampleRate == device->Frequency) + { + device->mHrtf = hrtf; + device->HrtfName = entry.name; + } + else if(hrtf) + hrtf->DecRef(); + } + + if(!device->mHrtf) + { + auto find_hrtf = [device](const EnumeratedHrtf &entry) -> bool + { + HrtfEntry *hrtf{GetLoadedHrtf(entry.hrtf)}; + if(!hrtf) return false; + if(hrtf->sampleRate != device->Frequency) + { + hrtf->DecRef(); + return false; + } + device->mHrtf = hrtf; + device->HrtfName = entry.name; + return true; + }; + std::find_if(device->HrtfList.cbegin(), device->HrtfList.cend(), find_hrtf); + } + + if(device->mHrtf) + { + if(old_hrtf) + old_hrtf->DecRef(); + old_hrtf = nullptr; + + InitHrtfPanning(device); + device->PostProcess = ProcessHrtf; + return; + } + device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + +no_hrtf: + if(old_hrtf) + old_hrtf->DecRef(); + old_hrtf = nullptr; + + device->mRenderMode = StereoPair; + + if(device->Type != Loopback) + { + if(auto cflevopt = ConfigValueInt(device->DeviceName.c_str(), nullptr, "cf_level")) + { + if(*cflevopt > 0 && *cflevopt <= 6) + { + device->Bs2b = al::make_unique(); + bs2b_set_params(device->Bs2b.get(), *cflevopt, device->Frequency); + TRACE("BS2B enabled\n"); + InitPanning(device); + device->PostProcess = ProcessBs2b; + return; + } + } + } + + if(auto encopt = ConfigValueStr(device->DeviceName.c_str(), nullptr, "stereo-encoding")) + { + const char *mode{encopt->c_str()}; + if(strcasecmp(mode, "uhj") == 0) + device->mRenderMode = NormalRender; + else if(strcasecmp(mode, "panpot") != 0) + ERR("Unexpected stereo-encoding: %s\n", mode); + } + if(device->mRenderMode == NormalRender) + { + device->Uhj_Encoder = al::make_unique(); + TRACE("UHJ enabled\n"); + InitUhjPanning(device); + device->PostProcess = ProcessUhj; + return; + } + + TRACE("Stereo rendering\n"); + InitPanning(device); + device->PostProcess = ProcessAmbiDec; +} + + +void aluInitEffectPanning(ALeffectslot *slot, ALCdevice *device) +{ + const size_t count{AmbiChannelsFromOrder(device->mAmbiOrder)}; + slot->MixBuffer.resize(count); + slot->MixBuffer.shrink_to_fit(); + + auto acnmap_end = AmbiIndex::From3D.begin() + count; + auto iter = std::transform(AmbiIndex::From3D.begin(), acnmap_end, slot->Wet.AmbiMap.begin(), + [](const ALsizei &acn) noexcept -> BFChannelConfig + { return BFChannelConfig{1.0f, acn}; } + ); + std::fill(iter, slot->Wet.AmbiMap.end(), BFChannelConfig{}); + slot->Wet.Buffer = {slot->MixBuffer.data(), slot->MixBuffer.size()}; +} + + +void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread, + ALfloat (&coeffs)[MAX_AMBI_CHANNELS]) +{ + /* Zeroth-order */ + coeffs[0] = 1.0f; /* ACN 0 = 1 */ + /* First-order */ + coeffs[1] = 1.732050808f * y; /* ACN 1 = sqrt(3) * Y */ + coeffs[2] = 1.732050808f * z; /* ACN 2 = sqrt(3) * Z */ + coeffs[3] = 1.732050808f * x; /* ACN 3 = sqrt(3) * X */ + /* Second-order */ + coeffs[4] = 3.872983346f * x * y; /* ACN 4 = sqrt(15) * X * Y */ + coeffs[5] = 3.872983346f * y * z; /* ACN 5 = sqrt(15) * Y * Z */ + coeffs[6] = 1.118033989f * (z*z*3.0f - 1.0f); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */ + coeffs[7] = 3.872983346f * x * z; /* ACN 7 = sqrt(15) * X * Z */ + coeffs[8] = 1.936491673f * (x*x - y*y); /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */ + /* Third-order */ + coeffs[9] = 2.091650066f * y * (x*x*3.0f - y*y); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */ + coeffs[10] = 10.246950766f * z * x * y; /* ACN 10 = sqrt(105) * Z * X * Y */ + coeffs[11] = 1.620185175f * y * (z*z*5.0f - 1.0f); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */ + coeffs[12] = 1.322875656f * z * (z*z*5.0f - 3.0f); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */ + coeffs[13] = 1.620185175f * x * (z*z*5.0f - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */ + coeffs[14] = 5.123475383f * z * (x*x - y*y); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */ + coeffs[15] = 2.091650066f * x * (x*x - y*y*3.0f); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */ + /* Fourth-order */ + /* ACN 16 = sqrt(35)*3/2 * X * Y * (X*X - Y*Y) */ + /* ACN 17 = sqrt(35/2)*3/2 * (3*X*X - Y*Y) * Y * Z */ + /* ACN 18 = sqrt(5)*3/2 * X * Y * (7*Z*Z - 1) */ + /* ACN 19 = sqrt(5/2)*3/2 * Y * Z * (7*Z*Z - 3) */ + /* ACN 20 = 3/8 * (35*Z*Z*Z*Z - 30*Z*Z + 3) */ + /* ACN 21 = sqrt(5/2)*3/2 * X * Z * (7*Z*Z - 3) */ + /* ACN 22 = sqrt(5)*3/4 * (X*X - Y*Y) * (7*Z*Z - 1) */ + /* ACN 23 = sqrt(35/2)*3/2 * (X*X - 3*Y*Y) * X * Z */ + /* ACN 24 = sqrt(35)*3/8 * (X*X*X*X - 6*X*X*Y*Y + Y*Y*Y*Y) */ + + if(spread > 0.0f) + { + /* Implement the spread by using a spherical source that subtends the + * angle spread. See: + * http://www.ppsloan.org/publications/StupidSH36.pdf - Appendix A3 + * + * When adjusted for N3D normalization instead of SN3D, these + * calculations are: + * + * ZH0 = -sqrt(pi) * (-1+ca); + * ZH1 = 0.5*sqrt(pi) * sa*sa; + * ZH2 = -0.5*sqrt(pi) * ca*(-1+ca)*(ca+1); + * ZH3 = -0.125*sqrt(pi) * (-1+ca)*(ca+1)*(5*ca*ca - 1); + * ZH4 = -0.125*sqrt(pi) * ca*(-1+ca)*(ca+1)*(7*ca*ca - 3); + * ZH5 = -0.0625*sqrt(pi) * (-1+ca)*(ca+1)*(21*ca*ca*ca*ca - 14*ca*ca + 1); + * + * The gain of the source is compensated for size, so that the + * loudness doesn't depend on the spread. Thus: + * + * ZH0 = 1.0f; + * ZH1 = 0.5f * (ca+1.0f); + * ZH2 = 0.5f * (ca+1.0f)*ca; + * ZH3 = 0.125f * (ca+1.0f)*(5.0f*ca*ca - 1.0f); + * ZH4 = 0.125f * (ca+1.0f)*(7.0f*ca*ca - 3.0f)*ca; + * ZH5 = 0.0625f * (ca+1.0f)*(21.0f*ca*ca*ca*ca - 14.0f*ca*ca + 1.0f); + */ + ALfloat ca = std::cos(spread * 0.5f); + /* Increase the source volume by up to +3dB for a full spread. */ + ALfloat scale = std::sqrt(1.0f + spread/al::MathDefs::Tau()); + + ALfloat ZH0_norm = scale; + ALfloat ZH1_norm = 0.5f * (ca+1.f) * scale; + ALfloat ZH2_norm = 0.5f * (ca+1.f)*ca * scale; + ALfloat ZH3_norm = 0.125f * (ca+1.f)*(5.f*ca*ca-1.f) * scale; + + /* Zeroth-order */ + coeffs[0] *= ZH0_norm; + /* First-order */ + coeffs[1] *= ZH1_norm; + coeffs[2] *= ZH1_norm; + coeffs[3] *= ZH1_norm; + /* Second-order */ + coeffs[4] *= ZH2_norm; + coeffs[5] *= ZH2_norm; + coeffs[6] *= ZH2_norm; + coeffs[7] *= ZH2_norm; + coeffs[8] *= ZH2_norm; + /* Third-order */ + coeffs[9] *= ZH3_norm; + coeffs[10] *= ZH3_norm; + coeffs[11] *= ZH3_norm; + coeffs[12] *= ZH3_norm; + coeffs[13] *= ZH3_norm; + coeffs[14] *= ZH3_norm; + coeffs[15] *= ZH3_norm; + } +} + +void ComputePanGains(const MixParams *mix, const ALfloat *RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) +{ + auto ambimap = mix->AmbiMap.cbegin(); + + auto iter = std::transform(ambimap, ambimap+mix->Buffer.size(), std::begin(gains), + [coeffs,ingain](const BFChannelConfig &chanmap) noexcept -> ALfloat + { + ASSUME(chanmap.Index >= 0); + return chanmap.Scale * coeffs[chanmap.Index] * ingain; + } + ); + std::fill(iter, std::end(gains), 0.0f); +} diff --git a/alc/ringbuffer.cpp b/alc/ringbuffer.cpp new file mode 100644 index 00000000..6ef576a5 --- /dev/null +++ b/alc/ringbuffer.cpp @@ -0,0 +1,253 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include + +#include "ringbuffer.h" +#include "atomic.h" +#include "threads.h" +#include "almalloc.h" +#include "compat.h" + + +RingBufferPtr CreateRingBuffer(size_t sz, size_t elem_sz, int limit_writes) +{ + size_t power_of_two{0u}; + if(sz > 0) + { + power_of_two = sz; + power_of_two |= power_of_two>>1; + power_of_two |= power_of_two>>2; + power_of_two |= power_of_two>>4; + power_of_two |= power_of_two>>8; + power_of_two |= power_of_two>>16; +#if SIZE_MAX > UINT_MAX + power_of_two |= power_of_two>>32; +#endif + } + ++power_of_two; + if(power_of_two < sz) return nullptr; + + const size_t bufbytes{power_of_two * elem_sz}; + RingBufferPtr rb{new (al_calloc(16, sizeof(*rb) + bufbytes)) RingBuffer{bufbytes}}; + rb->mWriteSize = limit_writes ? sz : (power_of_two-1); + rb->mSizeMask = power_of_two - 1; + rb->mElemSize = elem_sz; + + return rb; +} + +void RingBuffer::reset() noexcept +{ + mWritePtr.store(0, std::memory_order_relaxed); + mReadPtr.store(0, std::memory_order_relaxed); + std::fill_n(mBuffer.begin(), (mSizeMask+1)*mElemSize, al::byte{}); +} + + +size_t RingBuffer::readSpace() const noexcept +{ + size_t w = mWritePtr.load(std::memory_order_acquire); + size_t r = mReadPtr.load(std::memory_order_acquire); + return (w-r) & mSizeMask; +} + +size_t RingBuffer::writeSpace() const noexcept +{ + size_t w = mWritePtr.load(std::memory_order_acquire); + size_t r = mReadPtr.load(std::memory_order_acquire) + mWriteSize - mSizeMask; + return (r-w-1) & mSizeMask; +} + + +size_t RingBuffer::read(void *dest, size_t cnt) noexcept +{ + const size_t free_cnt{readSpace()}; + if(free_cnt == 0) return 0; + + const size_t to_read{std::min(cnt, free_cnt)}; + size_t read_ptr{mReadPtr.load(std::memory_order_relaxed) & mSizeMask}; + + size_t n1, n2; + const size_t cnt2{read_ptr + to_read}; + if(cnt2 > mSizeMask+1) + { + n1 = mSizeMask+1 - read_ptr; + n2 = cnt2 & mSizeMask; + } + else + { + n1 = to_read; + n2 = 0; + } + + auto outiter = std::copy_n(mBuffer.begin() + read_ptr*mElemSize, n1*mElemSize, + static_cast(dest)); + read_ptr += n1; + if(n2 > 0) + { + std::copy_n(mBuffer.begin(), n2*mElemSize, outiter); + read_ptr += n2; + } + mReadPtr.store(read_ptr, std::memory_order_release); + return to_read; +} + +size_t RingBuffer::peek(void *dest, size_t cnt) const noexcept +{ + const size_t free_cnt{readSpace()}; + if(free_cnt == 0) return 0; + + const size_t to_read{std::min(cnt, free_cnt)}; + size_t read_ptr{mReadPtr.load(std::memory_order_relaxed) & mSizeMask}; + + size_t n1, n2; + const size_t cnt2{read_ptr + to_read}; + if(cnt2 > mSizeMask+1) + { + n1 = mSizeMask+1 - read_ptr; + n2 = cnt2 & mSizeMask; + } + else + { + n1 = to_read; + n2 = 0; + } + + auto outiter = std::copy_n(mBuffer.begin() + read_ptr*mElemSize, n1*mElemSize, + static_cast(dest)); + if(n2 > 0) + std::copy_n(mBuffer.begin(), n2*mElemSize, outiter); + return to_read; +} + +size_t RingBuffer::write(const void *src, size_t cnt) noexcept +{ + const size_t free_cnt{writeSpace()}; + if(free_cnt == 0) return 0; + + const size_t to_write{std::min(cnt, free_cnt)}; + size_t write_ptr{mWritePtr.load(std::memory_order_relaxed) & mSizeMask}; + + size_t n1, n2; + const size_t cnt2{write_ptr + to_write}; + if(cnt2 > mSizeMask+1) + { + n1 = mSizeMask+1 - write_ptr; + n2 = cnt2 & mSizeMask; + } + else + { + n1 = to_write; + n2 = 0; + } + + auto srcbytes = static_cast(src); + std::copy_n(srcbytes, n1*mElemSize, mBuffer.begin() + write_ptr*mElemSize); + write_ptr += n1; + if(n2 > 0) + { + std::copy_n(srcbytes + n1*mElemSize, n2*mElemSize, mBuffer.begin()); + write_ptr += n2; + } + mWritePtr.store(write_ptr, std::memory_order_release); + return to_write; +} + + +void RingBuffer::readAdvance(size_t cnt) noexcept +{ + mReadPtr.fetch_add(cnt, std::memory_order_acq_rel); +} + +void RingBuffer::writeAdvance(size_t cnt) noexcept +{ + mWritePtr.fetch_add(cnt, std::memory_order_acq_rel); +} + + +ll_ringbuffer_data_pair RingBuffer::getReadVector() const noexcept +{ + ll_ringbuffer_data_pair ret; + + size_t w{mWritePtr.load(std::memory_order_acquire)}; + size_t r{mReadPtr.load(std::memory_order_acquire)}; + w &= mSizeMask; + r &= mSizeMask; + const size_t free_cnt{(w-r) & mSizeMask}; + + const size_t cnt2{r + free_cnt}; + if(cnt2 > mSizeMask+1) + { + /* Two part vector: the rest of the buffer after the current read ptr, + * plus some from the start of the buffer. */ + ret.first.buf = const_cast(mBuffer.data() + r*mElemSize); + ret.first.len = mSizeMask+1 - r; + ret.second.buf = const_cast(mBuffer.data()); + ret.second.len = cnt2 & mSizeMask; + } + else + { + /* Single part vector: just the rest of the buffer */ + ret.first.buf = const_cast(mBuffer.data() + r*mElemSize); + ret.first.len = free_cnt; + ret.second.buf = nullptr; + ret.second.len = 0; + } + + return ret; +} + +ll_ringbuffer_data_pair RingBuffer::getWriteVector() const noexcept +{ + ll_ringbuffer_data_pair ret; + + size_t w{mWritePtr.load(std::memory_order_acquire)}; + size_t r{mReadPtr.load(std::memory_order_acquire) + mWriteSize - mSizeMask}; + w &= mSizeMask; + r &= mSizeMask; + const size_t free_cnt{(r-w-1) & mSizeMask}; + + const size_t cnt2{w + free_cnt}; + if(cnt2 > mSizeMask+1) + { + /* Two part vector: the rest of the buffer after the current write ptr, + * plus some from the start of the buffer. */ + ret.first.buf = const_cast(mBuffer.data() + w*mElemSize); + ret.first.len = mSizeMask+1 - w; + ret.second.buf = const_cast(mBuffer.data()); + ret.second.len = cnt2 & mSizeMask; + } + else + { + ret.first.buf = const_cast(mBuffer.data() + w*mElemSize); + ret.first.len = free_cnt; + ret.second.buf = nullptr; + ret.second.len = 0; + } + + return ret; +} diff --git a/alc/ringbuffer.h b/alc/ringbuffer.h new file mode 100644 index 00000000..84139b66 --- /dev/null +++ b/alc/ringbuffer.h @@ -0,0 +1,99 @@ +#ifndef RINGBUFFER_H +#define RINGBUFFER_H + +#include + +#include +#include +#include + +#include "albyte.h" +#include "almalloc.h" + + +/* NOTE: This lockless ringbuffer implementation is copied from JACK, extended + * to include an element size. Consequently, parameters and return values for a + * size or count is in 'elements', not bytes. Additionally, it only supports + * single-consumer/single-provider operation. + */ + +struct ll_ringbuffer_data { + al::byte *buf; + size_t len; +}; +using ll_ringbuffer_data_pair = std::pair; + + +struct RingBuffer { + std::atomic mWritePtr{0u}; + std::atomic mReadPtr{0u}; + size_t mWriteSize{0u}; + size_t mSizeMask{0u}; + size_t mElemSize{0u}; + + al::FlexArray mBuffer; + + RingBuffer(const size_t count) : mBuffer{count} { } + RingBuffer(const RingBuffer&) = delete; + RingBuffer& operator=(const RingBuffer&) = delete; + + /** Reset the read and write pointers to zero. This is not thread safe. */ + void reset() noexcept; + + /** + * The non-copying data reader. Returns two ringbuffer data pointers that + * hold the current readable data. If the readable data is in one segment + * the second segment has zero length. + */ + ll_ringbuffer_data_pair getReadVector() const noexcept; + /** + * The non-copying data writer. Returns two ringbuffer data pointers that + * hold the current writeable data. If the writeable data is in one segment + * the second segment has zero length. + */ + ll_ringbuffer_data_pair getWriteVector() const noexcept; + + /** + * Return the number of elements available for reading. This is the number + * of elements in front of the read pointer and behind the write pointer. + */ + size_t readSpace() const noexcept; + /** + * The copying data reader. Copy at most `cnt' elements into `dest'. + * Returns the actual number of elements copied. + */ + size_t read(void *dest, size_t cnt) noexcept; + /** + * The copying data reader w/o read pointer advance. Copy at most `cnt' + * elements into `dest'. Returns the actual number of elements copied. + */ + size_t peek(void *dest, size_t cnt) const noexcept; + /** Advance the read pointer `cnt' places. */ + void readAdvance(size_t cnt) noexcept; + + /** + * Return the number of elements available for writing. This is the number + * of elements in front of the write pointer and behind the read pointer. + */ + size_t writeSpace() const noexcept; + /** + * The copying data writer. Copy at most `cnt' elements from `src'. Returns + * the actual number of elements copied. + */ + size_t write(const void *src, size_t cnt) noexcept; + /** Advance the write pointer `cnt' places. */ + void writeAdvance(size_t cnt) noexcept; + + DEF_PLACE_NEWDEL() +}; +using RingBufferPtr = std::unique_ptr; + + +/** + * Create a new ringbuffer to hold at least `sz' elements of `elem_sz' bytes. + * The number of elements is rounded up to the next power of two (even if it is + * already a power of two, to ensure the requested amount can be written). + */ +RingBufferPtr CreateRingBuffer(size_t sz, size_t elem_sz, int limit_writes); + +#endif /* RINGBUFFER_H */ diff --git a/alc/uhjfilter.cpp b/alc/uhjfilter.cpp new file mode 100644 index 00000000..55999647 --- /dev/null +++ b/alc/uhjfilter.cpp @@ -0,0 +1,131 @@ + +#include "config.h" + +#include "uhjfilter.h" + +#include + +#include "alu.h" + +namespace { + +/* This is the maximum number of samples processed for each inner loop + * iteration. */ +#define MAX_UPDATE_SAMPLES 128 + + +constexpr ALfloat Filter1CoeffSqr[4] = { + 0.479400865589f, 0.876218493539f, 0.976597589508f, 0.997499255936f +}; +constexpr ALfloat Filter2CoeffSqr[4] = { + 0.161758498368f, 0.733028932341f, 0.945349700329f, 0.990599156685f +}; + +void allpass_process(AllPassState *state, ALfloat *dst, const ALfloat *src, const ALfloat aa, ALsizei todo) +{ + ALfloat z1{state->z[0]}; + ALfloat z2{state->z[1]}; + auto proc_sample = [aa,&z1,&z2](ALfloat input) noexcept -> ALfloat + { + ALfloat output = input*aa + z1; + z1 = z2; z2 = output*aa - input; + return output; + }; + std::transform(src, src+todo, dst, proc_sample); + state->z[0] = z1; + state->z[1] = z2; +} + +} // namespace + + +/* NOTE: There seems to be a bit of an inconsistency in how this encoding is + * supposed to work. Some references, such as + * + * http://members.tripod.com/martin_leese/Ambisonic/UHJ_file_format.html + * + * specify a pre-scaling of sqrt(2) on the W channel input, while other + * references, such as + * + * https://en.wikipedia.org/wiki/Ambisonic_UHJ_format#Encoding.5B1.5D + * and + * https://wiki.xiph.org/Ambisonics#UHJ_format + * + * do not. The sqrt(2) scaling is in line with B-Format decoder coefficients + * which include such a scaling for the W channel input, however the original + * source for this equation is a 1985 paper by Michael Gerzon, which does not + * apparently include the scaling. Applying the extra scaling creates a louder + * result with a narrower stereo image compared to not scaling, and I don't + * know which is the intended result. + */ + +void Uhj2Encoder::encode(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, FloatBufferLine *InSamples, const ALsizei SamplesToDo) +{ + alignas(16) ALfloat D[MAX_UPDATE_SAMPLES], S[MAX_UPDATE_SAMPLES]; + alignas(16) ALfloat temp[MAX_UPDATE_SAMPLES]; + + ASSUME(SamplesToDo > 0); + + auto winput = InSamples[0].cbegin(); + auto xinput = InSamples[1].cbegin(); + auto yinput = InSamples[2].cbegin(); + for(ALsizei base{0};base < SamplesToDo;) + { + const ALsizei todo{mini(SamplesToDo - base, MAX_UPDATE_SAMPLES)}; + ASSUME(todo > 0); + + /* D = 0.6554516*Y */ + std::transform(yinput, yinput+todo, std::begin(temp), + [](const float y) noexcept -> float { return 0.6554516f*y; }); + allpass_process(&mFilter1_Y[0], temp, temp, Filter1CoeffSqr[0], todo); + allpass_process(&mFilter1_Y[1], temp, temp, Filter1CoeffSqr[1], todo); + allpass_process(&mFilter1_Y[2], temp, temp, Filter1CoeffSqr[2], todo); + allpass_process(&mFilter1_Y[3], temp, temp, Filter1CoeffSqr[3], todo); + /* NOTE: Filter1 requires a 1 sample delay for the final output, so + * take the last processed sample from the previous run as the first + * output sample. + */ + D[0] = mLastY; + for(ALsizei i{1};i < todo;i++) + D[i] = temp[i-1]; + mLastY = temp[todo-1]; + + /* D += j(-0.3420201*W + 0.5098604*X) */ + std::transform(winput, winput+todo, xinput, std::begin(temp), + [](const float w, const float x) noexcept -> float + { return -0.3420201f*w + 0.5098604f*x; }); + allpass_process(&mFilter2_WX[0], temp, temp, Filter2CoeffSqr[0], todo); + allpass_process(&mFilter2_WX[1], temp, temp, Filter2CoeffSqr[1], todo); + allpass_process(&mFilter2_WX[2], temp, temp, Filter2CoeffSqr[2], todo); + allpass_process(&mFilter2_WX[3], temp, temp, Filter2CoeffSqr[3], todo); + for(ALsizei i{0};i < todo;i++) + D[i] += temp[i]; + + /* S = 0.9396926*W + 0.1855740*X */ + std::transform(winput, winput+todo, xinput, std::begin(temp), + [](const float w, const float x) noexcept -> float + { return 0.9396926f*w + 0.1855740f*x; }); + allpass_process(&mFilter1_WX[0], temp, temp, Filter1CoeffSqr[0], todo); + allpass_process(&mFilter1_WX[1], temp, temp, Filter1CoeffSqr[1], todo); + allpass_process(&mFilter1_WX[2], temp, temp, Filter1CoeffSqr[2], todo); + allpass_process(&mFilter1_WX[3], temp, temp, Filter1CoeffSqr[3], todo); + S[0] = mLastWX; + for(ALsizei i{1};i < todo;i++) + S[i] = temp[i-1]; + mLastWX = temp[todo-1]; + + /* Left = (S + D)/2.0 */ + ALfloat *RESTRICT left = al::assume_aligned<16>(LeftOut.data()+base); + for(ALsizei i{0};i < todo;i++) + left[i] += (S[i] + D[i]) * 0.5f; + /* Right = (S - D)/2.0 */ + ALfloat *RESTRICT right = al::assume_aligned<16>(RightOut.data()+base); + for(ALsizei i{0};i < todo;i++) + right[i] += (S[i] - D[i]) * 0.5f; + + winput += todo; + xinput += todo; + yinput += todo; + base += todo; + } +} diff --git a/alc/uhjfilter.h b/alc/uhjfilter.h new file mode 100644 index 00000000..53e4f89e --- /dev/null +++ b/alc/uhjfilter.h @@ -0,0 +1,54 @@ +#ifndef UHJFILTER_H +#define UHJFILTER_H + +#include "AL/al.h" + +#include "alcmain.h" +#include "almalloc.h" + + +struct AllPassState { + ALfloat z[2]{0.0f, 0.0f}; +}; + +/* Encoding 2-channel UHJ from B-Format is done as: + * + * S = 0.9396926*W + 0.1855740*X + * D = j(-0.3420201*W + 0.5098604*X) + 0.6554516*Y + * + * Left = (S + D)/2.0 + * Right = (S - D)/2.0 + * + * where j is a wide-band +90 degree phase shift. + * + * The phase shift is done using a Hilbert transform, described here: + * https://web.archive.org/web/20060708031958/http://www.biochem.oulu.fi/~oniemita/dsp/hilbert/ + * It works using 2 sets of 4 chained filters. The first filter chain produces + * a phase shift of varying magnitude over a wide range of frequencies, while + * the second filter chain produces a phase shift 90 degrees ahead of the + * first over the same range. + * + * Combining these two stages requires the use of three filter chains. S- + * channel output uses a Filter1 chain on the W and X channel mix, while the D- + * channel output uses a Filter1 chain on the Y channel plus a Filter2 chain on + * the W and X channel mix. This results in the W and X input mix on the D- + * channel output having the required +90 degree phase shift relative to the + * other inputs. + */ + +struct Uhj2Encoder { + AllPassState mFilter1_Y[4]; + AllPassState mFilter2_WX[4]; + AllPassState mFilter1_WX[4]; + ALfloat mLastY{0.0f}, mLastWX{0.0f}; + + /* Encodes a 2-channel UHJ (stereo-compatible) signal from a B-Format input + * signal. The input must use FuMa channel ordering and scaling. + */ + void encode(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, FloatBufferLine *InSamples, + const ALsizei SamplesToDo); + + DEF_NEWDEL(Uhj2Encoder) +}; + +#endif /* UHJFILTER_H */ diff --git a/alc/vector.h b/alc/vector.h new file mode 100644 index 00000000..1b69d6a7 --- /dev/null +++ b/alc/vector.h @@ -0,0 +1,15 @@ +#ifndef AL_VECTOR_H +#define AL_VECTOR_H + +#include + +#include "almalloc.h" + +namespace al { + +template +using vector = std::vector>; + +} // namespace al + +#endif /* AL_VECTOR_H */ -- cgit v1.2.3 From 83432a7e5c7f565a08c41bb104ae25286c5fc82b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Jul 2019 19:09:07 -0700 Subject: Move some headers out of the Include subdirectory --- CMakeLists.txt | 16 ++--- OpenAL32/Include/alAuxEffectSlot.h | 100 ----------------------------- OpenAL32/Include/alBuffer.h | 120 ----------------------------------- OpenAL32/Include/alEffect.h | 59 ----------------- OpenAL32/Include/alError.h | 22 ------- OpenAL32/Include/alFilter.h | 56 ---------------- OpenAL32/Include/alListener.h | 59 ----------------- OpenAL32/Include/alSource.h | 127 ------------------------------------- OpenAL32/alAuxEffectSlot.h | 100 +++++++++++++++++++++++++++++ OpenAL32/alBuffer.h | 120 +++++++++++++++++++++++++++++++++++ OpenAL32/alEffect.h | 59 +++++++++++++++++ OpenAL32/alError.h | 22 +++++++ OpenAL32/alFilter.h | 56 ++++++++++++++++ OpenAL32/alListener.h | 59 +++++++++++++++++ OpenAL32/alSource.h | 127 +++++++++++++++++++++++++++++++++++++ 15 files changed, 551 insertions(+), 551 deletions(-) delete mode 100644 OpenAL32/Include/alAuxEffectSlot.h delete mode 100644 OpenAL32/Include/alBuffer.h delete mode 100644 OpenAL32/Include/alEffect.h delete mode 100644 OpenAL32/Include/alError.h delete mode 100644 OpenAL32/Include/alFilter.h delete mode 100644 OpenAL32/Include/alListener.h delete mode 100644 OpenAL32/Include/alSource.h create mode 100644 OpenAL32/alAuxEffectSlot.h create mode 100644 OpenAL32/alBuffer.h create mode 100644 OpenAL32/alEffect.h create mode 100644 OpenAL32/alError.h create mode 100644 OpenAL32/alFilter.h create mode 100644 OpenAL32/alListener.h create mode 100644 OpenAL32/alSource.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 190692c8..65e9ebd6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -619,21 +619,21 @@ SET(COMMON_OBJS common/vecmat.h ) SET(OPENAL_OBJS - OpenAL32/Include/alAuxEffectSlot.h OpenAL32/alAuxEffectSlot.cpp - OpenAL32/Include/alBuffer.h + OpenAL32/alAuxEffectSlot.h OpenAL32/alBuffer.cpp - OpenAL32/Include/alEffect.h + OpenAL32/alBuffer.h OpenAL32/alEffect.cpp - OpenAL32/Include/alError.h + OpenAL32/alEffect.h OpenAL32/alError.cpp + OpenAL32/alError.h OpenAL32/alExtension.cpp - OpenAL32/Include/alFilter.h OpenAL32/alFilter.cpp - OpenAL32/Include/alListener.h + OpenAL32/alFilter.h OpenAL32/alListener.cpp - OpenAL32/Include/alSource.h + OpenAL32/alListener.h OpenAL32/alSource.cpp + OpenAL32/alSource.h OpenAL32/alState.cpp OpenAL32/event.cpp ) @@ -1313,7 +1313,7 @@ TARGET_INCLUDE_DIRECTORIES(${IMPL_TARGET} ${INC_PATHS} ${OpenAL_BINARY_DIR} ${OpenAL_SOURCE_DIR}/alc - ${OpenAL_SOURCE_DIR}/OpenAL32/Include + ${OpenAL_SOURCE_DIR}/OpenAL32 ${OpenAL_SOURCE_DIR}/common ) diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h deleted file mode 100644 index b6976d13..00000000 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef _AL_AUXEFFECTSLOT_H_ -#define _AL_AUXEFFECTSLOT_H_ - -#include - -#include "alcmain.h" -#include "alEffect.h" -#include "ambidefs.h" -#include "effects/base.h" - -#include "almalloc.h" -#include "atomic.h" - - -struct ALeffectslot; - - -using ALeffectslotArray = al::FlexArray; - - -struct ALeffectslotProps { - ALfloat Gain; - ALboolean AuxSendAuto; - ALeffectslot *Target; - - ALenum Type; - EffectProps Props; - - EffectState *State; - - std::atomic next; -}; - - -struct ALeffectslot { - ALfloat Gain{1.0f}; - ALboolean AuxSendAuto{AL_TRUE}; - ALeffectslot *Target{nullptr}; - - struct { - ALenum Type{AL_EFFECT_NULL}; - EffectProps Props{}; - - EffectState *State{nullptr}; - } Effect; - - std::atomic_flag PropsClean; - - RefCount ref{0u}; - - std::atomic Update{nullptr}; - - struct { - ALfloat Gain{1.0f}; - ALboolean AuxSendAuto{AL_TRUE}; - ALeffectslot *Target{nullptr}; - - ALenum EffectType{AL_EFFECT_NULL}; - EffectProps mEffectProps{}; - EffectState *mEffectState{nullptr}; - - ALfloat RoomRolloff{0.0f}; /* Added to the source's room rolloff, not multiplied. */ - ALfloat DecayTime{0.0f}; - ALfloat DecayLFRatio{0.0f}; - ALfloat DecayHFRatio{0.0f}; - ALboolean DecayHFLimit{AL_FALSE}; - ALfloat AirAbsorptionGainHF{1.0f}; - } Params; - - /* Self ID */ - ALuint id{}; - - /* Mixing buffer used by the Wet mix. */ - al::vector MixBuffer; - - /* Wet buffer configuration is ACN channel order with N3D scaling. - * Consequently, effects that only want to work with mono input can use - * channel 0 by itself. Effects that want multichannel can process the - * ambisonics signal and make a B-Format source pan. - */ - MixParams Wet; - - ALeffectslot() { PropsClean.test_and_set(std::memory_order_relaxed); } - ALeffectslot(const ALeffectslot&) = delete; - ALeffectslot& operator=(const ALeffectslot&) = delete; - ~ALeffectslot(); - - static ALeffectslotArray *CreatePtrArray(size_t count) noexcept; - - DEF_PLACE_NEWDEL() -}; - -ALenum InitEffectSlot(ALeffectslot *slot); -void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context); -void UpdateAllEffectSlotProps(ALCcontext *context); - - -ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect); - -#endif diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h deleted file mode 100644 index 92655784..00000000 --- a/OpenAL32/Include/alBuffer.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef _AL_BUFFER_H_ -#define _AL_BUFFER_H_ - -#include "AL/alc.h" -#include "AL/al.h" -#include "AL/alext.h" - -#include "inprogext.h" -#include "atomic.h" -#include "vector.h" -#include "albyte.h" - - -/* User formats */ -enum UserFmtType : unsigned char { - UserFmtUByte, - UserFmtShort, - UserFmtFloat, - UserFmtDouble, - UserFmtMulaw, - UserFmtAlaw, - UserFmtIMA4, - UserFmtMSADPCM, -}; -enum UserFmtChannels : unsigned char { - UserFmtMono, - UserFmtStereo, - UserFmtRear, - UserFmtQuad, - UserFmtX51, /* (WFX order) */ - UserFmtX61, /* (WFX order) */ - UserFmtX71, /* (WFX order) */ - UserFmtBFormat2D, /* WXY */ - UserFmtBFormat3D, /* WXYZ */ -}; - -ALsizei BytesFromUserFmt(UserFmtType type); -ALsizei ChannelsFromUserFmt(UserFmtChannels chans); -inline ALsizei FrameSizeFromUserFmt(UserFmtChannels chans, UserFmtType type) -{ return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type); } - - -/* Storable formats */ -enum FmtType : unsigned char { - FmtUByte = UserFmtUByte, - FmtShort = UserFmtShort, - FmtFloat = UserFmtFloat, - FmtDouble = UserFmtDouble, - FmtMulaw = UserFmtMulaw, - FmtAlaw = UserFmtAlaw, -}; -enum FmtChannels : unsigned char { - FmtMono = UserFmtMono, - FmtStereo = UserFmtStereo, - FmtRear = UserFmtRear, - FmtQuad = UserFmtQuad, - FmtX51 = UserFmtX51, - FmtX61 = UserFmtX61, - FmtX71 = UserFmtX71, - FmtBFormat2D = UserFmtBFormat2D, - FmtBFormat3D = UserFmtBFormat3D, -}; -#define MAX_INPUT_CHANNELS (8) - -/* DevFmtType traits, providing the type, etc given a DevFmtType. */ -template -struct FmtTypeTraits { }; - -template<> -struct FmtTypeTraits { using Type = ALubyte; }; -template<> -struct FmtTypeTraits { using Type = ALshort; }; -template<> -struct FmtTypeTraits { using Type = ALfloat; }; -template<> -struct FmtTypeTraits { using Type = ALdouble; }; -template<> -struct FmtTypeTraits { using Type = ALubyte; }; -template<> -struct FmtTypeTraits { using Type = ALubyte; }; - - -ALsizei BytesFromFmt(FmtType type); -ALsizei ChannelsFromFmt(FmtChannels chans); -inline ALsizei FrameSizeFromFmt(FmtChannels chans, FmtType type) -{ return ChannelsFromFmt(chans) * BytesFromFmt(type); } - - -struct ALbuffer { - al::vector mData; - - ALsizei Frequency{0}; - ALbitfieldSOFT Access{0u}; - ALsizei SampleLen{0}; - - FmtChannels mFmtChannels{}; - FmtType mFmtType{}; - - UserFmtType OriginalType{}; - ALsizei OriginalSize{0}; - ALsizei OriginalAlign{0}; - - ALsizei LoopStart{0}; - ALsizei LoopEnd{0}; - - std::atomic UnpackAlign{0}; - std::atomic PackAlign{0}; - - ALbitfieldSOFT MappedAccess{0u}; - ALsizei MappedOffset{0}; - ALsizei MappedSize{0}; - - /* Number of times buffer was attached to a source (deletion can only occur when 0) */ - RefCount ref{0u}; - - /* Self ID */ - ALuint id{0}; -}; - -#endif diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h deleted file mode 100644 index d43aa206..00000000 --- a/OpenAL32/Include/alEffect.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef _AL_EFFECT_H_ -#define _AL_EFFECT_H_ - -#include "alcmain.h" -#include "effects/base.h" - - -enum { - EAXREVERB_EFFECT = 0, - REVERB_EFFECT, - AUTOWAH_EFFECT, - CHORUS_EFFECT, - COMPRESSOR_EFFECT, - DISTORTION_EFFECT, - ECHO_EFFECT, - EQUALIZER_EFFECT, - FLANGER_EFFECT, - FSHIFTER_EFFECT, - MODULATOR_EFFECT, - PSHIFTER_EFFECT, - VMORPHER_EFFECT, - DEDICATED_EFFECT, - - MAX_EFFECTS -}; -extern ALboolean DisabledEffects[MAX_EFFECTS]; - -extern ALfloat ReverbBoost; - -struct EffectList { - const char name[16]; - int type; - ALenum val; -}; -extern const EffectList gEffectList[15]; - - -struct ALeffect { - // Effect type (AL_EFFECT_NULL, ...) - ALenum type{AL_EFFECT_NULL}; - - EffectProps Props{}; - - const EffectVtable *vtab{nullptr}; - - /* Self ID */ - ALuint id{0u}; -}; - -inline ALboolean IsReverbEffect(ALenum type) -{ return type == AL_EFFECT_REVERB || type == AL_EFFECT_EAXREVERB; } - -EffectStateFactory *getFactoryByType(ALenum type); - -void InitEffect(ALeffect *effect); - -void LoadReverbPreset(const char *name, ALeffect *effect); - -#endif diff --git a/OpenAL32/Include/alError.h b/OpenAL32/Include/alError.h deleted file mode 100644 index 0abd6b26..00000000 --- a/OpenAL32/Include/alError.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _AL_ERROR_H_ -#define _AL_ERROR_H_ - -#include "alcmain.h" -#include "logging.h" - - -extern bool TrapALError; - -void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) DECL_FORMAT(printf, 3, 4); - -#define SETERR_GOTO(ctx, err, lbl, ...) do { \ - alSetError((ctx), (err), __VA_ARGS__); \ - goto lbl; \ -} while(0) - -#define SETERR_RETURN(ctx, err, retval, ...) do { \ - alSetError((ctx), (err), __VA_ARGS__); \ - return retval; \ -} while(0) - -#endif diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h deleted file mode 100644 index 1c033ac3..00000000 --- a/OpenAL32/Include/alFilter.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef _AL_FILTER_H_ -#define _AL_FILTER_H_ - -#include "AL/alc.h" -#include "AL/al.h" - - -#define LOWPASSFREQREF (5000.0f) -#define HIGHPASSFREQREF (250.0f) - - -struct ALfilter; - -struct ALfilterVtable { - void (*const setParami)(ALfilter *filter, ALCcontext *context, ALenum param, ALint val); - void (*const setParamiv)(ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals); - void (*const setParamf)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val); - void (*const setParamfv)(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals); - - void (*const getParami)(ALfilter *filter, ALCcontext *context, ALenum param, ALint *val); - void (*const getParamiv)(ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals); - void (*const getParamf)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val); - void (*const getParamfv)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals); -}; - -#define DEFINE_ALFILTER_VTABLE(T) \ -const ALfilterVtable T##_vtable = { \ - T##_setParami, T##_setParamiv, T##_setParamf, T##_setParamfv, \ - T##_getParami, T##_getParamiv, T##_getParamf, T##_getParamfv, \ -} - -struct ALfilter { - // Filter type (AL_FILTER_NULL, ...) - ALenum type; - - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - - const ALfilterVtable *vtab; - - /* Self ID */ - ALuint id; -}; -#define ALfilter_setParami(o, c, p, v) ((o)->vtab->setParami(o, c, p, v)) -#define ALfilter_setParamf(o, c, p, v) ((o)->vtab->setParamf(o, c, p, v)) -#define ALfilter_setParamiv(o, c, p, v) ((o)->vtab->setParamiv(o, c, p, v)) -#define ALfilter_setParamfv(o, c, p, v) ((o)->vtab->setParamfv(o, c, p, v)) -#define ALfilter_getParami(o, c, p, v) ((o)->vtab->getParami(o, c, p, v)) -#define ALfilter_getParamf(o, c, p, v) ((o)->vtab->getParamf(o, c, p, v)) -#define ALfilter_getParamiv(o, c, p, v) ((o)->vtab->getParamiv(o, c, p, v)) -#define ALfilter_getParamfv(o, c, p, v) ((o)->vtab->getParamfv(o, c, p, v)) - -#endif diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h deleted file mode 100644 index 4d59dbf9..00000000 --- a/OpenAL32/Include/alListener.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef _AL_LISTENER_H_ -#define _AL_LISTENER_H_ - -#include - -#include "AL/alc.h" -#include "AL/al.h" -#include "AL/alext.h" - -#include "atomic.h" -#include "vecmat.h" - -enum class DistanceModel; - - -struct ALlistenerProps { - std::array Position; - std::array Velocity; - std::array OrientAt; - std::array OrientUp; - ALfloat Gain; - - std::atomic next; -}; - -struct ALlistener { - std::array Position{{0.0f, 0.0f, 0.0f}}; - std::array Velocity{{0.0f, 0.0f, 0.0f}}; - std::array OrientAt{{0.0f, 0.0f, -1.0f}}; - std::array OrientUp{{0.0f, 1.0f, 0.0f}}; - ALfloat Gain{1.0f}; - - std::atomic_flag PropsClean; - - /* Pointer to the most recent property values that are awaiting an update. - */ - std::atomic Update{nullptr}; - - struct { - alu::Matrix Matrix; - alu::Vector Velocity; - - ALfloat Gain; - ALfloat MetersPerUnit; - - ALfloat DopplerFactor; - ALfloat SpeedOfSound; /* in units per sec! */ - ALfloat ReverbSpeedOfSound; /* in meters per sec! */ - - ALboolean SourceDistanceModel; - DistanceModel mDistanceModel; - } Params; - - ALlistener() { PropsClean.test_and_set(std::memory_order_relaxed); } -}; - -void UpdateListenerProps(ALCcontext *context); - -#endif diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h deleted file mode 100644 index 330bb9f4..00000000 --- a/OpenAL32/Include/alSource.h +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef _AL_SOURCE_H_ -#define _AL_SOURCE_H_ - -#include - -#include "alcmain.h" -#include "alu.h" -#include "hrtf.h" -#include "almalloc.h" -#include "atomic.h" - -#define DEFAULT_SENDS 2 - -struct ALbuffer; -struct ALsource; -struct ALeffectslot; - - -struct ALbufferlistitem { - std::atomic next; - ALsizei max_samples; - ALsizei num_buffers; - ALbuffer *buffers[]; - - static constexpr size_t Sizeof(size_t num_buffers) noexcept - { - return maxz(offsetof(ALbufferlistitem, buffers) + sizeof(ALbuffer*)*num_buffers, - sizeof(ALbufferlistitem)); - } -}; - - -struct ALsource { - /** Source properties. */ - ALfloat Pitch; - ALfloat Gain; - ALfloat OuterGain; - ALfloat MinGain; - ALfloat MaxGain; - ALfloat InnerAngle; - ALfloat OuterAngle; - ALfloat RefDistance; - ALfloat MaxDistance; - ALfloat RolloffFactor; - std::array Position; - std::array Velocity; - std::array Direction; - std::array OrientAt; - std::array OrientUp; - ALboolean HeadRelative; - ALboolean Looping; - DistanceModel mDistanceModel; - Resampler mResampler; - ALboolean DirectChannels; - SpatializeMode mSpatialize; - - ALboolean DryGainHFAuto; - ALboolean WetGainAuto; - ALboolean WetGainHFAuto; - ALfloat OuterGainHF; - - ALfloat AirAbsorptionFactor; - ALfloat RoomRolloffFactor; - ALfloat DopplerFactor; - - /* NOTE: Stereo pan angles are specified in radians, counter-clockwise - * rather than clockwise. - */ - std::array StereoPan; - - ALfloat Radius; - - /** Direct filter and auxiliary send info. */ - struct { - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - } Direct; - struct SendData { - ALeffectslot *Slot; - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - }; - al::vector Send; - - /** - * Last user-specified offset, and the offset type (bytes, samples, or - * seconds). - */ - ALdouble Offset; - ALenum OffsetType; - - /** Source type (static, streaming, or undetermined) */ - ALint SourceType; - - /** Source state (initial, playing, paused, or stopped) */ - ALenum state; - - /** Source Buffer Queue head. */ - ALbufferlistitem *queue; - - std::atomic_flag PropsClean; - - /* Index into the context's Voices array. Lazily updated, only checked and - * reset when looking up the voice. - */ - ALint VoiceIdx; - - /** Self ID */ - ALuint id; - - - ALsource(ALsizei num_sends); - ~ALsource(); - - ALsource(const ALsource&) = delete; - ALsource& operator=(const ALsource&) = delete; -}; - -void UpdateAllSourceProps(ALCcontext *context); - -#endif diff --git a/OpenAL32/alAuxEffectSlot.h b/OpenAL32/alAuxEffectSlot.h new file mode 100644 index 00000000..b6976d13 --- /dev/null +++ b/OpenAL32/alAuxEffectSlot.h @@ -0,0 +1,100 @@ +#ifndef _AL_AUXEFFECTSLOT_H_ +#define _AL_AUXEFFECTSLOT_H_ + +#include + +#include "alcmain.h" +#include "alEffect.h" +#include "ambidefs.h" +#include "effects/base.h" + +#include "almalloc.h" +#include "atomic.h" + + +struct ALeffectslot; + + +using ALeffectslotArray = al::FlexArray; + + +struct ALeffectslotProps { + ALfloat Gain; + ALboolean AuxSendAuto; + ALeffectslot *Target; + + ALenum Type; + EffectProps Props; + + EffectState *State; + + std::atomic next; +}; + + +struct ALeffectslot { + ALfloat Gain{1.0f}; + ALboolean AuxSendAuto{AL_TRUE}; + ALeffectslot *Target{nullptr}; + + struct { + ALenum Type{AL_EFFECT_NULL}; + EffectProps Props{}; + + EffectState *State{nullptr}; + } Effect; + + std::atomic_flag PropsClean; + + RefCount ref{0u}; + + std::atomic Update{nullptr}; + + struct { + ALfloat Gain{1.0f}; + ALboolean AuxSendAuto{AL_TRUE}; + ALeffectslot *Target{nullptr}; + + ALenum EffectType{AL_EFFECT_NULL}; + EffectProps mEffectProps{}; + EffectState *mEffectState{nullptr}; + + ALfloat RoomRolloff{0.0f}; /* Added to the source's room rolloff, not multiplied. */ + ALfloat DecayTime{0.0f}; + ALfloat DecayLFRatio{0.0f}; + ALfloat DecayHFRatio{0.0f}; + ALboolean DecayHFLimit{AL_FALSE}; + ALfloat AirAbsorptionGainHF{1.0f}; + } Params; + + /* Self ID */ + ALuint id{}; + + /* Mixing buffer used by the Wet mix. */ + al::vector MixBuffer; + + /* Wet buffer configuration is ACN channel order with N3D scaling. + * Consequently, effects that only want to work with mono input can use + * channel 0 by itself. Effects that want multichannel can process the + * ambisonics signal and make a B-Format source pan. + */ + MixParams Wet; + + ALeffectslot() { PropsClean.test_and_set(std::memory_order_relaxed); } + ALeffectslot(const ALeffectslot&) = delete; + ALeffectslot& operator=(const ALeffectslot&) = delete; + ~ALeffectslot(); + + static ALeffectslotArray *CreatePtrArray(size_t count) noexcept; + + DEF_PLACE_NEWDEL() +}; + +ALenum InitEffectSlot(ALeffectslot *slot); +void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context); +void UpdateAllEffectSlotProps(ALCcontext *context); + + +ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect); + +#endif diff --git a/OpenAL32/alBuffer.h b/OpenAL32/alBuffer.h new file mode 100644 index 00000000..92655784 --- /dev/null +++ b/OpenAL32/alBuffer.h @@ -0,0 +1,120 @@ +#ifndef _AL_BUFFER_H_ +#define _AL_BUFFER_H_ + +#include "AL/alc.h" +#include "AL/al.h" +#include "AL/alext.h" + +#include "inprogext.h" +#include "atomic.h" +#include "vector.h" +#include "albyte.h" + + +/* User formats */ +enum UserFmtType : unsigned char { + UserFmtUByte, + UserFmtShort, + UserFmtFloat, + UserFmtDouble, + UserFmtMulaw, + UserFmtAlaw, + UserFmtIMA4, + UserFmtMSADPCM, +}; +enum UserFmtChannels : unsigned char { + UserFmtMono, + UserFmtStereo, + UserFmtRear, + UserFmtQuad, + UserFmtX51, /* (WFX order) */ + UserFmtX61, /* (WFX order) */ + UserFmtX71, /* (WFX order) */ + UserFmtBFormat2D, /* WXY */ + UserFmtBFormat3D, /* WXYZ */ +}; + +ALsizei BytesFromUserFmt(UserFmtType type); +ALsizei ChannelsFromUserFmt(UserFmtChannels chans); +inline ALsizei FrameSizeFromUserFmt(UserFmtChannels chans, UserFmtType type) +{ return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type); } + + +/* Storable formats */ +enum FmtType : unsigned char { + FmtUByte = UserFmtUByte, + FmtShort = UserFmtShort, + FmtFloat = UserFmtFloat, + FmtDouble = UserFmtDouble, + FmtMulaw = UserFmtMulaw, + FmtAlaw = UserFmtAlaw, +}; +enum FmtChannels : unsigned char { + FmtMono = UserFmtMono, + FmtStereo = UserFmtStereo, + FmtRear = UserFmtRear, + FmtQuad = UserFmtQuad, + FmtX51 = UserFmtX51, + FmtX61 = UserFmtX61, + FmtX71 = UserFmtX71, + FmtBFormat2D = UserFmtBFormat2D, + FmtBFormat3D = UserFmtBFormat3D, +}; +#define MAX_INPUT_CHANNELS (8) + +/* DevFmtType traits, providing the type, etc given a DevFmtType. */ +template +struct FmtTypeTraits { }; + +template<> +struct FmtTypeTraits { using Type = ALubyte; }; +template<> +struct FmtTypeTraits { using Type = ALshort; }; +template<> +struct FmtTypeTraits { using Type = ALfloat; }; +template<> +struct FmtTypeTraits { using Type = ALdouble; }; +template<> +struct FmtTypeTraits { using Type = ALubyte; }; +template<> +struct FmtTypeTraits { using Type = ALubyte; }; + + +ALsizei BytesFromFmt(FmtType type); +ALsizei ChannelsFromFmt(FmtChannels chans); +inline ALsizei FrameSizeFromFmt(FmtChannels chans, FmtType type) +{ return ChannelsFromFmt(chans) * BytesFromFmt(type); } + + +struct ALbuffer { + al::vector mData; + + ALsizei Frequency{0}; + ALbitfieldSOFT Access{0u}; + ALsizei SampleLen{0}; + + FmtChannels mFmtChannels{}; + FmtType mFmtType{}; + + UserFmtType OriginalType{}; + ALsizei OriginalSize{0}; + ALsizei OriginalAlign{0}; + + ALsizei LoopStart{0}; + ALsizei LoopEnd{0}; + + std::atomic UnpackAlign{0}; + std::atomic PackAlign{0}; + + ALbitfieldSOFT MappedAccess{0u}; + ALsizei MappedOffset{0}; + ALsizei MappedSize{0}; + + /* Number of times buffer was attached to a source (deletion can only occur when 0) */ + RefCount ref{0u}; + + /* Self ID */ + ALuint id{0}; +}; + +#endif diff --git a/OpenAL32/alEffect.h b/OpenAL32/alEffect.h new file mode 100644 index 00000000..d43aa206 --- /dev/null +++ b/OpenAL32/alEffect.h @@ -0,0 +1,59 @@ +#ifndef _AL_EFFECT_H_ +#define _AL_EFFECT_H_ + +#include "alcmain.h" +#include "effects/base.h" + + +enum { + EAXREVERB_EFFECT = 0, + REVERB_EFFECT, + AUTOWAH_EFFECT, + CHORUS_EFFECT, + COMPRESSOR_EFFECT, + DISTORTION_EFFECT, + ECHO_EFFECT, + EQUALIZER_EFFECT, + FLANGER_EFFECT, + FSHIFTER_EFFECT, + MODULATOR_EFFECT, + PSHIFTER_EFFECT, + VMORPHER_EFFECT, + DEDICATED_EFFECT, + + MAX_EFFECTS +}; +extern ALboolean DisabledEffects[MAX_EFFECTS]; + +extern ALfloat ReverbBoost; + +struct EffectList { + const char name[16]; + int type; + ALenum val; +}; +extern const EffectList gEffectList[15]; + + +struct ALeffect { + // Effect type (AL_EFFECT_NULL, ...) + ALenum type{AL_EFFECT_NULL}; + + EffectProps Props{}; + + const EffectVtable *vtab{nullptr}; + + /* Self ID */ + ALuint id{0u}; +}; + +inline ALboolean IsReverbEffect(ALenum type) +{ return type == AL_EFFECT_REVERB || type == AL_EFFECT_EAXREVERB; } + +EffectStateFactory *getFactoryByType(ALenum type); + +void InitEffect(ALeffect *effect); + +void LoadReverbPreset(const char *name, ALeffect *effect); + +#endif diff --git a/OpenAL32/alError.h b/OpenAL32/alError.h new file mode 100644 index 00000000..0abd6b26 --- /dev/null +++ b/OpenAL32/alError.h @@ -0,0 +1,22 @@ +#ifndef _AL_ERROR_H_ +#define _AL_ERROR_H_ + +#include "alcmain.h" +#include "logging.h" + + +extern bool TrapALError; + +void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) DECL_FORMAT(printf, 3, 4); + +#define SETERR_GOTO(ctx, err, lbl, ...) do { \ + alSetError((ctx), (err), __VA_ARGS__); \ + goto lbl; \ +} while(0) + +#define SETERR_RETURN(ctx, err, retval, ...) do { \ + alSetError((ctx), (err), __VA_ARGS__); \ + return retval; \ +} while(0) + +#endif diff --git a/OpenAL32/alFilter.h b/OpenAL32/alFilter.h new file mode 100644 index 00000000..1c033ac3 --- /dev/null +++ b/OpenAL32/alFilter.h @@ -0,0 +1,56 @@ +#ifndef _AL_FILTER_H_ +#define _AL_FILTER_H_ + +#include "AL/alc.h" +#include "AL/al.h" + + +#define LOWPASSFREQREF (5000.0f) +#define HIGHPASSFREQREF (250.0f) + + +struct ALfilter; + +struct ALfilterVtable { + void (*const setParami)(ALfilter *filter, ALCcontext *context, ALenum param, ALint val); + void (*const setParamiv)(ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals); + void (*const setParamf)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val); + void (*const setParamfv)(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals); + + void (*const getParami)(ALfilter *filter, ALCcontext *context, ALenum param, ALint *val); + void (*const getParamiv)(ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals); + void (*const getParamf)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val); + void (*const getParamfv)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals); +}; + +#define DEFINE_ALFILTER_VTABLE(T) \ +const ALfilterVtable T##_vtable = { \ + T##_setParami, T##_setParamiv, T##_setParamf, T##_setParamfv, \ + T##_getParami, T##_getParamiv, T##_getParamf, T##_getParamfv, \ +} + +struct ALfilter { + // Filter type (AL_FILTER_NULL, ...) + ALenum type; + + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; + + const ALfilterVtable *vtab; + + /* Self ID */ + ALuint id; +}; +#define ALfilter_setParami(o, c, p, v) ((o)->vtab->setParami(o, c, p, v)) +#define ALfilter_setParamf(o, c, p, v) ((o)->vtab->setParamf(o, c, p, v)) +#define ALfilter_setParamiv(o, c, p, v) ((o)->vtab->setParamiv(o, c, p, v)) +#define ALfilter_setParamfv(o, c, p, v) ((o)->vtab->setParamfv(o, c, p, v)) +#define ALfilter_getParami(o, c, p, v) ((o)->vtab->getParami(o, c, p, v)) +#define ALfilter_getParamf(o, c, p, v) ((o)->vtab->getParamf(o, c, p, v)) +#define ALfilter_getParamiv(o, c, p, v) ((o)->vtab->getParamiv(o, c, p, v)) +#define ALfilter_getParamfv(o, c, p, v) ((o)->vtab->getParamfv(o, c, p, v)) + +#endif diff --git a/OpenAL32/alListener.h b/OpenAL32/alListener.h new file mode 100644 index 00000000..4d59dbf9 --- /dev/null +++ b/OpenAL32/alListener.h @@ -0,0 +1,59 @@ +#ifndef _AL_LISTENER_H_ +#define _AL_LISTENER_H_ + +#include + +#include "AL/alc.h" +#include "AL/al.h" +#include "AL/alext.h" + +#include "atomic.h" +#include "vecmat.h" + +enum class DistanceModel; + + +struct ALlistenerProps { + std::array Position; + std::array Velocity; + std::array OrientAt; + std::array OrientUp; + ALfloat Gain; + + std::atomic next; +}; + +struct ALlistener { + std::array Position{{0.0f, 0.0f, 0.0f}}; + std::array Velocity{{0.0f, 0.0f, 0.0f}}; + std::array OrientAt{{0.0f, 0.0f, -1.0f}}; + std::array OrientUp{{0.0f, 1.0f, 0.0f}}; + ALfloat Gain{1.0f}; + + std::atomic_flag PropsClean; + + /* Pointer to the most recent property values that are awaiting an update. + */ + std::atomic Update{nullptr}; + + struct { + alu::Matrix Matrix; + alu::Vector Velocity; + + ALfloat Gain; + ALfloat MetersPerUnit; + + ALfloat DopplerFactor; + ALfloat SpeedOfSound; /* in units per sec! */ + ALfloat ReverbSpeedOfSound; /* in meters per sec! */ + + ALboolean SourceDistanceModel; + DistanceModel mDistanceModel; + } Params; + + ALlistener() { PropsClean.test_and_set(std::memory_order_relaxed); } +}; + +void UpdateListenerProps(ALCcontext *context); + +#endif diff --git a/OpenAL32/alSource.h b/OpenAL32/alSource.h new file mode 100644 index 00000000..330bb9f4 --- /dev/null +++ b/OpenAL32/alSource.h @@ -0,0 +1,127 @@ +#ifndef _AL_SOURCE_H_ +#define _AL_SOURCE_H_ + +#include + +#include "alcmain.h" +#include "alu.h" +#include "hrtf.h" +#include "almalloc.h" +#include "atomic.h" + +#define DEFAULT_SENDS 2 + +struct ALbuffer; +struct ALsource; +struct ALeffectslot; + + +struct ALbufferlistitem { + std::atomic next; + ALsizei max_samples; + ALsizei num_buffers; + ALbuffer *buffers[]; + + static constexpr size_t Sizeof(size_t num_buffers) noexcept + { + return maxz(offsetof(ALbufferlistitem, buffers) + sizeof(ALbuffer*)*num_buffers, + sizeof(ALbufferlistitem)); + } +}; + + +struct ALsource { + /** Source properties. */ + ALfloat Pitch; + ALfloat Gain; + ALfloat OuterGain; + ALfloat MinGain; + ALfloat MaxGain; + ALfloat InnerAngle; + ALfloat OuterAngle; + ALfloat RefDistance; + ALfloat MaxDistance; + ALfloat RolloffFactor; + std::array Position; + std::array Velocity; + std::array Direction; + std::array OrientAt; + std::array OrientUp; + ALboolean HeadRelative; + ALboolean Looping; + DistanceModel mDistanceModel; + Resampler mResampler; + ALboolean DirectChannels; + SpatializeMode mSpatialize; + + ALboolean DryGainHFAuto; + ALboolean WetGainAuto; + ALboolean WetGainHFAuto; + ALfloat OuterGainHF; + + ALfloat AirAbsorptionFactor; + ALfloat RoomRolloffFactor; + ALfloat DopplerFactor; + + /* NOTE: Stereo pan angles are specified in radians, counter-clockwise + * rather than clockwise. + */ + std::array StereoPan; + + ALfloat Radius; + + /** Direct filter and auxiliary send info. */ + struct { + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; + } Direct; + struct SendData { + ALeffectslot *Slot; + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; + }; + al::vector Send; + + /** + * Last user-specified offset, and the offset type (bytes, samples, or + * seconds). + */ + ALdouble Offset; + ALenum OffsetType; + + /** Source type (static, streaming, or undetermined) */ + ALint SourceType; + + /** Source state (initial, playing, paused, or stopped) */ + ALenum state; + + /** Source Buffer Queue head. */ + ALbufferlistitem *queue; + + std::atomic_flag PropsClean; + + /* Index into the context's Voices array. Lazily updated, only checked and + * reset when looking up the voice. + */ + ALint VoiceIdx; + + /** Self ID */ + ALuint id; + + + ALsource(ALsizei num_sends); + ~ALsource(); + + ALsource(const ALsource&) = delete; + ALsource& operator=(const ALsource&) = delete; +}; + +void UpdateAllSourceProps(ALCcontext *context); + +#endif -- cgit v1.2.3 From d38d2553649555714bfe20f8ca72614974993d47 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Jul 2019 21:29:59 -0700 Subject: More include cleanups --- OpenAL32/alAuxEffectSlot.cpp | 24 +++++++++++++++--------- OpenAL32/alAuxEffectSlot.h | 19 +++++++++++-------- OpenAL32/alBuffer.cpp | 5 ++--- OpenAL32/alBuffer.h | 13 +++++++------ OpenAL32/alEffect.cpp | 2 +- OpenAL32/alEffect.h | 8 +++++--- OpenAL32/alError.cpp | 10 +++++----- OpenAL32/alError.h | 8 +++++--- OpenAL32/alExtension.cpp | 7 ++++--- OpenAL32/alFilter.cpp | 17 +++++++++++++---- OpenAL32/alFilter.h | 6 +++--- OpenAL32/alListener.cpp | 15 ++++++++++----- OpenAL32/alListener.h | 9 ++++----- OpenAL32/alSource.cpp | 3 --- OpenAL32/alSource.h | 22 +++++++++++++--------- alc/alu.h | 4 ++-- alc/converter.cpp | 3 +++ alc/converter.h | 7 ++++++- alc/hrtf.h | 2 +- alc/mastering.cpp | 16 +++++++++++----- alc/mastering.h | 4 ++-- alc/ringbuffer.cpp | 10 +++------- alc/uhjfilter.cpp | 5 ++++- 23 files changed, 130 insertions(+), 89 deletions(-) diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp index cc2893c3..42966bf2 100644 --- a/OpenAL32/alAuxEffectSlot.cpp +++ b/OpenAL32/alAuxEffectSlot.cpp @@ -20,25 +20,31 @@ #include "config.h" -#include -#include +#include "alAuxEffectSlot.h" -#include #include +#include +#include +#include +#include +#include #include "AL/al.h" #include "AL/alc.h" +#include "alEffect.h" +#include "alError.h" #include "alcmain.h" #include "alcontext.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alListener.h" -#include "alSource.h" - -#include "fpu_modes.h" #include "alexcpt.h" #include "almalloc.h" +#include "alnumeric.h" +#include "alspan.h" +#include "alu.h" +#include "fpu_modes.h" +#include "inprogext.h" +#include "logging.h" +#include "opthelpers.h" namespace { diff --git a/OpenAL32/alAuxEffectSlot.h b/OpenAL32/alAuxEffectSlot.h index b6976d13..369638a0 100644 --- a/OpenAL32/alAuxEffectSlot.h +++ b/OpenAL32/alAuxEffectSlot.h @@ -1,17 +1,20 @@ -#ifndef _AL_AUXEFFECTSLOT_H_ -#define _AL_AUXEFFECTSLOT_H_ +#ifndef AL_AUXEFFECTSLOT_H +#define AL_AUXEFFECTSLOT_H -#include +#include +#include -#include "alcmain.h" -#include "alEffect.h" -#include "ambidefs.h" -#include "effects/base.h" +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/efx.h" +#include "alcmain.h" #include "almalloc.h" #include "atomic.h" +#include "effects/base.h" +#include "vector.h" - +struct ALeffect; struct ALeffectslot; diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp index 597f98cb..505b9dab 100644 --- a/OpenAL32/alBuffer.cpp +++ b/OpenAL32/alBuffer.cpp @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -40,9 +40,9 @@ #include "AL/alc.h" #include "AL/alext.h" -#include "alcmain.h" #include "alError.h" #include "albyte.h" +#include "alcmain.h" #include "alcontext.h" #include "alexcpt.h" #include "almalloc.h" @@ -51,7 +51,6 @@ #include "atomic.h" #include "inprogext.h" #include "opthelpers.h" -#include "vector.h" namespace { diff --git a/OpenAL32/alBuffer.h b/OpenAL32/alBuffer.h index 92655784..1d5873e5 100644 --- a/OpenAL32/alBuffer.h +++ b/OpenAL32/alBuffer.h @@ -1,14 +1,15 @@ -#ifndef _AL_BUFFER_H_ -#define _AL_BUFFER_H_ +#ifndef AL_BUFFER_H +#define AL_BUFFER_H + +#include -#include "AL/alc.h" #include "AL/al.h" -#include "AL/alext.h" -#include "inprogext.h" +#include "albyte.h" +#include "almalloc.h" #include "atomic.h" +#include "inprogext.h" #include "vector.h" -#include "albyte.h" /* User formats */ diff --git a/OpenAL32/alEffect.cpp b/OpenAL32/alEffect.cpp index 14353d1c..4a75f69f 100644 --- a/OpenAL32/alEffect.cpp +++ b/OpenAL32/alEffect.cpp @@ -37,8 +37,8 @@ #include "AL/efx-presets.h" #include "AL/efx.h" -#include "alcmain.h" #include "alError.h" +#include "alcmain.h" #include "alcontext.h" #include "alexcpt.h" #include "almalloc.h" diff --git a/OpenAL32/alEffect.h b/OpenAL32/alEffect.h index d43aa206..270b8e20 100644 --- a/OpenAL32/alEffect.h +++ b/OpenAL32/alEffect.h @@ -1,7 +1,9 @@ -#ifndef _AL_EFFECT_H_ -#define _AL_EFFECT_H_ +#ifndef AL_EFFECT_H +#define AL_EFFECT_H + +#include "AL/al.h" +#include "AL/efx.h" -#include "alcmain.h" #include "effects/base.h" diff --git a/OpenAL32/alError.cpp b/OpenAL32/alError.cpp index 782e10ec..159aee52 100644 --- a/OpenAL32/alError.cpp +++ b/OpenAL32/alError.cpp @@ -22,6 +22,11 @@ #include "alError.h" +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + #include #include #include @@ -29,11 +34,6 @@ #include #include -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#endif - #include "AL/al.h" #include "AL/alc.h" diff --git a/OpenAL32/alError.h b/OpenAL32/alError.h index 0abd6b26..6408b60c 100644 --- a/OpenAL32/alError.h +++ b/OpenAL32/alError.h @@ -1,7 +1,9 @@ -#ifndef _AL_ERROR_H_ -#define _AL_ERROR_H_ +#ifndef AL_ERROR_H +#define AL_ERROR_H + +#include "AL/al.h" +#include "AL/alc.h" -#include "alcmain.h" #include "logging.h" diff --git a/OpenAL32/alExtension.cpp b/OpenAL32/alExtension.cpp index 5abcf1cf..80681090 100644 --- a/OpenAL32/alExtension.cpp +++ b/OpenAL32/alExtension.cpp @@ -20,17 +20,18 @@ #include "config.h" +#include #include #include -#include #include "AL/al.h" #include "AL/alc.h" -#include "alcmain.h" -#include "alcontext.h" #include "alError.h" +#include "alcontext.h" #include "alexcpt.h" +#include "opthelpers.h" + AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName) START_API_FUNC diff --git a/OpenAL32/alFilter.cpp b/OpenAL32/alFilter.cpp index cac12581..31fbaf21 100644 --- a/OpenAL32/alFilter.cpp +++ b/OpenAL32/alFilter.cpp @@ -20,16 +20,25 @@ #include "config.h" -#include +#include "alFilter.h" #include +#include +#include +#include +#include +#include + +#include "AL/efx.h" +#include "alError.h" #include "alcmain.h" #include "alcontext.h" -#include "alu.h" -#include "alFilter.h" -#include "alError.h" #include "alexcpt.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "opthelpers.h" +#include "vector.h" namespace { diff --git a/OpenAL32/alFilter.h b/OpenAL32/alFilter.h index 1c033ac3..db098d70 100644 --- a/OpenAL32/alFilter.h +++ b/OpenAL32/alFilter.h @@ -1,8 +1,8 @@ -#ifndef _AL_FILTER_H_ -#define _AL_FILTER_H_ +#ifndef AL_FILTER_H +#define AL_FILTER_H -#include "AL/alc.h" #include "AL/al.h" +#include "AL/alc.h" #define LOWPASSFREQREF (5000.0f) diff --git a/OpenAL32/alListener.cpp b/OpenAL32/alListener.cpp index 067c0f55..d3bf3aaa 100644 --- a/OpenAL32/alListener.cpp +++ b/OpenAL32/alListener.cpp @@ -20,15 +20,20 @@ #include "config.h" +#include "alListener.h" + #include +#include + +#include "AL/efx.h" -#include "alcmain.h" -#include "alcontext.h" -#include "alu.h" #include "alError.h" -#include "alListener.h" -#include "alSource.h" +#include "alcontext.h" #include "alexcpt.h" +#include "almalloc.h" +#include "atomic.h" +#include "opthelpers.h" + #define DO_UPDATEPROPS() do { \ if(!context->DeferUpdates.load(std::memory_order_acquire)) \ diff --git a/OpenAL32/alListener.h b/OpenAL32/alListener.h index 4d59dbf9..a71db9f8 100644 --- a/OpenAL32/alListener.h +++ b/OpenAL32/alListener.h @@ -1,13 +1,12 @@ -#ifndef _AL_LISTENER_H_ -#define _AL_LISTENER_H_ +#ifndef AL_LISTENER_H +#define AL_LISTENER_H #include +#include -#include "AL/alc.h" #include "AL/al.h" -#include "AL/alext.h" +#include "AL/alc.h" -#include "atomic.h" #include "vecmat.h" enum class DistanceModel; diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp index b080f874..4af5cc47 100644 --- a/OpenAL32/alSource.cpp +++ b/OpenAL32/alSource.cpp @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -39,7 +38,6 @@ #include #include #include -#include #include #include "AL/al.h" @@ -69,7 +67,6 @@ #include "opthelpers.h" #include "ringbuffer.h" #include "threads.h" -#include "vector.h" namespace { diff --git a/OpenAL32/alSource.h b/OpenAL32/alSource.h index 330bb9f4..c9892398 100644 --- a/OpenAL32/alSource.h +++ b/OpenAL32/alSource.h @@ -1,21 +1,25 @@ -#ifndef _AL_SOURCE_H_ -#define _AL_SOURCE_H_ +#ifndef AL_SOURCE_H +#define AL_SOURCE_H #include +#include +#include -#include "alcmain.h" -#include "alu.h" -#include "hrtf.h" -#include "almalloc.h" -#include "atomic.h" +#include "AL/al.h" +#include "AL/alc.h" -#define DEFAULT_SENDS 2 +#include "alcontext.h" +#include "alnumeric.h" +#include "alu.h" +#include "vector.h" struct ALbuffer; -struct ALsource; struct ALeffectslot; +#define DEFAULT_SENDS 2 + + struct ALbufferlistitem { std::atomic next; ALsizei max_samples; diff --git a/alc/alu.h b/alc/alu.h index 9acf904a..ef88bdf6 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -1,5 +1,5 @@ -#ifndef _ALU_H_ -#define _ALU_H_ +#ifndef ALU_H +#define ALU_H #include #include diff --git a/alc/converter.cpp b/alc/converter.cpp index 0f8e8941..2e357fb8 100644 --- a/alc/converter.cpp +++ b/alc/converter.cpp @@ -4,7 +4,10 @@ #include "converter.h" #include +#include +#include +#include "albyte.h" #include "fpu_modes.h" #include "mixer/defs.h" diff --git a/alc/converter.h b/alc/converter.h index 033e4d3f..bc51e46a 100644 --- a/alc/converter.h +++ b/alc/converter.h @@ -1,11 +1,16 @@ #ifndef CONVERTER_H #define CONVERTER_H +#include #include +#include "AL/al.h" + #include "alcmain.h" -#include "alu.h" #include "almalloc.h" +#include "alnumeric.h" +#include "alu.h" + struct SampleConverter { DevFmtType mSrcType{}; diff --git a/alc/hrtf.h b/alc/hrtf.h index 6c41cb82..29f7fce0 100644 --- a/alc/hrtf.h +++ b/alc/hrtf.h @@ -13,9 +13,9 @@ #include "atomic.h" #include "vector.h" - struct HrtfHandle; + #define HRTF_HISTORY_BITS (6) #define HRTF_HISTORY_LENGTH (1< -#include +#include "mastering.h" + #include +#include +#include #include +#include +#include +#include -#include "mastering.h" -#include "alu.h" #include "almalloc.h" -#include "math_defs.h" +#include "alnumeric.h" +#include "alu.h" +#include "opthelpers.h" /* These structures assume BUFFERSIZE is a power of 2. */ diff --git a/alc/mastering.h b/alc/mastering.h index 34dc8dcb..5be769ac 100644 --- a/alc/mastering.h +++ b/alc/mastering.h @@ -5,13 +5,13 @@ #include "AL/al.h" -#include "almalloc.h" /* For FloatBufferLine/BUFFERSIZE. */ #include "alcmain.h" - +#include "almalloc.h" struct SlidingHold; + /* General topology and basic automation was based on the following paper: * * D. Giannoulis, M. Massberg and J. D. Reiss, diff --git a/alc/ringbuffer.cpp b/alc/ringbuffer.cpp index 6ef576a5..d99676b8 100644 --- a/alc/ringbuffer.cpp +++ b/alc/ringbuffer.cpp @@ -20,17 +20,13 @@ #include "config.h" -#include -#include -#include +#include "ringbuffer.h" #include +#include +#include -#include "ringbuffer.h" -#include "atomic.h" -#include "threads.h" #include "almalloc.h" -#include "compat.h" RingBufferPtr CreateRingBuffer(size_t sz, size_t elem_sz, int limit_writes) diff --git a/alc/uhjfilter.cpp b/alc/uhjfilter.cpp index 55999647..b2cdf328 100644 --- a/alc/uhjfilter.cpp +++ b/alc/uhjfilter.cpp @@ -4,8 +4,11 @@ #include "uhjfilter.h" #include +#include + +#include "alnumeric.h" +#include "opthelpers.h" -#include "alu.h" namespace { -- cgit v1.2.3 From 40e937c63a2a74ef2ff94ba8a056cce0a07832ed Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Jul 2019 08:16:39 -0700 Subject: Cleanup the examples' includes --- examples/alffplay.cpp | 31 +++++++++++++++++++++++-------- examples/alhrtf.c | 7 +++++-- examples/allatency.c | 5 +++-- examples/alloopback.c | 7 +++++-- examples/almultireverb.c | 9 ++++++--- examples/alplay.c | 5 +++-- examples/alrecord.c | 1 - examples/alreverb.c | 6 ++++-- examples/alstream.c | 7 +++---- examples/common/alhelpers.c | 6 ++---- examples/common/alhelpers.h | 2 -- 11 files changed, 54 insertions(+), 32 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index eb5004c6..cdb228e1 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -8,29 +8,44 @@ #include #include #include +#include #include +#include #include -#include -#include -#include +#include #include +#include +#include +#include +#include +#include +#include #include -#include -#include #include #include -#include +#include +#include +#include extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libavformat/avio.h" -#include "libavutil/time.h" +#include "libavformat/version.h" +#include "libavutil/avutil.h" +#include "libavutil/error.h" +#include "libavutil/frame.h" +#include "libavutil/mem.h" #include "libavutil/pixfmt.h" -#include "libavutil/avstring.h" +#include "libavutil/rational.h" +#include "libavutil/samplefmt.h" +#include "libavutil/time.h" +#include "libavutil/version.h" #include "libavutil/channel_layout.h" #include "libswscale/swscale.h" #include "libswresample/swresample.h" + +struct SwsContext; } #include "SDL.h" diff --git a/examples/alhrtf.c b/examples/alhrtf.c index f9150ae1..96cf0255 100644 --- a/examples/alhrtf.c +++ b/examples/alhrtf.c @@ -24,11 +24,14 @@ /* This file contains an example for selecting an HRTF. */ -#include #include #include +#include +#include -#include +#include "SDL_sound.h" +#include "SDL_audio.h" +#include "SDL_stdinc.h" #include "AL/al.h" #include "AL/alc.h" diff --git a/examples/allatency.c b/examples/allatency.c index d561373f..2bc76289 100644 --- a/examples/allatency.c +++ b/examples/allatency.c @@ -27,10 +27,11 @@ #include #include -#include +#include "SDL_sound.h" +#include "SDL_audio.h" +#include "SDL_stdinc.h" #include "AL/al.h" -#include "AL/alc.h" #include "AL/alext.h" #include "common/alhelpers.h" diff --git a/examples/alloopback.c b/examples/alloopback.c index 16553f9b..313b89d5 100644 --- a/examples/alloopback.c +++ b/examples/alloopback.c @@ -26,11 +26,14 @@ * output handling. */ -#include #include #include +#include -#include +#include "SDL.h" +#include "SDL_audio.h" +#include "SDL_error.h" +#include "SDL_stdinc.h" #include "AL/al.h" #include "AL/alc.h" diff --git a/examples/almultireverb.c b/examples/almultireverb.c index f1b1872f..efd3bf16 100644 --- a/examples/almultireverb.c +++ b/examples/almultireverb.c @@ -29,15 +29,18 @@ * listener. */ -#include #include #include +#include +#include -#include +#include "SDL_sound.h" +#include "SDL_audio.h" +#include "SDL_stdinc.h" #include "AL/al.h" #include "AL/alc.h" -#include "AL/alext.h" +#include "AL/efx.h" #include "AL/efx-presets.h" #include "common/alhelpers.h" diff --git a/examples/alplay.c b/examples/alplay.c index 81cb56d5..4ff8fb7f 100644 --- a/examples/alplay.c +++ b/examples/alplay.c @@ -27,10 +27,11 @@ #include #include -#include +#include "SDL_sound.h" +#include "SDL_audio.h" +#include "SDL_stdinc.h" #include "AL/al.h" -#include "AL/alc.h" #include "common/alhelpers.h" diff --git a/examples/alrecord.c b/examples/alrecord.c index c4984f99..d65414c9 100644 --- a/examples/alrecord.c +++ b/examples/alrecord.c @@ -28,7 +28,6 @@ #include #include #include -#include #include "AL/al.h" #include "AL/alc.h" diff --git a/examples/alreverb.c b/examples/alreverb.c index e6c9e606..e1d3c207 100644 --- a/examples/alreverb.c +++ b/examples/alreverb.c @@ -27,11 +27,13 @@ #include #include -#include +#include "SDL_sound.h" +#include "SDL_audio.h" +#include "SDL_stdinc.h" #include "AL/al.h" #include "AL/alc.h" -#include "AL/alext.h" +#include "AL/efx.h" #include "AL/efx-presets.h" #include "common/alhelpers.h" diff --git a/examples/alstream.c b/examples/alstream.c index 68115e8d..cb447355 100644 --- a/examples/alstream.c +++ b/examples/alstream.c @@ -27,14 +27,13 @@ #include #include #include -#include #include -#include +#include "SDL_sound.h" +#include "SDL_audio.h" +#include "SDL_stdinc.h" #include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" #include "common/alhelpers.h" diff --git a/examples/common/alhelpers.c b/examples/common/alhelpers.c index 3077d0b7..b387fd2d 100644 --- a/examples/common/alhelpers.c +++ b/examples/common/alhelpers.c @@ -28,16 +28,14 @@ * finding an appropriate buffer format, and getting readable strings for * channel configs and sample types. */ -#include +#include "alhelpers.h" + #include #include #include #include "AL/al.h" #include "AL/alc.h" -#include "AL/alext.h" - -#include "alhelpers.h" /* InitAL opens a device and sets up a context using default attributes, making diff --git a/examples/common/alhelpers.h b/examples/common/alhelpers.h index 5caeda38..3752d218 100644 --- a/examples/common/alhelpers.h +++ b/examples/common/alhelpers.h @@ -1,9 +1,7 @@ #ifndef ALHELPERS_H #define ALHELPERS_H -#include "AL/alc.h" #include "AL/al.h" -#include "AL/alext.h" #ifdef __cplusplus extern "C" { -- cgit v1.2.3 From f0408809d6b2012aca0f1e8a344e087cb504a231 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Jul 2019 09:29:35 -0700 Subject: Cleanup common sources' includes --- common/alcomplex.cpp | 11 +++++------ common/almalloc.h | 11 +++++++---- common/alnumeric.h | 3 ++- common/aloptional.h | 2 ++ common/alspan.h | 6 +++--- common/threads.cpp | 20 ++++++++++++-------- common/threads.h | 4 ---- common/vecmat.h | 13 ++++++------- 8 files changed, 37 insertions(+), 33 deletions(-) diff --git a/common/alcomplex.cpp b/common/alcomplex.cpp index 9074cf5f..71d3c5f8 100644 --- a/common/alcomplex.cpp +++ b/common/alcomplex.cpp @@ -3,14 +3,13 @@ #include "alcomplex.h" -#include #include +#include +#include +#include -namespace { - -constexpr double Pi{3.141592653589793238462643383279502884}; +#include "math_defs.h" -} // namespace void complex_fft(const al::span> buffer, const double sign) { @@ -36,7 +35,7 @@ void complex_fft(const al::span> buffer, const double sign) for(size_t i{1u};i < fftsize;i<<=1, step<<=1) { const size_t step2{step >> 1}; - double arg{Pi / step2}; + double arg{al::MathDefs::Pi() / step2}; std::complex w{std::cos(arg), std::sin(arg)*sign}; std::complex u{1.0, 0.0}; diff --git a/common/almalloc.h b/common/almalloc.h index 801df1d8..3fc979c9 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -1,11 +1,14 @@ #ifndef AL_MALLOC_H #define AL_MALLOC_H -#include - -#include -#include #include +#include +#include +#include +#include +#include +#include +#include void *al_malloc(size_t alignment, size_t size); diff --git a/common/alnumeric.h b/common/alnumeric.h index e97c40e2..950eebe1 100644 --- a/common/alnumeric.h +++ b/common/alnumeric.h @@ -1,7 +1,8 @@ #ifndef AL_NUMERIC_H #define AL_NUMERIC_H -#include +#include +#include #ifdef HAVE_INTRIN_H #include #endif diff --git a/common/aloptional.h b/common/aloptional.h index 2ed882e4..79827482 100644 --- a/common/aloptional.h +++ b/common/aloptional.h @@ -1,7 +1,9 @@ #ifndef AL_OPTIONAL_H #define AL_OPTIONAL_H +#include #include +#include #include "almalloc.h" diff --git a/common/alspan.h b/common/alspan.h index b7995121..60a2bc4a 100644 --- a/common/alspan.h +++ b/common/alspan.h @@ -1,11 +1,11 @@ #ifndef AL_SPAN_H #define AL_SPAN_H -#include - #include -#include +#include #include +#include +#include namespace al { diff --git a/common/threads.cpp b/common/threads.cpp index 45f73243..fe34f5b0 100644 --- a/common/threads.cpp +++ b/common/threads.cpp @@ -22,12 +22,13 @@ #include "threads.h" -#include #include #ifdef _WIN32 +#include + void althrd_setname(const char *name) { #if defined(_MSC_VER) @@ -86,7 +87,7 @@ bool semaphore::try_wait() noexcept #else -#include +#if defined(HAVE_PTHREAD_SETNAME_NP) || defined(HAVE_PTHREAD_SET_NAME_NP) #include #ifdef HAVE_PTHREAD_NP_H #include @@ -94,20 +95,21 @@ bool semaphore::try_wait() noexcept void althrd_setname(const char *name) { -#if defined(HAVE_PTHREAD_SETNAME_NP) -#if defined(PTHREAD_SETNAME_NP_ONE_PARAM) +#if defined(HAVE_PTHREAD_SET_NAME_NP) + pthread_set_name_np(pthread_self(), name); +#elif defined(PTHREAD_SETNAME_NP_ONE_PARAM) pthread_setname_np(name); #elif defined(PTHREAD_SETNAME_NP_THREE_PARAMS) pthread_setname_np(pthread_self(), "%s", (void*)name); #else pthread_setname_np(pthread_self(), name); #endif -#elif defined(HAVE_PTHREAD_SET_NAME_NP) - pthread_set_name_np(pthread_self(), name); +} + #else - (void)name; + +void althrd_setname(const char*) { } #endif -} namespace al { @@ -134,6 +136,8 @@ bool semaphore::try_wait() noexcept #else /* !__APPLE__ */ +#include + semaphore::semaphore(unsigned int initial) { if(sem_init(&mSem, 0, initial) != 0) diff --git a/common/threads.h b/common/threads.h index 8a640390..ff571a66 100644 --- a/common/threads.h +++ b/common/threads.h @@ -1,10 +1,6 @@ #ifndef AL_THREADS_H #define AL_THREADS_H -#include - -#include - #if defined(__GNUC__) && defined(__i386__) /* force_align_arg_pointer is required for proper function arguments aligning * when SSE code is used. Some systems (Windows, QNX) do not guarantee our diff --git a/common/vecmat.h b/common/vecmat.h index ab407b15..83f1381e 100644 --- a/common/vecmat.h +++ b/common/vecmat.h @@ -1,12 +1,11 @@ #ifndef COMMON_VECMAT_H #define COMMON_VECMAT_H -#include #include +#include +#include #include -#include -#include "math_defs.h" namespace alu { @@ -19,11 +18,11 @@ public: : mVals{{a, b, c, d}} { } Vector(const Vector &rhs) noexcept - { std::copy(rhs.mVals.begin(), rhs.mVals.end(), mVals.begin()); } + { mVals = rhs.mVals; } Vector& operator=(const Vector &rhs) noexcept { - std::copy(rhs.mVals.begin(), rhs.mVals.end(), mVals.begin()); + mVals = rhs.mVals; return *this; } @@ -67,11 +66,11 @@ public: : mVals{{{{aa, ab, ac, ad}}, {{ba, bb, bc, bd}}, {{ca, cb, cc, cd}}, {{da, db, dc, dd}}}} { } Matrix(const Matrix &rhs) noexcept - { std::copy(rhs.mVals.begin(), rhs.mVals.end(), mVals.begin()); } + { mVals = rhs.mVals; } Matrix& operator=(const Matrix &rhs) noexcept { - std::copy(rhs.mVals.begin(), rhs.mVals.end(), mVals.begin()); + mVals = rhs.mVals; return *this; } -- cgit v1.2.3 From 8ccb7604d30147583fda134e220807f3dc2f07e5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Jul 2019 13:46:25 -0700 Subject: Remove some unnecessary cmake checks --- CMakeLists.txt | 47 ++++++++++++++++------------------------------- 1 file changed, 16 insertions(+), 31 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 65e9ebd6..6b942fda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -419,7 +419,7 @@ IF(NOT HAVE_GUIDDEF_H) CHECK_INCLUDE_FILE(initguid.h HAVE_INITGUID_H) ENDIF() -# Some systems need libm for some of the following math functions to work +# Some systems need libm for some math functions to work SET(MATH_LIB ) CHECK_LIBRARY_EXISTS(m pow "" HAVE_LIBM) IF(HAVE_LIBM) @@ -498,23 +498,12 @@ ENDIF() IF(NOT WIN32) - CHECK_SYMBOL_EXISTS(gettimeofday sys/time.h HAVE_GETTIMEOFDAY) - IF(NOT HAVE_GETTIMEOFDAY) - MESSAGE(FATAL_ERROR "No timing function found!") - ENDIF() - - CHECK_SYMBOL_EXISTS(nanosleep time.h HAVE_NANOSLEEP) - IF(NOT HAVE_NANOSLEEP) - MESSAGE(FATAL_ERROR "No sleep function found!") - ENDIF() - - # We need pthreads outside of Windows + # We need pthreads outside of Windows, for semaphores. It's also used to + # set the priority and name of threads, when possible. CHECK_INCLUDE_FILE(pthread.h HAVE_PTHREAD_H) IF(NOT HAVE_PTHREAD_H) MESSAGE(FATAL_ERROR "PThreads is required for non-Windows builds!") ENDIF() - # Some systems need pthread_np.h to get recursive mutexes - CHECK_INCLUDE_FILES("pthread.h;pthread_np.h" HAVE_PTHREAD_NP_H) CHECK_C_COMPILER_FLAG(-pthread HAVE_PTHREAD) IF(HAVE_PTHREAD) @@ -530,6 +519,8 @@ IF(NOT WIN32) CHECK_SYMBOL_EXISTS(pthread_setschedparam pthread.h HAVE_PTHREAD_SETSCHEDPARAM) + # Some systems need pthread_np.h to get pthread_setname_np + CHECK_INCLUDE_FILES("pthread.h;pthread_np.h" HAVE_PTHREAD_NP_H) IF(HAVE_PTHREAD_NP_H) CHECK_SYMBOL_EXISTS(pthread_setname_np "pthread.h;pthread_np.h" HAVE_PTHREAD_SETNAME_NP) IF(NOT HAVE_PTHREAD_SETNAME_NP) @@ -581,11 +572,6 @@ int main() ) ENDIF() ENDIF() - - CHECK_LIBRARY_EXISTS(rt clock_gettime "" HAVE_LIBRT) - IF(HAVE_LIBRT) - SET(EXTRA_LIBS rt ${EXTRA_LIBS}) - ENDIF() ENDIF() CHECK_SYMBOL_EXISTS(getopt unistd.h HAVE_GETOPT) @@ -1500,15 +1486,21 @@ IF(ALSOFT_UTILS) MESSAGE(STATUS "") ENDIF() +IF(ALSOFT_EXAMPLES OR ALSOFT_TESTS) + # Add a static library with common functions used by multiple targets + ADD_LIBRARY(ex-common STATIC examples/common/alhelpers.c) + TARGET_COMPILE_DEFINITIONS(ex-common PUBLIC ${CPP_DEFS}) + TARGET_INCLUDE_DIRECTORIES(ex-common PUBLIC ${OpenAL_SOURCE_DIR}/common) + TARGET_COMPILE_OPTIONS(ex-common PUBLIC ${C_FLAGS}) + TARGET_LINK_LIBRARIES(ex-common PUBLIC OpenAL) +ENDIF() + IF(ALSOFT_TESTS) - ADD_EXECUTABLE(altonegen - examples/altonegen.c - examples/common/alhelpers.c - ) + ADD_EXECUTABLE(altonegen examples/altonegen.c) TARGET_COMPILE_DEFINITIONS(altonegen PRIVATE ${CPP_DEFS}) TARGET_INCLUDE_DIRECTORIES(altonegen PRIVATE ${OpenAL_SOURCE_DIR}/common) TARGET_COMPILE_OPTIONS(altonegen PRIVATE ${C_FLAGS}) - TARGET_LINK_LIBRARIES(altonegen PRIVATE ${LINKER_FLAGS} OpenAL ${MATH_LIB}) + TARGET_LINK_LIBRARIES(altonegen PRIVATE ${LINKER_FLAGS} ${MATH_LIB} ex-common) IF(ALSOFT_INSTALL) INSTALL(TARGETS altonegen @@ -1523,13 +1515,6 @@ IF(ALSOFT_TESTS) ENDIF() IF(ALSOFT_EXAMPLES) - # Add a static library with common functions used by multiple targets - ADD_LIBRARY(ex-common STATIC examples/common/alhelpers.c) - TARGET_COMPILE_DEFINITIONS(ex-common PUBLIC ${CPP_DEFS}) - TARGET_INCLUDE_DIRECTORIES(ex-common PUBLIC ${OpenAL_SOURCE_DIR}/common) - TARGET_COMPILE_OPTIONS(ex-common PUBLIC ${C_FLAGS}) - TARGET_LINK_LIBRARIES(ex-common PUBLIC OpenAL) - ADD_EXECUTABLE(alrecord examples/alrecord.c) TARGET_LINK_LIBRARIES(alrecord PRIVATE ${LINKER_FLAGS} ex-common) -- cgit v1.2.3 From 0a26bab14e0100b883f59958f3ce417888cebc62 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Jul 2019 15:40:17 -0700 Subject: Rename the OpenAL32 directory to al --- CMakeLists.txt | 36 +- OpenAL32/alAuxEffectSlot.cpp | 808 ---------- OpenAL32/alAuxEffectSlot.h | 103 -- OpenAL32/alBuffer.cpp | 1408 ---------------- OpenAL32/alBuffer.h | 121 -- OpenAL32/alEffect.cpp | 742 --------- OpenAL32/alEffect.h | 61 - OpenAL32/alError.cpp | 118 -- OpenAL32/alError.h | 24 - OpenAL32/alExtension.cpp | 80 - OpenAL32/alFilter.cpp | 665 -------- OpenAL32/alFilter.h | 56 - OpenAL32/alListener.cpp | 454 ------ OpenAL32/alListener.h | 58 - OpenAL32/alSource.cpp | 3638 ------------------------------------------ OpenAL32/alSource.h | 131 -- OpenAL32/alState.cpp | 859 ---------- OpenAL32/event.cpp | 216 --- al/alAuxEffectSlot.cpp | 808 ++++++++++ al/alAuxEffectSlot.h | 103 ++ al/alBuffer.cpp | 1408 ++++++++++++++++ al/alBuffer.h | 121 ++ al/alEffect.cpp | 742 +++++++++ al/alEffect.h | 61 + al/alError.cpp | 118 ++ al/alError.h | 24 + al/alExtension.cpp | 80 + al/alFilter.cpp | 665 ++++++++ al/alFilter.h | 56 + al/alListener.cpp | 454 ++++++ al/alListener.h | 58 + al/alSource.cpp | 3638 ++++++++++++++++++++++++++++++++++++++++++ al/alSource.h | 131 ++ al/alState.cpp | 859 ++++++++++ al/event.cpp | 216 +++ 35 files changed, 9560 insertions(+), 9560 deletions(-) delete mode 100644 OpenAL32/alAuxEffectSlot.cpp delete mode 100644 OpenAL32/alAuxEffectSlot.h delete mode 100644 OpenAL32/alBuffer.cpp delete mode 100644 OpenAL32/alBuffer.h delete mode 100644 OpenAL32/alEffect.cpp delete mode 100644 OpenAL32/alEffect.h delete mode 100644 OpenAL32/alError.cpp delete mode 100644 OpenAL32/alError.h delete mode 100644 OpenAL32/alExtension.cpp delete mode 100644 OpenAL32/alFilter.cpp delete mode 100644 OpenAL32/alFilter.h delete mode 100644 OpenAL32/alListener.cpp delete mode 100644 OpenAL32/alListener.h delete mode 100644 OpenAL32/alSource.cpp delete mode 100644 OpenAL32/alSource.h delete mode 100644 OpenAL32/alState.cpp delete mode 100644 OpenAL32/event.cpp create mode 100644 al/alAuxEffectSlot.cpp create mode 100644 al/alAuxEffectSlot.h create mode 100644 al/alBuffer.cpp create mode 100644 al/alBuffer.h create mode 100644 al/alEffect.cpp create mode 100644 al/alEffect.h create mode 100644 al/alError.cpp create mode 100644 al/alError.h create mode 100644 al/alExtension.cpp create mode 100644 al/alFilter.cpp create mode 100644 al/alFilter.h create mode 100644 al/alListener.cpp create mode 100644 al/alListener.h create mode 100644 al/alSource.cpp create mode 100644 al/alSource.h create mode 100644 al/alState.cpp create mode 100644 al/event.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b942fda..258c93e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -605,23 +605,23 @@ SET(COMMON_OBJS common/vecmat.h ) SET(OPENAL_OBJS - OpenAL32/alAuxEffectSlot.cpp - OpenAL32/alAuxEffectSlot.h - OpenAL32/alBuffer.cpp - OpenAL32/alBuffer.h - OpenAL32/alEffect.cpp - OpenAL32/alEffect.h - OpenAL32/alError.cpp - OpenAL32/alError.h - OpenAL32/alExtension.cpp - OpenAL32/alFilter.cpp - OpenAL32/alFilter.h - OpenAL32/alListener.cpp - OpenAL32/alListener.h - OpenAL32/alSource.cpp - OpenAL32/alSource.h - OpenAL32/alState.cpp - OpenAL32/event.cpp + al/alAuxEffectSlot.cpp + al/alAuxEffectSlot.h + al/alBuffer.cpp + al/alBuffer.h + al/alEffect.cpp + al/alEffect.h + al/alError.cpp + al/alError.h + al/alExtension.cpp + al/alFilter.cpp + al/alFilter.h + al/alListener.cpp + al/alListener.h + al/alSource.cpp + al/alSource.h + al/alState.cpp + al/event.cpp ) SET(ALC_OBJS alc/alc.cpp @@ -1299,7 +1299,7 @@ TARGET_INCLUDE_DIRECTORIES(${IMPL_TARGET} ${INC_PATHS} ${OpenAL_BINARY_DIR} ${OpenAL_SOURCE_DIR}/alc - ${OpenAL_SOURCE_DIR}/OpenAL32 + ${OpenAL_SOURCE_DIR}/al ${OpenAL_SOURCE_DIR}/common ) diff --git a/OpenAL32/alAuxEffectSlot.cpp b/OpenAL32/alAuxEffectSlot.cpp deleted file mode 100644 index 42966bf2..00000000 --- a/OpenAL32/alAuxEffectSlot.cpp +++ /dev/null @@ -1,808 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "alAuxEffectSlot.h" - -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" - -#include "alEffect.h" -#include "alError.h" -#include "alcmain.h" -#include "alcontext.h" -#include "alexcpt.h" -#include "almalloc.h" -#include "alnumeric.h" -#include "alspan.h" -#include "alu.h" -#include "fpu_modes.h" -#include "inprogext.h" -#include "logging.h" -#include "opthelpers.h" - - -namespace { - -inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept -{ - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= context->EffectSlotList.size())) - return nullptr; - EffectSlotSubList &sublist{context->EffectSlotList[lidx]}; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) - return nullptr; - return sublist.EffectSlots + slidx; -} - -inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) noexcept -{ - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= device->EffectList.size())) - return nullptr; - EffectSubList &sublist = device->EffectList[lidx]; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) - return nullptr; - return sublist.Effects + slidx; -} - - -void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) -{ - if(count < 1) return; - ALeffectslotArray *curarray{context->ActiveAuxSlots.load(std::memory_order_acquire)}; - size_t newcount{curarray->size() + count}; - - /* Insert the new effect slots into the head of the array, followed by the - * existing ones. - */ - ALeffectslotArray *newarray = ALeffectslot::CreatePtrArray(newcount); - auto slotiter = std::transform(slotids, slotids+count, newarray->begin(), - [context](ALuint id) noexcept -> ALeffectslot* - { return LookupEffectSlot(context, id); } - ); - std::copy(curarray->begin(), curarray->end(), slotiter); - - /* Remove any duplicates (first instance of each will be kept). */ - auto last = newarray->end(); - for(auto start=newarray->begin()+1;;) - { - last = std::remove(start, last, *(start-1)); - if(start == last) break; - ++start; - } - newcount = static_cast(std::distance(newarray->begin(), last)); - - /* Reallocate newarray if the new size ended up smaller from duplicate - * removal. - */ - if(UNLIKELY(newcount < newarray->size())) - { - curarray = newarray; - newarray = ALeffectslot::CreatePtrArray(newcount); - std::copy_n(curarray->begin(), newcount, newarray->begin()); - delete curarray; - curarray = nullptr; - } - - curarray = context->ActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); - ALCdevice *device{context->Device}; - while((device->MixCount.load(std::memory_order_acquire)&1)) - std::this_thread::yield(); - delete curarray; -} - -void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) -{ - if(count < 1) return; - ALeffectslotArray *curarray{context->ActiveAuxSlots.load(std::memory_order_acquire)}; - - /* Don't shrink the allocated array size since we don't know how many (if - * any) of the effect slots to remove are in the array. - */ - ALeffectslotArray *newarray = ALeffectslot::CreatePtrArray(curarray->size()); - - /* Copy each element in curarray to newarray whose ID is not in slotids. */ - const ALuint *slotids_end{slotids + count}; - auto slotiter = std::copy_if(curarray->begin(), curarray->end(), newarray->begin(), - [slotids, slotids_end](const ALeffectslot *slot) -> bool - { return std::find(slotids, slotids_end, slot->id) == slotids_end; } - ); - - /* Reallocate with the new size. */ - auto newsize = static_cast(std::distance(newarray->begin(), slotiter)); - if(LIKELY(newsize != newarray->size())) - { - curarray = newarray; - newarray = ALeffectslot::CreatePtrArray(newsize); - std::copy_n(curarray->begin(), newsize, newarray->begin()); - - delete curarray; - curarray = nullptr; - } - - curarray = context->ActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); - ALCdevice *device{context->Device}; - while((device->MixCount.load(std::memory_order_acquire)&1)) - std::this_thread::yield(); - delete curarray; -} - - -ALeffectslot *AllocEffectSlot(ALCcontext *context) -{ - ALCdevice *device{context->Device}; - std::lock_guard _{context->EffectSlotLock}; - if(context->NumEffectSlots >= device->AuxiliaryEffectSlotMax) - { - alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u effect slot limit", - device->AuxiliaryEffectSlotMax); - return nullptr; - } - auto sublist = std::find_if(context->EffectSlotList.begin(), context->EffectSlotList.end(), - [](const EffectSlotSubList &entry) noexcept -> bool - { return entry.FreeMask != 0; } - ); - auto lidx = static_cast(std::distance(context->EffectSlotList.begin(), sublist)); - ALeffectslot *slot; - ALsizei slidx; - if(LIKELY(sublist != context->EffectSlotList.end())) - { - slidx = CTZ64(sublist->FreeMask); - slot = sublist->EffectSlots + slidx; - } - else - { - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ - if(UNLIKELY(context->EffectSlotList.size() >= 1<<25)) - { - alSetError(context, AL_OUT_OF_MEMORY, "Too many effect slots allocated"); - return nullptr; - } - context->EffectSlotList.emplace_back(); - sublist = context->EffectSlotList.end() - 1; - - sublist->FreeMask = ~0_u64; - sublist->EffectSlots = static_cast(al_calloc(16, sizeof(ALeffectslot)*64)); - if(UNLIKELY(!sublist->EffectSlots)) - { - context->EffectSlotList.pop_back(); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect slot batch"); - return nullptr; - } - - slidx = 0; - slot = sublist->EffectSlots + slidx; - } - - slot = new (slot) ALeffectslot{}; - ALenum err{InitEffectSlot(slot)}; - if(err != AL_NO_ERROR) - { - al::destroy_at(slot); - alSetError(context, err, "Effect slot object initialization failed"); - return nullptr; - } - aluInitEffectPanning(slot, device); - - /* Add 1 to avoid source ID 0. */ - slot->id = ((lidx<<6) | slidx) + 1; - - context->NumEffectSlots += 1; - sublist->FreeMask &= ~(1_u64 << slidx); - - return slot; -} - -void FreeEffectSlot(ALCcontext *context, ALeffectslot *slot) -{ - ALuint id = slot->id - 1; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; - - al::destroy_at(slot); - - context->EffectSlotList[lidx].FreeMask |= 1_u64 << slidx; - context->NumEffectSlots--; -} - - -#define DO_UPDATEPROPS() do { \ - if(!context->DeferUpdates.load(std::memory_order_acquire)) \ - UpdateEffectSlotProps(slot, context.get()); \ - else \ - slot->PropsClean.clear(std::memory_order_release); \ -} while(0) - -} // namespace - -ALeffectslotArray *ALeffectslot::CreatePtrArray(size_t count) noexcept -{ - /* Allocate space for twice as many pointers, so the mixer has scratch - * space to store a sorted list during mixing. - */ - void *ptr{al_calloc(alignof(ALeffectslotArray), ALeffectslotArray::Sizeof(count*2))}; - return new (ptr) ALeffectslotArray{count}; -} - - -AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Generating %d effect slots", n); - if(n == 0) return; - - if(n == 1) - { - ALeffectslot *slot{AllocEffectSlot(context.get())}; - if(!slot) return; - effectslots[0] = slot->id; - } - else - { - auto tempids = al::vector(n); - auto alloc_end = std::find_if_not(tempids.begin(), tempids.end(), - [&context](ALuint &id) -> bool - { - ALeffectslot *slot{AllocEffectSlot(context.get())}; - if(!slot) return false; - id = slot->id; - return true; - } - ); - if(alloc_end != tempids.end()) - { - auto count = static_cast(std::distance(tempids.begin(), alloc_end)); - alDeleteAuxiliaryEffectSlots(count, tempids.data()); - return; - } - - std::copy(tempids.cbegin(), tempids.cend(), effectslots); - } - - std::unique_lock slotlock{context->EffectSlotLock}; - AddActiveEffectSlots(effectslots, n, context.get()); -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Deleting %d effect slots", n); - if(n == 0) return; - - std::lock_guard _{context->EffectSlotLock}; - auto effectslots_end = effectslots + n; - auto bad_slot = std::find_if(effectslots, effectslots_end, - [&context](ALuint id) -> bool - { - ALeffectslot *slot{LookupEffectSlot(context.get(), id)}; - if(!slot) - { - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect slot ID %u", id); - return true; - } - if(ReadRef(&slot->ref) != 0) - { - alSetError(context.get(), AL_INVALID_NAME, "Deleting in-use effect slot %u", id); - return true; - } - return false; - } - ); - if(bad_slot != effectslots_end) - return; - - // All effectslots are valid, remove and delete them - RemoveActiveEffectSlots(effectslots, n, context.get()); - std::for_each(effectslots, effectslots_end, - [&context](ALuint sid) -> void - { - ALeffectslot *slot{LookupEffectSlot(context.get(), sid)}; - if(slot) FreeEffectSlot(context.get(), slot); - } - ); -} -END_API_FUNC - -AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(LIKELY(context)) - { - std::lock_guard _{context->EffectSlotLock}; - if(LookupEffectSlot(context.get(), effectslot) != nullptr) - return AL_TRUE; - } - return AL_FALSE; -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->EffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - - ALeffectslot *target{}; - ALCdevice *device{}; - ALenum err{}; - switch(param) - { - case AL_EFFECTSLOT_EFFECT: - device = context->Device; - - { std::lock_guard ___{device->EffectLock}; - ALeffect *effect{value ? LookupEffect(device, value) : nullptr}; - if(!(value == 0 || effect != nullptr)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Invalid effect ID %u", value); - err = InitializeEffect(context.get(), slot, effect); - } - if(err != AL_NO_ERROR) - { - alSetError(context.get(), err, "Effect initialization failed"); - return; - } - break; - - case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: - if(!(value == AL_TRUE || value == AL_FALSE)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, - "Effect slot auxiliary send auto out of range"); - slot->AuxSendAuto = value; - break; - - case AL_EFFECTSLOT_TARGET_SOFT: - target = (value ? LookupEffectSlot(context.get(), value) : nullptr); - if(value && !target) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Invalid effect slot target ID"); - if(target) - { - ALeffectslot *checker{target}; - while(checker && checker != slot) - checker = checker->Target; - if(checker) - SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, - "Setting target of effect slot ID %u to %u creates circular chain", slot->id, - target->id); - } - - if(ALeffectslot *oldtarget{slot->Target}) - { - /* We must force an update if there was an existing effect slot - * target, in case it's about to be deleted. - */ - if(target) IncrementRef(&target->ref); - DecrementRef(&oldtarget->ref); - slot->Target = target; - UpdateEffectSlotProps(slot, context.get()); - return; - } - - if(target) IncrementRef(&target->ref); - slot->Target = target; - break; - - default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot integer property 0x%04x", param); - } - DO_UPDATEPROPS(); -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values) -START_API_FUNC -{ - switch(param) - { - case AL_EFFECTSLOT_EFFECT: - case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: - case AL_EFFECTSLOT_TARGET_SOFT: - alAuxiliaryEffectSloti(effectslot, param, values[0]); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->EffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - - switch(param) - { - default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot integer-vector property 0x%04x", param); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->EffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - - switch(param) - { - case AL_EFFECTSLOT_GAIN: - if(!(value >= 0.0f && value <= 1.0f)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Effect slot gain out of range"); - slot->Gain = value; - break; - - default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, "Invalid effect slot float property 0x%04x", - param); - } - DO_UPDATEPROPS(); -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values) -START_API_FUNC -{ - switch(param) - { - case AL_EFFECTSLOT_GAIN: - alAuxiliaryEffectSlotf(effectslot, param, values[0]); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->EffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - - switch(param) - { - default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot float-vector property 0x%04x", param); - } -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->EffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - - switch(param) - { - case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: - *value = slot->AuxSendAuto; - break; - - case AL_EFFECTSLOT_TARGET_SOFT: - *value = slot->Target ? slot->Target->id : 0; - break; - - default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot integer property 0x%04x", param); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values) -START_API_FUNC -{ - switch(param) - { - case AL_EFFECTSLOT_EFFECT: - case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: - case AL_EFFECTSLOT_TARGET_SOFT: - alGetAuxiliaryEffectSloti(effectslot, param, values); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->EffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - - switch(param) - { - default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot integer-vector property 0x%04x", param); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->EffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - - switch(param) - { - case AL_EFFECTSLOT_GAIN: - *value = slot->Gain; - break; - - default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot float property 0x%04x", param); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values) -START_API_FUNC -{ - switch(param) - { - case AL_EFFECTSLOT_GAIN: - alGetAuxiliaryEffectSlotf(effectslot, param, values); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->EffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - - switch(param) - { - default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot float-vector property 0x%04x", param); - } -} -END_API_FUNC - - -ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect) -{ - ALenum newtype{effect ? effect->type : AL_EFFECT_NULL}; - if(newtype != EffectSlot->Effect.Type) - { - EffectStateFactory *factory{getFactoryByType(newtype)}; - if(!factory) - { - ERR("Failed to find factory for effect type 0x%04x\n", newtype); - return AL_INVALID_ENUM; - } - EffectState *State{factory->create()}; - if(!State) return AL_OUT_OF_MEMORY; - - FPUCtl mixer_mode{}; - ALCdevice *Device{Context->Device}; - std::unique_lock statelock{Device->StateLock}; - State->mOutTarget = Device->Dry.Buffer; - if(State->deviceUpdate(Device) == AL_FALSE) - { - statelock.unlock(); - mixer_mode.leave(); - State->DecRef(); - return AL_OUT_OF_MEMORY; - } - mixer_mode.leave(); - - if(!effect) - { - EffectSlot->Effect.Type = AL_EFFECT_NULL; - EffectSlot->Effect.Props = EffectProps {}; - } - else - { - EffectSlot->Effect.Type = effect->type; - EffectSlot->Effect.Props = effect->Props; - } - - EffectSlot->Effect.State->DecRef(); - EffectSlot->Effect.State = State; - } - else if(effect) - EffectSlot->Effect.Props = effect->Props; - - /* Remove state references from old effect slot property updates. */ - ALeffectslotProps *props{Context->FreeEffectslotProps.load()}; - while(props) - { - if(props->State) - props->State->DecRef(); - props->State = nullptr; - props = props->next.load(std::memory_order_relaxed); - } - - return AL_NO_ERROR; -} - - -void EffectState::IncRef() noexcept -{ - auto ref = IncrementRef(&mRef); - TRACEREF("EffectState %p increasing refcount to %u\n", this, ref); -} - -void EffectState::DecRef() noexcept -{ - auto ref = DecrementRef(&mRef); - TRACEREF("EffectState %p decreasing refcount to %u\n", this, ref); - if(ref == 0) delete this; -} - - -ALenum InitEffectSlot(ALeffectslot *slot) -{ - EffectStateFactory *factory{getFactoryByType(slot->Effect.Type)}; - if(!factory) return AL_INVALID_VALUE; - slot->Effect.State = factory->create(); - if(!slot->Effect.State) return AL_OUT_OF_MEMORY; - - slot->Effect.State->IncRef(); - slot->Params.mEffectState = slot->Effect.State; - return AL_NO_ERROR; -} - -ALeffectslot::~ALeffectslot() -{ - if(Target) - DecrementRef(&Target->ref); - Target = nullptr; - - ALeffectslotProps *props{Update.load()}; - if(props) - { - if(props->State) props->State->DecRef(); - TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props); - al_free(props); - } - - if(Effect.State) - Effect.State->DecRef(); - if(Params.mEffectState) - Params.mEffectState->DecRef(); -} - -void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) -{ - /* Get an unused property container, or allocate a new one as needed. */ - ALeffectslotProps *props{context->FreeEffectslotProps.load(std::memory_order_relaxed)}; - if(!props) - props = static_cast(al_calloc(16, sizeof(*props))); - else - { - ALeffectslotProps *next; - do { - next = props->next.load(std::memory_order_relaxed); - } while(context->FreeEffectslotProps.compare_exchange_weak(props, next, - std::memory_order_seq_cst, std::memory_order_acquire) == 0); - } - - /* Copy in current property values. */ - props->Gain = slot->Gain; - props->AuxSendAuto = slot->AuxSendAuto; - props->Target = slot->Target; - - props->Type = slot->Effect.Type; - props->Props = slot->Effect.Props; - /* Swap out any stale effect state object there may be in the container, to - * delete it. - */ - EffectState *oldstate{props->State}; - slot->Effect.State->IncRef(); - props->State = slot->Effect.State; - - /* Set the new container for updating internal parameters. */ - props = slot->Update.exchange(props, std::memory_order_acq_rel); - if(props) - { - /* If there was an unused update container, put it back in the - * freelist. - */ - if(props->State) - props->State->DecRef(); - props->State = nullptr; - AtomicReplaceHead(context->FreeEffectslotProps, props); - } - - if(oldstate) - oldstate->DecRef(); -} - -void UpdateAllEffectSlotProps(ALCcontext *context) -{ - std::lock_guard _{context->EffectSlotLock}; - ALeffectslotArray *auxslots{context->ActiveAuxSlots.load(std::memory_order_acquire)}; - for(ALeffectslot *slot : *auxslots) - { - if(!slot->PropsClean.test_and_set(std::memory_order_acq_rel)) - UpdateEffectSlotProps(slot, context); - } -} - -EffectSlotSubList::~EffectSlotSubList() -{ - uint64_t usemask{~FreeMask}; - while(usemask) - { - ALsizei idx{CTZ64(usemask)}; - al::destroy_at(EffectSlots+idx); - usemask &= ~(1_u64 << idx); - } - FreeMask = ~usemask; - al_free(EffectSlots); - EffectSlots = nullptr; -} diff --git a/OpenAL32/alAuxEffectSlot.h b/OpenAL32/alAuxEffectSlot.h deleted file mode 100644 index 369638a0..00000000 --- a/OpenAL32/alAuxEffectSlot.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef AL_AUXEFFECTSLOT_H -#define AL_AUXEFFECTSLOT_H - -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/efx.h" - -#include "alcmain.h" -#include "almalloc.h" -#include "atomic.h" -#include "effects/base.h" -#include "vector.h" - -struct ALeffect; -struct ALeffectslot; - - -using ALeffectslotArray = al::FlexArray; - - -struct ALeffectslotProps { - ALfloat Gain; - ALboolean AuxSendAuto; - ALeffectslot *Target; - - ALenum Type; - EffectProps Props; - - EffectState *State; - - std::atomic next; -}; - - -struct ALeffectslot { - ALfloat Gain{1.0f}; - ALboolean AuxSendAuto{AL_TRUE}; - ALeffectslot *Target{nullptr}; - - struct { - ALenum Type{AL_EFFECT_NULL}; - EffectProps Props{}; - - EffectState *State{nullptr}; - } Effect; - - std::atomic_flag PropsClean; - - RefCount ref{0u}; - - std::atomic Update{nullptr}; - - struct { - ALfloat Gain{1.0f}; - ALboolean AuxSendAuto{AL_TRUE}; - ALeffectslot *Target{nullptr}; - - ALenum EffectType{AL_EFFECT_NULL}; - EffectProps mEffectProps{}; - EffectState *mEffectState{nullptr}; - - ALfloat RoomRolloff{0.0f}; /* Added to the source's room rolloff, not multiplied. */ - ALfloat DecayTime{0.0f}; - ALfloat DecayLFRatio{0.0f}; - ALfloat DecayHFRatio{0.0f}; - ALboolean DecayHFLimit{AL_FALSE}; - ALfloat AirAbsorptionGainHF{1.0f}; - } Params; - - /* Self ID */ - ALuint id{}; - - /* Mixing buffer used by the Wet mix. */ - al::vector MixBuffer; - - /* Wet buffer configuration is ACN channel order with N3D scaling. - * Consequently, effects that only want to work with mono input can use - * channel 0 by itself. Effects that want multichannel can process the - * ambisonics signal and make a B-Format source pan. - */ - MixParams Wet; - - ALeffectslot() { PropsClean.test_and_set(std::memory_order_relaxed); } - ALeffectslot(const ALeffectslot&) = delete; - ALeffectslot& operator=(const ALeffectslot&) = delete; - ~ALeffectslot(); - - static ALeffectslotArray *CreatePtrArray(size_t count) noexcept; - - DEF_PLACE_NEWDEL() -}; - -ALenum InitEffectSlot(ALeffectslot *slot); -void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context); -void UpdateAllEffectSlotProps(ALCcontext *context); - - -ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect); - -#endif diff --git a/OpenAL32/alBuffer.cpp b/OpenAL32/alBuffer.cpp deleted file mode 100644 index 505b9dab..00000000 --- a/OpenAL32/alBuffer.cpp +++ /dev/null @@ -1,1408 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "alBuffer.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" - -#include "alError.h" -#include "albyte.h" -#include "alcmain.h" -#include "alcontext.h" -#include "alexcpt.h" -#include "almalloc.h" -#include "alnumeric.h" -#include "aloptional.h" -#include "atomic.h" -#include "inprogext.h" -#include "opthelpers.h" - - -namespace { - -/* IMA ADPCM Stepsize table */ -constexpr int IMAStep_size[89] = { - 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, - 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, - 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, - 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, - 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, - 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, - 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493,10442, - 11487,12635,13899,15289,16818,18500,20350,22358,24633,27086,29794, - 32767 -}; - -/* IMA4 ADPCM Codeword decode table */ -constexpr int IMA4Codeword[16] = { - 1, 3, 5, 7, 9, 11, 13, 15, - -1,-3,-5,-7,-9,-11,-13,-15, -}; - -/* IMA4 ADPCM Step index adjust decode table */ -constexpr int IMA4Index_adjust[16] = { - -1,-1,-1,-1, 2, 4, 6, 8, - -1,-1,-1,-1, 2, 4, 6, 8 -}; - - -/* MSADPCM Adaption table */ -constexpr int MSADPCMAdaption[16] = { - 230, 230, 230, 230, 307, 409, 512, 614, - 768, 614, 512, 409, 307, 230, 230, 230 -}; - -/* MSADPCM Adaption Coefficient tables */ -constexpr int MSADPCMAdaptionCoeff[7][2] = { - { 256, 0 }, - { 512, -256 }, - { 0, 0 }, - { 192, 64 }, - { 240, 0 }, - { 460, -208 }, - { 392, -232 } -}; - - -void DecodeIMA4Block(ALshort *dst, const al::byte *src, ALint numchans, ALsizei align) -{ - ALint sample[MAX_INPUT_CHANNELS]{}; - ALint index[MAX_INPUT_CHANNELS]{}; - ALuint code[MAX_INPUT_CHANNELS]{}; - - for(int c{0};c < numchans;c++) - { - sample[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); - sample[c] = (sample[c]^0x8000) - 32768; - src += 2; - index[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); - index[c] = clampi((index[c]^0x8000) - 32768, 0, 88); - src += 2; - - *(dst++) = sample[c]; - } - - for(int i{1};i < align;i++) - { - if((i&7) == 1) - { - for(int c{0};c < numchans;c++) - { - code[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<< 8) | - (al::to_integer(src[2])<<16) | (al::to_integer(src[3])<<24); - src += 4; - } - } - - for(int c{0};c < numchans;c++) - { - const ALuint nibble{code[c]&0xf}; - code[c] >>= 4; - - sample[c] += IMA4Codeword[nibble] * IMAStep_size[index[c]] / 8; - sample[c] = clampi(sample[c], -32768, 32767); - - index[c] += IMA4Index_adjust[nibble]; - index[c] = clampi(index[c], 0, 88); - - *(dst++) = sample[c]; - } - } -} - -void DecodeMSADPCMBlock(ALshort *dst, const al::byte *src, ALint numchans, ALsizei align) -{ - ALubyte blockpred[MAX_INPUT_CHANNELS]{}; - ALint delta[MAX_INPUT_CHANNELS]{}; - ALshort samples[MAX_INPUT_CHANNELS][2]{}; - - for(int c{0};c < numchans;c++) - { - blockpred[c] = minu(al::to_integer(src[0]), 6); - ++src; - } - for(int c{0};c < numchans;c++) - { - delta[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); - delta[c] = (delta[c]^0x8000) - 32768; - src += 2; - } - for(int c{0};c < numchans;c++) - { - samples[c][0] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); - samples[c][0] = (samples[c][0]^0x8000) - 32768; - src += 2; - } - for(int c{0};c < numchans;c++) - { - samples[c][1] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); - samples[c][1] = (samples[c][1]^0x8000) - 32768; - src += 2; - } - - /* Second sample is written first. */ - for(int c{0};c < numchans;c++) - *(dst++) = samples[c][1]; - for(int c{0};c < numchans;c++) - *(dst++) = samples[c][0]; - - int num{0}; - for(int i{2};i < align;i++) - { - for(int c{0};c < numchans;c++) - { - /* Read the nibble (first is in the upper bits). */ - al::byte nibble; - if(!(num++ & 1)) - nibble = *src >> 4; - else - nibble = *(src++) & 0x0f; - - ALint pred{(samples[c][0]*MSADPCMAdaptionCoeff[blockpred[c]][0] + - samples[c][1]*MSADPCMAdaptionCoeff[blockpred[c]][1]) / 256}; - pred += (al::to_integer(nibble^0x08) - 0x08) * delta[c]; - pred = clampi(pred, -32768, 32767); - - samples[c][1] = samples[c][0]; - samples[c][0] = pred; - - delta[c] = (MSADPCMAdaption[al::to_integer(nibble)] * delta[c]) / 256; - delta[c] = maxi(16, delta[c]); - - *(dst++) = pred; - } - } -} - -void Convert_ALshort_ALima4(ALshort *dst, const al::byte *src, ALsizei numchans, ALsizei len, - ALsizei align) -{ - const ALsizei byte_align{((align-1)/2 + 4) * numchans}; - - len /= align; - while(len--) - { - DecodeIMA4Block(dst, src, numchans, align); - src += byte_align; - dst += align*numchans; - } -} - -void Convert_ALshort_ALmsadpcm(ALshort *dst, const al::byte *src, ALsizei numchans, ALsizei len, - ALsizei align) -{ - const ALsizei byte_align{((align-2)/2 + 7) * numchans}; - - len /= align; - while(len--) - { - DecodeMSADPCMBlock(dst, src, numchans, align); - src += byte_align; - dst += align*numchans; - } -} - - -constexpr ALbitfieldSOFT INVALID_STORAGE_MASK{~unsigned(AL_MAP_READ_BIT_SOFT | - AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT)}; -constexpr ALbitfieldSOFT MAP_READ_WRITE_FLAGS{AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT}; -constexpr ALbitfieldSOFT INVALID_MAP_FLAGS{~unsigned(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | - AL_MAP_PERSISTENT_BIT_SOFT)}; - - -ALbuffer *AllocBuffer(ALCcontext *context) -{ - ALCdevice *device{context->Device}; - std::lock_guard _{device->BufferLock}; - auto sublist = std::find_if(device->BufferList.begin(), device->BufferList.end(), - [](const BufferSubList &entry) noexcept -> bool - { return entry.FreeMask != 0; } - ); - - auto lidx = static_cast(std::distance(device->BufferList.begin(), sublist)); - ALbuffer *buffer{nullptr}; - ALsizei slidx{0}; - if(LIKELY(sublist != device->BufferList.end())) - { - slidx = CTZ64(sublist->FreeMask); - buffer = sublist->Buffers + slidx; - } - else - { - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ - if(UNLIKELY(device->BufferList.size() >= 1<<25)) - { - alSetError(context, AL_OUT_OF_MEMORY, "Too many buffers allocated"); - return nullptr; - } - device->BufferList.emplace_back(); - sublist = device->BufferList.end() - 1; - sublist->FreeMask = ~0_u64; - sublist->Buffers = reinterpret_cast(al_calloc(16, sizeof(ALbuffer)*64)); - if(UNLIKELY(!sublist->Buffers)) - { - device->BufferList.pop_back(); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate buffer batch"); - return nullptr; - } - - slidx = 0; - buffer = sublist->Buffers + slidx; - } - - buffer = new (buffer) ALbuffer{}; - /* Add 1 to avoid buffer ID 0. */ - buffer->id = ((lidx<<6) | slidx) + 1; - - sublist->FreeMask &= ~(1_u64 << slidx); - - return buffer; -} - -void FreeBuffer(ALCdevice *device, ALbuffer *buffer) -{ - ALuint id{buffer->id - 1}; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; - - al::destroy_at(buffer); - - device->BufferList[lidx].FreeMask |= 1_u64 << slidx; -} - -inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) -{ - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= device->BufferList.size())) - return nullptr; - BufferSubList &sublist = device->BufferList[lidx]; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) - return nullptr; - return sublist.Buffers + slidx; -} - - -ALsizei SanitizeAlignment(UserFmtType type, ALsizei align) -{ - if(align < 0) - return 0; - - if(align == 0) - { - if(type == UserFmtIMA4) - { - /* Here is where things vary: - * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel - * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel - */ - return 65; - } - if(type == UserFmtMSADPCM) - return 64; - return 1; - } - - if(type == UserFmtIMA4) - { - /* IMA4 block alignment must be a multiple of 8, plus 1. */ - if((align&7) == 1) return align; - return 0; - } - if(type == UserFmtMSADPCM) - { - /* MSADPCM block alignment must be a multiple of 2. */ - if((align&1) == 0) return align; - return 0; - } - - return align; -} - - -const ALchar *NameFromUserFmtType(UserFmtType type) -{ - switch(type) - { - case UserFmtUByte: return "Unsigned Byte"; - case UserFmtShort: return "Signed Short"; - case UserFmtFloat: return "Float32"; - case UserFmtDouble: return "Float64"; - case UserFmtMulaw: return "muLaw"; - case UserFmtAlaw: return "aLaw"; - case UserFmtIMA4: return "IMA4 ADPCM"; - case UserFmtMSADPCM: return "MSADPCM"; - } - return ""; -} - -/* - * LoadData - * - * Loads the specified data into the buffer, using the specified format. - */ -void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, UserFmtChannels SrcChannels, UserFmtType SrcType, const al::byte *SrcData, ALbitfieldSOFT access) -{ - if(UNLIKELY(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)) - SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer %u", - ALBuf->id); - - /* Currently no channel configurations need to be converted. */ - FmtChannels DstChannels{FmtMono}; - switch(SrcChannels) - { - case UserFmtMono: DstChannels = FmtMono; break; - case UserFmtStereo: DstChannels = FmtStereo; break; - case UserFmtRear: DstChannels = FmtRear; break; - case UserFmtQuad: DstChannels = FmtQuad; break; - case UserFmtX51: DstChannels = FmtX51; break; - case UserFmtX61: DstChannels = FmtX61; break; - case UserFmtX71: DstChannels = FmtX71; break; - case UserFmtBFormat2D: DstChannels = FmtBFormat2D; break; - case UserFmtBFormat3D: DstChannels = FmtBFormat3D; break; - } - if (UNLIKELY(static_cast(SrcChannels) != - static_cast(DstChannels))) - SETERR_RETURN(context, AL_INVALID_ENUM, , "Invalid format"); - - /* IMA4 and MSADPCM convert to 16-bit short. */ - FmtType DstType{FmtUByte}; - switch(SrcType) - { - case UserFmtUByte: DstType = FmtUByte; break; - case UserFmtShort: DstType = FmtShort; break; - case UserFmtFloat: DstType = FmtFloat; break; - case UserFmtDouble: DstType = FmtDouble; break; - case UserFmtAlaw: DstType = FmtAlaw; break; - case UserFmtMulaw: DstType = FmtMulaw; break; - case UserFmtIMA4: DstType = FmtShort; break; - case UserFmtMSADPCM: DstType = FmtShort; break; - } - - /* TODO: Currently we can only map samples when they're not converted. To - * allow it would need some kind of double-buffering to hold onto a copy of - * the original data. - */ - if((access&MAP_READ_WRITE_FLAGS)) - { - if (UNLIKELY(static_cast(SrcType) != static_cast(DstType))) - SETERR_RETURN(context, AL_INVALID_VALUE, , - "%s samples cannot be mapped", - NameFromUserFmtType(SrcType)); - } - - const ALsizei unpackalign{ALBuf->UnpackAlign.load()}; - const ALsizei align{SanitizeAlignment(SrcType, unpackalign)}; - if(UNLIKELY(align < 1)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid unpack alignment %d for %s samples", - unpackalign, NameFromUserFmtType(SrcType)); - - if((access&AL_PRESERVE_DATA_BIT_SOFT)) - { - /* Can only preserve data with the same format and alignment. */ - if(UNLIKELY(ALBuf->mFmtChannels != DstChannels || ALBuf->OriginalType != SrcType)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched format"); - if(UNLIKELY(ALBuf->OriginalAlign != align)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched alignment"); - } - - /* Convert the input/source size in bytes to sample frames using the unpack - * block alignment. - */ - const ALsizei SrcByteAlign{ - (SrcType == UserFmtIMA4) ? ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels) : - (SrcType == UserFmtMSADPCM) ? ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels) : - (align * FrameSizeFromUserFmt(SrcChannels, SrcType)) - }; - if(UNLIKELY((size%SrcByteAlign) != 0)) - SETERR_RETURN(context, AL_INVALID_VALUE,, - "Data size %d is not a multiple of frame size %d (%d unpack alignment)", - size, SrcByteAlign, align); - - if(UNLIKELY(size/SrcByteAlign > std::numeric_limits::max()/align)) - SETERR_RETURN(context, AL_OUT_OF_MEMORY,, - "Buffer size overflow, %d blocks x %d samples per block", size/SrcByteAlign, align); - const ALsizei frames{size / SrcByteAlign * align}; - - /* Convert the sample frames to the number of bytes needed for internal - * storage. - */ - ALsizei NumChannels{ChannelsFromFmt(DstChannels)}; - ALsizei FrameSize{NumChannels * BytesFromFmt(DstType)}; - if(UNLIKELY(frames > std::numeric_limits::max()/FrameSize)) - SETERR_RETURN(context, AL_OUT_OF_MEMORY,, - "Buffer size overflow, %d frames x %d bytes per frame", frames, FrameSize); - size_t newsize{static_cast(frames) * FrameSize}; - - /* Round up to the next 16-byte multiple. This could reallocate only when - * increasing or the new size is less than half the current, but then the - * buffer's AL_SIZE would not be very reliable for accounting buffer memory - * usage, and reporting the real size could cause problems for apps that - * use AL_SIZE to try to get the buffer's play length. - */ - newsize = RoundUp(newsize, 16); - if(newsize != ALBuf->mData.size()) - { - auto newdata = al::vector(newsize, al::byte{}); - if((access&AL_PRESERVE_DATA_BIT_SOFT)) - { - const size_t tocopy{minz(newdata.size(), ALBuf->mData.size())}; - std::copy_n(ALBuf->mData.begin(), tocopy, newdata.begin()); - } - ALBuf->mData = std::move(newdata); - } - - if(SrcType == UserFmtIMA4) - { - assert(DstType == FmtShort); - if(SrcData != nullptr && !ALBuf->mData.empty()) - Convert_ALshort_ALima4(reinterpret_cast(ALBuf->mData.data()), - SrcData, NumChannels, frames, align); - ALBuf->OriginalAlign = align; - } - else if(SrcType == UserFmtMSADPCM) - { - assert(DstType == FmtShort); - if(SrcData != nullptr && !ALBuf->mData.empty()) - Convert_ALshort_ALmsadpcm(reinterpret_cast(ALBuf->mData.data()), - SrcData, NumChannels, frames, align); - ALBuf->OriginalAlign = align; - } - else - { - assert(static_cast(SrcType) == static_cast(DstType)); - if(SrcData != nullptr && !ALBuf->mData.empty()) - std::copy_n(SrcData, frames*FrameSize, ALBuf->mData.begin()); - ALBuf->OriginalAlign = 1; - } - ALBuf->OriginalSize = size; - ALBuf->OriginalType = SrcType; - - ALBuf->Frequency = freq; - ALBuf->mFmtChannels = DstChannels; - ALBuf->mFmtType = DstType; - ALBuf->Access = access; - - ALBuf->SampleLen = frames; - ALBuf->LoopStart = 0; - ALBuf->LoopEnd = ALBuf->SampleLen; -} - -struct DecompResult { UserFmtChannels channels; UserFmtType type; }; -al::optional DecomposeUserFormat(ALenum format) -{ - struct FormatMap { - ALenum format; - UserFmtChannels channels; - UserFmtType type; - }; - static constexpr std::array UserFmtList{{ - { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte }, - { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort }, - { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat }, - { AL_FORMAT_MONO_DOUBLE_EXT, UserFmtMono, UserFmtDouble }, - { AL_FORMAT_MONO_IMA4, UserFmtMono, UserFmtIMA4 }, - { AL_FORMAT_MONO_MSADPCM_SOFT, UserFmtMono, UserFmtMSADPCM }, - { AL_FORMAT_MONO_MULAW, UserFmtMono, UserFmtMulaw }, - { AL_FORMAT_MONO_ALAW_EXT, UserFmtMono, UserFmtAlaw }, - - { AL_FORMAT_STEREO8, UserFmtStereo, UserFmtUByte }, - { AL_FORMAT_STEREO16, UserFmtStereo, UserFmtShort }, - { AL_FORMAT_STEREO_FLOAT32, UserFmtStereo, UserFmtFloat }, - { AL_FORMAT_STEREO_DOUBLE_EXT, UserFmtStereo, UserFmtDouble }, - { AL_FORMAT_STEREO_IMA4, UserFmtStereo, UserFmtIMA4 }, - { AL_FORMAT_STEREO_MSADPCM_SOFT, UserFmtStereo, UserFmtMSADPCM }, - { AL_FORMAT_STEREO_MULAW, UserFmtStereo, UserFmtMulaw }, - { AL_FORMAT_STEREO_ALAW_EXT, UserFmtStereo, UserFmtAlaw }, - - { AL_FORMAT_REAR8, UserFmtRear, UserFmtUByte }, - { AL_FORMAT_REAR16, UserFmtRear, UserFmtShort }, - { AL_FORMAT_REAR32, UserFmtRear, UserFmtFloat }, - { AL_FORMAT_REAR_MULAW, UserFmtRear, UserFmtMulaw }, - - { AL_FORMAT_QUAD8_LOKI, UserFmtQuad, UserFmtUByte }, - { AL_FORMAT_QUAD16_LOKI, UserFmtQuad, UserFmtShort }, - - { AL_FORMAT_QUAD8, UserFmtQuad, UserFmtUByte }, - { AL_FORMAT_QUAD16, UserFmtQuad, UserFmtShort }, - { AL_FORMAT_QUAD32, UserFmtQuad, UserFmtFloat }, - { AL_FORMAT_QUAD_MULAW, UserFmtQuad, UserFmtMulaw }, - - { AL_FORMAT_51CHN8, UserFmtX51, UserFmtUByte }, - { AL_FORMAT_51CHN16, UserFmtX51, UserFmtShort }, - { AL_FORMAT_51CHN32, UserFmtX51, UserFmtFloat }, - { AL_FORMAT_51CHN_MULAW, UserFmtX51, UserFmtMulaw }, - - { AL_FORMAT_61CHN8, UserFmtX61, UserFmtUByte }, - { AL_FORMAT_61CHN16, UserFmtX61, UserFmtShort }, - { AL_FORMAT_61CHN32, UserFmtX61, UserFmtFloat }, - { AL_FORMAT_61CHN_MULAW, UserFmtX61, UserFmtMulaw }, - - { AL_FORMAT_71CHN8, UserFmtX71, UserFmtUByte }, - { AL_FORMAT_71CHN16, UserFmtX71, UserFmtShort }, - { AL_FORMAT_71CHN32, UserFmtX71, UserFmtFloat }, - { AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw }, - - { AL_FORMAT_BFORMAT2D_8, UserFmtBFormat2D, UserFmtUByte }, - { AL_FORMAT_BFORMAT2D_16, UserFmtBFormat2D, UserFmtShort }, - { AL_FORMAT_BFORMAT2D_FLOAT32, UserFmtBFormat2D, UserFmtFloat }, - { AL_FORMAT_BFORMAT2D_MULAW, UserFmtBFormat2D, UserFmtMulaw }, - - { AL_FORMAT_BFORMAT3D_8, UserFmtBFormat3D, UserFmtUByte }, - { AL_FORMAT_BFORMAT3D_16, UserFmtBFormat3D, UserFmtShort }, - { AL_FORMAT_BFORMAT3D_FLOAT32, UserFmtBFormat3D, UserFmtFloat }, - { AL_FORMAT_BFORMAT3D_MULAW, UserFmtBFormat3D, UserFmtMulaw }, - }}; - - for(const auto &fmt : UserFmtList) - { - if(fmt.format == format) - return al::make_optional(DecompResult{fmt.channels, fmt.type}); - } - return al::nullopt; -} - -} // namespace - - -AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(UNLIKELY(n < 0)) - { - alSetError(context.get(), AL_INVALID_VALUE, "Generating %d buffers", n); - return; - } - - if(LIKELY(n == 1)) - { - /* Special handling for the easy and normal case. */ - ALbuffer *buffer = AllocBuffer(context.get()); - if(buffer) buffers[0] = buffer->id; - } - else if(n > 1) - { - /* Store the allocated buffer IDs in a separate local list, to avoid - * modifying the user storage in case of failure. - */ - al::vector ids; - ids.reserve(n); - do { - ALbuffer *buffer = AllocBuffer(context.get()); - if(!buffer) - { - alDeleteBuffers(static_cast(ids.size()), ids.data()); - return; - } - - ids.emplace_back(buffer->id); - } while(--n); - std::copy(ids.begin(), ids.end(), buffers); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(UNLIKELY(n < 0)) - { - alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d buffers", n); - return; - } - if(UNLIKELY(n == 0)) - return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - /* First try to find any buffers that are invalid or in-use. */ - const ALuint *buffers_end = buffers + n; - auto invbuf = std::find_if(buffers, buffers_end, - [device, &context](ALuint bid) -> bool - { - if(!bid) return false; - ALbuffer *ALBuf = LookupBuffer(device, bid); - if(UNLIKELY(!ALBuf)) - { - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", bid); - return true; - } - if(UNLIKELY(ReadRef(&ALBuf->ref) != 0)) - { - alSetError(context.get(), AL_INVALID_OPERATION, "Deleting in-use buffer %u", bid); - return true; - } - return false; - } - ); - if(LIKELY(invbuf == buffers_end)) - { - /* All good. Delete non-0 buffer IDs. */ - std::for_each(buffers, buffers_end, - [device](ALuint bid) -> void - { - ALbuffer *buffer{bid ? LookupBuffer(device, bid) : nullptr}; - if(buffer) FreeBuffer(device, buffer); - } - ); - } -} -END_API_FUNC - -AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(LIKELY(context)) - { - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - if(!buffer || LookupBuffer(device, buffer)) - return AL_TRUE; - } - return AL_FALSE; -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq) -START_API_FUNC -{ alBufferStorageSOFT(buffer, format, data, size, freq, 0); } -END_API_FUNC - -AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(size < 0)) - alSetError(context.get(), AL_INVALID_VALUE, "Negative storage size %d", size); - else if(UNLIKELY(freq < 1)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid sample rate %d", freq); - else if(UNLIKELY((flags&INVALID_STORAGE_MASK) != 0)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid storage flags 0x%x", - flags&INVALID_STORAGE_MASK); - else if(UNLIKELY((flags&AL_MAP_PERSISTENT_BIT_SOFT) && !(flags&MAP_READ_WRITE_FLAGS))) - alSetError(context.get(), AL_INVALID_VALUE, - "Declaring persistently mapped storage without read or write access"); - else - { - auto usrfmt = DecomposeUserFormat(format); - if(UNLIKELY(!usrfmt)) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid format 0x%04x", format); - else - LoadData(context.get(), albuf, freq, size, usrfmt->channels, usrfmt->type, - static_cast(data), flags); - } -} -END_API_FUNC - -AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return nullptr; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY((access&INVALID_MAP_FLAGS) != 0)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid map flags 0x%x", access&INVALID_MAP_FLAGS); - else if(UNLIKELY(!(access&MAP_READ_WRITE_FLAGS))) - alSetError(context.get(), AL_INVALID_VALUE, "Mapping buffer %u without read or write access", - buffer); - else - { - ALbitfieldSOFT unavailable = (albuf->Access^access) & access; - if(UNLIKELY(ReadRef(&albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT))) - alSetError(context.get(), AL_INVALID_OPERATION, - "Mapping in-use buffer %u without persistent mapping", buffer); - else if(UNLIKELY(albuf->MappedAccess != 0)) - alSetError(context.get(), AL_INVALID_OPERATION, "Mapping already-mapped buffer %u", buffer); - else if(UNLIKELY((unavailable&AL_MAP_READ_BIT_SOFT))) - alSetError(context.get(), AL_INVALID_VALUE, - "Mapping buffer %u for reading without read access", buffer); - else if(UNLIKELY((unavailable&AL_MAP_WRITE_BIT_SOFT))) - alSetError(context.get(), AL_INVALID_VALUE, - "Mapping buffer %u for writing without write access", buffer); - else if(UNLIKELY((unavailable&AL_MAP_PERSISTENT_BIT_SOFT))) - alSetError(context.get(), AL_INVALID_VALUE, - "Mapping buffer %u persistently without persistent access", buffer); - else if(UNLIKELY(offset < 0 || offset >= albuf->OriginalSize || - length <= 0 || length > albuf->OriginalSize - offset)) - alSetError(context.get(), AL_INVALID_VALUE, "Mapping invalid range %d+%d for buffer %u", - offset, length, buffer); - else - { - void *retval = albuf->mData.data() + offset; - albuf->MappedAccess = access; - albuf->MappedOffset = offset; - albuf->MappedSize = length; - return retval; - } - } - - return nullptr; -} -END_API_FUNC - -AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(albuf->MappedAccess == 0) - alSetError(context.get(), AL_INVALID_OPERATION, "Unmapping unmapped buffer %u", buffer); - else - { - albuf->MappedAccess = 0; - albuf->MappedOffset = 0; - albuf->MappedSize = 0; - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT))) - alSetError(context.get(), AL_INVALID_OPERATION, - "Flushing buffer %u while not mapped for writing", buffer); - else if(UNLIKELY(offset < albuf->MappedOffset || - offset >= albuf->MappedOffset+albuf->MappedSize || - length <= 0 || length > albuf->MappedOffset+albuf->MappedSize-offset)) - alSetError(context.get(), AL_INVALID_VALUE, "Flushing invalid range %d+%d on buffer %u", - offset, length, buffer); - else - { - /* FIXME: Need to use some method of double-buffering for the mixer and - * app to hold separate memory, which can be safely transfered - * asynchronously. Currently we just say the app shouldn't write where - * OpenAL's reading, and hope for the best... - */ - std::atomic_thread_fence(std::memory_order_seq_cst); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - { - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - return; - } - - auto usrfmt = DecomposeUserFormat(format); - if(UNLIKELY(!usrfmt)) - { - alSetError(context.get(), AL_INVALID_ENUM, "Invalid format 0x%04x", format); - return; - } - - ALsizei unpack_align{albuf->UnpackAlign.load()}; - ALsizei align{SanitizeAlignment(usrfmt->type, unpack_align)}; - if(UNLIKELY(align < 1)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid unpack alignment %d", unpack_align); - else if(UNLIKELY(long{usrfmt->channels} != long{albuf->mFmtChannels} || - usrfmt->type != albuf->OriginalType)) - alSetError(context.get(), AL_INVALID_ENUM, - "Unpacking data with mismatched format"); - else if(UNLIKELY(align != albuf->OriginalAlign)) - alSetError(context.get(), AL_INVALID_VALUE, - "Unpacking data with alignment %u does not match original alignment %u", - align, albuf->OriginalAlign); - else if(UNLIKELY(albuf->MappedAccess != 0)) - alSetError(context.get(), AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u", - buffer); - else - { - ALsizei num_chans{ChannelsFromFmt(albuf->mFmtChannels)}; - ALsizei frame_size{num_chans * BytesFromFmt(albuf->mFmtType)}; - ALsizei byte_align{ - (albuf->OriginalType == UserFmtIMA4) ? ((align-1)/2 + 4) * num_chans : - (albuf->OriginalType == UserFmtMSADPCM) ? ((align-2)/2 + 7) * num_chans : - (align * frame_size) - }; - - if(UNLIKELY(offset < 0 || length < 0 || offset > albuf->OriginalSize || - length > albuf->OriginalSize-offset)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid data sub-range %d+%d on buffer %u", - offset, length, buffer); - else if(UNLIKELY((offset%byte_align) != 0)) - alSetError(context.get(), AL_INVALID_VALUE, - "Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)", - offset, byte_align, align); - else if(UNLIKELY((length%byte_align) != 0)) - alSetError(context.get(), AL_INVALID_VALUE, - "Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)", - length, byte_align, align); - else - { - /* offset -> byte offset, length -> sample count */ - offset = offset/byte_align * align * frame_size; - length = length/byte_align * align; - - void *dst = albuf->mData.data() + offset; - if(usrfmt->type == UserFmtIMA4 && albuf->mFmtType == FmtShort) - Convert_ALshort_ALima4(static_cast(dst), - static_cast(data), num_chans, length, align); - else if(usrfmt->type == UserFmtMSADPCM && albuf->mFmtType == FmtShort) - Convert_ALshort_ALmsadpcm(static_cast(dst), - static_cast(data), num_chans, length, align); - else - { - assert(long{usrfmt->type} == static_cast(albuf->mFmtType)); - memcpy(dst, data, length * frame_size); - } - } - } -} -END_API_FUNC - - -AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint /*buffer*/, ALuint /*samplerate*/, - ALenum /*internalformat*/, ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, - const ALvoid* /*data*/) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - alSetError(context.get(), AL_INVALID_OPERATION, "alBufferSamplesSOFT not supported"); -} -END_API_FUNC - -AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint /*buffer*/, ALsizei /*offset*/, - ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, const ALvoid* /*data*/) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - alSetError(context.get(), AL_INVALID_OPERATION, "alBufferSubSamplesSOFT not supported"); -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint /*buffer*/, ALsizei /*offset*/, - ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, ALvoid* /*data*/) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - alSetError(context.get(), AL_INVALID_OPERATION, "alGetBufferSamplesSOFT not supported"); -} -END_API_FUNC - -AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum /*format*/) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(!context) return AL_FALSE; - - alSetError(context.get(), AL_INVALID_OPERATION, "alIsBufferFormatSupportedSOFT not supported"); - return AL_FALSE; -} -END_API_FUNC - - -AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat /*value*/) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, - ALfloat /*value1*/, ALfloat /*value2*/, ALfloat /*value3*/) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!values)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); - } -} -END_API_FUNC - - -AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else switch(param) - { - case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: - if(UNLIKELY(value < 0)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid unpack block alignment %d", value); - else - albuf->UnpackAlign.store(value); - break; - - case AL_PACK_BLOCK_ALIGNMENT_SOFT: - if(UNLIKELY(value < 0)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid pack block alignment %d", value); - else - albuf->PackAlign.store(value); - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, - ALint /*value1*/, ALint /*value2*/, ALint /*value3*/) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values) -START_API_FUNC -{ - if(values) - { - switch(param) - { - case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: - case AL_PACK_BLOCK_ALIGNMENT_SOFT: - alBufferi(buffer, param, values[0]); - return; - } - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!values)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_LOOP_POINTS_SOFT: - if(UNLIKELY(ReadRef(&albuf->ref) != 0)) - alSetError(context.get(), AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points", - buffer); - else if(UNLIKELY(values[0] >= values[1] || values[0] < 0 || values[1] > albuf->SampleLen)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid loop point range %d -> %d o buffer %u", - values[0], values[1], buffer); - else - { - albuf->LoopStart = values[0]; - albuf->LoopEnd = values[1]; - } - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", - param); - } -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!value)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!value1 || !value2 || !value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values) -START_API_FUNC -{ - switch(param) - { - case AL_SEC_LENGTH_SOFT: - alGetBufferf(buffer, param, values); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!values)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); - } -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!value)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_FREQUENCY: - *value = albuf->Frequency; - break; - - case AL_BITS: - *value = BytesFromFmt(albuf->mFmtType) * 8; - break; - - case AL_CHANNELS: - *value = ChannelsFromFmt(albuf->mFmtChannels); - break; - - case AL_SIZE: - *value = albuf->SampleLen * FrameSizeFromFmt(albuf->mFmtChannels, albuf->mFmtType); - break; - - case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: - *value = albuf->UnpackAlign.load(); - break; - - case AL_PACK_BLOCK_ALIGNMENT_SOFT: - *value = albuf->PackAlign.load(); - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!value1 || !value2 || !value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values) -START_API_FUNC -{ - switch(param) - { - case AL_FREQUENCY: - case AL_BITS: - case AL_CHANNELS: - case AL_SIZE: - case AL_INTERNAL_FORMAT_SOFT: - case AL_BYTE_LENGTH_SOFT: - case AL_SAMPLE_LENGTH_SOFT: - case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: - case AL_PACK_BLOCK_ALIGNMENT_SOFT: - alGetBufferi(buffer, param, values); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!values)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_LOOP_POINTS_SOFT: - values[0] = albuf->LoopStart; - values[1] = albuf->LoopEnd; - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", - param); - } -} -END_API_FUNC - - -ALsizei BytesFromUserFmt(UserFmtType type) -{ - switch(type) - { - case UserFmtUByte: return sizeof(ALubyte); - case UserFmtShort: return sizeof(ALshort); - case UserFmtFloat: return sizeof(ALfloat); - case UserFmtDouble: return sizeof(ALdouble); - case UserFmtMulaw: return sizeof(ALubyte); - case UserFmtAlaw: return sizeof(ALubyte); - case UserFmtIMA4: break; /* not handled here */ - case UserFmtMSADPCM: break; /* not handled here */ - } - return 0; -} -ALsizei ChannelsFromUserFmt(UserFmtChannels chans) -{ - switch(chans) - { - case UserFmtMono: return 1; - case UserFmtStereo: return 2; - case UserFmtRear: return 2; - case UserFmtQuad: return 4; - case UserFmtX51: return 6; - case UserFmtX61: return 7; - case UserFmtX71: return 8; - case UserFmtBFormat2D: return 3; - case UserFmtBFormat3D: return 4; - } - return 0; -} - -ALsizei BytesFromFmt(FmtType type) -{ - switch(type) - { - case FmtUByte: return sizeof(ALubyte); - case FmtShort: return sizeof(ALshort); - case FmtFloat: return sizeof(ALfloat); - case FmtDouble: return sizeof(ALdouble); - case FmtMulaw: return sizeof(ALubyte); - case FmtAlaw: return sizeof(ALubyte); - } - return 0; -} -ALsizei ChannelsFromFmt(FmtChannels chans) -{ - switch(chans) - { - case FmtMono: return 1; - case FmtStereo: return 2; - case FmtRear: return 2; - case FmtQuad: return 4; - case FmtX51: return 6; - case FmtX61: return 7; - case FmtX71: return 8; - case FmtBFormat2D: return 3; - case FmtBFormat3D: return 4; - } - return 0; -} - - -BufferSubList::~BufferSubList() -{ - uint64_t usemask{~FreeMask}; - while(usemask) - { - ALsizei idx{CTZ64(usemask)}; - al::destroy_at(Buffers+idx); - usemask &= ~(1_u64 << idx); - } - FreeMask = ~usemask; - al_free(Buffers); - Buffers = nullptr; -} diff --git a/OpenAL32/alBuffer.h b/OpenAL32/alBuffer.h deleted file mode 100644 index 1d5873e5..00000000 --- a/OpenAL32/alBuffer.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef AL_BUFFER_H -#define AL_BUFFER_H - -#include - -#include "AL/al.h" - -#include "albyte.h" -#include "almalloc.h" -#include "atomic.h" -#include "inprogext.h" -#include "vector.h" - - -/* User formats */ -enum UserFmtType : unsigned char { - UserFmtUByte, - UserFmtShort, - UserFmtFloat, - UserFmtDouble, - UserFmtMulaw, - UserFmtAlaw, - UserFmtIMA4, - UserFmtMSADPCM, -}; -enum UserFmtChannels : unsigned char { - UserFmtMono, - UserFmtStereo, - UserFmtRear, - UserFmtQuad, - UserFmtX51, /* (WFX order) */ - UserFmtX61, /* (WFX order) */ - UserFmtX71, /* (WFX order) */ - UserFmtBFormat2D, /* WXY */ - UserFmtBFormat3D, /* WXYZ */ -}; - -ALsizei BytesFromUserFmt(UserFmtType type); -ALsizei ChannelsFromUserFmt(UserFmtChannels chans); -inline ALsizei FrameSizeFromUserFmt(UserFmtChannels chans, UserFmtType type) -{ return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type); } - - -/* Storable formats */ -enum FmtType : unsigned char { - FmtUByte = UserFmtUByte, - FmtShort = UserFmtShort, - FmtFloat = UserFmtFloat, - FmtDouble = UserFmtDouble, - FmtMulaw = UserFmtMulaw, - FmtAlaw = UserFmtAlaw, -}; -enum FmtChannels : unsigned char { - FmtMono = UserFmtMono, - FmtStereo = UserFmtStereo, - FmtRear = UserFmtRear, - FmtQuad = UserFmtQuad, - FmtX51 = UserFmtX51, - FmtX61 = UserFmtX61, - FmtX71 = UserFmtX71, - FmtBFormat2D = UserFmtBFormat2D, - FmtBFormat3D = UserFmtBFormat3D, -}; -#define MAX_INPUT_CHANNELS (8) - -/* DevFmtType traits, providing the type, etc given a DevFmtType. */ -template -struct FmtTypeTraits { }; - -template<> -struct FmtTypeTraits { using Type = ALubyte; }; -template<> -struct FmtTypeTraits { using Type = ALshort; }; -template<> -struct FmtTypeTraits { using Type = ALfloat; }; -template<> -struct FmtTypeTraits { using Type = ALdouble; }; -template<> -struct FmtTypeTraits { using Type = ALubyte; }; -template<> -struct FmtTypeTraits { using Type = ALubyte; }; - - -ALsizei BytesFromFmt(FmtType type); -ALsizei ChannelsFromFmt(FmtChannels chans); -inline ALsizei FrameSizeFromFmt(FmtChannels chans, FmtType type) -{ return ChannelsFromFmt(chans) * BytesFromFmt(type); } - - -struct ALbuffer { - al::vector mData; - - ALsizei Frequency{0}; - ALbitfieldSOFT Access{0u}; - ALsizei SampleLen{0}; - - FmtChannels mFmtChannels{}; - FmtType mFmtType{}; - - UserFmtType OriginalType{}; - ALsizei OriginalSize{0}; - ALsizei OriginalAlign{0}; - - ALsizei LoopStart{0}; - ALsizei LoopEnd{0}; - - std::atomic UnpackAlign{0}; - std::atomic PackAlign{0}; - - ALbitfieldSOFT MappedAccess{0u}; - ALsizei MappedOffset{0}; - ALsizei MappedSize{0}; - - /* Number of times buffer was attached to a source (deletion can only occur when 0) */ - RefCount ref{0u}; - - /* Self ID */ - ALuint id{0}; -}; - -#endif diff --git a/OpenAL32/alEffect.cpp b/OpenAL32/alEffect.cpp deleted file mode 100644 index 4a75f69f..00000000 --- a/OpenAL32/alEffect.cpp +++ /dev/null @@ -1,742 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "alEffect.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" -#include "AL/efx-presets.h" -#include "AL/efx.h" - -#include "alError.h" -#include "alcmain.h" -#include "alcontext.h" -#include "alexcpt.h" -#include "almalloc.h" -#include "alnumeric.h" -#include "effects/base.h" -#include "logging.h" -#include "opthelpers.h" -#include "vector.h" - - -const EffectList gEffectList[15]{ - { "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB }, - { "reverb", REVERB_EFFECT, AL_EFFECT_REVERB }, - { "autowah", AUTOWAH_EFFECT, AL_EFFECT_AUTOWAH }, - { "chorus", CHORUS_EFFECT, AL_EFFECT_CHORUS }, - { "compressor", COMPRESSOR_EFFECT, AL_EFFECT_COMPRESSOR }, - { "distortion", DISTORTION_EFFECT, AL_EFFECT_DISTORTION }, - { "echo", ECHO_EFFECT, AL_EFFECT_ECHO }, - { "equalizer", EQUALIZER_EFFECT, AL_EFFECT_EQUALIZER }, - { "flanger", FLANGER_EFFECT, AL_EFFECT_FLANGER }, - { "fshifter", FSHIFTER_EFFECT, AL_EFFECT_FREQUENCY_SHIFTER }, - { "modulator", MODULATOR_EFFECT, AL_EFFECT_RING_MODULATOR }, - { "pshifter", PSHIFTER_EFFECT, AL_EFFECT_PITCH_SHIFTER }, - { "vmorpher", VMORPHER_EFFECT, AL_EFFECT_VOCAL_MORPHER }, - { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT }, - { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_DIALOGUE }, -}; - -ALboolean DisabledEffects[MAX_EFFECTS]; - -namespace { - -constexpr struct FactoryItem { - ALenum Type; - EffectStateFactory* (&GetFactory)(void); -} FactoryList[] = { - { AL_EFFECT_NULL, NullStateFactory_getFactory }, - { AL_EFFECT_EAXREVERB, ReverbStateFactory_getFactory }, - { AL_EFFECT_REVERB, StdReverbStateFactory_getFactory }, - { AL_EFFECT_AUTOWAH, AutowahStateFactory_getFactory }, - { AL_EFFECT_CHORUS, ChorusStateFactory_getFactory }, - { AL_EFFECT_COMPRESSOR, CompressorStateFactory_getFactory }, - { AL_EFFECT_DISTORTION, DistortionStateFactory_getFactory }, - { AL_EFFECT_ECHO, EchoStateFactory_getFactory }, - { AL_EFFECT_EQUALIZER, EqualizerStateFactory_getFactory }, - { AL_EFFECT_FLANGER, FlangerStateFactory_getFactory }, - { AL_EFFECT_FREQUENCY_SHIFTER, FshifterStateFactory_getFactory }, - { AL_EFFECT_RING_MODULATOR, ModulatorStateFactory_getFactory }, - { AL_EFFECT_PITCH_SHIFTER, PshifterStateFactory_getFactory}, - { AL_EFFECT_VOCAL_MORPHER, VmorpherStateFactory_getFactory}, - { AL_EFFECT_DEDICATED_DIALOGUE, DedicatedStateFactory_getFactory }, - { AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedStateFactory_getFactory } -}; - - -template -void ALeffect_setParami(ALeffect *effect, T&& ...args) -{ effect->vtab->setParami(&effect->Props, std::forward(args)...); } -template -void ALeffect_setParamiv(ALeffect *effect, T&& ...args) -{ effect->vtab->setParamiv(&effect->Props, std::forward(args)...); } -template -void ALeffect_setParamf(ALeffect *effect, T&& ...args) -{ effect->vtab->setParamf(&effect->Props, std::forward(args)...); } -template -void ALeffect_setParamfv(ALeffect *effect, T&& ...args) -{ effect->vtab->setParamfv(&effect->Props, std::forward(args)...); } - -template -void ALeffect_getParami(const ALeffect *effect, T&& ...args) -{ effect->vtab->getParami(&effect->Props, std::forward(args)...); } -template -void ALeffect_getParamiv(const ALeffect *effect, T&& ...args) -{ effect->vtab->getParamiv(&effect->Props, std::forward(args)...); } -template -void ALeffect_getParamf(const ALeffect *effect, T&& ...args) -{ effect->vtab->getParamf(&effect->Props, std::forward(args)...); } -template -void ALeffect_getParamfv(const ALeffect *effect, T&& ...args) -{ effect->vtab->getParamfv(&effect->Props, std::forward(args)...); } - - -void InitEffectParams(ALeffect *effect, ALenum type) -{ - EffectStateFactory *factory = getFactoryByType(type); - if(factory) - { - effect->Props = factory->getDefaultProps(); - effect->vtab = factory->getEffectVtable(); - } - else - { - effect->Props = EffectProps {}; - effect->vtab = nullptr; - } - effect->type = type; -} - -ALeffect *AllocEffect(ALCcontext *context) -{ - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - auto sublist = std::find_if(device->EffectList.begin(), device->EffectList.end(), - [](const EffectSubList &entry) noexcept -> bool - { return entry.FreeMask != 0; } - ); - - auto lidx = static_cast(std::distance(device->EffectList.begin(), sublist)); - ALeffect *effect{nullptr}; - ALsizei slidx{0}; - if(LIKELY(sublist != device->EffectList.end())) - { - slidx = CTZ64(sublist->FreeMask); - effect = sublist->Effects + slidx; - } - else - { - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ - if(UNLIKELY(device->EffectList.size() >= 1<<25)) - { - alSetError(context, AL_OUT_OF_MEMORY, "Too many effects allocated"); - return nullptr; - } - device->EffectList.emplace_back(); - sublist = device->EffectList.end() - 1; - sublist->FreeMask = ~0_u64; - sublist->Effects = static_cast(al_calloc(16, sizeof(ALeffect)*64)); - if(UNLIKELY(!sublist->Effects)) - { - device->EffectList.pop_back(); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect batch"); - return nullptr; - } - - slidx = 0; - effect = sublist->Effects + slidx; - } - - effect = new (effect) ALeffect{}; - InitEffectParams(effect, AL_EFFECT_NULL); - - /* Add 1 to avoid effect ID 0. */ - effect->id = ((lidx<<6) | slidx) + 1; - - sublist->FreeMask &= ~(1_u64 << slidx); - - return effect; -} - -void FreeEffect(ALCdevice *device, ALeffect *effect) -{ - ALuint id = effect->id - 1; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; - - al::destroy_at(effect); - - device->EffectList[lidx].FreeMask |= 1_u64 << slidx; -} - -inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) -{ - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= device->EffectList.size())) - return nullptr; - EffectSubList &sublist = device->EffectList[lidx]; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) - return nullptr; - return sublist.Effects + slidx; -} - -} // namespace - -AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(UNLIKELY(n < 0)) - { - alSetError(context.get(), AL_INVALID_VALUE, "Generating %d effects", n); - return; - } - - if(LIKELY(n == 1)) - { - /* Special handling for the easy and normal case. */ - ALeffect *effect = AllocEffect(context.get()); - if(effect) effects[0] = effect->id; - } - else if(n > 1) - { - /* Store the allocated buffer IDs in a separate local list, to avoid - * modifying the user storage in case of failure. - */ - al::vector ids; - ids.reserve(n); - do { - ALeffect *effect = AllocEffect(context.get()); - if(!effect) - { - alDeleteEffects(static_cast(ids.size()), ids.data()); - return; - } - - ids.emplace_back(effect->id); - } while(--n); - std::copy(ids.begin(), ids.end(), effects); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(UNLIKELY(n < 0)) - { - alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d effects", n); - return; - } - if(UNLIKELY(n == 0)) - return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - - /* First try to find any effects that are invalid. */ - const ALuint *effects_end = effects + n; - auto inveffect = std::find_if(effects, effects_end, - [device, &context](ALuint eid) -> bool - { - if(!eid) return false; - ALeffect *effect{LookupEffect(device, eid)}; - if(UNLIKELY(!effect)) - { - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", eid); - return true; - } - return false; - } - ); - if(LIKELY(inveffect == effects_end)) - { - /* All good. Delete non-0 effect IDs. */ - std::for_each(effects, effects_end, - [device](ALuint eid) -> void - { - ALeffect *effect{eid ? LookupEffect(device, eid) : nullptr}; - if(effect) FreeEffect(device, effect); - } - ); - } -} -END_API_FUNC - -AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(LIKELY(context)) - { - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - if(!effect || LookupEffect(device, effect)) - return AL_TRUE; - } - return AL_FALSE; -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - - ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - if(param == AL_EFFECT_TYPE) - { - ALboolean isOk{value == AL_EFFECT_NULL}; - if(!isOk) - { - for(const EffectList &effectitem : gEffectList) - { - if(value == effectitem.val && !DisabledEffects[effectitem.type]) - { - isOk = AL_TRUE; - break; - } - } - } - - if(isOk) - InitEffectParams(aleffect, value); - else - alSetError(context.get(), AL_INVALID_VALUE, "Effect type 0x%04x not supported", value); - } - else - { - /* Call the appropriate handler */ - ALeffect_setParami(aleffect, context.get(), param, value); - } - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *values) -START_API_FUNC -{ - switch(param) - { - case AL_EFFECT_TYPE: - alEffecti(effect, param, values[0]); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - - ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - /* Call the appropriate handler */ - ALeffect_setParamiv(aleffect, context.get(), param, values); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - - ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - /* Call the appropriate handler */ - ALeffect_setParamf(aleffect, context.get(), param, value); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - - ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - /* Call the appropriate handler */ - ALeffect_setParamfv(aleffect, context.get(), param, values); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - - const ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - if(param == AL_EFFECT_TYPE) - *value = aleffect->type; - else - { - /* Call the appropriate handler */ - ALeffect_getParami(aleffect, context.get(), param, value); - } - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *values) -START_API_FUNC -{ - switch(param) - { - case AL_EFFECT_TYPE: - alGetEffecti(effect, param, values); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - - const ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - /* Call the appropriate handler */ - ALeffect_getParamiv(aleffect, context.get(), param, values); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - - const ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - /* Call the appropriate handler */ - ALeffect_getParamf(aleffect, context.get(), param, value); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - - const ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - /* Call the appropriate handler */ - ALeffect_getParamfv(aleffect, context.get(), param, values); - } -} -END_API_FUNC - - -void InitEffect(ALeffect *effect) -{ - InitEffectParams(effect, AL_EFFECT_NULL); -} - -EffectSubList::~EffectSubList() -{ - uint64_t usemask{~FreeMask}; - while(usemask) - { - ALsizei idx = CTZ64(usemask); - al::destroy_at(Effects+idx); - usemask &= ~(1_u64 << idx); - } - FreeMask = ~usemask; - al_free(Effects); - Effects = nullptr; -} - - -EffectStateFactory *getFactoryByType(ALenum type) -{ - auto iter = std::find_if(std::begin(FactoryList), std::end(FactoryList), - [type](const FactoryItem &item) noexcept -> bool - { return item.Type == type; } - ); - return (iter != std::end(FactoryList)) ? iter->GetFactory() : nullptr; -} - - -#define DECL(x) { #x, EFX_REVERB_PRESET_##x } -static const struct { - const char name[32]; - EFXEAXREVERBPROPERTIES props; -} reverblist[] = { - DECL(GENERIC), - DECL(PADDEDCELL), - DECL(ROOM), - DECL(BATHROOM), - DECL(LIVINGROOM), - DECL(STONEROOM), - DECL(AUDITORIUM), - DECL(CONCERTHALL), - DECL(CAVE), - DECL(ARENA), - DECL(HANGAR), - DECL(CARPETEDHALLWAY), - DECL(HALLWAY), - DECL(STONECORRIDOR), - DECL(ALLEY), - DECL(FOREST), - DECL(CITY), - DECL(MOUNTAINS), - DECL(QUARRY), - DECL(PLAIN), - DECL(PARKINGLOT), - DECL(SEWERPIPE), - DECL(UNDERWATER), - DECL(DRUGGED), - DECL(DIZZY), - DECL(PSYCHOTIC), - - DECL(CASTLE_SMALLROOM), - DECL(CASTLE_SHORTPASSAGE), - DECL(CASTLE_MEDIUMROOM), - DECL(CASTLE_LARGEROOM), - DECL(CASTLE_LONGPASSAGE), - DECL(CASTLE_HALL), - DECL(CASTLE_CUPBOARD), - DECL(CASTLE_COURTYARD), - DECL(CASTLE_ALCOVE), - - DECL(FACTORY_SMALLROOM), - DECL(FACTORY_SHORTPASSAGE), - DECL(FACTORY_MEDIUMROOM), - DECL(FACTORY_LARGEROOM), - DECL(FACTORY_LONGPASSAGE), - DECL(FACTORY_HALL), - DECL(FACTORY_CUPBOARD), - DECL(FACTORY_COURTYARD), - DECL(FACTORY_ALCOVE), - - DECL(ICEPALACE_SMALLROOM), - DECL(ICEPALACE_SHORTPASSAGE), - DECL(ICEPALACE_MEDIUMROOM), - DECL(ICEPALACE_LARGEROOM), - DECL(ICEPALACE_LONGPASSAGE), - DECL(ICEPALACE_HALL), - DECL(ICEPALACE_CUPBOARD), - DECL(ICEPALACE_COURTYARD), - DECL(ICEPALACE_ALCOVE), - - DECL(SPACESTATION_SMALLROOM), - DECL(SPACESTATION_SHORTPASSAGE), - DECL(SPACESTATION_MEDIUMROOM), - DECL(SPACESTATION_LARGEROOM), - DECL(SPACESTATION_LONGPASSAGE), - DECL(SPACESTATION_HALL), - DECL(SPACESTATION_CUPBOARD), - DECL(SPACESTATION_ALCOVE), - - DECL(WOODEN_SMALLROOM), - DECL(WOODEN_SHORTPASSAGE), - DECL(WOODEN_MEDIUMROOM), - DECL(WOODEN_LARGEROOM), - DECL(WOODEN_LONGPASSAGE), - DECL(WOODEN_HALL), - DECL(WOODEN_CUPBOARD), - DECL(WOODEN_COURTYARD), - DECL(WOODEN_ALCOVE), - - DECL(SPORT_EMPTYSTADIUM), - DECL(SPORT_SQUASHCOURT), - DECL(SPORT_SMALLSWIMMINGPOOL), - DECL(SPORT_LARGESWIMMINGPOOL), - DECL(SPORT_GYMNASIUM), - DECL(SPORT_FULLSTADIUM), - DECL(SPORT_STADIUMTANNOY), - - DECL(PREFAB_WORKSHOP), - DECL(PREFAB_SCHOOLROOM), - DECL(PREFAB_PRACTISEROOM), - DECL(PREFAB_OUTHOUSE), - DECL(PREFAB_CARAVAN), - - DECL(DOME_TOMB), - DECL(PIPE_SMALL), - DECL(DOME_SAINTPAULS), - DECL(PIPE_LONGTHIN), - DECL(PIPE_LARGE), - DECL(PIPE_RESONANT), - - DECL(OUTDOORS_BACKYARD), - DECL(OUTDOORS_ROLLINGPLAINS), - DECL(OUTDOORS_DEEPCANYON), - DECL(OUTDOORS_CREEK), - DECL(OUTDOORS_VALLEY), - - DECL(MOOD_HEAVEN), - DECL(MOOD_HELL), - DECL(MOOD_MEMORY), - - DECL(DRIVING_COMMENTATOR), - DECL(DRIVING_PITGARAGE), - DECL(DRIVING_INCAR_RACER), - DECL(DRIVING_INCAR_SPORTS), - DECL(DRIVING_INCAR_LUXURY), - DECL(DRIVING_FULLGRANDSTAND), - DECL(DRIVING_EMPTYGRANDSTAND), - DECL(DRIVING_TUNNEL), - - DECL(CITY_STREETS), - DECL(CITY_SUBWAY), - DECL(CITY_MUSEUM), - DECL(CITY_LIBRARY), - DECL(CITY_UNDERPASS), - DECL(CITY_ABANDONED), - - DECL(DUSTYROOM), - DECL(CHAPEL), - DECL(SMALLWATERROOM), -}; -#undef DECL - -void LoadReverbPreset(const char *name, ALeffect *effect) -{ - if(strcasecmp(name, "NONE") == 0) - { - InitEffectParams(effect, AL_EFFECT_NULL); - TRACE("Loading reverb '%s'\n", "NONE"); - return; - } - - if(!DisabledEffects[EAXREVERB_EFFECT]) - InitEffectParams(effect, AL_EFFECT_EAXREVERB); - else if(!DisabledEffects[REVERB_EFFECT]) - InitEffectParams(effect, AL_EFFECT_REVERB); - else - InitEffectParams(effect, AL_EFFECT_NULL); - for(const auto &reverbitem : reverblist) - { - const EFXEAXREVERBPROPERTIES *props; - - if(strcasecmp(name, reverbitem.name) != 0) - continue; - - TRACE("Loading reverb '%s'\n", reverbitem.name); - props = &reverbitem.props; - effect->Props.Reverb.Density = props->flDensity; - effect->Props.Reverb.Diffusion = props->flDiffusion; - effect->Props.Reverb.Gain = props->flGain; - effect->Props.Reverb.GainHF = props->flGainHF; - effect->Props.Reverb.GainLF = props->flGainLF; - effect->Props.Reverb.DecayTime = props->flDecayTime; - effect->Props.Reverb.DecayHFRatio = props->flDecayHFRatio; - effect->Props.Reverb.DecayLFRatio = props->flDecayLFRatio; - effect->Props.Reverb.ReflectionsGain = props->flReflectionsGain; - effect->Props.Reverb.ReflectionsDelay = props->flReflectionsDelay; - effect->Props.Reverb.ReflectionsPan[0] = props->flReflectionsPan[0]; - effect->Props.Reverb.ReflectionsPan[1] = props->flReflectionsPan[1]; - effect->Props.Reverb.ReflectionsPan[2] = props->flReflectionsPan[2]; - effect->Props.Reverb.LateReverbGain = props->flLateReverbGain; - effect->Props.Reverb.LateReverbDelay = props->flLateReverbDelay; - effect->Props.Reverb.LateReverbPan[0] = props->flLateReverbPan[0]; - effect->Props.Reverb.LateReverbPan[1] = props->flLateReverbPan[1]; - effect->Props.Reverb.LateReverbPan[2] = props->flLateReverbPan[2]; - effect->Props.Reverb.EchoTime = props->flEchoTime; - effect->Props.Reverb.EchoDepth = props->flEchoDepth; - effect->Props.Reverb.ModulationTime = props->flModulationTime; - effect->Props.Reverb.ModulationDepth = props->flModulationDepth; - effect->Props.Reverb.AirAbsorptionGainHF = props->flAirAbsorptionGainHF; - effect->Props.Reverb.HFReference = props->flHFReference; - effect->Props.Reverb.LFReference = props->flLFReference; - effect->Props.Reverb.RoomRolloffFactor = props->flRoomRolloffFactor; - effect->Props.Reverb.DecayHFLimit = props->iDecayHFLimit; - return; - } - - WARN("Reverb preset '%s' not found\n", name); -} diff --git a/OpenAL32/alEffect.h b/OpenAL32/alEffect.h deleted file mode 100644 index 270b8e20..00000000 --- a/OpenAL32/alEffect.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef AL_EFFECT_H -#define AL_EFFECT_H - -#include "AL/al.h" -#include "AL/efx.h" - -#include "effects/base.h" - - -enum { - EAXREVERB_EFFECT = 0, - REVERB_EFFECT, - AUTOWAH_EFFECT, - CHORUS_EFFECT, - COMPRESSOR_EFFECT, - DISTORTION_EFFECT, - ECHO_EFFECT, - EQUALIZER_EFFECT, - FLANGER_EFFECT, - FSHIFTER_EFFECT, - MODULATOR_EFFECT, - PSHIFTER_EFFECT, - VMORPHER_EFFECT, - DEDICATED_EFFECT, - - MAX_EFFECTS -}; -extern ALboolean DisabledEffects[MAX_EFFECTS]; - -extern ALfloat ReverbBoost; - -struct EffectList { - const char name[16]; - int type; - ALenum val; -}; -extern const EffectList gEffectList[15]; - - -struct ALeffect { - // Effect type (AL_EFFECT_NULL, ...) - ALenum type{AL_EFFECT_NULL}; - - EffectProps Props{}; - - const EffectVtable *vtab{nullptr}; - - /* Self ID */ - ALuint id{0u}; -}; - -inline ALboolean IsReverbEffect(ALenum type) -{ return type == AL_EFFECT_REVERB || type == AL_EFFECT_EAXREVERB; } - -EffectStateFactory *getFactoryByType(ALenum type); - -void InitEffect(ALeffect *effect); - -void LoadReverbPreset(const char *name, ALeffect *effect); - -#endif diff --git a/OpenAL32/alError.cpp b/OpenAL32/alError.cpp deleted file mode 100644 index 159aee52..00000000 --- a/OpenAL32/alError.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2000 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "alError.h" - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" - -#include "alcmain.h" -#include "alcontext.h" -#include "alexcpt.h" -#include "almalloc.h" -#include "inprogext.h" -#include "logging.h" -#include "opthelpers.h" -#include "vector.h" - - -bool TrapALError{false}; - -void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) -{ - auto message = al::vector(256); - - va_list args, args2; - va_start(args, msg); - va_copy(args2, args); - int msglen{std::vsnprintf(message.data(), message.size(), msg, args)}; - if(msglen >= 0 && static_cast(msglen) >= message.size()) - { - message.resize(static_cast(msglen) + 1u); - msglen = std::vsnprintf(message.data(), message.size(), msg, args2); - } - va_end(args2); - va_end(args); - - if(msglen >= 0) msg = message.data(); - else msg = ""; - msglen = static_cast(strlen(msg)); - - WARN("Error generated on context %p, code 0x%04x, \"%s\"\n", context, errorCode, msg); - if(TrapALError) - { -#ifdef _WIN32 - /* DebugBreak will cause an exception if there is no debugger */ - if(IsDebuggerPresent()) - DebugBreak(); -#elif defined(SIGTRAP) - raise(SIGTRAP); -#endif - } - - ALenum curerr{AL_NO_ERROR}; - context->LastError.compare_exchange_strong(curerr, errorCode); - if((context->EnabledEvts.load(std::memory_order_relaxed)&EventType_Error)) - { - std::lock_guard _{context->EventCbLock}; - ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; - if((enabledevts&EventType_Error) && context->EventCb) - (*context->EventCb)(AL_EVENT_TYPE_ERROR_SOFT, 0, errorCode, msglen, msg, - context->EventParam); - } -} - -AL_API ALenum AL_APIENTRY alGetError(void) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) - { - constexpr ALenum deferror{AL_INVALID_OPERATION}; - WARN("Querying error state on null context (implicitly 0x%04x)\n", deferror); - if(TrapALError) - { -#ifdef _WIN32 - if(IsDebuggerPresent()) - DebugBreak(); -#elif defined(SIGTRAP) - raise(SIGTRAP); -#endif - } - return deferror; - } - - return context->LastError.exchange(AL_NO_ERROR); -} -END_API_FUNC diff --git a/OpenAL32/alError.h b/OpenAL32/alError.h deleted file mode 100644 index 6408b60c..00000000 --- a/OpenAL32/alError.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef AL_ERROR_H -#define AL_ERROR_H - -#include "AL/al.h" -#include "AL/alc.h" - -#include "logging.h" - - -extern bool TrapALError; - -void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) DECL_FORMAT(printf, 3, 4); - -#define SETERR_GOTO(ctx, err, lbl, ...) do { \ - alSetError((ctx), (err), __VA_ARGS__); \ - goto lbl; \ -} while(0) - -#define SETERR_RETURN(ctx, err, retval, ...) do { \ - alSetError((ctx), (err), __VA_ARGS__); \ - return retval; \ -} while(0) - -#endif diff --git a/OpenAL32/alExtension.cpp b/OpenAL32/alExtension.cpp deleted file mode 100644 index 80681090..00000000 --- a/OpenAL32/alExtension.cpp +++ /dev/null @@ -1,80 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" - -#include "alError.h" -#include "alcontext.h" -#include "alexcpt.h" -#include "opthelpers.h" - - -AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return AL_FALSE; - - if(!extName) - SETERR_RETURN(context.get(), AL_INVALID_VALUE, AL_FALSE, "NULL pointer"); - - size_t len{strlen(extName)}; - const char *ptr{context->ExtensionList}; - while(ptr && *ptr) - { - if(strncasecmp(ptr, extName, len) == 0 && - (ptr[len] == '\0' || isspace(ptr[len]))) - return AL_TRUE; - - if((ptr=strchr(ptr, ' ')) != nullptr) - { - do { - ++ptr; - } while(isspace(*ptr)); - } - } - - return AL_FALSE; -} -END_API_FUNC - - -AL_API ALvoid* AL_APIENTRY alGetProcAddress(const ALchar *funcName) -START_API_FUNC -{ - if(!funcName) return nullptr; - return alcGetProcAddress(nullptr, funcName); -} -END_API_FUNC - -AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *enumName) -START_API_FUNC -{ - if(!enumName) return static_cast(0); - return alcGetEnumValue(nullptr, enumName); -} -END_API_FUNC diff --git a/OpenAL32/alFilter.cpp b/OpenAL32/alFilter.cpp deleted file mode 100644 index 31fbaf21..00000000 --- a/OpenAL32/alFilter.cpp +++ /dev/null @@ -1,665 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "alFilter.h" - -#include -#include -#include -#include -#include -#include - -#include "AL/efx.h" - -#include "alError.h" -#include "alcmain.h" -#include "alcontext.h" -#include "alexcpt.h" -#include "almalloc.h" -#include "alnumeric.h" -#include "opthelpers.h" -#include "vector.h" - - -namespace { - -#define FILTER_MIN_GAIN 0.0f -#define FILTER_MAX_GAIN 4.0f /* +12dB */ - -void ALlowpass_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } -void ALlowpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } -void ALlowpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_LOWPASS_GAIN: - if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gain %f out of range", val); - filter->Gain = val; - break; - - case AL_LOWPASS_GAINHF: - if(!(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gainhf %f out of range", val); - filter->GainHF = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param); - } -} -void ALlowpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) -{ ALlowpass_setParamf(filter, context, param, vals[0]); } - -void ALlowpass_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } -void ALlowpass_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } -void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_LOWPASS_GAIN: - *val = filter->Gain; - break; - - case AL_LOWPASS_GAINHF: - *val = filter->GainHF; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param); - } -} -void ALlowpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) -{ ALlowpass_getParamf(filter, context, param, vals); } - -DEFINE_ALFILTER_VTABLE(ALlowpass); - - -void ALhighpass_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } -void ALhighpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } -void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_HIGHPASS_GAIN: - if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gain out of range"); - filter->Gain = val; - break; - - case AL_HIGHPASS_GAINLF: - if(!(val >= AL_HIGHPASS_MIN_GAINLF && val <= AL_HIGHPASS_MAX_GAINLF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gainlf out of range"); - filter->GainLF = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param); - } -} -void ALhighpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) -{ ALhighpass_setParamf(filter, context, param, vals[0]); } - -void ALhighpass_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } -void ALhighpass_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } -void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_HIGHPASS_GAIN: - *val = filter->Gain; - break; - - case AL_HIGHPASS_GAINLF: - *val = filter->GainLF; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param); - } -} -void ALhighpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) -{ ALhighpass_getParamf(filter, context, param, vals); } - -DEFINE_ALFILTER_VTABLE(ALhighpass); - - -void ALbandpass_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } -void ALbandpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } -void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_BANDPASS_GAIN: - if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gain out of range"); - filter->Gain = val; - break; - - case AL_BANDPASS_GAINHF: - if(!(val >= AL_BANDPASS_MIN_GAINHF && val <= AL_BANDPASS_MAX_GAINHF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainhf out of range"); - filter->GainHF = val; - break; - - case AL_BANDPASS_GAINLF: - if(!(val >= AL_BANDPASS_MIN_GAINLF && val <= AL_BANDPASS_MAX_GAINLF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainlf out of range"); - filter->GainLF = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param); - } -} -void ALbandpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) -{ ALbandpass_setParamf(filter, context, param, vals[0]); } - -void ALbandpass_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } -void ALbandpass_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } -void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_BANDPASS_GAIN: - *val = filter->Gain; - break; - - case AL_BANDPASS_GAINHF: - *val = filter->GainHF; - break; - - case AL_BANDPASS_GAINLF: - *val = filter->GainLF; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param); - } -} -void ALbandpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) -{ ALbandpass_getParamf(filter, context, param, vals); } - -DEFINE_ALFILTER_VTABLE(ALbandpass); - - -void ALnullfilter_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -void ALnullfilter_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -void ALnullfilter_setParamf(ALfilter*, ALCcontext *context, ALenum param, ALfloat) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -void ALnullfilter_setParamfv(ALfilter*, ALCcontext *context, ALenum param, const ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } - -void ALnullfilter_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -void ALnullfilter_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -void ALnullfilter_getParamf(ALfilter*, ALCcontext *context, ALenum param, ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -void ALnullfilter_getParamfv(ALfilter*, ALCcontext *context, ALenum param, ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } - -DEFINE_ALFILTER_VTABLE(ALnullfilter); - - -void InitFilterParams(ALfilter *filter, ALenum type) -{ - if(type == AL_FILTER_LOWPASS) - { - filter->Gain = AL_LOWPASS_DEFAULT_GAIN; - filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF; - filter->HFReference = LOWPASSFREQREF; - filter->GainLF = 1.0f; - filter->LFReference = HIGHPASSFREQREF; - filter->vtab = &ALlowpass_vtable; - } - else if(type == AL_FILTER_HIGHPASS) - { - filter->Gain = AL_HIGHPASS_DEFAULT_GAIN; - filter->GainHF = 1.0f; - filter->HFReference = LOWPASSFREQREF; - filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF; - filter->LFReference = HIGHPASSFREQREF; - filter->vtab = &ALhighpass_vtable; - } - else if(type == AL_FILTER_BANDPASS) - { - filter->Gain = AL_BANDPASS_DEFAULT_GAIN; - filter->GainHF = AL_BANDPASS_DEFAULT_GAINHF; - filter->HFReference = LOWPASSFREQREF; - filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF; - filter->LFReference = HIGHPASSFREQREF; - filter->vtab = &ALbandpass_vtable; - } - else - { - filter->Gain = 1.0f; - filter->GainHF = 1.0f; - filter->HFReference = LOWPASSFREQREF; - filter->GainLF = 1.0f; - filter->LFReference = HIGHPASSFREQREF; - filter->vtab = &ALnullfilter_vtable; - } - filter->type = type; -} - -ALfilter *AllocFilter(ALCcontext *context) -{ - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - auto sublist = std::find_if(device->FilterList.begin(), device->FilterList.end(), - [](const FilterSubList &entry) noexcept -> bool - { return entry.FreeMask != 0; } - ); - - auto lidx = static_cast(std::distance(device->FilterList.begin(), sublist)); - ALfilter *filter{nullptr}; - ALsizei slidx{0}; - if(LIKELY(sublist != device->FilterList.end())) - { - slidx = CTZ64(sublist->FreeMask); - filter = sublist->Filters + slidx; - } - else - { - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ - if(UNLIKELY(device->FilterList.size() >= 1<<25)) - { - alSetError(context, AL_OUT_OF_MEMORY, "Too many filters allocated"); - return nullptr; - } - device->FilterList.emplace_back(); - sublist = device->FilterList.end() - 1; - sublist->FreeMask = ~0_u64; - sublist->Filters = static_cast(al_calloc(16, sizeof(ALfilter)*64)); - if(UNLIKELY(!sublist->Filters)) - { - device->FilterList.pop_back(); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate filter batch"); - return nullptr; - } - - slidx = 0; - filter = sublist->Filters + slidx; - } - - filter = new (filter) ALfilter{}; - InitFilterParams(filter, AL_FILTER_NULL); - - /* Add 1 to avoid filter ID 0. */ - filter->id = ((lidx<<6) | slidx) + 1; - - sublist->FreeMask &= ~(1_u64 << slidx); - - return filter; -} - -void FreeFilter(ALCdevice *device, ALfilter *filter) -{ - ALuint id = filter->id - 1; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; - - al::destroy_at(filter); - - device->FilterList[lidx].FreeMask |= 1_u64 << slidx; -} - - -inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) -{ - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= device->FilterList.size())) - return nullptr; - FilterSubList &sublist = device->FilterList[lidx]; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) - return nullptr; - return sublist.Filters + slidx; -} - -} // namespace - -AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(UNLIKELY(n < 0)) - { - alSetError(context.get(), AL_INVALID_VALUE, "Generating %d filters", n); - return; - } - - if(LIKELY(n == 1)) - { - /* Special handling for the easy and normal case. */ - ALfilter *filter = AllocFilter(context.get()); - if(filter) filters[0] = filter->id; - } - else if(n > 1) - { - /* Store the allocated buffer IDs in a separate local list, to avoid - * modifying the user storage in case of failure. - */ - al::vector ids; - ids.reserve(n); - do { - ALfilter *filter = AllocFilter(context.get()); - if(!filter) - { - alDeleteFilters(static_cast(ids.size()), ids.data()); - return; - } - - ids.emplace_back(filter->id); - } while(--n); - std::copy(ids.begin(), ids.end(), filters); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(UNLIKELY(n < 0)) - { - alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d filters", n); - return; - } - if(UNLIKELY(n == 0)) - return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - - /* First try to find any filters that are invalid. */ - const ALuint *filters_end = filters + n; - auto invflt = std::find_if(filters, filters_end, - [device, &context](ALuint fid) -> bool - { - if(!fid) return false; - ALfilter *filter{LookupFilter(device, fid)}; - if(UNLIKELY(!filter)) - { - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", fid); - return true; - } - return false; - } - ); - if(LIKELY(invflt == filters_end)) - { - /* All good. Delete non-0 filter IDs. */ - std::for_each(filters, filters_end, - [device](ALuint fid) -> void - { - ALfilter *filter{fid ? LookupFilter(device, fid) : nullptr}; - if(filter) FreeFilter(device, filter); - } - ); - } -} -END_API_FUNC - -AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(LIKELY(context)) - { - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - if(!filter || LookupFilter(device, filter)) - return AL_TRUE; - } - return AL_FALSE; -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - - ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - if(param == AL_FILTER_TYPE) - { - if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS || - value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS) - InitFilterParams(alfilt, value); - else - alSetError(context.get(), AL_INVALID_VALUE, "Invalid filter type 0x%04x", value); - } - else - { - /* Call the appropriate handler */ - ALfilter_setParami(alfilt, context.get(), param, value); - } - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *values) -START_API_FUNC -{ - switch(param) - { - case AL_FILTER_TYPE: - alFilteri(filter, param, values[0]); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - - ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_setParamiv(alfilt, context.get(), param, values); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - - ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_setParamf(alfilt, context.get(), param, value); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - - ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_setParamfv(alfilt, context.get(), param, values); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - - ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - if(param == AL_FILTER_TYPE) - *value = alfilt->type; - else - { - /* Call the appropriate handler */ - ALfilter_getParami(alfilt, context.get(), param, value); - } - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *values) -START_API_FUNC -{ - switch(param) - { - case AL_FILTER_TYPE: - alGetFilteri(filter, param, values); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - - ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_getParamiv(alfilt, context.get(), param, values); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - - ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_getParamf(alfilt, context.get(), param, value); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - - ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_getParamfv(alfilt, context.get(), param, values); - } -} -END_API_FUNC - - -FilterSubList::~FilterSubList() -{ - uint64_t usemask{~FreeMask}; - while(usemask) - { - ALsizei idx = CTZ64(usemask); - al::destroy_at(Filters+idx); - usemask &= ~(1_u64 << idx); - } - FreeMask = ~usemask; - al_free(Filters); - Filters = nullptr; -} diff --git a/OpenAL32/alFilter.h b/OpenAL32/alFilter.h deleted file mode 100644 index db098d70..00000000 --- a/OpenAL32/alFilter.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef AL_FILTER_H -#define AL_FILTER_H - -#include "AL/al.h" -#include "AL/alc.h" - - -#define LOWPASSFREQREF (5000.0f) -#define HIGHPASSFREQREF (250.0f) - - -struct ALfilter; - -struct ALfilterVtable { - void (*const setParami)(ALfilter *filter, ALCcontext *context, ALenum param, ALint val); - void (*const setParamiv)(ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals); - void (*const setParamf)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val); - void (*const setParamfv)(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals); - - void (*const getParami)(ALfilter *filter, ALCcontext *context, ALenum param, ALint *val); - void (*const getParamiv)(ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals); - void (*const getParamf)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val); - void (*const getParamfv)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals); -}; - -#define DEFINE_ALFILTER_VTABLE(T) \ -const ALfilterVtable T##_vtable = { \ - T##_setParami, T##_setParamiv, T##_setParamf, T##_setParamfv, \ - T##_getParami, T##_getParamiv, T##_getParamf, T##_getParamfv, \ -} - -struct ALfilter { - // Filter type (AL_FILTER_NULL, ...) - ALenum type; - - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - - const ALfilterVtable *vtab; - - /* Self ID */ - ALuint id; -}; -#define ALfilter_setParami(o, c, p, v) ((o)->vtab->setParami(o, c, p, v)) -#define ALfilter_setParamf(o, c, p, v) ((o)->vtab->setParamf(o, c, p, v)) -#define ALfilter_setParamiv(o, c, p, v) ((o)->vtab->setParamiv(o, c, p, v)) -#define ALfilter_setParamfv(o, c, p, v) ((o)->vtab->setParamfv(o, c, p, v)) -#define ALfilter_getParami(o, c, p, v) ((o)->vtab->getParami(o, c, p, v)) -#define ALfilter_getParamf(o, c, p, v) ((o)->vtab->getParamf(o, c, p, v)) -#define ALfilter_getParamiv(o, c, p, v) ((o)->vtab->getParamiv(o, c, p, v)) -#define ALfilter_getParamfv(o, c, p, v) ((o)->vtab->getParamfv(o, c, p, v)) - -#endif diff --git a/OpenAL32/alListener.cpp b/OpenAL32/alListener.cpp deleted file mode 100644 index d3bf3aaa..00000000 --- a/OpenAL32/alListener.cpp +++ /dev/null @@ -1,454 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2000 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "alListener.h" - -#include -#include - -#include "AL/efx.h" - -#include "alError.h" -#include "alcontext.h" -#include "alexcpt.h" -#include "almalloc.h" -#include "atomic.h" -#include "opthelpers.h" - - -#define DO_UPDATEPROPS() do { \ - if(!context->DeferUpdates.load(std::memory_order_acquire)) \ - UpdateListenerProps(context.get()); \ - else \ - listener.PropsClean.clear(std::memory_order_release); \ -} while(0) - - -AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; - switch(param) - { - case AL_GAIN: - if(!(value >= 0.0f && std::isfinite(value))) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener gain out of range"); - listener.Gain = value; - DO_UPDATEPROPS(); - break; - - case AL_METERS_PER_UNIT: - if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, - "Listener meters per unit out of range"); - context->MetersPerUnit = value; - if(!context->DeferUpdates.load(std::memory_order_acquire)) - UpdateContextProps(context.get()); - else - context->PropsClean.clear(std::memory_order_release); - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float property"); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; - switch(param) - { - case AL_POSITION: - if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3))) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener position out of range"); - listener.Position[0] = value1; - listener.Position[1] = value2; - listener.Position[2] = value3; - DO_UPDATEPROPS(); - break; - - case AL_VELOCITY: - if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3))) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener velocity out of range"); - listener.Velocity[0] = value1; - listener.Velocity[1] = value2; - listener.Velocity[2] = value3; - DO_UPDATEPROPS(); - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-float property"); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) -START_API_FUNC -{ - if(values) - { - switch(param) - { - case AL_GAIN: - case AL_METERS_PER_UNIT: - alListenerf(param, values[0]); - return; - - case AL_POSITION: - case AL_VELOCITY: - alListener3f(param, values[0], values[1], values[2]); - return; - } - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; - if(!values) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "NULL pointer"); - switch(param) - { - case AL_ORIENTATION: - if(!(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) && - std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5]))) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener orientation out of range"); - /* AT then UP */ - listener.OrientAt[0] = values[0]; - listener.OrientAt[1] = values[1]; - listener.OrientAt[2] = values[2]; - listener.OrientUp[0] = values[3]; - listener.OrientUp[1] = values[4]; - listener.OrientUp[2] = values[5]; - DO_UPDATEPROPS(); - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float-vector property"); - } -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint /*value*/) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer property"); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3) -START_API_FUNC -{ - switch(param) - { - case AL_POSITION: - case AL_VELOCITY: - alListener3f(param, static_cast(value1), static_cast(value2), static_cast(value3)); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-integer property"); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values) -START_API_FUNC -{ - if(values) - { - ALfloat fvals[6]; - switch(param) - { - case AL_POSITION: - case AL_VELOCITY: - alListener3f(param, static_cast(values[0]), static_cast(values[1]), static_cast(values[2])); - return; - - case AL_ORIENTATION: - fvals[0] = static_cast(values[0]); - fvals[1] = static_cast(values[1]); - fvals[2] = static_cast(values[2]); - fvals[3] = static_cast(values[3]); - fvals[4] = static_cast(values[4]); - fvals[5] = static_cast(values[5]); - alListenerfv(param, fvals); - return; - } - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer-vector property"); - } -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; - if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_GAIN: - *value = listener.Gain; - break; - - case AL_METERS_PER_UNIT: - *value = context->MetersPerUnit; - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float property"); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; - if(!value1 || !value2 || !value3) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_POSITION: - *value1 = listener.Position[0]; - *value2 = listener.Position[1]; - *value3 = listener.Position[2]; - break; - - case AL_VELOCITY: - *value1 = listener.Velocity[0]; - *value2 = listener.Velocity[1]; - *value3 = listener.Velocity[2]; - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-float property"); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) -START_API_FUNC -{ - switch(param) - { - case AL_GAIN: - case AL_METERS_PER_UNIT: - alGetListenerf(param, values); - return; - - case AL_POSITION: - case AL_VELOCITY: - alGetListener3f(param, values+0, values+1, values+2); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; - if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_ORIENTATION: - // AT then UP - values[0] = listener.OrientAt[0]; - values[1] = listener.OrientAt[1]; - values[2] = listener.OrientAt[2]; - values[3] = listener.OrientUp[0]; - values[4] = listener.OrientUp[1]; - values[5] = listener.OrientUp[2]; - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float-vector property"); - } -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer property"); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; - if(!value1 || !value2 || !value3) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_POSITION: - *value1 = static_cast(listener.Position[0]); - *value2 = static_cast(listener.Position[1]); - *value3 = static_cast(listener.Position[2]); - break; - - case AL_VELOCITY: - *value1 = static_cast(listener.Velocity[0]); - *value2 = static_cast(listener.Velocity[1]); - *value3 = static_cast(listener.Velocity[2]); - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-integer property"); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) -START_API_FUNC -{ - switch(param) - { - case AL_POSITION: - case AL_VELOCITY: - alGetListener3i(param, values+0, values+1, values+2); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; - if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_ORIENTATION: - // AT then UP - values[0] = static_cast(listener.OrientAt[0]); - values[1] = static_cast(listener.OrientAt[1]); - values[2] = static_cast(listener.OrientAt[2]); - values[3] = static_cast(listener.OrientUp[0]); - values[4] = static_cast(listener.OrientUp[1]); - values[5] = static_cast(listener.OrientUp[2]); - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer-vector property"); - } -} -END_API_FUNC - - -void UpdateListenerProps(ALCcontext *context) -{ - /* Get an unused proprty container, or allocate a new one as needed. */ - ALlistenerProps *props{context->FreeListenerProps.load(std::memory_order_acquire)}; - if(!props) - props = static_cast(al_calloc(16, sizeof(*props))); - else - { - ALlistenerProps *next; - do { - next = props->next.load(std::memory_order_relaxed); - } while(context->FreeListenerProps.compare_exchange_weak(props, next, - std::memory_order_seq_cst, std::memory_order_acquire) == 0); - } - - /* Copy in current property values. */ - ALlistener &listener = context->Listener; - props->Position = listener.Position; - props->Velocity = listener.Velocity; - props->OrientAt = listener.OrientAt; - props->OrientUp = listener.OrientUp; - props->Gain = listener.Gain; - - /* Set the new container for updating internal parameters. */ - props = listener.Update.exchange(props, std::memory_order_acq_rel); - if(props) - { - /* If there was an unused update container, put it back in the - * freelist. - */ - AtomicReplaceHead(context->FreeListenerProps, props); - } -} diff --git a/OpenAL32/alListener.h b/OpenAL32/alListener.h deleted file mode 100644 index a71db9f8..00000000 --- a/OpenAL32/alListener.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef AL_LISTENER_H -#define AL_LISTENER_H - -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" - -#include "vecmat.h" - -enum class DistanceModel; - - -struct ALlistenerProps { - std::array Position; - std::array Velocity; - std::array OrientAt; - std::array OrientUp; - ALfloat Gain; - - std::atomic next; -}; - -struct ALlistener { - std::array Position{{0.0f, 0.0f, 0.0f}}; - std::array Velocity{{0.0f, 0.0f, 0.0f}}; - std::array OrientAt{{0.0f, 0.0f, -1.0f}}; - std::array OrientUp{{0.0f, 1.0f, 0.0f}}; - ALfloat Gain{1.0f}; - - std::atomic_flag PropsClean; - - /* Pointer to the most recent property values that are awaiting an update. - */ - std::atomic Update{nullptr}; - - struct { - alu::Matrix Matrix; - alu::Vector Velocity; - - ALfloat Gain; - ALfloat MetersPerUnit; - - ALfloat DopplerFactor; - ALfloat SpeedOfSound; /* in units per sec! */ - ALfloat ReverbSpeedOfSound; /* in meters per sec! */ - - ALboolean SourceDistanceModel; - DistanceModel mDistanceModel; - } Params; - - ALlistener() { PropsClean.test_and_set(std::memory_order_relaxed); } -}; - -void UpdateListenerProps(ALCcontext *context); - -#endif diff --git a/OpenAL32/alSource.cpp b/OpenAL32/alSource.cpp deleted file mode 100644 index 4af5cc47..00000000 --- a/OpenAL32/alSource.cpp +++ /dev/null @@ -1,3638 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "alSource.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" -#include "AL/efx.h" - -#include "alAuxEffectSlot.h" -#include "alBuffer.h" -#include "alError.h" -#include "alFilter.h" -#include "alcmain.h" -#include "alcontext.h" -#include "alexcpt.h" -#include "almalloc.h" -#include "alnumeric.h" -#include "alu.h" -#include "ambidefs.h" -#include "atomic.h" -#include "backends/base.h" -#include "bformatdec.h" -#include "filters/nfc.h" -#include "filters/splitter.h" -#include "inprogext.h" -#include "logging.h" -#include "math_defs.h" -#include "opthelpers.h" -#include "ringbuffer.h" -#include "threads.h" - - -namespace { - -using namespace std::placeholders; - -inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) -{ - ALint idx{source->VoiceIdx}; - if(idx >= 0 && static_cast(idx) < context->VoiceCount.load(std::memory_order_relaxed)) - { - ALuint sid{source->id}; - ALvoice &voice = (*context->Voices)[idx]; - if(voice.mSourceID.load(std::memory_order_acquire) == sid) - return &voice; - } - source->VoiceIdx = -1; - return nullptr; -} - -void UpdateSourceProps(const ALsource *source, ALvoice *voice, ALCcontext *context) -{ - /* Get an unused property container, or allocate a new one as needed. */ - ALvoiceProps *props{context->FreeVoiceProps.load(std::memory_order_acquire)}; - if(!props) - props = new ALvoiceProps{}; - else - { - ALvoiceProps *next; - do { - next = props->next.load(std::memory_order_relaxed); - } while(context->FreeVoiceProps.compare_exchange_weak(props, next, - std::memory_order_acq_rel, std::memory_order_acquire) == 0); - } - - /* Copy in current property values. */ - props->Pitch = source->Pitch; - props->Gain = source->Gain; - props->OuterGain = source->OuterGain; - props->MinGain = source->MinGain; - props->MaxGain = source->MaxGain; - props->InnerAngle = source->InnerAngle; - props->OuterAngle = source->OuterAngle; - props->RefDistance = source->RefDistance; - props->MaxDistance = source->MaxDistance; - props->RolloffFactor = source->RolloffFactor; - props->Position = source->Position; - props->Velocity = source->Velocity; - props->Direction = source->Direction; - props->OrientAt = source->OrientAt; - props->OrientUp = source->OrientUp; - props->HeadRelative = source->HeadRelative; - props->mDistanceModel = source->mDistanceModel; - props->mResampler = source->mResampler; - props->DirectChannels = source->DirectChannels; - props->mSpatializeMode = source->mSpatialize; - - props->DryGainHFAuto = source->DryGainHFAuto; - props->WetGainAuto = source->WetGainAuto; - props->WetGainHFAuto = source->WetGainHFAuto; - props->OuterGainHF = source->OuterGainHF; - - props->AirAbsorptionFactor = source->AirAbsorptionFactor; - props->RoomRolloffFactor = source->RoomRolloffFactor; - props->DopplerFactor = source->DopplerFactor; - - props->StereoPan = source->StereoPan; - - props->Radius = source->Radius; - - props->Direct.Gain = source->Direct.Gain; - props->Direct.GainHF = source->Direct.GainHF; - props->Direct.HFReference = source->Direct.HFReference; - props->Direct.GainLF = source->Direct.GainLF; - props->Direct.LFReference = source->Direct.LFReference; - - auto copy_send = [](const ALsource::SendData &srcsend) noexcept -> ALvoicePropsBase::SendData - { - ALvoicePropsBase::SendData ret; - ret.Slot = srcsend.Slot; - ret.Gain = srcsend.Gain; - ret.GainHF = srcsend.GainHF; - ret.HFReference = srcsend.HFReference; - ret.GainLF = srcsend.GainLF; - ret.LFReference = srcsend.LFReference; - return ret; - }; - std::transform(source->Send.cbegin(), source->Send.cend(), props->Send, copy_send); - - /* Set the new container for updating internal parameters. */ - props = voice->mUpdate.exchange(props, std::memory_order_acq_rel); - if(props) - { - /* If there was an unused update container, put it back in the - * freelist. - */ - AtomicReplaceHead(context->FreeVoiceProps, props); - } -} - -/* GetSourceSampleOffset - * - * Gets the current read offset for the given Source, in 32.32 fixed-point - * samples. The offset is relative to the start of the queue (not the start of - * the current buffer). - */ -int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, std::chrono::nanoseconds *clocktime) -{ - ALCdevice *device{context->Device}; - const ALbufferlistitem *Current; - uint64_t readPos; - ALuint refcount; - ALvoice *voice; - - do { - Current = nullptr; - readPos = 0; - while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) - std::this_thread::yield(); - *clocktime = GetDeviceClockTime(device); - - voice = GetSourceVoice(Source, context); - if(voice) - { - Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); - - readPos = uint64_t{voice->mPosition.load(std::memory_order_relaxed)} << 32; - readPos |= int64_t{voice->mPositionFrac.load(std::memory_order_relaxed)} << - (32-FRACTIONBITS); - } - std::atomic_thread_fence(std::memory_order_acquire); - } while(refcount != device->MixCount.load(std::memory_order_relaxed)); - - if(voice) - { - const ALbufferlistitem *BufferList{Source->queue}; - while(BufferList && BufferList != Current) - { - readPos += int64_t{BufferList->max_samples} << 32; - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - readPos = minu64(readPos, 0x7fffffffffffffff_u64); - } - - return static_cast(readPos); -} - -/* GetSourceSecOffset - * - * Gets the current read offset for the given Source, in seconds. The offset is - * relative to the start of the queue (not the start of the current buffer). - */ -ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, std::chrono::nanoseconds *clocktime) -{ - ALCdevice *device{context->Device}; - const ALbufferlistitem *Current; - uint64_t readPos; - ALuint refcount; - ALvoice *voice; - - do { - Current = nullptr; - readPos = 0; - while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) - std::this_thread::yield(); - *clocktime = GetDeviceClockTime(device); - - voice = GetSourceVoice(Source, context); - if(voice) - { - Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); - - readPos = uint64_t{voice->mPosition.load(std::memory_order_relaxed)} << FRACTIONBITS; - readPos |= voice->mPositionFrac.load(std::memory_order_relaxed); - } - std::atomic_thread_fence(std::memory_order_acquire); - } while(refcount != device->MixCount.load(std::memory_order_relaxed)); - - ALdouble offset{0.0}; - if(voice) - { - const ALbufferlistitem *BufferList{Source->queue}; - const ALbuffer *BufferFmt{nullptr}; - while(BufferList && BufferList != Current) - { - for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i) - BufferFmt = BufferList->buffers[i]; - readPos += int64_t{BufferList->max_samples} << FRACTIONBITS; - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - - while(BufferList && !BufferFmt) - { - for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i) - BufferFmt = BufferList->buffers[i]; - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - assert(BufferFmt != nullptr); - - offset = static_cast(readPos) / static_castFRACTIONONE / - static_cast(BufferFmt->Frequency); - } - - return offset; -} - -/* GetSourceOffset - * - * Gets the current read offset for the given Source, in the appropriate format - * (Bytes, Samples or Seconds). The offset is relative to the start of the - * queue (not the start of the current buffer). - */ -ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) -{ - ALCdevice *device{context->Device}; - const ALbufferlistitem *Current; - ALuint readPos; - ALsizei readPosFrac; - ALuint refcount; - ALvoice *voice; - - do { - Current = nullptr; - readPos = readPosFrac = 0; - while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) - std::this_thread::yield(); - voice = GetSourceVoice(Source, context); - if(voice) - { - Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); - - readPos = voice->mPosition.load(std::memory_order_relaxed); - readPosFrac = voice->mPositionFrac.load(std::memory_order_relaxed); - } - std::atomic_thread_fence(std::memory_order_acquire); - } while(refcount != device->MixCount.load(std::memory_order_relaxed)); - - ALdouble offset{0.0}; - if(voice) - { - const ALbufferlistitem *BufferList{Source->queue}; - const ALbuffer *BufferFmt{nullptr}; - ALboolean readFin{AL_FALSE}; - ALuint totalBufferLen{0u}; - - while(BufferList) - { - for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i) - BufferFmt = BufferList->buffers[i]; - - readFin |= (BufferList == Current); - totalBufferLen += BufferList->max_samples; - if(!readFin) readPos += BufferList->max_samples; - - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - assert(BufferFmt != nullptr); - - if(Source->Looping) - readPos %= totalBufferLen; - else - { - /* Wrap back to 0 */ - if(readPos >= totalBufferLen) - readPos = readPosFrac = 0; - } - - offset = 0.0; - switch(name) - { - case AL_SEC_OFFSET: - offset = (readPos + static_cast(readPosFrac)/FRACTIONONE) / BufferFmt->Frequency; - break; - - case AL_SAMPLE_OFFSET: - offset = readPos + static_cast(readPosFrac)/FRACTIONONE; - break; - - case AL_BYTE_OFFSET: - if(BufferFmt->OriginalType == UserFmtIMA4) - { - ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; - ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->mFmtChannels); - ALuint FrameBlockSize = BufferFmt->OriginalAlign; - - /* Round down to nearest ADPCM block */ - offset = static_cast(readPos / FrameBlockSize * BlockSize); - } - else if(BufferFmt->OriginalType == UserFmtMSADPCM) - { - ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; - ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->mFmtChannels); - ALuint FrameBlockSize = BufferFmt->OriginalAlign; - - /* Round down to nearest ADPCM block */ - offset = static_cast(readPos / FrameBlockSize * BlockSize); - } - else - { - const ALsizei FrameSize{FrameSizeFromFmt(BufferFmt->mFmtChannels, - BufferFmt->mFmtType)}; - offset = static_cast(readPos * FrameSize); - } - break; - } - } - - return offset; -} - - -/* GetSampleOffset - * - * Retrieves the sample offset into the Source's queue (from the Sample, Byte - * or Second offset supplied by the application). This takes into account the - * fact that the buffer format may have been modifed since. - */ -ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac) -{ - const ALbuffer *BufferFmt{nullptr}; - const ALbufferlistitem *BufferList; - - /* Find the first valid Buffer in the Queue */ - BufferList = Source->queue; - while(BufferList) - { - for(ALsizei i{0};i < BufferList->num_buffers && !BufferFmt;i++) - BufferFmt = BufferList->buffers[i]; - if(BufferFmt) break; - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - if(!BufferFmt) - { - Source->OffsetType = AL_NONE; - Source->Offset = 0.0; - return AL_FALSE; - } - - ALdouble dbloff, dblfrac; - switch(Source->OffsetType) - { - case AL_BYTE_OFFSET: - /* Determine the ByteOffset (and ensure it is block aligned) */ - *offset = static_cast(Source->Offset); - if(BufferFmt->OriginalType == UserFmtIMA4) - { - ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; - *offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels); - *offset *= BufferFmt->OriginalAlign; - } - else if(BufferFmt->OriginalType == UserFmtMSADPCM) - { - ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; - *offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels); - *offset *= BufferFmt->OriginalAlign; - } - else - *offset /= FrameSizeFromFmt(BufferFmt->mFmtChannels, BufferFmt->mFmtType); - *frac = 0; - break; - - case AL_SAMPLE_OFFSET: - dblfrac = modf(Source->Offset, &dbloff); - *offset = static_cast(mind(dbloff, std::numeric_limits::max())); - *frac = static_cast(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0)); - break; - - case AL_SEC_OFFSET: - dblfrac = modf(Source->Offset*BufferFmt->Frequency, &dbloff); - *offset = static_cast(mind(dbloff, std::numeric_limits::max())); - *frac = static_cast(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0)); - break; - } - Source->OffsetType = AL_NONE; - Source->Offset = 0.0; - - return AL_TRUE; -} - -/* ApplyOffset - * - * Apply the stored playback offset to the Source. This function will update - * the number of buffers "played" given the stored offset. - */ -ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) -{ - /* Get sample frame offset */ - ALuint offset{0u}; - ALsizei frac{0}; - if(!GetSampleOffset(Source, &offset, &frac)) - return AL_FALSE; - - ALuint totalBufferLen{0u}; - ALbufferlistitem *BufferList{Source->queue}; - while(BufferList && totalBufferLen <= offset) - { - if(static_cast(BufferList->max_samples) > offset-totalBufferLen) - { - /* Offset is in this buffer */ - voice->mPosition.store(offset - totalBufferLen, std::memory_order_relaxed); - voice->mPositionFrac.store(frac, std::memory_order_relaxed); - voice->mCurrentBuffer.store(BufferList, std::memory_order_release); - return AL_TRUE; - } - totalBufferLen += BufferList->max_samples; - - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - - /* Offset is out of range of the queue */ - return AL_FALSE; -} - - -ALsource *AllocSource(ALCcontext *context) -{ - ALCdevice *device{context->Device}; - std::lock_guard _{context->SourceLock}; - if(context->NumSources >= device->SourcesMax) - { - alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax); - return nullptr; - } - auto sublist = std::find_if(context->SourceList.begin(), context->SourceList.end(), - [](const SourceSubList &entry) noexcept -> bool - { return entry.FreeMask != 0; } - ); - auto lidx = static_cast(std::distance(context->SourceList.begin(), sublist)); - ALsource *source; - ALsizei slidx; - if(LIKELY(sublist != context->SourceList.end())) - { - slidx = CTZ64(sublist->FreeMask); - source = sublist->Sources + slidx; - } - else - { - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ - if(UNLIKELY(context->SourceList.size() >= 1<<25)) - { - alSetError(context, AL_OUT_OF_MEMORY, "Too many sources allocated"); - return nullptr; - } - context->SourceList.emplace_back(); - sublist = context->SourceList.end() - 1; - - sublist->FreeMask = ~0_u64; - sublist->Sources = static_cast(al_calloc(16, sizeof(ALsource)*64)); - if(UNLIKELY(!sublist->Sources)) - { - context->SourceList.pop_back(); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate source batch"); - return nullptr; - } - - slidx = 0; - source = sublist->Sources + slidx; - } - - source = new (source) ALsource{device->NumAuxSends}; - - /* Add 1 to avoid source ID 0. */ - source->id = ((lidx<<6) | slidx) + 1; - - context->NumSources += 1; - sublist->FreeMask &= ~(1_u64 << slidx); - - return source; -} - -void FreeSource(ALCcontext *context, ALsource *source) -{ - ALuint id = source->id - 1; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; - - ALCdevice *device{context->Device}; - BackendUniqueLock backlock{*device->Backend}; - if(ALvoice *voice{GetSourceVoice(source, context)}) - { - voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed); - voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); - voice->mSourceID.store(0u, std::memory_order_relaxed); - std::atomic_thread_fence(std::memory_order_release); - /* Don't set the voice to stopping if it was already stopped or - * stopping. - */ - ALvoice::State oldvstate{ALvoice::Playing}; - voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping, - std::memory_order_acq_rel, std::memory_order_acquire); - } - backlock.unlock(); - - al::destroy_at(source); - - context->SourceList[lidx].FreeMask |= 1_u64 << slidx; - context->NumSources--; -} - - -inline ALsource *LookupSource(ALCcontext *context, ALuint id) noexcept -{ - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= context->SourceList.size())) - return nullptr; - SourceSubList &sublist{context->SourceList[lidx]}; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) - return nullptr; - return sublist.Sources + slidx; -} - -inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) noexcept -{ - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= device->BufferList.size())) - return nullptr; - BufferSubList &sublist = device->BufferList[lidx]; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) - return nullptr; - return sublist.Buffers + slidx; -} - -inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) noexcept -{ - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= device->FilterList.size())) - return nullptr; - FilterSubList &sublist = device->FilterList[lidx]; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) - return nullptr; - return sublist.Filters + slidx; -} - -inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept -{ - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= context->EffectSlotList.size())) - return nullptr; - EffectSlotSubList &sublist{context->EffectSlotList[lidx]}; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) - return nullptr; - return sublist.EffectSlots + slidx; -} - - -enum SourceProp : ALenum { - srcPitch = AL_PITCH, - srcGain = AL_GAIN, - srcMinGain = AL_MIN_GAIN, - srcMaxGain = AL_MAX_GAIN, - srcMaxDistance = AL_MAX_DISTANCE, - srcRolloffFactor = AL_ROLLOFF_FACTOR, - srcDopplerFactor = AL_DOPPLER_FACTOR, - srcConeOuterGain = AL_CONE_OUTER_GAIN, - srcSecOffset = AL_SEC_OFFSET, - srcSampleOffset = AL_SAMPLE_OFFSET, - srcByteOffset = AL_BYTE_OFFSET, - srcConeInnerAngle = AL_CONE_INNER_ANGLE, - srcConeOuterAngle = AL_CONE_OUTER_ANGLE, - srcRefDistance = AL_REFERENCE_DISTANCE, - - srcPosition = AL_POSITION, - srcVelocity = AL_VELOCITY, - srcDirection = AL_DIRECTION, - - srcSourceRelative = AL_SOURCE_RELATIVE, - srcLooping = AL_LOOPING, - srcBuffer = AL_BUFFER, - srcSourceState = AL_SOURCE_STATE, - srcBuffersQueued = AL_BUFFERS_QUEUED, - srcBuffersProcessed = AL_BUFFERS_PROCESSED, - srcSourceType = AL_SOURCE_TYPE, - - /* ALC_EXT_EFX */ - srcConeOuterGainHF = AL_CONE_OUTER_GAINHF, - srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR, - srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR, - srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO, - srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, - srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, - srcDirectFilter = AL_DIRECT_FILTER, - srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER, - - /* AL_SOFT_direct_channels */ - srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT, - - /* AL_EXT_source_distance_model */ - srcDistanceModel = AL_DISTANCE_MODEL, - - /* AL_SOFT_source_latency */ - srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT, - srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT, - - /* AL_EXT_STEREO_ANGLES */ - srcAngles = AL_STEREO_ANGLES, - - /* AL_EXT_SOURCE_RADIUS */ - srcRadius = AL_SOURCE_RADIUS, - - /* AL_EXT_BFORMAT */ - srcOrientation = AL_ORIENTATION, - - /* AL_SOFT_source_resampler */ - srcResampler = AL_SOURCE_RESAMPLER_SOFT, - - /* AL_SOFT_source_spatialize */ - srcSpatialize = AL_SOURCE_SPATIALIZE_SOFT, - - /* ALC_SOFT_device_clock */ - srcSampleOffsetClockSOFT = AL_SAMPLE_OFFSET_CLOCK_SOFT, - srcSecOffsetClockSOFT = AL_SEC_OFFSET_CLOCK_SOFT, -}; - -/** - * Returns if the last known state for the source was playing or paused. Does - * not sync with the mixer voice. - */ -inline bool IsPlayingOrPaused(ALsource *source) -{ return source->state == AL_PLAYING || source->state == AL_PAUSED; } - -/** - * Returns an updated source state using the matching voice's status (or lack - * thereof). - */ -inline ALenum GetSourceState(ALsource *source, ALvoice *voice) -{ - if(!voice && source->state == AL_PLAYING) - source->state = AL_STOPPED; - return source->state; -} - -/** - * Returns if the source should specify an update, given the context's - * deferring state and the source's last known state. - */ -inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context) -{ - return !context->DeferUpdates.load(std::memory_order_acquire) && - IsPlayingOrPaused(source); -} - - -/** Can only be called while the mixer is locked! */ -void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) -{ - ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)}; - if(!(enabledevt&EventType_SourceStateChange)) return; - - /* The mixer may have queued a state change that's not yet been processed, - * and we don't want state change messages to occur out of order, so send - * it through the async queue to ensure proper ordering. - */ - RingBuffer *ring{context->AsyncEvents.get()}; - auto evt_vec = ring->getWriteVector(); - if(evt_vec.first.len < 1) return; - - AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_SourceStateChange}}; - evt->u.srcstate.id = id; - evt->u.srcstate.state = state; - ring->writeAdvance(1); - context->EventSem.post(); -} - - -ALint FloatValsByProp(ALenum prop) -{ - switch(static_cast(prop)) - { - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_REFERENCE_DISTANCE: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_SOURCE_RADIUS: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - return 1; - - case AL_STEREO_ANGLES: - return 2; - - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - return 3; - - case AL_ORIENTATION: - return 6; - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - - case AL_BUFFER: - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - break; /* i/i64 only */ - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; /* i64 only */ - } - return 0; -} -ALint DoubleValsByProp(ALenum prop) -{ - switch(static_cast(prop)) - { - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_REFERENCE_DISTANCE: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_SOURCE_RADIUS: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - return 1; - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - case AL_STEREO_ANGLES: - return 2; - - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - return 3; - - case AL_ORIENTATION: - return 6; - - case AL_BUFFER: - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - break; /* i/i64 only */ - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; /* i64 only */ - } - return 0; -} - -ALint IntValsByProp(ALenum prop) -{ - switch(static_cast(prop)) - { - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_REFERENCE_DISTANCE: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_BUFFER: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_DIRECT_FILTER: - case AL_SOURCE_RADIUS: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - return 1; - - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - case AL_AUXILIARY_SEND_FILTER: - return 3; - - case AL_ORIENTATION: - return 6; - - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; /* i64 only */ - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - case AL_STEREO_ANGLES: - break; /* Float/double only */ - } - return 0; -} -ALint Int64ValsByProp(ALenum prop) -{ - switch(static_cast(prop)) - { - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_REFERENCE_DISTANCE: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_BUFFER: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_DIRECT_FILTER: - case AL_SOURCE_RADIUS: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - return 1; - - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - return 2; - - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - case AL_AUXILIARY_SEND_FILTER: - return 3; - - case AL_ORIENTATION: - return 6; - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - case AL_STEREO_ANGLES: - break; /* Float/double only */ - } - return 0; -} - - -ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values); -ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values); -ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values); - -#define CHECKVAL(x) do { \ - if(!(x)) \ - { \ - alSetError(Context, AL_INVALID_VALUE, "Value out of range"); \ - return AL_FALSE; \ - } \ -} while(0) - -void UpdateSourceProps(ALsource *source, ALCcontext *context) -{ - ALvoice *voice; - if(SourceShouldUpdate(source, context) && (voice=GetSourceVoice(source, context)) != nullptr) - UpdateSourceProps(source, voice, context); - else - source->PropsClean.clear(std::memory_order_release); -} - -ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values) -{ - ALint ival; - - switch(prop) - { - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - /* Query only */ - SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, - "Setting read-only source property 0x%04x", prop); - - case AL_PITCH: - CHECKVAL(*values >= 0.0f); - - Source->Pitch = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_CONE_INNER_ANGLE: - CHECKVAL(*values >= 0.0f && *values <= 360.0f); - - Source->InnerAngle = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_CONE_OUTER_ANGLE: - CHECKVAL(*values >= 0.0f && *values <= 360.0f); - - Source->OuterAngle = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_GAIN: - CHECKVAL(*values >= 0.0f); - - Source->Gain = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_MAX_DISTANCE: - CHECKVAL(*values >= 0.0f); - - Source->MaxDistance = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_ROLLOFF_FACTOR: - CHECKVAL(*values >= 0.0f); - - Source->RolloffFactor = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_REFERENCE_DISTANCE: - CHECKVAL(*values >= 0.0f); - - Source->RefDistance = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_MIN_GAIN: - CHECKVAL(*values >= 0.0f); - - Source->MinGain = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_MAX_GAIN: - CHECKVAL(*values >= 0.0f); - - Source->MaxGain = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_CONE_OUTER_GAIN: - CHECKVAL(*values >= 0.0f && *values <= 1.0f); - - Source->OuterGain = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_CONE_OUTER_GAINHF: - CHECKVAL(*values >= 0.0f && *values <= 1.0f); - - Source->OuterGainHF = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_AIR_ABSORPTION_FACTOR: - CHECKVAL(*values >= 0.0f && *values <= 10.0f); - - Source->AirAbsorptionFactor = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_ROOM_ROLLOFF_FACTOR: - CHECKVAL(*values >= 0.0f && *values <= 10.0f); - - Source->RoomRolloffFactor = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_DOPPLER_FACTOR: - CHECKVAL(*values >= 0.0f && *values <= 1.0f); - - Source->DopplerFactor = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - CHECKVAL(*values >= 0.0f); - - Source->OffsetType = prop; - Source->Offset = *values; - - if(IsPlayingOrPaused(Source)) - { - ALCdevice *device{Context->Device}; - BackendLockGuard _{*device->Backend}; - /* Double-check that the source is still playing while we have - * the lock. - */ - if(ALvoice *voice{GetSourceVoice(Source, Context)}) - { - if(ApplyOffset(Source, voice) == AL_FALSE) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid offset"); - } - } - return AL_TRUE; - - case AL_SOURCE_RADIUS: - CHECKVAL(*values >= 0.0f && std::isfinite(*values)); - - Source->Radius = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_STEREO_ANGLES: - CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1])); - - Source->StereoPan[0] = values[0]; - Source->StereoPan[1] = values[1]; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - - case AL_POSITION: - CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); - - Source->Position[0] = values[0]; - Source->Position[1] = values[1]; - Source->Position[2] = values[2]; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_VELOCITY: - CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); - - Source->Velocity[0] = values[0]; - Source->Velocity[1] = values[1]; - Source->Velocity[2] = values[2]; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_DIRECTION: - CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); - - Source->Direction[0] = values[0]; - Source->Direction[1] = values[1]; - Source->Direction[2] = values[2]; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_ORIENTATION: - CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) && - std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5])); - - Source->OrientAt[0] = values[0]; - Source->OrientAt[1] = values[1]; - Source->OrientAt[2] = values[2]; - Source->OrientUp[0] = values[3]; - Source->OrientUp[1] = values[4]; - Source->OrientUp[2] = values[5]; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_SOURCE_TYPE: - case AL_DISTANCE_MODEL: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - ival = static_cast(values[0]); - return SetSourceiv(Source, Context, prop, &ival); - - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - ival = static_cast(static_cast(values[0])); - return SetSourceiv(Source, Context, prop, &ival); - - case AL_BUFFER: - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; - } - - ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source float property 0x%04x", prop); -} - -ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values) -{ - ALCdevice *device{Context->Device}; - ALbuffer *buffer{nullptr}; - ALfilter *filter{nullptr}; - ALeffectslot *slot{nullptr}; - ALbufferlistitem *oldlist{nullptr}; - std::unique_lock slotlock; - std::unique_lock filtlock; - std::unique_lock buflock; - ALfloat fvals[6]; - - switch(prop) - { - case AL_SOURCE_STATE: - case AL_SOURCE_TYPE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - /* Query only */ - SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, - "Setting read-only source property 0x%04x", prop); - - case AL_SOURCE_RELATIVE: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->HeadRelative = static_cast(*values); - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_LOOPING: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->Looping = static_cast(*values); - if(IsPlayingOrPaused(Source)) - { - ALvoice *voice{GetSourceVoice(Source, Context)}; - if(voice) - { - if(Source->Looping) - voice->mLoopBuffer.store(Source->queue, std::memory_order_release); - else - voice->mLoopBuffer.store(nullptr, std::memory_order_release); - - /* If the source is playing, wait for the current mix to finish - * to ensure it isn't currently looping back or reaching the - * end. - */ - while((device->MixCount.load(std::memory_order_acquire)&1)) - std::this_thread::yield(); - } - } - return AL_TRUE; - - case AL_BUFFER: - buflock = std::unique_lock{device->BufferLock}; - if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != nullptr)) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid buffer ID %u", - *values); - - if(buffer && buffer->MappedAccess != 0 && - !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) - SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, - "Setting non-persistently mapped buffer %u", buffer->id); - else - { - ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context)); - if(state == AL_PLAYING || state == AL_PAUSED) - SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, - "Setting buffer on playing or paused source %u", Source->id); - } - - oldlist = Source->queue; - if(buffer != nullptr) - { - /* Add the selected buffer to a one-item queue */ - auto newlist = static_cast(al_calloc(alignof(void*), - ALbufferlistitem::Sizeof(1u))); - newlist->next.store(nullptr, std::memory_order_relaxed); - newlist->max_samples = buffer->SampleLen; - newlist->num_buffers = 1; - newlist->buffers[0] = buffer; - IncrementRef(&buffer->ref); - - /* Source is now Static */ - Source->SourceType = AL_STATIC; - Source->queue = newlist; - } - else - { - /* Source is now Undetermined */ - Source->SourceType = AL_UNDETERMINED; - Source->queue = nullptr; - } - buflock.unlock(); - - /* Delete all elements in the previous queue */ - while(oldlist != nullptr) - { - ALbufferlistitem *temp{oldlist}; - oldlist = temp->next.load(std::memory_order_relaxed); - - for(ALsizei i{0};i < temp->num_buffers;i++) - { - if(temp->buffers[i]) - DecrementRef(&temp->buffers[i]->ref); - } - al_free(temp); - } - return AL_TRUE; - - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - CHECKVAL(*values >= 0); - - Source->OffsetType = prop; - Source->Offset = *values; - - if(IsPlayingOrPaused(Source)) - { - ALCdevice *device{Context->Device}; - BackendLockGuard _{*device->Backend}; - if(ALvoice *voice{GetSourceVoice(Source, Context)}) - { - if(ApplyOffset(Source, voice) == AL_FALSE) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, - "Invalid source offset"); - } - } - return AL_TRUE; - - case AL_DIRECT_FILTER: - filtlock = std::unique_lock{device->FilterLock}; - if(!(*values == 0 || (filter=LookupFilter(device, *values)) != nullptr)) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", - *values); - - if(!filter) - { - Source->Direct.Gain = 1.0f; - Source->Direct.GainHF = 1.0f; - Source->Direct.HFReference = LOWPASSFREQREF; - Source->Direct.GainLF = 1.0f; - Source->Direct.LFReference = HIGHPASSFREQREF; - } - else - { - Source->Direct.Gain = filter->Gain; - Source->Direct.GainHF = filter->GainHF; - Source->Direct.HFReference = filter->HFReference; - Source->Direct.GainLF = filter->GainLF; - Source->Direct.LFReference = filter->LFReference; - } - filtlock.unlock(); - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_DIRECT_FILTER_GAINHF_AUTO: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->DryGainHFAuto = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->WetGainAuto = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->WetGainHFAuto = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_DIRECT_CHANNELS_SOFT: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->DirectChannels = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_DISTANCE_MODEL: - CHECKVAL(*values == AL_NONE || - *values == AL_INVERSE_DISTANCE || - *values == AL_INVERSE_DISTANCE_CLAMPED || - *values == AL_LINEAR_DISTANCE || - *values == AL_LINEAR_DISTANCE_CLAMPED || - *values == AL_EXPONENT_DISTANCE || - *values == AL_EXPONENT_DISTANCE_CLAMPED); - - Source->mDistanceModel = static_cast(*values); - if(Context->SourceDistanceModel) - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_SOURCE_RESAMPLER_SOFT: - CHECKVAL(*values >= 0 && *values <= ResamplerMax); - - Source->mResampler = static_cast(*values); - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_SOURCE_SPATIALIZE_SOFT: - CHECKVAL(*values >= AL_FALSE && *values <= AL_AUTO_SOFT); - - Source->mSpatialize = static_cast(*values); - UpdateSourceProps(Source, Context); - return AL_TRUE; - - - case AL_AUXILIARY_SEND_FILTER: - slotlock = std::unique_lock{Context->EffectSlotLock}; - if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != nullptr)) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid effect ID %u", - values[0]); - if(static_cast(values[1]) >= static_cast(device->NumAuxSends)) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid send %u", values[1]); - - filtlock = std::unique_lock{device->FilterLock}; - if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != nullptr)) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", - values[2]); - - if(!filter) - { - /* Disable filter */ - Source->Send[values[1]].Gain = 1.0f; - Source->Send[values[1]].GainHF = 1.0f; - Source->Send[values[1]].HFReference = LOWPASSFREQREF; - Source->Send[values[1]].GainLF = 1.0f; - Source->Send[values[1]].LFReference = HIGHPASSFREQREF; - } - else - { - Source->Send[values[1]].Gain = filter->Gain; - Source->Send[values[1]].GainHF = filter->GainHF; - Source->Send[values[1]].HFReference = filter->HFReference; - Source->Send[values[1]].GainLF = filter->GainLF; - Source->Send[values[1]].LFReference = filter->LFReference; - } - filtlock.unlock(); - - if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source)) - { - /* Add refcount on the new slot, and release the previous slot */ - if(slot) IncrementRef(&slot->ref); - if(Source->Send[values[1]].Slot) - DecrementRef(&Source->Send[values[1]].Slot->ref); - Source->Send[values[1]].Slot = slot; - - /* We must force an update if the auxiliary slot changed on an - * active source, in case the slot is about to be deleted. - */ - ALvoice *voice{GetSourceVoice(Source, Context)}; - if(voice) UpdateSourceProps(Source, voice, Context); - else Source->PropsClean.clear(std::memory_order_release); - } - else - { - if(slot) IncrementRef(&slot->ref); - if(Source->Send[values[1]].Slot) - DecrementRef(&Source->Send[values[1]].Slot->ref); - Source->Send[values[1]].Slot = slot; - UpdateSourceProps(Source, Context); - } - - return AL_TRUE; - - - /* 1x float */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_SOURCE_RADIUS: - fvals[0] = static_cast(*values); - return SetSourcefv(Source, Context, prop, fvals); - - /* 3x float */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - fvals[0] = static_cast(values[0]); - fvals[1] = static_cast(values[1]); - fvals[2] = static_cast(values[2]); - return SetSourcefv(Source, Context, prop, fvals); - - /* 6x float */ - case AL_ORIENTATION: - fvals[0] = static_cast(values[0]); - fvals[1] = static_cast(values[1]); - fvals[2] = static_cast(values[2]); - fvals[3] = static_cast(values[3]); - fvals[4] = static_cast(values[4]); - fvals[5] = static_cast(values[5]); - return SetSourcefv(Source, Context, prop, fvals); - - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - case AL_STEREO_ANGLES: - break; - } - - ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x", - prop); -} - -ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values) -{ - ALfloat fvals[6]; - ALint ivals[3]; - - switch(prop) - { - case AL_SOURCE_TYPE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_STATE: - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - /* Query only */ - SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, - "Setting read-only source property 0x%04x", prop); - - /* 1x int */ - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - CHECKVAL(*values <= INT_MAX && *values >= INT_MIN); - - ivals[0] = static_cast(*values); - return SetSourceiv(Source, Context, prop, ivals); - - /* 1x uint */ - case AL_BUFFER: - case AL_DIRECT_FILTER: - CHECKVAL(*values <= UINT_MAX && *values >= 0); - - ivals[0] = static_cast(*values); - return SetSourceiv(Source, Context, prop, ivals); - - /* 3x uint */ - case AL_AUXILIARY_SEND_FILTER: - CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 && - values[1] <= UINT_MAX && values[1] >= 0 && - values[2] <= UINT_MAX && values[2] >= 0); - - ivals[0] = static_cast(values[0]); - ivals[1] = static_cast(values[1]); - ivals[2] = static_cast(values[2]); - return SetSourceiv(Source, Context, prop, ivals); - - /* 1x float */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_SOURCE_RADIUS: - fvals[0] = static_cast(*values); - return SetSourcefv(Source, Context, prop, fvals); - - /* 3x float */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - fvals[0] = static_cast(values[0]); - fvals[1] = static_cast(values[1]); - fvals[2] = static_cast(values[2]); - return SetSourcefv(Source, Context, prop, fvals); - - /* 6x float */ - case AL_ORIENTATION: - fvals[0] = static_cast(values[0]); - fvals[1] = static_cast(values[1]); - fvals[2] = static_cast(values[2]); - fvals[3] = static_cast(values[3]); - fvals[4] = static_cast(values[4]); - fvals[5] = static_cast(values[5]); - return SetSourcefv(Source, Context, prop, fvals); - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - case AL_STEREO_ANGLES: - break; - } - - ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x", - prop); -} - -#undef CHECKVAL - - -ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values); -ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values); -ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64SOFT *values); - -ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values) -{ - ALCdevice *device{Context->Device}; - ClockLatency clocktime; - std::chrono::nanoseconds srcclock; - ALint ivals[3]; - ALboolean err; - - switch(prop) - { - case AL_GAIN: - *values = Source->Gain; - return AL_TRUE; - - case AL_PITCH: - *values = Source->Pitch; - return AL_TRUE; - - case AL_MAX_DISTANCE: - *values = Source->MaxDistance; - return AL_TRUE; - - case AL_ROLLOFF_FACTOR: - *values = Source->RolloffFactor; - return AL_TRUE; - - case AL_REFERENCE_DISTANCE: - *values = Source->RefDistance; - return AL_TRUE; - - case AL_CONE_INNER_ANGLE: - *values = Source->InnerAngle; - return AL_TRUE; - - case AL_CONE_OUTER_ANGLE: - *values = Source->OuterAngle; - return AL_TRUE; - - case AL_MIN_GAIN: - *values = Source->MinGain; - return AL_TRUE; - - case AL_MAX_GAIN: - *values = Source->MaxGain; - return AL_TRUE; - - case AL_CONE_OUTER_GAIN: - *values = Source->OuterGain; - return AL_TRUE; - - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - *values = GetSourceOffset(Source, prop, Context); - return AL_TRUE; - - case AL_CONE_OUTER_GAINHF: - *values = Source->OuterGainHF; - return AL_TRUE; - - case AL_AIR_ABSORPTION_FACTOR: - *values = Source->AirAbsorptionFactor; - return AL_TRUE; - - case AL_ROOM_ROLLOFF_FACTOR: - *values = Source->RoomRolloffFactor; - return AL_TRUE; - - case AL_DOPPLER_FACTOR: - *values = Source->DopplerFactor; - return AL_TRUE; - - case AL_SOURCE_RADIUS: - *values = Source->Radius; - return AL_TRUE; - - case AL_STEREO_ANGLES: - values[0] = Source->StereoPan[0]; - values[1] = Source->StereoPan[1]; - return AL_TRUE; - - case AL_SEC_OFFSET_LATENCY_SOFT: - /* Get the source offset with the clock time first. Then get the - * clock time with the device latency. Order is important. - */ - values[0] = GetSourceSecOffset(Source, Context, &srcclock); - { std::lock_guard _{device->StateLock}; - clocktime = GetClockLatency(device); - } - if(srcclock == clocktime.ClockTime) - values[1] = static_cast(clocktime.Latency.count()) / 1000000000.0; - else - { - /* If the clock time incremented, reduce the latency by that - * much since it's that much closer to the source offset it got - * earlier. - */ - std::chrono::nanoseconds diff = clocktime.ClockTime - srcclock; - values[1] = static_cast((clocktime.Latency - std::min(clocktime.Latency, diff)).count()) / - 1000000000.0; - } - return AL_TRUE; - - case AL_SEC_OFFSET_CLOCK_SOFT: - values[0] = GetSourceSecOffset(Source, Context, &srcclock); - values[1] = srcclock.count() / 1000000000.0; - return AL_TRUE; - - case AL_POSITION: - values[0] = Source->Position[0]; - values[1] = Source->Position[1]; - values[2] = Source->Position[2]; - return AL_TRUE; - - case AL_VELOCITY: - values[0] = Source->Velocity[0]; - values[1] = Source->Velocity[1]; - values[2] = Source->Velocity[2]; - return AL_TRUE; - - case AL_DIRECTION: - values[0] = Source->Direction[0]; - values[1] = Source->Direction[1]; - values[2] = Source->Direction[2]; - return AL_TRUE; - - case AL_ORIENTATION: - values[0] = Source->OrientAt[0]; - values[1] = Source->OrientAt[1]; - values[2] = Source->OrientAt[2]; - values[3] = Source->OrientUp[0]; - values[4] = Source->OrientUp[1]; - values[5] = Source->OrientUp[2]; - return AL_TRUE; - - /* 1x int */ - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) - *values = static_cast(ivals[0]); - return err; - - case AL_BUFFER: - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; - } - - ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source double property 0x%04x", - prop); -} - -ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values) -{ - ALbufferlistitem *BufferList; - ALdouble dvals[6]; - ALboolean err; - - switch(prop) - { - case AL_SOURCE_RELATIVE: - *values = Source->HeadRelative; - return AL_TRUE; - - case AL_LOOPING: - *values = Source->Looping; - return AL_TRUE; - - case AL_BUFFER: - BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : nullptr; - *values = (BufferList && BufferList->num_buffers >= 1 && BufferList->buffers[0]) ? - BufferList->buffers[0]->id : 0; - return AL_TRUE; - - case AL_SOURCE_STATE: - *values = GetSourceState(Source, GetSourceVoice(Source, Context)); - return AL_TRUE; - - case AL_BUFFERS_QUEUED: - if(!(BufferList=Source->queue)) - *values = 0; - else - { - ALsizei count = 0; - do { - count += BufferList->num_buffers; - BufferList = BufferList->next.load(std::memory_order_relaxed); - } while(BufferList != nullptr); - *values = count; - } - return AL_TRUE; - - case AL_BUFFERS_PROCESSED: - if(Source->Looping || Source->SourceType != AL_STREAMING) - { - /* Buffers on a looping source are in a perpetual state of - * PENDING, so don't report any as PROCESSED */ - *values = 0; - } - else - { - const ALbufferlistitem *BufferList{Source->queue}; - const ALbufferlistitem *Current{nullptr}; - ALsizei played{0}; - - ALvoice *voice{GetSourceVoice(Source, Context)}; - if(voice != nullptr) - Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); - else if(Source->state == AL_INITIAL) - Current = BufferList; - - while(BufferList && BufferList != Current) - { - played += BufferList->num_buffers; - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - *values = played; - } - return AL_TRUE; - - case AL_SOURCE_TYPE: - *values = Source->SourceType; - return AL_TRUE; - - case AL_DIRECT_FILTER_GAINHF_AUTO: - *values = Source->DryGainHFAuto; - return AL_TRUE; - - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - *values = Source->WetGainAuto; - return AL_TRUE; - - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - *values = Source->WetGainHFAuto; - return AL_TRUE; - - case AL_DIRECT_CHANNELS_SOFT: - *values = Source->DirectChannels; - return AL_TRUE; - - case AL_DISTANCE_MODEL: - *values = static_cast(Source->mDistanceModel); - return AL_TRUE; - - case AL_SOURCE_RESAMPLER_SOFT: - *values = Source->mResampler; - return AL_TRUE; - - case AL_SOURCE_SPATIALIZE_SOFT: - *values = Source->mSpatialize; - return AL_TRUE; - - /* 1x float/double */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_DOPPLER_FACTOR: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_SOURCE_RADIUS: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - *values = static_cast(dvals[0]); - return err; - - /* 3x float/double */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - { - values[0] = static_cast(dvals[0]); - values[1] = static_cast(dvals[1]); - values[2] = static_cast(dvals[2]); - } - return err; - - /* 6x float/double */ - case AL_ORIENTATION: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - { - values[0] = static_cast(dvals[0]); - values[1] = static_cast(dvals[1]); - values[2] = static_cast(dvals[2]); - values[3] = static_cast(dvals[3]); - values[4] = static_cast(dvals[4]); - values[5] = static_cast(dvals[5]); - } - return err; - - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; /* i64 only */ - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - case AL_STEREO_ANGLES: - break; /* Float/double only */ - - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - break; /* ??? */ - } - - ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x", - prop); -} - -ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64SOFT *values) -{ - ALCdevice *device = Context->Device; - ClockLatency clocktime; - std::chrono::nanoseconds srcclock; - ALdouble dvals[6]; - ALint ivals[3]; - ALboolean err; - - switch(prop) - { - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - /* Get the source offset with the clock time first. Then get the - * clock time with the device latency. Order is important. - */ - values[0] = GetSourceSampleOffset(Source, Context, &srcclock); - { std::lock_guard _{device->StateLock}; - clocktime = GetClockLatency(device); - } - if(srcclock == clocktime.ClockTime) - values[1] = clocktime.Latency.count(); - else - { - /* If the clock time incremented, reduce the latency by that - * much since it's that much closer to the source offset it got - * earlier. - */ - auto diff = clocktime.ClockTime - srcclock; - values[1] = (clocktime.Latency - std::min(clocktime.Latency, diff)).count(); - } - return AL_TRUE; - - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - values[0] = GetSourceSampleOffset(Source, Context, &srcclock); - values[1] = srcclock.count(); - return AL_TRUE; - - /* 1x float/double */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_DOPPLER_FACTOR: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_SOURCE_RADIUS: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - *values = static_cast(dvals[0]); - return err; - - /* 3x float/double */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - { - values[0] = static_cast(dvals[0]); - values[1] = static_cast(dvals[1]); - values[2] = static_cast(dvals[2]); - } - return err; - - /* 6x float/double */ - case AL_ORIENTATION: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - { - values[0] = static_cast(dvals[0]); - values[1] = static_cast(dvals[1]); - values[2] = static_cast(dvals[2]); - values[3] = static_cast(dvals[3]); - values[4] = static_cast(dvals[4]); - values[5] = static_cast(dvals[5]); - } - return err; - - /* 1x int */ - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) - *values = ivals[0]; - return err; - - /* 1x uint */ - case AL_BUFFER: - case AL_DIRECT_FILTER: - if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) - *values = static_cast(ivals[0]); - return err; - - /* 3x uint */ - case AL_AUXILIARY_SEND_FILTER: - if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) - { - values[0] = static_cast(ivals[0]); - values[1] = static_cast(ivals[1]); - values[2] = static_cast(ivals[2]); - } - return err; - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - case AL_STEREO_ANGLES: - break; /* Float/double only */ - } - - ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x", - prop); -} - -} // namespace - -AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(n < 0) - alSetError(context.get(), AL_INVALID_VALUE, "Generating %d sources", n); - else if(n == 1) - { - ALsource *source = AllocSource(context.get()); - if(source) sources[0] = source->id; - } - else - { - al::vector tempids(n); - auto alloc_end = std::find_if_not(tempids.begin(), tempids.end(), - [&context](ALuint &id) -> bool - { - ALsource *source{AllocSource(context.get())}; - if(!source) return false; - id = source->id; - return true; - } - ); - if(alloc_end != tempids.end()) - alDeleteSources(static_cast(std::distance(tempids.begin(), alloc_end)), - tempids.data()); - else - std::copy(tempids.cbegin(), tempids.cend(), sources); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Deleting %d sources", n); - - std::lock_guard _{context->SourceLock}; - - /* Check that all Sources are valid */ - const ALuint *sources_end = sources + n; - auto invsrc = std::find_if_not(sources, sources_end, - [&context](ALuint sid) -> bool - { - if(!LookupSource(context.get(), sid)) - { - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", sid); - return false; - } - return true; - } - ); - if(LIKELY(invsrc == sources_end)) - { - /* All good. Delete source IDs. */ - std::for_each(sources, sources_end, - [&context](ALuint sid) -> void - { - ALsource *src{LookupSource(context.get(), sid)}; - if(src) FreeSource(context.get(), src); - } - ); - } -} -END_API_FUNC - -AL_API ALboolean AL_APIENTRY alIsSource(ALuint source) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(LIKELY(context)) - { - std::lock_guard _{context->SourceLock}; - if(LookupSource(context.get(), source) != nullptr) - return AL_TRUE; - } - return AL_FALSE; -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(FloatValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid float property 0x%04x", param); - else - SetSourcefv(Source, context.get(), static_cast(param), &value); -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(FloatValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); - else - { - ALfloat fvals[3] = { value1, value2, value3 }; - SetSourcefv(Source, context.get(), static_cast(param), fvals); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(FloatValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); - else - SetSourcefv(Source, context.get(), static_cast(param), values); -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(DoubleValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid double property 0x%04x", param); - else - { - ALfloat fval = static_cast(value); - SetSourcefv(Source, context.get(), static_cast(param), &fval); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(DoubleValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); - else { - ALfloat fvals[3] = {static_cast(value1), - static_cast(value2), - static_cast(value3)}; - SetSourcefv(Source, context.get(), static_cast(param), fvals); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else - { - ALint count{DoubleValsByProp(param)}; - if(count < 1 || count > 6) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); - else - { - ALfloat fvals[6]; - ALint i; - - for(i = 0;i < count;i++) - fvals[i] = static_cast(values[i]); - SetSourcefv(Source, context.get(), static_cast(param), fvals); - } - } -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(IntValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); - else - SetSourceiv(Source, context.get(), static_cast(param), &value); -} -END_API_FUNC - -AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(IntValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); - else - { - ALint ivals[3] = { value1, value2, value3 }; - SetSourceiv(Source, context.get(), static_cast(param), ivals); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(IntValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); - else - SetSourceiv(Source, context.get(), static_cast(param), values); -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(Int64ValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); - else - SetSourcei64v(Source, context.get(), static_cast(param), &value); -} -END_API_FUNC - -AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(Int64ValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); - else - { - ALint64SOFT i64vals[3] = { value1, value2, value3 }; - SetSourcei64v(Source, context.get(), static_cast(param), i64vals); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(Int64ValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); - else - SetSourcei64v(Source, context.get(), static_cast(param), values); -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(FloatValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid float property 0x%04x", param); - else - { - ALdouble dval; - if(GetSourcedv(Source, context.get(), static_cast(param), &dval)) - *value = static_cast(dval); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(FloatValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); - else - { - ALdouble dvals[3]; - if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) - { - *value1 = static_cast(dvals[0]); - *value2 = static_cast(dvals[1]); - *value3 = static_cast(dvals[2]); - } - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else - { - ALint count{FloatValsByProp(param)}; - if(count < 1 && count > 6) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); - else - { - ALdouble dvals[6]; - if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) - { - for(ALint i{0};i < count;i++) - values[i] = static_cast(dvals[i]); - } - } - } -} -END_API_FUNC - - -AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(DoubleValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid double property 0x%04x", param); - else - GetSourcedv(Source, context.get(), static_cast(param), value); -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(DoubleValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); - else - { - ALdouble dvals[3]; - if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) - { - *value1 = dvals[0]; - *value2 = dvals[1]; - *value3 = dvals[2]; - } - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(DoubleValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); - else - GetSourcedv(Source, context.get(), static_cast(param), values); -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(IntValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); - else - GetSourceiv(Source, context.get(), static_cast(param), value); -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(IntValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); - else - { - ALint ivals[3]; - if(GetSourceiv(Source, context.get(), static_cast(param), ivals)) - { - *value1 = ivals[0]; - *value2 = ivals[1]; - *value3 = ivals[2]; - } - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(IntValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); - else - GetSourceiv(Source, context.get(), static_cast(param), values); -} -END_API_FUNC - - -AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(Int64ValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); - else - GetSourcei64v(Source, context.get(), static_cast(param), value); -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(Int64ValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); - else - { - ALint64SOFT i64vals[3]; - if(GetSourcei64v(Source, context.get(), static_cast(param), i64vals)) - { - *value1 = i64vals[0]; - *value2 = i64vals[1]; - *value3 = i64vals[2]; - } - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(Int64ValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); - else - GetSourcei64v(Source, context.get(), static_cast(param), values); -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source) -START_API_FUNC -{ alSourcePlayv(1, &source); } -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Playing %d sources", n); - if(n == 0) return; - - al::vector extra_sources; - std::array source_storage; - ALsource **srchandles{source_storage.data()}; - if(UNLIKELY(static_cast(n) > source_storage.size())) - { - extra_sources.resize(n); - srchandles = extra_sources.data(); - } - - std::lock_guard _{context->SourceLock}; - for(ALsizei i{0};i < n;i++) - { - srchandles[i] = LookupSource(context.get(), sources[i]); - if(!srchandles[i]) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); - } - - ALCdevice *device{context->Device}; - BackendLockGuard __{*device->Backend}; - /* If the device is disconnected, go right to stopped. */ - if(UNLIKELY(!device->Connected.load(std::memory_order_acquire))) - { - /* TODO: Send state change event? */ - std::for_each(srchandles, srchandles+n, - [](ALsource *source) -> void - { - source->OffsetType = AL_NONE; - source->Offset = 0.0; - source->state = AL_STOPPED; - } - ); - return; - } - - /* Count the number of reusable voices. */ - auto voices_end = context->Voices->begin() + - context->VoiceCount.load(std::memory_order_relaxed); - auto free_voices = std::accumulate(context->Voices->begin(), voices_end, ALsizei{0}, - [](const ALsizei count, const ALvoice &voice) noexcept -> ALsizei - { - if(voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && - voice.mSourceID.load(std::memory_order_relaxed) == 0u) - return count + 1; - return count; - } - ); - if(UNLIKELY(n > free_voices)) - { - /* Increment the number of voices to handle the request. */ - const ALuint need_voices{static_cast(n) - free_voices}; - const size_t rem_voices{context->Voices->size() - - context->VoiceCount.load(std::memory_order_relaxed)}; - - if(UNLIKELY(need_voices > rem_voices)) - { - /* Allocate more voices to get enough. */ - const size_t alloc_count{need_voices - rem_voices}; - if(UNLIKELY(context->Voices->size() > std::numeric_limits::max()-alloc_count)) - SETERR_RETURN(context.get(), AL_OUT_OF_MEMORY,, - "Overflow increasing voice count to %zu + %zu", context->Voices->size(), - alloc_count); - - const size_t newcount{context->Voices->size() + alloc_count}; - AllocateVoices(context.get(), newcount); - } - - context->VoiceCount.fetch_add(need_voices, std::memory_order_relaxed); - } - - auto start_source = [&context,device](ALsource *source) -> void - { - /* Check that there is a queue containing at least one valid, non zero - * length buffer. - */ - ALbufferlistitem *BufferList{source->queue}; - while(BufferList && BufferList->max_samples == 0) - BufferList = BufferList->next.load(std::memory_order_relaxed); - - /* If there's nothing to play, go right to stopped. */ - if(UNLIKELY(!BufferList)) - { - /* NOTE: A source without any playable buffers should not have an - * ALvoice since it shouldn't be in a playing or paused state. So - * there's no need to look up its voice and clear the source. - */ - ALenum oldstate{GetSourceState(source, nullptr)}; - source->OffsetType = AL_NONE; - source->Offset = 0.0; - if(oldstate != AL_STOPPED) - { - source->state = AL_STOPPED; - SendStateChangeEvent(context.get(), source->id, AL_STOPPED); - } - return; - } - - ALvoice *voice{GetSourceVoice(source, context.get())}; - switch(GetSourceState(source, voice)) - { - case AL_PLAYING: - assert(voice != nullptr); - /* A source that's already playing is restarted from the beginning. */ - voice->mCurrentBuffer.store(BufferList, std::memory_order_relaxed); - voice->mPosition.store(0u, std::memory_order_relaxed); - voice->mPositionFrac.store(0, std::memory_order_release); - return; - - case AL_PAUSED: - assert(voice != nullptr); - /* A source that's paused simply resumes. */ - voice->mPlayState.store(ALvoice::Playing, std::memory_order_release); - source->state = AL_PLAYING; - SendStateChangeEvent(context.get(), source->id, AL_PLAYING); - return; - - default: - assert(voice == nullptr); - break; - } - - /* Look for an unused voice to play this source with. */ - auto voices_end = context->Voices->begin() + - context->VoiceCount.load(std::memory_order_relaxed); - voice = std::find_if(context->Voices->begin(), voices_end, - [](const ALvoice &voice) noexcept -> bool - { - return voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && - voice.mSourceID.load(std::memory_order_relaxed) == 0u; - } - ); - assert(voice != voices_end); - auto vidx = static_cast(std::distance(context->Voices->begin(), voice)); - voice->mPlayState.store(ALvoice::Stopped, std::memory_order_release); - - source->PropsClean.test_and_set(std::memory_order_acquire); - UpdateSourceProps(source, voice, context.get()); - - /* A source that's not playing or paused has any offset applied when it - * starts playing. - */ - if(source->Looping) - voice->mLoopBuffer.store(source->queue, std::memory_order_relaxed); - else - voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); - voice->mCurrentBuffer.store(BufferList, std::memory_order_relaxed); - voice->mPosition.store(0u, std::memory_order_relaxed); - voice->mPositionFrac.store(0, std::memory_order_relaxed); - bool start_fading{false}; - if(ApplyOffset(source, voice) != AL_FALSE) - start_fading = voice->mPosition.load(std::memory_order_relaxed) != 0 || - voice->mPositionFrac.load(std::memory_order_relaxed) != 0 || - voice->mCurrentBuffer.load(std::memory_order_relaxed) != BufferList; - - auto buffers_end = BufferList->buffers + BufferList->num_buffers; - auto buffer = std::find_if(BufferList->buffers, buffers_end, - std::bind(std::not_equal_to{}, _1, nullptr)); - if(buffer != buffers_end) - { - voice->mFrequency = (*buffer)->Frequency; - voice->mFmtChannels = (*buffer)->mFmtChannels; - voice->mNumChannels = ChannelsFromFmt((*buffer)->mFmtChannels); - voice->mSampleSize = BytesFromFmt((*buffer)->mFmtType); - } - - /* Clear the stepping value so the mixer knows not to mix this until - * the update gets applied. - */ - voice->mStep = 0; - - voice->mFlags = start_fading ? VOICE_IS_FADING : 0; - if(source->SourceType == AL_STATIC) voice->mFlags |= VOICE_IS_STATIC; - - /* Don't need to set the VOICE_IS_AMBISONIC flag if the device is - * mixing in first order. No HF scaling is necessary to mix it. - */ - if((voice->mFmtChannels == FmtBFormat2D || voice->mFmtChannels == FmtBFormat3D) && - device->mAmbiOrder > 1) - { - const int *OrderFromChan; - if(voice->mFmtChannels == FmtBFormat2D) - { - static constexpr int Order2DFromChan[MAX_AMBI2D_CHANNELS]{ - 0, 1,1, 2,2, 3,3 - }; - OrderFromChan = Order2DFromChan; - } - else - { - static constexpr int Order3DFromChan[MAX_AMBI_CHANNELS]{ - 0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3, - }; - OrderFromChan = Order3DFromChan; - } - - BandSplitter splitter{400.0f / static_cast(device->Frequency)}; - - const auto scales = BFormatDec::GetHFOrderScales(1, device->mAmbiOrder); - auto init_ambi = [scales,&OrderFromChan,&splitter](ALvoice::ChannelData &chandata) -> void - { - chandata.mPrevSamples.fill(0.0f); - chandata.mAmbiScale = scales[*(OrderFromChan++)]; - chandata.mAmbiSplitter = splitter; - }; - std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, - init_ambi); - - voice->mFlags |= VOICE_IS_AMBISONIC; - } - else - { - /* Clear previous samples. */ - auto clear_prevs = [](ALvoice::ChannelData &chandata) -> void - { chandata.mPrevSamples.fill(0.0f); }; - std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, - clear_prevs); - } - - auto clear_params = [device](ALvoice::ChannelData &chandata) -> void - { - chandata.mDryParams = DirectParams{}; - std::fill_n(chandata.mWetParams.begin(), device->NumAuxSends, SendParams{}); - }; - std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, - clear_params); - - if(device->AvgSpeakerDist > 0.0f) - { - const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC / - (device->AvgSpeakerDist * device->Frequency)}; - auto init_nfc = [w1](ALvoice::ChannelData &chandata) -> void - { chandata.mDryParams.NFCtrlFilter.init(w1); }; - std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, - init_nfc); - } - - voice->mSourceID.store(source->id, std::memory_order_relaxed); - voice->mPlayState.store(ALvoice::Playing, std::memory_order_release); - source->state = AL_PLAYING; - source->VoiceIdx = vidx; - - SendStateChangeEvent(context.get(), source->id, AL_PLAYING); - }; - std::for_each(srchandles, srchandles+n, start_source); -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source) -START_API_FUNC -{ alSourcePausev(1, &source); } -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Pausing %d sources", n); - if(n == 0) return; - - al::vector extra_sources; - std::array source_storage; - ALsource **srchandles{source_storage.data()}; - if(UNLIKELY(static_cast(n) > source_storage.size())) - { - extra_sources.resize(n); - srchandles = extra_sources.data(); - } - - std::lock_guard _{context->SourceLock}; - for(ALsizei i{0};i < n;i++) - { - srchandles[i] = LookupSource(context.get(), sources[i]); - if(!srchandles[i]) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); - } - - ALCdevice *device{context->Device}; - BackendLockGuard __{*device->Backend}; - auto pause_source = [&context](ALsource *source) -> void - { - ALvoice *voice{GetSourceVoice(source, context.get())}; - if(voice) - { - std::atomic_thread_fence(std::memory_order_release); - ALvoice::State oldvstate{ALvoice::Playing}; - voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping, - std::memory_order_acq_rel, std::memory_order_acquire); - } - if(GetSourceState(source, voice) == AL_PLAYING) - { - source->state = AL_PAUSED; - SendStateChangeEvent(context.get(), source->id, AL_PAUSED); - } - }; - std::for_each(srchandles, srchandles+n, pause_source); -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source) -START_API_FUNC -{ alSourceStopv(1, &source); } -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Stopping %d sources", n); - if(n == 0) return; - - al::vector extra_sources; - std::array source_storage; - ALsource **srchandles{source_storage.data()}; - if(UNLIKELY(static_cast(n) > source_storage.size())) - { - extra_sources.resize(n); - srchandles = extra_sources.data(); - } - - std::lock_guard _{context->SourceLock}; - for(ALsizei i{0};i < n;i++) - { - srchandles[i] = LookupSource(context.get(), sources[i]); - if(!srchandles[i]) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); - } - - ALCdevice *device{context->Device}; - BackendLockGuard __{*device->Backend}; - auto stop_source = [&context](ALsource *source) -> void - { - ALvoice *voice{GetSourceVoice(source, context.get())}; - if(voice != nullptr) - { - voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed); - voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); - voice->mSourceID.store(0u, std::memory_order_relaxed); - std::atomic_thread_fence(std::memory_order_release); - ALvoice::State oldvstate{ALvoice::Playing}; - voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping, - std::memory_order_acq_rel, std::memory_order_acquire); - voice = nullptr; - } - ALenum oldstate{GetSourceState(source, voice)}; - if(oldstate != AL_INITIAL && oldstate != AL_STOPPED) - { - source->state = AL_STOPPED; - SendStateChangeEvent(context.get(), source->id, AL_STOPPED); - } - source->OffsetType = AL_NONE; - source->Offset = 0.0; - }; - std::for_each(srchandles, srchandles+n, stop_source); -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source) -START_API_FUNC -{ alSourceRewindv(1, &source); } -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Rewinding %d sources", n); - if(n == 0) return; - - al::vector extra_sources; - std::array source_storage; - ALsource **srchandles{source_storage.data()}; - if(UNLIKELY(static_cast(n) > source_storage.size())) - { - extra_sources.resize(n); - srchandles = extra_sources.data(); - } - - std::lock_guard _{context->SourceLock}; - for(ALsizei i{0};i < n;i++) - { - srchandles[i] = LookupSource(context.get(), sources[i]); - if(!srchandles[i]) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); - } - - ALCdevice *device{context->Device}; - BackendLockGuard __{*device->Backend}; - auto rewind_source = [&context](ALsource *source) -> void - { - ALvoice *voice{GetSourceVoice(source, context.get())}; - if(voice != nullptr) - { - voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed); - voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); - voice->mSourceID.store(0u, std::memory_order_relaxed); - std::atomic_thread_fence(std::memory_order_release); - ALvoice::State oldvstate{ALvoice::Playing}; - voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping, - std::memory_order_acq_rel, std::memory_order_acquire); - voice = nullptr; - } - if(GetSourceState(source, voice) != AL_INITIAL) - { - source->state = AL_INITIAL; - SendStateChangeEvent(context.get(), source->id, AL_INITIAL); - } - source->OffsetType = AL_NONE; - source->Offset = 0.0; - }; - std::for_each(srchandles, srchandles+n, rewind_source); -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(nb < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffers", nb); - if(nb == 0) return; - - std::lock_guard _{context->SourceLock}; - ALsource *source{LookupSource(context.get(),src)}; - if(UNLIKELY(!source)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); - - /* Can't queue on a Static Source */ - if(UNLIKELY(source->SourceType == AL_STATIC)) - SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src); - - /* Check for a valid Buffer, for its frequency and format */ - ALCdevice *device{context->Device}; - ALbuffer *BufferFmt{nullptr}; - ALbufferlistitem *BufferList{source->queue}; - while(BufferList) - { - for(ALsizei i{0};i < BufferList->num_buffers;i++) - { - if((BufferFmt=BufferList->buffers[i]) != nullptr) - break; - } - if(BufferFmt) break; - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - - std::unique_lock buflock{device->BufferLock}; - ALbufferlistitem *BufferListStart{nullptr}; - BufferList = nullptr; - for(ALsizei i{0};i < nb;i++) - { - ALbuffer *buffer{nullptr}; - if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr) - { - alSetError(context.get(), AL_INVALID_NAME, "Queueing invalid buffer ID %u", - buffers[i]); - goto buffer_error; - } - - if(!BufferListStart) - { - BufferListStart = static_cast(al_calloc(alignof(void*), - ALbufferlistitem::Sizeof(1u))); - BufferList = BufferListStart; - } - else - { - auto item = static_cast(al_calloc(alignof(void*), - ALbufferlistitem::Sizeof(1u))); - BufferList->next.store(item, std::memory_order_relaxed); - BufferList = item; - } - BufferList->next.store(nullptr, std::memory_order_relaxed); - BufferList->max_samples = buffer ? buffer->SampleLen : 0; - BufferList->num_buffers = 1; - BufferList->buffers[0] = buffer; - if(!buffer) continue; - - IncrementRef(&buffer->ref); - - if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) - { - alSetError(context.get(), AL_INVALID_OPERATION, - "Queueing non-persistently mapped buffer %u", buffer->id); - goto buffer_error; - } - - if(BufferFmt == nullptr) - BufferFmt = buffer; - else if(BufferFmt->Frequency != buffer->Frequency || - BufferFmt->mFmtChannels != buffer->mFmtChannels || - BufferFmt->OriginalType != buffer->OriginalType) - { - alSetError(context.get(), AL_INVALID_OPERATION, - "Queueing buffer with mismatched format"); - - buffer_error: - /* A buffer failed (invalid ID or format), so unlock and release - * each buffer we had. */ - while(BufferListStart) - { - ALbufferlistitem *next = BufferListStart->next.load(std::memory_order_relaxed); - for(i = 0;i < BufferListStart->num_buffers;i++) - { - if((buffer=BufferListStart->buffers[i]) != nullptr) - DecrementRef(&buffer->ref); - } - al_free(BufferListStart); - BufferListStart = next; - } - return; - } - } - /* All buffers good. */ - buflock.unlock(); - - /* Source is now streaming */ - source->SourceType = AL_STREAMING; - - if(!(BufferList=source->queue)) - source->queue = BufferListStart; - else - { - ALbufferlistitem *next; - while((next=BufferList->next.load(std::memory_order_relaxed)) != nullptr) - BufferList = next; - BufferList->next.store(BufferListStart, std::memory_order_release); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(nb < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffer layers", nb); - if(nb == 0) return; - - std::lock_guard _{context->SourceLock}; - ALsource *source{LookupSource(context.get(),src)}; - if(UNLIKELY(!source)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); - - /* Can't queue on a Static Source */ - if(UNLIKELY(source->SourceType == AL_STATIC)) - SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src); - - /* Check for a valid Buffer, for its frequency and format */ - ALCdevice *device{context->Device}; - ALbuffer *BufferFmt{nullptr}; - ALbufferlistitem *BufferList{source->queue}; - while(BufferList) - { - for(ALsizei i{0};i < BufferList->num_buffers;i++) - { - if((BufferFmt=BufferList->buffers[i]) != nullptr) - break; - } - if(BufferFmt) break; - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - - std::unique_lock buflock{device->BufferLock}; - auto BufferListStart = static_cast(al_calloc(alignof(void*), - ALbufferlistitem::Sizeof(nb))); - BufferList = BufferListStart; - BufferList->next.store(nullptr, std::memory_order_relaxed); - BufferList->max_samples = 0; - BufferList->num_buffers = 0; - - for(ALsizei i{0};i < nb;i++) - { - ALbuffer *buffer{nullptr}; - if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr) - { - alSetError(context.get(), AL_INVALID_NAME, "Queueing invalid buffer ID %u", - buffers[i]); - goto buffer_error; - } - - BufferList->buffers[BufferList->num_buffers++] = buffer; - if(!buffer) continue; - - IncrementRef(&buffer->ref); - - BufferList->max_samples = maxi(BufferList->max_samples, buffer->SampleLen); - - if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) - { - alSetError(context.get(), AL_INVALID_OPERATION, - "Queueing non-persistently mapped buffer %u", buffer->id); - goto buffer_error; - } - - if(BufferFmt == nullptr) - BufferFmt = buffer; - else if(BufferFmt->Frequency != buffer->Frequency || - BufferFmt->mFmtChannels != buffer->mFmtChannels || - BufferFmt->OriginalType != buffer->OriginalType) - { - alSetError(context.get(), AL_INVALID_OPERATION, - "Queueing buffer with mismatched format"); - - buffer_error: - /* A buffer failed (invalid ID or format), so unlock and release - * each buffer we had. */ - while(BufferListStart) - { - ALbufferlistitem *next{BufferListStart->next.load(std::memory_order_relaxed)}; - for(i = 0;i < BufferListStart->num_buffers;i++) - { - if((buffer=BufferListStart->buffers[i]) != nullptr) - DecrementRef(&buffer->ref); - } - al_free(BufferListStart); - BufferListStart = next; - } - return; - } - } - /* All buffers good. */ - buflock.unlock(); - - /* Source is now streaming */ - source->SourceType = AL_STREAMING; - - if(!(BufferList=source->queue)) - source->queue = BufferListStart; - else - { - ALbufferlistitem *next; - while((next=BufferList->next.load(std::memory_order_relaxed)) != nullptr) - BufferList = next; - BufferList->next.store(BufferListStart, std::memory_order_release); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(nb < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing %d buffers", nb); - if(nb == 0) return; - - std::lock_guard _{context->SourceLock}; - ALsource *source{LookupSource(context.get(),src)}; - if(UNLIKELY(!source)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); - - if(UNLIKELY(source->Looping)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing from looping source %u", src); - if(UNLIKELY(source->SourceType != AL_STREAMING)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, - "Unqueueing from a non-streaming source %u", src); - - /* Make sure enough buffers have been processed to unqueue. */ - ALbufferlistitem *BufferList{source->queue}; - ALvoice *voice{GetSourceVoice(source, context.get())}; - ALbufferlistitem *Current{nullptr}; - if(voice) - Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); - else if(source->state == AL_INITIAL) - Current = BufferList; - if(UNLIKELY(BufferList == Current)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing pending buffers"); - - ALsizei i{BufferList->num_buffers}; - while(i < nb) - { - /* If the next bufferlist to check is NULL or is the current one, it's - * trying to unqueue pending buffers. - */ - ALbufferlistitem *next{BufferList->next.load(std::memory_order_relaxed)}; - if(UNLIKELY(!next) || UNLIKELY(next == Current)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing pending buffers"); - BufferList = next; - - i += BufferList->num_buffers; - } - - while(nb > 0) - { - ALbufferlistitem *head{source->queue}; - ALbufferlistitem *next{head->next.load(std::memory_order_relaxed)}; - for(i = 0;i < head->num_buffers && nb > 0;i++,nb--) - { - ALbuffer *buffer{head->buffers[i]}; - if(!buffer) - *(buffers++) = 0; - else - { - *(buffers++) = buffer->id; - DecrementRef(&buffer->ref); - } - } - if(i < head->num_buffers) - { - /* This head has some buffers left over, so move them to the front - * and update the sample and buffer count. - */ - ALsizei max_length{0}; - ALsizei j{0}; - while(i < head->num_buffers) - { - ALbuffer *buffer{head->buffers[i++]}; - if(buffer) max_length = maxi(max_length, buffer->SampleLen); - head->buffers[j++] = buffer; - } - head->max_samples = max_length; - head->num_buffers = j; - break; - } - - /* Otherwise, free this item and set the source queue head to the next - * one. - */ - al_free(head); - source->queue = next; - } -} -END_API_FUNC - - -ALsource::ALsource(ALsizei num_sends) -{ - InnerAngle = 360.0f; - OuterAngle = 360.0f; - Pitch = 1.0f; - Position[0] = 0.0f; - Position[1] = 0.0f; - Position[2] = 0.0f; - Velocity[0] = 0.0f; - Velocity[1] = 0.0f; - Velocity[2] = 0.0f; - Direction[0] = 0.0f; - Direction[1] = 0.0f; - Direction[2] = 0.0f; - OrientAt[0] = 0.0f; - OrientAt[1] = 0.0f; - OrientAt[2] = -1.0f; - OrientUp[0] = 0.0f; - OrientUp[1] = 1.0f; - OrientUp[2] = 0.0f; - RefDistance = 1.0f; - MaxDistance = std::numeric_limits::max(); - RolloffFactor = 1.0f; - Gain = 1.0f; - MinGain = 0.0f; - MaxGain = 1.0f; - OuterGain = 0.0f; - OuterGainHF = 1.0f; - - DryGainHFAuto = AL_TRUE; - WetGainAuto = AL_TRUE; - WetGainHFAuto = AL_TRUE; - AirAbsorptionFactor = 0.0f; - RoomRolloffFactor = 0.0f; - DopplerFactor = 1.0f; - HeadRelative = AL_FALSE; - Looping = AL_FALSE; - mDistanceModel = DistanceModel::Default; - mResampler = ResamplerDefault; - DirectChannels = AL_FALSE; - mSpatialize = SpatializeAuto; - - StereoPan[0] = Deg2Rad( 30.0f); - StereoPan[1] = Deg2Rad(-30.0f); - - Radius = 0.0f; - - Direct.Gain = 1.0f; - Direct.GainHF = 1.0f; - Direct.HFReference = LOWPASSFREQREF; - Direct.GainLF = 1.0f; - Direct.LFReference = HIGHPASSFREQREF; - Send.resize(num_sends); - for(auto &send : Send) - { - send.Slot = nullptr; - send.Gain = 1.0f; - send.GainHF = 1.0f; - send.HFReference = LOWPASSFREQREF; - send.GainLF = 1.0f; - send.LFReference = HIGHPASSFREQREF; - } - - Offset = 0.0; - OffsetType = AL_NONE; - SourceType = AL_UNDETERMINED; - state = AL_INITIAL; - - queue = nullptr; - - PropsClean.test_and_set(std::memory_order_relaxed); - - VoiceIdx = -1; -} - -ALsource::~ALsource() -{ - ALbufferlistitem *BufferList{queue}; - while(BufferList != nullptr) - { - ALbufferlistitem *next{BufferList->next.load(std::memory_order_relaxed)}; - for(ALsizei i{0};i < BufferList->num_buffers;i++) - { - if(BufferList->buffers[i]) - DecrementRef(&BufferList->buffers[i]->ref); - } - al_free(BufferList); - BufferList = next; - } - queue = nullptr; - - std::for_each(Send.begin(), Send.end(), - [](ALsource::SendData &send) -> void - { - if(send.Slot) - DecrementRef(&send.Slot->ref); - send.Slot = nullptr; - } - ); -} - -void UpdateAllSourceProps(ALCcontext *context) -{ - auto voices_end = context->Voices->begin() + - context->VoiceCount.load(std::memory_order_relaxed); - std::for_each(context->Voices->begin(), voices_end, - [context](ALvoice &voice) -> void - { - ALuint sid{voice.mSourceID.load(std::memory_order_acquire)}; - ALsource *source = sid ? LookupSource(context, sid) : nullptr; - if(source && !source->PropsClean.test_and_set(std::memory_order_acq_rel)) - UpdateSourceProps(source, &voice, context); - } - ); -} - -SourceSubList::~SourceSubList() -{ - uint64_t usemask{~FreeMask}; - while(usemask) - { - ALsizei idx{CTZ64(usemask)}; - al::destroy_at(Sources+idx); - usemask &= ~(1_u64 << idx); - } - FreeMask = ~usemask; - al_free(Sources); - Sources = nullptr; -} diff --git a/OpenAL32/alSource.h b/OpenAL32/alSource.h deleted file mode 100644 index c9892398..00000000 --- a/OpenAL32/alSource.h +++ /dev/null @@ -1,131 +0,0 @@ -#ifndef AL_SOURCE_H -#define AL_SOURCE_H - -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" - -#include "alcontext.h" -#include "alnumeric.h" -#include "alu.h" -#include "vector.h" - -struct ALbuffer; -struct ALeffectslot; - - -#define DEFAULT_SENDS 2 - - -struct ALbufferlistitem { - std::atomic next; - ALsizei max_samples; - ALsizei num_buffers; - ALbuffer *buffers[]; - - static constexpr size_t Sizeof(size_t num_buffers) noexcept - { - return maxz(offsetof(ALbufferlistitem, buffers) + sizeof(ALbuffer*)*num_buffers, - sizeof(ALbufferlistitem)); - } -}; - - -struct ALsource { - /** Source properties. */ - ALfloat Pitch; - ALfloat Gain; - ALfloat OuterGain; - ALfloat MinGain; - ALfloat MaxGain; - ALfloat InnerAngle; - ALfloat OuterAngle; - ALfloat RefDistance; - ALfloat MaxDistance; - ALfloat RolloffFactor; - std::array Position; - std::array Velocity; - std::array Direction; - std::array OrientAt; - std::array OrientUp; - ALboolean HeadRelative; - ALboolean Looping; - DistanceModel mDistanceModel; - Resampler mResampler; - ALboolean DirectChannels; - SpatializeMode mSpatialize; - - ALboolean DryGainHFAuto; - ALboolean WetGainAuto; - ALboolean WetGainHFAuto; - ALfloat OuterGainHF; - - ALfloat AirAbsorptionFactor; - ALfloat RoomRolloffFactor; - ALfloat DopplerFactor; - - /* NOTE: Stereo pan angles are specified in radians, counter-clockwise - * rather than clockwise. - */ - std::array StereoPan; - - ALfloat Radius; - - /** Direct filter and auxiliary send info. */ - struct { - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - } Direct; - struct SendData { - ALeffectslot *Slot; - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - }; - al::vector Send; - - /** - * Last user-specified offset, and the offset type (bytes, samples, or - * seconds). - */ - ALdouble Offset; - ALenum OffsetType; - - /** Source type (static, streaming, or undetermined) */ - ALint SourceType; - - /** Source state (initial, playing, paused, or stopped) */ - ALenum state; - - /** Source Buffer Queue head. */ - ALbufferlistitem *queue; - - std::atomic_flag PropsClean; - - /* Index into the context's Voices array. Lazily updated, only checked and - * reset when looking up the voice. - */ - ALint VoiceIdx; - - /** Self ID */ - ALuint id; - - - ALsource(ALsizei num_sends); - ~ALsource(); - - ALsource(const ALsource&) = delete; - ALsource& operator=(const ALsource&) = delete; -}; - -void UpdateAllSourceProps(ALCcontext *context); - -#endif diff --git a/OpenAL32/alState.cpp b/OpenAL32/alState.cpp deleted file mode 100644 index ee8d3a1c..00000000 --- a/OpenAL32/alState.cpp +++ /dev/null @@ -1,859 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2000 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "version.h" - -#include -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" - -#include "alError.h" -#include "alcmain.h" -#include "alcontext.h" -#include "alexcpt.h" -#include "almalloc.h" -#include "alspan.h" -#include "alu.h" -#include "atomic.h" -#include "inprogext.h" -#include "opthelpers.h" - - -namespace { - -constexpr ALchar alVendor[] = "OpenAL Community"; -constexpr ALchar alVersion[] = "1.1 ALSOFT " ALSOFT_VERSION; -constexpr ALchar alRenderer[] = "OpenAL Soft"; - -// Error Messages -constexpr ALchar alNoError[] = "No Error"; -constexpr ALchar alErrInvalidName[] = "Invalid Name"; -constexpr ALchar alErrInvalidEnum[] = "Invalid Enum"; -constexpr ALchar alErrInvalidValue[] = "Invalid Value"; -constexpr ALchar alErrInvalidOp[] = "Invalid Operation"; -constexpr ALchar alErrOutOfMemory[] = "Out of Memory"; - -/* Resampler strings */ -constexpr ALchar alPointResampler[] = "Nearest"; -constexpr ALchar alLinearResampler[] = "Linear"; -constexpr ALchar alCubicResampler[] = "Cubic"; -constexpr ALchar alBSinc12Resampler[] = "11th order Sinc"; -constexpr ALchar alBSinc24Resampler[] = "23rd order Sinc"; - -} // namespace - -/* WARNING: Non-standard export! Not part of any extension, or exposed in the - * alcFunctions list. - */ -extern "C" AL_API const ALchar* AL_APIENTRY alsoft_get_version(void) -START_API_FUNC -{ - const char *spoof{getenv("ALSOFT_SPOOF_VERSION")}; - if(spoof && spoof[0] != '\0') return spoof; - return ALSOFT_VERSION; -} -END_API_FUNC - -#define DO_UPDATEPROPS() do { \ - if(!context->DeferUpdates.load(std::memory_order_acquire)) \ - UpdateContextProps(context.get()); \ - else \ - context->PropsClean.clear(std::memory_order_release); \ -} while(0) - - -AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - switch(capability) - { - case AL_SOURCE_DISTANCE_MODEL: - context->SourceDistanceModel = AL_TRUE; - DO_UPDATEPROPS(); - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - switch(capability) - { - case AL_SOURCE_DISTANCE_MODEL: - context->SourceDistanceModel = AL_FALSE; - DO_UPDATEPROPS(); - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability); - } -} -END_API_FUNC - -AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return AL_FALSE; - - std::lock_guard _{context->PropLock}; - ALboolean value{AL_FALSE}; - switch(capability) - { - case AL_SOURCE_DISTANCE_MODEL: - value = context->SourceDistanceModel; - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability); - } - - return value; -} -END_API_FUNC - -AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return AL_FALSE; - - std::lock_guard _{context->PropLock}; - ALboolean value{AL_FALSE}; - switch(pname) - { - case AL_DOPPLER_FACTOR: - if(context->DopplerFactor != 0.0f) - value = AL_TRUE; - break; - - case AL_DOPPLER_VELOCITY: - if(context->DopplerVelocity != 0.0f) - value = AL_TRUE; - break; - - case AL_DISTANCE_MODEL: - if(context->mDistanceModel == DistanceModel::Default) - value = AL_TRUE; - break; - - case AL_SPEED_OF_SOUND: - if(context->SpeedOfSound != 0.0f) - value = AL_TRUE; - break; - - case AL_DEFERRED_UPDATES_SOFT: - if(context->DeferUpdates.load(std::memory_order_acquire)) - value = AL_TRUE; - break; - - case AL_GAIN_LIMIT_SOFT: - if(GAIN_MIX_MAX/context->GainBoost != 0.0f) - value = AL_TRUE; - break; - - case AL_NUM_RESAMPLERS_SOFT: - /* Always non-0. */ - value = AL_TRUE; - break; - - case AL_DEFAULT_RESAMPLER_SOFT: - value = ResamplerDefault ? AL_TRUE : AL_FALSE; - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid boolean property 0x%04x", pname); - } - - return value; -} -END_API_FUNC - -AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return 0.0; - - std::lock_guard _{context->PropLock}; - ALdouble value{0.0}; - switch(pname) - { - case AL_DOPPLER_FACTOR: - value = static_cast(context->DopplerFactor); - break; - - case AL_DOPPLER_VELOCITY: - value = static_cast(context->DopplerVelocity); - break; - - case AL_DISTANCE_MODEL: - value = static_cast(context->mDistanceModel); - break; - - case AL_SPEED_OF_SOUND: - value = static_cast(context->SpeedOfSound); - break; - - case AL_DEFERRED_UPDATES_SOFT: - if(context->DeferUpdates.load(std::memory_order_acquire)) - value = static_cast(AL_TRUE); - break; - - case AL_GAIN_LIMIT_SOFT: - value = static_castGAIN_MIX_MAX/context->GainBoost; - break; - - case AL_NUM_RESAMPLERS_SOFT: - value = static_cast(ResamplerMax + 1); - break; - - case AL_DEFAULT_RESAMPLER_SOFT: - value = static_cast(ResamplerDefault); - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid double property 0x%04x", pname); - } - - return value; -} -END_API_FUNC - -AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return 0.0f; - - std::lock_guard _{context->PropLock}; - ALfloat value{0.0f}; - switch(pname) - { - case AL_DOPPLER_FACTOR: - value = context->DopplerFactor; - break; - - case AL_DOPPLER_VELOCITY: - value = context->DopplerVelocity; - break; - - case AL_DISTANCE_MODEL: - value = static_cast(context->mDistanceModel); - break; - - case AL_SPEED_OF_SOUND: - value = context->SpeedOfSound; - break; - - case AL_DEFERRED_UPDATES_SOFT: - if(context->DeferUpdates.load(std::memory_order_acquire)) - value = static_cast(AL_TRUE); - break; - - case AL_GAIN_LIMIT_SOFT: - value = GAIN_MIX_MAX/context->GainBoost; - break; - - case AL_NUM_RESAMPLERS_SOFT: - value = static_cast(ResamplerMax + 1); - break; - - case AL_DEFAULT_RESAMPLER_SOFT: - value = static_cast(ResamplerDefault); - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid float property 0x%04x", pname); - } - - return value; -} -END_API_FUNC - -AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return 0; - - std::lock_guard _{context->PropLock}; - ALint value{0}; - switch(pname) - { - case AL_DOPPLER_FACTOR: - value = static_cast(context->DopplerFactor); - break; - - case AL_DOPPLER_VELOCITY: - value = static_cast(context->DopplerVelocity); - break; - - case AL_DISTANCE_MODEL: - value = static_cast(context->mDistanceModel); - break; - - case AL_SPEED_OF_SOUND: - value = static_cast(context->SpeedOfSound); - break; - - case AL_DEFERRED_UPDATES_SOFT: - if(context->DeferUpdates.load(std::memory_order_acquire)) - value = static_cast(AL_TRUE); - break; - - case AL_GAIN_LIMIT_SOFT: - value = static_cast(GAIN_MIX_MAX/context->GainBoost); - break; - - case AL_NUM_RESAMPLERS_SOFT: - value = ResamplerMax + 1; - break; - - case AL_DEFAULT_RESAMPLER_SOFT: - value = ResamplerDefault; - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer property 0x%04x", pname); - } - - return value; -} -END_API_FUNC - -extern "C" AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return 0; - - std::lock_guard _{context->PropLock}; - ALint64SOFT value{0}; - switch(pname) - { - case AL_DOPPLER_FACTOR: - value = (ALint64SOFT)context->DopplerFactor; - break; - - case AL_DOPPLER_VELOCITY: - value = (ALint64SOFT)context->DopplerVelocity; - break; - - case AL_DISTANCE_MODEL: - value = (ALint64SOFT)context->mDistanceModel; - break; - - case AL_SPEED_OF_SOUND: - value = (ALint64SOFT)context->SpeedOfSound; - break; - - case AL_DEFERRED_UPDATES_SOFT: - if(context->DeferUpdates.load(std::memory_order_acquire)) - value = (ALint64SOFT)AL_TRUE; - break; - - case AL_GAIN_LIMIT_SOFT: - value = (ALint64SOFT)(GAIN_MIX_MAX/context->GainBoost); - break; - - case AL_NUM_RESAMPLERS_SOFT: - value = (ALint64SOFT)(ResamplerMax + 1); - break; - - case AL_DEFAULT_RESAMPLER_SOFT: - value = (ALint64SOFT)ResamplerDefault; - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer64 property 0x%04x", pname); - } - - return value; -} -END_API_FUNC - -AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return nullptr; - - std::lock_guard _{context->PropLock}; - void *value{nullptr}; - switch(pname) - { - case AL_EVENT_CALLBACK_FUNCTION_SOFT: - value = reinterpret_cast(context->EventCb); - break; - - case AL_EVENT_CALLBACK_USER_PARAM_SOFT: - value = context->EventParam; - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname); - } - - return value; -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values) -START_API_FUNC -{ - if(values) - { - switch(pname) - { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetBoolean(pname); - return; - } - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(pname) - { - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid boolean-vector property 0x%04x", pname); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values) -START_API_FUNC -{ - if(values) - { - switch(pname) - { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetDouble(pname); - return; - } - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(pname) - { - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid double-vector property 0x%04x", pname); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values) -START_API_FUNC -{ - if(values) - { - switch(pname) - { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetFloat(pname); - return; - } - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(pname) - { - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid float-vector property 0x%04x", pname); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values) -START_API_FUNC -{ - if(values) - { - switch(pname) - { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetInteger(pname); - return; - } - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(pname) - { - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer-vector property 0x%04x", pname); - } -} -END_API_FUNC - -extern "C" AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values) -START_API_FUNC -{ - if(values) - { - switch(pname) - { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetInteger64SOFT(pname); - return; - } - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(pname) - { - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer64-vector property 0x%04x", pname); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values) -START_API_FUNC -{ - if(values) - { - switch(pname) - { - case AL_EVENT_CALLBACK_FUNCTION_SOFT: - case AL_EVENT_CALLBACK_USER_PARAM_SOFT: - values[0] = alGetPointerSOFT(pname); - return; - } - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(pname) - { - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid pointer-vector property 0x%04x", pname); - } -} -END_API_FUNC - -AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return nullptr; - - const ALchar *value{nullptr}; - switch(pname) - { - case AL_VENDOR: - value = alVendor; - break; - - case AL_VERSION: - value = alVersion; - break; - - case AL_RENDERER: - value = alRenderer; - break; - - case AL_EXTENSIONS: - value = context->ExtensionList; - break; - - case AL_NO_ERROR: - value = alNoError; - break; - - case AL_INVALID_NAME: - value = alErrInvalidName; - break; - - case AL_INVALID_ENUM: - value = alErrInvalidEnum; - break; - - case AL_INVALID_VALUE: - value = alErrInvalidValue; - break; - - case AL_INVALID_OPERATION: - value = alErrInvalidOp; - break; - - case AL_OUT_OF_MEMORY: - value = alErrOutOfMemory; - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid string property 0x%04x", pname); - } - return value; -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(!(value >= 0.0f && std::isfinite(value))) - alSetError(context.get(), AL_INVALID_VALUE, "Doppler factor %f out of range", value); - else - { - std::lock_guard _{context->PropLock}; - context->DopplerFactor = value; - DO_UPDATEPROPS(); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if((context->EnabledEvts.load(std::memory_order_relaxed)&EventType_Deprecated)) - { - static constexpr ALCchar msg[] = - "alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound"; - const ALsizei msglen = static_cast(strlen(msg)); - std::lock_guard _{context->EventCbLock}; - ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; - if((enabledevts&EventType_Deprecated) && context->EventCb) - (*context->EventCb)(AL_EVENT_TYPE_DEPRECATED_SOFT, 0, 0, msglen, msg, - context->EventParam); - } - - if(!(value >= 0.0f && std::isfinite(value))) - alSetError(context.get(), AL_INVALID_VALUE, "Doppler velocity %f out of range", value); - else - { - std::lock_guard _{context->PropLock}; - context->DopplerVelocity = value; - DO_UPDATEPROPS(); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(!(value > 0.0f && std::isfinite(value))) - alSetError(context.get(), AL_INVALID_VALUE, "Speed of sound %f out of range", value); - else - { - std::lock_guard _{context->PropLock}; - context->SpeedOfSound = value; - DO_UPDATEPROPS(); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(!(value == AL_INVERSE_DISTANCE || value == AL_INVERSE_DISTANCE_CLAMPED || - value == AL_LINEAR_DISTANCE || value == AL_LINEAR_DISTANCE_CLAMPED || - value == AL_EXPONENT_DISTANCE || value == AL_EXPONENT_DISTANCE_CLAMPED || - value == AL_NONE)) - alSetError(context.get(), AL_INVALID_VALUE, "Distance model 0x%04x out of range", value); - else - { - std::lock_guard _{context->PropLock}; - context->mDistanceModel = static_cast(value); - if(!context->SourceDistanceModel) - DO_UPDATEPROPS(); - } -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCcontext_DeferUpdates(context.get()); -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCcontext_ProcessUpdates(context.get()); -} -END_API_FUNC - - -AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index) -START_API_FUNC -{ - const char *ResamplerNames[] = { - alPointResampler, alLinearResampler, - alCubicResampler, alBSinc12Resampler, - alBSinc24Resampler, - }; - static_assert(al::size(ResamplerNames) == ResamplerMax+1, "Incorrect ResamplerNames list"); - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return nullptr; - - const ALchar *value{nullptr}; - switch(pname) - { - case AL_RESAMPLER_NAME_SOFT: - if(index < 0 || static_cast(index) >= al::size(ResamplerNames)) - alSetError(context.get(), AL_INVALID_VALUE, "Resampler name index %d out of range", - index); - else - value = ResamplerNames[index]; - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid string indexed property"); - } - return value; -} -END_API_FUNC - - -void UpdateContextProps(ALCcontext *context) -{ - /* Get an unused proprty container, or allocate a new one as needed. */ - ALcontextProps *props{context->FreeContextProps.load(std::memory_order_acquire)}; - if(!props) - props = static_cast(al_calloc(16, sizeof(*props))); - else - { - ALcontextProps *next; - do { - next = props->next.load(std::memory_order_relaxed); - } while(context->FreeContextProps.compare_exchange_weak(props, next, - std::memory_order_seq_cst, std::memory_order_acquire) == 0); - } - - /* Copy in current property values. */ - props->MetersPerUnit = context->MetersPerUnit; - - props->DopplerFactor = context->DopplerFactor; - props->DopplerVelocity = context->DopplerVelocity; - props->SpeedOfSound = context->SpeedOfSound; - - props->SourceDistanceModel = context->SourceDistanceModel; - props->mDistanceModel = context->mDistanceModel; - - /* Set the new container for updating internal parameters. */ - props = context->Update.exchange(props, std::memory_order_acq_rel); - if(props) - { - /* If there was an unused update container, put it back in the - * freelist. - */ - AtomicReplaceHead(context->FreeContextProps, props); - } -} diff --git a/OpenAL32/event.cpp b/OpenAL32/event.cpp deleted file mode 100644 index d50cef2e..00000000 --- a/OpenAL32/event.cpp +++ /dev/null @@ -1,216 +0,0 @@ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" - -#include "alError.h" -#include "albyte.h" -#include "alcmain.h" -#include "alcontext.h" -#include "alexcpt.h" -#include "almalloc.h" -#include "effects/base.h" -#include "inprogext.h" -#include "logging.h" -#include "opthelpers.h" -#include "ringbuffer.h" -#include "threads.h" - - -static int EventThread(ALCcontext *context) -{ - RingBuffer *ring{context->AsyncEvents.get()}; - bool quitnow{false}; - while(LIKELY(!quitnow)) - { - auto evt_data = ring->getReadVector().first; - if(evt_data.len == 0) - { - context->EventSem.wait(); - continue; - } - - std::lock_guard _{context->EventCbLock}; - do { - auto &evt = *reinterpret_cast(evt_data.buf); - evt_data.buf += sizeof(AsyncEvent); - evt_data.len -= 1; - /* This automatically destructs the event object and advances the - * ringbuffer's read offset at the end of scope. - */ - const struct EventAutoDestructor { - AsyncEvent &evt_; - RingBuffer *ring_; - ~EventAutoDestructor() - { - al::destroy_at(&evt_); - ring_->readAdvance(1); - } - } _{evt, ring}; - - quitnow = evt.EnumType == EventType_KillThread; - if(UNLIKELY(quitnow)) break; - - if(evt.EnumType == EventType_ReleaseEffectState) - { - evt.u.mEffectState->DecRef(); - continue; - } - - ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_acquire)}; - if(!context->EventCb) continue; - - if(evt.EnumType == EventType_SourceStateChange) - { - if(!(enabledevts&EventType_SourceStateChange)) - continue; - std::string msg{"Source ID " + std::to_string(evt.u.srcstate.id)}; - msg += " state has changed to "; - msg += (evt.u.srcstate.state==AL_INITIAL) ? "AL_INITIAL" : - (evt.u.srcstate.state==AL_PLAYING) ? "AL_PLAYING" : - (evt.u.srcstate.state==AL_PAUSED) ? "AL_PAUSED" : - (evt.u.srcstate.state==AL_STOPPED) ? "AL_STOPPED" : ""; - context->EventCb(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, evt.u.srcstate.id, - evt.u.srcstate.state, static_cast(msg.length()), msg.c_str(), - context->EventParam - ); - } - else if(evt.EnumType == EventType_BufferCompleted) - { - if(!(enabledevts&EventType_BufferCompleted)) - continue; - std::string msg{std::to_string(evt.u.bufcomp.count)}; - if(evt.u.bufcomp.count == 1) msg += " buffer completed"; - else msg += " buffers completed"; - context->EventCb(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, evt.u.bufcomp.id, - evt.u.bufcomp.count, static_cast(msg.length()), msg.c_str(), - context->EventParam - ); - } - else if((enabledevts&evt.EnumType) == evt.EnumType) - context->EventCb(evt.u.user.type, evt.u.user.id, evt.u.user.param, - static_cast(strlen(evt.u.user.msg)), evt.u.user.msg, - context->EventParam - ); - } while(evt_data.len != 0); - } - return 0; -} - -void StartEventThrd(ALCcontext *ctx) -{ - try { - ctx->EventThread = std::thread{EventThread, ctx}; - } - catch(std::exception& e) { - ERR("Failed to start event thread: %s\n", e.what()); - } - catch(...) { - ERR("Failed to start event thread! Expect problems.\n"); - } -} - -void StopEventThrd(ALCcontext *ctx) -{ - static constexpr AsyncEvent kill_evt{EventType_KillThread}; - RingBuffer *ring{ctx->AsyncEvents.get()}; - auto evt_data = ring->getWriteVector().first; - if(evt_data.len == 0) - { - do { - std::this_thread::yield(); - evt_data = ring->getWriteVector().first; - } while(evt_data.len == 0); - } - new (evt_data.buf) AsyncEvent{kill_evt}; - ring->writeAdvance(1); - - ctx->EventSem.post(); - if(ctx->EventThread.joinable()) - ctx->EventThread.join(); -} - -AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(count < 0) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Controlling %d events", count); - if(count == 0) return; - if(!types) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "NULL pointer"); - - ALbitfieldSOFT flags{0}; - const ALenum *types_end = types+count; - auto bad_type = std::find_if_not(types, types_end, - [&flags](ALenum type) noexcept -> bool - { - if(type == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT) - flags |= EventType_BufferCompleted; - else if(type == AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT) - flags |= EventType_SourceStateChange; - else if(type == AL_EVENT_TYPE_ERROR_SOFT) - flags |= EventType_Error; - else if(type == AL_EVENT_TYPE_PERFORMANCE_SOFT) - flags |= EventType_Performance; - else if(type == AL_EVENT_TYPE_DEPRECATED_SOFT) - flags |= EventType_Deprecated; - else if(type == AL_EVENT_TYPE_DISCONNECTED_SOFT) - flags |= EventType_Disconnected; - else - return false; - return true; - } - ); - if(bad_type != types_end) - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, "Invalid event type 0x%04x", *bad_type); - - if(enable) - { - ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; - while(context->EnabledEvts.compare_exchange_weak(enabledevts, enabledevts|flags, - std::memory_order_acq_rel, std::memory_order_acquire) == 0) - { - /* enabledevts is (re-)filled with the current value on failure, so - * just try again. - */ - } - } - else - { - ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; - while(context->EnabledEvts.compare_exchange_weak(enabledevts, enabledevts&~flags, - std::memory_order_acq_rel, std::memory_order_acquire) == 0) - { - } - /* Wait to ensure the event handler sees the changed flags before - * returning. - */ - std::lock_guard{context->EventCbLock}; - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->EventCbLock}; - context->EventCb = callback; - context->EventParam = userParam; -} -END_API_FUNC diff --git a/al/alAuxEffectSlot.cpp b/al/alAuxEffectSlot.cpp new file mode 100644 index 00000000..42966bf2 --- /dev/null +++ b/al/alAuxEffectSlot.cpp @@ -0,0 +1,808 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "alAuxEffectSlot.h" + +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" + +#include "alEffect.h" +#include "alError.h" +#include "alcmain.h" +#include "alcontext.h" +#include "alexcpt.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "alspan.h" +#include "alu.h" +#include "fpu_modes.h" +#include "inprogext.h" +#include "logging.h" +#include "opthelpers.h" + + +namespace { + +inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= context->EffectSlotList.size())) + return nullptr; + EffectSlotSubList &sublist{context->EffectSlotList[lidx]}; + if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + return nullptr; + return sublist.EffectSlots + slidx; +} + +inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) noexcept +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= device->EffectList.size())) + return nullptr; + EffectSubList &sublist = device->EffectList[lidx]; + if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + return nullptr; + return sublist.Effects + slidx; +} + + +void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) +{ + if(count < 1) return; + ALeffectslotArray *curarray{context->ActiveAuxSlots.load(std::memory_order_acquire)}; + size_t newcount{curarray->size() + count}; + + /* Insert the new effect slots into the head of the array, followed by the + * existing ones. + */ + ALeffectslotArray *newarray = ALeffectslot::CreatePtrArray(newcount); + auto slotiter = std::transform(slotids, slotids+count, newarray->begin(), + [context](ALuint id) noexcept -> ALeffectslot* + { return LookupEffectSlot(context, id); } + ); + std::copy(curarray->begin(), curarray->end(), slotiter); + + /* Remove any duplicates (first instance of each will be kept). */ + auto last = newarray->end(); + for(auto start=newarray->begin()+1;;) + { + last = std::remove(start, last, *(start-1)); + if(start == last) break; + ++start; + } + newcount = static_cast(std::distance(newarray->begin(), last)); + + /* Reallocate newarray if the new size ended up smaller from duplicate + * removal. + */ + if(UNLIKELY(newcount < newarray->size())) + { + curarray = newarray; + newarray = ALeffectslot::CreatePtrArray(newcount); + std::copy_n(curarray->begin(), newcount, newarray->begin()); + delete curarray; + curarray = nullptr; + } + + curarray = context->ActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); + ALCdevice *device{context->Device}; + while((device->MixCount.load(std::memory_order_acquire)&1)) + std::this_thread::yield(); + delete curarray; +} + +void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) +{ + if(count < 1) return; + ALeffectslotArray *curarray{context->ActiveAuxSlots.load(std::memory_order_acquire)}; + + /* Don't shrink the allocated array size since we don't know how many (if + * any) of the effect slots to remove are in the array. + */ + ALeffectslotArray *newarray = ALeffectslot::CreatePtrArray(curarray->size()); + + /* Copy each element in curarray to newarray whose ID is not in slotids. */ + const ALuint *slotids_end{slotids + count}; + auto slotiter = std::copy_if(curarray->begin(), curarray->end(), newarray->begin(), + [slotids, slotids_end](const ALeffectslot *slot) -> bool + { return std::find(slotids, slotids_end, slot->id) == slotids_end; } + ); + + /* Reallocate with the new size. */ + auto newsize = static_cast(std::distance(newarray->begin(), slotiter)); + if(LIKELY(newsize != newarray->size())) + { + curarray = newarray; + newarray = ALeffectslot::CreatePtrArray(newsize); + std::copy_n(curarray->begin(), newsize, newarray->begin()); + + delete curarray; + curarray = nullptr; + } + + curarray = context->ActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); + ALCdevice *device{context->Device}; + while((device->MixCount.load(std::memory_order_acquire)&1)) + std::this_thread::yield(); + delete curarray; +} + + +ALeffectslot *AllocEffectSlot(ALCcontext *context) +{ + ALCdevice *device{context->Device}; + std::lock_guard _{context->EffectSlotLock}; + if(context->NumEffectSlots >= device->AuxiliaryEffectSlotMax) + { + alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u effect slot limit", + device->AuxiliaryEffectSlotMax); + return nullptr; + } + auto sublist = std::find_if(context->EffectSlotList.begin(), context->EffectSlotList.end(), + [](const EffectSlotSubList &entry) noexcept -> bool + { return entry.FreeMask != 0; } + ); + auto lidx = static_cast(std::distance(context->EffectSlotList.begin(), sublist)); + ALeffectslot *slot; + ALsizei slidx; + if(LIKELY(sublist != context->EffectSlotList.end())) + { + slidx = CTZ64(sublist->FreeMask); + slot = sublist->EffectSlots + slidx; + } + else + { + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(context->EffectSlotList.size() >= 1<<25)) + { + alSetError(context, AL_OUT_OF_MEMORY, "Too many effect slots allocated"); + return nullptr; + } + context->EffectSlotList.emplace_back(); + sublist = context->EffectSlotList.end() - 1; + + sublist->FreeMask = ~0_u64; + sublist->EffectSlots = static_cast(al_calloc(16, sizeof(ALeffectslot)*64)); + if(UNLIKELY(!sublist->EffectSlots)) + { + context->EffectSlotList.pop_back(); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect slot batch"); + return nullptr; + } + + slidx = 0; + slot = sublist->EffectSlots + slidx; + } + + slot = new (slot) ALeffectslot{}; + ALenum err{InitEffectSlot(slot)}; + if(err != AL_NO_ERROR) + { + al::destroy_at(slot); + alSetError(context, err, "Effect slot object initialization failed"); + return nullptr; + } + aluInitEffectPanning(slot, device); + + /* Add 1 to avoid source ID 0. */ + slot->id = ((lidx<<6) | slidx) + 1; + + context->NumEffectSlots += 1; + sublist->FreeMask &= ~(1_u64 << slidx); + + return slot; +} + +void FreeEffectSlot(ALCcontext *context, ALeffectslot *slot) +{ + ALuint id = slot->id - 1; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; + + al::destroy_at(slot); + + context->EffectSlotList[lidx].FreeMask |= 1_u64 << slidx; + context->NumEffectSlots--; +} + + +#define DO_UPDATEPROPS() do { \ + if(!context->DeferUpdates.load(std::memory_order_acquire)) \ + UpdateEffectSlotProps(slot, context.get()); \ + else \ + slot->PropsClean.clear(std::memory_order_release); \ +} while(0) + +} // namespace + +ALeffectslotArray *ALeffectslot::CreatePtrArray(size_t count) noexcept +{ + /* Allocate space for twice as many pointers, so the mixer has scratch + * space to store a sorted list during mixing. + */ + void *ptr{al_calloc(alignof(ALeffectslotArray), ALeffectslotArray::Sizeof(count*2))}; + return new (ptr) ALeffectslotArray{count}; +} + + +AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(n < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Generating %d effect slots", n); + if(n == 0) return; + + if(n == 1) + { + ALeffectslot *slot{AllocEffectSlot(context.get())}; + if(!slot) return; + effectslots[0] = slot->id; + } + else + { + auto tempids = al::vector(n); + auto alloc_end = std::find_if_not(tempids.begin(), tempids.end(), + [&context](ALuint &id) -> bool + { + ALeffectslot *slot{AllocEffectSlot(context.get())}; + if(!slot) return false; + id = slot->id; + return true; + } + ); + if(alloc_end != tempids.end()) + { + auto count = static_cast(std::distance(tempids.begin(), alloc_end)); + alDeleteAuxiliaryEffectSlots(count, tempids.data()); + return; + } + + std::copy(tempids.cbegin(), tempids.cend(), effectslots); + } + + std::unique_lock slotlock{context->EffectSlotLock}; + AddActiveEffectSlots(effectslots, n, context.get()); +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(n < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Deleting %d effect slots", n); + if(n == 0) return; + + std::lock_guard _{context->EffectSlotLock}; + auto effectslots_end = effectslots + n; + auto bad_slot = std::find_if(effectslots, effectslots_end, + [&context](ALuint id) -> bool + { + ALeffectslot *slot{LookupEffectSlot(context.get(), id)}; + if(!slot) + { + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect slot ID %u", id); + return true; + } + if(ReadRef(&slot->ref) != 0) + { + alSetError(context.get(), AL_INVALID_NAME, "Deleting in-use effect slot %u", id); + return true; + } + return false; + } + ); + if(bad_slot != effectslots_end) + return; + + // All effectslots are valid, remove and delete them + RemoveActiveEffectSlots(effectslots, n, context.get()); + std::for_each(effectslots, effectslots_end, + [&context](ALuint sid) -> void + { + ALeffectslot *slot{LookupEffectSlot(context.get(), sid)}; + if(slot) FreeEffectSlot(context.get(), slot); + } + ); +} +END_API_FUNC + +AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(LIKELY(context)) + { + std::lock_guard _{context->EffectSlotLock}; + if(LookupEffectSlot(context.get(), effectslot) != nullptr) + return AL_TRUE; + } + return AL_FALSE; +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + + ALeffectslot *target{}; + ALCdevice *device{}; + ALenum err{}; + switch(param) + { + case AL_EFFECTSLOT_EFFECT: + device = context->Device; + + { std::lock_guard ___{device->EffectLock}; + ALeffect *effect{value ? LookupEffect(device, value) : nullptr}; + if(!(value == 0 || effect != nullptr)) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Invalid effect ID %u", value); + err = InitializeEffect(context.get(), slot, effect); + } + if(err != AL_NO_ERROR) + { + alSetError(context.get(), err, "Effect initialization failed"); + return; + } + break; + + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + if(!(value == AL_TRUE || value == AL_FALSE)) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, + "Effect slot auxiliary send auto out of range"); + slot->AuxSendAuto = value; + break; + + case AL_EFFECTSLOT_TARGET_SOFT: + target = (value ? LookupEffectSlot(context.get(), value) : nullptr); + if(value && !target) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Invalid effect slot target ID"); + if(target) + { + ALeffectslot *checker{target}; + while(checker && checker != slot) + checker = checker->Target; + if(checker) + SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, + "Setting target of effect slot ID %u to %u creates circular chain", slot->id, + target->id); + } + + if(ALeffectslot *oldtarget{slot->Target}) + { + /* We must force an update if there was an existing effect slot + * target, in case it's about to be deleted. + */ + if(target) IncrementRef(&target->ref); + DecrementRef(&oldtarget->ref); + slot->Target = target; + UpdateEffectSlotProps(slot, context.get()); + return; + } + + if(target) IncrementRef(&target->ref); + slot->Target = target; + break; + + default: + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot integer property 0x%04x", param); + } + DO_UPDATEPROPS(); +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values) +START_API_FUNC +{ + switch(param) + { + case AL_EFFECTSLOT_EFFECT: + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + case AL_EFFECTSLOT_TARGET_SOFT: + alAuxiliaryEffectSloti(effectslot, param, values[0]); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + + switch(param) + { + default: + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot integer-vector property 0x%04x", param); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + + switch(param) + { + case AL_EFFECTSLOT_GAIN: + if(!(value >= 0.0f && value <= 1.0f)) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Effect slot gain out of range"); + slot->Gain = value; + break; + + default: + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, "Invalid effect slot float property 0x%04x", + param); + } + DO_UPDATEPROPS(); +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values) +START_API_FUNC +{ + switch(param) + { + case AL_EFFECTSLOT_GAIN: + alAuxiliaryEffectSlotf(effectslot, param, values[0]); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + + switch(param) + { + default: + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot float-vector property 0x%04x", param); + } +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + + switch(param) + { + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + *value = slot->AuxSendAuto; + break; + + case AL_EFFECTSLOT_TARGET_SOFT: + *value = slot->Target ? slot->Target->id : 0; + break; + + default: + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot integer property 0x%04x", param); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values) +START_API_FUNC +{ + switch(param) + { + case AL_EFFECTSLOT_EFFECT: + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + case AL_EFFECTSLOT_TARGET_SOFT: + alGetAuxiliaryEffectSloti(effectslot, param, values); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + + switch(param) + { + default: + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot integer-vector property 0x%04x", param); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + + switch(param) + { + case AL_EFFECTSLOT_GAIN: + *value = slot->Gain; + break; + + default: + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot float property 0x%04x", param); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values) +START_API_FUNC +{ + switch(param) + { + case AL_EFFECTSLOT_GAIN: + alGetAuxiliaryEffectSlotf(effectslot, param, values); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + + switch(param) + { + default: + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot float-vector property 0x%04x", param); + } +} +END_API_FUNC + + +ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect) +{ + ALenum newtype{effect ? effect->type : AL_EFFECT_NULL}; + if(newtype != EffectSlot->Effect.Type) + { + EffectStateFactory *factory{getFactoryByType(newtype)}; + if(!factory) + { + ERR("Failed to find factory for effect type 0x%04x\n", newtype); + return AL_INVALID_ENUM; + } + EffectState *State{factory->create()}; + if(!State) return AL_OUT_OF_MEMORY; + + FPUCtl mixer_mode{}; + ALCdevice *Device{Context->Device}; + std::unique_lock statelock{Device->StateLock}; + State->mOutTarget = Device->Dry.Buffer; + if(State->deviceUpdate(Device) == AL_FALSE) + { + statelock.unlock(); + mixer_mode.leave(); + State->DecRef(); + return AL_OUT_OF_MEMORY; + } + mixer_mode.leave(); + + if(!effect) + { + EffectSlot->Effect.Type = AL_EFFECT_NULL; + EffectSlot->Effect.Props = EffectProps {}; + } + else + { + EffectSlot->Effect.Type = effect->type; + EffectSlot->Effect.Props = effect->Props; + } + + EffectSlot->Effect.State->DecRef(); + EffectSlot->Effect.State = State; + } + else if(effect) + EffectSlot->Effect.Props = effect->Props; + + /* Remove state references from old effect slot property updates. */ + ALeffectslotProps *props{Context->FreeEffectslotProps.load()}; + while(props) + { + if(props->State) + props->State->DecRef(); + props->State = nullptr; + props = props->next.load(std::memory_order_relaxed); + } + + return AL_NO_ERROR; +} + + +void EffectState::IncRef() noexcept +{ + auto ref = IncrementRef(&mRef); + TRACEREF("EffectState %p increasing refcount to %u\n", this, ref); +} + +void EffectState::DecRef() noexcept +{ + auto ref = DecrementRef(&mRef); + TRACEREF("EffectState %p decreasing refcount to %u\n", this, ref); + if(ref == 0) delete this; +} + + +ALenum InitEffectSlot(ALeffectslot *slot) +{ + EffectStateFactory *factory{getFactoryByType(slot->Effect.Type)}; + if(!factory) return AL_INVALID_VALUE; + slot->Effect.State = factory->create(); + if(!slot->Effect.State) return AL_OUT_OF_MEMORY; + + slot->Effect.State->IncRef(); + slot->Params.mEffectState = slot->Effect.State; + return AL_NO_ERROR; +} + +ALeffectslot::~ALeffectslot() +{ + if(Target) + DecrementRef(&Target->ref); + Target = nullptr; + + ALeffectslotProps *props{Update.load()}; + if(props) + { + if(props->State) props->State->DecRef(); + TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props); + al_free(props); + } + + if(Effect.State) + Effect.State->DecRef(); + if(Params.mEffectState) + Params.mEffectState->DecRef(); +} + +void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) +{ + /* Get an unused property container, or allocate a new one as needed. */ + ALeffectslotProps *props{context->FreeEffectslotProps.load(std::memory_order_relaxed)}; + if(!props) + props = static_cast(al_calloc(16, sizeof(*props))); + else + { + ALeffectslotProps *next; + do { + next = props->next.load(std::memory_order_relaxed); + } while(context->FreeEffectslotProps.compare_exchange_weak(props, next, + std::memory_order_seq_cst, std::memory_order_acquire) == 0); + } + + /* Copy in current property values. */ + props->Gain = slot->Gain; + props->AuxSendAuto = slot->AuxSendAuto; + props->Target = slot->Target; + + props->Type = slot->Effect.Type; + props->Props = slot->Effect.Props; + /* Swap out any stale effect state object there may be in the container, to + * delete it. + */ + EffectState *oldstate{props->State}; + slot->Effect.State->IncRef(); + props->State = slot->Effect.State; + + /* Set the new container for updating internal parameters. */ + props = slot->Update.exchange(props, std::memory_order_acq_rel); + if(props) + { + /* If there was an unused update container, put it back in the + * freelist. + */ + if(props->State) + props->State->DecRef(); + props->State = nullptr; + AtomicReplaceHead(context->FreeEffectslotProps, props); + } + + if(oldstate) + oldstate->DecRef(); +} + +void UpdateAllEffectSlotProps(ALCcontext *context) +{ + std::lock_guard _{context->EffectSlotLock}; + ALeffectslotArray *auxslots{context->ActiveAuxSlots.load(std::memory_order_acquire)}; + for(ALeffectslot *slot : *auxslots) + { + if(!slot->PropsClean.test_and_set(std::memory_order_acq_rel)) + UpdateEffectSlotProps(slot, context); + } +} + +EffectSlotSubList::~EffectSlotSubList() +{ + uint64_t usemask{~FreeMask}; + while(usemask) + { + ALsizei idx{CTZ64(usemask)}; + al::destroy_at(EffectSlots+idx); + usemask &= ~(1_u64 << idx); + } + FreeMask = ~usemask; + al_free(EffectSlots); + EffectSlots = nullptr; +} diff --git a/al/alAuxEffectSlot.h b/al/alAuxEffectSlot.h new file mode 100644 index 00000000..369638a0 --- /dev/null +++ b/al/alAuxEffectSlot.h @@ -0,0 +1,103 @@ +#ifndef AL_AUXEFFECTSLOT_H +#define AL_AUXEFFECTSLOT_H + +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/efx.h" + +#include "alcmain.h" +#include "almalloc.h" +#include "atomic.h" +#include "effects/base.h" +#include "vector.h" + +struct ALeffect; +struct ALeffectslot; + + +using ALeffectslotArray = al::FlexArray; + + +struct ALeffectslotProps { + ALfloat Gain; + ALboolean AuxSendAuto; + ALeffectslot *Target; + + ALenum Type; + EffectProps Props; + + EffectState *State; + + std::atomic next; +}; + + +struct ALeffectslot { + ALfloat Gain{1.0f}; + ALboolean AuxSendAuto{AL_TRUE}; + ALeffectslot *Target{nullptr}; + + struct { + ALenum Type{AL_EFFECT_NULL}; + EffectProps Props{}; + + EffectState *State{nullptr}; + } Effect; + + std::atomic_flag PropsClean; + + RefCount ref{0u}; + + std::atomic Update{nullptr}; + + struct { + ALfloat Gain{1.0f}; + ALboolean AuxSendAuto{AL_TRUE}; + ALeffectslot *Target{nullptr}; + + ALenum EffectType{AL_EFFECT_NULL}; + EffectProps mEffectProps{}; + EffectState *mEffectState{nullptr}; + + ALfloat RoomRolloff{0.0f}; /* Added to the source's room rolloff, not multiplied. */ + ALfloat DecayTime{0.0f}; + ALfloat DecayLFRatio{0.0f}; + ALfloat DecayHFRatio{0.0f}; + ALboolean DecayHFLimit{AL_FALSE}; + ALfloat AirAbsorptionGainHF{1.0f}; + } Params; + + /* Self ID */ + ALuint id{}; + + /* Mixing buffer used by the Wet mix. */ + al::vector MixBuffer; + + /* Wet buffer configuration is ACN channel order with N3D scaling. + * Consequently, effects that only want to work with mono input can use + * channel 0 by itself. Effects that want multichannel can process the + * ambisonics signal and make a B-Format source pan. + */ + MixParams Wet; + + ALeffectslot() { PropsClean.test_and_set(std::memory_order_relaxed); } + ALeffectslot(const ALeffectslot&) = delete; + ALeffectslot& operator=(const ALeffectslot&) = delete; + ~ALeffectslot(); + + static ALeffectslotArray *CreatePtrArray(size_t count) noexcept; + + DEF_PLACE_NEWDEL() +}; + +ALenum InitEffectSlot(ALeffectslot *slot); +void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context); +void UpdateAllEffectSlotProps(ALCcontext *context); + + +ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect); + +#endif diff --git a/al/alBuffer.cpp b/al/alBuffer.cpp new file mode 100644 index 00000000..505b9dab --- /dev/null +++ b/al/alBuffer.cpp @@ -0,0 +1,1408 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "alBuffer.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" + +#include "alError.h" +#include "albyte.h" +#include "alcmain.h" +#include "alcontext.h" +#include "alexcpt.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "aloptional.h" +#include "atomic.h" +#include "inprogext.h" +#include "opthelpers.h" + + +namespace { + +/* IMA ADPCM Stepsize table */ +constexpr int IMAStep_size[89] = { + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, + 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, + 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, + 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, + 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, + 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, + 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493,10442, + 11487,12635,13899,15289,16818,18500,20350,22358,24633,27086,29794, + 32767 +}; + +/* IMA4 ADPCM Codeword decode table */ +constexpr int IMA4Codeword[16] = { + 1, 3, 5, 7, 9, 11, 13, 15, + -1,-3,-5,-7,-9,-11,-13,-15, +}; + +/* IMA4 ADPCM Step index adjust decode table */ +constexpr int IMA4Index_adjust[16] = { + -1,-1,-1,-1, 2, 4, 6, 8, + -1,-1,-1,-1, 2, 4, 6, 8 +}; + + +/* MSADPCM Adaption table */ +constexpr int MSADPCMAdaption[16] = { + 230, 230, 230, 230, 307, 409, 512, 614, + 768, 614, 512, 409, 307, 230, 230, 230 +}; + +/* MSADPCM Adaption Coefficient tables */ +constexpr int MSADPCMAdaptionCoeff[7][2] = { + { 256, 0 }, + { 512, -256 }, + { 0, 0 }, + { 192, 64 }, + { 240, 0 }, + { 460, -208 }, + { 392, -232 } +}; + + +void DecodeIMA4Block(ALshort *dst, const al::byte *src, ALint numchans, ALsizei align) +{ + ALint sample[MAX_INPUT_CHANNELS]{}; + ALint index[MAX_INPUT_CHANNELS]{}; + ALuint code[MAX_INPUT_CHANNELS]{}; + + for(int c{0};c < numchans;c++) + { + sample[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + sample[c] = (sample[c]^0x8000) - 32768; + src += 2; + index[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + index[c] = clampi((index[c]^0x8000) - 32768, 0, 88); + src += 2; + + *(dst++) = sample[c]; + } + + for(int i{1};i < align;i++) + { + if((i&7) == 1) + { + for(int c{0};c < numchans;c++) + { + code[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<< 8) | + (al::to_integer(src[2])<<16) | (al::to_integer(src[3])<<24); + src += 4; + } + } + + for(int c{0};c < numchans;c++) + { + const ALuint nibble{code[c]&0xf}; + code[c] >>= 4; + + sample[c] += IMA4Codeword[nibble] * IMAStep_size[index[c]] / 8; + sample[c] = clampi(sample[c], -32768, 32767); + + index[c] += IMA4Index_adjust[nibble]; + index[c] = clampi(index[c], 0, 88); + + *(dst++) = sample[c]; + } + } +} + +void DecodeMSADPCMBlock(ALshort *dst, const al::byte *src, ALint numchans, ALsizei align) +{ + ALubyte blockpred[MAX_INPUT_CHANNELS]{}; + ALint delta[MAX_INPUT_CHANNELS]{}; + ALshort samples[MAX_INPUT_CHANNELS][2]{}; + + for(int c{0};c < numchans;c++) + { + blockpred[c] = minu(al::to_integer(src[0]), 6); + ++src; + } + for(int c{0};c < numchans;c++) + { + delta[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + delta[c] = (delta[c]^0x8000) - 32768; + src += 2; + } + for(int c{0};c < numchans;c++) + { + samples[c][0] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + samples[c][0] = (samples[c][0]^0x8000) - 32768; + src += 2; + } + for(int c{0};c < numchans;c++) + { + samples[c][1] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + samples[c][1] = (samples[c][1]^0x8000) - 32768; + src += 2; + } + + /* Second sample is written first. */ + for(int c{0};c < numchans;c++) + *(dst++) = samples[c][1]; + for(int c{0};c < numchans;c++) + *(dst++) = samples[c][0]; + + int num{0}; + for(int i{2};i < align;i++) + { + for(int c{0};c < numchans;c++) + { + /* Read the nibble (first is in the upper bits). */ + al::byte nibble; + if(!(num++ & 1)) + nibble = *src >> 4; + else + nibble = *(src++) & 0x0f; + + ALint pred{(samples[c][0]*MSADPCMAdaptionCoeff[blockpred[c]][0] + + samples[c][1]*MSADPCMAdaptionCoeff[blockpred[c]][1]) / 256}; + pred += (al::to_integer(nibble^0x08) - 0x08) * delta[c]; + pred = clampi(pred, -32768, 32767); + + samples[c][1] = samples[c][0]; + samples[c][0] = pred; + + delta[c] = (MSADPCMAdaption[al::to_integer(nibble)] * delta[c]) / 256; + delta[c] = maxi(16, delta[c]); + + *(dst++) = pred; + } + } +} + +void Convert_ALshort_ALima4(ALshort *dst, const al::byte *src, ALsizei numchans, ALsizei len, + ALsizei align) +{ + const ALsizei byte_align{((align-1)/2 + 4) * numchans}; + + len /= align; + while(len--) + { + DecodeIMA4Block(dst, src, numchans, align); + src += byte_align; + dst += align*numchans; + } +} + +void Convert_ALshort_ALmsadpcm(ALshort *dst, const al::byte *src, ALsizei numchans, ALsizei len, + ALsizei align) +{ + const ALsizei byte_align{((align-2)/2 + 7) * numchans}; + + len /= align; + while(len--) + { + DecodeMSADPCMBlock(dst, src, numchans, align); + src += byte_align; + dst += align*numchans; + } +} + + +constexpr ALbitfieldSOFT INVALID_STORAGE_MASK{~unsigned(AL_MAP_READ_BIT_SOFT | + AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT)}; +constexpr ALbitfieldSOFT MAP_READ_WRITE_FLAGS{AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT}; +constexpr ALbitfieldSOFT INVALID_MAP_FLAGS{~unsigned(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | + AL_MAP_PERSISTENT_BIT_SOFT)}; + + +ALbuffer *AllocBuffer(ALCcontext *context) +{ + ALCdevice *device{context->Device}; + std::lock_guard _{device->BufferLock}; + auto sublist = std::find_if(device->BufferList.begin(), device->BufferList.end(), + [](const BufferSubList &entry) noexcept -> bool + { return entry.FreeMask != 0; } + ); + + auto lidx = static_cast(std::distance(device->BufferList.begin(), sublist)); + ALbuffer *buffer{nullptr}; + ALsizei slidx{0}; + if(LIKELY(sublist != device->BufferList.end())) + { + slidx = CTZ64(sublist->FreeMask); + buffer = sublist->Buffers + slidx; + } + else + { + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(device->BufferList.size() >= 1<<25)) + { + alSetError(context, AL_OUT_OF_MEMORY, "Too many buffers allocated"); + return nullptr; + } + device->BufferList.emplace_back(); + sublist = device->BufferList.end() - 1; + sublist->FreeMask = ~0_u64; + sublist->Buffers = reinterpret_cast(al_calloc(16, sizeof(ALbuffer)*64)); + if(UNLIKELY(!sublist->Buffers)) + { + device->BufferList.pop_back(); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate buffer batch"); + return nullptr; + } + + slidx = 0; + buffer = sublist->Buffers + slidx; + } + + buffer = new (buffer) ALbuffer{}; + /* Add 1 to avoid buffer ID 0. */ + buffer->id = ((lidx<<6) | slidx) + 1; + + sublist->FreeMask &= ~(1_u64 << slidx); + + return buffer; +} + +void FreeBuffer(ALCdevice *device, ALbuffer *buffer) +{ + ALuint id{buffer->id - 1}; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; + + al::destroy_at(buffer); + + device->BufferList[lidx].FreeMask |= 1_u64 << slidx; +} + +inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= device->BufferList.size())) + return nullptr; + BufferSubList &sublist = device->BufferList[lidx]; + if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + return nullptr; + return sublist.Buffers + slidx; +} + + +ALsizei SanitizeAlignment(UserFmtType type, ALsizei align) +{ + if(align < 0) + return 0; + + if(align == 0) + { + if(type == UserFmtIMA4) + { + /* Here is where things vary: + * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel + * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel + */ + return 65; + } + if(type == UserFmtMSADPCM) + return 64; + return 1; + } + + if(type == UserFmtIMA4) + { + /* IMA4 block alignment must be a multiple of 8, plus 1. */ + if((align&7) == 1) return align; + return 0; + } + if(type == UserFmtMSADPCM) + { + /* MSADPCM block alignment must be a multiple of 2. */ + if((align&1) == 0) return align; + return 0; + } + + return align; +} + + +const ALchar *NameFromUserFmtType(UserFmtType type) +{ + switch(type) + { + case UserFmtUByte: return "Unsigned Byte"; + case UserFmtShort: return "Signed Short"; + case UserFmtFloat: return "Float32"; + case UserFmtDouble: return "Float64"; + case UserFmtMulaw: return "muLaw"; + case UserFmtAlaw: return "aLaw"; + case UserFmtIMA4: return "IMA4 ADPCM"; + case UserFmtMSADPCM: return "MSADPCM"; + } + return ""; +} + +/* + * LoadData + * + * Loads the specified data into the buffer, using the specified format. + */ +void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, UserFmtChannels SrcChannels, UserFmtType SrcType, const al::byte *SrcData, ALbitfieldSOFT access) +{ + if(UNLIKELY(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)) + SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer %u", + ALBuf->id); + + /* Currently no channel configurations need to be converted. */ + FmtChannels DstChannels{FmtMono}; + switch(SrcChannels) + { + case UserFmtMono: DstChannels = FmtMono; break; + case UserFmtStereo: DstChannels = FmtStereo; break; + case UserFmtRear: DstChannels = FmtRear; break; + case UserFmtQuad: DstChannels = FmtQuad; break; + case UserFmtX51: DstChannels = FmtX51; break; + case UserFmtX61: DstChannels = FmtX61; break; + case UserFmtX71: DstChannels = FmtX71; break; + case UserFmtBFormat2D: DstChannels = FmtBFormat2D; break; + case UserFmtBFormat3D: DstChannels = FmtBFormat3D; break; + } + if (UNLIKELY(static_cast(SrcChannels) != + static_cast(DstChannels))) + SETERR_RETURN(context, AL_INVALID_ENUM, , "Invalid format"); + + /* IMA4 and MSADPCM convert to 16-bit short. */ + FmtType DstType{FmtUByte}; + switch(SrcType) + { + case UserFmtUByte: DstType = FmtUByte; break; + case UserFmtShort: DstType = FmtShort; break; + case UserFmtFloat: DstType = FmtFloat; break; + case UserFmtDouble: DstType = FmtDouble; break; + case UserFmtAlaw: DstType = FmtAlaw; break; + case UserFmtMulaw: DstType = FmtMulaw; break; + case UserFmtIMA4: DstType = FmtShort; break; + case UserFmtMSADPCM: DstType = FmtShort; break; + } + + /* TODO: Currently we can only map samples when they're not converted. To + * allow it would need some kind of double-buffering to hold onto a copy of + * the original data. + */ + if((access&MAP_READ_WRITE_FLAGS)) + { + if (UNLIKELY(static_cast(SrcType) != static_cast(DstType))) + SETERR_RETURN(context, AL_INVALID_VALUE, , + "%s samples cannot be mapped", + NameFromUserFmtType(SrcType)); + } + + const ALsizei unpackalign{ALBuf->UnpackAlign.load()}; + const ALsizei align{SanitizeAlignment(SrcType, unpackalign)}; + if(UNLIKELY(align < 1)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid unpack alignment %d for %s samples", + unpackalign, NameFromUserFmtType(SrcType)); + + if((access&AL_PRESERVE_DATA_BIT_SOFT)) + { + /* Can only preserve data with the same format and alignment. */ + if(UNLIKELY(ALBuf->mFmtChannels != DstChannels || ALBuf->OriginalType != SrcType)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched format"); + if(UNLIKELY(ALBuf->OriginalAlign != align)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched alignment"); + } + + /* Convert the input/source size in bytes to sample frames using the unpack + * block alignment. + */ + const ALsizei SrcByteAlign{ + (SrcType == UserFmtIMA4) ? ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels) : + (SrcType == UserFmtMSADPCM) ? ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels) : + (align * FrameSizeFromUserFmt(SrcChannels, SrcType)) + }; + if(UNLIKELY((size%SrcByteAlign) != 0)) + SETERR_RETURN(context, AL_INVALID_VALUE,, + "Data size %d is not a multiple of frame size %d (%d unpack alignment)", + size, SrcByteAlign, align); + + if(UNLIKELY(size/SrcByteAlign > std::numeric_limits::max()/align)) + SETERR_RETURN(context, AL_OUT_OF_MEMORY,, + "Buffer size overflow, %d blocks x %d samples per block", size/SrcByteAlign, align); + const ALsizei frames{size / SrcByteAlign * align}; + + /* Convert the sample frames to the number of bytes needed for internal + * storage. + */ + ALsizei NumChannels{ChannelsFromFmt(DstChannels)}; + ALsizei FrameSize{NumChannels * BytesFromFmt(DstType)}; + if(UNLIKELY(frames > std::numeric_limits::max()/FrameSize)) + SETERR_RETURN(context, AL_OUT_OF_MEMORY,, + "Buffer size overflow, %d frames x %d bytes per frame", frames, FrameSize); + size_t newsize{static_cast(frames) * FrameSize}; + + /* Round up to the next 16-byte multiple. This could reallocate only when + * increasing or the new size is less than half the current, but then the + * buffer's AL_SIZE would not be very reliable for accounting buffer memory + * usage, and reporting the real size could cause problems for apps that + * use AL_SIZE to try to get the buffer's play length. + */ + newsize = RoundUp(newsize, 16); + if(newsize != ALBuf->mData.size()) + { + auto newdata = al::vector(newsize, al::byte{}); + if((access&AL_PRESERVE_DATA_BIT_SOFT)) + { + const size_t tocopy{minz(newdata.size(), ALBuf->mData.size())}; + std::copy_n(ALBuf->mData.begin(), tocopy, newdata.begin()); + } + ALBuf->mData = std::move(newdata); + } + + if(SrcType == UserFmtIMA4) + { + assert(DstType == FmtShort); + if(SrcData != nullptr && !ALBuf->mData.empty()) + Convert_ALshort_ALima4(reinterpret_cast(ALBuf->mData.data()), + SrcData, NumChannels, frames, align); + ALBuf->OriginalAlign = align; + } + else if(SrcType == UserFmtMSADPCM) + { + assert(DstType == FmtShort); + if(SrcData != nullptr && !ALBuf->mData.empty()) + Convert_ALshort_ALmsadpcm(reinterpret_cast(ALBuf->mData.data()), + SrcData, NumChannels, frames, align); + ALBuf->OriginalAlign = align; + } + else + { + assert(static_cast(SrcType) == static_cast(DstType)); + if(SrcData != nullptr && !ALBuf->mData.empty()) + std::copy_n(SrcData, frames*FrameSize, ALBuf->mData.begin()); + ALBuf->OriginalAlign = 1; + } + ALBuf->OriginalSize = size; + ALBuf->OriginalType = SrcType; + + ALBuf->Frequency = freq; + ALBuf->mFmtChannels = DstChannels; + ALBuf->mFmtType = DstType; + ALBuf->Access = access; + + ALBuf->SampleLen = frames; + ALBuf->LoopStart = 0; + ALBuf->LoopEnd = ALBuf->SampleLen; +} + +struct DecompResult { UserFmtChannels channels; UserFmtType type; }; +al::optional DecomposeUserFormat(ALenum format) +{ + struct FormatMap { + ALenum format; + UserFmtChannels channels; + UserFmtType type; + }; + static constexpr std::array UserFmtList{{ + { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte }, + { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort }, + { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat }, + { AL_FORMAT_MONO_DOUBLE_EXT, UserFmtMono, UserFmtDouble }, + { AL_FORMAT_MONO_IMA4, UserFmtMono, UserFmtIMA4 }, + { AL_FORMAT_MONO_MSADPCM_SOFT, UserFmtMono, UserFmtMSADPCM }, + { AL_FORMAT_MONO_MULAW, UserFmtMono, UserFmtMulaw }, + { AL_FORMAT_MONO_ALAW_EXT, UserFmtMono, UserFmtAlaw }, + + { AL_FORMAT_STEREO8, UserFmtStereo, UserFmtUByte }, + { AL_FORMAT_STEREO16, UserFmtStereo, UserFmtShort }, + { AL_FORMAT_STEREO_FLOAT32, UserFmtStereo, UserFmtFloat }, + { AL_FORMAT_STEREO_DOUBLE_EXT, UserFmtStereo, UserFmtDouble }, + { AL_FORMAT_STEREO_IMA4, UserFmtStereo, UserFmtIMA4 }, + { AL_FORMAT_STEREO_MSADPCM_SOFT, UserFmtStereo, UserFmtMSADPCM }, + { AL_FORMAT_STEREO_MULAW, UserFmtStereo, UserFmtMulaw }, + { AL_FORMAT_STEREO_ALAW_EXT, UserFmtStereo, UserFmtAlaw }, + + { AL_FORMAT_REAR8, UserFmtRear, UserFmtUByte }, + { AL_FORMAT_REAR16, UserFmtRear, UserFmtShort }, + { AL_FORMAT_REAR32, UserFmtRear, UserFmtFloat }, + { AL_FORMAT_REAR_MULAW, UserFmtRear, UserFmtMulaw }, + + { AL_FORMAT_QUAD8_LOKI, UserFmtQuad, UserFmtUByte }, + { AL_FORMAT_QUAD16_LOKI, UserFmtQuad, UserFmtShort }, + + { AL_FORMAT_QUAD8, UserFmtQuad, UserFmtUByte }, + { AL_FORMAT_QUAD16, UserFmtQuad, UserFmtShort }, + { AL_FORMAT_QUAD32, UserFmtQuad, UserFmtFloat }, + { AL_FORMAT_QUAD_MULAW, UserFmtQuad, UserFmtMulaw }, + + { AL_FORMAT_51CHN8, UserFmtX51, UserFmtUByte }, + { AL_FORMAT_51CHN16, UserFmtX51, UserFmtShort }, + { AL_FORMAT_51CHN32, UserFmtX51, UserFmtFloat }, + { AL_FORMAT_51CHN_MULAW, UserFmtX51, UserFmtMulaw }, + + { AL_FORMAT_61CHN8, UserFmtX61, UserFmtUByte }, + { AL_FORMAT_61CHN16, UserFmtX61, UserFmtShort }, + { AL_FORMAT_61CHN32, UserFmtX61, UserFmtFloat }, + { AL_FORMAT_61CHN_MULAW, UserFmtX61, UserFmtMulaw }, + + { AL_FORMAT_71CHN8, UserFmtX71, UserFmtUByte }, + { AL_FORMAT_71CHN16, UserFmtX71, UserFmtShort }, + { AL_FORMAT_71CHN32, UserFmtX71, UserFmtFloat }, + { AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw }, + + { AL_FORMAT_BFORMAT2D_8, UserFmtBFormat2D, UserFmtUByte }, + { AL_FORMAT_BFORMAT2D_16, UserFmtBFormat2D, UserFmtShort }, + { AL_FORMAT_BFORMAT2D_FLOAT32, UserFmtBFormat2D, UserFmtFloat }, + { AL_FORMAT_BFORMAT2D_MULAW, UserFmtBFormat2D, UserFmtMulaw }, + + { AL_FORMAT_BFORMAT3D_8, UserFmtBFormat3D, UserFmtUByte }, + { AL_FORMAT_BFORMAT3D_16, UserFmtBFormat3D, UserFmtShort }, + { AL_FORMAT_BFORMAT3D_FLOAT32, UserFmtBFormat3D, UserFmtFloat }, + { AL_FORMAT_BFORMAT3D_MULAW, UserFmtBFormat3D, UserFmtMulaw }, + }}; + + for(const auto &fmt : UserFmtList) + { + if(fmt.format == format) + return al::make_optional(DecompResult{fmt.channels, fmt.type}); + } + return al::nullopt; +} + +} // namespace + + +AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(UNLIKELY(n < 0)) + { + alSetError(context.get(), AL_INVALID_VALUE, "Generating %d buffers", n); + return; + } + + if(LIKELY(n == 1)) + { + /* Special handling for the easy and normal case. */ + ALbuffer *buffer = AllocBuffer(context.get()); + if(buffer) buffers[0] = buffer->id; + } + else if(n > 1) + { + /* Store the allocated buffer IDs in a separate local list, to avoid + * modifying the user storage in case of failure. + */ + al::vector ids; + ids.reserve(n); + do { + ALbuffer *buffer = AllocBuffer(context.get()); + if(!buffer) + { + alDeleteBuffers(static_cast(ids.size()), ids.data()); + return; + } + + ids.emplace_back(buffer->id); + } while(--n); + std::copy(ids.begin(), ids.end(), buffers); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(UNLIKELY(n < 0)) + { + alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d buffers", n); + return; + } + if(UNLIKELY(n == 0)) + return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + /* First try to find any buffers that are invalid or in-use. */ + const ALuint *buffers_end = buffers + n; + auto invbuf = std::find_if(buffers, buffers_end, + [device, &context](ALuint bid) -> bool + { + if(!bid) return false; + ALbuffer *ALBuf = LookupBuffer(device, bid); + if(UNLIKELY(!ALBuf)) + { + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", bid); + return true; + } + if(UNLIKELY(ReadRef(&ALBuf->ref) != 0)) + { + alSetError(context.get(), AL_INVALID_OPERATION, "Deleting in-use buffer %u", bid); + return true; + } + return false; + } + ); + if(LIKELY(invbuf == buffers_end)) + { + /* All good. Delete non-0 buffer IDs. */ + std::for_each(buffers, buffers_end, + [device](ALuint bid) -> void + { + ALbuffer *buffer{bid ? LookupBuffer(device, bid) : nullptr}; + if(buffer) FreeBuffer(device, buffer); + } + ); + } +} +END_API_FUNC + +AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(LIKELY(context)) + { + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + if(!buffer || LookupBuffer(device, buffer)) + return AL_TRUE; + } + return AL_FALSE; +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq) +START_API_FUNC +{ alBufferStorageSOFT(buffer, format, data, size, freq, 0); } +END_API_FUNC + +AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(size < 0)) + alSetError(context.get(), AL_INVALID_VALUE, "Negative storage size %d", size); + else if(UNLIKELY(freq < 1)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid sample rate %d", freq); + else if(UNLIKELY((flags&INVALID_STORAGE_MASK) != 0)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid storage flags 0x%x", + flags&INVALID_STORAGE_MASK); + else if(UNLIKELY((flags&AL_MAP_PERSISTENT_BIT_SOFT) && !(flags&MAP_READ_WRITE_FLAGS))) + alSetError(context.get(), AL_INVALID_VALUE, + "Declaring persistently mapped storage without read or write access"); + else + { + auto usrfmt = DecomposeUserFormat(format); + if(UNLIKELY(!usrfmt)) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid format 0x%04x", format); + else + LoadData(context.get(), albuf, freq, size, usrfmt->channels, usrfmt->type, + static_cast(data), flags); + } +} +END_API_FUNC + +AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return nullptr; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY((access&INVALID_MAP_FLAGS) != 0)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid map flags 0x%x", access&INVALID_MAP_FLAGS); + else if(UNLIKELY(!(access&MAP_READ_WRITE_FLAGS))) + alSetError(context.get(), AL_INVALID_VALUE, "Mapping buffer %u without read or write access", + buffer); + else + { + ALbitfieldSOFT unavailable = (albuf->Access^access) & access; + if(UNLIKELY(ReadRef(&albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT))) + alSetError(context.get(), AL_INVALID_OPERATION, + "Mapping in-use buffer %u without persistent mapping", buffer); + else if(UNLIKELY(albuf->MappedAccess != 0)) + alSetError(context.get(), AL_INVALID_OPERATION, "Mapping already-mapped buffer %u", buffer); + else if(UNLIKELY((unavailable&AL_MAP_READ_BIT_SOFT))) + alSetError(context.get(), AL_INVALID_VALUE, + "Mapping buffer %u for reading without read access", buffer); + else if(UNLIKELY((unavailable&AL_MAP_WRITE_BIT_SOFT))) + alSetError(context.get(), AL_INVALID_VALUE, + "Mapping buffer %u for writing without write access", buffer); + else if(UNLIKELY((unavailable&AL_MAP_PERSISTENT_BIT_SOFT))) + alSetError(context.get(), AL_INVALID_VALUE, + "Mapping buffer %u persistently without persistent access", buffer); + else if(UNLIKELY(offset < 0 || offset >= albuf->OriginalSize || + length <= 0 || length > albuf->OriginalSize - offset)) + alSetError(context.get(), AL_INVALID_VALUE, "Mapping invalid range %d+%d for buffer %u", + offset, length, buffer); + else + { + void *retval = albuf->mData.data() + offset; + albuf->MappedAccess = access; + albuf->MappedOffset = offset; + albuf->MappedSize = length; + return retval; + } + } + + return nullptr; +} +END_API_FUNC + +AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(albuf->MappedAccess == 0) + alSetError(context.get(), AL_INVALID_OPERATION, "Unmapping unmapped buffer %u", buffer); + else + { + albuf->MappedAccess = 0; + albuf->MappedOffset = 0; + albuf->MappedSize = 0; + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT))) + alSetError(context.get(), AL_INVALID_OPERATION, + "Flushing buffer %u while not mapped for writing", buffer); + else if(UNLIKELY(offset < albuf->MappedOffset || + offset >= albuf->MappedOffset+albuf->MappedSize || + length <= 0 || length > albuf->MappedOffset+albuf->MappedSize-offset)) + alSetError(context.get(), AL_INVALID_VALUE, "Flushing invalid range %d+%d on buffer %u", + offset, length, buffer); + else + { + /* FIXME: Need to use some method of double-buffering for the mixer and + * app to hold separate memory, which can be safely transfered + * asynchronously. Currently we just say the app shouldn't write where + * OpenAL's reading, and hope for the best... + */ + std::atomic_thread_fence(std::memory_order_seq_cst); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + { + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + return; + } + + auto usrfmt = DecomposeUserFormat(format); + if(UNLIKELY(!usrfmt)) + { + alSetError(context.get(), AL_INVALID_ENUM, "Invalid format 0x%04x", format); + return; + } + + ALsizei unpack_align{albuf->UnpackAlign.load()}; + ALsizei align{SanitizeAlignment(usrfmt->type, unpack_align)}; + if(UNLIKELY(align < 1)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid unpack alignment %d", unpack_align); + else if(UNLIKELY(long{usrfmt->channels} != long{albuf->mFmtChannels} || + usrfmt->type != albuf->OriginalType)) + alSetError(context.get(), AL_INVALID_ENUM, + "Unpacking data with mismatched format"); + else if(UNLIKELY(align != albuf->OriginalAlign)) + alSetError(context.get(), AL_INVALID_VALUE, + "Unpacking data with alignment %u does not match original alignment %u", + align, albuf->OriginalAlign); + else if(UNLIKELY(albuf->MappedAccess != 0)) + alSetError(context.get(), AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u", + buffer); + else + { + ALsizei num_chans{ChannelsFromFmt(albuf->mFmtChannels)}; + ALsizei frame_size{num_chans * BytesFromFmt(albuf->mFmtType)}; + ALsizei byte_align{ + (albuf->OriginalType == UserFmtIMA4) ? ((align-1)/2 + 4) * num_chans : + (albuf->OriginalType == UserFmtMSADPCM) ? ((align-2)/2 + 7) * num_chans : + (align * frame_size) + }; + + if(UNLIKELY(offset < 0 || length < 0 || offset > albuf->OriginalSize || + length > albuf->OriginalSize-offset)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid data sub-range %d+%d on buffer %u", + offset, length, buffer); + else if(UNLIKELY((offset%byte_align) != 0)) + alSetError(context.get(), AL_INVALID_VALUE, + "Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)", + offset, byte_align, align); + else if(UNLIKELY((length%byte_align) != 0)) + alSetError(context.get(), AL_INVALID_VALUE, + "Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)", + length, byte_align, align); + else + { + /* offset -> byte offset, length -> sample count */ + offset = offset/byte_align * align * frame_size; + length = length/byte_align * align; + + void *dst = albuf->mData.data() + offset; + if(usrfmt->type == UserFmtIMA4 && albuf->mFmtType == FmtShort) + Convert_ALshort_ALima4(static_cast(dst), + static_cast(data), num_chans, length, align); + else if(usrfmt->type == UserFmtMSADPCM && albuf->mFmtType == FmtShort) + Convert_ALshort_ALmsadpcm(static_cast(dst), + static_cast(data), num_chans, length, align); + else + { + assert(long{usrfmt->type} == static_cast(albuf->mFmtType)); + memcpy(dst, data, length * frame_size); + } + } + } +} +END_API_FUNC + + +AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint /*buffer*/, ALuint /*samplerate*/, + ALenum /*internalformat*/, ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, + const ALvoid* /*data*/) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + alSetError(context.get(), AL_INVALID_OPERATION, "alBufferSamplesSOFT not supported"); +} +END_API_FUNC + +AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint /*buffer*/, ALsizei /*offset*/, + ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, const ALvoid* /*data*/) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + alSetError(context.get(), AL_INVALID_OPERATION, "alBufferSubSamplesSOFT not supported"); +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint /*buffer*/, ALsizei /*offset*/, + ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, ALvoid* /*data*/) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + alSetError(context.get(), AL_INVALID_OPERATION, "alGetBufferSamplesSOFT not supported"); +} +END_API_FUNC + +AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum /*format*/) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(!context) return AL_FALSE; + + alSetError(context.get(), AL_INVALID_OPERATION, "alIsBufferFormatSupportedSOFT not supported"); + return AL_FALSE; +} +END_API_FUNC + + +AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat /*value*/) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, + ALfloat /*value1*/, ALfloat /*value2*/, ALfloat /*value3*/) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!values)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); + } +} +END_API_FUNC + + +AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else switch(param) + { + case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: + if(UNLIKELY(value < 0)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid unpack block alignment %d", value); + else + albuf->UnpackAlign.store(value); + break; + + case AL_PACK_BLOCK_ALIGNMENT_SOFT: + if(UNLIKELY(value < 0)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid pack block alignment %d", value); + else + albuf->PackAlign.store(value); + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, + ALint /*value1*/, ALint /*value2*/, ALint /*value3*/) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values) +START_API_FUNC +{ + if(values) + { + switch(param) + { + case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: + case AL_PACK_BLOCK_ALIGNMENT_SOFT: + alBufferi(buffer, param, values[0]); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!values)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_LOOP_POINTS_SOFT: + if(UNLIKELY(ReadRef(&albuf->ref) != 0)) + alSetError(context.get(), AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points", + buffer); + else if(UNLIKELY(values[0] >= values[1] || values[0] < 0 || values[1] > albuf->SampleLen)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid loop point range %d -> %d o buffer %u", + values[0], values[1], buffer); + else + { + albuf->LoopStart = values[0]; + albuf->LoopEnd = values[1]; + } + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", + param); + } +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!value)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!value1 || !value2 || !value3)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values) +START_API_FUNC +{ + switch(param) + { + case AL_SEC_LENGTH_SOFT: + alGetBufferf(buffer, param, values); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!values)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); + } +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!value)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_FREQUENCY: + *value = albuf->Frequency; + break; + + case AL_BITS: + *value = BytesFromFmt(albuf->mFmtType) * 8; + break; + + case AL_CHANNELS: + *value = ChannelsFromFmt(albuf->mFmtChannels); + break; + + case AL_SIZE: + *value = albuf->SampleLen * FrameSizeFromFmt(albuf->mFmtChannels, albuf->mFmtType); + break; + + case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: + *value = albuf->UnpackAlign.load(); + break; + + case AL_PACK_BLOCK_ALIGNMENT_SOFT: + *value = albuf->PackAlign.load(); + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!value1 || !value2 || !value3)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values) +START_API_FUNC +{ + switch(param) + { + case AL_FREQUENCY: + case AL_BITS: + case AL_CHANNELS: + case AL_SIZE: + case AL_INTERNAL_FORMAT_SOFT: + case AL_BYTE_LENGTH_SOFT: + case AL_SAMPLE_LENGTH_SOFT: + case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: + case AL_PACK_BLOCK_ALIGNMENT_SOFT: + alGetBufferi(buffer, param, values); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!values)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_LOOP_POINTS_SOFT: + values[0] = albuf->LoopStart; + values[1] = albuf->LoopEnd; + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", + param); + } +} +END_API_FUNC + + +ALsizei BytesFromUserFmt(UserFmtType type) +{ + switch(type) + { + case UserFmtUByte: return sizeof(ALubyte); + case UserFmtShort: return sizeof(ALshort); + case UserFmtFloat: return sizeof(ALfloat); + case UserFmtDouble: return sizeof(ALdouble); + case UserFmtMulaw: return sizeof(ALubyte); + case UserFmtAlaw: return sizeof(ALubyte); + case UserFmtIMA4: break; /* not handled here */ + case UserFmtMSADPCM: break; /* not handled here */ + } + return 0; +} +ALsizei ChannelsFromUserFmt(UserFmtChannels chans) +{ + switch(chans) + { + case UserFmtMono: return 1; + case UserFmtStereo: return 2; + case UserFmtRear: return 2; + case UserFmtQuad: return 4; + case UserFmtX51: return 6; + case UserFmtX61: return 7; + case UserFmtX71: return 8; + case UserFmtBFormat2D: return 3; + case UserFmtBFormat3D: return 4; + } + return 0; +} + +ALsizei BytesFromFmt(FmtType type) +{ + switch(type) + { + case FmtUByte: return sizeof(ALubyte); + case FmtShort: return sizeof(ALshort); + case FmtFloat: return sizeof(ALfloat); + case FmtDouble: return sizeof(ALdouble); + case FmtMulaw: return sizeof(ALubyte); + case FmtAlaw: return sizeof(ALubyte); + } + return 0; +} +ALsizei ChannelsFromFmt(FmtChannels chans) +{ + switch(chans) + { + case FmtMono: return 1; + case FmtStereo: return 2; + case FmtRear: return 2; + case FmtQuad: return 4; + case FmtX51: return 6; + case FmtX61: return 7; + case FmtX71: return 8; + case FmtBFormat2D: return 3; + case FmtBFormat3D: return 4; + } + return 0; +} + + +BufferSubList::~BufferSubList() +{ + uint64_t usemask{~FreeMask}; + while(usemask) + { + ALsizei idx{CTZ64(usemask)}; + al::destroy_at(Buffers+idx); + usemask &= ~(1_u64 << idx); + } + FreeMask = ~usemask; + al_free(Buffers); + Buffers = nullptr; +} diff --git a/al/alBuffer.h b/al/alBuffer.h new file mode 100644 index 00000000..1d5873e5 --- /dev/null +++ b/al/alBuffer.h @@ -0,0 +1,121 @@ +#ifndef AL_BUFFER_H +#define AL_BUFFER_H + +#include + +#include "AL/al.h" + +#include "albyte.h" +#include "almalloc.h" +#include "atomic.h" +#include "inprogext.h" +#include "vector.h" + + +/* User formats */ +enum UserFmtType : unsigned char { + UserFmtUByte, + UserFmtShort, + UserFmtFloat, + UserFmtDouble, + UserFmtMulaw, + UserFmtAlaw, + UserFmtIMA4, + UserFmtMSADPCM, +}; +enum UserFmtChannels : unsigned char { + UserFmtMono, + UserFmtStereo, + UserFmtRear, + UserFmtQuad, + UserFmtX51, /* (WFX order) */ + UserFmtX61, /* (WFX order) */ + UserFmtX71, /* (WFX order) */ + UserFmtBFormat2D, /* WXY */ + UserFmtBFormat3D, /* WXYZ */ +}; + +ALsizei BytesFromUserFmt(UserFmtType type); +ALsizei ChannelsFromUserFmt(UserFmtChannels chans); +inline ALsizei FrameSizeFromUserFmt(UserFmtChannels chans, UserFmtType type) +{ return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type); } + + +/* Storable formats */ +enum FmtType : unsigned char { + FmtUByte = UserFmtUByte, + FmtShort = UserFmtShort, + FmtFloat = UserFmtFloat, + FmtDouble = UserFmtDouble, + FmtMulaw = UserFmtMulaw, + FmtAlaw = UserFmtAlaw, +}; +enum FmtChannels : unsigned char { + FmtMono = UserFmtMono, + FmtStereo = UserFmtStereo, + FmtRear = UserFmtRear, + FmtQuad = UserFmtQuad, + FmtX51 = UserFmtX51, + FmtX61 = UserFmtX61, + FmtX71 = UserFmtX71, + FmtBFormat2D = UserFmtBFormat2D, + FmtBFormat3D = UserFmtBFormat3D, +}; +#define MAX_INPUT_CHANNELS (8) + +/* DevFmtType traits, providing the type, etc given a DevFmtType. */ +template +struct FmtTypeTraits { }; + +template<> +struct FmtTypeTraits { using Type = ALubyte; }; +template<> +struct FmtTypeTraits { using Type = ALshort; }; +template<> +struct FmtTypeTraits { using Type = ALfloat; }; +template<> +struct FmtTypeTraits { using Type = ALdouble; }; +template<> +struct FmtTypeTraits { using Type = ALubyte; }; +template<> +struct FmtTypeTraits { using Type = ALubyte; }; + + +ALsizei BytesFromFmt(FmtType type); +ALsizei ChannelsFromFmt(FmtChannels chans); +inline ALsizei FrameSizeFromFmt(FmtChannels chans, FmtType type) +{ return ChannelsFromFmt(chans) * BytesFromFmt(type); } + + +struct ALbuffer { + al::vector mData; + + ALsizei Frequency{0}; + ALbitfieldSOFT Access{0u}; + ALsizei SampleLen{0}; + + FmtChannels mFmtChannels{}; + FmtType mFmtType{}; + + UserFmtType OriginalType{}; + ALsizei OriginalSize{0}; + ALsizei OriginalAlign{0}; + + ALsizei LoopStart{0}; + ALsizei LoopEnd{0}; + + std::atomic UnpackAlign{0}; + std::atomic PackAlign{0}; + + ALbitfieldSOFT MappedAccess{0u}; + ALsizei MappedOffset{0}; + ALsizei MappedSize{0}; + + /* Number of times buffer was attached to a source (deletion can only occur when 0) */ + RefCount ref{0u}; + + /* Self ID */ + ALuint id{0}; +}; + +#endif diff --git a/al/alEffect.cpp b/al/alEffect.cpp new file mode 100644 index 00000000..4a75f69f --- /dev/null +++ b/al/alEffect.cpp @@ -0,0 +1,742 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "alEffect.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" +#include "AL/efx-presets.h" +#include "AL/efx.h" + +#include "alError.h" +#include "alcmain.h" +#include "alcontext.h" +#include "alexcpt.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "effects/base.h" +#include "logging.h" +#include "opthelpers.h" +#include "vector.h" + + +const EffectList gEffectList[15]{ + { "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB }, + { "reverb", REVERB_EFFECT, AL_EFFECT_REVERB }, + { "autowah", AUTOWAH_EFFECT, AL_EFFECT_AUTOWAH }, + { "chorus", CHORUS_EFFECT, AL_EFFECT_CHORUS }, + { "compressor", COMPRESSOR_EFFECT, AL_EFFECT_COMPRESSOR }, + { "distortion", DISTORTION_EFFECT, AL_EFFECT_DISTORTION }, + { "echo", ECHO_EFFECT, AL_EFFECT_ECHO }, + { "equalizer", EQUALIZER_EFFECT, AL_EFFECT_EQUALIZER }, + { "flanger", FLANGER_EFFECT, AL_EFFECT_FLANGER }, + { "fshifter", FSHIFTER_EFFECT, AL_EFFECT_FREQUENCY_SHIFTER }, + { "modulator", MODULATOR_EFFECT, AL_EFFECT_RING_MODULATOR }, + { "pshifter", PSHIFTER_EFFECT, AL_EFFECT_PITCH_SHIFTER }, + { "vmorpher", VMORPHER_EFFECT, AL_EFFECT_VOCAL_MORPHER }, + { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT }, + { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_DIALOGUE }, +}; + +ALboolean DisabledEffects[MAX_EFFECTS]; + +namespace { + +constexpr struct FactoryItem { + ALenum Type; + EffectStateFactory* (&GetFactory)(void); +} FactoryList[] = { + { AL_EFFECT_NULL, NullStateFactory_getFactory }, + { AL_EFFECT_EAXREVERB, ReverbStateFactory_getFactory }, + { AL_EFFECT_REVERB, StdReverbStateFactory_getFactory }, + { AL_EFFECT_AUTOWAH, AutowahStateFactory_getFactory }, + { AL_EFFECT_CHORUS, ChorusStateFactory_getFactory }, + { AL_EFFECT_COMPRESSOR, CompressorStateFactory_getFactory }, + { AL_EFFECT_DISTORTION, DistortionStateFactory_getFactory }, + { AL_EFFECT_ECHO, EchoStateFactory_getFactory }, + { AL_EFFECT_EQUALIZER, EqualizerStateFactory_getFactory }, + { AL_EFFECT_FLANGER, FlangerStateFactory_getFactory }, + { AL_EFFECT_FREQUENCY_SHIFTER, FshifterStateFactory_getFactory }, + { AL_EFFECT_RING_MODULATOR, ModulatorStateFactory_getFactory }, + { AL_EFFECT_PITCH_SHIFTER, PshifterStateFactory_getFactory}, + { AL_EFFECT_VOCAL_MORPHER, VmorpherStateFactory_getFactory}, + { AL_EFFECT_DEDICATED_DIALOGUE, DedicatedStateFactory_getFactory }, + { AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedStateFactory_getFactory } +}; + + +template +void ALeffect_setParami(ALeffect *effect, T&& ...args) +{ effect->vtab->setParami(&effect->Props, std::forward(args)...); } +template +void ALeffect_setParamiv(ALeffect *effect, T&& ...args) +{ effect->vtab->setParamiv(&effect->Props, std::forward(args)...); } +template +void ALeffect_setParamf(ALeffect *effect, T&& ...args) +{ effect->vtab->setParamf(&effect->Props, std::forward(args)...); } +template +void ALeffect_setParamfv(ALeffect *effect, T&& ...args) +{ effect->vtab->setParamfv(&effect->Props, std::forward(args)...); } + +template +void ALeffect_getParami(const ALeffect *effect, T&& ...args) +{ effect->vtab->getParami(&effect->Props, std::forward(args)...); } +template +void ALeffect_getParamiv(const ALeffect *effect, T&& ...args) +{ effect->vtab->getParamiv(&effect->Props, std::forward(args)...); } +template +void ALeffect_getParamf(const ALeffect *effect, T&& ...args) +{ effect->vtab->getParamf(&effect->Props, std::forward(args)...); } +template +void ALeffect_getParamfv(const ALeffect *effect, T&& ...args) +{ effect->vtab->getParamfv(&effect->Props, std::forward(args)...); } + + +void InitEffectParams(ALeffect *effect, ALenum type) +{ + EffectStateFactory *factory = getFactoryByType(type); + if(factory) + { + effect->Props = factory->getDefaultProps(); + effect->vtab = factory->getEffectVtable(); + } + else + { + effect->Props = EffectProps {}; + effect->vtab = nullptr; + } + effect->type = type; +} + +ALeffect *AllocEffect(ALCcontext *context) +{ + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + auto sublist = std::find_if(device->EffectList.begin(), device->EffectList.end(), + [](const EffectSubList &entry) noexcept -> bool + { return entry.FreeMask != 0; } + ); + + auto lidx = static_cast(std::distance(device->EffectList.begin(), sublist)); + ALeffect *effect{nullptr}; + ALsizei slidx{0}; + if(LIKELY(sublist != device->EffectList.end())) + { + slidx = CTZ64(sublist->FreeMask); + effect = sublist->Effects + slidx; + } + else + { + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(device->EffectList.size() >= 1<<25)) + { + alSetError(context, AL_OUT_OF_MEMORY, "Too many effects allocated"); + return nullptr; + } + device->EffectList.emplace_back(); + sublist = device->EffectList.end() - 1; + sublist->FreeMask = ~0_u64; + sublist->Effects = static_cast(al_calloc(16, sizeof(ALeffect)*64)); + if(UNLIKELY(!sublist->Effects)) + { + device->EffectList.pop_back(); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect batch"); + return nullptr; + } + + slidx = 0; + effect = sublist->Effects + slidx; + } + + effect = new (effect) ALeffect{}; + InitEffectParams(effect, AL_EFFECT_NULL); + + /* Add 1 to avoid effect ID 0. */ + effect->id = ((lidx<<6) | slidx) + 1; + + sublist->FreeMask &= ~(1_u64 << slidx); + + return effect; +} + +void FreeEffect(ALCdevice *device, ALeffect *effect) +{ + ALuint id = effect->id - 1; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; + + al::destroy_at(effect); + + device->EffectList[lidx].FreeMask |= 1_u64 << slidx; +} + +inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= device->EffectList.size())) + return nullptr; + EffectSubList &sublist = device->EffectList[lidx]; + if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + return nullptr; + return sublist.Effects + slidx; +} + +} // namespace + +AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(UNLIKELY(n < 0)) + { + alSetError(context.get(), AL_INVALID_VALUE, "Generating %d effects", n); + return; + } + + if(LIKELY(n == 1)) + { + /* Special handling for the easy and normal case. */ + ALeffect *effect = AllocEffect(context.get()); + if(effect) effects[0] = effect->id; + } + else if(n > 1) + { + /* Store the allocated buffer IDs in a separate local list, to avoid + * modifying the user storage in case of failure. + */ + al::vector ids; + ids.reserve(n); + do { + ALeffect *effect = AllocEffect(context.get()); + if(!effect) + { + alDeleteEffects(static_cast(ids.size()), ids.data()); + return; + } + + ids.emplace_back(effect->id); + } while(--n); + std::copy(ids.begin(), ids.end(), effects); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(UNLIKELY(n < 0)) + { + alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d effects", n); + return; + } + if(UNLIKELY(n == 0)) + return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + + /* First try to find any effects that are invalid. */ + const ALuint *effects_end = effects + n; + auto inveffect = std::find_if(effects, effects_end, + [device, &context](ALuint eid) -> bool + { + if(!eid) return false; + ALeffect *effect{LookupEffect(device, eid)}; + if(UNLIKELY(!effect)) + { + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", eid); + return true; + } + return false; + } + ); + if(LIKELY(inveffect == effects_end)) + { + /* All good. Delete non-0 effect IDs. */ + std::for_each(effects, effects_end, + [device](ALuint eid) -> void + { + ALeffect *effect{eid ? LookupEffect(device, eid) : nullptr}; + if(effect) FreeEffect(device, effect); + } + ); + } +} +END_API_FUNC + +AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(LIKELY(context)) + { + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + if(!effect || LookupEffect(device, effect)) + return AL_TRUE; + } + return AL_FALSE; +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + + ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + if(param == AL_EFFECT_TYPE) + { + ALboolean isOk{value == AL_EFFECT_NULL}; + if(!isOk) + { + for(const EffectList &effectitem : gEffectList) + { + if(value == effectitem.val && !DisabledEffects[effectitem.type]) + { + isOk = AL_TRUE; + break; + } + } + } + + if(isOk) + InitEffectParams(aleffect, value); + else + alSetError(context.get(), AL_INVALID_VALUE, "Effect type 0x%04x not supported", value); + } + else + { + /* Call the appropriate handler */ + ALeffect_setParami(aleffect, context.get(), param, value); + } + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *values) +START_API_FUNC +{ + switch(param) + { + case AL_EFFECT_TYPE: + alEffecti(effect, param, values[0]); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + + ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + /* Call the appropriate handler */ + ALeffect_setParamiv(aleffect, context.get(), param, values); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + + ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + /* Call the appropriate handler */ + ALeffect_setParamf(aleffect, context.get(), param, value); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + + ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + /* Call the appropriate handler */ + ALeffect_setParamfv(aleffect, context.get(), param, values); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + + const ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + if(param == AL_EFFECT_TYPE) + *value = aleffect->type; + else + { + /* Call the appropriate handler */ + ALeffect_getParami(aleffect, context.get(), param, value); + } + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *values) +START_API_FUNC +{ + switch(param) + { + case AL_EFFECT_TYPE: + alGetEffecti(effect, param, values); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + + const ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + /* Call the appropriate handler */ + ALeffect_getParamiv(aleffect, context.get(), param, values); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + + const ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + /* Call the appropriate handler */ + ALeffect_getParamf(aleffect, context.get(), param, value); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + + const ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + /* Call the appropriate handler */ + ALeffect_getParamfv(aleffect, context.get(), param, values); + } +} +END_API_FUNC + + +void InitEffect(ALeffect *effect) +{ + InitEffectParams(effect, AL_EFFECT_NULL); +} + +EffectSubList::~EffectSubList() +{ + uint64_t usemask{~FreeMask}; + while(usemask) + { + ALsizei idx = CTZ64(usemask); + al::destroy_at(Effects+idx); + usemask &= ~(1_u64 << idx); + } + FreeMask = ~usemask; + al_free(Effects); + Effects = nullptr; +} + + +EffectStateFactory *getFactoryByType(ALenum type) +{ + auto iter = std::find_if(std::begin(FactoryList), std::end(FactoryList), + [type](const FactoryItem &item) noexcept -> bool + { return item.Type == type; } + ); + return (iter != std::end(FactoryList)) ? iter->GetFactory() : nullptr; +} + + +#define DECL(x) { #x, EFX_REVERB_PRESET_##x } +static const struct { + const char name[32]; + EFXEAXREVERBPROPERTIES props; +} reverblist[] = { + DECL(GENERIC), + DECL(PADDEDCELL), + DECL(ROOM), + DECL(BATHROOM), + DECL(LIVINGROOM), + DECL(STONEROOM), + DECL(AUDITORIUM), + DECL(CONCERTHALL), + DECL(CAVE), + DECL(ARENA), + DECL(HANGAR), + DECL(CARPETEDHALLWAY), + DECL(HALLWAY), + DECL(STONECORRIDOR), + DECL(ALLEY), + DECL(FOREST), + DECL(CITY), + DECL(MOUNTAINS), + DECL(QUARRY), + DECL(PLAIN), + DECL(PARKINGLOT), + DECL(SEWERPIPE), + DECL(UNDERWATER), + DECL(DRUGGED), + DECL(DIZZY), + DECL(PSYCHOTIC), + + DECL(CASTLE_SMALLROOM), + DECL(CASTLE_SHORTPASSAGE), + DECL(CASTLE_MEDIUMROOM), + DECL(CASTLE_LARGEROOM), + DECL(CASTLE_LONGPASSAGE), + DECL(CASTLE_HALL), + DECL(CASTLE_CUPBOARD), + DECL(CASTLE_COURTYARD), + DECL(CASTLE_ALCOVE), + + DECL(FACTORY_SMALLROOM), + DECL(FACTORY_SHORTPASSAGE), + DECL(FACTORY_MEDIUMROOM), + DECL(FACTORY_LARGEROOM), + DECL(FACTORY_LONGPASSAGE), + DECL(FACTORY_HALL), + DECL(FACTORY_CUPBOARD), + DECL(FACTORY_COURTYARD), + DECL(FACTORY_ALCOVE), + + DECL(ICEPALACE_SMALLROOM), + DECL(ICEPALACE_SHORTPASSAGE), + DECL(ICEPALACE_MEDIUMROOM), + DECL(ICEPALACE_LARGEROOM), + DECL(ICEPALACE_LONGPASSAGE), + DECL(ICEPALACE_HALL), + DECL(ICEPALACE_CUPBOARD), + DECL(ICEPALACE_COURTYARD), + DECL(ICEPALACE_ALCOVE), + + DECL(SPACESTATION_SMALLROOM), + DECL(SPACESTATION_SHORTPASSAGE), + DECL(SPACESTATION_MEDIUMROOM), + DECL(SPACESTATION_LARGEROOM), + DECL(SPACESTATION_LONGPASSAGE), + DECL(SPACESTATION_HALL), + DECL(SPACESTATION_CUPBOARD), + DECL(SPACESTATION_ALCOVE), + + DECL(WOODEN_SMALLROOM), + DECL(WOODEN_SHORTPASSAGE), + DECL(WOODEN_MEDIUMROOM), + DECL(WOODEN_LARGEROOM), + DECL(WOODEN_LONGPASSAGE), + DECL(WOODEN_HALL), + DECL(WOODEN_CUPBOARD), + DECL(WOODEN_COURTYARD), + DECL(WOODEN_ALCOVE), + + DECL(SPORT_EMPTYSTADIUM), + DECL(SPORT_SQUASHCOURT), + DECL(SPORT_SMALLSWIMMINGPOOL), + DECL(SPORT_LARGESWIMMINGPOOL), + DECL(SPORT_GYMNASIUM), + DECL(SPORT_FULLSTADIUM), + DECL(SPORT_STADIUMTANNOY), + + DECL(PREFAB_WORKSHOP), + DECL(PREFAB_SCHOOLROOM), + DECL(PREFAB_PRACTISEROOM), + DECL(PREFAB_OUTHOUSE), + DECL(PREFAB_CARAVAN), + + DECL(DOME_TOMB), + DECL(PIPE_SMALL), + DECL(DOME_SAINTPAULS), + DECL(PIPE_LONGTHIN), + DECL(PIPE_LARGE), + DECL(PIPE_RESONANT), + + DECL(OUTDOORS_BACKYARD), + DECL(OUTDOORS_ROLLINGPLAINS), + DECL(OUTDOORS_DEEPCANYON), + DECL(OUTDOORS_CREEK), + DECL(OUTDOORS_VALLEY), + + DECL(MOOD_HEAVEN), + DECL(MOOD_HELL), + DECL(MOOD_MEMORY), + + DECL(DRIVING_COMMENTATOR), + DECL(DRIVING_PITGARAGE), + DECL(DRIVING_INCAR_RACER), + DECL(DRIVING_INCAR_SPORTS), + DECL(DRIVING_INCAR_LUXURY), + DECL(DRIVING_FULLGRANDSTAND), + DECL(DRIVING_EMPTYGRANDSTAND), + DECL(DRIVING_TUNNEL), + + DECL(CITY_STREETS), + DECL(CITY_SUBWAY), + DECL(CITY_MUSEUM), + DECL(CITY_LIBRARY), + DECL(CITY_UNDERPASS), + DECL(CITY_ABANDONED), + + DECL(DUSTYROOM), + DECL(CHAPEL), + DECL(SMALLWATERROOM), +}; +#undef DECL + +void LoadReverbPreset(const char *name, ALeffect *effect) +{ + if(strcasecmp(name, "NONE") == 0) + { + InitEffectParams(effect, AL_EFFECT_NULL); + TRACE("Loading reverb '%s'\n", "NONE"); + return; + } + + if(!DisabledEffects[EAXREVERB_EFFECT]) + InitEffectParams(effect, AL_EFFECT_EAXREVERB); + else if(!DisabledEffects[REVERB_EFFECT]) + InitEffectParams(effect, AL_EFFECT_REVERB); + else + InitEffectParams(effect, AL_EFFECT_NULL); + for(const auto &reverbitem : reverblist) + { + const EFXEAXREVERBPROPERTIES *props; + + if(strcasecmp(name, reverbitem.name) != 0) + continue; + + TRACE("Loading reverb '%s'\n", reverbitem.name); + props = &reverbitem.props; + effect->Props.Reverb.Density = props->flDensity; + effect->Props.Reverb.Diffusion = props->flDiffusion; + effect->Props.Reverb.Gain = props->flGain; + effect->Props.Reverb.GainHF = props->flGainHF; + effect->Props.Reverb.GainLF = props->flGainLF; + effect->Props.Reverb.DecayTime = props->flDecayTime; + effect->Props.Reverb.DecayHFRatio = props->flDecayHFRatio; + effect->Props.Reverb.DecayLFRatio = props->flDecayLFRatio; + effect->Props.Reverb.ReflectionsGain = props->flReflectionsGain; + effect->Props.Reverb.ReflectionsDelay = props->flReflectionsDelay; + effect->Props.Reverb.ReflectionsPan[0] = props->flReflectionsPan[0]; + effect->Props.Reverb.ReflectionsPan[1] = props->flReflectionsPan[1]; + effect->Props.Reverb.ReflectionsPan[2] = props->flReflectionsPan[2]; + effect->Props.Reverb.LateReverbGain = props->flLateReverbGain; + effect->Props.Reverb.LateReverbDelay = props->flLateReverbDelay; + effect->Props.Reverb.LateReverbPan[0] = props->flLateReverbPan[0]; + effect->Props.Reverb.LateReverbPan[1] = props->flLateReverbPan[1]; + effect->Props.Reverb.LateReverbPan[2] = props->flLateReverbPan[2]; + effect->Props.Reverb.EchoTime = props->flEchoTime; + effect->Props.Reverb.EchoDepth = props->flEchoDepth; + effect->Props.Reverb.ModulationTime = props->flModulationTime; + effect->Props.Reverb.ModulationDepth = props->flModulationDepth; + effect->Props.Reverb.AirAbsorptionGainHF = props->flAirAbsorptionGainHF; + effect->Props.Reverb.HFReference = props->flHFReference; + effect->Props.Reverb.LFReference = props->flLFReference; + effect->Props.Reverb.RoomRolloffFactor = props->flRoomRolloffFactor; + effect->Props.Reverb.DecayHFLimit = props->iDecayHFLimit; + return; + } + + WARN("Reverb preset '%s' not found\n", name); +} diff --git a/al/alEffect.h b/al/alEffect.h new file mode 100644 index 00000000..270b8e20 --- /dev/null +++ b/al/alEffect.h @@ -0,0 +1,61 @@ +#ifndef AL_EFFECT_H +#define AL_EFFECT_H + +#include "AL/al.h" +#include "AL/efx.h" + +#include "effects/base.h" + + +enum { + EAXREVERB_EFFECT = 0, + REVERB_EFFECT, + AUTOWAH_EFFECT, + CHORUS_EFFECT, + COMPRESSOR_EFFECT, + DISTORTION_EFFECT, + ECHO_EFFECT, + EQUALIZER_EFFECT, + FLANGER_EFFECT, + FSHIFTER_EFFECT, + MODULATOR_EFFECT, + PSHIFTER_EFFECT, + VMORPHER_EFFECT, + DEDICATED_EFFECT, + + MAX_EFFECTS +}; +extern ALboolean DisabledEffects[MAX_EFFECTS]; + +extern ALfloat ReverbBoost; + +struct EffectList { + const char name[16]; + int type; + ALenum val; +}; +extern const EffectList gEffectList[15]; + + +struct ALeffect { + // Effect type (AL_EFFECT_NULL, ...) + ALenum type{AL_EFFECT_NULL}; + + EffectProps Props{}; + + const EffectVtable *vtab{nullptr}; + + /* Self ID */ + ALuint id{0u}; +}; + +inline ALboolean IsReverbEffect(ALenum type) +{ return type == AL_EFFECT_REVERB || type == AL_EFFECT_EAXREVERB; } + +EffectStateFactory *getFactoryByType(ALenum type); + +void InitEffect(ALeffect *effect); + +void LoadReverbPreset(const char *name, ALeffect *effect); + +#endif diff --git a/al/alError.cpp b/al/alError.cpp new file mode 100644 index 00000000..159aee52 --- /dev/null +++ b/al/alError.cpp @@ -0,0 +1,118 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2000 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "alError.h" + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" + +#include "alcmain.h" +#include "alcontext.h" +#include "alexcpt.h" +#include "almalloc.h" +#include "inprogext.h" +#include "logging.h" +#include "opthelpers.h" +#include "vector.h" + + +bool TrapALError{false}; + +void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) +{ + auto message = al::vector(256); + + va_list args, args2; + va_start(args, msg); + va_copy(args2, args); + int msglen{std::vsnprintf(message.data(), message.size(), msg, args)}; + if(msglen >= 0 && static_cast(msglen) >= message.size()) + { + message.resize(static_cast(msglen) + 1u); + msglen = std::vsnprintf(message.data(), message.size(), msg, args2); + } + va_end(args2); + va_end(args); + + if(msglen >= 0) msg = message.data(); + else msg = ""; + msglen = static_cast(strlen(msg)); + + WARN("Error generated on context %p, code 0x%04x, \"%s\"\n", context, errorCode, msg); + if(TrapALError) + { +#ifdef _WIN32 + /* DebugBreak will cause an exception if there is no debugger */ + if(IsDebuggerPresent()) + DebugBreak(); +#elif defined(SIGTRAP) + raise(SIGTRAP); +#endif + } + + ALenum curerr{AL_NO_ERROR}; + context->LastError.compare_exchange_strong(curerr, errorCode); + if((context->EnabledEvts.load(std::memory_order_relaxed)&EventType_Error)) + { + std::lock_guard _{context->EventCbLock}; + ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; + if((enabledevts&EventType_Error) && context->EventCb) + (*context->EventCb)(AL_EVENT_TYPE_ERROR_SOFT, 0, errorCode, msglen, msg, + context->EventParam); + } +} + +AL_API ALenum AL_APIENTRY alGetError(void) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) + { + constexpr ALenum deferror{AL_INVALID_OPERATION}; + WARN("Querying error state on null context (implicitly 0x%04x)\n", deferror); + if(TrapALError) + { +#ifdef _WIN32 + if(IsDebuggerPresent()) + DebugBreak(); +#elif defined(SIGTRAP) + raise(SIGTRAP); +#endif + } + return deferror; + } + + return context->LastError.exchange(AL_NO_ERROR); +} +END_API_FUNC diff --git a/al/alError.h b/al/alError.h new file mode 100644 index 00000000..6408b60c --- /dev/null +++ b/al/alError.h @@ -0,0 +1,24 @@ +#ifndef AL_ERROR_H +#define AL_ERROR_H + +#include "AL/al.h" +#include "AL/alc.h" + +#include "logging.h" + + +extern bool TrapALError; + +void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) DECL_FORMAT(printf, 3, 4); + +#define SETERR_GOTO(ctx, err, lbl, ...) do { \ + alSetError((ctx), (err), __VA_ARGS__); \ + goto lbl; \ +} while(0) + +#define SETERR_RETURN(ctx, err, retval, ...) do { \ + alSetError((ctx), (err), __VA_ARGS__); \ + return retval; \ +} while(0) + +#endif diff --git a/al/alExtension.cpp b/al/alExtension.cpp new file mode 100644 index 00000000..80681090 --- /dev/null +++ b/al/alExtension.cpp @@ -0,0 +1,80 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" + +#include "alError.h" +#include "alcontext.h" +#include "alexcpt.h" +#include "opthelpers.h" + + +AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return AL_FALSE; + + if(!extName) + SETERR_RETURN(context.get(), AL_INVALID_VALUE, AL_FALSE, "NULL pointer"); + + size_t len{strlen(extName)}; + const char *ptr{context->ExtensionList}; + while(ptr && *ptr) + { + if(strncasecmp(ptr, extName, len) == 0 && + (ptr[len] == '\0' || isspace(ptr[len]))) + return AL_TRUE; + + if((ptr=strchr(ptr, ' ')) != nullptr) + { + do { + ++ptr; + } while(isspace(*ptr)); + } + } + + return AL_FALSE; +} +END_API_FUNC + + +AL_API ALvoid* AL_APIENTRY alGetProcAddress(const ALchar *funcName) +START_API_FUNC +{ + if(!funcName) return nullptr; + return alcGetProcAddress(nullptr, funcName); +} +END_API_FUNC + +AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *enumName) +START_API_FUNC +{ + if(!enumName) return static_cast(0); + return alcGetEnumValue(nullptr, enumName); +} +END_API_FUNC diff --git a/al/alFilter.cpp b/al/alFilter.cpp new file mode 100644 index 00000000..31fbaf21 --- /dev/null +++ b/al/alFilter.cpp @@ -0,0 +1,665 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "alFilter.h" + +#include +#include +#include +#include +#include +#include + +#include "AL/efx.h" + +#include "alError.h" +#include "alcmain.h" +#include "alcontext.h" +#include "alexcpt.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "opthelpers.h" +#include "vector.h" + + +namespace { + +#define FILTER_MIN_GAIN 0.0f +#define FILTER_MAX_GAIN 4.0f /* +12dB */ + +void ALlowpass_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) +{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } +void ALlowpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } +void ALlowpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_LOWPASS_GAIN: + if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gain %f out of range", val); + filter->Gain = val; + break; + + case AL_LOWPASS_GAINHF: + if(!(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gainhf %f out of range", val); + filter->GainHF = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param); + } +} +void ALlowpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALlowpass_setParamf(filter, context, param, vals[0]); } + +void ALlowpass_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } +void ALlowpass_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } +void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_LOWPASS_GAIN: + *val = filter->Gain; + break; + + case AL_LOWPASS_GAINHF: + *val = filter->GainHF; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param); + } +} +void ALlowpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALlowpass_getParamf(filter, context, param, vals); } + +DEFINE_ALFILTER_VTABLE(ALlowpass); + + +void ALhighpass_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) +{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } +void ALhighpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } +void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_HIGHPASS_GAIN: + if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gain out of range"); + filter->Gain = val; + break; + + case AL_HIGHPASS_GAINLF: + if(!(val >= AL_HIGHPASS_MIN_GAINLF && val <= AL_HIGHPASS_MAX_GAINLF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gainlf out of range"); + filter->GainLF = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param); + } +} +void ALhighpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALhighpass_setParamf(filter, context, param, vals[0]); } + +void ALhighpass_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } +void ALhighpass_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } +void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_HIGHPASS_GAIN: + *val = filter->Gain; + break; + + case AL_HIGHPASS_GAINLF: + *val = filter->GainLF; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param); + } +} +void ALhighpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALhighpass_getParamf(filter, context, param, vals); } + +DEFINE_ALFILTER_VTABLE(ALhighpass); + + +void ALbandpass_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) +{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } +void ALbandpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } +void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_BANDPASS_GAIN: + if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gain out of range"); + filter->Gain = val; + break; + + case AL_BANDPASS_GAINHF: + if(!(val >= AL_BANDPASS_MIN_GAINHF && val <= AL_BANDPASS_MAX_GAINHF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainhf out of range"); + filter->GainHF = val; + break; + + case AL_BANDPASS_GAINLF: + if(!(val >= AL_BANDPASS_MIN_GAINLF && val <= AL_BANDPASS_MAX_GAINLF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainlf out of range"); + filter->GainLF = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param); + } +} +void ALbandpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALbandpass_setParamf(filter, context, param, vals[0]); } + +void ALbandpass_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } +void ALbandpass_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } +void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_BANDPASS_GAIN: + *val = filter->Gain; + break; + + case AL_BANDPASS_GAINHF: + *val = filter->GainHF; + break; + + case AL_BANDPASS_GAINLF: + *val = filter->GainLF; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param); + } +} +void ALbandpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALbandpass_getParamf(filter, context, param, vals); } + +DEFINE_ALFILTER_VTABLE(ALbandpass); + + +void ALnullfilter_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +void ALnullfilter_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +void ALnullfilter_setParamf(ALfilter*, ALCcontext *context, ALenum param, ALfloat) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +void ALnullfilter_setParamfv(ALfilter*, ALCcontext *context, ALenum param, const ALfloat*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } + +void ALnullfilter_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +void ALnullfilter_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +void ALnullfilter_getParamf(ALfilter*, ALCcontext *context, ALenum param, ALfloat*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +void ALnullfilter_getParamfv(ALfilter*, ALCcontext *context, ALenum param, ALfloat*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } + +DEFINE_ALFILTER_VTABLE(ALnullfilter); + + +void InitFilterParams(ALfilter *filter, ALenum type) +{ + if(type == AL_FILTER_LOWPASS) + { + filter->Gain = AL_LOWPASS_DEFAULT_GAIN; + filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF; + filter->HFReference = LOWPASSFREQREF; + filter->GainLF = 1.0f; + filter->LFReference = HIGHPASSFREQREF; + filter->vtab = &ALlowpass_vtable; + } + else if(type == AL_FILTER_HIGHPASS) + { + filter->Gain = AL_HIGHPASS_DEFAULT_GAIN; + filter->GainHF = 1.0f; + filter->HFReference = LOWPASSFREQREF; + filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF; + filter->LFReference = HIGHPASSFREQREF; + filter->vtab = &ALhighpass_vtable; + } + else if(type == AL_FILTER_BANDPASS) + { + filter->Gain = AL_BANDPASS_DEFAULT_GAIN; + filter->GainHF = AL_BANDPASS_DEFAULT_GAINHF; + filter->HFReference = LOWPASSFREQREF; + filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF; + filter->LFReference = HIGHPASSFREQREF; + filter->vtab = &ALbandpass_vtable; + } + else + { + filter->Gain = 1.0f; + filter->GainHF = 1.0f; + filter->HFReference = LOWPASSFREQREF; + filter->GainLF = 1.0f; + filter->LFReference = HIGHPASSFREQREF; + filter->vtab = &ALnullfilter_vtable; + } + filter->type = type; +} + +ALfilter *AllocFilter(ALCcontext *context) +{ + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + auto sublist = std::find_if(device->FilterList.begin(), device->FilterList.end(), + [](const FilterSubList &entry) noexcept -> bool + { return entry.FreeMask != 0; } + ); + + auto lidx = static_cast(std::distance(device->FilterList.begin(), sublist)); + ALfilter *filter{nullptr}; + ALsizei slidx{0}; + if(LIKELY(sublist != device->FilterList.end())) + { + slidx = CTZ64(sublist->FreeMask); + filter = sublist->Filters + slidx; + } + else + { + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(device->FilterList.size() >= 1<<25)) + { + alSetError(context, AL_OUT_OF_MEMORY, "Too many filters allocated"); + return nullptr; + } + device->FilterList.emplace_back(); + sublist = device->FilterList.end() - 1; + sublist->FreeMask = ~0_u64; + sublist->Filters = static_cast(al_calloc(16, sizeof(ALfilter)*64)); + if(UNLIKELY(!sublist->Filters)) + { + device->FilterList.pop_back(); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate filter batch"); + return nullptr; + } + + slidx = 0; + filter = sublist->Filters + slidx; + } + + filter = new (filter) ALfilter{}; + InitFilterParams(filter, AL_FILTER_NULL); + + /* Add 1 to avoid filter ID 0. */ + filter->id = ((lidx<<6) | slidx) + 1; + + sublist->FreeMask &= ~(1_u64 << slidx); + + return filter; +} + +void FreeFilter(ALCdevice *device, ALfilter *filter) +{ + ALuint id = filter->id - 1; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; + + al::destroy_at(filter); + + device->FilterList[lidx].FreeMask |= 1_u64 << slidx; +} + + +inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= device->FilterList.size())) + return nullptr; + FilterSubList &sublist = device->FilterList[lidx]; + if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + return nullptr; + return sublist.Filters + slidx; +} + +} // namespace + +AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(UNLIKELY(n < 0)) + { + alSetError(context.get(), AL_INVALID_VALUE, "Generating %d filters", n); + return; + } + + if(LIKELY(n == 1)) + { + /* Special handling for the easy and normal case. */ + ALfilter *filter = AllocFilter(context.get()); + if(filter) filters[0] = filter->id; + } + else if(n > 1) + { + /* Store the allocated buffer IDs in a separate local list, to avoid + * modifying the user storage in case of failure. + */ + al::vector ids; + ids.reserve(n); + do { + ALfilter *filter = AllocFilter(context.get()); + if(!filter) + { + alDeleteFilters(static_cast(ids.size()), ids.data()); + return; + } + + ids.emplace_back(filter->id); + } while(--n); + std::copy(ids.begin(), ids.end(), filters); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(UNLIKELY(n < 0)) + { + alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d filters", n); + return; + } + if(UNLIKELY(n == 0)) + return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + /* First try to find any filters that are invalid. */ + const ALuint *filters_end = filters + n; + auto invflt = std::find_if(filters, filters_end, + [device, &context](ALuint fid) -> bool + { + if(!fid) return false; + ALfilter *filter{LookupFilter(device, fid)}; + if(UNLIKELY(!filter)) + { + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", fid); + return true; + } + return false; + } + ); + if(LIKELY(invflt == filters_end)) + { + /* All good. Delete non-0 filter IDs. */ + std::for_each(filters, filters_end, + [device](ALuint fid) -> void + { + ALfilter *filter{fid ? LookupFilter(device, fid) : nullptr}; + if(filter) FreeFilter(device, filter); + } + ); + } +} +END_API_FUNC + +AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(LIKELY(context)) + { + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + if(!filter || LookupFilter(device, filter)) + return AL_TRUE; + } + return AL_FALSE; +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + if(param == AL_FILTER_TYPE) + { + if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS || + value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS) + InitFilterParams(alfilt, value); + else + alSetError(context.get(), AL_INVALID_VALUE, "Invalid filter type 0x%04x", value); + } + else + { + /* Call the appropriate handler */ + ALfilter_setParami(alfilt, context.get(), param, value); + } + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *values) +START_API_FUNC +{ + switch(param) + { + case AL_FILTER_TYPE: + alFilteri(filter, param, values[0]); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_setParamiv(alfilt, context.get(), param, values); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_setParamf(alfilt, context.get(), param, value); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_setParamfv(alfilt, context.get(), param, values); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + if(param == AL_FILTER_TYPE) + *value = alfilt->type; + else + { + /* Call the appropriate handler */ + ALfilter_getParami(alfilt, context.get(), param, value); + } + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *values) +START_API_FUNC +{ + switch(param) + { + case AL_FILTER_TYPE: + alGetFilteri(filter, param, values); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_getParamiv(alfilt, context.get(), param, values); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_getParamf(alfilt, context.get(), param, value); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_getParamfv(alfilt, context.get(), param, values); + } +} +END_API_FUNC + + +FilterSubList::~FilterSubList() +{ + uint64_t usemask{~FreeMask}; + while(usemask) + { + ALsizei idx = CTZ64(usemask); + al::destroy_at(Filters+idx); + usemask &= ~(1_u64 << idx); + } + FreeMask = ~usemask; + al_free(Filters); + Filters = nullptr; +} diff --git a/al/alFilter.h b/al/alFilter.h new file mode 100644 index 00000000..db098d70 --- /dev/null +++ b/al/alFilter.h @@ -0,0 +1,56 @@ +#ifndef AL_FILTER_H +#define AL_FILTER_H + +#include "AL/al.h" +#include "AL/alc.h" + + +#define LOWPASSFREQREF (5000.0f) +#define HIGHPASSFREQREF (250.0f) + + +struct ALfilter; + +struct ALfilterVtable { + void (*const setParami)(ALfilter *filter, ALCcontext *context, ALenum param, ALint val); + void (*const setParamiv)(ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals); + void (*const setParamf)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val); + void (*const setParamfv)(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals); + + void (*const getParami)(ALfilter *filter, ALCcontext *context, ALenum param, ALint *val); + void (*const getParamiv)(ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals); + void (*const getParamf)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val); + void (*const getParamfv)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals); +}; + +#define DEFINE_ALFILTER_VTABLE(T) \ +const ALfilterVtable T##_vtable = { \ + T##_setParami, T##_setParamiv, T##_setParamf, T##_setParamfv, \ + T##_getParami, T##_getParamiv, T##_getParamf, T##_getParamfv, \ +} + +struct ALfilter { + // Filter type (AL_FILTER_NULL, ...) + ALenum type; + + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; + + const ALfilterVtable *vtab; + + /* Self ID */ + ALuint id; +}; +#define ALfilter_setParami(o, c, p, v) ((o)->vtab->setParami(o, c, p, v)) +#define ALfilter_setParamf(o, c, p, v) ((o)->vtab->setParamf(o, c, p, v)) +#define ALfilter_setParamiv(o, c, p, v) ((o)->vtab->setParamiv(o, c, p, v)) +#define ALfilter_setParamfv(o, c, p, v) ((o)->vtab->setParamfv(o, c, p, v)) +#define ALfilter_getParami(o, c, p, v) ((o)->vtab->getParami(o, c, p, v)) +#define ALfilter_getParamf(o, c, p, v) ((o)->vtab->getParamf(o, c, p, v)) +#define ALfilter_getParamiv(o, c, p, v) ((o)->vtab->getParamiv(o, c, p, v)) +#define ALfilter_getParamfv(o, c, p, v) ((o)->vtab->getParamfv(o, c, p, v)) + +#endif diff --git a/al/alListener.cpp b/al/alListener.cpp new file mode 100644 index 00000000..d3bf3aaa --- /dev/null +++ b/al/alListener.cpp @@ -0,0 +1,454 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2000 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "alListener.h" + +#include +#include + +#include "AL/efx.h" + +#include "alError.h" +#include "alcontext.h" +#include "alexcpt.h" +#include "almalloc.h" +#include "atomic.h" +#include "opthelpers.h" + + +#define DO_UPDATEPROPS() do { \ + if(!context->DeferUpdates.load(std::memory_order_acquire)) \ + UpdateListenerProps(context.get()); \ + else \ + listener.PropsClean.clear(std::memory_order_release); \ +} while(0) + + +AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; + switch(param) + { + case AL_GAIN: + if(!(value >= 0.0f && std::isfinite(value))) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener gain out of range"); + listener.Gain = value; + DO_UPDATEPROPS(); + break; + + case AL_METERS_PER_UNIT: + if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT)) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, + "Listener meters per unit out of range"); + context->MetersPerUnit = value; + if(!context->DeferUpdates.load(std::memory_order_acquire)) + UpdateContextProps(context.get()); + else + context->PropsClean.clear(std::memory_order_release); + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float property"); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; + switch(param) + { + case AL_POSITION: + if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3))) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener position out of range"); + listener.Position[0] = value1; + listener.Position[1] = value2; + listener.Position[2] = value3; + DO_UPDATEPROPS(); + break; + + case AL_VELOCITY: + if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3))) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener velocity out of range"); + listener.Velocity[0] = value1; + listener.Velocity[1] = value2; + listener.Velocity[2] = value3; + DO_UPDATEPROPS(); + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-float property"); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) +START_API_FUNC +{ + if(values) + { + switch(param) + { + case AL_GAIN: + case AL_METERS_PER_UNIT: + alListenerf(param, values[0]); + return; + + case AL_POSITION: + case AL_VELOCITY: + alListener3f(param, values[0], values[1], values[2]); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; + if(!values) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "NULL pointer"); + switch(param) + { + case AL_ORIENTATION: + if(!(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) && + std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5]))) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener orientation out of range"); + /* AT then UP */ + listener.OrientAt[0] = values[0]; + listener.OrientAt[1] = values[1]; + listener.OrientAt[2] = values[2]; + listener.OrientUp[0] = values[3]; + listener.OrientUp[1] = values[4]; + listener.OrientUp[2] = values[5]; + DO_UPDATEPROPS(); + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float-vector property"); + } +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint /*value*/) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer property"); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3) +START_API_FUNC +{ + switch(param) + { + case AL_POSITION: + case AL_VELOCITY: + alListener3f(param, static_cast(value1), static_cast(value2), static_cast(value3)); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-integer property"); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values) +START_API_FUNC +{ + if(values) + { + ALfloat fvals[6]; + switch(param) + { + case AL_POSITION: + case AL_VELOCITY: + alListener3f(param, static_cast(values[0]), static_cast(values[1]), static_cast(values[2])); + return; + + case AL_ORIENTATION: + fvals[0] = static_cast(values[0]); + fvals[1] = static_cast(values[1]); + fvals[2] = static_cast(values[2]); + fvals[3] = static_cast(values[3]); + fvals[4] = static_cast(values[4]); + fvals[5] = static_cast(values[5]); + alListenerfv(param, fvals); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer-vector property"); + } +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; + if(!value) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_GAIN: + *value = listener.Gain; + break; + + case AL_METERS_PER_UNIT: + *value = context->MetersPerUnit; + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float property"); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; + if(!value1 || !value2 || !value3) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_POSITION: + *value1 = listener.Position[0]; + *value2 = listener.Position[1]; + *value3 = listener.Position[2]; + break; + + case AL_VELOCITY: + *value1 = listener.Velocity[0]; + *value2 = listener.Velocity[1]; + *value3 = listener.Velocity[2]; + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-float property"); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) +START_API_FUNC +{ + switch(param) + { + case AL_GAIN: + case AL_METERS_PER_UNIT: + alGetListenerf(param, values); + return; + + case AL_POSITION: + case AL_VELOCITY: + alGetListener3f(param, values+0, values+1, values+2); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_ORIENTATION: + // AT then UP + values[0] = listener.OrientAt[0]; + values[1] = listener.OrientAt[1]; + values[2] = listener.OrientAt[2]; + values[3] = listener.OrientUp[0]; + values[4] = listener.OrientUp[1]; + values[5] = listener.OrientUp[2]; + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float-vector property"); + } +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + if(!value) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer property"); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; + if(!value1 || !value2 || !value3) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_POSITION: + *value1 = static_cast(listener.Position[0]); + *value2 = static_cast(listener.Position[1]); + *value3 = static_cast(listener.Position[2]); + break; + + case AL_VELOCITY: + *value1 = static_cast(listener.Velocity[0]); + *value2 = static_cast(listener.Velocity[1]); + *value3 = static_cast(listener.Velocity[2]); + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-integer property"); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) +START_API_FUNC +{ + switch(param) + { + case AL_POSITION: + case AL_VELOCITY: + alGetListener3i(param, values+0, values+1, values+2); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_ORIENTATION: + // AT then UP + values[0] = static_cast(listener.OrientAt[0]); + values[1] = static_cast(listener.OrientAt[1]); + values[2] = static_cast(listener.OrientAt[2]); + values[3] = static_cast(listener.OrientUp[0]); + values[4] = static_cast(listener.OrientUp[1]); + values[5] = static_cast(listener.OrientUp[2]); + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer-vector property"); + } +} +END_API_FUNC + + +void UpdateListenerProps(ALCcontext *context) +{ + /* Get an unused proprty container, or allocate a new one as needed. */ + ALlistenerProps *props{context->FreeListenerProps.load(std::memory_order_acquire)}; + if(!props) + props = static_cast(al_calloc(16, sizeof(*props))); + else + { + ALlistenerProps *next; + do { + next = props->next.load(std::memory_order_relaxed); + } while(context->FreeListenerProps.compare_exchange_weak(props, next, + std::memory_order_seq_cst, std::memory_order_acquire) == 0); + } + + /* Copy in current property values. */ + ALlistener &listener = context->Listener; + props->Position = listener.Position; + props->Velocity = listener.Velocity; + props->OrientAt = listener.OrientAt; + props->OrientUp = listener.OrientUp; + props->Gain = listener.Gain; + + /* Set the new container for updating internal parameters. */ + props = listener.Update.exchange(props, std::memory_order_acq_rel); + if(props) + { + /* If there was an unused update container, put it back in the + * freelist. + */ + AtomicReplaceHead(context->FreeListenerProps, props); + } +} diff --git a/al/alListener.h b/al/alListener.h new file mode 100644 index 00000000..a71db9f8 --- /dev/null +++ b/al/alListener.h @@ -0,0 +1,58 @@ +#ifndef AL_LISTENER_H +#define AL_LISTENER_H + +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" + +#include "vecmat.h" + +enum class DistanceModel; + + +struct ALlistenerProps { + std::array Position; + std::array Velocity; + std::array OrientAt; + std::array OrientUp; + ALfloat Gain; + + std::atomic next; +}; + +struct ALlistener { + std::array Position{{0.0f, 0.0f, 0.0f}}; + std::array Velocity{{0.0f, 0.0f, 0.0f}}; + std::array OrientAt{{0.0f, 0.0f, -1.0f}}; + std::array OrientUp{{0.0f, 1.0f, 0.0f}}; + ALfloat Gain{1.0f}; + + std::atomic_flag PropsClean; + + /* Pointer to the most recent property values that are awaiting an update. + */ + std::atomic Update{nullptr}; + + struct { + alu::Matrix Matrix; + alu::Vector Velocity; + + ALfloat Gain; + ALfloat MetersPerUnit; + + ALfloat DopplerFactor; + ALfloat SpeedOfSound; /* in units per sec! */ + ALfloat ReverbSpeedOfSound; /* in meters per sec! */ + + ALboolean SourceDistanceModel; + DistanceModel mDistanceModel; + } Params; + + ALlistener() { PropsClean.test_and_set(std::memory_order_relaxed); } +}; + +void UpdateListenerProps(ALCcontext *context); + +#endif diff --git a/al/alSource.cpp b/al/alSource.cpp new file mode 100644 index 00000000..4af5cc47 --- /dev/null +++ b/al/alSource.cpp @@ -0,0 +1,3638 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "alSource.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" +#include "AL/efx.h" + +#include "alAuxEffectSlot.h" +#include "alBuffer.h" +#include "alError.h" +#include "alFilter.h" +#include "alcmain.h" +#include "alcontext.h" +#include "alexcpt.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "alu.h" +#include "ambidefs.h" +#include "atomic.h" +#include "backends/base.h" +#include "bformatdec.h" +#include "filters/nfc.h" +#include "filters/splitter.h" +#include "inprogext.h" +#include "logging.h" +#include "math_defs.h" +#include "opthelpers.h" +#include "ringbuffer.h" +#include "threads.h" + + +namespace { + +using namespace std::placeholders; + +inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) +{ + ALint idx{source->VoiceIdx}; + if(idx >= 0 && static_cast(idx) < context->VoiceCount.load(std::memory_order_relaxed)) + { + ALuint sid{source->id}; + ALvoice &voice = (*context->Voices)[idx]; + if(voice.mSourceID.load(std::memory_order_acquire) == sid) + return &voice; + } + source->VoiceIdx = -1; + return nullptr; +} + +void UpdateSourceProps(const ALsource *source, ALvoice *voice, ALCcontext *context) +{ + /* Get an unused property container, or allocate a new one as needed. */ + ALvoiceProps *props{context->FreeVoiceProps.load(std::memory_order_acquire)}; + if(!props) + props = new ALvoiceProps{}; + else + { + ALvoiceProps *next; + do { + next = props->next.load(std::memory_order_relaxed); + } while(context->FreeVoiceProps.compare_exchange_weak(props, next, + std::memory_order_acq_rel, std::memory_order_acquire) == 0); + } + + /* Copy in current property values. */ + props->Pitch = source->Pitch; + props->Gain = source->Gain; + props->OuterGain = source->OuterGain; + props->MinGain = source->MinGain; + props->MaxGain = source->MaxGain; + props->InnerAngle = source->InnerAngle; + props->OuterAngle = source->OuterAngle; + props->RefDistance = source->RefDistance; + props->MaxDistance = source->MaxDistance; + props->RolloffFactor = source->RolloffFactor; + props->Position = source->Position; + props->Velocity = source->Velocity; + props->Direction = source->Direction; + props->OrientAt = source->OrientAt; + props->OrientUp = source->OrientUp; + props->HeadRelative = source->HeadRelative; + props->mDistanceModel = source->mDistanceModel; + props->mResampler = source->mResampler; + props->DirectChannels = source->DirectChannels; + props->mSpatializeMode = source->mSpatialize; + + props->DryGainHFAuto = source->DryGainHFAuto; + props->WetGainAuto = source->WetGainAuto; + props->WetGainHFAuto = source->WetGainHFAuto; + props->OuterGainHF = source->OuterGainHF; + + props->AirAbsorptionFactor = source->AirAbsorptionFactor; + props->RoomRolloffFactor = source->RoomRolloffFactor; + props->DopplerFactor = source->DopplerFactor; + + props->StereoPan = source->StereoPan; + + props->Radius = source->Radius; + + props->Direct.Gain = source->Direct.Gain; + props->Direct.GainHF = source->Direct.GainHF; + props->Direct.HFReference = source->Direct.HFReference; + props->Direct.GainLF = source->Direct.GainLF; + props->Direct.LFReference = source->Direct.LFReference; + + auto copy_send = [](const ALsource::SendData &srcsend) noexcept -> ALvoicePropsBase::SendData + { + ALvoicePropsBase::SendData ret; + ret.Slot = srcsend.Slot; + ret.Gain = srcsend.Gain; + ret.GainHF = srcsend.GainHF; + ret.HFReference = srcsend.HFReference; + ret.GainLF = srcsend.GainLF; + ret.LFReference = srcsend.LFReference; + return ret; + }; + std::transform(source->Send.cbegin(), source->Send.cend(), props->Send, copy_send); + + /* Set the new container for updating internal parameters. */ + props = voice->mUpdate.exchange(props, std::memory_order_acq_rel); + if(props) + { + /* If there was an unused update container, put it back in the + * freelist. + */ + AtomicReplaceHead(context->FreeVoiceProps, props); + } +} + +/* GetSourceSampleOffset + * + * Gets the current read offset for the given Source, in 32.32 fixed-point + * samples. The offset is relative to the start of the queue (not the start of + * the current buffer). + */ +int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, std::chrono::nanoseconds *clocktime) +{ + ALCdevice *device{context->Device}; + const ALbufferlistitem *Current; + uint64_t readPos; + ALuint refcount; + ALvoice *voice; + + do { + Current = nullptr; + readPos = 0; + while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) + std::this_thread::yield(); + *clocktime = GetDeviceClockTime(device); + + voice = GetSourceVoice(Source, context); + if(voice) + { + Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); + + readPos = uint64_t{voice->mPosition.load(std::memory_order_relaxed)} << 32; + readPos |= int64_t{voice->mPositionFrac.load(std::memory_order_relaxed)} << + (32-FRACTIONBITS); + } + std::atomic_thread_fence(std::memory_order_acquire); + } while(refcount != device->MixCount.load(std::memory_order_relaxed)); + + if(voice) + { + const ALbufferlistitem *BufferList{Source->queue}; + while(BufferList && BufferList != Current) + { + readPos += int64_t{BufferList->max_samples} << 32; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + readPos = minu64(readPos, 0x7fffffffffffffff_u64); + } + + return static_cast(readPos); +} + +/* GetSourceSecOffset + * + * Gets the current read offset for the given Source, in seconds. The offset is + * relative to the start of the queue (not the start of the current buffer). + */ +ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, std::chrono::nanoseconds *clocktime) +{ + ALCdevice *device{context->Device}; + const ALbufferlistitem *Current; + uint64_t readPos; + ALuint refcount; + ALvoice *voice; + + do { + Current = nullptr; + readPos = 0; + while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) + std::this_thread::yield(); + *clocktime = GetDeviceClockTime(device); + + voice = GetSourceVoice(Source, context); + if(voice) + { + Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); + + readPos = uint64_t{voice->mPosition.load(std::memory_order_relaxed)} << FRACTIONBITS; + readPos |= voice->mPositionFrac.load(std::memory_order_relaxed); + } + std::atomic_thread_fence(std::memory_order_acquire); + } while(refcount != device->MixCount.load(std::memory_order_relaxed)); + + ALdouble offset{0.0}; + if(voice) + { + const ALbufferlistitem *BufferList{Source->queue}; + const ALbuffer *BufferFmt{nullptr}; + while(BufferList && BufferList != Current) + { + for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i) + BufferFmt = BufferList->buffers[i]; + readPos += int64_t{BufferList->max_samples} << FRACTIONBITS; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + + while(BufferList && !BufferFmt) + { + for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i) + BufferFmt = BufferList->buffers[i]; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + assert(BufferFmt != nullptr); + + offset = static_cast(readPos) / static_castFRACTIONONE / + static_cast(BufferFmt->Frequency); + } + + return offset; +} + +/* GetSourceOffset + * + * Gets the current read offset for the given Source, in the appropriate format + * (Bytes, Samples or Seconds). The offset is relative to the start of the + * queue (not the start of the current buffer). + */ +ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) +{ + ALCdevice *device{context->Device}; + const ALbufferlistitem *Current; + ALuint readPos; + ALsizei readPosFrac; + ALuint refcount; + ALvoice *voice; + + do { + Current = nullptr; + readPos = readPosFrac = 0; + while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) + std::this_thread::yield(); + voice = GetSourceVoice(Source, context); + if(voice) + { + Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); + + readPos = voice->mPosition.load(std::memory_order_relaxed); + readPosFrac = voice->mPositionFrac.load(std::memory_order_relaxed); + } + std::atomic_thread_fence(std::memory_order_acquire); + } while(refcount != device->MixCount.load(std::memory_order_relaxed)); + + ALdouble offset{0.0}; + if(voice) + { + const ALbufferlistitem *BufferList{Source->queue}; + const ALbuffer *BufferFmt{nullptr}; + ALboolean readFin{AL_FALSE}; + ALuint totalBufferLen{0u}; + + while(BufferList) + { + for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i) + BufferFmt = BufferList->buffers[i]; + + readFin |= (BufferList == Current); + totalBufferLen += BufferList->max_samples; + if(!readFin) readPos += BufferList->max_samples; + + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + assert(BufferFmt != nullptr); + + if(Source->Looping) + readPos %= totalBufferLen; + else + { + /* Wrap back to 0 */ + if(readPos >= totalBufferLen) + readPos = readPosFrac = 0; + } + + offset = 0.0; + switch(name) + { + case AL_SEC_OFFSET: + offset = (readPos + static_cast(readPosFrac)/FRACTIONONE) / BufferFmt->Frequency; + break; + + case AL_SAMPLE_OFFSET: + offset = readPos + static_cast(readPosFrac)/FRACTIONONE; + break; + + case AL_BYTE_OFFSET: + if(BufferFmt->OriginalType == UserFmtIMA4) + { + ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; + ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->mFmtChannels); + ALuint FrameBlockSize = BufferFmt->OriginalAlign; + + /* Round down to nearest ADPCM block */ + offset = static_cast(readPos / FrameBlockSize * BlockSize); + } + else if(BufferFmt->OriginalType == UserFmtMSADPCM) + { + ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; + ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->mFmtChannels); + ALuint FrameBlockSize = BufferFmt->OriginalAlign; + + /* Round down to nearest ADPCM block */ + offset = static_cast(readPos / FrameBlockSize * BlockSize); + } + else + { + const ALsizei FrameSize{FrameSizeFromFmt(BufferFmt->mFmtChannels, + BufferFmt->mFmtType)}; + offset = static_cast(readPos * FrameSize); + } + break; + } + } + + return offset; +} + + +/* GetSampleOffset + * + * Retrieves the sample offset into the Source's queue (from the Sample, Byte + * or Second offset supplied by the application). This takes into account the + * fact that the buffer format may have been modifed since. + */ +ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac) +{ + const ALbuffer *BufferFmt{nullptr}; + const ALbufferlistitem *BufferList; + + /* Find the first valid Buffer in the Queue */ + BufferList = Source->queue; + while(BufferList) + { + for(ALsizei i{0};i < BufferList->num_buffers && !BufferFmt;i++) + BufferFmt = BufferList->buffers[i]; + if(BufferFmt) break; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + if(!BufferFmt) + { + Source->OffsetType = AL_NONE; + Source->Offset = 0.0; + return AL_FALSE; + } + + ALdouble dbloff, dblfrac; + switch(Source->OffsetType) + { + case AL_BYTE_OFFSET: + /* Determine the ByteOffset (and ensure it is block aligned) */ + *offset = static_cast(Source->Offset); + if(BufferFmt->OriginalType == UserFmtIMA4) + { + ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; + *offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels); + *offset *= BufferFmt->OriginalAlign; + } + else if(BufferFmt->OriginalType == UserFmtMSADPCM) + { + ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; + *offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels); + *offset *= BufferFmt->OriginalAlign; + } + else + *offset /= FrameSizeFromFmt(BufferFmt->mFmtChannels, BufferFmt->mFmtType); + *frac = 0; + break; + + case AL_SAMPLE_OFFSET: + dblfrac = modf(Source->Offset, &dbloff); + *offset = static_cast(mind(dbloff, std::numeric_limits::max())); + *frac = static_cast(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0)); + break; + + case AL_SEC_OFFSET: + dblfrac = modf(Source->Offset*BufferFmt->Frequency, &dbloff); + *offset = static_cast(mind(dbloff, std::numeric_limits::max())); + *frac = static_cast(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0)); + break; + } + Source->OffsetType = AL_NONE; + Source->Offset = 0.0; + + return AL_TRUE; +} + +/* ApplyOffset + * + * Apply the stored playback offset to the Source. This function will update + * the number of buffers "played" given the stored offset. + */ +ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) +{ + /* Get sample frame offset */ + ALuint offset{0u}; + ALsizei frac{0}; + if(!GetSampleOffset(Source, &offset, &frac)) + return AL_FALSE; + + ALuint totalBufferLen{0u}; + ALbufferlistitem *BufferList{Source->queue}; + while(BufferList && totalBufferLen <= offset) + { + if(static_cast(BufferList->max_samples) > offset-totalBufferLen) + { + /* Offset is in this buffer */ + voice->mPosition.store(offset - totalBufferLen, std::memory_order_relaxed); + voice->mPositionFrac.store(frac, std::memory_order_relaxed); + voice->mCurrentBuffer.store(BufferList, std::memory_order_release); + return AL_TRUE; + } + totalBufferLen += BufferList->max_samples; + + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + + /* Offset is out of range of the queue */ + return AL_FALSE; +} + + +ALsource *AllocSource(ALCcontext *context) +{ + ALCdevice *device{context->Device}; + std::lock_guard _{context->SourceLock}; + if(context->NumSources >= device->SourcesMax) + { + alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax); + return nullptr; + } + auto sublist = std::find_if(context->SourceList.begin(), context->SourceList.end(), + [](const SourceSubList &entry) noexcept -> bool + { return entry.FreeMask != 0; } + ); + auto lidx = static_cast(std::distance(context->SourceList.begin(), sublist)); + ALsource *source; + ALsizei slidx; + if(LIKELY(sublist != context->SourceList.end())) + { + slidx = CTZ64(sublist->FreeMask); + source = sublist->Sources + slidx; + } + else + { + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(context->SourceList.size() >= 1<<25)) + { + alSetError(context, AL_OUT_OF_MEMORY, "Too many sources allocated"); + return nullptr; + } + context->SourceList.emplace_back(); + sublist = context->SourceList.end() - 1; + + sublist->FreeMask = ~0_u64; + sublist->Sources = static_cast(al_calloc(16, sizeof(ALsource)*64)); + if(UNLIKELY(!sublist->Sources)) + { + context->SourceList.pop_back(); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate source batch"); + return nullptr; + } + + slidx = 0; + source = sublist->Sources + slidx; + } + + source = new (source) ALsource{device->NumAuxSends}; + + /* Add 1 to avoid source ID 0. */ + source->id = ((lidx<<6) | slidx) + 1; + + context->NumSources += 1; + sublist->FreeMask &= ~(1_u64 << slidx); + + return source; +} + +void FreeSource(ALCcontext *context, ALsource *source) +{ + ALuint id = source->id - 1; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; + + ALCdevice *device{context->Device}; + BackendUniqueLock backlock{*device->Backend}; + if(ALvoice *voice{GetSourceVoice(source, context)}) + { + voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed); + voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); + voice->mSourceID.store(0u, std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_release); + /* Don't set the voice to stopping if it was already stopped or + * stopping. + */ + ALvoice::State oldvstate{ALvoice::Playing}; + voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping, + std::memory_order_acq_rel, std::memory_order_acquire); + } + backlock.unlock(); + + al::destroy_at(source); + + context->SourceList[lidx].FreeMask |= 1_u64 << slidx; + context->NumSources--; +} + + +inline ALsource *LookupSource(ALCcontext *context, ALuint id) noexcept +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= context->SourceList.size())) + return nullptr; + SourceSubList &sublist{context->SourceList[lidx]}; + if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + return nullptr; + return sublist.Sources + slidx; +} + +inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) noexcept +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= device->BufferList.size())) + return nullptr; + BufferSubList &sublist = device->BufferList[lidx]; + if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + return nullptr; + return sublist.Buffers + slidx; +} + +inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) noexcept +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= device->FilterList.size())) + return nullptr; + FilterSubList &sublist = device->FilterList[lidx]; + if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + return nullptr; + return sublist.Filters + slidx; +} + +inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= context->EffectSlotList.size())) + return nullptr; + EffectSlotSubList &sublist{context->EffectSlotList[lidx]}; + if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + return nullptr; + return sublist.EffectSlots + slidx; +} + + +enum SourceProp : ALenum { + srcPitch = AL_PITCH, + srcGain = AL_GAIN, + srcMinGain = AL_MIN_GAIN, + srcMaxGain = AL_MAX_GAIN, + srcMaxDistance = AL_MAX_DISTANCE, + srcRolloffFactor = AL_ROLLOFF_FACTOR, + srcDopplerFactor = AL_DOPPLER_FACTOR, + srcConeOuterGain = AL_CONE_OUTER_GAIN, + srcSecOffset = AL_SEC_OFFSET, + srcSampleOffset = AL_SAMPLE_OFFSET, + srcByteOffset = AL_BYTE_OFFSET, + srcConeInnerAngle = AL_CONE_INNER_ANGLE, + srcConeOuterAngle = AL_CONE_OUTER_ANGLE, + srcRefDistance = AL_REFERENCE_DISTANCE, + + srcPosition = AL_POSITION, + srcVelocity = AL_VELOCITY, + srcDirection = AL_DIRECTION, + + srcSourceRelative = AL_SOURCE_RELATIVE, + srcLooping = AL_LOOPING, + srcBuffer = AL_BUFFER, + srcSourceState = AL_SOURCE_STATE, + srcBuffersQueued = AL_BUFFERS_QUEUED, + srcBuffersProcessed = AL_BUFFERS_PROCESSED, + srcSourceType = AL_SOURCE_TYPE, + + /* ALC_EXT_EFX */ + srcConeOuterGainHF = AL_CONE_OUTER_GAINHF, + srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR, + srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR, + srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO, + srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, + srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, + srcDirectFilter = AL_DIRECT_FILTER, + srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER, + + /* AL_SOFT_direct_channels */ + srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT, + + /* AL_EXT_source_distance_model */ + srcDistanceModel = AL_DISTANCE_MODEL, + + /* AL_SOFT_source_latency */ + srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT, + srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT, + + /* AL_EXT_STEREO_ANGLES */ + srcAngles = AL_STEREO_ANGLES, + + /* AL_EXT_SOURCE_RADIUS */ + srcRadius = AL_SOURCE_RADIUS, + + /* AL_EXT_BFORMAT */ + srcOrientation = AL_ORIENTATION, + + /* AL_SOFT_source_resampler */ + srcResampler = AL_SOURCE_RESAMPLER_SOFT, + + /* AL_SOFT_source_spatialize */ + srcSpatialize = AL_SOURCE_SPATIALIZE_SOFT, + + /* ALC_SOFT_device_clock */ + srcSampleOffsetClockSOFT = AL_SAMPLE_OFFSET_CLOCK_SOFT, + srcSecOffsetClockSOFT = AL_SEC_OFFSET_CLOCK_SOFT, +}; + +/** + * Returns if the last known state for the source was playing or paused. Does + * not sync with the mixer voice. + */ +inline bool IsPlayingOrPaused(ALsource *source) +{ return source->state == AL_PLAYING || source->state == AL_PAUSED; } + +/** + * Returns an updated source state using the matching voice's status (or lack + * thereof). + */ +inline ALenum GetSourceState(ALsource *source, ALvoice *voice) +{ + if(!voice && source->state == AL_PLAYING) + source->state = AL_STOPPED; + return source->state; +} + +/** + * Returns if the source should specify an update, given the context's + * deferring state and the source's last known state. + */ +inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context) +{ + return !context->DeferUpdates.load(std::memory_order_acquire) && + IsPlayingOrPaused(source); +} + + +/** Can only be called while the mixer is locked! */ +void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) +{ + ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)}; + if(!(enabledevt&EventType_SourceStateChange)) return; + + /* The mixer may have queued a state change that's not yet been processed, + * and we don't want state change messages to occur out of order, so send + * it through the async queue to ensure proper ordering. + */ + RingBuffer *ring{context->AsyncEvents.get()}; + auto evt_vec = ring->getWriteVector(); + if(evt_vec.first.len < 1) return; + + AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_SourceStateChange}}; + evt->u.srcstate.id = id; + evt->u.srcstate.state = state; + ring->writeAdvance(1); + context->EventSem.post(); +} + + +ALint FloatValsByProp(ALenum prop) +{ + switch(static_cast(prop)) + { + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_SOURCE_RADIUS: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + return 1; + + case AL_STEREO_ANGLES: + return 2; + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + return 3; + + case AL_ORIENTATION: + return 6; + + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + break; /* Double only */ + + case AL_BUFFER: + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + break; /* i/i64 only */ + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; /* i64 only */ + } + return 0; +} +ALint DoubleValsByProp(ALenum prop) +{ + switch(static_cast(prop)) + { + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_SOURCE_RADIUS: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + return 1; + + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + case AL_STEREO_ANGLES: + return 2; + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + return 3; + + case AL_ORIENTATION: + return 6; + + case AL_BUFFER: + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + break; /* i/i64 only */ + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; /* i64 only */ + } + return 0; +} + +ALint IntValsByProp(ALenum prop) +{ + switch(static_cast(prop)) + { + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_BUFFER: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_DIRECT_FILTER: + case AL_SOURCE_RADIUS: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + return 1; + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + case AL_AUXILIARY_SEND_FILTER: + return 3; + + case AL_ORIENTATION: + return 6; + + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; /* i64 only */ + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + break; /* Double only */ + case AL_STEREO_ANGLES: + break; /* Float/double only */ + } + return 0; +} +ALint Int64ValsByProp(ALenum prop) +{ + switch(static_cast(prop)) + { + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_BUFFER: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_DIRECT_FILTER: + case AL_SOURCE_RADIUS: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + return 1; + + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + return 2; + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + case AL_AUXILIARY_SEND_FILTER: + return 3; + + case AL_ORIENTATION: + return 6; + + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + break; /* Double only */ + case AL_STEREO_ANGLES: + break; /* Float/double only */ + } + return 0; +} + + +ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values); +ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values); +ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values); + +#define CHECKVAL(x) do { \ + if(!(x)) \ + { \ + alSetError(Context, AL_INVALID_VALUE, "Value out of range"); \ + return AL_FALSE; \ + } \ +} while(0) + +void UpdateSourceProps(ALsource *source, ALCcontext *context) +{ + ALvoice *voice; + if(SourceShouldUpdate(source, context) && (voice=GetSourceVoice(source, context)) != nullptr) + UpdateSourceProps(source, voice, context); + else + source->PropsClean.clear(std::memory_order_release); +} + +ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values) +{ + ALint ival; + + switch(prop) + { + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + /* Query only */ + SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, + "Setting read-only source property 0x%04x", prop); + + case AL_PITCH: + CHECKVAL(*values >= 0.0f); + + Source->Pitch = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_CONE_INNER_ANGLE: + CHECKVAL(*values >= 0.0f && *values <= 360.0f); + + Source->InnerAngle = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_CONE_OUTER_ANGLE: + CHECKVAL(*values >= 0.0f && *values <= 360.0f); + + Source->OuterAngle = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_GAIN: + CHECKVAL(*values >= 0.0f); + + Source->Gain = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_MAX_DISTANCE: + CHECKVAL(*values >= 0.0f); + + Source->MaxDistance = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_ROLLOFF_FACTOR: + CHECKVAL(*values >= 0.0f); + + Source->RolloffFactor = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_REFERENCE_DISTANCE: + CHECKVAL(*values >= 0.0f); + + Source->RefDistance = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_MIN_GAIN: + CHECKVAL(*values >= 0.0f); + + Source->MinGain = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_MAX_GAIN: + CHECKVAL(*values >= 0.0f); + + Source->MaxGain = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_CONE_OUTER_GAIN: + CHECKVAL(*values >= 0.0f && *values <= 1.0f); + + Source->OuterGain = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_CONE_OUTER_GAINHF: + CHECKVAL(*values >= 0.0f && *values <= 1.0f); + + Source->OuterGainHF = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_AIR_ABSORPTION_FACTOR: + CHECKVAL(*values >= 0.0f && *values <= 10.0f); + + Source->AirAbsorptionFactor = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_ROOM_ROLLOFF_FACTOR: + CHECKVAL(*values >= 0.0f && *values <= 10.0f); + + Source->RoomRolloffFactor = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_DOPPLER_FACTOR: + CHECKVAL(*values >= 0.0f && *values <= 1.0f); + + Source->DopplerFactor = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + CHECKVAL(*values >= 0.0f); + + Source->OffsetType = prop; + Source->Offset = *values; + + if(IsPlayingOrPaused(Source)) + { + ALCdevice *device{Context->Device}; + BackendLockGuard _{*device->Backend}; + /* Double-check that the source is still playing while we have + * the lock. + */ + if(ALvoice *voice{GetSourceVoice(Source, Context)}) + { + if(ApplyOffset(Source, voice) == AL_FALSE) + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid offset"); + } + } + return AL_TRUE; + + case AL_SOURCE_RADIUS: + CHECKVAL(*values >= 0.0f && std::isfinite(*values)); + + Source->Radius = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_STEREO_ANGLES: + CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1])); + + Source->StereoPan[0] = values[0]; + Source->StereoPan[1] = values[1]; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + + case AL_POSITION: + CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); + + Source->Position[0] = values[0]; + Source->Position[1] = values[1]; + Source->Position[2] = values[2]; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_VELOCITY: + CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); + + Source->Velocity[0] = values[0]; + Source->Velocity[1] = values[1]; + Source->Velocity[2] = values[2]; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_DIRECTION: + CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); + + Source->Direction[0] = values[0]; + Source->Direction[1] = values[1]; + Source->Direction[2] = values[2]; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_ORIENTATION: + CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) && + std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5])); + + Source->OrientAt[0] = values[0]; + Source->OrientAt[1] = values[1]; + Source->OrientAt[2] = values[2]; + Source->OrientUp[0] = values[3]; + Source->OrientUp[1] = values[4]; + Source->OrientUp[2] = values[5]; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_SOURCE_TYPE: + case AL_DISTANCE_MODEL: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + ival = static_cast(values[0]); + return SetSourceiv(Source, Context, prop, &ival); + + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + ival = static_cast(static_cast(values[0])); + return SetSourceiv(Source, Context, prop, &ival); + + case AL_BUFFER: + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; + } + + ERR("Unexpected property: 0x%04x\n", prop); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source float property 0x%04x", prop); +} + +ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values) +{ + ALCdevice *device{Context->Device}; + ALbuffer *buffer{nullptr}; + ALfilter *filter{nullptr}; + ALeffectslot *slot{nullptr}; + ALbufferlistitem *oldlist{nullptr}; + std::unique_lock slotlock; + std::unique_lock filtlock; + std::unique_lock buflock; + ALfloat fvals[6]; + + switch(prop) + { + case AL_SOURCE_STATE: + case AL_SOURCE_TYPE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + /* Query only */ + SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, + "Setting read-only source property 0x%04x", prop); + + case AL_SOURCE_RELATIVE: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->HeadRelative = static_cast(*values); + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_LOOPING: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->Looping = static_cast(*values); + if(IsPlayingOrPaused(Source)) + { + ALvoice *voice{GetSourceVoice(Source, Context)}; + if(voice) + { + if(Source->Looping) + voice->mLoopBuffer.store(Source->queue, std::memory_order_release); + else + voice->mLoopBuffer.store(nullptr, std::memory_order_release); + + /* If the source is playing, wait for the current mix to finish + * to ensure it isn't currently looping back or reaching the + * end. + */ + while((device->MixCount.load(std::memory_order_acquire)&1)) + std::this_thread::yield(); + } + } + return AL_TRUE; + + case AL_BUFFER: + buflock = std::unique_lock{device->BufferLock}; + if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != nullptr)) + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid buffer ID %u", + *values); + + if(buffer && buffer->MappedAccess != 0 && + !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) + SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, + "Setting non-persistently mapped buffer %u", buffer->id); + else + { + ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context)); + if(state == AL_PLAYING || state == AL_PAUSED) + SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, + "Setting buffer on playing or paused source %u", Source->id); + } + + oldlist = Source->queue; + if(buffer != nullptr) + { + /* Add the selected buffer to a one-item queue */ + auto newlist = static_cast(al_calloc(alignof(void*), + ALbufferlistitem::Sizeof(1u))); + newlist->next.store(nullptr, std::memory_order_relaxed); + newlist->max_samples = buffer->SampleLen; + newlist->num_buffers = 1; + newlist->buffers[0] = buffer; + IncrementRef(&buffer->ref); + + /* Source is now Static */ + Source->SourceType = AL_STATIC; + Source->queue = newlist; + } + else + { + /* Source is now Undetermined */ + Source->SourceType = AL_UNDETERMINED; + Source->queue = nullptr; + } + buflock.unlock(); + + /* Delete all elements in the previous queue */ + while(oldlist != nullptr) + { + ALbufferlistitem *temp{oldlist}; + oldlist = temp->next.load(std::memory_order_relaxed); + + for(ALsizei i{0};i < temp->num_buffers;i++) + { + if(temp->buffers[i]) + DecrementRef(&temp->buffers[i]->ref); + } + al_free(temp); + } + return AL_TRUE; + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + CHECKVAL(*values >= 0); + + Source->OffsetType = prop; + Source->Offset = *values; + + if(IsPlayingOrPaused(Source)) + { + ALCdevice *device{Context->Device}; + BackendLockGuard _{*device->Backend}; + if(ALvoice *voice{GetSourceVoice(Source, Context)}) + { + if(ApplyOffset(Source, voice) == AL_FALSE) + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, + "Invalid source offset"); + } + } + return AL_TRUE; + + case AL_DIRECT_FILTER: + filtlock = std::unique_lock{device->FilterLock}; + if(!(*values == 0 || (filter=LookupFilter(device, *values)) != nullptr)) + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", + *values); + + if(!filter) + { + Source->Direct.Gain = 1.0f; + Source->Direct.GainHF = 1.0f; + Source->Direct.HFReference = LOWPASSFREQREF; + Source->Direct.GainLF = 1.0f; + Source->Direct.LFReference = HIGHPASSFREQREF; + } + else + { + Source->Direct.Gain = filter->Gain; + Source->Direct.GainHF = filter->GainHF; + Source->Direct.HFReference = filter->HFReference; + Source->Direct.GainLF = filter->GainLF; + Source->Direct.LFReference = filter->LFReference; + } + filtlock.unlock(); + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_DIRECT_FILTER_GAINHF_AUTO: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->DryGainHFAuto = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->WetGainAuto = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->WetGainHFAuto = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_DIRECT_CHANNELS_SOFT: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->DirectChannels = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_DISTANCE_MODEL: + CHECKVAL(*values == AL_NONE || + *values == AL_INVERSE_DISTANCE || + *values == AL_INVERSE_DISTANCE_CLAMPED || + *values == AL_LINEAR_DISTANCE || + *values == AL_LINEAR_DISTANCE_CLAMPED || + *values == AL_EXPONENT_DISTANCE || + *values == AL_EXPONENT_DISTANCE_CLAMPED); + + Source->mDistanceModel = static_cast(*values); + if(Context->SourceDistanceModel) + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_SOURCE_RESAMPLER_SOFT: + CHECKVAL(*values >= 0 && *values <= ResamplerMax); + + Source->mResampler = static_cast(*values); + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_SOURCE_SPATIALIZE_SOFT: + CHECKVAL(*values >= AL_FALSE && *values <= AL_AUTO_SOFT); + + Source->mSpatialize = static_cast(*values); + UpdateSourceProps(Source, Context); + return AL_TRUE; + + + case AL_AUXILIARY_SEND_FILTER: + slotlock = std::unique_lock{Context->EffectSlotLock}; + if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != nullptr)) + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid effect ID %u", + values[0]); + if(static_cast(values[1]) >= static_cast(device->NumAuxSends)) + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid send %u", values[1]); + + filtlock = std::unique_lock{device->FilterLock}; + if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != nullptr)) + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", + values[2]); + + if(!filter) + { + /* Disable filter */ + Source->Send[values[1]].Gain = 1.0f; + Source->Send[values[1]].GainHF = 1.0f; + Source->Send[values[1]].HFReference = LOWPASSFREQREF; + Source->Send[values[1]].GainLF = 1.0f; + Source->Send[values[1]].LFReference = HIGHPASSFREQREF; + } + else + { + Source->Send[values[1]].Gain = filter->Gain; + Source->Send[values[1]].GainHF = filter->GainHF; + Source->Send[values[1]].HFReference = filter->HFReference; + Source->Send[values[1]].GainLF = filter->GainLF; + Source->Send[values[1]].LFReference = filter->LFReference; + } + filtlock.unlock(); + + if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source)) + { + /* Add refcount on the new slot, and release the previous slot */ + if(slot) IncrementRef(&slot->ref); + if(Source->Send[values[1]].Slot) + DecrementRef(&Source->Send[values[1]].Slot->ref); + Source->Send[values[1]].Slot = slot; + + /* We must force an update if the auxiliary slot changed on an + * active source, in case the slot is about to be deleted. + */ + ALvoice *voice{GetSourceVoice(Source, Context)}; + if(voice) UpdateSourceProps(Source, voice, Context); + else Source->PropsClean.clear(std::memory_order_release); + } + else + { + if(slot) IncrementRef(&slot->ref); + if(Source->Send[values[1]].Slot) + DecrementRef(&Source->Send[values[1]].Slot->ref); + Source->Send[values[1]].Slot = slot; + UpdateSourceProps(Source, Context); + } + + return AL_TRUE; + + + /* 1x float */ + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_REFERENCE_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_SOURCE_RADIUS: + fvals[0] = static_cast(*values); + return SetSourcefv(Source, Context, prop, fvals); + + /* 3x float */ + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + fvals[0] = static_cast(values[0]); + fvals[1] = static_cast(values[1]); + fvals[2] = static_cast(values[2]); + return SetSourcefv(Source, Context, prop, fvals); + + /* 6x float */ + case AL_ORIENTATION: + fvals[0] = static_cast(values[0]); + fvals[1] = static_cast(values[1]); + fvals[2] = static_cast(values[2]); + fvals[3] = static_cast(values[3]); + fvals[4] = static_cast(values[4]); + fvals[5] = static_cast(values[5]); + return SetSourcefv(Source, Context, prop, fvals); + + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + case AL_STEREO_ANGLES: + break; + } + + ERR("Unexpected property: 0x%04x\n", prop); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x", + prop); +} + +ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values) +{ + ALfloat fvals[6]; + ALint ivals[3]; + + switch(prop) + { + case AL_SOURCE_TYPE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_STATE: + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + /* Query only */ + SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, + "Setting read-only source property 0x%04x", prop); + + /* 1x int */ + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + CHECKVAL(*values <= INT_MAX && *values >= INT_MIN); + + ivals[0] = static_cast(*values); + return SetSourceiv(Source, Context, prop, ivals); + + /* 1x uint */ + case AL_BUFFER: + case AL_DIRECT_FILTER: + CHECKVAL(*values <= UINT_MAX && *values >= 0); + + ivals[0] = static_cast(*values); + return SetSourceiv(Source, Context, prop, ivals); + + /* 3x uint */ + case AL_AUXILIARY_SEND_FILTER: + CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 && + values[1] <= UINT_MAX && values[1] >= 0 && + values[2] <= UINT_MAX && values[2] >= 0); + + ivals[0] = static_cast(values[0]); + ivals[1] = static_cast(values[1]); + ivals[2] = static_cast(values[2]); + return SetSourceiv(Source, Context, prop, ivals); + + /* 1x float */ + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_REFERENCE_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_SOURCE_RADIUS: + fvals[0] = static_cast(*values); + return SetSourcefv(Source, Context, prop, fvals); + + /* 3x float */ + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + fvals[0] = static_cast(values[0]); + fvals[1] = static_cast(values[1]); + fvals[2] = static_cast(values[2]); + return SetSourcefv(Source, Context, prop, fvals); + + /* 6x float */ + case AL_ORIENTATION: + fvals[0] = static_cast(values[0]); + fvals[1] = static_cast(values[1]); + fvals[2] = static_cast(values[2]); + fvals[3] = static_cast(values[3]); + fvals[4] = static_cast(values[4]); + fvals[5] = static_cast(values[5]); + return SetSourcefv(Source, Context, prop, fvals); + + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + case AL_STEREO_ANGLES: + break; + } + + ERR("Unexpected property: 0x%04x\n", prop); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x", + prop); +} + +#undef CHECKVAL + + +ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values); +ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values); +ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64SOFT *values); + +ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values) +{ + ALCdevice *device{Context->Device}; + ClockLatency clocktime; + std::chrono::nanoseconds srcclock; + ALint ivals[3]; + ALboolean err; + + switch(prop) + { + case AL_GAIN: + *values = Source->Gain; + return AL_TRUE; + + case AL_PITCH: + *values = Source->Pitch; + return AL_TRUE; + + case AL_MAX_DISTANCE: + *values = Source->MaxDistance; + return AL_TRUE; + + case AL_ROLLOFF_FACTOR: + *values = Source->RolloffFactor; + return AL_TRUE; + + case AL_REFERENCE_DISTANCE: + *values = Source->RefDistance; + return AL_TRUE; + + case AL_CONE_INNER_ANGLE: + *values = Source->InnerAngle; + return AL_TRUE; + + case AL_CONE_OUTER_ANGLE: + *values = Source->OuterAngle; + return AL_TRUE; + + case AL_MIN_GAIN: + *values = Source->MinGain; + return AL_TRUE; + + case AL_MAX_GAIN: + *values = Source->MaxGain; + return AL_TRUE; + + case AL_CONE_OUTER_GAIN: + *values = Source->OuterGain; + return AL_TRUE; + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + *values = GetSourceOffset(Source, prop, Context); + return AL_TRUE; + + case AL_CONE_OUTER_GAINHF: + *values = Source->OuterGainHF; + return AL_TRUE; + + case AL_AIR_ABSORPTION_FACTOR: + *values = Source->AirAbsorptionFactor; + return AL_TRUE; + + case AL_ROOM_ROLLOFF_FACTOR: + *values = Source->RoomRolloffFactor; + return AL_TRUE; + + case AL_DOPPLER_FACTOR: + *values = Source->DopplerFactor; + return AL_TRUE; + + case AL_SOURCE_RADIUS: + *values = Source->Radius; + return AL_TRUE; + + case AL_STEREO_ANGLES: + values[0] = Source->StereoPan[0]; + values[1] = Source->StereoPan[1]; + return AL_TRUE; + + case AL_SEC_OFFSET_LATENCY_SOFT: + /* Get the source offset with the clock time first. Then get the + * clock time with the device latency. Order is important. + */ + values[0] = GetSourceSecOffset(Source, Context, &srcclock); + { std::lock_guard _{device->StateLock}; + clocktime = GetClockLatency(device); + } + if(srcclock == clocktime.ClockTime) + values[1] = static_cast(clocktime.Latency.count()) / 1000000000.0; + else + { + /* If the clock time incremented, reduce the latency by that + * much since it's that much closer to the source offset it got + * earlier. + */ + std::chrono::nanoseconds diff = clocktime.ClockTime - srcclock; + values[1] = static_cast((clocktime.Latency - std::min(clocktime.Latency, diff)).count()) / + 1000000000.0; + } + return AL_TRUE; + + case AL_SEC_OFFSET_CLOCK_SOFT: + values[0] = GetSourceSecOffset(Source, Context, &srcclock); + values[1] = srcclock.count() / 1000000000.0; + return AL_TRUE; + + case AL_POSITION: + values[0] = Source->Position[0]; + values[1] = Source->Position[1]; + values[2] = Source->Position[2]; + return AL_TRUE; + + case AL_VELOCITY: + values[0] = Source->Velocity[0]; + values[1] = Source->Velocity[1]; + values[2] = Source->Velocity[2]; + return AL_TRUE; + + case AL_DIRECTION: + values[0] = Source->Direction[0]; + values[1] = Source->Direction[1]; + values[2] = Source->Direction[2]; + return AL_TRUE; + + case AL_ORIENTATION: + values[0] = Source->OrientAt[0]; + values[1] = Source->OrientAt[1]; + values[2] = Source->OrientAt[2]; + values[3] = Source->OrientUp[0]; + values[4] = Source->OrientUp[1]; + values[5] = Source->OrientUp[2]; + return AL_TRUE; + + /* 1x int */ + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) + *values = static_cast(ivals[0]); + return err; + + case AL_BUFFER: + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; + } + + ERR("Unexpected property: 0x%04x\n", prop); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source double property 0x%04x", + prop); +} + +ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values) +{ + ALbufferlistitem *BufferList; + ALdouble dvals[6]; + ALboolean err; + + switch(prop) + { + case AL_SOURCE_RELATIVE: + *values = Source->HeadRelative; + return AL_TRUE; + + case AL_LOOPING: + *values = Source->Looping; + return AL_TRUE; + + case AL_BUFFER: + BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : nullptr; + *values = (BufferList && BufferList->num_buffers >= 1 && BufferList->buffers[0]) ? + BufferList->buffers[0]->id : 0; + return AL_TRUE; + + case AL_SOURCE_STATE: + *values = GetSourceState(Source, GetSourceVoice(Source, Context)); + return AL_TRUE; + + case AL_BUFFERS_QUEUED: + if(!(BufferList=Source->queue)) + *values = 0; + else + { + ALsizei count = 0; + do { + count += BufferList->num_buffers; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } while(BufferList != nullptr); + *values = count; + } + return AL_TRUE; + + case AL_BUFFERS_PROCESSED: + if(Source->Looping || Source->SourceType != AL_STREAMING) + { + /* Buffers on a looping source are in a perpetual state of + * PENDING, so don't report any as PROCESSED */ + *values = 0; + } + else + { + const ALbufferlistitem *BufferList{Source->queue}; + const ALbufferlistitem *Current{nullptr}; + ALsizei played{0}; + + ALvoice *voice{GetSourceVoice(Source, Context)}; + if(voice != nullptr) + Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); + else if(Source->state == AL_INITIAL) + Current = BufferList; + + while(BufferList && BufferList != Current) + { + played += BufferList->num_buffers; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + *values = played; + } + return AL_TRUE; + + case AL_SOURCE_TYPE: + *values = Source->SourceType; + return AL_TRUE; + + case AL_DIRECT_FILTER_GAINHF_AUTO: + *values = Source->DryGainHFAuto; + return AL_TRUE; + + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + *values = Source->WetGainAuto; + return AL_TRUE; + + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + *values = Source->WetGainHFAuto; + return AL_TRUE; + + case AL_DIRECT_CHANNELS_SOFT: + *values = Source->DirectChannels; + return AL_TRUE; + + case AL_DISTANCE_MODEL: + *values = static_cast(Source->mDistanceModel); + return AL_TRUE; + + case AL_SOURCE_RESAMPLER_SOFT: + *values = Source->mResampler; + return AL_TRUE; + + case AL_SOURCE_SPATIALIZE_SOFT: + *values = Source->mSpatialize; + return AL_TRUE; + + /* 1x float/double */ + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_REFERENCE_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_DOPPLER_FACTOR: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_SOURCE_RADIUS: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + *values = static_cast(dvals[0]); + return err; + + /* 3x float/double */ + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + { + values[0] = static_cast(dvals[0]); + values[1] = static_cast(dvals[1]); + values[2] = static_cast(dvals[2]); + } + return err; + + /* 6x float/double */ + case AL_ORIENTATION: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + { + values[0] = static_cast(dvals[0]); + values[1] = static_cast(dvals[1]); + values[2] = static_cast(dvals[2]); + values[3] = static_cast(dvals[3]); + values[4] = static_cast(dvals[4]); + values[5] = static_cast(dvals[5]); + } + return err; + + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; /* i64 only */ + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + break; /* Double only */ + case AL_STEREO_ANGLES: + break; /* Float/double only */ + + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + break; /* ??? */ + } + + ERR("Unexpected property: 0x%04x\n", prop); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x", + prop); +} + +ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64SOFT *values) +{ + ALCdevice *device = Context->Device; + ClockLatency clocktime; + std::chrono::nanoseconds srcclock; + ALdouble dvals[6]; + ALint ivals[3]; + ALboolean err; + + switch(prop) + { + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + /* Get the source offset with the clock time first. Then get the + * clock time with the device latency. Order is important. + */ + values[0] = GetSourceSampleOffset(Source, Context, &srcclock); + { std::lock_guard _{device->StateLock}; + clocktime = GetClockLatency(device); + } + if(srcclock == clocktime.ClockTime) + values[1] = clocktime.Latency.count(); + else + { + /* If the clock time incremented, reduce the latency by that + * much since it's that much closer to the source offset it got + * earlier. + */ + auto diff = clocktime.ClockTime - srcclock; + values[1] = (clocktime.Latency - std::min(clocktime.Latency, diff)).count(); + } + return AL_TRUE; + + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + values[0] = GetSourceSampleOffset(Source, Context, &srcclock); + values[1] = srcclock.count(); + return AL_TRUE; + + /* 1x float/double */ + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_REFERENCE_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_DOPPLER_FACTOR: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_SOURCE_RADIUS: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + *values = static_cast(dvals[0]); + return err; + + /* 3x float/double */ + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + { + values[0] = static_cast(dvals[0]); + values[1] = static_cast(dvals[1]); + values[2] = static_cast(dvals[2]); + } + return err; + + /* 6x float/double */ + case AL_ORIENTATION: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + { + values[0] = static_cast(dvals[0]); + values[1] = static_cast(dvals[1]); + values[2] = static_cast(dvals[2]); + values[3] = static_cast(dvals[3]); + values[4] = static_cast(dvals[4]); + values[5] = static_cast(dvals[5]); + } + return err; + + /* 1x int */ + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) + *values = ivals[0]; + return err; + + /* 1x uint */ + case AL_BUFFER: + case AL_DIRECT_FILTER: + if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) + *values = static_cast(ivals[0]); + return err; + + /* 3x uint */ + case AL_AUXILIARY_SEND_FILTER: + if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) + { + values[0] = static_cast(ivals[0]); + values[1] = static_cast(ivals[1]); + values[2] = static_cast(ivals[2]); + } + return err; + + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + break; /* Double only */ + case AL_STEREO_ANGLES: + break; /* Float/double only */ + } + + ERR("Unexpected property: 0x%04x\n", prop); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x", + prop); +} + +} // namespace + +AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(n < 0) + alSetError(context.get(), AL_INVALID_VALUE, "Generating %d sources", n); + else if(n == 1) + { + ALsource *source = AllocSource(context.get()); + if(source) sources[0] = source->id; + } + else + { + al::vector tempids(n); + auto alloc_end = std::find_if_not(tempids.begin(), tempids.end(), + [&context](ALuint &id) -> bool + { + ALsource *source{AllocSource(context.get())}; + if(!source) return false; + id = source->id; + return true; + } + ); + if(alloc_end != tempids.end()) + alDeleteSources(static_cast(std::distance(tempids.begin(), alloc_end)), + tempids.data()); + else + std::copy(tempids.cbegin(), tempids.cend(), sources); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(n < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Deleting %d sources", n); + + std::lock_guard _{context->SourceLock}; + + /* Check that all Sources are valid */ + const ALuint *sources_end = sources + n; + auto invsrc = std::find_if_not(sources, sources_end, + [&context](ALuint sid) -> bool + { + if(!LookupSource(context.get(), sid)) + { + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", sid); + return false; + } + return true; + } + ); + if(LIKELY(invsrc == sources_end)) + { + /* All good. Delete source IDs. */ + std::for_each(sources, sources_end, + [&context](ALuint sid) -> void + { + ALsource *src{LookupSource(context.get(), sid)}; + if(src) FreeSource(context.get(), src); + } + ); + } +} +END_API_FUNC + +AL_API ALboolean AL_APIENTRY alIsSource(ALuint source) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(LIKELY(context)) + { + std::lock_guard _{context->SourceLock}; + if(LookupSource(context.get(), source) != nullptr) + return AL_TRUE; + } + return AL_FALSE; +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(FloatValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid float property 0x%04x", param); + else + SetSourcefv(Source, context.get(), static_cast(param), &value); +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(FloatValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); + else + { + ALfloat fvals[3] = { value1, value2, value3 }; + SetSourcefv(Source, context.get(), static_cast(param), fvals); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(FloatValsByProp(param) < 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); + else + SetSourcefv(Source, context.get(), static_cast(param), values); +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(DoubleValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid double property 0x%04x", param); + else + { + ALfloat fval = static_cast(value); + SetSourcefv(Source, context.get(), static_cast(param), &fval); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(DoubleValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); + else { + ALfloat fvals[3] = {static_cast(value1), + static_cast(value2), + static_cast(value3)}; + SetSourcefv(Source, context.get(), static_cast(param), fvals); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else + { + ALint count{DoubleValsByProp(param)}; + if(count < 1 || count > 6) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); + else + { + ALfloat fvals[6]; + ALint i; + + for(i = 0;i < count;i++) + fvals[i] = static_cast(values[i]); + SetSourcefv(Source, context.get(), static_cast(param), fvals); + } + } +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(IntValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); + else + SetSourceiv(Source, context.get(), static_cast(param), &value); +} +END_API_FUNC + +AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(IntValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); + else + { + ALint ivals[3] = { value1, value2, value3 }; + SetSourceiv(Source, context.get(), static_cast(param), ivals); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(IntValsByProp(param) < 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); + else + SetSourceiv(Source, context.get(), static_cast(param), values); +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(Int64ValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); + else + SetSourcei64v(Source, context.get(), static_cast(param), &value); +} +END_API_FUNC + +AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(Int64ValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); + else + { + ALint64SOFT i64vals[3] = { value1, value2, value3 }; + SetSourcei64v(Source, context.get(), static_cast(param), i64vals); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(Int64ValsByProp(param) < 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); + else + SetSourcei64v(Source, context.get(), static_cast(param), values); +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!value) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(FloatValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid float property 0x%04x", param); + else + { + ALdouble dval; + if(GetSourcedv(Source, context.get(), static_cast(param), &dval)) + *value = static_cast(dval); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!(value1 && value2 && value3)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(FloatValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); + else + { + ALdouble dvals[3]; + if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) + { + *value1 = static_cast(dvals[0]); + *value2 = static_cast(dvals[1]); + *value3 = static_cast(dvals[2]); + } + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else + { + ALint count{FloatValsByProp(param)}; + if(count < 1 && count > 6) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); + else + { + ALdouble dvals[6]; + if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) + { + for(ALint i{0};i < count;i++) + values[i] = static_cast(dvals[i]); + } + } + } +} +END_API_FUNC + + +AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!value) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(DoubleValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid double property 0x%04x", param); + else + GetSourcedv(Source, context.get(), static_cast(param), value); +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!(value1 && value2 && value3)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(DoubleValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); + else + { + ALdouble dvals[3]; + if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) + { + *value1 = dvals[0]; + *value2 = dvals[1]; + *value3 = dvals[2]; + } + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(DoubleValsByProp(param) < 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); + else + GetSourcedv(Source, context.get(), static_cast(param), values); +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!value) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(IntValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); + else + GetSourceiv(Source, context.get(), static_cast(param), value); +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!(value1 && value2 && value3)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(IntValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); + else + { + ALint ivals[3]; + if(GetSourceiv(Source, context.get(), static_cast(param), ivals)) + { + *value1 = ivals[0]; + *value2 = ivals[1]; + *value3 = ivals[2]; + } + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(IntValsByProp(param) < 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); + else + GetSourceiv(Source, context.get(), static_cast(param), values); +} +END_API_FUNC + + +AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!value) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(Int64ValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); + else + GetSourcei64v(Source, context.get(), static_cast(param), value); +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!(value1 && value2 && value3)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(Int64ValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); + else + { + ALint64SOFT i64vals[3]; + if(GetSourcei64v(Source, context.get(), static_cast(param), i64vals)) + { + *value1 = i64vals[0]; + *value2 = i64vals[1]; + *value3 = i64vals[2]; + } + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(Int64ValsByProp(param) < 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); + else + GetSourcei64v(Source, context.get(), static_cast(param), values); +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source) +START_API_FUNC +{ alSourcePlayv(1, &source); } +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(n < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Playing %d sources", n); + if(n == 0) return; + + al::vector extra_sources; + std::array source_storage; + ALsource **srchandles{source_storage.data()}; + if(UNLIKELY(static_cast(n) > source_storage.size())) + { + extra_sources.resize(n); + srchandles = extra_sources.data(); + } + + std::lock_guard _{context->SourceLock}; + for(ALsizei i{0};i < n;i++) + { + srchandles[i] = LookupSource(context.get(), sources[i]); + if(!srchandles[i]) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); + } + + ALCdevice *device{context->Device}; + BackendLockGuard __{*device->Backend}; + /* If the device is disconnected, go right to stopped. */ + if(UNLIKELY(!device->Connected.load(std::memory_order_acquire))) + { + /* TODO: Send state change event? */ + std::for_each(srchandles, srchandles+n, + [](ALsource *source) -> void + { + source->OffsetType = AL_NONE; + source->Offset = 0.0; + source->state = AL_STOPPED; + } + ); + return; + } + + /* Count the number of reusable voices. */ + auto voices_end = context->Voices->begin() + + context->VoiceCount.load(std::memory_order_relaxed); + auto free_voices = std::accumulate(context->Voices->begin(), voices_end, ALsizei{0}, + [](const ALsizei count, const ALvoice &voice) noexcept -> ALsizei + { + if(voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && + voice.mSourceID.load(std::memory_order_relaxed) == 0u) + return count + 1; + return count; + } + ); + if(UNLIKELY(n > free_voices)) + { + /* Increment the number of voices to handle the request. */ + const ALuint need_voices{static_cast(n) - free_voices}; + const size_t rem_voices{context->Voices->size() - + context->VoiceCount.load(std::memory_order_relaxed)}; + + if(UNLIKELY(need_voices > rem_voices)) + { + /* Allocate more voices to get enough. */ + const size_t alloc_count{need_voices - rem_voices}; + if(UNLIKELY(context->Voices->size() > std::numeric_limits::max()-alloc_count)) + SETERR_RETURN(context.get(), AL_OUT_OF_MEMORY,, + "Overflow increasing voice count to %zu + %zu", context->Voices->size(), + alloc_count); + + const size_t newcount{context->Voices->size() + alloc_count}; + AllocateVoices(context.get(), newcount); + } + + context->VoiceCount.fetch_add(need_voices, std::memory_order_relaxed); + } + + auto start_source = [&context,device](ALsource *source) -> void + { + /* Check that there is a queue containing at least one valid, non zero + * length buffer. + */ + ALbufferlistitem *BufferList{source->queue}; + while(BufferList && BufferList->max_samples == 0) + BufferList = BufferList->next.load(std::memory_order_relaxed); + + /* If there's nothing to play, go right to stopped. */ + if(UNLIKELY(!BufferList)) + { + /* NOTE: A source without any playable buffers should not have an + * ALvoice since it shouldn't be in a playing or paused state. So + * there's no need to look up its voice and clear the source. + */ + ALenum oldstate{GetSourceState(source, nullptr)}; + source->OffsetType = AL_NONE; + source->Offset = 0.0; + if(oldstate != AL_STOPPED) + { + source->state = AL_STOPPED; + SendStateChangeEvent(context.get(), source->id, AL_STOPPED); + } + return; + } + + ALvoice *voice{GetSourceVoice(source, context.get())}; + switch(GetSourceState(source, voice)) + { + case AL_PLAYING: + assert(voice != nullptr); + /* A source that's already playing is restarted from the beginning. */ + voice->mCurrentBuffer.store(BufferList, std::memory_order_relaxed); + voice->mPosition.store(0u, std::memory_order_relaxed); + voice->mPositionFrac.store(0, std::memory_order_release); + return; + + case AL_PAUSED: + assert(voice != nullptr); + /* A source that's paused simply resumes. */ + voice->mPlayState.store(ALvoice::Playing, std::memory_order_release); + source->state = AL_PLAYING; + SendStateChangeEvent(context.get(), source->id, AL_PLAYING); + return; + + default: + assert(voice == nullptr); + break; + } + + /* Look for an unused voice to play this source with. */ + auto voices_end = context->Voices->begin() + + context->VoiceCount.load(std::memory_order_relaxed); + voice = std::find_if(context->Voices->begin(), voices_end, + [](const ALvoice &voice) noexcept -> bool + { + return voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && + voice.mSourceID.load(std::memory_order_relaxed) == 0u; + } + ); + assert(voice != voices_end); + auto vidx = static_cast(std::distance(context->Voices->begin(), voice)); + voice->mPlayState.store(ALvoice::Stopped, std::memory_order_release); + + source->PropsClean.test_and_set(std::memory_order_acquire); + UpdateSourceProps(source, voice, context.get()); + + /* A source that's not playing or paused has any offset applied when it + * starts playing. + */ + if(source->Looping) + voice->mLoopBuffer.store(source->queue, std::memory_order_relaxed); + else + voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); + voice->mCurrentBuffer.store(BufferList, std::memory_order_relaxed); + voice->mPosition.store(0u, std::memory_order_relaxed); + voice->mPositionFrac.store(0, std::memory_order_relaxed); + bool start_fading{false}; + if(ApplyOffset(source, voice) != AL_FALSE) + start_fading = voice->mPosition.load(std::memory_order_relaxed) != 0 || + voice->mPositionFrac.load(std::memory_order_relaxed) != 0 || + voice->mCurrentBuffer.load(std::memory_order_relaxed) != BufferList; + + auto buffers_end = BufferList->buffers + BufferList->num_buffers; + auto buffer = std::find_if(BufferList->buffers, buffers_end, + std::bind(std::not_equal_to{}, _1, nullptr)); + if(buffer != buffers_end) + { + voice->mFrequency = (*buffer)->Frequency; + voice->mFmtChannels = (*buffer)->mFmtChannels; + voice->mNumChannels = ChannelsFromFmt((*buffer)->mFmtChannels); + voice->mSampleSize = BytesFromFmt((*buffer)->mFmtType); + } + + /* Clear the stepping value so the mixer knows not to mix this until + * the update gets applied. + */ + voice->mStep = 0; + + voice->mFlags = start_fading ? VOICE_IS_FADING : 0; + if(source->SourceType == AL_STATIC) voice->mFlags |= VOICE_IS_STATIC; + + /* Don't need to set the VOICE_IS_AMBISONIC flag if the device is + * mixing in first order. No HF scaling is necessary to mix it. + */ + if((voice->mFmtChannels == FmtBFormat2D || voice->mFmtChannels == FmtBFormat3D) && + device->mAmbiOrder > 1) + { + const int *OrderFromChan; + if(voice->mFmtChannels == FmtBFormat2D) + { + static constexpr int Order2DFromChan[MAX_AMBI2D_CHANNELS]{ + 0, 1,1, 2,2, 3,3 + }; + OrderFromChan = Order2DFromChan; + } + else + { + static constexpr int Order3DFromChan[MAX_AMBI_CHANNELS]{ + 0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3, + }; + OrderFromChan = Order3DFromChan; + } + + BandSplitter splitter{400.0f / static_cast(device->Frequency)}; + + const auto scales = BFormatDec::GetHFOrderScales(1, device->mAmbiOrder); + auto init_ambi = [scales,&OrderFromChan,&splitter](ALvoice::ChannelData &chandata) -> void + { + chandata.mPrevSamples.fill(0.0f); + chandata.mAmbiScale = scales[*(OrderFromChan++)]; + chandata.mAmbiSplitter = splitter; + }; + std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, + init_ambi); + + voice->mFlags |= VOICE_IS_AMBISONIC; + } + else + { + /* Clear previous samples. */ + auto clear_prevs = [](ALvoice::ChannelData &chandata) -> void + { chandata.mPrevSamples.fill(0.0f); }; + std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, + clear_prevs); + } + + auto clear_params = [device](ALvoice::ChannelData &chandata) -> void + { + chandata.mDryParams = DirectParams{}; + std::fill_n(chandata.mWetParams.begin(), device->NumAuxSends, SendParams{}); + }; + std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, + clear_params); + + if(device->AvgSpeakerDist > 0.0f) + { + const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC / + (device->AvgSpeakerDist * device->Frequency)}; + auto init_nfc = [w1](ALvoice::ChannelData &chandata) -> void + { chandata.mDryParams.NFCtrlFilter.init(w1); }; + std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, + init_nfc); + } + + voice->mSourceID.store(source->id, std::memory_order_relaxed); + voice->mPlayState.store(ALvoice::Playing, std::memory_order_release); + source->state = AL_PLAYING; + source->VoiceIdx = vidx; + + SendStateChangeEvent(context.get(), source->id, AL_PLAYING); + }; + std::for_each(srchandles, srchandles+n, start_source); +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source) +START_API_FUNC +{ alSourcePausev(1, &source); } +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(n < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Pausing %d sources", n); + if(n == 0) return; + + al::vector extra_sources; + std::array source_storage; + ALsource **srchandles{source_storage.data()}; + if(UNLIKELY(static_cast(n) > source_storage.size())) + { + extra_sources.resize(n); + srchandles = extra_sources.data(); + } + + std::lock_guard _{context->SourceLock}; + for(ALsizei i{0};i < n;i++) + { + srchandles[i] = LookupSource(context.get(), sources[i]); + if(!srchandles[i]) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); + } + + ALCdevice *device{context->Device}; + BackendLockGuard __{*device->Backend}; + auto pause_source = [&context](ALsource *source) -> void + { + ALvoice *voice{GetSourceVoice(source, context.get())}; + if(voice) + { + std::atomic_thread_fence(std::memory_order_release); + ALvoice::State oldvstate{ALvoice::Playing}; + voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping, + std::memory_order_acq_rel, std::memory_order_acquire); + } + if(GetSourceState(source, voice) == AL_PLAYING) + { + source->state = AL_PAUSED; + SendStateChangeEvent(context.get(), source->id, AL_PAUSED); + } + }; + std::for_each(srchandles, srchandles+n, pause_source); +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source) +START_API_FUNC +{ alSourceStopv(1, &source); } +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(n < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Stopping %d sources", n); + if(n == 0) return; + + al::vector extra_sources; + std::array source_storage; + ALsource **srchandles{source_storage.data()}; + if(UNLIKELY(static_cast(n) > source_storage.size())) + { + extra_sources.resize(n); + srchandles = extra_sources.data(); + } + + std::lock_guard _{context->SourceLock}; + for(ALsizei i{0};i < n;i++) + { + srchandles[i] = LookupSource(context.get(), sources[i]); + if(!srchandles[i]) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); + } + + ALCdevice *device{context->Device}; + BackendLockGuard __{*device->Backend}; + auto stop_source = [&context](ALsource *source) -> void + { + ALvoice *voice{GetSourceVoice(source, context.get())}; + if(voice != nullptr) + { + voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed); + voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); + voice->mSourceID.store(0u, std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_release); + ALvoice::State oldvstate{ALvoice::Playing}; + voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping, + std::memory_order_acq_rel, std::memory_order_acquire); + voice = nullptr; + } + ALenum oldstate{GetSourceState(source, voice)}; + if(oldstate != AL_INITIAL && oldstate != AL_STOPPED) + { + source->state = AL_STOPPED; + SendStateChangeEvent(context.get(), source->id, AL_STOPPED); + } + source->OffsetType = AL_NONE; + source->Offset = 0.0; + }; + std::for_each(srchandles, srchandles+n, stop_source); +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source) +START_API_FUNC +{ alSourceRewindv(1, &source); } +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(n < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Rewinding %d sources", n); + if(n == 0) return; + + al::vector extra_sources; + std::array source_storage; + ALsource **srchandles{source_storage.data()}; + if(UNLIKELY(static_cast(n) > source_storage.size())) + { + extra_sources.resize(n); + srchandles = extra_sources.data(); + } + + std::lock_guard _{context->SourceLock}; + for(ALsizei i{0};i < n;i++) + { + srchandles[i] = LookupSource(context.get(), sources[i]); + if(!srchandles[i]) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); + } + + ALCdevice *device{context->Device}; + BackendLockGuard __{*device->Backend}; + auto rewind_source = [&context](ALsource *source) -> void + { + ALvoice *voice{GetSourceVoice(source, context.get())}; + if(voice != nullptr) + { + voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed); + voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); + voice->mSourceID.store(0u, std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_release); + ALvoice::State oldvstate{ALvoice::Playing}; + voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping, + std::memory_order_acq_rel, std::memory_order_acquire); + voice = nullptr; + } + if(GetSourceState(source, voice) != AL_INITIAL) + { + source->state = AL_INITIAL; + SendStateChangeEvent(context.get(), source->id, AL_INITIAL); + } + source->OffsetType = AL_NONE; + source->Offset = 0.0; + }; + std::for_each(srchandles, srchandles+n, rewind_source); +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(nb < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffers", nb); + if(nb == 0) return; + + std::lock_guard _{context->SourceLock}; + ALsource *source{LookupSource(context.get(),src)}; + if(UNLIKELY(!source)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); + + /* Can't queue on a Static Source */ + if(UNLIKELY(source->SourceType == AL_STATIC)) + SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src); + + /* Check for a valid Buffer, for its frequency and format */ + ALCdevice *device{context->Device}; + ALbuffer *BufferFmt{nullptr}; + ALbufferlistitem *BufferList{source->queue}; + while(BufferList) + { + for(ALsizei i{0};i < BufferList->num_buffers;i++) + { + if((BufferFmt=BufferList->buffers[i]) != nullptr) + break; + } + if(BufferFmt) break; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + + std::unique_lock buflock{device->BufferLock}; + ALbufferlistitem *BufferListStart{nullptr}; + BufferList = nullptr; + for(ALsizei i{0};i < nb;i++) + { + ALbuffer *buffer{nullptr}; + if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr) + { + alSetError(context.get(), AL_INVALID_NAME, "Queueing invalid buffer ID %u", + buffers[i]); + goto buffer_error; + } + + if(!BufferListStart) + { + BufferListStart = static_cast(al_calloc(alignof(void*), + ALbufferlistitem::Sizeof(1u))); + BufferList = BufferListStart; + } + else + { + auto item = static_cast(al_calloc(alignof(void*), + ALbufferlistitem::Sizeof(1u))); + BufferList->next.store(item, std::memory_order_relaxed); + BufferList = item; + } + BufferList->next.store(nullptr, std::memory_order_relaxed); + BufferList->max_samples = buffer ? buffer->SampleLen : 0; + BufferList->num_buffers = 1; + BufferList->buffers[0] = buffer; + if(!buffer) continue; + + IncrementRef(&buffer->ref); + + if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) + { + alSetError(context.get(), AL_INVALID_OPERATION, + "Queueing non-persistently mapped buffer %u", buffer->id); + goto buffer_error; + } + + if(BufferFmt == nullptr) + BufferFmt = buffer; + else if(BufferFmt->Frequency != buffer->Frequency || + BufferFmt->mFmtChannels != buffer->mFmtChannels || + BufferFmt->OriginalType != buffer->OriginalType) + { + alSetError(context.get(), AL_INVALID_OPERATION, + "Queueing buffer with mismatched format"); + + buffer_error: + /* A buffer failed (invalid ID or format), so unlock and release + * each buffer we had. */ + while(BufferListStart) + { + ALbufferlistitem *next = BufferListStart->next.load(std::memory_order_relaxed); + for(i = 0;i < BufferListStart->num_buffers;i++) + { + if((buffer=BufferListStart->buffers[i]) != nullptr) + DecrementRef(&buffer->ref); + } + al_free(BufferListStart); + BufferListStart = next; + } + return; + } + } + /* All buffers good. */ + buflock.unlock(); + + /* Source is now streaming */ + source->SourceType = AL_STREAMING; + + if(!(BufferList=source->queue)) + source->queue = BufferListStart; + else + { + ALbufferlistitem *next; + while((next=BufferList->next.load(std::memory_order_relaxed)) != nullptr) + BufferList = next; + BufferList->next.store(BufferListStart, std::memory_order_release); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(nb < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffer layers", nb); + if(nb == 0) return; + + std::lock_guard _{context->SourceLock}; + ALsource *source{LookupSource(context.get(),src)}; + if(UNLIKELY(!source)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); + + /* Can't queue on a Static Source */ + if(UNLIKELY(source->SourceType == AL_STATIC)) + SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src); + + /* Check for a valid Buffer, for its frequency and format */ + ALCdevice *device{context->Device}; + ALbuffer *BufferFmt{nullptr}; + ALbufferlistitem *BufferList{source->queue}; + while(BufferList) + { + for(ALsizei i{0};i < BufferList->num_buffers;i++) + { + if((BufferFmt=BufferList->buffers[i]) != nullptr) + break; + } + if(BufferFmt) break; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + + std::unique_lock buflock{device->BufferLock}; + auto BufferListStart = static_cast(al_calloc(alignof(void*), + ALbufferlistitem::Sizeof(nb))); + BufferList = BufferListStart; + BufferList->next.store(nullptr, std::memory_order_relaxed); + BufferList->max_samples = 0; + BufferList->num_buffers = 0; + + for(ALsizei i{0};i < nb;i++) + { + ALbuffer *buffer{nullptr}; + if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr) + { + alSetError(context.get(), AL_INVALID_NAME, "Queueing invalid buffer ID %u", + buffers[i]); + goto buffer_error; + } + + BufferList->buffers[BufferList->num_buffers++] = buffer; + if(!buffer) continue; + + IncrementRef(&buffer->ref); + + BufferList->max_samples = maxi(BufferList->max_samples, buffer->SampleLen); + + if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) + { + alSetError(context.get(), AL_INVALID_OPERATION, + "Queueing non-persistently mapped buffer %u", buffer->id); + goto buffer_error; + } + + if(BufferFmt == nullptr) + BufferFmt = buffer; + else if(BufferFmt->Frequency != buffer->Frequency || + BufferFmt->mFmtChannels != buffer->mFmtChannels || + BufferFmt->OriginalType != buffer->OriginalType) + { + alSetError(context.get(), AL_INVALID_OPERATION, + "Queueing buffer with mismatched format"); + + buffer_error: + /* A buffer failed (invalid ID or format), so unlock and release + * each buffer we had. */ + while(BufferListStart) + { + ALbufferlistitem *next{BufferListStart->next.load(std::memory_order_relaxed)}; + for(i = 0;i < BufferListStart->num_buffers;i++) + { + if((buffer=BufferListStart->buffers[i]) != nullptr) + DecrementRef(&buffer->ref); + } + al_free(BufferListStart); + BufferListStart = next; + } + return; + } + } + /* All buffers good. */ + buflock.unlock(); + + /* Source is now streaming */ + source->SourceType = AL_STREAMING; + + if(!(BufferList=source->queue)) + source->queue = BufferListStart; + else + { + ALbufferlistitem *next; + while((next=BufferList->next.load(std::memory_order_relaxed)) != nullptr) + BufferList = next; + BufferList->next.store(BufferListStart, std::memory_order_release); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(nb < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing %d buffers", nb); + if(nb == 0) return; + + std::lock_guard _{context->SourceLock}; + ALsource *source{LookupSource(context.get(),src)}; + if(UNLIKELY(!source)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); + + if(UNLIKELY(source->Looping)) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing from looping source %u", src); + if(UNLIKELY(source->SourceType != AL_STREAMING)) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, + "Unqueueing from a non-streaming source %u", src); + + /* Make sure enough buffers have been processed to unqueue. */ + ALbufferlistitem *BufferList{source->queue}; + ALvoice *voice{GetSourceVoice(source, context.get())}; + ALbufferlistitem *Current{nullptr}; + if(voice) + Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); + else if(source->state == AL_INITIAL) + Current = BufferList; + if(UNLIKELY(BufferList == Current)) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing pending buffers"); + + ALsizei i{BufferList->num_buffers}; + while(i < nb) + { + /* If the next bufferlist to check is NULL or is the current one, it's + * trying to unqueue pending buffers. + */ + ALbufferlistitem *next{BufferList->next.load(std::memory_order_relaxed)}; + if(UNLIKELY(!next) || UNLIKELY(next == Current)) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing pending buffers"); + BufferList = next; + + i += BufferList->num_buffers; + } + + while(nb > 0) + { + ALbufferlistitem *head{source->queue}; + ALbufferlistitem *next{head->next.load(std::memory_order_relaxed)}; + for(i = 0;i < head->num_buffers && nb > 0;i++,nb--) + { + ALbuffer *buffer{head->buffers[i]}; + if(!buffer) + *(buffers++) = 0; + else + { + *(buffers++) = buffer->id; + DecrementRef(&buffer->ref); + } + } + if(i < head->num_buffers) + { + /* This head has some buffers left over, so move them to the front + * and update the sample and buffer count. + */ + ALsizei max_length{0}; + ALsizei j{0}; + while(i < head->num_buffers) + { + ALbuffer *buffer{head->buffers[i++]}; + if(buffer) max_length = maxi(max_length, buffer->SampleLen); + head->buffers[j++] = buffer; + } + head->max_samples = max_length; + head->num_buffers = j; + break; + } + + /* Otherwise, free this item and set the source queue head to the next + * one. + */ + al_free(head); + source->queue = next; + } +} +END_API_FUNC + + +ALsource::ALsource(ALsizei num_sends) +{ + InnerAngle = 360.0f; + OuterAngle = 360.0f; + Pitch = 1.0f; + Position[0] = 0.0f; + Position[1] = 0.0f; + Position[2] = 0.0f; + Velocity[0] = 0.0f; + Velocity[1] = 0.0f; + Velocity[2] = 0.0f; + Direction[0] = 0.0f; + Direction[1] = 0.0f; + Direction[2] = 0.0f; + OrientAt[0] = 0.0f; + OrientAt[1] = 0.0f; + OrientAt[2] = -1.0f; + OrientUp[0] = 0.0f; + OrientUp[1] = 1.0f; + OrientUp[2] = 0.0f; + RefDistance = 1.0f; + MaxDistance = std::numeric_limits::max(); + RolloffFactor = 1.0f; + Gain = 1.0f; + MinGain = 0.0f; + MaxGain = 1.0f; + OuterGain = 0.0f; + OuterGainHF = 1.0f; + + DryGainHFAuto = AL_TRUE; + WetGainAuto = AL_TRUE; + WetGainHFAuto = AL_TRUE; + AirAbsorptionFactor = 0.0f; + RoomRolloffFactor = 0.0f; + DopplerFactor = 1.0f; + HeadRelative = AL_FALSE; + Looping = AL_FALSE; + mDistanceModel = DistanceModel::Default; + mResampler = ResamplerDefault; + DirectChannels = AL_FALSE; + mSpatialize = SpatializeAuto; + + StereoPan[0] = Deg2Rad( 30.0f); + StereoPan[1] = Deg2Rad(-30.0f); + + Radius = 0.0f; + + Direct.Gain = 1.0f; + Direct.GainHF = 1.0f; + Direct.HFReference = LOWPASSFREQREF; + Direct.GainLF = 1.0f; + Direct.LFReference = HIGHPASSFREQREF; + Send.resize(num_sends); + for(auto &send : Send) + { + send.Slot = nullptr; + send.Gain = 1.0f; + send.GainHF = 1.0f; + send.HFReference = LOWPASSFREQREF; + send.GainLF = 1.0f; + send.LFReference = HIGHPASSFREQREF; + } + + Offset = 0.0; + OffsetType = AL_NONE; + SourceType = AL_UNDETERMINED; + state = AL_INITIAL; + + queue = nullptr; + + PropsClean.test_and_set(std::memory_order_relaxed); + + VoiceIdx = -1; +} + +ALsource::~ALsource() +{ + ALbufferlistitem *BufferList{queue}; + while(BufferList != nullptr) + { + ALbufferlistitem *next{BufferList->next.load(std::memory_order_relaxed)}; + for(ALsizei i{0};i < BufferList->num_buffers;i++) + { + if(BufferList->buffers[i]) + DecrementRef(&BufferList->buffers[i]->ref); + } + al_free(BufferList); + BufferList = next; + } + queue = nullptr; + + std::for_each(Send.begin(), Send.end(), + [](ALsource::SendData &send) -> void + { + if(send.Slot) + DecrementRef(&send.Slot->ref); + send.Slot = nullptr; + } + ); +} + +void UpdateAllSourceProps(ALCcontext *context) +{ + auto voices_end = context->Voices->begin() + + context->VoiceCount.load(std::memory_order_relaxed); + std::for_each(context->Voices->begin(), voices_end, + [context](ALvoice &voice) -> void + { + ALuint sid{voice.mSourceID.load(std::memory_order_acquire)}; + ALsource *source = sid ? LookupSource(context, sid) : nullptr; + if(source && !source->PropsClean.test_and_set(std::memory_order_acq_rel)) + UpdateSourceProps(source, &voice, context); + } + ); +} + +SourceSubList::~SourceSubList() +{ + uint64_t usemask{~FreeMask}; + while(usemask) + { + ALsizei idx{CTZ64(usemask)}; + al::destroy_at(Sources+idx); + usemask &= ~(1_u64 << idx); + } + FreeMask = ~usemask; + al_free(Sources); + Sources = nullptr; +} diff --git a/al/alSource.h b/al/alSource.h new file mode 100644 index 00000000..c9892398 --- /dev/null +++ b/al/alSource.h @@ -0,0 +1,131 @@ +#ifndef AL_SOURCE_H +#define AL_SOURCE_H + +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" + +#include "alcontext.h" +#include "alnumeric.h" +#include "alu.h" +#include "vector.h" + +struct ALbuffer; +struct ALeffectslot; + + +#define DEFAULT_SENDS 2 + + +struct ALbufferlistitem { + std::atomic next; + ALsizei max_samples; + ALsizei num_buffers; + ALbuffer *buffers[]; + + static constexpr size_t Sizeof(size_t num_buffers) noexcept + { + return maxz(offsetof(ALbufferlistitem, buffers) + sizeof(ALbuffer*)*num_buffers, + sizeof(ALbufferlistitem)); + } +}; + + +struct ALsource { + /** Source properties. */ + ALfloat Pitch; + ALfloat Gain; + ALfloat OuterGain; + ALfloat MinGain; + ALfloat MaxGain; + ALfloat InnerAngle; + ALfloat OuterAngle; + ALfloat RefDistance; + ALfloat MaxDistance; + ALfloat RolloffFactor; + std::array Position; + std::array Velocity; + std::array Direction; + std::array OrientAt; + std::array OrientUp; + ALboolean HeadRelative; + ALboolean Looping; + DistanceModel mDistanceModel; + Resampler mResampler; + ALboolean DirectChannels; + SpatializeMode mSpatialize; + + ALboolean DryGainHFAuto; + ALboolean WetGainAuto; + ALboolean WetGainHFAuto; + ALfloat OuterGainHF; + + ALfloat AirAbsorptionFactor; + ALfloat RoomRolloffFactor; + ALfloat DopplerFactor; + + /* NOTE: Stereo pan angles are specified in radians, counter-clockwise + * rather than clockwise. + */ + std::array StereoPan; + + ALfloat Radius; + + /** Direct filter and auxiliary send info. */ + struct { + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; + } Direct; + struct SendData { + ALeffectslot *Slot; + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; + }; + al::vector Send; + + /** + * Last user-specified offset, and the offset type (bytes, samples, or + * seconds). + */ + ALdouble Offset; + ALenum OffsetType; + + /** Source type (static, streaming, or undetermined) */ + ALint SourceType; + + /** Source state (initial, playing, paused, or stopped) */ + ALenum state; + + /** Source Buffer Queue head. */ + ALbufferlistitem *queue; + + std::atomic_flag PropsClean; + + /* Index into the context's Voices array. Lazily updated, only checked and + * reset when looking up the voice. + */ + ALint VoiceIdx; + + /** Self ID */ + ALuint id; + + + ALsource(ALsizei num_sends); + ~ALsource(); + + ALsource(const ALsource&) = delete; + ALsource& operator=(const ALsource&) = delete; +}; + +void UpdateAllSourceProps(ALCcontext *context); + +#endif diff --git a/al/alState.cpp b/al/alState.cpp new file mode 100644 index 00000000..ee8d3a1c --- /dev/null +++ b/al/alState.cpp @@ -0,0 +1,859 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2000 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "version.h" + +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" + +#include "alError.h" +#include "alcmain.h" +#include "alcontext.h" +#include "alexcpt.h" +#include "almalloc.h" +#include "alspan.h" +#include "alu.h" +#include "atomic.h" +#include "inprogext.h" +#include "opthelpers.h" + + +namespace { + +constexpr ALchar alVendor[] = "OpenAL Community"; +constexpr ALchar alVersion[] = "1.1 ALSOFT " ALSOFT_VERSION; +constexpr ALchar alRenderer[] = "OpenAL Soft"; + +// Error Messages +constexpr ALchar alNoError[] = "No Error"; +constexpr ALchar alErrInvalidName[] = "Invalid Name"; +constexpr ALchar alErrInvalidEnum[] = "Invalid Enum"; +constexpr ALchar alErrInvalidValue[] = "Invalid Value"; +constexpr ALchar alErrInvalidOp[] = "Invalid Operation"; +constexpr ALchar alErrOutOfMemory[] = "Out of Memory"; + +/* Resampler strings */ +constexpr ALchar alPointResampler[] = "Nearest"; +constexpr ALchar alLinearResampler[] = "Linear"; +constexpr ALchar alCubicResampler[] = "Cubic"; +constexpr ALchar alBSinc12Resampler[] = "11th order Sinc"; +constexpr ALchar alBSinc24Resampler[] = "23rd order Sinc"; + +} // namespace + +/* WARNING: Non-standard export! Not part of any extension, or exposed in the + * alcFunctions list. + */ +extern "C" AL_API const ALchar* AL_APIENTRY alsoft_get_version(void) +START_API_FUNC +{ + const char *spoof{getenv("ALSOFT_SPOOF_VERSION")}; + if(spoof && spoof[0] != '\0') return spoof; + return ALSOFT_VERSION; +} +END_API_FUNC + +#define DO_UPDATEPROPS() do { \ + if(!context->DeferUpdates.load(std::memory_order_acquire)) \ + UpdateContextProps(context.get()); \ + else \ + context->PropsClean.clear(std::memory_order_release); \ +} while(0) + + +AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + switch(capability) + { + case AL_SOURCE_DISTANCE_MODEL: + context->SourceDistanceModel = AL_TRUE; + DO_UPDATEPROPS(); + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + switch(capability) + { + case AL_SOURCE_DISTANCE_MODEL: + context->SourceDistanceModel = AL_FALSE; + DO_UPDATEPROPS(); + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability); + } +} +END_API_FUNC + +AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return AL_FALSE; + + std::lock_guard _{context->PropLock}; + ALboolean value{AL_FALSE}; + switch(capability) + { + case AL_SOURCE_DISTANCE_MODEL: + value = context->SourceDistanceModel; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability); + } + + return value; +} +END_API_FUNC + +AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return AL_FALSE; + + std::lock_guard _{context->PropLock}; + ALboolean value{AL_FALSE}; + switch(pname) + { + case AL_DOPPLER_FACTOR: + if(context->DopplerFactor != 0.0f) + value = AL_TRUE; + break; + + case AL_DOPPLER_VELOCITY: + if(context->DopplerVelocity != 0.0f) + value = AL_TRUE; + break; + + case AL_DISTANCE_MODEL: + if(context->mDistanceModel == DistanceModel::Default) + value = AL_TRUE; + break; + + case AL_SPEED_OF_SOUND: + if(context->SpeedOfSound != 0.0f) + value = AL_TRUE; + break; + + case AL_DEFERRED_UPDATES_SOFT: + if(context->DeferUpdates.load(std::memory_order_acquire)) + value = AL_TRUE; + break; + + case AL_GAIN_LIMIT_SOFT: + if(GAIN_MIX_MAX/context->GainBoost != 0.0f) + value = AL_TRUE; + break; + + case AL_NUM_RESAMPLERS_SOFT: + /* Always non-0. */ + value = AL_TRUE; + break; + + case AL_DEFAULT_RESAMPLER_SOFT: + value = ResamplerDefault ? AL_TRUE : AL_FALSE; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid boolean property 0x%04x", pname); + } + + return value; +} +END_API_FUNC + +AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return 0.0; + + std::lock_guard _{context->PropLock}; + ALdouble value{0.0}; + switch(pname) + { + case AL_DOPPLER_FACTOR: + value = static_cast(context->DopplerFactor); + break; + + case AL_DOPPLER_VELOCITY: + value = static_cast(context->DopplerVelocity); + break; + + case AL_DISTANCE_MODEL: + value = static_cast(context->mDistanceModel); + break; + + case AL_SPEED_OF_SOUND: + value = static_cast(context->SpeedOfSound); + break; + + case AL_DEFERRED_UPDATES_SOFT: + if(context->DeferUpdates.load(std::memory_order_acquire)) + value = static_cast(AL_TRUE); + break; + + case AL_GAIN_LIMIT_SOFT: + value = static_castGAIN_MIX_MAX/context->GainBoost; + break; + + case AL_NUM_RESAMPLERS_SOFT: + value = static_cast(ResamplerMax + 1); + break; + + case AL_DEFAULT_RESAMPLER_SOFT: + value = static_cast(ResamplerDefault); + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid double property 0x%04x", pname); + } + + return value; +} +END_API_FUNC + +AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return 0.0f; + + std::lock_guard _{context->PropLock}; + ALfloat value{0.0f}; + switch(pname) + { + case AL_DOPPLER_FACTOR: + value = context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + value = context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + value = static_cast(context->mDistanceModel); + break; + + case AL_SPEED_OF_SOUND: + value = context->SpeedOfSound; + break; + + case AL_DEFERRED_UPDATES_SOFT: + if(context->DeferUpdates.load(std::memory_order_acquire)) + value = static_cast(AL_TRUE); + break; + + case AL_GAIN_LIMIT_SOFT: + value = GAIN_MIX_MAX/context->GainBoost; + break; + + case AL_NUM_RESAMPLERS_SOFT: + value = static_cast(ResamplerMax + 1); + break; + + case AL_DEFAULT_RESAMPLER_SOFT: + value = static_cast(ResamplerDefault); + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid float property 0x%04x", pname); + } + + return value; +} +END_API_FUNC + +AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return 0; + + std::lock_guard _{context->PropLock}; + ALint value{0}; + switch(pname) + { + case AL_DOPPLER_FACTOR: + value = static_cast(context->DopplerFactor); + break; + + case AL_DOPPLER_VELOCITY: + value = static_cast(context->DopplerVelocity); + break; + + case AL_DISTANCE_MODEL: + value = static_cast(context->mDistanceModel); + break; + + case AL_SPEED_OF_SOUND: + value = static_cast(context->SpeedOfSound); + break; + + case AL_DEFERRED_UPDATES_SOFT: + if(context->DeferUpdates.load(std::memory_order_acquire)) + value = static_cast(AL_TRUE); + break; + + case AL_GAIN_LIMIT_SOFT: + value = static_cast(GAIN_MIX_MAX/context->GainBoost); + break; + + case AL_NUM_RESAMPLERS_SOFT: + value = ResamplerMax + 1; + break; + + case AL_DEFAULT_RESAMPLER_SOFT: + value = ResamplerDefault; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer property 0x%04x", pname); + } + + return value; +} +END_API_FUNC + +extern "C" AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return 0; + + std::lock_guard _{context->PropLock}; + ALint64SOFT value{0}; + switch(pname) + { + case AL_DOPPLER_FACTOR: + value = (ALint64SOFT)context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + value = (ALint64SOFT)context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + value = (ALint64SOFT)context->mDistanceModel; + break; + + case AL_SPEED_OF_SOUND: + value = (ALint64SOFT)context->SpeedOfSound; + break; + + case AL_DEFERRED_UPDATES_SOFT: + if(context->DeferUpdates.load(std::memory_order_acquire)) + value = (ALint64SOFT)AL_TRUE; + break; + + case AL_GAIN_LIMIT_SOFT: + value = (ALint64SOFT)(GAIN_MIX_MAX/context->GainBoost); + break; + + case AL_NUM_RESAMPLERS_SOFT: + value = (ALint64SOFT)(ResamplerMax + 1); + break; + + case AL_DEFAULT_RESAMPLER_SOFT: + value = (ALint64SOFT)ResamplerDefault; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer64 property 0x%04x", pname); + } + + return value; +} +END_API_FUNC + +AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return nullptr; + + std::lock_guard _{context->PropLock}; + void *value{nullptr}; + switch(pname) + { + case AL_EVENT_CALLBACK_FUNCTION_SOFT: + value = reinterpret_cast(context->EventCb); + break; + + case AL_EVENT_CALLBACK_USER_PARAM_SOFT: + value = context->EventParam; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname); + } + + return value; +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values) +START_API_FUNC +{ + if(values) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + case AL_DOPPLER_VELOCITY: + case AL_DISTANCE_MODEL: + case AL_SPEED_OF_SOUND: + case AL_DEFERRED_UPDATES_SOFT: + case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: + values[0] = alGetBoolean(pname); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(pname) + { + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid boolean-vector property 0x%04x", pname); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values) +START_API_FUNC +{ + if(values) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + case AL_DOPPLER_VELOCITY: + case AL_DISTANCE_MODEL: + case AL_SPEED_OF_SOUND: + case AL_DEFERRED_UPDATES_SOFT: + case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: + values[0] = alGetDouble(pname); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(pname) + { + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid double-vector property 0x%04x", pname); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values) +START_API_FUNC +{ + if(values) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + case AL_DOPPLER_VELOCITY: + case AL_DISTANCE_MODEL: + case AL_SPEED_OF_SOUND: + case AL_DEFERRED_UPDATES_SOFT: + case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: + values[0] = alGetFloat(pname); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(pname) + { + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid float-vector property 0x%04x", pname); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values) +START_API_FUNC +{ + if(values) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + case AL_DOPPLER_VELOCITY: + case AL_DISTANCE_MODEL: + case AL_SPEED_OF_SOUND: + case AL_DEFERRED_UPDATES_SOFT: + case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: + values[0] = alGetInteger(pname); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(pname) + { + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer-vector property 0x%04x", pname); + } +} +END_API_FUNC + +extern "C" AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values) +START_API_FUNC +{ + if(values) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + case AL_DOPPLER_VELOCITY: + case AL_DISTANCE_MODEL: + case AL_SPEED_OF_SOUND: + case AL_DEFERRED_UPDATES_SOFT: + case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: + values[0] = alGetInteger64SOFT(pname); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(pname) + { + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer64-vector property 0x%04x", pname); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values) +START_API_FUNC +{ + if(values) + { + switch(pname) + { + case AL_EVENT_CALLBACK_FUNCTION_SOFT: + case AL_EVENT_CALLBACK_USER_PARAM_SOFT: + values[0] = alGetPointerSOFT(pname); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(pname) + { + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid pointer-vector property 0x%04x", pname); + } +} +END_API_FUNC + +AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return nullptr; + + const ALchar *value{nullptr}; + switch(pname) + { + case AL_VENDOR: + value = alVendor; + break; + + case AL_VERSION: + value = alVersion; + break; + + case AL_RENDERER: + value = alRenderer; + break; + + case AL_EXTENSIONS: + value = context->ExtensionList; + break; + + case AL_NO_ERROR: + value = alNoError; + break; + + case AL_INVALID_NAME: + value = alErrInvalidName; + break; + + case AL_INVALID_ENUM: + value = alErrInvalidEnum; + break; + + case AL_INVALID_VALUE: + value = alErrInvalidValue; + break; + + case AL_INVALID_OPERATION: + value = alErrInvalidOp; + break; + + case AL_OUT_OF_MEMORY: + value = alErrOutOfMemory; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid string property 0x%04x", pname); + } + return value; +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!(value >= 0.0f && std::isfinite(value))) + alSetError(context.get(), AL_INVALID_VALUE, "Doppler factor %f out of range", value); + else + { + std::lock_guard _{context->PropLock}; + context->DopplerFactor = value; + DO_UPDATEPROPS(); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if((context->EnabledEvts.load(std::memory_order_relaxed)&EventType_Deprecated)) + { + static constexpr ALCchar msg[] = + "alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound"; + const ALsizei msglen = static_cast(strlen(msg)); + std::lock_guard _{context->EventCbLock}; + ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; + if((enabledevts&EventType_Deprecated) && context->EventCb) + (*context->EventCb)(AL_EVENT_TYPE_DEPRECATED_SOFT, 0, 0, msglen, msg, + context->EventParam); + } + + if(!(value >= 0.0f && std::isfinite(value))) + alSetError(context.get(), AL_INVALID_VALUE, "Doppler velocity %f out of range", value); + else + { + std::lock_guard _{context->PropLock}; + context->DopplerVelocity = value; + DO_UPDATEPROPS(); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!(value > 0.0f && std::isfinite(value))) + alSetError(context.get(), AL_INVALID_VALUE, "Speed of sound %f out of range", value); + else + { + std::lock_guard _{context->PropLock}; + context->SpeedOfSound = value; + DO_UPDATEPROPS(); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!(value == AL_INVERSE_DISTANCE || value == AL_INVERSE_DISTANCE_CLAMPED || + value == AL_LINEAR_DISTANCE || value == AL_LINEAR_DISTANCE_CLAMPED || + value == AL_EXPONENT_DISTANCE || value == AL_EXPONENT_DISTANCE_CLAMPED || + value == AL_NONE)) + alSetError(context.get(), AL_INVALID_VALUE, "Distance model 0x%04x out of range", value); + else + { + std::lock_guard _{context->PropLock}; + context->mDistanceModel = static_cast(value); + if(!context->SourceDistanceModel) + DO_UPDATEPROPS(); + } +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCcontext_DeferUpdates(context.get()); +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCcontext_ProcessUpdates(context.get()); +} +END_API_FUNC + + +AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index) +START_API_FUNC +{ + const char *ResamplerNames[] = { + alPointResampler, alLinearResampler, + alCubicResampler, alBSinc12Resampler, + alBSinc24Resampler, + }; + static_assert(al::size(ResamplerNames) == ResamplerMax+1, "Incorrect ResamplerNames list"); + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return nullptr; + + const ALchar *value{nullptr}; + switch(pname) + { + case AL_RESAMPLER_NAME_SOFT: + if(index < 0 || static_cast(index) >= al::size(ResamplerNames)) + alSetError(context.get(), AL_INVALID_VALUE, "Resampler name index %d out of range", + index); + else + value = ResamplerNames[index]; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid string indexed property"); + } + return value; +} +END_API_FUNC + + +void UpdateContextProps(ALCcontext *context) +{ + /* Get an unused proprty container, or allocate a new one as needed. */ + ALcontextProps *props{context->FreeContextProps.load(std::memory_order_acquire)}; + if(!props) + props = static_cast(al_calloc(16, sizeof(*props))); + else + { + ALcontextProps *next; + do { + next = props->next.load(std::memory_order_relaxed); + } while(context->FreeContextProps.compare_exchange_weak(props, next, + std::memory_order_seq_cst, std::memory_order_acquire) == 0); + } + + /* Copy in current property values. */ + props->MetersPerUnit = context->MetersPerUnit; + + props->DopplerFactor = context->DopplerFactor; + props->DopplerVelocity = context->DopplerVelocity; + props->SpeedOfSound = context->SpeedOfSound; + + props->SourceDistanceModel = context->SourceDistanceModel; + props->mDistanceModel = context->mDistanceModel; + + /* Set the new container for updating internal parameters. */ + props = context->Update.exchange(props, std::memory_order_acq_rel); + if(props) + { + /* If there was an unused update container, put it back in the + * freelist. + */ + AtomicReplaceHead(context->FreeContextProps, props); + } +} diff --git a/al/event.cpp b/al/event.cpp new file mode 100644 index 00000000..d50cef2e --- /dev/null +++ b/al/event.cpp @@ -0,0 +1,216 @@ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" + +#include "alError.h" +#include "albyte.h" +#include "alcmain.h" +#include "alcontext.h" +#include "alexcpt.h" +#include "almalloc.h" +#include "effects/base.h" +#include "inprogext.h" +#include "logging.h" +#include "opthelpers.h" +#include "ringbuffer.h" +#include "threads.h" + + +static int EventThread(ALCcontext *context) +{ + RingBuffer *ring{context->AsyncEvents.get()}; + bool quitnow{false}; + while(LIKELY(!quitnow)) + { + auto evt_data = ring->getReadVector().first; + if(evt_data.len == 0) + { + context->EventSem.wait(); + continue; + } + + std::lock_guard _{context->EventCbLock}; + do { + auto &evt = *reinterpret_cast(evt_data.buf); + evt_data.buf += sizeof(AsyncEvent); + evt_data.len -= 1; + /* This automatically destructs the event object and advances the + * ringbuffer's read offset at the end of scope. + */ + const struct EventAutoDestructor { + AsyncEvent &evt_; + RingBuffer *ring_; + ~EventAutoDestructor() + { + al::destroy_at(&evt_); + ring_->readAdvance(1); + } + } _{evt, ring}; + + quitnow = evt.EnumType == EventType_KillThread; + if(UNLIKELY(quitnow)) break; + + if(evt.EnumType == EventType_ReleaseEffectState) + { + evt.u.mEffectState->DecRef(); + continue; + } + + ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_acquire)}; + if(!context->EventCb) continue; + + if(evt.EnumType == EventType_SourceStateChange) + { + if(!(enabledevts&EventType_SourceStateChange)) + continue; + std::string msg{"Source ID " + std::to_string(evt.u.srcstate.id)}; + msg += " state has changed to "; + msg += (evt.u.srcstate.state==AL_INITIAL) ? "AL_INITIAL" : + (evt.u.srcstate.state==AL_PLAYING) ? "AL_PLAYING" : + (evt.u.srcstate.state==AL_PAUSED) ? "AL_PAUSED" : + (evt.u.srcstate.state==AL_STOPPED) ? "AL_STOPPED" : ""; + context->EventCb(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, evt.u.srcstate.id, + evt.u.srcstate.state, static_cast(msg.length()), msg.c_str(), + context->EventParam + ); + } + else if(evt.EnumType == EventType_BufferCompleted) + { + if(!(enabledevts&EventType_BufferCompleted)) + continue; + std::string msg{std::to_string(evt.u.bufcomp.count)}; + if(evt.u.bufcomp.count == 1) msg += " buffer completed"; + else msg += " buffers completed"; + context->EventCb(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, evt.u.bufcomp.id, + evt.u.bufcomp.count, static_cast(msg.length()), msg.c_str(), + context->EventParam + ); + } + else if((enabledevts&evt.EnumType) == evt.EnumType) + context->EventCb(evt.u.user.type, evt.u.user.id, evt.u.user.param, + static_cast(strlen(evt.u.user.msg)), evt.u.user.msg, + context->EventParam + ); + } while(evt_data.len != 0); + } + return 0; +} + +void StartEventThrd(ALCcontext *ctx) +{ + try { + ctx->EventThread = std::thread{EventThread, ctx}; + } + catch(std::exception& e) { + ERR("Failed to start event thread: %s\n", e.what()); + } + catch(...) { + ERR("Failed to start event thread! Expect problems.\n"); + } +} + +void StopEventThrd(ALCcontext *ctx) +{ + static constexpr AsyncEvent kill_evt{EventType_KillThread}; + RingBuffer *ring{ctx->AsyncEvents.get()}; + auto evt_data = ring->getWriteVector().first; + if(evt_data.len == 0) + { + do { + std::this_thread::yield(); + evt_data = ring->getWriteVector().first; + } while(evt_data.len == 0); + } + new (evt_data.buf) AsyncEvent{kill_evt}; + ring->writeAdvance(1); + + ctx->EventSem.post(); + if(ctx->EventThread.joinable()) + ctx->EventThread.join(); +} + +AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(count < 0) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Controlling %d events", count); + if(count == 0) return; + if(!types) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "NULL pointer"); + + ALbitfieldSOFT flags{0}; + const ALenum *types_end = types+count; + auto bad_type = std::find_if_not(types, types_end, + [&flags](ALenum type) noexcept -> bool + { + if(type == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT) + flags |= EventType_BufferCompleted; + else if(type == AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT) + flags |= EventType_SourceStateChange; + else if(type == AL_EVENT_TYPE_ERROR_SOFT) + flags |= EventType_Error; + else if(type == AL_EVENT_TYPE_PERFORMANCE_SOFT) + flags |= EventType_Performance; + else if(type == AL_EVENT_TYPE_DEPRECATED_SOFT) + flags |= EventType_Deprecated; + else if(type == AL_EVENT_TYPE_DISCONNECTED_SOFT) + flags |= EventType_Disconnected; + else + return false; + return true; + } + ); + if(bad_type != types_end) + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, "Invalid event type 0x%04x", *bad_type); + + if(enable) + { + ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; + while(context->EnabledEvts.compare_exchange_weak(enabledevts, enabledevts|flags, + std::memory_order_acq_rel, std::memory_order_acquire) == 0) + { + /* enabledevts is (re-)filled with the current value on failure, so + * just try again. + */ + } + } + else + { + ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; + while(context->EnabledEvts.compare_exchange_weak(enabledevts, enabledevts&~flags, + std::memory_order_acq_rel, std::memory_order_acquire) == 0) + { + } + /* Wait to ensure the event handler sees the changed flags before + * returning. + */ + std::lock_guard{context->EventCbLock}; + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->EventCbLock}; + context->EventCb = callback; + context->EventParam = userParam; +} +END_API_FUNC -- cgit v1.2.3 From 76d87330ec7c34efeee86654db4c6ed405810de2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Jul 2019 15:57:48 -0700 Subject: Move the event declarations to a separate header --- CMakeLists.txt | 1 + al/alError.cpp | 2 +- al/alSource.cpp | 1 + al/alState.cpp | 2 +- al/event.cpp | 3 ++- al/event.h | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ alc/alc.cpp | 1 + alc/alcmain.h | 46 ---------------------------------------------- alc/alu.cpp | 1 + alc/mixvoice.cpp | 1 + 10 files changed, 64 insertions(+), 49 deletions(-) create mode 100644 al/event.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 258c93e9..315f1752 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -622,6 +622,7 @@ SET(OPENAL_OBJS al/alSource.h al/alState.cpp al/event.cpp + al/event.h ) SET(ALC_OBJS alc/alc.cpp diff --git a/al/alError.cpp b/al/alError.cpp index 159aee52..bff92444 100644 --- a/al/alError.cpp +++ b/al/alError.cpp @@ -37,10 +37,10 @@ #include "AL/al.h" #include "AL/alc.h" -#include "alcmain.h" #include "alcontext.h" #include "alexcpt.h" #include "almalloc.h" +#include "event.h" #include "inprogext.h" #include "logging.h" #include "opthelpers.h" diff --git a/al/alSource.cpp b/al/alSource.cpp index 4af5cc47..fdd063ac 100644 --- a/al/alSource.cpp +++ b/al/alSource.cpp @@ -59,6 +59,7 @@ #include "atomic.h" #include "backends/base.h" #include "bformatdec.h" +#include "event.h" #include "filters/nfc.h" #include "filters/splitter.h" #include "inprogext.h" diff --git a/al/alState.cpp b/al/alState.cpp index ee8d3a1c..001412a8 100644 --- a/al/alState.cpp +++ b/al/alState.cpp @@ -33,13 +33,13 @@ #include "AL/alext.h" #include "alError.h" -#include "alcmain.h" #include "alcontext.h" #include "alexcpt.h" #include "almalloc.h" #include "alspan.h" #include "alu.h" #include "atomic.h" +#include "event.h" #include "inprogext.h" #include "opthelpers.h" diff --git a/al/event.cpp b/al/event.cpp index d50cef2e..44d825c6 100644 --- a/al/event.cpp +++ b/al/event.cpp @@ -1,6 +1,8 @@ #include "config.h" +#include "event.h" + #include #include #include @@ -16,7 +18,6 @@ #include "alError.h" #include "albyte.h" -#include "alcmain.h" #include "alcontext.h" #include "alexcpt.h" #include "almalloc.h" diff --git a/al/event.h b/al/event.h new file mode 100644 index 00000000..e98be560 --- /dev/null +++ b/al/event.h @@ -0,0 +1,55 @@ +#ifndef AL_EVENT_H +#define AL_EVENT_H + +#include "AL/al.h" +#include "AL/alc.h" + +struct EffectState; + + +enum { + /* End event thread processing. */ + EventType_KillThread = 0, + + /* User event types. */ + EventType_SourceStateChange = 1<<0, + EventType_BufferCompleted = 1<<1, + EventType_Error = 1<<2, + EventType_Performance = 1<<3, + EventType_Deprecated = 1<<4, + EventType_Disconnected = 1<<5, + + /* Internal events. */ + EventType_ReleaseEffectState = 65536, +}; + +struct AsyncEvent { + unsigned int EnumType{0u}; + union { + char dummy; + struct { + ALuint id; + ALenum state; + } srcstate; + struct { + ALuint id; + ALsizei count; + } bufcomp; + struct { + ALenum type; + ALuint id; + ALuint param; + ALchar msg[1008]; + } user; + EffectState *mEffectState; + } u{}; + + AsyncEvent() noexcept = default; + constexpr AsyncEvent(unsigned int type) noexcept : EnumType{type} { } +}; + + +void StartEventThrd(ALCcontext *ctx); +void StopEventThrd(ALCcontext *ctx); + +#endif diff --git a/alc/alc.cpp b/alc/alc.cpp index 00f90d91..de0038a2 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -74,6 +74,7 @@ #include "compat.h" #include "cpu_caps.h" #include "effects/base.h" +#include "event.h" #include "filters/nfc.h" #include "filters/splitter.h" #include "fpu_modes.h" diff --git a/alc/alcmain.h b/alc/alcmain.h index a22e0e81..85f37e73 100644 --- a/alc/alcmain.h +++ b/alc/alcmain.h @@ -461,48 +461,6 @@ struct ALCdevice { #define RECORD_THREAD_NAME "alsoft-record" -enum { - /* End event thread processing. */ - EventType_KillThread = 0, - - /* User event types. */ - EventType_SourceStateChange = 1<<0, - EventType_BufferCompleted = 1<<1, - EventType_Error = 1<<2, - EventType_Performance = 1<<3, - EventType_Deprecated = 1<<4, - EventType_Disconnected = 1<<5, - - /* Internal events. */ - EventType_ReleaseEffectState = 65536, -}; - -struct AsyncEvent { - unsigned int EnumType{0u}; - union { - char dummy; - struct { - ALuint id; - ALenum state; - } srcstate; - struct { - ALuint id; - ALsizei count; - } bufcomp; - struct { - ALenum type; - ALuint id; - ALuint param; - ALchar msg[1008]; - } user; - EffectState *mEffectState; - } u{}; - - AsyncEvent() noexcept = default; - constexpr AsyncEvent(unsigned int type) noexcept : EnumType{type} { } -}; - - void AllocateVoices(ALCcontext *context, size_t num_voices); @@ -525,10 +483,6 @@ inline ALint GetChannelIdxByName(const RealMixParams &real, Channel chan) noexce { return real.ChannelIndex[chan]; } -void StartEventThrd(ALCcontext *ctx); -void StopEventThrd(ALCcontext *ctx); - - al::vector SearchDataFiles(const char *match, const char *subdir); #endif diff --git a/alc/alu.cpp b/alc/alu.cpp index cc1a5a98..31689997 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -60,6 +60,7 @@ #include "bs2b.h" #include "cpu_caps.h" #include "effects/base.h" +#include "event.h" #include "filters/biquad.h" #include "filters/nfc.h" #include "filters/splitter.h" diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index be872f6d..aea04b15 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -50,6 +50,7 @@ #include "alspan.h" #include "alu.h" #include "cpu_caps.h" +#include "event.h" #include "filters/biquad.h" #include "filters/nfc.h" #include "filters/splitter.h" -- cgit v1.2.3 From c2de0782cfec62d6a1c3fe2d409d0f64528ae5f7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Jul 2019 16:49:56 -0700 Subject: Minor formatting fixes --- al/event.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/al/event.cpp b/al/event.cpp index 44d825c6..ae2825d0 100644 --- a/al/event.cpp +++ b/al/event.cpp @@ -55,7 +55,7 @@ static int EventThread(ALCcontext *context) RingBuffer *ring_; ~EventAutoDestructor() { - al::destroy_at(&evt_); + al::destroy_at(std::addressof(evt_)); ring_->readAdvance(1); } } _{evt, ring}; @@ -84,8 +84,7 @@ static int EventThread(ALCcontext *context) (evt.u.srcstate.state==AL_STOPPED) ? "AL_STOPPED" : ""; context->EventCb(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, evt.u.srcstate.id, evt.u.srcstate.state, static_cast(msg.length()), msg.c_str(), - context->EventParam - ); + context->EventParam); } else if(evt.EnumType == EventType_BufferCompleted) { @@ -96,14 +95,12 @@ static int EventThread(ALCcontext *context) else msg += " buffers completed"; context->EventCb(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, evt.u.bufcomp.id, evt.u.bufcomp.count, static_cast(msg.length()), msg.c_str(), - context->EventParam - ); + context->EventParam); } else if((enabledevts&evt.EnumType) == evt.EnumType) context->EventCb(evt.u.user.type, evt.u.user.id, evt.u.user.param, static_cast(strlen(evt.u.user.msg)), evt.u.user.msg, - context->EventParam - ); + context->EventParam); } while(evt_data.len != 0); } return 0; -- cgit v1.2.3 From 4c9e18c5a0c29548eb38db636785aa7064713c5d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Jul 2019 17:54:07 -0700 Subject: Rename al/* sources to avoid camel-case --- CMakeLists.txt | 34 +- al/alAuxEffectSlot.cpp | 808 ---------- al/alAuxEffectSlot.h | 103 -- al/alBuffer.cpp | 1408 ----------------- al/alBuffer.h | 121 -- al/alEffect.cpp | 742 --------- al/alEffect.h | 61 - al/alError.cpp | 118 -- al/alError.h | 24 - al/alExtension.cpp | 80 - al/alFilter.cpp | 665 -------- al/alFilter.h | 56 - al/alListener.cpp | 454 ------ al/alListener.h | 58 - al/alSource.cpp | 3639 -------------------------------------------- al/alSource.h | 131 -- al/alState.cpp | 859 ----------- al/auxeffectslot.cpp | 808 ++++++++++ al/auxeffectslot.h | 103 ++ al/buffer.cpp | 1408 +++++++++++++++++ al/buffer.h | 121 ++ al/effect.cpp | 742 +++++++++ al/effect.h | 61 + al/error.cpp | 118 ++ al/error.h | 24 + al/event.cpp | 2 +- al/extension.cpp | 80 + al/filter.cpp | 665 ++++++++ al/filter.h | 56 + al/listener.cpp | 454 ++++++ al/listener.h | 58 + al/source.cpp | 3639 ++++++++++++++++++++++++++++++++++++++++++++ al/source.h | 131 ++ al/state.cpp | 859 +++++++++++ alc/alc.cpp | 14 +- alc/alcontext.h | 2 +- alc/alu.cpp | 10 +- alc/alu.h | 2 +- alc/effects/autowah.cpp | 4 +- alc/effects/chorus.cpp | 4 +- alc/effects/compressor.cpp | 4 +- alc/effects/dedicated.cpp | 4 +- alc/effects/distortion.cpp | 4 +- alc/effects/echo.cpp | 6 +- alc/effects/equalizer.cpp | 4 +- alc/effects/fshifter.cpp | 4 +- alc/effects/modulator.cpp | 4 +- alc/effects/null.cpp | 4 +- alc/effects/pshifter.cpp | 7 +- alc/effects/reverb.cpp | 6 +- alc/effects/vmorpher.cpp | 4 +- alc/mixer/mixer_c.cpp | 3 +- alc/mixer/mixer_sse.cpp | 2 - alc/mixvoice.cpp | 6 +- alc/panning.cpp | 2 +- 55 files changed, 9393 insertions(+), 9397 deletions(-) delete mode 100644 al/alAuxEffectSlot.cpp delete mode 100644 al/alAuxEffectSlot.h delete mode 100644 al/alBuffer.cpp delete mode 100644 al/alBuffer.h delete mode 100644 al/alEffect.cpp delete mode 100644 al/alEffect.h delete mode 100644 al/alError.cpp delete mode 100644 al/alError.h delete mode 100644 al/alExtension.cpp delete mode 100644 al/alFilter.cpp delete mode 100644 al/alFilter.h delete mode 100644 al/alListener.cpp delete mode 100644 al/alListener.h delete mode 100644 al/alSource.cpp delete mode 100644 al/alSource.h delete mode 100644 al/alState.cpp create mode 100644 al/auxeffectslot.cpp create mode 100644 al/auxeffectslot.h create mode 100644 al/buffer.cpp create mode 100644 al/buffer.h create mode 100644 al/effect.cpp create mode 100644 al/effect.h create mode 100644 al/error.cpp create mode 100644 al/error.h create mode 100644 al/extension.cpp create mode 100644 al/filter.cpp create mode 100644 al/filter.h create mode 100644 al/listener.cpp create mode 100644 al/listener.h create mode 100644 al/source.cpp create mode 100644 al/source.h create mode 100644 al/state.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 315f1752..db43215d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -605,22 +605,22 @@ SET(COMMON_OBJS common/vecmat.h ) SET(OPENAL_OBJS - al/alAuxEffectSlot.cpp - al/alAuxEffectSlot.h - al/alBuffer.cpp - al/alBuffer.h - al/alEffect.cpp - al/alEffect.h - al/alError.cpp - al/alError.h - al/alExtension.cpp - al/alFilter.cpp - al/alFilter.h - al/alListener.cpp - al/alListener.h - al/alSource.cpp - al/alSource.h - al/alState.cpp + al/auxeffectslot.cpp + al/auxeffectslot.h + al/buffer.cpp + al/buffer.h + al/effect.cpp + al/effect.h + al/error.cpp + al/error.h + al/extension.cpp + al/filter.cpp + al/filter.h + al/listener.cpp + al/listener.h + al/source.cpp + al/source.h + al/state.cpp al/event.cpp al/event.h ) @@ -1299,8 +1299,8 @@ TARGET_INCLUDE_DIRECTORIES(${IMPL_TARGET} PRIVATE ${INC_PATHS} ${OpenAL_BINARY_DIR} + ${OpenAL_SOURCE_DIR} ${OpenAL_SOURCE_DIR}/alc - ${OpenAL_SOURCE_DIR}/al ${OpenAL_SOURCE_DIR}/common ) diff --git a/al/alAuxEffectSlot.cpp b/al/alAuxEffectSlot.cpp deleted file mode 100644 index 42966bf2..00000000 --- a/al/alAuxEffectSlot.cpp +++ /dev/null @@ -1,808 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "alAuxEffectSlot.h" - -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" - -#include "alEffect.h" -#include "alError.h" -#include "alcmain.h" -#include "alcontext.h" -#include "alexcpt.h" -#include "almalloc.h" -#include "alnumeric.h" -#include "alspan.h" -#include "alu.h" -#include "fpu_modes.h" -#include "inprogext.h" -#include "logging.h" -#include "opthelpers.h" - - -namespace { - -inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept -{ - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= context->EffectSlotList.size())) - return nullptr; - EffectSlotSubList &sublist{context->EffectSlotList[lidx]}; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) - return nullptr; - return sublist.EffectSlots + slidx; -} - -inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) noexcept -{ - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= device->EffectList.size())) - return nullptr; - EffectSubList &sublist = device->EffectList[lidx]; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) - return nullptr; - return sublist.Effects + slidx; -} - - -void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) -{ - if(count < 1) return; - ALeffectslotArray *curarray{context->ActiveAuxSlots.load(std::memory_order_acquire)}; - size_t newcount{curarray->size() + count}; - - /* Insert the new effect slots into the head of the array, followed by the - * existing ones. - */ - ALeffectslotArray *newarray = ALeffectslot::CreatePtrArray(newcount); - auto slotiter = std::transform(slotids, slotids+count, newarray->begin(), - [context](ALuint id) noexcept -> ALeffectslot* - { return LookupEffectSlot(context, id); } - ); - std::copy(curarray->begin(), curarray->end(), slotiter); - - /* Remove any duplicates (first instance of each will be kept). */ - auto last = newarray->end(); - for(auto start=newarray->begin()+1;;) - { - last = std::remove(start, last, *(start-1)); - if(start == last) break; - ++start; - } - newcount = static_cast(std::distance(newarray->begin(), last)); - - /* Reallocate newarray if the new size ended up smaller from duplicate - * removal. - */ - if(UNLIKELY(newcount < newarray->size())) - { - curarray = newarray; - newarray = ALeffectslot::CreatePtrArray(newcount); - std::copy_n(curarray->begin(), newcount, newarray->begin()); - delete curarray; - curarray = nullptr; - } - - curarray = context->ActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); - ALCdevice *device{context->Device}; - while((device->MixCount.load(std::memory_order_acquire)&1)) - std::this_thread::yield(); - delete curarray; -} - -void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) -{ - if(count < 1) return; - ALeffectslotArray *curarray{context->ActiveAuxSlots.load(std::memory_order_acquire)}; - - /* Don't shrink the allocated array size since we don't know how many (if - * any) of the effect slots to remove are in the array. - */ - ALeffectslotArray *newarray = ALeffectslot::CreatePtrArray(curarray->size()); - - /* Copy each element in curarray to newarray whose ID is not in slotids. */ - const ALuint *slotids_end{slotids + count}; - auto slotiter = std::copy_if(curarray->begin(), curarray->end(), newarray->begin(), - [slotids, slotids_end](const ALeffectslot *slot) -> bool - { return std::find(slotids, slotids_end, slot->id) == slotids_end; } - ); - - /* Reallocate with the new size. */ - auto newsize = static_cast(std::distance(newarray->begin(), slotiter)); - if(LIKELY(newsize != newarray->size())) - { - curarray = newarray; - newarray = ALeffectslot::CreatePtrArray(newsize); - std::copy_n(curarray->begin(), newsize, newarray->begin()); - - delete curarray; - curarray = nullptr; - } - - curarray = context->ActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); - ALCdevice *device{context->Device}; - while((device->MixCount.load(std::memory_order_acquire)&1)) - std::this_thread::yield(); - delete curarray; -} - - -ALeffectslot *AllocEffectSlot(ALCcontext *context) -{ - ALCdevice *device{context->Device}; - std::lock_guard _{context->EffectSlotLock}; - if(context->NumEffectSlots >= device->AuxiliaryEffectSlotMax) - { - alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u effect slot limit", - device->AuxiliaryEffectSlotMax); - return nullptr; - } - auto sublist = std::find_if(context->EffectSlotList.begin(), context->EffectSlotList.end(), - [](const EffectSlotSubList &entry) noexcept -> bool - { return entry.FreeMask != 0; } - ); - auto lidx = static_cast(std::distance(context->EffectSlotList.begin(), sublist)); - ALeffectslot *slot; - ALsizei slidx; - if(LIKELY(sublist != context->EffectSlotList.end())) - { - slidx = CTZ64(sublist->FreeMask); - slot = sublist->EffectSlots + slidx; - } - else - { - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ - if(UNLIKELY(context->EffectSlotList.size() >= 1<<25)) - { - alSetError(context, AL_OUT_OF_MEMORY, "Too many effect slots allocated"); - return nullptr; - } - context->EffectSlotList.emplace_back(); - sublist = context->EffectSlotList.end() - 1; - - sublist->FreeMask = ~0_u64; - sublist->EffectSlots = static_cast(al_calloc(16, sizeof(ALeffectslot)*64)); - if(UNLIKELY(!sublist->EffectSlots)) - { - context->EffectSlotList.pop_back(); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect slot batch"); - return nullptr; - } - - slidx = 0; - slot = sublist->EffectSlots + slidx; - } - - slot = new (slot) ALeffectslot{}; - ALenum err{InitEffectSlot(slot)}; - if(err != AL_NO_ERROR) - { - al::destroy_at(slot); - alSetError(context, err, "Effect slot object initialization failed"); - return nullptr; - } - aluInitEffectPanning(slot, device); - - /* Add 1 to avoid source ID 0. */ - slot->id = ((lidx<<6) | slidx) + 1; - - context->NumEffectSlots += 1; - sublist->FreeMask &= ~(1_u64 << slidx); - - return slot; -} - -void FreeEffectSlot(ALCcontext *context, ALeffectslot *slot) -{ - ALuint id = slot->id - 1; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; - - al::destroy_at(slot); - - context->EffectSlotList[lidx].FreeMask |= 1_u64 << slidx; - context->NumEffectSlots--; -} - - -#define DO_UPDATEPROPS() do { \ - if(!context->DeferUpdates.load(std::memory_order_acquire)) \ - UpdateEffectSlotProps(slot, context.get()); \ - else \ - slot->PropsClean.clear(std::memory_order_release); \ -} while(0) - -} // namespace - -ALeffectslotArray *ALeffectslot::CreatePtrArray(size_t count) noexcept -{ - /* Allocate space for twice as many pointers, so the mixer has scratch - * space to store a sorted list during mixing. - */ - void *ptr{al_calloc(alignof(ALeffectslotArray), ALeffectslotArray::Sizeof(count*2))}; - return new (ptr) ALeffectslotArray{count}; -} - - -AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Generating %d effect slots", n); - if(n == 0) return; - - if(n == 1) - { - ALeffectslot *slot{AllocEffectSlot(context.get())}; - if(!slot) return; - effectslots[0] = slot->id; - } - else - { - auto tempids = al::vector(n); - auto alloc_end = std::find_if_not(tempids.begin(), tempids.end(), - [&context](ALuint &id) -> bool - { - ALeffectslot *slot{AllocEffectSlot(context.get())}; - if(!slot) return false; - id = slot->id; - return true; - } - ); - if(alloc_end != tempids.end()) - { - auto count = static_cast(std::distance(tempids.begin(), alloc_end)); - alDeleteAuxiliaryEffectSlots(count, tempids.data()); - return; - } - - std::copy(tempids.cbegin(), tempids.cend(), effectslots); - } - - std::unique_lock slotlock{context->EffectSlotLock}; - AddActiveEffectSlots(effectslots, n, context.get()); -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Deleting %d effect slots", n); - if(n == 0) return; - - std::lock_guard _{context->EffectSlotLock}; - auto effectslots_end = effectslots + n; - auto bad_slot = std::find_if(effectslots, effectslots_end, - [&context](ALuint id) -> bool - { - ALeffectslot *slot{LookupEffectSlot(context.get(), id)}; - if(!slot) - { - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect slot ID %u", id); - return true; - } - if(ReadRef(&slot->ref) != 0) - { - alSetError(context.get(), AL_INVALID_NAME, "Deleting in-use effect slot %u", id); - return true; - } - return false; - } - ); - if(bad_slot != effectslots_end) - return; - - // All effectslots are valid, remove and delete them - RemoveActiveEffectSlots(effectslots, n, context.get()); - std::for_each(effectslots, effectslots_end, - [&context](ALuint sid) -> void - { - ALeffectslot *slot{LookupEffectSlot(context.get(), sid)}; - if(slot) FreeEffectSlot(context.get(), slot); - } - ); -} -END_API_FUNC - -AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(LIKELY(context)) - { - std::lock_guard _{context->EffectSlotLock}; - if(LookupEffectSlot(context.get(), effectslot) != nullptr) - return AL_TRUE; - } - return AL_FALSE; -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->EffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - - ALeffectslot *target{}; - ALCdevice *device{}; - ALenum err{}; - switch(param) - { - case AL_EFFECTSLOT_EFFECT: - device = context->Device; - - { std::lock_guard ___{device->EffectLock}; - ALeffect *effect{value ? LookupEffect(device, value) : nullptr}; - if(!(value == 0 || effect != nullptr)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Invalid effect ID %u", value); - err = InitializeEffect(context.get(), slot, effect); - } - if(err != AL_NO_ERROR) - { - alSetError(context.get(), err, "Effect initialization failed"); - return; - } - break; - - case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: - if(!(value == AL_TRUE || value == AL_FALSE)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, - "Effect slot auxiliary send auto out of range"); - slot->AuxSendAuto = value; - break; - - case AL_EFFECTSLOT_TARGET_SOFT: - target = (value ? LookupEffectSlot(context.get(), value) : nullptr); - if(value && !target) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Invalid effect slot target ID"); - if(target) - { - ALeffectslot *checker{target}; - while(checker && checker != slot) - checker = checker->Target; - if(checker) - SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, - "Setting target of effect slot ID %u to %u creates circular chain", slot->id, - target->id); - } - - if(ALeffectslot *oldtarget{slot->Target}) - { - /* We must force an update if there was an existing effect slot - * target, in case it's about to be deleted. - */ - if(target) IncrementRef(&target->ref); - DecrementRef(&oldtarget->ref); - slot->Target = target; - UpdateEffectSlotProps(slot, context.get()); - return; - } - - if(target) IncrementRef(&target->ref); - slot->Target = target; - break; - - default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot integer property 0x%04x", param); - } - DO_UPDATEPROPS(); -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values) -START_API_FUNC -{ - switch(param) - { - case AL_EFFECTSLOT_EFFECT: - case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: - case AL_EFFECTSLOT_TARGET_SOFT: - alAuxiliaryEffectSloti(effectslot, param, values[0]); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->EffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - - switch(param) - { - default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot integer-vector property 0x%04x", param); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->EffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - - switch(param) - { - case AL_EFFECTSLOT_GAIN: - if(!(value >= 0.0f && value <= 1.0f)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Effect slot gain out of range"); - slot->Gain = value; - break; - - default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, "Invalid effect slot float property 0x%04x", - param); - } - DO_UPDATEPROPS(); -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values) -START_API_FUNC -{ - switch(param) - { - case AL_EFFECTSLOT_GAIN: - alAuxiliaryEffectSlotf(effectslot, param, values[0]); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->EffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - - switch(param) - { - default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot float-vector property 0x%04x", param); - } -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->EffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - - switch(param) - { - case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: - *value = slot->AuxSendAuto; - break; - - case AL_EFFECTSLOT_TARGET_SOFT: - *value = slot->Target ? slot->Target->id : 0; - break; - - default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot integer property 0x%04x", param); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values) -START_API_FUNC -{ - switch(param) - { - case AL_EFFECTSLOT_EFFECT: - case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: - case AL_EFFECTSLOT_TARGET_SOFT: - alGetAuxiliaryEffectSloti(effectslot, param, values); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->EffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - - switch(param) - { - default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot integer-vector property 0x%04x", param); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->EffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - - switch(param) - { - case AL_EFFECTSLOT_GAIN: - *value = slot->Gain; - break; - - default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot float property 0x%04x", param); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values) -START_API_FUNC -{ - switch(param) - { - case AL_EFFECTSLOT_GAIN: - alGetAuxiliaryEffectSlotf(effectslot, param, values); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->EffectSlotLock}; - ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); - - switch(param) - { - default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot float-vector property 0x%04x", param); - } -} -END_API_FUNC - - -ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect) -{ - ALenum newtype{effect ? effect->type : AL_EFFECT_NULL}; - if(newtype != EffectSlot->Effect.Type) - { - EffectStateFactory *factory{getFactoryByType(newtype)}; - if(!factory) - { - ERR("Failed to find factory for effect type 0x%04x\n", newtype); - return AL_INVALID_ENUM; - } - EffectState *State{factory->create()}; - if(!State) return AL_OUT_OF_MEMORY; - - FPUCtl mixer_mode{}; - ALCdevice *Device{Context->Device}; - std::unique_lock statelock{Device->StateLock}; - State->mOutTarget = Device->Dry.Buffer; - if(State->deviceUpdate(Device) == AL_FALSE) - { - statelock.unlock(); - mixer_mode.leave(); - State->DecRef(); - return AL_OUT_OF_MEMORY; - } - mixer_mode.leave(); - - if(!effect) - { - EffectSlot->Effect.Type = AL_EFFECT_NULL; - EffectSlot->Effect.Props = EffectProps {}; - } - else - { - EffectSlot->Effect.Type = effect->type; - EffectSlot->Effect.Props = effect->Props; - } - - EffectSlot->Effect.State->DecRef(); - EffectSlot->Effect.State = State; - } - else if(effect) - EffectSlot->Effect.Props = effect->Props; - - /* Remove state references from old effect slot property updates. */ - ALeffectslotProps *props{Context->FreeEffectslotProps.load()}; - while(props) - { - if(props->State) - props->State->DecRef(); - props->State = nullptr; - props = props->next.load(std::memory_order_relaxed); - } - - return AL_NO_ERROR; -} - - -void EffectState::IncRef() noexcept -{ - auto ref = IncrementRef(&mRef); - TRACEREF("EffectState %p increasing refcount to %u\n", this, ref); -} - -void EffectState::DecRef() noexcept -{ - auto ref = DecrementRef(&mRef); - TRACEREF("EffectState %p decreasing refcount to %u\n", this, ref); - if(ref == 0) delete this; -} - - -ALenum InitEffectSlot(ALeffectslot *slot) -{ - EffectStateFactory *factory{getFactoryByType(slot->Effect.Type)}; - if(!factory) return AL_INVALID_VALUE; - slot->Effect.State = factory->create(); - if(!slot->Effect.State) return AL_OUT_OF_MEMORY; - - slot->Effect.State->IncRef(); - slot->Params.mEffectState = slot->Effect.State; - return AL_NO_ERROR; -} - -ALeffectslot::~ALeffectslot() -{ - if(Target) - DecrementRef(&Target->ref); - Target = nullptr; - - ALeffectslotProps *props{Update.load()}; - if(props) - { - if(props->State) props->State->DecRef(); - TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props); - al_free(props); - } - - if(Effect.State) - Effect.State->DecRef(); - if(Params.mEffectState) - Params.mEffectState->DecRef(); -} - -void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) -{ - /* Get an unused property container, or allocate a new one as needed. */ - ALeffectslotProps *props{context->FreeEffectslotProps.load(std::memory_order_relaxed)}; - if(!props) - props = static_cast(al_calloc(16, sizeof(*props))); - else - { - ALeffectslotProps *next; - do { - next = props->next.load(std::memory_order_relaxed); - } while(context->FreeEffectslotProps.compare_exchange_weak(props, next, - std::memory_order_seq_cst, std::memory_order_acquire) == 0); - } - - /* Copy in current property values. */ - props->Gain = slot->Gain; - props->AuxSendAuto = slot->AuxSendAuto; - props->Target = slot->Target; - - props->Type = slot->Effect.Type; - props->Props = slot->Effect.Props; - /* Swap out any stale effect state object there may be in the container, to - * delete it. - */ - EffectState *oldstate{props->State}; - slot->Effect.State->IncRef(); - props->State = slot->Effect.State; - - /* Set the new container for updating internal parameters. */ - props = slot->Update.exchange(props, std::memory_order_acq_rel); - if(props) - { - /* If there was an unused update container, put it back in the - * freelist. - */ - if(props->State) - props->State->DecRef(); - props->State = nullptr; - AtomicReplaceHead(context->FreeEffectslotProps, props); - } - - if(oldstate) - oldstate->DecRef(); -} - -void UpdateAllEffectSlotProps(ALCcontext *context) -{ - std::lock_guard _{context->EffectSlotLock}; - ALeffectslotArray *auxslots{context->ActiveAuxSlots.load(std::memory_order_acquire)}; - for(ALeffectslot *slot : *auxslots) - { - if(!slot->PropsClean.test_and_set(std::memory_order_acq_rel)) - UpdateEffectSlotProps(slot, context); - } -} - -EffectSlotSubList::~EffectSlotSubList() -{ - uint64_t usemask{~FreeMask}; - while(usemask) - { - ALsizei idx{CTZ64(usemask)}; - al::destroy_at(EffectSlots+idx); - usemask &= ~(1_u64 << idx); - } - FreeMask = ~usemask; - al_free(EffectSlots); - EffectSlots = nullptr; -} diff --git a/al/alAuxEffectSlot.h b/al/alAuxEffectSlot.h deleted file mode 100644 index 369638a0..00000000 --- a/al/alAuxEffectSlot.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef AL_AUXEFFECTSLOT_H -#define AL_AUXEFFECTSLOT_H - -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/efx.h" - -#include "alcmain.h" -#include "almalloc.h" -#include "atomic.h" -#include "effects/base.h" -#include "vector.h" - -struct ALeffect; -struct ALeffectslot; - - -using ALeffectslotArray = al::FlexArray; - - -struct ALeffectslotProps { - ALfloat Gain; - ALboolean AuxSendAuto; - ALeffectslot *Target; - - ALenum Type; - EffectProps Props; - - EffectState *State; - - std::atomic next; -}; - - -struct ALeffectslot { - ALfloat Gain{1.0f}; - ALboolean AuxSendAuto{AL_TRUE}; - ALeffectslot *Target{nullptr}; - - struct { - ALenum Type{AL_EFFECT_NULL}; - EffectProps Props{}; - - EffectState *State{nullptr}; - } Effect; - - std::atomic_flag PropsClean; - - RefCount ref{0u}; - - std::atomic Update{nullptr}; - - struct { - ALfloat Gain{1.0f}; - ALboolean AuxSendAuto{AL_TRUE}; - ALeffectslot *Target{nullptr}; - - ALenum EffectType{AL_EFFECT_NULL}; - EffectProps mEffectProps{}; - EffectState *mEffectState{nullptr}; - - ALfloat RoomRolloff{0.0f}; /* Added to the source's room rolloff, not multiplied. */ - ALfloat DecayTime{0.0f}; - ALfloat DecayLFRatio{0.0f}; - ALfloat DecayHFRatio{0.0f}; - ALboolean DecayHFLimit{AL_FALSE}; - ALfloat AirAbsorptionGainHF{1.0f}; - } Params; - - /* Self ID */ - ALuint id{}; - - /* Mixing buffer used by the Wet mix. */ - al::vector MixBuffer; - - /* Wet buffer configuration is ACN channel order with N3D scaling. - * Consequently, effects that only want to work with mono input can use - * channel 0 by itself. Effects that want multichannel can process the - * ambisonics signal and make a B-Format source pan. - */ - MixParams Wet; - - ALeffectslot() { PropsClean.test_and_set(std::memory_order_relaxed); } - ALeffectslot(const ALeffectslot&) = delete; - ALeffectslot& operator=(const ALeffectslot&) = delete; - ~ALeffectslot(); - - static ALeffectslotArray *CreatePtrArray(size_t count) noexcept; - - DEF_PLACE_NEWDEL() -}; - -ALenum InitEffectSlot(ALeffectslot *slot); -void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context); -void UpdateAllEffectSlotProps(ALCcontext *context); - - -ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect); - -#endif diff --git a/al/alBuffer.cpp b/al/alBuffer.cpp deleted file mode 100644 index 505b9dab..00000000 --- a/al/alBuffer.cpp +++ /dev/null @@ -1,1408 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "alBuffer.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" - -#include "alError.h" -#include "albyte.h" -#include "alcmain.h" -#include "alcontext.h" -#include "alexcpt.h" -#include "almalloc.h" -#include "alnumeric.h" -#include "aloptional.h" -#include "atomic.h" -#include "inprogext.h" -#include "opthelpers.h" - - -namespace { - -/* IMA ADPCM Stepsize table */ -constexpr int IMAStep_size[89] = { - 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, - 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, - 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, - 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, - 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, - 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, - 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493,10442, - 11487,12635,13899,15289,16818,18500,20350,22358,24633,27086,29794, - 32767 -}; - -/* IMA4 ADPCM Codeword decode table */ -constexpr int IMA4Codeword[16] = { - 1, 3, 5, 7, 9, 11, 13, 15, - -1,-3,-5,-7,-9,-11,-13,-15, -}; - -/* IMA4 ADPCM Step index adjust decode table */ -constexpr int IMA4Index_adjust[16] = { - -1,-1,-1,-1, 2, 4, 6, 8, - -1,-1,-1,-1, 2, 4, 6, 8 -}; - - -/* MSADPCM Adaption table */ -constexpr int MSADPCMAdaption[16] = { - 230, 230, 230, 230, 307, 409, 512, 614, - 768, 614, 512, 409, 307, 230, 230, 230 -}; - -/* MSADPCM Adaption Coefficient tables */ -constexpr int MSADPCMAdaptionCoeff[7][2] = { - { 256, 0 }, - { 512, -256 }, - { 0, 0 }, - { 192, 64 }, - { 240, 0 }, - { 460, -208 }, - { 392, -232 } -}; - - -void DecodeIMA4Block(ALshort *dst, const al::byte *src, ALint numchans, ALsizei align) -{ - ALint sample[MAX_INPUT_CHANNELS]{}; - ALint index[MAX_INPUT_CHANNELS]{}; - ALuint code[MAX_INPUT_CHANNELS]{}; - - for(int c{0};c < numchans;c++) - { - sample[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); - sample[c] = (sample[c]^0x8000) - 32768; - src += 2; - index[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); - index[c] = clampi((index[c]^0x8000) - 32768, 0, 88); - src += 2; - - *(dst++) = sample[c]; - } - - for(int i{1};i < align;i++) - { - if((i&7) == 1) - { - for(int c{0};c < numchans;c++) - { - code[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<< 8) | - (al::to_integer(src[2])<<16) | (al::to_integer(src[3])<<24); - src += 4; - } - } - - for(int c{0};c < numchans;c++) - { - const ALuint nibble{code[c]&0xf}; - code[c] >>= 4; - - sample[c] += IMA4Codeword[nibble] * IMAStep_size[index[c]] / 8; - sample[c] = clampi(sample[c], -32768, 32767); - - index[c] += IMA4Index_adjust[nibble]; - index[c] = clampi(index[c], 0, 88); - - *(dst++) = sample[c]; - } - } -} - -void DecodeMSADPCMBlock(ALshort *dst, const al::byte *src, ALint numchans, ALsizei align) -{ - ALubyte blockpred[MAX_INPUT_CHANNELS]{}; - ALint delta[MAX_INPUT_CHANNELS]{}; - ALshort samples[MAX_INPUT_CHANNELS][2]{}; - - for(int c{0};c < numchans;c++) - { - blockpred[c] = minu(al::to_integer(src[0]), 6); - ++src; - } - for(int c{0};c < numchans;c++) - { - delta[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); - delta[c] = (delta[c]^0x8000) - 32768; - src += 2; - } - for(int c{0};c < numchans;c++) - { - samples[c][0] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); - samples[c][0] = (samples[c][0]^0x8000) - 32768; - src += 2; - } - for(int c{0};c < numchans;c++) - { - samples[c][1] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); - samples[c][1] = (samples[c][1]^0x8000) - 32768; - src += 2; - } - - /* Second sample is written first. */ - for(int c{0};c < numchans;c++) - *(dst++) = samples[c][1]; - for(int c{0};c < numchans;c++) - *(dst++) = samples[c][0]; - - int num{0}; - for(int i{2};i < align;i++) - { - for(int c{0};c < numchans;c++) - { - /* Read the nibble (first is in the upper bits). */ - al::byte nibble; - if(!(num++ & 1)) - nibble = *src >> 4; - else - nibble = *(src++) & 0x0f; - - ALint pred{(samples[c][0]*MSADPCMAdaptionCoeff[blockpred[c]][0] + - samples[c][1]*MSADPCMAdaptionCoeff[blockpred[c]][1]) / 256}; - pred += (al::to_integer(nibble^0x08) - 0x08) * delta[c]; - pred = clampi(pred, -32768, 32767); - - samples[c][1] = samples[c][0]; - samples[c][0] = pred; - - delta[c] = (MSADPCMAdaption[al::to_integer(nibble)] * delta[c]) / 256; - delta[c] = maxi(16, delta[c]); - - *(dst++) = pred; - } - } -} - -void Convert_ALshort_ALima4(ALshort *dst, const al::byte *src, ALsizei numchans, ALsizei len, - ALsizei align) -{ - const ALsizei byte_align{((align-1)/2 + 4) * numchans}; - - len /= align; - while(len--) - { - DecodeIMA4Block(dst, src, numchans, align); - src += byte_align; - dst += align*numchans; - } -} - -void Convert_ALshort_ALmsadpcm(ALshort *dst, const al::byte *src, ALsizei numchans, ALsizei len, - ALsizei align) -{ - const ALsizei byte_align{((align-2)/2 + 7) * numchans}; - - len /= align; - while(len--) - { - DecodeMSADPCMBlock(dst, src, numchans, align); - src += byte_align; - dst += align*numchans; - } -} - - -constexpr ALbitfieldSOFT INVALID_STORAGE_MASK{~unsigned(AL_MAP_READ_BIT_SOFT | - AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT)}; -constexpr ALbitfieldSOFT MAP_READ_WRITE_FLAGS{AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT}; -constexpr ALbitfieldSOFT INVALID_MAP_FLAGS{~unsigned(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | - AL_MAP_PERSISTENT_BIT_SOFT)}; - - -ALbuffer *AllocBuffer(ALCcontext *context) -{ - ALCdevice *device{context->Device}; - std::lock_guard _{device->BufferLock}; - auto sublist = std::find_if(device->BufferList.begin(), device->BufferList.end(), - [](const BufferSubList &entry) noexcept -> bool - { return entry.FreeMask != 0; } - ); - - auto lidx = static_cast(std::distance(device->BufferList.begin(), sublist)); - ALbuffer *buffer{nullptr}; - ALsizei slidx{0}; - if(LIKELY(sublist != device->BufferList.end())) - { - slidx = CTZ64(sublist->FreeMask); - buffer = sublist->Buffers + slidx; - } - else - { - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ - if(UNLIKELY(device->BufferList.size() >= 1<<25)) - { - alSetError(context, AL_OUT_OF_MEMORY, "Too many buffers allocated"); - return nullptr; - } - device->BufferList.emplace_back(); - sublist = device->BufferList.end() - 1; - sublist->FreeMask = ~0_u64; - sublist->Buffers = reinterpret_cast(al_calloc(16, sizeof(ALbuffer)*64)); - if(UNLIKELY(!sublist->Buffers)) - { - device->BufferList.pop_back(); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate buffer batch"); - return nullptr; - } - - slidx = 0; - buffer = sublist->Buffers + slidx; - } - - buffer = new (buffer) ALbuffer{}; - /* Add 1 to avoid buffer ID 0. */ - buffer->id = ((lidx<<6) | slidx) + 1; - - sublist->FreeMask &= ~(1_u64 << slidx); - - return buffer; -} - -void FreeBuffer(ALCdevice *device, ALbuffer *buffer) -{ - ALuint id{buffer->id - 1}; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; - - al::destroy_at(buffer); - - device->BufferList[lidx].FreeMask |= 1_u64 << slidx; -} - -inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) -{ - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= device->BufferList.size())) - return nullptr; - BufferSubList &sublist = device->BufferList[lidx]; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) - return nullptr; - return sublist.Buffers + slidx; -} - - -ALsizei SanitizeAlignment(UserFmtType type, ALsizei align) -{ - if(align < 0) - return 0; - - if(align == 0) - { - if(type == UserFmtIMA4) - { - /* Here is where things vary: - * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel - * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel - */ - return 65; - } - if(type == UserFmtMSADPCM) - return 64; - return 1; - } - - if(type == UserFmtIMA4) - { - /* IMA4 block alignment must be a multiple of 8, plus 1. */ - if((align&7) == 1) return align; - return 0; - } - if(type == UserFmtMSADPCM) - { - /* MSADPCM block alignment must be a multiple of 2. */ - if((align&1) == 0) return align; - return 0; - } - - return align; -} - - -const ALchar *NameFromUserFmtType(UserFmtType type) -{ - switch(type) - { - case UserFmtUByte: return "Unsigned Byte"; - case UserFmtShort: return "Signed Short"; - case UserFmtFloat: return "Float32"; - case UserFmtDouble: return "Float64"; - case UserFmtMulaw: return "muLaw"; - case UserFmtAlaw: return "aLaw"; - case UserFmtIMA4: return "IMA4 ADPCM"; - case UserFmtMSADPCM: return "MSADPCM"; - } - return ""; -} - -/* - * LoadData - * - * Loads the specified data into the buffer, using the specified format. - */ -void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, UserFmtChannels SrcChannels, UserFmtType SrcType, const al::byte *SrcData, ALbitfieldSOFT access) -{ - if(UNLIKELY(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)) - SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer %u", - ALBuf->id); - - /* Currently no channel configurations need to be converted. */ - FmtChannels DstChannels{FmtMono}; - switch(SrcChannels) - { - case UserFmtMono: DstChannels = FmtMono; break; - case UserFmtStereo: DstChannels = FmtStereo; break; - case UserFmtRear: DstChannels = FmtRear; break; - case UserFmtQuad: DstChannels = FmtQuad; break; - case UserFmtX51: DstChannels = FmtX51; break; - case UserFmtX61: DstChannels = FmtX61; break; - case UserFmtX71: DstChannels = FmtX71; break; - case UserFmtBFormat2D: DstChannels = FmtBFormat2D; break; - case UserFmtBFormat3D: DstChannels = FmtBFormat3D; break; - } - if (UNLIKELY(static_cast(SrcChannels) != - static_cast(DstChannels))) - SETERR_RETURN(context, AL_INVALID_ENUM, , "Invalid format"); - - /* IMA4 and MSADPCM convert to 16-bit short. */ - FmtType DstType{FmtUByte}; - switch(SrcType) - { - case UserFmtUByte: DstType = FmtUByte; break; - case UserFmtShort: DstType = FmtShort; break; - case UserFmtFloat: DstType = FmtFloat; break; - case UserFmtDouble: DstType = FmtDouble; break; - case UserFmtAlaw: DstType = FmtAlaw; break; - case UserFmtMulaw: DstType = FmtMulaw; break; - case UserFmtIMA4: DstType = FmtShort; break; - case UserFmtMSADPCM: DstType = FmtShort; break; - } - - /* TODO: Currently we can only map samples when they're not converted. To - * allow it would need some kind of double-buffering to hold onto a copy of - * the original data. - */ - if((access&MAP_READ_WRITE_FLAGS)) - { - if (UNLIKELY(static_cast(SrcType) != static_cast(DstType))) - SETERR_RETURN(context, AL_INVALID_VALUE, , - "%s samples cannot be mapped", - NameFromUserFmtType(SrcType)); - } - - const ALsizei unpackalign{ALBuf->UnpackAlign.load()}; - const ALsizei align{SanitizeAlignment(SrcType, unpackalign)}; - if(UNLIKELY(align < 1)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid unpack alignment %d for %s samples", - unpackalign, NameFromUserFmtType(SrcType)); - - if((access&AL_PRESERVE_DATA_BIT_SOFT)) - { - /* Can only preserve data with the same format and alignment. */ - if(UNLIKELY(ALBuf->mFmtChannels != DstChannels || ALBuf->OriginalType != SrcType)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched format"); - if(UNLIKELY(ALBuf->OriginalAlign != align)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched alignment"); - } - - /* Convert the input/source size in bytes to sample frames using the unpack - * block alignment. - */ - const ALsizei SrcByteAlign{ - (SrcType == UserFmtIMA4) ? ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels) : - (SrcType == UserFmtMSADPCM) ? ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels) : - (align * FrameSizeFromUserFmt(SrcChannels, SrcType)) - }; - if(UNLIKELY((size%SrcByteAlign) != 0)) - SETERR_RETURN(context, AL_INVALID_VALUE,, - "Data size %d is not a multiple of frame size %d (%d unpack alignment)", - size, SrcByteAlign, align); - - if(UNLIKELY(size/SrcByteAlign > std::numeric_limits::max()/align)) - SETERR_RETURN(context, AL_OUT_OF_MEMORY,, - "Buffer size overflow, %d blocks x %d samples per block", size/SrcByteAlign, align); - const ALsizei frames{size / SrcByteAlign * align}; - - /* Convert the sample frames to the number of bytes needed for internal - * storage. - */ - ALsizei NumChannels{ChannelsFromFmt(DstChannels)}; - ALsizei FrameSize{NumChannels * BytesFromFmt(DstType)}; - if(UNLIKELY(frames > std::numeric_limits::max()/FrameSize)) - SETERR_RETURN(context, AL_OUT_OF_MEMORY,, - "Buffer size overflow, %d frames x %d bytes per frame", frames, FrameSize); - size_t newsize{static_cast(frames) * FrameSize}; - - /* Round up to the next 16-byte multiple. This could reallocate only when - * increasing or the new size is less than half the current, but then the - * buffer's AL_SIZE would not be very reliable for accounting buffer memory - * usage, and reporting the real size could cause problems for apps that - * use AL_SIZE to try to get the buffer's play length. - */ - newsize = RoundUp(newsize, 16); - if(newsize != ALBuf->mData.size()) - { - auto newdata = al::vector(newsize, al::byte{}); - if((access&AL_PRESERVE_DATA_BIT_SOFT)) - { - const size_t tocopy{minz(newdata.size(), ALBuf->mData.size())}; - std::copy_n(ALBuf->mData.begin(), tocopy, newdata.begin()); - } - ALBuf->mData = std::move(newdata); - } - - if(SrcType == UserFmtIMA4) - { - assert(DstType == FmtShort); - if(SrcData != nullptr && !ALBuf->mData.empty()) - Convert_ALshort_ALima4(reinterpret_cast(ALBuf->mData.data()), - SrcData, NumChannels, frames, align); - ALBuf->OriginalAlign = align; - } - else if(SrcType == UserFmtMSADPCM) - { - assert(DstType == FmtShort); - if(SrcData != nullptr && !ALBuf->mData.empty()) - Convert_ALshort_ALmsadpcm(reinterpret_cast(ALBuf->mData.data()), - SrcData, NumChannels, frames, align); - ALBuf->OriginalAlign = align; - } - else - { - assert(static_cast(SrcType) == static_cast(DstType)); - if(SrcData != nullptr && !ALBuf->mData.empty()) - std::copy_n(SrcData, frames*FrameSize, ALBuf->mData.begin()); - ALBuf->OriginalAlign = 1; - } - ALBuf->OriginalSize = size; - ALBuf->OriginalType = SrcType; - - ALBuf->Frequency = freq; - ALBuf->mFmtChannels = DstChannels; - ALBuf->mFmtType = DstType; - ALBuf->Access = access; - - ALBuf->SampleLen = frames; - ALBuf->LoopStart = 0; - ALBuf->LoopEnd = ALBuf->SampleLen; -} - -struct DecompResult { UserFmtChannels channels; UserFmtType type; }; -al::optional DecomposeUserFormat(ALenum format) -{ - struct FormatMap { - ALenum format; - UserFmtChannels channels; - UserFmtType type; - }; - static constexpr std::array UserFmtList{{ - { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte }, - { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort }, - { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat }, - { AL_FORMAT_MONO_DOUBLE_EXT, UserFmtMono, UserFmtDouble }, - { AL_FORMAT_MONO_IMA4, UserFmtMono, UserFmtIMA4 }, - { AL_FORMAT_MONO_MSADPCM_SOFT, UserFmtMono, UserFmtMSADPCM }, - { AL_FORMAT_MONO_MULAW, UserFmtMono, UserFmtMulaw }, - { AL_FORMAT_MONO_ALAW_EXT, UserFmtMono, UserFmtAlaw }, - - { AL_FORMAT_STEREO8, UserFmtStereo, UserFmtUByte }, - { AL_FORMAT_STEREO16, UserFmtStereo, UserFmtShort }, - { AL_FORMAT_STEREO_FLOAT32, UserFmtStereo, UserFmtFloat }, - { AL_FORMAT_STEREO_DOUBLE_EXT, UserFmtStereo, UserFmtDouble }, - { AL_FORMAT_STEREO_IMA4, UserFmtStereo, UserFmtIMA4 }, - { AL_FORMAT_STEREO_MSADPCM_SOFT, UserFmtStereo, UserFmtMSADPCM }, - { AL_FORMAT_STEREO_MULAW, UserFmtStereo, UserFmtMulaw }, - { AL_FORMAT_STEREO_ALAW_EXT, UserFmtStereo, UserFmtAlaw }, - - { AL_FORMAT_REAR8, UserFmtRear, UserFmtUByte }, - { AL_FORMAT_REAR16, UserFmtRear, UserFmtShort }, - { AL_FORMAT_REAR32, UserFmtRear, UserFmtFloat }, - { AL_FORMAT_REAR_MULAW, UserFmtRear, UserFmtMulaw }, - - { AL_FORMAT_QUAD8_LOKI, UserFmtQuad, UserFmtUByte }, - { AL_FORMAT_QUAD16_LOKI, UserFmtQuad, UserFmtShort }, - - { AL_FORMAT_QUAD8, UserFmtQuad, UserFmtUByte }, - { AL_FORMAT_QUAD16, UserFmtQuad, UserFmtShort }, - { AL_FORMAT_QUAD32, UserFmtQuad, UserFmtFloat }, - { AL_FORMAT_QUAD_MULAW, UserFmtQuad, UserFmtMulaw }, - - { AL_FORMAT_51CHN8, UserFmtX51, UserFmtUByte }, - { AL_FORMAT_51CHN16, UserFmtX51, UserFmtShort }, - { AL_FORMAT_51CHN32, UserFmtX51, UserFmtFloat }, - { AL_FORMAT_51CHN_MULAW, UserFmtX51, UserFmtMulaw }, - - { AL_FORMAT_61CHN8, UserFmtX61, UserFmtUByte }, - { AL_FORMAT_61CHN16, UserFmtX61, UserFmtShort }, - { AL_FORMAT_61CHN32, UserFmtX61, UserFmtFloat }, - { AL_FORMAT_61CHN_MULAW, UserFmtX61, UserFmtMulaw }, - - { AL_FORMAT_71CHN8, UserFmtX71, UserFmtUByte }, - { AL_FORMAT_71CHN16, UserFmtX71, UserFmtShort }, - { AL_FORMAT_71CHN32, UserFmtX71, UserFmtFloat }, - { AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw }, - - { AL_FORMAT_BFORMAT2D_8, UserFmtBFormat2D, UserFmtUByte }, - { AL_FORMAT_BFORMAT2D_16, UserFmtBFormat2D, UserFmtShort }, - { AL_FORMAT_BFORMAT2D_FLOAT32, UserFmtBFormat2D, UserFmtFloat }, - { AL_FORMAT_BFORMAT2D_MULAW, UserFmtBFormat2D, UserFmtMulaw }, - - { AL_FORMAT_BFORMAT3D_8, UserFmtBFormat3D, UserFmtUByte }, - { AL_FORMAT_BFORMAT3D_16, UserFmtBFormat3D, UserFmtShort }, - { AL_FORMAT_BFORMAT3D_FLOAT32, UserFmtBFormat3D, UserFmtFloat }, - { AL_FORMAT_BFORMAT3D_MULAW, UserFmtBFormat3D, UserFmtMulaw }, - }}; - - for(const auto &fmt : UserFmtList) - { - if(fmt.format == format) - return al::make_optional(DecompResult{fmt.channels, fmt.type}); - } - return al::nullopt; -} - -} // namespace - - -AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(UNLIKELY(n < 0)) - { - alSetError(context.get(), AL_INVALID_VALUE, "Generating %d buffers", n); - return; - } - - if(LIKELY(n == 1)) - { - /* Special handling for the easy and normal case. */ - ALbuffer *buffer = AllocBuffer(context.get()); - if(buffer) buffers[0] = buffer->id; - } - else if(n > 1) - { - /* Store the allocated buffer IDs in a separate local list, to avoid - * modifying the user storage in case of failure. - */ - al::vector ids; - ids.reserve(n); - do { - ALbuffer *buffer = AllocBuffer(context.get()); - if(!buffer) - { - alDeleteBuffers(static_cast(ids.size()), ids.data()); - return; - } - - ids.emplace_back(buffer->id); - } while(--n); - std::copy(ids.begin(), ids.end(), buffers); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(UNLIKELY(n < 0)) - { - alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d buffers", n); - return; - } - if(UNLIKELY(n == 0)) - return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - /* First try to find any buffers that are invalid or in-use. */ - const ALuint *buffers_end = buffers + n; - auto invbuf = std::find_if(buffers, buffers_end, - [device, &context](ALuint bid) -> bool - { - if(!bid) return false; - ALbuffer *ALBuf = LookupBuffer(device, bid); - if(UNLIKELY(!ALBuf)) - { - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", bid); - return true; - } - if(UNLIKELY(ReadRef(&ALBuf->ref) != 0)) - { - alSetError(context.get(), AL_INVALID_OPERATION, "Deleting in-use buffer %u", bid); - return true; - } - return false; - } - ); - if(LIKELY(invbuf == buffers_end)) - { - /* All good. Delete non-0 buffer IDs. */ - std::for_each(buffers, buffers_end, - [device](ALuint bid) -> void - { - ALbuffer *buffer{bid ? LookupBuffer(device, bid) : nullptr}; - if(buffer) FreeBuffer(device, buffer); - } - ); - } -} -END_API_FUNC - -AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(LIKELY(context)) - { - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - if(!buffer || LookupBuffer(device, buffer)) - return AL_TRUE; - } - return AL_FALSE; -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq) -START_API_FUNC -{ alBufferStorageSOFT(buffer, format, data, size, freq, 0); } -END_API_FUNC - -AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(size < 0)) - alSetError(context.get(), AL_INVALID_VALUE, "Negative storage size %d", size); - else if(UNLIKELY(freq < 1)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid sample rate %d", freq); - else if(UNLIKELY((flags&INVALID_STORAGE_MASK) != 0)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid storage flags 0x%x", - flags&INVALID_STORAGE_MASK); - else if(UNLIKELY((flags&AL_MAP_PERSISTENT_BIT_SOFT) && !(flags&MAP_READ_WRITE_FLAGS))) - alSetError(context.get(), AL_INVALID_VALUE, - "Declaring persistently mapped storage without read or write access"); - else - { - auto usrfmt = DecomposeUserFormat(format); - if(UNLIKELY(!usrfmt)) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid format 0x%04x", format); - else - LoadData(context.get(), albuf, freq, size, usrfmt->channels, usrfmt->type, - static_cast(data), flags); - } -} -END_API_FUNC - -AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return nullptr; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY((access&INVALID_MAP_FLAGS) != 0)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid map flags 0x%x", access&INVALID_MAP_FLAGS); - else if(UNLIKELY(!(access&MAP_READ_WRITE_FLAGS))) - alSetError(context.get(), AL_INVALID_VALUE, "Mapping buffer %u without read or write access", - buffer); - else - { - ALbitfieldSOFT unavailable = (albuf->Access^access) & access; - if(UNLIKELY(ReadRef(&albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT))) - alSetError(context.get(), AL_INVALID_OPERATION, - "Mapping in-use buffer %u without persistent mapping", buffer); - else if(UNLIKELY(albuf->MappedAccess != 0)) - alSetError(context.get(), AL_INVALID_OPERATION, "Mapping already-mapped buffer %u", buffer); - else if(UNLIKELY((unavailable&AL_MAP_READ_BIT_SOFT))) - alSetError(context.get(), AL_INVALID_VALUE, - "Mapping buffer %u for reading without read access", buffer); - else if(UNLIKELY((unavailable&AL_MAP_WRITE_BIT_SOFT))) - alSetError(context.get(), AL_INVALID_VALUE, - "Mapping buffer %u for writing without write access", buffer); - else if(UNLIKELY((unavailable&AL_MAP_PERSISTENT_BIT_SOFT))) - alSetError(context.get(), AL_INVALID_VALUE, - "Mapping buffer %u persistently without persistent access", buffer); - else if(UNLIKELY(offset < 0 || offset >= albuf->OriginalSize || - length <= 0 || length > albuf->OriginalSize - offset)) - alSetError(context.get(), AL_INVALID_VALUE, "Mapping invalid range %d+%d for buffer %u", - offset, length, buffer); - else - { - void *retval = albuf->mData.data() + offset; - albuf->MappedAccess = access; - albuf->MappedOffset = offset; - albuf->MappedSize = length; - return retval; - } - } - - return nullptr; -} -END_API_FUNC - -AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(albuf->MappedAccess == 0) - alSetError(context.get(), AL_INVALID_OPERATION, "Unmapping unmapped buffer %u", buffer); - else - { - albuf->MappedAccess = 0; - albuf->MappedOffset = 0; - albuf->MappedSize = 0; - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT))) - alSetError(context.get(), AL_INVALID_OPERATION, - "Flushing buffer %u while not mapped for writing", buffer); - else if(UNLIKELY(offset < albuf->MappedOffset || - offset >= albuf->MappedOffset+albuf->MappedSize || - length <= 0 || length > albuf->MappedOffset+albuf->MappedSize-offset)) - alSetError(context.get(), AL_INVALID_VALUE, "Flushing invalid range %d+%d on buffer %u", - offset, length, buffer); - else - { - /* FIXME: Need to use some method of double-buffering for the mixer and - * app to hold separate memory, which can be safely transfered - * asynchronously. Currently we just say the app shouldn't write where - * OpenAL's reading, and hope for the best... - */ - std::atomic_thread_fence(std::memory_order_seq_cst); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - { - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - return; - } - - auto usrfmt = DecomposeUserFormat(format); - if(UNLIKELY(!usrfmt)) - { - alSetError(context.get(), AL_INVALID_ENUM, "Invalid format 0x%04x", format); - return; - } - - ALsizei unpack_align{albuf->UnpackAlign.load()}; - ALsizei align{SanitizeAlignment(usrfmt->type, unpack_align)}; - if(UNLIKELY(align < 1)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid unpack alignment %d", unpack_align); - else if(UNLIKELY(long{usrfmt->channels} != long{albuf->mFmtChannels} || - usrfmt->type != albuf->OriginalType)) - alSetError(context.get(), AL_INVALID_ENUM, - "Unpacking data with mismatched format"); - else if(UNLIKELY(align != albuf->OriginalAlign)) - alSetError(context.get(), AL_INVALID_VALUE, - "Unpacking data with alignment %u does not match original alignment %u", - align, albuf->OriginalAlign); - else if(UNLIKELY(albuf->MappedAccess != 0)) - alSetError(context.get(), AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u", - buffer); - else - { - ALsizei num_chans{ChannelsFromFmt(albuf->mFmtChannels)}; - ALsizei frame_size{num_chans * BytesFromFmt(albuf->mFmtType)}; - ALsizei byte_align{ - (albuf->OriginalType == UserFmtIMA4) ? ((align-1)/2 + 4) * num_chans : - (albuf->OriginalType == UserFmtMSADPCM) ? ((align-2)/2 + 7) * num_chans : - (align * frame_size) - }; - - if(UNLIKELY(offset < 0 || length < 0 || offset > albuf->OriginalSize || - length > albuf->OriginalSize-offset)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid data sub-range %d+%d on buffer %u", - offset, length, buffer); - else if(UNLIKELY((offset%byte_align) != 0)) - alSetError(context.get(), AL_INVALID_VALUE, - "Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)", - offset, byte_align, align); - else if(UNLIKELY((length%byte_align) != 0)) - alSetError(context.get(), AL_INVALID_VALUE, - "Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)", - length, byte_align, align); - else - { - /* offset -> byte offset, length -> sample count */ - offset = offset/byte_align * align * frame_size; - length = length/byte_align * align; - - void *dst = albuf->mData.data() + offset; - if(usrfmt->type == UserFmtIMA4 && albuf->mFmtType == FmtShort) - Convert_ALshort_ALima4(static_cast(dst), - static_cast(data), num_chans, length, align); - else if(usrfmt->type == UserFmtMSADPCM && albuf->mFmtType == FmtShort) - Convert_ALshort_ALmsadpcm(static_cast(dst), - static_cast(data), num_chans, length, align); - else - { - assert(long{usrfmt->type} == static_cast(albuf->mFmtType)); - memcpy(dst, data, length * frame_size); - } - } - } -} -END_API_FUNC - - -AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint /*buffer*/, ALuint /*samplerate*/, - ALenum /*internalformat*/, ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, - const ALvoid* /*data*/) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - alSetError(context.get(), AL_INVALID_OPERATION, "alBufferSamplesSOFT not supported"); -} -END_API_FUNC - -AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint /*buffer*/, ALsizei /*offset*/, - ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, const ALvoid* /*data*/) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - alSetError(context.get(), AL_INVALID_OPERATION, "alBufferSubSamplesSOFT not supported"); -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint /*buffer*/, ALsizei /*offset*/, - ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, ALvoid* /*data*/) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - alSetError(context.get(), AL_INVALID_OPERATION, "alGetBufferSamplesSOFT not supported"); -} -END_API_FUNC - -AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum /*format*/) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(!context) return AL_FALSE; - - alSetError(context.get(), AL_INVALID_OPERATION, "alIsBufferFormatSupportedSOFT not supported"); - return AL_FALSE; -} -END_API_FUNC - - -AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat /*value*/) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, - ALfloat /*value1*/, ALfloat /*value2*/, ALfloat /*value3*/) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!values)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); - } -} -END_API_FUNC - - -AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else switch(param) - { - case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: - if(UNLIKELY(value < 0)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid unpack block alignment %d", value); - else - albuf->UnpackAlign.store(value); - break; - - case AL_PACK_BLOCK_ALIGNMENT_SOFT: - if(UNLIKELY(value < 0)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid pack block alignment %d", value); - else - albuf->PackAlign.store(value); - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, - ALint /*value1*/, ALint /*value2*/, ALint /*value3*/) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values) -START_API_FUNC -{ - if(values) - { - switch(param) - { - case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: - case AL_PACK_BLOCK_ALIGNMENT_SOFT: - alBufferi(buffer, param, values[0]); - return; - } - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!values)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_LOOP_POINTS_SOFT: - if(UNLIKELY(ReadRef(&albuf->ref) != 0)) - alSetError(context.get(), AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points", - buffer); - else if(UNLIKELY(values[0] >= values[1] || values[0] < 0 || values[1] > albuf->SampleLen)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid loop point range %d -> %d o buffer %u", - values[0], values[1], buffer); - else - { - albuf->LoopStart = values[0]; - albuf->LoopEnd = values[1]; - } - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", - param); - } -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!value)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!value1 || !value2 || !value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values) -START_API_FUNC -{ - switch(param) - { - case AL_SEC_LENGTH_SOFT: - alGetBufferf(buffer, param, values); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!values)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); - } -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!value)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_FREQUENCY: - *value = albuf->Frequency; - break; - - case AL_BITS: - *value = BytesFromFmt(albuf->mFmtType) * 8; - break; - - case AL_CHANNELS: - *value = ChannelsFromFmt(albuf->mFmtChannels); - break; - - case AL_SIZE: - *value = albuf->SampleLen * FrameSizeFromFmt(albuf->mFmtChannels, albuf->mFmtType); - break; - - case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: - *value = albuf->UnpackAlign.load(); - break; - - case AL_PACK_BLOCK_ALIGNMENT_SOFT: - *value = albuf->PackAlign.load(); - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!value1 || !value2 || !value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values) -START_API_FUNC -{ - switch(param) - { - case AL_FREQUENCY: - case AL_BITS: - case AL_CHANNELS: - case AL_SIZE: - case AL_INTERNAL_FORMAT_SOFT: - case AL_BYTE_LENGTH_SOFT: - case AL_SAMPLE_LENGTH_SOFT: - case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: - case AL_PACK_BLOCK_ALIGNMENT_SOFT: - alGetBufferi(buffer, param, values); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device = context->Device; - std::lock_guard _{device->BufferLock}; - ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!values)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_LOOP_POINTS_SOFT: - values[0] = albuf->LoopStart; - values[1] = albuf->LoopEnd; - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", - param); - } -} -END_API_FUNC - - -ALsizei BytesFromUserFmt(UserFmtType type) -{ - switch(type) - { - case UserFmtUByte: return sizeof(ALubyte); - case UserFmtShort: return sizeof(ALshort); - case UserFmtFloat: return sizeof(ALfloat); - case UserFmtDouble: return sizeof(ALdouble); - case UserFmtMulaw: return sizeof(ALubyte); - case UserFmtAlaw: return sizeof(ALubyte); - case UserFmtIMA4: break; /* not handled here */ - case UserFmtMSADPCM: break; /* not handled here */ - } - return 0; -} -ALsizei ChannelsFromUserFmt(UserFmtChannels chans) -{ - switch(chans) - { - case UserFmtMono: return 1; - case UserFmtStereo: return 2; - case UserFmtRear: return 2; - case UserFmtQuad: return 4; - case UserFmtX51: return 6; - case UserFmtX61: return 7; - case UserFmtX71: return 8; - case UserFmtBFormat2D: return 3; - case UserFmtBFormat3D: return 4; - } - return 0; -} - -ALsizei BytesFromFmt(FmtType type) -{ - switch(type) - { - case FmtUByte: return sizeof(ALubyte); - case FmtShort: return sizeof(ALshort); - case FmtFloat: return sizeof(ALfloat); - case FmtDouble: return sizeof(ALdouble); - case FmtMulaw: return sizeof(ALubyte); - case FmtAlaw: return sizeof(ALubyte); - } - return 0; -} -ALsizei ChannelsFromFmt(FmtChannels chans) -{ - switch(chans) - { - case FmtMono: return 1; - case FmtStereo: return 2; - case FmtRear: return 2; - case FmtQuad: return 4; - case FmtX51: return 6; - case FmtX61: return 7; - case FmtX71: return 8; - case FmtBFormat2D: return 3; - case FmtBFormat3D: return 4; - } - return 0; -} - - -BufferSubList::~BufferSubList() -{ - uint64_t usemask{~FreeMask}; - while(usemask) - { - ALsizei idx{CTZ64(usemask)}; - al::destroy_at(Buffers+idx); - usemask &= ~(1_u64 << idx); - } - FreeMask = ~usemask; - al_free(Buffers); - Buffers = nullptr; -} diff --git a/al/alBuffer.h b/al/alBuffer.h deleted file mode 100644 index 1d5873e5..00000000 --- a/al/alBuffer.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef AL_BUFFER_H -#define AL_BUFFER_H - -#include - -#include "AL/al.h" - -#include "albyte.h" -#include "almalloc.h" -#include "atomic.h" -#include "inprogext.h" -#include "vector.h" - - -/* User formats */ -enum UserFmtType : unsigned char { - UserFmtUByte, - UserFmtShort, - UserFmtFloat, - UserFmtDouble, - UserFmtMulaw, - UserFmtAlaw, - UserFmtIMA4, - UserFmtMSADPCM, -}; -enum UserFmtChannels : unsigned char { - UserFmtMono, - UserFmtStereo, - UserFmtRear, - UserFmtQuad, - UserFmtX51, /* (WFX order) */ - UserFmtX61, /* (WFX order) */ - UserFmtX71, /* (WFX order) */ - UserFmtBFormat2D, /* WXY */ - UserFmtBFormat3D, /* WXYZ */ -}; - -ALsizei BytesFromUserFmt(UserFmtType type); -ALsizei ChannelsFromUserFmt(UserFmtChannels chans); -inline ALsizei FrameSizeFromUserFmt(UserFmtChannels chans, UserFmtType type) -{ return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type); } - - -/* Storable formats */ -enum FmtType : unsigned char { - FmtUByte = UserFmtUByte, - FmtShort = UserFmtShort, - FmtFloat = UserFmtFloat, - FmtDouble = UserFmtDouble, - FmtMulaw = UserFmtMulaw, - FmtAlaw = UserFmtAlaw, -}; -enum FmtChannels : unsigned char { - FmtMono = UserFmtMono, - FmtStereo = UserFmtStereo, - FmtRear = UserFmtRear, - FmtQuad = UserFmtQuad, - FmtX51 = UserFmtX51, - FmtX61 = UserFmtX61, - FmtX71 = UserFmtX71, - FmtBFormat2D = UserFmtBFormat2D, - FmtBFormat3D = UserFmtBFormat3D, -}; -#define MAX_INPUT_CHANNELS (8) - -/* DevFmtType traits, providing the type, etc given a DevFmtType. */ -template -struct FmtTypeTraits { }; - -template<> -struct FmtTypeTraits { using Type = ALubyte; }; -template<> -struct FmtTypeTraits { using Type = ALshort; }; -template<> -struct FmtTypeTraits { using Type = ALfloat; }; -template<> -struct FmtTypeTraits { using Type = ALdouble; }; -template<> -struct FmtTypeTraits { using Type = ALubyte; }; -template<> -struct FmtTypeTraits { using Type = ALubyte; }; - - -ALsizei BytesFromFmt(FmtType type); -ALsizei ChannelsFromFmt(FmtChannels chans); -inline ALsizei FrameSizeFromFmt(FmtChannels chans, FmtType type) -{ return ChannelsFromFmt(chans) * BytesFromFmt(type); } - - -struct ALbuffer { - al::vector mData; - - ALsizei Frequency{0}; - ALbitfieldSOFT Access{0u}; - ALsizei SampleLen{0}; - - FmtChannels mFmtChannels{}; - FmtType mFmtType{}; - - UserFmtType OriginalType{}; - ALsizei OriginalSize{0}; - ALsizei OriginalAlign{0}; - - ALsizei LoopStart{0}; - ALsizei LoopEnd{0}; - - std::atomic UnpackAlign{0}; - std::atomic PackAlign{0}; - - ALbitfieldSOFT MappedAccess{0u}; - ALsizei MappedOffset{0}; - ALsizei MappedSize{0}; - - /* Number of times buffer was attached to a source (deletion can only occur when 0) */ - RefCount ref{0u}; - - /* Self ID */ - ALuint id{0}; -}; - -#endif diff --git a/al/alEffect.cpp b/al/alEffect.cpp deleted file mode 100644 index 4a75f69f..00000000 --- a/al/alEffect.cpp +++ /dev/null @@ -1,742 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "alEffect.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" -#include "AL/efx-presets.h" -#include "AL/efx.h" - -#include "alError.h" -#include "alcmain.h" -#include "alcontext.h" -#include "alexcpt.h" -#include "almalloc.h" -#include "alnumeric.h" -#include "effects/base.h" -#include "logging.h" -#include "opthelpers.h" -#include "vector.h" - - -const EffectList gEffectList[15]{ - { "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB }, - { "reverb", REVERB_EFFECT, AL_EFFECT_REVERB }, - { "autowah", AUTOWAH_EFFECT, AL_EFFECT_AUTOWAH }, - { "chorus", CHORUS_EFFECT, AL_EFFECT_CHORUS }, - { "compressor", COMPRESSOR_EFFECT, AL_EFFECT_COMPRESSOR }, - { "distortion", DISTORTION_EFFECT, AL_EFFECT_DISTORTION }, - { "echo", ECHO_EFFECT, AL_EFFECT_ECHO }, - { "equalizer", EQUALIZER_EFFECT, AL_EFFECT_EQUALIZER }, - { "flanger", FLANGER_EFFECT, AL_EFFECT_FLANGER }, - { "fshifter", FSHIFTER_EFFECT, AL_EFFECT_FREQUENCY_SHIFTER }, - { "modulator", MODULATOR_EFFECT, AL_EFFECT_RING_MODULATOR }, - { "pshifter", PSHIFTER_EFFECT, AL_EFFECT_PITCH_SHIFTER }, - { "vmorpher", VMORPHER_EFFECT, AL_EFFECT_VOCAL_MORPHER }, - { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT }, - { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_DIALOGUE }, -}; - -ALboolean DisabledEffects[MAX_EFFECTS]; - -namespace { - -constexpr struct FactoryItem { - ALenum Type; - EffectStateFactory* (&GetFactory)(void); -} FactoryList[] = { - { AL_EFFECT_NULL, NullStateFactory_getFactory }, - { AL_EFFECT_EAXREVERB, ReverbStateFactory_getFactory }, - { AL_EFFECT_REVERB, StdReverbStateFactory_getFactory }, - { AL_EFFECT_AUTOWAH, AutowahStateFactory_getFactory }, - { AL_EFFECT_CHORUS, ChorusStateFactory_getFactory }, - { AL_EFFECT_COMPRESSOR, CompressorStateFactory_getFactory }, - { AL_EFFECT_DISTORTION, DistortionStateFactory_getFactory }, - { AL_EFFECT_ECHO, EchoStateFactory_getFactory }, - { AL_EFFECT_EQUALIZER, EqualizerStateFactory_getFactory }, - { AL_EFFECT_FLANGER, FlangerStateFactory_getFactory }, - { AL_EFFECT_FREQUENCY_SHIFTER, FshifterStateFactory_getFactory }, - { AL_EFFECT_RING_MODULATOR, ModulatorStateFactory_getFactory }, - { AL_EFFECT_PITCH_SHIFTER, PshifterStateFactory_getFactory}, - { AL_EFFECT_VOCAL_MORPHER, VmorpherStateFactory_getFactory}, - { AL_EFFECT_DEDICATED_DIALOGUE, DedicatedStateFactory_getFactory }, - { AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedStateFactory_getFactory } -}; - - -template -void ALeffect_setParami(ALeffect *effect, T&& ...args) -{ effect->vtab->setParami(&effect->Props, std::forward(args)...); } -template -void ALeffect_setParamiv(ALeffect *effect, T&& ...args) -{ effect->vtab->setParamiv(&effect->Props, std::forward(args)...); } -template -void ALeffect_setParamf(ALeffect *effect, T&& ...args) -{ effect->vtab->setParamf(&effect->Props, std::forward(args)...); } -template -void ALeffect_setParamfv(ALeffect *effect, T&& ...args) -{ effect->vtab->setParamfv(&effect->Props, std::forward(args)...); } - -template -void ALeffect_getParami(const ALeffect *effect, T&& ...args) -{ effect->vtab->getParami(&effect->Props, std::forward(args)...); } -template -void ALeffect_getParamiv(const ALeffect *effect, T&& ...args) -{ effect->vtab->getParamiv(&effect->Props, std::forward(args)...); } -template -void ALeffect_getParamf(const ALeffect *effect, T&& ...args) -{ effect->vtab->getParamf(&effect->Props, std::forward(args)...); } -template -void ALeffect_getParamfv(const ALeffect *effect, T&& ...args) -{ effect->vtab->getParamfv(&effect->Props, std::forward(args)...); } - - -void InitEffectParams(ALeffect *effect, ALenum type) -{ - EffectStateFactory *factory = getFactoryByType(type); - if(factory) - { - effect->Props = factory->getDefaultProps(); - effect->vtab = factory->getEffectVtable(); - } - else - { - effect->Props = EffectProps {}; - effect->vtab = nullptr; - } - effect->type = type; -} - -ALeffect *AllocEffect(ALCcontext *context) -{ - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - auto sublist = std::find_if(device->EffectList.begin(), device->EffectList.end(), - [](const EffectSubList &entry) noexcept -> bool - { return entry.FreeMask != 0; } - ); - - auto lidx = static_cast(std::distance(device->EffectList.begin(), sublist)); - ALeffect *effect{nullptr}; - ALsizei slidx{0}; - if(LIKELY(sublist != device->EffectList.end())) - { - slidx = CTZ64(sublist->FreeMask); - effect = sublist->Effects + slidx; - } - else - { - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ - if(UNLIKELY(device->EffectList.size() >= 1<<25)) - { - alSetError(context, AL_OUT_OF_MEMORY, "Too many effects allocated"); - return nullptr; - } - device->EffectList.emplace_back(); - sublist = device->EffectList.end() - 1; - sublist->FreeMask = ~0_u64; - sublist->Effects = static_cast(al_calloc(16, sizeof(ALeffect)*64)); - if(UNLIKELY(!sublist->Effects)) - { - device->EffectList.pop_back(); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect batch"); - return nullptr; - } - - slidx = 0; - effect = sublist->Effects + slidx; - } - - effect = new (effect) ALeffect{}; - InitEffectParams(effect, AL_EFFECT_NULL); - - /* Add 1 to avoid effect ID 0. */ - effect->id = ((lidx<<6) | slidx) + 1; - - sublist->FreeMask &= ~(1_u64 << slidx); - - return effect; -} - -void FreeEffect(ALCdevice *device, ALeffect *effect) -{ - ALuint id = effect->id - 1; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; - - al::destroy_at(effect); - - device->EffectList[lidx].FreeMask |= 1_u64 << slidx; -} - -inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) -{ - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= device->EffectList.size())) - return nullptr; - EffectSubList &sublist = device->EffectList[lidx]; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) - return nullptr; - return sublist.Effects + slidx; -} - -} // namespace - -AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(UNLIKELY(n < 0)) - { - alSetError(context.get(), AL_INVALID_VALUE, "Generating %d effects", n); - return; - } - - if(LIKELY(n == 1)) - { - /* Special handling for the easy and normal case. */ - ALeffect *effect = AllocEffect(context.get()); - if(effect) effects[0] = effect->id; - } - else if(n > 1) - { - /* Store the allocated buffer IDs in a separate local list, to avoid - * modifying the user storage in case of failure. - */ - al::vector ids; - ids.reserve(n); - do { - ALeffect *effect = AllocEffect(context.get()); - if(!effect) - { - alDeleteEffects(static_cast(ids.size()), ids.data()); - return; - } - - ids.emplace_back(effect->id); - } while(--n); - std::copy(ids.begin(), ids.end(), effects); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(UNLIKELY(n < 0)) - { - alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d effects", n); - return; - } - if(UNLIKELY(n == 0)) - return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - - /* First try to find any effects that are invalid. */ - const ALuint *effects_end = effects + n; - auto inveffect = std::find_if(effects, effects_end, - [device, &context](ALuint eid) -> bool - { - if(!eid) return false; - ALeffect *effect{LookupEffect(device, eid)}; - if(UNLIKELY(!effect)) - { - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", eid); - return true; - } - return false; - } - ); - if(LIKELY(inveffect == effects_end)) - { - /* All good. Delete non-0 effect IDs. */ - std::for_each(effects, effects_end, - [device](ALuint eid) -> void - { - ALeffect *effect{eid ? LookupEffect(device, eid) : nullptr}; - if(effect) FreeEffect(device, effect); - } - ); - } -} -END_API_FUNC - -AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(LIKELY(context)) - { - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - if(!effect || LookupEffect(device, effect)) - return AL_TRUE; - } - return AL_FALSE; -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - - ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - if(param == AL_EFFECT_TYPE) - { - ALboolean isOk{value == AL_EFFECT_NULL}; - if(!isOk) - { - for(const EffectList &effectitem : gEffectList) - { - if(value == effectitem.val && !DisabledEffects[effectitem.type]) - { - isOk = AL_TRUE; - break; - } - } - } - - if(isOk) - InitEffectParams(aleffect, value); - else - alSetError(context.get(), AL_INVALID_VALUE, "Effect type 0x%04x not supported", value); - } - else - { - /* Call the appropriate handler */ - ALeffect_setParami(aleffect, context.get(), param, value); - } - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *values) -START_API_FUNC -{ - switch(param) - { - case AL_EFFECT_TYPE: - alEffecti(effect, param, values[0]); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - - ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - /* Call the appropriate handler */ - ALeffect_setParamiv(aleffect, context.get(), param, values); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - - ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - /* Call the appropriate handler */ - ALeffect_setParamf(aleffect, context.get(), param, value); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - - ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - /* Call the appropriate handler */ - ALeffect_setParamfv(aleffect, context.get(), param, values); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - - const ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - if(param == AL_EFFECT_TYPE) - *value = aleffect->type; - else - { - /* Call the appropriate handler */ - ALeffect_getParami(aleffect, context.get(), param, value); - } - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *values) -START_API_FUNC -{ - switch(param) - { - case AL_EFFECT_TYPE: - alGetEffecti(effect, param, values); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - - const ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - /* Call the appropriate handler */ - ALeffect_getParamiv(aleffect, context.get(), param, values); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - - const ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - /* Call the appropriate handler */ - ALeffect_getParamf(aleffect, context.get(), param, value); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->EffectLock}; - - const ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); - else - { - /* Call the appropriate handler */ - ALeffect_getParamfv(aleffect, context.get(), param, values); - } -} -END_API_FUNC - - -void InitEffect(ALeffect *effect) -{ - InitEffectParams(effect, AL_EFFECT_NULL); -} - -EffectSubList::~EffectSubList() -{ - uint64_t usemask{~FreeMask}; - while(usemask) - { - ALsizei idx = CTZ64(usemask); - al::destroy_at(Effects+idx); - usemask &= ~(1_u64 << idx); - } - FreeMask = ~usemask; - al_free(Effects); - Effects = nullptr; -} - - -EffectStateFactory *getFactoryByType(ALenum type) -{ - auto iter = std::find_if(std::begin(FactoryList), std::end(FactoryList), - [type](const FactoryItem &item) noexcept -> bool - { return item.Type == type; } - ); - return (iter != std::end(FactoryList)) ? iter->GetFactory() : nullptr; -} - - -#define DECL(x) { #x, EFX_REVERB_PRESET_##x } -static const struct { - const char name[32]; - EFXEAXREVERBPROPERTIES props; -} reverblist[] = { - DECL(GENERIC), - DECL(PADDEDCELL), - DECL(ROOM), - DECL(BATHROOM), - DECL(LIVINGROOM), - DECL(STONEROOM), - DECL(AUDITORIUM), - DECL(CONCERTHALL), - DECL(CAVE), - DECL(ARENA), - DECL(HANGAR), - DECL(CARPETEDHALLWAY), - DECL(HALLWAY), - DECL(STONECORRIDOR), - DECL(ALLEY), - DECL(FOREST), - DECL(CITY), - DECL(MOUNTAINS), - DECL(QUARRY), - DECL(PLAIN), - DECL(PARKINGLOT), - DECL(SEWERPIPE), - DECL(UNDERWATER), - DECL(DRUGGED), - DECL(DIZZY), - DECL(PSYCHOTIC), - - DECL(CASTLE_SMALLROOM), - DECL(CASTLE_SHORTPASSAGE), - DECL(CASTLE_MEDIUMROOM), - DECL(CASTLE_LARGEROOM), - DECL(CASTLE_LONGPASSAGE), - DECL(CASTLE_HALL), - DECL(CASTLE_CUPBOARD), - DECL(CASTLE_COURTYARD), - DECL(CASTLE_ALCOVE), - - DECL(FACTORY_SMALLROOM), - DECL(FACTORY_SHORTPASSAGE), - DECL(FACTORY_MEDIUMROOM), - DECL(FACTORY_LARGEROOM), - DECL(FACTORY_LONGPASSAGE), - DECL(FACTORY_HALL), - DECL(FACTORY_CUPBOARD), - DECL(FACTORY_COURTYARD), - DECL(FACTORY_ALCOVE), - - DECL(ICEPALACE_SMALLROOM), - DECL(ICEPALACE_SHORTPASSAGE), - DECL(ICEPALACE_MEDIUMROOM), - DECL(ICEPALACE_LARGEROOM), - DECL(ICEPALACE_LONGPASSAGE), - DECL(ICEPALACE_HALL), - DECL(ICEPALACE_CUPBOARD), - DECL(ICEPALACE_COURTYARD), - DECL(ICEPALACE_ALCOVE), - - DECL(SPACESTATION_SMALLROOM), - DECL(SPACESTATION_SHORTPASSAGE), - DECL(SPACESTATION_MEDIUMROOM), - DECL(SPACESTATION_LARGEROOM), - DECL(SPACESTATION_LONGPASSAGE), - DECL(SPACESTATION_HALL), - DECL(SPACESTATION_CUPBOARD), - DECL(SPACESTATION_ALCOVE), - - DECL(WOODEN_SMALLROOM), - DECL(WOODEN_SHORTPASSAGE), - DECL(WOODEN_MEDIUMROOM), - DECL(WOODEN_LARGEROOM), - DECL(WOODEN_LONGPASSAGE), - DECL(WOODEN_HALL), - DECL(WOODEN_CUPBOARD), - DECL(WOODEN_COURTYARD), - DECL(WOODEN_ALCOVE), - - DECL(SPORT_EMPTYSTADIUM), - DECL(SPORT_SQUASHCOURT), - DECL(SPORT_SMALLSWIMMINGPOOL), - DECL(SPORT_LARGESWIMMINGPOOL), - DECL(SPORT_GYMNASIUM), - DECL(SPORT_FULLSTADIUM), - DECL(SPORT_STADIUMTANNOY), - - DECL(PREFAB_WORKSHOP), - DECL(PREFAB_SCHOOLROOM), - DECL(PREFAB_PRACTISEROOM), - DECL(PREFAB_OUTHOUSE), - DECL(PREFAB_CARAVAN), - - DECL(DOME_TOMB), - DECL(PIPE_SMALL), - DECL(DOME_SAINTPAULS), - DECL(PIPE_LONGTHIN), - DECL(PIPE_LARGE), - DECL(PIPE_RESONANT), - - DECL(OUTDOORS_BACKYARD), - DECL(OUTDOORS_ROLLINGPLAINS), - DECL(OUTDOORS_DEEPCANYON), - DECL(OUTDOORS_CREEK), - DECL(OUTDOORS_VALLEY), - - DECL(MOOD_HEAVEN), - DECL(MOOD_HELL), - DECL(MOOD_MEMORY), - - DECL(DRIVING_COMMENTATOR), - DECL(DRIVING_PITGARAGE), - DECL(DRIVING_INCAR_RACER), - DECL(DRIVING_INCAR_SPORTS), - DECL(DRIVING_INCAR_LUXURY), - DECL(DRIVING_FULLGRANDSTAND), - DECL(DRIVING_EMPTYGRANDSTAND), - DECL(DRIVING_TUNNEL), - - DECL(CITY_STREETS), - DECL(CITY_SUBWAY), - DECL(CITY_MUSEUM), - DECL(CITY_LIBRARY), - DECL(CITY_UNDERPASS), - DECL(CITY_ABANDONED), - - DECL(DUSTYROOM), - DECL(CHAPEL), - DECL(SMALLWATERROOM), -}; -#undef DECL - -void LoadReverbPreset(const char *name, ALeffect *effect) -{ - if(strcasecmp(name, "NONE") == 0) - { - InitEffectParams(effect, AL_EFFECT_NULL); - TRACE("Loading reverb '%s'\n", "NONE"); - return; - } - - if(!DisabledEffects[EAXREVERB_EFFECT]) - InitEffectParams(effect, AL_EFFECT_EAXREVERB); - else if(!DisabledEffects[REVERB_EFFECT]) - InitEffectParams(effect, AL_EFFECT_REVERB); - else - InitEffectParams(effect, AL_EFFECT_NULL); - for(const auto &reverbitem : reverblist) - { - const EFXEAXREVERBPROPERTIES *props; - - if(strcasecmp(name, reverbitem.name) != 0) - continue; - - TRACE("Loading reverb '%s'\n", reverbitem.name); - props = &reverbitem.props; - effect->Props.Reverb.Density = props->flDensity; - effect->Props.Reverb.Diffusion = props->flDiffusion; - effect->Props.Reverb.Gain = props->flGain; - effect->Props.Reverb.GainHF = props->flGainHF; - effect->Props.Reverb.GainLF = props->flGainLF; - effect->Props.Reverb.DecayTime = props->flDecayTime; - effect->Props.Reverb.DecayHFRatio = props->flDecayHFRatio; - effect->Props.Reverb.DecayLFRatio = props->flDecayLFRatio; - effect->Props.Reverb.ReflectionsGain = props->flReflectionsGain; - effect->Props.Reverb.ReflectionsDelay = props->flReflectionsDelay; - effect->Props.Reverb.ReflectionsPan[0] = props->flReflectionsPan[0]; - effect->Props.Reverb.ReflectionsPan[1] = props->flReflectionsPan[1]; - effect->Props.Reverb.ReflectionsPan[2] = props->flReflectionsPan[2]; - effect->Props.Reverb.LateReverbGain = props->flLateReverbGain; - effect->Props.Reverb.LateReverbDelay = props->flLateReverbDelay; - effect->Props.Reverb.LateReverbPan[0] = props->flLateReverbPan[0]; - effect->Props.Reverb.LateReverbPan[1] = props->flLateReverbPan[1]; - effect->Props.Reverb.LateReverbPan[2] = props->flLateReverbPan[2]; - effect->Props.Reverb.EchoTime = props->flEchoTime; - effect->Props.Reverb.EchoDepth = props->flEchoDepth; - effect->Props.Reverb.ModulationTime = props->flModulationTime; - effect->Props.Reverb.ModulationDepth = props->flModulationDepth; - effect->Props.Reverb.AirAbsorptionGainHF = props->flAirAbsorptionGainHF; - effect->Props.Reverb.HFReference = props->flHFReference; - effect->Props.Reverb.LFReference = props->flLFReference; - effect->Props.Reverb.RoomRolloffFactor = props->flRoomRolloffFactor; - effect->Props.Reverb.DecayHFLimit = props->iDecayHFLimit; - return; - } - - WARN("Reverb preset '%s' not found\n", name); -} diff --git a/al/alEffect.h b/al/alEffect.h deleted file mode 100644 index 270b8e20..00000000 --- a/al/alEffect.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef AL_EFFECT_H -#define AL_EFFECT_H - -#include "AL/al.h" -#include "AL/efx.h" - -#include "effects/base.h" - - -enum { - EAXREVERB_EFFECT = 0, - REVERB_EFFECT, - AUTOWAH_EFFECT, - CHORUS_EFFECT, - COMPRESSOR_EFFECT, - DISTORTION_EFFECT, - ECHO_EFFECT, - EQUALIZER_EFFECT, - FLANGER_EFFECT, - FSHIFTER_EFFECT, - MODULATOR_EFFECT, - PSHIFTER_EFFECT, - VMORPHER_EFFECT, - DEDICATED_EFFECT, - - MAX_EFFECTS -}; -extern ALboolean DisabledEffects[MAX_EFFECTS]; - -extern ALfloat ReverbBoost; - -struct EffectList { - const char name[16]; - int type; - ALenum val; -}; -extern const EffectList gEffectList[15]; - - -struct ALeffect { - // Effect type (AL_EFFECT_NULL, ...) - ALenum type{AL_EFFECT_NULL}; - - EffectProps Props{}; - - const EffectVtable *vtab{nullptr}; - - /* Self ID */ - ALuint id{0u}; -}; - -inline ALboolean IsReverbEffect(ALenum type) -{ return type == AL_EFFECT_REVERB || type == AL_EFFECT_EAXREVERB; } - -EffectStateFactory *getFactoryByType(ALenum type); - -void InitEffect(ALeffect *effect); - -void LoadReverbPreset(const char *name, ALeffect *effect); - -#endif diff --git a/al/alError.cpp b/al/alError.cpp deleted file mode 100644 index bff92444..00000000 --- a/al/alError.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2000 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "alError.h" - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" - -#include "alcontext.h" -#include "alexcpt.h" -#include "almalloc.h" -#include "event.h" -#include "inprogext.h" -#include "logging.h" -#include "opthelpers.h" -#include "vector.h" - - -bool TrapALError{false}; - -void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) -{ - auto message = al::vector(256); - - va_list args, args2; - va_start(args, msg); - va_copy(args2, args); - int msglen{std::vsnprintf(message.data(), message.size(), msg, args)}; - if(msglen >= 0 && static_cast(msglen) >= message.size()) - { - message.resize(static_cast(msglen) + 1u); - msglen = std::vsnprintf(message.data(), message.size(), msg, args2); - } - va_end(args2); - va_end(args); - - if(msglen >= 0) msg = message.data(); - else msg = ""; - msglen = static_cast(strlen(msg)); - - WARN("Error generated on context %p, code 0x%04x, \"%s\"\n", context, errorCode, msg); - if(TrapALError) - { -#ifdef _WIN32 - /* DebugBreak will cause an exception if there is no debugger */ - if(IsDebuggerPresent()) - DebugBreak(); -#elif defined(SIGTRAP) - raise(SIGTRAP); -#endif - } - - ALenum curerr{AL_NO_ERROR}; - context->LastError.compare_exchange_strong(curerr, errorCode); - if((context->EnabledEvts.load(std::memory_order_relaxed)&EventType_Error)) - { - std::lock_guard _{context->EventCbLock}; - ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; - if((enabledevts&EventType_Error) && context->EventCb) - (*context->EventCb)(AL_EVENT_TYPE_ERROR_SOFT, 0, errorCode, msglen, msg, - context->EventParam); - } -} - -AL_API ALenum AL_APIENTRY alGetError(void) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) - { - constexpr ALenum deferror{AL_INVALID_OPERATION}; - WARN("Querying error state on null context (implicitly 0x%04x)\n", deferror); - if(TrapALError) - { -#ifdef _WIN32 - if(IsDebuggerPresent()) - DebugBreak(); -#elif defined(SIGTRAP) - raise(SIGTRAP); -#endif - } - return deferror; - } - - return context->LastError.exchange(AL_NO_ERROR); -} -END_API_FUNC diff --git a/al/alError.h b/al/alError.h deleted file mode 100644 index 6408b60c..00000000 --- a/al/alError.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef AL_ERROR_H -#define AL_ERROR_H - -#include "AL/al.h" -#include "AL/alc.h" - -#include "logging.h" - - -extern bool TrapALError; - -void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) DECL_FORMAT(printf, 3, 4); - -#define SETERR_GOTO(ctx, err, lbl, ...) do { \ - alSetError((ctx), (err), __VA_ARGS__); \ - goto lbl; \ -} while(0) - -#define SETERR_RETURN(ctx, err, retval, ...) do { \ - alSetError((ctx), (err), __VA_ARGS__); \ - return retval; \ -} while(0) - -#endif diff --git a/al/alExtension.cpp b/al/alExtension.cpp deleted file mode 100644 index 80681090..00000000 --- a/al/alExtension.cpp +++ /dev/null @@ -1,80 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" - -#include "alError.h" -#include "alcontext.h" -#include "alexcpt.h" -#include "opthelpers.h" - - -AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return AL_FALSE; - - if(!extName) - SETERR_RETURN(context.get(), AL_INVALID_VALUE, AL_FALSE, "NULL pointer"); - - size_t len{strlen(extName)}; - const char *ptr{context->ExtensionList}; - while(ptr && *ptr) - { - if(strncasecmp(ptr, extName, len) == 0 && - (ptr[len] == '\0' || isspace(ptr[len]))) - return AL_TRUE; - - if((ptr=strchr(ptr, ' ')) != nullptr) - { - do { - ++ptr; - } while(isspace(*ptr)); - } - } - - return AL_FALSE; -} -END_API_FUNC - - -AL_API ALvoid* AL_APIENTRY alGetProcAddress(const ALchar *funcName) -START_API_FUNC -{ - if(!funcName) return nullptr; - return alcGetProcAddress(nullptr, funcName); -} -END_API_FUNC - -AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *enumName) -START_API_FUNC -{ - if(!enumName) return static_cast(0); - return alcGetEnumValue(nullptr, enumName); -} -END_API_FUNC diff --git a/al/alFilter.cpp b/al/alFilter.cpp deleted file mode 100644 index 31fbaf21..00000000 --- a/al/alFilter.cpp +++ /dev/null @@ -1,665 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "alFilter.h" - -#include -#include -#include -#include -#include -#include - -#include "AL/efx.h" - -#include "alError.h" -#include "alcmain.h" -#include "alcontext.h" -#include "alexcpt.h" -#include "almalloc.h" -#include "alnumeric.h" -#include "opthelpers.h" -#include "vector.h" - - -namespace { - -#define FILTER_MIN_GAIN 0.0f -#define FILTER_MAX_GAIN 4.0f /* +12dB */ - -void ALlowpass_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } -void ALlowpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } -void ALlowpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_LOWPASS_GAIN: - if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gain %f out of range", val); - filter->Gain = val; - break; - - case AL_LOWPASS_GAINHF: - if(!(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gainhf %f out of range", val); - filter->GainHF = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param); - } -} -void ALlowpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) -{ ALlowpass_setParamf(filter, context, param, vals[0]); } - -void ALlowpass_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } -void ALlowpass_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } -void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_LOWPASS_GAIN: - *val = filter->Gain; - break; - - case AL_LOWPASS_GAINHF: - *val = filter->GainHF; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param); - } -} -void ALlowpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) -{ ALlowpass_getParamf(filter, context, param, vals); } - -DEFINE_ALFILTER_VTABLE(ALlowpass); - - -void ALhighpass_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } -void ALhighpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } -void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_HIGHPASS_GAIN: - if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gain out of range"); - filter->Gain = val; - break; - - case AL_HIGHPASS_GAINLF: - if(!(val >= AL_HIGHPASS_MIN_GAINLF && val <= AL_HIGHPASS_MAX_GAINLF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gainlf out of range"); - filter->GainLF = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param); - } -} -void ALhighpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) -{ ALhighpass_setParamf(filter, context, param, vals[0]); } - -void ALhighpass_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } -void ALhighpass_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } -void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_HIGHPASS_GAIN: - *val = filter->Gain; - break; - - case AL_HIGHPASS_GAINLF: - *val = filter->GainLF; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param); - } -} -void ALhighpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) -{ ALhighpass_getParamf(filter, context, param, vals); } - -DEFINE_ALFILTER_VTABLE(ALhighpass); - - -void ALbandpass_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } -void ALbandpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } -void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) -{ - switch(param) - { - case AL_BANDPASS_GAIN: - if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gain out of range"); - filter->Gain = val; - break; - - case AL_BANDPASS_GAINHF: - if(!(val >= AL_BANDPASS_MIN_GAINHF && val <= AL_BANDPASS_MAX_GAINHF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainhf out of range"); - filter->GainHF = val; - break; - - case AL_BANDPASS_GAINLF: - if(!(val >= AL_BANDPASS_MIN_GAINLF && val <= AL_BANDPASS_MAX_GAINLF)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainlf out of range"); - filter->GainLF = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param); - } -} -void ALbandpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) -{ ALbandpass_setParamf(filter, context, param, vals[0]); } - -void ALbandpass_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } -void ALbandpass_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } -void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) -{ - switch(param) - { - case AL_BANDPASS_GAIN: - *val = filter->Gain; - break; - - case AL_BANDPASS_GAINHF: - *val = filter->GainHF; - break; - - case AL_BANDPASS_GAINLF: - *val = filter->GainLF; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param); - } -} -void ALbandpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) -{ ALbandpass_getParamf(filter, context, param, vals); } - -DEFINE_ALFILTER_VTABLE(ALbandpass); - - -void ALnullfilter_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -void ALnullfilter_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -void ALnullfilter_setParamf(ALfilter*, ALCcontext *context, ALenum param, ALfloat) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -void ALnullfilter_setParamfv(ALfilter*, ALCcontext *context, ALenum param, const ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } - -void ALnullfilter_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -void ALnullfilter_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -void ALnullfilter_getParamf(ALfilter*, ALCcontext *context, ALenum param, ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } -void ALnullfilter_getParamfv(ALfilter*, ALCcontext *context, ALenum param, ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } - -DEFINE_ALFILTER_VTABLE(ALnullfilter); - - -void InitFilterParams(ALfilter *filter, ALenum type) -{ - if(type == AL_FILTER_LOWPASS) - { - filter->Gain = AL_LOWPASS_DEFAULT_GAIN; - filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF; - filter->HFReference = LOWPASSFREQREF; - filter->GainLF = 1.0f; - filter->LFReference = HIGHPASSFREQREF; - filter->vtab = &ALlowpass_vtable; - } - else if(type == AL_FILTER_HIGHPASS) - { - filter->Gain = AL_HIGHPASS_DEFAULT_GAIN; - filter->GainHF = 1.0f; - filter->HFReference = LOWPASSFREQREF; - filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF; - filter->LFReference = HIGHPASSFREQREF; - filter->vtab = &ALhighpass_vtable; - } - else if(type == AL_FILTER_BANDPASS) - { - filter->Gain = AL_BANDPASS_DEFAULT_GAIN; - filter->GainHF = AL_BANDPASS_DEFAULT_GAINHF; - filter->HFReference = LOWPASSFREQREF; - filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF; - filter->LFReference = HIGHPASSFREQREF; - filter->vtab = &ALbandpass_vtable; - } - else - { - filter->Gain = 1.0f; - filter->GainHF = 1.0f; - filter->HFReference = LOWPASSFREQREF; - filter->GainLF = 1.0f; - filter->LFReference = HIGHPASSFREQREF; - filter->vtab = &ALnullfilter_vtable; - } - filter->type = type; -} - -ALfilter *AllocFilter(ALCcontext *context) -{ - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - auto sublist = std::find_if(device->FilterList.begin(), device->FilterList.end(), - [](const FilterSubList &entry) noexcept -> bool - { return entry.FreeMask != 0; } - ); - - auto lidx = static_cast(std::distance(device->FilterList.begin(), sublist)); - ALfilter *filter{nullptr}; - ALsizei slidx{0}; - if(LIKELY(sublist != device->FilterList.end())) - { - slidx = CTZ64(sublist->FreeMask); - filter = sublist->Filters + slidx; - } - else - { - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ - if(UNLIKELY(device->FilterList.size() >= 1<<25)) - { - alSetError(context, AL_OUT_OF_MEMORY, "Too many filters allocated"); - return nullptr; - } - device->FilterList.emplace_back(); - sublist = device->FilterList.end() - 1; - sublist->FreeMask = ~0_u64; - sublist->Filters = static_cast(al_calloc(16, sizeof(ALfilter)*64)); - if(UNLIKELY(!sublist->Filters)) - { - device->FilterList.pop_back(); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate filter batch"); - return nullptr; - } - - slidx = 0; - filter = sublist->Filters + slidx; - } - - filter = new (filter) ALfilter{}; - InitFilterParams(filter, AL_FILTER_NULL); - - /* Add 1 to avoid filter ID 0. */ - filter->id = ((lidx<<6) | slidx) + 1; - - sublist->FreeMask &= ~(1_u64 << slidx); - - return filter; -} - -void FreeFilter(ALCdevice *device, ALfilter *filter) -{ - ALuint id = filter->id - 1; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; - - al::destroy_at(filter); - - device->FilterList[lidx].FreeMask |= 1_u64 << slidx; -} - - -inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) -{ - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= device->FilterList.size())) - return nullptr; - FilterSubList &sublist = device->FilterList[lidx]; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) - return nullptr; - return sublist.Filters + slidx; -} - -} // namespace - -AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(UNLIKELY(n < 0)) - { - alSetError(context.get(), AL_INVALID_VALUE, "Generating %d filters", n); - return; - } - - if(LIKELY(n == 1)) - { - /* Special handling for the easy and normal case. */ - ALfilter *filter = AllocFilter(context.get()); - if(filter) filters[0] = filter->id; - } - else if(n > 1) - { - /* Store the allocated buffer IDs in a separate local list, to avoid - * modifying the user storage in case of failure. - */ - al::vector ids; - ids.reserve(n); - do { - ALfilter *filter = AllocFilter(context.get()); - if(!filter) - { - alDeleteFilters(static_cast(ids.size()), ids.data()); - return; - } - - ids.emplace_back(filter->id); - } while(--n); - std::copy(ids.begin(), ids.end(), filters); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(UNLIKELY(n < 0)) - { - alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d filters", n); - return; - } - if(UNLIKELY(n == 0)) - return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - - /* First try to find any filters that are invalid. */ - const ALuint *filters_end = filters + n; - auto invflt = std::find_if(filters, filters_end, - [device, &context](ALuint fid) -> bool - { - if(!fid) return false; - ALfilter *filter{LookupFilter(device, fid)}; - if(UNLIKELY(!filter)) - { - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", fid); - return true; - } - return false; - } - ); - if(LIKELY(invflt == filters_end)) - { - /* All good. Delete non-0 filter IDs. */ - std::for_each(filters, filters_end, - [device](ALuint fid) -> void - { - ALfilter *filter{fid ? LookupFilter(device, fid) : nullptr}; - if(filter) FreeFilter(device, filter); - } - ); - } -} -END_API_FUNC - -AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(LIKELY(context)) - { - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - if(!filter || LookupFilter(device, filter)) - return AL_TRUE; - } - return AL_FALSE; -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - - ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - if(param == AL_FILTER_TYPE) - { - if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS || - value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS) - InitFilterParams(alfilt, value); - else - alSetError(context.get(), AL_INVALID_VALUE, "Invalid filter type 0x%04x", value); - } - else - { - /* Call the appropriate handler */ - ALfilter_setParami(alfilt, context.get(), param, value); - } - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *values) -START_API_FUNC -{ - switch(param) - { - case AL_FILTER_TYPE: - alFilteri(filter, param, values[0]); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - - ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_setParamiv(alfilt, context.get(), param, values); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - - ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_setParamf(alfilt, context.get(), param, value); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - - ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_setParamfv(alfilt, context.get(), param, values); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - - ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - if(param == AL_FILTER_TYPE) - *value = alfilt->type; - else - { - /* Call the appropriate handler */ - ALfilter_getParami(alfilt, context.get(), param, value); - } - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *values) -START_API_FUNC -{ - switch(param) - { - case AL_FILTER_TYPE: - alGetFilteri(filter, param, values); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - - ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_getParamiv(alfilt, context.get(), param, values); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - - ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_getParamf(alfilt, context.get(), param, value); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCdevice *device{context->Device}; - std::lock_guard _{device->FilterLock}; - - ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); - else - { - /* Call the appropriate handler */ - ALfilter_getParamfv(alfilt, context.get(), param, values); - } -} -END_API_FUNC - - -FilterSubList::~FilterSubList() -{ - uint64_t usemask{~FreeMask}; - while(usemask) - { - ALsizei idx = CTZ64(usemask); - al::destroy_at(Filters+idx); - usemask &= ~(1_u64 << idx); - } - FreeMask = ~usemask; - al_free(Filters); - Filters = nullptr; -} diff --git a/al/alFilter.h b/al/alFilter.h deleted file mode 100644 index db098d70..00000000 --- a/al/alFilter.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef AL_FILTER_H -#define AL_FILTER_H - -#include "AL/al.h" -#include "AL/alc.h" - - -#define LOWPASSFREQREF (5000.0f) -#define HIGHPASSFREQREF (250.0f) - - -struct ALfilter; - -struct ALfilterVtable { - void (*const setParami)(ALfilter *filter, ALCcontext *context, ALenum param, ALint val); - void (*const setParamiv)(ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals); - void (*const setParamf)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val); - void (*const setParamfv)(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals); - - void (*const getParami)(ALfilter *filter, ALCcontext *context, ALenum param, ALint *val); - void (*const getParamiv)(ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals); - void (*const getParamf)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val); - void (*const getParamfv)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals); -}; - -#define DEFINE_ALFILTER_VTABLE(T) \ -const ALfilterVtable T##_vtable = { \ - T##_setParami, T##_setParamiv, T##_setParamf, T##_setParamfv, \ - T##_getParami, T##_getParamiv, T##_getParamf, T##_getParamfv, \ -} - -struct ALfilter { - // Filter type (AL_FILTER_NULL, ...) - ALenum type; - - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - - const ALfilterVtable *vtab; - - /* Self ID */ - ALuint id; -}; -#define ALfilter_setParami(o, c, p, v) ((o)->vtab->setParami(o, c, p, v)) -#define ALfilter_setParamf(o, c, p, v) ((o)->vtab->setParamf(o, c, p, v)) -#define ALfilter_setParamiv(o, c, p, v) ((o)->vtab->setParamiv(o, c, p, v)) -#define ALfilter_setParamfv(o, c, p, v) ((o)->vtab->setParamfv(o, c, p, v)) -#define ALfilter_getParami(o, c, p, v) ((o)->vtab->getParami(o, c, p, v)) -#define ALfilter_getParamf(o, c, p, v) ((o)->vtab->getParamf(o, c, p, v)) -#define ALfilter_getParamiv(o, c, p, v) ((o)->vtab->getParamiv(o, c, p, v)) -#define ALfilter_getParamfv(o, c, p, v) ((o)->vtab->getParamfv(o, c, p, v)) - -#endif diff --git a/al/alListener.cpp b/al/alListener.cpp deleted file mode 100644 index d3bf3aaa..00000000 --- a/al/alListener.cpp +++ /dev/null @@ -1,454 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2000 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "alListener.h" - -#include -#include - -#include "AL/efx.h" - -#include "alError.h" -#include "alcontext.h" -#include "alexcpt.h" -#include "almalloc.h" -#include "atomic.h" -#include "opthelpers.h" - - -#define DO_UPDATEPROPS() do { \ - if(!context->DeferUpdates.load(std::memory_order_acquire)) \ - UpdateListenerProps(context.get()); \ - else \ - listener.PropsClean.clear(std::memory_order_release); \ -} while(0) - - -AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; - switch(param) - { - case AL_GAIN: - if(!(value >= 0.0f && std::isfinite(value))) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener gain out of range"); - listener.Gain = value; - DO_UPDATEPROPS(); - break; - - case AL_METERS_PER_UNIT: - if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, - "Listener meters per unit out of range"); - context->MetersPerUnit = value; - if(!context->DeferUpdates.load(std::memory_order_acquire)) - UpdateContextProps(context.get()); - else - context->PropsClean.clear(std::memory_order_release); - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float property"); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; - switch(param) - { - case AL_POSITION: - if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3))) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener position out of range"); - listener.Position[0] = value1; - listener.Position[1] = value2; - listener.Position[2] = value3; - DO_UPDATEPROPS(); - break; - - case AL_VELOCITY: - if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3))) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener velocity out of range"); - listener.Velocity[0] = value1; - listener.Velocity[1] = value2; - listener.Velocity[2] = value3; - DO_UPDATEPROPS(); - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-float property"); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) -START_API_FUNC -{ - if(values) - { - switch(param) - { - case AL_GAIN: - case AL_METERS_PER_UNIT: - alListenerf(param, values[0]); - return; - - case AL_POSITION: - case AL_VELOCITY: - alListener3f(param, values[0], values[1], values[2]); - return; - } - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; - if(!values) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "NULL pointer"); - switch(param) - { - case AL_ORIENTATION: - if(!(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) && - std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5]))) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener orientation out of range"); - /* AT then UP */ - listener.OrientAt[0] = values[0]; - listener.OrientAt[1] = values[1]; - listener.OrientAt[2] = values[2]; - listener.OrientUp[0] = values[3]; - listener.OrientUp[1] = values[4]; - listener.OrientUp[2] = values[5]; - DO_UPDATEPROPS(); - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float-vector property"); - } -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint /*value*/) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer property"); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3) -START_API_FUNC -{ - switch(param) - { - case AL_POSITION: - case AL_VELOCITY: - alListener3f(param, static_cast(value1), static_cast(value2), static_cast(value3)); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-integer property"); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values) -START_API_FUNC -{ - if(values) - { - ALfloat fvals[6]; - switch(param) - { - case AL_POSITION: - case AL_VELOCITY: - alListener3f(param, static_cast(values[0]), static_cast(values[1]), static_cast(values[2])); - return; - - case AL_ORIENTATION: - fvals[0] = static_cast(values[0]); - fvals[1] = static_cast(values[1]); - fvals[2] = static_cast(values[2]); - fvals[3] = static_cast(values[3]); - fvals[4] = static_cast(values[4]); - fvals[5] = static_cast(values[5]); - alListenerfv(param, fvals); - return; - } - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer-vector property"); - } -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; - if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_GAIN: - *value = listener.Gain; - break; - - case AL_METERS_PER_UNIT: - *value = context->MetersPerUnit; - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float property"); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; - if(!value1 || !value2 || !value3) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_POSITION: - *value1 = listener.Position[0]; - *value2 = listener.Position[1]; - *value3 = listener.Position[2]; - break; - - case AL_VELOCITY: - *value1 = listener.Velocity[0]; - *value2 = listener.Velocity[1]; - *value3 = listener.Velocity[2]; - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-float property"); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) -START_API_FUNC -{ - switch(param) - { - case AL_GAIN: - case AL_METERS_PER_UNIT: - alGetListenerf(param, values); - return; - - case AL_POSITION: - case AL_VELOCITY: - alGetListener3f(param, values+0, values+1, values+2); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; - if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_ORIENTATION: - // AT then UP - values[0] = listener.OrientAt[0]; - values[1] = listener.OrientAt[1]; - values[2] = listener.OrientAt[2]; - values[3] = listener.OrientUp[0]; - values[4] = listener.OrientUp[1]; - values[5] = listener.OrientUp[2]; - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float-vector property"); - } -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer property"); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; - if(!value1 || !value2 || !value3) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_POSITION: - *value1 = static_cast(listener.Position[0]); - *value2 = static_cast(listener.Position[1]); - *value3 = static_cast(listener.Position[2]); - break; - - case AL_VELOCITY: - *value1 = static_cast(listener.Velocity[0]); - *value2 = static_cast(listener.Velocity[1]); - *value3 = static_cast(listener.Velocity[2]); - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-integer property"); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) -START_API_FUNC -{ - switch(param) - { - case AL_POSITION: - case AL_VELOCITY: - alGetListener3i(param, values+0, values+1, values+2); - return; - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; - if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(param) - { - case AL_ORIENTATION: - // AT then UP - values[0] = static_cast(listener.OrientAt[0]); - values[1] = static_cast(listener.OrientAt[1]); - values[2] = static_cast(listener.OrientAt[2]); - values[3] = static_cast(listener.OrientUp[0]); - values[4] = static_cast(listener.OrientUp[1]); - values[5] = static_cast(listener.OrientUp[2]); - break; - - default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer-vector property"); - } -} -END_API_FUNC - - -void UpdateListenerProps(ALCcontext *context) -{ - /* Get an unused proprty container, or allocate a new one as needed. */ - ALlistenerProps *props{context->FreeListenerProps.load(std::memory_order_acquire)}; - if(!props) - props = static_cast(al_calloc(16, sizeof(*props))); - else - { - ALlistenerProps *next; - do { - next = props->next.load(std::memory_order_relaxed); - } while(context->FreeListenerProps.compare_exchange_weak(props, next, - std::memory_order_seq_cst, std::memory_order_acquire) == 0); - } - - /* Copy in current property values. */ - ALlistener &listener = context->Listener; - props->Position = listener.Position; - props->Velocity = listener.Velocity; - props->OrientAt = listener.OrientAt; - props->OrientUp = listener.OrientUp; - props->Gain = listener.Gain; - - /* Set the new container for updating internal parameters. */ - props = listener.Update.exchange(props, std::memory_order_acq_rel); - if(props) - { - /* If there was an unused update container, put it back in the - * freelist. - */ - AtomicReplaceHead(context->FreeListenerProps, props); - } -} diff --git a/al/alListener.h b/al/alListener.h deleted file mode 100644 index a71db9f8..00000000 --- a/al/alListener.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef AL_LISTENER_H -#define AL_LISTENER_H - -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" - -#include "vecmat.h" - -enum class DistanceModel; - - -struct ALlistenerProps { - std::array Position; - std::array Velocity; - std::array OrientAt; - std::array OrientUp; - ALfloat Gain; - - std::atomic next; -}; - -struct ALlistener { - std::array Position{{0.0f, 0.0f, 0.0f}}; - std::array Velocity{{0.0f, 0.0f, 0.0f}}; - std::array OrientAt{{0.0f, 0.0f, -1.0f}}; - std::array OrientUp{{0.0f, 1.0f, 0.0f}}; - ALfloat Gain{1.0f}; - - std::atomic_flag PropsClean; - - /* Pointer to the most recent property values that are awaiting an update. - */ - std::atomic Update{nullptr}; - - struct { - alu::Matrix Matrix; - alu::Vector Velocity; - - ALfloat Gain; - ALfloat MetersPerUnit; - - ALfloat DopplerFactor; - ALfloat SpeedOfSound; /* in units per sec! */ - ALfloat ReverbSpeedOfSound; /* in meters per sec! */ - - ALboolean SourceDistanceModel; - DistanceModel mDistanceModel; - } Params; - - ALlistener() { PropsClean.test_and_set(std::memory_order_relaxed); } -}; - -void UpdateListenerProps(ALCcontext *context); - -#endif diff --git a/al/alSource.cpp b/al/alSource.cpp deleted file mode 100644 index fdd063ac..00000000 --- a/al/alSource.cpp +++ /dev/null @@ -1,3639 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "alSource.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" -#include "AL/efx.h" - -#include "alAuxEffectSlot.h" -#include "alBuffer.h" -#include "alError.h" -#include "alFilter.h" -#include "alcmain.h" -#include "alcontext.h" -#include "alexcpt.h" -#include "almalloc.h" -#include "alnumeric.h" -#include "alu.h" -#include "ambidefs.h" -#include "atomic.h" -#include "backends/base.h" -#include "bformatdec.h" -#include "event.h" -#include "filters/nfc.h" -#include "filters/splitter.h" -#include "inprogext.h" -#include "logging.h" -#include "math_defs.h" -#include "opthelpers.h" -#include "ringbuffer.h" -#include "threads.h" - - -namespace { - -using namespace std::placeholders; - -inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) -{ - ALint idx{source->VoiceIdx}; - if(idx >= 0 && static_cast(idx) < context->VoiceCount.load(std::memory_order_relaxed)) - { - ALuint sid{source->id}; - ALvoice &voice = (*context->Voices)[idx]; - if(voice.mSourceID.load(std::memory_order_acquire) == sid) - return &voice; - } - source->VoiceIdx = -1; - return nullptr; -} - -void UpdateSourceProps(const ALsource *source, ALvoice *voice, ALCcontext *context) -{ - /* Get an unused property container, or allocate a new one as needed. */ - ALvoiceProps *props{context->FreeVoiceProps.load(std::memory_order_acquire)}; - if(!props) - props = new ALvoiceProps{}; - else - { - ALvoiceProps *next; - do { - next = props->next.load(std::memory_order_relaxed); - } while(context->FreeVoiceProps.compare_exchange_weak(props, next, - std::memory_order_acq_rel, std::memory_order_acquire) == 0); - } - - /* Copy in current property values. */ - props->Pitch = source->Pitch; - props->Gain = source->Gain; - props->OuterGain = source->OuterGain; - props->MinGain = source->MinGain; - props->MaxGain = source->MaxGain; - props->InnerAngle = source->InnerAngle; - props->OuterAngle = source->OuterAngle; - props->RefDistance = source->RefDistance; - props->MaxDistance = source->MaxDistance; - props->RolloffFactor = source->RolloffFactor; - props->Position = source->Position; - props->Velocity = source->Velocity; - props->Direction = source->Direction; - props->OrientAt = source->OrientAt; - props->OrientUp = source->OrientUp; - props->HeadRelative = source->HeadRelative; - props->mDistanceModel = source->mDistanceModel; - props->mResampler = source->mResampler; - props->DirectChannels = source->DirectChannels; - props->mSpatializeMode = source->mSpatialize; - - props->DryGainHFAuto = source->DryGainHFAuto; - props->WetGainAuto = source->WetGainAuto; - props->WetGainHFAuto = source->WetGainHFAuto; - props->OuterGainHF = source->OuterGainHF; - - props->AirAbsorptionFactor = source->AirAbsorptionFactor; - props->RoomRolloffFactor = source->RoomRolloffFactor; - props->DopplerFactor = source->DopplerFactor; - - props->StereoPan = source->StereoPan; - - props->Radius = source->Radius; - - props->Direct.Gain = source->Direct.Gain; - props->Direct.GainHF = source->Direct.GainHF; - props->Direct.HFReference = source->Direct.HFReference; - props->Direct.GainLF = source->Direct.GainLF; - props->Direct.LFReference = source->Direct.LFReference; - - auto copy_send = [](const ALsource::SendData &srcsend) noexcept -> ALvoicePropsBase::SendData - { - ALvoicePropsBase::SendData ret; - ret.Slot = srcsend.Slot; - ret.Gain = srcsend.Gain; - ret.GainHF = srcsend.GainHF; - ret.HFReference = srcsend.HFReference; - ret.GainLF = srcsend.GainLF; - ret.LFReference = srcsend.LFReference; - return ret; - }; - std::transform(source->Send.cbegin(), source->Send.cend(), props->Send, copy_send); - - /* Set the new container for updating internal parameters. */ - props = voice->mUpdate.exchange(props, std::memory_order_acq_rel); - if(props) - { - /* If there was an unused update container, put it back in the - * freelist. - */ - AtomicReplaceHead(context->FreeVoiceProps, props); - } -} - -/* GetSourceSampleOffset - * - * Gets the current read offset for the given Source, in 32.32 fixed-point - * samples. The offset is relative to the start of the queue (not the start of - * the current buffer). - */ -int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, std::chrono::nanoseconds *clocktime) -{ - ALCdevice *device{context->Device}; - const ALbufferlistitem *Current; - uint64_t readPos; - ALuint refcount; - ALvoice *voice; - - do { - Current = nullptr; - readPos = 0; - while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) - std::this_thread::yield(); - *clocktime = GetDeviceClockTime(device); - - voice = GetSourceVoice(Source, context); - if(voice) - { - Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); - - readPos = uint64_t{voice->mPosition.load(std::memory_order_relaxed)} << 32; - readPos |= int64_t{voice->mPositionFrac.load(std::memory_order_relaxed)} << - (32-FRACTIONBITS); - } - std::atomic_thread_fence(std::memory_order_acquire); - } while(refcount != device->MixCount.load(std::memory_order_relaxed)); - - if(voice) - { - const ALbufferlistitem *BufferList{Source->queue}; - while(BufferList && BufferList != Current) - { - readPos += int64_t{BufferList->max_samples} << 32; - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - readPos = minu64(readPos, 0x7fffffffffffffff_u64); - } - - return static_cast(readPos); -} - -/* GetSourceSecOffset - * - * Gets the current read offset for the given Source, in seconds. The offset is - * relative to the start of the queue (not the start of the current buffer). - */ -ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, std::chrono::nanoseconds *clocktime) -{ - ALCdevice *device{context->Device}; - const ALbufferlistitem *Current; - uint64_t readPos; - ALuint refcount; - ALvoice *voice; - - do { - Current = nullptr; - readPos = 0; - while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) - std::this_thread::yield(); - *clocktime = GetDeviceClockTime(device); - - voice = GetSourceVoice(Source, context); - if(voice) - { - Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); - - readPos = uint64_t{voice->mPosition.load(std::memory_order_relaxed)} << FRACTIONBITS; - readPos |= voice->mPositionFrac.load(std::memory_order_relaxed); - } - std::atomic_thread_fence(std::memory_order_acquire); - } while(refcount != device->MixCount.load(std::memory_order_relaxed)); - - ALdouble offset{0.0}; - if(voice) - { - const ALbufferlistitem *BufferList{Source->queue}; - const ALbuffer *BufferFmt{nullptr}; - while(BufferList && BufferList != Current) - { - for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i) - BufferFmt = BufferList->buffers[i]; - readPos += int64_t{BufferList->max_samples} << FRACTIONBITS; - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - - while(BufferList && !BufferFmt) - { - for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i) - BufferFmt = BufferList->buffers[i]; - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - assert(BufferFmt != nullptr); - - offset = static_cast(readPos) / static_castFRACTIONONE / - static_cast(BufferFmt->Frequency); - } - - return offset; -} - -/* GetSourceOffset - * - * Gets the current read offset for the given Source, in the appropriate format - * (Bytes, Samples or Seconds). The offset is relative to the start of the - * queue (not the start of the current buffer). - */ -ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) -{ - ALCdevice *device{context->Device}; - const ALbufferlistitem *Current; - ALuint readPos; - ALsizei readPosFrac; - ALuint refcount; - ALvoice *voice; - - do { - Current = nullptr; - readPos = readPosFrac = 0; - while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) - std::this_thread::yield(); - voice = GetSourceVoice(Source, context); - if(voice) - { - Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); - - readPos = voice->mPosition.load(std::memory_order_relaxed); - readPosFrac = voice->mPositionFrac.load(std::memory_order_relaxed); - } - std::atomic_thread_fence(std::memory_order_acquire); - } while(refcount != device->MixCount.load(std::memory_order_relaxed)); - - ALdouble offset{0.0}; - if(voice) - { - const ALbufferlistitem *BufferList{Source->queue}; - const ALbuffer *BufferFmt{nullptr}; - ALboolean readFin{AL_FALSE}; - ALuint totalBufferLen{0u}; - - while(BufferList) - { - for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i) - BufferFmt = BufferList->buffers[i]; - - readFin |= (BufferList == Current); - totalBufferLen += BufferList->max_samples; - if(!readFin) readPos += BufferList->max_samples; - - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - assert(BufferFmt != nullptr); - - if(Source->Looping) - readPos %= totalBufferLen; - else - { - /* Wrap back to 0 */ - if(readPos >= totalBufferLen) - readPos = readPosFrac = 0; - } - - offset = 0.0; - switch(name) - { - case AL_SEC_OFFSET: - offset = (readPos + static_cast(readPosFrac)/FRACTIONONE) / BufferFmt->Frequency; - break; - - case AL_SAMPLE_OFFSET: - offset = readPos + static_cast(readPosFrac)/FRACTIONONE; - break; - - case AL_BYTE_OFFSET: - if(BufferFmt->OriginalType == UserFmtIMA4) - { - ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; - ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->mFmtChannels); - ALuint FrameBlockSize = BufferFmt->OriginalAlign; - - /* Round down to nearest ADPCM block */ - offset = static_cast(readPos / FrameBlockSize * BlockSize); - } - else if(BufferFmt->OriginalType == UserFmtMSADPCM) - { - ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; - ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->mFmtChannels); - ALuint FrameBlockSize = BufferFmt->OriginalAlign; - - /* Round down to nearest ADPCM block */ - offset = static_cast(readPos / FrameBlockSize * BlockSize); - } - else - { - const ALsizei FrameSize{FrameSizeFromFmt(BufferFmt->mFmtChannels, - BufferFmt->mFmtType)}; - offset = static_cast(readPos * FrameSize); - } - break; - } - } - - return offset; -} - - -/* GetSampleOffset - * - * Retrieves the sample offset into the Source's queue (from the Sample, Byte - * or Second offset supplied by the application). This takes into account the - * fact that the buffer format may have been modifed since. - */ -ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac) -{ - const ALbuffer *BufferFmt{nullptr}; - const ALbufferlistitem *BufferList; - - /* Find the first valid Buffer in the Queue */ - BufferList = Source->queue; - while(BufferList) - { - for(ALsizei i{0};i < BufferList->num_buffers && !BufferFmt;i++) - BufferFmt = BufferList->buffers[i]; - if(BufferFmt) break; - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - if(!BufferFmt) - { - Source->OffsetType = AL_NONE; - Source->Offset = 0.0; - return AL_FALSE; - } - - ALdouble dbloff, dblfrac; - switch(Source->OffsetType) - { - case AL_BYTE_OFFSET: - /* Determine the ByteOffset (and ensure it is block aligned) */ - *offset = static_cast(Source->Offset); - if(BufferFmt->OriginalType == UserFmtIMA4) - { - ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; - *offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels); - *offset *= BufferFmt->OriginalAlign; - } - else if(BufferFmt->OriginalType == UserFmtMSADPCM) - { - ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; - *offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels); - *offset *= BufferFmt->OriginalAlign; - } - else - *offset /= FrameSizeFromFmt(BufferFmt->mFmtChannels, BufferFmt->mFmtType); - *frac = 0; - break; - - case AL_SAMPLE_OFFSET: - dblfrac = modf(Source->Offset, &dbloff); - *offset = static_cast(mind(dbloff, std::numeric_limits::max())); - *frac = static_cast(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0)); - break; - - case AL_SEC_OFFSET: - dblfrac = modf(Source->Offset*BufferFmt->Frequency, &dbloff); - *offset = static_cast(mind(dbloff, std::numeric_limits::max())); - *frac = static_cast(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0)); - break; - } - Source->OffsetType = AL_NONE; - Source->Offset = 0.0; - - return AL_TRUE; -} - -/* ApplyOffset - * - * Apply the stored playback offset to the Source. This function will update - * the number of buffers "played" given the stored offset. - */ -ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) -{ - /* Get sample frame offset */ - ALuint offset{0u}; - ALsizei frac{0}; - if(!GetSampleOffset(Source, &offset, &frac)) - return AL_FALSE; - - ALuint totalBufferLen{0u}; - ALbufferlistitem *BufferList{Source->queue}; - while(BufferList && totalBufferLen <= offset) - { - if(static_cast(BufferList->max_samples) > offset-totalBufferLen) - { - /* Offset is in this buffer */ - voice->mPosition.store(offset - totalBufferLen, std::memory_order_relaxed); - voice->mPositionFrac.store(frac, std::memory_order_relaxed); - voice->mCurrentBuffer.store(BufferList, std::memory_order_release); - return AL_TRUE; - } - totalBufferLen += BufferList->max_samples; - - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - - /* Offset is out of range of the queue */ - return AL_FALSE; -} - - -ALsource *AllocSource(ALCcontext *context) -{ - ALCdevice *device{context->Device}; - std::lock_guard _{context->SourceLock}; - if(context->NumSources >= device->SourcesMax) - { - alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax); - return nullptr; - } - auto sublist = std::find_if(context->SourceList.begin(), context->SourceList.end(), - [](const SourceSubList &entry) noexcept -> bool - { return entry.FreeMask != 0; } - ); - auto lidx = static_cast(std::distance(context->SourceList.begin(), sublist)); - ALsource *source; - ALsizei slidx; - if(LIKELY(sublist != context->SourceList.end())) - { - slidx = CTZ64(sublist->FreeMask); - source = sublist->Sources + slidx; - } - else - { - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ - if(UNLIKELY(context->SourceList.size() >= 1<<25)) - { - alSetError(context, AL_OUT_OF_MEMORY, "Too many sources allocated"); - return nullptr; - } - context->SourceList.emplace_back(); - sublist = context->SourceList.end() - 1; - - sublist->FreeMask = ~0_u64; - sublist->Sources = static_cast(al_calloc(16, sizeof(ALsource)*64)); - if(UNLIKELY(!sublist->Sources)) - { - context->SourceList.pop_back(); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate source batch"); - return nullptr; - } - - slidx = 0; - source = sublist->Sources + slidx; - } - - source = new (source) ALsource{device->NumAuxSends}; - - /* Add 1 to avoid source ID 0. */ - source->id = ((lidx<<6) | slidx) + 1; - - context->NumSources += 1; - sublist->FreeMask &= ~(1_u64 << slidx); - - return source; -} - -void FreeSource(ALCcontext *context, ALsource *source) -{ - ALuint id = source->id - 1; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; - - ALCdevice *device{context->Device}; - BackendUniqueLock backlock{*device->Backend}; - if(ALvoice *voice{GetSourceVoice(source, context)}) - { - voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed); - voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); - voice->mSourceID.store(0u, std::memory_order_relaxed); - std::atomic_thread_fence(std::memory_order_release); - /* Don't set the voice to stopping if it was already stopped or - * stopping. - */ - ALvoice::State oldvstate{ALvoice::Playing}; - voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping, - std::memory_order_acq_rel, std::memory_order_acquire); - } - backlock.unlock(); - - al::destroy_at(source); - - context->SourceList[lidx].FreeMask |= 1_u64 << slidx; - context->NumSources--; -} - - -inline ALsource *LookupSource(ALCcontext *context, ALuint id) noexcept -{ - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= context->SourceList.size())) - return nullptr; - SourceSubList &sublist{context->SourceList[lidx]}; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) - return nullptr; - return sublist.Sources + slidx; -} - -inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) noexcept -{ - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= device->BufferList.size())) - return nullptr; - BufferSubList &sublist = device->BufferList[lidx]; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) - return nullptr; - return sublist.Buffers + slidx; -} - -inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) noexcept -{ - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= device->FilterList.size())) - return nullptr; - FilterSubList &sublist = device->FilterList[lidx]; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) - return nullptr; - return sublist.Filters + slidx; -} - -inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept -{ - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; - - if(UNLIKELY(lidx >= context->EffectSlotList.size())) - return nullptr; - EffectSlotSubList &sublist{context->EffectSlotList[lidx]}; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) - return nullptr; - return sublist.EffectSlots + slidx; -} - - -enum SourceProp : ALenum { - srcPitch = AL_PITCH, - srcGain = AL_GAIN, - srcMinGain = AL_MIN_GAIN, - srcMaxGain = AL_MAX_GAIN, - srcMaxDistance = AL_MAX_DISTANCE, - srcRolloffFactor = AL_ROLLOFF_FACTOR, - srcDopplerFactor = AL_DOPPLER_FACTOR, - srcConeOuterGain = AL_CONE_OUTER_GAIN, - srcSecOffset = AL_SEC_OFFSET, - srcSampleOffset = AL_SAMPLE_OFFSET, - srcByteOffset = AL_BYTE_OFFSET, - srcConeInnerAngle = AL_CONE_INNER_ANGLE, - srcConeOuterAngle = AL_CONE_OUTER_ANGLE, - srcRefDistance = AL_REFERENCE_DISTANCE, - - srcPosition = AL_POSITION, - srcVelocity = AL_VELOCITY, - srcDirection = AL_DIRECTION, - - srcSourceRelative = AL_SOURCE_RELATIVE, - srcLooping = AL_LOOPING, - srcBuffer = AL_BUFFER, - srcSourceState = AL_SOURCE_STATE, - srcBuffersQueued = AL_BUFFERS_QUEUED, - srcBuffersProcessed = AL_BUFFERS_PROCESSED, - srcSourceType = AL_SOURCE_TYPE, - - /* ALC_EXT_EFX */ - srcConeOuterGainHF = AL_CONE_OUTER_GAINHF, - srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR, - srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR, - srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO, - srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, - srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, - srcDirectFilter = AL_DIRECT_FILTER, - srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER, - - /* AL_SOFT_direct_channels */ - srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT, - - /* AL_EXT_source_distance_model */ - srcDistanceModel = AL_DISTANCE_MODEL, - - /* AL_SOFT_source_latency */ - srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT, - srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT, - - /* AL_EXT_STEREO_ANGLES */ - srcAngles = AL_STEREO_ANGLES, - - /* AL_EXT_SOURCE_RADIUS */ - srcRadius = AL_SOURCE_RADIUS, - - /* AL_EXT_BFORMAT */ - srcOrientation = AL_ORIENTATION, - - /* AL_SOFT_source_resampler */ - srcResampler = AL_SOURCE_RESAMPLER_SOFT, - - /* AL_SOFT_source_spatialize */ - srcSpatialize = AL_SOURCE_SPATIALIZE_SOFT, - - /* ALC_SOFT_device_clock */ - srcSampleOffsetClockSOFT = AL_SAMPLE_OFFSET_CLOCK_SOFT, - srcSecOffsetClockSOFT = AL_SEC_OFFSET_CLOCK_SOFT, -}; - -/** - * Returns if the last known state for the source was playing or paused. Does - * not sync with the mixer voice. - */ -inline bool IsPlayingOrPaused(ALsource *source) -{ return source->state == AL_PLAYING || source->state == AL_PAUSED; } - -/** - * Returns an updated source state using the matching voice's status (or lack - * thereof). - */ -inline ALenum GetSourceState(ALsource *source, ALvoice *voice) -{ - if(!voice && source->state == AL_PLAYING) - source->state = AL_STOPPED; - return source->state; -} - -/** - * Returns if the source should specify an update, given the context's - * deferring state and the source's last known state. - */ -inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context) -{ - return !context->DeferUpdates.load(std::memory_order_acquire) && - IsPlayingOrPaused(source); -} - - -/** Can only be called while the mixer is locked! */ -void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) -{ - ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)}; - if(!(enabledevt&EventType_SourceStateChange)) return; - - /* The mixer may have queued a state change that's not yet been processed, - * and we don't want state change messages to occur out of order, so send - * it through the async queue to ensure proper ordering. - */ - RingBuffer *ring{context->AsyncEvents.get()}; - auto evt_vec = ring->getWriteVector(); - if(evt_vec.first.len < 1) return; - - AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_SourceStateChange}}; - evt->u.srcstate.id = id; - evt->u.srcstate.state = state; - ring->writeAdvance(1); - context->EventSem.post(); -} - - -ALint FloatValsByProp(ALenum prop) -{ - switch(static_cast(prop)) - { - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_REFERENCE_DISTANCE: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_SOURCE_RADIUS: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - return 1; - - case AL_STEREO_ANGLES: - return 2; - - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - return 3; - - case AL_ORIENTATION: - return 6; - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - - case AL_BUFFER: - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - break; /* i/i64 only */ - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; /* i64 only */ - } - return 0; -} -ALint DoubleValsByProp(ALenum prop) -{ - switch(static_cast(prop)) - { - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_REFERENCE_DISTANCE: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_SOURCE_RADIUS: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - return 1; - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - case AL_STEREO_ANGLES: - return 2; - - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - return 3; - - case AL_ORIENTATION: - return 6; - - case AL_BUFFER: - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - break; /* i/i64 only */ - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; /* i64 only */ - } - return 0; -} - -ALint IntValsByProp(ALenum prop) -{ - switch(static_cast(prop)) - { - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_REFERENCE_DISTANCE: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_BUFFER: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_DIRECT_FILTER: - case AL_SOURCE_RADIUS: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - return 1; - - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - case AL_AUXILIARY_SEND_FILTER: - return 3; - - case AL_ORIENTATION: - return 6; - - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; /* i64 only */ - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - case AL_STEREO_ANGLES: - break; /* Float/double only */ - } - return 0; -} -ALint Int64ValsByProp(ALenum prop) -{ - switch(static_cast(prop)) - { - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_REFERENCE_DISTANCE: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_BUFFER: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_DIRECT_FILTER: - case AL_SOURCE_RADIUS: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - return 1; - - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - return 2; - - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - case AL_AUXILIARY_SEND_FILTER: - return 3; - - case AL_ORIENTATION: - return 6; - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - case AL_STEREO_ANGLES: - break; /* Float/double only */ - } - return 0; -} - - -ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values); -ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values); -ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values); - -#define CHECKVAL(x) do { \ - if(!(x)) \ - { \ - alSetError(Context, AL_INVALID_VALUE, "Value out of range"); \ - return AL_FALSE; \ - } \ -} while(0) - -void UpdateSourceProps(ALsource *source, ALCcontext *context) -{ - ALvoice *voice; - if(SourceShouldUpdate(source, context) && (voice=GetSourceVoice(source, context)) != nullptr) - UpdateSourceProps(source, voice, context); - else - source->PropsClean.clear(std::memory_order_release); -} - -ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values) -{ - ALint ival; - - switch(prop) - { - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - /* Query only */ - SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, - "Setting read-only source property 0x%04x", prop); - - case AL_PITCH: - CHECKVAL(*values >= 0.0f); - - Source->Pitch = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_CONE_INNER_ANGLE: - CHECKVAL(*values >= 0.0f && *values <= 360.0f); - - Source->InnerAngle = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_CONE_OUTER_ANGLE: - CHECKVAL(*values >= 0.0f && *values <= 360.0f); - - Source->OuterAngle = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_GAIN: - CHECKVAL(*values >= 0.0f); - - Source->Gain = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_MAX_DISTANCE: - CHECKVAL(*values >= 0.0f); - - Source->MaxDistance = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_ROLLOFF_FACTOR: - CHECKVAL(*values >= 0.0f); - - Source->RolloffFactor = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_REFERENCE_DISTANCE: - CHECKVAL(*values >= 0.0f); - - Source->RefDistance = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_MIN_GAIN: - CHECKVAL(*values >= 0.0f); - - Source->MinGain = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_MAX_GAIN: - CHECKVAL(*values >= 0.0f); - - Source->MaxGain = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_CONE_OUTER_GAIN: - CHECKVAL(*values >= 0.0f && *values <= 1.0f); - - Source->OuterGain = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_CONE_OUTER_GAINHF: - CHECKVAL(*values >= 0.0f && *values <= 1.0f); - - Source->OuterGainHF = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_AIR_ABSORPTION_FACTOR: - CHECKVAL(*values >= 0.0f && *values <= 10.0f); - - Source->AirAbsorptionFactor = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_ROOM_ROLLOFF_FACTOR: - CHECKVAL(*values >= 0.0f && *values <= 10.0f); - - Source->RoomRolloffFactor = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_DOPPLER_FACTOR: - CHECKVAL(*values >= 0.0f && *values <= 1.0f); - - Source->DopplerFactor = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - CHECKVAL(*values >= 0.0f); - - Source->OffsetType = prop; - Source->Offset = *values; - - if(IsPlayingOrPaused(Source)) - { - ALCdevice *device{Context->Device}; - BackendLockGuard _{*device->Backend}; - /* Double-check that the source is still playing while we have - * the lock. - */ - if(ALvoice *voice{GetSourceVoice(Source, Context)}) - { - if(ApplyOffset(Source, voice) == AL_FALSE) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid offset"); - } - } - return AL_TRUE; - - case AL_SOURCE_RADIUS: - CHECKVAL(*values >= 0.0f && std::isfinite(*values)); - - Source->Radius = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_STEREO_ANGLES: - CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1])); - - Source->StereoPan[0] = values[0]; - Source->StereoPan[1] = values[1]; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - - case AL_POSITION: - CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); - - Source->Position[0] = values[0]; - Source->Position[1] = values[1]; - Source->Position[2] = values[2]; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_VELOCITY: - CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); - - Source->Velocity[0] = values[0]; - Source->Velocity[1] = values[1]; - Source->Velocity[2] = values[2]; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_DIRECTION: - CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); - - Source->Direction[0] = values[0]; - Source->Direction[1] = values[1]; - Source->Direction[2] = values[2]; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_ORIENTATION: - CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) && - std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5])); - - Source->OrientAt[0] = values[0]; - Source->OrientAt[1] = values[1]; - Source->OrientAt[2] = values[2]; - Source->OrientUp[0] = values[3]; - Source->OrientUp[1] = values[4]; - Source->OrientUp[2] = values[5]; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_SOURCE_TYPE: - case AL_DISTANCE_MODEL: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - ival = static_cast(values[0]); - return SetSourceiv(Source, Context, prop, &ival); - - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - ival = static_cast(static_cast(values[0])); - return SetSourceiv(Source, Context, prop, &ival); - - case AL_BUFFER: - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; - } - - ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source float property 0x%04x", prop); -} - -ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values) -{ - ALCdevice *device{Context->Device}; - ALbuffer *buffer{nullptr}; - ALfilter *filter{nullptr}; - ALeffectslot *slot{nullptr}; - ALbufferlistitem *oldlist{nullptr}; - std::unique_lock slotlock; - std::unique_lock filtlock; - std::unique_lock buflock; - ALfloat fvals[6]; - - switch(prop) - { - case AL_SOURCE_STATE: - case AL_SOURCE_TYPE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - /* Query only */ - SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, - "Setting read-only source property 0x%04x", prop); - - case AL_SOURCE_RELATIVE: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->HeadRelative = static_cast(*values); - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_LOOPING: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->Looping = static_cast(*values); - if(IsPlayingOrPaused(Source)) - { - ALvoice *voice{GetSourceVoice(Source, Context)}; - if(voice) - { - if(Source->Looping) - voice->mLoopBuffer.store(Source->queue, std::memory_order_release); - else - voice->mLoopBuffer.store(nullptr, std::memory_order_release); - - /* If the source is playing, wait for the current mix to finish - * to ensure it isn't currently looping back or reaching the - * end. - */ - while((device->MixCount.load(std::memory_order_acquire)&1)) - std::this_thread::yield(); - } - } - return AL_TRUE; - - case AL_BUFFER: - buflock = std::unique_lock{device->BufferLock}; - if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != nullptr)) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid buffer ID %u", - *values); - - if(buffer && buffer->MappedAccess != 0 && - !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) - SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, - "Setting non-persistently mapped buffer %u", buffer->id); - else - { - ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context)); - if(state == AL_PLAYING || state == AL_PAUSED) - SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, - "Setting buffer on playing or paused source %u", Source->id); - } - - oldlist = Source->queue; - if(buffer != nullptr) - { - /* Add the selected buffer to a one-item queue */ - auto newlist = static_cast(al_calloc(alignof(void*), - ALbufferlistitem::Sizeof(1u))); - newlist->next.store(nullptr, std::memory_order_relaxed); - newlist->max_samples = buffer->SampleLen; - newlist->num_buffers = 1; - newlist->buffers[0] = buffer; - IncrementRef(&buffer->ref); - - /* Source is now Static */ - Source->SourceType = AL_STATIC; - Source->queue = newlist; - } - else - { - /* Source is now Undetermined */ - Source->SourceType = AL_UNDETERMINED; - Source->queue = nullptr; - } - buflock.unlock(); - - /* Delete all elements in the previous queue */ - while(oldlist != nullptr) - { - ALbufferlistitem *temp{oldlist}; - oldlist = temp->next.load(std::memory_order_relaxed); - - for(ALsizei i{0};i < temp->num_buffers;i++) - { - if(temp->buffers[i]) - DecrementRef(&temp->buffers[i]->ref); - } - al_free(temp); - } - return AL_TRUE; - - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - CHECKVAL(*values >= 0); - - Source->OffsetType = prop; - Source->Offset = *values; - - if(IsPlayingOrPaused(Source)) - { - ALCdevice *device{Context->Device}; - BackendLockGuard _{*device->Backend}; - if(ALvoice *voice{GetSourceVoice(Source, Context)}) - { - if(ApplyOffset(Source, voice) == AL_FALSE) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, - "Invalid source offset"); - } - } - return AL_TRUE; - - case AL_DIRECT_FILTER: - filtlock = std::unique_lock{device->FilterLock}; - if(!(*values == 0 || (filter=LookupFilter(device, *values)) != nullptr)) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", - *values); - - if(!filter) - { - Source->Direct.Gain = 1.0f; - Source->Direct.GainHF = 1.0f; - Source->Direct.HFReference = LOWPASSFREQREF; - Source->Direct.GainLF = 1.0f; - Source->Direct.LFReference = HIGHPASSFREQREF; - } - else - { - Source->Direct.Gain = filter->Gain; - Source->Direct.GainHF = filter->GainHF; - Source->Direct.HFReference = filter->HFReference; - Source->Direct.GainLF = filter->GainLF; - Source->Direct.LFReference = filter->LFReference; - } - filtlock.unlock(); - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_DIRECT_FILTER_GAINHF_AUTO: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->DryGainHFAuto = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->WetGainAuto = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->WetGainHFAuto = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_DIRECT_CHANNELS_SOFT: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->DirectChannels = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_DISTANCE_MODEL: - CHECKVAL(*values == AL_NONE || - *values == AL_INVERSE_DISTANCE || - *values == AL_INVERSE_DISTANCE_CLAMPED || - *values == AL_LINEAR_DISTANCE || - *values == AL_LINEAR_DISTANCE_CLAMPED || - *values == AL_EXPONENT_DISTANCE || - *values == AL_EXPONENT_DISTANCE_CLAMPED); - - Source->mDistanceModel = static_cast(*values); - if(Context->SourceDistanceModel) - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_SOURCE_RESAMPLER_SOFT: - CHECKVAL(*values >= 0 && *values <= ResamplerMax); - - Source->mResampler = static_cast(*values); - UpdateSourceProps(Source, Context); - return AL_TRUE; - - case AL_SOURCE_SPATIALIZE_SOFT: - CHECKVAL(*values >= AL_FALSE && *values <= AL_AUTO_SOFT); - - Source->mSpatialize = static_cast(*values); - UpdateSourceProps(Source, Context); - return AL_TRUE; - - - case AL_AUXILIARY_SEND_FILTER: - slotlock = std::unique_lock{Context->EffectSlotLock}; - if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != nullptr)) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid effect ID %u", - values[0]); - if(static_cast(values[1]) >= static_cast(device->NumAuxSends)) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid send %u", values[1]); - - filtlock = std::unique_lock{device->FilterLock}; - if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != nullptr)) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", - values[2]); - - if(!filter) - { - /* Disable filter */ - Source->Send[values[1]].Gain = 1.0f; - Source->Send[values[1]].GainHF = 1.0f; - Source->Send[values[1]].HFReference = LOWPASSFREQREF; - Source->Send[values[1]].GainLF = 1.0f; - Source->Send[values[1]].LFReference = HIGHPASSFREQREF; - } - else - { - Source->Send[values[1]].Gain = filter->Gain; - Source->Send[values[1]].GainHF = filter->GainHF; - Source->Send[values[1]].HFReference = filter->HFReference; - Source->Send[values[1]].GainLF = filter->GainLF; - Source->Send[values[1]].LFReference = filter->LFReference; - } - filtlock.unlock(); - - if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source)) - { - /* Add refcount on the new slot, and release the previous slot */ - if(slot) IncrementRef(&slot->ref); - if(Source->Send[values[1]].Slot) - DecrementRef(&Source->Send[values[1]].Slot->ref); - Source->Send[values[1]].Slot = slot; - - /* We must force an update if the auxiliary slot changed on an - * active source, in case the slot is about to be deleted. - */ - ALvoice *voice{GetSourceVoice(Source, Context)}; - if(voice) UpdateSourceProps(Source, voice, Context); - else Source->PropsClean.clear(std::memory_order_release); - } - else - { - if(slot) IncrementRef(&slot->ref); - if(Source->Send[values[1]].Slot) - DecrementRef(&Source->Send[values[1]].Slot->ref); - Source->Send[values[1]].Slot = slot; - UpdateSourceProps(Source, Context); - } - - return AL_TRUE; - - - /* 1x float */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_SOURCE_RADIUS: - fvals[0] = static_cast(*values); - return SetSourcefv(Source, Context, prop, fvals); - - /* 3x float */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - fvals[0] = static_cast(values[0]); - fvals[1] = static_cast(values[1]); - fvals[2] = static_cast(values[2]); - return SetSourcefv(Source, Context, prop, fvals); - - /* 6x float */ - case AL_ORIENTATION: - fvals[0] = static_cast(values[0]); - fvals[1] = static_cast(values[1]); - fvals[2] = static_cast(values[2]); - fvals[3] = static_cast(values[3]); - fvals[4] = static_cast(values[4]); - fvals[5] = static_cast(values[5]); - return SetSourcefv(Source, Context, prop, fvals); - - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - case AL_STEREO_ANGLES: - break; - } - - ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x", - prop); -} - -ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values) -{ - ALfloat fvals[6]; - ALint ivals[3]; - - switch(prop) - { - case AL_SOURCE_TYPE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_STATE: - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - /* Query only */ - SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, - "Setting read-only source property 0x%04x", prop); - - /* 1x int */ - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - CHECKVAL(*values <= INT_MAX && *values >= INT_MIN); - - ivals[0] = static_cast(*values); - return SetSourceiv(Source, Context, prop, ivals); - - /* 1x uint */ - case AL_BUFFER: - case AL_DIRECT_FILTER: - CHECKVAL(*values <= UINT_MAX && *values >= 0); - - ivals[0] = static_cast(*values); - return SetSourceiv(Source, Context, prop, ivals); - - /* 3x uint */ - case AL_AUXILIARY_SEND_FILTER: - CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 && - values[1] <= UINT_MAX && values[1] >= 0 && - values[2] <= UINT_MAX && values[2] >= 0); - - ivals[0] = static_cast(values[0]); - ivals[1] = static_cast(values[1]); - ivals[2] = static_cast(values[2]); - return SetSourceiv(Source, Context, prop, ivals); - - /* 1x float */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_SOURCE_RADIUS: - fvals[0] = static_cast(*values); - return SetSourcefv(Source, Context, prop, fvals); - - /* 3x float */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - fvals[0] = static_cast(values[0]); - fvals[1] = static_cast(values[1]); - fvals[2] = static_cast(values[2]); - return SetSourcefv(Source, Context, prop, fvals); - - /* 6x float */ - case AL_ORIENTATION: - fvals[0] = static_cast(values[0]); - fvals[1] = static_cast(values[1]); - fvals[2] = static_cast(values[2]); - fvals[3] = static_cast(values[3]); - fvals[4] = static_cast(values[4]); - fvals[5] = static_cast(values[5]); - return SetSourcefv(Source, Context, prop, fvals); - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - case AL_STEREO_ANGLES: - break; - } - - ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x", - prop); -} - -#undef CHECKVAL - - -ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values); -ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values); -ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64SOFT *values); - -ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values) -{ - ALCdevice *device{Context->Device}; - ClockLatency clocktime; - std::chrono::nanoseconds srcclock; - ALint ivals[3]; - ALboolean err; - - switch(prop) - { - case AL_GAIN: - *values = Source->Gain; - return AL_TRUE; - - case AL_PITCH: - *values = Source->Pitch; - return AL_TRUE; - - case AL_MAX_DISTANCE: - *values = Source->MaxDistance; - return AL_TRUE; - - case AL_ROLLOFF_FACTOR: - *values = Source->RolloffFactor; - return AL_TRUE; - - case AL_REFERENCE_DISTANCE: - *values = Source->RefDistance; - return AL_TRUE; - - case AL_CONE_INNER_ANGLE: - *values = Source->InnerAngle; - return AL_TRUE; - - case AL_CONE_OUTER_ANGLE: - *values = Source->OuterAngle; - return AL_TRUE; - - case AL_MIN_GAIN: - *values = Source->MinGain; - return AL_TRUE; - - case AL_MAX_GAIN: - *values = Source->MaxGain; - return AL_TRUE; - - case AL_CONE_OUTER_GAIN: - *values = Source->OuterGain; - return AL_TRUE; - - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - *values = GetSourceOffset(Source, prop, Context); - return AL_TRUE; - - case AL_CONE_OUTER_GAINHF: - *values = Source->OuterGainHF; - return AL_TRUE; - - case AL_AIR_ABSORPTION_FACTOR: - *values = Source->AirAbsorptionFactor; - return AL_TRUE; - - case AL_ROOM_ROLLOFF_FACTOR: - *values = Source->RoomRolloffFactor; - return AL_TRUE; - - case AL_DOPPLER_FACTOR: - *values = Source->DopplerFactor; - return AL_TRUE; - - case AL_SOURCE_RADIUS: - *values = Source->Radius; - return AL_TRUE; - - case AL_STEREO_ANGLES: - values[0] = Source->StereoPan[0]; - values[1] = Source->StereoPan[1]; - return AL_TRUE; - - case AL_SEC_OFFSET_LATENCY_SOFT: - /* Get the source offset with the clock time first. Then get the - * clock time with the device latency. Order is important. - */ - values[0] = GetSourceSecOffset(Source, Context, &srcclock); - { std::lock_guard _{device->StateLock}; - clocktime = GetClockLatency(device); - } - if(srcclock == clocktime.ClockTime) - values[1] = static_cast(clocktime.Latency.count()) / 1000000000.0; - else - { - /* If the clock time incremented, reduce the latency by that - * much since it's that much closer to the source offset it got - * earlier. - */ - std::chrono::nanoseconds diff = clocktime.ClockTime - srcclock; - values[1] = static_cast((clocktime.Latency - std::min(clocktime.Latency, diff)).count()) / - 1000000000.0; - } - return AL_TRUE; - - case AL_SEC_OFFSET_CLOCK_SOFT: - values[0] = GetSourceSecOffset(Source, Context, &srcclock); - values[1] = srcclock.count() / 1000000000.0; - return AL_TRUE; - - case AL_POSITION: - values[0] = Source->Position[0]; - values[1] = Source->Position[1]; - values[2] = Source->Position[2]; - return AL_TRUE; - - case AL_VELOCITY: - values[0] = Source->Velocity[0]; - values[1] = Source->Velocity[1]; - values[2] = Source->Velocity[2]; - return AL_TRUE; - - case AL_DIRECTION: - values[0] = Source->Direction[0]; - values[1] = Source->Direction[1]; - values[2] = Source->Direction[2]; - return AL_TRUE; - - case AL_ORIENTATION: - values[0] = Source->OrientAt[0]; - values[1] = Source->OrientAt[1]; - values[2] = Source->OrientAt[2]; - values[3] = Source->OrientUp[0]; - values[4] = Source->OrientUp[1]; - values[5] = Source->OrientUp[2]; - return AL_TRUE; - - /* 1x int */ - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) - *values = static_cast(ivals[0]); - return err; - - case AL_BUFFER: - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; - } - - ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source double property 0x%04x", - prop); -} - -ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values) -{ - ALbufferlistitem *BufferList; - ALdouble dvals[6]; - ALboolean err; - - switch(prop) - { - case AL_SOURCE_RELATIVE: - *values = Source->HeadRelative; - return AL_TRUE; - - case AL_LOOPING: - *values = Source->Looping; - return AL_TRUE; - - case AL_BUFFER: - BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : nullptr; - *values = (BufferList && BufferList->num_buffers >= 1 && BufferList->buffers[0]) ? - BufferList->buffers[0]->id : 0; - return AL_TRUE; - - case AL_SOURCE_STATE: - *values = GetSourceState(Source, GetSourceVoice(Source, Context)); - return AL_TRUE; - - case AL_BUFFERS_QUEUED: - if(!(BufferList=Source->queue)) - *values = 0; - else - { - ALsizei count = 0; - do { - count += BufferList->num_buffers; - BufferList = BufferList->next.load(std::memory_order_relaxed); - } while(BufferList != nullptr); - *values = count; - } - return AL_TRUE; - - case AL_BUFFERS_PROCESSED: - if(Source->Looping || Source->SourceType != AL_STREAMING) - { - /* Buffers on a looping source are in a perpetual state of - * PENDING, so don't report any as PROCESSED */ - *values = 0; - } - else - { - const ALbufferlistitem *BufferList{Source->queue}; - const ALbufferlistitem *Current{nullptr}; - ALsizei played{0}; - - ALvoice *voice{GetSourceVoice(Source, Context)}; - if(voice != nullptr) - Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); - else if(Source->state == AL_INITIAL) - Current = BufferList; - - while(BufferList && BufferList != Current) - { - played += BufferList->num_buffers; - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - *values = played; - } - return AL_TRUE; - - case AL_SOURCE_TYPE: - *values = Source->SourceType; - return AL_TRUE; - - case AL_DIRECT_FILTER_GAINHF_AUTO: - *values = Source->DryGainHFAuto; - return AL_TRUE; - - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - *values = Source->WetGainAuto; - return AL_TRUE; - - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - *values = Source->WetGainHFAuto; - return AL_TRUE; - - case AL_DIRECT_CHANNELS_SOFT: - *values = Source->DirectChannels; - return AL_TRUE; - - case AL_DISTANCE_MODEL: - *values = static_cast(Source->mDistanceModel); - return AL_TRUE; - - case AL_SOURCE_RESAMPLER_SOFT: - *values = Source->mResampler; - return AL_TRUE; - - case AL_SOURCE_SPATIALIZE_SOFT: - *values = Source->mSpatialize; - return AL_TRUE; - - /* 1x float/double */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_DOPPLER_FACTOR: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_SOURCE_RADIUS: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - *values = static_cast(dvals[0]); - return err; - - /* 3x float/double */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - { - values[0] = static_cast(dvals[0]); - values[1] = static_cast(dvals[1]); - values[2] = static_cast(dvals[2]); - } - return err; - - /* 6x float/double */ - case AL_ORIENTATION: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - { - values[0] = static_cast(dvals[0]); - values[1] = static_cast(dvals[1]); - values[2] = static_cast(dvals[2]); - values[3] = static_cast(dvals[3]); - values[4] = static_cast(dvals[4]); - values[5] = static_cast(dvals[5]); - } - return err; - - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; /* i64 only */ - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - case AL_STEREO_ANGLES: - break; /* Float/double only */ - - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - break; /* ??? */ - } - - ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x", - prop); -} - -ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64SOFT *values) -{ - ALCdevice *device = Context->Device; - ClockLatency clocktime; - std::chrono::nanoseconds srcclock; - ALdouble dvals[6]; - ALint ivals[3]; - ALboolean err; - - switch(prop) - { - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - /* Get the source offset with the clock time first. Then get the - * clock time with the device latency. Order is important. - */ - values[0] = GetSourceSampleOffset(Source, Context, &srcclock); - { std::lock_guard _{device->StateLock}; - clocktime = GetClockLatency(device); - } - if(srcclock == clocktime.ClockTime) - values[1] = clocktime.Latency.count(); - else - { - /* If the clock time incremented, reduce the latency by that - * much since it's that much closer to the source offset it got - * earlier. - */ - auto diff = clocktime.ClockTime - srcclock; - values[1] = (clocktime.Latency - std::min(clocktime.Latency, diff)).count(); - } - return AL_TRUE; - - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - values[0] = GetSourceSampleOffset(Source, Context, &srcclock); - values[1] = srcclock.count(); - return AL_TRUE; - - /* 1x float/double */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_DOPPLER_FACTOR: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_SOURCE_RADIUS: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - *values = static_cast(dvals[0]); - return err; - - /* 3x float/double */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - { - values[0] = static_cast(dvals[0]); - values[1] = static_cast(dvals[1]); - values[2] = static_cast(dvals[2]); - } - return err; - - /* 6x float/double */ - case AL_ORIENTATION: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - { - values[0] = static_cast(dvals[0]); - values[1] = static_cast(dvals[1]); - values[2] = static_cast(dvals[2]); - values[3] = static_cast(dvals[3]); - values[4] = static_cast(dvals[4]); - values[5] = static_cast(dvals[5]); - } - return err; - - /* 1x int */ - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) - *values = ivals[0]; - return err; - - /* 1x uint */ - case AL_BUFFER: - case AL_DIRECT_FILTER: - if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) - *values = static_cast(ivals[0]); - return err; - - /* 3x uint */ - case AL_AUXILIARY_SEND_FILTER: - if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) - { - values[0] = static_cast(ivals[0]); - values[1] = static_cast(ivals[1]); - values[2] = static_cast(ivals[2]); - } - return err; - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - case AL_STEREO_ANGLES: - break; /* Float/double only */ - } - - ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x", - prop); -} - -} // namespace - -AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(n < 0) - alSetError(context.get(), AL_INVALID_VALUE, "Generating %d sources", n); - else if(n == 1) - { - ALsource *source = AllocSource(context.get()); - if(source) sources[0] = source->id; - } - else - { - al::vector tempids(n); - auto alloc_end = std::find_if_not(tempids.begin(), tempids.end(), - [&context](ALuint &id) -> bool - { - ALsource *source{AllocSource(context.get())}; - if(!source) return false; - id = source->id; - return true; - } - ); - if(alloc_end != tempids.end()) - alDeleteSources(static_cast(std::distance(tempids.begin(), alloc_end)), - tempids.data()); - else - std::copy(tempids.cbegin(), tempids.cend(), sources); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Deleting %d sources", n); - - std::lock_guard _{context->SourceLock}; - - /* Check that all Sources are valid */ - const ALuint *sources_end = sources + n; - auto invsrc = std::find_if_not(sources, sources_end, - [&context](ALuint sid) -> bool - { - if(!LookupSource(context.get(), sid)) - { - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", sid); - return false; - } - return true; - } - ); - if(LIKELY(invsrc == sources_end)) - { - /* All good. Delete source IDs. */ - std::for_each(sources, sources_end, - [&context](ALuint sid) -> void - { - ALsource *src{LookupSource(context.get(), sid)}; - if(src) FreeSource(context.get(), src); - } - ); - } -} -END_API_FUNC - -AL_API ALboolean AL_APIENTRY alIsSource(ALuint source) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(LIKELY(context)) - { - std::lock_guard _{context->SourceLock}; - if(LookupSource(context.get(), source) != nullptr) - return AL_TRUE; - } - return AL_FALSE; -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(FloatValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid float property 0x%04x", param); - else - SetSourcefv(Source, context.get(), static_cast(param), &value); -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(FloatValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); - else - { - ALfloat fvals[3] = { value1, value2, value3 }; - SetSourcefv(Source, context.get(), static_cast(param), fvals); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(FloatValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); - else - SetSourcefv(Source, context.get(), static_cast(param), values); -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(DoubleValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid double property 0x%04x", param); - else - { - ALfloat fval = static_cast(value); - SetSourcefv(Source, context.get(), static_cast(param), &fval); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(DoubleValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); - else { - ALfloat fvals[3] = {static_cast(value1), - static_cast(value2), - static_cast(value3)}; - SetSourcefv(Source, context.get(), static_cast(param), fvals); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else - { - ALint count{DoubleValsByProp(param)}; - if(count < 1 || count > 6) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); - else - { - ALfloat fvals[6]; - ALint i; - - for(i = 0;i < count;i++) - fvals[i] = static_cast(values[i]); - SetSourcefv(Source, context.get(), static_cast(param), fvals); - } - } -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(IntValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); - else - SetSourceiv(Source, context.get(), static_cast(param), &value); -} -END_API_FUNC - -AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(IntValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); - else - { - ALint ivals[3] = { value1, value2, value3 }; - SetSourceiv(Source, context.get(), static_cast(param), ivals); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(IntValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); - else - SetSourceiv(Source, context.get(), static_cast(param), values); -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(Int64ValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); - else - SetSourcei64v(Source, context.get(), static_cast(param), &value); -} -END_API_FUNC - -AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(Int64ValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); - else - { - ALint64SOFT i64vals[3] = { value1, value2, value3 }; - SetSourcei64v(Source, context.get(), static_cast(param), i64vals); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(Int64ValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); - else - SetSourcei64v(Source, context.get(), static_cast(param), values); -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(FloatValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid float property 0x%04x", param); - else - { - ALdouble dval; - if(GetSourcedv(Source, context.get(), static_cast(param), &dval)) - *value = static_cast(dval); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(FloatValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); - else - { - ALdouble dvals[3]; - if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) - { - *value1 = static_cast(dvals[0]); - *value2 = static_cast(dvals[1]); - *value3 = static_cast(dvals[2]); - } - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else - { - ALint count{FloatValsByProp(param)}; - if(count < 1 && count > 6) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); - else - { - ALdouble dvals[6]; - if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) - { - for(ALint i{0};i < count;i++) - values[i] = static_cast(dvals[i]); - } - } - } -} -END_API_FUNC - - -AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(DoubleValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid double property 0x%04x", param); - else - GetSourcedv(Source, context.get(), static_cast(param), value); -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(DoubleValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); - else - { - ALdouble dvals[3]; - if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) - { - *value1 = dvals[0]; - *value2 = dvals[1]; - *value3 = dvals[2]; - } - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(DoubleValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); - else - GetSourcedv(Source, context.get(), static_cast(param), values); -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(IntValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); - else - GetSourceiv(Source, context.get(), static_cast(param), value); -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(IntValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); - else - { - ALint ivals[3]; - if(GetSourceiv(Source, context.get(), static_cast(param), ivals)) - { - *value1 = ivals[0]; - *value2 = ivals[1]; - *value3 = ivals[2]; - } - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(IntValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); - else - GetSourceiv(Source, context.get(), static_cast(param), values); -} -END_API_FUNC - - -AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(Int64ValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); - else - GetSourcei64v(Source, context.get(), static_cast(param), value); -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(Int64ValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); - else - { - ALint64SOFT i64vals[3]; - if(GetSourcei64v(Source, context.get(), static_cast(param), i64vals)) - { - *value1 = i64vals[0]; - *value2 = i64vals[1]; - *value3 = i64vals[2]; - } - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->SourceLock}; - ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else if(Int64ValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); - else - GetSourcei64v(Source, context.get(), static_cast(param), values); -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source) -START_API_FUNC -{ alSourcePlayv(1, &source); } -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Playing %d sources", n); - if(n == 0) return; - - al::vector extra_sources; - std::array source_storage; - ALsource **srchandles{source_storage.data()}; - if(UNLIKELY(static_cast(n) > source_storage.size())) - { - extra_sources.resize(n); - srchandles = extra_sources.data(); - } - - std::lock_guard _{context->SourceLock}; - for(ALsizei i{0};i < n;i++) - { - srchandles[i] = LookupSource(context.get(), sources[i]); - if(!srchandles[i]) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); - } - - ALCdevice *device{context->Device}; - BackendLockGuard __{*device->Backend}; - /* If the device is disconnected, go right to stopped. */ - if(UNLIKELY(!device->Connected.load(std::memory_order_acquire))) - { - /* TODO: Send state change event? */ - std::for_each(srchandles, srchandles+n, - [](ALsource *source) -> void - { - source->OffsetType = AL_NONE; - source->Offset = 0.0; - source->state = AL_STOPPED; - } - ); - return; - } - - /* Count the number of reusable voices. */ - auto voices_end = context->Voices->begin() + - context->VoiceCount.load(std::memory_order_relaxed); - auto free_voices = std::accumulate(context->Voices->begin(), voices_end, ALsizei{0}, - [](const ALsizei count, const ALvoice &voice) noexcept -> ALsizei - { - if(voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && - voice.mSourceID.load(std::memory_order_relaxed) == 0u) - return count + 1; - return count; - } - ); - if(UNLIKELY(n > free_voices)) - { - /* Increment the number of voices to handle the request. */ - const ALuint need_voices{static_cast(n) - free_voices}; - const size_t rem_voices{context->Voices->size() - - context->VoiceCount.load(std::memory_order_relaxed)}; - - if(UNLIKELY(need_voices > rem_voices)) - { - /* Allocate more voices to get enough. */ - const size_t alloc_count{need_voices - rem_voices}; - if(UNLIKELY(context->Voices->size() > std::numeric_limits::max()-alloc_count)) - SETERR_RETURN(context.get(), AL_OUT_OF_MEMORY,, - "Overflow increasing voice count to %zu + %zu", context->Voices->size(), - alloc_count); - - const size_t newcount{context->Voices->size() + alloc_count}; - AllocateVoices(context.get(), newcount); - } - - context->VoiceCount.fetch_add(need_voices, std::memory_order_relaxed); - } - - auto start_source = [&context,device](ALsource *source) -> void - { - /* Check that there is a queue containing at least one valid, non zero - * length buffer. - */ - ALbufferlistitem *BufferList{source->queue}; - while(BufferList && BufferList->max_samples == 0) - BufferList = BufferList->next.load(std::memory_order_relaxed); - - /* If there's nothing to play, go right to stopped. */ - if(UNLIKELY(!BufferList)) - { - /* NOTE: A source without any playable buffers should not have an - * ALvoice since it shouldn't be in a playing or paused state. So - * there's no need to look up its voice and clear the source. - */ - ALenum oldstate{GetSourceState(source, nullptr)}; - source->OffsetType = AL_NONE; - source->Offset = 0.0; - if(oldstate != AL_STOPPED) - { - source->state = AL_STOPPED; - SendStateChangeEvent(context.get(), source->id, AL_STOPPED); - } - return; - } - - ALvoice *voice{GetSourceVoice(source, context.get())}; - switch(GetSourceState(source, voice)) - { - case AL_PLAYING: - assert(voice != nullptr); - /* A source that's already playing is restarted from the beginning. */ - voice->mCurrentBuffer.store(BufferList, std::memory_order_relaxed); - voice->mPosition.store(0u, std::memory_order_relaxed); - voice->mPositionFrac.store(0, std::memory_order_release); - return; - - case AL_PAUSED: - assert(voice != nullptr); - /* A source that's paused simply resumes. */ - voice->mPlayState.store(ALvoice::Playing, std::memory_order_release); - source->state = AL_PLAYING; - SendStateChangeEvent(context.get(), source->id, AL_PLAYING); - return; - - default: - assert(voice == nullptr); - break; - } - - /* Look for an unused voice to play this source with. */ - auto voices_end = context->Voices->begin() + - context->VoiceCount.load(std::memory_order_relaxed); - voice = std::find_if(context->Voices->begin(), voices_end, - [](const ALvoice &voice) noexcept -> bool - { - return voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && - voice.mSourceID.load(std::memory_order_relaxed) == 0u; - } - ); - assert(voice != voices_end); - auto vidx = static_cast(std::distance(context->Voices->begin(), voice)); - voice->mPlayState.store(ALvoice::Stopped, std::memory_order_release); - - source->PropsClean.test_and_set(std::memory_order_acquire); - UpdateSourceProps(source, voice, context.get()); - - /* A source that's not playing or paused has any offset applied when it - * starts playing. - */ - if(source->Looping) - voice->mLoopBuffer.store(source->queue, std::memory_order_relaxed); - else - voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); - voice->mCurrentBuffer.store(BufferList, std::memory_order_relaxed); - voice->mPosition.store(0u, std::memory_order_relaxed); - voice->mPositionFrac.store(0, std::memory_order_relaxed); - bool start_fading{false}; - if(ApplyOffset(source, voice) != AL_FALSE) - start_fading = voice->mPosition.load(std::memory_order_relaxed) != 0 || - voice->mPositionFrac.load(std::memory_order_relaxed) != 0 || - voice->mCurrentBuffer.load(std::memory_order_relaxed) != BufferList; - - auto buffers_end = BufferList->buffers + BufferList->num_buffers; - auto buffer = std::find_if(BufferList->buffers, buffers_end, - std::bind(std::not_equal_to{}, _1, nullptr)); - if(buffer != buffers_end) - { - voice->mFrequency = (*buffer)->Frequency; - voice->mFmtChannels = (*buffer)->mFmtChannels; - voice->mNumChannels = ChannelsFromFmt((*buffer)->mFmtChannels); - voice->mSampleSize = BytesFromFmt((*buffer)->mFmtType); - } - - /* Clear the stepping value so the mixer knows not to mix this until - * the update gets applied. - */ - voice->mStep = 0; - - voice->mFlags = start_fading ? VOICE_IS_FADING : 0; - if(source->SourceType == AL_STATIC) voice->mFlags |= VOICE_IS_STATIC; - - /* Don't need to set the VOICE_IS_AMBISONIC flag if the device is - * mixing in first order. No HF scaling is necessary to mix it. - */ - if((voice->mFmtChannels == FmtBFormat2D || voice->mFmtChannels == FmtBFormat3D) && - device->mAmbiOrder > 1) - { - const int *OrderFromChan; - if(voice->mFmtChannels == FmtBFormat2D) - { - static constexpr int Order2DFromChan[MAX_AMBI2D_CHANNELS]{ - 0, 1,1, 2,2, 3,3 - }; - OrderFromChan = Order2DFromChan; - } - else - { - static constexpr int Order3DFromChan[MAX_AMBI_CHANNELS]{ - 0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3, - }; - OrderFromChan = Order3DFromChan; - } - - BandSplitter splitter{400.0f / static_cast(device->Frequency)}; - - const auto scales = BFormatDec::GetHFOrderScales(1, device->mAmbiOrder); - auto init_ambi = [scales,&OrderFromChan,&splitter](ALvoice::ChannelData &chandata) -> void - { - chandata.mPrevSamples.fill(0.0f); - chandata.mAmbiScale = scales[*(OrderFromChan++)]; - chandata.mAmbiSplitter = splitter; - }; - std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, - init_ambi); - - voice->mFlags |= VOICE_IS_AMBISONIC; - } - else - { - /* Clear previous samples. */ - auto clear_prevs = [](ALvoice::ChannelData &chandata) -> void - { chandata.mPrevSamples.fill(0.0f); }; - std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, - clear_prevs); - } - - auto clear_params = [device](ALvoice::ChannelData &chandata) -> void - { - chandata.mDryParams = DirectParams{}; - std::fill_n(chandata.mWetParams.begin(), device->NumAuxSends, SendParams{}); - }; - std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, - clear_params); - - if(device->AvgSpeakerDist > 0.0f) - { - const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC / - (device->AvgSpeakerDist * device->Frequency)}; - auto init_nfc = [w1](ALvoice::ChannelData &chandata) -> void - { chandata.mDryParams.NFCtrlFilter.init(w1); }; - std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, - init_nfc); - } - - voice->mSourceID.store(source->id, std::memory_order_relaxed); - voice->mPlayState.store(ALvoice::Playing, std::memory_order_release); - source->state = AL_PLAYING; - source->VoiceIdx = vidx; - - SendStateChangeEvent(context.get(), source->id, AL_PLAYING); - }; - std::for_each(srchandles, srchandles+n, start_source); -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source) -START_API_FUNC -{ alSourcePausev(1, &source); } -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Pausing %d sources", n); - if(n == 0) return; - - al::vector extra_sources; - std::array source_storage; - ALsource **srchandles{source_storage.data()}; - if(UNLIKELY(static_cast(n) > source_storage.size())) - { - extra_sources.resize(n); - srchandles = extra_sources.data(); - } - - std::lock_guard _{context->SourceLock}; - for(ALsizei i{0};i < n;i++) - { - srchandles[i] = LookupSource(context.get(), sources[i]); - if(!srchandles[i]) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); - } - - ALCdevice *device{context->Device}; - BackendLockGuard __{*device->Backend}; - auto pause_source = [&context](ALsource *source) -> void - { - ALvoice *voice{GetSourceVoice(source, context.get())}; - if(voice) - { - std::atomic_thread_fence(std::memory_order_release); - ALvoice::State oldvstate{ALvoice::Playing}; - voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping, - std::memory_order_acq_rel, std::memory_order_acquire); - } - if(GetSourceState(source, voice) == AL_PLAYING) - { - source->state = AL_PAUSED; - SendStateChangeEvent(context.get(), source->id, AL_PAUSED); - } - }; - std::for_each(srchandles, srchandles+n, pause_source); -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source) -START_API_FUNC -{ alSourceStopv(1, &source); } -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Stopping %d sources", n); - if(n == 0) return; - - al::vector extra_sources; - std::array source_storage; - ALsource **srchandles{source_storage.data()}; - if(UNLIKELY(static_cast(n) > source_storage.size())) - { - extra_sources.resize(n); - srchandles = extra_sources.data(); - } - - std::lock_guard _{context->SourceLock}; - for(ALsizei i{0};i < n;i++) - { - srchandles[i] = LookupSource(context.get(), sources[i]); - if(!srchandles[i]) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); - } - - ALCdevice *device{context->Device}; - BackendLockGuard __{*device->Backend}; - auto stop_source = [&context](ALsource *source) -> void - { - ALvoice *voice{GetSourceVoice(source, context.get())}; - if(voice != nullptr) - { - voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed); - voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); - voice->mSourceID.store(0u, std::memory_order_relaxed); - std::atomic_thread_fence(std::memory_order_release); - ALvoice::State oldvstate{ALvoice::Playing}; - voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping, - std::memory_order_acq_rel, std::memory_order_acquire); - voice = nullptr; - } - ALenum oldstate{GetSourceState(source, voice)}; - if(oldstate != AL_INITIAL && oldstate != AL_STOPPED) - { - source->state = AL_STOPPED; - SendStateChangeEvent(context.get(), source->id, AL_STOPPED); - } - source->OffsetType = AL_NONE; - source->Offset = 0.0; - }; - std::for_each(srchandles, srchandles+n, stop_source); -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source) -START_API_FUNC -{ alSourceRewindv(1, &source); } -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Rewinding %d sources", n); - if(n == 0) return; - - al::vector extra_sources; - std::array source_storage; - ALsource **srchandles{source_storage.data()}; - if(UNLIKELY(static_cast(n) > source_storage.size())) - { - extra_sources.resize(n); - srchandles = extra_sources.data(); - } - - std::lock_guard _{context->SourceLock}; - for(ALsizei i{0};i < n;i++) - { - srchandles[i] = LookupSource(context.get(), sources[i]); - if(!srchandles[i]) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); - } - - ALCdevice *device{context->Device}; - BackendLockGuard __{*device->Backend}; - auto rewind_source = [&context](ALsource *source) -> void - { - ALvoice *voice{GetSourceVoice(source, context.get())}; - if(voice != nullptr) - { - voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed); - voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); - voice->mSourceID.store(0u, std::memory_order_relaxed); - std::atomic_thread_fence(std::memory_order_release); - ALvoice::State oldvstate{ALvoice::Playing}; - voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping, - std::memory_order_acq_rel, std::memory_order_acquire); - voice = nullptr; - } - if(GetSourceState(source, voice) != AL_INITIAL) - { - source->state = AL_INITIAL; - SendStateChangeEvent(context.get(), source->id, AL_INITIAL); - } - source->OffsetType = AL_NONE; - source->Offset = 0.0; - }; - std::for_each(srchandles, srchandles+n, rewind_source); -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(nb < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffers", nb); - if(nb == 0) return; - - std::lock_guard _{context->SourceLock}; - ALsource *source{LookupSource(context.get(),src)}; - if(UNLIKELY(!source)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); - - /* Can't queue on a Static Source */ - if(UNLIKELY(source->SourceType == AL_STATIC)) - SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src); - - /* Check for a valid Buffer, for its frequency and format */ - ALCdevice *device{context->Device}; - ALbuffer *BufferFmt{nullptr}; - ALbufferlistitem *BufferList{source->queue}; - while(BufferList) - { - for(ALsizei i{0};i < BufferList->num_buffers;i++) - { - if((BufferFmt=BufferList->buffers[i]) != nullptr) - break; - } - if(BufferFmt) break; - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - - std::unique_lock buflock{device->BufferLock}; - ALbufferlistitem *BufferListStart{nullptr}; - BufferList = nullptr; - for(ALsizei i{0};i < nb;i++) - { - ALbuffer *buffer{nullptr}; - if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr) - { - alSetError(context.get(), AL_INVALID_NAME, "Queueing invalid buffer ID %u", - buffers[i]); - goto buffer_error; - } - - if(!BufferListStart) - { - BufferListStart = static_cast(al_calloc(alignof(void*), - ALbufferlistitem::Sizeof(1u))); - BufferList = BufferListStart; - } - else - { - auto item = static_cast(al_calloc(alignof(void*), - ALbufferlistitem::Sizeof(1u))); - BufferList->next.store(item, std::memory_order_relaxed); - BufferList = item; - } - BufferList->next.store(nullptr, std::memory_order_relaxed); - BufferList->max_samples = buffer ? buffer->SampleLen : 0; - BufferList->num_buffers = 1; - BufferList->buffers[0] = buffer; - if(!buffer) continue; - - IncrementRef(&buffer->ref); - - if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) - { - alSetError(context.get(), AL_INVALID_OPERATION, - "Queueing non-persistently mapped buffer %u", buffer->id); - goto buffer_error; - } - - if(BufferFmt == nullptr) - BufferFmt = buffer; - else if(BufferFmt->Frequency != buffer->Frequency || - BufferFmt->mFmtChannels != buffer->mFmtChannels || - BufferFmt->OriginalType != buffer->OriginalType) - { - alSetError(context.get(), AL_INVALID_OPERATION, - "Queueing buffer with mismatched format"); - - buffer_error: - /* A buffer failed (invalid ID or format), so unlock and release - * each buffer we had. */ - while(BufferListStart) - { - ALbufferlistitem *next = BufferListStart->next.load(std::memory_order_relaxed); - for(i = 0;i < BufferListStart->num_buffers;i++) - { - if((buffer=BufferListStart->buffers[i]) != nullptr) - DecrementRef(&buffer->ref); - } - al_free(BufferListStart); - BufferListStart = next; - } - return; - } - } - /* All buffers good. */ - buflock.unlock(); - - /* Source is now streaming */ - source->SourceType = AL_STREAMING; - - if(!(BufferList=source->queue)) - source->queue = BufferListStart; - else - { - ALbufferlistitem *next; - while((next=BufferList->next.load(std::memory_order_relaxed)) != nullptr) - BufferList = next; - BufferList->next.store(BufferListStart, std::memory_order_release); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(nb < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffer layers", nb); - if(nb == 0) return; - - std::lock_guard _{context->SourceLock}; - ALsource *source{LookupSource(context.get(),src)}; - if(UNLIKELY(!source)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); - - /* Can't queue on a Static Source */ - if(UNLIKELY(source->SourceType == AL_STATIC)) - SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src); - - /* Check for a valid Buffer, for its frequency and format */ - ALCdevice *device{context->Device}; - ALbuffer *BufferFmt{nullptr}; - ALbufferlistitem *BufferList{source->queue}; - while(BufferList) - { - for(ALsizei i{0};i < BufferList->num_buffers;i++) - { - if((BufferFmt=BufferList->buffers[i]) != nullptr) - break; - } - if(BufferFmt) break; - BufferList = BufferList->next.load(std::memory_order_relaxed); - } - - std::unique_lock buflock{device->BufferLock}; - auto BufferListStart = static_cast(al_calloc(alignof(void*), - ALbufferlistitem::Sizeof(nb))); - BufferList = BufferListStart; - BufferList->next.store(nullptr, std::memory_order_relaxed); - BufferList->max_samples = 0; - BufferList->num_buffers = 0; - - for(ALsizei i{0};i < nb;i++) - { - ALbuffer *buffer{nullptr}; - if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr) - { - alSetError(context.get(), AL_INVALID_NAME, "Queueing invalid buffer ID %u", - buffers[i]); - goto buffer_error; - } - - BufferList->buffers[BufferList->num_buffers++] = buffer; - if(!buffer) continue; - - IncrementRef(&buffer->ref); - - BufferList->max_samples = maxi(BufferList->max_samples, buffer->SampleLen); - - if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) - { - alSetError(context.get(), AL_INVALID_OPERATION, - "Queueing non-persistently mapped buffer %u", buffer->id); - goto buffer_error; - } - - if(BufferFmt == nullptr) - BufferFmt = buffer; - else if(BufferFmt->Frequency != buffer->Frequency || - BufferFmt->mFmtChannels != buffer->mFmtChannels || - BufferFmt->OriginalType != buffer->OriginalType) - { - alSetError(context.get(), AL_INVALID_OPERATION, - "Queueing buffer with mismatched format"); - - buffer_error: - /* A buffer failed (invalid ID or format), so unlock and release - * each buffer we had. */ - while(BufferListStart) - { - ALbufferlistitem *next{BufferListStart->next.load(std::memory_order_relaxed)}; - for(i = 0;i < BufferListStart->num_buffers;i++) - { - if((buffer=BufferListStart->buffers[i]) != nullptr) - DecrementRef(&buffer->ref); - } - al_free(BufferListStart); - BufferListStart = next; - } - return; - } - } - /* All buffers good. */ - buflock.unlock(); - - /* Source is now streaming */ - source->SourceType = AL_STREAMING; - - if(!(BufferList=source->queue)) - source->queue = BufferListStart; - else - { - ALbufferlistitem *next; - while((next=BufferList->next.load(std::memory_order_relaxed)) != nullptr) - BufferList = next; - BufferList->next.store(BufferListStart, std::memory_order_release); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(nb < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing %d buffers", nb); - if(nb == 0) return; - - std::lock_guard _{context->SourceLock}; - ALsource *source{LookupSource(context.get(),src)}; - if(UNLIKELY(!source)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); - - if(UNLIKELY(source->Looping)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing from looping source %u", src); - if(UNLIKELY(source->SourceType != AL_STREAMING)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, - "Unqueueing from a non-streaming source %u", src); - - /* Make sure enough buffers have been processed to unqueue. */ - ALbufferlistitem *BufferList{source->queue}; - ALvoice *voice{GetSourceVoice(source, context.get())}; - ALbufferlistitem *Current{nullptr}; - if(voice) - Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); - else if(source->state == AL_INITIAL) - Current = BufferList; - if(UNLIKELY(BufferList == Current)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing pending buffers"); - - ALsizei i{BufferList->num_buffers}; - while(i < nb) - { - /* If the next bufferlist to check is NULL or is the current one, it's - * trying to unqueue pending buffers. - */ - ALbufferlistitem *next{BufferList->next.load(std::memory_order_relaxed)}; - if(UNLIKELY(!next) || UNLIKELY(next == Current)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing pending buffers"); - BufferList = next; - - i += BufferList->num_buffers; - } - - while(nb > 0) - { - ALbufferlistitem *head{source->queue}; - ALbufferlistitem *next{head->next.load(std::memory_order_relaxed)}; - for(i = 0;i < head->num_buffers && nb > 0;i++,nb--) - { - ALbuffer *buffer{head->buffers[i]}; - if(!buffer) - *(buffers++) = 0; - else - { - *(buffers++) = buffer->id; - DecrementRef(&buffer->ref); - } - } - if(i < head->num_buffers) - { - /* This head has some buffers left over, so move them to the front - * and update the sample and buffer count. - */ - ALsizei max_length{0}; - ALsizei j{0}; - while(i < head->num_buffers) - { - ALbuffer *buffer{head->buffers[i++]}; - if(buffer) max_length = maxi(max_length, buffer->SampleLen); - head->buffers[j++] = buffer; - } - head->max_samples = max_length; - head->num_buffers = j; - break; - } - - /* Otherwise, free this item and set the source queue head to the next - * one. - */ - al_free(head); - source->queue = next; - } -} -END_API_FUNC - - -ALsource::ALsource(ALsizei num_sends) -{ - InnerAngle = 360.0f; - OuterAngle = 360.0f; - Pitch = 1.0f; - Position[0] = 0.0f; - Position[1] = 0.0f; - Position[2] = 0.0f; - Velocity[0] = 0.0f; - Velocity[1] = 0.0f; - Velocity[2] = 0.0f; - Direction[0] = 0.0f; - Direction[1] = 0.0f; - Direction[2] = 0.0f; - OrientAt[0] = 0.0f; - OrientAt[1] = 0.0f; - OrientAt[2] = -1.0f; - OrientUp[0] = 0.0f; - OrientUp[1] = 1.0f; - OrientUp[2] = 0.0f; - RefDistance = 1.0f; - MaxDistance = std::numeric_limits::max(); - RolloffFactor = 1.0f; - Gain = 1.0f; - MinGain = 0.0f; - MaxGain = 1.0f; - OuterGain = 0.0f; - OuterGainHF = 1.0f; - - DryGainHFAuto = AL_TRUE; - WetGainAuto = AL_TRUE; - WetGainHFAuto = AL_TRUE; - AirAbsorptionFactor = 0.0f; - RoomRolloffFactor = 0.0f; - DopplerFactor = 1.0f; - HeadRelative = AL_FALSE; - Looping = AL_FALSE; - mDistanceModel = DistanceModel::Default; - mResampler = ResamplerDefault; - DirectChannels = AL_FALSE; - mSpatialize = SpatializeAuto; - - StereoPan[0] = Deg2Rad( 30.0f); - StereoPan[1] = Deg2Rad(-30.0f); - - Radius = 0.0f; - - Direct.Gain = 1.0f; - Direct.GainHF = 1.0f; - Direct.HFReference = LOWPASSFREQREF; - Direct.GainLF = 1.0f; - Direct.LFReference = HIGHPASSFREQREF; - Send.resize(num_sends); - for(auto &send : Send) - { - send.Slot = nullptr; - send.Gain = 1.0f; - send.GainHF = 1.0f; - send.HFReference = LOWPASSFREQREF; - send.GainLF = 1.0f; - send.LFReference = HIGHPASSFREQREF; - } - - Offset = 0.0; - OffsetType = AL_NONE; - SourceType = AL_UNDETERMINED; - state = AL_INITIAL; - - queue = nullptr; - - PropsClean.test_and_set(std::memory_order_relaxed); - - VoiceIdx = -1; -} - -ALsource::~ALsource() -{ - ALbufferlistitem *BufferList{queue}; - while(BufferList != nullptr) - { - ALbufferlistitem *next{BufferList->next.load(std::memory_order_relaxed)}; - for(ALsizei i{0};i < BufferList->num_buffers;i++) - { - if(BufferList->buffers[i]) - DecrementRef(&BufferList->buffers[i]->ref); - } - al_free(BufferList); - BufferList = next; - } - queue = nullptr; - - std::for_each(Send.begin(), Send.end(), - [](ALsource::SendData &send) -> void - { - if(send.Slot) - DecrementRef(&send.Slot->ref); - send.Slot = nullptr; - } - ); -} - -void UpdateAllSourceProps(ALCcontext *context) -{ - auto voices_end = context->Voices->begin() + - context->VoiceCount.load(std::memory_order_relaxed); - std::for_each(context->Voices->begin(), voices_end, - [context](ALvoice &voice) -> void - { - ALuint sid{voice.mSourceID.load(std::memory_order_acquire)}; - ALsource *source = sid ? LookupSource(context, sid) : nullptr; - if(source && !source->PropsClean.test_and_set(std::memory_order_acq_rel)) - UpdateSourceProps(source, &voice, context); - } - ); -} - -SourceSubList::~SourceSubList() -{ - uint64_t usemask{~FreeMask}; - while(usemask) - { - ALsizei idx{CTZ64(usemask)}; - al::destroy_at(Sources+idx); - usemask &= ~(1_u64 << idx); - } - FreeMask = ~usemask; - al_free(Sources); - Sources = nullptr; -} diff --git a/al/alSource.h b/al/alSource.h deleted file mode 100644 index c9892398..00000000 --- a/al/alSource.h +++ /dev/null @@ -1,131 +0,0 @@ -#ifndef AL_SOURCE_H -#define AL_SOURCE_H - -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" - -#include "alcontext.h" -#include "alnumeric.h" -#include "alu.h" -#include "vector.h" - -struct ALbuffer; -struct ALeffectslot; - - -#define DEFAULT_SENDS 2 - - -struct ALbufferlistitem { - std::atomic next; - ALsizei max_samples; - ALsizei num_buffers; - ALbuffer *buffers[]; - - static constexpr size_t Sizeof(size_t num_buffers) noexcept - { - return maxz(offsetof(ALbufferlistitem, buffers) + sizeof(ALbuffer*)*num_buffers, - sizeof(ALbufferlistitem)); - } -}; - - -struct ALsource { - /** Source properties. */ - ALfloat Pitch; - ALfloat Gain; - ALfloat OuterGain; - ALfloat MinGain; - ALfloat MaxGain; - ALfloat InnerAngle; - ALfloat OuterAngle; - ALfloat RefDistance; - ALfloat MaxDistance; - ALfloat RolloffFactor; - std::array Position; - std::array Velocity; - std::array Direction; - std::array OrientAt; - std::array OrientUp; - ALboolean HeadRelative; - ALboolean Looping; - DistanceModel mDistanceModel; - Resampler mResampler; - ALboolean DirectChannels; - SpatializeMode mSpatialize; - - ALboolean DryGainHFAuto; - ALboolean WetGainAuto; - ALboolean WetGainHFAuto; - ALfloat OuterGainHF; - - ALfloat AirAbsorptionFactor; - ALfloat RoomRolloffFactor; - ALfloat DopplerFactor; - - /* NOTE: Stereo pan angles are specified in radians, counter-clockwise - * rather than clockwise. - */ - std::array StereoPan; - - ALfloat Radius; - - /** Direct filter and auxiliary send info. */ - struct { - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - } Direct; - struct SendData { - ALeffectslot *Slot; - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - }; - al::vector Send; - - /** - * Last user-specified offset, and the offset type (bytes, samples, or - * seconds). - */ - ALdouble Offset; - ALenum OffsetType; - - /** Source type (static, streaming, or undetermined) */ - ALint SourceType; - - /** Source state (initial, playing, paused, or stopped) */ - ALenum state; - - /** Source Buffer Queue head. */ - ALbufferlistitem *queue; - - std::atomic_flag PropsClean; - - /* Index into the context's Voices array. Lazily updated, only checked and - * reset when looking up the voice. - */ - ALint VoiceIdx; - - /** Self ID */ - ALuint id; - - - ALsource(ALsizei num_sends); - ~ALsource(); - - ALsource(const ALsource&) = delete; - ALsource& operator=(const ALsource&) = delete; -}; - -void UpdateAllSourceProps(ALCcontext *context); - -#endif diff --git a/al/alState.cpp b/al/alState.cpp deleted file mode 100644 index 001412a8..00000000 --- a/al/alState.cpp +++ /dev/null @@ -1,859 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2000 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include "version.h" - -#include -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" - -#include "alError.h" -#include "alcontext.h" -#include "alexcpt.h" -#include "almalloc.h" -#include "alspan.h" -#include "alu.h" -#include "atomic.h" -#include "event.h" -#include "inprogext.h" -#include "opthelpers.h" - - -namespace { - -constexpr ALchar alVendor[] = "OpenAL Community"; -constexpr ALchar alVersion[] = "1.1 ALSOFT " ALSOFT_VERSION; -constexpr ALchar alRenderer[] = "OpenAL Soft"; - -// Error Messages -constexpr ALchar alNoError[] = "No Error"; -constexpr ALchar alErrInvalidName[] = "Invalid Name"; -constexpr ALchar alErrInvalidEnum[] = "Invalid Enum"; -constexpr ALchar alErrInvalidValue[] = "Invalid Value"; -constexpr ALchar alErrInvalidOp[] = "Invalid Operation"; -constexpr ALchar alErrOutOfMemory[] = "Out of Memory"; - -/* Resampler strings */ -constexpr ALchar alPointResampler[] = "Nearest"; -constexpr ALchar alLinearResampler[] = "Linear"; -constexpr ALchar alCubicResampler[] = "Cubic"; -constexpr ALchar alBSinc12Resampler[] = "11th order Sinc"; -constexpr ALchar alBSinc24Resampler[] = "23rd order Sinc"; - -} // namespace - -/* WARNING: Non-standard export! Not part of any extension, or exposed in the - * alcFunctions list. - */ -extern "C" AL_API const ALchar* AL_APIENTRY alsoft_get_version(void) -START_API_FUNC -{ - const char *spoof{getenv("ALSOFT_SPOOF_VERSION")}; - if(spoof && spoof[0] != '\0') return spoof; - return ALSOFT_VERSION; -} -END_API_FUNC - -#define DO_UPDATEPROPS() do { \ - if(!context->DeferUpdates.load(std::memory_order_acquire)) \ - UpdateContextProps(context.get()); \ - else \ - context->PropsClean.clear(std::memory_order_release); \ -} while(0) - - -AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - switch(capability) - { - case AL_SOURCE_DISTANCE_MODEL: - context->SourceDistanceModel = AL_TRUE; - DO_UPDATEPROPS(); - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - std::lock_guard _{context->PropLock}; - switch(capability) - { - case AL_SOURCE_DISTANCE_MODEL: - context->SourceDistanceModel = AL_FALSE; - DO_UPDATEPROPS(); - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability); - } -} -END_API_FUNC - -AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return AL_FALSE; - - std::lock_guard _{context->PropLock}; - ALboolean value{AL_FALSE}; - switch(capability) - { - case AL_SOURCE_DISTANCE_MODEL: - value = context->SourceDistanceModel; - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability); - } - - return value; -} -END_API_FUNC - -AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return AL_FALSE; - - std::lock_guard _{context->PropLock}; - ALboolean value{AL_FALSE}; - switch(pname) - { - case AL_DOPPLER_FACTOR: - if(context->DopplerFactor != 0.0f) - value = AL_TRUE; - break; - - case AL_DOPPLER_VELOCITY: - if(context->DopplerVelocity != 0.0f) - value = AL_TRUE; - break; - - case AL_DISTANCE_MODEL: - if(context->mDistanceModel == DistanceModel::Default) - value = AL_TRUE; - break; - - case AL_SPEED_OF_SOUND: - if(context->SpeedOfSound != 0.0f) - value = AL_TRUE; - break; - - case AL_DEFERRED_UPDATES_SOFT: - if(context->DeferUpdates.load(std::memory_order_acquire)) - value = AL_TRUE; - break; - - case AL_GAIN_LIMIT_SOFT: - if(GAIN_MIX_MAX/context->GainBoost != 0.0f) - value = AL_TRUE; - break; - - case AL_NUM_RESAMPLERS_SOFT: - /* Always non-0. */ - value = AL_TRUE; - break; - - case AL_DEFAULT_RESAMPLER_SOFT: - value = ResamplerDefault ? AL_TRUE : AL_FALSE; - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid boolean property 0x%04x", pname); - } - - return value; -} -END_API_FUNC - -AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return 0.0; - - std::lock_guard _{context->PropLock}; - ALdouble value{0.0}; - switch(pname) - { - case AL_DOPPLER_FACTOR: - value = static_cast(context->DopplerFactor); - break; - - case AL_DOPPLER_VELOCITY: - value = static_cast(context->DopplerVelocity); - break; - - case AL_DISTANCE_MODEL: - value = static_cast(context->mDistanceModel); - break; - - case AL_SPEED_OF_SOUND: - value = static_cast(context->SpeedOfSound); - break; - - case AL_DEFERRED_UPDATES_SOFT: - if(context->DeferUpdates.load(std::memory_order_acquire)) - value = static_cast(AL_TRUE); - break; - - case AL_GAIN_LIMIT_SOFT: - value = static_castGAIN_MIX_MAX/context->GainBoost; - break; - - case AL_NUM_RESAMPLERS_SOFT: - value = static_cast(ResamplerMax + 1); - break; - - case AL_DEFAULT_RESAMPLER_SOFT: - value = static_cast(ResamplerDefault); - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid double property 0x%04x", pname); - } - - return value; -} -END_API_FUNC - -AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return 0.0f; - - std::lock_guard _{context->PropLock}; - ALfloat value{0.0f}; - switch(pname) - { - case AL_DOPPLER_FACTOR: - value = context->DopplerFactor; - break; - - case AL_DOPPLER_VELOCITY: - value = context->DopplerVelocity; - break; - - case AL_DISTANCE_MODEL: - value = static_cast(context->mDistanceModel); - break; - - case AL_SPEED_OF_SOUND: - value = context->SpeedOfSound; - break; - - case AL_DEFERRED_UPDATES_SOFT: - if(context->DeferUpdates.load(std::memory_order_acquire)) - value = static_cast(AL_TRUE); - break; - - case AL_GAIN_LIMIT_SOFT: - value = GAIN_MIX_MAX/context->GainBoost; - break; - - case AL_NUM_RESAMPLERS_SOFT: - value = static_cast(ResamplerMax + 1); - break; - - case AL_DEFAULT_RESAMPLER_SOFT: - value = static_cast(ResamplerDefault); - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid float property 0x%04x", pname); - } - - return value; -} -END_API_FUNC - -AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return 0; - - std::lock_guard _{context->PropLock}; - ALint value{0}; - switch(pname) - { - case AL_DOPPLER_FACTOR: - value = static_cast(context->DopplerFactor); - break; - - case AL_DOPPLER_VELOCITY: - value = static_cast(context->DopplerVelocity); - break; - - case AL_DISTANCE_MODEL: - value = static_cast(context->mDistanceModel); - break; - - case AL_SPEED_OF_SOUND: - value = static_cast(context->SpeedOfSound); - break; - - case AL_DEFERRED_UPDATES_SOFT: - if(context->DeferUpdates.load(std::memory_order_acquire)) - value = static_cast(AL_TRUE); - break; - - case AL_GAIN_LIMIT_SOFT: - value = static_cast(GAIN_MIX_MAX/context->GainBoost); - break; - - case AL_NUM_RESAMPLERS_SOFT: - value = ResamplerMax + 1; - break; - - case AL_DEFAULT_RESAMPLER_SOFT: - value = ResamplerDefault; - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer property 0x%04x", pname); - } - - return value; -} -END_API_FUNC - -extern "C" AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return 0; - - std::lock_guard _{context->PropLock}; - ALint64SOFT value{0}; - switch(pname) - { - case AL_DOPPLER_FACTOR: - value = (ALint64SOFT)context->DopplerFactor; - break; - - case AL_DOPPLER_VELOCITY: - value = (ALint64SOFT)context->DopplerVelocity; - break; - - case AL_DISTANCE_MODEL: - value = (ALint64SOFT)context->mDistanceModel; - break; - - case AL_SPEED_OF_SOUND: - value = (ALint64SOFT)context->SpeedOfSound; - break; - - case AL_DEFERRED_UPDATES_SOFT: - if(context->DeferUpdates.load(std::memory_order_acquire)) - value = (ALint64SOFT)AL_TRUE; - break; - - case AL_GAIN_LIMIT_SOFT: - value = (ALint64SOFT)(GAIN_MIX_MAX/context->GainBoost); - break; - - case AL_NUM_RESAMPLERS_SOFT: - value = (ALint64SOFT)(ResamplerMax + 1); - break; - - case AL_DEFAULT_RESAMPLER_SOFT: - value = (ALint64SOFT)ResamplerDefault; - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer64 property 0x%04x", pname); - } - - return value; -} -END_API_FUNC - -AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return nullptr; - - std::lock_guard _{context->PropLock}; - void *value{nullptr}; - switch(pname) - { - case AL_EVENT_CALLBACK_FUNCTION_SOFT: - value = reinterpret_cast(context->EventCb); - break; - - case AL_EVENT_CALLBACK_USER_PARAM_SOFT: - value = context->EventParam; - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname); - } - - return value; -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values) -START_API_FUNC -{ - if(values) - { - switch(pname) - { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetBoolean(pname); - return; - } - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(pname) - { - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid boolean-vector property 0x%04x", pname); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values) -START_API_FUNC -{ - if(values) - { - switch(pname) - { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetDouble(pname); - return; - } - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(pname) - { - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid double-vector property 0x%04x", pname); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values) -START_API_FUNC -{ - if(values) - { - switch(pname) - { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetFloat(pname); - return; - } - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(pname) - { - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid float-vector property 0x%04x", pname); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values) -START_API_FUNC -{ - if(values) - { - switch(pname) - { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetInteger(pname); - return; - } - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(pname) - { - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer-vector property 0x%04x", pname); - } -} -END_API_FUNC - -extern "C" AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values) -START_API_FUNC -{ - if(values) - { - switch(pname) - { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetInteger64SOFT(pname); - return; - } - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(pname) - { - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer64-vector property 0x%04x", pname); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values) -START_API_FUNC -{ - if(values) - { - switch(pname) - { - case AL_EVENT_CALLBACK_FUNCTION_SOFT: - case AL_EVENT_CALLBACK_USER_PARAM_SOFT: - values[0] = alGetPointerSOFT(pname); - return; - } - } - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); - else switch(pname) - { - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid pointer-vector property 0x%04x", pname); - } -} -END_API_FUNC - -AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return nullptr; - - const ALchar *value{nullptr}; - switch(pname) - { - case AL_VENDOR: - value = alVendor; - break; - - case AL_VERSION: - value = alVersion; - break; - - case AL_RENDERER: - value = alRenderer; - break; - - case AL_EXTENSIONS: - value = context->ExtensionList; - break; - - case AL_NO_ERROR: - value = alNoError; - break; - - case AL_INVALID_NAME: - value = alErrInvalidName; - break; - - case AL_INVALID_ENUM: - value = alErrInvalidEnum; - break; - - case AL_INVALID_VALUE: - value = alErrInvalidValue; - break; - - case AL_INVALID_OPERATION: - value = alErrInvalidOp; - break; - - case AL_OUT_OF_MEMORY: - value = alErrOutOfMemory; - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid string property 0x%04x", pname); - } - return value; -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(!(value >= 0.0f && std::isfinite(value))) - alSetError(context.get(), AL_INVALID_VALUE, "Doppler factor %f out of range", value); - else - { - std::lock_guard _{context->PropLock}; - context->DopplerFactor = value; - DO_UPDATEPROPS(); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if((context->EnabledEvts.load(std::memory_order_relaxed)&EventType_Deprecated)) - { - static constexpr ALCchar msg[] = - "alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound"; - const ALsizei msglen = static_cast(strlen(msg)); - std::lock_guard _{context->EventCbLock}; - ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; - if((enabledevts&EventType_Deprecated) && context->EventCb) - (*context->EventCb)(AL_EVENT_TYPE_DEPRECATED_SOFT, 0, 0, msglen, msg, - context->EventParam); - } - - if(!(value >= 0.0f && std::isfinite(value))) - alSetError(context.get(), AL_INVALID_VALUE, "Doppler velocity %f out of range", value); - else - { - std::lock_guard _{context->PropLock}; - context->DopplerVelocity = value; - DO_UPDATEPROPS(); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(!(value > 0.0f && std::isfinite(value))) - alSetError(context.get(), AL_INVALID_VALUE, "Speed of sound %f out of range", value); - else - { - std::lock_guard _{context->PropLock}; - context->SpeedOfSound = value; - DO_UPDATEPROPS(); - } -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - if(!(value == AL_INVERSE_DISTANCE || value == AL_INVERSE_DISTANCE_CLAMPED || - value == AL_LINEAR_DISTANCE || value == AL_LINEAR_DISTANCE_CLAMPED || - value == AL_EXPONENT_DISTANCE || value == AL_EXPONENT_DISTANCE_CLAMPED || - value == AL_NONE)) - alSetError(context.get(), AL_INVALID_VALUE, "Distance model 0x%04x out of range", value); - else - { - std::lock_guard _{context->PropLock}; - context->mDistanceModel = static_cast(value); - if(!context->SourceDistanceModel) - DO_UPDATEPROPS(); - } -} -END_API_FUNC - - -AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCcontext_DeferUpdates(context.get()); -} -END_API_FUNC - -AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; - - ALCcontext_ProcessUpdates(context.get()); -} -END_API_FUNC - - -AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index) -START_API_FUNC -{ - const char *ResamplerNames[] = { - alPointResampler, alLinearResampler, - alCubicResampler, alBSinc12Resampler, - alBSinc24Resampler, - }; - static_assert(al::size(ResamplerNames) == ResamplerMax+1, "Incorrect ResamplerNames list"); - - ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return nullptr; - - const ALchar *value{nullptr}; - switch(pname) - { - case AL_RESAMPLER_NAME_SOFT: - if(index < 0 || static_cast(index) >= al::size(ResamplerNames)) - alSetError(context.get(), AL_INVALID_VALUE, "Resampler name index %d out of range", - index); - else - value = ResamplerNames[index]; - break; - - default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid string indexed property"); - } - return value; -} -END_API_FUNC - - -void UpdateContextProps(ALCcontext *context) -{ - /* Get an unused proprty container, or allocate a new one as needed. */ - ALcontextProps *props{context->FreeContextProps.load(std::memory_order_acquire)}; - if(!props) - props = static_cast(al_calloc(16, sizeof(*props))); - else - { - ALcontextProps *next; - do { - next = props->next.load(std::memory_order_relaxed); - } while(context->FreeContextProps.compare_exchange_weak(props, next, - std::memory_order_seq_cst, std::memory_order_acquire) == 0); - } - - /* Copy in current property values. */ - props->MetersPerUnit = context->MetersPerUnit; - - props->DopplerFactor = context->DopplerFactor; - props->DopplerVelocity = context->DopplerVelocity; - props->SpeedOfSound = context->SpeedOfSound; - - props->SourceDistanceModel = context->SourceDistanceModel; - props->mDistanceModel = context->mDistanceModel; - - /* Set the new container for updating internal parameters. */ - props = context->Update.exchange(props, std::memory_order_acq_rel); - if(props) - { - /* If there was an unused update container, put it back in the - * freelist. - */ - AtomicReplaceHead(context->FreeContextProps, props); - } -} diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp new file mode 100644 index 00000000..605923dd --- /dev/null +++ b/al/auxeffectslot.cpp @@ -0,0 +1,808 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "auxeffectslot.h" + +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" + +#include "alcmain.h" +#include "alcontext.h" +#include "alexcpt.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "alspan.h" +#include "alu.h" +#include "effect.h" +#include "error.h" +#include "fpu_modes.h" +#include "inprogext.h" +#include "logging.h" +#include "opthelpers.h" + + +namespace { + +inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= context->EffectSlotList.size())) + return nullptr; + EffectSlotSubList &sublist{context->EffectSlotList[lidx]}; + if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + return nullptr; + return sublist.EffectSlots + slidx; +} + +inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) noexcept +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= device->EffectList.size())) + return nullptr; + EffectSubList &sublist = device->EffectList[lidx]; + if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + return nullptr; + return sublist.Effects + slidx; +} + + +void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) +{ + if(count < 1) return; + ALeffectslotArray *curarray{context->ActiveAuxSlots.load(std::memory_order_acquire)}; + size_t newcount{curarray->size() + count}; + + /* Insert the new effect slots into the head of the array, followed by the + * existing ones. + */ + ALeffectslotArray *newarray = ALeffectslot::CreatePtrArray(newcount); + auto slotiter = std::transform(slotids, slotids+count, newarray->begin(), + [context](ALuint id) noexcept -> ALeffectslot* + { return LookupEffectSlot(context, id); } + ); + std::copy(curarray->begin(), curarray->end(), slotiter); + + /* Remove any duplicates (first instance of each will be kept). */ + auto last = newarray->end(); + for(auto start=newarray->begin()+1;;) + { + last = std::remove(start, last, *(start-1)); + if(start == last) break; + ++start; + } + newcount = static_cast(std::distance(newarray->begin(), last)); + + /* Reallocate newarray if the new size ended up smaller from duplicate + * removal. + */ + if(UNLIKELY(newcount < newarray->size())) + { + curarray = newarray; + newarray = ALeffectslot::CreatePtrArray(newcount); + std::copy_n(curarray->begin(), newcount, newarray->begin()); + delete curarray; + curarray = nullptr; + } + + curarray = context->ActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); + ALCdevice *device{context->Device}; + while((device->MixCount.load(std::memory_order_acquire)&1)) + std::this_thread::yield(); + delete curarray; +} + +void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) +{ + if(count < 1) return; + ALeffectslotArray *curarray{context->ActiveAuxSlots.load(std::memory_order_acquire)}; + + /* Don't shrink the allocated array size since we don't know how many (if + * any) of the effect slots to remove are in the array. + */ + ALeffectslotArray *newarray = ALeffectslot::CreatePtrArray(curarray->size()); + + /* Copy each element in curarray to newarray whose ID is not in slotids. */ + const ALuint *slotids_end{slotids + count}; + auto slotiter = std::copy_if(curarray->begin(), curarray->end(), newarray->begin(), + [slotids, slotids_end](const ALeffectslot *slot) -> bool + { return std::find(slotids, slotids_end, slot->id) == slotids_end; } + ); + + /* Reallocate with the new size. */ + auto newsize = static_cast(std::distance(newarray->begin(), slotiter)); + if(LIKELY(newsize != newarray->size())) + { + curarray = newarray; + newarray = ALeffectslot::CreatePtrArray(newsize); + std::copy_n(curarray->begin(), newsize, newarray->begin()); + + delete curarray; + curarray = nullptr; + } + + curarray = context->ActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); + ALCdevice *device{context->Device}; + while((device->MixCount.load(std::memory_order_acquire)&1)) + std::this_thread::yield(); + delete curarray; +} + + +ALeffectslot *AllocEffectSlot(ALCcontext *context) +{ + ALCdevice *device{context->Device}; + std::lock_guard _{context->EffectSlotLock}; + if(context->NumEffectSlots >= device->AuxiliaryEffectSlotMax) + { + alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u effect slot limit", + device->AuxiliaryEffectSlotMax); + return nullptr; + } + auto sublist = std::find_if(context->EffectSlotList.begin(), context->EffectSlotList.end(), + [](const EffectSlotSubList &entry) noexcept -> bool + { return entry.FreeMask != 0; } + ); + auto lidx = static_cast(std::distance(context->EffectSlotList.begin(), sublist)); + ALeffectslot *slot; + ALsizei slidx; + if(LIKELY(sublist != context->EffectSlotList.end())) + { + slidx = CTZ64(sublist->FreeMask); + slot = sublist->EffectSlots + slidx; + } + else + { + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(context->EffectSlotList.size() >= 1<<25)) + { + alSetError(context, AL_OUT_OF_MEMORY, "Too many effect slots allocated"); + return nullptr; + } + context->EffectSlotList.emplace_back(); + sublist = context->EffectSlotList.end() - 1; + + sublist->FreeMask = ~0_u64; + sublist->EffectSlots = static_cast(al_calloc(16, sizeof(ALeffectslot)*64)); + if(UNLIKELY(!sublist->EffectSlots)) + { + context->EffectSlotList.pop_back(); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect slot batch"); + return nullptr; + } + + slidx = 0; + slot = sublist->EffectSlots + slidx; + } + + slot = new (slot) ALeffectslot{}; + ALenum err{InitEffectSlot(slot)}; + if(err != AL_NO_ERROR) + { + al::destroy_at(slot); + alSetError(context, err, "Effect slot object initialization failed"); + return nullptr; + } + aluInitEffectPanning(slot, device); + + /* Add 1 to avoid source ID 0. */ + slot->id = ((lidx<<6) | slidx) + 1; + + context->NumEffectSlots += 1; + sublist->FreeMask &= ~(1_u64 << slidx); + + return slot; +} + +void FreeEffectSlot(ALCcontext *context, ALeffectslot *slot) +{ + ALuint id = slot->id - 1; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; + + al::destroy_at(slot); + + context->EffectSlotList[lidx].FreeMask |= 1_u64 << slidx; + context->NumEffectSlots--; +} + + +#define DO_UPDATEPROPS() do { \ + if(!context->DeferUpdates.load(std::memory_order_acquire)) \ + UpdateEffectSlotProps(slot, context.get()); \ + else \ + slot->PropsClean.clear(std::memory_order_release); \ +} while(0) + +} // namespace + +ALeffectslotArray *ALeffectslot::CreatePtrArray(size_t count) noexcept +{ + /* Allocate space for twice as many pointers, so the mixer has scratch + * space to store a sorted list during mixing. + */ + void *ptr{al_calloc(alignof(ALeffectslotArray), ALeffectslotArray::Sizeof(count*2))}; + return new (ptr) ALeffectslotArray{count}; +} + + +AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(n < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Generating %d effect slots", n); + if(n == 0) return; + + if(n == 1) + { + ALeffectslot *slot{AllocEffectSlot(context.get())}; + if(!slot) return; + effectslots[0] = slot->id; + } + else + { + auto tempids = al::vector(n); + auto alloc_end = std::find_if_not(tempids.begin(), tempids.end(), + [&context](ALuint &id) -> bool + { + ALeffectslot *slot{AllocEffectSlot(context.get())}; + if(!slot) return false; + id = slot->id; + return true; + } + ); + if(alloc_end != tempids.end()) + { + auto count = static_cast(std::distance(tempids.begin(), alloc_end)); + alDeleteAuxiliaryEffectSlots(count, tempids.data()); + return; + } + + std::copy(tempids.cbegin(), tempids.cend(), effectslots); + } + + std::unique_lock slotlock{context->EffectSlotLock}; + AddActiveEffectSlots(effectslots, n, context.get()); +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(n < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Deleting %d effect slots", n); + if(n == 0) return; + + std::lock_guard _{context->EffectSlotLock}; + auto effectslots_end = effectslots + n; + auto bad_slot = std::find_if(effectslots, effectslots_end, + [&context](ALuint id) -> bool + { + ALeffectslot *slot{LookupEffectSlot(context.get(), id)}; + if(!slot) + { + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect slot ID %u", id); + return true; + } + if(ReadRef(&slot->ref) != 0) + { + alSetError(context.get(), AL_INVALID_NAME, "Deleting in-use effect slot %u", id); + return true; + } + return false; + } + ); + if(bad_slot != effectslots_end) + return; + + // All effectslots are valid, remove and delete them + RemoveActiveEffectSlots(effectslots, n, context.get()); + std::for_each(effectslots, effectslots_end, + [&context](ALuint sid) -> void + { + ALeffectslot *slot{LookupEffectSlot(context.get(), sid)}; + if(slot) FreeEffectSlot(context.get(), slot); + } + ); +} +END_API_FUNC + +AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(LIKELY(context)) + { + std::lock_guard _{context->EffectSlotLock}; + if(LookupEffectSlot(context.get(), effectslot) != nullptr) + return AL_TRUE; + } + return AL_FALSE; +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + + ALeffectslot *target{}; + ALCdevice *device{}; + ALenum err{}; + switch(param) + { + case AL_EFFECTSLOT_EFFECT: + device = context->Device; + + { std::lock_guard ___{device->EffectLock}; + ALeffect *effect{value ? LookupEffect(device, value) : nullptr}; + if(!(value == 0 || effect != nullptr)) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Invalid effect ID %u", value); + err = InitializeEffect(context.get(), slot, effect); + } + if(err != AL_NO_ERROR) + { + alSetError(context.get(), err, "Effect initialization failed"); + return; + } + break; + + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + if(!(value == AL_TRUE || value == AL_FALSE)) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, + "Effect slot auxiliary send auto out of range"); + slot->AuxSendAuto = value; + break; + + case AL_EFFECTSLOT_TARGET_SOFT: + target = (value ? LookupEffectSlot(context.get(), value) : nullptr); + if(value && !target) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Invalid effect slot target ID"); + if(target) + { + ALeffectslot *checker{target}; + while(checker && checker != slot) + checker = checker->Target; + if(checker) + SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, + "Setting target of effect slot ID %u to %u creates circular chain", slot->id, + target->id); + } + + if(ALeffectslot *oldtarget{slot->Target}) + { + /* We must force an update if there was an existing effect slot + * target, in case it's about to be deleted. + */ + if(target) IncrementRef(&target->ref); + DecrementRef(&oldtarget->ref); + slot->Target = target; + UpdateEffectSlotProps(slot, context.get()); + return; + } + + if(target) IncrementRef(&target->ref); + slot->Target = target; + break; + + default: + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot integer property 0x%04x", param); + } + DO_UPDATEPROPS(); +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values) +START_API_FUNC +{ + switch(param) + { + case AL_EFFECTSLOT_EFFECT: + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + case AL_EFFECTSLOT_TARGET_SOFT: + alAuxiliaryEffectSloti(effectslot, param, values[0]); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + + switch(param) + { + default: + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot integer-vector property 0x%04x", param); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + + switch(param) + { + case AL_EFFECTSLOT_GAIN: + if(!(value >= 0.0f && value <= 1.0f)) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Effect slot gain out of range"); + slot->Gain = value; + break; + + default: + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, "Invalid effect slot float property 0x%04x", + param); + } + DO_UPDATEPROPS(); +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values) +START_API_FUNC +{ + switch(param) + { + case AL_EFFECTSLOT_GAIN: + alAuxiliaryEffectSlotf(effectslot, param, values[0]); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + + switch(param) + { + default: + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot float-vector property 0x%04x", param); + } +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + + switch(param) + { + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + *value = slot->AuxSendAuto; + break; + + case AL_EFFECTSLOT_TARGET_SOFT: + *value = slot->Target ? slot->Target->id : 0; + break; + + default: + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot integer property 0x%04x", param); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values) +START_API_FUNC +{ + switch(param) + { + case AL_EFFECTSLOT_EFFECT: + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + case AL_EFFECTSLOT_TARGET_SOFT: + alGetAuxiliaryEffectSloti(effectslot, param, values); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + + switch(param) + { + default: + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot integer-vector property 0x%04x", param); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + + switch(param) + { + case AL_EFFECTSLOT_GAIN: + *value = slot->Gain; + break; + + default: + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot float property 0x%04x", param); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values) +START_API_FUNC +{ + switch(param) + { + case AL_EFFECTSLOT_GAIN: + alGetAuxiliaryEffectSlotf(effectslot, param, values); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->EffectSlotLock}; + ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); + if(UNLIKELY(!slot)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + + switch(param) + { + default: + SETERR_RETURN(context.get(), AL_INVALID_ENUM,, + "Invalid effect slot float-vector property 0x%04x", param); + } +} +END_API_FUNC + + +ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect) +{ + ALenum newtype{effect ? effect->type : AL_EFFECT_NULL}; + if(newtype != EffectSlot->Effect.Type) + { + EffectStateFactory *factory{getFactoryByType(newtype)}; + if(!factory) + { + ERR("Failed to find factory for effect type 0x%04x\n", newtype); + return AL_INVALID_ENUM; + } + EffectState *State{factory->create()}; + if(!State) return AL_OUT_OF_MEMORY; + + FPUCtl mixer_mode{}; + ALCdevice *Device{Context->Device}; + std::unique_lock statelock{Device->StateLock}; + State->mOutTarget = Device->Dry.Buffer; + if(State->deviceUpdate(Device) == AL_FALSE) + { + statelock.unlock(); + mixer_mode.leave(); + State->DecRef(); + return AL_OUT_OF_MEMORY; + } + mixer_mode.leave(); + + if(!effect) + { + EffectSlot->Effect.Type = AL_EFFECT_NULL; + EffectSlot->Effect.Props = EffectProps {}; + } + else + { + EffectSlot->Effect.Type = effect->type; + EffectSlot->Effect.Props = effect->Props; + } + + EffectSlot->Effect.State->DecRef(); + EffectSlot->Effect.State = State; + } + else if(effect) + EffectSlot->Effect.Props = effect->Props; + + /* Remove state references from old effect slot property updates. */ + ALeffectslotProps *props{Context->FreeEffectslotProps.load()}; + while(props) + { + if(props->State) + props->State->DecRef(); + props->State = nullptr; + props = props->next.load(std::memory_order_relaxed); + } + + return AL_NO_ERROR; +} + + +void EffectState::IncRef() noexcept +{ + auto ref = IncrementRef(&mRef); + TRACEREF("EffectState %p increasing refcount to %u\n", this, ref); +} + +void EffectState::DecRef() noexcept +{ + auto ref = DecrementRef(&mRef); + TRACEREF("EffectState %p decreasing refcount to %u\n", this, ref); + if(ref == 0) delete this; +} + + +ALenum InitEffectSlot(ALeffectslot *slot) +{ + EffectStateFactory *factory{getFactoryByType(slot->Effect.Type)}; + if(!factory) return AL_INVALID_VALUE; + slot->Effect.State = factory->create(); + if(!slot->Effect.State) return AL_OUT_OF_MEMORY; + + slot->Effect.State->IncRef(); + slot->Params.mEffectState = slot->Effect.State; + return AL_NO_ERROR; +} + +ALeffectslot::~ALeffectslot() +{ + if(Target) + DecrementRef(&Target->ref); + Target = nullptr; + + ALeffectslotProps *props{Update.load()}; + if(props) + { + if(props->State) props->State->DecRef(); + TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props); + al_free(props); + } + + if(Effect.State) + Effect.State->DecRef(); + if(Params.mEffectState) + Params.mEffectState->DecRef(); +} + +void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) +{ + /* Get an unused property container, or allocate a new one as needed. */ + ALeffectslotProps *props{context->FreeEffectslotProps.load(std::memory_order_relaxed)}; + if(!props) + props = static_cast(al_calloc(16, sizeof(*props))); + else + { + ALeffectslotProps *next; + do { + next = props->next.load(std::memory_order_relaxed); + } while(context->FreeEffectslotProps.compare_exchange_weak(props, next, + std::memory_order_seq_cst, std::memory_order_acquire) == 0); + } + + /* Copy in current property values. */ + props->Gain = slot->Gain; + props->AuxSendAuto = slot->AuxSendAuto; + props->Target = slot->Target; + + props->Type = slot->Effect.Type; + props->Props = slot->Effect.Props; + /* Swap out any stale effect state object there may be in the container, to + * delete it. + */ + EffectState *oldstate{props->State}; + slot->Effect.State->IncRef(); + props->State = slot->Effect.State; + + /* Set the new container for updating internal parameters. */ + props = slot->Update.exchange(props, std::memory_order_acq_rel); + if(props) + { + /* If there was an unused update container, put it back in the + * freelist. + */ + if(props->State) + props->State->DecRef(); + props->State = nullptr; + AtomicReplaceHead(context->FreeEffectslotProps, props); + } + + if(oldstate) + oldstate->DecRef(); +} + +void UpdateAllEffectSlotProps(ALCcontext *context) +{ + std::lock_guard _{context->EffectSlotLock}; + ALeffectslotArray *auxslots{context->ActiveAuxSlots.load(std::memory_order_acquire)}; + for(ALeffectslot *slot : *auxslots) + { + if(!slot->PropsClean.test_and_set(std::memory_order_acq_rel)) + UpdateEffectSlotProps(slot, context); + } +} + +EffectSlotSubList::~EffectSlotSubList() +{ + uint64_t usemask{~FreeMask}; + while(usemask) + { + ALsizei idx{CTZ64(usemask)}; + al::destroy_at(EffectSlots+idx); + usemask &= ~(1_u64 << idx); + } + FreeMask = ~usemask; + al_free(EffectSlots); + EffectSlots = nullptr; +} diff --git a/al/auxeffectslot.h b/al/auxeffectslot.h new file mode 100644 index 00000000..369638a0 --- /dev/null +++ b/al/auxeffectslot.h @@ -0,0 +1,103 @@ +#ifndef AL_AUXEFFECTSLOT_H +#define AL_AUXEFFECTSLOT_H + +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/efx.h" + +#include "alcmain.h" +#include "almalloc.h" +#include "atomic.h" +#include "effects/base.h" +#include "vector.h" + +struct ALeffect; +struct ALeffectslot; + + +using ALeffectslotArray = al::FlexArray; + + +struct ALeffectslotProps { + ALfloat Gain; + ALboolean AuxSendAuto; + ALeffectslot *Target; + + ALenum Type; + EffectProps Props; + + EffectState *State; + + std::atomic next; +}; + + +struct ALeffectslot { + ALfloat Gain{1.0f}; + ALboolean AuxSendAuto{AL_TRUE}; + ALeffectslot *Target{nullptr}; + + struct { + ALenum Type{AL_EFFECT_NULL}; + EffectProps Props{}; + + EffectState *State{nullptr}; + } Effect; + + std::atomic_flag PropsClean; + + RefCount ref{0u}; + + std::atomic Update{nullptr}; + + struct { + ALfloat Gain{1.0f}; + ALboolean AuxSendAuto{AL_TRUE}; + ALeffectslot *Target{nullptr}; + + ALenum EffectType{AL_EFFECT_NULL}; + EffectProps mEffectProps{}; + EffectState *mEffectState{nullptr}; + + ALfloat RoomRolloff{0.0f}; /* Added to the source's room rolloff, not multiplied. */ + ALfloat DecayTime{0.0f}; + ALfloat DecayLFRatio{0.0f}; + ALfloat DecayHFRatio{0.0f}; + ALboolean DecayHFLimit{AL_FALSE}; + ALfloat AirAbsorptionGainHF{1.0f}; + } Params; + + /* Self ID */ + ALuint id{}; + + /* Mixing buffer used by the Wet mix. */ + al::vector MixBuffer; + + /* Wet buffer configuration is ACN channel order with N3D scaling. + * Consequently, effects that only want to work with mono input can use + * channel 0 by itself. Effects that want multichannel can process the + * ambisonics signal and make a B-Format source pan. + */ + MixParams Wet; + + ALeffectslot() { PropsClean.test_and_set(std::memory_order_relaxed); } + ALeffectslot(const ALeffectslot&) = delete; + ALeffectslot& operator=(const ALeffectslot&) = delete; + ~ALeffectslot(); + + static ALeffectslotArray *CreatePtrArray(size_t count) noexcept; + + DEF_PLACE_NEWDEL() +}; + +ALenum InitEffectSlot(ALeffectslot *slot); +void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context); +void UpdateAllEffectSlotProps(ALCcontext *context); + + +ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect); + +#endif diff --git a/al/buffer.cpp b/al/buffer.cpp new file mode 100644 index 00000000..8b9c67e0 --- /dev/null +++ b/al/buffer.cpp @@ -0,0 +1,1408 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "buffer.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" + +#include "albyte.h" +#include "alcmain.h" +#include "alcontext.h" +#include "alexcpt.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "aloptional.h" +#include "atomic.h" +#include "error.h" +#include "inprogext.h" +#include "opthelpers.h" + + +namespace { + +/* IMA ADPCM Stepsize table */ +constexpr int IMAStep_size[89] = { + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, + 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, + 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, + 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, + 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, + 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, + 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493,10442, + 11487,12635,13899,15289,16818,18500,20350,22358,24633,27086,29794, + 32767 +}; + +/* IMA4 ADPCM Codeword decode table */ +constexpr int IMA4Codeword[16] = { + 1, 3, 5, 7, 9, 11, 13, 15, + -1,-3,-5,-7,-9,-11,-13,-15, +}; + +/* IMA4 ADPCM Step index adjust decode table */ +constexpr int IMA4Index_adjust[16] = { + -1,-1,-1,-1, 2, 4, 6, 8, + -1,-1,-1,-1, 2, 4, 6, 8 +}; + + +/* MSADPCM Adaption table */ +constexpr int MSADPCMAdaption[16] = { + 230, 230, 230, 230, 307, 409, 512, 614, + 768, 614, 512, 409, 307, 230, 230, 230 +}; + +/* MSADPCM Adaption Coefficient tables */ +constexpr int MSADPCMAdaptionCoeff[7][2] = { + { 256, 0 }, + { 512, -256 }, + { 0, 0 }, + { 192, 64 }, + { 240, 0 }, + { 460, -208 }, + { 392, -232 } +}; + + +void DecodeIMA4Block(ALshort *dst, const al::byte *src, ALint numchans, ALsizei align) +{ + ALint sample[MAX_INPUT_CHANNELS]{}; + ALint index[MAX_INPUT_CHANNELS]{}; + ALuint code[MAX_INPUT_CHANNELS]{}; + + for(int c{0};c < numchans;c++) + { + sample[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + sample[c] = (sample[c]^0x8000) - 32768; + src += 2; + index[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + index[c] = clampi((index[c]^0x8000) - 32768, 0, 88); + src += 2; + + *(dst++) = sample[c]; + } + + for(int i{1};i < align;i++) + { + if((i&7) == 1) + { + for(int c{0};c < numchans;c++) + { + code[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<< 8) | + (al::to_integer(src[2])<<16) | (al::to_integer(src[3])<<24); + src += 4; + } + } + + for(int c{0};c < numchans;c++) + { + const ALuint nibble{code[c]&0xf}; + code[c] >>= 4; + + sample[c] += IMA4Codeword[nibble] * IMAStep_size[index[c]] / 8; + sample[c] = clampi(sample[c], -32768, 32767); + + index[c] += IMA4Index_adjust[nibble]; + index[c] = clampi(index[c], 0, 88); + + *(dst++) = sample[c]; + } + } +} + +void DecodeMSADPCMBlock(ALshort *dst, const al::byte *src, ALint numchans, ALsizei align) +{ + ALubyte blockpred[MAX_INPUT_CHANNELS]{}; + ALint delta[MAX_INPUT_CHANNELS]{}; + ALshort samples[MAX_INPUT_CHANNELS][2]{}; + + for(int c{0};c < numchans;c++) + { + blockpred[c] = minu(al::to_integer(src[0]), 6); + ++src; + } + for(int c{0};c < numchans;c++) + { + delta[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + delta[c] = (delta[c]^0x8000) - 32768; + src += 2; + } + for(int c{0};c < numchans;c++) + { + samples[c][0] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + samples[c][0] = (samples[c][0]^0x8000) - 32768; + src += 2; + } + for(int c{0};c < numchans;c++) + { + samples[c][1] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + samples[c][1] = (samples[c][1]^0x8000) - 32768; + src += 2; + } + + /* Second sample is written first. */ + for(int c{0};c < numchans;c++) + *(dst++) = samples[c][1]; + for(int c{0};c < numchans;c++) + *(dst++) = samples[c][0]; + + int num{0}; + for(int i{2};i < align;i++) + { + for(int c{0};c < numchans;c++) + { + /* Read the nibble (first is in the upper bits). */ + al::byte nibble; + if(!(num++ & 1)) + nibble = *src >> 4; + else + nibble = *(src++) & 0x0f; + + ALint pred{(samples[c][0]*MSADPCMAdaptionCoeff[blockpred[c]][0] + + samples[c][1]*MSADPCMAdaptionCoeff[blockpred[c]][1]) / 256}; + pred += (al::to_integer(nibble^0x08) - 0x08) * delta[c]; + pred = clampi(pred, -32768, 32767); + + samples[c][1] = samples[c][0]; + samples[c][0] = pred; + + delta[c] = (MSADPCMAdaption[al::to_integer(nibble)] * delta[c]) / 256; + delta[c] = maxi(16, delta[c]); + + *(dst++) = pred; + } + } +} + +void Convert_ALshort_ALima4(ALshort *dst, const al::byte *src, ALsizei numchans, ALsizei len, + ALsizei align) +{ + const ALsizei byte_align{((align-1)/2 + 4) * numchans}; + + len /= align; + while(len--) + { + DecodeIMA4Block(dst, src, numchans, align); + src += byte_align; + dst += align*numchans; + } +} + +void Convert_ALshort_ALmsadpcm(ALshort *dst, const al::byte *src, ALsizei numchans, ALsizei len, + ALsizei align) +{ + const ALsizei byte_align{((align-2)/2 + 7) * numchans}; + + len /= align; + while(len--) + { + DecodeMSADPCMBlock(dst, src, numchans, align); + src += byte_align; + dst += align*numchans; + } +} + + +constexpr ALbitfieldSOFT INVALID_STORAGE_MASK{~unsigned(AL_MAP_READ_BIT_SOFT | + AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT)}; +constexpr ALbitfieldSOFT MAP_READ_WRITE_FLAGS{AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT}; +constexpr ALbitfieldSOFT INVALID_MAP_FLAGS{~unsigned(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | + AL_MAP_PERSISTENT_BIT_SOFT)}; + + +ALbuffer *AllocBuffer(ALCcontext *context) +{ + ALCdevice *device{context->Device}; + std::lock_guard _{device->BufferLock}; + auto sublist = std::find_if(device->BufferList.begin(), device->BufferList.end(), + [](const BufferSubList &entry) noexcept -> bool + { return entry.FreeMask != 0; } + ); + + auto lidx = static_cast(std::distance(device->BufferList.begin(), sublist)); + ALbuffer *buffer{nullptr}; + ALsizei slidx{0}; + if(LIKELY(sublist != device->BufferList.end())) + { + slidx = CTZ64(sublist->FreeMask); + buffer = sublist->Buffers + slidx; + } + else + { + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(device->BufferList.size() >= 1<<25)) + { + alSetError(context, AL_OUT_OF_MEMORY, "Too many buffers allocated"); + return nullptr; + } + device->BufferList.emplace_back(); + sublist = device->BufferList.end() - 1; + sublist->FreeMask = ~0_u64; + sublist->Buffers = reinterpret_cast(al_calloc(16, sizeof(ALbuffer)*64)); + if(UNLIKELY(!sublist->Buffers)) + { + device->BufferList.pop_back(); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate buffer batch"); + return nullptr; + } + + slidx = 0; + buffer = sublist->Buffers + slidx; + } + + buffer = new (buffer) ALbuffer{}; + /* Add 1 to avoid buffer ID 0. */ + buffer->id = ((lidx<<6) | slidx) + 1; + + sublist->FreeMask &= ~(1_u64 << slidx); + + return buffer; +} + +void FreeBuffer(ALCdevice *device, ALbuffer *buffer) +{ + ALuint id{buffer->id - 1}; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; + + al::destroy_at(buffer); + + device->BufferList[lidx].FreeMask |= 1_u64 << slidx; +} + +inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= device->BufferList.size())) + return nullptr; + BufferSubList &sublist = device->BufferList[lidx]; + if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + return nullptr; + return sublist.Buffers + slidx; +} + + +ALsizei SanitizeAlignment(UserFmtType type, ALsizei align) +{ + if(align < 0) + return 0; + + if(align == 0) + { + if(type == UserFmtIMA4) + { + /* Here is where things vary: + * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel + * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel + */ + return 65; + } + if(type == UserFmtMSADPCM) + return 64; + return 1; + } + + if(type == UserFmtIMA4) + { + /* IMA4 block alignment must be a multiple of 8, plus 1. */ + if((align&7) == 1) return align; + return 0; + } + if(type == UserFmtMSADPCM) + { + /* MSADPCM block alignment must be a multiple of 2. */ + if((align&1) == 0) return align; + return 0; + } + + return align; +} + + +const ALchar *NameFromUserFmtType(UserFmtType type) +{ + switch(type) + { + case UserFmtUByte: return "Unsigned Byte"; + case UserFmtShort: return "Signed Short"; + case UserFmtFloat: return "Float32"; + case UserFmtDouble: return "Float64"; + case UserFmtMulaw: return "muLaw"; + case UserFmtAlaw: return "aLaw"; + case UserFmtIMA4: return "IMA4 ADPCM"; + case UserFmtMSADPCM: return "MSADPCM"; + } + return ""; +} + +/* + * LoadData + * + * Loads the specified data into the buffer, using the specified format. + */ +void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, UserFmtChannels SrcChannels, UserFmtType SrcType, const al::byte *SrcData, ALbitfieldSOFT access) +{ + if(UNLIKELY(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)) + SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer %u", + ALBuf->id); + + /* Currently no channel configurations need to be converted. */ + FmtChannels DstChannels{FmtMono}; + switch(SrcChannels) + { + case UserFmtMono: DstChannels = FmtMono; break; + case UserFmtStereo: DstChannels = FmtStereo; break; + case UserFmtRear: DstChannels = FmtRear; break; + case UserFmtQuad: DstChannels = FmtQuad; break; + case UserFmtX51: DstChannels = FmtX51; break; + case UserFmtX61: DstChannels = FmtX61; break; + case UserFmtX71: DstChannels = FmtX71; break; + case UserFmtBFormat2D: DstChannels = FmtBFormat2D; break; + case UserFmtBFormat3D: DstChannels = FmtBFormat3D; break; + } + if (UNLIKELY(static_cast(SrcChannels) != + static_cast(DstChannels))) + SETERR_RETURN(context, AL_INVALID_ENUM, , "Invalid format"); + + /* IMA4 and MSADPCM convert to 16-bit short. */ + FmtType DstType{FmtUByte}; + switch(SrcType) + { + case UserFmtUByte: DstType = FmtUByte; break; + case UserFmtShort: DstType = FmtShort; break; + case UserFmtFloat: DstType = FmtFloat; break; + case UserFmtDouble: DstType = FmtDouble; break; + case UserFmtAlaw: DstType = FmtAlaw; break; + case UserFmtMulaw: DstType = FmtMulaw; break; + case UserFmtIMA4: DstType = FmtShort; break; + case UserFmtMSADPCM: DstType = FmtShort; break; + } + + /* TODO: Currently we can only map samples when they're not converted. To + * allow it would need some kind of double-buffering to hold onto a copy of + * the original data. + */ + if((access&MAP_READ_WRITE_FLAGS)) + { + if (UNLIKELY(static_cast(SrcType) != static_cast(DstType))) + SETERR_RETURN(context, AL_INVALID_VALUE, , + "%s samples cannot be mapped", + NameFromUserFmtType(SrcType)); + } + + const ALsizei unpackalign{ALBuf->UnpackAlign.load()}; + const ALsizei align{SanitizeAlignment(SrcType, unpackalign)}; + if(UNLIKELY(align < 1)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid unpack alignment %d for %s samples", + unpackalign, NameFromUserFmtType(SrcType)); + + if((access&AL_PRESERVE_DATA_BIT_SOFT)) + { + /* Can only preserve data with the same format and alignment. */ + if(UNLIKELY(ALBuf->mFmtChannels != DstChannels || ALBuf->OriginalType != SrcType)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched format"); + if(UNLIKELY(ALBuf->OriginalAlign != align)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched alignment"); + } + + /* Convert the input/source size in bytes to sample frames using the unpack + * block alignment. + */ + const ALsizei SrcByteAlign{ + (SrcType == UserFmtIMA4) ? ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels) : + (SrcType == UserFmtMSADPCM) ? ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels) : + (align * FrameSizeFromUserFmt(SrcChannels, SrcType)) + }; + if(UNLIKELY((size%SrcByteAlign) != 0)) + SETERR_RETURN(context, AL_INVALID_VALUE,, + "Data size %d is not a multiple of frame size %d (%d unpack alignment)", + size, SrcByteAlign, align); + + if(UNLIKELY(size/SrcByteAlign > std::numeric_limits::max()/align)) + SETERR_RETURN(context, AL_OUT_OF_MEMORY,, + "Buffer size overflow, %d blocks x %d samples per block", size/SrcByteAlign, align); + const ALsizei frames{size / SrcByteAlign * align}; + + /* Convert the sample frames to the number of bytes needed for internal + * storage. + */ + ALsizei NumChannels{ChannelsFromFmt(DstChannels)}; + ALsizei FrameSize{NumChannels * BytesFromFmt(DstType)}; + if(UNLIKELY(frames > std::numeric_limits::max()/FrameSize)) + SETERR_RETURN(context, AL_OUT_OF_MEMORY,, + "Buffer size overflow, %d frames x %d bytes per frame", frames, FrameSize); + size_t newsize{static_cast(frames) * FrameSize}; + + /* Round up to the next 16-byte multiple. This could reallocate only when + * increasing or the new size is less than half the current, but then the + * buffer's AL_SIZE would not be very reliable for accounting buffer memory + * usage, and reporting the real size could cause problems for apps that + * use AL_SIZE to try to get the buffer's play length. + */ + newsize = RoundUp(newsize, 16); + if(newsize != ALBuf->mData.size()) + { + auto newdata = al::vector(newsize, al::byte{}); + if((access&AL_PRESERVE_DATA_BIT_SOFT)) + { + const size_t tocopy{minz(newdata.size(), ALBuf->mData.size())}; + std::copy_n(ALBuf->mData.begin(), tocopy, newdata.begin()); + } + ALBuf->mData = std::move(newdata); + } + + if(SrcType == UserFmtIMA4) + { + assert(DstType == FmtShort); + if(SrcData != nullptr && !ALBuf->mData.empty()) + Convert_ALshort_ALima4(reinterpret_cast(ALBuf->mData.data()), + SrcData, NumChannels, frames, align); + ALBuf->OriginalAlign = align; + } + else if(SrcType == UserFmtMSADPCM) + { + assert(DstType == FmtShort); + if(SrcData != nullptr && !ALBuf->mData.empty()) + Convert_ALshort_ALmsadpcm(reinterpret_cast(ALBuf->mData.data()), + SrcData, NumChannels, frames, align); + ALBuf->OriginalAlign = align; + } + else + { + assert(static_cast(SrcType) == static_cast(DstType)); + if(SrcData != nullptr && !ALBuf->mData.empty()) + std::copy_n(SrcData, frames*FrameSize, ALBuf->mData.begin()); + ALBuf->OriginalAlign = 1; + } + ALBuf->OriginalSize = size; + ALBuf->OriginalType = SrcType; + + ALBuf->Frequency = freq; + ALBuf->mFmtChannels = DstChannels; + ALBuf->mFmtType = DstType; + ALBuf->Access = access; + + ALBuf->SampleLen = frames; + ALBuf->LoopStart = 0; + ALBuf->LoopEnd = ALBuf->SampleLen; +} + +struct DecompResult { UserFmtChannels channels; UserFmtType type; }; +al::optional DecomposeUserFormat(ALenum format) +{ + struct FormatMap { + ALenum format; + UserFmtChannels channels; + UserFmtType type; + }; + static constexpr std::array UserFmtList{{ + { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte }, + { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort }, + { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat }, + { AL_FORMAT_MONO_DOUBLE_EXT, UserFmtMono, UserFmtDouble }, + { AL_FORMAT_MONO_IMA4, UserFmtMono, UserFmtIMA4 }, + { AL_FORMAT_MONO_MSADPCM_SOFT, UserFmtMono, UserFmtMSADPCM }, + { AL_FORMAT_MONO_MULAW, UserFmtMono, UserFmtMulaw }, + { AL_FORMAT_MONO_ALAW_EXT, UserFmtMono, UserFmtAlaw }, + + { AL_FORMAT_STEREO8, UserFmtStereo, UserFmtUByte }, + { AL_FORMAT_STEREO16, UserFmtStereo, UserFmtShort }, + { AL_FORMAT_STEREO_FLOAT32, UserFmtStereo, UserFmtFloat }, + { AL_FORMAT_STEREO_DOUBLE_EXT, UserFmtStereo, UserFmtDouble }, + { AL_FORMAT_STEREO_IMA4, UserFmtStereo, UserFmtIMA4 }, + { AL_FORMAT_STEREO_MSADPCM_SOFT, UserFmtStereo, UserFmtMSADPCM }, + { AL_FORMAT_STEREO_MULAW, UserFmtStereo, UserFmtMulaw }, + { AL_FORMAT_STEREO_ALAW_EXT, UserFmtStereo, UserFmtAlaw }, + + { AL_FORMAT_REAR8, UserFmtRear, UserFmtUByte }, + { AL_FORMAT_REAR16, UserFmtRear, UserFmtShort }, + { AL_FORMAT_REAR32, UserFmtRear, UserFmtFloat }, + { AL_FORMAT_REAR_MULAW, UserFmtRear, UserFmtMulaw }, + + { AL_FORMAT_QUAD8_LOKI, UserFmtQuad, UserFmtUByte }, + { AL_FORMAT_QUAD16_LOKI, UserFmtQuad, UserFmtShort }, + + { AL_FORMAT_QUAD8, UserFmtQuad, UserFmtUByte }, + { AL_FORMAT_QUAD16, UserFmtQuad, UserFmtShort }, + { AL_FORMAT_QUAD32, UserFmtQuad, UserFmtFloat }, + { AL_FORMAT_QUAD_MULAW, UserFmtQuad, UserFmtMulaw }, + + { AL_FORMAT_51CHN8, UserFmtX51, UserFmtUByte }, + { AL_FORMAT_51CHN16, UserFmtX51, UserFmtShort }, + { AL_FORMAT_51CHN32, UserFmtX51, UserFmtFloat }, + { AL_FORMAT_51CHN_MULAW, UserFmtX51, UserFmtMulaw }, + + { AL_FORMAT_61CHN8, UserFmtX61, UserFmtUByte }, + { AL_FORMAT_61CHN16, UserFmtX61, UserFmtShort }, + { AL_FORMAT_61CHN32, UserFmtX61, UserFmtFloat }, + { AL_FORMAT_61CHN_MULAW, UserFmtX61, UserFmtMulaw }, + + { AL_FORMAT_71CHN8, UserFmtX71, UserFmtUByte }, + { AL_FORMAT_71CHN16, UserFmtX71, UserFmtShort }, + { AL_FORMAT_71CHN32, UserFmtX71, UserFmtFloat }, + { AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw }, + + { AL_FORMAT_BFORMAT2D_8, UserFmtBFormat2D, UserFmtUByte }, + { AL_FORMAT_BFORMAT2D_16, UserFmtBFormat2D, UserFmtShort }, + { AL_FORMAT_BFORMAT2D_FLOAT32, UserFmtBFormat2D, UserFmtFloat }, + { AL_FORMAT_BFORMAT2D_MULAW, UserFmtBFormat2D, UserFmtMulaw }, + + { AL_FORMAT_BFORMAT3D_8, UserFmtBFormat3D, UserFmtUByte }, + { AL_FORMAT_BFORMAT3D_16, UserFmtBFormat3D, UserFmtShort }, + { AL_FORMAT_BFORMAT3D_FLOAT32, UserFmtBFormat3D, UserFmtFloat }, + { AL_FORMAT_BFORMAT3D_MULAW, UserFmtBFormat3D, UserFmtMulaw }, + }}; + + for(const auto &fmt : UserFmtList) + { + if(fmt.format == format) + return al::make_optional(DecompResult{fmt.channels, fmt.type}); + } + return al::nullopt; +} + +} // namespace + + +AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(UNLIKELY(n < 0)) + { + alSetError(context.get(), AL_INVALID_VALUE, "Generating %d buffers", n); + return; + } + + if(LIKELY(n == 1)) + { + /* Special handling for the easy and normal case. */ + ALbuffer *buffer = AllocBuffer(context.get()); + if(buffer) buffers[0] = buffer->id; + } + else if(n > 1) + { + /* Store the allocated buffer IDs in a separate local list, to avoid + * modifying the user storage in case of failure. + */ + al::vector ids; + ids.reserve(n); + do { + ALbuffer *buffer = AllocBuffer(context.get()); + if(!buffer) + { + alDeleteBuffers(static_cast(ids.size()), ids.data()); + return; + } + + ids.emplace_back(buffer->id); + } while(--n); + std::copy(ids.begin(), ids.end(), buffers); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(UNLIKELY(n < 0)) + { + alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d buffers", n); + return; + } + if(UNLIKELY(n == 0)) + return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + /* First try to find any buffers that are invalid or in-use. */ + const ALuint *buffers_end = buffers + n; + auto invbuf = std::find_if(buffers, buffers_end, + [device, &context](ALuint bid) -> bool + { + if(!bid) return false; + ALbuffer *ALBuf = LookupBuffer(device, bid); + if(UNLIKELY(!ALBuf)) + { + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", bid); + return true; + } + if(UNLIKELY(ReadRef(&ALBuf->ref) != 0)) + { + alSetError(context.get(), AL_INVALID_OPERATION, "Deleting in-use buffer %u", bid); + return true; + } + return false; + } + ); + if(LIKELY(invbuf == buffers_end)) + { + /* All good. Delete non-0 buffer IDs. */ + std::for_each(buffers, buffers_end, + [device](ALuint bid) -> void + { + ALbuffer *buffer{bid ? LookupBuffer(device, bid) : nullptr}; + if(buffer) FreeBuffer(device, buffer); + } + ); + } +} +END_API_FUNC + +AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(LIKELY(context)) + { + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + if(!buffer || LookupBuffer(device, buffer)) + return AL_TRUE; + } + return AL_FALSE; +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq) +START_API_FUNC +{ alBufferStorageSOFT(buffer, format, data, size, freq, 0); } +END_API_FUNC + +AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(size < 0)) + alSetError(context.get(), AL_INVALID_VALUE, "Negative storage size %d", size); + else if(UNLIKELY(freq < 1)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid sample rate %d", freq); + else if(UNLIKELY((flags&INVALID_STORAGE_MASK) != 0)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid storage flags 0x%x", + flags&INVALID_STORAGE_MASK); + else if(UNLIKELY((flags&AL_MAP_PERSISTENT_BIT_SOFT) && !(flags&MAP_READ_WRITE_FLAGS))) + alSetError(context.get(), AL_INVALID_VALUE, + "Declaring persistently mapped storage without read or write access"); + else + { + auto usrfmt = DecomposeUserFormat(format); + if(UNLIKELY(!usrfmt)) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid format 0x%04x", format); + else + LoadData(context.get(), albuf, freq, size, usrfmt->channels, usrfmt->type, + static_cast(data), flags); + } +} +END_API_FUNC + +AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return nullptr; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY((access&INVALID_MAP_FLAGS) != 0)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid map flags 0x%x", access&INVALID_MAP_FLAGS); + else if(UNLIKELY(!(access&MAP_READ_WRITE_FLAGS))) + alSetError(context.get(), AL_INVALID_VALUE, "Mapping buffer %u without read or write access", + buffer); + else + { + ALbitfieldSOFT unavailable = (albuf->Access^access) & access; + if(UNLIKELY(ReadRef(&albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT))) + alSetError(context.get(), AL_INVALID_OPERATION, + "Mapping in-use buffer %u without persistent mapping", buffer); + else if(UNLIKELY(albuf->MappedAccess != 0)) + alSetError(context.get(), AL_INVALID_OPERATION, "Mapping already-mapped buffer %u", buffer); + else if(UNLIKELY((unavailable&AL_MAP_READ_BIT_SOFT))) + alSetError(context.get(), AL_INVALID_VALUE, + "Mapping buffer %u for reading without read access", buffer); + else if(UNLIKELY((unavailable&AL_MAP_WRITE_BIT_SOFT))) + alSetError(context.get(), AL_INVALID_VALUE, + "Mapping buffer %u for writing without write access", buffer); + else if(UNLIKELY((unavailable&AL_MAP_PERSISTENT_BIT_SOFT))) + alSetError(context.get(), AL_INVALID_VALUE, + "Mapping buffer %u persistently without persistent access", buffer); + else if(UNLIKELY(offset < 0 || offset >= albuf->OriginalSize || + length <= 0 || length > albuf->OriginalSize - offset)) + alSetError(context.get(), AL_INVALID_VALUE, "Mapping invalid range %d+%d for buffer %u", + offset, length, buffer); + else + { + void *retval = albuf->mData.data() + offset; + albuf->MappedAccess = access; + albuf->MappedOffset = offset; + albuf->MappedSize = length; + return retval; + } + } + + return nullptr; +} +END_API_FUNC + +AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(albuf->MappedAccess == 0) + alSetError(context.get(), AL_INVALID_OPERATION, "Unmapping unmapped buffer %u", buffer); + else + { + albuf->MappedAccess = 0; + albuf->MappedOffset = 0; + albuf->MappedSize = 0; + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT))) + alSetError(context.get(), AL_INVALID_OPERATION, + "Flushing buffer %u while not mapped for writing", buffer); + else if(UNLIKELY(offset < albuf->MappedOffset || + offset >= albuf->MappedOffset+albuf->MappedSize || + length <= 0 || length > albuf->MappedOffset+albuf->MappedSize-offset)) + alSetError(context.get(), AL_INVALID_VALUE, "Flushing invalid range %d+%d on buffer %u", + offset, length, buffer); + else + { + /* FIXME: Need to use some method of double-buffering for the mixer and + * app to hold separate memory, which can be safely transfered + * asynchronously. Currently we just say the app shouldn't write where + * OpenAL's reading, and hope for the best... + */ + std::atomic_thread_fence(std::memory_order_seq_cst); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + { + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + return; + } + + auto usrfmt = DecomposeUserFormat(format); + if(UNLIKELY(!usrfmt)) + { + alSetError(context.get(), AL_INVALID_ENUM, "Invalid format 0x%04x", format); + return; + } + + ALsizei unpack_align{albuf->UnpackAlign.load()}; + ALsizei align{SanitizeAlignment(usrfmt->type, unpack_align)}; + if(UNLIKELY(align < 1)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid unpack alignment %d", unpack_align); + else if(UNLIKELY(long{usrfmt->channels} != long{albuf->mFmtChannels} || + usrfmt->type != albuf->OriginalType)) + alSetError(context.get(), AL_INVALID_ENUM, + "Unpacking data with mismatched format"); + else if(UNLIKELY(align != albuf->OriginalAlign)) + alSetError(context.get(), AL_INVALID_VALUE, + "Unpacking data with alignment %u does not match original alignment %u", + align, albuf->OriginalAlign); + else if(UNLIKELY(albuf->MappedAccess != 0)) + alSetError(context.get(), AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u", + buffer); + else + { + ALsizei num_chans{ChannelsFromFmt(albuf->mFmtChannels)}; + ALsizei frame_size{num_chans * BytesFromFmt(albuf->mFmtType)}; + ALsizei byte_align{ + (albuf->OriginalType == UserFmtIMA4) ? ((align-1)/2 + 4) * num_chans : + (albuf->OriginalType == UserFmtMSADPCM) ? ((align-2)/2 + 7) * num_chans : + (align * frame_size) + }; + + if(UNLIKELY(offset < 0 || length < 0 || offset > albuf->OriginalSize || + length > albuf->OriginalSize-offset)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid data sub-range %d+%d on buffer %u", + offset, length, buffer); + else if(UNLIKELY((offset%byte_align) != 0)) + alSetError(context.get(), AL_INVALID_VALUE, + "Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)", + offset, byte_align, align); + else if(UNLIKELY((length%byte_align) != 0)) + alSetError(context.get(), AL_INVALID_VALUE, + "Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)", + length, byte_align, align); + else + { + /* offset -> byte offset, length -> sample count */ + offset = offset/byte_align * align * frame_size; + length = length/byte_align * align; + + void *dst = albuf->mData.data() + offset; + if(usrfmt->type == UserFmtIMA4 && albuf->mFmtType == FmtShort) + Convert_ALshort_ALima4(static_cast(dst), + static_cast(data), num_chans, length, align); + else if(usrfmt->type == UserFmtMSADPCM && albuf->mFmtType == FmtShort) + Convert_ALshort_ALmsadpcm(static_cast(dst), + static_cast(data), num_chans, length, align); + else + { + assert(long{usrfmt->type} == static_cast(albuf->mFmtType)); + memcpy(dst, data, length * frame_size); + } + } + } +} +END_API_FUNC + + +AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint /*buffer*/, ALuint /*samplerate*/, + ALenum /*internalformat*/, ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, + const ALvoid* /*data*/) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + alSetError(context.get(), AL_INVALID_OPERATION, "alBufferSamplesSOFT not supported"); +} +END_API_FUNC + +AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint /*buffer*/, ALsizei /*offset*/, + ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, const ALvoid* /*data*/) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + alSetError(context.get(), AL_INVALID_OPERATION, "alBufferSubSamplesSOFT not supported"); +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint /*buffer*/, ALsizei /*offset*/, + ALsizei /*samples*/, ALenum /*channels*/, ALenum /*type*/, ALvoid* /*data*/) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + alSetError(context.get(), AL_INVALID_OPERATION, "alGetBufferSamplesSOFT not supported"); +} +END_API_FUNC + +AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum /*format*/) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(!context) return AL_FALSE; + + alSetError(context.get(), AL_INVALID_OPERATION, "alIsBufferFormatSupportedSOFT not supported"); + return AL_FALSE; +} +END_API_FUNC + + +AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat /*value*/) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, + ALfloat /*value1*/, ALfloat /*value2*/, ALfloat /*value3*/) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!values)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); + } +} +END_API_FUNC + + +AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else switch(param) + { + case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: + if(UNLIKELY(value < 0)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid unpack block alignment %d", value); + else + albuf->UnpackAlign.store(value); + break; + + case AL_PACK_BLOCK_ALIGNMENT_SOFT: + if(UNLIKELY(value < 0)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid pack block alignment %d", value); + else + albuf->PackAlign.store(value); + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, + ALint /*value1*/, ALint /*value2*/, ALint /*value3*/) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values) +START_API_FUNC +{ + if(values) + { + switch(param) + { + case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: + case AL_PACK_BLOCK_ALIGNMENT_SOFT: + alBufferi(buffer, param, values[0]); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!values)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_LOOP_POINTS_SOFT: + if(UNLIKELY(ReadRef(&albuf->ref) != 0)) + alSetError(context.get(), AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points", + buffer); + else if(UNLIKELY(values[0] >= values[1] || values[0] < 0 || values[1] > albuf->SampleLen)) + alSetError(context.get(), AL_INVALID_VALUE, "Invalid loop point range %d -> %d o buffer %u", + values[0], values[1], buffer); + else + { + albuf->LoopStart = values[0]; + albuf->LoopEnd = values[1]; + } + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", + param); + } +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!value)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!value1 || !value2 || !value3)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values) +START_API_FUNC +{ + switch(param) + { + case AL_SEC_LENGTH_SOFT: + alGetBufferf(buffer, param, values); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!values)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); + } +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!value)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_FREQUENCY: + *value = albuf->Frequency; + break; + + case AL_BITS: + *value = BytesFromFmt(albuf->mFmtType) * 8; + break; + + case AL_CHANNELS: + *value = ChannelsFromFmt(albuf->mFmtChannels); + break; + + case AL_SIZE: + *value = albuf->SampleLen * FrameSizeFromFmt(albuf->mFmtChannels, albuf->mFmtType); + break; + + case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: + *value = albuf->UnpackAlign.load(); + break; + + case AL_PACK_BLOCK_ALIGNMENT_SOFT: + *value = albuf->PackAlign.load(); + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!value1 || !value2 || !value3)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values) +START_API_FUNC +{ + switch(param) + { + case AL_FREQUENCY: + case AL_BITS: + case AL_CHANNELS: + case AL_SIZE: + case AL_INTERNAL_FORMAT_SOFT: + case AL_BYTE_LENGTH_SOFT: + case AL_SAMPLE_LENGTH_SOFT: + case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: + case AL_PACK_BLOCK_ALIGNMENT_SOFT: + alGetBufferi(buffer, param, values); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard _{device->BufferLock}; + ALbuffer *albuf = LookupBuffer(device, buffer); + if(UNLIKELY(!albuf)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!values)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_LOOP_POINTS_SOFT: + values[0] = albuf->LoopStart; + values[1] = albuf->LoopEnd; + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", + param); + } +} +END_API_FUNC + + +ALsizei BytesFromUserFmt(UserFmtType type) +{ + switch(type) + { + case UserFmtUByte: return sizeof(ALubyte); + case UserFmtShort: return sizeof(ALshort); + case UserFmtFloat: return sizeof(ALfloat); + case UserFmtDouble: return sizeof(ALdouble); + case UserFmtMulaw: return sizeof(ALubyte); + case UserFmtAlaw: return sizeof(ALubyte); + case UserFmtIMA4: break; /* not handled here */ + case UserFmtMSADPCM: break; /* not handled here */ + } + return 0; +} +ALsizei ChannelsFromUserFmt(UserFmtChannels chans) +{ + switch(chans) + { + case UserFmtMono: return 1; + case UserFmtStereo: return 2; + case UserFmtRear: return 2; + case UserFmtQuad: return 4; + case UserFmtX51: return 6; + case UserFmtX61: return 7; + case UserFmtX71: return 8; + case UserFmtBFormat2D: return 3; + case UserFmtBFormat3D: return 4; + } + return 0; +} + +ALsizei BytesFromFmt(FmtType type) +{ + switch(type) + { + case FmtUByte: return sizeof(ALubyte); + case FmtShort: return sizeof(ALshort); + case FmtFloat: return sizeof(ALfloat); + case FmtDouble: return sizeof(ALdouble); + case FmtMulaw: return sizeof(ALubyte); + case FmtAlaw: return sizeof(ALubyte); + } + return 0; +} +ALsizei ChannelsFromFmt(FmtChannels chans) +{ + switch(chans) + { + case FmtMono: return 1; + case FmtStereo: return 2; + case FmtRear: return 2; + case FmtQuad: return 4; + case FmtX51: return 6; + case FmtX61: return 7; + case FmtX71: return 8; + case FmtBFormat2D: return 3; + case FmtBFormat3D: return 4; + } + return 0; +} + + +BufferSubList::~BufferSubList() +{ + uint64_t usemask{~FreeMask}; + while(usemask) + { + ALsizei idx{CTZ64(usemask)}; + al::destroy_at(Buffers+idx); + usemask &= ~(1_u64 << idx); + } + FreeMask = ~usemask; + al_free(Buffers); + Buffers = nullptr; +} diff --git a/al/buffer.h b/al/buffer.h new file mode 100644 index 00000000..1d5873e5 --- /dev/null +++ b/al/buffer.h @@ -0,0 +1,121 @@ +#ifndef AL_BUFFER_H +#define AL_BUFFER_H + +#include + +#include "AL/al.h" + +#include "albyte.h" +#include "almalloc.h" +#include "atomic.h" +#include "inprogext.h" +#include "vector.h" + + +/* User formats */ +enum UserFmtType : unsigned char { + UserFmtUByte, + UserFmtShort, + UserFmtFloat, + UserFmtDouble, + UserFmtMulaw, + UserFmtAlaw, + UserFmtIMA4, + UserFmtMSADPCM, +}; +enum UserFmtChannels : unsigned char { + UserFmtMono, + UserFmtStereo, + UserFmtRear, + UserFmtQuad, + UserFmtX51, /* (WFX order) */ + UserFmtX61, /* (WFX order) */ + UserFmtX71, /* (WFX order) */ + UserFmtBFormat2D, /* WXY */ + UserFmtBFormat3D, /* WXYZ */ +}; + +ALsizei BytesFromUserFmt(UserFmtType type); +ALsizei ChannelsFromUserFmt(UserFmtChannels chans); +inline ALsizei FrameSizeFromUserFmt(UserFmtChannels chans, UserFmtType type) +{ return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type); } + + +/* Storable formats */ +enum FmtType : unsigned char { + FmtUByte = UserFmtUByte, + FmtShort = UserFmtShort, + FmtFloat = UserFmtFloat, + FmtDouble = UserFmtDouble, + FmtMulaw = UserFmtMulaw, + FmtAlaw = UserFmtAlaw, +}; +enum FmtChannels : unsigned char { + FmtMono = UserFmtMono, + FmtStereo = UserFmtStereo, + FmtRear = UserFmtRear, + FmtQuad = UserFmtQuad, + FmtX51 = UserFmtX51, + FmtX61 = UserFmtX61, + FmtX71 = UserFmtX71, + FmtBFormat2D = UserFmtBFormat2D, + FmtBFormat3D = UserFmtBFormat3D, +}; +#define MAX_INPUT_CHANNELS (8) + +/* DevFmtType traits, providing the type, etc given a DevFmtType. */ +template +struct FmtTypeTraits { }; + +template<> +struct FmtTypeTraits { using Type = ALubyte; }; +template<> +struct FmtTypeTraits { using Type = ALshort; }; +template<> +struct FmtTypeTraits { using Type = ALfloat; }; +template<> +struct FmtTypeTraits { using Type = ALdouble; }; +template<> +struct FmtTypeTraits { using Type = ALubyte; }; +template<> +struct FmtTypeTraits { using Type = ALubyte; }; + + +ALsizei BytesFromFmt(FmtType type); +ALsizei ChannelsFromFmt(FmtChannels chans); +inline ALsizei FrameSizeFromFmt(FmtChannels chans, FmtType type) +{ return ChannelsFromFmt(chans) * BytesFromFmt(type); } + + +struct ALbuffer { + al::vector mData; + + ALsizei Frequency{0}; + ALbitfieldSOFT Access{0u}; + ALsizei SampleLen{0}; + + FmtChannels mFmtChannels{}; + FmtType mFmtType{}; + + UserFmtType OriginalType{}; + ALsizei OriginalSize{0}; + ALsizei OriginalAlign{0}; + + ALsizei LoopStart{0}; + ALsizei LoopEnd{0}; + + std::atomic UnpackAlign{0}; + std::atomic PackAlign{0}; + + ALbitfieldSOFT MappedAccess{0u}; + ALsizei MappedOffset{0}; + ALsizei MappedSize{0}; + + /* Number of times buffer was attached to a source (deletion can only occur when 0) */ + RefCount ref{0u}; + + /* Self ID */ + ALuint id{0}; +}; + +#endif diff --git a/al/effect.cpp b/al/effect.cpp new file mode 100644 index 00000000..b6cd5463 --- /dev/null +++ b/al/effect.cpp @@ -0,0 +1,742 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "effect.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" +#include "AL/efx-presets.h" +#include "AL/efx.h" + +#include "alcmain.h" +#include "alcontext.h" +#include "alexcpt.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "effects/base.h" +#include "error.h" +#include "logging.h" +#include "opthelpers.h" +#include "vector.h" + + +const EffectList gEffectList[15]{ + { "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB }, + { "reverb", REVERB_EFFECT, AL_EFFECT_REVERB }, + { "autowah", AUTOWAH_EFFECT, AL_EFFECT_AUTOWAH }, + { "chorus", CHORUS_EFFECT, AL_EFFECT_CHORUS }, + { "compressor", COMPRESSOR_EFFECT, AL_EFFECT_COMPRESSOR }, + { "distortion", DISTORTION_EFFECT, AL_EFFECT_DISTORTION }, + { "echo", ECHO_EFFECT, AL_EFFECT_ECHO }, + { "equalizer", EQUALIZER_EFFECT, AL_EFFECT_EQUALIZER }, + { "flanger", FLANGER_EFFECT, AL_EFFECT_FLANGER }, + { "fshifter", FSHIFTER_EFFECT, AL_EFFECT_FREQUENCY_SHIFTER }, + { "modulator", MODULATOR_EFFECT, AL_EFFECT_RING_MODULATOR }, + { "pshifter", PSHIFTER_EFFECT, AL_EFFECT_PITCH_SHIFTER }, + { "vmorpher", VMORPHER_EFFECT, AL_EFFECT_VOCAL_MORPHER }, + { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT }, + { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_DIALOGUE }, +}; + +ALboolean DisabledEffects[MAX_EFFECTS]; + +namespace { + +constexpr struct FactoryItem { + ALenum Type; + EffectStateFactory* (&GetFactory)(void); +} FactoryList[] = { + { AL_EFFECT_NULL, NullStateFactory_getFactory }, + { AL_EFFECT_EAXREVERB, ReverbStateFactory_getFactory }, + { AL_EFFECT_REVERB, StdReverbStateFactory_getFactory }, + { AL_EFFECT_AUTOWAH, AutowahStateFactory_getFactory }, + { AL_EFFECT_CHORUS, ChorusStateFactory_getFactory }, + { AL_EFFECT_COMPRESSOR, CompressorStateFactory_getFactory }, + { AL_EFFECT_DISTORTION, DistortionStateFactory_getFactory }, + { AL_EFFECT_ECHO, EchoStateFactory_getFactory }, + { AL_EFFECT_EQUALIZER, EqualizerStateFactory_getFactory }, + { AL_EFFECT_FLANGER, FlangerStateFactory_getFactory }, + { AL_EFFECT_FREQUENCY_SHIFTER, FshifterStateFactory_getFactory }, + { AL_EFFECT_RING_MODULATOR, ModulatorStateFactory_getFactory }, + { AL_EFFECT_PITCH_SHIFTER, PshifterStateFactory_getFactory}, + { AL_EFFECT_VOCAL_MORPHER, VmorpherStateFactory_getFactory}, + { AL_EFFECT_DEDICATED_DIALOGUE, DedicatedStateFactory_getFactory }, + { AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedStateFactory_getFactory } +}; + + +template +void ALeffect_setParami(ALeffect *effect, T&& ...args) +{ effect->vtab->setParami(&effect->Props, std::forward(args)...); } +template +void ALeffect_setParamiv(ALeffect *effect, T&& ...args) +{ effect->vtab->setParamiv(&effect->Props, std::forward(args)...); } +template +void ALeffect_setParamf(ALeffect *effect, T&& ...args) +{ effect->vtab->setParamf(&effect->Props, std::forward(args)...); } +template +void ALeffect_setParamfv(ALeffect *effect, T&& ...args) +{ effect->vtab->setParamfv(&effect->Props, std::forward(args)...); } + +template +void ALeffect_getParami(const ALeffect *effect, T&& ...args) +{ effect->vtab->getParami(&effect->Props, std::forward(args)...); } +template +void ALeffect_getParamiv(const ALeffect *effect, T&& ...args) +{ effect->vtab->getParamiv(&effect->Props, std::forward(args)...); } +template +void ALeffect_getParamf(const ALeffect *effect, T&& ...args) +{ effect->vtab->getParamf(&effect->Props, std::forward(args)...); } +template +void ALeffect_getParamfv(const ALeffect *effect, T&& ...args) +{ effect->vtab->getParamfv(&effect->Props, std::forward(args)...); } + + +void InitEffectParams(ALeffect *effect, ALenum type) +{ + EffectStateFactory *factory = getFactoryByType(type); + if(factory) + { + effect->Props = factory->getDefaultProps(); + effect->vtab = factory->getEffectVtable(); + } + else + { + effect->Props = EffectProps {}; + effect->vtab = nullptr; + } + effect->type = type; +} + +ALeffect *AllocEffect(ALCcontext *context) +{ + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + auto sublist = std::find_if(device->EffectList.begin(), device->EffectList.end(), + [](const EffectSubList &entry) noexcept -> bool + { return entry.FreeMask != 0; } + ); + + auto lidx = static_cast(std::distance(device->EffectList.begin(), sublist)); + ALeffect *effect{nullptr}; + ALsizei slidx{0}; + if(LIKELY(sublist != device->EffectList.end())) + { + slidx = CTZ64(sublist->FreeMask); + effect = sublist->Effects + slidx; + } + else + { + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(device->EffectList.size() >= 1<<25)) + { + alSetError(context, AL_OUT_OF_MEMORY, "Too many effects allocated"); + return nullptr; + } + device->EffectList.emplace_back(); + sublist = device->EffectList.end() - 1; + sublist->FreeMask = ~0_u64; + sublist->Effects = static_cast(al_calloc(16, sizeof(ALeffect)*64)); + if(UNLIKELY(!sublist->Effects)) + { + device->EffectList.pop_back(); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect batch"); + return nullptr; + } + + slidx = 0; + effect = sublist->Effects + slidx; + } + + effect = new (effect) ALeffect{}; + InitEffectParams(effect, AL_EFFECT_NULL); + + /* Add 1 to avoid effect ID 0. */ + effect->id = ((lidx<<6) | slidx) + 1; + + sublist->FreeMask &= ~(1_u64 << slidx); + + return effect; +} + +void FreeEffect(ALCdevice *device, ALeffect *effect) +{ + ALuint id = effect->id - 1; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; + + al::destroy_at(effect); + + device->EffectList[lidx].FreeMask |= 1_u64 << slidx; +} + +inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= device->EffectList.size())) + return nullptr; + EffectSubList &sublist = device->EffectList[lidx]; + if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + return nullptr; + return sublist.Effects + slidx; +} + +} // namespace + +AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(UNLIKELY(n < 0)) + { + alSetError(context.get(), AL_INVALID_VALUE, "Generating %d effects", n); + return; + } + + if(LIKELY(n == 1)) + { + /* Special handling for the easy and normal case. */ + ALeffect *effect = AllocEffect(context.get()); + if(effect) effects[0] = effect->id; + } + else if(n > 1) + { + /* Store the allocated buffer IDs in a separate local list, to avoid + * modifying the user storage in case of failure. + */ + al::vector ids; + ids.reserve(n); + do { + ALeffect *effect = AllocEffect(context.get()); + if(!effect) + { + alDeleteEffects(static_cast(ids.size()), ids.data()); + return; + } + + ids.emplace_back(effect->id); + } while(--n); + std::copy(ids.begin(), ids.end(), effects); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(UNLIKELY(n < 0)) + { + alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d effects", n); + return; + } + if(UNLIKELY(n == 0)) + return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + + /* First try to find any effects that are invalid. */ + const ALuint *effects_end = effects + n; + auto inveffect = std::find_if(effects, effects_end, + [device, &context](ALuint eid) -> bool + { + if(!eid) return false; + ALeffect *effect{LookupEffect(device, eid)}; + if(UNLIKELY(!effect)) + { + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", eid); + return true; + } + return false; + } + ); + if(LIKELY(inveffect == effects_end)) + { + /* All good. Delete non-0 effect IDs. */ + std::for_each(effects, effects_end, + [device](ALuint eid) -> void + { + ALeffect *effect{eid ? LookupEffect(device, eid) : nullptr}; + if(effect) FreeEffect(device, effect); + } + ); + } +} +END_API_FUNC + +AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(LIKELY(context)) + { + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + if(!effect || LookupEffect(device, effect)) + return AL_TRUE; + } + return AL_FALSE; +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + + ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + if(param == AL_EFFECT_TYPE) + { + ALboolean isOk{value == AL_EFFECT_NULL}; + if(!isOk) + { + for(const EffectList &effectitem : gEffectList) + { + if(value == effectitem.val && !DisabledEffects[effectitem.type]) + { + isOk = AL_TRUE; + break; + } + } + } + + if(isOk) + InitEffectParams(aleffect, value); + else + alSetError(context.get(), AL_INVALID_VALUE, "Effect type 0x%04x not supported", value); + } + else + { + /* Call the appropriate handler */ + ALeffect_setParami(aleffect, context.get(), param, value); + } + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *values) +START_API_FUNC +{ + switch(param) + { + case AL_EFFECT_TYPE: + alEffecti(effect, param, values[0]); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + + ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + /* Call the appropriate handler */ + ALeffect_setParamiv(aleffect, context.get(), param, values); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + + ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + /* Call the appropriate handler */ + ALeffect_setParamf(aleffect, context.get(), param, value); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + + ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + /* Call the appropriate handler */ + ALeffect_setParamfv(aleffect, context.get(), param, values); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + + const ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + if(param == AL_EFFECT_TYPE) + *value = aleffect->type; + else + { + /* Call the appropriate handler */ + ALeffect_getParami(aleffect, context.get(), param, value); + } + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *values) +START_API_FUNC +{ + switch(param) + { + case AL_EFFECT_TYPE: + alGetEffecti(effect, param, values); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + + const ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + /* Call the appropriate handler */ + ALeffect_getParamiv(aleffect, context.get(), param, values); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + + const ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + /* Call the appropriate handler */ + ALeffect_getParamf(aleffect, context.get(), param, value); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->EffectLock}; + + const ALeffect *aleffect{LookupEffect(device, effect)}; + if(UNLIKELY(!aleffect)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + else + { + /* Call the appropriate handler */ + ALeffect_getParamfv(aleffect, context.get(), param, values); + } +} +END_API_FUNC + + +void InitEffect(ALeffect *effect) +{ + InitEffectParams(effect, AL_EFFECT_NULL); +} + +EffectSubList::~EffectSubList() +{ + uint64_t usemask{~FreeMask}; + while(usemask) + { + ALsizei idx = CTZ64(usemask); + al::destroy_at(Effects+idx); + usemask &= ~(1_u64 << idx); + } + FreeMask = ~usemask; + al_free(Effects); + Effects = nullptr; +} + + +EffectStateFactory *getFactoryByType(ALenum type) +{ + auto iter = std::find_if(std::begin(FactoryList), std::end(FactoryList), + [type](const FactoryItem &item) noexcept -> bool + { return item.Type == type; } + ); + return (iter != std::end(FactoryList)) ? iter->GetFactory() : nullptr; +} + + +#define DECL(x) { #x, EFX_REVERB_PRESET_##x } +static const struct { + const char name[32]; + EFXEAXREVERBPROPERTIES props; +} reverblist[] = { + DECL(GENERIC), + DECL(PADDEDCELL), + DECL(ROOM), + DECL(BATHROOM), + DECL(LIVINGROOM), + DECL(STONEROOM), + DECL(AUDITORIUM), + DECL(CONCERTHALL), + DECL(CAVE), + DECL(ARENA), + DECL(HANGAR), + DECL(CARPETEDHALLWAY), + DECL(HALLWAY), + DECL(STONECORRIDOR), + DECL(ALLEY), + DECL(FOREST), + DECL(CITY), + DECL(MOUNTAINS), + DECL(QUARRY), + DECL(PLAIN), + DECL(PARKINGLOT), + DECL(SEWERPIPE), + DECL(UNDERWATER), + DECL(DRUGGED), + DECL(DIZZY), + DECL(PSYCHOTIC), + + DECL(CASTLE_SMALLROOM), + DECL(CASTLE_SHORTPASSAGE), + DECL(CASTLE_MEDIUMROOM), + DECL(CASTLE_LARGEROOM), + DECL(CASTLE_LONGPASSAGE), + DECL(CASTLE_HALL), + DECL(CASTLE_CUPBOARD), + DECL(CASTLE_COURTYARD), + DECL(CASTLE_ALCOVE), + + DECL(FACTORY_SMALLROOM), + DECL(FACTORY_SHORTPASSAGE), + DECL(FACTORY_MEDIUMROOM), + DECL(FACTORY_LARGEROOM), + DECL(FACTORY_LONGPASSAGE), + DECL(FACTORY_HALL), + DECL(FACTORY_CUPBOARD), + DECL(FACTORY_COURTYARD), + DECL(FACTORY_ALCOVE), + + DECL(ICEPALACE_SMALLROOM), + DECL(ICEPALACE_SHORTPASSAGE), + DECL(ICEPALACE_MEDIUMROOM), + DECL(ICEPALACE_LARGEROOM), + DECL(ICEPALACE_LONGPASSAGE), + DECL(ICEPALACE_HALL), + DECL(ICEPALACE_CUPBOARD), + DECL(ICEPALACE_COURTYARD), + DECL(ICEPALACE_ALCOVE), + + DECL(SPACESTATION_SMALLROOM), + DECL(SPACESTATION_SHORTPASSAGE), + DECL(SPACESTATION_MEDIUMROOM), + DECL(SPACESTATION_LARGEROOM), + DECL(SPACESTATION_LONGPASSAGE), + DECL(SPACESTATION_HALL), + DECL(SPACESTATION_CUPBOARD), + DECL(SPACESTATION_ALCOVE), + + DECL(WOODEN_SMALLROOM), + DECL(WOODEN_SHORTPASSAGE), + DECL(WOODEN_MEDIUMROOM), + DECL(WOODEN_LARGEROOM), + DECL(WOODEN_LONGPASSAGE), + DECL(WOODEN_HALL), + DECL(WOODEN_CUPBOARD), + DECL(WOODEN_COURTYARD), + DECL(WOODEN_ALCOVE), + + DECL(SPORT_EMPTYSTADIUM), + DECL(SPORT_SQUASHCOURT), + DECL(SPORT_SMALLSWIMMINGPOOL), + DECL(SPORT_LARGESWIMMINGPOOL), + DECL(SPORT_GYMNASIUM), + DECL(SPORT_FULLSTADIUM), + DECL(SPORT_STADIUMTANNOY), + + DECL(PREFAB_WORKSHOP), + DECL(PREFAB_SCHOOLROOM), + DECL(PREFAB_PRACTISEROOM), + DECL(PREFAB_OUTHOUSE), + DECL(PREFAB_CARAVAN), + + DECL(DOME_TOMB), + DECL(PIPE_SMALL), + DECL(DOME_SAINTPAULS), + DECL(PIPE_LONGTHIN), + DECL(PIPE_LARGE), + DECL(PIPE_RESONANT), + + DECL(OUTDOORS_BACKYARD), + DECL(OUTDOORS_ROLLINGPLAINS), + DECL(OUTDOORS_DEEPCANYON), + DECL(OUTDOORS_CREEK), + DECL(OUTDOORS_VALLEY), + + DECL(MOOD_HEAVEN), + DECL(MOOD_HELL), + DECL(MOOD_MEMORY), + + DECL(DRIVING_COMMENTATOR), + DECL(DRIVING_PITGARAGE), + DECL(DRIVING_INCAR_RACER), + DECL(DRIVING_INCAR_SPORTS), + DECL(DRIVING_INCAR_LUXURY), + DECL(DRIVING_FULLGRANDSTAND), + DECL(DRIVING_EMPTYGRANDSTAND), + DECL(DRIVING_TUNNEL), + + DECL(CITY_STREETS), + DECL(CITY_SUBWAY), + DECL(CITY_MUSEUM), + DECL(CITY_LIBRARY), + DECL(CITY_UNDERPASS), + DECL(CITY_ABANDONED), + + DECL(DUSTYROOM), + DECL(CHAPEL), + DECL(SMALLWATERROOM), +}; +#undef DECL + +void LoadReverbPreset(const char *name, ALeffect *effect) +{ + if(strcasecmp(name, "NONE") == 0) + { + InitEffectParams(effect, AL_EFFECT_NULL); + TRACE("Loading reverb '%s'\n", "NONE"); + return; + } + + if(!DisabledEffects[EAXREVERB_EFFECT]) + InitEffectParams(effect, AL_EFFECT_EAXREVERB); + else if(!DisabledEffects[REVERB_EFFECT]) + InitEffectParams(effect, AL_EFFECT_REVERB); + else + InitEffectParams(effect, AL_EFFECT_NULL); + for(const auto &reverbitem : reverblist) + { + const EFXEAXREVERBPROPERTIES *props; + + if(strcasecmp(name, reverbitem.name) != 0) + continue; + + TRACE("Loading reverb '%s'\n", reverbitem.name); + props = &reverbitem.props; + effect->Props.Reverb.Density = props->flDensity; + effect->Props.Reverb.Diffusion = props->flDiffusion; + effect->Props.Reverb.Gain = props->flGain; + effect->Props.Reverb.GainHF = props->flGainHF; + effect->Props.Reverb.GainLF = props->flGainLF; + effect->Props.Reverb.DecayTime = props->flDecayTime; + effect->Props.Reverb.DecayHFRatio = props->flDecayHFRatio; + effect->Props.Reverb.DecayLFRatio = props->flDecayLFRatio; + effect->Props.Reverb.ReflectionsGain = props->flReflectionsGain; + effect->Props.Reverb.ReflectionsDelay = props->flReflectionsDelay; + effect->Props.Reverb.ReflectionsPan[0] = props->flReflectionsPan[0]; + effect->Props.Reverb.ReflectionsPan[1] = props->flReflectionsPan[1]; + effect->Props.Reverb.ReflectionsPan[2] = props->flReflectionsPan[2]; + effect->Props.Reverb.LateReverbGain = props->flLateReverbGain; + effect->Props.Reverb.LateReverbDelay = props->flLateReverbDelay; + effect->Props.Reverb.LateReverbPan[0] = props->flLateReverbPan[0]; + effect->Props.Reverb.LateReverbPan[1] = props->flLateReverbPan[1]; + effect->Props.Reverb.LateReverbPan[2] = props->flLateReverbPan[2]; + effect->Props.Reverb.EchoTime = props->flEchoTime; + effect->Props.Reverb.EchoDepth = props->flEchoDepth; + effect->Props.Reverb.ModulationTime = props->flModulationTime; + effect->Props.Reverb.ModulationDepth = props->flModulationDepth; + effect->Props.Reverb.AirAbsorptionGainHF = props->flAirAbsorptionGainHF; + effect->Props.Reverb.HFReference = props->flHFReference; + effect->Props.Reverb.LFReference = props->flLFReference; + effect->Props.Reverb.RoomRolloffFactor = props->flRoomRolloffFactor; + effect->Props.Reverb.DecayHFLimit = props->iDecayHFLimit; + return; + } + + WARN("Reverb preset '%s' not found\n", name); +} diff --git a/al/effect.h b/al/effect.h new file mode 100644 index 00000000..270b8e20 --- /dev/null +++ b/al/effect.h @@ -0,0 +1,61 @@ +#ifndef AL_EFFECT_H +#define AL_EFFECT_H + +#include "AL/al.h" +#include "AL/efx.h" + +#include "effects/base.h" + + +enum { + EAXREVERB_EFFECT = 0, + REVERB_EFFECT, + AUTOWAH_EFFECT, + CHORUS_EFFECT, + COMPRESSOR_EFFECT, + DISTORTION_EFFECT, + ECHO_EFFECT, + EQUALIZER_EFFECT, + FLANGER_EFFECT, + FSHIFTER_EFFECT, + MODULATOR_EFFECT, + PSHIFTER_EFFECT, + VMORPHER_EFFECT, + DEDICATED_EFFECT, + + MAX_EFFECTS +}; +extern ALboolean DisabledEffects[MAX_EFFECTS]; + +extern ALfloat ReverbBoost; + +struct EffectList { + const char name[16]; + int type; + ALenum val; +}; +extern const EffectList gEffectList[15]; + + +struct ALeffect { + // Effect type (AL_EFFECT_NULL, ...) + ALenum type{AL_EFFECT_NULL}; + + EffectProps Props{}; + + const EffectVtable *vtab{nullptr}; + + /* Self ID */ + ALuint id{0u}; +}; + +inline ALboolean IsReverbEffect(ALenum type) +{ return type == AL_EFFECT_REVERB || type == AL_EFFECT_EAXREVERB; } + +EffectStateFactory *getFactoryByType(ALenum type); + +void InitEffect(ALeffect *effect); + +void LoadReverbPreset(const char *name, ALeffect *effect); + +#endif diff --git a/al/error.cpp b/al/error.cpp new file mode 100644 index 00000000..f5f0801e --- /dev/null +++ b/al/error.cpp @@ -0,0 +1,118 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2000 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "error.h" + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" + +#include "alcontext.h" +#include "alexcpt.h" +#include "almalloc.h" +#include "event.h" +#include "inprogext.h" +#include "logging.h" +#include "opthelpers.h" +#include "vector.h" + + +bool TrapALError{false}; + +void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) +{ + auto message = al::vector(256); + + va_list args, args2; + va_start(args, msg); + va_copy(args2, args); + int msglen{std::vsnprintf(message.data(), message.size(), msg, args)}; + if(msglen >= 0 && static_cast(msglen) >= message.size()) + { + message.resize(static_cast(msglen) + 1u); + msglen = std::vsnprintf(message.data(), message.size(), msg, args2); + } + va_end(args2); + va_end(args); + + if(msglen >= 0) msg = message.data(); + else msg = ""; + msglen = static_cast(strlen(msg)); + + WARN("Error generated on context %p, code 0x%04x, \"%s\"\n", context, errorCode, msg); + if(TrapALError) + { +#ifdef _WIN32 + /* DebugBreak will cause an exception if there is no debugger */ + if(IsDebuggerPresent()) + DebugBreak(); +#elif defined(SIGTRAP) + raise(SIGTRAP); +#endif + } + + ALenum curerr{AL_NO_ERROR}; + context->LastError.compare_exchange_strong(curerr, errorCode); + if((context->EnabledEvts.load(std::memory_order_relaxed)&EventType_Error)) + { + std::lock_guard _{context->EventCbLock}; + ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; + if((enabledevts&EventType_Error) && context->EventCb) + (*context->EventCb)(AL_EVENT_TYPE_ERROR_SOFT, 0, errorCode, msglen, msg, + context->EventParam); + } +} + +AL_API ALenum AL_APIENTRY alGetError(void) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) + { + constexpr ALenum deferror{AL_INVALID_OPERATION}; + WARN("Querying error state on null context (implicitly 0x%04x)\n", deferror); + if(TrapALError) + { +#ifdef _WIN32 + if(IsDebuggerPresent()) + DebugBreak(); +#elif defined(SIGTRAP) + raise(SIGTRAP); +#endif + } + return deferror; + } + + return context->LastError.exchange(AL_NO_ERROR); +} +END_API_FUNC diff --git a/al/error.h b/al/error.h new file mode 100644 index 00000000..6408b60c --- /dev/null +++ b/al/error.h @@ -0,0 +1,24 @@ +#ifndef AL_ERROR_H +#define AL_ERROR_H + +#include "AL/al.h" +#include "AL/alc.h" + +#include "logging.h" + + +extern bool TrapALError; + +void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) DECL_FORMAT(printf, 3, 4); + +#define SETERR_GOTO(ctx, err, lbl, ...) do { \ + alSetError((ctx), (err), __VA_ARGS__); \ + goto lbl; \ +} while(0) + +#define SETERR_RETURN(ctx, err, retval, ...) do { \ + alSetError((ctx), (err), __VA_ARGS__); \ + return retval; \ +} while(0) + +#endif diff --git a/al/event.cpp b/al/event.cpp index ae2825d0..b103d0da 100644 --- a/al/event.cpp +++ b/al/event.cpp @@ -16,12 +16,12 @@ #include "AL/al.h" #include "AL/alc.h" -#include "alError.h" #include "albyte.h" #include "alcontext.h" #include "alexcpt.h" #include "almalloc.h" #include "effects/base.h" +#include "error.h" #include "inprogext.h" #include "logging.h" #include "opthelpers.h" diff --git a/al/extension.cpp b/al/extension.cpp new file mode 100644 index 00000000..e38d4382 --- /dev/null +++ b/al/extension.cpp @@ -0,0 +1,80 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" + +#include "alcontext.h" +#include "alexcpt.h" +#include "error.h" +#include "opthelpers.h" + + +AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return AL_FALSE; + + if(!extName) + SETERR_RETURN(context.get(), AL_INVALID_VALUE, AL_FALSE, "NULL pointer"); + + size_t len{strlen(extName)}; + const char *ptr{context->ExtensionList}; + while(ptr && *ptr) + { + if(strncasecmp(ptr, extName, len) == 0 && + (ptr[len] == '\0' || isspace(ptr[len]))) + return AL_TRUE; + + if((ptr=strchr(ptr, ' ')) != nullptr) + { + do { + ++ptr; + } while(isspace(*ptr)); + } + } + + return AL_FALSE; +} +END_API_FUNC + + +AL_API ALvoid* AL_APIENTRY alGetProcAddress(const ALchar *funcName) +START_API_FUNC +{ + if(!funcName) return nullptr; + return alcGetProcAddress(nullptr, funcName); +} +END_API_FUNC + +AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *enumName) +START_API_FUNC +{ + if(!enumName) return static_cast(0); + return alcGetEnumValue(nullptr, enumName); +} +END_API_FUNC diff --git a/al/filter.cpp b/al/filter.cpp new file mode 100644 index 00000000..405842f3 --- /dev/null +++ b/al/filter.cpp @@ -0,0 +1,665 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "filter.h" + +#include +#include +#include +#include +#include +#include + +#include "AL/efx.h" + +#include "alcmain.h" +#include "alcontext.h" +#include "alexcpt.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "error.h" +#include "opthelpers.h" +#include "vector.h" + + +namespace { + +#define FILTER_MIN_GAIN 0.0f +#define FILTER_MAX_GAIN 4.0f /* +12dB */ + +void ALlowpass_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) +{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } +void ALlowpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } +void ALlowpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_LOWPASS_GAIN: + if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gain %f out of range", val); + filter->Gain = val; + break; + + case AL_LOWPASS_GAINHF: + if(!(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gainhf %f out of range", val); + filter->GainHF = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param); + } +} +void ALlowpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALlowpass_setParamf(filter, context, param, vals[0]); } + +void ALlowpass_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } +void ALlowpass_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } +void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_LOWPASS_GAIN: + *val = filter->Gain; + break; + + case AL_LOWPASS_GAINHF: + *val = filter->GainHF; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param); + } +} +void ALlowpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALlowpass_getParamf(filter, context, param, vals); } + +DEFINE_ALFILTER_VTABLE(ALlowpass); + + +void ALhighpass_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) +{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } +void ALhighpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } +void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_HIGHPASS_GAIN: + if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gain out of range"); + filter->Gain = val; + break; + + case AL_HIGHPASS_GAINLF: + if(!(val >= AL_HIGHPASS_MIN_GAINLF && val <= AL_HIGHPASS_MAX_GAINLF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gainlf out of range"); + filter->GainLF = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param); + } +} +void ALhighpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALhighpass_setParamf(filter, context, param, vals[0]); } + +void ALhighpass_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } +void ALhighpass_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } +void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_HIGHPASS_GAIN: + *val = filter->Gain; + break; + + case AL_HIGHPASS_GAINLF: + *val = filter->GainLF; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param); + } +} +void ALhighpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALhighpass_getParamf(filter, context, param, vals); } + +DEFINE_ALFILTER_VTABLE(ALhighpass); + + +void ALbandpass_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) +{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } +void ALbandpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } +void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_BANDPASS_GAIN: + if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gain out of range"); + filter->Gain = val; + break; + + case AL_BANDPASS_GAINHF: + if(!(val >= AL_BANDPASS_MIN_GAINHF && val <= AL_BANDPASS_MAX_GAINHF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainhf out of range"); + filter->GainHF = val; + break; + + case AL_BANDPASS_GAINLF: + if(!(val >= AL_BANDPASS_MIN_GAINLF && val <= AL_BANDPASS_MAX_GAINLF)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainlf out of range"); + filter->GainLF = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param); + } +} +void ALbandpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALbandpass_setParamf(filter, context, param, vals[0]); } + +void ALbandpass_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } +void ALbandpass_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } +void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_BANDPASS_GAIN: + *val = filter->Gain; + break; + + case AL_BANDPASS_GAINHF: + *val = filter->GainHF; + break; + + case AL_BANDPASS_GAINLF: + *val = filter->GainLF; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param); + } +} +void ALbandpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALbandpass_getParamf(filter, context, param, vals); } + +DEFINE_ALFILTER_VTABLE(ALbandpass); + + +void ALnullfilter_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +void ALnullfilter_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +void ALnullfilter_setParamf(ALfilter*, ALCcontext *context, ALenum param, ALfloat) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +void ALnullfilter_setParamfv(ALfilter*, ALCcontext *context, ALenum param, const ALfloat*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } + +void ALnullfilter_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +void ALnullfilter_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +void ALnullfilter_getParamf(ALfilter*, ALCcontext *context, ALenum param, ALfloat*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +void ALnullfilter_getParamfv(ALfilter*, ALCcontext *context, ALenum param, ALfloat*) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } + +DEFINE_ALFILTER_VTABLE(ALnullfilter); + + +void InitFilterParams(ALfilter *filter, ALenum type) +{ + if(type == AL_FILTER_LOWPASS) + { + filter->Gain = AL_LOWPASS_DEFAULT_GAIN; + filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF; + filter->HFReference = LOWPASSFREQREF; + filter->GainLF = 1.0f; + filter->LFReference = HIGHPASSFREQREF; + filter->vtab = &ALlowpass_vtable; + } + else if(type == AL_FILTER_HIGHPASS) + { + filter->Gain = AL_HIGHPASS_DEFAULT_GAIN; + filter->GainHF = 1.0f; + filter->HFReference = LOWPASSFREQREF; + filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF; + filter->LFReference = HIGHPASSFREQREF; + filter->vtab = &ALhighpass_vtable; + } + else if(type == AL_FILTER_BANDPASS) + { + filter->Gain = AL_BANDPASS_DEFAULT_GAIN; + filter->GainHF = AL_BANDPASS_DEFAULT_GAINHF; + filter->HFReference = LOWPASSFREQREF; + filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF; + filter->LFReference = HIGHPASSFREQREF; + filter->vtab = &ALbandpass_vtable; + } + else + { + filter->Gain = 1.0f; + filter->GainHF = 1.0f; + filter->HFReference = LOWPASSFREQREF; + filter->GainLF = 1.0f; + filter->LFReference = HIGHPASSFREQREF; + filter->vtab = &ALnullfilter_vtable; + } + filter->type = type; +} + +ALfilter *AllocFilter(ALCcontext *context) +{ + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + auto sublist = std::find_if(device->FilterList.begin(), device->FilterList.end(), + [](const FilterSubList &entry) noexcept -> bool + { return entry.FreeMask != 0; } + ); + + auto lidx = static_cast(std::distance(device->FilterList.begin(), sublist)); + ALfilter *filter{nullptr}; + ALsizei slidx{0}; + if(LIKELY(sublist != device->FilterList.end())) + { + slidx = CTZ64(sublist->FreeMask); + filter = sublist->Filters + slidx; + } + else + { + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(device->FilterList.size() >= 1<<25)) + { + alSetError(context, AL_OUT_OF_MEMORY, "Too many filters allocated"); + return nullptr; + } + device->FilterList.emplace_back(); + sublist = device->FilterList.end() - 1; + sublist->FreeMask = ~0_u64; + sublist->Filters = static_cast(al_calloc(16, sizeof(ALfilter)*64)); + if(UNLIKELY(!sublist->Filters)) + { + device->FilterList.pop_back(); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate filter batch"); + return nullptr; + } + + slidx = 0; + filter = sublist->Filters + slidx; + } + + filter = new (filter) ALfilter{}; + InitFilterParams(filter, AL_FILTER_NULL); + + /* Add 1 to avoid filter ID 0. */ + filter->id = ((lidx<<6) | slidx) + 1; + + sublist->FreeMask &= ~(1_u64 << slidx); + + return filter; +} + +void FreeFilter(ALCdevice *device, ALfilter *filter) +{ + ALuint id = filter->id - 1; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; + + al::destroy_at(filter); + + device->FilterList[lidx].FreeMask |= 1_u64 << slidx; +} + + +inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= device->FilterList.size())) + return nullptr; + FilterSubList &sublist = device->FilterList[lidx]; + if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + return nullptr; + return sublist.Filters + slidx; +} + +} // namespace + +AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(UNLIKELY(n < 0)) + { + alSetError(context.get(), AL_INVALID_VALUE, "Generating %d filters", n); + return; + } + + if(LIKELY(n == 1)) + { + /* Special handling for the easy and normal case. */ + ALfilter *filter = AllocFilter(context.get()); + if(filter) filters[0] = filter->id; + } + else if(n > 1) + { + /* Store the allocated buffer IDs in a separate local list, to avoid + * modifying the user storage in case of failure. + */ + al::vector ids; + ids.reserve(n); + do { + ALfilter *filter = AllocFilter(context.get()); + if(!filter) + { + alDeleteFilters(static_cast(ids.size()), ids.data()); + return; + } + + ids.emplace_back(filter->id); + } while(--n); + std::copy(ids.begin(), ids.end(), filters); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(UNLIKELY(n < 0)) + { + alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d filters", n); + return; + } + if(UNLIKELY(n == 0)) + return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + /* First try to find any filters that are invalid. */ + const ALuint *filters_end = filters + n; + auto invflt = std::find_if(filters, filters_end, + [device, &context](ALuint fid) -> bool + { + if(!fid) return false; + ALfilter *filter{LookupFilter(device, fid)}; + if(UNLIKELY(!filter)) + { + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", fid); + return true; + } + return false; + } + ); + if(LIKELY(invflt == filters_end)) + { + /* All good. Delete non-0 filter IDs. */ + std::for_each(filters, filters_end, + [device](ALuint fid) -> void + { + ALfilter *filter{fid ? LookupFilter(device, fid) : nullptr}; + if(filter) FreeFilter(device, filter); + } + ); + } +} +END_API_FUNC + +AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(LIKELY(context)) + { + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + if(!filter || LookupFilter(device, filter)) + return AL_TRUE; + } + return AL_FALSE; +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + if(param == AL_FILTER_TYPE) + { + if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS || + value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS) + InitFilterParams(alfilt, value); + else + alSetError(context.get(), AL_INVALID_VALUE, "Invalid filter type 0x%04x", value); + } + else + { + /* Call the appropriate handler */ + ALfilter_setParami(alfilt, context.get(), param, value); + } + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *values) +START_API_FUNC +{ + switch(param) + { + case AL_FILTER_TYPE: + alFilteri(filter, param, values[0]); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_setParamiv(alfilt, context.get(), param, values); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_setParamf(alfilt, context.get(), param, value); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_setParamfv(alfilt, context.get(), param, values); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + if(param == AL_FILTER_TYPE) + *value = alfilt->type; + else + { + /* Call the appropriate handler */ + ALfilter_getParami(alfilt, context.get(), param, value); + } + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *values) +START_API_FUNC +{ + switch(param) + { + case AL_FILTER_TYPE: + alGetFilteri(filter, param, values); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_getParamiv(alfilt, context.get(), param, values); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_getParamf(alfilt, context.get(), param, value); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device{context->Device}; + std::lock_guard _{device->FilterLock}; + + ALfilter *alfilt{LookupFilter(device, filter)}; + if(UNLIKELY(!alfilt)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + else + { + /* Call the appropriate handler */ + ALfilter_getParamfv(alfilt, context.get(), param, values); + } +} +END_API_FUNC + + +FilterSubList::~FilterSubList() +{ + uint64_t usemask{~FreeMask}; + while(usemask) + { + ALsizei idx = CTZ64(usemask); + al::destroy_at(Filters+idx); + usemask &= ~(1_u64 << idx); + } + FreeMask = ~usemask; + al_free(Filters); + Filters = nullptr; +} diff --git a/al/filter.h b/al/filter.h new file mode 100644 index 00000000..db098d70 --- /dev/null +++ b/al/filter.h @@ -0,0 +1,56 @@ +#ifndef AL_FILTER_H +#define AL_FILTER_H + +#include "AL/al.h" +#include "AL/alc.h" + + +#define LOWPASSFREQREF (5000.0f) +#define HIGHPASSFREQREF (250.0f) + + +struct ALfilter; + +struct ALfilterVtable { + void (*const setParami)(ALfilter *filter, ALCcontext *context, ALenum param, ALint val); + void (*const setParamiv)(ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals); + void (*const setParamf)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val); + void (*const setParamfv)(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals); + + void (*const getParami)(ALfilter *filter, ALCcontext *context, ALenum param, ALint *val); + void (*const getParamiv)(ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals); + void (*const getParamf)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val); + void (*const getParamfv)(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals); +}; + +#define DEFINE_ALFILTER_VTABLE(T) \ +const ALfilterVtable T##_vtable = { \ + T##_setParami, T##_setParamiv, T##_setParamf, T##_setParamfv, \ + T##_getParami, T##_getParamiv, T##_getParamf, T##_getParamfv, \ +} + +struct ALfilter { + // Filter type (AL_FILTER_NULL, ...) + ALenum type; + + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; + + const ALfilterVtable *vtab; + + /* Self ID */ + ALuint id; +}; +#define ALfilter_setParami(o, c, p, v) ((o)->vtab->setParami(o, c, p, v)) +#define ALfilter_setParamf(o, c, p, v) ((o)->vtab->setParamf(o, c, p, v)) +#define ALfilter_setParamiv(o, c, p, v) ((o)->vtab->setParamiv(o, c, p, v)) +#define ALfilter_setParamfv(o, c, p, v) ((o)->vtab->setParamfv(o, c, p, v)) +#define ALfilter_getParami(o, c, p, v) ((o)->vtab->getParami(o, c, p, v)) +#define ALfilter_getParamf(o, c, p, v) ((o)->vtab->getParamf(o, c, p, v)) +#define ALfilter_getParamiv(o, c, p, v) ((o)->vtab->getParamiv(o, c, p, v)) +#define ALfilter_getParamfv(o, c, p, v) ((o)->vtab->getParamfv(o, c, p, v)) + +#endif diff --git a/al/listener.cpp b/al/listener.cpp new file mode 100644 index 00000000..d67bf072 --- /dev/null +++ b/al/listener.cpp @@ -0,0 +1,454 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2000 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "listener.h" + +#include +#include + +#include "AL/efx.h" + +#include "alcontext.h" +#include "alexcpt.h" +#include "almalloc.h" +#include "atomic.h" +#include "error.h" +#include "opthelpers.h" + + +#define DO_UPDATEPROPS() do { \ + if(!context->DeferUpdates.load(std::memory_order_acquire)) \ + UpdateListenerProps(context.get()); \ + else \ + listener.PropsClean.clear(std::memory_order_release); \ +} while(0) + + +AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; + switch(param) + { + case AL_GAIN: + if(!(value >= 0.0f && std::isfinite(value))) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener gain out of range"); + listener.Gain = value; + DO_UPDATEPROPS(); + break; + + case AL_METERS_PER_UNIT: + if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT)) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, + "Listener meters per unit out of range"); + context->MetersPerUnit = value; + if(!context->DeferUpdates.load(std::memory_order_acquire)) + UpdateContextProps(context.get()); + else + context->PropsClean.clear(std::memory_order_release); + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float property"); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; + switch(param) + { + case AL_POSITION: + if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3))) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener position out of range"); + listener.Position[0] = value1; + listener.Position[1] = value2; + listener.Position[2] = value3; + DO_UPDATEPROPS(); + break; + + case AL_VELOCITY: + if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3))) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener velocity out of range"); + listener.Velocity[0] = value1; + listener.Velocity[1] = value2; + listener.Velocity[2] = value3; + DO_UPDATEPROPS(); + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-float property"); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) +START_API_FUNC +{ + if(values) + { + switch(param) + { + case AL_GAIN: + case AL_METERS_PER_UNIT: + alListenerf(param, values[0]); + return; + + case AL_POSITION: + case AL_VELOCITY: + alListener3f(param, values[0], values[1], values[2]); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; + if(!values) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "NULL pointer"); + switch(param) + { + case AL_ORIENTATION: + if(!(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) && + std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5]))) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener orientation out of range"); + /* AT then UP */ + listener.OrientAt[0] = values[0]; + listener.OrientAt[1] = values[1]; + listener.OrientAt[2] = values[2]; + listener.OrientUp[0] = values[3]; + listener.OrientUp[1] = values[4]; + listener.OrientUp[2] = values[5]; + DO_UPDATEPROPS(); + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float-vector property"); + } +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint /*value*/) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer property"); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3) +START_API_FUNC +{ + switch(param) + { + case AL_POSITION: + case AL_VELOCITY: + alListener3f(param, static_cast(value1), static_cast(value2), static_cast(value3)); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-integer property"); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values) +START_API_FUNC +{ + if(values) + { + ALfloat fvals[6]; + switch(param) + { + case AL_POSITION: + case AL_VELOCITY: + alListener3f(param, static_cast(values[0]), static_cast(values[1]), static_cast(values[2])); + return; + + case AL_ORIENTATION: + fvals[0] = static_cast(values[0]); + fvals[1] = static_cast(values[1]); + fvals[2] = static_cast(values[2]); + fvals[3] = static_cast(values[3]); + fvals[4] = static_cast(values[4]); + fvals[5] = static_cast(values[5]); + alListenerfv(param, fvals); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer-vector property"); + } +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; + if(!value) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_GAIN: + *value = listener.Gain; + break; + + case AL_METERS_PER_UNIT: + *value = context->MetersPerUnit; + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float property"); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; + if(!value1 || !value2 || !value3) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_POSITION: + *value1 = listener.Position[0]; + *value2 = listener.Position[1]; + *value3 = listener.Position[2]; + break; + + case AL_VELOCITY: + *value1 = listener.Velocity[0]; + *value2 = listener.Velocity[1]; + *value3 = listener.Velocity[2]; + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-float property"); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) +START_API_FUNC +{ + switch(param) + { + case AL_GAIN: + case AL_METERS_PER_UNIT: + alGetListenerf(param, values); + return; + + case AL_POSITION: + case AL_VELOCITY: + alGetListener3f(param, values+0, values+1, values+2); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_ORIENTATION: + // AT then UP + values[0] = listener.OrientAt[0]; + values[1] = listener.OrientAt[1]; + values[2] = listener.OrientAt[2]; + values[3] = listener.OrientUp[0]; + values[4] = listener.OrientUp[1]; + values[5] = listener.OrientUp[2]; + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float-vector property"); + } +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + if(!value) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer property"); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; + if(!value1 || !value2 || !value3) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_POSITION: + *value1 = static_cast(listener.Position[0]); + *value2 = static_cast(listener.Position[1]); + *value3 = static_cast(listener.Position[2]); + break; + + case AL_VELOCITY: + *value1 = static_cast(listener.Velocity[0]); + *value2 = static_cast(listener.Velocity[1]); + *value3 = static_cast(listener.Velocity[2]); + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-integer property"); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) +START_API_FUNC +{ + switch(param) + { + case AL_POSITION: + case AL_VELOCITY: + alGetListener3i(param, values+0, values+1, values+2); + return; + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALlistener &listener = context->Listener; + std::lock_guard _{context->PropLock}; + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(param) + { + case AL_ORIENTATION: + // AT then UP + values[0] = static_cast(listener.OrientAt[0]); + values[1] = static_cast(listener.OrientAt[1]); + values[2] = static_cast(listener.OrientAt[2]); + values[3] = static_cast(listener.OrientUp[0]); + values[4] = static_cast(listener.OrientUp[1]); + values[5] = static_cast(listener.OrientUp[2]); + break; + + default: + alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer-vector property"); + } +} +END_API_FUNC + + +void UpdateListenerProps(ALCcontext *context) +{ + /* Get an unused proprty container, or allocate a new one as needed. */ + ALlistenerProps *props{context->FreeListenerProps.load(std::memory_order_acquire)}; + if(!props) + props = static_cast(al_calloc(16, sizeof(*props))); + else + { + ALlistenerProps *next; + do { + next = props->next.load(std::memory_order_relaxed); + } while(context->FreeListenerProps.compare_exchange_weak(props, next, + std::memory_order_seq_cst, std::memory_order_acquire) == 0); + } + + /* Copy in current property values. */ + ALlistener &listener = context->Listener; + props->Position = listener.Position; + props->Velocity = listener.Velocity; + props->OrientAt = listener.OrientAt; + props->OrientUp = listener.OrientUp; + props->Gain = listener.Gain; + + /* Set the new container for updating internal parameters. */ + props = listener.Update.exchange(props, std::memory_order_acq_rel); + if(props) + { + /* If there was an unused update container, put it back in the + * freelist. + */ + AtomicReplaceHead(context->FreeListenerProps, props); + } +} diff --git a/al/listener.h b/al/listener.h new file mode 100644 index 00000000..a71db9f8 --- /dev/null +++ b/al/listener.h @@ -0,0 +1,58 @@ +#ifndef AL_LISTENER_H +#define AL_LISTENER_H + +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" + +#include "vecmat.h" + +enum class DistanceModel; + + +struct ALlistenerProps { + std::array Position; + std::array Velocity; + std::array OrientAt; + std::array OrientUp; + ALfloat Gain; + + std::atomic next; +}; + +struct ALlistener { + std::array Position{{0.0f, 0.0f, 0.0f}}; + std::array Velocity{{0.0f, 0.0f, 0.0f}}; + std::array OrientAt{{0.0f, 0.0f, -1.0f}}; + std::array OrientUp{{0.0f, 1.0f, 0.0f}}; + ALfloat Gain{1.0f}; + + std::atomic_flag PropsClean; + + /* Pointer to the most recent property values that are awaiting an update. + */ + std::atomic Update{nullptr}; + + struct { + alu::Matrix Matrix; + alu::Vector Velocity; + + ALfloat Gain; + ALfloat MetersPerUnit; + + ALfloat DopplerFactor; + ALfloat SpeedOfSound; /* in units per sec! */ + ALfloat ReverbSpeedOfSound; /* in meters per sec! */ + + ALboolean SourceDistanceModel; + DistanceModel mDistanceModel; + } Params; + + ALlistener() { PropsClean.test_and_set(std::memory_order_relaxed); } +}; + +void UpdateListenerProps(ALCcontext *context); + +#endif diff --git a/al/source.cpp b/al/source.cpp new file mode 100644 index 00000000..b4582e6b --- /dev/null +++ b/al/source.cpp @@ -0,0 +1,3639 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "source.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" +#include "AL/efx.h" + +#include "alcmain.h" +#include "alcontext.h" +#include "alexcpt.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "alu.h" +#include "ambidefs.h" +#include "atomic.h" +#include "auxeffectslot.h" +#include "backends/base.h" +#include "bformatdec.h" +#include "buffer.h" +#include "error.h" +#include "event.h" +#include "filter.h" +#include "filters/nfc.h" +#include "filters/splitter.h" +#include "inprogext.h" +#include "logging.h" +#include "math_defs.h" +#include "opthelpers.h" +#include "ringbuffer.h" +#include "threads.h" + + +namespace { + +using namespace std::placeholders; + +inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) +{ + ALint idx{source->VoiceIdx}; + if(idx >= 0 && static_cast(idx) < context->VoiceCount.load(std::memory_order_relaxed)) + { + ALuint sid{source->id}; + ALvoice &voice = (*context->Voices)[idx]; + if(voice.mSourceID.load(std::memory_order_acquire) == sid) + return &voice; + } + source->VoiceIdx = -1; + return nullptr; +} + +void UpdateSourceProps(const ALsource *source, ALvoice *voice, ALCcontext *context) +{ + /* Get an unused property container, or allocate a new one as needed. */ + ALvoiceProps *props{context->FreeVoiceProps.load(std::memory_order_acquire)}; + if(!props) + props = new ALvoiceProps{}; + else + { + ALvoiceProps *next; + do { + next = props->next.load(std::memory_order_relaxed); + } while(context->FreeVoiceProps.compare_exchange_weak(props, next, + std::memory_order_acq_rel, std::memory_order_acquire) == 0); + } + + /* Copy in current property values. */ + props->Pitch = source->Pitch; + props->Gain = source->Gain; + props->OuterGain = source->OuterGain; + props->MinGain = source->MinGain; + props->MaxGain = source->MaxGain; + props->InnerAngle = source->InnerAngle; + props->OuterAngle = source->OuterAngle; + props->RefDistance = source->RefDistance; + props->MaxDistance = source->MaxDistance; + props->RolloffFactor = source->RolloffFactor; + props->Position = source->Position; + props->Velocity = source->Velocity; + props->Direction = source->Direction; + props->OrientAt = source->OrientAt; + props->OrientUp = source->OrientUp; + props->HeadRelative = source->HeadRelative; + props->mDistanceModel = source->mDistanceModel; + props->mResampler = source->mResampler; + props->DirectChannels = source->DirectChannels; + props->mSpatializeMode = source->mSpatialize; + + props->DryGainHFAuto = source->DryGainHFAuto; + props->WetGainAuto = source->WetGainAuto; + props->WetGainHFAuto = source->WetGainHFAuto; + props->OuterGainHF = source->OuterGainHF; + + props->AirAbsorptionFactor = source->AirAbsorptionFactor; + props->RoomRolloffFactor = source->RoomRolloffFactor; + props->DopplerFactor = source->DopplerFactor; + + props->StereoPan = source->StereoPan; + + props->Radius = source->Radius; + + props->Direct.Gain = source->Direct.Gain; + props->Direct.GainHF = source->Direct.GainHF; + props->Direct.HFReference = source->Direct.HFReference; + props->Direct.GainLF = source->Direct.GainLF; + props->Direct.LFReference = source->Direct.LFReference; + + auto copy_send = [](const ALsource::SendData &srcsend) noexcept -> ALvoicePropsBase::SendData + { + ALvoicePropsBase::SendData ret; + ret.Slot = srcsend.Slot; + ret.Gain = srcsend.Gain; + ret.GainHF = srcsend.GainHF; + ret.HFReference = srcsend.HFReference; + ret.GainLF = srcsend.GainLF; + ret.LFReference = srcsend.LFReference; + return ret; + }; + std::transform(source->Send.cbegin(), source->Send.cend(), props->Send, copy_send); + + /* Set the new container for updating internal parameters. */ + props = voice->mUpdate.exchange(props, std::memory_order_acq_rel); + if(props) + { + /* If there was an unused update container, put it back in the + * freelist. + */ + AtomicReplaceHead(context->FreeVoiceProps, props); + } +} + +/* GetSourceSampleOffset + * + * Gets the current read offset for the given Source, in 32.32 fixed-point + * samples. The offset is relative to the start of the queue (not the start of + * the current buffer). + */ +int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, std::chrono::nanoseconds *clocktime) +{ + ALCdevice *device{context->Device}; + const ALbufferlistitem *Current; + uint64_t readPos; + ALuint refcount; + ALvoice *voice; + + do { + Current = nullptr; + readPos = 0; + while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) + std::this_thread::yield(); + *clocktime = GetDeviceClockTime(device); + + voice = GetSourceVoice(Source, context); + if(voice) + { + Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); + + readPos = uint64_t{voice->mPosition.load(std::memory_order_relaxed)} << 32; + readPos |= int64_t{voice->mPositionFrac.load(std::memory_order_relaxed)} << + (32-FRACTIONBITS); + } + std::atomic_thread_fence(std::memory_order_acquire); + } while(refcount != device->MixCount.load(std::memory_order_relaxed)); + + if(voice) + { + const ALbufferlistitem *BufferList{Source->queue}; + while(BufferList && BufferList != Current) + { + readPos += int64_t{BufferList->max_samples} << 32; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + readPos = minu64(readPos, 0x7fffffffffffffff_u64); + } + + return static_cast(readPos); +} + +/* GetSourceSecOffset + * + * Gets the current read offset for the given Source, in seconds. The offset is + * relative to the start of the queue (not the start of the current buffer). + */ +ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, std::chrono::nanoseconds *clocktime) +{ + ALCdevice *device{context->Device}; + const ALbufferlistitem *Current; + uint64_t readPos; + ALuint refcount; + ALvoice *voice; + + do { + Current = nullptr; + readPos = 0; + while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) + std::this_thread::yield(); + *clocktime = GetDeviceClockTime(device); + + voice = GetSourceVoice(Source, context); + if(voice) + { + Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); + + readPos = uint64_t{voice->mPosition.load(std::memory_order_relaxed)} << FRACTIONBITS; + readPos |= voice->mPositionFrac.load(std::memory_order_relaxed); + } + std::atomic_thread_fence(std::memory_order_acquire); + } while(refcount != device->MixCount.load(std::memory_order_relaxed)); + + ALdouble offset{0.0}; + if(voice) + { + const ALbufferlistitem *BufferList{Source->queue}; + const ALbuffer *BufferFmt{nullptr}; + while(BufferList && BufferList != Current) + { + for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i) + BufferFmt = BufferList->buffers[i]; + readPos += int64_t{BufferList->max_samples} << FRACTIONBITS; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + + while(BufferList && !BufferFmt) + { + for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i) + BufferFmt = BufferList->buffers[i]; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + assert(BufferFmt != nullptr); + + offset = static_cast(readPos) / static_castFRACTIONONE / + static_cast(BufferFmt->Frequency); + } + + return offset; +} + +/* GetSourceOffset + * + * Gets the current read offset for the given Source, in the appropriate format + * (Bytes, Samples or Seconds). The offset is relative to the start of the + * queue (not the start of the current buffer). + */ +ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) +{ + ALCdevice *device{context->Device}; + const ALbufferlistitem *Current; + ALuint readPos; + ALsizei readPosFrac; + ALuint refcount; + ALvoice *voice; + + do { + Current = nullptr; + readPos = readPosFrac = 0; + while(((refcount=device->MixCount.load(std::memory_order_acquire))&1)) + std::this_thread::yield(); + voice = GetSourceVoice(Source, context); + if(voice) + { + Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); + + readPos = voice->mPosition.load(std::memory_order_relaxed); + readPosFrac = voice->mPositionFrac.load(std::memory_order_relaxed); + } + std::atomic_thread_fence(std::memory_order_acquire); + } while(refcount != device->MixCount.load(std::memory_order_relaxed)); + + ALdouble offset{0.0}; + if(voice) + { + const ALbufferlistitem *BufferList{Source->queue}; + const ALbuffer *BufferFmt{nullptr}; + ALboolean readFin{AL_FALSE}; + ALuint totalBufferLen{0u}; + + while(BufferList) + { + for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i) + BufferFmt = BufferList->buffers[i]; + + readFin |= (BufferList == Current); + totalBufferLen += BufferList->max_samples; + if(!readFin) readPos += BufferList->max_samples; + + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + assert(BufferFmt != nullptr); + + if(Source->Looping) + readPos %= totalBufferLen; + else + { + /* Wrap back to 0 */ + if(readPos >= totalBufferLen) + readPos = readPosFrac = 0; + } + + offset = 0.0; + switch(name) + { + case AL_SEC_OFFSET: + offset = (readPos + static_cast(readPosFrac)/FRACTIONONE) / BufferFmt->Frequency; + break; + + case AL_SAMPLE_OFFSET: + offset = readPos + static_cast(readPosFrac)/FRACTIONONE; + break; + + case AL_BYTE_OFFSET: + if(BufferFmt->OriginalType == UserFmtIMA4) + { + ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; + ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->mFmtChannels); + ALuint FrameBlockSize = BufferFmt->OriginalAlign; + + /* Round down to nearest ADPCM block */ + offset = static_cast(readPos / FrameBlockSize * BlockSize); + } + else if(BufferFmt->OriginalType == UserFmtMSADPCM) + { + ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; + ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->mFmtChannels); + ALuint FrameBlockSize = BufferFmt->OriginalAlign; + + /* Round down to nearest ADPCM block */ + offset = static_cast(readPos / FrameBlockSize * BlockSize); + } + else + { + const ALsizei FrameSize{FrameSizeFromFmt(BufferFmt->mFmtChannels, + BufferFmt->mFmtType)}; + offset = static_cast(readPos * FrameSize); + } + break; + } + } + + return offset; +} + + +/* GetSampleOffset + * + * Retrieves the sample offset into the Source's queue (from the Sample, Byte + * or Second offset supplied by the application). This takes into account the + * fact that the buffer format may have been modifed since. + */ +ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac) +{ + const ALbuffer *BufferFmt{nullptr}; + const ALbufferlistitem *BufferList; + + /* Find the first valid Buffer in the Queue */ + BufferList = Source->queue; + while(BufferList) + { + for(ALsizei i{0};i < BufferList->num_buffers && !BufferFmt;i++) + BufferFmt = BufferList->buffers[i]; + if(BufferFmt) break; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + if(!BufferFmt) + { + Source->OffsetType = AL_NONE; + Source->Offset = 0.0; + return AL_FALSE; + } + + ALdouble dbloff, dblfrac; + switch(Source->OffsetType) + { + case AL_BYTE_OFFSET: + /* Determine the ByteOffset (and ensure it is block aligned) */ + *offset = static_cast(Source->Offset); + if(BufferFmt->OriginalType == UserFmtIMA4) + { + ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; + *offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels); + *offset *= BufferFmt->OriginalAlign; + } + else if(BufferFmt->OriginalType == UserFmtMSADPCM) + { + ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; + *offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels); + *offset *= BufferFmt->OriginalAlign; + } + else + *offset /= FrameSizeFromFmt(BufferFmt->mFmtChannels, BufferFmt->mFmtType); + *frac = 0; + break; + + case AL_SAMPLE_OFFSET: + dblfrac = modf(Source->Offset, &dbloff); + *offset = static_cast(mind(dbloff, std::numeric_limits::max())); + *frac = static_cast(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0)); + break; + + case AL_SEC_OFFSET: + dblfrac = modf(Source->Offset*BufferFmt->Frequency, &dbloff); + *offset = static_cast(mind(dbloff, std::numeric_limits::max())); + *frac = static_cast(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0)); + break; + } + Source->OffsetType = AL_NONE; + Source->Offset = 0.0; + + return AL_TRUE; +} + +/* ApplyOffset + * + * Apply the stored playback offset to the Source. This function will update + * the number of buffers "played" given the stored offset. + */ +ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) +{ + /* Get sample frame offset */ + ALuint offset{0u}; + ALsizei frac{0}; + if(!GetSampleOffset(Source, &offset, &frac)) + return AL_FALSE; + + ALuint totalBufferLen{0u}; + ALbufferlistitem *BufferList{Source->queue}; + while(BufferList && totalBufferLen <= offset) + { + if(static_cast(BufferList->max_samples) > offset-totalBufferLen) + { + /* Offset is in this buffer */ + voice->mPosition.store(offset - totalBufferLen, std::memory_order_relaxed); + voice->mPositionFrac.store(frac, std::memory_order_relaxed); + voice->mCurrentBuffer.store(BufferList, std::memory_order_release); + return AL_TRUE; + } + totalBufferLen += BufferList->max_samples; + + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + + /* Offset is out of range of the queue */ + return AL_FALSE; +} + + +ALsource *AllocSource(ALCcontext *context) +{ + ALCdevice *device{context->Device}; + std::lock_guard _{context->SourceLock}; + if(context->NumSources >= device->SourcesMax) + { + alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax); + return nullptr; + } + auto sublist = std::find_if(context->SourceList.begin(), context->SourceList.end(), + [](const SourceSubList &entry) noexcept -> bool + { return entry.FreeMask != 0; } + ); + auto lidx = static_cast(std::distance(context->SourceList.begin(), sublist)); + ALsource *source; + ALsizei slidx; + if(LIKELY(sublist != context->SourceList.end())) + { + slidx = CTZ64(sublist->FreeMask); + source = sublist->Sources + slidx; + } + else + { + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(context->SourceList.size() >= 1<<25)) + { + alSetError(context, AL_OUT_OF_MEMORY, "Too many sources allocated"); + return nullptr; + } + context->SourceList.emplace_back(); + sublist = context->SourceList.end() - 1; + + sublist->FreeMask = ~0_u64; + sublist->Sources = static_cast(al_calloc(16, sizeof(ALsource)*64)); + if(UNLIKELY(!sublist->Sources)) + { + context->SourceList.pop_back(); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate source batch"); + return nullptr; + } + + slidx = 0; + source = sublist->Sources + slidx; + } + + source = new (source) ALsource{device->NumAuxSends}; + + /* Add 1 to avoid source ID 0. */ + source->id = ((lidx<<6) | slidx) + 1; + + context->NumSources += 1; + sublist->FreeMask &= ~(1_u64 << slidx); + + return source; +} + +void FreeSource(ALCcontext *context, ALsource *source) +{ + ALuint id = source->id - 1; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; + + ALCdevice *device{context->Device}; + BackendUniqueLock backlock{*device->Backend}; + if(ALvoice *voice{GetSourceVoice(source, context)}) + { + voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed); + voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); + voice->mSourceID.store(0u, std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_release); + /* Don't set the voice to stopping if it was already stopped or + * stopping. + */ + ALvoice::State oldvstate{ALvoice::Playing}; + voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping, + std::memory_order_acq_rel, std::memory_order_acquire); + } + backlock.unlock(); + + al::destroy_at(source); + + context->SourceList[lidx].FreeMask |= 1_u64 << slidx; + context->NumSources--; +} + + +inline ALsource *LookupSource(ALCcontext *context, ALuint id) noexcept +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= context->SourceList.size())) + return nullptr; + SourceSubList &sublist{context->SourceList[lidx]}; + if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + return nullptr; + return sublist.Sources + slidx; +} + +inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) noexcept +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= device->BufferList.size())) + return nullptr; + BufferSubList &sublist = device->BufferList[lidx]; + if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + return nullptr; + return sublist.Buffers + slidx; +} + +inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) noexcept +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= device->FilterList.size())) + return nullptr; + FilterSubList &sublist = device->FilterList[lidx]; + if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + return nullptr; + return sublist.Filters + slidx; +} + +inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept +{ + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= context->EffectSlotList.size())) + return nullptr; + EffectSlotSubList &sublist{context->EffectSlotList[lidx]}; + if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + return nullptr; + return sublist.EffectSlots + slidx; +} + + +enum SourceProp : ALenum { + srcPitch = AL_PITCH, + srcGain = AL_GAIN, + srcMinGain = AL_MIN_GAIN, + srcMaxGain = AL_MAX_GAIN, + srcMaxDistance = AL_MAX_DISTANCE, + srcRolloffFactor = AL_ROLLOFF_FACTOR, + srcDopplerFactor = AL_DOPPLER_FACTOR, + srcConeOuterGain = AL_CONE_OUTER_GAIN, + srcSecOffset = AL_SEC_OFFSET, + srcSampleOffset = AL_SAMPLE_OFFSET, + srcByteOffset = AL_BYTE_OFFSET, + srcConeInnerAngle = AL_CONE_INNER_ANGLE, + srcConeOuterAngle = AL_CONE_OUTER_ANGLE, + srcRefDistance = AL_REFERENCE_DISTANCE, + + srcPosition = AL_POSITION, + srcVelocity = AL_VELOCITY, + srcDirection = AL_DIRECTION, + + srcSourceRelative = AL_SOURCE_RELATIVE, + srcLooping = AL_LOOPING, + srcBuffer = AL_BUFFER, + srcSourceState = AL_SOURCE_STATE, + srcBuffersQueued = AL_BUFFERS_QUEUED, + srcBuffersProcessed = AL_BUFFERS_PROCESSED, + srcSourceType = AL_SOURCE_TYPE, + + /* ALC_EXT_EFX */ + srcConeOuterGainHF = AL_CONE_OUTER_GAINHF, + srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR, + srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR, + srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO, + srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, + srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, + srcDirectFilter = AL_DIRECT_FILTER, + srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER, + + /* AL_SOFT_direct_channels */ + srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT, + + /* AL_EXT_source_distance_model */ + srcDistanceModel = AL_DISTANCE_MODEL, + + /* AL_SOFT_source_latency */ + srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT, + srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT, + + /* AL_EXT_STEREO_ANGLES */ + srcAngles = AL_STEREO_ANGLES, + + /* AL_EXT_SOURCE_RADIUS */ + srcRadius = AL_SOURCE_RADIUS, + + /* AL_EXT_BFORMAT */ + srcOrientation = AL_ORIENTATION, + + /* AL_SOFT_source_resampler */ + srcResampler = AL_SOURCE_RESAMPLER_SOFT, + + /* AL_SOFT_source_spatialize */ + srcSpatialize = AL_SOURCE_SPATIALIZE_SOFT, + + /* ALC_SOFT_device_clock */ + srcSampleOffsetClockSOFT = AL_SAMPLE_OFFSET_CLOCK_SOFT, + srcSecOffsetClockSOFT = AL_SEC_OFFSET_CLOCK_SOFT, +}; + +/** + * Returns if the last known state for the source was playing or paused. Does + * not sync with the mixer voice. + */ +inline bool IsPlayingOrPaused(ALsource *source) +{ return source->state == AL_PLAYING || source->state == AL_PAUSED; } + +/** + * Returns an updated source state using the matching voice's status (or lack + * thereof). + */ +inline ALenum GetSourceState(ALsource *source, ALvoice *voice) +{ + if(!voice && source->state == AL_PLAYING) + source->state = AL_STOPPED; + return source->state; +} + +/** + * Returns if the source should specify an update, given the context's + * deferring state and the source's last known state. + */ +inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context) +{ + return !context->DeferUpdates.load(std::memory_order_acquire) && + IsPlayingOrPaused(source); +} + + +/** Can only be called while the mixer is locked! */ +void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) +{ + ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)}; + if(!(enabledevt&EventType_SourceStateChange)) return; + + /* The mixer may have queued a state change that's not yet been processed, + * and we don't want state change messages to occur out of order, so send + * it through the async queue to ensure proper ordering. + */ + RingBuffer *ring{context->AsyncEvents.get()}; + auto evt_vec = ring->getWriteVector(); + if(evt_vec.first.len < 1) return; + + AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_SourceStateChange}}; + evt->u.srcstate.id = id; + evt->u.srcstate.state = state; + ring->writeAdvance(1); + context->EventSem.post(); +} + + +ALint FloatValsByProp(ALenum prop) +{ + switch(static_cast(prop)) + { + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_SOURCE_RADIUS: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + return 1; + + case AL_STEREO_ANGLES: + return 2; + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + return 3; + + case AL_ORIENTATION: + return 6; + + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + break; /* Double only */ + + case AL_BUFFER: + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + break; /* i/i64 only */ + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; /* i64 only */ + } + return 0; +} +ALint DoubleValsByProp(ALenum prop) +{ + switch(static_cast(prop)) + { + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_SOURCE_RADIUS: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + return 1; + + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + case AL_STEREO_ANGLES: + return 2; + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + return 3; + + case AL_ORIENTATION: + return 6; + + case AL_BUFFER: + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + break; /* i/i64 only */ + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; /* i64 only */ + } + return 0; +} + +ALint IntValsByProp(ALenum prop) +{ + switch(static_cast(prop)) + { + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_BUFFER: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_DIRECT_FILTER: + case AL_SOURCE_RADIUS: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + return 1; + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + case AL_AUXILIARY_SEND_FILTER: + return 3; + + case AL_ORIENTATION: + return 6; + + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; /* i64 only */ + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + break; /* Double only */ + case AL_STEREO_ANGLES: + break; /* Float/double only */ + } + return 0; +} +ALint Int64ValsByProp(ALenum prop) +{ + switch(static_cast(prop)) + { + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_BUFFER: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_DIRECT_FILTER: + case AL_SOURCE_RADIUS: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + return 1; + + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + return 2; + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + case AL_AUXILIARY_SEND_FILTER: + return 3; + + case AL_ORIENTATION: + return 6; + + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + break; /* Double only */ + case AL_STEREO_ANGLES: + break; /* Float/double only */ + } + return 0; +} + + +ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values); +ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values); +ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values); + +#define CHECKVAL(x) do { \ + if(!(x)) \ + { \ + alSetError(Context, AL_INVALID_VALUE, "Value out of range"); \ + return AL_FALSE; \ + } \ +} while(0) + +void UpdateSourceProps(ALsource *source, ALCcontext *context) +{ + ALvoice *voice; + if(SourceShouldUpdate(source, context) && (voice=GetSourceVoice(source, context)) != nullptr) + UpdateSourceProps(source, voice, context); + else + source->PropsClean.clear(std::memory_order_release); +} + +ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values) +{ + ALint ival; + + switch(prop) + { + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + /* Query only */ + SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, + "Setting read-only source property 0x%04x", prop); + + case AL_PITCH: + CHECKVAL(*values >= 0.0f); + + Source->Pitch = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_CONE_INNER_ANGLE: + CHECKVAL(*values >= 0.0f && *values <= 360.0f); + + Source->InnerAngle = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_CONE_OUTER_ANGLE: + CHECKVAL(*values >= 0.0f && *values <= 360.0f); + + Source->OuterAngle = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_GAIN: + CHECKVAL(*values >= 0.0f); + + Source->Gain = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_MAX_DISTANCE: + CHECKVAL(*values >= 0.0f); + + Source->MaxDistance = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_ROLLOFF_FACTOR: + CHECKVAL(*values >= 0.0f); + + Source->RolloffFactor = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_REFERENCE_DISTANCE: + CHECKVAL(*values >= 0.0f); + + Source->RefDistance = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_MIN_GAIN: + CHECKVAL(*values >= 0.0f); + + Source->MinGain = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_MAX_GAIN: + CHECKVAL(*values >= 0.0f); + + Source->MaxGain = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_CONE_OUTER_GAIN: + CHECKVAL(*values >= 0.0f && *values <= 1.0f); + + Source->OuterGain = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_CONE_OUTER_GAINHF: + CHECKVAL(*values >= 0.0f && *values <= 1.0f); + + Source->OuterGainHF = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_AIR_ABSORPTION_FACTOR: + CHECKVAL(*values >= 0.0f && *values <= 10.0f); + + Source->AirAbsorptionFactor = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_ROOM_ROLLOFF_FACTOR: + CHECKVAL(*values >= 0.0f && *values <= 10.0f); + + Source->RoomRolloffFactor = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_DOPPLER_FACTOR: + CHECKVAL(*values >= 0.0f && *values <= 1.0f); + + Source->DopplerFactor = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + CHECKVAL(*values >= 0.0f); + + Source->OffsetType = prop; + Source->Offset = *values; + + if(IsPlayingOrPaused(Source)) + { + ALCdevice *device{Context->Device}; + BackendLockGuard _{*device->Backend}; + /* Double-check that the source is still playing while we have + * the lock. + */ + if(ALvoice *voice{GetSourceVoice(Source, Context)}) + { + if(ApplyOffset(Source, voice) == AL_FALSE) + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid offset"); + } + } + return AL_TRUE; + + case AL_SOURCE_RADIUS: + CHECKVAL(*values >= 0.0f && std::isfinite(*values)); + + Source->Radius = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_STEREO_ANGLES: + CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1])); + + Source->StereoPan[0] = values[0]; + Source->StereoPan[1] = values[1]; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + + case AL_POSITION: + CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); + + Source->Position[0] = values[0]; + Source->Position[1] = values[1]; + Source->Position[2] = values[2]; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_VELOCITY: + CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); + + Source->Velocity[0] = values[0]; + Source->Velocity[1] = values[1]; + Source->Velocity[2] = values[2]; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_DIRECTION: + CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); + + Source->Direction[0] = values[0]; + Source->Direction[1] = values[1]; + Source->Direction[2] = values[2]; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_ORIENTATION: + CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) && + std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5])); + + Source->OrientAt[0] = values[0]; + Source->OrientAt[1] = values[1]; + Source->OrientAt[2] = values[2]; + Source->OrientUp[0] = values[3]; + Source->OrientUp[1] = values[4]; + Source->OrientUp[2] = values[5]; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_SOURCE_TYPE: + case AL_DISTANCE_MODEL: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + ival = static_cast(values[0]); + return SetSourceiv(Source, Context, prop, &ival); + + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + ival = static_cast(static_cast(values[0])); + return SetSourceiv(Source, Context, prop, &ival); + + case AL_BUFFER: + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; + } + + ERR("Unexpected property: 0x%04x\n", prop); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source float property 0x%04x", prop); +} + +ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values) +{ + ALCdevice *device{Context->Device}; + ALbuffer *buffer{nullptr}; + ALfilter *filter{nullptr}; + ALeffectslot *slot{nullptr}; + ALbufferlistitem *oldlist{nullptr}; + std::unique_lock slotlock; + std::unique_lock filtlock; + std::unique_lock buflock; + ALfloat fvals[6]; + + switch(prop) + { + case AL_SOURCE_STATE: + case AL_SOURCE_TYPE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + /* Query only */ + SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, + "Setting read-only source property 0x%04x", prop); + + case AL_SOURCE_RELATIVE: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->HeadRelative = static_cast(*values); + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_LOOPING: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->Looping = static_cast(*values); + if(IsPlayingOrPaused(Source)) + { + ALvoice *voice{GetSourceVoice(Source, Context)}; + if(voice) + { + if(Source->Looping) + voice->mLoopBuffer.store(Source->queue, std::memory_order_release); + else + voice->mLoopBuffer.store(nullptr, std::memory_order_release); + + /* If the source is playing, wait for the current mix to finish + * to ensure it isn't currently looping back or reaching the + * end. + */ + while((device->MixCount.load(std::memory_order_acquire)&1)) + std::this_thread::yield(); + } + } + return AL_TRUE; + + case AL_BUFFER: + buflock = std::unique_lock{device->BufferLock}; + if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != nullptr)) + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid buffer ID %u", + *values); + + if(buffer && buffer->MappedAccess != 0 && + !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) + SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, + "Setting non-persistently mapped buffer %u", buffer->id); + else + { + ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context)); + if(state == AL_PLAYING || state == AL_PAUSED) + SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, + "Setting buffer on playing or paused source %u", Source->id); + } + + oldlist = Source->queue; + if(buffer != nullptr) + { + /* Add the selected buffer to a one-item queue */ + auto newlist = static_cast(al_calloc(alignof(void*), + ALbufferlistitem::Sizeof(1u))); + newlist->next.store(nullptr, std::memory_order_relaxed); + newlist->max_samples = buffer->SampleLen; + newlist->num_buffers = 1; + newlist->buffers[0] = buffer; + IncrementRef(&buffer->ref); + + /* Source is now Static */ + Source->SourceType = AL_STATIC; + Source->queue = newlist; + } + else + { + /* Source is now Undetermined */ + Source->SourceType = AL_UNDETERMINED; + Source->queue = nullptr; + } + buflock.unlock(); + + /* Delete all elements in the previous queue */ + while(oldlist != nullptr) + { + ALbufferlistitem *temp{oldlist}; + oldlist = temp->next.load(std::memory_order_relaxed); + + for(ALsizei i{0};i < temp->num_buffers;i++) + { + if(temp->buffers[i]) + DecrementRef(&temp->buffers[i]->ref); + } + al_free(temp); + } + return AL_TRUE; + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + CHECKVAL(*values >= 0); + + Source->OffsetType = prop; + Source->Offset = *values; + + if(IsPlayingOrPaused(Source)) + { + ALCdevice *device{Context->Device}; + BackendLockGuard _{*device->Backend}; + if(ALvoice *voice{GetSourceVoice(Source, Context)}) + { + if(ApplyOffset(Source, voice) == AL_FALSE) + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, + "Invalid source offset"); + } + } + return AL_TRUE; + + case AL_DIRECT_FILTER: + filtlock = std::unique_lock{device->FilterLock}; + if(!(*values == 0 || (filter=LookupFilter(device, *values)) != nullptr)) + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", + *values); + + if(!filter) + { + Source->Direct.Gain = 1.0f; + Source->Direct.GainHF = 1.0f; + Source->Direct.HFReference = LOWPASSFREQREF; + Source->Direct.GainLF = 1.0f; + Source->Direct.LFReference = HIGHPASSFREQREF; + } + else + { + Source->Direct.Gain = filter->Gain; + Source->Direct.GainHF = filter->GainHF; + Source->Direct.HFReference = filter->HFReference; + Source->Direct.GainLF = filter->GainLF; + Source->Direct.LFReference = filter->LFReference; + } + filtlock.unlock(); + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_DIRECT_FILTER_GAINHF_AUTO: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->DryGainHFAuto = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->WetGainAuto = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->WetGainHFAuto = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_DIRECT_CHANNELS_SOFT: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->DirectChannels = *values; + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_DISTANCE_MODEL: + CHECKVAL(*values == AL_NONE || + *values == AL_INVERSE_DISTANCE || + *values == AL_INVERSE_DISTANCE_CLAMPED || + *values == AL_LINEAR_DISTANCE || + *values == AL_LINEAR_DISTANCE_CLAMPED || + *values == AL_EXPONENT_DISTANCE || + *values == AL_EXPONENT_DISTANCE_CLAMPED); + + Source->mDistanceModel = static_cast(*values); + if(Context->SourceDistanceModel) + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_SOURCE_RESAMPLER_SOFT: + CHECKVAL(*values >= 0 && *values <= ResamplerMax); + + Source->mResampler = static_cast(*values); + UpdateSourceProps(Source, Context); + return AL_TRUE; + + case AL_SOURCE_SPATIALIZE_SOFT: + CHECKVAL(*values >= AL_FALSE && *values <= AL_AUTO_SOFT); + + Source->mSpatialize = static_cast(*values); + UpdateSourceProps(Source, Context); + return AL_TRUE; + + + case AL_AUXILIARY_SEND_FILTER: + slotlock = std::unique_lock{Context->EffectSlotLock}; + if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != nullptr)) + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid effect ID %u", + values[0]); + if(static_cast(values[1]) >= static_cast(device->NumAuxSends)) + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid send %u", values[1]); + + filtlock = std::unique_lock{device->FilterLock}; + if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != nullptr)) + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", + values[2]); + + if(!filter) + { + /* Disable filter */ + Source->Send[values[1]].Gain = 1.0f; + Source->Send[values[1]].GainHF = 1.0f; + Source->Send[values[1]].HFReference = LOWPASSFREQREF; + Source->Send[values[1]].GainLF = 1.0f; + Source->Send[values[1]].LFReference = HIGHPASSFREQREF; + } + else + { + Source->Send[values[1]].Gain = filter->Gain; + Source->Send[values[1]].GainHF = filter->GainHF; + Source->Send[values[1]].HFReference = filter->HFReference; + Source->Send[values[1]].GainLF = filter->GainLF; + Source->Send[values[1]].LFReference = filter->LFReference; + } + filtlock.unlock(); + + if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source)) + { + /* Add refcount on the new slot, and release the previous slot */ + if(slot) IncrementRef(&slot->ref); + if(Source->Send[values[1]].Slot) + DecrementRef(&Source->Send[values[1]].Slot->ref); + Source->Send[values[1]].Slot = slot; + + /* We must force an update if the auxiliary slot changed on an + * active source, in case the slot is about to be deleted. + */ + ALvoice *voice{GetSourceVoice(Source, Context)}; + if(voice) UpdateSourceProps(Source, voice, Context); + else Source->PropsClean.clear(std::memory_order_release); + } + else + { + if(slot) IncrementRef(&slot->ref); + if(Source->Send[values[1]].Slot) + DecrementRef(&Source->Send[values[1]].Slot->ref); + Source->Send[values[1]].Slot = slot; + UpdateSourceProps(Source, Context); + } + + return AL_TRUE; + + + /* 1x float */ + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_REFERENCE_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_SOURCE_RADIUS: + fvals[0] = static_cast(*values); + return SetSourcefv(Source, Context, prop, fvals); + + /* 3x float */ + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + fvals[0] = static_cast(values[0]); + fvals[1] = static_cast(values[1]); + fvals[2] = static_cast(values[2]); + return SetSourcefv(Source, Context, prop, fvals); + + /* 6x float */ + case AL_ORIENTATION: + fvals[0] = static_cast(values[0]); + fvals[1] = static_cast(values[1]); + fvals[2] = static_cast(values[2]); + fvals[3] = static_cast(values[3]); + fvals[4] = static_cast(values[4]); + fvals[5] = static_cast(values[5]); + return SetSourcefv(Source, Context, prop, fvals); + + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + case AL_STEREO_ANGLES: + break; + } + + ERR("Unexpected property: 0x%04x\n", prop); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x", + prop); +} + +ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values) +{ + ALfloat fvals[6]; + ALint ivals[3]; + + switch(prop) + { + case AL_SOURCE_TYPE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_STATE: + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + /* Query only */ + SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, + "Setting read-only source property 0x%04x", prop); + + /* 1x int */ + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + CHECKVAL(*values <= INT_MAX && *values >= INT_MIN); + + ivals[0] = static_cast(*values); + return SetSourceiv(Source, Context, prop, ivals); + + /* 1x uint */ + case AL_BUFFER: + case AL_DIRECT_FILTER: + CHECKVAL(*values <= UINT_MAX && *values >= 0); + + ivals[0] = static_cast(*values); + return SetSourceiv(Source, Context, prop, ivals); + + /* 3x uint */ + case AL_AUXILIARY_SEND_FILTER: + CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 && + values[1] <= UINT_MAX && values[1] >= 0 && + values[2] <= UINT_MAX && values[2] >= 0); + + ivals[0] = static_cast(values[0]); + ivals[1] = static_cast(values[1]); + ivals[2] = static_cast(values[2]); + return SetSourceiv(Source, Context, prop, ivals); + + /* 1x float */ + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_REFERENCE_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_SOURCE_RADIUS: + fvals[0] = static_cast(*values); + return SetSourcefv(Source, Context, prop, fvals); + + /* 3x float */ + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + fvals[0] = static_cast(values[0]); + fvals[1] = static_cast(values[1]); + fvals[2] = static_cast(values[2]); + return SetSourcefv(Source, Context, prop, fvals); + + /* 6x float */ + case AL_ORIENTATION: + fvals[0] = static_cast(values[0]); + fvals[1] = static_cast(values[1]); + fvals[2] = static_cast(values[2]); + fvals[3] = static_cast(values[3]); + fvals[4] = static_cast(values[4]); + fvals[5] = static_cast(values[5]); + return SetSourcefv(Source, Context, prop, fvals); + + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + case AL_STEREO_ANGLES: + break; + } + + ERR("Unexpected property: 0x%04x\n", prop); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x", + prop); +} + +#undef CHECKVAL + + +ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values); +ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values); +ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64SOFT *values); + +ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values) +{ + ALCdevice *device{Context->Device}; + ClockLatency clocktime; + std::chrono::nanoseconds srcclock; + ALint ivals[3]; + ALboolean err; + + switch(prop) + { + case AL_GAIN: + *values = Source->Gain; + return AL_TRUE; + + case AL_PITCH: + *values = Source->Pitch; + return AL_TRUE; + + case AL_MAX_DISTANCE: + *values = Source->MaxDistance; + return AL_TRUE; + + case AL_ROLLOFF_FACTOR: + *values = Source->RolloffFactor; + return AL_TRUE; + + case AL_REFERENCE_DISTANCE: + *values = Source->RefDistance; + return AL_TRUE; + + case AL_CONE_INNER_ANGLE: + *values = Source->InnerAngle; + return AL_TRUE; + + case AL_CONE_OUTER_ANGLE: + *values = Source->OuterAngle; + return AL_TRUE; + + case AL_MIN_GAIN: + *values = Source->MinGain; + return AL_TRUE; + + case AL_MAX_GAIN: + *values = Source->MaxGain; + return AL_TRUE; + + case AL_CONE_OUTER_GAIN: + *values = Source->OuterGain; + return AL_TRUE; + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + *values = GetSourceOffset(Source, prop, Context); + return AL_TRUE; + + case AL_CONE_OUTER_GAINHF: + *values = Source->OuterGainHF; + return AL_TRUE; + + case AL_AIR_ABSORPTION_FACTOR: + *values = Source->AirAbsorptionFactor; + return AL_TRUE; + + case AL_ROOM_ROLLOFF_FACTOR: + *values = Source->RoomRolloffFactor; + return AL_TRUE; + + case AL_DOPPLER_FACTOR: + *values = Source->DopplerFactor; + return AL_TRUE; + + case AL_SOURCE_RADIUS: + *values = Source->Radius; + return AL_TRUE; + + case AL_STEREO_ANGLES: + values[0] = Source->StereoPan[0]; + values[1] = Source->StereoPan[1]; + return AL_TRUE; + + case AL_SEC_OFFSET_LATENCY_SOFT: + /* Get the source offset with the clock time first. Then get the + * clock time with the device latency. Order is important. + */ + values[0] = GetSourceSecOffset(Source, Context, &srcclock); + { std::lock_guard _{device->StateLock}; + clocktime = GetClockLatency(device); + } + if(srcclock == clocktime.ClockTime) + values[1] = static_cast(clocktime.Latency.count()) / 1000000000.0; + else + { + /* If the clock time incremented, reduce the latency by that + * much since it's that much closer to the source offset it got + * earlier. + */ + std::chrono::nanoseconds diff = clocktime.ClockTime - srcclock; + values[1] = static_cast((clocktime.Latency - std::min(clocktime.Latency, diff)).count()) / + 1000000000.0; + } + return AL_TRUE; + + case AL_SEC_OFFSET_CLOCK_SOFT: + values[0] = GetSourceSecOffset(Source, Context, &srcclock); + values[1] = srcclock.count() / 1000000000.0; + return AL_TRUE; + + case AL_POSITION: + values[0] = Source->Position[0]; + values[1] = Source->Position[1]; + values[2] = Source->Position[2]; + return AL_TRUE; + + case AL_VELOCITY: + values[0] = Source->Velocity[0]; + values[1] = Source->Velocity[1]; + values[2] = Source->Velocity[2]; + return AL_TRUE; + + case AL_DIRECTION: + values[0] = Source->Direction[0]; + values[1] = Source->Direction[1]; + values[2] = Source->Direction[2]; + return AL_TRUE; + + case AL_ORIENTATION: + values[0] = Source->OrientAt[0]; + values[1] = Source->OrientAt[1]; + values[2] = Source->OrientAt[2]; + values[3] = Source->OrientUp[0]; + values[4] = Source->OrientUp[1]; + values[5] = Source->OrientUp[2]; + return AL_TRUE; + + /* 1x int */ + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) + *values = static_cast(ivals[0]); + return err; + + case AL_BUFFER: + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; + } + + ERR("Unexpected property: 0x%04x\n", prop); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source double property 0x%04x", + prop); +} + +ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values) +{ + ALbufferlistitem *BufferList; + ALdouble dvals[6]; + ALboolean err; + + switch(prop) + { + case AL_SOURCE_RELATIVE: + *values = Source->HeadRelative; + return AL_TRUE; + + case AL_LOOPING: + *values = Source->Looping; + return AL_TRUE; + + case AL_BUFFER: + BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : nullptr; + *values = (BufferList && BufferList->num_buffers >= 1 && BufferList->buffers[0]) ? + BufferList->buffers[0]->id : 0; + return AL_TRUE; + + case AL_SOURCE_STATE: + *values = GetSourceState(Source, GetSourceVoice(Source, Context)); + return AL_TRUE; + + case AL_BUFFERS_QUEUED: + if(!(BufferList=Source->queue)) + *values = 0; + else + { + ALsizei count = 0; + do { + count += BufferList->num_buffers; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } while(BufferList != nullptr); + *values = count; + } + return AL_TRUE; + + case AL_BUFFERS_PROCESSED: + if(Source->Looping || Source->SourceType != AL_STREAMING) + { + /* Buffers on a looping source are in a perpetual state of + * PENDING, so don't report any as PROCESSED */ + *values = 0; + } + else + { + const ALbufferlistitem *BufferList{Source->queue}; + const ALbufferlistitem *Current{nullptr}; + ALsizei played{0}; + + ALvoice *voice{GetSourceVoice(Source, Context)}; + if(voice != nullptr) + Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); + else if(Source->state == AL_INITIAL) + Current = BufferList; + + while(BufferList && BufferList != Current) + { + played += BufferList->num_buffers; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + *values = played; + } + return AL_TRUE; + + case AL_SOURCE_TYPE: + *values = Source->SourceType; + return AL_TRUE; + + case AL_DIRECT_FILTER_GAINHF_AUTO: + *values = Source->DryGainHFAuto; + return AL_TRUE; + + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + *values = Source->WetGainAuto; + return AL_TRUE; + + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + *values = Source->WetGainHFAuto; + return AL_TRUE; + + case AL_DIRECT_CHANNELS_SOFT: + *values = Source->DirectChannels; + return AL_TRUE; + + case AL_DISTANCE_MODEL: + *values = static_cast(Source->mDistanceModel); + return AL_TRUE; + + case AL_SOURCE_RESAMPLER_SOFT: + *values = Source->mResampler; + return AL_TRUE; + + case AL_SOURCE_SPATIALIZE_SOFT: + *values = Source->mSpatialize; + return AL_TRUE; + + /* 1x float/double */ + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_REFERENCE_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_DOPPLER_FACTOR: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_SOURCE_RADIUS: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + *values = static_cast(dvals[0]); + return err; + + /* 3x float/double */ + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + { + values[0] = static_cast(dvals[0]); + values[1] = static_cast(dvals[1]); + values[2] = static_cast(dvals[2]); + } + return err; + + /* 6x float/double */ + case AL_ORIENTATION: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + { + values[0] = static_cast(dvals[0]); + values[1] = static_cast(dvals[1]); + values[2] = static_cast(dvals[2]); + values[3] = static_cast(dvals[3]); + values[4] = static_cast(dvals[4]); + values[5] = static_cast(dvals[5]); + } + return err; + + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; /* i64 only */ + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + break; /* Double only */ + case AL_STEREO_ANGLES: + break; /* Float/double only */ + + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + break; /* ??? */ + } + + ERR("Unexpected property: 0x%04x\n", prop); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x", + prop); +} + +ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64SOFT *values) +{ + ALCdevice *device = Context->Device; + ClockLatency clocktime; + std::chrono::nanoseconds srcclock; + ALdouble dvals[6]; + ALint ivals[3]; + ALboolean err; + + switch(prop) + { + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + /* Get the source offset with the clock time first. Then get the + * clock time with the device latency. Order is important. + */ + values[0] = GetSourceSampleOffset(Source, Context, &srcclock); + { std::lock_guard _{device->StateLock}; + clocktime = GetClockLatency(device); + } + if(srcclock == clocktime.ClockTime) + values[1] = clocktime.Latency.count(); + else + { + /* If the clock time incremented, reduce the latency by that + * much since it's that much closer to the source offset it got + * earlier. + */ + auto diff = clocktime.ClockTime - srcclock; + values[1] = (clocktime.Latency - std::min(clocktime.Latency, diff)).count(); + } + return AL_TRUE; + + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + values[0] = GetSourceSampleOffset(Source, Context, &srcclock); + values[1] = srcclock.count(); + return AL_TRUE; + + /* 1x float/double */ + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_REFERENCE_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_DOPPLER_FACTOR: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_SOURCE_RADIUS: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + *values = static_cast(dvals[0]); + return err; + + /* 3x float/double */ + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + { + values[0] = static_cast(dvals[0]); + values[1] = static_cast(dvals[1]); + values[2] = static_cast(dvals[2]); + } + return err; + + /* 6x float/double */ + case AL_ORIENTATION: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + { + values[0] = static_cast(dvals[0]); + values[1] = static_cast(dvals[1]); + values[2] = static_cast(dvals[2]); + values[3] = static_cast(dvals[3]); + values[4] = static_cast(dvals[4]); + values[5] = static_cast(dvals[5]); + } + return err; + + /* 1x int */ + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) + *values = ivals[0]; + return err; + + /* 1x uint */ + case AL_BUFFER: + case AL_DIRECT_FILTER: + if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) + *values = static_cast(ivals[0]); + return err; + + /* 3x uint */ + case AL_AUXILIARY_SEND_FILTER: + if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) + { + values[0] = static_cast(ivals[0]); + values[1] = static_cast(ivals[1]); + values[2] = static_cast(ivals[2]); + } + return err; + + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + break; /* Double only */ + case AL_STEREO_ANGLES: + break; /* Float/double only */ + } + + ERR("Unexpected property: 0x%04x\n", prop); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x", + prop); +} + +} // namespace + +AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(n < 0) + alSetError(context.get(), AL_INVALID_VALUE, "Generating %d sources", n); + else if(n == 1) + { + ALsource *source = AllocSource(context.get()); + if(source) sources[0] = source->id; + } + else + { + al::vector tempids(n); + auto alloc_end = std::find_if_not(tempids.begin(), tempids.end(), + [&context](ALuint &id) -> bool + { + ALsource *source{AllocSource(context.get())}; + if(!source) return false; + id = source->id; + return true; + } + ); + if(alloc_end != tempids.end()) + alDeleteSources(static_cast(std::distance(tempids.begin(), alloc_end)), + tempids.data()); + else + std::copy(tempids.cbegin(), tempids.cend(), sources); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(n < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Deleting %d sources", n); + + std::lock_guard _{context->SourceLock}; + + /* Check that all Sources are valid */ + const ALuint *sources_end = sources + n; + auto invsrc = std::find_if_not(sources, sources_end, + [&context](ALuint sid) -> bool + { + if(!LookupSource(context.get(), sid)) + { + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", sid); + return false; + } + return true; + } + ); + if(LIKELY(invsrc == sources_end)) + { + /* All good. Delete source IDs. */ + std::for_each(sources, sources_end, + [&context](ALuint sid) -> void + { + ALsource *src{LookupSource(context.get(), sid)}; + if(src) FreeSource(context.get(), src); + } + ); + } +} +END_API_FUNC + +AL_API ALboolean AL_APIENTRY alIsSource(ALuint source) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(LIKELY(context)) + { + std::lock_guard _{context->SourceLock}; + if(LookupSource(context.get(), source) != nullptr) + return AL_TRUE; + } + return AL_FALSE; +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(FloatValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid float property 0x%04x", param); + else + SetSourcefv(Source, context.get(), static_cast(param), &value); +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(FloatValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); + else + { + ALfloat fvals[3] = { value1, value2, value3 }; + SetSourcefv(Source, context.get(), static_cast(param), fvals); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(FloatValsByProp(param) < 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); + else + SetSourcefv(Source, context.get(), static_cast(param), values); +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(DoubleValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid double property 0x%04x", param); + else + { + ALfloat fval = static_cast(value); + SetSourcefv(Source, context.get(), static_cast(param), &fval); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(DoubleValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); + else { + ALfloat fvals[3] = {static_cast(value1), + static_cast(value2), + static_cast(value3)}; + SetSourcefv(Source, context.get(), static_cast(param), fvals); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else + { + ALint count{DoubleValsByProp(param)}; + if(count < 1 || count > 6) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); + else + { + ALfloat fvals[6]; + ALint i; + + for(i = 0;i < count;i++) + fvals[i] = static_cast(values[i]); + SetSourcefv(Source, context.get(), static_cast(param), fvals); + } + } +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(IntValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); + else + SetSourceiv(Source, context.get(), static_cast(param), &value); +} +END_API_FUNC + +AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(IntValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); + else + { + ALint ivals[3] = { value1, value2, value3 }; + SetSourceiv(Source, context.get(), static_cast(param), ivals); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source = LookupSource(context.get(), source); + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(IntValsByProp(param) < 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); + else + SetSourceiv(Source, context.get(), static_cast(param), values); +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(Int64ValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); + else + SetSourcei64v(Source, context.get(), static_cast(param), &value); +} +END_API_FUNC + +AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(Int64ValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); + else + { + ALint64SOFT i64vals[3] = { value1, value2, value3 }; + SetSourcei64v(Source, context.get(), static_cast(param), i64vals); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + std::lock_guard __{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(Int64ValsByProp(param) < 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); + else + SetSourcei64v(Source, context.get(), static_cast(param), values); +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!value) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(FloatValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid float property 0x%04x", param); + else + { + ALdouble dval; + if(GetSourcedv(Source, context.get(), static_cast(param), &dval)) + *value = static_cast(dval); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!(value1 && value2 && value3)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(FloatValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); + else + { + ALdouble dvals[3]; + if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) + { + *value1 = static_cast(dvals[0]); + *value2 = static_cast(dvals[1]); + *value3 = static_cast(dvals[2]); + } + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else + { + ALint count{FloatValsByProp(param)}; + if(count < 1 && count > 6) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); + else + { + ALdouble dvals[6]; + if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) + { + for(ALint i{0};i < count;i++) + values[i] = static_cast(dvals[i]); + } + } + } +} +END_API_FUNC + + +AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!value) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(DoubleValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid double property 0x%04x", param); + else + GetSourcedv(Source, context.get(), static_cast(param), value); +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!(value1 && value2 && value3)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(DoubleValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); + else + { + ALdouble dvals[3]; + if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) + { + *value1 = dvals[0]; + *value2 = dvals[1]; + *value3 = dvals[2]; + } + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(DoubleValsByProp(param) < 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); + else + GetSourcedv(Source, context.get(), static_cast(param), values); +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!value) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(IntValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); + else + GetSourceiv(Source, context.get(), static_cast(param), value); +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!(value1 && value2 && value3)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(IntValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); + else + { + ALint ivals[3]; + if(GetSourceiv(Source, context.get(), static_cast(param), ivals)) + { + *value1 = ivals[0]; + *value2 = ivals[1]; + *value3 = ivals[2]; + } + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(IntValsByProp(param) < 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); + else + GetSourceiv(Source, context.get(), static_cast(param), values); +} +END_API_FUNC + + +AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!value) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(Int64ValsByProp(param) != 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); + else + GetSourcei64v(Source, context.get(), static_cast(param), value); +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!(value1 && value2 && value3)) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(Int64ValsByProp(param) != 3) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); + else + { + ALint64SOFT i64vals[3]; + if(GetSourcei64v(Source, context.get(), static_cast(param), i64vals)) + { + *value1 = i64vals[0]; + *value2 = i64vals[1]; + *value3 = i64vals[2]; + } + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->SourceLock}; + ALsource *Source{LookupSource(context.get(), source)}; + if(UNLIKELY(!Source)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + else if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else if(Int64ValsByProp(param) < 1) + alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); + else + GetSourcei64v(Source, context.get(), static_cast(param), values); +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source) +START_API_FUNC +{ alSourcePlayv(1, &source); } +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(n < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Playing %d sources", n); + if(n == 0) return; + + al::vector extra_sources; + std::array source_storage; + ALsource **srchandles{source_storage.data()}; + if(UNLIKELY(static_cast(n) > source_storage.size())) + { + extra_sources.resize(n); + srchandles = extra_sources.data(); + } + + std::lock_guard _{context->SourceLock}; + for(ALsizei i{0};i < n;i++) + { + srchandles[i] = LookupSource(context.get(), sources[i]); + if(!srchandles[i]) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); + } + + ALCdevice *device{context->Device}; + BackendLockGuard __{*device->Backend}; + /* If the device is disconnected, go right to stopped. */ + if(UNLIKELY(!device->Connected.load(std::memory_order_acquire))) + { + /* TODO: Send state change event? */ + std::for_each(srchandles, srchandles+n, + [](ALsource *source) -> void + { + source->OffsetType = AL_NONE; + source->Offset = 0.0; + source->state = AL_STOPPED; + } + ); + return; + } + + /* Count the number of reusable voices. */ + auto voices_end = context->Voices->begin() + + context->VoiceCount.load(std::memory_order_relaxed); + auto free_voices = std::accumulate(context->Voices->begin(), voices_end, ALsizei{0}, + [](const ALsizei count, const ALvoice &voice) noexcept -> ALsizei + { + if(voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && + voice.mSourceID.load(std::memory_order_relaxed) == 0u) + return count + 1; + return count; + } + ); + if(UNLIKELY(n > free_voices)) + { + /* Increment the number of voices to handle the request. */ + const ALuint need_voices{static_cast(n) - free_voices}; + const size_t rem_voices{context->Voices->size() - + context->VoiceCount.load(std::memory_order_relaxed)}; + + if(UNLIKELY(need_voices > rem_voices)) + { + /* Allocate more voices to get enough. */ + const size_t alloc_count{need_voices - rem_voices}; + if(UNLIKELY(context->Voices->size() > std::numeric_limits::max()-alloc_count)) + SETERR_RETURN(context.get(), AL_OUT_OF_MEMORY,, + "Overflow increasing voice count to %zu + %zu", context->Voices->size(), + alloc_count); + + const size_t newcount{context->Voices->size() + alloc_count}; + AllocateVoices(context.get(), newcount); + } + + context->VoiceCount.fetch_add(need_voices, std::memory_order_relaxed); + } + + auto start_source = [&context,device](ALsource *source) -> void + { + /* Check that there is a queue containing at least one valid, non zero + * length buffer. + */ + ALbufferlistitem *BufferList{source->queue}; + while(BufferList && BufferList->max_samples == 0) + BufferList = BufferList->next.load(std::memory_order_relaxed); + + /* If there's nothing to play, go right to stopped. */ + if(UNLIKELY(!BufferList)) + { + /* NOTE: A source without any playable buffers should not have an + * ALvoice since it shouldn't be in a playing or paused state. So + * there's no need to look up its voice and clear the source. + */ + ALenum oldstate{GetSourceState(source, nullptr)}; + source->OffsetType = AL_NONE; + source->Offset = 0.0; + if(oldstate != AL_STOPPED) + { + source->state = AL_STOPPED; + SendStateChangeEvent(context.get(), source->id, AL_STOPPED); + } + return; + } + + ALvoice *voice{GetSourceVoice(source, context.get())}; + switch(GetSourceState(source, voice)) + { + case AL_PLAYING: + assert(voice != nullptr); + /* A source that's already playing is restarted from the beginning. */ + voice->mCurrentBuffer.store(BufferList, std::memory_order_relaxed); + voice->mPosition.store(0u, std::memory_order_relaxed); + voice->mPositionFrac.store(0, std::memory_order_release); + return; + + case AL_PAUSED: + assert(voice != nullptr); + /* A source that's paused simply resumes. */ + voice->mPlayState.store(ALvoice::Playing, std::memory_order_release); + source->state = AL_PLAYING; + SendStateChangeEvent(context.get(), source->id, AL_PLAYING); + return; + + default: + assert(voice == nullptr); + break; + } + + /* Look for an unused voice to play this source with. */ + auto voices_end = context->Voices->begin() + + context->VoiceCount.load(std::memory_order_relaxed); + voice = std::find_if(context->Voices->begin(), voices_end, + [](const ALvoice &voice) noexcept -> bool + { + return voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && + voice.mSourceID.load(std::memory_order_relaxed) == 0u; + } + ); + assert(voice != voices_end); + auto vidx = static_cast(std::distance(context->Voices->begin(), voice)); + voice->mPlayState.store(ALvoice::Stopped, std::memory_order_release); + + source->PropsClean.test_and_set(std::memory_order_acquire); + UpdateSourceProps(source, voice, context.get()); + + /* A source that's not playing or paused has any offset applied when it + * starts playing. + */ + if(source->Looping) + voice->mLoopBuffer.store(source->queue, std::memory_order_relaxed); + else + voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); + voice->mCurrentBuffer.store(BufferList, std::memory_order_relaxed); + voice->mPosition.store(0u, std::memory_order_relaxed); + voice->mPositionFrac.store(0, std::memory_order_relaxed); + bool start_fading{false}; + if(ApplyOffset(source, voice) != AL_FALSE) + start_fading = voice->mPosition.load(std::memory_order_relaxed) != 0 || + voice->mPositionFrac.load(std::memory_order_relaxed) != 0 || + voice->mCurrentBuffer.load(std::memory_order_relaxed) != BufferList; + + auto buffers_end = BufferList->buffers + BufferList->num_buffers; + auto buffer = std::find_if(BufferList->buffers, buffers_end, + std::bind(std::not_equal_to{}, _1, nullptr)); + if(buffer != buffers_end) + { + voice->mFrequency = (*buffer)->Frequency; + voice->mFmtChannels = (*buffer)->mFmtChannels; + voice->mNumChannels = ChannelsFromFmt((*buffer)->mFmtChannels); + voice->mSampleSize = BytesFromFmt((*buffer)->mFmtType); + } + + /* Clear the stepping value so the mixer knows not to mix this until + * the update gets applied. + */ + voice->mStep = 0; + + voice->mFlags = start_fading ? VOICE_IS_FADING : 0; + if(source->SourceType == AL_STATIC) voice->mFlags |= VOICE_IS_STATIC; + + /* Don't need to set the VOICE_IS_AMBISONIC flag if the device is + * mixing in first order. No HF scaling is necessary to mix it. + */ + if((voice->mFmtChannels == FmtBFormat2D || voice->mFmtChannels == FmtBFormat3D) && + device->mAmbiOrder > 1) + { + const int *OrderFromChan; + if(voice->mFmtChannels == FmtBFormat2D) + { + static constexpr int Order2DFromChan[MAX_AMBI2D_CHANNELS]{ + 0, 1,1, 2,2, 3,3 + }; + OrderFromChan = Order2DFromChan; + } + else + { + static constexpr int Order3DFromChan[MAX_AMBI_CHANNELS]{ + 0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3, + }; + OrderFromChan = Order3DFromChan; + } + + BandSplitter splitter{400.0f / static_cast(device->Frequency)}; + + const auto scales = BFormatDec::GetHFOrderScales(1, device->mAmbiOrder); + auto init_ambi = [scales,&OrderFromChan,&splitter](ALvoice::ChannelData &chandata) -> void + { + chandata.mPrevSamples.fill(0.0f); + chandata.mAmbiScale = scales[*(OrderFromChan++)]; + chandata.mAmbiSplitter = splitter; + }; + std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, + init_ambi); + + voice->mFlags |= VOICE_IS_AMBISONIC; + } + else + { + /* Clear previous samples. */ + auto clear_prevs = [](ALvoice::ChannelData &chandata) -> void + { chandata.mPrevSamples.fill(0.0f); }; + std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, + clear_prevs); + } + + auto clear_params = [device](ALvoice::ChannelData &chandata) -> void + { + chandata.mDryParams = DirectParams{}; + std::fill_n(chandata.mWetParams.begin(), device->NumAuxSends, SendParams{}); + }; + std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, + clear_params); + + if(device->AvgSpeakerDist > 0.0f) + { + const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC / + (device->AvgSpeakerDist * device->Frequency)}; + auto init_nfc = [w1](ALvoice::ChannelData &chandata) -> void + { chandata.mDryParams.NFCtrlFilter.init(w1); }; + std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, + init_nfc); + } + + voice->mSourceID.store(source->id, std::memory_order_relaxed); + voice->mPlayState.store(ALvoice::Playing, std::memory_order_release); + source->state = AL_PLAYING; + source->VoiceIdx = vidx; + + SendStateChangeEvent(context.get(), source->id, AL_PLAYING); + }; + std::for_each(srchandles, srchandles+n, start_source); +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source) +START_API_FUNC +{ alSourcePausev(1, &source); } +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(n < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Pausing %d sources", n); + if(n == 0) return; + + al::vector extra_sources; + std::array source_storage; + ALsource **srchandles{source_storage.data()}; + if(UNLIKELY(static_cast(n) > source_storage.size())) + { + extra_sources.resize(n); + srchandles = extra_sources.data(); + } + + std::lock_guard _{context->SourceLock}; + for(ALsizei i{0};i < n;i++) + { + srchandles[i] = LookupSource(context.get(), sources[i]); + if(!srchandles[i]) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); + } + + ALCdevice *device{context->Device}; + BackendLockGuard __{*device->Backend}; + auto pause_source = [&context](ALsource *source) -> void + { + ALvoice *voice{GetSourceVoice(source, context.get())}; + if(voice) + { + std::atomic_thread_fence(std::memory_order_release); + ALvoice::State oldvstate{ALvoice::Playing}; + voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping, + std::memory_order_acq_rel, std::memory_order_acquire); + } + if(GetSourceState(source, voice) == AL_PLAYING) + { + source->state = AL_PAUSED; + SendStateChangeEvent(context.get(), source->id, AL_PAUSED); + } + }; + std::for_each(srchandles, srchandles+n, pause_source); +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source) +START_API_FUNC +{ alSourceStopv(1, &source); } +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(n < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Stopping %d sources", n); + if(n == 0) return; + + al::vector extra_sources; + std::array source_storage; + ALsource **srchandles{source_storage.data()}; + if(UNLIKELY(static_cast(n) > source_storage.size())) + { + extra_sources.resize(n); + srchandles = extra_sources.data(); + } + + std::lock_guard _{context->SourceLock}; + for(ALsizei i{0};i < n;i++) + { + srchandles[i] = LookupSource(context.get(), sources[i]); + if(!srchandles[i]) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); + } + + ALCdevice *device{context->Device}; + BackendLockGuard __{*device->Backend}; + auto stop_source = [&context](ALsource *source) -> void + { + ALvoice *voice{GetSourceVoice(source, context.get())}; + if(voice != nullptr) + { + voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed); + voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); + voice->mSourceID.store(0u, std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_release); + ALvoice::State oldvstate{ALvoice::Playing}; + voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping, + std::memory_order_acq_rel, std::memory_order_acquire); + voice = nullptr; + } + ALenum oldstate{GetSourceState(source, voice)}; + if(oldstate != AL_INITIAL && oldstate != AL_STOPPED) + { + source->state = AL_STOPPED; + SendStateChangeEvent(context.get(), source->id, AL_STOPPED); + } + source->OffsetType = AL_NONE; + source->Offset = 0.0; + }; + std::for_each(srchandles, srchandles+n, stop_source); +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source) +START_API_FUNC +{ alSourceRewindv(1, &source); } +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(n < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Rewinding %d sources", n); + if(n == 0) return; + + al::vector extra_sources; + std::array source_storage; + ALsource **srchandles{source_storage.data()}; + if(UNLIKELY(static_cast(n) > source_storage.size())) + { + extra_sources.resize(n); + srchandles = extra_sources.data(); + } + + std::lock_guard _{context->SourceLock}; + for(ALsizei i{0};i < n;i++) + { + srchandles[i] = LookupSource(context.get(), sources[i]); + if(!srchandles[i]) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); + } + + ALCdevice *device{context->Device}; + BackendLockGuard __{*device->Backend}; + auto rewind_source = [&context](ALsource *source) -> void + { + ALvoice *voice{GetSourceVoice(source, context.get())}; + if(voice != nullptr) + { + voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed); + voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); + voice->mSourceID.store(0u, std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_release); + ALvoice::State oldvstate{ALvoice::Playing}; + voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping, + std::memory_order_acq_rel, std::memory_order_acquire); + voice = nullptr; + } + if(GetSourceState(source, voice) != AL_INITIAL) + { + source->state = AL_INITIAL; + SendStateChangeEvent(context.get(), source->id, AL_INITIAL); + } + source->OffsetType = AL_NONE; + source->Offset = 0.0; + }; + std::for_each(srchandles, srchandles+n, rewind_source); +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(nb < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffers", nb); + if(nb == 0) return; + + std::lock_guard _{context->SourceLock}; + ALsource *source{LookupSource(context.get(),src)}; + if(UNLIKELY(!source)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); + + /* Can't queue on a Static Source */ + if(UNLIKELY(source->SourceType == AL_STATIC)) + SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src); + + /* Check for a valid Buffer, for its frequency and format */ + ALCdevice *device{context->Device}; + ALbuffer *BufferFmt{nullptr}; + ALbufferlistitem *BufferList{source->queue}; + while(BufferList) + { + for(ALsizei i{0};i < BufferList->num_buffers;i++) + { + if((BufferFmt=BufferList->buffers[i]) != nullptr) + break; + } + if(BufferFmt) break; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + + std::unique_lock buflock{device->BufferLock}; + ALbufferlistitem *BufferListStart{nullptr}; + BufferList = nullptr; + for(ALsizei i{0};i < nb;i++) + { + ALbuffer *buffer{nullptr}; + if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr) + { + alSetError(context.get(), AL_INVALID_NAME, "Queueing invalid buffer ID %u", + buffers[i]); + goto buffer_error; + } + + if(!BufferListStart) + { + BufferListStart = static_cast(al_calloc(alignof(void*), + ALbufferlistitem::Sizeof(1u))); + BufferList = BufferListStart; + } + else + { + auto item = static_cast(al_calloc(alignof(void*), + ALbufferlistitem::Sizeof(1u))); + BufferList->next.store(item, std::memory_order_relaxed); + BufferList = item; + } + BufferList->next.store(nullptr, std::memory_order_relaxed); + BufferList->max_samples = buffer ? buffer->SampleLen : 0; + BufferList->num_buffers = 1; + BufferList->buffers[0] = buffer; + if(!buffer) continue; + + IncrementRef(&buffer->ref); + + if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) + { + alSetError(context.get(), AL_INVALID_OPERATION, + "Queueing non-persistently mapped buffer %u", buffer->id); + goto buffer_error; + } + + if(BufferFmt == nullptr) + BufferFmt = buffer; + else if(BufferFmt->Frequency != buffer->Frequency || + BufferFmt->mFmtChannels != buffer->mFmtChannels || + BufferFmt->OriginalType != buffer->OriginalType) + { + alSetError(context.get(), AL_INVALID_OPERATION, + "Queueing buffer with mismatched format"); + + buffer_error: + /* A buffer failed (invalid ID or format), so unlock and release + * each buffer we had. */ + while(BufferListStart) + { + ALbufferlistitem *next = BufferListStart->next.load(std::memory_order_relaxed); + for(i = 0;i < BufferListStart->num_buffers;i++) + { + if((buffer=BufferListStart->buffers[i]) != nullptr) + DecrementRef(&buffer->ref); + } + al_free(BufferListStart); + BufferListStart = next; + } + return; + } + } + /* All buffers good. */ + buflock.unlock(); + + /* Source is now streaming */ + source->SourceType = AL_STREAMING; + + if(!(BufferList=source->queue)) + source->queue = BufferListStart; + else + { + ALbufferlistitem *next; + while((next=BufferList->next.load(std::memory_order_relaxed)) != nullptr) + BufferList = next; + BufferList->next.store(BufferListStart, std::memory_order_release); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(nb < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffer layers", nb); + if(nb == 0) return; + + std::lock_guard _{context->SourceLock}; + ALsource *source{LookupSource(context.get(),src)}; + if(UNLIKELY(!source)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); + + /* Can't queue on a Static Source */ + if(UNLIKELY(source->SourceType == AL_STATIC)) + SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src); + + /* Check for a valid Buffer, for its frequency and format */ + ALCdevice *device{context->Device}; + ALbuffer *BufferFmt{nullptr}; + ALbufferlistitem *BufferList{source->queue}; + while(BufferList) + { + for(ALsizei i{0};i < BufferList->num_buffers;i++) + { + if((BufferFmt=BufferList->buffers[i]) != nullptr) + break; + } + if(BufferFmt) break; + BufferList = BufferList->next.load(std::memory_order_relaxed); + } + + std::unique_lock buflock{device->BufferLock}; + auto BufferListStart = static_cast(al_calloc(alignof(void*), + ALbufferlistitem::Sizeof(nb))); + BufferList = BufferListStart; + BufferList->next.store(nullptr, std::memory_order_relaxed); + BufferList->max_samples = 0; + BufferList->num_buffers = 0; + + for(ALsizei i{0};i < nb;i++) + { + ALbuffer *buffer{nullptr}; + if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr) + { + alSetError(context.get(), AL_INVALID_NAME, "Queueing invalid buffer ID %u", + buffers[i]); + goto buffer_error; + } + + BufferList->buffers[BufferList->num_buffers++] = buffer; + if(!buffer) continue; + + IncrementRef(&buffer->ref); + + BufferList->max_samples = maxi(BufferList->max_samples, buffer->SampleLen); + + if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) + { + alSetError(context.get(), AL_INVALID_OPERATION, + "Queueing non-persistently mapped buffer %u", buffer->id); + goto buffer_error; + } + + if(BufferFmt == nullptr) + BufferFmt = buffer; + else if(BufferFmt->Frequency != buffer->Frequency || + BufferFmt->mFmtChannels != buffer->mFmtChannels || + BufferFmt->OriginalType != buffer->OriginalType) + { + alSetError(context.get(), AL_INVALID_OPERATION, + "Queueing buffer with mismatched format"); + + buffer_error: + /* A buffer failed (invalid ID or format), so unlock and release + * each buffer we had. */ + while(BufferListStart) + { + ALbufferlistitem *next{BufferListStart->next.load(std::memory_order_relaxed)}; + for(i = 0;i < BufferListStart->num_buffers;i++) + { + if((buffer=BufferListStart->buffers[i]) != nullptr) + DecrementRef(&buffer->ref); + } + al_free(BufferListStart); + BufferListStart = next; + } + return; + } + } + /* All buffers good. */ + buflock.unlock(); + + /* Source is now streaming */ + source->SourceType = AL_STREAMING; + + if(!(BufferList=source->queue)) + source->queue = BufferListStart; + else + { + ALbufferlistitem *next; + while((next=BufferList->next.load(std::memory_order_relaxed)) != nullptr) + BufferList = next; + BufferList->next.store(BufferListStart, std::memory_order_release); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(nb < 0) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing %d buffers", nb); + if(nb == 0) return; + + std::lock_guard _{context->SourceLock}; + ALsource *source{LookupSource(context.get(),src)}; + if(UNLIKELY(!source)) + SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); + + if(UNLIKELY(source->Looping)) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing from looping source %u", src); + if(UNLIKELY(source->SourceType != AL_STREAMING)) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, + "Unqueueing from a non-streaming source %u", src); + + /* Make sure enough buffers have been processed to unqueue. */ + ALbufferlistitem *BufferList{source->queue}; + ALvoice *voice{GetSourceVoice(source, context.get())}; + ALbufferlistitem *Current{nullptr}; + if(voice) + Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); + else if(source->state == AL_INITIAL) + Current = BufferList; + if(UNLIKELY(BufferList == Current)) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing pending buffers"); + + ALsizei i{BufferList->num_buffers}; + while(i < nb) + { + /* If the next bufferlist to check is NULL or is the current one, it's + * trying to unqueue pending buffers. + */ + ALbufferlistitem *next{BufferList->next.load(std::memory_order_relaxed)}; + if(UNLIKELY(!next) || UNLIKELY(next == Current)) + SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing pending buffers"); + BufferList = next; + + i += BufferList->num_buffers; + } + + while(nb > 0) + { + ALbufferlistitem *head{source->queue}; + ALbufferlistitem *next{head->next.load(std::memory_order_relaxed)}; + for(i = 0;i < head->num_buffers && nb > 0;i++,nb--) + { + ALbuffer *buffer{head->buffers[i]}; + if(!buffer) + *(buffers++) = 0; + else + { + *(buffers++) = buffer->id; + DecrementRef(&buffer->ref); + } + } + if(i < head->num_buffers) + { + /* This head has some buffers left over, so move them to the front + * and update the sample and buffer count. + */ + ALsizei max_length{0}; + ALsizei j{0}; + while(i < head->num_buffers) + { + ALbuffer *buffer{head->buffers[i++]}; + if(buffer) max_length = maxi(max_length, buffer->SampleLen); + head->buffers[j++] = buffer; + } + head->max_samples = max_length; + head->num_buffers = j; + break; + } + + /* Otherwise, free this item and set the source queue head to the next + * one. + */ + al_free(head); + source->queue = next; + } +} +END_API_FUNC + + +ALsource::ALsource(ALsizei num_sends) +{ + InnerAngle = 360.0f; + OuterAngle = 360.0f; + Pitch = 1.0f; + Position[0] = 0.0f; + Position[1] = 0.0f; + Position[2] = 0.0f; + Velocity[0] = 0.0f; + Velocity[1] = 0.0f; + Velocity[2] = 0.0f; + Direction[0] = 0.0f; + Direction[1] = 0.0f; + Direction[2] = 0.0f; + OrientAt[0] = 0.0f; + OrientAt[1] = 0.0f; + OrientAt[2] = -1.0f; + OrientUp[0] = 0.0f; + OrientUp[1] = 1.0f; + OrientUp[2] = 0.0f; + RefDistance = 1.0f; + MaxDistance = std::numeric_limits::max(); + RolloffFactor = 1.0f; + Gain = 1.0f; + MinGain = 0.0f; + MaxGain = 1.0f; + OuterGain = 0.0f; + OuterGainHF = 1.0f; + + DryGainHFAuto = AL_TRUE; + WetGainAuto = AL_TRUE; + WetGainHFAuto = AL_TRUE; + AirAbsorptionFactor = 0.0f; + RoomRolloffFactor = 0.0f; + DopplerFactor = 1.0f; + HeadRelative = AL_FALSE; + Looping = AL_FALSE; + mDistanceModel = DistanceModel::Default; + mResampler = ResamplerDefault; + DirectChannels = AL_FALSE; + mSpatialize = SpatializeAuto; + + StereoPan[0] = Deg2Rad( 30.0f); + StereoPan[1] = Deg2Rad(-30.0f); + + Radius = 0.0f; + + Direct.Gain = 1.0f; + Direct.GainHF = 1.0f; + Direct.HFReference = LOWPASSFREQREF; + Direct.GainLF = 1.0f; + Direct.LFReference = HIGHPASSFREQREF; + Send.resize(num_sends); + for(auto &send : Send) + { + send.Slot = nullptr; + send.Gain = 1.0f; + send.GainHF = 1.0f; + send.HFReference = LOWPASSFREQREF; + send.GainLF = 1.0f; + send.LFReference = HIGHPASSFREQREF; + } + + Offset = 0.0; + OffsetType = AL_NONE; + SourceType = AL_UNDETERMINED; + state = AL_INITIAL; + + queue = nullptr; + + PropsClean.test_and_set(std::memory_order_relaxed); + + VoiceIdx = -1; +} + +ALsource::~ALsource() +{ + ALbufferlistitem *BufferList{queue}; + while(BufferList != nullptr) + { + ALbufferlistitem *next{BufferList->next.load(std::memory_order_relaxed)}; + for(ALsizei i{0};i < BufferList->num_buffers;i++) + { + if(BufferList->buffers[i]) + DecrementRef(&BufferList->buffers[i]->ref); + } + al_free(BufferList); + BufferList = next; + } + queue = nullptr; + + std::for_each(Send.begin(), Send.end(), + [](ALsource::SendData &send) -> void + { + if(send.Slot) + DecrementRef(&send.Slot->ref); + send.Slot = nullptr; + } + ); +} + +void UpdateAllSourceProps(ALCcontext *context) +{ + auto voices_end = context->Voices->begin() + + context->VoiceCount.load(std::memory_order_relaxed); + std::for_each(context->Voices->begin(), voices_end, + [context](ALvoice &voice) -> void + { + ALuint sid{voice.mSourceID.load(std::memory_order_acquire)}; + ALsource *source = sid ? LookupSource(context, sid) : nullptr; + if(source && !source->PropsClean.test_and_set(std::memory_order_acq_rel)) + UpdateSourceProps(source, &voice, context); + } + ); +} + +SourceSubList::~SourceSubList() +{ + uint64_t usemask{~FreeMask}; + while(usemask) + { + ALsizei idx{CTZ64(usemask)}; + al::destroy_at(Sources+idx); + usemask &= ~(1_u64 << idx); + } + FreeMask = ~usemask; + al_free(Sources); + Sources = nullptr; +} diff --git a/al/source.h b/al/source.h new file mode 100644 index 00000000..c9892398 --- /dev/null +++ b/al/source.h @@ -0,0 +1,131 @@ +#ifndef AL_SOURCE_H +#define AL_SOURCE_H + +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" + +#include "alcontext.h" +#include "alnumeric.h" +#include "alu.h" +#include "vector.h" + +struct ALbuffer; +struct ALeffectslot; + + +#define DEFAULT_SENDS 2 + + +struct ALbufferlistitem { + std::atomic next; + ALsizei max_samples; + ALsizei num_buffers; + ALbuffer *buffers[]; + + static constexpr size_t Sizeof(size_t num_buffers) noexcept + { + return maxz(offsetof(ALbufferlistitem, buffers) + sizeof(ALbuffer*)*num_buffers, + sizeof(ALbufferlistitem)); + } +}; + + +struct ALsource { + /** Source properties. */ + ALfloat Pitch; + ALfloat Gain; + ALfloat OuterGain; + ALfloat MinGain; + ALfloat MaxGain; + ALfloat InnerAngle; + ALfloat OuterAngle; + ALfloat RefDistance; + ALfloat MaxDistance; + ALfloat RolloffFactor; + std::array Position; + std::array Velocity; + std::array Direction; + std::array OrientAt; + std::array OrientUp; + ALboolean HeadRelative; + ALboolean Looping; + DistanceModel mDistanceModel; + Resampler mResampler; + ALboolean DirectChannels; + SpatializeMode mSpatialize; + + ALboolean DryGainHFAuto; + ALboolean WetGainAuto; + ALboolean WetGainHFAuto; + ALfloat OuterGainHF; + + ALfloat AirAbsorptionFactor; + ALfloat RoomRolloffFactor; + ALfloat DopplerFactor; + + /* NOTE: Stereo pan angles are specified in radians, counter-clockwise + * rather than clockwise. + */ + std::array StereoPan; + + ALfloat Radius; + + /** Direct filter and auxiliary send info. */ + struct { + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; + } Direct; + struct SendData { + ALeffectslot *Slot; + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; + }; + al::vector Send; + + /** + * Last user-specified offset, and the offset type (bytes, samples, or + * seconds). + */ + ALdouble Offset; + ALenum OffsetType; + + /** Source type (static, streaming, or undetermined) */ + ALint SourceType; + + /** Source state (initial, playing, paused, or stopped) */ + ALenum state; + + /** Source Buffer Queue head. */ + ALbufferlistitem *queue; + + std::atomic_flag PropsClean; + + /* Index into the context's Voices array. Lazily updated, only checked and + * reset when looking up the voice. + */ + ALint VoiceIdx; + + /** Self ID */ + ALuint id; + + + ALsource(ALsizei num_sends); + ~ALsource(); + + ALsource(const ALsource&) = delete; + ALsource& operator=(const ALsource&) = delete; +}; + +void UpdateAllSourceProps(ALCcontext *context); + +#endif diff --git a/al/state.cpp b/al/state.cpp new file mode 100644 index 00000000..cbb43685 --- /dev/null +++ b/al/state.cpp @@ -0,0 +1,859 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2000 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include "version.h" + +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" + +#include "alcontext.h" +#include "alexcpt.h" +#include "almalloc.h" +#include "alspan.h" +#include "alu.h" +#include "atomic.h" +#include "error.h" +#include "event.h" +#include "inprogext.h" +#include "opthelpers.h" + + +namespace { + +constexpr ALchar alVendor[] = "OpenAL Community"; +constexpr ALchar alVersion[] = "1.1 ALSOFT " ALSOFT_VERSION; +constexpr ALchar alRenderer[] = "OpenAL Soft"; + +// Error Messages +constexpr ALchar alNoError[] = "No Error"; +constexpr ALchar alErrInvalidName[] = "Invalid Name"; +constexpr ALchar alErrInvalidEnum[] = "Invalid Enum"; +constexpr ALchar alErrInvalidValue[] = "Invalid Value"; +constexpr ALchar alErrInvalidOp[] = "Invalid Operation"; +constexpr ALchar alErrOutOfMemory[] = "Out of Memory"; + +/* Resampler strings */ +constexpr ALchar alPointResampler[] = "Nearest"; +constexpr ALchar alLinearResampler[] = "Linear"; +constexpr ALchar alCubicResampler[] = "Cubic"; +constexpr ALchar alBSinc12Resampler[] = "11th order Sinc"; +constexpr ALchar alBSinc24Resampler[] = "23rd order Sinc"; + +} // namespace + +/* WARNING: Non-standard export! Not part of any extension, or exposed in the + * alcFunctions list. + */ +extern "C" AL_API const ALchar* AL_APIENTRY alsoft_get_version(void) +START_API_FUNC +{ + const char *spoof{getenv("ALSOFT_SPOOF_VERSION")}; + if(spoof && spoof[0] != '\0') return spoof; + return ALSOFT_VERSION; +} +END_API_FUNC + +#define DO_UPDATEPROPS() do { \ + if(!context->DeferUpdates.load(std::memory_order_acquire)) \ + UpdateContextProps(context.get()); \ + else \ + context->PropsClean.clear(std::memory_order_release); \ +} while(0) + + +AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + switch(capability) + { + case AL_SOURCE_DISTANCE_MODEL: + context->SourceDistanceModel = AL_TRUE; + DO_UPDATEPROPS(); + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + std::lock_guard _{context->PropLock}; + switch(capability) + { + case AL_SOURCE_DISTANCE_MODEL: + context->SourceDistanceModel = AL_FALSE; + DO_UPDATEPROPS(); + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability); + } +} +END_API_FUNC + +AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return AL_FALSE; + + std::lock_guard _{context->PropLock}; + ALboolean value{AL_FALSE}; + switch(capability) + { + case AL_SOURCE_DISTANCE_MODEL: + value = context->SourceDistanceModel; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability); + } + + return value; +} +END_API_FUNC + +AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return AL_FALSE; + + std::lock_guard _{context->PropLock}; + ALboolean value{AL_FALSE}; + switch(pname) + { + case AL_DOPPLER_FACTOR: + if(context->DopplerFactor != 0.0f) + value = AL_TRUE; + break; + + case AL_DOPPLER_VELOCITY: + if(context->DopplerVelocity != 0.0f) + value = AL_TRUE; + break; + + case AL_DISTANCE_MODEL: + if(context->mDistanceModel == DistanceModel::Default) + value = AL_TRUE; + break; + + case AL_SPEED_OF_SOUND: + if(context->SpeedOfSound != 0.0f) + value = AL_TRUE; + break; + + case AL_DEFERRED_UPDATES_SOFT: + if(context->DeferUpdates.load(std::memory_order_acquire)) + value = AL_TRUE; + break; + + case AL_GAIN_LIMIT_SOFT: + if(GAIN_MIX_MAX/context->GainBoost != 0.0f) + value = AL_TRUE; + break; + + case AL_NUM_RESAMPLERS_SOFT: + /* Always non-0. */ + value = AL_TRUE; + break; + + case AL_DEFAULT_RESAMPLER_SOFT: + value = ResamplerDefault ? AL_TRUE : AL_FALSE; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid boolean property 0x%04x", pname); + } + + return value; +} +END_API_FUNC + +AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return 0.0; + + std::lock_guard _{context->PropLock}; + ALdouble value{0.0}; + switch(pname) + { + case AL_DOPPLER_FACTOR: + value = static_cast(context->DopplerFactor); + break; + + case AL_DOPPLER_VELOCITY: + value = static_cast(context->DopplerVelocity); + break; + + case AL_DISTANCE_MODEL: + value = static_cast(context->mDistanceModel); + break; + + case AL_SPEED_OF_SOUND: + value = static_cast(context->SpeedOfSound); + break; + + case AL_DEFERRED_UPDATES_SOFT: + if(context->DeferUpdates.load(std::memory_order_acquire)) + value = static_cast(AL_TRUE); + break; + + case AL_GAIN_LIMIT_SOFT: + value = static_castGAIN_MIX_MAX/context->GainBoost; + break; + + case AL_NUM_RESAMPLERS_SOFT: + value = static_cast(ResamplerMax + 1); + break; + + case AL_DEFAULT_RESAMPLER_SOFT: + value = static_cast(ResamplerDefault); + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid double property 0x%04x", pname); + } + + return value; +} +END_API_FUNC + +AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return 0.0f; + + std::lock_guard _{context->PropLock}; + ALfloat value{0.0f}; + switch(pname) + { + case AL_DOPPLER_FACTOR: + value = context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + value = context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + value = static_cast(context->mDistanceModel); + break; + + case AL_SPEED_OF_SOUND: + value = context->SpeedOfSound; + break; + + case AL_DEFERRED_UPDATES_SOFT: + if(context->DeferUpdates.load(std::memory_order_acquire)) + value = static_cast(AL_TRUE); + break; + + case AL_GAIN_LIMIT_SOFT: + value = GAIN_MIX_MAX/context->GainBoost; + break; + + case AL_NUM_RESAMPLERS_SOFT: + value = static_cast(ResamplerMax + 1); + break; + + case AL_DEFAULT_RESAMPLER_SOFT: + value = static_cast(ResamplerDefault); + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid float property 0x%04x", pname); + } + + return value; +} +END_API_FUNC + +AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return 0; + + std::lock_guard _{context->PropLock}; + ALint value{0}; + switch(pname) + { + case AL_DOPPLER_FACTOR: + value = static_cast(context->DopplerFactor); + break; + + case AL_DOPPLER_VELOCITY: + value = static_cast(context->DopplerVelocity); + break; + + case AL_DISTANCE_MODEL: + value = static_cast(context->mDistanceModel); + break; + + case AL_SPEED_OF_SOUND: + value = static_cast(context->SpeedOfSound); + break; + + case AL_DEFERRED_UPDATES_SOFT: + if(context->DeferUpdates.load(std::memory_order_acquire)) + value = static_cast(AL_TRUE); + break; + + case AL_GAIN_LIMIT_SOFT: + value = static_cast(GAIN_MIX_MAX/context->GainBoost); + break; + + case AL_NUM_RESAMPLERS_SOFT: + value = ResamplerMax + 1; + break; + + case AL_DEFAULT_RESAMPLER_SOFT: + value = ResamplerDefault; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer property 0x%04x", pname); + } + + return value; +} +END_API_FUNC + +extern "C" AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return 0; + + std::lock_guard _{context->PropLock}; + ALint64SOFT value{0}; + switch(pname) + { + case AL_DOPPLER_FACTOR: + value = (ALint64SOFT)context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + value = (ALint64SOFT)context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + value = (ALint64SOFT)context->mDistanceModel; + break; + + case AL_SPEED_OF_SOUND: + value = (ALint64SOFT)context->SpeedOfSound; + break; + + case AL_DEFERRED_UPDATES_SOFT: + if(context->DeferUpdates.load(std::memory_order_acquire)) + value = (ALint64SOFT)AL_TRUE; + break; + + case AL_GAIN_LIMIT_SOFT: + value = (ALint64SOFT)(GAIN_MIX_MAX/context->GainBoost); + break; + + case AL_NUM_RESAMPLERS_SOFT: + value = (ALint64SOFT)(ResamplerMax + 1); + break; + + case AL_DEFAULT_RESAMPLER_SOFT: + value = (ALint64SOFT)ResamplerDefault; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer64 property 0x%04x", pname); + } + + return value; +} +END_API_FUNC + +AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return nullptr; + + std::lock_guard _{context->PropLock}; + void *value{nullptr}; + switch(pname) + { + case AL_EVENT_CALLBACK_FUNCTION_SOFT: + value = reinterpret_cast(context->EventCb); + break; + + case AL_EVENT_CALLBACK_USER_PARAM_SOFT: + value = context->EventParam; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname); + } + + return value; +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values) +START_API_FUNC +{ + if(values) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + case AL_DOPPLER_VELOCITY: + case AL_DISTANCE_MODEL: + case AL_SPEED_OF_SOUND: + case AL_DEFERRED_UPDATES_SOFT: + case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: + values[0] = alGetBoolean(pname); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(pname) + { + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid boolean-vector property 0x%04x", pname); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values) +START_API_FUNC +{ + if(values) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + case AL_DOPPLER_VELOCITY: + case AL_DISTANCE_MODEL: + case AL_SPEED_OF_SOUND: + case AL_DEFERRED_UPDATES_SOFT: + case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: + values[0] = alGetDouble(pname); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(pname) + { + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid double-vector property 0x%04x", pname); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values) +START_API_FUNC +{ + if(values) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + case AL_DOPPLER_VELOCITY: + case AL_DISTANCE_MODEL: + case AL_SPEED_OF_SOUND: + case AL_DEFERRED_UPDATES_SOFT: + case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: + values[0] = alGetFloat(pname); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(pname) + { + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid float-vector property 0x%04x", pname); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values) +START_API_FUNC +{ + if(values) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + case AL_DOPPLER_VELOCITY: + case AL_DISTANCE_MODEL: + case AL_SPEED_OF_SOUND: + case AL_DEFERRED_UPDATES_SOFT: + case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: + values[0] = alGetInteger(pname); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(pname) + { + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer-vector property 0x%04x", pname); + } +} +END_API_FUNC + +extern "C" AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values) +START_API_FUNC +{ + if(values) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + case AL_DOPPLER_VELOCITY: + case AL_DISTANCE_MODEL: + case AL_SPEED_OF_SOUND: + case AL_DEFERRED_UPDATES_SOFT: + case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: + values[0] = alGetInteger64SOFT(pname); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(pname) + { + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer64-vector property 0x%04x", pname); + } +} +END_API_FUNC + +AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values) +START_API_FUNC +{ + if(values) + { + switch(pname) + { + case AL_EVENT_CALLBACK_FUNCTION_SOFT: + case AL_EVENT_CALLBACK_USER_PARAM_SOFT: + values[0] = alGetPointerSOFT(pname); + return; + } + } + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!values) + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + else switch(pname) + { + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid pointer-vector property 0x%04x", pname); + } +} +END_API_FUNC + +AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return nullptr; + + const ALchar *value{nullptr}; + switch(pname) + { + case AL_VENDOR: + value = alVendor; + break; + + case AL_VERSION: + value = alVersion; + break; + + case AL_RENDERER: + value = alRenderer; + break; + + case AL_EXTENSIONS: + value = context->ExtensionList; + break; + + case AL_NO_ERROR: + value = alNoError; + break; + + case AL_INVALID_NAME: + value = alErrInvalidName; + break; + + case AL_INVALID_ENUM: + value = alErrInvalidEnum; + break; + + case AL_INVALID_VALUE: + value = alErrInvalidValue; + break; + + case AL_INVALID_OPERATION: + value = alErrInvalidOp; + break; + + case AL_OUT_OF_MEMORY: + value = alErrOutOfMemory; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid string property 0x%04x", pname); + } + return value; +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!(value >= 0.0f && std::isfinite(value))) + alSetError(context.get(), AL_INVALID_VALUE, "Doppler factor %f out of range", value); + else + { + std::lock_guard _{context->PropLock}; + context->DopplerFactor = value; + DO_UPDATEPROPS(); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if((context->EnabledEvts.load(std::memory_order_relaxed)&EventType_Deprecated)) + { + static constexpr ALCchar msg[] = + "alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound"; + const ALsizei msglen = static_cast(strlen(msg)); + std::lock_guard _{context->EventCbLock}; + ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; + if((enabledevts&EventType_Deprecated) && context->EventCb) + (*context->EventCb)(AL_EVENT_TYPE_DEPRECATED_SOFT, 0, 0, msglen, msg, + context->EventParam); + } + + if(!(value >= 0.0f && std::isfinite(value))) + alSetError(context.get(), AL_INVALID_VALUE, "Doppler velocity %f out of range", value); + else + { + std::lock_guard _{context->PropLock}; + context->DopplerVelocity = value; + DO_UPDATEPROPS(); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!(value > 0.0f && std::isfinite(value))) + alSetError(context.get(), AL_INVALID_VALUE, "Speed of sound %f out of range", value); + else + { + std::lock_guard _{context->PropLock}; + context->SpeedOfSound = value; + DO_UPDATEPROPS(); + } +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + if(!(value == AL_INVERSE_DISTANCE || value == AL_INVERSE_DISTANCE_CLAMPED || + value == AL_LINEAR_DISTANCE || value == AL_LINEAR_DISTANCE_CLAMPED || + value == AL_EXPONENT_DISTANCE || value == AL_EXPONENT_DISTANCE_CLAMPED || + value == AL_NONE)) + alSetError(context.get(), AL_INVALID_VALUE, "Distance model 0x%04x out of range", value); + else + { + std::lock_guard _{context->PropLock}; + context->mDistanceModel = static_cast(value); + if(!context->SourceDistanceModel) + DO_UPDATEPROPS(); + } +} +END_API_FUNC + + +AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCcontext_DeferUpdates(context.get()); +} +END_API_FUNC + +AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void) +START_API_FUNC +{ + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCcontext_ProcessUpdates(context.get()); +} +END_API_FUNC + + +AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index) +START_API_FUNC +{ + const char *ResamplerNames[] = { + alPointResampler, alLinearResampler, + alCubicResampler, alBSinc12Resampler, + alBSinc24Resampler, + }; + static_assert(al::size(ResamplerNames) == ResamplerMax+1, "Incorrect ResamplerNames list"); + + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return nullptr; + + const ALchar *value{nullptr}; + switch(pname) + { + case AL_RESAMPLER_NAME_SOFT: + if(index < 0 || static_cast(index) >= al::size(ResamplerNames)) + alSetError(context.get(), AL_INVALID_VALUE, "Resampler name index %d out of range", + index); + else + value = ResamplerNames[index]; + break; + + default: + alSetError(context.get(), AL_INVALID_VALUE, "Invalid string indexed property"); + } + return value; +} +END_API_FUNC + + +void UpdateContextProps(ALCcontext *context) +{ + /* Get an unused proprty container, or allocate a new one as needed. */ + ALcontextProps *props{context->FreeContextProps.load(std::memory_order_acquire)}; + if(!props) + props = static_cast(al_calloc(16, sizeof(*props))); + else + { + ALcontextProps *next; + do { + next = props->next.load(std::memory_order_relaxed); + } while(context->FreeContextProps.compare_exchange_weak(props, next, + std::memory_order_seq_cst, std::memory_order_acquire) == 0); + } + + /* Copy in current property values. */ + props->MetersPerUnit = context->MetersPerUnit; + + props->DopplerFactor = context->DopplerFactor; + props->DopplerVelocity = context->DopplerVelocity; + props->SpeedOfSound = context->SpeedOfSound; + + props->SourceDistanceModel = context->SourceDistanceModel; + props->mDistanceModel = context->mDistanceModel; + + /* Set the new container for updating internal parameters. */ + props = context->Update.exchange(props, std::memory_order_acq_rel); + if(props) + { + /* If there was an unused update container, put it back in the + * freelist. + */ + AtomicReplaceHead(context->FreeContextProps, props); + } +} diff --git a/alc/alc.cpp b/alc/alc.cpp index de0038a2..538bea9f 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -51,13 +51,14 @@ #include "AL/alext.h" #include "AL/efx.h" -#include "alAuxEffectSlot.h" +#include "al/auxeffectslot.h" +#include "al/effect.h" +#include "al/error.h" +#include "al/event.h" +#include "al/filter.h" +#include "al/listener.h" +#include "al/source.h" #include "alcmain.h" -#include "alEffect.h" -#include "alError.h" -#include "alFilter.h" -#include "alListener.h" -#include "alSource.h" #include "albyte.h" #include "alconfig.h" #include "alcontext.h" @@ -74,7 +75,6 @@ #include "compat.h" #include "cpu_caps.h" #include "effects/base.h" -#include "event.h" #include "filters/nfc.h" #include "filters/splitter.h" #include "fpu_modes.h" diff --git a/alc/alcontext.h b/alc/alcontext.h index cf956079..a2da77b0 100644 --- a/alc/alcontext.h +++ b/alc/alcontext.h @@ -17,7 +17,7 @@ #include "almalloc.h" #include "alnumeric.h" -#include "alListener.h" +#include "al/listener.h" #include "alu.h" diff --git a/alc/alu.cpp b/alc/alu.cpp index 31689997..b2e1effa 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -45,11 +45,12 @@ #include "AL/alc.h" #include "AL/efx.h" -#include "alAuxEffectSlot.h" -#include "alBuffer.h" +#include "al/auxeffectslot.h" +#include "al/buffer.h" +#include "al/effect.h" +#include "al/event.h" +#include "al/listener.h" #include "alcmain.h" -#include "alEffect.h" -#include "alListener.h" #include "alcontext.h" #include "almalloc.h" #include "alnumeric.h" @@ -60,7 +61,6 @@ #include "bs2b.h" #include "cpu_caps.h" #include "effects/base.h" -#include "event.h" #include "filters/biquad.h" #include "filters/nfc.h" #include "filters/splitter.h" diff --git a/alc/alu.h b/alc/alu.h index ef88bdf6..88c22e6f 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -10,7 +10,7 @@ #include "AL/alc.h" #include "AL/alext.h" -#include "alBuffer.h" +#include "al/buffer.h" #include "alcmain.h" #include "almalloc.h" #include "alspan.h" diff --git a/alc/effects/autowah.cpp b/alc/effects/autowah.cpp index 96292636..298d5c96 100644 --- a/alc/effects/autowah.cpp +++ b/alc/effects/autowah.cpp @@ -25,10 +25,10 @@ #include +#include "al/auxeffectslot.h" +#include "al/error.h" #include "alcmain.h" #include "alcontext.h" -#include "alAuxEffectSlot.h" -#include "alError.h" #include "alu.h" #include "filters/biquad.h" #include "vecmat.h" diff --git a/alc/effects/chorus.cpp b/alc/effects/chorus.cpp index d475b57a..28514a9b 100644 --- a/alc/effects/chorus.cpp +++ b/alc/effects/chorus.cpp @@ -30,9 +30,9 @@ #include "AL/alc.h" #include "AL/efx.h" -#include "alAuxEffectSlot.h" +#include "al/auxeffectslot.h" +#include "al/error.h" #include "alcmain.h" -#include "alError.h" #include "alcontext.h" #include "almalloc.h" #include "alnumeric.h" diff --git a/alc/effects/compressor.cpp b/alc/effects/compressor.cpp index 4a487097..86e2e02b 100644 --- a/alc/effects/compressor.cpp +++ b/alc/effects/compressor.cpp @@ -22,11 +22,11 @@ #include +#include "al/auxeffectslot.h" +#include "al/error.h" #include "alcmain.h" #include "alcontext.h" #include "alu.h" -#include "alAuxEffectSlot.h" -#include "alError.h" #include "vecmat.h" diff --git a/alc/effects/dedicated.cpp b/alc/effects/dedicated.cpp index b31b3750..c05df772 100644 --- a/alc/effects/dedicated.cpp +++ b/alc/effects/dedicated.cpp @@ -24,10 +24,10 @@ #include #include +#include "al/auxeffectslot.h" +#include "al/error.h" #include "alcmain.h" #include "alcontext.h" -#include "alAuxEffectSlot.h" -#include "alError.h" #include "alu.h" diff --git a/alc/effects/distortion.cpp b/alc/effects/distortion.cpp index 59557395..a74575d4 100644 --- a/alc/effects/distortion.cpp +++ b/alc/effects/distortion.cpp @@ -25,10 +25,10 @@ #include +#include "al/auxeffectslot.h" +#include "al/error.h" #include "alcmain.h" #include "alcontext.h" -#include "alAuxEffectSlot.h" -#include "alError.h" #include "alu.h" #include "filters/biquad.h" diff --git a/alc/effects/echo.cpp b/alc/effects/echo.cpp index c10f2eb2..8e309cbb 100644 --- a/alc/effects/echo.cpp +++ b/alc/effects/echo.cpp @@ -25,11 +25,11 @@ #include +#include "al/auxeffectslot.h" +#include "al/error.h" +#include "al/filter.h" #include "alcmain.h" #include "alcontext.h" -#include "alFilter.h" -#include "alAuxEffectSlot.h" -#include "alError.h" #include "alu.h" #include "filters/biquad.h" #include "vector.h" diff --git a/alc/effects/equalizer.cpp b/alc/effects/equalizer.cpp index 69ab5021..0ae3a25f 100644 --- a/alc/effects/equalizer.cpp +++ b/alc/effects/equalizer.cpp @@ -26,10 +26,10 @@ #include #include +#include "al/auxeffectslot.h" +#include "al/error.h" #include "alcmain.h" #include "alcontext.h" -#include "alAuxEffectSlot.h" -#include "alError.h" #include "alu.h" #include "filters/biquad.h" #include "vecmat.h" diff --git a/alc/effects/fshifter.cpp b/alc/effects/fshifter.cpp index b47aa00e..b36c53a1 100644 --- a/alc/effects/fshifter.cpp +++ b/alc/effects/fshifter.cpp @@ -26,10 +26,10 @@ #include #include +#include "al/auxeffectslot.h" +#include "al/error.h" #include "alcmain.h" #include "alcontext.h" -#include "alAuxEffectSlot.h" -#include "alError.h" #include "alu.h" #include "alcomplex.h" diff --git a/alc/effects/modulator.cpp b/alc/effects/modulator.cpp index 086482d7..5f28e1da 100644 --- a/alc/effects/modulator.cpp +++ b/alc/effects/modulator.cpp @@ -26,10 +26,10 @@ #include #include +#include "al/auxeffectslot.h" +#include "al/error.h" #include "alcmain.h" #include "alcontext.h" -#include "alAuxEffectSlot.h" -#include "alError.h" #include "alu.h" #include "filters/biquad.h" #include "vecmat.h" diff --git a/alc/effects/null.cpp b/alc/effects/null.cpp index e55c8699..b4799077 100644 --- a/alc/effects/null.cpp +++ b/alc/effects/null.cpp @@ -5,10 +5,10 @@ #include "AL/al.h" #include "AL/alc.h" +#include "al/auxeffectslot.h" +#include "al/error.h" #include "alcmain.h" #include "alcontext.h" -#include "alAuxEffectSlot.h" -#include "alError.h" namespace { diff --git a/alc/effects/pshifter.cpp b/alc/effects/pshifter.cpp index 39d3cf1a..eac5894b 100644 --- a/alc/effects/pshifter.cpp +++ b/alc/effects/pshifter.cpp @@ -30,14 +30,13 @@ #include #include +#include "al/auxeffectslot.h" +#include "al/error.h" #include "alcmain.h" +#include "alcomplex.h" #include "alcontext.h" -#include "alAuxEffectSlot.h" -#include "alError.h" #include "alu.h" -#include "alcomplex.h" - namespace { diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index ac996b3f..82b04436 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -29,12 +29,12 @@ #include #include +#include "al/auxeffectslot.h" +#include "al/error.h" +#include "al/listener.h" #include "alcmain.h" #include "alcontext.h" #include "alu.h" -#include "alAuxEffectSlot.h" -#include "alListener.h" -#include "alError.h" #include "bformatdec.h" #include "filters/biquad.h" #include "vector.h" diff --git a/alc/effects/vmorpher.cpp b/alc/effects/vmorpher.cpp index eebba3f1..d1bf8587 100644 --- a/alc/effects/vmorpher.cpp +++ b/alc/effects/vmorpher.cpp @@ -25,10 +25,10 @@ #include #include +#include "al/auxeffectslot.h" +#include "al/error.h" #include "alcmain.h" #include "alcontext.h" -#include "alAuxEffectSlot.h" -#include "alError.h" #include "alu.h" namespace { diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index 47c4a6f4..3513cf2b 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -6,8 +6,7 @@ #include "alcmain.h" #include "alu.h" -#include "alSource.h" -#include "alAuxEffectSlot.h" + #include "defs.h" #include "hrtfbase.h" diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index b763fdbd..516dabac 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -9,8 +9,6 @@ #include "alcmain.h" #include "alu.h" -#include "alSource.h" -#include "alAuxEffectSlot.h" #include "defs.h" #include "hrtfbase.h" diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index aea04b15..0d7b2cee 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -39,9 +39,10 @@ #include "AL/al.h" #include "AL/alc.h" -#include "alBuffer.h" +#include "al/buffer.h" +#include "al/event.h" +#include "al/source.h" #include "alcmain.h" -#include "alSource.h" #include "albyte.h" #include "alconfig.h" #include "alcontext.h" @@ -50,7 +51,6 @@ #include "alspan.h" #include "alu.h" #include "cpu_caps.h" -#include "event.h" #include "filters/biquad.h" #include "filters/nfc.h" #include "filters/splitter.h" diff --git a/alc/panning.cpp b/alc/panning.cpp index 3a67e33a..fd1e29ce 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -32,8 +32,8 @@ #include #include +#include "al/auxeffectslot.h" #include "alcmain.h" -#include "alAuxEffectSlot.h" #include "alu.h" #include "alconfig.h" #include "ambdec.h" -- cgit v1.2.3 From 06e5454eb9cd0d61fca25de7079d0b036d34b037 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Jul 2019 19:40:03 -0700 Subject: Use Transposed Direct Form II for the BS2B filters --- alc/bs2b.cpp | 73 ++++++++++++++++++++++++++++-------------------------------- alc/bs2b.h | 7 +++--- 2 files changed, 37 insertions(+), 43 deletions(-) diff --git a/alc/bs2b.cpp b/alc/bs2b.cpp index 2d1b96aa..71249d4a 100644 --- a/alc/bs2b.cpp +++ b/alc/bs2b.cpp @@ -23,9 +23,9 @@ #include "config.h" -#include -#include #include +#include +#include #include "bs2b.h" #include "math_defs.h" @@ -35,7 +35,7 @@ static void init(struct bs2b *bs2b) { float Fc_lo, Fc_hi; - float G_lo, G_hi; + float G_lo, G_hi; float x, g; switch(bs2b->level) @@ -127,60 +127,55 @@ int bs2b_get_srate(struct bs2b *bs2b) void bs2b_clear(struct bs2b *bs2b) { - std::fill(std::begin(bs2b->last_sample), std::end(bs2b->last_sample), bs2b::t_last_sample{}); + std::fill(std::begin(bs2b->history), std::end(bs2b->history), bs2b::t_last_sample{}); } /* bs2b_clear */ -void bs2b_cross_feed(struct bs2b *bs2b, float *RESTRICT Left, float *RESTRICT Right, int SamplesToDo) +void bs2b_cross_feed(struct bs2b *bs2b, float *Left, float *Right, int SamplesToDo) { + const float a0_lo{bs2b->a0_lo}; + const float b1_lo{bs2b->b1_lo}; + const float a0_hi{bs2b->a0_hi}; + const float a1_hi{bs2b->a1_hi}; + const float b1_hi{bs2b->b1_hi}; float lsamples[128][2]; float rsamples[128][2]; - int base; - for(base = 0;base < SamplesToDo;) + for(int base{0};base < SamplesToDo;) { - int todo = std::min(128, SamplesToDo-base); - int i; + const int todo{std::min(128, SamplesToDo-base)}; /* Process left input */ - lsamples[0][0] = bs2b->a0_lo*Left[0] + - bs2b->b1_lo*bs2b->last_sample[0].lo; - lsamples[0][1] = bs2b->a0_hi*Left[0] + - bs2b->a1_hi*bs2b->last_sample[0].asis + - bs2b->b1_hi*bs2b->last_sample[0].hi; - for(i = 1;i < todo;i++) + float z_lo{bs2b->history[0].lo}; + float z_hi{bs2b->history[0].hi}; + for(int i{0};i < todo;i++) { - lsamples[i][0] = bs2b->a0_lo*Left[i] + - bs2b->b1_lo*lsamples[i-1][0]; - lsamples[i][1] = bs2b->a0_hi*Left[i] + - bs2b->a1_hi*Left[i-1] + - bs2b->b1_hi*lsamples[i-1][1]; + lsamples[i][0] = a0_lo*Left[i] + z_lo; + z_lo = b1_lo*lsamples[i][0]; + + lsamples[i][1] = a0_hi*Left[i] + z_hi; + z_hi = a1_hi*Left[i] + b1_hi*lsamples[i][1]; } - bs2b->last_sample[0].asis = Left[i-1]; - bs2b->last_sample[0].lo = lsamples[i-1][0]; - bs2b->last_sample[0].hi = lsamples[i-1][1]; + bs2b->history[0].lo = z_lo; + bs2b->history[0].hi = z_hi; /* Process right input */ - rsamples[0][0] = bs2b->a0_lo*Right[0] + - bs2b->b1_lo*bs2b->last_sample[1].lo; - rsamples[0][1] = bs2b->a0_hi*Right[0] + - bs2b->a1_hi*bs2b->last_sample[1].asis + - bs2b->b1_hi*bs2b->last_sample[1].hi; - for(i = 1;i < todo;i++) + z_lo = bs2b->history[1].lo; + z_hi = bs2b->history[1].hi; + for(int i{0};i < todo;i++) { - rsamples[i][0] = bs2b->a0_lo*Right[i] + - bs2b->b1_lo*rsamples[i-1][0]; - rsamples[i][1] = bs2b->a0_hi*Right[i] + - bs2b->a1_hi*Right[i-1] + - bs2b->b1_hi*rsamples[i-1][1]; + rsamples[i][0] = a0_lo*Right[i] + z_lo; + z_lo = b1_lo*rsamples[i][0]; + + rsamples[i][1] = a0_hi*Right[i] + z_hi; + z_hi = a1_hi*Right[i] + b1_hi*rsamples[i][1]; } - bs2b->last_sample[1].asis = Right[i-1]; - bs2b->last_sample[1].lo = rsamples[i-1][0]; - bs2b->last_sample[1].hi = rsamples[i-1][1]; + bs2b->history[1].lo = z_lo; + bs2b->history[1].hi = z_hi; /* Crossfeed */ - for(i = 0;i < todo;i++) + for(int i{0};i < todo;i++) *(Left++) = lsamples[i][1] + rsamples[i][0]; - for(i = 0;i < todo;i++) + for(int i{0};i < todo;i++) *(Right++) = rsamples[i][1] + lsamples[i][0]; base += todo; diff --git a/alc/bs2b.h b/alc/bs2b.h index e235e765..d9bcc172 100644 --- a/alc/bs2b.h +++ b/alc/bs2b.h @@ -57,14 +57,13 @@ struct bs2b { float a1_hi; float b1_hi; - /* Buffer of last filtered sample. + /* Buffer of filter history * [0] - first channel, [1] - second channel */ struct t_last_sample { - float asis; float lo; float hi; - } last_sample[2]; + } history[2]; DEF_NEWDEL(bs2b) }; @@ -85,6 +84,6 @@ int bs2b_get_srate(bs2b *bs2b); /* Clear buffer */ void bs2b_clear(bs2b *bs2b); -void bs2b_cross_feed(bs2b *bs2b, float *RESTRICT Left, float *RESTRICT Right, int SamplesToDo); +void bs2b_cross_feed(bs2b *bs2b, float *Left, float *Right, int SamplesToDo); #endif /* BS2B_H */ -- cgit v1.2.3 From 488d1de9444d2866644a9e926089043186e6232b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Jul 2019 19:59:48 -0700 Subject: More include cleanup --- alc/ambdec.cpp | 12 +++++------- alc/backends/base.cpp | 10 ++++++---- alc/backends/base.h | 6 ++++-- alc/effects/null.cpp | 7 ++++--- alc/filters/nfc.cpp | 2 +- alc/filters/splitter.cpp | 4 +++- alc/filters/splitter.h | 2 ++ 7 files changed, 25 insertions(+), 18 deletions(-) diff --git a/alc/ambdec.cpp b/alc/ambdec.cpp index 0991cfc5..fa29d268 100644 --- a/alc/ambdec.cpp +++ b/alc/ambdec.cpp @@ -3,17 +3,15 @@ #include "ambdec.h" -#include -#include #include - -#include -#include -#include +#include +#include +#include #include +#include -#include "logging.h" #include "compat.h" +#include "logging.h" namespace { diff --git a/alc/backends/base.cpp b/alc/backends/base.cpp index a7d47c6d..78b9196e 100644 --- a/alc/backends/base.cpp +++ b/alc/backends/base.cpp @@ -1,14 +1,16 @@ #include "config.h" -#include +#include "base.h" +#include #include -#include "alcmain.h" -#include "alu.h" +#include "AL/al.h" -#include "backends/base.h" +#include "alcmain.h" +#include "alnumeric.h" +#include "atomic.h" ClockLatency GetClockLatency(ALCdevice *device) diff --git a/alc/backends/base.h b/alc/backends/base.h index 437e31d9..5e294fe8 100644 --- a/alc/backends/base.h +++ b/alc/backends/base.h @@ -1,10 +1,12 @@ #ifndef ALC_BACKENDS_BASE_H #define ALC_BACKENDS_BASE_H -#include #include -#include +#include #include +#include + +#include "AL/alc.h" #include "alcmain.h" diff --git a/alc/effects/null.cpp b/alc/effects/null.cpp index b4799077..c4eebb3d 100644 --- a/alc/effects/null.cpp +++ b/alc/effects/null.cpp @@ -1,6 +1,5 @@ -#include "config.h" -#include +#include "config.h" #include "AL/al.h" #include "AL/alc.h" @@ -8,7 +7,9 @@ #include "al/auxeffectslot.h" #include "al/error.h" #include "alcmain.h" -#include "alcontext.h" +#include "almalloc.h" +#include "alspan.h" +#include "effects/base.h" namespace { diff --git a/alc/filters/nfc.cpp b/alc/filters/nfc.cpp index 1a567f2c..4e36bc66 100644 --- a/alc/filters/nfc.cpp +++ b/alc/filters/nfc.cpp @@ -5,7 +5,7 @@ #include -#include "alcmain.h" +#include "opthelpers.h" /* Near-field control filters are the basis for handling the near-field effect. diff --git a/alc/filters/splitter.cpp b/alc/filters/splitter.cpp index 09e7bfe8..7463d795 100644 --- a/alc/filters/splitter.cpp +++ b/alc/filters/splitter.cpp @@ -3,11 +3,13 @@ #include "splitter.h" +#include #include #include -#include #include "math_defs.h" +#include "opthelpers.h" + template void BandSplitterR::init(Real f0norm) diff --git a/alc/filters/splitter.h b/alc/filters/splitter.h index 927c4d17..d7b0240d 100644 --- a/alc/filters/splitter.h +++ b/alc/filters/splitter.h @@ -1,6 +1,8 @@ #ifndef FILTER_SPLITTER_H #define FILTER_SPLITTER_H +#include + #include "alcmain.h" #include "almalloc.h" -- cgit v1.2.3 From ea76e003e7f2063687ed662282d388078ecf385b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 Jul 2019 09:05:54 -0700 Subject: Properly prefix ALCcontext members --- al/auxeffectslot.cpp | 86 +++++++++---------- al/buffer.cpp | 40 ++++----- al/effect.cpp | 22 ++--- al/error.cpp | 16 ++-- al/event.cpp | 50 +++++------ al/extension.cpp | 2 +- al/filter.cpp | 22 ++--- al/listener.cpp | 58 ++++++------- al/source.cpp | 208 ++++++++++++++++++++++----------------------- al/state.cpp | 130 ++++++++++++++-------------- alc/alc.cpp | 158 +++++++++++++++++----------------- alc/alcontext.h | 76 ++++++++--------- alc/alu.cpp | 60 ++++++------- alc/effects/autowah.cpp | 2 +- alc/effects/chorus.cpp | 2 +- alc/effects/distortion.cpp | 2 +- alc/effects/echo.cpp | 2 +- alc/effects/equalizer.cpp | 2 +- alc/effects/fshifter.cpp | 2 +- alc/effects/modulator.cpp | 2 +- alc/effects/reverb.cpp | 4 +- alc/effects/vmorpher.cpp | 2 +- alc/mixvoice.cpp | 14 +-- 23 files changed, 481 insertions(+), 481 deletions(-) diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index 605923dd..880c970d 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -54,9 +54,9 @@ inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; - if(UNLIKELY(lidx >= context->EffectSlotList.size())) + if(UNLIKELY(lidx >= context->mEffectSlotList.size())) return nullptr; - EffectSlotSubList &sublist{context->EffectSlotList[lidx]}; + EffectSlotSubList &sublist{context->mEffectSlotList[lidx]}; if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) return nullptr; return sublist.EffectSlots + slidx; @@ -79,7 +79,7 @@ inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) noexcept void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) { if(count < 1) return; - ALeffectslotArray *curarray{context->ActiveAuxSlots.load(std::memory_order_acquire)}; + ALeffectslotArray *curarray{context->mActiveAuxSlots.load(std::memory_order_acquire)}; size_t newcount{curarray->size() + count}; /* Insert the new effect slots into the head of the array, followed by the @@ -114,8 +114,8 @@ void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *cont curarray = nullptr; } - curarray = context->ActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); - ALCdevice *device{context->Device}; + curarray = context->mActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); + ALCdevice *device{context->mDevice}; while((device->MixCount.load(std::memory_order_acquire)&1)) std::this_thread::yield(); delete curarray; @@ -124,7 +124,7 @@ void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *cont void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) { if(count < 1) return; - ALeffectslotArray *curarray{context->ActiveAuxSlots.load(std::memory_order_acquire)}; + ALeffectslotArray *curarray{context->mActiveAuxSlots.load(std::memory_order_acquire)}; /* Don't shrink the allocated array size since we don't know how many (if * any) of the effect slots to remove are in the array. @@ -150,8 +150,8 @@ void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *c curarray = nullptr; } - curarray = context->ActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); - ALCdevice *device{context->Device}; + curarray = context->mActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); + ALCdevice *device{context->mDevice}; while((device->MixCount.load(std::memory_order_acquire)&1)) std::this_thread::yield(); delete curarray; @@ -160,22 +160,22 @@ void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *c ALeffectslot *AllocEffectSlot(ALCcontext *context) { - ALCdevice *device{context->Device}; - std::lock_guard _{context->EffectSlotLock}; - if(context->NumEffectSlots >= device->AuxiliaryEffectSlotMax) + ALCdevice *device{context->mDevice}; + std::lock_guard _{context->mEffectSlotLock}; + if(context->mNumEffectSlots >= device->AuxiliaryEffectSlotMax) { alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u effect slot limit", device->AuxiliaryEffectSlotMax); return nullptr; } - auto sublist = std::find_if(context->EffectSlotList.begin(), context->EffectSlotList.end(), + auto sublist = std::find_if(context->mEffectSlotList.begin(), context->mEffectSlotList.end(), [](const EffectSlotSubList &entry) noexcept -> bool { return entry.FreeMask != 0; } ); - auto lidx = static_cast(std::distance(context->EffectSlotList.begin(), sublist)); + auto lidx = static_cast(std::distance(context->mEffectSlotList.begin(), sublist)); ALeffectslot *slot; ALsizei slidx; - if(LIKELY(sublist != context->EffectSlotList.end())) + if(LIKELY(sublist != context->mEffectSlotList.end())) { slidx = CTZ64(sublist->FreeMask); slot = sublist->EffectSlots + slidx; @@ -185,19 +185,19 @@ ALeffectslot *AllocEffectSlot(ALCcontext *context) /* Don't allocate so many list entries that the 32-bit ID could * overflow... */ - if(UNLIKELY(context->EffectSlotList.size() >= 1<<25)) + if(UNLIKELY(context->mEffectSlotList.size() >= 1<<25)) { alSetError(context, AL_OUT_OF_MEMORY, "Too many effect slots allocated"); return nullptr; } - context->EffectSlotList.emplace_back(); - sublist = context->EffectSlotList.end() - 1; + context->mEffectSlotList.emplace_back(); + sublist = context->mEffectSlotList.end() - 1; sublist->FreeMask = ~0_u64; sublist->EffectSlots = static_cast(al_calloc(16, sizeof(ALeffectslot)*64)); if(UNLIKELY(!sublist->EffectSlots)) { - context->EffectSlotList.pop_back(); + context->mEffectSlotList.pop_back(); alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect slot batch"); return nullptr; } @@ -219,7 +219,7 @@ ALeffectslot *AllocEffectSlot(ALCcontext *context) /* Add 1 to avoid source ID 0. */ slot->id = ((lidx<<6) | slidx) + 1; - context->NumEffectSlots += 1; + context->mNumEffectSlots += 1; sublist->FreeMask &= ~(1_u64 << slidx); return slot; @@ -233,13 +233,13 @@ void FreeEffectSlot(ALCcontext *context, ALeffectslot *slot) al::destroy_at(slot); - context->EffectSlotList[lidx].FreeMask |= 1_u64 << slidx; - context->NumEffectSlots--; + context->mEffectSlotList[lidx].FreeMask |= 1_u64 << slidx; + context->mNumEffectSlots--; } #define DO_UPDATEPROPS() do { \ - if(!context->DeferUpdates.load(std::memory_order_acquire)) \ + if(!context->mDeferUpdates.load(std::memory_order_acquire)) \ UpdateEffectSlotProps(slot, context.get()); \ else \ slot->PropsClean.clear(std::memory_order_release); \ @@ -295,7 +295,7 @@ START_API_FUNC std::copy(tempids.cbegin(), tempids.cend(), effectslots); } - std::unique_lock slotlock{context->EffectSlotLock}; + std::unique_lock slotlock{context->mEffectSlotLock}; AddActiveEffectSlots(effectslots, n, context.get()); } END_API_FUNC @@ -310,7 +310,7 @@ START_API_FUNC SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Deleting %d effect slots", n); if(n == 0) return; - std::lock_guard _{context->EffectSlotLock}; + std::lock_guard _{context->mEffectSlotLock}; auto effectslots_end = effectslots + n; auto bad_slot = std::find_if(effectslots, effectslots_end, [&context](ALuint id) -> bool @@ -350,7 +350,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(LIKELY(context)) { - std::lock_guard _{context->EffectSlotLock}; + std::lock_guard _{context->mEffectSlotLock}; if(LookupEffectSlot(context.get(), effectslot) != nullptr) return AL_TRUE; } @@ -365,8 +365,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->EffectSlotLock}; + std::lock_guard _{context->mPropLock}; + std::lock_guard __{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); @@ -377,7 +377,7 @@ START_API_FUNC switch(param) { case AL_EFFECTSLOT_EFFECT: - device = context->Device; + device = context->mDevice; { std::lock_guard ___{device->EffectLock}; ALeffect *effect{value ? LookupEffect(device, value) : nullptr}; @@ -453,7 +453,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->EffectSlotLock}; + std::lock_guard _{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); @@ -473,8 +473,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->EffectSlotLock}; + std::lock_guard _{context->mPropLock}; + std::lock_guard __{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); @@ -508,7 +508,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->EffectSlotLock}; + std::lock_guard _{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); @@ -529,7 +529,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->EffectSlotLock}; + std::lock_guard _{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); @@ -566,7 +566,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->EffectSlotLock}; + std::lock_guard _{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); @@ -586,7 +586,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->EffectSlotLock}; + std::lock_guard _{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); @@ -617,7 +617,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->EffectSlotLock}; + std::lock_guard _{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); @@ -647,7 +647,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect if(!State) return AL_OUT_OF_MEMORY; FPUCtl mixer_mode{}; - ALCdevice *Device{Context->Device}; + ALCdevice *Device{Context->mDevice}; std::unique_lock statelock{Device->StateLock}; State->mOutTarget = Device->Dry.Buffer; if(State->deviceUpdate(Device) == AL_FALSE) @@ -677,7 +677,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect EffectSlot->Effect.Props = effect->Props; /* Remove state references from old effect slot property updates. */ - ALeffectslotProps *props{Context->FreeEffectslotProps.load()}; + ALeffectslotProps *props{Context->mFreeEffectslotProps.load()}; while(props) { if(props->State) @@ -739,7 +739,7 @@ ALeffectslot::~ALeffectslot() void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) { /* Get an unused property container, or allocate a new one as needed. */ - ALeffectslotProps *props{context->FreeEffectslotProps.load(std::memory_order_relaxed)}; + ALeffectslotProps *props{context->mFreeEffectslotProps.load(std::memory_order_relaxed)}; if(!props) props = static_cast(al_calloc(16, sizeof(*props))); else @@ -747,7 +747,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) ALeffectslotProps *next; do { next = props->next.load(std::memory_order_relaxed); - } while(context->FreeEffectslotProps.compare_exchange_weak(props, next, + } while(context->mFreeEffectslotProps.compare_exchange_weak(props, next, std::memory_order_seq_cst, std::memory_order_acquire) == 0); } @@ -775,7 +775,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) if(props->State) props->State->DecRef(); props->State = nullptr; - AtomicReplaceHead(context->FreeEffectslotProps, props); + AtomicReplaceHead(context->mFreeEffectslotProps, props); } if(oldstate) @@ -784,8 +784,8 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) void UpdateAllEffectSlotProps(ALCcontext *context) { - std::lock_guard _{context->EffectSlotLock}; - ALeffectslotArray *auxslots{context->ActiveAuxSlots.load(std::memory_order_acquire)}; + std::lock_guard _{context->mEffectSlotLock}; + ALeffectslotArray *auxslots{context->mActiveAuxSlots.load(std::memory_order_acquire)}; for(ALeffectslot *slot : *auxslots) { if(!slot->PropsClean.test_and_set(std::memory_order_acq_rel)) diff --git a/al/buffer.cpp b/al/buffer.cpp index 8b9c67e0..d4f2d179 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -247,7 +247,7 @@ constexpr ALbitfieldSOFT INVALID_MAP_FLAGS{~unsigned(AL_MAP_READ_BIT_SOFT | AL_M ALbuffer *AllocBuffer(ALCcontext *context) { - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->BufferLock}; auto sublist = std::find_if(device->BufferList.begin(), device->BufferList.end(), [](const BufferSubList &entry) noexcept -> bool @@ -657,7 +657,7 @@ START_API_FUNC if(UNLIKELY(n == 0)) return; - ALCdevice *device = context->Device; + ALCdevice *device = context->mDevice; std::lock_guard _{device->BufferLock}; /* First try to find any buffers that are invalid or in-use. */ @@ -700,7 +700,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(LIKELY(context)) { - ALCdevice *device = context->Device; + ALCdevice *device = context->mDevice; std::lock_guard _{device->BufferLock}; if(!buffer || LookupBuffer(device, buffer)) return AL_TRUE; @@ -721,7 +721,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->Device; + ALCdevice *device = context->mDevice; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); @@ -755,7 +755,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return nullptr; - ALCdevice *device = context->Device; + ALCdevice *device = context->mDevice; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); @@ -807,7 +807,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->Device; + ALCdevice *device = context->mDevice; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); @@ -830,7 +830,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->Device; + ALCdevice *device = context->mDevice; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); @@ -862,7 +862,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->Device; + ALCdevice *device = context->mDevice; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); @@ -992,7 +992,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->Device; + ALCdevice *device = context->mDevice; std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) @@ -1012,7 +1012,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->Device; + ALCdevice *device = context->mDevice; std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) @@ -1031,7 +1031,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->Device; + ALCdevice *device = context->mDevice; std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) @@ -1053,7 +1053,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->Device; + ALCdevice *device = context->mDevice; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); @@ -1088,7 +1088,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->Device; + ALCdevice *device = context->mDevice; std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) @@ -1118,7 +1118,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->Device; + ALCdevice *device = context->mDevice; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); @@ -1156,7 +1156,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->Device; + ALCdevice *device = context->mDevice; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); @@ -1178,7 +1178,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->Device; + ALCdevice *device = context->mDevice; std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) @@ -1206,7 +1206,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->Device; + ALCdevice *device = context->mDevice; std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) @@ -1228,7 +1228,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->Device; + ALCdevice *device = context->mDevice; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) @@ -1273,7 +1273,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->Device; + ALCdevice *device = context->mDevice; std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); @@ -1308,7 +1308,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->Device; + ALCdevice *device = context->mDevice; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) diff --git a/al/effect.cpp b/al/effect.cpp index b6cd5463..b6291129 100644 --- a/al/effect.cpp +++ b/al/effect.cpp @@ -139,7 +139,7 @@ void InitEffectParams(ALeffect *effect, ALenum type) ALeffect *AllocEffect(ALCcontext *context) { - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->EffectLock}; auto sublist = std::find_if(device->EffectList.begin(), device->EffectList.end(), [](const EffectSubList &entry) noexcept -> bool @@ -270,7 +270,7 @@ START_API_FUNC if(UNLIKELY(n == 0)) return; - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->EffectLock}; /* First try to find any effects that are invalid. */ @@ -308,7 +308,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(LIKELY(context)) { - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->EffectLock}; if(!effect || LookupEffect(device, effect)) return AL_TRUE; @@ -323,7 +323,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->EffectLock}; ALeffect *aleffect{LookupEffect(device, effect)}; @@ -373,7 +373,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->EffectLock}; ALeffect *aleffect{LookupEffect(device, effect)}; @@ -393,7 +393,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->EffectLock}; ALeffect *aleffect{LookupEffect(device, effect)}; @@ -413,7 +413,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->EffectLock}; ALeffect *aleffect{LookupEffect(device, effect)}; @@ -433,7 +433,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->EffectLock}; const ALeffect *aleffect{LookupEffect(device, effect)}; @@ -465,7 +465,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->EffectLock}; const ALeffect *aleffect{LookupEffect(device, effect)}; @@ -485,7 +485,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->EffectLock}; const ALeffect *aleffect{LookupEffect(device, effect)}; @@ -505,7 +505,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->EffectLock}; const ALeffect *aleffect{LookupEffect(device, effect)}; diff --git a/al/error.cpp b/al/error.cpp index f5f0801e..f5ec9f52 100644 --- a/al/error.cpp +++ b/al/error.cpp @@ -82,14 +82,14 @@ void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) } ALenum curerr{AL_NO_ERROR}; - context->LastError.compare_exchange_strong(curerr, errorCode); - if((context->EnabledEvts.load(std::memory_order_relaxed)&EventType_Error)) + context->mLastError.compare_exchange_strong(curerr, errorCode); + if((context->mEnabledEvts.load(std::memory_order_relaxed)&EventType_Error)) { - std::lock_guard _{context->EventCbLock}; - ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; - if((enabledevts&EventType_Error) && context->EventCb) - (*context->EventCb)(AL_EVENT_TYPE_ERROR_SOFT, 0, errorCode, msglen, msg, - context->EventParam); + std::lock_guard _{context->mEventCbLock}; + ALbitfieldSOFT enabledevts{context->mEnabledEvts.load(std::memory_order_relaxed)}; + if((enabledevts&EventType_Error) && context->mEventCb) + (*context->mEventCb)(AL_EVENT_TYPE_ERROR_SOFT, 0, errorCode, msglen, msg, + context->mEventParam); } } @@ -113,6 +113,6 @@ START_API_FUNC return deferror; } - return context->LastError.exchange(AL_NO_ERROR); + return context->mLastError.exchange(AL_NO_ERROR); } END_API_FUNC diff --git a/al/event.cpp b/al/event.cpp index b103d0da..b2710561 100644 --- a/al/event.cpp +++ b/al/event.cpp @@ -31,18 +31,18 @@ static int EventThread(ALCcontext *context) { - RingBuffer *ring{context->AsyncEvents.get()}; + RingBuffer *ring{context->mAsyncEvents.get()}; bool quitnow{false}; while(LIKELY(!quitnow)) { auto evt_data = ring->getReadVector().first; if(evt_data.len == 0) { - context->EventSem.wait(); + context->mEventSem.wait(); continue; } - std::lock_guard _{context->EventCbLock}; + std::lock_guard _{context->mEventCbLock}; do { auto &evt = *reinterpret_cast(evt_data.buf); evt_data.buf += sizeof(AsyncEvent); @@ -69,8 +69,8 @@ static int EventThread(ALCcontext *context) continue; } - ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_acquire)}; - if(!context->EventCb) continue; + ALbitfieldSOFT enabledevts{context->mEnabledEvts.load(std::memory_order_acquire)}; + if(!context->mEventCb) continue; if(evt.EnumType == EventType_SourceStateChange) { @@ -82,9 +82,9 @@ static int EventThread(ALCcontext *context) (evt.u.srcstate.state==AL_PLAYING) ? "AL_PLAYING" : (evt.u.srcstate.state==AL_PAUSED) ? "AL_PAUSED" : (evt.u.srcstate.state==AL_STOPPED) ? "AL_STOPPED" : ""; - context->EventCb(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, evt.u.srcstate.id, + context->mEventCb(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, evt.u.srcstate.id, evt.u.srcstate.state, static_cast(msg.length()), msg.c_str(), - context->EventParam); + context->mEventParam); } else if(evt.EnumType == EventType_BufferCompleted) { @@ -93,14 +93,14 @@ static int EventThread(ALCcontext *context) std::string msg{std::to_string(evt.u.bufcomp.count)}; if(evt.u.bufcomp.count == 1) msg += " buffer completed"; else msg += " buffers completed"; - context->EventCb(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, evt.u.bufcomp.id, + context->mEventCb(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, evt.u.bufcomp.id, evt.u.bufcomp.count, static_cast(msg.length()), msg.c_str(), - context->EventParam); + context->mEventParam); } else if((enabledevts&evt.EnumType) == evt.EnumType) - context->EventCb(evt.u.user.type, evt.u.user.id, evt.u.user.param, + context->mEventCb(evt.u.user.type, evt.u.user.id, evt.u.user.param, static_cast(strlen(evt.u.user.msg)), evt.u.user.msg, - context->EventParam); + context->mEventParam); } while(evt_data.len != 0); } return 0; @@ -109,7 +109,7 @@ static int EventThread(ALCcontext *context) void StartEventThrd(ALCcontext *ctx) { try { - ctx->EventThread = std::thread{EventThread, ctx}; + ctx->mEventThread = std::thread{EventThread, ctx}; } catch(std::exception& e) { ERR("Failed to start event thread: %s\n", e.what()); @@ -122,7 +122,7 @@ void StartEventThrd(ALCcontext *ctx) void StopEventThrd(ALCcontext *ctx) { static constexpr AsyncEvent kill_evt{EventType_KillThread}; - RingBuffer *ring{ctx->AsyncEvents.get()}; + RingBuffer *ring{ctx->mAsyncEvents.get()}; auto evt_data = ring->getWriteVector().first; if(evt_data.len == 0) { @@ -134,9 +134,9 @@ void StopEventThrd(ALCcontext *ctx) new (evt_data.buf) AsyncEvent{kill_evt}; ring->writeAdvance(1); - ctx->EventSem.post(); - if(ctx->EventThread.joinable()) - ctx->EventThread.join(); + ctx->mEventSem.post(); + if(ctx->mEventThread.joinable()) + ctx->mEventThread.join(); } AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable) @@ -176,8 +176,8 @@ START_API_FUNC if(enable) { - ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; - while(context->EnabledEvts.compare_exchange_weak(enabledevts, enabledevts|flags, + ALbitfieldSOFT enabledevts{context->mEnabledEvts.load(std::memory_order_relaxed)}; + while(context->mEnabledEvts.compare_exchange_weak(enabledevts, enabledevts|flags, std::memory_order_acq_rel, std::memory_order_acquire) == 0) { /* enabledevts is (re-)filled with the current value on failure, so @@ -187,15 +187,15 @@ START_API_FUNC } else { - ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; - while(context->EnabledEvts.compare_exchange_weak(enabledevts, enabledevts&~flags, + ALbitfieldSOFT enabledevts{context->mEnabledEvts.load(std::memory_order_relaxed)}; + while(context->mEnabledEvts.compare_exchange_weak(enabledevts, enabledevts&~flags, std::memory_order_acq_rel, std::memory_order_acquire) == 0) { } /* Wait to ensure the event handler sees the changed flags before * returning. */ - std::lock_guard{context->EventCbLock}; + std::lock_guard{context->mEventCbLock}; } } END_API_FUNC @@ -206,9 +206,9 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->EventCbLock}; - context->EventCb = callback; - context->EventParam = userParam; + std::lock_guard _{context->mPropLock}; + std::lock_guard __{context->mEventCbLock}; + context->mEventCb = callback; + context->mEventParam = userParam; } END_API_FUNC diff --git a/al/extension.cpp b/al/extension.cpp index e38d4382..c190ad03 100644 --- a/al/extension.cpp +++ b/al/extension.cpp @@ -43,7 +43,7 @@ START_API_FUNC SETERR_RETURN(context.get(), AL_INVALID_VALUE, AL_FALSE, "NULL pointer"); size_t len{strlen(extName)}; - const char *ptr{context->ExtensionList}; + const char *ptr{context->mExtensionList}; while(ptr && *ptr) { if(strncasecmp(ptr, extName, len) == 0 && diff --git a/al/filter.cpp b/al/filter.cpp index 405842f3..d9fce069 100644 --- a/al/filter.cpp +++ b/al/filter.cpp @@ -279,7 +279,7 @@ void InitFilterParams(ALfilter *filter, ALenum type) ALfilter *AllocFilter(ALCcontext *context) { - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->FilterLock}; auto sublist = std::find_if(device->FilterList.begin(), device->FilterList.end(), [](const FilterSubList &entry) noexcept -> bool @@ -411,7 +411,7 @@ START_API_FUNC if(UNLIKELY(n == 0)) return; - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->FilterLock}; /* First try to find any filters that are invalid. */ @@ -449,7 +449,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(LIKELY(context)) { - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->FilterLock}; if(!filter || LookupFilter(device, filter)) return AL_TRUE; @@ -465,7 +465,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; @@ -503,7 +503,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; @@ -523,7 +523,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; @@ -543,7 +543,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; @@ -563,7 +563,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; @@ -595,7 +595,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; @@ -615,7 +615,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; @@ -635,7 +635,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; diff --git a/al/listener.cpp b/al/listener.cpp index d67bf072..ba0a7268 100644 --- a/al/listener.cpp +++ b/al/listener.cpp @@ -36,7 +36,7 @@ #define DO_UPDATEPROPS() do { \ - if(!context->DeferUpdates.load(std::memory_order_acquire)) \ + if(!context->mDeferUpdates.load(std::memory_order_acquire)) \ UpdateListenerProps(context.get()); \ else \ listener.PropsClean.clear(std::memory_order_release); \ @@ -49,8 +49,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; + ALlistener &listener = context->mListener; + std::lock_guard _{context->mPropLock}; switch(param) { case AL_GAIN: @@ -64,11 +64,11 @@ START_API_FUNC if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT)) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener meters per unit out of range"); - context->MetersPerUnit = value; - if(!context->DeferUpdates.load(std::memory_order_acquire)) + context->mMetersPerUnit = value; + if(!context->mDeferUpdates.load(std::memory_order_acquire)) UpdateContextProps(context.get()); else - context->PropsClean.clear(std::memory_order_release); + context->mPropsClean.clear(std::memory_order_release); break; default: @@ -83,8 +83,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; + ALlistener &listener = context->mListener; + std::lock_guard _{context->mPropLock}; switch(param) { case AL_POSITION: @@ -133,8 +133,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; + ALlistener &listener = context->mListener; + std::lock_guard _{context->mPropLock}; if(!values) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "NULL pointer"); switch(param) { @@ -165,7 +165,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->mPropLock}; switch(param) { default: @@ -188,7 +188,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->mPropLock}; switch(param) { default: @@ -225,7 +225,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->mPropLock}; if(!values) alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) @@ -243,8 +243,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; + ALlistener &listener = context->mListener; + std::lock_guard _{context->mPropLock}; if(!value) alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) @@ -254,7 +254,7 @@ START_API_FUNC break; case AL_METERS_PER_UNIT: - *value = context->MetersPerUnit; + *value = context->mMetersPerUnit; break; default: @@ -269,8 +269,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; + ALlistener &listener = context->mListener; + std::lock_guard _{context->mPropLock}; if(!value1 || !value2 || !value3) alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) @@ -312,8 +312,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; + ALlistener &listener = context->mListener; + std::lock_guard _{context->mPropLock}; if(!values) alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) @@ -341,7 +341,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->mPropLock}; if(!value) alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) @@ -358,8 +358,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; + ALlistener &listener = context->mListener; + std::lock_guard _{context->mPropLock}; if(!value1 || !value2 || !value3) alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) @@ -396,8 +396,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALlistener &listener = context->Listener; - std::lock_guard _{context->PropLock}; + ALlistener &listener = context->mListener; + std::lock_guard _{context->mPropLock}; if(!values) alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) @@ -422,7 +422,7 @@ END_API_FUNC void UpdateListenerProps(ALCcontext *context) { /* Get an unused proprty container, or allocate a new one as needed. */ - ALlistenerProps *props{context->FreeListenerProps.load(std::memory_order_acquire)}; + ALlistenerProps *props{context->mFreeListenerProps.load(std::memory_order_acquire)}; if(!props) props = static_cast(al_calloc(16, sizeof(*props))); else @@ -430,12 +430,12 @@ void UpdateListenerProps(ALCcontext *context) ALlistenerProps *next; do { next = props->next.load(std::memory_order_relaxed); - } while(context->FreeListenerProps.compare_exchange_weak(props, next, + } while(context->mFreeListenerProps.compare_exchange_weak(props, next, std::memory_order_seq_cst, std::memory_order_acquire) == 0); } /* Copy in current property values. */ - ALlistener &listener = context->Listener; + ALlistener &listener = context->mListener; props->Position = listener.Position; props->Velocity = listener.Velocity; props->OrientAt = listener.OrientAt; @@ -449,6 +449,6 @@ void UpdateListenerProps(ALCcontext *context) /* If there was an unused update container, put it back in the * freelist. */ - AtomicReplaceHead(context->FreeListenerProps, props); + AtomicReplaceHead(context->mFreeListenerProps, props); } } diff --git a/al/source.cpp b/al/source.cpp index b4582e6b..39b635a4 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -77,10 +77,10 @@ using namespace std::placeholders; inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) { ALint idx{source->VoiceIdx}; - if(idx >= 0 && static_cast(idx) < context->VoiceCount.load(std::memory_order_relaxed)) + if(idx >= 0 && static_cast(idx) < context->mVoiceCount.load(std::memory_order_relaxed)) { ALuint sid{source->id}; - ALvoice &voice = (*context->Voices)[idx]; + ALvoice &voice = (*context->mVoices)[idx]; if(voice.mSourceID.load(std::memory_order_acquire) == sid) return &voice; } @@ -91,7 +91,7 @@ inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) void UpdateSourceProps(const ALsource *source, ALvoice *voice, ALCcontext *context) { /* Get an unused property container, or allocate a new one as needed. */ - ALvoiceProps *props{context->FreeVoiceProps.load(std::memory_order_acquire)}; + ALvoiceProps *props{context->mFreeVoiceProps.load(std::memory_order_acquire)}; if(!props) props = new ALvoiceProps{}; else @@ -99,7 +99,7 @@ void UpdateSourceProps(const ALsource *source, ALvoice *voice, ALCcontext *conte ALvoiceProps *next; do { next = props->next.load(std::memory_order_relaxed); - } while(context->FreeVoiceProps.compare_exchange_weak(props, next, + } while(context->mFreeVoiceProps.compare_exchange_weak(props, next, std::memory_order_acq_rel, std::memory_order_acquire) == 0); } @@ -164,7 +164,7 @@ void UpdateSourceProps(const ALsource *source, ALvoice *voice, ALCcontext *conte /* If there was an unused update container, put it back in the * freelist. */ - AtomicReplaceHead(context->FreeVoiceProps, props); + AtomicReplaceHead(context->mFreeVoiceProps, props); } } @@ -176,7 +176,7 @@ void UpdateSourceProps(const ALsource *source, ALvoice *voice, ALCcontext *conte */ int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, std::chrono::nanoseconds *clocktime) { - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; const ALbufferlistitem *Current; uint64_t readPos; ALuint refcount; @@ -222,7 +222,7 @@ int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, std::chrono */ ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, std::chrono::nanoseconds *clocktime) { - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; const ALbufferlistitem *Current; uint64_t readPos; ALuint refcount; @@ -282,7 +282,7 @@ ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, std::chrono:: */ ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) { - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; const ALbufferlistitem *Current; ALuint readPos; ALsizei readPosFrac; @@ -484,21 +484,21 @@ ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) ALsource *AllocSource(ALCcontext *context) { - ALCdevice *device{context->Device}; - std::lock_guard _{context->SourceLock}; - if(context->NumSources >= device->SourcesMax) + ALCdevice *device{context->mDevice}; + std::lock_guard _{context->mSourceLock}; + if(context->mNumSources >= device->SourcesMax) { alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax); return nullptr; } - auto sublist = std::find_if(context->SourceList.begin(), context->SourceList.end(), + auto sublist = std::find_if(context->mSourceList.begin(), context->mSourceList.end(), [](const SourceSubList &entry) noexcept -> bool { return entry.FreeMask != 0; } ); - auto lidx = static_cast(std::distance(context->SourceList.begin(), sublist)); + auto lidx = static_cast(std::distance(context->mSourceList.begin(), sublist)); ALsource *source; ALsizei slidx; - if(LIKELY(sublist != context->SourceList.end())) + if(LIKELY(sublist != context->mSourceList.end())) { slidx = CTZ64(sublist->FreeMask); source = sublist->Sources + slidx; @@ -508,19 +508,19 @@ ALsource *AllocSource(ALCcontext *context) /* Don't allocate so many list entries that the 32-bit ID could * overflow... */ - if(UNLIKELY(context->SourceList.size() >= 1<<25)) + if(UNLIKELY(context->mSourceList.size() >= 1<<25)) { alSetError(context, AL_OUT_OF_MEMORY, "Too many sources allocated"); return nullptr; } - context->SourceList.emplace_back(); - sublist = context->SourceList.end() - 1; + context->mSourceList.emplace_back(); + sublist = context->mSourceList.end() - 1; sublist->FreeMask = ~0_u64; sublist->Sources = static_cast(al_calloc(16, sizeof(ALsource)*64)); if(UNLIKELY(!sublist->Sources)) { - context->SourceList.pop_back(); + context->mSourceList.pop_back(); alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate source batch"); return nullptr; } @@ -534,7 +534,7 @@ ALsource *AllocSource(ALCcontext *context) /* Add 1 to avoid source ID 0. */ source->id = ((lidx<<6) | slidx) + 1; - context->NumSources += 1; + context->mNumSources += 1; sublist->FreeMask &= ~(1_u64 << slidx); return source; @@ -546,7 +546,7 @@ void FreeSource(ALCcontext *context, ALsource *source) ALsizei lidx = id >> 6; ALsizei slidx = id & 0x3f; - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; BackendUniqueLock backlock{*device->Backend}; if(ALvoice *voice{GetSourceVoice(source, context)}) { @@ -565,8 +565,8 @@ void FreeSource(ALCcontext *context, ALsource *source) al::destroy_at(source); - context->SourceList[lidx].FreeMask |= 1_u64 << slidx; - context->NumSources--; + context->mSourceList[lidx].FreeMask |= 1_u64 << slidx; + context->mNumSources--; } @@ -575,9 +575,9 @@ inline ALsource *LookupSource(ALCcontext *context, ALuint id) noexcept ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; - if(UNLIKELY(lidx >= context->SourceList.size())) + if(UNLIKELY(lidx >= context->mSourceList.size())) return nullptr; - SourceSubList &sublist{context->SourceList[lidx]}; + SourceSubList &sublist{context->mSourceList[lidx]}; if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) return nullptr; return sublist.Sources + slidx; @@ -614,9 +614,9 @@ inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; - if(UNLIKELY(lidx >= context->EffectSlotList.size())) + if(UNLIKELY(lidx >= context->mEffectSlotList.size())) return nullptr; - EffectSlotSubList &sublist{context->EffectSlotList[lidx]}; + EffectSlotSubList &sublist{context->mEffectSlotList[lidx]}; if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) return nullptr; return sublist.EffectSlots + slidx; @@ -715,7 +715,7 @@ inline ALenum GetSourceState(ALsource *source, ALvoice *voice) */ inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context) { - return !context->DeferUpdates.load(std::memory_order_acquire) && + return !context->mDeferUpdates.load(std::memory_order_acquire) && IsPlayingOrPaused(source); } @@ -723,14 +723,14 @@ inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context) /** Can only be called while the mixer is locked! */ void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) { - ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)}; + ALbitfieldSOFT enabledevt{context->mEnabledEvts.load(std::memory_order_acquire)}; if(!(enabledevt&EventType_SourceStateChange)) return; /* The mixer may have queued a state change that's not yet been processed, * and we don't want state change messages to occur out of order, so send * it through the async queue to ensure proper ordering. */ - RingBuffer *ring{context->AsyncEvents.get()}; + RingBuffer *ring{context->mAsyncEvents.get()}; auto evt_vec = ring->getWriteVector(); if(evt_vec.first.len < 1) return; @@ -738,7 +738,7 @@ void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) evt->u.srcstate.id = id; evt->u.srcstate.state = state; ring->writeAdvance(1); - context->EventSem.post(); + context->mEventSem.post(); } @@ -1127,7 +1127,7 @@ ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, co if(IsPlayingOrPaused(Source)) { - ALCdevice *device{Context->Device}; + ALCdevice *device{Context->mDevice}; BackendLockGuard _{*device->Backend}; /* Double-check that the source is still playing while we have * the lock. @@ -1230,7 +1230,7 @@ ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, co ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values) { - ALCdevice *device{Context->Device}; + ALCdevice *device{Context->mDevice}; ALbuffer *buffer{nullptr}; ALfilter *filter{nullptr}; ALeffectslot *slot{nullptr}; @@ -1348,7 +1348,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co if(IsPlayingOrPaused(Source)) { - ALCdevice *device{Context->Device}; + ALCdevice *device{Context->mDevice}; BackendLockGuard _{*device->Backend}; if(ALvoice *voice{GetSourceVoice(Source, Context)}) { @@ -1423,7 +1423,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co *values == AL_EXPONENT_DISTANCE_CLAMPED); Source->mDistanceModel = static_cast(*values); - if(Context->SourceDistanceModel) + if(Context->mSourceDistanceModel) UpdateSourceProps(Source, Context); return AL_TRUE; @@ -1443,7 +1443,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co case AL_AUXILIARY_SEND_FILTER: - slotlock = std::unique_lock{Context->EffectSlotLock}; + slotlock = std::unique_lock{Context->mEffectSlotLock}; if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != nullptr)) SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid effect ID %u", values[0]); @@ -1664,7 +1664,7 @@ ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values) { - ALCdevice *device{Context->Device}; + ALCdevice *device{Context->mDevice}; ClockLatency clocktime; std::chrono::nanoseconds srcclock; ALint ivals[3]; @@ -1997,7 +1997,7 @@ ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64SOFT *values) { - ALCdevice *device = Context->Device; + ALCdevice *device = Context->mDevice; ClockLatency clocktime; std::chrono::nanoseconds srcclock; ALdouble dvals[6]; @@ -2172,7 +2172,7 @@ START_API_FUNC if(n < 0) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Deleting %d sources", n); - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; /* Check that all Sources are valid */ const ALuint *sources_end = sources + n; @@ -2207,7 +2207,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(LIKELY(context)) { - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; if(LookupSource(context.get(), source) != nullptr) return AL_TRUE; } @@ -2222,8 +2222,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard _{context->mPropLock}; + std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2240,8 +2240,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard _{context->mPropLock}; + std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2261,8 +2261,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard _{context->mPropLock}; + std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2282,8 +2282,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard _{context->mPropLock}; + std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2303,8 +2303,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard _{context->mPropLock}; + std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2325,8 +2325,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard _{context->mPropLock}; + std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2357,8 +2357,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard _{context->mPropLock}; + std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2375,8 +2375,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard _{context->mPropLock}; + std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2396,8 +2396,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard _{context->mPropLock}; + std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2417,8 +2417,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard _{context->mPropLock}; + std::lock_guard __{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2435,8 +2435,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard _{context->mPropLock}; + std::lock_guard __{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2456,8 +2456,8 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; - std::lock_guard __{context->SourceLock}; + std::lock_guard _{context->mPropLock}; + std::lock_guard __{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2477,7 +2477,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2500,7 +2500,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2527,7 +2527,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2558,7 +2558,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2577,7 +2577,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2604,7 +2604,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2624,7 +2624,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2643,7 +2643,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2670,7 +2670,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2690,7 +2690,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2709,7 +2709,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2736,7 +2736,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2774,7 +2774,7 @@ START_API_FUNC srchandles = extra_sources.data(); } - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; for(ALsizei i{0};i < n;i++) { srchandles[i] = LookupSource(context.get(), sources[i]); @@ -2782,7 +2782,7 @@ START_API_FUNC SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; BackendLockGuard __{*device->Backend}; /* If the device is disconnected, go right to stopped. */ if(UNLIKELY(!device->Connected.load(std::memory_order_acquire))) @@ -2800,9 +2800,9 @@ START_API_FUNC } /* Count the number of reusable voices. */ - auto voices_end = context->Voices->begin() + - context->VoiceCount.load(std::memory_order_relaxed); - auto free_voices = std::accumulate(context->Voices->begin(), voices_end, ALsizei{0}, + auto voices_end = context->mVoices->begin() + + context->mVoiceCount.load(std::memory_order_relaxed); + auto free_voices = std::accumulate(context->mVoices->begin(), voices_end, ALsizei{0}, [](const ALsizei count, const ALvoice &voice) noexcept -> ALsizei { if(voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && @@ -2815,23 +2815,23 @@ START_API_FUNC { /* Increment the number of voices to handle the request. */ const ALuint need_voices{static_cast(n) - free_voices}; - const size_t rem_voices{context->Voices->size() - - context->VoiceCount.load(std::memory_order_relaxed)}; + const size_t rem_voices{context->mVoices->size() - + context->mVoiceCount.load(std::memory_order_relaxed)}; if(UNLIKELY(need_voices > rem_voices)) { /* Allocate more voices to get enough. */ const size_t alloc_count{need_voices - rem_voices}; - if(UNLIKELY(context->Voices->size() > std::numeric_limits::max()-alloc_count)) + if(UNLIKELY(context->mVoices->size() > std::numeric_limits::max()-alloc_count)) SETERR_RETURN(context.get(), AL_OUT_OF_MEMORY,, - "Overflow increasing voice count to %zu + %zu", context->Voices->size(), + "Overflow increasing voice count to %zu + %zu", context->mVoices->size(), alloc_count); - const size_t newcount{context->Voices->size() + alloc_count}; + const size_t newcount{context->mVoices->size() + alloc_count}; AllocateVoices(context.get(), newcount); } - context->VoiceCount.fetch_add(need_voices, std::memory_order_relaxed); + context->mVoiceCount.fetch_add(need_voices, std::memory_order_relaxed); } auto start_source = [&context,device](ALsource *source) -> void @@ -2886,9 +2886,9 @@ START_API_FUNC } /* Look for an unused voice to play this source with. */ - auto voices_end = context->Voices->begin() + - context->VoiceCount.load(std::memory_order_relaxed); - voice = std::find_if(context->Voices->begin(), voices_end, + auto voices_end = context->mVoices->begin() + + context->mVoiceCount.load(std::memory_order_relaxed); + voice = std::find_if(context->mVoices->begin(), voices_end, [](const ALvoice &voice) noexcept -> bool { return voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && @@ -2896,7 +2896,7 @@ START_API_FUNC } ); assert(voice != voices_end); - auto vidx = static_cast(std::distance(context->Voices->begin(), voice)); + auto vidx = static_cast(std::distance(context->mVoices->begin(), voice)); voice->mPlayState.store(ALvoice::Stopped, std::memory_order_release); source->PropsClean.test_and_set(std::memory_order_acquire); @@ -3036,7 +3036,7 @@ START_API_FUNC srchandles = extra_sources.data(); } - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; for(ALsizei i{0};i < n;i++) { srchandles[i] = LookupSource(context.get(), sources[i]); @@ -3044,7 +3044,7 @@ START_API_FUNC SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; BackendLockGuard __{*device->Backend}; auto pause_source = [&context](ALsource *source) -> void { @@ -3091,7 +3091,7 @@ START_API_FUNC srchandles = extra_sources.data(); } - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; for(ALsizei i{0};i < n;i++) { srchandles[i] = LookupSource(context.get(), sources[i]); @@ -3099,7 +3099,7 @@ START_API_FUNC SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; BackendLockGuard __{*device->Backend}; auto stop_source = [&context](ALsource *source) -> void { @@ -3153,7 +3153,7 @@ START_API_FUNC srchandles = extra_sources.data(); } - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; for(ALsizei i{0};i < n;i++) { srchandles[i] = LookupSource(context.get(), sources[i]); @@ -3161,7 +3161,7 @@ START_API_FUNC SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; BackendLockGuard __{*device->Backend}; auto rewind_source = [&context](ALsource *source) -> void { @@ -3200,7 +3200,7 @@ START_API_FUNC SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffers", nb); if(nb == 0) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; ALsource *source{LookupSource(context.get(),src)}; if(UNLIKELY(!source)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); @@ -3210,7 +3210,7 @@ START_API_FUNC SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src); /* Check for a valid Buffer, for its frequency and format */ - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; ALbuffer *BufferFmt{nullptr}; ALbufferlistitem *BufferList{source->queue}; while(BufferList) @@ -3319,7 +3319,7 @@ START_API_FUNC SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffer layers", nb); if(nb == 0) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; ALsource *source{LookupSource(context.get(),src)}; if(UNLIKELY(!source)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); @@ -3329,7 +3329,7 @@ START_API_FUNC SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src); /* Check for a valid Buffer, for its frequency and format */ - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; ALbuffer *BufferFmt{nullptr}; ALbufferlistitem *BufferList{source->queue}; while(BufferList) @@ -3429,7 +3429,7 @@ START_API_FUNC SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing %d buffers", nb); if(nb == 0) return; - std::lock_guard _{context->SourceLock}; + std::lock_guard _{context->mSourceLock}; ALsource *source{LookupSource(context.get(),src)}; if(UNLIKELY(!source)) SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); @@ -3611,9 +3611,9 @@ ALsource::~ALsource() void UpdateAllSourceProps(ALCcontext *context) { - auto voices_end = context->Voices->begin() + - context->VoiceCount.load(std::memory_order_relaxed); - std::for_each(context->Voices->begin(), voices_end, + auto voices_end = context->mVoices->begin() + + context->mVoiceCount.load(std::memory_order_relaxed); + std::for_each(context->mVoices->begin(), voices_end, [context](ALvoice &voice) -> void { ALuint sid{voice.mSourceID.load(std::memory_order_acquire)}; diff --git a/al/state.cpp b/al/state.cpp index cbb43685..b1885f5c 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -80,10 +80,10 @@ START_API_FUNC END_API_FUNC #define DO_UPDATEPROPS() do { \ - if(!context->DeferUpdates.load(std::memory_order_acquire)) \ + if(!context->mDeferUpdates.load(std::memory_order_acquire)) \ UpdateContextProps(context.get()); \ else \ - context->PropsClean.clear(std::memory_order_release); \ + context->mPropsClean.clear(std::memory_order_release); \ } while(0) @@ -93,11 +93,11 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->mPropLock}; switch(capability) { case AL_SOURCE_DISTANCE_MODEL: - context->SourceDistanceModel = AL_TRUE; + context->mSourceDistanceModel = AL_TRUE; DO_UPDATEPROPS(); break; @@ -113,11 +113,11 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->mPropLock}; switch(capability) { case AL_SOURCE_DISTANCE_MODEL: - context->SourceDistanceModel = AL_FALSE; + context->mSourceDistanceModel = AL_FALSE; DO_UPDATEPROPS(); break; @@ -133,12 +133,12 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return AL_FALSE; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->mPropLock}; ALboolean value{AL_FALSE}; switch(capability) { case AL_SOURCE_DISTANCE_MODEL: - value = context->SourceDistanceModel; + value = context->mSourceDistanceModel; break; default: @@ -155,17 +155,17 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return AL_FALSE; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->mPropLock}; ALboolean value{AL_FALSE}; switch(pname) { case AL_DOPPLER_FACTOR: - if(context->DopplerFactor != 0.0f) + if(context->mDopplerFactor != 0.0f) value = AL_TRUE; break; case AL_DOPPLER_VELOCITY: - if(context->DopplerVelocity != 0.0f) + if(context->mDopplerVelocity != 0.0f) value = AL_TRUE; break; @@ -175,17 +175,17 @@ START_API_FUNC break; case AL_SPEED_OF_SOUND: - if(context->SpeedOfSound != 0.0f) + if(context->mSpeedOfSound != 0.0f) value = AL_TRUE; break; case AL_DEFERRED_UPDATES_SOFT: - if(context->DeferUpdates.load(std::memory_order_acquire)) + if(context->mDeferUpdates.load(std::memory_order_acquire)) value = AL_TRUE; break; case AL_GAIN_LIMIT_SOFT: - if(GAIN_MIX_MAX/context->GainBoost != 0.0f) + if(GAIN_MIX_MAX/context->mGainBoost != 0.0f) value = AL_TRUE; break; @@ -212,16 +212,16 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return 0.0; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->mPropLock}; ALdouble value{0.0}; switch(pname) { case AL_DOPPLER_FACTOR: - value = static_cast(context->DopplerFactor); + value = static_cast(context->mDopplerFactor); break; case AL_DOPPLER_VELOCITY: - value = static_cast(context->DopplerVelocity); + value = static_cast(context->mDopplerVelocity); break; case AL_DISTANCE_MODEL: @@ -229,16 +229,16 @@ START_API_FUNC break; case AL_SPEED_OF_SOUND: - value = static_cast(context->SpeedOfSound); + value = static_cast(context->mSpeedOfSound); break; case AL_DEFERRED_UPDATES_SOFT: - if(context->DeferUpdates.load(std::memory_order_acquire)) + if(context->mDeferUpdates.load(std::memory_order_acquire)) value = static_cast(AL_TRUE); break; case AL_GAIN_LIMIT_SOFT: - value = static_castGAIN_MIX_MAX/context->GainBoost; + value = static_castGAIN_MIX_MAX/context->mGainBoost; break; case AL_NUM_RESAMPLERS_SOFT: @@ -263,16 +263,16 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return 0.0f; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->mPropLock}; ALfloat value{0.0f}; switch(pname) { case AL_DOPPLER_FACTOR: - value = context->DopplerFactor; + value = context->mDopplerFactor; break; case AL_DOPPLER_VELOCITY: - value = context->DopplerVelocity; + value = context->mDopplerVelocity; break; case AL_DISTANCE_MODEL: @@ -280,16 +280,16 @@ START_API_FUNC break; case AL_SPEED_OF_SOUND: - value = context->SpeedOfSound; + value = context->mSpeedOfSound; break; case AL_DEFERRED_UPDATES_SOFT: - if(context->DeferUpdates.load(std::memory_order_acquire)) + if(context->mDeferUpdates.load(std::memory_order_acquire)) value = static_cast(AL_TRUE); break; case AL_GAIN_LIMIT_SOFT: - value = GAIN_MIX_MAX/context->GainBoost; + value = GAIN_MIX_MAX/context->mGainBoost; break; case AL_NUM_RESAMPLERS_SOFT: @@ -314,16 +314,16 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return 0; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->mPropLock}; ALint value{0}; switch(pname) { case AL_DOPPLER_FACTOR: - value = static_cast(context->DopplerFactor); + value = static_cast(context->mDopplerFactor); break; case AL_DOPPLER_VELOCITY: - value = static_cast(context->DopplerVelocity); + value = static_cast(context->mDopplerVelocity); break; case AL_DISTANCE_MODEL: @@ -331,16 +331,16 @@ START_API_FUNC break; case AL_SPEED_OF_SOUND: - value = static_cast(context->SpeedOfSound); + value = static_cast(context->mSpeedOfSound); break; case AL_DEFERRED_UPDATES_SOFT: - if(context->DeferUpdates.load(std::memory_order_acquire)) + if(context->mDeferUpdates.load(std::memory_order_acquire)) value = static_cast(AL_TRUE); break; case AL_GAIN_LIMIT_SOFT: - value = static_cast(GAIN_MIX_MAX/context->GainBoost); + value = static_cast(GAIN_MIX_MAX/context->mGainBoost); break; case AL_NUM_RESAMPLERS_SOFT: @@ -365,16 +365,16 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return 0; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->mPropLock}; ALint64SOFT value{0}; switch(pname) { case AL_DOPPLER_FACTOR: - value = (ALint64SOFT)context->DopplerFactor; + value = (ALint64SOFT)context->mDopplerFactor; break; case AL_DOPPLER_VELOCITY: - value = (ALint64SOFT)context->DopplerVelocity; + value = (ALint64SOFT)context->mDopplerVelocity; break; case AL_DISTANCE_MODEL: @@ -382,16 +382,16 @@ START_API_FUNC break; case AL_SPEED_OF_SOUND: - value = (ALint64SOFT)context->SpeedOfSound; + value = (ALint64SOFT)context->mSpeedOfSound; break; case AL_DEFERRED_UPDATES_SOFT: - if(context->DeferUpdates.load(std::memory_order_acquire)) + if(context->mDeferUpdates.load(std::memory_order_acquire)) value = (ALint64SOFT)AL_TRUE; break; case AL_GAIN_LIMIT_SOFT: - value = (ALint64SOFT)(GAIN_MIX_MAX/context->GainBoost); + value = (ALint64SOFT)(GAIN_MIX_MAX/context->mGainBoost); break; case AL_NUM_RESAMPLERS_SOFT: @@ -416,16 +416,16 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return nullptr; - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->mPropLock}; void *value{nullptr}; switch(pname) { case AL_EVENT_CALLBACK_FUNCTION_SOFT: - value = reinterpret_cast(context->EventCb); + value = reinterpret_cast(context->mEventCb); break; case AL_EVENT_CALLBACK_USER_PARAM_SOFT: - value = context->EventParam; + value = context->mEventParam; break; default: @@ -650,7 +650,7 @@ START_API_FUNC break; case AL_EXTENSIONS: - value = context->ExtensionList; + value = context->mExtensionList; break; case AL_NO_ERROR: @@ -694,8 +694,8 @@ START_API_FUNC alSetError(context.get(), AL_INVALID_VALUE, "Doppler factor %f out of range", value); else { - std::lock_guard _{context->PropLock}; - context->DopplerFactor = value; + std::lock_guard _{context->mPropLock}; + context->mDopplerFactor = value; DO_UPDATEPROPS(); } } @@ -707,24 +707,24 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - if((context->EnabledEvts.load(std::memory_order_relaxed)&EventType_Deprecated)) + if((context->mEnabledEvts.load(std::memory_order_relaxed)&EventType_Deprecated)) { static constexpr ALCchar msg[] = "alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound"; const ALsizei msglen = static_cast(strlen(msg)); - std::lock_guard _{context->EventCbLock}; - ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)}; - if((enabledevts&EventType_Deprecated) && context->EventCb) - (*context->EventCb)(AL_EVENT_TYPE_DEPRECATED_SOFT, 0, 0, msglen, msg, - context->EventParam); + std::lock_guard _{context->mEventCbLock}; + ALbitfieldSOFT enabledevts{context->mEnabledEvts.load(std::memory_order_relaxed)}; + if((enabledevts&EventType_Deprecated) && context->mEventCb) + (*context->mEventCb)(AL_EVENT_TYPE_DEPRECATED_SOFT, 0, 0, msglen, msg, + context->mEventParam); } if(!(value >= 0.0f && std::isfinite(value))) alSetError(context.get(), AL_INVALID_VALUE, "Doppler velocity %f out of range", value); else { - std::lock_guard _{context->PropLock}; - context->DopplerVelocity = value; + std::lock_guard _{context->mPropLock}; + context->mDopplerVelocity = value; DO_UPDATEPROPS(); } } @@ -740,8 +740,8 @@ START_API_FUNC alSetError(context.get(), AL_INVALID_VALUE, "Speed of sound %f out of range", value); else { - std::lock_guard _{context->PropLock}; - context->SpeedOfSound = value; + std::lock_guard _{context->mPropLock}; + context->mSpeedOfSound = value; DO_UPDATEPROPS(); } } @@ -760,9 +760,9 @@ START_API_FUNC alSetError(context.get(), AL_INVALID_VALUE, "Distance model 0x%04x out of range", value); else { - std::lock_guard _{context->PropLock}; + std::lock_guard _{context->mPropLock}; context->mDistanceModel = static_cast(value); - if(!context->SourceDistanceModel) + if(!context->mSourceDistanceModel) DO_UPDATEPROPS(); } } @@ -825,7 +825,7 @@ END_API_FUNC void UpdateContextProps(ALCcontext *context) { /* Get an unused proprty container, or allocate a new one as needed. */ - ALcontextProps *props{context->FreeContextProps.load(std::memory_order_acquire)}; + ALcontextProps *props{context->mFreeContextProps.load(std::memory_order_acquire)}; if(!props) props = static_cast(al_calloc(16, sizeof(*props))); else @@ -833,27 +833,27 @@ void UpdateContextProps(ALCcontext *context) ALcontextProps *next; do { next = props->next.load(std::memory_order_relaxed); - } while(context->FreeContextProps.compare_exchange_weak(props, next, + } while(context->mFreeContextProps.compare_exchange_weak(props, next, std::memory_order_seq_cst, std::memory_order_acquire) == 0); } /* Copy in current property values. */ - props->MetersPerUnit = context->MetersPerUnit; + props->MetersPerUnit = context->mMetersPerUnit; - props->DopplerFactor = context->DopplerFactor; - props->DopplerVelocity = context->DopplerVelocity; - props->SpeedOfSound = context->SpeedOfSound; + props->DopplerFactor = context->mDopplerFactor; + props->DopplerVelocity = context->mDopplerVelocity; + props->SpeedOfSound = context->mSpeedOfSound; - props->SourceDistanceModel = context->SourceDistanceModel; + props->SourceDistanceModel = context->mSourceDistanceModel; props->mDistanceModel = context->mDistanceModel; /* Set the new container for updating internal parameters. */ - props = context->Update.exchange(props, std::memory_order_acq_rel); + props = context->mUpdate.exchange(props, std::memory_order_acq_rel); if(props) { /* If there was an unused update container, put it back in the * freelist. */ - AtomicReplaceHead(context->FreeContextProps, props); + AtomicReplaceHead(context->mFreeContextProps, props); } } diff --git a/alc/alc.cpp b/alc/alc.cpp index 538bea9f..49ecf54b 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -833,7 +833,7 @@ std::atomic LastNullDeviceError{ALC_NO_ERROR}; /* Thread-local current context */ void ReleaseThreadCtx(ALCcontext *context) { - auto ref = DecrementRef(&context->ref); + auto ref = DecrementRef(&context->mRef); TRACEREF("ALCcontext %p decreasing refcount to %u\n", context, ref); ERR("Context %p current for thread being destroyed, possible leak!\n", context); } @@ -1599,7 +1599,7 @@ void SetDefaultChannelOrder(ALCdevice *device) */ void ALCcontext_DeferUpdates(ALCcontext *context) { - context->DeferUpdates.store(true); + context->mDeferUpdates.store(true); } /* ALCcontext_ProcessUpdates @@ -1608,19 +1608,19 @@ void ALCcontext_DeferUpdates(ALCcontext *context) */ void ALCcontext_ProcessUpdates(ALCcontext *context) { - std::lock_guard _{context->PropLock}; - if(context->DeferUpdates.exchange(false)) + std::lock_guard _{context->mPropLock}; + if(context->mDeferUpdates.exchange(false)) { /* Tell the mixer to stop applying updates, then wait for any active * updating to finish, before providing updates. */ - context->HoldUpdates.store(true, std::memory_order_release); - while((context->UpdateCount.load(std::memory_order_acquire)&1) != 0) + context->mHoldUpdates.store(true, std::memory_order_release); + while((context->mUpdateCount.load(std::memory_order_acquire)&1) != 0) std::this_thread::yield(); - if(!context->PropsClean.test_and_set(std::memory_order_acq_rel)) + if(!context->mPropsClean.test_and_set(std::memory_order_acq_rel)) UpdateContextProps(context); - if(!context->Listener.PropsClean.test_and_set(std::memory_order_acq_rel)) + if(!context->mListener.PropsClean.test_and_set(std::memory_order_acq_rel)) UpdateListenerProps(context); UpdateAllEffectSlotProps(context); UpdateAllSourceProps(context); @@ -1628,7 +1628,7 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) /* Now with all updates declared, let the mixer continue applying them * so they all happen at once. */ - context->HoldUpdates.store(false, std::memory_order_release); + context->mHoldUpdates.store(false, std::memory_order_release); } } @@ -2167,9 +2167,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) FPUCtl mixer_mode{}; for(ALCcontext *context : *device->mContexts.load()) { - if(context->DefaultSlot) + if(context->mDefaultSlot) { - ALeffectslot *slot = context->DefaultSlot.get(); + ALeffectslot *slot = context->mDefaultSlot.get(); aluInitEffectPanning(slot, device); EffectState *state{slot->Effect.State}; @@ -2180,9 +2180,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) UpdateEffectSlotProps(slot, context); } - std::unique_lock proplock{context->PropLock}; - std::unique_lock slotlock{context->EffectSlotLock}; - for(auto &sublist : context->EffectSlotList) + std::unique_lock proplock{context->mPropLock}; + std::unique_lock slotlock{context->mEffectSlotLock}; + for(auto &sublist : context->mEffectSlotList) { uint64_t usemask = ~sublist.FreeMask; while(usemask) @@ -2204,8 +2204,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } slotlock.unlock(); - std::unique_lock srclock{context->SourceLock}; - for(auto &sublist : context->SourceList) + std::unique_lock srclock{context->mSourceLock}; + for(auto &sublist : context->mSourceList) { uint64_t usemask = ~sublist.FreeMask; while(usemask) @@ -2245,7 +2245,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) * auxiliary sends is changing. Active sources will have updates * respecified in UpdateAllSourceProps. */ - ALvoiceProps *vprops{context->FreeVoiceProps.exchange(nullptr, std::memory_order_acq_rel)}; + ALvoiceProps *vprops{context->mFreeVoiceProps.exchange(nullptr, std::memory_order_acq_rel)}; while(vprops) { ALvoiceProps *next = vprops->next.load(std::memory_order_relaxed); @@ -2253,8 +2253,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) vprops = next; } - auto voices = context->Voices.get(); - auto voices_end = voices->begin() + context->VoiceCount.load(std::memory_order_relaxed); + auto voices = context->mVoices.get(); + auto voices_end = voices->begin() + context->mVoiceCount.load(std::memory_order_relaxed); if(device->NumAuxSends < old_sends) { const ALsizei num_sends{device->NumAuxSends}; @@ -2300,9 +2300,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ); srclock.unlock(); - context->PropsClean.test_and_set(std::memory_order_release); + context->mPropsClean.test_and_set(std::memory_order_release); UpdateContextProps(context); - context->Listener.PropsClean.test_and_set(std::memory_order_release); + context->mListener.PropsClean.test_and_set(std::memory_order_release); UpdateListenerProps(context); UpdateAllSourceProps(context); } @@ -2383,9 +2383,9 @@ static DeviceRef VerifyDevice(ALCdevice *device) } -ALCcontext::ALCcontext(ALCdevice *device) : Device{device} +ALCcontext::ALCcontext(ALCdevice *device) : mDevice{device} { - PropsClean.test_and_set(std::memory_order_relaxed); + mPropsClean.test_and_set(std::memory_order_relaxed); } /* InitContext @@ -2394,43 +2394,43 @@ ALCcontext::ALCcontext(ALCdevice *device) : Device{device} */ static ALvoid InitContext(ALCcontext *Context) { - ALlistener &listener = Context->Listener; + ALlistener &listener = Context->mListener; ALeffectslotArray *auxslots; //Validate Context - if(!Context->DefaultSlot) + if(!Context->mDefaultSlot) auxslots = ALeffectslot::CreatePtrArray(0); else { auxslots = ALeffectslot::CreatePtrArray(1); - (*auxslots)[0] = Context->DefaultSlot.get(); + (*auxslots)[0] = Context->mDefaultSlot.get(); } - Context->ActiveAuxSlots.store(auxslots, std::memory_order_relaxed); + Context->mActiveAuxSlots.store(auxslots, std::memory_order_relaxed); //Set globals Context->mDistanceModel = DistanceModel::Default; - Context->SourceDistanceModel = AL_FALSE; - Context->DopplerFactor = 1.0f; - Context->DopplerVelocity = 1.0f; - Context->SpeedOfSound = SPEEDOFSOUNDMETRESPERSEC; - Context->MetersPerUnit = AL_DEFAULT_METERS_PER_UNIT; + Context->mSourceDistanceModel = AL_FALSE; + Context->mDopplerFactor = 1.0f; + Context->mDopplerVelocity = 1.0f; + Context->mSpeedOfSound = SPEEDOFSOUNDMETRESPERSEC; + Context->mMetersPerUnit = AL_DEFAULT_METERS_PER_UNIT; - Context->ExtensionList = alExtList; + Context->mExtensionList = alExtList; listener.Params.Matrix = alu::Matrix::Identity(); listener.Params.Velocity = alu::Vector{}; listener.Params.Gain = listener.Gain; - listener.Params.MetersPerUnit = Context->MetersPerUnit; - listener.Params.DopplerFactor = Context->DopplerFactor; - listener.Params.SpeedOfSound = Context->SpeedOfSound * Context->DopplerVelocity; + listener.Params.MetersPerUnit = Context->mMetersPerUnit; + listener.Params.DopplerFactor = Context->mDopplerFactor; + listener.Params.SpeedOfSound = Context->mSpeedOfSound * Context->mDopplerVelocity; listener.Params.ReverbSpeedOfSound = listener.Params.SpeedOfSound * listener.Params.MetersPerUnit; - listener.Params.SourceDistanceModel = Context->SourceDistanceModel; + listener.Params.SourceDistanceModel = Context->mSourceDistanceModel; listener.Params.mDistanceModel = Context->mDistanceModel; - Context->AsyncEvents = CreateRingBuffer(511, sizeof(AsyncEvent), false); + Context->mAsyncEvents = CreateRingBuffer(511, sizeof(AsyncEvent), false); StartEventThrd(Context); } @@ -2444,14 +2444,14 @@ ALCcontext::~ALCcontext() { TRACE("Freeing context %p\n", this); - ALcontextProps *cprops{Update.exchange(nullptr, std::memory_order_relaxed)}; + ALcontextProps *cprops{mUpdate.exchange(nullptr, std::memory_order_relaxed)}; if(cprops) { TRACE("Freed unapplied context update %p\n", cprops); al_free(cprops); } size_t count{0}; - cprops = FreeContextProps.exchange(nullptr, std::memory_order_acquire); + cprops = mFreeContextProps.exchange(nullptr, std::memory_order_acquire); while(cprops) { ALcontextProps *next{cprops->next.load(std::memory_order_relaxed)}; @@ -2461,17 +2461,17 @@ ALCcontext::~ALCcontext() } TRACE("Freed %zu context property object%s\n", count, (count==1)?"":"s"); - count = std::accumulate(SourceList.cbegin(), SourceList.cend(), size_t{0u}, + count = std::accumulate(mSourceList.cbegin(), mSourceList.cend(), size_t{0u}, [](size_t cur, const SourceSubList &sublist) noexcept -> size_t { return cur + POPCNT64(~sublist.FreeMask); } ); if(count > 0) WARN("%zu Source%s not deleted\n", count, (count==1)?"":"s"); - SourceList.clear(); - NumSources = 0; + mSourceList.clear(); + mNumSources = 0; count = 0; - ALeffectslotProps *eprops{FreeEffectslotProps.exchange(nullptr, std::memory_order_acquire)}; + ALeffectslotProps *eprops{mFreeEffectslotProps.exchange(nullptr, std::memory_order_acquire)}; while(eprops) { ALeffectslotProps *next{eprops->next.load(std::memory_order_relaxed)}; @@ -2482,20 +2482,20 @@ ALCcontext::~ALCcontext() } TRACE("Freed %zu AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s"); - delete ActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed); - DefaultSlot = nullptr; + delete mActiveAuxSlots.exchange(nullptr, std::memory_order_relaxed); + mDefaultSlot = nullptr; - count = std::accumulate(EffectSlotList.cbegin(), EffectSlotList.cend(), size_t{0u}, + count = std::accumulate(mEffectSlotList.cbegin(), mEffectSlotList.cend(), size_t{0u}, [](size_t cur, const EffectSlotSubList &sublist) noexcept -> size_t { return cur + POPCNT64(~sublist.FreeMask); } ); if(count > 0) WARN("%zu AuxiliaryEffectSlot%s not deleted\n", count, (count==1)?"":"s"); - EffectSlotList.clear(); - NumEffectSlots = 0; + mEffectSlotList.clear(); + mNumEffectSlots = 0; count = 0; - ALvoiceProps *vprops{FreeVoiceProps.exchange(nullptr, std::memory_order_acquire)}; + ALvoiceProps *vprops{mFreeVoiceProps.exchange(nullptr, std::memory_order_acquire)}; while(vprops) { ALvoiceProps *next{vprops->next.load(std::memory_order_relaxed)}; @@ -2505,17 +2505,17 @@ ALCcontext::~ALCcontext() } TRACE("Freed %zu voice property object%s\n", count, (count==1)?"":"s"); - Voices = nullptr; - VoiceCount.store(0, std::memory_order_relaxed); + mVoices = nullptr; + mVoiceCount.store(0, std::memory_order_relaxed); - ALlistenerProps *lprops{Listener.Update.exchange(nullptr, std::memory_order_relaxed)}; + ALlistenerProps *lprops{mListener.Update.exchange(nullptr, std::memory_order_relaxed)}; if(lprops) { TRACE("Freed unapplied listener update %p\n", lprops); al_free(lprops); } count = 0; - lprops = FreeListenerProps.exchange(nullptr, std::memory_order_acquire); + lprops = mFreeListenerProps.exchange(nullptr, std::memory_order_acquire); while(lprops) { ALlistenerProps *next{lprops->next.load(std::memory_order_relaxed)}; @@ -2525,10 +2525,10 @@ ALCcontext::~ALCcontext() } TRACE("Freed %zu listener property object%s\n", count, (count==1)?"":"s"); - if(AsyncEvents) + if(mAsyncEvents) { count = 0; - auto evt_vec = AsyncEvents->getReadVector(); + auto evt_vec = mAsyncEvents->getReadVector(); if(evt_vec.first.len > 0) { al::destroy_n(reinterpret_cast(evt_vec.first.buf), evt_vec.first.len); @@ -2541,10 +2541,10 @@ ALCcontext::~ALCcontext() } if(count > 0) TRACE("Destructed %zu orphaned event%s\n", count, (count==1)?"":"s"); - AsyncEvents->readAdvance(count); + mAsyncEvents->readAdvance(count); } - ALCdevice_DecRef(Device); + ALCdevice_DecRef(mDevice); } /* ReleaseContext @@ -2612,13 +2612,13 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) static void ALCcontext_IncRef(ALCcontext *context) { - auto ref = IncrementRef(&context->ref); + auto ref = IncrementRef(&context->mRef); TRACEREF("ALCcontext %p increasing refcount to %u\n", context, ref); } void ALCcontext_DecRef(ALCcontext *context) { - auto ref = DecrementRef(&context->ref); + auto ref = DecrementRef(&context->mRef); TRACEREF("ALCcontext %p decreasing refcount to %u\n", context, ref); if(UNLIKELY(ref == 0)) delete context; } @@ -2661,10 +2661,10 @@ ContextRef GetContextRef(void) void AllocateVoices(ALCcontext *context, size_t num_voices) { - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; const ALsizei num_sends{device->NumAuxSends}; - if(context->Voices && num_voices == context->Voices->size()) + if(context->mVoices && num_voices == context->mVoices->size()) return; std::unique_ptr> voices; @@ -2673,11 +2673,11 @@ void AllocateVoices(ALCcontext *context, size_t num_voices) voices.reset(new (ptr) al::FlexArray{num_voices}); } - const size_t v_count{minz(context->VoiceCount.load(std::memory_order_relaxed), num_voices)}; - if(context->Voices) + const size_t v_count{minz(context->mVoiceCount.load(std::memory_order_relaxed), num_voices)}; + if(context->mVoices) { /* Copy the old voice data to the new storage. */ - auto viter = std::move(context->Voices->begin(), context->Voices->begin()+v_count, + auto viter = std::move(context->mVoices->begin(), context->mVoices->begin()+v_count, voices->begin()); /* Clear extraneous property set sends. */ @@ -2697,8 +2697,8 @@ void AllocateVoices(ALCcontext *context, size_t num_voices) std::for_each(voices->begin(), viter, clear_sends); } - context->Voices = std::move(voices); - context->VoiceCount.store(static_cast(v_count), std::memory_order_relaxed); + context->mVoices = std::move(voices); + context->mVoiceCount.store(static_cast(v_count), std::memory_order_relaxed); } @@ -3444,7 +3444,7 @@ START_API_FUNC dev->LastError.store(ALC_NO_ERROR); ContextRef context{new ALCcontext{dev.get()}}; - ALCdevice_IncRef(context->Device); + ALCdevice_IncRef(context->mDevice); ALCenum err{UpdateDeviceParams(dev.get(), attrList)}; if(err != ALC_NO_ERROR) @@ -3461,12 +3461,12 @@ START_API_FUNC if(DefaultEffect.type != AL_EFFECT_NULL && dev->Type == Playback) { void *ptr{al_calloc(16, sizeof(ALeffectslot))}; - context->DefaultSlot = std::unique_ptr{new (ptr) ALeffectslot{}}; - if(InitEffectSlot(context->DefaultSlot.get()) == AL_NO_ERROR) - aluInitEffectPanning(context->DefaultSlot.get(), dev.get()); + context->mDefaultSlot = std::unique_ptr{new (ptr) ALeffectslot{}}; + if(InitEffectSlot(context->mDefaultSlot.get()) == AL_NO_ERROR) + aluInitEffectPanning(context->mDefaultSlot.get(), dev.get()); else { - context->DefaultSlot = nullptr; + context->mDefaultSlot = nullptr; ERR("Failed to initialize the default effect slot\n"); } } @@ -3483,8 +3483,8 @@ START_API_FUNC const ALfloat db{clampf(valf, -24.0f, 24.0f)}; if(db != valf) WARN("volume-adjust clamped: %f, range: +/-%f\n", valf, 24.0f); - context->GainBoost = std::pow(10.0f, db/20.0f); - TRACE("volume-adjust gain: %f\n", context->GainBoost); + context->mGainBoost = std::pow(10.0f, db/20.0f); + TRACE("volume-adjust gain: %f\n", context->mGainBoost); } } UpdateListenerProps(context.get()); @@ -3526,10 +3526,10 @@ START_API_FUNC ContextList.insert(iter, ContextRef{context.get()}); } - if(context->DefaultSlot) + if(context->mDefaultSlot) { - if(InitializeEffect(context.get(), context->DefaultSlot.get(), &DefaultEffect) == AL_NO_ERROR) - UpdateEffectSlotProps(context->DefaultSlot.get(), context.get()); + if(InitializeEffect(context.get(), context->mDefaultSlot.get(), &DefaultEffect) == AL_NO_ERROR) + UpdateEffectSlotProps(context->mDefaultSlot.get(), context.get()); else ERR("Failed to initialize the default effect\n"); } @@ -3560,7 +3560,7 @@ START_API_FUNC ContextRef ctx{std::move(*iter)}; ContextList.erase(iter); - ALCdevice *Device{ctx->Device}; + ALCdevice *Device{ctx->mDevice}; std::lock_guard _{Device->StateLock}; if(!ReleaseContext(ctx.get(), Device) && Device->Flags.get()) @@ -3671,7 +3671,7 @@ START_API_FUNC alcSetError(nullptr, ALC_INVALID_CONTEXT); return nullptr; } - return ctx->Device; + return ctx->mDevice; } END_API_FUNC diff --git a/alc/alcontext.h b/alc/alcontext.h index a2da77b0..8156c345 100644 --- a/alc/alcontext.h +++ b/alc/alcontext.h @@ -73,70 +73,70 @@ struct EffectSlotSubList { }; struct ALCcontext { - RefCount ref{1u}; + RefCount mRef{1u}; - al::vector SourceList; - ALuint NumSources{0}; - std::mutex SourceLock; + al::vector mSourceList; + ALuint mNumSources{0}; + std::mutex mSourceLock; - al::vector EffectSlotList; - ALuint NumEffectSlots{0u}; - std::mutex EffectSlotLock; + al::vector mEffectSlotList; + ALuint mNumEffectSlots{0u}; + std::mutex mEffectSlotLock; - std::atomic LastError{AL_NO_ERROR}; + std::atomic mLastError{AL_NO_ERROR}; DistanceModel mDistanceModel{DistanceModel::Default}; - ALboolean SourceDistanceModel{AL_FALSE}; + ALboolean mSourceDistanceModel{AL_FALSE}; - ALfloat DopplerFactor{1.0f}; - ALfloat DopplerVelocity{1.0f}; - ALfloat SpeedOfSound{}; - ALfloat MetersPerUnit{1.0f}; + ALfloat mDopplerFactor{1.0f}; + ALfloat mDopplerVelocity{1.0f}; + ALfloat mSpeedOfSound{}; + ALfloat mMetersPerUnit{1.0f}; - std::atomic_flag PropsClean; - std::atomic DeferUpdates{false}; + std::atomic_flag mPropsClean; + std::atomic mDeferUpdates{false}; - std::mutex PropLock; + std::mutex mPropLock; /* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit * indicates if updates are currently happening). */ - RefCount UpdateCount{0u}; - std::atomic HoldUpdates{false}; + RefCount mUpdateCount{0u}; + std::atomic mHoldUpdates{false}; - ALfloat GainBoost{1.0f}; + ALfloat mGainBoost{1.0f}; - std::atomic Update{nullptr}; + std::atomic mUpdate{nullptr}; /* Linked lists of unused property containers, free to use for future * updates. */ - std::atomic FreeContextProps{nullptr}; - std::atomic FreeListenerProps{nullptr}; - std::atomic FreeVoiceProps{nullptr}; - std::atomic FreeEffectslotProps{nullptr}; + std::atomic mFreeContextProps{nullptr}; + std::atomic mFreeListenerProps{nullptr}; + std::atomic mFreeVoiceProps{nullptr}; + std::atomic mFreeEffectslotProps{nullptr}; - std::unique_ptr> Voices{nullptr}; - std::atomic VoiceCount{0u}; + std::unique_ptr> mVoices{nullptr}; + std::atomic mVoiceCount{0u}; using ALeffectslotArray = al::FlexArray; - std::atomic ActiveAuxSlots{nullptr}; + std::atomic mActiveAuxSlots{nullptr}; - std::thread EventThread; - al::semaphore EventSem; - std::unique_ptr AsyncEvents; - std::atomic EnabledEvts{0u}; - std::mutex EventCbLock; - ALEVENTPROCSOFT EventCb{}; - void *EventParam{nullptr}; + std::thread mEventThread; + al::semaphore mEventSem; + std::unique_ptr mAsyncEvents; + std::atomic mEnabledEvts{0u}; + std::mutex mEventCbLock; + ALEVENTPROCSOFT mEventCb{}; + void *mEventParam{nullptr}; /* Default effect slot */ - std::unique_ptr DefaultSlot; + std::unique_ptr mDefaultSlot; - ALCdevice *const Device; - const ALCchar *ExtensionList{nullptr}; + ALCdevice *const mDevice; + const ALCchar *mExtensionList{nullptr}; - ALlistener Listener{}; + ALlistener mListener{}; ALCcontext(ALCdevice *device); diff --git a/alc/alu.cpp b/alc/alu.cpp index b2e1effa..2469d08d 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -279,10 +279,10 @@ alu::Vector operator*(const alu::Matrix &mtx, const alu::Vector &vec) noexcept bool CalcContextParams(ALCcontext *Context) { - ALcontextProps *props{Context->Update.exchange(nullptr, std::memory_order_acq_rel)}; + ALcontextProps *props{Context->mUpdate.exchange(nullptr, std::memory_order_acq_rel)}; if(!props) return false; - ALlistener &Listener = Context->Listener; + ALlistener &Listener = Context->mListener; Listener.Params.MetersPerUnit = props->MetersPerUnit; Listener.Params.DopplerFactor = props->DopplerFactor; @@ -294,13 +294,13 @@ bool CalcContextParams(ALCcontext *Context) Listener.Params.SourceDistanceModel = props->SourceDistanceModel; Listener.Params.mDistanceModel = props->mDistanceModel; - AtomicReplaceHead(Context->FreeContextProps, props); + AtomicReplaceHead(Context->mFreeContextProps, props); return true; } bool CalcListenerParams(ALCcontext *Context) { - ALlistener &Listener = Context->Listener; + ALlistener &Listener = Context->mListener; ALlistenerProps *props{Listener.Update.exchange(nullptr, std::memory_order_acq_rel)}; if(!props) return false; @@ -328,9 +328,9 @@ bool CalcListenerParams(ALCcontext *Context) const alu::Vector vel{props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f}; Listener.Params.Velocity = Listener.Params.Matrix * vel; - Listener.Params.Gain = props->Gain * Context->GainBoost; + Listener.Params.Gain = props->Gain * Context->mGainBoost; - AtomicReplaceHead(Context->FreeListenerProps, props); + AtomicReplaceHead(Context->mFreeListenerProps, props); return true; } @@ -391,14 +391,14 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) /* Otherwise, if it would be deleted, send it off with a release * event. */ - RingBuffer *ring{context->AsyncEvents.get()}; + RingBuffer *ring{context->mAsyncEvents.get()}; auto evt_vec = ring->getWriteVector(); if(LIKELY(evt_vec.first.len > 0)) { AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_ReleaseEffectState}}; evt->u.mEffectState = oldstate; ring->writeAdvance(1); - context->EventSem.post(); + context->mEventSem.post(); } else { @@ -411,7 +411,7 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) } } - AtomicReplaceHead(context->FreeEffectslotProps, props); + AtomicReplaceHead(context->mFreeEffectslotProps, props); } EffectTarget output; @@ -419,7 +419,7 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) output = EffectTarget{&target->Wet, nullptr}; else { - ALCdevice *device{context->Device}; + ALCdevice *device{context->mDevice}; output = EffectTarget{&device->Dry, &device->RealOut}; } state->update(context, slot, &slot->Params.mEffectProps, output); @@ -960,7 +960,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const ALCcontext *ALContext) { - const ALCdevice *Device{ALContext->Device}; + const ALCdevice *Device{ALContext->mDevice}; ALeffectslot *SendSlots[MAX_SENDS]; voice->mDirect.Buffer = Device->Dry.Buffer; @@ -968,7 +968,7 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons { SendSlots[i] = props->Send[i].Slot; if(!SendSlots[i] && i == 0) - SendSlots[i] = ALContext->DefaultSlot.get(); + SendSlots[i] = ALContext->mDefaultSlot.get(); if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) { SendSlots[i] = nullptr; @@ -992,7 +992,7 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons voice->mResampler = SelectResampler(props->mResampler); /* Calculate gains */ - const ALlistener &Listener = ALContext->Listener; + const ALlistener &Listener = ALContext->mListener; ALfloat DryGain{clampf(props->Gain, props->MinGain, props->MaxGain)}; DryGain *= props->Direct.Gain * Listener.Params.Gain; DryGain = minf(DryGain, GAIN_MIX_MAX); @@ -1014,9 +1014,9 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const ALCcontext *ALContext) { - const ALCdevice *Device{ALContext->Device}; + const ALCdevice *Device{ALContext->mDevice}; const ALsizei NumSends{Device->NumAuxSends}; - const ALlistener &Listener = ALContext->Listener; + const ALlistener &Listener = ALContext->mListener; /* Set mixing buffers and get send parameters. */ voice->mDirect.Buffer = Device->Dry.Buffer; @@ -1029,7 +1029,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A { SendSlots[i] = props->Send[i].Slot; if(!SendSlots[i] && i == 0) - SendSlots[i] = ALContext->DefaultSlot.get(); + SendSlots[i] = ALContext->mDefaultSlot.get(); if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) { SendSlots[i] = nullptr; @@ -1342,7 +1342,7 @@ void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) { voice->mProps = *props; - AtomicReplaceHead(context->FreeVoiceProps, props); + AtomicReplaceHead(context->mFreeVoiceProps, props); } if((voice->mProps.mSpatializeMode == SpatializeAuto && voice->mFmtChannels == FmtMono) || @@ -1355,8 +1355,8 @@ void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray *slots) { - IncrementRef(&ctx->UpdateCount); - if(LIKELY(!ctx->HoldUpdates.load(std::memory_order_acquire))) + IncrementRef(&ctx->mUpdateCount); + if(LIKELY(!ctx->mHoldUpdates.load(std::memory_order_acquire))) { bool cforce{CalcContextParams(ctx)}; bool force{CalcListenerParams(ctx) || cforce}; @@ -1365,8 +1365,8 @@ void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray *slots) { return CalcEffectSlotParams(slot, ctx, cforce) | force; } ); - std::for_each(ctx->Voices->begin(), - ctx->Voices->begin() + ctx->VoiceCount.load(std::memory_order_acquire), + std::for_each(ctx->mVoices->begin(), + ctx->mVoices->begin() + ctx->mVoiceCount.load(std::memory_order_acquire), [ctx,force](ALvoice &voice) -> void { ALuint sid{voice.mSourceID.load(std::memory_order_acquire)}; @@ -1374,14 +1374,14 @@ void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray *slots) } ); } - IncrementRef(&ctx->UpdateCount); + IncrementRef(&ctx->mUpdateCount); } void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) { ASSUME(SamplesToDo > 0); - const ALeffectslotArray *auxslots{ctx->ActiveAuxSlots.load(std::memory_order_acquire)}; + const ALeffectslotArray *auxslots{ctx->mActiveAuxSlots.load(std::memory_order_acquire)}; /* Process pending propery updates for objects on the context. */ ProcessParamUpdates(ctx, auxslots); @@ -1396,8 +1396,8 @@ void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) ); /* Process voices that have a playing source. */ - std::for_each(ctx->Voices->begin(), - ctx->Voices->begin() + ctx->VoiceCount.load(std::memory_order_acquire), + std::for_each(ctx->mVoices->begin(), + ctx->mVoices->begin() + ctx->mVoiceCount.load(std::memory_order_acquire), [SamplesToDo,ctx](ALvoice &voice) -> void { const ALvoice::State vstate{voice.mPlayState.load(std::memory_order_acquire)}; @@ -1772,16 +1772,16 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) for(ALCcontext *ctx : *device->mContexts.load()) { - const ALbitfieldSOFT enabledevt{ctx->EnabledEvts.load(std::memory_order_acquire)}; + const ALbitfieldSOFT enabledevt{ctx->mEnabledEvts.load(std::memory_order_acquire)}; if((enabledevt&EventType_Disconnected)) { - RingBuffer *ring{ctx->AsyncEvents.get()}; + RingBuffer *ring{ctx->mAsyncEvents.get()}; auto evt_data = ring->getWriteVector().first; if(evt_data.len > 0) { new (evt_data.buf) AsyncEvent{evt}; ring->writeAdvance(1); - ctx->EventSem.post(); + ctx->mEventSem.post(); } } @@ -1792,8 +1792,8 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) voice.mSourceID.store(0u, std::memory_order_relaxed); voice.mPlayState.store(ALvoice::Stopped, std::memory_order_release); }; - std::for_each(ctx->Voices->begin(), - ctx->Voices->begin() + ctx->VoiceCount.load(std::memory_order_acquire), + std::for_each(ctx->mVoices->begin(), + ctx->mVoices->begin() + ctx->mVoiceCount.load(std::memory_order_acquire), stop_voice); } } diff --git a/alc/effects/autowah.cpp b/alc/effects/autowah.cpp index 298d5c96..d92e114a 100644 --- a/alc/effects/autowah.cpp +++ b/alc/effects/autowah.cpp @@ -107,7 +107,7 @@ ALboolean ALautowahState::deviceUpdate(const ALCdevice*) void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { - const ALCdevice *device{context->Device}; + const ALCdevice *device{context->mDevice}; const ALfloat ReleaseTime{clampf(props->Autowah.ReleaseTime, 0.001f, 1.0f)}; diff --git a/alc/effects/chorus.cpp b/alc/effects/chorus.cpp index 28514a9b..7a473723 100644 --- a/alc/effects/chorus.cpp +++ b/alc/effects/chorus.cpp @@ -158,7 +158,7 @@ void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, co /* The LFO depth is scaled to be relative to the sample delay. Clamp the * delay and depth to allow enough padding for resampling. */ - const ALCdevice *device{Context->Device}; + const ALCdevice *device{Context->mDevice}; const auto frequency = static_cast(device->Frequency); mDelay = maxi(float2int(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f), mindelay); mDepth = minf(props->Chorus.Depth * mDelay, static_cast(mDelay - mindelay)); diff --git a/alc/effects/distortion.cpp b/alc/effects/distortion.cpp index a74575d4..79278f0d 100644 --- a/alc/effects/distortion.cpp +++ b/alc/effects/distortion.cpp @@ -64,7 +64,7 @@ ALboolean DistortionState::deviceUpdate(const ALCdevice*) void DistortionState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { - const ALCdevice *device{context->Device}; + const ALCdevice *device{context->mDevice}; /* Store waveshaper edge settings. */ const ALfloat edge{ diff --git a/alc/effects/echo.cpp b/alc/effects/echo.cpp index 8e309cbb..9a43c037 100644 --- a/alc/effects/echo.cpp +++ b/alc/effects/echo.cpp @@ -94,7 +94,7 @@ ALboolean EchoState::deviceUpdate(const ALCdevice *Device) void EchoState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { - const ALCdevice *device = context->Device; + const ALCdevice *device = context->mDevice; const auto frequency = static_cast(device->Frequency); mTap[0].delay = maxi(float2int(props->Echo.Delay*frequency + 0.5f), 1); diff --git a/alc/effects/equalizer.cpp b/alc/effects/equalizer.cpp index 0ae3a25f..25ccf264 100644 --- a/alc/effects/equalizer.cpp +++ b/alc/effects/equalizer.cpp @@ -112,7 +112,7 @@ ALboolean EqualizerState::deviceUpdate(const ALCdevice*) void EqualizerState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { - const ALCdevice *device = context->Device; + const ALCdevice *device = context->mDevice; auto frequency = static_cast(device->Frequency); ALfloat gain, f0norm; diff --git a/alc/effects/fshifter.cpp b/alc/effects/fshifter.cpp index b36c53a1..9b204d2e 100644 --- a/alc/effects/fshifter.cpp +++ b/alc/effects/fshifter.cpp @@ -109,7 +109,7 @@ ALboolean FshifterState::deviceUpdate(const ALCdevice*) void FshifterState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { - const ALCdevice *device{context->Device}; + const ALCdevice *device{context->mDevice}; ALfloat step{props->Fshifter.Frequency / static_cast(device->Frequency)}; mPhaseStep = fastf2i(minf(step, 0.5f) * FRACTIONONE); diff --git a/alc/effects/modulator.cpp b/alc/effects/modulator.cpp index 5f28e1da..bd63c56c 100644 --- a/alc/effects/modulator.cpp +++ b/alc/effects/modulator.cpp @@ -110,7 +110,7 @@ ALboolean ModulatorState::deviceUpdate(const ALCdevice*) void ModulatorState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { - const ALCdevice *device{context->Device}; + const ALCdevice *device{context->mDevice}; const float step{props->Modulator.Frequency / static_cast(device->Frequency)}; mStep = fastf2i(clampf(step*WAVEFORM_FRACONE, 0.0f, ALfloat{WAVEFORM_FRACONE-1})); diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 82b04436..bc4995ff 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -906,8 +906,8 @@ void ReverbState::update3DPanning(const ALfloat *ReflectionsPan, const ALfloat * void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, const EffectProps *props, const EffectTarget target) { - const ALCdevice *Device{Context->Device}; - const ALlistener &Listener = Context->Listener; + const ALCdevice *Device{Context->mDevice}; + const ALlistener &Listener = Context->mListener; const auto frequency = static_cast(Device->Frequency); /* Calculate the master filters */ diff --git a/alc/effects/vmorpher.cpp b/alc/effects/vmorpher.cpp index d1bf8587..ae8c98e1 100644 --- a/alc/effects/vmorpher.cpp +++ b/alc/effects/vmorpher.cpp @@ -210,7 +210,7 @@ ALboolean VmorpherState::deviceUpdate(const ALCdevice* /*device*/) void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { - const ALCdevice *device{context->Device}; + const ALCdevice *device{context->mDevice}; const ALfloat frequency{static_cast(device->Frequency)}; const ALfloat step{props->Vmorpher.Rate / static_cast(device->Frequency)}; mStep = fastf2i(clampf(step*WAVEFORM_FRACONE, 0.0f, ALfloat{WAVEFORM_FRACONE-1})); diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 0d7b2cee..881759c0 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -291,10 +291,10 @@ constexpr ALshort aLawDecompressionTable[256] = { void SendSourceStoppedEvent(ALCcontext *context, ALuint id) { - ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)}; + ALbitfieldSOFT enabledevt{context->mEnabledEvts.load(std::memory_order_acquire)}; if(!(enabledevt&EventType_SourceStateChange)) return; - RingBuffer *ring{context->AsyncEvents.get()}; + RingBuffer *ring{context->mAsyncEvents.get()}; auto evt_vec = ring->getWriteVector(); if(evt_vec.first.len < 1) return; @@ -303,7 +303,7 @@ void SendSourceStoppedEvent(ALCcontext *context, ALuint id) evt->u.srcstate.state = AL_STOPPED; ring->writeAdvance(1); - context->EventSem.post(); + context->mEventSem.post(); } @@ -544,7 +544,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc ASSUME(SampleSize > 0); ASSUME(increment > 0); - ALCdevice *Device{Context->Device}; + ALCdevice *Device{Context->mDevice}; const ALsizei NumSends{Device->NumAuxSends}; const ALsizei IrSize{Device->mHrtf ? Device->mHrtf->irSize : 0}; @@ -929,10 +929,10 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc std::atomic_thread_fence(std::memory_order_release); /* Send any events now, after the position/buffer info was updated. */ - ALbitfieldSOFT enabledevt{Context->EnabledEvts.load(std::memory_order_acquire)}; + ALbitfieldSOFT enabledevt{Context->mEnabledEvts.load(std::memory_order_acquire)}; if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) { - RingBuffer *ring{Context->AsyncEvents.get()}; + RingBuffer *ring{Context->mAsyncEvents.get()}; auto evt_vec = ring->getWriteVector(); if(evt_vec.first.len > 0) { @@ -940,7 +940,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc evt->u.bufcomp.id = SourceID; evt->u.bufcomp.count = buffers_done; ring->writeAdvance(1); - Context->EventSem.post(); + Context->mEventSem.post(); } } -- cgit v1.2.3 From ac554de67d5eb353283c3359bbac15fb4ddad7d9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 Jul 2019 14:13:05 -0700 Subject: Turn some functions into methods --- al/source.cpp | 2 +- al/state.cpp | 4 +-- alc/alc.cpp | 77 ++++++++++++++++++++++----------------------------------- alc/alcmain.h | 3 --- alc/alcontext.h | 22 ++++++++++++----- 5 files changed, 48 insertions(+), 60 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index 39b635a4..35d3bb84 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -2828,7 +2828,7 @@ START_API_FUNC alloc_count); const size_t newcount{context->mVoices->size() + alloc_count}; - AllocateVoices(context.get(), newcount); + context->allocVoices(newcount); } context->mVoiceCount.fetch_add(need_voices, std::memory_order_relaxed); diff --git a/al/state.cpp b/al/state.cpp index b1885f5c..903ab614 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -775,7 +775,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCcontext_DeferUpdates(context.get()); + context->deferUpdates(); } END_API_FUNC @@ -785,7 +785,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCcontext_ProcessUpdates(context.get()); + context->processUpdates(); } END_API_FUNC diff --git a/alc/alc.cpp b/alc/alc.cpp index 49ecf54b..db5fd094 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -1591,44 +1591,29 @@ void SetDefaultChannelOrder(ALCdevice *device) } -/* ALCcontext_DeferUpdates - * - * Defers/suspends updates for the given context's listener and sources. This - * does *NOT* stop mixing, but rather prevents certain property changes from - * taking effect. - */ -void ALCcontext_DeferUpdates(ALCcontext *context) +void ALCcontext::processUpdates() { - context->mDeferUpdates.store(true); -} - -/* ALCcontext_ProcessUpdates - * - * Resumes update processing after being deferred. - */ -void ALCcontext_ProcessUpdates(ALCcontext *context) -{ - std::lock_guard _{context->mPropLock}; - if(context->mDeferUpdates.exchange(false)) + std::lock_guard _{mPropLock}; + if(mDeferUpdates.exchange(false)) { /* Tell the mixer to stop applying updates, then wait for any active * updating to finish, before providing updates. */ - context->mHoldUpdates.store(true, std::memory_order_release); - while((context->mUpdateCount.load(std::memory_order_acquire)&1) != 0) + mHoldUpdates.store(true, std::memory_order_release); + while((mUpdateCount.load(std::memory_order_acquire)&1) != 0) std::this_thread::yield(); - if(!context->mPropsClean.test_and_set(std::memory_order_acq_rel)) - UpdateContextProps(context); - if(!context->mListener.PropsClean.test_and_set(std::memory_order_acq_rel)) - UpdateListenerProps(context); - UpdateAllEffectSlotProps(context); - UpdateAllSourceProps(context); + if(!mPropsClean.test_and_set(std::memory_order_acq_rel)) + UpdateContextProps(this); + if(!mListener.PropsClean.test_and_set(std::memory_order_acq_rel)) + UpdateListenerProps(this); + UpdateAllEffectSlotProps(this); + UpdateAllSourceProps(this); /* Now with all updates declared, let the mixer continue applying them * so they all happen at once. */ - context->mHoldUpdates.store(false, std::memory_order_release); + mHoldUpdates.store(false, std::memory_order_release); } } @@ -2559,12 +2544,12 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) { WARN("%p released while current on thread\n", context); LocalContext.set(nullptr); - ALCcontext_DecRef(context); + context->decRef(); } ALCcontext *origctx{context}; if(GlobalContext.compare_exchange_strong(origctx, nullptr)) - ALCcontext_DecRef(context); + context->decRef(); bool ret{}; { @@ -2616,11 +2601,11 @@ static void ALCcontext_IncRef(ALCcontext *context) TRACEREF("ALCcontext %p increasing refcount to %u\n", context, ref); } -void ALCcontext_DecRef(ALCcontext *context) +void ALCcontext::decRef() noexcept { - auto ref = DecrementRef(&context->mRef); - TRACEREF("ALCcontext %p decreasing refcount to %u\n", context, ref); - if(UNLIKELY(ref == 0)) delete context; + auto ref = DecrementRef(&mRef); + TRACEREF("ALCcontext %p decreasing refcount to %u\n", this, ref); + if(UNLIKELY(ref == 0)) delete this; } /* VerifyContext @@ -2659,12 +2644,11 @@ ContextRef GetContextRef(void) } -void AllocateVoices(ALCcontext *context, size_t num_voices) +void ALCcontext::allocVoices(size_t num_voices) { - ALCdevice *device{context->mDevice}; - const ALsizei num_sends{device->NumAuxSends}; + const ALsizei num_sends{mDevice->NumAuxSends}; - if(context->mVoices && num_voices == context->mVoices->size()) + if(mVoices && num_voices == mVoices->size()) return; std::unique_ptr> voices; @@ -2673,12 +2657,11 @@ void AllocateVoices(ALCcontext *context, size_t num_voices) voices.reset(new (ptr) al::FlexArray{num_voices}); } - const size_t v_count{minz(context->mVoiceCount.load(std::memory_order_relaxed), num_voices)}; - if(context->mVoices) + const size_t v_count{minz(mVoiceCount.load(std::memory_order_relaxed), num_voices)}; + if(mVoices) { /* Copy the old voice data to the new storage. */ - auto viter = std::move(context->mVoices->begin(), context->mVoices->begin()+v_count, - voices->begin()); + auto viter = std::move(mVoices->begin(), mVoices->begin()+v_count, voices->begin()); /* Clear extraneous property set sends. */ auto clear_sends = [num_sends](ALvoice &voice) -> void @@ -2697,8 +2680,8 @@ void AllocateVoices(ALCcontext *context, size_t num_voices) std::for_each(voices->begin(), viter, clear_sends); } - context->mVoices = std::move(voices); - context->mVoiceCount.store(static_cast(v_count), std::memory_order_relaxed); + mVoices = std::move(voices); + mVoiceCount.store(static_cast(v_count), std::memory_order_relaxed); } @@ -2734,7 +2717,7 @@ START_API_FUNC if(!ctx) alcSetError(nullptr, ALC_INVALID_CONTEXT); else - ALCcontext_DeferUpdates(ctx.get()); + ctx->deferUpdates(); } END_API_FUNC @@ -2752,7 +2735,7 @@ START_API_FUNC if(!ctx) alcSetError(nullptr, ALC_INVALID_CONTEXT); else - ALCcontext_ProcessUpdates(ctx.get()); + ctx->processUpdates(); } END_API_FUNC @@ -3452,11 +3435,9 @@ START_API_FUNC alcSetError(dev.get(), err); if(err == ALC_INVALID_DEVICE) aluHandleDisconnect(dev.get(), "Device update failure"); - statelock.unlock(); - return nullptr; } - AllocateVoices(context.get(), 256); + context->allocVoices(256); if(DefaultEffect.type != AL_EFFECT_NULL && dev->Type == Playback) { diff --git a/alc/alcmain.h b/alc/alcmain.h index 85f37e73..f69dc755 100644 --- a/alc/alcmain.h +++ b/alc/alcmain.h @@ -461,9 +461,6 @@ struct ALCdevice { #define RECORD_THREAD_NAME "alsoft-record" -void AllocateVoices(ALCcontext *context, size_t num_voices); - - extern ALint RTPrioLevel; void SetRTPriority(void); diff --git a/alc/alcontext.h b/alc/alcontext.h index 8156c345..9c2ce4a3 100644 --- a/alc/alcontext.h +++ b/alc/alcontext.h @@ -144,16 +144,26 @@ struct ALCcontext { ALCcontext& operator=(const ALCcontext&) = delete; ~ALCcontext(); + void decRef() noexcept; + + void allocVoices(size_t num_voices); + + /** + * Defers/suspends updates for the given context's listener and sources. + * This does *NOT* stop mixing, but rather prevents certain property + * changes from taking effect. + */ + void deferUpdates() noexcept + { mDeferUpdates.store(true); } + + /** Resumes update processing after being deferred. */ + void processUpdates(); + DEF_NEWDEL(ALCcontext) }; -void ALCcontext_DecRef(ALCcontext *context); - void UpdateContextProps(ALCcontext *context); -void ALCcontext_DeferUpdates(ALCcontext *context); -void ALCcontext_ProcessUpdates(ALCcontext *context); - /* Simple RAII context reference. Takes the reference of the provided * ALCcontext, and decrements it when leaving scope. Movable (transfer @@ -165,7 +175,7 @@ class ContextRef { void reset() noexcept { if(mCtx) - ALCcontext_DecRef(mCtx); + mCtx->decRef(); mCtx = nullptr; } -- cgit v1.2.3 From f286c3fa3857579a6c7cf84f32ff953e498577bf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 Jul 2019 21:32:05 -0700 Subject: Move another function to a ALCcontext method --- CMakeLists.txt | 1 - al/auxeffectslot.cpp | 77 ++++++++------- al/buffer.cpp | 185 ++++++++++++++++++------------------ al/effect.cpp | 29 +++--- al/error.cpp | 19 ++-- al/error.h | 24 ----- al/event.cpp | 7 +- al/extension.cpp | 3 +- al/filter.cpp | 81 ++++++++-------- al/listener.cpp | 52 +++++----- al/source.cpp | 230 ++++++++++++++++++++++----------------------- al/state.cpp | 57 ++++++----- alc/alc.cpp | 1 - alc/alcontext.h | 23 +++-- alc/effects/autowah.cpp | 13 ++- alc/effects/chorus.cpp | 17 ++-- alc/effects/compressor.cpp | 17 ++-- alc/effects/dedicated.cpp | 13 ++- alc/effects/distortion.cpp | 15 ++- alc/effects/echo.cpp | 13 ++- alc/effects/equalizer.cpp | 13 ++- alc/effects/fshifter.cpp | 13 ++- alc/effects/modulator.cpp | 9 +- alc/effects/null.cpp | 10 +- alc/effects/pshifter.cpp | 15 +-- alc/effects/reverb.cpp | 23 ++--- alc/effects/vmorpher.cpp | 17 ++-- 27 files changed, 467 insertions(+), 510 deletions(-) delete mode 100644 al/error.h diff --git a/CMakeLists.txt b/CMakeLists.txt index db43215d..e72f2a01 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -612,7 +612,6 @@ SET(OPENAL_OBJS al/effect.cpp al/effect.h al/error.cpp - al/error.h al/extension.cpp al/filter.cpp al/filter.h diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index 880c970d..2d10efde 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -40,7 +40,6 @@ #include "alspan.h" #include "alu.h" #include "effect.h" -#include "error.h" #include "fpu_modes.h" #include "inprogext.h" #include "logging.h" @@ -164,7 +163,7 @@ ALeffectslot *AllocEffectSlot(ALCcontext *context) std::lock_guard _{context->mEffectSlotLock}; if(context->mNumEffectSlots >= device->AuxiliaryEffectSlotMax) { - alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u effect slot limit", + context->setError(AL_OUT_OF_MEMORY, "Exceeding %u effect slot limit", device->AuxiliaryEffectSlotMax); return nullptr; } @@ -187,7 +186,7 @@ ALeffectslot *AllocEffectSlot(ALCcontext *context) */ if(UNLIKELY(context->mEffectSlotList.size() >= 1<<25)) { - alSetError(context, AL_OUT_OF_MEMORY, "Too many effect slots allocated"); + context->setError(AL_OUT_OF_MEMORY, "Too many effect slots allocated"); return nullptr; } context->mEffectSlotList.emplace_back(); @@ -198,7 +197,7 @@ ALeffectslot *AllocEffectSlot(ALCcontext *context) if(UNLIKELY(!sublist->EffectSlots)) { context->mEffectSlotList.pop_back(); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect slot batch"); + context->setError(AL_OUT_OF_MEMORY, "Failed to allocate effect slot batch"); return nullptr; } @@ -211,7 +210,7 @@ ALeffectslot *AllocEffectSlot(ALCcontext *context) if(err != AL_NO_ERROR) { al::destroy_at(slot); - alSetError(context, err, "Effect slot object initialization failed"); + context->setError(err, "Effect slot object initialization failed"); return nullptr; } aluInitEffectPanning(slot, device); @@ -264,7 +263,7 @@ START_API_FUNC if(UNLIKELY(!context)) return; if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Generating %d effect slots", n); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Generating %d effect slots", n); if(n == 0) return; if(n == 1) @@ -307,7 +306,7 @@ START_API_FUNC if(UNLIKELY(!context)) return; if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Deleting %d effect slots", n); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Deleting %d effect slots", n); if(n == 0) return; std::lock_guard _{context->mEffectSlotLock}; @@ -318,12 +317,12 @@ START_API_FUNC ALeffectslot *slot{LookupEffectSlot(context.get(), id)}; if(!slot) { - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect slot ID %u", id); + context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", id); return true; } if(ReadRef(&slot->ref) != 0) { - alSetError(context.get(), AL_INVALID_NAME, "Deleting in-use effect slot %u", id); + context->setError(AL_INVALID_NAME, "Deleting in-use effect slot %u", id); return true; } return false; @@ -369,7 +368,7 @@ START_API_FUNC std::lock_guard __{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); ALeffectslot *target{}; ALCdevice *device{}; @@ -382,34 +381,34 @@ START_API_FUNC { std::lock_guard ___{device->EffectLock}; ALeffect *effect{value ? LookupEffect(device, value) : nullptr}; if(!(value == 0 || effect != nullptr)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Invalid effect ID %u", value); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid effect ID %u", value); err = InitializeEffect(context.get(), slot, effect); } if(err != AL_NO_ERROR) { - alSetError(context.get(), err, "Effect initialization failed"); + context->setError(err, "Effect initialization failed"); return; } break; case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: if(!(value == AL_TRUE || value == AL_FALSE)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, - "Effect slot auxiliary send auto out of range"); + SETERR_RETURN(context, AL_INVALID_VALUE,, + "Effect slot auxiliary send auto out of range"); slot->AuxSendAuto = value; break; case AL_EFFECTSLOT_TARGET_SOFT: target = (value ? LookupEffectSlot(context.get(), value) : nullptr); if(value && !target) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Invalid effect slot target ID"); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid effect slot target ID"); if(target) { ALeffectslot *checker{target}; while(checker && checker != slot) checker = checker->Target; if(checker) - SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, + SETERR_RETURN(context, AL_INVALID_OPERATION,, "Setting target of effect slot ID %u to %u creates circular chain", slot->id, target->id); } @@ -431,8 +430,8 @@ START_API_FUNC break; default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot integer property 0x%04x", param); + SETERR_RETURN(context, AL_INVALID_ENUM,, "Invalid effect slot integer property 0x%04x", + param); } DO_UPDATEPROPS(); } @@ -456,13 +455,13 @@ START_API_FUNC std::lock_guard _{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); switch(param) { default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot integer-vector property 0x%04x", param); + SETERR_RETURN(context, AL_INVALID_ENUM,, + "Invalid effect slot integer-vector property 0x%04x", param); } } END_API_FUNC @@ -477,19 +476,19 @@ START_API_FUNC std::lock_guard __{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); switch(param) { case AL_EFFECTSLOT_GAIN: if(!(value >= 0.0f && value <= 1.0f)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Effect slot gain out of range"); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Effect slot gain out of range"); slot->Gain = value; break; default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, "Invalid effect slot float property 0x%04x", - param); + SETERR_RETURN(context, AL_INVALID_ENUM,, "Invalid effect slot float property 0x%04x", + param); } DO_UPDATEPROPS(); } @@ -511,13 +510,13 @@ START_API_FUNC std::lock_guard _{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); switch(param) { default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot float-vector property 0x%04x", param); + SETERR_RETURN(context, AL_INVALID_ENUM,, + "Invalid effect slot float-vector property 0x%04x", param); } } END_API_FUNC @@ -532,7 +531,7 @@ START_API_FUNC std::lock_guard _{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); switch(param) { @@ -545,8 +544,7 @@ START_API_FUNC break; default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid effect slot integer property 0x%04x", param); } } END_API_FUNC @@ -569,13 +567,13 @@ START_API_FUNC std::lock_guard _{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); switch(param) { default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot integer-vector property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid effect slot integer-vector property 0x%04x", + param); } } END_API_FUNC @@ -589,7 +587,7 @@ START_API_FUNC std::lock_guard _{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); switch(param) { @@ -598,8 +596,7 @@ START_API_FUNC break; default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid effect slot float property 0x%04x", param); } } END_API_FUNC @@ -620,13 +617,13 @@ START_API_FUNC std::lock_guard _{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); if(UNLIKELY(!slot)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); + SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); switch(param) { default: - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, - "Invalid effect slot float-vector property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid effect slot float-vector property 0x%04x", + param); } } END_API_FUNC diff --git a/al/buffer.cpp b/al/buffer.cpp index d4f2d179..d6d743d0 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -48,7 +48,6 @@ #include "alnumeric.h" #include "aloptional.h" #include "atomic.h" -#include "error.h" #include "inprogext.h" #include "opthelpers.h" @@ -269,7 +268,7 @@ ALbuffer *AllocBuffer(ALCcontext *context) */ if(UNLIKELY(device->BufferList.size() >= 1<<25)) { - alSetError(context, AL_OUT_OF_MEMORY, "Too many buffers allocated"); + context->setError(AL_OUT_OF_MEMORY, "Too many buffers allocated"); return nullptr; } device->BufferList.emplace_back(); @@ -279,7 +278,7 @@ ALbuffer *AllocBuffer(ALCcontext *context) if(UNLIKELY(!sublist->Buffers)) { device->BufferList.pop_back(); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate buffer batch"); + context->setError(AL_OUT_OF_MEMORY, "Failed to allocate buffer batch"); return nullptr; } @@ -611,7 +610,7 @@ START_API_FUNC if(UNLIKELY(n < 0)) { - alSetError(context.get(), AL_INVALID_VALUE, "Generating %d buffers", n); + context->setError(AL_INVALID_VALUE, "Generating %d buffers", n); return; } @@ -651,7 +650,7 @@ START_API_FUNC if(UNLIKELY(n < 0)) { - alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d buffers", n); + context->setError(AL_INVALID_VALUE, "Deleting %d buffers", n); return; } if(UNLIKELY(n == 0)) @@ -669,12 +668,12 @@ START_API_FUNC ALbuffer *ALBuf = LookupBuffer(device, bid); if(UNLIKELY(!ALBuf)) { - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", bid); + context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", bid); return true; } if(UNLIKELY(ReadRef(&ALBuf->ref) != 0)) { - alSetError(context.get(), AL_INVALID_OPERATION, "Deleting in-use buffer %u", bid); + context->setError(AL_INVALID_OPERATION, "Deleting in-use buffer %u", bid); return true; } return false; @@ -726,22 +725,22 @@ START_API_FUNC ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(size < 0)) - alSetError(context.get(), AL_INVALID_VALUE, "Negative storage size %d", size); + context->setError(AL_INVALID_VALUE, "Negative storage size %d", size); else if(UNLIKELY(freq < 1)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid sample rate %d", freq); + context->setError(AL_INVALID_VALUE, "Invalid sample rate %d", freq); else if(UNLIKELY((flags&INVALID_STORAGE_MASK) != 0)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid storage flags 0x%x", - flags&INVALID_STORAGE_MASK); + context->setError(AL_INVALID_VALUE, "Invalid storage flags 0x%x", + flags&INVALID_STORAGE_MASK); else if(UNLIKELY((flags&AL_MAP_PERSISTENT_BIT_SOFT) && !(flags&MAP_READ_WRITE_FLAGS))) - alSetError(context.get(), AL_INVALID_VALUE, - "Declaring persistently mapped storage without read or write access"); + context->setError(AL_INVALID_VALUE, + "Declaring persistently mapped storage without read or write access"); else { auto usrfmt = DecomposeUserFormat(format); if(UNLIKELY(!usrfmt)) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid format 0x%04x", format); + context->setError(AL_INVALID_ENUM, "Invalid format 0x%04x", format); else LoadData(context.get(), albuf, freq, size, usrfmt->channels, usrfmt->type, static_cast(data), flags); @@ -760,33 +759,33 @@ START_API_FUNC ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY((access&INVALID_MAP_FLAGS) != 0)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid map flags 0x%x", access&INVALID_MAP_FLAGS); + context->setError(AL_INVALID_VALUE, "Invalid map flags 0x%x", access&INVALID_MAP_FLAGS); else if(UNLIKELY(!(access&MAP_READ_WRITE_FLAGS))) - alSetError(context.get(), AL_INVALID_VALUE, "Mapping buffer %u without read or write access", - buffer); + context->setError(AL_INVALID_VALUE, "Mapping buffer %u without read or write access", + buffer); else { ALbitfieldSOFT unavailable = (albuf->Access^access) & access; if(UNLIKELY(ReadRef(&albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT))) - alSetError(context.get(), AL_INVALID_OPERATION, - "Mapping in-use buffer %u without persistent mapping", buffer); + context->setError(AL_INVALID_OPERATION, + "Mapping in-use buffer %u without persistent mapping", buffer); else if(UNLIKELY(albuf->MappedAccess != 0)) - alSetError(context.get(), AL_INVALID_OPERATION, "Mapping already-mapped buffer %u", buffer); + context->setError(AL_INVALID_OPERATION, "Mapping already-mapped buffer %u", buffer); else if(UNLIKELY((unavailable&AL_MAP_READ_BIT_SOFT))) - alSetError(context.get(), AL_INVALID_VALUE, - "Mapping buffer %u for reading without read access", buffer); + context->setError(AL_INVALID_VALUE, + "Mapping buffer %u for reading without read access", buffer); else if(UNLIKELY((unavailable&AL_MAP_WRITE_BIT_SOFT))) - alSetError(context.get(), AL_INVALID_VALUE, - "Mapping buffer %u for writing without write access", buffer); + context->setError(AL_INVALID_VALUE, + "Mapping buffer %u for writing without write access", buffer); else if(UNLIKELY((unavailable&AL_MAP_PERSISTENT_BIT_SOFT))) - alSetError(context.get(), AL_INVALID_VALUE, - "Mapping buffer %u persistently without persistent access", buffer); + context->setError(AL_INVALID_VALUE, + "Mapping buffer %u persistently without persistent access", buffer); else if(UNLIKELY(offset < 0 || offset >= albuf->OriginalSize || length <= 0 || length > albuf->OriginalSize - offset)) - alSetError(context.get(), AL_INVALID_VALUE, "Mapping invalid range %d+%d for buffer %u", - offset, length, buffer); + context->setError(AL_INVALID_VALUE, "Mapping invalid range %d+%d for buffer %u", + offset, length, buffer); else { void *retval = albuf->mData.data() + offset; @@ -812,9 +811,9 @@ START_API_FUNC ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(albuf->MappedAccess == 0) - alSetError(context.get(), AL_INVALID_OPERATION, "Unmapping unmapped buffer %u", buffer); + context->setError(AL_INVALID_OPERATION, "Unmapping unmapped buffer %u", buffer); else { albuf->MappedAccess = 0; @@ -835,15 +834,15 @@ START_API_FUNC ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT))) - alSetError(context.get(), AL_INVALID_OPERATION, - "Flushing buffer %u while not mapped for writing", buffer); + context->setError(AL_INVALID_OPERATION, "Flushing buffer %u while not mapped for writing", + buffer); else if(UNLIKELY(offset < albuf->MappedOffset || offset >= albuf->MappedOffset+albuf->MappedSize || length <= 0 || length > albuf->MappedOffset+albuf->MappedSize-offset)) - alSetError(context.get(), AL_INVALID_VALUE, "Flushing invalid range %d+%d on buffer %u", - offset, length, buffer); + context->setError(AL_INVALID_VALUE, "Flushing invalid range %d+%d on buffer %u", offset, + length, buffer); else { /* FIXME: Need to use some method of double-buffering for the mixer and @@ -868,32 +867,30 @@ START_API_FUNC ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) { - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); return; } auto usrfmt = DecomposeUserFormat(format); if(UNLIKELY(!usrfmt)) { - alSetError(context.get(), AL_INVALID_ENUM, "Invalid format 0x%04x", format); + context->setError(AL_INVALID_ENUM, "Invalid format 0x%04x", format); return; } ALsizei unpack_align{albuf->UnpackAlign.load()}; ALsizei align{SanitizeAlignment(usrfmt->type, unpack_align)}; if(UNLIKELY(align < 1)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid unpack alignment %d", unpack_align); + context->setError(AL_INVALID_VALUE, "Invalid unpack alignment %d", unpack_align); else if(UNLIKELY(long{usrfmt->channels} != long{albuf->mFmtChannels} || usrfmt->type != albuf->OriginalType)) - alSetError(context.get(), AL_INVALID_ENUM, - "Unpacking data with mismatched format"); + context->setError(AL_INVALID_ENUM, "Unpacking data with mismatched format"); else if(UNLIKELY(align != albuf->OriginalAlign)) - alSetError(context.get(), AL_INVALID_VALUE, - "Unpacking data with alignment %u does not match original alignment %u", - align, albuf->OriginalAlign); + context->setError(AL_INVALID_VALUE, + "Unpacking data with alignment %u does not match original alignment %u", align, + albuf->OriginalAlign); else if(UNLIKELY(albuf->MappedAccess != 0)) - alSetError(context.get(), AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u", - buffer); + context->setError(AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u", buffer); else { ALsizei num_chans{ChannelsFromFmt(albuf->mFmtChannels)}; @@ -906,14 +903,14 @@ START_API_FUNC if(UNLIKELY(offset < 0 || length < 0 || offset > albuf->OriginalSize || length > albuf->OriginalSize-offset)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid data sub-range %d+%d on buffer %u", - offset, length, buffer); + context->setError(AL_INVALID_VALUE, "Invalid data sub-range %d+%d on buffer %u", + offset, length, buffer); else if(UNLIKELY((offset%byte_align) != 0)) - alSetError(context.get(), AL_INVALID_VALUE, + context->setError(AL_INVALID_VALUE, "Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)", offset, byte_align, align); else if(UNLIKELY((length%byte_align) != 0)) - alSetError(context.get(), AL_INVALID_VALUE, + context->setError(AL_INVALID_VALUE, "Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)", length, byte_align, align); else @@ -948,7 +945,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - alSetError(context.get(), AL_INVALID_OPERATION, "alBufferSamplesSOFT not supported"); + context->setError(AL_INVALID_OPERATION, "alBufferSamplesSOFT not supported"); } END_API_FUNC @@ -959,7 +956,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - alSetError(context.get(), AL_INVALID_OPERATION, "alBufferSubSamplesSOFT not supported"); + context->setError(AL_INVALID_OPERATION, "alBufferSubSamplesSOFT not supported"); } END_API_FUNC @@ -970,7 +967,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - alSetError(context.get(), AL_INVALID_OPERATION, "alGetBufferSamplesSOFT not supported"); + context->setError(AL_INVALID_OPERATION, "alGetBufferSamplesSOFT not supported"); } END_API_FUNC @@ -980,7 +977,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(!context) return AL_FALSE; - alSetError(context.get(), AL_INVALID_OPERATION, "alIsBufferFormatSupportedSOFT not supported"); + context->setError(AL_INVALID_OPERATION, "alIsBufferFormatSupportedSOFT not supported"); return AL_FALSE; } END_API_FUNC @@ -996,11 +993,11 @@ START_API_FUNC std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else switch(param) { default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); } } END_API_FUNC @@ -1016,11 +1013,11 @@ START_API_FUNC std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else switch(param) { default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); } } END_API_FUNC @@ -1035,13 +1032,13 @@ START_API_FUNC std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!values)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); } } END_API_FUNC @@ -1058,25 +1055,25 @@ START_API_FUNC ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else switch(param) { case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: if(UNLIKELY(value < 0)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid unpack block alignment %d", value); + context->setError(AL_INVALID_VALUE, "Invalid unpack block alignment %d", value); else albuf->UnpackAlign.store(value); break; case AL_PACK_BLOCK_ALIGNMENT_SOFT: if(UNLIKELY(value < 0)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid pack block alignment %d", value); + context->setError(AL_INVALID_VALUE, "Invalid pack block alignment %d", value); else albuf->PackAlign.store(value); break; default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); } } END_API_FUNC @@ -1092,11 +1089,11 @@ START_API_FUNC std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else switch(param) { default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); } } END_API_FUNC @@ -1123,18 +1120,18 @@ START_API_FUNC ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!values)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_LOOP_POINTS_SOFT: if(UNLIKELY(ReadRef(&albuf->ref) != 0)) - alSetError(context.get(), AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points", - buffer); + context->setError(AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points", + buffer); else if(UNLIKELY(values[0] >= values[1] || values[0] < 0 || values[1] > albuf->SampleLen)) - alSetError(context.get(), AL_INVALID_VALUE, "Invalid loop point range %d -> %d o buffer %u", - values[0], values[1], buffer); + context->setError(AL_INVALID_VALUE, "Invalid loop point range %d -> %d on buffer %u", + values[0], values[1], buffer); else { albuf->LoopStart = values[0]; @@ -1143,8 +1140,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", - param); + context->setError(AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", param); } } END_API_FUNC @@ -1161,13 +1157,13 @@ START_API_FUNC ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!value)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); } } END_API_FUNC @@ -1182,13 +1178,13 @@ START_API_FUNC std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!value1 || !value2 || !value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); } } END_API_FUNC @@ -1210,13 +1206,13 @@ START_API_FUNC std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!values)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); } } END_API_FUNC @@ -1232,9 +1228,9 @@ START_API_FUNC std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!value)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_FREQUENCY: @@ -1262,7 +1258,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); } } END_API_FUNC @@ -1276,13 +1272,13 @@ START_API_FUNC ALCdevice *device = context->mDevice; std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!value1 || !value2 || !value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); } } END_API_FUNC @@ -1312,9 +1308,9 @@ START_API_FUNC std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!values)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_LOOP_POINTS_SOFT: @@ -1323,8 +1319,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", - param); + context->setError(AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", param); } } END_API_FUNC diff --git a/al/effect.cpp b/al/effect.cpp index b6291129..2d72916e 100644 --- a/al/effect.cpp +++ b/al/effect.cpp @@ -43,7 +43,6 @@ #include "almalloc.h" #include "alnumeric.h" #include "effects/base.h" -#include "error.h" #include "logging.h" #include "opthelpers.h" #include "vector.h" @@ -161,7 +160,7 @@ ALeffect *AllocEffect(ALCcontext *context) */ if(UNLIKELY(device->EffectList.size() >= 1<<25)) { - alSetError(context, AL_OUT_OF_MEMORY, "Too many effects allocated"); + context->setError(AL_OUT_OF_MEMORY, "Too many effects allocated"); return nullptr; } device->EffectList.emplace_back(); @@ -171,7 +170,7 @@ ALeffect *AllocEffect(ALCcontext *context) if(UNLIKELY(!sublist->Effects)) { device->EffectList.pop_back(); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect batch"); + context->setError(AL_OUT_OF_MEMORY, "Failed to allocate effect batch"); return nullptr; } @@ -224,7 +223,7 @@ START_API_FUNC if(UNLIKELY(n < 0)) { - alSetError(context.get(), AL_INVALID_VALUE, "Generating %d effects", n); + context->setError(AL_INVALID_VALUE, "Generating %d effects", n); return; } @@ -264,7 +263,7 @@ START_API_FUNC if(UNLIKELY(n < 0)) { - alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d effects", n); + context->setError(AL_INVALID_VALUE, "Deleting %d effects", n); return; } if(UNLIKELY(n == 0)) @@ -282,7 +281,7 @@ START_API_FUNC ALeffect *effect{LookupEffect(device, eid)}; if(UNLIKELY(!effect)) { - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", eid); + context->setError(AL_INVALID_NAME, "Invalid effect ID %u", eid); return true; } return false; @@ -328,7 +327,7 @@ START_API_FUNC ALeffect *aleffect{LookupEffect(device, effect)}; if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect); else { if(param == AL_EFFECT_TYPE) @@ -349,7 +348,7 @@ START_API_FUNC if(isOk) InitEffectParams(aleffect, value); else - alSetError(context.get(), AL_INVALID_VALUE, "Effect type 0x%04x not supported", value); + context->setError(AL_INVALID_VALUE, "Effect type 0x%04x not supported", value); } else { @@ -378,7 +377,7 @@ START_API_FUNC ALeffect *aleffect{LookupEffect(device, effect)}; if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect); else { /* Call the appropriate handler */ @@ -398,7 +397,7 @@ START_API_FUNC ALeffect *aleffect{LookupEffect(device, effect)}; if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect); else { /* Call the appropriate handler */ @@ -418,7 +417,7 @@ START_API_FUNC ALeffect *aleffect{LookupEffect(device, effect)}; if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect); else { /* Call the appropriate handler */ @@ -438,7 +437,7 @@ START_API_FUNC const ALeffect *aleffect{LookupEffect(device, effect)}; if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect); else { if(param == AL_EFFECT_TYPE) @@ -470,7 +469,7 @@ START_API_FUNC const ALeffect *aleffect{LookupEffect(device, effect)}; if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect); else { /* Call the appropriate handler */ @@ -490,7 +489,7 @@ START_API_FUNC const ALeffect *aleffect{LookupEffect(device, effect)}; if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect); else { /* Call the appropriate handler */ @@ -510,7 +509,7 @@ START_API_FUNC const ALeffect *aleffect{LookupEffect(device, effect)}; if(UNLIKELY(!aleffect)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect); + context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect); else { /* Call the appropriate handler */ diff --git a/al/error.cpp b/al/error.cpp index f5ec9f52..8bd78fe2 100644 --- a/al/error.cpp +++ b/al/error.cpp @@ -20,8 +20,6 @@ #include "config.h" -#include "error.h" - #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include @@ -49,7 +47,7 @@ bool TrapALError{false}; -void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) +void ALCcontext::setError(ALenum errorCode, const char *msg, ...) { auto message = al::vector(256); @@ -69,7 +67,7 @@ void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) else msg = ""; msglen = static_cast(strlen(msg)); - WARN("Error generated on context %p, code 0x%04x, \"%s\"\n", context, errorCode, msg); + WARN("Error generated on context %p, code 0x%04x, \"%s\"\n", this, errorCode, msg); if(TrapALError) { #ifdef _WIN32 @@ -82,14 +80,13 @@ void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) } ALenum curerr{AL_NO_ERROR}; - context->mLastError.compare_exchange_strong(curerr, errorCode); - if((context->mEnabledEvts.load(std::memory_order_relaxed)&EventType_Error)) + mLastError.compare_exchange_strong(curerr, errorCode); + if((mEnabledEvts.load(std::memory_order_relaxed)&EventType_Error)) { - std::lock_guard _{context->mEventCbLock}; - ALbitfieldSOFT enabledevts{context->mEnabledEvts.load(std::memory_order_relaxed)}; - if((enabledevts&EventType_Error) && context->mEventCb) - (*context->mEventCb)(AL_EVENT_TYPE_ERROR_SOFT, 0, errorCode, msglen, msg, - context->mEventParam); + std::lock_guard _{mEventCbLock}; + ALbitfieldSOFT enabledevts{mEnabledEvts.load(std::memory_order_relaxed)}; + if((enabledevts&EventType_Error) && mEventCb) + (*mEventCb)(AL_EVENT_TYPE_ERROR_SOFT, 0, errorCode, msglen, msg, mEventParam); } } diff --git a/al/error.h b/al/error.h deleted file mode 100644 index 6408b60c..00000000 --- a/al/error.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef AL_ERROR_H -#define AL_ERROR_H - -#include "AL/al.h" -#include "AL/alc.h" - -#include "logging.h" - - -extern bool TrapALError; - -void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) DECL_FORMAT(printf, 3, 4); - -#define SETERR_GOTO(ctx, err, lbl, ...) do { \ - alSetError((ctx), (err), __VA_ARGS__); \ - goto lbl; \ -} while(0) - -#define SETERR_RETURN(ctx, err, retval, ...) do { \ - alSetError((ctx), (err), __VA_ARGS__); \ - return retval; \ -} while(0) - -#endif diff --git a/al/event.cpp b/al/event.cpp index b2710561..0d41e713 100644 --- a/al/event.cpp +++ b/al/event.cpp @@ -21,7 +21,6 @@ #include "alexcpt.h" #include "almalloc.h" #include "effects/base.h" -#include "error.h" #include "inprogext.h" #include "logging.h" #include "opthelpers.h" @@ -145,9 +144,9 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - if(count < 0) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Controlling %d events", count); + if(count < 0) SETERR_RETURN(context, AL_INVALID_VALUE,, "Controlling %d events", count); if(count == 0) return; - if(!types) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "NULL pointer"); + if(!types) SETERR_RETURN(context, AL_INVALID_VALUE,, "NULL pointer"); ALbitfieldSOFT flags{0}; const ALenum *types_end = types+count; @@ -172,7 +171,7 @@ START_API_FUNC } ); if(bad_type != types_end) - SETERR_RETURN(context.get(), AL_INVALID_ENUM,, "Invalid event type 0x%04x", *bad_type); + SETERR_RETURN(context, AL_INVALID_ENUM,, "Invalid event type 0x%04x", *bad_type); if(enable) { diff --git a/al/extension.cpp b/al/extension.cpp index c190ad03..1b36e3db 100644 --- a/al/extension.cpp +++ b/al/extension.cpp @@ -29,7 +29,6 @@ #include "alcontext.h" #include "alexcpt.h" -#include "error.h" #include "opthelpers.h" @@ -40,7 +39,7 @@ START_API_FUNC if(UNLIKELY(!context)) return AL_FALSE; if(!extName) - SETERR_RETURN(context.get(), AL_INVALID_VALUE, AL_FALSE, "NULL pointer"); + SETERR_RETURN(context, AL_INVALID_VALUE, AL_FALSE, "NULL pointer"); size_t len{strlen(extName)}; const char *ptr{context->mExtensionList}; diff --git a/al/filter.cpp b/al/filter.cpp index d9fce069..5009daae 100644 --- a/al/filter.cpp +++ b/al/filter.cpp @@ -36,7 +36,6 @@ #include "alexcpt.h" #include "almalloc.h" #include "alnumeric.h" -#include "error.h" #include "opthelpers.h" #include "vector.h" @@ -47,9 +46,9 @@ namespace { #define FILTER_MAX_GAIN 4.0f /* +12dB */ void ALlowpass_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } void ALlowpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } void ALlowpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) { switch(param) @@ -67,16 +66,16 @@ void ALlowpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, AL break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param); } } void ALlowpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) { ALlowpass_setParamf(filter, context, param, vals[0]); } void ALlowpass_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } void ALlowpass_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) @@ -90,7 +89,7 @@ void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, AL break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param); } } void ALlowpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) @@ -100,9 +99,9 @@ DEFINE_ALFILTER_VTABLE(ALlowpass); void ALhighpass_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } void ALhighpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) { switch(param) @@ -120,16 +119,16 @@ void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, A break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param); } } void ALhighpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) { ALhighpass_setParamf(filter, context, param, vals[0]); } void ALhighpass_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } void ALhighpass_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) @@ -143,7 +142,7 @@ void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, A break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param); } } void ALhighpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) @@ -153,9 +152,9 @@ DEFINE_ALFILTER_VTABLE(ALhighpass); void ALbandpass_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } void ALbandpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) { switch(param) @@ -179,16 +178,16 @@ void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, A break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param); } } void ALbandpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) { ALbandpass_setParamf(filter, context, param, vals[0]); } void ALbandpass_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } void ALbandpass_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) @@ -206,7 +205,7 @@ void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, A break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param); } } void ALbandpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) @@ -216,22 +215,22 @@ DEFINE_ALFILTER_VTABLE(ALbandpass); void ALnullfilter_setParami(ALfilter*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } void ALnullfilter_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } void ALnullfilter_setParamf(ALfilter*, ALCcontext *context, ALenum param, ALfloat) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } void ALnullfilter_setParamfv(ALfilter*, ALCcontext *context, ALenum param, const ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } void ALnullfilter_getParami(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } void ALnullfilter_getParamiv(ALfilter*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } void ALnullfilter_getParamf(ALfilter*, ALCcontext *context, ALenum param, ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } void ALnullfilter_getParamfv(ALfilter*, ALCcontext *context, ALenum param, ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } DEFINE_ALFILTER_VTABLE(ALnullfilter); @@ -301,7 +300,7 @@ ALfilter *AllocFilter(ALCcontext *context) */ if(UNLIKELY(device->FilterList.size() >= 1<<25)) { - alSetError(context, AL_OUT_OF_MEMORY, "Too many filters allocated"); + context->setError(AL_OUT_OF_MEMORY, "Too many filters allocated"); return nullptr; } device->FilterList.emplace_back(); @@ -311,7 +310,7 @@ ALfilter *AllocFilter(ALCcontext *context) if(UNLIKELY(!sublist->Filters)) { device->FilterList.pop_back(); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate filter batch"); + context->setError(AL_OUT_OF_MEMORY, "Failed to allocate filter batch"); return nullptr; } @@ -365,7 +364,7 @@ START_API_FUNC if(UNLIKELY(n < 0)) { - alSetError(context.get(), AL_INVALID_VALUE, "Generating %d filters", n); + context->setError(AL_INVALID_VALUE, "Generating %d filters", n); return; } @@ -405,7 +404,7 @@ START_API_FUNC if(UNLIKELY(n < 0)) { - alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d filters", n); + context->setError(AL_INVALID_VALUE, "Deleting %d filters", n); return; } if(UNLIKELY(n == 0)) @@ -423,7 +422,7 @@ START_API_FUNC ALfilter *filter{LookupFilter(device, fid)}; if(UNLIKELY(!filter)) { - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", fid); + context->setError(AL_INVALID_NAME, "Invalid filter ID %u", fid); return true; } return false; @@ -470,7 +469,7 @@ START_API_FUNC ALfilter *alfilt{LookupFilter(device, filter)}; if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter); else { if(param == AL_FILTER_TYPE) @@ -479,7 +478,7 @@ START_API_FUNC value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS) InitFilterParams(alfilt, value); else - alSetError(context.get(), AL_INVALID_VALUE, "Invalid filter type 0x%04x", value); + context->setError(AL_INVALID_VALUE, "Invalid filter type 0x%04x", value); } else { @@ -508,7 +507,7 @@ START_API_FUNC ALfilter *alfilt{LookupFilter(device, filter)}; if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter); else { /* Call the appropriate handler */ @@ -528,7 +527,7 @@ START_API_FUNC ALfilter *alfilt{LookupFilter(device, filter)}; if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter); else { /* Call the appropriate handler */ @@ -548,7 +547,7 @@ START_API_FUNC ALfilter *alfilt{LookupFilter(device, filter)}; if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter); else { /* Call the appropriate handler */ @@ -568,7 +567,7 @@ START_API_FUNC ALfilter *alfilt{LookupFilter(device, filter)}; if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter); else { if(param == AL_FILTER_TYPE) @@ -600,7 +599,7 @@ START_API_FUNC ALfilter *alfilt{LookupFilter(device, filter)}; if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter); else { /* Call the appropriate handler */ @@ -620,7 +619,7 @@ START_API_FUNC ALfilter *alfilt{LookupFilter(device, filter)}; if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter); else { /* Call the appropriate handler */ @@ -640,7 +639,7 @@ START_API_FUNC ALfilter *alfilt{LookupFilter(device, filter)}; if(UNLIKELY(!alfilt)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid filter ID %u", filter); + context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter); else { /* Call the appropriate handler */ diff --git a/al/listener.cpp b/al/listener.cpp index ba0a7268..3a1f32a4 100644 --- a/al/listener.cpp +++ b/al/listener.cpp @@ -31,7 +31,6 @@ #include "alexcpt.h" #include "almalloc.h" #include "atomic.h" -#include "error.h" #include "opthelpers.h" @@ -55,15 +54,14 @@ START_API_FUNC { case AL_GAIN: if(!(value >= 0.0f && std::isfinite(value))) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener gain out of range"); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Listener gain out of range"); listener.Gain = value; DO_UPDATEPROPS(); break; case AL_METERS_PER_UNIT: if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, - "Listener meters per unit out of range"); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Listener meters per unit out of range"); context->mMetersPerUnit = value; if(!context->mDeferUpdates.load(std::memory_order_acquire)) UpdateContextProps(context.get()); @@ -72,7 +70,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float property"); + context->setError(AL_INVALID_ENUM, "Invalid listener float property"); } } END_API_FUNC @@ -89,7 +87,7 @@ START_API_FUNC { case AL_POSITION: if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3))) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener position out of range"); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Listener position out of range"); listener.Position[0] = value1; listener.Position[1] = value2; listener.Position[2] = value3; @@ -98,7 +96,7 @@ START_API_FUNC case AL_VELOCITY: if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3))) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener velocity out of range"); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Listener velocity out of range"); listener.Velocity[0] = value1; listener.Velocity[1] = value2; listener.Velocity[2] = value3; @@ -106,7 +104,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-float property"); + context->setError(AL_INVALID_ENUM, "Invalid listener 3-float property"); } } END_API_FUNC @@ -135,13 +133,13 @@ START_API_FUNC ALlistener &listener = context->mListener; std::lock_guard _{context->mPropLock}; - if(!values) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "NULL pointer"); + if(!values) SETERR_RETURN(context, AL_INVALID_VALUE,, "NULL pointer"); switch(param) { case AL_ORIENTATION: if(!(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) && std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5]))) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Listener orientation out of range"); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Listener orientation out of range"); /* AT then UP */ listener.OrientAt[0] = values[0]; listener.OrientAt[1] = values[1]; @@ -153,7 +151,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float-vector property"); + context->setError(AL_INVALID_ENUM, "Invalid listener float-vector property"); } } END_API_FUNC @@ -169,7 +167,7 @@ START_API_FUNC switch(param) { default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer property"); + context->setError(AL_INVALID_ENUM, "Invalid listener integer property"); } } END_API_FUNC @@ -192,7 +190,7 @@ START_API_FUNC switch(param) { default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-integer property"); + context->setError(AL_INVALID_ENUM, "Invalid listener 3-integer property"); } } END_API_FUNC @@ -227,11 +225,11 @@ START_API_FUNC std::lock_guard _{context->mPropLock}; if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer-vector property"); + context->setError(AL_INVALID_ENUM, "Invalid listener integer-vector property"); } } END_API_FUNC @@ -246,7 +244,7 @@ START_API_FUNC ALlistener &listener = context->mListener; std::lock_guard _{context->mPropLock}; if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_GAIN: @@ -258,7 +256,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float property"); + context->setError(AL_INVALID_ENUM, "Invalid listener float property"); } } END_API_FUNC @@ -272,7 +270,7 @@ START_API_FUNC ALlistener &listener = context->mListener; std::lock_guard _{context->mPropLock}; if(!value1 || !value2 || !value3) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_POSITION: @@ -288,7 +286,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-float property"); + context->setError(AL_INVALID_ENUM, "Invalid listener 3-float property"); } } END_API_FUNC @@ -315,7 +313,7 @@ START_API_FUNC ALlistener &listener = context->mListener; std::lock_guard _{context->mPropLock}; if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_ORIENTATION: @@ -329,7 +327,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener float-vector property"); + context->setError(AL_INVALID_ENUM, "Invalid listener float-vector property"); } } END_API_FUNC @@ -343,11 +341,11 @@ START_API_FUNC std::lock_guard _{context->mPropLock}; if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer property"); + context->setError(AL_INVALID_ENUM, "Invalid listener integer property"); } } END_API_FUNC @@ -361,7 +359,7 @@ START_API_FUNC ALlistener &listener = context->mListener; std::lock_guard _{context->mPropLock}; if(!value1 || !value2 || !value3) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_POSITION: @@ -377,7 +375,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener 3-integer property"); + context->setError(AL_INVALID_ENUM, "Invalid listener 3-integer property"); } } END_API_FUNC @@ -399,7 +397,7 @@ START_API_FUNC ALlistener &listener = context->mListener; std::lock_guard _{context->mPropLock}; if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_ORIENTATION: @@ -413,7 +411,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_ENUM, "Invalid listener integer-vector property"); + context->setError(AL_INVALID_ENUM, "Invalid listener integer-vector property"); } } END_API_FUNC diff --git a/al/source.cpp b/al/source.cpp index 35d3bb84..ab509804 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -57,7 +57,6 @@ #include "backends/base.h" #include "bformatdec.h" #include "buffer.h" -#include "error.h" #include "event.h" #include "filter.h" #include "filters/nfc.h" @@ -488,7 +487,7 @@ ALsource *AllocSource(ALCcontext *context) std::lock_guard _{context->mSourceLock}; if(context->mNumSources >= device->SourcesMax) { - alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax); + context->setError(AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax); return nullptr; } auto sublist = std::find_if(context->mSourceList.begin(), context->mSourceList.end(), @@ -510,7 +509,7 @@ ALsource *AllocSource(ALCcontext *context) */ if(UNLIKELY(context->mSourceList.size() >= 1<<25)) { - alSetError(context, AL_OUT_OF_MEMORY, "Too many sources allocated"); + context->setError(AL_OUT_OF_MEMORY, "Too many sources allocated"); return nullptr; } context->mSourceList.emplace_back(); @@ -521,7 +520,7 @@ ALsource *AllocSource(ALCcontext *context) if(UNLIKELY(!sublist->Sources)) { context->mSourceList.pop_back(); - alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate source batch"); + context->setError(AL_OUT_OF_MEMORY, "Failed to allocate source batch"); return nullptr; } @@ -993,7 +992,7 @@ ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, #define CHECKVAL(x) do { \ if(!(x)) \ { \ - alSetError(Context, AL_INVALID_VALUE, "Value out of range"); \ + Context->setError(AL_INVALID_VALUE, "Value out of range"); \ return AL_FALSE; \ } \ } while(0) @@ -1225,7 +1224,8 @@ ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, co } ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source float property 0x%04x", prop); + Context->setError(AL_INVALID_ENUM, "Invalid source float property 0x%04x", prop); + return AL_FALSE; } ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values) @@ -1548,8 +1548,8 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co } ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x", - prop); + Context->setError(AL_INVALID_ENUM, "Invalid source integer property 0x%04x", prop); + return AL_FALSE; } ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values) @@ -1651,8 +1651,8 @@ ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, } ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x", - prop); + Context->setError(AL_INVALID_ENUM, "Invalid source integer64 property 0x%04x", prop); + return AL_FALSE; } #undef CHECKVAL @@ -1824,8 +1824,8 @@ ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL } ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source double property 0x%04x", - prop); + Context->setError(AL_INVALID_ENUM, "Invalid source double property 0x%04x", prop); + return AL_FALSE; } ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values) @@ -1991,8 +1991,8 @@ ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL } ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x", - prop); + Context->setError(AL_INVALID_ENUM, "Invalid source integer property 0x%04x", prop); + return AL_FALSE; } ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64SOFT *values) @@ -2123,8 +2123,8 @@ ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, } ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x", - prop); + Context->setError(AL_INVALID_ENUM, "Invalid source integer64 property 0x%04x", prop); + return AL_FALSE; } } // namespace @@ -2136,7 +2136,7 @@ START_API_FUNC if(UNLIKELY(!context)) return; if(n < 0) - alSetError(context.get(), AL_INVALID_VALUE, "Generating %d sources", n); + context->setError(AL_INVALID_VALUE, "Generating %d sources", n); else if(n == 1) { ALsource *source = AllocSource(context.get()); @@ -2170,7 +2170,7 @@ START_API_FUNC if(UNLIKELY(!context)) return; if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Deleting %d sources", n); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Deleting %d sources", n); std::lock_guard _{context->mSourceLock}; @@ -2181,7 +2181,7 @@ START_API_FUNC { if(!LookupSource(context.get(), sid)) { - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", sid); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", sid); return false; } return true; @@ -2226,9 +2226,9 @@ START_API_FUNC std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(FloatValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid float property 0x%04x", param); else SetSourcefv(Source, context.get(), static_cast(param), &value); } @@ -2244,9 +2244,9 @@ START_API_FUNC std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(FloatValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); else { ALfloat fvals[3] = { value1, value2, value3 }; @@ -2265,11 +2265,11 @@ START_API_FUNC std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else if(FloatValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); else SetSourcefv(Source, context.get(), static_cast(param), values); } @@ -2286,9 +2286,9 @@ START_API_FUNC std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(DoubleValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid double property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid double property 0x%04x", param); else { ALfloat fval = static_cast(value); @@ -2307,9 +2307,9 @@ START_API_FUNC std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(DoubleValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); else { ALfloat fvals[3] = {static_cast(value1), static_cast(value2), @@ -2329,14 +2329,14 @@ START_API_FUNC std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else { ALint count{DoubleValsByProp(param)}; if(count < 1 || count > 6) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); else { ALfloat fvals[6]; @@ -2361,9 +2361,9 @@ START_API_FUNC std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(IntValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); else SetSourceiv(Source, context.get(), static_cast(param), &value); } @@ -2379,9 +2379,9 @@ START_API_FUNC std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(IntValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); else { ALint ivals[3] = { value1, value2, value3 }; @@ -2400,11 +2400,11 @@ START_API_FUNC std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else if(IntValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); else SetSourceiv(Source, context.get(), static_cast(param), values); } @@ -2421,9 +2421,9 @@ START_API_FUNC std::lock_guard __{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(Int64ValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); else SetSourcei64v(Source, context.get(), static_cast(param), &value); } @@ -2439,9 +2439,9 @@ START_API_FUNC std::lock_guard __{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(Int64ValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); else { ALint64SOFT i64vals[3] = { value1, value2, value3 }; @@ -2460,11 +2460,11 @@ START_API_FUNC std::lock_guard __{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else if(Int64ValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); else SetSourcei64v(Source, context.get(), static_cast(param), values); } @@ -2480,11 +2480,11 @@ START_API_FUNC std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else if(FloatValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid float property 0x%04x", param); else { ALdouble dval; @@ -2503,11 +2503,11 @@ START_API_FUNC std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else if(FloatValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); else { ALdouble dvals[3]; @@ -2530,14 +2530,14 @@ START_API_FUNC std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else { ALint count{FloatValsByProp(param)}; if(count < 1 && count > 6) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); else { ALdouble dvals[6]; @@ -2561,11 +2561,11 @@ START_API_FUNC std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else if(DoubleValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid double property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid double property 0x%04x", param); else GetSourcedv(Source, context.get(), static_cast(param), value); } @@ -2580,11 +2580,11 @@ START_API_FUNC std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else if(DoubleValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); else { ALdouble dvals[3]; @@ -2607,11 +2607,11 @@ START_API_FUNC std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else if(DoubleValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); else GetSourcedv(Source, context.get(), static_cast(param), values); } @@ -2627,11 +2627,11 @@ START_API_FUNC std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else if(IntValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); else GetSourceiv(Source, context.get(), static_cast(param), value); } @@ -2646,11 +2646,11 @@ START_API_FUNC std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else if(IntValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); else { ALint ivals[3]; @@ -2673,11 +2673,11 @@ START_API_FUNC std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else if(IntValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); else GetSourceiv(Source, context.get(), static_cast(param), values); } @@ -2693,11 +2693,11 @@ START_API_FUNC std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else if(Int64ValsByProp(param) != 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); else GetSourcei64v(Source, context.get(), static_cast(param), value); } @@ -2712,11 +2712,11 @@ START_API_FUNC std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else if(Int64ValsByProp(param) != 3) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); else { ALint64SOFT i64vals[3]; @@ -2739,11 +2739,11 @@ START_API_FUNC std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) - alSetError(context.get(), AL_INVALID_NAME, "Invalid source ID %u", source); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else if(Int64ValsByProp(param) < 1) - alSetError(context.get(), AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); else GetSourcei64v(Source, context.get(), static_cast(param), values); } @@ -2762,7 +2762,7 @@ START_API_FUNC if(UNLIKELY(!context)) return; if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Playing %d sources", n); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Playing %d sources", n); if(n == 0) return; al::vector extra_sources; @@ -2779,7 +2779,7 @@ START_API_FUNC { srchandles[i] = LookupSource(context.get(), sources[i]); if(!srchandles[i]) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); + SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } ALCdevice *device{context->mDevice}; @@ -2823,7 +2823,7 @@ START_API_FUNC /* Allocate more voices to get enough. */ const size_t alloc_count{need_voices - rem_voices}; if(UNLIKELY(context->mVoices->size() > std::numeric_limits::max()-alloc_count)) - SETERR_RETURN(context.get(), AL_OUT_OF_MEMORY,, + SETERR_RETURN(context, AL_OUT_OF_MEMORY,, "Overflow increasing voice count to %zu + %zu", context->mVoices->size(), alloc_count); @@ -3024,7 +3024,7 @@ START_API_FUNC if(UNLIKELY(!context)) return; if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Pausing %d sources", n); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Pausing %d sources", n); if(n == 0) return; al::vector extra_sources; @@ -3041,7 +3041,7 @@ START_API_FUNC { srchandles[i] = LookupSource(context.get(), sources[i]); if(!srchandles[i]) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); + SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } ALCdevice *device{context->mDevice}; @@ -3079,7 +3079,7 @@ START_API_FUNC if(UNLIKELY(!context)) return; if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Stopping %d sources", n); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Stopping %d sources", n); if(n == 0) return; al::vector extra_sources; @@ -3096,7 +3096,7 @@ START_API_FUNC { srchandles[i] = LookupSource(context.get(), sources[i]); if(!srchandles[i]) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); + SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } ALCdevice *device{context->mDevice}; @@ -3141,7 +3141,7 @@ START_API_FUNC if(UNLIKELY(!context)) return; if(n < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Rewinding %d sources", n); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Rewinding %d sources", n); if(n == 0) return; al::vector extra_sources; @@ -3158,7 +3158,7 @@ START_API_FUNC { srchandles[i] = LookupSource(context.get(), sources[i]); if(!srchandles[i]) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); + SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } ALCdevice *device{context->mDevice}; @@ -3197,17 +3197,17 @@ START_API_FUNC if(UNLIKELY(!context)) return; if(nb < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffers", nb); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Queueing %d buffers", nb); if(nb == 0) return; std::lock_guard _{context->mSourceLock}; ALsource *source{LookupSource(context.get(),src)}; if(UNLIKELY(!source)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); + SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", src); /* Can't queue on a Static Source */ if(UNLIKELY(source->SourceType == AL_STATIC)) - SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src); + SETERR_RETURN(context, AL_INVALID_OPERATION,, "Queueing onto static source %u", src); /* Check for a valid Buffer, for its frequency and format */ ALCdevice *device{context->mDevice}; @@ -3232,8 +3232,7 @@ START_API_FUNC ALbuffer *buffer{nullptr}; if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr) { - alSetError(context.get(), AL_INVALID_NAME, "Queueing invalid buffer ID %u", - buffers[i]); + context->setError(AL_INVALID_NAME, "Queueing invalid buffer ID %u", buffers[i]); goto buffer_error; } @@ -3260,8 +3259,8 @@ START_API_FUNC if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) { - alSetError(context.get(), AL_INVALID_OPERATION, - "Queueing non-persistently mapped buffer %u", buffer->id); + context->setError(AL_INVALID_OPERATION, "Queueing non-persistently mapped buffer %u", + buffer->id); goto buffer_error; } @@ -3271,8 +3270,7 @@ START_API_FUNC BufferFmt->mFmtChannels != buffer->mFmtChannels || BufferFmt->OriginalType != buffer->OriginalType) { - alSetError(context.get(), AL_INVALID_OPERATION, - "Queueing buffer with mismatched format"); + context->setError(AL_INVALID_OPERATION, "Queueing buffer with mismatched format"); buffer_error: /* A buffer failed (invalid ID or format), so unlock and release @@ -3316,17 +3314,17 @@ START_API_FUNC if(UNLIKELY(!context)) return; if(nb < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Queueing %d buffer layers", nb); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Queueing %d buffer layers", nb); if(nb == 0) return; std::lock_guard _{context->mSourceLock}; ALsource *source{LookupSource(context.get(),src)}; if(UNLIKELY(!source)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); + SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", src); /* Can't queue on a Static Source */ if(UNLIKELY(source->SourceType == AL_STATIC)) - SETERR_RETURN(context.get(), AL_INVALID_OPERATION,, "Queueing onto static source %u", src); + SETERR_RETURN(context, AL_INVALID_OPERATION,, "Queueing onto static source %u", src); /* Check for a valid Buffer, for its frequency and format */ ALCdevice *device{context->mDevice}; @@ -3356,8 +3354,7 @@ START_API_FUNC ALbuffer *buffer{nullptr}; if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr) { - alSetError(context.get(), AL_INVALID_NAME, "Queueing invalid buffer ID %u", - buffers[i]); + context->setError(AL_INVALID_NAME, "Queueing invalid buffer ID %u", buffers[i]); goto buffer_error; } @@ -3370,8 +3367,8 @@ START_API_FUNC if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) { - alSetError(context.get(), AL_INVALID_OPERATION, - "Queueing non-persistently mapped buffer %u", buffer->id); + context->setError(AL_INVALID_OPERATION, "Queueing non-persistently mapped buffer %u", + buffer->id); goto buffer_error; } @@ -3381,8 +3378,7 @@ START_API_FUNC BufferFmt->mFmtChannels != buffer->mFmtChannels || BufferFmt->OriginalType != buffer->OriginalType) { - alSetError(context.get(), AL_INVALID_OPERATION, - "Queueing buffer with mismatched format"); + context->setError(AL_INVALID_OPERATION, "Queueing buffer with mismatched format"); buffer_error: /* A buffer failed (invalid ID or format), so unlock and release @@ -3426,19 +3422,19 @@ START_API_FUNC if(UNLIKELY(!context)) return; if(nb < 0) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing %d buffers", nb); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Unqueueing %d buffers", nb); if(nb == 0) return; std::lock_guard _{context->mSourceLock}; ALsource *source{LookupSource(context.get(),src)}; if(UNLIKELY(!source)) - SETERR_RETURN(context.get(), AL_INVALID_NAME,, "Invalid source ID %u", src); + SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", src); if(UNLIKELY(source->Looping)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing from looping source %u", src); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Unqueueing from looping source %u", src); if(UNLIKELY(source->SourceType != AL_STREAMING)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, - "Unqueueing from a non-streaming source %u", src); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Unqueueing from a non-streaming source %u", + src); /* Make sure enough buffers have been processed to unqueue. */ ALbufferlistitem *BufferList{source->queue}; @@ -3449,7 +3445,7 @@ START_API_FUNC else if(source->state == AL_INITIAL) Current = BufferList; if(UNLIKELY(BufferList == Current)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing pending buffers"); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Unqueueing pending buffers"); ALsizei i{BufferList->num_buffers}; while(i < nb) @@ -3459,7 +3455,7 @@ START_API_FUNC */ ALbufferlistitem *next{BufferList->next.load(std::memory_order_relaxed)}; if(UNLIKELY(!next) || UNLIKELY(next == Current)) - SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Unqueueing pending buffers"); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Unqueueing pending buffers"); BufferList = next; i += BufferList->num_buffers; diff --git a/al/state.cpp b/al/state.cpp index 903ab614..3f2f8b79 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -102,7 +102,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability); + context->setError(AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability); } } END_API_FUNC @@ -122,7 +122,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability); + context->setError(AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability); } } END_API_FUNC @@ -142,7 +142,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability); + context->setError(AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability); } return value; @@ -199,7 +199,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid boolean property 0x%04x", pname); + context->setError(AL_INVALID_VALUE, "Invalid boolean property 0x%04x", pname); } return value; @@ -250,7 +250,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid double property 0x%04x", pname); + context->setError(AL_INVALID_VALUE, "Invalid double property 0x%04x", pname); } return value; @@ -301,7 +301,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid float property 0x%04x", pname); + context->setError(AL_INVALID_VALUE, "Invalid float property 0x%04x", pname); } return value; @@ -352,7 +352,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer property 0x%04x", pname); + context->setError(AL_INVALID_VALUE, "Invalid integer property 0x%04x", pname); } return value; @@ -403,7 +403,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer64 property 0x%04x", pname); + context->setError(AL_INVALID_VALUE, "Invalid integer64 property 0x%04x", pname); } return value; @@ -429,7 +429,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname); + context->setError(AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname); } return value; @@ -460,11 +460,11 @@ START_API_FUNC if(UNLIKELY(!context)) return; if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(pname) { default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid boolean-vector property 0x%04x", pname); + context->setError(AL_INVALID_VALUE, "Invalid boolean-vector property 0x%04x", pname); } } END_API_FUNC @@ -493,11 +493,11 @@ START_API_FUNC if(UNLIKELY(!context)) return; if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(pname) { default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid double-vector property 0x%04x", pname); + context->setError(AL_INVALID_VALUE, "Invalid double-vector property 0x%04x", pname); } } END_API_FUNC @@ -526,11 +526,11 @@ START_API_FUNC if(UNLIKELY(!context)) return; if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(pname) { default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid float-vector property 0x%04x", pname); + context->setError(AL_INVALID_VALUE, "Invalid float-vector property 0x%04x", pname); } } END_API_FUNC @@ -559,11 +559,11 @@ START_API_FUNC if(UNLIKELY(!context)) return; if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(pname) { default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer-vector property 0x%04x", pname); + context->setError(AL_INVALID_VALUE, "Invalid integer-vector property 0x%04x", pname); } } END_API_FUNC @@ -592,11 +592,11 @@ START_API_FUNC if(UNLIKELY(!context)) return; if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(pname) { default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid integer64-vector property 0x%04x", pname); + context->setError(AL_INVALID_VALUE, "Invalid integer64-vector property 0x%04x", pname); } } END_API_FUNC @@ -619,11 +619,11 @@ START_API_FUNC if(UNLIKELY(!context)) return; if(!values) - alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); + context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(pname) { default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid pointer-vector property 0x%04x", pname); + context->setError(AL_INVALID_VALUE, "Invalid pointer-vector property 0x%04x", pname); } } END_API_FUNC @@ -678,7 +678,7 @@ START_API_FUNC break; default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid string property 0x%04x", pname); + context->setError(AL_INVALID_VALUE, "Invalid string property 0x%04x", pname); } return value; } @@ -691,7 +691,7 @@ START_API_FUNC if(UNLIKELY(!context)) return; if(!(value >= 0.0f && std::isfinite(value))) - alSetError(context.get(), AL_INVALID_VALUE, "Doppler factor %f out of range", value); + context->setError(AL_INVALID_VALUE, "Doppler factor %f out of range", value); else { std::lock_guard _{context->mPropLock}; @@ -720,7 +720,7 @@ START_API_FUNC } if(!(value >= 0.0f && std::isfinite(value))) - alSetError(context.get(), AL_INVALID_VALUE, "Doppler velocity %f out of range", value); + context->setError(AL_INVALID_VALUE, "Doppler velocity %f out of range", value); else { std::lock_guard _{context->mPropLock}; @@ -737,7 +737,7 @@ START_API_FUNC if(UNLIKELY(!context)) return; if(!(value > 0.0f && std::isfinite(value))) - alSetError(context.get(), AL_INVALID_VALUE, "Speed of sound %f out of range", value); + context->setError(AL_INVALID_VALUE, "Speed of sound %f out of range", value); else { std::lock_guard _{context->mPropLock}; @@ -757,7 +757,7 @@ START_API_FUNC value == AL_LINEAR_DISTANCE || value == AL_LINEAR_DISTANCE_CLAMPED || value == AL_EXPONENT_DISTANCE || value == AL_EXPONENT_DISTANCE_CLAMPED || value == AL_NONE)) - alSetError(context.get(), AL_INVALID_VALUE, "Distance model 0x%04x out of range", value); + context->setError(AL_INVALID_VALUE, "Distance model 0x%04x out of range", value); else { std::lock_guard _{context->mPropLock}; @@ -808,14 +808,13 @@ START_API_FUNC { case AL_RESAMPLER_NAME_SOFT: if(index < 0 || static_cast(index) >= al::size(ResamplerNames)) - alSetError(context.get(), AL_INVALID_VALUE, "Resampler name index %d out of range", - index); + context->setError(AL_INVALID_VALUE, "Resampler name index %d out of range", index); else value = ResamplerNames[index]; break; default: - alSetError(context.get(), AL_INVALID_VALUE, "Invalid string indexed property"); + context->setError(AL_INVALID_VALUE, "Invalid string indexed property"); } return value; } diff --git a/alc/alc.cpp b/alc/alc.cpp index db5fd094..240aca6d 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -53,7 +53,6 @@ #include "al/auxeffectslot.h" #include "al/effect.h" -#include "al/error.h" #include "al/event.h" #include "al/filter.h" #include "al/listener.h" diff --git a/alc/alcontext.h b/alc/alcontext.h index 9c2ce4a3..833d4c5b 100644 --- a/alc/alcontext.h +++ b/alc/alcontext.h @@ -9,16 +9,16 @@ #include "AL/al.h" #include "AL/alc.h" #include "AL/alext.h" -#include "inprogext.h" -#include "atomic.h" -#include "vector.h" -#include "threads.h" +#include "al/listener.h" #include "almalloc.h" #include "alnumeric.h" - -#include "al/listener.h" #include "alu.h" +#include "atomic.h" +#include "inprogext.h" +#include "logging.h" +#include "threads.h" +#include "vector.h" struct ALsource; @@ -159,9 +159,17 @@ struct ALCcontext { /** Resumes update processing after being deferred. */ void processUpdates(); + void setError(ALenum errorCode, const char *msg, ...) DECL_FORMAT(printf, 3, 4); + DEF_NEWDEL(ALCcontext) }; +#define SETERR_RETURN(ctx, err, retval, ...) do { \ + (ctx)->setError((err), __VA_ARGS__); \ + return retval; \ +} while(0) + + void UpdateContextProps(ALCcontext *context); @@ -224,4 +232,7 @@ struct ALcontextProps { std::atomic next; }; + +extern bool TrapALError; + #endif /* ALCONTEXT_H */ diff --git a/alc/effects/autowah.cpp b/alc/effects/autowah.cpp index d92e114a..1aac749e 100644 --- a/alc/effects/autowah.cpp +++ b/alc/effects/autowah.cpp @@ -26,7 +26,6 @@ #include #include "al/auxeffectslot.h" -#include "al/error.h" #include "alcmain.h" #include "alcontext.h" #include "alu.h" @@ -226,16 +225,16 @@ void ALautowah_setParamf(EffectProps *props, ALCcontext *context, ALenum param, break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param); } } void ALautowah_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) { ALautowah_setParamf(props, context, param, vals[0]); } void ALautowah_setParami(EffectProps*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param); } void ALautowah_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x", param); } void ALautowah_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) { @@ -258,7 +257,7 @@ void ALautowah_getParamf(const EffectProps *props, ALCcontext *context, ALenum p break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param); } } @@ -266,9 +265,9 @@ void ALautowah_getParamfv(const EffectProps *props, ALCcontext *context, ALenum { ALautowah_getParamf(props, context, param, vals); } void ALautowah_getParami(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param); } void ALautowah_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x", param); } DEFINE_ALEFFECT_VTABLE(ALautowah); diff --git a/alc/effects/chorus.cpp b/alc/effects/chorus.cpp index 7a473723..31f10c81 100644 --- a/alc/effects/chorus.cpp +++ b/alc/effects/chorus.cpp @@ -31,7 +31,6 @@ #include "AL/efx.h" #include "al/auxeffectslot.h" -#include "al/error.h" #include "alcmain.h" #include "alcontext.h" #include "almalloc.h" @@ -290,7 +289,7 @@ void Chorus_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALi break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param); } } void Chorus_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) @@ -324,7 +323,7 @@ void Chorus_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALf break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param); } } void Chorus_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) @@ -343,7 +342,7 @@ void Chorus_getParami(const EffectProps *props, ALCcontext *context, ALenum para break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param); } } void Chorus_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) @@ -369,7 +368,7 @@ void Chorus_getParamf(const EffectProps *props, ALCcontext *context, ALenum para break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param); } } void Chorus_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) @@ -414,7 +413,7 @@ void Flanger_setParami(EffectProps *props, ALCcontext *context, ALenum param, AL break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param); } } void Flanger_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) @@ -448,7 +447,7 @@ void Flanger_setParamf(EffectProps *props, ALCcontext *context, ALenum param, AL break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param); } } void Flanger_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) @@ -467,7 +466,7 @@ void Flanger_getParami(const EffectProps *props, ALCcontext *context, ALenum par break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param); } } void Flanger_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) @@ -493,7 +492,7 @@ void Flanger_getParamf(const EffectProps *props, ALCcontext *context, ALenum par break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param); } } void Flanger_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) diff --git a/alc/effects/compressor.cpp b/alc/effects/compressor.cpp index 86e2e02b..63867762 100644 --- a/alc/effects/compressor.cpp +++ b/alc/effects/compressor.cpp @@ -23,7 +23,6 @@ #include #include "al/auxeffectslot.h" -#include "al/error.h" #include "alcmain.h" #include "alcontext.h" #include "alu.h" @@ -166,16 +165,16 @@ void Compressor_setParami(EffectProps *props, ALCcontext *context, ALenum param, break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid compressor integer property 0x%04x", - param); + context->setError(AL_INVALID_ENUM, "Invalid compressor integer property 0x%04x", + param); } } void Compressor_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) { Compressor_setParami(props, context, param, vals[0]); } void Compressor_setParamf(EffectProps*, ALCcontext *context, ALenum param, ALfloat) -{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param); } void Compressor_setParamfv(EffectProps*, ALCcontext *context, ALenum param, const ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float-vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid compressor float-vector property 0x%04x", param); } void Compressor_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val) { @@ -186,16 +185,16 @@ void Compressor_getParami(const EffectProps *props, ALCcontext *context, ALenum break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid compressor integer property 0x%04x", - param); + context->setError(AL_INVALID_ENUM, "Invalid compressor integer property 0x%04x", + param); } } void Compressor_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) { Compressor_getParami(props, context, param, vals); } void Compressor_getParamf(const EffectProps*, ALCcontext *context, ALenum param, ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param); } void Compressor_getParamfv(const EffectProps*, ALCcontext *context, ALenum param, ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float-vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid compressor float-vector property 0x%04x", param); } DEFINE_ALEFFECT_VTABLE(Compressor); diff --git a/alc/effects/dedicated.cpp b/alc/effects/dedicated.cpp index c05df772..2e49658f 100644 --- a/alc/effects/dedicated.cpp +++ b/alc/effects/dedicated.cpp @@ -25,7 +25,6 @@ #include #include "al/auxeffectslot.h" -#include "al/error.h" #include "alcmain.h" #include "alcontext.h" #include "alu.h" @@ -95,9 +94,9 @@ void DedicatedState::process(const ALsizei samplesToDo, const FloatBufferLine *R void Dedicated_setParami(EffectProps*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param); } void Dedicated_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x", param); } void Dedicated_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) { switch(param) @@ -109,16 +108,16 @@ void Dedicated_setParamf(EffectProps *props, ALCcontext *context, ALenum param, break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param); } } void Dedicated_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) { Dedicated_setParamf(props, context, param, vals[0]); } void Dedicated_getParami(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param); } void Dedicated_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x", param); } void Dedicated_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) @@ -128,7 +127,7 @@ void Dedicated_getParamf(const EffectProps *props, ALCcontext *context, ALenum p break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param); } } void Dedicated_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) diff --git a/alc/effects/distortion.cpp b/alc/effects/distortion.cpp index 79278f0d..3fd08229 100644 --- a/alc/effects/distortion.cpp +++ b/alc/effects/distortion.cpp @@ -26,7 +26,6 @@ #include #include "al/auxeffectslot.h" -#include "al/error.h" #include "alcmain.h" #include "alcontext.h" #include "alu.h" @@ -159,9 +158,9 @@ void DistortionState::process(const ALsizei samplesToDo, const FloatBufferLine * void Distortion_setParami(EffectProps*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param); } void Distortion_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x", param); } void Distortion_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) { switch(param) @@ -197,17 +196,16 @@ void Distortion_setParamf(EffectProps *props, ALCcontext *context, ALenum param, break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", - param); + context->setError(AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", param); } } void Distortion_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) { Distortion_setParamf(props, context, param, vals[0]); } void Distortion_getParami(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param); } void Distortion_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x", param); } void Distortion_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) @@ -233,8 +231,7 @@ void Distortion_getParamf(const EffectProps *props, ALCcontext *context, ALenum break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", - param); + context->setError(AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", param); } } void Distortion_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) diff --git a/alc/effects/echo.cpp b/alc/effects/echo.cpp index 9a43c037..d14db80c 100644 --- a/alc/effects/echo.cpp +++ b/alc/effects/echo.cpp @@ -26,7 +26,6 @@ #include #include "al/auxeffectslot.h" -#include "al/error.h" #include "al/filter.h" #include "alcmain.h" #include "alcontext.h" @@ -163,9 +162,9 @@ void EchoState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRI void Echo_setParami(EffectProps*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param); } void Echo_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param); } void Echo_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) { switch(param) @@ -201,16 +200,16 @@ void Echo_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALflo break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param); } } void Echo_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) { Echo_setParamf(props, context, param, vals[0]); } void Echo_getParami(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param); } void Echo_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param); } void Echo_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) @@ -236,7 +235,7 @@ void Echo_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param); } } void Echo_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) diff --git a/alc/effects/equalizer.cpp b/alc/effects/equalizer.cpp index 25ccf264..4b900bcf 100644 --- a/alc/effects/equalizer.cpp +++ b/alc/effects/equalizer.cpp @@ -27,7 +27,6 @@ #include #include "al/auxeffectslot.h" -#include "al/error.h" #include "alcmain.h" #include "alcontext.h" #include "alu.h" @@ -174,9 +173,9 @@ void EqualizerState::process(const ALsizei samplesToDo, const FloatBufferLine *R void Equalizer_setParami(EffectProps*, ALCcontext *context, ALenum param, ALint) -{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param); } void Equalizer_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x", param); } void Equalizer_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) { switch(param) @@ -242,16 +241,16 @@ void Equalizer_setParamf(EffectProps *props, ALCcontext *context, ALenum param, break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param); } } void Equalizer_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) { Equalizer_setParamf(props, context, param, vals[0]); } void Equalizer_getParami(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param); } void Equalizer_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x", param); } void Equalizer_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) @@ -297,7 +296,7 @@ void Equalizer_getParamf(const EffectProps *props, ALCcontext *context, ALenum p break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param); } } void Equalizer_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) diff --git a/alc/effects/fshifter.cpp b/alc/effects/fshifter.cpp index 9b204d2e..bca29bba 100644 --- a/alc/effects/fshifter.cpp +++ b/alc/effects/fshifter.cpp @@ -27,7 +27,6 @@ #include #include "al/auxeffectslot.h" -#include "al/error.h" #include "alcmain.h" #include "alcontext.h" #include "alu.h" @@ -213,7 +212,8 @@ void Fshifter_setParamf(EffectProps *props, ALCcontext *context, ALenum param, A break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", + param); } } void Fshifter_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) @@ -236,7 +236,8 @@ void Fshifter_setParami(EffectProps *props, ALCcontext *context, ALenum param, A break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", + param); } } void Fshifter_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) @@ -253,7 +254,8 @@ void Fshifter_getParami(const EffectProps *props, ALCcontext *context, ALenum pa *val = props->Fshifter.RightDirection; break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", + param); } } void Fshifter_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) @@ -268,7 +270,8 @@ void Fshifter_getParamf(const EffectProps *props, ALCcontext *context, ALenum pa break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", + param); } } void Fshifter_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) diff --git a/alc/effects/modulator.cpp b/alc/effects/modulator.cpp index bd63c56c..d7118285 100644 --- a/alc/effects/modulator.cpp +++ b/alc/effects/modulator.cpp @@ -27,7 +27,6 @@ #include #include "al/auxeffectslot.h" -#include "al/error.h" #include "alcmain.h" #include "alcontext.h" #include "alu.h" @@ -187,7 +186,7 @@ void Modulator_setParamf(EffectProps *props, ALCcontext *context, ALenum param, break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param); } } void Modulator_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) @@ -208,7 +207,7 @@ void Modulator_setParami(EffectProps *props, ALCcontext *context, ALenum param, break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x", param); } } void Modulator_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) @@ -229,7 +228,7 @@ void Modulator_getParami(const EffectProps *props, ALCcontext *context, ALenum p break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x", param); } } void Modulator_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) @@ -246,7 +245,7 @@ void Modulator_getParamf(const EffectProps *props, ALCcontext *context, ALenum p break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param); } } void Modulator_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) diff --git a/alc/effects/null.cpp b/alc/effects/null.cpp index c4eebb3d..245b9b04 100644 --- a/alc/effects/null.cpp +++ b/alc/effects/null.cpp @@ -5,8 +5,8 @@ #include "AL/alc.h" #include "al/auxeffectslot.h" -#include "al/error.h" #include "alcmain.h" +#include "alcontext.h" #include "almalloc.h" #include "alspan.h" #include "effects/base.h" @@ -69,7 +69,7 @@ void NullEffect_setParami(EffectProps* /*props*/, ALCcontext *context, ALenum pa switch(param) { default: - alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x", param); } } void NullEffect_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) @@ -85,7 +85,7 @@ void NullEffect_setParamf(EffectProps* /*props*/, ALCcontext *context, ALenum pa switch(param) { default: - alSetError(context, AL_INVALID_ENUM, "Invalid null effect float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid null effect float property 0x%04x", param); } } void NullEffect_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) @@ -102,7 +102,7 @@ void NullEffect_getParami(const EffectProps* /*props*/, ALCcontext *context, ALe switch(param) { default: - alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x", param); } } void NullEffect_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) @@ -118,7 +118,7 @@ void NullEffect_getParamf(const EffectProps* /*props*/, ALCcontext *context, ALe switch(param) { default: - alSetError(context, AL_INVALID_ENUM, "Invalid null effect float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid null effect float property 0x%04x", param); } } void NullEffect_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) diff --git a/alc/effects/pshifter.cpp b/alc/effects/pshifter.cpp index eac5894b..a08052b9 100644 --- a/alc/effects/pshifter.cpp +++ b/alc/effects/pshifter.cpp @@ -31,7 +31,6 @@ #include #include "al/auxeffectslot.h" -#include "al/error.h" #include "alcmain.h" #include "alcomplex.h" #include "alcontext.h" @@ -325,9 +324,9 @@ void PshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE void Pshifter_setParamf(EffectProps*, ALCcontext *context, ALenum param, ALfloat) -{ alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param); } void Pshifter_setParamfv(EffectProps*, ALCcontext *context, ALenum param, const ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float-vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid pitch shifter float-vector property 0x%04x", param); } void Pshifter_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val) { @@ -346,7 +345,8 @@ void Pshifter_setParami(EffectProps *props, ALCcontext *context, ALenum param, A break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x", + param); } } void Pshifter_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) @@ -364,16 +364,17 @@ void Pshifter_getParami(const EffectProps *props, ALCcontext *context, ALenum pa break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x", + param); } } void Pshifter_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) { Pshifter_getParami(props, context, param, vals); } void Pshifter_getParamf(const EffectProps*, ALCcontext *context, ALenum param, ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param); } void Pshifter_getParamfv(const EffectProps*, ALCcontext *context, ALenum param, ALfloat*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float vector-property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid pitch shifter float vector-property 0x%04x", param); } DEFINE_ALEFFECT_VTABLE(Pshifter); diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index bc4995ff..6e6844e0 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -30,7 +30,6 @@ #include #include "al/auxeffectslot.h" -#include "al/error.h" #include "al/listener.h" #include "alcmain.h" #include "alcontext.h" @@ -1545,8 +1544,8 @@ void EAXReverb_setParami(EffectProps *props, ALCcontext *context, ALenum param, break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb integer property 0x%04x", - param); + context->setError(AL_INVALID_ENUM, "Invalid EAX reverb integer property 0x%04x", + param); } } void EAXReverb_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) @@ -1676,8 +1675,7 @@ void EAXReverb_setParamf(EffectProps *props, ALCcontext *context, ALenum param, break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", - param); + context->setError(AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", param); } } void EAXReverb_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) @@ -1714,8 +1712,8 @@ void EAXReverb_getParami(const EffectProps *props, ALCcontext *context, ALenum p break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb integer property 0x%04x", - param); + context->setError(AL_INVALID_ENUM, "Invalid EAX reverb integer property 0x%04x", + param); } } void EAXReverb_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) @@ -1805,8 +1803,7 @@ void EAXReverb_getParamf(const EffectProps *props, ALCcontext *context, ALenum p break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", - param); + context->setError(AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", param); } } void EAXReverb_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) @@ -1884,7 +1881,7 @@ void StdReverb_setParami(EffectProps *props, ALCcontext *context, ALenum param, break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid reverb integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid reverb integer property 0x%04x", param); } } void StdReverb_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals) @@ -1966,7 +1963,7 @@ void StdReverb_setParamf(EffectProps *props, ALCcontext *context, ALenum param, break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid reverb float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid reverb float property 0x%04x", param); } } void StdReverb_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) @@ -1981,7 +1978,7 @@ void StdReverb_getParami(const EffectProps *props, ALCcontext *context, ALenum p break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid reverb integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid reverb integer property 0x%04x", param); } } void StdReverb_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals) @@ -2039,7 +2036,7 @@ void StdReverb_getParamf(const EffectProps *props, ALCcontext *context, ALenum p break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid reverb float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid reverb float property 0x%04x", param); } } void StdReverb_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) diff --git a/alc/effects/vmorpher.cpp b/alc/effects/vmorpher.cpp index ae8c98e1..95016105 100644 --- a/alc/effects/vmorpher.cpp +++ b/alc/effects/vmorpher.cpp @@ -26,7 +26,6 @@ #include #include "al/auxeffectslot.h" -#include "al/error.h" #include "alcmain.h" #include "alcontext.h" #include "alu.h" @@ -333,11 +332,12 @@ void Vmorpher_setParami(EffectProps* props, ALCcontext *context, ALenum param, A break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x", + param); } } void Vmorpher_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x", param); } void Vmorpher_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val) { switch(param) @@ -349,7 +349,8 @@ void Vmorpher_setParamf(EffectProps *props, ALCcontext *context, ALenum param, A break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x", + param); } } void Vmorpher_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) @@ -380,11 +381,12 @@ void Vmorpher_getParami(const EffectProps* props, ALCcontext *context, ALenum pa break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x", + param); } } void Vmorpher_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) -{ alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x", param); } +{ context->setError(AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x", param); } void Vmorpher_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) @@ -394,7 +396,8 @@ void Vmorpher_getParamf(const EffectProps *props, ALCcontext *context, ALenum pa break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x", param); + context->setError(AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x", + param); } } void Vmorpher_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) -- cgit v1.2.3 From 4cd7eee01cd7ab2cb14ca71551954f5bd76bfd12 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 Jul 2019 21:50:47 -0700 Subject: Remove improper include --- al/state.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/al/state.cpp b/al/state.cpp index 3f2f8b79..3e8f4d18 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -38,7 +38,6 @@ #include "alspan.h" #include "alu.h" #include "atomic.h" -#include "error.h" #include "event.h" #include "inprogext.h" #include "opthelpers.h" -- cgit v1.2.3 From a0aa5bc80a5c38f4ba92e38f924f4141344da819 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Jul 2019 09:20:53 -0700 Subject: Add iterators to ALbufferlistitem And change some types to ALuint --- al/buffer.cpp | 7 ++- al/buffer.h | 6 +- al/source.cpp | 187 +++++++++++++++++++++++++------------------------------ al/source.h | 53 ++++++++++++++-- alc/mixvoice.cpp | 62 +++++++++--------- 5 files changed, 170 insertions(+), 145 deletions(-) diff --git a/al/buffer.cpp b/al/buffer.cpp index d6d743d0..4e843e03 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -459,14 +459,14 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U if(UNLIKELY(size/SrcByteAlign > std::numeric_limits::max()/align)) SETERR_RETURN(context, AL_OUT_OF_MEMORY,, "Buffer size overflow, %d blocks x %d samples per block", size/SrcByteAlign, align); - const ALsizei frames{size / SrcByteAlign * align}; + const auto frames = static_cast(size / SrcByteAlign * align); /* Convert the sample frames to the number of bytes needed for internal * storage. */ ALsizei NumChannels{ChannelsFromFmt(DstChannels)}; ALsizei FrameSize{NumChannels * BytesFromFmt(DstType)}; - if(UNLIKELY(frames > std::numeric_limits::max()/FrameSize)) + if(UNLIKELY(frames > std::numeric_limits::max()/FrameSize)) SETERR_RETURN(context, AL_OUT_OF_MEMORY,, "Buffer size overflow, %d frames x %d bytes per frame", frames, FrameSize); size_t newsize{static_cast(frames) * FrameSize}; @@ -1129,7 +1129,8 @@ START_API_FUNC if(UNLIKELY(ReadRef(&albuf->ref) != 0)) context->setError(AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points", buffer); - else if(UNLIKELY(values[0] >= values[1] || values[0] < 0 || values[1] > albuf->SampleLen)) + else if(UNLIKELY(values[0] < 0 || values[0] >= values[1] || + static_cast(values[1]) > albuf->SampleLen)) context->setError(AL_INVALID_VALUE, "Invalid loop point range %d -> %d on buffer %u", values[0], values[1], buffer); else diff --git a/al/buffer.h b/al/buffer.h index 1d5873e5..e5149bb1 100644 --- a/al/buffer.h +++ b/al/buffer.h @@ -92,7 +92,7 @@ struct ALbuffer { ALsizei Frequency{0}; ALbitfieldSOFT Access{0u}; - ALsizei SampleLen{0}; + ALuint SampleLen{0u}; FmtChannels mFmtChannels{}; FmtType mFmtType{}; @@ -101,8 +101,8 @@ struct ALbuffer { ALsizei OriginalSize{0}; ALsizei OriginalAlign{0}; - ALsizei LoopStart{0}; - ALsizei LoopEnd{0}; + ALuint LoopStart{0u}; + ALuint LoopEnd{0u}; std::atomic UnpackAlign{0}; std::atomic PackAlign{0}; diff --git a/al/source.cpp b/al/source.cpp index ab509804..6708c970 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -205,8 +205,8 @@ int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, std::chrono const ALbufferlistitem *BufferList{Source->queue}; while(BufferList && BufferList != Current) { - readPos += int64_t{BufferList->max_samples} << 32; - BufferList = BufferList->next.load(std::memory_order_relaxed); + readPos += int64_t{BufferList->mMaxSamples} << 32; + BufferList = BufferList->mNext.load(std::memory_order_relaxed); } readPos = minu64(readPos, 0x7fffffffffffffff_u64); } @@ -252,17 +252,17 @@ ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, std::chrono:: const ALbuffer *BufferFmt{nullptr}; while(BufferList && BufferList != Current) { - for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i) - BufferFmt = BufferList->buffers[i]; - readPos += int64_t{BufferList->max_samples} << FRACTIONBITS; - BufferList = BufferList->next.load(std::memory_order_relaxed); + for(ALuint i{0};!BufferFmt && i < BufferList->mNumBuffers;++i) + BufferFmt = (*BufferList)[i]; + readPos += int64_t{BufferList->mMaxSamples} << FRACTIONBITS; + BufferList = BufferList->mNext.load(std::memory_order_relaxed); } while(BufferList && !BufferFmt) { - for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i) - BufferFmt = BufferList->buffers[i]; - BufferList = BufferList->next.load(std::memory_order_relaxed); + for(ALuint i{0};!BufferFmt && i < BufferList->mNumBuffers;++i) + BufferFmt = (*BufferList)[i]; + BufferList = BufferList->mNext.load(std::memory_order_relaxed); } assert(BufferFmt != nullptr); @@ -314,14 +314,14 @@ ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) while(BufferList) { - for(ALsizei i{0};!BufferFmt && i < BufferList->num_buffers;++i) - BufferFmt = BufferList->buffers[i]; + for(ALuint i{0};!BufferFmt && i < BufferList->mNumBuffers;++i) + BufferFmt = (*BufferList)[i]; readFin |= (BufferList == Current); - totalBufferLen += BufferList->max_samples; - if(!readFin) readPos += BufferList->max_samples; + totalBufferLen += BufferList->mMaxSamples; + if(!readFin) readPos += BufferList->mMaxSamples; - BufferList = BufferList->next.load(std::memory_order_relaxed); + BufferList = BufferList->mNext.load(std::memory_order_relaxed); } assert(BufferFmt != nullptr); @@ -393,10 +393,10 @@ ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac) BufferList = Source->queue; while(BufferList) { - for(ALsizei i{0};i < BufferList->num_buffers && !BufferFmt;i++) - BufferFmt = BufferList->buffers[i]; + for(ALuint i{0};!BufferFmt && i < BufferList->mNumBuffers;i++) + BufferFmt = (*BufferList)[i]; if(BufferFmt) break; - BufferList = BufferList->next.load(std::memory_order_relaxed); + BufferList = BufferList->mNext.load(std::memory_order_relaxed); } if(!BufferFmt) { @@ -463,7 +463,7 @@ ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) ALbufferlistitem *BufferList{Source->queue}; while(BufferList && totalBufferLen <= offset) { - if(static_cast(BufferList->max_samples) > offset-totalBufferLen) + if(static_cast(BufferList->mMaxSamples) > offset-totalBufferLen) { /* Offset is in this buffer */ voice->mPosition.store(offset - totalBufferLen, std::memory_order_relaxed); @@ -471,9 +471,9 @@ ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) voice->mCurrentBuffer.store(BufferList, std::memory_order_release); return AL_TRUE; } - totalBufferLen += BufferList->max_samples; + totalBufferLen += BufferList->mMaxSamples; - BufferList = BufferList->next.load(std::memory_order_relaxed); + BufferList = BufferList->mNext.load(std::memory_order_relaxed); } /* Offset is out of range of the queue */ @@ -1305,10 +1305,10 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co /* Add the selected buffer to a one-item queue */ auto newlist = static_cast(al_calloc(alignof(void*), ALbufferlistitem::Sizeof(1u))); - newlist->next.store(nullptr, std::memory_order_relaxed); - newlist->max_samples = buffer->SampleLen; - newlist->num_buffers = 1; - newlist->buffers[0] = buffer; + newlist->mNext.store(nullptr, std::memory_order_relaxed); + newlist->mMaxSamples = buffer->SampleLen; + newlist->mNumBuffers = 1; + newlist->mBuffers[0] = buffer; IncrementRef(&buffer->ref); /* Source is now Static */ @@ -1327,13 +1327,11 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co while(oldlist != nullptr) { ALbufferlistitem *temp{oldlist}; - oldlist = temp->next.load(std::memory_order_relaxed); + oldlist = temp->mNext.load(std::memory_order_relaxed); - for(ALsizei i{0};i < temp->num_buffers;i++) - { - if(temp->buffers[i]) - DecrementRef(&temp->buffers[i]->ref); - } + std::for_each(temp->begin(), temp->end(), + [](ALbuffer *buffer) -> void + { if(buffer) DecrementRef(&buffer->ref); }); al_free(temp); } return AL_TRUE; @@ -1846,8 +1844,8 @@ ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL case AL_BUFFER: BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : nullptr; - *values = (BufferList && BufferList->num_buffers >= 1 && BufferList->buffers[0]) ? - BufferList->buffers[0]->id : 0; + *values = (BufferList && BufferList->mNumBuffers >= 1 && BufferList->front()) ? + BufferList->front()->id : 0; return AL_TRUE; case AL_SOURCE_STATE: @@ -1861,8 +1859,8 @@ ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL { ALsizei count = 0; do { - count += BufferList->num_buffers; - BufferList = BufferList->next.load(std::memory_order_relaxed); + count += BufferList->mNumBuffers; + BufferList = BufferList->mNext.load(std::memory_order_relaxed); } while(BufferList != nullptr); *values = count; } @@ -1889,8 +1887,8 @@ ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL while(BufferList && BufferList != Current) { - played += BufferList->num_buffers; - BufferList = BufferList->next.load(std::memory_order_relaxed); + played += BufferList->mNumBuffers; + BufferList = BufferList->mNext.load(std::memory_order_relaxed); } *values = played; } @@ -2840,8 +2838,8 @@ START_API_FUNC * length buffer. */ ALbufferlistitem *BufferList{source->queue}; - while(BufferList && BufferList->max_samples == 0) - BufferList = BufferList->next.load(std::memory_order_relaxed); + while(BufferList && BufferList->mMaxSamples == 0) + BufferList = BufferList->mNext.load(std::memory_order_relaxed); /* If there's nothing to play, go right to stopped. */ if(UNLIKELY(!BufferList)) @@ -2918,10 +2916,9 @@ START_API_FUNC voice->mPositionFrac.load(std::memory_order_relaxed) != 0 || voice->mCurrentBuffer.load(std::memory_order_relaxed) != BufferList; - auto buffers_end = BufferList->buffers + BufferList->num_buffers; - auto buffer = std::find_if(BufferList->buffers, buffers_end, + auto buffer = std::find_if(BufferList->cbegin(), BufferList->cend(), std::bind(std::not_equal_to{}, _1, nullptr)); - if(buffer != buffers_end) + if(buffer != BufferList->cend()) { voice->mFrequency = (*buffer)->Frequency; voice->mFmtChannels = (*buffer)->mFmtChannels; @@ -3215,13 +3212,10 @@ START_API_FUNC ALbufferlistitem *BufferList{source->queue}; while(BufferList) { - for(ALsizei i{0};i < BufferList->num_buffers;i++) - { - if((BufferFmt=BufferList->buffers[i]) != nullptr) - break; - } + for(ALuint i{0};!BufferFmt && i < BufferList->mNumBuffers;i++) + BufferFmt = (*BufferList)[i]; if(BufferFmt) break; - BufferList = BufferList->next.load(std::memory_order_relaxed); + BufferList = BufferList->mNext.load(std::memory_order_relaxed); } std::unique_lock buflock{device->BufferLock}; @@ -3246,13 +3240,13 @@ START_API_FUNC { auto item = static_cast(al_calloc(alignof(void*), ALbufferlistitem::Sizeof(1u))); - BufferList->next.store(item, std::memory_order_relaxed); + BufferList->mNext.store(item, std::memory_order_relaxed); BufferList = item; } - BufferList->next.store(nullptr, std::memory_order_relaxed); - BufferList->max_samples = buffer ? buffer->SampleLen : 0; - BufferList->num_buffers = 1; - BufferList->buffers[0] = buffer; + BufferList->mNext.store(nullptr, std::memory_order_relaxed); + BufferList->mMaxSamples = buffer ? buffer->SampleLen : 0; + BufferList->mNumBuffers = 1; + BufferList->mBuffers[0] = buffer; if(!buffer) continue; IncrementRef(&buffer->ref); @@ -3277,12 +3271,10 @@ START_API_FUNC * each buffer we had. */ while(BufferListStart) { - ALbufferlistitem *next = BufferListStart->next.load(std::memory_order_relaxed); - for(i = 0;i < BufferListStart->num_buffers;i++) - { - if((buffer=BufferListStart->buffers[i]) != nullptr) - DecrementRef(&buffer->ref); - } + ALbufferlistitem *next = BufferListStart->mNext.load(std::memory_order_relaxed); + std::for_each(BufferListStart->begin(), BufferListStart->end(), + [](ALbuffer *buffer) -> void + { if(buffer) DecrementRef(&buffer->ref); }); al_free(BufferListStart); BufferListStart = next; } @@ -3300,9 +3292,9 @@ START_API_FUNC else { ALbufferlistitem *next; - while((next=BufferList->next.load(std::memory_order_relaxed)) != nullptr) + while((next=BufferList->mNext.load(std::memory_order_relaxed)) != nullptr) BufferList = next; - BufferList->next.store(BufferListStart, std::memory_order_release); + BufferList->mNext.store(BufferListStart, std::memory_order_release); } } END_API_FUNC @@ -3332,22 +3324,19 @@ START_API_FUNC ALbufferlistitem *BufferList{source->queue}; while(BufferList) { - for(ALsizei i{0};i < BufferList->num_buffers;i++) - { - if((BufferFmt=BufferList->buffers[i]) != nullptr) - break; - } + for(ALuint i{0};!BufferFmt && i < BufferList->mNumBuffers;i++) + BufferFmt = (*BufferList)[i]; if(BufferFmt) break; - BufferList = BufferList->next.load(std::memory_order_relaxed); + BufferList = BufferList->mNext.load(std::memory_order_relaxed); } std::unique_lock buflock{device->BufferLock}; auto BufferListStart = static_cast(al_calloc(alignof(void*), ALbufferlistitem::Sizeof(nb))); BufferList = BufferListStart; - BufferList->next.store(nullptr, std::memory_order_relaxed); - BufferList->max_samples = 0; - BufferList->num_buffers = 0; + BufferList->mNext.store(nullptr, std::memory_order_relaxed); + BufferList->mMaxSamples = 0; + BufferList->mNumBuffers = 0; for(ALsizei i{0};i < nb;i++) { @@ -3358,12 +3347,12 @@ START_API_FUNC goto buffer_error; } - BufferList->buffers[BufferList->num_buffers++] = buffer; + BufferList->mBuffers[BufferList->mNumBuffers++] = buffer; if(!buffer) continue; IncrementRef(&buffer->ref); - BufferList->max_samples = maxi(BufferList->max_samples, buffer->SampleLen); + BufferList->mMaxSamples = maxu(BufferList->mMaxSamples, buffer->SampleLen); if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) { @@ -3385,12 +3374,10 @@ START_API_FUNC * each buffer we had. */ while(BufferListStart) { - ALbufferlistitem *next{BufferListStart->next.load(std::memory_order_relaxed)}; - for(i = 0;i < BufferListStart->num_buffers;i++) - { - if((buffer=BufferListStart->buffers[i]) != nullptr) - DecrementRef(&buffer->ref); - } + ALbufferlistitem *next{BufferListStart->mNext.load(std::memory_order_relaxed)}; + std::for_each(BufferListStart->begin(), BufferListStart->end(), + [](ALbuffer *buffer) -> void + { if(buffer) DecrementRef(&buffer->ref); }); al_free(BufferListStart); BufferListStart = next; } @@ -3408,9 +3395,9 @@ START_API_FUNC else { ALbufferlistitem *next; - while((next=BufferList->next.load(std::memory_order_relaxed)) != nullptr) + while((next=BufferList->mNext.load(std::memory_order_relaxed)) != nullptr) BufferList = next; - BufferList->next.store(BufferListStart, std::memory_order_release); + BufferList->mNext.store(BufferListStart, std::memory_order_release); } } END_API_FUNC @@ -3447,27 +3434,27 @@ START_API_FUNC if(UNLIKELY(BufferList == Current)) SETERR_RETURN(context, AL_INVALID_VALUE,, "Unqueueing pending buffers"); - ALsizei i{BufferList->num_buffers}; - while(i < nb) + ALuint i{BufferList->mNumBuffers}; + while(i < static_cast(nb)) { /* If the next bufferlist to check is NULL or is the current one, it's * trying to unqueue pending buffers. */ - ALbufferlistitem *next{BufferList->next.load(std::memory_order_relaxed)}; + ALbufferlistitem *next{BufferList->mNext.load(std::memory_order_relaxed)}; if(UNLIKELY(!next) || UNLIKELY(next == Current)) SETERR_RETURN(context, AL_INVALID_VALUE,, "Unqueueing pending buffers"); BufferList = next; - i += BufferList->num_buffers; + i += BufferList->mNumBuffers; } while(nb > 0) { ALbufferlistitem *head{source->queue}; - ALbufferlistitem *next{head->next.load(std::memory_order_relaxed)}; - for(i = 0;i < head->num_buffers && nb > 0;i++,nb--) + ALbufferlistitem *next{head->mNext.load(std::memory_order_relaxed)}; + for(i = 0;i < head->mNumBuffers && nb > 0;i++,nb--) { - ALbuffer *buffer{head->buffers[i]}; + ALbuffer *buffer{(*head)[i]}; if(!buffer) *(buffers++) = 0; else @@ -3476,21 +3463,21 @@ START_API_FUNC DecrementRef(&buffer->ref); } } - if(i < head->num_buffers) + if(i < head->mNumBuffers) { /* This head has some buffers left over, so move them to the front * and update the sample and buffer count. */ - ALsizei max_length{0}; - ALsizei j{0}; - while(i < head->num_buffers) + ALuint max_length{0}; + ALuint j{0}; + while(i < head->mNumBuffers) { - ALbuffer *buffer{head->buffers[i++]}; - if(buffer) max_length = maxi(max_length, buffer->SampleLen); - head->buffers[j++] = buffer; + ALbuffer *buffer{(*head)[i++]}; + if(buffer) max_length = maxu(max_length, buffer->SampleLen); + head->mBuffers[j++] = buffer; } - head->max_samples = max_length; - head->num_buffers = j; + head->mMaxSamples = max_length; + head->mNumBuffers = j; break; } @@ -3584,12 +3571,10 @@ ALsource::~ALsource() ALbufferlistitem *BufferList{queue}; while(BufferList != nullptr) { - ALbufferlistitem *next{BufferList->next.load(std::memory_order_relaxed)}; - for(ALsizei i{0};i < BufferList->num_buffers;i++) - { - if(BufferList->buffers[i]) - DecrementRef(&BufferList->buffers[i]->ref); - } + ALbufferlistitem *next{BufferList->mNext.load(std::memory_order_relaxed)}; + std::for_each(BufferList->begin(), BufferList->end(), + [](ALbuffer *buffer) -> void + { if(buffer) DecrementRef(&buffer->ref); }); al_free(BufferList); BufferList = next; } diff --git a/al/source.h b/al/source.h index c9892398..1aafafab 100644 --- a/al/source.h +++ b/al/source.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "AL/al.h" #include "AL/alc.h" @@ -21,16 +22,58 @@ struct ALeffectslot; struct ALbufferlistitem { - std::atomic next; - ALsizei max_samples; - ALsizei num_buffers; - ALbuffer *buffers[]; + using element_type = ALbuffer*; + using value_type = ALbuffer*; + using index_type = size_t; + using difference_type = ptrdiff_t; + + using pointer = ALbuffer**; + using const_pointer = ALbuffer*const*; + using reference = ALbuffer*&; + using const_reference = ALbuffer*const&; + + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + + std::atomic mNext; + ALuint mMaxSamples; + ALuint mNumBuffers; + element_type mBuffers[]; static constexpr size_t Sizeof(size_t num_buffers) noexcept { - return maxz(offsetof(ALbufferlistitem, buffers) + sizeof(ALbuffer*)*num_buffers, + return maxz(offsetof(ALbufferlistitem, mBuffers) + sizeof(element_type)*num_buffers, sizeof(ALbufferlistitem)); } + + reference front() { return mBuffers[0]; } + const_reference front() const { return mBuffers[0]; } + reference back() { return mBuffers[mNumBuffers-1]; } + const_reference back() const { return mBuffers[mNumBuffers-1]; } + reference operator[](index_type idx) { return mBuffers[idx]; } + const_reference operator[](index_type idx) const { return mBuffers[idx]; } + pointer data() noexcept { return mBuffers; } + const_pointer data() const noexcept { return mBuffers; } + + index_type size() const noexcept { return mNumBuffers; } + bool empty() const noexcept { return mNumBuffers == 0; } + + iterator begin() noexcept { return mBuffers; } + iterator end() noexcept { return mBuffers+mNumBuffers; } + const_iterator begin() const noexcept { return mBuffers; } + const_iterator end() const noexcept { return mBuffers+mNumBuffers; } + const_iterator cbegin() const noexcept { return mBuffers; } + const_iterator cend() const noexcept { return mBuffers+mNumBuffers; } + + reverse_iterator rbegin() noexcept { return reverse_iterator{end()}; } + reverse_iterator rend() noexcept { return reverse_iterator{begin()}; } + const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator{end()}; } + const_reverse_iterator rend() const noexcept { return const_reverse_iterator{begin()}; } + const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{cend()}; } + const_reverse_iterator crend() const noexcept { return const_reverse_iterator{cbegin()}; } }; diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 881759c0..e2b2bf51 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -382,15 +382,15 @@ void LoadSamples(ALfloat *RESTRICT dst, const al::byte *src, ALint srcstep, FmtT } ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&BufferLoopItem, - const ALsizei NumChannels, const ALsizei SampleSize, const ALsizei chan, ALsizei DataPosInt, + const ALsizei NumChannels, const ALsizei SampleSize, const ALsizei chan, ALuint DataPosInt, al::span SrcBuffer) { /* TODO: For static sources, loop points are taken from the first buffer * (should be adjusted by any buffer offset, to possibly be added later). */ - const ALbuffer *Buffer0{BufferListItem->buffers[0]}; - const ALsizei LoopStart{Buffer0->LoopStart}; - const ALsizei LoopEnd{Buffer0->LoopEnd}; + const ALbuffer *Buffer0{BufferListItem->front()}; + const ALuint LoopStart{Buffer0->LoopStart}; + const ALuint LoopEnd{Buffer0->LoopEnd}; ASSUME(LoopStart >= 0); ASSUME(LoopEnd > LoopStart); @@ -416,10 +416,9 @@ ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&B return CompLen; }; /* It's impossible to have a buffer list item with no entries. */ - ASSUME(BufferListItem->num_buffers > 0); - auto buffers_end = BufferListItem->buffers + BufferListItem->num_buffers; - SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->buffers, buffers_end, - size_t{0u}, load_buffer)); + ASSUME(BufferListItem->mNumBuffers > 0); + SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->begin(), + BufferListItem->end(), size_t{0u}, load_buffer)); } else { @@ -442,10 +441,9 @@ ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&B LoadSamples(SrcData.data(), Data, NumChannels, buffer->mFmtType, DataSize); return CompLen; }; - ASSUME(BufferListItem->num_buffers > 0); - auto buffers_end = BufferListItem->buffers + BufferListItem->num_buffers; - SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->buffers, buffers_end, - size_t{0u}, load_buffer)); + ASSUME(BufferListItem->mNumBuffers > 0); + SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->begin(), + BufferListItem->end(), size_t{0u}, load_buffer)); const auto LoopSize = static_cast(LoopEnd - LoopStart); while(!SrcBuffer.empty()) @@ -468,24 +466,24 @@ ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&B LoadSamples(SrcData.data(), Data, NumChannels, buffer->mFmtType, DataSize); return CompLen; }; - SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->buffers, buffers_end, - size_t{0u}, load_buffer_loop)); + SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->begin(), + BufferListItem->end(), size_t{0u}, load_buffer_loop)); } } return SrcBuffer.begin(); } ALfloat *LoadBufferQueue(ALbufferlistitem *BufferListItem, ALbufferlistitem *BufferLoopItem, - const ALsizei NumChannels, const ALsizei SampleSize, const ALsizei chan, ALsizei DataPosInt, + const ALsizei NumChannels, const ALsizei SampleSize, const ALsizei chan, ALuint DataPosInt, al::span SrcBuffer) { /* Crawl the buffer queue to fill in the temp buffer */ while(BufferListItem && !SrcBuffer.empty()) { - if(DataPosInt >= BufferListItem->max_samples) + if(DataPosInt >= BufferListItem->mMaxSamples) { - DataPosInt -= BufferListItem->max_samples; - BufferListItem = BufferListItem->next.load(std::memory_order_acquire); + DataPosInt -= BufferListItem->mMaxSamples; + BufferListItem = BufferListItem->mNext.load(std::memory_order_acquire); if(!BufferListItem) BufferListItem = BufferLoopItem; continue; } @@ -505,15 +503,14 @@ ALfloat *LoadBufferQueue(ALbufferlistitem *BufferListItem, ALbufferlistitem *Buf LoadSamples(SrcBuffer.data(), Data, NumChannels, buffer->mFmtType, DataSize); return CompLen; }; - ASSUME(BufferListItem->num_buffers > 0); - auto buffers_end = BufferListItem->buffers + BufferListItem->num_buffers; - SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->buffers, buffers_end, - size_t{0u}, load_buffer)); + ASSUME(BufferListItem->mNumBuffers > 0); + SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->begin(), + BufferListItem->end(), size_t{0u}, load_buffer)); if(SrcBuffer.empty()) break; DataPosInt = 0; - BufferListItem = BufferListItem->next.load(std::memory_order_acquire); + BufferListItem = BufferListItem->mNext.load(std::memory_order_acquire); if(!BufferListItem) BufferListItem = BufferLoopItem; } @@ -530,7 +527,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc /* Get voice info */ const bool isstatic{(voice->mFlags&VOICE_IS_STATIC) != 0}; - ALsizei DataPosInt{static_cast(voice->mPosition.load(std::memory_order_relaxed))}; + ALuint DataPosInt{voice->mPosition.load(std::memory_order_relaxed)}; ALsizei DataPosFrac{voice->mPositionFrac.load(std::memory_order_relaxed)}; ALbufferlistitem *BufferListItem{voice->mCurrentBuffer.load(std::memory_order_relaxed)}; ALbufferlistitem *BufferLoopItem{voice->mLoopBuffer.load(std::memory_order_relaxed)}; @@ -538,7 +535,6 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc const ALsizei SampleSize{voice->mSampleSize}; const ALint increment{voice->mStep}; - ASSUME(DataPosInt >= 0); ASSUME(DataPosFrac >= 0); ASSUME(NumChannels > 0); ASSUME(SampleSize > 0); @@ -868,9 +864,9 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc if(BufferLoopItem) { /* Handle looping static source */ - const ALbuffer *Buffer{BufferListItem->buffers[0]}; - const ALsizei LoopStart{Buffer->LoopStart}; - const ALsizei LoopEnd{Buffer->LoopEnd}; + const ALbuffer *Buffer{BufferListItem->front()}; + const ALuint LoopStart{Buffer->LoopStart}; + const ALuint LoopEnd{Buffer->LoopEnd}; if(DataPosInt >= LoopEnd) { assert(LoopEnd > LoopStart); @@ -880,7 +876,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc else { /* Handle non-looping static source */ - if(DataPosInt >= BufferListItem->max_samples) + if(DataPosInt >= BufferListItem->mMaxSamples) { if(LIKELY(vstate == ALvoice::Playing)) vstate = ALvoice::Stopped; @@ -892,13 +888,13 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc else while(1) { /* Handle streaming source */ - if(BufferListItem->max_samples > DataPosInt) + if(BufferListItem->mMaxSamples > DataPosInt) break; - DataPosInt -= BufferListItem->max_samples; + DataPosInt -= BufferListItem->mMaxSamples; - buffers_done += BufferListItem->num_buffers; - BufferListItem = BufferListItem->next.load(std::memory_order_relaxed); + buffers_done += BufferListItem->mNumBuffers; + BufferListItem = BufferListItem->mNext.load(std::memory_order_relaxed); if(!BufferListItem && !(BufferListItem=BufferLoopItem)) { if(LIKELY(vstate == ALvoice::Playing)) -- cgit v1.2.3 From 471f905fbd5f665148d2e9f40aca7ee6b1bead7b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Jul 2019 10:09:43 -0700 Subject: Use enums for the resampler and mixer template tags --- alc/mixer/defs.h | 56 +++++++++++++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/alc/mixer/defs.h b/alc/mixer/defs.h index 3e5d1125..0cd4162a 100644 --- a/alc/mixer/defs.h +++ b/alc/mixer/defs.h @@ -1,46 +1,44 @@ #ifndef MIXER_DEFS_H #define MIXER_DEFS_H -#include "AL/alc.h" #include "AL/al.h" #include "alcmain.h" -#include "alu.h" #include "alspan.h" - - -struct MixGains; -struct MixHrtfFilter; -struct HrtfState; -struct DirectHrtfState; - - -struct CTag { }; -struct SSETag { }; -struct SSE2Tag { }; -struct SSE3Tag { }; -struct SSE4Tag { }; -struct NEONTag { }; - -struct CopyTag { }; -struct PointTag { }; -struct LerpTag { }; -struct CubicTag { }; -struct BSincTag { }; - -template +#include "alu.h" +#include "hrtf.h" + + +enum InstSetType { + CTag, + SSETag, + SSE2Tag, + SSE3Tag, + SSE4Tag, + NEONTag +}; + +enum ResampleType { + CopyTag, + PointTag, + LerpTag, + CubicTag, + BSincTag +}; + +template const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen); -template +template void Mix_(const ALfloat *data, const al::span OutBuffer, ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize); -template +template void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize); -template +template void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfFilter *hrtfparams, const ALsizei BufferSize); -template +template void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize); -template +template void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, const ALsizei BufferSize); /* Vectorized resampler helpers */ -- cgit v1.2.3 From d1f72624a749bd9c2a17ddeb303703a78f53d4a5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Jul 2019 10:28:04 -0700 Subject: Fix a couple ASSUME statements --- alc/mixer/mixer_sse2.cpp | 2 +- alc/mixer/mixer_sse41.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/alc/mixer/mixer_sse2.cpp b/alc/mixer/mixer_sse2.cpp index b5d00106..b1c67f09 100644 --- a/alc/mixer/mixer_sse2.cpp +++ b/alc/mixer/mixer_sse2.cpp @@ -35,7 +35,7 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES const __m128 fracOne4{_mm_set1_ps(1.0f/FRACTIONONE)}; const __m128i fracMask4{_mm_set1_epi32(FRACTIONMASK)}; - ASSUME(frac > 0); + ASSUME(frac >= 0); ASSUME(increment > 0); ASSUME(dstlen >= 0); diff --git a/alc/mixer/mixer_sse41.cpp b/alc/mixer/mixer_sse41.cpp index 7efbda7b..077be44c 100644 --- a/alc/mixer/mixer_sse41.cpp +++ b/alc/mixer/mixer_sse41.cpp @@ -36,7 +36,7 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES const __m128 fracOne4{_mm_set1_ps(1.0f/FRACTIONONE)}; const __m128i fracMask4{_mm_set1_epi32(FRACTIONMASK)}; - ASSUME(frac > 0); + ASSUME(frac >= 0); ASSUME(increment > 0); ASSUME(dstlen >= 0); -- cgit v1.2.3 From 151ff51e7d7b8265cac804f3b754a87924902090 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Jul 2019 10:46:33 -0700 Subject: Don't templatize HrirArray --- alc/alu.h | 2 +- alc/hrtf.cpp | 4 ++-- alc/hrtf.h | 14 ++++++-------- alc/mixer/hrtfbase.h | 4 ++-- alc/mixer/mixer_c.cpp | 2 +- alc/mixer/mixer_neon.cpp | 2 +- alc/mixer/mixer_sse.cpp | 2 +- 7 files changed, 14 insertions(+), 16 deletions(-) diff --git a/alc/alu.h b/alc/alu.h index 88c22e6f..d569c482 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -98,7 +98,7 @@ enum { struct MixHrtfFilter { - const HrirArray *Coeffs; + const HrirArray *Coeffs; ALsizei Delay[2]; ALfloat Gain; ALfloat GainStep; diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index 786c4c5d..8130288a 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -216,7 +216,7 @@ IdxBlend CalcAzIndex(ALsizei azcount, ALfloat az) * and azimuth in radians. The coefficients are normalized. */ void GetHrtfCoeffs(const HrtfEntry *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat distance, - ALfloat spread, HrirArray &coeffs, ALsizei (&delays)[2]) + ALfloat spread, HrirArray &coeffs, ALsizei (&delays)[2]) { const ALfloat dirfact{1.0f - (spread / al::MathDefs::Tau())}; @@ -348,7 +348,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin const ALdouble xover_norm{400.0 / Hrtf->sampleRate}; BandSplitterR splitter{xover_norm}; - auto tmpres = al::vector>(NumChannels); + auto tmpres = al::vector,HRIR_LENGTH>>(NumChannels); auto tmpfilt = al::vector>(3); for(size_t c{0u};c < AmbiCount;++c) { diff --git a/alc/hrtf.h b/alc/hrtf.h index 29f7fce0..e40e6cb4 100644 --- a/alc/hrtf.h +++ b/alc/hrtf.h @@ -63,17 +63,15 @@ struct EnumeratedHrtf { using float2 = std::array; - -template -using HrirArray = std::array,HRIR_LENGTH>; +using HrirArray = std::array; struct HrtfState { alignas(16) std::array History; - alignas(16) HrirArray Values; + alignas(16) HrirArray Values; }; struct HrtfFilter { - alignas(16) HrirArray Coeffs; + alignas(16) HrirArray Coeffs; ALsizei Delay[2]; ALfloat Gain; }; @@ -82,8 +80,8 @@ struct DirectHrtfState { /* HRTF filter state for dry buffer content */ ALsizei IrSize{0}; struct ChanData { - alignas(16) HrirArray Values; - alignas(16) HrirArray Coeffs; + alignas(16) HrirArray Values; + alignas(16) HrirArray Coeffs; }; al::FlexArray Chan; @@ -108,7 +106,7 @@ al::vector EnumerateHrtf(const char *devname); HrtfEntry *GetLoadedHrtf(HrtfHandle *handle); void GetHrtfCoeffs(const HrtfEntry *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat distance, - ALfloat spread, HrirArray &coeffs, ALsizei (&delays)[2]); + ALfloat spread, HrirArray &coeffs, ALsizei (&delays)[2]); /** * Produces HRTF filter coefficients for decoding B-Format, given a set of diff --git a/alc/mixer/hrtfbase.h b/alc/mixer/hrtfbase.h index a76bd62e..3c8208f3 100644 --- a/alc/mixer/hrtfbase.h +++ b/alc/mixer/hrtfbase.h @@ -9,7 +9,7 @@ using ApplyCoeffsT = void(ALsizei Offset, float2 *RESTRICT Values, const ALsizei irSize, - const HrirArray &Coeffs, const ALfloat left, const ALfloat right); + const HrirArray &Coeffs, const ALfloat left, const ALfloat right); template inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, @@ -20,7 +20,7 @@ inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, ASSUME(IrSize >= 4); ASSUME(BufferSize > 0); - const auto &Coeffs = *hrtfparams->Coeffs; + const HrirArray &Coeffs = *hrtfparams->Coeffs; const ALfloat gainstep{hrtfparams->GainStep}; const ALfloat gain{hrtfparams->Gain}; diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index 3513cf2b..765b03fa 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -104,7 +104,7 @@ const ALfloat *Resample_(const InterpState *state, const ALfloat static inline void ApplyCoeffs(ALsizei /*Offset*/, float2 *RESTRICT Values, const ALsizei IrSize, - const HrirArray &Coeffs, const ALfloat left, const ALfloat right) + const HrirArray &Coeffs, const ALfloat left, const ALfloat right) { ASSUME(IrSize >= 2); for(ALsizei c{0};c < IrSize;++c) diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index fa487d97..b4ca61d7 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -136,7 +136,7 @@ const ALfloat *Resample_(const InterpState *state, const ALflo static inline void ApplyCoeffs(ALsizei /*Offset*/, float2 *RESTRICT Values, const ALsizei IrSize, - const HrirArray &Coeffs, const ALfloat left, const ALfloat right) + const HrirArray &Coeffs, const ALfloat left, const ALfloat right) { ASSUME(IrSize >= 2); diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index 516dabac..b52ef256 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -75,7 +75,7 @@ const ALfloat *Resample_(const InterpState *state, const ALfloa static inline void ApplyCoeffs(ALsizei Offset, float2 *RESTRICT Values, const ALsizei IrSize, - const HrirArray &Coeffs, const ALfloat left, const ALfloat right) + const HrirArray &Coeffs, const ALfloat left, const ALfloat right) { const __m128 lrlr{_mm_setr_ps(left, right, left, right)}; -- cgit v1.2.3 From 62534f424ae0534927f948fa6cead4bdd9f73745 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Jul 2019 11:05:53 -0700 Subject: Use float2 where appropriate --- alc/hrtf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index 8130288a..124707c5 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -436,8 +436,8 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin for(ALuint i{0u};i < NumChannels;++i) { - auto copy_arr = [](const std::array &in) noexcept -> std::array - { return std::array{{static_cast(in[0]), static_cast(in[1])}}; }; + auto copy_arr = [](const std::array &in) noexcept -> float2 + { return float2{{static_cast(in[0]), static_cast(in[1])}}; }; std::transform(tmpres[i].begin(), tmpres[i].end(), state->Chan[i].Coeffs.begin(), copy_arr); } -- cgit v1.2.3 From 380f3dc11de1b3d8e6a00b2920cb809cfb953c0d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Aug 2019 09:21:56 -0700 Subject: Cleanup alcontext.h includes --- alc/alcontext.h | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/alc/alcontext.h b/alc/alcontext.h index 833d4c5b..43b9c08f 100644 --- a/alc/alcontext.h +++ b/alc/alcontext.h @@ -1,14 +1,16 @@ #ifndef ALCONTEXT_H #define ALCONTEXT_H -#include #include +#include +#include #include +#include #include +#include #include "AL/al.h" #include "AL/alc.h" -#include "AL/alext.h" #include "al/listener.h" #include "almalloc.h" @@ -20,15 +22,12 @@ #include "threads.h" #include "vector.h" - -struct ALsource; struct ALeffectslot; -struct ALcontextProps; -struct ALlistenerProps; -struct ALvoiceProps; struct ALeffectslotProps; +struct ALsource; struct RingBuffer; + enum class DistanceModel { InverseClamped = AL_INVERSE_DISTANCE_CLAMPED, LinearClamped = AL_LINEAR_DISTANCE_CLAMPED, @@ -41,6 +40,19 @@ enum class DistanceModel { Default = InverseClamped }; + +struct ALcontextProps { + ALfloat DopplerFactor; + ALfloat DopplerVelocity; + ALfloat SpeedOfSound; + ALboolean SourceDistanceModel; + DistanceModel mDistanceModel; + ALfloat MetersPerUnit; + + std::atomic next; +}; + + struct SourceSubList { uint64_t FreeMask{~0_u64}; ALsource *Sources{nullptr}; /* 64 */ @@ -153,8 +165,7 @@ struct ALCcontext { * This does *NOT* stop mixing, but rather prevents certain property * changes from taking effect. */ - void deferUpdates() noexcept - { mDeferUpdates.store(true); } + void deferUpdates() noexcept { mDeferUpdates.store(true); } /** Resumes update processing after being deferred. */ void processUpdates(); @@ -221,18 +232,6 @@ inline bool operator<(const ContextRef &lhs, const ALCcontext *rhs) noexcept ContextRef GetContextRef(void); -struct ALcontextProps { - ALfloat DopplerFactor; - ALfloat DopplerVelocity; - ALfloat SpeedOfSound; - ALboolean SourceDistanceModel; - DistanceModel mDistanceModel; - ALfloat MetersPerUnit; - - std::atomic next; -}; - - extern bool TrapALError; #endif /* ALCONTEXT_H */ -- cgit v1.2.3 From 65f7fc610e6a6101509906c0c9bbbd794c9a3737 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Aug 2019 13:28:53 -0700 Subject: Add a common base for auto-deleting ref-counted objects Which will also work as the basis for a future intrusive_ptr --- CMakeLists.txt | 1 + al/auxeffectslot.cpp | 44 +++++++++++-------------------- al/buffer.cpp | 8 +++--- al/event.cpp | 2 +- al/source.cpp | 26 +++++++++---------- alc/alc.cpp | 70 +++++++++++++++++--------------------------------- alc/alcmain.h | 5 ++-- alc/alcontext.h | 9 +++---- alc/alu.cpp | 24 +++++------------ alc/backends/base.cpp | 4 +-- alc/effects/base.h | 9 ++----- alc/hrtf.cpp | 8 +++--- common/atomic.h | 16 ++++++------ common/intrusive_ptr.h | 48 ++++++++++++++++++++++++++++++++++ 14 files changed, 133 insertions(+), 141 deletions(-) create mode 100644 common/intrusive_ptr.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e72f2a01..5f3f9763 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -598,6 +598,7 @@ SET(COMMON_OBJS common/aloptional.h common/alspan.h common/atomic.h + common/intrusive_ptr.h common/math_defs.h common/opthelpers.h common/threads.cpp diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index 2d10efde..b4e93858 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -320,7 +320,7 @@ START_API_FUNC context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", id); return true; } - if(ReadRef(&slot->ref) != 0) + if(ReadRef(slot->ref) != 0) { context->setError(AL_INVALID_NAME, "Deleting in-use effect slot %u", id); return true; @@ -418,14 +418,14 @@ START_API_FUNC /* We must force an update if there was an existing effect slot * target, in case it's about to be deleted. */ - if(target) IncrementRef(&target->ref); - DecrementRef(&oldtarget->ref); + if(target) IncrementRef(target->ref); + DecrementRef(oldtarget->ref); slot->Target = target; UpdateEffectSlotProps(slot, context.get()); return; } - if(target) IncrementRef(&target->ref); + if(target) IncrementRef(target->ref); slot->Target = target; break; @@ -651,7 +651,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect { statelock.unlock(); mixer_mode.leave(); - State->DecRef(); + State->release(); return AL_OUT_OF_MEMORY; } mixer_mode.leave(); @@ -667,7 +667,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect EffectSlot->Effect.Props = effect->Props; } - EffectSlot->Effect.State->DecRef(); + EffectSlot->Effect.State->release(); EffectSlot->Effect.State = State; } else if(effect) @@ -678,7 +678,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect while(props) { if(props->State) - props->State->DecRef(); + props->State->release(); props->State = nullptr; props = props->next.load(std::memory_order_relaxed); } @@ -687,20 +687,6 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect } -void EffectState::IncRef() noexcept -{ - auto ref = IncrementRef(&mRef); - TRACEREF("EffectState %p increasing refcount to %u\n", this, ref); -} - -void EffectState::DecRef() noexcept -{ - auto ref = DecrementRef(&mRef); - TRACEREF("EffectState %p decreasing refcount to %u\n", this, ref); - if(ref == 0) delete this; -} - - ALenum InitEffectSlot(ALeffectslot *slot) { EffectStateFactory *factory{getFactoryByType(slot->Effect.Type)}; @@ -708,7 +694,7 @@ ALenum InitEffectSlot(ALeffectslot *slot) slot->Effect.State = factory->create(); if(!slot->Effect.State) return AL_OUT_OF_MEMORY; - slot->Effect.State->IncRef(); + slot->Effect.State->add_ref(); slot->Params.mEffectState = slot->Effect.State; return AL_NO_ERROR; } @@ -716,21 +702,21 @@ ALenum InitEffectSlot(ALeffectslot *slot) ALeffectslot::~ALeffectslot() { if(Target) - DecrementRef(&Target->ref); + DecrementRef(Target->ref); Target = nullptr; ALeffectslotProps *props{Update.load()}; if(props) { - if(props->State) props->State->DecRef(); + if(props->State) props->State->release(); TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props); al_free(props); } if(Effect.State) - Effect.State->DecRef(); + Effect.State->release(); if(Params.mEffectState) - Params.mEffectState->DecRef(); + Params.mEffectState->release(); } void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) @@ -759,7 +745,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) * delete it. */ EffectState *oldstate{props->State}; - slot->Effect.State->IncRef(); + slot->Effect.State->add_ref(); props->State = slot->Effect.State; /* Set the new container for updating internal parameters. */ @@ -770,13 +756,13 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) * freelist. */ if(props->State) - props->State->DecRef(); + props->State->release(); props->State = nullptr; AtomicReplaceHead(context->mFreeEffectslotProps, props); } if(oldstate) - oldstate->DecRef(); + oldstate->release(); } void UpdateAllEffectSlotProps(ALCcontext *context) diff --git a/al/buffer.cpp b/al/buffer.cpp index 4e843e03..173c76bd 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -380,7 +380,7 @@ const ALchar *NameFromUserFmtType(UserFmtType type) */ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, UserFmtChannels SrcChannels, UserFmtType SrcType, const al::byte *SrcData, ALbitfieldSOFT access) { - if(UNLIKELY(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)) + if(UNLIKELY(ReadRef(ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)) SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer %u", ALBuf->id); @@ -671,7 +671,7 @@ START_API_FUNC context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", bid); return true; } - if(UNLIKELY(ReadRef(&ALBuf->ref) != 0)) + if(UNLIKELY(ReadRef(ALBuf->ref) != 0)) { context->setError(AL_INVALID_OPERATION, "Deleting in-use buffer %u", bid); return true; @@ -768,7 +768,7 @@ START_API_FUNC else { ALbitfieldSOFT unavailable = (albuf->Access^access) & access; - if(UNLIKELY(ReadRef(&albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT))) + if(UNLIKELY(ReadRef(albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT))) context->setError(AL_INVALID_OPERATION, "Mapping in-use buffer %u without persistent mapping", buffer); else if(UNLIKELY(albuf->MappedAccess != 0)) @@ -1126,7 +1126,7 @@ START_API_FUNC else switch(param) { case AL_LOOP_POINTS_SOFT: - if(UNLIKELY(ReadRef(&albuf->ref) != 0)) + if(UNLIKELY(ReadRef(albuf->ref) != 0)) context->setError(AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points", buffer); else if(UNLIKELY(values[0] < 0 || values[0] >= values[1] || diff --git a/al/event.cpp b/al/event.cpp index 0d41e713..75827b59 100644 --- a/al/event.cpp +++ b/al/event.cpp @@ -64,7 +64,7 @@ static int EventThread(ALCcontext *context) if(evt.EnumType == EventType_ReleaseEffectState) { - evt.u.mEffectState->DecRef(); + evt.u.mEffectState->release(); continue; } diff --git a/al/source.cpp b/al/source.cpp index 6708c970..1e0940de 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -1309,7 +1309,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co newlist->mMaxSamples = buffer->SampleLen; newlist->mNumBuffers = 1; newlist->mBuffers[0] = buffer; - IncrementRef(&buffer->ref); + IncrementRef(buffer->ref); /* Source is now Static */ Source->SourceType = AL_STATIC; @@ -1331,7 +1331,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co std::for_each(temp->begin(), temp->end(), [](ALbuffer *buffer) -> void - { if(buffer) DecrementRef(&buffer->ref); }); + { if(buffer) DecrementRef(buffer->ref); }); al_free(temp); } return AL_TRUE; @@ -1475,9 +1475,9 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source)) { /* Add refcount on the new slot, and release the previous slot */ - if(slot) IncrementRef(&slot->ref); + if(slot) IncrementRef(slot->ref); if(Source->Send[values[1]].Slot) - DecrementRef(&Source->Send[values[1]].Slot->ref); + DecrementRef(Source->Send[values[1]].Slot->ref); Source->Send[values[1]].Slot = slot; /* We must force an update if the auxiliary slot changed on an @@ -1489,9 +1489,9 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co } else { - if(slot) IncrementRef(&slot->ref); + if(slot) IncrementRef(slot->ref); if(Source->Send[values[1]].Slot) - DecrementRef(&Source->Send[values[1]].Slot->ref); + DecrementRef(Source->Send[values[1]].Slot->ref); Source->Send[values[1]].Slot = slot; UpdateSourceProps(Source, Context); } @@ -3249,7 +3249,7 @@ START_API_FUNC BufferList->mBuffers[0] = buffer; if(!buffer) continue; - IncrementRef(&buffer->ref); + IncrementRef(buffer->ref); if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) { @@ -3274,7 +3274,7 @@ START_API_FUNC ALbufferlistitem *next = BufferListStart->mNext.load(std::memory_order_relaxed); std::for_each(BufferListStart->begin(), BufferListStart->end(), [](ALbuffer *buffer) -> void - { if(buffer) DecrementRef(&buffer->ref); }); + { if(buffer) DecrementRef(buffer->ref); }); al_free(BufferListStart); BufferListStart = next; } @@ -3350,7 +3350,7 @@ START_API_FUNC BufferList->mBuffers[BufferList->mNumBuffers++] = buffer; if(!buffer) continue; - IncrementRef(&buffer->ref); + IncrementRef(buffer->ref); BufferList->mMaxSamples = maxu(BufferList->mMaxSamples, buffer->SampleLen); @@ -3377,7 +3377,7 @@ START_API_FUNC ALbufferlistitem *next{BufferListStart->mNext.load(std::memory_order_relaxed)}; std::for_each(BufferListStart->begin(), BufferListStart->end(), [](ALbuffer *buffer) -> void - { if(buffer) DecrementRef(&buffer->ref); }); + { if(buffer) DecrementRef(buffer->ref); }); al_free(BufferListStart); BufferListStart = next; } @@ -3460,7 +3460,7 @@ START_API_FUNC else { *(buffers++) = buffer->id; - DecrementRef(&buffer->ref); + DecrementRef(buffer->ref); } } if(i < head->mNumBuffers) @@ -3574,7 +3574,7 @@ ALsource::~ALsource() ALbufferlistitem *next{BufferList->mNext.load(std::memory_order_relaxed)}; std::for_each(BufferList->begin(), BufferList->end(), [](ALbuffer *buffer) -> void - { if(buffer) DecrementRef(&buffer->ref); }); + { if(buffer) DecrementRef(buffer->ref); }); al_free(BufferList); BufferList = next; } @@ -3584,7 +3584,7 @@ ALsource::~ALsource() [](ALsource::SendData &send) -> void { if(send.Slot) - DecrementRef(&send.Slot->ref); + DecrementRef(send.Slot->ref); send.Slot = nullptr; } ); diff --git a/alc/alc.cpp b/alc/alc.cpp index 240aca6d..73723f26 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -79,6 +79,7 @@ #include "fpu_modes.h" #include "hrtf.h" #include "inprogext.h" +#include "intrusive_ptr.h" #include "logging.h" #include "mastering.h" #include "opthelpers.h" @@ -832,9 +833,9 @@ std::atomic LastNullDeviceError{ALC_NO_ERROR}; /* Thread-local current context */ void ReleaseThreadCtx(ALCcontext *context) { - auto ref = DecrementRef(&context->mRef); - TRACEREF("ALCcontext %p decreasing refcount to %u\n", context, ref); - ERR("Context %p current for thread being destroyed, possible leak!\n", context); + const bool result{context->releaseIfNoDelete()}; + ERR("Context %p current for thread being destroyed%s!\n", context, + result ? "" : ", leak detected"); } std::atomic ThreadCtxProc{ReleaseThreadCtx}; @@ -907,19 +908,6 @@ constexpr ALCint alcEFXMinorVersion = 0; al::FlexArray EmptyContextArray{0u}; -void ALCdevice_IncRef(ALCdevice *device) -{ - auto ref = IncrementRef(&device->ref); - TRACEREF("ALCdevice %p increasing refcount to %u\n", device, ref); -} - -void ALCdevice_DecRef(ALCdevice *device) -{ - auto ref = DecrementRef(&device->ref); - TRACEREF("ALCdevice %p decreasing refcount to %u\n", device, ref); - if(UNLIKELY(ref == 0)) delete device; -} - /* Simple RAII device reference. Takes the reference of the provided ALCdevice, * and decrements it when leaving scope. Movable (transfer reference) but not * copyable (no new references). @@ -930,7 +918,7 @@ class DeviceRef { void reset() noexcept { if(mDev) - ALCdevice_DecRef(mDev); + mDev->release(); mDev = nullptr; } @@ -1658,10 +1646,10 @@ static std::unique_ptr CreateDeviceLimiter(const ALCdevice *device, */ static inline void UpdateClockBase(ALCdevice *device) { - IncrementRef(&device->MixCount); + IncrementRef(device->MixCount); device->ClockBase += nanoseconds{seconds{device->SamplesDone}} / device->Frequency; device->SamplesDone = 0; - IncrementRef(&device->MixCount); + IncrementRef(device->MixCount); } /* UpdateDeviceParams @@ -2205,7 +2193,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) for(s = device->NumAuxSends;s < old_sends;s++) { if(source->Send[s].Slot) - DecrementRef(&source->Send[s].Slot->ref); + DecrementRef(source->Send[s].Slot->ref); source->Send[s].Slot = nullptr; } source->Send.resize(device->NumAuxSends); @@ -2360,7 +2348,7 @@ static DeviceRef VerifyDevice(ALCdevice *device) auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device); if(iter != DeviceList.cend() && *iter == device) { - ALCdevice_IncRef(iter->get()); + (*iter)->add_ref(); return DeviceRef{iter->get()}; } return DeviceRef{}; @@ -2459,7 +2447,7 @@ ALCcontext::~ALCcontext() while(eprops) { ALeffectslotProps *next{eprops->next.load(std::memory_order_relaxed)}; - if(eprops->State) eprops->State->DecRef(); + if(eprops->State) eprops->State->release(); al_free(eprops); eprops = next; ++count; @@ -2528,7 +2516,7 @@ ALCcontext::~ALCcontext() mAsyncEvents->readAdvance(count); } - ALCdevice_DecRef(mDevice); + mDevice->release(); } /* ReleaseContext @@ -2543,12 +2531,12 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) { WARN("%p released while current on thread\n", context); LocalContext.set(nullptr); - context->decRef(); + context->release(); } ALCcontext *origctx{context}; if(GlobalContext.compare_exchange_strong(origctx, nullptr)) - context->decRef(); + context->release(); bool ret{}; { @@ -2594,18 +2582,6 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) return ret; } -static void ALCcontext_IncRef(ALCcontext *context) -{ - auto ref = IncrementRef(&context->mRef); - TRACEREF("ALCcontext %p increasing refcount to %u\n", context, ref); -} - -void ALCcontext::decRef() noexcept -{ - auto ref = DecrementRef(&mRef); - TRACEREF("ALCcontext %p decreasing refcount to %u\n", this, ref); - if(UNLIKELY(ref == 0)) delete this; -} /* VerifyContext * @@ -2617,7 +2593,7 @@ static ContextRef VerifyContext(ALCcontext *context) auto iter = std::lower_bound(ContextList.cbegin(), ContextList.cend(), context); if(iter != ContextList.cend() && *iter == context) { - ALCcontext_IncRef(iter->get()); + (*iter)->add_ref(); return ContextRef{iter->get()}; } return ContextRef{}; @@ -2632,12 +2608,12 @@ ContextRef GetContextRef(void) { ALCcontext *context{LocalContext.get()}; if(context) - ALCcontext_IncRef(context); + context->add_ref(); else { std::lock_guard _{ListLock}; context = GlobalContext.load(std::memory_order_acquire); - if(context) ALCcontext_IncRef(context); + if(context) context->add_ref(); } return ContextRef{context}; } @@ -3278,11 +3254,11 @@ START_API_FUNC ALuint samplecount; ALuint refcount; do { - while(((refcount=ReadRef(&dev->MixCount))&1) != 0) + while(((refcount=ReadRef(dev->MixCount))&1) != 0) std::this_thread::yield(); basecount = dev->ClockBase; samplecount = dev->SamplesDone; - } while(refcount != ReadRef(&dev->MixCount)); + } while(refcount != ReadRef(dev->MixCount)); basecount += nanoseconds{seconds{samplecount}} / dev->Frequency; *values = basecount.count(); } @@ -3426,7 +3402,7 @@ START_API_FUNC dev->LastError.store(ALC_NO_ERROR); ContextRef context{new ALCcontext{dev.get()}}; - ALCdevice_IncRef(context->mDevice); + dev->add_ref(); ALCenum err{UpdateDeviceParams(dev.get(), attrList)}; if(err != ALC_NO_ERROR) @@ -3502,7 +3478,7 @@ START_API_FUNC { std::lock_guard _{ListLock}; auto iter = std::lower_bound(ContextList.cbegin(), ContextList.cend(), context.get()); - ALCcontext_IncRef(context.get()); + context->add_ref(); ContextList.insert(iter, ContextRef{context.get()}); } @@ -3850,7 +3826,7 @@ START_API_FUNC { std::lock_guard _{ListLock}; auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get()); - ALCdevice_IncRef(device.get()); + device->add_ref(); DeviceList.insert(iter, DeviceRef{device.get()}); } @@ -3976,7 +3952,7 @@ START_API_FUNC { std::lock_guard _{ListLock}; auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get()); - ALCdevice_IncRef(device.get()); + device->add_ref(); DeviceList.insert(iter, DeviceRef{device.get()}); } @@ -4145,7 +4121,7 @@ START_API_FUNC { std::lock_guard _{ListLock}; auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get()); - ALCdevice_IncRef(device.get()); + device->add_ref(); DeviceList.insert(iter, DeviceRef{device.get()}); } diff --git a/alc/alcmain.h b/alc/alcmain.h index f69dc755..5b4e4a2b 100644 --- a/alc/alcmain.h +++ b/alc/alcmain.h @@ -24,6 +24,7 @@ #include "atomic.h" #include "hrtf.h" #include "inprogext.h" +#include "intrusive_ptr.h" #include "vector.h" class BFormatDec; @@ -310,9 +311,7 @@ enum { DeviceFlagsCount }; -struct ALCdevice { - RefCount ref{1u}; - +struct ALCdevice : public al::intrusive_ref { std::atomic Connected{true}; const DeviceType Type{}; diff --git a/alc/alcontext.h b/alc/alcontext.h index 43b9c08f..53da10dc 100644 --- a/alc/alcontext.h +++ b/alc/alcontext.h @@ -18,6 +18,7 @@ #include "alu.h" #include "atomic.h" #include "inprogext.h" +#include "intrusive_ptr.h" #include "logging.h" #include "threads.h" #include "vector.h" @@ -84,9 +85,7 @@ struct EffectSlotSubList { { std::swap(FreeMask, rhs.FreeMask); std::swap(EffectSlots, rhs.EffectSlots); return *this; } }; -struct ALCcontext { - RefCount mRef{1u}; - +struct ALCcontext : public al::intrusive_ref { al::vector mSourceList; ALuint mNumSources{0}; std::mutex mSourceLock; @@ -156,8 +155,6 @@ struct ALCcontext { ALCcontext& operator=(const ALCcontext&) = delete; ~ALCcontext(); - void decRef() noexcept; - void allocVoices(size_t num_voices); /** @@ -194,7 +191,7 @@ class ContextRef { void reset() noexcept { if(mCtx) - mCtx->decRef(); + mCtx->release(); mCtx = nullptr; } diff --git a/alc/alu.cpp b/alc/alu.cpp index 2469d08d..8d627b97 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -373,20 +373,10 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) EffectState *oldstate{slot->Params.mEffectState}; slot->Params.mEffectState = state; - /* Manually decrement the old effect state's refcount if it's greater - * than 1. We need to be a bit clever here to avoid the refcount - * reaching 0 since it can't be deleted in the mixer. + /* Only decrement the old state if it won't get deleted, since we can't + * be deleting/freeing anything in the mixer. */ - ALuint oldval{oldstate->mRef.load(std::memory_order_acquire)}; - while(oldval > 1 && !oldstate->mRef.compare_exchange_weak(oldval, oldval-1, - std::memory_order_acq_rel, std::memory_order_acquire)) - { - /* oldval was updated with the current value on failure, so just - * try again. - */ - } - - if(oldval < 2) + if(!oldstate->releaseIfNoDelete()) { /* Otherwise, if it would be deleted, send it off with a release * event. @@ -1355,7 +1345,7 @@ void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray *slots) { - IncrementRef(&ctx->mUpdateCount); + IncrementRef(ctx->mUpdateCount); if(LIKELY(!ctx->mHoldUpdates.load(std::memory_order_acquire))) { bool cforce{CalcContextParams(ctx)}; @@ -1374,7 +1364,7 @@ void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray *slots) } ); } - IncrementRef(&ctx->mUpdateCount); + IncrementRef(ctx->mUpdateCount); } void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) @@ -1676,7 +1666,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) ); /* Increment the mix count at the start (lsb should now be 1). */ - IncrementRef(&device->MixCount); + IncrementRef(device->MixCount); /* For each context on this device, process and mix its sources and * effects. @@ -1694,7 +1684,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) device->SamplesDone %= device->Frequency; /* Increment the mix count at the end (lsb should now be 0). */ - IncrementRef(&device->MixCount); + IncrementRef(device->MixCount); /* Apply any needed post-process for finalizing the Dry mix to the * RealOut (Ambisonic decode, UHJ encode, etc). diff --git a/alc/backends/base.cpp b/alc/backends/base.cpp index 78b9196e..095990b7 100644 --- a/alc/backends/base.cpp +++ b/alc/backends/base.cpp @@ -43,11 +43,11 @@ ClockLatency BackendBase::getClockLatency() ALuint refcount; do { - while(((refcount=mDevice->MixCount.load(std::memory_order_acquire))&1)) + while(((refcount=ReadRef(mDevice->MixCount))&1) != 0) std::this_thread::yield(); ret.ClockTime = GetDeviceClockTime(mDevice); std::atomic_thread_fence(std::memory_order_acquire); - } while(refcount != mDevice->MixCount.load(std::memory_order_relaxed)); + } while(refcount != ReadRef(mDevice->MixCount)); /* NOTE: The device will generally have about all but one periods filled at * any given time during playback. Without a more accurate measurement from diff --git a/alc/effects/base.h b/alc/effects/base.h index 4f48de22..89a9e8e4 100644 --- a/alc/effects/base.h +++ b/alc/effects/base.h @@ -5,7 +5,7 @@ #include "almalloc.h" #include "alspan.h" #include "atomic.h" - +#include "intrusive_ptr.h" struct ALeffectslot; @@ -149,9 +149,7 @@ struct EffectTarget { RealMixParams *RealOut; }; -struct EffectState { - RefCount mRef{1u}; - +struct EffectState : public al::intrusive_ref { al::span mOutTarget; @@ -160,9 +158,6 @@ struct EffectState { virtual ALboolean deviceUpdate(const ALCdevice *device) = 0; virtual void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) = 0; virtual void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) = 0; - - void IncRef() noexcept; - void DecRef() noexcept; }; diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index 124707c5..a8b56019 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -484,7 +484,7 @@ std::unique_ptr CreateHrtfStore(ALuint rate, ALsizei irSize, const AL ERR("Out of memory allocating storage for %s.\n", filename); else { - InitRef(&Hrtf->ref, 1u); + InitRef(Hrtf->ref, 1u); Hrtf->sampleRate = rate; Hrtf->irSize = irSize; Hrtf->fdCount = fdCount; @@ -1373,13 +1373,13 @@ HrtfEntry *GetLoadedHrtf(HrtfHandle *handle) void HrtfEntry::IncRef() { - auto ref = IncrementRef(&this->ref); + auto ref = IncrementRef(this->ref); TRACEREF("HrtfEntry %p increasing refcount to %u\n", this, ref); } void HrtfEntry::DecRef() { - auto ref = DecrementRef(&this->ref); + auto ref = DecrementRef(this->ref); TRACEREF("HrtfEntry %p decreasing refcount to %u\n", this, ref); if(ref == 0) { @@ -1389,7 +1389,7 @@ void HrtfEntry::DecRef() auto delete_unused = [](HrtfHandlePtr &handle) -> void { HrtfEntry *entry{handle->entry.get()}; - if(entry && ReadRef(&entry->ref) == 0) + if(entry && ReadRef(entry->ref) == 0) { TRACE("Unloading unused HRTF %s\n", handle->filename.data()); handle->entry = nullptr; diff --git a/common/atomic.h b/common/atomic.h index e34f35bb..5e9b04c6 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -6,14 +6,14 @@ using RefCount = std::atomic; -inline void InitRef(RefCount *ptr, unsigned int value) -{ ptr->store(value, std::memory_order_relaxed); } -inline unsigned int ReadRef(RefCount *ptr) -{ return ptr->load(std::memory_order_acquire); } -inline unsigned int IncrementRef(RefCount *ptr) -{ return ptr->fetch_add(1u, std::memory_order_acq_rel)+1u; } -inline unsigned int DecrementRef(RefCount *ptr) -{ return ptr->fetch_sub(1u, std::memory_order_acq_rel)-1u; } +inline void InitRef(RefCount &ref, unsigned int value) +{ ref.store(value, std::memory_order_relaxed); } +inline unsigned int ReadRef(RefCount &ref) +{ return ref.load(std::memory_order_acquire); } +inline unsigned int IncrementRef(RefCount &ref) +{ return ref.fetch_add(1u, std::memory_order_acq_rel)+1u; } +inline unsigned int DecrementRef(RefCount &ref) +{ return ref.fetch_sub(1u, std::memory_order_acq_rel)-1u; } /* WARNING: A livelock is theoretically possible if another thread keeps diff --git a/common/intrusive_ptr.h b/common/intrusive_ptr.h new file mode 100644 index 00000000..8f34aeac --- /dev/null +++ b/common/intrusive_ptr.h @@ -0,0 +1,48 @@ +#ifndef INTRUSIVE_PTR_H +#define INTRUSIVE_PTR_H + +#include "atomic.h" +#include "opthelpers.h" + + +namespace al { + +template +class intrusive_ref { + RefCount mRef{1u}; + +public: + unsigned int add_ref() noexcept { return IncrementRef(mRef); } + unsigned int release() noexcept + { + auto ref = DecrementRef(mRef); + if(UNLIKELY(ref == 0)) + delete static_cast(this); + return ref; + } + + /** + * Release only if doing so would not bring the object to 0 references and + * delete it. Returns false if the object could not be released. + * + * NOTE: The caller is responsible for handling a failed release, as it + * means the object has no other references and needs to be be deleted + * somehow. + */ + bool releaseIfNoDelete() noexcept + { + auto val = mRef.load(std::memory_order_acquire); + while(val > 1 && !mRef.compare_exchange_strong(val, val-1, std::memory_order_acq_rel)) + { + /* val was updated with the current value on failure, so just try + * again. + */ + } + + return val >= 2; + } +}; + +} // namespace al + +#endif /* INTRUSIVE_PTR_H */ -- cgit v1.2.3 From 57e7fff6f67f302d0202b2229a960c02c3cb3c5d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Aug 2019 14:29:02 -0700 Subject: Remove an unnecessary variable --- alc/alc.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index 73723f26..462d4bd0 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -838,16 +838,14 @@ void ReleaseThreadCtx(ALCcontext *context) result ? "" : ", leak detected"); } -std::atomic ThreadCtxProc{ReleaseThreadCtx}; class ThreadCtx { ALCcontext *ctx{nullptr}; public: ~ThreadCtx() { - auto destruct = ThreadCtxProc.load(); - if(destruct && ctx) - destruct(ctx); + if(ctx) + ReleaseThreadCtx(ctx); ctx = nullptr; } -- cgit v1.2.3 From 0be823320d651130e79fbba33eff81676d59b09c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Aug 2019 15:19:37 -0700 Subject: Add and use an intrusive_ptr type --- alc/alc.cpp | 63 ++++-------------------------------------------- alc/alcontext.h | 50 +++----------------------------------- common/intrusive_ptr.h | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 105 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index 462d4bd0..6837d107 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -906,53 +906,7 @@ constexpr ALCint alcEFXMinorVersion = 0; al::FlexArray EmptyContextArray{0u}; -/* Simple RAII device reference. Takes the reference of the provided ALCdevice, - * and decrements it when leaving scope. Movable (transfer reference) but not - * copyable (no new references). - */ -class DeviceRef { - ALCdevice *mDev{nullptr}; - - void reset() noexcept - { - if(mDev) - mDev->release(); - mDev = nullptr; - } - -public: - DeviceRef() noexcept = default; - DeviceRef(DeviceRef&& rhs) noexcept : mDev{rhs.mDev} - { rhs.mDev = nullptr; } - explicit DeviceRef(ALCdevice *dev) noexcept : mDev(dev) { } - ~DeviceRef() { reset(); } - - DeviceRef& operator=(const DeviceRef&) = delete; - DeviceRef& operator=(DeviceRef&& rhs) noexcept - { - std::swap(mDev, rhs.mDev); - return *this; - } - - operator bool() const noexcept { return mDev != nullptr; } - - ALCdevice* operator->() const noexcept { return mDev; } - ALCdevice* get() const noexcept { return mDev; } - - ALCdevice* release() noexcept - { - ALCdevice *ret{mDev}; - mDev = nullptr; - return ret; - } -}; - -inline bool operator==(const DeviceRef &lhs, const ALCdevice *rhs) noexcept -{ return lhs.get() == rhs; } -inline bool operator!=(const DeviceRef &lhs, const ALCdevice *rhs) noexcept -{ return !(lhs == rhs); } -inline bool operator<(const DeviceRef &lhs, const ALCdevice *rhs) noexcept -{ return lhs.get() < rhs; } +using DeviceRef = al::intrusive_ptr; /************************************************ @@ -2345,11 +2299,8 @@ static DeviceRef VerifyDevice(ALCdevice *device) std::lock_guard _{ListLock}; auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device); if(iter != DeviceList.cend() && *iter == device) - { - (*iter)->add_ref(); - return DeviceRef{iter->get()}; - } - return DeviceRef{}; + return *iter; + return nullptr; } @@ -2590,14 +2541,10 @@ static ContextRef VerifyContext(ALCcontext *context) std::lock_guard _{ListLock}; auto iter = std::lower_bound(ContextList.cbegin(), ContextList.cend(), context); if(iter != ContextList.cend() && *iter == context) - { - (*iter)->add_ref(); - return ContextRef{iter->get()}; - } - return ContextRef{}; + return *iter; + return nullptr; } - /* GetContextRef * * Returns a new reference to the currently active context for this thread. diff --git a/alc/alcontext.h b/alc/alcontext.h index 53da10dc..ebb70a79 100644 --- a/alc/alcontext.h +++ b/alc/alcontext.h @@ -178,56 +178,12 @@ struct ALCcontext : public al::intrusive_ref { } while(0) -void UpdateContextProps(ALCcontext *context); - - -/* Simple RAII context reference. Takes the reference of the provided - * ALCcontext, and decrements it when leaving scope. Movable (transfer - * reference) but not copyable (no new references). - */ -class ContextRef { - ALCcontext *mCtx{nullptr}; - - void reset() noexcept - { - if(mCtx) - mCtx->release(); - mCtx = nullptr; - } - -public: - ContextRef() noexcept = default; - ContextRef(ContextRef&& rhs) noexcept : mCtx{rhs.mCtx} - { rhs.mCtx = nullptr; } - explicit ContextRef(ALCcontext *ctx) noexcept : mCtx(ctx) { } - ~ContextRef() { reset(); } - - ContextRef& operator=(const ContextRef&) = delete; - ContextRef& operator=(ContextRef&& rhs) noexcept - { std::swap(mCtx, rhs.mCtx); return *this; } - - operator bool() const noexcept { return mCtx != nullptr; } - - ALCcontext* operator->() const noexcept { return mCtx; } - ALCcontext* get() const noexcept { return mCtx; } - - ALCcontext* release() noexcept - { - ALCcontext *ret{mCtx}; - mCtx = nullptr; - return ret; - } -}; - -inline bool operator==(const ContextRef &lhs, const ALCcontext *rhs) noexcept -{ return lhs.get() == rhs; } -inline bool operator!=(const ContextRef &lhs, const ALCcontext *rhs) noexcept -{ return !(lhs == rhs); } -inline bool operator<(const ContextRef &lhs, const ALCcontext *rhs) noexcept -{ return lhs.get() < rhs; } +using ContextRef = al::intrusive_ptr; ContextRef GetContextRef(void); +void UpdateContextProps(ALCcontext *context); + extern bool TrapALError; diff --git a/common/intrusive_ptr.h b/common/intrusive_ptr.h index 8f34aeac..85f019fd 100644 --- a/common/intrusive_ptr.h +++ b/common/intrusive_ptr.h @@ -43,6 +43,71 @@ public: } }; + +template +class intrusive_ptr { + T *mPtr{nullptr}; + +public: + intrusive_ptr() noexcept = default; + intrusive_ptr(const intrusive_ptr &rhs) noexcept : mPtr{rhs.mPtr} + { if(mPtr) mPtr->add_ref(); } + intrusive_ptr(intrusive_ptr&& rhs) noexcept : mPtr{rhs.mPtr} + { rhs.mPtr = nullptr; } + intrusive_ptr(std::nullptr_t) noexcept { } + explicit intrusive_ptr(T *ptr) noexcept : mPtr{ptr} { } + ~intrusive_ptr() { reset(); } + + intrusive_ptr& operator=(const intrusive_ptr &rhs) noexcept + { + if(rhs.mPtr) rhs.mPtr->add_ref(); + if(mPtr) mPtr->release(); + mPtr = rhs.mPtr; + return *this; + } + intrusive_ptr& operator=(intrusive_ptr&& rhs) noexcept + { std::swap(mPtr, rhs.mPtr); return *this; } + + operator bool() const noexcept { return mPtr != nullptr; } + + T* operator->() const noexcept { return mPtr; } + T* get() const noexcept { return mPtr; } + + void reset() noexcept + { + if(mPtr) + mPtr->release(); + mPtr = nullptr; + } + + T* release() noexcept + { + T *ret{mPtr}; + mPtr = nullptr; + return ret; + } + + void swap(intrusive_ptr &rhs) noexcept { std::swap(mPtr, rhs.mPtr); } + void swap(intrusive_ptr&& rhs) noexcept { std::swap(mPtr, rhs.mPtr); } +}; + +#define AL_DECL_OP(op) \ +template \ +inline bool operator op(const intrusive_ptr &lhs, const T *rhs) noexcept \ +{ return lhs.get() op rhs; } \ +template \ +inline bool operator op(const T *lhs, const intrusive_ptr &rhs) noexcept \ +{ return lhs op rhs.get(); } + +AL_DECL_OP(==) +AL_DECL_OP(!=) +AL_DECL_OP(<=) +AL_DECL_OP(>=) +AL_DECL_OP(<) +AL_DECL_OP(>) + +#undef AL_DECL_OP + } // namespace al #endif /* INTRUSIVE_PTR_H */ -- cgit v1.2.3 From 4917024c9485d5ed3362ddcb1a0d0f8ee45dfedc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Aug 2019 15:54:17 -0700 Subject: Reduce the AsyncEvent struct size The "user" message length is significantly reduced to fit the struct in 256 bytes, rather than 1KB. --- al/event.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/al/event.h b/al/event.h index e98be560..ae1b421b 100644 --- a/al/event.h +++ b/al/event.h @@ -39,7 +39,7 @@ struct AsyncEvent { ALenum type; ALuint id; ALuint param; - ALchar msg[1008]; + ALchar msg[232]; } user; EffectState *mEffectState; } u{}; -- cgit v1.2.3 From 33bcced82a1e97811d4212195b6e6ca9cf2242b1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Aug 2019 19:44:09 -0700 Subject: Use a smart pointer for holding the context's device --- al/auxeffectslot.cpp | 10 +++++----- al/buffer.cpp | 40 ++++++++++++++++++++-------------------- al/effect.cpp | 22 +++++++++++----------- al/event.cpp | 3 +-- al/filter.cpp | 22 +++++++++++----------- al/source.cpp | 32 ++++++++++++++++---------------- alc/alc.cpp | 13 +++++-------- alc/alcontext.h | 4 ++-- alc/alu.cpp | 6 +++--- alc/effects/autowah.cpp | 2 +- alc/effects/chorus.cpp | 2 +- alc/effects/distortion.cpp | 2 +- alc/effects/echo.cpp | 2 +- alc/effects/equalizer.cpp | 2 +- alc/effects/fshifter.cpp | 2 +- alc/effects/modulator.cpp | 2 +- alc/effects/reverb.cpp | 2 +- alc/effects/vmorpher.cpp | 2 +- alc/mixvoice.cpp | 2 +- 19 files changed, 84 insertions(+), 88 deletions(-) diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index b4e93858..912765fc 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -114,7 +114,7 @@ void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *cont } curarray = context->mActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; while((device->MixCount.load(std::memory_order_acquire)&1)) std::this_thread::yield(); delete curarray; @@ -150,7 +150,7 @@ void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *c } curarray = context->mActiveAuxSlots.exchange(newarray, std::memory_order_acq_rel); - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; while((device->MixCount.load(std::memory_order_acquire)&1)) std::this_thread::yield(); delete curarray; @@ -159,7 +159,7 @@ void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *c ALeffectslot *AllocEffectSlot(ALCcontext *context) { - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{context->mEffectSlotLock}; if(context->mNumEffectSlots >= device->AuxiliaryEffectSlotMax) { @@ -376,7 +376,7 @@ START_API_FUNC switch(param) { case AL_EFFECTSLOT_EFFECT: - device = context->mDevice; + device = context->mDevice.get(); { std::lock_guard ___{device->EffectLock}; ALeffect *effect{value ? LookupEffect(device, value) : nullptr}; @@ -644,7 +644,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect if(!State) return AL_OUT_OF_MEMORY; FPUCtl mixer_mode{}; - ALCdevice *Device{Context->mDevice}; + ALCdevice *Device{Context->mDevice.get()}; std::unique_lock statelock{Device->StateLock}; State->mOutTarget = Device->Dry.Buffer; if(State->deviceUpdate(Device) == AL_FALSE) diff --git a/al/buffer.cpp b/al/buffer.cpp index 173c76bd..a068399c 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -246,7 +246,7 @@ constexpr ALbitfieldSOFT INVALID_MAP_FLAGS{~unsigned(AL_MAP_READ_BIT_SOFT | AL_M ALbuffer *AllocBuffer(ALCcontext *context) { - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; auto sublist = std::find_if(device->BufferList.begin(), device->BufferList.end(), [](const BufferSubList &entry) noexcept -> bool @@ -656,7 +656,7 @@ START_API_FUNC if(UNLIKELY(n == 0)) return; - ALCdevice *device = context->mDevice; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; /* First try to find any buffers that are invalid or in-use. */ @@ -699,7 +699,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(LIKELY(context)) { - ALCdevice *device = context->mDevice; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; if(!buffer || LookupBuffer(device, buffer)) return AL_TRUE; @@ -720,7 +720,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->mDevice; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); @@ -754,7 +754,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return nullptr; - ALCdevice *device = context->mDevice; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); @@ -806,7 +806,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->mDevice; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); @@ -829,7 +829,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->mDevice; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); @@ -861,7 +861,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->mDevice; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); @@ -989,7 +989,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->mDevice; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) @@ -1009,7 +1009,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->mDevice; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) @@ -1028,7 +1028,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->mDevice; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) @@ -1050,7 +1050,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->mDevice; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); @@ -1085,7 +1085,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->mDevice; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) @@ -1115,7 +1115,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->mDevice; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); @@ -1153,7 +1153,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->mDevice; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); @@ -1175,7 +1175,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->mDevice; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) @@ -1203,7 +1203,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->mDevice; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) @@ -1225,7 +1225,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->mDevice; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) @@ -1270,7 +1270,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->mDevice; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); @@ -1305,7 +1305,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device = context->mDevice; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); if(UNLIKELY(!albuf)) diff --git a/al/effect.cpp b/al/effect.cpp index 2d72916e..15200a88 100644 --- a/al/effect.cpp +++ b/al/effect.cpp @@ -138,7 +138,7 @@ void InitEffectParams(ALeffect *effect, ALenum type) ALeffect *AllocEffect(ALCcontext *context) { - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; auto sublist = std::find_if(device->EffectList.begin(), device->EffectList.end(), [](const EffectSubList &entry) noexcept -> bool @@ -269,7 +269,7 @@ START_API_FUNC if(UNLIKELY(n == 0)) return; - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; /* First try to find any effects that are invalid. */ @@ -307,7 +307,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(LIKELY(context)) { - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; if(!effect || LookupEffect(device, effect)) return AL_TRUE; @@ -322,7 +322,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; ALeffect *aleffect{LookupEffect(device, effect)}; @@ -372,7 +372,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; ALeffect *aleffect{LookupEffect(device, effect)}; @@ -392,7 +392,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; ALeffect *aleffect{LookupEffect(device, effect)}; @@ -412,7 +412,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; ALeffect *aleffect{LookupEffect(device, effect)}; @@ -432,7 +432,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; const ALeffect *aleffect{LookupEffect(device, effect)}; @@ -464,7 +464,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; const ALeffect *aleffect{LookupEffect(device, effect)}; @@ -484,7 +484,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; const ALeffect *aleffect{LookupEffect(device, effect)}; @@ -504,7 +504,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; const ALeffect *aleffect{LookupEffect(device, effect)}; diff --git a/al/event.cpp b/al/event.cpp index 75827b59..06a2e008 100644 --- a/al/event.cpp +++ b/al/event.cpp @@ -120,7 +120,6 @@ void StartEventThrd(ALCcontext *ctx) void StopEventThrd(ALCcontext *ctx) { - static constexpr AsyncEvent kill_evt{EventType_KillThread}; RingBuffer *ring{ctx->mAsyncEvents.get()}; auto evt_data = ring->getWriteVector().first; if(evt_data.len == 0) @@ -130,7 +129,7 @@ void StopEventThrd(ALCcontext *ctx) evt_data = ring->getWriteVector().first; } while(evt_data.len == 0); } - new (evt_data.buf) AsyncEvent{kill_evt}; + new (evt_data.buf) AsyncEvent{EventType_KillThread}; ring->writeAdvance(1); ctx->mEventSem.post(); diff --git a/al/filter.cpp b/al/filter.cpp index 5009daae..b52267f1 100644 --- a/al/filter.cpp +++ b/al/filter.cpp @@ -278,7 +278,7 @@ void InitFilterParams(ALfilter *filter, ALenum type) ALfilter *AllocFilter(ALCcontext *context) { - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; auto sublist = std::find_if(device->FilterList.begin(), device->FilterList.end(), [](const FilterSubList &entry) noexcept -> bool @@ -410,7 +410,7 @@ START_API_FUNC if(UNLIKELY(n == 0)) return; - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; /* First try to find any filters that are invalid. */ @@ -448,7 +448,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(LIKELY(context)) { - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; if(!filter || LookupFilter(device, filter)) return AL_TRUE; @@ -464,7 +464,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; @@ -502,7 +502,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; @@ -522,7 +522,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; @@ -542,7 +542,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; @@ -562,7 +562,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; @@ -594,7 +594,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; @@ -614,7 +614,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; @@ -634,7 +634,7 @@ START_API_FUNC ContextRef context{GetContextRef()}; if(UNLIKELY(!context)) return; - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; diff --git a/al/source.cpp b/al/source.cpp index 1e0940de..5ba36524 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -175,7 +175,7 @@ void UpdateSourceProps(const ALsource *source, ALvoice *voice, ALCcontext *conte */ int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, std::chrono::nanoseconds *clocktime) { - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; const ALbufferlistitem *Current; uint64_t readPos; ALuint refcount; @@ -221,7 +221,7 @@ int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, std::chrono */ ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, std::chrono::nanoseconds *clocktime) { - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; const ALbufferlistitem *Current; uint64_t readPos; ALuint refcount; @@ -281,7 +281,7 @@ ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, std::chrono:: */ ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) { - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; const ALbufferlistitem *Current; ALuint readPos; ALsizei readPosFrac; @@ -483,7 +483,7 @@ ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) ALsource *AllocSource(ALCcontext *context) { - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; std::lock_guard _{context->mSourceLock}; if(context->mNumSources >= device->SourcesMax) { @@ -545,7 +545,7 @@ void FreeSource(ALCcontext *context, ALsource *source) ALsizei lidx = id >> 6; ALsizei slidx = id & 0x3f; - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; BackendUniqueLock backlock{*device->Backend}; if(ALvoice *voice{GetSourceVoice(source, context)}) { @@ -1126,7 +1126,7 @@ ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, co if(IsPlayingOrPaused(Source)) { - ALCdevice *device{Context->mDevice}; + ALCdevice *device{Context->mDevice.get()}; BackendLockGuard _{*device->Backend}; /* Double-check that the source is still playing while we have * the lock. @@ -1230,7 +1230,7 @@ ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, co ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values) { - ALCdevice *device{Context->mDevice}; + ALCdevice *device{Context->mDevice.get()}; ALbuffer *buffer{nullptr}; ALfilter *filter{nullptr}; ALeffectslot *slot{nullptr}; @@ -1346,7 +1346,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co if(IsPlayingOrPaused(Source)) { - ALCdevice *device{Context->mDevice}; + ALCdevice *device{Context->mDevice.get()}; BackendLockGuard _{*device->Backend}; if(ALvoice *voice{GetSourceVoice(Source, Context)}) { @@ -1662,7 +1662,7 @@ ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values) { - ALCdevice *device{Context->mDevice}; + ALCdevice *device{Context->mDevice.get()}; ClockLatency clocktime; std::chrono::nanoseconds srcclock; ALint ivals[3]; @@ -1995,7 +1995,7 @@ ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64SOFT *values) { - ALCdevice *device = Context->mDevice; + ALCdevice *device = Context->mDevice.get(); ClockLatency clocktime; std::chrono::nanoseconds srcclock; ALdouble dvals[6]; @@ -2780,7 +2780,7 @@ START_API_FUNC SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; BackendLockGuard __{*device->Backend}; /* If the device is disconnected, go right to stopped. */ if(UNLIKELY(!device->Connected.load(std::memory_order_acquire))) @@ -3041,7 +3041,7 @@ START_API_FUNC SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; BackendLockGuard __{*device->Backend}; auto pause_source = [&context](ALsource *source) -> void { @@ -3096,7 +3096,7 @@ START_API_FUNC SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; BackendLockGuard __{*device->Backend}; auto stop_source = [&context](ALsource *source) -> void { @@ -3158,7 +3158,7 @@ START_API_FUNC SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); } - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; BackendLockGuard __{*device->Backend}; auto rewind_source = [&context](ALsource *source) -> void { @@ -3207,7 +3207,7 @@ START_API_FUNC SETERR_RETURN(context, AL_INVALID_OPERATION,, "Queueing onto static source %u", src); /* Check for a valid Buffer, for its frequency and format */ - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; ALbuffer *BufferFmt{nullptr}; ALbufferlistitem *BufferList{source->queue}; while(BufferList) @@ -3319,7 +3319,7 @@ START_API_FUNC SETERR_RETURN(context, AL_INVALID_OPERATION,, "Queueing onto static source %u", src); /* Check for a valid Buffer, for its frequency and format */ - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; ALbuffer *BufferFmt{nullptr}; ALbufferlistitem *BufferList{source->queue}; while(BufferList) diff --git a/alc/alc.cpp b/alc/alc.cpp index 6837d107..20776fba 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -2304,7 +2304,7 @@ static DeviceRef VerifyDevice(ALCdevice *device) } -ALCcontext::ALCcontext(ALCdevice *device) : mDevice{device} +ALCcontext::ALCcontext(al::intrusive_ptr device) : mDevice{std::move(device)} { mPropsClean.test_and_set(std::memory_order_relaxed); } @@ -2464,8 +2464,6 @@ ALCcontext::~ALCcontext() TRACE("Destructed %zu orphaned event%s\n", count, (count==1)?"":"s"); mAsyncEvents->readAdvance(count); } - - mDevice->release(); } /* ReleaseContext @@ -3346,9 +3344,6 @@ START_API_FUNC dev->LastError.store(ALC_NO_ERROR); - ContextRef context{new ALCcontext{dev.get()}}; - dev->add_ref(); - ALCenum err{UpdateDeviceParams(dev.get(), attrList)}; if(err != ALC_NO_ERROR) { @@ -3357,6 +3352,8 @@ START_API_FUNC aluHandleDisconnect(dev.get(), "Device update failure"); return nullptr; } + + ContextRef context{new ALCcontext{dev}}; context->allocVoices(256); if(DefaultEffect.type != AL_EFFECT_NULL && dev->Type == Playback) @@ -3461,7 +3458,7 @@ START_API_FUNC ContextRef ctx{std::move(*iter)}; ContextList.erase(iter); - ALCdevice *Device{ctx->mDevice}; + ALCdevice *Device{ctx->mDevice.get()}; std::lock_guard _{Device->StateLock}; if(!ReleaseContext(ctx.get(), Device) && Device->Flags.get()) @@ -3572,7 +3569,7 @@ START_API_FUNC alcSetError(nullptr, ALC_INVALID_CONTEXT); return nullptr; } - return ctx->mDevice; + return ctx->mDevice.get(); } END_API_FUNC diff --git a/alc/alcontext.h b/alc/alcontext.h index ebb70a79..c4f23dfb 100644 --- a/alc/alcontext.h +++ b/alc/alcontext.h @@ -144,13 +144,13 @@ struct ALCcontext : public al::intrusive_ref { /* Default effect slot */ std::unique_ptr mDefaultSlot; - ALCdevice *const mDevice; + const al::intrusive_ptr mDevice; const ALCchar *mExtensionList{nullptr}; ALlistener mListener{}; - ALCcontext(ALCdevice *device); + ALCcontext(al::intrusive_ptr device); ALCcontext(const ALCcontext&) = delete; ALCcontext& operator=(const ALCcontext&) = delete; ~ALCcontext(); diff --git a/alc/alu.cpp b/alc/alu.cpp index 8d627b97..7d333fcb 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -409,7 +409,7 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) output = EffectTarget{&target->Wet, nullptr}; else { - ALCdevice *device{context->mDevice}; + ALCdevice *device{context->mDevice.get()}; output = EffectTarget{&device->Dry, &device->RealOut}; } state->update(context, slot, &slot->Params.mEffectProps, output); @@ -950,7 +950,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const ALCcontext *ALContext) { - const ALCdevice *Device{ALContext->mDevice}; + const ALCdevice *Device{ALContext->mDevice.get()}; ALeffectslot *SendSlots[MAX_SENDS]; voice->mDirect.Buffer = Device->Dry.Buffer; @@ -1004,7 +1004,7 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const ALCcontext *ALContext) { - const ALCdevice *Device{ALContext->mDevice}; + const ALCdevice *Device{ALContext->mDevice.get()}; const ALsizei NumSends{Device->NumAuxSends}; const ALlistener &Listener = ALContext->mListener; diff --git a/alc/effects/autowah.cpp b/alc/effects/autowah.cpp index 1aac749e..f16c5ba5 100644 --- a/alc/effects/autowah.cpp +++ b/alc/effects/autowah.cpp @@ -106,7 +106,7 @@ ALboolean ALautowahState::deviceUpdate(const ALCdevice*) void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { - const ALCdevice *device{context->mDevice}; + const ALCdevice *device{context->mDevice.get()}; const ALfloat ReleaseTime{clampf(props->Autowah.ReleaseTime, 0.001f, 1.0f)}; diff --git a/alc/effects/chorus.cpp b/alc/effects/chorus.cpp index 31f10c81..5966d3bd 100644 --- a/alc/effects/chorus.cpp +++ b/alc/effects/chorus.cpp @@ -157,7 +157,7 @@ void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, co /* The LFO depth is scaled to be relative to the sample delay. Clamp the * delay and depth to allow enough padding for resampling. */ - const ALCdevice *device{Context->mDevice}; + const ALCdevice *device{Context->mDevice.get()}; const auto frequency = static_cast(device->Frequency); mDelay = maxi(float2int(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f), mindelay); mDepth = minf(props->Chorus.Depth * mDelay, static_cast(mDelay - mindelay)); diff --git a/alc/effects/distortion.cpp b/alc/effects/distortion.cpp index 3fd08229..ec1550f5 100644 --- a/alc/effects/distortion.cpp +++ b/alc/effects/distortion.cpp @@ -63,7 +63,7 @@ ALboolean DistortionState::deviceUpdate(const ALCdevice*) void DistortionState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { - const ALCdevice *device{context->mDevice}; + const ALCdevice *device{context->mDevice.get()}; /* Store waveshaper edge settings. */ const ALfloat edge{ diff --git a/alc/effects/echo.cpp b/alc/effects/echo.cpp index d14db80c..d41c4f67 100644 --- a/alc/effects/echo.cpp +++ b/alc/effects/echo.cpp @@ -93,7 +93,7 @@ ALboolean EchoState::deviceUpdate(const ALCdevice *Device) void EchoState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { - const ALCdevice *device = context->mDevice; + const ALCdevice *device{context->mDevice.get()}; const auto frequency = static_cast(device->Frequency); mTap[0].delay = maxi(float2int(props->Echo.Delay*frequency + 0.5f), 1); diff --git a/alc/effects/equalizer.cpp b/alc/effects/equalizer.cpp index 4b900bcf..a8e81b37 100644 --- a/alc/effects/equalizer.cpp +++ b/alc/effects/equalizer.cpp @@ -111,7 +111,7 @@ ALboolean EqualizerState::deviceUpdate(const ALCdevice*) void EqualizerState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { - const ALCdevice *device = context->mDevice; + const ALCdevice *device{context->mDevice.get()}; auto frequency = static_cast(device->Frequency); ALfloat gain, f0norm; diff --git a/alc/effects/fshifter.cpp b/alc/effects/fshifter.cpp index bca29bba..a6c2c747 100644 --- a/alc/effects/fshifter.cpp +++ b/alc/effects/fshifter.cpp @@ -108,7 +108,7 @@ ALboolean FshifterState::deviceUpdate(const ALCdevice*) void FshifterState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { - const ALCdevice *device{context->mDevice}; + const ALCdevice *device{context->mDevice.get()}; ALfloat step{props->Fshifter.Frequency / static_cast(device->Frequency)}; mPhaseStep = fastf2i(minf(step, 0.5f) * FRACTIONONE); diff --git a/alc/effects/modulator.cpp b/alc/effects/modulator.cpp index d7118285..8a6378cd 100644 --- a/alc/effects/modulator.cpp +++ b/alc/effects/modulator.cpp @@ -109,7 +109,7 @@ ALboolean ModulatorState::deviceUpdate(const ALCdevice*) void ModulatorState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { - const ALCdevice *device{context->mDevice}; + const ALCdevice *device{context->mDevice.get()}; const float step{props->Modulator.Frequency / static_cast(device->Frequency)}; mStep = fastf2i(clampf(step*WAVEFORM_FRACONE, 0.0f, ALfloat{WAVEFORM_FRACONE-1})); diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 6e6844e0..51a57360 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -905,7 +905,7 @@ void ReverbState::update3DPanning(const ALfloat *ReflectionsPan, const ALfloat * void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, const EffectProps *props, const EffectTarget target) { - const ALCdevice *Device{Context->mDevice}; + const ALCdevice *Device{Context->mDevice.get()}; const ALlistener &Listener = Context->mListener; const auto frequency = static_cast(Device->Frequency); diff --git a/alc/effects/vmorpher.cpp b/alc/effects/vmorpher.cpp index 95016105..ad0f026b 100644 --- a/alc/effects/vmorpher.cpp +++ b/alc/effects/vmorpher.cpp @@ -209,7 +209,7 @@ ALboolean VmorpherState::deviceUpdate(const ALCdevice* /*device*/) void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { - const ALCdevice *device{context->mDevice}; + const ALCdevice *device{context->mDevice.get()}; const ALfloat frequency{static_cast(device->Frequency)}; const ALfloat step{props->Vmorpher.Rate / static_cast(device->Frequency)}; mStep = fastf2i(clampf(step*WAVEFORM_FRACONE, 0.0f, ALfloat{WAVEFORM_FRACONE-1})); diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index e2b2bf51..b1d7500a 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -540,7 +540,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc ASSUME(SampleSize > 0); ASSUME(increment > 0); - ALCdevice *Device{Context->mDevice}; + ALCdevice *Device{Context->mDevice.get()}; const ALsizei NumSends{Device->NumAuxSends}; const ALsizei IrSize{Device->mHrtf ? Device->mHrtf->irSize : 0}; -- cgit v1.2.3 From 61bb079036aa90a819f58d1c26b4f3c14588b218 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Aug 2019 20:15:47 -0700 Subject: Add operator* to intrusive_ptr --- common/intrusive_ptr.h | 1 + 1 file changed, 1 insertion(+) diff --git a/common/intrusive_ptr.h b/common/intrusive_ptr.h index 85f019fd..831b8302 100644 --- a/common/intrusive_ptr.h +++ b/common/intrusive_ptr.h @@ -70,6 +70,7 @@ public: operator bool() const noexcept { return mPtr != nullptr; } + T& operator*() const noexcept { return *mPtr; } T* operator->() const noexcept { return mPtr; } T* get() const noexcept { return mPtr; } -- cgit v1.2.3 From ce7c86b21731b026f12f53dda42b9553ebd94fee Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Aug 2019 11:07:48 -0700 Subject: Avoid reloading the voices array when processing --- alc/alu.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/alc/alu.cpp b/alc/alu.cpp index 7d333fcb..253dbe48 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -1343,20 +1343,20 @@ void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) } -void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray *slots) +void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray &slots, + const al::span voices) { IncrementRef(ctx->mUpdateCount); if(LIKELY(!ctx->mHoldUpdates.load(std::memory_order_acquire))) { bool cforce{CalcContextParams(ctx)}; bool force{CalcListenerParams(ctx) || cforce}; - force = std::accumulate(slots->begin(), slots->end(), force, + force = std::accumulate(slots.begin(), slots.end(), force, [ctx,cforce](bool force, ALeffectslot *slot) -> bool { return CalcEffectSlotParams(slot, ctx, cforce) | force; } ); - std::for_each(ctx->mVoices->begin(), - ctx->mVoices->begin() + ctx->mVoiceCount.load(std::memory_order_acquire), + std::for_each(voices.begin(), voices.end(), [ctx,force](ALvoice &voice) -> void { ALuint sid{voice.mSourceID.load(std::memory_order_acquire)}; @@ -1371,13 +1371,15 @@ void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) { ASSUME(SamplesToDo > 0); - const ALeffectslotArray *auxslots{ctx->mActiveAuxSlots.load(std::memory_order_acquire)}; + const ALeffectslotArray &auxslots = *ctx->mActiveAuxSlots.load(std::memory_order_acquire); + const al::span voices{ctx->mVoices->data(), + ctx->mVoiceCount.load(std::memory_order_acquire)}; /* Process pending propery updates for objects on the context. */ - ProcessParamUpdates(ctx, auxslots); + ProcessParamUpdates(ctx, auxslots, voices); /* Clear auxiliary effect slot mixing buffers. */ - std::for_each(auxslots->begin(), auxslots->end(), + std::for_each(auxslots.begin(), auxslots.end(), [SamplesToDo](ALeffectslot *slot) -> void { for(auto &buffer : slot->MixBuffer) @@ -1386,8 +1388,7 @@ void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) ); /* Process voices that have a playing source. */ - std::for_each(ctx->mVoices->begin(), - ctx->mVoices->begin() + ctx->mVoiceCount.load(std::memory_order_acquire), + std::for_each(voices.begin(), voices.end(), [SamplesToDo,ctx](ALvoice &voice) -> void { const ALvoice::State vstate{voice.mPlayState.load(std::memory_order_acquire)}; @@ -1400,9 +1401,9 @@ void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) ); /* Process effects. */ - if(auxslots->size() < 1) return; - auto slots = auxslots->data(); - auto slots_end = slots + auxslots->size(); + if(auxslots.empty()) return; + auto slots = auxslots.data(); + auto slots_end = slots + auxslots.size(); /* First sort the slots into scratch storage, so that effects come before * their effect target (or their targets' target). -- cgit v1.2.3 From 9f223898f2f460d707d8506e28989d2952a767f9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Aug 2019 12:38:20 -0700 Subject: Use an unsigned voice index --- al/source.cpp | 17 ++++------------- al/source.h | 15 ++++++++------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index 5ba36524..a021cd1a 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -75,15 +75,15 @@ using namespace std::placeholders; inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) { - ALint idx{source->VoiceIdx}; - if(idx >= 0 && static_cast(idx) < context->mVoiceCount.load(std::memory_order_relaxed)) + ALuint idx{source->VoiceIdx}; + if(idx < context->mVoiceCount.load(std::memory_order_relaxed)) { ALuint sid{source->id}; ALvoice &voice = (*context->mVoices)[idx]; if(voice.mSourceID.load(std::memory_order_acquire) == sid) return &voice; } - source->VoiceIdx = -1; + source->VoiceIdx = INVALID_VOICE_IDX; return nullptr; } @@ -2894,7 +2894,7 @@ START_API_FUNC } ); assert(voice != voices_end); - auto vidx = static_cast(std::distance(context->mVoices->begin(), voice)); + auto vidx = static_cast(std::distance(context->mVoices->begin(), voice)); voice->mPlayState.store(ALvoice::Stopped, std::memory_order_release); source->PropsClean.test_and_set(std::memory_order_acquire); @@ -3554,16 +3554,7 @@ ALsource::ALsource(ALsizei num_sends) send.LFReference = HIGHPASSFREQREF; } - Offset = 0.0; - OffsetType = AL_NONE; - SourceType = AL_UNDETERMINED; - state = AL_INITIAL; - - queue = nullptr; - PropsClean.test_and_set(std::memory_order_relaxed); - - VoiceIdx = -1; } ALsource::~ALsource() diff --git a/al/source.h b/al/source.h index 1aafafab..a5d10cf9 100644 --- a/al/source.h +++ b/al/source.h @@ -20,6 +20,7 @@ struct ALeffectslot; #define DEFAULT_SENDS 2 +#define INVALID_VOICE_IDX static_cast(-1) struct ALbufferlistitem { using element_type = ALbuffer*; @@ -139,27 +140,27 @@ struct ALsource { * Last user-specified offset, and the offset type (bytes, samples, or * seconds). */ - ALdouble Offset; - ALenum OffsetType; + ALdouble Offset{0.0}; + ALenum OffsetType{AL_NONE}; /** Source type (static, streaming, or undetermined) */ - ALint SourceType; + ALint SourceType{AL_UNDETERMINED}; /** Source state (initial, playing, paused, or stopped) */ - ALenum state; + ALenum state{AL_INITIAL}; /** Source Buffer Queue head. */ - ALbufferlistitem *queue; + ALbufferlistitem *queue{nullptr}; std::atomic_flag PropsClean; /* Index into the context's Voices array. Lazily updated, only checked and * reset when looking up the voice. */ - ALint VoiceIdx; + ALuint VoiceIdx{INVALID_VOICE_IDX}; /** Self ID */ - ALuint id; + ALuint id{0}; ALsource(ALsizei num_sends); -- cgit v1.2.3 From a7a9c00275ee6ebe0ee543b9698f16ace8f5d35c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Aug 2019 18:30:22 -0700 Subject: Turn a couple more functions into methods --- alc/alc.cpp | 207 ++++++++++++++++++++++++-------------------------------- alc/alcontext.h | 12 +++- 2 files changed, 99 insertions(+), 120 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index 20776fba..3b2ed7a4 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -2309,58 +2309,6 @@ ALCcontext::ALCcontext(al::intrusive_ptr device) : mDevice{std::move( mPropsClean.test_and_set(std::memory_order_relaxed); } -/* InitContext - * - * Initializes context fields - */ -static ALvoid InitContext(ALCcontext *Context) -{ - ALlistener &listener = Context->mListener; - ALeffectslotArray *auxslots; - - //Validate Context - if(!Context->mDefaultSlot) - auxslots = ALeffectslot::CreatePtrArray(0); - else - { - auxslots = ALeffectslot::CreatePtrArray(1); - (*auxslots)[0] = Context->mDefaultSlot.get(); - } - Context->mActiveAuxSlots.store(auxslots, std::memory_order_relaxed); - - //Set globals - Context->mDistanceModel = DistanceModel::Default; - Context->mSourceDistanceModel = AL_FALSE; - Context->mDopplerFactor = 1.0f; - Context->mDopplerVelocity = 1.0f; - Context->mSpeedOfSound = SPEEDOFSOUNDMETRESPERSEC; - Context->mMetersPerUnit = AL_DEFAULT_METERS_PER_UNIT; - - Context->mExtensionList = alExtList; - - - listener.Params.Matrix = alu::Matrix::Identity(); - listener.Params.Velocity = alu::Vector{}; - listener.Params.Gain = listener.Gain; - listener.Params.MetersPerUnit = Context->mMetersPerUnit; - listener.Params.DopplerFactor = Context->mDopplerFactor; - listener.Params.SpeedOfSound = Context->mSpeedOfSound * Context->mDopplerVelocity; - listener.Params.ReverbSpeedOfSound = listener.Params.SpeedOfSound * - listener.Params.MetersPerUnit; - listener.Params.SourceDistanceModel = Context->mSourceDistanceModel; - listener.Params.mDistanceModel = Context->mDistanceModel; - - - Context->mAsyncEvents = CreateRingBuffer(511, sizeof(AsyncEvent), false); - StartEventThrd(Context); -} - - -/* ALCcontext::~ALCcontext() - * - * Cleans up the context, and destroys any remaining objects the app failed to - * delete. Called once there's no more references on the context. - */ ALCcontext::~ALCcontext() { TRACE("Freeing context %p\n", this); @@ -2466,65 +2414,103 @@ ALCcontext::~ALCcontext() } } -/* ReleaseContext - * - * Removes the context reference from the given device and removes it from - * being current on the running thread or globally. Returns true if other - * contexts still exist on the device. - */ -static bool ReleaseContext(ALCcontext *context, ALCdevice *device) +void ALCcontext::init() +{ + if(DefaultEffect.type != AL_EFFECT_NULL && mDevice->Type == Playback) + { + void *ptr{al_calloc(16, sizeof(ALeffectslot))}; + mDefaultSlot = std::unique_ptr{new (ptr) ALeffectslot{}}; + if(InitEffectSlot(mDefaultSlot.get()) == AL_NO_ERROR) + aluInitEffectPanning(mDefaultSlot.get(), mDevice.get()); + else + { + mDefaultSlot = nullptr; + ERR("Failed to initialize the default effect slot\n"); + } + } + + ALeffectslotArray *auxslots; + if(!mDefaultSlot) + auxslots = ALeffectslot::CreatePtrArray(0); + else + { + auxslots = ALeffectslot::CreatePtrArray(1); + (*auxslots)[0] = mDefaultSlot.get(); + } + mActiveAuxSlots.store(auxslots, std::memory_order_relaxed); + + mExtensionList = alExtList; + + + mListener.Params.Matrix = alu::Matrix::Identity(); + mListener.Params.Velocity = alu::Vector{}; + mListener.Params.Gain = mListener.Gain; + mListener.Params.MetersPerUnit = mMetersPerUnit; + mListener.Params.DopplerFactor = mDopplerFactor; + mListener.Params.SpeedOfSound = mSpeedOfSound * mDopplerVelocity; + mListener.Params.ReverbSpeedOfSound = mListener.Params.SpeedOfSound * + mListener.Params.MetersPerUnit; + mListener.Params.SourceDistanceModel = mSourceDistanceModel; + mListener.Params.mDistanceModel = mDistanceModel; + + + mAsyncEvents = CreateRingBuffer(511, sizeof(AsyncEvent), false); + StartEventThrd(this); + + + allocVoices(256); +} + +bool ALCcontext::deinit() { - if(LocalContext.get() == context) + if(LocalContext.get() == this) { - WARN("%p released while current on thread\n", context); + WARN("%p released while current on thread\n", this); LocalContext.set(nullptr); - context->release(); + release(); } - ALCcontext *origctx{context}; + ALCcontext *origctx{this}; if(GlobalContext.compare_exchange_strong(origctx, nullptr)) - context->release(); + release(); bool ret{}; + /* First make sure this context exists in the device's list. */ + auto *oldarray = mDevice->mContexts.load(std::memory_order_acquire); + if(auto toremove = std::count(oldarray->begin(), oldarray->end(), this)) { using ContextArray = al::FlexArray; - - /* First make sure this context exists in the device's list. */ - auto *oldarray = device->mContexts.load(std::memory_order_acquire); - if(auto toremove = std::count(oldarray->begin(), oldarray->end(), context)) + auto alloc_ctx_array = [](const size_t count) -> ContextArray* { - auto alloc_ctx_array = [](const size_t count) -> ContextArray* - { - if(count == 0) return &EmptyContextArray; - void *ptr{al_calloc(alignof(ContextArray), ContextArray::Sizeof(count))}; - return new (ptr) ContextArray{count}; - }; - auto *newarray = alloc_ctx_array(oldarray->size() - toremove); - - /* Copy the current/old context handles to the new array, excluding - * the given context. - */ - std::copy_if(oldarray->begin(), oldarray->end(), newarray->begin(), - std::bind(std::not_equal_to{}, _1, context)); - - /* Store the new context array in the device. Wait for any current - * mix to finish before deleting the old array. - */ - device->mContexts.store(newarray); - if(oldarray != &EmptyContextArray) - { - while((device->MixCount.load(std::memory_order_acquire)&1)) - std::this_thread::yield(); - delete oldarray; - } - - ret = !newarray->empty(); + if(count == 0) return &EmptyContextArray; + void *ptr{al_calloc(alignof(ContextArray), ContextArray::Sizeof(count))}; + return new (ptr) ContextArray{count}; + }; + auto *newarray = alloc_ctx_array(oldarray->size() - toremove); + + /* Copy the current/old context handles to the new array, excluding + * the given context. + */ + std::copy_if(oldarray->begin(), oldarray->end(), newarray->begin(), + std::bind(std::not_equal_to{}, _1, this)); + + /* Store the new context array in the device. Wait for any current + * mix to finish before deleting the old array. + */ + mDevice->mContexts.store(newarray); + if(oldarray != &EmptyContextArray) + { + while((mDevice->MixCount.load(std::memory_order_acquire)&1)) + std::this_thread::yield(); + delete oldarray; } - else - ret = !oldarray->empty(); + + ret = !newarray->empty(); } + else + ret = !oldarray->empty(); - StopEventThrd(context); + StopEventThrd(this); return ret; } @@ -3354,22 +3340,7 @@ START_API_FUNC } ContextRef context{new ALCcontext{dev}}; - context->allocVoices(256); - - if(DefaultEffect.type != AL_EFFECT_NULL && dev->Type == Playback) - { - void *ptr{al_calloc(16, sizeof(ALeffectslot))}; - context->mDefaultSlot = std::unique_ptr{new (ptr) ALeffectslot{}}; - if(InitEffectSlot(context->mDefaultSlot.get()) == AL_NO_ERROR) - aluInitEffectPanning(context->mDefaultSlot.get(), dev.get()); - else - { - context->mDefaultSlot = nullptr; - ERR("Failed to initialize the default effect slot\n"); - } - } - - InitContext(context.get()); + context->init(); if(auto volopt = ConfigValueFloat(dev->DeviceName.c_str(), nullptr, "volume-adjust")) { @@ -3396,7 +3367,7 @@ START_API_FUNC auto *oldarray = device->mContexts.load(); const size_t newcount{oldarray->size()+1}; void *ptr{al_calloc(alignof(ContextArray), ContextArray::Sizeof(newcount))}; - auto *newarray = new (ptr) ContextArray{newcount}; + std::unique_ptr newarray{new (ptr) ContextArray{newcount}}; /* Copy the current/old context handles to the new array, appending the * new context. @@ -3407,7 +3378,7 @@ START_API_FUNC /* Store the new context array in the device. Wait for any current mix * to finish before deleting the old array. */ - dev->mContexts.store(newarray); + dev->mContexts.store(newarray.release()); if(oldarray != &EmptyContextArray) { while((dev->MixCount.load(std::memory_order_acquire)&1)) @@ -3461,7 +3432,7 @@ START_API_FUNC ALCdevice *Device{ctx->mDevice.get()}; std::lock_guard _{Device->StateLock}; - if(!ReleaseContext(ctx.get(), Device) && Device->Flags.get()) + if(!ctx->deinit() && Device->Flags.get()) { Device->Backend->stop(); Device->Flags.unset(); @@ -3818,8 +3789,8 @@ START_API_FUNC for(ContextRef &context : orphanctxs) { - WARN("Releasing context %p\n", context.get()); - ReleaseContext(context.get(), dev.get()); + WARN("Releasing orphaned context %p\n", context.get()); + context->deinit(); } orphanctxs.clear(); diff --git a/alc/alcontext.h b/alc/alcontext.h index c4f23dfb..70215e9c 100644 --- a/alc/alcontext.h +++ b/alc/alcontext.h @@ -101,8 +101,8 @@ struct ALCcontext : public al::intrusive_ref { ALfloat mDopplerFactor{1.0f}; ALfloat mDopplerVelocity{1.0f}; - ALfloat mSpeedOfSound{}; - ALfloat mMetersPerUnit{1.0f}; + ALfloat mSpeedOfSound{SPEEDOFSOUNDMETRESPERSEC}; + ALfloat mMetersPerUnit{AL_DEFAULT_METERS_PER_UNIT}; std::atomic_flag mPropsClean; std::atomic mDeferUpdates{false}; @@ -155,6 +155,14 @@ struct ALCcontext : public al::intrusive_ref { ALCcontext& operator=(const ALCcontext&) = delete; ~ALCcontext(); + void init(); + /** + * Removes the context from its device and removes it from being current on + * the running thread or globally. Returns true if other contexts still + * exist on the device. + */ + bool deinit(); + void allocVoices(size_t num_voices); /** -- cgit v1.2.3 From 341743680415c4b3339d36fc4e67ab8a605a06ea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Aug 2019 12:14:50 -0700 Subject: Avoid manually incrementing a reference count --- alc/alc.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index 3b2ed7a4..c9520c6d 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -3391,8 +3391,7 @@ START_API_FUNC { std::lock_guard _{ListLock}; auto iter = std::lower_bound(ContextList.cbegin(), ContextList.cend(), context.get()); - context->add_ref(); - ContextList.insert(iter, ContextRef{context.get()}); + ContextList.emplace(iter, context); } if(context->mDefaultSlot) @@ -3739,8 +3738,7 @@ START_API_FUNC { std::lock_guard _{ListLock}; auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get()); - device->add_ref(); - DeviceList.insert(iter, DeviceRef{device.get()}); + DeviceList.emplace(iter, device); } TRACE("Created device %p, \"%s\"\n", device.get(), device->DeviceName.c_str()); @@ -3865,8 +3863,7 @@ START_API_FUNC { std::lock_guard _{ListLock}; auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get()); - device->add_ref(); - DeviceList.insert(iter, DeviceRef{device.get()}); + DeviceList.emplace(iter, device); } TRACE("Created device %p, \"%s\"\n", device.get(), device->DeviceName.c_str()); @@ -4034,8 +4031,7 @@ START_API_FUNC { std::lock_guard _{ListLock}; auto iter = std::lower_bound(DeviceList.cbegin(), DeviceList.cend(), device.get()); - device->add_ref(); - DeviceList.insert(iter, DeviceRef{device.get()}); + DeviceList.emplace(iter, device); } TRACE("Created device %p\n", device.get()); -- cgit v1.2.3 From 13222d719d7a38b46cf0b02771acffea5d569d46 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Aug 2019 13:05:42 -0700 Subject: Make a couple counts size_t --- alc/bformatdec.cpp | 2 ++ alc/filters/splitter.cpp | 6 +++--- alc/filters/splitter.h | 6 +++--- alc/hrtf.cpp | 8 ++++---- alc/mixvoice.cpp | 1 + 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/alc/bformatdec.cpp b/alc/bformatdec.cpp index 889bbf3a..6b20dd84 100644 --- a/alc/bformatdec.cpp +++ b/alc/bformatdec.cpp @@ -146,6 +146,8 @@ BFormatDec::BFormatDec(const ALuint inchans, const ALsizei chancount, void BFormatDec::process(const al::span OutBuffer, const FloatBufferLine *InSamples, const ALsizei SamplesToDo) { + ASSUME(SamplesToDo > 0); + if(mDualBand) { for(ALuint i{0};i < mNumChannels;i++) diff --git a/alc/filters/splitter.cpp b/alc/filters/splitter.cpp index 7463d795..66806ea9 100644 --- a/alc/filters/splitter.cpp +++ b/alc/filters/splitter.cpp @@ -27,7 +27,7 @@ void BandSplitterR::init(Real f0norm) } template -void BandSplitterR::process(Real *hpout, Real *lpout, const Real *input, const int count) +void BandSplitterR::process(Real *hpout, Real *lpout, const Real *input, const size_t count) { ASSUME(count > 0); @@ -63,7 +63,7 @@ void BandSplitterR::process(Real *hpout, Real *lpout, const Real *input, c } template -void BandSplitterR::applyHfScale(Real *samples, const Real hfscale, const int count) +void BandSplitterR::applyHfScale(Real *samples, const Real hfscale, const size_t count) { ASSUME(count > 0); @@ -97,7 +97,7 @@ void BandSplitterR::applyHfScale(Real *samples, const Real hfscale, const } template -void BandSplitterR::applyAllpass(Real *samples, const int count) const +void BandSplitterR::applyAllpass(Real *samples, const size_t count) const { ASSUME(count > 0); diff --git a/alc/filters/splitter.h b/alc/filters/splitter.h index d7b0240d..52bda713 100644 --- a/alc/filters/splitter.h +++ b/alc/filters/splitter.h @@ -22,15 +22,15 @@ public: void init(Real f0norm); void clear() noexcept { lp_z1 = lp_z2 = ap_z1 = 0.0f; } - void process(Real *hpout, Real *lpout, const Real *input, const int count); + void process(Real *hpout, Real *lpout, const Real *input, const size_t count); - void applyHfScale(Real *samples, const Real hfscale, const int count); + void applyHfScale(Real *samples, const Real hfscale, const size_t count); /* The all-pass portion of the band splitter. Applies the same phase shift * without splitting the signal. Note that each use of this method is * indepedent, it does not track history between calls. */ - void applyAllpass(Real *samples, const int count) const; + void applyAllpass(Real *samples, const size_t count) const; }; using BandSplitter = BandSplitterR; diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index a8b56019..590d102a 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -389,7 +389,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin * sample array. This produces the forward response with a backwards * phase-shift (+n degrees becomes -n degrees). */ - splitter.applyAllpass(tmpfilt[2].data(), static_cast(tmpfilt[2].size())); + splitter.applyAllpass(tmpfilt[2].data(), tmpfilt[2].size()); std::reverse(tmpfilt[2].begin(), tmpfilt[2].end()); /* Now apply the band-splitter. This applies the normal phase-shift, @@ -398,7 +398,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin */ splitter.clear(); splitter.process(tmpfilt[0].data(), tmpfilt[1].data(), tmpfilt[2].data(), - static_cast(tmpfilt[2].size())); + tmpfilt[2].size()); /* Apply left ear response with delay and HF scale. */ for(ALuint i{0u};i < NumChannels;++i) @@ -415,12 +415,12 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin std::transform(fir, fir+Hrtf->irSize, tmpfilt[2].rbegin() + HRIR_LENGTH*3, [](const ALfloat (&ir)[2]) noexcept -> ALdouble { return ir[1]; }); - splitter.applyAllpass(tmpfilt[2].data(), static_cast(tmpfilt[2].size())); + splitter.applyAllpass(tmpfilt[2].data(), tmpfilt[2].size()); std::reverse(tmpfilt[2].begin(), tmpfilt[2].end()); splitter.clear(); splitter.process(tmpfilt[0].data(), tmpfilt[1].data(), tmpfilt[2].data(), - static_cast(tmpfilt[2].size())); + tmpfilt[2].size()); for(ALuint i{0u};i < NumChannels;++i) { diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index b1d7500a..06324397 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -624,6 +624,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc DstBufferSize &= ~3; } + ASSUME(DstBufferSize > 0); for(ALsizei chan{0};chan < NumChannels;chan++) { ALvoice::ChannelData &chandata = voice->mChans[chan]; -- cgit v1.2.3 From 559d1666b8b029412ec9fe1bf2744dc9a4650583 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Aug 2019 14:59:01 -0700 Subject: Add a Create method to FlexArray for "raw" arrays --- alc/alc.cpp | 25 ++++++++++--------------- common/almalloc.h | 5 +++++ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index c9520c6d..615fc154 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -2483,20 +2483,19 @@ bool ALCcontext::deinit() auto alloc_ctx_array = [](const size_t count) -> ContextArray* { if(count == 0) return &EmptyContextArray; - void *ptr{al_calloc(alignof(ContextArray), ContextArray::Sizeof(count))}; - return new (ptr) ContextArray{count}; + return ContextArray::Create(count).release(); }; auto *newarray = alloc_ctx_array(oldarray->size() - toremove); - /* Copy the current/old context handles to the new array, excluding - * the given context. - */ + /* Copy the current/old context handles to the new array, excluding the + * given context. + */ std::copy_if(oldarray->begin(), oldarray->end(), newarray->begin(), std::bind(std::not_equal_to{}, _1, this)); - /* Store the new context array in the device. Wait for any current - * mix to finish before deleting the old array. - */ + /* Store the new context array in the device. Wait for any current mix + * to finish before deleting the old array. + */ mDevice->mContexts.store(newarray); if(oldarray != &EmptyContextArray) { @@ -2555,11 +2554,8 @@ void ALCcontext::allocVoices(size_t num_voices) if(mVoices && num_voices == mVoices->size()) return; - std::unique_ptr> voices; - { - void *ptr{al_calloc(16, al::FlexArray::Sizeof(num_voices))}; - voices.reset(new (ptr) al::FlexArray{num_voices}); - } + using ALvoiceArray = al::FlexArray; + std::unique_ptr voices{ALvoiceArray::Create(num_voices)}; const size_t v_count{minz(mVoiceCount.load(std::memory_order_relaxed), num_voices)}; if(mVoices) @@ -3366,8 +3362,7 @@ START_API_FUNC */ auto *oldarray = device->mContexts.load(); const size_t newcount{oldarray->size()+1}; - void *ptr{al_calloc(alignof(ContextArray), ContextArray::Sizeof(newcount))}; - std::unique_ptr newarray{new (ptr) ContextArray{newcount}}; + std::unique_ptr newarray{ContextArray::Create(newcount)}; /* Copy the current/old context handles to the new array, appending the * new context. diff --git a/common/almalloc.h b/common/almalloc.h index 3fc979c9..ca92316a 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -223,6 +223,11 @@ struct FlexArray { const index_type mSize; alignas(alignment) element_type mArray[0]; + static std::unique_ptr Create(index_type count) + { + void *ptr{al_calloc(alignof(FlexArray), Sizeof(count))}; + return std::unique_ptr{new (ptr) FlexArray{count}}; + } static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept { return base + -- cgit v1.2.3 From 7baa07e3adb91ce52358ebeb6e8aed51855422ba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Aug 2019 18:57:38 -0700 Subject: Pass spans to the source set-property methods This avoids an extra property check to get the size since the number of values can be checked when accessed. --- al/source.cpp | 431 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 212 insertions(+), 219 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index a021cd1a..043ef940 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -985,28 +985,38 @@ ALint Int64ValsByProp(ALenum prop) } -ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values); -ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values); -ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values); +bool SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span values); +bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span values); +bool SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span values); +#define CHECKSIZE(v, s) do { \ + if(UNLIKELY((v).size() != INT_MAX && (v).size() != (s))) \ + { \ + Context->setError(AL_INVALID_ENUM, \ + "Property 0x%04x expects %d value(s), got %zu", prop, (s), \ + (v).size()); \ + return false; \ + } \ +} while(0) #define CHECKVAL(x) do { \ - if(!(x)) \ + if(UNLIKELY(!(x))) \ { \ Context->setError(AL_INVALID_VALUE, "Value out of range"); \ - return AL_FALSE; \ + return false; \ } \ } while(0) -void UpdateSourceProps(ALsource *source, ALCcontext *context) +bool UpdateSourceProps(ALsource *source, ALCcontext *context) { ALvoice *voice; if(SourceShouldUpdate(source, context) && (voice=GetSourceVoice(source, context)) != nullptr) UpdateSourceProps(source, voice, context); else source->PropsClean.clear(std::memory_order_release); + return true; } -ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values) +bool SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span values) { ALint ival; @@ -1015,114 +1025,115 @@ ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, co case AL_SEC_OFFSET_LATENCY_SOFT: case AL_SEC_OFFSET_CLOCK_SOFT: /* Query only */ - SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, - "Setting read-only source property 0x%04x", prop); + SETERR_RETURN(Context, AL_INVALID_OPERATION, false, + "Setting read-only source property 0x%04x", prop); case AL_PITCH: - CHECKVAL(*values >= 0.0f); + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f); - Source->Pitch = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->Pitch = values[0]; + return UpdateSourceProps(Source, Context); case AL_CONE_INNER_ANGLE: - CHECKVAL(*values >= 0.0f && *values <= 360.0f); + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f && values[0] <= 360.0f); - Source->InnerAngle = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->InnerAngle = values[0]; + return UpdateSourceProps(Source, Context); case AL_CONE_OUTER_ANGLE: - CHECKVAL(*values >= 0.0f && *values <= 360.0f); + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f && values[0] <= 360.0f); - Source->OuterAngle = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->OuterAngle = values[0]; + return UpdateSourceProps(Source, Context); case AL_GAIN: - CHECKVAL(*values >= 0.0f); + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f); - Source->Gain = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->Gain = values[0]; + return UpdateSourceProps(Source, Context); case AL_MAX_DISTANCE: - CHECKVAL(*values >= 0.0f); + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f); - Source->MaxDistance = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->MaxDistance = values[0]; + return UpdateSourceProps(Source, Context); case AL_ROLLOFF_FACTOR: - CHECKVAL(*values >= 0.0f); + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f); - Source->RolloffFactor = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->RolloffFactor = values[0]; + return UpdateSourceProps(Source, Context); case AL_REFERENCE_DISTANCE: - CHECKVAL(*values >= 0.0f); + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f); - Source->RefDistance = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->RefDistance = values[0]; + return UpdateSourceProps(Source, Context); case AL_MIN_GAIN: - CHECKVAL(*values >= 0.0f); + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f); - Source->MinGain = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->MinGain = values[0]; + return UpdateSourceProps(Source, Context); case AL_MAX_GAIN: - CHECKVAL(*values >= 0.0f); + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f); - Source->MaxGain = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->MaxGain = values[0]; + return UpdateSourceProps(Source, Context); case AL_CONE_OUTER_GAIN: - CHECKVAL(*values >= 0.0f && *values <= 1.0f); + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f && values[0] <= 1.0f); - Source->OuterGain = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->OuterGain = values[0]; + return UpdateSourceProps(Source, Context); case AL_CONE_OUTER_GAINHF: - CHECKVAL(*values >= 0.0f && *values <= 1.0f); + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f && values[0] <= 1.0f); - Source->OuterGainHF = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->OuterGainHF = values[0]; + return UpdateSourceProps(Source, Context); case AL_AIR_ABSORPTION_FACTOR: - CHECKVAL(*values >= 0.0f && *values <= 10.0f); + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f && values[0] <= 10.0f); - Source->AirAbsorptionFactor = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->AirAbsorptionFactor = values[0]; + return UpdateSourceProps(Source, Context); case AL_ROOM_ROLLOFF_FACTOR: - CHECKVAL(*values >= 0.0f && *values <= 10.0f); + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f && values[0] <= 10.0f); - Source->RoomRolloffFactor = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->RoomRolloffFactor = values[0]; + return UpdateSourceProps(Source, Context); case AL_DOPPLER_FACTOR: - CHECKVAL(*values >= 0.0f && *values <= 1.0f); + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f && values[0] <= 1.0f); - Source->DopplerFactor = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->DopplerFactor = values[0]; + return UpdateSourceProps(Source, Context); case AL_SEC_OFFSET: case AL_SAMPLE_OFFSET: case AL_BYTE_OFFSET: - CHECKVAL(*values >= 0.0f); + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f); Source->OffsetType = prop; - Source->Offset = *values; + Source->Offset = values[0]; if(IsPlayingOrPaused(Source)) { @@ -1134,55 +1145,56 @@ ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, co if(ALvoice *voice{GetSourceVoice(Source, Context)}) { if(ApplyOffset(Source, voice) == AL_FALSE) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid offset"); + SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid offset"); } } - return AL_TRUE; + return true; case AL_SOURCE_RADIUS: - CHECKVAL(*values >= 0.0f && std::isfinite(*values)); + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f && std::isfinite(values[0])); - Source->Radius = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->Radius = values[0]; + return UpdateSourceProps(Source, Context); case AL_STEREO_ANGLES: + CHECKSIZE(values, 2); CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1])); Source->StereoPan[0] = values[0]; Source->StereoPan[1] = values[1]; - UpdateSourceProps(Source, Context); - return AL_TRUE; + return UpdateSourceProps(Source, Context); case AL_POSITION: + CHECKSIZE(values, 3); CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); Source->Position[0] = values[0]; Source->Position[1] = values[1]; Source->Position[2] = values[2]; - UpdateSourceProps(Source, Context); - return AL_TRUE; + return UpdateSourceProps(Source, Context); case AL_VELOCITY: + CHECKSIZE(values, 3); CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); Source->Velocity[0] = values[0]; Source->Velocity[1] = values[1]; Source->Velocity[2] = values[2]; - UpdateSourceProps(Source, Context); - return AL_TRUE; + return UpdateSourceProps(Source, Context); case AL_DIRECTION: + CHECKSIZE(values, 3); CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); Source->Direction[0] = values[0]; Source->Direction[1] = values[1]; Source->Direction[2] = values[2]; - UpdateSourceProps(Source, Context); - return AL_TRUE; + return UpdateSourceProps(Source, Context); case AL_ORIENTATION: + CHECKSIZE(values, 6); CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) && std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5])); @@ -1192,8 +1204,7 @@ ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, co Source->OrientUp[0] = values[3]; Source->OrientUp[1] = values[4]; Source->OrientUp[2] = values[5]; - UpdateSourceProps(Source, Context); - return AL_TRUE; + return UpdateSourceProps(Source, Context); case AL_SOURCE_RELATIVE: @@ -1207,13 +1218,15 @@ ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, co case AL_DIRECT_CHANNELS_SOFT: case AL_SOURCE_RESAMPLER_SOFT: case AL_SOURCE_SPATIALIZE_SOFT: + CHECKSIZE(values, 1); ival = static_cast(values[0]); - return SetSourceiv(Source, Context, prop, &ival); + return SetSourceiv(Source, Context, prop, {&ival, 1u}); case AL_BUFFERS_QUEUED: case AL_BUFFERS_PROCESSED: + CHECKSIZE(values, 1); ival = static_cast(static_cast(values[0])); - return SetSourceiv(Source, Context, prop, &ival); + return SetSourceiv(Source, Context, prop, {&ival, 1u}); case AL_BUFFER: case AL_DIRECT_FILTER: @@ -1225,10 +1238,10 @@ ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, co ERR("Unexpected property: 0x%04x\n", prop); Context->setError(AL_INVALID_ENUM, "Invalid source float property 0x%04x", prop); - return AL_FALSE; + return false; } -ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values) +bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span values) { ALCdevice *device{Context->mDevice.get()}; ALbuffer *buffer{nullptr}; @@ -1247,24 +1260,24 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co case AL_BUFFERS_QUEUED: case AL_BUFFERS_PROCESSED: /* Query only */ - SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, - "Setting read-only source property 0x%04x", prop); + SETERR_RETURN(Context, AL_INVALID_OPERATION, false, + "Setting read-only source property 0x%04x", prop); case AL_SOURCE_RELATIVE: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + CHECKSIZE(values, 1); + CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); - Source->HeadRelative = static_cast(*values); - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->HeadRelative = static_cast(values[0]); + return UpdateSourceProps(Source, Context); case AL_LOOPING: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + CHECKSIZE(values, 1); + CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); - Source->Looping = static_cast(*values); + Source->Looping = static_cast(values[0]); if(IsPlayingOrPaused(Source)) { - ALvoice *voice{GetSourceVoice(Source, Context)}; - if(voice) + if(ALvoice *voice{GetSourceVoice(Source, Context)}) { if(Source->Looping) voice->mLoopBuffer.store(Source->queue, std::memory_order_release); @@ -1279,24 +1292,24 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co std::this_thread::yield(); } } - return AL_TRUE; + return true; case AL_BUFFER: + CHECKSIZE(values, 1); buflock = std::unique_lock{device->BufferLock}; - if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != nullptr)) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid buffer ID %u", - *values); + if(!(values[0] == 0 || (buffer=LookupBuffer(device, values[0])) != nullptr)) + SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid buffer ID %u", values[0]); if(buffer && buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) - SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, - "Setting non-persistently mapped buffer %u", buffer->id); + SETERR_RETURN(Context, AL_INVALID_OPERATION, false, + "Setting non-persistently mapped buffer %u", buffer->id); else { ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context)); if(state == AL_PLAYING || state == AL_PAUSED) - SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, - "Setting buffer on playing or paused source %u", Source->id); + SETERR_RETURN(Context, AL_INVALID_OPERATION, false, + "Setting buffer on playing or paused source %u", Source->id); } oldlist = Source->queue; @@ -1334,15 +1347,16 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co { if(buffer) DecrementRef(buffer->ref); }); al_free(temp); } - return AL_TRUE; + return true; case AL_SEC_OFFSET: case AL_SAMPLE_OFFSET: case AL_BYTE_OFFSET: - CHECKVAL(*values >= 0); + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0); Source->OffsetType = prop; - Source->Offset = *values; + Source->Offset = values[0]; if(IsPlayingOrPaused(Source)) { @@ -1351,17 +1365,16 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co if(ALvoice *voice{GetSourceVoice(Source, Context)}) { if(ApplyOffset(Source, voice) == AL_FALSE) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, - "Invalid source offset"); + SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid source offset"); } } - return AL_TRUE; + return true; case AL_DIRECT_FILTER: + CHECKSIZE(values, 1); filtlock = std::unique_lock{device->FilterLock}; - if(!(*values == 0 || (filter=LookupFilter(device, *values)) != nullptr)) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", - *values); + if(!(values[0] == 0 || (filter=LookupFilter(device, values[0])) != nullptr)) + SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid filter ID %u", values[0]); if(!filter) { @@ -1380,78 +1393,74 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co Source->Direct.LFReference = filter->LFReference; } filtlock.unlock(); - UpdateSourceProps(Source, Context); - return AL_TRUE; + return UpdateSourceProps(Source, Context); case AL_DIRECT_FILTER_GAINHF_AUTO: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + CHECKSIZE(values, 1); + CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); - Source->DryGainHFAuto = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->DryGainHFAuto = values[0]; + return UpdateSourceProps(Source, Context); case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + CHECKSIZE(values, 1); + CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); - Source->WetGainAuto = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->WetGainAuto = values[0]; + return UpdateSourceProps(Source, Context); case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + CHECKSIZE(values, 1); + CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); - Source->WetGainHFAuto = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->WetGainHFAuto = values[0]; + return UpdateSourceProps(Source, Context); case AL_DIRECT_CHANNELS_SOFT: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + CHECKSIZE(values, 1); + CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); - Source->DirectChannels = *values; - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->DirectChannels = values[0]; + return UpdateSourceProps(Source, Context); case AL_DISTANCE_MODEL: - CHECKVAL(*values == AL_NONE || - *values == AL_INVERSE_DISTANCE || - *values == AL_INVERSE_DISTANCE_CLAMPED || - *values == AL_LINEAR_DISTANCE || - *values == AL_LINEAR_DISTANCE_CLAMPED || - *values == AL_EXPONENT_DISTANCE || - *values == AL_EXPONENT_DISTANCE_CLAMPED); - - Source->mDistanceModel = static_cast(*values); + CHECKSIZE(values, 1); + CHECKVAL(values[0] == AL_NONE || + values[0] == AL_INVERSE_DISTANCE || values[0] == AL_INVERSE_DISTANCE_CLAMPED || + values[0] == AL_LINEAR_DISTANCE || values[0] == AL_LINEAR_DISTANCE_CLAMPED || + values[0] == AL_EXPONENT_DISTANCE || values[0] == AL_EXPONENT_DISTANCE_CLAMPED); + + Source->mDistanceModel = static_cast(values[0]); if(Context->mSourceDistanceModel) - UpdateSourceProps(Source, Context); - return AL_TRUE; + return UpdateSourceProps(Source, Context); + return true; case AL_SOURCE_RESAMPLER_SOFT: - CHECKVAL(*values >= 0 && *values <= ResamplerMax); + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0 && values[0] <= ResamplerMax); - Source->mResampler = static_cast(*values); - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->mResampler = static_cast(values[0]); + return UpdateSourceProps(Source, Context); case AL_SOURCE_SPATIALIZE_SOFT: - CHECKVAL(*values >= AL_FALSE && *values <= AL_AUTO_SOFT); + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= AL_FALSE && values[0] <= AL_AUTO_SOFT); - Source->mSpatialize = static_cast(*values); - UpdateSourceProps(Source, Context); - return AL_TRUE; + Source->mSpatialize = static_cast(values[0]); + return UpdateSourceProps(Source, Context); case AL_AUXILIARY_SEND_FILTER: + CHECKSIZE(values, 3); slotlock = std::unique_lock{Context->mEffectSlotLock}; if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != nullptr)) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid effect ID %u", - values[0]); + SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid effect ID %u", values[0]); if(static_cast(values[1]) >= static_cast(device->NumAuxSends)) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid send %u", values[1]); + SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid send %u", values[1]); filtlock = std::unique_lock{device->FilterLock}; if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != nullptr)) - SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", - values[2]); + SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid filter ID %u", values[2]); if(!filter) { @@ -1495,8 +1504,7 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co Source->Send[values[1]].Slot = slot; UpdateSourceProps(Source, Context); } - - return AL_TRUE; + return true; /* 1x float */ @@ -1515,27 +1523,30 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co case AL_AIR_ABSORPTION_FACTOR: case AL_ROOM_ROLLOFF_FACTOR: case AL_SOURCE_RADIUS: - fvals[0] = static_cast(*values); - return SetSourcefv(Source, Context, prop, fvals); + CHECKSIZE(values, 1); + fvals[0] = static_cast(values[0]); + return SetSourcefv(Source, Context, prop, {fvals, 1u}); /* 3x float */ case AL_POSITION: case AL_VELOCITY: case AL_DIRECTION: + CHECKSIZE(values, 3); fvals[0] = static_cast(values[0]); fvals[1] = static_cast(values[1]); fvals[2] = static_cast(values[2]); - return SetSourcefv(Source, Context, prop, fvals); + return SetSourcefv(Source, Context, prop, {fvals, 3u}); /* 6x float */ case AL_ORIENTATION: + CHECKSIZE(values, 6); fvals[0] = static_cast(values[0]); fvals[1] = static_cast(values[1]); fvals[2] = static_cast(values[2]); fvals[3] = static_cast(values[3]); fvals[4] = static_cast(values[4]); fvals[5] = static_cast(values[5]); - return SetSourcefv(Source, Context, prop, fvals); + return SetSourcefv(Source, Context, prop, {fvals, 6u}); case AL_SAMPLE_OFFSET_LATENCY_SOFT: case AL_SEC_OFFSET_LATENCY_SOFT: @@ -1547,10 +1558,10 @@ ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, co ERR("Unexpected property: 0x%04x\n", prop); Context->setError(AL_INVALID_ENUM, "Invalid source integer property 0x%04x", prop); - return AL_FALSE; + return false; } -ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values) +bool SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span values) { ALfloat fvals[6]; ALint ivals[3]; @@ -1564,8 +1575,8 @@ ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, case AL_SAMPLE_OFFSET_LATENCY_SOFT: case AL_SAMPLE_OFFSET_CLOCK_SOFT: /* Query only */ - SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, - "Setting read-only source property 0x%04x", prop); + SETERR_RETURN(Context, AL_INVALID_OPERATION, false, + "Setting read-only source property 0x%04x", prop); /* 1x int */ case AL_SOURCE_RELATIVE: @@ -1580,21 +1591,24 @@ ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, case AL_DISTANCE_MODEL: case AL_SOURCE_RESAMPLER_SOFT: case AL_SOURCE_SPATIALIZE_SOFT: - CHECKVAL(*values <= INT_MAX && *values >= INT_MIN); + CHECKSIZE(values, 1); + CHECKVAL(values[0] <= INT_MAX && values[0] >= INT_MIN); - ivals[0] = static_cast(*values); - return SetSourceiv(Source, Context, prop, ivals); + ivals[0] = static_cast(values[0]); + return SetSourceiv(Source, Context, prop, {ivals, 1u}); /* 1x uint */ case AL_BUFFER: case AL_DIRECT_FILTER: - CHECKVAL(*values <= UINT_MAX && *values >= 0); + CHECKSIZE(values, 1); + CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0); - ivals[0] = static_cast(*values); - return SetSourceiv(Source, Context, prop, ivals); + ivals[0] = static_cast(values[0]); + return SetSourceiv(Source, Context, prop, {ivals, 1u}); /* 3x uint */ case AL_AUXILIARY_SEND_FILTER: + CHECKSIZE(values, 3); CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 && values[1] <= UINT_MAX && values[1] >= 0 && values[2] <= UINT_MAX && values[2] >= 0); @@ -1602,7 +1616,7 @@ ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ivals[0] = static_cast(values[0]); ivals[1] = static_cast(values[1]); ivals[2] = static_cast(values[2]); - return SetSourceiv(Source, Context, prop, ivals); + return SetSourceiv(Source, Context, prop, {ivals, 3u}); /* 1x float */ case AL_CONE_INNER_ANGLE: @@ -1620,27 +1634,30 @@ ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, case AL_AIR_ABSORPTION_FACTOR: case AL_ROOM_ROLLOFF_FACTOR: case AL_SOURCE_RADIUS: - fvals[0] = static_cast(*values); - return SetSourcefv(Source, Context, prop, fvals); + CHECKSIZE(values, 1); + fvals[0] = static_cast(values[0]); + return SetSourcefv(Source, Context, prop, {fvals, 1u}); /* 3x float */ case AL_POSITION: case AL_VELOCITY: case AL_DIRECTION: + CHECKSIZE(values, 3); fvals[0] = static_cast(values[0]); fvals[1] = static_cast(values[1]); fvals[2] = static_cast(values[2]); - return SetSourcefv(Source, Context, prop, fvals); + return SetSourcefv(Source, Context, prop, {fvals, 3u}); /* 6x float */ case AL_ORIENTATION: + CHECKSIZE(values, 6); fvals[0] = static_cast(values[0]); fvals[1] = static_cast(values[1]); fvals[2] = static_cast(values[2]); fvals[3] = static_cast(values[3]); fvals[4] = static_cast(values[4]); fvals[5] = static_cast(values[5]); - return SetSourcefv(Source, Context, prop, fvals); + return SetSourcefv(Source, Context, prop, {fvals, 6u}); case AL_SEC_OFFSET_LATENCY_SOFT: case AL_SEC_OFFSET_CLOCK_SOFT: @@ -2225,10 +2242,8 @@ START_API_FUNC ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(FloatValsByProp(param) != 1) - context->setError(AL_INVALID_ENUM, "Invalid float property 0x%04x", param); else - SetSourcefv(Source, context.get(), static_cast(param), &value); + SetSourcefv(Source, context.get(), static_cast(param), {&value, 1u}); } END_API_FUNC @@ -2243,11 +2258,9 @@ START_API_FUNC ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(FloatValsByProp(param) != 3) - context->setError(AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); else { - ALfloat fvals[3] = { value1, value2, value3 }; + const ALfloat fvals[3]{ value1, value2, value3 }; SetSourcefv(Source, context.get(), static_cast(param), fvals); } } @@ -2266,10 +2279,8 @@ START_API_FUNC context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); - else if(FloatValsByProp(param) < 1) - context->setError(AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); else - SetSourcefv(Source, context.get(), static_cast(param), values); + SetSourcefv(Source, context.get(), static_cast(param), {values, INT_MAX}); } END_API_FUNC @@ -2285,12 +2296,10 @@ START_API_FUNC ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(DoubleValsByProp(param) != 1) - context->setError(AL_INVALID_ENUM, "Invalid double property 0x%04x", param); else { - ALfloat fval = static_cast(value); - SetSourcefv(Source, context.get(), static_cast(param), &fval); + const auto fval = static_cast(value); + SetSourcefv(Source, context.get(), static_cast(param), {&fval, 1u}); } } END_API_FUNC @@ -2306,12 +2315,10 @@ START_API_FUNC ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(DoubleValsByProp(param) != 3) - context->setError(AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); - else { - ALfloat fvals[3] = {static_cast(value1), - static_cast(value2), - static_cast(value3)}; + else + { + const ALfloat fvals[3]{static_cast(value1), static_cast(value2), + static_cast(value3)}; SetSourcefv(Source, context.get(), static_cast(param), fvals); } } @@ -2332,17 +2339,15 @@ START_API_FUNC context->setError(AL_INVALID_VALUE, "NULL pointer"); else { - ALint count{DoubleValsByProp(param)}; + const ALuint count = DoubleValsByProp(param); if(count < 1 || count > 6) context->setError(AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); else { ALfloat fvals[6]; - ALint i; - - for(i = 0;i < count;i++) + for(ALuint i{0};i < count;i++) fvals[i] = static_cast(values[i]); - SetSourcefv(Source, context.get(), static_cast(param), fvals); + SetSourcefv(Source, context.get(), static_cast(param), {fvals, count}); } } } @@ -2360,10 +2365,8 @@ START_API_FUNC ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(IntValsByProp(param) != 1) - context->setError(AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); else - SetSourceiv(Source, context.get(), static_cast(param), &value); + SetSourceiv(Source, context.get(), static_cast(param), {&value, 1u}); } END_API_FUNC @@ -2378,11 +2381,9 @@ START_API_FUNC ALsource *Source = LookupSource(context.get(), source); if(UNLIKELY(!Source)) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(IntValsByProp(param) != 3) - context->setError(AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); else { - ALint ivals[3] = { value1, value2, value3 }; + const ALint ivals[3]{ value1, value2, value3 }; SetSourceiv(Source, context.get(), static_cast(param), ivals); } } @@ -2401,10 +2402,8 @@ START_API_FUNC context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); - else if(IntValsByProp(param) < 1) - context->setError(AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); else - SetSourceiv(Source, context.get(), static_cast(param), values); + SetSourceiv(Source, context.get(), static_cast(param), {values, INT_MAX}); } END_API_FUNC @@ -2420,10 +2419,8 @@ START_API_FUNC ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(Int64ValsByProp(param) != 1) - context->setError(AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); else - SetSourcei64v(Source, context.get(), static_cast(param), &value); + SetSourcei64v(Source, context.get(), static_cast(param), {&value, 1u}); } END_API_FUNC @@ -2438,11 +2435,9 @@ START_API_FUNC ALsource *Source{LookupSource(context.get(), source)}; if(UNLIKELY(!Source)) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(Int64ValsByProp(param) != 3) - context->setError(AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); else { - ALint64SOFT i64vals[3] = { value1, value2, value3 }; + const ALint64SOFT i64vals[3]{ value1, value2, value3 }; SetSourcei64v(Source, context.get(), static_cast(param), i64vals); } } @@ -2461,10 +2456,8 @@ START_API_FUNC context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); - else if(Int64ValsByProp(param) < 1) - context->setError(AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); else - SetSourcei64v(Source, context.get(), static_cast(param), values); + SetSourcei64v(Source, context.get(), static_cast(param), {values, INT_MAX}); } END_API_FUNC -- cgit v1.2.3 From 7897de31d0f75f4ac1d91fe8c470953e9f54d151 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Aug 2019 19:36:19 -0700 Subject: Pass spans to the source get-property methods --- al/source.cpp | 433 ++++++++++++++++++++++------------------------------------ 1 file changed, 165 insertions(+), 268 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index 043ef940..69bdf6b5 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -741,7 +741,7 @@ void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) } -ALint FloatValsByProp(ALenum prop) +ALuint FloatValsByProp(ALenum prop) { switch(static_cast(prop)) { @@ -803,7 +803,7 @@ ALint FloatValsByProp(ALenum prop) } return 0; } -ALint DoubleValsByProp(ALenum prop) +ALuint DoubleValsByProp(ALenum prop) { switch(static_cast(prop)) { @@ -864,126 +864,6 @@ ALint DoubleValsByProp(ALenum prop) return 0; } -ALint IntValsByProp(ALenum prop) -{ - switch(static_cast(prop)) - { - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_REFERENCE_DISTANCE: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_BUFFER: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_DIRECT_FILTER: - case AL_SOURCE_RADIUS: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - return 1; - - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - case AL_AUXILIARY_SEND_FILTER: - return 3; - - case AL_ORIENTATION: - return 6; - - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; /* i64 only */ - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - case AL_STEREO_ANGLES: - break; /* Float/double only */ - } - return 0; -} -ALint Int64ValsByProp(ALenum prop) -{ - switch(static_cast(prop)) - { - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_REFERENCE_DISTANCE: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_BUFFER: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_DIRECT_FILTER: - case AL_SOURCE_RADIUS: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - return 1; - - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - return 2; - - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - case AL_AUXILIARY_SEND_FILTER: - return 3; - - case AL_ORIENTATION: - return 6; - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - case AL_STEREO_ANGLES: - break; /* Float/double only */ - } - return 0; -} - bool SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span values); bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span values); @@ -1667,17 +1547,17 @@ bool SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ERR("Unexpected property: 0x%04x\n", prop); Context->setError(AL_INVALID_ENUM, "Invalid source integer64 property 0x%04x", prop); - return AL_FALSE; + return false; } #undef CHECKVAL -ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values); -ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values); -ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64SOFT *values); +bool GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span values); +bool GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span values); +bool GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span values); -ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values) +bool GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span values) { ALCdevice *device{Context->mDevice.get()}; ClockLatency clocktime; @@ -1688,77 +1568,95 @@ ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL switch(prop) { case AL_GAIN: - *values = Source->Gain; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->Gain; + return true; case AL_PITCH: - *values = Source->Pitch; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->Pitch; + return true; case AL_MAX_DISTANCE: - *values = Source->MaxDistance; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->MaxDistance; + return true; case AL_ROLLOFF_FACTOR: - *values = Source->RolloffFactor; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->RolloffFactor; + return true; case AL_REFERENCE_DISTANCE: - *values = Source->RefDistance; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->RefDistance; + return true; case AL_CONE_INNER_ANGLE: - *values = Source->InnerAngle; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->InnerAngle; + return true; case AL_CONE_OUTER_ANGLE: - *values = Source->OuterAngle; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->OuterAngle; + return true; case AL_MIN_GAIN: - *values = Source->MinGain; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->MinGain; + return true; case AL_MAX_GAIN: - *values = Source->MaxGain; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->MaxGain; + return true; case AL_CONE_OUTER_GAIN: - *values = Source->OuterGain; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->OuterGain; + return true; case AL_SEC_OFFSET: case AL_SAMPLE_OFFSET: case AL_BYTE_OFFSET: - *values = GetSourceOffset(Source, prop, Context); - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = GetSourceOffset(Source, prop, Context); + return true; case AL_CONE_OUTER_GAINHF: - *values = Source->OuterGainHF; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->OuterGainHF; + return true; case AL_AIR_ABSORPTION_FACTOR: - *values = Source->AirAbsorptionFactor; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->AirAbsorptionFactor; + return true; case AL_ROOM_ROLLOFF_FACTOR: - *values = Source->RoomRolloffFactor; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->RoomRolloffFactor; + return true; case AL_DOPPLER_FACTOR: - *values = Source->DopplerFactor; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->DopplerFactor; + return true; case AL_SOURCE_RADIUS: - *values = Source->Radius; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->Radius; + return true; case AL_STEREO_ANGLES: + CHECKSIZE(values, 2); values[0] = Source->StereoPan[0]; values[1] = Source->StereoPan[1]; - return AL_TRUE; + return true; case AL_SEC_OFFSET_LATENCY_SOFT: + CHECKSIZE(values, 2); /* Get the source offset with the clock time first. Then get the * clock time with the device latency. Order is important. */ @@ -1778,39 +1676,44 @@ ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL values[1] = static_cast((clocktime.Latency - std::min(clocktime.Latency, diff)).count()) / 1000000000.0; } - return AL_TRUE; + return true; case AL_SEC_OFFSET_CLOCK_SOFT: + CHECKSIZE(values, 2); values[0] = GetSourceSecOffset(Source, Context, &srcclock); values[1] = srcclock.count() / 1000000000.0; - return AL_TRUE; + return true; case AL_POSITION: + CHECKSIZE(values, 3); values[0] = Source->Position[0]; values[1] = Source->Position[1]; values[2] = Source->Position[2]; - return AL_TRUE; + return true; case AL_VELOCITY: + CHECKSIZE(values, 3); values[0] = Source->Velocity[0]; values[1] = Source->Velocity[1]; values[2] = Source->Velocity[2]; - return AL_TRUE; + return true; case AL_DIRECTION: + CHECKSIZE(values, 3); values[0] = Source->Direction[0]; values[1] = Source->Direction[1]; values[2] = Source->Direction[2]; - return AL_TRUE; + return true; case AL_ORIENTATION: + CHECKSIZE(values, 6); values[0] = Source->OrientAt[0]; values[1] = Source->OrientAt[1]; values[2] = Source->OrientAt[2]; values[3] = Source->OrientUp[0]; values[4] = Source->OrientUp[1]; values[5] = Source->OrientUp[2]; - return AL_TRUE; + return true; /* 1x int */ case AL_SOURCE_RELATIVE: @@ -1826,8 +1729,9 @@ ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL case AL_DISTANCE_MODEL: case AL_SOURCE_RESAMPLER_SOFT: case AL_SOURCE_SPATIALIZE_SOFT: - if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) - *values = static_cast(ivals[0]); + CHECKSIZE(values, 1); + if((err=GetSourceiv(Source, Context, prop, {ivals, 1u})) != AL_FALSE) + values[0] = static_cast(ivals[0]); return err; case AL_BUFFER: @@ -1840,10 +1744,10 @@ ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL ERR("Unexpected property: 0x%04x\n", prop); Context->setError(AL_INVALID_ENUM, "Invalid source double property 0x%04x", prop); - return AL_FALSE; + return false; } -ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values) +bool GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span values) { ALbufferlistitem *BufferList; ALdouble dvals[6]; @@ -1852,43 +1756,49 @@ ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL switch(prop) { case AL_SOURCE_RELATIVE: - *values = Source->HeadRelative; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->HeadRelative; + return true; case AL_LOOPING: - *values = Source->Looping; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->Looping; + return true; case AL_BUFFER: + CHECKSIZE(values, 1); BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : nullptr; - *values = (BufferList && BufferList->mNumBuffers >= 1 && BufferList->front()) ? - BufferList->front()->id : 0; - return AL_TRUE; + values[0] = (BufferList && !BufferList->empty() && BufferList->front()) ? + BufferList->front()->id : 0; + return true; case AL_SOURCE_STATE: - *values = GetSourceState(Source, GetSourceVoice(Source, Context)); - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = GetSourceState(Source, GetSourceVoice(Source, Context)); + return true; case AL_BUFFERS_QUEUED: + CHECKSIZE(values, 1); if(!(BufferList=Source->queue)) - *values = 0; + values[0] = 0; else { - ALsizei count = 0; + ALsizei count{0}; do { count += BufferList->mNumBuffers; BufferList = BufferList->mNext.load(std::memory_order_relaxed); } while(BufferList != nullptr); - *values = count; + values[0] = count; } - return AL_TRUE; + return true; case AL_BUFFERS_PROCESSED: + CHECKSIZE(values, 1); if(Source->Looping || Source->SourceType != AL_STREAMING) { /* Buffers on a looping source are in a perpetual state of * PENDING, so don't report any as PROCESSED */ - *values = 0; + values[0] = 0; } else { @@ -1907,41 +1817,49 @@ ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL played += BufferList->mNumBuffers; BufferList = BufferList->mNext.load(std::memory_order_relaxed); } - *values = played; + values[0] = played; } - return AL_TRUE; + return true; case AL_SOURCE_TYPE: - *values = Source->SourceType; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->SourceType; + return true; case AL_DIRECT_FILTER_GAINHF_AUTO: - *values = Source->DryGainHFAuto; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->DryGainHFAuto; + return true; case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - *values = Source->WetGainAuto; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->WetGainAuto; + return true; case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - *values = Source->WetGainHFAuto; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->WetGainHFAuto; + return true; case AL_DIRECT_CHANNELS_SOFT: - *values = Source->DirectChannels; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->DirectChannels; + return true; case AL_DISTANCE_MODEL: - *values = static_cast(Source->mDistanceModel); - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = static_cast(Source->mDistanceModel); + return true; case AL_SOURCE_RESAMPLER_SOFT: - *values = Source->mResampler; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->mResampler; + return true; case AL_SOURCE_SPATIALIZE_SOFT: - *values = Source->mSpatialize; - return AL_TRUE; + CHECKSIZE(values, 1); + values[0] = Source->mSpatialize; + return true; /* 1x float/double */ case AL_CONE_INNER_ANGLE: @@ -1962,15 +1880,17 @@ ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL case AL_ROOM_ROLLOFF_FACTOR: case AL_CONE_OUTER_GAINHF: case AL_SOURCE_RADIUS: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - *values = static_cast(dvals[0]); + CHECKSIZE(values, 1); + if((err=GetSourcedv(Source, Context, prop, {dvals, 1u})) != false) + values[0] = static_cast(dvals[0]); return err; /* 3x float/double */ case AL_POSITION: case AL_VELOCITY: case AL_DIRECTION: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + CHECKSIZE(values, 3); + if((err=GetSourcedv(Source, Context, prop, {dvals, 3u})) != false) { values[0] = static_cast(dvals[0]); values[1] = static_cast(dvals[1]); @@ -1980,7 +1900,8 @@ ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL /* 6x float/double */ case AL_ORIENTATION: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + CHECKSIZE(values, 6); + if((err=GetSourcedv(Source, Context, prop, {dvals, 6u})) != false) { values[0] = static_cast(dvals[0]); values[1] = static_cast(dvals[1]); @@ -2007,10 +1928,10 @@ ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, AL ERR("Unexpected property: 0x%04x\n", prop); Context->setError(AL_INVALID_ENUM, "Invalid source integer property 0x%04x", prop); - return AL_FALSE; + return false; } -ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64SOFT *values) +bool GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span values) { ALCdevice *device = Context->mDevice.get(); ClockLatency clocktime; @@ -2022,6 +1943,7 @@ ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, switch(prop) { case AL_SAMPLE_OFFSET_LATENCY_SOFT: + CHECKSIZE(values, 2); /* Get the source offset with the clock time first. Then get the * clock time with the device latency. Order is important. */ @@ -2040,9 +1962,10 @@ ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, auto diff = clocktime.ClockTime - srcclock; values[1] = (clocktime.Latency - std::min(clocktime.Latency, diff)).count(); } - return AL_TRUE; + return true; case AL_SAMPLE_OFFSET_CLOCK_SOFT: + CHECKSIZE(values, 2); values[0] = GetSourceSampleOffset(Source, Context, &srcclock); values[1] = srcclock.count(); return AL_TRUE; @@ -2066,15 +1989,17 @@ ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, case AL_ROOM_ROLLOFF_FACTOR: case AL_CONE_OUTER_GAINHF: case AL_SOURCE_RADIUS: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - *values = static_cast(dvals[0]); + CHECKSIZE(values, 1); + if((err=GetSourcedv(Source, Context, prop, {dvals, 1u})) != false) + values[0] = static_cast(dvals[0]); return err; /* 3x float/double */ case AL_POSITION: case AL_VELOCITY: case AL_DIRECTION: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + CHECKSIZE(values, 3); + if((err=GetSourcedv(Source, Context, prop, {dvals, 3u})) != false) { values[0] = static_cast(dvals[0]); values[1] = static_cast(dvals[1]); @@ -2084,7 +2009,8 @@ ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, /* 6x float/double */ case AL_ORIENTATION: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + CHECKSIZE(values, 6); + if((err=GetSourcedv(Source, Context, prop, {dvals, 6u})) != false) { values[0] = static_cast(dvals[0]); values[1] = static_cast(dvals[1]); @@ -2109,20 +2035,23 @@ ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, case AL_DISTANCE_MODEL: case AL_SOURCE_RESAMPLER_SOFT: case AL_SOURCE_SPATIALIZE_SOFT: - if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) - *values = ivals[0]; + CHECKSIZE(values, 1); + if((err=GetSourceiv(Source, Context, prop, {ivals, 1u})) != false) + values[0] = ivals[0]; return err; /* 1x uint */ case AL_BUFFER: case AL_DIRECT_FILTER: - if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) - *values = static_cast(ivals[0]); + CHECKSIZE(values, 1); + if((err=GetSourceiv(Source, Context, prop, {ivals, 1u})) != false) + values[0] = static_cast(ivals[0]); return err; /* 3x uint */ case AL_AUXILIARY_SEND_FILTER: - if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) + CHECKSIZE(values, 3); + if((err=GetSourceiv(Source, Context, prop, {ivals, 3u})) != false) { values[0] = static_cast(ivals[0]); values[1] = static_cast(ivals[1]); @@ -2139,7 +2068,7 @@ ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ERR("Unexpected property: 0x%04x\n", prop); Context->setError(AL_INVALID_ENUM, "Invalid source integer64 property 0x%04x", prop); - return AL_FALSE; + return false; } } // namespace @@ -2339,16 +2268,11 @@ START_API_FUNC context->setError(AL_INVALID_VALUE, "NULL pointer"); else { - const ALuint count = DoubleValsByProp(param); - if(count < 1 || count > 6) - context->setError(AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); - else - { - ALfloat fvals[6]; - for(ALuint i{0};i < count;i++) - fvals[i] = static_cast(values[i]); - SetSourcefv(Source, context.get(), static_cast(param), {fvals, count}); - } + const ALuint count{DoubleValsByProp(param)}; + ALfloat fvals[6]; + for(ALuint i{0};i < count;i++) + fvals[i] = static_cast(values[i]); + SetSourcefv(Source, context.get(), static_cast(param), {fvals, count}); } } END_API_FUNC @@ -2474,12 +2398,10 @@ START_API_FUNC context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) context->setError(AL_INVALID_VALUE, "NULL pointer"); - else if(FloatValsByProp(param) != 1) - context->setError(AL_INVALID_ENUM, "Invalid float property 0x%04x", param); else { ALdouble dval; - if(GetSourcedv(Source, context.get(), static_cast(param), &dval)) + if(GetSourcedv(Source, context.get(), static_cast(param), {&dval, 1u})) *value = static_cast(dval); } } @@ -2497,8 +2419,6 @@ START_API_FUNC context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) context->setError(AL_INVALID_VALUE, "NULL pointer"); - else if(FloatValsByProp(param) != 3) - context->setError(AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); else { ALdouble dvals[3]; @@ -2526,17 +2446,12 @@ START_API_FUNC context->setError(AL_INVALID_VALUE, "NULL pointer"); else { - ALint count{FloatValsByProp(param)}; - if(count < 1 && count > 6) - context->setError(AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); - else + const ALuint count{FloatValsByProp(param)}; + ALdouble dvals[6]; + if(GetSourcedv(Source, context.get(), static_cast(param), {dvals, count})) { - ALdouble dvals[6]; - if(GetSourcedv(Source, context.get(), static_cast(param), dvals)) - { - for(ALint i{0};i < count;i++) - values[i] = static_cast(dvals[i]); - } + for(ALuint i{0};i < count;i++) + values[i] = static_cast(dvals[i]); } } } @@ -2555,10 +2470,8 @@ START_API_FUNC context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) context->setError(AL_INVALID_VALUE, "NULL pointer"); - else if(DoubleValsByProp(param) != 1) - context->setError(AL_INVALID_ENUM, "Invalid double property 0x%04x", param); else - GetSourcedv(Source, context.get(), static_cast(param), value); + GetSourcedv(Source, context.get(), static_cast(param), {value, 1u}); } END_API_FUNC @@ -2574,8 +2487,6 @@ START_API_FUNC context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) context->setError(AL_INVALID_VALUE, "NULL pointer"); - else if(DoubleValsByProp(param) != 3) - context->setError(AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); else { ALdouble dvals[3]; @@ -2601,10 +2512,8 @@ START_API_FUNC context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); - else if(DoubleValsByProp(param) < 1) - context->setError(AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); else - GetSourcedv(Source, context.get(), static_cast(param), values); + GetSourcedv(Source, context.get(), static_cast(param), {values, INT_MAX}); } END_API_FUNC @@ -2621,10 +2530,8 @@ START_API_FUNC context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) context->setError(AL_INVALID_VALUE, "NULL pointer"); - else if(IntValsByProp(param) != 1) - context->setError(AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); else - GetSourceiv(Source, context.get(), static_cast(param), value); + GetSourceiv(Source, context.get(), static_cast(param), {value, 1u}); } END_API_FUNC @@ -2640,8 +2547,6 @@ START_API_FUNC context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) context->setError(AL_INVALID_VALUE, "NULL pointer"); - else if(IntValsByProp(param) != 3) - context->setError(AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); else { ALint ivals[3]; @@ -2667,10 +2572,8 @@ START_API_FUNC context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); - else if(IntValsByProp(param) < 1) - context->setError(AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); else - GetSourceiv(Source, context.get(), static_cast(param), values); + GetSourceiv(Source, context.get(), static_cast(param), {values, INT_MAX}); } END_API_FUNC @@ -2687,10 +2590,8 @@ START_API_FUNC context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) context->setError(AL_INVALID_VALUE, "NULL pointer"); - else if(Int64ValsByProp(param) != 1) - context->setError(AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); else - GetSourcei64v(Source, context.get(), static_cast(param), value); + GetSourcei64v(Source, context.get(), static_cast(param), {value, 1u}); } END_API_FUNC @@ -2706,8 +2607,6 @@ START_API_FUNC context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) context->setError(AL_INVALID_VALUE, "NULL pointer"); - else if(Int64ValsByProp(param) != 3) - context->setError(AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); else { ALint64SOFT i64vals[3]; @@ -2733,10 +2632,8 @@ START_API_FUNC context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); - else if(Int64ValsByProp(param) < 1) - context->setError(AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); else - GetSourcei64v(Source, context.get(), static_cast(param), values); + GetSourcei64v(Source, context.get(), static_cast(param), {values, INT_MAX}); } END_API_FUNC -- cgit v1.2.3 From 2fa2c35bdc2a09d5e856bb12ad6dff556bbe65a8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 4 Aug 2019 11:59:14 -0700 Subject: Modify LIKELY and UNLIKELY to not need extra parenthesis --- al/auxeffectslot.cpp | 56 ++++----- al/buffer.cpp | 224 ++++++++++++++++++------------------ al/effect.cpp | 70 ++++++------ al/error.cpp | 2 +- al/event.cpp | 12 +- al/extension.cpp | 2 +- al/filter.cpp | 70 ++++++------ al/listener.cpp | 24 ++-- al/source.cpp | 268 ++++++++++++++++++++++---------------------- al/state.cpp | 46 ++++---- alc/alc.cpp | 2 +- alc/alu.cpp | 12 +- alc/backends/opensl.cpp | 2 +- alc/backends/pulseaudio.cpp | 22 ++-- alc/bformatdec.cpp | 4 +- alc/effects/pshifter.cpp | 4 +- alc/effects/reverb.cpp | 2 +- alc/helpers.cpp | 2 +- alc/logging.h | 8 +- alc/mastering.cpp | 2 +- alc/mixer/mixer_neon.cpp | 6 +- alc/mixer/mixer_sse.cpp | 6 +- alc/mixvoice.cpp | 16 +-- common/alexcpt.cpp | 2 +- common/alnumeric.h | 6 +- common/intrusive_ptr.h | 2 +- common/opthelpers.h | 4 +- 27 files changed, 428 insertions(+), 448 deletions(-) diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index 912765fc..e961874d 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -53,10 +53,10 @@ inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; - if(UNLIKELY(lidx >= context->mEffectSlotList.size())) + if UNLIKELY(lidx >= context->mEffectSlotList.size()) return nullptr; EffectSlotSubList &sublist{context->mEffectSlotList[lidx]}; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + if UNLIKELY(sublist.FreeMask & (1_u64 << slidx)) return nullptr; return sublist.EffectSlots + slidx; } @@ -66,10 +66,10 @@ inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) noexcept ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; - if(UNLIKELY(lidx >= device->EffectList.size())) + if UNLIKELY(lidx >= device->EffectList.size()) return nullptr; EffectSubList &sublist = device->EffectList[lidx]; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + if UNLIKELY(sublist.FreeMask & (1_u64 << slidx)) return nullptr; return sublist.Effects + slidx; } @@ -104,7 +104,7 @@ void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *cont /* Reallocate newarray if the new size ended up smaller from duplicate * removal. */ - if(UNLIKELY(newcount < newarray->size())) + if UNLIKELY(newcount < newarray->size()) { curarray = newarray; newarray = ALeffectslot::CreatePtrArray(newcount); @@ -139,7 +139,7 @@ void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *c /* Reallocate with the new size. */ auto newsize = static_cast(std::distance(newarray->begin(), slotiter)); - if(LIKELY(newsize != newarray->size())) + if LIKELY(newsize != newarray->size()) { curarray = newarray; newarray = ALeffectslot::CreatePtrArray(newsize); @@ -174,7 +174,7 @@ ALeffectslot *AllocEffectSlot(ALCcontext *context) auto lidx = static_cast(std::distance(context->mEffectSlotList.begin(), sublist)); ALeffectslot *slot; ALsizei slidx; - if(LIKELY(sublist != context->mEffectSlotList.end())) + if LIKELY(sublist != context->mEffectSlotList.end()) { slidx = CTZ64(sublist->FreeMask); slot = sublist->EffectSlots + slidx; @@ -184,7 +184,7 @@ ALeffectslot *AllocEffectSlot(ALCcontext *context) /* Don't allocate so many list entries that the 32-bit ID could * overflow... */ - if(UNLIKELY(context->mEffectSlotList.size() >= 1<<25)) + if UNLIKELY(context->mEffectSlotList.size() >= 1<<25) { context->setError(AL_OUT_OF_MEMORY, "Too many effect slots allocated"); return nullptr; @@ -194,7 +194,7 @@ ALeffectslot *AllocEffectSlot(ALCcontext *context) sublist->FreeMask = ~0_u64; sublist->EffectSlots = static_cast(al_calloc(16, sizeof(ALeffectslot)*64)); - if(UNLIKELY(!sublist->EffectSlots)) + if UNLIKELY(!sublist->EffectSlots) { context->mEffectSlotList.pop_back(); context->setError(AL_OUT_OF_MEMORY, "Failed to allocate effect slot batch"); @@ -260,7 +260,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; if(n < 0) SETERR_RETURN(context, AL_INVALID_VALUE,, "Generating %d effect slots", n); @@ -303,7 +303,7 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; if(n < 0) SETERR_RETURN(context, AL_INVALID_VALUE,, "Deleting %d effect slots", n); @@ -347,7 +347,7 @@ AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot) START_API_FUNC { ContextRef context{GetContextRef()}; - if(LIKELY(context)) + if LIKELY(context) { std::lock_guard _{context->mEffectSlotLock}; if(LookupEffectSlot(context.get(), effectslot) != nullptr) @@ -362,12 +362,12 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; std::lock_guard __{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) + if UNLIKELY(!slot) SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); ALeffectslot *target{}; @@ -450,11 +450,11 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) + if UNLIKELY(!slot) SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); switch(param) @@ -470,12 +470,12 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; std::lock_guard __{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) + if UNLIKELY(!slot) SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); switch(param) @@ -505,11 +505,11 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) + if UNLIKELY(!slot) SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); switch(param) @@ -526,11 +526,11 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum pa START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) + if UNLIKELY(!slot) SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); switch(param) @@ -562,11 +562,11 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) + if UNLIKELY(!slot) SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); switch(param) @@ -582,11 +582,11 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum pa START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) + if UNLIKELY(!slot) SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); switch(param) @@ -612,11 +612,11 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mEffectSlotLock}; ALeffectslot *slot = LookupEffectSlot(context.get(), effectslot); - if(UNLIKELY(!slot)) + if UNLIKELY(!slot) SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid effect slot ID %u", effectslot); switch(param) diff --git a/al/buffer.cpp b/al/buffer.cpp index a068399c..df2496cb 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -256,7 +256,7 @@ ALbuffer *AllocBuffer(ALCcontext *context) auto lidx = static_cast(std::distance(device->BufferList.begin(), sublist)); ALbuffer *buffer{nullptr}; ALsizei slidx{0}; - if(LIKELY(sublist != device->BufferList.end())) + if LIKELY(sublist != device->BufferList.end()) { slidx = CTZ64(sublist->FreeMask); buffer = sublist->Buffers + slidx; @@ -266,7 +266,7 @@ ALbuffer *AllocBuffer(ALCcontext *context) /* Don't allocate so many list entries that the 32-bit ID could * overflow... */ - if(UNLIKELY(device->BufferList.size() >= 1<<25)) + if UNLIKELY(device->BufferList.size() >= 1<<25) { context->setError(AL_OUT_OF_MEMORY, "Too many buffers allocated"); return nullptr; @@ -275,7 +275,7 @@ ALbuffer *AllocBuffer(ALCcontext *context) sublist = device->BufferList.end() - 1; sublist->FreeMask = ~0_u64; sublist->Buffers = reinterpret_cast(al_calloc(16, sizeof(ALbuffer)*64)); - if(UNLIKELY(!sublist->Buffers)) + if UNLIKELY(!sublist->Buffers) { device->BufferList.pop_back(); context->setError(AL_OUT_OF_MEMORY, "Failed to allocate buffer batch"); @@ -311,10 +311,10 @@ inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; - if(UNLIKELY(lidx >= device->BufferList.size())) + if UNLIKELY(lidx >= device->BufferList.size()) return nullptr; BufferSubList &sublist = device->BufferList[lidx]; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + if UNLIKELY(sublist.FreeMask & (1_u64 << slidx)) return nullptr; return sublist.Buffers + slidx; } @@ -380,7 +380,7 @@ const ALchar *NameFromUserFmtType(UserFmtType type) */ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, UserFmtChannels SrcChannels, UserFmtType SrcType, const al::byte *SrcData, ALbitfieldSOFT access) { - if(UNLIKELY(ReadRef(ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)) + if UNLIKELY(ReadRef(ALBuf->ref) != 0 || ALBuf->MappedAccess != 0) SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer %u", ALBuf->id); @@ -398,8 +398,7 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U case UserFmtBFormat2D: DstChannels = FmtBFormat2D; break; case UserFmtBFormat3D: DstChannels = FmtBFormat3D; break; } - if (UNLIKELY(static_cast(SrcChannels) != - static_cast(DstChannels))) + if UNLIKELY(static_cast(SrcChannels) != static_cast(DstChannels)) SETERR_RETURN(context, AL_INVALID_ENUM, , "Invalid format"); /* IMA4 and MSADPCM convert to 16-bit short. */ @@ -422,24 +421,23 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U */ if((access&MAP_READ_WRITE_FLAGS)) { - if (UNLIKELY(static_cast(SrcType) != static_cast(DstType))) - SETERR_RETURN(context, AL_INVALID_VALUE, , - "%s samples cannot be mapped", - NameFromUserFmtType(SrcType)); + if UNLIKELY(static_cast(SrcType) != static_cast(DstType)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "%s samples cannot be mapped", + NameFromUserFmtType(SrcType)); } const ALsizei unpackalign{ALBuf->UnpackAlign.load()}; const ALsizei align{SanitizeAlignment(SrcType, unpackalign)}; - if(UNLIKELY(align < 1)) + if UNLIKELY(align < 1) SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid unpack alignment %d for %s samples", - unpackalign, NameFromUserFmtType(SrcType)); + unpackalign, NameFromUserFmtType(SrcType)); if((access&AL_PRESERVE_DATA_BIT_SOFT)) { /* Can only preserve data with the same format and alignment. */ - if(UNLIKELY(ALBuf->mFmtChannels != DstChannels || ALBuf->OriginalType != SrcType)) + if UNLIKELY(ALBuf->mFmtChannels != DstChannels || ALBuf->OriginalType != SrcType) SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched format"); - if(UNLIKELY(ALBuf->OriginalAlign != align)) + if UNLIKELY(ALBuf->OriginalAlign != align) SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched alignment"); } @@ -451,12 +449,12 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U (SrcType == UserFmtMSADPCM) ? ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels) : (align * FrameSizeFromUserFmt(SrcChannels, SrcType)) }; - if(UNLIKELY((size%SrcByteAlign) != 0)) + if UNLIKELY((size%SrcByteAlign) != 0) SETERR_RETURN(context, AL_INVALID_VALUE,, "Data size %d is not a multiple of frame size %d (%d unpack alignment)", size, SrcByteAlign, align); - if(UNLIKELY(size/SrcByteAlign > std::numeric_limits::max()/align)) + if UNLIKELY(size/SrcByteAlign > std::numeric_limits::max()/align) SETERR_RETURN(context, AL_OUT_OF_MEMORY,, "Buffer size overflow, %d blocks x %d samples per block", size/SrcByteAlign, align); const auto frames = static_cast(size / SrcByteAlign * align); @@ -466,7 +464,7 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U */ ALsizei NumChannels{ChannelsFromFmt(DstChannels)}; ALsizei FrameSize{NumChannels * BytesFromFmt(DstType)}; - if(UNLIKELY(frames > std::numeric_limits::max()/FrameSize)) + if UNLIKELY(frames > std::numeric_limits::max()/FrameSize) SETERR_RETURN(context, AL_OUT_OF_MEMORY,, "Buffer size overflow, %d frames x %d bytes per frame", frames, FrameSize); size_t newsize{static_cast(frames) * FrameSize}; @@ -606,21 +604,19 @@ AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; - if(UNLIKELY(n < 0)) - { + if UNLIKELY(n < 0) context->setError(AL_INVALID_VALUE, "Generating %d buffers", n); - return; - } + if UNLIKELY(n <= 0) return; - if(LIKELY(n == 1)) + if LIKELY(n == 1) { /* Special handling for the easy and normal case. */ ALbuffer *buffer = AllocBuffer(context.get()); if(buffer) buffers[0] = buffer->id; } - else if(n > 1) + else { /* Store the allocated buffer IDs in a separate local list, to avoid * modifying the user storage in case of failure. @@ -646,15 +642,11 @@ AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; - if(UNLIKELY(n < 0)) - { + if UNLIKELY(n < 0) context->setError(AL_INVALID_VALUE, "Deleting %d buffers", n); - return; - } - if(UNLIKELY(n == 0)) - return; + if UNLIKELY(n <= 0) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; @@ -666,12 +658,12 @@ START_API_FUNC { if(!bid) return false; ALbuffer *ALBuf = LookupBuffer(device, bid); - if(UNLIKELY(!ALBuf)) + if UNLIKELY(!ALBuf) { context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", bid); return true; } - if(UNLIKELY(ReadRef(ALBuf->ref) != 0)) + if UNLIKELY(ReadRef(ALBuf->ref) != 0) { context->setError(AL_INVALID_OPERATION, "Deleting in-use buffer %u", bid); return true; @@ -679,7 +671,7 @@ START_API_FUNC return false; } ); - if(LIKELY(invbuf == buffers_end)) + if LIKELY(invbuf == buffers_end) { /* All good. Delete non-0 buffer IDs. */ std::for_each(buffers, buffers_end, @@ -697,7 +689,7 @@ AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer) START_API_FUNC { ContextRef context{GetContextRef()}; - if(LIKELY(context)) + if LIKELY(context) { ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; @@ -718,28 +710,28 @@ AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) + if UNLIKELY(!albuf) context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(size < 0)) + else if UNLIKELY(size < 0) context->setError(AL_INVALID_VALUE, "Negative storage size %d", size); - else if(UNLIKELY(freq < 1)) + else if UNLIKELY(freq < 1) context->setError(AL_INVALID_VALUE, "Invalid sample rate %d", freq); - else if(UNLIKELY((flags&INVALID_STORAGE_MASK) != 0)) + else if UNLIKELY((flags&INVALID_STORAGE_MASK) != 0) context->setError(AL_INVALID_VALUE, "Invalid storage flags 0x%x", flags&INVALID_STORAGE_MASK); - else if(UNLIKELY((flags&AL_MAP_PERSISTENT_BIT_SOFT) && !(flags&MAP_READ_WRITE_FLAGS))) + else if UNLIKELY((flags&AL_MAP_PERSISTENT_BIT_SOFT) && !(flags&MAP_READ_WRITE_FLAGS)) context->setError(AL_INVALID_VALUE, "Declaring persistently mapped storage without read or write access"); else { auto usrfmt = DecomposeUserFormat(format); - if(UNLIKELY(!usrfmt)) + if UNLIKELY(!usrfmt) context->setError(AL_INVALID_ENUM, "Invalid format 0x%04x", format); else LoadData(context.get(), albuf, freq, size, usrfmt->channels, usrfmt->type, @@ -752,38 +744,38 @@ AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return nullptr; + if UNLIKELY(!context) return nullptr; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) + if UNLIKELY(!albuf) context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY((access&INVALID_MAP_FLAGS) != 0)) + else if UNLIKELY((access&INVALID_MAP_FLAGS) != 0) context->setError(AL_INVALID_VALUE, "Invalid map flags 0x%x", access&INVALID_MAP_FLAGS); - else if(UNLIKELY(!(access&MAP_READ_WRITE_FLAGS))) + else if UNLIKELY(!(access&MAP_READ_WRITE_FLAGS)) context->setError(AL_INVALID_VALUE, "Mapping buffer %u without read or write access", buffer); else { ALbitfieldSOFT unavailable = (albuf->Access^access) & access; - if(UNLIKELY(ReadRef(albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT))) + if UNLIKELY(ReadRef(albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT)) context->setError(AL_INVALID_OPERATION, "Mapping in-use buffer %u without persistent mapping", buffer); - else if(UNLIKELY(albuf->MappedAccess != 0)) + else if UNLIKELY(albuf->MappedAccess != 0) context->setError(AL_INVALID_OPERATION, "Mapping already-mapped buffer %u", buffer); - else if(UNLIKELY((unavailable&AL_MAP_READ_BIT_SOFT))) + else if UNLIKELY((unavailable&AL_MAP_READ_BIT_SOFT)) context->setError(AL_INVALID_VALUE, "Mapping buffer %u for reading without read access", buffer); - else if(UNLIKELY((unavailable&AL_MAP_WRITE_BIT_SOFT))) + else if UNLIKELY((unavailable&AL_MAP_WRITE_BIT_SOFT)) context->setError(AL_INVALID_VALUE, "Mapping buffer %u for writing without write access", buffer); - else if(UNLIKELY((unavailable&AL_MAP_PERSISTENT_BIT_SOFT))) + else if UNLIKELY((unavailable&AL_MAP_PERSISTENT_BIT_SOFT)) context->setError(AL_INVALID_VALUE, "Mapping buffer %u persistently without persistent access", buffer); - else if(UNLIKELY(offset < 0 || offset >= albuf->OriginalSize || - length <= 0 || length > albuf->OriginalSize - offset)) + else if UNLIKELY(offset < 0 || offset >= albuf->OriginalSize || + length <= 0 || length > albuf->OriginalSize - offset) context->setError(AL_INVALID_VALUE, "Mapping invalid range %d+%d for buffer %u", offset, length, buffer); else @@ -804,15 +796,15 @@ AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) + if UNLIKELY(!albuf) context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(albuf->MappedAccess == 0) + else if UNLIKELY(albuf->MappedAccess == 0) context->setError(AL_INVALID_OPERATION, "Unmapping unmapped buffer %u", buffer); else { @@ -827,20 +819,20 @@ AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, A START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) + if UNLIKELY(!albuf) context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT))) + else if UNLIKELY(!(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT)) context->setError(AL_INVALID_OPERATION, "Flushing buffer %u while not mapped for writing", buffer); - else if(UNLIKELY(offset < albuf->MappedOffset || + else if UNLIKELY(offset < albuf->MappedOffset || offset >= albuf->MappedOffset+albuf->MappedSize || - length <= 0 || length > albuf->MappedOffset+albuf->MappedSize-offset)) + length <= 0 || length > albuf->MappedOffset+albuf->MappedSize-offset) context->setError(AL_INVALID_VALUE, "Flushing invalid range %d+%d on buffer %u", offset, length, buffer); else @@ -859,20 +851,20 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) + if UNLIKELY(!albuf) { context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); return; } auto usrfmt = DecomposeUserFormat(format); - if(UNLIKELY(!usrfmt)) + if UNLIKELY(!usrfmt) { context->setError(AL_INVALID_ENUM, "Invalid format 0x%04x", format); return; @@ -880,16 +872,16 @@ START_API_FUNC ALsizei unpack_align{albuf->UnpackAlign.load()}; ALsizei align{SanitizeAlignment(usrfmt->type, unpack_align)}; - if(UNLIKELY(align < 1)) + if UNLIKELY(align < 1) context->setError(AL_INVALID_VALUE, "Invalid unpack alignment %d", unpack_align); - else if(UNLIKELY(long{usrfmt->channels} != long{albuf->mFmtChannels} || - usrfmt->type != albuf->OriginalType)) + else if UNLIKELY(long{usrfmt->channels} != long{albuf->mFmtChannels} || + usrfmt->type != albuf->OriginalType) context->setError(AL_INVALID_ENUM, "Unpacking data with mismatched format"); - else if(UNLIKELY(align != albuf->OriginalAlign)) + else if UNLIKELY(align != albuf->OriginalAlign) context->setError(AL_INVALID_VALUE, "Unpacking data with alignment %u does not match original alignment %u", align, albuf->OriginalAlign); - else if(UNLIKELY(albuf->MappedAccess != 0)) + else if UNLIKELY(albuf->MappedAccess != 0) context->setError(AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u", buffer); else { @@ -901,15 +893,15 @@ START_API_FUNC (align * frame_size) }; - if(UNLIKELY(offset < 0 || length < 0 || offset > albuf->OriginalSize || - length > albuf->OriginalSize-offset)) + if UNLIKELY(offset < 0 || length < 0 || offset > albuf->OriginalSize || + length > albuf->OriginalSize-offset) context->setError(AL_INVALID_VALUE, "Invalid data sub-range %d+%d on buffer %u", offset, length, buffer); - else if(UNLIKELY((offset%byte_align) != 0)) + else if UNLIKELY((offset%byte_align) != 0) context->setError(AL_INVALID_VALUE, "Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)", offset, byte_align, align); - else if(UNLIKELY((length%byte_align) != 0)) + else if UNLIKELY((length%byte_align) != 0) context->setError(AL_INVALID_VALUE, "Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)", length, byte_align, align); @@ -943,7 +935,7 @@ AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint /*buffer*/, ALuint /*samplera START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; context->setError(AL_INVALID_OPERATION, "alBufferSamplesSOFT not supported"); } @@ -954,7 +946,7 @@ AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint /*buffer*/, ALsizei /*offs START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; context->setError(AL_INVALID_OPERATION, "alBufferSubSamplesSOFT not supported"); } @@ -965,7 +957,7 @@ AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint /*buffer*/, ALsizei /*offs START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; context->setError(AL_INVALID_OPERATION, "alGetBufferSamplesSOFT not supported"); } @@ -975,7 +967,7 @@ AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum /*format*/) START_API_FUNC { ContextRef context{GetContextRef()}; - if(!context) return AL_FALSE; + if UNLIKELY(!context) return AL_FALSE; context->setError(AL_INVALID_OPERATION, "alIsBufferFormatSupportedSOFT not supported"); return AL_FALSE; @@ -987,12 +979,12 @@ AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat /*value*/ START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + if UNLIKELY(LookupBuffer(device, buffer) == nullptr) context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else switch(param) { @@ -1007,12 +999,12 @@ AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + if UNLIKELY(LookupBuffer(device, buffer) == nullptr) context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else switch(param) { @@ -1026,14 +1018,14 @@ AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *v START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + if UNLIKELY(LookupBuffer(device, buffer) == nullptr) context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!values)) + else if UNLIKELY(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { @@ -1048,25 +1040,25 @@ AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) + if UNLIKELY(!albuf) context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else switch(param) { case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: - if(UNLIKELY(value < 0)) + if UNLIKELY(value < 0) context->setError(AL_INVALID_VALUE, "Invalid unpack block alignment %d", value); else albuf->UnpackAlign.store(value); break; case AL_PACK_BLOCK_ALIGNMENT_SOFT: - if(UNLIKELY(value < 0)) + if UNLIKELY(value < 0) context->setError(AL_INVALID_VALUE, "Invalid pack block alignment %d", value); else albuf->PackAlign.store(value); @@ -1083,12 +1075,12 @@ AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + if UNLIKELY(LookupBuffer(device, buffer) == nullptr) context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else switch(param) { @@ -1113,24 +1105,24 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) + if UNLIKELY(!albuf) context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!values)) + else if UNLIKELY(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_LOOP_POINTS_SOFT: - if(UNLIKELY(ReadRef(albuf->ref) != 0)) + if UNLIKELY(ReadRef(albuf->ref) != 0) context->setError(AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points", buffer); - else if(UNLIKELY(values[0] < 0 || values[0] >= values[1] || - static_cast(values[1]) > albuf->SampleLen)) + else if UNLIKELY(values[0] < 0 || values[0] >= values[1] || + static_cast(values[1]) > albuf->SampleLen) context->setError(AL_INVALID_VALUE, "Invalid loop point range %d -> %d on buffer %u", values[0], values[1], buffer); else @@ -1151,15 +1143,15 @@ AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *val START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) + if UNLIKELY(!albuf) context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!value)) + else if UNLIKELY(!value) context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { @@ -1173,14 +1165,14 @@ AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *valu START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + if UNLIKELY(LookupBuffer(device, buffer) == nullptr) context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!value1 || !value2 || !value3)) + else if UNLIKELY(!value1 || !value2 || !value3) context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { @@ -1201,14 +1193,14 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + if UNLIKELY(LookupBuffer(device, buffer) == nullptr) context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!values)) + else if UNLIKELY(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { @@ -1223,14 +1215,14 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) + if UNLIKELY(!albuf) context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!value)) + else if UNLIKELY(!value) context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { @@ -1268,13 +1260,13 @@ AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1 START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; - if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + if UNLIKELY(LookupBuffer(device, buffer) == nullptr) context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!value1 || !value2 || !value3)) + else if UNLIKELY(!value1 || !value2 || !value3) context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { @@ -1303,14 +1295,14 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->BufferLock}; ALbuffer *albuf = LookupBuffer(device, buffer); - if(UNLIKELY(!albuf)) + if UNLIKELY(!albuf) context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", buffer); - else if(UNLIKELY(!values)) + else if UNLIKELY(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); else switch(param) { diff --git a/al/effect.cpp b/al/effect.cpp index 15200a88..e5571be0 100644 --- a/al/effect.cpp +++ b/al/effect.cpp @@ -148,7 +148,7 @@ ALeffect *AllocEffect(ALCcontext *context) auto lidx = static_cast(std::distance(device->EffectList.begin(), sublist)); ALeffect *effect{nullptr}; ALsizei slidx{0}; - if(LIKELY(sublist != device->EffectList.end())) + if LIKELY(sublist != device->EffectList.end()) { slidx = CTZ64(sublist->FreeMask); effect = sublist->Effects + slidx; @@ -158,7 +158,7 @@ ALeffect *AllocEffect(ALCcontext *context) /* Don't allocate so many list entries that the 32-bit ID could * overflow... */ - if(UNLIKELY(device->EffectList.size() >= 1<<25)) + if UNLIKELY(device->EffectList.size() >= 1<<25) { context->setError(AL_OUT_OF_MEMORY, "Too many effects allocated"); return nullptr; @@ -167,7 +167,7 @@ ALeffect *AllocEffect(ALCcontext *context) sublist = device->EffectList.end() - 1; sublist->FreeMask = ~0_u64; sublist->Effects = static_cast(al_calloc(16, sizeof(ALeffect)*64)); - if(UNLIKELY(!sublist->Effects)) + if UNLIKELY(!sublist->Effects) { device->EffectList.pop_back(); context->setError(AL_OUT_OF_MEMORY, "Failed to allocate effect batch"); @@ -205,10 +205,10 @@ inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; - if(UNLIKELY(lidx >= device->EffectList.size())) + if UNLIKELY(lidx >= device->EffectList.size()) return nullptr; EffectSubList &sublist = device->EffectList[lidx]; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + if UNLIKELY(sublist.FreeMask & (1_u64 << slidx)) return nullptr; return sublist.Effects + slidx; } @@ -219,21 +219,19 @@ AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; - if(UNLIKELY(n < 0)) - { + if UNLIKELY(n < 0) context->setError(AL_INVALID_VALUE, "Generating %d effects", n); - return; - } + if UNLIKELY(n <= 0) return; - if(LIKELY(n == 1)) + if LIKELY(n == 1) { /* Special handling for the easy and normal case. */ ALeffect *effect = AllocEffect(context.get()); if(effect) effects[0] = effect->id; } - else if(n > 1) + else { /* Store the allocated buffer IDs in a separate local list, to avoid * modifying the user storage in case of failure. @@ -259,15 +257,11 @@ AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; - if(UNLIKELY(n < 0)) - { + if UNLIKELY(n < 0) context->setError(AL_INVALID_VALUE, "Deleting %d effects", n); - return; - } - if(UNLIKELY(n == 0)) - return; + if UNLIKELY(n <= 0) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; @@ -279,7 +273,7 @@ START_API_FUNC { if(!eid) return false; ALeffect *effect{LookupEffect(device, eid)}; - if(UNLIKELY(!effect)) + if UNLIKELY(!effect) { context->setError(AL_INVALID_NAME, "Invalid effect ID %u", eid); return true; @@ -287,7 +281,7 @@ START_API_FUNC return false; } ); - if(LIKELY(inveffect == effects_end)) + if LIKELY(inveffect == effects_end) { /* All good. Delete non-0 effect IDs. */ std::for_each(effects, effects_end, @@ -305,7 +299,7 @@ AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect) START_API_FUNC { ContextRef context{GetContextRef()}; - if(LIKELY(context)) + if LIKELY(context) { ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; @@ -320,13 +314,13 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) + if UNLIKELY(!aleffect) context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect); else { @@ -370,13 +364,13 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) + if UNLIKELY(!aleffect) context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect); else { @@ -390,13 +384,13 @@ AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) + if UNLIKELY(!aleffect) context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect); else { @@ -410,13 +404,13 @@ AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) + if UNLIKELY(!aleffect) context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect); else { @@ -430,13 +424,13 @@ AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; const ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) + if UNLIKELY(!aleffect) context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect); else { @@ -462,13 +456,13 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; const ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) + if UNLIKELY(!aleffect) context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect); else { @@ -482,13 +476,13 @@ AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *val START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; const ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) + if UNLIKELY(!aleffect) context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect); else { @@ -502,13 +496,13 @@ AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *va START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->EffectLock}; const ALeffect *aleffect{LookupEffect(device, effect)}; - if(UNLIKELY(!aleffect)) + if UNLIKELY(!aleffect) context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect); else { diff --git a/al/error.cpp b/al/error.cpp index 8bd78fe2..a7080493 100644 --- a/al/error.cpp +++ b/al/error.cpp @@ -94,7 +94,7 @@ AL_API ALenum AL_APIENTRY alGetError(void) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) + if UNLIKELY(!context) { constexpr ALenum deferror{AL_INVALID_OPERATION}; WARN("Querying error state on null context (implicitly 0x%04x)\n", deferror); diff --git a/al/event.cpp b/al/event.cpp index 06a2e008..530f9679 100644 --- a/al/event.cpp +++ b/al/event.cpp @@ -32,7 +32,7 @@ static int EventThread(ALCcontext *context) { RingBuffer *ring{context->mAsyncEvents.get()}; bool quitnow{false}; - while(LIKELY(!quitnow)) + while LIKELY(!quitnow) { auto evt_data = ring->getReadVector().first; if(evt_data.len == 0) @@ -60,7 +60,7 @@ static int EventThread(ALCcontext *context) } _{evt, ring}; quitnow = evt.EnumType == EventType_KillThread; - if(UNLIKELY(quitnow)) break; + if UNLIKELY(quitnow) break; if(evt.EnumType == EventType_ReleaseEffectState) { @@ -141,10 +141,10 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; - if(count < 0) SETERR_RETURN(context, AL_INVALID_VALUE,, "Controlling %d events", count); - if(count == 0) return; + if(count < 0) context->setError(AL_INVALID_VALUE, "Controlling %d events", count); + if(count <= 0) return; if(!types) SETERR_RETURN(context, AL_INVALID_VALUE,, "NULL pointer"); ALbitfieldSOFT flags{0}; @@ -202,7 +202,7 @@ AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *user START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; std::lock_guard __{context->mEventCbLock}; diff --git a/al/extension.cpp b/al/extension.cpp index 1b36e3db..ab759262 100644 --- a/al/extension.cpp +++ b/al/extension.cpp @@ -36,7 +36,7 @@ AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return AL_FALSE; + if UNLIKELY(!context) return AL_FALSE; if(!extName) SETERR_RETURN(context, AL_INVALID_VALUE, AL_FALSE, "NULL pointer"); diff --git a/al/filter.cpp b/al/filter.cpp index b52267f1..41a96513 100644 --- a/al/filter.cpp +++ b/al/filter.cpp @@ -288,7 +288,7 @@ ALfilter *AllocFilter(ALCcontext *context) auto lidx = static_cast(std::distance(device->FilterList.begin(), sublist)); ALfilter *filter{nullptr}; ALsizei slidx{0}; - if(LIKELY(sublist != device->FilterList.end())) + if LIKELY(sublist != device->FilterList.end()) { slidx = CTZ64(sublist->FreeMask); filter = sublist->Filters + slidx; @@ -298,7 +298,7 @@ ALfilter *AllocFilter(ALCcontext *context) /* Don't allocate so many list entries that the 32-bit ID could * overflow... */ - if(UNLIKELY(device->FilterList.size() >= 1<<25)) + if UNLIKELY(device->FilterList.size() >= 1<<25) { context->setError(AL_OUT_OF_MEMORY, "Too many filters allocated"); return nullptr; @@ -307,7 +307,7 @@ ALfilter *AllocFilter(ALCcontext *context) sublist = device->FilterList.end() - 1; sublist->FreeMask = ~0_u64; sublist->Filters = static_cast(al_calloc(16, sizeof(ALfilter)*64)); - if(UNLIKELY(!sublist->Filters)) + if UNLIKELY(!sublist->Filters) { device->FilterList.pop_back(); context->setError(AL_OUT_OF_MEMORY, "Failed to allocate filter batch"); @@ -346,10 +346,10 @@ inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; - if(UNLIKELY(lidx >= device->FilterList.size())) + if UNLIKELY(lidx >= device->FilterList.size()) return nullptr; FilterSubList &sublist = device->FilterList[lidx]; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + if UNLIKELY(sublist.FreeMask & (1_u64 << slidx)) return nullptr; return sublist.Filters + slidx; } @@ -360,21 +360,19 @@ AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; - if(UNLIKELY(n < 0)) - { + if UNLIKELY(n < 0) context->setError(AL_INVALID_VALUE, "Generating %d filters", n); - return; - } + if UNLIKELY(n <= 0) return; - if(LIKELY(n == 1)) + if LIKELY(n == 1) { /* Special handling for the easy and normal case. */ ALfilter *filter = AllocFilter(context.get()); if(filter) filters[0] = filter->id; } - else if(n > 1) + else { /* Store the allocated buffer IDs in a separate local list, to avoid * modifying the user storage in case of failure. @@ -400,15 +398,11 @@ AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; - if(UNLIKELY(n < 0)) - { + if UNLIKELY(n < 0) context->setError(AL_INVALID_VALUE, "Deleting %d filters", n); - return; - } - if(UNLIKELY(n == 0)) - return; + if UNLIKELY(n <= 0) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; @@ -420,7 +414,7 @@ START_API_FUNC { if(!fid) return false; ALfilter *filter{LookupFilter(device, fid)}; - if(UNLIKELY(!filter)) + if UNLIKELY(!filter) { context->setError(AL_INVALID_NAME, "Invalid filter ID %u", fid); return true; @@ -428,7 +422,7 @@ START_API_FUNC return false; } ); - if(LIKELY(invflt == filters_end)) + if LIKELY(invflt == filters_end) { /* All good. Delete non-0 filter IDs. */ std::for_each(filters, filters_end, @@ -446,7 +440,7 @@ AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter) START_API_FUNC { ContextRef context{GetContextRef()}; - if(LIKELY(context)) + if LIKELY(context) { ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; @@ -462,13 +456,13 @@ AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) + if UNLIKELY(!alfilt) context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter); else { @@ -500,13 +494,13 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) + if UNLIKELY(!alfilt) context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter); else { @@ -520,13 +514,13 @@ AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) + if UNLIKELY(!alfilt) context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter); else { @@ -540,13 +534,13 @@ AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) + if UNLIKELY(!alfilt) context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter); else { @@ -560,13 +554,13 @@ AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) + if UNLIKELY(!alfilt) context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter); else { @@ -592,13 +586,13 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) + if UNLIKELY(!alfilt) context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter); else { @@ -612,13 +606,13 @@ AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *val START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) + if UNLIKELY(!alfilt) context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter); else { @@ -632,13 +626,13 @@ AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *va START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALCdevice *device{context->mDevice.get()}; std::lock_guard _{device->FilterLock}; ALfilter *alfilt{LookupFilter(device, filter)}; - if(UNLIKELY(!alfilt)) + if UNLIKELY(!alfilt) context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter); else { diff --git a/al/listener.cpp b/al/listener.cpp index 3a1f32a4..aebf2aa5 100644 --- a/al/listener.cpp +++ b/al/listener.cpp @@ -46,7 +46,7 @@ AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALlistener &listener = context->mListener; std::lock_guard _{context->mPropLock}; @@ -79,7 +79,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALlistener &listener = context->mListener; std::lock_guard _{context->mPropLock}; @@ -129,7 +129,7 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALlistener &listener = context->mListener; std::lock_guard _{context->mPropLock}; @@ -161,7 +161,7 @@ AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint /*value*/) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; switch(param) @@ -184,7 +184,7 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; switch(param) @@ -221,7 +221,7 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; if(!values) @@ -239,7 +239,7 @@ AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALlistener &listener = context->mListener; std::lock_guard _{context->mPropLock}; @@ -265,7 +265,7 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALlistener &listener = context->mListener; std::lock_guard _{context->mPropLock}; @@ -308,7 +308,7 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALlistener &listener = context->mListener; std::lock_guard _{context->mPropLock}; @@ -337,7 +337,7 @@ AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; if(!value) @@ -354,7 +354,7 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALlistener &listener = context->mListener; std::lock_guard _{context->mPropLock}; @@ -392,7 +392,7 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; ALlistener &listener = context->mListener; std::lock_guard _{context->mPropLock}; diff --git a/al/source.cpp b/al/source.cpp index 69bdf6b5..9273a7a8 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -497,7 +497,7 @@ ALsource *AllocSource(ALCcontext *context) auto lidx = static_cast(std::distance(context->mSourceList.begin(), sublist)); ALsource *source; ALsizei slidx; - if(LIKELY(sublist != context->mSourceList.end())) + if LIKELY(sublist != context->mSourceList.end()) { slidx = CTZ64(sublist->FreeMask); source = sublist->Sources + slidx; @@ -507,7 +507,7 @@ ALsource *AllocSource(ALCcontext *context) /* Don't allocate so many list entries that the 32-bit ID could * overflow... */ - if(UNLIKELY(context->mSourceList.size() >= 1<<25)) + if UNLIKELY(context->mSourceList.size() >= 1<<25) { context->setError(AL_OUT_OF_MEMORY, "Too many sources allocated"); return nullptr; @@ -517,7 +517,7 @@ ALsource *AllocSource(ALCcontext *context) sublist->FreeMask = ~0_u64; sublist->Sources = static_cast(al_calloc(16, sizeof(ALsource)*64)); - if(UNLIKELY(!sublist->Sources)) + if UNLIKELY(!sublist->Sources) { context->mSourceList.pop_back(); context->setError(AL_OUT_OF_MEMORY, "Failed to allocate source batch"); @@ -574,10 +574,10 @@ inline ALsource *LookupSource(ALCcontext *context, ALuint id) noexcept ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; - if(UNLIKELY(lidx >= context->mSourceList.size())) + if UNLIKELY(lidx >= context->mSourceList.size()) return nullptr; SourceSubList &sublist{context->mSourceList[lidx]}; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + if UNLIKELY(sublist.FreeMask & (1_u64 << slidx)) return nullptr; return sublist.Sources + slidx; } @@ -587,10 +587,10 @@ inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) noexcept ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; - if(UNLIKELY(lidx >= device->BufferList.size())) + if UNLIKELY(lidx >= device->BufferList.size()) return nullptr; BufferSubList &sublist = device->BufferList[lidx]; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + if UNLIKELY(sublist.FreeMask & (1_u64 << slidx)) return nullptr; return sublist.Buffers + slidx; } @@ -600,10 +600,10 @@ inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) noexcept ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; - if(UNLIKELY(lidx >= device->FilterList.size())) + if UNLIKELY(lidx >= device->FilterList.size()) return nullptr; FilterSubList &sublist = device->FilterList[lidx]; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + if UNLIKELY(sublist.FreeMask & (1_u64 << slidx)) return nullptr; return sublist.Filters + slidx; } @@ -613,10 +613,10 @@ inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; - if(UNLIKELY(lidx >= context->mEffectSlotList.size())) + if UNLIKELY(lidx >= context->mEffectSlotList.size()) return nullptr; EffectSlotSubList &sublist{context->mEffectSlotList[lidx]}; - if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx))) + if UNLIKELY(sublist.FreeMask & (1_u64 << slidx)) return nullptr; return sublist.EffectSlots + slidx; } @@ -870,7 +870,7 @@ bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a bool SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span values); #define CHECKSIZE(v, s) do { \ - if(UNLIKELY((v).size() != INT_MAX && (v).size() != (s))) \ + if UNLIKELY((v).size() != INT_MAX && (v).size() != (s)) \ { \ Context->setError(AL_INVALID_ENUM, \ "Property 0x%04x expects %d value(s), got %zu", prop, (s), \ @@ -879,7 +879,7 @@ bool SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const } \ } while(0) #define CHECKVAL(x) do { \ - if(UNLIKELY(!(x))) \ + if UNLIKELY(!(x)) \ { \ Context->setError(AL_INVALID_VALUE, "Value out of range"); \ return false; \ @@ -2077,9 +2077,9 @@ AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; - if(n < 0) + if UNLIKELY(n < 0) context->setError(AL_INVALID_VALUE, "Generating %d sources", n); else if(n == 1) { @@ -2111,9 +2111,9 @@ AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; - if(n < 0) + if UNLIKELY(n < 0) SETERR_RETURN(context, AL_INVALID_VALUE,, "Deleting %d sources", n); std::lock_guard _{context->mSourceLock}; @@ -2131,7 +2131,7 @@ START_API_FUNC return true; } ); - if(LIKELY(invsrc == sources_end)) + if LIKELY(invsrc == sources_end) { /* All good. Delete source IDs. */ std::for_each(sources, sources_end, @@ -2149,7 +2149,7 @@ AL_API ALboolean AL_APIENTRY alIsSource(ALuint source) START_API_FUNC { ContextRef context{GetContextRef()}; - if(LIKELY(context)) + if LIKELY(context) { std::lock_guard _{context->mSourceLock}; if(LookupSource(context.get(), source) != nullptr) @@ -2164,12 +2164,12 @@ AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else SetSourcefv(Source, context.get(), static_cast(param), {&value, 1u}); @@ -2180,12 +2180,12 @@ AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1 START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else { @@ -2199,14 +2199,14 @@ AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) + else if UNLIKELY(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); else SetSourcefv(Source, context.get(), static_cast(param), {values, INT_MAX}); @@ -2218,17 +2218,17 @@ AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble va START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else { - const auto fval = static_cast(value); - SetSourcefv(Source, context.get(), static_cast(param), {&fval, 1u}); + const ALfloat fval[1]{static_cast(value)}; + SetSourcefv(Source, context.get(), static_cast(param), fval); } } END_API_FUNC @@ -2237,12 +2237,12 @@ AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble v START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else { @@ -2257,14 +2257,14 @@ AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdo START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) + else if UNLIKELY(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); else { @@ -2282,12 +2282,12 @@ AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else SetSourceiv(Source, context.get(), static_cast(param), {&value, 1u}); @@ -2298,12 +2298,12 @@ AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, AL START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else { @@ -2317,14 +2317,14 @@ AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *val START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; std::lock_guard __{context->mSourceLock}; ALsource *Source = LookupSource(context.get(), source); - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) + else if UNLIKELY(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); else SetSourceiv(Source, context.get(), static_cast(param), {values, INT_MAX}); @@ -2336,12 +2336,12 @@ AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SO START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; std::lock_guard __{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else SetSourcei64v(Source, context.get(), static_cast(param), {&value, 1u}); @@ -2352,12 +2352,12 @@ AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOF START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; std::lock_guard __{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); else { @@ -2371,14 +2371,14 @@ AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALin START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; std::lock_guard __{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) + else if UNLIKELY(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); else SetSourcei64v(Source, context.get(), static_cast(param), {values, INT_MAX}); @@ -2390,19 +2390,19 @@ AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *val START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) + else if UNLIKELY(!value) context->setError(AL_INVALID_VALUE, "NULL pointer"); else { - ALdouble dval; - if(GetSourcedv(Source, context.get(), static_cast(param), {&dval, 1u})) - *value = static_cast(dval); + ALdouble dval[1]; + if(GetSourcedv(Source, context.get(), static_cast(param), dval)) + *value = static_cast(dval[1]); } } END_API_FUNC @@ -2411,13 +2411,13 @@ AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *va START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) + else if UNLIKELY(!(value1 && value2 && value3)) context->setError(AL_INVALID_VALUE, "NULL pointer"); else { @@ -2436,13 +2436,13 @@ AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *va START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) + else if UNLIKELY(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); else { @@ -2462,13 +2462,13 @@ AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble * START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) + else if UNLIKELY(!value) context->setError(AL_INVALID_VALUE, "NULL pointer"); else GetSourcedv(Source, context.get(), static_cast(param), {value, 1u}); @@ -2479,13 +2479,13 @@ AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) + else if UNLIKELY(!(value1 && value2 && value3)) context->setError(AL_INVALID_VALUE, "NULL pointer"); else { @@ -2504,13 +2504,13 @@ AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) + else if UNLIKELY(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); else GetSourcedv(Source, context.get(), static_cast(param), {values, INT_MAX}); @@ -2522,13 +2522,13 @@ AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) + else if UNLIKELY(!value) context->setError(AL_INVALID_VALUE, "NULL pointer"); else GetSourceiv(Source, context.get(), static_cast(param), {value, 1u}); @@ -2539,13 +2539,13 @@ AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1 START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) + else if UNLIKELY(!(value1 && value2 && value3)) context->setError(AL_INVALID_VALUE, "NULL pointer"); else { @@ -2564,13 +2564,13 @@ AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) + else if UNLIKELY(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); else GetSourceiv(Source, context.get(), static_cast(param), {values, INT_MAX}); @@ -2582,13 +2582,13 @@ AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64S START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!value) + else if UNLIKELY(!value) context->setError(AL_INVALID_VALUE, "NULL pointer"); else GetSourcei64v(Source, context.get(), static_cast(param), {value, 1u}); @@ -2599,13 +2599,13 @@ AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64 START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!(value1 && value2 && value3)) + else if UNLIKELY(!(value1 && value2 && value3)) context->setError(AL_INVALID_VALUE, "NULL pointer"); else { @@ -2624,13 +2624,13 @@ AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64 START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mSourceLock}; ALsource *Source{LookupSource(context.get(), source)}; - if(UNLIKELY(!Source)) + if UNLIKELY(!Source) context->setError(AL_INVALID_NAME, "Invalid source ID %u", source); - else if(!values) + else if UNLIKELY(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); else GetSourcei64v(Source, context.get(), static_cast(param), {values, INT_MAX}); @@ -2647,16 +2647,16 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; - if(n < 0) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Playing %d sources", n); - if(n == 0) return; + if UNLIKELY(n < 0) + context->setError(AL_INVALID_VALUE, "Playing %d sources", n); + if UNLIKELY(n <= 0) return; al::vector extra_sources; std::array source_storage; ALsource **srchandles{source_storage.data()}; - if(UNLIKELY(static_cast(n) > source_storage.size())) + if UNLIKELY(static_cast(n) > source_storage.size()) { extra_sources.resize(n); srchandles = extra_sources.data(); @@ -2673,7 +2673,7 @@ START_API_FUNC ALCdevice *device{context->mDevice.get()}; BackendLockGuard __{*device->Backend}; /* If the device is disconnected, go right to stopped. */ - if(UNLIKELY(!device->Connected.load(std::memory_order_acquire))) + if UNLIKELY(!device->Connected.load(std::memory_order_acquire)) { /* TODO: Send state change event? */ std::for_each(srchandles, srchandles+n, @@ -2699,18 +2699,18 @@ START_API_FUNC return count; } ); - if(UNLIKELY(n > free_voices)) + if UNLIKELY(n > free_voices) { /* Increment the number of voices to handle the request. */ const ALuint need_voices{static_cast(n) - free_voices}; const size_t rem_voices{context->mVoices->size() - context->mVoiceCount.load(std::memory_order_relaxed)}; - if(UNLIKELY(need_voices > rem_voices)) + if UNLIKELY(need_voices > rem_voices) { /* Allocate more voices to get enough. */ const size_t alloc_count{need_voices - rem_voices}; - if(UNLIKELY(context->mVoices->size() > std::numeric_limits::max()-alloc_count)) + if UNLIKELY(context->mVoices->size() > std::numeric_limits::max()-alloc_count) SETERR_RETURN(context, AL_OUT_OF_MEMORY,, "Overflow increasing voice count to %zu + %zu", context->mVoices->size(), alloc_count); @@ -2732,7 +2732,7 @@ START_API_FUNC BufferList = BufferList->mNext.load(std::memory_order_relaxed); /* If there's nothing to play, go right to stopped. */ - if(UNLIKELY(!BufferList)) + if UNLIKELY(!BufferList) { /* NOTE: A source without any playable buffers should not have an * ALvoice since it shouldn't be in a playing or paused state. So @@ -2908,16 +2908,16 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; - if(n < 0) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Pausing %d sources", n); - if(n == 0) return; + if UNLIKELY(n < 0) + context->setError(AL_INVALID_VALUE, "Pausing %d sources", n); + if UNLIKELY(n <= 0) return; al::vector extra_sources; std::array source_storage; ALsource **srchandles{source_storage.data()}; - if(UNLIKELY(static_cast(n) > source_storage.size())) + if UNLIKELY(static_cast(n) > source_storage.size()) { extra_sources.resize(n); srchandles = extra_sources.data(); @@ -2963,16 +2963,16 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; - if(n < 0) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Stopping %d sources", n); - if(n == 0) return; + if UNLIKELY(n < 0) + context->setError(AL_INVALID_VALUE, "Stopping %d sources", n); + if UNLIKELY(n <= 0) return; al::vector extra_sources; std::array source_storage; ALsource **srchandles{source_storage.data()}; - if(UNLIKELY(static_cast(n) > source_storage.size())) + if UNLIKELY(static_cast(n) > source_storage.size()) { extra_sources.resize(n); srchandles = extra_sources.data(); @@ -3025,16 +3025,16 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; - if(n < 0) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Rewinding %d sources", n); - if(n == 0) return; + if UNLIKELY(n < 0) + context->setError(AL_INVALID_VALUE, "Rewinding %d sources", n); + if UNLIKELY(n <= 0) return; al::vector extra_sources; std::array source_storage; ALsource **srchandles{source_storage.data()}; - if(UNLIKELY(static_cast(n) > source_storage.size())) + if UNLIKELY(static_cast(n) > source_storage.size()) { extra_sources.resize(n); srchandles = extra_sources.data(); @@ -3081,19 +3081,19 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; - if(nb < 0) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Queueing %d buffers", nb); - if(nb == 0) return; + if UNLIKELY(nb < 0) + context->setError(AL_INVALID_VALUE, "Queueing %d buffers", nb); + if UNLIKELY(nb <= 0) return; std::lock_guard _{context->mSourceLock}; ALsource *source{LookupSource(context.get(),src)}; - if(UNLIKELY(!source)) + if UNLIKELY(!source) SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", src); /* Can't queue on a Static Source */ - if(UNLIKELY(source->SourceType == AL_STATIC)) + if UNLIKELY(source->SourceType == AL_STATIC) SETERR_RETURN(context, AL_INVALID_OPERATION,, "Queueing onto static source %u", src); /* Check for a valid Buffer, for its frequency and format */ @@ -3193,19 +3193,19 @@ AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, co START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; - if(nb < 0) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Queueing %d buffer layers", nb); - if(nb == 0) return; + if UNLIKELY(nb < 0) + context->setError(AL_INVALID_VALUE, "Queueing %d buffer layers", nb); + if UNLIKELY(nb <= 0) return; std::lock_guard _{context->mSourceLock}; ALsource *source{LookupSource(context.get(),src)}; - if(UNLIKELY(!source)) + if UNLIKELY(!source) SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", src); /* Can't queue on a Static Source */ - if(UNLIKELY(source->SourceType == AL_STATIC)) + if UNLIKELY(source->SourceType == AL_STATIC) SETERR_RETURN(context, AL_INVALID_OPERATION,, "Queueing onto static source %u", src); /* Check for a valid Buffer, for its frequency and format */ @@ -3296,20 +3296,20 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; - if(nb < 0) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Unqueueing %d buffers", nb); - if(nb == 0) return; + if UNLIKELY(nb < 0) + context->setError(AL_INVALID_VALUE, "Unqueueing %d buffers", nb); + if UNLIKELY(nb <= 0) return; std::lock_guard _{context->mSourceLock}; ALsource *source{LookupSource(context.get(),src)}; - if(UNLIKELY(!source)) + if UNLIKELY(!source) SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", src); - if(UNLIKELY(source->Looping)) + if UNLIKELY(source->Looping) SETERR_RETURN(context, AL_INVALID_VALUE,, "Unqueueing from looping source %u", src); - if(UNLIKELY(source->SourceType != AL_STREAMING)) + if UNLIKELY(source->SourceType != AL_STREAMING) SETERR_RETURN(context, AL_INVALID_VALUE,, "Unqueueing from a non-streaming source %u", src); @@ -3321,7 +3321,7 @@ START_API_FUNC Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); else if(source->state == AL_INITIAL) Current = BufferList; - if(UNLIKELY(BufferList == Current)) + if UNLIKELY(BufferList == Current) SETERR_RETURN(context, AL_INVALID_VALUE,, "Unqueueing pending buffers"); ALuint i{BufferList->mNumBuffers}; @@ -3331,7 +3331,7 @@ START_API_FUNC * trying to unqueue pending buffers. */ ALbufferlistitem *next{BufferList->mNext.load(std::memory_order_relaxed)}; - if(UNLIKELY(!next) || UNLIKELY(next == Current)) + if UNLIKELY(!next || next == Current) SETERR_RETURN(context, AL_INVALID_VALUE,, "Unqueueing pending buffers"); BufferList = next; diff --git a/al/state.cpp b/al/state.cpp index 3e8f4d18..b0338296 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -90,7 +90,7 @@ AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; switch(capability) @@ -110,7 +110,7 @@ AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; std::lock_guard _{context->mPropLock}; switch(capability) @@ -130,7 +130,7 @@ AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return AL_FALSE; + if UNLIKELY(!context) return AL_FALSE; std::lock_guard _{context->mPropLock}; ALboolean value{AL_FALSE}; @@ -152,7 +152,7 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return AL_FALSE; + if UNLIKELY(!context) return AL_FALSE; std::lock_guard _{context->mPropLock}; ALboolean value{AL_FALSE}; @@ -209,7 +209,7 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return 0.0; + if UNLIKELY(!context) return 0.0; std::lock_guard _{context->mPropLock}; ALdouble value{0.0}; @@ -260,7 +260,7 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return 0.0f; + if UNLIKELY(!context) return 0.0f; std::lock_guard _{context->mPropLock}; ALfloat value{0.0f}; @@ -311,7 +311,7 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return 0; + if UNLIKELY(!context) return 0; std::lock_guard _{context->mPropLock}; ALint value{0}; @@ -362,7 +362,7 @@ extern "C" AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return 0; + if UNLIKELY(!context) return 0_i64; std::lock_guard _{context->mPropLock}; ALint64SOFT value{0}; @@ -413,7 +413,7 @@ AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return nullptr; + if UNLIKELY(!context) return nullptr; std::lock_guard _{context->mPropLock}; void *value{nullptr}; @@ -456,7 +456,7 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; if(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); @@ -489,7 +489,7 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; if(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); @@ -522,7 +522,7 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; if(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); @@ -555,7 +555,7 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; if(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); @@ -588,7 +588,7 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; if(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); @@ -615,7 +615,7 @@ START_API_FUNC } ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; if(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); @@ -631,7 +631,7 @@ AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return nullptr; + if UNLIKELY(!context) return nullptr; const ALchar *value{nullptr}; switch(pname) @@ -687,7 +687,7 @@ AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; if(!(value >= 0.0f && std::isfinite(value))) context->setError(AL_INVALID_VALUE, "Doppler factor %f out of range", value); @@ -704,7 +704,7 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; if((context->mEnabledEvts.load(std::memory_order_relaxed)&EventType_Deprecated)) { @@ -733,7 +733,7 @@ AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; if(!(value > 0.0f && std::isfinite(value))) context->setError(AL_INVALID_VALUE, "Speed of sound %f out of range", value); @@ -750,7 +750,7 @@ AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; if(!(value == AL_INVERSE_DISTANCE || value == AL_INVERSE_DISTANCE_CLAMPED || value == AL_LINEAR_DISTANCE || value == AL_LINEAR_DISTANCE_CLAMPED || @@ -772,7 +772,7 @@ AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; context->deferUpdates(); } @@ -782,7 +782,7 @@ AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void) START_API_FUNC { ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return; + if UNLIKELY(!context) return; context->processUpdates(); } @@ -800,7 +800,7 @@ START_API_FUNC static_assert(al::size(ResamplerNames) == ResamplerMax+1, "Incorrect ResamplerNames list"); ContextRef context{GetContextRef()}; - if(UNLIKELY(!context)) return nullptr; + if UNLIKELY(!context) return nullptr; const ALchar *value{nullptr}; switch(pname) diff --git a/alc/alc.cpp b/alc/alc.cpp index 615fc154..f66654c2 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -4193,7 +4193,7 @@ START_API_FUNC device->Connected.store(true); ALCenum err{UpdateDeviceParams(dev.get(), attribs)}; - if(LIKELY(err == ALC_NO_ERROR)) return ALC_TRUE; + if LIKELY(err == ALC_NO_ERROR) return ALC_TRUE; alcSetError(dev.get(), err); if(err == ALC_INVALID_DEVICE) diff --git a/alc/alu.cpp b/alc/alu.cpp index 253dbe48..412bfffa 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -383,7 +383,7 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) */ RingBuffer *ring{context->mAsyncEvents.get()}; auto evt_vec = ring->getWriteVector(); - if(LIKELY(evt_vec.first.len > 0)) + if LIKELY(evt_vec.first.len > 0) { AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_ReleaseEffectState}}; evt->u.mEffectState = oldstate; @@ -1347,7 +1347,7 @@ void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray &slots, const al::span voices) { IncrementRef(ctx->mUpdateCount); - if(LIKELY(!ctx->mHoldUpdates.load(std::memory_order_acquire))) + if LIKELY(!ctx->mHoldUpdates.load(std::memory_order_acquire)) { bool cforce{CalcContextParams(ctx)}; bool force{CalcListenerParams(ctx) || cforce}; @@ -1463,7 +1463,7 @@ void ApplyStablizer(FrontStablizer *Stablizer, const al::span B auto &DelayBuf = Stablizer->DelayBuf[i]; auto buffer_end = Buffer[i].begin() + SamplesToDo; - if(LIKELY(SamplesToDo >= ALsizei{FrontStablizer::DelayLength})) + if LIKELY(SamplesToDo >= ALsizei{FrontStablizer::DelayLength}) { auto delay_end = std::rotate(Buffer[i].begin(), buffer_end - FrontStablizer::DelayLength, buffer_end); @@ -1556,7 +1556,7 @@ void ApplyDistanceComp(const al::span Samples, const ALsizei Sa ALfloat *inout{al::assume_aligned<16>(chanbuffer.data())}; auto inout_end = inout + SamplesToDo; - if(LIKELY(SamplesToDo >= base)) + if LIKELY(SamplesToDo >= base) { auto delay_end = std::rotate(inout, inout_end - base, inout_end); std::swap_ranges(inout, delay_end, distbuf); @@ -1690,7 +1690,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) /* Apply any needed post-process for finalizing the Dry mix to the * RealOut (Ambisonic decode, UHJ encode, etc). */ - if(LIKELY(device->PostProcess)) + if LIKELY(device->PostProcess) device->PostProcess(device, SamplesToDo); const al::span RealOut{device->RealOut.Buffer}; @@ -1718,7 +1718,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) if(device->DitherDepth > 0.0f) ApplyDither(RealOut, &device->DitherSeed, device->DitherDepth, SamplesToDo); - if(LIKELY(OutBuffer)) + if LIKELY(OutBuffer) { /* Finally, interleave and convert samples, writing to the device's * output buffer. diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index b34dc0cb..d9a7836e 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -136,7 +136,7 @@ const char *res_str(SLresult result) } #define PRINTERR(x, s) do { \ - if(UNLIKELY((x) != SL_RESULT_SUCCESS)) \ + if UNLIKELY((x) != SL_RESULT_SUCCESS) \ ERR("%s: %s\n", (s), res_str((x))); \ } while(0) diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index da209c8d..2ddcc86d 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -379,7 +379,7 @@ pa_context *connect_context(std::unique_lock &plock) if(!binname.fname.empty()) name = binname.fname.c_str(); - if(UNLIKELY(!pulse_mainloop)) + if UNLIKELY(!pulse_mainloop) { std::thread{pulse_mainloop_thread}.detach(); while(!pulse_mainloop) @@ -744,7 +744,7 @@ void PulsePlayback::streamWriteCallback(pa_stream *stream, size_t nbytes) aluMixData(mDevice, buf, nbytes/mFrameSize); int ret{pa_stream_write(stream, buf, nbytes, pa_xfree, 0, PA_SEEK_RELATIVE)}; - if(UNLIKELY(ret != PA_OK)) + if UNLIKELY(ret != PA_OK) ERR("Failed to write to stream: %d, %s\n", ret, pa_strerror(ret)); } @@ -1064,7 +1064,7 @@ ClockLatency PulsePlayback::getClockLatency() err = pa_stream_get_latency(mStream, &latency, &neg); } - if(UNLIKELY(err != 0)) + if UNLIKELY(err != 0) { /* 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 @@ -1075,7 +1075,7 @@ ClockLatency PulsePlayback::getClockLatency() latency = 0; neg = 0; } - else if(UNLIKELY(neg)) + else if UNLIKELY(neg) latency = 0; ret.Latency = std::chrono::microseconds{latency}; @@ -1328,24 +1328,24 @@ ALCenum PulseCapture::captureSamples(ALCvoid *buffer, ALCuint samples) { if(mCapBuffer.empty()) { - if(UNLIKELY(!mDevice->Connected.load(std::memory_order_acquire))) + if UNLIKELY(!mDevice->Connected.load(std::memory_order_acquire)) break; const pa_stream_state_t state{pa_stream_get_state(mStream)}; - if(UNLIKELY(!PA_STREAM_IS_GOOD(state))) + if UNLIKELY(!PA_STREAM_IS_GOOD(state)) { aluHandleDisconnect(mDevice, "Bad capture state: %u", state); break; } const void *capbuf; size_t caplen; - if(UNLIKELY(pa_stream_peek(mStream, &capbuf, &caplen) < 0)) + if UNLIKELY(pa_stream_peek(mStream, &capbuf, &caplen) < 0) { aluHandleDisconnect(mDevice, "Failed retrieving capture samples: %s", pa_strerror(pa_context_errno(mContext))); break; } if(caplen == 0) break; - if(UNLIKELY(!capbuf)) + if UNLIKELY(!capbuf) mCapLen = -static_cast(caplen); else mCapLen = static_cast(caplen); @@ -1353,7 +1353,7 @@ ALCenum PulseCapture::captureSamples(ALCvoid *buffer, ALCuint samples) } const size_t rem{minz(dstbuf.size(), mCapBuffer.size())}; - if(UNLIKELY(mCapLen < 0)) + if UNLIKELY(mCapLen < 0) std::fill_n(dstbuf.begin(), rem, mSilentVal); else std::copy_n(mCapBuffer.begin(), rem, dstbuf.begin()); @@ -1409,13 +1409,13 @@ ClockLatency PulseCapture::getClockLatency() err = pa_stream_get_latency(mStream, &latency, &neg); } - if(UNLIKELY(err != 0)) + if UNLIKELY(err != 0) { ERR("Failed to get stream latency: 0x%x\n", err); latency = 0; neg = 0; } - else if(UNLIKELY(neg)) + else if UNLIKELY(neg) latency = 0; ret.Latency = std::chrono::microseconds{latency}; diff --git a/alc/bformatdec.cpp b/alc/bformatdec.cpp index 6b20dd84..8319600e 100644 --- a/alc/bformatdec.cpp +++ b/alc/bformatdec.cpp @@ -160,7 +160,7 @@ void BFormatDec::process(const al::span OutBuffer, ALuint enabled{mEnabled}; for(FloatBufferLine &outbuf : OutBuffer) { - if(LIKELY(enabled&1)) + if LIKELY(enabled&1) { MixRowSamples(outbuf, (*mixmtx)[sHFBand], hfsamples, 0, SamplesToDo); MixRowSamples(outbuf, (*mixmtx)[sLFBand], lfsamples, 0, SamplesToDo); @@ -176,7 +176,7 @@ void BFormatDec::process(const al::span OutBuffer, ALuint enabled{mEnabled}; for(FloatBufferLine &outbuf : OutBuffer) { - if(LIKELY(enabled&1)) + if LIKELY(enabled&1) MixRowSamples(outbuf, *mixmtx, insamples, 0, SamplesToDo); ++mixmtx; enabled >>= 1; diff --git a/alc/effects/pshifter.cpp b/alc/effects/pshifter.cpp index a08052b9..819e510c 100644 --- a/alc/effects/pshifter.cpp +++ b/alc/effects/pshifter.cpp @@ -68,11 +68,11 @@ inline int double2int(double d) shift = ((conv.i64>>52)&0x7ff) - (1023+52); /* Over/underflow */ - if(UNLIKELY(shift >= 63 || shift < -52)) + if UNLIKELY(shift >= 63 || shift < -52) return 0; mant = (conv.i64&0xfffffffffffff_i64) | 0x10000000000000_i64; - if(LIKELY(shift < 0)) + if LIKELY(shift < 0) return (int)(mant >> -shift) * sign; return (int)(mant << shift) * sign; diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 51a57360..a8c4523e 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -1484,7 +1484,7 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST mDelay.write(offset, c, afmt[c].data()+base, todo); /* Process the samples for reverb. */ - if(UNLIKELY(fadeCount < FADE_SAMPLES)) + if UNLIKELY(fadeCount < FADE_SAMPLES) { auto fade = static_cast(fadeCount); diff --git a/alc/helpers.cpp b/alc/helpers.cpp index e86af6ce..7a547168 100644 --- a/alc/helpers.cpp +++ b/alc/helpers.cpp @@ -478,7 +478,7 @@ void al_print(FILE *logfile, const char *fmt, ...) va_start(args, fmt); va_copy(args2, args); int msglen{std::vsnprintf(str, sizeof(stcmsg), fmt, args)}; - if(UNLIKELY(msglen >= 0 && static_cast(msglen) >= sizeof(stcmsg))) + if UNLIKELY(msglen >= 0 && static_cast(msglen) >= sizeof(stcmsg)) { dynmsg.resize(static_cast(msglen) + 1u); str = dynmsg.data(); diff --git a/alc/logging.h b/alc/logging.h index 0bb0c87b..8a3e75e6 100644 --- a/alc/logging.h +++ b/alc/logging.h @@ -39,24 +39,24 @@ enum LogLevel { extern LogLevel gLogLevel; #define TRACEREF(...) do { \ - if(UNLIKELY(gLogLevel >= LogRef)) \ + if UNLIKELY(gLogLevel >= LogRef) \ AL_PRINT("(--)", __VA_ARGS__); \ } while(0) #define TRACE(...) do { \ - if(UNLIKELY(gLogLevel >= LogTrace)) \ + if UNLIKELY(gLogLevel >= LogTrace) \ AL_PRINT("(II)", __VA_ARGS__); \ LOG_ANDROID(ANDROID_LOG_DEBUG, __VA_ARGS__); \ } while(0) #define WARN(...) do { \ - if(UNLIKELY(gLogLevel >= LogWarning)) \ + if UNLIKELY(gLogLevel >= LogWarning) \ AL_PRINT("(WW)", __VA_ARGS__); \ LOG_ANDROID(ANDROID_LOG_WARN, __VA_ARGS__); \ } while(0) #define ERR(...) do { \ - if(UNLIKELY(gLogLevel >= LogError)) \ + if UNLIKELY(gLogLevel >= LogError) \ AL_PRINT("(EE)", __VA_ARGS__); \ LOG_ANDROID(ANDROID_LOG_ERROR, __VA_ARGS__); \ } while(0) diff --git a/alc/mastering.cpp b/alc/mastering.cpp index ec40001b..d4d87c25 100644 --- a/alc/mastering.cpp +++ b/alc/mastering.cpp @@ -314,7 +314,7 @@ void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, FloatBufferLine *O ALfloat *delaybuf{al::assume_aligned<16>(Comp->mDelay[c].data())}; auto inout_end = inout + SamplesToDo; - if(LIKELY(SamplesToDo >= lookAhead)) + if LIKELY(SamplesToDo >= lookAhead) { auto delay_end = std::rotate(inout, inout_end - lookAhead, inout_end); std::swap_ranges(inout, delay_end, delaybuf); diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index b4ca61d7..f43063ce 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -209,7 +209,7 @@ void Mix_(const ALfloat *data, const al::span OutBuffe const ALfloat step{diff * delta}; ALfloat step_count{0.0f}; /* Mix with applying gain steps in aligned multiples of 4. */ - if(LIKELY(minsize > 3)) + if LIKELY(minsize > 3) { const float32x4_t four4{vdupq_n_f32(4.0f)}; const float32x4_t step4{vdupq_n_f32(step)}; @@ -258,7 +258,7 @@ void Mix_(const ALfloat *data, const al::span OutBuffe if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; - if(LIKELY(BufferSize-pos > 3)) + if LIKELY(BufferSize-pos > 3) { ALsizei todo{(BufferSize-pos) >> 2}; const float32x4_t gain4 = vdupq_n_f32(gain); @@ -289,7 +289,7 @@ void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, continue; ALsizei pos{0}; - if(LIKELY(BufferSize > 3)) + if LIKELY(BufferSize > 3) { ALsizei todo{BufferSize >> 2}; float32x4_t gain4{vdupq_n_f32(gain)}; diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index b52ef256..cff37d2b 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -165,7 +165,7 @@ void Mix_(const ALfloat *data, const al::span OutBuffer const ALfloat step{diff * delta}; ALfloat step_count{0.0f}; /* Mix with applying gain steps in aligned multiples of 4. */ - if(LIKELY(minsize > 3)) + if LIKELY(minsize > 3) { const __m128 four4{_mm_set1_ps(4.0f)}; const __m128 step4{_mm_set1_ps(step)}; @@ -211,7 +211,7 @@ void Mix_(const ALfloat *data, const al::span OutBuffer if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; - if(LIKELY(BufferSize-pos > 3)) + if LIKELY(BufferSize-pos > 3) { ALsizei todo{(BufferSize-pos) >> 2}; const __m128 gain4{_mm_set1_ps(gain)}; @@ -242,7 +242,7 @@ void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, continue; ALsizei pos{0}; - if(LIKELY(BufferSize > 3)) + if LIKELY(BufferSize > 3) { ALsizei todo{BufferSize >> 2}; const __m128 gain4 = _mm_set1_ps(gain); diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 06324397..df955719 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -635,7 +635,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc SrcData.begin()); std::fill(srciter, SrcData.end(), 0.0f); - if(UNLIKELY(!BufferListItem)) + if UNLIKELY(!BufferListItem) srciter = std::copy(chandata.mPrevSamples.begin()+MAX_RESAMPLE_PADDING, chandata.mPrevSamples.end(), srciter); else if(isstatic) @@ -645,7 +645,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc srciter = LoadBufferQueue(BufferListItem, BufferLoopItem, NumChannels, SampleSize, chan, DataPosInt, {srciter, SrcData.end()}); - if(UNLIKELY(srciter != SrcData.end())) + if UNLIKELY(srciter != SrcData.end()) { /* If the source buffer wasn't filled, copy the last sample for * the remaining buffer. Ideally it should have ended with @@ -734,7 +734,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc * and new target gains given how much of the fade time * this mix handles. */ - if(LIKELY(Counter > fademix)) + if LIKELY(Counter > fademix) { const ALfloat a{static_cast(fademix) / static_cast(Counter)}; @@ -758,7 +758,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc parms.Hrtf.Old.Gain = TargetGain; } - if(LIKELY(fademix < DstBufferSize)) + if LIKELY(fademix < DstBufferSize) { const ALsizei todo{DstBufferSize - fademix}; ALfloat gain{TargetGain}; @@ -856,7 +856,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc OutPos += DstBufferSize; Counter = maxi(DstBufferSize, Counter) - DstBufferSize; - if(UNLIKELY(!BufferListItem)) + if UNLIKELY(!BufferListItem) { /* Do nothing extra when there's no buffers. */ } @@ -879,7 +879,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc /* Handle non-looping static source */ if(DataPosInt >= BufferListItem->mMaxSamples) { - if(LIKELY(vstate == ALvoice::Playing)) + if LIKELY(vstate == ALvoice::Playing) vstate = ALvoice::Stopped; BufferListItem = nullptr; break; @@ -898,7 +898,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc BufferListItem = BufferListItem->mNext.load(std::memory_order_relaxed); if(!BufferListItem && !(BufferListItem=BufferLoopItem)) { - if(LIKELY(vstate == ALvoice::Playing)) + if LIKELY(vstate == ALvoice::Playing) vstate = ALvoice::Stopped; break; } @@ -908,7 +908,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc voice->mFlags |= VOICE_IS_FADING; /* Don't update positions and buffers if we were stopping. */ - if(UNLIKELY(vstate == ALvoice::Stopping)) + if UNLIKELY(vstate == ALvoice::Stopping) { voice->mPlayState.store(ALvoice::Stopped, std::memory_order_release); return; diff --git a/common/alexcpt.cpp b/common/alexcpt.cpp index 9e04bbaf..5055e34f 100644 --- a/common/alexcpt.cpp +++ b/common/alexcpt.cpp @@ -17,7 +17,7 @@ backend_exception::backend_exception(ALCenum code, const char *msg, ...) : mErro va_start(args, msg); va_copy(args2, args); int msglen{std::vsnprintf(nullptr, 0, msg, args)}; - if(LIKELY(msglen > 0)) + if LIKELY(msglen > 0) { mMessage.resize(static_cast(msglen)+1); std::vsnprintf(&mMessage[0], mMessage.length(), msg, args2); diff --git a/common/alnumeric.h b/common/alnumeric.h index 950eebe1..7035715c 100644 --- a/common/alnumeric.h +++ b/common/alnumeric.h @@ -246,11 +246,11 @@ inline int float2int(float f) noexcept shift = ((conv.i>>23)&0xff) - (127+23); /* Over/underflow */ - if(UNLIKELY(shift >= 31 || shift < -23)) + if UNLIKELY(shift >= 31 || shift < -23) return 0; mant = (conv.i&0x7fffff) | 0x800000; - if(LIKELY(shift < 0)) + if LIKELY(shift < 0) return (mant >> -shift) * sign; return (mant << shift) * sign; @@ -293,7 +293,7 @@ inline float fast_roundf(float f) noexcept sign = (conv.i>>31)&0x01; expo = (conv.i>>23)&0xff; - if(UNLIKELY(expo >= 150/*+23*/)) + if UNLIKELY(expo >= 150/*+23*/) { /* An exponent (base-2) of 23 or higher is incapable of sub-integral * precision, so it's already an integral value. We don't need to worry diff --git a/common/intrusive_ptr.h b/common/intrusive_ptr.h index 831b8302..fa76ad48 100644 --- a/common/intrusive_ptr.h +++ b/common/intrusive_ptr.h @@ -16,7 +16,7 @@ public: unsigned int release() noexcept { auto ref = DecrementRef(mRef); - if(UNLIKELY(ref == 0)) + if UNLIKELY(ref == 0) delete static_cast(this); return ref; } diff --git a/common/opthelpers.h b/common/opthelpers.h index c83229f5..58578c15 100644 --- a/common/opthelpers.h +++ b/common/opthelpers.h @@ -12,9 +12,9 @@ * required to be true, but it can result in more optimal code for the true * path at the expense of a less optimal false path. */ -#define LIKELY(x) __builtin_expect(!!(x), !false) +#define LIKELY(x) (__builtin_expect(!!(x), !false)) /* The opposite of LIKELY, optimizing the case where the condition is false. */ -#define UNLIKELY(x) __builtin_expect(!!(x), false) +#define UNLIKELY(x) (__builtin_expect(!!(x), false)) /* Unlike LIKELY, ASSUME requires the condition to be true or else it invokes * undefined behavior. It's essentially an assert without actually checking the * condition at run-time, allowing for stronger optimizations than LIKELY. -- cgit v1.2.3 From 082622951d99edfe4bfbf66b7af05bf0e8a8f4f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 4 Aug 2019 17:29:55 -0700 Subject: Don't allow numeric values for the resampler option --- alc/mixvoice.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index df955719..8c54b706 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -195,14 +195,7 @@ void aluInitMixer() ResamplerDefault = FIR4Resampler; } else - { - char *end; - long n = strtol(str, &end, 0); - if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == FIR4Resampler)) - ResamplerDefault = static_cast(n); - else - WARN("Invalid resampler: %s\n", str); - } + ERR("Invalid resampler: %s\n", str); } MixHrtfBlendSamples = SelectHrtfBlendMixer(); -- cgit v1.2.3 From 3bc9490fd2861bdb28951bae5af37500e93de7ad Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 4 Aug 2019 17:45:46 -0700 Subject: Move some structs to where they're used --- al/buffer.h | 17 ----------------- alc/mixvoice.cpp | 57 ++++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/al/buffer.h b/al/buffer.h index e5149bb1..2c01aae2 100644 --- a/al/buffer.h +++ b/al/buffer.h @@ -63,23 +63,6 @@ enum FmtChannels : unsigned char { }; #define MAX_INPUT_CHANNELS (8) -/* DevFmtType traits, providing the type, etc given a DevFmtType. */ -template -struct FmtTypeTraits { }; - -template<> -struct FmtTypeTraits { using Type = ALubyte; }; -template<> -struct FmtTypeTraits { using Type = ALshort; }; -template<> -struct FmtTypeTraits { using Type = ALfloat; }; -template<> -struct FmtTypeTraits { using Type = ALdouble; }; -template<> -struct FmtTypeTraits { using Type = ALubyte; }; -template<> -struct FmtTypeTraits { using Type = ALubyte; }; - ALsizei BytesFromFmt(FmtType type); ALsizei ChannelsFromFmt(FmtChannels chans); diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 8c54b706..0c644344 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -281,6 +281,42 @@ constexpr ALshort aLawDecompressionTable[256] = { 944, 912, 1008, 976, 816, 784, 880, 848 }; +template +struct FmtTypeTraits { }; + +template<> +struct FmtTypeTraits { + using Type = ALubyte; + static constexpr ALfloat to_float(const Type val) { return (val-128) * (1.0f/128.0f); } +}; +template<> +struct FmtTypeTraits { + using Type = ALshort; + static constexpr ALfloat to_float(const Type val) { return val * (1.0f/32768.0f); } +}; +template<> +struct FmtTypeTraits { + using Type = ALfloat; + static constexpr ALfloat to_float(const Type val) { return val; } +}; +template<> +struct FmtTypeTraits { + using Type = ALdouble; + static constexpr ALfloat to_float(const Type val) { return static_cast(val); } +}; +template<> +struct FmtTypeTraits { + using Type = ALubyte; + static constexpr ALfloat to_float(const Type val) + { return muLawDecompressionTable[val] * (1.0f/32768.0f); } +}; +template<> +struct FmtTypeTraits { + using Type = ALubyte; + static constexpr ALfloat to_float(const Type val) + { return aLawDecompressionTable[val] * (1.0f/32768.0f); } +}; + void SendSourceStoppedEvent(ALCcontext *context, ALuint id) { @@ -328,25 +364,6 @@ const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, ALfloat } -/* Base template left undefined. Should be marked =delete, but Clang 3.8.1 - * chokes on that given the inline specializations. - */ -template -inline ALfloat LoadSample(typename FmtTypeTraits::Type val); - -template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) -{ return (val-128) * (1.0f/128.0f); } -template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) -{ return val * (1.0f/32768.0f); } -template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) -{ return val; } -template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) -{ return static_cast(val); } -template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) -{ return muLawDecompressionTable[val] * (1.0f/32768.0f); } -template<> inline ALfloat LoadSample(FmtTypeTraits::Type val) -{ return aLawDecompressionTable[val] * (1.0f/32768.0f); } - template inline void LoadSampleArray(ALfloat *RESTRICT dst, const al::byte *src, ALint srcstep, const ptrdiff_t samples) @@ -355,7 +372,7 @@ inline void LoadSampleArray(ALfloat *RESTRICT dst, const al::byte *src, ALint sr const SampleType *RESTRICT ssrc{reinterpret_cast(src)}; for(ALsizei i{0};i < samples;i++) - dst[i] += LoadSample(ssrc[i*srcstep]); + dst[i] += FmtTypeTraits::to_float(ssrc[i*srcstep]); } void LoadSamples(ALfloat *RESTRICT dst, const al::byte *src, ALint srcstep, FmtType srctype, -- cgit v1.2.3 From 3154a915b1f811416f3c29c6af0c0f13fc3acd3e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 5 Aug 2019 11:37:05 -0700 Subject: Remove the ReverbSpeedOfSound hack No other effect depends on context or listener properties, so reverb being the only exception for speed of sound and meters per unit was putting extra work on the effect engine for no real reason. Especially since the reverb decay time should be the time actual time to decay irrespective of other settings. --- al/listener.h | 1 - alc/alc.cpp | 2 - alc/alu.cpp | 134 ++++++++++++++++++++----------------------------- alc/alu.h | 1 - alc/effects/reverb.cpp | 9 ++-- 5 files changed, 59 insertions(+), 88 deletions(-) diff --git a/al/listener.h b/al/listener.h index a71db9f8..692880cd 100644 --- a/al/listener.h +++ b/al/listener.h @@ -44,7 +44,6 @@ struct ALlistener { ALfloat DopplerFactor; ALfloat SpeedOfSound; /* in units per sec! */ - ALfloat ReverbSpeedOfSound; /* in meters per sec! */ ALboolean SourceDistanceModel; DistanceModel mDistanceModel; diff --git a/alc/alc.cpp b/alc/alc.cpp index f66654c2..ca7ce4fb 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -2448,8 +2448,6 @@ void ALCcontext::init() mListener.Params.MetersPerUnit = mMetersPerUnit; mListener.Params.DopplerFactor = mDopplerFactor; mListener.Params.SpeedOfSound = mSpeedOfSound * mDopplerVelocity; - mListener.Params.ReverbSpeedOfSound = mListener.Params.SpeedOfSound * - mListener.Params.MetersPerUnit; mListener.Params.SourceDistanceModel = mSourceDistanceModel; mListener.Params.mDistanceModel = mDistanceModel; diff --git a/alc/alu.cpp b/alc/alu.cpp index 412bfffa..4044c712 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -102,15 +102,6 @@ ALfloat InitZScale() return ret; } -ALboolean InitReverbSOS() -{ - ALboolean ret{AL_FALSE}; - const char *str{getenv("__ALSOFT_REVERB_IGNORES_SOUND_SPEED")}; - if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) - ret = AL_TRUE; - return ret; -} - } // namespace /* Cone scalar */ @@ -119,9 +110,6 @@ const ALfloat ConeScale{InitConeScale()}; /* Localized Z scalar for mono sources */ const ALfloat ZScale{InitZScale()}; -/* Force default speed of sound for distance-related reverb decay. */ -const ALboolean OverrideReverbSpeedOfSound{InitReverbSOS()}; - namespace { @@ -287,9 +275,6 @@ bool CalcContextParams(ALCcontext *Context) Listener.Params.DopplerFactor = props->DopplerFactor; Listener.Params.SpeedOfSound = props->SpeedOfSound * props->DopplerVelocity; - if(!OverrideReverbSpeedOfSound) - Listener.Params.ReverbSpeedOfSound = Listener.Params.SpeedOfSound * - Listener.Params.MetersPerUnit; Listener.Params.SourceDistanceModel = props->SourceDistanceModel; Listener.Params.mDistanceModel = props->mDistanceModel; @@ -334,76 +319,68 @@ bool CalcListenerParams(ALCcontext *Context) return true; } -bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force) +bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context) { ALeffectslotProps *props{slot->Update.exchange(nullptr, std::memory_order_acq_rel)}; - if(!props && !force) return false; + if(!props) return false; - EffectState *state; - if(!props) - state = slot->Params.mEffectState; + slot->Params.Gain = props->Gain; + slot->Params.AuxSendAuto = props->AuxSendAuto; + slot->Params.Target = props->Target; + slot->Params.EffectType = props->Type; + slot->Params.mEffectProps = props->Props; + if(IsReverbEffect(props->Type)) + { + slot->Params.RoomRolloff = props->Props.Reverb.RoomRolloffFactor; + slot->Params.DecayTime = props->Props.Reverb.DecayTime; + slot->Params.DecayLFRatio = props->Props.Reverb.DecayLFRatio; + slot->Params.DecayHFRatio = props->Props.Reverb.DecayHFRatio; + slot->Params.DecayHFLimit = props->Props.Reverb.DecayHFLimit; + slot->Params.AirAbsorptionGainHF = props->Props.Reverb.AirAbsorptionGainHF; + } else { - slot->Params.Gain = props->Gain; - slot->Params.AuxSendAuto = props->AuxSendAuto; - slot->Params.Target = props->Target; - slot->Params.EffectType = props->Type; - slot->Params.mEffectProps = props->Props; - if(IsReverbEffect(props->Type)) + slot->Params.RoomRolloff = 0.0f; + slot->Params.DecayTime = 0.0f; + slot->Params.DecayLFRatio = 0.0f; + slot->Params.DecayHFRatio = 0.0f; + slot->Params.DecayHFLimit = AL_FALSE; + slot->Params.AirAbsorptionGainHF = 1.0f; + } + + EffectState *state{props->State}; + props->State = nullptr; + EffectState *oldstate{slot->Params.mEffectState}; + slot->Params.mEffectState = state; + + /* Only release the old state if it won't get deleted, since we can't be + * deleting/freeing anything in the mixer. + */ + if(!oldstate->releaseIfNoDelete()) + { + /* Otherwise, if it would be deleted send it off with a release event. */ + RingBuffer *ring{context->mAsyncEvents.get()}; + auto evt_vec = ring->getWriteVector(); + if LIKELY(evt_vec.first.len > 0) { - slot->Params.RoomRolloff = props->Props.Reverb.RoomRolloffFactor; - slot->Params.DecayTime = props->Props.Reverb.DecayTime; - slot->Params.DecayLFRatio = props->Props.Reverb.DecayLFRatio; - slot->Params.DecayHFRatio = props->Props.Reverb.DecayHFRatio; - slot->Params.DecayHFLimit = props->Props.Reverb.DecayHFLimit; - slot->Params.AirAbsorptionGainHF = props->Props.Reverb.AirAbsorptionGainHF; + AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_ReleaseEffectState}}; + evt->u.mEffectState = oldstate; + ring->writeAdvance(1); + context->mEventSem.post(); } else { - slot->Params.RoomRolloff = 0.0f; - slot->Params.DecayTime = 0.0f; - slot->Params.DecayLFRatio = 0.0f; - slot->Params.DecayHFRatio = 0.0f; - slot->Params.DecayHFLimit = AL_FALSE; - slot->Params.AirAbsorptionGainHF = 1.0f; - } - - state = props->State; - props->State = nullptr; - EffectState *oldstate{slot->Params.mEffectState}; - slot->Params.mEffectState = state; - - /* Only decrement the old state if it won't get deleted, since we can't - * be deleting/freeing anything in the mixer. - */ - if(!oldstate->releaseIfNoDelete()) - { - /* Otherwise, if it would be deleted, send it off with a release - * event. + /* If writing the event failed, the queue was probably full. Store + * the old state in the property object where it can eventually be + * cleaned up sometime later (not ideal, but better than blocking + * or leaking). */ - RingBuffer *ring{context->mAsyncEvents.get()}; - auto evt_vec = ring->getWriteVector(); - if LIKELY(evt_vec.first.len > 0) - { - AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_ReleaseEffectState}}; - evt->u.mEffectState = oldstate; - ring->writeAdvance(1); - context->mEventSem.post(); - } - else - { - /* If writing the event failed, the queue was probably full. - * Store the old state in the property object where it can - * eventually be cleaned up sometime later (not ideal, but - * better than blocking or leaking). - */ - props->State = oldstate; - } + props->State = oldstate; } - - AtomicReplaceHead(context->mFreeEffectslotProps, props); } + AtomicReplaceHead(context->mFreeEffectslotProps, props); + EffectTarget output; if(ALeffectslot *target{slot->Params.Target}) output = EffectTarget{&target->Wet, nullptr}; @@ -1034,8 +1011,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A /* Calculate the distances to where this effect's decay reaches * -60dB. */ - DecayDistance[i] = SendSlots[i]->Params.DecayTime * - Listener.Params.ReverbSpeedOfSound; + DecayDistance[i] = SendSlots[i]->Params.DecayTime * SPEEDOFSOUNDMETRESPERSEC; DecayLFDistance[i] = DecayDistance[i] * SendSlots[i]->Params.DecayLFRatio; DecayHFDistance[i] = DecayDistance[i] * SendSlots[i]->Params.DecayHFRatio; if(SendSlots[i]->Params.DecayHFLimit) @@ -1349,11 +1325,11 @@ void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray &slots, IncrementRef(ctx->mUpdateCount); if LIKELY(!ctx->mHoldUpdates.load(std::memory_order_acquire)) { - bool cforce{CalcContextParams(ctx)}; - bool force{CalcListenerParams(ctx) || cforce}; - force = std::accumulate(slots.begin(), slots.end(), force, - [ctx,cforce](bool force, ALeffectslot *slot) -> bool - { return CalcEffectSlotParams(slot, ctx, cforce) | force; } + bool force{CalcContextParams(ctx)}; + force |= CalcListenerParams(ctx); + force |= std::accumulate(slots.begin(), slots.end(), bool{false}, + [ctx](bool force, ALeffectslot *slot) -> bool + { return CalcEffectSlotParams(slot, ctx) | force; } ); std::for_each(voices.begin(), voices.end(), diff --git a/alc/alu.h b/alc/alu.h index d569c482..c795c777 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -461,6 +461,5 @@ extern RowMixerFunc MixRowSamples; extern const ALfloat ConeScale; extern const ALfloat ZScale; -extern const ALboolean OverrideReverbSpeedOfSound; #endif diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index a8c4523e..eb8db3d1 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -675,14 +675,15 @@ inline ALvoid CalcMatrixCoeffs(const ALfloat diffusion, ALfloat *x, ALfloat *y) * filters. */ ALfloat CalcLimitedHfRatio(const ALfloat hfRatio, const ALfloat airAbsorptionGainHF, - const ALfloat decayTime, const ALfloat SpeedOfSound) + const ALfloat decayTime) { /* Find the attenuation due to air absorption in dB (converting delay * time to meters using the speed of sound). Then reversing the decay * equation, solve for HF ratio. The delay length is cancelled out of * the equation, so it can be calculated once for all lines. */ - ALfloat limitRatio{1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) * SpeedOfSound)}; + ALfloat limitRatio{1.0f / + (CalcDecayLength(airAbsorptionGainHF, decayTime) * SPEEDOFSOUNDMETRESPERSEC)}; /* Using the limit calculated above, apply the upper bound to the HF ratio. */ @@ -906,7 +907,6 @@ void ReverbState::update3DPanning(const ALfloat *ReflectionsPan, const ALfloat * void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, const EffectProps *props, const EffectTarget target) { const ALCdevice *Device{Context->mDevice.get()}; - const ALlistener &Listener = Context->mListener; const auto frequency = static_cast(Device->Frequency); /* Calculate the master filters */ @@ -944,8 +944,7 @@ void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, co ALfloat hfRatio{props->Reverb.DecayHFRatio}; if(props->Reverb.DecayHFLimit && props->Reverb.AirAbsorptionGainHF < 1.0f) hfRatio = CalcLimitedHfRatio(hfRatio, props->Reverb.AirAbsorptionGainHF, - props->Reverb.DecayTime, Listener.Params.ReverbSpeedOfSound - ); + props->Reverb.DecayTime); /* Calculate the LF/HF decay times. */ const ALfloat lfDecayTime{clampf(props->Reverb.DecayTime * props->Reverb.DecayLFRatio, -- cgit v1.2.3 From d24401c3f3fbed3f0aa7fd5e4777e0d83797fa10 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 5 Aug 2019 12:15:14 -0700 Subject: Move the meters per unit property to the listener --- al/listener.cpp | 10 ++++------ al/listener.h | 3 +++ al/state.cpp | 2 -- alc/alc.cpp | 2 +- alc/alcontext.h | 2 -- alc/alu.cpp | 3 +-- 6 files changed, 9 insertions(+), 13 deletions(-) diff --git a/al/listener.cpp b/al/listener.cpp index aebf2aa5..d2fb8807 100644 --- a/al/listener.cpp +++ b/al/listener.cpp @@ -62,11 +62,8 @@ START_API_FUNC case AL_METERS_PER_UNIT: if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT)) SETERR_RETURN(context, AL_INVALID_VALUE,, "Listener meters per unit out of range"); - context->mMetersPerUnit = value; - if(!context->mDeferUpdates.load(std::memory_order_acquire)) - UpdateContextProps(context.get()); - else - context->mPropsClean.clear(std::memory_order_release); + listener.mMetersPerUnit = value; + DO_UPDATEPROPS(); break; default: @@ -252,7 +249,7 @@ START_API_FUNC break; case AL_METERS_PER_UNIT: - *value = context->mMetersPerUnit; + *value = listener.mMetersPerUnit; break; default: @@ -439,6 +436,7 @@ void UpdateListenerProps(ALCcontext *context) props->OrientAt = listener.OrientAt; props->OrientUp = listener.OrientUp; props->Gain = listener.Gain; + props->MetersPerUnit = listener.mMetersPerUnit; /* Set the new container for updating internal parameters. */ props = listener.Update.exchange(props, std::memory_order_acq_rel); diff --git a/al/listener.h b/al/listener.h index 692880cd..094e3067 100644 --- a/al/listener.h +++ b/al/listener.h @@ -6,6 +6,7 @@ #include "AL/al.h" #include "AL/alc.h" +#include "AL/alext.h" #include "vecmat.h" @@ -18,6 +19,7 @@ struct ALlistenerProps { std::array OrientAt; std::array OrientUp; ALfloat Gain; + ALfloat MetersPerUnit; std::atomic next; }; @@ -28,6 +30,7 @@ struct ALlistener { std::array OrientAt{{0.0f, 0.0f, -1.0f}}; std::array OrientUp{{0.0f, 1.0f, 0.0f}}; ALfloat Gain{1.0f}; + ALfloat mMetersPerUnit{AL_DEFAULT_METERS_PER_UNIT}; std::atomic_flag PropsClean; diff --git a/al/state.cpp b/al/state.cpp index b0338296..cbfd12fe 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -836,8 +836,6 @@ void UpdateContextProps(ALCcontext *context) } /* Copy in current property values. */ - props->MetersPerUnit = context->mMetersPerUnit; - props->DopplerFactor = context->mDopplerFactor; props->DopplerVelocity = context->mDopplerVelocity; props->SpeedOfSound = context->mSpeedOfSound; diff --git a/alc/alc.cpp b/alc/alc.cpp index ca7ce4fb..143c2e4e 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -2445,7 +2445,7 @@ void ALCcontext::init() mListener.Params.Matrix = alu::Matrix::Identity(); mListener.Params.Velocity = alu::Vector{}; mListener.Params.Gain = mListener.Gain; - mListener.Params.MetersPerUnit = mMetersPerUnit; + mListener.Params.MetersPerUnit = mListener.mMetersPerUnit; mListener.Params.DopplerFactor = mDopplerFactor; mListener.Params.SpeedOfSound = mSpeedOfSound * mDopplerVelocity; mListener.Params.SourceDistanceModel = mSourceDistanceModel; diff --git a/alc/alcontext.h b/alc/alcontext.h index 70215e9c..f30a4bd0 100644 --- a/alc/alcontext.h +++ b/alc/alcontext.h @@ -48,7 +48,6 @@ struct ALcontextProps { ALfloat SpeedOfSound; ALboolean SourceDistanceModel; DistanceModel mDistanceModel; - ALfloat MetersPerUnit; std::atomic next; }; @@ -102,7 +101,6 @@ struct ALCcontext : public al::intrusive_ref { ALfloat mDopplerFactor{1.0f}; ALfloat mDopplerVelocity{1.0f}; ALfloat mSpeedOfSound{SPEEDOFSOUNDMETRESPERSEC}; - ALfloat mMetersPerUnit{AL_DEFAULT_METERS_PER_UNIT}; std::atomic_flag mPropsClean; std::atomic mDeferUpdates{false}; diff --git a/alc/alu.cpp b/alc/alu.cpp index 4044c712..f2c843fe 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -271,8 +271,6 @@ bool CalcContextParams(ALCcontext *Context) if(!props) return false; ALlistener &Listener = Context->mListener; - Listener.Params.MetersPerUnit = props->MetersPerUnit; - Listener.Params.DopplerFactor = props->DopplerFactor; Listener.Params.SpeedOfSound = props->SpeedOfSound * props->DopplerVelocity; @@ -314,6 +312,7 @@ bool CalcListenerParams(ALCcontext *Context) Listener.Params.Velocity = Listener.Params.Matrix * vel; Listener.Params.Gain = props->Gain * Context->mGainBoost; + Listener.Params.MetersPerUnit = props->MetersPerUnit; AtomicReplaceHead(Context->mFreeListenerProps, props); return true; -- cgit v1.2.3 From e286ec8d09b8d0a1939bca9eaa196514347282b1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 5 Aug 2019 15:03:18 -0700 Subject: Move some declarations out of alcmain.h --- CMakeLists.txt | 2 + alc/alcmain.h | 122 +----------------------------------------------- alc/backends/opensl.cpp | 3 +- alc/backends/wave.cpp | 1 + alc/devformat.h | 120 +++++++++++++++++++++++++++++++++++++++++++++++ common/endiantest.h | 14 ++++++ 6 files changed, 140 insertions(+), 122 deletions(-) create mode 100644 alc/devformat.h create mode 100644 common/endiantest.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f3f9763..2fd0b69a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -598,6 +598,7 @@ SET(COMMON_OBJS common/aloptional.h common/alspan.h common/atomic.h + common/endiantest.h common/intrusive_ptr.h common/math_defs.h common/opthelpers.h @@ -637,6 +638,7 @@ SET(ALC_OBJS alc/bs2b.h alc/converter.cpp alc/converter.h + alc/devformat.h alc/inprogext.h alc/mastering.cpp alc/mastering.h diff --git a/alc/alcmain.h b/alc/alcmain.h index 5b4e4a2b..e7451ab0 100644 --- a/alc/alcmain.h +++ b/alc/alcmain.h @@ -22,6 +22,7 @@ #include "alspan.h" #include "ambidefs.h" #include "atomic.h" +#include "devformat.h" #include "hrtf.h" #include "inprogext.h" #include "intrusive_ptr.h" @@ -39,133 +40,12 @@ struct Uhj2Encoder; struct bs2b; -#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) -#define IS_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) -#else -static const union { - ALuint u; - ALubyte b[sizeof(ALuint)]; -} EndianTest = { 1 }; -#define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1) -#endif - - #define MIN_OUTPUT_RATE 8000 #define DEFAULT_OUTPUT_RATE 44100 #define DEFAULT_UPDATE_SIZE 882 /* 20ms */ #define DEFAULT_NUM_UPDATES 3 -enum Channel { - FrontLeft = 0, - FrontRight, - FrontCenter, - LFE, - BackLeft, - BackRight, - BackCenter, - SideLeft, - SideRight, - - UpperFrontLeft, - UpperFrontRight, - UpperBackLeft, - UpperBackRight, - LowerFrontLeft, - LowerFrontRight, - LowerBackLeft, - LowerBackRight, - - Aux0, - Aux1, - Aux2, - Aux3, - Aux4, - Aux5, - Aux6, - Aux7, - Aux8, - Aux9, - Aux10, - Aux11, - Aux12, - Aux13, - Aux14, - Aux15, - - MaxChannels -}; - - -/* Device formats */ -enum DevFmtType : ALenum { - DevFmtByte = ALC_BYTE_SOFT, - DevFmtUByte = ALC_UNSIGNED_BYTE_SOFT, - DevFmtShort = ALC_SHORT_SOFT, - DevFmtUShort = ALC_UNSIGNED_SHORT_SOFT, - DevFmtInt = ALC_INT_SOFT, - DevFmtUInt = ALC_UNSIGNED_INT_SOFT, - DevFmtFloat = ALC_FLOAT_SOFT, - - DevFmtTypeDefault = DevFmtFloat -}; -enum DevFmtChannels : ALenum { - DevFmtMono = ALC_MONO_SOFT, - DevFmtStereo = ALC_STEREO_SOFT, - DevFmtQuad = ALC_QUAD_SOFT, - DevFmtX51 = ALC_5POINT1_SOFT, - DevFmtX61 = ALC_6POINT1_SOFT, - DevFmtX71 = ALC_7POINT1_SOFT, - DevFmtAmbi3D = ALC_BFORMAT3D_SOFT, - - /* Similar to 5.1, except using rear channels instead of sides */ - DevFmtX51Rear = 0x70000000, - - DevFmtChannelsDefault = DevFmtStereo -}; -#define MAX_OUTPUT_CHANNELS (16) - -/* DevFmtType traits, providing the type, etc given a DevFmtType. */ -template -struct DevFmtTypeTraits { }; - -template<> -struct DevFmtTypeTraits { using Type = ALbyte; }; -template<> -struct DevFmtTypeTraits { using Type = ALubyte; }; -template<> -struct DevFmtTypeTraits { using Type = ALshort; }; -template<> -struct DevFmtTypeTraits { using Type = ALushort; }; -template<> -struct DevFmtTypeTraits { using Type = ALint; }; -template<> -struct DevFmtTypeTraits { using Type = ALuint; }; -template<> -struct DevFmtTypeTraits { using Type = ALfloat; }; - - -ALsizei BytesFromDevFmt(DevFmtType type) noexcept; -ALsizei ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept; -inline ALsizei FrameSizeFromDevFmt(DevFmtChannels chans, DevFmtType type, ALsizei ambiorder) noexcept -{ return ChannelsFromDevFmt(chans, ambiorder) * BytesFromDevFmt(type); } - -enum class AmbiLayout { - FuMa = ALC_FUMA_SOFT, /* FuMa channel order */ - ACN = ALC_ACN_SOFT, /* ACN channel order */ - - Default = ACN -}; - -enum class AmbiNorm { - FuMa = ALC_FUMA_SOFT, /* FuMa normalization */ - SN3D = ALC_SN3D_SOFT, /* SN3D normalization */ - N3D = ALC_N3D_SOFT, /* N3D normalization */ - - Default = SN3D -}; - - enum DeviceType { Playback, Capture, diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index d9a7836e..28305288 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -33,9 +33,10 @@ #include "alcmain.h" #include "alu.h" +#include "compat.h" +#include "endiantest.h" #include "ringbuffer.h" #include "threads.h" -#include "compat.h" #include #include diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp index 67ed7e79..6ca2fab4 100644 --- a/alc/backends/wave.cpp +++ b/alc/backends/wave.cpp @@ -41,6 +41,7 @@ #include "alnumeric.h" #include "alu.h" #include "compat.h" +#include "endiantest.h" #include "logging.h" #include "threads.h" #include "vector.h" diff --git a/alc/devformat.h b/alc/devformat.h new file mode 100644 index 00000000..95fe5fbd --- /dev/null +++ b/alc/devformat.h @@ -0,0 +1,120 @@ +#ifndef ALC_DEVFORMAT_H +#define ALC_DEVFORMAT_H + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" + +#include "inprogext.h" + + +enum Channel { + FrontLeft = 0, + FrontRight, + FrontCenter, + LFE, + BackLeft, + BackRight, + BackCenter, + SideLeft, + SideRight, + + UpperFrontLeft, + UpperFrontRight, + UpperBackLeft, + UpperBackRight, + LowerFrontLeft, + LowerFrontRight, + LowerBackLeft, + LowerBackRight, + + Aux0, + Aux1, + Aux2, + Aux3, + Aux4, + Aux5, + Aux6, + Aux7, + Aux8, + Aux9, + Aux10, + Aux11, + Aux12, + Aux13, + Aux14, + Aux15, + + MaxChannels +}; + + +/* Device formats */ +enum DevFmtType : ALenum { + DevFmtByte = ALC_BYTE_SOFT, + DevFmtUByte = ALC_UNSIGNED_BYTE_SOFT, + DevFmtShort = ALC_SHORT_SOFT, + DevFmtUShort = ALC_UNSIGNED_SHORT_SOFT, + DevFmtInt = ALC_INT_SOFT, + DevFmtUInt = ALC_UNSIGNED_INT_SOFT, + DevFmtFloat = ALC_FLOAT_SOFT, + + DevFmtTypeDefault = DevFmtFloat +}; +enum DevFmtChannels : ALenum { + DevFmtMono = ALC_MONO_SOFT, + DevFmtStereo = ALC_STEREO_SOFT, + DevFmtQuad = ALC_QUAD_SOFT, + DevFmtX51 = ALC_5POINT1_SOFT, + DevFmtX61 = ALC_6POINT1_SOFT, + DevFmtX71 = ALC_7POINT1_SOFT, + DevFmtAmbi3D = ALC_BFORMAT3D_SOFT, + + /* Similar to 5.1, except using rear channels instead of sides */ + DevFmtX51Rear = 0x70000000, + + DevFmtChannelsDefault = DevFmtStereo +}; +#define MAX_OUTPUT_CHANNELS (16) + +/* DevFmtType traits, providing the type, etc given a DevFmtType. */ +template +struct DevFmtTypeTraits { }; + +template<> +struct DevFmtTypeTraits { using Type = ALbyte; }; +template<> +struct DevFmtTypeTraits { using Type = ALubyte; }; +template<> +struct DevFmtTypeTraits { using Type = ALshort; }; +template<> +struct DevFmtTypeTraits { using Type = ALushort; }; +template<> +struct DevFmtTypeTraits { using Type = ALint; }; +template<> +struct DevFmtTypeTraits { using Type = ALuint; }; +template<> +struct DevFmtTypeTraits { using Type = ALfloat; }; + + +ALsizei BytesFromDevFmt(DevFmtType type) noexcept; +ALsizei ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept; +inline ALsizei FrameSizeFromDevFmt(DevFmtChannels chans, DevFmtType type, ALsizei ambiorder) noexcept +{ return ChannelsFromDevFmt(chans, ambiorder) * BytesFromDevFmt(type); } + +enum class AmbiLayout { + FuMa = ALC_FUMA_SOFT, /* FuMa channel order */ + ACN = ALC_ACN_SOFT, /* ACN channel order */ + + Default = ACN +}; + +enum class AmbiNorm { + FuMa = ALC_FUMA_SOFT, /* FuMa normalization */ + SN3D = ALC_SN3D_SOFT, /* SN3D normalization */ + N3D = ALC_N3D_SOFT, /* N3D normalization */ + + Default = SN3D +}; + +#endif /* ALC_DEVFORMAT_H */ diff --git a/common/endiantest.h b/common/endiantest.h new file mode 100644 index 00000000..0a20eb91 --- /dev/null +++ b/common/endiantest.h @@ -0,0 +1,14 @@ +#ifndef AL_ENDIANTEST_H +#define AL_ENDIANTEST_H + +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) +#define IS_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#else +static const union { + unsigned int u; + unsigned char b[sizeof(unsigned int)]; +} EndianTest = { 1 }; +#define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1) +#endif + +#endif /* AL_ENDIANTEST_H */ -- cgit v1.2.3 From d06afa7ca11e06186a62c9465ad099374a4514e7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 5 Aug 2019 15:11:03 -0700 Subject: Move a struct definition to where it's used --- alc/alcmain.h | 17 ++++++++++++++++- alc/filters/splitter.h | 18 ------------------ 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/alc/alcmain.h b/alc/alcmain.h index e7451ab0..464febcc 100644 --- a/alc/alcmain.h +++ b/alc/alcmain.h @@ -23,6 +23,7 @@ #include "ambidefs.h" #include "atomic.h" #include "devformat.h" +#include "filters/splitter.h" #include "hrtf.h" #include "inprogext.h" #include "intrusive_ptr.h" @@ -35,7 +36,6 @@ struct ALfilter; struct BackendBase; struct Compressor; struct EffectState; -struct FrontStablizer; struct Uhj2Encoder; struct bs2b; @@ -160,6 +160,21 @@ using FloatBufferLine = std::array; #define MAX_RESAMPLE_PADDING 24 +struct FrontStablizer { + static constexpr size_t DelayLength{256u}; + + alignas(16) float DelayBuf[MAX_OUTPUT_CHANNELS][DelayLength]; + + BandSplitter LFilter, RFilter; + alignas(16) float LSplit[2][BUFFERSIZE]; + alignas(16) float RSplit[2][BUFFERSIZE]; + + alignas(16) float TempBuf[BUFFERSIZE + DelayLength]; + + DEF_NEWDEL(FrontStablizer) +}; + + struct MixParams { /* Coefficient channel mapping for mixing to the buffer. */ std::array AmbiMap{}; diff --git a/alc/filters/splitter.h b/alc/filters/splitter.h index 52bda713..b024f0c3 100644 --- a/alc/filters/splitter.h +++ b/alc/filters/splitter.h @@ -3,9 +3,6 @@ #include -#include "alcmain.h" -#include "almalloc.h" - /* Band splitter. Splits a signal into two phase-matching frequency bands. */ template @@ -34,19 +31,4 @@ public: }; using BandSplitter = BandSplitterR; - -struct FrontStablizer { - static constexpr size_t DelayLength{256u}; - - alignas(16) float DelayBuf[MAX_OUTPUT_CHANNELS][DelayLength]; - - BandSplitter LFilter, RFilter; - alignas(16) float LSplit[2][BUFFERSIZE]; - alignas(16) float RSplit[2][BUFFERSIZE]; - - alignas(16) float TempBuf[BUFFERSIZE + DelayLength]; - - DEF_NEWDEL(FrontStablizer) -}; - #endif /* FILTER_SPLITTER_H */ -- cgit v1.2.3 From 80a85febcfb44369b7c84f4d64a7e53bf390f920 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 5 Aug 2019 18:36:39 -0700 Subject: Update some includes --- alc/alc.cpp | 1 + alc/alu.cpp | 2 +- alc/alu.h | 1 + alc/bformatdec.cpp | 2 ++ alc/bformatdec.h | 1 + alc/converter.cpp | 2 ++ alc/converter.h | 1 + alc/helpers.cpp | 6 ++++++ alc/hrtf.cpp | 3 +-- alc/mastering.cpp | 2 ++ alc/mixvoice.cpp | 2 +- alc/panning.cpp | 38 +++++++++++++++++++++++++------------- alc/uhjfilter.cpp | 2 ++ 13 files changed, 46 insertions(+), 17 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index 143c2e4e..a34a0824 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -73,6 +73,7 @@ #include "bs2b.h" #include "compat.h" #include "cpu_caps.h" +#include "devformat.h" #include "effects/base.h" #include "filters/nfc.h" #include "filters/splitter.h" diff --git a/alc/alu.cpp b/alc/alu.cpp index f2c843fe..b50927e2 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -60,6 +60,7 @@ #include "bformatdec.h" #include "bs2b.h" #include "cpu_caps.h" +#include "devformat.h" #include "effects/base.h" #include "filters/biquad.h" #include "filters/nfc.h" @@ -75,7 +76,6 @@ #include "threads.h" #include "uhjfilter.h" #include "vecmat.h" -#include "vector.h" #include "bsinc_inc.h" diff --git a/alc/alu.h b/alc/alu.h index c795c777..dd133f5a 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -15,6 +15,7 @@ #include "almalloc.h" #include "alspan.h" #include "ambidefs.h" +#include "devformat.h" #include "filters/biquad.h" #include "filters/nfc.h" #include "filters/splitter.h" diff --git a/alc/bformatdec.cpp b/alc/bformatdec.cpp index 8319600e..98ef58cb 100644 --- a/alc/bformatdec.cpp +++ b/alc/bformatdec.cpp @@ -10,6 +10,8 @@ #include #include +#include "AL/al.h" + #include "almalloc.h" #include "alu.h" #include "ambdec.h" diff --git a/alc/bformatdec.h b/alc/bformatdec.h index 06974651..6d0bf4e6 100644 --- a/alc/bformatdec.h +++ b/alc/bformatdec.h @@ -10,6 +10,7 @@ #include "almalloc.h" #include "alspan.h" #include "ambidefs.h" +#include "devformat.h" #include "filters/splitter.h" #include "vector.h" diff --git a/alc/converter.cpp b/alc/converter.cpp index 2e357fb8..1fa4a5d0 100644 --- a/alc/converter.cpp +++ b/alc/converter.cpp @@ -7,6 +7,8 @@ #include #include +#include "AL/al.h" + #include "albyte.h" #include "fpu_modes.h" #include "mixer/defs.h" diff --git a/alc/converter.h b/alc/converter.h index bc51e46a..9a3308b5 100644 --- a/alc/converter.h +++ b/alc/converter.h @@ -10,6 +10,7 @@ #include "almalloc.h" #include "alnumeric.h" #include "alu.h" +#include "devformat.h" struct SampleConverter { diff --git a/alc/helpers.cpp b/alc/helpers.cpp index 7a547168..2174de05 100644 --- a/alc/helpers.cpp +++ b/alc/helpers.cpp @@ -109,6 +109,7 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x #include "cpu_caps.h" #include "fpu_modes.h" #include "logging.h" +#include "vector.h" #if defined(HAVE_GCC_GET_CPUID) && (defined(__i386__) || defined(__x86_64__) || \ @@ -595,6 +596,11 @@ void SetRTPriority(void) #else +#if defined(HAVE_PTHREAD_SETSCHEDPARAM) && !defined(__OpenBSD__) +#include +#include +#endif + const PathNamePair &GetProcBinary() { static PathNamePair ret; diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index 590d102a..5446c412 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -1363,8 +1363,7 @@ HrtfEntry *GetLoadedHrtf(HrtfHandle *handle) return nullptr; } - TRACE("Loaded HRTF support for format: %s %uhz\n", - DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); + TRACE("Loaded HRTF support for sample rate: %uhz\n", hrtf->sampleRate); handle->entry = std::move(hrtf); return handle->entry.get(); diff --git a/alc/mastering.cpp b/alc/mastering.cpp index d4d87c25..fa767e83 100644 --- a/alc/mastering.cpp +++ b/alc/mastering.cpp @@ -11,6 +11,8 @@ #include #include +#include "AL/al.h" + #include "almalloc.h" #include "alnumeric.h" #include "alu.h" diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 0c644344..cf3eeb50 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -51,6 +50,7 @@ #include "alspan.h" #include "alu.h" #include "cpu_caps.h" +#include "devformat.h" #include "filters/biquad.h" #include "filters/nfc.h" #include "filters/splitter.h" diff --git a/alc/panning.cpp b/alc/panning.cpp index fd1e29ce..55af4747 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -20,29 +20,41 @@ #include "config.h" +#include +#include +#include #include -#include +#include #include -#include -#include - -#include -#include -#include -#include #include +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" #include "al/auxeffectslot.h" #include "alcmain.h" -#include "alu.h" #include "alconfig.h" +#include "almalloc.h" +#include "alnumeric.h" +#include "aloptional.h" +#include "alspan.h" +#include "alu.h" #include "ambdec.h" +#include "ambidefs.h" #include "bformatdec.h" -#include "filters/splitter.h" -#include "uhjfilter.h" #include "bs2b.h" - -#include "alspan.h" +#include "devformat.h" +#include "hrtf.h" +#include "logging.h" +#include "math_defs.h" +#include "opthelpers.h" +#include "uhjfilter.h" constexpr std::array AmbiScale::FromN3D; diff --git a/alc/uhjfilter.cpp b/alc/uhjfilter.cpp index b2cdf328..7f3cd069 100644 --- a/alc/uhjfilter.cpp +++ b/alc/uhjfilter.cpp @@ -6,6 +6,8 @@ #include #include +#include "AL/al.h" + #include "alnumeric.h" #include "opthelpers.h" -- cgit v1.2.3 From ad059fb62eaf49d06b190732936b81b1f366b4f6 Mon Sep 17 00:00:00 2001 From: Li Keqing Date: Wed, 7 Aug 2019 13:29:26 +0800 Subject: no AudioObjectPropertyAddress on iOS --- alc/backends/coreaudio.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index b4b46382..cfa7703a 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -400,7 +400,9 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) AudioComponentDescription desc; UInt32 outputFrameCount; UInt32 propertySize; +#if !TARGET_OS_IOS AudioObjectPropertyAddress propertyAddress; +#endif UInt32 enableIO; AudioComponent comp; OSStatus err; -- cgit v1.2.3 From 7c069e29ee721b2d1294dea72aa48d73d45d2009 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 5 Aug 2019 22:40:19 -0700 Subject: Update some more includes --- al/auxeffectslot.cpp | 1 + al/event.cpp | 1 + al/filter.cpp | 2 ++ al/listener.cpp | 2 ++ al/listener.h | 2 +- al/source.cpp | 1 + al/state.cpp | 1 + 7 files changed, 9 insertions(+), 1 deletion(-) diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index e961874d..a0b8840f 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -31,6 +31,7 @@ #include "AL/al.h" #include "AL/alc.h" +#include "AL/efx.h" #include "alcmain.h" #include "alcontext.h" diff --git a/al/event.cpp b/al/event.cpp index 530f9679..13b1533f 100644 --- a/al/event.cpp +++ b/al/event.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "AL/al.h" #include "AL/alc.h" diff --git a/al/filter.cpp b/al/filter.cpp index 41a96513..b1118550 100644 --- a/al/filter.cpp +++ b/al/filter.cpp @@ -29,6 +29,8 @@ #include #include +#include "AL/al.h" +#include "AL/alc.h" #include "AL/efx.h" #include "alcmain.h" diff --git a/al/listener.cpp b/al/listener.cpp index d2fb8807..bcee0b08 100644 --- a/al/listener.cpp +++ b/al/listener.cpp @@ -25,6 +25,8 @@ #include #include +#include "AL/al.h" +#include "AL/alc.h" #include "AL/efx.h" #include "alcontext.h" diff --git a/al/listener.h b/al/listener.h index 094e3067..05d93d19 100644 --- a/al/listener.h +++ b/al/listener.h @@ -6,7 +6,7 @@ #include "AL/al.h" #include "AL/alc.h" -#include "AL/alext.h" +#include "AL/efx.h" #include "vecmat.h" diff --git a/al/source.cpp b/al/source.cpp index 9273a7a8..b5d0b383 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -50,6 +50,7 @@ #include "alexcpt.h" #include "almalloc.h" #include "alnumeric.h" +#include "alspan.h" #include "alu.h" #include "ambidefs.h" #include "atomic.h" diff --git a/al/state.cpp b/al/state.cpp index cbfd12fe..8c95c22f 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -35,6 +35,7 @@ #include "alcontext.h" #include "alexcpt.h" #include "almalloc.h" +#include "alnumeric.h" #include "alspan.h" #include "alu.h" #include "atomic.h" -- cgit v1.2.3 From 5b33b4aa970b9ec7791d3cee34fe107038e7a8ca Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 7 Aug 2019 11:43:53 -0700 Subject: Make the post-process methods member functions --- alc/alcmain.h | 13 ++++++++++--- alc/alu.cpp | 44 ++++++++++++++++++++------------------------ alc/alu.h | 5 ----- alc/panning.cpp | 10 +++++----- 4 files changed, 35 insertions(+), 37 deletions(-) diff --git a/alc/alcmain.h b/alc/alcmain.h index 464febcc..910e3279 100644 --- a/alc/alcmain.h +++ b/alc/alcmain.h @@ -188,8 +188,6 @@ struct RealMixParams { al::span Buffer; }; -using POSTPROCESS = void(*)(ALCdevice *device, const ALsizei SamplesToDo); - enum { // Frequency was requested by the app or config file FrequencyRequest, @@ -305,7 +303,8 @@ struct ALCdevice : public al::intrusive_ref { /* Stereo-to-binaural filter */ std::unique_ptr Bs2b; - POSTPROCESS PostProcess{}; + using PostProc = void(ALCdevice::*)(const ALsizei SamplesToDo); + PostProc PostProcess{nullptr}; std::unique_ptr Stablizer; @@ -345,6 +344,14 @@ struct ALCdevice : public al::intrusive_ref { ALsizei channelsFromFmt() const noexcept { return ChannelsFromDevFmt(FmtChans, mAmbiOrder); } ALsizei frameSizeFromFmt() const noexcept { return bytesFromFmt() * channelsFromFmt(); } + void ProcessHrtf(const ALsizei SamplesToDo); + void ProcessAmbiDec(const ALsizei SamplesToDo); + void ProcessUhj(const ALsizei SamplesToDo); + void ProcessBs2b(const ALsizei SamplesToDo); + + inline void postProcess(const ALsizei SamplesToDo) + { if LIKELY(PostProcess) (this->*PostProcess)(SamplesToDo); } + DEF_NEWDEL(ALCdevice) }; diff --git a/alc/alu.cpp b/alc/alu.cpp index b50927e2..8cef4228 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -147,51 +147,47 @@ void aluInit(void) } -void ProcessHrtf(ALCdevice *device, const ALsizei SamplesToDo) +void ALCdevice::ProcessHrtf(const ALsizei SamplesToDo) { /* HRTF is stereo output only. */ - const int lidx{device->RealOut.ChannelIndex[FrontLeft]}; - const int ridx{device->RealOut.ChannelIndex[FrontRight]}; + const int lidx{RealOut.ChannelIndex[FrontLeft]}; + const int ridx{RealOut.ChannelIndex[FrontRight]}; ASSUME(lidx >= 0 && ridx >= 0); - DirectHrtfState *state{device->mHrtfState.get()}; - MixDirectHrtf(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], device->Dry.Buffer, - device->HrtfAccumData, state, SamplesToDo); + MixDirectHrtf(RealOut.Buffer[lidx], RealOut.Buffer[ridx], Dry.Buffer, HrtfAccumData, + mHrtfState.get(), SamplesToDo); } -void ProcessAmbiDec(ALCdevice *device, const ALsizei SamplesToDo) +void ALCdevice::ProcessAmbiDec(const ALsizei SamplesToDo) { - BFormatDec *ambidec{device->AmbiDecoder.get()}; - ambidec->process(device->RealOut.Buffer, device->Dry.Buffer.data(), SamplesToDo); + AmbiDecoder->process(RealOut.Buffer, Dry.Buffer.data(), SamplesToDo); } -void ProcessUhj(ALCdevice *device, const ALsizei SamplesToDo) +void ALCdevice::ProcessUhj(const ALsizei SamplesToDo) { /* UHJ is stereo output only. */ - const int lidx{device->RealOut.ChannelIndex[FrontLeft]}; - const int ridx{device->RealOut.ChannelIndex[FrontRight]}; + const int lidx{RealOut.ChannelIndex[FrontLeft]}; + const int ridx{RealOut.ChannelIndex[FrontRight]}; ASSUME(lidx >= 0 && ridx >= 0); /* Encode to stereo-compatible 2-channel UHJ output. */ - Uhj2Encoder *uhj2enc{device->Uhj_Encoder.get()}; - uhj2enc->encode(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], - device->Dry.Buffer.data(), SamplesToDo); + Uhj_Encoder->encode(RealOut.Buffer[lidx], RealOut.Buffer[ridx], Dry.Buffer.data(), + SamplesToDo); } -void ProcessBs2b(ALCdevice *device, const ALsizei SamplesToDo) +void ALCdevice::ProcessBs2b(const ALsizei SamplesToDo) { /* First, decode the ambisonic mix to the "real" output. */ - BFormatDec *ambidec{device->AmbiDecoder.get()}; - ambidec->process(device->RealOut.Buffer, device->Dry.Buffer.data(), SamplesToDo); + AmbiDecoder->process(RealOut.Buffer, Dry.Buffer.data(), SamplesToDo); /* BS2B is stereo output only. */ - const int lidx{device->RealOut.ChannelIndex[FrontLeft]}; - const int ridx{device->RealOut.ChannelIndex[FrontRight]}; + const int lidx{RealOut.ChannelIndex[FrontLeft]}; + const int ridx{RealOut.ChannelIndex[FrontRight]}; ASSUME(lidx >= 0 && ridx >= 0); /* Now apply the BS2B binaural/crossfeed filter. */ - bs2b_cross_feed(device->Bs2b.get(), device->RealOut.Buffer[lidx].data(), - device->RealOut.Buffer[ridx].data(), SamplesToDo); + bs2b_cross_feed(Bs2b.get(), RealOut.Buffer[lidx].data(), RealOut.Buffer[ridx].data(), + SamplesToDo); } @@ -1665,8 +1661,8 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) /* Apply any needed post-process for finalizing the Dry mix to the * RealOut (Ambisonic decode, UHJ encode, etc). */ - if LIKELY(device->PostProcess) - device->PostProcess(device, SamplesToDo); + device->postProcess(SamplesToDo); + const al::span RealOut{device->RealOut.Buffer}; /* Apply front image stablization for surround sound, if applicable. */ diff --git a/alc/alu.h b/alc/alu.h index dd133f5a..b030dbaa 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -380,11 +380,6 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr void aluInitEffectPanning(ALeffectslot *slot, ALCdevice *device); -void ProcessHrtf(ALCdevice *device, const ALsizei SamplesToDo); -void ProcessAmbiDec(ALCdevice *device, const ALsizei SamplesToDo); -void ProcessUhj(ALCdevice *device, const ALsizei SamplesToDo); -void ProcessBs2b(ALCdevice *device, const ALsizei SamplesToDo); - /** * Calculates ambisonic encoder coefficients using the X, Y, and Z direction * components, which must represent a normalized (unit length) vector, and the diff --git a/alc/panning.cpp b/alc/panning.cpp index 55af4747..d946d1fc 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -721,7 +721,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr InitCustomPanning(device, !!hqdec, pconf, speakermap); } if(device->AmbiDecoder) - device->PostProcess = ProcessAmbiDec; + device->PostProcess = &ALCdevice::ProcessAmbiDec; return; } @@ -802,7 +802,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr old_hrtf = nullptr; InitHrtfPanning(device); - device->PostProcess = ProcessHrtf; + device->PostProcess = &ALCdevice::ProcessHrtf; return; } device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; @@ -824,7 +824,7 @@ no_hrtf: bs2b_set_params(device->Bs2b.get(), *cflevopt, device->Frequency); TRACE("BS2B enabled\n"); InitPanning(device); - device->PostProcess = ProcessBs2b; + device->PostProcess = &ALCdevice::ProcessBs2b; return; } } @@ -843,13 +843,13 @@ no_hrtf: device->Uhj_Encoder = al::make_unique(); TRACE("UHJ enabled\n"); InitUhjPanning(device); - device->PostProcess = ProcessUhj; + device->PostProcess = &ALCdevice::ProcessUhj; return; } TRACE("Stereo rendering\n"); InitPanning(device); - device->PostProcess = ProcessAmbiDec; + device->PostProcess = &ALCdevice::ProcessAmbiDec; } -- cgit v1.2.3 From 0eb5e80f676c1072e1bc2c125789660b6a2be09e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 7 Aug 2019 15:43:37 -0700 Subject: Don't store options that are set to blank/default --- alc/alconfig.cpp | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/alc/alconfig.cpp b/alc/alconfig.cpp index b246a91d..e7632ef7 100644 --- a/alc/alconfig.cpp +++ b/alc/alconfig.cpp @@ -76,7 +76,7 @@ bool readline(std::istream &f, std::string &output) return std::getline(f, output) && !output.empty(); } -std:: string expdup(const char *str) +std::string expdup(const char *str) { std::string output; @@ -138,23 +138,19 @@ void LoadConfigFromFile(std::istream &f) while(readline(f, buffer)) { - while(!buffer.empty() && std::isspace(buffer.back())) - buffer.pop_back(); if(lstrip(buffer).empty()) continue; - buffer.push_back(0); - char *line{&buffer[0]}; - - if(line[0] == '[') + if(buffer[0] == '[') { + char *line{&buffer[0]}; char *section = line+1; char *endsection; endsection = std::strchr(section, ']'); if(!endsection || section == endsection) { - ERR("config parse error: bad line \"%s\"\n", line); + ERR(" config parse error: bad line \"%s\"\n", line); continue; } if(endsection[1] != 0) @@ -164,7 +160,7 @@ void LoadConfigFromFile(std::istream &f) ++end; if(*end != 0 && *end != '#') { - ERR("config parse error: bad line \"%s\"\n", line); + ERR(" config parse error: bad line \"%s\"\n", line); continue; } } @@ -223,10 +219,14 @@ void LoadConfigFromFile(std::istream &f) continue; } - char *comment{std::strchr(line, '#')}; - if(comment) *(comment++) = 0; - if(!line[0]) continue; + auto cmtpos = buffer.find('#'); + if(cmtpos != std::string::npos) + buffer.resize(cmtpos); + while(!buffer.empty() && std::isspace(buffer.back())) + buffer.pop_back(); + if(buffer.empty()) continue; + const char *line{&buffer[0]}; char key[256]{}; char value[256]{}; if(std::sscanf(line, "%255[^=] = \"%255[^\"]\"", key, value) == 2 || @@ -238,14 +238,14 @@ void LoadConfigFromFile(std::istream &f) if(std::strcmp(value, "\"\"") == 0 || std::strcmp(value, "''") == 0) value[0] = 0; } - else if(sscanf(line, "%255[^=] %255[=]", key, value) == 2) + else if(std::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); + ERR(" config parse error: malformed option line: \"%s\"\n\n", line); continue; } @@ -259,20 +259,22 @@ void LoadConfigFromFile(std::istream &f) while(!fullKey.empty() && std::isspace(fullKey.back())) fullKey.pop_back(); + TRACE(" found '%s' = '%s'\n", fullKey.c_str(), value); + /* Check if we already have this option set */ auto ent = std::find_if(ConfOpts.begin(), ConfOpts.end(), [&fullKey](const ConfigEntry &entry) -> bool { return entry.key == fullKey; } ); if(ent != ConfOpts.end()) - ent->value = expdup(value); - else { - ConfOpts.emplace_back(ConfigEntry{std::move(fullKey), expdup(value)}); - ent = ConfOpts.end()-1; + if(value[0]) + ent->value = expdup(value); + else + ConfOpts.erase(ent); } - - TRACE("found '%s' = '%s'\n", ent->key.c_str(), ent->value.c_str()); + else if(value[0]) + ConfOpts.emplace_back(ConfigEntry{std::move(fullKey), expdup(value)}); } ConfOpts.shrink_to_fit(); } -- cgit v1.2.3 From e22dc272182a44d03452c9ef44198c8173053839 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 7 Aug 2019 15:56:38 -0700 Subject: Improve log formatting for file searches --- alc/helpers.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alc/helpers.cpp b/alc/helpers.cpp index 2174de05..d1401c3c 100644 --- a/alc/helpers.cpp +++ b/alc/helpers.cpp @@ -516,7 +516,7 @@ static void DirectorySearch(const char *path, const char *ext, al::vectord_name; - TRACE("Got result %s\n", str.c_str()); + TRACE(" got %s\n", str.c_str()); } closedir(dir); -- cgit v1.2.3 From a4391a213d705810a13f225e6927812ac69c52f8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Aug 2019 12:40:34 -0700 Subject: Turn a couple methods into member functions --- alc/effects/reverb.cpp | 81 +++++++++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index eb8db3d1..77ac0f94 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -226,6 +226,36 @@ struct DelayLineI { ALsizei Mask{0}; ALfloat (*Line)[NUM_LINES]{nullptr}; + /* Given the allocated sample buffer, this function updates each delay line + * offset. + */ + void realizeLineOffset(ALfloat *sampleBuffer) + { + union { + ALfloat *f; + ALfloat (*f4)[NUM_LINES]; + } u; + u.f = &sampleBuffer[reinterpret_cast(Line) * NUM_LINES]; + Line = u.f4; + } + + /* Calculate the length of a delay line and store its mask and offset. */ + ALuint calcLineLength(const ALfloat length, const ptrdiff_t offset, const ALfloat frequency, + const ALuint extra) + { + /* All line lengths are powers of 2, calculated from their lengths in + * seconds, rounded up. + */ + auto samples = static_cast(float2int(std::ceil(length*frequency))); + samples = NextPowerOf2(samples + extra); + + /* All lines share a single sample buffer. */ + Mask = samples - 1; + Line = reinterpret_cast(offset); + + /* Return the sample count for accumulation. */ + return samples; + } void write(ALsizei offset, const ALsizei c, const ALfloat *RESTRICT in, const ALsizei count) const noexcept { @@ -457,37 +487,6 @@ struct ReverbState final : public EffectState { inline ALfloat CalcDelayLengthMult(ALfloat density) { return maxf(5.0f, std::cbrt(density*DENSITY_SCALE)); } -/* Given the allocated sample buffer, this function updates each delay line - * offset. - */ -inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLineI *Delay) -{ - union { - ALfloat *f; - ALfloat (*f4)[NUM_LINES]; - } u; - u.f = &sampleBuffer[reinterpret_cast(Delay->Line) * NUM_LINES]; - Delay->Line = u.f4; -} - -/* Calculate the length of a delay line and store its mask and offset. */ -ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const ALfloat frequency, - const ALuint extra, DelayLineI *Delay) -{ - /* All line lengths are powers of 2, calculated from their lengths in - * seconds, rounded up. - */ - auto samples = static_cast(float2int(std::ceil(length*frequency))); - samples = NextPowerOf2(samples + extra); - - /* All lines share a single sample buffer. */ - Delay->Mask = samples - 1; - Delay->Line = reinterpret_cast(offset); - - /* Return the sample count for accumulation. */ - return samples; -} - /* Calculates the delay line metrics and allocates the shared sample buffer * for all lines given the sample rate (frequency). If an allocation failure * occurs, it returns AL_FALSE. @@ -512,25 +511,25 @@ bool ReverbState::allocLines(const ALfloat frequency) ALfloat length{AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS.back()*multiplier + AL_EAXREVERB_MAX_LATE_REVERB_DELAY + (LATE_LINE_LENGTHS.back() - LATE_LINE_LENGTHS.front())/float{LATE_LINE_LENGTHS_size}*multiplier}; - totalSamples += CalcLineLength(length, totalSamples, frequency, BUFFERSIZE, &mDelay); + totalSamples += mDelay.calcLineLength(length, totalSamples, frequency, BUFFERSIZE); /* The early vector all-pass line. */ length = EARLY_ALLPASS_LENGTHS.back() * multiplier; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &mEarly.VecAp.Delay); + totalSamples += mEarly.VecAp.Delay.calcLineLength(length, totalSamples, frequency, 0); /* The early reflection line. */ length = EARLY_LINE_LENGTHS.back() * multiplier; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &mEarly.Delay); + totalSamples += mEarly.Delay.calcLineLength(length, totalSamples, frequency, 0); /* The late vector all-pass line. */ length = LATE_ALLPASS_LENGTHS.back() * multiplier; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &mLate.VecAp.Delay); + totalSamples += mLate.VecAp.Delay.calcLineLength(length, totalSamples, frequency, 0); /* The late delay lines are calculated from the largest maximum density * line length. */ length = LATE_LINE_LENGTHS.back() * multiplier; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &mLate.Delay); + totalSamples += mLate.Delay.calcLineLength(length, totalSamples, frequency, 0); totalSamples *= NUM_LINES; if(totalSamples != mSampleBuffer.size()) @@ -543,11 +542,11 @@ bool ReverbState::allocLines(const ALfloat frequency) std::fill(mSampleBuffer.begin(), mSampleBuffer.end(), 0.0f); /* Update all delays to reflect the new sample buffer. */ - RealizeLineOffset(mSampleBuffer.data(), &mDelay); - RealizeLineOffset(mSampleBuffer.data(), &mEarly.VecAp.Delay); - RealizeLineOffset(mSampleBuffer.data(), &mEarly.Delay); - RealizeLineOffset(mSampleBuffer.data(), &mLate.VecAp.Delay); - RealizeLineOffset(mSampleBuffer.data(), &mLate.Delay); + mDelay.realizeLineOffset(mSampleBuffer.data()); + mEarly.VecAp.Delay.realizeLineOffset(mSampleBuffer.data()); + mEarly.Delay.realizeLineOffset(mSampleBuffer.data()); + mLate.VecAp.Delay.realizeLineOffset(mSampleBuffer.data()); + mLate.Delay.realizeLineOffset(mSampleBuffer.data()); return true; } -- cgit v1.2.3 From fb1fde9fb030116cdfc66af3ff7277d89a31953a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Aug 2019 12:44:53 -0700 Subject: Simplify the weighted decay time calculation --- alc/effects/reverb.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 77ac0f94..423aedd8 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -767,15 +767,11 @@ void LateReverb::updateLines(const ALfloat density, const ALfloat diffusion, * approximate bandwidth. This attempts to compensate for losses of energy * that reduce decay time due to scattering into highly attenuated bands. */ - const ALfloat bandWeights[3]{ - lf0norm*norm_weight_factor, - hf0norm*norm_weight_factor - lf0norm*norm_weight_factor, - 1.0f - hf0norm*norm_weight_factor}; - DensityGain[1] = CalcDensityGain( - CalcDecayCoeff(length, - bandWeights[0]*lfDecayTime + bandWeights[1]*mfDecayTime + bandWeights[2]*hfDecayTime - ) - ); + const ALfloat decayTimeWeighted{ + (lf0norm*norm_weight_factor)*lfDecayTime + + (hf0norm*norm_weight_factor - lf0norm*norm_weight_factor)*mfDecayTime + + (1.0f - hf0norm*norm_weight_factor)*hfDecayTime}; + DensityGain[1] = CalcDensityGain(CalcDecayCoeff(length, decayTimeWeighted)); /* Calculate the all-pass feed-back/forward coefficient. */ VecAp.Coeff = std::sqrt(0.5f) * std::pow(diffusion, 2.0f); -- cgit v1.2.3 From f900efa7f258563bfc5a50f925f834097dcee433 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Aug 2019 15:13:47 -0700 Subject: Simplify and fix vocal morpher pitch calculations --- alc/effects/vmorpher.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/alc/effects/vmorpher.cpp b/alc/effects/vmorpher.cpp index ad0f026b..bf144abb 100644 --- a/alc/effects/vmorpher.cpp +++ b/alc/effects/vmorpher.cpp @@ -223,8 +223,8 @@ void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, else /*if(props->Vmorpher.Waveform == AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE)*/ mGetSamples = Oscillate; - const ALfloat pitchA{fastf2i(std::pow(2.0f, props->Vmorpher.PhonemeACoarseTuning*100.0f / 2400.0f)*FRACTIONONE) * (1.0f/FRACTIONONE)}; - const ALfloat pitchB{fastf2i(std::pow(2.0f, props->Vmorpher.PhonemeBCoarseTuning*100.0f / 2400.0f)*FRACTIONONE) * (1.0f/FRACTIONONE)}; + const ALfloat pitchA{std::pow(2.0f, props->Vmorpher.PhonemeACoarseTuning / 12.0f)}; + const ALfloat pitchB{std::pow(2.0f, props->Vmorpher.PhonemeBCoarseTuning / 12.0f)}; auto vowelA = getFiltersByPhoneme(props->Vmorpher.PhonemeA, frequency, pitchA); auto vowelB = getFiltersByPhoneme(props->Vmorpher.PhonemeB, frequency, pitchB); @@ -261,11 +261,8 @@ void VmorpherState::process(const ALsizei samplesToDo, const FloatBufferLine *RE ASSUME(numInput > 0); for(ALsizei c{0};c < numInput;c++) { - for (ALsizei i{0};i < td;i++) - { - mSampleBufferA[i] = 0.0f; - mSampleBufferB[i] = 0.0f; - } + std::fill_n(std::begin(mSampleBufferA), td, 0.0f); + std::fill_n(std::begin(mSampleBufferB), td, 0.0f); auto& vowelA = mChans[c].Formants[VOWEL_A_INDEX]; auto& vowelB = mChans[c].Formants[VOWEL_B_INDEX]; -- cgit v1.2.3 From becd1cf1bdb91e95b1680a106a5625d42db3b1a8 Mon Sep 17 00:00:00 2001 From: Minmin Gong Date: Thu, 8 Aug 2019 00:07:12 -0700 Subject: Enable to detect Windows SDK v1903 --- cmake/FindWindowsSDK.cmake | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/cmake/FindWindowsSDK.cmake b/cmake/FindWindowsSDK.cmake index 007c9b17..3fcc3bf4 100644 --- a/cmake/FindWindowsSDK.cmake +++ b/cmake/FindWindowsSDK.cmake @@ -73,10 +73,11 @@ macro(_winsdk_announce) endmacro() set(_winsdk_win10vers - 10.0.17763.0 # Windows 10 Version 1809 - 10.0.17134.0 # Windows 10 Version 1803 (April 2018 Update) - 10.0.16299.0 # Windows 10 Version 1709 (Fall Creators Update) - 10.0.15063.0 # Windows 10 Version 1703 (Creators Update) + 10.0.18362.0 # Windows 10 Version 1903 + 10.0.17763.0 # Windows 10 Version 1809 + 10.0.17134.0 # Windows 10 Version 1803 (April 2018 Update) + 10.0.16299.0 # Windows 10 Version 1709 (Fall Creators Update) + 10.0.15063.0 # Windows 10 Version 1703 (Creators Update) 10.0.14393.0 # Redstone aka Win10 1607 "Anniversary Update" 10.0.10586.0 # TH2 aka Win10 1511 10.0.10240.0 # Win10 RTM @@ -531,11 +532,11 @@ if(WINDOWSSDK_FOUND) winv6.3 # Win 8.1 min requirement ) - list(APPEND _suffixes - "lib/${_ver}/${_winsdk_arch}" - "lib/${_ver}/um/${_winsdk_arch8}" - "lib/${_ver}/km/${_winsdk_arch8}" - ) + list(APPEND _suffixes + "lib/${_ver}/${_winsdk_arch}" + "lib/${_ver}/um/${_winsdk_arch8}" + "lib/${_ver}/km/${_winsdk_arch8}" + ) endforeach() # Look for WDF libraries in Win10+ SDK -- cgit v1.2.3 From c4f1c95a45555c97d6dc5881dea9f4bf3bb1728c Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Sat, 10 Aug 2019 18:42:02 +0200 Subject: Add parameter DECLs for vocal morpher --- alc/alc.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/alc/alc.cpp b/alc/alc.cpp index a34a0824..c1989913 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -751,6 +751,13 @@ constexpr struct { DECL(AL_AUTOWAH_RESONANCE), DECL(AL_AUTOWAH_PEAK_GAIN), + DECL(AL_VOCAL_MORPHER_PHONEMEA), + DECL(AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING), + DECL(AL_VOCAL_MORPHER_PHONEMEB), + DECL(AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING), + DECL(AL_VOCAL_MORPHER_WAVEFORM), + DECL(AL_VOCAL_MORPHER_RATE), + DECL(AL_NUM_RESAMPLERS_SOFT), DECL(AL_DEFAULT_RESAMPLER_SOFT), DECL(AL_SOURCE_RESAMPLER_SOFT), -- cgit v1.2.3 From 98029d64b96c2f5edc5dc1e290fa4d30a1338bb4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 9 Aug 2019 20:09:47 -0700 Subject: Fix and clarify the peaking biquad filter --- alc/effects/equalizer.cpp | 13 +++++++------ alc/filters/biquad.cpp | 1 - alc/filters/biquad.h | 9 +++++---- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/alc/effects/equalizer.cpp b/alc/effects/equalizer.cpp index a8e81b37..12183814 100644 --- a/alc/effects/equalizer.cpp +++ b/alc/effects/equalizer.cpp @@ -116,25 +116,26 @@ void EqualizerState::update(const ALCcontext *context, const ALeffectslot *slot, ALfloat gain, f0norm; /* Calculate coefficients for the each type of filter. Note that the shelf - * filters' gain is for the reference frequency, which is the centerpoint - * of the transition band. + * and peaking filters' gain is for the centerpoint of the transition band, + * meaning its dB needs to be doubled for the shelf or peak to reach the + * provided gain. */ - gain = maxf(sqrtf(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */ + gain = maxf(std::sqrt(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */ f0norm = props->Equalizer.LowCutoff/frequency; mChans[0].filter[0].setParams(BiquadType::LowShelf, gain, f0norm, BiquadFilter::rcpQFromSlope(gain, 0.75f)); - gain = maxf(props->Equalizer.Mid1Gain, 0.0625f); + gain = maxf(std::sqrt(props->Equalizer.Mid1Gain), 0.0625f); f0norm = props->Equalizer.Mid1Center/frequency; mChans[0].filter[1].setParams(BiquadType::Peaking, gain, f0norm, BiquadFilter::rcpQFromBandwidth(f0norm, props->Equalizer.Mid1Width)); - gain = maxf(props->Equalizer.Mid2Gain, 0.0625f); + gain = maxf(std::sqrt(props->Equalizer.Mid2Gain), 0.0625f); f0norm = props->Equalizer.Mid2Center/frequency; mChans[0].filter[2].setParams(BiquadType::Peaking, gain, f0norm, BiquadFilter::rcpQFromBandwidth(f0norm, props->Equalizer.Mid2Width)); - gain = maxf(sqrtf(props->Equalizer.HighGain), 0.0625f); + gain = maxf(std::sqrt(props->Equalizer.HighGain), 0.0625f); f0norm = props->Equalizer.HighCutoff/frequency; mChans[0].filter[3].setParams(BiquadType::HighShelf, gain, f0norm, BiquadFilter::rcpQFromSlope(gain, 0.75f)); diff --git a/alc/filters/biquad.cpp b/alc/filters/biquad.cpp index 6a3cef64..871c4af4 100644 --- a/alc/filters/biquad.cpp +++ b/alc/filters/biquad.cpp @@ -47,7 +47,6 @@ void BiquadFilterR::setParams(BiquadType type, Real gain, Real f0norm, Rea a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; break; case BiquadType::Peaking: - gain = std::sqrt(gain); b[0] = 1.0f + alpha * gain; b[1] = -2.0f * cos_w0; b[2] = 1.0f - alpha * gain; diff --git a/alc/filters/biquad.h b/alc/filters/biquad.h index 893a69a9..f8d7f0ba 100644 --- a/alc/filters/biquad.h +++ b/alc/filters/biquad.h @@ -11,10 +11,11 @@ * EQ biquad filter coefficients" by Robert Bristow-Johnson * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */ -/* Implementation note: For the shelf filters, the specified gain is for the - * reference frequency, which is the centerpoint of the transition band. This - * better matches EFX filter design. To set the gain for the shelf itself, use - * the square root of the desired linear gain (or halve the dB gain). +/* Implementation note: For the shelf and peaking filters, the specified gain + * is for the centerpoint of the transition band. This better fits EFX filter + * behavior, which expects the shelf's reference frequency to reach the given + * gain. To set the gain for the shelf or peak itself, use the square root of + * the desired linear gain (or halve the dB gain). */ enum class BiquadType { -- cgit v1.2.3 From e3f5bd37e632229fd7e9e849911578e58e7ccbb5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 10 Aug 2019 16:35:29 -0700 Subject: Avoid __popcnt[64] on MSVC It requires SSE4, and provides no fallback mechanism for CPU targets lacking the opcode it maps to. --- common/alnumeric.h | 72 +++++++++++++++++++++++------------------------------- 1 file changed, 31 insertions(+), 41 deletions(-) diff --git a/common/alnumeric.h b/common/alnumeric.h index 7035715c..b51893d6 100644 --- a/common/alnumeric.h +++ b/common/alnumeric.h @@ -106,11 +106,34 @@ inline size_t RoundUp(size_t value, size_t r) noexcept #define CTZ64 __builtin_ctzll #endif -#elif defined(HAVE_BITSCANFORWARD64_INTRINSIC) +#else + +/* There be black magics here. The popcnt method is derived from + * https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel + * while the ctz-utilizing-popcnt algorithm is shown here + * http://www.hackersdelight.org/hdcodetxt/ntz.c.txt + * as the ntz2 variant. These likely aren't the most efficient methods, but + * they're good enough if the GCC built-ins aren't available. + */ +inline int fallback_popcnt32(uint32_t v) +{ + v = v - ((v >> 1) & 0x55555555u); + v = (v & 0x33333333u) + ((v >> 2) & 0x33333333u); + v = (v + (v >> 4)) & 0x0f0f0f0fu; + return (int)((v * 0x01010101u) >> 24); +} +#define POPCNT32 fallback_popcnt32 +inline int fallback_popcnt64(uint64_t v) +{ + v = v - ((v >> 1) & 0x5555555555555555_u64); + v = (v & 0x3333333333333333_u64) + ((v >> 2) & 0x3333333333333333_u64); + v = (v + (v >> 4)) & 0x0f0f0f0f0f0f0f0f_u64; + return (int)((v * 0x0101010101010101_u64) >> 56); +} +#define POPCNT64 fallback_popcnt64 + +#if defined(HAVE_BITSCANFORWARD64_INTRINSIC) -inline int msvc64_popcnt32(uint32_t v) -{ return (int)__popcnt(v); } -#define POPCNT32 msvc64_popcnt32 inline int msvc64_ctz32(uint32_t v) { unsigned long idx = 32; @@ -118,10 +141,6 @@ inline int msvc64_ctz32(uint32_t v) return (int)idx; } #define CTZ32 msvc64_ctz32 - -inline int msvc64_popcnt64(uint64_t v) -{ return (int)__popcnt64(v); } -#define POPCNT64 msvc64_popcnt64 inline int msvc64_ctz64(uint64_t v) { unsigned long idx = 64; @@ -132,9 +151,6 @@ inline int msvc64_ctz64(uint64_t v) #elif defined(HAVE_BITSCANFORWARD_INTRINSIC) -inline int msvc_popcnt32(uint32_t v) -{ return (int)__popcnt(v); } -#define POPCNT32 msvc_popcnt32 inline int msvc_ctz32(uint32_t v) { unsigned long idx = 32; @@ -142,10 +158,6 @@ inline int msvc_ctz32(uint32_t v) return (int)idx; } #define CTZ32 msvc_ctz32 - -inline int msvc_popcnt64(uint64_t v) -{ return (int)(__popcnt((uint32_t)v) + __popcnt((uint32_t)(v>>32))); } -#define POPCNT64 msvc_popcnt64 inline int msvc_ctz64(uint64_t v) { unsigned long idx = 64; @@ -160,36 +172,14 @@ inline int msvc_ctz64(uint64_t v) #else -/* There be black magics here. The popcnt method is derived from - * https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel - * while the ctz-utilizing-popcnt algorithm is shown here - * http://www.hackersdelight.org/hdcodetxt/ntz.c.txt - * as the ntz2 variant. These likely aren't the most efficient methods, but - * they're good enough if the GCC or MSVC intrinsics aren't available. - */ -inline int fallback_popcnt32(uint32_t v) -{ - v = v - ((v >> 1) & 0x55555555u); - v = (v & 0x33333333u) + ((v >> 2) & 0x33333333u); - v = (v + (v >> 4)) & 0x0f0f0f0fu; - return (int)((v * 0x01010101u) >> 24); -} -#define POPCNT32 fallback_popcnt32 inline int fallback_ctz32(uint32_t value) -{ return fallback_popcnt32(~value & (value - 1)); } +{ return POPCNT32(~value & (value - 1)); } #define CTZ32 fallback_ctz32 - -inline int fallback_popcnt64(uint64_t v) -{ - v = v - ((v >> 1) & 0x5555555555555555_u64); - v = (v & 0x3333333333333333_u64) + ((v >> 2) & 0x3333333333333333_u64); - v = (v + (v >> 4)) & 0x0f0f0f0f0f0f0f0f_u64; - return (int)((v * 0x0101010101010101_u64) >> 56); -} -#define POPCNT64 fallback_popcnt64 inline int fallback_ctz64(uint64_t value) -{ return fallback_popcnt64(~value & (value - 1)); } +{ return POPCNT64(~value & (value - 1)); } #define CTZ64 fallback_ctz64 + +#endif #endif -- cgit v1.2.3 From dca2365051e4697f5a1692252e9516398f746e0b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 10 Aug 2019 20:31:08 -0700 Subject: Fix array access index --- al/source.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/al/source.cpp b/al/source.cpp index b5d0b383..98c52816 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -2403,7 +2403,7 @@ START_API_FUNC { ALdouble dval[1]; if(GetSourcedv(Source, context.get(), static_cast(param), dval)) - *value = static_cast(dval[1]); + *value = static_cast(dval[0]); } } END_API_FUNC -- cgit v1.2.3 From 70058a8a8405a36c66235a56b482c4c0c7a46780 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 10 Aug 2019 21:54:30 -0700 Subject: Move the dynload decls and defs to common --- CMakeLists.txt | 2 ++ alc/backends/alsa.cpp | 2 +- alc/backends/dsound.cpp | 1 + alc/backends/jack.cpp | 2 +- alc/backends/portaudio.cpp | 2 +- alc/backends/pulseaudio.cpp | 3 ++- alc/compat.h | 16 ------------ alc/helpers.cpp | 45 -------------------------------- common/dynload.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++++ common/dynload.h | 14 ++++++++++ 10 files changed, 84 insertions(+), 65 deletions(-) create mode 100644 common/dynload.cpp create mode 100644 common/dynload.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fd0b69a..6fe05f35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -598,6 +598,8 @@ SET(COMMON_OBJS common/aloptional.h common/alspan.h common/atomic.h + common/dynload.cpp + common/dynload.h common/endiantest.h common/intrusive_ptr.h common/math_defs.h diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index c133df68..64f9cf46 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -44,7 +44,7 @@ #include "alnumeric.h" #include "aloptional.h" #include "alu.h" -#include "compat.h" +#include "dynload.h" #include "logging.h" #include "ringbuffer.h" #include "threads.h" diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index 5a156d54..b9e52c0c 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -48,6 +48,7 @@ #include "alu.h" #include "ringbuffer.h" #include "compat.h" +#include "dynload.h" #include "threads.h" /* MinGW-w64 needs this for some unknown reason now. */ diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp index 3f81d08c..e688b96b 100644 --- a/alc/backends/jack.cpp +++ b/alc/backends/jack.cpp @@ -32,9 +32,9 @@ #include "alcmain.h" #include "alu.h" #include "alconfig.h" +#include "dynload.h" #include "ringbuffer.h" #include "threads.h" -#include "compat.h" #include #include diff --git a/alc/backends/portaudio.cpp b/alc/backends/portaudio.cpp index 73e972c5..fcfd4b01 100644 --- a/alc/backends/portaudio.cpp +++ b/alc/backends/portaudio.cpp @@ -29,8 +29,8 @@ #include "alcmain.h" #include "alu.h" #include "alconfig.h" +#include "dynload.h" #include "ringbuffer.h" -#include "compat.h" #include diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 2ddcc86d..ca2ecb43 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -37,8 +37,9 @@ #include "alcmain.h" #include "alu.h" #include "alconfig.h" -#include "compat.h" #include "alexcpt.h" +#include "compat.h" +#include "dynload.h" #include diff --git a/alc/compat.h b/alc/compat.h index 4ffc40bf..648fa5b1 100644 --- a/alc/compat.h +++ b/alc/compat.h @@ -1,8 +1,6 @@ #ifndef AL_COMPAT_H #define AL_COMPAT_H -#ifdef __cplusplus - #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN @@ -86,8 +84,6 @@ public: } // namespace al -#define HAVE_DYNLOAD 1 - #else /* _WIN32 */ #include @@ -99,10 +95,6 @@ using ifstream = std::ifstream; } // namespace al -#if defined(HAVE_DLFCN_H) -#define HAVE_DYNLOAD 1 -#endif - #endif /* _WIN32 */ #include @@ -110,12 +102,4 @@ using ifstream = std::ifstream; struct PathNamePair { std::string path, fname; }; const PathNamePair &GetProcBinary(void); -#ifdef HAVE_DYNLOAD -void *LoadLib(const char *name); -void CloseLib(void *handle); -void *GetSymbol(void *handle, const char *name); -#endif - -#endif /* __cplusplus */ - #endif /* AL_COMPAT_H */ diff --git a/alc/helpers.cpp b/alc/helpers.cpp index d1401c3c..b952c5ed 100644 --- a/alc/helpers.cpp +++ b/alc/helpers.cpp @@ -81,9 +81,6 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x #endif #endif /* AL_NO_UID_DEFS */ -#ifdef HAVE_DLFCN_H -#include -#endif #ifdef HAVE_INTRIN_H #include #endif @@ -454,21 +451,6 @@ const PathNamePair &GetProcBinary() } -void *LoadLib(const char *name) -{ - std::wstring wname{utf8_to_wstr(name)}; - return LoadLibraryW(wname.c_str()); -} -void CloseLib(void *handle) -{ FreeLibrary(static_cast(handle)); } -void *GetSymbol(void *handle, const char *name) -{ - void *ret{reinterpret_cast(GetProcAddress(static_cast(handle), name))}; - if(!ret) ERR("Failed to load %s\n", name); - return ret; -} - - void al_print(FILE *logfile, const char *fmt, ...) { al::vector dynmsg; @@ -683,33 +665,6 @@ const PathNamePair &GetProcBinary() } -#ifdef HAVE_DLFCN_H - -void *LoadLib(const char *name) -{ - dlerror(); - void *handle{dlopen(name, RTLD_NOW)}; - const char *err{dlerror()}; - if(err) handle = nullptr; - return handle; -} -void CloseLib(void *handle) -{ dlclose(handle); } -void *GetSymbol(void *handle, const char *name) -{ - dlerror(); - void *sym{dlsym(handle, name)}; - const char *err{dlerror()}; - if(err) - { - WARN("Failed to load %s: %s\n", name, err); - sym = nullptr; - } - return sym; -} - -#endif /* HAVE_DLFCN_H */ - void al_print(FILE *logfile, const char *fmt, ...) { va_list ap; diff --git a/common/dynload.cpp b/common/dynload.cpp new file mode 100644 index 00000000..89824f78 --- /dev/null +++ b/common/dynload.cpp @@ -0,0 +1,62 @@ + +#include "config.h" + +#include "dynload.h" + + +#ifdef _WIN32 + +#define WIN32_LEAN_AND_MEAN +#include + +#include + +inline std::wstring utf8_to_wstr(const char *str) +{ + std::wstring ret; + + int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + if(len > 0) + { + ret.resize(len); + MultiByteToWideChar(CP_UTF8, 0, str, -1, &ret[0], len); + ret.pop_back(); + } + + return ret; +} + +void *LoadLib(const char *name) +{ + std::wstring wname{utf8_to_wstr(name)}; + return LoadLibraryW(wname.c_str()); +} +void CloseLib(void *handle) +{ FreeLibrary(static_cast(handle)); } +void *GetSymbol(void *handle, const char *name) +{ return reinterpret_cast(GetProcAddress(static_cast(handle), name)); } + +#elif defined(HAVE_DLFCN_H) + +#include + +void *LoadLib(const char *name) +{ + dlerror(); + void *handle{dlopen(name, RTLD_NOW)}; + const char *err{dlerror()}; + if(err) handle = nullptr; + return handle; +} +void CloseLib(void *handle) +{ dlclose(handle); } +void *GetSymbol(void *handle, const char *name) +{ + dlerror(); + void *sym{dlsym(handle, name)}; + const char *err{dlerror()}; + if(err) sym = nullptr; + return sym; +} + +#endif diff --git a/common/dynload.h b/common/dynload.h new file mode 100644 index 00000000..bd9e86f7 --- /dev/null +++ b/common/dynload.h @@ -0,0 +1,14 @@ +#ifndef AL_DYNLOAD_H +#define AL_DYNLOAD_H + +#if defined(_WIN32) || defined(HAVE_DLFCN_H) + +#define HAVE_DYNLOAD + +void *LoadLib(const char *name); +void CloseLib(void *handle); +void *GetSymbol(void *handle, const char *name); + +#endif + +#endif /* AL_DYNLOAD_H */ -- cgit v1.2.3 From 7118733458bc388a900677da6e0d4e4244d0f536 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Aug 2019 03:34:35 -0700 Subject: Remove multiple buffers per queue item And simplify related code --- al/source.cpp | 252 +++++++++++-------------------------------------------- al/source.h | 58 ++----------- alc/inprogext.h | 8 -- alc/mixvoice.cpp | 133 +++++++++-------------------- 4 files changed, 96 insertions(+), 355 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index 98c52816..4bdf51fe 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -206,7 +206,7 @@ int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, std::chrono const ALbufferlistitem *BufferList{Source->queue}; while(BufferList && BufferList != Current) { - readPos += int64_t{BufferList->mMaxSamples} << 32; + readPos += int64_t{BufferList->mSampleLen} << 32; BufferList = BufferList->mNext.load(std::memory_order_relaxed); } readPos = minu64(readPos, 0x7fffffffffffffff_u64); @@ -253,16 +253,14 @@ ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, std::chrono:: const ALbuffer *BufferFmt{nullptr}; while(BufferList && BufferList != Current) { - for(ALuint i{0};!BufferFmt && i < BufferList->mNumBuffers;++i) - BufferFmt = (*BufferList)[i]; - readPos += int64_t{BufferList->mMaxSamples} << FRACTIONBITS; + if(!BufferFmt) BufferFmt = BufferList->mBuffer; + readPos += int64_t{BufferList->mSampleLen} << FRACTIONBITS; BufferList = BufferList->mNext.load(std::memory_order_relaxed); } while(BufferList && !BufferFmt) { - for(ALuint i{0};!BufferFmt && i < BufferList->mNumBuffers;++i) - BufferFmt = (*BufferList)[i]; + BufferFmt = BufferList->mBuffer; BufferList = BufferList->mNext.load(std::memory_order_relaxed); } assert(BufferFmt != nullptr); @@ -315,12 +313,11 @@ ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) while(BufferList) { - for(ALuint i{0};!BufferFmt && i < BufferList->mNumBuffers;++i) - BufferFmt = (*BufferList)[i]; + if(!BufferFmt) BufferFmt = BufferList->mBuffer; readFin |= (BufferList == Current); - totalBufferLen += BufferList->mMaxSamples; - if(!readFin) readPos += BufferList->mMaxSamples; + totalBufferLen += BufferList->mSampleLen; + if(!readFin) readPos += BufferList->mSampleLen; BufferList = BufferList->mNext.load(std::memory_order_relaxed); } @@ -392,11 +389,9 @@ ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac) /* Find the first valid Buffer in the Queue */ BufferList = Source->queue; - while(BufferList) + while(BufferList && !BufferFmt) { - for(ALuint i{0};!BufferFmt && i < BufferList->mNumBuffers;i++) - BufferFmt = (*BufferList)[i]; - if(BufferFmt) break; + BufferFmt = BufferList->mBuffer; BufferList = BufferList->mNext.load(std::memory_order_relaxed); } if(!BufferFmt) @@ -464,7 +459,7 @@ ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) ALbufferlistitem *BufferList{Source->queue}; while(BufferList && totalBufferLen <= offset) { - if(static_cast(BufferList->mMaxSamples) > offset-totalBufferLen) + if(BufferList->mSampleLen > offset-totalBufferLen) { /* Offset is in this buffer */ voice->mPosition.store(offset - totalBufferLen, std::memory_order_relaxed); @@ -472,7 +467,7 @@ ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) voice->mCurrentBuffer.store(BufferList, std::memory_order_release); return AL_TRUE; } - totalBufferLen += BufferList->mMaxSamples; + totalBufferLen += BufferList->mSampleLen; BufferList = BufferList->mNext.load(std::memory_order_relaxed); } @@ -1197,12 +1192,9 @@ bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a if(buffer != nullptr) { /* Add the selected buffer to a one-item queue */ - auto newlist = static_cast(al_calloc(alignof(void*), - ALbufferlistitem::Sizeof(1u))); - newlist->mNext.store(nullptr, std::memory_order_relaxed); - newlist->mMaxSamples = buffer->SampleLen; - newlist->mNumBuffers = 1; - newlist->mBuffers[0] = buffer; + auto newlist = new ALbufferlistitem{}; + newlist->mSampleLen = buffer->SampleLen; + newlist->mBuffer = buffer; IncrementRef(buffer->ref); /* Source is now Static */ @@ -1220,13 +1212,11 @@ bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a /* Delete all elements in the previous queue */ while(oldlist != nullptr) { - ALbufferlistitem *temp{oldlist}; + std::unique_ptr temp{oldlist}; oldlist = temp->mNext.load(std::memory_order_relaxed); - std::for_each(temp->begin(), temp->end(), - [](ALbuffer *buffer) -> void - { if(buffer) DecrementRef(buffer->ref); }); - al_free(temp); + if(ALbuffer *buffer{temp->mBuffer}) + DecrementRef(buffer->ref); } return true; @@ -1769,8 +1759,7 @@ bool GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a case AL_BUFFER: CHECKSIZE(values, 1); BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : nullptr; - values[0] = (BufferList && !BufferList->empty() && BufferList->front()) ? - BufferList->front()->id : 0; + values[0] = (BufferList && BufferList->mBuffer) ? BufferList->mBuffer->id : 0; return true; case AL_SOURCE_STATE: @@ -1786,7 +1775,7 @@ bool GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a { ALsizei count{0}; do { - count += BufferList->mNumBuffers; + ++count; BufferList = BufferList->mNext.load(std::memory_order_relaxed); } while(BufferList != nullptr); values[0] = count; @@ -1815,7 +1804,7 @@ bool GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a while(BufferList && BufferList != Current) { - played += BufferList->mNumBuffers; + ++played; BufferList = BufferList->mNext.load(std::memory_order_relaxed); } values[0] = played; @@ -2729,7 +2718,7 @@ START_API_FUNC * length buffer. */ ALbufferlistitem *BufferList{source->queue}; - while(BufferList && BufferList->mMaxSamples == 0) + while(BufferList && BufferList->mSampleLen == 0) BufferList = BufferList->mNext.load(std::memory_order_relaxed); /* If there's nothing to play, go right to stopped. */ @@ -2807,15 +2796,11 @@ START_API_FUNC voice->mPositionFrac.load(std::memory_order_relaxed) != 0 || voice->mCurrentBuffer.load(std::memory_order_relaxed) != BufferList; - auto buffer = std::find_if(BufferList->cbegin(), BufferList->cend(), - std::bind(std::not_equal_to{}, _1, nullptr)); - if(buffer != BufferList->cend()) - { - voice->mFrequency = (*buffer)->Frequency; - voice->mFmtChannels = (*buffer)->mFmtChannels; - voice->mNumChannels = ChannelsFromFmt((*buffer)->mFmtChannels); - voice->mSampleSize = BytesFromFmt((*buffer)->mFmtType); - } + ALbuffer *buffer{BufferList->mBuffer}; + voice->mFrequency = buffer->Frequency; + voice->mFmtChannels = buffer->mFmtChannels; + voice->mNumChannels = ChannelsFromFmt(buffer->mFmtChannels); + voice->mSampleSize = BytesFromFmt(buffer->mFmtType); /* Clear the stepping value so the mixer knows not to mix this until * the update gets applied. @@ -3101,11 +3086,9 @@ START_API_FUNC ALCdevice *device{context->mDevice.get()}; ALbuffer *BufferFmt{nullptr}; ALbufferlistitem *BufferList{source->queue}; - while(BufferList) + while(BufferList && !BufferFmt) { - for(ALuint i{0};!BufferFmt && i < BufferList->mNumBuffers;i++) - BufferFmt = (*BufferList)[i]; - if(BufferFmt) break; + BufferFmt = BufferList->mBuffer; BufferList = BufferList->mNext.load(std::memory_order_relaxed); } @@ -3123,128 +3106,22 @@ START_API_FUNC if(!BufferListStart) { - BufferListStart = static_cast(al_calloc(alignof(void*), - ALbufferlistitem::Sizeof(1u))); + BufferListStart = new ALbufferlistitem{}; BufferList = BufferListStart; } else { - auto item = static_cast(al_calloc(alignof(void*), - ALbufferlistitem::Sizeof(1u))); + auto item = new ALbufferlistitem{}; BufferList->mNext.store(item, std::memory_order_relaxed); BufferList = item; } BufferList->mNext.store(nullptr, std::memory_order_relaxed); - BufferList->mMaxSamples = buffer ? buffer->SampleLen : 0; - BufferList->mNumBuffers = 1; - BufferList->mBuffers[0] = buffer; - if(!buffer) continue; - - IncrementRef(buffer->ref); - - if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) - { - context->setError(AL_INVALID_OPERATION, "Queueing non-persistently mapped buffer %u", - buffer->id); - goto buffer_error; - } - - if(BufferFmt == nullptr) - BufferFmt = buffer; - else if(BufferFmt->Frequency != buffer->Frequency || - BufferFmt->mFmtChannels != buffer->mFmtChannels || - BufferFmt->OriginalType != buffer->OriginalType) - { - context->setError(AL_INVALID_OPERATION, "Queueing buffer with mismatched format"); - - buffer_error: - /* A buffer failed (invalid ID or format), so unlock and release - * each buffer we had. */ - while(BufferListStart) - { - ALbufferlistitem *next = BufferListStart->mNext.load(std::memory_order_relaxed); - std::for_each(BufferListStart->begin(), BufferListStart->end(), - [](ALbuffer *buffer) -> void - { if(buffer) DecrementRef(buffer->ref); }); - al_free(BufferListStart); - BufferListStart = next; - } - return; - } - } - /* All buffers good. */ - buflock.unlock(); - - /* Source is now streaming */ - source->SourceType = AL_STREAMING; - - if(!(BufferList=source->queue)) - source->queue = BufferListStart; - else - { - ALbufferlistitem *next; - while((next=BufferList->mNext.load(std::memory_order_relaxed)) != nullptr) - BufferList = next; - BufferList->mNext.store(BufferListStart, std::memory_order_release); - } -} -END_API_FUNC - -AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers) -START_API_FUNC -{ - ContextRef context{GetContextRef()}; - if UNLIKELY(!context) return; - - if UNLIKELY(nb < 0) - context->setError(AL_INVALID_VALUE, "Queueing %d buffer layers", nb); - if UNLIKELY(nb <= 0) return; - - std::lock_guard _{context->mSourceLock}; - ALsource *source{LookupSource(context.get(),src)}; - if UNLIKELY(!source) - SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", src); - - /* Can't queue on a Static Source */ - if UNLIKELY(source->SourceType == AL_STATIC) - SETERR_RETURN(context, AL_INVALID_OPERATION,, "Queueing onto static source %u", src); - - /* Check for a valid Buffer, for its frequency and format */ - ALCdevice *device{context->mDevice.get()}; - ALbuffer *BufferFmt{nullptr}; - ALbufferlistitem *BufferList{source->queue}; - while(BufferList) - { - for(ALuint i{0};!BufferFmt && i < BufferList->mNumBuffers;i++) - BufferFmt = (*BufferList)[i]; - if(BufferFmt) break; - BufferList = BufferList->mNext.load(std::memory_order_relaxed); - } - - std::unique_lock buflock{device->BufferLock}; - auto BufferListStart = static_cast(al_calloc(alignof(void*), - ALbufferlistitem::Sizeof(nb))); - BufferList = BufferListStart; - BufferList->mNext.store(nullptr, std::memory_order_relaxed); - BufferList->mMaxSamples = 0; - BufferList->mNumBuffers = 0; - - for(ALsizei i{0};i < nb;i++) - { - ALbuffer *buffer{nullptr}; - if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == nullptr) - { - context->setError(AL_INVALID_NAME, "Queueing invalid buffer ID %u", buffers[i]); - goto buffer_error; - } - - BufferList->mBuffers[BufferList->mNumBuffers++] = buffer; + BufferList->mSampleLen = buffer ? buffer->SampleLen : 0; + BufferList->mBuffer = buffer; if(!buffer) continue; IncrementRef(buffer->ref); - BufferList->mMaxSamples = maxu(BufferList->mMaxSamples, buffer->SampleLen); - if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) { context->setError(AL_INVALID_OPERATION, "Queueing non-persistently mapped buffer %u", @@ -3265,12 +3142,9 @@ START_API_FUNC * each buffer we had. */ while(BufferListStart) { - ALbufferlistitem *next{BufferListStart->mNext.load(std::memory_order_relaxed)}; - std::for_each(BufferListStart->begin(), BufferListStart->end(), - [](ALbuffer *buffer) -> void - { if(buffer) DecrementRef(buffer->ref); }); - al_free(BufferListStart); - BufferListStart = next; + std::unique_ptr head{BufferListStart}; + BufferListStart = head->mNext.load(std::memory_order_relaxed); + if(ALbuffer *buffer{head->mBuffer}) DecrementRef(buffer->ref); } return; } @@ -3325,7 +3199,7 @@ START_API_FUNC if UNLIKELY(BufferList == Current) SETERR_RETURN(context, AL_INVALID_VALUE,, "Unqueueing pending buffers"); - ALuint i{BufferList->mNumBuffers}; + ALuint i{1u}; while(i < static_cast(nb)) { /* If the next bufferlist to check is NULL or is the current one, it's @@ -3336,47 +3210,22 @@ START_API_FUNC SETERR_RETURN(context, AL_INVALID_VALUE,, "Unqueueing pending buffers"); BufferList = next; - i += BufferList->mNumBuffers; + ++i; } while(nb > 0) { - ALbufferlistitem *head{source->queue}; - ALbufferlistitem *next{head->mNext.load(std::memory_order_relaxed)}; - for(i = 0;i < head->mNumBuffers && nb > 0;i++,nb--) - { - ALbuffer *buffer{(*head)[i]}; - if(!buffer) - *(buffers++) = 0; - else - { - *(buffers++) = buffer->id; - DecrementRef(buffer->ref); - } - } - if(i < head->mNumBuffers) + std::unique_ptr head{source->queue}; + source->queue = head->mNext.load(std::memory_order_relaxed); + + if(ALbuffer *buffer{head->mBuffer}) { - /* This head has some buffers left over, so move them to the front - * and update the sample and buffer count. - */ - ALuint max_length{0}; - ALuint j{0}; - while(i < head->mNumBuffers) - { - ALbuffer *buffer{(*head)[i++]}; - if(buffer) max_length = maxu(max_length, buffer->SampleLen); - head->mBuffers[j++] = buffer; - } - head->mMaxSamples = max_length; - head->mNumBuffers = j; - break; + *(buffers++) = buffer->id; + DecrementRef(buffer->ref); } - - /* Otherwise, free this item and set the source queue head to the next - * one. - */ - al_free(head); - source->queue = next; + else + *(buffers++) = 0; + --nb; } } END_API_FUNC @@ -3453,12 +3302,9 @@ ALsource::~ALsource() ALbufferlistitem *BufferList{queue}; while(BufferList != nullptr) { - ALbufferlistitem *next{BufferList->mNext.load(std::memory_order_relaxed)}; - std::for_each(BufferList->begin(), BufferList->end(), - [](ALbuffer *buffer) -> void - { if(buffer) DecrementRef(buffer->ref); }); - al_free(BufferList); - BufferList = next; + std::unique_ptr head{BufferList}; + BufferList = head->mNext.load(std::memory_order_relaxed); + if(ALbuffer *buffer{BufferList->mBuffer}) DecrementRef(buffer->ref); } queue = nullptr; diff --git a/al/source.h b/al/source.h index a5d10cf9..05037fd3 100644 --- a/al/source.h +++ b/al/source.h @@ -10,6 +10,7 @@ #include "AL/alc.h" #include "alcontext.h" +#include "almalloc.h" #include "alnumeric.h" #include "alu.h" #include "vector.h" @@ -23,58 +24,11 @@ struct ALeffectslot; #define INVALID_VOICE_IDX static_cast(-1) struct ALbufferlistitem { - using element_type = ALbuffer*; - using value_type = ALbuffer*; - using index_type = size_t; - using difference_type = ptrdiff_t; - - using pointer = ALbuffer**; - using const_pointer = ALbuffer*const*; - using reference = ALbuffer*&; - using const_reference = ALbuffer*const&; - - using iterator = pointer; - using const_iterator = const_pointer; - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - - - std::atomic mNext; - ALuint mMaxSamples; - ALuint mNumBuffers; - element_type mBuffers[]; - - static constexpr size_t Sizeof(size_t num_buffers) noexcept - { - return maxz(offsetof(ALbufferlistitem, mBuffers) + sizeof(element_type)*num_buffers, - sizeof(ALbufferlistitem)); - } - - reference front() { return mBuffers[0]; } - const_reference front() const { return mBuffers[0]; } - reference back() { return mBuffers[mNumBuffers-1]; } - const_reference back() const { return mBuffers[mNumBuffers-1]; } - reference operator[](index_type idx) { return mBuffers[idx]; } - const_reference operator[](index_type idx) const { return mBuffers[idx]; } - pointer data() noexcept { return mBuffers; } - const_pointer data() const noexcept { return mBuffers; } - - index_type size() const noexcept { return mNumBuffers; } - bool empty() const noexcept { return mNumBuffers == 0; } - - iterator begin() noexcept { return mBuffers; } - iterator end() noexcept { return mBuffers+mNumBuffers; } - const_iterator begin() const noexcept { return mBuffers; } - const_iterator end() const noexcept { return mBuffers+mNumBuffers; } - const_iterator cbegin() const noexcept { return mBuffers; } - const_iterator cend() const noexcept { return mBuffers+mNumBuffers; } - - reverse_iterator rbegin() noexcept { return reverse_iterator{end()}; } - reverse_iterator rend() noexcept { return reverse_iterator{begin()}; } - const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator{end()}; } - const_reverse_iterator rend() const noexcept { return const_reverse_iterator{begin()}; } - const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{cend()}; } - const_reverse_iterator crend() const noexcept { return const_reverse_iterator{cbegin()}; } + std::atomic mNext{nullptr}; + ALuint mSampleLen{0u}; + ALbuffer *mBuffer{nullptr}; + + DEF_NEWDEL(ALbufferlistitem) }; diff --git a/alc/inprogext.h b/alc/inprogext.h index 15881b59..ad3ea288 100644 --- a/alc/inprogext.h +++ b/alc/inprogext.h @@ -72,14 +72,6 @@ AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values); #endif #endif -#ifndef AL_SOFT_buffer_layers -#define AL_SOFT_buffer_layers -typedef void (AL_APIENTRY*LPALSOURCEQUEUEBUFFERLAYERSSOFT)(ALuint src, ALsizei nb, const ALuint *buffers); -#ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers); -#endif -#endif - #ifndef AL_SOFT_effect_chain #define AL_SOFT_effect_chain #define AL_EFFECTSLOT_TARGET_SOFT 0xf000 diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index cf3eeb50..295b1352 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -372,7 +372,7 @@ inline void LoadSampleArray(ALfloat *RESTRICT dst, const al::byte *src, ALint sr const SampleType *RESTRICT ssrc{reinterpret_cast(src)}; for(ALsizei i{0};i < samples;i++) - dst[i] += FmtTypeTraits::to_float(ssrc[i*srcstep]); + dst[i] = FmtTypeTraits::to_float(ssrc[i*srcstep]); } void LoadSamples(ALfloat *RESTRICT dst, const al::byte *src, ALint srcstep, FmtType srctype, @@ -395,12 +395,9 @@ ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&B const ALsizei NumChannels, const ALsizei SampleSize, const ALsizei chan, ALuint DataPosInt, al::span SrcBuffer) { - /* TODO: For static sources, loop points are taken from the first buffer - * (should be adjusted by any buffer offset, to possibly be added later). - */ - const ALbuffer *Buffer0{BufferListItem->front()}; - const ALuint LoopStart{Buffer0->LoopStart}; - const ALuint LoopEnd{Buffer0->LoopEnd}; + const ALbuffer *Buffer{BufferListItem->mBuffer}; + const ALuint LoopStart{Buffer->LoopStart}; + const ALuint LoopEnd{Buffer->LoopEnd}; ASSUME(LoopStart >= 0); ASSUME(LoopEnd > LoopStart); @@ -409,75 +406,37 @@ ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&B { BufferLoopItem = nullptr; - auto load_buffer = [DataPosInt,NumChannels,SampleSize,chan,SrcBuffer](size_t CompLen, const ALbuffer *buffer) -> size_t - { - if(DataPosInt >= buffer->SampleLen) - return CompLen; - - /* Load what's left to play from the buffer */ - const size_t DataSize{std::min(SrcBuffer.size(), - buffer->SampleLen - DataPosInt)}; - CompLen = std::max(CompLen, DataSize); - - const al::byte *Data{buffer->mData.data()}; - Data += (DataPosInt*NumChannels + chan)*SampleSize; - - LoadSamples(SrcBuffer.data(), Data, NumChannels, buffer->mFmtType, DataSize); - return CompLen; - }; - /* It's impossible to have a buffer list item with no entries. */ - ASSUME(BufferListItem->mNumBuffers > 0); - SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->begin(), - BufferListItem->end(), size_t{0u}, load_buffer)); + /* Load what's left to play from the buffer */ + const size_t DataSize{minz(SrcBuffer.size(), Buffer->SampleLen-DataPosInt)}; + + const al::byte *Data{Buffer->mData.data()}; + Data += (DataPosInt*NumChannels + chan)*SampleSize; + + LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataSize); + SrcBuffer = SrcBuffer.subspan(DataSize); } else { - const al::span SrcData{SrcBuffer.first( - std::min(SrcBuffer.size(), LoopEnd - DataPosInt))}; + /* Load what's left of this loop iteration */ + const size_t DataSize{minz(SrcBuffer.size(), LoopEnd-DataPosInt)}; - auto load_buffer = [DataPosInt,NumChannels,SampleSize,chan,SrcData](size_t CompLen, const ALbuffer *buffer) -> size_t - { - if(DataPosInt >= buffer->SampleLen) - return CompLen; + const al::byte *Data{Buffer->mData.data()}; + Data += (DataPosInt*NumChannels + chan)*SampleSize; - /* Load what's left of this loop iteration */ - const size_t DataSize{std::min(SrcData.size(), - buffer->SampleLen - DataPosInt)}; - CompLen = std::max(CompLen, DataSize); - - const al::byte *Data{buffer->mData.data()}; - Data += (DataPosInt*NumChannels + chan)*SampleSize; - - LoadSamples(SrcData.data(), Data, NumChannels, buffer->mFmtType, DataSize); - return CompLen; - }; - ASSUME(BufferListItem->mNumBuffers > 0); - SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->begin(), - BufferListItem->end(), size_t{0u}, load_buffer)); + LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataSize); + SrcBuffer = SrcBuffer.subspan(DataSize); + /* Load any repeats of the loop we can to fill the buffer. */ const auto LoopSize = static_cast(LoopEnd - LoopStart); while(!SrcBuffer.empty()) { - const al::span SrcData{SrcBuffer.first( - std::min(SrcBuffer.size(), LoopSize))}; - - auto load_buffer_loop = [LoopStart,NumChannels,SampleSize,chan,SrcData](size_t CompLen, const ALbuffer *buffer) -> size_t - { - if(LoopStart >= buffer->SampleLen) - return CompLen; - - const size_t DataSize{std::min(SrcData.size(), - buffer->SampleLen-LoopStart)}; - CompLen = std::max(CompLen, DataSize); + const size_t DataSize{minz(SrcBuffer.size(), LoopSize)}; - const al::byte *Data{buffer->mData.data()}; - Data += (LoopStart*NumChannels + chan)*SampleSize; + const al::byte *Data{Buffer->mData.data()}; + Data += (LoopStart*NumChannels + chan)*SampleSize; - LoadSamples(SrcData.data(), Data, NumChannels, buffer->mFmtType, DataSize); - return CompLen; - }; - SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->begin(), - BufferListItem->end(), size_t{0u}, load_buffer_loop)); + LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataSize); + SrcBuffer = SrcBuffer.subspan(DataSize); } } return SrcBuffer.begin(); @@ -490,35 +449,24 @@ ALfloat *LoadBufferQueue(ALbufferlistitem *BufferListItem, ALbufferlistitem *Buf /* Crawl the buffer queue to fill in the temp buffer */ while(BufferListItem && !SrcBuffer.empty()) { - if(DataPosInt >= BufferListItem->mMaxSamples) + ALbuffer *Buffer{BufferListItem->mBuffer}; + if(!(Buffer && DataPosInt < Buffer->SampleLen)) { - DataPosInt -= BufferListItem->mMaxSamples; + if(Buffer) DataPosInt -= Buffer->SampleLen; BufferListItem = BufferListItem->mNext.load(std::memory_order_acquire); if(!BufferListItem) BufferListItem = BufferLoopItem; continue; } - auto load_buffer = [DataPosInt,NumChannels,SampleSize,chan,SrcBuffer](size_t CompLen, const ALbuffer *buffer) -> size_t - { - if(!buffer) return CompLen; - if(DataPosInt >= buffer->SampleLen) - return CompLen; + const size_t DataSize{std::min(SrcBuffer.size(), Buffer->SampleLen-DataPosInt)}; - const size_t DataSize{std::min(SrcBuffer.size(), buffer->SampleLen-DataPosInt)}; - CompLen = std::max(CompLen, DataSize); + const al::byte *Data{Buffer->mData.data()}; + Data += (DataPosInt*NumChannels + chan)*SampleSize; - const al::byte *Data{buffer->mData.data()}; - Data += (DataPosInt*NumChannels + chan)*SampleSize; + LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataSize); + SrcBuffer = SrcBuffer.subspan(DataSize); + if(SrcBuffer.empty()) break; - LoadSamples(SrcBuffer.data(), Data, NumChannels, buffer->mFmtType, DataSize); - return CompLen; - }; - ASSUME(BufferListItem->mNumBuffers > 0); - SrcBuffer = SrcBuffer.subspan(std::accumulate(BufferListItem->begin(), - BufferListItem->end(), size_t{0u}, load_buffer)); - - if(SrcBuffer.empty()) - break; DataPosInt = 0; BufferListItem = BufferListItem->mNext.load(std::memory_order_acquire); if(!BufferListItem) BufferListItem = BufferLoopItem; @@ -640,10 +588,11 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc ALvoice::ChannelData &chandata = voice->mChans[chan]; const al::span SrcData{Device->SourceData, SrcBufferSize}; - /* Load the previous samples into the source data first, and clear the rest. */ + /* Load the previous samples into the source data first, then load + * what we can from the buffer queue. + */ auto srciter = std::copy_n(chandata.mPrevSamples.begin(), MAX_RESAMPLE_PADDING, SrcData.begin()); - std::fill(srciter, SrcData.end(), 0.0f); if UNLIKELY(!BufferListItem) srciter = std::copy(chandata.mPrevSamples.begin()+MAX_RESAMPLE_PADDING, @@ -875,7 +824,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc if(BufferLoopItem) { /* Handle looping static source */ - const ALbuffer *Buffer{BufferListItem->front()}; + const ALbuffer *Buffer{BufferListItem->mBuffer}; const ALuint LoopStart{Buffer->LoopStart}; const ALuint LoopEnd{Buffer->LoopEnd}; if(DataPosInt >= LoopEnd) @@ -887,7 +836,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc else { /* Handle non-looping static source */ - if(DataPosInt >= BufferListItem->mMaxSamples) + if(DataPosInt >= BufferListItem->mSampleLen) { if LIKELY(vstate == ALvoice::Playing) vstate = ALvoice::Stopped; @@ -899,12 +848,12 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc else while(1) { /* Handle streaming source */ - if(BufferListItem->mMaxSamples > DataPosInt) + if(BufferListItem->mSampleLen > DataPosInt) break; - DataPosInt -= BufferListItem->mMaxSamples; + DataPosInt -= BufferListItem->mSampleLen; - buffers_done += BufferListItem->mNumBuffers; + ++buffers_done; BufferListItem = BufferListItem->mNext.load(std::memory_order_relaxed); if(!BufferListItem && !(BufferListItem=BufferLoopItem)) { -- cgit v1.2.3 From e200569cd319448d12099f27a2713c69da382d26 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Aug 2019 18:50:07 -0700 Subject: Move the wstr converters to a separate header --- CMakeLists.txt | 1 + alc/alc.cpp | 1 + alc/alconfig.cpp | 1 + alc/backends/dsound.cpp | 1 + alc/backends/wasapi.cpp | 1 + alc/backends/wave.cpp | 1 + alc/backends/winmm.cpp | 1 + alc/compat.h | 30 ------------------------------ alc/helpers.cpp | 1 + common/dynload.cpp | 21 +-------------------- common/strutils.h | 43 +++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 52 insertions(+), 50 deletions(-) create mode 100644 common/strutils.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6fe05f35..cfcfd6aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -604,6 +604,7 @@ SET(COMMON_OBJS common/intrusive_ptr.h common/math_defs.h common/opthelpers.h + common/strutils.h common/threads.cpp common/threads.h common/vecmat.h diff --git a/alc/alc.cpp b/alc/alc.cpp index c1989913..adead648 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -85,6 +85,7 @@ #include "mastering.h" #include "opthelpers.h" #include "ringbuffer.h" +#include "strutils.h" #include "threads.h" #include "uhjfilter.h" #include "vecmat.h" diff --git a/alc/alconfig.cpp b/alc/alconfig.cpp index e7632ef7..f6190b58 100644 --- a/alc/alconfig.cpp +++ b/alc/alconfig.cpp @@ -47,6 +47,7 @@ #include "alcmain.h" #include "logging.h" +#include "strutils.h" #include "compat.h" diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index b9e52c0c..ad182cf7 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -49,6 +49,7 @@ #include "ringbuffer.h" #include "compat.h" #include "dynload.h" +#include "strutils.h" #include "threads.h" /* MinGW-w64 needs this for some unknown reason now. */ diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index bd009463..cc53be66 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -59,6 +59,7 @@ #include "ringbuffer.h" #include "compat.h" #include "converter.h" +#include "strutils.h" #include "threads.h" diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp index 6ca2fab4..aa4130af 100644 --- a/alc/backends/wave.cpp +++ b/alc/backends/wave.cpp @@ -43,6 +43,7 @@ #include "compat.h" #include "endiantest.h" #include "logging.h" +#include "strutils.h" #include "threads.h" #include "vector.h" diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp index cd32e95b..b6787a24 100644 --- a/alc/backends/winmm.cpp +++ b/alc/backends/winmm.cpp @@ -40,6 +40,7 @@ #include "alcmain.h" #include "alu.h" #include "ringbuffer.h" +#include "strutils.h" #include "threads.h" #include "compat.h" diff --git a/alc/compat.h b/alc/compat.h index 648fa5b1..f2e10513 100644 --- a/alc/compat.h +++ b/alc/compat.h @@ -10,36 +10,6 @@ #include #include -inline std::string wstr_to_utf8(const WCHAR *wstr) -{ - std::string ret; - - int len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr); - if(len > 0) - { - ret.resize(len); - WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &ret[0], len, nullptr, nullptr); - ret.pop_back(); - } - - return ret; -} - -inline std::wstring utf8_to_wstr(const char *str) -{ - std::wstring ret; - - int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); - if(len > 0) - { - ret.resize(len); - MultiByteToWideChar(CP_UTF8, 0, str, -1, &ret[0], len); - ret.pop_back(); - } - - return ret; -} - namespace al { diff --git a/alc/helpers.cpp b/alc/helpers.cpp index b952c5ed..27219b03 100644 --- a/alc/helpers.cpp +++ b/alc/helpers.cpp @@ -106,6 +106,7 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x #include "cpu_caps.h" #include "fpu_modes.h" #include "logging.h" +#include "strutils.h" #include "vector.h" diff --git a/common/dynload.cpp b/common/dynload.cpp index 89824f78..98d2c521 100644 --- a/common/dynload.cpp +++ b/common/dynload.cpp @@ -3,29 +3,10 @@ #include "dynload.h" +#include "strutils.h" #ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include - -#include - -inline std::wstring utf8_to_wstr(const char *str) -{ - std::wstring ret; - - int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); - if(len > 0) - { - ret.resize(len); - MultiByteToWideChar(CP_UTF8, 0, str, -1, &ret[0], len); - ret.pop_back(); - } - - return ret; -} - void *LoadLib(const char *name) { std::wstring wname{utf8_to_wstr(name)}; diff --git a/common/strutils.h b/common/strutils.h new file mode 100644 index 00000000..2bfd15fc --- /dev/null +++ b/common/strutils.h @@ -0,0 +1,43 @@ +#ifndef AL_STRUTILS_H +#define AL_STRUTILS_H + +#ifdef _WIN32 + +#define WIN32_LEAN_AND_MEAN +#include + +#include + +inline std::string wstr_to_utf8(const WCHAR *wstr) +{ + std::string ret; + + int len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr); + if(len > 0) + { + ret.resize(len); + WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &ret[0], len, nullptr, nullptr); + ret.pop_back(); + } + + return ret; +} + +inline std::wstring utf8_to_wstr(const char *str) +{ + std::wstring ret; + + int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0); + if(len > 0) + { + ret.resize(len); + MultiByteToWideChar(CP_UTF8, 0, str, -1, &ret[0], len); + ret.pop_back(); + } + + return ret; +} + +#endif + +#endif /* AL_STRUTILS_H */ -- cgit v1.2.3 From f290bf275189726ebc81610ef4f1f667ca723fe3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Aug 2019 20:53:20 -0700 Subject: Move vector.h to common --- CMakeLists.txt | 2 +- alc/vector.h | 15 --------------- common/vector.h | 15 +++++++++++++++ 3 files changed, 16 insertions(+), 16 deletions(-) delete mode 100644 alc/vector.h create mode 100644 common/vector.h diff --git a/CMakeLists.txt b/CMakeLists.txt index cfcfd6aa..6ce57dc3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -608,6 +608,7 @@ SET(COMMON_OBJS common/threads.cpp common/threads.h common/vecmat.h + common/vector.h ) SET(OPENAL_OBJS al/auxeffectslot.cpp @@ -672,7 +673,6 @@ SET(ALC_OBJS alc/cpu_caps.h alc/fpu_modes.h alc/logging.h - alc/vector.h alc/hrtf.cpp alc/hrtf.h alc/uhjfilter.cpp diff --git a/alc/vector.h b/alc/vector.h deleted file mode 100644 index 1b69d6a7..00000000 --- a/alc/vector.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef AL_VECTOR_H -#define AL_VECTOR_H - -#include - -#include "almalloc.h" - -namespace al { - -template -using vector = std::vector>; - -} // namespace al - -#endif /* AL_VECTOR_H */ diff --git a/common/vector.h b/common/vector.h new file mode 100644 index 00000000..1b69d6a7 --- /dev/null +++ b/common/vector.h @@ -0,0 +1,15 @@ +#ifndef AL_VECTOR_H +#define AL_VECTOR_H + +#include + +#include "almalloc.h" + +namespace al { + +template +using vector = std::vector>; + +} // namespace al + +#endif /* AL_VECTOR_H */ -- cgit v1.2.3 From 50d16d2422febe2f4f56e7f29794778b10606b3a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Aug 2019 22:48:18 -0700 Subject: Don't use INT_MAX for unknown span lengths 32-bit doesn't like it, for some reason. Use the largest possible length it could be. --- al/source.cpp | 50 ++++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index 4bdf51fe..b20f6e81 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -737,6 +737,8 @@ void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) } +constexpr size_t MaxValues{6u}; + ALuint FloatValsByProp(ALenum prop) { switch(static_cast(prop)) @@ -866,20 +868,16 @@ bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a bool SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span values); #define CHECKSIZE(v, s) do { \ - if UNLIKELY((v).size() != INT_MAX && (v).size() != (s)) \ - { \ - Context->setError(AL_INVALID_ENUM, \ - "Property 0x%04x expects %d value(s), got %zu", prop, (s), \ - (v).size()); \ - return false; \ - } \ + if LIKELY((v).size() == (s) || (v).size() == MaxValues) break; \ + Context->setError(AL_INVALID_ENUM, \ + "Property 0x%04x expects %d value(s), got %zu", prop, (s), \ + (v).size()); \ + return false; \ } while(0) #define CHECKVAL(x) do { \ - if UNLIKELY(!(x)) \ - { \ - Context->setError(AL_INVALID_VALUE, "Value out of range"); \ - return false; \ - } \ + if LIKELY(x) break; \ + Context->setError(AL_INVALID_VALUE, "Value out of range"); \ + return false; \ } while(0) bool UpdateSourceProps(ALsource *source, ALCcontext *context) @@ -1434,8 +1432,8 @@ bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a bool SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span values) { - ALfloat fvals[6]; - ALint ivals[3]; + ALfloat fvals[MaxValues]; + ALint ivals[MaxValues]; switch(prop) { @@ -1553,7 +1551,7 @@ bool GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a ALCdevice *device{Context->mDevice.get()}; ClockLatency clocktime; std::chrono::nanoseconds srcclock; - ALint ivals[3]; + ALint ivals[MaxValues]; ALboolean err; switch(prop) @@ -1741,7 +1739,7 @@ bool GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a bool GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span values) { ALbufferlistitem *BufferList; - ALdouble dvals[6]; + ALdouble dvals[MaxValues]; ALboolean err; switch(prop) @@ -1926,8 +1924,8 @@ bool GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALCdevice *device = Context->mDevice.get(); ClockLatency clocktime; std::chrono::nanoseconds srcclock; - ALdouble dvals[6]; - ALint ivals[3]; + ALdouble dvals[MaxValues]; + ALint ivals[MaxValues]; ALboolean err; switch(prop) @@ -2199,7 +2197,7 @@ START_API_FUNC else if UNLIKELY(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); else - SetSourcefv(Source, context.get(), static_cast(param), {values, INT_MAX}); + SetSourcefv(Source, context.get(), static_cast(param), {values, MaxValues}); } END_API_FUNC @@ -2259,7 +2257,7 @@ START_API_FUNC else { const ALuint count{DoubleValsByProp(param)}; - ALfloat fvals[6]; + ALfloat fvals[MaxValues]; for(ALuint i{0};i < count;i++) fvals[i] = static_cast(values[i]); SetSourcefv(Source, context.get(), static_cast(param), {fvals, count}); @@ -2317,7 +2315,7 @@ START_API_FUNC else if UNLIKELY(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); else - SetSourceiv(Source, context.get(), static_cast(param), {values, INT_MAX}); + SetSourceiv(Source, context.get(), static_cast(param), {values, MaxValues}); } END_API_FUNC @@ -2371,7 +2369,7 @@ START_API_FUNC else if UNLIKELY(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); else - SetSourcei64v(Source, context.get(), static_cast(param), {values, INT_MAX}); + SetSourcei64v(Source, context.get(), static_cast(param), {values, MaxValues}); } END_API_FUNC @@ -2437,7 +2435,7 @@ START_API_FUNC else { const ALuint count{FloatValsByProp(param)}; - ALdouble dvals[6]; + ALdouble dvals[MaxValues]; if(GetSourcedv(Source, context.get(), static_cast(param), {dvals, count})) { for(ALuint i{0};i < count;i++) @@ -2503,7 +2501,7 @@ START_API_FUNC else if UNLIKELY(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); else - GetSourcedv(Source, context.get(), static_cast(param), {values, INT_MAX}); + GetSourcedv(Source, context.get(), static_cast(param), {values, MaxValues}); } END_API_FUNC @@ -2563,7 +2561,7 @@ START_API_FUNC else if UNLIKELY(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); else - GetSourceiv(Source, context.get(), static_cast(param), {values, INT_MAX}); + GetSourceiv(Source, context.get(), static_cast(param), {values, MaxValues}); } END_API_FUNC @@ -2623,7 +2621,7 @@ START_API_FUNC else if UNLIKELY(!values) context->setError(AL_INVALID_VALUE, "NULL pointer"); else - GetSourcei64v(Source, context.get(), static_cast(param), {values, INT_MAX}); + GetSourcei64v(Source, context.get(), static_cast(param), {values, MaxValues}); } END_API_FUNC -- cgit v1.2.3 From 1aaf65abfecbde8548f90b1d0b0308b21bd0776d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Aug 2019 03:59:52 -0700 Subject: Add methods to get env vars as an optional --- CMakeLists.txt | 1 + al/state.cpp | 5 ++-- alc/alc.cpp | 68 ++++++++++++++++++++++----------------------- alc/alconfig.cpp | 54 +++++++++++++++++------------------ alc/alu.cpp | 17 ++++++++---- alc/backends/pulseaudio.cpp | 5 ++-- alc/helpers.cpp | 39 +++++++++++++------------- common/strutils.cpp | 27 ++++++++++++++++++ common/strutils.h | 15 ++++++++-- 9 files changed, 137 insertions(+), 94 deletions(-) create mode 100644 common/strutils.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ce57dc3..c11d311c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -604,6 +604,7 @@ SET(COMMON_OBJS common/intrusive_ptr.h common/math_defs.h common/opthelpers.h + common/strutils.cpp common/strutils.h common/threads.cpp common/threads.h diff --git a/al/state.cpp b/al/state.cpp index 8c95c22f..884aa9d2 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -42,6 +42,7 @@ #include "event.h" #include "inprogext.h" #include "opthelpers.h" +#include "strutils.h" namespace { @@ -73,8 +74,8 @@ constexpr ALchar alBSinc24Resampler[] = "23rd order Sinc"; extern "C" AL_API const ALchar* AL_APIENTRY alsoft_get_version(void) START_API_FUNC { - const char *spoof{getenv("ALSOFT_SPOOF_VERSION")}; - if(spoof && spoof[0] != '\0') return spoof; + static const auto spoof = al::getenv("ALSOFT_SPOOF_VERSION"); + if(spoof) return spoof->c_str(); return ALSOFT_VERSION; } END_API_FUNC diff --git a/alc/alc.cpp b/alc/alc.cpp index adead648..d4cf040a 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -929,25 +929,23 @@ std::recursive_mutex ListLock; void alc_initconfig(void) { - const char *str{getenv("ALSOFT_LOGLEVEL")}; - if(str) + if(auto loglevel = al::getenv("ALSOFT_LOGLEVEL")) { - long lvl = strtol(str, nullptr, 0); + long lvl = strtol(loglevel->c_str(), nullptr, 0); if(lvl >= NoLog && lvl <= LogRef) gLogLevel = static_cast(lvl); } - str = getenv("ALSOFT_LOGFILE"); - if(str && str[0]) + if(auto logfile = al::getenv("ALSOFT_LOGFILE")) { #ifdef _WIN32 - std::wstring wname{utf8_to_wstr(str)}; - FILE *logfile = _wfopen(wname.c_str(), L"wt"); + std::wstring wname{utf8_to_wstr(logfile->c_str())}; + FILE *logf{_wfopen(wname.c_str(), L"wt")}; #else - FILE *logfile = fopen(str, "wt"); + FILE *logf{fopen(logfile->c_str(), "wt")}; #endif - if(logfile) gLogFile = logfile; - else ERR("Failed to open log file '%s'\n", str); + if(logf) gLogFile = logf; + else ERR("Failed to open log file '%s'\n", logfile->c_str()); } TRACE("Initializing library v%s-%s %s\n", ALSOFT_VERSION, ALSOFT_GIT_COMMIT_HASH, @@ -970,16 +968,15 @@ void alc_initconfig(void) } ReadALConfig(); - str = getenv("__ALSOFT_SUSPEND_CONTEXT"); - if(str && *str) + if(auto suspendmode = al::getenv("__ALSOFT_SUSPEND_CONTEXT")) { - if(strcasecmp(str, "ignore") == 0) + if(strcasecmp(suspendmode->c_str(), "ignore") == 0) { SuspendDefers = false; TRACE("Selected context suspend behavior, \"ignore\"\n"); } else - ERR("Unhandled context suspend behavior setting: \"%s\"\n", str); + ERR("Unhandled context suspend behavior setting: \"%s\"\n", suspendmode->c_str()); } int capfilter{0}; @@ -997,7 +994,7 @@ void alc_initconfig(void) #endif if(auto cpuopt = ConfigValueStr(nullptr, nullptr, "disable-cpu-exts")) { - str = cpuopt->c_str(); + const char *str{cpuopt->c_str()}; if(strcasecmp(str, "all") == 0) capfilter = 0; else @@ -1043,22 +1040,31 @@ void alc_initconfig(void) aluInit(); aluInitMixer(); - str = getenv("ALSOFT_TRAP_ERROR"); - if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) + auto traperr = al::getenv("ALSOFT_TRAP_ERROR"); + if(traperr && (strcasecmp(traperr->c_str(), "true") == 0 + || strtol(traperr->c_str(), nullptr, 0) == 1)) { TrapALError = true; TrapALCError = true; } else { - str = getenv("ALSOFT_TRAP_AL_ERROR"); - if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) - TrapALError = true; + traperr = al::getenv("ALSOFT_TRAP_AL_ERROR"); + if(traperr) + { + if(strcasecmp(traperr->c_str(), "true") == 0 + || strtol(traperr->c_str(), nullptr, 0) == 1) + TrapALError = true; + } TrapALError = !!GetConfigValueBool(nullptr, nullptr, "trap-al-error", TrapALError); - str = getenv("ALSOFT_TRAP_ALC_ERROR"); - if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) + traperr = al::getenv("ALSOFT_TRAP_ALC_ERROR"); + if(traperr) + { + if(strcasecmp(traperr->c_str(), "true") == 0 + || strtol(traperr->c_str(), nullptr, 0) == 1) TrapALCError = true; + } TrapALCError = !!GetConfigValueBool(nullptr, nullptr, "trap-alc-error", TrapALCError); } @@ -1068,13 +1074,8 @@ void alc_initconfig(void) ReverbBoost *= std::pow(10.0f, valf / 20.0f); } - auto devopt = ConfigValueStr(nullptr, nullptr, "drivers"); - if(const char *devs{getenv("ALSOFT_DRIVERS")}) - { - if(devs[0]) - devopt = devs; - } - if(devopt) + auto devopt = al::getenv("ALSOFT_DRIVERS"); + if(devopt || (devopt=ConfigValueStr(nullptr, nullptr, "drivers"))) { auto backendlist_cur = std::begin(BackendList); @@ -1165,7 +1166,7 @@ void alc_initconfig(void) { const char *next{exclopt->c_str()}; do { - str = next; + const char *str{next}; next = strchr(str, ','); if(!str[0] || next == str) @@ -1182,10 +1183,9 @@ void alc_initconfig(void) } InitEffect(&DefaultEffect); - auto defrevopt = ConfigValueStr(nullptr, nullptr, "default-reverb"); - if((str=getenv("ALSOFT_DEFAULT_REVERB")) && str[0]) - defrevopt = str; - if(defrevopt) LoadReverbPreset(defrevopt->c_str(), &DefaultEffect); + auto defrevopt = al::getenv("ALSOFT_DEFAULT_REVERB"); + if(defrevopt || (defrevopt=ConfigValueStr(nullptr, nullptr, "default-reverb"))) + LoadReverbPreset(defrevopt->c_str(), &DefaultEffect); } #define DO_INITCONFIG() std::call_once(alc_config_once, [](){alc_initconfig();}) diff --git a/alc/alconfig.cpp b/alc/alconfig.cpp index f6190b58..93c37703 100644 --- a/alc/alconfig.cpp +++ b/alc/alconfig.cpp @@ -81,6 +81,7 @@ std::string expdup(const char *str) { std::string output; + std::string envval; while(*str != '\0') { const char *addstr; @@ -107,20 +108,20 @@ std::string expdup(const char *str) } else { - bool hasbraces{(*str == '{')}; - if(hasbraces) str++; - - std::string envname; - while((std::isalnum(*str) || *str == '_')) - envname += *(str++); + const bool hasbraces{(*str == '{')}; + if(hasbraces) str++; + const char *envstart = str; + while(std::isalnum(*str) || *str == '_') + ++str; if(hasbraces && *str != '}') continue; - + const std::string envname{envstart, str}; if(hasbraces) str++; - if((addstr=std::getenv(envname.c_str())) == nullptr) - continue; - addstrlen = std::strlen(addstr); + + envval = al::getenv(envname.c_str()).value_or(std::string{}); + addstr = envval.data(); + addstrlen = envval.length(); } } if(addstrlen == 0) @@ -308,18 +309,17 @@ void ReadALConfig() LoadConfigFromFile(f); } - const WCHAR *str{_wgetenv(L"ALSOFT_CONF")}; - if(str != nullptr && *str) + if(auto confpath = al::getenv(L"ALSOFT_CONF")) { - std::string filepath{wstr_to_utf8(str)}; - - TRACE("Loading config %s...\n", filepath.c_str()); - al::ifstream f{filepath}; + TRACE("Loading config %s...\n", wstr_to_utf8(confpath->c_str()).c_str()); + al::ifstream f{*confpath}; if(f.is_open()) LoadConfigFromFile(f); } } + #else + void ReadALConfig() { const char *str{"/etc/openal/alsoft.conf"}; @@ -330,9 +330,7 @@ void ReadALConfig() LoadConfigFromFile(f); f.close(); - if(!(str=getenv("XDG_CONFIG_DIRS")) || str[0] == 0) - str = "/etc/xdg"; - std::string confpaths = str; + std::string confpaths{al::getenv("XDG_CONFIG_DIRS").value_or("/etc/xdg")}; /* Go through the list in reverse, since "the order of base directories * denotes their importance; the first directory listed is the most * important". Ergo, we need to load the settings from the later dirs @@ -385,9 +383,9 @@ void ReadALConfig() } #endif - if((str=getenv("HOME")) != nullptr && *str) + if(auto homedir = al::getenv("HOME")) { - fname = str; + fname = *homedir; if(fname.back() != '/') fname += "/.alsoftrc"; else fname += ".alsoftrc"; @@ -397,18 +395,18 @@ void ReadALConfig() LoadConfigFromFile(f); } - if((str=getenv("XDG_CONFIG_HOME")) != nullptr && str[0] != 0) + if(auto configdir = al::getenv("XDG_CONFIG_HOME")) { - fname = str; + fname = *configdir; if(fname.back() != '/') fname += "/alsoft.conf"; else fname += "alsoft.conf"; } else { fname.clear(); - if((str=getenv("HOME")) != nullptr && str[0] != 0) + if(auto homedir = al::getenv("HOME")) { - fname = str; + fname = *homedir; if(fname.back() != '/') fname += "/.config/alsoft.conf"; else fname += ".config/alsoft.conf"; } @@ -433,10 +431,10 @@ void ReadALConfig() LoadConfigFromFile(f); } - if((str=getenv("ALSOFT_CONF")) != nullptr && *str) + if(auto confname = al::getenv("ALSOFT_CONF")) { - TRACE("Loading config %s...\n", str); - al::ifstream f{str}; + TRACE("Loading config %s...\n", confname->c_str()); + al::ifstream f{*confname}; if(f.is_open()) LoadConfigFromFile(f); } diff --git a/alc/alu.cpp b/alc/alu.cpp index 8cef4228..aebb2236 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -73,6 +73,7 @@ #include "mixer/defs.h" #include "opthelpers.h" #include "ringbuffer.h" +#include "strutils.h" #include "threads.h" #include "uhjfilter.h" #include "vecmat.h" @@ -87,18 +88,22 @@ using namespace std::placeholders; ALfloat InitConeScale() { ALfloat ret{1.0f}; - const char *str{getenv("__ALSOFT_HALF_ANGLE_CONES")}; - if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) - ret *= 0.5f; + if(auto optval = al::getenv("__ALSOFT_HALF_ANGLE_CONES")) + { + if(strcasecmp(optval->c_str(), "true") == 0 || strtol(optval->c_str(), nullptr, 0) == 1) + ret *= 0.5f; + } return ret; } ALfloat InitZScale() { ALfloat ret{1.0f}; - const char *str{getenv("__ALSOFT_REVERSE_Z")}; - if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) - ret *= -1.0f; + if(auto optval = al::getenv("__ALSOFT_REVERSE_Z")) + { + if(strcasecmp(optval->c_str(), "true") == 0 || strtol(optval->c_str(), nullptr, 0) == 1) + ret *= -1.0f; + } return ret; } diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index ca2ecb43..499a192f 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -40,6 +40,7 @@ #include "alexcpt.h" #include "compat.h" #include "dynload.h" +#include "strutils.h" #include @@ -855,8 +856,8 @@ ALCenum PulsePlayback::open(const ALCchar *name) if(!pulse_name) { - pulse_name = getenv("ALSOFT_PULSE_DEFAULT"); - if(pulse_name && !pulse_name[0]) pulse_name = nullptr; + static const auto defname = al::getenv("ALSOFT_PULSE_DEFAULT"); + if(defname) pulse_name = defname->c_str(); } TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); mStream = pulse_connect_stream(pulse_name, plock, mContext, flags, nullptr, &spec, nullptr, diff --git a/alc/helpers.cpp b/alc/helpers.cpp index 27219b03..daf09de0 100644 --- a/alc/helpers.cpp +++ b/alc/helpers.cpp @@ -530,22 +530,21 @@ al::vector SearchDataFiles(const char *ext, const char *subdir) std::string path; /* Search the app-local directory. */ - WCHAR *cwdbuf{_wgetenv(L"ALSOFT_LOCAL_PATH")}; - if(cwdbuf && *cwdbuf != '\0') + if(auto localpath = al::getenv(L"ALSOFT_LOCAL_PATH")) { - path = wstr_to_utf8(cwdbuf); + path = wstr_to_utf8(localpath->c_str()); if(is_slash(path.back())) path.pop_back(); } - else if(!(cwdbuf=_wgetcwd(nullptr, 0))) - path = "."; - else + else if(WCHAR *cwdbuf{_wgetcwd(nullptr, 0)}) { path = wstr_to_utf8(cwdbuf); if(is_slash(path.back())) path.pop_back(); free(cwdbuf); } + else + path = "."; std::replace(path.begin(), path.end(), '/', '\\'); DirectorySearch(path.c_str(), ext, &results); @@ -725,9 +724,8 @@ al::vector SearchDataFiles(const char *ext, const char *subdir) } /* Search the app-local directory. */ - const char *str{getenv("ALSOFT_LOCAL_PATH")}; - if(str && *str != '\0') - DirectorySearch(str, ext, &results); + if(auto localpath = al::getenv("ALSOFT_LOCAL_PATH")) + DirectorySearch(localpath->c_str(), ext, &results); else { al::vector cwdbuf(256); @@ -750,17 +748,17 @@ al::vector SearchDataFiles(const char *ext, const char *subdir) } // Search local data dir - if((str=getenv("XDG_DATA_HOME")) != nullptr && str[0] != '\0') + if(auto datapath = al::getenv("XDG_DATA_HOME")) { - std::string path{str}; + std::string &path = *datapath; if(path.back() != '/') path += '/'; path += subdir; DirectorySearch(path.c_str(), ext, &results); } - else if((str=getenv("HOME")) != nullptr && str[0] != '\0') + else if(auto homepath = al::getenv("HOME")) { - std::string path{str}; + std::string &path = *homepath; if(path.back() == '/') path.pop_back(); path += "/.local/share/"; @@ -769,17 +767,18 @@ al::vector SearchDataFiles(const char *ext, const char *subdir) } // Search global data dirs - if((str=getenv("XDG_DATA_DIRS")) == nullptr || str[0] == '\0') - str = "/usr/local/share/:/usr/share/"; + std::string datadirs{al::getenv("XDG_DATA_DIRS").value_or("/usr/local/share/:/usr/share/")}; - const char *next{str}; - while((str=next) != nullptr && str[0] != '\0') + size_t curpos{0u}; + while(curpos < datadirs.size()) { - next = strchr(str, ':'); + size_t nextpos{datadirs.find(':', curpos)}; - std::string path = (next ? std::string(str, next++) : std::string(str)); - if(path.empty()) continue; + std::string path{(nextpos != std::string::npos) ? + datadirs.substr(curpos, nextpos++ - curpos) : datadirs.substr(curpos)}; + curpos = nextpos; + if(path.empty()) continue; if(path.back() != '/') path += '/'; path += subdir; diff --git a/common/strutils.cpp b/common/strutils.cpp new file mode 100644 index 00000000..0163de7b --- /dev/null +++ b/common/strutils.cpp @@ -0,0 +1,27 @@ + +#include "config.h" + +#include "strutils.h" + +#include + + +namespace al { + +al::optional getenv(const char *envname) +{ + const char *str{std::getenv(envname)}; + if(str && str[0] != '\0') return str; + return al::nullopt; +} + +#ifdef _WIN32 +al::optional getenv(const WCHAR *envname) +{ + const WCHAR *str{_wgetenv(envname)}; + if(str && str[0] != L'\0') return str; + return al::nullopt; +} +#endif + +} // namespace al diff --git a/common/strutils.h b/common/strutils.h index 2bfd15fc..db9b07c6 100644 --- a/common/strutils.h +++ b/common/strutils.h @@ -1,12 +1,14 @@ #ifndef AL_STRUTILS_H #define AL_STRUTILS_H -#ifdef _WIN32 +#include + +#include "aloptional.h" +#ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include -#include inline std::string wstr_to_utf8(const WCHAR *wstr) { @@ -40,4 +42,13 @@ inline std::wstring utf8_to_wstr(const char *str) #endif +namespace al { + +al::optional getenv(const char *envname); +#ifdef _WIN32 +al::optional getenv(const WCHAR *envname); +#endif + +} // namespace al + #endif /* AL_STRUTILS_H */ -- cgit v1.2.3 From 81d17bb80f77cc5d078547b5fb102a2b44fecee0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Aug 2019 14:30:47 -0700 Subject: Fix some return types --- al/source.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index b20f6e81..018e49a0 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -1552,7 +1552,7 @@ bool GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a ClockLatency clocktime; std::chrono::nanoseconds srcclock; ALint ivals[MaxValues]; - ALboolean err; + bool err; switch(prop) { @@ -1719,7 +1719,7 @@ bool GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a case AL_SOURCE_RESAMPLER_SOFT: case AL_SOURCE_SPATIALIZE_SOFT: CHECKSIZE(values, 1); - if((err=GetSourceiv(Source, Context, prop, {ivals, 1u})) != AL_FALSE) + if((err=GetSourceiv(Source, Context, prop, {ivals, 1u})) != false) values[0] = static_cast(ivals[0]); return err; @@ -1740,7 +1740,7 @@ bool GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a { ALbufferlistitem *BufferList; ALdouble dvals[MaxValues]; - ALboolean err; + bool err; switch(prop) { @@ -1926,7 +1926,7 @@ bool GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const std::chrono::nanoseconds srcclock; ALdouble dvals[MaxValues]; ALint ivals[MaxValues]; - ALboolean err; + bool err; switch(prop) { @@ -1956,7 +1956,7 @@ bool GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const CHECKSIZE(values, 2); values[0] = GetSourceSampleOffset(Source, Context, &srcclock); values[1] = srcclock.count(); - return AL_TRUE; + return true; /* 1x float/double */ case AL_CONE_INNER_ANGLE: -- cgit v1.2.3 From dff906c13b57d3c18b973bc282668c2665f653a4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Aug 2019 14:32:04 -0700 Subject: Remove always-true assumption --- alc/mixvoice.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 295b1352..c8833ed3 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -398,7 +398,6 @@ ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&B const ALbuffer *Buffer{BufferListItem->mBuffer}; const ALuint LoopStart{Buffer->LoopStart}; const ALuint LoopEnd{Buffer->LoopEnd}; - ASSUME(LoopStart >= 0); ASSUME(LoopEnd > LoopStart); /* If current pos is beyond the loop range, do not loop */ -- cgit v1.2.3 From 38a565bdf8ab9f7da601dd12f03cdc8f9b37f23c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Aug 2019 14:56:17 -0700 Subject: Move UID definitions to a separate source --- CMakeLists.txt | 35 ++++++++++++++++++----------------- alc/helpers.cpp | 50 +++++++++----------------------------------------- alc/uiddefs.cpp | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 58 deletions(-) create mode 100644 alc/uiddefs.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c11d311c..7626c1ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -619,6 +619,8 @@ SET(OPENAL_OBJS al/effect.cpp al/effect.h al/error.cpp + al/event.cpp + al/event.h al/extension.cpp al/filter.cpp al/filter.h @@ -627,8 +629,6 @@ SET(OPENAL_OBJS al/source.cpp al/source.h al/state.cpp - al/event.cpp - al/event.h ) SET(ALC_OBJS alc/alc.cpp @@ -638,17 +638,18 @@ SET(ALC_OBJS alc/alconfig.cpp alc/alconfig.h alc/alcontext.h + alc/ambdec.cpp + alc/ambdec.h alc/ambidefs.h + alc/bformatdec.cpp + alc/bformatdec.h alc/bs2b.cpp alc/bs2b.h + alc/compat.h alc/converter.cpp alc/converter.h + alc/cpu_caps.h alc/devformat.h - alc/inprogext.h - alc/mastering.cpp - alc/mastering.h - alc/ringbuffer.cpp - alc/ringbuffer.h alc/effects/base.h alc/effects/autowah.cpp alc/effects/chorus.cpp @@ -669,21 +670,21 @@ SET(ALC_OBJS alc/filters/nfc.h alc/filters/splitter.cpp alc/filters/splitter.h - alc/helpers.cpp - alc/compat.h - alc/cpu_caps.h alc/fpu_modes.h - alc/logging.h + alc/helpers.cpp alc/hrtf.cpp alc/hrtf.h + alc/inprogext.h + alc/logging.h + alc/mastering.cpp + alc/mastering.h + alc/mixvoice.cpp + alc/panning.cpp + alc/ringbuffer.cpp + alc/ringbuffer.h alc/uhjfilter.cpp alc/uhjfilter.h - alc/ambdec.cpp - alc/ambdec.h - alc/bformatdec.cpp - alc/bformatdec.h - alc/panning.cpp - alc/mixvoice.cpp + alc/uiddefs.cpp alc/mixer/defs.h alc/mixer/hrtfbase.h alc/mixer/mixer_c.cpp diff --git a/alc/helpers.cpp b/alc/helpers.cpp index daf09de0..ba95c0f8 100644 --- a/alc/helpers.cpp +++ b/alc/helpers.cpp @@ -40,47 +40,6 @@ #ifdef HAVE_DIRENT_H #include #endif -#ifdef HAVE_PROC_PIDPATH -#include -#endif - -#ifdef __FreeBSD__ -#include -#include -#endif - -#ifndef AL_NO_UID_DEFS -#if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H) -#define INITGUID -#include -#ifdef HAVE_GUIDDEF_H -#include -#else -#include -#endif - -DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71); -DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71); - -DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf,0x08, 0x00,0xa0,0xc9,0x25,0xcd,0x16); - -DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e,0x3d, 0xc4,0x57,0x92,0x91,0x69,0x2e); -DEFINE_GUID(IID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6); -DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2); -DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2); -DEFINE_GUID(IID_IAudioCaptureClient, 0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x18,0x5c,0x39,0x5c,0xd3,0x17); - -#ifdef HAVE_WASAPI -#include -#include -#include -DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); -DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); -DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23,0xe0, 0xc0,0xff,0xee,0x7f,0x0e, 4 ); -#endif -#endif -#endif /* AL_NO_UID_DEFS */ - #ifdef HAVE_INTRIN_H #include #endif @@ -94,6 +53,15 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x #include #endif +#ifdef HAVE_PROC_PIDPATH +#include +#endif + +#ifdef __FreeBSD__ +#include +#include +#endif + #ifndef _WIN32 #include #elif defined(_WIN32_IE) diff --git a/alc/uiddefs.cpp b/alc/uiddefs.cpp new file mode 100644 index 00000000..244c01a5 --- /dev/null +++ b/alc/uiddefs.cpp @@ -0,0 +1,37 @@ + +#include "config.h" + + +#ifndef AL_NO_UID_DEFS + +#if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H) +#define INITGUID +#include +#ifdef HAVE_GUIDDEF_H +#include +#else +#include +#endif + +DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71); +DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71); + +DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf,0x08, 0x00,0xa0,0xc9,0x25,0xcd,0x16); + +DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e,0x3d, 0xc4,0x57,0x92,0x91,0x69,0x2e); +DEFINE_GUID(IID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6); +DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2); +DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2); +DEFINE_GUID(IID_IAudioCaptureClient, 0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x18,0x5c,0x39,0x5c,0xd3,0x17); + +#ifdef HAVE_WASAPI +#include +#include +#include +DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23,0xe0, 0xc0,0xff,0xee,0x7f,0x0e, 4 ); +#endif +#endif + +#endif /* AL_NO_UID_DEFS */ -- cgit v1.2.3 From bc9f39b5ac69b34cb3d278e5573dc63811a0c442 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Aug 2019 17:10:04 -0700 Subject: Environment variables should override config settings --- alc/alc.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index d4cf040a..6a39ab46 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -1051,21 +1051,17 @@ void alc_initconfig(void) { traperr = al::getenv("ALSOFT_TRAP_AL_ERROR"); if(traperr) - { - if(strcasecmp(traperr->c_str(), "true") == 0 - || strtol(traperr->c_str(), nullptr, 0) == 1) - TrapALError = true; - } - TrapALError = !!GetConfigValueBool(nullptr, nullptr, "trap-al-error", TrapALError); + TrapALError = strcasecmp(traperr->c_str(), "true") == 0 + || strtol(traperr->c_str(), nullptr, 0) == 1; + else + TrapALError = !!GetConfigValueBool(nullptr, nullptr, "trap-al-error", false); traperr = al::getenv("ALSOFT_TRAP_ALC_ERROR"); if(traperr) - { - if(strcasecmp(traperr->c_str(), "true") == 0 - || strtol(traperr->c_str(), nullptr, 0) == 1) - TrapALCError = true; - } - TrapALCError = !!GetConfigValueBool(nullptr, nullptr, "trap-alc-error", TrapALCError); + TrapALCError = strcasecmp(traperr->c_str(), "true") == 0 + || strtol(traperr->c_str(), nullptr, 0) == 1; + else + TrapALCError = !!GetConfigValueBool(nullptr, nullptr, "trap-alc-error", false); } if(auto boostopt = ConfigValueFloat(nullptr, "reverb", "boost")) -- cgit v1.2.3 From 91ff01d1ad3c2995266902f41454c04e2b6e5d47 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Aug 2019 20:33:26 -0700 Subject: Don't explicitly inline a particular function --- al/source.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/al/source.cpp b/al/source.cpp index 018e49a0..95c3305e 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -74,7 +74,7 @@ namespace { using namespace std::placeholders; -inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) +ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) { ALuint idx{source->VoiceIdx}; if(idx < context->mVoiceCount.load(std::memory_order_relaxed)) -- cgit v1.2.3 From 0806a003e2b359b173b84548d8b78a25e8b51ca3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Aug 2019 20:33:44 -0700 Subject: Use new/delete for listener properties --- al/listener.cpp | 2 +- al/listener.h | 3 +++ alc/alc.cpp | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/al/listener.cpp b/al/listener.cpp index bcee0b08..402d8a27 100644 --- a/al/listener.cpp +++ b/al/listener.cpp @@ -421,7 +421,7 @@ void UpdateListenerProps(ALCcontext *context) /* Get an unused proprty container, or allocate a new one as needed. */ ALlistenerProps *props{context->mFreeListenerProps.load(std::memory_order_acquire)}; if(!props) - props = static_cast(al_calloc(16, sizeof(*props))); + props = new ALlistenerProps{}; else { ALlistenerProps *next; diff --git a/al/listener.h b/al/listener.h index 05d93d19..1b440bca 100644 --- a/al/listener.h +++ b/al/listener.h @@ -8,6 +8,7 @@ #include "AL/alc.h" #include "AL/efx.h" +#include "almalloc.h" #include "vecmat.h" enum class DistanceModel; @@ -22,6 +23,8 @@ struct ALlistenerProps { ALfloat MetersPerUnit; std::atomic next; + + DEF_NEWDEL(ALlistenerProps) }; struct ALlistener { diff --git a/alc/alc.cpp b/alc/alc.cpp index 6a39ab46..ca7dbb0f 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -2386,14 +2386,14 @@ ALCcontext::~ALCcontext() if(lprops) { TRACE("Freed unapplied listener update %p\n", lprops); - al_free(lprops); + delete lprops; } count = 0; lprops = mFreeListenerProps.exchange(nullptr, std::memory_order_acquire); while(lprops) { ALlistenerProps *next{lprops->next.load(std::memory_order_relaxed)}; - al_free(lprops); + delete lprops; lprops = next; ++count; } -- cgit v1.2.3 From ecab99bce914c6c74351fb2d5878dd82d73b1fe2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Aug 2019 22:06:14 -0700 Subject: Move update pointers to the containers they update --- al/auxeffectslot.cpp | 4 ++-- al/auxeffectslot.h | 4 ++-- al/listener.cpp | 2 +- al/listener.h | 9 +++++---- alc/alc.cpp | 2 +- alc/alu.cpp | 4 ++-- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index a0b8840f..e2dccb4d 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -706,7 +706,7 @@ ALeffectslot::~ALeffectslot() DecrementRef(Target->ref); Target = nullptr; - ALeffectslotProps *props{Update.load()}; + ALeffectslotProps *props{Params.Update.load()}; if(props) { if(props->State) props->State->release(); @@ -750,7 +750,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) props->State = slot->Effect.State; /* Set the new container for updating internal parameters. */ - props = slot->Update.exchange(props, std::memory_order_acq_rel); + props = slot->Params.Update.exchange(props, std::memory_order_acq_rel); if(props) { /* If there was an unused update container, put it back in the diff --git a/al/auxeffectslot.h b/al/auxeffectslot.h index 369638a0..9acb6d6b 100644 --- a/al/auxeffectslot.h +++ b/al/auxeffectslot.h @@ -51,9 +51,9 @@ struct ALeffectslot { RefCount ref{0u}; - std::atomic Update{nullptr}; - struct { + std::atomic Update{nullptr}; + ALfloat Gain{1.0f}; ALboolean AuxSendAuto{AL_TRUE}; ALeffectslot *Target{nullptr}; diff --git a/al/listener.cpp b/al/listener.cpp index 402d8a27..7a14a9ba 100644 --- a/al/listener.cpp +++ b/al/listener.cpp @@ -441,7 +441,7 @@ void UpdateListenerProps(ALCcontext *context) props->MetersPerUnit = listener.mMetersPerUnit; /* Set the new container for updating internal parameters. */ - props = listener.Update.exchange(props, std::memory_order_acq_rel); + props = listener.Params.Update.exchange(props, std::memory_order_acq_rel); if(props) { /* If there was an unused update container, put it back in the diff --git a/al/listener.h b/al/listener.h index 1b440bca..318ab024 100644 --- a/al/listener.h +++ b/al/listener.h @@ -37,11 +37,12 @@ struct ALlistener { std::atomic_flag PropsClean; - /* Pointer to the most recent property values that are awaiting an update. - */ - std::atomic Update{nullptr}; - struct { + /* Pointer to the most recent property values that are awaiting an + * update. + */ + std::atomic Update{nullptr}; + alu::Matrix Matrix; alu::Vector Velocity; diff --git a/alc/alc.cpp b/alc/alc.cpp index ca7dbb0f..baf31993 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -2382,7 +2382,7 @@ ALCcontext::~ALCcontext() mVoices = nullptr; mVoiceCount.store(0, std::memory_order_relaxed); - ALlistenerProps *lprops{mListener.Update.exchange(nullptr, std::memory_order_relaxed)}; + ALlistenerProps *lprops{mListener.Params.Update.exchange(nullptr, std::memory_order_relaxed)}; if(lprops) { TRACE("Freed unapplied listener update %p\n", lprops); diff --git a/alc/alu.cpp b/alc/alu.cpp index aebb2236..4a0ea8f9 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -286,7 +286,7 @@ bool CalcListenerParams(ALCcontext *Context) { ALlistener &Listener = Context->mListener; - ALlistenerProps *props{Listener.Update.exchange(nullptr, std::memory_order_acq_rel)}; + ALlistenerProps *props{Listener.Params.Update.exchange(nullptr, std::memory_order_acq_rel)}; if(!props) return false; /* AT then UP */ @@ -321,7 +321,7 @@ bool CalcListenerParams(ALCcontext *Context) bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context) { - ALeffectslotProps *props{slot->Update.exchange(nullptr, std::memory_order_acq_rel)}; + ALeffectslotProps *props{slot->Params.Update.exchange(nullptr, std::memory_order_acq_rel)}; if(!props) return false; slot->Params.Gain = props->Gain; -- cgit v1.2.3 From 351ccf2e11cfc429eeb76f7812565d0ed27043d5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Aug 2019 22:25:59 -0700 Subject: Use new/delete for context and effectslot properties --- al/auxeffectslot.cpp | 4 ++-- al/auxeffectslot.h | 2 ++ al/state.cpp | 2 +- alc/alc.cpp | 6 +++--- alc/alcontext.h | 2 ++ 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index e2dccb4d..b2f2c249 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -711,7 +711,7 @@ ALeffectslot::~ALeffectslot() { if(props->State) props->State->release(); TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props); - al_free(props); + delete props; } if(Effect.State) @@ -725,7 +725,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) /* Get an unused property container, or allocate a new one as needed. */ ALeffectslotProps *props{context->mFreeEffectslotProps.load(std::memory_order_relaxed)}; if(!props) - props = static_cast(al_calloc(16, sizeof(*props))); + props = new ALeffectslotProps{}; else { ALeffectslotProps *next; diff --git a/al/auxeffectslot.h b/al/auxeffectslot.h index 9acb6d6b..a6eb94f9 100644 --- a/al/auxeffectslot.h +++ b/al/auxeffectslot.h @@ -32,6 +32,8 @@ struct ALeffectslotProps { EffectState *State; std::atomic next; + + DEF_NEWDEL(ALeffectslotProps) }; diff --git a/al/state.cpp b/al/state.cpp index 884aa9d2..64cbae6e 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -827,7 +827,7 @@ void UpdateContextProps(ALCcontext *context) /* Get an unused proprty container, or allocate a new one as needed. */ ALcontextProps *props{context->mFreeContextProps.load(std::memory_order_acquire)}; if(!props) - props = static_cast(al_calloc(16, sizeof(*props))); + props = new ALcontextProps{}; else { ALcontextProps *next; diff --git a/alc/alc.cpp b/alc/alc.cpp index baf31993..9be224d5 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -2322,14 +2322,14 @@ ALCcontext::~ALCcontext() if(cprops) { TRACE("Freed unapplied context update %p\n", cprops); - al_free(cprops); + delete cprops; } size_t count{0}; cprops = mFreeContextProps.exchange(nullptr, std::memory_order_acquire); while(cprops) { ALcontextProps *next{cprops->next.load(std::memory_order_relaxed)}; - al_free(cprops); + delete cprops; cprops = next; ++count; } @@ -2350,7 +2350,7 @@ ALCcontext::~ALCcontext() { ALeffectslotProps *next{eprops->next.load(std::memory_order_relaxed)}; if(eprops->State) eprops->State->release(); - al_free(eprops); + delete eprops; eprops = next; ++count; } diff --git a/alc/alcontext.h b/alc/alcontext.h index f30a4bd0..c91d0a21 100644 --- a/alc/alcontext.h +++ b/alc/alcontext.h @@ -50,6 +50,8 @@ struct ALcontextProps { DistanceModel mDistanceModel; std::atomic next; + + DEF_NEWDEL(ALcontextProps) }; -- cgit v1.2.3 From ddf7e0f07c658a1754f108d43f5d35615488d2b9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Aug 2019 21:23:30 -0700 Subject: Use a std::array for the reverb sample buffer --- alc/effects/reverb.cpp | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 423aedd8..e69da59d 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -224,20 +224,13 @@ struct DelayLineI { * of 2 to allow the use of bit-masking instead of a modulus for wrapping. */ ALsizei Mask{0}; - ALfloat (*Line)[NUM_LINES]{nullptr}; + std::array *Line{nullptr}; /* Given the allocated sample buffer, this function updates each delay line * offset. */ - void realizeLineOffset(ALfloat *sampleBuffer) - { - union { - ALfloat *f; - ALfloat (*f4)[NUM_LINES]; - } u; - u.f = &sampleBuffer[reinterpret_cast(Line) * NUM_LINES]; - Line = u.f4; - } + void realizeLineOffset(std::array *sampleBuffer) noexcept + { Line = &sampleBuffer[reinterpret_cast(Line)]; } /* Calculate the length of a delay line and store its mask and offset. */ ALuint calcLineLength(const ALfloat length, const ptrdiff_t offset, const ALfloat frequency, @@ -251,7 +244,7 @@ struct DelayLineI { /* All lines share a single sample buffer. */ Mask = samples - 1; - Line = reinterpret_cast(offset); + Line = reinterpret_cast*>(offset); /* Return the sample count for accumulation. */ return samples; @@ -350,7 +343,7 @@ struct ReverbState final : public EffectState { /* All delay lines are allocated as a single buffer to reduce memory * fragmentation and management code. */ - al::vector mSampleBuffer; + al::vector,16> mSampleBuffer; struct { /* Calculated parameters which indicate if cross-fading is needed after @@ -531,7 +524,6 @@ bool ReverbState::allocLines(const ALfloat frequency) length = LATE_LINE_LENGTHS.back() * multiplier; totalSamples += mLate.Delay.calcLineLength(length, totalSamples, frequency, 0); - totalSamples *= NUM_LINES; if(totalSamples != mSampleBuffer.size()) { mSampleBuffer.resize(totalSamples); @@ -539,7 +531,7 @@ bool ReverbState::allocLines(const ALfloat frequency) } /* Clear the sample buffer. */ - std::fill(mSampleBuffer.begin(), mSampleBuffer.end(), 0.0f); + std::fill(mSampleBuffer.begin(), mSampleBuffer.end(), std::array{}); /* Update all delays to reflect the new sample buffer. */ mDelay.realizeLineOffset(mSampleBuffer.data()); @@ -1029,8 +1021,8 @@ void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, co * Where D is a diagonal matrix (of x), and S is a triangular matrix (of y) * whose combination of signs are being iterated. */ -inline void VectorPartialScatter(ALfloat *RESTRICT out, const ALfloat *RESTRICT in, - const ALfloat xCoeff, const ALfloat yCoeff) +inline void VectorPartialScatter(std::array &RESTRICT out, + const std::array &RESTRICT in, const ALfloat xCoeff, const ALfloat yCoeff) { out[0] = xCoeff*in[0] + yCoeff*( in[1] + -in[2] + in[3]); out[1] = xCoeff*in[1] + yCoeff*(-in[0] + in[2] + in[3]); @@ -1051,7 +1043,7 @@ void VectorScatterRevDelayIn(const DelayLineI delay, ALint offset, const ALfloat offset &= delay.Mask; ALsizei td{mini(delay.Mask+1 - offset, count-i)}; do { - ALfloat f[NUM_LINES]; + std::array f; for(ALsizei j{0};j < NUM_LINES;j++) f[NUM_LINES-1-j] = in[j][base+i]; ++i; @@ -1094,7 +1086,7 @@ void VecAllpass::processUnfaded(const al::span sample ALsizei td{mini(delay.Mask+1 - maxoff, todo - i)}; do { - ALfloat f[NUM_LINES]; + std::array f; for(ALsizei j{0};j < NUM_LINES;j++) { const ALfloat input{samples[j][i]}; @@ -1140,7 +1132,7 @@ void VecAllpass::processFaded(const al::span samples, do { fade += FadeStep; - ALfloat f[NUM_LINES]; + std::array f; for(ALsizei j{0};j < NUM_LINES;j++) f[j] = delay.Line[vap_offset[j][0]++][j]*(1.0f-fade) + delay.Line[vap_offset[j][1]++][j]*fade; -- cgit v1.2.3 From 16886bd2598f4547805f6f54e1155296abc3b05b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Aug 2019 23:00:46 -0700 Subject: Avoid an out parameter for VectorPartialScatter --- alc/effects/reverb.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index e69da59d..c3ce26c9 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -1021,13 +1021,15 @@ void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, co * Where D is a diagonal matrix (of x), and S is a triangular matrix (of y) * whose combination of signs are being iterated. */ -inline void VectorPartialScatter(std::array &RESTRICT out, - const std::array &RESTRICT in, const ALfloat xCoeff, const ALfloat yCoeff) +inline auto VectorPartialScatter(const std::array &RESTRICT in, + const ALfloat xCoeff, const ALfloat yCoeff) -> std::array { + std::array out; out[0] = xCoeff*in[0] + yCoeff*( in[1] + -in[2] + in[3]); out[1] = xCoeff*in[1] + yCoeff*(-in[0] + in[2] + in[3]); out[2] = xCoeff*in[2] + yCoeff*( in[0] + -in[1] + in[3]); out[3] = xCoeff*in[3] + yCoeff*(-in[0] + -in[1] + -in[2] ); + return out; } /* Utilizes the above, but reverses the input channels. */ @@ -1048,7 +1050,7 @@ void VectorScatterRevDelayIn(const DelayLineI delay, ALint offset, const ALfloat f[NUM_LINES-1-j] = in[j][base+i]; ++i; - VectorPartialScatter(delay.Line[offset++], f, xCoeff, yCoeff); + delay.Line[offset++] = VectorPartialScatter(f, xCoeff, yCoeff); } while(--td); } } @@ -1097,7 +1099,7 @@ void VecAllpass::processUnfaded(const al::span sample } ++i; - VectorPartialScatter(delay.Line[offset++], f, xCoeff, yCoeff); + delay.Line[offset++] = VectorPartialScatter(f, xCoeff, yCoeff); } while(--td); } } @@ -1147,7 +1149,7 @@ void VecAllpass::processFaded(const al::span samples, } ++i; - VectorPartialScatter(delay.Line[offset++], f, xCoeff, yCoeff); + delay.Line[offset++] = VectorPartialScatter(f, xCoeff, yCoeff); } while(--td); } } -- cgit v1.2.3 From ff66061091baedaa7d677ede65aba592c8f8aa5d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Aug 2019 03:09:50 -0700 Subject: Reduce the size of reverb's temporary buffer storage The size of ReverbState is now almost half of what it was. --- alc/effects/reverb.cpp | 179 ++++++++++++++++++++++++++----------------------- 1 file changed, 94 insertions(+), 85 deletions(-) diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index c3ce26c9..26d4d012 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -48,6 +48,11 @@ namespace { using namespace std::placeholders; +/* Max samples per process iteration. Used to limit the size needed for + * temporary buffers. Must be a multiple of 4 for SIMD alignment. + */ +constexpr int MAX_UPDATE_SAMPLES{(BUFFERSIZE/3) & ~3}; + /* The number of samples used for cross-faded delay lines. This can be used * to balance the compensation for abrupt line changes and attenuation due to * minimally lengthed recursive lines. Try to keep this below the device @@ -387,75 +392,80 @@ struct ReverbState final : public EffectState { ALsizei mFadeCount{0}; /* Maximum number of samples to process at once. */ - ALsizei mMaxUpdate[2]{BUFFERSIZE, BUFFERSIZE}; + ALsizei mMaxUpdate[2]{MAX_UPDATE_SAMPLES, MAX_UPDATE_SAMPLES}; /* The current write offset for all delay lines. */ ALsizei mOffset{0}; - /* Temporary storage used when processing. */ + /* Temporary storage used when processing. Note that mTempSamples is really + * broken up into three interleaved sections (due to the mixers' multi- + * channel I/O requiring a BUFFERSIZE channel length). This will hopefully + * be handled better in the future. + */ + alignas(16) FloatBufferLine mTempLine{}; alignas(16) std::array mTempSamples{}; - alignas(16) std::array mEarlyBuffer{}; - alignas(16) std::array mLateBuffer{}; + static constexpr int sEarlyOffset{MAX_UPDATE_SAMPLES}; + static constexpr int sLateOffset{MAX_UPDATE_SAMPLES*2}; using MixOutT = void (ReverbState::*)(const al::span samplesOut, - const ALsizei todo); + const ALsizei counter, const ALsizei offset, const ALsizei todo); MixOutT mMixOut{&ReverbState::MixOutPlain}; std::array mOrderScales{}; std::array,2> mAmbiSplitter; - void MixOutPlain(const al::span samplesOut, const ALsizei todo) + void MixOutPlain(const al::span samplesOut, const ALsizei counter, + const ALsizei offset, const ALsizei todo) { ASSUME(todo > 0); /* Convert back to B-Format, and mix the results to output. */ for(ALsizei c{0};c < NUM_LINES;c++) { - std::fill_n(mTempSamples[0].begin(), todo, 0.0f); - MixRowSamples(mTempSamples[0], A2B[c], mEarlyBuffer, 0, todo); - MixSamples(mTempSamples[0].data(), samplesOut, mEarly.CurrentGain[c], - mEarly.PanGain[c], todo, 0, todo); + std::fill_n(mTempLine.begin(), todo, 0.0f); + MixRowSamples(mTempLine, A2B[c], mTempSamples, sEarlyOffset, todo); + MixSamples(mTempLine.data(), samplesOut, mEarly.CurrentGain[c], + mEarly.PanGain[c], counter, offset, todo); } - for(ALsizei c{0};c < NUM_LINES;c++) { - std::fill_n(mTempSamples[0].begin(), todo, 0.0f); - MixRowSamples(mTempSamples[0], A2B[c], mLateBuffer, 0, todo); - MixSamples(mTempSamples[0].data(), samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], - todo, 0, todo); + std::fill_n(mTempLine.begin(), todo, 0.0f); + MixRowSamples(mTempLine, A2B[c], mTempSamples, sLateOffset, todo); + MixSamples(mTempLine.data(), samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], + counter, offset, todo); } } - void MixOutAmbiUp(const al::span samplesOut, const ALsizei todo) + void MixOutAmbiUp(const al::span samplesOut, const ALsizei counter, + const ALsizei offset, const ALsizei todo) { ASSUME(todo > 0); for(ALsizei c{0};c < NUM_LINES;c++) { - std::fill_n(mTempSamples[0].begin(), todo, 0.0f); - MixRowSamples(mTempSamples[0], A2B[c], mEarlyBuffer, 0, todo); + std::fill_n(mTempLine.begin(), todo, 0.0f); + MixRowSamples(mTempLine, A2B[c], mTempSamples, sEarlyOffset, todo); /* Apply scaling to the B-Format's HF response to "upsample" it to * higher-order output. */ const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; - mAmbiSplitter[0][c].applyHfScale(mTempSamples[0].data(), hfscale, todo); + mAmbiSplitter[0][c].applyHfScale(mTempLine.data(), hfscale, todo); - MixSamples(mTempSamples[0].data(), samplesOut, mEarly.CurrentGain[c], - mEarly.PanGain[c], todo, 0, todo); + MixSamples(mTempLine.data(), samplesOut, mEarly.CurrentGain[c], + mEarly.PanGain[c], counter, offset, todo); } - for(ALsizei c{0};c < NUM_LINES;c++) { - std::fill_n(mTempSamples[0].begin(), todo, 0.0f); - MixRowSamples(mTempSamples[0], A2B[c], mLateBuffer, 0, todo); + std::fill_n(mTempLine.begin(), todo, 0.0f); + MixRowSamples(mTempLine, A2B[c], mTempSamples, sLateOffset, todo); const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; - mAmbiSplitter[1][c].applyHfScale(mTempSamples[0].data(), hfscale, todo); + mAmbiSplitter[1][c].applyHfScale(mTempLine.data(), hfscale, todo); - MixSamples(mTempSamples[0].data(), samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], - todo, 0, todo); + MixSamples(mTempLine.data(), samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], + counter, offset, todo); } } @@ -592,7 +602,7 @@ ALboolean ReverbState::deviceUpdate(const ALCdevice *device) /* Reset counters and offset base. */ mFadeCount = 0; - std::fill(std::begin(mMaxUpdate), std::end(mMaxUpdate), BUFFERSIZE); + std::fill(std::begin(mMaxUpdate), std::end(mMaxUpdate), MAX_UPDATE_SAMPLES); mOffset = 0; if(device->mAmbiOrder > 1) @@ -949,7 +959,7 @@ void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, co props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain, target); /* Calculate the max update size from the smallest relevant delay. */ - mMaxUpdate[1] = mini(BUFFERSIZE, mini(mEarly.Offset[0][1], mLate.Offset[0][1])); + mMaxUpdate[1] = mini(MAX_UPDATE_SAMPLES, mini(mEarly.Offset[0][1], mLate.Offset[0][1])); /* Determine if delay-line cross-fading is required. Density is essentially * a master control for the feedback delays, so changes the offsets of many @@ -1174,7 +1184,7 @@ void VecAllpass::processFaded(const al::span samples, * line processing and non-transitional processing. */ void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei todo, - const ALsizei base, const al::span out) + const ALsizei base) { const al::span temps{State->mTempSamples}; const DelayLineI early_delay{State->mEarly.Delay}; @@ -1213,6 +1223,7 @@ void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALs { ALint feedb_tap{offset - State->mEarly.Offset[j][0]}; const ALfloat feedb_coeff{State->mEarly.Coeff[j][0]}; + float *out = State->mTempSamples[j].data()+State->sEarlyOffset + base; ASSUME(base >= 0); for(ALsizei i{0};i < todo;) @@ -1220,7 +1231,7 @@ void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALs feedb_tap &= early_delay.Mask; ALsizei td{mini(early_delay.Mask+1 - feedb_tap, todo - i)}; do { - out[j][base+i] = temps[j][i] + early_delay.Line[feedb_tap++][j]*feedb_coeff; + out[i] = temps[j][i] + early_delay.Line[feedb_tap++][j]*feedb_coeff; ++i; } while(--td); } @@ -1233,11 +1244,12 @@ void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALs * bounce to improve the initial diffusion in the late reverb. */ const ALsizei late_feed_tap{offset - State->mLateFeedTap}; - VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, + const al::span out{State->mTempSamples}; + VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, State->sEarlyOffset+base, {out.cbegin(), out.cend()}, todo); } void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, - const ALfloat fade, const ALsizei base, const al::span out) + const ALfloat fade) { const al::span temps{State->mTempSamples}; const DelayLineI early_delay{State->mEarly.Delay}; @@ -1281,9 +1293,9 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz const ALfloat feedb_oldCoeff{State->mEarly.Coeff[j][0]}; const ALfloat feedb_oldCoeffStep{-feedb_oldCoeff / FADE_SAMPLES}; const ALfloat feedb_newCoeffStep{State->mEarly.Coeff[j][1] / FADE_SAMPLES}; + float *out = State->mTempSamples[j].data() + State->sEarlyOffset; ALfloat fadeCount{fade}; - ASSUME(base >= 0); for(ALsizei i{0};i < todo;) { feedb_tap0 &= early_delay.Mask; @@ -1294,7 +1306,7 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz fadeCount += 1.0f; const ALfloat fade0{feedb_oldCoeff + feedb_oldCoeffStep*fadeCount}; const ALfloat fade1{feedb_newCoeffStep*fadeCount}; - out[j][base+i] = temps[j][i] + + out[i] = temps[j][i] + early_delay.Line[feedb_tap0++][j]*fade0 + early_delay.Line[feedb_tap1++][j]*fade1; ++i; @@ -1305,7 +1317,8 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz early_delay.write(offset, NUM_LINES-1-j, temps[j].data(), todo); const ALsizei late_feed_tap{offset - State->mLateFeedTap}; - VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, + const al::span out{State->mTempSamples}; + VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, State->sEarlyOffset, {out.cbegin(), out.cend()}, todo); } @@ -1324,7 +1337,7 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz * processing and one for non-transitional processing. */ void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei todo, - const ALsizei base, const al::span out) + const ALsizei base) { const al::span temps{State->mTempSamples}; const DelayLineI late_delay{State->mLate.Delay}; @@ -1363,16 +1376,16 @@ void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei * out the results for mixing. */ State->mLate.VecAp.processUnfaded(temps, offset, mixX, mixY, todo); - for(ALsizei j{0};j < NUM_LINES;j++) - std::copy_n(temps[j].begin(), todo, out[j].begin()+base); + std::copy_n(temps[j].begin(), todo, + State->mTempSamples[j].begin()+State->sLateOffset + base); /* Finally, scatter and bounce the results to refeed the feedback buffer. */ - VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, - {out.cbegin(), out.cend()}, todo); + VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, 0, {temps.cbegin(), temps.cend()}, + todo); } void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, - const ALfloat fade, const ALsizei base, const al::span out) + const ALfloat fade) { const al::span temps{State->mTempSamples}; const DelayLineI late_delay{State->mLate.Delay}; @@ -1425,68 +1438,63 @@ void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei to } State->mLate.VecAp.processFaded(temps, offset, mixX, mixY, fade, todo); - for(ALsizei j{0};j < NUM_LINES;j++) - std::copy_n(temps[j].begin(), todo, out[j].begin()+base); + std::copy_n(temps[j].begin(), todo, State->mTempSamples[j].begin()+State->sLateOffset); - VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, base, - {out.cbegin(), out.cend()}, todo); + VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, 0, {temps.cbegin(), temps.cend()}, + todo); } void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) { + ALsizei offset{mOffset}; ALsizei fadeCount{mFadeCount}; ASSUME(samplesToDo > 0); + ASSUME(offset >= 0); /* Convert B-Format to A-Format for processing. */ - const al::span afmt{mTempSamples}; for(ALsizei c{0};c < NUM_LINES;c++) { - std::fill_n(afmt[c].begin(), samplesToDo, 0.0f); - MixRowSamples(afmt[c], B2A[c], {samplesIn, samplesIn+numInput}, 0, samplesToDo); + std::fill_n(mTempLine.begin(), samplesToDo, 0.0f); + MixRowSamples(mTempLine, B2A[c], {samplesIn, samplesIn+numInput}, 0, samplesToDo); - /* Band-pass the incoming samples. */ - mFilter[c].Lp.process(afmt[c].data(), afmt[c].data(), samplesToDo); - mFilter[c].Hp.process(afmt[c].data(), afmt[c].data(), samplesToDo); + /* Band-pass the incoming samples and feed the initial delay line. */ + mFilter[c].Lp.process(mTempLine.data(), mTempLine.data(), samplesToDo); + mFilter[c].Hp.process(mTempLine.data(), mTempLine.data(), samplesToDo); + mDelay.write(offset, c, mTempLine.data(), samplesToDo); } /* Process reverb for these samples. */ for(ALsizei base{0};base < samplesToDo;) { - ALsizei todo{samplesToDo - base}; - /* If cross-fading, don't do more samples than there are to fade. */ - if(FADE_SAMPLES-fadeCount > 0) - { - todo = mini(todo, FADE_SAMPLES-fadeCount); - todo = mini(todo, mMaxUpdate[0]); - } - todo = mini(todo, mMaxUpdate[1]); - ASSUME(todo > 0 && todo <= BUFFERSIZE); - - const ALsizei offset{mOffset + base}; - ASSUME(offset >= 0); - - /* Feed the initial delay line. */ - for(ALsizei c{0};c < NUM_LINES;c++) - mDelay.write(offset, c, afmt[c].data()+base, todo); + /* Calculate the number of samples we can do this iteration. */ + ALsizei todo{mini(samplesToDo - base, mini(mMaxUpdate[0], mMaxUpdate[1]))}; + /* Some mixers require maintaining a 4-sample alignment, so ensure that + * if it's not the last iteration. + */ + if(base+todo < samplesToDo) todo &= ~3; + ASSUME(todo > 0); /* Process the samples for reverb. */ + ALsizei samples_done{0}; if UNLIKELY(fadeCount < FADE_SAMPLES) { + /* If cross-fading, don't do more samples than there are to fade. */ + const ALsizei tofade{mini(todo, FADE_SAMPLES-fadeCount)}; auto fade = static_cast(fadeCount); - /* Generate early reflections and late reverb. */ - EarlyReflection_Faded(this, offset, todo, fade, base, mEarlyBuffer); - - LateReverb_Faded(this, offset, todo, fade, base, mLateBuffer); + /* Generate cross-faded early reflections and late reverb. */ + EarlyReflection_Faded(this, offset, tofade, fade); + LateReverb_Faded(this, offset, tofade, fade); - /* Step fading forward. */ - fadeCount += todo; - if(fadeCount >= FADE_SAMPLES) + /* Step forward by amount faded. */ + samples_done += tofade; + offset += tofade; + fadeCount += tofade; + if(fadeCount == FADE_SAMPLES) { /* Update the cross-fading delay line taps. */ - fadeCount = FADE_SAMPLES; for(ALsizei c{0};c < NUM_LINES;c++) { mEarlyDelayTap[c][0] = mEarlyDelayTap[c][1]; @@ -1503,21 +1511,22 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST mMaxUpdate[0] = mMaxUpdate[1]; } } - else + if LIKELY(samples_done < todo) { - /* Generate early reflections and late reverb. */ - EarlyReflection_Unfaded(this, offset, todo, base, mEarlyBuffer); - - LateReverb_Unfaded(this, offset, todo, base, mLateBuffer); + /* Generate non-faded early reflections and late reverb. */ + const ALsizei remaining{todo - samples_done}; + EarlyReflection_Unfaded(this, offset, remaining, samples_done); + LateReverb_Unfaded(this, offset, remaining, samples_done); + offset += remaining; } + /* Finally, mix early reflections and late reverb. */ + (this->*mMixOut)(samplesOut, samplesToDo-base, base, todo); + base += todo; } - mOffset = (mOffset+samplesToDo) & 0x3fffffff; + mOffset = offset & 0x3fffffff; mFadeCount = fadeCount; - - /* Finally, mix early reflections and late reverb. */ - (this->*mMixOut)(samplesOut, samplesToDo); } -- cgit v1.2.3 From 42602b9ede2d9ea9ead9c8f32d000388f7642670 Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Sun, 18 Aug 2019 18:49:52 +0200 Subject: Alsoft-config: Add vocal morpher effect --- alsoftrc.sample | 2 +- utils/alsoft-config/mainwindow.cpp | 4 ++++ utils/alsoft-config/mainwindow.ui | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/alsoftrc.sample b/alsoftrc.sample index 0128008c..f0dde916 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -236,7 +236,7 @@ # help for apps that try to use effects which are too CPU intensive for the # system to handle. Available effects are: eaxreverb,reverb,autowah,chorus, # compressor,distortion,echo,equalizer,flanger,modulator,dedicated,pshifter, -# fshifter +# fshifter,vmorpher. #excludefx = ## default-reverb: (global) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 64178922..ce14596d 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -416,6 +416,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->enableModulatorCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->enableDedicatedCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->enablePitchShifterCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableVocalMorpherCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->pulseAutospawnCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->pulseAllowMovesCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); @@ -887,6 +888,7 @@ void MainWindow::loadConfig(const QString &fname) ui->enableModulatorCheck->setChecked(!excludefx.contains("modulator", Qt::CaseInsensitive)); ui->enableDedicatedCheck->setChecked(!excludefx.contains("dedicated", Qt::CaseInsensitive)); ui->enablePitchShifterCheck->setChecked(!excludefx.contains("pshifter", Qt::CaseInsensitive)); + ui->enableVocalMorpherCheck->setChecked(!excludefx.contains("vmorpher", Qt::CaseInsensitive)); ui->pulseAutospawnCheckBox->setCheckState(getCheckState(settings.value("pulse/spawn-server"))); ui->pulseAllowMovesCheckBox->setCheckState(getCheckState(settings.value("pulse/allow-moves"))); @@ -1092,6 +1094,8 @@ void MainWindow::saveConfig(const QString &fname) const strlist.append("dedicated"); if(!ui->enablePitchShifterCheck->isChecked()) strlist.append("pshifter"); + if(!ui->enableVocalMorpherCheck->isChecked()) + strlist.append("vmorpher"); settings.setValue("excludefx", strlist.join(QChar(','))); settings.setValue("pulse/spawn-server", getCheckValue(ui->pulseAutospawnCheckBox)); diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 54844226..1b73536e 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -2264,6 +2264,22 @@ added by the ALC_EXT_DEDICATED extension. true + + + + 320 + 210 + 131 + 21 + + + + Vocal morpher + + + true + + -- cgit v1.2.3 From 550f1dce1fa00bc084e6dacbb40fdafb6867a015 Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Sun, 18 Aug 2019 19:12:38 +0200 Subject: Move double2int function Move inline double2int function to alnumeric.h from pshifter.cpp --- alc/effects/pshifter.cpp | 35 +---------------------------------- common/alnumeric.h | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/alc/effects/pshifter.cpp b/alc/effects/pshifter.cpp index 819e510c..0ba0b496 100644 --- a/alc/effects/pshifter.cpp +++ b/alc/effects/pshifter.cpp @@ -34,6 +34,7 @@ #include "alcmain.h" #include "alcomplex.h" #include "alcontext.h" +#include "alnumeric.h" #include "alu.h" @@ -48,40 +49,6 @@ using complex_d = std::complex; #define STFT_STEP (STFT_SIZE / OVERSAMP) #define FIFO_LATENCY (STFT_STEP * (OVERSAMP-1)) -inline int double2int(double d) -{ -#if defined(HAVE_SSE_INTRINSICS) - return _mm_cvttsd_si32(_mm_set_sd(d)); - -#elif ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) && \ - !defined(__SSE2_MATH__)) || (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP < 2) - - int sign, shift; - int64_t mant; - union { - double d; - int64_t i64; - } conv; - - conv.d = d; - sign = (conv.i64>>63) | 1; - shift = ((conv.i64>>52)&0x7ff) - (1023+52); - - /* Over/underflow */ - if UNLIKELY(shift >= 63 || shift < -52) - return 0; - - mant = (conv.i64&0xfffffffffffff_i64) | 0x10000000000000_i64; - if LIKELY(shift < 0) - return (int)(mant >> -shift) * sign; - return (int)(mant << shift) * sign; - -#else - - return static_cast(d); -#endif -} - /* Define a Hann window, used to filter the STFT input and output. */ /* Making this constexpr seems to require C++14. */ std::array InitHannWindow() diff --git a/common/alnumeric.h b/common/alnumeric.h index b51893d6..0a05f4bf 100644 --- a/common/alnumeric.h +++ b/common/alnumeric.h @@ -250,6 +250,41 @@ inline int float2int(float f) noexcept #endif } +/** Converts double-to-int using standard behavior (truncation). */ +inline int double2int(double d) noexcept +{ +#if defined(HAVE_SSE_INTRINSICS) + return _mm_cvttsd_si32(_mm_set_sd(d)); + +#elif ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) && \ + !defined(__SSE2_MATH__)) || (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP < 2) + + int sign, shift; + int64_t mant; + union { + double d; + int64_t i64; + } conv; + + conv.d = d; + sign = (conv.i64 >> 63) | 1; + shift = ((conv.i64 >> 52) & 0x7ff) - (1023 + 52); + + /* Over/underflow */ + if UNLIKELY(shift >= 63 || shift < -52) + return 0; + + mant = (conv.i64 & 0xfffffffffffff_i64) | 0x10000000000000_i64; + if LIKELY(shift < 0) + return (int)(mant >> -shift) * sign; + return (int)(mant << shift) * sign; + +#else + + return static_cast(d); +#endif +} + /** * Rounds a float to the nearest integral value, according to the current * rounding mode. This is essentially an inlined version of rintf, although -- cgit v1.2.3 From eaaa194163b07f404818ce6452597086081e8251 Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Sun, 18 Aug 2019 19:28:00 +0200 Subject: EFX: Update Frequency shifter Add f. shifter processing for L and R channels. --- alc/effects/fshifter.cpp | 83 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 28 deletions(-) diff --git a/alc/effects/fshifter.cpp b/alc/effects/fshifter.cpp index a6c2c747..addf512c 100644 --- a/alc/effects/fshifter.cpp +++ b/alc/effects/fshifter.cpp @@ -62,9 +62,10 @@ alignas(16) const std::array HannWindow = InitHannWindow(); struct FshifterState final : public EffectState { /* Effect parameters */ ALsizei mCount{}; - ALsizei mPhaseStep{}; - ALsizei mPhase{}; - ALdouble mLdSign{}; + ALsizei mPhaseStep[2]{}; + ALsizei mPhase[2]{}; + ALdouble mSign[2]{}; + /*Effects buffers*/ ALfloat mInFIFO[HIL_SIZE]{}; @@ -76,8 +77,10 @@ struct FshifterState final : public EffectState { alignas(16) ALfloat mBufferOut[BUFFERSIZE]{}; /* Effect gains for each output channel */ - ALfloat mCurrentGains[MAX_OUTPUT_CHANNELS]{}; - ALfloat mTargetGains[MAX_OUTPUT_CHANNELS]{}; + struct { + ALfloat Current[MAX_OUTPUT_CHANNELS]{}; + ALfloat Target[MAX_OUTPUT_CHANNELS]{}; + }mGains[2]; ALboolean deviceUpdate(const ALCdevice *device) override; @@ -91,17 +94,20 @@ ALboolean FshifterState::deviceUpdate(const ALCdevice*) { /* (Re-)initializing parameters and clear the buffers. */ mCount = FIFO_LATENCY; - mPhaseStep = 0; - mPhase = 0; - mLdSign = 1.0; + std::fill(std::begin(mPhaseStep), std::end(mPhaseStep), 0); + std::fill(std::begin(mPhase), std::end(mPhase), 0); + std::fill(std::begin(mSign), std::end(mSign), 1.0); std::fill(std::begin(mInFIFO), std::end(mInFIFO), 0.0f); std::fill(std::begin(mOutFIFO), std::end(mOutFIFO), complex_d{}); std::fill(std::begin(mOutputAccum), std::end(mOutputAccum), complex_d{}); std::fill(std::begin(mAnalytic), std::end(mAnalytic), complex_d{}); - std::fill(std::begin(mCurrentGains), std::end(mCurrentGains), 0.0f); - std::fill(std::begin(mTargetGains), std::end(mTargetGains), 0.0f); + for (auto &gain : mGains) + { + std::fill(std::begin(gain.Current), std::end(gain.Current), 0.0f); + std::fill(std::begin(gain.Target), std::end(gain.Target), 0.0f); + } return AL_TRUE; } @@ -111,29 +117,47 @@ void FshifterState::update(const ALCcontext *context, const ALeffectslot *slot, const ALCdevice *device{context->mDevice.get()}; ALfloat step{props->Fshifter.Frequency / static_cast(device->Frequency)}; - mPhaseStep = fastf2i(minf(step, 0.5f) * FRACTIONONE); + mPhaseStep[0] = mPhaseStep[1] = fastf2i(minf(step, 0.5f) * FRACTIONONE); switch(props->Fshifter.LeftDirection) { case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: - mLdSign = -1.0; + mSign[0] = -1.0; break; case AL_FREQUENCY_SHIFTER_DIRECTION_UP: - mLdSign = 1.0; + mSign[0] = 1.0; break; case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: - mPhase = 0; - mPhaseStep = 0; + mPhase[0] = 0; + mPhaseStep[0] = 0; break; } - ALfloat coeffs[MAX_AMBI_CHANNELS]; - CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); + switch (props->Fshifter.RightDirection) + { + case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: + mSign[1] = -1.0; + break; + + case AL_FREQUENCY_SHIFTER_DIRECTION_UP: + mSign[1] = 1.0; + break; + + case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: + mPhase[1] = 0; + mPhaseStep[1] = 0; + break; + } + + ALfloat coeffs[2][MAX_AMBI_CHANNELS]; + CalcDirectionCoeffs({-1.0f, 0.0f, -1.0f}, 0.0f, coeffs[0]); + CalcDirectionCoeffs({1.0f, 0.0f, -1.0f }, 0.0f, coeffs[1]); mOutTarget = target.Main->Buffer; - ComputePanGains(target.Main, coeffs, slot->Params.Gain, mTargetGains); + ComputePanGains(target.Main, coeffs[0], slot->Params.Gain, mGains[0].Target); + ComputePanGains(target.Main, coeffs[1], slot->Params.Gain, mGains[1].Target); } void FshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) @@ -185,19 +209,22 @@ void FshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE } /* Process frequency shifter using the analytic signal obtained. */ - for(k = 0;k < samplesToDo;k++) + for (ALsizei c{0}; c < 2; c++) { - double phase = mPhase * ((1.0/FRACTIONONE) * al::MathDefs::Tau()); - BufferOut[k] = static_cast(mOutdata[k].real()*std::cos(phase) + - mOutdata[k].imag()*std::sin(phase)*mLdSign); + for (k = 0; k < samplesToDo; k++) + { + double phase = mPhase[c] * ((1.0 / FRACTIONONE) * al::MathDefs::Tau()); + BufferOut[k] = static_cast(mOutdata[k].real()*std::cos(phase) + + mOutdata[k].imag()*std::sin(phase)*mSign[c]); - mPhase += mPhaseStep; - mPhase &= FRACTIONMASK; - } + mPhase[c] += mPhaseStep[c]; + mPhase[c] &= FRACTIONMASK; + } - /* Now, mix the processed sound data to the output. */ - MixSamples(BufferOut, samplesOut, mCurrentGains, mTargetGains, maxi(samplesToDo, 512), 0, - samplesToDo); + /* Now, mix the processed sound data to the output. */ + MixSamples(BufferOut, samplesOut, mGains[c].Current, mGains[c].Target, maxi(samplesToDo, 512), 0, + samplesToDo); + } } -- cgit v1.2.3 From 4f4ef3a41015cfc499afc1d3101f2e99d29ebb9e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Aug 2019 03:55:09 -0700 Subject: Don't require MixRow's output to be a FloatBufferLine --- alc/alu.h | 2 +- alc/bformatdec.cpp | 6 +++--- alc/effects/reverb.cpp | 10 +++++----- alc/mixer/defs.h | 2 +- alc/mixer/mixer_c.cpp | 2 +- alc/mixer/mixer_neon.cpp | 2 +- alc/mixer/mixer_sse.cpp | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/alc/alu.h b/alc/alu.h index b030dbaa..5044f573 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -317,7 +317,7 @@ struct ALvoice { using MixerFunc = void(*)(const ALfloat *data, const al::span OutBuffer, ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize); -using RowMixerFunc = void(*)(FloatBufferLine &OutBuffer, const ALfloat *gains, +using RowMixerFunc = void(*)(ALfloat *OutBuffer, const ALfloat *gains, const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize); using HrtfMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, diff --git a/alc/bformatdec.cpp b/alc/bformatdec.cpp index 98ef58cb..a241cc93 100644 --- a/alc/bformatdec.cpp +++ b/alc/bformatdec.cpp @@ -164,8 +164,8 @@ void BFormatDec::process(const al::span OutBuffer, { if LIKELY(enabled&1) { - MixRowSamples(outbuf, (*mixmtx)[sHFBand], hfsamples, 0, SamplesToDo); - MixRowSamples(outbuf, (*mixmtx)[sLFBand], lfsamples, 0, SamplesToDo); + MixRowSamples(outbuf.data(), (*mixmtx)[sHFBand], hfsamples, 0, SamplesToDo); + MixRowSamples(outbuf.data(), (*mixmtx)[sLFBand], lfsamples, 0, SamplesToDo); } ++mixmtx; enabled >>= 1; @@ -179,7 +179,7 @@ void BFormatDec::process(const al::span OutBuffer, for(FloatBufferLine &outbuf : OutBuffer) { if LIKELY(enabled&1) - MixRowSamples(outbuf, *mixmtx, insamples, 0, SamplesToDo); + MixRowSamples(outbuf.data(), *mixmtx, insamples, 0, SamplesToDo); ++mixmtx; enabled >>= 1; } diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 26d4d012..08d1ea7b 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -424,14 +424,14 @@ struct ReverbState final : public EffectState { for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), todo, 0.0f); - MixRowSamples(mTempLine, A2B[c], mTempSamples, sEarlyOffset, todo); + MixRowSamples(mTempLine.data(), A2B[c], mTempSamples, sEarlyOffset, todo); MixSamples(mTempLine.data(), samplesOut, mEarly.CurrentGain[c], mEarly.PanGain[c], counter, offset, todo); } for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), todo, 0.0f); - MixRowSamples(mTempLine, A2B[c], mTempSamples, sLateOffset, todo); + MixRowSamples(mTempLine.data(), A2B[c], mTempSamples, sLateOffset, todo); MixSamples(mTempLine.data(), samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], counter, offset, todo); } @@ -445,7 +445,7 @@ struct ReverbState final : public EffectState { for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), todo, 0.0f); - MixRowSamples(mTempLine, A2B[c], mTempSamples, sEarlyOffset, todo); + MixRowSamples(mTempLine.data(), A2B[c], mTempSamples, sEarlyOffset, todo); /* Apply scaling to the B-Format's HF response to "upsample" it to * higher-order output. @@ -459,7 +459,7 @@ struct ReverbState final : public EffectState { for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), todo, 0.0f); - MixRowSamples(mTempLine, A2B[c], mTempSamples, sLateOffset, todo); + MixRowSamples(mTempLine.data(), A2B[c], mTempSamples, sLateOffset, todo); const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; mAmbiSplitter[1][c].applyHfScale(mTempLine.data(), hfscale, todo); @@ -1457,7 +1457,7 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), samplesToDo, 0.0f); - MixRowSamples(mTempLine, B2A[c], {samplesIn, samplesIn+numInput}, 0, samplesToDo); + MixRowSamples(mTempLine.data(), B2A[c], {samplesIn, samplesIn+numInput}, 0, samplesToDo); /* Band-pass the incoming samples and feed the initial delay line. */ mFilter[c].Lp.process(mTempLine.data(), mTempLine.data(), samplesToDo); diff --git a/alc/mixer/defs.h b/alc/mixer/defs.h index 0cd4162a..55de2e67 100644 --- a/alc/mixer/defs.h +++ b/alc/mixer/defs.h @@ -32,7 +32,7 @@ const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, template void Mix_(const ALfloat *data, const al::span OutBuffer, ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize); template -void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize); +void MixRow_(ALfloat *OutBuffer, const ALfloat *Gains, const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize); template void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfFilter *hrtfparams, const ALsizei BufferSize); diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index 765b03fa..ff20bb2b 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -189,7 +189,7 @@ void Mix_(const ALfloat *data, const al::span OutBuffer, * stepping is necessary. */ template<> -void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, +void MixRow_(ALfloat *OutBuffer, const ALfloat *Gains, const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize) { ASSUME(BufferSize > 0); diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index f43063ce..40cbdb23 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -276,7 +276,7 @@ void Mix_(const ALfloat *data, const al::span OutBuffe } template<> -void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, +void MixRow_(ALfloat *OutBuffer, const ALfloat *Gains, const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize) { ASSUME(BufferSize > 0); diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index cff37d2b..6c7715fc 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -229,7 +229,7 @@ void Mix_(const ALfloat *data, const al::span OutBuffer } template<> -void MixRow_(FloatBufferLine &OutBuffer, const ALfloat *Gains, +void MixRow_(ALfloat *OutBuffer, const ALfloat *Gains, const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize) { ASSUME(BufferSize > 0); -- cgit v1.2.3 From 6629b65ab94d9e8a856d860774a508805252daee Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Aug 2019 15:22:10 -0700 Subject: Formatting cleanup --- alc/effects/fshifter.cpp | 54 ++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/alc/effects/fshifter.cpp b/alc/effects/fshifter.cpp index addf512c..7688c762 100644 --- a/alc/effects/fshifter.cpp +++ b/alc/effects/fshifter.cpp @@ -80,7 +80,7 @@ struct FshifterState final : public EffectState { struct { ALfloat Current[MAX_OUTPUT_CHANNELS]{}; ALfloat Target[MAX_OUTPUT_CHANNELS]{}; - }mGains[2]; + } mGains[2]; ALboolean deviceUpdate(const ALCdevice *device) override; @@ -93,7 +93,7 @@ struct FshifterState final : public EffectState { ALboolean FshifterState::deviceUpdate(const ALCdevice*) { /* (Re-)initializing parameters and clear the buffers. */ - mCount = FIFO_LATENCY; + mCount = FIFO_LATENCY; std::fill(std::begin(mPhaseStep), std::end(mPhaseStep), 0); std::fill(std::begin(mPhase), std::end(mPhase), 0); @@ -103,7 +103,7 @@ ALboolean FshifterState::deviceUpdate(const ALCdevice*) std::fill(std::begin(mOutputAccum), std::end(mOutputAccum), complex_d{}); std::fill(std::begin(mAnalytic), std::end(mAnalytic), complex_d{}); - for (auto &gain : mGains) + for(auto &gain : mGains) { std::fill(std::begin(gain.Current), std::end(gain.Current), 0.0f); std::fill(std::begin(gain.Target), std::end(gain.Target), 0.0f); @@ -121,39 +121,39 @@ void FshifterState::update(const ALCcontext *context, const ALeffectslot *slot, switch(props->Fshifter.LeftDirection) { - case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: - mSign[0] = -1.0; - break; + case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: + mSign[0] = -1.0; + break; - case AL_FREQUENCY_SHIFTER_DIRECTION_UP: - mSign[0] = 1.0; - break; + case AL_FREQUENCY_SHIFTER_DIRECTION_UP: + mSign[0] = 1.0; + break; - case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: - mPhase[0] = 0; - mPhaseStep[0] = 0; - break; + case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: + mPhase[0] = 0; + mPhaseStep[0] = 0; + break; } switch (props->Fshifter.RightDirection) { - case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: - mSign[1] = -1.0; + case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: + mSign[1] = -1.0; break; - case AL_FREQUENCY_SHIFTER_DIRECTION_UP: - mSign[1] = 1.0; + case AL_FREQUENCY_SHIFTER_DIRECTION_UP: + mSign[1] = 1.0; break; - case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: - mPhase[1] = 0; - mPhaseStep[1] = 0; - break; + case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: + mPhase[1] = 0; + mPhaseStep[1] = 0; + break; } ALfloat coeffs[2][MAX_AMBI_CHANNELS]; CalcDirectionCoeffs({-1.0f, 0.0f, -1.0f}, 0.0f, coeffs[0]); - CalcDirectionCoeffs({1.0f, 0.0f, -1.0f }, 0.0f, coeffs[1]); + CalcDirectionCoeffs({ 1.0f, 0.0f, -1.0f}, 0.0f, coeffs[1]); mOutTarget = target.Main->Buffer; ComputePanGains(target.Main, coeffs[0], slot->Params.Gain, mGains[0].Target); @@ -177,7 +177,7 @@ void FshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE for(j = 0;j < todo;j++,k++) { mInFIFO[k] = samplesIn[0][base+j]; - mOutdata[base+j] = mOutFIFO[k-FIFO_LATENCY]; + mOutdata[base+j] = mOutFIFO[k-FIFO_LATENCY]; } mCount += todo; base += todo; @@ -209,9 +209,9 @@ void FshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE } /* Process frequency shifter using the analytic signal obtained. */ - for (ALsizei c{0}; c < 2; c++) + for(ALsizei c{0};c < 2;++c) { - for (k = 0; k < samplesToDo; k++) + for(k = 0;k < samplesToDo;++k) { double phase = mPhase[c] * ((1.0 / FRACTIONONE) * al::MathDefs::Tau()); BufferOut[k] = static_cast(mOutdata[k].real()*std::cos(phase) + @@ -222,8 +222,8 @@ void FshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE } /* Now, mix the processed sound data to the output. */ - MixSamples(BufferOut, samplesOut, mGains[c].Current, mGains[c].Target, maxi(samplesToDo, 512), 0, - samplesToDo); + MixSamples(BufferOut, samplesOut, mGains[c].Current, mGains[c].Target, + maxi(samplesToDo, 512), 0, samplesToDo); } } -- cgit v1.2.3 From 2bbdd329cd6e1ea08f240f5420edadb076134302 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Aug 2019 15:37:39 -0700 Subject: Use the appropriate type --- alc/mixvoice.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index c8833ed3..1fc5bd33 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -366,17 +366,17 @@ const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, ALfloat template inline void LoadSampleArray(ALfloat *RESTRICT dst, const al::byte *src, ALint srcstep, - const ptrdiff_t samples) + const size_t samples) { using SampleType = typename FmtTypeTraits::Type; const SampleType *RESTRICT ssrc{reinterpret_cast(src)}; - for(ALsizei i{0};i < samples;i++) + for(size_t i{0u};i < samples;i++) dst[i] = FmtTypeTraits::to_float(ssrc[i*srcstep]); } void LoadSamples(ALfloat *RESTRICT dst, const al::byte *src, ALint srcstep, FmtType srctype, - const ptrdiff_t samples) + const size_t samples) { #define HANDLE_FMT(T) case T: LoadSampleArray(dst, src, srcstep, samples); break switch(srctype) @@ -457,7 +457,7 @@ ALfloat *LoadBufferQueue(ALbufferlistitem *BufferListItem, ALbufferlistitem *Buf continue; } - const size_t DataSize{std::min(SrcBuffer.size(), Buffer->SampleLen-DataPosInt)}; + const size_t DataSize{minz(SrcBuffer.size(), Buffer->SampleLen-DataPosInt)}; const al::byte *Data{Buffer->mData.data()}; Data += (DataPosInt*NumChannels + chan)*SampleSize; -- cgit v1.2.3 From a9223ae601c45c6bdc3c3001ce7b5f30141046b1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Aug 2019 23:26:49 -0700 Subject: Improve subspan default template argument --- common/alspan.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/alspan.h b/common/alspan.h index 60a2bc4a..6a43b32a 100644 --- a/common/alspan.h +++ b/common/alspan.h @@ -249,9 +249,9 @@ public: constexpr span last(size_t count) const { return (count >= size()) ? *this : span{mDataEnd-count, mDataEnd}; } - template + template constexpr span subspan() const - { return span{mData+O, C}; } + { return span{mData+O, (C!=dynamic_extent) ? mData+C : mDataEnd}; } constexpr span subspan(size_t offset, size_t count=dynamic_extent) const { -- cgit v1.2.3 From 2d0568c0484fa5abc74b084c094a325adb0bc452 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Aug 2019 08:02:08 -0700 Subject: Allow using a variable channel stride for MixRowSamples --- alc/alu.h | 5 ++--- alc/bformatdec.cpp | 12 ++++++------ alc/bformatdec.h | 5 ++--- alc/effects/reverb.cpp | 15 ++++++++++----- alc/mixer/defs.h | 2 +- alc/mixer/mixer_c.cpp | 11 ++++++----- alc/mixer/mixer_neon.cpp | 11 ++++++----- alc/mixer/mixer_sse.cpp | 11 ++++++----- 8 files changed, 39 insertions(+), 33 deletions(-) diff --git a/alc/alu.h b/alc/alu.h index 5044f573..117c932d 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -317,9 +317,8 @@ struct ALvoice { using MixerFunc = void(*)(const ALfloat *data, const al::span OutBuffer, ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize); -using RowMixerFunc = void(*)(ALfloat *OutBuffer, const ALfloat *gains, - const al::span InSamples, const ALsizei InPos, - const ALsizei BufferSize); +using RowMixerFunc = void(*)(ALfloat *OutBuffer, const al::span Gains, + const ALfloat *InSamples, const ALsizei InStride, const ALsizei BufferSize); using HrtfMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfFilter *hrtfparams, const ALsizei BufferSize); diff --git a/alc/bformatdec.cpp b/alc/bformatdec.cpp index a241cc93..ce4c4b3b 100644 --- a/alc/bformatdec.cpp +++ b/alc/bformatdec.cpp @@ -156,16 +156,16 @@ void BFormatDec::process(const al::span OutBuffer, mXOver[i].process(mSamplesHF[i].data(), mSamplesLF[i].data(), InSamples[i].data(), SamplesToDo); - const al::span hfsamples{mSamplesHF, mNumChannels}; - const al::span lfsamples{mSamplesLF, mNumChannels}; ALfloat (*mixmtx)[sNumBands][MAX_AMBI_CHANNELS]{mMatrix.Dual}; ALuint enabled{mEnabled}; for(FloatBufferLine &outbuf : OutBuffer) { if LIKELY(enabled&1) { - MixRowSamples(outbuf.data(), (*mixmtx)[sHFBand], hfsamples, 0, SamplesToDo); - MixRowSamples(outbuf.data(), (*mixmtx)[sLFBand], lfsamples, 0, SamplesToDo); + MixRowSamples(outbuf.data(), {(*mixmtx)[sHFBand], mNumChannels}, + mSamplesHF->data(), mSamplesHF->size(), SamplesToDo); + MixRowSamples(outbuf.data(), {(*mixmtx)[sLFBand], mNumChannels}, + mSamplesLF->data(), mSamplesLF->size(), SamplesToDo); } ++mixmtx; enabled >>= 1; @@ -173,13 +173,13 @@ void BFormatDec::process(const al::span OutBuffer, } else { - const al::span insamples{InSamples, mNumChannels}; ALfloat (*mixmtx)[MAX_AMBI_CHANNELS]{mMatrix.Single}; ALuint enabled{mEnabled}; for(FloatBufferLine &outbuf : OutBuffer) { if LIKELY(enabled&1) - MixRowSamples(outbuf.data(), *mixmtx, insamples, 0, SamplesToDo); + MixRowSamples(outbuf.data(), {*mixmtx, mNumChannels}, InSamples->data(), + InSamples->size(), SamplesToDo); ++mixmtx; enabled >>= 1; } diff --git a/alc/bformatdec.h b/alc/bformatdec.h index 6d0bf4e6..dbde90c8 100644 --- a/alc/bformatdec.h +++ b/alc/bformatdec.h @@ -24,8 +24,10 @@ class BFormatDec { static constexpr size_t sLFBand{1}; static constexpr size_t sNumBands{2}; + bool mDualBand{false}; ALuint mEnabled{0u}; /* Bitfield of enabled channels. */ + ALuint mNumChannels{0u}; union MatrixU { ALfloat Dual[MAX_OUTPUT_CHANNELS][sNumBands][MAX_AMBI_CHANNELS]; ALfloat Single[MAX_OUTPUT_CHANNELS][MAX_AMBI_CHANNELS]; @@ -39,9 +41,6 @@ class BFormatDec { FloatBufferLine *mSamplesHF{nullptr}; FloatBufferLine *mSamplesLF{nullptr}; - ALuint mNumChannels{0u}; - bool mDualBand{false}; - public: BFormatDec(const AmbDecConf *conf, const bool allow_2band, const ALuint inchans, const ALuint srate, const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]); diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 08d1ea7b..6fafe241 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -424,14 +424,16 @@ struct ReverbState final : public EffectState { for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), todo, 0.0f); - MixRowSamples(mTempLine.data(), A2B[c], mTempSamples, sEarlyOffset, todo); + MixRowSamples(mTempLine.data(), A2B[c], mTempSamples[0].data()+sEarlyOffset, + mTempSamples[0].size(), todo); MixSamples(mTempLine.data(), samplesOut, mEarly.CurrentGain[c], mEarly.PanGain[c], counter, offset, todo); } for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), todo, 0.0f); - MixRowSamples(mTempLine.data(), A2B[c], mTempSamples, sLateOffset, todo); + MixRowSamples(mTempLine.data(), A2B[c], mTempSamples[0].data()+sLateOffset, + mTempSamples[0].size(), todo); MixSamples(mTempLine.data(), samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], counter, offset, todo); } @@ -445,7 +447,8 @@ struct ReverbState final : public EffectState { for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), todo, 0.0f); - MixRowSamples(mTempLine.data(), A2B[c], mTempSamples, sEarlyOffset, todo); + MixRowSamples(mTempLine.data(), A2B[c], mTempSamples[0].data()+sEarlyOffset, + mTempSamples[0].size(), todo); /* Apply scaling to the B-Format's HF response to "upsample" it to * higher-order output. @@ -459,7 +462,8 @@ struct ReverbState final : public EffectState { for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), todo, 0.0f); - MixRowSamples(mTempLine.data(), A2B[c], mTempSamples, sLateOffset, todo); + MixRowSamples(mTempLine.data(), A2B[c], mTempSamples[0].data()+sLateOffset, + mTempSamples[0].size(), todo); const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; mAmbiSplitter[1][c].applyHfScale(mTempLine.data(), hfscale, todo); @@ -1457,7 +1461,8 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), samplesToDo, 0.0f); - MixRowSamples(mTempLine.data(), B2A[c], {samplesIn, samplesIn+numInput}, 0, samplesToDo); + MixRowSamples(mTempLine.data(), {B2A[c], B2A[c]+numInput}, samplesIn->data(), + samplesIn->size(), samplesToDo); /* Band-pass the incoming samples and feed the initial delay line. */ mFilter[c].Lp.process(mTempLine.data(), mTempLine.data(), samplesToDo); diff --git a/alc/mixer/defs.h b/alc/mixer/defs.h index 55de2e67..19fb42d0 100644 --- a/alc/mixer/defs.h +++ b/alc/mixer/defs.h @@ -32,7 +32,7 @@ const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, template void Mix_(const ALfloat *data, const al::span OutBuffer, ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize); template -void MixRow_(ALfloat *OutBuffer, const ALfloat *Gains, const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize); +void MixRow_(ALfloat *OutBuffer, const al::span Gains, const ALfloat *InSamples, const ALsizei InStride, const ALsizei BufferSize); template void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfFilter *hrtfparams, const ALsizei BufferSize); diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index ff20bb2b..4985933c 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -189,15 +189,16 @@ void Mix_(const ALfloat *data, const al::span OutBuffer, * stepping is necessary. */ template<> -void MixRow_(ALfloat *OutBuffer, const ALfloat *Gains, - const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize) +void MixRow_(ALfloat *OutBuffer, const al::span Gains, + const ALfloat *InSamples, const ALsizei InStride, const ALsizei BufferSize) { ASSUME(BufferSize > 0); - for(const FloatBufferLine &input : InSamples) + for(const ALfloat gain : Gains) { - const ALfloat *RESTRICT src{input.data()+InPos}; - const ALfloat gain{*(Gains++)}; + const ALfloat *RESTRICT src{InSamples}; + InSamples += InStride; + if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index 40cbdb23..c6ea2c60 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -276,15 +276,16 @@ void Mix_(const ALfloat *data, const al::span OutBuffe } template<> -void MixRow_(ALfloat *OutBuffer, const ALfloat *Gains, - const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize) +void MixRow_(ALfloat *OutBuffer, const al::span Gains, + const ALfloat *InSamples, const ALsizei InStride, const ALsizei BufferSize) { ASSUME(BufferSize > 0); - for(const FloatBufferLine &input : InSamples) + for(const ALfloat gain : Gains) { - const ALfloat *RESTRICT src{al::assume_aligned<16>(input.data()+InPos)}; - const ALfloat gain{*(Gains++)}; + const ALfloat *RESTRICT src{InSamples}; + InSamples += InStride; + if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index 6c7715fc..b5958c8e 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -229,15 +229,16 @@ void Mix_(const ALfloat *data, const al::span OutBuffer } template<> -void MixRow_(ALfloat *OutBuffer, const ALfloat *Gains, - const al::span InSamples, const ALsizei InPos, const ALsizei BufferSize) +void MixRow_(ALfloat *OutBuffer, const al::span Gains, + const ALfloat *InSamples, const ALsizei InStride, const ALsizei BufferSize) { ASSUME(BufferSize > 0); - for(const FloatBufferLine &input : InSamples) + for(const ALfloat gain : Gains) { - const ALfloat *RESTRICT src{al::assume_aligned<16>(input.data()+InPos)}; - const ALfloat gain{*(Gains++)}; + const ALfloat *RESTRICT src{InSamples}; + InSamples += InStride; + if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; -- cgit v1.2.3 From c0cd43d1002f164e12757e22d018e25ce351c3b3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Aug 2019 08:46:57 -0700 Subject: More logically separate temp reverb buffers --- alc/effects/reverb.cpp | 73 +++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 6fafe241..31a44f5b 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -51,7 +51,7 @@ using namespace std::placeholders; /* Max samples per process iteration. Used to limit the size needed for * temporary buffers. Must be a multiple of 4 for SIMD alignment. */ -constexpr int MAX_UPDATE_SAMPLES{(BUFFERSIZE/3) & ~3}; +constexpr int MAX_UPDATE_SAMPLES{256}; /* The number of samples used for cross-faded delay lines. This can be used * to balance the compensation for abrupt line changes and attenuation due to @@ -224,6 +224,8 @@ constexpr std::array LATE_LINE_LENGTHS{{ constexpr auto LATE_LINE_LENGTHS_size = LATE_LINE_LENGTHS.size(); +using ReverbUpdateLine = std::array; + struct DelayLineI { /* The delay lines use interleaved samples, with the lengths being powers * of 2 to allow the use of bit-masking instead of a modulus for wrapping. @@ -274,9 +276,9 @@ struct VecAllpass { ALfloat Coeff{0.0f}; ALsizei Offset[NUM_LINES][2]{}; - void processFaded(const al::span samples, ALsizei offset, + void processFaded(const al::span samples, ALsizei offset, const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, const ALsizei todo); - void processUnfaded(const al::span samples, ALsizei offset, + void processUnfaded(const al::span samples, ALsizei offset, const ALfloat xCoeff, const ALfloat yCoeff, const ALsizei todo); }; @@ -397,15 +399,13 @@ struct ReverbState final : public EffectState { /* The current write offset for all delay lines. */ ALsizei mOffset{0}; - /* Temporary storage used when processing. Note that mTempSamples is really - * broken up into three interleaved sections (due to the mixers' multi- - * channel I/O requiring a BUFFERSIZE channel length). This will hopefully - * be handled better in the future. - */ - alignas(16) FloatBufferLine mTempLine{}; - alignas(16) std::array mTempSamples{}; - static constexpr int sEarlyOffset{MAX_UPDATE_SAMPLES}; - static constexpr int sLateOffset{MAX_UPDATE_SAMPLES*2}; + /* Temporary storage used when processing. */ + union { + alignas(16) FloatBufferLine mTempLine{}; + alignas(16) std::array mTempSamples; + }; + alignas(16) std::array mEarlySamples{}; + alignas(16) std::array mLateSamples{}; using MixOutT = void (ReverbState::*)(const al::span samplesOut, const ALsizei counter, const ALsizei offset, const ALsizei todo); @@ -424,16 +424,16 @@ struct ReverbState final : public EffectState { for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), todo, 0.0f); - MixRowSamples(mTempLine.data(), A2B[c], mTempSamples[0].data()+sEarlyOffset, - mTempSamples[0].size(), todo); + MixRowSamples(mTempLine.data(), A2B[c], mEarlySamples[0].data(), + mEarlySamples[0].size(), todo); MixSamples(mTempLine.data(), samplesOut, mEarly.CurrentGain[c], mEarly.PanGain[c], counter, offset, todo); } for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), todo, 0.0f); - MixRowSamples(mTempLine.data(), A2B[c], mTempSamples[0].data()+sLateOffset, - mTempSamples[0].size(), todo); + MixRowSamples(mTempLine.data(), A2B[c], mLateSamples[0].data(), mLateSamples[0].size(), + todo); MixSamples(mTempLine.data(), samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], counter, offset, todo); } @@ -447,8 +447,8 @@ struct ReverbState final : public EffectState { for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), todo, 0.0f); - MixRowSamples(mTempLine.data(), A2B[c], mTempSamples[0].data()+sEarlyOffset, - mTempSamples[0].size(), todo); + MixRowSamples(mTempLine.data(), A2B[c], mEarlySamples[0].data(), + mEarlySamples[0].size(), todo); /* Apply scaling to the B-Format's HF response to "upsample" it to * higher-order output. @@ -462,8 +462,8 @@ struct ReverbState final : public EffectState { for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), todo, 0.0f); - MixRowSamples(mTempLine.data(), A2B[c], mTempSamples[0].data()+sLateOffset, - mTempSamples[0].size(), todo); + MixRowSamples(mTempLine.data(), A2B[c], mLateSamples[0].data(), mLateSamples[0].size(), + todo); const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; mAmbiSplitter[1][c].applyHfScale(mTempLine.data(), hfscale, todo); @@ -1048,7 +1048,7 @@ inline auto VectorPartialScatter(const std::array &RESTRICT in, /* Utilizes the above, but reverses the input channels. */ void VectorScatterRevDelayIn(const DelayLineI delay, ALint offset, const ALfloat xCoeff, - const ALfloat yCoeff, const ALsizei base, const al::span in, + const ALfloat yCoeff, const ALsizei base, const al::span in, const ALsizei count) { ASSUME(base >= 0); @@ -1079,7 +1079,7 @@ void VectorScatterRevDelayIn(const DelayLineI delay, ALint offset, const ALfloat * Two static specializations are used for transitional (cross-faded) delay * line processing and non-transitional processing. */ -void VecAllpass::processUnfaded(const al::span samples, ALsizei offset, +void VecAllpass::processUnfaded(const al::span samples, ALsizei offset, const ALfloat xCoeff, const ALfloat yCoeff, const ALsizei todo) { const DelayLineI delay{Delay}; @@ -1117,7 +1117,7 @@ void VecAllpass::processUnfaded(const al::span sample } while(--td); } } -void VecAllpass::processFaded(const al::span samples, ALsizei offset, +void VecAllpass::processFaded(const al::span samples, ALsizei offset, const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, const ALsizei todo) { const DelayLineI delay{Delay}; @@ -1190,7 +1190,7 @@ void VecAllpass::processFaded(const al::span samples, void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei todo, const ALsizei base) { - const al::span temps{State->mTempSamples}; + const al::span temps{State->mTempSamples}; const DelayLineI early_delay{State->mEarly.Delay}; const DelayLineI main_delay{State->mDelay}; const ALfloat mixX{State->mMixX}; @@ -1227,7 +1227,7 @@ void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALs { ALint feedb_tap{offset - State->mEarly.Offset[j][0]}; const ALfloat feedb_coeff{State->mEarly.Coeff[j][0]}; - float *out = State->mTempSamples[j].data()+State->sEarlyOffset + base; + float *out = State->mEarlySamples[j].data() + base; ASSUME(base >= 0); for(ALsizei i{0};i < todo;) @@ -1248,14 +1248,14 @@ void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALs * bounce to improve the initial diffusion in the late reverb. */ const ALsizei late_feed_tap{offset - State->mLateFeedTap}; - const al::span out{State->mTempSamples}; - VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, State->sEarlyOffset+base, + const al::span out{State->mEarlySamples}; + VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, {out.cbegin(), out.cend()}, todo); } void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, const ALfloat fade) { - const al::span temps{State->mTempSamples}; + const al::span temps{State->mTempSamples}; const DelayLineI early_delay{State->mEarly.Delay}; const DelayLineI main_delay{State->mDelay}; const ALfloat mixX{State->mMixX}; @@ -1297,7 +1297,7 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz const ALfloat feedb_oldCoeff{State->mEarly.Coeff[j][0]}; const ALfloat feedb_oldCoeffStep{-feedb_oldCoeff / FADE_SAMPLES}; const ALfloat feedb_newCoeffStep{State->mEarly.Coeff[j][1] / FADE_SAMPLES}; - float *out = State->mTempSamples[j].data() + State->sEarlyOffset; + float *out = State->mEarlySamples[j].data(); ALfloat fadeCount{fade}; for(ALsizei i{0};i < todo;) @@ -1321,9 +1321,9 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz early_delay.write(offset, NUM_LINES-1-j, temps[j].data(), todo); const ALsizei late_feed_tap{offset - State->mLateFeedTap}; - const al::span out{State->mTempSamples}; - VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, State->sEarlyOffset, - {out.cbegin(), out.cend()}, todo); + const al::span out{State->mEarlySamples}; + VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, 0, {out.cbegin(), out.cend()}, + todo); } /* This generates the reverb tail using a modified feed-back delay network @@ -1343,7 +1343,7 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei todo, const ALsizei base) { - const al::span temps{State->mTempSamples}; + const al::span temps{State->mTempSamples}; const DelayLineI late_delay{State->mLate.Delay}; const DelayLineI main_delay{State->mDelay}; const ALfloat mixX{State->mMixX}; @@ -1381,8 +1381,7 @@ void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei */ State->mLate.VecAp.processUnfaded(temps, offset, mixX, mixY, todo); for(ALsizei j{0};j < NUM_LINES;j++) - std::copy_n(temps[j].begin(), todo, - State->mTempSamples[j].begin()+State->sLateOffset + base); + std::copy_n(temps[j].begin(), todo, State->mLateSamples[j].begin() + base); /* Finally, scatter and bounce the results to refeed the feedback buffer. */ VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, 0, {temps.cbegin(), temps.cend()}, @@ -1391,7 +1390,7 @@ void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, const ALfloat fade) { - const al::span temps{State->mTempSamples}; + const al::span temps{State->mTempSamples}; const DelayLineI late_delay{State->mLate.Delay}; const DelayLineI main_delay{State->mDelay}; const ALfloat mixX{State->mMixX}; @@ -1443,7 +1442,7 @@ void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei to State->mLate.VecAp.processFaded(temps, offset, mixX, mixY, fade, todo); for(ALsizei j{0};j < NUM_LINES;j++) - std::copy_n(temps[j].begin(), todo, State->mTempSamples[j].begin()+State->sLateOffset); + std::copy_n(temps[j].begin(), todo, State->mLateSamples[j].begin()); VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, 0, {temps.cbegin(), temps.cend()}, todo); -- cgit v1.2.3 From 34331c0dfaeecb40d4bbe771cdb65dfe5aa9f7a5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Aug 2019 09:14:54 -0700 Subject: Fix for GCC5 decaying an array to a pointer --- alc/effects/reverb.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 31a44f5b..f12e5ed9 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -424,7 +424,7 @@ struct ReverbState final : public EffectState { for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), todo, 0.0f); - MixRowSamples(mTempLine.data(), A2B[c], mEarlySamples[0].data(), + MixRowSamples(mTempLine.data(), {A2B[c], NUM_LINES}, mEarlySamples[0].data(), mEarlySamples[0].size(), todo); MixSamples(mTempLine.data(), samplesOut, mEarly.CurrentGain[c], mEarly.PanGain[c], counter, offset, todo); @@ -432,8 +432,8 @@ struct ReverbState final : public EffectState { for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), todo, 0.0f); - MixRowSamples(mTempLine.data(), A2B[c], mLateSamples[0].data(), mLateSamples[0].size(), - todo); + MixRowSamples(mTempLine.data(), {A2B[c], NUM_LINES}, mLateSamples[0].data(), + mLateSamples[0].size(), todo); MixSamples(mTempLine.data(), samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], counter, offset, todo); } @@ -447,7 +447,7 @@ struct ReverbState final : public EffectState { for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), todo, 0.0f); - MixRowSamples(mTempLine.data(), A2B[c], mEarlySamples[0].data(), + MixRowSamples(mTempLine.data(), {A2B[c], NUM_LINES}, mEarlySamples[0].data(), mEarlySamples[0].size(), todo); /* Apply scaling to the B-Format's HF response to "upsample" it to @@ -462,8 +462,8 @@ struct ReverbState final : public EffectState { for(ALsizei c{0};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), todo, 0.0f); - MixRowSamples(mTempLine.data(), A2B[c], mLateSamples[0].data(), mLateSamples[0].size(), - todo); + MixRowSamples(mTempLine.data(), {A2B[c], NUM_LINES}, mLateSamples[0].data(), + mLateSamples[0].size(), todo); const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; mAmbiSplitter[1][c].applyHfScale(mTempLine.data(), hfscale, todo); -- cgit v1.2.3 From 34a61122f64d6295f50508cc6945350a5be04924 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Aug 2019 09:49:01 -0700 Subject: Change NUM_LINES to a size_t for MSVC --- alc/effects/reverb.cpp | 66 +++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index f12e5ed9..8ff4feac 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -65,7 +65,7 @@ constexpr int FADE_SAMPLES{128}; * of the conversion matrices, and a few places where the length arrays are * assumed to have 4 elements. */ -constexpr int NUM_LINES{4}; +constexpr size_t NUM_LINES{4u}; /* The B-Format to A-Format conversion matrix. The arrangement of rows is @@ -421,7 +421,7 @@ struct ReverbState final : public EffectState { ASSUME(todo > 0); /* Convert back to B-Format, and mix the results to output. */ - for(ALsizei c{0};c < NUM_LINES;c++) + for(size_t c{0u};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), todo, 0.0f); MixRowSamples(mTempLine.data(), {A2B[c], NUM_LINES}, mEarlySamples[0].data(), @@ -429,7 +429,7 @@ struct ReverbState final : public EffectState { MixSamples(mTempLine.data(), samplesOut, mEarly.CurrentGain[c], mEarly.PanGain[c], counter, offset, todo); } - for(ALsizei c{0};c < NUM_LINES;c++) + for(size_t c{0u};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), todo, 0.0f); MixRowSamples(mTempLine.data(), {A2B[c], NUM_LINES}, mLateSamples[0].data(), @@ -444,7 +444,7 @@ struct ReverbState final : public EffectState { { ASSUME(todo > 0); - for(ALsizei c{0};c < NUM_LINES;c++) + for(size_t c{0u};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), todo, 0.0f); MixRowSamples(mTempLine.data(), {A2B[c], NUM_LINES}, mEarlySamples[0].data(), @@ -459,7 +459,7 @@ struct ReverbState final : public EffectState { MixSamples(mTempLine.data(), samplesOut, mEarly.CurrentGain[c], mEarly.PanGain[c], counter, offset, todo); } - for(ALsizei c{0};c < NUM_LINES;c++) + for(size_t c{0u};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), todo, 0.0f); MixRowSamples(mTempLine.data(), {A2B[c], NUM_LINES}, mLateSamples[0].data(), @@ -724,7 +724,7 @@ void EarlyReflections::updateLines(const ALfloat density, const ALfloat diffusio /* Calculate the all-pass feed-back/forward coefficient. */ VecAp.Coeff = std::sqrt(0.5f) * std::pow(diffusion, 2.0f); - for(ALsizei i{0};i < NUM_LINES;i++) + for(size_t i{0u};i < NUM_LINES;i++) { /* Calculate the length (in seconds) of each all-pass line. */ ALfloat length{EARLY_ALLPASS_LENGTHS[i] * multiplier}; @@ -782,7 +782,7 @@ void LateReverb::updateLines(const ALfloat density, const ALfloat diffusion, /* Calculate the all-pass feed-back/forward coefficient. */ VecAp.Coeff = std::sqrt(0.5f) * std::pow(diffusion, 2.0f); - for(ALsizei i{0};i < NUM_LINES;i++) + for(size_t i{0u};i < NUM_LINES;i++) { /* Calculate the length (in seconds) of each all-pass line. */ length = LATE_ALLPASS_LENGTHS[i] * multiplier; @@ -824,7 +824,7 @@ void ReverbState::updateDelayLine(const ALfloat earlyDelay, const ALfloat lateDe * delay path and offsets that would continue the propagation naturally * into the late lines. */ - for(ALsizei i{0};i < NUM_LINES;i++) + for(size_t i{0u};i < NUM_LINES;i++) { ALfloat length{earlyDelay + EARLY_TAP_LENGTHS[i]*multiplier}; mEarlyDelayTap[i][1] = float2int(length * frequency); @@ -891,13 +891,13 @@ void ReverbState::update3DPanning(const ALfloat *ReflectionsPan, const ALfloat * const alu::Matrix latemat{GetTransformFromVector(LateReverbPan)}; mOutTarget = target.Main->Buffer; - for(ALsizei i{0};i < NUM_LINES;i++) + for(size_t i{0u};i < NUM_LINES;i++) { const ALfloat coeffs[MAX_AMBI_CHANNELS]{earlymat[0][i], earlymat[1][i], earlymat[2][i], earlymat[3][i]}; ComputePanGains(target.Main, coeffs, earlyGain, mEarly.PanGain[i]); } - for(ALsizei i{0};i < NUM_LINES;i++) + for(size_t i{0u};i < NUM_LINES;i++) { const ALfloat coeffs[MAX_AMBI_CHANNELS]{latemat[0][i], latemat[1][i], latemat[2][i], latemat[3][i]}; @@ -922,7 +922,7 @@ void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, co ALfloat gainlf{maxf(props->Reverb.GainLF, 0.001f)}; mFilter[0].Hp.setParams(BiquadType::LowShelf, gainlf, lf0norm, mFilter[0].Hp.rcpQFromSlope(gainlf, 1.0f)); - for(ALsizei i{1};i < NUM_LINES;i++) + for(size_t i{1u};i < NUM_LINES;i++) { mFilter[i].Lp.copyParamsFrom(mFilter[0].Lp); mFilter[i].Hp.copyParamsFrom(mFilter[0].Hp); @@ -1060,7 +1060,7 @@ void VectorScatterRevDelayIn(const DelayLineI delay, ALint offset, const ALfloat ALsizei td{mini(delay.Mask+1 - offset, count-i)}; do { std::array f; - for(ALsizei j{0};j < NUM_LINES;j++) + for(size_t j{0u};j < NUM_LINES;j++) f[NUM_LINES-1-j] = in[j][base+i]; ++i; @@ -1088,22 +1088,22 @@ void VecAllpass::processUnfaded(const al::span sampl ASSUME(todo > 0); ALsizei vap_offset[NUM_LINES]; - for(ALsizei j{0};j < NUM_LINES;j++) + for(size_t j{0u};j < NUM_LINES;j++) vap_offset[j] = offset - Offset[j][0]; for(ALsizei i{0};i < todo;) { - for(ALsizei j{0};j < NUM_LINES;j++) + for(size_t j{0u};j < NUM_LINES;j++) vap_offset[j] &= delay.Mask; offset &= delay.Mask; ALsizei maxoff{offset}; - for(ALsizei j{0};j < NUM_LINES;j++) + for(size_t j{0u};j < NUM_LINES;j++) maxoff = maxi(maxoff, vap_offset[j]); ALsizei td{mini(delay.Mask+1 - maxoff, todo - i)}; do { std::array f; - for(ALsizei j{0};j < NUM_LINES;j++) + for(size_t j{0u};j < NUM_LINES;j++) { const ALfloat input{samples[j][i]}; const ALfloat out{delay.Line[vap_offset[j]++][j] - feedCoeff*input}; @@ -1127,14 +1127,14 @@ void VecAllpass::processFaded(const al::span samples fade *= 1.0f/FADE_SAMPLES; ALsizei vap_offset[NUM_LINES][2]; - for(ALsizei j{0};j < NUM_LINES;j++) + for(size_t j{0u};j < NUM_LINES;j++) { vap_offset[j][0] = offset - Offset[j][0]; vap_offset[j][1] = offset - Offset[j][1]; } for(ALsizei i{0};i < todo;) { - for(ALsizei j{0};j < NUM_LINES;j++) + for(size_t j{0u};j < NUM_LINES;j++) { vap_offset[j][0] &= delay.Mask; vap_offset[j][1] &= delay.Mask; @@ -1142,18 +1142,18 @@ void VecAllpass::processFaded(const al::span samples offset &= delay.Mask; ALsizei maxoff{offset}; - for(ALsizei j{0};j < NUM_LINES;j++) + for(size_t j{0u};j < NUM_LINES;j++) maxoff = maxi(maxoff, maxi(vap_offset[j][0], vap_offset[j][1])); ALsizei td{mini(delay.Mask+1 - maxoff, todo - i)}; do { fade += FadeStep; std::array f; - for(ALsizei j{0};j < NUM_LINES;j++) + for(size_t j{0u};j < NUM_LINES;j++) f[j] = delay.Line[vap_offset[j][0]++][j]*(1.0f-fade) + delay.Line[vap_offset[j][1]++][j]*fade; - for(ALsizei j{0};j < NUM_LINES;j++) + for(size_t j{0u};j < NUM_LINES;j++) { const ALfloat input{samples[j][i]}; const ALfloat out{f[j] - feedCoeff*input}; @@ -1201,7 +1201,7 @@ void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALs /* First, load decorrelated samples from the main delay line as the primary * reflections. */ - for(ALsizei j{0};j < NUM_LINES;j++) + for(size_t j{0u};j < NUM_LINES;j++) { ALsizei early_delay_tap{offset - State->mEarlyDelayTap[j][0]}; const ALfloat coeff{State->mEarlyDelayCoeff[j][0]}; @@ -1223,7 +1223,7 @@ void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALs /* Apply a delay and bounce to generate secondary reflections, combine with * the primary reflections and write out the result for mixing. */ - for(ALsizei j{0};j < NUM_LINES;j++) + for(size_t j{0u};j < NUM_LINES;j++) { ALint feedb_tap{offset - State->mEarly.Offset[j][0]}; const ALfloat feedb_coeff{State->mEarly.Coeff[j][0]}; @@ -1240,7 +1240,7 @@ void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALs } while(--td); } } - for(ALsizei j{0};j < NUM_LINES;j++) + for(size_t j{0u};j < NUM_LINES;j++) early_delay.write(offset, NUM_LINES-1-j, temps[j].data(), todo); /* Also write the result back to the main delay line for the late reverb @@ -1263,7 +1263,7 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz ASSUME(todo > 0); - for(ALsizei j{0};j < NUM_LINES;j++) + for(size_t j{0u};j < NUM_LINES;j++) { ALsizei early_delay_tap0{offset - State->mEarlyDelayTap[j][0]}; ALsizei early_delay_tap1{offset - State->mEarlyDelayTap[j][1]}; @@ -1290,7 +1290,7 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz State->mEarly.VecAp.processFaded(temps, offset, mixX, mixY, fade, todo); - for(ALsizei j{0};j < NUM_LINES;j++) + for(size_t j{0u};j < NUM_LINES;j++) { ALint feedb_tap0{offset - State->mEarly.Offset[j][0]}; ALint feedb_tap1{offset - State->mEarly.Offset[j][1]}; @@ -1317,7 +1317,7 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz } while(--td); } } - for(ALsizei j{0};j < NUM_LINES;j++) + for(size_t j{0u};j < NUM_LINES;j++) early_delay.write(offset, NUM_LINES-1-j, temps[j].data(), todo); const ALsizei late_feed_tap{offset - State->mLateFeedTap}; @@ -1354,7 +1354,7 @@ void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei /* First, load decorrelated samples from the main and feedback delay lines. * Filter the signal to apply its frequency-dependent decay. */ - for(ALsizei j{0};j < NUM_LINES;j++) + for(size_t j{0u};j < NUM_LINES;j++) { ALsizei late_delay_tap{offset - State->mLateDelayTap[j][0]}; ALsizei late_feedb_tap{offset - State->mLate.Offset[j][0]}; @@ -1380,7 +1380,7 @@ void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei * out the results for mixing. */ State->mLate.VecAp.processUnfaded(temps, offset, mixX, mixY, todo); - for(ALsizei j{0};j < NUM_LINES;j++) + for(size_t j{0u};j < NUM_LINES;j++) std::copy_n(temps[j].begin(), todo, State->mLateSamples[j].begin() + base); /* Finally, scatter and bounce the results to refeed the feedback buffer. */ @@ -1398,7 +1398,7 @@ void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei to ASSUME(todo > 0); - for(ALsizei j{0};j < NUM_LINES;j++) + for(size_t j{0u};j < NUM_LINES;j++) { const ALfloat oldMidGain{State->mLate.T60[j].MidGain[0]}; const ALfloat midGain{State->mLate.T60[j].MidGain[1]}; @@ -1441,7 +1441,7 @@ void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei to } State->mLate.VecAp.processFaded(temps, offset, mixX, mixY, fade, todo); - for(ALsizei j{0};j < NUM_LINES;j++) + for(size_t j{0u};j < NUM_LINES;j++) std::copy_n(temps[j].begin(), todo, State->mLateSamples[j].begin()); VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, 0, {temps.cbegin(), temps.cend()}, @@ -1457,7 +1457,7 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST ASSUME(offset >= 0); /* Convert B-Format to A-Format for processing. */ - for(ALsizei c{0};c < NUM_LINES;c++) + for(size_t c{0u};c < NUM_LINES;c++) { std::fill_n(mTempLine.begin(), samplesToDo, 0.0f); MixRowSamples(mTempLine.data(), {B2A[c], B2A[c]+numInput}, samplesIn->data(), @@ -1499,7 +1499,7 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST if(fadeCount == FADE_SAMPLES) { /* Update the cross-fading delay line taps. */ - for(ALsizei c{0};c < NUM_LINES;c++) + for(size_t c{0u};c < NUM_LINES;c++) { mEarlyDelayTap[c][0] = mEarlyDelayTap[c][1]; mEarlyDelayCoeff[c][0] = mEarlyDelayCoeff[c][1]; -- cgit v1.2.3 From 8fd90334a13608a781e36fc830cd79bf746edd42 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Aug 2019 00:27:28 -0700 Subject: Pass the MixRow buffer size as a span --- alc/alu.h | 4 ++-- alc/bformatdec.cpp | 13 +++++++------ alc/effects/reverb.cpp | 32 +++++++++++++++++--------------- alc/mixer/defs.h | 3 ++- alc/mixer/mixer_c.cpp | 14 ++++++-------- alc/mixer/mixer_neon.cpp | 25 +++++++++++-------------- alc/mixer/mixer_sse.cpp | 27 ++++++++++++--------------- 7 files changed, 57 insertions(+), 61 deletions(-) diff --git a/alc/alu.h b/alc/alu.h index 117c932d..c63e33fd 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -317,8 +317,8 @@ struct ALvoice { using MixerFunc = void(*)(const ALfloat *data, const al::span OutBuffer, ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize); -using RowMixerFunc = void(*)(ALfloat *OutBuffer, const al::span Gains, - const ALfloat *InSamples, const ALsizei InStride, const ALsizei BufferSize); +using RowMixerFunc = void(*)(const al::span OutBuffer, const al::span Gains, + const float *InSamples, const size_t InStride); using HrtfMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfFilter *hrtfparams, const ALsizei BufferSize); diff --git a/alc/bformatdec.cpp b/alc/bformatdec.cpp index ce4c4b3b..7d681bc6 100644 --- a/alc/bformatdec.cpp +++ b/alc/bformatdec.cpp @@ -162,10 +162,11 @@ void BFormatDec::process(const al::span OutBuffer, { if LIKELY(enabled&1) { - MixRowSamples(outbuf.data(), {(*mixmtx)[sHFBand], mNumChannels}, - mSamplesHF->data(), mSamplesHF->size(), SamplesToDo); - MixRowSamples(outbuf.data(), {(*mixmtx)[sLFBand], mNumChannels}, - mSamplesLF->data(), mSamplesLF->size(), SamplesToDo); + const al::span outspan{outbuf.data(), outbuf.data()+SamplesToDo}; + MixRowSamples(outspan, {(*mixmtx)[sHFBand], mNumChannels}, mSamplesHF->data(), + mSamplesHF->size()); + MixRowSamples(outspan, {(*mixmtx)[sLFBand], mNumChannels}, mSamplesLF->data(), + mSamplesLF->size()); } ++mixmtx; enabled >>= 1; @@ -178,8 +179,8 @@ void BFormatDec::process(const al::span OutBuffer, for(FloatBufferLine &outbuf : OutBuffer) { if LIKELY(enabled&1) - MixRowSamples(outbuf.data(), {*mixmtx, mNumChannels}, InSamples->data(), - InSamples->size(), SamplesToDo); + MixRowSamples({outbuf.data(), outbuf.data()+SamplesToDo}, {*mixmtx, mNumChannels}, + InSamples->data(), InSamples->size()); ++mixmtx; enabled >>= 1; } diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 8ff4feac..5f8daabe 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -421,19 +421,20 @@ struct ReverbState final : public EffectState { ASSUME(todo > 0); /* Convert back to B-Format, and mix the results to output. */ + const al::span tmpspan{mTempLine.begin(), mTempLine.begin()+todo}; for(size_t c{0u};c < NUM_LINES;c++) { - std::fill_n(mTempLine.begin(), todo, 0.0f); - MixRowSamples(mTempLine.data(), {A2B[c], NUM_LINES}, mEarlySamples[0].data(), - mEarlySamples[0].size(), todo); + std::fill(tmpspan.begin(), tmpspan.end(), 0.0f); + MixRowSamples(tmpspan, {A2B[c], NUM_LINES}, mEarlySamples[0].data(), + mEarlySamples[0].size()); MixSamples(mTempLine.data(), samplesOut, mEarly.CurrentGain[c], mEarly.PanGain[c], counter, offset, todo); } for(size_t c{0u};c < NUM_LINES;c++) { - std::fill_n(mTempLine.begin(), todo, 0.0f); - MixRowSamples(mTempLine.data(), {A2B[c], NUM_LINES}, mLateSamples[0].data(), - mLateSamples[0].size(), todo); + std::fill(tmpspan.begin(), tmpspan.end(), 0.0f); + MixRowSamples(tmpspan, {A2B[c], NUM_LINES}, mLateSamples[0].data(), + mLateSamples[0].size()); MixSamples(mTempLine.data(), samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], counter, offset, todo); } @@ -444,11 +445,12 @@ struct ReverbState final : public EffectState { { ASSUME(todo > 0); + const al::span tmpspan{mTempLine.begin(), mTempLine.begin()+todo}; for(size_t c{0u};c < NUM_LINES;c++) { - std::fill_n(mTempLine.begin(), todo, 0.0f); - MixRowSamples(mTempLine.data(), {A2B[c], NUM_LINES}, mEarlySamples[0].data(), - mEarlySamples[0].size(), todo); + std::fill(tmpspan.begin(), tmpspan.end(), 0.0f); + MixRowSamples(tmpspan, {A2B[c], NUM_LINES}, mEarlySamples[0].data(), + mEarlySamples[0].size()); /* Apply scaling to the B-Format's HF response to "upsample" it to * higher-order output. @@ -461,9 +463,9 @@ struct ReverbState final : public EffectState { } for(size_t c{0u};c < NUM_LINES;c++) { - std::fill_n(mTempLine.begin(), todo, 0.0f); - MixRowSamples(mTempLine.data(), {A2B[c], NUM_LINES}, mLateSamples[0].data(), - mLateSamples[0].size(), todo); + std::fill(tmpspan.begin(), tmpspan.end(), 0.0f); + MixRowSamples(tmpspan, {A2B[c], NUM_LINES}, mLateSamples[0].data(), + mLateSamples[0].size()); const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; mAmbiSplitter[1][c].applyHfScale(mTempLine.data(), hfscale, todo); @@ -1457,11 +1459,11 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST ASSUME(offset >= 0); /* Convert B-Format to A-Format for processing. */ + const al::span tmpspan{mTempLine.begin(), mTempLine.begin()+samplesToDo}; for(size_t c{0u};c < NUM_LINES;c++) { - std::fill_n(mTempLine.begin(), samplesToDo, 0.0f); - MixRowSamples(mTempLine.data(), {B2A[c], B2A[c]+numInput}, samplesIn->data(), - samplesIn->size(), samplesToDo); + std::fill(tmpspan.begin(), tmpspan.end(), 0.0f); + MixRowSamples(tmpspan, {B2A[c], B2A[c]+numInput}, samplesIn->data(), samplesIn->size()); /* Band-pass the incoming samples and feed the initial delay line. */ mFilter[c].Lp.process(mTempLine.data(), mTempLine.data(), samplesToDo); diff --git a/alc/mixer/defs.h b/alc/mixer/defs.h index 19fb42d0..adaed8f5 100644 --- a/alc/mixer/defs.h +++ b/alc/mixer/defs.h @@ -32,7 +32,8 @@ const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, template void Mix_(const ALfloat *data, const al::span OutBuffer, ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize); template -void MixRow_(ALfloat *OutBuffer, const al::span Gains, const ALfloat *InSamples, const ALsizei InStride, const ALsizei BufferSize); +void MixRow_(const al::span OutBuffer, const al::span Gains, + const float *InSamples, const size_t InStride); template void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfFilter *hrtfparams, const ALsizei BufferSize); diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index 4985933c..dd094040 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -189,20 +189,18 @@ void Mix_(const ALfloat *data, const al::span OutBuffer, * stepping is necessary. */ template<> -void MixRow_(ALfloat *OutBuffer, const al::span Gains, - const ALfloat *InSamples, const ALsizei InStride, const ALsizei BufferSize) +void MixRow_(const al::span OutBuffer, const al::span Gains, + const float *InSamples, const size_t InStride) { - ASSUME(BufferSize > 0); - - for(const ALfloat gain : Gains) + for(const float gain : Gains) { - const ALfloat *RESTRICT src{InSamples}; + const float *RESTRICT src{InSamples}; InSamples += InStride; if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; - for(ALsizei i{0};i < BufferSize;i++) - OutBuffer[i] += src[i] * gain; + std::transform(OutBuffer.begin(), OutBuffer.end(), src, OutBuffer.begin(), + [gain](const ALfloat cur, const ALfloat src) -> ALfloat { return cur + src*gain; }); } } diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index c6ea2c60..829d4ea1 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -276,11 +276,9 @@ void Mix_(const ALfloat *data, const al::span OutBuffe } template<> -void MixRow_(ALfloat *OutBuffer, const al::span Gains, - const ALfloat *InSamples, const ALsizei InStride, const ALsizei BufferSize) +void MixRow_(const al::span OutBuffer, const al::span Gains, + const ALfloat *InSamples, const ALsizei InStride) { - ASSUME(BufferSize > 0); - for(const ALfloat gain : Gains) { const ALfloat *RESTRICT src{InSamples}; @@ -289,20 +287,19 @@ void MixRow_(ALfloat *OutBuffer, const al::span Gains, if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; - ALsizei pos{0}; - if LIKELY(BufferSize > 3) + auto out_iter = OutBuffer.begin(); + if(size_t todo{OutBuffer.size() >> 2}) { - ALsizei todo{BufferSize >> 2}; - float32x4_t gain4{vdupq_n_f32(gain)}; + const float32x4_t gain4{vdupq_n_f32(gain)}; do { - const float32x4_t val4 = vld1q_f32(&src[pos]); - float32x4_t dry4 = vld1q_f32(&OutBuffer[pos]); + const float32x4_t val4 = vld1q_f32(src); + float32x4_t dry4 = vld1q_f32(out_iter); dry4 = vmlaq_f32(dry4, val4, gain4); - vst1q_f32(&OutBuffer[pos], dry4); - pos += 4; + vst1q_f32(out_iter, dry4); + out_iter += 4; src += 4; } while(--todo); } - for(;pos < BufferSize;pos++) - OutBuffer[pos] += src[pos]*gain; + std::transform(out_iter, OutBuffer.end(), src, out_iter, + [gain](const ALfloat cur, const ALfloat src) -> ALfloat { return cur + src*gain; }); } } diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index b5958c8e..b3454898 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -229,33 +229,30 @@ void Mix_(const ALfloat *data, const al::span OutBuffer } template<> -void MixRow_(ALfloat *OutBuffer, const al::span Gains, - const ALfloat *InSamples, const ALsizei InStride, const ALsizei BufferSize) +void MixRow_(const al::span OutBuffer, const al::span Gains, + const float *InSamples, const size_t InStride) { - ASSUME(BufferSize > 0); - - for(const ALfloat gain : Gains) + for(const float gain : Gains) { - const ALfloat *RESTRICT src{InSamples}; + const float *RESTRICT src{InSamples}; InSamples += InStride; if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; - ALsizei pos{0}; - if LIKELY(BufferSize > 3) + auto out_iter = OutBuffer.begin(); + if(size_t todo{OutBuffer.size() >> 2}) { - ALsizei todo{BufferSize >> 2}; const __m128 gain4 = _mm_set1_ps(gain); do { - const __m128 val4{_mm_load_ps(&src[pos])}; - __m128 dry4{_mm_load_ps(&OutBuffer[pos])}; + const __m128 val4{_mm_load_ps(src)}; + __m128 dry4{_mm_load_ps(out_iter)}; dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); - _mm_store_ps(&OutBuffer[pos], dry4); - pos += 4; + _mm_store_ps(out_iter, dry4); + out_iter += 4; src += 4; } while(--todo); } - for(;pos < BufferSize;pos++) - OutBuffer[pos] += src[pos]*gain; + std::transform(out_iter, OutBuffer.end(), src, out_iter, + [gain](const ALfloat cur, const ALfloat src) -> ALfloat { return cur + src*gain; }); } } -- cgit v1.2.3 From 4883091f5de278b7469790efa466df5d93d465b0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Aug 2019 01:24:02 -0700 Subject: Rename the Mix function input for clarity --- alc/alu.h | 2 +- alc/mixer/defs.h | 4 +++- alc/mixer/mixer_c.cpp | 8 ++++---- alc/mixer/mixer_neon.cpp | 14 +++++++------- alc/mixer/mixer_sse.cpp | 14 +++++++------- 5 files changed, 22 insertions(+), 20 deletions(-) diff --git a/alc/alu.h b/alc/alu.h index c63e33fd..eba9ee0e 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -314,7 +314,7 @@ struct ALvoice { }; -using MixerFunc = void(*)(const ALfloat *data, const al::span OutBuffer, +using MixerFunc = void(*)(const ALfloat *InSamples, const al::span OutBuffer, ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize); using RowMixerFunc = void(*)(const al::span OutBuffer, const al::span Gains, diff --git a/alc/mixer/defs.h b/alc/mixer/defs.h index adaed8f5..1e5e68bb 100644 --- a/alc/mixer/defs.h +++ b/alc/mixer/defs.h @@ -30,7 +30,9 @@ template const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen); template -void Mix_(const ALfloat *data, const al::span OutBuffer, ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize); +void Mix_(const float *InSamples, const al::span OutBuffer, float *CurrentGains, + const float *TargetGains, const ALsizei Counter, const ALsizei OutPos, + const ALsizei BufferSize); template void MixRow_(const al::span OutBuffer, const al::span Gains, const float *InSamples, const size_t InStride); diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index dd094040..8b5c0f41 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -142,8 +142,8 @@ void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> -void Mix_(const ALfloat *data, const al::span OutBuffer, - ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, +void Mix_(const float *InSamples, const al::span OutBuffer, + float *CurrentGains, const float *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize) { ASSUME(BufferSize > 0); @@ -163,7 +163,7 @@ void Mix_(const ALfloat *data, const al::span OutBuffer, ALfloat step_count{0.0f}; for(;pos < minsize;pos++) { - dst[pos] += data[pos] * (gain + step*step_count); + dst[pos] += InSamples[pos] * (gain + step*step_count); step_count += 1.0f; } if(pos == Counter) @@ -178,7 +178,7 @@ void Mix_(const ALfloat *data, const al::span OutBuffer, if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; for(;pos < BufferSize;pos++) - dst[pos] += data[pos]*gain; + dst[pos] += InSamples[pos]*gain; } } diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index 829d4ea1..b80f8cf8 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -189,8 +189,8 @@ void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut template<> -void Mix_(const ALfloat *data, const al::span OutBuffer, - ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, +void Mix_(const float *InSamples, const al::span OutBuffer, + float *CurrentGains, const float *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize) { ASSUME(BufferSize > 0); @@ -223,7 +223,7 @@ void Mix_(const ALfloat *data, const al::span OutBuffe ALsizei todo{minsize >> 2}; do { - const float32x4_t val4 = vld1q_f32(&data[pos]); + const float32x4_t val4 = vld1q_f32(&InSamples[pos]); float32x4_t dry4 = vld1q_f32(&dst[pos]); dry4 = vmlaq_f32(dry4, val4, vmlaq_f32(gain4, step4, step_count4)); step_count4 = vaddq_f32(step_count4, four4); @@ -239,7 +239,7 @@ void Mix_(const ALfloat *data, const al::span OutBuffe /* Mix with applying left over gain steps that aren't aligned multiples of 4. */ for(;pos < minsize;pos++) { - dst[pos] += data[pos]*(gain + step*step_count); + dst[pos] += InSamples[pos]*(gain + step*step_count); step_count += 1.0f; } if(pos == Counter) @@ -251,7 +251,7 @@ void Mix_(const ALfloat *data, const al::span OutBuffe /* Mix until pos is aligned with 4 or the mix is done. */ minsize = mini(BufferSize, (pos+3)&~3); for(;pos < minsize;pos++) - dst[pos] += data[pos]*gain; + dst[pos] += InSamples[pos]*gain; } ++CurrentGains; ++TargetGains; @@ -263,7 +263,7 @@ void Mix_(const ALfloat *data, const al::span OutBuffe ALsizei todo{(BufferSize-pos) >> 2}; const float32x4_t gain4 = vdupq_n_f32(gain); do { - const float32x4_t val4 = vld1q_f32(&data[pos]); + const float32x4_t val4 = vld1q_f32(&InSamples[pos]); float32x4_t dry4 = vld1q_f32(&dst[pos]); dry4 = vmlaq_f32(dry4, val4, gain4); vst1q_f32(&dst[pos], dry4); @@ -271,7 +271,7 @@ void Mix_(const ALfloat *data, const al::span OutBuffe } while(--todo); } for(;pos < BufferSize;pos++) - dst[pos] += data[pos]*gain; + dst[pos] += InSamples[pos]*gain; } } diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index b3454898..bd0042a1 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -145,8 +145,8 @@ void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> -void Mix_(const ALfloat *data, const al::span OutBuffer, - ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, +void Mix_(const float *InSamples, const al::span OutBuffer, + float *CurrentGains, const float *TargetGains, const ALsizei Counter, const ALsizei OutPos, const ALsizei BufferSize) { ASSUME(BufferSize > 0); @@ -173,7 +173,7 @@ void Mix_(const ALfloat *data, const al::span OutBuffer __m128 step_count4{_mm_setr_ps(0.0f, 1.0f, 2.0f, 3.0f)}; ALsizei todo{minsize >> 2}; do { - const __m128 val4{_mm_load_ps(&data[pos])}; + const __m128 val4{_mm_load_ps(&InSamples[pos])}; __m128 dry4{_mm_load_ps(&dst[pos])}; #define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z)) /* dry += val * (gain + step*step_count) */ @@ -192,7 +192,7 @@ void Mix_(const ALfloat *data, const al::span OutBuffer /* Mix with applying left over gain steps that aren't aligned multiples of 4. */ for(;pos < minsize;pos++) { - dst[pos] += data[pos]*(gain + step*step_count); + dst[pos] += InSamples[pos]*(gain + step*step_count); step_count += 1.0f; } if(pos == Counter) @@ -204,7 +204,7 @@ void Mix_(const ALfloat *data, const al::span OutBuffer /* Mix until pos is aligned with 4 or the mix is done. */ minsize = mini(BufferSize, (pos+3)&~3); for(;pos < minsize;pos++) - dst[pos] += data[pos]*gain; + dst[pos] += InSamples[pos]*gain; } ++CurrentGains; ++TargetGains; @@ -216,7 +216,7 @@ void Mix_(const ALfloat *data, const al::span OutBuffer ALsizei todo{(BufferSize-pos) >> 2}; const __m128 gain4{_mm_set1_ps(gain)}; do { - const __m128 val4{_mm_load_ps(&data[pos])}; + const __m128 val4{_mm_load_ps(&InSamples[pos])}; __m128 dry4{_mm_load_ps(&dst[pos])}; dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); _mm_store_ps(&dst[pos], dry4); @@ -224,7 +224,7 @@ void Mix_(const ALfloat *data, const al::span OutBuffer } while(--todo); } for(;pos < BufferSize;pos++) - dst[pos] += data[pos]*gain; + dst[pos] += InSamples[pos]*gain; } } -- cgit v1.2.3 From 102ef6cb3356ef81e2a392d3aa8bd6324eb3ff30 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Aug 2019 04:16:44 -0700 Subject: Pass a span for the Mix function's input --- alc/alu.h | 6 +++--- alc/effects/autowah.cpp | 4 ++-- alc/effects/chorus.cpp | 8 +++---- alc/effects/dedicated.cpp | 4 ++-- alc/effects/echo.cpp | 4 ++-- alc/effects/equalizer.cpp | 4 ++-- alc/effects/fshifter.cpp | 4 ++-- alc/effects/modulator.cpp | 4 ++-- alc/effects/pshifter.cpp | 4 ++-- alc/effects/reverb.cpp | 20 +++++++++--------- alc/effects/vmorpher.cpp | 11 +++++----- alc/mixer/defs.h | 5 ++--- alc/mixer/mixer_c.cpp | 24 ++++++++++----------- alc/mixer/mixer_neon.cpp | 54 ++++++++++++++++++++++------------------------- alc/mixer/mixer_sse.cpp | 51 +++++++++++++++++++++----------------------- alc/mixvoice.cpp | 22 ++++++++++--------- 16 files changed, 110 insertions(+), 119 deletions(-) diff --git a/alc/alu.h b/alc/alu.h index eba9ee0e..9765e113 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -314,9 +314,9 @@ struct ALvoice { }; -using MixerFunc = void(*)(const ALfloat *InSamples, const al::span OutBuffer, - ALfloat *CurrentGains, const ALfloat *TargetGains, const ALsizei Counter, const ALsizei OutPos, - const ALsizei BufferSize); +using MixerFunc = void(*)(const al::span InSamples, + const al::span OutBuffer, float *CurrentGains, const float *TargetGains, + const ALsizei Counter, const ALsizei OutPos); using RowMixerFunc = void(*)(const al::span OutBuffer, const al::span Gains, const float *InSamples, const size_t InStride); using HrtfMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, diff --git a/alc/effects/autowah.cpp b/alc/effects/autowah.cpp index f16c5ba5..10d69b6c 100644 --- a/alc/effects/autowah.cpp +++ b/alc/effects/autowah.cpp @@ -190,8 +190,8 @@ void ALautowahState::process(const ALsizei samplesToDo, const FloatBufferLine *R mChans[c].Filter.z2 = z2; /* Now, mix the processed sound data to the output. */ - MixSamples(mBufferOut, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, - samplesToDo, 0, samplesToDo); + MixSamples({mBufferOut, mBufferOut+samplesToDo}, samplesOut, mChans[c].CurrentGains, + mChans[c].TargetGains, samplesToDo, 0); } } diff --git a/alc/effects/chorus.cpp b/alc/effects/chorus.cpp index 5966d3bd..7b43962c 100644 --- a/alc/effects/chorus.cpp +++ b/alc/effects/chorus.cpp @@ -218,9 +218,8 @@ void ChorusState::process(const ALsizei samplesToDo, const FloatBufferLine *REST for(ALsizei base{0};base < samplesToDo;) { const ALsizei todo = mini(256, samplesToDo-base); - ALint moddelays[2][256]; - alignas(16) ALfloat temps[2][256]; + ALint moddelays[2][256]; if(mWaveform == WaveForm::Sinusoid) { GetSinusoidDelays(moddelays[0], mLfoOffset, mLfoRange, mLfoScale, mDepth, mDelay, @@ -237,6 +236,7 @@ void ChorusState::process(const ALsizei samplesToDo, const FloatBufferLine *REST } mLfoOffset = (mLfoOffset+todo) % mLfoRange; + alignas(16) ALfloat temps[2][256]; for(ALsizei i{0};i < todo;i++) { // Feed the buffer's input first (necessary for delays < 1). @@ -262,8 +262,8 @@ void ChorusState::process(const ALsizei samplesToDo, const FloatBufferLine *REST } for(ALsizei c{0};c < 2;c++) - MixSamples(temps[c], samplesOut, mGains[c].Current, mGains[c].Target, samplesToDo-base, - base, todo); + MixSamples({temps[c], temps[c]+todo}, samplesOut, mGains[c].Current, mGains[c].Target, + samplesToDo-base, base); base += todo; } diff --git a/alc/effects/dedicated.cpp b/alc/effects/dedicated.cpp index 2e49658f..dc5e8527 100644 --- a/alc/effects/dedicated.cpp +++ b/alc/effects/dedicated.cpp @@ -88,8 +88,8 @@ void DedicatedState::update(const ALCcontext*, const ALeffectslot *slot, const E void DedicatedState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) { - MixSamples(samplesIn[0].data(), samplesOut, mCurrentGains, mTargetGains, samplesToDo, 0, - samplesToDo); + MixSamples({samplesIn[0].data(), samplesIn[0].data()+samplesToDo}, samplesOut, mCurrentGains, + mTargetGains, samplesToDo, 0); } diff --git a/alc/effects/echo.cpp b/alc/effects/echo.cpp index d41c4f67..57279005 100644 --- a/alc/effects/echo.cpp +++ b/alc/effects/echo.cpp @@ -156,8 +156,8 @@ void EchoState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRI mOffset = offset; for(ALsizei c{0};c < 2;c++) - MixSamples(mTempBuffer[c], samplesOut, mGains[c].Current, mGains[c].Target, samplesToDo, 0, - samplesToDo); + MixSamples({mTempBuffer[c], mTempBuffer[c]+samplesToDo}, samplesOut, mGains[c].Current, + mGains[c].Target, samplesToDo, 0); } diff --git a/alc/effects/equalizer.cpp b/alc/effects/equalizer.cpp index 12183814..27de12ad 100644 --- a/alc/effects/equalizer.cpp +++ b/alc/effects/equalizer.cpp @@ -167,8 +167,8 @@ void EqualizerState::process(const ALsizei samplesToDo, const FloatBufferLine *R mChans[c].filter[2].process(mSampleBuffer, mSampleBuffer, samplesToDo); mChans[c].filter[3].process(mSampleBuffer, mSampleBuffer, samplesToDo); - MixSamples(mSampleBuffer, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, - samplesToDo, 0, samplesToDo); + MixSamples({mSampleBuffer, mSampleBuffer+samplesToDo}, samplesOut, mChans[c].CurrentGains, + mChans[c].TargetGains, samplesToDo, 0); } } diff --git a/alc/effects/fshifter.cpp b/alc/effects/fshifter.cpp index 7688c762..638325ec 100644 --- a/alc/effects/fshifter.cpp +++ b/alc/effects/fshifter.cpp @@ -222,8 +222,8 @@ void FshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE } /* Now, mix the processed sound data to the output. */ - MixSamples(BufferOut, samplesOut, mGains[c].Current, mGains[c].Target, - maxi(samplesToDo, 512), 0, samplesToDo); + MixSamples({BufferOut, BufferOut+samplesToDo}, samplesOut, mGains[c].Current, + mGains[c].Target, maxi(samplesToDo, 512), 0); } } diff --git a/alc/effects/modulator.cpp b/alc/effects/modulator.cpp index 8a6378cd..48022e15 100644 --- a/alc/effects/modulator.cpp +++ b/alc/effects/modulator.cpp @@ -160,8 +160,8 @@ void ModulatorState::process(const ALsizei samplesToDo, const FloatBufferLine *R for(i = 0;i < td;i++) temps[i] *= modsamples[i]; - MixSamples(temps, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, - samplesToDo-base, base, td); + MixSamples({temps, temps+td}, samplesOut, mChans[c].CurrentGains, + mChans[c].TargetGains, samplesToDo-base, base); } base += td; diff --git a/alc/effects/pshifter.cpp b/alc/effects/pshifter.cpp index 0ba0b496..e1181fe7 100644 --- a/alc/effects/pshifter.cpp +++ b/alc/effects/pshifter.cpp @@ -285,8 +285,8 @@ void PshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE mCount = count; /* Now, mix the processed sound data to the output. */ - MixSamples(bufferOut, samplesOut, mCurrentGains, mTargetGains, maxi(samplesToDo, 512), 0, - samplesToDo); + MixSamples({bufferOut, bufferOut+samplesToDo}, samplesOut, mCurrentGains, mTargetGains, + maxi(samplesToDo, 512), 0); } diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 5f8daabe..1e5cb861 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -427,16 +427,16 @@ struct ReverbState final : public EffectState { std::fill(tmpspan.begin(), tmpspan.end(), 0.0f); MixRowSamples(tmpspan, {A2B[c], NUM_LINES}, mEarlySamples[0].data(), mEarlySamples[0].size()); - MixSamples(mTempLine.data(), samplesOut, mEarly.CurrentGain[c], - mEarly.PanGain[c], counter, offset, todo); + MixSamples(tmpspan, samplesOut, mEarly.CurrentGain[c], mEarly.PanGain[c], counter, + offset); } for(size_t c{0u};c < NUM_LINES;c++) { std::fill(tmpspan.begin(), tmpspan.end(), 0.0f); MixRowSamples(tmpspan, {A2B[c], NUM_LINES}, mLateSamples[0].data(), mLateSamples[0].size()); - MixSamples(mTempLine.data(), samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], - counter, offset, todo); + MixSamples(tmpspan, samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], counter, + offset); } } @@ -456,10 +456,10 @@ struct ReverbState final : public EffectState { * higher-order output. */ const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; - mAmbiSplitter[0][c].applyHfScale(mTempLine.data(), hfscale, todo); + mAmbiSplitter[0][c].applyHfScale(tmpspan.data(), hfscale, todo); - MixSamples(mTempLine.data(), samplesOut, mEarly.CurrentGain[c], - mEarly.PanGain[c], counter, offset, todo); + MixSamples(tmpspan, samplesOut, mEarly.CurrentGain[c], mEarly.PanGain[c], counter, + offset); } for(size_t c{0u};c < NUM_LINES;c++) { @@ -468,10 +468,10 @@ struct ReverbState final : public EffectState { mLateSamples[0].size()); const ALfloat hfscale{(c==0) ? mOrderScales[0] : mOrderScales[1]}; - mAmbiSplitter[1][c].applyHfScale(mTempLine.data(), hfscale, todo); + mAmbiSplitter[1][c].applyHfScale(tmpspan.data(), hfscale, todo); - MixSamples(mTempLine.data(), samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], - counter, offset, todo); + MixSamples(tmpspan, samplesOut, mLate.CurrentGain[c], mLate.PanGain[c], counter, + offset); } } diff --git a/alc/effects/vmorpher.cpp b/alc/effects/vmorpher.cpp index bf144abb..1f796786 100644 --- a/alc/effects/vmorpher.cpp +++ b/alc/effects/vmorpher.cpp @@ -279,14 +279,13 @@ void VmorpherState::process(const ALsizei samplesToDo, const FloatBufferLine *RE vowelB[2].process(&samplesIn[c][base], mSampleBufferB, td); vowelB[3].process(&samplesIn[c][base], mSampleBufferB, td); - alignas(16) ALfloat samplesBlended[MAX_UPDATE_SAMPLES]; - - for (ALsizei i{0};i < td;i++) - samplesBlended[i] = lerp(mSampleBufferA[i], mSampleBufferB[i], lfo[i]); + alignas(16) ALfloat blended[MAX_UPDATE_SAMPLES]; + for(ALsizei i{0};i < td;i++) + blended[i] = lerp(mSampleBufferA[i], mSampleBufferB[i], lfo[i]); /* Now, mix the processed sound data to the output. */ - MixSamples(samplesBlended, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, - samplesToDo-base, base, td); + MixSamples({blended, blended+td}, samplesOut, mChans[c].CurrentGains, + mChans[c].TargetGains, samplesToDo-base, base); } base += td; diff --git a/alc/mixer/defs.h b/alc/mixer/defs.h index 1e5e68bb..9d4fd063 100644 --- a/alc/mixer/defs.h +++ b/alc/mixer/defs.h @@ -30,9 +30,8 @@ template const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen); template -void Mix_(const float *InSamples, const al::span OutBuffer, float *CurrentGains, - const float *TargetGains, const ALsizei Counter, const ALsizei OutPos, - const ALsizei BufferSize); +void Mix_(const al::span InSamples, const al::span OutBuffer, + float *CurrentGains, const float *TargetGains, const ALsizei Counter, const ALsizei OutPos); template void MixRow_(const al::span OutBuffer, const al::span Gains, const float *InSamples, const size_t InStride); diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index 8b5c0f41..e7ca23d5 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -142,31 +142,29 @@ void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> -void Mix_(const float *InSamples, const al::span OutBuffer, - float *CurrentGains, const float *TargetGains, const ALsizei Counter, const ALsizei OutPos, - const ALsizei BufferSize) +void Mix_(const al::span InSamples, const al::span OutBuffer, + float *CurrentGains, const float *TargetGains, const ALsizei Counter, const ALsizei OutPos) { - ASSUME(BufferSize > 0); - const ALfloat delta{(Counter > 0) ? 1.0f / static_cast(Counter) : 0.0f}; + const bool reached_target{InSamples.size() >= static_cast(Counter)}; + const auto min_end = reached_target ? InSamples.begin() + Counter : InSamples.end(); for(FloatBufferLine &output : OutBuffer) { - ALfloat *RESTRICT dst{output.data()+OutPos}; + ALfloat *RESTRICT dst{al::assume_aligned<16>(output.data()+OutPos)}; ALfloat gain{*CurrentGains}; const ALfloat diff{*TargetGains - gain}; - ALsizei pos{0}; + auto in_iter = InSamples.begin(); if(std::fabs(diff) > std::numeric_limits::epsilon()) { - ALsizei minsize{mini(BufferSize, Counter)}; const ALfloat step{diff * delta}; ALfloat step_count{0.0f}; - for(;pos < minsize;pos++) + while(in_iter != min_end) { - dst[pos] += InSamples[pos] * (gain + step*step_count); + *(dst++) += *(in_iter++) * (gain + step*step_count); step_count += 1.0f; } - if(pos == Counter) + if(reached_target) gain = *TargetGains; else gain += step*step_count; @@ -177,8 +175,8 @@ void Mix_(const float *InSamples, const al::span OutBuffe if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; - for(;pos < BufferSize;pos++) - dst[pos] += InSamples[pos]*gain; + while(in_iter != InSamples.end()) + *(dst++) += *(in_iter++) * gain; } } diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index b80f8cf8..1c4466c2 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -189,27 +189,27 @@ void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut template<> -void Mix_(const float *InSamples, const al::span OutBuffer, - float *CurrentGains, const float *TargetGains, const ALsizei Counter, const ALsizei OutPos, - const ALsizei BufferSize) +void Mix_(const al::span InSamples, const al::span OutBuffer, + float *CurrentGains, const float *TargetGains, const ALsizei Counter, const ALsizei OutPos) { - ASSUME(BufferSize > 0); - - const ALfloat delta{(Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f}; + const ALfloat delta{(Counter > 0) ? 1.0f / static_cast(Counter) : 0.0f}; + const bool reached_target{InSamples.size() >= static_cast(Counter)}; + const auto min_end = reached_target ? InSamples.begin() + Counter : InSamples.end(); + const auto aligned_end = minz(InSamples.size(), (min_end-InSamples.begin()+3) & ~3) + + InSamples.begin(); for(FloatBufferLine &output : OutBuffer) { ALfloat *RESTRICT dst{al::assume_aligned<16>(output.data()+OutPos)}; ALfloat gain{*CurrentGains}; const ALfloat diff{*TargetGains - gain}; - ALsizei pos{0}; + auto in_iter = InSamples.begin(); if(std::fabs(diff) > std::numeric_limits::epsilon()) { - ALsizei minsize{mini(BufferSize, Counter)}; const ALfloat step{diff * delta}; ALfloat step_count{0.0f}; /* Mix with applying gain steps in aligned multiples of 4. */ - if LIKELY(minsize > 3) + if(ptrdiff_t todo{(min_end-in_iter) >> 2}) { const float32x4_t four4{vdupq_n_f32(4.0f)}; const float32x4_t step4{vdupq_n_f32(step)}; @@ -220,15 +220,13 @@ void Mix_(const float *InSamples, const al::span OutBu vsetq_lane_f32(3.0f, vdupq_n_f32(0.0f), 3), 2), 1), 0 )}; - ALsizei todo{minsize >> 2}; - do { - const float32x4_t val4 = vld1q_f32(&InSamples[pos]); - float32x4_t dry4 = vld1q_f32(&dst[pos]); + const float32x4_t val4 = vld1q_f32(in_iter); + float32x4_t dry4 = vld1q_f32(dst); dry4 = vmlaq_f32(dry4, val4, vmlaq_f32(gain4, step4, step_count4)); step_count4 = vaddq_f32(step_count4, four4); - vst1q_f32(&dst[pos], dry4); - pos += 4; + vst1q_f32(dst, dry4); + in_iter += 4; dst += 4; } while(--todo); /* NOTE: step_count4 now represents the next four counts after * the last four mixed samples, so the lowest element @@ -237,41 +235,39 @@ void Mix_(const float *InSamples, const al::span OutBu step_count = vgetq_lane_f32(step_count4, 0); } /* Mix with applying left over gain steps that aren't aligned multiples of 4. */ - for(;pos < minsize;pos++) + while(in_iter != min_end) { - dst[pos] += InSamples[pos]*(gain + step*step_count); + *(dst++) += *(in_iter++) * (gain + step*step_count); step_count += 1.0f; } - if(pos == Counter) + if(reached_target) gain = *TargetGains; else gain += step*step_count; *CurrentGains = gain; /* Mix until pos is aligned with 4 or the mix is done. */ - minsize = mini(BufferSize, (pos+3)&~3); - for(;pos < minsize;pos++) - dst[pos] += InSamples[pos]*gain; + while(in_iter != aligned_end) + *(dst++) += *(in_iter++) * gain; } ++CurrentGains; ++TargetGains; if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; - if LIKELY(BufferSize-pos > 3) + if(ptrdiff_t todo{(InSamples.end()-in_iter) >> 2}) { - ALsizei todo{(BufferSize-pos) >> 2}; const float32x4_t gain4 = vdupq_n_f32(gain); do { - const float32x4_t val4 = vld1q_f32(&InSamples[pos]); - float32x4_t dry4 = vld1q_f32(&dst[pos]); + const float32x4_t val4 = vld1q_f32(in_iter); + float32x4_t dry4 = vld1q_f32(dst); dry4 = vmlaq_f32(dry4, val4, gain4); - vst1q_f32(&dst[pos], dry4); - pos += 4; + vst1q_f32(dst, dry4); + in_iter += 4; dst += 4; } while(--todo); } - for(;pos < BufferSize;pos++) - dst[pos] += InSamples[pos]*gain; + while(in_iter != InSamples.end()) + *(dst++) += *(in_iter++) * gain; } } diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index bd0042a1..3c8204d2 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -145,43 +145,42 @@ void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> -void Mix_(const float *InSamples, const al::span OutBuffer, - float *CurrentGains, const float *TargetGains, const ALsizei Counter, const ALsizei OutPos, - const ALsizei BufferSize) +void Mix_(const al::span InSamples, const al::span OutBuffer, + float *CurrentGains, const float *TargetGains, const ALsizei Counter, const ALsizei OutPos) { - ASSUME(BufferSize > 0); - const ALfloat delta{(Counter > 0) ? 1.0f / static_cast(Counter) : 0.0f}; + const bool reached_target{InSamples.size() >= static_cast(Counter)}; + const auto min_end = reached_target ? InSamples.begin() + Counter : InSamples.end(); + const auto aligned_end = minz(InSamples.size(), (min_end-InSamples.begin()+3) & ~3) + + InSamples.begin(); for(FloatBufferLine &output : OutBuffer) { ALfloat *RESTRICT dst{al::assume_aligned<16>(output.data()+OutPos)}; ALfloat gain{*CurrentGains}; const ALfloat diff{*TargetGains - gain}; - ALsizei pos{0}; + auto in_iter = InSamples.begin(); if(std::fabs(diff) > std::numeric_limits::epsilon()) { - ALsizei minsize{mini(BufferSize, Counter)}; const ALfloat step{diff * delta}; ALfloat step_count{0.0f}; /* Mix with applying gain steps in aligned multiples of 4. */ - if LIKELY(minsize > 3) + if(ptrdiff_t todo{(min_end-in_iter) >> 2}) { const __m128 four4{_mm_set1_ps(4.0f)}; const __m128 step4{_mm_set1_ps(step)}; const __m128 gain4{_mm_set1_ps(gain)}; __m128 step_count4{_mm_setr_ps(0.0f, 1.0f, 2.0f, 3.0f)}; - ALsizei todo{minsize >> 2}; do { - const __m128 val4{_mm_load_ps(&InSamples[pos])}; - __m128 dry4{_mm_load_ps(&dst[pos])}; + const __m128 val4{_mm_load_ps(in_iter)}; + __m128 dry4{_mm_load_ps(dst)}; #define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z)) /* dry += val * (gain + step*step_count) */ dry4 = MLA4(dry4, val4, MLA4(gain4, step4, step_count4)); #undef MLA4 - _mm_store_ps(&dst[pos], dry4); + _mm_store_ps(dst, dry4); step_count4 = _mm_add_ps(step_count4, four4); - pos += 4; + in_iter += 4; dst += 4; } while(--todo); /* NOTE: step_count4 now represents the next four counts after * the last four mixed samples, so the lowest element @@ -190,41 +189,39 @@ void Mix_(const float *InSamples, const al::span OutBuf step_count = _mm_cvtss_f32(step_count4); } /* Mix with applying left over gain steps that aren't aligned multiples of 4. */ - for(;pos < minsize;pos++) + while(in_iter != min_end) { - dst[pos] += InSamples[pos]*(gain + step*step_count); + *(dst++) += *(in_iter++) * (gain + step*step_count); step_count += 1.0f; } - if(pos == Counter) + if(reached_target) gain = *TargetGains; else gain += step*step_count; *CurrentGains = gain; /* Mix until pos is aligned with 4 or the mix is done. */ - minsize = mini(BufferSize, (pos+3)&~3); - for(;pos < minsize;pos++) - dst[pos] += InSamples[pos]*gain; + while(in_iter != aligned_end) + *(dst++) += *(in_iter++) * gain; } ++CurrentGains; ++TargetGains; if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; - if LIKELY(BufferSize-pos > 3) + if(ptrdiff_t todo{(InSamples.end()-in_iter) >> 2}) { - ALsizei todo{(BufferSize-pos) >> 2}; const __m128 gain4{_mm_set1_ps(gain)}; do { - const __m128 val4{_mm_load_ps(&InSamples[pos])}; - __m128 dry4{_mm_load_ps(&dst[pos])}; + const __m128 val4{_mm_load_ps(in_iter)}; + __m128 dry4{_mm_load_ps(dst)}; dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); - _mm_store_ps(&dst[pos], dry4); - pos += 4; + _mm_store_ps(dst, dry4); + in_iter += 4; dst += 4; } while(--todo); } - for(;pos < BufferSize;pos++) - dst[pos] += InSamples[pos]*gain; + while(in_iter != InSamples.end()) + *(dst++) += *(in_iter++) * gain; } } diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 1fc5bd33..a44b6a10 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -762,19 +762,21 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc SilentTarget : parms.Gains.Target}; const size_t outcount{Device->NumChannelsPerOrder[0]}; - MixSamples(samples, voice->mDirect.Buffer.first(outcount), parms.Gains.Current, - TargetGains, Counter, OutPos, DstBufferSize); + MixSamples({samples, samples+DstBufferSize}, + voice->mDirect.Buffer.first(outcount), parms.Gains.Current, TargetGains, + Counter, OutPos); - ALfloat (&nfcsamples)[BUFFERSIZE] = Device->NfcSampleData; + const al::span nfcsamples{Device->NfcSampleData, + static_cast(DstBufferSize)}; size_t chanoffset{outcount}; using FilterProc = void (NfcFilter::*)(float*,const float*,int); - auto apply_nfc = [voice,&parms,samples,TargetGains,DstBufferSize,Counter,OutPos,&chanoffset,&nfcsamples](const FilterProc process, const size_t outcount) -> void + auto apply_nfc = [voice,&parms,samples,TargetGains,DstBufferSize,Counter,OutPos,&chanoffset,nfcsamples](const FilterProc process, const size_t outcount) -> void { if(outcount < 1) return; - (parms.NFCtrlFilter.*process)(nfcsamples, samples, DstBufferSize); + (parms.NFCtrlFilter.*process)(nfcsamples.data(), samples, DstBufferSize); MixSamples(nfcsamples, voice->mDirect.Buffer.subspan(chanoffset, outcount), parms.Gains.Current+chanoffset, TargetGains+chanoffset, Counter, - OutPos, DstBufferSize); + OutPos); chanoffset += outcount; }; apply_nfc(&NfcFilter::process1, Device->NumChannelsPerOrder[1]); @@ -785,8 +787,8 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc { const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? SilentTarget : parms.Gains.Target}; - MixSamples(samples, voice->mDirect.Buffer, parms.Gains.Current, TargetGains, - Counter, OutPos, DstBufferSize); + MixSamples({samples, samples+DstBufferSize}, voice->mDirect.Buffer, + parms.Gains.Current, TargetGains, Counter, OutPos); } } @@ -802,8 +804,8 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc const ALfloat *TargetGains{UNLIKELY(vstate==ALvoice::Stopping) ? SilentTarget : parms.Gains.Target}; - MixSamples(samples, voice->mSend[send].Buffer, parms.Gains.Current, TargetGains, - Counter, OutPos, DstBufferSize); + MixSamples({samples, samples+DstBufferSize}, voice->mSend[send].Buffer, + parms.Gains.Current, TargetGains, Counter, OutPos); }; } /* Update positions */ -- cgit v1.2.3 From 7a8f81259c515291126f29a0e65aff791efe16b0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Aug 2019 05:26:51 -0700 Subject: Use size_t for the NFC and biquad filters' sample count --- alc/effects/reverb.cpp | 2 +- alc/filters/biquad.cpp | 2 +- alc/filters/biquad.h | 3 ++- alc/filters/nfc.cpp | 8 ++++---- alc/filters/nfc.h | 11 +++++++---- alc/mixvoice.cpp | 8 ++++---- 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 1e5cb861..7f6da778 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -293,7 +293,7 @@ struct T60Filter { const ALfloat hfDecayTime, const ALfloat lf0norm, const ALfloat hf0norm); /* Applies the two T60 damping filter sections. */ - void process(ALfloat *samples, const ALsizei todo) + void process(ALfloat *samples, const size_t todo) { HFFilter.process(samples, samples, todo); LFFilter.process(samples, samples, todo); diff --git a/alc/filters/biquad.cpp b/alc/filters/biquad.cpp index 871c4af4..a4d81604 100644 --- a/alc/filters/biquad.cpp +++ b/alc/filters/biquad.cpp @@ -89,7 +89,7 @@ void BiquadFilterR::setParams(BiquadType type, Real gain, Real f0norm, Rea } template -void BiquadFilterR::process(Real *dst, const Real *src, int numsamples) +void BiquadFilterR::process(Real *dst, const Real *src, const size_t numsamples) { ASSUME(numsamples > 0); diff --git a/alc/filters/biquad.h b/alc/filters/biquad.h index f8d7f0ba..9de86f2f 100644 --- a/alc/filters/biquad.h +++ b/alc/filters/biquad.h @@ -2,6 +2,7 @@ #define FILTERS_BIQUAD_H #include +#include #include #include "math_defs.h" @@ -72,7 +73,7 @@ public: } - void process(Real *dst, const Real *src, int numsamples); + void process(Real *dst, const Real *src, const size_t numsamples); /* Rather hacky. It's just here to support "manual" processing. */ std::pair getComponents() const noexcept diff --git a/alc/filters/nfc.cpp b/alc/filters/nfc.cpp index 4e36bc66..e4436b27 100644 --- a/alc/filters/nfc.cpp +++ b/alc/filters/nfc.cpp @@ -278,7 +278,7 @@ void NfcFilter::adjust(const float w0) noexcept } -void NfcFilter::process1(float *RESTRICT dst, const float *RESTRICT src, const int count) +void NfcFilter::process1(float *RESTRICT dst, const float *RESTRICT src, const size_t count) { ASSUME(count > 0); @@ -297,7 +297,7 @@ void NfcFilter::process1(float *RESTRICT dst, const float *RESTRICT src, const i first.z[0] = z1; } -void NfcFilter::process2(float *RESTRICT dst, const float *RESTRICT src, const int count) +void NfcFilter::process2(float *RESTRICT dst, const float *RESTRICT src, const size_t count) { ASSUME(count > 0); @@ -321,7 +321,7 @@ void NfcFilter::process2(float *RESTRICT dst, const float *RESTRICT src, const i second.z[1] = z2; } -void NfcFilter::process3(float *RESTRICT dst, const float *RESTRICT src, const int count) +void NfcFilter::process3(float *RESTRICT dst, const float *RESTRICT src, const size_t count) { ASSUME(count > 0); @@ -353,7 +353,7 @@ void NfcFilter::process3(float *RESTRICT dst, const float *RESTRICT src, const i third.z[2] = z3; } -void NfcFilter::process4(float *RESTRICT dst, const float *RESTRICT src, const int count) +void NfcFilter::process4(float *RESTRICT dst, const float *RESTRICT src, const size_t count) { ASSUME(count > 0); diff --git a/alc/filters/nfc.h b/alc/filters/nfc.h index b656850a..d2bf3339 100644 --- a/alc/filters/nfc.h +++ b/alc/filters/nfc.h @@ -1,6 +1,9 @@ #ifndef FILTER_NFC_H #define FILTER_NFC_H +#include + + struct NfcFilter1 { float base_gain, gain; float b1, a1; @@ -43,16 +46,16 @@ public: void adjust(const float w0) noexcept; /* Near-field control filter for first-order ambisonic channels (1-3). */ - void process1(float *RESTRICT dst, const float *RESTRICT src, const int count); + void process1(float *RESTRICT dst, const float *RESTRICT src, const size_t count); /* Near-field control filter for second-order ambisonic channels (4-8). */ - void process2(float *RESTRICT dst, const float *RESTRICT src, const int count); + void process2(float *RESTRICT dst, const float *RESTRICT src, const size_t count); /* Near-field control filter for third-order ambisonic channels (9-15). */ - void process3(float *RESTRICT dst, const float *RESTRICT src, const int count); + void process3(float *RESTRICT dst, const float *RESTRICT src, const size_t count); /* Near-field control filter for fourth-order ambisonic channels (16-24). */ - void process4(float *RESTRICT dst, const float *RESTRICT src, const int count); + void process4(float *RESTRICT dst, const float *RESTRICT src, const size_t count); }; #endif /* FILTER_NFC_H */ diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index a44b6a10..189e504b 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -337,7 +337,7 @@ void SendSourceStoppedEvent(ALCcontext *context, ALuint id) const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, ALfloat *dst, - const ALfloat *src, ALsizei numsamples, int type) + const ALfloat *src, const size_t numsamples, int type) { switch(type) { @@ -769,11 +769,11 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc const al::span nfcsamples{Device->NfcSampleData, static_cast(DstBufferSize)}; size_t chanoffset{outcount}; - using FilterProc = void (NfcFilter::*)(float*,const float*,int); - auto apply_nfc = [voice,&parms,samples,TargetGains,DstBufferSize,Counter,OutPos,&chanoffset,nfcsamples](const FilterProc process, const size_t outcount) -> void + using FilterProc = void (NfcFilter::*)(float*,const float*,const size_t); + auto apply_nfc = [voice,&parms,samples,TargetGains,Counter,OutPos,&chanoffset,nfcsamples](const FilterProc process, const size_t outcount) -> void { if(outcount < 1) return; - (parms.NFCtrlFilter.*process)(nfcsamples.data(), samples, DstBufferSize); + (parms.NFCtrlFilter.*process)(nfcsamples.data(), samples, nfcsamples.size()); MixSamples(nfcsamples, voice->mDirect.Buffer.subspan(chanoffset, outcount), parms.Gains.Current+chanoffset, TargetGains+chanoffset, Counter, OutPos); -- cgit v1.2.3 From 2ab52968f4faa48a0857eaa8423ae7576f64f2d6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Aug 2019 06:03:31 -0700 Subject: Track the MixVoice sample count and fade counter as unsigned --- alc/alu.h | 2 +- alc/mixvoice.cpp | 34 ++++++++++++++++------------------ 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/alc/alu.h b/alc/alu.h index 9765e113..7bde7b03 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -445,7 +445,7 @@ inline std::array GetAmbiIdentityRow(size_t i) noexce } -void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCcontext *Context, const ALsizei SamplesToDo); +void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCcontext *Context, const ALuint SamplesToDo); void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples); /* Caller must lock the device state, and the mixer must not be running. */ diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 189e504b..c13245eb 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -476,7 +476,7 @@ ALfloat *LoadBufferQueue(ALbufferlistitem *BufferListItem, ALbufferlistitem *Buf } // namespace -void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCcontext *Context, const ALsizei SamplesToDo) +void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCcontext *Context, const ALuint SamplesToDo) { static constexpr ALfloat SilentTarget[MAX_OUTPUT_CHANNELS]{}; @@ -507,7 +507,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc ResamplerFunc Resample{(increment == FRACTIONONE && DataPosFrac == 0) ? Resample_ : voice->mResampler}; - ALsizei Counter{(voice->mFlags&VOICE_IS_FADING) ? SamplesToDo : 0}; + ALuint Counter{(voice->mFlags&VOICE_IS_FADING) ? SamplesToDo : 0}; if(!Counter) { /* No fading, just overwrite the old/current params. */ @@ -549,20 +549,20 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc } ALsizei buffers_done{0}; - ALsizei OutPos{0}; + ALuint OutPos{0u}; do { /* Figure out how many buffer samples will be needed */ - ALsizei DstBufferSize{SamplesToDo - OutPos}; + ALuint DstBufferSize{SamplesToDo - OutPos}; /* Calculate the last written dst sample pos. */ - int64_t DataSize64{DstBufferSize - 1}; + uint64_t DataSize64{DstBufferSize - 1}; /* Calculate the last read src sample pos. */ DataSize64 = (DataSize64*increment + DataPosFrac) >> FRACTIONBITS; /* +1 to get the src sample count, include padding. */ DataSize64 += 1 + MAX_RESAMPLE_PADDING*2; auto SrcBufferSize = static_cast( - mini64(DataSize64, BUFFERSIZE + MAX_RESAMPLE_PADDING*2 + 1)); + minu64(DataSize64, BUFFERSIZE + MAX_RESAMPLE_PADDING*2 + 1)); if(SrcBufferSize > BUFFERSIZE + MAX_RESAMPLE_PADDING*2) { SrcBufferSize = BUFFERSIZE + MAX_RESAMPLE_PADDING*2; @@ -572,7 +572,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc */ DataSize64 = SrcBufferSize - MAX_RESAMPLE_PADDING*2; DataSize64 = ((DataSize64<(mini64(DataSize64, DstBufferSize)); + DstBufferSize = static_cast(minu64(DataSize64, DstBufferSize)); /* Some mixers like having a multiple of 4, so try to give that * unless this is the last update. @@ -652,7 +652,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc auto &AccumSamples = Device->HrtfAccumData; const ALfloat TargetGain{UNLIKELY(vstate == ALvoice::Stopping) ? 0.0f : parms.Hrtf.Target.Gain}; - ALsizei fademix{0}; + ALuint fademix{0u}; /* Copy the HRTF history and new input samples into a temp * buffer. @@ -682,7 +682,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc */ if(Counter && (parms.Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD) && OutPos == 0) { - fademix = mini(DstBufferSize, 128); + fademix = minu(DstBufferSize, 128); ALfloat gain{TargetGain}; @@ -718,7 +718,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc if LIKELY(fademix < DstBufferSize) { - const ALsizei todo{DstBufferSize - fademix}; + const ALuint todo{DstBufferSize - fademix}; ALfloat gain{TargetGain}; /* Interpolate the target gain if the gain fading lasts @@ -762,12 +762,10 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc SilentTarget : parms.Gains.Target}; const size_t outcount{Device->NumChannelsPerOrder[0]}; - MixSamples({samples, samples+DstBufferSize}, - voice->mDirect.Buffer.first(outcount), parms.Gains.Current, TargetGains, - Counter, OutPos); + MixSamples({samples, DstBufferSize}, voice->mDirect.Buffer.first(outcount), + parms.Gains.Current, TargetGains, Counter, OutPos); - const al::span nfcsamples{Device->NfcSampleData, - static_cast(DstBufferSize)}; + const al::span nfcsamples{Device->NfcSampleData, DstBufferSize}; size_t chanoffset{outcount}; using FilterProc = void (NfcFilter::*)(float*,const float*,const size_t); auto apply_nfc = [voice,&parms,samples,TargetGains,Counter,OutPos,&chanoffset,nfcsamples](const FilterProc process, const size_t outcount) -> void @@ -787,7 +785,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc { const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? SilentTarget : parms.Gains.Target}; - MixSamples({samples, samples+DstBufferSize}, voice->mDirect.Buffer, + MixSamples({samples, DstBufferSize}, voice->mDirect.Buffer, parms.Gains.Current, TargetGains, Counter, OutPos); } } @@ -804,7 +802,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc const ALfloat *TargetGains{UNLIKELY(vstate==ALvoice::Stopping) ? SilentTarget : parms.Gains.Target}; - MixSamples({samples, samples+DstBufferSize}, voice->mSend[send].Buffer, + MixSamples({samples, DstBufferSize}, voice->mSend[send].Buffer, parms.Gains.Current, TargetGains, Counter, OutPos); }; } @@ -814,7 +812,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc DataPosFrac &= FRACTIONMASK; OutPos += DstBufferSize; - Counter = maxi(DstBufferSize, Counter) - DstBufferSize; + Counter = maxu(DstBufferSize, Counter) - DstBufferSize; if UNLIKELY(!BufferListItem) { -- cgit v1.2.3 From ce76cc144142a065e2702bd57f4358929c38d1bc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Aug 2019 07:57:37 -0700 Subject: Use unsigned for the sample and channel converters --- alc/backends/coreaudio.cpp | 9 ++++---- alc/backends/wasapi.cpp | 10 ++++----- alc/converter.cpp | 52 +++++++++++++++++++++++----------------------- alc/converter.h | 8 +++---- 4 files changed, 38 insertions(+), 41 deletions(-) diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index cfa7703a..c903ff07 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -654,15 +654,14 @@ ALCenum CoreAudioCapture::captureSamples(void *buffer, ALCuint samples) auto rec_vec = mRing->getReadVector(); const void *src0{rec_vec.first.buf}; - auto src0len = static_cast(rec_vec.first.len); - auto got = static_cast(mConverter->convert(&src0, &src0len, buffer, samples)); + auto src0len = static_cast(rec_vec.first.len); + ALuint got{mConverter->convert(&src0, &src0len, buffer, samples)}; size_t total_read{rec_vec.first.len - src0len}; if(got < samples && !src0len && rec_vec.second.len > 0) { const void *src1{rec_vec.second.buf}; - auto src1len = static_cast(rec_vec.second.len); - got += static_cast(mConverter->convert(&src1, &src1len, - static_cast(buffer)+got, samples-got)); + auto src1len = static_cast(rec_vec.second.len); + got += mConverter->convert(&src1, &src1len, static_cast(buffer)+got, samples-got); total_read += rec_vec.second.len - src1len; } diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index cc53be66..dbf1208d 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -1229,10 +1229,10 @@ FORCE_ALIGN int WasapiCapture::recordProc() if(mSampleConv) { const ALvoid *srcdata{rdata}; - auto srcframes = static_cast(numsamples); + ALuint srcframes{numsamples}; dstframes = mSampleConv->convert(&srcdata, &srcframes, data.first.buf, - static_cast(minz(data.first.len, INT_MAX))); + static_cast(minz(data.first.len, INT_MAX))); if(srcframes > 0 && dstframes == data.first.len && data.second.len > 0) { /* If some source samples remain, all of the first dest @@ -1240,14 +1240,14 @@ FORCE_ALIGN int WasapiCapture::recordProc() * dest block, do another run for the second block. */ dstframes += mSampleConv->convert(&srcdata, &srcframes, data.second.buf, - static_cast(minz(data.second.len, INT_MAX))); + static_cast(minz(data.second.len, INT_MAX))); } } else { const auto framesize = static_cast(mDevice->frameSizeFromFmt()); - size_t len1 = minz(data.first.len, numsamples); - size_t len2 = minz(data.second.len, numsamples-len1); + size_t len1{minz(data.first.len, numsamples)}; + size_t len2{minz(data.second.len, numsamples-len1)}; memcpy(data.first.buf, rdata, len1*framesize); if(len2 > 0) diff --git a/alc/converter.cpp b/alc/converter.cpp index 1fa4a5d0..e66e5929 100644 --- a/alc/converter.cpp +++ b/alc/converter.cpp @@ -41,17 +41,17 @@ template<> inline ALfloat LoadSample(DevFmtTypeTraits::T template inline void LoadSampleArray(ALfloat *RESTRICT dst, const void *src, const size_t srcstep, - const ALsizei samples) noexcept + const size_t samples) noexcept { using SampleType = typename DevFmtTypeTraits::Type; const SampleType *ssrc = static_cast(src); - for(ALsizei i{0};i < samples;i++) + for(size_t i{0u};i < samples;i++) dst[i] = LoadSample(ssrc[i*srcstep]); } void LoadSamples(ALfloat *dst, const ALvoid *src, const size_t srcstep, const DevFmtType srctype, - const ALsizei samples) noexcept + const size_t samples) noexcept { #define HANDLE_FMT(T) \ case T: LoadSampleArray(dst, src, srcstep, samples); break @@ -91,18 +91,18 @@ template<> inline ALubyte StoreSample(ALfloat val) noexcept template inline void StoreSampleArray(void *dst, const ALfloat *RESTRICT src, const size_t dststep, - const ALsizei samples) noexcept + const size_t samples) noexcept { using SampleType = typename DevFmtTypeTraits::Type; SampleType *sdst = static_cast(dst); - for(ALsizei i{0};i < samples;i++) + for(size_t i{0u};i < samples;i++) sdst[i*dststep] = StoreSample(src[i]); } void StoreSamples(ALvoid *dst, const ALfloat *src, const size_t dststep, const DevFmtType dsttype, - const ALsizei samples) noexcept + const size_t samples) noexcept { #define HANDLE_FMT(T) \ case T: StoreSampleArray(dst, src, dststep, samples); break @@ -121,22 +121,22 @@ void StoreSamples(ALvoid *dst, const ALfloat *src, const size_t dststep, const D template -void Mono2Stereo(ALfloat *RESTRICT dst, const void *src, const ALsizei frames) noexcept +void Mono2Stereo(ALfloat *RESTRICT dst, const void *src, const size_t frames) noexcept { using SampleType = typename DevFmtTypeTraits::Type; const SampleType *ssrc = static_cast(src); - for(ALsizei i{0};i < frames;i++) + for(size_t i{0u};i < frames;i++) dst[i*2 + 1] = dst[i*2 + 0] = LoadSample(ssrc[i]) * 0.707106781187f; } template -void Stereo2Mono(ALfloat *RESTRICT dst, const void *src, const ALsizei frames) noexcept +void Stereo2Mono(ALfloat *RESTRICT dst, const void *src, const size_t frames) noexcept { using SampleType = typename DevFmtTypeTraits::Type; const SampleType *ssrc = static_cast(src); - for(ALsizei i{0};i < frames;i++) + for(size_t i{0u};i < frames;i++) dst[i] = (LoadSample(ssrc[i*2 + 0])+LoadSample(ssrc[i*2 + 1])) * 0.707106781187f; } @@ -178,13 +178,13 @@ SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, return converter; } -ALsizei SampleConverter::availableOut(ALsizei srcframes) const +ALuint SampleConverter::availableOut(ALuint srcframes) const { ALint prepcount{mSrcPrepCount}; if(prepcount < 0) { /* Negative prepcount means we need to skip that many input samples. */ - if(-prepcount >= srcframes) + if(static_cast(-prepcount) >= srcframes) return 0; srcframes += prepcount; prepcount = 0; @@ -197,7 +197,7 @@ ALsizei SampleConverter::availableOut(ALsizei srcframes) const } if(prepcount < MAX_RESAMPLE_PADDING*2 && - MAX_RESAMPLE_PADDING*2 - prepcount >= srcframes) + static_cast(MAX_RESAMPLE_PADDING*2 - prepcount) >= srcframes) { /* Not enough input samples to generate an output sample. */ return 0; @@ -210,26 +210,26 @@ ALsizei SampleConverter::availableOut(ALsizei srcframes) const DataSize64 -= mFracOffset; /* If we have a full prep, we can generate at least one sample. */ - return static_cast(clampu64((DataSize64 + mIncrement-1)/mIncrement, 1, BUFFERSIZE)); + return static_cast(clampu64((DataSize64 + mIncrement-1)/mIncrement, 1, BUFFERSIZE)); } -ALsizei SampleConverter::convert(const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes) +ALuint SampleConverter::convert(const ALvoid **src, ALuint *srcframes, ALvoid *dst, ALuint dstframes) { const ALsizei SrcFrameSize{static_cast(mChan.size()) * mSrcTypeSize}; const ALsizei DstFrameSize{static_cast(mChan.size()) * mDstTypeSize}; const ALsizei increment{mIncrement}; auto SamplesIn = static_cast(*src); - ALsizei NumSrcSamples{*srcframes}; + ALuint NumSrcSamples{*srcframes}; FPUCtl mixer_mode{}; - ALsizei pos{0}; + ALuint pos{0}; while(pos < dstframes && NumSrcSamples > 0) { ALint prepcount{mSrcPrepCount}; if(prepcount < 0) { /* Negative prepcount means we need to skip that many input samples. */ - if(-prepcount >= NumSrcSamples) + if(static_cast(-prepcount) >= NumSrcSamples) { mSrcPrepCount = prepcount + NumSrcSamples; NumSrcSamples = 0; @@ -240,10 +240,10 @@ ALsizei SampleConverter::convert(const ALvoid **src, ALsizei *srcframes, ALvoid mSrcPrepCount = 0; continue; } - ALint toread{mini(NumSrcSamples, BUFFERSIZE - MAX_RESAMPLE_PADDING*2)}; + ALuint toread{minu(NumSrcSamples, BUFFERSIZE - MAX_RESAMPLE_PADDING*2)}; if(prepcount < MAX_RESAMPLE_PADDING*2 && - MAX_RESAMPLE_PADDING*2 - prepcount >= toread) + static_cast(MAX_RESAMPLE_PADDING*2 - prepcount) >= toread) { /* Not enough input samples to generate an output sample. Store * what we're given for later. @@ -267,9 +267,9 @@ ALsizei SampleConverter::convert(const ALvoid **src, ALsizei *srcframes, ALvoid DataSize64 -= DataPosFrac; /* If we have a full prep, we can generate at least one sample. */ - auto DstSize = static_cast( + auto DstSize = static_cast( clampu64((DataSize64 + increment-1)/increment, 1, BUFFERSIZE)); - DstSize = mini(DstSize, dstframes-pos); + DstSize = minu(DstSize, dstframes-pos); for(size_t chan{0u};chan < mChan.size();chan++) { @@ -285,13 +285,13 @@ ALsizei SampleConverter::convert(const ALvoid **src, ALsizei *srcframes, ALvoid /* Store as many prep samples for next time as possible, given the * number of output samples being generated. */ - ALsizei SrcDataEnd{(DstSize*increment + DataPosFrac)>>FRACTIONBITS}; + ALuint SrcDataEnd{(DstSize*increment + DataPosFrac)>>FRACTIONBITS}; if(SrcDataEnd >= prepcount+toread) std::fill(std::begin(mChan[chan].PrevSamples), std::end(mChan[chan].PrevSamples), 0.0f); else { - size_t len = mini(MAX_RESAMPLE_PADDING*2, prepcount+toread-SrcDataEnd); + size_t len{minu(MAX_RESAMPLE_PADDING*2, prepcount+toread-SrcDataEnd)}; std::copy_n(SrcData+SrcDataEnd, len, mChan[chan].PrevSamples); std::fill(std::begin(mChan[chan].PrevSamples)+len, std::end(mChan[chan].PrevSamples), 0.0f); @@ -314,7 +314,7 @@ ALsizei SampleConverter::convert(const ALvoid **src, ALsizei *srcframes, ALvoid /* Update the src and dst pointers in case there's still more to do. */ SamplesIn += SrcFrameSize*(DataPosFrac>>FRACTIONBITS); - NumSrcSamples -= mini(NumSrcSamples, (DataPosFrac>>FRACTIONBITS)); + NumSrcSamples -= minu(NumSrcSamples, (DataPosFrac>>FRACTIONBITS)); dst = static_cast(dst) + DstFrameSize*DstSize; pos += DstSize; @@ -335,7 +335,7 @@ ChannelConverterPtr CreateChannelConverter(DevFmtType srcType, DevFmtChannels sr return al::make_unique(srcType, srcChans, dstChans); } -void ChannelConverter::convert(const ALvoid *src, ALfloat *dst, ALsizei frames) const +void ChannelConverter::convert(const ALvoid *src, ALfloat *dst, ALuint frames) const { if(mSrcChans == DevFmtStereo && mDstChans == DevFmtMono) { diff --git a/alc/converter.h b/alc/converter.h index 9a3308b5..50254213 100644 --- a/alc/converter.h +++ b/alc/converter.h @@ -35,11 +35,9 @@ struct SampleConverter { al::FlexArray mChan; SampleConverter(size_t numchans) : mChan{numchans} { } - SampleConverter(const SampleConverter&) = delete; - SampleConverter& operator=(const SampleConverter&) = delete; - ALsizei convert(const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes); - ALsizei availableOut(ALsizei srcframes) const; + ALuint convert(const ALvoid **src, ALuint *srcframes, ALvoid *dst, ALuint dstframes); + ALuint availableOut(ALuint srcframes) const; static constexpr size_t Sizeof(size_t length) noexcept { @@ -64,7 +62,7 @@ struct ChannelConverter { : mSrcType(srctype), mSrcChans(srcchans), mDstChans(dstchans) { } - void convert(const ALvoid *src, ALfloat *dst, ALsizei frames) const; + void convert(const ALvoid *src, ALfloat *dst, ALuint frames) const; DEF_NEWDEL(ChannelConverter) }; -- cgit v1.2.3 From 0961f4eb00782df66e3ada75b4055b44a28240f3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Aug 2019 08:46:12 -0700 Subject: Pass a span to the Resample function --- alc/alu.h | 5 ++--- alc/converter.cpp | 2 +- alc/mixer/defs.h | 2 +- alc/mixer/mixer_c.cpp | 32 +++++++++++++++----------------- alc/mixer/mixer_neon.cpp | 31 +++++++++++++++---------------- alc/mixer/mixer_sse.cpp | 9 ++++----- alc/mixer/mixer_sse2.cpp | 17 +++++++++-------- alc/mixer/mixer_sse41.cpp | 17 +++++++++-------- alc/mixvoice.cpp | 2 +- 9 files changed, 57 insertions(+), 60 deletions(-) diff --git a/alc/alu.h b/alc/alu.h index 7bde7b03..4ab093d2 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -80,9 +80,8 @@ union InterpState { BsincState bsinc; }; -using ResamplerFunc = const ALfloat*(*)(const InterpState *state, - const ALfloat *RESTRICT src, ALsizei frac, ALint increment, - ALfloat *RESTRICT dst, ALsizei dstlen); +using ResamplerFunc = const ALfloat*(*)(const InterpState *state, const ALfloat *RESTRICT src, + ALsizei frac, ALint increment, const al::span dst); void BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *table); diff --git a/alc/converter.cpp b/alc/converter.cpp index e66e5929..de61415a 100644 --- a/alc/converter.cpp +++ b/alc/converter.cpp @@ -299,7 +299,7 @@ ALuint SampleConverter::convert(const ALvoid **src, ALuint *srcframes, ALvoid *d /* Now resample, and store the result in the output buffer. */ const ALfloat *ResampledData{mResample(&mState, SrcData+MAX_RESAMPLE_PADDING, - DataPosFrac, increment, DstData, DstSize)}; + DataPosFrac, increment, {DstData, DstSize})}; StoreSamples(DstSamples, ResampledData, mChan.size(), mDstType, DstSize); } diff --git a/alc/mixer/defs.h b/alc/mixer/defs.h index 9d4fd063..bdb208c4 100644 --- a/alc/mixer/defs.h +++ b/alc/mixer/defs.h @@ -27,7 +27,7 @@ enum ResampleType { }; template -const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen); +const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, ALint increment, const al::span dst); template void Mix_(const al::span InSamples, const al::span OutBuffer, diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index e7ca23d5..743431da 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -44,9 +44,8 @@ inline ALfloat do_bsinc(const InterpState &istate, const ALfloat *RESTRICT vals, using SamplerT = ALfloat(const InterpState&, const ALfloat*RESTRICT, const ALsizei); template const ALfloat *DoResample(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei numsamples) + ALsizei frac, ALint increment, const al::span dst) { - ASSUME(numsamples > 0); ASSUME(increment > 0); ASSUME(frac >= 0); @@ -61,46 +60,45 @@ const ALfloat *DoResample(const InterpState *state, const ALfloat *RESTRICT src, return ret; }; - std::generate_n(dst, numsamples, proc_sample); + std::generate(dst.begin(), dst.end(), proc_sample); - return dst; + return dst.begin(); } } // namespace template<> const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, ALsizei, - ALint, ALfloat *RESTRICT dst, ALsizei dstlen) + ALint, const al::span dst) { - ASSUME(dstlen > 0); #if defined(HAVE_SSE) || defined(HAVE_NEON) /* Avoid copying the source data if it's aligned like the destination. */ - if((reinterpret_cast(src)&15) == (reinterpret_cast(dst)&15)) + if((reinterpret_cast(src)&15) == (reinterpret_cast(dst.data())&15)) return src; #endif - std::copy_n(src, dstlen, dst); - return dst; + std::copy_n(src, dst.size(), dst.begin()); + return dst.begin(); } template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) -{ return DoResample(state, src, frac, increment, dst, dstlen); } + ALsizei frac, ALint increment, const al::span dst) +{ return DoResample(state, src, frac, increment, dst); } template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) -{ return DoResample(state, src, frac, increment, dst, dstlen); } + ALsizei frac, ALint increment, const al::span dst) +{ return DoResample(state, src, frac, increment, dst); } template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) -{ return DoResample(state, src-1, frac, increment, dst, dstlen); } + ALsizei frac, ALint increment, const al::span dst) +{ return DoResample(state, src-1, frac, increment, dst); } template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) -{ return DoResample(state, src-state->bsinc.l, frac, increment, dst, dstlen); } + ALsizei frac, ALint increment, const al::span dst) +{ return DoResample(state, src-state->bsinc.l, frac, increment, dst); } static inline void ApplyCoeffs(ALsizei /*Offset*/, float2 *RESTRICT Values, const ALsizei IrSize, diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index 1c4466c2..53b2fe8d 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -16,25 +16,24 @@ template<> const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) + ALsizei frac, ALint increment, const al::span dst) { const int32x4_t increment4 = vdupq_n_s32(increment*4); const float32x4_t fracOne4 = vdupq_n_f32(1.0f/FRACTIONONE); const int32x4_t fracMask4 = vdupq_n_s32(FRACTIONMASK); alignas(16) ALsizei pos_[4], frac_[4]; int32x4_t pos4, frac4; - ALsizei todo, pos, i; ASSUME(frac >= 0); ASSUME(increment > 0); - ASSUME(dstlen > 0); InitiatePositionArrays(frac, increment, frac_, pos_, 4); frac4 = vld1q_s32(frac_); pos4 = vld1q_s32(pos_); - todo = dstlen & ~3; - for(i = 0;i < todo;i += 4) + auto dst_iter = dst.begin(); + const auto aligned_end = (dst.size()&~3) + dst_iter; + while(dst_iter != aligned_end) { const int pos0 = vgetq_lane_s32(pos4, 0); const int pos1 = vgetq_lane_s32(pos4, 1); @@ -48,7 +47,8 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES const float32x4_t mu = vmulq_f32(vcvtq_f32_s32(frac4), fracOne4); const float32x4_t out = vmlaq_f32(val1, mu, r0); - vst1q_f32(&dst[i], out); + vst1q_f32(dst_iter, out); + dst_iter += 4; frac4 = vaddq_s32(frac4, increment4); pos4 = vaddq_s32(pos4, vshrq_n_s32(frac4, FRACTIONBITS)); @@ -58,39 +58,38 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES /* NOTE: These four elements represent the position *after* the last four * samples, so the lowest element is the next position to resample. */ - pos = vgetq_lane_s32(pos4, 0); + ALsizei pos{vgetq_lane_s32(pos4, 0)}; frac = vgetq_lane_s32(frac4, 0); - for(;i < dstlen;++i) + while(dst_iter != dst.end()) { - dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); + *(dst_iter++) = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); frac += increment; pos += frac>>FRACTIONBITS; frac &= FRACTIONMASK; } - return dst; + return dst.begin(); } template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) + ALsizei frac, ALint increment, const al::span dst) { const ALfloat *const filter = state->bsinc.filter; const float32x4_t sf4 = vdupq_n_f32(state->bsinc.sf); const ALsizei m = state->bsinc.m; const float32x4_t *fil, *scd, *phd, *spd; - ALsizei pi, i, j, offset; + ALsizei pi, j, offset; float32x4_t r4; ALfloat pf; ASSUME(m > 0); - ASSUME(dstlen > 0); ASSUME(increment > 0); ASSUME(frac >= 0); src -= state->bsinc.l; - for(i = 0;i < dstlen;i++) + for(float &out_sample : dst) { // Calculate the phase index and factor. #define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) @@ -125,13 +124,13 @@ const ALfloat *Resample_(const InterpState *state, const ALflo } r4 = vaddq_f32(r4, vcombine_f32(vrev64_f32(vget_high_f32(r4)), vrev64_f32(vget_low_f32(r4)))); - dst[i] = vget_lane_f32(vadd_f32(vget_low_f32(r4), vget_high_f32(r4)), 0); + out_sample = vget_lane_f32(vadd_f32(vget_low_f32(r4), vget_high_f32(r4)), 0); frac += increment; src += frac>>FRACTIONBITS; frac &= FRACTIONMASK; } - return dst; + return dst.begin(); } diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index 3c8204d2..c154eeef 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -15,19 +15,18 @@ template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) + ALsizei frac, ALint increment, const al::span dst) { const ALfloat *const filter{state->bsinc.filter}; const __m128 sf4{_mm_set1_ps(state->bsinc.sf)}; const ALsizei m{state->bsinc.m}; ASSUME(m > 0); - ASSUME(dstlen > 0); ASSUME(increment > 0); ASSUME(frac >= 0); src -= state->bsinc.l; - for(ALsizei i{0};i < dstlen;i++) + for(float &out_sample : dst) { // Calculate the phase index and factor. #define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) @@ -64,13 +63,13 @@ const ALfloat *Resample_(const InterpState *state, const ALfloa } r4 = _mm_add_ps(r4, _mm_shuffle_ps(r4, r4, _MM_SHUFFLE(0, 1, 2, 3))); r4 = _mm_add_ps(r4, _mm_movehl_ps(r4, r4)); - dst[i] = _mm_cvtss_f32(r4); + out_sample = _mm_cvtss_f32(r4); frac += increment; src += frac>>FRACTIONBITS; frac &= FRACTIONMASK; } - return dst; + return dst.begin(); } diff --git a/alc/mixer/mixer_sse2.cpp b/alc/mixer/mixer_sse2.cpp index b1c67f09..e3443f4e 100644 --- a/alc/mixer/mixer_sse2.cpp +++ b/alc/mixer/mixer_sse2.cpp @@ -29,7 +29,7 @@ template<> const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) + ALsizei frac, ALint increment, const al::span dst) { const __m128i increment4{_mm_set1_epi32(increment*4)}; const __m128 fracOne4{_mm_set1_ps(1.0f/FRACTIONONE)}; @@ -37,15 +37,15 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES ASSUME(frac >= 0); ASSUME(increment > 0); - ASSUME(dstlen >= 0); alignas(16) ALsizei pos_[4], frac_[4]; InitiatePositionArrays(frac, increment, frac_, pos_, 4); __m128i frac4{_mm_setr_epi32(frac_[0], frac_[1], frac_[2], frac_[3])}; __m128i pos4{_mm_setr_epi32(pos_[0], pos_[1], pos_[2], pos_[3])}; - const ALsizei todo{dstlen & ~3}; - for(ALsizei i{0};i < todo;i += 4) + auto dst_iter = dst.begin(); + const auto aligned_end = (dst.size()&~3) + dst_iter; + while(dst_iter != aligned_end) { const int pos0{_mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(0, 0, 0, 0)))}; const int pos1{_mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(1, 1, 1, 1)))}; @@ -59,7 +59,8 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES 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); + _mm_store_ps(dst_iter, out); + dst_iter += 4; frac4 = _mm_add_epi32(frac4, increment4); pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS)); @@ -72,13 +73,13 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES ALsizei pos{_mm_cvtsi128_si32(pos4)}; frac = _mm_cvtsi128_si32(frac4); - for(ALsizei i{todo};i < dstlen;++i) + while(dst_iter != dst.end()) { - dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); + *(dst_iter++) = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); frac += increment; pos += frac>>FRACTIONBITS; frac &= FRACTIONMASK; } - return dst; + return dst.begin(); } diff --git a/alc/mixer/mixer_sse41.cpp b/alc/mixer/mixer_sse41.cpp index 077be44c..424b9b5f 100644 --- a/alc/mixer/mixer_sse41.cpp +++ b/alc/mixer/mixer_sse41.cpp @@ -30,7 +30,7 @@ template<> const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, ALfloat *RESTRICT dst, ALsizei dstlen) + ALsizei frac, ALint increment, const al::span dst) { const __m128i increment4{_mm_set1_epi32(increment*4)}; const __m128 fracOne4{_mm_set1_ps(1.0f/FRACTIONONE)}; @@ -38,15 +38,15 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES ASSUME(frac >= 0); ASSUME(increment > 0); - ASSUME(dstlen >= 0); alignas(16) ALsizei pos_[4], frac_[4]; InitiatePositionArrays(frac, increment, frac_, pos_, 4); __m128i frac4{_mm_setr_epi32(frac_[0], frac_[1], frac_[2], frac_[3])}; __m128i pos4{_mm_setr_epi32(pos_[0], pos_[1], pos_[2], pos_[3])}; - const ALsizei todo{dstlen & ~3}; - for(ALsizei i{0};i < todo;i += 4) + auto dst_iter = dst.begin(); + const auto aligned_end = (dst.size()&~3) + dst_iter; + while(dst_iter != aligned_end) { const int pos0{_mm_extract_epi32(pos4, 0)}; const int pos1{_mm_extract_epi32(pos4, 1)}; @@ -60,7 +60,8 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES 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); + _mm_store_ps(dst_iter, out); + dst_iter += 4; frac4 = _mm_add_epi32(frac4, increment4); pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS)); @@ -73,13 +74,13 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES ALsizei pos{_mm_cvtsi128_si32(pos4)}; frac = _mm_cvtsi128_si32(frac4); - for(ALsizei i{todo};i < dstlen;++i) + while(dst_iter != dst.end()) { - dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); + *(dst_iter++) = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); frac += increment; pos += frac>>FRACTIONBITS; frac &= FRACTIONMASK; } - return dst; + return dst.begin(); } diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index c13245eb..6bdbdec1 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -621,7 +621,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc /* Resample, then apply ambisonic upsampling as needed. */ const ALfloat *ResampledData{Resample(&voice->mResampleState, &SrcData[MAX_RESAMPLE_PADDING], DataPosFrac, increment, - Device->ResampledData, DstBufferSize)}; + {Device->ResampledData, DstBufferSize})}; if((voice->mFlags&VOICE_IS_AMBISONIC)) { const ALfloat hfscale{chandata.mAmbiScale}; -- cgit v1.2.3 From a7f078927d76b91ee01dece2852c6a55b23aeb22 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Aug 2019 09:20:18 -0700 Subject: Fix MixRow definition for NEON --- alc/mixer/mixer_neon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index 53b2fe8d..9a3722ab 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -271,8 +271,8 @@ void Mix_(const al::span InSamples, const al::span -void MixRow_(const al::span OutBuffer, const al::span Gains, - const ALfloat *InSamples, const ALsizei InStride) +void MixRow_(const al::span OutBuffer, const al::span Gains, + const float *InSamples, const size_t InStride) { for(const ALfloat gain : Gains) { -- cgit v1.2.3 From a3a295f6dc9cba540ae8f41eef33b7b955b39ef6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Aug 2019 09:31:08 -0700 Subject: Try to fix span construction for MSVC --- alc/effects/reverb.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 7f6da778..9fbff668 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -421,7 +421,7 @@ struct ReverbState final : public EffectState { ASSUME(todo > 0); /* Convert back to B-Format, and mix the results to output. */ - const al::span tmpspan{mTempLine.begin(), mTempLine.begin()+todo}; + const al::span tmpspan{mTempLine.data(), mTempLine.data()+todo}; for(size_t c{0u};c < NUM_LINES;c++) { std::fill(tmpspan.begin(), tmpspan.end(), 0.0f); @@ -445,7 +445,7 @@ struct ReverbState final : public EffectState { { ASSUME(todo > 0); - const al::span tmpspan{mTempLine.begin(), mTempLine.begin()+todo}; + const al::span tmpspan{mTempLine.data(), mTempLine.data()+todo}; for(size_t c{0u};c < NUM_LINES;c++) { std::fill(tmpspan.begin(), tmpspan.end(), 0.0f); @@ -1459,7 +1459,7 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST ASSUME(offset >= 0); /* Convert B-Format to A-Format for processing. */ - const al::span tmpspan{mTempLine.begin(), mTempLine.begin()+samplesToDo}; + const al::span tmpspan{mTempLine.data(), mTempLine.data()+samplesToDo}; for(size_t c{0u};c < NUM_LINES;c++) { std::fill(tmpspan.begin(), tmpspan.end(), 0.0f); -- cgit v1.2.3 From 9e326846f654f751445e1ce2ccfc6d00c91a993d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Aug 2019 10:36:17 -0700 Subject: Simplify passing some span parameters --- alc/effects/reverb.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 9fbff668..48ff93ae 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -1250,9 +1250,8 @@ void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALs * bounce to improve the initial diffusion in the late reverb. */ const ALsizei late_feed_tap{offset - State->mLateFeedTap}; - const al::span out{State->mEarlySamples}; - VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, - {out.cbegin(), out.cend()}, todo); + const al::span out{State->mEarlySamples}; + VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, out, todo); } void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, const ALfloat fade) @@ -1323,9 +1322,8 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz early_delay.write(offset, NUM_LINES-1-j, temps[j].data(), todo); const ALsizei late_feed_tap{offset - State->mLateFeedTap}; - const al::span out{State->mEarlySamples}; - VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, 0, {out.cbegin(), out.cend()}, - todo); + const al::span out{State->mEarlySamples}; + VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, 0, out, todo); } /* This generates the reverb tail using a modified feed-back delay network @@ -1386,8 +1384,7 @@ void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei std::copy_n(temps[j].begin(), todo, State->mLateSamples[j].begin() + base); /* Finally, scatter and bounce the results to refeed the feedback buffer. */ - VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, 0, {temps.cbegin(), temps.cend()}, - todo); + VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, 0, temps, todo); } void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, const ALfloat fade) @@ -1446,8 +1443,7 @@ void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei to for(size_t j{0u};j < NUM_LINES;j++) std::copy_n(temps[j].begin(), todo, State->mLateSamples[j].begin()); - VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, 0, {temps.cbegin(), temps.cend()}, - todo); + VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, 0, temps, todo); } void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) -- cgit v1.2.3 From a19f65f2c8e092e2314295cea5b72e3576490d45 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Aug 2019 11:09:59 -0700 Subject: Use size_t for reverb offsets and masks --- alc/effects/reverb.cpp | 189 ++++++++++++++++++++++++------------------------- 1 file changed, 92 insertions(+), 97 deletions(-) diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 48ff93ae..d6a25d91 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -51,14 +51,14 @@ using namespace std::placeholders; /* Max samples per process iteration. Used to limit the size needed for * temporary buffers. Must be a multiple of 4 for SIMD alignment. */ -constexpr int MAX_UPDATE_SAMPLES{256}; +constexpr size_t MAX_UPDATE_SAMPLES{256}; /* The number of samples used for cross-faded delay lines. This can be used * to balance the compensation for abrupt line changes and attenuation due to * minimally lengthed recursive lines. Try to keep this below the device * update size. */ -constexpr int FADE_SAMPLES{128}; +constexpr size_t FADE_SAMPLES{128}; /* The number of spatialized lines or channels to process. Four channels allows * for a 3D A-Format response. NOTE: This can't be changed without taking care @@ -230,7 +230,7 @@ struct DelayLineI { /* The delay lines use interleaved samples, with the lengths being powers * of 2 to allow the use of bit-masking instead of a modulus for wrapping. */ - ALsizei Mask{0}; + size_t Mask{0u}; std::array *Line{nullptr}; /* Given the allocated sample buffer, this function updates each delay line @@ -257,13 +257,13 @@ struct DelayLineI { return samples; } - void write(ALsizei offset, const ALsizei c, const ALfloat *RESTRICT in, const ALsizei count) const noexcept + void write(size_t offset, const size_t c, const ALfloat *RESTRICT in, const size_t count) const noexcept { ASSUME(count > 0); - for(ALsizei i{0};i < count;) + for(size_t i{0u};i < count;) { offset &= Mask; - ALsizei td{mini(Mask+1 - offset, count - i)}; + size_t td{minz(Mask+1 - offset, count - i)}; do { Line[offset++][c] = in[i++]; } while(--td); @@ -274,12 +274,12 @@ struct DelayLineI { struct VecAllpass { DelayLineI Delay; ALfloat Coeff{0.0f}; - ALsizei Offset[NUM_LINES][2]{}; + size_t Offset[NUM_LINES][2]{}; - void processFaded(const al::span samples, ALsizei offset, - const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, const ALsizei todo); - void processUnfaded(const al::span samples, ALsizei offset, - const ALfloat xCoeff, const ALfloat yCoeff, const ALsizei todo); + void processFaded(const al::span samples, size_t offset, + const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, const size_t todo); + void processUnfaded(const al::span samples, size_t offset, + const ALfloat xCoeff, const ALfloat yCoeff, const size_t todo); }; struct T60Filter { @@ -310,7 +310,7 @@ struct EarlyReflections { * reflections. */ DelayLineI Delay; - ALsizei Offset[NUM_LINES][2]{}; + size_t Offset[NUM_LINES][2]{}; ALfloat Coeff[NUM_LINES][2]{}; /* The gain for each output channel based on 3D panning. */ @@ -324,7 +324,7 @@ struct EarlyReflections { struct LateReverb { /* A recursive delay line is used fill in the reverb tail. */ DelayLineI Delay; - ALsizei Offset[NUM_LINES][2]{}; + size_t Offset[NUM_LINES][2]{}; /* Attenuation to compensate for the modal density and decay rate of the * late lines. @@ -375,12 +375,12 @@ struct ReverbState final : public EffectState { DelayLineI mDelay; /* Tap points for early reflection delay. */ - ALsizei mEarlyDelayTap[NUM_LINES][2]{}; + size_t mEarlyDelayTap[NUM_LINES][2]{}; ALfloat mEarlyDelayCoeff[NUM_LINES][2]{}; /* Tap points for late reverb feed and delay. */ - ALsizei mLateFeedTap{}; - ALsizei mLateDelayTap[NUM_LINES][2]{}; + size_t mLateFeedTap{}; + size_t mLateDelayTap[NUM_LINES][2]{}; /* Coefficients for the all-pass and line scattering matrices. */ ALfloat mMixX{0.0f}; @@ -391,13 +391,13 @@ struct ReverbState final : public EffectState { LateReverb mLate; /* Indicates the cross-fade point for delay line reads [0,FADE_SAMPLES]. */ - ALsizei mFadeCount{0}; + size_t mFadeCount{0}; /* Maximum number of samples to process at once. */ - ALsizei mMaxUpdate[2]{MAX_UPDATE_SAMPLES, MAX_UPDATE_SAMPLES}; + size_t mMaxUpdate[2]{MAX_UPDATE_SAMPLES, MAX_UPDATE_SAMPLES}; /* The current write offset for all delay lines. */ - ALsizei mOffset{0}; + size_t mOffset{}; /* Temporary storage used when processing. */ union { @@ -408,20 +408,20 @@ struct ReverbState final : public EffectState { alignas(16) std::array mLateSamples{}; using MixOutT = void (ReverbState::*)(const al::span samplesOut, - const ALsizei counter, const ALsizei offset, const ALsizei todo); + const size_t counter, const size_t offset, const size_t todo); MixOutT mMixOut{&ReverbState::MixOutPlain}; std::array mOrderScales{}; std::array,2> mAmbiSplitter; - void MixOutPlain(const al::span samplesOut, const ALsizei counter, - const ALsizei offset, const ALsizei todo) + void MixOutPlain(const al::span samplesOut, const size_t counter, + const size_t offset, const size_t todo) { ASSUME(todo > 0); /* Convert back to B-Format, and mix the results to output. */ - const al::span tmpspan{mTempLine.data(), mTempLine.data()+todo}; + const al::span tmpspan{mTempLine.data(), todo}; for(size_t c{0u};c < NUM_LINES;c++) { std::fill(tmpspan.begin(), tmpspan.end(), 0.0f); @@ -440,12 +440,12 @@ struct ReverbState final : public EffectState { } } - void MixOutAmbiUp(const al::span samplesOut, const ALsizei counter, - const ALsizei offset, const ALsizei todo) + void MixOutAmbiUp(const al::span samplesOut, const size_t counter, + const size_t offset, const size_t todo) { ASSUME(todo > 0); - const al::span tmpspan{mTempLine.data(), mTempLine.data()+todo}; + const al::span tmpspan{mTempLine.data(), todo}; for(size_t c{0u};c < NUM_LINES;c++) { std::fill(tmpspan.begin(), tmpspan.end(), 0.0f); @@ -505,7 +505,7 @@ bool ReverbState::allocLines(const ALfloat frequency) /* All delay line lengths are calculated to accomodate the full range of * lengths given their respective paramters. */ - ALuint totalSamples{0u}; + size_t totalSamples{0u}; /* Multiplier for the maximum density value, i.e. density=1, which is * actually the least density... @@ -965,7 +965,7 @@ void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, co props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain, target); /* Calculate the max update size from the smallest relevant delay. */ - mMaxUpdate[1] = mini(MAX_UPDATE_SAMPLES, mini(mEarly.Offset[0][1], mLate.Offset[0][1])); + mMaxUpdate[1] = minz(MAX_UPDATE_SAMPLES, minz(mEarly.Offset[0][1], mLate.Offset[0][1])); /* Determine if delay-line cross-fading is required. Density is essentially * a master control for the feedback delays, so changes the offsets of many @@ -1049,17 +1049,16 @@ inline auto VectorPartialScatter(const std::array &RESTRICT in, } /* Utilizes the above, but reverses the input channels. */ -void VectorScatterRevDelayIn(const DelayLineI delay, ALint offset, const ALfloat xCoeff, - const ALfloat yCoeff, const ALsizei base, const al::span in, - const ALsizei count) +void VectorScatterRevDelayIn(const DelayLineI delay, size_t offset, const ALfloat xCoeff, + const ALfloat yCoeff, const size_t base, const al::span in, + const size_t count) { - ASSUME(base >= 0); ASSUME(count > 0); - for(ALsizei i{0};i < count;) + for(size_t i{0u};i < count;) { offset &= delay.Mask; - ALsizei td{mini(delay.Mask+1 - offset, count-i)}; + size_t td{minz(delay.Mask+1 - offset, count-i)}; do { std::array f; for(size_t j{0u};j < NUM_LINES;j++) @@ -1081,27 +1080,27 @@ void VectorScatterRevDelayIn(const DelayLineI delay, ALint offset, const ALfloat * Two static specializations are used for transitional (cross-faded) delay * line processing and non-transitional processing. */ -void VecAllpass::processUnfaded(const al::span samples, ALsizei offset, - const ALfloat xCoeff, const ALfloat yCoeff, const ALsizei todo) +void VecAllpass::processUnfaded(const al::span samples, size_t offset, + const ALfloat xCoeff, const ALfloat yCoeff, const size_t todo) { const DelayLineI delay{Delay}; const ALfloat feedCoeff{Coeff}; ASSUME(todo > 0); - ALsizei vap_offset[NUM_LINES]; + size_t vap_offset[NUM_LINES]; for(size_t j{0u};j < NUM_LINES;j++) vap_offset[j] = offset - Offset[j][0]; - for(ALsizei i{0};i < todo;) + for(size_t i{0u};i < todo;) { for(size_t j{0u};j < NUM_LINES;j++) vap_offset[j] &= delay.Mask; offset &= delay.Mask; - ALsizei maxoff{offset}; + size_t maxoff{offset}; for(size_t j{0u};j < NUM_LINES;j++) - maxoff = maxi(maxoff, vap_offset[j]); - ALsizei td{mini(delay.Mask+1 - maxoff, todo - i)}; + maxoff = maxz(maxoff, vap_offset[j]); + size_t td{minz(delay.Mask+1 - maxoff, todo - i)}; do { std::array f; @@ -1119,8 +1118,8 @@ void VecAllpass::processUnfaded(const al::span sampl } while(--td); } } -void VecAllpass::processFaded(const al::span samples, ALsizei offset, - const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, const ALsizei todo) +void VecAllpass::processFaded(const al::span samples, size_t offset, + const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, const size_t todo) { const DelayLineI delay{Delay}; const ALfloat feedCoeff{Coeff}; @@ -1128,13 +1127,13 @@ void VecAllpass::processFaded(const al::span samples ASSUME(todo > 0); fade *= 1.0f/FADE_SAMPLES; - ALsizei vap_offset[NUM_LINES][2]; + size_t vap_offset[NUM_LINES][2]; for(size_t j{0u};j < NUM_LINES;j++) { vap_offset[j][0] = offset - Offset[j][0]; vap_offset[j][1] = offset - Offset[j][1]; } - for(ALsizei i{0};i < todo;) + for(size_t i{0u};i < todo;) { for(size_t j{0u};j < NUM_LINES;j++) { @@ -1143,10 +1142,10 @@ void VecAllpass::processFaded(const al::span samples } offset &= delay.Mask; - ALsizei maxoff{offset}; + size_t maxoff{offset}; for(size_t j{0u};j < NUM_LINES;j++) - maxoff = maxi(maxoff, maxi(vap_offset[j][0], vap_offset[j][1])); - ALsizei td{mini(delay.Mask+1 - maxoff, todo - i)}; + maxoff = maxz(maxoff, maxz(vap_offset[j][0], vap_offset[j][1])); + size_t td{minz(delay.Mask+1 - maxoff, todo - i)}; do { fade += FadeStep; @@ -1189,8 +1188,8 @@ void VecAllpass::processFaded(const al::span samples * Two static specializations are used for transitional (cross-faded) delay * line processing and non-transitional processing. */ -void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei todo, - const ALsizei base) +void EarlyReflection_Unfaded(ReverbState *State, const size_t offset, const size_t todo, + const size_t base) { const al::span temps{State->mTempSamples}; const DelayLineI early_delay{State->mEarly.Delay}; @@ -1205,12 +1204,12 @@ void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALs */ for(size_t j{0u};j < NUM_LINES;j++) { - ALsizei early_delay_tap{offset - State->mEarlyDelayTap[j][0]}; + size_t early_delay_tap{offset - State->mEarlyDelayTap[j][0]}; const ALfloat coeff{State->mEarlyDelayCoeff[j][0]}; - for(ALsizei i{0};i < todo;) + for(size_t i{0u};i < todo;) { early_delay_tap &= main_delay.Mask; - ALsizei td{mini(main_delay.Mask+1 - early_delay_tap, todo - i)}; + size_t td{minz(main_delay.Mask+1 - early_delay_tap, todo - i)}; do { temps[j][i++] = main_delay.Line[early_delay_tap++][j] * coeff; } while(--td); @@ -1227,15 +1226,14 @@ void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALs */ for(size_t j{0u};j < NUM_LINES;j++) { - ALint feedb_tap{offset - State->mEarly.Offset[j][0]}; + size_t feedb_tap{offset - State->mEarly.Offset[j][0]}; const ALfloat feedb_coeff{State->mEarly.Coeff[j][0]}; float *out = State->mEarlySamples[j].data() + base; - ASSUME(base >= 0); - for(ALsizei i{0};i < todo;) + for(size_t i{0u};i < todo;) { feedb_tap &= early_delay.Mask; - ALsizei td{mini(early_delay.Mask+1 - feedb_tap, todo - i)}; + size_t td{minz(early_delay.Mask+1 - feedb_tap, todo - i)}; do { out[i] = temps[j][i] + early_delay.Line[feedb_tap++][j]*feedb_coeff; ++i; @@ -1249,11 +1247,11 @@ void EarlyReflection_Unfaded(ReverbState *State, const ALsizei offset, const ALs * stage to pick up at the appropriate time, appplying a scatter and * bounce to improve the initial diffusion in the late reverb. */ - const ALsizei late_feed_tap{offset - State->mLateFeedTap}; + const size_t late_feed_tap{offset - State->mLateFeedTap}; const al::span out{State->mEarlySamples}; VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, out, todo); } -void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, +void EarlyReflection_Faded(ReverbState *State, const size_t offset, const size_t todo, const ALfloat fade) { const al::span temps{State->mTempSamples}; @@ -1266,18 +1264,18 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz for(size_t j{0u};j < NUM_LINES;j++) { - ALsizei early_delay_tap0{offset - State->mEarlyDelayTap[j][0]}; - ALsizei early_delay_tap1{offset - State->mEarlyDelayTap[j][1]}; + size_t early_delay_tap0{offset - State->mEarlyDelayTap[j][0]}; + size_t early_delay_tap1{offset - State->mEarlyDelayTap[j][1]}; const ALfloat oldCoeff{State->mEarlyDelayCoeff[j][0]}; const ALfloat oldCoeffStep{-oldCoeff / FADE_SAMPLES}; const ALfloat newCoeffStep{State->mEarlyDelayCoeff[j][1] / FADE_SAMPLES}; ALfloat fadeCount{fade}; - for(ALsizei i{0};i < todo;) + for(size_t i{0u};i < todo;) { early_delay_tap0 &= main_delay.Mask; early_delay_tap1 &= main_delay.Mask; - ALsizei td{mini(main_delay.Mask+1 - maxi(early_delay_tap0, early_delay_tap1), todo-i)}; + size_t td{minz(main_delay.Mask+1 - maxz(early_delay_tap0, early_delay_tap1), todo-i)}; do { fadeCount += 1.0f; const ALfloat fade0{oldCoeff + oldCoeffStep*fadeCount}; @@ -1293,19 +1291,19 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz for(size_t j{0u};j < NUM_LINES;j++) { - ALint feedb_tap0{offset - State->mEarly.Offset[j][0]}; - ALint feedb_tap1{offset - State->mEarly.Offset[j][1]}; + size_t feedb_tap0{offset - State->mEarly.Offset[j][0]}; + size_t feedb_tap1{offset - State->mEarly.Offset[j][1]}; const ALfloat feedb_oldCoeff{State->mEarly.Coeff[j][0]}; const ALfloat feedb_oldCoeffStep{-feedb_oldCoeff / FADE_SAMPLES}; const ALfloat feedb_newCoeffStep{State->mEarly.Coeff[j][1] / FADE_SAMPLES}; float *out = State->mEarlySamples[j].data(); ALfloat fadeCount{fade}; - for(ALsizei i{0};i < todo;) + for(size_t i{0u};i < todo;) { feedb_tap0 &= early_delay.Mask; feedb_tap1 &= early_delay.Mask; - ALsizei td{mini(early_delay.Mask+1 - maxi(feedb_tap0, feedb_tap1), todo - i)}; + size_t td{minz(early_delay.Mask+1 - maxz(feedb_tap0, feedb_tap1), todo - i)}; do { fadeCount += 1.0f; @@ -1321,7 +1319,7 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz for(size_t j{0u};j < NUM_LINES;j++) early_delay.write(offset, NUM_LINES-1-j, temps[j].data(), todo); - const ALsizei late_feed_tap{offset - State->mLateFeedTap}; + const size_t late_feed_tap{offset - State->mLateFeedTap}; const al::span out{State->mEarlySamples}; VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, 0, out, todo); } @@ -1340,8 +1338,8 @@ void EarlyReflection_Faded(ReverbState *State, const ALsizei offset, const ALsiz * Two variations are made, one for for transitional (cross-faded) delay line * processing and one for non-transitional processing. */ -void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei todo, - const ALsizei base) +void LateReverb_Unfaded(ReverbState *State, const size_t offset, const size_t todo, + const size_t base) { const al::span temps{State->mTempSamples}; const DelayLineI late_delay{State->mLate.Delay}; @@ -1356,17 +1354,16 @@ void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei */ for(size_t j{0u};j < NUM_LINES;j++) { - ALsizei late_delay_tap{offset - State->mLateDelayTap[j][0]}; - ALsizei late_feedb_tap{offset - State->mLate.Offset[j][0]}; + size_t late_delay_tap{offset - State->mLateDelayTap[j][0]}; + size_t late_feedb_tap{offset - State->mLate.Offset[j][0]}; const ALfloat midGain{State->mLate.T60[j].MidGain[0]}; const ALfloat densityGain{State->mLate.DensityGain[0] * midGain}; - for(ALsizei i{0};i < todo;) + for(size_t i{0u};i < todo;) { late_delay_tap &= main_delay.Mask; late_feedb_tap &= late_delay.Mask; - ALsizei td{mini( - mini(main_delay.Mask+1 - late_delay_tap, late_delay.Mask+1 - late_feedb_tap), - todo - i)}; + size_t td{minz(todo - i, + minz(main_delay.Mask+1 - late_delay_tap, late_delay.Mask+1 - late_feedb_tap))}; do { temps[j][i++] = main_delay.Line[late_delay_tap++][j]*densityGain + @@ -1386,7 +1383,7 @@ void LateReverb_Unfaded(ReverbState *State, const ALsizei offset, const ALsizei /* Finally, scatter and bounce the results to refeed the feedback buffer. */ VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, 0, temps, todo); } -void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei todo, +void LateReverb_Faded(ReverbState *State, const size_t offset, const size_t todo, const ALfloat fade) { const al::span temps{State->mTempSamples}; @@ -1407,22 +1404,21 @@ void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei to const ALfloat densityGain{State->mLate.DensityGain[1] * midGain}; const ALfloat oldDensityStep{-oldDensityGain / FADE_SAMPLES}; const ALfloat densityStep{densityGain / FADE_SAMPLES}; - ALsizei late_delay_tap0{offset - State->mLateDelayTap[j][0]}; - ALsizei late_delay_tap1{offset - State->mLateDelayTap[j][1]}; - ALsizei late_feedb_tap0{offset - State->mLate.Offset[j][0]}; - ALsizei late_feedb_tap1{offset - State->mLate.Offset[j][1]}; + size_t late_delay_tap0{offset - State->mLateDelayTap[j][0]}; + size_t late_delay_tap1{offset - State->mLateDelayTap[j][1]}; + size_t late_feedb_tap0{offset - State->mLate.Offset[j][0]}; + size_t late_feedb_tap1{offset - State->mLate.Offset[j][1]}; ALfloat fadeCount{fade}; - for(ALsizei i{0};i < todo;) + for(size_t i{0u};i < todo;) { late_delay_tap0 &= main_delay.Mask; late_delay_tap1 &= main_delay.Mask; late_feedb_tap0 &= late_delay.Mask; late_feedb_tap1 &= late_delay.Mask; - ALsizei td{mini( - mini(main_delay.Mask+1 - maxi(late_delay_tap0, late_delay_tap1), - late_delay.Mask+1 - maxi(late_feedb_tap0, late_feedb_tap1)), - todo - i)}; + size_t td{minz(todo - i, + minz(main_delay.Mask+1 - maxz(late_delay_tap0, late_delay_tap1), + late_delay.Mask+1 - maxz(late_feedb_tap0, late_feedb_tap1)))}; do { fadeCount += 1.0f; const ALfloat fade0{oldDensityGain + oldDensityStep*fadeCount}; @@ -1448,11 +1444,10 @@ void LateReverb_Faded(ReverbState *State, const ALsizei offset, const ALsizei to void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) { - ALsizei offset{mOffset}; - ALsizei fadeCount{mFadeCount}; + size_t offset{mOffset}; + size_t fadeCount{mFadeCount}; ASSUME(samplesToDo > 0); - ASSUME(offset >= 0); /* Convert B-Format to A-Format for processing. */ const al::span tmpspan{mTempLine.data(), mTempLine.data()+samplesToDo}; @@ -1468,22 +1463,22 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST } /* Process reverb for these samples. */ - for(ALsizei base{0};base < samplesToDo;) + for(size_t base{0};base < static_cast(samplesToDo);) { /* Calculate the number of samples we can do this iteration. */ - ALsizei todo{mini(samplesToDo - base, mini(mMaxUpdate[0], mMaxUpdate[1]))}; + size_t todo{minz(samplesToDo - base, minz(mMaxUpdate[0], mMaxUpdate[1]))}; /* Some mixers require maintaining a 4-sample alignment, so ensure that * if it's not the last iteration. */ - if(base+todo < samplesToDo) todo &= ~3; + if(base+todo < static_cast(samplesToDo)) todo &= ~3; ASSUME(todo > 0); /* Process the samples for reverb. */ - ALsizei samples_done{0}; + size_t samples_done{0u}; if UNLIKELY(fadeCount < FADE_SAMPLES) { /* If cross-fading, don't do more samples than there are to fade. */ - const ALsizei tofade{mini(todo, FADE_SAMPLES-fadeCount)}; + const size_t tofade{minz(todo, FADE_SAMPLES-fadeCount)}; auto fade = static_cast(fadeCount); /* Generate cross-faded early reflections and late reverb. */ @@ -1516,18 +1511,18 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST if LIKELY(samples_done < todo) { /* Generate non-faded early reflections and late reverb. */ - const ALsizei remaining{todo - samples_done}; + const size_t remaining{todo - samples_done}; EarlyReflection_Unfaded(this, offset, remaining, samples_done); LateReverb_Unfaded(this, offset, remaining, samples_done); offset += remaining; } /* Finally, mix early reflections and late reverb. */ - (this->*mMixOut)(samplesOut, samplesToDo-base, base, todo); + (this->*mMixOut)(samplesOut, static_cast(samplesToDo)-base, base, todo); base += todo; } - mOffset = offset & 0x3fffffff; + mOffset = offset; mFadeCount = fadeCount; } -- cgit v1.2.3 From 3fa83547e9d3857ad034fa29bd991111a3753259 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Aug 2019 11:39:39 -0700 Subject: Use size_t for HrtfMixer functions' buffer size --- alc/alu.cpp | 1 + alc/alu.h | 6 +++--- alc/mixer/defs.h | 6 +++--- alc/mixer/hrtfbase.h | 28 ++++++++++++++-------------- alc/mixer/mixer_c.cpp | 8 ++++---- alc/mixer/mixer_neon.cpp | 14 ++++++-------- alc/mixer/mixer_sse.cpp | 8 ++++---- 7 files changed, 35 insertions(+), 36 deletions(-) diff --git a/alc/alu.cpp b/alc/alu.cpp index 4a0ea8f9..a7d7cd70 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -159,6 +159,7 @@ void ALCdevice::ProcessHrtf(const ALsizei SamplesToDo) const int ridx{RealOut.ChannelIndex[FrontRight]}; ASSUME(lidx >= 0 && ridx >= 0); + ASSUME(SamplesToDo >= 0); MixDirectHrtf(RealOut.Buffer[lidx], RealOut.Buffer[ridx], Dry.Buffer, HrtfAccumData, mHrtfState.get(), SamplesToDo); } diff --git a/alc/alu.h b/alc/alu.h index 4ab093d2..e4036d19 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -320,13 +320,13 @@ using RowMixerFunc = void(*)(const al::span OutBuffer, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, - const ALsizei BufferSize); + const size_t BufferSize); #define GAIN_MIX_MAX (1000.0f) /* +60dB */ diff --git a/alc/mixer/defs.h b/alc/mixer/defs.h index bdb208c4..1a949ef3 100644 --- a/alc/mixer/defs.h +++ b/alc/mixer/defs.h @@ -37,11 +37,11 @@ void MixRow_(const al::span OutBuffer, const al::span Gains, const float *InSamples, const size_t InStride); template -void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfFilter *hrtfparams, const ALsizei BufferSize); +void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize); template -void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize); +void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize); template -void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, const ALsizei BufferSize); +void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, const size_t BufferSize); /* Vectorized resampler helpers */ inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *RESTRICT frac_arr, ALsizei *RESTRICT pos_arr, ALsizei size) diff --git a/alc/mixer/hrtfbase.h b/alc/mixer/hrtfbase.h index 3c8208f3..741e17d0 100644 --- a/alc/mixer/hrtfbase.h +++ b/alc/mixer/hrtfbase.h @@ -8,13 +8,13 @@ #include "opthelpers.h" -using ApplyCoeffsT = void(ALsizei Offset, float2 *RESTRICT Values, const ALsizei irSize, +using ApplyCoeffsT = void(size_t Offset, float2 *RESTRICT Values, const ALsizei irSize, const HrirArray &Coeffs, const ALfloat left, const ALfloat right); template inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *RESTRICT AccumSamples, const ALsizei OutPos, - const ALsizei IrSize, MixHrtfFilter *hrtfparams, const ALsizei BufferSize) + const ALsizei IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) { ASSUME(OutPos >= 0); ASSUME(IrSize >= 4); @@ -29,7 +29,7 @@ inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, HRTF_HISTORY_LENGTH - hrtfparams->Delay[1] }; ASSUME(Delay[0] >= 0 && Delay[1] >= 0); ALfloat stepcount{0.0f}; - for(ALsizei i{0};i < BufferSize;++i) + for(size_t i{0u};i < BufferSize;++i) { const ALfloat g{gain + gainstep*stepcount}; const ALfloat left{InSamples[Delay[0]++] * g}; @@ -39,9 +39,9 @@ inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, stepcount += 1.0f; } - for(ALsizei i{0};i < BufferSize;++i) + for(size_t i{0u};i < BufferSize;++i) LeftOut[OutPos+i] += AccumSamples[i][0]; - for(ALsizei i{0};i < BufferSize;++i) + for(size_t i{0u};i < BufferSize;++i) RightOut[OutPos+i] += AccumSamples[i][1]; hrtfparams->Gain = gain + gainstep*stepcount; @@ -51,7 +51,7 @@ template inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *RESTRICT AccumSamples, const ALsizei OutPos, const ALsizei IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, - const ALsizei BufferSize) + const size_t BufferSize) { const auto &OldCoeffs = oldparams->Coeffs; const ALfloat oldGain{oldparams->Gain}; @@ -68,7 +68,7 @@ inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut HRTF_HISTORY_LENGTH - oldparams->Delay[1] }; ASSUME(Delay[0] >= 0 && Delay[1] >= 0); ALfloat stepcount{0.0f}; - for(ALsizei i{0};i < BufferSize;++i) + for(size_t i{0u};i < BufferSize;++i) { const ALfloat g{oldGain + oldGainStep*stepcount}; const ALfloat left{InSamples[Delay[0]++] * g}; @@ -82,7 +82,7 @@ inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut Delay[1] = HRTF_HISTORY_LENGTH - newparams->Delay[1]; ASSUME(Delay[0] >= 0 && Delay[1] >= 0); stepcount = 0.0f; - for(ALsizei i{0};i < BufferSize;++i) + for(size_t i{0u};i < BufferSize;++i) { const ALfloat g{newGainStep*stepcount}; const ALfloat left{InSamples[Delay[0]++] * g}; @@ -92,9 +92,9 @@ inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut stepcount += 1.0f; } - for(ALsizei i{0};i < BufferSize;++i) + for(size_t i{0u};i < BufferSize;++i) LeftOut[OutPos+i] += AccumSamples[i][0]; - for(ALsizei i{0};i < BufferSize;++i) + for(size_t i{0u};i < BufferSize;++i) RightOut[OutPos+i] += AccumSamples[i][1]; newparams->Gain = newGainStep*stepcount; @@ -103,7 +103,7 @@ inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut template inline void MixDirectHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *RESTRICT AccumSamples, - DirectHrtfState *State, const ALsizei BufferSize) + DirectHrtfState *State, const size_t BufferSize) { ASSUME(BufferSize > 0); @@ -119,14 +119,14 @@ inline void MixDirectHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOu chanstate->Values.size(), AccumSamples); std::fill_n(accum_iter, BufferSize, float2{}); - for(ALsizei i{0};i < BufferSize;++i) + for(size_t i{0u};i < BufferSize;++i) { const ALfloat insample{input[i]}; ApplyCoeffs(i, AccumSamples+i, IrSize, Coeffs, insample, insample); } - for(ALsizei i{0};i < BufferSize;++i) + for(size_t i{0u};i < BufferSize;++i) LeftOut[i] += AccumSamples[i][0]; - for(ALsizei i{0};i < BufferSize;++i) + for(size_t i{0u};i < BufferSize;++i) RightOut[i] += AccumSamples[i][1]; std::copy_n(AccumSamples + BufferSize, chanstate->Values.size(), diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index 743431da..4af88fec 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -101,7 +101,7 @@ const ALfloat *Resample_(const InterpState *state, const ALfloat { return DoResample(state, src-state->bsinc.l, frac, increment, dst); } -static inline void ApplyCoeffs(ALsizei /*Offset*/, float2 *RESTRICT Values, const ALsizei IrSize, +static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const ALsizei IrSize, const HrirArray &Coeffs, const ALfloat left, const ALfloat right) { ASSUME(IrSize >= 2); @@ -115,7 +115,7 @@ static inline void ApplyCoeffs(ALsizei /*Offset*/, float2 *RESTRICT Values, cons template<> void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - MixHrtfFilter *hrtfparams, const ALsizei BufferSize) + MixHrtfFilter *hrtfparams, const size_t BufferSize) { MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, hrtfparams, BufferSize); @@ -124,7 +124,7 @@ void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize) + const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, oldparams, newparams, BufferSize); @@ -133,7 +133,7 @@ void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, - const ALsizei BufferSize) + const size_t BufferSize) { MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, BufferSize); } diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index 9a3722ab..bbf1d9f1 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -134,7 +134,7 @@ const ALfloat *Resample_(const InterpState *state, const ALflo } -static inline void ApplyCoeffs(ALsizei /*Offset*/, float2 *RESTRICT Values, const ALsizei IrSize, +static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const ALsizei IrSize, const HrirArray &Coeffs, const ALfloat left, const ALfloat right) { ASSUME(IrSize >= 2); @@ -149,21 +149,19 @@ static inline void ApplyCoeffs(ALsizei /*Offset*/, float2 *RESTRICT Values, cons for(ALsizei c{0};c < IrSize;c += 2) { - float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[c ][0]), - vld1_f32((float32_t*)&Values[c+1][0])); + float32x4_t vals = vld1q_f32((float32_t*)&Values[c][0]); float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]); vals = vmlaq_f32(vals, coefs, leftright4); - vst1_f32((float32_t*)&Values[c ][0], vget_low_f32(vals)); - vst1_f32((float32_t*)&Values[c+1][0], vget_high_f32(vals)); + vst1_f32((float32_t*)&Values[c][0], vals); } } template<> void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - MixHrtfFilter *hrtfparams, const ALsizei BufferSize) + MixHrtfFilter *hrtfparams, const size_t BufferSize) { MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, hrtfparams, BufferSize); @@ -172,7 +170,7 @@ void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize) + const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, oldparams, newparams, BufferSize); @@ -181,7 +179,7 @@ void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, - const ALsizei BufferSize) + const size_t BufferSize) { MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, BufferSize); } diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index c154eeef..b7503118 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -73,7 +73,7 @@ const ALfloat *Resample_(const InterpState *state, const ALfloa } -static inline void ApplyCoeffs(ALsizei Offset, float2 *RESTRICT Values, const ALsizei IrSize, +static inline void ApplyCoeffs(size_t Offset, float2 *RESTRICT Values, const ALsizei IrSize, const HrirArray &Coeffs, const ALfloat left, const ALfloat right) { const __m128 lrlr{_mm_setr_ps(left, right, left, right)}; @@ -119,7 +119,7 @@ static inline void ApplyCoeffs(ALsizei Offset, float2 *RESTRICT Values, const AL template<> void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - MixHrtfFilter *hrtfparams, const ALsizei BufferSize) + MixHrtfFilter *hrtfparams, const size_t BufferSize) { MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, hrtfparams, BufferSize); @@ -128,7 +128,7 @@ void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, - const HrtfFilter *oldparams, MixHrtfFilter *newparams, const ALsizei BufferSize) + const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, oldparams, newparams, BufferSize); @@ -137,7 +137,7 @@ void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, - const ALsizei BufferSize) + const size_t BufferSize) { MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, BufferSize); } -- cgit v1.2.3 From 80710c146a69823cef9827415c04f9f5491dc38c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Aug 2019 12:00:24 -0700 Subject: Use size_t for the mixers' fade counter and outpos --- alc/alu.h | 6 +++--- alc/mixer/defs.h | 9 +++++---- alc/mixer/hrtfbase.h | 6 ++---- alc/mixer/mixer_c.cpp | 8 ++++---- alc/mixer/mixer_neon.cpp | 8 ++++---- alc/mixer/mixer_sse.cpp | 8 ++++---- 6 files changed, 22 insertions(+), 23 deletions(-) diff --git a/alc/alu.h b/alc/alu.h index e4036d19..c4848e3e 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -315,14 +315,14 @@ struct ALvoice { using MixerFunc = void(*)(const al::span InSamples, const al::span OutBuffer, float *CurrentGains, const float *TargetGains, - const ALsizei Counter, const ALsizei OutPos); + const size_t Counter, const size_t OutPos); using RowMixerFunc = void(*)(const al::span OutBuffer, const al::span Gains, const float *InSamples, const size_t InStride); using HrtfMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, + const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALsizei IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize); using HrtfMixerBlendFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, + const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALsizei IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize); using HrtfDirectMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, diff --git a/alc/mixer/defs.h b/alc/mixer/defs.h index 1a949ef3..bb5ca56e 100644 --- a/alc/mixer/defs.h +++ b/alc/mixer/defs.h @@ -27,19 +27,20 @@ enum ResampleType { }; template -const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, ALint increment, const al::span dst); +const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, + ALint increment, const al::span dst); template void Mix_(const al::span InSamples, const al::span OutBuffer, - float *CurrentGains, const float *TargetGains, const ALsizei Counter, const ALsizei OutPos); + float *CurrentGains, const float *TargetGains, const size_t Counter, const size_t OutPos); template void MixRow_(const al::span OutBuffer, const al::span Gains, const float *InSamples, const size_t InStride); template -void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize); +void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALsizei IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize); template -void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize); +void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALsizei IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize); template void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, const size_t BufferSize); diff --git a/alc/mixer/hrtfbase.h b/alc/mixer/hrtfbase.h index 741e17d0..82446714 100644 --- a/alc/mixer/hrtfbase.h +++ b/alc/mixer/hrtfbase.h @@ -13,10 +13,9 @@ using ApplyCoeffsT = void(size_t Offset, float2 *RESTRICT Values, const ALsizei template inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *RESTRICT AccumSamples, const ALsizei OutPos, + const ALfloat *InSamples, float2 *RESTRICT AccumSamples, const size_t OutPos, const ALsizei IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) { - ASSUME(OutPos >= 0); ASSUME(IrSize >= 4); ASSUME(BufferSize > 0); @@ -49,7 +48,7 @@ inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *RESTRICT AccumSamples, const ALsizei OutPos, + const ALfloat *InSamples, float2 *RESTRICT AccumSamples, const size_t OutPos, const ALsizei IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { @@ -59,7 +58,6 @@ inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut const auto &NewCoeffs = *newparams->Coeffs; const ALfloat newGainStep{newparams->GainStep}; - ASSUME(OutPos >= 0); ASSUME(IrSize >= 4); ASSUME(BufferSize > 0); diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index 4af88fec..dbdbf16d 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -114,7 +114,7 @@ static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const template<> void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, + const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALsizei IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) { MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, @@ -123,7 +123,7 @@ void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, + const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALsizei IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, @@ -141,10 +141,10 @@ void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void Mix_(const al::span InSamples, const al::span OutBuffer, - float *CurrentGains, const float *TargetGains, const ALsizei Counter, const ALsizei OutPos) + float *CurrentGains, const float *TargetGains, const size_t Counter, const size_t OutPos) { const ALfloat delta{(Counter > 0) ? 1.0f / static_cast(Counter) : 0.0f}; - const bool reached_target{InSamples.size() >= static_cast(Counter)}; + const bool reached_target{InSamples.size() >= Counter}; const auto min_end = reached_target ? InSamples.begin() + Counter : InSamples.end(); for(FloatBufferLine &output : OutBuffer) { diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index bbf1d9f1..10965234 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -160,7 +160,7 @@ static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const template<> void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, + const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALsizei IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) { MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, @@ -169,7 +169,7 @@ void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, + const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALsizei IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, @@ -187,10 +187,10 @@ void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut template<> void Mix_(const al::span InSamples, const al::span OutBuffer, - float *CurrentGains, const float *TargetGains, const ALsizei Counter, const ALsizei OutPos) + float *CurrentGains, const float *TargetGains, const size_t Counter, const size_t OutPos) { const ALfloat delta{(Counter > 0) ? 1.0f / static_cast(Counter) : 0.0f}; - const bool reached_target{InSamples.size() >= static_cast(Counter)}; + const bool reached_target{InSamples.size() >= Counter}; const auto min_end = reached_target ? InSamples.begin() + Counter : InSamples.end(); const auto aligned_end = minz(InSamples.size(), (min_end-InSamples.begin()+3) & ~3) + InSamples.begin(); diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index b7503118..36690a2e 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -118,7 +118,7 @@ static inline void ApplyCoeffs(size_t Offset, float2 *RESTRICT Values, const ALs template<> void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, + const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALsizei IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) { MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, @@ -127,7 +127,7 @@ void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const ALsizei OutPos, const ALsizei IrSize, + const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALsizei IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, @@ -145,10 +145,10 @@ void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void Mix_(const al::span InSamples, const al::span OutBuffer, - float *CurrentGains, const float *TargetGains, const ALsizei Counter, const ALsizei OutPos) + float *CurrentGains, const float *TargetGains, const size_t Counter, const size_t OutPos) { const ALfloat delta{(Counter > 0) ? 1.0f / static_cast(Counter) : 0.0f}; - const bool reached_target{InSamples.size() >= static_cast(Counter)}; + const bool reached_target{InSamples.size() >= Counter}; const auto min_end = reached_target ? InSamples.begin() + Counter : InSamples.end(); const auto aligned_end = minz(InSamples.size(), (min_end-InSamples.begin()+3) & ~3) + InSamples.begin(); -- cgit v1.2.3 From 3a6676b61e0ff4f7aa27482fa421f86150cc0c3b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Aug 2019 12:19:38 -0700 Subject: Fix NEON store call --- alc/mixer/mixer_neon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index 10965234..7b9f7d4e 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -154,7 +154,7 @@ static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const vals = vmlaq_f32(vals, coefs, leftright4); - vst1_f32((float32_t*)&Values[c][0], vals); + vst1q_f32((float32_t*)&Values[c][0], vals); } } -- cgit v1.2.3 From 3e499e70fd947e6c4487f9496c1647909a61586f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Aug 2019 12:31:46 -0700 Subject: Try to improve non-dynamic-extent span construction --- common/alspan.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/alspan.h b/common/alspan.h index 6a43b32a..63b36eaa 100644 --- a/common/alspan.h +++ b/common/alspan.h @@ -116,8 +116,8 @@ public: constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { } template constexpr span(const U &cont) : span{al::data(cont), al::size(cont)} { } - template::value && extent == N && std::is_convertible::value)> - constexpr span(const span &span_) noexcept : span{al::data(span_), al::size(span_)} { } + template::value && std::is_convertible::value)> + constexpr span(const span &span_) noexcept : span{al::data(span_), al::size(span_)} { } constexpr span(const span&) noexcept = default; span& operator=(const span &rhs) noexcept = default; -- cgit v1.2.3 From bb46cec0b1acd8848774aedba45adb929108fa8e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Aug 2019 14:30:04 -0700 Subject: Pass samplesToDo as size_t to effects --- alc/effects/autowah.cpp | 10 +++++----- alc/effects/base.h | 4 +++- alc/effects/chorus.cpp | 16 ++++++++-------- alc/effects/compressor.cpp | 14 +++++++------- alc/effects/dedicated.cpp | 8 ++++---- alc/effects/distortion.cpp | 14 +++++++------- alc/effects/echo.cpp | 23 +++++++++++------------ alc/effects/equalizer.cpp | 6 +++--- alc/effects/fshifter.cpp | 18 +++++++++--------- alc/effects/modulator.cpp | 24 +++++++++++------------- alc/effects/null.cpp | 4 ++-- alc/effects/pshifter.cpp | 32 ++++++++++++++++---------------- alc/effects/reverb.cpp | 12 ++++++------ alc/effects/vmorpher.cpp | 24 ++++++++++++------------ 14 files changed, 104 insertions(+), 105 deletions(-) diff --git a/alc/effects/autowah.cpp b/alc/effects/autowah.cpp index 10d69b6c..144798f8 100644 --- a/alc/effects/autowah.cpp +++ b/alc/effects/autowah.cpp @@ -71,7 +71,7 @@ struct ALautowahState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(ALautowahState) }; @@ -126,7 +126,7 @@ void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, } } -void ALautowahState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) +void ALautowahState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) { const ALfloat attack_rate = mAttackRate; const ALfloat release_rate = mReleaseRate; @@ -136,7 +136,7 @@ void ALautowahState::process(const ALsizei samplesToDo, const FloatBufferLine *R const ALfloat bandwidth = mBandwidthNorm; ALfloat env_delay{mEnvDelay}; - for(ALsizei i{0};i < samplesToDo;i++) + for(size_t i{0u};i < samplesToDo;i++) { ALfloat w0, sample, a; @@ -166,7 +166,7 @@ void ALautowahState::process(const ALsizei samplesToDo, const FloatBufferLine *R ALfloat z1{mChans[c].Filter.z1}; ALfloat z2{mChans[c].Filter.z2}; - for(ALsizei i{0};i < samplesToDo;i++) + for(size_t i{0u};i < samplesToDo;i++) { const ALfloat alpha = mEnv[i].alpha; const ALfloat cos_w0 = mEnv[i].cos_w0; @@ -190,7 +190,7 @@ void ALautowahState::process(const ALsizei samplesToDo, const FloatBufferLine *R mChans[c].Filter.z2 = z2; /* Now, mix the processed sound data to the output. */ - MixSamples({mBufferOut, mBufferOut+samplesToDo}, samplesOut, mChans[c].CurrentGains, + MixSamples({mBufferOut, samplesToDo}, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, samplesToDo, 0); } } diff --git a/alc/effects/base.h b/alc/effects/base.h index 89a9e8e4..4d22c4c4 100644 --- a/alc/effects/base.h +++ b/alc/effects/base.h @@ -1,6 +1,8 @@ #ifndef EFFECTS_BASE_H #define EFFECTS_BASE_H +#include + #include "alcmain.h" #include "almalloc.h" #include "alspan.h" @@ -157,7 +159,7 @@ struct EffectState : public al::intrusive_ref { virtual ALboolean deviceUpdate(const ALCdevice *device) = 0; virtual void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) = 0; - virtual void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) = 0; + virtual void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) = 0; }; diff --git a/alc/effects/chorus.cpp b/alc/effects/chorus.cpp index 7b43962c..37e29b8e 100644 --- a/alc/effects/chorus.cpp +++ b/alc/effects/chorus.cpp @@ -55,7 +55,7 @@ enum class WaveForm { }; void GetTriangleDelays(ALint *delays, const ALsizei start_offset, const ALsizei lfo_range, - const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, const ALsizei todo) + const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, const size_t todo) { ASSUME(start_offset >= 0); ASSUME(lfo_range > 0); @@ -71,7 +71,7 @@ void GetTriangleDelays(ALint *delays, const ALsizei start_offset, const ALsizei } void GetSinusoidDelays(ALint *delays, const ALsizei start_offset, const ALsizei lfo_range, - const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, const ALsizei todo) + const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, const size_t todo) { ASSUME(start_offset >= 0); ASSUME(lfo_range > 0); @@ -111,7 +111,7 @@ struct ChorusState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(ChorusState) }; @@ -207,7 +207,7 @@ void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, co } } -void ChorusState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) +void ChorusState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) { const auto bufmask = static_cast(mSampleBuffer.size()-1); const ALfloat feedback{mFeedback}; @@ -215,9 +215,9 @@ void ChorusState::process(const ALsizei samplesToDo, const FloatBufferLine *REST ALfloat *RESTRICT delaybuf{mSampleBuffer.data()}; ALsizei offset{mOffset}; - for(ALsizei base{0};base < samplesToDo;) + for(size_t base{0u};base < samplesToDo;) { - const ALsizei todo = mini(256, samplesToDo-base); + const size_t todo{minz(256, samplesToDo-base)}; ALint moddelays[2][256]; if(mWaveform == WaveForm::Sinusoid) @@ -237,7 +237,7 @@ void ChorusState::process(const ALsizei samplesToDo, const FloatBufferLine *REST mLfoOffset = (mLfoOffset+todo) % mLfoRange; alignas(16) ALfloat temps[2][256]; - for(ALsizei i{0};i < todo;i++) + for(size_t i{0u};i < todo;i++) { // Feed the buffer's input first (necessary for delays < 1). delaybuf[offset&bufmask] = samplesIn[0][base+i]; @@ -262,7 +262,7 @@ void ChorusState::process(const ALsizei samplesToDo, const FloatBufferLine *REST } for(ALsizei c{0};c < 2;c++) - MixSamples({temps[c], temps[c]+todo}, samplesOut, mGains[c].Current, mGains[c].Target, + MixSamples({temps[c], todo}, samplesOut, mGains[c].Current, mGains[c].Target, samplesToDo-base, base); base += todo; diff --git a/alc/effects/compressor.cpp b/alc/effects/compressor.cpp index 63867762..e2f644ed 100644 --- a/alc/effects/compressor.cpp +++ b/alc/effects/compressor.cpp @@ -51,7 +51,7 @@ struct CompressorState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(CompressorState) }; @@ -85,18 +85,18 @@ void CompressorState::update(const ALCcontext*, const ALeffectslot *slot, const } } -void CompressorState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) +void CompressorState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) { - for(ALsizei base{0};base < samplesToDo;) + for(size_t base{0u};base < samplesToDo;) { ALfloat gains[256]; - const ALsizei td{mini(256, samplesToDo-base)}; + const size_t td{minz(256, samplesToDo-base)}; /* Generate the per-sample gains from the signal envelope. */ ALfloat env{mEnvFollower}; if(mEnabled) { - for(ALsizei i{0};i < td;++i) + for(size_t i{0u};i < td;++i) { /* Clamp the absolute amplitude to the defined envelope limits, * then attack or release the envelope to reach it. @@ -120,7 +120,7 @@ void CompressorState::process(const ALsizei samplesToDo, const FloatBufferLine * * ensure smooth gain changes when the compressor is turned on and * off. */ - for(ALsizei i{0};i < td;++i) + for(size_t i{0u};i < td;++i) { const ALfloat amplitude{1.0f}; if(amplitude > env) @@ -144,7 +144,7 @@ void CompressorState::process(const ALsizei samplesToDo, const FloatBufferLine * if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; - for(ALsizei i{0};i < td;i++) + for(size_t i{0u};i < td;i++) output[base+i] += samplesIn[j][base+i] * gains[i] * gain; } } diff --git a/alc/effects/dedicated.cpp b/alc/effects/dedicated.cpp index dc5e8527..83cba773 100644 --- a/alc/effects/dedicated.cpp +++ b/alc/effects/dedicated.cpp @@ -39,7 +39,7 @@ struct DedicatedState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(DedicatedState) }; @@ -86,10 +86,10 @@ void DedicatedState::update(const ALCcontext*, const ALeffectslot *slot, const E } } -void DedicatedState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) +void DedicatedState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) { - MixSamples({samplesIn[0].data(), samplesIn[0].data()+samplesToDo}, samplesOut, mCurrentGains, - mTargetGains, samplesToDo, 0); + MixSamples({samplesIn[0].data(), samplesToDo}, samplesOut, mCurrentGains, mTargetGains, + samplesToDo, 0); } diff --git a/alc/effects/distortion.cpp b/alc/effects/distortion.cpp index ec1550f5..ac6486cb 100644 --- a/alc/effects/distortion.cpp +++ b/alc/effects/distortion.cpp @@ -49,7 +49,7 @@ struct DistortionState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(DistortionState) }; @@ -93,22 +93,22 @@ void DistortionState::update(const ALCcontext *context, const ALeffectslot *slot ComputePanGains(target.Main, coeffs, slot->Params.Gain*props->Distortion.Gain, mGain); } -void DistortionState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) +void DistortionState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) { const ALfloat fc{mEdgeCoeff}; - for(ALsizei base{0};base < samplesToDo;) + for(size_t base{0u};base < samplesToDo;) { /* Perform 4x oversampling to avoid aliasing. Oversampling greatly * improves distortion quality and allows to implement lowpass and * bandpass filters using high frequencies, at which classic IIR * filters became unstable. */ - ALsizei todo{mini(BUFFERSIZE, (samplesToDo-base) * 4)}; + size_t todo{minz(BUFFERSIZE, (samplesToDo-base) * 4)}; /* Fill oversample buffer using zero stuffing. Multiply the sample by * the amount of oversampling to maintain the signal's power. */ - for(ALsizei i{0};i < todo;i++) + for(size_t i{0u};i < todo;i++) mBuffer[0][i] = !(i&3) ? samplesIn[0][(i>>2)+base] * 4.0f : 0.0f; /* First step, do lowpass filtering of original signal. Additionally @@ -123,7 +123,7 @@ void DistortionState::process(const ALsizei samplesToDo, const FloatBufferLine * * waveshaping are intended to modify waveform without boost/clipping/ * attenuation process. */ - for(ALsizei i{0};i < todo;i++) + for(size_t i{0u};i < todo;i++) { ALfloat smp{mBuffer[1][i]}; @@ -148,7 +148,7 @@ void DistortionState::process(const ALsizei samplesToDo, const FloatBufferLine * if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; - for(ALsizei i{0};i < todo;i++) + for(size_t i{0u};i < todo;i++) output[base+i] += gain * mBuffer[1][i*4]; } diff --git a/alc/effects/echo.cpp b/alc/effects/echo.cpp index 57279005..4a9ee1bc 100644 --- a/alc/effects/echo.cpp +++ b/alc/effects/echo.cpp @@ -42,9 +42,9 @@ struct EchoState final : public EffectState { // The echo is two tap. The delay is the number of samples from before the // current offset struct { - ALsizei delay{0}; + size_t delay{0u}; } mTap[2]; - ALsizei mOffset{0}; + size_t mOffset{0u}; /* The panning gains for the two taps */ struct { @@ -59,7 +59,7 @@ struct EchoState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(EchoState) }; @@ -117,26 +117,25 @@ void EchoState::update(const ALCcontext *context, const ALeffectslot *slot, cons ComputePanGains(target.Main, coeffs[1], slot->Params.Gain, mGains[1].Target); } -void EchoState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) +void EchoState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) { const auto mask = static_cast(mSampleBuffer.size()-1); ALfloat *RESTRICT delaybuf{mSampleBuffer.data()}; - ALsizei offset{mOffset}; - ALsizei tap1{offset - mTap[0].delay}; - ALsizei tap2{offset - mTap[1].delay}; + size_t offset{mOffset}; + size_t tap1{offset - mTap[0].delay}; + size_t tap2{offset - mTap[1].delay}; ALfloat z1, z2; ASSUME(samplesToDo > 0); - ASSUME(mask > 0); std::tie(z1, z2) = mFilter.getComponents(); - for(ALsizei i{0};i < samplesToDo;) + for(size_t i{0u};i < samplesToDo;) { offset &= mask; tap1 &= mask; tap2 &= mask; - ALsizei td{mini(mask+1 - maxi(offset, maxi(tap1, tap2)), samplesToDo-i)}; + size_t td{minz(mask+1 - maxz(offset, maxz(tap1, tap2)), samplesToDo-i)}; do { /* Feed the delay buffer's input first. */ delaybuf[offset] = samplesIn[0][i]; @@ -156,8 +155,8 @@ void EchoState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRI mOffset = offset; for(ALsizei c{0};c < 2;c++) - MixSamples({mTempBuffer[c], mTempBuffer[c]+samplesToDo}, samplesOut, mGains[c].Current, - mGains[c].Target, samplesToDo, 0); + MixSamples({mTempBuffer[c], samplesToDo}, samplesOut, mGains[c].Current, mGains[c].Target, + samplesToDo, 0); } diff --git a/alc/effects/equalizer.cpp b/alc/effects/equalizer.cpp index 27de12ad..05818ebf 100644 --- a/alc/effects/equalizer.cpp +++ b/alc/effects/equalizer.cpp @@ -93,7 +93,7 @@ struct EqualizerState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(EqualizerState) }; @@ -157,7 +157,7 @@ void EqualizerState::update(const ALCcontext *context, const ALeffectslot *slot, } } -void EqualizerState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) +void EqualizerState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) { ASSUME(numInput > 0); for(ALsizei c{0};c < numInput;c++) @@ -167,7 +167,7 @@ void EqualizerState::process(const ALsizei samplesToDo, const FloatBufferLine *R mChans[c].filter[2].process(mSampleBuffer, mSampleBuffer, samplesToDo); mChans[c].filter[3].process(mSampleBuffer, mSampleBuffer, samplesToDo); - MixSamples({mSampleBuffer, mSampleBuffer+samplesToDo}, samplesOut, mChans[c].CurrentGains, + MixSamples({mSampleBuffer, samplesToDo}, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, samplesToDo, 0); } } diff --git a/alc/effects/fshifter.cpp b/alc/effects/fshifter.cpp index 638325ec..6983ae42 100644 --- a/alc/effects/fshifter.cpp +++ b/alc/effects/fshifter.cpp @@ -61,7 +61,7 @@ alignas(16) const std::array HannWindow = InitHannWindow(); struct FshifterState final : public EffectState { /* Effect parameters */ - ALsizei mCount{}; + size_t mCount{}; ALsizei mPhaseStep[2]{}; ALsizei mPhase[2]{}; ALdouble mSign[2]{}; @@ -85,7 +85,7 @@ struct FshifterState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(FshifterState) }; @@ -117,7 +117,7 @@ void FshifterState::update(const ALCcontext *context, const ALeffectslot *slot, const ALCdevice *device{context->mDevice.get()}; ALfloat step{props->Fshifter.Frequency / static_cast(device->Frequency)}; - mPhaseStep[0] = mPhaseStep[1] = fastf2i(minf(step, 0.5f) * FRACTIONONE); + mPhaseStep[0] = mPhaseStep[1] = fastf2i(minf(step, 0.5f) * FRACTIONONE); switch(props->Fshifter.LeftDirection) { @@ -160,15 +160,15 @@ void FshifterState::update(const ALCcontext *context, const ALeffectslot *slot, ComputePanGains(target.Main, coeffs[1], slot->Params.Gain, mGains[1].Target); } -void FshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) +void FshifterState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) { static constexpr complex_d complex_zero{0.0, 0.0}; ALfloat *RESTRICT BufferOut = mBufferOut; - ALsizei j, k, base; + size_t j, k; - for(base = 0;base < samplesToDo;) + for(size_t base{0u};base < samplesToDo;) { - const ALsizei todo{mini(HIL_SIZE-mCount, samplesToDo-base)}; + const size_t todo{minz(HIL_SIZE-mCount, samplesToDo-base)}; ASSUME(todo > 0); @@ -222,8 +222,8 @@ void FshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE } /* Now, mix the processed sound data to the output. */ - MixSamples({BufferOut, BufferOut+samplesToDo}, samplesOut, mGains[c].Current, - mGains[c].Target, maxi(samplesToDo, 512), 0); + MixSamples({BufferOut, samplesToDo}, samplesOut, mGains[c].Current, mGains[c].Target, + maxz(samplesToDo, 512), 0); } } diff --git a/alc/effects/modulator.cpp b/alc/effects/modulator.cpp index 48022e15..a4a8e5c9 100644 --- a/alc/effects/modulator.cpp +++ b/alc/effects/modulator.cpp @@ -64,10 +64,9 @@ inline ALfloat One(ALsizei) } template -void Modulate(ALfloat *RESTRICT dst, ALsizei index, const ALsizei step, ALsizei todo) +void Modulate(ALfloat *RESTRICT dst, ALsizei index, const ALsizei step, size_t todo) { - ALsizei i; - for(i = 0;i < todo;i++) + for(size_t i{0u};i < todo;i++) { index += step; index &= WAVEFORM_FRACMASK; @@ -77,7 +76,7 @@ void Modulate(ALfloat *RESTRICT dst, ALsizei index, const ALsizei step, ALsizei struct ModulatorState final : public EffectState { - void (*mGetSamples)(ALfloat*RESTRICT, ALsizei, const ALsizei, ALsizei){}; + void (*mGetSamples)(ALfloat*RESTRICT, ALsizei, const ALsizei, size_t){}; ALsizei mIndex{0}; ALsizei mStep{1}; @@ -92,7 +91,7 @@ struct ModulatorState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(ModulatorState) }; @@ -139,29 +138,28 @@ void ModulatorState::update(const ALCcontext *context, const ALeffectslot *slot, } } -void ModulatorState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) +void ModulatorState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) { - for(ALsizei base{0};base < samplesToDo;) + for(size_t base{0u};base < samplesToDo;) { alignas(16) ALfloat modsamples[MAX_UPDATE_SAMPLES]; - ALsizei td = mini(MAX_UPDATE_SAMPLES, samplesToDo-base); - ALsizei c, i; + size_t td{minz(MAX_UPDATE_SAMPLES, samplesToDo-base)}; mGetSamples(modsamples, mIndex, mStep, td); mIndex += (mStep*td) & WAVEFORM_FRACMASK; mIndex &= WAVEFORM_FRACMASK; ASSUME(numInput > 0); - for(c = 0;c < numInput;c++) + for(ALsizei c{0};c < numInput;c++) { alignas(16) ALfloat temps[MAX_UPDATE_SAMPLES]; mChans[c].Filter.process(temps, &samplesIn[c][base], td); - for(i = 0;i < td;i++) + for(size_t i{0u};i < td;i++) temps[i] *= modsamples[i]; - MixSamples({temps, temps+td}, samplesOut, mChans[c].CurrentGains, - mChans[c].TargetGains, samplesToDo-base, base); + MixSamples({temps, td}, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, + samplesToDo-base, base); } base += td; diff --git a/alc/effects/null.cpp b/alc/effects/null.cpp index 245b9b04..c833a73a 100644 --- a/alc/effects/null.cpp +++ b/alc/effects/null.cpp @@ -20,7 +20,7 @@ struct NullState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(NullState) }; @@ -57,7 +57,7 @@ void NullState::update(const ALCcontext* /*context*/, const ALeffectslot* /*slot * input to the output buffer. The result should be added to the output buffer, * not replace it. */ -void NullState::process(const ALsizei /*samplesToDo*/, +void NullState::process(const size_t/*samplesToDo*/, const FloatBufferLine *RESTRICT /*samplesIn*/, const ALsizei /*numInput*/, const al::span /*samplesOut*/) { diff --git a/alc/effects/pshifter.cpp b/alc/effects/pshifter.cpp index e1181fe7..a3f162c9 100644 --- a/alc/effects/pshifter.cpp +++ b/alc/effects/pshifter.cpp @@ -92,7 +92,7 @@ inline complex_d polar2rect(const ALphasor &number) struct PshifterState final : public EffectState { /* Effect parameters */ - ALsizei mCount; + size_t mCount; ALsizei mPitchShiftI; ALfloat mPitchShift; ALfloat mFreqPerBin; @@ -118,7 +118,7 @@ struct PshifterState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(PshifterState) }; @@ -161,7 +161,7 @@ void PshifterState::update(const ALCcontext*, const ALeffectslot *slot, const Ef ComputePanGains(target.Main, coeffs, slot->Params.Gain, mTargetGains); } -void PshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) +void PshifterState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) { /* Pitch shifter engine based on the work of Stephan Bernsee. * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/ @@ -170,9 +170,9 @@ void PshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE static constexpr ALdouble expected{al::MathDefs::Tau() / OVERSAMP}; const ALdouble freq_per_bin{mFreqPerBin}; ALfloat *RESTRICT bufferOut{mBufferOut}; - ALsizei count{mCount}; + size_t count{mCount}; - for(ALsizei i{0};i < samplesToDo;) + for(size_t i{0u};i < samplesToDo;) { do { /* Fill FIFO buffer with samples data */ @@ -187,7 +187,7 @@ void PshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE count = FIFO_LATENCY; /* Real signal windowing and store in FFTbuffer */ - for(ALsizei k{0};k < STFT_SIZE;k++) + for(size_t k{0u};k < STFT_SIZE;k++) { mFFTbuffer[k].real(mInFIFO[k] * HannWindow[k]); mFFTbuffer[k].imag(0.0); @@ -200,7 +200,7 @@ void PshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE /* Analyze the obtained data. Since the real FFT is symmetric, only * STFT_HALF_SIZE+1 samples are needed. */ - for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) + for(size_t k{0u};k < STFT_HALF_SIZE+1;k++) { /* Compute amplitude and phase */ ALphasor component{rect2polar(mFFTbuffer[k])}; @@ -228,15 +228,15 @@ void PshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE /* PROCESSING */ /* pitch shifting */ - for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) + for(size_t k{0u};k < STFT_HALF_SIZE+1;k++) { mSyntesis_buffer[k].Amplitude = 0.0; mSyntesis_buffer[k].Frequency = 0.0; } - for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) + for(size_t k{0u};k < STFT_HALF_SIZE+1;k++) { - ALsizei j{(k*mPitchShiftI) >> FRACTIONBITS}; + size_t j{(k*mPitchShiftI) >> FRACTIONBITS}; if(j >= STFT_HALF_SIZE+1) break; mSyntesis_buffer[j].Amplitude += mAnalysis_buffer[k].Amplitude; @@ -245,7 +245,7 @@ void PshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE /* SYNTHESIS */ /* Synthesis the processing data */ - for(ALsizei k{0};k < STFT_HALF_SIZE+1;k++) + for(size_t k{0u};k < STFT_HALF_SIZE+1;k++) { ALphasor component; ALdouble tmp; @@ -263,19 +263,19 @@ void PshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE mFFTbuffer[k] = polar2rect(component); } /* zero negative frequencies for recontruct a real signal */ - for(ALsizei k{STFT_HALF_SIZE+1};k < STFT_SIZE;k++) + for(size_t k{STFT_HALF_SIZE+1};k < STFT_SIZE;k++) mFFTbuffer[k] = complex_d{}; /* Apply iFFT to buffer data */ complex_fft(mFFTbuffer, 1.0); /* Windowing and add to output */ - for(ALsizei k{0};k < STFT_SIZE;k++) + for(size_t k{0u};k < STFT_SIZE;k++) mOutputAccum[k] += HannWindow[k] * mFFTbuffer[k].real() / (0.5 * STFT_HALF_SIZE * OVERSAMP); /* Shift accumulator, input & output FIFO */ - ALsizei j, k; + size_t j, k; for(k = 0;k < STFT_STEP;k++) mOutFIFO[k] = static_cast(mOutputAccum[k]); for(j = 0;k < STFT_SIZE;k++,j++) mOutputAccum[j] = mOutputAccum[k]; for(;j < STFT_SIZE;j++) mOutputAccum[j] = 0.0; @@ -285,8 +285,8 @@ void PshifterState::process(const ALsizei samplesToDo, const FloatBufferLine *RE mCount = count; /* Now, mix the processed sound data to the output. */ - MixSamples({bufferOut, bufferOut+samplesToDo}, samplesOut, mCurrentGains, mTargetGains, - maxi(samplesToDo, 512), 0); + MixSamples({bufferOut, samplesToDo}, samplesOut, mCurrentGains, mTargetGains, + maxz(samplesToDo, 512), 0); } diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index d6a25d91..e611bf87 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -484,7 +484,7 @@ struct ReverbState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; DEF_NEWDEL(ReverbState) }; @@ -1442,7 +1442,7 @@ void LateReverb_Faded(ReverbState *State, const size_t offset, const size_t todo VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, 0, temps, todo); } -void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) +void ReverbState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) { size_t offset{mOffset}; size_t fadeCount{mFadeCount}; @@ -1450,7 +1450,7 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST ASSUME(samplesToDo > 0); /* Convert B-Format to A-Format for processing. */ - const al::span tmpspan{mTempLine.data(), mTempLine.data()+samplesToDo}; + const al::span tmpspan{mTempLine.data(), samplesToDo}; for(size_t c{0u};c < NUM_LINES;c++) { std::fill(tmpspan.begin(), tmpspan.end(), 0.0f); @@ -1463,14 +1463,14 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST } /* Process reverb for these samples. */ - for(size_t base{0};base < static_cast(samplesToDo);) + for(size_t base{0};base < samplesToDo;) { /* Calculate the number of samples we can do this iteration. */ size_t todo{minz(samplesToDo - base, minz(mMaxUpdate[0], mMaxUpdate[1]))}; /* Some mixers require maintaining a 4-sample alignment, so ensure that * if it's not the last iteration. */ - if(base+todo < static_cast(samplesToDo)) todo &= ~3; + if(base+todo < samplesToDo) todo &= ~3; ASSUME(todo > 0); /* Process the samples for reverb. */ @@ -1518,7 +1518,7 @@ void ReverbState::process(const ALsizei samplesToDo, const FloatBufferLine *REST } /* Finally, mix early reflections and late reverb. */ - (this->*mMixOut)(samplesOut, static_cast(samplesToDo)-base, base, todo); + (this->*mMixOut)(samplesOut, samplesToDo-base, base, todo); base += todo; } diff --git a/alc/effects/vmorpher.cpp b/alc/effects/vmorpher.cpp index 1f796786..a75420a3 100644 --- a/alc/effects/vmorpher.cpp +++ b/alc/effects/vmorpher.cpp @@ -66,9 +66,9 @@ inline ALfloat Half(ALsizei) } template -void Oscillate(ALfloat *RESTRICT dst, ALsizei index, const ALsizei step, ALsizei todo) +void Oscillate(ALfloat *RESTRICT dst, ALsizei index, const ALsizei step, size_t todo) { - for(ALsizei i{0};i < todo;i++) + for(size_t i{0u};i < todo;i++) { index += step; index &= WAVEFORM_FRACMASK; @@ -86,7 +86,7 @@ struct FormantFilter FormantFilter() = default; FormantFilter(ALfloat f0norm_, ALfloat gain) : f0norm{f0norm_}, fGain{gain} { } - inline void process(const ALfloat* samplesIn, ALfloat* samplesOut, const ALsizei numInput) + inline void process(const ALfloat* samplesIn, ALfloat* samplesOut, const size_t numInput) { /* A state variable filter from a topology-preserving transform. * Based on a talk given by Ivan Cohen: https://www.youtube.com/watch?v=esjHXGPyrhg @@ -94,7 +94,7 @@ struct FormantFilter const ALfloat g = std::tan(al::MathDefs::Pi() * f0norm); const ALfloat h = 1.0f / (1 + (g / Q_FACTOR) + (g * g)); - for (ALsizei i{0};i < numInput;i++) + for(size_t i{0u};i < numInput;i++) { const ALfloat H = h * (samplesIn[i] - (1.0f / Q_FACTOR + g) * s1 - s2); const ALfloat B = g * H + s1; @@ -126,7 +126,7 @@ struct VmorpherState final : public EffectState { ALfloat TargetGains[MAX_OUTPUT_CHANNELS]{}; } mChans[MAX_AMBI_CHANNELS]; - void (*mGetSamples)(ALfloat* RESTRICT, ALsizei, const ALsizei, ALsizei) {}; + void (*mGetSamples)(ALfloat* RESTRICT, ALsizei, const ALsizei, size_t){}; ALsizei mIndex{0}; ALsizei mStep{1}; @@ -137,7 +137,7 @@ struct VmorpherState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; static std::array getFiltersByPhoneme(ALenum phoneme, ALfloat frequency, ALfloat pitch); @@ -244,15 +244,15 @@ void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, } } -void VmorpherState::process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) +void VmorpherState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) { /* Following the EFX specification for a conformant implementation which describes * the effect as a pair of 4-band formant filters blended together using an LFO. */ - for(ALsizei base{0};base < samplesToDo;) + for(size_t base{0u};base < samplesToDo;) { alignas(16) ALfloat lfo[MAX_UPDATE_SAMPLES]; - const ALsizei td = mini(MAX_UPDATE_SAMPLES, samplesToDo-base); + const size_t td{minz(MAX_UPDATE_SAMPLES, samplesToDo-base)}; mGetSamples(lfo, mIndex, mStep, td); mIndex += (mStep * td) & WAVEFORM_FRACMASK; @@ -280,12 +280,12 @@ void VmorpherState::process(const ALsizei samplesToDo, const FloatBufferLine *RE vowelB[3].process(&samplesIn[c][base], mSampleBufferB, td); alignas(16) ALfloat blended[MAX_UPDATE_SAMPLES]; - for(ALsizei i{0};i < td;i++) + for(size_t i{0u};i < td;i++) blended[i] = lerp(mSampleBufferA[i], mSampleBufferB[i], lfo[i]); /* Now, mix the processed sound data to the output. */ - MixSamples({blended, blended+td}, samplesOut, mChans[c].CurrentGains, - mChans[c].TargetGains, samplesToDo-base, base); + MixSamples({blended, td}, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, + samplesToDo-base, base); } base += td; -- cgit v1.2.3 From 024d5d900aa7f9e3435459b0a8cfe354dc8e21fd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Aug 2019 03:00:19 -0700 Subject: Dereference the correct buffer when destructing a source --- al/source.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/al/source.cpp b/al/source.cpp index 95c3305e..49f2fb2a 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -3302,7 +3302,7 @@ ALsource::~ALsource() { std::unique_ptr head{BufferList}; BufferList = head->mNext.load(std::memory_order_relaxed); - if(ALbuffer *buffer{BufferList->mBuffer}) DecrementRef(buffer->ref); + if(ALbuffer *buffer{head->mBuffer}) DecrementRef(buffer->ref); } queue = nullptr; -- cgit v1.2.3 From 7ad2ed965c9506476f44a5d51deaa4de6b8557bf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Aug 2019 07:43:28 -0700 Subject: Avoid reading from pointers to __m128 values --- alc/mixer/mixer_neon.cpp | 42 ++++++++++++++++++------------------------ alc/mixer/mixer_sse.cpp | 29 +++++++++++++---------------- 2 files changed, 31 insertions(+), 40 deletions(-) diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index 7b9f7d4e..991443c9 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -76,13 +76,9 @@ template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, ALint increment, const al::span dst) { - const ALfloat *const filter = state->bsinc.filter; - const float32x4_t sf4 = vdupq_n_f32(state->bsinc.sf); - const ALsizei m = state->bsinc.m; - const float32x4_t *fil, *scd, *phd, *spd; - ALsizei pi, j, offset; - float32x4_t r4; - ALfloat pf; + const ALfloat *const filter{state->bsinc.filter}; + const float32x4_t sf4{vdupq_n_f32(state->bsinc.sf)}; + const ALsizei m{state->bsinc.m}; ASSUME(m > 0); ASSUME(increment > 0); @@ -93,34 +89,32 @@ const ALfloat *Resample_(const InterpState *state, const ALflo { // Calculate the phase index and factor. #define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) - pi = frac >> FRAC_PHASE_BITDIFF; - pf = (frac & ((1<> FRAC_PHASE_BITDIFF}; + const ALfloat pf{(frac & ((1<> 2; const float32x4_t pf4 = vdupq_n_f32(pf); + const float *fil{filter + m*pi*4}; + const float *scd{fil + m}; + const float *phd{scd + m}; + const float *spd{phd + m}; + ALsizei td{m >> 2}; + size_t j{0u}; - ASSUME(count > 0); - - for(j = 0;j < count;j++) - { + do { /* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */ const float32x4_t f4 = vmlaq_f32( - vmlaq_f32(fil[j], sf4, scd[j]), - pf4, vmlaq_f32(phd[j], sf4, spd[j]) - ); + vmlaq_f32(vld1q_f32(fil), sf4, vld1q_f32(scd)), + pf4, vmlaq_f32(vld1q_f32(phd), sf4, vld1q_f32(spd))); + fil += 4; scd += 4; phd += 4; spd += 4; /* r += f*src */ - r4 = vmlaq_f32(r4, f4, vld1q_f32(&src[j*4])); - } + r4 = vmlaq_f32(r4, f4, vld1q_f32(&src[j])); + j += 4; + } while(--td); } r4 = vaddq_f32(r4, vcombine_f32(vrev64_f32(vget_high_f32(r4)), vrev64_f32(vget_low_f32(r4)))); diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index 36690a2e..8d2abc88 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -34,31 +34,28 @@ const ALfloat *Resample_(const InterpState *state, const ALfloa const ALfloat pf{(frac & ((1<(filter + offset)}; offset += m; - const __m128 *scd{reinterpret_cast(filter + offset)}; offset += m; - const __m128 *phd{reinterpret_cast(filter + offset)}; offset += m; - const __m128 *spd{reinterpret_cast(filter + offset)}; - // Apply the scale and phase interpolated filter. __m128 r4{_mm_setzero_ps()}; { - const ALsizei count{m >> 2}; const __m128 pf4{_mm_set1_ps(pf)}; - - ASSUME(count > 0); + const float *fil{filter + m*pi*4}; + const float *scd{fil + m}; + const float *phd{scd + m}; + const float *spd{phd + m}; + ALsizei td{m >> 2}; + size_t j{0u}; #define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z)) - for(ALsizei j{0};j < count;j++) - { + do { /* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */ const __m128 f4 = MLA4( - MLA4(fil[j], sf4, scd[j]), - pf4, MLA4(phd[j], sf4, spd[j]) - ); + MLA4(_mm_load_ps(fil), sf4, _mm_load_ps(scd)), + pf4, MLA4(_mm_load_ps(phd), sf4, _mm_load_ps(spd))); + fil += 4; scd += 4; phd += 4; spd += 4; /* r += f*src */ - r4 = MLA4(r4, f4, _mm_loadu_ps(&src[j*4])); - } + r4 = MLA4(r4, f4, _mm_loadu_ps(&src[j])); + j += 4; + } while(--td); #undef MLA4 } r4 = _mm_add_ps(r4, _mm_shuffle_ps(r4, r4, _MM_SHUFFLE(0, 1, 2, 3))); -- cgit v1.2.3 From b7ab8b68962f3c3db486baf3fc8654df696408dc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Aug 2019 18:53:09 -0700 Subject: Fix a variable declaration --- alc/mixer/mixer_neon.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index 991443c9..472eae1b 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -94,10 +94,9 @@ const ALfloat *Resample_(const InterpState *state, const ALflo #undef FRAC_PHASE_BITDIFF // Apply the scale and phase interpolated filter. - r4 = vdupq_n_f32(0.0f); + float32x4_t r4{vdupq_n_f32(0.0f)}; { - const ALsizei count = m >> 2; - const float32x4_t pf4 = vdupq_n_f32(pf); + const float32x4_t pf4{vdupq_n_f32(pf)}; const float *fil{filter + m*pi*4}; const float *scd{fil + m}; const float *phd{scd + m}; -- cgit v1.2.3 From 02d38091c885a5fb7c30dda5193752544e985a09 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 23 Aug 2019 15:34:45 -0700 Subject: Make a couple functions into member functions --- alc/effects/reverb.cpp | 144 ++++++++++++++++++++++++------------------------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index e611bf87..ce81dfbd 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -482,6 +482,12 @@ struct ReverbState final : public EffectState { void update3DPanning(const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, const ALfloat earlyGain, const ALfloat lateGain, const EffectTarget &target); + void earlyUnfaded(const size_t offset, const size_t todo, const size_t base); + void earlyFaded(const size_t offset, const size_t todo, const ALfloat fade); + + void lateUnfaded(const size_t offset, const size_t todo, const size_t base); + void lateFaded(const size_t offset, const size_t todo, const ALfloat fade); + ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; @@ -1188,14 +1194,13 @@ void VecAllpass::processFaded(const al::span samples * Two static specializations are used for transitional (cross-faded) delay * line processing and non-transitional processing. */ -void EarlyReflection_Unfaded(ReverbState *State, const size_t offset, const size_t todo, - const size_t base) +void ReverbState::earlyUnfaded(const size_t offset, const size_t todo, const size_t base) { - const al::span temps{State->mTempSamples}; - const DelayLineI early_delay{State->mEarly.Delay}; - const DelayLineI main_delay{State->mDelay}; - const ALfloat mixX{State->mMixX}; - const ALfloat mixY{State->mMixY}; + const al::span temps{mTempSamples}; + const DelayLineI early_delay{mEarly.Delay}; + const DelayLineI main_delay{mDelay}; + const ALfloat mixX{mMixX}; + const ALfloat mixY{mMixY}; ASSUME(todo > 0); @@ -1204,8 +1209,8 @@ void EarlyReflection_Unfaded(ReverbState *State, const size_t offset, const size */ for(size_t j{0u};j < NUM_LINES;j++) { - size_t early_delay_tap{offset - State->mEarlyDelayTap[j][0]}; - const ALfloat coeff{State->mEarlyDelayCoeff[j][0]}; + size_t early_delay_tap{offset - mEarlyDelayTap[j][0]}; + const ALfloat coeff{mEarlyDelayCoeff[j][0]}; for(size_t i{0u};i < todo;) { early_delay_tap &= main_delay.Mask; @@ -1219,16 +1224,16 @@ void EarlyReflection_Unfaded(ReverbState *State, const size_t offset, const size /* Apply a vector all-pass, to help color the initial reflections based on * the diffusion strength. */ - State->mEarly.VecAp.processUnfaded(temps, offset, mixX, mixY, todo); + mEarly.VecAp.processUnfaded(temps, offset, mixX, mixY, todo); /* Apply a delay and bounce to generate secondary reflections, combine with * the primary reflections and write out the result for mixing. */ for(size_t j{0u};j < NUM_LINES;j++) { - size_t feedb_tap{offset - State->mEarly.Offset[j][0]}; - const ALfloat feedb_coeff{State->mEarly.Coeff[j][0]}; - float *out = State->mEarlySamples[j].data() + base; + size_t feedb_tap{offset - mEarly.Offset[j][0]}; + const ALfloat feedb_coeff{mEarly.Coeff[j][0]}; + float *out = mEarlySamples[j].data() + base; for(size_t i{0u};i < todo;) { @@ -1247,28 +1252,26 @@ void EarlyReflection_Unfaded(ReverbState *State, const size_t offset, const size * stage to pick up at the appropriate time, appplying a scatter and * bounce to improve the initial diffusion in the late reverb. */ - const size_t late_feed_tap{offset - State->mLateFeedTap}; - const al::span out{State->mEarlySamples}; - VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, out, todo); + const size_t late_feed_tap{offset - mLateFeedTap}; + VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, mEarlySamples, todo); } -void EarlyReflection_Faded(ReverbState *State, const size_t offset, const size_t todo, - const ALfloat fade) +void ReverbState::earlyFaded(const size_t offset, const size_t todo, const ALfloat fade) { - const al::span temps{State->mTempSamples}; - const DelayLineI early_delay{State->mEarly.Delay}; - const DelayLineI main_delay{State->mDelay}; - const ALfloat mixX{State->mMixX}; - const ALfloat mixY{State->mMixY}; + const al::span temps{mTempSamples}; + const DelayLineI early_delay{mEarly.Delay}; + const DelayLineI main_delay{mDelay}; + const ALfloat mixX{mMixX}; + const ALfloat mixY{mMixY}; ASSUME(todo > 0); for(size_t j{0u};j < NUM_LINES;j++) { - size_t early_delay_tap0{offset - State->mEarlyDelayTap[j][0]}; - size_t early_delay_tap1{offset - State->mEarlyDelayTap[j][1]}; - const ALfloat oldCoeff{State->mEarlyDelayCoeff[j][0]}; + size_t early_delay_tap0{offset - mEarlyDelayTap[j][0]}; + size_t early_delay_tap1{offset - mEarlyDelayTap[j][1]}; + const ALfloat oldCoeff{mEarlyDelayCoeff[j][0]}; const ALfloat oldCoeffStep{-oldCoeff / FADE_SAMPLES}; - const ALfloat newCoeffStep{State->mEarlyDelayCoeff[j][1] / FADE_SAMPLES}; + const ALfloat newCoeffStep{mEarlyDelayCoeff[j][1] / FADE_SAMPLES}; ALfloat fadeCount{fade}; for(size_t i{0u};i < todo;) @@ -1287,16 +1290,16 @@ void EarlyReflection_Faded(ReverbState *State, const size_t offset, const size_t } } - State->mEarly.VecAp.processFaded(temps, offset, mixX, mixY, fade, todo); + mEarly.VecAp.processFaded(temps, offset, mixX, mixY, fade, todo); for(size_t j{0u};j < NUM_LINES;j++) { - size_t feedb_tap0{offset - State->mEarly.Offset[j][0]}; - size_t feedb_tap1{offset - State->mEarly.Offset[j][1]}; - const ALfloat feedb_oldCoeff{State->mEarly.Coeff[j][0]}; + size_t feedb_tap0{offset - mEarly.Offset[j][0]}; + size_t feedb_tap1{offset - mEarly.Offset[j][1]}; + const ALfloat feedb_oldCoeff{mEarly.Coeff[j][0]}; const ALfloat feedb_oldCoeffStep{-feedb_oldCoeff / FADE_SAMPLES}; - const ALfloat feedb_newCoeffStep{State->mEarly.Coeff[j][1] / FADE_SAMPLES}; - float *out = State->mEarlySamples[j].data(); + const ALfloat feedb_newCoeffStep{mEarly.Coeff[j][1] / FADE_SAMPLES}; + float *out = mEarlySamples[j].data(); ALfloat fadeCount{fade}; for(size_t i{0u};i < todo;) @@ -1319,9 +1322,8 @@ void EarlyReflection_Faded(ReverbState *State, const size_t offset, const size_t for(size_t j{0u};j < NUM_LINES;j++) early_delay.write(offset, NUM_LINES-1-j, temps[j].data(), todo); - const size_t late_feed_tap{offset - State->mLateFeedTap}; - const al::span out{State->mEarlySamples}; - VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, 0, out, todo); + const size_t late_feed_tap{offset - mLateFeedTap}; + VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, 0, mEarlySamples, todo); } /* This generates the reverb tail using a modified feed-back delay network @@ -1338,14 +1340,13 @@ void EarlyReflection_Faded(ReverbState *State, const size_t offset, const size_t * Two variations are made, one for for transitional (cross-faded) delay line * processing and one for non-transitional processing. */ -void LateReverb_Unfaded(ReverbState *State, const size_t offset, const size_t todo, - const size_t base) +void ReverbState::lateUnfaded(const size_t offset, const size_t todo, const size_t base) { - const al::span temps{State->mTempSamples}; - const DelayLineI late_delay{State->mLate.Delay}; - const DelayLineI main_delay{State->mDelay}; - const ALfloat mixX{State->mMixX}; - const ALfloat mixY{State->mMixY}; + const al::span temps{mTempSamples}; + const DelayLineI late_delay{mLate.Delay}; + const DelayLineI main_delay{mDelay}; + const ALfloat mixX{mMixX}; + const ALfloat mixY{mMixY}; ASSUME(todo > 0); @@ -1354,10 +1355,10 @@ void LateReverb_Unfaded(ReverbState *State, const size_t offset, const size_t to */ for(size_t j{0u};j < NUM_LINES;j++) { - size_t late_delay_tap{offset - State->mLateDelayTap[j][0]}; - size_t late_feedb_tap{offset - State->mLate.Offset[j][0]}; - const ALfloat midGain{State->mLate.T60[j].MidGain[0]}; - const ALfloat densityGain{State->mLate.DensityGain[0] * midGain}; + size_t late_delay_tap{offset - mLateDelayTap[j][0]}; + size_t late_feedb_tap{offset - mLate.Offset[j][0]}; + const ALfloat midGain{mLate.T60[j].MidGain[0]}; + const ALfloat densityGain{mLate.DensityGain[0] * midGain}; for(size_t i{0u};i < todo;) { late_delay_tap &= main_delay.Mask; @@ -1370,44 +1371,43 @@ void LateReverb_Unfaded(ReverbState *State, const size_t offset, const size_t to late_delay.Line[late_feedb_tap++][j]*midGain; } while(--td); } - State->mLate.T60[j].process(temps[j].data(), todo); + mLate.T60[j].process(temps[j].data(), todo); } /* Apply a vector all-pass to improve micro-surface diffusion, and write * out the results for mixing. */ - State->mLate.VecAp.processUnfaded(temps, offset, mixX, mixY, todo); + mLate.VecAp.processUnfaded(temps, offset, mixX, mixY, todo); for(size_t j{0u};j < NUM_LINES;j++) - std::copy_n(temps[j].begin(), todo, State->mLateSamples[j].begin() + base); + std::copy_n(temps[j].begin(), todo, mLateSamples[j].begin() + base); /* Finally, scatter and bounce the results to refeed the feedback buffer. */ VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, 0, temps, todo); } -void LateReverb_Faded(ReverbState *State, const size_t offset, const size_t todo, - const ALfloat fade) +void ReverbState::lateFaded(const size_t offset, const size_t todo, const ALfloat fade) { - const al::span temps{State->mTempSamples}; - const DelayLineI late_delay{State->mLate.Delay}; - const DelayLineI main_delay{State->mDelay}; - const ALfloat mixX{State->mMixX}; - const ALfloat mixY{State->mMixY}; + const al::span temps{mTempSamples}; + const DelayLineI late_delay{mLate.Delay}; + const DelayLineI main_delay{mDelay}; + const ALfloat mixX{mMixX}; + const ALfloat mixY{mMixY}; ASSUME(todo > 0); for(size_t j{0u};j < NUM_LINES;j++) { - const ALfloat oldMidGain{State->mLate.T60[j].MidGain[0]}; - const ALfloat midGain{State->mLate.T60[j].MidGain[1]}; + const ALfloat oldMidGain{mLate.T60[j].MidGain[0]}; + const ALfloat midGain{mLate.T60[j].MidGain[1]}; const ALfloat oldMidStep{-oldMidGain / FADE_SAMPLES}; const ALfloat midStep{midGain / FADE_SAMPLES}; - const ALfloat oldDensityGain{State->mLate.DensityGain[0] * oldMidGain}; - const ALfloat densityGain{State->mLate.DensityGain[1] * midGain}; + const ALfloat oldDensityGain{mLate.DensityGain[0] * oldMidGain}; + const ALfloat densityGain{mLate.DensityGain[1] * midGain}; const ALfloat oldDensityStep{-oldDensityGain / FADE_SAMPLES}; const ALfloat densityStep{densityGain / FADE_SAMPLES}; - size_t late_delay_tap0{offset - State->mLateDelayTap[j][0]}; - size_t late_delay_tap1{offset - State->mLateDelayTap[j][1]}; - size_t late_feedb_tap0{offset - State->mLate.Offset[j][0]}; - size_t late_feedb_tap1{offset - State->mLate.Offset[j][1]}; + size_t late_delay_tap0{offset - mLateDelayTap[j][0]}; + size_t late_delay_tap1{offset - mLateDelayTap[j][1]}; + size_t late_feedb_tap0{offset - mLate.Offset[j][0]}; + size_t late_feedb_tap1{offset - mLate.Offset[j][1]}; ALfloat fadeCount{fade}; for(size_t i{0u};i < todo;) @@ -1432,12 +1432,12 @@ void LateReverb_Faded(ReverbState *State, const size_t offset, const size_t todo late_delay.Line[late_feedb_tap1++][j]*gfade1; } while(--td); } - State->mLate.T60[j].process(temps[j].data(), todo); + mLate.T60[j].process(temps[j].data(), todo); } - State->mLate.VecAp.processFaded(temps, offset, mixX, mixY, fade, todo); + mLate.VecAp.processFaded(temps, offset, mixX, mixY, fade, todo); for(size_t j{0u};j < NUM_LINES;j++) - std::copy_n(temps[j].begin(), todo, State->mLateSamples[j].begin()); + std::copy_n(temps[j].begin(), todo, mLateSamples[j].begin()); VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, 0, temps, todo); } @@ -1482,8 +1482,8 @@ void ReverbState::process(const size_t samplesToDo, const FloatBufferLine *RESTR auto fade = static_cast(fadeCount); /* Generate cross-faded early reflections and late reverb. */ - EarlyReflection_Faded(this, offset, tofade, fade); - LateReverb_Faded(this, offset, tofade, fade); + earlyFaded(offset, tofade, fade); + lateFaded(offset, tofade, fade); /* Step forward by amount faded. */ samples_done += tofade; @@ -1512,8 +1512,8 @@ void ReverbState::process(const size_t samplesToDo, const FloatBufferLine *RESTR { /* Generate non-faded early reflections and late reverb. */ const size_t remaining{todo - samples_done}; - EarlyReflection_Unfaded(this, offset, remaining, samples_done); - LateReverb_Unfaded(this, offset, remaining, samples_done); + earlyUnfaded(offset, remaining, samples_done); + lateUnfaded(offset, remaining, samples_done); offset += remaining; } -- cgit v1.2.3 From e165cae3cddec51332660bdb1e69d7fa5f687e68 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 24 Aug 2019 16:25:56 -0700 Subject: Fade reverb over the whole update Since the early and late panning gains fade over the course of the update, it should match the fading done by the feedback loops to avoid percussive "blasts" when transitioning to a long-decay low-gain environment from a short-decay high-gain environment. --- alc/effects/reverb.cpp | 210 ++++++++++++++++++++++++------------------------- 1 file changed, 104 insertions(+), 106 deletions(-) diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index ce81dfbd..5d9dbf81 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -53,13 +53,6 @@ using namespace std::placeholders; */ constexpr size_t MAX_UPDATE_SAMPLES{256}; -/* The number of samples used for cross-faded delay lines. This can be used - * to balance the compensation for abrupt line changes and attenuation due to - * minimally lengthed recursive lines. Try to keep this below the device - * update size. - */ -constexpr size_t FADE_SAMPLES{128}; - /* The number of spatialized lines or channels to process. Four channels allows * for a 3D A-Format response. NOTE: This can't be changed without taking care * of the conversion matrices, and a few places where the length arrays are @@ -91,8 +84,6 @@ alignas(16) constexpr ALfloat A2B[NUM_LINES][NUM_LINES]{ }; -constexpr ALfloat FadeStep{1.0f / FADE_SAMPLES}; - /* The all-pass and delay lines have a variable length dependent on the * effect's density parameter, which helps alter the perceived environment * size. The size-to-density conversion is a cubed scale: @@ -277,7 +268,8 @@ struct VecAllpass { size_t Offset[NUM_LINES][2]{}; void processFaded(const al::span samples, size_t offset, - const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, const size_t todo); + const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fadeCount, const ALfloat fadeStep, + const size_t todo); void processUnfaded(const al::span samples, size_t offset, const ALfloat xCoeff, const ALfloat yCoeff, const size_t todo); }; @@ -390,8 +382,7 @@ struct ReverbState final : public EffectState { LateReverb mLate; - /* Indicates the cross-fade point for delay line reads [0,FADE_SAMPLES]. */ - size_t mFadeCount{0}; + bool mDoFading{}; /* Maximum number of samples to process at once. */ size_t mMaxUpdate[2]{MAX_UPDATE_SAMPLES, MAX_UPDATE_SAMPLES}; @@ -482,11 +473,13 @@ struct ReverbState final : public EffectState { void update3DPanning(const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, const ALfloat earlyGain, const ALfloat lateGain, const EffectTarget &target); - void earlyUnfaded(const size_t offset, const size_t todo, const size_t base); - void earlyFaded(const size_t offset, const size_t todo, const ALfloat fade); + void earlyUnfaded(const size_t offset, const size_t todo); + void earlyFaded(const size_t offset, const size_t todo, const ALfloat fade, + const ALfloat fadeStep); - void lateUnfaded(const size_t offset, const size_t todo, const size_t base); - void lateFaded(const size_t offset, const size_t todo, const ALfloat fade); + void lateUnfaded(const size_t offset, const size_t todo); + void lateFaded(const size_t offset, const size_t todo, const ALfloat fade, + const ALfloat fadeStep); ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; @@ -612,8 +605,8 @@ ALboolean ReverbState::deviceUpdate(const ALCdevice *device) for(auto &gains : mLate.PanGain) std::fill(std::begin(gains), std::end(gains), 0.0f); - /* Reset counters and offset base. */ - mFadeCount = 0; + /* Reset fading and offset base. */ + mDoFading = true; std::fill(std::begin(mMaxUpdate), std::end(mMaxUpdate), MAX_UPDATE_SAMPLES); mOffset = 0; @@ -977,7 +970,7 @@ void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, co * a master control for the feedback delays, so changes the offsets of many * delay lines. */ - if(mParams.Density != props->Reverb.Density || + mDoFading |= (mParams.Density != props->Reverb.Density || /* Diffusion and decay times influences the decay rate (gain) of the * late reverb T60 filter. */ @@ -989,15 +982,17 @@ void ReverbState::update(const ALCcontext *Context, const ALeffectslot *Slot, co * gain. */ mParams.HFReference != props->Reverb.HFReference || - mParams.LFReference != props->Reverb.LFReference) - mFadeCount = 0; - mParams.Density = props->Reverb.Density; - mParams.Diffusion = props->Reverb.Diffusion; - mParams.DecayTime = props->Reverb.DecayTime; - mParams.HFDecayTime = hfDecayTime; - mParams.LFDecayTime = lfDecayTime; - mParams.HFReference = props->Reverb.HFReference; - mParams.LFReference = props->Reverb.LFReference; + mParams.LFReference != props->Reverb.LFReference); + if(mDoFading) + { + mParams.Density = props->Reverb.Density; + mParams.Diffusion = props->Reverb.Diffusion; + mParams.DecayTime = props->Reverb.DecayTime; + mParams.HFDecayTime = hfDecayTime; + mParams.LFDecayTime = lfDecayTime; + mParams.HFReference = props->Reverb.HFReference; + mParams.LFReference = props->Reverb.LFReference; + } } @@ -1056,8 +1051,7 @@ inline auto VectorPartialScatter(const std::array &RESTRICT in, /* Utilizes the above, but reverses the input channels. */ void VectorScatterRevDelayIn(const DelayLineI delay, size_t offset, const ALfloat xCoeff, - const ALfloat yCoeff, const size_t base, const al::span in, - const size_t count) + const ALfloat yCoeff, const al::span in, const size_t count) { ASSUME(count > 0); @@ -1068,7 +1062,7 @@ void VectorScatterRevDelayIn(const DelayLineI delay, size_t offset, const ALfloa do { std::array f; for(size_t j{0u};j < NUM_LINES;j++) - f[NUM_LINES-1-j] = in[j][base+i]; + f[NUM_LINES-1-j] = in[j][i]; ++i; delay.Line[offset++] = VectorPartialScatter(f, xCoeff, yCoeff); @@ -1125,14 +1119,14 @@ void VecAllpass::processUnfaded(const al::span sampl } } void VecAllpass::processFaded(const al::span samples, size_t offset, - const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, const size_t todo) + const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fadeCount, const ALfloat fadeStep, + const size_t todo) { const DelayLineI delay{Delay}; const ALfloat feedCoeff{Coeff}; ASSUME(todo > 0); - fade *= 1.0f/FADE_SAMPLES; size_t vap_offset[NUM_LINES][2]; for(size_t j{0u};j < NUM_LINES;j++) { @@ -1154,7 +1148,9 @@ void VecAllpass::processFaded(const al::span samples size_t td{minz(delay.Mask+1 - maxoff, todo - i)}; do { - fade += FadeStep; + fadeCount += 1.0f; + const float fade{fadeCount * fadeStep}; + std::array f; for(size_t j{0u};j < NUM_LINES;j++) f[j] = delay.Line[vap_offset[j][0]++][j]*(1.0f-fade) + @@ -1194,7 +1190,7 @@ void VecAllpass::processFaded(const al::span samples * Two static specializations are used for transitional (cross-faded) delay * line processing and non-transitional processing. */ -void ReverbState::earlyUnfaded(const size_t offset, const size_t todo, const size_t base) +void ReverbState::earlyUnfaded(const size_t offset, const size_t todo) { const al::span temps{mTempSamples}; const DelayLineI early_delay{mEarly.Delay}; @@ -1233,7 +1229,7 @@ void ReverbState::earlyUnfaded(const size_t offset, const size_t todo, const siz { size_t feedb_tap{offset - mEarly.Offset[j][0]}; const ALfloat feedb_coeff{mEarly.Coeff[j][0]}; - float *out = mEarlySamples[j].data() + base; + float *out = mEarlySamples[j].data(); for(size_t i{0u};i < todo;) { @@ -1253,9 +1249,10 @@ void ReverbState::earlyUnfaded(const size_t offset, const size_t todo, const siz * bounce to improve the initial diffusion in the late reverb. */ const size_t late_feed_tap{offset - mLateFeedTap}; - VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, base, mEarlySamples, todo); + VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, mEarlySamples, todo); } -void ReverbState::earlyFaded(const size_t offset, const size_t todo, const ALfloat fade) +void ReverbState::earlyFaded(const size_t offset, const size_t todo, const ALfloat fade, + const ALfloat fadeStep) { const al::span temps{mTempSamples}; const DelayLineI early_delay{mEarly.Delay}; @@ -1270,8 +1267,8 @@ void ReverbState::earlyFaded(const size_t offset, const size_t todo, const ALflo size_t early_delay_tap0{offset - mEarlyDelayTap[j][0]}; size_t early_delay_tap1{offset - mEarlyDelayTap[j][1]}; const ALfloat oldCoeff{mEarlyDelayCoeff[j][0]}; - const ALfloat oldCoeffStep{-oldCoeff / FADE_SAMPLES}; - const ALfloat newCoeffStep{mEarlyDelayCoeff[j][1] / FADE_SAMPLES}; + const ALfloat oldCoeffStep{-oldCoeff * fadeStep}; + const ALfloat newCoeffStep{mEarlyDelayCoeff[j][1] * fadeStep}; ALfloat fadeCount{fade}; for(size_t i{0u};i < todo;) @@ -1290,15 +1287,15 @@ void ReverbState::earlyFaded(const size_t offset, const size_t todo, const ALflo } } - mEarly.VecAp.processFaded(temps, offset, mixX, mixY, fade, todo); + mEarly.VecAp.processFaded(temps, offset, mixX, mixY, fade, fadeStep, todo); for(size_t j{0u};j < NUM_LINES;j++) { size_t feedb_tap0{offset - mEarly.Offset[j][0]}; size_t feedb_tap1{offset - mEarly.Offset[j][1]}; const ALfloat feedb_oldCoeff{mEarly.Coeff[j][0]}; - const ALfloat feedb_oldCoeffStep{-feedb_oldCoeff / FADE_SAMPLES}; - const ALfloat feedb_newCoeffStep{mEarly.Coeff[j][1] / FADE_SAMPLES}; + const ALfloat feedb_oldCoeffStep{-feedb_oldCoeff * fadeStep}; + const ALfloat feedb_newCoeffStep{mEarly.Coeff[j][1] * fadeStep}; float *out = mEarlySamples[j].data(); ALfloat fadeCount{fade}; @@ -1323,7 +1320,7 @@ void ReverbState::earlyFaded(const size_t offset, const size_t todo, const ALflo early_delay.write(offset, NUM_LINES-1-j, temps[j].data(), todo); const size_t late_feed_tap{offset - mLateFeedTap}; - VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, 0, mEarlySamples, todo); + VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, mEarlySamples, todo); } /* This generates the reverb tail using a modified feed-back delay network @@ -1340,7 +1337,7 @@ void ReverbState::earlyFaded(const size_t offset, const size_t todo, const ALflo * Two variations are made, one for for transitional (cross-faded) delay line * processing and one for non-transitional processing. */ -void ReverbState::lateUnfaded(const size_t offset, const size_t todo, const size_t base) +void ReverbState::lateUnfaded(const size_t offset, const size_t todo) { const al::span temps{mTempSamples}; const DelayLineI late_delay{mLate.Delay}; @@ -1379,12 +1376,13 @@ void ReverbState::lateUnfaded(const size_t offset, const size_t todo, const size */ mLate.VecAp.processUnfaded(temps, offset, mixX, mixY, todo); for(size_t j{0u};j < NUM_LINES;j++) - std::copy_n(temps[j].begin(), todo, mLateSamples[j].begin() + base); + std::copy_n(temps[j].begin(), todo, mLateSamples[j].begin()); /* Finally, scatter and bounce the results to refeed the feedback buffer. */ - VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, 0, temps, todo); + VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, temps, todo); } -void ReverbState::lateFaded(const size_t offset, const size_t todo, const ALfloat fade) +void ReverbState::lateFaded(const size_t offset, const size_t todo, const ALfloat fade, + const ALfloat fadeStep) { const al::span temps{mTempSamples}; const DelayLineI late_delay{mLate.Delay}; @@ -1398,12 +1396,12 @@ void ReverbState::lateFaded(const size_t offset, const size_t todo, const ALfloa { const ALfloat oldMidGain{mLate.T60[j].MidGain[0]}; const ALfloat midGain{mLate.T60[j].MidGain[1]}; - const ALfloat oldMidStep{-oldMidGain / FADE_SAMPLES}; - const ALfloat midStep{midGain / FADE_SAMPLES}; + const ALfloat oldMidStep{-oldMidGain * fadeStep}; + const ALfloat midStep{midGain * fadeStep}; const ALfloat oldDensityGain{mLate.DensityGain[0] * oldMidGain}; const ALfloat densityGain{mLate.DensityGain[1] * midGain}; - const ALfloat oldDensityStep{-oldDensityGain / FADE_SAMPLES}; - const ALfloat densityStep{densityGain / FADE_SAMPLES}; + const ALfloat oldDensityStep{-oldDensityGain * fadeStep}; + const ALfloat densityStep{densityGain * fadeStep}; size_t late_delay_tap0{offset - mLateDelayTap[j][0]}; size_t late_delay_tap1{offset - mLateDelayTap[j][1]}; size_t late_feedb_tap0{offset - mLate.Offset[j][0]}; @@ -1435,17 +1433,16 @@ void ReverbState::lateFaded(const size_t offset, const size_t todo, const ALfloa mLate.T60[j].process(temps[j].data(), todo); } - mLate.VecAp.processFaded(temps, offset, mixX, mixY, fade, todo); + mLate.VecAp.processFaded(temps, offset, mixX, mixY, fade, fadeStep, todo); for(size_t j{0u};j < NUM_LINES;j++) std::copy_n(temps[j].begin(), todo, mLateSamples[j].begin()); - VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, 0, temps, todo); + VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, temps, todo); } void ReverbState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) { size_t offset{mOffset}; - size_t fadeCount{mFadeCount}; ASSUME(samplesToDo > 0); @@ -1463,67 +1460,68 @@ void ReverbState::process(const size_t samplesToDo, const FloatBufferLine *RESTR } /* Process reverb for these samples. */ - for(size_t base{0};base < samplesToDo;) + if LIKELY(!mDoFading) { - /* Calculate the number of samples we can do this iteration. */ - size_t todo{minz(samplesToDo - base, minz(mMaxUpdate[0], mMaxUpdate[1]))}; - /* Some mixers require maintaining a 4-sample alignment, so ensure that - * if it's not the last iteration. - */ - if(base+todo < samplesToDo) todo &= ~3; - ASSUME(todo > 0); + for(size_t base{0};base < samplesToDo;) + { + /* Calculate the number of samples we can do this iteration. */ + size_t todo{minz(samplesToDo - base, mMaxUpdate[0])}; + /* Some mixers require maintaining a 4-sample alignment, so ensure + * that if it's not the last iteration. + */ + if(base+todo < samplesToDo) todo &= ~3; + ASSUME(todo > 0); + + /* Generate non-faded early reflections and late reverb. */ + earlyUnfaded(offset, todo); + lateUnfaded(offset, todo); - /* Process the samples for reverb. */ - size_t samples_done{0u}; - if UNLIKELY(fadeCount < FADE_SAMPLES) + /* Finally, mix early reflections and late reverb. */ + (this->*mMixOut)(samplesOut, samplesToDo-base, base, todo); + + offset += todo; + base += todo; + } + } + else + { + const float fadeStep{1.0f / static_cast(samplesToDo)}; + for(size_t base{0};base < samplesToDo;) { - /* If cross-fading, don't do more samples than there are to fade. */ - const size_t tofade{minz(todo, FADE_SAMPLES-fadeCount)}; - auto fade = static_cast(fadeCount); + size_t todo{minz(samplesToDo - base, minz(mMaxUpdate[0], mMaxUpdate[1]))}; + if(base+todo < samplesToDo) todo &= ~3; + ASSUME(todo > 0); /* Generate cross-faded early reflections and late reverb. */ - earlyFaded(offset, tofade, fade); - lateFaded(offset, tofade, fade); - - /* Step forward by amount faded. */ - samples_done += tofade; - offset += tofade; - fadeCount += tofade; - if(fadeCount == FADE_SAMPLES) - { - /* Update the cross-fading delay line taps. */ - for(size_t c{0u};c < NUM_LINES;c++) - { - mEarlyDelayTap[c][0] = mEarlyDelayTap[c][1]; - mEarlyDelayCoeff[c][0] = mEarlyDelayCoeff[c][1]; - mEarly.VecAp.Offset[c][0] = mEarly.VecAp.Offset[c][1]; - mEarly.Offset[c][0] = mEarly.Offset[c][1]; - mEarly.Coeff[c][0] = mEarly.Coeff[c][1]; - mLateDelayTap[c][0] = mLateDelayTap[c][1]; - mLate.VecAp.Offset[c][0] = mLate.VecAp.Offset[c][1]; - mLate.Offset[c][0] = mLate.Offset[c][1]; - mLate.T60[c].MidGain[0] = mLate.T60[c].MidGain[1]; - } - mLate.DensityGain[0] = mLate.DensityGain[1]; - mMaxUpdate[0] = mMaxUpdate[1]; - } + auto fadeCount = static_cast(base); + earlyFaded(offset, todo, fadeCount, fadeStep); + lateFaded(offset, todo, fadeCount, fadeStep); + + /* Finally, mix early reflections and late reverb. */ + (this->*mMixOut)(samplesOut, samplesToDo-base, base, todo); + + offset += todo; + base += todo; } - if LIKELY(samples_done < todo) + + /* Update the cross-fading delay line taps. */ + for(size_t c{0u};c < NUM_LINES;c++) { - /* Generate non-faded early reflections and late reverb. */ - const size_t remaining{todo - samples_done}; - earlyUnfaded(offset, remaining, samples_done); - lateUnfaded(offset, remaining, samples_done); - offset += remaining; + mEarlyDelayTap[c][0] = mEarlyDelayTap[c][1]; + mEarlyDelayCoeff[c][0] = mEarlyDelayCoeff[c][1]; + mEarly.VecAp.Offset[c][0] = mEarly.VecAp.Offset[c][1]; + mEarly.Offset[c][0] = mEarly.Offset[c][1]; + mEarly.Coeff[c][0] = mEarly.Coeff[c][1]; + mLateDelayTap[c][0] = mLateDelayTap[c][1]; + mLate.VecAp.Offset[c][0] = mLate.VecAp.Offset[c][1]; + mLate.Offset[c][0] = mLate.Offset[c][1]; + mLate.T60[c].MidGain[0] = mLate.T60[c].MidGain[1]; } - - /* Finally, mix early reflections and late reverb. */ - (this->*mMixOut)(samplesOut, samplesToDo-base, base, todo); - - base += todo; + mLate.DensityGain[0] = mLate.DensityGain[1]; + mMaxUpdate[0] = mMaxUpdate[1]; + mDoFading = false; } mOffset = offset; - mFadeCount = fadeCount; } -- cgit v1.2.3 From 88a8bf903b08cd93ea7028a4c726f39e4cde7c79 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 25 Aug 2019 15:36:40 -0700 Subject: Use size_t for the post-process sample length --- alc/alcmain.h | 12 ++++++------ alc/alu.cpp | 9 ++++----- alc/bformatdec.cpp | 6 +++--- alc/bformatdec.h | 2 +- alc/bs2b.cpp | 14 +++++++------- alc/bs2b.h | 2 +- alc/uhjfilter.cpp | 17 +++++++++-------- alc/uhjfilter.h | 2 +- 8 files changed, 32 insertions(+), 32 deletions(-) diff --git a/alc/alcmain.h b/alc/alcmain.h index 910e3279..6b6a8de3 100644 --- a/alc/alcmain.h +++ b/alc/alcmain.h @@ -303,7 +303,7 @@ struct ALCdevice : public al::intrusive_ref { /* Stereo-to-binaural filter */ std::unique_ptr Bs2b; - using PostProc = void(ALCdevice::*)(const ALsizei SamplesToDo); + using PostProc = void(ALCdevice::*)(const size_t SamplesToDo); PostProc PostProcess{nullptr}; std::unique_ptr Stablizer; @@ -344,12 +344,12 @@ struct ALCdevice : public al::intrusive_ref { ALsizei channelsFromFmt() const noexcept { return ChannelsFromDevFmt(FmtChans, mAmbiOrder); } ALsizei frameSizeFromFmt() const noexcept { return bytesFromFmt() * channelsFromFmt(); } - void ProcessHrtf(const ALsizei SamplesToDo); - void ProcessAmbiDec(const ALsizei SamplesToDo); - void ProcessUhj(const ALsizei SamplesToDo); - void ProcessBs2b(const ALsizei SamplesToDo); + void ProcessHrtf(const size_t SamplesToDo); + void ProcessAmbiDec(const size_t SamplesToDo); + void ProcessUhj(const size_t SamplesToDo); + void ProcessBs2b(const size_t SamplesToDo); - inline void postProcess(const ALsizei SamplesToDo) + inline void postProcess(const size_t SamplesToDo) { if LIKELY(PostProcess) (this->*PostProcess)(SamplesToDo); } DEF_NEWDEL(ALCdevice) diff --git a/alc/alu.cpp b/alc/alu.cpp index a7d7cd70..c961f5d5 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -152,24 +152,23 @@ void aluInit(void) } -void ALCdevice::ProcessHrtf(const ALsizei SamplesToDo) +void ALCdevice::ProcessHrtf(const size_t SamplesToDo) { /* HRTF is stereo output only. */ const int lidx{RealOut.ChannelIndex[FrontLeft]}; const int ridx{RealOut.ChannelIndex[FrontRight]}; ASSUME(lidx >= 0 && ridx >= 0); - ASSUME(SamplesToDo >= 0); MixDirectHrtf(RealOut.Buffer[lidx], RealOut.Buffer[ridx], Dry.Buffer, HrtfAccumData, mHrtfState.get(), SamplesToDo); } -void ALCdevice::ProcessAmbiDec(const ALsizei SamplesToDo) +void ALCdevice::ProcessAmbiDec(const size_t SamplesToDo) { AmbiDecoder->process(RealOut.Buffer, Dry.Buffer.data(), SamplesToDo); } -void ALCdevice::ProcessUhj(const ALsizei SamplesToDo) +void ALCdevice::ProcessUhj(const size_t SamplesToDo) { /* UHJ is stereo output only. */ const int lidx{RealOut.ChannelIndex[FrontLeft]}; @@ -181,7 +180,7 @@ void ALCdevice::ProcessUhj(const ALsizei SamplesToDo) SamplesToDo); } -void ALCdevice::ProcessBs2b(const ALsizei SamplesToDo) +void ALCdevice::ProcessBs2b(const size_t SamplesToDo) { /* First, decode the ambisonic mix to the "real" output. */ AmbiDecoder->process(RealOut.Buffer, Dry.Buffer.data(), SamplesToDo); diff --git a/alc/bformatdec.cpp b/alc/bformatdec.cpp index 7d681bc6..c2137b33 100644 --- a/alc/bformatdec.cpp +++ b/alc/bformatdec.cpp @@ -146,7 +146,7 @@ BFormatDec::BFormatDec(const ALuint inchans, const ALsizei chancount, void BFormatDec::process(const al::span OutBuffer, - const FloatBufferLine *InSamples, const ALsizei SamplesToDo) + const FloatBufferLine *InSamples, const size_t SamplesToDo) { ASSUME(SamplesToDo > 0); @@ -162,7 +162,7 @@ void BFormatDec::process(const al::span OutBuffer, { if LIKELY(enabled&1) { - const al::span outspan{outbuf.data(), outbuf.data()+SamplesToDo}; + const al::span outspan{outbuf.data(), SamplesToDo}; MixRowSamples(outspan, {(*mixmtx)[sHFBand], mNumChannels}, mSamplesHF->data(), mSamplesHF->size()); MixRowSamples(outspan, {(*mixmtx)[sLFBand], mNumChannels}, mSamplesLF->data(), @@ -179,7 +179,7 @@ void BFormatDec::process(const al::span OutBuffer, for(FloatBufferLine &outbuf : OutBuffer) { if LIKELY(enabled&1) - MixRowSamples({outbuf.data(), outbuf.data()+SamplesToDo}, {*mixmtx, mNumChannels}, + MixRowSamples({outbuf.data(), SamplesToDo}, {*mixmtx, mNumChannels}, InSamples->data(), InSamples->size()); ++mixmtx; enabled >>= 1; diff --git a/alc/bformatdec.h b/alc/bformatdec.h index dbde90c8..98cbb022 100644 --- a/alc/bformatdec.h +++ b/alc/bformatdec.h @@ -50,7 +50,7 @@ public: /* Decodes the ambisonic input to the given output channels. */ void process(const al::span OutBuffer, const FloatBufferLine *InSamples, - const ALsizei SamplesToDo); + const size_t SamplesToDo); /* Retrieves per-order HF scaling factors for "upsampling" ambisonic data. */ static std::array GetHFOrderScales(const ALsizei in_order, diff --git a/alc/bs2b.cpp b/alc/bs2b.cpp index 71249d4a..fb75188c 100644 --- a/alc/bs2b.cpp +++ b/alc/bs2b.cpp @@ -130,7 +130,7 @@ void bs2b_clear(struct bs2b *bs2b) std::fill(std::begin(bs2b->history), std::end(bs2b->history), bs2b::t_last_sample{}); } /* bs2b_clear */ -void bs2b_cross_feed(struct bs2b *bs2b, float *Left, float *Right, int SamplesToDo) +void bs2b_cross_feed(struct bs2b *bs2b, float *Left, float *Right, size_t SamplesToDo) { const float a0_lo{bs2b->a0_lo}; const float b1_lo{bs2b->b1_lo}; @@ -140,14 +140,14 @@ void bs2b_cross_feed(struct bs2b *bs2b, float *Left, float *Right, int SamplesTo float lsamples[128][2]; float rsamples[128][2]; - for(int base{0};base < SamplesToDo;) + for(size_t base{0};base < SamplesToDo;) { - const int todo{std::min(128, SamplesToDo-base)}; + const size_t todo{std::min(128, SamplesToDo-base)}; /* Process left input */ float z_lo{bs2b->history[0].lo}; float z_hi{bs2b->history[0].hi}; - for(int i{0};i < todo;i++) + for(size_t i{0};i < todo;i++) { lsamples[i][0] = a0_lo*Left[i] + z_lo; z_lo = b1_lo*lsamples[i][0]; @@ -161,7 +161,7 @@ void bs2b_cross_feed(struct bs2b *bs2b, float *Left, float *Right, int SamplesTo /* Process right input */ z_lo = bs2b->history[1].lo; z_hi = bs2b->history[1].hi; - for(int i{0};i < todo;i++) + for(size_t i{0};i < todo;i++) { rsamples[i][0] = a0_lo*Right[i] + z_lo; z_lo = b1_lo*rsamples[i][0]; @@ -173,9 +173,9 @@ void bs2b_cross_feed(struct bs2b *bs2b, float *Left, float *Right, int SamplesTo bs2b->history[1].hi = z_hi; /* Crossfeed */ - for(int i{0};i < todo;i++) + for(size_t i{0};i < todo;i++) *(Left++) = lsamples[i][1] + rsamples[i][0]; - for(int i{0};i < todo;i++) + for(size_t i{0};i < todo;i++) *(Right++) = rsamples[i][1] + lsamples[i][0]; base += todo; diff --git a/alc/bs2b.h b/alc/bs2b.h index d9bcc172..df717cd4 100644 --- a/alc/bs2b.h +++ b/alc/bs2b.h @@ -84,6 +84,6 @@ int bs2b_get_srate(bs2b *bs2b); /* Clear buffer */ void bs2b_clear(bs2b *bs2b); -void bs2b_cross_feed(bs2b *bs2b, float *Left, float *Right, int SamplesToDo); +void bs2b_cross_feed(bs2b *bs2b, float *Left, float *Right, size_t SamplesToDo); #endif /* BS2B_H */ diff --git a/alc/uhjfilter.cpp b/alc/uhjfilter.cpp index 7f3cd069..222f519a 100644 --- a/alc/uhjfilter.cpp +++ b/alc/uhjfilter.cpp @@ -64,7 +64,8 @@ void allpass_process(AllPassState *state, ALfloat *dst, const ALfloat *src, cons * know which is the intended result. */ -void Uhj2Encoder::encode(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, FloatBufferLine *InSamples, const ALsizei SamplesToDo) +void Uhj2Encoder::encode(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + FloatBufferLine *InSamples, const size_t SamplesToDo) { alignas(16) ALfloat D[MAX_UPDATE_SAMPLES], S[MAX_UPDATE_SAMPLES]; alignas(16) ALfloat temp[MAX_UPDATE_SAMPLES]; @@ -74,9 +75,9 @@ void Uhj2Encoder::encode(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, Fl auto winput = InSamples[0].cbegin(); auto xinput = InSamples[1].cbegin(); auto yinput = InSamples[2].cbegin(); - for(ALsizei base{0};base < SamplesToDo;) + for(size_t base{0};base < SamplesToDo;) { - const ALsizei todo{mini(SamplesToDo - base, MAX_UPDATE_SAMPLES)}; + const size_t todo{minz(SamplesToDo - base, MAX_UPDATE_SAMPLES)}; ASSUME(todo > 0); /* D = 0.6554516*Y */ @@ -91,7 +92,7 @@ void Uhj2Encoder::encode(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, Fl * output sample. */ D[0] = mLastY; - for(ALsizei i{1};i < todo;i++) + for(size_t i{1};i < todo;i++) D[i] = temp[i-1]; mLastY = temp[todo-1]; @@ -103,7 +104,7 @@ void Uhj2Encoder::encode(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, Fl allpass_process(&mFilter2_WX[1], temp, temp, Filter2CoeffSqr[1], todo); allpass_process(&mFilter2_WX[2], temp, temp, Filter2CoeffSqr[2], todo); allpass_process(&mFilter2_WX[3], temp, temp, Filter2CoeffSqr[3], todo); - for(ALsizei i{0};i < todo;i++) + for(size_t i{0};i < todo;i++) D[i] += temp[i]; /* S = 0.9396926*W + 0.1855740*X */ @@ -115,17 +116,17 @@ void Uhj2Encoder::encode(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, Fl allpass_process(&mFilter1_WX[2], temp, temp, Filter1CoeffSqr[2], todo); allpass_process(&mFilter1_WX[3], temp, temp, Filter1CoeffSqr[3], todo); S[0] = mLastWX; - for(ALsizei i{1};i < todo;i++) + for(size_t i{1};i < todo;i++) S[i] = temp[i-1]; mLastWX = temp[todo-1]; /* Left = (S + D)/2.0 */ ALfloat *RESTRICT left = al::assume_aligned<16>(LeftOut.data()+base); - for(ALsizei i{0};i < todo;i++) + for(size_t i{0};i < todo;i++) left[i] += (S[i] + D[i]) * 0.5f; /* Right = (S - D)/2.0 */ ALfloat *RESTRICT right = al::assume_aligned<16>(RightOut.data()+base); - for(ALsizei i{0};i < todo;i++) + for(size_t i{0};i < todo;i++) right[i] += (S[i] - D[i]) * 0.5f; winput += todo; diff --git a/alc/uhjfilter.h b/alc/uhjfilter.h index 53e4f89e..88d30351 100644 --- a/alc/uhjfilter.h +++ b/alc/uhjfilter.h @@ -46,7 +46,7 @@ struct Uhj2Encoder { * signal. The input must use FuMa channel ordering and scaling. */ void encode(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, FloatBufferLine *InSamples, - const ALsizei SamplesToDo); + const size_t SamplesToDo); DEF_NEWDEL(Uhj2Encoder) }; -- cgit v1.2.3 From b93098f7df73b877d40303ce3d9e4d9776a9c245 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 25 Aug 2019 17:24:53 -0700 Subject: Use unsigned sample counts for the compressor/limiter --- alc/mastering.cpp | 89 ++++++++++++++++++++++--------------------------------- alc/mastering.h | 4 +-- 2 files changed, 37 insertions(+), 56 deletions(-) diff --git a/alc/mastering.cpp b/alc/mastering.cpp index fa767e83..2f575f35 100644 --- a/alc/mastering.cpp +++ b/alc/mastering.cpp @@ -24,10 +24,10 @@ static_assert((BUFFERSIZE & (BUFFERSIZE-1)) == 0, "BUFFERSIZE is not a power of struct SlidingHold { alignas(16) ALfloat mValues[BUFFERSIZE]; - ALsizei mExpiries[BUFFERSIZE]; - ALsizei mLowerIndex; - ALsizei mUpperIndex; - ALsizei mLength; + ALuint mExpiries[BUFFERSIZE]; + ALuint mLowerIndex; + ALuint mUpperIndex; + ALuint mLength; }; @@ -42,17 +42,14 @@ using namespace std::placeholders; * * http://www.richardhartersworld.com/cri/2001/slidingmin.html */ -ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALfloat in) +ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALuint i, const ALfloat in) { static constexpr ALsizei mask{BUFFERSIZE - 1}; - const ALsizei length{Hold->mLength}; + const ALuint length{Hold->mLength}; ALfloat (&values)[BUFFERSIZE] = Hold->mValues; - ALsizei (&expiries)[BUFFERSIZE] = Hold->mExpiries; - ALsizei lowerIndex{Hold->mLowerIndex}; - ALsizei upperIndex{Hold->mUpperIndex}; - - ASSUME(upperIndex >= 0); - ASSUME(lowerIndex >= 0); + ALuint (&expiries)[BUFFERSIZE] = Hold->mExpiries; + ALuint lowerIndex{Hold->mLowerIndex}; + ALuint upperIndex{Hold->mUpperIndex}; if(i >= expiries[upperIndex]) upperIndex = (upperIndex + 1) & mask; @@ -85,36 +82,31 @@ ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALfloat in) return values[upperIndex]; } -void ShiftSlidingHold(SlidingHold *Hold, const ALsizei n) +void ShiftSlidingHold(SlidingHold *Hold, const ALuint n) { - ASSUME(Hold->mUpperIndex >= 0); - ASSUME(Hold->mLowerIndex >= 0); - auto exp_begin = std::begin(Hold->mExpiries) + Hold->mUpperIndex; auto exp_last = std::begin(Hold->mExpiries) + Hold->mLowerIndex; - if(exp_last < exp_begin) + if(exp_last-exp_begin < 0) { std::transform(exp_begin, std::end(Hold->mExpiries), exp_begin, - std::bind(std::minus{}, _1, n)); + std::bind(std::minus{}, _1, n)); exp_begin = std::begin(Hold->mExpiries); } - std::transform(exp_begin, exp_last+1, exp_begin, std::bind(std::minus{}, _1, n)); + std::transform(exp_begin, exp_last+1, exp_begin, std::bind(std::minus{}, _1, n)); } /* Multichannel compression is linked via the absolute maximum of all * channels. */ -void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, const FloatBufferLine *OutBuffer) +void LinkChannels(Compressor *Comp, const ALuint SamplesToDo, const FloatBufferLine *OutBuffer) { - const ALsizei index{Comp->mLookAhead}; const ALuint numChans{Comp->mNumChans}; ASSUME(SamplesToDo > 0); ASSUME(numChans > 0); - ASSUME(index >= 0); - auto side_begin = std::begin(Comp->mSideChain) + index; + auto side_begin = std::begin(Comp->mSideChain) + Comp->mLookAhead; std::fill(side_begin, side_begin+SamplesToDo, 0.0f); auto fill_max = [SamplesToDo,side_begin](const FloatBufferLine &input) -> void @@ -131,15 +123,13 @@ void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, const FloatBuffer * it uses an instantaneous squared peak detector and a squared RMS detector * both with 200ms release times. */ -static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo) +static void CrestDetector(Compressor *Comp, const ALuint SamplesToDo) { const ALfloat a_crest{Comp->mCrestCoeff}; - const ALsizei index{Comp->mLookAhead}; ALfloat y2_peak{Comp->mLastPeakSq}; ALfloat y2_rms{Comp->mLastRmsSq}; ASSUME(SamplesToDo > 0); - ASSUME(index >= 0); auto calc_crest = [&y2_rms,&y2_peak,a_crest](const ALfloat x_abs) noexcept -> ALfloat { @@ -149,7 +139,7 @@ static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo) y2_rms = lerp(x2, y2_rms, a_crest); return y2_peak / y2_rms; }; - auto side_begin = std::begin(Comp->mSideChain) + index; + auto side_begin = std::begin(Comp->mSideChain) + Comp->mLookAhead; std::transform(side_begin, side_begin+SamplesToDo, std::begin(Comp->mCrestFactor), calc_crest); Comp->mLastPeakSq = y2_peak; @@ -160,15 +150,12 @@ static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo) * value of the incoming signal) and performs most of its operations in the * log domain. */ -void PeakDetector(Compressor *Comp, const ALsizei SamplesToDo) +void PeakDetector(Compressor *Comp, const ALuint SamplesToDo) { - const ALsizei index{Comp->mLookAhead}; - ASSUME(SamplesToDo > 0); - ASSUME(index >= 0); /* Clamp the minimum amplitude to near-zero and convert to logarithm. */ - auto side_begin = std::begin(Comp->mSideChain) + index; + auto side_begin = std::begin(Comp->mSideChain) + Comp->mLookAhead; std::transform(side_begin, side_begin+SamplesToDo, side_begin, std::bind(static_cast(std::log), std::bind(maxf, 0.000001f, _1))); } @@ -177,21 +164,18 @@ void PeakDetector(Compressor *Comp, const ALsizei SamplesToDo) * solidly detect fast transients. This is best used when operating as a * limiter. */ -void PeakHoldDetector(Compressor *Comp, const ALsizei SamplesToDo) +void PeakHoldDetector(Compressor *Comp, const ALuint SamplesToDo) { - const ALsizei index{Comp->mLookAhead}; - ASSUME(SamplesToDo > 0); - ASSUME(index >= 0); SlidingHold *hold{Comp->mHold}; - ALsizei i{0}; + ALuint i{0}; auto detect_peak = [&i,hold](const ALfloat x_abs) -> ALfloat { const ALfloat x_G{std::log(maxf(0.000001f, x_abs))}; return UpdateSlidingHold(hold, i++, x_G); }; - auto side_begin = std::begin(Comp->mSideChain) + index; + auto side_begin = std::begin(Comp->mSideChain) + Comp->mLookAhead; std::transform(side_begin, side_begin+SamplesToDo, side_begin, detect_peak); ShiftSlidingHold(hold, SamplesToDo); @@ -202,22 +186,21 @@ void PeakHoldDetector(Compressor *Comp, const ALsizei SamplesToDo) * to knee width, attack/release times, make-up/post gain, and clipping * reduction. */ -void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) +void GainCompressor(Compressor *Comp, const ALuint SamplesToDo) { const bool autoKnee{Comp->mAuto.Knee}; const bool autoAttack{Comp->mAuto.Attack}; const bool autoRelease{Comp->mAuto.Release}; const bool autoPostGain{Comp->mAuto.PostGain}; const bool autoDeclip{Comp->mAuto.Declip}; - const ALsizei lookAhead{Comp->mLookAhead}; + const ALuint lookAhead{Comp->mLookAhead}; const ALfloat threshold{Comp->mThreshold}; const ALfloat slope{Comp->mSlope}; const ALfloat attack{Comp->mAttack}; const ALfloat release{Comp->mRelease}; const ALfloat c_est{Comp->mGainEstimate}; const ALfloat a_adp{Comp->mAdaptCoeff}; - const ALfloat (&crestFactor)[BUFFERSIZE] = Comp->mCrestFactor; - ALfloat (&sideChain)[BUFFERSIZE*2] = Comp->mSideChain; + const ALfloat *crestFactor{Comp->mCrestFactor}; ALfloat postGain{Comp->mPostGain}; ALfloat knee{Comp->mKnee}; ALfloat t_att{attack}; @@ -229,9 +212,8 @@ void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) ALfloat c_dev{Comp->mLastGainDev}; ASSUME(SamplesToDo > 0); - ASSUME(lookAhead >= 0); - for(ALsizei i{0};i < SamplesToDo;i++) + for(ALfloat &sideChain : al::span{Comp->mSideChain, SamplesToDo}) { if(autoKnee) knee = maxf(0.0f, 2.5f * (c_dev + c_est)); @@ -240,14 +222,14 @@ void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) /* This is the gain computer. It applies a static compression curve * to the control signal. */ - const ALfloat x_over{sideChain[lookAhead+i] - threshold}; + const ALfloat x_over{std::addressof(sideChain)[lookAhead] - threshold}; const ALfloat y_G{ (x_over <= -knee_h) ? 0.0f : (std::fabs(x_over) < knee_h) ? (x_over + knee_h) * (x_over + knee_h) / (2.0f * knee) : x_over }; - const ALfloat y2_crest{crestFactor[i]}; + const ALfloat y2_crest{*(crestFactor++)}; if(autoAttack) { t_att = 2.0f*attack/y2_crest; @@ -283,12 +265,12 @@ void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) * same output level. */ if(autoDeclip) - c_dev = maxf(c_dev, sideChain[i] - y_L - threshold - c_est); + c_dev = maxf(c_dev, sideChain - y_L - threshold - c_est); postGain = -(c_dev + c_est); } - sideChain[i] = std::exp(postGain - y_L); + sideChain = std::exp(postGain - y_L); } Comp->mLastRelease = y_1; @@ -301,10 +283,10 @@ void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) * reaching the offending impulse. This is best used when operating as a * limiter. */ -void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, FloatBufferLine *OutBuffer) +void SignalDelay(Compressor *Comp, const ALuint SamplesToDo, FloatBufferLine *OutBuffer) { const ALuint numChans{Comp->mNumChans}; - const ALsizei lookAhead{Comp->mLookAhead}; + const ALuint lookAhead{Comp->mLookAhead}; ASSUME(SamplesToDo > 0); ASSUME(numChans > 0); @@ -362,9 +344,9 @@ std::unique_ptr CompressorInit(const ALuint NumChans, const ALuint S const ALfloat ThresholdDb, const ALfloat Ratio, const ALfloat KneeDb, const ALfloat AttackTime, const ALfloat ReleaseTime) { - const auto lookAhead = static_cast( + const auto lookAhead = static_cast( clampf(std::round(LookAheadTime*SampleRate), 0.0f, BUFFERSIZE-1)); - const auto hold = static_cast( + const auto hold = static_cast( clampf(std::round(HoldTime*SampleRate), 0.0f, BUFFERSIZE-1)); size_t size{sizeof(Compressor)}; @@ -437,7 +419,7 @@ Compressor::~Compressor() } -void Compressor::process(const ALsizei SamplesToDo, FloatBufferLine *OutBuffer) +void Compressor::process(const ALuint SamplesToDo, FloatBufferLine *OutBuffer) { const ALuint numChans{mNumChans}; @@ -481,7 +463,6 @@ void Compressor::process(const ALsizei SamplesToDo, FloatBufferLine *OutBuffer) }; std::for_each(OutBuffer, OutBuffer+numChans, apply_comp); - ASSUME(mLookAhead >= 0); auto side_begin = std::begin(mSideChain) + SamplesToDo; std::copy(side_begin, side_begin+mLookAhead, std::begin(mSideChain)); } diff --git a/alc/mastering.h b/alc/mastering.h index 5be769ac..03cd21c0 100644 --- a/alc/mastering.h +++ b/alc/mastering.h @@ -34,7 +34,7 @@ struct Compressor { bool Declip : 1; } mAuto{}; - ALsizei mLookAhead{0}; + ALuint mLookAhead{0}; ALfloat mPreGain{0.0f}; ALfloat mPostGain{0.0f}; @@ -64,7 +64,7 @@ struct Compressor { ~Compressor(); - void process(const ALsizei SamplesToDo, FloatBufferLine *OutBuffer); + void process(const ALuint SamplesToDo, FloatBufferLine *OutBuffer); ALsizei getLookAhead() const noexcept { return mLookAhead; } DEF_PLACE_NEWDEL() -- cgit v1.2.3 From 164626a7be1cd0a9b92d34b9bb7f5c891fe57fae Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 25 Aug 2019 17:54:36 -0700 Subject: Pass unsigned sample count to aluMixData --- alc/alc.cpp | 2 +- alc/alcmain.h | 2 +- alc/alu.cpp | 22 +++++++++++----------- alc/alu.h | 2 +- alc/panning.cpp | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index 9be224d5..a69a8e7c 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -4074,7 +4074,7 @@ START_API_FUNC alcSetError(dev.get(), ALC_INVALID_VALUE); else { - BackendLockGuard _{*device->Backend}; + BackendLockGuard _{*dev->Backend}; aluMixData(dev.get(), buffer, samples); } } diff --git a/alc/alcmain.h b/alc/alcmain.h index 6b6a8de3..556268ce 100644 --- a/alc/alcmain.h +++ b/alc/alcmain.h @@ -113,7 +113,7 @@ class DistanceComp { public: struct DistData { ALfloat Gain{1.0f}; - ALsizei Length{0}; /* Valid range is [0...MAX_DELAY_LENGTH). */ + ALuint Length{0u}; /* Valid range is [0...MAX_DELAY_LENGTH). */ ALfloat *Buffer{nullptr}; }; diff --git a/alc/alu.cpp b/alc/alu.cpp index c961f5d5..ba42c21f 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -1343,7 +1343,7 @@ void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray &slots, IncrementRef(ctx->mUpdateCount); } -void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) +void ProcessContext(ALCcontext *ctx, const ALuint SamplesToDo) { ASSUME(SamplesToDo > 0); @@ -1424,7 +1424,7 @@ void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo) void ApplyStablizer(FrontStablizer *Stablizer, const al::span Buffer, - const ALuint lidx, const ALuint ridx, const ALuint cidx, const ALsizei SamplesToDo) + const ALuint lidx, const ALuint ridx, const ALuint cidx, const ALuint SamplesToDo) { ASSUME(SamplesToDo > 0); @@ -1439,7 +1439,7 @@ void ApplyStablizer(FrontStablizer *Stablizer, const al::span B auto &DelayBuf = Stablizer->DelayBuf[i]; auto buffer_end = Buffer[i].begin() + SamplesToDo; - if LIKELY(SamplesToDo >= ALsizei{FrontStablizer::DelayLength}) + if LIKELY(SamplesToDo >= ALuint{FrontStablizer::DelayLength}) { auto delay_end = std::rotate(Buffer[i].begin(), buffer_end - FrontStablizer::DelayLength, buffer_end); @@ -1489,7 +1489,7 @@ void ApplyStablizer(FrontStablizer *Stablizer, const al::span B apply_splitter(Buffer[lidx], Stablizer->DelayBuf[lidx], Stablizer->LFilter, lsplit); apply_splitter(Buffer[ridx], Stablizer->DelayBuf[ridx], Stablizer->RFilter, rsplit); - for(ALsizei i{0};i < SamplesToDo;i++) + for(ALuint i{0};i < SamplesToDo;i++) { ALfloat lfsum{lsplit[0][i] + rsplit[0][i]}; ALfloat hfsum{lsplit[1][i] + rsplit[1][i]}; @@ -1515,7 +1515,7 @@ void ApplyStablizer(FrontStablizer *Stablizer, const al::span B } } -void ApplyDistanceComp(const al::span Samples, const ALsizei SamplesToDo, +void ApplyDistanceComp(const al::span Samples, const ALuint SamplesToDo, const DistanceComp::DistData *distcomp) { ASSUME(SamplesToDo > 0); @@ -1523,7 +1523,7 @@ void ApplyDistanceComp(const al::span Samples, const ALsizei Sa for(auto &chanbuffer : Samples) { const ALfloat gain{distcomp->Gain}; - const ALsizei base{distcomp->Length}; + const ALuint base{distcomp->Length}; ALfloat *distbuf{al::assume_aligned<16>(distcomp->Buffer)}; ++distcomp; @@ -1547,7 +1547,7 @@ void ApplyDistanceComp(const al::span Samples, const ALsizei Sa } void ApplyDither(const al::span Samples, ALuint *dither_seed, - const ALfloat quant_scale, const ALsizei SamplesToDo) + const ALfloat quant_scale, const ALuint SamplesToDo) { /* Dithering. Generate whitenoise (uniform distribution of random values * between -1 and +1) and add it to the sample values, after scaling up to @@ -1605,7 +1605,7 @@ template<> inline ALubyte SampleConv(ALfloat val) noexcept template void Write(const al::span InBuffer, ALvoid *OutBuffer, const size_t Offset, - const ALsizei SamplesToDo) + const ALuint SamplesToDo) { using SampleType = typename DevFmtTypeTraits::Type; @@ -1629,12 +1629,12 @@ void Write(const al::span InBuffer, ALvoid *OutBuffer, co } // namespace -void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) +void aluMixData(ALCdevice *device, ALvoid *OutBuffer, const ALuint NumSamples) { FPUCtl mixer_mode{}; - for(ALsizei SamplesDone{0};SamplesDone < NumSamples;) + for(ALuint SamplesDone{0u};SamplesDone < NumSamples;) { - const ALsizei SamplesToDo{mini(NumSamples-SamplesDone, BUFFERSIZE)}; + const ALuint SamplesToDo{minu(NumSamples-SamplesDone, BUFFERSIZE)}; /* Clear main mixing buffers. */ std::for_each(device->MixBuffer.begin(), device->MixBuffer.end(), diff --git a/alc/alu.h b/alc/alu.h index c4848e3e..df20ea4a 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -446,7 +446,7 @@ inline std::array GetAmbiIdentityRow(size_t i) noexce void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCcontext *Context, const ALuint SamplesToDo); -void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples); +void aluMixData(ALCdevice *device, ALvoid *OutBuffer, const ALuint NumSamples); /* Caller must lock the device state, and the mixer must not be running. */ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) DECL_FORMAT(printf, 2, 3); diff --git a/alc/panning.cpp b/alc/panning.cpp index d946d1fc..5143b1ea 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -318,9 +318,9 @@ void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei ( delay = ALfloat{MAX_DELAY_LENGTH-1}; } - ChanDelay[chan].Length = static_cast(delay); + ChanDelay[chan].Length = static_cast(delay); ChanDelay[chan].Gain = speaker.Distance / maxdist; - TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan, + TRACE("Channel %u \"%s\" distance compensation: %u samples, %f gain\n", chan, speaker.Name.c_str(), ChanDelay[chan].Length, ChanDelay[chan].Gain); /* Round up to the next 4th sample, so each channel buffer starts -- cgit v1.2.3 From 4e72d7b3eccfb13055c55d2ccac8bf0db3be9ecb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 25 Aug 2019 18:09:14 -0700 Subject: Use al::byte for a couple more buffers --- alc/backends/alsa.cpp | 10 +++++----- alc/backends/wave.cpp | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index 64f9cf46..766ff167 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -403,7 +403,7 @@ struct AlsaPlayback final : public BackendBase { snd_pcm_t *mPcmHandle{nullptr}; - al::vector mBuffer; + al::vector mBuffer; std::atomic mKillNow{true}; std::thread mThread; @@ -550,7 +550,7 @@ int AlsaPlayback::mixerNoMMapProc() } lock(); - char *WritePtr{mBuffer.data()}; + al::byte *WritePtr{mBuffer.data()}; avail = snd_pcm_bytes_to_frames(mPcmHandle, mBuffer.size()); aluMixData(mDevice, WritePtr, avail); while(avail > 0) @@ -874,7 +874,7 @@ struct AlsaCapture final : public BackendBase { snd_pcm_t *mPcmHandle{nullptr}; - al::vector mBuffer; + al::vector mBuffer; bool mDoCapture{false}; RingBufferPtr mRing{nullptr}; @@ -1044,7 +1044,7 @@ void AlsaCapture::stop() { /* The ring buffer implicitly captures when checking availability. * Direct access needs to explicitly capture it into temp storage. */ - al::vector temp(snd_pcm_frames_to_bytes(mPcmHandle, avail)); + auto temp = al::vector(snd_pcm_frames_to_bytes(mPcmHandle, avail)); captureSamples(temp.data(), avail); mBuffer = std::move(temp); } @@ -1106,7 +1106,7 @@ ALCenum AlsaCapture::captureSamples(ALCvoid *buffer, ALCuint samples) continue; } - buffer = static_cast(buffer) + amt; + buffer = static_cast(buffer) + amt; samples -= amt; } if(samples > 0) diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp index aa4130af..b16f711b 100644 --- a/alc/backends/wave.cpp +++ b/alc/backends/wave.cpp @@ -35,6 +35,7 @@ #include "AL/al.h" +#include "albyte.h" #include "alcmain.h" #include "alconfig.h" #include "almalloc.h" @@ -103,7 +104,7 @@ struct WaveBackend final : public BackendBase { FILE *mFile{nullptr}; long mDataStart{-1}; - al::vector mBuffer; + al::vector mBuffer; std::atomic mKillNow{true}; std::thread mThread; @@ -151,13 +152,12 @@ int WaveBackend::mixerProc() if(!IS_LITTLE_ENDIAN) { const ALsizei bytesize{mDevice->bytesFromFmt()}; - ALsizei i; if(bytesize == 2) { ALushort *samples = reinterpret_cast(mBuffer.data()); - const auto len = static_cast(mBuffer.size() / 2); - for(i = 0;i < len;i++) + const size_t len{mBuffer.size() / 2}; + for(size_t i{0};i < len;i++) { ALushort samp = samples[i]; samples[i] = (samp>>8) | (samp<<8); @@ -166,8 +166,8 @@ int WaveBackend::mixerProc() else if(bytesize == 4) { ALuint *samples = reinterpret_cast(mBuffer.data()); - const auto len = static_cast(mBuffer.size() / 4); - for(i = 0;i < len;i++) + const size_t len{mBuffer.size() / 4}; + for(size_t i{0};i < len;i++) { ALuint samp = samples[i]; samples[i] = (samp>>24) | ((samp>>8)&0x0000ff00) | -- cgit v1.2.3 From 12e6dc0cced98d8d4379dbdaa922381920d32df2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 25 Aug 2019 21:30:32 -0700 Subject: Fix a function's sample count type --- alc/uhjfilter.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/alc/uhjfilter.cpp b/alc/uhjfilter.cpp index 222f519a..7d01a91f 100644 --- a/alc/uhjfilter.cpp +++ b/alc/uhjfilter.cpp @@ -26,13 +26,14 @@ constexpr ALfloat Filter2CoeffSqr[4] = { 0.161758498368f, 0.733028932341f, 0.945349700329f, 0.990599156685f }; -void allpass_process(AllPassState *state, ALfloat *dst, const ALfloat *src, const ALfloat aa, ALsizei todo) +void allpass_process(AllPassState *state, ALfloat *dst, const ALfloat *src, const ALfloat aa, + const size_t todo) { ALfloat z1{state->z[0]}; ALfloat z2{state->z[1]}; - auto proc_sample = [aa,&z1,&z2](ALfloat input) noexcept -> ALfloat + auto proc_sample = [aa,&z1,&z2](const ALfloat input) noexcept -> ALfloat { - ALfloat output = input*aa + z1; + const ALfloat output{input*aa + z1}; z1 = z2; z2 = output*aa - input; return output; }; -- cgit v1.2.3 From 7dbf69afa270417c28605a265cc2ec0a7c4fc939 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Aug 2019 09:16:20 -0700 Subject: Use a span for effect state input --- alc/alu.cpp | 3 +-- alc/effects/autowah.cpp | 23 ++++++++++++----------- alc/effects/base.h | 2 +- alc/effects/chorus.cpp | 4 ++-- alc/effects/compressor.cpp | 12 ++++++------ alc/effects/dedicated.cpp | 4 ++-- alc/effects/distortion.cpp | 4 ++-- alc/effects/echo.cpp | 4 ++-- alc/effects/equalizer.cpp | 23 ++++++++++++----------- alc/effects/fshifter.cpp | 4 ++-- alc/effects/modulator.cpp | 13 +++++++------ alc/effects/null.cpp | 4 ++-- alc/effects/pshifter.cpp | 4 ++-- alc/effects/reverb.cpp | 7 ++++--- alc/effects/vmorpher.cpp | 31 ++++++++++++++++--------------- 15 files changed, 73 insertions(+), 69 deletions(-) diff --git a/alc/alu.cpp b/alc/alu.cpp index ba42c21f..7f3f286b 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -1416,8 +1416,7 @@ void ProcessContext(ALCcontext *ctx, const ALuint SamplesToDo) [SamplesToDo](const ALeffectslot *slot) -> void { EffectState *state{slot->Params.mEffectState}; - state->process(SamplesToDo, slot->Wet.Buffer.data(), - static_cast(slot->Wet.Buffer.size()), state->mOutTarget); + state->process(SamplesToDo, slot->Wet.Buffer, state->mOutTarget); } ); } diff --git a/alc/effects/autowah.cpp b/alc/effects/autowah.cpp index 144798f8..f28cfd54 100644 --- a/alc/effects/autowah.cpp +++ b/alc/effects/autowah.cpp @@ -71,7 +71,7 @@ struct ALautowahState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) override; DEF_NEWDEL(ALautowahState) }; @@ -126,7 +126,7 @@ void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, } } -void ALautowahState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) +void ALautowahState::process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) { const ALfloat attack_rate = mAttackRate; const ALfloat release_rate = mReleaseRate; @@ -154,8 +154,8 @@ void ALautowahState::process(const size_t samplesToDo, const FloatBufferLine *RE } mEnvDelay = env_delay; - ASSUME(numInput > 0); - for(ALsizei c{0};c < numInput;++c) + auto chandata = std::addressof(mChans[0]); + for(const auto &insamples : samplesIn) { /* This effectively inlines BiquadFilter_setParams for a peaking * filter and BiquadFilter_processC. The alpha and cosine components @@ -163,8 +163,8 @@ void ALautowahState::process(const size_t samplesToDo, const FloatBufferLine *RE * envelope. Because the filter changes for each sample, the * coefficients are transient and don't need to be held. */ - ALfloat z1{mChans[c].Filter.z1}; - ALfloat z2{mChans[c].Filter.z2}; + ALfloat z1{chandata->Filter.z1}; + ALfloat z2{chandata->Filter.z2}; for(size_t i{0u};i < samplesToDo;i++) { @@ -180,18 +180,19 @@ void ALautowahState::process(const size_t samplesToDo, const FloatBufferLine *RE a[1] = -2.0f * cos_w0; a[2] = 1.0f - alpha/res_gain; - input = samplesIn[c][i]; + input = insamples[i]; output = input*(b[0]/a[0]) + z1; z1 = input*(b[1]/a[0]) - output*(a[1]/a[0]) + z2; z2 = input*(b[2]/a[0]) - output*(a[2]/a[0]); mBufferOut[i] = output; } - mChans[c].Filter.z1 = z1; - mChans[c].Filter.z2 = z2; + chandata->Filter.z1 = z1; + chandata->Filter.z2 = z2; /* Now, mix the processed sound data to the output. */ - MixSamples({mBufferOut, samplesToDo}, samplesOut, mChans[c].CurrentGains, - mChans[c].TargetGains, samplesToDo, 0); + MixSamples({mBufferOut, samplesToDo}, samplesOut, chandata->CurrentGains, + chandata->TargetGains, samplesToDo, 0); + ++chandata; } } diff --git a/alc/effects/base.h b/alc/effects/base.h index 4d22c4c4..7bc170aa 100644 --- a/alc/effects/base.h +++ b/alc/effects/base.h @@ -159,7 +159,7 @@ struct EffectState : public al::intrusive_ref { virtual ALboolean deviceUpdate(const ALCdevice *device) = 0; virtual void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) = 0; - virtual void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) = 0; + virtual void process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) = 0; }; diff --git a/alc/effects/chorus.cpp b/alc/effects/chorus.cpp index 37e29b8e..0d59c338 100644 --- a/alc/effects/chorus.cpp +++ b/alc/effects/chorus.cpp @@ -111,7 +111,7 @@ struct ChorusState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) override; DEF_NEWDEL(ChorusState) }; @@ -207,7 +207,7 @@ void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, co } } -void ChorusState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) +void ChorusState::process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) { const auto bufmask = static_cast(mSampleBuffer.size()-1); const ALfloat feedback{mFeedback}; diff --git a/alc/effects/compressor.cpp b/alc/effects/compressor.cpp index e2f644ed..176e5a58 100644 --- a/alc/effects/compressor.cpp +++ b/alc/effects/compressor.cpp @@ -51,7 +51,7 @@ struct CompressorState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) override; DEF_NEWDEL(CompressorState) }; @@ -85,7 +85,7 @@ void CompressorState::update(const ALCcontext*, const ALeffectslot *slot, const } } -void CompressorState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) +void CompressorState::process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) { for(size_t base{0u};base < samplesToDo;) { @@ -134,10 +134,10 @@ void CompressorState::process(const size_t samplesToDo, const FloatBufferLine *R mEnvFollower = env; /* Now compress the signal amplitude to output. */ - ASSUME(numInput > 0); - for(ALsizei j{0};j < numInput;j++) + auto changains = std::addressof(mGain[0]); + for(const auto &input : samplesIn) { - const ALfloat *outgains{mGain[j]}; + const ALfloat *outgains{*(changains++)}; for(FloatBufferLine &output : samplesOut) { const ALfloat gain{*(outgains++)}; @@ -145,7 +145,7 @@ void CompressorState::process(const size_t samplesToDo, const FloatBufferLine *R continue; for(size_t i{0u};i < td;i++) - output[base+i] += samplesIn[j][base+i] * gains[i] * gain; + output[base+i] += input[base+i] * gains[i] * gain; } } diff --git a/alc/effects/dedicated.cpp b/alc/effects/dedicated.cpp index 83cba773..02fdcc78 100644 --- a/alc/effects/dedicated.cpp +++ b/alc/effects/dedicated.cpp @@ -39,7 +39,7 @@ struct DedicatedState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) override; DEF_NEWDEL(DedicatedState) }; @@ -86,7 +86,7 @@ void DedicatedState::update(const ALCcontext*, const ALeffectslot *slot, const E } } -void DedicatedState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) +void DedicatedState::process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) { MixSamples({samplesIn[0].data(), samplesToDo}, samplesOut, mCurrentGains, mTargetGains, samplesToDo, 0); diff --git a/alc/effects/distortion.cpp b/alc/effects/distortion.cpp index ac6486cb..7dd43008 100644 --- a/alc/effects/distortion.cpp +++ b/alc/effects/distortion.cpp @@ -49,7 +49,7 @@ struct DistortionState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) override; DEF_NEWDEL(DistortionState) }; @@ -93,7 +93,7 @@ void DistortionState::update(const ALCcontext *context, const ALeffectslot *slot ComputePanGains(target.Main, coeffs, slot->Params.Gain*props->Distortion.Gain, mGain); } -void DistortionState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) +void DistortionState::process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) { const ALfloat fc{mEdgeCoeff}; for(size_t base{0u};base < samplesToDo;) diff --git a/alc/effects/echo.cpp b/alc/effects/echo.cpp index 4a9ee1bc..d95011c2 100644 --- a/alc/effects/echo.cpp +++ b/alc/effects/echo.cpp @@ -59,7 +59,7 @@ struct EchoState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) override; DEF_NEWDEL(EchoState) }; @@ -117,7 +117,7 @@ void EchoState::update(const ALCcontext *context, const ALeffectslot *slot, cons ComputePanGains(target.Main, coeffs[1], slot->Params.Gain, mGains[1].Target); } -void EchoState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) +void EchoState::process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) { const auto mask = static_cast(mSampleBuffer.size()-1); ALfloat *RESTRICT delaybuf{mSampleBuffer.data()}; diff --git a/alc/effects/equalizer.cpp b/alc/effects/equalizer.cpp index 05818ebf..929bff14 100644 --- a/alc/effects/equalizer.cpp +++ b/alc/effects/equalizer.cpp @@ -93,7 +93,7 @@ struct EqualizerState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) override; DEF_NEWDEL(EqualizerState) }; @@ -157,18 +157,19 @@ void EqualizerState::update(const ALCcontext *context, const ALeffectslot *slot, } } -void EqualizerState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) +void EqualizerState::process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) { - ASSUME(numInput > 0); - for(ALsizei c{0};c < numInput;c++) + auto chandata = std::addressof(mChans[0]); + for(const auto &input : samplesIn) { - mChans[c].filter[0].process(mSampleBuffer, samplesIn[c].data(), samplesToDo); - mChans[c].filter[1].process(mSampleBuffer, mSampleBuffer, samplesToDo); - mChans[c].filter[2].process(mSampleBuffer, mSampleBuffer, samplesToDo); - mChans[c].filter[3].process(mSampleBuffer, mSampleBuffer, samplesToDo); - - MixSamples({mSampleBuffer, samplesToDo}, samplesOut, mChans[c].CurrentGains, - mChans[c].TargetGains, samplesToDo, 0); + chandata->filter[0].process(mSampleBuffer, input.data(), samplesToDo); + chandata->filter[1].process(mSampleBuffer, mSampleBuffer, samplesToDo); + chandata->filter[2].process(mSampleBuffer, mSampleBuffer, samplesToDo); + chandata->filter[3].process(mSampleBuffer, mSampleBuffer, samplesToDo); + + MixSamples({mSampleBuffer, samplesToDo}, samplesOut, chandata->CurrentGains, + chandata->TargetGains, samplesToDo, 0); + ++chandata; } } diff --git a/alc/effects/fshifter.cpp b/alc/effects/fshifter.cpp index 6983ae42..351b138f 100644 --- a/alc/effects/fshifter.cpp +++ b/alc/effects/fshifter.cpp @@ -85,7 +85,7 @@ struct FshifterState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) override; DEF_NEWDEL(FshifterState) }; @@ -160,7 +160,7 @@ void FshifterState::update(const ALCcontext *context, const ALeffectslot *slot, ComputePanGains(target.Main, coeffs[1], slot->Params.Gain, mGains[1].Target); } -void FshifterState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) +void FshifterState::process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) { static constexpr complex_d complex_zero{0.0, 0.0}; ALfloat *RESTRICT BufferOut = mBufferOut; diff --git a/alc/effects/modulator.cpp b/alc/effects/modulator.cpp index a4a8e5c9..ffb1c381 100644 --- a/alc/effects/modulator.cpp +++ b/alc/effects/modulator.cpp @@ -91,7 +91,7 @@ struct ModulatorState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) override; DEF_NEWDEL(ModulatorState) }; @@ -138,7 +138,7 @@ void ModulatorState::update(const ALCcontext *context, const ALeffectslot *slot, } } -void ModulatorState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) +void ModulatorState::process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) { for(size_t base{0u};base < samplesToDo;) { @@ -149,17 +149,18 @@ void ModulatorState::process(const size_t samplesToDo, const FloatBufferLine *RE mIndex += (mStep*td) & WAVEFORM_FRACMASK; mIndex &= WAVEFORM_FRACMASK; - ASSUME(numInput > 0); - for(ALsizei c{0};c < numInput;c++) + auto chandata = std::addressof(mChans[0]); + for(const auto &input : samplesIn) { alignas(16) ALfloat temps[MAX_UPDATE_SAMPLES]; - mChans[c].Filter.process(temps, &samplesIn[c][base], td); + chandata->Filter.process(temps, &input[base], td); for(size_t i{0u};i < td;i++) temps[i] *= modsamples[i]; - MixSamples({temps, td}, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, + MixSamples({temps, td}, samplesOut, chandata->CurrentGains, chandata->TargetGains, samplesToDo-base, base); + ++chandata; } base += td; diff --git a/alc/effects/null.cpp b/alc/effects/null.cpp index c833a73a..e0497296 100644 --- a/alc/effects/null.cpp +++ b/alc/effects/null.cpp @@ -20,7 +20,7 @@ struct NullState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) override; DEF_NEWDEL(NullState) }; @@ -58,7 +58,7 @@ void NullState::update(const ALCcontext* /*context*/, const ALeffectslot* /*slot * not replace it. */ void NullState::process(const size_t/*samplesToDo*/, - const FloatBufferLine *RESTRICT /*samplesIn*/, const ALsizei /*numInput*/, + const al::span /*samplesIn*/, const al::span /*samplesOut*/) { } diff --git a/alc/effects/pshifter.cpp b/alc/effects/pshifter.cpp index a3f162c9..9d011b12 100644 --- a/alc/effects/pshifter.cpp +++ b/alc/effects/pshifter.cpp @@ -118,7 +118,7 @@ struct PshifterState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) override; DEF_NEWDEL(PshifterState) }; @@ -161,7 +161,7 @@ void PshifterState::update(const ALCcontext*, const ALeffectslot *slot, const Ef ComputePanGains(target.Main, coeffs, slot->Params.Gain, mTargetGains); } -void PshifterState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei /*numInput*/, const al::span samplesOut) +void PshifterState::process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) { /* Pitch shifter engine based on the work of Stephan Bernsee. * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/ diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 5d9dbf81..4cd9124e 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -483,7 +483,7 @@ struct ReverbState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) override; DEF_NEWDEL(ReverbState) }; @@ -1440,18 +1440,19 @@ void ReverbState::lateFaded(const size_t offset, const size_t todo, const ALfloa VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, temps, todo); } -void ReverbState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) +void ReverbState::process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) { size_t offset{mOffset}; ASSUME(samplesToDo > 0); /* Convert B-Format to A-Format for processing. */ + const size_t numInput{samplesIn.size()}; const al::span tmpspan{mTempLine.data(), samplesToDo}; for(size_t c{0u};c < NUM_LINES;c++) { std::fill(tmpspan.begin(), tmpspan.end(), 0.0f); - MixRowSamples(tmpspan, {B2A[c], B2A[c]+numInput}, samplesIn->data(), samplesIn->size()); + MixRowSamples(tmpspan, {B2A[c], numInput}, samplesIn[0].data(), samplesIn[0].size()); /* Band-pass the incoming samples and feed the initial delay line. */ mFilter[c].Lp.process(mTempLine.data(), mTempLine.data(), samplesToDo); diff --git a/alc/effects/vmorpher.cpp b/alc/effects/vmorpher.cpp index a75420a3..a3524371 100644 --- a/alc/effects/vmorpher.cpp +++ b/alc/effects/vmorpher.cpp @@ -137,7 +137,7 @@ struct VmorpherState final : public EffectState { ALboolean deviceUpdate(const ALCdevice *device) override; void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; - void process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) override; + void process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) override; static std::array getFiltersByPhoneme(ALenum phoneme, ALfloat frequency, ALfloat pitch); @@ -244,7 +244,7 @@ void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, } } -void VmorpherState::process(const size_t samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span samplesOut) +void VmorpherState::process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) { /* Following the EFX specification for a conformant implementation which describes * the effect as a pair of 4-band formant filters blended together using an LFO. @@ -258,34 +258,35 @@ void VmorpherState::process(const size_t samplesToDo, const FloatBufferLine *RES mIndex += (mStep * td) & WAVEFORM_FRACMASK; mIndex &= WAVEFORM_FRACMASK; - ASSUME(numInput > 0); - for(ALsizei c{0};c < numInput;c++) + auto chandata = std::addressof(mChans[0]); + for(const auto &input : samplesIn) { std::fill_n(std::begin(mSampleBufferA), td, 0.0f); std::fill_n(std::begin(mSampleBufferB), td, 0.0f); - auto& vowelA = mChans[c].Formants[VOWEL_A_INDEX]; - auto& vowelB = mChans[c].Formants[VOWEL_B_INDEX]; + auto& vowelA = chandata->Formants[VOWEL_A_INDEX]; + auto& vowelB = chandata->Formants[VOWEL_B_INDEX]; /* Process first vowel. */ - vowelA[0].process(&samplesIn[c][base], mSampleBufferA, td); - vowelA[1].process(&samplesIn[c][base], mSampleBufferA, td); - vowelA[2].process(&samplesIn[c][base], mSampleBufferA, td); - vowelA[3].process(&samplesIn[c][base], mSampleBufferA, td); + vowelA[0].process(&input[base], mSampleBufferA, td); + vowelA[1].process(&input[base], mSampleBufferA, td); + vowelA[2].process(&input[base], mSampleBufferA, td); + vowelA[3].process(&input[base], mSampleBufferA, td); /* Process second vowel. */ - vowelB[0].process(&samplesIn[c][base], mSampleBufferB, td); - vowelB[1].process(&samplesIn[c][base], mSampleBufferB, td); - vowelB[2].process(&samplesIn[c][base], mSampleBufferB, td); - vowelB[3].process(&samplesIn[c][base], mSampleBufferB, td); + vowelB[0].process(&input[base], mSampleBufferB, td); + vowelB[1].process(&input[base], mSampleBufferB, td); + vowelB[2].process(&input[base], mSampleBufferB, td); + vowelB[3].process(&input[base], mSampleBufferB, td); alignas(16) ALfloat blended[MAX_UPDATE_SAMPLES]; for(size_t i{0u};i < td;i++) blended[i] = lerp(mSampleBufferA[i], mSampleBufferB[i], lfo[i]); /* Now, mix the processed sound data to the output. */ - MixSamples({blended, td}, samplesOut, mChans[c].CurrentGains, mChans[c].TargetGains, + MixSamples({blended, td}, samplesOut, chandata->CurrentGains, chandata->TargetGains, samplesToDo-base, base); + ++chandata; } base += td; -- cgit v1.2.3 From b5a6dcc14ff58243899b8dbfca72e6b65792373c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Aug 2019 11:02:09 -0700 Subject: Remove some unnecessary local spans --- alc/effects/reverb.cpp | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 4cd9124e..2caf9025 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -1192,7 +1192,6 @@ void VecAllpass::processFaded(const al::span samples */ void ReverbState::earlyUnfaded(const size_t offset, const size_t todo) { - const al::span temps{mTempSamples}; const DelayLineI early_delay{mEarly.Delay}; const DelayLineI main_delay{mDelay}; const ALfloat mixX{mMixX}; @@ -1212,7 +1211,7 @@ void ReverbState::earlyUnfaded(const size_t offset, const size_t todo) early_delay_tap &= main_delay.Mask; size_t td{minz(main_delay.Mask+1 - early_delay_tap, todo - i)}; do { - temps[j][i++] = main_delay.Line[early_delay_tap++][j] * coeff; + mTempSamples[j][i++] = main_delay.Line[early_delay_tap++][j] * coeff; } while(--td); } } @@ -1220,7 +1219,7 @@ void ReverbState::earlyUnfaded(const size_t offset, const size_t todo) /* Apply a vector all-pass, to help color the initial reflections based on * the diffusion strength. */ - mEarly.VecAp.processUnfaded(temps, offset, mixX, mixY, todo); + mEarly.VecAp.processUnfaded(mTempSamples, offset, mixX, mixY, todo); /* Apply a delay and bounce to generate secondary reflections, combine with * the primary reflections and write out the result for mixing. @@ -1236,13 +1235,13 @@ void ReverbState::earlyUnfaded(const size_t offset, const size_t todo) feedb_tap &= early_delay.Mask; size_t td{minz(early_delay.Mask+1 - feedb_tap, todo - i)}; do { - out[i] = temps[j][i] + early_delay.Line[feedb_tap++][j]*feedb_coeff; + out[i] = mTempSamples[j][i] + early_delay.Line[feedb_tap++][j]*feedb_coeff; ++i; } while(--td); } } for(size_t j{0u};j < NUM_LINES;j++) - early_delay.write(offset, NUM_LINES-1-j, temps[j].data(), todo); + early_delay.write(offset, NUM_LINES-1-j, mTempSamples[j].data(), todo); /* Also write the result back to the main delay line for the late reverb * stage to pick up at the appropriate time, appplying a scatter and @@ -1254,7 +1253,6 @@ void ReverbState::earlyUnfaded(const size_t offset, const size_t todo) void ReverbState::earlyFaded(const size_t offset, const size_t todo, const ALfloat fade, const ALfloat fadeStep) { - const al::span temps{mTempSamples}; const DelayLineI early_delay{mEarly.Delay}; const DelayLineI main_delay{mDelay}; const ALfloat mixX{mMixX}; @@ -1280,14 +1278,14 @@ void ReverbState::earlyFaded(const size_t offset, const size_t todo, const ALflo fadeCount += 1.0f; const ALfloat fade0{oldCoeff + oldCoeffStep*fadeCount}; const ALfloat fade1{newCoeffStep*fadeCount}; - temps[j][i++] = + mTempSamples[j][i++] = main_delay.Line[early_delay_tap0++][j]*fade0 + main_delay.Line[early_delay_tap1++][j]*fade1; } while(--td); } } - mEarly.VecAp.processFaded(temps, offset, mixX, mixY, fade, fadeStep, todo); + mEarly.VecAp.processFaded(mTempSamples, offset, mixX, mixY, fade, fadeStep, todo); for(size_t j{0u};j < NUM_LINES;j++) { @@ -1309,7 +1307,7 @@ void ReverbState::earlyFaded(const size_t offset, const size_t todo, const ALflo fadeCount += 1.0f; const ALfloat fade0{feedb_oldCoeff + feedb_oldCoeffStep*fadeCount}; const ALfloat fade1{feedb_newCoeffStep*fadeCount}; - out[i] = temps[j][i] + + out[i] = mTempSamples[j][i] + early_delay.Line[feedb_tap0++][j]*fade0 + early_delay.Line[feedb_tap1++][j]*fade1; ++i; @@ -1317,7 +1315,7 @@ void ReverbState::earlyFaded(const size_t offset, const size_t todo, const ALflo } } for(size_t j{0u};j < NUM_LINES;j++) - early_delay.write(offset, NUM_LINES-1-j, temps[j].data(), todo); + early_delay.write(offset, NUM_LINES-1-j, mTempSamples[j].data(), todo); const size_t late_feed_tap{offset - mLateFeedTap}; VectorScatterRevDelayIn(main_delay, late_feed_tap, mixX, mixY, mEarlySamples, todo); @@ -1339,7 +1337,6 @@ void ReverbState::earlyFaded(const size_t offset, const size_t todo, const ALflo */ void ReverbState::lateUnfaded(const size_t offset, const size_t todo) { - const al::span temps{mTempSamples}; const DelayLineI late_delay{mLate.Delay}; const DelayLineI main_delay{mDelay}; const ALfloat mixX{mMixX}; @@ -1363,28 +1360,27 @@ void ReverbState::lateUnfaded(const size_t offset, const size_t todo) size_t td{minz(todo - i, minz(main_delay.Mask+1 - late_delay_tap, late_delay.Mask+1 - late_feedb_tap))}; do { - temps[j][i++] = + mTempSamples[j][i++] = main_delay.Line[late_delay_tap++][j]*densityGain + late_delay.Line[late_feedb_tap++][j]*midGain; } while(--td); } - mLate.T60[j].process(temps[j].data(), todo); + mLate.T60[j].process(mTempSamples[j].data(), todo); } /* Apply a vector all-pass to improve micro-surface diffusion, and write * out the results for mixing. */ - mLate.VecAp.processUnfaded(temps, offset, mixX, mixY, todo); + mLate.VecAp.processUnfaded(mTempSamples, offset, mixX, mixY, todo); for(size_t j{0u};j < NUM_LINES;j++) - std::copy_n(temps[j].begin(), todo, mLateSamples[j].begin()); + std::copy_n(mTempSamples[j].begin(), todo, mLateSamples[j].begin()); /* Finally, scatter and bounce the results to refeed the feedback buffer. */ - VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, temps, todo); + VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, mTempSamples, todo); } void ReverbState::lateFaded(const size_t offset, const size_t todo, const ALfloat fade, const ALfloat fadeStep) { - const al::span temps{mTempSamples}; const DelayLineI late_delay{mLate.Delay}; const DelayLineI main_delay{mDelay}; const ALfloat mixX{mMixX}; @@ -1423,21 +1419,21 @@ void ReverbState::lateFaded(const size_t offset, const size_t todo, const ALfloa const ALfloat fade1{densityStep*fadeCount}; const ALfloat gfade0{oldMidGain + oldMidStep*fadeCount}; const ALfloat gfade1{midStep*fadeCount}; - temps[j][i++] = + mTempSamples[j][i++] = main_delay.Line[late_delay_tap0++][j]*fade0 + main_delay.Line[late_delay_tap1++][j]*fade1 + late_delay.Line[late_feedb_tap0++][j]*gfade0 + late_delay.Line[late_feedb_tap1++][j]*gfade1; } while(--td); } - mLate.T60[j].process(temps[j].data(), todo); + mLate.T60[j].process(mTempSamples[j].data(), todo); } - mLate.VecAp.processFaded(temps, offset, mixX, mixY, fade, fadeStep, todo); + mLate.VecAp.processFaded(mTempSamples, offset, mixX, mixY, fade, fadeStep, todo); for(size_t j{0u};j < NUM_LINES;j++) - std::copy_n(temps[j].begin(), todo, mLateSamples[j].begin()); + std::copy_n(mTempSamples[j].begin(), todo, mLateSamples[j].begin()); - VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, temps, todo); + VectorScatterRevDelayIn(late_delay, offset, mixX, mixY, mTempSamples, todo); } void ReverbState::process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) @@ -1498,7 +1494,6 @@ void ReverbState::process(const size_t samplesToDo, const al::span*mMixOut)(samplesOut, samplesToDo-base, base, todo); offset += todo; -- cgit v1.2.3 From 3223b6a9060d5d5df2d1d79985f47dff20de8412 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Aug 2019 19:13:31 -0700 Subject: Update mainwindow.cpp Use the less-error-prone pointer-to-member syntax for connect calls, and use uniform initialization more often. --- utils/alsoft-config/mainwindow.cpp | 455 ++++++++++++++++++------------------- 1 file changed, 227 insertions(+), 228 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index ce14596d..3b7b428a 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -170,7 +170,7 @@ static QString getBaseDataPath() return base; } -static QStringList getAllDataPaths(QString append=QString()) +static QStringList getAllDataPaths(const QString &append) { QStringList list; list.append(getBaseDataPath()); @@ -204,7 +204,7 @@ static QString getValueFromName(const NameValuePair (&list)[N], const QString &s if(str == list[i].name) return list[i].value; } - return QString(); + return QString{}; } template @@ -215,7 +215,7 @@ static QString getNameFromValue(const NameValuePair (&list)[N], const QString &s if(str == list[i].value) return list[i].name; } - return QString(); + return QString{}; } @@ -232,10 +232,10 @@ QString getCheckValue(const QCheckBox *checkbox) { const Qt::CheckState state{checkbox->checkState()}; if(state == Qt::Checked) - return QString("true"); + return QString{"true"}; if(state == Qt::Unchecked) - return QString("false"); - return QString(); + return QString{"false"}; + return QString{}; } } @@ -320,129 +320,131 @@ MainWindow::MainWindow(QWidget *parent) : #endif - mPeriodSizeValidator = new QIntValidator(64, 8192, this); + mPeriodSizeValidator = new QIntValidator{64, 8192, this}; ui->periodSizeEdit->setValidator(mPeriodSizeValidator); - mPeriodCountValidator = new QIntValidator(2, 16, this); + mPeriodCountValidator = new QIntValidator{2, 16, this}; ui->periodCountEdit->setValidator(mPeriodCountValidator); - mSourceCountValidator = new QIntValidator(0, 4096, this); + mSourceCountValidator = new QIntValidator{0, 4096, this}; ui->srcCountLineEdit->setValidator(mSourceCountValidator); - mEffectSlotValidator = new QIntValidator(0, 64, this); + mEffectSlotValidator = new QIntValidator{0, 64, this}; ui->effectSlotLineEdit->setValidator(mEffectSlotValidator); - mSourceSendValidator = new QIntValidator(0, 16, this); + mSourceSendValidator = new QIntValidator{0, 16, this}; ui->srcSendLineEdit->setValidator(mSourceSendValidator); - mSampleRateValidator = new QIntValidator(8000, 192000, this); + mSampleRateValidator = new QIntValidator{8000, 192000, this}; ui->sampleRateCombo->lineEdit()->setValidator(mSampleRateValidator); - mJackBufferValidator = new QIntValidator(0, 8192, this); + mJackBufferValidator = new QIntValidator{0, 8192, this}; ui->jackBufferSizeLine->setValidator(mJackBufferValidator); - connect(ui->actionLoad, SIGNAL(triggered()), this, SLOT(loadConfigFromFile())); - connect(ui->actionSave_As, SIGNAL(triggered()), this, SLOT(saveConfigAsFile())); - - connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(showAboutPage())); - - connect(ui->closeCancelButton, SIGNAL(clicked()), this, SLOT(cancelCloseAction())); - connect(ui->applyButton, SIGNAL(clicked()), this, SLOT(saveCurrentConfig())); - - connect(ui->channelConfigCombo, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); - connect(ui->sampleFormatCombo, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); - connect(ui->stereoModeCombo, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); - connect(ui->sampleRateCombo, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); - connect(ui->sampleRateCombo, SIGNAL(editTextChanged(const QString&)), this, SLOT(enableApplyButton())); - - connect(ui->resamplerSlider, SIGNAL(valueChanged(int)), this, SLOT(updateResamplerLabel(int))); - - connect(ui->periodSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(updatePeriodSizeEdit(int))); - connect(ui->periodSizeEdit, SIGNAL(editingFinished()), this, SLOT(updatePeriodSizeSlider())); - connect(ui->periodCountSlider, SIGNAL(valueChanged(int)), this, SLOT(updatePeriodCountEdit(int))); - connect(ui->periodCountEdit, SIGNAL(editingFinished()), this, SLOT(updatePeriodCountSlider())); - - connect(ui->stereoEncodingComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(enableApplyButton())); - connect(ui->ambiFormatComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(enableApplyButton())); - connect(ui->outputLimiterCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->outputDitherCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - - connect(ui->decoderHQModeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->decoderDistCompCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->decoderNFEffectsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->decoderNFRefDelaySpinBox, SIGNAL(valueChanged(double)), this, SLOT(enableApplyButton())); - connect(ui->decoderQuadLineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); - connect(ui->decoderQuadButton, SIGNAL(clicked()), this, SLOT(selectQuadDecoderFile())); - connect(ui->decoder51LineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); - connect(ui->decoder51Button, SIGNAL(clicked()), this, SLOT(select51DecoderFile())); - connect(ui->decoder61LineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); - connect(ui->decoder61Button, SIGNAL(clicked()), this, SLOT(select61DecoderFile())); - connect(ui->decoder71LineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); - connect(ui->decoder71Button, SIGNAL(clicked()), this, SLOT(select71DecoderFile())); - - connect(ui->preferredHrtfComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); - connect(ui->hrtfStateComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); - connect(ui->hrtfmodeSlider, SIGNAL(valueChanged(int)), this, SLOT(updateHrtfModeLabel(int))); - - connect(ui->hrtfAddButton, SIGNAL(clicked()), this, SLOT(addHrtfFile())); - connect(ui->hrtfRemoveButton, SIGNAL(clicked()), this, SLOT(removeHrtfFile())); - connect(ui->hrtfFileList, SIGNAL(itemSelectionChanged()), this, SLOT(updateHrtfRemoveButton())); - connect(ui->defaultHrtfPathsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - - connect(ui->srcCountLineEdit, SIGNAL(editingFinished()), this, SLOT(enableApplyButton())); - connect(ui->srcSendLineEdit, SIGNAL(editingFinished()), this, SLOT(enableApplyButton())); - connect(ui->effectSlotLineEdit, SIGNAL(editingFinished()), this, SLOT(enableApplyButton())); - - connect(ui->enableSSECheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->enableSSE2CheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->enableSSE3CheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->enableSSE41CheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->enableNeonCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->actionLoad, &QAction::triggered, this, &MainWindow::loadConfigFromFile); + connect(ui->actionSave_As, &QAction::triggered, this, &MainWindow::saveConfigAsFile); + + connect(ui->actionAbout, &QAction::triggered, this, &MainWindow::showAboutPage); + + connect(ui->closeCancelButton, &QPushButton::clicked, this, &MainWindow::cancelCloseAction); + connect(ui->applyButton, &QPushButton::clicked, this, &MainWindow::saveCurrentConfig); + + auto qcb_cicstr = static_cast(&QComboBox::currentIndexChanged); + connect(ui->channelConfigCombo, qcb_cicstr, this, &MainWindow::enableApplyButton); + connect(ui->sampleFormatCombo, qcb_cicstr, this, &MainWindow::enableApplyButton); + connect(ui->stereoModeCombo, qcb_cicstr, this, &MainWindow::enableApplyButton); + connect(ui->sampleRateCombo, qcb_cicstr, this, &MainWindow::enableApplyButton); + connect(ui->sampleRateCombo, &QComboBox::editTextChanged, this, &MainWindow::enableApplyButton); + + connect(ui->resamplerSlider, &QSlider::valueChanged, this, &MainWindow::updateResamplerLabel); + + connect(ui->periodSizeSlider, &QSlider::valueChanged, this, &MainWindow::updatePeriodSizeEdit); + connect(ui->periodSizeEdit, &QLineEdit::editingFinished, this, &MainWindow::updatePeriodSizeSlider); + connect(ui->periodCountSlider, &QSlider::valueChanged, this, &MainWindow::updatePeriodCountEdit); + connect(ui->periodCountEdit, &QLineEdit::editingFinished, this, &MainWindow::updatePeriodCountSlider); + + connect(ui->stereoEncodingComboBox, qcb_cicstr, this, &MainWindow::enableApplyButton); + connect(ui->ambiFormatComboBox, qcb_cicstr, this, &MainWindow::enableApplyButton); + connect(ui->outputLimiterCheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->outputDitherCheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + + connect(ui->decoderHQModeCheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->decoderDistCompCheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->decoderNFEffectsCheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + auto qdsb_vcd = static_cast(&QDoubleSpinBox::valueChanged); + connect(ui->decoderNFRefDelaySpinBox, qdsb_vcd, this, &MainWindow::enableApplyButton); + connect(ui->decoderQuadLineEdit, &QLineEdit::textChanged, this, &MainWindow::enableApplyButton); + connect(ui->decoderQuadButton, &QPushButton::clicked, this, &MainWindow::selectQuadDecoderFile); + connect(ui->decoder51LineEdit, &QLineEdit::textChanged, this, &MainWindow::enableApplyButton); + connect(ui->decoder51Button, &QPushButton::clicked, this, &MainWindow::select51DecoderFile); + connect(ui->decoder61LineEdit, &QLineEdit::textChanged, this, &MainWindow::enableApplyButton); + connect(ui->decoder61Button, &QPushButton::clicked, this, &MainWindow::select61DecoderFile); + connect(ui->decoder71LineEdit, &QLineEdit::textChanged, this, &MainWindow::enableApplyButton); + connect(ui->decoder71Button, &QPushButton::clicked, this, &MainWindow::select71DecoderFile); + + connect(ui->preferredHrtfComboBox, qcb_cicstr, this, &MainWindow::enableApplyButton); + connect(ui->hrtfStateComboBox, qcb_cicstr, this, &MainWindow::enableApplyButton); + connect(ui->hrtfmodeSlider, &QSlider::valueChanged, this, &MainWindow::updateHrtfModeLabel); + + connect(ui->hrtfAddButton, &QPushButton::clicked, this, &MainWindow::addHrtfFile); + connect(ui->hrtfRemoveButton, &QPushButton::clicked, this, &MainWindow::removeHrtfFile); + connect(ui->hrtfFileList, &QListWidget::itemSelectionChanged, this, &MainWindow::updateHrtfRemoveButton); + connect(ui->defaultHrtfPathsCheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + + connect(ui->srcCountLineEdit, &QLineEdit::editingFinished, this, &MainWindow::enableApplyButton); + connect(ui->srcSendLineEdit, &QLineEdit::editingFinished, this, &MainWindow::enableApplyButton); + connect(ui->effectSlotLineEdit, &QLineEdit::editingFinished, this, &MainWindow::enableApplyButton); + + connect(ui->enableSSECheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->enableSSE2CheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->enableSSE3CheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->enableSSE41CheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->enableNeonCheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); ui->enabledBackendList->setContextMenuPolicy(Qt::CustomContextMenu); - connect(ui->enabledBackendList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showEnabledBackendMenu(QPoint))); + connect(ui->enabledBackendList, &QListWidget::customContextMenuRequested, this, &MainWindow::showEnabledBackendMenu); ui->disabledBackendList->setContextMenuPolicy(Qt::CustomContextMenu); - connect(ui->disabledBackendList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showDisabledBackendMenu(QPoint))); - connect(ui->backendCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - - connect(ui->defaultReverbComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); - connect(ui->enableEaxReverbCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->enableStdReverbCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->enableAutowahCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->enableChorusCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->enableCompressorCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->enableDistortionCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->enableEchoCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->enableEqualizerCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->enableFlangerCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->enableFrequencyShifterCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->enableModulatorCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->enableDedicatedCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->enablePitchShifterCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->enableVocalMorpherCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - - connect(ui->pulseAutospawnCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->pulseAllowMovesCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->pulseFixRateCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->pulseAdjLatencyCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - - connect(ui->jackAutospawnCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->jackBufferSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(updateJackBufferSizeEdit(int))); - connect(ui->jackBufferSizeLine, SIGNAL(editingFinished()), this, SLOT(updateJackBufferSizeSlider())); - - connect(ui->alsaDefaultDeviceLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); - connect(ui->alsaDefaultCaptureLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); - connect(ui->alsaResamplerCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->alsaMmapCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - - connect(ui->ossDefaultDeviceLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); - connect(ui->ossPlaybackPushButton, SIGNAL(clicked(bool)), this, SLOT(selectOSSPlayback())); - connect(ui->ossDefaultCaptureLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); - connect(ui->ossCapturePushButton, SIGNAL(clicked(bool)), this, SLOT(selectOSSCapture())); - - connect(ui->solarisDefaultDeviceLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); - connect(ui->solarisPlaybackPushButton, SIGNAL(clicked(bool)), this, SLOT(selectSolarisPlayback())); - - connect(ui->waveOutputLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); - connect(ui->waveOutputButton, SIGNAL(clicked(bool)), this, SLOT(selectWaveOutput())); - connect(ui->waveBFormatCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->disabledBackendList, &QListWidget::customContextMenuRequested, this, &MainWindow::showDisabledBackendMenu); + connect(ui->backendCheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + + connect(ui->defaultReverbComboBox, qcb_cicstr, this, &MainWindow::enableApplyButton); + connect(ui->enableEaxReverbCheck, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->enableStdReverbCheck, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->enableAutowahCheck, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->enableChorusCheck, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->enableCompressorCheck, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->enableDistortionCheck, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->enableEchoCheck, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->enableEqualizerCheck, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->enableFlangerCheck, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->enableFrequencyShifterCheck, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->enableModulatorCheck, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->enableDedicatedCheck, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->enablePitchShifterCheck, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->enableVocalMorpherCheck, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + + connect(ui->pulseAutospawnCheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->pulseAllowMovesCheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->pulseFixRateCheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->pulseAdjLatencyCheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + + connect(ui->jackAutospawnCheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->jackBufferSizeSlider, &QSlider::valueChanged, this, &MainWindow::updateJackBufferSizeEdit); + connect(ui->jackBufferSizeLine, &QLineEdit::editingFinished, this, &MainWindow::updateJackBufferSizeSlider); + + connect(ui->alsaDefaultDeviceLine, &QLineEdit::textChanged, this, &MainWindow::enableApplyButton); + connect(ui->alsaDefaultCaptureLine, &QLineEdit::textChanged, this, &MainWindow::enableApplyButton); + connect(ui->alsaResamplerCheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + connect(ui->alsaMmapCheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); + + connect(ui->ossDefaultDeviceLine, &QLineEdit::textChanged, this, &MainWindow::enableApplyButton); + connect(ui->ossPlaybackPushButton, &QPushButton::clicked, this, &MainWindow::selectOSSPlayback); + connect(ui->ossDefaultCaptureLine, &QLineEdit::textChanged, this, &MainWindow::enableApplyButton); + connect(ui->ossCapturePushButton, &QPushButton::clicked, this, &MainWindow::selectOSSCapture); + + connect(ui->solarisDefaultDeviceLine, &QLineEdit::textChanged, this, &MainWindow::enableApplyButton); + connect(ui->solarisPlaybackPushButton, &QPushButton::clicked, this, &MainWindow::selectSolarisPlayback); + + connect(ui->waveOutputLine, &QLineEdit::textChanged, this, &MainWindow::enableApplyButton); + connect(ui->waveOutputButton, &QPushButton::clicked, this, &MainWindow::selectWaveOutput); + connect(ui->waveBFormatCheckBox, &QCheckBox::stateChanged, this, &MainWindow::enableApplyButton); ui->backendListWidget->setCurrentRow(0); ui->tabWidget->setCurrentIndex(0); @@ -481,8 +483,7 @@ void MainWindow::closeEvent(QCloseEvent *event) { QMessageBox::StandardButton btn = QMessageBox::warning(this, tr("Apply changes?"), tr("Save changes before quitting?"), - QMessageBox::Save | QMessageBox::No | QMessageBox::Cancel - ); + QMessageBox::Save | QMessageBox::No | QMessageBox::Cancel); if(btn == QMessageBox::Save) saveCurrentConfig(); if(btn == QMessageBox::Cancel) @@ -503,8 +504,7 @@ void MainWindow::showAboutPage() { QMessageBox::information(this, tr("About"), tr("OpenAL Soft Configuration Utility.\nBuilt for OpenAL Soft library version ")+ - (ALSOFT_VERSION "-" ALSOFT_GIT_COMMIT_HASH " (" ALSOFT_GIT_BRANCH " branch).") - ); + (ALSOFT_VERSION "-" ALSOFT_GIT_COMMIT_HASH " (" ALSOFT_GIT_BRANCH " branch).")); } @@ -521,17 +521,17 @@ QStringList MainWindow::collectHrtfs() { if(!fname.endsWith(".mhr", Qt::CaseInsensitive)) continue; - QString fullname = dir.absoluteFilePath(fname); + QString fullname{dir.absoluteFilePath(fname)}; if(processed.contains(fullname)) continue; processed.push_back(fullname); - QString name = fname.left(fname.length()-4); + QString name{fname.left(fname.length()-4)}; if(!ret.contains(name)) ret.push_back(name); else { - size_t i = 2; + size_t i{2}; do { QString s = name+" #"+QString::number(i); if(!ret.contains(s)) @@ -550,25 +550,25 @@ QStringList MainWindow::collectHrtfs() QStringList paths = getAllDataPaths("/openal/hrtf"); foreach(const QString &name, paths) { - QDir dir(name); - QStringList fnames = dir.entryList(QDir::Files | QDir::Readable, QDir::Name); + QDir dir{name}; + QStringList fnames{dir.entryList(QDir::Files | QDir::Readable, QDir::Name)}; foreach(const QString &fname, fnames) { if(!fname.endsWith(".mhr", Qt::CaseInsensitive)) continue; - QString fullname = dir.absoluteFilePath(fname); + QString fullname{dir.absoluteFilePath(fname)}; if(processed.contains(fullname)) continue; processed.push_back(fullname); - QString name = fname.left(fname.length()-4); + QString name{fname.left(fname.length()-4)}; if(!ret.contains(name)) ret.push_back(name); else { - size_t i = 2; + size_t i{2}; do { - QString s = name+" #"+QString::number(i); + QString s{name+" #"+QString::number(i)}; if(!ret.contains(s)) { ret.push_back(s); @@ -598,33 +598,33 @@ void MainWindow::loadConfigFromFile() void MainWindow::loadConfig(const QString &fname) { - QSettings settings(fname, QSettings::IniFormat); + QSettings settings{fname, QSettings::IniFormat}; QString sampletype = settings.value("sample-type").toString(); ui->sampleFormatCombo->setCurrentIndex(0); if(sampletype.isEmpty() == false) { - QString str = getNameFromValue(sampleTypeList, sampletype); + QString str{getNameFromValue(sampleTypeList, sampletype)}; if(!str.isEmpty()) { - int j = ui->sampleFormatCombo->findText(str); + const int j{ui->sampleFormatCombo->findText(str)}; if(j > 0) ui->sampleFormatCombo->setCurrentIndex(j); } } - QString channelconfig = settings.value("channels").toString(); + QString channelconfig{settings.value("channels").toString()}; ui->channelConfigCombo->setCurrentIndex(0); if(channelconfig.isEmpty() == false) { - QString str = getNameFromValue(speakerModeList, channelconfig); + QString str{getNameFromValue(speakerModeList, channelconfig)}; if(!str.isEmpty()) { - int j = ui->channelConfigCombo->findText(str); + const int j{ui->channelConfigCombo->findText(str)}; if(j > 0) ui->channelConfigCombo->setCurrentIndex(j); } } - QString srate = settings.value("frequency").toString(); + QString srate{settings.value("frequency").toString()}; if(srate.isEmpty()) ui->sampleRateCombo->setCurrentIndex(0); else @@ -665,15 +665,15 @@ void MainWindow::loadConfig(const QString &fname) ui->stereoModeCombo->setCurrentIndex(0); if(stereomode.isEmpty() == false) { - QString str = getNameFromValue(stereoModeList, stereomode); + QString str{getNameFromValue(stereoModeList, stereomode)}; if(!str.isEmpty()) { - int j = ui->stereoModeCombo->findText(str); + const int j{ui->stereoModeCombo->findText(str)}; if(j > 0) ui->stereoModeCombo->setCurrentIndex(j); } } - int periodsize = settings.value("period_size").toInt(); + int periodsize{settings.value("period_size").toInt()}; ui->periodSizeEdit->clear(); if(periodsize >= 64) { @@ -681,7 +681,7 @@ void MainWindow::loadConfig(const QString &fname) updatePeriodSizeSlider(); } - int periodcount = settings.value("periods").toInt(); + int periodcount{settings.value("periods").toInt()}; ui->periodCountEdit->clear(); if(periodcount >= 2) { @@ -692,35 +692,35 @@ void MainWindow::loadConfig(const QString &fname) ui->outputLimiterCheckBox->setCheckState(getCheckState(settings.value("output-limiter"))); ui->outputDitherCheckBox->setCheckState(getCheckState(settings.value("dither"))); - QString stereopan = settings.value("stereo-encoding").toString(); + QString stereopan{settings.value("stereo-encoding").toString()}; ui->stereoEncodingComboBox->setCurrentIndex(0); if(stereopan.isEmpty() == false) { - QString str = getNameFromValue(stereoEncList, stereopan); + QString str{getNameFromValue(stereoEncList, stereopan)}; if(!str.isEmpty()) { - int j = ui->stereoEncodingComboBox->findText(str); + const int j{ui->stereoEncodingComboBox->findText(str)}; if(j > 0) ui->stereoEncodingComboBox->setCurrentIndex(j); } } - QString ambiformat = settings.value("ambi-format").toString(); + QString ambiformat{settings.value("ambi-format").toString()}; ui->ambiFormatComboBox->setCurrentIndex(0); if(ambiformat.isEmpty() == false) { - QString str = getNameFromValue(ambiFormatList, ambiformat); + QString str{getNameFromValue(ambiFormatList, ambiformat)}; if(!str.isEmpty()) { - int j = ui->ambiFormatComboBox->findText(str); + const int j{ui->ambiFormatComboBox->findText(str)}; if(j > 0) ui->ambiFormatComboBox->setCurrentIndex(j); } } - bool hqmode = settings.value("decoder/hq-mode", false).toBool(); + bool hqmode{settings.value("decoder/hq-mode", false).toBool()}; ui->decoderHQModeCheckBox->setChecked(hqmode); ui->decoderDistCompCheckBox->setCheckState(getCheckState(settings.value("decoder/distance-comp"))); ui->decoderNFEffectsCheckBox->setCheckState(getCheckState(settings.value("decoder/nfc"))); - double refdelay = settings.value("decoder/nfc-ref-delay", 0.0).toDouble(); + double refdelay{settings.value("decoder/nfc-ref-delay", 0.0).toDouble()}; ui->decoderNFRefDelaySpinBox->setValue(refdelay); ui->decoderQuadLineEdit->setText(settings.value("decoder/quad").toString()); @@ -728,18 +728,18 @@ void MainWindow::loadConfig(const QString &fname) ui->decoder61LineEdit->setText(settings.value("decoder/surround61").toString()); ui->decoder71LineEdit->setText(settings.value("decoder/surround71").toString()); - QStringList disabledCpuExts = settings.value("disable-cpu-exts").toStringList(); + QStringList disabledCpuExts{settings.value("disable-cpu-exts").toStringList()}; if(disabledCpuExts.size() == 1) disabledCpuExts = disabledCpuExts[0].split(QChar(',')); - for(QStringList::iterator iter = disabledCpuExts.begin();iter != disabledCpuExts.end();iter++) - *iter = iter->trimmed(); + for(QString &name : disabledCpuExts) + name = name.trimmed(); ui->enableSSECheckBox->setChecked(!disabledCpuExts.contains("sse", Qt::CaseInsensitive)); ui->enableSSE2CheckBox->setChecked(!disabledCpuExts.contains("sse2", Qt::CaseInsensitive)); ui->enableSSE3CheckBox->setChecked(!disabledCpuExts.contains("sse3", Qt::CaseInsensitive)); ui->enableSSE41CheckBox->setChecked(!disabledCpuExts.contains("sse4.1", Qt::CaseInsensitive)); ui->enableNeonCheckBox->setChecked(!disabledCpuExts.contains("neon", Qt::CaseInsensitive)); - QString hrtfmode = settings.value("hrtf-mode").toString().trimmed(); + QString hrtfmode{settings.value("hrtf-mode").toString().trimmed()}; ui->hrtfmodeSlider->setValue(3); ui->hrtfmodeLabel->setText(hrtfModeList[3].name); /* The "basic" mode name is no longer supported. Use "ambi2" instead. */ @@ -754,11 +754,11 @@ void MainWindow::loadConfig(const QString &fname) } } - QStringList hrtf_paths = settings.value("hrtf-paths").toStringList(); + QStringList hrtf_paths{settings.value("hrtf-paths").toStringList()}; if(hrtf_paths.size() == 1) hrtf_paths = hrtf_paths[0].split(QChar(',')); - for(QStringList::iterator iter = hrtf_paths.begin();iter != hrtf_paths.end();iter++) - *iter = iter->trimmed(); + for(QString &name : hrtf_paths) + name = name.trimmed(); if(!hrtf_paths.empty() && !hrtf_paths.back().isEmpty()) ui->defaultHrtfPathsCheckBox->setCheckState(Qt::Unchecked); else @@ -771,7 +771,7 @@ void MainWindow::loadConfig(const QString &fname) ui->hrtfFileList->addItems(hrtf_paths); updateHrtfRemoveButton(); - QString hrtfstate = settings.value("hrtf").toString().toLower(); + QString hrtfstate{settings.value("hrtf").toString().toLower()}; if(hrtfstate == "true") ui->hrtfStateComboBox->setCurrentIndex(1); else if(hrtfstate == "false") @@ -783,16 +783,16 @@ void MainWindow::loadConfig(const QString &fname) ui->preferredHrtfComboBox->addItem("- Any -"); if(ui->defaultHrtfPathsCheckBox->isChecked()) { - QStringList hrtfs = collectHrtfs(); + QStringList hrtfs{collectHrtfs()}; foreach(const QString &name, hrtfs) ui->preferredHrtfComboBox->addItem(name); } - QString defaulthrtf = settings.value("default-hrtf").toString(); + QString defaulthrtf{settings.value("default-hrtf").toString()}; ui->preferredHrtfComboBox->setCurrentIndex(0); if(defaulthrtf.isEmpty() == false) { - int i = ui->preferredHrtfComboBox->findText(defaulthrtf); + int i{ui->preferredHrtfComboBox->findText(defaulthrtf)}; if(i > 0) ui->preferredHrtfComboBox->setCurrentIndex(i); else @@ -806,23 +806,23 @@ void MainWindow::loadConfig(const QString &fname) ui->enabledBackendList->clear(); ui->disabledBackendList->clear(); - QStringList drivers = settings.value("drivers").toStringList(); + QStringList drivers{settings.value("drivers").toStringList()}; if(drivers.size() == 0) ui->backendCheckBox->setChecked(true); else { if(drivers.size() == 1) drivers = drivers[0].split(QChar(',')); - for(QStringList::iterator iter = drivers.begin();iter != drivers.end();iter++) + for(QString &name : drivers) { - *iter = iter->trimmed(); + name = name.trimmed(); /* Convert "mmdevapi" references to "wasapi" for backwards * compatibility. */ - if(*iter == "-mmdevapi") - *iter = "-wasapi"; - else if(*iter == "mmdevapi") - *iter = "wasapi"; + if(name == "-mmdevapi") + name = "-wasapi"; + else if(name == "mmdevapi") + name = "wasapi"; } bool lastWasEmpty = false; @@ -842,7 +842,7 @@ void MainWindow::loadConfig(const QString &fname) } else if(backend.size() > 1) { - QStringRef backendref = backend.rightRef(backend.size()-1); + QStringRef backendref{backend.rightRef(backend.size()-1)}; for(int j = 0;backendList[j].backend_name[0];j++) { if(backendref == backendList[j].backend_name) @@ -856,7 +856,7 @@ void MainWindow::loadConfig(const QString &fname) ui->backendCheckBox->setChecked(lastWasEmpty); } - QString defaultreverb = settings.value("default-reverb").toString().toLower(); + QString defaultreverb{settings.value("default-reverb").toString().toLower()}; ui->defaultReverbComboBox->setCurrentIndex(0); if(defaultreverb.isEmpty() == false) { @@ -870,11 +870,11 @@ void MainWindow::loadConfig(const QString &fname) } } - QStringList excludefx = settings.value("excludefx").toStringList(); + QStringList excludefx{settings.value("excludefx").toStringList()}; if(excludefx.size() == 1) excludefx = excludefx[0].split(QChar(',')); - for(QStringList::iterator iter = excludefx.begin();iter != excludefx.end();iter++) - *iter = iter->trimmed(); + for(QString &name : excludefx) + name = name.trimmed(); ui->enableEaxReverbCheck->setChecked(!excludefx.contains("eaxreverb", Qt::CaseInsensitive)); ui->enableStdReverbCheck->setChecked(!excludefx.contains("reverb", Qt::CaseInsensitive)); ui->enableAutowahCheck->setChecked(!excludefx.contains("autowah", Qt::CaseInsensitive)); @@ -929,7 +929,7 @@ void MainWindow::saveCurrentConfig() void MainWindow::saveConfigAsFile() { - QString fname = QFileDialog::getOpenFileName(this, tr("Select Files")); + QString fname{QFileDialog::getOpenFileName(this, tr("Select Files"))}; if(fname.isEmpty() == false) { saveConfig(fname); @@ -940,13 +940,13 @@ void MainWindow::saveConfigAsFile() void MainWindow::saveConfig(const QString &fname) const { - QSettings settings(fname, QSettings::IniFormat); + QSettings settings{fname, QSettings::IniFormat}; /* HACK: Compound any stringlist values into a comma-separated string. */ - QStringList allkeys = settings.allKeys(); + QStringList allkeys{settings.allKeys()}; foreach(const QString &key, allkeys) { - QStringList vals = settings.value(key).toStringList(); + QStringList vals{settings.value(key).toStringList()}; if(vals.size() > 1) settings.setValue(key, vals.join(QChar(','))); } @@ -954,9 +954,9 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("sample-type", getValueFromName(sampleTypeList, ui->sampleFormatCombo->currentText())); settings.setValue("channels", getValueFromName(speakerModeList, ui->channelConfigCombo->currentText())); - uint rate = ui->sampleRateCombo->currentText().toUInt(); + uint rate{ui->sampleRateCombo->currentText().toUInt()}; if(rate <= 0) - settings.setValue("frequency", QString()); + settings.setValue("frequency", QString{}); else settings.setValue("frequency", rate); @@ -976,13 +976,13 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("dither", getCheckValue(ui->outputDitherCheckBox)); settings.setValue("decoder/hq-mode", - ui->decoderHQModeCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) + ui->decoderHQModeCheckBox->isChecked() ? QString{"true"} : QString{/*"false"*/} ); settings.setValue("decoder/distance-comp", getCheckValue(ui->decoderDistCompCheckBox)); settings.setValue("decoder/nfc", getCheckValue(ui->decoderNFEffectsCheckBox)); double refdelay = ui->decoderNFRefDelaySpinBox->value(); settings.setValue("decoder/nfc-ref-delay", - (refdelay > 0.0) ? QString::number(refdelay) : QString() + (refdelay > 0.0) ? QString::number(refdelay) : QString{} ); settings.setValue("decoder/quad", ui->decoderQuadLineEdit->text()); @@ -1010,27 +1010,28 @@ void MainWindow::saveConfig(const QString &fname) const else if(ui->hrtfStateComboBox->currentIndex() == 2) settings.setValue("hrtf", "false"); else - settings.setValue("hrtf", QString()); + settings.setValue("hrtf", QString{}); if(ui->preferredHrtfComboBox->currentIndex() == 0) - settings.setValue("default-hrtf", QString()); + settings.setValue("default-hrtf", QString{}); else { - QString str = ui->preferredHrtfComboBox->currentText(); + QString str{ui->preferredHrtfComboBox->currentText()}; settings.setValue("default-hrtf", str); } strlist.clear(); + strlist.reserve(ui->hrtfFileList->count()); for(int i = 0;i < ui->hrtfFileList->count();i++) strlist.append(ui->hrtfFileList->item(i)->text()); if(!strlist.empty() && ui->defaultHrtfPathsCheckBox->isChecked()) - strlist.append(QString()); - settings.setValue("hrtf-paths", strlist.join(QChar(','))); + strlist.append(QString{}); + settings.setValue("hrtf-paths", strlist.join(QChar{','})); strlist.clear(); for(int i = 0;i < ui->enabledBackendList->count();i++) { - QString label = ui->enabledBackendList->item(i)->text(); + QString label{ui->enabledBackendList->item(i)->text()}; for(int j = 0;backendList[j].backend_name[0];j++) { if(label == backendList[j].full_string) @@ -1042,12 +1043,12 @@ void MainWindow::saveConfig(const QString &fname) const } for(int i = 0;i < ui->disabledBackendList->count();i++) { - QString label = ui->disabledBackendList->item(i)->text(); + QString label{ui->disabledBackendList->item(i)->text()}; for(int j = 0;backendList[j].backend_name[0];j++) { if(label == backendList[j].full_string) { - strlist.append(QChar('-')+QString(backendList[j].backend_name)); + strlist.append(QChar{'-'}+QString{backendList[j].backend_name}); break; } } @@ -1055,15 +1056,15 @@ void MainWindow::saveConfig(const QString &fname) const if(strlist.size() == 0 && !ui->backendCheckBox->isChecked()) strlist.append("-all"); else if(ui->backendCheckBox->isChecked()) - strlist.append(QString()); + strlist.append(QString{}); settings.setValue("drivers", strlist.join(QChar(','))); // TODO: Remove check when we can properly match global values. if(ui->defaultReverbComboBox->currentIndex() == 0) - settings.setValue("default-reverb", QString()); + settings.setValue("default-reverb", QString{}); else { - QString str = ui->defaultReverbComboBox->currentText().toLower(); + QString str{ui->defaultReverbComboBox->currentText().toLower()}; settings.setValue("default-reverb", str); } @@ -1096,7 +1097,7 @@ void MainWindow::saveConfig(const QString &fname) const strlist.append("pshifter"); if(!ui->enableVocalMorpherCheck->isChecked()) strlist.append("vmorpher"); - settings.setValue("excludefx", strlist.join(QChar(','))); + settings.setValue("excludefx", strlist.join(QChar{','})); settings.setValue("pulse/spawn-server", getCheckValue(ui->pulseAutospawnCheckBox)); settings.setValue("pulse/allow-moves", getCheckValue(ui->pulseAllowMovesCheckBox)); @@ -1118,7 +1119,7 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("wave/file", ui->waveOutputLine->text()); settings.setValue("wave/bformat", - ui->waveBFormatCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) + ui->waveBFormatCheckBox->isChecked() ? QString{"true"} : QString{/*"false"*/} ); /* Remove empty keys @@ -1127,8 +1128,8 @@ void MainWindow::saveConfig(const QString &fname) const allkeys = settings.allKeys(); foreach(const QString &key, allkeys) { - QString str = settings.value(key).toString(); - if(str == QString()) + QString str{settings.value(key).toString()}; + if(str == QString{}) settings.remove(key); } } @@ -1200,13 +1201,13 @@ void MainWindow::select71DecoderFile() { selectDecoderFile(ui->decoder71LineEdit, "Select 7.1 Surround Decoder");} void MainWindow::selectDecoderFile(QLineEdit *line, const char *caption) { - QString dir = line->text(); + QString dir{line->text()}; if(dir.isEmpty() || QDir::isRelativePath(dir)) { - QStringList paths = getAllDataPaths("/openal/presets"); + QStringList paths{getAllDataPaths("/openal/presets")}; while(!paths.isEmpty()) { - if(QDir(paths.last()).exists()) + if(QDir{paths.last()}.exists()) { dir = paths.last(); break; @@ -1214,9 +1215,8 @@ void MainWindow::selectDecoderFile(QLineEdit *line, const char *caption) paths.removeLast(); } } - QString fname = QFileDialog::getOpenFileName(this, tr(caption), - dir, tr("AmbDec Files (*.ambdec);;All Files (*.*)") - ); + QString fname{QFileDialog::getOpenFileName(this, tr(caption), + dir, tr("AmbDec Files (*.ambdec);;All Files (*.*)"))}; if(!fname.isEmpty()) { line->setText(fname); @@ -1235,8 +1235,8 @@ void MainWindow::updateJackBufferSizeEdit(int size) void MainWindow::updateJackBufferSizeSlider() { - int value = ui->jackBufferSizeLine->text().toInt(); - int pos = static_cast(floor(log2(value) + 0.5)); + int value{ui->jackBufferSizeLine->text().toInt()}; + auto pos = static_cast(floor(log2(value) + 0.5)); ui->jackBufferSizeSlider->setSliderPosition(pos); enableApplyButton(); } @@ -1251,7 +1251,7 @@ void MainWindow::updateHrtfModeLabel(int num) void MainWindow::addHrtfFile() { - QString path = QFileDialog::getExistingDirectory(this, tr("Select HRTF Path")); + QString path{QFileDialog::getExistingDirectory(this, tr("Select HRTF Path"))}; if(path.isEmpty() == false && !getAllDataPaths("/openal/hrtf").contains(path)) { ui->hrtfFileList->addItem(path); @@ -1261,7 +1261,7 @@ void MainWindow::addHrtfFile() void MainWindow::removeHrtfFile() { - QList selected = ui->hrtfFileList->selectedItems(); + QList selected{ui->hrtfFileList->selectedItems()}; if(!selected.isEmpty()) { foreach(QListWidgetItem *item, selected) @@ -1277,37 +1277,37 @@ void MainWindow::updateHrtfRemoveButton() void MainWindow::showEnabledBackendMenu(QPoint pt) { - QMap actionMap; + QHash actionMap; pt = ui->enabledBackendList->mapToGlobal(pt); QMenu ctxmenu; - QAction *removeAction = ctxmenu.addAction(QIcon::fromTheme("list-remove"), "Remove"); + QAction *removeAction{ctxmenu.addAction(QIcon::fromTheme("list-remove"), "Remove")}; if(ui->enabledBackendList->selectedItems().size() == 0) removeAction->setEnabled(false); ctxmenu.addSeparator(); for(size_t i = 0;backendList[i].backend_name[0];i++) { - QString backend = backendList[i].full_string; - QAction *action = ctxmenu.addAction(QString("Add ")+backend); + QString backend{backendList[i].full_string}; + QAction *action{ctxmenu.addAction(QString("Add ")+backend)}; actionMap[action] = backend; if(ui->enabledBackendList->findItems(backend, Qt::MatchFixedString).size() != 0 || ui->disabledBackendList->findItems(backend, Qt::MatchFixedString).size() != 0) action->setEnabled(false); } - QAction *gotAction = ctxmenu.exec(pt); + QAction *gotAction{ctxmenu.exec(pt)}; if(gotAction == removeAction) { - QList selected = ui->enabledBackendList->selectedItems(); + QList selected{ui->enabledBackendList->selectedItems()}; foreach(QListWidgetItem *item, selected) delete item; enableApplyButton(); } else if(gotAction != nullptr) { - QMap::const_iterator iter = actionMap.find(gotAction); - if(iter != actionMap.end()) + auto iter = actionMap.constFind(gotAction); + if(iter != actionMap.cend()) ui->enabledBackendList->addItem(iter.value()); enableApplyButton(); } @@ -1315,37 +1315,37 @@ void MainWindow::showEnabledBackendMenu(QPoint pt) void MainWindow::showDisabledBackendMenu(QPoint pt) { - QMap actionMap; + QHash actionMap; pt = ui->disabledBackendList->mapToGlobal(pt); QMenu ctxmenu; - QAction *removeAction = ctxmenu.addAction(QIcon::fromTheme("list-remove"), "Remove"); + QAction *removeAction{ctxmenu.addAction(QIcon::fromTheme("list-remove"), "Remove")}; if(ui->disabledBackendList->selectedItems().size() == 0) removeAction->setEnabled(false); ctxmenu.addSeparator(); for(size_t i = 0;backendList[i].backend_name[0];i++) { - QString backend = backendList[i].full_string; - QAction *action = ctxmenu.addAction(QString("Add ")+backend); + QString backend{backendList[i].full_string}; + QAction *action{ctxmenu.addAction(QString("Add ")+backend)}; actionMap[action] = backend; if(ui->disabledBackendList->findItems(backend, Qt::MatchFixedString).size() != 0 || ui->enabledBackendList->findItems(backend, Qt::MatchFixedString).size() != 0) action->setEnabled(false); } - QAction *gotAction = ctxmenu.exec(pt); + QAction *gotAction{ctxmenu.exec(pt)}; if(gotAction == removeAction) { - QList selected = ui->disabledBackendList->selectedItems(); + QList selected{ui->disabledBackendList->selectedItems()}; foreach(QListWidgetItem *item, selected) delete item; enableApplyButton(); } else if(gotAction != nullptr) { - QMap::const_iterator iter = actionMap.find(gotAction); - if(iter != actionMap.end()) + auto iter = actionMap.constFind(gotAction); + if(iter != actionMap.cend()) ui->disabledBackendList->addItem(iter.value()); enableApplyButton(); } @@ -1353,9 +1353,9 @@ void MainWindow::showDisabledBackendMenu(QPoint pt) void MainWindow::selectOSSPlayback() { - QString current = ui->ossDefaultDeviceLine->text(); + QString current{ui->ossDefaultDeviceLine->text()}; if(current.isEmpty()) current = ui->ossDefaultDeviceLine->placeholderText(); - QString fname = QFileDialog::getOpenFileName(this, tr("Select Playback Device"), current); + QString fname{QFileDialog::getOpenFileName(this, tr("Select Playback Device"), current)}; if(!fname.isEmpty()) { ui->ossDefaultDeviceLine->setText(fname); @@ -1365,9 +1365,9 @@ void MainWindow::selectOSSPlayback() void MainWindow::selectOSSCapture() { - QString current = ui->ossDefaultCaptureLine->text(); + QString current{ui->ossDefaultCaptureLine->text()}; if(current.isEmpty()) current = ui->ossDefaultCaptureLine->placeholderText(); - QString fname = QFileDialog::getOpenFileName(this, tr("Select Capture Device"), current); + QString fname{QFileDialog::getOpenFileName(this, tr("Select Capture Device"), current)}; if(!fname.isEmpty()) { ui->ossDefaultCaptureLine->setText(fname); @@ -1377,9 +1377,9 @@ void MainWindow::selectOSSCapture() void MainWindow::selectSolarisPlayback() { - QString current = ui->solarisDefaultDeviceLine->text(); + QString current{ui->solarisDefaultDeviceLine->text()}; if(current.isEmpty()) current = ui->solarisDefaultDeviceLine->placeholderText(); - QString fname = QFileDialog::getOpenFileName(this, tr("Select Playback Device"), current); + QString fname{QFileDialog::getOpenFileName(this, tr("Select Playback Device"), current)}; if(!fname.isEmpty()) { ui->solarisDefaultDeviceLine->setText(fname); @@ -1389,9 +1389,8 @@ void MainWindow::selectSolarisPlayback() void MainWindow::selectWaveOutput() { - QString fname = QFileDialog::getSaveFileName(this, tr("Select Wave File Output"), - ui->waveOutputLine->text(), tr("Wave Files (*.wav *.amb);;All Files (*.*)") - ); + QString fname{QFileDialog::getSaveFileName(this, tr("Select Wave File Output"), + ui->waveOutputLine->text(), tr("Wave Files (*.wav *.amb);;All Files (*.*)"))}; if(!fname.isEmpty()) { ui->waveOutputLine->setText(fname); -- cgit v1.2.3 From 5b6772440a60399a662877b953b36164f33dc7d8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 27 Aug 2019 12:31:19 -0700 Subject: Remove a couple unnecessary variables --- alc/effects/reverb.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 2caf9025..6017f6d1 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -192,7 +192,6 @@ constexpr std::array EARLY_LINE_LENGTHS{{ constexpr std::array LATE_ALLPASS_LENGTHS{{ 1.6182800e-4f, 2.0389060e-4f, 2.8159360e-4f, 3.2365600e-4f }}; -constexpr auto LATE_ALLPASS_LENGTHS_size = LATE_ALLPASS_LENGTHS.size(); /* The late lines are used to approximate the decaying cycle of recursive * late reflections. @@ -212,7 +211,6 @@ constexpr auto LATE_ALLPASS_LENGTHS_size = LATE_ALLPASS_LENGTHS.size(); constexpr std::array LATE_LINE_LENGTHS{{ 1.9419362e-3f, 2.4466860e-3f, 3.3791220e-3f, 3.8838720e-3f }}; -constexpr auto LATE_LINE_LENGTHS_size = LATE_LINE_LENGTHS.size(); using ReverbUpdateLine = std::array; @@ -518,7 +516,7 @@ bool ReverbState::allocLines(const ALfloat frequency) */ ALfloat length{AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS.back()*multiplier + AL_EAXREVERB_MAX_LATE_REVERB_DELAY + - (LATE_LINE_LENGTHS.back() - LATE_LINE_LENGTHS.front())/float{LATE_LINE_LENGTHS_size}*multiplier}; + (LATE_LINE_LENGTHS.back() - LATE_LINE_LENGTHS.front())/float{NUM_LINES}*multiplier}; totalSamples += mDelay.calcLineLength(length, totalSamples, frequency, BUFFERSIZE); /* The early vector all-pass line. */ @@ -756,7 +754,7 @@ void LateReverb::updateLines(const ALfloat density, const ALfloat diffusion, const ALfloat late_allpass_avg{ std::accumulate(LATE_ALLPASS_LENGTHS.begin(), LATE_ALLPASS_LENGTHS.end(), 0.0f) / - float{LATE_ALLPASS_LENGTHS_size}}; + float{NUM_LINES}}; /* To compensate for changes in modal density and decay time of the late * reverb signal, the input is attenuated based on the maximal energy of @@ -768,7 +766,7 @@ void LateReverb::updateLines(const ALfloat density, const ALfloat diffusion, */ const ALfloat multiplier{CalcDelayLengthMult(density)}; ALfloat length{std::accumulate(LATE_LINE_LENGTHS.begin(), LATE_LINE_LENGTHS.end(), 0.0f) / - float{LATE_LINE_LENGTHS_size} * multiplier}; + float{NUM_LINES} * multiplier}; length += late_allpass_avg * multiplier; /* The density gain calculation uses an average decay time weighted by * approximate bandwidth. This attempts to compensate for losses of energy @@ -833,8 +831,8 @@ void ReverbState::updateDelayLine(const ALfloat earlyDelay, const ALfloat lateDe length = EARLY_TAP_LENGTHS[i]*multiplier; mEarlyDelayCoeff[i][1] = CalcDecayCoeff(length, decayTime); - length = lateDelay + (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS.front()) / - float{LATE_LINE_LENGTHS_size} * multiplier; + length = (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS.front())/float{NUM_LINES}*multiplier + + lateDelay; mLateDelayTap[i][1] = mLateFeedTap + float2int(length * frequency); } } -- cgit v1.2.3 From a546343148ad87786b1a199e9ca91ffc50da4e81 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 31 Aug 2019 14:53:28 -0700 Subject: Make MixVoice a member function --- alc/alu.cpp | 6 +--- alc/alu.h | 4 +-- alc/mixvoice.cpp | 103 ++++++++++++++++++++++++++++--------------------------- 3 files changed, 55 insertions(+), 58 deletions(-) diff --git a/alc/alu.cpp b/alc/alu.cpp index 7f3f286b..869346c4 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -1368,11 +1368,7 @@ void ProcessContext(ALCcontext *ctx, const ALuint SamplesToDo) [SamplesToDo,ctx](ALvoice &voice) -> void { const ALvoice::State vstate{voice.mPlayState.load(std::memory_order_acquire)}; - if(vstate == ALvoice::Stopped) return; - const ALuint sid{voice.mSourceID.load(std::memory_order_relaxed)}; - if(voice.mStep < 1) return; - - MixVoice(&voice, vstate, sid, ctx, SamplesToDo); + if(vstate != ALvoice::Stopped) voice.mix(vstate, ctx, SamplesToDo); } ); diff --git a/alc/alu.h b/alc/alu.h index df20ea4a..da6f6a94 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -310,6 +310,8 @@ struct ALvoice { return *this; } + + void mix(ALvoice::State vstate, ALCcontext *Context, const ALuint SamplesToDo); }; @@ -444,8 +446,6 @@ inline std::array GetAmbiIdentityRow(size_t i) noexce } -void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCcontext *Context, const ALuint SamplesToDo); - void aluMixData(ALCdevice *device, ALvoid *OutBuffer, const ALuint NumSamples); /* Caller must lock the device state, and the mixer must not be running. */ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) DECL_FORMAT(printf, 2, 3); diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 6bdbdec1..97583107 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -320,9 +320,6 @@ struct FmtTypeTraits { void SendSourceStoppedEvent(ALCcontext *context, ALuint id) { - ALbitfieldSOFT enabledevt{context->mEnabledEvts.load(std::memory_order_acquire)}; - if(!(enabledevt&EventType_SourceStateChange)) return; - RingBuffer *ring{context->mAsyncEvents.get()}; auto evt_vec = ring->getWriteVector(); if(evt_vec.first.len < 1) return; @@ -476,21 +473,22 @@ ALfloat *LoadBufferQueue(ALbufferlistitem *BufferListItem, ALbufferlistitem *Buf } // namespace -void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCcontext *Context, const ALuint SamplesToDo) +void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) { static constexpr ALfloat SilentTarget[MAX_OUTPUT_CHANNELS]{}; ASSUME(SamplesToDo > 0); /* Get voice info */ - const bool isstatic{(voice->mFlags&VOICE_IS_STATIC) != 0}; - ALuint DataPosInt{voice->mPosition.load(std::memory_order_relaxed)}; - ALsizei DataPosFrac{voice->mPositionFrac.load(std::memory_order_relaxed)}; - ALbufferlistitem *BufferListItem{voice->mCurrentBuffer.load(std::memory_order_relaxed)}; - ALbufferlistitem *BufferLoopItem{voice->mLoopBuffer.load(std::memory_order_relaxed)}; - const ALsizei NumChannels{voice->mNumChannels}; - const ALsizei SampleSize{voice->mSampleSize}; - const ALint increment{voice->mStep}; + const bool isstatic{(mFlags&VOICE_IS_STATIC) != 0}; + ALuint DataPosInt{mPosition.load(std::memory_order_relaxed)}; + ALsizei DataPosFrac{mPositionFrac.load(std::memory_order_relaxed)}; + ALbufferlistitem *BufferListItem{mCurrentBuffer.load(std::memory_order_relaxed)}; + ALbufferlistitem *BufferLoopItem{mLoopBuffer.load(std::memory_order_relaxed)}; + const ALsizei NumChannels{mNumChannels}; + const ALsizei SampleSize{mSampleSize}; + const ALint increment{mStep}; + if(increment < 1) return; ASSUME(DataPosFrac >= 0); ASSUME(NumChannels > 0); @@ -505,24 +503,24 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc ASSUME(IrSize >= 0); ResamplerFunc Resample{(increment == FRACTIONONE && DataPosFrac == 0) ? - Resample_ : voice->mResampler}; + Resample_ : mResampler}; - ALuint Counter{(voice->mFlags&VOICE_IS_FADING) ? SamplesToDo : 0}; + ALuint Counter{(mFlags&VOICE_IS_FADING) ? SamplesToDo : 0}; if(!Counter) { /* No fading, just overwrite the old/current params. */ for(ALsizei chan{0};chan < NumChannels;chan++) { - ALvoice::ChannelData &chandata = voice->mChans[chan]; + ChannelData &chandata = mChans[chan]; DirectParams &parms = chandata.mDryParams; - if(!(voice->mFlags&VOICE_HAS_HRTF)) + if(!(mFlags&VOICE_HAS_HRTF)) std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target), std::begin(parms.Gains.Current)); else parms.Hrtf.Old = parms.Hrtf.Target; for(ALsizei send{0};send < NumSends;++send) { - if(voice->mSend[send].Buffer.empty()) + if(mSend[send].Buffer.empty()) continue; SendParams &parms = chandata.mWetParams[send]; @@ -531,11 +529,11 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc } } } - else if((voice->mFlags&VOICE_HAS_HRTF)) + else if((mFlags&VOICE_HAS_HRTF)) { for(ALsizei chan{0};chan < NumChannels;chan++) { - DirectParams &parms = voice->mChans[chan].mDryParams; + DirectParams &parms = mChans[chan].mDryParams; if(!(parms.Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD)) { /* The old HRTF params are silent, so overwrite the old @@ -584,7 +582,7 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc ASSUME(DstBufferSize > 0); for(ALsizei chan{0};chan < NumChannels;chan++) { - ALvoice::ChannelData &chandata = voice->mChans[chan]; + ChannelData &chandata = mChans[chan]; const al::span SrcData{Device->SourceData, SrcBufferSize}; /* Load the previous samples into the source data first, then load @@ -619,10 +617,10 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc chandata.mPrevSamples.size(), chandata.mPrevSamples.begin()); /* Resample, then apply ambisonic upsampling as needed. */ - const ALfloat *ResampledData{Resample(&voice->mResampleState, + const ALfloat *ResampledData{Resample(&mResampleState, &SrcData[MAX_RESAMPLE_PADDING], DataPosFrac, increment, {Device->ResampledData, DstBufferSize})}; - if((voice->mFlags&VOICE_IS_AMBISONIC)) + if((mFlags&VOICE_IS_AMBISONIC)) { const ALfloat hfscale{chandata.mAmbiScale}; /* Beware the evil const_cast. It's safe since it's pointing to @@ -639,10 +637,9 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc { DirectParams &parms = chandata.mDryParams; const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, - Device->FilteredData, ResampledData, DstBufferSize, - voice->mDirect.FilterType)}; + Device->FilteredData, ResampledData, DstBufferSize, mDirect.FilterType)}; - if((voice->mFlags&VOICE_HAS_HRTF)) + if((mFlags&VOICE_HAS_HRTF)) { const int OutLIdx{GetChannelIdxByName(Device->RealOut, FrontLeft)}; const int OutRIdx{GetChannelIdxByName(Device->RealOut, FrontRight)}; @@ -705,9 +702,9 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc hrtfparams.Gain = 0.0f; hrtfparams.GainStep = gain / static_cast(fademix); - MixHrtfBlendSamples(voice->mDirect.Buffer[OutLIdx], - voice->mDirect.Buffer[OutRIdx], HrtfSamples, AccumSamples, OutPos, - IrSize, &parms.Hrtf.Old, &hrtfparams, fademix); + MixHrtfBlendSamples(mDirect.Buffer[OutLIdx], mDirect.Buffer[OutRIdx], + HrtfSamples, AccumSamples, OutPos, IrSize, &parms.Hrtf.Old, + &hrtfparams, fademix); /* Update the old parameters with the result. */ parms.Hrtf.Old = parms.Hrtf.Target; if(fademix < Counter) @@ -738,9 +735,9 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc hrtfparams.Gain = parms.Hrtf.Old.Gain; hrtfparams.GainStep = (gain - parms.Hrtf.Old.Gain) / static_cast(todo); - MixHrtfSamples(voice->mDirect.Buffer[OutLIdx], - voice->mDirect.Buffer[OutRIdx], HrtfSamples+fademix, - AccumSamples+fademix, OutPos+fademix, IrSize, &hrtfparams, todo); + MixHrtfSamples(mDirect.Buffer[OutLIdx], mDirect.Buffer[OutRIdx], + HrtfSamples+fademix, AccumSamples+fademix, OutPos+fademix, IrSize, + &hrtfparams, todo); /* Store the interpolated gain or the final target gain * depending if the fade is done. */ @@ -756,23 +753,23 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc std::copy_n(std::begin(AccumSamples) + DstBufferSize, parms.Hrtf.State.Values.size(), parms.Hrtf.State.Values.begin()); } - else if((voice->mFlags&VOICE_HAS_NFC)) + else if((mFlags&VOICE_HAS_NFC)) { const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? SilentTarget : parms.Gains.Target}; const size_t outcount{Device->NumChannelsPerOrder[0]}; - MixSamples({samples, DstBufferSize}, voice->mDirect.Buffer.first(outcount), + MixSamples({samples, DstBufferSize}, mDirect.Buffer.first(outcount), parms.Gains.Current, TargetGains, Counter, OutPos); const al::span nfcsamples{Device->NfcSampleData, DstBufferSize}; size_t chanoffset{outcount}; using FilterProc = void (NfcFilter::*)(float*,const float*,const size_t); - auto apply_nfc = [voice,&parms,samples,TargetGains,Counter,OutPos,&chanoffset,nfcsamples](const FilterProc process, const size_t outcount) -> void + auto apply_nfc = [this,&parms,samples,TargetGains,Counter,OutPos,&chanoffset,nfcsamples](const FilterProc process, const size_t outcount) -> void { if(outcount < 1) return; (parms.NFCtrlFilter.*process)(nfcsamples.data(), samples, nfcsamples.size()); - MixSamples(nfcsamples, voice->mDirect.Buffer.subspan(chanoffset, outcount), + MixSamples(nfcsamples, mDirect.Buffer.subspan(chanoffset, outcount), parms.Gains.Current+chanoffset, TargetGains+chanoffset, Counter, OutPos); chanoffset += outcount; @@ -785,25 +782,25 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc { const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? SilentTarget : parms.Gains.Target}; - MixSamples({samples, DstBufferSize}, voice->mDirect.Buffer, - parms.Gains.Current, TargetGains, Counter, OutPos); + MixSamples({samples, DstBufferSize}, mDirect.Buffer, parms.Gains.Current, + TargetGains, Counter, OutPos); } } ALfloat (&FilterBuf)[BUFFERSIZE] = Device->FilteredData; for(ALsizei send{0};send < NumSends;++send) { - if(voice->mSend[send].Buffer.empty()) + if(mSend[send].Buffer.empty()) continue; SendParams &parms = chandata.mWetParams[send]; const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, - FilterBuf, ResampledData, DstBufferSize, voice->mSend[send].FilterType)}; + FilterBuf, ResampledData, DstBufferSize, mSend[send].FilterType)}; const ALfloat *TargetGains{UNLIKELY(vstate==ALvoice::Stopping) ? SilentTarget : parms.Gains.Target}; - MixSamples({samples, DstBufferSize}, voice->mSend[send].Buffer, - parms.Gains.Current, TargetGains, Counter, OutPos); + MixSamples({samples, DstBufferSize}, mSend[send].Buffer, parms.Gains.Current, + TargetGains, Counter, OutPos); }; } /* Update positions */ @@ -863,28 +860,31 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc } } while(OutPos < SamplesToDo); - voice->mFlags |= VOICE_IS_FADING; + mFlags |= VOICE_IS_FADING; /* Don't update positions and buffers if we were stopping. */ if UNLIKELY(vstate == ALvoice::Stopping) { - voice->mPlayState.store(ALvoice::Stopped, std::memory_order_release); + mPlayState.store(ALvoice::Stopped, std::memory_order_release); return; } + /* Capture the source ID in case it's reset for stopping. */ + const ALuint SourceID{mSourceID.load(std::memory_order_relaxed)}; + /* Update voice info */ - voice->mPosition.store(DataPosInt, std::memory_order_relaxed); - voice->mPositionFrac.store(DataPosFrac, std::memory_order_relaxed); - voice->mCurrentBuffer.store(BufferListItem, std::memory_order_relaxed); + mPosition.store(DataPosInt, std::memory_order_relaxed); + mPositionFrac.store(DataPosFrac, std::memory_order_relaxed); + mCurrentBuffer.store(BufferListItem, std::memory_order_relaxed); if(vstate == ALvoice::Stopped) { - voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); - voice->mSourceID.store(0u, std::memory_order_relaxed); + mLoopBuffer.store(nullptr, std::memory_order_relaxed); + mSourceID.store(0u, std::memory_order_relaxed); } std::atomic_thread_fence(std::memory_order_release); /* Send any events now, after the position/buffer info was updated. */ - ALbitfieldSOFT enabledevt{Context->mEnabledEvts.load(std::memory_order_acquire)}; + const ALbitfieldSOFT enabledevt{Context->mEnabledEvts.load(std::memory_order_acquire)}; if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) { RingBuffer *ring{Context->mAsyncEvents.get()}; @@ -904,7 +904,8 @@ void MixVoice(ALvoice *voice, ALvoice::State vstate, const ALuint SourceID, ALCc /* If the voice just ended, set it to Stopping so the next render * ensures any residual noise fades to 0 amplitude. */ - voice->mPlayState.store(ALvoice::Stopping, std::memory_order_release); - SendSourceStoppedEvent(Context, SourceID); + mPlayState.store(ALvoice::Stopping, std::memory_order_release); + if((enabledevt&EventType_SourceStateChange)) + SendSourceStoppedEvent(Context, SourceID); } } -- cgit v1.2.3 From 3973334a64f0aa428c9cbd06c89cfb60951810c8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 31 Aug 2019 15:49:34 -0700 Subject: Store the voice fraction offset as unsigned --- al/source.cpp | 22 +++++++++++----------- alc/alu.h | 4 ++-- alc/mixer/defs.h | 2 +- alc/mixer/mixer_c.cpp | 27 +++++++++++++-------------- alc/mixer/mixer_neon.cpp | 36 +++++++++++++++++------------------- alc/mixer/mixer_sse.cpp | 9 ++++----- alc/mixer/mixer_sse2.cpp | 9 ++++----- alc/mixer/mixer_sse41.cpp | 9 ++++----- alc/mixvoice.cpp | 3 +-- 9 files changed, 57 insertions(+), 64 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index 49f2fb2a..d9a7cb87 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -195,7 +195,7 @@ int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, std::chrono Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); readPos = uint64_t{voice->mPosition.load(std::memory_order_relaxed)} << 32; - readPos |= int64_t{voice->mPositionFrac.load(std::memory_order_relaxed)} << + readPos |= uint64_t{voice->mPositionFrac.load(std::memory_order_relaxed)} << (32-FRACTIONBITS); } std::atomic_thread_fence(std::memory_order_acquire); @@ -206,7 +206,7 @@ int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, std::chrono const ALbufferlistitem *BufferList{Source->queue}; while(BufferList && BufferList != Current) { - readPos += int64_t{BufferList->mSampleLen} << 32; + readPos += uint64_t{BufferList->mSampleLen} << 32; BufferList = BufferList->mNext.load(std::memory_order_relaxed); } readPos = minu64(readPos, 0x7fffffffffffffff_u64); @@ -254,7 +254,7 @@ ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, std::chrono:: while(BufferList && BufferList != Current) { if(!BufferFmt) BufferFmt = BufferList->mBuffer; - readPos += int64_t{BufferList->mSampleLen} << FRACTIONBITS; + readPos += uint64_t{BufferList->mSampleLen} << FRACTIONBITS; BufferList = BufferList->mNext.load(std::memory_order_relaxed); } @@ -265,7 +265,7 @@ ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, std::chrono:: } assert(BufferFmt != nullptr); - offset = static_cast(readPos) / static_castFRACTIONONE / + offset = static_cast(readPos) / ALdouble{FRACTIONONE} / static_cast(BufferFmt->Frequency); } @@ -283,7 +283,7 @@ ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) ALCdevice *device{context->mDevice.get()}; const ALbufferlistitem *Current; ALuint readPos; - ALsizei readPosFrac; + ALuint readPosFrac; ALuint refcount; ALvoice *voice; @@ -382,7 +382,7 @@ ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) * or Second offset supplied by the application). This takes into account the * fact that the buffer format may have been modifed since. */ -ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac) +ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac) { const ALbuffer *BufferFmt{nullptr}; const ALbufferlistitem *BufferList; @@ -426,14 +426,14 @@ ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac) case AL_SAMPLE_OFFSET: dblfrac = modf(Source->Offset, &dbloff); - *offset = static_cast(mind(dbloff, std::numeric_limits::max())); - *frac = static_cast(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0)); + *offset = static_cast(mind(dbloff, std::numeric_limits::max())); + *frac = static_cast(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0)); break; case AL_SEC_OFFSET: dblfrac = modf(Source->Offset*BufferFmt->Frequency, &dbloff); - *offset = static_cast(mind(dbloff, std::numeric_limits::max())); - *frac = static_cast(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0)); + *offset = static_cast(mind(dbloff, std::numeric_limits::max())); + *frac = static_cast(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0)); break; } Source->OffsetType = AL_NONE; @@ -451,7 +451,7 @@ ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) { /* Get sample frame offset */ ALuint offset{0u}; - ALsizei frac{0}; + ALuint frac{0u}; if(!GetSampleOffset(Source, &offset, &frac)) return AL_FALSE; diff --git a/alc/alu.h b/alc/alu.h index da6f6a94..51c5f702 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -81,7 +81,7 @@ union InterpState { }; using ResamplerFunc = const ALfloat*(*)(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, const al::span dst); + ALuint frac, ALint increment, const al::span dst); void BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *table); @@ -219,7 +219,7 @@ struct ALvoice { */ std::atomic mPosition; /** Fractional (fixed-point) offset to the next sample. */ - std::atomic mPositionFrac; + std::atomic mPositionFrac; /* Current buffer queue item being played. */ std::atomic mCurrentBuffer; diff --git a/alc/mixer/defs.h b/alc/mixer/defs.h index bb5ca56e..4aa3c6b6 100644 --- a/alc/mixer/defs.h +++ b/alc/mixer/defs.h @@ -27,7 +27,7 @@ enum ResampleType { }; template -const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALsizei frac, +const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALuint frac, ALint increment, const al::span dst); template diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index dbdbf16d..7a79d1e2 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -13,23 +13,23 @@ namespace { -inline ALfloat do_point(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei) +inline ALfloat do_point(const InterpState&, const ALfloat *RESTRICT vals, const ALuint) { return vals[0]; } -inline ALfloat do_lerp(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei frac) +inline ALfloat do_lerp(const InterpState&, const ALfloat *RESTRICT vals, const ALuint frac) { return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); } -inline ALfloat do_cubic(const InterpState&, const ALfloat *RESTRICT vals, const ALsizei frac) +inline ALfloat do_cubic(const InterpState&, const ALfloat *RESTRICT vals, const ALuint frac) { return cubic(vals[0], vals[1], vals[2], vals[3], frac * (1.0f/FRACTIONONE)); } -inline ALfloat do_bsinc(const InterpState &istate, const ALfloat *RESTRICT vals, const ALsizei frac) +inline ALfloat do_bsinc(const InterpState &istate, const ALfloat *RESTRICT vals, const ALuint frac) { ASSUME(istate.bsinc.m > 0); // Calculate the phase index and factor. #define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) - const ALsizei pi{frac >> FRAC_PHASE_BITDIFF}; + const ALuint pi{frac >> FRAC_PHASE_BITDIFF}; const ALfloat pf{(frac & ((1< const ALfloat *DoResample(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, const al::span dst) + ALuint frac, ALint increment, const al::span dst) { ASSUME(increment > 0); - ASSUME(frac >= 0); const InterpState istate{*state}; auto proc_sample = [&src,&frac,istate,increment]() -> ALfloat @@ -68,7 +67,7 @@ const ALfloat *DoResample(const InterpState *state, const ALfloat *RESTRICT src, } // namespace template<> -const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, ALsizei, +const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, ALuint, ALint, const al::span dst) { #if defined(HAVE_SSE) || defined(HAVE_NEON) @@ -82,22 +81,22 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRI template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, const al::span dst) + ALuint frac, ALint increment, const al::span dst) { return DoResample(state, src, frac, increment, dst); } template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, const al::span dst) + ALuint frac, ALint increment, const al::span dst) { return DoResample(state, src, frac, increment, dst); } template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, const al::span dst) + ALuint frac, ALint increment, const al::span dst) { return DoResample(state, src-1, frac, increment, dst); } template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, const al::span dst) + ALuint frac, ALint increment, const al::span dst) { return DoResample(state, src-state->bsinc.l, frac, increment, dst); } diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index 472eae1b..d3e89aec 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -16,7 +16,7 @@ template<> const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, const al::span dst) + ALuint frac, ALint increment, const al::span dst) { const int32x4_t increment4 = vdupq_n_s32(increment*4); const float32x4_t fracOne4 = vdupq_n_f32(1.0f/FRACTIONONE); @@ -24,7 +24,6 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES alignas(16) ALsizei pos_[4], frac_[4]; int32x4_t pos4, frac4; - ASSUME(frac >= 0); ASSUME(increment > 0); InitiatePositionArrays(frac, increment, frac_, pos_, 4); @@ -35,17 +34,17 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES const auto aligned_end = (dst.size()&~3) + dst_iter; while(dst_iter != aligned_end) { - const int pos0 = vgetq_lane_s32(pos4, 0); - const int pos1 = vgetq_lane_s32(pos4, 1); - const int pos2 = vgetq_lane_s32(pos4, 2); - const int pos3 = vgetq_lane_s32(pos4, 3); - const float32x4_t val1 = (float32x4_t){src[pos0], src[pos1], src[pos2], src[pos3]}; - const float32x4_t val2 = (float32x4_t){src[pos0+1], src[pos1+1], src[pos2+1], src[pos3+1]}; + const int pos0{vgetq_lane_s32(pos4, 0)}; + const int pos1{vgetq_lane_s32(pos4, 1)}; + const int pos2{vgetq_lane_s32(pos4, 2)}; + const int pos3{vgetq_lane_s32(pos4, 3)}; + const float32x4_t val1{src[pos0], src[pos1], src[pos2], src[pos3]}; + const float32x4_t val2{src[pos0+1], src[pos1+1], src[pos2+1], src[pos3+1]}; /* val1 + (val2-val1)*mu */ - const float32x4_t r0 = vsubq_f32(val2, val1); - const float32x4_t mu = vmulq_f32(vcvtq_f32_s32(frac4), fracOne4); - const float32x4_t out = vmlaq_f32(val1, mu, r0); + const float32x4_t r0{vsubq_f32(val2, val1)}; + const float32x4_t mu{vmulq_f32(vcvtq_f32_s32(frac4), fracOne4)}; + const float32x4_t out{vmlaq_f32(val1, mu, r0)}; vst1q_f32(dst_iter, out); dst_iter += 4; @@ -58,15 +57,15 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES /* NOTE: These four elements represent the position *after* the last four * samples, so the lowest element is the next position to resample. */ - ALsizei pos{vgetq_lane_s32(pos4, 0)}; + src += static_cast(vgetq_lane_s32(pos4, 0)); frac = vgetq_lane_s32(frac4, 0); while(dst_iter != dst.end()) { - *(dst_iter++) = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); + *(dst_iter++) = lerp(src[0], src[1], frac * (1.0f/FRACTIONONE)); frac += increment; - pos += frac>>FRACTIONBITS; + src += frac>>FRACTIONBITS; frac &= FRACTIONMASK; } return dst.begin(); @@ -74,22 +73,21 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, const al::span dst) + ALuint frac, ALint increment, const al::span dst) { const ALfloat *const filter{state->bsinc.filter}; const float32x4_t sf4{vdupq_n_f32(state->bsinc.sf)}; - const ALsizei m{state->bsinc.m}; + const ptrdiff_t m{state->bsinc.m}; ASSUME(m > 0); ASSUME(increment > 0); - ASSUME(frac >= 0); src -= state->bsinc.l; for(float &out_sample : dst) { // Calculate the phase index and factor. #define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) - const ALsizei pi{frac >> FRAC_PHASE_BITDIFF}; + const ALuint pi{frac >> FRAC_PHASE_BITDIFF}; const ALfloat pf{(frac & ((1<(const InterpState *state, const ALflo const float *scd{fil + m}; const float *phd{scd + m}; const float *spd{phd + m}; - ALsizei td{m >> 2}; + ptrdiff_t td{m >> 2}; size_t j{0u}; do { diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index 8d2abc88..05ebe26f 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -15,22 +15,21 @@ template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, const al::span dst) + ALuint frac, ALint increment, const al::span dst) { const ALfloat *const filter{state->bsinc.filter}; const __m128 sf4{_mm_set1_ps(state->bsinc.sf)}; - const ALsizei m{state->bsinc.m}; + const ptrdiff_t m{state->bsinc.m}; ASSUME(m > 0); ASSUME(increment > 0); - ASSUME(frac >= 0); src -= state->bsinc.l; for(float &out_sample : dst) { // Calculate the phase index and factor. #define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) - const ALsizei pi{frac >> FRAC_PHASE_BITDIFF}; + const ALuint pi{frac >> FRAC_PHASE_BITDIFF}; const ALfloat pf{(frac & ((1<(const InterpState *state, const ALfloa const float *scd{fil + m}; const float *phd{scd + m}; const float *spd{phd + m}; - ALsizei td{m >> 2}; + ptrdiff_t td{m >> 2}; size_t j{0u}; #define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z)) diff --git a/alc/mixer/mixer_sse2.cpp b/alc/mixer/mixer_sse2.cpp index e3443f4e..b126cd25 100644 --- a/alc/mixer/mixer_sse2.cpp +++ b/alc/mixer/mixer_sse2.cpp @@ -29,13 +29,12 @@ template<> const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, const al::span dst) + ALuint frac, ALint increment, const al::span dst) { const __m128i increment4{_mm_set1_epi32(increment*4)}; const __m128 fracOne4{_mm_set1_ps(1.0f/FRACTIONONE)}; const __m128i fracMask4{_mm_set1_epi32(FRACTIONMASK)}; - ASSUME(frac >= 0); ASSUME(increment > 0); alignas(16) ALsizei pos_[4], frac_[4]; @@ -70,15 +69,15 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES /* NOTE: These four elements represent the position *after* the last four * samples, so the lowest element is the next position to resample. */ - ALsizei pos{_mm_cvtsi128_si32(pos4)}; + src += static_cast(_mm_cvtsi128_si32(pos4)); frac = _mm_cvtsi128_si32(frac4); while(dst_iter != dst.end()) { - *(dst_iter++) = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); + *(dst_iter++) = lerp(src[0], src[1], frac * (1.0f/FRACTIONONE)); frac += increment; - pos += frac>>FRACTIONBITS; + src += frac>>FRACTIONBITS; frac &= FRACTIONMASK; } return dst.begin(); diff --git a/alc/mixer/mixer_sse41.cpp b/alc/mixer/mixer_sse41.cpp index 424b9b5f..06c51e6a 100644 --- a/alc/mixer/mixer_sse41.cpp +++ b/alc/mixer/mixer_sse41.cpp @@ -30,13 +30,12 @@ template<> const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, - ALsizei frac, ALint increment, const al::span dst) + ALuint frac, ALint increment, const al::span dst) { const __m128i increment4{_mm_set1_epi32(increment*4)}; const __m128 fracOne4{_mm_set1_ps(1.0f/FRACTIONONE)}; const __m128i fracMask4{_mm_set1_epi32(FRACTIONMASK)}; - ASSUME(frac >= 0); ASSUME(increment > 0); alignas(16) ALsizei pos_[4], frac_[4]; @@ -71,15 +70,15 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES /* NOTE: These four elements represent the position *after* the last four * samples, so the lowest element is the next position to resample. */ - ALsizei pos{_mm_cvtsi128_si32(pos4)}; + src += static_cast(_mm_cvtsi128_si32(pos4)); frac = _mm_cvtsi128_si32(frac4); while(dst_iter != dst.end()) { - *(dst_iter++) = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); + *(dst_iter++) = lerp(src[0], src[1], frac * (1.0f/FRACTIONONE)); frac += increment; - pos += frac>>FRACTIONBITS; + src += frac>>FRACTIONBITS; frac &= FRACTIONMASK; } return dst.begin(); diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 97583107..2d1a4655 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -482,7 +482,7 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) /* Get voice info */ const bool isstatic{(mFlags&VOICE_IS_STATIC) != 0}; ALuint DataPosInt{mPosition.load(std::memory_order_relaxed)}; - ALsizei DataPosFrac{mPositionFrac.load(std::memory_order_relaxed)}; + ALuint DataPosFrac{mPositionFrac.load(std::memory_order_relaxed)}; ALbufferlistitem *BufferListItem{mCurrentBuffer.load(std::memory_order_relaxed)}; ALbufferlistitem *BufferLoopItem{mLoopBuffer.load(std::memory_order_relaxed)}; const ALsizei NumChannels{mNumChannels}; @@ -490,7 +490,6 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) const ALint increment{mStep}; if(increment < 1) return; - ASSUME(DataPosFrac >= 0); ASSUME(NumChannels > 0); ASSUME(SampleSize > 0); ASSUME(increment > 0); -- cgit v1.2.3 From 96af306b3c999e05194c0fd431dc49b2219a7649 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 31 Aug 2019 20:24:34 -0700 Subject: Update the language for travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e24ed7d8..98b5adcc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -language: c +language: cpp matrix: include: - os: linux -- cgit v1.2.3 From 5becf4bb73ffc448dbad5ba6dd9377f3c8ab8697 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 31 Aug 2019 21:47:58 -0700 Subject: Don't include version.h in mainwindow.cpp Should help with post-commit compile times --- utils/alsoft-config/CMakeLists.txt | 2 ++ utils/alsoft-config/mainwindow.cpp | 8 ++++---- utils/alsoft-config/verstr.cpp | 10 ++++++++++ utils/alsoft-config/verstr.h | 6 ++++++ 4 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 utils/alsoft-config/verstr.cpp create mode 100644 utils/alsoft-config/verstr.h diff --git a/utils/alsoft-config/CMakeLists.txt b/utils/alsoft-config/CMakeLists.txt index 7996ee97..68b9e9de 100644 --- a/utils/alsoft-config/CMakeLists.txt +++ b/utils/alsoft-config/CMakeLists.txt @@ -8,6 +8,8 @@ set(alsoft-config_SRCS main.cpp mainwindow.cpp mainwindow.h + verstr.cpp + verstr.h ) set(alsoft-config_UIS mainwindow.ui) set(alsoft-config_MOCS mainwindow.h) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 3b7b428a..c0c0e1e5 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -1,7 +1,7 @@ #include "config.h" -#include "version.h" +#include "mainwindow.h" #include #include @@ -11,8 +11,8 @@ #include #include #include -#include "mainwindow.h" #include "ui_mainwindow.h" +#include "verstr.h" namespace { @@ -503,8 +503,8 @@ void MainWindow::cancelCloseAction() void MainWindow::showAboutPage() { QMessageBox::information(this, tr("About"), - tr("OpenAL Soft Configuration Utility.\nBuilt for OpenAL Soft library version ")+ - (ALSOFT_VERSION "-" ALSOFT_GIT_COMMIT_HASH " (" ALSOFT_GIT_BRANCH " branch).")); + tr("OpenAL Soft Configuration Utility.\nBuilt for OpenAL Soft library version ") + + tr(GetVersionString())); } diff --git a/utils/alsoft-config/verstr.cpp b/utils/alsoft-config/verstr.cpp new file mode 100644 index 00000000..b2fd0a17 --- /dev/null +++ b/utils/alsoft-config/verstr.cpp @@ -0,0 +1,10 @@ + +#include "verstr.h" + +#include "version.h" + + +const char *GetVersionString() +{ + return ALSOFT_VERSION "-" ALSOFT_GIT_COMMIT_HASH " (" ALSOFT_GIT_BRANCH " branch)."; +} diff --git a/utils/alsoft-config/verstr.h b/utils/alsoft-config/verstr.h new file mode 100644 index 00000000..a97f0895 --- /dev/null +++ b/utils/alsoft-config/verstr.h @@ -0,0 +1,6 @@ +#ifndef VERSTR_H +#define VERSTR_H + +const char *GetVersionString(); + +#endif /* VERSTR_H */ -- cgit v1.2.3 From a15f25b07ad442890bb9a75a7ef7f43cf5ab2ef4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 31 Aug 2019 22:28:26 -0700 Subject: Return a QString from GetVersionString --- utils/alsoft-config/mainwindow.cpp | 2 +- utils/alsoft-config/verstr.cpp | 4 ++-- utils/alsoft-config/verstr.h | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index c0c0e1e5..aa0df438 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -504,7 +504,7 @@ void MainWindow::showAboutPage() { QMessageBox::information(this, tr("About"), tr("OpenAL Soft Configuration Utility.\nBuilt for OpenAL Soft library version ") + - tr(GetVersionString())); + GetVersionString()); } diff --git a/utils/alsoft-config/verstr.cpp b/utils/alsoft-config/verstr.cpp index b2fd0a17..42b1aeac 100644 --- a/utils/alsoft-config/verstr.cpp +++ b/utils/alsoft-config/verstr.cpp @@ -4,7 +4,7 @@ #include "version.h" -const char *GetVersionString() +QString GetVersionString() { - return ALSOFT_VERSION "-" ALSOFT_GIT_COMMIT_HASH " (" ALSOFT_GIT_BRANCH " branch)."; + return QStringLiteral(ALSOFT_VERSION "-" ALSOFT_GIT_COMMIT_HASH " (" ALSOFT_GIT_BRANCH " branch)."); } diff --git a/utils/alsoft-config/verstr.h b/utils/alsoft-config/verstr.h index a97f0895..73e3ecbd 100644 --- a/utils/alsoft-config/verstr.h +++ b/utils/alsoft-config/verstr.h @@ -1,6 +1,8 @@ #ifndef VERSTR_H #define VERSTR_H -const char *GetVersionString(); +#include + +QString GetVersionString(); #endif /* VERSTR_H */ -- cgit v1.2.3 From aee10ef60623e012e5edc6fcf31b2d71b2086bc9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 1 Sep 2019 00:24:49 -0700 Subject: Hold the source lock in UpdateAllSourceProps --- al/source.cpp | 1 + alc/alc.cpp | 41 ++++++++++++++++++++--------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index d9a7cb87..08e4bff6 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -3318,6 +3318,7 @@ ALsource::~ALsource() void UpdateAllSourceProps(ALCcontext *context) { + std::lock_guard _{context->mSourceLock}; auto voices_end = context->mVoices->begin() + context->mVoiceCount.load(std::memory_order_relaxed); std::for_each(context->mVoices->begin(), voices_end, diff --git a/alc/alc.cpp b/alc/alc.cpp index a69a8e7c..8ee762d5 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -2203,30 +2203,29 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) }; std::for_each(voices->begin(), voices_end, clear_sends); } - std::for_each(voices->begin(), voices_end, - [device](ALvoice &voice) -> void - { - delete voice.mUpdate.exchange(nullptr, std::memory_order_acq_rel); + auto reset_voice = [device](ALvoice &voice) -> void + { + delete voice.mUpdate.exchange(nullptr, std::memory_order_acq_rel); - /* Force the voice to stopped if it was stopping. */ - ALvoice::State vstate{ALvoice::Stopping}; - voice.mPlayState.compare_exchange_strong(vstate, ALvoice::Stopped, - std::memory_order_acquire, std::memory_order_acquire); - if(voice.mSourceID.load(std::memory_order_relaxed) == 0u) - return; + /* Force the voice to stopped if it was stopping. */ + ALvoice::State vstate{ALvoice::Stopping}; + voice.mPlayState.compare_exchange_strong(vstate, ALvoice::Stopped, + std::memory_order_acquire, std::memory_order_acquire); + if(voice.mSourceID.load(std::memory_order_relaxed) == 0u) + return; - if(device->AvgSpeakerDist > 0.0f) - { - /* Reinitialize the NFC filters for new parameters. */ - const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC / - (device->AvgSpeakerDist * device->Frequency)}; - auto init_nfc = [w1](ALvoice::ChannelData &chandata) -> void - { chandata.mDryParams.NFCtrlFilter.init(w1); }; - std::for_each(voice.mChans.begin(), voice.mChans.begin()+voice.mNumChannels, - init_nfc); - } + if(device->AvgSpeakerDist > 0.0f) + { + /* Reinitialize the NFC filters for new parameters. */ + const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC / + (device->AvgSpeakerDist * device->Frequency)}; + auto init_nfc = [w1](ALvoice::ChannelData &chandata) -> void + { chandata.mDryParams.NFCtrlFilter.init(w1); }; + std::for_each(voice.mChans.begin(), voice.mChans.begin()+voice.mNumChannels, + init_nfc); } - ); + }; + std::for_each(voices->begin(), voices_end, reset_voice); srclock.unlock(); context->mPropsClean.test_and_set(std::memory_order_release); -- cgit v1.2.3 From d15950f383cfdff64d464721b02b9f9b8cb4a0f2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 1 Sep 2019 15:03:22 -0700 Subject: Avoid accumulating a temporary --- alc/alu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alc/alu.cpp b/alc/alu.cpp index 869346c4..3cf7f4cf 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -1327,8 +1327,8 @@ void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray &slots, { bool force{CalcContextParams(ctx)}; force |= CalcListenerParams(ctx); - force |= std::accumulate(slots.begin(), slots.end(), bool{false}, - [ctx](bool force, ALeffectslot *slot) -> bool + force = std::accumulate(slots.begin(), slots.end(), force, + [ctx](const bool force, ALeffectslot *slot) -> bool { return CalcEffectSlotParams(slot, ctx) | force; } ); -- cgit v1.2.3 From 727217ce0a9765270551ad6e10a25ee0b7fb74e6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 1 Sep 2019 15:28:33 -0700 Subject: Ensure AL_STOPPED state change events are sent With explicit calls to alSourceStop on a playing or paused source --- al/source.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index 08e4bff6..010dee1c 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -2974,7 +2974,11 @@ START_API_FUNC BackendLockGuard __{*device->Backend}; auto stop_source = [&context](ALsource *source) -> void { + /* Get the source state before clearing from the voice, so we know what + * state the source+voice was actually in. + */ ALvoice *voice{GetSourceVoice(source, context.get())}; + const ALenum oldstate{GetSourceState(source, voice)}; if(voice != nullptr) { voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed); @@ -2986,7 +2990,6 @@ START_API_FUNC std::memory_order_acq_rel, std::memory_order_acquire); voice = nullptr; } - ALenum oldstate{GetSourceState(source, voice)}; if(oldstate != AL_INITIAL && oldstate != AL_STOPPED) { source->state = AL_STOPPED; @@ -3048,7 +3051,7 @@ START_API_FUNC std::memory_order_acq_rel, std::memory_order_acquire); voice = nullptr; } - if(GetSourceState(source, voice) != AL_INITIAL) + if(source->state != AL_INITIAL) { source->state = AL_INITIAL; SendStateChangeEvent(context.get(), source->id, AL_INITIAL); -- cgit v1.2.3 From bb35e24c9ba7ec01c05fc1f07ef737c15821283a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 1 Sep 2019 17:54:17 -0700 Subject: Avoid unnecessary placement new definitions --- al/auxeffectslot.cpp | 7 +------ al/auxeffectslot.h | 2 +- al/source.cpp | 7 +------ alc/alc.cpp | 3 +-- 4 files changed, 4 insertions(+), 15 deletions(-) diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index b2f2c249..3eb8b80a 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -173,13 +173,9 @@ ALeffectslot *AllocEffectSlot(ALCcontext *context) { return entry.FreeMask != 0; } ); auto lidx = static_cast(std::distance(context->mEffectSlotList.begin(), sublist)); - ALeffectslot *slot; ALsizei slidx; if LIKELY(sublist != context->mEffectSlotList.end()) - { slidx = CTZ64(sublist->FreeMask); - slot = sublist->EffectSlots + slidx; - } else { /* Don't allocate so many list entries that the 32-bit ID could @@ -203,10 +199,9 @@ ALeffectslot *AllocEffectSlot(ALCcontext *context) } slidx = 0; - slot = sublist->EffectSlots + slidx; } - slot = new (slot) ALeffectslot{}; + ALeffectslot *slot{::new (sublist->EffectSlots + slidx) ALeffectslot{}}; ALenum err{InitEffectSlot(slot)}; if(err != AL_NO_ERROR) { diff --git a/al/auxeffectslot.h b/al/auxeffectslot.h index a6eb94f9..2471447f 100644 --- a/al/auxeffectslot.h +++ b/al/auxeffectslot.h @@ -92,7 +92,7 @@ struct ALeffectslot { static ALeffectslotArray *CreatePtrArray(size_t count) noexcept; - DEF_PLACE_NEWDEL() + DEF_NEWDEL(ALeffectslot) }; ALenum InitEffectSlot(ALeffectslot *slot); diff --git a/al/source.cpp b/al/source.cpp index 010dee1c..86a7d94c 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -491,13 +491,9 @@ ALsource *AllocSource(ALCcontext *context) { return entry.FreeMask != 0; } ); auto lidx = static_cast(std::distance(context->mSourceList.begin(), sublist)); - ALsource *source; ALsizei slidx; if LIKELY(sublist != context->mSourceList.end()) - { slidx = CTZ64(sublist->FreeMask); - source = sublist->Sources + slidx; - } else { /* Don't allocate so many list entries that the 32-bit ID could @@ -521,10 +517,9 @@ ALsource *AllocSource(ALCcontext *context) } slidx = 0; - source = sublist->Sources + slidx; } - source = new (source) ALsource{device->NumAuxSends}; + ALsource *source{::new (sublist->Sources + slidx) ALsource{device->NumAuxSends}}; /* Add 1 to avoid source ID 0. */ source->id = ((lidx<<6) | slidx) + 1; diff --git a/alc/alc.cpp b/alc/alc.cpp index 8ee762d5..7964a2b3 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -2422,8 +2422,7 @@ void ALCcontext::init() { if(DefaultEffect.type != AL_EFFECT_NULL && mDevice->Type == Playback) { - void *ptr{al_calloc(16, sizeof(ALeffectslot))}; - mDefaultSlot = std::unique_ptr{new (ptr) ALeffectslot{}}; + mDefaultSlot = std::unique_ptr{new ALeffectslot{}}; if(InitEffectSlot(mDefaultSlot.get()) == AL_NO_ERROR) aluInitEffectPanning(mDefaultSlot.get(), mDevice.get()); else -- cgit v1.2.3 From 3d7ce5a86010240262bdd1763218b3beeda21c5e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 1 Sep 2019 18:07:16 -0700 Subject: Use global placement new for AL object batches --- al/buffer.cpp | 8 ++------ al/effect.cpp | 9 ++------- al/filter.cpp | 7 +------ 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/al/buffer.cpp b/al/buffer.cpp index df2496cb..03b68038 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -254,13 +254,9 @@ ALbuffer *AllocBuffer(ALCcontext *context) ); auto lidx = static_cast(std::distance(device->BufferList.begin(), sublist)); - ALbuffer *buffer{nullptr}; ALsizei slidx{0}; if LIKELY(sublist != device->BufferList.end()) - { slidx = CTZ64(sublist->FreeMask); - buffer = sublist->Buffers + slidx; - } else { /* Don't allocate so many list entries that the 32-bit ID could @@ -283,10 +279,10 @@ ALbuffer *AllocBuffer(ALCcontext *context) } slidx = 0; - buffer = sublist->Buffers + slidx; } - buffer = new (buffer) ALbuffer{}; + ALbuffer *buffer{::new (sublist->Buffers + slidx) ALbuffer{}}; + /* Add 1 to avoid buffer ID 0. */ buffer->id = ((lidx<<6) | slidx) + 1; diff --git a/al/effect.cpp b/al/effect.cpp index e5571be0..3836a5e4 100644 --- a/al/effect.cpp +++ b/al/effect.cpp @@ -130,7 +130,7 @@ void InitEffectParams(ALeffect *effect, ALenum type) } else { - effect->Props = EffectProps {}; + effect->Props = EffectProps{}; effect->vtab = nullptr; } effect->type = type; @@ -146,13 +146,9 @@ ALeffect *AllocEffect(ALCcontext *context) ); auto lidx = static_cast(std::distance(device->EffectList.begin(), sublist)); - ALeffect *effect{nullptr}; ALsizei slidx{0}; if LIKELY(sublist != device->EffectList.end()) - { slidx = CTZ64(sublist->FreeMask); - effect = sublist->Effects + slidx; - } else { /* Don't allocate so many list entries that the 32-bit ID could @@ -175,10 +171,9 @@ ALeffect *AllocEffect(ALCcontext *context) } slidx = 0; - effect = sublist->Effects + slidx; } - effect = new (effect) ALeffect{}; + ALeffect *effect{::new (sublist->Effects + slidx) ALeffect{}}; InitEffectParams(effect, AL_EFFECT_NULL); /* Add 1 to avoid effect ID 0. */ diff --git a/al/filter.cpp b/al/filter.cpp index b1118550..abb2795b 100644 --- a/al/filter.cpp +++ b/al/filter.cpp @@ -288,13 +288,9 @@ ALfilter *AllocFilter(ALCcontext *context) ); auto lidx = static_cast(std::distance(device->FilterList.begin(), sublist)); - ALfilter *filter{nullptr}; ALsizei slidx{0}; if LIKELY(sublist != device->FilterList.end()) - { slidx = CTZ64(sublist->FreeMask); - filter = sublist->Filters + slidx; - } else { /* Don't allocate so many list entries that the 32-bit ID could @@ -317,10 +313,9 @@ ALfilter *AllocFilter(ALCcontext *context) } slidx = 0; - filter = sublist->Filters + slidx; } - filter = new (filter) ALfilter{}; + ALfilter *filter{::new (sublist->Filters + slidx) ALfilter{}}; InitFilterParams(filter, AL_FILTER_NULL); /* Add 1 to avoid filter ID 0. */ -- cgit v1.2.3 From e1ee1bcde907e0021de38c1823fb5a67d49ebae9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 3 Sep 2019 21:23:54 -0700 Subject: Clean up some formatting --- alc/mixvoice.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 2d1a4655..2efc5a24 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -633,10 +633,11 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) } /* Now filter and mix to the appropriate outputs. */ + ALfloat (&FilterBuf)[BUFFERSIZE] = Device->FilteredData; { DirectParams &parms = chandata.mDryParams; - const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, - Device->FilteredData, ResampledData, DstBufferSize, mDirect.FilterType)}; + const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, FilterBuf, + ResampledData, DstBufferSize, mDirect.FilterType)}; if((mFlags&VOICE_HAS_HRTF)) { @@ -786,21 +787,20 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) } } - ALfloat (&FilterBuf)[BUFFERSIZE] = Device->FilteredData; for(ALsizei send{0};send < NumSends;++send) { if(mSend[send].Buffer.empty()) continue; SendParams &parms = chandata.mWetParams[send]; - const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, - FilterBuf, ResampledData, DstBufferSize, mSend[send].FilterType)}; + const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, FilterBuf, + ResampledData, DstBufferSize, mSend[send].FilterType)}; const ALfloat *TargetGains{UNLIKELY(vstate==ALvoice::Stopping) ? SilentTarget : parms.Gains.Target}; MixSamples({samples, DstBufferSize}, mSend[send].Buffer, parms.Gains.Current, TargetGains, Counter, OutPos); - }; + } } /* Update positions */ DataPosFrac += increment*DstBufferSize; -- cgit v1.2.3 From 8940bbd034177182bb6fc1e3953e57674e488309 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 3 Sep 2019 23:19:24 -0700 Subject: Only use one accumulation buffer for B-Format HRTF mixing It's all getting added together anyway and all channels are continuous inputs, so this is fewer passes over various buffers. --- alc/hrtf.cpp | 2 +- alc/hrtf.h | 13 ++++--------- alc/mixer/hrtfbase.h | 26 +++++++++++--------------- 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index 5446c412..c0e2b982 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -438,7 +438,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin { auto copy_arr = [](const std::array &in) noexcept -> float2 { return float2{{static_cast(in[0]), static_cast(in[1])}}; }; - std::transform(tmpres[i].begin(), tmpres[i].end(), state->Chan[i].Coeffs.begin(), + std::transform(tmpres[i].begin(), tmpres[i].end(), state->Coeffs[i].begin(), copy_arr); } tmpres.clear(); diff --git a/alc/hrtf.h b/alc/hrtf.h index e40e6cb4..487dca61 100644 --- a/alc/hrtf.h +++ b/alc/hrtf.h @@ -79,19 +79,14 @@ struct HrtfFilter { struct DirectHrtfState { /* HRTF filter state for dry buffer content */ ALsizei IrSize{0}; - struct ChanData { - alignas(16) HrirArray Values; - alignas(16) HrirArray Coeffs; - }; - al::FlexArray Chan; + alignas(16) HrirArray Values; + al::FlexArray Coeffs; - DirectHrtfState(size_t numchans) : Chan{numchans} { } - DirectHrtfState(const DirectHrtfState&) = delete; - DirectHrtfState& operator=(const DirectHrtfState&) = delete; + DirectHrtfState(size_t numchans) : Coeffs{numchans} { } static std::unique_ptr Create(size_t num_chans); static constexpr size_t Sizeof(size_t numchans) noexcept - { return al::FlexArray::Sizeof(numchans, offsetof(DirectHrtfState, Chan)); } + { return al::FlexArray::Sizeof(numchans, offsetof(DirectHrtfState, Coeffs)); } DEF_PLACE_NEWDEL() }; diff --git a/alc/mixer/hrtfbase.h b/alc/mixer/hrtfbase.h index 82446714..5ae83fc9 100644 --- a/alc/mixer/hrtfbase.h +++ b/alc/mixer/hrtfbase.h @@ -108,29 +108,25 @@ inline void MixDirectHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOu const ALsizei IrSize{State->IrSize}; ASSUME(IrSize >= 4); - auto chanstate = State->Chan.begin(); + auto accum_iter = std::copy_n(State->Values.begin(), State->Values.size(), AccumSamples); + std::fill_n(accum_iter, BufferSize, float2{}); + + auto coeff_iter = State->Coeffs.begin(); for(const FloatBufferLine &input : InSamples) { - const auto &Coeffs = chanstate->Coeffs; - - auto accum_iter = std::copy_n(chanstate->Values.begin(), - chanstate->Values.size(), AccumSamples); - std::fill_n(accum_iter, BufferSize, float2{}); - + const auto &Coeffs = *(coeff_iter++); for(size_t i{0u};i < BufferSize;++i) { const ALfloat insample{input[i]}; ApplyCoeffs(i, AccumSamples+i, IrSize, Coeffs, insample, insample); } - for(size_t i{0u};i < BufferSize;++i) - LeftOut[i] += AccumSamples[i][0]; - for(size_t i{0u};i < BufferSize;++i) - RightOut[i] += AccumSamples[i][1]; - - std::copy_n(AccumSamples + BufferSize, chanstate->Values.size(), - chanstate->Values.begin()); - ++chanstate; } + for(size_t i{0u};i < BufferSize;++i) + LeftOut[i] += AccumSamples[i][0]; + for(size_t i{0u};i < BufferSize;++i) + RightOut[i] += AccumSamples[i][1]; + + std::copy_n(AccumSamples + BufferSize, State->Values.size(), State->Values.begin()); } #endif /* MIXER_HRTFBASE_H */ -- cgit v1.2.3 From e873165019e8ae9300be9066101554c18a29df83 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 4 Sep 2019 19:31:30 -0700 Subject: Only ASSUME values where a variable is used --- alc/mixer/hrtfbase.h | 3 --- alc/mixer/mixer_c.cpp | 2 +- alc/mixer/mixer_neon.cpp | 2 +- alc/mixer/mixer_sse.cpp | 2 +- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/alc/mixer/hrtfbase.h b/alc/mixer/hrtfbase.h index 5ae83fc9..0309fe5d 100644 --- a/alc/mixer/hrtfbase.h +++ b/alc/mixer/hrtfbase.h @@ -16,7 +16,6 @@ inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *RESTRICT AccumSamples, const size_t OutPos, const ALsizei IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) { - ASSUME(IrSize >= 4); ASSUME(BufferSize > 0); const HrirArray &Coeffs = *hrtfparams->Coeffs; @@ -58,7 +57,6 @@ inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut const auto &NewCoeffs = *newparams->Coeffs; const ALfloat newGainStep{newparams->GainStep}; - ASSUME(IrSize >= 4); ASSUME(BufferSize > 0); ALsizei Delay[2]{ @@ -106,7 +104,6 @@ inline void MixDirectHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOu ASSUME(BufferSize > 0); const ALsizei IrSize{State->IrSize}; - ASSUME(IrSize >= 4); auto accum_iter = std::copy_n(State->Values.begin(), State->Values.size(), AccumSamples); std::fill_n(accum_iter, BufferSize, float2{}); diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index 7a79d1e2..a8fb9a19 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -103,7 +103,7 @@ const ALfloat *Resample_(const InterpState *state, const ALfloat static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const ALsizei IrSize, const HrirArray &Coeffs, const ALfloat left, const ALfloat right) { - ASSUME(IrSize >= 2); + ASSUME(IrSize >= 4); for(ALsizei c{0};c < IrSize;++c) { Values[c][0] += Coeffs[c][0] * left; diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index d3e89aec..b8a15c62 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -128,7 +128,7 @@ const ALfloat *Resample_(const InterpState *state, const ALflo static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const ALsizei IrSize, const HrirArray &Coeffs, const ALfloat left, const ALfloat right) { - ASSUME(IrSize >= 2); + ASSUME(IrSize >= 4); float32x4_t leftright4; { diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index 05ebe26f..1965f3e6 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -74,7 +74,7 @@ static inline void ApplyCoeffs(size_t Offset, float2 *RESTRICT Values, const ALs { const __m128 lrlr{_mm_setr_ps(left, right, left, right)}; - ASSUME(IrSize >= 2); + ASSUME(IrSize >= 4); if((Offset&1)) { -- cgit v1.2.3 From c47a6d2279b80031db9b012713c27885b2d14047 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 4 Sep 2019 20:31:55 -0700 Subject: Increment the mix count during disconnect So attempts to get the current playback offset behave correctly while disconnecting. --- alc/alu.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/alc/alu.cpp b/alc/alu.cpp index 3cf7f4cf..861929ef 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -1732,6 +1732,7 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) if(msglen < 0 || static_cast(msglen) >= sizeof(evt.u.user.msg)) evt.u.user.msg[sizeof(evt.u.user.msg)-1] = 0; + IncrementRef(device->MixCount); for(ALCcontext *ctx : *device->mContexts.load()) { const ALbitfieldSOFT enabledevt{ctx->mEnabledEvts.load(std::memory_order_acquire)}; @@ -1741,7 +1742,7 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) auto evt_data = ring->getWriteVector().first; if(evt_data.len > 0) { - new (evt_data.buf) AsyncEvent{evt}; + ::new (evt_data.buf) AsyncEvent{evt}; ring->writeAdvance(1); ctx->mEventSem.post(); } @@ -1758,4 +1759,5 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) ctx->mVoices->begin() + ctx->mVoiceCount.load(std::memory_order_acquire), stop_voice); } + IncrementRef(device->MixCount); } -- cgit v1.2.3 From ef2769af03825f278b855858681e4cbe55c0734b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 4 Sep 2019 23:04:55 -0700 Subject: Use a normal vector for the voices array --- al/source.cpp | 55 +++++++++++++++++-------------------------------------- alc/alc.cpp | 50 +++++--------------------------------------------- alc/alcontext.h | 5 +---- alc/alu.cpp | 7 ++----- alc/alu.h | 1 + 5 files changed, 26 insertions(+), 92 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index 86a7d94c..be565d58 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -77,10 +77,10 @@ using namespace std::placeholders; ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) { ALuint idx{source->VoiceIdx}; - if(idx < context->mVoiceCount.load(std::memory_order_relaxed)) + if(idx < context->mVoices.size()) { ALuint sid{source->id}; - ALvoice &voice = (*context->mVoices)[idx]; + ALvoice &voice = context->mVoices[idx]; if(voice.mSourceID.load(std::memory_order_acquire) == sid) return &voice; } @@ -2671,38 +2671,20 @@ START_API_FUNC } /* Count the number of reusable voices. */ - auto voices_end = context->mVoices->begin() + - context->mVoiceCount.load(std::memory_order_relaxed); - auto free_voices = std::accumulate(context->mVoices->begin(), voices_end, ALsizei{0}, - [](const ALsizei count, const ALvoice &voice) noexcept -> ALsizei - { - if(voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && - voice.mSourceID.load(std::memory_order_relaxed) == 0u) - return count + 1; - return count; - } - ); + auto count_free_voices = [](const ALsizei count, const ALvoice &voice) noexcept -> ALsizei + { + if(voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && + voice.mSourceID.load(std::memory_order_relaxed) == 0u) + return count + 1; + return count; + }; + auto free_voices = std::accumulate(context->mVoices.begin(), context->mVoices.end(), + ALsizei{0}, count_free_voices); if UNLIKELY(n > free_voices) { - /* Increment the number of voices to handle the request. */ + /* Increase the number of voices to handle the request. */ const ALuint need_voices{static_cast(n) - free_voices}; - const size_t rem_voices{context->mVoices->size() - - context->mVoiceCount.load(std::memory_order_relaxed)}; - - if UNLIKELY(need_voices > rem_voices) - { - /* Allocate more voices to get enough. */ - const size_t alloc_count{need_voices - rem_voices}; - if UNLIKELY(context->mVoices->size() > std::numeric_limits::max()-alloc_count) - SETERR_RETURN(context, AL_OUT_OF_MEMORY,, - "Overflow increasing voice count to %zu + %zu", context->mVoices->size(), - alloc_count); - - const size_t newcount{context->mVoices->size() + alloc_count}; - context->allocVoices(newcount); - } - - context->mVoiceCount.fetch_add(need_voices, std::memory_order_relaxed); + context->mVoices.resize(context->mVoices.size() + need_voices); } auto start_source = [&context,device](ALsource *source) -> void @@ -2757,9 +2739,8 @@ START_API_FUNC } /* Look for an unused voice to play this source with. */ - auto voices_end = context->mVoices->begin() + - context->mVoiceCount.load(std::memory_order_relaxed); - voice = std::find_if(context->mVoices->begin(), voices_end, + auto voices_end = context->mVoices.data() + context->mVoices.size(); + voice = std::find_if(context->mVoices.data(), voices_end, [](const ALvoice &voice) noexcept -> bool { return voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && @@ -2767,7 +2748,7 @@ START_API_FUNC } ); assert(voice != voices_end); - auto vidx = static_cast(std::distance(context->mVoices->begin(), voice)); + auto vidx = static_cast(std::distance(context->mVoices.data(), voice)); voice->mPlayState.store(ALvoice::Stopped, std::memory_order_release); source->PropsClean.test_and_set(std::memory_order_acquire); @@ -3317,9 +3298,7 @@ ALsource::~ALsource() void UpdateAllSourceProps(ALCcontext *context) { std::lock_guard _{context->mSourceLock}; - auto voices_end = context->mVoices->begin() + - context->mVoiceCount.load(std::memory_order_relaxed); - std::for_each(context->mVoices->begin(), voices_end, + std::for_each(context->mVoices.begin(), context->mVoices.end(), [context](ALvoice &voice) -> void { ALuint sid{voice.mSourceID.load(std::memory_order_acquire)}; diff --git a/alc/alc.cpp b/alc/alc.cpp index 7964a2b3..81afaeb0 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -2182,8 +2182,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) vprops = next; } - auto voices = context->mVoices.get(); - auto voices_end = voices->begin() + context->mVoiceCount.load(std::memory_order_relaxed); if(device->NumAuxSends < old_sends) { const ALsizei num_sends{device->NumAuxSends}; @@ -2201,7 +2199,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) }; std::for_each(voice.mChans.begin(), voice.mChans.end(), clear_chan_sends); }; - std::for_each(voices->begin(), voices_end, clear_sends); + std::for_each(context->mVoices.begin(), context->mVoices.end(), clear_sends); } auto reset_voice = [device](ALvoice &voice) -> void { @@ -2225,7 +2223,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) init_nfc); } }; - std::for_each(voices->begin(), voices_end, reset_voice); + std::for_each(context->mVoices.begin(), context->mVoices.end(), reset_voice); srclock.unlock(); context->mPropsClean.test_and_set(std::memory_order_release); @@ -2378,8 +2376,7 @@ ALCcontext::~ALCcontext() } TRACE("Freed %zu voice property object%s\n", count, (count==1)?"":"s"); - mVoices = nullptr; - mVoiceCount.store(0, std::memory_order_relaxed); + mVoices.clear(); ALlistenerProps *lprops{mListener.Params.Update.exchange(nullptr, std::memory_order_relaxed)}; if(lprops) @@ -2459,7 +2456,8 @@ void ALCcontext::init() StartEventThrd(this); - allocVoices(256); + mVoices.reserve(256); + mVoices.resize(64); } bool ALCcontext::deinit() @@ -2548,44 +2546,6 @@ ContextRef GetContextRef(void) } -void ALCcontext::allocVoices(size_t num_voices) -{ - const ALsizei num_sends{mDevice->NumAuxSends}; - - if(mVoices && num_voices == mVoices->size()) - return; - - using ALvoiceArray = al::FlexArray; - std::unique_ptr voices{ALvoiceArray::Create(num_voices)}; - - const size_t v_count{minz(mVoiceCount.load(std::memory_order_relaxed), num_voices)}; - if(mVoices) - { - /* Copy the old voice data to the new storage. */ - auto viter = std::move(mVoices->begin(), mVoices->begin()+v_count, voices->begin()); - - /* Clear extraneous property set sends. */ - auto clear_sends = [num_sends](ALvoice &voice) -> void - { - std::fill(std::begin(voice.mProps.Send)+num_sends, std::end(voice.mProps.Send), - ALvoiceProps::SendData{}); - - std::fill(voice.mSend.begin()+num_sends, voice.mSend.end(), ALvoice::SendData{}); - auto clear_chan_sends = [num_sends](ALvoice::ChannelData &chandata) -> void - { - std::fill(chandata.mWetParams.begin()+num_sends, chandata.mWetParams.end(), - SendParams{}); - }; - std::for_each(voice.mChans.begin(), voice.mChans.end(), clear_chan_sends); - }; - std::for_each(voices->begin(), viter, clear_sends); - } - - mVoices = std::move(voices); - mVoiceCount.store(static_cast(v_count), std::memory_order_relaxed); -} - - /************************************************ * Standard ALC functions ************************************************/ diff --git a/alc/alcontext.h b/alc/alcontext.h index c91d0a21..dd622654 100644 --- a/alc/alcontext.h +++ b/alc/alcontext.h @@ -127,8 +127,7 @@ struct ALCcontext : public al::intrusive_ref { std::atomic mFreeVoiceProps{nullptr}; std::atomic mFreeEffectslotProps{nullptr}; - std::unique_ptr> mVoices{nullptr}; - std::atomic mVoiceCount{0u}; + al::vector mVoices; using ALeffectslotArray = al::FlexArray; std::atomic mActiveAuxSlots{nullptr}; @@ -163,8 +162,6 @@ struct ALCcontext : public al::intrusive_ref { */ bool deinit(); - void allocVoices(size_t num_voices); - /** * Defers/suspends updates for the given context's listener and sources. * This does *NOT* stop mixing, but rather prevents certain property diff --git a/alc/alu.cpp b/alc/alu.cpp index 861929ef..e58ff3b4 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -1348,8 +1348,7 @@ void ProcessContext(ALCcontext *ctx, const ALuint SamplesToDo) ASSUME(SamplesToDo > 0); const ALeffectslotArray &auxslots = *ctx->mActiveAuxSlots.load(std::memory_order_acquire); - const al::span voices{ctx->mVoices->data(), - ctx->mVoiceCount.load(std::memory_order_acquire)}; + const al::span voices{ctx->mVoices.data(), ctx->mVoices.size()}; /* Process pending propery updates for objects on the context. */ ProcessParamUpdates(ctx, auxslots, voices); @@ -1755,9 +1754,7 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) voice.mSourceID.store(0u, std::memory_order_relaxed); voice.mPlayState.store(ALvoice::Stopped, std::memory_order_release); }; - std::for_each(ctx->mVoices->begin(), - ctx->mVoices->begin() + ctx->mVoiceCount.load(std::memory_order_acquire), - stop_voice); + std::for_each(ctx->mVoices.begin(), ctx->mVoices.end(), stop_voice); } IncrementRef(device->MixCount); } diff --git a/alc/alu.h b/alc/alu.h index 51c5f702..3b6045f0 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -269,6 +269,7 @@ struct ALvoice { ALvoice() = default; ALvoice(const ALvoice&) = delete; + ALvoice(ALvoice&& rhs) noexcept { *this = std::move(rhs); } ~ALvoice() { delete mUpdate.exchange(nullptr, std::memory_order_acq_rel); } ALvoice& operator=(const ALvoice&) = delete; ALvoice& operator=(ALvoice&& rhs) noexcept -- cgit v1.2.3 From 97c043da072470afcb9707eeb81ff52336d63e1e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 5 Sep 2019 04:00:49 -0700 Subject: Don't set voice properties in ApplyOffset --- al/source.cpp | 65 ++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index be565d58..9bae27a5 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -50,6 +50,7 @@ #include "alexcpt.h" #include "almalloc.h" #include "alnumeric.h" +#include "aloptional.h" #include "alspan.h" #include "alu.h" #include "ambidefs.h" @@ -382,7 +383,7 @@ ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) * or Second offset supplied by the application). This takes into account the * fact that the buffer format may have been modifed since. */ -ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac) +bool GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac) { const ALbuffer *BufferFmt{nullptr}; const ALbufferlistitem *BufferList; @@ -398,7 +399,7 @@ ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac) { Source->OffsetType = AL_NONE; Source->Offset = 0.0; - return AL_FALSE; + return false; } ALdouble dbloff, dblfrac; @@ -439,21 +440,30 @@ ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac) Source->OffsetType = AL_NONE; Source->Offset = 0.0; - return AL_TRUE; + return true; } -/* ApplyOffset + +struct VoicePos { + ALuint pos, frac; + ALbufferlistitem *bufferitem; +}; + +/** + * CalcOffset * - * Apply the stored playback offset to the Source. This function will update - * the number of buffers "played" given the stored offset. + * Calculates the voice position, fixed-point fraction, and bufferlist item + * using the source's stored offset. If the source has no stored offset, or the + * offset is out of range, returns an empty optional. */ -ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) +al::optional CalcOffset(ALsource *Source) { + al::optional ret; + /* Get sample frame offset */ - ALuint offset{0u}; - ALuint frac{0u}; + ALuint offset{0u}, frac{0u}; if(!GetSampleOffset(Source, &offset, &frac)) - return AL_FALSE; + return ret; ALuint totalBufferLen{0u}; ALbufferlistitem *BufferList{Source->queue}; @@ -462,10 +472,8 @@ ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) if(BufferList->mSampleLen > offset-totalBufferLen) { /* Offset is in this buffer */ - voice->mPosition.store(offset - totalBufferLen, std::memory_order_relaxed); - voice->mPositionFrac.store(frac, std::memory_order_relaxed); - voice->mCurrentBuffer.store(BufferList, std::memory_order_release); - return AL_TRUE; + ret = {offset-totalBufferLen, frac, BufferList}; + return ret; } totalBufferLen += BufferList->mSampleLen; @@ -473,7 +481,7 @@ ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) } /* Offset is out of range of the queue */ - return AL_FALSE; + return ret; } @@ -1013,8 +1021,12 @@ bool SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a */ if(ALvoice *voice{GetSourceVoice(Source, Context)}) { - if(ApplyOffset(Source, voice) == AL_FALSE) - SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid offset"); + auto vpos = CalcOffset(Source); + if(!vpos) SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid offset"); + + voice->mPosition.store(vpos->pos, std::memory_order_relaxed); + voice->mPositionFrac.store(vpos->frac, std::memory_order_relaxed); + voice->mCurrentBuffer.store(vpos->bufferitem, std::memory_order_release); } } return true; @@ -1228,8 +1240,12 @@ bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a BackendLockGuard _{*device->Backend}; if(ALvoice *voice{GetSourceVoice(Source, Context)}) { - if(ApplyOffset(Source, voice) == AL_FALSE) - SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid source offset"); + auto vpos = CalcOffset(Source); + if(!vpos) SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid source offset"); + + voice->mPosition.store(vpos->pos, std::memory_order_relaxed); + voice->mPositionFrac.store(vpos->frac, std::memory_order_relaxed); + voice->mCurrentBuffer.store(vpos->bufferitem, std::memory_order_release); } } return true; @@ -2765,10 +2781,13 @@ START_API_FUNC voice->mPosition.store(0u, std::memory_order_relaxed); voice->mPositionFrac.store(0, std::memory_order_relaxed); bool start_fading{false}; - if(ApplyOffset(source, voice) != AL_FALSE) - start_fading = voice->mPosition.load(std::memory_order_relaxed) != 0 || - voice->mPositionFrac.load(std::memory_order_relaxed) != 0 || - voice->mCurrentBuffer.load(std::memory_order_relaxed) != BufferList; + if(auto vpos = CalcOffset(source)) + { + start_fading = vpos->pos != 0 || vpos->frac != 0 || vpos->bufferitem != BufferList; + voice->mPosition.store(vpos->pos, std::memory_order_relaxed); + voice->mPositionFrac.store(vpos->frac, std::memory_order_relaxed); + voice->mCurrentBuffer.store(vpos->bufferitem, std::memory_order_relaxed); + } ALbuffer *buffer{BufferList->mBuffer}; voice->mFrequency = buffer->Frequency; -- cgit v1.2.3 From e5c9643dd55721ce36ea84bf15134127e04aba71 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 5 Sep 2019 15:08:22 -0700 Subject: Combine two functions into one --- al/source.cpp | 97 ++++++++++++++++++++++++----------------------------------- 1 file changed, 40 insertions(+), 57 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index 9bae27a5..1b5aa851 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -377,96 +377,79 @@ ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) } -/* GetSampleOffset +struct VoicePos { + ALuint pos, frac; + ALbufferlistitem *bufferitem; +}; + +/** + * GetSampleOffset * - * Retrieves the sample offset into the Source's queue (from the Sample, Byte - * or Second offset supplied by the application). This takes into account the - * fact that the buffer format may have been modifed since. + * Retrieves the voice position, fixed-point fraction, and bufferlist item + * using the source's stored offset and offset type. If the source has no + * stored offset, or the offset is out of range, returns an empty optional. */ -bool GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac) +al::optional GetSampleOffset(ALsource *Source) { - const ALbuffer *BufferFmt{nullptr}; - const ALbufferlistitem *BufferList; - + al::optional ret; + /* Find the first valid Buffer in the Queue */ - BufferList = Source->queue; - while(BufferList && !BufferFmt) + const ALbuffer *BufferFmt{nullptr}; + ALbufferlistitem *BufferList{Source->queue}; + while(BufferList) { - BufferFmt = BufferList->mBuffer; + if((BufferFmt=BufferList->mBuffer) != nullptr) break; BufferList = BufferList->mNext.load(std::memory_order_relaxed); } - if(!BufferFmt) + if(!BufferList) { Source->OffsetType = AL_NONE; Source->Offset = 0.0; - return false; + return ret; } + /* Get sample frame offset */ + ALuint offset{0u}, frac{0u}; ALdouble dbloff, dblfrac; switch(Source->OffsetType) { case AL_BYTE_OFFSET: /* Determine the ByteOffset (and ensure it is block aligned) */ - *offset = static_cast(Source->Offset); + offset = static_cast(Source->Offset); if(BufferFmt->OriginalType == UserFmtIMA4) { - ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; - *offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels); - *offset *= BufferFmt->OriginalAlign; + const ALsizei align{(BufferFmt->OriginalAlign-1)/2 + 4}; + offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels); + offset *= BufferFmt->OriginalAlign; } else if(BufferFmt->OriginalType == UserFmtMSADPCM) { - ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; - *offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels); - *offset *= BufferFmt->OriginalAlign; + const ALsizei align{(BufferFmt->OriginalAlign-2)/2 + 7}; + offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels); + offset *= BufferFmt->OriginalAlign; } else - *offset /= FrameSizeFromFmt(BufferFmt->mFmtChannels, BufferFmt->mFmtType); - *frac = 0; + offset /= FrameSizeFromFmt(BufferFmt->mFmtChannels, BufferFmt->mFmtType); + frac = 0; break; case AL_SAMPLE_OFFSET: - dblfrac = modf(Source->Offset, &dbloff); - *offset = static_cast(mind(dbloff, std::numeric_limits::max())); - *frac = static_cast(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0)); + dblfrac = std::modf(Source->Offset, &dbloff); + offset = static_cast(mind(dbloff, std::numeric_limits::max())); + frac = static_cast(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0)); break; case AL_SEC_OFFSET: - dblfrac = modf(Source->Offset*BufferFmt->Frequency, &dbloff); - *offset = static_cast(mind(dbloff, std::numeric_limits::max())); - *frac = static_cast(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0)); + dblfrac = std::modf(Source->Offset*BufferFmt->Frequency, &dbloff); + offset = static_cast(mind(dbloff, std::numeric_limits::max())); + frac = static_cast(mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0)); break; } Source->OffsetType = AL_NONE; Source->Offset = 0.0; - return true; -} - - -struct VoicePos { - ALuint pos, frac; - ALbufferlistitem *bufferitem; -}; - -/** - * CalcOffset - * - * Calculates the voice position, fixed-point fraction, and bufferlist item - * using the source's stored offset. If the source has no stored offset, or the - * offset is out of range, returns an empty optional. - */ -al::optional CalcOffset(ALsource *Source) -{ - al::optional ret; - - /* Get sample frame offset */ - ALuint offset{0u}, frac{0u}; - if(!GetSampleOffset(Source, &offset, &frac)) - return ret; - + /* Find the bufferlist item this offset belongs to. */ ALuint totalBufferLen{0u}; - ALbufferlistitem *BufferList{Source->queue}; while(BufferList && totalBufferLen <= offset) { if(BufferList->mSampleLen > offset-totalBufferLen) @@ -1021,7 +1004,7 @@ bool SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a */ if(ALvoice *voice{GetSourceVoice(Source, Context)}) { - auto vpos = CalcOffset(Source); + auto vpos = GetSampleOffset(Source); if(!vpos) SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid offset"); voice->mPosition.store(vpos->pos, std::memory_order_relaxed); @@ -1240,7 +1223,7 @@ bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a BackendLockGuard _{*device->Backend}; if(ALvoice *voice{GetSourceVoice(Source, Context)}) { - auto vpos = CalcOffset(Source); + auto vpos = GetSampleOffset(Source); if(!vpos) SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid source offset"); voice->mPosition.store(vpos->pos, std::memory_order_relaxed); @@ -2781,7 +2764,7 @@ START_API_FUNC voice->mPosition.store(0u, std::memory_order_relaxed); voice->mPositionFrac.store(0, std::memory_order_relaxed); bool start_fading{false}; - if(auto vpos = CalcOffset(source)) + if(auto vpos = GetSampleOffset(source)) { start_fading = vpos->pos != 0 || vpos->frac != 0 || vpos->bufferitem != BufferList; voice->mPosition.store(vpos->pos, std::memory_order_relaxed); -- cgit v1.2.3 From 987fd13796d5761b7adc5f6e137e7a6149d02f7b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 6 Sep 2019 21:20:20 -0700 Subject: Use a new voice when restarting a playing source --- al/source.cpp | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index 1b5aa851..44c46d65 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -2716,14 +2716,6 @@ START_API_FUNC ALvoice *voice{GetSourceVoice(source, context.get())}; switch(GetSourceState(source, voice)) { - case AL_PLAYING: - assert(voice != nullptr); - /* A source that's already playing is restarted from the beginning. */ - voice->mCurrentBuffer.store(BufferList, std::memory_order_relaxed); - voice->mPosition.store(0u, std::memory_order_relaxed); - voice->mPositionFrac.store(0, std::memory_order_release); - return; - case AL_PAUSED: assert(voice != nullptr); /* A source that's paused simply resumes. */ @@ -2732,6 +2724,19 @@ START_API_FUNC SendStateChangeEvent(context.get(), source->id, AL_PLAYING); return; + case AL_PLAYING: + assert(voice != nullptr); + /* A source that's already playing is restarted from the beginning. + * Stop the current voice and start a new one so it properly cross- + * fades back to the beginning. + */ + voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed); + voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); + voice->mSourceID.store(0u, std::memory_order_release); + voice->mPlayState.store(ALvoice::Stopping, std::memory_order_release); + voice = nullptr; + break; + default: assert(voice == nullptr); break; @@ -2851,10 +2856,13 @@ START_API_FUNC voice->mSourceID.store(source->id, std::memory_order_relaxed); voice->mPlayState.store(ALvoice::Playing, std::memory_order_release); - source->state = AL_PLAYING; source->VoiceIdx = vidx; - SendStateChangeEvent(context.get(), source->id, AL_PLAYING); + if(source->state != AL_PLAYING) + { + source->state = AL_PLAYING; + SendStateChangeEvent(context.get(), source->id, AL_PLAYING); + } }; std::for_each(srchandles, srchandles+n, start_source); } -- cgit v1.2.3 From fcb496bb5c8735a9a1efc926bd0caa8657bbaf5e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 8 Sep 2019 00:31:55 -0700 Subject: Avoid unnecessary explicit copy methods --- common/vecmat.h | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/common/vecmat.h b/common/vecmat.h index 83f1381e..7186ec6c 100644 --- a/common/vecmat.h +++ b/common/vecmat.h @@ -10,21 +10,13 @@ namespace alu { class Vector { - alignas(16) std::array mVals{}; + alignas(16) std::array mVals; public: - constexpr Vector() noexcept = default; + Vector() noexcept = default; constexpr Vector(float a, float b, float c, float d) noexcept : mVals{{a, b, c, d}} { } - Vector(const Vector &rhs) noexcept - { mVals = rhs.mVals; } - - Vector& operator=(const Vector &rhs) noexcept - { - mVals = rhs.mVals; - return *this; - } float& operator[](size_t idx) noexcept { return mVals[idx]; } constexpr const float& operator[](size_t idx) const noexcept { return mVals[idx]; } @@ -55,24 +47,16 @@ public: }; class Matrix { - alignas(16) std::array,4> mVals{}; + alignas(16) std::array,4> mVals; public: - constexpr Matrix() noexcept = default; + Matrix() noexcept = default; constexpr Matrix(float aa, float ab, float ac, float ad, float ba, float bb, float bc, float bd, float ca, float cb, float cc, float cd, float da, float db, float dc, float dd) noexcept : mVals{{{{aa, ab, ac, ad}}, {{ba, bb, bc, bd}}, {{ca, cb, cc, cd}}, {{da, db, dc, dd}}}} { } - Matrix(const Matrix &rhs) noexcept - { mVals = rhs.mVals; } - - Matrix& operator=(const Matrix &rhs) noexcept - { - mVals = rhs.mVals; - return *this; - } std::array& operator[](size_t idx) noexcept { return mVals[idx]; } constexpr const std::array& operator[](size_t idx) const noexcept { return mVals[idx]; } -- cgit v1.2.3 From ec8b56ef3bae5bff16b93b08f9c6cab11b7e53b2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 8 Sep 2019 00:59:10 -0700 Subject: Remove unneeded TRACEREF logging --- alc/hrtf.cpp | 4 ++-- alc/logging.h | 5 ----- docs/env-vars.txt | 3 --- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index c0e2b982..5a39f686 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -1373,13 +1373,13 @@ HrtfEntry *GetLoadedHrtf(HrtfHandle *handle) void HrtfEntry::IncRef() { auto ref = IncrementRef(this->ref); - TRACEREF("HrtfEntry %p increasing refcount to %u\n", this, ref); + TRACE("HrtfEntry %p increasing refcount to %u\n", this, ref); } void HrtfEntry::DecRef() { auto ref = DecrementRef(this->ref); - TRACEREF("HrtfEntry %p decreasing refcount to %u\n", this, ref); + TRACE("HrtfEntry %p decreasing refcount to %u\n", this, ref); if(ref == 0) { std::lock_guard _{LoadedHrtfLock}; diff --git a/alc/logging.h b/alc/logging.h index 8a3e75e6..24cfda71 100644 --- a/alc/logging.h +++ b/alc/logging.h @@ -38,11 +38,6 @@ enum LogLevel { }; extern LogLevel gLogLevel; -#define TRACEREF(...) do { \ - if UNLIKELY(gLogLevel >= LogRef) \ - AL_PRINT("(--)", __VA_ARGS__); \ -} while(0) - #define TRACE(...) do { \ if UNLIKELY(gLogLevel >= LogTrace) \ AL_PRINT("(II)", __VA_ARGS__); \ diff --git a/docs/env-vars.txt b/docs/env-vars.txt index a973ee81..2b8d5e4d 100644 --- a/docs/env-vars.txt +++ b/docs/env-vars.txt @@ -11,9 +11,6 @@ Specifies the amount of logging OpenAL Soft will write out: 1 - Prints out errors only 2 - Prints out warnings and errors 3 - Prints out additional information, as well as warnings and errors -4 - Same as 3, but also device and context reference count changes. This will - print out *a lot* of info, and is generally not useful unless you're trying - to track a reference leak within the library. ALSOFT_LOGFILE Specifies a filename that logged output will be written to. Note that the file -- cgit v1.2.3 From 449c09bf031731a3f36b71f78a2d54b059802367 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 8 Sep 2019 00:59:56 -0700 Subject: Remove mention of an unsupported env var --- docs/env-vars.txt | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/docs/env-vars.txt b/docs/env-vars.txt index 2b8d5e4d..fee9ffb0 100644 --- a/docs/env-vars.txt +++ b/docs/env-vars.txt @@ -76,13 +76,3 @@ which some applications make use of to protect against partial updates. In an attempt to standardize on that behavior, OpenAL Soft has changed those methods accordingly. Setting this to "ignore" restores the previous no-op behavior for applications that interact poorly with the new behavior. - -__ALSOFT_REVERB_IGNORES_SOUND_SPEED -Older versions of OpenAL Soft ignored the app-specified speed of sound when -calculating distance-related reverb decays and always assumed the default -343.3m/s. Now, both of the AL_SPEED_OF_SOUND and AL_METERS_PER_UNIT properties -are taken into account for speed of sound adjustments to have an appropriate -affect on the reverb decay. Consequently, applications that use reverb but -don't set these properties properly may find the reverb decay too strong. -Setting this to "true" or "1" will revert to the old behavior for those apps -and assume the default speed of sound for reverb. -- cgit v1.2.3 From 19e1cd7430a19cb3592b4bd3e737e2a0e4314a91 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 8 Sep 2019 01:36:19 -0700 Subject: Make hq-mode the default and update ambisonics.txt --- alc/panning.cpp | 7 +++---- alsoftrc.sample | 2 +- docs/ambisonics.txt | 41 ++++++++++++++++---------------------- utils/alsoft-config/mainwindow.cpp | 4 ++-- 4 files changed, 23 insertions(+), 31 deletions(-) diff --git a/alc/panning.cpp b/alc/panning.cpp index 5143b1ea..a33b9387 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -509,9 +509,8 @@ void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, co auto accum_spkr_dist = std::bind(std::plus{}, _1, std::bind(std::mem_fn(&AmbDecConf::SpeakerConf::Distance), _2)); const ALfloat avg_dist{ - std::accumulate(conf->Speakers.begin(), conf->Speakers.end(), float{0.0f}, - accum_spkr_dist) / static_cast(conf->Speakers.size()) - }; + std::accumulate(conf->Speakers.begin(), conf->Speakers.end(), 0.0f, accum_spkr_dist) / + static_cast(conf->Speakers.size())}; InitNearFieldCtrl(device, avg_dist, order, (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? chans_per_order3d : chans_per_order2d); @@ -717,7 +716,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr InitPanning(device); else { - int hqdec{GetConfigValueBool(devname, "decoder", "hq-mode", 0)}; + int hqdec{GetConfigValueBool(devname, "decoder", "hq-mode", 1)}; InitCustomPanning(device, !!hqdec, pconf, speakermap); } if(device->AmbiDecoder) diff --git a/alsoftrc.sample b/alsoftrc.sample index f0dde916..7cb780a3 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -272,7 +272,7 @@ # configuration files for the appropriate speaker configuration you intend to # use (see the quad, surround51, etc options below). Currently, up to third- # order decoding is supported. -#hq-mode = false +#hq-mode = true ## distance-comp: # Enables compensation for the speakers' relative distances to the listener. diff --git a/docs/ambisonics.txt b/docs/ambisonics.txt index 2d94427e..b03e3bed 100644 --- a/docs/ambisonics.txt +++ b/docs/ambisonics.txt @@ -79,30 +79,23 @@ Soft (or any other OpenAL implementation that wishes to) can render using Ambisonics and decode the ambisonic mix for a high level of accuracy over what simple pan-pot could provide. -This is effectively what the high-quality mode option does, when given an -appropriate decoder configuation for the playback channel layout. 3D rendering -and effect mixing is done to an ambisonic buffer, which is later decoded for -output utilizing the benefits available to ambisonic processing. - -The basic, non-high-quality, renderer uses similar principles, however it skips -the frequency-dependent processing (so low frequency sounds are treated the -same as high frequency sounds) and does some creative manipulation of the -involved math to skip the intermediate ambisonic buffer, rendering more -directly to the output while still taking advantage of all the available -speakers to reconstruct the sound wave. This method trades away some playback -quality for less memory and processor usage. - -In addition to providing good support for surround sound playback, Ambisonics -also has benefits with stereo output. 2-channel UHJ is a stereo-compatible -format that encodes some surround sound information using a wide-band 90-degree -phase shift filter. It works by taking a B-Format signal, and deriving a -frontal stereo mix with the rear sounds attenuated and filtered in with it. -Although the result is not as good as 3-channel (2D) B-Format, it has the -distinct advantage of only using 2 channels and being compatible with stereo -output. This means it will sound just fine when played as-is through a normal -stereo device, or it may optionally be fed to a properly configured surround -sound receiver which can extract the encoded information and restore some of -the original surround sound signal. +When given an appropriate decoder configuration for the channel layout, the +ambisonic mix can be decoded utilizing the benefits available to ambisonic +processing, including frequency-dependent processing and near-field effects. +Without a decoder configuration, the ambisonic mix can still be decoded for +good stereo or surround sound output, although without near-field effects as +there's no speaker distance information. + +In addition to surround sound output, Ambisonics also has benefits with stereo +output. 2-channel UHJ is a stereo-compatible format that encodes some surround +sound information using a wide-band 90-degree phase shift filter. This is +generated by taking the ambisonic mix and deriving a front-stereo mix with +with the rear sounds filtered in with it. Although the result is not as good as +3-channel (2D) B-Format, it has the distinct advantage of only using 2 channels +and being compatible with stereo output. This means it will sound just fine +when played as-is through a normal stereo device, or it may optionally be fed +to a properly configured surround sound receiver which can extract the encoded +information and restore some of the original surround sound signal. What Are Its Limitations? diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index aa0df438..7e5159cf 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -716,7 +716,7 @@ void MainWindow::loadConfig(const QString &fname) } } - bool hqmode{settings.value("decoder/hq-mode", false).toBool()}; + bool hqmode{settings.value("decoder/hq-mode", true).toBool()}; ui->decoderHQModeCheckBox->setChecked(hqmode); ui->decoderDistCompCheckBox->setCheckState(getCheckState(settings.value("decoder/distance-comp"))); ui->decoderNFEffectsCheckBox->setCheckState(getCheckState(settings.value("decoder/nfc"))); @@ -976,7 +976,7 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("dither", getCheckValue(ui->outputDitherCheckBox)); settings.setValue("decoder/hq-mode", - ui->decoderHQModeCheckBox->isChecked() ? QString{"true"} : QString{/*"false"*/} + ui->decoderHQModeCheckBox->isChecked() ? QString{/*"true"*/} : QString{"false"} ); settings.setValue("decoder/distance-comp", getCheckValue(ui->decoderDistCompCheckBox)); settings.setValue("decoder/nfc", getCheckValue(ui->decoderNFEffectsCheckBox)); -- cgit v1.2.3 From 65374dc5d00a2fa64657d4310f7a27c09eaa4c9a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 10 Sep 2019 23:01:33 -0700 Subject: Avoid dynamically allocating ChannelConverter --- alc/backends/wasapi.cpp | 22 ++++++---------------- alc/converter.cpp | 8 -------- alc/converter.h | 10 +--------- 3 files changed, 7 insertions(+), 33 deletions(-) diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index dbf1208d..ec1ee936 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -1166,7 +1166,7 @@ struct WasapiCapture final : public BackendBase, WasapiProxy { IAudioCaptureClient *mCapture{nullptr}; HANDLE mNotifyEvent{nullptr}; - ChannelConverterPtr mChannelConv; + ChannelConverter mChannelConv{}; SampleConverterPtr mSampleConv; RingBufferPtr mRing; @@ -1216,10 +1216,10 @@ FORCE_ALIGN int WasapiCapture::recordProc() ERR("Failed to get capture buffer: 0x%08lx\n", hr); else { - if(mChannelConv) + if(mChannelConv.is_active()) { samples.resize(numsamples*2); - mChannelConv->convert(rdata, samples.data(), numsamples); + mChannelConv.convert(rdata, samples.data(), numsamples); rdata = reinterpret_cast(samples.data()); } @@ -1487,7 +1487,7 @@ HRESULT WasapiCapture::resetProxy() } mSampleConv = nullptr; - mChannelConv = nullptr; + mChannelConv = {}; if(wfx != nullptr) { @@ -1546,12 +1546,7 @@ HRESULT WasapiCapture::resetProxy() if(mDevice->FmtChans == DevFmtMono && OutputType.Format.nChannels == 2) { - mChannelConv = CreateChannelConverter(srcType, DevFmtStereo, mDevice->FmtChans); - if(!mChannelConv) - { - ERR("Failed to create %s stereo-to-mono converter\n", DevFmtTypeString(srcType)); - return E_FAIL; - } + mChannelConv = ChannelConverter{srcType, DevFmtStereo, mDevice->FmtChans}; TRACE("Created %s stereo-to-mono converter\n", DevFmtTypeString(srcType)); /* The channel converter always outputs float, so change the input type * for the resampler/type-converter. @@ -1560,12 +1555,7 @@ HRESULT WasapiCapture::resetProxy() } else if(mDevice->FmtChans == DevFmtStereo && OutputType.Format.nChannels == 1) { - mChannelConv = CreateChannelConverter(srcType, DevFmtMono, mDevice->FmtChans); - if(!mChannelConv) - { - ERR("Failed to create %s mono-to-stereo converter\n", DevFmtTypeString(srcType)); - return E_FAIL; - } + mChannelConv = ChannelConverter{srcType, DevFmtMono, mDevice->FmtChans}; TRACE("Created %s mono-to-stereo converter\n", DevFmtTypeString(srcType)); srcType = DevFmtFloat; } diff --git a/alc/converter.cpp b/alc/converter.cpp index de61415a..7e3c17cc 100644 --- a/alc/converter.cpp +++ b/alc/converter.cpp @@ -327,14 +327,6 @@ ALuint SampleConverter::convert(const ALvoid **src, ALuint *srcframes, ALvoid *d } -ChannelConverterPtr CreateChannelConverter(DevFmtType srcType, DevFmtChannels srcChans, DevFmtChannels dstChans) -{ - if(srcChans != dstChans && !((srcChans == DevFmtMono && dstChans == DevFmtStereo) || - (srcChans == DevFmtStereo && dstChans == DevFmtMono))) - return nullptr; - return al::make_unique(srcType, srcChans, dstChans); -} - void ChannelConverter::convert(const ALvoid *src, ALfloat *dst, ALuint frames) const { if(mSrcChans == DevFmtStereo && mDstChans == DevFmtMono) diff --git a/alc/converter.h b/alc/converter.h index 50254213..62f09af1 100644 --- a/alc/converter.h +++ b/alc/converter.h @@ -58,17 +58,9 @@ struct ChannelConverter { DevFmtChannels mSrcChans; DevFmtChannels mDstChans; - ChannelConverter(DevFmtType srctype, DevFmtChannels srcchans, DevFmtChannels dstchans) - : mSrcType(srctype), mSrcChans(srcchans), mDstChans(dstchans) - { } + bool is_active() const noexcept { return mSrcChans != mDstChans; } void convert(const ALvoid *src, ALfloat *dst, ALuint frames) const; - - DEF_NEWDEL(ChannelConverter) }; -using ChannelConverterPtr = std::unique_ptr; - -ChannelConverterPtr CreateChannelConverter(DevFmtType srcType, DevFmtChannels srcChans, - DevFmtChannels dstChans); #endif /* CONVERTER_H */ -- cgit v1.2.3 From c6c50484160435ee96e51eece154013fe6e48237 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 11 Sep 2019 03:22:10 -0700 Subject: Don't inherit for the allocator --- common/almalloc.h | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/common/almalloc.h b/common/almalloc.h index ca92316a..785592bd 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -34,36 +34,32 @@ namespace al { #define REQUIRES(...) typename std::enable_if<(__VA_ARGS__),int>::type = 0 -template -struct allocator : public std::allocator { - using size_type = size_t; - using pointer = T*; - using const_pointer = const T*; +template +struct allocator { + using value_type = T; + using is_always_equal = std::true_type; template struct rebind { - using other = allocator; + using other = allocator; }; - pointer allocate(size_type n, const void* = nullptr) - { - if(n > std::numeric_limits::max() / sizeof(T)) - throw std::bad_alloc(); + allocator() = default; + template + constexpr allocator(const allocator&) noexcept { } - void *ret{al_malloc(alignment, n*sizeof(T))}; - if(!ret) throw std::bad_alloc(); - return static_cast(ret); + [[nodiscard]] T *allocate(std::size_t n) + { + if(n > std::numeric_limits::max() / sizeof(T)) throw std::bad_alloc(); + if(auto p = static_cast(al_malloc(alignment, n*sizeof(T)))) return p; + throw std::bad_alloc(); } - - void deallocate(pointer p, size_type) - { al_free(p); } - - allocator() : std::allocator() { } - allocator(const allocator &a) : std::allocator(a) { } - template - allocator(const allocator &a) : std::allocator(a) - { } + void deallocate(T *p, std::size_t) noexcept { al_free(p); } }; +template +bool operator==(const allocator&, const allocator&) noexcept { return true; } +template +bool operator!=(const allocator&, const allocator&) noexcept { return false; } template inline T* assume_aligned(T *ptr) noexcept -- cgit v1.2.3 From 5b37e2339bc91de3424b51600c3d3b96401d0b9c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 11 Sep 2019 03:59:53 -0700 Subject: Simplify flexible array member usage --- alc/converter.cpp | 11 +++++------ alc/converter.h | 8 +------- alc/hrtf.cpp | 19 ++++--------------- alc/hrtf.h | 4 +--- alc/ringbuffer.cpp | 2 +- alc/ringbuffer.h | 4 +--- common/almalloc.h | 20 ++++++++++++++++++-- 7 files changed, 31 insertions(+), 37 deletions(-) diff --git a/alc/converter.cpp b/alc/converter.cpp index 7e3c17cc..58b59179 100644 --- a/alc/converter.cpp +++ b/alc/converter.cpp @@ -143,14 +143,13 @@ void Stereo2Mono(ALfloat *RESTRICT dst, const void *src, const size_t frames) no } // namespace -SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, ALsizei numchans, - ALsizei srcRate, ALsizei dstRate, Resampler resampler) +SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, size_t numchans, + ALsizei srcRate, ALsizei dstRate, Resampler resampler) { - if(numchans <= 0 || srcRate <= 0 || dstRate <= 0) + if(numchans < 1 || srcRate < 1 || dstRate < 1) return nullptr; - void *ptr{al_calloc(16, SampleConverter::Sizeof(numchans))}; - SampleConverterPtr converter{new (ptr) SampleConverter{static_cast(numchans)}}; + SampleConverterPtr converter{new (FamCount{numchans}) SampleConverter{numchans}}; converter->mSrcType = srcType; converter->mDstType = dstType; converter->mSrcTypeSize = BytesFromDevFmt(srcType); @@ -162,7 +161,7 @@ SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, /* Have to set the mixer FPU mode since that's what the resampler code expects. */ FPUCtl mixer_mode{}; auto step = static_cast( - mind(static_cast(srcRate)/dstRate*FRACTIONONE + 0.5, MAX_PITCH*FRACTIONONE)); + mind(srcRate*ALdouble{FRACTIONONE}/dstRate + 0.5, MAX_PITCH*FRACTIONONE)); converter->mIncrement = maxi(step, 1); if(converter->mIncrement == FRACTIONONE) converter->mResample = Resample_; diff --git a/alc/converter.h b/alc/converter.h index 62f09af1..46e57f10 100644 --- a/alc/converter.h +++ b/alc/converter.h @@ -39,13 +39,7 @@ struct SampleConverter { ALuint convert(const ALvoid **src, ALuint *srcframes, ALvoid *dst, ALuint dstframes); ALuint availableOut(ALuint srcframes) const; - static constexpr size_t Sizeof(size_t length) noexcept - { - return maxz(sizeof(SampleConverter), - al::FlexArray::Sizeof(length, offsetof(SampleConverter, mChan))); - } - - DEF_PLACE_NEWDEL() + DEF_FAM_NEWDEL(SampleConverter, mChan) }; using SampleConverterPtr = std::unique_ptr; diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index 5a39f686..04818a4f 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -61,22 +61,12 @@ struct HrtfHandle { HrtfHandle(const HrtfHandle&) = delete; HrtfHandle& operator=(const HrtfHandle&) = delete; - static std::unique_ptr Create(size_t fname_len); - static constexpr size_t Sizeof(size_t length) noexcept - { - return maxz(sizeof(HrtfHandle), - al::FlexArray::Sizeof(length, offsetof(HrtfHandle, filename))); - } + static std::unique_ptr Create(size_t fname_len) + { return std::unique_ptr{new (FamCount{fname_len}) HrtfHandle{fname_len}}; } - DEF_PLACE_NEWDEL() + DEF_FAM_NEWDEL(HrtfHandle, filename) }; -std::unique_ptr HrtfHandle::Create(size_t fname_len) -{ - void *ptr{al_calloc(alignof(HrtfHandle), HrtfHandle::Sizeof(fname_len))}; - return std::unique_ptr{new (ptr) HrtfHandle{fname_len}}; -} - namespace { using namespace std::placeholders; @@ -294,8 +284,7 @@ void GetHrtfCoeffs(const HrtfEntry *Hrtf, ALfloat elevation, ALfloat azimuth, AL std::unique_ptr DirectHrtfState::Create(size_t num_chans) { - void *ptr{al_calloc(16, DirectHrtfState::Sizeof(num_chans))}; - return std::unique_ptr{new (ptr) DirectHrtfState{num_chans}}; + return std::unique_ptr{new (FamCount{num_chans}) DirectHrtfState{num_chans}}; } void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuint NumChannels, diff --git a/alc/hrtf.h b/alc/hrtf.h index 487dca61..85614f2e 100644 --- a/alc/hrtf.h +++ b/alc/hrtf.h @@ -85,10 +85,8 @@ struct DirectHrtfState { DirectHrtfState(size_t numchans) : Coeffs{numchans} { } static std::unique_ptr Create(size_t num_chans); - static constexpr size_t Sizeof(size_t numchans) noexcept - { return al::FlexArray::Sizeof(numchans, offsetof(DirectHrtfState, Coeffs)); } - DEF_PLACE_NEWDEL() + DEF_FAM_NEWDEL(DirectHrtfState, Coeffs) }; struct AngularPoint { diff --git a/alc/ringbuffer.cpp b/alc/ringbuffer.cpp index d99676b8..d61f6129 100644 --- a/alc/ringbuffer.cpp +++ b/alc/ringbuffer.cpp @@ -48,7 +48,7 @@ RingBufferPtr CreateRingBuffer(size_t sz, size_t elem_sz, int limit_writes) if(power_of_two < sz) return nullptr; const size_t bufbytes{power_of_two * elem_sz}; - RingBufferPtr rb{new (al_calloc(16, sizeof(*rb) + bufbytes)) RingBuffer{bufbytes}}; + RingBufferPtr rb{new (FamCount{bufbytes}) RingBuffer{bufbytes}}; rb->mWriteSize = limit_writes ? sz : (power_of_two-1); rb->mSizeMask = power_of_two - 1; rb->mElemSize = elem_sz; diff --git a/alc/ringbuffer.h b/alc/ringbuffer.h index 84139b66..3151fdcb 100644 --- a/alc/ringbuffer.h +++ b/alc/ringbuffer.h @@ -34,8 +34,6 @@ struct RingBuffer { al::FlexArray mBuffer; RingBuffer(const size_t count) : mBuffer{count} { } - RingBuffer(const RingBuffer&) = delete; - RingBuffer& operator=(const RingBuffer&) = delete; /** Reset the read and write pointers to zero. This is not thread safe. */ void reset() noexcept; @@ -84,7 +82,7 @@ struct RingBuffer { /** Advance the write pointer `cnt' places. */ void writeAdvance(size_t cnt) noexcept; - DEF_PLACE_NEWDEL() + DEF_FAM_NEWDEL(RingBuffer, mBuffer) }; using RingBufferPtr = std::unique_ptr; diff --git a/common/almalloc.h b/common/almalloc.h index 785592bd..232294cc 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -27,8 +27,24 @@ void al_free(void *ptr) noexcept; #define DEF_PLACE_NEWDEL() \ void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } \ - void operator delete(void *block) noexcept { al_free(block); } \ - void operator delete(void* /*block*/, void* /*ptr*/) noexcept { } + void operator delete(void *block, void*) noexcept { al_free(block); } \ + void operator delete(void *block) noexcept { al_free(block); } + +struct FamCount { size_t mCount; }; + +#define DEF_FAM_NEWDEL(T, FamMem) \ + static constexpr size_t Sizeof(size_t count) noexcept \ + { return decltype(FamMem)::Sizeof(count, offsetof(T, FamMem)); } \ + \ + void *operator new(size_t /*size*/, FamCount fam) \ + { \ + if(void *ret{al_malloc(alignof(T), T::Sizeof(fam.mCount))}) \ + return ret; \ + throw std::bad_alloc(); \ + } \ + void operator delete(void *block, FamCount /*fam*/) { al_free(block); } \ + void operator delete(void *block) noexcept { al_free(block); } + namespace al { -- cgit v1.2.3 From e4b15aeefcc220a46542c4bb2a2cea033e7954f0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 11 Sep 2019 04:55:54 -0700 Subject: Fix some implicit casts --- utils/makemhr/loaddef.cpp | 16 +++++++-------- utils/makemhr/makemhr.cpp | 51 +++++++++++++++++++++++------------------------ utils/sofa-info.cpp | 2 +- 3 files changed, 34 insertions(+), 35 deletions(-) diff --git a/utils/makemhr/loaddef.cpp b/utils/makemhr/loaddef.cpp index 28f2e1b0..89893e38 100644 --- a/utils/makemhr/loaddef.cpp +++ b/utils/makemhr/loaddef.cpp @@ -402,7 +402,7 @@ static int TrReadInt(TokenReaderT *tr, const int loBound, const int hiBound, int return 0; } temp[len] = '\0'; - *value = strtol(temp, nullptr, 10); + *value = static_cast(strtol(temp, nullptr, 10)); if(*value < loBound || *value > hiBound) { TrErrorAt(tr, tr->mLine, col, "Expected a value from %d to %d.\n", loBound, hiBound); @@ -1123,9 +1123,9 @@ static int LoadSofaSource(SourceRefT *src, const uint hrirRate, const uint n, do various coordinate systems, listener/source orientations, and direciontal vectors defined in the SOFA file. */ - target[0] = src->mAzimuth; - target[1] = src->mElevation; - target[2] = src->mRadius; + target[0] = static_cast(src->mAzimuth); + target[1] = static_cast(src->mElevation); + target[2] = static_cast(src->mRadius); mysofa_s2c(target); nearest = mysofa_lookup(sofa->lookup, target); @@ -1147,7 +1147,7 @@ static int LoadSofaSource(SourceRefT *src, const uint hrirRate, const uint n, do return 0; } - ExtractSofaHrir(sofa, nearest, src->mChannel, src->mOffset, n, hrir); + ExtractSofaHrir(sofa, static_cast(nearest), src->mChannel, src->mOffset, n, hrir); return 1; } @@ -1834,13 +1834,13 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData) continue; double ef{(90.0 + aer[1]) * (hData->mFds[fi].mEvCount - 1) / 180.0}; - ei = (int)std::round(ef); + ei = (uint)std::round(ef); ef = (ef - ei) * 180.0f / (hData->mFds[fi].mEvCount - 1); if(std::abs(ef) >= 0.1) continue; double af{aer[0] * hData->mFds[fi].mEvs[ei].mAzCount / 360.0f}; - ai = (int)std::round(af); + ai = (uint)std::round(af); af = (af - ai) * 360.0f / hData->mFds[fi].mEvs[ei].mAzCount; ai = ai % hData->mFds[fi].mEvs[ei].mAzCount; if(std::abs(af) >= 0.1) @@ -1913,7 +1913,7 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData) if(!TrReadIdent(tr, MAX_IDENT_LEN, ident)) return 0; - ti = MatchTargetEar(ident); + ti = static_cast(MatchTargetEar(ident)); if(static_cast(ti) < 0) { TrErrorAt(tr, line, col, "Expected a target ear.\n"); diff --git a/utils/makemhr/makemhr.cpp b/utils/makemhr/makemhr.cpp index e480277e..5930e582 100644 --- a/utils/makemhr/makemhr.cpp +++ b/utils/makemhr/makemhr.cpp @@ -220,15 +220,16 @@ static inline uint dither_rng(uint *seed) // Performs a triangular probability density function dither. The input samples // should be normalized (-1 to +1). static void TpdfDither(double *RESTRICT out, const double *RESTRICT in, const double scale, - const int count, const int step, uint *seed) + const uint count, const uint step, uint *seed) { static constexpr double PRNG_SCALE = 1.0 / std::numeric_limits::max(); - for(int i{0};i < count;i++) + for(uint i{0};i < count;i++) { uint prn0{dither_rng(seed)}; uint prn1{dither_rng(seed)}; - out[i*step] = std::round(in[i]*scale + (prn0*PRNG_SCALE - prn1*PRNG_SCALE)); + *out = std::round(*(in++)*scale + (prn0*PRNG_SCALE - prn1*PRNG_SCALE)); + out += step; } } @@ -254,18 +255,18 @@ static void FftArrange(const uint n, complex_d *inout) } // Performs the summation. -static void FftSummation(const int n, const double s, complex_d *cplx) +static void FftSummation(const uint n, const double s, complex_d *cplx) { double pi; - int m, m2; - int i, k, mk; + uint m, m2; + uint i, k, mk; pi = s * M_PI; for(m = 1, m2 = 2;m < n; m <<= 1, m2 <<= 1) { // v = Complex (-2.0 * sin (0.5 * pi / m) * sin (0.5 * pi / m), -sin (pi / m)) - double sm = sin(0.5 * pi / m); - auto v = complex_d{-2.0*sm*sm, -sin(pi / m)}; + double sm = std::sin(0.5 * pi / m); + auto v = complex_d{-2.0*sm*sm, -std::sin(pi / m)}; auto w = complex_d{1.0, 0.0}; for(i = 0;i < m;i++) { @@ -511,7 +512,7 @@ static double CalcKaiserBeta(const double rejection) * p -- gain compensation factor when sampling * f_t -- normalized center frequency (or cutoff; 0.5 is nyquist) */ -static double SincFilter(const int l, const double b, const double gain, const double cutoff, const int i) +static double SincFilter(const uint l, const double b, const double gain, const double cutoff, const uint i) { return Kaiser(b, static_cast(i - l) / l) * 2.0 * gain * cutoff * Sinc(2.0 * cutoff * (i - l)); } @@ -546,17 +547,15 @@ static double SincFilter(const int l, const double b, const double gain, const d // that's used to cut frequencies above the destination nyquist. void ResamplerSetup(ResamplerT *rs, const uint srcRate, const uint dstRate) { - double cutoff, width, beta; - uint gcd, l; - int i; - - gcd = Gcd(srcRate, dstRate); + const uint gcd{Gcd(srcRate, dstRate)}; rs->mP = dstRate / gcd; rs->mQ = srcRate / gcd; + /* The cutoff is adjusted by half the transition width, so the transition * ends before the nyquist (0.5). Both are scaled by the downsampling * factor. */ + double cutoff, width; if(rs->mP > rs->mQ) { cutoff = 0.475 / rs->mP; @@ -569,13 +568,13 @@ void ResamplerSetup(ResamplerT *rs, const uint srcRate, const uint dstRate) } // A rejection of -180 dB is used for the stop band. Round up when // calculating the left offset to avoid increasing the transition width. - l = (CalcKaiserOrder(180.0, width)+1) / 2; - beta = CalcKaiserBeta(180.0); + const uint l{(CalcKaiserOrder(180.0, width)+1) / 2}; + const double beta{CalcKaiserBeta(180.0)}; rs->mM = l*2 + 1; rs->mL = l; rs->mF.resize(rs->mM); - for(i = 0;i < (static_cast(rs->mM));i++) - rs->mF[i] = SincFilter(static_cast(l), beta, rs->mP, cutoff, i); + for(uint i{0};i < rs->mM;i++) + rs->mF[i] = SincFilter(l, beta, rs->mP, cutoff, i); } // Perform the upsample-filter-downsample resampling operation using a @@ -709,8 +708,8 @@ static int StoreMhr(const HrirDataT *hData, const char *filename) { const double scale = (hData->mSampleType == ST_S16) ? 32767.0 : ((hData->mSampleType == ST_S24) ? 8388607.0 : 0.0); - const int bps = (hData->mSampleType == ST_S16) ? 2 : - ((hData->mSampleType == ST_S24) ? 3 : 0); + const uint bps = (hData->mSampleType == ST_S16) ? 2 : + ((hData->mSampleType == ST_S24) ? 3 : 0); for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) { @@ -960,8 +959,8 @@ struct HrirReconstructor { std::vector mIrs; std::atomic mCurrent; std::atomic mDone; - size_t mFftSize; - size_t mIrPoints; + uint mFftSize; + uint mIrPoints; void Worker() { @@ -987,7 +986,7 @@ struct HrirReconstructor { */ MinimumPhase(mFftSize, mIrs[idx], h.data()); FftInverse(mFftSize, h.data()); - for(size_t i{0u};i < mIrPoints;++i) + for(uint i{0u};i < mIrPoints;++i) mIrs[idx][i] = h[i].real(); /* Increment the number of IRs done. */ @@ -1684,7 +1683,7 @@ int main(int argc, char *argv[]) switch(opt) { case 'r': - outRate = strtoul(optarg, &end, 10); + outRate = static_cast(strtoul(optarg, &end, 10)); if(end[0] != '\0' || outRate < MIN_RATE || outRate > MAX_RATE) { fprintf(stderr, "\nError: Got unexpected value \"%s\" for option -%c, expected between %u to %u.\n", optarg, opt, MIN_RATE, MAX_RATE); @@ -1697,7 +1696,7 @@ int main(int argc, char *argv[]) break; case 'f': - fftSize = strtoul(optarg, &end, 10); + fftSize = static_cast(strtoul(optarg, &end, 10)); if(end[0] != '\0' || (fftSize&(fftSize-1)) || fftSize < MIN_FFTSIZE || fftSize > MAX_FFTSIZE) { fprintf(stderr, "\nError: Got unexpected value \"%s\" for option -%c, expected a power-of-two between %u to %u.\n", optarg, opt, MIN_FFTSIZE, MAX_FFTSIZE); @@ -1744,7 +1743,7 @@ int main(int argc, char *argv[]) break; case 'w': - truncSize = strtoul(optarg, &end, 10); + truncSize = static_cast(strtoul(optarg, &end, 10)); if(end[0] != '\0' || truncSize < MIN_TRUNCSIZE || truncSize > MAX_TRUNCSIZE || (truncSize%MOD_TRUNCSIZE)) { fprintf(stderr, "\nError: Got unexpected value \"%s\" for option -%c, expected multiple of %u between %u to %u.\n", optarg, opt, MOD_TRUNCSIZE, MIN_TRUNCSIZE, MAX_TRUNCSIZE); diff --git a/utils/sofa-info.cpp b/utils/sofa-info.cpp index c7c7a8f7..83e3d065 100644 --- a/utils/sofa-info.cpp +++ b/utils/sofa-info.cpp @@ -84,7 +84,7 @@ static void PrintSofaArray(const char *prefix, struct MYSOFA_ARRAY *array) * of other axes as necessary. The epsilons are used to constrain the * equality of unique elements. */ -static uint GetUniquelySortedElems(const uint m, const float *triplets, const int axis, +static uint GetUniquelySortedElems(const uint m, const float *triplets, const uint axis, const float *const (&filters)[3], const float (&epsilons)[3], float *elems) { -- cgit v1.2.3 From 388928f3aa1ecf1a4f930c27687e7d0d4a9fd824 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 11 Sep 2019 05:53:10 -0700 Subject: Fix some more implicit casts --- al/auxeffectslot.cpp | 41 +-- alc/alc.cpp | 729 +++++++++++++++++++++++++-------------------------- alc/mastering.h | 2 +- common/albyte.h | 2 +- common/alspan.h | 5 +- 5 files changed, 389 insertions(+), 390 deletions(-) diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index 3eb8b80a..06627bc8 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -51,8 +51,8 @@ namespace { inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept { - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; + const size_t lidx{(id-1) >> 6}; + const ALuint slidx{(id-1) & 0x3f}; if UNLIKELY(lidx >= context->mEffectSlotList.size()) return nullptr; @@ -64,8 +64,8 @@ inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) noexcept { - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; + const size_t lidx{(id-1) >> 6}; + const ALuint slidx{(id-1) & 0x3f}; if UNLIKELY(lidx >= device->EffectList.size()) return nullptr; @@ -76,7 +76,7 @@ inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) noexcept } -void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) +void AddActiveEffectSlots(const ALuint *slotids, size_t count, ALCcontext *context) { if(count < 1) return; ALeffectslotArray *curarray{context->mActiveAuxSlots.load(std::memory_order_acquire)}; @@ -121,7 +121,7 @@ void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *cont delete curarray; } -void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) +void RemoveActiveEffectSlots(const ALuint *slotids, size_t count, ALCcontext *context) { if(count < 1) return; ALeffectslotArray *curarray{context->mActiveAuxSlots.load(std::memory_order_acquire)}; @@ -172,10 +172,10 @@ ALeffectslot *AllocEffectSlot(ALCcontext *context) [](const EffectSlotSubList &entry) noexcept -> bool { return entry.FreeMask != 0; } ); - auto lidx = static_cast(std::distance(context->mEffectSlotList.begin(), sublist)); - ALsizei slidx; + auto lidx = static_cast(std::distance(context->mEffectSlotList.begin(), sublist)); + ALuint slidx; if LIKELY(sublist != context->mEffectSlotList.end()) - slidx = CTZ64(sublist->FreeMask); + slidx = static_cast(CTZ64(sublist->FreeMask)); else { /* Don't allocate so many list entries that the 32-bit ID could @@ -222,9 +222,9 @@ ALeffectslot *AllocEffectSlot(ALCcontext *context) void FreeEffectSlot(ALCcontext *context, ALeffectslot *slot) { - ALuint id = slot->id - 1; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; + const ALuint id{slot->id - 1}; + const size_t lidx{id >> 6}; + const size_t slidx{id & 0x3f}; al::destroy_at(slot); @@ -270,7 +270,7 @@ START_API_FUNC } else { - auto tempids = al::vector(n); + auto tempids = al::vector(static_cast(n)); auto alloc_end = std::find_if_not(tempids.begin(), tempids.end(), [&context](ALuint &id) -> bool { @@ -291,7 +291,7 @@ START_API_FUNC } std::unique_lock slotlock{context->mEffectSlotLock}; - AddActiveEffectSlots(effectslots, n, context.get()); + AddActiveEffectSlots(effectslots, static_cast(n), context.get()); } END_API_FUNC @@ -328,7 +328,7 @@ START_API_FUNC return; // All effectslots are valid, remove and delete them - RemoveActiveEffectSlots(effectslots, n, context.get()); + RemoveActiveEffectSlots(effectslots, static_cast(n), context.get()); std::for_each(effectslots, effectslots_end, [&context](ALuint sid) -> void { @@ -375,7 +375,7 @@ START_API_FUNC device = context->mDevice.get(); { std::lock_guard ___{device->EffectLock}; - ALeffect *effect{value ? LookupEffect(device, value) : nullptr}; + ALeffect *effect{value ? LookupEffect(device, static_cast(value)) : nullptr}; if(!(value == 0 || effect != nullptr)) SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid effect ID %u", value); err = InitializeEffect(context.get(), slot, effect); @@ -391,11 +391,11 @@ START_API_FUNC if(!(value == AL_TRUE || value == AL_FALSE)) SETERR_RETURN(context, AL_INVALID_VALUE,, "Effect slot auxiliary send auto out of range"); - slot->AuxSendAuto = value; + slot->AuxSendAuto = static_cast(value); break; case AL_EFFECTSLOT_TARGET_SOFT: - target = (value ? LookupEffectSlot(context.get(), value) : nullptr); + target = LookupEffectSlot(context.get(), static_cast(value)); if(value && !target) SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid effect slot target ID"); if(target) @@ -536,7 +536,10 @@ START_API_FUNC break; case AL_EFFECTSLOT_TARGET_SOFT: - *value = slot->Target ? slot->Target->id : 0; + if(auto *target = slot->Target) + *value = static_cast(target->id); + else + *value = 0; break; default: diff --git a/alc/alc.cpp b/alc/alc.cpp index 81afaeb0..5f52ca26 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -1664,7 +1664,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) break; case ALC_FREQUENCY: - freq = attrList[attrIdx + 1]; + freq = static_cast(attrList[attrIdx + 1]); TRACE_ATTR(ALC_FREQUENCY, freq); break; @@ -1684,13 +1684,13 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) break; case ALC_MONO_SOURCES: - numMono = attrList[attrIdx + 1]; + numMono = static_cast(attrList[attrIdx + 1]); TRACE_ATTR(ALC_MONO_SOURCES, numMono); if(numMono > INT_MAX) numMono = 0; break; case ALC_STEREO_SOURCES: - numStereo = attrList[attrIdx + 1]; + numStereo = static_cast(attrList[attrIdx + 1]); TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); if(numStereo > INT_MAX) numStereo = 0; break; @@ -1780,7 +1780,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->Flags.unset(); else { - freq = maxi(freq, MIN_OUTPUT_RATE); + freq = maxu(freq, MIN_OUTPUT_RATE); device->UpdateSize = (device->UpdateSize*freq + device->Frequency/2) / device->Frequency; @@ -1886,8 +1886,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); if(!device->HrtfList.empty()) { - if(hrtf_id >= 0 && static_cast(hrtf_id) < device->HrtfList.size()) - hrtf = GetLoadedHrtf(device->HrtfList[hrtf_id].hrtf); + if(hrtf_id >= 0 && static_cast(hrtf_id) < device->HrtfList.size()) + hrtf = GetLoadedHrtf(device->HrtfList[static_cast(hrtf_id)].hrtf); else hrtf = GetLoadedHrtf(device->HrtfList.front().hrtf); } @@ -2146,24 +2146,18 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(old_sends != device->NumAuxSends) { - ALsizei s; - for(s = device->NumAuxSends;s < old_sends;s++) - { - if(source->Send[s].Slot) - DecrementRef(source->Send[s].Slot->ref); - source->Send[s].Slot = nullptr; - } - source->Send.resize(device->NumAuxSends); + if(source->Send.size() > static_cast(device->NumAuxSends)) + std::for_each(source->Send.begin()+device->NumAuxSends, source->Send.end(), + [](ALsource::SendData &send) -> void + { + if(send.Slot) + DecrementRef(send.Slot->ref); + send.Slot = nullptr; + }); + + source->Send.resize(static_cast(device->NumAuxSends), + ALsource::SendData{nullptr, 1.0f, 1.0f, LOWPASSFREQREF, 1.0f, HIGHPASSFREQREF}); source->Send.shrink_to_fit(); - for(s = old_sends;s < device->NumAuxSends;s++) - { - source->Send[s].Slot = nullptr; - source->Send[s].Gain = 1.0f; - source->Send[s].GainHF = 1.0f; - source->Send[s].HFReference = LOWPASSFREQREF; - source->Send[s].GainLF = 1.0f; - source->Send[s].LFReference = HIGHPASSFREQREF; - } } source->PropsClean.clear(std::memory_order_release); @@ -2264,21 +2258,21 @@ ALCdevice::~ALCdevice() size_t count{std::accumulate(BufferList.cbegin(), BufferList.cend(), size_t{0u}, [](size_t cur, const BufferSubList &sublist) noexcept -> size_t - { return cur + POPCNT64(~sublist.FreeMask); } + { return cur + static_cast(POPCNT64(~sublist.FreeMask)); } )}; if(count > 0) WARN("%zu Buffer%s not deleted\n", count, (count==1)?"":"s"); count = std::accumulate(EffectList.cbegin(), EffectList.cend(), size_t{0u}, [](size_t cur, const EffectSubList &sublist) noexcept -> size_t - { return cur + POPCNT64(~sublist.FreeMask); } + { return cur + static_cast(POPCNT64(~sublist.FreeMask)); } ); if(count > 0) WARN("%zu Effect%s not deleted\n", count, (count==1)?"":"s"); count = std::accumulate(FilterList.cbegin(), FilterList.cend(), size_t{0u}, [](size_t cur, const FilterSubList &sublist) noexcept -> size_t - { return cur + POPCNT64(~sublist.FreeMask); } + { return cur + static_cast(POPCNT64(~sublist.FreeMask)); } ); if(count > 0) WARN("%zu Filter%s not deleted\n", count, (count==1)?"":"s"); @@ -2334,7 +2328,7 @@ ALCcontext::~ALCcontext() count = std::accumulate(mSourceList.cbegin(), mSourceList.cend(), size_t{0u}, [](size_t cur, const SourceSubList &sublist) noexcept -> size_t - { return cur + POPCNT64(~sublist.FreeMask); } + { return cur + static_cast(POPCNT64(~sublist.FreeMask)); } ); if(count > 0) WARN("%zu Source%s not deleted\n", count, (count==1)?"":"s"); @@ -2358,7 +2352,7 @@ ALCcontext::~ALCcontext() count = std::accumulate(mEffectSlotList.cbegin(), mEffectSlotList.cend(), size_t{0u}, [](size_t cur, const EffectSlotSubList &sublist) noexcept -> size_t - { return cur + POPCNT64(~sublist.FreeMask); } + { return cur + static_cast(POPCNT64(~sublist.FreeMask)); } ); if(count > 0) WARN("%zu AuxiliaryEffectSlot%s not deleted\n", count, (count==1)?"":"s"); @@ -2476,7 +2470,7 @@ bool ALCcontext::deinit() bool ret{}; /* First make sure this context exists in the device's list. */ auto *oldarray = mDevice->mContexts.load(std::memory_order_acquire); - if(auto toremove = std::count(oldarray->begin(), oldarray->end(), this)) + if(auto toremove = static_cast(std::count(oldarray->begin(), oldarray->end(), this))) { using ContextArray = al::FlexArray; auto alloc_ctx_array = [](const size_t count) -> ContextArray* @@ -2719,9 +2713,9 @@ static inline ALCsizei NumAttrsForDevice(ALCdevice *device) return 29; } -static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, const al::span values) +static size_t GetIntegerv(ALCdevice *device, ALCenum param, const al::span values) { - ALCsizei i; + size_t i; if(values.empty()) { @@ -2733,33 +2727,33 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, const al::span(NumAttrsForDevice(device))) - alcSetError(device, ALC_INVALID_VALUE); - else - { - std::lock_guard _{device->StateLock}; - values[i++] = ALC_MAJOR_VERSION; - values[i++] = alcMajorVersion; - values[i++] = ALC_MINOR_VERSION; - values[i++] = alcMinorVersion; - values[i++] = ALC_CAPTURE_SAMPLES; - values[i++] = device->Backend->availableSamples(); - values[i++] = ALC_CONNECTED; - values[i++] = device->Connected.load(std::memory_order_relaxed); - values[i++] = 0; - } - return i; - - case ALC_MAJOR_VERSION: - values[0] = alcMajorVersion; - return 1; - case ALC_MINOR_VERSION: - values[0] = alcMinorVersion; - return 1; - - case ALC_CAPTURE_SAMPLES: - { std::lock_guard _{device->StateLock}; - values[0] = device->Backend->availableSamples(); - } - return 1; - - case ALC_CONNECTED: - { std::lock_guard _{device->StateLock}; - values[0] = device->Connected.load(std::memory_order_acquire); - } - return 1; - - default: - alcSetError(device, ALC_INVALID_ENUM); - return 0; - } - return 0; - } - - /* render device */ - switch(param) - { case ALC_ATTRIBUTES_SIZE: values[0] = NumAttrsForDevice(device); return 1; @@ -2835,63 +2777,10 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, const al::spanFrequency; - if(device->Type != Loopback) - { - values[i++] = ALC_REFRESH; - values[i++] = device->Frequency / device->UpdateSize; - - values[i++] = ALC_SYNC; - values[i++] = ALC_FALSE; - } - else - { - if(device->FmtChans == DevFmtAmbi3D) - { - values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; - values[i++] = static_cast(device->mAmbiLayout); - - values[i++] = ALC_AMBISONIC_SCALING_SOFT; - values[i++] = static_cast(device->mAmbiScale); - - values[i++] = ALC_AMBISONIC_ORDER_SOFT; - values[i++] = device->mAmbiOrder; - } - - values[i++] = ALC_FORMAT_CHANNELS_SOFT; - values[i++] = device->FmtChans; - - values[i++] = ALC_FORMAT_TYPE_SOFT; - values[i++] = device->FmtType; - } - - values[i++] = ALC_MONO_SOURCES; - values[i++] = device->NumMonoSources; - - values[i++] = ALC_STEREO_SOURCES; - values[i++] = device->NumStereoSources; - - values[i++] = ALC_MAX_AUXILIARY_SENDS; - values[i++] = device->NumAuxSends; - - values[i++] = ALC_HRTF_SOFT; - values[i++] = (device->mHrtf ? ALC_TRUE : ALC_FALSE); - - values[i++] = ALC_HRTF_STATUS_SOFT; - values[i++] = device->HrtfStatus; - - values[i++] = ALC_OUTPUT_LIMITER_SOFT; - values[i++] = device->Limiter ? ALC_TRUE : ALC_FALSE; - - values[i++] = ALC_MAX_AMBISONIC_ORDER_SOFT; - values[i++] = MAX_AMBI_ORDER; - + values[i++] = ALC_CAPTURE_SAMPLES; + values[i++] = static_cast(device->Backend->availableSamples()); + values[i++] = ALC_CONNECTED; + values[i++] = device->Connected.load(std::memory_order_relaxed); values[i++] = 0; } return i; @@ -2899,134 +2788,241 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, const al::spanFrequency; - return 1; - - case ALC_REFRESH: - if(device->Type == Loopback) + case ALC_CAPTURE_SAMPLES: { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; - } - { std::lock_guard _{device->StateLock}; - values[0] = device->Frequency / device->UpdateSize; + std::lock_guard _{device->StateLock}; + values[0] = static_cast(device->Backend->availableSamples()); } return 1; - case ALC_SYNC: - if(device->Type == Loopback) + case ALC_CONNECTED: { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; + std::lock_guard _{device->StateLock}; + values[0] = device->Connected.load(std::memory_order_acquire); } - values[0] = ALC_FALSE; return 1; - case ALC_FORMAT_CHANNELS_SOFT: - if(device->Type != Loopback) - { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; - } - values[0] = device->FmtChans; - return 1; + default: + alcSetError(device, ALC_INVALID_ENUM); + } + return 0; + } - case ALC_FORMAT_TYPE_SOFT: + /* render device */ + switch(param) + { + case ALC_ATTRIBUTES_SIZE: + values[0] = NumAttrsForDevice(device); + return 1; + + case ALC_ALL_ATTRIBUTES: + i = 0; + if(values.size() < static_cast(NumAttrsForDevice(device))) + alcSetError(device, ALC_INVALID_VALUE); + else + { + std::lock_guard _{device->StateLock}; + values[i++] = ALC_MAJOR_VERSION; + values[i++] = alcMajorVersion; + values[i++] = ALC_MINOR_VERSION; + values[i++] = alcMinorVersion; + values[i++] = ALC_EFX_MAJOR_VERSION; + values[i++] = alcEFXMajorVersion; + values[i++] = ALC_EFX_MINOR_VERSION; + values[i++] = alcEFXMinorVersion; + + values[i++] = ALC_FREQUENCY; + values[i++] = static_cast(device->Frequency); if(device->Type != Loopback) { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; - } - values[0] = device->FmtType; - return 1; + values[i++] = ALC_REFRESH; + values[i++] = static_cast(device->Frequency / device->UpdateSize); - case ALC_AMBISONIC_LAYOUT_SOFT: - if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) - { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; + values[i++] = ALC_SYNC; + values[i++] = ALC_FALSE; } - values[0] = static_cast(device->mAmbiLayout); - return 1; - - case ALC_AMBISONIC_SCALING_SOFT: - if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) + else { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; - } - values[0] = static_cast(device->mAmbiScale); - return 1; + if(device->FmtChans == DevFmtAmbi3D) + { + values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; + values[i++] = static_cast(device->mAmbiLayout); - case ALC_AMBISONIC_ORDER_SOFT: - if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) - { - alcSetError(device, ALC_INVALID_DEVICE); - return 0; + values[i++] = ALC_AMBISONIC_SCALING_SOFT; + values[i++] = static_cast(device->mAmbiScale); + + values[i++] = ALC_AMBISONIC_ORDER_SOFT; + values[i++] = device->mAmbiOrder; + } + + values[i++] = ALC_FORMAT_CHANNELS_SOFT; + values[i++] = device->FmtChans; + + values[i++] = ALC_FORMAT_TYPE_SOFT; + values[i++] = device->FmtType; } - values[0] = device->mAmbiOrder; - return 1; - case ALC_MONO_SOURCES: - values[0] = device->NumMonoSources; - return 1; + values[i++] = ALC_MONO_SOURCES; + values[i++] = static_cast(device->NumMonoSources); - case ALC_STEREO_SOURCES: - values[0] = device->NumStereoSources; - return 1; + values[i++] = ALC_STEREO_SOURCES; + values[i++] = static_cast(device->NumStereoSources); - case ALC_MAX_AUXILIARY_SENDS: - values[0] = device->NumAuxSends; - return 1; + values[i++] = ALC_MAX_AUXILIARY_SENDS; + values[i++] = device->NumAuxSends; - case ALC_CONNECTED: - { std::lock_guard _{device->StateLock}; - values[0] = device->Connected.load(std::memory_order_acquire); - } - return 1; + values[i++] = ALC_HRTF_SOFT; + values[i++] = (device->mHrtf ? ALC_TRUE : ALC_FALSE); - case ALC_HRTF_SOFT: - values[0] = (device->mHrtf ? ALC_TRUE : ALC_FALSE); - return 1; + values[i++] = ALC_HRTF_STATUS_SOFT; + values[i++] = device->HrtfStatus; - case ALC_HRTF_STATUS_SOFT: - values[0] = device->HrtfStatus; - return 1; + values[i++] = ALC_OUTPUT_LIMITER_SOFT; + values[i++] = device->Limiter ? ALC_TRUE : ALC_FALSE; - case ALC_NUM_HRTF_SPECIFIERS_SOFT: - { std::lock_guard _{device->StateLock}; - device->HrtfList.clear(); - device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); - values[0] = static_cast(minz(device->HrtfList.size(), - std::numeric_limits::max())); - } - return 1; + values[i++] = ALC_MAX_AMBISONIC_ORDER_SOFT; + values[i++] = MAX_AMBI_ORDER; - case ALC_OUTPUT_LIMITER_SOFT: - values[0] = device->Limiter ? ALC_TRUE : ALC_FALSE; - return 1; + values[i++] = 0; + } + return i; - case ALC_MAX_AMBISONIC_ORDER_SOFT: - values[0] = MAX_AMBI_ORDER; - return 1; + case ALC_MAJOR_VERSION: + values[0] = alcMajorVersion; + return 1; - default: - alcSetError(device, ALC_INVALID_ENUM); + case ALC_MINOR_VERSION: + values[0] = alcMinorVersion; + return 1; + + case ALC_EFX_MAJOR_VERSION: + values[0] = alcEFXMajorVersion; + return 1; + + case ALC_EFX_MINOR_VERSION: + values[0] = alcEFXMinorVersion; + return 1; + + case ALC_FREQUENCY: + values[0] = static_cast(device->Frequency); + return 1; + + case ALC_REFRESH: + if(device->Type == Loopback) + { + alcSetError(device, ALC_INVALID_DEVICE); return 0; + } + { + std::lock_guard _{device->StateLock}; + values[0] = static_cast(device->Frequency / device->UpdateSize); + } + return 1; + + case ALC_SYNC: + if(device->Type == Loopback) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = ALC_FALSE; + return 1; + + case ALC_FORMAT_CHANNELS_SOFT: + if(device->Type != Loopback) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = device->FmtChans; + return 1; + + case ALC_FORMAT_TYPE_SOFT: + if(device->Type != Loopback) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = device->FmtType; + return 1; + + case ALC_AMBISONIC_LAYOUT_SOFT: + if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = static_cast(device->mAmbiLayout); + return 1; + + case ALC_AMBISONIC_SCALING_SOFT: + if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = static_cast(device->mAmbiScale); + return 1; + + case ALC_AMBISONIC_ORDER_SOFT: + if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = device->mAmbiOrder; + return 1; + + case ALC_MONO_SOURCES: + values[0] = static_cast(device->NumMonoSources); + return 1; + + case ALC_STEREO_SOURCES: + values[0] = static_cast(device->NumStereoSources); + return 1; + + case ALC_MAX_AUXILIARY_SENDS: + values[0] = device->NumAuxSends; + return 1; + + case ALC_CONNECTED: + { + std::lock_guard _{device->StateLock}; + values[0] = device->Connected.load(std::memory_order_acquire); + } + return 1; + + case ALC_HRTF_SOFT: + values[0] = (device->mHrtf ? ALC_TRUE : ALC_FALSE); + return 1; + + case ALC_HRTF_STATUS_SOFT: + values[0] = device->HrtfStatus; + return 1; + + case ALC_NUM_HRTF_SPECIFIERS_SOFT: + { + std::lock_guard _{device->StateLock}; + device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); + values[0] = static_cast(minz(device->HrtfList.size(), + std::numeric_limits::max())); + } + return 1; + + case ALC_OUTPUT_LIMITER_SOFT: + values[0] = device->Limiter ? ALC_TRUE : ALC_FALSE; + return 1; + + case ALC_MAX_AMBISONIC_ORDER_SOFT: + values[0] = MAX_AMBI_ORDER; + return 1; + + default: + alcSetError(device, ALC_INVALID_ENUM); } return 0; } @@ -3054,127 +3050,126 @@ START_API_FUNC alcSetError(dev.get(), ALC_INVALID_VALUE); else if(!dev || dev->Type == Capture) { - auto ivals = al::vector(size); - size = GetIntegerv(dev.get(), pname, {ivals.data(), ivals.size()}); - std::copy(ivals.begin(), ivals.begin()+size, values); + auto ivals = al::vector(static_cast(size)); + size_t got{GetIntegerv(dev.get(), pname, {ivals.data(), ivals.size()})}; + std::copy_n(ivals.begin(), got, values); + return; } - else /* render device */ + /* render device */ + switch(pname) { - switch(pname) - { - case ALC_ATTRIBUTES_SIZE: - *values = NumAttrsForDevice(dev.get())+4; - break; - - case ALC_ALL_ATTRIBUTES: - if(size < NumAttrsForDevice(dev.get())+4) - alcSetError(dev.get(), ALC_INVALID_VALUE); - else - { - ALsizei i{0}; - std::lock_guard _{dev->StateLock}; - values[i++] = ALC_FREQUENCY; - values[i++] = dev->Frequency; + case ALC_ATTRIBUTES_SIZE: + *values = NumAttrsForDevice(dev.get())+4; + break; - if(dev->Type != Loopback) - { - values[i++] = ALC_REFRESH; - values[i++] = dev->Frequency / dev->UpdateSize; + case ALC_ALL_ATTRIBUTES: + if(size < NumAttrsForDevice(dev.get())+4) + alcSetError(dev.get(), ALC_INVALID_VALUE); + else + { + size_t i{0}; + std::lock_guard _{dev->StateLock}; + values[i++] = ALC_FREQUENCY; + values[i++] = dev->Frequency; - values[i++] = ALC_SYNC; - values[i++] = ALC_FALSE; - } - else - { - if(dev->FmtChans == DevFmtAmbi3D) - { - values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; - values[i++] = static_cast(dev->mAmbiLayout); + if(dev->Type != Loopback) + { + values[i++] = ALC_REFRESH; + values[i++] = dev->Frequency / dev->UpdateSize; - values[i++] = ALC_AMBISONIC_SCALING_SOFT; - values[i++] = static_cast(dev->mAmbiScale); + values[i++] = ALC_SYNC; + values[i++] = ALC_FALSE; + } + else + { + if(dev->FmtChans == DevFmtAmbi3D) + { + values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; + values[i++] = static_cast(dev->mAmbiLayout); - values[i++] = ALC_AMBISONIC_ORDER_SOFT; - values[i++] = dev->mAmbiOrder; - } + values[i++] = ALC_AMBISONIC_SCALING_SOFT; + values[i++] = static_cast(dev->mAmbiScale); - values[i++] = ALC_FORMAT_CHANNELS_SOFT; - values[i++] = dev->FmtChans; + values[i++] = ALC_AMBISONIC_ORDER_SOFT; + values[i++] = dev->mAmbiOrder; + } - values[i++] = ALC_FORMAT_TYPE_SOFT; - values[i++] = dev->FmtType; - } + values[i++] = ALC_FORMAT_CHANNELS_SOFT; + values[i++] = dev->FmtChans; - values[i++] = ALC_MONO_SOURCES; - values[i++] = dev->NumMonoSources; + values[i++] = ALC_FORMAT_TYPE_SOFT; + values[i++] = dev->FmtType; + } - values[i++] = ALC_STEREO_SOURCES; - values[i++] = dev->NumStereoSources; + values[i++] = ALC_MONO_SOURCES; + values[i++] = dev->NumMonoSources; - values[i++] = ALC_MAX_AUXILIARY_SENDS; - values[i++] = dev->NumAuxSends; + values[i++] = ALC_STEREO_SOURCES; + values[i++] = dev->NumStereoSources; - values[i++] = ALC_HRTF_SOFT; - values[i++] = (dev->mHrtf ? ALC_TRUE : ALC_FALSE); + values[i++] = ALC_MAX_AUXILIARY_SENDS; + values[i++] = dev->NumAuxSends; - values[i++] = ALC_HRTF_STATUS_SOFT; - values[i++] = dev->HrtfStatus; + values[i++] = ALC_HRTF_SOFT; + values[i++] = (dev->mHrtf ? ALC_TRUE : ALC_FALSE); - values[i++] = ALC_OUTPUT_LIMITER_SOFT; - values[i++] = dev->Limiter ? ALC_TRUE : ALC_FALSE; + values[i++] = ALC_HRTF_STATUS_SOFT; + values[i++] = dev->HrtfStatus; - ClockLatency clock{GetClockLatency(dev.get())}; - values[i++] = ALC_DEVICE_CLOCK_SOFT; - values[i++] = clock.ClockTime.count(); + values[i++] = ALC_OUTPUT_LIMITER_SOFT; + values[i++] = dev->Limiter ? ALC_TRUE : ALC_FALSE; - values[i++] = ALC_DEVICE_LATENCY_SOFT; - values[i++] = clock.Latency.count(); + ClockLatency clock{GetClockLatency(dev.get())}; + values[i++] = ALC_DEVICE_CLOCK_SOFT; + values[i++] = clock.ClockTime.count(); - values[i++] = 0; - } - break; + values[i++] = ALC_DEVICE_LATENCY_SOFT; + values[i++] = clock.Latency.count(); - case ALC_DEVICE_CLOCK_SOFT: - { std::lock_guard _{dev->StateLock}; - nanoseconds basecount; - ALuint samplecount; - ALuint refcount; - do { - while(((refcount=ReadRef(dev->MixCount))&1) != 0) - std::this_thread::yield(); - basecount = dev->ClockBase; - samplecount = dev->SamplesDone; - } while(refcount != ReadRef(dev->MixCount)); - basecount += nanoseconds{seconds{samplecount}} / dev->Frequency; - *values = basecount.count(); - } - break; + values[i++] = 0; + } + break; - case ALC_DEVICE_LATENCY_SOFT: - { std::lock_guard _{dev->StateLock}; - ClockLatency clock{GetClockLatency(dev.get())}; - *values = clock.Latency.count(); - } - break; + case ALC_DEVICE_CLOCK_SOFT: + { std::lock_guard _{dev->StateLock}; + nanoseconds basecount; + ALuint samplecount; + ALuint refcount; + do { + while(((refcount=ReadRef(dev->MixCount))&1) != 0) + std::this_thread::yield(); + basecount = dev->ClockBase; + samplecount = dev->SamplesDone; + } while(refcount != ReadRef(dev->MixCount)); + basecount += nanoseconds{seconds{samplecount}} / dev->Frequency; + *values = basecount.count(); + } + break; - case ALC_DEVICE_CLOCK_LATENCY_SOFT: - if(size < 2) - alcSetError(dev.get(), ALC_INVALID_VALUE); - else - { - std::lock_guard _{dev->StateLock}; - ClockLatency clock{GetClockLatency(dev.get())}; - values[0] = clock.ClockTime.count(); - values[1] = clock.Latency.count(); - } - break; + case ALC_DEVICE_LATENCY_SOFT: + { std::lock_guard _{dev->StateLock}; + ClockLatency clock{GetClockLatency(dev.get())}; + *values = clock.Latency.count(); + } + break; - default: - auto ivals = al::vector(size); - size = GetIntegerv(dev.get(), pname, {ivals.data(), ivals.size()}); - std::copy(ivals.begin(), ivals.begin()+size, values); - break; + case ALC_DEVICE_CLOCK_LATENCY_SOFT: + if(size < 2) + alcSetError(dev.get(), ALC_INVALID_VALUE); + else + { + std::lock_guard _{dev->StateLock}; + ClockLatency clock{GetClockLatency(dev.get())}; + values[0] = clock.ClockTime.count(); + values[1] = clock.Latency.count(); } + break; + + default: + auto ivals = al::vector(static_cast(size)); + size_t got{GetIntegerv(dev.get(), pname, {ivals.data(), ivals.size()})}; + std::copy_n(ivals.begin(), got, values); + break; } } END_API_FUNC @@ -3794,8 +3789,8 @@ START_API_FUNC device->FmtType = decompfmt->type; device->Flags.set(); - device->UpdateSize = samples; - device->BufferSize = samples; + device->UpdateSize = static_cast(samples); + device->BufferSize = static_cast(samples); try { device->Backend = CaptureFactory->createBackend(device.get(), BackendType::Capture); @@ -3912,7 +3907,7 @@ START_API_FUNC { std::lock_guard _{dev->StateLock}; BackendBase *backend{dev->Backend.get()}; if(samples >= 0 && backend->availableSamples() >= static_cast(samples)) - err = backend->captureSamples(buffer, samples); + err = backend->captureSamples(buffer, static_cast(samples)); } if(err != ALC_NO_ERROR) alcSetError(dev.get(), err); @@ -4033,7 +4028,7 @@ START_API_FUNC else { BackendLockGuard _{*dev->Backend}; - aluMixData(dev.get(), buffer, samples); + aluMixData(dev.get(), buffer, static_cast(samples)); } } END_API_FUNC @@ -4114,7 +4109,7 @@ START_API_FUNC { case ALC_HRTF_SPECIFIER_SOFT: if(index >= 0 && static_cast(index) < dev->HrtfList.size()) - return dev->HrtfList[index].name.c_str(); + return dev->HrtfList[static_cast(index)].name.c_str(); alcSetError(dev.get(), ALC_INVALID_VALUE); break; diff --git a/alc/mastering.h b/alc/mastering.h index 03cd21c0..6c8fc628 100644 --- a/alc/mastering.h +++ b/alc/mastering.h @@ -65,7 +65,7 @@ struct Compressor { ~Compressor(); void process(const ALuint SamplesToDo, FloatBufferLine *OutBuffer); - ALsizei getLookAhead() const noexcept { return mLookAhead; } + ALsizei getLookAhead() const noexcept { return static_cast(mLookAhead); } DEF_PLACE_NEWDEL() }; diff --git a/common/albyte.h b/common/albyte.h index c7f4d219..798d136d 100644 --- a/common/albyte.h +++ b/common/albyte.h @@ -38,7 +38,7 @@ inline al::byte& operator>>=(al::byte &lhs, T rhs) noexcept #define AL_DECL_OP(op) \ template::value)> \ inline constexpr al::byte operator op (al::byte lhs, T rhs) noexcept \ -{ return al::byte(to_integer(lhs) op rhs); } \ +{ return al::byte(to_integer(lhs) op static_cast(rhs)); } \ template::value)> \ inline al::byte& operator op##= (al::byte &lhs, T rhs) noexcept \ { lhs = lhs op rhs; return lhs; } \ diff --git a/common/alspan.h b/common/alspan.h index 63b36eaa..4fe0f111 100644 --- a/common/alspan.h +++ b/common/alspan.h @@ -221,8 +221,9 @@ public: constexpr reference operator[](index_type idx) const { return mData[idx]; } constexpr pointer data() const noexcept { return mData; } - constexpr index_type size() const noexcept { return mDataEnd-mData; } - constexpr index_type size_bytes() const noexcept { return (mDataEnd-mData) * sizeof(value_type); } + constexpr index_type size() const noexcept { return static_cast(mDataEnd-mData); } + constexpr index_type size_bytes() const noexcept + { return static_cast(mDataEnd-mData) * sizeof(value_type); } constexpr bool empty() const noexcept { return mData == mDataEnd; } constexpr iterator begin() const noexcept { return mData; } -- cgit v1.2.3 From be0442c6207cc10fca079a803bbdd8985959b657 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 11 Sep 2019 06:47:56 -0700 Subject: Avoid C-style casts in C++ --- CMakeLists.txt | 2 +- al/state.cpp | 16 ++++++++-------- alc/alc.cpp | 18 ++++++++---------- alc/backends/sdl2.cpp | 2 +- alc/backends/sndio.cpp | 2 +- alc/backends/wasapi.cpp | 9 ++++++--- alc/backends/winmm.cpp | 8 +++++--- alc/helpers.cpp | 2 +- utils/makemhr/loaddef.cpp | 12 ++++++------ utils/makemhr/loadsofa.cpp | 2 +- utils/sofa-info.cpp | 2 +- 11 files changed, 39 insertions(+), 36 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7626c1ef..c37a2d18 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -220,7 +220,7 @@ IF(MSVC) ENDFOREACH(flag_var) ENDIF() ELSE() - SET(C_FLAGS ${C_FLAGS} -Winline -Wall) + SET(C_FLAGS ${C_FLAGS} -Winline -Wall -Wold-style-cast) CHECK_C_COMPILER_FLAG(-Wextra HAVE_W_EXTRA) IF(HAVE_W_EXTRA) SET(C_FLAGS ${C_FLAGS} -Wextra) diff --git a/al/state.cpp b/al/state.cpp index 64cbae6e..cc5d8bac 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -371,36 +371,36 @@ START_API_FUNC switch(pname) { case AL_DOPPLER_FACTOR: - value = (ALint64SOFT)context->mDopplerFactor; + value = static_cast(context->mDopplerFactor); break; case AL_DOPPLER_VELOCITY: - value = (ALint64SOFT)context->mDopplerVelocity; + value = static_cast(context->mDopplerVelocity); break; case AL_DISTANCE_MODEL: - value = (ALint64SOFT)context->mDistanceModel; + value = static_cast(context->mDistanceModel); break; case AL_SPEED_OF_SOUND: - value = (ALint64SOFT)context->mSpeedOfSound; + value = static_cast(context->mSpeedOfSound); break; case AL_DEFERRED_UPDATES_SOFT: if(context->mDeferUpdates.load(std::memory_order_acquire)) - value = (ALint64SOFT)AL_TRUE; + value = AL_TRUE; break; case AL_GAIN_LIMIT_SOFT: - value = (ALint64SOFT)(GAIN_MIX_MAX/context->mGainBoost); + value = static_cast(GAIN_MIX_MAX/context->mGainBoost); break; case AL_NUM_RESAMPLERS_SOFT: - value = (ALint64SOFT)(ResamplerMax + 1); + value = static_cast(ResamplerMax + 1); break; case AL_DEFAULT_RESAMPLER_SOFT: - value = (ALint64SOFT)ResamplerDefault; + value = static_cast(ResamplerDefault); break; default: diff --git a/alc/alc.cpp b/alc/alc.cpp index 5f52ca26..10ab3b94 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -214,7 +215,7 @@ BackendFactory *CaptureFactory{}; /************************************************ * Functions, enums, and errors ************************************************/ -#define DECL(x) { #x, (ALCvoid*)(x) } +#define DECL(x) { #x, reinterpret_cast(x) } const struct { const ALCchar *funcName; ALCvoid *address; @@ -1228,14 +1229,11 @@ BOOL APIENTRY DllMain(HINSTANCE module, DWORD reason, LPVOID /*reserved*/) { 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*)module, &module); - break; - - case DLL_PROCESS_DETACH: - break; + 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, + reinterpret_cast(module), &module); + break; } return TRUE; } @@ -2087,7 +2085,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) TRACE("Output limiter enabled, %.4fdB limit\n", thrshld_dB); } - TRACE("Fixed device latency: %ldns\n", (long)device->FixedLatency.count()); + TRACE("Fixed device latency: %" PRId64 "ns\n", int64_t{device->FixedLatency.count()}); /* Need to delay returning failure until replacement Send arrays have been * allocated with the appropriate size. diff --git a/alc/backends/sdl2.cpp b/alc/backends/sdl2.cpp index 29d27c05..4b3b5e63 100644 --- a/alc/backends/sdl2.cpp +++ b/alc/backends/sdl2.cpp @@ -133,7 +133,7 @@ ALCenum Sdl2Backend::open(const ALCchar *name) mDevice->FmtChans = DevFmtStereo; else { - ERR("Got unhandled SDL channel count: %d\n", (int)have.channels); + ERR("Got unhandled SDL channel count: %d\n", int{have.channels}); return ALC_INVALID_VALUE; } switch(have.format) diff --git a/alc/backends/sndio.cpp b/alc/backends/sndio.cpp index 587f67bb..c7a86670 100644 --- a/alc/backends/sndio.cpp +++ b/alc/backends/sndio.cpp @@ -396,7 +396,7 @@ ALCenum SndioCapture::open(const ALCchar *name) (mDevice->FmtType == DevFmtUShort && par.bits == 16 && par.sig == 0) || (mDevice->FmtType == DevFmtInt && par.bits == 32 && par.sig != 0) || (mDevice->FmtType == DevFmtUInt && par.bits == 32 && par.sig == 0)) || - mDevice->channelsFromFmt() != (ALsizei)par.rchan || + mDevice->channelsFromFmt() != static_cast(par.rchan) || mDevice->Frequency != par.rate) { ERR("Failed to set format %s %s %uhz, got %c%u %u-channel %uhz instead\n", diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index ec1ee936..55c95146 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -81,6 +81,9 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x namespace { +inline constexpr REFERENCE_TIME operator "" _reftime(unsigned long long int n) noexcept +{ return static_cast(n); } + #define MONO SPEAKER_FRONT_CENTER #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT) #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT) @@ -90,7 +93,7 @@ namespace { #define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) #define X7DOT1_WIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_FRONT_LEFT_OF_CENTER|SPEAKER_FRONT_RIGHT_OF_CENTER) -#define REFTIME_PER_SEC ((REFERENCE_TIME)10000000) +#define REFTIME_PER_SEC 10000000_reftime #define DEVNAME_HEAD "OpenAL Soft on " @@ -1051,7 +1054,7 @@ HRESULT WasapiPlayback::resetProxy() /* Find the nearest multiple of the period size to the update size */ if(min_per < per_time) min_per *= maxi64((per_time + min_per/2) / min_per, 1); - min_len = (UINT32)ScaleCeil(min_per, mDevice->Frequency, REFTIME_PER_SEC); + min_len = static_cast(ScaleCeil(min_per, mDevice->Frequency, REFTIME_PER_SEC)); min_len = minu(min_len, buffer_len/2); mDevice->UpdateSize = min_len; @@ -1680,7 +1683,7 @@ void WasapiCapture::stopProxy() ALCuint WasapiCapture::availableSamples() -{ return (ALCuint)mRing->readSpace(); } +{ return static_cast(mRing->readSpace()); } ALCenum WasapiCapture::captureSamples(void *buffer, ALCuint samples) { diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp index b6787a24..76e6fe3b 100644 --- a/alc/backends/winmm.cpp +++ b/alc/backends/winmm.cpp @@ -245,7 +245,8 @@ retry_open: mFormat.nAvgBytesPerSec = mFormat.nSamplesPerSec * mFormat.nBlockAlign; mFormat.cbSize = 0; - MMRESULT res{waveOutOpen(&mOutHdl, DeviceID, &mFormat, (DWORD_PTR)&WinMMPlayback::waveOutProcC, + MMRESULT res{waveOutOpen(&mOutHdl, DeviceID, &mFormat, + reinterpret_cast(&WinMMPlayback::waveOutProcC), reinterpret_cast(this), CALLBACK_FUNCTION)}; if(res != MMSYSERR_NOERROR) { @@ -506,7 +507,8 @@ ALCenum WinMMCapture::open(const ALCchar *name) mFormat.nAvgBytesPerSec = mFormat.nSamplesPerSec * mFormat.nBlockAlign; mFormat.cbSize = 0; - MMRESULT res{waveInOpen(&mInHdl, DeviceID, &mFormat, (DWORD_PTR)&WinMMCapture::waveInProcC, + MMRESULT res{waveInOpen(&mInHdl, DeviceID, &mFormat, + reinterpret_cast(&WinMMCapture::waveInProcC), reinterpret_cast(this), CALLBACK_FUNCTION)}; if(res != MMSYSERR_NOERROR) { @@ -590,7 +592,7 @@ ALCenum WinMMCapture::captureSamples(void *buffer, ALCuint samples) } ALCuint WinMMCapture::availableSamples() -{ return (ALCuint)mRing->readSpace(); } +{ return static_cast(mRing->readSpace()); } } // namespace diff --git a/alc/helpers.cpp b/alc/helpers.cpp index ba95c0f8..84787637 100644 --- a/alc/helpers.cpp +++ b/alc/helpers.cpp @@ -255,7 +255,7 @@ auto filebuf::underflow() -> int_type { // Read in the next chunk of data, and set the pointers on success DWORD got{}; - if(ReadFile(mFile, mBuffer.data(), (DWORD)mBuffer.size(), &got, nullptr)) + if(ReadFile(mFile, mBuffer.data(), static_cast(mBuffer.size()), &got, nullptr)) setg(mBuffer.data(), mBuffer.data(), mBuffer.data()+got); } if(gptr() == egptr()) diff --git a/utils/makemhr/loaddef.cpp b/utils/makemhr/loaddef.cpp index 89893e38..5f6d76d8 100644 --- a/utils/makemhr/loaddef.cpp +++ b/utils/makemhr/loaddef.cpp @@ -1047,7 +1047,7 @@ static int LoadWaveSource(FILE *fp, SourceRefT *src, const uint hrirRate, const // Load a Spatially Oriented Format for Accoustics (SOFA) file. static MYSOFA_EASY* LoadSofaFile(SourceRefT *src, const uint hrirRate, const uint n) { - struct MYSOFA_EASY *sofa{mysofa_cache_lookup(src->mPath, (float)hrirRate)}; + struct MYSOFA_EASY *sofa{mysofa_cache_lookup(src->mPath, static_cast(hrirRate))}; if(sofa) return sofa; sofa = static_cast(calloc(1, sizeof(*sofa))); @@ -1096,7 +1096,7 @@ static MYSOFA_EASY* LoadSofaFile(SourceRefT *src, const uint hrirRate, const uin fprintf(stderr, "\nError: Out of memory.\n"); return nullptr; } - return mysofa_cache_store(sofa, src->mPath, (float)hrirRate); + return mysofa_cache_store(sofa, src->mPath, static_cast(hrirRate)); } // Copies the HRIR data from a particular SOFA measurement. @@ -1532,7 +1532,7 @@ static int ReadSourceRef(TokenReaderT *tr, SourceRefT *src) src->mType = ET_NONE; src->mSize = 0; src->mBits = 0; - src->mChannel = (uint)intVal; + src->mChannel = static_cast(intVal); src->mSkip = 0; } else if(src->mFormat == SF_WAVE) @@ -1666,7 +1666,7 @@ static int ReadSofaRef(TokenReaderT *tr, SourceRefT *src) TrReadOperator(tr, "@"); if(!TrReadInt(tr, 0, 0x7FFFFFFF, &intVal)) return 0; - src->mOffset = (uint)intVal; + src->mOffset = static_cast(intVal); } else src->mOffset = 0; @@ -1834,13 +1834,13 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData) continue; double ef{(90.0 + aer[1]) * (hData->mFds[fi].mEvCount - 1) / 180.0}; - ei = (uint)std::round(ef); + ei = static_cast(std::round(ef)); ef = (ef - ei) * 180.0f / (hData->mFds[fi].mEvCount - 1); if(std::abs(ef) >= 0.1) continue; double af{aer[0] * hData->mFds[fi].mEvs[ei].mAzCount / 360.0f}; - ai = (uint)std::round(af); + ai = static_cast(std::round(af)); af = (af - ai) * 360.0f / hData->mFds[fi].mEvs[ei].mAzCount; ai = ai % hData->mFds[fi].mEvs[ei].mAzCount; if(std::abs(af) >= 0.1) diff --git a/utils/makemhr/loadsofa.cpp b/utils/makemhr/loadsofa.cpp index 7fb169e2..e82376aa 100644 --- a/utils/makemhr/loadsofa.cpp +++ b/utils/makemhr/loadsofa.cpp @@ -221,7 +221,7 @@ static bool PrepareLayout(const uint m, const float *xyzs, HrirDataT *hData) float ev{90.0f + elems[ei]}; float eif{std::round(ev / step)}; - if(std::fabs(eif - (uint)eif) < (0.1f / step)) + if(std::fabs(eif - static_cast(eif)) < (0.1f / step)) { evStart = static_cast(eif); break; diff --git a/utils/sofa-info.cpp b/utils/sofa-info.cpp index 83e3d065..e9f2257c 100644 --- a/utils/sofa-info.cpp +++ b/utils/sofa-info.cpp @@ -242,7 +242,7 @@ static void PrintCompatibleLayout(const uint m, const float *xyzs) float ev{90.0f + elems[ei]}; float eif{std::round(ev / step)}; - if(std::fabs(eif - (uint)eif) < (0.1f / step)) + if(std::fabs(eif - static_cast(eif)) < (0.1f / step)) { evStart = static_cast(eif); break; -- cgit v1.2.3 From a895709b6f67586d4aec3c6f0b276b01899cae86 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 11 Sep 2019 06:58:27 -0700 Subject: Fix function declaration --- alc/backends/wasapi.cpp | 5 +++-- alc/converter.cpp | 2 +- alc/converter.h | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 55c95146..806db122 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -1565,8 +1565,9 @@ HRESULT WasapiCapture::resetProxy() if(mDevice->Frequency != OutputType.Format.nSamplesPerSec || mDevice->FmtType != srcType) { - mSampleConv = CreateSampleConverter(srcType, mDevice->FmtType, mDevice->channelsFromFmt(), - OutputType.Format.nSamplesPerSec, mDevice->Frequency, BSinc24Resampler); + mSampleConv = CreateSampleConverter(srcType, mDevice->FmtType, + static_cast(mDevice->channelsFromFmt()), OutputType.Format.nSamplesPerSec, + mDevice->Frequency, BSinc24Resampler); if(!mSampleConv) { ERR("Failed to create converter for %s format, dst: %s %uhz, src: %s %luhz\n", diff --git a/alc/converter.cpp b/alc/converter.cpp index 58b59179..faf24948 100644 --- a/alc/converter.cpp +++ b/alc/converter.cpp @@ -144,7 +144,7 @@ void Stereo2Mono(ALfloat *RESTRICT dst, const void *src, const size_t frames) no } // namespace SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, size_t numchans, - ALsizei srcRate, ALsizei dstRate, Resampler resampler) + ALuint srcRate, ALuint dstRate, Resampler resampler) { if(numchans < 1 || srcRate < 1 || dstRate < 1) return nullptr; diff --git a/alc/converter.h b/alc/converter.h index 46e57f10..8a7b6f5f 100644 --- a/alc/converter.h +++ b/alc/converter.h @@ -43,8 +43,8 @@ struct SampleConverter { }; using SampleConverterPtr = std::unique_ptr; -SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, ALsizei numchans, - ALsizei srcRate, ALsizei dstRate, Resampler resampler); +SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, size_t numchans, + ALuint srcRate, ALuint dstRate, Resampler resampler); struct ChannelConverter { -- cgit v1.2.3 From 14c76ca2447a9c905ffad6898795b2024b1a85f6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 11 Sep 2019 07:32:14 -0700 Subject: Fix allocator comparison operators --- common/almalloc.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/almalloc.h b/common/almalloc.h index 232294cc..37b57d2b 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -72,10 +72,10 @@ struct allocator { } void deallocate(T *p, std::size_t) noexcept { al_free(p); } }; -template -bool operator==(const allocator&, const allocator&) noexcept { return true; } -template -bool operator!=(const allocator&, const allocator&) noexcept { return false; } +template +bool operator==(const allocator&, const allocator&) noexcept { return true; } +template +bool operator!=(const allocator&, const allocator&) noexcept { return false; } template inline T* assume_aligned(T *ptr) noexcept -- cgit v1.2.3 From 1a9f1e0869f7327216d57e2a44b6ba9752986152 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 11 Sep 2019 08:08:23 -0700 Subject: Fix a few more C-style casts --- alc/backends/coreaudio.cpp | 2 +- alc/backends/opensl.cpp | 5 +++-- alc/mixer/mixer_neon.cpp | 6 +++--- common/almalloc.cpp | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index c903ff07..39f6241a 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -585,7 +585,7 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) // The output format should be the requested format, but using the hardware sample rate // This is because the AudioUnit will automatically scale other properties, except for sample rate err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, - 1, (void*)&outputFormat, sizeof(outputFormat)); + 1, &outputFormat, sizeof(outputFormat)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index 28305288..3ec2177f 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -849,7 +849,7 @@ void OpenSLCapture::stop() } } -ALCenum OpenSLCapture::captureSamples(void* buffer, ALCuint samples) +ALCenum OpenSLCapture::captureSamples(void *buffer, ALCuint samples) { ALsizei chunk_size = mDevice->UpdateSize * mFrameSize; SLAndroidSimpleBufferQueueItf bufferQueue; @@ -866,7 +866,8 @@ ALCenum OpenSLCapture::captureSamples(void* buffer, ALCuint samples) for(i = 0;i < samples;) { ALCuint rem{minu(samples - i, mDevice->UpdateSize - mSplOffset)}; - memcpy((ALCbyte*)buffer + i*mFrameSize, data.first.buf + mSplOffset*mFrameSize, + memcpy(static_cast(buffer) + i*mFrameSize, + data.first.buf + mSplOffset*mFrameSize, rem * mFrameSize); mSplOffset += rem; diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index b8a15c62..d5b1658f 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -140,12 +140,12 @@ static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const for(ALsizei c{0};c < IrSize;c += 2) { - float32x4_t vals = vld1q_f32((float32_t*)&Values[c][0]); - float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]); + float32x4_t vals = vld1q_f32(&Values[c][0]); + float32x4_t coefs = vld1q_f32(&Coeffs[c][0]); vals = vmlaq_f32(vals, coefs, leftright4); - vst1q_f32((float32_t*)&Values[c][0], vals); + vst1q_f32(&Values[c][0], vals); } } diff --git a/common/almalloc.cpp b/common/almalloc.cpp index 8ab48248..8700bddc 100644 --- a/common/almalloc.cpp +++ b/common/almalloc.cpp @@ -34,7 +34,7 @@ void *al_malloc(size_t alignment, size_t size) if(ret != nullptr) { *(ret++) = 0x00; - while(((ptrdiff_t)ret&(alignment-1)) != 0) + while((reinterpret_cast(ret)&(alignment-1)) != 0) *(ret++) = 0x55; } return ret; -- cgit v1.2.3 From 681c78d3485357ff9fae6b98ad2c20c83c767aba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 11 Sep 2019 12:28:33 -0700 Subject: Allocate buffer batches separately from buffers --- al/buffer.cpp | 82 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/al/buffer.cpp b/al/buffer.cpp index 03b68038..3cf9a60f 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include "AL/al.h" @@ -244,42 +245,41 @@ constexpr ALbitfieldSOFT INVALID_MAP_FLAGS{~unsigned(AL_MAP_READ_BIT_SOFT | AL_M AL_MAP_PERSISTENT_BIT_SOFT)}; -ALbuffer *AllocBuffer(ALCcontext *context) +bool EnsureBuffers(ALCdevice *device, size_t needed) { - ALCdevice *device{context->mDevice.get()}; - std::lock_guard _{device->BufferLock}; - auto sublist = std::find_if(device->BufferList.begin(), device->BufferList.end(), - [](const BufferSubList &entry) noexcept -> bool - { return entry.FreeMask != 0; } - ); + size_t count{std::accumulate(device->BufferList.cbegin(), device->BufferList.cend(), size_t{0}, + [](size_t cur, const BufferSubList &sublist) noexcept -> size_t + { return cur + static_cast(POPCNT64(~sublist.FreeMask)); } + )}; - auto lidx = static_cast(std::distance(device->BufferList.begin(), sublist)); - ALsizei slidx{0}; - if LIKELY(sublist != device->BufferList.end()) - slidx = CTZ64(sublist->FreeMask); - else + while(needed > count) { - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ if UNLIKELY(device->BufferList.size() >= 1<<25) - { - context->setError(AL_OUT_OF_MEMORY, "Too many buffers allocated"); - return nullptr; - } + return false; + device->BufferList.emplace_back(); - sublist = device->BufferList.end() - 1; + auto sublist = device->BufferList.end() - 1; sublist->FreeMask = ~0_u64; - sublist->Buffers = reinterpret_cast(al_calloc(16, sizeof(ALbuffer)*64)); + sublist->Buffers = static_cast(al_calloc(alignof(ALbuffer), sizeof(ALbuffer)*64)); if UNLIKELY(!sublist->Buffers) { device->BufferList.pop_back(); - context->setError(AL_OUT_OF_MEMORY, "Failed to allocate buffer batch"); - return nullptr; + return false; } - - slidx = 0; + count += 64; } + return true; +} + +ALbuffer *AllocBuffer(ALCdevice *device) +{ + auto sublist = std::find_if(device->BufferList.begin(), device->BufferList.end(), + [](const BufferSubList &entry) noexcept -> bool + { return entry.FreeMask != 0; } + ); + + auto lidx = static_cast(std::distance(device->BufferList.begin(), sublist)); + auto slidx = static_cast(CTZ64(sublist->FreeMask)); ALbuffer *buffer{::new (sublist->Buffers + slidx) ALbuffer{}}; @@ -293,9 +293,9 @@ ALbuffer *AllocBuffer(ALCcontext *context) void FreeBuffer(ALCdevice *device, ALbuffer *buffer) { - ALuint id{buffer->id - 1}; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; + const ALuint id{buffer->id - 1}; + const size_t lidx{id >> 6}; + const ALuint slidx{id & 0x3f}; al::destroy_at(buffer); @@ -304,8 +304,8 @@ void FreeBuffer(ALCdevice *device, ALbuffer *buffer) inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) { - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; + const size_t lidx{(id-1) >> 6}; + const ALuint slidx{(id-1) & 0x3f}; if UNLIKELY(lidx >= device->BufferList.size()) return nullptr; @@ -606,11 +606,19 @@ START_API_FUNC context->setError(AL_INVALID_VALUE, "Generating %d buffers", n); if UNLIKELY(n <= 0) return; + ALCdevice *device{context->mDevice.get()}; + std::unique_lock buflock{device->BufferLock}; + if(!EnsureBuffers(device, static_cast(n))) + { + context->setError(AL_OUT_OF_MEMORY, "Failed to allocate %d buffer%s", n, (n==1)?"":"s"); + return; + } + if LIKELY(n == 1) { /* Special handling for the easy and normal case. */ - ALbuffer *buffer = AllocBuffer(context.get()); - if(buffer) buffers[0] = buffer->id; + ALbuffer *buffer{AllocBuffer(device)}; + buffers[0] = buffer->id; } else { @@ -618,15 +626,9 @@ START_API_FUNC * modifying the user storage in case of failure. */ al::vector ids; - ids.reserve(n); + ids.reserve(static_cast(n)); do { - ALbuffer *buffer = AllocBuffer(context.get()); - if(!buffer) - { - alDeleteBuffers(static_cast(ids.size()), ids.data()); - return; - } - + ALbuffer *buffer{AllocBuffer(device)}; ids.emplace_back(buffer->id); } while(--n); std::copy(ids.begin(), ids.end(), buffers); -- cgit v1.2.3 From 07e2aa3bc0c7dde66b332e400f71bfd0d9cb1c5f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 11 Sep 2019 14:33:26 -0700 Subject: Clean up some more implicit conversions --- al/buffer.cpp | 248 ++++++++++++++++++++++++++++--------------------------- al/buffer.h | 19 ++--- al/event.cpp | 4 +- al/event.h | 2 +- al/source.cpp | 113 ++++++++++++------------- alc/mixvoice.cpp | 28 +++---- 6 files changed, 204 insertions(+), 210 deletions(-) diff --git a/al/buffer.cpp b/al/buffer.cpp index 3cf9a60f..1b4f6846 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -99,13 +99,13 @@ constexpr int MSADPCMAdaptionCoeff[7][2] = { }; -void DecodeIMA4Block(ALshort *dst, const al::byte *src, ALint numchans, ALsizei align) +void DecodeIMA4Block(ALshort *dst, const al::byte *src, size_t numchans, size_t align) { ALint sample[MAX_INPUT_CHANNELS]{}; ALint index[MAX_INPUT_CHANNELS]{}; ALuint code[MAX_INPUT_CHANNELS]{}; - for(int c{0};c < numchans;c++) + for(size_t c{0};c < numchans;c++) { sample[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); sample[c] = (sample[c]^0x8000) - 32768; @@ -114,14 +114,14 @@ void DecodeIMA4Block(ALshort *dst, const al::byte *src, ALint numchans, ALsizei index[c] = clampi((index[c]^0x8000) - 32768, 0, 88); src += 2; - *(dst++) = sample[c]; + *(dst++) = static_cast(sample[c]); } - for(int i{1};i < align;i++) + for(size_t i{1};i < align;i++) { if((i&7) == 1) { - for(int c{0};c < numchans;c++) + for(size_t c{0};c < numchans;c++) { code[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<< 8) | (al::to_integer(src[2])<<16) | (al::to_integer(src[3])<<24); @@ -129,7 +129,7 @@ void DecodeIMA4Block(ALshort *dst, const al::byte *src, ALint numchans, ALsizei } } - for(int c{0};c < numchans;c++) + for(size_t c{0};c < numchans;c++) { const ALuint nibble{code[c]&0xf}; code[c] >>= 4; @@ -140,51 +140,53 @@ void DecodeIMA4Block(ALshort *dst, const al::byte *src, ALint numchans, ALsizei index[c] += IMA4Index_adjust[nibble]; index[c] = clampi(index[c], 0, 88); - *(dst++) = sample[c]; + *(dst++) = static_cast(sample[c]); } } } -void DecodeMSADPCMBlock(ALshort *dst, const al::byte *src, ALint numchans, ALsizei align) +void DecodeMSADPCMBlock(ALshort *dst, const al::byte *src, size_t numchans, size_t align) { ALubyte blockpred[MAX_INPUT_CHANNELS]{}; ALint delta[MAX_INPUT_CHANNELS]{}; ALshort samples[MAX_INPUT_CHANNELS][2]{}; - for(int c{0};c < numchans;c++) + for(size_t c{0};c < numchans;c++) { - blockpred[c] = minu(al::to_integer(src[0]), 6); + blockpred[c] = std::min(al::to_integer(src[0]), 6); ++src; } - for(int c{0};c < numchans;c++) + for(size_t c{0};c < numchans;c++) { delta[c] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); delta[c] = (delta[c]^0x8000) - 32768; src += 2; } - for(int c{0};c < numchans;c++) + for(size_t c{0};c < numchans;c++) { - samples[c][0] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + samples[c][0] = static_cast(al::to_integer(src[0]) | + (al::to_integer(src[1])<<8)); samples[c][0] = (samples[c][0]^0x8000) - 32768; src += 2; } - for(int c{0};c < numchans;c++) + for(size_t c{0};c < numchans;c++) { - samples[c][1] = al::to_integer(src[0]) | (al::to_integer(src[1])<<8); + samples[c][1] = static_cast(al::to_integer(src[0]) | + (al::to_integer(src[1])<<8)); samples[c][1] = (samples[c][1]^0x8000) - 32768; src += 2; } /* Second sample is written first. */ - for(int c{0};c < numchans;c++) + for(size_t c{0};c < numchans;c++) *(dst++) = samples[c][1]; - for(int c{0};c < numchans;c++) + for(size_t c{0};c < numchans;c++) *(dst++) = samples[c][0]; int num{0}; - for(int i{2};i < align;i++) + for(size_t i{2};i < align;i++) { - for(int c{0};c < numchans;c++) + for(size_t c{0};c < numchans;c++) { /* Read the nibble (first is in the upper bits). */ al::byte nibble; @@ -199,20 +201,20 @@ void DecodeMSADPCMBlock(ALshort *dst, const al::byte *src, ALint numchans, ALsiz pred = clampi(pred, -32768, 32767); samples[c][1] = samples[c][0]; - samples[c][0] = pred; + samples[c][0] = static_cast(pred); delta[c] = (MSADPCMAdaption[al::to_integer(nibble)] * delta[c]) / 256; delta[c] = maxi(16, delta[c]); - *(dst++) = pred; + *(dst++) = static_cast(pred); } } } -void Convert_ALshort_ALima4(ALshort *dst, const al::byte *src, ALsizei numchans, ALsizei len, - ALsizei align) +void Convert_ALshort_ALima4(ALshort *dst, const al::byte *src, size_t numchans, size_t len, + size_t align) { - const ALsizei byte_align{((align-1)/2 + 4) * numchans}; + const size_t byte_align{((align-1)/2 + 4) * numchans}; len /= align; while(len--) @@ -223,10 +225,10 @@ void Convert_ALshort_ALima4(ALshort *dst, const al::byte *src, ALsizei numchans, } } -void Convert_ALshort_ALmsadpcm(ALshort *dst, const al::byte *src, ALsizei numchans, ALsizei len, - ALsizei align) +void Convert_ALshort_ALmsadpcm(ALshort *dst, const al::byte *src, size_t numchans, size_t len, + size_t align) { - const ALsizei byte_align{((align-2)/2 + 7) * numchans}; + const size_t byte_align{((align-2)/2 + 7) * numchans}; len /= align; while(len--) @@ -238,6 +240,41 @@ void Convert_ALshort_ALmsadpcm(ALshort *dst, const al::byte *src, ALsizei numcha } +ALuint BytesFromUserFmt(UserFmtType type) +{ + switch(type) + { + case UserFmtUByte: return sizeof(ALubyte); + case UserFmtShort: return sizeof(ALshort); + case UserFmtFloat: return sizeof(ALfloat); + case UserFmtDouble: return sizeof(ALdouble); + case UserFmtMulaw: return sizeof(ALubyte); + case UserFmtAlaw: return sizeof(ALubyte); + case UserFmtIMA4: break; /* not handled here */ + case UserFmtMSADPCM: break; /* not handled here */ + } + return 0; +} +ALuint ChannelsFromUserFmt(UserFmtChannels chans) +{ + switch(chans) + { + case UserFmtMono: return 1; + case UserFmtStereo: return 2; + case UserFmtRear: return 2; + case UserFmtQuad: return 4; + case UserFmtX51: return 6; + case UserFmtX61: return 7; + case UserFmtX71: return 8; + case UserFmtBFormat2D: return 3; + case UserFmtBFormat3D: return 4; + } + return 0; +} +inline ALuint FrameSizeFromUserFmt(UserFmtChannels chans, UserFmtType type) +{ return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type); } + + constexpr ALbitfieldSOFT INVALID_STORAGE_MASK{~unsigned(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT)}; constexpr ALbitfieldSOFT MAP_READ_WRITE_FLAGS{AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT}; @@ -316,11 +353,8 @@ inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) } -ALsizei SanitizeAlignment(UserFmtType type, ALsizei align) +ALuint SanitizeAlignment(UserFmtType type, ALuint align) { - if(align < 0) - return 0; - if(align == 0) { if(type == UserFmtIMA4) @@ -339,17 +373,17 @@ ALsizei SanitizeAlignment(UserFmtType type, ALsizei align) if(type == UserFmtIMA4) { /* IMA4 block alignment must be a multiple of 8, plus 1. */ - if((align&7) == 1) return align; + if((align&7) == 1) return static_cast(align); return 0; } if(type == UserFmtMSADPCM) { /* MSADPCM block alignment must be a multiple of 2. */ - if((align&1) == 0) return align; + if((align&1) == 0) return static_cast(align); return 0; } - return align; + return static_cast(align); } @@ -369,12 +403,10 @@ const ALchar *NameFromUserFmtType(UserFmtType type) return ""; } -/* - * LoadData - * - * Loads the specified data into the buffer, using the specified format. - */ -void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, UserFmtChannels SrcChannels, UserFmtType SrcType, const al::byte *SrcData, ALbitfieldSOFT access) +/** Loads the specified data into the buffer, using the specified format. */ +void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, ALuint size, + UserFmtChannels SrcChannels, UserFmtType SrcType, const al::byte *SrcData, + ALbitfieldSOFT access) { if UNLIKELY(ReadRef(ALBuf->ref) != 0 || ALBuf->MappedAccess != 0) SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer %u", @@ -422,10 +454,10 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U NameFromUserFmtType(SrcType)); } - const ALsizei unpackalign{ALBuf->UnpackAlign.load()}; - const ALsizei align{SanitizeAlignment(SrcType, unpackalign)}; + const ALuint unpackalign{ALBuf->UnpackAlign}; + const ALuint align{SanitizeAlignment(SrcType, unpackalign)}; if UNLIKELY(align < 1) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid unpack alignment %d for %s samples", + SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid unpack alignment %u for %s samples", unpackalign, NameFromUserFmtType(SrcType)); if((access&AL_PRESERVE_DATA_BIT_SOFT)) @@ -433,14 +465,14 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U /* Can only preserve data with the same format and alignment. */ if UNLIKELY(ALBuf->mFmtChannels != DstChannels || ALBuf->OriginalType != SrcType) SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched format"); - if UNLIKELY(ALBuf->OriginalAlign != align) + if UNLIKELY(static_cast(ALBuf->OriginalAlign) != align) SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched alignment"); } /* Convert the input/source size in bytes to sample frames using the unpack * block alignment. */ - const ALsizei SrcByteAlign{ + const ALuint SrcByteAlign{ (SrcType == UserFmtIMA4) ? ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels) : (SrcType == UserFmtMSADPCM) ? ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels) : (align * FrameSizeFromUserFmt(SrcChannels, SrcType)) @@ -453,13 +485,13 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, U if UNLIKELY(size/SrcByteAlign > std::numeric_limits::max()/align) SETERR_RETURN(context, AL_OUT_OF_MEMORY,, "Buffer size overflow, %d blocks x %d samples per block", size/SrcByteAlign, align); - const auto frames = static_cast(size / SrcByteAlign * align); + const ALuint frames{size / SrcByteAlign * align}; /* Convert the sample frames to the number of bytes needed for internal * storage. */ - ALsizei NumChannels{ChannelsFromFmt(DstChannels)}; - ALsizei FrameSize{NumChannels * BytesFromFmt(DstType)}; + ALuint NumChannels{ChannelsFromFmt(DstChannels)}; + ALuint FrameSize{NumChannels * BytesFromFmt(DstType)}; if UNLIKELY(frames > std::numeric_limits::max()/FrameSize) SETERR_RETURN(context, AL_OUT_OF_MEMORY,, "Buffer size overflow, %d frames x %d bytes per frame", frames, FrameSize); @@ -588,7 +620,7 @@ al::optional DecomposeUserFormat(ALenum format) for(const auto &fmt : UserFmtList) { if(fmt.format == format) - return al::make_optional(DecompResult{fmt.channels, fmt.type}); + return al::make_optional({fmt.channels, fmt.type}); } return al::nullopt; } @@ -607,7 +639,7 @@ START_API_FUNC if UNLIKELY(n <= 0) return; ALCdevice *device{context->mDevice.get()}; - std::unique_lock buflock{device->BufferLock}; + std::lock_guard _{device->BufferLock}; if(!EnsureBuffers(device, static_cast(n))) { context->setError(AL_OUT_OF_MEMORY, "Failed to allocate %d buffer%s", n, (n==1)?"":"s"); @@ -732,8 +764,8 @@ START_API_FUNC if UNLIKELY(!usrfmt) context->setError(AL_INVALID_ENUM, "Invalid format 0x%04x", format); else - LoadData(context.get(), albuf, freq, size, usrfmt->channels, usrfmt->type, - static_cast(data), flags); + LoadData(context.get(), albuf, freq, static_cast(size), usrfmt->channels, + usrfmt->type, static_cast(data), flags); } } END_API_FUNC @@ -772,8 +804,9 @@ START_API_FUNC else if UNLIKELY((unavailable&AL_MAP_PERSISTENT_BIT_SOFT)) context->setError(AL_INVALID_VALUE, "Mapping buffer %u persistently without persistent access", buffer); - else if UNLIKELY(offset < 0 || offset >= albuf->OriginalSize || - length <= 0 || length > albuf->OriginalSize - offset) + else if UNLIKELY(offset < 0 || length <= 0 + || static_cast(offset) >= albuf->OriginalSize + || static_cast(length) > albuf->OriginalSize - static_cast(offset)) context->setError(AL_INVALID_VALUE, "Mapping invalid range %d+%d for buffer %u", offset, length, buffer); else @@ -828,9 +861,9 @@ START_API_FUNC else if UNLIKELY(!(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT)) context->setError(AL_INVALID_OPERATION, "Flushing buffer %u while not mapped for writing", buffer); - else if UNLIKELY(offset < albuf->MappedOffset || - offset >= albuf->MappedOffset+albuf->MappedSize || - length <= 0 || length > albuf->MappedOffset+albuf->MappedSize-offset) + else if UNLIKELY(offset < albuf->MappedOffset || length <= 0 + || offset >= albuf->MappedOffset+albuf->MappedSize + || length > albuf->MappedOffset+albuf->MappedSize-offset) context->setError(AL_INVALID_VALUE, "Flushing invalid range %d+%d on buffer %u", offset, length, buffer); else @@ -868,12 +901,12 @@ START_API_FUNC return; } - ALsizei unpack_align{albuf->UnpackAlign.load()}; - ALsizei align{SanitizeAlignment(usrfmt->type, unpack_align)}; + ALuint unpack_align{albuf->UnpackAlign}; + ALuint align{SanitizeAlignment(usrfmt->type, unpack_align)}; if UNLIKELY(align < 1) - context->setError(AL_INVALID_VALUE, "Invalid unpack alignment %d", unpack_align); - else if UNLIKELY(long{usrfmt->channels} != long{albuf->mFmtChannels} || - usrfmt->type != albuf->OriginalType) + context->setError(AL_INVALID_VALUE, "Invalid unpack alignment %u", unpack_align); + else if UNLIKELY(long{usrfmt->channels} != long{albuf->mFmtChannels} + || usrfmt->type != albuf->OriginalType) context->setError(AL_INVALID_ENUM, "Unpacking data with mismatched format"); else if UNLIKELY(align != albuf->OriginalAlign) context->setError(AL_INVALID_VALUE, @@ -883,43 +916,43 @@ START_API_FUNC context->setError(AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u", buffer); else { - ALsizei num_chans{ChannelsFromFmt(albuf->mFmtChannels)}; - ALsizei frame_size{num_chans * BytesFromFmt(albuf->mFmtType)}; - ALsizei byte_align{ + ALuint num_chans{ChannelsFromFmt(albuf->mFmtChannels)}; + ALuint frame_size{num_chans * BytesFromFmt(albuf->mFmtType)}; + ALuint byte_align{ (albuf->OriginalType == UserFmtIMA4) ? ((align-1)/2 + 4) * num_chans : (albuf->OriginalType == UserFmtMSADPCM) ? ((align-2)/2 + 7) * num_chans : (align * frame_size) }; - if UNLIKELY(offset < 0 || length < 0 || offset > albuf->OriginalSize || - length > albuf->OriginalSize-offset) + if UNLIKELY(offset < 0 || length < 0 || static_cast(offset) > albuf->OriginalSize + || static_cast(length) > albuf->OriginalSize-static_cast(offset)) context->setError(AL_INVALID_VALUE, "Invalid data sub-range %d+%d on buffer %u", offset, length, buffer); - else if UNLIKELY((offset%byte_align) != 0) + else if UNLIKELY((static_cast(offset)%byte_align) != 0) context->setError(AL_INVALID_VALUE, "Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)", offset, byte_align, align); - else if UNLIKELY((length%byte_align) != 0) + else if UNLIKELY((static_cast(length)%byte_align) != 0) context->setError(AL_INVALID_VALUE, "Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)", length, byte_align, align); else { /* offset -> byte offset, length -> sample count */ - offset = offset/byte_align * align * frame_size; - length = length/byte_align * align; + size_t byteoff{static_cast(offset)/byte_align * align * frame_size}; + size_t samplen{static_cast(length)/byte_align * align}; - void *dst = albuf->mData.data() + offset; + void *dst = albuf->mData.data() + byteoff; if(usrfmt->type == UserFmtIMA4 && albuf->mFmtType == FmtShort) Convert_ALshort_ALima4(static_cast(dst), - static_cast(data), num_chans, length, align); + static_cast(data), num_chans, samplen, align); else if(usrfmt->type == UserFmtMSADPCM && albuf->mFmtType == FmtShort) Convert_ALshort_ALmsadpcm(static_cast(dst), - static_cast(data), num_chans, length, align); + static_cast(data), num_chans, samplen, align); else { - assert(long{usrfmt->type} == static_cast(albuf->mFmtType)); - memcpy(dst, data, length * frame_size); + assert(long{usrfmt->type} == long{albuf->mFmtType}); + memcpy(dst, data, size_t{samplen} * frame_size); } } } @@ -1052,14 +1085,14 @@ START_API_FUNC if UNLIKELY(value < 0) context->setError(AL_INVALID_VALUE, "Invalid unpack block alignment %d", value); else - albuf->UnpackAlign.store(value); + albuf->UnpackAlign = static_cast(value); break; case AL_PACK_BLOCK_ALIGNMENT_SOFT: if UNLIKELY(value < 0) context->setError(AL_INVALID_VALUE, "Invalid pack block alignment %d", value); else - albuf->PackAlign.store(value); + albuf->PackAlign = static_cast(value); break; default: @@ -1119,14 +1152,14 @@ START_API_FUNC if UNLIKELY(ReadRef(albuf->ref) != 0) context->setError(AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points", buffer); - else if UNLIKELY(values[0] < 0 || values[0] >= values[1] || - static_cast(values[1]) > albuf->SampleLen) + else if UNLIKELY(values[0] < 0 || values[0] >= values[1] + || static_cast(values[1]) > albuf->SampleLen) context->setError(AL_INVALID_VALUE, "Invalid loop point range %d -> %d on buffer %u", values[0], values[1], buffer); else { - albuf->LoopStart = values[0]; - albuf->LoopEnd = values[1]; + albuf->LoopStart = static_cast(values[0]); + albuf->LoopEnd = static_cast(values[1]); } break; @@ -1229,23 +1262,24 @@ START_API_FUNC break; case AL_BITS: - *value = BytesFromFmt(albuf->mFmtType) * 8; + *value = static_cast(BytesFromFmt(albuf->mFmtType) * 8); break; case AL_CHANNELS: - *value = ChannelsFromFmt(albuf->mFmtChannels); + *value = static_cast(ChannelsFromFmt(albuf->mFmtChannels)); break; case AL_SIZE: - *value = albuf->SampleLen * FrameSizeFromFmt(albuf->mFmtChannels, albuf->mFmtType); + *value = static_cast(albuf->SampleLen * + FrameSizeFromFmt(albuf->mFmtChannels, albuf->mFmtType)); break; case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: - *value = albuf->UnpackAlign.load(); + *value = static_cast(albuf->UnpackAlign); break; case AL_PACK_BLOCK_ALIGNMENT_SOFT: - *value = albuf->PackAlign.load(); + *value = static_cast(albuf->PackAlign); break; default: @@ -1305,8 +1339,8 @@ START_API_FUNC else switch(param) { case AL_LOOP_POINTS_SOFT: - values[0] = albuf->LoopStart; - values[1] = albuf->LoopEnd; + values[0] = static_cast(albuf->LoopStart); + values[1] = static_cast(albuf->LoopEnd); break; default: @@ -1316,39 +1350,7 @@ START_API_FUNC END_API_FUNC -ALsizei BytesFromUserFmt(UserFmtType type) -{ - switch(type) - { - case UserFmtUByte: return sizeof(ALubyte); - case UserFmtShort: return sizeof(ALshort); - case UserFmtFloat: return sizeof(ALfloat); - case UserFmtDouble: return sizeof(ALdouble); - case UserFmtMulaw: return sizeof(ALubyte); - case UserFmtAlaw: return sizeof(ALubyte); - case UserFmtIMA4: break; /* not handled here */ - case UserFmtMSADPCM: break; /* not handled here */ - } - return 0; -} -ALsizei ChannelsFromUserFmt(UserFmtChannels chans) -{ - switch(chans) - { - case UserFmtMono: return 1; - case UserFmtStereo: return 2; - case UserFmtRear: return 2; - case UserFmtQuad: return 4; - case UserFmtX51: return 6; - case UserFmtX61: return 7; - case UserFmtX71: return 8; - case UserFmtBFormat2D: return 3; - case UserFmtBFormat3D: return 4; - } - return 0; -} - -ALsizei BytesFromFmt(FmtType type) +ALuint BytesFromFmt(FmtType type) { switch(type) { @@ -1361,7 +1363,7 @@ ALsizei BytesFromFmt(FmtType type) } return 0; } -ALsizei ChannelsFromFmt(FmtChannels chans) +ALuint ChannelsFromFmt(FmtChannels chans) { switch(chans) { diff --git a/al/buffer.h b/al/buffer.h index 2c01aae2..70faf56e 100644 --- a/al/buffer.h +++ b/al/buffer.h @@ -35,11 +35,6 @@ enum UserFmtChannels : unsigned char { UserFmtBFormat3D, /* WXYZ */ }; -ALsizei BytesFromUserFmt(UserFmtType type); -ALsizei ChannelsFromUserFmt(UserFmtChannels chans); -inline ALsizei FrameSizeFromUserFmt(UserFmtChannels chans, UserFmtType type) -{ return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type); } - /* Storable formats */ enum FmtType : unsigned char { @@ -64,9 +59,9 @@ enum FmtChannels : unsigned char { #define MAX_INPUT_CHANNELS (8) -ALsizei BytesFromFmt(FmtType type); -ALsizei ChannelsFromFmt(FmtChannels chans); -inline ALsizei FrameSizeFromFmt(FmtChannels chans, FmtType type) +ALuint BytesFromFmt(FmtType type); +ALuint ChannelsFromFmt(FmtChannels chans); +inline ALuint FrameSizeFromFmt(FmtChannels chans, FmtType type) { return ChannelsFromFmt(chans) * BytesFromFmt(type); } @@ -81,14 +76,14 @@ struct ALbuffer { FmtType mFmtType{}; UserFmtType OriginalType{}; - ALsizei OriginalSize{0}; - ALsizei OriginalAlign{0}; + ALuint OriginalSize{0}; + ALuint OriginalAlign{0}; ALuint LoopStart{0u}; ALuint LoopEnd{0u}; - std::atomic UnpackAlign{0}; - std::atomic PackAlign{0}; + ALuint UnpackAlign{0}; + ALuint PackAlign{0}; ALbitfieldSOFT MappedAccess{0u}; ALsizei MappedOffset{0}; diff --git a/al/event.cpp b/al/event.cpp index 13b1533f..2832ace7 100644 --- a/al/event.cpp +++ b/al/event.cpp @@ -83,8 +83,8 @@ static int EventThread(ALCcontext *context) (evt.u.srcstate.state==AL_PAUSED) ? "AL_PAUSED" : (evt.u.srcstate.state==AL_STOPPED) ? "AL_STOPPED" : ""; context->mEventCb(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, evt.u.srcstate.id, - evt.u.srcstate.state, static_cast(msg.length()), msg.c_str(), - context->mEventParam); + static_cast(evt.u.srcstate.state), static_cast(msg.length()), + msg.c_str(), context->mEventParam); } else if(evt.EnumType == EventType_BufferCompleted) { diff --git a/al/event.h b/al/event.h index ae1b421b..9056d577 100644 --- a/al/event.h +++ b/al/event.h @@ -33,7 +33,7 @@ struct AsyncEvent { } srcstate; struct { ALuint id; - ALsizei count; + ALuint count; } bufcomp; struct { ALenum type; diff --git a/al/source.cpp b/al/source.cpp index 44c46d65..d368b3f0 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -305,72 +305,69 @@ ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) } while(refcount != device->MixCount.load(std::memory_order_relaxed)); ALdouble offset{0.0}; - if(voice) - { - const ALbufferlistitem *BufferList{Source->queue}; - const ALbuffer *BufferFmt{nullptr}; - ALboolean readFin{AL_FALSE}; - ALuint totalBufferLen{0u}; + if(!voice) return offset; - while(BufferList) - { - if(!BufferFmt) BufferFmt = BufferList->mBuffer; + const ALbufferlistitem *BufferList{Source->queue}; + const ALbuffer *BufferFmt{nullptr}; + ALboolean readFin{AL_FALSE}; + ALuint totalBufferLen{0u}; - readFin |= (BufferList == Current); - totalBufferLen += BufferList->mSampleLen; - if(!readFin) readPos += BufferList->mSampleLen; + while(BufferList) + { + if(!BufferFmt) BufferFmt = BufferList->mBuffer; - BufferList = BufferList->mNext.load(std::memory_order_relaxed); - } - assert(BufferFmt != nullptr); + readFin |= (BufferList == Current); + totalBufferLen += BufferList->mSampleLen; + if(!readFin) readPos += BufferList->mSampleLen; - if(Source->Looping) - readPos %= totalBufferLen; - else - { - /* Wrap back to 0 */ - if(readPos >= totalBufferLen) - readPos = readPosFrac = 0; - } + BufferList = BufferList->mNext.load(std::memory_order_relaxed); + } + assert(BufferFmt != nullptr); - offset = 0.0; - switch(name) - { - case AL_SEC_OFFSET: - offset = (readPos + static_cast(readPosFrac)/FRACTIONONE) / BufferFmt->Frequency; - break; + if(Source->Looping) + readPos %= totalBufferLen; + else + { + /* Wrap back to 0 */ + if(readPos >= totalBufferLen) + readPos = readPosFrac = 0; + } - case AL_SAMPLE_OFFSET: - offset = readPos + static_cast(readPosFrac)/FRACTIONONE; - break; + switch(name) + { + case AL_SEC_OFFSET: + offset = (readPos + static_cast(readPosFrac)/FRACTIONONE) / BufferFmt->Frequency; + break; - case AL_BYTE_OFFSET: - if(BufferFmt->OriginalType == UserFmtIMA4) - { - ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; - ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->mFmtChannels); - ALuint FrameBlockSize = BufferFmt->OriginalAlign; + case AL_SAMPLE_OFFSET: + offset = readPos + static_cast(readPosFrac)/FRACTIONONE; + break; - /* Round down to nearest ADPCM block */ - offset = static_cast(readPos / FrameBlockSize * BlockSize); - } - else if(BufferFmt->OriginalType == UserFmtMSADPCM) - { - ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; - ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->mFmtChannels); - ALuint FrameBlockSize = BufferFmt->OriginalAlign; + case AL_BYTE_OFFSET: + if(BufferFmt->OriginalType == UserFmtIMA4) + { + ALuint FrameBlockSize{BufferFmt->OriginalAlign}; + ALuint align{(BufferFmt->OriginalAlign-1)/2 + 4}; + ALuint BlockSize{align * ChannelsFromFmt(BufferFmt->mFmtChannels)}; - /* Round down to nearest ADPCM block */ - offset = static_cast(readPos / FrameBlockSize * BlockSize); - } - else - { - const ALsizei FrameSize{FrameSizeFromFmt(BufferFmt->mFmtChannels, - BufferFmt->mFmtType)}; - offset = static_cast(readPos * FrameSize); - } - break; + /* Round down to nearest ADPCM block */ + offset = static_cast(readPos / FrameBlockSize * BlockSize); } + else if(BufferFmt->OriginalType == UserFmtMSADPCM) + { + ALuint FrameBlockSize{BufferFmt->OriginalAlign}; + ALuint align{(FrameBlockSize-2)/2 + 7}; + ALuint BlockSize{align * ChannelsFromFmt(BufferFmt->mFmtChannels)}; + + /* Round down to nearest ADPCM block */ + offset = static_cast(readPos / FrameBlockSize * BlockSize); + } + else + { + const ALuint FrameSize{FrameSizeFromFmt(BufferFmt->mFmtChannels, BufferFmt->mFmtType)}; + offset = static_cast(readPos * FrameSize); + } + break; } return offset; @@ -418,13 +415,13 @@ al::optional GetSampleOffset(ALsource *Source) offset = static_cast(Source->Offset); if(BufferFmt->OriginalType == UserFmtIMA4) { - const ALsizei align{(BufferFmt->OriginalAlign-1)/2 + 4}; + const ALuint align{(BufferFmt->OriginalAlign-1)/2 + 4}; offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels); offset *= BufferFmt->OriginalAlign; } else if(BufferFmt->OriginalType == UserFmtMSADPCM) { - const ALsizei align{(BufferFmt->OriginalAlign-2)/2 + 7}; + const ALuint align{(BufferFmt->OriginalAlign-2)/2 + 7}; offset /= align * ChannelsFromFmt(BufferFmt->mFmtChannels); offset *= BufferFmt->OriginalAlign; } diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 2efc5a24..09b76fb7 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -362,7 +362,7 @@ const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, ALfloat template -inline void LoadSampleArray(ALfloat *RESTRICT dst, const al::byte *src, ALint srcstep, +inline void LoadSampleArray(ALfloat *RESTRICT dst, const al::byte *src, const size_t srcstep, const size_t samples) { using SampleType = typename FmtTypeTraits::Type; @@ -372,7 +372,7 @@ inline void LoadSampleArray(ALfloat *RESTRICT dst, const al::byte *src, ALint sr dst[i] = FmtTypeTraits::to_float(ssrc[i*srcstep]); } -void LoadSamples(ALfloat *RESTRICT dst, const al::byte *src, ALint srcstep, FmtType srctype, +void LoadSamples(ALfloat *RESTRICT dst, const al::byte *src, const size_t srcstep, FmtType srctype, const size_t samples) { #define HANDLE_FMT(T) case T: LoadSampleArray(dst, src, srcstep, samples); break @@ -389,7 +389,7 @@ void LoadSamples(ALfloat *RESTRICT dst, const al::byte *src, ALint srcstep, FmtT } ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&BufferLoopItem, - const ALsizei NumChannels, const ALsizei SampleSize, const ALsizei chan, ALuint DataPosInt, + const size_t NumChannels, const size_t SampleSize, const size_t chan, size_t DataPosInt, al::span SrcBuffer) { const ALbuffer *Buffer{BufferListItem->mBuffer}; @@ -439,7 +439,7 @@ ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&B } ALfloat *LoadBufferQueue(ALbufferlistitem *BufferListItem, ALbufferlistitem *BufferLoopItem, - const ALsizei NumChannels, const ALsizei SampleSize, const ALsizei chan, ALuint DataPosInt, + const size_t NumChannels, const size_t SampleSize, const size_t chan, size_t DataPosInt, al::span SrcBuffer) { /* Crawl the buffer queue to fill in the temp buffer */ @@ -485,9 +485,9 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) ALuint DataPosFrac{mPositionFrac.load(std::memory_order_relaxed)}; ALbufferlistitem *BufferListItem{mCurrentBuffer.load(std::memory_order_relaxed)}; ALbufferlistitem *BufferLoopItem{mLoopBuffer.load(std::memory_order_relaxed)}; - const ALsizei NumChannels{mNumChannels}; - const ALsizei SampleSize{mSampleSize}; - const ALint increment{mStep}; + const auto NumChannels = static_cast(mNumChannels); + const auto SampleSize = static_cast(mSampleSize); + const auto increment = static_cast(mStep); if(increment < 1) return; ASSUME(NumChannels > 0); @@ -508,7 +508,7 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) if(!Counter) { /* No fading, just overwrite the old/current params. */ - for(ALsizei chan{0};chan < NumChannels;chan++) + for(ALuint chan{0};chan < NumChannels;chan++) { ChannelData &chandata = mChans[chan]; DirectParams &parms = chandata.mDryParams; @@ -530,7 +530,7 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) } else if((mFlags&VOICE_HAS_HRTF)) { - for(ALsizei chan{0};chan < NumChannels;chan++) + for(ALuint chan{0};chan < NumChannels;chan++) { DirectParams &parms = mChans[chan].mDryParams; if(!(parms.Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD)) @@ -545,7 +545,7 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) } } - ALsizei buffers_done{0}; + ALuint buffers_done{0u}; ALuint OutPos{0u}; do { /* Figure out how many buffer samples will be needed */ @@ -575,11 +575,11 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) * unless this is the last update. */ if(DstBufferSize < SamplesToDo-OutPos) - DstBufferSize &= ~3; + DstBufferSize &= ~3u; } ASSUME(DstBufferSize > 0); - for(ALsizei chan{0};chan < NumChannels;chan++) + for(ALuint chan{0};chan < NumChannels;chan++) { ChannelData &chandata = mChans[chan]; const al::span SrcData{Device->SourceData, SrcBufferSize}; @@ -616,8 +616,8 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) chandata.mPrevSamples.size(), chandata.mPrevSamples.begin()); /* Resample, then apply ambisonic upsampling as needed. */ - const ALfloat *ResampledData{Resample(&mResampleState, - &SrcData[MAX_RESAMPLE_PADDING], DataPosFrac, increment, + const ALfloat *ResampledData{Resample(&mResampleState, &SrcData[MAX_RESAMPLE_PADDING], + DataPosFrac, static_cast(increment), {Device->ResampledData, DstBufferSize})}; if((mFlags&VOICE_IS_AMBISONIC)) { -- cgit v1.2.3 From 474d478854ef2ec46bf7b0cb6148c91b7fb8cc2c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 11 Sep 2019 15:55:37 -0700 Subject: Only pass -Wold-style-cast for C++ --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c37a2d18..4effb94a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -220,7 +220,7 @@ IF(MSVC) ENDFOREACH(flag_var) ENDIF() ELSE() - SET(C_FLAGS ${C_FLAGS} -Winline -Wall -Wold-style-cast) + SET(C_FLAGS ${C_FLAGS} -Winline -Wall $<$:-Wold-style-cast>) CHECK_C_COMPILER_FLAG(-Wextra HAVE_W_EXTRA) IF(HAVE_W_EXTRA) SET(C_FLAGS ${C_FLAGS} -Wextra) -- cgit v1.2.3 From 4c76f32ddac5145231609b1cb4f28028abed814b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Sep 2019 03:14:01 -0700 Subject: Avoid implicit conversions with the examples and utils --- examples/alffplay.cpp | 86 +++++++++++++++++++++++---------------------- examples/alhrtf.c | 13 ++++--- examples/allatency.c | 4 +-- examples/alloopback.c | 2 +- examples/almultireverb.c | 18 +++++----- examples/alplay.c | 4 +-- examples/alrecord.c | 24 ++++++------- examples/alreverb.c | 8 ++--- examples/alstream.c | 17 +++++---- examples/altonegen.c | 8 ++--- examples/common/alhelpers.c | 4 +-- utils/makemhr/loadsofa.cpp | 2 +- utils/openal-info.c | 2 +- 13 files changed, 99 insertions(+), 93 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index cdb228e1..655ffc96 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -213,7 +213,7 @@ class PacketQueue { void pop() { AVPacket *pkt = &mPackets.front(); - mTotalSize -= pkt->size; + mTotalSize -= static_cast(pkt->size); av_packet_unref(pkt); mPackets.pop_front(); } @@ -267,7 +267,7 @@ public: return true; } - mTotalSize += mPackets.back().size; + mTotalSize += static_cast(mPackets.back().size); } mCondVar.notify_one(); return true; @@ -299,7 +299,7 @@ struct AudioState { SwrContextPtr mSwresCtx; /* Conversion format, for what gets fed to OpenAL */ - int mDstChanLayout{0}; + uint64_t mDstChanLayout{0}; AVSampleFormat mDstSampleFmt{AV_SAMPLE_FMT_NONE}; /* Storage of converted samples */ @@ -310,14 +310,14 @@ struct AudioState { /* OpenAL format */ ALenum mFormat{AL_NONE}; - ALsizei mFrameSize{0}; + ALuint mFrameSize{0}; std::mutex mSrcMutex; std::condition_variable mSrcCond; std::atomic_flag mConnected; ALuint mSource{0}; std::vector mBuffers; - ALsizei mBufferIdx{0}; + ALuint mBufferIdx{0}; AudioState(MovieState &movie) : mMovie(movie) { mConnected.test_and_set(std::memory_order_relaxed); } @@ -326,7 +326,7 @@ struct AudioState { if(mSource) alDeleteSources(1, &mSource); if(!mBuffers.empty()) - alDeleteBuffers(mBuffers.size(), mBuffers.data()); + alDeleteBuffers(static_cast(mBuffers.size()), mBuffers.data()); av_freep(&mSamples); } @@ -348,7 +348,7 @@ struct AudioState { int getSync(); int decodeFrame(); - bool readAudio(uint8_t *samples, int length); + bool readAudio(uint8_t *samples, unsigned int length); int handler(); }; @@ -441,7 +441,7 @@ struct MovieState { nanoseconds getDuration(); - int streamComponentOpen(int stream_index); + int streamComponentOpen(unsigned int stream_index); int parse_handler(); }; @@ -618,17 +618,17 @@ int AudioState::decodeFrame() * multiple of the template type size. */ template -static void sample_dup(uint8_t *out, const uint8_t *in, int count, int frame_size) +static void sample_dup(uint8_t *out, const uint8_t *in, unsigned int count, size_t frame_size) { - const T *sample = reinterpret_cast(in); - T *dst = reinterpret_cast(out); + auto *sample = reinterpret_cast(in); + auto *dst = reinterpret_cast(out); if(frame_size == sizeof(T)) std::fill_n(dst, count, *sample); else { /* NOTE: frame_size is a multiple of sizeof(T). */ - int type_mult = frame_size / sizeof(T); - int i = 0; + size_t type_mult{frame_size / sizeof(T)}; + size_t i{0}; std::generate_n(dst, count*type_mult, [sample,type_mult,&i]() -> T { @@ -641,10 +641,10 @@ static void sample_dup(uint8_t *out, const uint8_t *in, int count, int frame_siz } -bool AudioState::readAudio(uint8_t *samples, int length) +bool AudioState::readAudio(uint8_t *samples, unsigned int length) { - int sample_skip = getSync(); - int audio_size = 0; + int sample_skip{getSync()}; + unsigned int audio_size{0}; /* Read the next chunk of data, refill the buffer, and queue it * on the source */ @@ -669,16 +669,17 @@ bool AudioState::readAudio(uint8_t *samples, int length) continue; } - int rem = length - audio_size; + unsigned int rem{length - audio_size}; if(mSamplesPos >= 0) { - int len = mSamplesLen - mSamplesPos; + const auto len = static_cast(mSamplesLen - mSamplesPos); if(rem > len) rem = len; - memcpy(samples, mSamples + mSamplesPos*mFrameSize, rem*mFrameSize); + std::copy_n(mSamples + static_cast(mSamplesPos)*mFrameSize, + rem*mFrameSize, samples); } else { - rem = std::min(rem, -mSamplesPos); + rem = std::min(rem, static_cast(-mSamplesPos)); /* Add samples by copying the first sample */ if((mFrameSize&7) == 0) @@ -692,7 +693,7 @@ bool AudioState::readAudio(uint8_t *samples, int length) } mSamplesPos += rem; - mCurrentPts += nanoseconds(seconds(rem)) / mCodecCtx->sample_rate; + mCurrentPts += nanoseconds{seconds{rem}} / mCodecCtx->sample_rate; samples += rem*mFrameSize; audio_size += rem; } @@ -701,10 +702,10 @@ bool AudioState::readAudio(uint8_t *samples, int length) if(audio_size < length) { - int rem = length - audio_size; + const unsigned int rem{length - audio_size}; std::fill_n(samples, rem*mFrameSize, (mDstSampleFmt == AV_SAMPLE_FMT_U8) ? 0x80 : 0x00); - mCurrentPts += nanoseconds(seconds(rem)) / mCodecCtx->sample_rate; + mCurrentPts += nanoseconds{seconds{rem}} / mCodecCtx->sample_rate; audio_size += rem; } return true; @@ -928,8 +929,8 @@ int AudioState::handler() } } void *samples{nullptr}; - ALsizei buffer_len = std::chrono::duration_cast>( - mCodecCtx->sample_rate * AudioBufferTime).count() * mFrameSize; + ALsizei buffer_len = static_cast(std::chrono::duration_cast( + mCodecCtx->sample_rate * AudioBufferTime).count() * mFrameSize); mSamples = nullptr; mSamplesMax = 0; @@ -968,9 +969,9 @@ int AudioState::handler() } else mSwresCtx.reset(swr_alloc_set_opts(nullptr, - mDstChanLayout, mDstSampleFmt, mCodecCtx->sample_rate, - mCodecCtx->channel_layout ? mCodecCtx->channel_layout : - static_cast(av_get_default_channel_layout(mCodecCtx->channels)), + static_cast(mDstChanLayout), mDstSampleFmt, mCodecCtx->sample_rate, + mCodecCtx->channel_layout ? static_cast(mCodecCtx->channel_layout) : + av_get_default_channel_layout(mCodecCtx->channels), mCodecCtx->sample_fmt, mCodecCtx->sample_rate, 0, nullptr)); if(!mSwresCtx || swr_init(mSwresCtx.get()) != 0) @@ -980,7 +981,7 @@ int AudioState::handler() } mBuffers.assign(AudioBufferTotalTime / AudioBufferTime, 0); - alGenBuffers(mBuffers.size(), mBuffers.data()); + alGenBuffers(static_cast(mBuffers.size()), mBuffers.data()); alGenSources(1, &mSource); if(EnableDirectOut) @@ -1003,12 +1004,12 @@ int AudioState::handler() if(alGetError() != AL_NO_ERROR) { fprintf(stderr, "Failed to use mapped buffers\n"); - samples = av_malloc(buffer_len); + samples = av_malloc(static_cast(buffer_len)); } } else #endif - samples = av_malloc(buffer_len); + samples = av_malloc(static_cast(buffer_len)); /* Prefill the codec buffer. */ do { @@ -1053,14 +1054,15 @@ int AudioState::handler() { auto ptr = static_cast(alMapBufferSOFT(bufid, 0, buffer_len, AL_MAP_WRITE_BIT_SOFT)); - bool got_audio{readAudio(ptr, buffer_len)}; + bool got_audio{readAudio(ptr, static_cast(buffer_len))}; alUnmapBufferSOFT(bufid); if(!got_audio) break; } else #endif { - if(!readAudio(static_cast(samples), buffer_len)) + auto ptr = static_cast(samples); + if(!readAudio(ptr, static_cast(buffer_len))) break; alBufferData(bufid, mFormat, samples, buffer_len, mCodecCtx->sample_rate); } @@ -1138,27 +1140,27 @@ void VideoState::display(SDL_Window *screen, SDL_Renderer *renderer) if(!mImage) return; - float aspect_ratio; + double aspect_ratio; int win_w, win_h; int w, h, x, y; if(mCodecCtx->sample_aspect_ratio.num == 0) - aspect_ratio = 0.0f; + aspect_ratio = 0.0; else { aspect_ratio = av_q2d(mCodecCtx->sample_aspect_ratio) * mCodecCtx->width / mCodecCtx->height; } - if(aspect_ratio <= 0.0f) - aspect_ratio = static_cast(mCodecCtx->width) / static_cast(mCodecCtx->height); + if(aspect_ratio <= 0.0) + aspect_ratio = static_cast(mCodecCtx->width) / mCodecCtx->height; SDL_GetWindowSize(screen, &win_w, &win_h); h = win_h; - w = (static_cast(rint(h * aspect_ratio)) + 3) & ~3; + w = (static_cast(std::rint(h * aspect_ratio)) + 3) & ~3; if(w > win_w) { w = win_w; - h = (static_cast(rint(w / aspect_ratio)) + 3) & ~3; + h = (static_cast(std::rint(w / aspect_ratio)) + 3) & ~3; } x = (win_w - w) / 2; y = (win_h - h) / 2; @@ -1460,9 +1462,9 @@ nanoseconds MovieState::getMasterClock() nanoseconds MovieState::getDuration() { return std::chrono::duration>(mFormatCtx->duration); } -int MovieState::streamComponentOpen(int stream_index) +int MovieState::streamComponentOpen(unsigned int stream_index) { - if(stream_index < 0 || static_cast(stream_index) >= mFormatCtx->nb_streams) + if(stream_index >= mFormatCtx->nb_streams) return -1; /* Get a pointer to the codec context for the stream, and open the @@ -1499,7 +1501,7 @@ int MovieState::streamComponentOpen(int stream_index) return -1; } - return stream_index; + return static_cast(stream_index); } int MovieState::parse_handler() diff --git a/examples/alhrtf.c b/examples/alhrtf.c index 96cf0255..f09f3e99 100644 --- a/examples/alhrtf.c +++ b/examples/alhrtf.c @@ -112,7 +112,7 @@ static ALuint LoadSound(const char *filename) * close the file. */ buffer = 0; alGenBuffers(1, &buffer); - alBufferData(buffer, format, sample->buffer, slen, sample->actual.rate); + alBufferData(buffer, format, sample->buffer, (ALsizei)slen, (ALsizei)sample->actual.rate); Sound_FreeSample(sample); /* Check if an error occured, and clean up if so. */ @@ -132,6 +132,7 @@ static ALuint LoadSound(const char *filename) int main(int argc, char **argv) { ALCdevice *device; + ALCcontext *context; ALboolean has_angle_ext; ALuint source, buffer; const char *soundname; @@ -153,7 +154,8 @@ int main(int argc, char **argv) if(InitAL(&argv, &argc) != 0) return 1; - device = alcGetContextsDevice(alcGetCurrentContext()); + context = alcGetCurrentContext(); + device = alcGetContextsDevice(context); if(!alcIsExtensionPresent(device, "ALC_SOFT_HRTF")) { fprintf(stderr, "Error: ALC_SOFT_HRTF not supported\n"); @@ -171,7 +173,7 @@ int main(int argc, char **argv) * stereo sources. */ has_angle_ext = alIsExtensionPresent("AL_EXT_STEREO_ANGLES"); - printf("AL_EXT_STEREO_ANGLES%s found\n", has_angle_ext?"":" not"); + printf("AL_EXT_STEREO_ANGLES %sfound\n", has_angle_ext?"":"not "); /* Check for user-preferred HRTF */ if(strcmp(argv[0], "-hrtf") == 0) @@ -255,7 +257,7 @@ int main(int argc, char **argv) alGenSources(1, &source); alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); alSource3f(source, AL_POSITION, 0.0f, 0.0f, -1.0f); - alSourcei(source, AL_BUFFER, buffer); + alSourcei(source, AL_BUFFER, (ALint)buffer); assert(alGetError()==AL_NO_ERROR && "Failed to setup sound source"); /* Play the sound until it finishes. */ @@ -264,6 +266,8 @@ int main(int argc, char **argv) do { al_nssleep(10000000); + alcSuspendContext(context); + /* Rotate the source around the listener by about 1/4 cycle per second, * and keep it within -pi...+pi. */ @@ -282,6 +286,7 @@ int main(int argc, char **argv) ALfloat angles[2] = { (ALfloat)(M_PI/6.0 - angle), (ALfloat)(-M_PI/6.0 - angle) }; alSourcefv(source, AL_STEREO_ANGLES, angles); } + alcProcessContext(context); alGetSourcei(source, AL_SOURCE_STATE, &state); } while(alGetError() == AL_NO_ERROR && state == AL_PLAYING); diff --git a/examples/allatency.c b/examples/allatency.c index 2bc76289..ad700cc1 100644 --- a/examples/allatency.c +++ b/examples/allatency.c @@ -115,7 +115,7 @@ static ALuint LoadSound(const char *filename) * close the file. */ buffer = 0; alGenBuffers(1, &buffer); - alBufferData(buffer, format, sample->buffer, slen, sample->actual.rate); + alBufferData(buffer, format, sample->buffer, (ALsizei)slen, (ALsizei)sample->actual.rate); Sound_FreeSample(sample); /* Check if an error occured, and clean up if so. */ @@ -188,7 +188,7 @@ int main(int argc, char **argv) /* Create the source to play the sound with. */ source = 0; alGenSources(1, &source); - alSourcei(source, AL_BUFFER, buffer); + alSourcei(source, AL_BUFFER, (ALint)buffer); assert(alGetError()==AL_NO_ERROR && "Failed to setup sound source"); /* Play the sound until it finishes. */ diff --git a/examples/alloopback.c b/examples/alloopback.c index 313b89d5..426a2af9 100644 --- a/examples/alloopback.c +++ b/examples/alloopback.c @@ -249,7 +249,7 @@ int main(int argc, char *argv[]) /* Create the source to play the sound with. */ source = 0; alGenSources(1, &source); - alSourcei(source, AL_BUFFER, buffer); + alSourcei(source, AL_BUFFER, (ALint)buffer); assert(alGetError()==AL_NO_ERROR && "Failed to setup sound source"); /* Play the sound until it finishes. */ diff --git a/examples/almultireverb.c b/examples/almultireverb.c index efd3bf16..b967a050 100644 --- a/examples/almultireverb.c +++ b/examples/almultireverb.c @@ -211,7 +211,7 @@ static ALuint LoadSound(const char *filename) * close the file. */ buffer = 0; alGenBuffers(1, &buffer); - alBufferData(buffer, format, sample->buffer, slen, sample->actual.rate); + alBufferData(buffer, format, sample->buffer, (ALsizei)slen, (ALsizei)sample->actual.rate); Sound_FreeSample(sample); /* Check if an error occured, and clean up if so. */ @@ -443,8 +443,8 @@ static void UpdateListenerAndEffects(float timediff, const ALuint slots[2], cons } /* Finally, update the effect slots with the updated effect parameters. */ - alAuxiliaryEffectSloti(slots[0], AL_EFFECTSLOT_EFFECT, effects[0]); - alAuxiliaryEffectSloti(slots[1], AL_EFFECTSLOT_EFFECT, effects[1]); + alAuxiliaryEffectSloti(slots[0], AL_EFFECTSLOT_EFFECT, (ALint)effects[0]); + alAuxiliaryEffectSloti(slots[1], AL_EFFECTSLOT_EFFECT, (ALint)effects[1]); } @@ -598,8 +598,8 @@ int main(int argc, char **argv) * effect properties. Modifying or deleting the effect object afterward * won't directly affect the effect slot until they're reapplied like this. */ - alAuxiliaryEffectSloti(slots[0], AL_EFFECTSLOT_EFFECT, effects[0]); - alAuxiliaryEffectSloti(slots[1], AL_EFFECTSLOT_EFFECT, effects[1]); + alAuxiliaryEffectSloti(slots[0], AL_EFFECTSLOT_EFFECT, (ALint)effects[0]); + alAuxiliaryEffectSloti(slots[1], AL_EFFECTSLOT_EFFECT, (ALint)effects[1]); assert(alGetError()==AL_NO_ERROR && "Failed to set effect slot"); /* For the purposes of this example, prepare a filter that optionally @@ -621,8 +621,8 @@ int main(int argc, char **argv) alGenSources(1, &source); alSourcei(source, AL_LOOPING, AL_TRUE); alSource3f(source, AL_POSITION, -5.0f, 0.0f, -2.0f); - alSourcei(source, AL_DIRECT_FILTER, direct_filter); - alSourcei(source, AL_BUFFER, buffer); + alSourcei(source, AL_DIRECT_FILTER, (ALint)direct_filter); + alSourcei(source, AL_BUFFER, (ALint)buffer); /* Connect the source to the effect slots. Here, we connect source send 0 * to Zone 0's slot, and send 1 to Zone 1's slot. Filters can be specified @@ -631,8 +631,8 @@ int main(int argc, char **argv) * can only see a zone through a window or thin wall may be attenuated for * that zone. */ - alSource3i(source, AL_AUXILIARY_SEND_FILTER, slots[0], 0, AL_FILTER_NULL); - alSource3i(source, AL_AUXILIARY_SEND_FILTER, slots[1], 1, AL_FILTER_NULL); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, (ALint)slots[0], 0, AL_FILTER_NULL); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, (ALint)slots[1], 1, AL_FILTER_NULL); assert(alGetError()==AL_NO_ERROR && "Failed to setup sound source"); /* Get the current time as the base for timing in the main loop. */ diff --git a/examples/alplay.c b/examples/alplay.c index 4ff8fb7f..09ad96b4 100644 --- a/examples/alplay.c +++ b/examples/alplay.c @@ -101,7 +101,7 @@ static ALuint LoadSound(const char *filename) * close the file. */ buffer = 0; alGenBuffers(1, &buffer); - alBufferData(buffer, format, sample->buffer, slen, sample->actual.rate); + alBufferData(buffer, format, sample->buffer, (ALsizei)slen, (ALsizei)sample->actual.rate); Sound_FreeSample(sample); /* Check if an error occured, and clean up if so. */ @@ -151,7 +151,7 @@ int main(int argc, char **argv) /* Create the source to play the sound with. */ source = 0; alGenSources(1, &source); - alSourcei(source, AL_BUFFER, buffer); + alSourcei(source, AL_BUFFER, (ALint)buffer); assert(alGetError()==AL_NO_ERROR && "Failed to setup sound source"); /* Play the sound until it finishes. */ diff --git a/examples/alrecord.c b/examples/alrecord.c index d65414c9..627f8540 100644 --- a/examples/alrecord.c +++ b/examples/alrecord.c @@ -73,9 +73,9 @@ typedef struct Recorder { ALuint mDataSize; float mRecTime; - int mChannels; - int mBits; - int mSampleRate; + ALuint mChannels; + ALuint mBits; + ALuint mSampleRate; ALuint mFrameSize; ALbyte *mBuffer; ALsizei mBufferSize; @@ -139,7 +139,7 @@ int main(int argc, char **argv) return 1; } - recorder.mChannels = strtol(argv[1], &end, 0); + recorder.mChannels = (ALuint)strtoul(argv[1], &end, 0); if((recorder.mChannels != 1 && recorder.mChannels != 2) || (end && *end != '\0')) { fprintf(stderr, "Invalid channels: %s\n", argv[1]); @@ -156,7 +156,7 @@ int main(int argc, char **argv) return 1; } - recorder.mBits = strtol(argv[1], &end, 0); + recorder.mBits = (ALuint)strtoul(argv[1], &end, 0); if((recorder.mBits != 8 && recorder.mBits != 16 && recorder.mBits != 32) || (end && *end != '\0')) { @@ -174,7 +174,7 @@ int main(int argc, char **argv) return 1; } - recorder.mSampleRate = strtol(argv[1], &end, 0); + recorder.mSampleRate = (ALuint)strtoul(argv[1], &end, 0); if(!(recorder.mSampleRate >= 8000 && recorder.mSampleRate <= 96000) || (end && *end != '\0')) { fprintf(stderr, "Invalid sample rate: %s\n", argv[1]); @@ -285,15 +285,15 @@ int main(int argc, char **argv) // 16-bit val, format type id (1 = integer PCM, 3 = float PCM) fwrite16le((recorder.mBits == 32) ? 0x0003 : 0x0001, recorder.mFile); // 16-bit val, channel count - fwrite16le(recorder.mChannels, recorder.mFile); + fwrite16le((ALushort)recorder.mChannels, recorder.mFile); // 32-bit val, frequency fwrite32le(recorder.mSampleRate, recorder.mFile); // 32-bit val, bytes per second fwrite32le(recorder.mSampleRate * recorder.mFrameSize, recorder.mFile); // 16-bit val, frame size - fwrite16le(recorder.mFrameSize, recorder.mFile); + fwrite16le((ALushort)recorder.mFrameSize, recorder.mFile); // 16-bit val, bits per sample - fwrite16le(recorder.mBits, recorder.mFile); + fwrite16le((ALushort)recorder.mBits, recorder.mFile); // 16-bit val, extra byte count fwrite16le(0, recorder.mFile); @@ -331,7 +331,7 @@ int main(int argc, char **argv) } if(count > recorder.mBufferSize) { - ALbyte *data = calloc(recorder.mFrameSize, count); + ALbyte *data = calloc(recorder.mFrameSize, (ALuint)count); free(recorder.mBuffer); recorder.mBuffer = data; recorder.mBufferSize = count; @@ -365,7 +365,7 @@ int main(int argc, char **argv) } } #endif - recorder.mDataSize += (ALuint)fwrite(recorder.mBuffer, recorder.mFrameSize, count, + recorder.mDataSize += (ALuint)fwrite(recorder.mBuffer, recorder.mFrameSize, (ALuint)count, recorder.mFile); } alcCaptureStop(recorder.mDevice); @@ -385,7 +385,7 @@ int main(int argc, char **argv) { fwrite32le(recorder.mDataSize*recorder.mFrameSize, recorder.mFile); if(fseek(recorder.mFile, 4, SEEK_SET) == 0) - fwrite32le(total_size - 8, recorder.mFile); + fwrite32le((ALuint)total_size - 8, recorder.mFile); } fclose(recorder.mFile); diff --git a/examples/alreverb.c b/examples/alreverb.c index e1d3c207..68f0269f 100644 --- a/examples/alreverb.c +++ b/examples/alreverb.c @@ -209,7 +209,7 @@ static ALuint LoadSound(const char *filename) * close the file. */ buffer = 0; alGenBuffers(1, &buffer); - alBufferData(buffer, format, sample->buffer, slen, sample->actual.rate); + alBufferData(buffer, format, sample->buffer, (ALsizei)slen, (ALsizei)sample->actual.rate); Sound_FreeSample(sample); /* Check if an error occured, and clean up if so. */ @@ -309,18 +309,18 @@ int main(int argc, char **argv) * effectively copies the effect properties. You can modify or delete the * effect object afterward without affecting the effect slot. */ - alAuxiliaryEffectSloti(slot, AL_EFFECTSLOT_EFFECT, effect); + alAuxiliaryEffectSloti(slot, AL_EFFECTSLOT_EFFECT, (ALint)effect); assert(alGetError()==AL_NO_ERROR && "Failed to set effect slot"); /* Create the source to play the sound with. */ source = 0; alGenSources(1, &source); - alSourcei(source, AL_BUFFER, buffer); + alSourcei(source, AL_BUFFER, (ALint)buffer); /* Connect the source to the effect slot. This tells the source to use the * effect slot 'slot', on send #0 with the AL_FILTER_NULL filter object. */ - alSource3i(source, AL_AUXILIARY_SEND_FILTER, slot, 0, AL_FILTER_NULL); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, (ALint)slot, 0, AL_FILTER_NULL); assert(alGetError()==AL_NO_ERROR && "Failed to setup sound source"); /* Play the sound until it finishes. */ diff --git a/examples/alstream.c b/examples/alstream.c index cb447355..56505ddb 100644 --- a/examples/alstream.c +++ b/examples/alstream.c @@ -160,10 +160,10 @@ static int OpenPlayerFile(StreamPlayer *player, const char *filename) fprintf(stderr, "Unsupported channel count: %d\n", player->sample->actual.channels); goto error; } - player->srate = player->sample->actual.rate; + player->srate = (ALsizei)player->sample->actual.rate; frame_size = player->sample->actual.channels * - SDL_AUDIO_BITSIZE(player->sample->actual.format) / 8; + SDL_AUDIO_BITSIZE(player->sample->actual.format) / 8; /* Set the buffer size, given the desired millisecond length. */ Sound_SetBufferSize(player->sample, (Uint32)((Uint64)player->srate*BUFFER_TIME_MS/1000) * @@ -191,7 +191,7 @@ static void ClosePlayerFile(StreamPlayer *player) /* Prebuffers some audio from the file, and starts playing the source */ static int StartPlayer(StreamPlayer *player) { - size_t i; + ALsizei i; /* Rewind the source position and clear the buffer queue */ alSourceRewind(player->source); @@ -204,8 +204,8 @@ static int StartPlayer(StreamPlayer *player) Uint32 slen = Sound_Decode(player->sample); if(slen == 0) break; - alBufferData(player->buffers[i], player->format, - player->sample->buffer, slen, player->srate); + alBufferData(player->buffers[i], player->format, player->sample->buffer, (ALsizei)slen, + player->srate); } if(alGetError() != AL_NO_ERROR) { @@ -255,8 +255,8 @@ static int UpdatePlayer(StreamPlayer *player) slen = Sound_Decode(player->sample); if(slen > 0) { - alBufferData(bufid, player->format, player->sample->buffer, slen, - player->srate); + alBufferData(bufid, player->format, player->sample->buffer, (ALsizei)slen, + player->srate); alSourceQueueBuffers(player->source, 1, &bufid); } if(alGetError() != AL_NO_ERROR) @@ -323,8 +323,7 @@ int main(int argc, char **argv) else namepart = argv[i]; - printf("Playing: %s (%s, %dhz)\n", namepart, FormatName(player->format), - player->srate); + printf("Playing: %s (%s, %dhz)\n", namepart, FormatName(player->format), player->srate); fflush(stdout); if(!StartPlayer(player)) diff --git a/examples/altonegen.c b/examples/altonegen.c index 628e695d..aacc3496 100644 --- a/examples/altonegen.c +++ b/examples/altonegen.c @@ -91,7 +91,7 @@ static void ApplySin(ALfloat *data, ALdouble g, ALuint srate, ALuint freq) static ALuint CreateWave(enum WaveType type, ALuint freq, ALuint srate) { ALuint seed = 22222; - ALint data_size; + ALuint data_size; ALfloat *data; ALuint buffer; ALenum err; @@ -142,7 +142,7 @@ static ALuint CreateWave(enum WaveType type, ALuint freq, ALuint srate) /* Buffer the audio data into a new buffer object. */ buffer = 0; alGenBuffers(1, &buffer); - alBufferData(buffer, AL_FORMAT_MONO_FLOAT32, data, data_size, srate); + alBufferData(buffer, AL_FORMAT_MONO_FLOAT32, data, (ALsizei)data_size, (ALsizei)srate); free(data); /* Check if an error occured, and clean up if so. */ @@ -257,7 +257,7 @@ int main(int argc, char *argv[]) srate = dev_rate; /* Load the sound into a buffer. */ - buffer = CreateWave(wavetype, tone_freq, srate); + buffer = CreateWave(wavetype, (ALuint)tone_freq, (ALuint)srate); if(!buffer) { CloseAL(); @@ -271,7 +271,7 @@ int main(int argc, char *argv[]) /* Create the source to play the sound with. */ source = 0; alGenSources(1, &source); - alSourcei(source, AL_BUFFER, buffer); + alSourcei(source, AL_BUFFER, (ALint)buffer); assert(alGetError()==AL_NO_ERROR && "Failed to setup sound source"); /* Play the sound for a while. */ diff --git a/examples/common/alhelpers.c b/examples/common/alhelpers.c index b387fd2d..730d2e13 100644 --- a/examples/common/alhelpers.c +++ b/examples/common/alhelpers.c @@ -159,12 +159,12 @@ int altime_get(void) struct timespec ts; int ret = clock_gettime(CLOCK_REALTIME, &ts); if(ret != 0) return 0; - cur_time = ts.tv_sec*1000 + ts.tv_nsec/1000000; + cur_time = (int)(ts.tv_sec*1000 + ts.tv_nsec/1000000); #else /* _POSIX_TIMERS > 0 */ struct timeval tv; int ret = gettimeofday(&tv, NULL); if(ret != 0) return 0; - cur_time = tv.tv_sec*1000 + tv.tv_usec/1000; + cur_time = (int)(tv.tv_sec*1000 + tv.tv_usec/1000); #endif if(!start_time) diff --git a/utils/makemhr/loadsofa.cpp b/utils/makemhr/loadsofa.cpp index e82376aa..02911e12 100644 --- a/utils/makemhr/loadsofa.cpp +++ b/utils/makemhr/loadsofa.cpp @@ -50,7 +50,7 @@ static const char *SofaErrorStr(int err) * of other axes as necessary. The epsilons are used to constrain the * equality of unique elements. */ -static uint GetUniquelySortedElems(const uint m, const float *triplets, const int axis, +static uint GetUniquelySortedElems(const uint m, const float *triplets, const uint axis, const double *const (&filters)[3], const double (&epsilons)[3], float *elems) { uint count{0u}; diff --git a/utils/openal-info.c b/utils/openal-info.c index 12dc6311..cc628b6e 100644 --- a/utils/openal-info.c +++ b/utils/openal-info.c @@ -124,7 +124,7 @@ static void printList(const char *list, char separator) next = strchr(list, separator); if(next) { - len = next-list; + len = (size_t)(next-list); do { next++; } while(*next == separator); -- cgit v1.2.3 From 6699f3cf1cd563814ec5c4513613d588a05e2941 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Sep 2019 04:17:21 -0700 Subject: Use unsigned channel indices --- alc/alc.cpp | 6 +++--- alc/alcmain.h | 9 +++++---- alc/alu.cpp | 37 ++++++++++++++++++------------------- alc/backends/pulseaudio.cpp | 4 ++-- alc/bformatdec.cpp | 11 +++++------ alc/bformatdec.h | 4 ++-- alc/effects/dedicated.cpp | 10 ++++++---- alc/mixvoice.cpp | 5 ++--- alc/panning.cpp | 34 ++++++++++++++++++---------------- 9 files changed, 61 insertions(+), 59 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index 10ab3b94..a819bbf7 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -1409,7 +1409,7 @@ static ALCboolean IsValidAmbiScaling(ALCenum scaling) */ void SetDefaultWFXChannelOrder(ALCdevice *device) { - device->RealOut.ChannelIndex.fill(-1); + device->RealOut.ChannelIndex.fill(INVALID_CHANNEL_INDEX); switch(device->FmtChans) { @@ -1497,7 +1497,7 @@ void SetDefaultWFXChannelOrder(ALCdevice *device) */ void SetDefaultChannelOrder(ALCdevice *device) { - device->RealOut.ChannelIndex.fill(-1); + device->RealOut.ChannelIndex.fill(INVALID_CHANNEL_INDEX); switch(device->FmtChans) { @@ -1849,7 +1849,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->Dry.AmbiMap.fill(BFChannelConfig{}); device->Dry.Buffer = {}; std::fill(std::begin(device->NumChannelsPerOrder), std::end(device->NumChannelsPerOrder), 0u); - device->RealOut.ChannelIndex.fill(-1); + device->RealOut.ChannelIndex.fill(INVALID_CHANNEL_INDEX); device->RealOut.Buffer = {}; device->MixBuffer.clear(); device->MixBuffer.shrink_to_fit(); diff --git a/alc/alcmain.h b/alc/alcmain.h index 556268ce..fb93488f 100644 --- a/alc/alcmain.h +++ b/alc/alcmain.h @@ -183,7 +183,7 @@ struct MixParams { }; struct RealMixParams { - std::array ChannelIndex{}; + std::array ChannelIndex{}; al::span Buffer; }; @@ -374,11 +374,12 @@ const ALCchar *DevFmtChannelsString(DevFmtChannels chans) noexcept; /** * GetChannelIdxByName * - * Returns the index for the given channel name (e.g. FrontCenter), or -1 if it - * doesn't exist. + * Returns the index for the given channel name (e.g. FrontCenter), or + * INVALID_CHANNEL_INDEX if it doesn't exist. */ -inline ALint GetChannelIdxByName(const RealMixParams &real, Channel chan) noexcept +inline ALuint GetChannelIdxByName(const RealMixParams &real, Channel chan) noexcept { return real.ChannelIndex[chan]; } +#define INVALID_CHANNEL_INDEX ~0u al::vector SearchDataFiles(const char *match, const char *subdir); diff --git a/alc/alu.cpp b/alc/alu.cpp index e58ff3b4..a1c6ab7a 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -155,9 +155,8 @@ void aluInit(void) void ALCdevice::ProcessHrtf(const size_t SamplesToDo) { /* HRTF is stereo output only. */ - const int lidx{RealOut.ChannelIndex[FrontLeft]}; - const int ridx{RealOut.ChannelIndex[FrontRight]}; - ASSUME(lidx >= 0 && ridx >= 0); + const ALuint lidx{RealOut.ChannelIndex[FrontLeft]}; + const ALuint ridx{RealOut.ChannelIndex[FrontRight]}; MixDirectHrtf(RealOut.Buffer[lidx], RealOut.Buffer[ridx], Dry.Buffer, HrtfAccumData, mHrtfState.get(), SamplesToDo); @@ -171,9 +170,8 @@ void ALCdevice::ProcessAmbiDec(const size_t SamplesToDo) void ALCdevice::ProcessUhj(const size_t SamplesToDo) { /* UHJ is stereo output only. */ - const int lidx{RealOut.ChannelIndex[FrontLeft]}; - const int ridx{RealOut.ChannelIndex[FrontRight]}; - ASSUME(lidx >= 0 && ridx >= 0); + const ALuint lidx{RealOut.ChannelIndex[FrontLeft]}; + const ALuint ridx{RealOut.ChannelIndex[FrontRight]}; /* Encode to stereo-compatible 2-channel UHJ output. */ Uhj_Encoder->encode(RealOut.Buffer[lidx], RealOut.Buffer[ridx], Dry.Buffer.data(), @@ -186,9 +184,8 @@ void ALCdevice::ProcessBs2b(const size_t SamplesToDo) AmbiDecoder->process(RealOut.Buffer, Dry.Buffer.data(), SamplesToDo); /* BS2B is stereo output only. */ - const int lidx{RealOut.ChannelIndex[FrontLeft]}; - const int ridx{RealOut.ChannelIndex[FrontRight]}; - ASSUME(lidx >= 0 && ridx >= 0); + const ALuint lidx{RealOut.ChannelIndex[FrontLeft]}; + const ALuint ridx{RealOut.ChannelIndex[FrontRight]}; /* Now apply the BS2B binaural/crossfeed filter. */ bs2b_cross_feed(Bs2b.get(), RealOut.Buffer[lidx].data(), RealOut.Buffer[ridx].data(), @@ -662,8 +659,9 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo for(ALsizei c{0};c < num_channels;c++) { - int idx{GetChannelIdxByName(Device->RealOut, chans[c].channel)}; - if(idx != -1) voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain; + const ALuint idx{GetChannelIdxByName(Device->RealOut, chans[c].channel)}; + if(idx != INVALID_CHANNEL_INDEX) + voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain; } /* Auxiliary sends still use normal channel panning since they mix to @@ -807,8 +805,9 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo { if(Device->Dry.Buffer.data() == Device->RealOut.Buffer.data()) { - int idx = GetChannelIdxByName(Device->RealOut, chans[c].channel); - if(idx != -1) voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain; + const ALuint idx{GetChannelIdxByName(Device->RealOut, chans[c].channel)}; + if(idx != INVALID_CHANNEL_INDEX) + voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain; } continue; } @@ -854,8 +853,9 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo { if(Device->Dry.Buffer.data() == Device->RealOut.Buffer.data()) { - int idx = GetChannelIdxByName(Device->RealOut, chans[c].channel); - if(idx != -1) voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain; + const ALuint idx{GetChannelIdxByName(Device->RealOut, chans[c].channel)}; + if(idx != INVALID_CHANNEL_INDEX) + voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain; } continue; } @@ -1667,10 +1667,9 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, const ALuint NumSamples) /* Apply front image stablization for surround sound, if applicable. */ if(device->Stablizer) { - const int lidx{GetChannelIdxByName(device->RealOut, FrontLeft)}; - const int ridx{GetChannelIdxByName(device->RealOut, FrontRight)}; - const int cidx{GetChannelIdxByName(device->RealOut, FrontCenter)}; - assert(lidx >= 0 && ridx >= 0 && cidx >= 0); + const ALuint lidx{GetChannelIdxByName(device->RealOut, FrontLeft)}; + const ALuint ridx{GetChannelIdxByName(device->RealOut, FrontRight)}; + const ALuint cidx{GetChannelIdxByName(device->RealOut, FrontCenter)}; ApplyStablizer(device->Stablizer.get(), RealOut, lidx, ridx, cidx, SamplesToDo); } diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 499a192f..c1e615ae 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -278,8 +278,8 @@ size_t ChannelFromPulse(pa_channel_position_t chan) void SetChannelOrderFromMap(ALCdevice *device, const pa_channel_map &chanmap) { - device->RealOut.ChannelIndex.fill(-1); - for(int i{0};i < chanmap.channels;++i) + device->RealOut.ChannelIndex.fill(INVALID_CHANNEL_INDEX); + for(ALuint i{0};i < chanmap.channels;++i) device->RealOut.ChannelIndex[ChannelFromPulse(chanmap.map[i])] = i; } diff --git a/alc/bformatdec.cpp b/alc/bformatdec.cpp index c2137b33..17b0d3d9 100644 --- a/alc/bformatdec.cpp +++ b/alc/bformatdec.cpp @@ -49,7 +49,7 @@ inline auto GetAmbiScales(AmbDecScale scaletype) noexcept -> const std::arrayFreqBands == 2); if(!mDualBand) @@ -64,7 +64,7 @@ BFormatDec::BFormatDec(const AmbDecConf *conf, const bool allow_2band, const ALu mNumChannels = inchans; mEnabled = std::accumulate(std::begin(chanmap), std::begin(chanmap)+conf->Speakers.size(), 0u, - [](ALuint mask, const ALsizei &chan) noexcept -> ALuint + [](ALuint mask, const ALuint &chan) noexcept -> ALuint { return mask | (1 << chan); } ); @@ -120,21 +120,20 @@ BFormatDec::BFormatDec(const AmbDecConf *conf, const bool allow_2band, const ALu BFormatDec::BFormatDec(const ALuint inchans, const ALsizei chancount, const ChannelDec (&chancoeffs)[MAX_OUTPUT_CHANNELS], - const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]) + const ALuint (&chanmap)[MAX_OUTPUT_CHANNELS]) { mSamples.resize(2); mNumChannels = inchans; ASSUME(chancount > 0); mEnabled = std::accumulate(std::begin(chanmap), std::begin(chanmap)+chancount, 0u, - [](ALuint mask, const ALsizei &chan) noexcept -> ALuint + [](ALuint mask, const ALuint &chan) noexcept -> ALuint { return mask | (1 << chan); } ); const ChannelDec *incoeffs{chancoeffs}; - auto set_coeffs = [this,inchans,&incoeffs](const ALsizei chanidx) noexcept -> void + auto set_coeffs = [this,inchans,&incoeffs](const ALuint chanidx) noexcept -> void { - ASSUME(chanidx >= 0); ALfloat (&mtx)[MAX_AMBI_CHANNELS] = mMatrix.Single[chanidx]; const ALfloat (&coeffs)[MAX_AMBI_CHANNELS] = *(incoeffs++); diff --git a/alc/bformatdec.h b/alc/bformatdec.h index 98cbb022..dc8059b0 100644 --- a/alc/bformatdec.h +++ b/alc/bformatdec.h @@ -43,10 +43,10 @@ class BFormatDec { public: BFormatDec(const AmbDecConf *conf, const bool allow_2band, const ALuint inchans, - const ALuint srate, const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]); + const ALuint srate, const ALuint (&chanmap)[MAX_OUTPUT_CHANNELS]); BFormatDec(const ALuint inchans, const ALsizei chancount, const ChannelDec (&chancoeffs)[MAX_OUTPUT_CHANNELS], - const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS]); + const ALuint (&chanmap)[MAX_OUTPUT_CHANNELS]); /* Decodes the ambisonic input to the given output channels. */ void process(const al::span OutBuffer, const FloatBufferLine *InSamples, diff --git a/alc/effects/dedicated.cpp b/alc/effects/dedicated.cpp index 02fdcc78..aa81e13b 100644 --- a/alc/effects/dedicated.cpp +++ b/alc/effects/dedicated.cpp @@ -58,8 +58,9 @@ void DedicatedState::update(const ALCcontext*, const ALeffectslot *slot, const E if(slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) { - const int idx{!target.RealOut ? -1 : GetChannelIdxByName(*target.RealOut, LFE)}; - if(idx != -1) + const ALuint idx{!target.RealOut ? INVALID_CHANNEL_INDEX : + GetChannelIdxByName(*target.RealOut, LFE)}; + if(idx != INVALID_CHANNEL_INDEX) { mOutTarget = target.RealOut->Buffer; mTargetGains[idx] = Gain; @@ -69,8 +70,9 @@ void DedicatedState::update(const ALCcontext*, const ALeffectslot *slot, const E { /* Dialog goes to the front-center speaker if it exists, otherwise it * plays from the front-center location. */ - const int idx{!target.RealOut ? -1 : GetChannelIdxByName(*target.RealOut, FrontCenter)}; - if(idx != -1) + const ALuint idx{!target.RealOut ? INVALID_CHANNEL_INDEX : + GetChannelIdxByName(*target.RealOut, FrontCenter)}; + if(idx != INVALID_CHANNEL_INDEX) { mOutTarget = target.RealOut->Buffer; mTargetGains[idx] = Gain; diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 09b76fb7..98b86c9a 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -641,9 +641,8 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) if((mFlags&VOICE_HAS_HRTF)) { - const int OutLIdx{GetChannelIdxByName(Device->RealOut, FrontLeft)}; - const int OutRIdx{GetChannelIdxByName(Device->RealOut, FrontRight)}; - ASSUME(OutLIdx >= 0 && OutRIdx >= 0); + const ALuint OutLIdx{GetChannelIdxByName(Device->RealOut, FrontLeft)}; + const ALuint OutRIdx{GetChannelIdxByName(Device->RealOut, FrontRight)}; auto &HrtfSamples = Device->HrtfSourceData; auto &AccumSamples = Device->HrtfAccumData; diff --git a/alc/panning.cpp b/alc/panning.cpp index a33b9387..31daf455 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -147,9 +147,9 @@ struct ChannelMap { ALfloat Config[MAX_AMBI2D_CHANNELS]; }; -bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) +bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALuint (&speakermap)[MAX_OUTPUT_CHANNELS]) { - auto map_spkr = [device](const AmbDecConf::SpeakerConf &speaker) -> ALsizei + auto map_spkr = [device](const AmbDecConf::SpeakerConf &speaker) -> ALuint { /* NOTE: AmbDec does not define any standard speaker names, however * for this to work we have to by able to find the output channel @@ -222,15 +222,15 @@ bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei (&speaker return -1; } } - const int chidx{GetChannelIdxByName(device->RealOut, ch)}; - if(chidx == -1) + const ALuint chidx{GetChannelIdxByName(device->RealOut, ch)}; + if(chidx == INVALID_CHANNEL_INDEX) ERR("Failed to lookup AmbDec speaker label %s\n", speaker.Name.c_str()); return chidx; }; std::transform(conf->Speakers.begin(), conf->Speakers.end(), std::begin(speakermap), map_spkr); /* Return success if no invalid entries are found. */ - auto speakermap_end = std::begin(speakermap) + conf->Speakers.size(); - return std::find(std::begin(speakermap), speakermap_end, -1) == speakermap_end; + auto spkrmap_end = std::begin(speakermap) + conf->Speakers.size(); + return std::find(std::begin(speakermap), spkrmap_end, INVALID_CHANNEL_INDEX) == spkrmap_end; } @@ -285,7 +285,8 @@ void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, std::fill(iter, std::end(device->NumChannelsPerOrder), 0u); } -void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) +void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, + const ALuint (&speakermap)[MAX_OUTPUT_CHANNELS]) { auto get_max = std::bind(maxf, _1, std::bind(std::mem_fn(&AmbDecConf::SpeakerConf::Distance), _2)); @@ -302,7 +303,7 @@ void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei ( for(size_t i{0u};i < conf->Speakers.size();i++) { const AmbDecConf::SpeakerConf &speaker = conf->Speakers[i]; - const ALsizei chan{speakermap[i]}; + const ALuint chan{speakermap[i]}; /* Distance compensation only delays in steps of the sample rate. This * is a bit less accurate since the delay time falls to the nearest @@ -429,11 +430,11 @@ void InitPanning(ALCdevice *device) else { ChannelDec chancoeffs[MAX_OUTPUT_CHANNELS]{}; - ALsizei idxmap[MAX_OUTPUT_CHANNELS]{}; + ALuint idxmap[MAX_OUTPUT_CHANNELS]{}; for(size_t i{0u};i < chanmap.size();++i) { - const ALint idx{GetChannelIdxByName(device->RealOut, chanmap[i].ChanName)}; - if(idx < 0) + const ALuint idx{GetChannelIdxByName(device->RealOut, chanmap[i].ChanName)}; + if(idx == INVALID_CHANNEL_INDEX) { ERR("Failed to find %s channel in device\n", GetLabelFromChannel(chanmap[i].ChanName)); @@ -465,7 +466,8 @@ void InitPanning(ALCdevice *device) } } -void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, const ALsizei (&speakermap)[MAX_OUTPUT_CHANNELS]) +void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, + const ALuint (&speakermap)[MAX_OUTPUT_CHANNELS]) { static constexpr ALuint chans_per_order2d[MAX_AMBI_ORDER+1] = { 1, 2, 2, 2 }; static constexpr ALuint chans_per_order3d[MAX_AMBI_ORDER+1] = { 1, 3, 5, 7 }; @@ -474,9 +476,9 @@ void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, co ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n", conf->XOverFreq); - ALsizei order{(conf->ChanMask > AMBI_2ORDER_MASK) ? 3 : - (conf->ChanMask > AMBI_1ORDER_MASK) ? 2 : 1}; - device->mAmbiOrder = order; + const ALuint order{(conf->ChanMask > AMBI_2ORDER_MASK) ? 3u : + (conf->ChanMask > AMBI_1ORDER_MASK) ? 2u : 1u}; + device->mAmbiOrder = static_cast(order); ALuint count; if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) @@ -692,7 +694,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr } const char *devname{device->DeviceName.c_str()}; - ALsizei speakermap[MAX_OUTPUT_CHANNELS]; + ALuint speakermap[MAX_OUTPUT_CHANNELS]; AmbDecConf *pconf{nullptr}; AmbDecConf conf{}; if(layout) -- cgit v1.2.3 From b71eb4dafd9e525020a5f2cd869d671fb3e8e5bd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Sep 2019 04:30:52 -0700 Subject: Don't use [[nodiscard]] in C++11 To silence some warnings in older compilers, and fix an error with newer MSVC. --- common/almalloc.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/common/almalloc.h b/common/almalloc.h index 37b57d2b..d144ca35 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -42,7 +42,7 @@ struct FamCount { size_t mCount; }; return ret; \ throw std::bad_alloc(); \ } \ - void operator delete(void *block, FamCount /*fam*/) { al_free(block); } \ + void operator delete(void *block, FamCount) { al_free(block); } \ void operator delete(void *block) noexcept { al_free(block); } @@ -61,12 +61,12 @@ struct allocator { }; allocator() = default; - template - constexpr allocator(const allocator&) noexcept { } + template + constexpr allocator(const allocator&) noexcept { } - [[nodiscard]] T *allocate(std::size_t n) + T *allocate(std::size_t n) { - if(n > std::numeric_limits::max() / sizeof(T)) throw std::bad_alloc(); + if(n > std::numeric_limits::max()/sizeof(T)) throw std::bad_alloc(); if(auto p = static_cast(al_malloc(alignment, n*sizeof(T)))) return p; throw std::bad_alloc(); } -- cgit v1.2.3 From c0ce03d8b9533c768687964743420b18c5003455 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Sep 2019 06:29:32 -0700 Subject: Get rid of more implicit conversions --- al/auxeffectslot.cpp | 110 ++++++++++++++++++++++++++------------------------- al/effect.cpp | 86 ++++++++++++++++++++-------------------- al/error.cpp | 3 +- al/filter.cpp | 81 +++++++++++++++++++------------------ al/state.cpp | 20 +++++----- 5 files changed, 156 insertions(+), 144 deletions(-) diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index 06627bc8..f2801329 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "AL/al.h" @@ -158,58 +159,52 @@ void RemoveActiveEffectSlots(const ALuint *slotids, size_t count, ALCcontext *co } -ALeffectslot *AllocEffectSlot(ALCcontext *context) +bool EnsureEffectSlots(ALCcontext *context, size_t needed) { - ALCdevice *device{context->mDevice.get()}; - std::lock_guard _{context->mEffectSlotLock}; - if(context->mNumEffectSlots >= device->AuxiliaryEffectSlotMax) - { - context->setError(AL_OUT_OF_MEMORY, "Exceeding %u effect slot limit", - device->AuxiliaryEffectSlotMax); - return nullptr; - } - auto sublist = std::find_if(context->mEffectSlotList.begin(), context->mEffectSlotList.end(), - [](const EffectSlotSubList &entry) noexcept -> bool - { return entry.FreeMask != 0; } - ); - auto lidx = static_cast(std::distance(context->mEffectSlotList.begin(), sublist)); - ALuint slidx; - if LIKELY(sublist != context->mEffectSlotList.end()) - slidx = static_cast(CTZ64(sublist->FreeMask)); - else + size_t count{std::accumulate(context->mEffectSlotList.cbegin(), + context->mEffectSlotList.cend(), size_t{0}, + [](size_t cur, const EffectSlotSubList &sublist) noexcept -> size_t + { return cur + static_cast(POPCNT64(~sublist.FreeMask)); } + )}; + + while(needed > count) { - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ if UNLIKELY(context->mEffectSlotList.size() >= 1<<25) - { - context->setError(AL_OUT_OF_MEMORY, "Too many effect slots allocated"); - return nullptr; - } - context->mEffectSlotList.emplace_back(); - sublist = context->mEffectSlotList.end() - 1; + return false; + context->mEffectSlotList.emplace_back(); + auto sublist = context->mEffectSlotList.end() - 1; sublist->FreeMask = ~0_u64; - sublist->EffectSlots = static_cast(al_calloc(16, sizeof(ALeffectslot)*64)); + sublist->EffectSlots = static_cast( + al_calloc(alignof(ALeffectslot), sizeof(ALeffectslot)*64)); if UNLIKELY(!sublist->EffectSlots) { context->mEffectSlotList.pop_back(); - context->setError(AL_OUT_OF_MEMORY, "Failed to allocate effect slot batch"); - return nullptr; + return false; } - - slidx = 0; + count += 64; } + return true; +} + +ALeffectslot *AllocEffectSlot(ALCcontext *context) +{ + auto sublist = std::find_if(context->mEffectSlotList.begin(), context->mEffectSlotList.end(), + [](const EffectSlotSubList &entry) noexcept -> bool + { return entry.FreeMask != 0; } + ); + + auto lidx = static_cast(std::distance(context->mEffectSlotList.begin(), sublist)); + auto slidx = static_cast(CTZ64(sublist->FreeMask)); ALeffectslot *slot{::new (sublist->EffectSlots + slidx) ALeffectslot{}}; - ALenum err{InitEffectSlot(slot)}; - if(err != AL_NO_ERROR) + if(ALenum err{InitEffectSlot(slot)}) { al::destroy_at(slot); context->setError(err, "Effect slot object initialization failed"); return nullptr; } - aluInitEffectPanning(slot, device); + aluInitEffectPanning(slot, context->mDevice.get()); /* Add 1 to avoid source ID 0. */ slot->id = ((lidx<<6) | slidx) + 1; @@ -224,7 +219,7 @@ void FreeEffectSlot(ALCcontext *context, ALeffectslot *slot) { const ALuint id{slot->id - 1}; const size_t lidx{id >> 6}; - const size_t slidx{id & 0x3f}; + const ALuint slidx{id & 0x3f}; al::destroy_at(slot); @@ -262,6 +257,21 @@ START_API_FUNC SETERR_RETURN(context, AL_INVALID_VALUE,, "Generating %d effect slots", n); if(n == 0) return; + std::unique_lock slotlock{context->mEffectSlotLock}; + ALCdevice *device{context->mDevice.get()}; + if(static_cast(n) > device->AuxiliaryEffectSlotMax-context->mNumEffectSlots) + { + context->setError(AL_OUT_OF_MEMORY, "Exceeding %u effect slot limit (%u + %d)", + device->AuxiliaryEffectSlotMax, context->mNumEffectSlots, n); + return; + } + if(!EnsureEffectSlots(context.get(), static_cast(n))) + { + context->setError(AL_OUT_OF_MEMORY, "Failed to allocate %d effectslot%s", n, + (n==1) ? "" : "s"); + return; + } + if(n == 1) { ALeffectslot *slot{AllocEffectSlot(context.get())}; @@ -270,27 +280,21 @@ START_API_FUNC } else { - auto tempids = al::vector(static_cast(n)); - auto alloc_end = std::find_if_not(tempids.begin(), tempids.end(), - [&context](ALuint &id) -> bool + al::vector ids; + ids.reserve(static_cast(n)); + do { + ALeffectslot *slot{AllocEffectSlot(context.get())}; + if(!slot) { - ALeffectslot *slot{AllocEffectSlot(context.get())}; - if(!slot) return false; - id = slot->id; - return true; + slotlock.unlock(); + alDeleteAuxiliaryEffectSlots(static_cast(ids.size()), ids.data()); + return; } - ); - if(alloc_end != tempids.end()) - { - auto count = static_cast(std::distance(tempids.begin(), alloc_end)); - alDeleteAuxiliaryEffectSlots(count, tempids.data()); - return; - } - - std::copy(tempids.cbegin(), tempids.cend(), effectslots); + ids.emplace_back(slot->id); + } while(--n); + std::copy(ids.cbegin(), ids.cend(), effectslots); } - std::unique_lock slotlock{context->mEffectSlotLock}; AddActiveEffectSlots(effectslots, static_cast(n), context.get()); } END_API_FUNC diff --git a/al/effect.cpp b/al/effect.cpp index 3836a5e4..c27fc8df 100644 --- a/al/effect.cpp +++ b/al/effect.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "AL/al.h" @@ -136,42 +137,41 @@ void InitEffectParams(ALeffect *effect, ALenum type) effect->type = type; } -ALeffect *AllocEffect(ALCcontext *context) +bool EnsureEffects(ALCdevice *device, size_t needed) { - ALCdevice *device{context->mDevice.get()}; - std::lock_guard _{device->EffectLock}; - auto sublist = std::find_if(device->EffectList.begin(), device->EffectList.end(), - [](const EffectSubList &entry) noexcept -> bool - { return entry.FreeMask != 0; } - ); + size_t count{std::accumulate(device->EffectList.cbegin(), device->EffectList.cend(), size_t{0}, + [](size_t cur, const EffectSubList &sublist) noexcept -> size_t + { return cur + static_cast(POPCNT64(~sublist.FreeMask)); } + )}; - auto lidx = static_cast(std::distance(device->EffectList.begin(), sublist)); - ALsizei slidx{0}; - if LIKELY(sublist != device->EffectList.end()) - slidx = CTZ64(sublist->FreeMask); - else + while(needed > count) { - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ if UNLIKELY(device->EffectList.size() >= 1<<25) - { - context->setError(AL_OUT_OF_MEMORY, "Too many effects allocated"); - return nullptr; - } + return false; + device->EffectList.emplace_back(); - sublist = device->EffectList.end() - 1; + auto sublist = device->EffectList.end() - 1; sublist->FreeMask = ~0_u64; - sublist->Effects = static_cast(al_calloc(16, sizeof(ALeffect)*64)); + sublist->Effects = static_cast(al_calloc(alignof(ALeffect), sizeof(ALeffect)*64)); if UNLIKELY(!sublist->Effects) { device->EffectList.pop_back(); - context->setError(AL_OUT_OF_MEMORY, "Failed to allocate effect batch"); - return nullptr; + return false; } - - slidx = 0; + count += 64; } + return true; +} + +ALeffect *AllocEffect(ALCdevice *device) +{ + auto sublist = std::find_if(device->EffectList.begin(), device->EffectList.end(), + [](const EffectSubList &entry) noexcept -> bool + { return entry.FreeMask != 0; } + ); + + auto lidx = static_cast(std::distance(device->EffectList.begin(), sublist)); + auto slidx = static_cast(CTZ64(sublist->FreeMask)); ALeffect *effect{::new (sublist->Effects + slidx) ALeffect{}}; InitEffectParams(effect, AL_EFFECT_NULL); @@ -186,9 +186,9 @@ ALeffect *AllocEffect(ALCcontext *context) void FreeEffect(ALCdevice *device, ALeffect *effect) { - ALuint id = effect->id - 1; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; + const ALuint id{effect->id - 1}; + const size_t lidx{id >> 6}; + const ALuint slidx{id & 0x3f}; al::destroy_at(effect); @@ -197,8 +197,8 @@ void FreeEffect(ALCdevice *device, ALeffect *effect) inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) { - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; + const size_t lidx{(id-1) >> 6}; + const ALuint slidx{(id-1) & 0x3f}; if UNLIKELY(lidx >= device->EffectList.size()) return nullptr; @@ -220,11 +220,19 @@ START_API_FUNC context->setError(AL_INVALID_VALUE, "Generating %d effects", n); if UNLIKELY(n <= 0) return; + ALCdevice *device{context->mDevice.get()}; + std::lock_guard _{device->EffectLock}; + if(!EnsureEffects(device, static_cast(n))) + { + context->setError(AL_OUT_OF_MEMORY, "Failed to allocate %d effect%s", n, (n==1)?"":"s"); + return; + } + if LIKELY(n == 1) { /* Special handling for the easy and normal case. */ - ALeffect *effect = AllocEffect(context.get()); - if(effect) effects[0] = effect->id; + ALeffect *effect{AllocEffect(device)}; + effects[0] = effect->id; } else { @@ -232,18 +240,12 @@ START_API_FUNC * modifying the user storage in case of failure. */ al::vector ids; - ids.reserve(n); + ids.reserve(static_cast(n)); do { - ALeffect *effect = AllocEffect(context.get()); - if(!effect) - { - alDeleteEffects(static_cast(ids.size()), ids.data()); - return; - } - + ALeffect *effect{AllocEffect(device)}; ids.emplace_back(effect->id); } while(--n); - std::copy(ids.begin(), ids.end(), effects); + std::copy(ids.cbegin(), ids.cend(), effects); } } END_API_FUNC @@ -722,7 +724,7 @@ void LoadReverbPreset(const char *name, ALeffect *effect) effect->Props.Reverb.HFReference = props->flHFReference; effect->Props.Reverb.LFReference = props->flLFReference; effect->Props.Reverb.RoomRolloffFactor = props->flRoomRolloffFactor; - effect->Props.Reverb.DecayHFLimit = props->iDecayHFLimit; + effect->Props.Reverb.DecayHFLimit = props->iDecayHFLimit ? AL_TRUE : AL_FALSE; return; } diff --git a/al/error.cpp b/al/error.cpp index a7080493..f3e2dbb3 100644 --- a/al/error.cpp +++ b/al/error.cpp @@ -86,7 +86,8 @@ void ALCcontext::setError(ALenum errorCode, const char *msg, ...) std::lock_guard _{mEventCbLock}; ALbitfieldSOFT enabledevts{mEnabledEvts.load(std::memory_order_relaxed)}; if((enabledevts&EventType_Error) && mEventCb) - (*mEventCb)(AL_EVENT_TYPE_ERROR_SOFT, 0, errorCode, msglen, msg, mEventParam); + (*mEventCb)(AL_EVENT_TYPE_ERROR_SOFT, 0, static_cast(errorCode), msglen, msg, + mEventParam); } } diff --git a/al/filter.cpp b/al/filter.cpp index abb2795b..920b4ca1 100644 --- a/al/filter.cpp +++ b/al/filter.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "AL/al.h" #include "AL/alc.h" @@ -278,42 +279,42 @@ void InitFilterParams(ALfilter *filter, ALenum type) filter->type = type; } -ALfilter *AllocFilter(ALCcontext *context) +bool EnsureFilters(ALCdevice *device, size_t needed) { - ALCdevice *device{context->mDevice.get()}; - std::lock_guard _{device->FilterLock}; - auto sublist = std::find_if(device->FilterList.begin(), device->FilterList.end(), - [](const FilterSubList &entry) noexcept -> bool - { return entry.FreeMask != 0; } - ); + size_t count{std::accumulate(device->FilterList.cbegin(), device->FilterList.cend(), size_t{0}, + [](size_t cur, const FilterSubList &sublist) noexcept -> size_t + { return cur + static_cast(POPCNT64(~sublist.FreeMask)); } + )}; - auto lidx = static_cast(std::distance(device->FilterList.begin(), sublist)); - ALsizei slidx{0}; - if LIKELY(sublist != device->FilterList.end()) - slidx = CTZ64(sublist->FreeMask); - else + while(needed > count) { - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ if UNLIKELY(device->FilterList.size() >= 1<<25) - { - context->setError(AL_OUT_OF_MEMORY, "Too many filters allocated"); - return nullptr; - } + return false; + device->FilterList.emplace_back(); - sublist = device->FilterList.end() - 1; + auto sublist = device->FilterList.end() - 1; sublist->FreeMask = ~0_u64; - sublist->Filters = static_cast(al_calloc(16, sizeof(ALfilter)*64)); + sublist->Filters = static_cast(al_calloc(alignof(ALfilter), sizeof(ALfilter)*64)); if UNLIKELY(!sublist->Filters) { device->FilterList.pop_back(); - context->setError(AL_OUT_OF_MEMORY, "Failed to allocate filter batch"); - return nullptr; + return false; } - - slidx = 0; + count += 64; } + return true; +} + + +ALfilter *AllocFilter(ALCdevice *device) +{ + auto sublist = std::find_if(device->FilterList.begin(), device->FilterList.end(), + [](const FilterSubList &entry) noexcept -> bool + { return entry.FreeMask != 0; } + ); + + auto lidx = static_cast(std::distance(device->FilterList.begin(), sublist)); + auto slidx = static_cast(CTZ64(sublist->FreeMask)); ALfilter *filter{::new (sublist->Filters + slidx) ALfilter{}}; InitFilterParams(filter, AL_FILTER_NULL); @@ -328,9 +329,9 @@ ALfilter *AllocFilter(ALCcontext *context) void FreeFilter(ALCdevice *device, ALfilter *filter) { - ALuint id = filter->id - 1; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; + const ALuint id{filter->id - 1}; + const size_t lidx{id >> 6}; + const ALuint slidx{id & 0x3f}; al::destroy_at(filter); @@ -340,8 +341,8 @@ void FreeFilter(ALCdevice *device, ALfilter *filter) inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) { - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; + const size_t lidx{(id-1) >> 6}; + const ALuint slidx{(id-1) & 0x3f}; if UNLIKELY(lidx >= device->FilterList.size()) return nullptr; @@ -363,10 +364,18 @@ START_API_FUNC context->setError(AL_INVALID_VALUE, "Generating %d filters", n); if UNLIKELY(n <= 0) return; + ALCdevice *device{context->mDevice.get()}; + std::lock_guard _{device->EffectLock}; + if(!EnsureFilters(device, static_cast(n))) + { + context->setError(AL_OUT_OF_MEMORY, "Failed to allocate %d filter%s", n, (n==1)?"":"s"); + return; + } + if LIKELY(n == 1) { /* Special handling for the easy and normal case. */ - ALfilter *filter = AllocFilter(context.get()); + ALfilter *filter{AllocFilter(device)}; if(filter) filters[0] = filter->id; } else @@ -375,15 +384,9 @@ START_API_FUNC * modifying the user storage in case of failure. */ al::vector ids; - ids.reserve(n); + ids.reserve(static_cast(n)); do { - ALfilter *filter = AllocFilter(context.get()); - if(!filter) - { - alDeleteFilters(static_cast(ids.size()), ids.data()); - return; - } - + ALfilter *filter{AllocFilter(device)}; ids.emplace_back(filter->id); } while(--n); std::copy(ids.begin(), ids.end(), filters); diff --git a/al/state.cpp b/al/state.cpp index cc5d8bac..74fb3b55 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -218,11 +218,11 @@ START_API_FUNC switch(pname) { case AL_DOPPLER_FACTOR: - value = static_cast(context->mDopplerFactor); + value = context->mDopplerFactor; break; case AL_DOPPLER_VELOCITY: - value = static_cast(context->mDopplerVelocity); + value = context->mDopplerVelocity; break; case AL_DISTANCE_MODEL: @@ -230,7 +230,7 @@ START_API_FUNC break; case AL_SPEED_OF_SOUND: - value = static_cast(context->mSpeedOfSound); + value = context->mSpeedOfSound; break; case AL_DEFERRED_UPDATES_SOFT: @@ -239,7 +239,7 @@ START_API_FUNC break; case AL_GAIN_LIMIT_SOFT: - value = static_castGAIN_MIX_MAX/context->mGainBoost; + value = ALdouble{GAIN_MIX_MAX}/context->mGainBoost; break; case AL_NUM_RESAMPLERS_SOFT: @@ -337,7 +337,7 @@ START_API_FUNC case AL_DEFERRED_UPDATES_SOFT: if(context->mDeferUpdates.load(std::memory_order_acquire)) - value = static_cast(AL_TRUE); + value = AL_TRUE; break; case AL_GAIN_LIMIT_SOFT: @@ -710,14 +710,16 @@ START_API_FUNC if((context->mEnabledEvts.load(std::memory_order_relaxed)&EventType_Deprecated)) { - static constexpr ALCchar msg[] = - "alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound"; - const ALsizei msglen = static_cast(strlen(msg)); std::lock_guard _{context->mEventCbLock}; ALbitfieldSOFT enabledevts{context->mEnabledEvts.load(std::memory_order_relaxed)}; if((enabledevts&EventType_Deprecated) && context->mEventCb) + { + static constexpr ALCchar msg[] = + "alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound"; + const ALsizei msglen{sizeof(msg)-1}; (*context->mEventCb)(AL_EVENT_TYPE_DEPRECATED_SOFT, 0, 0, msglen, msg, - context->mEventParam); + context->mEventParam); + } } if(!(value >= 0.0f && std::isfinite(value))) -- cgit v1.2.3 From 2e010d29cba51aec339179d52d3faddf84faafb0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Sep 2019 11:33:04 -0700 Subject: Clean up implicit conversions in source.cpp --- al/source.cpp | 2512 +++++++++++++++++++++++++++--------------------------- al/source.h | 16 +- alc/alu.h | 4 +- alc/mixvoice.cpp | 4 +- 4 files changed, 1270 insertions(+), 1266 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index d368b3f0..3c22b620 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -74,6 +74,7 @@ namespace { using namespace std::placeholders; +using std::chrono::nanoseconds; ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) { @@ -175,7 +176,7 @@ void UpdateSourceProps(const ALsource *source, ALvoice *voice, ALCcontext *conte * samples. The offset is relative to the start of the queue (not the start of * the current buffer). */ -int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, std::chrono::nanoseconds *clocktime) +int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, nanoseconds *clocktime) { ALCdevice *device{context->mDevice.get()}; const ALbufferlistitem *Current; @@ -221,7 +222,7 @@ int64_t GetSourceSampleOffset(ALsource *Source, ALCcontext *context, std::chrono * Gets the current read offset for the given Source, in seconds. The offset is * relative to the start of the queue (not the start of the current buffer). */ -ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, std::chrono::nanoseconds *clocktime) +ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, nanoseconds *clocktime) { ALCdevice *device{context->mDevice.get()}; const ALbufferlistitem *Current; @@ -465,49 +466,72 @@ al::optional GetSampleOffset(ALsource *Source) } -ALsource *AllocSource(ALCcontext *context) +/** + * Returns if the last known state for the source was playing or paused. Does + * not sync with the mixer voice. + */ +inline bool IsPlayingOrPaused(ALsource *source) +{ return source->state == AL_PLAYING || source->state == AL_PAUSED; } + +/** + * Returns an updated source state using the matching voice's status (or lack + * thereof). + */ +inline ALenum GetSourceState(ALsource *source, ALvoice *voice) { - ALCdevice *device{context->mDevice.get()}; - std::lock_guard _{context->mSourceLock}; - if(context->mNumSources >= device->SourcesMax) - { - context->setError(AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax); - return nullptr; - } - auto sublist = std::find_if(context->mSourceList.begin(), context->mSourceList.end(), - [](const SourceSubList &entry) noexcept -> bool - { return entry.FreeMask != 0; } - ); - auto lidx = static_cast(std::distance(context->mSourceList.begin(), sublist)); - ALsizei slidx; - if LIKELY(sublist != context->mSourceList.end()) - slidx = CTZ64(sublist->FreeMask); - else + if(!voice && source->state == AL_PLAYING) + source->state = AL_STOPPED; + return source->state; +} + +/** + * Returns if the source should specify an update, given the context's + * deferring state and the source's last known state. + */ +inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context) +{ + return !context->mDeferUpdates.load(std::memory_order_acquire) && + IsPlayingOrPaused(source); +} + + +bool EnsureSources(ALCcontext *context, size_t needed) +{ + size_t count{std::accumulate(context->mSourceList.cbegin(), context->mSourceList.cend(), + size_t{0}, + [](size_t cur, const SourceSubList &sublist) noexcept -> size_t + { return cur + static_cast(POPCNT64(~sublist.FreeMask)); } + )}; + + while(needed > count) { - /* Don't allocate so many list entries that the 32-bit ID could - * overflow... - */ if UNLIKELY(context->mSourceList.size() >= 1<<25) - { - context->setError(AL_OUT_OF_MEMORY, "Too many sources allocated"); - return nullptr; - } - context->mSourceList.emplace_back(); - sublist = context->mSourceList.end() - 1; + return false; + context->mSourceList.emplace_back(); + auto sublist = context->mSourceList.end() - 1; sublist->FreeMask = ~0_u64; - sublist->Sources = static_cast(al_calloc(16, sizeof(ALsource)*64)); + sublist->Sources = static_cast(al_calloc(alignof(ALsource), sizeof(ALsource)*64)); if UNLIKELY(!sublist->Sources) { context->mSourceList.pop_back(); - context->setError(AL_OUT_OF_MEMORY, "Failed to allocate source batch"); - return nullptr; + return false; } - - slidx = 0; + count += 64; } + return true; +} - ALsource *source{::new (sublist->Sources + slidx) ALsource{device->NumAuxSends}}; +ALsource *AllocSource(ALCcontext *context, ALsizei num_sends) +{ + auto sublist = std::find_if(context->mSourceList.begin(), context->mSourceList.end(), + [](const SourceSubList &entry) noexcept -> bool + { return entry.FreeMask != 0; } + ); + auto lidx = static_cast(std::distance(context->mSourceList.begin(), sublist)); + auto slidx = static_cast(CTZ64(sublist->FreeMask)); + + ALsource *source{::new (sublist->Sources + slidx) ALsource{num_sends}}; /* Add 1 to avoid source ID 0. */ source->id = ((lidx<<6) | slidx) + 1; @@ -520,26 +544,28 @@ ALsource *AllocSource(ALCcontext *context) void FreeSource(ALCcontext *context, ALsource *source) { - ALuint id = source->id - 1; - ALsizei lidx = id >> 6; - ALsizei slidx = id & 0x3f; + const ALuint id{source->id - 1}; + const size_t lidx{id >> 6}; + const ALuint slidx{id & 0x3f}; - ALCdevice *device{context->mDevice.get()}; - BackendUniqueLock backlock{*device->Backend}; - if(ALvoice *voice{GetSourceVoice(source, context)}) - { - voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed); - voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); - voice->mSourceID.store(0u, std::memory_order_relaxed); - std::atomic_thread_fence(std::memory_order_release); - /* Don't set the voice to stopping if it was already stopped or - * stopping. - */ - ALvoice::State oldvstate{ALvoice::Playing}; - voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping, - std::memory_order_acq_rel, std::memory_order_acquire); + if(IsPlayingOrPaused(source)) + { + ALCdevice *device{context->mDevice.get()}; + BackendLockGuard _{*device->Backend}; + if(ALvoice *voice{GetSourceVoice(source, context)}) + { + voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed); + voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed); + voice->mSourceID.store(0u, std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_release); + /* Don't set the voice to stopping if it was already stopped or + * stopping. + */ + ALvoice::State oldvstate{ALvoice::Playing}; + voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping, + std::memory_order_acq_rel, std::memory_order_acquire); + } } - backlock.unlock(); al::destroy_at(source); @@ -550,8 +576,8 @@ void FreeSource(ALCcontext *context, ALsource *source) inline ALsource *LookupSource(ALCcontext *context, ALuint id) noexcept { - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; + const size_t lidx{(id-1) >> 6}; + const ALuint slidx{(id-1) & 0x3f}; if UNLIKELY(lidx >= context->mSourceList.size()) return nullptr; @@ -563,8 +589,8 @@ inline ALsource *LookupSource(ALCcontext *context, ALuint id) noexcept inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) noexcept { - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; + const size_t lidx{(id-1) >> 6}; + const ALuint slidx{(id-1) & 0x3f}; if UNLIKELY(lidx >= device->BufferList.size()) return nullptr; @@ -576,8 +602,8 @@ inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) noexcept inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) noexcept { - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; + const size_t lidx{(id-1) >> 6}; + const ALuint slidx{(id-1) & 0x3f}; if UNLIKELY(lidx >= device->FilterList.size()) return nullptr; @@ -589,8 +615,8 @@ inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) noexcept inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) noexcept { - ALuint lidx = (id-1) >> 6; - ALsizei slidx = (id-1) & 0x3f; + const size_t lidx{(id-1) >> 6}; + const ALuint slidx{(id-1) & 0x3f}; if UNLIKELY(lidx >= context->mEffectSlotList.size()) return nullptr; @@ -669,34 +695,6 @@ enum SourceProp : ALenum { srcSecOffsetClockSOFT = AL_SEC_OFFSET_CLOCK_SOFT, }; -/** - * Returns if the last known state for the source was playing or paused. Does - * not sync with the mixer voice. - */ -inline bool IsPlayingOrPaused(ALsource *source) -{ return source->state == AL_PLAYING || source->state == AL_PAUSED; } - -/** - * Returns an updated source state using the matching voice's status (or lack - * thereof). - */ -inline ALenum GetSourceState(ALsource *source, ALvoice *voice) -{ - if(!voice && source->state == AL_PLAYING) - source->state = AL_STOPPED; - return source->state; -} - -/** - * Returns if the source should specify an update, given the context's - * deferring state and the source's last known state. - */ -inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context) -{ - return !context->mDeferUpdates.load(std::memory_order_acquire) && - IsPlayingOrPaused(source); -} - /** Can only be called while the mixer is locked! */ void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) @@ -712,7 +710,7 @@ void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) auto evt_vec = ring->getWriteVector(); if(evt_vec.first.len < 1) return; - AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_SourceStateChange}}; + AsyncEvent *evt{::new (evt_vec.first.buf) AsyncEvent{EventType_SourceStateChange}}; evt->u.srcstate.id = id; evt->u.srcstate.state = state; ring->writeAdvance(1); @@ -726,61 +724,61 @@ ALuint FloatValsByProp(ALenum prop) { switch(static_cast(prop)) { - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_REFERENCE_DISTANCE: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_SOURCE_RADIUS: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - return 1; - - case AL_STEREO_ANGLES: - return 2; - - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - return 3; - - case AL_ORIENTATION: - return 6; - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - - case AL_BUFFER: - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - break; /* i/i64 only */ - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; /* i64 only */ + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_SOURCE_RADIUS: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + return 1; + + case AL_STEREO_ANGLES: + return 2; + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + return 3; + + case AL_ORIENTATION: + return 6; + + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + break; /* Double only */ + + case AL_BUFFER: + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + break; /* i/i64 only */ + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; /* i64 only */ } return 0; } @@ -788,59 +786,59 @@ ALuint DoubleValsByProp(ALenum prop) { switch(static_cast(prop)) { - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_REFERENCE_DISTANCE: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_SOURCE_RADIUS: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - return 1; - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - case AL_STEREO_ANGLES: - return 2; - - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - return 3; - - case AL_ORIENTATION: - return 6; - - case AL_BUFFER: - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - break; /* i/i64 only */ - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; /* i64 only */ + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_SOURCE_RADIUS: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + return 1; + + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + case AL_STEREO_ANGLES: + return 2; + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + return 3; + + case AL_ORIENTATION: + return 6; + + case AL_BUFFER: + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + break; /* i/i64 only */ + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; /* i64 only */ } return 0; } @@ -879,222 +877,222 @@ bool SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a switch(prop) { - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - /* Query only */ - SETERR_RETURN(Context, AL_INVALID_OPERATION, false, - "Setting read-only source property 0x%04x", prop); + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + /* Query only */ + SETERR_RETURN(Context, AL_INVALID_OPERATION, false, + "Setting read-only source property 0x%04x", prop); - case AL_PITCH: - CHECKSIZE(values, 1); - CHECKVAL(values[0] >= 0.0f); + case AL_PITCH: + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f); - Source->Pitch = values[0]; - return UpdateSourceProps(Source, Context); + Source->Pitch = values[0]; + return UpdateSourceProps(Source, Context); - case AL_CONE_INNER_ANGLE: - CHECKSIZE(values, 1); - CHECKVAL(values[0] >= 0.0f && values[0] <= 360.0f); + case AL_CONE_INNER_ANGLE: + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f && values[0] <= 360.0f); - Source->InnerAngle = values[0]; - return UpdateSourceProps(Source, Context); + Source->InnerAngle = values[0]; + return UpdateSourceProps(Source, Context); - case AL_CONE_OUTER_ANGLE: - CHECKSIZE(values, 1); - CHECKVAL(values[0] >= 0.0f && values[0] <= 360.0f); + case AL_CONE_OUTER_ANGLE: + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f && values[0] <= 360.0f); - Source->OuterAngle = values[0]; - return UpdateSourceProps(Source, Context); + Source->OuterAngle = values[0]; + return UpdateSourceProps(Source, Context); - case AL_GAIN: - CHECKSIZE(values, 1); - CHECKVAL(values[0] >= 0.0f); + case AL_GAIN: + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f); - Source->Gain = values[0]; - return UpdateSourceProps(Source, Context); + Source->Gain = values[0]; + return UpdateSourceProps(Source, Context); - case AL_MAX_DISTANCE: - CHECKSIZE(values, 1); - CHECKVAL(values[0] >= 0.0f); + case AL_MAX_DISTANCE: + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f); - Source->MaxDistance = values[0]; - return UpdateSourceProps(Source, Context); + Source->MaxDistance = values[0]; + return UpdateSourceProps(Source, Context); - case AL_ROLLOFF_FACTOR: - CHECKSIZE(values, 1); - CHECKVAL(values[0] >= 0.0f); + case AL_ROLLOFF_FACTOR: + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f); - Source->RolloffFactor = values[0]; - return UpdateSourceProps(Source, Context); + Source->RolloffFactor = values[0]; + return UpdateSourceProps(Source, Context); - case AL_REFERENCE_DISTANCE: - CHECKSIZE(values, 1); - CHECKVAL(values[0] >= 0.0f); + case AL_REFERENCE_DISTANCE: + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f); - Source->RefDistance = values[0]; - return UpdateSourceProps(Source, Context); + Source->RefDistance = values[0]; + return UpdateSourceProps(Source, Context); - case AL_MIN_GAIN: - CHECKSIZE(values, 1); - CHECKVAL(values[0] >= 0.0f); + case AL_MIN_GAIN: + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f); - Source->MinGain = values[0]; - return UpdateSourceProps(Source, Context); + Source->MinGain = values[0]; + return UpdateSourceProps(Source, Context); - case AL_MAX_GAIN: - CHECKSIZE(values, 1); - CHECKVAL(values[0] >= 0.0f); + case AL_MAX_GAIN: + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f); - Source->MaxGain = values[0]; - return UpdateSourceProps(Source, Context); + Source->MaxGain = values[0]; + return UpdateSourceProps(Source, Context); - case AL_CONE_OUTER_GAIN: - CHECKSIZE(values, 1); - CHECKVAL(values[0] >= 0.0f && values[0] <= 1.0f); + case AL_CONE_OUTER_GAIN: + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f && values[0] <= 1.0f); - Source->OuterGain = values[0]; - return UpdateSourceProps(Source, Context); + Source->OuterGain = values[0]; + return UpdateSourceProps(Source, Context); - case AL_CONE_OUTER_GAINHF: - CHECKSIZE(values, 1); - CHECKVAL(values[0] >= 0.0f && values[0] <= 1.0f); + case AL_CONE_OUTER_GAINHF: + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f && values[0] <= 1.0f); - Source->OuterGainHF = values[0]; - return UpdateSourceProps(Source, Context); + Source->OuterGainHF = values[0]; + return UpdateSourceProps(Source, Context); - case AL_AIR_ABSORPTION_FACTOR: - CHECKSIZE(values, 1); - CHECKVAL(values[0] >= 0.0f && values[0] <= 10.0f); + case AL_AIR_ABSORPTION_FACTOR: + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f && values[0] <= 10.0f); - Source->AirAbsorptionFactor = values[0]; - return UpdateSourceProps(Source, Context); + Source->AirAbsorptionFactor = values[0]; + return UpdateSourceProps(Source, Context); - case AL_ROOM_ROLLOFF_FACTOR: - CHECKSIZE(values, 1); - CHECKVAL(values[0] >= 0.0f && values[0] <= 10.0f); + case AL_ROOM_ROLLOFF_FACTOR: + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f && values[0] <= 10.0f); - Source->RoomRolloffFactor = values[0]; - return UpdateSourceProps(Source, Context); + Source->RoomRolloffFactor = values[0]; + return UpdateSourceProps(Source, Context); - case AL_DOPPLER_FACTOR: - CHECKSIZE(values, 1); - CHECKVAL(values[0] >= 0.0f && values[0] <= 1.0f); + case AL_DOPPLER_FACTOR: + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f && values[0] <= 1.0f); - Source->DopplerFactor = values[0]; - return UpdateSourceProps(Source, Context); + Source->DopplerFactor = values[0]; + return UpdateSourceProps(Source, Context); - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - CHECKSIZE(values, 1); - CHECKVAL(values[0] >= 0.0f); + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f); - Source->OffsetType = prop; - Source->Offset = values[0]; + Source->OffsetType = prop; + Source->Offset = values[0]; - if(IsPlayingOrPaused(Source)) + if(IsPlayingOrPaused(Source)) + { + ALCdevice *device{Context->mDevice.get()}; + BackendLockGuard _{*device->Backend}; + /* Double-check that the source is still playing while we have the + * lock. + */ + if(ALvoice *voice{GetSourceVoice(Source, Context)}) { - ALCdevice *device{Context->mDevice.get()}; - BackendLockGuard _{*device->Backend}; - /* Double-check that the source is still playing while we have - * the lock. - */ - if(ALvoice *voice{GetSourceVoice(Source, Context)}) - { - auto vpos = GetSampleOffset(Source); - if(!vpos) SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid offset"); - - voice->mPosition.store(vpos->pos, std::memory_order_relaxed); - voice->mPositionFrac.store(vpos->frac, std::memory_order_relaxed); - voice->mCurrentBuffer.store(vpos->bufferitem, std::memory_order_release); - } - } - return true; + auto vpos = GetSampleOffset(Source); + if(!vpos) SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid offset"); - case AL_SOURCE_RADIUS: - CHECKSIZE(values, 1); - CHECKVAL(values[0] >= 0.0f && std::isfinite(values[0])); - - Source->Radius = values[0]; - return UpdateSourceProps(Source, Context); - - case AL_STEREO_ANGLES: - CHECKSIZE(values, 2); - CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1])); - - Source->StereoPan[0] = values[0]; - Source->StereoPan[1] = values[1]; - return UpdateSourceProps(Source, Context); - - - case AL_POSITION: - CHECKSIZE(values, 3); - CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); - - Source->Position[0] = values[0]; - Source->Position[1] = values[1]; - Source->Position[2] = values[2]; - return UpdateSourceProps(Source, Context); - - case AL_VELOCITY: - CHECKSIZE(values, 3); - CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); - - Source->Velocity[0] = values[0]; - Source->Velocity[1] = values[1]; - Source->Velocity[2] = values[2]; - return UpdateSourceProps(Source, Context); - - case AL_DIRECTION: - CHECKSIZE(values, 3); - CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); - - Source->Direction[0] = values[0]; - Source->Direction[1] = values[1]; - Source->Direction[2] = values[2]; - return UpdateSourceProps(Source, Context); - - case AL_ORIENTATION: - CHECKSIZE(values, 6); - CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) && - std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5])); - - Source->OrientAt[0] = values[0]; - Source->OrientAt[1] = values[1]; - Source->OrientAt[2] = values[2]; - Source->OrientUp[0] = values[3]; - Source->OrientUp[1] = values[4]; - Source->OrientUp[2] = values[5]; - return UpdateSourceProps(Source, Context); - - - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_SOURCE_TYPE: - case AL_DISTANCE_MODEL: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - CHECKSIZE(values, 1); - ival = static_cast(values[0]); - return SetSourceiv(Source, Context, prop, {&ival, 1u}); - - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - CHECKSIZE(values, 1); - ival = static_cast(static_cast(values[0])); - return SetSourceiv(Source, Context, prop, {&ival, 1u}); - - case AL_BUFFER: - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; + voice->mPosition.store(vpos->pos, std::memory_order_relaxed); + voice->mPositionFrac.store(vpos->frac, std::memory_order_relaxed); + voice->mCurrentBuffer.store(vpos->bufferitem, std::memory_order_release); + } + } + return true; + + case AL_SOURCE_RADIUS: + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0.0f && std::isfinite(values[0])); + + Source->Radius = values[0]; + return UpdateSourceProps(Source, Context); + + case AL_STEREO_ANGLES: + CHECKSIZE(values, 2); + CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1])); + + Source->StereoPan[0] = values[0]; + Source->StereoPan[1] = values[1]; + return UpdateSourceProps(Source, Context); + + + case AL_POSITION: + CHECKSIZE(values, 3); + CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); + + Source->Position[0] = values[0]; + Source->Position[1] = values[1]; + Source->Position[2] = values[2]; + return UpdateSourceProps(Source, Context); + + case AL_VELOCITY: + CHECKSIZE(values, 3); + CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); + + Source->Velocity[0] = values[0]; + Source->Velocity[1] = values[1]; + Source->Velocity[2] = values[2]; + return UpdateSourceProps(Source, Context); + + case AL_DIRECTION: + CHECKSIZE(values, 3); + CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2])); + + Source->Direction[0] = values[0]; + Source->Direction[1] = values[1]; + Source->Direction[2] = values[2]; + return UpdateSourceProps(Source, Context); + + case AL_ORIENTATION: + CHECKSIZE(values, 6); + CHECKVAL(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) + && std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5])); + + Source->OrientAt[0] = values[0]; + Source->OrientAt[1] = values[1]; + Source->OrientAt[2] = values[2]; + Source->OrientUp[0] = values[3]; + Source->OrientUp[1] = values[4]; + Source->OrientUp[2] = values[5]; + return UpdateSourceProps(Source, Context); + + + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_SOURCE_TYPE: + case AL_DISTANCE_MODEL: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + CHECKSIZE(values, 1); + ival = static_cast(values[0]); + return SetSourceiv(Source, Context, prop, {&ival, 1u}); + + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + CHECKSIZE(values, 1); + ival = static_cast(static_cast(values[0])); + return SetSourceiv(Source, Context, prop, {&ival, 1u}); + + case AL_BUFFER: + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; } ERR("Unexpected property: 0x%04x\n", prop); @@ -1116,304 +1114,308 @@ bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a switch(prop) { - case AL_SOURCE_STATE: - case AL_SOURCE_TYPE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - /* Query only */ - SETERR_RETURN(Context, AL_INVALID_OPERATION, false, - "Setting read-only source property 0x%04x", prop); - - case AL_SOURCE_RELATIVE: - CHECKSIZE(values, 1); - CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); - - Source->HeadRelative = static_cast(values[0]); - return UpdateSourceProps(Source, Context); - - case AL_LOOPING: - CHECKSIZE(values, 1); - CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); - - Source->Looping = static_cast(values[0]); - if(IsPlayingOrPaused(Source)) + case AL_SOURCE_STATE: + case AL_SOURCE_TYPE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + /* Query only */ + SETERR_RETURN(Context, AL_INVALID_OPERATION, false, + "Setting read-only source property 0x%04x", prop); + + case AL_SOURCE_RELATIVE: + CHECKSIZE(values, 1); + CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); + + Source->HeadRelative = static_cast(values[0]); + return UpdateSourceProps(Source, Context); + + case AL_LOOPING: + CHECKSIZE(values, 1); + CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); + + Source->Looping = static_cast(values[0]); + if(IsPlayingOrPaused(Source)) + { + if(ALvoice *voice{GetSourceVoice(Source, Context)}) { - if(ALvoice *voice{GetSourceVoice(Source, Context)}) - { - if(Source->Looping) - voice->mLoopBuffer.store(Source->queue, std::memory_order_release); - else - voice->mLoopBuffer.store(nullptr, std::memory_order_release); - - /* If the source is playing, wait for the current mix to finish - * to ensure it isn't currently looping back or reaching the - * end. - */ - while((device->MixCount.load(std::memory_order_acquire)&1)) - std::this_thread::yield(); - } + if(Source->Looping) + voice->mLoopBuffer.store(Source->queue, std::memory_order_release); + else + voice->mLoopBuffer.store(nullptr, std::memory_order_release); + + /* If the source is playing, wait for the current mix to finish + * to ensure it isn't currently looping back or reaching the + * end. + */ + while((device->MixCount.load(std::memory_order_acquire)&1)) + std::this_thread::yield(); } - return true; + } + return true; - case AL_BUFFER: - CHECKSIZE(values, 1); - buflock = std::unique_lock{device->BufferLock}; - if(!(values[0] == 0 || (buffer=LookupBuffer(device, values[0])) != nullptr)) - SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid buffer ID %u", values[0]); + case AL_BUFFER: + CHECKSIZE(values, 1); + buflock = std::unique_lock{device->BufferLock}; + if(values[0] && (buffer=LookupBuffer(device, static_cast(values[0]))) == nullptr) + SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid buffer ID %u", + static_cast(values[0])); - if(buffer && buffer->MappedAccess != 0 && - !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) + if(buffer && buffer->MappedAccess != 0 && + !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) + SETERR_RETURN(Context, AL_INVALID_OPERATION, false, + "Setting non-persistently mapped buffer %u", buffer->id); + else + { + ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context)); + if(state == AL_PLAYING || state == AL_PAUSED) SETERR_RETURN(Context, AL_INVALID_OPERATION, false, - "Setting non-persistently mapped buffer %u", buffer->id); - else - { - ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context)); - if(state == AL_PLAYING || state == AL_PAUSED) - SETERR_RETURN(Context, AL_INVALID_OPERATION, false, - "Setting buffer on playing or paused source %u", Source->id); - } + "Setting buffer on playing or paused source %u", Source->id); + } - oldlist = Source->queue; - if(buffer != nullptr) - { - /* Add the selected buffer to a one-item queue */ - auto newlist = new ALbufferlistitem{}; - newlist->mSampleLen = buffer->SampleLen; - newlist->mBuffer = buffer; - IncrementRef(buffer->ref); - - /* Source is now Static */ - Source->SourceType = AL_STATIC; - Source->queue = newlist; - } - else - { - /* Source is now Undetermined */ - Source->SourceType = AL_UNDETERMINED; - Source->queue = nullptr; - } - buflock.unlock(); + oldlist = Source->queue; + if(buffer != nullptr) + { + /* Add the selected buffer to a one-item queue */ + auto newlist = new ALbufferlistitem{}; + newlist->mSampleLen = buffer->SampleLen; + newlist->mBuffer = buffer; + IncrementRef(buffer->ref); + + /* Source is now Static */ + Source->SourceType = AL_STATIC; + Source->queue = newlist; + } + else + { + /* Source is now Undetermined */ + Source->SourceType = AL_UNDETERMINED; + Source->queue = nullptr; + } + buflock.unlock(); - /* Delete all elements in the previous queue */ - while(oldlist != nullptr) - { - std::unique_ptr temp{oldlist}; - oldlist = temp->mNext.load(std::memory_order_relaxed); + /* Delete all elements in the previous queue */ + while(oldlist != nullptr) + { + std::unique_ptr temp{oldlist}; + oldlist = temp->mNext.load(std::memory_order_relaxed); - if(ALbuffer *buffer{temp->mBuffer}) - DecrementRef(buffer->ref); - } - return true; + if(ALbuffer *buffer{temp->mBuffer}) + DecrementRef(buffer->ref); + } + return true; - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - CHECKSIZE(values, 1); - CHECKVAL(values[0] >= 0); + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0); - Source->OffsetType = prop; - Source->Offset = values[0]; + Source->OffsetType = prop; + Source->Offset = values[0]; - if(IsPlayingOrPaused(Source)) + if(IsPlayingOrPaused(Source)) + { + ALCdevice *device{Context->mDevice.get()}; + BackendLockGuard _{*device->Backend}; + if(ALvoice *voice{GetSourceVoice(Source, Context)}) { - ALCdevice *device{Context->mDevice.get()}; - BackendLockGuard _{*device->Backend}; - if(ALvoice *voice{GetSourceVoice(Source, Context)}) - { - auto vpos = GetSampleOffset(Source); - if(!vpos) SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid source offset"); - - voice->mPosition.store(vpos->pos, std::memory_order_relaxed); - voice->mPositionFrac.store(vpos->frac, std::memory_order_relaxed); - voice->mCurrentBuffer.store(vpos->bufferitem, std::memory_order_release); - } - } - return true; - - case AL_DIRECT_FILTER: - CHECKSIZE(values, 1); - filtlock = std::unique_lock{device->FilterLock}; - if(!(values[0] == 0 || (filter=LookupFilter(device, values[0])) != nullptr)) - SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid filter ID %u", values[0]); + auto vpos = GetSampleOffset(Source); + if(!vpos) SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid source offset"); - if(!filter) - { - Source->Direct.Gain = 1.0f; - Source->Direct.GainHF = 1.0f; - Source->Direct.HFReference = LOWPASSFREQREF; - Source->Direct.GainLF = 1.0f; - Source->Direct.LFReference = HIGHPASSFREQREF; + voice->mPosition.store(vpos->pos, std::memory_order_relaxed); + voice->mPositionFrac.store(vpos->frac, std::memory_order_relaxed); + voice->mCurrentBuffer.store(vpos->bufferitem, std::memory_order_release); } - else - { - Source->Direct.Gain = filter->Gain; - Source->Direct.GainHF = filter->GainHF; - Source->Direct.HFReference = filter->HFReference; - Source->Direct.GainLF = filter->GainLF; - Source->Direct.LFReference = filter->LFReference; - } - filtlock.unlock(); - return UpdateSourceProps(Source, Context); + } + return true; - case AL_DIRECT_FILTER_GAINHF_AUTO: - CHECKSIZE(values, 1); - CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); + case AL_DIRECT_FILTER: + CHECKSIZE(values, 1); + filtlock = std::unique_lock{device->FilterLock}; + if(values[0] && (filter=LookupFilter(device, static_cast(values[0]))) == nullptr) + SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid filter ID %u", + static_cast(values[0])); - Source->DryGainHFAuto = values[0]; - return UpdateSourceProps(Source, Context); + if(!filter) + { + Source->Direct.Gain = 1.0f; + Source->Direct.GainHF = 1.0f; + Source->Direct.HFReference = LOWPASSFREQREF; + Source->Direct.GainLF = 1.0f; + Source->Direct.LFReference = HIGHPASSFREQREF; + } + else + { + Source->Direct.Gain = filter->Gain; + Source->Direct.GainHF = filter->GainHF; + Source->Direct.HFReference = filter->HFReference; + Source->Direct.GainLF = filter->GainLF; + Source->Direct.LFReference = filter->LFReference; + } + filtlock.unlock(); + return UpdateSourceProps(Source, Context); - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - CHECKSIZE(values, 1); - CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); + case AL_DIRECT_FILTER_GAINHF_AUTO: + CHECKSIZE(values, 1); + CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); - Source->WetGainAuto = values[0]; - return UpdateSourceProps(Source, Context); + Source->DryGainHFAuto = values[0]; + return UpdateSourceProps(Source, Context); - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - CHECKSIZE(values, 1); - CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + CHECKSIZE(values, 1); + CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); - Source->WetGainHFAuto = values[0]; - return UpdateSourceProps(Source, Context); + Source->WetGainAuto = values[0]; + return UpdateSourceProps(Source, Context); - case AL_DIRECT_CHANNELS_SOFT: - CHECKSIZE(values, 1); - CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + CHECKSIZE(values, 1); + CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); - Source->DirectChannels = values[0]; - return UpdateSourceProps(Source, Context); + Source->WetGainHFAuto = values[0]; + return UpdateSourceProps(Source, Context); - case AL_DISTANCE_MODEL: - CHECKSIZE(values, 1); - CHECKVAL(values[0] == AL_NONE || - values[0] == AL_INVERSE_DISTANCE || values[0] == AL_INVERSE_DISTANCE_CLAMPED || - values[0] == AL_LINEAR_DISTANCE || values[0] == AL_LINEAR_DISTANCE_CLAMPED || - values[0] == AL_EXPONENT_DISTANCE || values[0] == AL_EXPONENT_DISTANCE_CLAMPED); + case AL_DIRECT_CHANNELS_SOFT: + CHECKSIZE(values, 1); + CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); - Source->mDistanceModel = static_cast(values[0]); - if(Context->mSourceDistanceModel) - return UpdateSourceProps(Source, Context); - return true; + Source->DirectChannels = values[0]; + return UpdateSourceProps(Source, Context); - case AL_SOURCE_RESAMPLER_SOFT: - CHECKSIZE(values, 1); - CHECKVAL(values[0] >= 0 && values[0] <= ResamplerMax); + case AL_DISTANCE_MODEL: + CHECKSIZE(values, 1); + CHECKVAL(values[0] == AL_NONE || + values[0] == AL_INVERSE_DISTANCE || values[0] == AL_INVERSE_DISTANCE_CLAMPED || + values[0] == AL_LINEAR_DISTANCE || values[0] == AL_LINEAR_DISTANCE_CLAMPED || + values[0] == AL_EXPONENT_DISTANCE || values[0] == AL_EXPONENT_DISTANCE_CLAMPED); - Source->mResampler = static_cast(values[0]); + Source->mDistanceModel = static_cast(values[0]); + if(Context->mSourceDistanceModel) return UpdateSourceProps(Source, Context); + return true; - case AL_SOURCE_SPATIALIZE_SOFT: - CHECKSIZE(values, 1); - CHECKVAL(values[0] >= AL_FALSE && values[0] <= AL_AUTO_SOFT); + case AL_SOURCE_RESAMPLER_SOFT: + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= 0 && values[0] <= ResamplerMax); - Source->mSpatialize = static_cast(values[0]); - return UpdateSourceProps(Source, Context); + Source->mResampler = static_cast(values[0]); + return UpdateSourceProps(Source, Context); + case AL_SOURCE_SPATIALIZE_SOFT: + CHECKSIZE(values, 1); + CHECKVAL(values[0] >= AL_FALSE && values[0] <= AL_AUTO_SOFT); - case AL_AUXILIARY_SEND_FILTER: - CHECKSIZE(values, 3); - slotlock = std::unique_lock{Context->mEffectSlotLock}; - if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != nullptr)) - SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid effect ID %u", values[0]); - if(static_cast(values[1]) >= static_cast(device->NumAuxSends)) - SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid send %u", values[1]); + Source->mSpatialize = static_cast(values[0]); + return UpdateSourceProps(Source, Context); - filtlock = std::unique_lock{device->FilterLock}; - if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != nullptr)) - SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid filter ID %u", values[2]); - if(!filter) - { - /* Disable filter */ - Source->Send[values[1]].Gain = 1.0f; - Source->Send[values[1]].GainHF = 1.0f; - Source->Send[values[1]].HFReference = LOWPASSFREQREF; - Source->Send[values[1]].GainLF = 1.0f; - Source->Send[values[1]].LFReference = HIGHPASSFREQREF; - } - else - { - Source->Send[values[1]].Gain = filter->Gain; - Source->Send[values[1]].GainHF = filter->GainHF; - Source->Send[values[1]].HFReference = filter->HFReference; - Source->Send[values[1]].GainLF = filter->GainLF; - Source->Send[values[1]].LFReference = filter->LFReference; - } - filtlock.unlock(); + case AL_AUXILIARY_SEND_FILTER: + CHECKSIZE(values, 3); + slotlock = std::unique_lock{Context->mEffectSlotLock}; + if(values[0] && (slot=LookupEffectSlot(Context, static_cast(values[0]))) == nullptr) + SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid effect ID %u", values[0]); + if(static_cast(values[1]) >= static_cast(device->NumAuxSends)) + SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid send %u", values[1]); - if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source)) - { - /* Add refcount on the new slot, and release the previous slot */ - if(slot) IncrementRef(slot->ref); - if(Source->Send[values[1]].Slot) - DecrementRef(Source->Send[values[1]].Slot->ref); - Source->Send[values[1]].Slot = slot; - - /* We must force an update if the auxiliary slot changed on an - * active source, in case the slot is about to be deleted. - */ - ALvoice *voice{GetSourceVoice(Source, Context)}; - if(voice) UpdateSourceProps(Source, voice, Context); - else Source->PropsClean.clear(std::memory_order_release); - } - else - { - if(slot) IncrementRef(slot->ref); - if(Source->Send[values[1]].Slot) - DecrementRef(Source->Send[values[1]].Slot->ref); - Source->Send[values[1]].Slot = slot; - UpdateSourceProps(Source, Context); - } - return true; - - - /* 1x float */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_SOURCE_RADIUS: - CHECKSIZE(values, 1); - fvals[0] = static_cast(values[0]); - return SetSourcefv(Source, Context, prop, {fvals, 1u}); - - /* 3x float */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - CHECKSIZE(values, 3); - fvals[0] = static_cast(values[0]); - fvals[1] = static_cast(values[1]); - fvals[2] = static_cast(values[2]); - return SetSourcefv(Source, Context, prop, {fvals, 3u}); - - /* 6x float */ - case AL_ORIENTATION: - CHECKSIZE(values, 6); - fvals[0] = static_cast(values[0]); - fvals[1] = static_cast(values[1]); - fvals[2] = static_cast(values[2]); - fvals[3] = static_cast(values[3]); - fvals[4] = static_cast(values[4]); - fvals[5] = static_cast(values[5]); - return SetSourcefv(Source, Context, prop, {fvals, 6u}); - - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - case AL_STEREO_ANGLES: - break; + filtlock = std::unique_lock{device->FilterLock}; + if(values[2] && (filter=LookupFilter(device, static_cast(values[2]))) == nullptr) + SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid filter ID %u", values[2]); + + if(!filter) + { + /* Disable filter */ + auto &send = Source->Send[static_cast(values[1])]; + send.Gain = 1.0f; + send.GainHF = 1.0f; + send.HFReference = LOWPASSFREQREF; + send.GainLF = 1.0f; + send.LFReference = HIGHPASSFREQREF; + } + else + { + auto &send = Source->Send[static_cast(values[1])]; + send.Gain = filter->Gain; + send.GainHF = filter->GainHF; + send.HFReference = filter->HFReference; + send.GainLF = filter->GainLF; + send.LFReference = filter->LFReference; + } + filtlock.unlock(); + + if(slot != Source->Send[static_cast(values[1])].Slot && IsPlayingOrPaused(Source)) + { + /* Add refcount on the new slot, and release the previous slot */ + if(slot) IncrementRef(slot->ref); + if(auto *slot = Source->Send[static_cast(values[1])].Slot) + DecrementRef(slot->ref); + Source->Send[static_cast(values[1])].Slot = slot; + + /* We must force an update if the auxiliary slot changed on an + * active source, in case the slot is about to be deleted. + */ + ALvoice *voice{GetSourceVoice(Source, Context)}; + if(voice) UpdateSourceProps(Source, voice, Context); + else Source->PropsClean.clear(std::memory_order_release); + } + else + { + if(slot) IncrementRef(slot->ref); + if(auto *slot = Source->Send[static_cast(values[1])].Slot) + DecrementRef(slot->ref); + Source->Send[static_cast(values[1])].Slot = slot; + UpdateSourceProps(Source, Context); + } + return true; + + + /* 1x float */ + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_REFERENCE_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_SOURCE_RADIUS: + CHECKSIZE(values, 1); + fvals[0] = static_cast(values[0]); + return SetSourcefv(Source, Context, prop, {fvals, 1u}); + + /* 3x float */ + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + CHECKSIZE(values, 3); + fvals[0] = static_cast(values[0]); + fvals[1] = static_cast(values[1]); + fvals[2] = static_cast(values[2]); + return SetSourcefv(Source, Context, prop, {fvals, 3u}); + + /* 6x float */ + case AL_ORIENTATION: + CHECKSIZE(values, 6); + fvals[0] = static_cast(values[0]); + fvals[1] = static_cast(values[1]); + fvals[2] = static_cast(values[2]); + fvals[3] = static_cast(values[3]); + fvals[4] = static_cast(values[4]); + fvals[5] = static_cast(values[5]); + return SetSourcefv(Source, Context, prop, {fvals, 6u}); + + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + case AL_STEREO_ANGLES: + break; } ERR("Unexpected property: 0x%04x\n", prop); @@ -1428,101 +1430,100 @@ bool SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const switch(prop) { - case AL_SOURCE_TYPE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_STATE: - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - /* Query only */ - SETERR_RETURN(Context, AL_INVALID_OPERATION, false, - "Setting read-only source property 0x%04x", prop); - - /* 1x int */ - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - CHECKSIZE(values, 1); - CHECKVAL(values[0] <= INT_MAX && values[0] >= INT_MIN); - - ivals[0] = static_cast(values[0]); - return SetSourceiv(Source, Context, prop, {ivals, 1u}); - - /* 1x uint */ - case AL_BUFFER: - case AL_DIRECT_FILTER: - CHECKSIZE(values, 1); - CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0); - - ivals[0] = static_cast(values[0]); - return SetSourceiv(Source, Context, prop, {ivals, 1u}); - - /* 3x uint */ - case AL_AUXILIARY_SEND_FILTER: - CHECKSIZE(values, 3); - CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 && - values[1] <= UINT_MAX && values[1] >= 0 && - values[2] <= UINT_MAX && values[2] >= 0); - - ivals[0] = static_cast(values[0]); - ivals[1] = static_cast(values[1]); - ivals[2] = static_cast(values[2]); - return SetSourceiv(Source, Context, prop, {ivals, 3u}); - - /* 1x float */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_DOPPLER_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_SOURCE_RADIUS: - CHECKSIZE(values, 1); - fvals[0] = static_cast(values[0]); - return SetSourcefv(Source, Context, prop, {fvals, 1u}); - - /* 3x float */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - CHECKSIZE(values, 3); - fvals[0] = static_cast(values[0]); - fvals[1] = static_cast(values[1]); - fvals[2] = static_cast(values[2]); - return SetSourcefv(Source, Context, prop, {fvals, 3u}); - - /* 6x float */ - case AL_ORIENTATION: - CHECKSIZE(values, 6); - fvals[0] = static_cast(values[0]); - fvals[1] = static_cast(values[1]); - fvals[2] = static_cast(values[2]); - fvals[3] = static_cast(values[3]); - fvals[4] = static_cast(values[4]); - fvals[5] = static_cast(values[5]); - return SetSourcefv(Source, Context, prop, {fvals, 6u}); - - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - case AL_STEREO_ANGLES: - break; + case AL_SOURCE_TYPE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_STATE: + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + /* Query only */ + SETERR_RETURN(Context, AL_INVALID_OPERATION, false, + "Setting read-only source property 0x%04x", prop); + + /* 1x int */ + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + CHECKSIZE(values, 1); + CHECKVAL(values[0] <= INT_MAX && values[0] >= INT_MIN); + + ivals[0] = static_cast(values[0]); + return SetSourceiv(Source, Context, prop, {ivals, 1u}); + + /* 1x uint */ + case AL_BUFFER: + case AL_DIRECT_FILTER: + CHECKSIZE(values, 1); + CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0); + + ivals[0] = static_cast(values[0]); + return SetSourceiv(Source, Context, prop, {ivals, 1u}); + + /* 3x uint */ + case AL_AUXILIARY_SEND_FILTER: + CHECKSIZE(values, 3); + CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 && values[1] <= UINT_MAX && values[1] >= 0 + && values[2] <= UINT_MAX && values[2] >= 0); + + ivals[0] = static_cast(values[0]); + ivals[1] = static_cast(values[1]); + ivals[2] = static_cast(values[2]); + return SetSourceiv(Source, Context, prop, {ivals, 3u}); + + /* 1x float */ + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_REFERENCE_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_SOURCE_RADIUS: + CHECKSIZE(values, 1); + fvals[0] = static_cast(values[0]); + return SetSourcefv(Source, Context, prop, {fvals, 1u}); + + /* 3x float */ + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + CHECKSIZE(values, 3); + fvals[0] = static_cast(values[0]); + fvals[1] = static_cast(values[1]); + fvals[2] = static_cast(values[2]); + return SetSourcefv(Source, Context, prop, {fvals, 3u}); + + /* 6x float */ + case AL_ORIENTATION: + CHECKSIZE(values, 6); + fvals[0] = static_cast(values[0]); + fvals[1] = static_cast(values[1]); + fvals[2] = static_cast(values[2]); + fvals[3] = static_cast(values[3]); + fvals[4] = static_cast(values[4]); + fvals[5] = static_cast(values[5]); + return SetSourcefv(Source, Context, prop, {fvals, 6u}); + + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + case AL_STEREO_ANGLES: + break; } ERR("Unexpected property: 0x%04x\n", prop); @@ -1541,185 +1542,185 @@ bool GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a { ALCdevice *device{Context->mDevice.get()}; ClockLatency clocktime; - std::chrono::nanoseconds srcclock; + nanoseconds srcclock; ALint ivals[MaxValues]; bool err; switch(prop) { - case AL_GAIN: - CHECKSIZE(values, 1); - values[0] = Source->Gain; - return true; - - case AL_PITCH: - CHECKSIZE(values, 1); - values[0] = Source->Pitch; - return true; - - case AL_MAX_DISTANCE: - CHECKSIZE(values, 1); - values[0] = Source->MaxDistance; - return true; - - case AL_ROLLOFF_FACTOR: - CHECKSIZE(values, 1); - values[0] = Source->RolloffFactor; - return true; - - case AL_REFERENCE_DISTANCE: - CHECKSIZE(values, 1); - values[0] = Source->RefDistance; - return true; - - case AL_CONE_INNER_ANGLE: - CHECKSIZE(values, 1); - values[0] = Source->InnerAngle; - return true; - - case AL_CONE_OUTER_ANGLE: - CHECKSIZE(values, 1); - values[0] = Source->OuterAngle; - return true; - - case AL_MIN_GAIN: - CHECKSIZE(values, 1); - values[0] = Source->MinGain; - return true; - - case AL_MAX_GAIN: - CHECKSIZE(values, 1); - values[0] = Source->MaxGain; - return true; - - case AL_CONE_OUTER_GAIN: - CHECKSIZE(values, 1); - values[0] = Source->OuterGain; - return true; - - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - CHECKSIZE(values, 1); - values[0] = GetSourceOffset(Source, prop, Context); - return true; - - case AL_CONE_OUTER_GAINHF: - CHECKSIZE(values, 1); - values[0] = Source->OuterGainHF; - return true; - - case AL_AIR_ABSORPTION_FACTOR: - CHECKSIZE(values, 1); - values[0] = Source->AirAbsorptionFactor; - return true; - - case AL_ROOM_ROLLOFF_FACTOR: - CHECKSIZE(values, 1); - values[0] = Source->RoomRolloffFactor; - return true; - - case AL_DOPPLER_FACTOR: - CHECKSIZE(values, 1); - values[0] = Source->DopplerFactor; - return true; - - case AL_SOURCE_RADIUS: - CHECKSIZE(values, 1); - values[0] = Source->Radius; - return true; - - case AL_STEREO_ANGLES: - CHECKSIZE(values, 2); - values[0] = Source->StereoPan[0]; - values[1] = Source->StereoPan[1]; - return true; - - case AL_SEC_OFFSET_LATENCY_SOFT: - CHECKSIZE(values, 2); - /* Get the source offset with the clock time first. Then get the - * clock time with the device latency. Order is important. + case AL_GAIN: + CHECKSIZE(values, 1); + values[0] = Source->Gain; + return true; + + case AL_PITCH: + CHECKSIZE(values, 1); + values[0] = Source->Pitch; + return true; + + case AL_MAX_DISTANCE: + CHECKSIZE(values, 1); + values[0] = Source->MaxDistance; + return true; + + case AL_ROLLOFF_FACTOR: + CHECKSIZE(values, 1); + values[0] = Source->RolloffFactor; + return true; + + case AL_REFERENCE_DISTANCE: + CHECKSIZE(values, 1); + values[0] = Source->RefDistance; + return true; + + case AL_CONE_INNER_ANGLE: + CHECKSIZE(values, 1); + values[0] = Source->InnerAngle; + return true; + + case AL_CONE_OUTER_ANGLE: + CHECKSIZE(values, 1); + values[0] = Source->OuterAngle; + return true; + + case AL_MIN_GAIN: + CHECKSIZE(values, 1); + values[0] = Source->MinGain; + return true; + + case AL_MAX_GAIN: + CHECKSIZE(values, 1); + values[0] = Source->MaxGain; + return true; + + case AL_CONE_OUTER_GAIN: + CHECKSIZE(values, 1); + values[0] = Source->OuterGain; + return true; + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + CHECKSIZE(values, 1); + values[0] = GetSourceOffset(Source, prop, Context); + return true; + + case AL_CONE_OUTER_GAINHF: + CHECKSIZE(values, 1); + values[0] = Source->OuterGainHF; + return true; + + case AL_AIR_ABSORPTION_FACTOR: + CHECKSIZE(values, 1); + values[0] = Source->AirAbsorptionFactor; + return true; + + case AL_ROOM_ROLLOFF_FACTOR: + CHECKSIZE(values, 1); + values[0] = Source->RoomRolloffFactor; + return true; + + case AL_DOPPLER_FACTOR: + CHECKSIZE(values, 1); + values[0] = Source->DopplerFactor; + return true; + + case AL_SOURCE_RADIUS: + CHECKSIZE(values, 1); + values[0] = Source->Radius; + return true; + + case AL_STEREO_ANGLES: + CHECKSIZE(values, 2); + values[0] = Source->StereoPan[0]; + values[1] = Source->StereoPan[1]; + return true; + + case AL_SEC_OFFSET_LATENCY_SOFT: + CHECKSIZE(values, 2); + /* Get the source offset with the clock time first. Then get the clock + * time with the device latency. Order is important. + */ + values[0] = GetSourceSecOffset(Source, Context, &srcclock); + { + std::lock_guard _{device->StateLock}; + clocktime = GetClockLatency(device); + } + if(srcclock == clocktime.ClockTime) + values[1] = static_cast(clocktime.Latency.count()) / 1000000000.0; + else + { + /* If the clock time incremented, reduce the latency by that much + * since it's that much closer to the source offset it got earlier. */ - values[0] = GetSourceSecOffset(Source, Context, &srcclock); - { std::lock_guard _{device->StateLock}; - clocktime = GetClockLatency(device); - } - if(srcclock == clocktime.ClockTime) - values[1] = static_cast(clocktime.Latency.count()) / 1000000000.0; - else - { - /* If the clock time incremented, reduce the latency by that - * much since it's that much closer to the source offset it got - * earlier. - */ - std::chrono::nanoseconds diff = clocktime.ClockTime - srcclock; - values[1] = static_cast((clocktime.Latency - std::min(clocktime.Latency, diff)).count()) / - 1000000000.0; - } - return true; - - case AL_SEC_OFFSET_CLOCK_SOFT: - CHECKSIZE(values, 2); - values[0] = GetSourceSecOffset(Source, Context, &srcclock); - values[1] = srcclock.count() / 1000000000.0; - return true; - - case AL_POSITION: - CHECKSIZE(values, 3); - values[0] = Source->Position[0]; - values[1] = Source->Position[1]; - values[2] = Source->Position[2]; - return true; - - case AL_VELOCITY: - CHECKSIZE(values, 3); - values[0] = Source->Velocity[0]; - values[1] = Source->Velocity[1]; - values[2] = Source->Velocity[2]; - return true; - - case AL_DIRECTION: - CHECKSIZE(values, 3); - values[0] = Source->Direction[0]; - values[1] = Source->Direction[1]; - values[2] = Source->Direction[2]; - return true; - - case AL_ORIENTATION: - CHECKSIZE(values, 6); - values[0] = Source->OrientAt[0]; - values[1] = Source->OrientAt[1]; - values[2] = Source->OrientAt[2]; - values[3] = Source->OrientUp[0]; - values[4] = Source->OrientUp[1]; - values[5] = Source->OrientUp[2]; - return true; - - /* 1x int */ - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - CHECKSIZE(values, 1); - if((err=GetSourceiv(Source, Context, prop, {ivals, 1u})) != false) - values[0] = static_cast(ivals[0]); - return err; - - case AL_BUFFER: - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; + const nanoseconds diff{clocktime.ClockTime - srcclock}; + const nanoseconds latency{clocktime.Latency - std::min(clocktime.Latency, diff)}; + values[1] = static_cast(latency.count()) / 1000000000.0; + } + return true; + + case AL_SEC_OFFSET_CLOCK_SOFT: + CHECKSIZE(values, 2); + values[0] = GetSourceSecOffset(Source, Context, &srcclock); + values[1] = srcclock.count() / 1000000000.0; + return true; + + case AL_POSITION: + CHECKSIZE(values, 3); + values[0] = Source->Position[0]; + values[1] = Source->Position[1]; + values[2] = Source->Position[2]; + return true; + + case AL_VELOCITY: + CHECKSIZE(values, 3); + values[0] = Source->Velocity[0]; + values[1] = Source->Velocity[1]; + values[2] = Source->Velocity[2]; + return true; + + case AL_DIRECTION: + CHECKSIZE(values, 3); + values[0] = Source->Direction[0]; + values[1] = Source->Direction[1]; + values[2] = Source->Direction[2]; + return true; + + case AL_ORIENTATION: + CHECKSIZE(values, 6); + values[0] = Source->OrientAt[0]; + values[1] = Source->OrientAt[1]; + values[2] = Source->OrientAt[2]; + values[3] = Source->OrientUp[0]; + values[4] = Source->OrientUp[1]; + values[5] = Source->OrientUp[2]; + return true; + + /* 1x int */ + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + CHECKSIZE(values, 1); + if((err=GetSourceiv(Source, Context, prop, {ivals, 1u})) != false) + values[0] = static_cast(ivals[0]); + return err; + + case AL_BUFFER: + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; } ERR("Unexpected property: 0x%04x\n", prop); @@ -1735,174 +1736,176 @@ bool GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a switch(prop) { - case AL_SOURCE_RELATIVE: - CHECKSIZE(values, 1); - values[0] = Source->HeadRelative; - return true; - - case AL_LOOPING: - CHECKSIZE(values, 1); - values[0] = Source->Looping; - return true; - - case AL_BUFFER: - CHECKSIZE(values, 1); - BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : nullptr; - values[0] = (BufferList && BufferList->mBuffer) ? BufferList->mBuffer->id : 0; - return true; - - case AL_SOURCE_STATE: - CHECKSIZE(values, 1); - values[0] = GetSourceState(Source, GetSourceVoice(Source, Context)); - return true; - - case AL_BUFFERS_QUEUED: - CHECKSIZE(values, 1); - if(!(BufferList=Source->queue)) - values[0] = 0; - else - { - ALsizei count{0}; - do { - ++count; - BufferList = BufferList->mNext.load(std::memory_order_relaxed); - } while(BufferList != nullptr); - values[0] = count; - } - return true; + case AL_SOURCE_RELATIVE: + CHECKSIZE(values, 1); + values[0] = Source->HeadRelative; + return true; + + case AL_LOOPING: + CHECKSIZE(values, 1); + values[0] = Source->Looping; + return true; + + case AL_BUFFER: + CHECKSIZE(values, 1); + BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : nullptr; + values[0] = (BufferList && BufferList->mBuffer) ? + static_cast(BufferList->mBuffer->id) : 0; + return true; + + case AL_SOURCE_STATE: + CHECKSIZE(values, 1); + values[0] = GetSourceState(Source, GetSourceVoice(Source, Context)); + return true; + + case AL_BUFFERS_QUEUED: + CHECKSIZE(values, 1); + if(!(BufferList=Source->queue)) + values[0] = 0; + else + { + ALsizei count{0}; + do { + ++count; + BufferList = BufferList->mNext.load(std::memory_order_relaxed); + } while(BufferList != nullptr); + values[0] = count; + } + return true; - case AL_BUFFERS_PROCESSED: - CHECKSIZE(values, 1); - if(Source->Looping || Source->SourceType != AL_STREAMING) - { - /* Buffers on a looping source are in a perpetual state of - * PENDING, so don't report any as PROCESSED */ - values[0] = 0; - } - else - { - const ALbufferlistitem *BufferList{Source->queue}; - const ALbufferlistitem *Current{nullptr}; - ALsizei played{0}; - - ALvoice *voice{GetSourceVoice(Source, Context)}; - if(voice != nullptr) - Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); - else if(Source->state == AL_INITIAL) - Current = BufferList; - - while(BufferList && BufferList != Current) - { - ++played; - BufferList = BufferList->mNext.load(std::memory_order_relaxed); - } - values[0] = played; - } - return true; - - case AL_SOURCE_TYPE: - CHECKSIZE(values, 1); - values[0] = Source->SourceType; - return true; - - case AL_DIRECT_FILTER_GAINHF_AUTO: - CHECKSIZE(values, 1); - values[0] = Source->DryGainHFAuto; - return true; - - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - CHECKSIZE(values, 1); - values[0] = Source->WetGainAuto; - return true; - - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - CHECKSIZE(values, 1); - values[0] = Source->WetGainHFAuto; - return true; - - case AL_DIRECT_CHANNELS_SOFT: - CHECKSIZE(values, 1); - values[0] = Source->DirectChannels; - return true; - - case AL_DISTANCE_MODEL: - CHECKSIZE(values, 1); - values[0] = static_cast(Source->mDistanceModel); - return true; - - case AL_SOURCE_RESAMPLER_SOFT: - CHECKSIZE(values, 1); - values[0] = Source->mResampler; - return true; - - case AL_SOURCE_SPATIALIZE_SOFT: - CHECKSIZE(values, 1); - values[0] = Source->mSpatialize; - return true; - - /* 1x float/double */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_DOPPLER_FACTOR: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_SOURCE_RADIUS: - CHECKSIZE(values, 1); - if((err=GetSourcedv(Source, Context, prop, {dvals, 1u})) != false) - values[0] = static_cast(dvals[0]); - return err; - - /* 3x float/double */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - CHECKSIZE(values, 3); - if((err=GetSourcedv(Source, Context, prop, {dvals, 3u})) != false) - { - values[0] = static_cast(dvals[0]); - values[1] = static_cast(dvals[1]); - values[2] = static_cast(dvals[2]); - } - return err; + case AL_BUFFERS_PROCESSED: + CHECKSIZE(values, 1); + if(Source->Looping || Source->SourceType != AL_STREAMING) + { + /* Buffers on a looping source are in a perpetual state of PENDING, + * so don't report any as PROCESSED + */ + values[0] = 0; + } + else + { + const ALbufferlistitem *BufferList{Source->queue}; + const ALbufferlistitem *Current{nullptr}; + ALsizei played{0}; + + ALvoice *voice{GetSourceVoice(Source, Context)}; + if(voice != nullptr) + Current = voice->mCurrentBuffer.load(std::memory_order_relaxed); + else if(Source->state == AL_INITIAL) + Current = BufferList; - /* 6x float/double */ - case AL_ORIENTATION: - CHECKSIZE(values, 6); - if((err=GetSourcedv(Source, Context, prop, {dvals, 6u})) != false) + while(BufferList && BufferList != Current) { - values[0] = static_cast(dvals[0]); - values[1] = static_cast(dvals[1]); - values[2] = static_cast(dvals[2]); - values[3] = static_cast(dvals[3]); - values[4] = static_cast(dvals[4]); - values[5] = static_cast(dvals[5]); + ++played; + BufferList = BufferList->mNext.load(std::memory_order_relaxed); } - return err; - - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - break; /* i64 only */ - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - case AL_STEREO_ANGLES: - break; /* Float/double only */ - - case AL_DIRECT_FILTER: - case AL_AUXILIARY_SEND_FILTER: - break; /* ??? */ + values[0] = played; + } + return true; + + case AL_SOURCE_TYPE: + CHECKSIZE(values, 1); + values[0] = Source->SourceType; + return true; + + case AL_DIRECT_FILTER_GAINHF_AUTO: + CHECKSIZE(values, 1); + values[0] = Source->DryGainHFAuto; + return true; + + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + CHECKSIZE(values, 1); + values[0] = Source->WetGainAuto; + return true; + + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + CHECKSIZE(values, 1); + values[0] = Source->WetGainHFAuto; + return true; + + case AL_DIRECT_CHANNELS_SOFT: + CHECKSIZE(values, 1); + values[0] = Source->DirectChannels; + return true; + + case AL_DISTANCE_MODEL: + CHECKSIZE(values, 1); + values[0] = static_cast(Source->mDistanceModel); + return true; + + case AL_SOURCE_RESAMPLER_SOFT: + CHECKSIZE(values, 1); + values[0] = Source->mResampler; + return true; + + case AL_SOURCE_SPATIALIZE_SOFT: + CHECKSIZE(values, 1); + values[0] = Source->mSpatialize; + return true; + + /* 1x float/double */ + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_REFERENCE_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_DOPPLER_FACTOR: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_SOURCE_RADIUS: + CHECKSIZE(values, 1); + if((err=GetSourcedv(Source, Context, prop, {dvals, 1u})) != false) + values[0] = static_cast(dvals[0]); + return err; + + /* 3x float/double */ + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + CHECKSIZE(values, 3); + if((err=GetSourcedv(Source, Context, prop, {dvals, 3u})) != false) + { + values[0] = static_cast(dvals[0]); + values[1] = static_cast(dvals[1]); + values[2] = static_cast(dvals[2]); + } + return err; + + /* 6x float/double */ + case AL_ORIENTATION: + CHECKSIZE(values, 6); + if((err=GetSourcedv(Source, Context, prop, {dvals, 6u})) != false) + { + values[0] = static_cast(dvals[0]); + values[1] = static_cast(dvals[1]); + values[2] = static_cast(dvals[2]); + values[3] = static_cast(dvals[3]); + values[4] = static_cast(dvals[4]); + values[5] = static_cast(dvals[5]); + } + return err; + + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + break; /* i64 only */ + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + break; /* Double only */ + case AL_STEREO_ANGLES: + break; /* Float/double only */ + + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + break; /* ??? */ } ERR("Unexpected property: 0x%04x\n", prop); @@ -1914,135 +1917,135 @@ bool GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const { ALCdevice *device = Context->mDevice.get(); ClockLatency clocktime; - std::chrono::nanoseconds srcclock; + nanoseconds srcclock; ALdouble dvals[MaxValues]; ALint ivals[MaxValues]; bool err; switch(prop) { - case AL_SAMPLE_OFFSET_LATENCY_SOFT: - CHECKSIZE(values, 2); - /* Get the source offset with the clock time first. Then get the - * clock time with the device latency. Order is important. + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + CHECKSIZE(values, 2); + /* Get the source offset with the clock time first. Then get the clock + * time with the device latency. Order is important. + */ + values[0] = GetSourceSampleOffset(Source, Context, &srcclock); + { + std::lock_guard _{device->StateLock}; + clocktime = GetClockLatency(device); + } + if(srcclock == clocktime.ClockTime) + values[1] = clocktime.Latency.count(); + else + { + /* If the clock time incremented, reduce the latency by that much + * since it's that much closer to the source offset it got earlier. */ - values[0] = GetSourceSampleOffset(Source, Context, &srcclock); - { std::lock_guard _{device->StateLock}; - clocktime = GetClockLatency(device); - } - if(srcclock == clocktime.ClockTime) - values[1] = clocktime.Latency.count(); - else - { - /* If the clock time incremented, reduce the latency by that - * much since it's that much closer to the source offset it got - * earlier. - */ - auto diff = clocktime.ClockTime - srcclock; - values[1] = (clocktime.Latency - std::min(clocktime.Latency, diff)).count(); - } - return true; - - case AL_SAMPLE_OFFSET_CLOCK_SOFT: - CHECKSIZE(values, 2); - values[0] = GetSourceSampleOffset(Source, Context, &srcclock); - values[1] = srcclock.count(); - return true; - - /* 1x float/double */ - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_PITCH: - case AL_GAIN: - case AL_MIN_GAIN: - case AL_MAX_GAIN: - case AL_REFERENCE_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAIN: - case AL_MAX_DISTANCE: - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - case AL_DOPPLER_FACTOR: - case AL_AIR_ABSORPTION_FACTOR: - case AL_ROOM_ROLLOFF_FACTOR: - case AL_CONE_OUTER_GAINHF: - case AL_SOURCE_RADIUS: - CHECKSIZE(values, 1); - if((err=GetSourcedv(Source, Context, prop, {dvals, 1u})) != false) - values[0] = static_cast(dvals[0]); - return err; - - /* 3x float/double */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - CHECKSIZE(values, 3); - if((err=GetSourcedv(Source, Context, prop, {dvals, 3u})) != false) - { - values[0] = static_cast(dvals[0]); - values[1] = static_cast(dvals[1]); - values[2] = static_cast(dvals[2]); - } - return err; + const nanoseconds diff{clocktime.ClockTime - srcclock}; + values[1] = nanoseconds{clocktime.Latency - std::min(clocktime.Latency, diff)}.count(); + } + return true; + + case AL_SAMPLE_OFFSET_CLOCK_SOFT: + CHECKSIZE(values, 2); + values[0] = GetSourceSampleOffset(Source, Context, &srcclock); + values[1] = srcclock.count(); + return true; + + /* 1x float/double */ + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_REFERENCE_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_DOPPLER_FACTOR: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_SOURCE_RADIUS: + CHECKSIZE(values, 1); + if((err=GetSourcedv(Source, Context, prop, {dvals, 1u})) != false) + values[0] = static_cast(dvals[0]); + return err; + + /* 3x float/double */ + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + CHECKSIZE(values, 3); + if((err=GetSourcedv(Source, Context, prop, {dvals, 3u})) != false) + { + values[0] = static_cast(dvals[0]); + values[1] = static_cast(dvals[1]); + values[2] = static_cast(dvals[2]); + } + return err; - /* 6x float/double */ - case AL_ORIENTATION: - CHECKSIZE(values, 6); - if((err=GetSourcedv(Source, Context, prop, {dvals, 6u})) != false) - { - values[0] = static_cast(dvals[0]); - values[1] = static_cast(dvals[1]); - values[2] = static_cast(dvals[2]); - values[3] = static_cast(dvals[3]); - values[4] = static_cast(dvals[4]); - values[5] = static_cast(dvals[5]); - } - return err; - - /* 1x int */ - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BUFFERS_QUEUED: - case AL_BUFFERS_PROCESSED: - case AL_SOURCE_TYPE: - case AL_DIRECT_FILTER_GAINHF_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - case AL_DIRECT_CHANNELS_SOFT: - case AL_DISTANCE_MODEL: - case AL_SOURCE_RESAMPLER_SOFT: - case AL_SOURCE_SPATIALIZE_SOFT: - CHECKSIZE(values, 1); - if((err=GetSourceiv(Source, Context, prop, {ivals, 1u})) != false) - values[0] = ivals[0]; - return err; - - /* 1x uint */ - case AL_BUFFER: - case AL_DIRECT_FILTER: - CHECKSIZE(values, 1); - if((err=GetSourceiv(Source, Context, prop, {ivals, 1u})) != false) - values[0] = static_cast(ivals[0]); - return err; - - /* 3x uint */ - case AL_AUXILIARY_SEND_FILTER: - CHECKSIZE(values, 3); - if((err=GetSourceiv(Source, Context, prop, {ivals, 3u})) != false) - { - values[0] = static_cast(ivals[0]); - values[1] = static_cast(ivals[1]); - values[2] = static_cast(ivals[2]); - } - return err; + /* 6x float/double */ + case AL_ORIENTATION: + CHECKSIZE(values, 6); + if((err=GetSourcedv(Source, Context, prop, {dvals, 6u})) != false) + { + values[0] = static_cast(dvals[0]); + values[1] = static_cast(dvals[1]); + values[2] = static_cast(dvals[2]); + values[3] = static_cast(dvals[3]); + values[4] = static_cast(dvals[4]); + values[5] = static_cast(dvals[5]); + } + return err; + + /* 1x int */ + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: + CHECKSIZE(values, 1); + if((err=GetSourceiv(Source, Context, prop, {ivals, 1u})) != false) + values[0] = ivals[0]; + return err; + + /* 1x uint */ + case AL_BUFFER: + case AL_DIRECT_FILTER: + CHECKSIZE(values, 1); + if((err=GetSourceiv(Source, Context, prop, {ivals, 1u})) != false) + values[0] = static_cast(ivals[0]); + return err; + + /* 3x uint */ + case AL_AUXILIARY_SEND_FILTER: + CHECKSIZE(values, 3); + if((err=GetSourceiv(Source, Context, prop, {ivals, 3u})) != false) + { + values[0] = static_cast(ivals[0]); + values[1] = static_cast(ivals[1]); + values[2] = static_cast(ivals[2]); + } + return err; - case AL_SEC_OFFSET_LATENCY_SOFT: - case AL_SEC_OFFSET_CLOCK_SOFT: - break; /* Double only */ - case AL_STEREO_ANGLES: - break; /* Float/double only */ + case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_CLOCK_SOFT: + break; /* Double only */ + case AL_STEREO_ANGLES: + break; /* Float/double only */ } ERR("Unexpected property: 0x%04x\n", prop); @@ -2060,28 +2063,36 @@ START_API_FUNC if UNLIKELY(n < 0) context->setError(AL_INVALID_VALUE, "Generating %d sources", n); - else if(n == 1) + if UNLIKELY(n <= 0) return; + + std::unique_lock srclock{context->mSourceLock}; + ALCdevice *device{context->mDevice.get()}; + if(static_cast(n) >= device->SourcesMax-context->mNumSources) + { + context->setError(AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax); + return; + } + if(!EnsureSources(context.get(), static_cast(n))) { - ALsource *source = AllocSource(context.get()); - if(source) sources[0] = source->id; + context->setError(AL_OUT_OF_MEMORY, "Failed to allocate %d source%s", n, (n==1)?"":"s"); + return; + } + + if(n == 1) + { + ALsource *source{AllocSource(context.get(), device->NumAuxSends)}; + sources[0] = source->id; } else { - al::vector tempids(n); - auto alloc_end = std::find_if_not(tempids.begin(), tempids.end(), - [&context](ALuint &id) -> bool - { - ALsource *source{AllocSource(context.get())}; - if(!source) return false; - id = source->id; - return true; - } - ); - if(alloc_end != tempids.end()) - alDeleteSources(static_cast(std::distance(tempids.begin(), alloc_end)), - tempids.data()); - else - std::copy(tempids.cbegin(), tempids.cend(), sources); + const ALsizei num_sends{device->NumAuxSends}; + al::vector ids; + ids.reserve(static_cast(n)); + do { + ALsource *source{AllocSource(context.get(), num_sends)}; + ids.emplace_back(source->id); + } while(--n); + std::copy(ids.cbegin(), ids.cend(), sources); } } END_API_FUNC @@ -2098,29 +2109,24 @@ START_API_FUNC std::lock_guard _{context->mSourceLock}; /* Check that all Sources are valid */ + auto validate_source = [&context](ALuint sid) -> bool + { return LookupSource(context.get(), sid) != nullptr; }; + const ALuint *sources_end = sources + n; - auto invsrc = std::find_if_not(sources, sources_end, - [&context](ALuint sid) -> bool - { - if(!LookupSource(context.get(), sid)) - { - context->setError(AL_INVALID_NAME, "Invalid source ID %u", sid); - return false; - } - return true; - } - ); - if LIKELY(invsrc == sources_end) + auto invsrc = std::find_if_not(sources, sources_end, validate_source); + if UNLIKELY(invsrc != sources_end) { - /* All good. Delete source IDs. */ - std::for_each(sources, sources_end, - [&context](ALuint sid) -> void - { - ALsource *src{LookupSource(context.get(), sid)}; - if(src) FreeSource(context.get(), src); - } - ); + context->setError(AL_INVALID_NAME, "Invalid source ID %u", *invsrc); + return; } + + /* All good. Delete source IDs. */ + auto delete_source = [&context](ALuint sid) -> void + { + ALsource *src{LookupSource(context.get(), sid)}; + if(src) FreeSource(context.get(), src); + }; + std::for_each(sources, sources_end, delete_source); } END_API_FUNC @@ -2637,7 +2643,7 @@ START_API_FUNC ALsource **srchandles{source_storage.data()}; if UNLIKELY(static_cast(n) > source_storage.size()) { - extra_sources.resize(n); + extra_sources.resize(static_cast(n)); srchandles = extra_sources.data(); } @@ -2667,16 +2673,16 @@ START_API_FUNC } /* Count the number of reusable voices. */ - auto count_free_voices = [](const ALsizei count, const ALvoice &voice) noexcept -> ALsizei + auto count_free_voices = [](const ALuint count, const ALvoice &voice) noexcept -> ALuint { - if(voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && - voice.mSourceID.load(std::memory_order_relaxed) == 0u) + if(voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped + && voice.mSourceID.load(std::memory_order_relaxed) == 0u) return count + 1; return count; }; auto free_voices = std::accumulate(context->mVoices.begin(), context->mVoices.end(), - ALsizei{0}, count_free_voices); - if UNLIKELY(n > free_voices) + ALuint{0}, count_free_voices); + if UNLIKELY(static_cast(n) > free_voices) { /* Increase the number of voices to handle the request. */ const ALuint need_voices{static_cast(n) - free_voices}; @@ -2775,7 +2781,7 @@ START_API_FUNC } ALbuffer *buffer{BufferList->mBuffer}; - voice->mFrequency = buffer->Frequency; + voice->mFrequency = static_cast(buffer->Frequency); voice->mFmtChannels = buffer->mFmtChannels; voice->mNumChannels = ChannelsFromFmt(buffer->mFmtChannels); voice->mSampleSize = BytesFromFmt(buffer->mFmtType); @@ -2791,20 +2797,20 @@ START_API_FUNC /* Don't need to set the VOICE_IS_AMBISONIC flag if the device is * mixing in first order. No HF scaling is necessary to mix it. */ - if((voice->mFmtChannels == FmtBFormat2D || voice->mFmtChannels == FmtBFormat3D) && - device->mAmbiOrder > 1) + if((voice->mFmtChannels == FmtBFormat2D || voice->mFmtChannels == FmtBFormat3D) + && device->mAmbiOrder > 1) { - const int *OrderFromChan; + const ALuint *OrderFromChan; if(voice->mFmtChannels == FmtBFormat2D) { - static constexpr int Order2DFromChan[MAX_AMBI2D_CHANNELS]{ + static constexpr ALuint Order2DFromChan[MAX_AMBI2D_CHANNELS]{ 0, 1,1, 2,2, 3,3 }; OrderFromChan = Order2DFromChan; } else { - static constexpr int Order3DFromChan[MAX_AMBI_CHANNELS]{ + static constexpr ALuint Order3DFromChan[MAX_AMBI_CHANNELS]{ 0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3, }; OrderFromChan = Order3DFromChan; @@ -2886,7 +2892,7 @@ START_API_FUNC ALsource **srchandles{source_storage.data()}; if UNLIKELY(static_cast(n) > source_storage.size()) { - extra_sources.resize(n); + extra_sources.resize(static_cast(n)); srchandles = extra_sources.data(); } @@ -2941,7 +2947,7 @@ START_API_FUNC ALsource **srchandles{source_storage.data()}; if UNLIKELY(static_cast(n) > source_storage.size()) { - extra_sources.resize(n); + extra_sources.resize(static_cast(n)); srchandles = extra_sources.data(); } @@ -3006,7 +3012,7 @@ START_API_FUNC ALsource **srchandles{source_storage.data()}; if UNLIKELY(static_cast(n) > source_storage.size()) { - extra_sources.resize(n); + extra_sources.resize(static_cast(n)); srchandles = extra_sources.data(); } @@ -3197,8 +3203,7 @@ START_API_FUNC ++i; } - while(nb > 0) - { + do { std::unique_ptr head{source->queue}; source->queue = head->mNext.load(std::memory_order_relaxed); @@ -3209,8 +3214,7 @@ START_API_FUNC } else *(buffers++) = 0; - --nb; - } + } while(--nb); } END_API_FUNC @@ -3267,7 +3271,7 @@ ALsource::ALsource(ALsizei num_sends) Direct.HFReference = LOWPASSFREQREF; Direct.GainLF = 1.0f; Direct.LFReference = HIGHPASSFREQREF; - Send.resize(num_sends); + Send.resize(static_cast(num_sends)); for(auto &send : Send) { send.Slot = nullptr; diff --git a/al/source.h b/al/source.h index 05037fd3..e0219a04 100644 --- a/al/source.h +++ b/al/source.h @@ -49,17 +49,17 @@ struct ALsource { std::array Direction; std::array OrientAt; std::array OrientUp; - ALboolean HeadRelative; - ALboolean Looping; + bool HeadRelative; + bool Looping; DistanceModel mDistanceModel; Resampler mResampler; - ALboolean DirectChannels; + bool DirectChannels; SpatializeMode mSpatialize; - ALboolean DryGainHFAuto; - ALboolean WetGainAuto; - ALboolean WetGainHFAuto; - ALfloat OuterGainHF; + bool DryGainHFAuto; + bool WetGainAuto; + bool WetGainHFAuto; + ALfloat OuterGainHF; ALfloat AirAbsorptionFactor; ALfloat RoomRolloffFactor; @@ -98,7 +98,7 @@ struct ALsource { ALenum OffsetType{AL_NONE}; /** Source type (static, streaming, or undetermined) */ - ALint SourceType{AL_UNDETERMINED}; + ALenum SourceType{AL_UNDETERMINED}; /** Source state (initial, playing, paused, or stopped) */ ALenum state{AL_INITIAL}; diff --git a/alc/alu.h b/alc/alu.h index 3b6045f0..51b7a5c1 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -232,8 +232,8 @@ struct ALvoice { /* Properties for the attached buffer(s). */ FmtChannels mFmtChannels; ALuint mFrequency; - ALsizei mNumChannels; - ALsizei mSampleSize; + ALuint mNumChannels; + ALuint mSampleSize; /** Current target parameters used for mixing. */ ALint mStep; diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 98b86c9a..acc3af1d 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -485,8 +485,8 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) ALuint DataPosFrac{mPositionFrac.load(std::memory_order_relaxed)}; ALbufferlistitem *BufferListItem{mCurrentBuffer.load(std::memory_order_relaxed)}; ALbufferlistitem *BufferLoopItem{mLoopBuffer.load(std::memory_order_relaxed)}; - const auto NumChannels = static_cast(mNumChannels); - const auto SampleSize = static_cast(mSampleSize); + const ALuint NumChannels{mNumChannels}; + const ALuint SampleSize{mSampleSize}; const auto increment = static_cast(mStep); if(increment < 1) return; -- cgit v1.2.3 From ac48569c691f92311be81271e9b6b57947eb35a0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Sep 2019 11:59:36 -0700 Subject: Avoid a macro call and mark unlikely paths as unlikely --- al/auxeffectslot.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index f2801329..85c07c89 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -253,9 +253,9 @@ START_API_FUNC ContextRef context{GetContextRef()}; if UNLIKELY(!context) return; - if(n < 0) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Generating %d effect slots", n); - if(n == 0) return; + if UNLIKELY(n < 0) + context->setError(AL_INVALID_VALUE, "Generating %d effect slots", n); + if UNLIKELY(n <= 0) return; std::unique_lock slotlock{context->mEffectSlotLock}; ALCdevice *device{context->mDevice.get()}; -- cgit v1.2.3 From 6ca8fadd583ade917a07da90c038ce62220593f7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Sep 2019 12:14:23 -0700 Subject: Fix counting free objects --- al/auxeffectslot.cpp | 2 +- al/buffer.cpp | 2 +- al/effect.cpp | 2 +- al/filter.cpp | 2 +- al/source.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index 85c07c89..4dc38ecc 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -164,7 +164,7 @@ bool EnsureEffectSlots(ALCcontext *context, size_t needed) size_t count{std::accumulate(context->mEffectSlotList.cbegin(), context->mEffectSlotList.cend(), size_t{0}, [](size_t cur, const EffectSlotSubList &sublist) noexcept -> size_t - { return cur + static_cast(POPCNT64(~sublist.FreeMask)); } + { return cur + static_cast(POPCNT64(sublist.FreeMask)); } )}; while(needed > count) diff --git a/al/buffer.cpp b/al/buffer.cpp index 1b4f6846..de1b1e9a 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -286,7 +286,7 @@ bool EnsureBuffers(ALCdevice *device, size_t needed) { size_t count{std::accumulate(device->BufferList.cbegin(), device->BufferList.cend(), size_t{0}, [](size_t cur, const BufferSubList &sublist) noexcept -> size_t - { return cur + static_cast(POPCNT64(~sublist.FreeMask)); } + { return cur + static_cast(POPCNT64(sublist.FreeMask)); } )}; while(needed > count) diff --git a/al/effect.cpp b/al/effect.cpp index c27fc8df..0bef3ce6 100644 --- a/al/effect.cpp +++ b/al/effect.cpp @@ -141,7 +141,7 @@ bool EnsureEffects(ALCdevice *device, size_t needed) { size_t count{std::accumulate(device->EffectList.cbegin(), device->EffectList.cend(), size_t{0}, [](size_t cur, const EffectSubList &sublist) noexcept -> size_t - { return cur + static_cast(POPCNT64(~sublist.FreeMask)); } + { return cur + static_cast(POPCNT64(sublist.FreeMask)); } )}; while(needed > count) diff --git a/al/filter.cpp b/al/filter.cpp index 920b4ca1..2dd82bb0 100644 --- a/al/filter.cpp +++ b/al/filter.cpp @@ -283,7 +283,7 @@ bool EnsureFilters(ALCdevice *device, size_t needed) { size_t count{std::accumulate(device->FilterList.cbegin(), device->FilterList.cend(), size_t{0}, [](size_t cur, const FilterSubList &sublist) noexcept -> size_t - { return cur + static_cast(POPCNT64(~sublist.FreeMask)); } + { return cur + static_cast(POPCNT64(sublist.FreeMask)); } )}; while(needed > count) diff --git a/al/source.cpp b/al/source.cpp index 3c22b620..38c4ff54 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -500,7 +500,7 @@ bool EnsureSources(ALCcontext *context, size_t needed) size_t count{std::accumulate(context->mSourceList.cbegin(), context->mSourceList.cend(), size_t{0}, [](size_t cur, const SourceSubList &sublist) noexcept -> size_t - { return cur + static_cast(POPCNT64(~sublist.FreeMask)); } + { return cur + static_cast(POPCNT64(sublist.FreeMask)); } )}; while(needed > count) -- cgit v1.2.3 From 70b58d79fe06581a7ca6db3feb17d5d07f8f8de6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Sep 2019 12:19:07 -0700 Subject: Fix source limit check --- al/source.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index 38c4ff54..b9989d5d 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -2067,9 +2067,10 @@ START_API_FUNC std::unique_lock srclock{context->mSourceLock}; ALCdevice *device{context->mDevice.get()}; - if(static_cast(n) >= device->SourcesMax-context->mNumSources) + if(static_cast(n) > device->SourcesMax-context->mNumSources) { - context->setError(AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax); + context->setError(AL_OUT_OF_MEMORY, "Exceeding %u source limit (%u + %d)", + device->SourcesMax, context->mNumSources, n); return; } if(!EnsureSources(context.get(), static_cast(n))) -- cgit v1.2.3 From 5ca8796d6ab804841be2724ecb3daa134eb23c39 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Sep 2019 17:10:33 -0700 Subject: Clean up some lambda definitions --- al/auxeffectslot.cpp | 52 ++++++++++++++++++++++++---------------------------- al/buffer.cpp | 49 +++++++++++++++++++++++-------------------------- al/effect.cpp | 38 +++++++++++++++----------------------- al/filter.cpp | 38 +++++++++++++++----------------------- al/source.cpp | 4 ++-- 5 files changed, 79 insertions(+), 102 deletions(-) diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index 4dc38ecc..b765887c 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -193,7 +193,6 @@ ALeffectslot *AllocEffectSlot(ALCcontext *context) [](const EffectSlotSubList &entry) noexcept -> bool { return entry.FreeMask != 0; } ); - auto lidx = static_cast(std::distance(context->mEffectSlotList.begin(), sublist)); auto slidx = static_cast(CTZ64(sublist->FreeMask)); @@ -305,41 +304,38 @@ START_API_FUNC ContextRef context{GetContextRef()}; if UNLIKELY(!context) return; - if(n < 0) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Deleting %d effect slots", n); - if(n == 0) return; + if UNLIKELY(n < 0) + context->setError(AL_INVALID_VALUE, "Deleting %d effect slots", n); + if UNLIKELY(n <= 0) return; std::lock_guard _{context->mEffectSlotLock}; - auto effectslots_end = effectslots + n; - auto bad_slot = std::find_if(effectslots, effectslots_end, - [&context](ALuint id) -> bool + auto validate_slot = [&context](const ALuint id) -> bool + { + ALeffectslot *slot{LookupEffectSlot(context.get(), id)}; + if UNLIKELY(!slot) { - ALeffectslot *slot{LookupEffectSlot(context.get(), id)}; - if(!slot) - { - context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", id); - return true; - } - if(ReadRef(slot->ref) != 0) - { - context->setError(AL_INVALID_NAME, "Deleting in-use effect slot %u", id); - return true; - } + context->setError(AL_INVALID_NAME, "Invalid effect slot ID %u", id); return false; } - ); - if(bad_slot != effectslots_end) - return; + if UNLIKELY(ReadRef(slot->ref) != 0) + { + context->setError(AL_INVALID_OPERATION, "Deleting in-use effect slot %u", id); + return false; + } + return true; + }; + auto effectslots_end = effectslots + n; + auto bad_slot = std::find_if_not(effectslots, effectslots_end, validate_slot); + if UNLIKELY(bad_slot != effectslots_end) return; // All effectslots are valid, remove and delete them RemoveActiveEffectSlots(effectslots, static_cast(n), context.get()); - std::for_each(effectslots, effectslots_end, - [&context](ALuint sid) -> void - { - ALeffectslot *slot{LookupEffectSlot(context.get(), sid)}; - if(slot) FreeEffectSlot(context.get(), slot); - } - ); + auto delete_slot = [&context](const ALuint sid) -> void + { + ALeffectslot *slot{LookupEffectSlot(context.get(), sid)}; + if(slot) FreeEffectSlot(context.get(), slot); + }; + std::for_each(effectslots, effectslots_end, delete_slot); } END_API_FUNC diff --git a/al/buffer.cpp b/al/buffer.cpp index de1b1e9a..42db68a8 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -682,36 +682,33 @@ START_API_FUNC std::lock_guard _{device->BufferLock}; /* First try to find any buffers that are invalid or in-use. */ - const ALuint *buffers_end = buffers + n; - auto invbuf = std::find_if(buffers, buffers_end, - [device, &context](ALuint bid) -> bool + auto validate_buffer = [device, &context](const ALuint bid) -> bool + { + if(!bid) return true; + ALbuffer *ALBuf{LookupBuffer(device, bid)}; + if UNLIKELY(!ALBuf) { - if(!bid) return false; - ALbuffer *ALBuf = LookupBuffer(device, bid); - if UNLIKELY(!ALBuf) - { - context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", bid); - return true; - } - if UNLIKELY(ReadRef(ALBuf->ref) != 0) - { - context->setError(AL_INVALID_OPERATION, "Deleting in-use buffer %u", bid); - return true; - } + context->setError(AL_INVALID_NAME, "Invalid buffer ID %u", bid); return false; } - ); - if LIKELY(invbuf == buffers_end) + if UNLIKELY(ReadRef(ALBuf->ref) != 0) + { + context->setError(AL_INVALID_OPERATION, "Deleting in-use buffer %u", bid); + return false; + } + return true; + }; + const ALuint *buffers_end = buffers + n; + auto invbuf = std::find_if_not(buffers, buffers_end, validate_buffer); + if UNLIKELY(invbuf != buffers_end) return; + + /* All good. Delete non-0 buffer IDs. */ + auto delete_buffer = [device](const ALuint bid) -> void { - /* All good. Delete non-0 buffer IDs. */ - std::for_each(buffers, buffers_end, - [device](ALuint bid) -> void - { - ALbuffer *buffer{bid ? LookupBuffer(device, bid) : nullptr}; - if(buffer) FreeBuffer(device, buffer); - } - ); - } + ALbuffer *buffer{bid ? LookupBuffer(device, bid) : nullptr}; + if(buffer) FreeBuffer(device, buffer); + }; + std::for_each(buffers, buffers_end, delete_buffer); } END_API_FUNC diff --git a/al/effect.cpp b/al/effect.cpp index 0bef3ce6..2ad4c26e 100644 --- a/al/effect.cpp +++ b/al/effect.cpp @@ -169,7 +169,6 @@ ALeffect *AllocEffect(ALCdevice *device) [](const EffectSubList &entry) noexcept -> bool { return entry.FreeMask != 0; } ); - auto lidx = static_cast(std::distance(device->EffectList.begin(), sublist)); auto slidx = static_cast(CTZ64(sublist->FreeMask)); @@ -264,31 +263,24 @@ START_API_FUNC std::lock_guard _{device->EffectLock}; /* First try to find any effects that are invalid. */ + auto validate_effect = [device](const ALuint eid) -> bool + { return !eid || LookupEffect(device, eid) != nullptr; }; + const ALuint *effects_end = effects + n; - auto inveffect = std::find_if(effects, effects_end, - [device, &context](ALuint eid) -> bool - { - if(!eid) return false; - ALeffect *effect{LookupEffect(device, eid)}; - if UNLIKELY(!effect) - { - context->setError(AL_INVALID_NAME, "Invalid effect ID %u", eid); - return true; - } - return false; - } - ); - if LIKELY(inveffect == effects_end) + auto inveffect = std::find_if_not(effects, effects_end, validate_effect); + if UNLIKELY(inveffect != effects_end) { - /* All good. Delete non-0 effect IDs. */ - std::for_each(effects, effects_end, - [device](ALuint eid) -> void - { - ALeffect *effect{eid ? LookupEffect(device, eid) : nullptr}; - if(effect) FreeEffect(device, effect); - } - ); + context->setError(AL_INVALID_NAME, "Invalid effect ID %u", *inveffect); + return; } + + /* All good. Delete non-0 effect IDs. */ + auto delete_effect = [device](ALuint eid) -> void + { + ALeffect *effect{eid ? LookupEffect(device, eid) : nullptr}; + if(effect) FreeEffect(device, effect); + }; + std::for_each(effects, effects_end, delete_effect); } END_API_FUNC diff --git a/al/filter.cpp b/al/filter.cpp index 2dd82bb0..33887254 100644 --- a/al/filter.cpp +++ b/al/filter.cpp @@ -312,7 +312,6 @@ ALfilter *AllocFilter(ALCdevice *device) [](const FilterSubList &entry) noexcept -> bool { return entry.FreeMask != 0; } ); - auto lidx = static_cast(std::distance(device->FilterList.begin(), sublist)); auto slidx = static_cast(CTZ64(sublist->FreeMask)); @@ -408,31 +407,24 @@ START_API_FUNC std::lock_guard _{device->FilterLock}; /* First try to find any filters that are invalid. */ + auto validate_filter = [device](const ALuint fid) -> bool + { return !fid || LookupFilter(device, fid) != nullptr; }; + const ALuint *filters_end = filters + n; - auto invflt = std::find_if(filters, filters_end, - [device, &context](ALuint fid) -> bool - { - if(!fid) return false; - ALfilter *filter{LookupFilter(device, fid)}; - if UNLIKELY(!filter) - { - context->setError(AL_INVALID_NAME, "Invalid filter ID %u", fid); - return true; - } - return false; - } - ); - if LIKELY(invflt == filters_end) + auto invflt = std::find_if_not(filters, filters_end, validate_filter); + if UNLIKELY(invflt != filters_end) { - /* All good. Delete non-0 filter IDs. */ - std::for_each(filters, filters_end, - [device](ALuint fid) -> void - { - ALfilter *filter{fid ? LookupFilter(device, fid) : nullptr}; - if(filter) FreeFilter(device, filter); - } - ); + context->setError(AL_INVALID_NAME, "Invalid filter ID %u", *invflt); + return; } + + /* All good. Delete non-0 filter IDs. */ + auto delete_filter = [device](const ALuint fid) -> void + { + ALfilter *filter{fid ? LookupFilter(device, fid) : nullptr}; + if(filter) FreeFilter(device, filter); + }; + std::for_each(filters, filters_end, delete_filter); } END_API_FUNC diff --git a/al/source.cpp b/al/source.cpp index b9989d5d..09b4133c 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -2110,7 +2110,7 @@ START_API_FUNC std::lock_guard _{context->mSourceLock}; /* Check that all Sources are valid */ - auto validate_source = [&context](ALuint sid) -> bool + auto validate_source = [&context](const ALuint sid) -> bool { return LookupSource(context.get(), sid) != nullptr; }; const ALuint *sources_end = sources + n; @@ -2122,7 +2122,7 @@ START_API_FUNC } /* All good. Delete source IDs. */ - auto delete_source = [&context](ALuint sid) -> void + auto delete_source = [&context](const ALuint sid) -> void { ALsource *src{LookupSource(context.get(), sid)}; if(src) FreeSource(context.get(), src); -- cgit v1.2.3 From 5f862a5b49412ef2690a271ed240d5a6fc881b37 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Sep 2019 17:45:06 -0700 Subject: Clean up sample converter implicit conversions --- alc/alu.cpp | 4 ++-- alc/alu.h | 2 +- alc/converter.cpp | 58 ++++++++++++++++++++++++++++-------------------------- alc/converter.h | 8 ++++---- alc/mixvoice.cpp | 2 +- common/alnumeric.h | 38 ++++++++++++++++++----------------- 6 files changed, 58 insertions(+), 54 deletions(-) diff --git a/alc/alu.cpp b/alc/alu.cpp index a1c6ab7a..8fab0b06 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -951,7 +951,7 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons if(Pitch > static_cast(MAX_PITCH)) voice->mStep = MAX_PITCH<mStep = maxi(fastf2i(Pitch * FRACTIONONE), 1); + voice->mStep = maxu(fastf2u(Pitch * FRACTIONONE), 1); if(props->mResampler == BSinc24Resampler) BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc24); else if(props->mResampler == BSinc12Resampler) @@ -1281,7 +1281,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A if(Pitch > static_cast(MAX_PITCH)) voice->mStep = MAX_PITCH<mStep = maxi(fastf2i(Pitch * FRACTIONONE), 1); + voice->mStep = maxu(fastf2u(Pitch * FRACTIONONE), 1); if(props->mResampler == BSinc24Resampler) BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc24); else if(props->mResampler == BSinc12Resampler) diff --git a/alc/alu.h b/alc/alu.h index 51b7a5c1..10b58612 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -236,7 +236,7 @@ struct ALvoice { ALuint mSampleSize; /** Current target parameters used for mixing. */ - ALint mStep; + ALuint mStep; ResamplerFunc mResampler; diff --git a/alc/converter.cpp b/alc/converter.cpp index faf24948..d7a57c12 100644 --- a/alc/converter.cpp +++ b/alc/converter.cpp @@ -32,11 +32,11 @@ template<> inline ALfloat LoadSample(DevFmtTypeTraits: { return val; } template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept -{ return LoadSample(val - 128); } +{ return LoadSample(static_cast(val - 128)); } template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept -{ return LoadSample(val - 32768); } +{ return LoadSample(static_cast(val - 32768)); } template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept -{ return LoadSample(val - 2147483648u); } +{ return LoadSample(static_cast(val - 2147483648u)); } template @@ -77,17 +77,17 @@ template<> inline ALfloat StoreSample(ALfloat val) noexcept template<> inline ALint StoreSample(ALfloat val) noexcept { return fastf2i(clampf(val*2147483648.0f, -2147483648.0f, 2147483520.0f)); } template<> inline ALshort StoreSample(ALfloat val) noexcept -{ return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); } +{ return static_cast(fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f))); } template<> inline ALbyte StoreSample(ALfloat val) noexcept -{ return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); } +{ return static_cast(fastf2i(clampf(val*128.0f, -128.0f, 127.0f))); } /* Define unsigned output variations. */ template<> inline ALuint StoreSample(ALfloat val) noexcept -{ return StoreSample(val) + 2147483648u; } +{ return static_cast(StoreSample(val)) + 2147483648u; } template<> inline ALushort StoreSample(ALfloat val) noexcept -{ return StoreSample(val) + 32768; } +{ return static_cast(StoreSample(val) + 32768); } template<> inline ALubyte StoreSample(ALfloat val) noexcept -{ return StoreSample(val) + 128; } +{ return static_cast(StoreSample(val) + 128); } template inline void StoreSampleArray(void *dst, const ALfloat *RESTRICT src, const size_t dststep, @@ -152,17 +152,17 @@ SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, SampleConverterPtr converter{new (FamCount{numchans}) SampleConverter{numchans}}; converter->mSrcType = srcType; converter->mDstType = dstType; - converter->mSrcTypeSize = BytesFromDevFmt(srcType); - converter->mDstTypeSize = BytesFromDevFmt(dstType); + converter->mSrcTypeSize = static_cast(BytesFromDevFmt(srcType)); + converter->mDstTypeSize = static_cast(BytesFromDevFmt(dstType)); converter->mSrcPrepCount = 0; converter->mFracOffset = 0; /* Have to set the mixer FPU mode since that's what the resampler code expects. */ FPUCtl mixer_mode{}; - auto step = static_cast( + auto step = static_cast( mind(srcRate*ALdouble{FRACTIONONE}/dstRate + 0.5, MAX_PITCH*FRACTIONONE)); - converter->mIncrement = maxi(step, 1); + converter->mIncrement = maxu(step, 1); if(converter->mIncrement == FRACTIONONE) converter->mResample = Resample_; else @@ -185,7 +185,7 @@ ALuint SampleConverter::availableOut(ALuint srcframes) const /* Negative prepcount means we need to skip that many input samples. */ if(static_cast(-prepcount) >= srcframes) return 0; - srcframes += prepcount; + srcframes -= static_cast(-prepcount); prepcount = 0; } @@ -214,9 +214,9 @@ ALuint SampleConverter::availableOut(ALuint srcframes) const ALuint SampleConverter::convert(const ALvoid **src, ALuint *srcframes, ALvoid *dst, ALuint dstframes) { - const ALsizei SrcFrameSize{static_cast(mChan.size()) * mSrcTypeSize}; - const ALsizei DstFrameSize{static_cast(mChan.size()) * mDstTypeSize}; - const ALsizei increment{mIncrement}; + const ALuint SrcFrameSize{static_cast(mChan.size()) * mSrcTypeSize}; + const ALuint DstFrameSize{static_cast(mChan.size()) * mDstTypeSize}; + const ALuint increment{mIncrement}; auto SamplesIn = static_cast(*src); ALuint NumSrcSamples{*srcframes}; @@ -230,12 +230,12 @@ ALuint SampleConverter::convert(const ALvoid **src, ALuint *srcframes, ALvoid *d /* Negative prepcount means we need to skip that many input samples. */ if(static_cast(-prepcount) >= NumSrcSamples) { - mSrcPrepCount = prepcount + NumSrcSamples; + mSrcPrepCount = static_cast(NumSrcSamples) + prepcount; NumSrcSamples = 0; break; } - SamplesIn += SrcFrameSize*-prepcount; - NumSrcSamples += prepcount; + SamplesIn += SrcFrameSize*static_cast(-prepcount); + NumSrcSamples -= static_cast(-prepcount); mSrcPrepCount = 0; continue; } @@ -251,14 +251,14 @@ ALuint SampleConverter::convert(const ALvoid **src, ALuint *srcframes, ALvoid *d LoadSamples(&mChan[chan].PrevSamples[prepcount], SamplesIn + mSrcTypeSize*chan, mChan.size(), mSrcType, toread); - mSrcPrepCount = prepcount + toread; + mSrcPrepCount = prepcount + static_cast(toread); NumSrcSamples = 0; break; } ALfloat *RESTRICT SrcData{mSrcSamples}; ALfloat *RESTRICT DstData{mDstSamples}; - ALsizei DataPosFrac{mFracOffset}; + ALuint DataPosFrac{mFracOffset}; auto DataSize64 = static_cast(prepcount); DataSize64 += toread; DataSize64 -= MAX_RESAMPLE_PADDING*2; @@ -285,20 +285,21 @@ ALuint SampleConverter::convert(const ALvoid **src, ALuint *srcframes, ALvoid *d * number of output samples being generated. */ ALuint SrcDataEnd{(DstSize*increment + DataPosFrac)>>FRACTIONBITS}; - if(SrcDataEnd >= prepcount+toread) + if(SrcDataEnd >= static_cast(prepcount)+toread) std::fill(std::begin(mChan[chan].PrevSamples), - std::end(mChan[chan].PrevSamples), 0.0f); + std::end(mChan[chan].PrevSamples), 0.0f); else { - size_t len{minu(MAX_RESAMPLE_PADDING*2, prepcount+toread-SrcDataEnd)}; + const size_t len{minz(al::size(mChan[chan].PrevSamples), + static_cast(prepcount)+toread-SrcDataEnd)}; std::copy_n(SrcData+SrcDataEnd, len, mChan[chan].PrevSamples); std::fill(std::begin(mChan[chan].PrevSamples)+len, - std::end(mChan[chan].PrevSamples), 0.0f); + std::end(mChan[chan].PrevSamples), 0.0f); } /* Now resample, and store the result in the output buffer. */ const ALfloat *ResampledData{mResample(&mState, SrcData+MAX_RESAMPLE_PADDING, - DataPosFrac, increment, {DstData, DstSize})}; + DataPosFrac, static_cast(increment), {DstData, DstSize})}; StoreSamples(DstSamples, ResampledData, mChan.size(), mDstType, DstSize); } @@ -307,7 +308,7 @@ ALuint SampleConverter::convert(const ALvoid **src, ALuint *srcframes, ALvoid *d * fractional offset. */ DataPosFrac += increment*DstSize; - mSrcPrepCount = mini(prepcount + toread - (DataPosFrac>>FRACTIONBITS), + mSrcPrepCount = mini(prepcount + static_cast(toread - (DataPosFrac>>FRACTIONBITS)), MAX_RESAMPLE_PADDING*2); mFracOffset = DataPosFrac & FRACTIONMASK; @@ -359,5 +360,6 @@ void ChannelConverter::convert(const ALvoid *src, ALfloat *dst, ALuint frames) c } } else - LoadSamples(dst, src, 1u, mSrcType, frames*ChannelsFromDevFmt(mSrcChans, 0)); + LoadSamples(dst, src, 1u, mSrcType, + frames*static_cast(ChannelsFromDevFmt(mSrcChans, 0))); } diff --git a/alc/converter.h b/alc/converter.h index 8a7b6f5f..8390eae3 100644 --- a/alc/converter.h +++ b/alc/converter.h @@ -16,13 +16,13 @@ struct SampleConverter { DevFmtType mSrcType{}; DevFmtType mDstType{}; - ALsizei mSrcTypeSize{}; - ALsizei mDstTypeSize{}; + ALuint mSrcTypeSize{}; + ALuint mDstTypeSize{}; ALint mSrcPrepCount{}; - ALsizei mFracOffset{}; - ALsizei mIncrement{}; + ALuint mFracOffset{}; + ALuint mIncrement{}; InterpState mState{}; ResamplerFunc mResample{}; diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index acc3af1d..c5eae591 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -487,7 +487,7 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) ALbufferlistitem *BufferLoopItem{mLoopBuffer.load(std::memory_order_relaxed)}; const ALuint NumChannels{mNumChannels}; const ALuint SampleSize{mSampleSize}; - const auto increment = static_cast(mStep); + const ALuint increment{mStep}; if(increment < 1) return; ASSUME(NumChannels > 0); diff --git a/common/alnumeric.h b/common/alnumeric.h index 0a05f4bf..94ea2ee0 100644 --- a/common/alnumeric.h +++ b/common/alnumeric.h @@ -216,6 +216,8 @@ inline int fastf2i(float f) noexcept return static_cast(f); #endif } +inline unsigned int fastf2u(float f) noexcept +{ return static_cast(fastf2i(f)); } /** Converts float-to-int using standard behavior (truncation). */ inline int float2int(float f) noexcept @@ -254,34 +256,34 @@ inline int float2int(float f) noexcept inline int double2int(double d) noexcept { #if defined(HAVE_SSE_INTRINSICS) - return _mm_cvttsd_si32(_mm_set_sd(d)); + return _mm_cvttsd_si32(_mm_set_sd(d)); #elif ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) && \ !defined(__SSE2_MATH__)) || (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP < 2) - int sign, shift; - int64_t mant; - union { - double d; - int64_t i64; - } conv; + int sign, shift; + int64_t mant; + union { + double d; + int64_t i64; + } conv; - conv.d = d; - sign = (conv.i64 >> 63) | 1; - shift = ((conv.i64 >> 52) & 0x7ff) - (1023 + 52); + conv.d = d; + sign = (conv.i64 >> 63) | 1; + shift = ((conv.i64 >> 52) & 0x7ff) - (1023 + 52); - /* Over/underflow */ - if UNLIKELY(shift >= 63 || shift < -52) - return 0; + /* Over/underflow */ + if UNLIKELY(shift >= 63 || shift < -52) + return 0; - mant = (conv.i64 & 0xfffffffffffff_i64) | 0x10000000000000_i64; - if LIKELY(shift < 0) - return (int)(mant >> -shift) * sign; - return (int)(mant << shift) * sign; + mant = (conv.i64 & 0xfffffffffffff_i64) | 0x10000000000000_i64; + if LIKELY(shift < 0) + return (int)(mant >> -shift) * sign; + return (int)(mant << shift) * sign; #else - return static_cast(d); + return static_cast(d); #endif } -- cgit v1.2.3 From c1690178ec0b020018857ed0b666ff9b16e01c21 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 13 Sep 2019 03:25:13 -0700 Subject: Make the resampler increment unsigned --- alc/alu.h | 2 +- alc/converter.cpp | 2 +- alc/mixer/defs.h | 9 +++++---- alc/mixer/mixer_c.cpp | 14 ++++++-------- alc/mixer/mixer_neon.cpp | 42 +++++++++++++++++++----------------------- alc/mixer/mixer_sse.cpp | 5 ++--- alc/mixer/mixer_sse2.cpp | 39 +++++++++++++++++++-------------------- alc/mixer/mixer_sse41.cpp | 43 +++++++++++++++++++++++-------------------- alc/mixvoice.cpp | 3 +-- 9 files changed, 77 insertions(+), 82 deletions(-) diff --git a/alc/alu.h b/alc/alu.h index 10b58612..aca7790e 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -81,7 +81,7 @@ union InterpState { }; using ResamplerFunc = const ALfloat*(*)(const InterpState *state, const ALfloat *RESTRICT src, - ALuint frac, ALint increment, const al::span dst); + ALuint frac, ALuint increment, const al::span dst); void BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *table); diff --git a/alc/converter.cpp b/alc/converter.cpp index d7a57c12..87a9d275 100644 --- a/alc/converter.cpp +++ b/alc/converter.cpp @@ -299,7 +299,7 @@ ALuint SampleConverter::convert(const ALvoid **src, ALuint *srcframes, ALvoid *d /* Now resample, and store the result in the output buffer. */ const ALfloat *ResampledData{mResample(&mState, SrcData+MAX_RESAMPLE_PADDING, - DataPosFrac, static_cast(increment), {DstData, DstSize})}; + DataPosFrac, increment, {DstData, DstSize})}; StoreSamples(DstSamples, ResampledData, mChan.size(), mDstType, DstSize); } diff --git a/alc/mixer/defs.h b/alc/mixer/defs.h index 4aa3c6b6..a6e07bd4 100644 --- a/alc/mixer/defs.h +++ b/alc/mixer/defs.h @@ -28,7 +28,7 @@ enum ResampleType { template const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALuint frac, - ALint increment, const al::span dst); + ALuint increment, const al::span dst); template void Mix_(const al::span InSamples, const al::span OutBuffer, @@ -45,13 +45,14 @@ template void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, const size_t BufferSize); /* Vectorized resampler helpers */ -inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *RESTRICT frac_arr, ALsizei *RESTRICT pos_arr, ALsizei size) +inline void InitPosArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, + size_t size) { pos_arr[0] = 0; frac_arr[0] = frac; - for(ALsizei i{1};i < size;i++) + for(size_t i{1};i < size;i++) { - ALint frac_tmp = frac_arr[i-1] + increment; + const ALuint frac_tmp{frac_arr[i-1] + increment}; pos_arr[i] = pos_arr[i-1] + (frac_tmp>>FRACTIONBITS); frac_arr[i] = frac_tmp&FRACTIONMASK; } diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index a8fb9a19..c5e712f9 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -44,10 +44,8 @@ inline ALfloat do_bsinc(const InterpState &istate, const ALfloat *RESTRICT vals, using SamplerT = ALfloat(const InterpState&, const ALfloat*RESTRICT, const ALuint); template const ALfloat *DoResample(const InterpState *state, const ALfloat *RESTRICT src, - ALuint frac, ALint increment, const al::span dst) + ALuint frac, ALuint increment, const al::span dst) { - ASSUME(increment > 0); - const InterpState istate{*state}; auto proc_sample = [&src,&frac,istate,increment]() -> ALfloat { @@ -68,7 +66,7 @@ const ALfloat *DoResample(const InterpState *state, const ALfloat *RESTRICT src, template<> const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, ALuint, - ALint, const al::span dst) + ALuint, const al::span dst) { #if defined(HAVE_SSE) || defined(HAVE_NEON) /* Avoid copying the source data if it's aligned like the destination. */ @@ -81,22 +79,22 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRI template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALuint frac, ALint increment, const al::span dst) + ALuint frac, ALuint increment, const al::span dst) { return DoResample(state, src, frac, increment, dst); } template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALuint frac, ALint increment, const al::span dst) + ALuint frac, ALuint increment, const al::span dst) { return DoResample(state, src, frac, increment, dst); } template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALuint frac, ALint increment, const al::span dst) + ALuint frac, ALuint increment, const al::span dst) { return DoResample(state, src-1, frac, increment, dst); } template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALuint frac, ALint increment, const al::span dst) + ALuint frac, ALuint increment, const al::span dst) { return DoResample(state, src-state->bsinc.l, frac, increment, dst); } diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index d5b1658f..c0a8e628 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -16,22 +16,20 @@ template<> const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, - ALuint frac, ALint increment, const al::span dst) + ALuint frac, ALuint increment, const al::span dst) { - const int32x4_t increment4 = vdupq_n_s32(increment*4); + const int32x4_t increment4 = vdupq_n_s32(static_cast(increment*4)); const float32x4_t fracOne4 = vdupq_n_f32(1.0f/FRACTIONONE); const int32x4_t fracMask4 = vdupq_n_s32(FRACTIONMASK); - alignas(16) ALsizei pos_[4], frac_[4]; + alignas(16) ALuint pos_[4], frac_[4]; int32x4_t pos4, frac4; - ASSUME(increment > 0); - - InitiatePositionArrays(frac, increment, frac_, pos_, 4); - frac4 = vld1q_s32(frac_); - pos4 = vld1q_s32(pos_); + InitPosArrays(frac, increment, frac_, pos_, 4); + frac4 = vld1q_s32(reinterpret_cast(frac_)); + pos4 = vld1q_s32(reinterpret_cast(pos_)); auto dst_iter = dst.begin(); - const auto aligned_end = (dst.size()&~3) + dst_iter; + const auto aligned_end = (dst.size()&~3u) + dst_iter; while(dst_iter != aligned_end) { const int pos0{vgetq_lane_s32(pos4, 0)}; @@ -54,33 +52,31 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES frac4 = vandq_s32(frac4, fracMask4); } - /* NOTE: These four elements represent the position *after* the last four - * samples, so the lowest element is the next position to resample. - */ - src += static_cast(vgetq_lane_s32(pos4, 0)); - frac = vgetq_lane_s32(frac4, 0); - - while(dst_iter != dst.end()) + if(dst_iter != dst.end()) { - *(dst_iter++) = lerp(src[0], src[1], frac * (1.0f/FRACTIONONE)); + src += static_cast(vgetq_lane_s32(pos4, 0)); + frac = vgetq_lane_s32(frac4, 0); - frac += increment; - src += frac>>FRACTIONBITS; - frac &= FRACTIONMASK; + do { + *(dst_iter++) = lerp(src[0], src[1], frac * (1.0f/FRACTIONONE)); + + frac += increment; + src += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } while(dst_iter != dst.end()); } return dst.begin(); } template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALuint frac, ALint increment, const al::span dst) + ALuint frac, ALuint increment, const al::span dst) { const ALfloat *const filter{state->bsinc.filter}; const float32x4_t sf4{vdupq_n_f32(state->bsinc.sf)}; const ptrdiff_t m{state->bsinc.m}; ASSUME(m > 0); - ASSUME(increment > 0); src -= state->bsinc.l; for(float &out_sample : dst) @@ -183,7 +179,7 @@ void Mix_(const al::span InSamples, const al::span 0) ? 1.0f / static_cast(Counter) : 0.0f}; const bool reached_target{InSamples.size() >= Counter}; const auto min_end = reached_target ? InSamples.begin() + Counter : InSamples.end(); - const auto aligned_end = minz(InSamples.size(), (min_end-InSamples.begin()+3) & ~3) + + const auto aligned_end = minz(InSamples.size(), (min_end-InSamples.begin()+3) & ~3u) + InSamples.begin(); for(FloatBufferLine &output : OutBuffer) { diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index 1965f3e6..82e2bfbe 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -15,14 +15,13 @@ template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, - ALuint frac, ALint increment, const al::span dst) + ALuint frac, ALuint increment, const al::span dst) { const ALfloat *const filter{state->bsinc.filter}; const __m128 sf4{_mm_set1_ps(state->bsinc.sf)}; const ptrdiff_t m{state->bsinc.m}; ASSUME(m > 0); - ASSUME(increment > 0); src -= state->bsinc.l; for(float &out_sample : dst) @@ -146,7 +145,7 @@ void Mix_(const al::span InSamples, const al::span 0) ? 1.0f / static_cast(Counter) : 0.0f}; const bool reached_target{InSamples.size() >= Counter}; const auto min_end = reached_target ? InSamples.begin() + Counter : InSamples.end(); - const auto aligned_end = minz(InSamples.size(), (min_end-InSamples.begin()+3) & ~3) + + const auto aligned_end = minz(InSamples.size(), (min_end-InSamples.begin()+3) & ~3u) + InSamples.begin(); for(FloatBufferLine &output : OutBuffer) { diff --git a/alc/mixer/mixer_sse2.cpp b/alc/mixer/mixer_sse2.cpp index b126cd25..38d77fd9 100644 --- a/alc/mixer/mixer_sse2.cpp +++ b/alc/mixer/mixer_sse2.cpp @@ -29,21 +29,21 @@ template<> const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, - ALuint frac, ALint increment, const al::span dst) + ALuint frac, ALuint increment, const al::span dst) { - const __m128i increment4{_mm_set1_epi32(increment*4)}; + const __m128i increment4{_mm_set1_epi32(static_cast(increment*4))}; const __m128 fracOne4{_mm_set1_ps(1.0f/FRACTIONONE)}; const __m128i fracMask4{_mm_set1_epi32(FRACTIONMASK)}; - ASSUME(increment > 0); - - alignas(16) ALsizei pos_[4], frac_[4]; - InitiatePositionArrays(frac, increment, frac_, pos_, 4); - __m128i frac4{_mm_setr_epi32(frac_[0], frac_[1], frac_[2], frac_[3])}; - __m128i pos4{_mm_setr_epi32(pos_[0], pos_[1], pos_[2], pos_[3])}; + alignas(16) ALuint pos_[4], frac_[4]; + InitPosArrays(frac, increment, frac_, pos_, 4); + __m128i frac4{_mm_setr_epi32(static_cast(frac_[0]), static_cast(frac_[1]), + static_cast(frac_[2]), static_cast(frac_[3]))}; + __m128i pos4{_mm_setr_epi32(static_cast(pos_[0]), static_cast(pos_[1]), + static_cast(pos_[2]), static_cast(pos_[3]))}; auto dst_iter = dst.begin(); - const auto aligned_end = (dst.size()&~3) + dst_iter; + const auto aligned_end = (dst.size()&~3u) + dst_iter; while(dst_iter != aligned_end) { const int pos0{_mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(0, 0, 0, 0)))}; @@ -66,19 +66,18 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES frac4 = _mm_and_si128(frac4, fracMask4); } - /* NOTE: These four elements represent the position *after* the last four - * samples, so the lowest element is the next position to resample. - */ - src += static_cast(_mm_cvtsi128_si32(pos4)); - frac = _mm_cvtsi128_si32(frac4); - - while(dst_iter != dst.end()) + if(dst_iter != dst.end()) { - *(dst_iter++) = lerp(src[0], src[1], frac * (1.0f/FRACTIONONE)); + src += static_cast(_mm_cvtsi128_si32(pos4)); + frac = static_cast(_mm_cvtsi128_si32(frac4)); + + do { + *(dst_iter++) = lerp(src[0], src[1], frac * (1.0f/FRACTIONONE)); - frac += increment; - src += frac>>FRACTIONBITS; - frac &= FRACTIONMASK; + frac += increment; + src += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } while(dst_iter != dst.end()); } return dst.begin(); } diff --git a/alc/mixer/mixer_sse41.cpp b/alc/mixer/mixer_sse41.cpp index 06c51e6a..0a87f76f 100644 --- a/alc/mixer/mixer_sse41.cpp +++ b/alc/mixer/mixer_sse41.cpp @@ -30,21 +30,21 @@ template<> const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, - ALuint frac, ALint increment, const al::span dst) + ALuint frac, ALuint increment, const al::span dst) { - const __m128i increment4{_mm_set1_epi32(increment*4)}; + const __m128i increment4{_mm_set1_epi32(static_cast(increment*4))}; const __m128 fracOne4{_mm_set1_ps(1.0f/FRACTIONONE)}; const __m128i fracMask4{_mm_set1_epi32(FRACTIONMASK)}; - ASSUME(increment > 0); - - alignas(16) ALsizei pos_[4], frac_[4]; - InitiatePositionArrays(frac, increment, frac_, pos_, 4); - __m128i frac4{_mm_setr_epi32(frac_[0], frac_[1], frac_[2], frac_[3])}; - __m128i pos4{_mm_setr_epi32(pos_[0], pos_[1], pos_[2], pos_[3])}; + alignas(16) ALuint pos_[4], frac_[4]; + InitPosArrays(frac, increment, frac_, pos_, 4); + __m128i frac4{_mm_setr_epi32(static_cast(frac_[0]), static_cast(frac_[1]), + static_cast(frac_[2]), static_cast(frac_[3]))}; + __m128i pos4{_mm_setr_epi32(static_cast(pos_[0]), static_cast(pos_[1]), + static_cast(pos_[2]), static_cast(pos_[3]))}; auto dst_iter = dst.begin(); - const auto aligned_end = (dst.size()&~3) + dst_iter; + const auto aligned_end = (dst.size()&~3u) + dst_iter; while(dst_iter != aligned_end) { const int pos0{_mm_extract_epi32(pos4, 0)}; @@ -67,19 +67,22 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES frac4 = _mm_and_si128(frac4, fracMask4); } - /* NOTE: These four elements represent the position *after* the last four - * samples, so the lowest element is the next position to resample. - */ - src += static_cast(_mm_cvtsi128_si32(pos4)); - frac = _mm_cvtsi128_si32(frac4); - - while(dst_iter != dst.end()) + if(dst_iter != dst.end()) { - *(dst_iter++) = lerp(src[0], src[1], frac * (1.0f/FRACTIONONE)); + /* NOTE: These four elements represent the position *after* the last + * four samples, so the lowest element is the next position to + * resample. + */ + src += static_cast(_mm_cvtsi128_si32(pos4)); + frac = static_cast(_mm_cvtsi128_si32(frac4)); + + do { + *(dst_iter++) = lerp(src[0], src[1], frac * (1.0f/FRACTIONONE)); - frac += increment; - src += frac>>FRACTIONBITS; - frac &= FRACTIONMASK; + frac += increment; + src += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } while(dst_iter != dst.end()); } return dst.begin(); } diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index c5eae591..3c621934 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -617,8 +617,7 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) /* Resample, then apply ambisonic upsampling as needed. */ const ALfloat *ResampledData{Resample(&mResampleState, &SrcData[MAX_RESAMPLE_PADDING], - DataPosFrac, static_cast(increment), - {Device->ResampledData, DstBufferSize})}; + DataPosFrac, increment, {Device->ResampledData, DstBufferSize})}; if((mFlags&VOICE_IS_AMBISONIC)) { const ALfloat hfscale{chandata.mAmbiScale}; -- cgit v1.2.3 From 5b763e14379e6989492a278515cdfc02a59cd568 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 13 Sep 2019 03:47:23 -0700 Subject: Clean up implicit conversions in alu.cpp --- alc/alu.cpp | 80 ++++++++++++++++++++++++++++--------------------------------- 1 file changed, 36 insertions(+), 44 deletions(-) diff --git a/alc/alu.cpp b/alc/alu.cpp index 8fab0b06..d9464125 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -451,12 +451,11 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo }; const auto Frequency = static_cast(Device->Frequency); - const ALsizei NumSends{Device->NumAuxSends}; - ASSUME(NumSends >= 0); + const auto NumSends = static_cast(Device->NumAuxSends); bool DirectChannels{props->DirectChannels != AL_FALSE}; const ChanMap *chans{nullptr}; - ALsizei num_channels{0}; + ALuint num_channels{0}; bool isbformat{false}; ALfloat downmix_gain{1.0f}; switch(voice->mFmtChannels) @@ -583,7 +582,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo const ALfloat &scale0 = AmbiScale::FromFuMa[0]; ComputePanGains(&Device->Dry, coeffs, DryGain*scale0, voice->mChans[0].mDryParams.Gains.Target); - for(ALsizei i{0};i < NumSends;i++) + for(ALuint i{0};i < NumSends;i++) { if(const ALeffectslot *Slot{SendSlots[i]}) ComputePanGains(&Slot->Wet, coeffs, WetGain[i]*scale0, @@ -636,12 +635,12 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo { 0.0f, -V[0]*zscale, V[1]*zscale, -V[2]*zscale } // FuMa Z }; - for(ALsizei c{0};c < num_channels;c++) + for(ALuint c{0};c < num_channels;c++) { ComputePanGains(&Device->Dry, matrix[c], DryGain, voice->mChans[c].mDryParams.Gains.Target); - for(ALsizei i{0};i < NumSends;i++) + for(ALuint i{0};i < NumSends;i++) { if(const ALeffectslot *Slot{SendSlots[i]}) ComputePanGains(&Slot->Wet, matrix[c], WetGain[i], @@ -657,7 +656,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo */ voice->mDirect.Buffer = Device->RealOut.Buffer; - for(ALsizei c{0};c < num_channels;c++) + for(ALuint c{0};c < num_channels;c++) { const ALuint idx{GetChannelIdxByName(Device->RealOut, chans[c].channel)}; if(idx != INVALID_CHANNEL_INDEX) @@ -667,12 +666,12 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo /* Auxiliary sends still use normal channel panning since they mix to * B-Format, which can't channel-match. */ - for(ALsizei c{0};c < num_channels;c++) + for(ALuint c{0};c < num_channels;c++) { ALfloat coeffs[MAX_AMBI_CHANNELS]; CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); - for(ALsizei i{0};i < NumSends;i++) + for(ALuint i{0};i < NumSends;i++) { if(const ALeffectslot *Slot{SendSlots[i]}) ComputePanGains(&Slot->Wet, coeffs, WetGain[i], @@ -701,7 +700,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo voice->mChans[0].mDryParams.Hrtf.Target.Gain = DryGain * downmix_gain; /* Remaining channels use the same results as the first. */ - for(ALsizei c{1};c < num_channels;c++) + for(ALuint c{1};c < num_channels;c++) { /* Skip LFE */ if(chans[c].channel == LFE) continue; @@ -714,12 +713,12 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo ALfloat coeffs[MAX_AMBI_CHANNELS]; CalcDirectionCoeffs({xpos, ypos, zpos}, Spread, coeffs); - for(ALsizei c{0};c < num_channels;c++) + for(ALuint c{0};c < num_channels;c++) { /* Skip LFE */ if(chans[c].channel == LFE) continue; - for(ALsizei i{0};i < NumSends;i++) + for(ALuint i{0};i < NumSends;i++) { if(const ALeffectslot *Slot{SendSlots[i]}) ComputePanGains(&Slot->Wet, coeffs, WetGain[i] * downmix_gain, @@ -733,7 +732,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo * relative location around the listener, providing "virtual * speaker" responses. */ - for(ALsizei c{0};c < num_channels;c++) + for(ALuint c{0};c < num_channels;c++) { /* Skip LFE */ if(chans[c].channel == LFE) @@ -752,7 +751,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo ALfloat coeffs[MAX_AMBI_CHANNELS]; CalcAngleCoeffs(chans[c].angle, chans[c].elevation, Spread, coeffs); - for(ALsizei i{0};i < NumSends;i++) + for(ALuint i{0};i < NumSends;i++) { if(const ALeffectslot *Slot{SendSlots[i]}) ComputePanGains(&Slot->Wet, coeffs, WetGain[i], @@ -779,7 +778,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo const ALfloat w0{SPEEDOFSOUNDMETRESPERSEC / (mdist * Frequency)}; /* Adjust NFC filters. */ - for(ALsizei c{0};c < num_channels;c++) + for(ALuint c{0};c < num_channels;c++) voice->mChans[c].mDryParams.NFCtrlFilter.adjust(w0); voice->mFlags |= VOICE_HAS_NFC; @@ -798,7 +797,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo CalcAngleCoeffs(ScaleAzimuthFront(az, 1.5f), ev, Spread, coeffs); } - for(ALsizei c{0};c < num_channels;c++) + for(ALuint c{0};c < num_channels;c++) { /* Special-case LFE */ if(chans[c].channel == LFE) @@ -814,14 +813,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo ComputePanGains(&Device->Dry, coeffs, DryGain * downmix_gain, voice->mChans[c].mDryParams.Gains.Target); - } - - for(ALsizei c{0};c < num_channels;c++) - { - /* Skip LFE */ - if(chans[c].channel == LFE) - continue; - for(ALsizei i{0};i < NumSends;i++) + for(ALuint i{0};i < NumSends;i++) { if(const ALeffectslot *Slot{SendSlots[i]}) ComputePanGains(&Slot->Wet, coeffs, WetGain[i] * downmix_gain, @@ -840,13 +832,13 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo */ const ALfloat w0{SPEEDOFSOUNDMETRESPERSEC / (Device->AvgSpeakerDist * Frequency)}; - for(ALsizei c{0};c < num_channels;c++) + for(ALuint c{0};c < num_channels;c++) voice->mChans[c].mDryParams.NFCtrlFilter.adjust(w0); voice->mFlags |= VOICE_HAS_NFC; } - for(ALsizei c{0};c < num_channels;c++) + for(ALuint c{0};c < num_channels;c++) { /* Special-case LFE */ if(chans[c].channel == LFE) @@ -869,7 +861,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo ComputePanGains(&Device->Dry, coeffs, DryGain, voice->mChans[c].mDryParams.Gains.Target); - for(ALsizei i{0};i < NumSends;i++) + for(ALuint i{0};i < NumSends;i++) { if(const ALeffectslot *Slot{SendSlots[i]}) ComputePanGains(&Slot->Wet, coeffs, WetGain[i], @@ -894,13 +886,13 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo lowpass.rcpQFromSlope(gainHF, 1.0f)); highpass.setParams(BiquadType::LowShelf, gainLF, lfScale, highpass.rcpQFromSlope(gainLF, 1.0f)); - for(ALsizei c{1};c < num_channels;c++) + for(ALuint c{1};c < num_channels;c++) { voice->mChans[c].mDryParams.LowPass.copyParamsFrom(lowpass); voice->mChans[c].mDryParams.HighPass.copyParamsFrom(highpass); } } - for(ALsizei i{0};i < NumSends;i++) + for(ALuint i{0};i < NumSends;i++) { const ALfloat hfScale{props->Send[i].HFReference / Frequency}; const ALfloat lfScale{props->Send[i].LFReference / Frequency}; @@ -917,7 +909,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo lowpass.rcpQFromSlope(gainHF, 1.0f)); highpass.setParams(BiquadType::LowShelf, gainLF, lfScale, highpass.rcpQFromSlope(gainLF, 1.0f)); - for(ALsizei c{1};c < num_channels;c++) + for(ALuint c{1};c < num_channels;c++) { voice->mChans[c].mWetParams[i].LowPass.copyParamsFrom(lowpass); voice->mChans[c].mWetParams[i].HighPass.copyParamsFrom(highpass); @@ -931,7 +923,7 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons ALeffectslot *SendSlots[MAX_SENDS]; voice->mDirect.Buffer = Device->Dry.Buffer; - for(ALsizei i{0};i < Device->NumAuxSends;i++) + for(ALuint i{0};i < static_cast(Device->NumAuxSends);i++) { SendSlots[i] = props->Send[i].Slot; if(!SendSlots[i] && i == 0) @@ -982,7 +974,7 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const ALCcontext *ALContext) { const ALCdevice *Device{ALContext->mDevice.get()}; - const ALsizei NumSends{Device->NumAuxSends}; + const auto NumSends = static_cast(Device->NumAuxSends); const ALlistener &Listener = ALContext->mListener; /* Set mixing buffers and get send parameters. */ @@ -992,7 +984,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A ALfloat DecayDistance[MAX_SENDS]; ALfloat DecayLFDistance[MAX_SENDS]; ALfloat DecayHFDistance[MAX_SENDS]; - for(ALsizei i{0};i < NumSends;i++) + for(ALuint i{0};i < NumSends;i++) { SendSlots[i] = props->Send[i].Slot; if(!SendSlots[i] && i == 0) @@ -1071,7 +1063,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A ALfloat DryGainHF{1.0f}; ALfloat DryGainLF{1.0f}; ALfloat WetGain[MAX_SENDS], WetGainHF[MAX_SENDS], WetGainLF[MAX_SENDS]; - for(ALsizei i{0};i < NumSends;i++) + for(ALuint i{0};i < NumSends;i++) { WetGain[i] = props->Gain; WetGainHF[i] = 1.0f; @@ -1095,7 +1087,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A { ALfloat dist = lerp(props->RefDistance, ClampedDist, props->RolloffFactor); if(dist > 0.0f) DryGain *= props->RefDistance / dist; - for(ALsizei i{0};i < NumSends;i++) + for(ALuint i{0};i < NumSends;i++) { dist = lerp(props->RefDistance, ClampedDist, RoomRolloff[i]); if(dist > 0.0f) WetGain[i] *= props->RefDistance / dist; @@ -1115,7 +1107,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A ALfloat attn = props->RolloffFactor * (ClampedDist-props->RefDistance) / (props->MaxDistance-props->RefDistance); DryGain *= maxf(1.0f - attn, 0.0f); - for(ALsizei i{0};i < NumSends;i++) + for(ALuint i{0};i < NumSends;i++) { attn = RoomRolloff[i] * (ClampedDist-props->RefDistance) / (props->MaxDistance-props->RefDistance); @@ -1134,7 +1126,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A else { DryGain *= std::pow(ClampedDist/props->RefDistance, -props->RolloffFactor); - for(ALsizei i{0};i < NumSends;i++) + for(ALuint i{0};i < NumSends;i++) WetGain[i] *= std::pow(ClampedDist/props->RefDistance, -RoomRolloff[i]); } break; @@ -1188,7 +1180,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A DryGain = minf(DryGain*props->Direct.Gain*Listener.Params.Gain, GAIN_MIX_MAX); DryGainHF *= props->Direct.GainHF; DryGainLF *= props->Direct.GainLF; - for(ALsizei i{0};i < NumSends;i++) + for(ALuint i{0};i < NumSends;i++) { WetGain[i] = clampf(WetGain[i], props->MinGain, props->MaxGain); WetGain[i] = minf(WetGain[i]*props->Send[i].Gain*Listener.Params.Gain, GAIN_MIX_MAX); @@ -1217,7 +1209,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A * source distance in meters. The initial decay of the reverb * effect is calculated and applied to the wet path. */ - for(ALsizei i{0};i < NumSends;i++) + for(ALuint i{0};i < NumSends;i++) { if(!(DecayDistance[i] > 0.0f)) continue; @@ -1585,17 +1577,17 @@ template<> inline ALint SampleConv(ALfloat val) noexcept return fastf2i(clampf(val*2147483648.0f, -2147483648.0f, 2147483520.0f)); } template<> inline ALshort SampleConv(ALfloat val) noexcept -{ return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); } +{ return static_cast(fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f))); } template<> inline ALbyte SampleConv(ALfloat val) noexcept -{ return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); } +{ return static_cast(fastf2i(clampf(val*128.0f, -128.0f, 127.0f))); } /* Define unsigned output variations. */ template<> inline ALuint SampleConv(ALfloat val) noexcept -{ return SampleConv(val) + 2147483648u; } +{ return static_cast(SampleConv(val)) + 2147483648u; } template<> inline ALushort SampleConv(ALfloat val) noexcept -{ return SampleConv(val) + 32768; } +{ return static_cast(SampleConv(val) + 32768); } template<> inline ALubyte SampleConv(ALfloat val) noexcept -{ return SampleConv(val) + 128; } +{ return static_cast(SampleConv(val) + 128); } template void Write(const al::span InBuffer, ALvoid *OutBuffer, const size_t Offset, -- cgit v1.2.3 From df306b55245de7a281d695046e74717e4cdd511f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 13 Sep 2019 04:15:05 -0700 Subject: Make NumAuxSends unsigned --- al/source.cpp | 10 +++++----- al/source.h | 2 +- alc/alc.cpp | 33 ++++++++++++++++++--------------- alc/alcmain.h | 2 +- alc/alu.cpp | 8 ++++---- alc/mixvoice.cpp | 7 +++---- 6 files changed, 32 insertions(+), 30 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index 09b4133c..478ee3d2 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -522,7 +522,7 @@ bool EnsureSources(ALCcontext *context, size_t needed) return true; } -ALsource *AllocSource(ALCcontext *context, ALsizei num_sends) +ALsource *AllocSource(ALCcontext *context, ALuint num_sends) { auto sublist = std::find_if(context->mSourceList.begin(), context->mSourceList.end(), [](const SourceSubList &entry) noexcept -> bool @@ -1315,7 +1315,7 @@ bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a slotlock = std::unique_lock{Context->mEffectSlotLock}; if(values[0] && (slot=LookupEffectSlot(Context, static_cast(values[0]))) == nullptr) SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid effect ID %u", values[0]); - if(static_cast(values[1]) >= static_cast(device->NumAuxSends)) + if(static_cast(values[1]) >= device->NumAuxSends) SETERR_RETURN(Context, AL_INVALID_VALUE, false, "Invalid send %u", values[1]); filtlock = std::unique_lock{device->FilterLock}; @@ -2086,7 +2086,7 @@ START_API_FUNC } else { - const ALsizei num_sends{device->NumAuxSends}; + const ALuint num_sends{device->NumAuxSends}; al::vector ids; ids.reserve(static_cast(n)); do { @@ -3220,7 +3220,7 @@ START_API_FUNC END_API_FUNC -ALsource::ALsource(ALsizei num_sends) +ALsource::ALsource(ALuint num_sends) { InnerAngle = 360.0f; OuterAngle = 360.0f; @@ -3272,7 +3272,7 @@ ALsource::ALsource(ALsizei num_sends) Direct.HFReference = LOWPASSFREQREF; Direct.GainLF = 1.0f; Direct.LFReference = HIGHPASSFREQREF; - Send.resize(static_cast(num_sends)); + Send.resize(num_sends); for(auto &send : Send) { send.Slot = nullptr; diff --git a/al/source.h b/al/source.h index e0219a04..7ca889d7 100644 --- a/al/source.h +++ b/al/source.h @@ -117,7 +117,7 @@ struct ALsource { ALuint id{0}; - ALsource(ALsizei num_sends); + ALsource(ALuint num_sends); ~ALsource(); ALsource(const ALsource&) = delete; diff --git a/alc/alc.cpp b/alc/alc.cpp index a819bbf7..6d7228f5 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -1614,15 +1614,15 @@ static inline void UpdateClockBase(ALCdevice *device) */ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { - HrtfRequestMode hrtf_userreq = Hrtf_Default; - HrtfRequestMode hrtf_appreq = Hrtf_Default; - ALCenum gainLimiter = device->LimiterState; - const ALsizei old_sends = device->NumAuxSends; - ALsizei new_sends = device->NumAuxSends; + HrtfRequestMode hrtf_userreq{Hrtf_Default}; + HrtfRequestMode hrtf_appreq{Hrtf_Default}; + ALCenum gainLimiter{device->LimiterState}; + const ALCuint old_sends{device->NumAuxSends}; + ALCuint new_sends{device->NumAuxSends}; DevFmtChannels oldChans; DevFmtType oldType; ALboolean update_failed; - ALCsizei hrtf_id = -1; + ALCsizei hrtf_id{-1}; ALCuint oldFreq; if((!attrList || !attrList[0]) && device->Type == Loopback) @@ -1644,7 +1644,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ALuint numMono{device->NumMonoSources}; ALuint numStereo{device->NumStereoSources}; - ALsizei numSends{old_sends}; + ALuint numSends{old_sends}; #define TRACE_ATTR(a, v) TRACE("%s = %d\n", #a, v) while(attrList[attrIdx]) @@ -1694,9 +1694,10 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) break; case ALC_MAX_AUXILIARY_SENDS: - numSends = attrList[attrIdx + 1]; + numSends = static_cast(attrList[attrIdx + 1]); TRACE_ATTR(ALC_MAX_AUXILIARY_SENDS, numSends); - numSends = clampi(numSends, 0, MAX_SENDS); + if(numSends > INT_MAX) numSends = 0; + else numSends = minu(numSends, MAX_SENDS); break; case ALC_HRTF_SOFT: @@ -1828,7 +1829,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->NumStereoSources = numStereo; if(auto sendsopt = ConfigValueInt(devname, nullptr, "sends")) - new_sends = mini(numSends, clampi(*sendsopt, 0, MAX_SENDS)); + new_sends = minu(numSends, static_cast(clampi(*sendsopt, 0, MAX_SENDS))); else new_sends = numSends; } @@ -2176,7 +2177,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(device->NumAuxSends < old_sends) { - const ALsizei num_sends{device->NumAuxSends}; + const ALuint num_sends{device->NumAuxSends}; /* Clear extraneous property set sends. */ auto clear_sends = [num_sends](ALvoice &voice) -> void { @@ -2871,7 +2872,7 @@ static size_t GetIntegerv(ALCdevice *device, ALCenum param, const al::span(device->NumStereoSources); values[i++] = ALC_MAX_AUXILIARY_SENDS; - values[i++] = device->NumAuxSends; + values[i++] = static_cast(device->NumAuxSends); values[i++] = ALC_HRTF_SOFT; values[i++] = (device->mHrtf ? ALC_TRUE : ALC_FALSE); @@ -2984,7 +2985,7 @@ static size_t GetIntegerv(ALCdevice *device, ALCenum param, const al::spanNumAuxSends; + values[0] = static_cast(device->NumAuxSends); return 1; case ALC_CONNECTED: @@ -3647,7 +3648,8 @@ START_API_FUNC } if(auto sendsopt = ConfigValueInt(deviceName, nullptr, "sends")) - device->NumAuxSends = clampi(DEFAULT_SENDS, 0, clampi(*sendsopt, 0, MAX_SENDS)); + device->NumAuxSends = clampu(DEFAULT_SENDS, 0, + static_cast(clampi(*sendsopt, 0, MAX_SENDS))); device->NumStereoSources = 1; device->NumMonoSources = device->SourcesMax - device->NumStereoSources; @@ -3959,7 +3961,8 @@ START_API_FUNC } if(auto sendsopt = ConfigValueInt(nullptr, nullptr, "sends")) - device->NumAuxSends = clampi(DEFAULT_SENDS, 0, clampi(*sendsopt, 0, MAX_SENDS)); + device->NumAuxSends = clampu(DEFAULT_SENDS, 0, + static_cast(clampi(*sendsopt, 0, MAX_SENDS))); device->NumStereoSources = 1; device->NumMonoSources = device->SourcesMax - device->NumStereoSources; diff --git a/alc/alcmain.h b/alc/alcmain.h index fb93488f..338897ab 100644 --- a/alc/alcmain.h +++ b/alc/alcmain.h @@ -242,7 +242,7 @@ struct ALCdevice : public al::intrusive_ref { ALCuint NumMonoSources{}; ALCuint NumStereoSources{}; - ALsizei NumAuxSends{}; + ALCuint NumAuxSends{}; // Map of Buffers for this device std::mutex BufferLock; diff --git a/alc/alu.cpp b/alc/alu.cpp index d9464125..0def577e 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -451,7 +451,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo }; const auto Frequency = static_cast(Device->Frequency); - const auto NumSends = static_cast(Device->NumAuxSends); + const ALuint NumSends{Device->NumAuxSends}; bool DirectChannels{props->DirectChannels != AL_FALSE}; const ChanMap *chans{nullptr}; @@ -923,7 +923,7 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons ALeffectslot *SendSlots[MAX_SENDS]; voice->mDirect.Buffer = Device->Dry.Buffer; - for(ALuint i{0};i < static_cast(Device->NumAuxSends);i++) + for(ALuint i{0};i < Device->NumAuxSends;i++) { SendSlots[i] = props->Send[i].Slot; if(!SendSlots[i] && i == 0) @@ -958,7 +958,7 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons ALfloat DryGainHF{props->Direct.GainHF}; ALfloat DryGainLF{props->Direct.GainLF}; ALfloat WetGain[MAX_SENDS], WetGainHF[MAX_SENDS], WetGainLF[MAX_SENDS]; - for(ALsizei i{0};i < Device->NumAuxSends;i++) + for(ALuint i{0};i < Device->NumAuxSends;i++) { WetGain[i] = clampf(props->Gain, props->MinGain, props->MaxGain); WetGain[i] *= props->Send[i].Gain * Listener.Params.Gain; @@ -974,7 +974,7 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const ALCcontext *ALContext) { const ALCdevice *Device{ALContext->mDevice.get()}; - const auto NumSends = static_cast(Device->NumAuxSends); + const ALuint NumSends{Device->NumAuxSends}; const ALlistener &Listener = ALContext->mListener; /* Set mixing buffers and get send parameters. */ diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 3c621934..9d7dead4 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -495,10 +495,9 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) ASSUME(increment > 0); ALCdevice *Device{Context->mDevice.get()}; - const ALsizei NumSends{Device->NumAuxSends}; + const ALuint NumSends{Device->NumAuxSends}; const ALsizei IrSize{Device->mHrtf ? Device->mHrtf->irSize : 0}; - ASSUME(NumSends >= 0); ASSUME(IrSize >= 0); ResamplerFunc Resample{(increment == FRACTIONONE && DataPosFrac == 0) ? @@ -517,7 +516,7 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) std::begin(parms.Gains.Current)); else parms.Hrtf.Old = parms.Hrtf.Target; - for(ALsizei send{0};send < NumSends;++send) + for(ALuint send{0};send < NumSends;++send) { if(mSend[send].Buffer.empty()) continue; @@ -785,7 +784,7 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) } } - for(ALsizei send{0};send < NumSends;++send) + for(ALuint send{0};send < NumSends;++send) { if(mSend[send].Buffer.empty()) continue; -- cgit v1.2.3 From 42548885767fa1492886d87d17592e79bc00924e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 13 Sep 2019 09:38:35 -0700 Subject: Make IrSize unsigned --- alc/helpers.cpp | 6 +- alc/hrtf.cpp | 186 +++++++++++++++++++++++++-------------------------- alc/hrtf.h | 6 +- alc/mixer/hrtfbase.h | 2 +- alc/mixvoice.cpp | 12 ++-- alc/panning.cpp | 2 +- 6 files changed, 105 insertions(+), 109 deletions(-) diff --git a/alc/helpers.cpp b/alc/helpers.cpp index 84787637..46be5a3b 100644 --- a/alc/helpers.cpp +++ b/alc/helpers.cpp @@ -614,7 +614,7 @@ const PathNamePair &GetProcBinary() return ret; } - pathname.resize(len); + pathname.resize(static_cast(len)); } while(!pathname.empty() && pathname.back() == 0) pathname.pop_back(); @@ -651,8 +651,8 @@ static void DirectorySearch(const char *path, const char *ext, al::vectorsize(); + auto base = results->cend() - results->cbegin(); + const size_t extlen{strlen(ext)}; struct dirent *dirent; while((dirent=readdir(dir)) != nullptr) diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index 04818a4f..bd6ecb3a 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -257,7 +257,7 @@ void GetHrtfCoeffs(const HrtfEntry *Hrtf, ALfloat elevation, ALfloat azimuth, AL Hrtf->delays[idx[2]][1]*blend[2] + Hrtf->delays[idx[3]][1]*blend[3] ); - const ALsizei irSize{Hrtf->irSize}; + const ALuint irSize{Hrtf->irSize}; ASSUME(irSize >= MIN_IR_SIZE); /* Calculate the sample offsets for the HRIR indices. */ @@ -304,27 +304,26 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin ASSUME(AmbiCount > 0); auto &field = Hrtf->field[0]; - ALsizei min_delay{HRTF_HISTORY_LENGTH}; - ALsizei max_delay{0}; - auto idx = al::vector(AmbiCount); - auto calc_idxs = [Hrtf,&field,&max_delay,&min_delay](const AngularPoint &pt) noexcept -> ALsizei + ALuint min_delay{HRTF_HISTORY_LENGTH}; + ALuint max_delay{0}; + auto idx = al::vector(AmbiCount); + auto calc_idxs = [Hrtf,&field,&max_delay,&min_delay](const AngularPoint &pt) noexcept -> ALuint { /* Calculate elevation index. */ - const auto evidx = clampi( - static_cast((90.0f+pt.Elev)*(field.evCount-1)/180.0f + 0.5f), + const auto evidx = clampi(float2int((90.0f+pt.Elev)*(field.evCount-1)/180.0f + 0.5f), 0, field.evCount-1); - const ALsizei azcount{Hrtf->elev[evidx].azCount}; - const ALsizei iroffset{Hrtf->elev[evidx].irOffset}; + const ALuint azcount{Hrtf->elev[evidx].azCount}; + const ALuint iroffset{Hrtf->elev[evidx].irOffset}; /* Calculate azimuth index for this elevation. */ - const auto azidx = static_cast((360.0f+pt.Azim)*azcount/360.0f + 0.5f) % azcount; + const auto azidx = static_cast((360.0f+pt.Azim)*azcount/360.0f + 0.5f) % azcount; /* Calculate the index for the impulse response. */ - ALsizei idx{iroffset + azidx}; + ALuint idx{iroffset + azidx}; - min_delay = mini(min_delay, mini(Hrtf->delays[idx][0], Hrtf->delays[idx][1])); - max_delay = maxi(max_delay, maxi(Hrtf->delays[idx][0], Hrtf->delays[idx][1])); + min_delay = minu(min_delay, minu(Hrtf->delays[idx][0], Hrtf->delays[idx][1])); + max_delay = maxu(max_delay, maxu(Hrtf->delays[idx][0], Hrtf->delays[idx][1])); return idx; }; @@ -342,8 +341,8 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin for(size_t c{0u};c < AmbiCount;++c) { const ALfloat (*fir)[2]{&Hrtf->coeffs[idx[c] * Hrtf->irSize]}; - const ALsizei ldelay{Hrtf->delays[idx[c]][0] - min_delay + base_delay}; - const ALsizei rdelay{Hrtf->delays[idx[c]][1] - min_delay + base_delay}; + const ALuint ldelay{Hrtf->delays[idx[c]][0] - min_delay + base_delay}; + const ALuint rdelay{Hrtf->delays[idx[c]][1] - min_delay + base_delay}; if(!DualBand) { @@ -352,9 +351,9 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin { const ALdouble mult{ALdouble{AmbiOrderHFGain[OrderFromChan[i]]} * AmbiMatrix[c][i]}; - const ALsizei numirs{mini(Hrtf->irSize, HRIR_LENGTH-maxi(ldelay, rdelay))}; - ALsizei lidx{ldelay}, ridx{rdelay}; - for(ALsizei j{0};j < numirs;++j) + const ALuint numirs{minu(Hrtf->irSize, HRIR_LENGTH-maxu(ldelay, rdelay))}; + ALuint lidx{ldelay}, ridx{rdelay}; + for(ALuint j{0};j < numirs;++j) { tmpres[i][lidx++][0] += fir[j][0] * mult; tmpres[i][ridx++][1] += fir[j][1] * mult; @@ -394,8 +393,8 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin { const ALdouble mult{AmbiMatrix[c][i]}; const ALdouble hfgain{AmbiOrderHFGain[OrderFromChan[i]]}; - ALsizei j{HRIR_LENGTH*3 - ldelay}; - for(ALsizei lidx{0};lidx < HRIR_LENGTH;++lidx,++j) + ALuint j{HRIR_LENGTH*3 - ldelay}; + for(ALuint lidx{0};lidx < HRIR_LENGTH;++lidx,++j) tmpres[i][lidx][0] += (tmpfilt[0][j]*hfgain + tmpfilt[1][j]) * mult; } @@ -415,8 +414,8 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin { const ALdouble mult{AmbiMatrix[c][i]}; const ALdouble hfgain{AmbiOrderHFGain[OrderFromChan[i]]}; - ALsizei j{HRIR_LENGTH*3 - rdelay}; - for(ALsizei ridx{0};ridx < HRIR_LENGTH;++ridx,++j) + ALuint j{HRIR_LENGTH*3 - rdelay}; + for(ALuint ridx{0};ridx < HRIR_LENGTH;++ridx,++j) tmpres[i][ridx][1] += (tmpfilt[0][j]*hfgain + tmpfilt[1][j]) * mult; } } @@ -432,33 +431,33 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin } tmpres.clear(); - ALsizei max_length{HRIR_LENGTH}; + ALuint max_length{HRIR_LENGTH}; /* Increase the IR size by double the base delay with dual-band processing * to account for the head and tail from the HF response scale. */ - const ALsizei irsize{mini(Hrtf->irSize + base_delay*2, max_length)}; - max_length = mini(max_delay-min_delay + irsize, max_length); + const ALuint irsize{minu(Hrtf->irSize + base_delay*2, max_length)}; + max_length = minu(max_delay-min_delay + irsize, max_length); /* Round up to the next IR size multiple. */ max_length += MOD_IR_SIZE-1; max_length -= max_length%MOD_IR_SIZE; - TRACE("Skipped delay: %d, max delay: %d, new FIR length: %d\n", - min_delay, max_delay-min_delay, max_length); + TRACE("Skipped delay: %u, max delay: %u, new FIR length: %u\n", min_delay, max_delay-min_delay, + max_length); state->IrSize = max_length; } namespace { -std::unique_ptr CreateHrtfStore(ALuint rate, ALsizei irSize, const ALsizei fdCount, +std::unique_ptr CreateHrtfStore(ALuint rate, ALushort irSize, const ALuint fdCount, const ALubyte *evCount, const ALfloat *distance, const ALushort *azCount, - const ALushort *irOffset, ALsizei irCount, const ALfloat (*coeffs)[2], + const ALushort *irOffset, ALushort irCount, const ALfloat (*coeffs)[2], const ALubyte (*delays)[2], const char *filename) { std::unique_ptr Hrtf; - ALsizei evTotal{std::accumulate(evCount, evCount+fdCount, 0)}; + ALuint evTotal{std::accumulate(evCount, evCount+fdCount, 0u)}; size_t total{sizeof(HrtfEntry)}; total = RoundUp(total, alignof(HrtfEntry::Field)); /* Align for field infos */ total += sizeof(HrtfEntry::Field)*fdCount; @@ -500,22 +499,22 @@ std::unique_ptr CreateHrtfStore(ALuint rate, ALsizei irSize, const AL assert(offset == total); /* Copy input data to storage. */ - for(ALsizei i{0};i < fdCount;i++) + for(ALuint i{0};i < fdCount;i++) { field_[i].distance = distance[i]; field_[i].evCount = evCount[i]; } - for(ALsizei i{0};i < evTotal;i++) + for(ALuint i{0};i < evTotal;i++) { elev_[i].azCount = azCount[i]; elev_[i].irOffset = irOffset[i]; } - for(ALsizei i{0};i < irSize*irCount;i++) + for(ALuint i{0};i < irSize*irCount;i++) { coeffs_[i][0] = coeffs[i][0]; coeffs_[i][1] = coeffs[i][1]; } - for(ALsizei i{0};i < irCount;i++) + for(ALuint i{0};i < irCount;i++) { delays_[i][0] = delays[i][0]; delays_[i][1] = delays[i][1]; @@ -564,7 +563,7 @@ ALuint GetLE_ALuint(std::istream &data) ret |= data.get() << 8; ret |= data.get() << 16; ret |= data.get() << 24; - return ret; + return static_cast(ret); } std::unique_ptr LoadHrtf00(std::istream &data, const char *filename) @@ -603,12 +602,11 @@ std::unique_ptr LoadHrtf00(std::istream &data, const char *filename) ERR("Failed reading %s\n", filename); return nullptr; } - for(ALsizei i{1};i < evCount;i++) + for(size_t i{1};i < evCount;i++) { if(evOffset[i] <= evOffset[i-1]) { - ERR("Invalid evOffset: evOffset[%d]=%d (last=%d)\n", - i, evOffset[i], evOffset[i-1]); + ERR("Invalid evOffset: evOffset[%zu]=%d (last=%d)\n", i, evOffset[i], evOffset[i-1]); failed = AL_TRUE; } } @@ -622,12 +620,12 @@ std::unique_ptr LoadHrtf00(std::istream &data, const char *filename) return nullptr; al::vector azCount(evCount); - for(ALsizei i{1};i < evCount;i++) + for(size_t i{1};i < evCount;i++) { azCount[i-1] = evOffset[i] - evOffset[i-1]; if(azCount[i-1] < MIN_AZ_COUNT || azCount[i-1] > MAX_AZ_COUNT) { - ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", + ERR("Unsupported azimuth count: azCount[%zd]=%d (%d to %d)\n", i-1, azCount[i-1], MIN_AZ_COUNT, MAX_AZ_COUNT); failed = AL_TRUE; } @@ -653,11 +651,11 @@ std::unique_ptr LoadHrtf00(std::istream &data, const char *filename) ERR("Failed reading %s\n", filename); return nullptr; } - for(ALsizei i{0};i < irCount;i++) + for(size_t i{0};i < irCount;i++) { if(delays[i][0] > MAX_HRIR_DELAY) { - ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); + ERR("Invalid delays[%zd]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); failed = AL_TRUE; } } @@ -665,16 +663,16 @@ std::unique_ptr LoadHrtf00(std::istream &data, const char *filename) return nullptr; /* Mirror the left ear responses to the right ear. */ - for(ALsizei i{0};i < evCount;i++) + for(size_t i{0};i < evCount;i++) { const ALushort evoffset{evOffset[i]}; const ALushort azcount{azCount[i]}; - for(ALsizei j{0};j < azcount;j++) + for(size_t j{0};j < azcount;j++) { - const ALsizei lidx{evoffset + j}; - const ALsizei ridx{evoffset + ((azcount-j) % azcount)}; + const size_t lidx{evoffset + j}; + const size_t ridx{evoffset + ((azcount-j) % azcount)}; - for(ALsizei k{0};k < irSize;k++) + for(size_t k{0};k < irSize;k++) coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; delays[ridx][1] = delays[lidx][0]; } @@ -720,22 +718,22 @@ std::unique_ptr LoadHrtf01(std::istream &data, const char *filename) ERR("Failed reading %s\n", filename); return nullptr; } - for(ALsizei i{0};i < evCount;++i) + for(size_t i{0};i < evCount;++i) { if(azCount[i] < MIN_AZ_COUNT || azCount[i] > MAX_AZ_COUNT) { - ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", - i, azCount[i], MIN_AZ_COUNT, MAX_AZ_COUNT); + ERR("Unsupported azimuth count: azCount[%zd]=%d (%d to %d)\n", i, azCount[i], + MIN_AZ_COUNT, MAX_AZ_COUNT); failed = AL_TRUE; } } if(failed) return nullptr; - al::vector evOffset(evCount); + auto evOffset = al::vector(evCount); evOffset[0] = 0; ALushort irCount{azCount[0]}; - for(ALsizei i{1};i < evCount;i++) + for(size_t i{1};i < evCount;i++) { evOffset[i] = evOffset[i-1] + azCount[i-1]; irCount += azCount[i]; @@ -752,11 +750,11 @@ std::unique_ptr LoadHrtf01(std::istream &data, const char *filename) ERR("Failed reading %s\n", filename); return nullptr; } - for(ALsizei i{0};i < irCount;i++) + for(size_t i{0};i < irCount;i++) { if(delays[i][0] > MAX_HRIR_DELAY) { - ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); + ERR("Invalid delays[%zd]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); failed = AL_TRUE; } } @@ -764,16 +762,16 @@ std::unique_ptr LoadHrtf01(std::istream &data, const char *filename) return nullptr; /* Mirror the left ear responses to the right ear. */ - for(ALsizei i{0};i < evCount;i++) + for(size_t i{0};i < evCount;i++) { const ALushort evoffset{evOffset[i]}; const ALushort azcount{azCount[i]}; - for(ALsizei j{0};j < azcount;j++) + for(size_t j{0};j < azcount;j++) { - const ALsizei lidx{evoffset + j}; - const ALsizei ridx{evoffset + ((azcount-j) % azcount)}; + const size_t lidx{evoffset + j}; + const size_t ridx{evoffset + ((azcount-j) % azcount)}; - for(ALsizei k{0};k < irSize;k++) + for(size_t k{0};k < irSize;k++) coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; delays[ridx][1] = delays[lidx][0]; } @@ -831,10 +829,10 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) if(failed) return nullptr; - al::vector distance(fdCount); - al::vector evCount(fdCount); - al::vector azCount; - for(ALsizei f{0};f < fdCount;f++) + auto distance = al::vector(fdCount); + auto evCount = al::vector(fdCount); + auto azCount = al::vector{}; + for(size_t f{0};f < fdCount;f++) { distance[f] = GetLE_ALushort(data) / 1000.0f; evCount[f] = GetLE_ALubyte(data); @@ -846,28 +844,28 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) if(distance[f] < MIN_FD_DISTANCE || distance[f] > MAX_FD_DISTANCE) { - ERR("Unsupported field distance[%d]=%f (%f to %f meters)\n", f, - distance[f], MIN_FD_DISTANCE, MAX_FD_DISTANCE); + ERR("Unsupported field distance[%zu]=%f (%f to %f meters)\n", f, distance[f], + MIN_FD_DISTANCE, MAX_FD_DISTANCE); failed = AL_TRUE; } if(f > 0 && distance[f] <= distance[f-1]) { - ERR("Field distance[%d] is not after previous (%f > %f)\n", f, distance[f], + ERR("Field distance[%zu] is not after previous (%f > %f)\n", f, distance[f], distance[f-1]); failed = AL_TRUE; } if(evCount[f] < MIN_EV_COUNT || evCount[f] > MAX_EV_COUNT) { - ERR("Unsupported elevation count: evCount[%d]=%d (%d to %d)\n", f, - evCount[f], MIN_EV_COUNT, MAX_EV_COUNT); + ERR("Unsupported elevation count: evCount[%zu]=%d (%d to %d)\n", f, evCount[f], + MIN_EV_COUNT, MAX_EV_COUNT); failed = AL_TRUE; } if(failed) return nullptr; - size_t ebase{azCount.size()}; + const size_t ebase{azCount.size()}; azCount.resize(ebase + evCount[f]); - std::generate(azCount.begin()+ebase, azCount.end(), + std::generate(azCount.begin()+static_cast(ebase), azCount.end(), std::bind(GetLE_ALubyte, std::ref(data))); if(!data || data.eof()) { @@ -875,11 +873,11 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) return nullptr; } - for(ALsizei e{0};e < evCount[f];e++) + for(size_t e{0};e < evCount[f];e++) { if(azCount[ebase+e] < MIN_AZ_COUNT || azCount[ebase+e] > MAX_AZ_COUNT) { - ERR("Unsupported azimuth count: azCount[%d][%d]=%d (%d to %d)\n", f, e, + ERR("Unsupported azimuth count: azCount[%zu][%zu]=%d (%d to %d)\n", f, e, azCount[ebase+e], MIN_AZ_COUNT, MAX_AZ_COUNT); failed = AL_TRUE; } @@ -888,13 +886,13 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) return nullptr; } - al::vector evOffset(azCount.size()); + auto evOffset = al::vector(azCount.size()); evOffset[0] = 0; std::partial_sum(azCount.cbegin(), azCount.cend()-1, evOffset.begin()+1); - const ALsizei irTotal{evOffset.back() + azCount.back()}; + const auto irTotal = static_cast(evOffset.back() + azCount.back()); - al::vector> coeffs(irSize*irTotal); - al::vector> delays(irTotal); + auto coeffs = al::vector>(irSize*irTotal); + auto delays = al::vector>(irTotal); if(channelType == CHANTYPE_LEFTONLY) { if(sampleType == SAMPLETYPE_S16) @@ -914,11 +912,11 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) ERR("Failed reading %s\n", filename); return nullptr; } - for(ALsizei i{0};i < irTotal;++i) + for(size_t i{0};i < irTotal;++i) { if(delays[i][0] > MAX_HRIR_DELAY) { - ERR("Invalid delays[%d][0]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); + ERR("Invalid delays[%zu][0]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); failed = AL_TRUE; } } @@ -952,16 +950,16 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) return nullptr; } - for(ALsizei i{0};i < irTotal;++i) + for(size_t i{0};i < irTotal;++i) { if(delays[i][0] > MAX_HRIR_DELAY) { - ERR("Invalid delays[%d][0]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); + ERR("Invalid delays[%zu][0]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY); failed = AL_TRUE; } if(delays[i][1] > MAX_HRIR_DELAY) { - ERR("Invalid delays[%d][1]: %d (%d)\n", i, delays[i][1], MAX_HRIR_DELAY); + ERR("Invalid delays[%zu][1]: %d (%d)\n", i, delays[i][1], MAX_HRIR_DELAY); failed = AL_TRUE; } } @@ -972,19 +970,19 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) if(channelType == CHANTYPE_LEFTONLY) { /* Mirror the left ear responses to the right ear. */ - ALsizei ebase{0}; - for(ALsizei f{0};f < fdCount;f++) + size_t ebase{0}; + for(size_t f{0};f < fdCount;f++) { - for(ALsizei e{0};e < evCount[f];e++) + for(size_t e{0};e < evCount[f];e++) { const ALushort evoffset{evOffset[ebase+e]}; const ALushort azcount{azCount[ebase+e]}; - for(ALsizei a{0};a < azcount;a++) + for(size_t a{0};a < azcount;a++) { - const ALsizei lidx{evoffset + a}; - const ALsizei ridx{evoffset + ((azcount-a) % azcount)}; + const size_t lidx{evoffset + a}; + const size_t ridx{evoffset + ((azcount-a) % azcount)}; - for(ALsizei k{0};k < irSize;k++) + for(size_t k{0};k < irSize;k++) coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; delays[ridx][1] = delays[lidx][0]; } @@ -1011,13 +1009,13 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) * of per-group azimuth counts. */ auto azcnt_end = azCount_.end(); - auto copy_azs = [&azCount,&azcnt_end](const size_t ebase, const ALubyte num_evs) -> size_t + auto copy_azs = [&azCount,&azcnt_end](const ptrdiff_t ebase, const ALubyte num_evs) -> ptrdiff_t { auto azcnt_src = azCount.begin()+ebase; azcnt_end = std::copy_backward(azcnt_src, azcnt_src+num_evs, azcnt_end); return ebase + num_evs; }; - std::accumulate(evCount.cbegin(), evCount.cend(), size_t{0u}, copy_azs); + std::accumulate(evCount.cbegin(), evCount.cend(), ptrdiff_t{0}, copy_azs); assert(azCount_.begin() == azcnt_end); /* Reestablish the IR offset for each elevation index, given the new @@ -1029,7 +1027,7 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) /* Reverse the order of each field's group of IRs. */ auto coeffs_end = coeffs_.end(); auto delays_end = delays_.end(); - auto copy_irs = [irSize,&azCount,&coeffs,&delays,&coeffs_end,&delays_end](const size_t ebase, const ALubyte num_evs) -> size_t + auto copy_irs = [irSize,&azCount,&coeffs,&delays,&coeffs_end,&delays_end](const ptrdiff_t ebase, const ALubyte num_evs) -> ptrdiff_t { const ALsizei abase{std::accumulate(azCount.cbegin(), azCount.cbegin()+ebase, 0)}; const ALsizei num_azs{std::accumulate(azCount.cbegin()+ebase, @@ -1042,7 +1040,7 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) return ebase + num_evs; }; - std::accumulate(evCount.cbegin(), evCount.cend(), size_t{0u}, copy_irs); + std::accumulate(evCount.cbegin(), evCount.cend(), ptrdiff_t{0}, copy_irs); assert(coeffs_.begin() == coeffs_end); assert(delays_.begin() == delays_end); @@ -1293,9 +1291,9 @@ HrtfEntry *GetLoadedHrtf(HrtfHandle *handle) std::unique_ptr stream; const char *name{""}; - ALuint residx{}; + ALint residx{}; char ch{}; - if(sscanf(handle->filename.data(), "!%u%c", &residx, &ch) == 2 && ch == '_') + if(sscanf(handle->filename.data(), "!%d%c", &residx, &ch) == 2 && ch == '_') { name = strchr(handle->filename.data(), ch)+1; diff --git a/alc/hrtf.h b/alc/hrtf.h index 85614f2e..92b3fd96 100644 --- a/alc/hrtf.h +++ b/alc/hrtf.h @@ -29,7 +29,7 @@ struct HrtfEntry { RefCount ref; ALuint sampleRate; - ALsizei irSize; + ALuint irSize; struct Field { ALfloat distance; @@ -38,7 +38,7 @@ struct HrtfEntry { /* NOTE: Fields are stored *backwards*. field[0] is the farthest field, and * field[fdCount-1] is the nearest. */ - ALsizei fdCount; + ALuint fdCount; const Field *field; struct Elevation { @@ -78,7 +78,7 @@ struct HrtfFilter { struct DirectHrtfState { /* HRTF filter state for dry buffer content */ - ALsizei IrSize{0}; + ALuint IrSize{0}; alignas(16) HrirArray Values; al::FlexArray Coeffs; diff --git a/alc/mixer/hrtfbase.h b/alc/mixer/hrtfbase.h index 0309fe5d..dd33ce2d 100644 --- a/alc/mixer/hrtfbase.h +++ b/alc/mixer/hrtfbase.h @@ -103,7 +103,7 @@ inline void MixDirectHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOu { ASSUME(BufferSize > 0); - const ALsizei IrSize{State->IrSize}; + const auto IrSize = static_cast(State->IrSize); auto accum_iter = std::copy_n(State->Values.begin(), State->Values.size(), AccumSamples); std::fill_n(accum_iter, BufferSize, float2{}); diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 9d7dead4..c3598612 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -496,9 +496,7 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) ALCdevice *Device{Context->mDevice.get()}; const ALuint NumSends{Device->NumAuxSends}; - const ALsizei IrSize{Device->mHrtf ? Device->mHrtf->irSize : 0}; - - ASSUME(IrSize >= 0); + const ALuint IrSize{Device->mHrtf ? Device->mHrtf->irSize : 0}; ResamplerFunc Resample{(increment == FRACTIONONE && DataPosFrac == 0) ? Resample_ : mResampler}; @@ -700,8 +698,8 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) hrtfparams.GainStep = gain / static_cast(fademix); MixHrtfBlendSamples(mDirect.Buffer[OutLIdx], mDirect.Buffer[OutRIdx], - HrtfSamples, AccumSamples, OutPos, IrSize, &parms.Hrtf.Old, - &hrtfparams, fademix); + HrtfSamples, AccumSamples, OutPos, static_cast(IrSize), + &parms.Hrtf.Old, &hrtfparams, fademix); /* Update the old parameters with the result. */ parms.Hrtf.Old = parms.Hrtf.Target; if(fademix < Counter) @@ -733,8 +731,8 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) hrtfparams.GainStep = (gain - parms.Hrtf.Old.Gain) / static_cast(todo); MixHrtfSamples(mDirect.Buffer[OutLIdx], mDirect.Buffer[OutRIdx], - HrtfSamples+fademix, AccumSamples+fademix, OutPos+fademix, IrSize, - &hrtfparams, todo); + HrtfSamples+fademix, AccumSamples+fademix, OutPos+fademix, + static_cast(IrSize), &hrtfparams, todo); /* Store the interpolated gain or the final target gain * depending if the fade is done. */ diff --git a/alc/panning.cpp b/alc/panning.cpp index 31daf455..b5394cbc 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -219,7 +219,7 @@ bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALuint (&speakerm else { ERR("AmbDec speaker label \"%s\" not recognized\n", name); - return -1; + return INVALID_CHANNEL_INDEX; } } const ALuint chidx{GetChannelIdxByName(device->RealOut, ch)}; -- cgit v1.2.3 From f09734b707c3036345d602cc187cc21248a54abd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 13 Sep 2019 11:19:11 -0700 Subject: Pass IrSize to the HRTF mixers as unsigned --- alc/alu.h | 4 ++-- alc/mixer/defs.h | 4 ++-- alc/mixer/hrtfbase.h | 8 ++++---- alc/mixer/mixer_c.cpp | 8 ++++---- alc/mixer/mixer_neon.cpp | 8 ++++---- alc/mixer/mixer_sse.cpp | 10 +++++----- alc/mixvoice.cpp | 8 ++++---- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/alc/alu.h b/alc/alu.h index aca7790e..cf021285 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -322,10 +322,10 @@ using MixerFunc = void(*)(const al::span InSamples, using RowMixerFunc = void(*)(const al::span OutBuffer, const al::span Gains, const float *InSamples, const size_t InStride); using HrtfMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALsizei IrSize, + const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize); using HrtfMixerBlendFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALsizei IrSize, + const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize); using HrtfDirectMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, diff --git a/alc/mixer/defs.h b/alc/mixer/defs.h index a6e07bd4..62e7d3ba 100644 --- a/alc/mixer/defs.h +++ b/alc/mixer/defs.h @@ -38,9 +38,9 @@ void MixRow_(const al::span OutBuffer, const al::span Gains, const float *InSamples, const size_t InStride); template -void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALsizei IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize); +void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize); template -void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALsizei IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize); +void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize); template void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, const size_t BufferSize); diff --git a/alc/mixer/hrtfbase.h b/alc/mixer/hrtfbase.h index dd33ce2d..d2432e90 100644 --- a/alc/mixer/hrtfbase.h +++ b/alc/mixer/hrtfbase.h @@ -8,13 +8,13 @@ #include "opthelpers.h" -using ApplyCoeffsT = void(size_t Offset, float2 *RESTRICT Values, const ALsizei irSize, +using ApplyCoeffsT = void(size_t Offset, float2 *RESTRICT Values, const ALuint irSize, const HrirArray &Coeffs, const ALfloat left, const ALfloat right); template inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *RESTRICT AccumSamples, const size_t OutPos, - const ALsizei IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) + const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) { ASSUME(BufferSize > 0); @@ -48,7 +48,7 @@ inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *RESTRICT AccumSamples, const size_t OutPos, - const ALsizei IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, + const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { const auto &OldCoeffs = oldparams->Coeffs; @@ -103,7 +103,7 @@ inline void MixDirectHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOu { ASSUME(BufferSize > 0); - const auto IrSize = static_cast(State->IrSize); + const ALuint IrSize{State->IrSize}; auto accum_iter = std::copy_n(State->Values.begin(), State->Values.size(), AccumSamples); std::fill_n(accum_iter, BufferSize, float2{}); diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index c5e712f9..720b264b 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -98,11 +98,11 @@ const ALfloat *Resample_(const InterpState *state, const ALfloat { return DoResample(state, src-state->bsinc.l, frac, increment, dst); } -static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const ALsizei IrSize, +static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const ALuint IrSize, const HrirArray &Coeffs, const ALfloat left, const ALfloat right) { ASSUME(IrSize >= 4); - for(ALsizei c{0};c < IrSize;++c) + for(ALuint c{0};c < IrSize;++c) { Values[c][0] += Coeffs[c][0] * left; Values[c][1] += Coeffs[c][1] * right; @@ -111,7 +111,7 @@ static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const template<> void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALsizei IrSize, + const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) { MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, @@ -120,7 +120,7 @@ void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALsizei IrSize, + const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index c0a8e628..852bef38 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -121,7 +121,7 @@ const ALfloat *Resample_(const InterpState *state, const ALflo } -static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const ALsizei IrSize, +static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const ALuint IrSize, const HrirArray &Coeffs, const ALfloat left, const ALfloat right) { ASSUME(IrSize >= 4); @@ -134,7 +134,7 @@ static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const leftright4 = vcombine_f32(leftright2, leftright2); } - for(ALsizei c{0};c < IrSize;c += 2) + for(ALuint c{0};c < IrSize;c += 2) { float32x4_t vals = vld1q_f32(&Values[c][0]); float32x4_t coefs = vld1q_f32(&Coeffs[c][0]); @@ -147,7 +147,7 @@ static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const template<> void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALsizei IrSize, + const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) { MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, @@ -156,7 +156,7 @@ void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALsizei IrSize, + const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index 82e2bfbe..368b8dfe 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -68,7 +68,7 @@ const ALfloat *Resample_(const InterpState *state, const ALfloa } -static inline void ApplyCoeffs(size_t Offset, float2 *RESTRICT Values, const ALsizei IrSize, +static inline void ApplyCoeffs(size_t Offset, float2 *RESTRICT Values, const ALuint IrSize, const HrirArray &Coeffs, const ALfloat left, const ALfloat right) { const __m128 lrlr{_mm_setr_ps(left, right, left, right)}; @@ -83,7 +83,7 @@ static inline void ApplyCoeffs(size_t Offset, float2 *RESTRICT Values, const ALs imp0 = _mm_mul_ps(lrlr, coeffs); vals = _mm_add_ps(imp0, vals); _mm_storel_pi(reinterpret_cast<__m64*>(&Values[0][0]), vals); - ALsizei i{1}; + ALuint i{1}; for(;i < IrSize-1;i += 2) { coeffs = _mm_load_ps(&Coeffs[i+1][0]); @@ -101,7 +101,7 @@ static inline void ApplyCoeffs(size_t Offset, float2 *RESTRICT Values, const ALs } else { - for(ALsizei i{0};i < IrSize;i += 2) + for(ALuint i{0};i < IrSize;i += 2) { __m128 coeffs{_mm_load_ps(&Coeffs[i][0])}; __m128 vals{_mm_load_ps(&Values[i][0])}; @@ -113,7 +113,7 @@ static inline void ApplyCoeffs(size_t Offset, float2 *RESTRICT Values, const ALs template<> void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALsizei IrSize, + const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) { MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, @@ -122,7 +122,7 @@ void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALsizei IrSize, + const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index c3598612..7bdeea5e 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -698,8 +698,8 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) hrtfparams.GainStep = gain / static_cast(fademix); MixHrtfBlendSamples(mDirect.Buffer[OutLIdx], mDirect.Buffer[OutRIdx], - HrtfSamples, AccumSamples, OutPos, static_cast(IrSize), - &parms.Hrtf.Old, &hrtfparams, fademix); + HrtfSamples, AccumSamples, OutPos, IrSize, &parms.Hrtf.Old, + &hrtfparams, fademix); /* Update the old parameters with the result. */ parms.Hrtf.Old = parms.Hrtf.Target; if(fademix < Counter) @@ -731,8 +731,8 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) hrtfparams.GainStep = (gain - parms.Hrtf.Old.Gain) / static_cast(todo); MixHrtfSamples(mDirect.Buffer[OutLIdx], mDirect.Buffer[OutRIdx], - HrtfSamples+fademix, AccumSamples+fademix, OutPos+fademix, - static_cast(IrSize), &hrtfparams, todo); + HrtfSamples+fademix, AccumSamples+fademix, OutPos+fademix, IrSize, + &hrtfparams, todo); /* Store the interpolated gain or the final target gain * depending if the fade is done. */ -- cgit v1.2.3 From fcd3bed0c0923ca2eff463e0e6cffc60e00f4a7d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 13 Sep 2019 12:51:16 -0700 Subject: Clean up more implicit conversions --- alc/backends/base.cpp | 3 ++- alc/backends/sdl2.cpp | 16 +++++++++------- alc/backends/wave.cpp | 30 +++++++++++++++--------------- alc/helpers.cpp | 6 +++--- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/alc/backends/base.cpp b/alc/backends/base.cpp index 095990b7..c4c6052b 100644 --- a/alc/backends/base.cpp +++ b/alc/backends/base.cpp @@ -53,7 +53,8 @@ ClockLatency BackendBase::getClockLatency() * any given time during playback. Without a more accurate measurement from * the output, this is an okay approximation. */ - ret.Latency = std::chrono::seconds{maxi(mDevice->BufferSize-mDevice->UpdateSize, 0)}; + ret.Latency = std::max(std::chrono::seconds{mDevice->BufferSize-mDevice->UpdateSize}, + std::chrono::seconds::zero()); ret.Latency /= mDevice->Frequency; return ret; diff --git a/alc/backends/sdl2.cpp b/alc/backends/sdl2.cpp index 4b3b5e63..28d020a1 100644 --- a/alc/backends/sdl2.cpp +++ b/alc/backends/sdl2.cpp @@ -62,7 +62,7 @@ struct Sdl2Backend final : public BackendBase { void unlock() override; SDL_AudioDeviceID mDeviceID{0u}; - ALsizei mFrameSize{0}; + ALuint mFrameSize{0}; ALuint mFrequency{0u}; DevFmtChannels mFmtChans{}; @@ -84,14 +84,16 @@ void Sdl2Backend::audioCallbackC(void *ptr, Uint8 *stream, int len) void Sdl2Backend::audioCallback(Uint8 *stream, int len) { - assert((len % mFrameSize) == 0); - aluMixData(mDevice, stream, len / mFrameSize); + const auto ulen = static_cast(len); + assert((ulen % mFrameSize) == 0); + aluMixData(mDevice, stream, ulen / mFrameSize); } ALCenum Sdl2Backend::open(const ALCchar *name) { SDL_AudioSpec want{}, have{}; - want.freq = mDevice->Frequency; + + want.freq = static_cast(mDevice->Frequency); switch(mDevice->FmtType) { case DevFmtUByte: want.format = AUDIO_U8; break; @@ -103,7 +105,7 @@ ALCenum Sdl2Backend::open(const ALCchar *name) case DevFmtFloat: want.format = AUDIO_F32; break; } want.channels = (mDevice->FmtChans == DevFmtMono) ? 1 : 2; - want.samples = mDevice->UpdateSize; + want.samples = static_cast(mDevice->UpdateSize); want.callback = &Sdl2Backend::audioCallbackC; want.userdata = this; @@ -126,7 +128,7 @@ ALCenum Sdl2Backend::open(const ALCchar *name) if(mDeviceID == 0) return ALC_INVALID_VALUE; - mDevice->Frequency = have.freq; + mDevice->Frequency = static_cast(have.freq); if(have.channels == 1) mDevice->FmtChans = DevFmtMono; else if(have.channels == 2) @@ -151,7 +153,7 @@ ALCenum Sdl2Backend::open(const ALCchar *name) mDevice->UpdateSize = have.samples; mDevice->BufferSize = have.samples * 2; /* SDL always (tries to) use two periods. */ - mFrameSize = mDevice->frameSizeFromFmt(); + mFrameSize = static_cast(mDevice->frameSizeFromFmt()); mFrequency = mDevice->Frequency; mFmtChans = mDevice->FmtChans; mFmtType = mDevice->FmtType; diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp index b16f711b..20f0d3f2 100644 --- a/alc/backends/wave.cpp +++ b/alc/backends/wave.cpp @@ -125,7 +125,7 @@ int WaveBackend::mixerProc() althrd_setname(MIXER_THREAD_NAME); - const ALsizei frameSize{mDevice->frameSizeFromFmt()}; + const auto frameSize = static_cast(mDevice->frameSizeFromFmt()); int64_t done{0}; auto start = std::chrono::steady_clock::now(); @@ -159,8 +159,8 @@ int WaveBackend::mixerProc() const size_t len{mBuffer.size() / 2}; for(size_t i{0};i < len;i++) { - ALushort samp = samples[i]; - samples[i] = (samp>>8) | (samp<<8); + const ALushort samp{samples[i]}; + samples[i] = static_cast((samp>>8) | (samp<<8)); } } else if(bytesize == 4) @@ -169,7 +169,7 @@ int WaveBackend::mixerProc() const size_t len{mBuffer.size() / 4}; for(size_t i{0};i < len;i++) { - ALuint samp = samples[i]; + const ALuint samp{samples[i]}; samples[i] = (samp>>24) | ((samp>>8)&0x0000ff00) | ((samp<<8)&0x00ff0000) | (samp<<24); } @@ -281,8 +281,8 @@ ALCboolean WaveBackend::reset() chanmask = 0; break; } - bytes = mDevice->bytesFromFmt(); - channels = mDevice->channelsFromFmt(); + bytes = static_cast(mDevice->bytesFromFmt()); + channels = static_cast(mDevice->channelsFromFmt()); rewind(mFile); @@ -297,25 +297,25 @@ ALCboolean WaveBackend::reset() // 16-bit val, format type id (extensible: 0xFFFE) fwrite16le(0xFFFE, mFile); // 16-bit val, channel count - fwrite16le(channels, mFile); + fwrite16le(static_cast(channels), mFile); // 32-bit val, frequency fwrite32le(mDevice->Frequency, mFile); // 32-bit val, bytes per second fwrite32le(mDevice->Frequency * channels * bytes, mFile); // 16-bit val, frame size - fwrite16le(channels * bytes, mFile); + fwrite16le(static_cast(channels * bytes), mFile); // 16-bit val, bits per sample - fwrite16le(bytes * 8, mFile); + fwrite16le(static_cast(bytes * 8), mFile); // 16-bit val, extra byte count fwrite16le(22, mFile); // 16-bit val, valid bits per sample - fwrite16le(bytes * 8, mFile); + fwrite16le(static_cast(bytes * 8), mFile); // 32-bit val, channel mask fwrite32le(chanmask, mFile); // 16 byte GUID, sub-type format val = fwrite((mDevice->FmtType == DevFmtFloat) ? - (isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) : - (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM), 1, 16, mFile); + (isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) : + (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM), 1, 16, mFile); (void)val; fputs("data", mFile); @@ -330,7 +330,7 @@ ALCboolean WaveBackend::reset() SetDefaultWFXChannelOrder(mDevice); - const ALuint bufsize{mDevice->frameSizeFromFmt() * mDevice->UpdateSize}; + const ALuint bufsize{static_cast(mDevice->frameSizeFromFmt())*mDevice->UpdateSize}; mBuffer.resize(bufsize); return ALC_TRUE; @@ -362,9 +362,9 @@ void WaveBackend::stop() { long dataLen{size - mDataStart}; if(fseek(mFile, mDataStart-4, SEEK_SET) == 0) - fwrite32le(dataLen, mFile); // 'data' header len + fwrite32le(static_cast(dataLen), mFile); // 'data' header len if(fseek(mFile, 4, SEEK_SET) == 0) - fwrite32le(size-8, mFile); // 'WAVE' header len + fwrite32le(static_cast(size-8), mFile); // 'WAVE' header len } } diff --git a/alc/helpers.cpp b/alc/helpers.cpp index 46be5a3b..77f96fb8 100644 --- a/alc/helpers.cpp +++ b/alc/helpers.cpp @@ -81,13 +81,13 @@ #if defined(HAVE_GCC_GET_CPUID) && (defined(__i386__) || defined(__x86_64__) || \ defined(_M_IX86) || defined(_M_X64)) using reg_type = unsigned int; -static inline void get_cpuid(int f, reg_type *regs) +static inline void get_cpuid(unsigned int f, reg_type *regs) { __get_cpuid(f, ®s[0], ®s[1], ®s[2], ®s[3]); } #define CAN_GET_CPUID #elif defined(HAVE_CPUID_INTRINSIC) && (defined(__i386__) || defined(__x86_64__) || \ defined(_M_IX86) || defined(_M_X64)) using reg_type = int; -static inline void get_cpuid(int f, reg_type *regs) +static inline void get_cpuid(unsigned int f, reg_type *regs) { (__cpuid)(regs, f); } #define CAN_GET_CPUID #endif @@ -104,7 +104,7 @@ void FillCPUCaps(int capfilter) union { reg_type regs[4]; char str[sizeof(reg_type[4])]; - } cpuinf[3] = {{ { 0, 0, 0, 0 } }}; + } cpuinf[3]{}; get_cpuid(0, cpuinf[0].regs); if(cpuinf[0].regs[0] == 0) -- cgit v1.2.3 From a250b6a98639571eedcaaf858d014d22eb008999 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 13 Sep 2019 14:29:25 -0700 Subject: Return unsigned values from the FromDevFmt functions --- alc/alc.cpp | 6 ++--- alc/alcmain.h | 6 ++--- alc/backends/dsound.cpp | 4 ++-- alc/backends/jack.cpp | 12 ++++------ alc/backends/oss.cpp | 59 ++++++++++++++++++++-------------------------- alc/backends/portaudio.cpp | 10 ++++---- alc/backends/sdl2.cpp | 2 +- alc/backends/sndio.cpp | 13 +++++----- alc/backends/solaris.cpp | 8 +++---- alc/backends/wasapi.cpp | 5 ++-- alc/backends/wave.cpp | 10 ++++---- alc/converter.cpp | 7 +++--- alc/devformat.h | 6 ++--- 13 files changed, 67 insertions(+), 81 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index 6d7228f5..9bb604a4 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -1272,7 +1272,7 @@ const ALCchar *DevFmtChannelsString(DevFmtChannels chans) noexcept return "(unknown channels)"; } -ALsizei BytesFromDevFmt(DevFmtType type) noexcept +ALuint BytesFromDevFmt(DevFmtType type) noexcept { switch(type) { @@ -1286,7 +1286,7 @@ ALsizei BytesFromDevFmt(DevFmtType type) noexcept } return 0; } -ALsizei ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept +ALuint ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept { switch(chans) { @@ -1297,7 +1297,7 @@ ALsizei ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept case DevFmtX51Rear: return 6; case DevFmtX61: return 7; case DevFmtX71: return 8; - case DevFmtAmbi3D: return (ambiorder+1) * (ambiorder+1); + case DevFmtAmbi3D: return static_cast((ambiorder+1) * (ambiorder+1)); } return 0; } diff --git a/alc/alcmain.h b/alc/alcmain.h index 338897ab..f7842d96 100644 --- a/alc/alcmain.h +++ b/alc/alcmain.h @@ -340,9 +340,9 @@ struct ALCdevice : public al::intrusive_ref { ALCdevice& operator=(const ALCdevice&) = delete; ~ALCdevice(); - ALsizei bytesFromFmt() const noexcept { return BytesFromDevFmt(FmtType); } - ALsizei channelsFromFmt() const noexcept { return ChannelsFromDevFmt(FmtChans, mAmbiOrder); } - ALsizei frameSizeFromFmt() const noexcept { return bytesFromFmt() * channelsFromFmt(); } + ALuint bytesFromFmt() const noexcept { return BytesFromDevFmt(FmtType); } + ALuint channelsFromFmt() const noexcept { return ChannelsFromDevFmt(FmtChans, mAmbiOrder); } + ALuint frameSizeFromFmt() const noexcept { return bytesFromFmt() * channelsFromFmt(); } void ProcessHrtf(const size_t SamplesToDo); void ProcessAmbiDec(const size_t SamplesToDo); diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index ad182cf7..1c44c2ec 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -219,7 +219,7 @@ FORCE_ALIGN int DSoundPlayback::mixerProc() return 1; } - ALsizei FrameSize{mDevice->frameSizeFromFmt()}; + ALuint FrameSize{mDevice->frameSizeFromFmt()}; DWORD FragSize{mDevice->UpdateSize * FrameSize}; bool Playing{false}; @@ -820,7 +820,7 @@ ALCuint DSoundCapture::availableSamples() if(!mDevice->Connected.load(std::memory_order_acquire)) return static_cast(mRing->readSpace()); - ALsizei FrameSize{mDevice->frameSizeFromFmt()}; + ALuint FrameSize{mDevice->frameSizeFromFmt()}; DWORD BufferBytes{mBufferBytes}; DWORD LastCursor{mCursor}; diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp index e688b96b..e1ae91f0 100644 --- a/alc/backends/jack.cpp +++ b/alc/backends/jack.cpp @@ -235,7 +235,7 @@ int JackPlayback::process(jack_nframes_t numframes) } auto data = mRing->getReadVector(); - jack_nframes_t todo{minu(numframes, data.first.len)}; + jack_nframes_t todo{minu(numframes, static_cast(data.first.len))}; std::transform(out, out+numchans, out, [&data,numchans,todo](ALfloat *outbuf) -> ALfloat* { @@ -254,7 +254,7 @@ int JackPlayback::process(jack_nframes_t numframes) ); jack_nframes_t total{todo}; - todo = minu(numframes-total, data.second.len); + todo = minu(numframes-total, static_cast(data.second.len)); if(todo > 0) { std::transform(out, out+numchans, out, @@ -315,8 +315,8 @@ int JackPlayback::mixerProc() auto todo = static_cast(data.first.len + data.second.len); todo -= todo%mDevice->UpdateSize; - ALuint len1{minu(data.first.len, todo)}; - ALuint len2{minu(data.second.len, todo-len1)}; + ALuint len1{minu(static_cast(data.first.len), todo)}; + ALuint len2{minu(static_cast(data.second.len), todo-len1)}; aluMixData(mDevice, data.first.buf, len1); if(len2 > 0) @@ -382,8 +382,7 @@ ALCboolean JackPlayback::reset() /* Force 32-bit float output. */ mDevice->FmtType = DevFmtFloat; - ALsizei numchans{mDevice->channelsFromFmt()}; - auto ports_end = std::begin(mPort) + numchans; + auto ports_end = std::begin(mPort) + mDevice->channelsFromFmt(); auto bad_port = std::find_if_not(std::begin(mPort), ports_end, [this](jack_port_t *&port) -> bool { @@ -410,7 +409,6 @@ ALCboolean JackPlayback::reset() } mDevice->FmtChans = DevFmtStereo; } - numchans = std::distance(std::begin(mPort), bad_port); } mRing = nullptr; diff --git a/alc/backends/oss.cpp b/alc/backends/oss.cpp index 8cfe9e96..48794a50 100644 --- a/alc/backends/oss.cpp +++ b/alc/backends/oss.cpp @@ -230,10 +230,10 @@ done: #endif -int log2i(ALCuint x) +ALCuint log2i(ALCuint x) { - int y = 0; - while (x > 1) + ALCuint y{0}; + while(x > 1) { x >>= 1; y++; @@ -276,7 +276,7 @@ int OSSPlayback::mixerProc() SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - const int frame_size{mDevice->frameSizeFromFmt()}; + const ALuint frame_size{mDevice->frameSizeFromFmt()}; lock(); while(!mKillNow.load(std::memory_order_acquire) && @@ -319,7 +319,7 @@ int OSSPlayback::mixerProc() break; } - to_write -= wrote; + to_write -= static_cast(wrote); write_ptr += wrote; } } @@ -361,16 +361,7 @@ ALCenum OSSPlayback::open(const ALCchar *name) ALCboolean OSSPlayback::reset() { - int numFragmentsLogSize; - int log2FragmentSize; - unsigned int periods; - audio_buf_info info; - ALuint frameSize; - int numChannels; - int ossFormat; - int ossSpeed; - const char *err; - + int ossFormat{}; switch(mDevice->FmtType) { case DevFmtByte: @@ -390,14 +381,16 @@ ALCboolean OSSPlayback::reset() break; } - periods = mDevice->BufferSize / mDevice->UpdateSize; - numChannels = mDevice->channelsFromFmt(); - ossSpeed = mDevice->Frequency; - frameSize = numChannels * mDevice->bytesFromFmt(); + ALuint periods{mDevice->BufferSize / mDevice->UpdateSize}; + ALuint numChannels{mDevice->channelsFromFmt()}; + ALuint ossSpeed{mDevice->Frequency}; + ALuint frameSize{numChannels * mDevice->bytesFromFmt()}; /* According to the OSS spec, 16 bytes (log2(16)) is the minimum. */ - log2FragmentSize = maxi(log2i(mDevice->UpdateSize*frameSize), 4); - numFragmentsLogSize = (periods << 16) | log2FragmentSize; + ALuint log2FragmentSize{maxu(log2i(mDevice->UpdateSize*frameSize), 4)}; + ALuint numFragmentsLogSize{(periods << 16) | log2FragmentSize}; + audio_buf_info info{}; + const char *err; #define CHECKERR(func) if((func) < 0) { \ err = #func; \ goto err; \ @@ -434,8 +427,8 @@ ALCboolean OSSPlayback::reset() } mDevice->Frequency = ossSpeed; - mDevice->UpdateSize = info.fragsize / frameSize; - mDevice->BufferSize = info.fragments * mDevice->UpdateSize; + mDevice->UpdateSize = static_cast(info.fragsize) / frameSize; + mDevice->BufferSize = static_cast(info.fragments) * mDevice->UpdateSize; SetDefaultChannelOrder(mDevice); @@ -505,7 +498,7 @@ int OSScapture::recordProc() SetRTPriority(); althrd_setname(RECORD_THREAD_NAME); - const int frame_size{mDevice->frameSizeFromFmt()}; + const ALuint frame_size{mDevice->frameSizeFromFmt()}; while(!mKillNow.load(std::memory_order_acquire)) { pollfd pollitem{}; @@ -592,17 +585,15 @@ ALCenum OSScapture::open(const ALCchar *name) return ALC_INVALID_VALUE; } - int periods{4}; - int numChannels{mDevice->channelsFromFmt()}; - int frameSize{numChannels * mDevice->bytesFromFmt()}; - int ossSpeed{static_cast(mDevice->Frequency)}; - int log2FragmentSize{log2i(mDevice->BufferSize * frameSize / periods)}; - + ALuint periods{4}; + ALuint numChannels{mDevice->channelsFromFmt()}; + ALuint frameSize{numChannels * mDevice->bytesFromFmt()}; + ALuint ossSpeed{mDevice->Frequency}; /* according to the OSS spec, 16 bytes are the minimum */ - log2FragmentSize = std::max(log2FragmentSize, 4); - int numFragmentsLogSize{(periods << 16) | log2FragmentSize}; + ALuint log2FragmentSize{maxu(log2i(mDevice->BufferSize * frameSize / periods), 4)}; + ALuint numFragmentsLogSize{(periods << 16) | log2FragmentSize}; - audio_buf_info info; + audio_buf_info info{}; const char *err; #define CHECKERR(func) if((func) < 0) { \ err = #func; \ @@ -687,7 +678,7 @@ ALCenum OSScapture::captureSamples(ALCvoid *buffer, ALCuint samples) } ALCuint OSScapture::availableSamples() -{ return mRing->readSpace(); } +{ return static_cast(mRing->readSpace()); } } // namespace diff --git a/alc/backends/portaudio.cpp b/alc/backends/portaudio.cpp index fcfd4b01..4704a806 100644 --- a/alc/backends/portaudio.cpp +++ b/alc/backends/portaudio.cpp @@ -114,7 +114,7 @@ int PortPlayback::writeCallback(const void*, void *outputBuffer, const PaStreamCallbackFlags) { lock(); - aluMixData(mDevice, outputBuffer, framesPerBuffer); + aluMixData(mDevice, outputBuffer, static_cast(framesPerBuffer)); unlock(); return 0; } @@ -182,7 +182,7 @@ retry_open: ALCboolean PortPlayback::reset() { const PaStreamInfo *streamInfo{Pa_GetStreamInfo(mStream)}; - mDevice->Frequency = streamInfo->sampleRate; + mDevice->Frequency = static_cast(streamInfo->sampleRate); mDevice->UpdateSize = mUpdateSize; if(mParams.sampleFormat == paInt8) @@ -293,7 +293,7 @@ ALCenum PortCapture::open(const ALCchar *name) ALuint samples{mDevice->BufferSize}; samples = maxu(samples, 100 * mDevice->Frequency / 1000); - ALsizei frame_size{mDevice->frameSizeFromFmt()}; + ALuint frame_size{mDevice->frameSizeFromFmt()}; mRing = CreateRingBuffer(samples, frame_size, false); if(!mRing) return ALC_INVALID_VALUE; @@ -326,7 +326,7 @@ ALCenum PortCapture::open(const ALCchar *name) ERR("%s samples not supported\n", DevFmtTypeString(mDevice->FmtType)); return ALC_INVALID_VALUE; } - mParams.channelCount = mDevice->channelsFromFmt(); + mParams.channelCount = static_cast(mDevice->channelsFromFmt()); PaError err{Pa_OpenStream(&mStream, &mParams, nullptr, mDevice->Frequency, paFramesPerBufferUnspecified, paNoFlag, &PortCapture::readCallbackC, this)}; @@ -361,7 +361,7 @@ void PortCapture::stop() ALCuint PortCapture::availableSamples() -{ return mRing->readSpace(); } +{ return static_cast(mRing->readSpace()); } ALCenum PortCapture::captureSamples(ALCvoid *buffer, ALCuint samples) { diff --git a/alc/backends/sdl2.cpp b/alc/backends/sdl2.cpp index 28d020a1..6af0ac9d 100644 --- a/alc/backends/sdl2.cpp +++ b/alc/backends/sdl2.cpp @@ -153,7 +153,7 @@ ALCenum Sdl2Backend::open(const ALCchar *name) mDevice->UpdateSize = have.samples; mDevice->BufferSize = have.samples * 2; /* SDL always (tries to) use two periods. */ - mFrameSize = static_cast(mDevice->frameSizeFromFmt()); + mFrameSize = mDevice->frameSizeFromFmt(); mFrequency = mDevice->Frequency; mFmtChans = mDevice->FmtChans; mFmtType = mDevice->FmtType; diff --git a/alc/backends/sndio.cpp b/alc/backends/sndio.cpp index c7a86670..4a470e82 100644 --- a/alc/backends/sndio.cpp +++ b/alc/backends/sndio.cpp @@ -76,16 +76,16 @@ int SndioPlayback::mixerProc() SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - const ALsizei frameSize{mDevice->frameSizeFromFmt()}; + const ALuint frameSize{mDevice->frameSizeFromFmt()}; while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) { - auto WritePtr = static_cast(mBuffer.data()); + ALubyte *WritePtr{mBuffer.data()}; size_t len{mBuffer.size()}; lock(); - aluMixData(mDevice, WritePtr, len/frameSize); + aluMixData(mDevice, WritePtr, static_cast(len/frameSize)); unlock(); while(len > 0 && !mKillNow.load(std::memory_order_acquire)) { @@ -277,7 +277,7 @@ int SndioCapture::recordProc() SetRTPriority(); althrd_setname(RECORD_THREAD_NAME); - const ALsizei frameSize{mDevice->frameSizeFromFmt()}; + const ALuint frameSize{mDevice->frameSizeFromFmt()}; while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) @@ -396,8 +396,7 @@ ALCenum SndioCapture::open(const ALCchar *name) (mDevice->FmtType == DevFmtUShort && par.bits == 16 && par.sig == 0) || (mDevice->FmtType == DevFmtInt && par.bits == 32 && par.sig != 0) || (mDevice->FmtType == DevFmtUInt && par.bits == 32 && par.sig == 0)) || - mDevice->channelsFromFmt() != static_cast(par.rchan) || - mDevice->Frequency != par.rate) + mDevice->channelsFromFmt() != par.rchan || mDevice->Frequency != par.rate) { ERR("Failed to set format %s %s %uhz, got %c%u %u-channel %uhz instead\n", DevFmtTypeString(mDevice->FmtType), DevFmtChannelsString(mDevice->FmtChans), @@ -457,7 +456,7 @@ ALCenum SndioCapture::captureSamples(void *buffer, ALCuint samples) } ALCuint SndioCapture::availableSamples() -{ return mRing->readSpace(); } +{ return static_cast(mRing->readSpace()); } } // namespace diff --git a/alc/backends/solaris.cpp b/alc/backends/solaris.cpp index 584f6e66..2e8fe458 100644 --- a/alc/backends/solaris.cpp +++ b/alc/backends/solaris.cpp @@ -88,7 +88,7 @@ int SolarisBackend::mixerProc() SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - const int frame_size{mDevice->frameSizeFromFmt()}; + const ALuint frame_size{mDevice->frameSizeFromFmt()}; lock(); while(!mKillNow.load(std::memory_order_acquire) && @@ -169,7 +169,7 @@ ALCboolean SolarisBackend::reset() if(mDevice->FmtChans != DevFmtMono) mDevice->FmtChans = DevFmtStereo; - ALsizei numChannels{mDevice->channelsFromFmt()}; + ALuint numChannels{mDevice->channelsFromFmt()}; info.play.channels = numChannels; switch(mDevice->FmtType) @@ -194,7 +194,7 @@ ALCboolean SolarisBackend::reset() break; } - ALsizei frameSize{numChannels * mDevice->bytesFromFmt()}; + ALuint frameSize{numChannels * mDevice->bytesFromFmt()}; info.play.buffer_size = mDevice->BufferSize * frameSize; if(ioctl(mFd, AUDIO_SETINFO, &info) < 0) @@ -203,7 +203,7 @@ ALCboolean SolarisBackend::reset() return ALC_FALSE; } - if(mDevice->channelsFromFmt() != (ALsizei)info.play.channels) + if(mDevice->channelsFromFmt() != info.play.channels) { ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(mDevice->FmtChans), info.play.channels); diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 806db122..55c95146 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -1565,9 +1565,8 @@ HRESULT WasapiCapture::resetProxy() if(mDevice->Frequency != OutputType.Format.nSamplesPerSec || mDevice->FmtType != srcType) { - mSampleConv = CreateSampleConverter(srcType, mDevice->FmtType, - static_cast(mDevice->channelsFromFmt()), OutputType.Format.nSamplesPerSec, - mDevice->Frequency, BSinc24Resampler); + mSampleConv = CreateSampleConverter(srcType, mDevice->FmtType, mDevice->channelsFromFmt(), + OutputType.Format.nSamplesPerSec, mDevice->Frequency, BSinc24Resampler); if(!mSampleConv) { ERR("Failed to create converter for %s format, dst: %s %uhz, src: %s %luhz\n", diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp index 20f0d3f2..f1171747 100644 --- a/alc/backends/wave.cpp +++ b/alc/backends/wave.cpp @@ -125,7 +125,7 @@ int WaveBackend::mixerProc() althrd_setname(MIXER_THREAD_NAME); - const auto frameSize = static_cast(mDevice->frameSizeFromFmt()); + const ALuint frameSize{mDevice->frameSizeFromFmt()}; int64_t done{0}; auto start = std::chrono::steady_clock::now(); @@ -151,7 +151,7 @@ int WaveBackend::mixerProc() if(!IS_LITTLE_ENDIAN) { - const ALsizei bytesize{mDevice->bytesFromFmt()}; + const ALuint bytesize{mDevice->bytesFromFmt()}; if(bytesize == 2) { @@ -281,8 +281,8 @@ ALCboolean WaveBackend::reset() chanmask = 0; break; } - bytes = static_cast(mDevice->bytesFromFmt()); - channels = static_cast(mDevice->channelsFromFmt()); + bytes = mDevice->bytesFromFmt(); + channels = mDevice->channelsFromFmt(); rewind(mFile); @@ -330,7 +330,7 @@ ALCboolean WaveBackend::reset() SetDefaultWFXChannelOrder(mDevice); - const ALuint bufsize{static_cast(mDevice->frameSizeFromFmt())*mDevice->UpdateSize}; + const ALuint bufsize{mDevice->frameSizeFromFmt() * mDevice->UpdateSize}; mBuffer.resize(bufsize); return ALC_TRUE; diff --git a/alc/converter.cpp b/alc/converter.cpp index 87a9d275..2913f533 100644 --- a/alc/converter.cpp +++ b/alc/converter.cpp @@ -152,8 +152,8 @@ SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, SampleConverterPtr converter{new (FamCount{numchans}) SampleConverter{numchans}}; converter->mSrcType = srcType; converter->mDstType = dstType; - converter->mSrcTypeSize = static_cast(BytesFromDevFmt(srcType)); - converter->mDstTypeSize = static_cast(BytesFromDevFmt(dstType)); + converter->mSrcTypeSize = BytesFromDevFmt(srcType); + converter->mDstTypeSize = BytesFromDevFmt(dstType); converter->mSrcPrepCount = 0; converter->mFracOffset = 0; @@ -360,6 +360,5 @@ void ChannelConverter::convert(const ALvoid *src, ALfloat *dst, ALuint frames) c } } else - LoadSamples(dst, src, 1u, mSrcType, - frames*static_cast(ChannelsFromDevFmt(mSrcChans, 0))); + LoadSamples(dst, src, 1u, mSrcType, frames * ChannelsFromDevFmt(mSrcChans, 0)); } diff --git a/alc/devformat.h b/alc/devformat.h index 95fe5fbd..674dd848 100644 --- a/alc/devformat.h +++ b/alc/devformat.h @@ -97,9 +97,9 @@ template<> struct DevFmtTypeTraits { using Type = ALfloat; }; -ALsizei BytesFromDevFmt(DevFmtType type) noexcept; -ALsizei ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept; -inline ALsizei FrameSizeFromDevFmt(DevFmtChannels chans, DevFmtType type, ALsizei ambiorder) noexcept +ALuint BytesFromDevFmt(DevFmtType type) noexcept; +ALuint ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept; +inline ALuint FrameSizeFromDevFmt(DevFmtChannels chans, DevFmtType type, ALsizei ambiorder) noexcept { return ChannelsFromDevFmt(chans, ambiorder) * BytesFromDevFmt(type); } enum class AmbiLayout { -- cgit v1.2.3 From 42ae95b8fafb0ea1fa676b1e0f67b23fd375a817 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 13 Sep 2019 14:44:52 -0700 Subject: Remove a couple no-op statements --- al/buffer.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/al/buffer.cpp b/al/buffer.cpp index 42db68a8..f1f792e9 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -166,14 +166,12 @@ void DecodeMSADPCMBlock(ALshort *dst, const al::byte *src, size_t numchans, size { samples[c][0] = static_cast(al::to_integer(src[0]) | (al::to_integer(src[1])<<8)); - samples[c][0] = (samples[c][0]^0x8000) - 32768; src += 2; } for(size_t c{0};c < numchans;c++) { samples[c][1] = static_cast(al::to_integer(src[0]) | (al::to_integer(src[1])<<8)); - samples[c][1] = (samples[c][1]^0x8000) - 32768; src += 2; } -- cgit v1.2.3 From 2646f509ee686f21458c32a990346be6e2a806d1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 13 Sep 2019 20:04:22 -0700 Subject: Store the ambisonic order as unsigned --- alc/alc.cpp | 14 +++++++------- alc/alcmain.h | 4 ++-- alc/backends/wave.cpp | 2 +- alc/bformatdec.cpp | 7 +++---- alc/bformatdec.h | 4 ++-- alc/devformat.h | 4 ++-- alc/panning.cpp | 8 ++++---- 7 files changed, 21 insertions(+), 22 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index 9bb604a4..408b3ca3 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -1286,7 +1286,7 @@ ALuint BytesFromDevFmt(DevFmtType type) noexcept } return 0; } -ALuint ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept +ALuint ChannelsFromDevFmt(DevFmtChannels chans, ALuint ambiorder) noexcept { switch(chans) { @@ -1297,7 +1297,7 @@ ALuint ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept case DevFmtX51Rear: return 6; case DevFmtX61: return 7; case DevFmtX71: return 8; - case DevFmtAmbi3D: return static_cast((ambiorder+1) * (ambiorder+1)); + case DevFmtAmbi3D: return (ambiorder+1) * (ambiorder+1); } return 0; } @@ -1639,7 +1639,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ALCenum schans{AL_NONE}; ALCenum stype{AL_NONE}; ALCsizei attrIdx{0}; - ALCsizei aorder{0}; + ALCuint aorder{0}; ALCuint freq{0u}; ALuint numMono{device->NumMonoSources}; @@ -1677,7 +1677,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) break; case ALC_AMBISONIC_ORDER_SOFT: - aorder = attrList[attrIdx + 1]; + aorder = static_cast(attrList[attrIdx + 1]); TRACE_ATTR(ALC_AMBISONIC_ORDER_SOFT, aorder); break; @@ -2855,7 +2855,7 @@ static size_t GetIntegerv(ALCdevice *device, ALCenum param, const al::span(device->mAmbiScale); values[i++] = ALC_AMBISONIC_ORDER_SOFT; - values[i++] = device->mAmbiOrder; + values[i++] = static_cast(device->mAmbiOrder); } values[i++] = ALC_FORMAT_CHANNELS_SOFT; @@ -2973,7 +2973,7 @@ static size_t GetIntegerv(ALCdevice *device, ALCenum param, const al::spanmAmbiOrder; + values[0] = static_cast(device->mAmbiOrder); return 1; case ALC_MONO_SOURCES: @@ -3558,7 +3558,7 @@ START_API_FUNC static constexpr struct ChannelMap { const char name[16]; DevFmtChannels chans; - ALsizei order; + ALuint order; } chanlist[] = { { "mono", DevFmtMono, 0 }, { "stereo", DevFmtStereo, 0 }, diff --git a/alc/alcmain.h b/alc/alcmain.h index f7842d96..933ee779 100644 --- a/alc/alcmain.h +++ b/alc/alcmain.h @@ -213,9 +213,9 @@ struct ALCdevice : public al::intrusive_ref { ALuint BufferSize{}; DevFmtChannels FmtChans{}; - DevFmtType FmtType{}; + DevFmtType FmtType{}; ALboolean IsHeadphones{AL_FALSE}; - ALsizei mAmbiOrder{0}; + ALuint mAmbiOrder{0}; /* For DevFmtAmbi* output only, specifies the channel order and * normalization. */ diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp index f1171747..41d0a880 100644 --- a/alc/backends/wave.cpp +++ b/alc/backends/wave.cpp @@ -274,7 +274,7 @@ ALCboolean WaveBackend::reset() case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break; case DevFmtAmbi3D: /* .amb output requires FuMa */ - mDevice->mAmbiOrder = mini(mDevice->mAmbiOrder, 3); + mDevice->mAmbiOrder = minu(mDevice->mAmbiOrder, 3); mDevice->mAmbiLayout = AmbiLayout::FuMa; mDevice->mAmbiScale = AmbiNorm::FuMa; isbformat = 1; diff --git a/alc/bformatdec.cpp b/alc/bformatdec.cpp index 17b0d3d9..9fbe32b8 100644 --- a/alc/bformatdec.cpp +++ b/alc/bformatdec.cpp @@ -31,7 +31,7 @@ constexpr ALfloat Ambi3DDecoderHFScale3O[MAX_AMBI_ORDER+1] = { 5.89792205e-01f, 8.79693856e-01f }; -inline auto GetDecoderHFScales(ALsizei order) noexcept -> const ALfloat(&)[MAX_AMBI_ORDER+1] +inline auto GetDecoderHFScales(ALuint order) noexcept -> const ALfloat(&)[MAX_AMBI_ORDER+1] { if(order >= 3) return Ambi3DDecoderHFScale3O; if(order == 2) return Ambi3DDecoderHFScale2O; @@ -187,17 +187,16 @@ void BFormatDec::process(const al::span OutBuffer, } -std::array BFormatDec::GetHFOrderScales(const ALsizei in_order, const ALsizei out_order) noexcept +std::array BFormatDec::GetHFOrderScales(const ALuint in_order, const ALuint out_order) noexcept { std::array ret{}; assert(out_order >= in_order); - ASSUME(out_order >= in_order); const ALfloat (&target)[MAX_AMBI_ORDER+1] = GetDecoderHFScales(out_order); const ALfloat (&input)[MAX_AMBI_ORDER+1] = GetDecoderHFScales(in_order); - for(ALsizei i{0};i < in_order+1;++i) + for(ALuint i{0};i < in_order+1;++i) ret[i] = input[i] / target[i]; return ret; diff --git a/alc/bformatdec.h b/alc/bformatdec.h index dc8059b0..edbb6d50 100644 --- a/alc/bformatdec.h +++ b/alc/bformatdec.h @@ -53,8 +53,8 @@ public: const size_t SamplesToDo); /* Retrieves per-order HF scaling factors for "upsampling" ambisonic data. */ - static std::array GetHFOrderScales(const ALsizei in_order, - const ALsizei out_order) noexcept; + static std::array GetHFOrderScales(const ALuint in_order, + const ALuint out_order) noexcept; DEF_NEWDEL(BFormatDec) }; diff --git a/alc/devformat.h b/alc/devformat.h index 674dd848..e7ff2ec4 100644 --- a/alc/devformat.h +++ b/alc/devformat.h @@ -98,8 +98,8 @@ struct DevFmtTypeTraits { using Type = ALfloat; }; ALuint BytesFromDevFmt(DevFmtType type) noexcept; -ALuint ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept; -inline ALuint FrameSizeFromDevFmt(DevFmtChannels chans, DevFmtType type, ALsizei ambiorder) noexcept +ALuint ChannelsFromDevFmt(DevFmtChannels chans, ALuint ambiorder) noexcept; +inline ALuint FrameSizeFromDevFmt(DevFmtChannels chans, DevFmtType type, ALuint ambiorder) noexcept { return ChannelsFromDevFmt(chans, ambiorder) * BytesFromDevFmt(type); } enum class AmbiLayout { diff --git a/alc/panning.cpp b/alc/panning.cpp index b5394cbc..8feff9a9 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -269,7 +269,7 @@ constexpr ChannelMap MonoCfg[1] = { { BackRight, { 2.04124145e-1f, -1.08880247e-1f, -1.88586120e-1f, 1.29099444e-1f, 7.45355993e-2f, -3.73460789e-2f, 0.00000000e+0f } }, }; -void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, +void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALuint order, const al::span chans_per_order) { /* NFC is only used when AvgSpeakerDist is greater than 0. */ @@ -448,7 +448,7 @@ void InitPanning(ALCdevice *device) * channel count. Built-in speaker decoders are always 2D, so just * reverse that calculation. */ - device->mAmbiOrder = static_cast((coeffcount-1) / 2); + device->mAmbiOrder = (coeffcount-1) / 2; std::transform(AmbiIndex::From2D.begin(), AmbiIndex::From2D.begin()+coeffcount, std::begin(device->Dry.AmbiMap), @@ -478,7 +478,7 @@ void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, const ALuint order{(conf->ChanMask > AMBI_2ORDER_MASK) ? 3u : (conf->ChanMask > AMBI_1ORDER_MASK) ? 2u : 1u}; - device->mAmbiOrder = static_cast(order); + device->mAmbiOrder = order; ALuint count; if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) @@ -582,7 +582,7 @@ void InitHrtfPanning(ALCdevice *device) * and it eases the CPU/memory load. */ device->mRenderMode = HrtfRender; - ALsizei ambi_order{1}; + ALuint ambi_order{1}; if(auto modeopt = ConfigValueStr(device->DeviceName.c_str(), nullptr, "hrtf-mode")) { const char *mode{modeopt->c_str()}; -- cgit v1.2.3 From 88364dcbc75ba73d68a3069e09b9cb17d15bd06b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 14 Sep 2019 08:29:02 -0700 Subject: Fix more implicit conversions --- alc/alconfig.cpp | 2 +- alc/ambidefs.h | 9 +++++---- alc/panning.cpp | 33 +++++++++++++++++---------------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/alc/alconfig.cpp b/alc/alconfig.cpp index 93c37703..8ca81bc8 100644 --- a/alc/alconfig.cpp +++ b/alc/alconfig.cpp @@ -189,7 +189,7 @@ void LoadConfigFromFile(std::istream &f) (section[2] >= 'a' && section[2] <= 'f') || (section[2] >= 'A' && section[2] <= 'F'))) { - unsigned char b = 0; + int b{0}; if(section[1] >= '0' && section[1] <= '9') b = (section[1]-'0') << 4; else if(section[1] >= 'a' && section[1] <= 'f') diff --git a/alc/ambidefs.h b/alc/ambidefs.h index 17a9815b..9bc3e969 100644 --- a/alc/ambidefs.h +++ b/alc/ambidefs.h @@ -2,6 +2,7 @@ #define AMBIDEFS_H #include +#include /* The maximum number of Ambisonics channels. For a given order (o), the size * needed will be (o+1)**2, thus zero-order has 1, first-order has 4, second- @@ -84,7 +85,7 @@ struct AmbiScale { }; struct AmbiIndex { - static constexpr std::array FromFuMa{{ + static constexpr std::array FromFuMa{{ 0, /* W */ 3, /* X */ 1, /* Y */ @@ -102,15 +103,15 @@ struct AmbiIndex { 15, /* P */ 9, /* Q */ }}; - static constexpr std::array FromACN{{ + static constexpr std::array FromACN{{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }}; - static constexpr std::array From2D{{ + static constexpr std::array From2D{{ 0, 1,3, 4,8, 9,15 }}; - static constexpr std::array From3D{{ + static constexpr std::array From3D{{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }}; diff --git a/alc/panning.cpp b/alc/panning.cpp index 8feff9a9..018296d3 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -60,10 +60,10 @@ constexpr std::array AmbiScale::FromN3D; constexpr std::array AmbiScale::FromSN3D; constexpr std::array AmbiScale::FromFuMa; -constexpr std::array AmbiIndex::FromFuMa; -constexpr std::array AmbiIndex::FromACN; -constexpr std::array AmbiIndex::From2D; -constexpr std::array AmbiIndex::From3D; +constexpr std::array AmbiIndex::FromFuMa; +constexpr std::array AmbiIndex::FromACN; +constexpr std::array AmbiIndex::From2D; +constexpr std::array AmbiIndex::From3D; namespace { @@ -352,7 +352,7 @@ auto GetAmbiScales(AmbiNorm scaletype) noexcept -> const std::array const std::array& +auto GetAmbiLayout(AmbiLayout layouttype) noexcept -> const std::array& { if(layouttype == AmbiLayout::FuMa) return AmbiIndex::FromFuMa; return AmbiIndex::FromACN; @@ -408,13 +408,13 @@ void InitPanning(ALCdevice *device) if(device->FmtChans == DevFmtAmbi3D) { const char *devname{device->DeviceName.c_str()}; - const std::array &acnmap = GetAmbiLayout(device->mAmbiLayout); + const std::array &acnmap = GetAmbiLayout(device->mAmbiLayout); const std::array &n3dscale = GetAmbiScales(device->mAmbiScale); /* For DevFmtAmbi3D, the ambisonic order is already set. */ const size_t count{AmbiChannelsFromOrder(device->mAmbiOrder)}; std::transform(acnmap.begin(), acnmap.begin()+count, std::begin(device->Dry.AmbiMap), - [&n3dscale](const ALsizei &acn) noexcept -> BFChannelConfig + [&n3dscale](const uint8_t &acn) noexcept -> BFChannelConfig { return BFChannelConfig{1.0f/n3dscale[acn], acn}; } ); AllocChannels(device, static_cast(count), 0); @@ -452,7 +452,7 @@ void InitPanning(ALCdevice *device) std::transform(AmbiIndex::From2D.begin(), AmbiIndex::From2D.begin()+coeffcount, std::begin(device->Dry.AmbiMap), - [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } + [](const uint8_t &index) noexcept { return BFChannelConfig{1.0f, index}; } ); AllocChannels(device, coeffcount, device->channelsFromFmt()); @@ -486,7 +486,7 @@ void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, count = static_cast(AmbiChannelsFromOrder(order)); std::transform(AmbiIndex::From3D.begin(), AmbiIndex::From3D.begin()+count, std::begin(device->Dry.AmbiMap), - [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } + [](const uint8_t &index) noexcept { return BFChannelConfig{1.0f, index}; } ); } else @@ -494,7 +494,7 @@ void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, count = static_cast(Ambi2DChannelsFromOrder(order)); std::transform(AmbiIndex::From2D.begin(), AmbiIndex::From2D.begin()+count, std::begin(device->Dry.AmbiMap), - [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } + [](const uint8_t &index) noexcept { return BFChannelConfig{1.0f, index}; } ); } AllocChannels(device, count, device->channelsFromFmt()); @@ -632,7 +632,7 @@ void InitHrtfPanning(ALCdevice *device) std::transform(AmbiIndex::From3D.begin(), AmbiIndex::From3D.begin()+count, std::begin(device->Dry.AmbiMap), - [](const ALsizei &index) noexcept { return BFChannelConfig{1.0f, index}; } + [](const uint8_t &index) noexcept { return BFChannelConfig{1.0f, index}; } ); AllocChannels(device, static_cast(count), device->channelsFromFmt()); @@ -652,7 +652,7 @@ void InitUhjPanning(ALCdevice *device) auto acnmap_end = AmbiIndex::FromFuMa.begin() + count; std::transform(AmbiIndex::FromFuMa.begin(), acnmap_end, std::begin(device->Dry.AmbiMap), - [](const ALsizei &acn) noexcept -> BFChannelConfig + [](const uint8_t &acn) noexcept -> BFChannelConfig { return BFChannelConfig{1.0f/AmbiScale::FromFuMa[acn], acn}; } ); AllocChannels(device, ALuint{count}, device->channelsFromFmt()); @@ -765,9 +765,9 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr if(device->HrtfList.empty()) device->HrtfList = EnumerateHrtf(device->DeviceName.c_str()); - if(hrtf_id >= 0 && static_cast(hrtf_id) < device->HrtfList.size()) + if(hrtf_id >= 0 && static_cast(hrtf_id) < device->HrtfList.size()) { - const EnumeratedHrtf &entry = device->HrtfList[hrtf_id]; + const EnumeratedHrtf &entry = device->HrtfList[static_cast(hrtf_id)]; HrtfEntry *hrtf{GetLoadedHrtf(entry.hrtf)}; if(hrtf && hrtf->sampleRate == device->Frequency) { @@ -822,7 +822,8 @@ no_hrtf: if(*cflevopt > 0 && *cflevopt <= 6) { device->Bs2b = al::make_unique(); - bs2b_set_params(device->Bs2b.get(), *cflevopt, device->Frequency); + bs2b_set_params(device->Bs2b.get(), *cflevopt, + static_cast(device->Frequency)); TRACE("BS2B enabled\n"); InitPanning(device); device->PostProcess = &ALCdevice::ProcessBs2b; @@ -862,7 +863,7 @@ void aluInitEffectPanning(ALeffectslot *slot, ALCdevice *device) auto acnmap_end = AmbiIndex::From3D.begin() + count; auto iter = std::transform(AmbiIndex::From3D.begin(), acnmap_end, slot->Wet.AmbiMap.begin(), - [](const ALsizei &acn) noexcept -> BFChannelConfig + [](const uint8_t &acn) noexcept -> BFChannelConfig { return BFChannelConfig{1.0f, acn}; } ); std::fill(iter, slot->Wet.AmbiMap.end(), BFChannelConfig{}); -- cgit v1.2.3 From 3675dfcfef3becf8cfe84b0b213d502a2cf0088a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 14 Sep 2019 08:50:07 -0700 Subject: Use an unsigned index value --- alc/alcmain.h | 2 +- alc/panning.cpp | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/alc/alcmain.h b/alc/alcmain.h index 933ee779..9182d5d4 100644 --- a/alc/alcmain.h +++ b/alc/alcmain.h @@ -142,7 +142,7 @@ public: struct BFChannelConfig { ALfloat Scale; - ALsizei Index; + ALuint Index; }; /* Size for temporary storage of buffer data, in ALfloats. Larger values need diff --git a/alc/panning.cpp b/alc/panning.cpp index 018296d3..7fb1d9ff 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -969,10 +969,7 @@ void ComputePanGains(const MixParams *mix, const ALfloat *RESTRICT coeffs, ALflo auto iter = std::transform(ambimap, ambimap+mix->Buffer.size(), std::begin(gains), [coeffs,ingain](const BFChannelConfig &chanmap) noexcept -> ALfloat - { - ASSUME(chanmap.Index >= 0); - return chanmap.Scale * coeffs[chanmap.Index] * ingain; - } + { return chanmap.Scale * coeffs[chanmap.Index] * ingain; } ); std::fill(iter, std::end(gains), 0.0f); } -- cgit v1.2.3 From fa64b1fd6d48165d1e028d1ec96174c3b7fc6341 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 14 Sep 2019 10:59:02 -0700 Subject: Fix implicit conversions in the effects --- alc/effects/base.h | 4 +-- alc/effects/chorus.cpp | 55 +++++++++++++--------------- alc/effects/echo.cpp | 18 ++++------ alc/effects/fshifter.cpp | 4 +-- alc/effects/modulator.cpp | 20 +++++------ alc/effects/pshifter.cpp | 8 ++--- alc/effects/reverb.cpp | 22 ++++++------ alc/effects/vmorpher.cpp | 92 +++++++++++++++++++++++------------------------ common/alnumeric.h | 2 ++ 9 files changed, 109 insertions(+), 116 deletions(-) diff --git a/alc/effects/base.h b/alc/effects/base.h index 7bc170aa..6889308d 100644 --- a/alc/effects/base.h +++ b/alc/effects/base.h @@ -27,7 +27,7 @@ union EffectProps { ALfloat LateReverbDelay; ALfloat AirAbsorptionGainHF; ALfloat RoomRolloffFactor; - ALboolean DecayHFLimit; + bool DecayHFLimit; // Additional EAX Reverb Properties ALfloat GainLF; @@ -59,7 +59,7 @@ union EffectProps { } Chorus; /* Also Flanger */ struct { - ALboolean OnOff; + bool OnOff; } Compressor; struct { diff --git a/alc/effects/chorus.cpp b/alc/effects/chorus.cpp index 0d59c338..6e73f1f0 100644 --- a/alc/effects/chorus.cpp +++ b/alc/effects/chorus.cpp @@ -54,47 +54,45 @@ enum class WaveForm { Triangle }; -void GetTriangleDelays(ALint *delays, const ALsizei start_offset, const ALsizei lfo_range, +void GetTriangleDelays(ALuint *delays, const ALuint start_offset, const ALuint lfo_range, const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, const size_t todo) { - ASSUME(start_offset >= 0); ASSUME(lfo_range > 0); ASSUME(todo > 0); - ALsizei offset{start_offset}; - auto gen_lfo = [&offset,lfo_range,lfo_scale,depth,delay]() -> ALint + ALuint offset{start_offset}; + auto gen_lfo = [&offset,lfo_range,lfo_scale,depth,delay]() -> ALuint { offset = (offset+1)%lfo_range; - return fastf2i((1.0f - std::abs(2.0f - lfo_scale*offset)) * depth) + delay; + return static_cast( + fastf2i((1.0f - std::abs(2.0f - lfo_scale*offset)) * depth) + delay); }; std::generate_n(delays, todo, gen_lfo); } -void GetSinusoidDelays(ALint *delays, const ALsizei start_offset, const ALsizei lfo_range, +void GetSinusoidDelays(ALuint *delays, const ALuint start_offset, const ALuint lfo_range, const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, const size_t todo) { - ASSUME(start_offset >= 0); ASSUME(lfo_range > 0); ASSUME(todo > 0); - ALsizei offset{start_offset}; - auto gen_lfo = [&offset,lfo_range,lfo_scale,depth,delay]() -> ALint + ALuint offset{start_offset}; + auto gen_lfo = [&offset,lfo_range,lfo_scale,depth,delay]() -> ALuint { - ASSUME(delay >= 0); offset = (offset+1)%lfo_range; - return fastf2i(std::sin(lfo_scale*offset) * depth) + delay; + return static_cast(fastf2i(std::sin(lfo_scale*offset) * depth) + delay); }; std::generate_n(delays, todo, gen_lfo); } struct ChorusState final : public EffectState { al::vector mSampleBuffer; - ALsizei mOffset{0}; + ALuint mOffset{0}; - ALsizei mLfoOffset{0}; - ALsizei mLfoRange{1}; + ALuint mLfoOffset{0}; + ALuint mLfoRange{1}; ALfloat mLfoScale{0.0f}; - ALint mLfoDisp{0}; + ALuint mLfoDisp{0}; /* Gains for left and right sides */ struct { @@ -118,12 +116,9 @@ struct ChorusState final : public EffectState { ALboolean ChorusState::deviceUpdate(const ALCdevice *Device) { - const ALfloat max_delay = maxf(AL_CHORUS_MAX_DELAY, AL_FLANGER_MAX_DELAY); - size_t maxlen; - - maxlen = NextPowerOf2(float2int(max_delay*2.0f*Device->Frequency) + 1u); - if(maxlen <= 0) return AL_FALSE; + constexpr ALfloat max_delay{maxf(AL_CHORUS_MAX_DELAY, AL_FLANGER_MAX_DELAY)}; + const size_t maxlen{NextPowerOf2(float2uint(max_delay*2.0f*Device->Frequency) + 1u)}; if(maxlen != mSampleBuffer.size()) { mSampleBuffer.resize(maxlen); @@ -142,7 +137,7 @@ ALboolean ChorusState::deviceUpdate(const ALCdevice *Device) void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, const EffectProps *props, const EffectTarget target) { - static constexpr ALsizei mindelay = MAX_RESAMPLE_PADDING << FRACTIONBITS; + constexpr ALsizei mindelay{MAX_RESAMPLE_PADDING << FRACTIONBITS}; switch(props->Chorus.Waveform) { @@ -186,9 +181,9 @@ void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, co /* Calculate LFO coefficient (number of samples per cycle). Limit the * max range to avoid overflow when calculating the displacement. */ - ALsizei lfo_range = float2int(minf(frequency/rate + 0.5f, static_cast(INT_MAX/360 - 180))); + ALuint lfo_range{float2uint(minf(frequency/rate + 0.5f, ALfloat{INT_MAX/360 - 180}))}; - mLfoOffset = float2int(static_cast(mLfoOffset)/mLfoRange*lfo_range + 0.5f) % lfo_range; + mLfoOffset = mLfoOffset * lfo_range / mLfoRange; mLfoRange = lfo_range; switch(mWaveform) { @@ -203,23 +198,23 @@ void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, co /* Calculate lfo phase displacement */ ALint phase{props->Chorus.Phase}; if(phase < 0) phase = 360 + phase; - mLfoDisp = (mLfoRange*phase + 180) / 360; + mLfoDisp = (mLfoRange*static_cast(phase) + 180) / 360; } } void ChorusState::process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) { - const auto bufmask = static_cast(mSampleBuffer.size()-1); + const size_t bufmask{mSampleBuffer.size()-1}; const ALfloat feedback{mFeedback}; - const ALsizei avgdelay{(mDelay + (FRACTIONONE>>1)) >> FRACTIONBITS}; + const ALuint avgdelay{(static_cast(mDelay) + (FRACTIONONE>>1)) >> FRACTIONBITS}; ALfloat *RESTRICT delaybuf{mSampleBuffer.data()}; - ALsizei offset{mOffset}; + ALuint offset{mOffset}; for(size_t base{0u};base < samplesToDo;) { const size_t todo{minz(256, samplesToDo-base)}; - ALint moddelays[2][256]; + ALuint moddelays[2][256]; if(mWaveform == WaveForm::Sinusoid) { GetSinusoidDelays(moddelays[0], mLfoOffset, mLfoRange, mLfoScale, mDepth, mDelay, @@ -243,7 +238,7 @@ void ChorusState::process(const size_t samplesToDo, const al::span>FRACTIONBITS)}; + ALuint delay{offset - (moddelays[0][i]>>FRACTIONBITS)}; ALfloat mu{(moddelays[0][i]&FRACTIONMASK) * (1.0f/FRACTIONONE)}; temps[0][i] = cubic(delaybuf[(delay+1) & bufmask], delaybuf[(delay ) & bufmask], delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask], @@ -258,7 +253,7 @@ void ChorusState::process(const size_t samplesToDo, const al::spanFrequency + 0.5f) + - float2int(AL_ECHO_MAX_LRDELAY*Device->Frequency + 0.5f); - maxlen = NextPowerOf2(maxlen); - if(maxlen <= 0) return AL_FALSE; - + const ALuint maxlen{NextPowerOf2(float2uint(AL_ECHO_MAX_DELAY*Device->Frequency + 0.5f) + + float2uint(AL_ECHO_MAX_LRDELAY*Device->Frequency + 0.5f))}; if(maxlen != mSampleBuffer.size()) { mSampleBuffer.resize(maxlen); @@ -96,8 +91,8 @@ void EchoState::update(const ALCcontext *context, const ALeffectslot *slot, cons const ALCdevice *device{context->mDevice.get()}; const auto frequency = static_cast(device->Frequency); - mTap[0].delay = maxi(float2int(props->Echo.Delay*frequency + 0.5f), 1); - mTap[1].delay = float2int(props->Echo.LRDelay*frequency + 0.5f) + mTap[0].delay; + mTap[0].delay = maxu(float2uint(props->Echo.Delay*frequency + 0.5f), 1); + mTap[1].delay = float2uint(props->Echo.LRDelay*frequency + 0.5f) + mTap[0].delay; const ALfloat gainhf{maxf(1.0f - props->Echo.Damping, 0.0625f)}; /* Limit -24dB */ mFilter.setParams(BiquadType::HighShelf, gainhf, LOWPASSFREQREF/frequency, @@ -119,7 +114,7 @@ void EchoState::update(const ALCcontext *context, const ALeffectslot *slot, cons void EchoState::process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) { - const auto mask = static_cast(mSampleBuffer.size()-1); + const size_t mask{mSampleBuffer.size()-1}; ALfloat *RESTRICT delaybuf{mSampleBuffer.data()}; size_t offset{mOffset}; size_t tap1{offset - mTap[0].delay}; @@ -128,6 +123,7 @@ void EchoState::process(const size_t samplesToDo, const al::span 0); + const BiquadFilter filter{mFilter}; std::tie(z1, z2) = mFilter.getComponents(); for(size_t i{0u};i < samplesToDo;) { @@ -148,7 +144,7 @@ void EchoState::process(const size_t samplesToDo, const al::span InitHannWindow() { std::array ret; /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */ - for(ALsizei i{0};i < HIL_SIZE>>1;i++) + for(size_t i{0};i < HIL_SIZE>>1;i++) { - ALdouble val = std::sin(al::MathDefs::Pi() * i / ALdouble{HIL_SIZE-1}); + const double val{std::sin(al::MathDefs::Pi() * i / double{HIL_SIZE-1})}; ret[i] = ret[HIL_SIZE-1-i] = val * val; } return ret; diff --git a/alc/effects/modulator.cpp b/alc/effects/modulator.cpp index ffb1c381..fbc6377c 100644 --- a/alc/effects/modulator.cpp +++ b/alc/effects/modulator.cpp @@ -42,29 +42,29 @@ namespace { #define WAVEFORM_FRACONE (1<(index) * (al::MathDefs::Tau() / ALfloat{WAVEFORM_FRACONE})); } -inline ALfloat Saw(ALsizei index) +inline ALfloat Saw(ALuint index) { return static_cast(index)*(2.0f/WAVEFORM_FRACONE) - 1.0f; } -inline ALfloat Square(ALsizei index) +inline ALfloat Square(ALuint index) { return static_cast(((index>>(WAVEFORM_FRACBITS-2))&2) - 1); } -inline ALfloat One(ALsizei) +inline ALfloat One(ALuint) { return 1.0f; } -template -void Modulate(ALfloat *RESTRICT dst, ALsizei index, const ALsizei step, size_t todo) +template +void Modulate(ALfloat *RESTRICT dst, ALuint index, const ALuint step, size_t todo) { for(size_t i{0u};i < todo;i++) { @@ -76,10 +76,10 @@ void Modulate(ALfloat *RESTRICT dst, ALsizei index, const ALsizei step, size_t t struct ModulatorState final : public EffectState { - void (*mGetSamples)(ALfloat*RESTRICT, ALsizei, const ALsizei, size_t){}; + void (*mGetSamples)(ALfloat*RESTRICT, ALuint, const ALuint, size_t){}; - ALsizei mIndex{0}; - ALsizei mStep{1}; + ALuint mIndex{0}; + ALuint mStep{1}; struct { BiquadFilter Filter; @@ -111,7 +111,7 @@ void ModulatorState::update(const ALCcontext *context, const ALeffectslot *slot, const ALCdevice *device{context->mDevice.get()}; const float step{props->Modulator.Frequency / static_cast(device->Frequency)}; - mStep = fastf2i(clampf(step*WAVEFORM_FRACONE, 0.0f, ALfloat{WAVEFORM_FRACONE-1})); + mStep = fastf2u(clampf(step*WAVEFORM_FRACONE, 0.0f, ALfloat{WAVEFORM_FRACONE-1})); if(mStep == 0) mGetSamples = Modulate; diff --git a/alc/effects/pshifter.cpp b/alc/effects/pshifter.cpp index 9d011b12..a4d66706 100644 --- a/alc/effects/pshifter.cpp +++ b/alc/effects/pshifter.cpp @@ -55,9 +55,9 @@ std::array InitHannWindow() { std::array ret; /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */ - for(ALsizei i{0};i < STFT_SIZE>>1;i++) + for(size_t i{0};i < STFT_SIZE>>1;i++) { - ALdouble val = std::sin(al::MathDefs::Pi() * i / ALdouble{STFT_SIZE-1}); + const double val{std::sin(al::MathDefs::Pi() * i / ALdouble{STFT_SIZE-1})}; ret[i] = ret[STFT_SIZE-1-i] = val * val; } return ret; @@ -93,7 +93,7 @@ inline complex_d polar2rect(const ALphasor &number) struct PshifterState final : public EffectState { /* Effect parameters */ size_t mCount; - ALsizei mPitchShiftI; + ALuint mPitchShiftI; ALfloat mPitchShift; ALfloat mFreqPerBin; @@ -151,7 +151,7 @@ void PshifterState::update(const ALCcontext*, const ALeffectslot *slot, const Ef const float pitch{std::pow(2.0f, static_cast(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f )}; - mPitchShiftI = fastf2i(pitch*FRACTIONONE); + mPitchShiftI = fastf2u(pitch*FRACTIONONE); mPitchShift = mPitchShiftI * (1.0f/FRACTIONONE); ALfloat coeffs[MAX_AMBI_CHANNELS]; diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 6017f6d1..b5100a14 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -229,13 +229,13 @@ struct DelayLineI { { Line = &sampleBuffer[reinterpret_cast(Line)]; } /* Calculate the length of a delay line and store its mask and offset. */ - ALuint calcLineLength(const ALfloat length, const ptrdiff_t offset, const ALfloat frequency, + ALuint calcLineLength(const ALfloat length, const uintptr_t offset, const ALfloat frequency, const ALuint extra) { /* All line lengths are powers of 2, calculated from their lengths in * seconds, rounded up. */ - auto samples = static_cast(float2int(std::ceil(length*frequency))); + ALuint samples{float2uint(std::ceil(length*frequency))}; samples = NextPowerOf2(samples + extra); /* All lines share a single sample buffer. */ @@ -567,7 +567,7 @@ ALboolean ReverbState::deviceUpdate(const ALCdevice *device) const ALfloat multiplier{CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY)}; /* The late feed taps are set a fixed position past the latest delay tap. */ - mLateFeedTap = float2int( + mLateFeedTap = float2uint( (AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS.back()*multiplier) * frequency); /* Clear filters and gain coefficients since the delay lines were all just @@ -729,13 +729,13 @@ void EarlyReflections::updateLines(const ALfloat density, const ALfloat diffusio ALfloat length{EARLY_ALLPASS_LENGTHS[i] * multiplier}; /* Calculate the delay offset for each all-pass line. */ - VecAp.Offset[i][1] = float2int(length * frequency); + VecAp.Offset[i][1] = float2uint(length * frequency); /* Calculate the length (in seconds) of each delay line. */ length = EARLY_LINE_LENGTHS[i] * multiplier; /* Calculate the delay offset for each delay line. */ - Offset[i][1] = float2int(length * frequency); + Offset[i][1] = float2uint(length * frequency); /* Calculate the gain (coefficient) for each line. */ Coeff[i][1] = CalcDecayCoeff(length, decayTime); @@ -787,13 +787,13 @@ void LateReverb::updateLines(const ALfloat density, const ALfloat diffusion, length = LATE_ALLPASS_LENGTHS[i] * multiplier; /* Calculate the delay offset for each all-pass line. */ - VecAp.Offset[i][1] = float2int(length * frequency); + VecAp.Offset[i][1] = float2uint(length * frequency); /* Calculate the length (in seconds) of each delay line. */ length = LATE_LINE_LENGTHS[i] * multiplier; /* Calculate the delay offset for each delay line. */ - Offset[i][1] = float2int(length*frequency + 0.5f); + Offset[i][1] = float2uint(length*frequency + 0.5f); /* Approximate the absorption that the vector all-pass would exhibit * given the current diffusion so we don't have to process a full T60 @@ -826,14 +826,14 @@ void ReverbState::updateDelayLine(const ALfloat earlyDelay, const ALfloat lateDe for(size_t i{0u};i < NUM_LINES;i++) { ALfloat length{earlyDelay + EARLY_TAP_LENGTHS[i]*multiplier}; - mEarlyDelayTap[i][1] = float2int(length * frequency); + mEarlyDelayTap[i][1] = float2uint(length * frequency); length = EARLY_TAP_LENGTHS[i]*multiplier; mEarlyDelayCoeff[i][1] = CalcDecayCoeff(length, decayTime); length = (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS.front())/float{NUM_LINES}*multiplier + lateDelay; - mLateDelayTap[i][1] = mLateFeedTap + float2int(length * frequency); + mLateDelayTap[i][1] = mLateFeedTap + float2uint(length * frequency); } } @@ -1464,7 +1464,7 @@ void ReverbState::process(const size_t samplesToDo, const al::span 0); /* Generate non-faded early reflections and late reverb. */ @@ -1484,7 +1484,7 @@ void ReverbState::process(const size_t samplesToDo, const al::span 0); /* Generate cross-faded early reflections and late reverb. */ diff --git a/alc/effects/vmorpher.cpp b/alc/effects/vmorpher.cpp index a3524371..a6a077b6 100644 --- a/alc/effects/vmorpher.cpp +++ b/alc/effects/vmorpher.cpp @@ -44,29 +44,29 @@ namespace { #define WAVEFORM_FRACONE (1<::Tau() / ALfloat{WAVEFORM_FRACONE}}; return std::sin(static_cast(index) * scale)*0.5f + 0.5f; } -inline ALfloat Saw(ALsizei index) +inline ALfloat Saw(ALuint index) { return static_cast(index) / ALfloat{WAVEFORM_FRACONE}; } -inline ALfloat Triangle(ALsizei index) +inline ALfloat Triangle(ALuint index) { return std::fabs(static_cast(index)*(2.0f/WAVEFORM_FRACONE) - 1.0f); } -inline ALfloat Half(ALsizei) +inline ALfloat Half(ALuint) { return 0.5f; } -template -void Oscillate(ALfloat *RESTRICT dst, ALsizei index, const ALsizei step, size_t todo) +template +void Oscillate(ALfloat *RESTRICT dst, ALuint index, const ALuint step, size_t todo) { for(size_t i{0u};i < todo;i++) { @@ -126,10 +126,10 @@ struct VmorpherState final : public EffectState { ALfloat TargetGains[MAX_OUTPUT_CHANNELS]{}; } mChans[MAX_AMBI_CHANNELS]; - void (*mGetSamples)(ALfloat* RESTRICT, ALsizei, const ALsizei, size_t){}; + void (*mGetSamples)(ALfloat* RESTRICT, ALuint, const ALuint, size_t){}; - ALsizei mIndex{0}; - ALsizei mStep{1}; + ALuint mIndex{0}; + ALuint mStep{1}; /* Effects buffers */ ALfloat mSampleBufferA[MAX_UPDATE_SAMPLES]{}; @@ -153,41 +153,41 @@ std::array VmorpherState::getFiltersByPhoneme(ALenum phoneme, A */ switch(phoneme) { - case AL_VOCAL_MORPHER_PHONEME_A: - return {{ - {( 800 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ - {(1150 * pitch) / frequency, 0.501187f}, /* std::pow(10.0f, -6 / 20.0f); */ - {(2900 * pitch) / frequency, 0.025118f}, /* std::pow(10.0f, -32 / 20.0f); */ - {(3900 * pitch) / frequency, 0.100000f} /* std::pow(10.0f, -20 / 20.0f); */ - }}; - case AL_VOCAL_MORPHER_PHONEME_E: - return {{ - {( 350 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ - {(2000 * pitch) / frequency, 0.100000f}, /* std::pow(10.0f, -20 / 20.0f); */ - {(2800 * pitch) / frequency, 0.177827f}, /* std::pow(10.0f, -15 / 20.0f); */ - {(3600 * pitch) / frequency, 0.009999f} /* std::pow(10.0f, -40 / 20.0f); */ - }}; - case AL_VOCAL_MORPHER_PHONEME_I: - return {{ - {( 270 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ - {(2140 * pitch) / frequency, 0.251188f}, /* std::pow(10.0f, -12 / 20.0f); */ - {(2950 * pitch) / frequency, 0.050118f}, /* std::pow(10.0f, -26 / 20.0f); */ - {(3900 * pitch) / frequency, 0.050118f} /* std::pow(10.0f, -26 / 20.0f); */ - }}; - case AL_VOCAL_MORPHER_PHONEME_O: - return {{ - {( 450 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ - {( 800 * pitch) / frequency, 0.281838f}, /* std::pow(10.0f, -11 / 20.0f); */ - {(2830 * pitch) / frequency, 0.079432f}, /* std::pow(10.0f, -22 / 20.0f); */ - {(3800 * pitch) / frequency, 0.079432f} /* std::pow(10.0f, -22 / 20.0f); */ - }}; - case AL_VOCAL_MORPHER_PHONEME_U: - return {{ - {( 325 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ - {( 700 * pitch) / frequency, 0.158489f}, /* std::pow(10.0f, -16 / 20.0f); */ - {(2700 * pitch) / frequency, 0.017782f}, /* std::pow(10.0f, -35 / 20.0f); */ - {(3800 * pitch) / frequency, 0.009999f} /* std::pow(10.0f, -40 / 20.0f); */ - }}; + case AL_VOCAL_MORPHER_PHONEME_A: + return {{ + {( 800 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ + {(1150 * pitch) / frequency, 0.501187f}, /* std::pow(10.0f, -6 / 20.0f); */ + {(2900 * pitch) / frequency, 0.025118f}, /* std::pow(10.0f, -32 / 20.0f); */ + {(3900 * pitch) / frequency, 0.100000f} /* std::pow(10.0f, -20 / 20.0f); */ + }}; + case AL_VOCAL_MORPHER_PHONEME_E: + return {{ + {( 350 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ + {(2000 * pitch) / frequency, 0.100000f}, /* std::pow(10.0f, -20 / 20.0f); */ + {(2800 * pitch) / frequency, 0.177827f}, /* std::pow(10.0f, -15 / 20.0f); */ + {(3600 * pitch) / frequency, 0.009999f} /* std::pow(10.0f, -40 / 20.0f); */ + }}; + case AL_VOCAL_MORPHER_PHONEME_I: + return {{ + {( 270 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ + {(2140 * pitch) / frequency, 0.251188f}, /* std::pow(10.0f, -12 / 20.0f); */ + {(2950 * pitch) / frequency, 0.050118f}, /* std::pow(10.0f, -26 / 20.0f); */ + {(3900 * pitch) / frequency, 0.050118f} /* std::pow(10.0f, -26 / 20.0f); */ + }}; + case AL_VOCAL_MORPHER_PHONEME_O: + return {{ + {( 450 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ + {( 800 * pitch) / frequency, 0.281838f}, /* std::pow(10.0f, -11 / 20.0f); */ + {(2830 * pitch) / frequency, 0.079432f}, /* std::pow(10.0f, -22 / 20.0f); */ + {(3800 * pitch) / frequency, 0.079432f} /* std::pow(10.0f, -22 / 20.0f); */ + }}; + case AL_VOCAL_MORPHER_PHONEME_U: + return {{ + {( 325 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ + {( 700 * pitch) / frequency, 0.158489f}, /* std::pow(10.0f, -16 / 20.0f); */ + {(2700 * pitch) / frequency, 0.017782f}, /* std::pow(10.0f, -35 / 20.0f); */ + {(3800 * pitch) / frequency, 0.009999f} /* std::pow(10.0f, -40 / 20.0f); */ + }}; } return {}; } @@ -211,8 +211,8 @@ void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, { const ALCdevice *device{context->mDevice.get()}; const ALfloat frequency{static_cast(device->Frequency)}; - const ALfloat step{props->Vmorpher.Rate / static_cast(device->Frequency)}; - mStep = fastf2i(clampf(step*WAVEFORM_FRACONE, 0.0f, ALfloat{WAVEFORM_FRACONE-1})); + const ALfloat step{props->Vmorpher.Rate / frequency}; + mStep = fastf2u(clampf(step*WAVEFORM_FRACONE, 0.0f, ALfloat{WAVEFORM_FRACONE-1})); if(mStep == 0) mGetSamples = Oscillate; diff --git a/common/alnumeric.h b/common/alnumeric.h index 94ea2ee0..b409ce9c 100644 --- a/common/alnumeric.h +++ b/common/alnumeric.h @@ -251,6 +251,8 @@ inline int float2int(float f) noexcept return static_cast(f); #endif } +inline unsigned int float2uint(float f) noexcept +{ return static_cast(float2int(f)); } /** Converts double-to-int using standard behavior (truncation). */ inline int double2int(double d) noexcept -- cgit v1.2.3 From 532197a650729be5e4405fd64f81e4443090a01e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 14 Sep 2019 12:44:35 -0700 Subject: Clean up (most) implicit conversions in the backends --- alc/backends/alsa.cpp | 93 ++++++++++++++++++++++++--------------------- alc/backends/dsound.cpp | 20 ++++++---- alc/backends/oss.cpp | 4 +- alc/backends/pulseaudio.cpp | 47 ++++++++++++----------- alc/backends/wasapi.cpp | 12 +++--- alc/backends/winmm.cpp | 8 ++-- 6 files changed, 98 insertions(+), 86 deletions(-) diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index 766ff167..cd85afaf 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -303,7 +303,7 @@ al::vector probe_devices(snd_pcm_stream_t stream) ERR("snd_ctl_pcm_next_device failed\n"); if(dev < 0) break; - snd_pcm_info_set_device(pcminfo, dev); + snd_pcm_info_set_device(pcminfo, static_cast(dev)); snd_pcm_info_set_subdevice(pcminfo, 0); snd_pcm_info_set_stream(pcminfo, stream); if((err=snd_ctl_pcm_info(handle, pcminfo)) < 0) @@ -425,7 +425,7 @@ int AlsaPlayback::mixerProc() althrd_setname(MIXER_THREAD_NAME); const snd_pcm_uframes_t update_size{mDevice->UpdateSize}; - const snd_pcm_uframes_t num_updates{mDevice->BufferSize / update_size}; + const snd_pcm_uframes_t buffer_size{mDevice->BufferSize}; while(!mKillNow.load(std::memory_order_acquire)) { int state{verify_state(mPcmHandle)}; @@ -436,14 +436,15 @@ int AlsaPlayback::mixerProc() break; } - snd_pcm_sframes_t avail{snd_pcm_avail_update(mPcmHandle)}; - if(avail < 0) + snd_pcm_sframes_t avails{snd_pcm_avail_update(mPcmHandle)}; + if(avails < 0) { - ERR("available update failed: %s\n", snd_strerror(avail)); + ERR("available update failed: %s\n", snd_strerror(static_cast(avails))); continue; } + snd_pcm_uframes_t avail{static_cast(avails)}; - if(static_cast(avail) > update_size*(num_updates+1)) + if(avail > buffer_size) { WARN("available samples exceeds the buffer size\n"); snd_pcm_reset(mPcmHandle); @@ -451,7 +452,7 @@ int AlsaPlayback::mixerProc() } // make sure there's frames to process - if(static_cast(avail) < update_size) + if(avail < update_size) { if(state != SND_PCM_STATE_RUNNING) { @@ -472,7 +473,7 @@ int AlsaPlayback::mixerProc() lock(); while(avail > 0) { - snd_pcm_uframes_t frames{static_cast(avail)}; + snd_pcm_uframes_t frames{avail}; const snd_pcm_channel_area_t *areas{}; snd_pcm_uframes_t offset{}; @@ -484,13 +485,13 @@ int AlsaPlayback::mixerProc() } char *WritePtr{static_cast(areas->addr) + (offset * areas->step / 8)}; - aluMixData(mDevice, WritePtr, frames); + aluMixData(mDevice, WritePtr, static_cast(frames)); snd_pcm_sframes_t commitres{snd_pcm_mmap_commit(mPcmHandle, offset, frames)}; - if(commitres < 0 || (commitres-frames) != 0) + if(commitres < 0 || (static_cast(commitres)-frames) != 0) { ERR("mmap commit error: %s\n", - snd_strerror(commitres >= 0 ? -EPIPE : commitres)); + snd_strerror(commitres >= 0 ? -EPIPE : static_cast(commitres))); break; } @@ -522,7 +523,7 @@ int AlsaPlayback::mixerNoMMapProc() snd_pcm_sframes_t avail{snd_pcm_avail_update(mPcmHandle)}; if(avail < 0) { - ERR("available update failed: %s\n", snd_strerror(avail)); + ERR("available update failed: %s\n", snd_strerror(static_cast(avail))); continue; } @@ -551,11 +552,12 @@ int AlsaPlayback::mixerNoMMapProc() lock(); al::byte *WritePtr{mBuffer.data()}; - avail = snd_pcm_bytes_to_frames(mPcmHandle, mBuffer.size()); - aluMixData(mDevice, WritePtr, avail); + avail = snd_pcm_bytes_to_frames(mPcmHandle, static_cast(mBuffer.size())); + aluMixData(mDevice, WritePtr, static_cast(avail)); while(avail > 0) { - snd_pcm_sframes_t ret{snd_pcm_writei(mPcmHandle, WritePtr, avail)}; + snd_pcm_sframes_t ret{snd_pcm_writei(mPcmHandle, WritePtr, + static_cast(avail))}; switch(ret) { case -EAGAIN: @@ -565,7 +567,7 @@ int AlsaPlayback::mixerNoMMapProc() #endif case -EPIPE: case -EINTR: - ret = snd_pcm_recover(mPcmHandle, ret, 1); + ret = snd_pcm_recover(mPcmHandle, static_cast(ret), 1); if(ret < 0) avail = 0; break; @@ -762,8 +764,8 @@ ALCboolean AlsaPlayback::reset() snd_pcm_sw_params_free(sp); sp = nullptr; - mDevice->BufferSize = bufferSizeInFrames; - mDevice->UpdateSize = periodSizeInFrames; + mDevice->BufferSize = static_cast(bufferSizeInFrames); + mDevice->UpdateSize = static_cast(periodSizeInFrames); mDevice->Frequency = rate; SetDefaultChannelOrder(mDevice); @@ -803,7 +805,8 @@ ALCboolean AlsaPlayback::start() int (AlsaPlayback::*thread_func)(){}; if(access == SND_PCM_ACCESS_RW_INTERLEAVED) { - mBuffer.resize(snd_pcm_frames_to_bytes(mPcmHandle, mDevice->UpdateSize)); + mBuffer.resize( + static_cast(snd_pcm_frames_to_bytes(mPcmHandle, mDevice->UpdateSize))); thread_func = &AlsaPlayback::mixerNoMMapProc; } else @@ -952,7 +955,7 @@ ALCenum AlsaCapture::open(const ALCchar *name) } snd_pcm_uframes_t bufferSizeInFrames{maxu(mDevice->BufferSize, 100*mDevice->Frequency/1000)}; - snd_pcm_uframes_t periodSizeInFrames{minu(bufferSizeInFrames, 25*mDevice->Frequency/1000)}; + snd_pcm_uframes_t periodSizeInFrames{minu(mDevice->BufferSize, 25*mDevice->Frequency/1000)}; bool needring{false}; const char *funcerr{}; @@ -1044,7 +1047,8 @@ void AlsaCapture::stop() { /* The ring buffer implicitly captures when checking availability. * Direct access needs to explicitly capture it into temp storage. */ - auto temp = al::vector(snd_pcm_frames_to_bytes(mPcmHandle, avail)); + auto temp = al::vector( + static_cast(snd_pcm_frames_to_bytes(mPcmHandle, avail))); captureSamples(temp.data(), avail); mBuffer = std::move(temp); } @@ -1070,11 +1074,11 @@ ALCenum AlsaCapture::captureSamples(ALCvoid *buffer, ALCuint samples) if(!mBuffer.empty()) { /* First get any data stored from the last stop */ - amt = snd_pcm_bytes_to_frames(mPcmHandle, mBuffer.size()); + amt = snd_pcm_bytes_to_frames(mPcmHandle, static_cast(mBuffer.size())); if(static_cast(amt) > samples) amt = samples; amt = snd_pcm_frames_to_bytes(mPcmHandle, amt); - memcpy(buffer, mBuffer.data(), amt); + std::copy_n(mBuffer.begin(), amt, static_cast(buffer)); mBuffer.erase(mBuffer.begin(), mBuffer.begin()+amt); amt = snd_pcm_bytes_to_frames(mPcmHandle, amt); @@ -1083,11 +1087,11 @@ ALCenum AlsaCapture::captureSamples(ALCvoid *buffer, ALCuint samples) amt = snd_pcm_readi(mPcmHandle, buffer, samples); if(amt < 0) { - ERR("read error: %s\n", snd_strerror(amt)); + ERR("read error: %s\n", snd_strerror(static_cast(amt))); if(amt == -EAGAIN) continue; - if((amt=snd_pcm_recover(mPcmHandle, amt, 1)) >= 0) + if((amt=snd_pcm_recover(mPcmHandle, static_cast(amt), 1)) >= 0) { amt = snd_pcm_start(mPcmHandle); if(amt >= 0) @@ -1095,8 +1099,9 @@ ALCenum AlsaCapture::captureSamples(ALCvoid *buffer, ALCuint samples) } if(amt < 0) { - ERR("restore error: %s\n", snd_strerror(amt)); - aluHandleDisconnect(mDevice, "Capture recovery failure: %s", snd_strerror(amt)); + const char *err{snd_strerror(static_cast(amt))}; + ERR("restore error: %s\n", err); + aluHandleDisconnect(mDevice, "Capture recovery failure: %s", err); break; } /* If the amount available is less than what's asked, we lost it @@ -1110,8 +1115,8 @@ ALCenum AlsaCapture::captureSamples(ALCvoid *buffer, ALCuint samples) samples -= amt; } if(samples > 0) - memset(buffer, ((mDevice->FmtType == DevFmtUByte) ? 0x80 : 0), - snd_pcm_frames_to_bytes(mPcmHandle, samples)); + std::fill_n(static_cast(buffer), snd_pcm_frames_to_bytes(mPcmHandle, samples), + al::byte((mDevice->FmtType == DevFmtUByte) ? 0x80 : 0)); return ALC_NO_ERROR; } @@ -1123,9 +1128,9 @@ ALCuint AlsaCapture::availableSamples() avail = snd_pcm_avail_update(mPcmHandle); if(avail < 0) { - ERR("avail update failed: %s\n", snd_strerror(avail)); + ERR("avail update failed: %s\n", snd_strerror(static_cast(avail))); - if((avail=snd_pcm_recover(mPcmHandle, avail, 1)) >= 0) + if((avail=snd_pcm_recover(mPcmHandle, static_cast(avail), 1)) >= 0) { if(mDoCapture) avail = snd_pcm_start(mPcmHandle); @@ -1134,17 +1139,18 @@ ALCuint AlsaCapture::availableSamples() } if(avail < 0) { - ERR("restore error: %s\n", snd_strerror(avail)); - aluHandleDisconnect(mDevice, "Capture recovery failure: %s", snd_strerror(avail)); + const char *err{snd_strerror(static_cast(avail))}; + ERR("restore error: %s\n", err); + aluHandleDisconnect(mDevice, "Capture recovery failure: %s", err); } } if(!mRing) { if(avail < 0) avail = 0; - avail += snd_pcm_bytes_to_frames(mPcmHandle, mBuffer.size()); + avail += snd_pcm_bytes_to_frames(mPcmHandle, static_cast(mBuffer.size())); if(avail > mLastAvail) mLastAvail = avail; - return mLastAvail; + return static_cast(mLastAvail); } while(avail > 0) @@ -1152,15 +1158,15 @@ ALCuint AlsaCapture::availableSamples() auto vec = mRing->getWriteVector(); if(vec.first.len == 0) break; - snd_pcm_sframes_t amt{std::min(vec.first.len, avail)}; - amt = snd_pcm_readi(mPcmHandle, vec.first.buf, amt); + snd_pcm_sframes_t amt{std::min(static_cast(vec.first.len), avail)}; + amt = snd_pcm_readi(mPcmHandle, vec.first.buf, static_cast(amt)); if(amt < 0) { - ERR("read error: %s\n", snd_strerror(amt)); + ERR("read error: %s\n", snd_strerror(static_cast(amt))); if(amt == -EAGAIN) continue; - if((amt=snd_pcm_recover(mPcmHandle, amt, 1)) >= 0) + if((amt=snd_pcm_recover(mPcmHandle, static_cast(amt), 1)) >= 0) { if(mDoCapture) amt = snd_pcm_start(mPcmHandle); @@ -1169,19 +1175,20 @@ ALCuint AlsaCapture::availableSamples() } if(amt < 0) { - ERR("restore error: %s\n", snd_strerror(amt)); - aluHandleDisconnect(mDevice, "Capture recovery failure: %s", snd_strerror(amt)); + const char *err{snd_strerror(static_cast(amt))}; + ERR("restore error: %s\n", err); + aluHandleDisconnect(mDevice, "Capture recovery failure: %s", err); break; } avail = amt; continue; } - mRing->writeAdvance(amt); + mRing->writeAdvance(static_cast(amt)); avail -= amt; } - return mRing->readSpace(); + return static_cast(mRing->readSpace()); } ClockLatency AlsaCapture::getClockLatency() diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index 1c44c2ec..f9184968 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -465,11 +465,13 @@ ALCboolean DSoundPlayback::reset() retry_open: hr = S_OK; OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; - OutputType.Format.nChannels = mDevice->channelsFromFmt(); - OutputType.Format.wBitsPerSample = mDevice->bytesFromFmt() * 8; - OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8; + OutputType.Format.nChannels = static_cast(mDevice->channelsFromFmt()); + OutputType.Format.wBitsPerSample = static_cast(mDevice->bytesFromFmt() * 8); + OutputType.Format.nBlockAlign = static_cast(OutputType.Format.nChannels * + OutputType.Format.wBitsPerSample / 8); OutputType.Format.nSamplesPerSec = mDevice->Frequency; - OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign; + OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * + OutputType.Format.nBlockAlign; OutputType.Format.cbSize = 0; } @@ -728,11 +730,13 @@ ALCenum DSoundCapture::open(const ALCchar *name) } InputType.Format.wFormatTag = WAVE_FORMAT_PCM; - InputType.Format.nChannels = mDevice->channelsFromFmt(); - InputType.Format.wBitsPerSample = mDevice->bytesFromFmt() * 8; - InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8; + InputType.Format.nChannels = static_cast(mDevice->channelsFromFmt()); + InputType.Format.wBitsPerSample = static_cast(mDevice->bytesFromFmt() * 8); + InputType.Format.nBlockAlign = static_cast(InputType.Format.nChannels * + InputType.Format.wBitsPerSample / 8); InputType.Format.nSamplesPerSec = mDevice->Frequency; - InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign; + InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec * + InputType.Format.nBlockAlign; InputType.Format.cbSize = 0; InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample; if(mDevice->FmtType == DevFmtFloat) diff --git a/alc/backends/oss.cpp b/alc/backends/oss.cpp index 48794a50..ffdf3c23 100644 --- a/alc/backends/oss.cpp +++ b/alc/backends/oss.cpp @@ -305,7 +305,7 @@ int OSSPlayback::mixerProc() ALubyte *write_ptr{mMixData.data()}; size_t to_write{mMixData.size()}; - aluMixData(mDevice, write_ptr, to_write/frame_size); + aluMixData(mDevice, write_ptr, static_cast(to_write/frame_size)); while(to_write > 0 && !mKillNow.load(std::memory_order_acquire)) { ssize_t wrote{write(mFd, write_ptr, to_write)}; @@ -531,7 +531,7 @@ int OSScapture::recordProc() strerror(errno)); break; } - mRing->writeAdvance(amt/frame_size); + mRing->writeAdvance(static_cast(amt)/frame_size); } } diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index c1e615ae..08420748 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -743,7 +743,7 @@ void PulsePlayback::streamWriteCallbackC(pa_stream *stream, size_t nbytes, void void PulsePlayback::streamWriteCallback(pa_stream *stream, size_t nbytes) { void *buf{pa_xmalloc(nbytes)}; - aluMixData(mDevice, buf, nbytes/mFrameSize); + aluMixData(mDevice, buf, static_cast(nbytes/mFrameSize)); int ret{pa_stream_write(stream, buf, nbytes, pa_xfree, 0, PA_SEEK_RELATIVE)}; if UNLIKELY(ret != PA_OK) @@ -864,7 +864,7 @@ ALCenum PulsePlayback::open(const ALCchar *name) BackendType::Playback); pa_stream_set_moved_callback(mStream, &PulsePlayback::streamMovedCallbackC, this); - mFrameSize = pa_frame_size(pa_stream_get_sample_spec(mStream)); + mFrameSize = static_cast(pa_frame_size(pa_stream_get_sample_spec(mStream))); mDeviceName = pa_stream_get_device_name(mStream); if(!dev_name) @@ -970,15 +970,16 @@ ALCboolean PulsePlayback::reset() break; } mSpec.rate = mDevice->Frequency; - mSpec.channels = mDevice->channelsFromFmt(); + mSpec.channels = static_cast(mDevice->channelsFromFmt()); if(pa_sample_spec_valid(&mSpec) == 0) throw al::backend_exception{ALC_INVALID_VALUE, "Invalid sample spec"}; - mAttr.maxlength = -1; - mAttr.tlength = mDevice->BufferSize * pa_frame_size(&mSpec); - mAttr.prebuf = 0; - mAttr.minreq = mDevice->UpdateSize * pa_frame_size(&mSpec); - mAttr.fragsize = -1; + const ALuint frame_size{static_cast(pa_frame_size(&mSpec))}; + mAttr.maxlength = ~0u; + mAttr.tlength = mDevice->BufferSize * frame_size; + mAttr.prebuf = 0u; + mAttr.minreq = mDevice->UpdateSize * frame_size; + mAttr.fragsize = ~0u; mStream = pulse_connect_stream(mDeviceName.c_str(), plock, mContext, flags, &mAttr, &mSpec, &chanmap, BackendType::Playback); @@ -987,7 +988,7 @@ ALCboolean PulsePlayback::reset() pa_stream_set_moved_callback(mStream, &PulsePlayback::streamMovedCallbackC, this); mSpec = *(pa_stream_get_sample_spec(mStream)); - mFrameSize = pa_frame_size(&mSpec); + mFrameSize = static_cast(pa_frame_size(&mSpec)); if(mDevice->Frequency != mSpec.rate) { @@ -1000,9 +1001,9 @@ ALCboolean PulsePlayback::reset() const ALuint buflen{static_cast(clampd(scale*mDevice->BufferSize + 0.5, perlen*2, std::numeric_limits::max()/mFrameSize))}; - mAttr.maxlength = -1; + mAttr.maxlength = ~0u; mAttr.tlength = buflen * mFrameSize; - mAttr.prebuf = 0; + mAttr.prebuf = 0u; mAttr.minreq = perlen * mFrameSize; op = pa_stream_set_buffer_attr(mStream, &mAttr, stream_success_callback, nullptr); @@ -1268,18 +1269,17 @@ ALCenum PulseCapture::open(const ALCchar *name) DevFmtTypeString(mDevice->FmtType)}; } mSpec.rate = mDevice->Frequency; - mSpec.channels = mDevice->channelsFromFmt(); + mSpec.channels = static_cast(mDevice->channelsFromFmt()); if(pa_sample_spec_valid(&mSpec) == 0) throw al::backend_exception{ALC_INVALID_VALUE, "Invalid sample format"}; - ALuint samples{mDevice->BufferSize}; - samples = maxu(samples, 100 * mDevice->Frequency / 1000); - - mAttr.minreq = -1; - mAttr.prebuf = -1; - mAttr.maxlength = samples * pa_frame_size(&mSpec); - mAttr.tlength = -1; - mAttr.fragsize = minu(samples, 50*mDevice->Frequency/1000) * pa_frame_size(&mSpec); + const ALuint frame_size{static_cast(pa_frame_size(&mSpec))}; + const ALuint samples{maxu(mDevice->BufferSize, 100 * mDevice->Frequency / 1000)}; + mAttr.minreq = ~0u; + mAttr.prebuf = ~0u; + mAttr.maxlength = samples * frame_size; + mAttr.tlength = ~0u; + mAttr.fragsize = minu(samples, 50*mDevice->Frequency/1000) * frame_size; pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_ADJUST_LATENCY}; if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 1)) @@ -1384,8 +1384,9 @@ ALCuint PulseCapture::availableSamples() size_t got{pa_stream_readable_size(mStream)}; if(static_cast(got) < 0) { - ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got)); - aluHandleDisconnect(mDevice, "Failed getting readable size: %s", pa_strerror(got)); + const char *err{pa_strerror(static_cast(got))}; + ERR("pa_stream_readable_size() failed: %s\n", err); + aluHandleDisconnect(mDevice, "Failed getting readable size: %s", err); } else { @@ -1396,7 +1397,7 @@ ALCuint PulseCapture::availableSamples() readable = std::min(readable, std::numeric_limits::max()); mLastReadable = std::max(mLastReadable, static_cast(readable)); - return mLastReadable / pa_frame_size(&mSpec); + return mLastReadable / static_cast(pa_frame_size(&mSpec)); } diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 55c95146..b762da76 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -942,10 +942,10 @@ HRESULT WasapiPlayback::resetProxy() } OutputType.Format.nSamplesPerSec = mDevice->Frequency; - OutputType.Format.nBlockAlign = OutputType.Format.nChannels * - OutputType.Format.wBitsPerSample / 8; + OutputType.Format.nBlockAlign = static_cast(OutputType.Format.nChannels * + OutputType.Format.wBitsPerSample / 8); OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * - OutputType.Format.nBlockAlign; + OutputType.Format.nBlockAlign; TraceFormat("Requesting playback format", &OutputType.Format); hr = mClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); @@ -1474,10 +1474,10 @@ HRESULT WasapiCapture::resetProxy() OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; OutputType.Format.nSamplesPerSec = mDevice->Frequency; - OutputType.Format.nBlockAlign = OutputType.Format.nChannels * - OutputType.Format.wBitsPerSample / 8; + OutputType.Format.nBlockAlign = static_cast(OutputType.Format.nChannels * + OutputType.Format.wBitsPerSample / 8); OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * - OutputType.Format.nBlockAlign; + OutputType.Format.nBlockAlign; OutputType.Format.cbSize = sizeof(OutputType) - sizeof(OutputType.Format); TraceFormat("Requesting capture format", &OutputType.Format); diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp index 76e6fe3b..30a19e13 100644 --- a/alc/backends/winmm.cpp +++ b/alc/backends/winmm.cpp @@ -240,7 +240,7 @@ retry_open: mFormat.wBitsPerSample = 16; } mFormat.nChannels = ((mDevice->FmtChans == DevFmtMono) ? 1 : 2); - mFormat.nBlockAlign = mFormat.wBitsPerSample * mFormat.nChannels / 8; + mFormat.nBlockAlign = static_cast(mFormat.wBitsPerSample * mFormat.nChannels / 8); mFormat.nSamplesPerSec = mDevice->Frequency; mFormat.nAvgBytesPerSec = mFormat.nSamplesPerSec * mFormat.nBlockAlign; mFormat.cbSize = 0; @@ -500,9 +500,9 @@ ALCenum WinMMCapture::open(const ALCchar *name) mFormat = WAVEFORMATEX{}; mFormat.wFormatTag = (mDevice->FmtType == DevFmtFloat) ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM; - mFormat.nChannels = mDevice->channelsFromFmt(); - mFormat.wBitsPerSample = mDevice->bytesFromFmt() * 8; - mFormat.nBlockAlign = mFormat.wBitsPerSample * mFormat.nChannels / 8; + mFormat.nChannels = static_cast(mDevice->channelsFromFmt()); + mFormat.wBitsPerSample = static_cast(mDevice->bytesFromFmt() * 8); + mFormat.nBlockAlign = static_cast(mFormat.wBitsPerSample * mFormat.nChannels / 8); mFormat.nSamplesPerSec = mDevice->Frequency; mFormat.nAvgBytesPerSec = mFormat.nSamplesPerSec * mFormat.nBlockAlign; mFormat.cbSize = 0; -- cgit v1.2.3 From 4e8caea97e7164b53fca31802cad7e1160930ae5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 14 Sep 2019 12:50:44 -0700 Subject: Enable -Wconversion warnings This is now clean with Clang 7, let's see what other compilers give. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4effb94a..3ec17ce5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -220,7 +220,7 @@ IF(MSVC) ENDFOREACH(flag_var) ENDIF() ELSE() - SET(C_FLAGS ${C_FLAGS} -Winline -Wall $<$:-Wold-style-cast>) + SET(C_FLAGS ${C_FLAGS} -Winline -Wall $<$:-Wold-style-cast> -Wconversion) CHECK_C_COMPILER_FLAG(-Wextra HAVE_W_EXTRA) IF(HAVE_W_EXTRA) SET(C_FLAGS ${C_FLAGS} -Wextra) -- cgit v1.2.3 From 0023614da545b2d1a7cecd730e80177e37e8ba9e Mon Sep 17 00:00:00 2001 From: Lopuska Date: Sun, 15 Sep 2019 02:09:05 +0200 Subject: pass proper effects slot number to AddActiveEffectSlots It resolves wrong logic when creating more than 1 aux slot at time in a batch --- al/auxeffectslot.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index b765887c..df35c533 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -280,7 +280,8 @@ START_API_FUNC else { al::vector ids; - ids.reserve(static_cast(n)); + ALsizei count{n}; + ids.reserve(static_cast(count)); do { ALeffectslot *slot{AllocEffectSlot(context.get())}; if(!slot) @@ -290,7 +291,7 @@ START_API_FUNC return; } ids.emplace_back(slot->id); - } while(--n); + } while(--count); std::copy(ids.cbegin(), ids.cend(), effectslots); } -- cgit v1.2.3 From 925894fb8b5aa3fd6ab3bdab18dcc08d360e5dbd Mon Sep 17 00:00:00 2001 From: Lopuska Date: Sun, 15 Sep 2019 02:58:53 +0200 Subject: removed unnecessary loop the caller in fshifter is already doing the same job by putting 0 for the imaginary part --- common/alcomplex.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/common/alcomplex.cpp b/common/alcomplex.cpp index 71d3c5f8..f77ec203 100644 --- a/common/alcomplex.cpp +++ b/common/alcomplex.cpp @@ -55,8 +55,6 @@ void complex_fft(const al::span> buffer, const double sign) void complex_hilbert(const al::span> buffer) { - std::for_each(buffer.begin(), buffer.end(), [](std::complex &c) { c.imag(0.0); }); - complex_fft(buffer, 1.0); const double inverse_size = 1.0/static_cast(buffer.size()); -- cgit v1.2.3 From 2c348cecb68bd3a71d388547d6b3330f9cebbfad Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 14 Sep 2019 16:55:28 -0700 Subject: Fix some more implicit conversions noted by GCC --- al/source.cpp | 6 +++--- alc/alc.cpp | 34 +++++++++++++++++-------------- alc/alu.cpp | 10 ++++----- alc/backends/alsa.cpp | 2 +- alc/backends/coreaudio.cpp | 17 ++++++++-------- alc/backends/opensl.cpp | 6 +++--- alc/backends/pulseaudio.cpp | 2 +- alc/bs2b.cpp | 4 ++-- alc/converter.cpp | 2 +- alc/effects/autowah.cpp | 9 +++++---- alc/effects/chorus.cpp | 32 +++++++++++++++-------------- alc/effects/echo.cpp | 6 ++++-- alc/effects/fshifter.cpp | 3 ++- alc/effects/modulator.cpp | 2 +- alc/effects/pshifter.cpp | 19 +++++++++--------- alc/effects/vmorpher.cpp | 14 +++++++------ alc/hrtf.cpp | 49 ++++++++++++++++++++++++--------------------- alc/mastering.cpp | 3 +-- alc/mastering.h | 3 +-- alc/mixer/mixer_c.cpp | 9 +++++---- alc/mixer/mixer_neon.cpp | 13 ++++++------ alc/mixer/mixer_sse.cpp | 7 ++++--- alc/mixer/mixer_sse2.cpp | 2 +- alc/mixer/mixer_sse41.cpp | 2 +- alc/mixvoice.cpp | 18 +++++++++-------- common/almalloc.cpp | 6 +++--- examples/alrecord.c | 5 +++-- examples/altonegen.c | 2 +- examples/common/alhelpers.c | 4 ++-- 29 files changed, 156 insertions(+), 135 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index 478ee3d2..733758f7 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -310,8 +310,8 @@ ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) const ALbufferlistitem *BufferList{Source->queue}; const ALbuffer *BufferFmt{nullptr}; - ALboolean readFin{AL_FALSE}; ALuint totalBufferLen{0u}; + bool readFin{false}; while(BufferList) { @@ -1662,7 +1662,7 @@ bool GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a case AL_SEC_OFFSET_CLOCK_SOFT: CHECKSIZE(values, 2); values[0] = GetSourceSecOffset(Source, Context, &srcclock); - values[1] = srcclock.count() / 1000000000.0; + values[1] = static_cast(srcclock.count()) / 1000000000.0; return true; case AL_POSITION: @@ -2851,7 +2851,7 @@ START_API_FUNC if(device->AvgSpeakerDist > 0.0f) { const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC / - (device->AvgSpeakerDist * device->Frequency)}; + (device->AvgSpeakerDist * static_cast(device->Frequency))}; auto init_nfc = [w1](ALvoice::ChannelData &chandata) -> void { chandata.mDryParams.NFCtrlFilter.init(w1); }; std::for_each(voice->mChans.begin(), voice->mChans.begin()+voice->mNumChannels, diff --git a/alc/alc.cpp b/alc/alc.cpp index 408b3ca3..8e9d3963 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -1587,9 +1587,9 @@ static void alcSetError(ALCdevice *device, ALCenum errorCode) static std::unique_ptr CreateDeviceLimiter(const ALCdevice *device, const ALfloat threshold) { - return CompressorInit(static_cast(device->RealOut.Buffer.size()), device->Frequency, - AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, 0.001f, 0.002f, 0.0f, 0.0f, threshold, - INFINITY, 0.0f, 0.020f, 0.200f); + return CompressorInit(static_cast(device->RealOut.Buffer.size()), + static_cast(device->Frequency), AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, 0.001f, + 0.002f, 0.0f, 0.0f, threshold, INFINITY, 0.0f, 0.020f, 0.200f); } /* UpdateClockBase @@ -2145,17 +2145,21 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(old_sends != device->NumAuxSends) { - if(source->Send.size() > static_cast(device->NumAuxSends)) - std::for_each(source->Send.begin()+device->NumAuxSends, source->Send.end(), - [](ALsource::SendData &send) -> void - { - if(send.Slot) - DecrementRef(send.Slot->ref); - send.Slot = nullptr; - }); - - source->Send.resize(static_cast(device->NumAuxSends), - ALsource::SendData{nullptr, 1.0f, 1.0f, LOWPASSFREQREF, 1.0f, HIGHPASSFREQREF}); + if(source->Send.size() > device->NumAuxSends) + { + auto clear_send = [](ALsource::SendData &send) -> void + { + if(send.Slot) + DecrementRef(send.Slot->ref); + send.Slot = nullptr; + }; + auto send_begin = source->Send.begin() + + static_cast(device->NumAuxSends); + std::for_each(send_begin, source->Send.end(), clear_send); + } + + source->Send.resize(device->NumAuxSends, + {nullptr, 1.0f, 1.0f, LOWPASSFREQREF, 1.0f, HIGHPASSFREQREF}); source->Send.shrink_to_fit(); } @@ -2209,7 +2213,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { /* Reinitialize the NFC filters for new parameters. */ const ALfloat w1{SPEEDOFSOUNDMETRESPERSEC / - (device->AvgSpeakerDist * device->Frequency)}; + (device->AvgSpeakerDist * static_cast(device->Frequency))}; auto init_nfc = [w1](ALvoice::ChannelData &chandata) -> void { chandata.mDryParams.NFCtrlFilter.init(w1); }; std::for_each(voice.mChans.begin(), voice.mChans.begin()+voice.mNumChannels, diff --git a/alc/alu.cpp b/alc/alu.cpp index 0def577e..d7acf8d3 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -201,19 +201,19 @@ void ALCdevice::ProcessBs2b(const size_t SamplesToDo) */ void BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *table) { - ALsizei si{BSINC_SCALE_COUNT - 1}; - ALfloat sf{0.0f}; + size_t si{BSINC_SCALE_COUNT - 1}; + float sf{0.0f}; if(increment > FRACTIONONE) { - sf = static_castFRACTIONONE / increment; + sf = FRACTIONONE / static_cast(increment); sf = maxf(0.0f, (BSINC_SCALE_COUNT-1) * (sf-table->scaleBase) * table->scaleRange); - si = float2int(sf); + si = float2uint(sf); /* The interpolation factor is fit to this diagonally-symmetric curve * to reduce the transition ripple caused by interpolating different * scales of the sinc function. */ - sf = 1.0f - std::cos(std::asin(sf - si)); + sf = 1.0f - std::cos(std::asin(sf - static_cast(si))); } state->sf = sf; diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index cd85afaf..b797c768 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -1112,7 +1112,7 @@ ALCenum AlsaCapture::captureSamples(ALCvoid *buffer, ALCuint samples) } buffer = static_cast(buffer) + amt; - samples -= amt; + samples -= static_cast(amt); } if(samples > 0) std::fill_n(static_cast(buffer), snd_pcm_frames_to_bytes(mPcmHandle, samples), diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 39f6241a..99b06b7a 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -177,7 +177,7 @@ ALCboolean CoreAudioPlayback::reset() { mDevice->BufferSize = static_cast(uint64_t{mDevice->BufferSize} * streamFormat.mSampleRate / mDevice->Frequency); - mDevice->Frequency = streamFormat.mSampleRate; + mDevice->Frequency = static_cast(streamFormat.mSampleRate); } /* FIXME: How to tell what channels are what in the output device, and how @@ -357,7 +357,8 @@ OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags*, } audiobuf = { { 0 } }; auto rec_vec = mRing->getWriteVector(); - inNumberFrames = minz(inNumberFrames, rec_vec.first.len+rec_vec.second.len); + inNumberFrames = static_cast(minz(inNumberFrames, + rec_vec.first.len+rec_vec.second.len)); // Fill the ringbuffer's two segments with data from the input device if(rec_vec.first.len >= inNumberFrames) @@ -369,7 +370,7 @@ OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags*, } else { - const size_t remaining{inNumberFrames-rec_vec.first.len}; + const auto remaining = static_cast(inNumberFrames - rec_vec.first.len); audiobuf.list.mNumberBuffers = 2; audiobuf.list.mBuffers[0].mNumberChannels = mFormat.mChannelsPerFrame; audiobuf.list.mBuffers[0].mData = rec_vec.first.buf; @@ -594,7 +595,7 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) // Set the AudioUnit output format frame count uint64_t FrameCount64{mDevice->UpdateSize}; - FrameCount64 = (FrameCount64*outputFormat.mSampleRate + mDevice->Frequency-1) / + FrameCount64 = static_cast(FrameCount64*outputFormat.mSampleRate + mDevice->Frequency-1) / mDevice->Frequency; FrameCount64 += MAX_RESAMPLE_PADDING*2; if(FrameCount64 > std::numeric_limits::max()/2) @@ -615,8 +616,8 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) // Set up sample converter if needed if(outputFormat.mSampleRate != mDevice->Frequency) mConverter = CreateSampleConverter(mDevice->FmtType, mDevice->FmtType, - mFormat.mChannelsPerFrame, hardwareFormat.mSampleRate, mDevice->Frequency, - BSinc24Resampler); + mFormat.mChannelsPerFrame, static_cast(hardwareFormat.mSampleRate), + mDevice->Frequency, BSinc24Resampler); mRing = CreateRingBuffer(outputFrameCount, mFrameSize, false); if(!mRing) return ALC_INVALID_VALUE; @@ -671,8 +672,8 @@ ALCenum CoreAudioCapture::captureSamples(void *buffer, ALCuint samples) ALCuint CoreAudioCapture::availableSamples() { - if(!mConverter) return mRing->readSpace(); - return mConverter->availableOut(mRing->readSpace()); + if(!mConverter) return static_cast(mRing->readSpace()); + return mConverter->availableOut(static_cast(mRing->readSpace())); } } // namespace diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index 3ec2177f..06d5cd40 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -170,7 +170,7 @@ struct OpenSLPlayback final : public BackendBase { RingBufferPtr mRing{nullptr}; al::semaphore mSem; - ALsizei mFrameSize{0}; + ALuint mFrameSize{0}; std::atomic mKillNow{true}; std::thread mThread; @@ -630,7 +630,7 @@ struct OpenSLCapture final : public BackendBase { RingBufferPtr mRing{nullptr}; ALCuint mSplOffset{0u}; - ALsizei mFrameSize{0}; + ALuint mFrameSize{0}; DEF_NEWDEL(OpenSLCapture) }; @@ -851,7 +851,7 @@ void OpenSLCapture::stop() ALCenum OpenSLCapture::captureSamples(void *buffer, ALCuint samples) { - ALsizei chunk_size = mDevice->UpdateSize * mFrameSize; + ALuint chunk_size{mDevice->UpdateSize * mFrameSize}; SLAndroidSimpleBufferQueueItf bufferQueue; SLresult result; ALCuint i; diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 08420748..30c13a69 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -1324,7 +1324,7 @@ ALCenum PulseCapture::captureSamples(ALCvoid *buffer, ALCuint samples) /* Capture is done in fragment-sized chunks, so we loop until we get all * that's available */ - mLastReadable -= dstbuf.size(); + mLastReadable -= static_cast(dstbuf.size()); std::lock_guard _{pulse_lock}; while(!dstbuf.empty()) { diff --git a/alc/bs2b.cpp b/alc/bs2b.cpp index fb75188c..00207bc0 100644 --- a/alc/bs2b.cpp +++ b/alc/bs2b.cpp @@ -91,11 +91,11 @@ static void init(struct bs2b *bs2b) * $d = 1 / 2 / pi / $fc; * $x = exp(-1 / $d); */ - x = std::exp(-al::MathDefs::Tau() * Fc_lo / bs2b->srate); + x = std::exp(-al::MathDefs::Tau() * Fc_lo / static_cast(bs2b->srate)); bs2b->b1_lo = x; bs2b->a0_lo = G_lo * (1.0f - x) * g; - x = std::exp(-al::MathDefs::Tau() * Fc_hi / bs2b->srate); + x = std::exp(-al::MathDefs::Tau() * Fc_hi / static_cast(bs2b->srate)); bs2b->b1_hi = x; bs2b->a0_hi = (1.0f - G_hi * (1.0f - x)) * g; bs2b->a1_hi = -x * g; diff --git a/alc/converter.cpp b/alc/converter.cpp index 2913f533..2ad2ac3b 100644 --- a/alc/converter.cpp +++ b/alc/converter.cpp @@ -27,7 +27,7 @@ template<> inline ALfloat LoadSample(DevFmtTypeTraits::T template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept { return val * (1.0f/32768.0f); } template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept -{ return val * (1.0f/2147483648.0f); } +{ return static_cast(val) * (1.0f/2147483648.0f); } template<> inline ALfloat LoadSample(DevFmtTypeTraits::Type val) noexcept { return val; } diff --git a/alc/effects/autowah.cpp b/alc/effects/autowah.cpp index f28cfd54..5e396d0c 100644 --- a/alc/effects/autowah.cpp +++ b/alc/effects/autowah.cpp @@ -107,16 +107,17 @@ ALboolean ALautowahState::deviceUpdate(const ALCdevice*) void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { const ALCdevice *device{context->mDevice.get()}; + const auto frequency = static_cast(device->Frequency); const ALfloat ReleaseTime{clampf(props->Autowah.ReleaseTime, 0.001f, 1.0f)}; - mAttackRate = expf(-1.0f / (props->Autowah.AttackTime*device->Frequency)); - mReleaseRate = expf(-1.0f / (ReleaseTime*device->Frequency)); + mAttackRate = std::exp(-1.0f / (props->Autowah.AttackTime*frequency)); + mReleaseRate = std::exp(-1.0f / (ReleaseTime*frequency)); /* 0-20dB Resonance Peak gain */ mResonanceGain = std::sqrt(std::log10(props->Autowah.Resonance)*10.0f / 3.0f); mPeakGain = 1.0f - std::log10(props->Autowah.PeakGain/AL_AUTOWAH_MAX_PEAK_GAIN); - mFreqMinNorm = MIN_FREQ / device->Frequency; - mBandwidthNorm = (MAX_FREQ-MIN_FREQ) / device->Frequency; + mFreqMinNorm = MIN_FREQ / frequency; + mBandwidthNorm = (MAX_FREQ-MIN_FREQ) / frequency; mOutTarget = target.Main->Buffer; for(size_t i{0u};i < slot->Wet.Buffer.size();++i) diff --git a/alc/effects/chorus.cpp b/alc/effects/chorus.cpp index 6e73f1f0..0e3c9d89 100644 --- a/alc/effects/chorus.cpp +++ b/alc/effects/chorus.cpp @@ -64,8 +64,8 @@ void GetTriangleDelays(ALuint *delays, const ALuint start_offset, const ALuint l auto gen_lfo = [&offset,lfo_range,lfo_scale,depth,delay]() -> ALuint { offset = (offset+1)%lfo_range; - return static_cast( - fastf2i((1.0f - std::abs(2.0f - lfo_scale*offset)) * depth) + delay); + const float offset_norm{static_cast(offset) * lfo_scale}; + return static_cast(fastf2i((1.0f-std::abs(2.0f-offset_norm)) * depth) + delay); }; std::generate_n(delays, todo, gen_lfo); } @@ -80,7 +80,8 @@ void GetSinusoidDelays(ALuint *delays, const ALuint start_offset, const ALuint l auto gen_lfo = [&offset,lfo_range,lfo_scale,depth,delay]() -> ALuint { offset = (offset+1)%lfo_range; - return static_cast(fastf2i(std::sin(lfo_scale*offset) * depth) + delay); + const float offset_norm{static_cast(offset) * lfo_scale}; + return static_cast(fastf2i(std::sin(offset_norm)*depth) + delay); }; std::generate_n(delays, todo, gen_lfo); } @@ -118,7 +119,8 @@ ALboolean ChorusState::deviceUpdate(const ALCdevice *Device) { constexpr ALfloat max_delay{maxf(AL_CHORUS_MAX_DELAY, AL_FLANGER_MAX_DELAY)}; - const size_t maxlen{NextPowerOf2(float2uint(max_delay*2.0f*Device->Frequency) + 1u)}; + const auto frequency = static_cast(Device->Frequency); + const size_t maxlen{NextPowerOf2(float2uint(max_delay*2.0f*frequency) + 1u)}; if(maxlen != mSampleBuffer.size()) { mSampleBuffer.resize(maxlen); @@ -153,9 +155,11 @@ void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, co * delay and depth to allow enough padding for resampling. */ const ALCdevice *device{Context->mDevice.get()}; - const auto frequency = static_cast(device->Frequency); + const auto frequency = static_cast(device->Frequency); + mDelay = maxi(float2int(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f), mindelay); - mDepth = minf(props->Chorus.Depth * mDelay, static_cast(mDelay - mindelay)); + mDepth = minf(props->Chorus.Depth * static_cast(mDelay), + static_cast(mDelay - mindelay)); mFeedback = props->Chorus.Feedback; @@ -188,10 +192,10 @@ void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, co switch(mWaveform) { case WaveForm::Triangle: - mLfoScale = 4.0f / mLfoRange; + mLfoScale = 4.0f / static_cast(mLfoRange); break; case WaveForm::Sinusoid: - mLfoScale = al::MathDefs::Tau() / mLfoRange; + mLfoScale = al::MathDefs::Tau() / static_cast(mLfoRange); break; } @@ -229,7 +233,7 @@ void ChorusState::process(const size_t samplesToDo, const al::span(todo)) % mLfoRange; alignas(16) ALfloat temps[2][256]; for(size_t i{0u};i < todo;i++) @@ -239,17 +243,15 @@ void ChorusState::process(const size_t samplesToDo, const al::span>FRACTIONBITS)}; - ALfloat mu{(moddelays[0][i]&FRACTIONMASK) * (1.0f/FRACTIONONE)}; + ALfloat mu{static_cast(moddelays[0][i]&FRACTIONMASK) * (1.0f/FRACTIONONE)}; temps[0][i] = cubic(delaybuf[(delay+1) & bufmask], delaybuf[(delay ) & bufmask], - delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask], - mu); + delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask], mu); // Tap for the right output. delay = offset - (moddelays[1][i]>>FRACTIONBITS); - mu = (moddelays[1][i]&FRACTIONMASK) * (1.0f/FRACTIONONE); + mu = static_cast(moddelays[1][i]&FRACTIONMASK) * (1.0f/FRACTIONONE); temps[1][i] = cubic(delaybuf[(delay+1) & bufmask], delaybuf[(delay ) & bufmask], - delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask], - mu); + delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask], mu); // Accumulate feedback from the average delay of the taps. delaybuf[offset&bufmask] += delaybuf[(offset-avgdelay) & bufmask] * feedback; diff --git a/alc/effects/echo.cpp b/alc/effects/echo.cpp index 47c0fedb..a9213df5 100644 --- a/alc/effects/echo.cpp +++ b/alc/effects/echo.cpp @@ -66,10 +66,12 @@ struct EchoState final : public EffectState { ALboolean EchoState::deviceUpdate(const ALCdevice *Device) { + const auto frequency = static_cast(Device->Frequency); + // Use the next power of 2 for the buffer length, so the tap offsets can be // wrapped using a mask instead of a modulo - const ALuint maxlen{NextPowerOf2(float2uint(AL_ECHO_MAX_DELAY*Device->Frequency + 0.5f) + - float2uint(AL_ECHO_MAX_LRDELAY*Device->Frequency + 0.5f))}; + const ALuint maxlen{NextPowerOf2(float2uint(AL_ECHO_MAX_DELAY*frequency + 0.5f) + + float2uint(AL_ECHO_MAX_LRDELAY*frequency + 0.5f))}; if(maxlen != mSampleBuffer.size()) { mSampleBuffer.resize(maxlen); diff --git a/alc/effects/fshifter.cpp b/alc/effects/fshifter.cpp index c015831c..1b935047 100644 --- a/alc/effects/fshifter.cpp +++ b/alc/effects/fshifter.cpp @@ -51,7 +51,8 @@ std::array InitHannWindow() /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */ for(size_t i{0};i < HIL_SIZE>>1;i++) { - const double val{std::sin(al::MathDefs::Pi() * i / double{HIL_SIZE-1})}; + constexpr double scale{al::MathDefs::Pi() / double{HIL_SIZE-1}}; + const double val{std::sin(static_cast(i) * scale)}; ret[i] = ret[HIL_SIZE-1-i] = val * val; } return ret; diff --git a/alc/effects/modulator.cpp b/alc/effects/modulator.cpp index fbc6377c..8042378a 100644 --- a/alc/effects/modulator.cpp +++ b/alc/effects/modulator.cpp @@ -146,7 +146,7 @@ void ModulatorState::process(const size_t samplesToDo, const al::span(mStep * td); mIndex &= WAVEFORM_FRACMASK; auto chandata = std::addressof(mChans[0]); diff --git a/alc/effects/pshifter.cpp b/alc/effects/pshifter.cpp index a4d66706..d7ba072e 100644 --- a/alc/effects/pshifter.cpp +++ b/alc/effects/pshifter.cpp @@ -57,7 +57,8 @@ std::array InitHannWindow() /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */ for(size_t i{0};i < STFT_SIZE>>1;i++) { - const double val{std::sin(al::MathDefs::Pi() * i / ALdouble{STFT_SIZE-1})}; + constexpr double scale{al::MathDefs::Pi() / double{STFT_SIZE-1}}; + const double val{std::sin(static_cast(i) * scale)}; ret[i] = ret[STFT_SIZE-1-i] = val * val; } return ret; @@ -129,7 +130,7 @@ ALboolean PshifterState::deviceUpdate(const ALCdevice *device) mCount = FIFO_LATENCY; mPitchShiftI = FRACTIONONE; mPitchShift = 1.0f; - mFreqPerBin = device->Frequency / static_cast(STFT_SIZE); + mFreqPerBin = static_cast(device->Frequency) / float{STFT_SIZE}; std::fill(std::begin(mInFIFO), std::end(mInFIFO), 0.0f); std::fill(std::begin(mOutFIFO), std::end(mOutFIFO), 0.0f); @@ -152,7 +153,7 @@ void PshifterState::update(const ALCcontext*, const ALeffectslot *slot, const Ef static_cast(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f )}; mPitchShiftI = fastf2u(pitch*FRACTIONONE); - mPitchShift = mPitchShiftI * (1.0f/FRACTIONONE); + mPitchShift = static_cast(mPitchShiftI) * (1.0f/FRACTIONONE); ALfloat coeffs[MAX_AMBI_CHANNELS]; CalcDirectionCoeffs({0.0f, 0.0f, -1.0f}, 0.0f, coeffs); @@ -187,7 +188,7 @@ void PshifterState::process(const size_t samplesToDo, const al::spanVmorpher.Waveform == AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE)*/ mGetSamples = Oscillate; - const ALfloat pitchA{std::pow(2.0f, props->Vmorpher.PhonemeACoarseTuning / 12.0f)}; - const ALfloat pitchB{std::pow(2.0f, props->Vmorpher.PhonemeBCoarseTuning / 12.0f)}; + const ALfloat pitchA{std::pow(2.0f, + static_cast(props->Vmorpher.PhonemeACoarseTuning) / 12.0f)}; + const ALfloat pitchB{std::pow(2.0f, + static_cast(props->Vmorpher.PhonemeBCoarseTuning) / 12.0f)}; auto vowelA = getFiltersByPhoneme(props->Vmorpher.PhonemeA, frequency, pitchA); auto vowelB = getFiltersByPhoneme(props->Vmorpher.PhonemeB, frequency, pitchB); @@ -255,7 +257,7 @@ void VmorpherState::process(const size_t samplesToDo, const al::span(mStep * td); mIndex &= WAVEFORM_FRACMASK; auto chandata = std::addressof(mChans[0]); diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index bd6ecb3a..e20bf0a9 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -182,10 +182,11 @@ struct IdxBlend { ALsizei idx; ALfloat blend; }; */ IdxBlend CalcEvIndex(ALsizei evcount, ALfloat ev) { - ev = (al::MathDefs::Pi()*0.5f + ev) * (evcount-1) / al::MathDefs::Pi(); + ev = (al::MathDefs::Pi()*0.5f + ev) * static_cast(evcount-1) / + al::MathDefs::Pi(); ALsizei idx{float2int(ev)}; - return IdxBlend{mini(idx, evcount-1), ev-idx}; + return IdxBlend{mini(idx, evcount-1), ev-static_cast(idx)}; } /* Calculate the azimuth index given the polar azimuth in radians. This will @@ -193,10 +194,11 @@ IdxBlend CalcEvIndex(ALsizei evcount, ALfloat ev) */ IdxBlend CalcAzIndex(ALsizei azcount, ALfloat az) { - az = (al::MathDefs::Tau()+az) * azcount / al::MathDefs::Tau(); + az = (al::MathDefs::Tau()+az) * static_cast(azcount) / + al::MathDefs::Tau(); ALsizei idx{float2int(az)}; - return IdxBlend{idx%azcount, az-idx}; + return IdxBlend{idx%azcount, az-static_cast(idx)}; } } // namespace @@ -303,24 +305,25 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin ASSUME(NumChannels > 0); ASSUME(AmbiCount > 0); - auto &field = Hrtf->field[0]; ALuint min_delay{HRTF_HISTORY_LENGTH}; ALuint max_delay{0}; auto idx = al::vector(AmbiCount); - auto calc_idxs = [Hrtf,&field,&max_delay,&min_delay](const AngularPoint &pt) noexcept -> ALuint + auto calc_idxs = [Hrtf,&max_delay,&min_delay](const AngularPoint &pt) noexcept -> ALuint { + auto &field = Hrtf->field[0]; /* Calculate elevation index. */ - const auto evidx = clampi(float2int((90.0f+pt.Elev)*(field.evCount-1)/180.0f + 0.5f), - 0, field.evCount-1); + const auto ev_limit = static_cast(field.evCount-1); + const ALuint evidx{float2uint(clampf((90.0f+pt.Elev)/180.0f, 0.0f, 1.0f)*ev_limit + 0.5f)}; const ALuint azcount{Hrtf->elev[evidx].azCount}; const ALuint iroffset{Hrtf->elev[evidx].irOffset}; /* Calculate azimuth index for this elevation. */ - const auto azidx = static_cast((360.0f+pt.Azim)*azcount/360.0f + 0.5f) % azcount; + const float az_norm{(360.0f*pt.Azim) / 360.0f}; + const ALuint azidx{float2uint(az_norm*static_cast(azcount) + 0.5f) % azcount}; /* Calculate the index for the impulse response. */ - ALuint idx{iroffset + azidx}; + const ALuint idx{iroffset + azidx}; min_delay = minu(min_delay, minu(Hrtf->delays[idx][0], Hrtf->delays[idx][1])); max_delay = maxu(max_delay, maxu(Hrtf->delays[idx][0], Hrtf->delays[idx][1])); @@ -594,7 +597,7 @@ std::unique_ptr LoadHrtf00(std::istream &data, const char *filename) if(failed) return nullptr; - al::vector evOffset(evCount); + auto evOffset = al::vector(evCount); for(auto &val : evOffset) val = GetLE_ALushort(data); if(!data || data.eof()) @@ -619,10 +622,10 @@ std::unique_ptr LoadHrtf00(std::istream &data, const char *filename) if(failed) return nullptr; - al::vector azCount(evCount); + auto azCount = al::vector(evCount); for(size_t i{1};i < evCount;i++) { - azCount[i-1] = evOffset[i] - evOffset[i-1]; + azCount[i-1] = static_cast(evOffset[i] - evOffset[i-1]); if(azCount[i-1] < MIN_AZ_COUNT || azCount[i-1] > MAX_AZ_COUNT) { ERR("Unsupported azimuth count: azCount[%zd]=%d (%d to %d)\n", @@ -630,7 +633,7 @@ std::unique_ptr LoadHrtf00(std::istream &data, const char *filename) failed = AL_TRUE; } } - azCount.back() = irCount - evOffset.back(); + azCount.back() = static_cast(irCount - evOffset.back()); if(azCount.back() < MIN_AZ_COUNT || azCount.back() > MAX_AZ_COUNT) { ERR("Unsupported azimuth count: azCount[%zu]=%d (%d to %d)\n", @@ -640,8 +643,8 @@ std::unique_ptr LoadHrtf00(std::istream &data, const char *filename) if(failed) return nullptr; - al::vector> coeffs(irSize*irCount); - al::vector> delays(irCount); + auto coeffs = al::vector>(irSize*irCount); + auto delays = al::vector>(irCount); for(auto &val : coeffs) val[0] = GetLE_ALshort(data) / 32768.0f; for(auto &val : delays) @@ -711,7 +714,7 @@ std::unique_ptr LoadHrtf01(std::istream &data, const char *filename) if(failed) return nullptr; - al::vector azCount(evCount); + auto azCount = al::vector(evCount); std::generate(azCount.begin(), azCount.end(), std::bind(GetLE_ALubyte, std::ref(data))); if(!data || data.eof()) { @@ -735,12 +738,12 @@ std::unique_ptr LoadHrtf01(std::istream &data, const char *filename) ALushort irCount{azCount[0]}; for(size_t i{1};i < evCount;i++) { - evOffset[i] = evOffset[i-1] + azCount[i-1]; + evOffset[i] = static_cast(evOffset[i-1] + azCount[i-1]); irCount += azCount[i]; } - al::vector> coeffs(irSize*irCount); - al::vector> delays(irCount); + auto coeffs = al::vector>(irSize*irCount); + auto delays = al::vector>(irCount); for(auto &val : coeffs) val[0] = GetLE_ALshort(data) / 32768.0f; for(auto &val : delays) @@ -903,7 +906,7 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) else if(sampleType == SAMPLETYPE_S24) { for(auto &val : coeffs) - val[0] = GetLE_ALint24(data) / 8388608.0f; + val[0] = static_cast(GetLE_ALint24(data)) / 8388608.0f; } for(auto &val : delays) val[0] = GetLE_ALubyte(data); @@ -935,8 +938,8 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) { for(auto &val : coeffs) { - val[0] = GetLE_ALint24(data) / 8388608.0f; - val[1] = GetLE_ALint24(data) / 8388608.0f; + val[0] = static_cast(GetLE_ALint24(data)) / 8388608.0f; + val[1] = static_cast(GetLE_ALint24(data)) / 8388608.0f; } } for(auto &val : delays) diff --git a/alc/mastering.cpp b/alc/mastering.cpp index 2f575f35..d0a2f78a 100644 --- a/alc/mastering.cpp +++ b/alc/mastering.cpp @@ -337,7 +337,7 @@ void SignalDelay(Compressor *Comp, const ALuint SamplesToDo, FloatBufferLine *Ou * ReleaseTimeMin - Release time (in seconds). Acts as a maximum when * automating release time. */ -std::unique_ptr CompressorInit(const ALuint NumChans, const ALuint SampleRate, +std::unique_ptr CompressorInit(const ALuint NumChans, const ALfloat SampleRate, const ALboolean AutoKnee, const ALboolean AutoAttack, const ALboolean AutoRelease, const ALboolean AutoPostGain, const ALboolean AutoDeclip, const ALfloat LookAheadTime, const ALfloat HoldTime, const ALfloat PreGainDb, const ALfloat PostGainDb, @@ -363,7 +363,6 @@ std::unique_ptr CompressorInit(const ALuint NumChans, const ALuint S auto Comp = std::unique_ptr{new (al_calloc(16, size)) Compressor{}}; Comp->mNumChans = NumChans; - Comp->mSampleRate = SampleRate; Comp->mAuto.Knee = AutoKnee != AL_FALSE; Comp->mAuto.Attack = AutoAttack != AL_FALSE; Comp->mAuto.Release = AutoRelease != AL_FALSE; diff --git a/alc/mastering.h b/alc/mastering.h index 6c8fc628..851381e9 100644 --- a/alc/mastering.h +++ b/alc/mastering.h @@ -24,7 +24,6 @@ struct SlidingHold; */ struct Compressor { ALuint mNumChans{0u}; - ALuint mSampleRate{0u}; struct { bool Knee : 1; @@ -94,7 +93,7 @@ struct Compressor { * ReleaseTimeMin - Release time (in seconds). Acts as a maximum when * automating release time. */ -std::unique_ptr CompressorInit(const ALuint NumChans, const ALuint SampleRate, +std::unique_ptr CompressorInit(const ALuint NumChans, const ALfloat SampleRate, const ALboolean AutoKnee, const ALboolean AutoAttack, const ALboolean AutoRelease, const ALboolean AutoPostGain, const ALboolean AutoDeclip, const ALfloat LookAheadTime, const ALfloat HoldTime, const ALfloat PreGainDb, const ALfloat PostGainDb, diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index 720b264b..74315dd5 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -16,9 +16,9 @@ namespace { inline ALfloat do_point(const InterpState&, const ALfloat *RESTRICT vals, const ALuint) { return vals[0]; } inline ALfloat do_lerp(const InterpState&, const ALfloat *RESTRICT vals, const ALuint frac) -{ return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); } +{ return lerp(vals[0], vals[1], static_cast(frac)*(1.0f/FRACTIONONE)); } inline ALfloat do_cubic(const InterpState&, const ALfloat *RESTRICT vals, const ALuint frac) -{ return cubic(vals[0], vals[1], vals[2], vals[3], frac * (1.0f/FRACTIONONE)); } +{ return cubic(vals[0], vals[1], vals[2], vals[3], static_cast(frac)*(1.0f/FRACTIONONE)); } inline ALfloat do_bsinc(const InterpState &istate, const ALfloat *RESTRICT vals, const ALuint frac) { ASSUME(istate.bsinc.m > 0); @@ -26,10 +26,11 @@ inline ALfloat do_bsinc(const InterpState &istate, const ALfloat *RESTRICT vals, // Calculate the phase index and factor. #define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) const ALuint pi{frac >> FRAC_PHASE_BITDIFF}; - const ALfloat pf{(frac & ((1<(frac & ((1<(istate.bsinc.m)*pi*4}; const ALfloat *scd{fil + istate.bsinc.m}; const ALfloat *phd{scd + istate.bsinc.m}; const ALfloat *spd{phd + istate.bsinc.m}; diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index 852bef38..2f11273a 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -55,10 +55,10 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES if(dst_iter != dst.end()) { src += static_cast(vgetq_lane_s32(pos4, 0)); - frac = vgetq_lane_s32(frac4, 0); + frac = static_cast(vgetq_lane_s32(frac4, 0)); do { - *(dst_iter++) = lerp(src[0], src[1], frac * (1.0f/FRACTIONONE)); + *(dst_iter++) = lerp(src[0], src[1], static_cast(frac) * (1.0f/FRACTIONONE)); frac += increment; src += frac>>FRACTIONBITS; @@ -84,14 +84,15 @@ const ALfloat *Resample_(const InterpState *state, const ALflo // Calculate the phase index and factor. #define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) const ALuint pi{frac >> FRAC_PHASE_BITDIFF}; - const ALfloat pf{(frac & ((1<(frac & ((1<(pi*4)}; const float *scd{fil + m}; const float *phd{scd + m}; const float *spd{phd + m}; @@ -179,8 +180,8 @@ void Mix_(const al::span InSamples, const al::span 0) ? 1.0f / static_cast(Counter) : 0.0f}; const bool reached_target{InSamples.size() >= Counter}; const auto min_end = reached_target ? InSamples.begin() + Counter : InSamples.end(); - const auto aligned_end = minz(InSamples.size(), (min_end-InSamples.begin()+3) & ~3u) + - InSamples.begin(); + const auto aligned_end = minz(static_cast(min_end-InSamples.begin()+3) & ~3u, + InSamples.size()) + InSamples.begin(); for(FloatBufferLine &output : OutBuffer) { ALfloat *RESTRICT dst{al::assume_aligned<16>(output.data()+OutPos)}; diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index 368b8dfe..65eb0dee 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -29,7 +29,8 @@ const ALfloat *Resample_(const InterpState *state, const ALfloa // Calculate the phase index and factor. #define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) const ALuint pi{frac >> FRAC_PHASE_BITDIFF}; - const ALfloat pf{(frac & ((1<(frac & ((1<(const al::span InSamples, const al::span 0) ? 1.0f / static_cast(Counter) : 0.0f}; const bool reached_target{InSamples.size() >= Counter}; const auto min_end = reached_target ? InSamples.begin() + Counter : InSamples.end(); - const auto aligned_end = minz(InSamples.size(), (min_end-InSamples.begin()+3) & ~3u) + - InSamples.begin(); + const auto aligned_end = minz(static_cast(min_end-InSamples.begin()+3) & ~3u, + InSamples.size()) + InSamples.begin(); for(FloatBufferLine &output : OutBuffer) { ALfloat *RESTRICT dst{al::assume_aligned<16>(output.data()+OutPos)}; diff --git a/alc/mixer/mixer_sse2.cpp b/alc/mixer/mixer_sse2.cpp index 38d77fd9..897cd1f7 100644 --- a/alc/mixer/mixer_sse2.cpp +++ b/alc/mixer/mixer_sse2.cpp @@ -72,7 +72,7 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES frac = static_cast(_mm_cvtsi128_si32(frac4)); do { - *(dst_iter++) = lerp(src[0], src[1], frac * (1.0f/FRACTIONONE)); + *(dst_iter++) = lerp(src[0], src[1], static_cast(frac) * (1.0f/FRACTIONONE)); frac += increment; src += frac>>FRACTIONBITS; diff --git a/alc/mixer/mixer_sse41.cpp b/alc/mixer/mixer_sse41.cpp index 0a87f76f..cfa21e99 100644 --- a/alc/mixer/mixer_sse41.cpp +++ b/alc/mixer/mixer_sse41.cpp @@ -77,7 +77,7 @@ const ALfloat *Resample_(const InterpState*, const ALfloat *RES frac = static_cast(_mm_cvtsi128_si32(frac4)); do { - *(dst_iter++) = lerp(src[0], src[1], frac * (1.0f/FRACTIONONE)); + *(dst_iter++) = lerp(src[0], src[1], static_cast(frac) * (1.0f/FRACTIONONE)); frac += increment; src += frac>>FRACTIONBITS; diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 7bdeea5e..d7a32f35 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -287,33 +287,35 @@ struct FmtTypeTraits { }; template<> struct FmtTypeTraits { using Type = ALubyte; - static constexpr ALfloat to_float(const Type val) { return (val-128) * (1.0f/128.0f); } + static constexpr ALfloat to_float(const Type val) noexcept + { return val*(1.0f/128.0f) - 128.0f; } }; template<> struct FmtTypeTraits { using Type = ALshort; - static constexpr ALfloat to_float(const Type val) { return val * (1.0f/32768.0f); } + static constexpr ALfloat to_float(const Type val) noexcept { return val*(1.0f/32768.0f); } }; template<> struct FmtTypeTraits { using Type = ALfloat; - static constexpr ALfloat to_float(const Type val) { return val; } + static constexpr ALfloat to_float(const Type val) noexcept { return val; } }; template<> struct FmtTypeTraits { using Type = ALdouble; - static constexpr ALfloat to_float(const Type val) { return static_cast(val); } + static constexpr ALfloat to_float(const Type val) noexcept + { return static_cast(val); } }; template<> struct FmtTypeTraits { using Type = ALubyte; - static constexpr ALfloat to_float(const Type val) + static constexpr ALfloat to_float(const Type val) noexcept { return muLawDecompressionTable[val] * (1.0f/32768.0f); } }; template<> struct FmtTypeTraits { using Type = ALubyte; - static constexpr ALfloat to_float(const Type val) + static constexpr ALfloat to_float(const Type val) noexcept { return aLawDecompressionTable[val] * (1.0f/32768.0f); } }; @@ -363,7 +365,7 @@ const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, ALfloat template inline void LoadSampleArray(ALfloat *RESTRICT dst, const al::byte *src, const size_t srcstep, - const size_t samples) + const size_t samples) noexcept { using SampleType = typename FmtTypeTraits::Type; @@ -373,7 +375,7 @@ inline void LoadSampleArray(ALfloat *RESTRICT dst, const al::byte *src, const si } void LoadSamples(ALfloat *RESTRICT dst, const al::byte *src, const size_t srcstep, FmtType srctype, - const size_t samples) + const size_t samples) noexcept { #define HANDLE_FMT(T) case T: LoadSampleArray(dst, src, srcstep, samples); break switch(srctype) diff --git a/common/almalloc.cpp b/common/almalloc.cpp index 8700bddc..842fb400 100644 --- a/common/almalloc.cpp +++ b/common/almalloc.cpp @@ -30,11 +30,11 @@ void *al_malloc(size_t alignment, size_t size) #elif defined(HAVE__ALIGNED_MALLOC) return _aligned_malloc(size, alignment); #else - char *ret = static_cast(malloc(size+alignment)); + auto *ret = static_cast(malloc(size+alignment)); if(ret != nullptr) { *(ret++) = 0x00; - while((reinterpret_cast(ret)&(alignment-1)) != 0) + while((reinterpret_cast(ret)&(alignment-1)) != 0) *(ret++) = 0x55; } return ret; @@ -57,7 +57,7 @@ void al_free(void *ptr) noexcept #else if(ptr != nullptr) { - char *finder = static_cast(ptr); + auto *finder = static_cast(ptr); do { --finder; } while(*finder == 0x55); diff --git a/examples/alrecord.c b/examples/alrecord.c index 627f8540..a66e5471 100644 --- a/examples/alrecord.c +++ b/examples/alrecord.c @@ -54,13 +54,14 @@ static float msvc_strtof(const char *str, char **end) static void fwrite16le(ALushort val, FILE *f) { - ALubyte data[2] = { val&0xff, (val>>8)&0xff }; + ALubyte data[2] = { (ALubyte)(val&0xff), (ALubyte)((val>>8)&0xff) }; fwrite(data, 1, 2, f); } static void fwrite32le(ALuint val, FILE *f) { - ALubyte data[4] = { val&0xff, (val>>8)&0xff, (val>>16)&0xff, (val>>24)&0xff }; + ALubyte data[4] = { (ALubyte)(val&0xff), (ALubyte)((val>>8)&0xff), (ALubyte)((val>>16)&0xff), + (ALubyte)((val>>24)&0xff) }; fwrite(data, 1, 4, f); } diff --git a/examples/altonegen.c b/examples/altonegen.c index aacc3496..26ae788d 100644 --- a/examples/altonegen.c +++ b/examples/altonegen.c @@ -97,7 +97,7 @@ static ALuint CreateWave(enum WaveType type, ALuint freq, ALuint srate) ALenum err; ALuint i; - data_size = srate * sizeof(ALfloat); + data_size = (ALuint)(srate * sizeof(ALfloat)); data = calloc(1, data_size); switch(type) { diff --git a/examples/common/alhelpers.c b/examples/common/alhelpers.c index 730d2e13..0febef43 100644 --- a/examples/common/alhelpers.c +++ b/examples/common/alhelpers.c @@ -175,8 +175,8 @@ int altime_get(void) void al_nssleep(unsigned long nsec) { struct timespec ts, rem; - ts.tv_sec = nsec / 1000000000ul; - ts.tv_nsec = nsec % 1000000000ul; + ts.tv_sec = (time_t)(nsec / 1000000000ul); + ts.tv_nsec = (long)(nsec % 1000000000ul); while(nanosleep(&ts, &rem) == -1 && errno == EINTR) ts = rem; } -- cgit v1.2.3 From d75de6ee4dc81a6a1cb5d6e77246ac2a3751a0fd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 14 Sep 2019 17:01:22 -0700 Subject: Don't hold the pulse lock while not necessary --- alc/backends/pulseaudio.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 30c13a69..9c54c07b 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -1325,13 +1325,13 @@ ALCenum PulseCapture::captureSamples(ALCvoid *buffer, ALCuint samples) /* Capture is done in fragment-sized chunks, so we loop until we get all * that's available */ mLastReadable -= static_cast(dstbuf.size()); - std::lock_guard _{pulse_lock}; while(!dstbuf.empty()) { if(mCapBuffer.empty()) { if UNLIKELY(!mDevice->Connected.load(std::memory_order_acquire)) break; + std::lock_guard _{pulse_lock}; const pa_stream_state_t state{pa_stream_get_state(mStream)}; if UNLIKELY(!PA_STREAM_IS_GOOD(state)) { @@ -1364,6 +1364,7 @@ ALCenum PulseCapture::captureSamples(ALCvoid *buffer, ALCuint samples) if(mCapBuffer.empty()) { + std::lock_guard _{pulse_lock}; pa_stream_drop(mStream); mCapLen = 0; } -- cgit v1.2.3 From 2cc0600476fc4ed13a64eeb59c02c213bd3b6dd4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 14 Sep 2019 17:14:26 -0700 Subject: Avoid recalculations in the formant filter process --- alc/effects/vmorpher.cpp | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/alc/effects/vmorpher.cpp b/alc/effects/vmorpher.cpp index c451bedb..d24d41d6 100644 --- a/alc/effects/vmorpher.cpp +++ b/alc/effects/vmorpher.cpp @@ -78,40 +78,47 @@ void Oscillate(ALfloat *RESTRICT dst, ALuint index, const ALuint step, size_t to struct FormantFilter { - ALfloat f0norm{0.0f}; - ALfloat fGain{1.0f}; - ALfloat s1{0.0f}; - ALfloat s2{0.0f}; + ALfloat mCoeff{0.0f}; + ALfloat mGain{1.0f}; + ALfloat mS1{0.0f}; + ALfloat mS2{0.0f}; FormantFilter() = default; - FormantFilter(ALfloat f0norm_, ALfloat gain) : f0norm{f0norm_}, fGain{gain} { } + FormantFilter(ALfloat f0norm, ALfloat gain) + : mCoeff{std::tan(al::MathDefs::Pi() * f0norm)}, mGain{gain} + { } inline void process(const ALfloat *samplesIn, ALfloat *samplesOut, const size_t numInput) { /* A state variable filter from a topology-preserving transform. * Based on a talk given by Ivan Cohen: https://www.youtube.com/watch?v=esjHXGPyrhg */ - const ALfloat g = std::tan(al::MathDefs::Pi() * f0norm); - const ALfloat h = 1.0f / (1 + (g / Q_FACTOR) + (g * g)); + const ALfloat g{mCoeff}; + const ALfloat gain{mGain}; + const ALfloat h{1.0f / (1.0f + (g/Q_FACTOR) + (g*g))}; + ALfloat s1{mS1}; + ALfloat s2{mS2}; for(size_t i{0u};i < numInput;i++) { - const ALfloat H = h * (samplesIn[i] - (1.0f / Q_FACTOR + g) * s1 - s2); - const ALfloat B = g * H + s1; - const ALfloat L = g * B + s2; + const ALfloat H{(samplesIn[i] - (1.0f/Q_FACTOR + g)*s1 - s2)*h}; + const ALfloat B{g*H + s1}; + const ALfloat L{g*B + s2}; - s1 = g * H + B; - s2 = g * B + L; + s1 = g*H + B; + s2 = g*B + L; // Apply peak and accumulate samples. - samplesOut[i] += B * fGain; + samplesOut[i] += B * gain; } + mS1 = s1; + mS2 = s2; } inline void clear() { - s1 = 0.0f; - s2 = 0.0f; + mS1 = 0.0f; + mS2 = 0.0f; } }; -- cgit v1.2.3 From 807d3b64cac2793ce678acb3fc4d4191b2252875 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 14 Sep 2019 18:27:57 -0700 Subject: Enable and fix more warnings --- CMakeLists.txt | 7 ++----- al/event.cpp | 18 +++++------------- al/source.cpp | 30 ++++++++++++++++-------------- alc/alc.cpp | 8 ++++---- alc/alconfig.cpp | 12 ++++++------ alc/backends/base.h | 2 ++ alc/backends/pulseaudio.cpp | 2 +- alc/filters/biquad.cpp | 28 ++++++++++++++-------------- alc/filters/biquad.h | 32 +++++++++++++++----------------- alc/filters/splitter.cpp | 44 ++++++++++++++++++++++---------------------- alc/filters/splitter.h | 10 +++++----- alc/hrtf.cpp | 8 ++++---- alc/hrtf.h | 2 +- alc/mixvoice.cpp | 29 +++++++++++++++-------------- utils/makemhr/loaddef.cpp | 9 ++++----- utils/makemhr/loadsofa.cpp | 10 +++------- utils/sofa-info.cpp | 10 +++------- 17 files changed, 122 insertions(+), 139 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ec17ce5..44d829d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -220,11 +220,8 @@ IF(MSVC) ENDFOREACH(flag_var) ENDIF() ELSE() - SET(C_FLAGS ${C_FLAGS} -Winline -Wall $<$:-Wold-style-cast> -Wconversion) - CHECK_C_COMPILER_FLAG(-Wextra HAVE_W_EXTRA) - IF(HAVE_W_EXTRA) - SET(C_FLAGS ${C_FLAGS} -Wextra) - ENDIF() + SET(C_FLAGS ${C_FLAGS} -Winline -Wall -Wextra -Wshadow -Wconversion -Wcast-align + $<$:-Wold-style-cast -Wnon-virtual-dtor -Woverloaded-virtual>) IF(ALSOFT_WERROR) SET(C_FLAGS ${C_FLAGS} -Werror) diff --git a/al/event.cpp b/al/event.cpp index 2832ace7..0da48cbf 100644 --- a/al/event.cpp +++ b/al/event.cpp @@ -44,21 +44,13 @@ static int EventThread(ALCcontext *context) std::lock_guard _{context->mEventCbLock}; do { - auto &evt = *reinterpret_cast(evt_data.buf); + auto *evt_ptr = reinterpret_cast(evt_data.buf); evt_data.buf += sizeof(AsyncEvent); evt_data.len -= 1; - /* This automatically destructs the event object and advances the - * ringbuffer's read offset at the end of scope. - */ - const struct EventAutoDestructor { - AsyncEvent &evt_; - RingBuffer *ring_; - ~EventAutoDestructor() - { - al::destroy_at(std::addressof(evt_)); - ring_->readAdvance(1); - } - } _{evt, ring}; + + AsyncEvent evt{*evt_ptr}; + al::destroy_at(evt_ptr); + ring->readAdvance(1); quitnow = evt.EnumType == EventType_KillThread; if UNLIKELY(quitnow) break; diff --git a/al/source.cpp b/al/source.cpp index 733758f7..f8d5fbcd 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -1199,7 +1199,7 @@ bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a std::unique_ptr temp{oldlist}; oldlist = temp->mNext.load(std::memory_order_relaxed); - if(ALbuffer *buffer{temp->mBuffer}) + if((buffer=temp->mBuffer) != nullptr) DecrementRef(buffer->ref); } return true; @@ -1215,7 +1215,6 @@ bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a if(IsPlayingOrPaused(Source)) { - ALCdevice *device{Context->mDevice.get()}; BackendLockGuard _{*device->Backend}; if(ALvoice *voice{GetSourceVoice(Source, Context)}) { @@ -1347,8 +1346,8 @@ bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a { /* Add refcount on the new slot, and release the previous slot */ if(slot) IncrementRef(slot->ref); - if(auto *slot = Source->Send[static_cast(values[1])].Slot) - DecrementRef(slot->ref); + if(auto *oldslot = Source->Send[static_cast(values[1])].Slot) + DecrementRef(oldslot->ref); Source->Send[static_cast(values[1])].Slot = slot; /* We must force an update if the auxiliary slot changed on an @@ -1361,8 +1360,8 @@ bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a else { if(slot) IncrementRef(slot->ref); - if(auto *slot = Source->Send[static_cast(values[1])].Slot) - DecrementRef(slot->ref); + if(auto *oldslot = Source->Send[static_cast(values[1])].Slot) + DecrementRef(oldslot->ref); Source->Send[static_cast(values[1])].Slot = slot; UpdateSourceProps(Source, Context); } @@ -1730,7 +1729,6 @@ bool GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a bool GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const al::span values) { - ALbufferlistitem *BufferList; ALdouble dvals[MaxValues]; bool err; @@ -1748,9 +1746,13 @@ bool GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a case AL_BUFFER: CHECKSIZE(values, 1); - BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : nullptr; - values[0] = (BufferList && BufferList->mBuffer) ? - static_cast(BufferList->mBuffer->id) : 0; + { + ALbufferlistitem *BufferList{nullptr}; + if(Source->SourceType == AL_STATIC) BufferList = Source->queue; + ALbuffer *buffer{nullptr}; + if(BufferList) buffer = BufferList->mBuffer; + values[0] = buffer ? static_cast(buffer->id) : 0; + } return true; case AL_SOURCE_STATE: @@ -1760,9 +1762,7 @@ bool GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a case AL_BUFFERS_QUEUED: CHECKSIZE(values, 1); - if(!(BufferList=Source->queue)) - values[0] = 0; - else + if(ALbufferlistitem *BufferList{Source->queue}) { ALsizei count{0}; do { @@ -1771,6 +1771,8 @@ bool GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a } while(BufferList != nullptr); values[0] = count; } + else + values[0] = 0; return true; case AL_BUFFERS_PROCESSED: @@ -3135,7 +3137,7 @@ START_API_FUNC { std::unique_ptr head{BufferListStart}; BufferListStart = head->mNext.load(std::memory_order_relaxed); - if(ALbuffer *buffer{head->mBuffer}) DecrementRef(buffer->ref); + if((buffer=head->mBuffer) != nullptr) DecrementRef(buffer->ref); } return; } diff --git a/alc/alc.cpp b/alc/alc.cpp index 8e9d3963..fa88cba8 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -3731,11 +3731,11 @@ START_API_FUNC al::vector orphanctxs; for(ALCcontext *ctx : *dev->mContexts.load()) { - auto iter = std::lower_bound(ContextList.begin(), ContextList.end(), ctx); - if(iter != ContextList.end() && *iter == ctx) + auto ctxiter = std::lower_bound(ContextList.begin(), ContextList.end(), ctx); + if(ctxiter != ContextList.end() && *ctxiter == ctx) { - orphanctxs.emplace_back(std::move(*iter)); - ContextList.erase(iter); + orphanctxs.emplace_back(std::move(*ctxiter)); + ContextList.erase(ctxiter); } } listlock.unlock(); diff --git a/alc/alconfig.cpp b/alc/alconfig.cpp index 8ca81bc8..666c2c2d 100644 --- a/alc/alconfig.cpp +++ b/alc/alconfig.cpp @@ -359,7 +359,7 @@ void ReadALConfig() else fname += "alsoft.conf"; TRACE("Loading config %s...\n", fname.c_str()); - al::ifstream f{fname}; + f = al::ifstream{fname}; if(f.is_open()) LoadConfigFromFile(f); } @@ -376,7 +376,7 @@ void ReadALConfig() if((configURL=CFBundleCopyResourceURL(mainBundle, CFSTR(".alsoftrc"), CFSTR(""), nullptr)) && CFURLGetFileSystemRepresentation(configURL, true, fileName, sizeof(fileName))) { - al::ifstream f{reinterpret_cast(fileName)}; + f = al::ifstream{reinterpret_cast(fileName)}; if(f.is_open()) LoadConfigFromFile(f); } @@ -390,7 +390,7 @@ void ReadALConfig() else fname += ".alsoftrc"; TRACE("Loading config %s...\n", fname.c_str()); - al::ifstream f{fname}; + f = al::ifstream{fname}; if(f.is_open()) LoadConfigFromFile(f); } @@ -414,7 +414,7 @@ void ReadALConfig() if(!fname.empty()) { TRACE("Loading config %s...\n", fname.c_str()); - al::ifstream f{fname}; + f = al::ifstream{fname}; if(f.is_open()) LoadConfigFromFile(f); } @@ -426,7 +426,7 @@ void ReadALConfig() else ppath += "alsoft.conf"; TRACE("Loading config %s...\n", ppath.c_str()); - al::ifstream f{ppath}; + f = al::ifstream{ppath}; if(f.is_open()) LoadConfigFromFile(f); } @@ -434,7 +434,7 @@ void ReadALConfig() if(auto confname = al::getenv("ALSOFT_CONF")) { TRACE("Loading config %s...\n", confname->c_str()); - al::ifstream f{*confname}; + f = al::ifstream{*confname}; if(f.is_open()) LoadConfigFromFile(f); } diff --git a/alc/backends/base.h b/alc/backends/base.h index 5e294fe8..e88734dc 100644 --- a/alc/backends/base.h +++ b/alc/backends/base.h @@ -68,6 +68,8 @@ enum class DevProbe { struct BackendFactory { + virtual ~BackendFactory() = default; + virtual bool init() = 0; virtual bool querySupport(BackendType type) = 0; diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 9c54c07b..23d4e71a 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -484,7 +484,7 @@ pa_stream *pulse_connect_stream(const char *device_name, std::unique_lock::setParams(BiquadType type, Real gain, Real f0norm, Rea break; } - a1 = a[1] / a[0]; - a2 = a[2] / a[0]; - b0 = b[0] / a[0]; - b1 = b[1] / a[0]; - b2 = b[2] / a[0]; + mA1 = a[1] / a[0]; + mA2 = a[2] / a[0]; + mB0 = b[0] / a[0]; + mB1 = b[1] / a[0]; + mB2 = b[2] / a[0]; } template @@ -93,13 +93,13 @@ void BiquadFilterR::process(Real *dst, const Real *src, const size_t numsa { ASSUME(numsamples > 0); - const Real b0{this->b0}; - const Real b1{this->b1}; - const Real b2{this->b2}; - const Real a1{this->a1}; - const Real a2{this->a2}; - Real z1{this->z1}; - Real z2{this->z2}; + const Real b0{mB0}; + const Real b1{mB1}; + const Real b2{mB2}; + const Real a1{mA1}; + const Real a2{mA2}; + Real z1{mZ1}; + Real z2{mZ2}; /* Processing loop is Transposed Direct Form II. This requires less storage * compared to Direct Form I (only two delay components, instead of a four- @@ -118,8 +118,8 @@ void BiquadFilterR::process(Real *dst, const Real *src, const size_t numsa }; std::transform(src, src+numsamples, dst, proc_sample); - this->z1 = z1; - this->z2 = z2; + mZ1 = z1; + mZ2 = z2; } template class BiquadFilterR; diff --git a/alc/filters/biquad.h b/alc/filters/biquad.h index 9de86f2f..9af954ae 100644 --- a/alc/filters/biquad.h +++ b/alc/filters/biquad.h @@ -38,14 +38,14 @@ enum class BiquadType { template class BiquadFilterR { /* Last two delayed components for direct form II. */ - Real z1{0.0f}, z2{0.0f}; + Real mZ1{0.0f}, mZ2{0.0f}; /* Transfer function coefficients "b" (numerator) */ - Real b0{1.0f}, b1{0.0f}, b2{0.0f}; + Real mB0{1.0f}, mB1{0.0f}, mB2{0.0f}; /* Transfer function coefficients "a" (denominator; a0 is pre-applied). */ - Real a1{0.0f}, a2{0.0f}; + Real mA1{0.0f}, mA2{0.0f}; public: - void clear() noexcept { z1 = z2 = 0.0f; } + void clear() noexcept { mZ1 = mZ2 = 0.0f; } /** * Sets the filter state for the specified filter type and its parameters. @@ -65,26 +65,24 @@ public: void copyParamsFrom(const BiquadFilterR &other) { - b0 = other.b0; - b1 = other.b1; - b2 = other.b2; - a1 = other.a1; - a2 = other.a2; + mB0 = other.mB0; + mB1 = other.mB1; + mB2 = other.mB2; + mA1 = other.mA1; + mA2 = other.mA2; } void process(Real *dst, const Real *src, const size_t numsamples); /* Rather hacky. It's just here to support "manual" processing. */ - std::pair getComponents() const noexcept - { return {z1, z2}; } - void setComponents(Real z1_, Real z2_) noexcept - { z1 = z1_; z2 = z2_; } - Real processOne(const Real in, Real &z1_, Real &z2_) const noexcept + std::pair getComponents() const noexcept { return {mZ1, mZ2}; } + void setComponents(Real z1, Real z2) noexcept { mZ1 = z1; mZ2 = z2; } + Real processOne(const Real in, Real &z1, Real &z2) const noexcept { - Real out{in*b0 + z1_}; - z1_ = in*b1 - out*a1 + z2_; - z2_ = in*b2 - out*a2; + Real out{in*mB0 + z1}; + z1 = in*mB1 - out*mA1 + z2; + z2 = in*mB2 - out*mA2; return out; } diff --git a/alc/filters/splitter.cpp b/alc/filters/splitter.cpp index 66806ea9..c6218e70 100644 --- a/alc/filters/splitter.cpp +++ b/alc/filters/splitter.cpp @@ -17,13 +17,13 @@ void BandSplitterR::init(Real f0norm) const Real w{f0norm * al::MathDefs::Tau()}; const Real cw{std::cos(w)}; if(cw > std::numeric_limits::epsilon()) - coeff = (std::sin(w) - 1.0f) / cw; + mCoeff = (std::sin(w) - 1.0f) / cw; else - coeff = cw * -0.5f; + mCoeff = cw * -0.5f; - lp_z1 = 0.0f; - lp_z2 = 0.0f; - ap_z1 = 0.0f; + mLpZ1 = 0.0f; + mLpZ2 = 0.0f; + mApZ1 = 0.0f; } template @@ -31,11 +31,11 @@ void BandSplitterR::process(Real *hpout, Real *lpout, const Real *input, c { ASSUME(count > 0); - const Real ap_coeff{this->coeff}; - const Real lp_coeff{this->coeff*0.5f + 0.5f}; - Real lp_z1{this->lp_z1}; - Real lp_z2{this->lp_z2}; - Real ap_z1{this->ap_z1}; + const Real ap_coeff{mCoeff}; + const Real lp_coeff{mCoeff*0.5f + 0.5f}; + Real lp_z1{mLpZ1}; + Real lp_z2{mLpZ2}; + Real ap_z1{mApZ1}; auto proc_sample = [ap_coeff,lp_coeff,&lp_z1,&lp_z2,&ap_z1,&lpout](const Real in) noexcept -> Real { /* Low-pass sample processing. */ @@ -57,9 +57,9 @@ void BandSplitterR::process(Real *hpout, Real *lpout, const Real *input, c return ap_y - lp_y; }; std::transform(input, input+count, hpout, proc_sample); - this->lp_z1 = lp_z1; - this->lp_z2 = lp_z2; - this->ap_z1 = ap_z1; + mLpZ1 = lp_z1; + mLpZ2 = lp_z2; + mApZ1 = ap_z1; } template @@ -67,11 +67,11 @@ void BandSplitterR::applyHfScale(Real *samples, const Real hfscale, const { ASSUME(count > 0); - const Real ap_coeff{this->coeff}; - const Real lp_coeff{this->coeff*0.5f + 0.5f}; - Real lp_z1{this->lp_z1}; - Real lp_z2{this->lp_z2}; - Real ap_z1{this->ap_z1}; + const Real ap_coeff{mCoeff}; + const Real lp_coeff{mCoeff*0.5f + 0.5f}; + Real lp_z1{mLpZ1}; + Real lp_z2{mLpZ2}; + Real ap_z1{mApZ1}; auto proc_sample = [hfscale,ap_coeff,lp_coeff,&lp_z1,&lp_z2,&ap_z1](const Real in) noexcept -> Real { /* Low-pass sample processing. */ @@ -91,9 +91,9 @@ void BandSplitterR::applyHfScale(Real *samples, const Real hfscale, const return (ap_y-lp_y)*hfscale + lp_y; }; std::transform(samples, samples+count, samples, proc_sample); - this->lp_z1 = lp_z1; - this->lp_z2 = lp_z2; - this->ap_z1 = ap_z1; + mLpZ1 = lp_z1; + mLpZ2 = lp_z2; + mApZ1 = ap_z1; } template @@ -101,7 +101,7 @@ void BandSplitterR::applyAllpass(Real *samples, const size_t count) const { ASSUME(count > 0); - const Real coeff{this->coeff}; + const Real coeff{mCoeff}; Real z1{0.0f}; auto proc_sample = [coeff,&z1](const Real in) noexcept -> Real { diff --git a/alc/filters/splitter.h b/alc/filters/splitter.h index b024f0c3..5117a244 100644 --- a/alc/filters/splitter.h +++ b/alc/filters/splitter.h @@ -7,10 +7,10 @@ /* Band splitter. Splits a signal into two phase-matching frequency bands. */ template class BandSplitterR { - Real coeff{0.0f}; - Real lp_z1{0.0f}; - Real lp_z2{0.0f}; - Real ap_z1{0.0f}; + Real mCoeff{0.0f}; + Real mLpZ1{0.0f}; + Real mLpZ2{0.0f}; + Real mApZ1{0.0f}; public: BandSplitterR() = default; @@ -18,7 +18,7 @@ public: BandSplitterR(Real f0norm) { init(f0norm); } void init(Real f0norm); - void clear() noexcept { lp_z1 = lp_z2 = ap_z1 = 0.0f; } + void clear() noexcept { mLpZ1 = mLpZ2 = mApZ1 = 0.0f; } void process(Real *hpout, Real *lpout, const Real *input, const size_t count); void applyHfScale(Real *samples, const Real hfscale, const size_t count); diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index e20bf0a9..3d2f36ea 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -475,7 +475,7 @@ std::unique_ptr CreateHrtfStore(ALuint rate, ALushort irSize, const A ERR("Out of memory allocating storage for %s.\n", filename); else { - InitRef(Hrtf->ref, 1u); + InitRef(Hrtf->mRef, 1u); Hrtf->sampleRate = rate; Hrtf->irSize = irSize; Hrtf->fdCount = fdCount; @@ -1362,13 +1362,13 @@ HrtfEntry *GetLoadedHrtf(HrtfHandle *handle) void HrtfEntry::IncRef() { - auto ref = IncrementRef(this->ref); + auto ref = IncrementRef(mRef); TRACE("HrtfEntry %p increasing refcount to %u\n", this, ref); } void HrtfEntry::DecRef() { - auto ref = DecrementRef(this->ref); + auto ref = DecrementRef(mRef); TRACE("HrtfEntry %p decreasing refcount to %u\n", this, ref); if(ref == 0) { @@ -1378,7 +1378,7 @@ void HrtfEntry::DecRef() auto delete_unused = [](HrtfHandlePtr &handle) -> void { HrtfEntry *entry{handle->entry.get()}; - if(entry && ReadRef(entry->ref) == 0) + if(entry && ReadRef(entry->mRef) == 0) { TRACE("Unloading unused HRTF %s\n", handle->filename.data()); handle->entry = nullptr; diff --git a/alc/hrtf.h b/alc/hrtf.h index 92b3fd96..20b3409d 100644 --- a/alc/hrtf.h +++ b/alc/hrtf.h @@ -26,7 +26,7 @@ struct HrtfHandle; struct HrtfEntry { - RefCount ref; + RefCount mRef; ALuint sampleRate; ALuint irSize; diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index d7a32f35..2b5972f3 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -405,24 +405,24 @@ ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&B BufferLoopItem = nullptr; /* Load what's left to play from the buffer */ - const size_t DataSize{minz(SrcBuffer.size(), Buffer->SampleLen-DataPosInt)}; + const size_t DataRem{minz(SrcBuffer.size(), Buffer->SampleLen-DataPosInt)}; const al::byte *Data{Buffer->mData.data()}; Data += (DataPosInt*NumChannels + chan)*SampleSize; - LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataSize); - SrcBuffer = SrcBuffer.subspan(DataSize); + LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataRem); + SrcBuffer = SrcBuffer.subspan(DataRem); } else { /* Load what's left of this loop iteration */ - const size_t DataSize{minz(SrcBuffer.size(), LoopEnd-DataPosInt)}; + const size_t DataRem{minz(SrcBuffer.size(), LoopEnd-DataPosInt)}; const al::byte *Data{Buffer->mData.data()}; Data += (DataPosInt*NumChannels + chan)*SampleSize; - LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataSize); - SrcBuffer = SrcBuffer.subspan(DataSize); + LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataRem); + SrcBuffer = SrcBuffer.subspan(DataRem); /* Load any repeats of the loop we can to fill the buffer. */ const auto LoopSize = static_cast(LoopEnd - LoopStart); @@ -430,8 +430,7 @@ ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&B { const size_t DataSize{minz(SrcBuffer.size(), LoopSize)}; - const al::byte *Data{Buffer->mData.data()}; - Data += (LoopStart*NumChannels + chan)*SampleSize; + Data = Buffer->mData.data() + (LoopStart*NumChannels + chan)*SampleSize; LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataSize); SrcBuffer = SrcBuffer.subspan(DataSize); @@ -510,12 +509,14 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) for(ALuint chan{0};chan < NumChannels;chan++) { ChannelData &chandata = mChans[chan]; - DirectParams &parms = chandata.mDryParams; - if(!(mFlags&VOICE_HAS_HRTF)) - std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target), - std::begin(parms.Gains.Current)); - else - parms.Hrtf.Old = parms.Hrtf.Target; + { + DirectParams &parms = chandata.mDryParams; + if(!(mFlags&VOICE_HAS_HRTF)) + std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target), + std::begin(parms.Gains.Current)); + else + parms.Hrtf.Old = parms.Hrtf.Target; + } for(ALuint send{0};send < NumSends;++send) { if(mSend[send].Buffer.empty()) diff --git a/utils/makemhr/loaddef.cpp b/utils/makemhr/loaddef.cpp index 5f6d76d8..aaefd62c 100644 --- a/utils/makemhr/loaddef.cpp +++ b/utils/makemhr/loaddef.cpp @@ -1737,7 +1737,7 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData) hData->mHrirsBase.resize(channels * hData->mIrCount * hData->mIrSize); double *hrirs = hData->mHrirsBase.data(); std::vector hrir(hData->mIrPoints); - uint line, col, fi, ei, ai, ti; + uint line, col, fi, ei, ai; int count; printf("Loading sources..."); @@ -1827,8 +1827,7 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData) for(fi = 0;fi < hData->mFdCount;fi++) { double delta = aer[2] - hData->mFds[fi].mDistance; - if(std::abs(delta) < 0.001) - break; + if(std::abs(delta) < 0.001) break; } if(fi >= hData->mFdCount) continue; @@ -1892,7 +1891,6 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData) for(;;) { SourceRefT src; - uint ti = 0; if(!ReadSourceRef(tr, &src)) return 0; @@ -1907,6 +1905,7 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData) if(!LoadSource(&src, hData->mIrRate, hData->mIrPoints, hrir.data())) return 0; + uint ti{0}; if(hData->mChannelType == CT_STEREO) { char ident[MAX_IDENT_LEN+1]; @@ -1976,7 +1975,7 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData) } } } - for(ti = 0;ti < channels;ti++) + for(uint ti{0};ti < channels;ti++) { for(fi = 0;fi < hData->mFdCount;fi++) { diff --git a/utils/makemhr/loadsofa.cpp b/utils/makemhr/loadsofa.cpp index 02911e12..219eb558 100644 --- a/utils/makemhr/loadsofa.cpp +++ b/utils/makemhr/loadsofa.cpp @@ -101,7 +101,6 @@ static float GetUniformStepSize(const double epsilon, const uint m, const float { auto steps = std::vector(m, 0.0f); auto counts = std::vector(m, 0u); - float step{0.0f}; uint count{0u}; for(uint stride{1u};stride < m/2;stride++) @@ -140,15 +139,12 @@ static float GetUniformStepSize(const double epsilon, const uint m, const float count = 1; if(counts[0] > m/2) - { - step = steps[0]; - return step; - } + return steps[0]; } if(counts[0] > 5) - step = steps[0]; - return step; + return steps[0]; + return 0.0f; } /* Attempts to produce a compatible layout. Most data sets tend to be diff --git a/utils/sofa-info.cpp b/utils/sofa-info.cpp index e9f2257c..87531b37 100644 --- a/utils/sofa-info.cpp +++ b/utils/sofa-info.cpp @@ -136,7 +136,6 @@ static float GetUniformStepSize(const float epsilon, const uint m, const float * { std::vector steps(m, 0.0f); std::vector counts(m, 0u); - float step{0.0f}; uint count{0u}; for(uint stride{1u};stride < m/2;stride++) @@ -175,15 +174,12 @@ static float GetUniformStepSize(const float epsilon, const uint m, const float * count = 1; if(counts[0] > m/2) - { - step = steps[0]; - return step; - } + return steps[0]; } if(counts[0] > 5) - step = steps[0]; - return step; + return steps[0]; + return 0.0f; } /* Attempts to produce a compatible layout. Most data sets tend to be -- cgit v1.2.3 From b212ab9ea21a093ba8fa9895e723bc76b84cf284 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 14 Sep 2019 18:37:00 -0700 Subject: Add a note about clearing complex_hilbert's imaginary input --- common/alcomplex.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/alcomplex.h b/common/alcomplex.h index f224cce2..12b86436 100644 --- a/common/alcomplex.h +++ b/common/alcomplex.h @@ -17,7 +17,8 @@ void complex_fft(const al::span> buffer, const double sign) * Calculate the complex helical sequence (discrete-time analytical signal) of * the given input using the discrete Hilbert transform (In-place algorithm). * Fills the buffer with the discrete-time analytical signal stored in the - * buffer. The buffer is an array of complex numbers and MUST BE power of two. + * buffer. The buffer is an array of complex numbers and MUST BE power of two, + * and the imaginary components should be cleared to 0. */ void complex_hilbert(const al::span> buffer); -- cgit v1.2.3 From b43cd047ba12f1977c0cf4692a3ea343c7a917d0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 14 Sep 2019 18:54:16 -0700 Subject: Build with -Wunused --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 44d829d6..762ce3e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -220,7 +220,7 @@ IF(MSVC) ENDFOREACH(flag_var) ENDIF() ELSE() - SET(C_FLAGS ${C_FLAGS} -Winline -Wall -Wextra -Wshadow -Wconversion -Wcast-align + SET(C_FLAGS ${C_FLAGS} -Winline -Wunused -Wall -Wextra -Wshadow -Wconversion -Wcast-align $<$:-Wold-style-cast -Wnon-virtual-dtor -Woverloaded-virtual>) IF(ALSOFT_WERROR) -- cgit v1.2.3 From e82c43fb38f13ee3efdda2b7a1395b8182fceb1c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 14 Sep 2019 19:07:30 -0700 Subject: Fix a copy-paste error --- alc/hrtf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index 3d2f36ea..7d40b16c 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -319,7 +319,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin const ALuint iroffset{Hrtf->elev[evidx].irOffset}; /* Calculate azimuth index for this elevation. */ - const float az_norm{(360.0f*pt.Azim) / 360.0f}; + const float az_norm{(360.0f+pt.Azim) / 360.0f}; const ALuint azidx{float2uint(az_norm*static_cast(azcount) + 0.5f) % azcount}; /* Calculate the index for the impulse response. */ -- cgit v1.2.3 From 4b8f78a8d633e3f39e2b708184c051465fcfef7d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 14 Sep 2019 19:42:54 -0700 Subject: Fix a few more GCC warnings --- alc/backends/coreaudio.cpp | 3 ++- alc/backends/opensl.cpp | 6 +++--- alc/backends/wasapi.cpp | 2 ++ alc/mixer/mixer_c.cpp | 2 +- common/alcomplex.cpp | 2 +- examples/almultireverb.c | 4 ++-- utils/openal-info.c | 2 +- 7 files changed, 12 insertions(+), 9 deletions(-) diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 99b06b7a..3ae9800c 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -374,7 +374,8 @@ OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags*, audiobuf.list.mNumberBuffers = 2; audiobuf.list.mBuffers[0].mNumberChannels = mFormat.mChannelsPerFrame; audiobuf.list.mBuffers[0].mData = rec_vec.first.buf; - audiobuf.list.mBuffers[0].mDataByteSize = rec_vec.first.len * mFormat.mBytesPerFrame; + audiobuf.list.mBuffers[0].mDataByteSize = static_cast(rec_vec.first.len) * + mFormat.mBytesPerFrame; audiobuf.list.mBuffers[1].mNumberChannels = mFormat.mChannelsPerFrame; audiobuf.list.mBuffers[1].mData = rec_vec.second.buf; audiobuf.list.mBuffers[1].mDataByteSize = remaining * mFormat.mBytesPerFrame; diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index 06d5cd40..3a2f455e 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -681,11 +681,11 @@ ALCenum OpenSLCapture::open(const ALCchar* name) { mFrameSize = mDevice->frameSizeFromFmt(); /* Ensure the total length is at least 100ms */ - ALsizei length{maxi(mDevice->BufferSize, mDevice->Frequency/10)}; + ALuint length{maxu(mDevice->BufferSize, mDevice->Frequency/10)}; /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */ - ALsizei update_len{clampi(mDevice->BufferSize/3, mDevice->Frequency/100, + ALuint update_len{clampu(mDevice->BufferSize/3, mDevice->Frequency/100, mDevice->Frequency/100*5)}; - ALsizei num_updates{(length+update_len-1) / update_len}; + ALuint num_updates{(length+update_len-1) / update_len}; try { mRing = CreateRingBuffer(num_updates, update_len*mFrameSize, false); diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index b762da76..0d04d5a7 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -429,6 +429,8 @@ constexpr char MessageStr[static_cast(MsgType::Count)][20]{ /* Proxy interface used by the message handler. */ struct WasapiProxy { + virtual ~WasapiProxy() = default; + virtual HRESULT openProxy() = 0; virtual void closeProxy() = 0; diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index 74315dd5..7beab1a9 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -30,7 +30,7 @@ inline ALfloat do_bsinc(const InterpState &istate, const ALfloat *RESTRICT vals, (1.0f/(1<(istate.bsinc.m)*pi*4}; + const ALfloat *fil{istate.bsinc.filter + istate.bsinc.m*static_cast(pi*4)}; const ALfloat *scd{fil + istate.bsinc.m}; const ALfloat *phd{scd + istate.bsinc.m}; const ALfloat *spd{phd + istate.bsinc.m}; diff --git a/common/alcomplex.cpp b/common/alcomplex.cpp index f77ec203..e5cbe8a0 100644 --- a/common/alcomplex.cpp +++ b/common/alcomplex.cpp @@ -35,7 +35,7 @@ void complex_fft(const al::span> buffer, const double sign) for(size_t i{1u};i < fftsize;i<<=1, step<<=1) { const size_t step2{step >> 1}; - double arg{al::MathDefs::Pi() / step2}; + double arg{al::MathDefs::Pi() / static_cast(step2)}; std::complex w{std::cos(arg), std::sin(arg)*sign}; std::complex u{1.0, 0.0}; diff --git a/examples/almultireverb.c b/examples/almultireverb.c index b967a050..4e3e188f 100644 --- a/examples/almultireverb.c +++ b/examples/almultireverb.c @@ -653,12 +653,12 @@ int main(int argc, char **argv) * Convert the difference to seconds. */ curtime = altime_get(); - timediff = (ALfloat)(curtime - basetime) / 1000.0f; + timediff = (float)(curtime - basetime) / 1000.0f; /* Avoid negative time deltas, in case of non-monotonic clocks. */ if(timediff < 0.0f) timediff = 0.0f; - else while(timediff >= 4.0f*((loops&1)+1)) + else while(timediff >= 4.0f*(float)((loops&1)+1)) { /* For this example, each transition occurs over 4 seconds, and * there's 2 transitions per cycle. diff --git a/utils/openal-info.c b/utils/openal-info.c index cc628b6e..76cdf37d 100644 --- a/utils/openal-info.c +++ b/utils/openal-info.c @@ -53,7 +53,7 @@ static WCHAR *FromUTF8(const char *str) if((len=MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)) > 0) { - out = calloc(sizeof(WCHAR), len); + out = calloc(sizeof(WCHAR), (unsigned int)(len)); MultiByteToWideChar(CP_UTF8, 0, str, -1, out, len); } return out; -- cgit v1.2.3 From e4cc77ea237c8a2ca67cb0a1cb28e6d652746590 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 14 Sep 2019 20:19:59 -0700 Subject: Fix a few warnings from MSVC --- al/source.cpp | 12 ++++++------ alc/effects/compressor.cpp | 2 +- alc/effects/reverb.cpp | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index f8d5fbcd..53d2a705 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -1126,14 +1126,14 @@ bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a CHECKSIZE(values, 1); CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); - Source->HeadRelative = static_cast(values[0]); + Source->HeadRelative = values[0] != AL_FALSE; return UpdateSourceProps(Source, Context); case AL_LOOPING: CHECKSIZE(values, 1); CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); - Source->Looping = static_cast(values[0]); + Source->Looping = values[0] != AL_FALSE; if(IsPlayingOrPaused(Source)) { if(ALvoice *voice{GetSourceVoice(Source, Context)}) @@ -1258,28 +1258,28 @@ bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a CHECKSIZE(values, 1); CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); - Source->DryGainHFAuto = values[0]; + Source->DryGainHFAuto = values[0] != AL_FALSE; return UpdateSourceProps(Source, Context); case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: CHECKSIZE(values, 1); CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); - Source->WetGainAuto = values[0]; + Source->WetGainAuto = values[0] != AL_FALSE; return UpdateSourceProps(Source, Context); case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: CHECKSIZE(values, 1); CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); - Source->WetGainHFAuto = values[0]; + Source->WetGainHFAuto = values[0] != AL_FALSE; return UpdateSourceProps(Source, Context); case AL_DIRECT_CHANNELS_SOFT: CHECKSIZE(values, 1); CHECKVAL(values[0] == AL_FALSE || values[0] == AL_TRUE); - Source->DirectChannels = values[0]; + Source->DirectChannels = values[0] != AL_FALSE; return UpdateSourceProps(Source, Context); case AL_DISTANCE_MODEL: diff --git a/alc/effects/compressor.cpp b/alc/effects/compressor.cpp index 176e5a58..44ffaaef 100644 --- a/alc/effects/compressor.cpp +++ b/alc/effects/compressor.cpp @@ -161,7 +161,7 @@ void Compressor_setParami(EffectProps *props, ALCcontext *context, ALenum param, case AL_COMPRESSOR_ONOFF: if(!(val >= AL_COMPRESSOR_MIN_ONOFF && val <= AL_COMPRESSOR_MAX_ONOFF)) SETERR_RETURN(context, AL_INVALID_VALUE,, "Compressor state out of range"); - props->Compressor.OnOff = val; + props->Compressor.OnOff = val != AL_FALSE; break; default: diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index b5100a14..82a80198 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -1526,7 +1526,7 @@ void EAXReverb_setParami(EffectProps *props, ALCcontext *context, ALenum param, case AL_EAXREVERB_DECAY_HFLIMIT: if(!(val >= AL_EAXREVERB_MIN_DECAY_HFLIMIT && val <= AL_EAXREVERB_MAX_DECAY_HFLIMIT)) SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay hflimit out of range"); - props->Reverb.DecayHFLimit = val; + props->Reverb.DecayHFLimit = val != AL_FALSE; break; default: @@ -1863,7 +1863,7 @@ void StdReverb_setParami(EffectProps *props, ALCcontext *context, ALenum param, case AL_REVERB_DECAY_HFLIMIT: if(!(val >= AL_REVERB_MIN_DECAY_HFLIMIT && val <= AL_REVERB_MAX_DECAY_HFLIMIT)) SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb decay hflimit out of range"); - props->Reverb.DecayHFLimit = val; + props->Reverb.DecayHFLimit = val != AL_FALSE; break; default: -- cgit v1.2.3 From c5a3c52822d0ab8e36c2d3d31936eae1da64049f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 Sep 2019 09:50:28 -0700 Subject: Return and pass more appropriate types for backends --- alc/alc.cpp | 9 +++++---- alc/backends/alsa.cpp | 38 +++++++++++++++++++------------------- alc/backends/base.cpp | 6 +++--- alc/backends/base.h | 7 ++++--- alc/backends/coreaudio.cpp | 38 +++++++++++++++++++------------------- alc/backends/dsound.cpp | 28 ++++++++++++++-------------- alc/backends/jack.cpp | 22 +++++++++++----------- alc/backends/loopback.cpp | 12 ++++++------ alc/backends/null.cpp | 14 +++++++------- alc/backends/opensl.cpp | 36 +++++++++++++++++------------------- alc/backends/oss.cpp | 32 ++++++++++++++++---------------- alc/backends/portaudio.cpp | 30 +++++++++++++++--------------- alc/backends/pulseaudio.cpp | 24 ++++++++++++------------ alc/backends/qsa.cpp | 18 +++++++++--------- alc/backends/sdl2.cpp | 12 ++++++------ alc/backends/sndio.cpp | 36 ++++++++++++++++++------------------ alc/backends/solaris.cpp | 20 ++++++++++---------- alc/backends/wasapi.cpp | 22 +++++++++++----------- alc/backends/wave.cpp | 16 ++++++++-------- alc/backends/winmm.cpp | 34 +++++++++++++++++----------------- 20 files changed, 227 insertions(+), 227 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index fa88cba8..4a4ed677 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -1920,7 +1920,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->UpdateSize, device->BufferSize); try { - if(device->Backend->reset() == ALC_FALSE) + if(device->Backend->reset() == false) return ALC_INVALID_DEVICE; } catch(std::exception &e) { @@ -2235,7 +2235,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(!device->Flags.get()) { - if(device->Backend->start() == ALC_FALSE) + if(device->Backend->start() == false) return ALC_INVALID_DEVICE; device->Flags.set(); } @@ -3911,7 +3911,8 @@ START_API_FUNC { std::lock_guard _{dev->StateLock}; BackendBase *backend{dev->Backend.get()}; if(samples >= 0 && backend->availableSamples() >= static_cast(samples)) - err = backend->captureSamples(buffer, static_cast(samples)); + err = backend->captureSamples(static_cast(buffer), + static_cast(samples)); } if(err != ALC_NO_ERROR) alcSetError(dev.get(), err); @@ -4085,7 +4086,7 @@ START_API_FUNC if(dev->mContexts.load()->empty()) return; - if(dev->Backend->start() == ALC_FALSE) + if(dev->Backend->start() == false) { aluHandleDisconnect(dev.get(), "Device start failure"); alcSetError(dev.get(), ALC_INVALID_DEVICE); diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index b797c768..da928171 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -395,8 +395,8 @@ struct AlsaPlayback final : public BackendBase { int mixerNoMMapProc(); ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; + bool reset() override; + bool start() override; void stop() override; ClockLatency getClockLatency() override; @@ -630,7 +630,7 @@ ALCenum AlsaPlayback::open(const ALCchar *name) return ALC_NO_ERROR; } -ALCboolean AlsaPlayback::reset() +bool AlsaPlayback::reset() { snd_pcm_format_t format{SND_PCM_FORMAT_UNKNOWN}; switch(mDevice->FmtType) @@ -770,16 +770,16 @@ ALCboolean AlsaPlayback::reset() SetDefaultChannelOrder(mDevice); - return ALC_TRUE; + return true; error: ERR("%s failed: %s\n", funcerr, snd_strerror(err)); if(hp) snd_pcm_hw_params_free(hp); if(sp) snd_pcm_sw_params_free(sp); - return ALC_FALSE; + return false; } -ALCboolean AlsaPlayback::start() +bool AlsaPlayback::start() { snd_pcm_hw_params_t *hp{}; snd_pcm_access_t access; @@ -797,7 +797,7 @@ ALCboolean AlsaPlayback::start() error: ERR("%s failed: %s\n", funcerr, snd_strerror(err)); if(hp) snd_pcm_hw_params_free(hp); - return ALC_FALSE; + return false; } snd_pcm_hw_params_free(hp); hp = nullptr; @@ -815,7 +815,7 @@ ALCboolean AlsaPlayback::start() if(err < 0) { ERR("snd_pcm_prepare(data->mPcmHandle) failed: %s\n", snd_strerror(err)); - return ALC_FALSE; + return false; } thread_func = &AlsaPlayback::mixerProc; } @@ -823,7 +823,7 @@ ALCboolean AlsaPlayback::start() try { mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(thread_func), this}; - return ALC_TRUE; + return true; } catch(std::exception& e) { ERR("Could not create playback thread: %s\n", e.what()); @@ -831,7 +831,7 @@ ALCboolean AlsaPlayback::start() catch(...) { } mBuffer.clear(); - return ALC_FALSE; + return false; } void AlsaPlayback::stop() @@ -869,9 +869,9 @@ struct AlsaCapture final : public BackendBase { ~AlsaCapture() override; ALCenum open(const ALCchar *name) override; - ALCboolean start() override; + bool start() override; void stop() override; - ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override; + ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; ALCuint availableSamples() override; ClockLatency getClockLatency() override; @@ -1015,7 +1015,7 @@ error2: } -ALCboolean AlsaCapture::start() +bool AlsaCapture::start() { int err{snd_pcm_prepare(mPcmHandle)}; if(err < 0) @@ -1029,11 +1029,11 @@ ALCboolean AlsaCapture::start() if(err < 0) { aluHandleDisconnect(mDevice, "Capture state failure: %s", snd_strerror(err)); - return ALC_FALSE; + return false; } mDoCapture = true; - return ALC_TRUE; + return true; } void AlsaCapture::stop() @@ -1058,7 +1058,7 @@ void AlsaCapture::stop() mDoCapture = false; } -ALCenum AlsaCapture::captureSamples(ALCvoid *buffer, ALCuint samples) +ALCenum AlsaCapture::captureSamples(al::byte *buffer, ALCuint samples) { if(mRing) { @@ -1078,7 +1078,7 @@ ALCenum AlsaCapture::captureSamples(ALCvoid *buffer, ALCuint samples) if(static_cast(amt) > samples) amt = samples; amt = snd_pcm_frames_to_bytes(mPcmHandle, amt); - std::copy_n(mBuffer.begin(), amt, static_cast(buffer)); + std::copy_n(mBuffer.begin(), amt, buffer); mBuffer.erase(mBuffer.begin(), mBuffer.begin()+amt); amt = snd_pcm_bytes_to_frames(mPcmHandle, amt); @@ -1111,11 +1111,11 @@ ALCenum AlsaCapture::captureSamples(ALCvoid *buffer, ALCuint samples) continue; } - buffer = static_cast(buffer) + amt; + buffer = buffer + amt; samples -= static_cast(amt); } if(samples > 0) - std::fill_n(static_cast(buffer), snd_pcm_frames_to_bytes(mPcmHandle, samples), + std::fill_n(buffer, snd_pcm_frames_to_bytes(mPcmHandle, samples), al::byte((mDevice->FmtType == DevFmtUByte) ? 0x80 : 0)); return ALC_NO_ERROR; diff --git a/alc/backends/base.cpp b/alc/backends/base.cpp index c4c6052b..a5f66606 100644 --- a/alc/backends/base.cpp +++ b/alc/backends/base.cpp @@ -28,10 +28,10 @@ BackendBase::BackendBase(ALCdevice *device) noexcept : mDevice{device} BackendBase::~BackendBase() = default; -ALCboolean BackendBase::reset() -{ return ALC_FALSE; } +bool BackendBase::reset() +{ return false; } -ALCenum BackendBase::captureSamples(void*, ALCuint) +ALCenum BackendBase::captureSamples(al::byte*, ALCuint) { return ALC_INVALID_DEVICE; } ALCuint BackendBase::availableSamples() diff --git a/alc/backends/base.h b/alc/backends/base.h index e88734dc..cc33ba50 100644 --- a/alc/backends/base.h +++ b/alc/backends/base.h @@ -9,6 +9,7 @@ #include "AL/alc.h" #include "alcmain.h" +#include "albyte.h" struct ClockLatency { @@ -33,11 +34,11 @@ ClockLatency GetClockLatency(ALCdevice *device); struct BackendBase { virtual ALCenum open(const ALCchar *name) = 0; - virtual ALCboolean reset(); - virtual ALCboolean start() = 0; + virtual bool reset(); + virtual bool start() = 0; virtual void stop() = 0; - virtual ALCenum captureSamples(void *buffer, ALCuint samples); + virtual ALCenum captureSamples(al::byte *buffer, ALCuint samples); virtual ALCuint availableSamples(); virtual ClockLatency getClockLatency(); diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 3ae9800c..72754718 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -54,8 +54,8 @@ struct CoreAudioPlayback final : public BackendBase { AudioBufferList *ioData); ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; + bool reset() override; + bool start() override; void stop() override; AudioUnit mAudioUnit; @@ -137,7 +137,7 @@ ALCenum CoreAudioPlayback::open(const ALCchar *name) return ALC_NO_ERROR; } -ALCboolean CoreAudioPlayback::reset() +bool CoreAudioPlayback::reset() { OSStatus err{AudioUnitUninitialize(mAudioUnit)}; if(err != noErr) @@ -151,7 +151,7 @@ ALCboolean CoreAudioPlayback::reset() if(err != noErr || size != sizeof(AudioStreamBasicDescription)) { ERR("AudioUnitGetProperty failed\n"); - return ALC_FALSE; + return false; } #if 0 @@ -170,7 +170,7 @@ ALCboolean CoreAudioPlayback::reset() if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); - return ALC_FALSE; + return false; } if(mDevice->Frequency != streamFormat.mSampleRate) @@ -254,7 +254,7 @@ ALCboolean CoreAudioPlayback::reset() if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); - return ALC_FALSE; + return false; } /* setup callback */ @@ -268,7 +268,7 @@ ALCboolean CoreAudioPlayback::reset() if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); - return ALC_FALSE; + return false; } /* init the default audio unit... */ @@ -276,21 +276,21 @@ ALCboolean CoreAudioPlayback::reset() if(err != noErr) { ERR("AudioUnitInitialize failed\n"); - return ALC_FALSE; + return false; } - return ALC_TRUE; + return true; } -ALCboolean CoreAudioPlayback::start() +bool CoreAudioPlayback::start() { OSStatus err{AudioOutputUnitStart(mAudioUnit)}; if(err != noErr) { ERR("AudioOutputUnitStart failed\n"); - return ALC_FALSE; + return false; } - return ALC_TRUE; + return true; } void CoreAudioPlayback::stop() @@ -313,9 +313,9 @@ struct CoreAudioCapture final : public BackendBase { UInt32 inNumberFrames, AudioBufferList *ioData); ALCenum open(const ALCchar *name) override; - ALCboolean start() override; + bool start() override; void stop() override; - ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; ALCuint availableSamples() override; AudioUnit mAudioUnit{0}; @@ -628,15 +628,15 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) } -ALCboolean CoreAudioCapture::start() +bool CoreAudioCapture::start() { OSStatus err{AudioOutputUnitStart(mAudioUnit)}; if(err != noErr) { ERR("AudioOutputUnitStart failed\n"); - return ALC_FALSE; + return false; } - return ALC_TRUE; + return true; } void CoreAudioCapture::stop() @@ -646,7 +646,7 @@ void CoreAudioCapture::stop() ERR("AudioOutputUnitStop failed\n"); } -ALCenum CoreAudioCapture::captureSamples(void *buffer, ALCuint samples) +ALCenum CoreAudioCapture::captureSamples(al::byte *buffer, ALCuint samples) { if(!mConverter) { @@ -663,7 +663,7 @@ ALCenum CoreAudioCapture::captureSamples(void *buffer, ALCuint samples) { const void *src1{rec_vec.second.buf}; auto src1len = static_cast(rec_vec.second.len); - got += mConverter->convert(&src1, &src1len, static_cast(buffer)+got, samples-got); + got += mConverter->convert(&src1, &src1len, buffer+got, samples-got); total_read += rec_vec.second.len - src1len; } diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index f9184968..c581fe8f 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -167,8 +167,8 @@ struct DSoundPlayback final : public BackendBase { int mixerProc(); ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; + bool reset() override; + bool start() override; void stop() override; IDirectSound *mDS{nullptr}; @@ -348,7 +348,7 @@ ALCenum DSoundPlayback::open(const ALCchar *name) return ALC_NO_ERROR; } -ALCboolean DSoundPlayback::reset() +bool DSoundPlayback::reset() { if(mNotifies) mNotifies->Release(); @@ -558,28 +558,28 @@ retry_open: if(mPrimaryBuffer) mPrimaryBuffer->Release(); mPrimaryBuffer = nullptr; - return ALC_FALSE; + return false; } ResetEvent(mNotifyEvent); SetDefaultWFXChannelOrder(mDevice); - return ALC_TRUE; + return true; } -ALCboolean DSoundPlayback::start() +bool DSoundPlayback::start() { try { mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&DSoundPlayback::mixerProc), this}; - return ALC_TRUE; + return true; } catch(std::exception& e) { ERR("Failed to start mixing thread: %s\n", e.what()); } catch(...) { } - return ALC_FALSE; + return false; } void DSoundPlayback::stop() @@ -597,9 +597,9 @@ struct DSoundCapture final : public BackendBase { ~DSoundCapture() override; ALCenum open(const ALCchar *name) override; - ALCboolean start() override; + bool start() override; void stop() override; - ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; ALCuint availableSamples() override; IDirectSoundCapture *mDSC{nullptr}; @@ -791,16 +791,16 @@ ALCenum DSoundCapture::open(const ALCchar *name) return ALC_NO_ERROR; } -ALCboolean DSoundCapture::start() +bool DSoundCapture::start() { HRESULT hr{mDSCbuffer->Start(DSCBSTART_LOOPING)}; if(FAILED(hr)) { ERR("start failed: 0x%08lx\n", hr); aluHandleDisconnect(mDevice, "Failure starting capture: 0x%lx", hr); - return ALC_FALSE; + return false; } - return ALC_TRUE; + return true; } void DSoundCapture::stop() @@ -813,7 +813,7 @@ void DSoundCapture::stop() } } -ALCenum DSoundCapture::captureSamples(void *buffer, ALCuint samples) +ALCenum DSoundCapture::captureSamples(al::byte *buffer, ALCuint samples) { mRing->read(buffer, samples); return ALC_NO_ERROR; diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp index e1ae91f0..660ea933 100644 --- a/alc/backends/jack.cpp +++ b/alc/backends/jack.cpp @@ -162,8 +162,8 @@ struct JackPlayback final : public BackendBase { int mixerProc(); ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; + bool reset() override; + bool start() override; void stop() override; ClockLatency getClockLatency() override; @@ -359,7 +359,7 @@ ALCenum JackPlayback::open(const ALCchar *name) return ALC_NO_ERROR; } -ALCboolean JackPlayback::reset() +bool JackPlayback::reset() { std::for_each(std::begin(mPort), std::end(mPort), [this](jack_port_t *port) -> void @@ -395,7 +395,7 @@ ALCboolean JackPlayback::reset() if(bad_port != ports_end) { ERR("Not enough JACK ports available for %s output\n", DevFmtChannelsString(mDevice->FmtChans)); - if(bad_port == std::begin(mPort)) return ALC_FALSE; + if(bad_port == std::begin(mPort)) return false; if(bad_port == std::begin(mPort)+1) mDevice->FmtChans = DevFmtMono; @@ -416,20 +416,20 @@ ALCboolean JackPlayback::reset() if(!mRing) { ERR("Failed to allocate ringbuffer\n"); - return ALC_FALSE; + return false; } SetDefaultChannelOrder(mDevice); - return ALC_TRUE; + return true; } -ALCboolean JackPlayback::start() +bool JackPlayback::start() { if(jack_activate(mClient)) { ERR("Failed to activate client\n"); - return ALC_FALSE; + return false; } const char **ports{jack_get_ports(mClient, nullptr, nullptr, @@ -438,7 +438,7 @@ ALCboolean JackPlayback::start() { ERR("No physical playback ports found\n"); jack_deactivate(mClient); - return ALC_FALSE; + return false; } std::mismatch(std::begin(mPort), std::end(mPort), ports, [this](const jack_port_t *port, const char *pname) -> bool @@ -460,7 +460,7 @@ ALCboolean JackPlayback::start() try { mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&JackPlayback::mixerProc), this}; - return ALC_TRUE; + return true; } catch(std::exception& e) { ERR("Could not create playback thread: %s\n", e.what()); @@ -468,7 +468,7 @@ ALCboolean JackPlayback::start() catch(...) { } jack_deactivate(mClient); - return ALC_FALSE; + return false; } void JackPlayback::stop() diff --git a/alc/backends/loopback.cpp b/alc/backends/loopback.cpp index 4a1c641a..7edc2d40 100644 --- a/alc/backends/loopback.cpp +++ b/alc/backends/loopback.cpp @@ -32,8 +32,8 @@ struct LoopbackBackend final : public BackendBase { LoopbackBackend(ALCdevice *device) noexcept : BackendBase{device} { } ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; + bool reset() override; + bool start() override; void stop() override; DEF_NEWDEL(LoopbackBackend) @@ -46,14 +46,14 @@ ALCenum LoopbackBackend::open(const ALCchar *name) return ALC_NO_ERROR; } -ALCboolean LoopbackBackend::reset() +bool LoopbackBackend::reset() { SetDefaultWFXChannelOrder(mDevice); - return ALC_TRUE; + return true; } -ALCboolean LoopbackBackend::start() -{ return ALC_TRUE; } +bool LoopbackBackend::start() +{ return true; } void LoopbackBackend::stop() { } diff --git a/alc/backends/null.cpp b/alc/backends/null.cpp index ae58cb8b..b6b115f1 100644 --- a/alc/backends/null.cpp +++ b/alc/backends/null.cpp @@ -52,8 +52,8 @@ struct NullBackend final : public BackendBase { int mixerProc(); ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; + bool reset() override; + bool start() override; void stop() override; std::atomic mKillNow{true}; @@ -120,25 +120,25 @@ ALCenum NullBackend::open(const ALCchar *name) return ALC_NO_ERROR; } -ALCboolean NullBackend::reset() +bool NullBackend::reset() { SetDefaultWFXChannelOrder(mDevice); - return ALC_TRUE; + return true; } -ALCboolean NullBackend::start() +bool NullBackend::start() { try { mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&NullBackend::mixerProc), this}; - return ALC_TRUE; + return true; } catch(std::exception& e) { ERR("Failed to start mixing thread: %s\n", e.what()); } catch(...) { } - return ALC_FALSE; + return false; } void NullBackend::stop() diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index 3a2f455e..0f1d8a21 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -152,8 +152,8 @@ struct OpenSLPlayback final : public BackendBase { int mixerProc(); ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; + bool reset() override; + bool start() override; void stop() override; ClockLatency getClockLatency() override; @@ -347,7 +347,7 @@ ALCenum OpenSLPlayback::open(const ALCchar *name) return ALC_NO_ERROR; } -ALCboolean OpenSLPlayback::reset() +bool OpenSLPlayback::reset() { SLDataLocator_AndroidSimpleBufferQueue loc_bufq; SLDataLocator_OutputMix loc_outmix; @@ -518,13 +518,13 @@ ALCboolean OpenSLPlayback::reset() VCALL0(mBufferQueueObj,Destroy)(); mBufferQueueObj = nullptr; - return ALC_FALSE; + return false; } - return ALC_TRUE; + return true; } -ALCboolean OpenSLPlayback::start() +bool OpenSLPlayback::start() { mRing->reset(); @@ -533,23 +533,23 @@ ALCboolean OpenSLPlayback::start() &bufferQueue)}; PRINTERR(result, "bufferQueue->GetInterface"); if(SL_RESULT_SUCCESS != result) - return ALC_FALSE; + return false; result = VCALL(bufferQueue,RegisterCallback)(&OpenSLPlayback::processC, this); PRINTERR(result, "bufferQueue->RegisterCallback"); - if(SL_RESULT_SUCCESS != result) return ALC_FALSE; + if(SL_RESULT_SUCCESS != result) return false; try { mKillNow.store(false, std::memory_order_release); mThread = std::thread(std::mem_fn(&OpenSLPlayback::mixerProc), this); - return ALC_TRUE; + return true; } catch(std::exception& e) { ERR("Could not create playback thread: %s\n", e.what()); } catch(...) { } - return ALC_FALSE; + return false; } void OpenSLPlayback::stop() @@ -615,9 +615,9 @@ struct OpenSLCapture final : public BackendBase { void process(SLAndroidSimpleBufferQueueItf bq); ALCenum open(const ALCchar *name) override; - ALCboolean start() override; + bool start() override; void stop() override; - ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; ALCuint availableSamples() override; /* engine interfaces */ @@ -815,7 +815,7 @@ ALCenum OpenSLCapture::open(const ALCchar* name) return ALC_NO_ERROR; } -ALCboolean OpenSLCapture::start() +bool OpenSLCapture::start() { SLRecordItf record; SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_RECORD, &record)}; @@ -830,10 +830,10 @@ ALCboolean OpenSLCapture::start() if(SL_RESULT_SUCCESS != result) { aluHandleDisconnect(mDevice, "Failed to start capture: 0x%08x", result); - return ALC_FALSE; + return false; } - return ALC_TRUE; + return true; } void OpenSLCapture::stop() @@ -849,7 +849,7 @@ void OpenSLCapture::stop() } } -ALCenum OpenSLCapture::captureSamples(void *buffer, ALCuint samples) +ALCenum OpenSLCapture::captureSamples(al::byte *buffer, ALCuint samples) { ALuint chunk_size{mDevice->UpdateSize * mFrameSize}; SLAndroidSimpleBufferQueueItf bufferQueue; @@ -866,9 +866,7 @@ ALCenum OpenSLCapture::captureSamples(void *buffer, ALCuint samples) for(i = 0;i < samples;) { ALCuint rem{minu(samples - i, mDevice->UpdateSize - mSplOffset)}; - memcpy(static_cast(buffer) + i*mFrameSize, - data.first.buf + mSplOffset*mFrameSize, - rem * mFrameSize); + memcpy(buffer + i*mFrameSize, data.first.buf + mSplOffset*mFrameSize, rem*mFrameSize); mSplOffset += rem; if(mSplOffset == mDevice->UpdateSize) diff --git a/alc/backends/oss.cpp b/alc/backends/oss.cpp index ffdf3c23..c825ce3e 100644 --- a/alc/backends/oss.cpp +++ b/alc/backends/oss.cpp @@ -249,8 +249,8 @@ struct OSSPlayback final : public BackendBase { int mixerProc(); ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; + bool reset() override; + bool start() override; void stop() override; int mFd{-1}; @@ -359,7 +359,7 @@ ALCenum OSSPlayback::open(const ALCchar *name) return ALC_NO_ERROR; } -ALCboolean OSSPlayback::reset() +bool OSSPlayback::reset() { int ossFormat{}; switch(mDevice->FmtType) @@ -406,7 +406,7 @@ ALCboolean OSSPlayback::reset() { err: ERR("%s failed: %s\n", err, strerror(errno)); - return ALC_FALSE; + return false; } #undef CHECKERR @@ -414,7 +414,7 @@ ALCboolean OSSPlayback::reset() { ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(mDevice->FmtChans), numChannels); - return ALC_FALSE; + return false; } if(!((ossFormat == AFMT_S8 && mDevice->FmtType == DevFmtByte) || @@ -423,7 +423,7 @@ ALCboolean OSSPlayback::reset() { ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(mDevice->FmtType), ossFormat); - return ALC_FALSE; + return false; } mDevice->Frequency = ossSpeed; @@ -434,22 +434,22 @@ ALCboolean OSSPlayback::reset() mMixData.resize(mDevice->UpdateSize * mDevice->frameSizeFromFmt()); - return ALC_TRUE; + return true; } -ALCboolean OSSPlayback::start() +bool OSSPlayback::start() { try { mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&OSSPlayback::mixerProc), this}; - return ALC_TRUE; + return true; } catch(std::exception& e) { ERR("Could not create playback thread: %s\n", e.what()); } catch(...) { } - return ALC_FALSE; + return false; } void OSSPlayback::stop() @@ -470,9 +470,9 @@ struct OSScapture final : public BackendBase { int recordProc(); ALCenum open(const ALCchar *name) override; - ALCboolean start() override; + bool start() override; void stop() override; - ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override; + ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; ALCuint availableSamples() override; int mFd{-1}; @@ -646,19 +646,19 @@ ALCenum OSScapture::open(const ALCchar *name) return ALC_NO_ERROR; } -ALCboolean OSScapture::start() +bool OSScapture::start() { try { mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&OSScapture::recordProc), this}; - return ALC_TRUE; + return true; } catch(std::exception& e) { ERR("Could not create record thread: %s\n", e.what()); } catch(...) { } - return ALC_FALSE; + return false; } void OSScapture::stop() @@ -671,7 +671,7 @@ void OSScapture::stop() ERR("Error resetting device: %s\n", strerror(errno)); } -ALCenum OSScapture::captureSamples(ALCvoid *buffer, ALCuint samples) +ALCenum OSScapture::captureSamples(al::byte *buffer, ALCuint samples) { mRing->read(buffer, samples); return ALC_NO_ERROR; diff --git a/alc/backends/portaudio.cpp b/alc/backends/portaudio.cpp index 4704a806..0b77f622 100644 --- a/alc/backends/portaudio.cpp +++ b/alc/backends/portaudio.cpp @@ -81,8 +81,8 @@ struct PortPlayback final : public BackendBase { const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags); ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; + bool reset() override; + bool start() override; void stop() override; PaStream *mStream{nullptr}; @@ -179,7 +179,7 @@ retry_open: } -ALCboolean PortPlayback::reset() +bool PortPlayback::reset() { const PaStreamInfo *streamInfo{Pa_GetStreamInfo(mStream)}; mDevice->Frequency = static_cast(streamInfo->sampleRate); @@ -198,7 +198,7 @@ ALCboolean PortPlayback::reset() else { ERR("Unexpected sample format: 0x%lx\n", mParams.sampleFormat); - return ALC_FALSE; + return false; } if(mParams.channelCount == 2) @@ -208,22 +208,22 @@ ALCboolean PortPlayback::reset() else { ERR("Unexpected channel count: %u\n", mParams.channelCount); - return ALC_FALSE; + return false; } SetDefaultChannelOrder(mDevice); - return ALC_TRUE; + return true; } -ALCboolean PortPlayback::start() +bool PortPlayback::start() { PaError err{Pa_StartStream(mStream)}; if(err != paNoError) { ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err)); - return ALC_FALSE; + return false; } - return ALC_TRUE; + return true; } void PortPlayback::stop() @@ -245,9 +245,9 @@ struct PortCapture final : public BackendBase { const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags); ALCenum open(const ALCchar *name) override; - ALCboolean start() override; + bool start() override; void stop() override; - ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override; + ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; ALCuint availableSamples() override; PaStream *mStream{nullptr}; @@ -341,15 +341,15 @@ ALCenum PortCapture::open(const ALCchar *name) } -ALCboolean PortCapture::start() +bool PortCapture::start() { PaError err{Pa_StartStream(mStream)}; if(err != paNoError) { ERR("Error starting stream: %s\n", Pa_GetErrorText(err)); - return ALC_FALSE; + return false; } - return ALC_TRUE; + return true; } void PortCapture::stop() @@ -363,7 +363,7 @@ void PortCapture::stop() ALCuint PortCapture::availableSamples() { return static_cast(mRing->readSpace()); } -ALCenum PortCapture::captureSamples(ALCvoid *buffer, ALCuint samples) +ALCenum PortCapture::captureSamples(al::byte *buffer, ALCuint samples) { mRing->read(buffer, samples); return ALC_NO_ERROR; diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 23d4e71a..e9997013 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -666,8 +666,8 @@ struct PulsePlayback final : public BackendBase { void streamMovedCallback(pa_stream *stream); ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; + bool reset() override; + bool start() override; void stop() override; ClockLatency getClockLatency() override; void lock() override; @@ -879,7 +879,7 @@ ALCenum PulsePlayback::open(const ALCchar *name) return ALC_NO_ERROR; } -ALCboolean PulsePlayback::reset() +bool PulsePlayback::reset() { std::unique_lock plock{pulse_lock}; @@ -1032,10 +1032,10 @@ ALCboolean PulsePlayback::reset() len, mAttr.prebuf, mDevice->BufferSize); } - return ALC_TRUE; + return true; } -ALCboolean PulsePlayback::start() +bool PulsePlayback::start() { std::unique_lock plock{pulse_lock}; @@ -1043,7 +1043,7 @@ ALCboolean PulsePlayback::start() pa_operation *op{pa_stream_cork(mStream, 0, stream_success_callback, nullptr)}; wait_for_operation(op, plock); - return ALC_TRUE; + return true; } void PulsePlayback::stop() @@ -1110,9 +1110,9 @@ struct PulseCapture final : public BackendBase { void streamMovedCallback(pa_stream *stream); ALCenum open(const ALCchar *name) override; - ALCboolean start() override; + bool start() override; void stop() override; - ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override; + ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; ALCuint availableSamples() override; ClockLatency getClockLatency() override; void lock() override; @@ -1303,12 +1303,12 @@ ALCenum PulseCapture::open(const ALCchar *name) return ALC_NO_ERROR; } -ALCboolean PulseCapture::start() +bool PulseCapture::start() { std::unique_lock plock{pulse_lock}; pa_operation *op{pa_stream_cork(mStream, 0, stream_success_callback, nullptr)}; wait_for_operation(op, plock); - return ALC_TRUE; + return true; } void PulseCapture::stop() @@ -1318,9 +1318,9 @@ void PulseCapture::stop() wait_for_operation(op, plock); } -ALCenum PulseCapture::captureSamples(ALCvoid *buffer, ALCuint samples) +ALCenum PulseCapture::captureSamples(al::byte *buffer, ALCuint samples) { - al::span dstbuf{static_cast(buffer), samples * pa_frame_size(&mSpec)}; + al::span dstbuf{buffer, samples * pa_frame_size(&mSpec)}; /* Capture is done in fragment-sized chunks, so we loop until we get all * that's available */ diff --git a/alc/backends/qsa.cpp b/alc/backends/qsa.cpp index 64ed53aa..5fee2989 100644 --- a/alc/backends/qsa.cpp +++ b/alc/backends/qsa.cpp @@ -175,8 +175,8 @@ struct PlaybackWrapper final : public BackendBase { ~PlaybackWrapper() override; ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; + bool reset() override; + bool start() override; void stop() override; std::unique_ptr mExtraData; @@ -616,10 +616,10 @@ PlaybackWrapper::~PlaybackWrapper() ALCenum PlaybackWrapper::open(const ALCchar *name) { return qsa_open_playback(this, name); } -ALCboolean PlaybackWrapper::reset() +bool PlaybackWrapper::reset() { return qsa_reset_playback(this); } -ALCboolean PlaybackWrapper::start() +bool PlaybackWrapper::start() { return qsa_start_playback(this); } void PlaybackWrapper::stop() @@ -635,9 +635,9 @@ struct CaptureWrapper final : public BackendBase { ~CaptureWrapper() override; ALCenum open(const ALCchar *name) override; - ALCboolean start() override; + bool start() override; void stop() override; - ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; ALCuint availableSamples() override; std::unique_ptr mExtraData; @@ -894,13 +894,13 @@ CaptureWrapper::~CaptureWrapper() ALCenum CaptureWrapper::open(const ALCchar *name) { return qsa_open_capture(this, name); } -ALCboolean CaptureWrapper::start() -{ qsa_start_capture(this); return ALC_TRUE; } +bool CaptureWrapper::start() +{ qsa_start_capture(this); return true; } void CaptureWrapper::stop() { qsa_stop_capture(this); } -ALCenum CaptureWrapper::captureSamples(void *buffer, ALCuint samples) +ALCenum CaptureWrapper::captureSamples(al::byte *buffer, ALCuint samples) { return qsa_capture_samples(this, buffer, samples); } ALCuint CaptureWrapper::availableSamples() diff --git a/alc/backends/sdl2.cpp b/alc/backends/sdl2.cpp index 6af0ac9d..71616906 100644 --- a/alc/backends/sdl2.cpp +++ b/alc/backends/sdl2.cpp @@ -55,8 +55,8 @@ struct Sdl2Backend final : public BackendBase { void audioCallback(Uint8 *stream, int len); ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; + bool reset() override; + bool start() override; void stop() override; void lock() override; void unlock() override; @@ -163,7 +163,7 @@ ALCenum Sdl2Backend::open(const ALCchar *name) return ALC_NO_ERROR; } -ALCboolean Sdl2Backend::reset() +bool Sdl2Backend::reset() { mDevice->Frequency = mFrequency; mDevice->FmtChans = mFmtChans; @@ -171,13 +171,13 @@ ALCboolean Sdl2Backend::reset() mDevice->UpdateSize = mUpdateSize; mDevice->BufferSize = mUpdateSize * 2; SetDefaultWFXChannelOrder(mDevice); - return ALC_TRUE; + return true; } -ALCboolean Sdl2Backend::start() +bool Sdl2Backend::start() { SDL_PauseAudioDevice(mDeviceID, 0); - return ALC_TRUE; + return true; } void Sdl2Backend::stop() diff --git a/alc/backends/sndio.cpp b/alc/backends/sndio.cpp index 4a470e82..d2654853 100644 --- a/alc/backends/sndio.cpp +++ b/alc/backends/sndio.cpp @@ -50,8 +50,8 @@ struct SndioPlayback final : public BackendBase { int mixerProc(); ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; + bool reset() override; + bool start() override; void stop() override; sio_hdl *mSndHandle{nullptr}; @@ -124,7 +124,7 @@ ALCenum SndioPlayback::open(const ALCchar *name) return ALC_NO_ERROR; } -ALCboolean SndioPlayback::reset() +bool SndioPlayback::reset() { sio_par par; sio_initpar(&par); @@ -169,13 +169,13 @@ ALCboolean SndioPlayback::reset() if(!sio_setpar(mSndHandle, &par) || !sio_getpar(mSndHandle, &par)) { ERR("Failed to set device parameters\n"); - return ALC_FALSE; + return false; } if(par.bits != par.bps*8) { ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8); - return ALC_FALSE; + return true; } mDevice->Frequency = par.rate; @@ -196,7 +196,7 @@ ALCboolean SndioPlayback::reset() else { ERR("Unhandled sample format: %s %u-bit\n", (par.sig?"signed":"unsigned"), par.bits); - return ALC_FALSE; + return false; } SetDefaultChannelOrder(mDevice); @@ -207,21 +207,21 @@ ALCboolean SndioPlayback::reset() mBuffer.resize(mDevice->UpdateSize * mDevice->frameSizeFromFmt()); std::fill(mBuffer.begin(), mBuffer.end(), 0); - return ALC_TRUE; + return true; } -ALCboolean SndioPlayback::start() +bool SndioPlayback::start() { if(!sio_start(mSndHandle)) { ERR("Error starting playback\n"); - return ALC_FALSE; + return false; } try { mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&SndioPlayback::mixerProc), this}; - return ALC_TRUE; + return true; } catch(std::exception& e) { ERR("Could not create playback thread: %s\n", e.what()); @@ -229,7 +229,7 @@ ALCboolean SndioPlayback::start() catch(...) { } sio_stop(mSndHandle); - return ALC_FALSE; + return false; } void SndioPlayback::stop() @@ -250,9 +250,9 @@ struct SndioCapture final : public BackendBase { int recordProc(); ALCenum open(const ALCchar *name) override; - ALCboolean start() override; + bool start() override; void stop() override; - ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; ALCuint availableSamples() override; sio_hdl *mSndHandle{nullptr}; @@ -417,18 +417,18 @@ ALCenum SndioCapture::open(const ALCchar *name) return ALC_NO_ERROR; } -ALCboolean SndioCapture::start() +bool SndioCapture::start() { if(!sio_start(mSndHandle)) { ERR("Error starting playback\n"); - return ALC_FALSE; + return false; } try { mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&SndioCapture::recordProc), this}; - return ALC_TRUE; + return true; } catch(std::exception& e) { ERR("Could not create record thread: %s\n", e.what()); @@ -436,7 +436,7 @@ ALCboolean SndioCapture::start() catch(...) { } sio_stop(mSndHandle); - return ALC_FALSE; + return false; } void SndioCapture::stop() @@ -449,7 +449,7 @@ void SndioCapture::stop() ERR("Error stopping device\n"); } -ALCenum SndioCapture::captureSamples(void *buffer, ALCuint samples) +ALCenum SndioCapture::captureSamples(al::byte *buffer, ALCuint samples) { mRing->read(buffer, samples); return ALC_NO_ERROR; diff --git a/alc/backends/solaris.cpp b/alc/backends/solaris.cpp index 2e8fe458..128924bb 100644 --- a/alc/backends/solaris.cpp +++ b/alc/backends/solaris.cpp @@ -62,8 +62,8 @@ struct SolarisBackend final : public BackendBase { int mixerProc(); ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; + bool reset() override; + bool start() override; void stop() override; int mFd{-1}; @@ -160,7 +160,7 @@ ALCenum SolarisBackend::open(const ALCchar *name) return ALC_NO_ERROR; } -ALCboolean SolarisBackend::reset() +bool SolarisBackend::reset() { audio_info_t info; AUDIO_INITINFO(&info); @@ -200,14 +200,14 @@ ALCboolean SolarisBackend::reset() if(ioctl(mFd, AUDIO_SETINFO, &info) < 0) { ERR("ioctl failed: %s\n", strerror(errno)); - return ALC_FALSE; + return false; } if(mDevice->channelsFromFmt() != info.play.channels) { ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(mDevice->FmtChans), info.play.channels); - return ALC_FALSE; + return false; } if(!((info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR8 && mDevice->FmtType == DevFmtUByte) || @@ -217,7 +217,7 @@ ALCboolean SolarisBackend::reset() { ERR("Could not set %s samples, got %d (0x%x)\n", DevFmtTypeString(mDevice->FmtType), info.play.precision, info.play.encoding); - return ALC_FALSE; + return false; } mDevice->Frequency = info.play.sample_rate; @@ -229,22 +229,22 @@ ALCboolean SolarisBackend::reset() mBuffer.resize(mDevice->UpdateSize * mDevice->frameSizeFromFmt()); std::fill(mBuffer.begin(), mBuffer.end(), 0); - return ALC_TRUE; + return true; } -ALCboolean SolarisBackend::start() +bool SolarisBackend::start() { try { mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&SolarisBackend::mixerProc), this}; - return ALC_TRUE; + return true; } catch(std::exception& e) { ERR("Could not create playback thread: %s\n", e.what()); } catch(...) { } - return ALC_FALSE; + return false; } void SolarisBackend::stop() diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 0d04d5a7..0dec5cb9 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -614,9 +614,9 @@ struct WasapiPlayback final : public BackendBase, WasapiProxy { HRESULT openProxy() override; void closeProxy() override; - ALCboolean reset() override; + bool reset() override; HRESULT resetProxy() override; - ALCboolean start() override; + bool start() override; HRESULT startProxy() override; void stop() override; void stopProxy() override; @@ -812,10 +812,10 @@ void WasapiPlayback::closeProxy() } -ALCboolean WasapiPlayback::reset() +bool WasapiPlayback::reset() { HRESULT hr{pushMessage(MsgType::ResetDevice).get()}; - return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; + return SUCCEEDED(hr) ? true : false; } HRESULT WasapiPlayback::resetProxy() @@ -1073,10 +1073,10 @@ HRESULT WasapiPlayback::resetProxy() } -ALCboolean WasapiPlayback::start() +bool WasapiPlayback::start() { HRESULT hr{pushMessage(MsgType::StartDevice).get()}; - return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; + return SUCCEEDED(hr) ? true : false; } HRESULT WasapiPlayback::startProxy() @@ -1156,12 +1156,12 @@ struct WasapiCapture final : public BackendBase, WasapiProxy { void closeProxy() override; HRESULT resetProxy() override; - ALCboolean start() override; + bool start() override; HRESULT startProxy() override; void stop() override; void stopProxy() override; - ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; ALCuint availableSamples() override; std::wstring mDevId; @@ -1622,10 +1622,10 @@ HRESULT WasapiCapture::resetProxy() } -ALCboolean WasapiCapture::start() +bool WasapiCapture::start() { HRESULT hr{pushMessage(MsgType::StartDevice).get()}; - return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; + return SUCCEEDED(hr) ? true : false; } HRESULT WasapiCapture::startProxy() @@ -1687,7 +1687,7 @@ void WasapiCapture::stopProxy() ALCuint WasapiCapture::availableSamples() { return static_cast(mRing->readSpace()); } -ALCenum WasapiCapture::captureSamples(void *buffer, ALCuint samples) +ALCenum WasapiCapture::captureSamples(al::byte *buffer, ALCuint samples) { mRing->read(buffer, samples); return ALC_NO_ERROR; diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp index 41d0a880..797a9fa5 100644 --- a/alc/backends/wave.cpp +++ b/alc/backends/wave.cpp @@ -97,8 +97,8 @@ struct WaveBackend final : public BackendBase { int mixerProc(); ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; + bool reset() override; + bool start() override; void stop() override; FILE *mFile{nullptr}; @@ -231,7 +231,7 @@ ALCenum WaveBackend::open(const ALCchar *name) return ALC_NO_ERROR; } -ALCboolean WaveBackend::reset() +bool WaveBackend::reset() { ALuint channels=0, bytes=0, chanmask=0; int isbformat = 0; @@ -324,7 +324,7 @@ ALCboolean WaveBackend::reset() if(ferror(mFile)) { ERR("Error writing header: %s\n", strerror(errno)); - return ALC_FALSE; + return false; } mDataStart = ftell(mFile); @@ -333,22 +333,22 @@ ALCboolean WaveBackend::reset() const ALuint bufsize{mDevice->frameSizeFromFmt() * mDevice->UpdateSize}; mBuffer.resize(bufsize); - return ALC_TRUE; + return true; } -ALCboolean WaveBackend::start() +bool WaveBackend::start() { try { mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&WaveBackend::mixerProc), this}; - return ALC_TRUE; + return true; } catch(std::exception& e) { ERR("Failed to start mixing thread: %s\n", e.what()); } catch(...) { } - return ALC_FALSE; + return false; } void WaveBackend::stop() diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp index 30a19e13..41c110d7 100644 --- a/alc/backends/winmm.cpp +++ b/alc/backends/winmm.cpp @@ -132,8 +132,8 @@ struct WinMMPlayback final : public BackendBase { int mixerProc(); ALCenum open(const ALCchar *name) override; - ALCboolean reset() override; - ALCboolean start() override; + bool reset() override; + bool start() override; void stop() override; std::atomic mWritable{0u}; @@ -263,7 +263,7 @@ retry_open: return ALC_NO_ERROR; } -ALCboolean WinMMPlayback::reset() +bool WinMMPlayback::reset() { mDevice->BufferSize = static_cast(uint64_t{mDevice->BufferSize} * mFormat.nSamplesPerSec / mDevice->Frequency); @@ -278,7 +278,7 @@ ALCboolean WinMMPlayback::reset() else { ERR("Unhandled IEEE float sample depth: %d\n", mFormat.wBitsPerSample); - return ALC_FALSE; + return false; } } else if(mFormat.wFormatTag == WAVE_FORMAT_PCM) @@ -290,13 +290,13 @@ ALCboolean WinMMPlayback::reset() else { ERR("Unhandled PCM sample depth: %d\n", mFormat.wBitsPerSample); - return ALC_FALSE; + return false; } } else { ERR("Unhandled format tag: 0x%04x\n", mFormat.wFormatTag); - return ALC_FALSE; + return false; } if(mFormat.nChannels == 2) @@ -306,7 +306,7 @@ ALCboolean WinMMPlayback::reset() else { ERR("Unhandled channel count: %d\n", mFormat.nChannels); - return ALC_FALSE; + return false; } SetDefaultWFXChannelOrder(mDevice); @@ -324,10 +324,10 @@ ALCboolean WinMMPlayback::reset() } mIdx = 0; - return ALC_TRUE; + return true; } -ALCboolean WinMMPlayback::start() +bool WinMMPlayback::start() { try { std::for_each(mWaveBuffer.begin(), mWaveBuffer.end(), @@ -338,14 +338,14 @@ ALCboolean WinMMPlayback::start() mKillNow.store(false, std::memory_order_release); mThread = std::thread{std::mem_fn(&WinMMPlayback::mixerProc), this}; - return ALC_TRUE; + return true; } catch(std::exception& e) { ERR("Failed to start mixing thread: %s\n", e.what()); } catch(...) { } - return ALC_FALSE; + return false; } void WinMMPlayback::stop() @@ -374,9 +374,9 @@ struct WinMMCapture final : public BackendBase { int captureProc(); ALCenum open(const ALCchar *name) override; - ALCboolean start() override; + bool start() override; void stop() override; - ALCenum captureSamples(void *buffer, ALCuint samples) override; + ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; ALCuint availableSamples() override; std::atomic mReadable{0u}; @@ -543,7 +543,7 @@ ALCenum WinMMCapture::open(const ALCchar *name) return ALC_NO_ERROR; } -ALCboolean WinMMCapture::start() +bool WinMMCapture::start() { try { for(size_t i{0};i < mWaveBuffer.size();++i) @@ -556,14 +556,14 @@ ALCboolean WinMMCapture::start() mThread = std::thread{std::mem_fn(&WinMMCapture::captureProc), this}; waveInStart(mInHdl); - return ALC_TRUE; + return true; } catch(std::exception& e) { ERR("Failed to start mixing thread: %s\n", e.what()); } catch(...) { } - return ALC_FALSE; + return false; } void WinMMCapture::stop() @@ -585,7 +585,7 @@ void WinMMCapture::stop() mIdx = 0; } -ALCenum WinMMCapture::captureSamples(void *buffer, ALCuint samples) +ALCenum WinMMCapture::captureSamples(al::byte *buffer, ALCuint samples) { mRing->read(buffer, samples); return ALC_NO_ERROR; -- cgit v1.2.3 From 47f0d301dc27e66263e754913782250f3899527e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 Sep 2019 10:22:56 -0700 Subject: Make the BackendFactory base destructor protected --- alc/backends/base.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/alc/backends/base.h b/alc/backends/base.h index cc33ba50..55240fd2 100644 --- a/alc/backends/base.h +++ b/alc/backends/base.h @@ -69,8 +69,6 @@ enum class DevProbe { struct BackendFactory { - virtual ~BackendFactory() = default; - virtual bool init() = 0; virtual bool querySupport(BackendType type) = 0; @@ -78,6 +76,9 @@ struct BackendFactory { virtual void probe(DevProbe type, std::string *outnames) = 0; virtual BackendPtr createBackend(ALCdevice *device, BackendType type) = 0; + +protected: + virtual ~BackendFactory() = default; }; #endif /* ALC_BACKENDS_BASE_H */ -- cgit v1.2.3 From a999df8ce5f3a2c5bdbe99cebea47a56d2bf1f66 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 Sep 2019 12:58:58 -0700 Subject: Rename ALautowah* for consistency --- alc/effects/autowah.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/alc/effects/autowah.cpp b/alc/effects/autowah.cpp index 5e396d0c..a79c21d9 100644 --- a/alc/effects/autowah.cpp +++ b/alc/effects/autowah.cpp @@ -38,7 +38,7 @@ namespace { #define MAX_FREQ 2500.0f #define Q_FACTOR 5.0f -struct ALautowahState final : public EffectState { +struct AutowahState final : public EffectState { /* Effect parameters */ ALfloat mAttackRate; ALfloat mReleaseRate; @@ -73,10 +73,10 @@ struct ALautowahState final : public EffectState { void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; void process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) override; - DEF_NEWDEL(ALautowahState) + DEF_NEWDEL(AutowahState) }; -ALboolean ALautowahState::deviceUpdate(const ALCdevice*) +ALboolean AutowahState::deviceUpdate(const ALCdevice*) { /* (Re-)initializing parameters and clear the buffers. */ @@ -104,7 +104,7 @@ ALboolean ALautowahState::deviceUpdate(const ALCdevice*) return AL_TRUE; } -void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) +void AutowahState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) { const ALCdevice *device{context->mDevice.get()}; const auto frequency = static_cast(device->Frequency); @@ -127,7 +127,7 @@ void ALautowahState::update(const ALCcontext *context, const ALeffectslot *slot, } } -void ALautowahState::process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) +void AutowahState::process(const size_t samplesToDo, const al::span samplesIn, const al::span samplesOut) { const ALfloat attack_rate = mAttackRate; const ALfloat release_rate = mReleaseRate; @@ -198,7 +198,7 @@ void ALautowahState::process(const size_t samplesToDo, const al::spansetError(AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param); } } -void ALautowah_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) -{ ALautowah_setParamf(props, context, param, vals[0]); } +void Autowah_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals) +{ Autowah_setParamf(props, context, param, vals[0]); } -void ALautowah_setParami(EffectProps*, ALCcontext *context, ALenum param, ALint) +void Autowah_setParami(EffectProps*, ALCcontext *context, ALenum param, ALint) { context->setError(AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param); } -void ALautowah_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) +void Autowah_setParamiv(EffectProps*, ALCcontext *context, ALenum param, const ALint*) { context->setError(AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x", param); } -void ALautowah_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) +void Autowah_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) { @@ -263,21 +263,21 @@ void ALautowah_getParamf(const EffectProps *props, ALCcontext *context, ALenum p } } -void ALautowah_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) -{ ALautowah_getParamf(props, context, param, vals); } +void Autowah_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals) +{ Autowah_getParamf(props, context, param, vals); } -void ALautowah_getParami(const EffectProps*, ALCcontext *context, ALenum param, ALint*) +void Autowah_getParami(const EffectProps*, ALCcontext *context, ALenum param, ALint*) { context->setError(AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param); } -void ALautowah_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) +void Autowah_getParamiv(const EffectProps*, ALCcontext *context, ALenum param, ALint*) { context->setError(AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x", param); } -DEFINE_ALEFFECT_VTABLE(ALautowah); +DEFINE_ALEFFECT_VTABLE(Autowah); struct AutowahStateFactory final : public EffectStateFactory { - EffectState *create() override { return new ALautowahState{}; } + EffectState *create() override { return new AutowahState{}; } EffectProps getDefaultProps() const noexcept override; - const EffectVtable *getEffectVtable() const noexcept override { return &ALautowah_vtable; } + const EffectVtable *getEffectVtable() const noexcept override { return &Autowah_vtable; } }; EffectProps AutowahStateFactory::getDefaultProps() const noexcept -- cgit v1.2.3 From 35129d66b78c146266cd85da68c5725fc289e49a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 Sep 2019 13:42:56 -0700 Subject: Clean up the spaghetti mess in alcCaptureSamples --- alc/alc.cpp | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index 4a4ed677..a5fde792 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -3907,14 +3907,26 @@ START_API_FUNC return; } - ALCenum err{ALC_INVALID_VALUE}; - { std::lock_guard _{dev->StateLock}; - BackendBase *backend{dev->Backend.get()}; - if(samples >= 0 && backend->availableSamples() >= static_cast(samples)) - err = backend->captureSamples(static_cast(buffer), - static_cast(samples)); + if(samples < 0 || (samples > 0 && buffer == nullptr)) + { + alcSetError(dev.get(), ALC_INVALID_VALUE); + return; } - if(err != ALC_NO_ERROR) + if(samples < 1) + return; + + std::lock_guard _{dev->StateLock}; + BackendBase *backend{dev->Backend.get()}; + + const auto usamples = static_cast(samples); + if(usamples > backend->availableSamples()) + { + alcSetError(dev.get(), ALC_INVALID_VALUE); + return; + } + + auto *bbuffer = static_cast(buffer); + if(ALCenum err{backend->captureSamples(bbuffer, usamples)}) alcSetError(dev.get(), err); } END_API_FUNC -- cgit v1.2.3 From e16e2269b6a18c960a25d58f43ffad5ed408bee9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 Sep 2019 20:46:37 -0700 Subject: Add a fallback if SLAndroidDataFormat_PCM_EX isn't available --- alc/backends/opensl.cpp | 147 ++++++++++++++++++++++++++++++------------------ 1 file changed, 91 insertions(+), 56 deletions(-) diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index 0f1d8a21..ec32c295 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -349,10 +349,6 @@ ALCenum OpenSLPlayback::open(const ALCchar *name) bool OpenSLPlayback::reset() { - SLDataLocator_AndroidSimpleBufferQueue loc_bufq; - SLDataLocator_OutputMix loc_outmix; - SLDataSource audioSrc; - SLDataSink audioSnk; SLresult result; if(mBufferQueueObj) @@ -439,44 +435,68 @@ bool OpenSLPlayback::reset() const std::array ids{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }}; const std::array reqs{{ SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }}; + SLDataLocator_OutputMix loc_outmix{}; + loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; + loc_outmix.outputMix = mOutputMix; + + SLDataSink audioSnk{}; + audioSnk.pLocator = &loc_outmix; + audioSnk.pFormat = nullptr; + + SLDataLocator_AndroidSimpleBufferQueue loc_bufq{}; loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; loc_bufq.numBuffers = mDevice->BufferSize / mDevice->UpdateSize; + SLDataSource audioSrc{}; #ifdef SL_ANDROID_DATAFORMAT_PCM_EX - SLAndroidDataFormat_PCM_EX format_pcm{}; - format_pcm.formatType = SL_ANDROID_DATAFORMAT_PCM_EX; - format_pcm.numChannels = mDevice->channelsFromFmt(); - format_pcm.sampleRate = mDevice->Frequency * 1000; - format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; - format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); - format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : - SL_BYTEORDER_BIGENDIAN; - format_pcm.representation = GetTypeRepresentation(mDevice->FmtType); -#else - SLDataFormat_PCM format_pcm{}; - format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = mDevice->channelsFromFmt(); - format_pcm.samplesPerSec = mDevice->Frequency * 1000; - format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; - format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); - format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : - SL_BYTEORDER_BIGENDIAN; -#endif + SLAndroidDataFormat_PCM_EX format_pcm_ex{}; + format_pcm_ex.formatType = SL_ANDROID_DATAFORMAT_PCM_EX; + format_pcm_ex.numChannels = mDevice->channelsFromFmt(); + format_pcm_ex.sampleRate = mDevice->Frequency * 1000; + format_pcm_ex.bitsPerSample = mDevice->bytesFromFmt() * 8; + format_pcm_ex.containerSize = format_pcm_ex.bitsPerSample; + format_pcm_ex.channelMask = GetChannelMask(mDevice->FmtChans); + format_pcm_ex.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; + format_pcm_ex.representation = GetTypeRepresentation(mDevice->FmtType); audioSrc.pLocator = &loc_bufq; - audioSrc.pFormat = &format_pcm; - - loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; - loc_outmix.outputMix = mOutputMix; - audioSnk.pLocator = &loc_outmix; - audioSnk.pFormat = nullptr; - + audioSrc.pFormat = &format_pcm_ex; result = VCALL(mEngine,CreateAudioPlayer)(&mBufferQueueObj, &audioSrc, &audioSnk, ids.size(), ids.data(), reqs.data()); - PRINTERR(result, "engine->CreateAudioPlayer"); + if(SL_RESULT_SUCCESS != result) +#endif + { + /* Alter sample type according to what SLDataFormat_PCM can support. */ + switch(mDevice->FmtType) + { + case DevFmtByte: mDevice->FmtType = DevFmtUByte; break; + case DevFmtUInt: mDevice->FmtType = DevFmtInt; break; + case DevFmtFloat: + case DevFmtUShort: mDevice->FmtType = DevFmtShort; break; + case DevFmtUByte: + case DevFmtShort: + case DevFmtInt: + break; + } + + SLDataFormat_PCM format_pcm{}; + format_pcm.formatType = SL_DATAFORMAT_PCM; + format_pcm.numChannels = mDevice->channelsFromFmt(); + format_pcm.samplesPerSec = mDevice->Frequency * 1000; + format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; + format_pcm.containerSize = format_pcm.bitsPerSample; + format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); + format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : + SL_BYTEORDER_BIGENDIAN; + + audioSrc.pLocator = &loc_bufq; + audioSrc.pFormat = &format_pcm; + + result = VCALL(mEngine,CreateAudioPlayer)(&mBufferQueueObj, &audioSrc, &audioSnk, ids.size(), + ids.data(), reqs.data()); + PRINTERR(result, "engine->CreateAudioPlayer"); + } if(SL_RESULT_SUCCESS == result) { /* Set the stream type to "media" (games, music, etc), if possible. */ @@ -717,34 +737,49 @@ ALCenum OpenSLCapture::open(const ALCchar* name) loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; loc_bq.numBuffers = mDevice->BufferSize / mDevice->UpdateSize; + SLDataSink audioSnk{}; #ifdef SL_ANDROID_DATAFORMAT_PCM_EX - SLAndroidDataFormat_PCM_EX format_pcm{}; - format_pcm.formatType = SL_ANDROID_DATAFORMAT_PCM_EX; - format_pcm.numChannels = mDevice->channelsFromFmt(); - format_pcm.sampleRate = mDevice->Frequency * 1000; - format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; - format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); - format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; - format_pcm.representation = GetTypeRepresentation(mDevice->FmtType); -#else - SLDataFormat_PCM format_pcm{}; - format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = mDevice->channelsFromFmt(); - format_pcm.samplesPerSec = mDevice->Frequency * 1000; - format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; - format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); - format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; -#endif + SLAndroidDataFormat_PCM_EX format_pcm_ex{}; + format_pcm_ex.formatType = SL_ANDROID_DATAFORMAT_PCM_EX; + format_pcm_ex.numChannels = mDevice->channelsFromFmt(); + format_pcm_ex.sampleRate = mDevice->Frequency * 1000; + format_pcm_ex.bitsPerSample = mDevice->bytesFromFmt() * 8; + format_pcm_ex.containerSize = format_pcm_ex.bitsPerSample; + format_pcm_ex.channelMask = GetChannelMask(mDevice->FmtChans); + format_pcm_ex.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : + SL_BYTEORDER_BIGENDIAN; + format_pcm_ex.representation = GetTypeRepresentation(mDevice->FmtType); - SLDataSink audioSnk{}; audioSnk.pLocator = &loc_bq; - audioSnk.pFormat = &format_pcm; - + audioSnk.pFormat = &format_pcm_ex; result = VCALL(mEngine,CreateAudioRecorder)(&mRecordObj, &audioSrc, &audioSnk, ids.size(), ids.data(), reqs.data()); - PRINTERR(result, "engine->CreateAudioRecorder"); + if(SL_RESULT_SUCCESS != result) +#endif + { + /* Fallback to SLDataFormat_PCM only if it supports the desired + * sample type. + */ + if(mDevice->FmtType == DevFmtUByte || mDevice->FmtType == DevFmtShort + || mDevice->FmtType == DevFmtInt) + { + SLDataFormat_PCM format_pcm{}; + format_pcm.formatType = SL_DATAFORMAT_PCM; + format_pcm.numChannels = mDevice->channelsFromFmt(); + format_pcm.samplesPerSec = mDevice->Frequency * 1000; + format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8; + format_pcm.containerSize = format_pcm.bitsPerSample; + format_pcm.channelMask = GetChannelMask(mDevice->FmtChans); + format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : + SL_BYTEORDER_BIGENDIAN; + + audioSnk.pLocator = &loc_bq; + audioSnk.pFormat = &format_pcm; + result = VCALL(mEngine,CreateAudioRecorder)(&mRecordObj, &audioSrc, &audioSnk, + ids.size(), ids.data(), reqs.data()); + } + PRINTERR(result, "engine->CreateAudioRecorder"); + } } if(SL_RESULT_SUCCESS == result) { -- cgit v1.2.3 From bf2c865d3953370ccf9d56e7a5dc6d2d4c587be1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Sep 2019 07:16:31 -0700 Subject: Clean up some more shadowing warnings --- al/source.cpp | 14 +++++++------- alc/alu.cpp | 21 ++++++++++----------- alc/backends/pulseaudio.cpp | 14 ++++++-------- alc/hrtf.cpp | 8 ++++---- alc/mixer/mixer_c.cpp | 7 ++++--- alc/mixer/mixer_neon.cpp | 12 +++++++----- alc/mixer/mixer_sse.cpp | 12 +++++++----- alc/mixvoice.cpp | 8 ++++---- 8 files changed, 49 insertions(+), 47 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index 53d2a705..f5550caf 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -2749,15 +2749,15 @@ START_API_FUNC } /* Look for an unused voice to play this source with. */ + auto find_voice = [](const ALvoice &v) noexcept -> bool + { + return v.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped + && v.mSourceID.load(std::memory_order_relaxed) == 0u; + }; auto voices_end = context->mVoices.data() + context->mVoices.size(); - voice = std::find_if(context->mVoices.data(), voices_end, - [](const ALvoice &voice) noexcept -> bool - { - return voice.mPlayState.load(std::memory_order_acquire) == ALvoice::Stopped && - voice.mSourceID.load(std::memory_order_relaxed) == 0u; - } - ); + voice = std::find_if(context->mVoices.data(), voices_end, find_voice); assert(voice != voices_end); + auto vidx = static_cast(std::distance(context->mVoices.data(), voice)); voice->mPlayState.store(ALvoice::Stopped, std::memory_order_release); diff --git a/alc/alu.cpp b/alc/alu.cpp index d7acf8d3..60c8e8e2 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -1320,17 +1320,16 @@ void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray &slots, bool force{CalcContextParams(ctx)}; force |= CalcListenerParams(ctx); force = std::accumulate(slots.begin(), slots.end(), force, - [ctx](const bool force, ALeffectslot *slot) -> bool - { return CalcEffectSlotParams(slot, ctx) | force; } + [ctx](const bool f, ALeffectslot *slot) -> bool + { return CalcEffectSlotParams(slot, ctx) | f; } ); - std::for_each(voices.begin(), voices.end(), - [ctx,force](ALvoice &voice) -> void - { - ALuint sid{voice.mSourceID.load(std::memory_order_acquire)}; - if(sid) CalcSourceParams(&voice, ctx, force); - } - ); + auto calc_params = [ctx,force](ALvoice &voice) -> void + { + if(ALuint sid{voice.mSourceID.load(std::memory_order_acquire)}) + CalcSourceParams(&voice, ctx, force); + }; + std::for_each(voices.begin(), voices.end(), calc_params); } IncrementRef(ctx->mUpdateCount); } @@ -1446,7 +1445,7 @@ void ApplyStablizer(FrontStablizer *Stablizer, const al::span B /* This applies the band-splitter, preserving phase at the cost of some * delay. The shorter the delay, the more error seeps into the result. */ - auto apply_splitter = [&tmpbuf,SamplesToDo](const FloatBufferLine &Buffer, + auto apply_splitter = [&tmpbuf,SamplesToDo](const FloatBufferLine &InBuf, ALfloat (&DelayBuf)[FrontStablizer::DelayLength], BandSplitter &Filter, ALfloat (&splitbuf)[2][BUFFERSIZE]) -> void { @@ -1457,7 +1456,7 @@ void ApplyStablizer(FrontStablizer *Stablizer, const al::span B */ auto tmpbuf_end = std::begin(tmpbuf) + SamplesToDo; std::copy_n(std::begin(DelayBuf), FrontStablizer::DelayLength, tmpbuf_end); - std::reverse_copy(Buffer.begin(), Buffer.begin()+SamplesToDo, std::begin(tmpbuf)); + std::reverse_copy(InBuf.begin(), InBuf.begin()+SamplesToDo, std::begin(tmpbuf)); std::copy_n(std::begin(tmpbuf), FrontStablizer::DelayLength, std::begin(DelayBuf)); /* Apply an all-pass on the reversed signal, then reverse the samples diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index e9997013..4d3b34d9 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -447,10 +447,8 @@ struct DevMap { bool checkName(const al::vector &list, const std::string &name) { - return std::find_if(list.cbegin(), list.cend(), - [&name](const DevMap &entry) -> bool - { return entry.name == name; } - ) != list.cend(); + auto match_name = [&name](const DevMap &entry) -> bool { return entry.name == name; }; + return std::find_if(list.cbegin(), list.cend(), match_name) != list.cend(); } al::vector PlaybackDevices; @@ -756,7 +754,7 @@ void PulsePlayback::sinkInfoCallbackC(pa_context *context, const pa_sink_info *i void PulsePlayback::sinkInfoCallback(pa_context*, const pa_sink_info *info, int eol) { struct ChannelMap { - DevFmtChannels chans; + DevFmtChannels fmt; pa_channel_map map; }; static constexpr std::array chanmaps{{ @@ -775,14 +773,14 @@ void PulsePlayback::sinkInfoCallback(pa_context*, const pa_sink_info *info, int return; } - auto chanmap = std::find_if(chanmaps.cbegin(), chanmaps.cend(), + auto chaniter = std::find_if(chanmaps.cbegin(), chanmaps.cend(), [info](const ChannelMap &chanmap) -> bool { return pa_channel_map_superset(&info->channel_map, &chanmap.map); } ); - if(chanmap != chanmaps.cend()) + if(chaniter != chanmaps.cend()) { if(!mDevice->Flags.get()) - mDevice->FmtChans = chanmap->chans; + mDevice->FmtChans = chaniter->fmt; } else { diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index 7d40b16c..7110478d 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -323,12 +323,12 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin const ALuint azidx{float2uint(az_norm*static_cast(azcount) + 0.5f) % azcount}; /* Calculate the index for the impulse response. */ - const ALuint idx{iroffset + azidx}; + const ALuint iridx{iroffset + azidx}; - min_delay = minu(min_delay, minu(Hrtf->delays[idx][0], Hrtf->delays[idx][1])); - max_delay = maxu(max_delay, maxu(Hrtf->delays[idx][0], Hrtf->delays[idx][1])); + min_delay = minu(min_delay, minu(Hrtf->delays[iridx][0], Hrtf->delays[iridx][1])); + max_delay = maxu(max_delay, maxu(Hrtf->delays[iridx][0], Hrtf->delays[iridx][1])); - return idx; + return iridx; }; std::transform(AmbiPoints, AmbiPoints+AmbiCount, idx.begin(), calc_idxs); diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index 7beab1a9..6e96e54e 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -188,13 +188,14 @@ void MixRow_(const al::span OutBuffer, const al::span { for(const float gain : Gains) { - const float *RESTRICT src{InSamples}; + const float *RESTRICT input{InSamples}; InSamples += InStride; if(!(std::fabs(gain) > GAIN_SILENCE_THRESHOLD)) continue; - std::transform(OutBuffer.begin(), OutBuffer.end(), src, OutBuffer.begin(), - [gain](const ALfloat cur, const ALfloat src) -> ALfloat { return cur + src*gain; }); + auto do_mix = [gain](const float cur, const float src) noexcept -> float + { return cur + src*gain; }; + std::transform(OutBuffer.begin(), OutBuffer.end(), input, OutBuffer.begin(), do_mix); } } diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index 2f11273a..e7313876 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -262,7 +262,7 @@ void MixRow_(const al::span OutBuffer, const al::span GAIN_SILENCE_THRESHOLD)) @@ -273,14 +273,16 @@ void MixRow_(const al::span OutBuffer, const al::span ALfloat { return cur + src*gain; }); + + auto do_mix = [gain](const float cur, const float src) noexcept -> float + { return cur + src*gain; }; + std::transform(out_iter, OutBuffer.end(), input, out_iter, do_mix); } } diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index 65eb0dee..d47a0e66 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -226,7 +226,7 @@ void MixRow_(const al::span OutBuffer, const al::span GAIN_SILENCE_THRESHOLD)) @@ -237,14 +237,16 @@ void MixRow_(const al::span OutBuffer, const al::span ALfloat { return cur + src*gain; }); + + auto do_mix = [gain](const float cur, const float src) noexcept -> float + { return cur + src*gain; }; + std::transform(out_iter, OutBuffer.end(), input, out_iter, do_mix); } } diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 2b5972f3..3d4d9cb8 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -763,14 +763,14 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) const al::span nfcsamples{Device->NfcSampleData, DstBufferSize}; size_t chanoffset{outcount}; using FilterProc = void (NfcFilter::*)(float*,const float*,const size_t); - auto apply_nfc = [this,&parms,samples,TargetGains,Counter,OutPos,&chanoffset,nfcsamples](const FilterProc process, const size_t outcount) -> void + auto apply_nfc = [this,&parms,samples,TargetGains,Counter,OutPos,&chanoffset,nfcsamples](const FilterProc process, const size_t chancount) -> void { - if(outcount < 1) return; + if(chancount < 1) return; (parms.NFCtrlFilter.*process)(nfcsamples.data(), samples, nfcsamples.size()); - MixSamples(nfcsamples, mDirect.Buffer.subspan(chanoffset, outcount), + MixSamples(nfcsamples, mDirect.Buffer.subspan(chanoffset, chancount), parms.Gains.Current+chanoffset, TargetGains+chanoffset, Counter, OutPos); - chanoffset += outcount; + chanoffset += chancount; }; apply_nfc(&NfcFilter::process1, Device->NumChannelsPerOrder[1]); apply_nfc(&NfcFilter::process2, Device->NumChannelsPerOrder[2]); -- cgit v1.2.3 From fcf850c1dd54dcf5de5bc7afc723ffac51e5c0c9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Sep 2019 07:32:13 -0700 Subject: Clean up some more conversion warnings --- alc/backends/opensl.cpp | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index ec32c295..50ea884d 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -146,7 +146,8 @@ struct OpenSLPlayback final : public BackendBase { OpenSLPlayback(ALCdevice *device) noexcept : BackendBase{device} { } ~OpenSLPlayback() override; - static void processC(SLAndroidSimpleBufferQueueItf bq, void *context); + static void processC(SLAndroidSimpleBufferQueueItf bq, void *context) + { static_cast(context)->process(bq); } void process(SLAndroidSimpleBufferQueueItf bq); int mixerProc(); @@ -196,9 +197,6 @@ OpenSLPlayback::~OpenSLPlayback() /* this callback handler is called every time a buffer finishes playing */ -void OpenSLPlayback::processC(SLAndroidSimpleBufferQueueItf bq, void *context) -{ static_cast(context)->process(bq); } - void OpenSLPlayback::process(SLAndroidSimpleBufferQueueItf) { /* A note on the ringbuffer usage: The buffer queue seems to hold on to the @@ -264,9 +262,11 @@ int OpenSLPlayback::mixerProc() } auto data = mRing->getWriteVector(); - aluMixData(mDevice, data.first.buf, data.first.len*mDevice->UpdateSize); + aluMixData(mDevice, data.first.buf, + static_cast(data.first.len*mDevice->UpdateSize)); if(data.second.len > 0) - aluMixData(mDevice, data.second.buf, data.second.len*mDevice->UpdateSize); + aluMixData(mDevice, data.second.buf, + static_cast(data.second.len*mDevice->UpdateSize)); size_t todo{data.first.len + data.second.len}; mRing->writeAdvance(todo); @@ -631,7 +631,8 @@ struct OpenSLCapture final : public BackendBase { OpenSLCapture(ALCdevice *device) noexcept : BackendBase{device} { } ~OpenSLCapture() override; - static void processC(SLAndroidSimpleBufferQueueItf bq, void *context); + static void processC(SLAndroidSimpleBufferQueueItf bq, void *context) + { static_cast(context)->process(bq); } void process(SLAndroidSimpleBufferQueueItf bq); ALCenum open(const ALCchar *name) override; @@ -668,9 +669,6 @@ OpenSLCapture::~OpenSLCapture() } -void OpenSLCapture::processC(SLAndroidSimpleBufferQueueItf bq, void *context) -{ static_cast(context)->process(bq); } - void OpenSLCapture::process(SLAndroidSimpleBufferQueueItf) { /* A new chunk has been written into the ring buffer, advance it. */ @@ -711,7 +709,7 @@ ALCenum OpenSLCapture::open(const ALCchar* name) mRing = CreateRingBuffer(num_updates, update_len*mFrameSize, false); mDevice->UpdateSize = update_len; - mDevice->BufferSize = mRing->writeSpace() * update_len; + mDevice->BufferSize = static_cast(mRing->writeSpace() * update_len); } catch(std::exception& e) { ERR("Failed to allocate ring buffer: %s\n", e.what()); @@ -886,25 +884,24 @@ void OpenSLCapture::stop() ALCenum OpenSLCapture::captureSamples(al::byte *buffer, ALCuint samples) { - ALuint chunk_size{mDevice->UpdateSize * mFrameSize}; SLAndroidSimpleBufferQueueItf bufferQueue; - SLresult result; - ALCuint i; - - result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); + SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue)}; PRINTERR(result, "recordObj->GetInterface"); + const ALuint update_size{mDevice->UpdateSize}; + const ALuint chunk_size{update_size * mFrameSize}; + /* Read the desired samples from the ring buffer then advance its read * pointer. */ auto data = mRing->getReadVector(); - for(i = 0;i < samples;) + for(ALCuint i{0};i < samples;) { - ALCuint rem{minu(samples - i, mDevice->UpdateSize - mSplOffset)}; - memcpy(buffer + i*mFrameSize, data.first.buf + mSplOffset*mFrameSize, rem*mFrameSize); + const ALCuint rem{minu(samples - i, update_size - mSplOffset)}; + std::copy_n(data.first.buf + mSplOffset*mFrameSize, rem*mFrameSize, buffer + i*mFrameSize); mSplOffset += rem; - if(mSplOffset == mDevice->UpdateSize) + if(mSplOffset == update_size) { /* Finished a chunk, reset the offset and advance the read pointer. */ mSplOffset = 0; @@ -924,7 +921,7 @@ ALCenum OpenSLCapture::captureSamples(al::byte *buffer, ALCuint samples) i += rem; } - if(SL_RESULT_SUCCESS != result) + if UNLIKELY(SL_RESULT_SUCCESS != result) { aluHandleDisconnect(mDevice, "Failed to update capture buffer: 0x%08x", result); return ALC_INVALID_DEVICE; @@ -934,7 +931,7 @@ ALCenum OpenSLCapture::captureSamples(al::byte *buffer, ALCuint samples) } ALCuint OpenSLCapture::availableSamples() -{ return mRing->readSpace()*mDevice->UpdateSize - mSplOffset; } +{ return static_cast(mRing->readSpace()*mDevice->UpdateSize - mSplOffset); } } // namespace -- cgit v1.2.3 From 650764775febeedd2834ce3a0838d6468f4b6b31 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Sep 2019 07:50:39 -0700 Subject: Fix typo --- alc/mixer/mixer_neon.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index e7313876..8a98f5de 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -262,7 +262,7 @@ void MixRow_(const al::span OutBuffer, const al::span GAIN_SILENCE_THRESHOLD)) @@ -273,11 +273,11 @@ void MixRow_(const al::span OutBuffer, const al::span Date: Mon, 16 Sep 2019 13:45:14 -0700 Subject: Add and use custom string types and functions --- CMakeLists.txt | 2 ++ al/extension.cpp | 4 +-- alc/alc.cpp | 78 +++++++++++++++++++++++++++++------------------------ common/alstring.cpp | 45 +++++++++++++++++++++++++++++++ common/alstring.h | 29 ++++++++++++++++++++ router/alc.cpp | 3 ++- 6 files changed, 123 insertions(+), 38 deletions(-) create mode 100644 common/alstring.cpp create mode 100644 common/alstring.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 762ce3e6..b8501740 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -594,6 +594,8 @@ SET(COMMON_OBJS common/alnumeric.h common/aloptional.h common/alspan.h + common/alstring.cpp + common/alstring.h common/atomic.h common/dynload.cpp common/dynload.h diff --git a/al/extension.cpp b/al/extension.cpp index ab759262..35c53136 100644 --- a/al/extension.cpp +++ b/al/extension.cpp @@ -29,6 +29,7 @@ #include "alcontext.h" #include "alexcpt.h" +#include "alstring.h" #include "opthelpers.h" @@ -45,8 +46,7 @@ START_API_FUNC const char *ptr{context->mExtensionList}; while(ptr && *ptr) { - if(strncasecmp(ptr, extName, len) == 0 && - (ptr[len] == '\0' || isspace(ptr[len]))) + if(al::strncasecmp(ptr, extName, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len]))) return AL_TRUE; if((ptr=strchr(ptr, ' ')) != nullptr) diff --git a/alc/alc.cpp b/alc/alc.cpp index a5fde792..8a0a3468 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -67,6 +67,7 @@ #include "alnumeric.h" #include "aloptional.h" #include "alspan.h" +#include "alstring.h" #include "alu.h" #include "ambidefs.h" #include "atomic.h" @@ -802,8 +803,8 @@ std::string alcAllDevicesList; std::string alcCaptureDeviceList; /* Default is always the first in the list */ -std::string alcDefaultAllDevicesSpecifier; -std::string alcCaptureDefaultDeviceSpecifier; +al::string alcDefaultAllDevicesSpecifier; +al::string alcCaptureDefaultDeviceSpecifier; /* Default context extensions */ constexpr ALchar alExtList[] = @@ -952,7 +953,7 @@ void alc_initconfig(void) TRACE("Initializing library v%s-%s %s\n", ALSOFT_VERSION, ALSOFT_GIT_COMMIT_HASH, ALSOFT_GIT_BRANCH); { - std::string names; + al::string names; if(std::begin(BackendList) == BackendListEnd) names += "(none)"; else @@ -971,7 +972,7 @@ void alc_initconfig(void) if(auto suspendmode = al::getenv("__ALSOFT_SUSPEND_CONTEXT")) { - if(strcasecmp(suspendmode->c_str(), "ignore") == 0) + if(al::strcasecmp(suspendmode->c_str(), "ignore") == 0) { SuspendDefers = false; TRACE("Selected context suspend behavior, \"ignore\"\n"); @@ -996,7 +997,7 @@ void alc_initconfig(void) if(auto cpuopt = ConfigValueStr(nullptr, nullptr, "disable-cpu-exts")) { const char *str{cpuopt->c_str()}; - if(strcasecmp(str, "all") == 0) + if(al::strcasecmp(str, "all") == 0) capfilter = 0; else { @@ -1013,15 +1014,15 @@ void alc_initconfig(void) size_t len{next ? static_cast(next-str) : strlen(str)}; while(len > 0 && isspace(str[len-1])) len--; - if(len == 3 && strncasecmp(str, "sse", len) == 0) + if(len == 3 && al::strncasecmp(str, "sse", len) == 0) capfilter &= ~CPU_CAP_SSE; - else if(len == 4 && strncasecmp(str, "sse2", len) == 0) + else if(len == 4 && al::strncasecmp(str, "sse2", len) == 0) capfilter &= ~CPU_CAP_SSE2; - else if(len == 4 && strncasecmp(str, "sse3", len) == 0) + else if(len == 4 && al::strncasecmp(str, "sse3", len) == 0) capfilter &= ~CPU_CAP_SSE3; - else if(len == 6 && strncasecmp(str, "sse4.1", len) == 0) + else if(len == 6 && al::strncasecmp(str, "sse4.1", len) == 0) capfilter &= ~CPU_CAP_SSE4_1; - else if(len == 4 && strncasecmp(str, "neon", len) == 0) + else if(len == 4 && al::strncasecmp(str, "neon", len) == 0) capfilter &= ~CPU_CAP_NEON; else WARN("Invalid CPU extension \"%s\"\n", str); @@ -1042,8 +1043,8 @@ void alc_initconfig(void) aluInitMixer(); auto traperr = al::getenv("ALSOFT_TRAP_ERROR"); - if(traperr && (strcasecmp(traperr->c_str(), "true") == 0 - || strtol(traperr->c_str(), nullptr, 0) == 1)) + if(traperr && (al::strcasecmp(traperr->c_str(), "true") == 0 + || std::strtol(traperr->c_str(), nullptr, 0) == 1)) { TrapALError = true; TrapALCError = true; @@ -1052,14 +1053,14 @@ void alc_initconfig(void) { traperr = al::getenv("ALSOFT_TRAP_AL_ERROR"); if(traperr) - TrapALError = strcasecmp(traperr->c_str(), "true") == 0 + TrapALError = al::strcasecmp(traperr->c_str(), "true") == 0 || strtol(traperr->c_str(), nullptr, 0) == 1; else TrapALError = !!GetConfigValueBool(nullptr, nullptr, "trap-al-error", false); traperr = al::getenv("ALSOFT_TRAP_ALC_ERROR"); if(traperr) - TrapALCError = strcasecmp(traperr->c_str(), "true") == 0 + TrapALCError = al::strcasecmp(traperr->c_str(), "true") == 0 || strtol(traperr->c_str(), nullptr, 0) == 1; else TrapALCError = !!GetConfigValueBool(nullptr, nullptr, "trap-alc-error", false); @@ -1870,11 +1871,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(auto hrtfopt = ConfigValueStr(device->DeviceName.c_str(), nullptr, "hrtf")) { const char *hrtf{hrtfopt->c_str()}; - if(strcasecmp(hrtf, "true") == 0) + if(al::strcasecmp(hrtf, "true") == 0) hrtf_userreq = Hrtf_Enable; - else if(strcasecmp(hrtf, "false") == 0) + else if(al::strcasecmp(hrtf, "false") == 0) hrtf_userreq = Hrtf_Disable; - else if(strcasecmp(hrtf, "auto") != 0) + else if(al::strcasecmp(hrtf, "auto") != 0) ERR("Unexpected hrtf value: %s\n", hrtf); } @@ -3194,8 +3195,7 @@ START_API_FUNC const char *ptr = (dev ? alcExtensionList : alcNoDeviceExtList); while(ptr && *ptr) { - if(strncasecmp(ptr, extName, len) == 0 && - (ptr[len] == '\0' || isspace(ptr[len]))) + if(al::strncasecmp(ptr, extName, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len]))) return ALC_TRUE; if((ptr=strchr(ptr, ' ')) != nullptr) @@ -3513,17 +3513,21 @@ START_API_FUNC return nullptr; } - if(deviceName && (!deviceName[0] || strcasecmp(deviceName, alcDefaultName) == 0 || strcasecmp(deviceName, "openal-soft") == 0 + if(deviceName) + { + if(!deviceName[0] || al::strcasecmp(deviceName, alcDefaultName) == 0 #ifdef _WIN32 - /* Some old Windows apps hardcode these expecting OpenAL to use a - * specific audio API, even when they're not enumerated. Creative's - * router effectively ignores them too. - */ - || strcasecmp(deviceName, "DirectSound3D") == 0 || strcasecmp(deviceName, "DirectSound") == 0 - || strcasecmp(deviceName, "MMSYSTEM") == 0 + /* Some old Windows apps hardcode these expecting OpenAL to use a + * specific audio API, even when they're not enumerated. Creative's + * router effectively ignores them too. + */ + || al::strcasecmp(deviceName, "DirectSound3D") == 0 + || al::strcasecmp(deviceName, "DirectSound") == 0 + || al::strcasecmp(deviceName, "MMSYSTEM") == 0 #endif - )) - deviceName = nullptr; + || al::strcasecmp(deviceName, "openal-soft") == 0) + deviceName = nullptr; + } DeviceRef device{new ALCdevice{Playback}}; @@ -3579,7 +3583,7 @@ START_API_FUNC const ALCchar *fmt{chanopt->c_str()}; auto iter = std::find_if(std::begin(chanlist), std::end(chanlist), [fmt](const ChannelMap &entry) -> bool - { return strcasecmp(entry.name, fmt) == 0; } + { return al::strcasecmp(entry.name, fmt) == 0; } ); if(iter == std::end(chanlist)) ERR("Unsupported channels: %s\n", fmt); @@ -3608,7 +3612,7 @@ START_API_FUNC const ALCchar *fmt{typeopt->c_str()}; auto iter = std::find_if(std::begin(typelist), std::end(typelist), [fmt](const TypeMap &entry) -> bool - { return strcasecmp(entry.name, fmt) == 0; } + { return al::strcasecmp(entry.name, fmt) == 0; } ); if(iter == std::end(typelist)) ERR("Unsupported sample-type: %s\n", fmt); @@ -3661,7 +3665,7 @@ START_API_FUNC if(auto ambiopt = ConfigValueStr(deviceName, nullptr, "ambi-format")) { const ALCchar *fmt{ambiopt->c_str()}; - if(strcasecmp(fmt, "fuma") == 0) + if(al::strcasecmp(fmt, "fuma") == 0) { if(device->mAmbiOrder > 3) ERR("FuMa is incompatible with %d%s order ambisonics (up to third-order only)\n", @@ -3676,12 +3680,12 @@ START_API_FUNC device->mAmbiScale = AmbiNorm::FuMa; } } - else if(strcasecmp(fmt, "ambix") == 0 || strcasecmp(fmt, "acn+sn3d") == 0) + else if(al::strcasecmp(fmt, "ambix") == 0 || al::strcasecmp(fmt, "acn+sn3d") == 0) { device->mAmbiLayout = AmbiLayout::ACN; device->mAmbiScale = AmbiNorm::SN3D; } - else if(strcasecmp(fmt, "acn+n3d") == 0) + else if(al::strcasecmp(fmt, "acn+n3d") == 0) { device->mAmbiLayout = AmbiLayout::ACN; device->mAmbiScale = AmbiNorm::N3D; @@ -3776,8 +3780,12 @@ START_API_FUNC return nullptr; } - if(deviceName && (!deviceName[0] || strcasecmp(deviceName, alcDefaultName) == 0 || strcasecmp(deviceName, "openal-soft") == 0)) - deviceName = nullptr; + if(deviceName) + { + if(!deviceName[0] || al::strcasecmp(deviceName, alcDefaultName) == 0 + || al::strcasecmp(deviceName, "openal-soft") == 0) + deviceName = nullptr; + } DeviceRef device{new ALCdevice{Capture}}; diff --git a/common/alstring.cpp b/common/alstring.cpp new file mode 100644 index 00000000..4a84be1d --- /dev/null +++ b/common/alstring.cpp @@ -0,0 +1,45 @@ + +#include "config.h" + +#include "alstring.h" + +#include +#include + + +namespace { + +int to_upper(const char ch) +{ + using char8_traits = std::char_traits; + return std::toupper(char8_traits::to_int_type(ch)); +} + +} // namespace + +namespace al { + +int strcasecmp(const char *str0, const char *str1) noexcept +{ + do { + const int diff{to_upper(*str0) - to_upper(*str1)}; + if(diff < 0) return -1; + if(diff > 0) return 1; + } while(*(str0++) && *(str1++)); + return 0; +} + +int strncasecmp(const char *str0, const char *str1, std::size_t len) noexcept +{ + if(len > 0) + { + do { + const int diff{to_upper(*str0) - to_upper(*str1)}; + if(diff < 0) return -1; + if(diff > 0) return 1; + } while(--len && *(str0++) && *(str1++)); + } + return 0; +} + +} // namespace al diff --git a/common/alstring.h b/common/alstring.h new file mode 100644 index 00000000..194e54a1 --- /dev/null +++ b/common/alstring.h @@ -0,0 +1,29 @@ +#ifndef AL_STRING_H +#define AL_STRING_H + +#include +#include + +#include "almalloc.h" + + +namespace al { + +template> +using basic_string = std::basic_string>; + +using string = basic_string; +using wstring = basic_string; +using u16string = basic_string; +using u32string = basic_string; + + +/* These would be better served by using a string_view-like span/view with + * case-insensitive char traits. + */ +int strcasecmp(const char *str0, const char *str1) noexcept; +int strncasecmp(const char *str0, const char *str1, std::size_t len) noexcept; + +} // namespace al + +#endif /* AL_STRING_H */ diff --git a/router/alc.cpp b/router/alc.cpp index 0f552523..6620b6a7 100644 --- a/router/alc.cpp +++ b/router/alc.cpp @@ -11,6 +11,7 @@ #include #include "AL/alc.h" +#include "alstring.h" #include "router.h" @@ -539,7 +540,7 @@ ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const A ptr = alcExtensionList; while(ptr && *ptr) { - if(strncasecmp(ptr, extname, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len]))) + if(al::strncasecmp(ptr, extname, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len]))) return ALC_TRUE; if((ptr=strchr(ptr, ' ')) != nullptr) { -- cgit v1.2.3 From 10a841cd7e2e3b5115fe86ce40ee9049318dfd8f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Sep 2019 14:10:48 -0700 Subject: Avoid an unused variable --- alc/alu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alc/alu.cpp b/alc/alu.cpp index 60c8e8e2..32c52526 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -1326,7 +1326,7 @@ void ProcessParamUpdates(ALCcontext *ctx, const ALeffectslotArray &slots, auto calc_params = [ctx,force](ALvoice &voice) -> void { - if(ALuint sid{voice.mSourceID.load(std::memory_order_acquire)}) + if(voice.mSourceID.load(std::memory_order_acquire) != 0) CalcSourceParams(&voice, ctx, force); }; std::for_each(voices.begin(), voices.end(), calc_params); -- cgit v1.2.3 From 7a9463f8637de3196e630264deaedc77e414a1e8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Sep 2019 14:46:41 -0700 Subject: Make the common code a separate static library --- CMakeLists.txt | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b8501740..bcd03cca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1234,6 +1234,12 @@ CONFIGURE_FILE( @ONLY) +ADD_LIBRARY(common STATIC EXCLUDE_FROM_ALL ${COMMON_OBJS}) +TARGET_COMPILE_OPTIONS(common PRIVATE ${C_FLAGS}) +TARGET_INCLUDE_DIRECTORIES(common PRIVATE ${OpenAL_BINARY_DIR}) +SET_TARGET_PROPERTIES(common PROPERTIES POSITION_INDEPENDENT_CODE TRUE) + + UNSET(HAS_ROUTER) SET(IMPL_TARGET OpenAL) # Either OpenAL or soft_oal. SET(SUBSYS_FLAG ) @@ -1244,9 +1250,9 @@ IF(LIBTYPE STREQUAL "STATIC") IF(WIN32 AND ALSOFT_NO_UID_DEFS) SET(CPP_DEFS ${CPP_DEFS} AL_NO_UID_DEFS) ENDIF() - ADD_LIBRARY(OpenAL STATIC ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS}) + ADD_LIBRARY(${IMPL_TARGET} STATIC ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS}) + TARGET_LINK_LIBRARIES(${IMPL_TARGET} PRIVATE ${LINKER_FLAGS} ${EXTRA_LIBS} ${MATH_LIB}) ELSE() - IF(WIN32) IF(MSVC) SET(SUBSYS_FLAG ${SUBSYS_FLAG} "/SUBSYSTEM:WINDOWS") @@ -1263,12 +1269,11 @@ ELSE() router/router.h router/alc.cpp router/al.cpp - ${COMMON_OBJS} ) TARGET_COMPILE_DEFINITIONS(OpenAL PRIVATE AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES ${CPP_DEFS}) TARGET_COMPILE_OPTIONS(OpenAL PRIVATE ${C_FLAGS}) - TARGET_LINK_LIBRARIES(OpenAL PRIVATE ${LINKER_FLAGS}) + TARGET_LINK_LIBRARIES(OpenAL PRIVATE common ${LINKER_FLAGS}) TARGET_INCLUDE_DIRECTORIES(OpenAL PUBLIC $ @@ -1289,15 +1294,13 @@ ELSE() SET(RC_CONFIG resources/soft_oal.rc) ENDIF() - ADD_LIBRARY(${IMPL_TARGET} SHARED ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS} ${RC_CONFIG}) + ADD_LIBRARY(${IMPL_TARGET} SHARED ${OPENAL_OBJS} ${ALC_OBJS} ${RC_CONFIG}) IF(WIN32) SET_TARGET_PROPERTIES(${IMPL_TARGET} PROPERTIES PREFIX "") ENDIF() + TARGET_LINK_LIBRARIES(${IMPL_TARGET} PRIVATE common ${LINKER_FLAGS} ${EXTRA_LIBS} ${MATH_LIB}) ENDIF() -TARGET_LINK_LIBRARIES(${IMPL_TARGET} - PRIVATE ${LINKER_FLAGS} ${EXTRA_LIBS} ${MATH_LIB}) - TARGET_INCLUDE_DIRECTORIES(${IMPL_TARGET} PUBLIC $ -- cgit v1.2.3 From 6d93b2ba81958eb277da4361924e89bc7048da41 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Sep 2019 14:55:52 -0700 Subject: Use our case-insensitive compare functions in makemhr --- CMakeLists.txt | 2 +- utils/makemhr/loaddef.cpp | 39 ++++++++++++++++++++------------------- utils/makemhr/makemhr.cpp | 3 ++- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bcd03cca..32cb017e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1470,7 +1470,7 @@ IF(ALSOFT_UTILS) target_include_directories(makemhr PRIVATE ${OpenAL_SOURCE_DIR}/common ${OpenAL_BINARY_DIR}) target_compile_options(makemhr PRIVATE ${C_FLAGS}) - target_link_libraries(makemhr PRIVATE ${LINKER_FLAGS} MySOFA::MySOFA) + target_link_libraries(makemhr PRIVATE common ${LINKER_FLAGS} MySOFA::MySOFA) set(UTIL_TARGETS ${UTIL_TARGETS} makemhr) set(SOFAINFO_SRCS utils/sofa-info.cpp) diff --git a/utils/makemhr/loaddef.cpp b/utils/makemhr/loaddef.cpp index aaefd62c..bc62b725 100644 --- a/utils/makemhr/loaddef.cpp +++ b/utils/makemhr/loaddef.cpp @@ -21,6 +21,8 @@ * Or visit: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ +#include "loaddef.h" + #include #include #include @@ -28,8 +30,7 @@ #include "mysofa.h" -#include "loaddef.h" - +#include "alstring.h" // Constants for accessing the token reader's ring buffer. #define TR_RING_BITS (16) @@ -1197,9 +1198,9 @@ static int LoadSource(SourceRefT *src, const uint hrirRate, const uint n, double // Match the channel type from a given identifier. static ChannelTypeT MatchChannelType(const char *ident) { - if(strcasecmp(ident, "mono") == 0) + if(al::strcasecmp(ident, "mono") == 0) return CT_MONO; - if(strcasecmp(ident, "stereo") == 0) + if(al::strcasecmp(ident, "stereo") == 0) return CT_STEREO; return CT_NONE; } @@ -1226,7 +1227,7 @@ static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint trunc TrIndication(tr, &line, &col); if(!TrReadIdent(tr, MAX_IDENT_LEN, ident)) return 0; - if(strcasecmp(ident, "rate") == 0) + if(al::strcasecmp(ident, "rate") == 0) { if(hasRate) { @@ -1240,7 +1241,7 @@ static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint trunc hData->mIrRate = static_cast(intVal); hasRate = 1; } - else if(strcasecmp(ident, "type") == 0) + else if(al::strcasecmp(ident, "type") == 0) { char type[MAX_IDENT_LEN+1]; @@ -1267,7 +1268,7 @@ static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint trunc } hasType = 1; } - else if(strcasecmp(ident, "points") == 0) + else if(al::strcasecmp(ident, "points") == 0) { if(hasPoints) { @@ -1297,7 +1298,7 @@ static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint trunc hData->mIrSize = points; hasPoints = 1; } - else if(strcasecmp(ident, "radius") == 0) + else if(al::strcasecmp(ident, "radius") == 0) { if(hasRadius) { @@ -1311,7 +1312,7 @@ static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint trunc hData->mRadius = fpVal; hasRadius = 1; } - else if(strcasecmp(ident, "distance") == 0) + else if(al::strcasecmp(ident, "distance") == 0) { uint count = 0; @@ -1350,7 +1351,7 @@ static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint trunc fdCount = count; hasDistance = 1; } - else if(strcasecmp(ident, "azimuths") == 0) + else if(al::strcasecmp(ident, "azimuths") == 0) { uint count = 0; @@ -1468,15 +1469,15 @@ static int ReadIndexTriplet(TokenReaderT *tr, const HrirDataT *hData, uint *fi, // Match the source format from a given identifier. static SourceFormatT MatchSourceFormat(const char *ident) { - if(strcasecmp(ident, "ascii") == 0) + if(al::strcasecmp(ident, "ascii") == 0) return SF_ASCII; - if(strcasecmp(ident, "bin_le") == 0) + if(al::strcasecmp(ident, "bin_le") == 0) return SF_BIN_LE; - if(strcasecmp(ident, "bin_be") == 0) + if(al::strcasecmp(ident, "bin_be") == 0) return SF_BIN_BE; - if(strcasecmp(ident, "wave") == 0) + if(al::strcasecmp(ident, "wave") == 0) return SF_WAVE; - if(strcasecmp(ident, "sofa") == 0) + if(al::strcasecmp(ident, "sofa") == 0) return SF_SOFA; return SF_NONE; } @@ -1484,9 +1485,9 @@ static SourceFormatT MatchSourceFormat(const char *ident) // Match the source element type from a given identifier. static ElementTypeT MatchElementType(const char *ident) { - if(strcasecmp(ident, "int") == 0) + if(al::strcasecmp(ident, "int") == 0) return ET_INT; - if(strcasecmp(ident, "fp") == 0) + if(al::strcasecmp(ident, "fp") == 0) return ET_FP; return ET_NONE; } @@ -1680,9 +1681,9 @@ static int ReadSofaRef(TokenReaderT *tr, SourceRefT *src) // Match the target ear (index) from a given identifier. static int MatchTargetEar(const char *ident) { - if(strcasecmp(ident, "left") == 0) + if(al::strcasecmp(ident, "left") == 0) return 0; - if(strcasecmp(ident, "right") == 0) + if(al::strcasecmp(ident, "right") == 0) return 1; return -1; } diff --git a/utils/makemhr/makemhr.cpp b/utils/makemhr/makemhr.cpp index 5930e582..8071ac18 100644 --- a/utils/makemhr/makemhr.cpp +++ b/utils/makemhr/makemhr.cpp @@ -87,6 +87,7 @@ #include "../getopt.h" #endif +#include "alstring.h" #include "loaddef.h" #include "loadsofa.h" @@ -178,7 +179,7 @@ static int StrSubst(const char *in, const char *pat, const char *rep, const size { if(patLen <= inLen-si) { - if(strncasecmp(&in[si], pat, patLen) == 0) + if(al::strncasecmp(&in[si], pat, patLen) == 0) { if(repLen > maxLen-di) { -- cgit v1.2.3 From 899a414591559633f2641a74325dffc5e54562c7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Sep 2019 15:10:36 -0700 Subject: Remove the last uses of the system's str[n]casecmp --- CMakeLists.txt | 20 -------------------- al/effect.cpp | 5 +++-- alc/alconfig.cpp | 13 +++++++------ alc/alu.cpp | 7 +++++-- alc/helpers.cpp | 3 ++- alc/mixvoice.cpp | 15 ++++++++------- alc/panning.cpp | 21 +++++++++++---------- 7 files changed, 36 insertions(+), 48 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 32cb017e..c1bc09cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -473,26 +473,6 @@ CHECK_SYMBOL_EXISTS(_aligned_malloc malloc.h HAVE__ALIGNED_MALLOC) CHECK_SYMBOL_EXISTS(proc_pidpath libproc.h HAVE_PROC_PIDPATH) CHECK_FUNCTION_EXISTS(stat HAVE_STAT) -CHECK_FUNCTION_EXISTS(strcasecmp HAVE_STRCASECMP) -IF(NOT HAVE_STRCASECMP) - CHECK_FUNCTION_EXISTS(_stricmp HAVE__STRICMP) - IF(NOT HAVE__STRICMP) - MESSAGE(FATAL_ERROR "No case-insensitive compare function found, please report!") - ENDIF() - - SET(CPP_DEFS ${CPP_DEFS} strcasecmp=_stricmp) -ENDIF() - -CHECK_FUNCTION_EXISTS(strncasecmp HAVE_STRNCASECMP) -IF(NOT HAVE_STRNCASECMP) - CHECK_FUNCTION_EXISTS(_strnicmp HAVE__STRNICMP) - IF(NOT HAVE__STRNICMP) - MESSAGE(FATAL_ERROR "No case-insensitive size-limitted compare function found, please report!") - ENDIF() - - SET(CPP_DEFS ${CPP_DEFS} strncasecmp=_strnicmp) -ENDIF() - IF(NOT WIN32) # We need pthreads outside of Windows, for semaphores. It's also used to diff --git a/al/effect.cpp b/al/effect.cpp index 2ad4c26e..f7d17f50 100644 --- a/al/effect.cpp +++ b/al/effect.cpp @@ -43,6 +43,7 @@ #include "alexcpt.h" #include "almalloc.h" #include "alnumeric.h" +#include "alstring.h" #include "effects/base.h" #include "logging.h" #include "opthelpers.h" @@ -668,7 +669,7 @@ static const struct { void LoadReverbPreset(const char *name, ALeffect *effect) { - if(strcasecmp(name, "NONE") == 0) + if(al::strcasecmp(name, "NONE") == 0) { InitEffectParams(effect, AL_EFFECT_NULL); TRACE("Loading reverb '%s'\n", "NONE"); @@ -685,7 +686,7 @@ void LoadReverbPreset(const char *name, ALeffect *effect) { const EFXEAXREVERBPROPERTIES *props; - if(strcasecmp(name, reverbitem.name) != 0) + if(al::strcasecmp(name, reverbitem.name) != 0) continue; TRACE("Loading reverb '%s'\n", reverbitem.name); diff --git a/alc/alconfig.cpp b/alc/alconfig.cpp index 666c2c2d..b266fe5b 100644 --- a/alc/alconfig.cpp +++ b/alc/alconfig.cpp @@ -46,6 +46,7 @@ #include #include "alcmain.h" +#include "alstring.h" #include "logging.h" #include "strutils.h" #include "compat.h" @@ -169,7 +170,7 @@ void LoadConfigFromFile(std::istream &f) *endsection = 0; curSection.clear(); - if(strcasecmp(section, "general") != 0) + if(al::strcasecmp(section, "general") != 0) { do { char *nextp = std::strchr(section, '%'); @@ -447,7 +448,7 @@ const char *GetConfigValue(const char *devName, const char *blockName, const cha return def; std::string key; - if(blockName && strcasecmp(blockName, "general") != 0) + if(blockName && al::strcasecmp(blockName, "general") != 0) { key = blockName; if(devName) @@ -532,8 +533,8 @@ al::optional ConfigValueBool(const char *devName, const char *blockName, c if(!val[0]) return al::nullopt; return al::make_optional( - strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || - strcasecmp(val, "on") == 0 || atoi(val) != 0); + al::strcasecmp(val, "true") == 0 || al::strcasecmp(val, "yes") == 0 || + al::strcasecmp(val, "on") == 0 || atoi(val) != 0); } int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def) @@ -541,6 +542,6 @@ int GetConfigValueBool(const char *devName, const char *blockName, const char *k const char *val = GetConfigValue(devName, blockName, keyName, ""); if(!val[0]) return def != 0; - return (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || - strcasecmp(val, "on") == 0 || atoi(val) != 0); + return (al::strcasecmp(val, "true") == 0 || al::strcasecmp(val, "yes") == 0 || + al::strcasecmp(val, "on") == 0 || atoi(val) != 0); } diff --git a/alc/alu.cpp b/alc/alu.cpp index 32c52526..b0405822 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -55,6 +55,7 @@ #include "almalloc.h" #include "alnumeric.h" #include "alspan.h" +#include "alstring.h" #include "ambidefs.h" #include "atomic.h" #include "bformatdec.h" @@ -90,7 +91,8 @@ ALfloat InitConeScale() ALfloat ret{1.0f}; if(auto optval = al::getenv("__ALSOFT_HALF_ANGLE_CONES")) { - if(strcasecmp(optval->c_str(), "true") == 0 || strtol(optval->c_str(), nullptr, 0) == 1) + if(al::strcasecmp(optval->c_str(), "true") == 0 + || strtol(optval->c_str(), nullptr, 0) == 1) ret *= 0.5f; } return ret; @@ -101,7 +103,8 @@ ALfloat InitZScale() ALfloat ret{1.0f}; if(auto optval = al::getenv("__ALSOFT_REVERSE_Z")) { - if(strcasecmp(optval->c_str(), "true") == 0 || strtol(optval->c_str(), nullptr, 0) == 1) + if(al::strcasecmp(optval->c_str(), "true") == 0 + || strtol(optval->c_str(), nullptr, 0) == 1) ret *= -1.0f; } return ret; diff --git a/alc/helpers.cpp b/alc/helpers.cpp index 77f96fb8..1d19d004 100644 --- a/alc/helpers.cpp +++ b/alc/helpers.cpp @@ -70,6 +70,7 @@ #include "alcmain.h" #include "almalloc.h" +#include "alstring.h" #include "compat.h" #include "cpu_caps.h" #include "fpu_modes.h" @@ -662,7 +663,7 @@ static void DirectorySearch(const char *path, const char *ext, al::vectord_name)}; if(len <= extlen) continue; - if(strcasecmp(dirent->d_name+len-extlen, ext) != 0) + if(al::strcasecmp(dirent->d_name+len-extlen, ext) != 0) continue; results->emplace_back(); diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 3d4d9cb8..34fe9275 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -48,6 +48,7 @@ #include "alnumeric.h" #include "aloptional.h" #include "alspan.h" +#include "alstring.h" #include "alu.h" #include "cpu_caps.h" #include "devformat.h" @@ -174,22 +175,22 @@ void aluInitMixer() if(auto resopt = ConfigValueStr(nullptr, nullptr, "resampler")) { const char *str{resopt->c_str()}; - if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0) + if(al::strcasecmp(str, "point") == 0 || al::strcasecmp(str, "none") == 0) ResamplerDefault = PointResampler; - else if(strcasecmp(str, "linear") == 0) + else if(al::strcasecmp(str, "linear") == 0) ResamplerDefault = LinearResampler; - else if(strcasecmp(str, "cubic") == 0) + else if(al::strcasecmp(str, "cubic") == 0) ResamplerDefault = FIR4Resampler; - else if(strcasecmp(str, "bsinc12") == 0) + else if(al::strcasecmp(str, "bsinc12") == 0) ResamplerDefault = BSinc12Resampler; - else if(strcasecmp(str, "bsinc24") == 0) + else if(al::strcasecmp(str, "bsinc24") == 0) ResamplerDefault = BSinc24Resampler; - else if(strcasecmp(str, "bsinc") == 0) + else if(al::strcasecmp(str, "bsinc") == 0) { WARN("Resampler option \"%s\" is deprecated, using bsinc12\n", str); ResamplerDefault = BSinc12Resampler; } - else if(strcasecmp(str, "sinc4") == 0 || strcasecmp(str, "sinc8") == 0) + else if(al::strcasecmp(str, "sinc4") == 0 || al::strcasecmp(str, "sinc8") == 0) { WARN("Resampler option \"%s\" is deprecated, using cubic\n", str); ResamplerDefault = FIR4Resampler; diff --git a/alc/panning.cpp b/alc/panning.cpp index 7fb1d9ff..7e2408da 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -44,6 +44,7 @@ #include "alnumeric.h" #include "aloptional.h" #include "alspan.h" +#include "alstring.h" #include "alu.h" #include "ambdec.h" #include "ambidefs.h" @@ -586,25 +587,25 @@ void InitHrtfPanning(ALCdevice *device) if(auto modeopt = ConfigValueStr(device->DeviceName.c_str(), nullptr, "hrtf-mode")) { const char *mode{modeopt->c_str()}; - if(strcasecmp(mode, "basic") == 0) + if(al::strcasecmp(mode, "basic") == 0) { ERR("HRTF mode \"%s\" deprecated, substituting \"%s\"\n", mode, "ambi2"); mode = "ambi2"; } - if(strcasecmp(mode, "full") == 0) + if(al::strcasecmp(mode, "full") == 0) device->mRenderMode = HrtfRender; - else if(strcasecmp(mode, "ambi1") == 0) + else if(al::strcasecmp(mode, "ambi1") == 0) { device->mRenderMode = NormalRender; ambi_order = 1; } - else if(strcasecmp(mode, "ambi2") == 0) + else if(al::strcasecmp(mode, "ambi2") == 0) { device->mRenderMode = NormalRender; ambi_order = 2; } - else if(strcasecmp(mode, "ambi3") == 0) + else if(al::strcasecmp(mode, "ambi3") == 0) { device->mRenderMode = NormalRender; ambi_order = 3; @@ -732,11 +733,11 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr if(auto modeopt = ConfigValueStr(device->DeviceName.c_str(), nullptr, "stereo-mode")) { const char *mode{modeopt->c_str()}; - if(strcasecmp(mode, "headphones") == 0) + if(al::strcasecmp(mode, "headphones") == 0) headphones = true; - else if(strcasecmp(mode, "speakers") == 0) + else if(al::strcasecmp(mode, "speakers") == 0) headphones = false; - else if(strcasecmp(mode, "auto") != 0) + else if(al::strcasecmp(mode, "auto") != 0) ERR("Unexpected stereo-mode: %s\n", mode); } } @@ -835,9 +836,9 @@ no_hrtf: if(auto encopt = ConfigValueStr(device->DeviceName.c_str(), nullptr, "stereo-encoding")) { const char *mode{encopt->c_str()}; - if(strcasecmp(mode, "uhj") == 0) + if(al::strcasecmp(mode, "uhj") == 0) device->mRenderMode = NormalRender; - else if(strcasecmp(mode, "panpot") != 0) + else if(al::strcasecmp(mode, "panpot") != 0) ERR("Unexpected stereo-encoding: %s\n", mode); } if(device->mRenderMode == NormalRender) -- cgit v1.2.3 From b00128411fc63885e0250afc6562a703553e8c32 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Sep 2019 15:45:20 -0700 Subject: Add a missing include directory for the common lib --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c1bc09cb..6114de20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1216,7 +1216,7 @@ CONFIGURE_FILE( ADD_LIBRARY(common STATIC EXCLUDE_FROM_ALL ${COMMON_OBJS}) TARGET_COMPILE_OPTIONS(common PRIVATE ${C_FLAGS}) -TARGET_INCLUDE_DIRECTORIES(common PRIVATE ${OpenAL_BINARY_DIR}) +TARGET_INCLUDE_DIRECTORIES(common PRIVATE ${OpenAL_BINARY_DIR} ${OpenAL_SOURCE_DIR}/include) SET_TARGET_PROPERTIES(common PROPERTIES POSITION_INDEPENDENT_CODE TRUE) -- cgit v1.2.3 From 6398bd83739a3cb3ae38078f4221c5ab28057824 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Sep 2019 15:57:05 -0700 Subject: Add preprocessor defines for the common lib --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6114de20..d467287a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1215,8 +1215,9 @@ CONFIGURE_FILE( ADD_LIBRARY(common STATIC EXCLUDE_FROM_ALL ${COMMON_OBJS}) -TARGET_COMPILE_OPTIONS(common PRIVATE ${C_FLAGS}) TARGET_INCLUDE_DIRECTORIES(common PRIVATE ${OpenAL_BINARY_DIR} ${OpenAL_SOURCE_DIR}/include) +TARGET_COMPILE_DEFINITIONS(common PRIVATE ${CPP_DEFS}) +TARGET_COMPILE_OPTIONS(common PRIVATE ${C_FLAGS}) SET_TARGET_PROPERTIES(common PROPERTIES POSITION_INDEPENDENT_CODE TRUE) -- cgit v1.2.3 From 62972babea90f8f0444d4dbaaabe9e017cc0abfb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Sep 2019 18:10:01 -0700 Subject: Remove unnecessary long long checks --- CMakeLists.txt | 8 -------- config.h.in | 3 --- 2 files changed, 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d467287a..d054cb84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,7 +114,6 @@ SET(EXPORT_DECL "") CHECK_TYPE_SIZE("long" SIZEOF_LONG) -CHECK_TYPE_SIZE("long long" SIZEOF_LONG_LONG) # Require C++11 @@ -553,13 +552,6 @@ ENDIF() CHECK_SYMBOL_EXISTS(getopt unistd.h HAVE_GETOPT) -# Check for a 64-bit type -IF(NOT SIZEOF_LONG MATCHES "8") - IF(NOT SIZEOF_LONG_LONG MATCHES "8") - MESSAGE(FATAL_ERROR "No 64-bit type found, please report!") - ENDIF() -ENDIF() - # Common sources used by both the OpenAL implementation library and potentially # the OpenAL router. diff --git a/config.h.in b/config.h.in index 9305e2a9..4a1e2b00 100644 --- a/config.h.in +++ b/config.h.in @@ -80,9 +80,6 @@ /* Define to the size of a long int type */ #cmakedefine SIZEOF_LONG ${SIZEOF_LONG} -/* Define to the size of a long long int type */ -#cmakedefine SIZEOF_LONG_LONG ${SIZEOF_LONG_LONG} - /* Define if we have GCC's format attribute */ #cmakedefine HAVE_GCC_FORMAT -- cgit v1.2.3 From 1da75126283cbd0f7ed3835a34c6e34e8dcfc32a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Sep 2019 21:49:06 -0700 Subject: Avoid an unnecessary multiply --- alc/alu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alc/alu.cpp b/alc/alu.cpp index b0405822..606d8fdb 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -400,8 +400,8 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context) inline float ScaleAzimuthFront(float azimuth, float scale) { const ALfloat abs_azi{std::fabs(azimuth)}; - if(!(abs_azi > al::MathDefs::Pi()*0.5f)) - return minf(abs_azi*scale, al::MathDefs::Pi()*0.5f) * std::copysign(1.0f, azimuth); + if(!(abs_azi >= al::MathDefs::Pi()*0.5f)) + return std::copysign(minf(abs_azi*scale, al::MathDefs::Pi()*0.5f), azimuth); return azimuth; } -- cgit v1.2.3 From aca9f4e09586f4b1859bb28c5712f39c1b95570e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 Sep 2019 18:38:46 -0700 Subject: Make the bsinc l and m coefficients unsigned --- alc/alu.h | 4 ++-- alc/mixer/mixer_c.cpp | 12 ++++++------ alc/mixer/mixer_neon.cpp | 11 ++++------- alc/mixer/mixer_sse.cpp | 6 ++---- native-tools/bsincgen.c | 21 +++++++++++---------- 5 files changed, 25 insertions(+), 29 deletions(-) diff --git a/alc/alu.h b/alc/alu.h index cf021285..33c67630 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -67,8 +67,8 @@ extern Resampler ResamplerDefault; */ struct BsincState { ALfloat sf; /* Scale interpolation factor. */ - ALsizei m; /* Coefficient count. */ - ALsizei l; /* Left coefficient offset. */ + ALuint m; /* Coefficient count. */ + ALuint l; /* Left coefficient offset. */ /* Filter coefficients, followed by the scale, phase, and scale-phase * delta coefficients. Starting at phase index 0, each subsequent phase * index follows contiguously. diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index 6e96e54e..42d515ae 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -21,7 +21,7 @@ inline ALfloat do_cubic(const InterpState&, const ALfloat *RESTRICT vals, const { return cubic(vals[0], vals[1], vals[2], vals[3], static_cast(frac)*(1.0f/FRACTIONONE)); } inline ALfloat do_bsinc(const InterpState &istate, const ALfloat *RESTRICT vals, const ALuint frac) { - ASSUME(istate.bsinc.m > 0); + const size_t m{istate.bsinc.m}; // Calculate the phase index and factor. #define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) @@ -30,14 +30,14 @@ inline ALfloat do_bsinc(const InterpState &istate, const ALfloat *RESTRICT vals, (1.0f/(1<(pi*4)}; - const ALfloat *scd{fil + istate.bsinc.m}; - const ALfloat *phd{scd + istate.bsinc.m}; - const ALfloat *spd{phd + istate.bsinc.m}; + const ALfloat *fil{istate.bsinc.filter + m*pi*4}; + const ALfloat *scd{fil + m}; + const ALfloat *phd{scd + m}; + const ALfloat *spd{phd + m}; // Apply the scale and phase interpolated filter. ALfloat r{0.0f}; - for(ALsizei j_f{0};j_f < istate.bsinc.m;j_f++) + for(size_t j_f{0};j_f < m;j_f++) r += (fil[j_f] + istate.bsinc.sf*scd[j_f] + pf*(phd[j_f] + istate.bsinc.sf*spd[j_f])) * vals[j_f]; return r; } diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index 8a98f5de..cd2b0ebc 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -74,9 +74,7 @@ const ALfloat *Resample_(const InterpState *state, const ALflo { const ALfloat *const filter{state->bsinc.filter}; const float32x4_t sf4{vdupq_n_f32(state->bsinc.sf)}; - const ptrdiff_t m{state->bsinc.m}; - - ASSUME(m > 0); + const size_t m{state->bsinc.m}; src -= state->bsinc.l; for(float &out_sample : dst) @@ -92,11 +90,11 @@ const ALfloat *Resample_(const InterpState *state, const ALflo float32x4_t r4{vdupq_n_f32(0.0f)}; { const float32x4_t pf4{vdupq_n_f32(pf)}; - const float *fil{filter + m*static_cast(pi*4)}; + const float *fil{filter + m*pi*4}; const float *scd{fil + m}; const float *phd{scd + m}; const float *spd{phd + m}; - ptrdiff_t td{m >> 2}; + size_t td{m >> 2}; size_t j{0u}; do { @@ -110,8 +108,7 @@ const ALfloat *Resample_(const InterpState *state, const ALflo j += 4; } while(--td); } - r4 = vaddq_f32(r4, vcombine_f32(vrev64_f32(vget_high_f32(r4)), - vrev64_f32(vget_low_f32(r4)))); + r4 = vaddq_f32(r4, vrev64q_f32(r4)); out_sample = vget_lane_f32(vadd_f32(vget_low_f32(r4), vget_high_f32(r4)), 0); frac += increment; diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index d47a0e66..9bb3bb8a 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -19,9 +19,7 @@ const ALfloat *Resample_(const InterpState *state, const ALfloa { const ALfloat *const filter{state->bsinc.filter}; const __m128 sf4{_mm_set1_ps(state->bsinc.sf)}; - const ptrdiff_t m{state->bsinc.m}; - - ASSUME(m > 0); + const size_t m{state->bsinc.m}; src -= state->bsinc.l; for(float &out_sample : dst) @@ -41,7 +39,7 @@ const ALfloat *Resample_(const InterpState *state, const ALfloa const float *scd{fil + m}; const float *phd{scd + m}; const float *spd{phd + m}; - ptrdiff_t td{m >> 2}; + size_t td{m >> 2}; size_t j{0u}; #define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z)) diff --git a/native-tools/bsincgen.c b/native-tools/bsincgen.c index 89f9f378..802403fd 100644 --- a/native-tools/bsincgen.c +++ b/native-tools/bsincgen.c @@ -278,13 +278,13 @@ static void BsiGenerateTables(FILE *output, const char *tabname, const double re fprintf(output, "\n "); for(i = 0; i < m; i++) fprintf(output, " %+14.9ef,", filter[si][pi][o + i]); - fprintf(output, "\n "); + fprintf(output, "\n "); for(i = 0; i < m; i++) fprintf(output, " %+14.9ef,", scDeltas[si][pi][o + i]); - fprintf(output, "\n "); + fprintf(output, "\n "); for(i = 0; i < m; i++) fprintf(output, " %+14.9ef,", phDeltas[si][pi][o + i]); - fprintf(output, "\n "); + fprintf(output, "\n "); for(i = 0; i < m; i++) fprintf(output, " %+14.9ef,", spDeltas[si][pi][o + i]); fprintf(output, "\n"); @@ -300,17 +300,17 @@ static void BsiGenerateTables(FILE *output, const char *tabname, const double re fprintf(output, " /* scaleBase */ %.9ef, /* scaleRange */ %.9ef,\n", scaleBase, 1.0 / scaleRange); fprintf(output, " /* m */ {"); - fprintf(output, " %d", mt[0]); + fprintf(output, " %du", mt[0]); for(si = 1; si < BSINC_SCALE_COUNT; si++) - fprintf(output, ", %d", mt[si]); + fprintf(output, ", %du", mt[si]); fprintf(output, " },\n"); fprintf(output, " /* filterOffset */ {"); - fprintf(output, " %d", 0); + fprintf(output, " %du", 0); i = mt[0]*4*BSINC_PHASE_COUNT; for(si = 1; si < BSINC_SCALE_COUNT; si++) { - fprintf(output, ", %d", i); + fprintf(output, ", %du", i); i += mt[si]*4*BSINC_PHASE_COUNT; } @@ -344,14 +344,15 @@ int main(int argc, char *argv[]) else output = stdout; - fprintf(output, "/* Generated by bsincgen, do not edit! */\n\n" + fprintf(output, "/* Generated by bsincgen, do not edit! */\n" +"#pragma once\n\n" "static_assert(BSINC_SCALE_COUNT == %d, \"Unexpected BSINC_SCALE_COUNT value!\");\n" "static_assert(BSINC_PHASE_COUNT == %d, \"Unexpected BSINC_PHASE_COUNT value!\");\n" "static_assert(FRACTIONONE == %d, \"Unexpected FRACTIONONE value!\");\n\n" "struct BSincTable {\n" " const float scaleBase, scaleRange;\n" -" const int m[BSINC_SCALE_COUNT];\n" -" const int filterOffset[BSINC_SCALE_COUNT];\n" +" const unsigned int m[BSINC_SCALE_COUNT];\n" +" const unsigned int filterOffset[BSINC_SCALE_COUNT];\n" " const float *Tab;\n" "};\n\n", BSINC_SCALE_COUNT, BSINC_PHASE_COUNT, FRACTIONONE); /* A 23rd order filter with a -60dB drop at nyquist. */ -- cgit v1.2.3 From dffb874478643ae79a8236ae2ae8b08a36830d7a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Sep 2019 08:58:36 -0700 Subject: Some cleanup for CMakeLists.txt --- CMakeLists.txt | 217 +++++++++++++++++++++++---------------------------------- 1 file changed, 87 insertions(+), 130 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d054cb84..80ce4422 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,8 +21,22 @@ IF(COMMAND CMAKE_POLICY) ENDIF(POLICY CMP0075) ENDIF(COMMAND CMAKE_POLICY) +SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS TRUE) + +IF(NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING + "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." + FORCE) +ENDIF() +IF(NOT CMAKE_DEBUG_POSTFIX) + SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING + "Library postfix for debug builds. Normally left blank." + FORCE) +ENDIF() + SET(CMAKE_MODULE_PATH "${OpenAL_SOURCE_DIR}/cmake") + INCLUDE(CheckFunctionExists) INCLUDE(CheckLibraryExists) INCLUDE(CheckIncludeFile) @@ -37,8 +51,6 @@ include(CheckStructHasMember) include(CheckFileOffsetBits) include(GNUInstallDirs) -SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS TRUE) - OPTION(ALSOFT_DLOPEN "Check for the dlopen API for loading optional libs" ON) @@ -65,7 +77,7 @@ if(DEFINED LIB_SUFFIX) endif() -SET(CPP_DEFS ) # C pre-process, not C++ +SET(CPP_DEFS ) # C pre-processor, not C++ SET(INC_PATHS ) SET(C_FLAGS ) SET(LINKER_FLAGS ) @@ -154,21 +166,18 @@ ENDIF() # C99 has restrict, but C++ does not, so we can only utilize __restrict. SET(RESTRICT_DECL ) -CHECK_C_SOURCE_COMPILES("int *__restrict foo; - int main() {return 0;}" HAVE___RESTRICT) +CHECK_CXX_SOURCE_COMPILES("int *__restrict foo; +int main() { return 0; }" HAVE___RESTRICT) IF(HAVE___RESTRICT) SET(RESTRICT_DECL "__restrict") ENDIF() -# Some systems may need libatomic for C11 atomic functions to work +# Some systems may need libatomic for atomic functions to work SET(OLD_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) SET(CMAKE_REQUIRED_LIBRARIES ${OLD_REQUIRED_LIBRARIES} atomic) -CHECK_C_SOURCE_COMPILES("#include -int _Atomic foo = ATOMIC_VAR_INIT(0); -int main() -{ - return atomic_fetch_add(&foo, 2); -}" +CHECK_CXX_SOURCE_COMPILES("#include +std::atomic foo{0}; +int main() { return foo.fetch_add(2); }" HAVE_LIBATOMIC) IF(NOT HAVE_LIBATOMIC) SET(CMAKE_REQUIRED_LIBRARIES "${OLD_REQUIRED_LIBRARIES}") @@ -184,17 +193,6 @@ IF(HAVE_LIBLOG) SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} log) ENDIF() -IF(NOT CMAKE_BUILD_TYPE) - SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING - "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." - FORCE) -ENDIF() -IF(NOT CMAKE_DEBUG_POSTFIX) - SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING - "Library postfix for debug builds. Normally left blank." - FORCE) -ENDIF() - IF(MSVC) SET(CPP_DEFS ${CPP_DEFS} _CRT_SECURE_NO_WARNINGS NOMINMAX) SET(C_FLAGS ${C_FLAGS} /wd4065 /wd4200) @@ -243,14 +241,7 @@ ELSE() if(ALSOFT_STATIC_LIBGCC) set(OLD_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} -static-libgcc) - check_c_source_compiles( -"#include -int main() -{ - return 0; -}" - HAVE_STATIC_LIBGCC_SWITCH - ) + check_cxx_source_compiles("int main() { }" HAVE_STATIC_LIBGCC_SWITCH) set(CMAKE_REQUIRED_LIBRARIES ${OLD_REQUIRED_LIBRARIES}) unset(OLD_REQUIRED_LIBRARIES) @@ -264,14 +255,7 @@ int main() if(ALSOFT_STATIC_STDCXX) set(OLD_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} "-Wl,--push-state,-Bstatic,-lstdc++,--pop-state") - check_cxx_source_compiles( -"#include -int main() -{ - return 0; -}" - HAVE_STATIC_LIBSTDCXX_SWITCH - ) + check_cxx_source_compiles("int main() { }" HAVE_STATIC_LIBSTDCXX_SWITCH) set(CMAKE_REQUIRED_LIBRARIES ${OLD_REQUIRED_LIBRARIES}) unset(OLD_REQUIRED_LIBRARIES) @@ -286,14 +270,7 @@ int main() if(ALSOFT_STATIC_WINPTHREAD) set(OLD_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} "-Wl,--push-state,-Bstatic,-lwinpthread,--pop-state") - check_cxx_source_compiles( -"#include -int main() -{ - return 0; -}" - HAVE_STATIC_LIBWINPTHREAD_SWITCH - ) + check_cxx_source_compiles("int main() { }" HAVE_STATIC_LIBWINPTHREAD_SWITCH) set(CMAKE_REQUIRED_LIBRARIES ${OLD_REQUIRED_LIBRARIES}) unset(OLD_REQUIRED_LIBRARIES) @@ -425,13 +402,12 @@ ENDIF() # Check for the dlopen API (for dynamicly loading backend libs) IF(ALSOFT_DLOPEN) + CHECK_INCLUDE_FILE(dlfcn.h HAVE_DLFCN_H) CHECK_LIBRARY_EXISTS(dl dlopen "" HAVE_LIBDL) IF(HAVE_LIBDL) SET(EXTRA_LIBS dl ${EXTRA_LIBS}) SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} dl) ENDIF() - - CHECK_INCLUDE_FILE(dlfcn.h HAVE_DLFCN_H) ENDIF() # Check for a cpuid intrinsic @@ -991,8 +967,8 @@ ENDIF() # Check CoreAudio backend OPTION(ALSOFT_REQUIRE_COREAUDIO "Require CoreAudio backend" OFF) FIND_LIBRARY(COREAUDIO_FRAMEWORK - NAMES CoreAudio - PATHS /System/Library/Frameworks + NAMES CoreAudio + PATHS /System/Library/Frameworks ) IF(COREAUDIO_FRAMEWORK) OPTION(ALSOFT_BACKEND_COREAUDIO "Enable CoreAudio backend" ON) @@ -1007,11 +983,12 @@ IF(COREAUDIO_FRAMEWORK) # Some versions of OSX may need the AudioToolbox framework. Add it if # it's found. FIND_LIBRARY(AUDIOTOOLBOX_LIBRARY - NAMES AudioToolbox - PATHS ~/Library/Frameworks - /Library/Frameworks - /System/Library/Frameworks - ) + NAMES AudioToolbox + PATHS + ~/Library/Frameworks + /Library/Frameworks + /System/Library/Frameworks + ) IF(AUDIOTOOLBOX_LIBRARY) SET(EXTRA_LIBS ${AUDIOTOOLBOX_LIBRARY} ${EXTRA_LIBS}) ENDIF() @@ -1072,12 +1049,9 @@ FIND_PACKAGE(Git) IF(GIT_FOUND AND EXISTS "${OpenAL_SOURCE_DIR}/.git") # Get the current working branch and its latest abbreviated commit hash ADD_CUSTOM_TARGET(build_version - ${CMAKE_COMMAND} -D GIT_EXECUTABLE=${GIT_EXECUTABLE} - -D LIB_VERSION=${LIB_VERSION} - -D LIB_VERSION_NUM=${LIB_VERSION_NUM} - -D SRC=${OpenAL_SOURCE_DIR}/version.h.in - -D DST=${OpenAL_BINARY_DIR}/version.h - -P ${OpenAL_SOURCE_DIR}/version.cmake + ${CMAKE_COMMAND} -D GIT_EXECUTABLE=${GIT_EXECUTABLE} -D LIB_VERSION=${LIB_VERSION} + -D LIB_VERSION_NUM=${LIB_VERSION_NUM} -D SRC=${OpenAL_SOURCE_DIR}/version.h.in + -D DST=${OpenAL_BINARY_DIR}/version.h -P ${OpenAL_SOURCE_DIR}/version.cmake WORKING_DIRECTORY "${OpenAL_SOURCE_DIR}" VERBATIM ) @@ -1119,8 +1093,9 @@ ELSE() COMMAND ${CMAKE_COMMAND} --build . --config "Release" WORKING_DIRECTORY "${NATIVE_BIN_DIR}" DEPENDS "${NATIVE_SRC_DIR}/CMakeLists.txt" - IMPLICIT_DEPENDS C "${NATIVE_SRC_DIR}/bin2h.c" - C "${NATIVE_SRC_DIR}/bsincgen.c" + IMPLICIT_DEPENDS + C "${NATIVE_SRC_DIR}/bin2h.c" + C "${NATIVE_SRC_DIR}/bsincgen.c" VERBATIM ) ENDIF() @@ -1310,8 +1285,8 @@ IF(WIN32 AND MINGW AND ALSOFT_BUILD_IMPORT_LIB AND NOT LIBTYPE STREQUAL "STATIC" MESSAGE(STATUS "WARNING: Cannot find dlltool, disabling .def/.lib generation") ENDIF() ELSE() - SET_PROPERTY(TARGET OpenAL APPEND_STRING PROPERTY LINK_FLAGS - " -Wl,--output-def,OpenAL32.def") + SET_PROPERTY(TARGET OpenAL APPEND_STRING PROPERTY + LINK_FLAGS " -Wl,--output-def,OpenAL32.def") ADD_CUSTOM_COMMAND(TARGET OpenAL POST_BUILD COMMAND "${SED_EXECUTABLE}" -i -e "s/ @[^ ]*//" OpenAL32.def COMMAND "${DLLTOOL_EXECUTABLE}" -d OpenAL32.def -l OpenAL32.lib -D OpenAL32.dll @@ -1323,32 +1298,30 @@ ENDIF() IF(ALSOFT_INSTALL) INSTALL(TARGETS OpenAL EXPORT OpenAL - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ${CMAKE_INSTALL_INCLUDEDIR}/AL - ) + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ${CMAKE_INSTALL_INCLUDEDIR}/AL) EXPORT(TARGETS OpenAL - NAMESPACE OpenAL:: - FILE OpenALConfig.cmake) + NAMESPACE OpenAL:: + FILE OpenALConfig.cmake) INSTALL(EXPORT OpenAL - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/OpenAL - NAMESPACE OpenAL:: - FILE OpenALConfig.cmake) - INSTALL(FILES include/AL/al.h - include/AL/alc.h - include/AL/alext.h - include/AL/efx.h - include/AL/efx-creative.h - include/AL/efx-presets.h - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/AL - ) + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/OpenAL + NAMESPACE OpenAL:: + FILE OpenALConfig.cmake) + INSTALL(FILES + include/AL/al.h + include/AL/alc.h + include/AL/alext.h + include/AL/efx.h + include/AL/efx-creative.h + include/AL/efx-presets.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/AL) INSTALL(FILES "${OpenAL_BINARY_DIR}/openal.pc" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") IF(TARGET soft_oal) INSTALL(TARGETS soft_oal - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - ) + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) ENDIF() ENDIF() @@ -1370,14 +1343,6 @@ IF(FPMATH_SET) MESSAGE(STATUS "") ENDIF() -IF(WIN32) - IF(NOT HAVE_DSOUND) - MESSAGE(STATUS "WARNING: Building the Windows version without DirectSound output") - MESSAGE(STATUS " This is probably NOT what you want!") - MESSAGE(STATUS "") - ENDIF() -ENDIF() - if(ALSOFT_EMBED_HRTF_DATA) message(STATUS "Embedding HRTF datasets") message(STATUS "") @@ -1386,33 +1351,30 @@ endif() # Install alsoft.conf configuration file IF(ALSOFT_CONFIG) INSTALL(FILES alsoftrc.sample - DESTINATION ${CMAKE_INSTALL_DATADIR}/openal - ) + DESTINATION ${CMAKE_INSTALL_DATADIR}/openal) MESSAGE(STATUS "Installing sample configuration") MESSAGE(STATUS "") ENDIF() # Install HRTF definitions IF(ALSOFT_HRTF_DEFS) - INSTALL(FILES hrtf/default-44100.mhr - hrtf/default-48000.mhr - DESTINATION ${CMAKE_INSTALL_DATADIR}/openal/hrtf - ) + INSTALL(FILES hrtf/default-44100.mhr hrtf/default-48000.mhr + DESTINATION ${CMAKE_INSTALL_DATADIR}/openal/hrtf) MESSAGE(STATUS "Installing HRTF definitions") MESSAGE(STATUS "") ENDIF() # Install AmbDec presets IF(ALSOFT_AMBDEC_PRESETS) - INSTALL(FILES presets/3D7.1.ambdec - presets/hexagon.ambdec - presets/itu5.1.ambdec - presets/itu5.1-nocenter.ambdec - presets/rectangle.ambdec - presets/square.ambdec - presets/presets.txt - DESTINATION ${CMAKE_INSTALL_DATADIR}/openal/presets - ) + INSTALL(FILES + presets/3D7.1.ambdec + presets/hexagon.ambdec + presets/itu5.1.ambdec + presets/itu5.1-nocenter.ambdec + presets/rectangle.ambdec + presets/square.ambdec + presets/presets.txt + DESTINATION ${CMAKE_INSTALL_DATADIR}/openal/presets) MESSAGE(STATUS "Installing AmbDec presets") MESSAGE(STATUS "") ENDIF() @@ -1456,10 +1418,9 @@ IF(ALSOFT_UTILS) IF(ALSOFT_INSTALL) INSTALL(TARGETS ${UTIL_TARGETS} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - ) + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) ENDIF() MESSAGE(STATUS "Building utility programs") @@ -1487,10 +1448,9 @@ IF(ALSOFT_TESTS) IF(ALSOFT_INSTALL) INSTALL(TARGETS altonegen - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - ) + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) ENDIF() MESSAGE(STATUS "Building test programs") @@ -1503,10 +1463,9 @@ IF(ALSOFT_EXAMPLES) IF(ALSOFT_INSTALL) INSTALL(TARGETS alrecord - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - ) + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) ENDIF() MESSAGE(STATUS "Building example programs") @@ -1558,10 +1517,9 @@ IF(ALSOFT_EXAMPLES) IF(ALSOFT_INSTALL) INSTALL(TARGETS alplay alstream alreverb almultireverb allatency alloopback alhrtf - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - ) + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) ENDIF() MESSAGE(STATUS "Building SDL_sound example programs") @@ -1600,10 +1558,9 @@ IF(ALSOFT_EXAMPLES) IF(ALSOFT_INSTALL) INSTALL(TARGETS alffplay - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - ) + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) ENDIF() MESSAGE(STATUS "Building SDL+FFmpeg example programs") ENDIF() -- cgit v1.2.3 From ab87e56b22a49e04ca614d71e8a848b0658327af Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Sep 2019 09:01:46 -0700 Subject: Enable some more MSVC warnings --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 80ce4422..8da3d93c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,7 +195,11 @@ ENDIF() IF(MSVC) SET(CPP_DEFS ${CPP_DEFS} _CRT_SECURE_NO_WARNINGS NOMINMAX) - SET(C_FLAGS ${C_FLAGS} /wd4065 /wd4200) + CHECK_CXX_COMPILER_FLAG(/permissive- HAVE_PERMISSIVE_SWITCH) + IF(HAVE_PERMISSIVE_SWITCH) + SET(C_FLAGS ${C_FLAGS} $<$:/permissive->) + ENDIF() + SET(C_FLAGS ${C_FLAGS} /W4 /w14640 /wd4065 /wd4200) IF(NOT DXSDK_DIR) STRING(REGEX REPLACE "\\\\" "/" DXSDK_DIR "$ENV{DXSDK_DIR}") -- cgit v1.2.3 From da80a7c2b2e4a66856bec4d7b44c7a7df05a31a5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Sep 2019 09:31:32 -0700 Subject: Disable warnings 4268 and 4324 on MSVC warning C4268: 'const' static/global data initialized with compiler generated default constructor fills the object with zeros warning C4324: structure was padded due to alignment specifier --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8da3d93c..3ef1ca6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -199,7 +199,7 @@ IF(MSVC) IF(HAVE_PERMISSIVE_SWITCH) SET(C_FLAGS ${C_FLAGS} $<$:/permissive->) ENDIF() - SET(C_FLAGS ${C_FLAGS} /W4 /w14640 /wd4065 /wd4200) + SET(C_FLAGS ${C_FLAGS} /W4 /w14640 /wd4065 /wd4200 /wd4268 /wd4324) IF(NOT DXSDK_DIR) STRING(REGEX REPLACE "\\\\" "/" DXSDK_DIR "$ENV{DXSDK_DIR}") -- cgit v1.2.3 From 66565ca7a3cd63e242eedb0141341eb9450f0d4a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Sep 2019 10:09:04 -0700 Subject: Enable and fix some more warnings --- CMakeLists.txt | 1 + al/auxeffectslot.cpp | 3 +- al/error.cpp | 3 +- alc/alc.cpp | 33 ++++++++++++---------- alc/hrtf.cpp | 4 +-- common/threads.cpp | 2 +- examples/alhrtf.c | 6 ++-- examples/allatency.c | 26 ++++++++--------- examples/alloopback.c | 8 +++--- examples/almultireverb.c | 72 ++++++++++++++++++++++++------------------------ examples/alreverb.c | 48 ++++++++++++++++---------------- utils/openal-info.c | 4 +-- 12 files changed, 108 insertions(+), 102 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ef1ca6b..4f6cf010 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -222,6 +222,7 @@ IF(MSVC) ENDIF() ELSE() SET(C_FLAGS ${C_FLAGS} -Winline -Wunused -Wall -Wextra -Wshadow -Wconversion -Wcast-align + -Wpedantic -Wno-zero-length-array $<$:-Wold-style-cast -Wnon-virtual-dtor -Woverloaded-virtual>) IF(ALSOFT_WERROR) diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index df35c533..3c312c66 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -709,7 +709,8 @@ ALeffectslot::~ALeffectslot() if(props) { if(props->State) props->State->release(); - TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props); + TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", + decltype(std::declval()){props}); delete props; } diff --git a/al/error.cpp b/al/error.cpp index f3e2dbb3..b667d14f 100644 --- a/al/error.cpp +++ b/al/error.cpp @@ -67,7 +67,8 @@ void ALCcontext::setError(ALenum errorCode, const char *msg, ...) else msg = ""; msglen = static_cast(strlen(msg)); - WARN("Error generated on context %p, code 0x%04x, \"%s\"\n", this, errorCode, msg); + WARN("Error generated on context %p, code 0x%04x, \"%s\"\n", + decltype(std::declval()){this}, errorCode, msg); if(TrapALError) { #ifdef _WIN32 diff --git a/alc/alc.cpp b/alc/alc.cpp index 8a0a3468..0652f858 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -845,8 +845,8 @@ std::atomic LastNullDeviceError{ALC_NO_ERROR}; void ReleaseThreadCtx(ALCcontext *context) { const bool result{context->releaseIfNoDelete()}; - ERR("Context %p current for thread being destroyed%s!\n", context, - result ? "" : ", leak detected"); + ERR("Context %p current for thread being destroyed%s!\n", + decltype(std::declval()){context}, result ? "" : ", leak detected"); } class ThreadCtx { @@ -1567,7 +1567,8 @@ void ALCcontext::processUpdates() */ static void alcSetError(ALCdevice *device, ALCenum errorCode) { - WARN("Error generated on device %p, code 0x%04x\n", device, errorCode); + WARN("Error generated on device %p, code 0x%04x\n", decltype(std::declval()){device}, + errorCode); if(TrapALCError) { #ifdef _WIN32 @@ -2256,7 +2257,7 @@ ALCdevice::ALCdevice(DeviceType type) : Type{type}, mContexts{&EmptyContextArray */ ALCdevice::~ALCdevice() { - TRACE("Freeing device %p\n", this); + TRACE("Freeing device %p\n", decltype(std::declval()){this}); Backend = nullptr; @@ -2311,15 +2312,15 @@ ALCcontext::ALCcontext(al::intrusive_ptr device) : mDevice{std::move( ALCcontext::~ALCcontext() { - TRACE("Freeing context %p\n", this); + TRACE("Freeing context %p\n", decltype(std::declval()){this}); + size_t count{0}; ALcontextProps *cprops{mUpdate.exchange(nullptr, std::memory_order_relaxed)}; if(cprops) { - TRACE("Freed unapplied context update %p\n", cprops); + ++count; delete cprops; } - size_t count{0}; cprops = mFreeContextProps.exchange(nullptr, std::memory_order_acquire); while(cprops) { @@ -2376,13 +2377,13 @@ ALCcontext::~ALCcontext() mVoices.clear(); + count = 0; ALlistenerProps *lprops{mListener.Params.Update.exchange(nullptr, std::memory_order_relaxed)}; if(lprops) { - TRACE("Freed unapplied listener update %p\n", lprops); + ++count; delete lprops; } - count = 0; lprops = mFreeListenerProps.exchange(nullptr, std::memory_order_acquire); while(lprops) { @@ -2462,7 +2463,7 @@ bool ALCcontext::deinit() { if(LocalContext.get() == this) { - WARN("%p released while current on thread\n", this); + WARN("%p released while current on thread\n", decltype(std::declval()){this}); LocalContext.set(nullptr); release(); } @@ -3356,7 +3357,7 @@ START_API_FUNC ERR("Failed to initialize the default effect\n"); } - TRACE("Created context %p\n", context.get()); + TRACE("Created context %p\n", decltype(std::declval()){context.get()}); return context.get(); } END_API_FUNC @@ -3700,7 +3701,8 @@ START_API_FUNC DeviceList.emplace(iter, device); } - TRACE("Created device %p, \"%s\"\n", device.get(), device->DeviceName.c_str()); + TRACE("Created device %p, \"%s\"\n", decltype(std::declval()){device.get()}, + device->DeviceName.c_str()); return device.get(); } END_API_FUNC @@ -3746,7 +3748,7 @@ START_API_FUNC for(ContextRef &context : orphanctxs) { - WARN("Releasing orphaned context %p\n", context.get()); + WARN("Releasing orphaned context %p\n", decltype(std::declval()){context.get()}); context->deinit(); } orphanctxs.clear(); @@ -3829,7 +3831,8 @@ START_API_FUNC DeviceList.emplace(iter, device); } - TRACE("Created device %p, \"%s\"\n", device.get(), device->DeviceName.c_str()); + TRACE("Created capture device %p, \"%s\"\n", decltype(std::declval()){device.get()}, + device->DeviceName.c_str()); return device.get(); } END_API_FUNC @@ -4011,7 +4014,7 @@ START_API_FUNC DeviceList.emplace(iter, device); } - TRACE("Created device %p\n", device.get()); + TRACE("Created loopback device %p\n", decltype(std::declval()){device.get()}); return device.get(); } END_API_FUNC diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index 7110478d..b925c5dd 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -1363,13 +1363,13 @@ HrtfEntry *GetLoadedHrtf(HrtfHandle *handle) void HrtfEntry::IncRef() { auto ref = IncrementRef(mRef); - TRACE("HrtfEntry %p increasing refcount to %u\n", this, ref); + TRACE("HrtfEntry %p increasing refcount to %u\n", decltype(std::declval()){this}, ref); } void HrtfEntry::DecRef() { auto ref = DecrementRef(mRef); - TRACE("HrtfEntry %p decreasing refcount to %u\n", this, ref); + TRACE("HrtfEntry %p decreasing refcount to %u\n", decltype(std::declval()){this}, ref); if(ref == 0) { std::lock_guard _{LoadedHrtfLock}; diff --git a/common/threads.cpp b/common/threads.cpp index fe34f5b0..ff01de42 100644 --- a/common/threads.cpp +++ b/common/threads.cpp @@ -43,7 +43,7 @@ void althrd_setname(const char *name) #pragma pack(pop) info.dwType = 0x1000; info.szName = name; - info.dwThreadID = -1; + info.dwThreadID = ~DWORD{0}; info.dwFlags = 0; __try { diff --git a/examples/alhrtf.c b/examples/alhrtf.c index f09f3e99..2be28a91 100644 --- a/examples/alhrtf.c +++ b/examples/alhrtf.c @@ -164,9 +164,9 @@ int main(int argc, char **argv) } /* Define a macro to help load the function pointers. */ -#define LOAD_PROC(d, x) ((x) = alcGetProcAddress((d), #x)) - LOAD_PROC(device, alcGetStringiSOFT); - LOAD_PROC(device, alcResetDeviceSOFT); +#define LOAD_PROC(d, T, x) ((x) = (T)alcGetProcAddress((d), #x)) + LOAD_PROC(device, LPALCGETSTRINGISOFT, alcGetStringiSOFT); + LOAD_PROC(device, LPALCRESETDEVICESOFT, alcResetDeviceSOFT); #undef LOAD_PROC /* Check for the AL_EXT_STEREO_ANGLES extension to be able to also rotate diff --git a/examples/allatency.c b/examples/allatency.c index ad700cc1..a61fb820 100644 --- a/examples/allatency.c +++ b/examples/allatency.c @@ -158,19 +158,19 @@ int main(int argc, char **argv) } /* Define a macro to help load the function pointers. */ -#define LOAD_PROC(x) ((x) = alGetProcAddress(#x)) - LOAD_PROC(alSourcedSOFT); - LOAD_PROC(alSource3dSOFT); - LOAD_PROC(alSourcedvSOFT); - LOAD_PROC(alGetSourcedSOFT); - LOAD_PROC(alGetSource3dSOFT); - LOAD_PROC(alGetSourcedvSOFT); - LOAD_PROC(alSourcei64SOFT); - LOAD_PROC(alSource3i64SOFT); - LOAD_PROC(alSourcei64vSOFT); - LOAD_PROC(alGetSourcei64SOFT); - LOAD_PROC(alGetSource3i64SOFT); - LOAD_PROC(alGetSourcei64vSOFT); +#define LOAD_PROC(T, x) ((x) = (T)alGetProcAddress(#x)) + LOAD_PROC(LPALSOURCEDSOFT, alSourcedSOFT); + LOAD_PROC(LPALSOURCE3DSOFT, alSource3dSOFT); + LOAD_PROC(LPALSOURCEDVSOFT, alSourcedvSOFT); + LOAD_PROC(LPALGETSOURCEDSOFT, alGetSourcedSOFT); + LOAD_PROC(LPALGETSOURCE3DSOFT, alGetSource3dSOFT); + LOAD_PROC(LPALGETSOURCEDVSOFT, alGetSourcedvSOFT); + LOAD_PROC(LPALSOURCEI64SOFT, alSourcei64SOFT); + LOAD_PROC(LPALSOURCE3I64SOFT, alSource3i64SOFT); + LOAD_PROC(LPALSOURCEI64VSOFT, alSourcei64vSOFT); + LOAD_PROC(LPALGETSOURCEI64SOFT, alGetSourcei64SOFT); + LOAD_PROC(LPALGETSOURCE3I64SOFT, alGetSource3i64SOFT); + LOAD_PROC(LPALGETSOURCEI64VSOFT, alGetSourcei64vSOFT); #undef LOAD_PROC /* Initialize SDL_sound. */ diff --git a/examples/alloopback.c b/examples/alloopback.c index 426a2af9..844efa74 100644 --- a/examples/alloopback.c +++ b/examples/alloopback.c @@ -149,10 +149,10 @@ int main(int argc, char *argv[]) } /* Define a macro to help load the function pointers. */ -#define LOAD_PROC(x) ((x) = alcGetProcAddress(NULL, #x)) - LOAD_PROC(alcLoopbackOpenDeviceSOFT); - LOAD_PROC(alcIsRenderFormatSupportedSOFT); - LOAD_PROC(alcRenderSamplesSOFT); +#define LOAD_PROC(T, x) ((x) = (T)alcGetProcAddress(NULL, #x)) + LOAD_PROC(LPALCLOOPBACKOPENDEVICESOFT, alcLoopbackOpenDeviceSOFT); + LOAD_PROC(LPALCISRENDERFORMATSUPPORTEDSOFT, alcIsRenderFormatSupportedSOFT); + LOAD_PROC(LPALCRENDERSAMPLESSOFT, alcRenderSamplesSOFT); #undef LOAD_PROC if(SDL_Init(SDL_INIT_AUDIO) == -1) diff --git a/examples/almultireverb.c b/examples/almultireverb.c index 4e3e188f..a90b3368 100644 --- a/examples/almultireverb.c +++ b/examples/almultireverb.c @@ -523,42 +523,42 @@ int main(int argc, char **argv) } /* Define a macro to help load the function pointers. */ -#define LOAD_PROC(x) ((x) = alGetProcAddress(#x)) - LOAD_PROC(alGenFilters); - LOAD_PROC(alDeleteFilters); - LOAD_PROC(alIsFilter); - LOAD_PROC(alFilteri); - LOAD_PROC(alFilteriv); - LOAD_PROC(alFilterf); - LOAD_PROC(alFilterfv); - LOAD_PROC(alGetFilteri); - LOAD_PROC(alGetFilteriv); - LOAD_PROC(alGetFilterf); - LOAD_PROC(alGetFilterfv); - - LOAD_PROC(alGenEffects); - LOAD_PROC(alDeleteEffects); - LOAD_PROC(alIsEffect); - LOAD_PROC(alEffecti); - LOAD_PROC(alEffectiv); - LOAD_PROC(alEffectf); - LOAD_PROC(alEffectfv); - LOAD_PROC(alGetEffecti); - LOAD_PROC(alGetEffectiv); - LOAD_PROC(alGetEffectf); - LOAD_PROC(alGetEffectfv); - - LOAD_PROC(alGenAuxiliaryEffectSlots); - LOAD_PROC(alDeleteAuxiliaryEffectSlots); - LOAD_PROC(alIsAuxiliaryEffectSlot); - LOAD_PROC(alAuxiliaryEffectSloti); - LOAD_PROC(alAuxiliaryEffectSlotiv); - LOAD_PROC(alAuxiliaryEffectSlotf); - LOAD_PROC(alAuxiliaryEffectSlotfv); - LOAD_PROC(alGetAuxiliaryEffectSloti); - LOAD_PROC(alGetAuxiliaryEffectSlotiv); - LOAD_PROC(alGetAuxiliaryEffectSlotf); - LOAD_PROC(alGetAuxiliaryEffectSlotfv); +#define LOAD_PROC(T, x) ((x) = (T)alGetProcAddress(#x)) + LOAD_PROC(LPALGENFILTERS, alGenFilters); + LOAD_PROC(LPALDELETEFILTERS, alDeleteFilters); + LOAD_PROC(LPALISFILTER, alIsFilter); + LOAD_PROC(LPALFILTERI, alFilteri); + LOAD_PROC(LPALFILTERIV, alFilteriv); + LOAD_PROC(LPALFILTERF, alFilterf); + LOAD_PROC(LPALFILTERFV, alFilterfv); + LOAD_PROC(LPALGETFILTERI, alGetFilteri); + LOAD_PROC(LPALGETFILTERIV, alGetFilteriv); + LOAD_PROC(LPALGETFILTERF, alGetFilterf); + LOAD_PROC(LPALGETFILTERFV, alGetFilterfv); + + LOAD_PROC(LPALGENEFFECTS, alGenEffects); + LOAD_PROC(LPALDELETEEFFECTS, alDeleteEffects); + LOAD_PROC(LPALISEFFECT, alIsEffect); + LOAD_PROC(LPALEFFECTI, alEffecti); + LOAD_PROC(LPALEFFECTIV, alEffectiv); + LOAD_PROC(LPALEFFECTF, alEffectf); + LOAD_PROC(LPALEFFECTFV, alEffectfv); + LOAD_PROC(LPALGETEFFECTI, alGetEffecti); + LOAD_PROC(LPALGETEFFECTIV, alGetEffectiv); + LOAD_PROC(LPALGETEFFECTF, alGetEffectf); + LOAD_PROC(LPALGETEFFECTFV, alGetEffectfv); + + LOAD_PROC(LPALGENAUXILIARYEFFECTSLOTS, alGenAuxiliaryEffectSlots); + LOAD_PROC(LPALDELETEAUXILIARYEFFECTSLOTS, alDeleteAuxiliaryEffectSlots); + LOAD_PROC(LPALISAUXILIARYEFFECTSLOT, alIsAuxiliaryEffectSlot); + LOAD_PROC(LPALAUXILIARYEFFECTSLOTI, alAuxiliaryEffectSloti); + LOAD_PROC(LPALAUXILIARYEFFECTSLOTIV, alAuxiliaryEffectSlotiv); + LOAD_PROC(LPALAUXILIARYEFFECTSLOTF, alAuxiliaryEffectSlotf); + LOAD_PROC(LPALAUXILIARYEFFECTSLOTFV, alAuxiliaryEffectSlotfv); + LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTI, alGetAuxiliaryEffectSloti); + LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTIV, alGetAuxiliaryEffectSlotiv); + LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTF, alGetAuxiliaryEffectSlotf); + LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTFV, alGetAuxiliaryEffectSlotfv); #undef LOAD_PROC /* Initialize SDL_sound. */ diff --git a/examples/alreverb.c b/examples/alreverb.c index 68f0269f..d789dffe 100644 --- a/examples/alreverb.c +++ b/examples/alreverb.c @@ -252,30 +252,30 @@ int main(int argc, char **argv) } /* Define a macro to help load the function pointers. */ -#define LOAD_PROC(x) ((x) = alGetProcAddress(#x)) - LOAD_PROC(alGenEffects); - LOAD_PROC(alDeleteEffects); - LOAD_PROC(alIsEffect); - LOAD_PROC(alEffecti); - LOAD_PROC(alEffectiv); - LOAD_PROC(alEffectf); - LOAD_PROC(alEffectfv); - LOAD_PROC(alGetEffecti); - LOAD_PROC(alGetEffectiv); - LOAD_PROC(alGetEffectf); - LOAD_PROC(alGetEffectfv); - - LOAD_PROC(alGenAuxiliaryEffectSlots); - LOAD_PROC(alDeleteAuxiliaryEffectSlots); - LOAD_PROC(alIsAuxiliaryEffectSlot); - LOAD_PROC(alAuxiliaryEffectSloti); - LOAD_PROC(alAuxiliaryEffectSlotiv); - LOAD_PROC(alAuxiliaryEffectSlotf); - LOAD_PROC(alAuxiliaryEffectSlotfv); - LOAD_PROC(alGetAuxiliaryEffectSloti); - LOAD_PROC(alGetAuxiliaryEffectSlotiv); - LOAD_PROC(alGetAuxiliaryEffectSlotf); - LOAD_PROC(alGetAuxiliaryEffectSlotfv); +#define LOAD_PROC(T, x) ((x) = (T)alGetProcAddress(#x)) + LOAD_PROC(LPALGENEFFECTS, alGenEffects); + LOAD_PROC(LPALDELETEEFFECTS, alDeleteEffects); + LOAD_PROC(LPALISEFFECT, alIsEffect); + LOAD_PROC(LPALEFFECTI, alEffecti); + LOAD_PROC(LPALEFFECTIV, alEffectiv); + LOAD_PROC(LPALEFFECTF, alEffectf); + LOAD_PROC(LPALEFFECTFV, alEffectfv); + LOAD_PROC(LPALGETEFFECTI, alGetEffecti); + LOAD_PROC(LPALGETEFFECTIV, alGetEffectiv); + LOAD_PROC(LPALGETEFFECTF, alGetEffectf); + LOAD_PROC(LPALGETEFFECTFV, alGetEffectfv); + + LOAD_PROC(LPALGENAUXILIARYEFFECTSLOTS, alGenAuxiliaryEffectSlots); + LOAD_PROC(LPALDELETEAUXILIARYEFFECTSLOTS, alDeleteAuxiliaryEffectSlots); + LOAD_PROC(LPALISAUXILIARYEFFECTSLOT, alIsAuxiliaryEffectSlot); + LOAD_PROC(LPALAUXILIARYEFFECTSLOTI, alAuxiliaryEffectSloti); + LOAD_PROC(LPALAUXILIARYEFFECTSLOTIV, alAuxiliaryEffectSlotiv); + LOAD_PROC(LPALAUXILIARYEFFECTSLOTF, alAuxiliaryEffectSlotf); + LOAD_PROC(LPALAUXILIARYEFFECTSLOTFV, alAuxiliaryEffectSlotfv); + LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTI, alGetAuxiliaryEffectSloti); + LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTIV, alGetAuxiliaryEffectSlotiv); + LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTF, alGetAuxiliaryEffectSlotf); + LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTFV, alGetAuxiliaryEffectSlotfv); #undef LOAD_PROC /* Initialize SDL_sound. */ diff --git a/utils/openal-info.c b/utils/openal-info.c index 76cdf37d..cdce77e0 100644 --- a/utils/openal-info.c +++ b/utils/openal-info.c @@ -223,7 +223,7 @@ static void printHRTFInfo(ALCdevice *device) return; } - alcGetStringiSOFT = alcGetProcAddress(device, "alcGetStringiSOFT"); + alcGetStringiSOFT = (LPALCGETSTRINGISOFT)alcGetProcAddress(device, "alcGetStringiSOFT"); alcGetIntegerv(device, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtfs); if(!num_hrtfs) @@ -263,7 +263,7 @@ static void printResamplerInfo(void) return; } - alGetStringiSOFT = alGetProcAddress("alGetStringiSOFT"); + alGetStringiSOFT = (LPALGETSTRINGISOFT)alGetProcAddress("alGetStringiSOFT"); num_resamplers = alGetInteger(AL_NUM_RESAMPLERS_SOFT); def_resampler = alGetInteger(AL_DEFAULT_RESAMPLER_SOFT); -- cgit v1.2.3 From b8f64155e9b5e2a048f4f055af235a210bcdedc7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Sep 2019 12:16:08 -0700 Subject: Silence a couple specific warning instances --- CMakeLists.txt | 2 +- common/almalloc.h | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f6cf010..515cbddc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -222,7 +222,7 @@ IF(MSVC) ENDIF() ELSE() SET(C_FLAGS ${C_FLAGS} -Winline -Wunused -Wall -Wextra -Wshadow -Wconversion -Wcast-align - -Wpedantic -Wno-zero-length-array + -Wpedantic $<$:-Wold-style-cast -Wnon-virtual-dtor -Woverloaded-virtual>) IF(ALSOFT_WERROR) diff --git a/common/almalloc.h b/common/almalloc.h index d144ca35..fd8d4be7 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -11,6 +11,23 @@ #include +#ifdef _MSC_VER +#define DIAGNOSTIC_PUSH _Pragma("warning(push)") +#define GNUDIAGNOSTIC(x) +#define MVSDIAGNOSTIC(x) _Pragma(x) +#define DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif defined(__GNUC__) || defined(__clang__) +#define DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") +#define GNUDIAGNOSTIC(x) _Pragma(x) +#define MVSDIAGNOSTIC(x) +#define DIAGNOSTIC_POP _Pragma("GCC diagnostic push") +#else +#define DIAGNOSTIC_PUSH +#define GNUDIAGNOSTIC(x) +#define MVSDIAGNOSTIC(x) +#define DIAGNOSTIC_POP +#endif + void *al_malloc(size_t alignment, size_t size); void *al_calloc(size_t alignment, size_t size); void al_free(void *ptr) noexcept; @@ -92,8 +109,14 @@ inline T* assume_aligned(T *ptr) noexcept #endif } +/* At least VS 2015 complains that 'ptr' is unused when the given type's + * destructor is trivial (a no-op). So disable that warning for this call. + */ +DIAGNOSTIC_PUSH +MVSDIAGNOSTIC("warning(disable : 4100)") template inline void destroy_at(T *ptr) { ptr->~T(); } +DIAGNOSTIC_POP template inline void destroy(T first, const T end) @@ -233,7 +256,11 @@ struct FlexArray { const index_type mSize; +DIAGNOSTIC_PUSH +GNUDIAGNOSTIC("GCC diagnostic ignored \"-Wpedantic\"") +MVSDIAGNOSTIC("warning(disable : 4200)") alignas(alignment) element_type mArray[0]; +DIAGNOSTIC_POP static std::unique_ptr Create(index_type count) { -- cgit v1.2.3 From 24a10589522f07e3ff152777a986ad0fb72f2935 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Sep 2019 13:58:04 -0700 Subject: Work around MSVC's lack of standard _Pragma support --- CMakeLists.txt | 2 +- common/almalloc.h | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 515cbddc..4b00194e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -199,7 +199,7 @@ IF(MSVC) IF(HAVE_PERMISSIVE_SWITCH) SET(C_FLAGS ${C_FLAGS} $<$:/permissive->) ENDIF() - SET(C_FLAGS ${C_FLAGS} /W4 /w14640 /wd4065 /wd4200 /wd4268 /wd4324) + SET(C_FLAGS ${C_FLAGS} /W4 /w14640 /wd4065 /wd4268 /wd4324) IF(NOT DXSDK_DIR) STRING(REGEX REPLACE "\\\\" "/" DXSDK_DIR "$ENV{DXSDK_DIR}") diff --git a/common/almalloc.h b/common/almalloc.h index fd8d4be7..e021337b 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -12,19 +12,19 @@ #ifdef _MSC_VER -#define DIAGNOSTIC_PUSH _Pragma("warning(push)") +#define DIAGNOSTIC_PUSH __pragma(warning(push)) #define GNUDIAGNOSTIC(x) -#define MVSDIAGNOSTIC(x) _Pragma(x) -#define DIAGNOSTIC_POP _Pragma("warning(pop)") +#define MVSDIAGNOSTIC(...) __pragma(__VA_ARGS__) +#define DIAGNOSTIC_POP __pragma(warning(pop)) #elif defined(__GNUC__) || defined(__clang__) #define DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") #define GNUDIAGNOSTIC(x) _Pragma(x) -#define MVSDIAGNOSTIC(x) +#define MVSDIAGNOSTIC(...) #define DIAGNOSTIC_POP _Pragma("GCC diagnostic push") #else #define DIAGNOSTIC_PUSH #define GNUDIAGNOSTIC(x) -#define MVSDIAGNOSTIC(x) +#define MVSDIAGNOSTIC(...) #define DIAGNOSTIC_POP #endif @@ -113,7 +113,7 @@ inline T* assume_aligned(T *ptr) noexcept * destructor is trivial (a no-op). So disable that warning for this call. */ DIAGNOSTIC_PUSH -MVSDIAGNOSTIC("warning(disable : 4100)") +MVSDIAGNOSTIC(warning(disable : 4100)) template inline void destroy_at(T *ptr) { ptr->~T(); } DIAGNOSTIC_POP @@ -258,7 +258,7 @@ struct FlexArray { const index_type mSize; DIAGNOSTIC_PUSH GNUDIAGNOSTIC("GCC diagnostic ignored \"-Wpedantic\"") -MVSDIAGNOSTIC("warning(disable : 4200)") +MVSDIAGNOSTIC(warning(disable : 4200)) alignas(alignment) element_type mArray[0]; DIAGNOSTIC_POP -- cgit v1.2.3 From 9a0a5c79d89d6056879124a7a9e68cffc5757a65 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Sep 2019 17:02:33 -0700 Subject: Avoid hiding a class member function --- alc/hrtf.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index b925c5dd..c1dc840b 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -159,10 +159,10 @@ class databuf final : public std::streambuf { } public: - databuf(const char_type *start, const char_type *end) noexcept + databuf(const char_type *start_, const char_type *end_) noexcept { - setg(const_cast(start), const_cast(start), - const_cast(end)); + setg(const_cast(start_), const_cast(start_), + const_cast(end_)); } }; @@ -170,8 +170,8 @@ class idstream final : public std::istream { databuf mStreamBuf; public: - idstream(const char *start, const char *end) - : std::istream{nullptr}, mStreamBuf{start, end} + idstream(const char *start_, const char *end_) + : std::istream{nullptr}, mStreamBuf{start_, end_} { init(&mStreamBuf); } }; -- cgit v1.2.3 From a092624ed3028cdea9b84403ca286c4415d4d57c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Sep 2019 18:20:11 -0700 Subject: Fix some Windows warnings --- alc/backends/dsound.cpp | 6 +++--- alc/backends/wasapi.cpp | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index c581fe8f..c7014e33 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -828,9 +828,9 @@ ALCuint DSoundCapture::availableSamples() DWORD BufferBytes{mBufferBytes}; DWORD LastCursor{mCursor}; - DWORD ReadCursor; - void *ReadPtr1, *ReadPtr2; - DWORD ReadCnt1, ReadCnt2; + DWORD ReadCursor{}; + void *ReadPtr1{}, *ReadPtr2{}; + DWORD ReadCnt1{}, ReadCnt2{}; HRESULT hr{mDSCbuffer->GetCurrentPosition(nullptr, &ReadCursor)}; if(SUCCEEDED(hr)) { diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 0dec5cb9..1271eeaa 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -402,7 +402,7 @@ void TraceFormat(const char *msg, const WAVEFORMATEX *format) } -enum class MsgType : unsigned int { +enum class MsgType { OpenDevice, ResetDevice, StartDevice, @@ -415,7 +415,7 @@ enum class MsgType : unsigned int { Count }; -constexpr char MessageStr[static_cast(MsgType::Count)][20]{ +constexpr char MessageStr[static_cast(MsgType::Count)][20]{ "Open Device", "Reset Device", "Start Device", @@ -522,8 +522,8 @@ int WasapiProxy::messageHandler(std::promise *promise) while(popMessage(msg)) { TRACE("Got message \"%s\" (0x%04x, this=%p)\n", - MessageStr[static_cast(msg.mType)], static_cast(msg.mType), - msg.mProxy); + MessageStr[static_cast(msg.mType)], static_cast(msg.mType), + decltype(std::declval()){msg.mProxy}); switch(msg.mType) { @@ -1042,8 +1042,8 @@ HRESULT WasapiPlayback::resetProxy() return hr; } - UINT32 buffer_len, min_len; - REFERENCE_TIME min_per; + UINT32 buffer_len{}, min_len{}; + REFERENCE_TIME min_per{}; hr = mClient->GetDevicePeriod(&min_per, nullptr); if(SUCCEEDED(hr)) hr = mClient->GetBufferSize(&buffer_len); @@ -1414,7 +1414,7 @@ HRESULT WasapiCapture::resetProxy() REFERENCE_TIME buf_time{mDevice->BufferSize * REFTIME_PER_SEC / mDevice->Frequency}; buf_time = maxu64(buf_time, REFTIME_PER_SEC/10); - WAVEFORMATEXTENSIBLE OutputType; + WAVEFORMATEXTENSIBLE OutputType{}; OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; switch(mDevice->FmtChans) { @@ -1589,8 +1589,8 @@ HRESULT WasapiCapture::resetProxy() return hr; } - UINT32 buffer_len; - REFERENCE_TIME min_per; + UINT32 buffer_len{}; + REFERENCE_TIME min_per{}; hr = mClient->GetDevicePeriod(&min_per, nullptr); if(SUCCEEDED(hr)) hr = mClient->GetBufferSize(&buffer_len); -- cgit v1.2.3 From ffb5623ead779bde507a9fda7603cb6fc6b4aa2b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Sep 2019 20:13:58 -0700 Subject: Fix a couple more annoying conversion warnings --- alc/hrtf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index c1dc840b..ebdee46a 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -512,7 +512,7 @@ std::unique_ptr CreateHrtfStore(ALuint rate, ALushort irSize, const A elev_[i].azCount = azCount[i]; elev_[i].irOffset = irOffset[i]; } - for(ALuint i{0};i < irSize*irCount;i++) + for(ALuint i{0};i < ALuint{irSize}*irCount;i++) { coeffs_[i][0] = coeffs[i][0]; coeffs_[i][1] = coeffs[i][1]; @@ -739,7 +739,7 @@ std::unique_ptr LoadHrtf01(std::istream &data, const char *filename) for(size_t i{1};i < evCount;i++) { evOffset[i] = static_cast(evOffset[i-1] + azCount[i-1]); - irCount += azCount[i]; + irCount = static_cast(irCount + azCount[i]); } auto coeffs = al::vector>(irSize*irCount); -- cgit v1.2.3 From c0678816fc9d3cf60ce35c0b608371c261691727 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Sep 2019 18:50:45 -0700 Subject: Remove deprecated CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS --- CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b00194e..81eb25bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,8 +21,6 @@ IF(COMMAND CMAKE_POLICY) ENDIF(POLICY CMP0075) ENDIF(COMMAND CMAKE_POLICY) -SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS TRUE) - IF(NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." -- cgit v1.2.3 From 057b253adba81430e51ce07951eda7dda03f7a08 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Sep 2019 21:01:10 -0700 Subject: Use an anonymous namespace instead of static --- alc/mixvoice.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 34fe9275..1d18a3a5 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -76,10 +76,13 @@ Resampler ResamplerDefault = LinearResampler; MixerFunc MixSamples = Mix_; RowMixerFunc MixRowSamples = MixRow_; -static HrtfMixerFunc MixHrtfSamples = MixHrtf_; -static HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_; -static MixerFunc SelectMixer() +namespace { + +HrtfMixerFunc MixHrtfSamples = MixHrtf_; +HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_; + +inline MixerFunc SelectMixer() { #ifdef HAVE_NEON if((CPUCapFlags&CPU_CAP_NEON)) @@ -92,7 +95,7 @@ static MixerFunc SelectMixer() return Mix_; } -static RowMixerFunc SelectRowMixer() +inline RowMixerFunc SelectRowMixer() { #ifdef HAVE_NEON if((CPUCapFlags&CPU_CAP_NEON)) @@ -105,7 +108,7 @@ static RowMixerFunc SelectRowMixer() return MixRow_; } -static inline HrtfMixerFunc SelectHrtfMixer() +inline HrtfMixerFunc SelectHrtfMixer() { #ifdef HAVE_NEON if((CPUCapFlags&CPU_CAP_NEON)) @@ -118,7 +121,7 @@ static inline HrtfMixerFunc SelectHrtfMixer() return MixHrtf_; } -static inline HrtfMixerBlendFunc SelectHrtfBlendMixer() +inline HrtfMixerBlendFunc SelectHrtfBlendMixer() { #ifdef HAVE_NEON if((CPUCapFlags&CPU_CAP_NEON)) @@ -131,6 +134,9 @@ static inline HrtfMixerBlendFunc SelectHrtfBlendMixer() return MixHrtfBlend_; } +} // namespace + + ResamplerFunc SelectResampler(Resampler resampler) { switch(resampler) -- cgit v1.2.3 From b9daffe1590b12b103f9706dfb0a440b629f3c49 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 20 Sep 2019 10:58:29 -0700 Subject: Don't clean up more than necessary on destruction --- common/aloptional.h | 4 ++-- common/intrusive_ptr.h | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/common/aloptional.h b/common/aloptional.h index 79827482..269cba0e 100644 --- a/common/aloptional.h +++ b/common/aloptional.h @@ -9,7 +9,7 @@ namespace al { -#define REQUIRES(...) bool _rt=true, typename std::enable_if<_rt && (__VA_ARGS__),int>::type = 0 +#define REQUIRES(...) bool rt_=true, typename std::enable_if::type = true struct nullopt_t { }; struct in_place_t { }; @@ -61,7 +61,7 @@ public: !std::is_constructible::value)> constexpr optional(U&& value) : mHasValue{true}, mValue{std::forward(value)} { } - ~optional() { reset(); } + ~optional() { if(mHasValue) al::destroy_at(std::addressof(mValue)); } optional& operator=(nullopt_t) noexcept { reset(); return *this; } template::value && std::is_copy_assignable::value)> diff --git a/common/intrusive_ptr.h b/common/intrusive_ptr.h index fa76ad48..595c831d 100644 --- a/common/intrusive_ptr.h +++ b/common/intrusive_ptr.h @@ -56,7 +56,7 @@ public: { rhs.mPtr = nullptr; } intrusive_ptr(std::nullptr_t) noexcept { } explicit intrusive_ptr(T *ptr) noexcept : mPtr{ptr} { } - ~intrusive_ptr() { reset(); } + ~intrusive_ptr() { if(mPtr) mPtr->release(); } intrusive_ptr& operator=(const intrusive_ptr &rhs) noexcept { @@ -66,7 +66,13 @@ public: return *this; } intrusive_ptr& operator=(intrusive_ptr&& rhs) noexcept - { std::swap(mPtr, rhs.mPtr); return *this; } + { + if(mPtr) + mPtr->release(); + mPtr = rhs.mPtr; + rhs.mPtr = nullptr; + return *this; + } operator bool() const noexcept { return mPtr != nullptr; } -- cgit v1.2.3 From 79a621ac47e01ad886bc7b4284e514d736650e6d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 20 Sep 2019 10:59:12 -0700 Subject: Simplify some REQUIRES uses --- common/albyte.h | 2 +- common/alspan.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/common/albyte.h b/common/albyte.h index 798d136d..23864636 100644 --- a/common/albyte.h +++ b/common/albyte.h @@ -13,7 +13,7 @@ namespace al { */ enum class byte : unsigned char { }; -#define REQUIRES(...) typename std::enable_if<(__VA_ARGS__),int>::type = 0 +#define REQUIRES(...) typename std::enable_if<(__VA_ARGS__),bool>::type = true template::value)> inline constexpr T to_integer(al::byte b) noexcept { return T(b); } diff --git a/common/alspan.h b/common/alspan.h index 4fe0f111..2e0fb027 100644 --- a/common/alspan.h +++ b/common/alspan.h @@ -74,7 +74,7 @@ namespace detail_ { : std::true_type { }; } // namespace detail_ -#define REQUIRES(...) typename std::enable_if<(__VA_ARGS__),int>::type = 0 +#define REQUIRES(...) bool rt_=true, typename std::enable_if::type = true #define USABLE_CONTAINER_DATA(...) \ std::is_convertible()))>::type(*)[],element_type(*)[]>::value #define IS_VALID_CONTAINER(C) \ @@ -104,13 +104,13 @@ public: static constexpr size_t extent{E}; - template + template constexpr span() noexcept { } constexpr span(pointer ptr, index_type /*count*/) : mData{ptr} { } constexpr span(pointer first, pointer /*last*/) : mData{first} { } constexpr span(element_type (&arr)[E]) noexcept : span{al::data(arr), al::size(arr)} { } constexpr span(std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } - template::value, REQUIRES(is_const)> + template::value)> constexpr span(const std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } template constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { } @@ -204,7 +204,7 @@ public: constexpr span(element_type (&arr)[N]) noexcept : span{al::data(arr), al::size(arr)} { } template constexpr span(std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } - template::value, REQUIRES(is_const)> + template::value)> constexpr span(const std::array &arr) noexcept : span{al::data(arr), al::size(arr)} { } template constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { } -- cgit v1.2.3 From 65eb0987e2f08655575f4d835e178b483901a053 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 20 Sep 2019 13:35:29 -0700 Subject: Remove and simplify some functions --- alc/effects/reverb.cpp | 14 ++++++++------ common/math_defs.h | 10 ++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 82a80198..4a85f640 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -844,6 +844,8 @@ void ReverbState::updateDelayLine(const ALfloat earlyDelay, const ALfloat lateDe */ alu::Matrix GetTransformFromVector(const ALfloat *vec) { + constexpr float sqrt_3{1.73205080756887719318f}; + /* Normalize the panning vector according to the N3D scale, which has an * extra sqrt(3) term on the directional components. Converting from OpenAL * to B-Format also requires negating X (ACN 1) and Z (ACN 3). Note however @@ -855,9 +857,9 @@ alu::Matrix GetTransformFromVector(const ALfloat *vec) ALfloat mag{std::sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2])}; if(mag > 1.0f) { - norm[0] = vec[0] / mag * -al::MathDefs::Sqrt3(); - norm[1] = vec[1] / mag * al::MathDefs::Sqrt3(); - norm[2] = vec[2] / mag * al::MathDefs::Sqrt3(); + norm[0] = vec[0] / mag * -sqrt_3; + norm[1] = vec[1] / mag * sqrt_3; + norm[2] = vec[2] / mag * sqrt_3; mag = 1.0f; } else @@ -866,9 +868,9 @@ alu::Matrix GetTransformFromVector(const ALfloat *vec) * term. There's no need to renormalize the magnitude since it would * just be reapplied in the matrix. */ - norm[0] = vec[0] * -al::MathDefs::Sqrt3(); - norm[1] = vec[1] * al::MathDefs::Sqrt3(); - norm[2] = vec[2] * al::MathDefs::Sqrt3(); + norm[0] = vec[0] * -sqrt_3; + norm[1] = vec[1] * sqrt_3; + norm[2] = vec[2] * sqrt_3; } return alu::Matrix{ diff --git a/common/math_defs.h b/common/math_defs.h index 9749bd53..0362a956 100644 --- a/common/math_defs.h +++ b/common/math_defs.h @@ -17,16 +17,14 @@ struct MathDefs { }; template<> struct MathDefs { - static constexpr inline float Pi() noexcept { return 3.14159265358979323846f; } - static constexpr inline float Tau() noexcept { return 3.14159265358979323846f * 2.0f; } - static constexpr inline float Sqrt3() noexcept { return 1.73205080756887719318f; } + static constexpr inline float Pi() noexcept { return static_cast(M_PI); } + static constexpr inline float Tau() noexcept { return static_cast(M_PI * 2.0); } }; template<> struct MathDefs { - static constexpr inline double Pi() noexcept { return 3.14159265358979323846; } - static constexpr inline double Tau() noexcept { return 3.14159265358979323846 * 2.0; } - static constexpr inline double Sqrt3() noexcept { return 1.73205080756887719318; } + static constexpr inline double Pi() noexcept { return M_PI; } + static constexpr inline double Tau() noexcept { return M_PI * 2.0; } }; } // namespace al -- cgit v1.2.3 From 2ab4883439b1bc96578e86cc894504b9a1d1021b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 20 Sep 2019 14:25:06 -0700 Subject: Silence some unreachable code warnings on MSVC --- common/alexcpt.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/common/alexcpt.h b/common/alexcpt.h index ff09bab2..654520cb 100644 --- a/common/alexcpt.h +++ b/common/alexcpt.h @@ -31,6 +31,18 @@ public: #define START_API_FUNC try +#ifndef _MSC_VER #define END_API_FUNC catch(...) { std::terminate(); } +#else +/* VS 2015 complains that some of these catch statements are unreachable code, + * due to the function body not able to throw anything. While technically true, + * it's preferable to mark API functions just in case that ever changes, so + * silence that warning. + */ +#define END_API_FUNC __pragma(warning(push)) \ +__pragma(warning(disable : 4702)) \ +catch(...) { std::terminate(); } \ +__pragma(warning(pop)) +#endif #endif /* ALEXCPT_H */ -- cgit v1.2.3 From 2ae1f8b8b64c2f1397649686507dabf72f4b8667 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 20 Sep 2019 14:40:12 -0700 Subject: Revert "Silence some unreachable code warnings on MSVC" This reverts commit 2ab4883439b1bc96578e86cc894504b9a1d1021b. It apparently didn't work at silencing anything. --- common/alexcpt.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/common/alexcpt.h b/common/alexcpt.h index 654520cb..ff09bab2 100644 --- a/common/alexcpt.h +++ b/common/alexcpt.h @@ -31,18 +31,6 @@ public: #define START_API_FUNC try -#ifndef _MSC_VER #define END_API_FUNC catch(...) { std::terminate(); } -#else -/* VS 2015 complains that some of these catch statements are unreachable code, - * due to the function body not able to throw anything. While technically true, - * it's preferable to mark API functions just in case that ever changes, so - * silence that warning. - */ -#define END_API_FUNC __pragma(warning(push)) \ -__pragma(warning(disable : 4702)) \ -catch(...) { std::terminate(); } \ -__pragma(warning(pop)) -#endif #endif /* ALEXCPT_H */ -- cgit v1.2.3 From a0a8af47ae0c28ccf9ee3ce2b8b5a4f00f280922 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 20 Sep 2019 14:56:21 -0700 Subject: Include VS2017 in AppVeyor builds --- appveyor.yml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 010a2da1..e9c52519 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,9 +2,17 @@ version: 1.19.1.{build} environment: matrix: - - GEN: "Visual Studio 14 2015" + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + GEN: "Visual Studio 14 2015" + ARCH: Win32 CFG: Release - - GEN: "Visual Studio 14 2015 Win64" + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + GEN: "Visual Studio 14 2015" + ARCH: x64 + CFG: Release + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + GEN: "Visual Studio 15 2017" + ARCH: x64 CFG: Release install: @@ -14,6 +22,6 @@ install: build_script: - cd build - - cmake -G"%GEN%" -DALSOFT_BUILD_ROUTER=ON -DALSOFT_REQUIRE_WINMM=ON -DALSOFT_REQUIRE_DSOUND=ON -DALSOFT_REQUIRE_WASAPI=ON -DALSOFT_EMBED_HRTF_DATA=YES .. + - cmake -G "%GEN%" -A %ARCH% -DALSOFT_BUILD_ROUTER=ON -DALSOFT_REQUIRE_WINMM=ON -DALSOFT_REQUIRE_DSOUND=ON -DALSOFT_REQUIRE_WASAPI=ON -DALSOFT_EMBED_HRTF_DATA=YES .. - cmake --build . --config %CFG% --clean-first -- cgit v1.2.3 From 8907a4fb04c50643f829034f711f7a96a69f57c9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 20 Sep 2019 15:45:59 -0700 Subject: Cleanup some router warnings --- router/alc.cpp | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/router/alc.cpp b/router/alc.cpp index 6620b6a7..c99e7c93 100644 --- a/router/alc.cpp +++ b/router/alc.cpp @@ -565,11 +565,11 @@ ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *f return DriverList[idx].alcGetProcAddress(device, funcname); } - auto entry = std::find_if(alcFunctions.cbegin(), alcFunctions.cend(), + auto iter = std::find_if(alcFunctions.cbegin(), alcFunctions.cend(), [funcname](const FuncExportEntry &entry) -> bool { return strcmp(funcname, entry.funcName) == 0; } ); - return (entry != alcFunctions.cend()) ? entry->address : nullptr; + return (iter != alcFunctions.cend()) ? iter->address : nullptr; } ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname) @@ -585,11 +585,11 @@ ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *e return DriverList[idx].alcGetEnumValue(device, enumname); } - auto entry = std::find_if(alcEnumerations.cbegin(), alcEnumerations.cend(), + auto iter = std::find_if(alcEnumerations.cbegin(), alcEnumerations.cend(), [enumname](const EnumExportEntry &entry) -> bool { return strcmp(enumname, entry.enumName) == 0; } ); - return (entry != alcEnumerations.cend()) ? entry->value : 0; + return (iter != alcEnumerations.cend()) ? iter->value : 0; } ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param) @@ -638,8 +638,8 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para } /* Ensure the list is double-null termianted. */ if(DevicesList.Names.empty()) - DevicesList.Names.emplace_back(0); - DevicesList.Names.emplace_back(0); + DevicesList.Names.emplace_back('\0'); + DevicesList.Names.emplace_back('\0'); return DevicesList.Names.data(); } @@ -665,8 +665,8 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para } /* Ensure the list is double-null termianted. */ if(AllDevicesList.Names.empty()) - AllDevicesList.Names.emplace_back(0); - AllDevicesList.Names.emplace_back(0); + AllDevicesList.Names.emplace_back('\0'); + AllDevicesList.Names.emplace_back('\0'); return AllDevicesList.Names.data(); } @@ -685,47 +685,47 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para } /* Ensure the list is double-null termianted. */ if(CaptureDevicesList.Names.empty()) - CaptureDevicesList.Names.emplace_back(0); - CaptureDevicesList.Names.emplace_back(0); + CaptureDevicesList.Names.emplace_back('\0'); + CaptureDevicesList.Names.emplace_back('\0'); return CaptureDevicesList.Names.data(); } case ALC_DEFAULT_DEVICE_SPECIFIER: { - auto drv = std::find_if(DriverList.cbegin(), DriverList.cend(), + auto iter = std::find_if(DriverList.cbegin(), DriverList.cend(), [](const DriverIface &drv) -> bool { return drv.ALCVer >= MAKE_ALC_VER(1, 1) || drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"); } ); - if(drv != DriverList.cend()) - return drv->alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER); + if(iter != DriverList.cend()) + return iter->alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER); return ""; } case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: { - auto drv = std::find_if(DriverList.cbegin(), DriverList.cend(), + auto iter = std::find_if(DriverList.cbegin(), DriverList.cend(), [](const DriverIface &drv) -> bool { return drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT") != ALC_FALSE; } ); - if(drv != DriverList.cend()) - return drv->alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER); + if(iter != DriverList.cend()) + return iter->alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER); return ""; } case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: { - auto drv = std::find_if(DriverList.cbegin(), DriverList.cend(), + auto iter = std::find_if(DriverList.cbegin(), DriverList.cend(), [](const DriverIface &drv) -> bool { return drv.ALCVer >= MAKE_ALC_VER(1, 1) || drv.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"); } ); - if(drv != DriverList.cend()) - return drv->alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); + if(iter != DriverList.cend()) + return iter->alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); return ""; } -- cgit v1.2.3 From 28e62456acbbabc7313a7f6f04c66a63464de92b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Sep 2019 12:08:45 -0700 Subject: Use an array and loop instead of individual tests --- alc/mixvoice.cpp | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 1d18a3a5..91a475f8 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -27,11 +27,9 @@ #include #include #include -#include #include #include #include -#include #include #include @@ -180,29 +178,37 @@ void aluInitMixer() { if(auto resopt = ConfigValueStr(nullptr, nullptr, "resampler")) { + struct ResamplerEntry { + const char name[12]; + const Resampler resampler; + }; + constexpr ResamplerEntry ResamplerList[]{ + { "none", PointResampler }, + { "point", PointResampler }, + { "cubic", FIR4Resampler }, + { "bsinc12", BSinc12Resampler }, + { "bsinc24", BSinc24Resampler }, + }; + const char *str{resopt->c_str()}; - if(al::strcasecmp(str, "point") == 0 || al::strcasecmp(str, "none") == 0) - ResamplerDefault = PointResampler; - else if(al::strcasecmp(str, "linear") == 0) - ResamplerDefault = LinearResampler; - else if(al::strcasecmp(str, "cubic") == 0) - ResamplerDefault = FIR4Resampler; - else if(al::strcasecmp(str, "bsinc12") == 0) - ResamplerDefault = BSinc12Resampler; - else if(al::strcasecmp(str, "bsinc24") == 0) - ResamplerDefault = BSinc24Resampler; - else if(al::strcasecmp(str, "bsinc") == 0) + if(al::strcasecmp(str, "bsinc") == 0) { WARN("Resampler option \"%s\" is deprecated, using bsinc12\n", str); - ResamplerDefault = BSinc12Resampler; + str = "bsinc12"; } else if(al::strcasecmp(str, "sinc4") == 0 || al::strcasecmp(str, "sinc8") == 0) { WARN("Resampler option \"%s\" is deprecated, using cubic\n", str); - ResamplerDefault = FIR4Resampler; + str = "cubic"; } - else + + auto iter = std::find_if(std::begin(ResamplerList), std::end(ResamplerList), + [str](const ResamplerEntry &entry) -> bool + { return al::strcasecmp(str, entry.name) == 0; }); + if(iter == std::end(ResamplerList)) ERR("Invalid resampler: %s\n", str); + else + ResamplerDefault = iter->resampler; } MixHrtfBlendSamples = SelectHrtfBlendMixer(); -- cgit v1.2.3 From c83055ff53ff575439c15a568731a7f86d7d3c6f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Sep 2019 15:49:18 -0700 Subject: Initial update for the changelog --- ChangeLog | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/ChangeLog b/ChangeLog index d234c14f..cb508612 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,54 @@ +openal-soft-1.20.0: + + Converted the library code base to C++11. A lot of hacks and custom + structures have been replaced with standard stuff. + + Fixed a performance problem with semaphores on macOS. + + Fixed bsinc SSE resampler on non-GCC compilers. + + Modified alcResetDeviceSOFT to attempt recovery of lost devices. + + Added a build option to use external native tools. For cross-compiling, + use with caution and ensure the native tools' binaries are up-to-date. + + Modified the virtual speaker layout for the HRTF B-Format decode. + + Added an adjust-latency config option for the PulseAudio backend. + + Improved the efficiency of the HRTF mixers. + + Fixed OpenSL capture. + + Improved the HRTF B-Format decoder coefficient generation. + + Fixed handling of WASAPI not reporting a default device. + + Renamed the makehrtf utility to makemhr. + + Added support for SOFA input files for makemhr. Either directly or through + a .def file. + + Added basic support for multi-field HRTFs. + + Improved handling of sources that end prematurely, to avoid loud clicks. + + Disabled some old KDE workarounds by default. Specifically, PulseAudio + streams can now be moved (KDE may try to move them after opening). + + Fixed support for extended capture/playback formats with OpenSL. + + Added an option for mixing first-, second-, or third-order B-Format with + HRTF output. This can improve HRTF performance given a number of sources. + + Added an RC file for proper DLL versioning information. + + Improved some reverb processing loops. + + Added a partial implementation of the Vocal Morpher effect. + + Improved reverb fading to be more consistent with pan fading. + openal-soft-1.19.1: Implemented capture support for the SoundIO backend. -- cgit v1.2.3 From 146afcbd7087e07dd9245ac503a9d7f93a45ec18 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Sep 2019 16:12:48 -0700 Subject: Explicitly mark a couple functions as inline --- alc/mixvoice.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 91a475f8..51af9c66 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -300,35 +300,35 @@ struct FmtTypeTraits { }; template<> struct FmtTypeTraits { using Type = ALubyte; - static constexpr ALfloat to_float(const Type val) noexcept + static constexpr inline float to_float(const Type val) noexcept { return val*(1.0f/128.0f) - 128.0f; } }; template<> struct FmtTypeTraits { using Type = ALshort; - static constexpr ALfloat to_float(const Type val) noexcept { return val*(1.0f/32768.0f); } + static constexpr inline float to_float(const Type val) noexcept { return val*(1.0f/32768.0f); } }; template<> struct FmtTypeTraits { using Type = ALfloat; - static constexpr ALfloat to_float(const Type val) noexcept { return val; } + static constexpr inline float to_float(const Type val) noexcept { return val; } }; template<> struct FmtTypeTraits { using Type = ALdouble; - static constexpr ALfloat to_float(const Type val) noexcept + static constexpr inline float to_float(const Type val) noexcept { return static_cast(val); } }; template<> struct FmtTypeTraits { using Type = ALubyte; - static constexpr ALfloat to_float(const Type val) noexcept + static constexpr inline float to_float(const Type val) noexcept { return muLawDecompressionTable[val] * (1.0f/32768.0f); } }; template<> struct FmtTypeTraits { using Type = ALubyte; - static constexpr ALfloat to_float(const Type val) noexcept + static constexpr inline float to_float(const Type val) noexcept { return aLawDecompressionTable[val] * (1.0f/32768.0f); } }; -- cgit v1.2.3 From 564c953e9465855890149a2d1b4b51f1f644fd9b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Sep 2019 16:47:33 -0700 Subject: Make the buffer frequency unsigned --- al/buffer.cpp | 6 +++--- al/buffer.h | 2 +- al/source.cpp | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/al/buffer.cpp b/al/buffer.cpp index f1f792e9..c9e195d1 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -463,7 +463,7 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, ALuint size, /* Can only preserve data with the same format and alignment. */ if UNLIKELY(ALBuf->mFmtChannels != DstChannels || ALBuf->OriginalType != SrcType) SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched format"); - if UNLIKELY(static_cast(ALBuf->OriginalAlign) != align) + if UNLIKELY(ALBuf->OriginalAlign != align) SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched alignment"); } @@ -539,7 +539,7 @@ void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq, ALuint size, ALBuf->OriginalSize = size; ALBuf->OriginalType = SrcType; - ALBuf->Frequency = freq; + ALBuf->Frequency = static_cast(freq); ALBuf->mFmtChannels = DstChannels; ALBuf->mFmtType = DstType; ALBuf->Access = access; @@ -1253,7 +1253,7 @@ START_API_FUNC else switch(param) { case AL_FREQUENCY: - *value = albuf->Frequency; + *value = static_cast(albuf->Frequency); break; case AL_BITS: diff --git a/al/buffer.h b/al/buffer.h index 70faf56e..d41eec5d 100644 --- a/al/buffer.h +++ b/al/buffer.h @@ -68,7 +68,7 @@ inline ALuint FrameSizeFromFmt(FmtChannels chans, FmtType type) struct ALbuffer { al::vector mData; - ALsizei Frequency{0}; + ALuint Frequency{0u}; ALbitfieldSOFT Access{0u}; ALuint SampleLen{0u}; diff --git a/al/source.cpp b/al/source.cpp index f5550caf..7eda4fb6 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -267,8 +267,7 @@ ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, nanoseconds * } assert(BufferFmt != nullptr); - offset = static_cast(readPos) / ALdouble{FRACTIONONE} / - static_cast(BufferFmt->Frequency); + offset = static_cast(readPos) / ALdouble{FRACTIONONE} / BufferFmt->Frequency; } return offset; @@ -2784,7 +2783,7 @@ START_API_FUNC } ALbuffer *buffer{BufferList->mBuffer}; - voice->mFrequency = static_cast(buffer->Frequency); + voice->mFrequency = buffer->Frequency; voice->mFmtChannels = buffer->mFmtChannels; voice->mNumChannels = ChannelsFromFmt(buffer->mFmtChannels); voice->mSampleSize = BytesFromFmt(buffer->mFmtType); -- cgit v1.2.3 From 9993ea818cab65293210b15a0678b55ef8601ecd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Sep 2019 19:46:19 -0700 Subject: Restructure the changelog updates --- ChangeLog | 51 ++++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/ChangeLog b/ChangeLog index cb508612..cf69ff5b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,53 +1,54 @@ openal-soft-1.20.0: - Converted the library code base to C++11. A lot of hacks and custom - structures have been replaced with standard stuff. + Converted the library codebase to C++11. A lot of hacks and custom + structures have been replaced with standard or cleaner implementations. - Fixed a performance problem with semaphores on macOS. + Partially implemented the Vocal Morpher effect. - Fixed bsinc SSE resampler on non-GCC compilers. + Fixed the bsinc SSE resampler on non-GCC compilers. + + Fixed OpenSL capture. + + Fixed support for extended capture/playback formats with OpenSL. + + Fixed handling of WASAPI not reporting a default device. + + Fixed performance problems relating to semaphores on macOS. Modified alcResetDeviceSOFT to attempt recovery of lost devices. - Added a build option to use external native tools. For cross-compiling, - use with caution and ensure the native tools' binaries are up-to-date. + Modified the virtual speaker layout for HRTF B-Format decoding. - Modified the virtual speaker layout for the HRTF B-Format decode. + Modified the PulseAudio backend to use a custom processing loop. - Added an adjust-latency config option for the PulseAudio backend. + Renamed the makehrtf utility to makemhr. Improved the efficiency of the HRTF mixers. - Fixed OpenSL capture. - Improved the HRTF B-Format decoder coefficient generation. - Fixed handling of WASAPI not reporting a default device. + Improved reverb fading to be more consistent with pan fading. - Renamed the makehrtf utility to makemhr. + Improved handling of sources that end prematurely, to avoid loud clicks. - Added support for SOFA input files for makemhr. Either directly or through - a .def file. + Improved some reverb processing loops. - Added basic support for multi-field HRTFs. + Added support for SOFA input files with makemhr. - Improved handling of sources that end prematurely, to avoid loud clicks. + Added a build option to use pre-built native tools. For cross-compiling, + use with caution and ensure the native tools' binaries are kept up-to-date. - Disabled some old KDE workarounds by default. Specifically, PulseAudio - streams can now be moved (KDE may try to move them after opening). + Added an adjust-latency config option for the PulseAudio backend. - Fixed support for extended capture/playback formats with OpenSL. + Added basic support for multi-field HRTFs. Added an option for mixing first-, second-, or third-order B-Format with HRTF output. This can improve HRTF performance given a number of sources. - Added an RC file for proper DLL versioning information. - - Improved some reverb processing loops. - - Added a partial implementation of the Vocal Morpher effect. + Added an RC file for proper DLL version information. - Improved reverb fading to be more consistent with pan fading. + Disabled some old KDE workarounds by default. Specifically, PulseAudio + streams can now be moved (KDE may try to move them after opening). openal-soft-1.19.1: -- cgit v1.2.3 From 9325f1d507e20b90b799217a9faa7ed9d55b0be7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Sep 2019 21:14:11 -0700 Subject: Split some code into separate functions --- alc/mixvoice.cpp | 254 +++++++++++++++++++++++++++---------------------------- 1 file changed, 126 insertions(+), 128 deletions(-) diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 51af9c66..bf10444a 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -485,6 +485,128 @@ ALfloat *LoadBufferQueue(ALbufferlistitem *BufferListItem, ALbufferlistitem *Buf return SrcBuffer.begin(); } + +void DoHrtfMix(ALvoice::DirectData &Direct, const float TargetGain, DirectParams &parms, + const float *samples, const ALuint DstBufferSize, const ALuint Counter, const ALuint OutPos, + const ALuint IrSize, ALCdevice *Device) +{ + const ALuint OutLIdx{GetChannelIdxByName(Device->RealOut, FrontLeft)}; + const ALuint OutRIdx{GetChannelIdxByName(Device->RealOut, FrontRight)}; + auto &HrtfSamples = Device->HrtfSourceData; + auto &AccumSamples = Device->HrtfAccumData; + + /* Copy the HRTF history and new input samples into a temp buffer. */ + auto src_iter = std::copy(parms.Hrtf.State.History.begin(), parms.Hrtf.State.History.end(), + std::begin(HrtfSamples)); + std::copy_n(samples, DstBufferSize, src_iter); + /* Copy the last used samples back into the history buffer for later. */ + std::copy_n(std::begin(HrtfSamples) + DstBufferSize, parms.Hrtf.State.History.size(), + parms.Hrtf.State.History.begin()); + + /* Copy the current filtered values being accumulated into the temp buffer. */ + auto accum_iter = std::copy_n(parms.Hrtf.State.Values.begin(), parms.Hrtf.State.Values.size(), + std::begin(AccumSamples)); + /* Clear the accumulation buffer that will start getting filled in. */ + std::fill_n(accum_iter, DstBufferSize, float2{}); + + /* If fading, the old gain is not silence, and this is the first mixing + * pass, fade between the IRs. + */ + ALuint fademix{0u}; + if(Counter && parms.Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD && OutPos == 0) + { + fademix = minu(DstBufferSize, 128); + + float gain{TargetGain}; + + /* The new coefficients need to fade in completely since they're + * replacing the old ones. To keep the gain fading consistent, + * interpolate between the old and new target gains given how much of + * the fade time this mix handles. + */ + if LIKELY(Counter > fademix) + { + const ALfloat a{static_cast(fademix) / static_cast(Counter)}; + gain = lerp(parms.Hrtf.Old.Gain, TargetGain, a); + } + MixHrtfFilter hrtfparams; + hrtfparams.Coeffs = &parms.Hrtf.Target.Coeffs; + hrtfparams.Delay[0] = parms.Hrtf.Target.Delay[0]; + hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1]; + hrtfparams.Gain = 0.0f; + hrtfparams.GainStep = gain / static_cast(fademix); + + MixHrtfBlendSamples(Direct.Buffer[OutLIdx], Direct.Buffer[OutRIdx], HrtfSamples, + AccumSamples, OutPos, IrSize, &parms.Hrtf.Old, &hrtfparams, fademix); + /* Update the old parameters with the result. */ + parms.Hrtf.Old = parms.Hrtf.Target; + if(fademix < Counter) + parms.Hrtf.Old.Gain = hrtfparams.Gain; + else + parms.Hrtf.Old.Gain = TargetGain; + } + + if LIKELY(fademix < DstBufferSize) + { + const ALuint todo{DstBufferSize - fademix}; + float gain{TargetGain}; + + /* Interpolate the target gain if the gain fading lasts longer than + * this mix. + */ + if(Counter > DstBufferSize) + { + const float a{static_cast(todo) / static_cast(Counter-fademix)}; + gain = lerp(parms.Hrtf.Old.Gain, TargetGain, a); + } + + MixHrtfFilter hrtfparams; + hrtfparams.Coeffs = &parms.Hrtf.Target.Coeffs; + hrtfparams.Delay[0] = parms.Hrtf.Target.Delay[0]; + hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1]; + hrtfparams.Gain = parms.Hrtf.Old.Gain; + hrtfparams.GainStep = (gain - parms.Hrtf.Old.Gain) / static_cast(todo); + MixHrtfSamples(Direct.Buffer[OutLIdx], Direct.Buffer[OutRIdx], HrtfSamples+fademix, + AccumSamples+fademix, OutPos+fademix, IrSize, &hrtfparams, todo); + /* Store the interpolated gain or the final target gain depending if + * the fade is done. + */ + if(DstBufferSize < Counter) + parms.Hrtf.Old.Gain = gain; + else + parms.Hrtf.Old.Gain = TargetGain; + } + + /* Copy the new in-progress accumulation values back for the next mix. */ + std::copy_n(std::begin(AccumSamples) + DstBufferSize, parms.Hrtf.State.Values.size(), + parms.Hrtf.State.Values.begin()); +} + +void DoNfcMix(ALvoice::DirectData &Direct, const float *TargetGains, DirectParams &parms, + const float *samples, const ALuint DstBufferSize, const ALuint Counter, const ALuint OutPos, + ALCdevice *Device) +{ + const size_t outcount{Device->NumChannelsPerOrder[0]}; + MixSamples({samples, DstBufferSize}, Direct.Buffer.first(outcount), + parms.Gains.Current, TargetGains, Counter, OutPos); + + const al::span nfcsamples{Device->NfcSampleData, DstBufferSize}; + size_t chanoffset{outcount}; + using FilterProc = void (NfcFilter::*)(float*,const float*,const size_t); + auto apply_nfc = [&Direct,&parms,samples,TargetGains,Counter,OutPos,&chanoffset,nfcsamples]( + const FilterProc process, const size_t chancount) -> void + { + if(chancount < 1) return; + (parms.NFCtrlFilter.*process)(nfcsamples.data(), samples, nfcsamples.size()); + MixSamples(nfcsamples, Direct.Buffer.subspan(chanoffset, chancount), + parms.Gains.Current+chanoffset, TargetGains+chanoffset, Counter, OutPos); + chanoffset += chancount; + }; + apply_nfc(&NfcFilter::process1, Device->NumChannelsPerOrder[1]); + apply_nfc(&NfcFilter::process2, Device->NumChannelsPerOrder[2]); + apply_nfc(&NfcFilter::process3, Device->NumChannelsPerOrder[3]); +} + } // namespace void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) @@ -653,141 +775,17 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) if((mFlags&VOICE_HAS_HRTF)) { - const ALuint OutLIdx{GetChannelIdxByName(Device->RealOut, FrontLeft)}; - const ALuint OutRIdx{GetChannelIdxByName(Device->RealOut, FrontRight)}; - - auto &HrtfSamples = Device->HrtfSourceData; - auto &AccumSamples = Device->HrtfAccumData; const ALfloat TargetGain{UNLIKELY(vstate == ALvoice::Stopping) ? 0.0f : parms.Hrtf.Target.Gain}; - ALuint fademix{0u}; - - /* Copy the HRTF history and new input samples into a temp - * buffer. - */ - auto src_iter = std::copy(parms.Hrtf.State.History.begin(), - parms.Hrtf.State.History.end(), std::begin(HrtfSamples)); - std::copy_n(samples, DstBufferSize, src_iter); - /* Copy the last used samples back into the history buffer - * for later. - */ - std::copy_n(std::begin(HrtfSamples) + DstBufferSize, - parms.Hrtf.State.History.size(), parms.Hrtf.State.History.begin()); - - /* Copy the current filtered values being accumulated into - * the temp buffer. - */ - auto accum_iter = std::copy_n(parms.Hrtf.State.Values.begin(), - parms.Hrtf.State.Values.size(), std::begin(AccumSamples)); - - /* Clear the accumulation buffer that will start getting - * filled in. - */ - std::fill_n(accum_iter, DstBufferSize, float2{}); - - /* If fading, the old gain is not silence, and this is the - * first mixing pass, fade between the IRs. - */ - if(Counter && (parms.Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD) && OutPos == 0) - { - fademix = minu(DstBufferSize, 128); - - ALfloat gain{TargetGain}; - - /* The new coefficients need to fade in completely - * since they're replacing the old ones. To keep the - * gain fading consistent, interpolate between the old - * and new target gains given how much of the fade time - * this mix handles. - */ - if LIKELY(Counter > fademix) - { - const ALfloat a{static_cast(fademix) / - static_cast(Counter)}; - gain = lerp(parms.Hrtf.Old.Gain, TargetGain, a); - } - MixHrtfFilter hrtfparams; - hrtfparams.Coeffs = &parms.Hrtf.Target.Coeffs; - hrtfparams.Delay[0] = parms.Hrtf.Target.Delay[0]; - hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1]; - hrtfparams.Gain = 0.0f; - hrtfparams.GainStep = gain / static_cast(fademix); - - MixHrtfBlendSamples(mDirect.Buffer[OutLIdx], mDirect.Buffer[OutRIdx], - HrtfSamples, AccumSamples, OutPos, IrSize, &parms.Hrtf.Old, - &hrtfparams, fademix); - /* Update the old parameters with the result. */ - parms.Hrtf.Old = parms.Hrtf.Target; - if(fademix < Counter) - parms.Hrtf.Old.Gain = hrtfparams.Gain; - else - parms.Hrtf.Old.Gain = TargetGain; - } - - if LIKELY(fademix < DstBufferSize) - { - const ALuint todo{DstBufferSize - fademix}; - ALfloat gain{TargetGain}; - - /* Interpolate the target gain if the gain fading lasts - * longer than this mix. - */ - if(Counter > DstBufferSize) - { - const ALfloat a{static_cast(todo) / - static_cast(Counter-fademix)}; - gain = lerp(parms.Hrtf.Old.Gain, TargetGain, a); - } - - MixHrtfFilter hrtfparams; - hrtfparams.Coeffs = &parms.Hrtf.Target.Coeffs; - hrtfparams.Delay[0] = parms.Hrtf.Target.Delay[0]; - hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1]; - hrtfparams.Gain = parms.Hrtf.Old.Gain; - hrtfparams.GainStep = (gain - parms.Hrtf.Old.Gain) / - static_cast(todo); - MixHrtfSamples(mDirect.Buffer[OutLIdx], mDirect.Buffer[OutRIdx], - HrtfSamples+fademix, AccumSamples+fademix, OutPos+fademix, IrSize, - &hrtfparams, todo); - /* Store the interpolated gain or the final target gain - * depending if the fade is done. - */ - if(DstBufferSize < Counter) - parms.Hrtf.Old.Gain = gain; - else - parms.Hrtf.Old.Gain = TargetGain; - } - - /* Copy the new in-progress accumulation values back for - * the next mix. - */ - std::copy_n(std::begin(AccumSamples) + DstBufferSize, - parms.Hrtf.State.Values.size(), parms.Hrtf.State.Values.begin()); + DoHrtfMix(mDirect, TargetGain, parms, samples, DstBufferSize, Counter, OutPos, + IrSize, Device); } else if((mFlags&VOICE_HAS_NFC)) { const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? SilentTarget : parms.Gains.Target}; - - const size_t outcount{Device->NumChannelsPerOrder[0]}; - MixSamples({samples, DstBufferSize}, mDirect.Buffer.first(outcount), - parms.Gains.Current, TargetGains, Counter, OutPos); - - const al::span nfcsamples{Device->NfcSampleData, DstBufferSize}; - size_t chanoffset{outcount}; - using FilterProc = void (NfcFilter::*)(float*,const float*,const size_t); - auto apply_nfc = [this,&parms,samples,TargetGains,Counter,OutPos,&chanoffset,nfcsamples](const FilterProc process, const size_t chancount) -> void - { - if(chancount < 1) return; - (parms.NFCtrlFilter.*process)(nfcsamples.data(), samples, nfcsamples.size()); - MixSamples(nfcsamples, mDirect.Buffer.subspan(chanoffset, chancount), - parms.Gains.Current+chanoffset, TargetGains+chanoffset, Counter, - OutPos); - chanoffset += chancount; - }; - apply_nfc(&NfcFilter::process1, Device->NumChannelsPerOrder[1]); - apply_nfc(&NfcFilter::process2, Device->NumChannelsPerOrder[2]); - apply_nfc(&NfcFilter::process3, Device->NumChannelsPerOrder[3]); + DoNfcMix(mDirect, TargetGains, parms, samples, DstBufferSize, Counter, OutPos, + Device); } else { -- cgit v1.2.3 From 5f6a35c960da4174670640fc9a805186968694df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Sep 2019 23:35:24 -0700 Subject: Avoid storing an integer in a pointer C++ does not guarantee that, given an int of sufficient size, converting int->ptr->int will result in the original value. A pointer may have more than one integer representation. Only ptr->int->ptr round trips are well-defined. --- alc/effects/reverb.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/alc/effects/reverb.cpp b/alc/effects/reverb.cpp index 4a85f640..6e56adf2 100644 --- a/alc/effects/reverb.cpp +++ b/alc/effects/reverb.cpp @@ -220,13 +220,16 @@ struct DelayLineI { * of 2 to allow the use of bit-masking instead of a modulus for wrapping. */ size_t Mask{0u}; - std::array *Line{nullptr}; + union { + uintptr_t LineOffset{0u}; + std::array *Line; + }; /* Given the allocated sample buffer, this function updates each delay line * offset. */ void realizeLineOffset(std::array *sampleBuffer) noexcept - { Line = &sampleBuffer[reinterpret_cast(Line)]; } + { Line = sampleBuffer + LineOffset; } /* Calculate the length of a delay line and store its mask and offset. */ ALuint calcLineLength(const ALfloat length, const uintptr_t offset, const ALfloat frequency, @@ -240,7 +243,7 @@ struct DelayLineI { /* All lines share a single sample buffer. */ Mask = samples - 1; - Line = reinterpret_cast*>(offset); + LineOffset = offset; /* Return the sample count for accumulation. */ return samples; -- cgit v1.2.3 From 9c95f62e95a76059548762f2e7d2e9bb0e8d4631 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 22 Sep 2019 11:17:31 -0700 Subject: Remove large file macros Large file offsets aren't being utilized, and C++ seems to use to 64-bit offsets anyway. --- CMakeLists.txt | 13 ------------- cmake/CheckFileOffsetBits.c | 9 --------- cmake/CheckFileOffsetBits.cmake | 39 --------------------------------------- 3 files changed, 61 deletions(-) delete mode 100644 cmake/CheckFileOffsetBits.c delete mode 100644 cmake/CheckFileOffsetBits.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 81eb25bf..b9087e95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,6 @@ INCLUDE(CheckCSourceCompiles) INCLUDE(CheckCXXSourceCompiles) INCLUDE(CheckTypeSize) include(CheckStructHasMember) -include(CheckFileOffsetBits) include(GNUInstallDirs) @@ -150,18 +149,6 @@ if(NOT WIN32) UNSET(OLD_REQUIRED_FLAGS) ENDIF() -# Set defines for large file support. Don't set this for Android targets. See: -# https://android-developers.googleblog.com/2017/09/introducing-android-native-development.html -IF(NOT ANDROID) - CHECK_FILE_OFFSET_BITS() - IF(_FILE_OFFSET_BITS) - SET(CPP_DEFS ${CPP_DEFS} "_FILE_OFFSET_BITS=${_FILE_OFFSET_BITS}") - SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_FILE_OFFSET_BITS=${_FILE_OFFSET_BITS}") - ENDIF() - SET(CPP_DEFS ${CPP_DEFS} _LARGEFILE_SOURCE _LARGE_FILES) - SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_LARGEFILE_SOURCE -D_LARGE_FILES") -ENDIF() - # C99 has restrict, but C++ does not, so we can only utilize __restrict. SET(RESTRICT_DECL ) CHECK_CXX_SOURCE_COMPILES("int *__restrict foo; diff --git a/cmake/CheckFileOffsetBits.c b/cmake/CheckFileOffsetBits.c deleted file mode 100644 index de98296e..00000000 --- a/cmake/CheckFileOffsetBits.c +++ /dev/null @@ -1,9 +0,0 @@ -#include - -#define KB ((off_t)(1024)) -#define MB ((off_t)(KB*1024)) -#define GB ((off_t)(MB*1024)) -int tb[((GB+GB+GB) > GB) ? 1 : -1]; - -int main() -{ return 0; } diff --git a/cmake/CheckFileOffsetBits.cmake b/cmake/CheckFileOffsetBits.cmake deleted file mode 100644 index 1dc154e4..00000000 --- a/cmake/CheckFileOffsetBits.cmake +++ /dev/null @@ -1,39 +0,0 @@ -# - Check if the _FILE_OFFSET_BITS macro is needed for large files -# CHECK_FILE_OFFSET_BITS() -# -# The following variables may be set before calling this macro to -# modify the way the check is run: -# -# CMAKE_REQUIRED_FLAGS = string of compile command line flags -# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) -# CMAKE_REQUIRED_INCLUDES = list of include directories -# Copyright (c) 2009, Chris Robinson -# -# Redistribution and use is allowed according to the terms of the LGPL license. - - -MACRO(CHECK_FILE_OFFSET_BITS) - - IF(NOT DEFINED _FILE_OFFSET_BITS) - MESSAGE(STATUS "Checking _FILE_OFFSET_BITS for large files") - TRY_COMPILE(__WITHOUT_FILE_OFFSET_BITS_64 - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/CheckFileOffsetBits.c - COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}) - IF(NOT __WITHOUT_FILE_OFFSET_BITS_64) - TRY_COMPILE(__WITH_FILE_OFFSET_BITS_64 - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/CheckFileOffsetBits.c - COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_FILE_OFFSET_BITS=64) - ENDIF(NOT __WITHOUT_FILE_OFFSET_BITS_64) - - IF(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64) - SET(_FILE_OFFSET_BITS 64 CACHE INTERNAL "_FILE_OFFSET_BITS macro needed for large files") - MESSAGE(STATUS "Checking _FILE_OFFSET_BITS for large files - 64") - ELSE(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64) - SET(_FILE_OFFSET_BITS "" CACHE INTERNAL "_FILE_OFFSET_BITS macro needed for large files") - MESSAGE(STATUS "Checking _FILE_OFFSET_BITS for large files - not needed") - ENDIF(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64) - ENDIF(NOT DEFINED _FILE_OFFSET_BITS) - -ENDMACRO(CHECK_FILE_OFFSET_BITS) \ No newline at end of file -- cgit v1.2.3 From 95996effaf04c87b7091c904e6545bc1e5e25aee Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 22 Sep 2019 12:23:41 -0700 Subject: Move the ifstream wrapper to common --- CMakeLists.txt | 2 + alc/alconfig.cpp | 10 ++-- alc/ambdec.cpp | 2 +- alc/compat.h | 66 ----------------------- alc/helpers.cpp | 137 ----------------------------------------------- alc/hrtf.cpp | 3 +- common/alfstream.cpp | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++ common/alfstream.h | 70 ++++++++++++++++++++++++ 8 files changed, 228 insertions(+), 209 deletions(-) create mode 100644 common/alfstream.cpp create mode 100644 common/alfstream.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b9087e95..c20fa021 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -527,6 +527,8 @@ SET(COMMON_OBJS common/alcomplex.h common/alexcpt.cpp common/alexcpt.h + common/alfstream.cpp + common/alfstream.h common/almalloc.cpp common/almalloc.h common/alnumeric.h diff --git a/alc/alconfig.cpp b/alc/alconfig.cpp index b266fe5b..ede39156 100644 --- a/alc/alconfig.cpp +++ b/alc/alconfig.cpp @@ -41,15 +41,17 @@ #include #endif -#include -#include #include +#include +#include +#include -#include "alcmain.h" +#include "alfstream.h" #include "alstring.h" +#include "compat.h" #include "logging.h" #include "strutils.h" -#include "compat.h" +#include "vector.h" namespace { diff --git a/alc/ambdec.cpp b/alc/ambdec.cpp index fa29d268..adf116fe 100644 --- a/alc/ambdec.cpp +++ b/alc/ambdec.cpp @@ -10,7 +10,7 @@ #include #include -#include "compat.h" +#include "alfstream.h" #include "logging.h" diff --git a/alc/compat.h b/alc/compat.h index f2e10513..960b4b94 100644 --- a/alc/compat.h +++ b/alc/compat.h @@ -1,72 +1,6 @@ #ifndef AL_COMPAT_H #define AL_COMPAT_H -#ifdef _WIN32 - -#define WIN32_LEAN_AND_MEAN -#include - -#include -#include -#include - - -namespace al { - -// Windows' std::ifstream fails with non-ANSI paths since the standard only -// specifies names using const char* (or std::string). MSVC has a non-standard -// extension using const wchar_t* (or std::wstring?) to handle Unicode paths, -// but not all Windows compilers support it. So we have to make our own istream -// that accepts UTF-8 paths and forwards to Unicode-aware I/O functions. -class filebuf final : public std::streambuf { - std::array mBuffer; - HANDLE mFile{INVALID_HANDLE_VALUE}; - - int_type underflow() override; - pos_type seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) override; - pos_type seekpos(pos_type pos, std::ios_base::openmode mode) override; - -public: - filebuf() = default; - ~filebuf() override; - - bool open(const wchar_t *filename, std::ios_base::openmode mode); - bool open(const char *filename, std::ios_base::openmode mode); - - bool is_open() const noexcept { return mFile != INVALID_HANDLE_VALUE; } -}; - -// Inherit from std::istream to use our custom streambuf -class ifstream final : public std::istream { - filebuf mStreamBuf; - -public: - ifstream(const wchar_t *filename, std::ios_base::openmode mode = std::ios_base::in); - ifstream(const std::wstring &filename, std::ios_base::openmode mode = std::ios_base::in) - : ifstream(filename.c_str(), mode) { } - ifstream(const char *filename, std::ios_base::openmode mode = std::ios_base::in); - ifstream(const std::string &filename, std::ios_base::openmode mode = std::ios_base::in) - : ifstream(filename.c_str(), mode) { } - ~ifstream() override; - - bool is_open() const noexcept { return mStreamBuf.is_open(); } -}; - -} // namespace al - -#else /* _WIN32 */ - -#include - -namespace al { - -using filebuf = std::filebuf; -using ifstream = std::ifstream; - -} // namespace al - -#endif /* _WIN32 */ - #include struct PathNamePair { std::string path, fname; }; diff --git a/alc/helpers.cpp b/alc/helpers.cpp index 1d19d004..1d534619 100644 --- a/alc/helpers.cpp +++ b/alc/helpers.cpp @@ -248,143 +248,6 @@ void FPUCtl::leave() #ifdef _WIN32 -namespace al { - -auto filebuf::underflow() -> int_type -{ - if(mFile != INVALID_HANDLE_VALUE && gptr() == egptr()) - { - // Read in the next chunk of data, and set the pointers on success - DWORD got{}; - if(ReadFile(mFile, mBuffer.data(), static_cast(mBuffer.size()), &got, nullptr)) - setg(mBuffer.data(), mBuffer.data(), mBuffer.data()+got); - } - if(gptr() == egptr()) - return traits_type::eof(); - return traits_type::to_int_type(*gptr()); -} - -auto filebuf::seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) -> pos_type -{ - if(mFile == INVALID_HANDLE_VALUE || (mode&std::ios_base::out) || !(mode&std::ios_base::in)) - return traits_type::eof(); - - LARGE_INTEGER fpos{}; - switch(whence) - { - case std::ios_base::beg: - fpos.QuadPart = offset; - if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_BEGIN)) - return traits_type::eof(); - break; - - case std::ios_base::cur: - // If the offset remains in the current buffer range, just - // update the pointer. - if((offset >= 0 && offset < off_type(egptr()-gptr())) || - (offset < 0 && -offset <= off_type(gptr()-eback()))) - { - // Get the current file offset to report the correct read - // offset. - fpos.QuadPart = 0; - if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_CURRENT)) - return traits_type::eof(); - setg(eback(), gptr()+offset, egptr()); - return fpos.QuadPart - off_type(egptr()-gptr()); - } - // Need to offset for the file offset being at egptr() while - // the requested offset is relative to gptr(). - offset -= off_type(egptr()-gptr()); - fpos.QuadPart = offset; - if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_CURRENT)) - return traits_type::eof(); - break; - - case std::ios_base::end: - fpos.QuadPart = offset; - if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_END)) - return traits_type::eof(); - break; - - default: - return traits_type::eof(); - } - setg(nullptr, nullptr, nullptr); - return fpos.QuadPart; -} - -auto filebuf::seekpos(pos_type pos, std::ios_base::openmode mode) -> pos_type -{ - // Simplified version of seekoff - if(mFile == INVALID_HANDLE_VALUE || (mode&std::ios_base::out) || !(mode&std::ios_base::in)) - return traits_type::eof(); - - LARGE_INTEGER fpos{}; - fpos.QuadPart = pos; - if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_BEGIN)) - return traits_type::eof(); - - setg(nullptr, nullptr, nullptr); - return fpos.QuadPart; -} - -filebuf::~filebuf() -{ - if(mFile != INVALID_HANDLE_VALUE) - CloseHandle(mFile); - mFile = INVALID_HANDLE_VALUE; -} - -bool filebuf::open(const wchar_t *filename, std::ios_base::openmode mode) -{ - if((mode&std::ios_base::out) || !(mode&std::ios_base::in)) - return false; - HANDLE f{CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, nullptr)}; - if(f == INVALID_HANDLE_VALUE) return false; - - if(mFile != INVALID_HANDLE_VALUE) - CloseHandle(mFile); - mFile = f; - - setg(nullptr, nullptr, nullptr); - return true; -} -bool filebuf::open(const char *filename, std::ios_base::openmode mode) -{ - std::wstring wname{utf8_to_wstr(filename)}; - return open(wname.c_str(), mode); -} - - -ifstream::ifstream(const wchar_t *filename, std::ios_base::openmode mode) - : std::istream{nullptr} -{ - init(&mStreamBuf); - - // Set the failbit if the file failed to open. - if((mode&std::ios_base::out) || !mStreamBuf.open(filename, mode|std::ios_base::in)) - clear(failbit); -} - -ifstream::ifstream(const char *filename, std::ios_base::openmode mode) - : std::istream{nullptr} -{ - init(&mStreamBuf); - - // Set the failbit if the file failed to open. - if((mode&std::ios_base::out) || !mStreamBuf.open(filename, mode|std::ios_base::in)) - clear(failbit); -} - -/* This is only here to ensure the compiler doesn't define an implicit - * destructor, which it tries to automatically inline and subsequently complain - * it can't inline without excessive code growth. - */ -ifstream::~ifstream() { } - -} // namespace al - const PathNamePair &GetProcBinary() { static PathNamePair ret; diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index ebdee46a..12d310d4 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -36,17 +36,18 @@ #include #include #include +#include #include #include "AL/al.h" #include "alcmain.h" #include "alconfig.h" +#include "alfstream.h" #include "almalloc.h" #include "alnumeric.h" #include "aloptional.h" #include "alspan.h" -#include "compat.h" #include "filters/splitter.h" #include "logging.h" #include "math_defs.h" diff --git a/common/alfstream.cpp b/common/alfstream.cpp new file mode 100644 index 00000000..7378c678 --- /dev/null +++ b/common/alfstream.cpp @@ -0,0 +1,147 @@ + +#include "config.h" + +#include "alfstream.h" + +#include "strutils.h" + +#ifdef _WIN32 + +namespace al { + +auto filebuf::underflow() -> int_type +{ + if(mFile != INVALID_HANDLE_VALUE && gptr() == egptr()) + { + // Read in the next chunk of data, and set the pointers on success + DWORD got{}; + if(ReadFile(mFile, mBuffer.data(), static_cast(mBuffer.size()), &got, nullptr)) + setg(mBuffer.data(), mBuffer.data(), mBuffer.data()+got); + } + if(gptr() == egptr()) + return traits_type::eof(); + return traits_type::to_int_type(*gptr()); +} + +auto filebuf::seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) -> pos_type +{ + if(mFile == INVALID_HANDLE_VALUE || (mode&std::ios_base::out) || !(mode&std::ios_base::in)) + return traits_type::eof(); + + LARGE_INTEGER fpos{}; + switch(whence) + { + case std::ios_base::beg: + fpos.QuadPart = offset; + if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_BEGIN)) + return traits_type::eof(); + break; + + case std::ios_base::cur: + // If the offset remains in the current buffer range, just + // update the pointer. + if((offset >= 0 && offset < off_type(egptr()-gptr())) || + (offset < 0 && -offset <= off_type(gptr()-eback()))) + { + // Get the current file offset to report the correct read + // offset. + fpos.QuadPart = 0; + if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_CURRENT)) + return traits_type::eof(); + setg(eback(), gptr()+offset, egptr()); + return fpos.QuadPart - off_type(egptr()-gptr()); + } + // Need to offset for the file offset being at egptr() while + // the requested offset is relative to gptr(). + offset -= off_type(egptr()-gptr()); + fpos.QuadPart = offset; + if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_CURRENT)) + return traits_type::eof(); + break; + + case std::ios_base::end: + fpos.QuadPart = offset; + if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_END)) + return traits_type::eof(); + break; + + default: + return traits_type::eof(); + } + setg(nullptr, nullptr, nullptr); + return fpos.QuadPart; +} + +auto filebuf::seekpos(pos_type pos, std::ios_base::openmode mode) -> pos_type +{ + // Simplified version of seekoff + if(mFile == INVALID_HANDLE_VALUE || (mode&std::ios_base::out) || !(mode&std::ios_base::in)) + return traits_type::eof(); + + LARGE_INTEGER fpos{}; + fpos.QuadPart = pos; + if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_BEGIN)) + return traits_type::eof(); + + setg(nullptr, nullptr, nullptr); + return fpos.QuadPart; +} + +filebuf::~filebuf() +{ + if(mFile != INVALID_HANDLE_VALUE) + CloseHandle(mFile); + mFile = INVALID_HANDLE_VALUE; +} + +bool filebuf::open(const wchar_t *filename, std::ios_base::openmode mode) +{ + if((mode&std::ios_base::out) || !(mode&std::ios_base::in)) + return false; + HANDLE f{CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, nullptr)}; + if(f == INVALID_HANDLE_VALUE) return false; + + if(mFile != INVALID_HANDLE_VALUE) + CloseHandle(mFile); + mFile = f; + + setg(nullptr, nullptr, nullptr); + return true; +} +bool filebuf::open(const char *filename, std::ios_base::openmode mode) +{ + std::wstring wname{utf8_to_wstr(filename)}; + return open(wname.c_str(), mode); +} + + +ifstream::ifstream(const wchar_t *filename, std::ios_base::openmode mode) + : std::istream{nullptr} +{ + init(&mStreamBuf); + + // Set the failbit if the file failed to open. + if((mode&std::ios_base::out) || !mStreamBuf.open(filename, mode|std::ios_base::in)) + clear(failbit); +} + +ifstream::ifstream(const char *filename, std::ios_base::openmode mode) + : std::istream{nullptr} +{ + init(&mStreamBuf); + + // Set the failbit if the file failed to open. + if((mode&std::ios_base::out) || !mStreamBuf.open(filename, mode|std::ios_base::in)) + clear(failbit); +} + +/* This is only here to ensure the compiler doesn't define an implicit + * destructor, which it tries to automatically inline and subsequently complain + * it can't inline without excessive code growth. + */ +ifstream::~ifstream() { } + +} // namespace al + +#endif diff --git a/common/alfstream.h b/common/alfstream.h new file mode 100644 index 00000000..046a6e2a --- /dev/null +++ b/common/alfstream.h @@ -0,0 +1,70 @@ +#ifndef AL_FSTREAM_H +#define AL_FSTREAM_H + +#ifdef _WIN32 + +#define WIN32_LEAN_AND_MEAN +#include + +#include +#include +#include + + +namespace al { + +// Windows' std::ifstream fails with non-ANSI paths since the standard only +// specifies names using const char* (or std::string). MSVC has a non-standard +// extension using const wchar_t* (or std::wstring?) to handle Unicode paths, +// but not all Windows compilers support it. So we have to make our own istream +// that accepts UTF-8 paths and forwards to Unicode-aware I/O functions. +class filebuf final : public std::streambuf { + std::array mBuffer; + HANDLE mFile{INVALID_HANDLE_VALUE}; + + int_type underflow() override; + pos_type seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) override; + pos_type seekpos(pos_type pos, std::ios_base::openmode mode) override; + +public: + filebuf() = default; + ~filebuf() override; + + bool open(const wchar_t *filename, std::ios_base::openmode mode); + bool open(const char *filename, std::ios_base::openmode mode); + + bool is_open() const noexcept { return mFile != INVALID_HANDLE_VALUE; } +}; + +// Inherit from std::istream to use our custom streambuf +class ifstream final : public std::istream { + filebuf mStreamBuf; + +public: + ifstream(const wchar_t *filename, std::ios_base::openmode mode = std::ios_base::in); + ifstream(const std::wstring &filename, std::ios_base::openmode mode = std::ios_base::in) + : ifstream(filename.c_str(), mode) { } + ifstream(const char *filename, std::ios_base::openmode mode = std::ios_base::in); + ifstream(const std::string &filename, std::ios_base::openmode mode = std::ios_base::in) + : ifstream(filename.c_str(), mode) { } + ~ifstream() override; + + bool is_open() const noexcept { return mStreamBuf.is_open(); } +}; + +} // namespace al + +#else /* _WIN32 */ + +#include + +namespace al { + +using filebuf = std::filebuf; +using ifstream = std::ifstream; + +} // namespace al + +#endif /* _WIN32 */ + +#endif /* AL_FSTREAM_H */ -- cgit v1.2.3 From 24db8a3f4bdbd787c23ac6e2ec78c2bafed81f1f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 22 Sep 2019 21:19:19 -0700 Subject: Make the resampler type an enum class --- al/source.cpp | 4 ++-- al/state.cpp | 15 ++++++++------- alc/alu.cpp | 8 ++++---- alc/alu.h | 16 ++++++++-------- alc/backends/coreaudio.cpp | 2 +- alc/backends/wasapi.cpp | 2 +- alc/converter.cpp | 4 ++-- alc/mixvoice.cpp | 22 +++++++++++----------- 8 files changed, 37 insertions(+), 36 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index 7eda4fb6..3aaaaf90 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -1295,7 +1295,7 @@ bool SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a case AL_SOURCE_RESAMPLER_SOFT: CHECKSIZE(values, 1); - CHECKVAL(values[0] >= 0 && values[0] <= ResamplerMax); + CHECKVAL(values[0] >= 0 && values[0] <= static_cast(Resampler::Max)); Source->mResampler = static_cast(values[0]); return UpdateSourceProps(Source, Context); @@ -1836,7 +1836,7 @@ bool GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const a case AL_SOURCE_RESAMPLER_SOFT: CHECKSIZE(values, 1); - values[0] = Source->mResampler; + values[0] = static_cast(Source->mResampler); return true; case AL_SOURCE_SPATIALIZE_SOFT: diff --git a/al/state.cpp b/al/state.cpp index 74fb3b55..8f456ed3 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -196,7 +196,7 @@ START_API_FUNC break; case AL_DEFAULT_RESAMPLER_SOFT: - value = ResamplerDefault ? AL_TRUE : AL_FALSE; + value = static_cast(ResamplerDefault) ? AL_TRUE : AL_FALSE; break; default: @@ -243,7 +243,7 @@ START_API_FUNC break; case AL_NUM_RESAMPLERS_SOFT: - value = static_cast(ResamplerMax + 1); + value = static_cast(Resampler::Max) + 1.0; break; case AL_DEFAULT_RESAMPLER_SOFT: @@ -294,7 +294,7 @@ START_API_FUNC break; case AL_NUM_RESAMPLERS_SOFT: - value = static_cast(ResamplerMax + 1); + value = static_cast(Resampler::Max) + 1.0f; break; case AL_DEFAULT_RESAMPLER_SOFT: @@ -345,11 +345,11 @@ START_API_FUNC break; case AL_NUM_RESAMPLERS_SOFT: - value = ResamplerMax + 1; + value = static_cast(Resampler::Max) + 1; break; case AL_DEFAULT_RESAMPLER_SOFT: - value = ResamplerDefault; + value = static_cast(ResamplerDefault); break; default: @@ -396,7 +396,7 @@ START_API_FUNC break; case AL_NUM_RESAMPLERS_SOFT: - value = static_cast(ResamplerMax + 1); + value = static_cast(Resampler::Max) + 1; break; case AL_DEFAULT_RESAMPLER_SOFT: @@ -801,7 +801,8 @@ START_API_FUNC alCubicResampler, alBSinc12Resampler, alBSinc24Resampler, }; - static_assert(al::size(ResamplerNames) == ResamplerMax+1, "Incorrect ResamplerNames list"); + static_assert(al::size(ResamplerNames) == static_cast(Resampler::Max)+1, + "Incorrect ResamplerNames list"); ContextRef context{GetContextRef()}; if UNLIKELY(!context) return nullptr; diff --git a/alc/alu.cpp b/alc/alu.cpp index 606d8fdb..8affbde4 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -947,9 +947,9 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons voice->mStep = MAX_PITCH<mStep = maxu(fastf2u(Pitch * FRACTIONONE), 1); - if(props->mResampler == BSinc24Resampler) + if(props->mResampler == Resampler::BSinc24) BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc24); - else if(props->mResampler == BSinc12Resampler) + else if(props->mResampler == Resampler::BSinc12) BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc12); voice->mResampler = SelectResampler(props->mResampler); @@ -1277,9 +1277,9 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A voice->mStep = MAX_PITCH<mStep = maxu(fastf2u(Pitch * FRACTIONONE), 1); - if(props->mResampler == BSinc24Resampler) + if(props->mResampler == Resampler::BSinc24) BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc24); - else if(props->mResampler == BSinc12Resampler) + else if(props->mResampler == Resampler::BSinc12) BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc12); voice->mResampler = SelectResampler(props->mResampler); diff --git a/alc/alu.h b/alc/alu.h index 33c67630..aa698f7d 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -42,14 +42,14 @@ enum SpatializeMode { SpatializeAuto = AL_AUTO_SOFT }; -enum Resampler { - PointResampler, - LinearResampler, - FIR4Resampler, - BSinc12Resampler, - BSinc24Resampler, - - ResamplerMax = BSinc24Resampler +enum class Resampler { + Point, + Linear, + Cubic, + BSinc12, + BSinc24, + + Max = BSinc24 }; extern Resampler ResamplerDefault; diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 72754718..9e8291e2 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -618,7 +618,7 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) if(outputFormat.mSampleRate != mDevice->Frequency) mConverter = CreateSampleConverter(mDevice->FmtType, mDevice->FmtType, mFormat.mChannelsPerFrame, static_cast(hardwareFormat.mSampleRate), - mDevice->Frequency, BSinc24Resampler); + mDevice->Frequency, Resampler::BSinc24); mRing = CreateRingBuffer(outputFrameCount, mFrameSize, false); if(!mRing) return ALC_INVALID_VALUE; diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 1271eeaa..e1a8dc6f 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -1568,7 +1568,7 @@ HRESULT WasapiCapture::resetProxy() if(mDevice->Frequency != OutputType.Format.nSamplesPerSec || mDevice->FmtType != srcType) { mSampleConv = CreateSampleConverter(srcType, mDevice->FmtType, mDevice->channelsFromFmt(), - OutputType.Format.nSamplesPerSec, mDevice->Frequency, BSinc24Resampler); + OutputType.Format.nSamplesPerSec, mDevice->Frequency, Resampler::BSinc24); if(!mSampleConv) { ERR("Failed to create converter for %s format, dst: %s %uhz, src: %s %luhz\n", diff --git a/alc/converter.cpp b/alc/converter.cpp index 2ad2ac3b..6622a997 100644 --- a/alc/converter.cpp +++ b/alc/converter.cpp @@ -167,9 +167,9 @@ SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, converter->mResample = Resample_; else { - if(resampler == BSinc24Resampler) + if(resampler == Resampler::BSinc24) BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc24); - else if(resampler == BSinc12Resampler) + else if(resampler == Resampler::BSinc12) BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc12); converter->mResample = SelectResampler(resampler); } diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index bf10444a..99e4dc48 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -70,7 +70,7 @@ static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, static_assert(MAX_RESAMPLE_PADDING >= 24, "MAX_RESAMPLE_PADDING must be at least 24!"); -Resampler ResamplerDefault = LinearResampler; +Resampler ResamplerDefault{Resampler::Linear}; MixerFunc MixSamples = Mix_; RowMixerFunc MixRowSamples = MixRow_; @@ -139,9 +139,9 @@ ResamplerFunc SelectResampler(Resampler resampler) { switch(resampler) { - case PointResampler: + case Resampler::Point: return Resample_; - case LinearResampler: + case Resampler::Linear: #ifdef HAVE_NEON if((CPUCapFlags&CPU_CAP_NEON)) return Resample_; @@ -155,10 +155,10 @@ ResamplerFunc SelectResampler(Resampler resampler) return Resample_; #endif return Resample_; - case FIR4Resampler: + case Resampler::Cubic: return Resample_; - case BSinc12Resampler: - case BSinc24Resampler: + case Resampler::BSinc12: + case Resampler::BSinc24: #ifdef HAVE_NEON if((CPUCapFlags&CPU_CAP_NEON)) return Resample_; @@ -183,11 +183,11 @@ void aluInitMixer() const Resampler resampler; }; constexpr ResamplerEntry ResamplerList[]{ - { "none", PointResampler }, - { "point", PointResampler }, - { "cubic", FIR4Resampler }, - { "bsinc12", BSinc12Resampler }, - { "bsinc24", BSinc24Resampler }, + { "none", Resampler::Point }, + { "point", Resampler::Point }, + { "cubic", Resampler::Cubic }, + { "bsinc12", Resampler::BSinc12 }, + { "bsinc24", Resampler::BSinc24 }, }; const char *str{resopt->c_str()}; -- cgit v1.2.3 From 61ffa23e44c0e4ad9bdc99b1cf6e7ab7d36eb1c1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 22 Sep 2019 21:27:10 -0700 Subject: Fix a couple more conversion warnings --- alc/backends/winmm.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp index 41c110d7..d58fa959 100644 --- a/alc/backends/winmm.cpp +++ b/alc/backends/winmm.cpp @@ -138,7 +138,7 @@ struct WinMMPlayback final : public BackendBase { std::atomic mWritable{0u}; al::semaphore mSem; - int mIdx{0}; + ALuint mIdx{0u}; std::array mWaveBuffer{}; HWAVEOUT mOutHdl{nullptr}; @@ -195,7 +195,7 @@ FORCE_ALIGN int WinMMPlayback::mixerProc() continue; } - int widx{mIdx}; + size_t widx{mIdx}; do { WAVEHDR &waveHdr = mWaveBuffer[widx]; widx = (widx+1) % mWaveBuffer.size(); @@ -204,7 +204,7 @@ FORCE_ALIGN int WinMMPlayback::mixerProc() mWritable.fetch_sub(1, std::memory_order_acq_rel); waveOutWrite(mOutHdl, &waveHdr, sizeof(WAVEHDR)); } while(--todo); - mIdx = widx; + mIdx = static_cast(widx); } unlock(); @@ -381,7 +381,7 @@ struct WinMMCapture final : public BackendBase { std::atomic mReadable{0u}; al::semaphore mSem; - int mIdx{0}; + ALuint mIdx{0}; std::array mWaveBuffer{}; HWAVEIN mInHdl{nullptr}; @@ -439,7 +439,7 @@ int WinMMCapture::captureProc() continue; } - int widx{mIdx}; + size_t widx{mIdx}; do { WAVEHDR &waveHdr = mWaveBuffer[widx]; widx = (widx+1) % mWaveBuffer.size(); @@ -448,7 +448,7 @@ int WinMMCapture::captureProc() mReadable.fetch_sub(1, std::memory_order_acq_rel); waveInAddBuffer(mInHdl, &waveHdr, sizeof(WAVEHDR)); } while(--todo); - mIdx = widx; + mIdx = static_cast(widx); } unlock(); -- cgit v1.2.3 From 4a111f7671c19f3cc0306e91ebe117d6bf7046ec Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 22 Sep 2019 21:27:59 -0700 Subject: Update changelog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index cf69ff5b..dd491ff0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,7 +9,7 @@ openal-soft-1.20.0: Fixed OpenSL capture. - Fixed support for extended capture/playback formats with OpenSL. + Fixed support for extended capture formats with OpenSL. Fixed handling of WASAPI not reporting a default device. -- cgit v1.2.3 From 34a0fad6cd2513f640c58dcff16817d00cf00456 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Sep 2019 17:38:43 -0700 Subject: Use a unique_ptr to auto-free MYSOFA_HRTF --- utils/sofa-info.cpp | 79 ++++++++++++++++++++++------------------------------- 1 file changed, 32 insertions(+), 47 deletions(-) diff --git a/utils/sofa-info.cpp b/utils/sofa-info.cpp index 87531b37..32bef938 100644 --- a/utils/sofa-info.cpp +++ b/utils/sofa-info.cpp @@ -22,17 +22,23 @@ */ #include -#include #include +#include #include #include #include "win_main_utf8.h" + using uint = unsigned int; +struct MySofaDeleter { + void operator()(MYSOFA_HRTF *sofa) { mysofa_free(sofa); } +}; +using MySofaHrtfPtr = std::unique_ptr; + // Per-field measurement info. struct HrirFdT { float mDistance{0.0f}; @@ -45,20 +51,13 @@ static const char *SofaErrorStr(int err) { switch(err) { - case MYSOFA_OK: - return "OK"; - case MYSOFA_INVALID_FORMAT: - return "Invalid format"; - case MYSOFA_UNSUPPORTED_FORMAT: - return "Unsupported format"; - case MYSOFA_INTERNAL_ERROR: - return "Internal error"; - case MYSOFA_NO_MEMORY: - return "Out of memory"; - case MYSOFA_READ_ERROR: - return "Read error"; + case MYSOFA_OK: return "OK"; + case MYSOFA_INVALID_FORMAT: return "Invalid format"; + case MYSOFA_UNSUPPORTED_FORMAT: return "Unsupported format"; + case MYSOFA_INTERNAL_ERROR: return "Internal error"; + case MYSOFA_NO_MEMORY: return "Out of memory"; + case MYSOFA_READ_ERROR: return "Read error"; } - return "Unknown"; } @@ -237,10 +236,11 @@ static void PrintCompatibleLayout(const uint m, const float *xyzs) { float ev{90.0f + elems[ei]}; float eif{std::round(ev / step)}; + const uint ev_start{static_cast(eif)}; - if(std::fabs(eif - static_cast(eif)) < (0.1f / step)) + if(std::fabs(eif - static_cast(ev_start)) < (0.1f/step)) { - evStart = static_cast(eif); + evStart = ev_start; break; } } @@ -259,7 +259,7 @@ static void PrintCompatibleLayout(const uint m, const float *xyzs) for(uint ei{evStart};ei < evCount;ei++) { - float ev{-90.0f + ei * 180.0f / (evCount - 1)}; + float ev{-90.0f + static_cast(ei)*180.0f/static_cast(evCount - 1)}; uint azCount{GetUniquelySortedElems(m, aers.data(), 0, { nullptr, &ev, &dist }, { 0.1f, 0.1f, 0.001f }, elems.data())}; if(azCount > (m / 3)) @@ -312,48 +312,33 @@ static void PrintCompatibleLayout(const uint m, const float *xyzs) // Load and inspect the given SOFA file. static void SofaInfo(const char *filename) { - struct MYSOFA_EASY sofa; - - sofa.lookup = nullptr; - sofa.neighborhood = nullptr; - int err; - sofa.hrtf = mysofa_load(filename, &err); - - if(!sofa.hrtf) + MySofaHrtfPtr sofa{mysofa_load(filename, &err)}; + if(!sofa) { - mysofa_close(&sofa); fprintf(stdout, "Error: Could not load source file '%s'.\n", filename); return; } - err = mysofa_check(sofa.hrtf); + /* NOTE: Some valid SOFA files are failing this check. */ + err = mysofa_check(sofa.get()); if(err != MYSOFA_OK) -/* NOTE: Some valid SOFA files are failing this check. - { - mysofa_close(&sofa); - fprintf(stdout, "Error: Malformed source file '%s' (%s).\n", filename, SofaErrorStr(err)); - - return; - } -*/ - fprintf(stdout, "Warning: Supposedly malformed source file '%s' (%s).\n", filename, SofaErrorStr(err)); - - mysofa_tocartesian(sofa.hrtf); + fprintf(stdout, "Warning: Supposedly malformed source file '%s' (%s).\n", filename, + SofaErrorStr(err)); - PrintSofaAttributes("Info", sofa.hrtf->attributes); + mysofa_tocartesian(sofa.get()); - fprintf(stdout, "Measurements: %u\n", sofa.hrtf->M); - fprintf(stdout, "Receivers: %u\n", sofa.hrtf->R); - fprintf(stdout, "Emitters: %u\n", sofa.hrtf->E); - fprintf(stdout, "Samples: %u\n", sofa.hrtf->N); + PrintSofaAttributes("Info", sofa->attributes); - PrintSofaArray("SampleRate", &sofa.hrtf->DataSamplingRate); - PrintSofaArray("DataDelay", &sofa.hrtf->DataDelay); + fprintf(stdout, "Measurements: %u\n", sofa->M); + fprintf(stdout, "Receivers: %u\n", sofa->R); + fprintf(stdout, "Emitters: %u\n", sofa->E); + fprintf(stdout, "Samples: %u\n", sofa->N); - PrintCompatibleLayout(sofa.hrtf->M, sofa.hrtf->SourcePosition.values); + PrintSofaArray("SampleRate", &sofa->DataSamplingRate); + PrintSofaArray("DataDelay", &sofa->DataDelay); - mysofa_free(sofa.hrtf); + PrintCompatibleLayout(sofa->M, sofa->SourcePosition.values); } int main(int argc, char *argv[]) -- cgit v1.2.3 From e01b32f8e02730b9e4474bbfcdbf2b88fc6c16f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Sep 2019 18:37:36 -0700 Subject: Use istream for makemhr input --- utils/makemhr/loaddef.cpp | 255 +++++++++++++++++++++++---------------------- utils/makemhr/loaddef.h | 7 +- utils/makemhr/loadsofa.cpp | 41 ++++---- utils/makemhr/makemhr.cpp | 87 ++++++++-------- 4 files changed, 198 insertions(+), 192 deletions(-) diff --git a/utils/makemhr/loaddef.cpp b/utils/makemhr/loaddef.cpp index bc62b725..619f5104 100644 --- a/utils/makemhr/loaddef.cpp +++ b/utils/makemhr/loaddef.cpp @@ -23,14 +23,23 @@ #include "loaddef.h" +#include +#include +#include #include #include +#include +#include +#include #include -#include - -#include "mysofa.h" +#include +#include +#include "alfstream.h" #include "alstring.h" +#include "makemhr.h" + +#include "mysofa.h" // Constants for accessing the token reader's ring buffer. #define TR_RING_BITS (16) @@ -42,13 +51,16 @@ // Token reader state for parsing the data set definition. struct TokenReaderT { - FILE *mFile; - const char *mName; - uint mLine; - uint mColumn; - char mRing[TR_RING_SIZE]; - size_t mIn; - size_t mOut; + std::istream &mIStream; + const char *mName{}; + uint mLine{}; + uint mColumn{}; + char mRing[TR_RING_SIZE]{}; + std::streamsize mIn{}; + std::streamsize mOut{}; + + TokenReaderT(std::istream &istream) noexcept : mIStream{istream} { } + TokenReaderT(const TokenReaderT&) = default; }; @@ -140,7 +152,8 @@ struct SourceRefT { // Setup the reader on the given file. The filename can be NULL if no error // output is desired. -static void TrSetup(FILE *fp, const char *startbytes, size_t startbytecount, const char *filename, TokenReaderT *tr) +static void TrSetup(const char *startbytes, std::streamsize startbytecount, const char *filename, + TokenReaderT *tr) { const char *name = nullptr; @@ -161,7 +174,6 @@ static void TrSetup(FILE *fp, const char *startbytes, size_t startbytecount, con } } - tr->mFile = fp; tr->mName = name; tr->mLine = 1; tr->mColumn = 1; @@ -170,7 +182,7 @@ static void TrSetup(FILE *fp, const char *startbytes, size_t startbytecount, con if(startbytecount > 0) { - memcpy(tr->mRing, startbytes, startbytecount); + std::copy_n(startbytes, startbytecount, std::begin(tr->mRing)); tr->mIn += startbytecount; } } @@ -179,22 +191,27 @@ static void TrSetup(FILE *fp, const char *startbytes, size_t startbytecount, con // is text to process. static int TrLoad(TokenReaderT *tr) { - size_t toLoad, in, count; + std::istream &istream = tr->mIStream; - toLoad = TR_RING_SIZE - (tr->mIn - tr->mOut); - if(toLoad >= TR_LOAD_SIZE && !feof(tr->mFile)) + std::streamsize toLoad{TR_RING_SIZE - static_cast(tr->mIn - tr->mOut)}; + if(toLoad >= TR_LOAD_SIZE && istream.good()) { // Load TR_LOAD_SIZE (or less if at the end of the file) per read. toLoad = TR_LOAD_SIZE; - in = tr->mIn&TR_RING_MASK; - count = TR_RING_SIZE - in; + std::streamsize in{tr->mIn&TR_RING_MASK}; + std::streamsize count{TR_RING_SIZE - in}; if(count < toLoad) { - tr->mIn += fread(&tr->mRing[in], 1, count, tr->mFile); - tr->mIn += fread(&tr->mRing[0], 1, toLoad-count, tr->mFile); + istream.read(&tr->mRing[in], count); + tr->mIn += istream.gcount(); + istream.read(&tr->mRing[0], toLoad-count); + tr->mIn += istream.gcount(); } else - tr->mIn += fread(&tr->mRing[in], 1, toLoad, tr->mFile); + { + istream.read(&tr->mRing[in], toLoad); + tr->mIn += istream.gcount(); + } if(tr->mOut >= TR_RING_SIZE) { @@ -303,7 +320,8 @@ static int TrIsIdent(TokenReaderT *tr) // errors and will not proceed to the next token. static int TrIsOperator(TokenReaderT *tr, const char *op) { - size_t out, len; + std::streamsize out; + size_t len; char ch; if(!TrSkipWhitespace(tr)) @@ -598,26 +616,24 @@ static int TrReadOperator(TokenReaderT *tr, const char *op) // Read a binary value of the specified byte order and byte size from a file, // storing it as a 32-bit unsigned integer. -static int ReadBin4(FILE *fp, const char *filename, const ByteOrderT order, const uint bytes, uint32_t *out) +static int ReadBin4(std::istream &istream, const char *filename, const ByteOrderT order, const uint bytes, uint32_t *out) { uint8_t in[4]; - uint32_t accum; - uint i; - - if(fread(in, 1, bytes, fp) != bytes) + istream.read(reinterpret_cast(in), static_cast(bytes)); + if(istream.gcount() != bytes) { fprintf(stderr, "\nError: Bad read from file '%s'.\n", filename); return 0; } - accum = 0; + uint32_t accum{0}; switch(order) { case BO_LITTLE: - for(i = 0;i < bytes;i++) + for(uint i = 0;i < bytes;i++) accum = (accum<<8) | in[bytes - i - 1]; break; case BO_BIG: - for(i = 0;i < bytes;i++) + for(uint i = 0;i < bytes;i++) accum = (accum<<8) | in[i]; break; default: @@ -629,18 +645,19 @@ static int ReadBin4(FILE *fp, const char *filename, const ByteOrderT order, cons // Read a binary value of the specified byte order from a file, storing it as // a 64-bit unsigned integer. -static int ReadBin8(FILE *fp, const char *filename, const ByteOrderT order, uint64_t *out) +static int ReadBin8(std::istream &istream, const char *filename, const ByteOrderT order, uint64_t *out) { uint8_t in[8]; uint64_t accum; uint i; - if(fread(in, 1, 8, fp) != 8) + istream.read(reinterpret_cast(in), 8); + if(istream.gcount() != 8) { fprintf(stderr, "\nError: Bad read from file '%s'.\n", filename); return 0; } - accum = 0ULL; + accum = 0; switch(order) { case BO_LITTLE: @@ -664,7 +681,8 @@ static int ReadBin8(FILE *fp, const char *filename, const ByteOrderT order, uint * whether they are padded toward the MSB (negative) or LSB (positive). * Floating-point types are not normalized. */ -static int ReadBinAsDouble(FILE *fp, const char *filename, const ByteOrderT order, const ElementTypeT type, const uint bytes, const int bits, double *out) +static int ReadBinAsDouble(std::istream &istream, const char *filename, const ByteOrderT order, + const ElementTypeT type, const uint bytes, const int bits, double *out) { union { uint32_t ui; @@ -679,14 +697,14 @@ static int ReadBinAsDouble(FILE *fp, const char *filename, const ByteOrderT orde *out = 0.0; if(bytes > 4) { - if(!ReadBin8(fp, filename, order, &v8.ui)) + if(!ReadBin8(istream, filename, order, &v8.ui)) return 0; if(type == ET_FP) *out = v8.f; } else { - if(!ReadBin4(fp, filename, order, bytes, &v4.ui)) + if(!ReadBin4(istream, filename, order, bytes, &v4.ui)) return 0; if(type == ET_FP) *out = v4.f; @@ -745,7 +763,8 @@ static int ReadAsciiAsDouble(TokenReaderT *tr, const char *filename, const Eleme // Read the RIFF/RIFX WAVE format chunk from a file, validating it against // the source parameters and data set metrics. -static int ReadWaveFormat(FILE *fp, const ByteOrderT order, const uint hrirRate, SourceRefT *src) +static int ReadWaveFormat(std::istream &istream, const ByteOrderT order, const uint hrirRate, + SourceRefT *src) { uint32_t fourCC, chunkSize; uint32_t format, channels, rate, dummy, block, size, bits; @@ -753,21 +772,21 @@ static int ReadWaveFormat(FILE *fp, const ByteOrderT order, const uint hrirRate, chunkSize = 0; do { if(chunkSize > 0) - fseek(fp, static_cast(chunkSize), SEEK_CUR); - if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC) || - !ReadBin4(fp, src->mPath, order, 4, &chunkSize)) + istream.seekg(static_cast(chunkSize), std::ios::cur); + if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC) + || !ReadBin4(istream, src->mPath, order, 4, &chunkSize)) return 0; } while(fourCC != FOURCC_FMT); - if(!ReadBin4(fp, src->mPath, order, 2, &format) || - !ReadBin4(fp, src->mPath, order, 2, &channels) || - !ReadBin4(fp, src->mPath, order, 4, &rate) || - !ReadBin4(fp, src->mPath, order, 4, &dummy) || - !ReadBin4(fp, src->mPath, order, 2, &block)) + if(!ReadBin4(istream, src->mPath, order, 2, &format) + || !ReadBin4(istream, src->mPath, order, 2, &channels) + || !ReadBin4(istream, src->mPath, order, 4, &rate) + || !ReadBin4(istream, src->mPath, order, 4, &dummy) + || !ReadBin4(istream, src->mPath, order, 2, &block)) return 0; block /= channels; if(chunkSize > 14) { - if(!ReadBin4(fp, src->mPath, order, 2, &size)) + if(!ReadBin4(istream, src->mPath, order, 2, &size)) return 0; size /= 8; if(block > size) @@ -777,23 +796,23 @@ static int ReadWaveFormat(FILE *fp, const ByteOrderT order, const uint hrirRate, size = block; if(format == WAVE_FORMAT_EXTENSIBLE) { - fseek(fp, 2, SEEK_CUR); - if(!ReadBin4(fp, src->mPath, order, 2, &bits)) + istream.seekg(2, std::ios::cur); + if(!ReadBin4(istream, src->mPath, order, 2, &bits)) return 0; if(bits == 0) bits = 8 * size; - fseek(fp, 4, SEEK_CUR); - if(!ReadBin4(fp, src->mPath, order, 2, &format)) + istream.seekg(4, std::ios::cur); + if(!ReadBin4(istream, src->mPath, order, 2, &format)) return 0; - fseek(fp, static_cast(chunkSize - 26), SEEK_CUR); + istream.seekg(static_cast(chunkSize - 26), std::ios::cur); } else { bits = 8 * size; if(chunkSize > 14) - fseek(fp, static_cast(chunkSize - 16), SEEK_CUR); + istream.seekg(static_cast(chunkSize - 16), std::ios::cur); else - fseek(fp, static_cast(chunkSize - 14), SEEK_CUR); + istream.seekg(static_cast(chunkSize - 14), std::ios::cur); } if(format != WAVE_FORMAT_PCM && format != WAVE_FORMAT_IEEE_FLOAT) { @@ -840,7 +859,8 @@ static int ReadWaveFormat(FILE *fp, const ByteOrderT order, const uint hrirRate, } // Read a RIFF/RIFX WAVE data chunk, converting all elements to doubles. -static int ReadWaveData(FILE *fp, const SourceRefT *src, const ByteOrderT order, const uint n, double *hrir) +static int ReadWaveData(std::istream &istream, const SourceRefT *src, const ByteOrderT order, + const uint n, double *hrir) { int pre, post, skip; uint i; @@ -852,19 +872,20 @@ static int ReadWaveData(FILE *fp, const SourceRefT *src, const ByteOrderT order, { skip += pre; if(skip > 0) - fseek(fp, skip, SEEK_CUR); - if(!ReadBinAsDouble(fp, src->mPath, order, src->mType, src->mSize, src->mBits, &hrir[i])) + istream.seekg(skip, std::ios::cur); + if(!ReadBinAsDouble(istream, src->mPath, order, src->mType, src->mSize, src->mBits, &hrir[i])) return 0; skip = post; } if(skip > 0) - fseek(fp, skip, SEEK_CUR); + istream.seekg(skip, std::ios::cur); return 1; } // Read the RIFF/RIFX WAVE list or data chunk, converting all elements to // doubles. -static int ReadWaveList(FILE *fp, const SourceRefT *src, const ByteOrderT order, const uint n, double *hrir) +static int ReadWaveList(std::istream &istream, const SourceRefT *src, const ByteOrderT order, + const uint n, double *hrir) { uint32_t fourCC, chunkSize, listSize, count; uint block, skip, offset, i; @@ -872,8 +893,8 @@ static int ReadWaveList(FILE *fp, const SourceRefT *src, const ByteOrderT order, for(;;) { - if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC) || - !ReadBin4(fp, src->mPath, order, 4, &chunkSize)) + if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC) + || !ReadBin4(istream, src->mPath, order, 4, &chunkSize)) return 0; if(fourCC == FOURCC_DATA) @@ -885,21 +906,21 @@ static int ReadWaveList(FILE *fp, const SourceRefT *src, const ByteOrderT order, fprintf(stderr, "\nError: Bad read from file '%s'.\n", src->mPath); return 0; } - fseek(fp, static_cast(src->mOffset * block), SEEK_CUR); - if(!ReadWaveData(fp, src, order, n, &hrir[0])) + istream.seekg(static_cast(src->mOffset * block), std::ios::cur); + if(!ReadWaveData(istream, src, order, n, &hrir[0])) return 0; return 1; } else if(fourCC == FOURCC_LIST) { - if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC)) + if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC)) return 0; chunkSize -= 4; if(fourCC == FOURCC_WAVL) break; } if(chunkSize > 0) - fseek(fp, static_cast(chunkSize), SEEK_CUR); + istream.seekg(static_cast(chunkSize), std::ios::cur); } listSize = chunkSize; block = src->mSize * src->mSkip; @@ -908,8 +929,8 @@ static int ReadWaveList(FILE *fp, const SourceRefT *src, const ByteOrderT order, lastSample = 0.0; while(offset < n && listSize > 8) { - if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC) || - !ReadBin4(fp, src->mPath, order, 4, &chunkSize)) + if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC) + || !ReadBin4(istream, src->mPath, order, 4, &chunkSize)) return 0; listSize -= 8 + chunkSize; if(fourCC == FOURCC_DATA) @@ -917,13 +938,13 @@ static int ReadWaveList(FILE *fp, const SourceRefT *src, const ByteOrderT order, count = chunkSize / block; if(count > skip) { - fseek(fp, static_cast(skip * block), SEEK_CUR); + istream.seekg(static_cast(skip * block), std::ios::cur); chunkSize -= skip * block; count -= skip; skip = 0; if(count > (n - offset)) count = n - offset; - if(!ReadWaveData(fp, src, order, count, &hrir[offset])) + if(!ReadWaveData(istream, src, order, count, &hrir[offset])) return 0; chunkSize -= count * block; offset += count; @@ -937,7 +958,7 @@ static int ReadWaveList(FILE *fp, const SourceRefT *src, const ByteOrderT order, } else if(fourCC == FOURCC_SLNT) { - if(!ReadBin4(fp, src->mPath, order, 4, &count)) + if(!ReadBin4(istream, src->mPath, order, 4, &count)) return 0; chunkSize -= 4; if(count > skip) @@ -957,7 +978,7 @@ static int ReadWaveList(FILE *fp, const SourceRefT *src, const ByteOrderT order, } } if(chunkSize > 0) - fseek(fp, static_cast(chunkSize), SEEK_CUR); + istream.seekg(static_cast(chunkSize), std::ios::cur); } if(offset < n) { @@ -969,13 +990,14 @@ static int ReadWaveList(FILE *fp, const SourceRefT *src, const ByteOrderT order, // Load a source HRIR from an ASCII text file containing a list of elements // separated by whitespace or common list operators (',', ';', ':', '|'). -static int LoadAsciiSource(FILE *fp, const SourceRefT *src, const uint n, double *hrir) +static int LoadAsciiSource(std::istream &istream, const SourceRefT *src, + const uint n, double *hrir) { - TokenReaderT tr; + TokenReaderT tr{istream}; uint i, j; double dummy; - TrSetup(fp, nullptr, 0, nullptr, &tr); + TrSetup(nullptr, 0, nullptr, &tr); for(i = 0;i < src->mOffset;i++) { if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, static_cast(src->mBits), &dummy)) @@ -995,29 +1017,29 @@ static int LoadAsciiSource(FILE *fp, const SourceRefT *src, const uint n, double } // Load a source HRIR from a binary file. -static int LoadBinarySource(FILE *fp, const SourceRefT *src, const ByteOrderT order, const uint n, double *hrir) +static int LoadBinarySource(std::istream &istream, const SourceRefT *src, const ByteOrderT order, + const uint n, double *hrir) { - uint i; - - fseek(fp, static_cast(src->mOffset), SEEK_SET); - for(i = 0;i < n;i++) + istream.seekg(static_cast(src->mOffset), std::ios::beg); + for(uint i{0};i < n;i++) { - if(!ReadBinAsDouble(fp, src->mPath, order, src->mType, src->mSize, src->mBits, &hrir[i])) + if(!ReadBinAsDouble(istream, src->mPath, order, src->mType, src->mSize, src->mBits, &hrir[i])) return 0; if(src->mSkip > 0) - fseek(fp, static_cast(src->mSkip), SEEK_CUR); + istream.seekg(static_cast(src->mSkip), std::ios::cur); } return 1; } // Load a source HRIR from a RIFF/RIFX WAVE file. -static int LoadWaveSource(FILE *fp, SourceRefT *src, const uint hrirRate, const uint n, double *hrir) +static int LoadWaveSource(std::istream &istream, SourceRefT *src, const uint hrirRate, + const uint n, double *hrir) { uint32_t fourCC, dummy; ByteOrderT order; - if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC) || - !ReadBin4(fp, src->mPath, BO_LITTLE, 4, &dummy)) + if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC) + || !ReadBin4(istream, src->mPath, BO_LITTLE, 4, &dummy)) return 0; if(fourCC == FOURCC_RIFF) order = BO_LITTLE; @@ -1029,16 +1051,16 @@ static int LoadWaveSource(FILE *fp, SourceRefT *src, const uint hrirRate, const return 0; } - if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC)) + if(!ReadBin4(istream, src->mPath, BO_LITTLE, 4, &fourCC)) return 0; if(fourCC != FOURCC_WAVE) { fprintf(stderr, "\nError: Not a RIFF/RIFX WAVE file '%s'.\n", src->mPath); return 0; } - if(!ReadWaveFormat(fp, order, hrirRate, src)) + if(!ReadWaveFormat(istream, order, hrirRate, src)) return 0; - if(!ReadWaveList(fp, src, order, n, hrir)) + if(!ReadWaveList(istream, src, order, n, hrir)) return 0; return 1; } @@ -1068,14 +1090,9 @@ static MYSOFA_EASY* LoadSofaFile(SourceRefT *src, const uint hrirRate, const uin fprintf(stderr, "\nError: Could not load source file '%s'.\n", src->mPath); return nullptr; } + /* NOTE: Some valid SOFA files are failing this check. */ err = mysofa_check(sofa->hrtf); if(err != MYSOFA_OK) -/* NOTE: Some valid SOFA files are failing this check. - { - mysofa_close(sofa); - fprintf(stderr, "\nError: Malformed source file '%s'.\n", src->mPath); - return nullptr; - }*/ fprintf(stderr, "\nWarning: Supposedly malformed source file '%s'.\n", src->mPath); if((src->mOffset + n) > sofa->hrtf->N) { @@ -1156,41 +1173,40 @@ static int LoadSofaSource(SourceRefT *src, const uint hrirRate, const uint n, do // Load a source HRIR from a supported file type. static int LoadSource(SourceRefT *src, const uint hrirRate, const uint n, double *hrir) { - FILE *fp{nullptr}; + std::unique_ptr istream; if(src->mFormat != SF_SOFA) { if(src->mFormat == SF_ASCII) - fp = fopen(src->mPath, "r"); + istream.reset(new al::ifstream{src->mPath}); else - fp = fopen(src->mPath, "rb"); - if(fp == nullptr) + istream.reset(new al::ifstream{src->mPath, std::ios::binary}); + if(!istream->good()) { fprintf(stderr, "\nError: Could not open source file '%s'.\n", src->mPath); return 0; } } - int result; + int result{0}; switch(src->mFormat) { case SF_ASCII: - result = LoadAsciiSource(fp, src, n, hrir); + result = LoadAsciiSource(*istream, src, n, hrir); break; case SF_BIN_LE: - result = LoadBinarySource(fp, src, BO_LITTLE, n, hrir); + result = LoadBinarySource(*istream, src, BO_LITTLE, n, hrir); break; case SF_BIN_BE: - result = LoadBinarySource(fp, src, BO_BIG, n, hrir); + result = LoadBinarySource(*istream, src, BO_BIG, n, hrir); break; case SF_WAVE: - result = LoadWaveSource(fp, src, hrirRate, n, hrir); + result = LoadWaveSource(*istream, src, hrirRate, n, hrir); break; case SF_SOFA: result = LoadSofaSource(src, hrirRate, n, hrir); break; - default: - result = 0; + case SF_NONE: + break; } - if(fp) fclose(fp); return result; } @@ -1833,21 +1849,20 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData) if(fi >= hData->mFdCount) continue; - double ef{(90.0 + aer[1]) * (hData->mFds[fi].mEvCount - 1) / 180.0}; + double ef{(90.0 + aer[1]) / 180.0 * (hData->mFds[fi].mEvCount - 1)}; ei = static_cast(std::round(ef)); - ef = (ef - ei) * 180.0f / (hData->mFds[fi].mEvCount - 1); + ef = (ef - ei) * 180.0 / (hData->mFds[fi].mEvCount - 1); if(std::abs(ef) >= 0.1) continue; - double af{aer[0] * hData->mFds[fi].mEvs[ei].mAzCount / 360.0f}; + double af{aer[0] / 360.0 * hData->mFds[fi].mEvs[ei].mAzCount}; ai = static_cast(std::round(af)); - af = (af - ai) * 360.0f / hData->mFds[fi].mEvs[ei].mAzCount; + af = (af - ai) * 360.0 / hData->mFds[fi].mEvs[ei].mAzCount; ai = ai % hData->mFds[fi].mEvs[ei].mAzCount; if(std::abs(af) >= 0.1) continue; HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; - if(azd->mIrs[0] != nullptr) { TrErrorAt(tr, line, col, "Redefinition of source [ %d, %d, %d ].\n", fi, ei, ai); @@ -2003,24 +2018,16 @@ static int ProcessSources(TokenReaderT *tr, HrirDataT *hData) } -bool LoadDefInput(FILE *fp, const char *startbytes, size_t startbytecount, const char *filename, - const uint fftSize, const uint truncSize, const ChannelModeT chanMode, HrirDataT *hData) +bool LoadDefInput(std::istream &istream, const char *startbytes, std::streamsize startbytecount, + const char *filename, const uint fftSize, const uint truncSize, const ChannelModeT chanMode, + HrirDataT *hData) { - TokenReaderT tr; + TokenReaderT tr{istream}; - TrSetup(fp, startbytes, startbytecount, filename, &tr); - if(!ProcessMetrics(&tr, fftSize, truncSize, chanMode, hData)) - { - if(fp != stdin) - fclose(fp); - return false; - } - if(!ProcessSources(&tr, hData)) - { - if(fp != stdin) - fclose(fp); + TrSetup(startbytes, startbytecount, filename, &tr); + if(!ProcessMetrics(&tr, fftSize, truncSize, chanMode, hData) + || !ProcessSources(&tr, hData)) return false; - } return true; } diff --git a/utils/makemhr/loaddef.h b/utils/makemhr/loaddef.h index 05862228..34fbb832 100644 --- a/utils/makemhr/loaddef.h +++ b/utils/makemhr/loaddef.h @@ -1,12 +1,13 @@ #ifndef LOADDEF_H #define LOADDEF_H -#include +#include #include "makemhr.h" -bool LoadDefInput(FILE *fp, const char *startbytes, size_t startbytecount, const char *filename, - const uint fftSize, const uint truncSize, const ChannelModeT chanMode, HrirDataT *hData); +bool LoadDefInput(std::istream &istream, const char *startbytes, std::streamsize startbytecount, + const char *filename, const uint fftSize, const uint truncSize, const ChannelModeT chanMode, + HrirDataT *hData); #endif /* LOADDEF_H */ diff --git a/utils/makemhr/loadsofa.cpp b/utils/makemhr/loadsofa.cpp index 219eb558..e0c08349 100644 --- a/utils/makemhr/loadsofa.cpp +++ b/utils/makemhr/loadsofa.cpp @@ -21,13 +21,20 @@ * Or visit: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ +#include "loadsofa.h" + +#include +#include +#include +#include #include #include -#include +#include +#include -#include "mysofa.h" +#include "makemhr.h" -#include "loadsofa.h" +#include "mysofa.h" static const char *SofaErrorStr(int err) @@ -216,10 +223,11 @@ static bool PrepareLayout(const uint m, const float *xyzs, HrirDataT *hData) { float ev{90.0f + elems[ei]}; float eif{std::round(ev / step)}; + const uint ei_start{static_cast(eif)}; - if(std::fabs(eif - static_cast(eif)) < (0.1f / step)) + if(std::fabs(eif - static_cast(ei_start)) < (0.1f/step)) { - evStart = static_cast(eif); + evStart = ei_start; break; } } @@ -428,8 +436,8 @@ static double CalcHrirOnset(const uint rate, const uint n, std::vector & } double mag{std::accumulate(upsampled.cbegin(), upsampled.cend(), double{0.0}, - [](const double mag, const double sample) -> double - { return std::max(mag, std::abs(sample)); })}; + [](const double magnitude, const double sample) -> double + { return std::max(magnitude, std::abs(sample)); })}; mag *= 0.15; auto iter = std::find_if(upsampled.cbegin(), upsampled.cend(), @@ -487,14 +495,14 @@ static bool LoadResponses(MYSOFA_HRTF *sofaHrtf, HrirDataT *hData) if(field == hData->mFds.cend()) continue; - double ef{(90.0+aer[1]) * (field->mEvCount-1) / 180.0}; + double ef{(90.0+aer[1]) / 180.0 * (field->mEvCount-1)}; auto ei = static_cast(std::round(ef)); - ef = (ef-ei) * 180.0f / (field->mEvCount-1); + ef = (ef-ei) * 180.0 / (field->mEvCount-1); if(std::abs(ef) >= 0.1) continue; - double af{aer[0] * field->mEvs[ei].mAzCount / 360.0f}; + double af{aer[0] / 360.0 * field->mEvs[ei].mAzCount}; auto ai = static_cast(std::round(af)); - af = (af-ai) * 360.0f / field->mEvs[ei].mAzCount; + af = (af-ai) * 360.0 / field->mEvs[ei].mAzCount; ai %= field->mEvs[ei].mAzCount; if(std::abs(af) >= 0.1) continue; @@ -541,14 +549,9 @@ bool LoadSofaFile(const char *filename, const uint fftSize, const uint truncSize return false; } + /* NOTE: Some valid SOFA files are failing this check. */ err = mysofa_check(sofaHrtf.get()); if(err != MYSOFA_OK) -/* NOTE: Some valid SOFA files are failing this check. - { - fprintf(stdout, "Error: Malformed source file '%s' (%s).\n", filename, SofaErrorStr(err)); - return false; - } -*/ fprintf(stderr, "Warning: Supposedly malformed source file '%s' (%s).\n", filename, SofaErrorStr(err)); @@ -589,8 +592,8 @@ bool LoadSofaFile(const char *filename, const uint fftSize, const uint truncSize /* Assume a default head radius of 9cm. */ hData->mRadius = 0.09; - if(!PrepareSampleRate(sofaHrtf.get(), hData) || !PrepareDelay(sofaHrtf.get(), hData) || - !CheckIrData(sofaHrtf.get())) + if(!PrepareSampleRate(sofaHrtf.get(), hData) || !PrepareDelay(sofaHrtf.get(), hData) + || !CheckIrData(sofaHrtf.get())) return false; if(!PrepareLayout(sofaHrtf->M, sofaHrtf->SourcePosition.values, hData)) return false; diff --git a/utils/makemhr/makemhr.cpp b/utils/makemhr/makemhr.cpp index 8071ac18..3659d40b 100644 --- a/utils/makemhr/makemhr.cpp +++ b/utils/makemhr/makemhr.cpp @@ -74,6 +74,7 @@ #include #include #include +#include #include #include #include @@ -87,6 +88,7 @@ #include "../getopt.h" #endif +#include "alfstream.h" #include "alstring.h" #include "loaddef.h" #include "loadsofa.h" @@ -1321,32 +1323,32 @@ static void NormalizeHrirs(HrirDataT *hData) /* Find the maximum amplitude and RMS out of all the IRs. */ struct LevelPair { double amp, rms; }; - auto proc0_field = [channels,irSize](const LevelPair levels, const HrirFdT &field) -> LevelPair + auto proc0_field = [channels,irSize](const LevelPair levels0, const HrirFdT &field) -> LevelPair { - auto proc_elev = [channels,irSize](const LevelPair levels, const HrirEvT &elev) -> LevelPair + auto proc_elev = [channels,irSize](const LevelPair levels1, const HrirEvT &elev) -> LevelPair { - auto proc_azi = [channels,irSize](const LevelPair levels, const HrirAzT &azi) -> LevelPair + auto proc_azi = [channels,irSize](const LevelPair levels2, const HrirAzT &azi) -> LevelPair { - auto proc_channel = [irSize](const LevelPair levels, const double *ir) -> LevelPair + auto proc_channel = [irSize](const LevelPair levels3, const double *ir) -> LevelPair { /* Calculate the peak amplitude and RMS of this IR. */ auto current = std::accumulate(ir, ir+irSize, LevelPair{0.0, 0.0}, - [](const LevelPair current, const double impulse) -> LevelPair + [](const LevelPair cur, const double impulse) -> LevelPair { - return LevelPair{std::max(std::abs(impulse), current.amp), - current.rms + impulse*impulse}; + return {std::max(std::abs(impulse), cur.amp), + cur.rms + impulse*impulse}; }); current.rms = std::sqrt(current.rms / irSize); /* Accumulate levels by taking the maximum amplitude and RMS. */ - return LevelPair{std::max(current.amp, levels.amp), - std::max(current.rms, levels.rms)}; + return LevelPair{std::max(current.amp, levels3.amp), + std::max(current.rms, levels3.rms)}; }; - return std::accumulate(azi.mIrs, azi.mIrs+channels, levels, proc_channel); + return std::accumulate(azi.mIrs, azi.mIrs+channels, levels2, proc_channel); }; - return std::accumulate(elev.mAzs, elev.mAzs+elev.mAzCount, levels, proc_azi); + return std::accumulate(elev.mAzs, elev.mAzs+elev.mAzCount, levels1, proc_azi); }; - return std::accumulate(field.mEvs, field.mEvs+field.mEvCount, levels, proc_elev); + return std::accumulate(field.mEvs, field.mEvs+field.mEvCount, levels0, proc_elev); }; const auto maxlev = std::accumulate(hData->mFds.begin(), hData->mFds.begin()+hData->mFdCount, LevelPair{0.0, 0.0}, proc0_field); @@ -1528,64 +1530,59 @@ int PrepareHrirData(const uint fdCount, const double (&distances)[MAX_FD_COUNT], * resulting data set as desired. If the input name is NULL it will read * from standard input. */ -static int ProcessDefinition(const char *inName, const uint outRate, const ChannelModeT chanMode, const uint fftSize, const int equalize, const int surface, const double limit, const uint truncSize, const HeadModelT model, const double radius, const char *outName) +static int ProcessDefinition(const char *inName, const uint outRate, const ChannelModeT chanMode, + const uint fftSize, const int equalize, const int surface, const double limit, + const uint truncSize, const HeadModelT model, const double radius, const char *outName) { char rateStr[8+1], expName[MAX_PATH_LEN]; - char startbytes[4]{}; - size_t startbytecount{0u}; HrirDataT hData; - FILE *fp; - int ret; if(!inName) { inName = "stdin"; - fp = stdin; + fprintf(stdout, "Reading HRIR definition from %s...\n", inName); + if(!LoadDefInput(std::cin, nullptr, 0, inName, fftSize, truncSize, chanMode, &hData)) + return 0; } else { - fp = fopen(inName, "r"); - if(fp == nullptr) + std::unique_ptr input{new al::ifstream{inName}}; + if(!input->is_open()) { fprintf(stderr, "Error: Could not open input file '%s'\n", inName); return 0; } - startbytecount = fread(startbytes, 1, sizeof(startbytes), fp); - if(startbytecount != sizeof(startbytes)) + char startbytes[4]{}; + input->read(startbytes, sizeof(startbytes)); + std::streamsize startbytecount{input->gcount()}; + if(startbytecount != sizeof(startbytes) || !input->good()) { - fclose(fp); fprintf(stderr, "Error: Could not read input file '%s'\n", inName); return 0; } - if(startbytes[0] == '\x89' && startbytes[1] == 'H' && startbytes[2] == 'D' && - startbytes[3] == 'F') + if(startbytes[0] == '\x89' && startbytes[1] == 'H' && startbytes[2] == 'D' + && startbytes[3] == 'F') { - fclose(fp); - fp = nullptr; - + input = nullptr; fprintf(stdout, "Reading HRTF data from %s...\n", inName); if(!LoadSofaFile(inName, fftSize, truncSize, chanMode, &hData)) return 0; } - } - if(fp != nullptr) - { - fprintf(stdout, "Reading HRIR definition from %s...\n", inName); - const bool success{LoadDefInput(fp, startbytes, startbytecount, inName, fftSize, truncSize, - chanMode, &hData)}; - if(fp != stdin) - fclose(fp); - if(!success) - return 0; + else + { + fprintf(stdout, "Reading HRIR definition from %s...\n", inName); + if(!LoadDefInput(*input, startbytes, startbytecount, inName, fftSize, truncSize, chanMode, &hData)) + return 0; + } } if(equalize) { - uint c = (hData.mChannelType == CT_STEREO) ? 2 : 1; - uint m = 1 + hData.mFftSize / 2; - std::vector dfa(c * m); + uint c{(hData.mChannelType == CT_STEREO) ? 2u : 1u}; + uint m{hData.mFftSize/2u + 1u}; + auto dfa = std::vector(c * m); if(hData.mFdCount > 1) { @@ -1614,12 +1611,10 @@ static int ProcessDefinition(const char *inName, const uint outRate, const Chann NormalizeHrirs(&hData); fprintf(stdout, "Calculating impulse delays...\n"); CalculateHrtds(model, (radius > DEFAULT_CUSTOM_RADIUS) ? radius : hData.mRadius, &hData); - snprintf(rateStr, 8, "%u", hData.mIrRate); - StrSubst(outName, "%r", rateStr, MAX_PATH_LEN, expName); + snprintf(rateStr, sizeof(rateStr), "%u", hData.mIrRate); + StrSubst(outName, "%r", rateStr, sizeof(expName), expName); fprintf(stdout, "Creating MHR data set %s...\n", expName); - ret = StoreMhr(&hData, expName); - - return ret; + return StoreMhr(&hData, expName); } static void PrintHelp(const char *argv0, FILE *ofile) -- cgit v1.2.3 From bf31ce688a0674f4e2eef676872303db23e0d0e7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Sep 2019 19:23:33 -0700 Subject: Add a missing header for Android --- alc/helpers.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/alc/helpers.cpp b/alc/helpers.cpp index 1d534619..2d532db1 100644 --- a/alc/helpers.cpp +++ b/alc/helpers.cpp @@ -70,6 +70,7 @@ #include "alcmain.h" #include "almalloc.h" +#include "alfstream.h" #include "alstring.h" #include "compat.h" #include "cpu_caps.h" -- cgit v1.2.3 From 96865d6b992d1f0d004ed49918a545306d10427e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Sep 2019 01:16:57 -0700 Subject: Only build ex-common as needed --- CMakeLists.txt | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c20fa021..2f833e41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1422,14 +1422,13 @@ IF(ALSOFT_UTILS) MESSAGE(STATUS "") ENDIF() -IF(ALSOFT_EXAMPLES OR ALSOFT_TESTS) - # Add a static library with common functions used by multiple targets - ADD_LIBRARY(ex-common STATIC examples/common/alhelpers.c) - TARGET_COMPILE_DEFINITIONS(ex-common PUBLIC ${CPP_DEFS}) - TARGET_INCLUDE_DIRECTORIES(ex-common PUBLIC ${OpenAL_SOURCE_DIR}/common) - TARGET_COMPILE_OPTIONS(ex-common PUBLIC ${C_FLAGS}) - TARGET_LINK_LIBRARIES(ex-common PUBLIC OpenAL) -ENDIF() + +# Add a static library with common functions used by multiple example targets +ADD_LIBRARY(ex-common STATIC EXCLUDE_FROM_ALL examples/common/alhelpers.c) +TARGET_COMPILE_DEFINITIONS(ex-common PUBLIC ${CPP_DEFS}) +TARGET_INCLUDE_DIRECTORIES(ex-common PUBLIC ${OpenAL_SOURCE_DIR}/common) +TARGET_COMPILE_OPTIONS(ex-common PUBLIC ${C_FLAGS}) +TARGET_LINK_LIBRARIES(ex-common PUBLIC OpenAL) IF(ALSOFT_TESTS) ADD_EXECUTABLE(altonegen examples/altonegen.c) -- cgit v1.2.3 From 6963712d46f1c6897dc887d8a7e3e8b734466589 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Sep 2019 13:51:40 -0700 Subject: Use an array to match the HRTF rendering method --- alc/panning.cpp | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/alc/panning.cpp b/alc/panning.cpp index 7e2408da..cdec7759 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -586,6 +586,18 @@ void InitHrtfPanning(ALCdevice *device) ALuint ambi_order{1}; if(auto modeopt = ConfigValueStr(device->DeviceName.c_str(), nullptr, "hrtf-mode")) { + struct HrtfModeEntry { + char name[8]; + RenderMode mode; + ALuint order; + }; + static constexpr HrtfModeEntry hrtf_modes[]{ + { "full", HrtfRender, 1 }, + { "ambi1", NormalRender, 1 }, + { "ambi2", NormalRender, 2 }, + { "ambi3", NormalRender, 3 }, + }; + const char *mode{modeopt->c_str()}; if(al::strcasecmp(mode, "basic") == 0) { @@ -593,25 +605,16 @@ void InitHrtfPanning(ALCdevice *device) mode = "ambi2"; } - if(al::strcasecmp(mode, "full") == 0) - device->mRenderMode = HrtfRender; - else if(al::strcasecmp(mode, "ambi1") == 0) - { - device->mRenderMode = NormalRender; - ambi_order = 1; - } - else if(al::strcasecmp(mode, "ambi2") == 0) - { - device->mRenderMode = NormalRender; - ambi_order = 2; - } - else if(al::strcasecmp(mode, "ambi3") == 0) + auto match_entry = [mode](const HrtfModeEntry &entry) -> bool + { return al::strcasecmp(mode, entry.name) == 0; }; + auto iter = std::find_if(std::begin(hrtf_modes), std::end(hrtf_modes), match_entry); + if(iter == std::end(hrtf_modes)) + ERR("Unexpected hrtf-mode: %s\n", mode); + else { - device->mRenderMode = NormalRender; - ambi_order = 3; + device->mRenderMode = iter->mode; + ambi_order = iter->order; } - else - ERR("Unexpected hrtf-mode: %s\n", mode); } TRACE("%s HRTF rendering enabled, using \"%s\"\n", (device->mRenderMode == HrtfRender) ? "Full" : -- cgit v1.2.3 From 16a715a2b51ca5563b21a6b694dd4a08728137b1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Sep 2019 21:49:12 -0700 Subject: Fix unsigned 8-bit buffers --- alc/mixvoice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 99e4dc48..bfb3b663 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -301,7 +301,7 @@ template<> struct FmtTypeTraits { using Type = ALubyte; static constexpr inline float to_float(const Type val) noexcept - { return val*(1.0f/128.0f) - 128.0f; } + { return val*(1.0f/128.0f) - 1.0f; } }; template<> struct FmtTypeTraits { -- cgit v1.2.3 From 5bb91b858f22bfda358635abe9d54841b7507bba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Sep 2019 22:27:12 -0700 Subject: Use blended HRIRs for the B-Format decode --- alc/hrtf.cpp | 133 ++++++++++++++++++++++++++++++++++++-------------------- alc/hrtf.h | 3 +- alc/panning.cpp | 41 +++++++++-------- 3 files changed, 107 insertions(+), 70 deletions(-) diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index 12d310d4..822ea54e 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -294,6 +294,12 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin const AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_CHANNELS], const size_t AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain) { + using double2 = std::array; + struct ImpulseResponse { + std::array hrir; + ALuint ldelay, rdelay; + }; + static constexpr int OrderFromChan[MAX_AMBI_CHANNELS]{ 0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3, }; @@ -308,30 +314,66 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin ALuint min_delay{HRTF_HISTORY_LENGTH}; ALuint max_delay{0}; - auto idx = al::vector(AmbiCount); - auto calc_idxs = [Hrtf,&max_delay,&min_delay](const AngularPoint &pt) noexcept -> ALuint + al::vector impres; impres.reserve(AmbiCount); + auto calc_res = [Hrtf,&max_delay,&min_delay](const AngularPoint &pt) -> ImpulseResponse { - auto &field = Hrtf->field[0]; - /* Calculate elevation index. */ - const auto ev_limit = static_cast(field.evCount-1); - const ALuint evidx{float2uint(clampf((90.0f+pt.Elev)/180.0f, 0.0f, 1.0f)*ev_limit + 0.5f)}; - - const ALuint azcount{Hrtf->elev[evidx].azCount}; - const ALuint iroffset{Hrtf->elev[evidx].irOffset}; + ImpulseResponse res; - /* Calculate azimuth index for this elevation. */ - const float az_norm{(360.0f+pt.Azim) / 360.0f}; - const ALuint azidx{float2uint(az_norm*static_cast(azcount) + 0.5f) % azcount}; + auto &field = Hrtf->field[0]; - /* Calculate the index for the impulse response. */ - const ALuint iridx{iroffset + azidx}; + /* Calculate the elevation indices. */ + const auto elev0 = CalcEvIndex(field.evCount, pt.Elev); + const ALsizei elev1_idx{mini(elev0.idx+1, field.evCount-1)}; + const ALsizei ir0offset{Hrtf->elev[elev0.idx].irOffset}; + const ALsizei ir1offset{Hrtf->elev[elev1_idx].irOffset}; + + /* Calculate azimuth indices. */ + const auto az0 = CalcAzIndex(Hrtf->elev[elev0.idx].azCount, pt.Azim); + const auto az1 = CalcAzIndex(Hrtf->elev[elev1_idx].azCount, pt.Azim); + + /* Calculate the HRIR indices to blend. */ + const ALuint idx[4]{ + static_cast(ir0offset + az0.idx), + static_cast(ir0offset + ((az0.idx+1) % Hrtf->elev[elev0.idx].azCount)), + static_cast(ir1offset + az1.idx), + static_cast(ir1offset + ((az1.idx+1) % Hrtf->elev[elev1_idx].azCount))}; + + /* Calculate bilinear blending weights. */ + const ALfloat blend[4]{ + (1.0f-elev0.blend) * (1.0f-az0.blend), + (1.0f-elev0.blend) * ( az0.blend), + ( elev0.blend) * (1.0f-az1.blend), + ( elev0.blend) * ( az1.blend)}; + + /* Calculate the blended HRIR delays. */ + res.ldelay = fastf2u( + Hrtf->delays[idx[0]][0]*blend[0] + Hrtf->delays[idx[1]][0]*blend[1] + + Hrtf->delays[idx[2]][0]*blend[2] + Hrtf->delays[idx[3]][0]*blend[3]); + res.rdelay = fastf2u( + Hrtf->delays[idx[0]][1]*blend[0] + Hrtf->delays[idx[1]][1]*blend[1] + + Hrtf->delays[idx[2]][1]*blend[2] + Hrtf->delays[idx[3]][1]*blend[3]); + + const size_t irSize{Hrtf->irSize}; + ASSUME(irSize >= MIN_IR_SIZE); + + /* Calculate the blended HRIR coefficients. */ + double *coeffout{al::assume_aligned<16>(&res.hrir[0][0])}; + std::fill(coeffout, coeffout + irSize*2, 0.0); + for(ALsizei c{0};c < 4;c++) + { + const ALfloat *srccoeffs{al::assume_aligned<16>(Hrtf->coeffs[idx[c]*irSize])}; + const ALfloat mult{blend[c]}; + auto blend_coeffs = [mult](const float src, const double coeff) noexcept -> double + { return src*mult + coeff; }; + std::transform(srccoeffs, srccoeffs + irSize*2, coeffout, coeffout, blend_coeffs); + } - min_delay = minu(min_delay, minu(Hrtf->delays[iridx][0], Hrtf->delays[iridx][1])); - max_delay = maxu(max_delay, maxu(Hrtf->delays[iridx][0], Hrtf->delays[iridx][1])); + min_delay = minu(min_delay, minu(res.ldelay, res.rdelay)); + max_delay = maxu(max_delay, maxu(res.ldelay, res.rdelay)); - return iridx; + return res; }; - std::transform(AmbiPoints, AmbiPoints+AmbiCount, idx.begin(), calc_idxs); + std::transform(AmbiPoints, AmbiPoints+AmbiCount, std::back_inserter(impres), calc_res); /* For dual-band processing, add a 16-sample delay to compensate for the HF * scale on the minimum-phase response. @@ -340,27 +382,26 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin const ALdouble xover_norm{400.0 / Hrtf->sampleRate}; BandSplitterR splitter{xover_norm}; - auto tmpres = al::vector,HRIR_LENGTH>>(NumChannels); - auto tmpfilt = al::vector>(3); + auto tmpres = al::vector>(NumChannels); + auto tmpflt = al::vector>(3); for(size_t c{0u};c < AmbiCount;++c) { - const ALfloat (*fir)[2]{&Hrtf->coeffs[idx[c] * Hrtf->irSize]}; - const ALuint ldelay{Hrtf->delays[idx[c]][0] - min_delay + base_delay}; - const ALuint rdelay{Hrtf->delays[idx[c]][1] - min_delay + base_delay}; + const al::span hrir{impres[c].hrir}; + const ALuint ldelay{impres[c].ldelay - min_delay + base_delay}; + const ALuint rdelay{impres[c].rdelay - min_delay + base_delay}; - if(!DualBand) + if /*constexpr*/(!DualBand) { /* For single-band decoding, apply the HF scale to the response. */ for(ALuint i{0u};i < NumChannels;++i) { - const ALdouble mult{ALdouble{AmbiOrderHFGain[OrderFromChan[i]]} * - AmbiMatrix[c][i]}; + const double mult{double{AmbiOrderHFGain[OrderFromChan[i]]} * AmbiMatrix[c][i]}; const ALuint numirs{minu(Hrtf->irSize, HRIR_LENGTH-maxu(ldelay, rdelay))}; ALuint lidx{ldelay}, ridx{rdelay}; for(ALuint j{0};j < numirs;++j) { - tmpres[i][lidx++][0] += fir[j][0] * mult; - tmpres[i][ridx++][1] += fir[j][1] * mult; + tmpres[i][lidx++][0] += hrir[j][0] * mult; + tmpres[i][ridx++][1] += hrir[j][1] * mult; } } continue; @@ -373,24 +414,23 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin */ /* Load the (left) HRIR backwards, into a temp buffer with padding. */ - std::fill(tmpfilt[2].begin(), tmpfilt[2].end(), 0.0); - std::transform(fir, fir+Hrtf->irSize, tmpfilt[2].rbegin() + HRIR_LENGTH*3, - [](const ALfloat (&ir)[2]) noexcept -> ALdouble { return ir[0]; }); + std::fill(tmpflt[2].begin(), tmpflt[2].end(), 0.0); + std::transform(hrir.begin(), hrir.begin()+Hrtf->irSize, tmpflt[2].rbegin() + HRIR_LENGTH*3, + [](const double2 &ir) noexcept -> double { return ir[0]; }); /* Apply the all-pass on the reversed signal and reverse the resulting * sample array. This produces the forward response with a backwards * phase-shift (+n degrees becomes -n degrees). */ - splitter.applyAllpass(tmpfilt[2].data(), tmpfilt[2].size()); - std::reverse(tmpfilt[2].begin(), tmpfilt[2].end()); + splitter.applyAllpass(tmpflt[2].data(), tmpflt[2].size()); + std::reverse(tmpflt[2].begin(), tmpflt[2].end()); /* Now apply the band-splitter. This applies the normal phase-shift, * which cancels out with the backwards phase-shift to get the original * phase on the split signal. */ splitter.clear(); - splitter.process(tmpfilt[0].data(), tmpfilt[1].data(), tmpfilt[2].data(), - tmpfilt[2].size()); + splitter.process(tmpflt[0].data(), tmpflt[1].data(), tmpflt[2].data(), tmpflt[2].size()); /* Apply left ear response with delay and HF scale. */ for(ALuint i{0u};i < NumChannels;++i) @@ -399,20 +439,19 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin const ALdouble hfgain{AmbiOrderHFGain[OrderFromChan[i]]}; ALuint j{HRIR_LENGTH*3 - ldelay}; for(ALuint lidx{0};lidx < HRIR_LENGTH;++lidx,++j) - tmpres[i][lidx][0] += (tmpfilt[0][j]*hfgain + tmpfilt[1][j]) * mult; + tmpres[i][lidx][0] += (tmpflt[0][j]*hfgain + tmpflt[1][j]) * mult; } /* Now run the same process on the right HRIR. */ - std::fill(tmpfilt[2].begin(), tmpfilt[2].end(), 0.0); - std::transform(fir, fir+Hrtf->irSize, tmpfilt[2].rbegin() + HRIR_LENGTH*3, - [](const ALfloat (&ir)[2]) noexcept -> ALdouble { return ir[1]; }); + std::fill(tmpflt[2].begin(), tmpflt[2].end(), 0.0); + std::transform(hrir.begin(), hrir.begin()+Hrtf->irSize, tmpflt[2].rbegin() + HRIR_LENGTH*3, + [](const double2 &ir) noexcept -> double { return ir[1]; }); - splitter.applyAllpass(tmpfilt[2].data(), tmpfilt[2].size()); - std::reverse(tmpfilt[2].begin(), tmpfilt[2].end()); + splitter.applyAllpass(tmpflt[2].data(), tmpflt[2].size()); + std::reverse(tmpflt[2].begin(), tmpflt[2].end()); splitter.clear(); - splitter.process(tmpfilt[0].data(), tmpfilt[1].data(), tmpfilt[2].data(), - tmpfilt[2].size()); + splitter.process(tmpflt[0].data(), tmpflt[1].data(), tmpflt[2].data(), tmpflt[2].size()); for(ALuint i{0u};i < NumChannels;++i) { @@ -420,15 +459,15 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin const ALdouble hfgain{AmbiOrderHFGain[OrderFromChan[i]]}; ALuint j{HRIR_LENGTH*3 - rdelay}; for(ALuint ridx{0};ridx < HRIR_LENGTH;++ridx,++j) - tmpres[i][ridx][1] += (tmpfilt[0][j]*hfgain + tmpfilt[1][j]) * mult; + tmpres[i][ridx][1] += (tmpflt[0][j]*hfgain + tmpflt[1][j]) * mult; } } - tmpfilt.clear(); - idx.clear(); + tmpflt.clear(); + impres.clear(); for(ALuint i{0u};i < NumChannels;++i) { - auto copy_arr = [](const std::array &in) noexcept -> float2 + auto copy_arr = [](const double2 &in) noexcept -> float2 { return float2{{static_cast(in[0]), static_cast(in[1])}}; }; std::transform(tmpres[i].begin(), tmpres[i].end(), state->Coeffs[i].begin(), copy_arr); diff --git a/alc/hrtf.h b/alc/hrtf.h index 20b3409d..c2f35f78 100644 --- a/alc/hrtf.h +++ b/alc/hrtf.h @@ -105,8 +105,7 @@ void GetHrtfCoeffs(const HrtfEntry *Hrtf, ALfloat elevation, ALfloat azimuth, AL * Produces HRTF filter coefficients for decoding B-Format, given a set of * virtual speaker positions, a matching decoding matrix, and per-order high- * frequency gains for the decoder. The calculated impulse responses are - * ordered and scaled according to the matrix input. Note the specified virtual - * positions should be in degrees, not radians! + * ordered and scaled according to the matrix input. */ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuint NumChannels, const AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_CHANNELS], diff --git a/alc/panning.cpp b/alc/panning.cpp index cdec7759..a2f1bed8 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -522,28 +522,27 @@ void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, void InitHrtfPanning(ALCdevice *device) { - /* NOTE: In degrees, and azimuth goes clockwise. */ static constexpr AngularPoint AmbiPoints[]{ - { 35.264390f, -45.000000f }, - { 35.264390f, 45.000000f }, - { 35.264390f, 135.000000f }, - { 35.264390f, -135.000000f }, - { -35.264390f, -45.000000f }, - { -35.264390f, 45.000000f }, - { -35.264390f, 135.000000f }, - { -35.264390f, -135.000000f }, - { 0.000000f, -20.905157f }, - { 0.000000f, 20.905157f }, - { 0.000000f, 159.094843f }, - { 0.000000f, -159.094843f }, - { 20.905157f, -90.000000f }, - { -20.905157f, -90.000000f }, - { -20.905157f, 90.000000f }, - { 20.905157f, 90.000000f }, - { 69.094843f, 0.000000f }, - { -69.094843f, 0.000000f }, - { -69.094843f, 180.000000f }, - { 69.094843f, 180.000000f }, + { Deg2Rad( 35.264390f), Deg2Rad( -45.000000f) }, + { Deg2Rad( 35.264390f), Deg2Rad( 45.000000f) }, + { Deg2Rad( 35.264390f), Deg2Rad( 135.000000f) }, + { Deg2Rad( 35.264390f), Deg2Rad(-135.000000f) }, + { Deg2Rad(-35.264390f), Deg2Rad( -45.000000f) }, + { Deg2Rad(-35.264390f), Deg2Rad( 45.000000f) }, + { Deg2Rad(-35.264390f), Deg2Rad( 135.000000f) }, + { Deg2Rad(-35.264390f), Deg2Rad(-135.000000f) }, + { Deg2Rad( 0.000000f), Deg2Rad( -20.905157f) }, + { Deg2Rad( 0.000000f), Deg2Rad( 20.905157f) }, + { Deg2Rad( 0.000000f), Deg2Rad( 159.094843f) }, + { Deg2Rad( 0.000000f), Deg2Rad(-159.094843f) }, + { Deg2Rad( 20.905157f), Deg2Rad( -90.000000f) }, + { Deg2Rad(-20.905157f), Deg2Rad( -90.000000f) }, + { Deg2Rad(-20.905157f), Deg2Rad( 90.000000f) }, + { Deg2Rad( 20.905157f), Deg2Rad( 90.000000f) }, + { Deg2Rad( 69.094843f), Deg2Rad( 0.000000f) }, + { Deg2Rad(-69.094843f), Deg2Rad( 0.000000f) }, + { Deg2Rad(-69.094843f), Deg2Rad( 180.000000f) }, + { Deg2Rad( 69.094843f), Deg2Rad( 180.000000f) }, }; static constexpr ALfloat AmbiMatrix[][MAX_AMBI_CHANNELS]{ { 5.00000000e-02f, 5.00000000e-02f, 5.00000000e-02f, 5.00000000e-02f, 6.45497224e-02f, 6.45497224e-02f, 0.00000000e+00f, 6.45497224e-02f, 0.00000000e+00f, 1.48264644e-02f, 6.33865691e-02f, 1.01126676e-01f, -7.36485380e-02f, -1.09260065e-02f, 7.08683387e-02f, -1.01622099e-01f }, -- cgit v1.2.3 From f009219523fd1bc7bcd2451f01e1635d0cec5cc3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Sep 2019 02:11:37 -0700 Subject: Avoid extraneous parameters --- alc/hrtf.cpp | 25 +++++++++++-------------- alc/hrtf.h | 7 ++++--- alc/panning.cpp | 4 ++-- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index 822ea54e..85b75e07 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -290,9 +290,9 @@ std::unique_ptr DirectHrtfState::Create(size_t num_chans) return std::unique_ptr{new (FamCount{num_chans}) DirectHrtfState{num_chans}}; } -void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuint NumChannels, - const AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_CHANNELS], - const size_t AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain) +void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, + const al::span AmbiPoints, const ALfloat (*AmbiMatrix)[MAX_AMBI_CHANNELS], + const ALfloat *AmbiOrderHFGain) { using double2 = std::array; struct ImpulseResponse { @@ -309,12 +309,9 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin */ static constexpr bool DualBand{true}; - ASSUME(NumChannels > 0); - ASSUME(AmbiCount > 0); - ALuint min_delay{HRTF_HISTORY_LENGTH}; ALuint max_delay{0}; - al::vector impres; impres.reserve(AmbiCount); + al::vector impres; impres.reserve(AmbiPoints.size()); auto calc_res = [Hrtf,&max_delay,&min_delay](const AngularPoint &pt) -> ImpulseResponse { ImpulseResponse res; @@ -373,7 +370,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin return res; }; - std::transform(AmbiPoints, AmbiPoints+AmbiCount, std::back_inserter(impres), calc_res); + std::transform(AmbiPoints.begin(), AmbiPoints.end(), std::back_inserter(impres), calc_res); /* For dual-band processing, add a 16-sample delay to compensate for the HF * scale on the minimum-phase response. @@ -382,9 +379,9 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin const ALdouble xover_norm{400.0 / Hrtf->sampleRate}; BandSplitterR splitter{xover_norm}; - auto tmpres = al::vector>(NumChannels); + auto tmpres = al::vector>(state->Coeffs.size()); auto tmpflt = al::vector>(3); - for(size_t c{0u};c < AmbiCount;++c) + for(size_t c{0u};c < AmbiPoints.size();++c) { const al::span hrir{impres[c].hrir}; const ALuint ldelay{impres[c].ldelay - min_delay + base_delay}; @@ -393,7 +390,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin if /*constexpr*/(!DualBand) { /* For single-band decoding, apply the HF scale to the response. */ - for(ALuint i{0u};i < NumChannels;++i) + for(size_t i{0u};i < state->Coeffs.size();++i) { const double mult{double{AmbiOrderHFGain[OrderFromChan[i]]} * AmbiMatrix[c][i]}; const ALuint numirs{minu(Hrtf->irSize, HRIR_LENGTH-maxu(ldelay, rdelay))}; @@ -433,7 +430,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin splitter.process(tmpflt[0].data(), tmpflt[1].data(), tmpflt[2].data(), tmpflt[2].size()); /* Apply left ear response with delay and HF scale. */ - for(ALuint i{0u};i < NumChannels;++i) + for(size_t i{0u};i < state->Coeffs.size();++i) { const ALdouble mult{AmbiMatrix[c][i]}; const ALdouble hfgain{AmbiOrderHFGain[OrderFromChan[i]]}; @@ -453,7 +450,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin splitter.clear(); splitter.process(tmpflt[0].data(), tmpflt[1].data(), tmpflt[2].data(), tmpflt[2].size()); - for(ALuint i{0u};i < NumChannels;++i) + for(size_t i{0u};i < state->Coeffs.size();++i) { const ALdouble mult{AmbiMatrix[c][i]}; const ALdouble hfgain{AmbiOrderHFGain[OrderFromChan[i]]}; @@ -465,7 +462,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuin tmpflt.clear(); impres.clear(); - for(ALuint i{0u};i < NumChannels;++i) + for(size_t i{0u};i < state->Coeffs.size();++i) { auto copy_arr = [](const double2 &in) noexcept -> float2 { return float2{{static_cast(in[0]), static_cast(in[1])}}; }; diff --git a/alc/hrtf.h b/alc/hrtf.h index c2f35f78..456f710c 100644 --- a/alc/hrtf.h +++ b/alc/hrtf.h @@ -9,6 +9,7 @@ #include "AL/al.h" #include "almalloc.h" +#include "alspan.h" #include "ambidefs.h" #include "atomic.h" #include "vector.h" @@ -107,8 +108,8 @@ void GetHrtfCoeffs(const HrtfEntry *Hrtf, ALfloat elevation, ALfloat azimuth, AL * frequency gains for the decoder. The calculated impulse responses are * ordered and scaled according to the matrix input. */ -void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALuint NumChannels, - const AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_CHANNELS], - const size_t AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain); +void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, + const al::span AmbiPoints, const ALfloat (*AmbiMatrix)[MAX_AMBI_CHANNELS], + const ALfloat *AmbiOrderHFGain); #endif /* ALC_HRTF_H */ diff --git a/alc/panning.cpp b/alc/panning.cpp index a2f1bed8..c2bcf223 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -639,8 +639,8 @@ void InitHrtfPanning(ALCdevice *device) ); AllocChannels(device, static_cast(count), device->channelsFromFmt()); - BuildBFormatHrtf(device->mHrtf, device->mHrtfState.get(), static_cast(count), - AmbiPoints, AmbiMatrix, al::size(AmbiPoints), AmbiOrderHFGain); + BuildBFormatHrtf(device->mHrtf, device->mHrtfState.get(), AmbiPoints, AmbiMatrix, + AmbiOrderHFGain); HrtfEntry *Hrtf{device->mHrtf}; InitNearFieldCtrl(device, Hrtf->field[0].distance, ambi_order, ChansPerOrder); -- cgit v1.2.3 From d50ca464cd5e4f07bc399fd244578b0b34d72aef Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Sep 2019 03:01:58 -0700 Subject: Use a span for holding the source handles --- al/source.cpp | 90 +++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 39 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index 3aaaaf90..a802cabc 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -2641,20 +2641,23 @@ START_API_FUNC if UNLIKELY(n <= 0) return; al::vector extra_sources; - std::array source_storage; - ALsource **srchandles{source_storage.data()}; - if UNLIKELY(static_cast(n) > source_storage.size()) + std::array source_storage; + al::span srchandles; + if LIKELY(static_cast(n) <= source_storage.size()) + srchandles = {source_storage.data(), static_cast(n)}; + else { extra_sources.resize(static_cast(n)); - srchandles = extra_sources.data(); + srchandles = {extra_sources.data(), extra_sources.size()}; } std::lock_guard _{context->mSourceLock}; - for(ALsizei i{0};i < n;i++) + for(auto &srchdl : srchandles) { - srchandles[i] = LookupSource(context.get(), sources[i]); - if(!srchandles[i]) - SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); + srchdl = LookupSource(context.get(), *sources); + if(!srchdl) + SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", *sources); + ++sources; } ALCdevice *device{context->mDevice.get()}; @@ -2663,7 +2666,7 @@ START_API_FUNC if UNLIKELY(!device->Connected.load(std::memory_order_acquire)) { /* TODO: Send state change event? */ - std::for_each(srchandles, srchandles+n, + std::for_each(srchandles.begin(), srchandles.end(), [](ALsource *source) -> void { source->OffsetType = AL_NONE; @@ -2684,10 +2687,10 @@ START_API_FUNC }; auto free_voices = std::accumulate(context->mVoices.begin(), context->mVoices.end(), ALuint{0}, count_free_voices); - if UNLIKELY(static_cast(n) > free_voices) + if UNLIKELY(srchandles.size() > free_voices) { /* Increase the number of voices to handle the request. */ - const ALuint need_voices{static_cast(n) - free_voices}; + const size_t need_voices{srchandles.size() - free_voices}; context->mVoices.resize(context->mVoices.size() + need_voices); } @@ -2869,7 +2872,7 @@ START_API_FUNC SendStateChangeEvent(context.get(), source->id, AL_PLAYING); } }; - std::for_each(srchandles, srchandles+n, start_source); + std::for_each(srchandles.begin(), srchandles.end(), start_source); } END_API_FUNC @@ -2890,20 +2893,23 @@ START_API_FUNC if UNLIKELY(n <= 0) return; al::vector extra_sources; - std::array source_storage; - ALsource **srchandles{source_storage.data()}; - if UNLIKELY(static_cast(n) > source_storage.size()) + std::array source_storage; + al::span srchandles; + if LIKELY(static_cast(n) <= source_storage.size()) + srchandles = {source_storage.data(), static_cast(n)}; + else { extra_sources.resize(static_cast(n)); - srchandles = extra_sources.data(); + srchandles = {extra_sources.data(), extra_sources.size()}; } std::lock_guard _{context->mSourceLock}; - for(ALsizei i{0};i < n;i++) + for(auto &srchdl : srchandles) { - srchandles[i] = LookupSource(context.get(), sources[i]); - if(!srchandles[i]) - SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); + srchdl = LookupSource(context.get(), *sources); + if(!srchdl) + SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", *sources); + ++sources; } ALCdevice *device{context->mDevice.get()}; @@ -2924,7 +2930,7 @@ START_API_FUNC SendStateChangeEvent(context.get(), source->id, AL_PAUSED); } }; - std::for_each(srchandles, srchandles+n, pause_source); + std::for_each(srchandles.begin(), srchandles.end(), pause_source); } END_API_FUNC @@ -2945,20 +2951,23 @@ START_API_FUNC if UNLIKELY(n <= 0) return; al::vector extra_sources; - std::array source_storage; - ALsource **srchandles{source_storage.data()}; - if UNLIKELY(static_cast(n) > source_storage.size()) + std::array source_storage; + al::span srchandles; + if LIKELY(static_cast(n) <= source_storage.size()) + srchandles = {source_storage.data(), static_cast(n)}; + else { extra_sources.resize(static_cast(n)); - srchandles = extra_sources.data(); + srchandles = {extra_sources.data(), extra_sources.size()}; } std::lock_guard _{context->mSourceLock}; - for(ALsizei i{0};i < n;i++) + for(auto &srchdl : srchandles) { - srchandles[i] = LookupSource(context.get(), sources[i]); - if(!srchandles[i]) - SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); + srchdl = LookupSource(context.get(), *sources); + if(!srchdl) + SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", *sources); + ++sources; } ALCdevice *device{context->mDevice.get()}; @@ -2989,7 +2998,7 @@ START_API_FUNC source->OffsetType = AL_NONE; source->Offset = 0.0; }; - std::for_each(srchandles, srchandles+n, stop_source); + std::for_each(srchandles.begin(), srchandles.end(), stop_source); } END_API_FUNC @@ -3010,20 +3019,23 @@ START_API_FUNC if UNLIKELY(n <= 0) return; al::vector extra_sources; - std::array source_storage; - ALsource **srchandles{source_storage.data()}; - if UNLIKELY(static_cast(n) > source_storage.size()) + std::array source_storage; + al::span srchandles; + if LIKELY(static_cast(n) <= source_storage.size()) + srchandles = {source_storage.data(), static_cast(n)}; + else { extra_sources.resize(static_cast(n)); - srchandles = extra_sources.data(); + srchandles = {extra_sources.data(), extra_sources.size()}; } std::lock_guard _{context->mSourceLock}; - for(ALsizei i{0};i < n;i++) + for(auto &srchdl : srchandles) { - srchandles[i] = LookupSource(context.get(), sources[i]); - if(!srchandles[i]) - SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", sources[i]); + srchdl = LookupSource(context.get(), *sources); + if(!srchdl) + SETERR_RETURN(context, AL_INVALID_NAME,, "Invalid source ID %u", *sources); + ++sources; } ALCdevice *device{context->mDevice.get()}; @@ -3050,7 +3062,7 @@ START_API_FUNC source->OffsetType = AL_NONE; source->Offset = 0.0; }; - std::for_each(srchandles, srchandles+n, rewind_source); + std::for_each(srchandles.begin(), srchandles.end(), rewind_source); } END_API_FUNC -- cgit v1.2.3 From 9b64e5e0db2a778313bb873bb38f481ce40efe31 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 26 Sep 2019 19:24:29 -0700 Subject: Implement a "fast" bsinc path This takes advantage of the fact than when increment <= 1 (when not down- sampling), the scale factor is always 0. As a result, the scale and scale-phase deltas never contribute to the filtered output. Removing those multiply+add operations cuts half of the work done by the inner loop. Sounds that do need to down-sample (when played with a high pitch, or is 48khz on 44.1khz output, for example), still go through the normal bsinc process. --- alc/alu.cpp | 4 ++-- alc/alu.h | 2 +- alc/converter.cpp | 2 +- alc/mixer/defs.h | 3 ++- alc/mixer/mixer_c.cpp | 25 +++++++++++++++++++++++++ alc/mixer/mixer_neon.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ alc/mixer/mixer_sse.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++++++ alc/mixvoice.cpp | 14 +++++++++++++- 8 files changed, 135 insertions(+), 6 deletions(-) diff --git a/alc/alu.cpp b/alc/alu.cpp index 8affbde4..86d2789e 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -951,7 +951,7 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc24); else if(props->mResampler == Resampler::BSinc12) BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc12); - voice->mResampler = SelectResampler(props->mResampler); + voice->mResampler = SelectResampler(props->mResampler, voice->mStep); /* Calculate gains */ const ALlistener &Listener = ALContext->mListener; @@ -1281,7 +1281,7 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc24); else if(props->mResampler == Resampler::BSinc12) BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc12); - voice->mResampler = SelectResampler(props->mResampler); + voice->mResampler = SelectResampler(props->mResampler, voice->mStep); ALfloat spread{0.0f}; if(props->Radius > Distance) diff --git a/alc/alu.h b/alc/alu.h index aa698f7d..e9858ddb 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -370,7 +370,7 @@ void aluInit(void); void aluInitMixer(void); -ResamplerFunc SelectResampler(Resampler resampler); +ResamplerFunc SelectResampler(Resampler resampler, ALuint increment); /* aluInitRenderer * diff --git a/alc/converter.cpp b/alc/converter.cpp index 6622a997..b0efb839 100644 --- a/alc/converter.cpp +++ b/alc/converter.cpp @@ -171,7 +171,7 @@ SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc24); else if(resampler == Resampler::BSinc12) BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc12); - converter->mResample = SelectResampler(resampler); + converter->mResample = SelectResampler(resampler, converter->mIncrement); } return converter; diff --git a/alc/mixer/defs.h b/alc/mixer/defs.h index 62e7d3ba..ce572973 100644 --- a/alc/mixer/defs.h +++ b/alc/mixer/defs.h @@ -23,7 +23,8 @@ enum ResampleType { PointTag, LerpTag, CubicTag, - BSincTag + BSincTag, + FastBSincTag }; template diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index 42d515ae..fafda70d 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -41,6 +41,26 @@ inline ALfloat do_bsinc(const InterpState &istate, const ALfloat *RESTRICT vals, r += (fil[j_f] + istate.bsinc.sf*scd[j_f] + pf*(phd[j_f] + istate.bsinc.sf*spd[j_f])) * vals[j_f]; return r; } +inline ALfloat do_fastbsinc(const InterpState &istate, const ALfloat *RESTRICT vals, const ALuint frac) +{ + const size_t m{istate.bsinc.m}; + + // Calculate the phase index and factor. +#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) + const ALuint pi{frac >> FRAC_PHASE_BITDIFF}; + const ALfloat pf{static_cast(frac & ((1< @@ -98,6 +118,11 @@ const ALfloat *Resample_(const InterpState *state, const ALfloat ALuint frac, ALuint increment, const al::span dst) { return DoResample(state, src-state->bsinc.l, frac, increment, dst); } +template<> +const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, + ALuint frac, ALuint increment, const al::span dst) +{ return DoResample(state, src-state->bsinc.l, frac, increment, dst); } + static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const ALuint IrSize, const HrirArray &Coeffs, const ALfloat left, const ALfloat right) diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index cd2b0ebc..178c7d6e 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -118,6 +118,50 @@ const ALfloat *Resample_(const InterpState *state, const ALflo return dst.begin(); } +template<> +const ALfloat *Resample_(const InterpState *state, + const ALfloat *RESTRICT src, ALuint frac, ALuint increment, const al::span dst) +{ + const ALfloat *const filter{state->bsinc.filter}; + const size_t m{state->bsinc.m}; + + src -= state->bsinc.l; + for(float &out_sample : dst) + { + // Calculate the phase index and factor. +#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) + const ALuint pi{frac >> FRAC_PHASE_BITDIFF}; + const ALfloat pf{static_cast(frac & ((1<> 2}; + size_t j{0u}; + + do { + /* f = fil + pf*phd */ + const float32x4_t f4 = vmlaq_f32(vld1q_f32(fil), pf4, vld1q_f32(phd)); + /* r += f*src */ + r4 = vmlaq_f32(r4, f4, vld1q_f32(&src[j])); + fil += 4; phd += 4; j += 4; + } while(--td); + } + r4 = vaddq_f32(r4, vrev64q_f32(r4)); + out_sample = vget_lane_f32(vadd_f32(vget_low_f32(r4), vget_high_f32(r4)), 0); + + frac += increment; + src += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } + return dst.begin(); +} + static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const ALuint IrSize, const HrirArray &Coeffs, const ALfloat left, const ALfloat right) diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index 9bb3bb8a..002d6064 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -66,6 +66,53 @@ const ALfloat *Resample_(const InterpState *state, const ALfloa return dst.begin(); } +template<> +const ALfloat *Resample_(const InterpState *state, + const ALfloat *RESTRICT src, ALuint frac, ALuint increment, const al::span dst) +{ + const ALfloat *const filter{state->bsinc.filter}; + const size_t m{state->bsinc.m}; + + src -= state->bsinc.l; + for(float &out_sample : dst) + { + // Calculate the phase index and factor. +#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) + const ALuint pi{frac >> FRAC_PHASE_BITDIFF}; + const ALfloat pf{static_cast(frac & ((1<> 2}; + size_t j{0u}; + +#define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z)) + do { + /* f = fil + pf*phd */ + const __m128 f4 = MLA4(_mm_load_ps(fil), pf4, _mm_load_ps(phd)); + /* r += f*src */ + r4 = MLA4(r4, f4, _mm_loadu_ps(&src[j])); + fil += 4; phd += 4; j += 4; + } while(--td); +#undef MLA4 + } + r4 = _mm_add_ps(r4, _mm_shuffle_ps(r4, r4, _MM_SHUFFLE(0, 1, 2, 3))); + r4 = _mm_add_ps(r4, _mm_movehl_ps(r4, r4)); + out_sample = _mm_cvtss_f32(r4); + + frac += increment; + src += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } + return dst.begin(); +} + static inline void ApplyCoeffs(size_t Offset, float2 *RESTRICT Values, const ALuint IrSize, const HrirArray &Coeffs, const ALfloat left, const ALfloat right) diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index bfb3b663..58a08ce3 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -135,7 +135,7 @@ inline HrtfMixerBlendFunc SelectHrtfBlendMixer() } // namespace -ResamplerFunc SelectResampler(Resampler resampler) +ResamplerFunc SelectResampler(Resampler resampler, ALuint increment) { switch(resampler) { @@ -159,6 +159,18 @@ ResamplerFunc SelectResampler(Resampler resampler) return Resample_; case Resampler::BSinc12: case Resampler::BSinc24: + if(increment <= FRACTIONONE) + { +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return Resample_; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return Resample_; +#endif + return Resample_; + } #ifdef HAVE_NEON if((CPUCapFlags&CPU_CAP_NEON)) return Resample_; -- cgit v1.2.3 From 00d5356b96d29775653bc6816fafff9cc94ef3ec Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Sep 2019 00:01:21 -0700 Subject: Remove the unnecessary FRACTIONONE from bsincgen --- native-tools/bsincgen.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/native-tools/bsincgen.c b/native-tools/bsincgen.c index 802403fd..b99d482f 100644 --- a/native-tools/bsincgen.c +++ b/native-tools/bsincgen.c @@ -43,26 +43,22 @@ #ifndef M_PI -#define M_PI (3.14159265358979323846) +#define M_PI 3.14159265358979323846 #endif #if !(defined(_ISOC99_SOURCE) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L)) #define log2(x) (log(x) / log(2.0)) #endif -/* Same as in alu.h! */ -#define FRACTIONBITS (12) -#define FRACTIONONE (1< Date: Sat, 28 Sep 2019 01:58:29 -0700 Subject: Add "fast" variants for the bsinc resamplers This simply omits the scale factor from the filter, similar to how up-sampling does. The consequence of this is less smooth transitions when ramping the pitch while down-sampling, but otherwise behaves fine. --- al/state.cpp | 7 +++++-- alc/alu.cpp | 8 ++++---- alc/alu.h | 2 ++ alc/converter.cpp | 4 ++-- alc/mixvoice.cpp | 7 ++++++- alsoftrc.sample | 6 +++++- utils/alsoft-config/mainwindow.cpp | 2 ++ 7 files changed, 26 insertions(+), 10 deletions(-) diff --git a/al/state.cpp b/al/state.cpp index 8f456ed3..d426f022 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -63,7 +63,9 @@ constexpr ALchar alErrOutOfMemory[] = "Out of Memory"; constexpr ALchar alPointResampler[] = "Nearest"; constexpr ALchar alLinearResampler[] = "Linear"; constexpr ALchar alCubicResampler[] = "Cubic"; +constexpr ALchar alFastBSinc12Resampler[] = "11th order Sinc (fast)"; constexpr ALchar alBSinc12Resampler[] = "11th order Sinc"; +constexpr ALchar alFastBSinc24Resampler[] = "23rd order Sinc (fast)"; constexpr ALchar alBSinc24Resampler[] = "23rd order Sinc"; } // namespace @@ -798,8 +800,9 @@ START_API_FUNC { const char *ResamplerNames[] = { alPointResampler, alLinearResampler, - alCubicResampler, alBSinc12Resampler, - alBSinc24Resampler, + alCubicResampler, alFastBSinc12Resampler, + alBSinc12Resampler, alFastBSinc24Resampler, + alBSinc24Resampler }; static_assert(al::size(ResamplerNames) == static_cast(Resampler::Max)+1, "Incorrect ResamplerNames list"); diff --git a/alc/alu.cpp b/alc/alu.cpp index 86d2789e..5df1c3a2 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -947,9 +947,9 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons voice->mStep = MAX_PITCH<mStep = maxu(fastf2u(Pitch * FRACTIONONE), 1); - if(props->mResampler == Resampler::BSinc24) + if(props->mResampler == Resampler::BSinc24 || props->mResampler == Resampler::FastBSinc24) BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc24); - else if(props->mResampler == Resampler::BSinc12) + else if(props->mResampler == Resampler::BSinc12 || props->mResampler == Resampler::FastBSinc12) BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc12); voice->mResampler = SelectResampler(props->mResampler, voice->mStep); @@ -1277,9 +1277,9 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A voice->mStep = MAX_PITCH<mStep = maxu(fastf2u(Pitch * FRACTIONONE), 1); - if(props->mResampler == Resampler::BSinc24) + if(props->mResampler == Resampler::BSinc24 || props->mResampler == Resampler::FastBSinc24) BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc24); - else if(props->mResampler == Resampler::BSinc12) + else if(props->mResampler == Resampler::BSinc12 || props->mResampler == Resampler::FastBSinc12) BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc12); voice->mResampler = SelectResampler(props->mResampler, voice->mStep); diff --git a/alc/alu.h b/alc/alu.h index e9858ddb..e2b25556 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -46,7 +46,9 @@ enum class Resampler { Point, Linear, Cubic, + FastBSinc12, BSinc12, + FastBSinc24, BSinc24, Max = BSinc24 diff --git a/alc/converter.cpp b/alc/converter.cpp index b0efb839..aff1c353 100644 --- a/alc/converter.cpp +++ b/alc/converter.cpp @@ -167,9 +167,9 @@ SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, converter->mResample = Resample_; else { - if(resampler == Resampler::BSinc24) + if(resampler == Resampler::BSinc24 || resampler == Resampler::FastBSinc24) BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc24); - else if(resampler == Resampler::BSinc12) + else if(resampler == Resampler::BSinc12 || resampler == Resampler::FastBSinc12) BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc12); converter->mResample = SelectResampler(resampler, converter->mIncrement); } diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 58a08ce3..e9e0d8df 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -161,6 +161,9 @@ ResamplerFunc SelectResampler(Resampler resampler, ALuint increment) case Resampler::BSinc24: if(increment <= FRACTIONONE) { + /* fall-through */ + case Resampler::FastBSinc12: + case Resampler::FastBSinc24: #ifdef HAVE_NEON if((CPUCapFlags&CPU_CAP_NEON)) return Resample_; @@ -191,7 +194,7 @@ void aluInitMixer() if(auto resopt = ConfigValueStr(nullptr, nullptr, "resampler")) { struct ResamplerEntry { - const char name[12]; + const char name[16]; const Resampler resampler; }; constexpr ResamplerEntry ResamplerList[]{ @@ -199,7 +202,9 @@ void aluInitMixer() { "point", Resampler::Point }, { "cubic", Resampler::Cubic }, { "bsinc12", Resampler::BSinc12 }, + { "fast_bsinc12", Resampler::FastBSinc12 }, { "bsinc24", Resampler::BSinc24 }, + { "fast_bsinc24", Resampler::FastBSinc24 }, }; const char *str{resopt->c_str()}; diff --git a/alsoftrc.sample b/alsoftrc.sample index 7cb780a3..de3ab6f3 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -161,14 +161,18 @@ #cf_level = 0 ## resampler: (global) -# Selects the resampler used when mixing sources. Valid values are: +# Selects the default resampler used when mixing sources. Valid values are: # point - nearest sample, no interpolation # linear - extrapolates samples using a linear slope between samples # cubic - extrapolates samples using a Catmull-Rom spline # bsinc12 - extrapolates samples using a band-limited Sinc filter (varying # between 12 and 24 points, with anti-aliasing) +# fast_bsinc12 - same as bsinc12, except without interpolation between down- +# sampling scales # bsinc24 - extrapolates samples using a band-limited Sinc filter (varying # between 24 and 48 points, with anti-aliasing) +# fast_bsinc24 - same as bsinc24, except without interpolation between down- +# sampling scales #resampler = linear ## rt-prio: (global) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 7e5159cf..f4f5fd45 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -101,7 +101,9 @@ static const struct NameValuePair { { "Linear", "linear" }, { "Default (Linear)", "" }, { "Cubic Spline", "cubic" }, + { "11th order Sinc (fast)", "fast_bsinc12" }, { "11th order Sinc", "bsinc12" }, + { "23rd order Sinc (fast)", "fast_bsinc24" }, { "23rd order Sinc", "bsinc24" }, { "", "" } -- cgit v1.2.3 From f7b574c8f2c6e24f52e73352a55cf685bfda3c0b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Sep 2019 03:15:48 -0700 Subject: Redo resampler strings to be safer Now the name is guaranteed to match the type, and to be ordered as the enum declares. --- al/state.cpp | 51 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/al/state.cpp b/al/state.cpp index d426f022..3d7388b2 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -60,13 +60,37 @@ constexpr ALchar alErrInvalidOp[] = "Invalid Operation"; constexpr ALchar alErrOutOfMemory[] = "Out of Memory"; /* Resampler strings */ -constexpr ALchar alPointResampler[] = "Nearest"; -constexpr ALchar alLinearResampler[] = "Linear"; -constexpr ALchar alCubicResampler[] = "Cubic"; -constexpr ALchar alFastBSinc12Resampler[] = "11th order Sinc (fast)"; -constexpr ALchar alBSinc12Resampler[] = "11th order Sinc"; -constexpr ALchar alFastBSinc24Resampler[] = "23rd order Sinc (fast)"; -constexpr ALchar alBSinc24Resampler[] = "23rd order Sinc"; +template struct ResamplerName { }; +template<> struct ResamplerName +{ static const ALchar *Get() noexcept { return "Nearest"; } }; +template<> struct ResamplerName +{ static const ALchar *Get() noexcept { return "Linear"; } }; +template<> struct ResamplerName +{ static const ALchar *Get() noexcept { return "Cubic"; } }; +template<> struct ResamplerName +{ static const ALchar *Get() noexcept { return "11th order Sinc (fast)"; } }; +template<> struct ResamplerName +{ static const ALchar *Get() noexcept { return "11th order Sinc"; } }; +template<> struct ResamplerName +{ static const ALchar *Get() noexcept { return "23rd order Sinc (fast)"; } }; +template<> struct ResamplerName +{ static const ALchar *Get() noexcept { return "23rd order Sinc"; } }; + +const ALchar *GetResamplerName(const Resampler rtype) noexcept +{ +#define HANDLE_RESAMPLER(r) case r: return ResamplerName::Get() + switch(rtype) + { + HANDLE_RESAMPLER(Resampler::Point); + HANDLE_RESAMPLER(Resampler::Linear); + HANDLE_RESAMPLER(Resampler::Cubic); + HANDLE_RESAMPLER(Resampler::FastBSinc12); + HANDLE_RESAMPLER(Resampler::BSinc12); + HANDLE_RESAMPLER(Resampler::FastBSinc24); + HANDLE_RESAMPLER(Resampler::BSinc24); + } +#undef HANDLE_RESAMPLER +} } // namespace @@ -798,15 +822,6 @@ END_API_FUNC AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index) START_API_FUNC { - const char *ResamplerNames[] = { - alPointResampler, alLinearResampler, - alCubicResampler, alFastBSinc12Resampler, - alBSinc12Resampler, alFastBSinc24Resampler, - alBSinc24Resampler - }; - static_assert(al::size(ResamplerNames) == static_cast(Resampler::Max)+1, - "Incorrect ResamplerNames list"); - ContextRef context{GetContextRef()}; if UNLIKELY(!context) return nullptr; @@ -814,10 +829,10 @@ START_API_FUNC switch(pname) { case AL_RESAMPLER_NAME_SOFT: - if(index < 0 || static_cast(index) >= al::size(ResamplerNames)) + if(index < 0 || index > static_cast(Resampler::Max)) context->setError(AL_INVALID_VALUE, "Resampler name index %d out of range", index); else - value = ResamplerNames[index]; + value = GetResamplerName(static_cast(index)); break; default: -- cgit v1.2.3 From cbc00bcffeb62eddac0dcf92d315f8188629b15b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Sep 2019 03:42:17 -0700 Subject: Combine two function calls into one --- alc/alu.cpp | 144 ++++++++++++++++++++++++++++++++++++++---------------- alc/alu.h | 9 +--- alc/converter.cpp | 12 ++--- alc/mixvoice.cpp | 54 -------------------- 4 files changed, 108 insertions(+), 111 deletions(-) diff --git a/alc/alu.cpp b/alc/alu.cpp index 5df1c3a2..4e9bf9e0 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -147,6 +147,83 @@ inline HrtfDirectMixerFunc SelectHrtfMixer(void) return MixDirectHrtf_; } + +inline void BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *table) +{ + size_t si{BSINC_SCALE_COUNT - 1}; + float sf{0.0f}; + + if(increment > FRACTIONONE) + { + sf = FRACTIONONE / static_cast(increment); + sf = maxf(0.0f, (BSINC_SCALE_COUNT-1) * (sf-table->scaleBase) * table->scaleRange); + si = float2uint(sf); + /* The interpolation factor is fit to this diagonally-symmetric curve + * to reduce the transition ripple caused by interpolating different + * scales of the sinc function. + */ + sf = 1.0f - std::cos(std::asin(sf - static_cast(si))); + } + + state->sf = sf; + state->m = table->m[si]; + state->l = (state->m/2) - 1; + state->filter = table->Tab + table->filterOffset[si]; +} + +inline ResamplerFunc SelectResampler(Resampler resampler, ALuint increment) +{ + switch(resampler) + { + case Resampler::Point: + return Resample_; + case Resampler::Linear: +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return Resample_; +#endif +#ifdef HAVE_SSE4_1 + if((CPUCapFlags&CPU_CAP_SSE4_1)) + return Resample_; +#endif +#ifdef HAVE_SSE2 + if((CPUCapFlags&CPU_CAP_SSE2)) + return Resample_; +#endif + return Resample_; + case Resampler::Cubic: + return Resample_; + case Resampler::BSinc12: + case Resampler::BSinc24: + if(increment <= FRACTIONONE) + { + /* fall-through */ + case Resampler::FastBSinc12: + case Resampler::FastBSinc24: +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return Resample_; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return Resample_; +#endif + return Resample_; + } +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return Resample_; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return Resample_; +#endif + return Resample_; + } + + return Resample_; +} + } // namespace void aluInit(void) @@ -155,6 +232,27 @@ void aluInit(void) } +ResamplerFunc PrepareResampler(Resampler resampler, ALuint increment, InterpState *state) +{ + switch(resampler) + { + case Resampler::Point: + case Resampler::Linear: + case Resampler::Cubic: + break; + case Resampler::FastBSinc12: + case Resampler::BSinc12: + BsincPrepare(increment, &state->bsinc, &bsinc12); + break; + case Resampler::FastBSinc24: + case Resampler::BSinc24: + BsincPrepare(increment, &state->bsinc, &bsinc24); + break; + } + return SelectResampler(resampler, increment); +} + + void ALCdevice::ProcessHrtf(const size_t SamplesToDo) { /* HRTF is stereo output only. */ @@ -196,36 +294,6 @@ void ALCdevice::ProcessBs2b(const size_t SamplesToDo) } -/* Prepares the interpolator for a given rate (determined by increment). - * - * With a bit of work, and a trade of memory for CPU cost, this could be - * modified for use with an interpolated increment for buttery-smooth pitch - * changes. - */ -void BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *table) -{ - size_t si{BSINC_SCALE_COUNT - 1}; - float sf{0.0f}; - - if(increment > FRACTIONONE) - { - sf = FRACTIONONE / static_cast(increment); - sf = maxf(0.0f, (BSINC_SCALE_COUNT-1) * (sf-table->scaleBase) * table->scaleRange); - si = float2uint(sf); - /* The interpolation factor is fit to this diagonally-symmetric curve - * to reduce the transition ripple caused by interpolating different - * scales of the sinc function. - */ - sf = 1.0f - std::cos(std::asin(sf - static_cast(si))); - } - - state->sf = sf; - state->m = table->m[si]; - state->l = (state->m/2) - 1; - state->filter = table->Tab + table->filterOffset[si]; -} - - namespace { /* This RNG method was created based on the math found in opusdec. It's quick, @@ -943,15 +1011,11 @@ void CalcNonAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, cons /* Calculate the stepping value */ const auto Pitch = static_cast(voice->mFrequency) / static_cast(Device->Frequency) * props->Pitch; - if(Pitch > static_cast(MAX_PITCH)) + if(Pitch > float{MAX_PITCH}) voice->mStep = MAX_PITCH<mStep = maxu(fastf2u(Pitch * FRACTIONONE), 1); - if(props->mResampler == Resampler::BSinc24 || props->mResampler == Resampler::FastBSinc24) - BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc24); - else if(props->mResampler == Resampler::BSinc12 || props->mResampler == Resampler::FastBSinc12) - BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc12); - voice->mResampler = SelectResampler(props->mResampler, voice->mStep); + voice->mResampler = PrepareResampler(props->mResampler, voice->mStep, &voice->mResampleState); /* Calculate gains */ const ALlistener &Listener = ALContext->mListener; @@ -1273,15 +1337,11 @@ void CalcAttnSourceParams(ALvoice *voice, const ALvoicePropsBase *props, const A * fixed-point stepping value. */ Pitch *= static_cast(voice->mFrequency)/static_cast(Device->Frequency); - if(Pitch > static_cast(MAX_PITCH)) + if(Pitch > float{MAX_PITCH}) voice->mStep = MAX_PITCH<mStep = maxu(fastf2u(Pitch * FRACTIONONE), 1); - if(props->mResampler == Resampler::BSinc24 || props->mResampler == Resampler::FastBSinc24) - BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc24); - else if(props->mResampler == Resampler::BSinc12 || props->mResampler == Resampler::FastBSinc12) - BsincPrepare(voice->mStep, &voice->mResampleState.bsinc, &bsinc12); - voice->mResampler = SelectResampler(props->mResampler, voice->mStep); + voice->mResampler = PrepareResampler(props->mResampler, voice->mStep, &voice->mResampleState); ALfloat spread{0.0f}; if(props->Radius > Distance) diff --git a/alc/alu.h b/alc/alu.h index e2b25556..476e3ab9 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -85,11 +85,6 @@ union InterpState { using ResamplerFunc = const ALfloat*(*)(const InterpState *state, const ALfloat *RESTRICT src, ALuint frac, ALuint increment, const al::span dst); -void BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *table); - -extern const BSincTable bsinc12; -extern const BSincTable bsinc24; - enum { AF_None = 0, @@ -372,8 +367,6 @@ void aluInit(void); void aluInitMixer(void); -ResamplerFunc SelectResampler(Resampler resampler, ALuint increment); - /* aluInitRenderer * * Set up the appropriate panning method and mixing method given the device @@ -383,6 +376,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr void aluInitEffectPanning(ALeffectslot *slot, ALCdevice *device); +ResamplerFunc PrepareResampler(Resampler resampler, ALuint increment, InterpState *state); + /** * Calculates ambisonic encoder coefficients using the X, Y, and Z direction * components, which must represent a normalized (unit length) vector, and the diff --git a/alc/converter.cpp b/alc/converter.cpp index aff1c353..0e7bd82f 100644 --- a/alc/converter.cpp +++ b/alc/converter.cpp @@ -10,6 +10,7 @@ #include "AL/al.h" #include "albyte.h" +#include "alu.h" #include "fpu_modes.h" #include "mixer/defs.h" @@ -161,18 +162,13 @@ SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, /* Have to set the mixer FPU mode since that's what the resampler code expects. */ FPUCtl mixer_mode{}; auto step = static_cast( - mind(srcRate*ALdouble{FRACTIONONE}/dstRate + 0.5, MAX_PITCH*FRACTIONONE)); + mind(srcRate*double{FRACTIONONE}/dstRate + 0.5, MAX_PITCH*FRACTIONONE)); converter->mIncrement = maxu(step, 1); if(converter->mIncrement == FRACTIONONE) converter->mResample = Resample_; else - { - if(resampler == Resampler::BSinc24 || resampler == Resampler::FastBSinc24) - BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc24); - else if(resampler == Resampler::BSinc12 || resampler == Resampler::FastBSinc12) - BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc12); - converter->mResample = SelectResampler(resampler, converter->mIncrement); - } + converter->mResample = PrepareResampler(resampler, converter->mIncrement, + &converter->mState); return converter; } diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index e9e0d8df..3e4c73a6 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -135,60 +135,6 @@ inline HrtfMixerBlendFunc SelectHrtfBlendMixer() } // namespace -ResamplerFunc SelectResampler(Resampler resampler, ALuint increment) -{ - switch(resampler) - { - case Resampler::Point: - return Resample_; - case Resampler::Linear: -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return Resample_; -#endif -#ifdef HAVE_SSE4_1 - if((CPUCapFlags&CPU_CAP_SSE4_1)) - return Resample_; -#endif -#ifdef HAVE_SSE2 - if((CPUCapFlags&CPU_CAP_SSE2)) - return Resample_; -#endif - return Resample_; - case Resampler::Cubic: - return Resample_; - case Resampler::BSinc12: - case Resampler::BSinc24: - if(increment <= FRACTIONONE) - { - /* fall-through */ - case Resampler::FastBSinc12: - case Resampler::FastBSinc24: -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return Resample_; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return Resample_; -#endif - return Resample_; - } -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return Resample_; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return Resample_; -#endif - return Resample_; - } - - return Resample_; -} - - void aluInitMixer() { if(auto resopt = ConfigValueStr(nullptr, nullptr, "resampler")) -- cgit v1.2.3 From 2d2e5539c0df2e180ab4d748413248422f3b1e30 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Sep 2019 03:44:13 -0700 Subject: Use FastBSinc24 for WASAPI and CoreAudio capture Given a fixed rate, there's no downside to the fast version. --- alc/backends/coreaudio.cpp | 2 +- alc/backends/wasapi.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 9e8291e2..92064336 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -618,7 +618,7 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) if(outputFormat.mSampleRate != mDevice->Frequency) mConverter = CreateSampleConverter(mDevice->FmtType, mDevice->FmtType, mFormat.mChannelsPerFrame, static_cast(hardwareFormat.mSampleRate), - mDevice->Frequency, Resampler::BSinc24); + mDevice->Frequency, Resampler::FastBSinc24); mRing = CreateRingBuffer(outputFrameCount, mFrameSize, false); if(!mRing) return ALC_INVALID_VALUE; diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index e1a8dc6f..2a610c8d 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -1568,7 +1568,7 @@ HRESULT WasapiCapture::resetProxy() if(mDevice->Frequency != OutputType.Format.nSamplesPerSec || mDevice->FmtType != srcType) { mSampleConv = CreateSampleConverter(srcType, mDevice->FmtType, mDevice->channelsFromFmt(), - OutputType.Format.nSamplesPerSec, mDevice->Frequency, Resampler::BSinc24); + OutputType.Format.nSamplesPerSec, mDevice->Frequency, Resampler::FastBSinc24); if(!mSampleConv) { ERR("Failed to create converter for %s format, dst: %s %uhz, src: %s %luhz\n", -- cgit v1.2.3 From 31ffb0887c44a910a5814cba1fdd5d69a4b49df2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Sep 2019 13:56:51 -0700 Subject: Don't let a function end without a return --- al/state.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/al/state.cpp b/al/state.cpp index 3d7388b2..017a1e53 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -62,19 +62,19 @@ constexpr ALchar alErrOutOfMemory[] = "Out of Memory"; /* Resampler strings */ template struct ResamplerName { }; template<> struct ResamplerName -{ static const ALchar *Get() noexcept { return "Nearest"; } }; +{ static constexpr const ALchar *Get() noexcept { return "Nearest"; } }; template<> struct ResamplerName -{ static const ALchar *Get() noexcept { return "Linear"; } }; +{ static constexpr const ALchar *Get() noexcept { return "Linear"; } }; template<> struct ResamplerName -{ static const ALchar *Get() noexcept { return "Cubic"; } }; +{ static constexpr const ALchar *Get() noexcept { return "Cubic"; } }; template<> struct ResamplerName -{ static const ALchar *Get() noexcept { return "11th order Sinc (fast)"; } }; +{ static constexpr const ALchar *Get() noexcept { return "11th order Sinc (fast)"; } }; template<> struct ResamplerName -{ static const ALchar *Get() noexcept { return "11th order Sinc"; } }; +{ static constexpr const ALchar *Get() noexcept { return "11th order Sinc"; } }; template<> struct ResamplerName -{ static const ALchar *Get() noexcept { return "23rd order Sinc (fast)"; } }; +{ static constexpr const ALchar *Get() noexcept { return "23rd order Sinc (fast)"; } }; template<> struct ResamplerName -{ static const ALchar *Get() noexcept { return "23rd order Sinc"; } }; +{ static constexpr const ALchar *Get() noexcept { return "23rd order Sinc"; } }; const ALchar *GetResamplerName(const Resampler rtype) noexcept { @@ -90,6 +90,7 @@ const ALchar *GetResamplerName(const Resampler rtype) noexcept HANDLE_RESAMPLER(Resampler::BSinc24); } #undef HANDLE_RESAMPLER + throw std::runtime_error{"Unexpected resampler index"}; } } // namespace -- cgit v1.2.3 From 4b746b8d37911600bb64e3cb9efe8c370968df1d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Sep 2019 14:35:42 -0700 Subject: Make MAX_RESAMPLER_PADDING specify the total padding --- alc/alcmain.h | 9 +++++---- alc/alu.h | 2 +- alc/backends/coreaudio.cpp | 2 +- alc/converter.cpp | 18 +++++++++--------- alc/converter.h | 2 +- alc/effects/chorus.cpp | 2 +- alc/mixvoice.cpp | 22 ++++++++++++---------- 7 files changed, 30 insertions(+), 27 deletions(-) diff --git a/alc/alcmain.h b/alc/alcmain.h index 9182d5d4..c26b3a28 100644 --- a/alc/alcmain.h +++ b/alc/alcmain.h @@ -154,10 +154,11 @@ struct BFChannelConfig { using FloatBufferLine = std::array; -/* Maximum number of samples to pad on either end of a buffer for resampling. - * Note that both the beginning and end need padding! +/* Maximum number of samples to pad on the ends of a buffer for resampling. + * Note that the padding is symmetric (half at the beginning and half at the + * end)! */ -#define MAX_RESAMPLE_PADDING 24 +#define MAX_RESAMPLER_PADDING 48 struct FrontStablizer { @@ -269,7 +270,7 @@ struct ALCdevice : public al::intrusive_ref { std::chrono::nanoseconds FixedLatency{0}; /* Temp storage used for mixer processing. */ - alignas(16) ALfloat SourceData[BUFFERSIZE + MAX_RESAMPLE_PADDING*2]; + alignas(16) ALfloat SourceData[BUFFERSIZE + MAX_RESAMPLER_PADDING]; alignas(16) ALfloat ResampledData[BUFFERSIZE]; alignas(16) ALfloat FilteredData[BUFFERSIZE]; union { diff --git a/alc/alu.h b/alc/alu.h index 476e3ab9..abe73245 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -254,7 +254,7 @@ struct ALvoice { std::array mSend; struct ChannelData { - alignas(16) std::array mPrevSamples; + alignas(16) std::array mPrevSamples; ALfloat mAmbiScale; BandSplitter mAmbiSplitter; diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 92064336..5d004efc 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -598,7 +598,7 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) uint64_t FrameCount64{mDevice->UpdateSize}; FrameCount64 = static_cast(FrameCount64*outputFormat.mSampleRate + mDevice->Frequency-1) / mDevice->Frequency; - FrameCount64 += MAX_RESAMPLE_PADDING*2; + FrameCount64 += MAX_RESAMPLER_PADDING; if(FrameCount64 > std::numeric_limits::max()/2) { ERR("FrameCount too large\n"); diff --git a/alc/converter.cpp b/alc/converter.cpp index 0e7bd82f..553bad58 100644 --- a/alc/converter.cpp +++ b/alc/converter.cpp @@ -191,8 +191,8 @@ ALuint SampleConverter::availableOut(ALuint srcframes) const return 0; } - if(prepcount < MAX_RESAMPLE_PADDING*2 && - static_cast(MAX_RESAMPLE_PADDING*2 - prepcount) >= srcframes) + if(prepcount < MAX_RESAMPLER_PADDING + && static_cast(MAX_RESAMPLER_PADDING - prepcount) >= srcframes) { /* Not enough input samples to generate an output sample. */ return 0; @@ -200,7 +200,7 @@ ALuint SampleConverter::availableOut(ALuint srcframes) const auto DataSize64 = static_cast(prepcount); DataSize64 += srcframes; - DataSize64 -= MAX_RESAMPLE_PADDING*2; + DataSize64 -= MAX_RESAMPLER_PADDING; DataSize64 <<= FRACTIONBITS; DataSize64 -= mFracOffset; @@ -235,10 +235,10 @@ ALuint SampleConverter::convert(const ALvoid **src, ALuint *srcframes, ALvoid *d mSrcPrepCount = 0; continue; } - ALuint toread{minu(NumSrcSamples, BUFFERSIZE - MAX_RESAMPLE_PADDING*2)}; + ALuint toread{minu(NumSrcSamples, BUFFERSIZE - MAX_RESAMPLER_PADDING)}; - if(prepcount < MAX_RESAMPLE_PADDING*2 && - static_cast(MAX_RESAMPLE_PADDING*2 - prepcount) >= toread) + if(prepcount < MAX_RESAMPLER_PADDING + && static_cast(MAX_RESAMPLER_PADDING - prepcount) >= toread) { /* Not enough input samples to generate an output sample. Store * what we're given for later. @@ -257,7 +257,7 @@ ALuint SampleConverter::convert(const ALvoid **src, ALuint *srcframes, ALvoid *d ALuint DataPosFrac{mFracOffset}; auto DataSize64 = static_cast(prepcount); DataSize64 += toread; - DataSize64 -= MAX_RESAMPLE_PADDING*2; + DataSize64 -= MAX_RESAMPLER_PADDING; DataSize64 <<= FRACTIONBITS; DataSize64 -= DataPosFrac; @@ -294,7 +294,7 @@ ALuint SampleConverter::convert(const ALvoid **src, ALuint *srcframes, ALvoid *d } /* Now resample, and store the result in the output buffer. */ - const ALfloat *ResampledData{mResample(&mState, SrcData+MAX_RESAMPLE_PADDING, + const ALfloat *ResampledData{mResample(&mState, SrcData+(MAX_RESAMPLER_PADDING>>1), DataPosFrac, increment, {DstData, DstSize})}; StoreSamples(DstSamples, ResampledData, mChan.size(), mDstType, DstSize); @@ -305,7 +305,7 @@ ALuint SampleConverter::convert(const ALvoid **src, ALuint *srcframes, ALvoid *d */ DataPosFrac += increment*DstSize; mSrcPrepCount = mini(prepcount + static_cast(toread - (DataPosFrac>>FRACTIONBITS)), - MAX_RESAMPLE_PADDING*2); + MAX_RESAMPLER_PADDING); mFracOffset = DataPosFrac & FRACTIONMASK; /* Update the src and dst pointers in case there's still more to do. */ diff --git a/alc/converter.h b/alc/converter.h index 8390eae3..d8fe7ba9 100644 --- a/alc/converter.h +++ b/alc/converter.h @@ -30,7 +30,7 @@ struct SampleConverter { alignas(16) ALfloat mDstSamples[BUFFERSIZE]{}; struct ChanSamples { - alignas(16) ALfloat PrevSamples[MAX_RESAMPLE_PADDING*2]; + alignas(16) ALfloat PrevSamples[MAX_RESAMPLER_PADDING]; }; al::FlexArray mChan; diff --git a/alc/effects/chorus.cpp b/alc/effects/chorus.cpp index 0e3c9d89..59e05be0 100644 --- a/alc/effects/chorus.cpp +++ b/alc/effects/chorus.cpp @@ -139,7 +139,7 @@ ALboolean ChorusState::deviceUpdate(const ALCdevice *Device) void ChorusState::update(const ALCcontext *Context, const ALeffectslot *Slot, const EffectProps *props, const EffectTarget target) { - constexpr ALsizei mindelay{MAX_RESAMPLE_PADDING << FRACTIONBITS}; + constexpr ALsizei mindelay{(MAX_RESAMPLER_PADDING>>1) << FRACTIONBITS}; switch(props->Chorus.Waveform) { diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index 3e4c73a6..b701a826 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -67,7 +67,8 @@ static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!"); /* BSinc24 requires up to 23 extra samples before the current position, and 24 after. */ -static_assert(MAX_RESAMPLE_PADDING >= 24, "MAX_RESAMPLE_PADDING must be at least 24!"); +static_assert(!(MAX_RESAMPLER_PADDING&1) && MAX_RESAMPLER_PADDING >= 48, + "MAX_RESAMPLER_PADDING must be a multiple of two and at least 48!"); Resampler ResamplerDefault{Resampler::Linear}; @@ -654,18 +655,18 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) /* Calculate the last read src sample pos. */ DataSize64 = (DataSize64*increment + DataPosFrac) >> FRACTIONBITS; /* +1 to get the src sample count, include padding. */ - DataSize64 += 1 + MAX_RESAMPLE_PADDING*2; + DataSize64 += 1 + MAX_RESAMPLER_PADDING; auto SrcBufferSize = static_cast( - minu64(DataSize64, BUFFERSIZE + MAX_RESAMPLE_PADDING*2 + 1)); - if(SrcBufferSize > BUFFERSIZE + MAX_RESAMPLE_PADDING*2) + minu64(DataSize64, BUFFERSIZE + MAX_RESAMPLER_PADDING + 1)); + if(SrcBufferSize > BUFFERSIZE + MAX_RESAMPLER_PADDING) { - SrcBufferSize = BUFFERSIZE + MAX_RESAMPLE_PADDING*2; + SrcBufferSize = BUFFERSIZE + MAX_RESAMPLER_PADDING; /* If the source buffer got saturated, we can't fill the desired * dst size. Figure out how many samples we can actually mix from * this. */ - DataSize64 = SrcBufferSize - MAX_RESAMPLE_PADDING*2; + DataSize64 = SrcBufferSize - MAX_RESAMPLER_PADDING; DataSize64 = ((DataSize64<(minu64(DataSize64, DstBufferSize)); @@ -685,11 +686,11 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) /* Load the previous samples into the source data first, then load * what we can from the buffer queue. */ - auto srciter = std::copy_n(chandata.mPrevSamples.begin(), MAX_RESAMPLE_PADDING, + auto srciter = std::copy_n(chandata.mPrevSamples.begin(), MAX_RESAMPLER_PADDING>>1, SrcData.begin()); if UNLIKELY(!BufferListItem) - srciter = std::copy(chandata.mPrevSamples.begin()+MAX_RESAMPLE_PADDING, + srciter = std::copy(chandata.mPrevSamples.begin()+(MAX_RESAMPLER_PADDING>>1), chandata.mPrevSamples.end(), srciter); else if(isstatic) srciter = LoadBufferStatic(BufferListItem, BufferLoopItem, NumChannels, @@ -714,8 +715,9 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) chandata.mPrevSamples.size(), chandata.mPrevSamples.begin()); /* Resample, then apply ambisonic upsampling as needed. */ - const ALfloat *ResampledData{Resample(&mResampleState, &SrcData[MAX_RESAMPLE_PADDING], - DataPosFrac, increment, {Device->ResampledData, DstBufferSize})}; + const ALfloat *ResampledData{Resample(&mResampleState, + &SrcData[MAX_RESAMPLER_PADDING>>1], DataPosFrac, increment, + {Device->ResampledData, DstBufferSize})}; if((mFlags&VOICE_IS_AMBISONIC)) { const ALfloat hfscale{chandata.mAmbiScale}; -- cgit v1.2.3 From 7783fa738c678ad88c8f4571f48ad0191767cbf1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Sep 2019 16:40:38 -0700 Subject: Make the BSincTables constexpr in an anonymous namespace --- alc/alu.h | 1 - native-tools/bsincgen.c | 6 ++++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/alc/alu.h b/alc/alu.h index abe73245..1d530602 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -24,7 +24,6 @@ struct ALbufferlistitem; struct ALeffectslot; -struct BSincTable; enum class DistanceModel; diff --git a/native-tools/bsincgen.c b/native-tools/bsincgen.c index b99d482f..83f03191 100644 --- a/native-tools/bsincgen.c +++ b/native-tools/bsincgen.c @@ -257,7 +257,7 @@ static void BsiGenerateTables(FILE *output, const char *tabname, const double re " * width) suffers to reduce the CPU cost. The bandlimiting will cut all sound\n" " * after downsampling by ~%.2f octaves.\n" " */\n" -"alignas(16) static constexpr float %s_tab[%d] = {\n", +"alignas(16) constexpr float %s_tab[%d] = {\n", order, (((order%100)/10) == 1) ? "th" : ((order%10) == 1) ? "st" : ((order%10) == 2) ? "nd" : @@ -286,7 +286,7 @@ static void BsiGenerateTables(FILE *output, const char *tabname, const double re fprintf(output, "\n"); } } - fprintf(output, "};\nconst BSincTable %s = {\n", tabname); + fprintf(output, "};\nconstexpr BSincTable %s = {\n", tabname); /* The scaleBase is calculated from the Kaiser window transition width. It represents the absolute limit to the filter before it fully cuts @@ -344,6 +344,7 @@ int main(int argc, char *argv[]) "#pragma once\n\n" "static_assert(BSINC_SCALE_COUNT == %d, \"Unexpected BSINC_SCALE_COUNT value!\");\n" "static_assert(BSINC_PHASE_COUNT == %d, \"Unexpected BSINC_PHASE_COUNT value!\");\n\n" +"namespace {\n\n" "struct BSincTable {\n" " const float scaleBase, scaleRange;\n" " const unsigned int m[BSINC_SCALE_COUNT];\n" @@ -355,6 +356,7 @@ int main(int argc, char *argv[]) /* An 11th order filter with a -40dB drop at nyquist. */ BsiGenerateTables(output, "bsinc12", 40.0, 11); + fprintf(output, "} // namespace\n"); if(output != stdout) fclose(output); output = NULL; -- cgit v1.2.3 From 00250042c819b5900e1ff3bd03285cffebd93464 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Sep 2019 16:41:26 -0700 Subject: Check MAX_RESAMPLER_PADDING properly to ensure it's large enough --- alc/alu.cpp | 4 ++++ alc/mixvoice.cpp | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/alc/alu.cpp b/alc/alu.cpp index 4e9bf9e0..21eea1db 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -82,6 +82,10 @@ #include "bsinc_inc.h" +static_assert(!(MAX_RESAMPLER_PADDING&1) && MAX_RESAMPLER_PADDING >= bsinc24.m[0], + "MAX_RESAMPLER_PADDING is not a multiple of two, or is too small"); + + namespace { using namespace std::placeholders; diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index b701a826..c696f114 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -66,10 +66,6 @@ static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!"); -/* BSinc24 requires up to 23 extra samples before the current position, and 24 after. */ -static_assert(!(MAX_RESAMPLER_PADDING&1) && MAX_RESAMPLER_PADDING >= 48, - "MAX_RESAMPLER_PADDING must be a multiple of two and at least 48!"); - Resampler ResamplerDefault{Resampler::Linear}; -- cgit v1.2.3 From fabb9add9b28b323ea6a882a3c7084e7638b7d09 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Sep 2019 23:31:49 -0700 Subject: Silence an MSVC warning --- alc/alc.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index 0652f858..1b1e12dd 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -912,9 +912,13 @@ constexpr ALCint alcEFXMinorVersion = 0; /* To avoid extraneous allocations, a 0-sized FlexArray is defined - * globally as a sharable object. + * globally as a sharable object. MSVC warns that a zero-sized array will have + * zero objects here, so silence that. */ +DIAGNOSTIC_PUSH +MVSDIAGNOSTIC(warning(disable : 4815)) al::FlexArray EmptyContextArray{0u}; +DIAGNOSTIC_POP using DeviceRef = al::intrusive_ptr; -- cgit v1.2.3 From 94ff2daafc071168a69d7af3694f0ab3126dddc0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 29 Sep 2019 16:02:25 -0700 Subject: Use using to avoid extraneous template instantiations --- common/alspan.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/alspan.h b/common/alspan.h index 2e0fb027..42e3523e 100644 --- a/common/alspan.h +++ b/common/alspan.h @@ -57,14 +57,14 @@ namespace detail_ { template struct is_span_> : std::true_type { }; template - struct is_span : is_span_::type> { }; + using is_span = is_span_::type>; template struct is_std_array_ : std::false_type { }; template struct is_std_array_> : std::true_type { }; template - struct is_std_array : is_std_array_::type> { }; + using is_std_array = is_std_array_::type>; template struct has_size_and_data : std::false_type { }; -- cgit v1.2.3 From fb56b020412eb090d9ce4e2ffcc691766e5214b2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 29 Sep 2019 22:43:46 -0700 Subject: Modify the bsinc resampler Readjusted the bsinc12 cutoff back to -60dB. Also increased the filter's phase count. --- alc/alu.h | 2 +- native-tools/bsincgen.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/alc/alu.h b/alc/alu.h index 1d530602..06be1a01 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -59,7 +59,7 @@ extern Resampler ResamplerDefault; */ #define BSINC_SCALE_BITS 4 #define BSINC_SCALE_COUNT (1< Date: Sun, 29 Sep 2019 23:39:04 -0700 Subject: Repack the bsinc resamplers coefficients This puts the base coefficients and the phase deltas next to each other. This improves caching, as the base and phase deltas are always used together while the scales are only used for the non-fast versions. --- alc/mixer/mixer_c.cpp | 8 ++++---- alc/mixer/mixer_neon.cpp | 8 ++++---- alc/mixer/mixer_sse.cpp | 8 ++++---- native-tools/bsincgen.c | 43 ++++++++++++++++++++++--------------------- 4 files changed, 34 insertions(+), 33 deletions(-) diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index fafda70d..f2164f53 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -31,9 +31,9 @@ inline ALfloat do_bsinc(const InterpState &istate, const ALfloat *RESTRICT vals, #undef FRAC_PHASE_BITDIFF const ALfloat *fil{istate.bsinc.filter + m*pi*4}; - const ALfloat *scd{fil + m}; - const ALfloat *phd{scd + m}; - const ALfloat *spd{phd + m}; + const ALfloat *phd{fil + m}; + const ALfloat *scd{phd + m}; + const ALfloat *spd{scd + m}; // Apply the scale and phase interpolated filter. ALfloat r{0.0f}; @@ -53,7 +53,7 @@ inline ALfloat do_fastbsinc(const InterpState &istate, const ALfloat *RESTRICT v #undef FRAC_PHASE_BITDIFF const ALfloat *fil{istate.bsinc.filter + m*pi*4}; - const ALfloat *phd{fil + m*2}; + const ALfloat *phd{fil + m}; // Apply the phase interpolated filter. ALfloat r{0.0f}; diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index 178c7d6e..75faa61f 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -91,9 +91,9 @@ const ALfloat *Resample_(const InterpState *state, const ALflo { const float32x4_t pf4{vdupq_n_f32(pf)}; const float *fil{filter + m*pi*4}; - const float *scd{fil + m}; - const float *phd{scd + m}; - const float *spd{phd + m}; + const float *phd{fil + m}; + const float *scd{phd + m}; + const float *spd{scd + m}; size_t td{m >> 2}; size_t j{0u}; @@ -140,7 +140,7 @@ const ALfloat *Resample_(const InterpState *state, { const float32x4_t pf4{vdupq_n_f32(pf)}; const float *fil{filter + m*pi*4}; - const float *phd{fil + m*2}; + const float *phd{fil + m}; size_t td{m >> 2}; size_t j{0u}; diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index 002d6064..84f651d1 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -36,9 +36,9 @@ const ALfloat *Resample_(const InterpState *state, const ALfloa { const __m128 pf4{_mm_set1_ps(pf)}; const float *fil{filter + m*pi*4}; - const float *scd{fil + m}; - const float *phd{scd + m}; - const float *spd{phd + m}; + const float *phd{fil + m}; + const float *scd{phd + m}; + const float *spd{scd + m}; size_t td{m >> 2}; size_t j{0u}; @@ -88,7 +88,7 @@ const ALfloat *Resample_(const InterpState *state, { const __m128 pf4{_mm_set1_ps(pf)}; const float *fil{filter + m*pi*4}; - const float *phd{fil + m*2}; + const float *phd{fil + m}; size_t td{m >> 2}; size_t j{0u}; diff --git a/native-tools/bsincgen.c b/native-tools/bsincgen.c index de59ddff..7e7a1fa3 100644 --- a/native-tools/bsincgen.c +++ b/native-tools/bsincgen.c @@ -137,8 +137,8 @@ static double CalcKaiserBeta(const double rejection) static void BsiGenerateTables(FILE *output, const char *tabname, const double rejection, const int order) { static double filter[BSINC_SCALE_COUNT][BSINC_PHASE_COUNT + 1][BSINC_POINTS_MAX]; - static double scDeltas[BSINC_SCALE_COUNT][BSINC_PHASE_COUNT ][BSINC_POINTS_MAX]; static double phDeltas[BSINC_SCALE_COUNT][BSINC_PHASE_COUNT + 1][BSINC_POINTS_MAX]; + static double scDeltas[BSINC_SCALE_COUNT][BSINC_PHASE_COUNT ][BSINC_POINTS_MAX]; static double spDeltas[BSINC_SCALE_COUNT][BSINC_PHASE_COUNT ][BSINC_POINTS_MAX]; static int mt[BSINC_SCALE_COUNT]; static double at[BSINC_SCALE_COUNT]; @@ -147,8 +147,8 @@ static void BsiGenerateTables(FILE *output, const char *tabname, const double re int si, pi, i; memset(filter, 0, sizeof(filter)); - memset(scDeltas, 0, sizeof(scDeltas)); memset(phDeltas, 0, sizeof(phDeltas)); + memset(scDeltas, 0, sizeof(scDeltas)); memset(spDeltas, 0, sizeof(spDeltas)); /* Calculate windowing parameters. The width describes the transition @@ -172,8 +172,8 @@ static void BsiGenerateTables(FILE *output, const char *tabname, const double re } /* Calculate the Kaiser-windowed Sinc filter coefficients for each scale - and phase. - */ + * and phase. + */ for(si = 0; si < BSINC_SCALE_COUNT; si++) { const int m = mt[si]; @@ -195,13 +195,10 @@ static void BsiGenerateTables(FILE *output, const char *tabname, const double re } } - /* Linear interpolation between scales is simplified by pre-calculating - the delta (b - a) in: x = a + f (b - a) - - Given a difference in points between scales, the destination points - will be 0, thus: x = a + f (-a) - */ - for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++) + /* Linear interpolation between phases is simplified by pre-calculating the + * delta (b - a) in: x = a + f (b - a) + */ + for(si = 0; si < BSINC_SCALE_COUNT; si++) { const int m = mt[si]; const int o = num_points_min - (m / 2); @@ -209,12 +206,16 @@ static void BsiGenerateTables(FILE *output, const char *tabname, const double re for(pi = 0; pi < BSINC_PHASE_COUNT; pi++) { for(i = 0; i < m; i++) - scDeltas[si][pi][o + i] = filter[si + 1][pi][o + i] - filter[si][pi][o + i]; + phDeltas[si][pi][o + i] = filter[si][pi + 1][o + i] - filter[si][pi][o + i]; } } - // Linear interpolation between phases is also simplified. - for(si = 0; si < BSINC_SCALE_COUNT; si++) + /* Linear interpolation between scales is also simplified. + * + * Given a difference in points between scales, the destination points will + * be 0, thus: x = a + f (-a) + */ + for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++) { const int m = mt[si]; const int o = num_points_min - (m / 2); @@ -222,13 +223,13 @@ static void BsiGenerateTables(FILE *output, const char *tabname, const double re for(pi = 0; pi < BSINC_PHASE_COUNT; pi++) { for(i = 0; i < m; i++) - phDeltas[si][pi][o + i] = filter[si][pi + 1][o + i] - filter[si][pi][o + i]; + scDeltas[si][pi][o + i] = filter[si + 1][pi][o + i] - filter[si][pi][o + i]; } } /* This last simplification is done to complete the bilinear equation for - the combination of scale and phase. - */ + * the combination of phase and scale. + */ for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++) { const int m = mt[si]; @@ -241,11 +242,11 @@ static void BsiGenerateTables(FILE *output, const char *tabname, const double re } } - // Make sure the number of points is a multiple of 4 (for SIMD). + /* Make sure the number of points is a multiple of 4 (for SIMD). */ for(si = 0; si < BSINC_SCALE_COUNT; si++) mt[si] = (mt[si]+3) & ~3; - // Calculate the table size. + /* Calculate the table size. */ i = 0; for(si = 0; si < BSINC_SCALE_COUNT; si++) i += 4 * BSINC_PHASE_COUNT * mt[si]; @@ -276,10 +277,10 @@ static void BsiGenerateTables(FILE *output, const char *tabname, const double re fprintf(output, " %+14.9ef,", filter[si][pi][o + i]); fprintf(output, "\n "); for(i = 0; i < m; i++) - fprintf(output, " %+14.9ef,", scDeltas[si][pi][o + i]); + fprintf(output, " %+14.9ef,", phDeltas[si][pi][o + i]); fprintf(output, "\n "); for(i = 0; i < m; i++) - fprintf(output, " %+14.9ef,", phDeltas[si][pi][o + i]); + fprintf(output, " %+14.9ef,", scDeltas[si][pi][o + i]); fprintf(output, "\n "); for(i = 0; i < m; i++) fprintf(output, " %+14.9ef,", spDeltas[si][pi][o + i]); -- cgit v1.2.3 From 0139d8a04fb6e976124206449c2fa3b9f2c2f56a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 30 Sep 2019 02:57:19 -0700 Subject: Remove noexcept from a function that explicitly throws --- al/state.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/al/state.cpp b/al/state.cpp index 017a1e53..3ce09be9 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -76,7 +76,7 @@ template<> struct ResamplerName template<> struct ResamplerName { static constexpr const ALchar *Get() noexcept { return "23rd order Sinc"; } }; -const ALchar *GetResamplerName(const Resampler rtype) noexcept +const ALchar *GetResamplerName(const Resampler rtype) { #define HANDLE_RESAMPLER(r) case r: return ResamplerName::Get() switch(rtype) @@ -90,6 +90,7 @@ const ALchar *GetResamplerName(const Resampler rtype) noexcept HANDLE_RESAMPLER(Resampler::BSinc24); } #undef HANDLE_RESAMPLER + /* Should never get here. */ throw std::runtime_error{"Unexpected resampler index"}; } -- cgit v1.2.3 From cf617760b6eb68d38493dd546746880cd5c88b90 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 30 Sep 2019 03:03:27 -0700 Subject: Separate a couple assignments from conditionals --- al/source.cpp | 3 ++- alc/mixvoice.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/al/source.cpp b/al/source.cpp index a802cabc..6d15f73a 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -3159,7 +3159,8 @@ START_API_FUNC /* Source is now streaming */ source->SourceType = AL_STREAMING; - if(!(BufferList=source->queue)) + BufferList = source->queue; + if(!BufferList) source->queue = BufferListStart; else { diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp index c696f114..d6be174e 100644 --- a/alc/mixvoice.cpp +++ b/alc/mixvoice.cpp @@ -820,7 +820,8 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) ++buffers_done; BufferListItem = BufferListItem->mNext.load(std::memory_order_relaxed); - if(!BufferListItem && !(BufferListItem=BufferLoopItem)) + if(!BufferListItem) BufferListItem = BufferLoopItem; + if(!BufferListItem) { if LIKELY(vstate == ALvoice::Playing) vstate = ALvoice::Stopped; -- cgit v1.2.3 From 4d127a2f9893a9c5b33f92224e0957a827484e07 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 30 Sep 2019 17:29:04 -0700 Subject: Avoid infs/nans in the crest detector It needs to be investigated why the rendered mix sometimes has such large sample values when starting, but the compressor/limiter shouldn't generate NaNs because of it. --- alc/mastering.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/alc/mastering.cpp b/alc/mastering.cpp index d0a2f78a..46cc3134 100644 --- a/alc/mastering.cpp +++ b/alc/mastering.cpp @@ -44,7 +44,7 @@ using namespace std::placeholders; */ ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALuint i, const ALfloat in) { - static constexpr ALsizei mask{BUFFERSIZE - 1}; + static constexpr ALuint mask{BUFFERSIZE - 1}; const ALuint length{Hold->mLength}; ALfloat (&values)[BUFFERSIZE] = Hold->mValues; ALuint (&expiries)[BUFFERSIZE] = Hold->mExpiries; @@ -133,7 +133,7 @@ static void CrestDetector(Compressor *Comp, const ALuint SamplesToDo) auto calc_crest = [&y2_rms,&y2_peak,a_crest](const ALfloat x_abs) noexcept -> ALfloat { - ALfloat x2 = maxf(0.000001f, x_abs * x_abs); + const ALfloat x2{clampf(x_abs * x_abs, 0.000001f, 1000000.0f)}; y2_peak = maxf(x2, lerp(x2, y2_peak, a_crest)); y2_rms = lerp(x2, y2_rms, a_crest); @@ -398,6 +398,7 @@ std::unique_ptr CompressorInit(const ALuint NumChans, const ALfloat { Comp->mDelay = ::new (static_cast(Comp.get() + 1)) FloatBufferLine[NumChans]; } + std::fill_n(Comp->mDelay, NumChans, FloatBufferLine{}); } Comp->mCrestCoeff = std::exp(-1.0f / (0.200f * SampleRate)); // 200ms -- cgit v1.2.3 From 5d7a1fa6dadcce17b6c1a52f2fb9eccbcc96a530 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 30 Sep 2019 19:29:01 -0700 Subject: Clear the HRTF state values on allocation --- alc/hrtf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alc/hrtf.h b/alc/hrtf.h index 456f710c..d133133a 100644 --- a/alc/hrtf.h +++ b/alc/hrtf.h @@ -80,7 +80,7 @@ struct HrtfFilter { struct DirectHrtfState { /* HRTF filter state for dry buffer content */ ALuint IrSize{0}; - alignas(16) HrirArray Values; + alignas(16) HrirArray Values{}; al::FlexArray Coeffs; DirectHrtfState(size_t numchans) : Coeffs{numchans} { } -- cgit v1.2.3 From 8f6fafd19a41f46eb82902da77f68a1d7b1f8215 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 30 Sep 2019 22:23:14 -0700 Subject: Update the changelog --- ChangeLog | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index dd491ff0..edef4331 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,7 +5,7 @@ openal-soft-1.20.0: Partially implemented the Vocal Morpher effect. - Fixed the bsinc SSE resampler on non-GCC compilers. + Fixed the bsinc SSE resamplers on non-GCC compilers. Fixed OpenSL capture. @@ -15,7 +15,10 @@ openal-soft-1.20.0: Fixed performance problems relating to semaphores on macOS. - Modified alcResetDeviceSOFT to attempt recovery of lost devices. + Modified the bsinc12 resampler's transition band to better avoid aliasing + noise. + + Modified alcResetDeviceSOFT to attempt recovery of disconnected devices. Modified the virtual speaker layout for HRTF B-Format decoding. @@ -23,6 +26,10 @@ openal-soft-1.20.0: Renamed the makehrtf utility to makemhr. + Improved the efficiency of the bsinc resamplers when up-sampling. + + Improved the quality of the bsinc resamplers slightly. + Improved the efficiency of the HRTF mixers. Improved the HRTF B-Format decoder coefficient generation. @@ -31,7 +38,10 @@ openal-soft-1.20.0: Improved handling of sources that end prematurely, to avoid loud clicks. - Improved some reverb processing loops. + Improved the performance of some reverb processing loops. + + Added fast_bsinc resamplers that improve efficiency at the cost of some + quality. Notably, when down-sampling with pitch ramping. Added support for SOFA input files with makemhr. -- cgit v1.2.3 From 0063f4bfac96f35899d9dec4e273f5ed642b4358 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 1 Oct 2019 01:49:21 -0700 Subject: Add some allocator fields GCC 6.3 seems to want --- common/almalloc.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/common/almalloc.h b/common/almalloc.h index e021337b..b844e5fc 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -70,6 +70,12 @@ namespace al { template struct allocator { using value_type = T; + using reference = T&; + using const_reference = const T&; + using pointer = T*; + using const_pointer = const T*; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; using is_always_equal = std::true_type; template -- cgit v1.2.3 From e2c1602ede1b17a4499cb4fa737eae04dc529ce0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 1 Oct 2019 19:56:39 -0700 Subject: Link the examples with librt if it exists --- CMakeLists.txt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f833e41..9bf09a3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1423,12 +1423,22 @@ IF(ALSOFT_UTILS) ENDIF() +# Some systems need to link with -lrt for clock_gettime as used by the common +# eaxmple functions. +SET(RT_LIB ) +CHECK_LIBRARY_EXISTS(rt clock_gettime "" HAVE_LIBRT) +IF(HAVE_LIBRT) + SET(RT_LIB rt) +ENDIF() + # Add a static library with common functions used by multiple example targets -ADD_LIBRARY(ex-common STATIC EXCLUDE_FROM_ALL examples/common/alhelpers.c) +ADD_LIBRARY(ex-common STATIC EXCLUDE_FROM_ALL + examples/common/alhelpers.c + examples/common/alhelpers.h) TARGET_COMPILE_DEFINITIONS(ex-common PUBLIC ${CPP_DEFS}) TARGET_INCLUDE_DIRECTORIES(ex-common PUBLIC ${OpenAL_SOURCE_DIR}/common) TARGET_COMPILE_OPTIONS(ex-common PUBLIC ${C_FLAGS}) -TARGET_LINK_LIBRARIES(ex-common PUBLIC OpenAL) +TARGET_LINK_LIBRARIES(ex-common PUBLIC OpenAL PRIVATE ${RT_LIB}) IF(ALSOFT_TESTS) ADD_EXECUTABLE(altonegen examples/altonegen.c) -- cgit v1.2.3 From a0a55d300fef56c4422482ae8aeaabaf2a3c4178 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 1 Oct 2019 21:45:44 -0700 Subject: Remove an unnecessary function --- alc/alc.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index 1b1e12dd..fad43f7b 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -842,13 +842,6 @@ constexpr ALchar alExtList[] = std::atomic LastNullDeviceError{ALC_NO_ERROR}; /* Thread-local current context */ -void ReleaseThreadCtx(ALCcontext *context) -{ - const bool result{context->releaseIfNoDelete()}; - ERR("Context %p current for thread being destroyed%s!\n", - decltype(std::declval()){context}, result ? "" : ", leak detected"); -} - class ThreadCtx { ALCcontext *ctx{nullptr}; @@ -856,8 +849,11 @@ public: ~ThreadCtx() { if(ctx) - ReleaseThreadCtx(ctx); - ctx = nullptr; + { + const bool result{ctx->releaseIfNoDelete()}; + ERR("Context %p current for thread being destroyed%s!\n", + decltype(std::declval()){ctx}, result ? "" : ", leak detected"); + } } ALCcontext *get() const noexcept { return ctx; } -- cgit v1.2.3 From 28d54efe72323cc6791d0ee3d15accff7765e853 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 1 Oct 2019 22:15:40 -0700 Subject: Use al::getenv to get the router env vars --- router/router.cpp | 82 +++++++++++++++++++++++++++---------------------------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/router/router.cpp b/router/router.cpp index e9173a22..88e75b67 100644 --- a/router/router.cpp +++ b/router/router.cpp @@ -3,18 +3,20 @@ #include "router.h" -#include -#include -#include - #include +#include +#include +#include #include "AL/alc.h" #include "AL/al.h" + #include "almalloc.h" +#include "strutils.h" #include "version.h" + std::vector DriverList; thread_local DriverIface *ThreadCtxDriver; @@ -27,51 +29,47 @@ static void LoadDriverList(void); BOOL APIENTRY DllMain(HINSTANCE, DWORD reason, void*) { - const char *str; - switch(reason) { - case DLL_PROCESS_ATTACH: - LogFile = stderr; - str = getenv("ALROUTER_LOGFILE"); - if(str && *str != '\0') - { - FILE *f = fopen(str, "w"); - if(f == nullptr) - ERR("Could not open log file: %s\n", str); - else - LogFile = f; - } - str = getenv("ALROUTER_LOGLEVEL"); - if(str && *str != '\0') - { - char *end = nullptr; - long l = strtol(str, &end, 0); - if(!end || *end != '\0') - ERR("Invalid log level value: %s\n", str); - else if(l < LogLevel_None || l > LogLevel_Trace) - ERR("Log level out of range: %s\n", str); - else - LogLevel = static_cast(l); - } - TRACE("Initializing router v0.1-%s %s\n", ALSOFT_GIT_COMMIT_HASH, ALSOFT_GIT_BRANCH); - LoadDriverList(); + case DLL_PROCESS_ATTACH: + LogFile = stderr; + if(auto logfname = al::getenv("ALROUTER_LOGFILE")) + { + FILE *f = fopen(logfname->c_str(), "w"); + if(f == nullptr) + ERR("Could not open log file: %s\n", logfname->c_str()); + else + LogFile = f; + } + if(auto loglev = al::getenv("ALROUTER_LOGLEVEL")) + { + char *end = nullptr; + long l = strtol(loglev->c_str(), &end, 0); + if(!end || *end != '\0') + ERR("Invalid log level value: %s\n", loglev->c_str()); + else if(l < LogLevel_None || l > LogLevel_Trace) + ERR("Log level out of range: %s\n", loglev->c_str()); + else + LogLevel = static_cast(l); + } + TRACE("Initializing router v0.1-%s %s\n", ALSOFT_GIT_COMMIT_HASH, ALSOFT_GIT_BRANCH); + LoadDriverList(); - break; + break; - case DLL_THREAD_ATTACH: - break; - case DLL_THREAD_DETACH: - break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; - case DLL_PROCESS_DETACH: - DriverList.clear(); + case DLL_PROCESS_DETACH: + DriverList.clear(); - if(LogFile && LogFile != stderr) - fclose(LogFile); - LogFile = nullptr; + if(LogFile && LogFile != stderr) + fclose(LogFile); + LogFile = nullptr; - break; + break; } return TRUE; } -- cgit v1.2.3 From accac7950ce8f49a9e9ccaa4be24e96347f4aca3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 1 Oct 2019 22:22:46 -0700 Subject: Silence some warnings from GCC in the router --- router/router.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/router/router.cpp b/router/router.cpp index 88e75b67..85a75aea 100644 --- a/router/router.cpp +++ b/router/router.cpp @@ -81,7 +81,7 @@ static void AddModule(HMODULE module, const WCHAR *name) { if(drv.Module == module) { - TRACE("Skipping already-loaded module %p\n", module); + TRACE("Skipping already-loaded module %p\n", decltype(std::declval()){module}); FreeLibrary(module); return; } @@ -99,8 +99,8 @@ static void AddModule(HMODULE module, const WCHAR *name) /* Load required functions. */ int err = 0; #define LOAD_PROC(x) do { \ - newdrv.x = reinterpret_cast( \ - GetProcAddress(module, #x)); \ + newdrv.x = reinterpret_cast(reinterpret_cast( \ + GetProcAddress(module, #x))); \ if(!newdrv.x) \ { \ ERR("Failed to find entry point for %s in %ls\n", #x, name); \ @@ -233,7 +233,7 @@ static void AddModule(HMODULE module, const WCHAR *name) DriverList.pop_back(); return; } - TRACE("Loaded module %p, %ls, ALC %d.%d\n", module, name, + TRACE("Loaded module %p, %ls, ALC %d.%d\n", decltype(std::declval()){module}, name, newdrv.ALCVer>>8, newdrv.ALCVer&255); #undef LOAD_PROC } -- cgit v1.2.3 From 69eb685dbce703cd95343ebe323c3d29390e4938 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 1 Oct 2019 22:35:33 -0700 Subject: Check for librt earlier --- CMakeLists.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9bf09a3f..5180504f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -390,6 +390,14 @@ IF(HAVE_LIBM) SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} m) ENDIF() +# Some systems need to link with -lrt for clock_gettime as used by the common +# eaxmple functions. +SET(RT_LIB ) +CHECK_LIBRARY_EXISTS(rt clock_gettime "" HAVE_LIBRT) +IF(HAVE_LIBRT) + SET(RT_LIB rt) +ENDIF() + # Check for the dlopen API (for dynamicly loading backend libs) IF(ALSOFT_DLOPEN) CHECK_INCLUDE_FILE(dlfcn.h HAVE_DLFCN_H) @@ -1423,14 +1431,6 @@ IF(ALSOFT_UTILS) ENDIF() -# Some systems need to link with -lrt for clock_gettime as used by the common -# eaxmple functions. -SET(RT_LIB ) -CHECK_LIBRARY_EXISTS(rt clock_gettime "" HAVE_LIBRT) -IF(HAVE_LIBRT) - SET(RT_LIB rt) -ENDIF() - # Add a static library with common functions used by multiple example targets ADD_LIBRARY(ex-common STATIC EXCLUDE_FROM_ALL examples/common/alhelpers.c -- cgit v1.2.3 From 2980adb8c0d28486da1229b182bc9c78ae5b1879 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 1 Oct 2019 22:50:28 -0700 Subject: Make sure the temporary HRIRs are properly aligned --- alc/hrtf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index 85b75e07..b23f9d6f 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -296,7 +296,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, { using double2 = std::array; struct ImpulseResponse { - std::array hrir; + alignas(16) std::array hrir; ALuint ldelay, rdelay; }; -- cgit v1.2.3 From 4620912f0ffef7bde9629377f38f75065c0c8bba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 1 Oct 2019 23:33:00 -0700 Subject: Don't inline the utf8 converters --- common/dynload.cpp | 3 ++- common/strutils.cpp | 35 +++++++++++++++++++++++++++++++++++ common/strutils.h | 38 ++++---------------------------------- 3 files changed, 41 insertions(+), 35 deletions(-) diff --git a/common/dynload.cpp b/common/dynload.cpp index 98d2c521..f1c2a7eb 100644 --- a/common/dynload.cpp +++ b/common/dynload.cpp @@ -6,6 +6,8 @@ #include "strutils.h" #ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include void *LoadLib(const char *name) { @@ -39,5 +41,4 @@ void *GetSymbol(void *handle, const char *name) if(err) sym = nullptr; return sym; } - #endif diff --git a/common/strutils.cpp b/common/strutils.cpp index 0163de7b..870a0ed3 100644 --- a/common/strutils.cpp +++ b/common/strutils.cpp @@ -6,6 +6,41 @@ #include +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include + +std::string wstr_to_utf8(const WCHAR *wstr) +{ + std::string ret; + + int len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr); + if(len > 0) + { + ret.resize(len); + WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &ret[0], len, nullptr, nullptr); + ret.pop_back(); + } + + return ret; +} + +std::wstring utf8_to_wstr(const char *str) +{ + std::wstring ret; + + int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0); + if(len > 0) + { + ret.resize(len); + MultiByteToWideChar(CP_UTF8, 0, str, -1, &ret[0], len); + ret.pop_back(); + } + + return ret; +} +#endif + namespace al { al::optional getenv(const char *envname) diff --git a/common/strutils.h b/common/strutils.h index db9b07c6..0c7a0e22 100644 --- a/common/strutils.h +++ b/common/strutils.h @@ -6,47 +6,17 @@ #include "aloptional.h" #ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include - - -inline std::string wstr_to_utf8(const WCHAR *wstr) -{ - std::string ret; - - int len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr); - if(len > 0) - { - ret.resize(len); - WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &ret[0], len, nullptr, nullptr); - ret.pop_back(); - } - - return ret; -} - -inline std::wstring utf8_to_wstr(const char *str) -{ - std::wstring ret; - - int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0); - if(len > 0) - { - ret.resize(len); - MultiByteToWideChar(CP_UTF8, 0, str, -1, &ret[0], len); - ret.pop_back(); - } - - return ret; -} +#include +std::string wstr_to_utf8(const wchar_t *wstr); +std::wstring utf8_to_wstr(const char *str); #endif namespace al { al::optional getenv(const char *envname); #ifdef _WIN32 -al::optional getenv(const WCHAR *envname); +al::optional getenv(const wchar_t *envname); #endif } // namespace al -- cgit v1.2.3 From a35cac7ce0efcac1ffd4af41de8456eed99dba0e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 Oct 2019 15:29:01 -0700 Subject: Rename mixvoice.cpp to voice.cpp --- CMakeLists.txt | 2 +- alc/mixvoice.cpp | 881 ------------------------------------------------------- alc/voice.cpp | 881 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 882 insertions(+), 882 deletions(-) delete mode 100644 alc/mixvoice.cpp create mode 100644 alc/voice.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5180504f..46fb692a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -625,13 +625,13 @@ SET(ALC_OBJS alc/logging.h alc/mastering.cpp alc/mastering.h - alc/mixvoice.cpp alc/panning.cpp alc/ringbuffer.cpp alc/ringbuffer.h alc/uhjfilter.cpp alc/uhjfilter.h alc/uiddefs.cpp + alc/voice.cpp alc/mixer/defs.h alc/mixer/hrtfbase.h alc/mixer/mixer_c.cpp diff --git a/alc/mixvoice.cpp b/alc/mixvoice.cpp deleted file mode 100644 index d6be174e..00000000 --- a/alc/mixvoice.cpp +++ /dev/null @@ -1,881 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" - -#include "al/buffer.h" -#include "al/event.h" -#include "al/source.h" -#include "alcmain.h" -#include "albyte.h" -#include "alconfig.h" -#include "alcontext.h" -#include "alnumeric.h" -#include "aloptional.h" -#include "alspan.h" -#include "alstring.h" -#include "alu.h" -#include "cpu_caps.h" -#include "devformat.h" -#include "filters/biquad.h" -#include "filters/nfc.h" -#include "filters/splitter.h" -#include "hrtf.h" -#include "inprogext.h" -#include "logging.h" -#include "mixer/defs.h" -#include "opthelpers.h" -#include "ringbuffer.h" -#include "threads.h" -#include "vector.h" - - -static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, - "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!"); - - -Resampler ResamplerDefault{Resampler::Linear}; - -MixerFunc MixSamples = Mix_; -RowMixerFunc MixRowSamples = MixRow_; - -namespace { - -HrtfMixerFunc MixHrtfSamples = MixHrtf_; -HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_; - -inline MixerFunc SelectMixer() -{ -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return Mix_; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return Mix_; -#endif - return Mix_; -} - -inline RowMixerFunc SelectRowMixer() -{ -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return MixRow_; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return MixRow_; -#endif - return MixRow_; -} - -inline HrtfMixerFunc SelectHrtfMixer() -{ -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return MixHrtf_; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return MixHrtf_; -#endif - return MixHrtf_; -} - -inline HrtfMixerBlendFunc SelectHrtfBlendMixer() -{ -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return MixHrtfBlend_; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return MixHrtfBlend_; -#endif - return MixHrtfBlend_; -} - -} // namespace - - -void aluInitMixer() -{ - if(auto resopt = ConfigValueStr(nullptr, nullptr, "resampler")) - { - struct ResamplerEntry { - const char name[16]; - const Resampler resampler; - }; - constexpr ResamplerEntry ResamplerList[]{ - { "none", Resampler::Point }, - { "point", Resampler::Point }, - { "cubic", Resampler::Cubic }, - { "bsinc12", Resampler::BSinc12 }, - { "fast_bsinc12", Resampler::FastBSinc12 }, - { "bsinc24", Resampler::BSinc24 }, - { "fast_bsinc24", Resampler::FastBSinc24 }, - }; - - const char *str{resopt->c_str()}; - if(al::strcasecmp(str, "bsinc") == 0) - { - WARN("Resampler option \"%s\" is deprecated, using bsinc12\n", str); - str = "bsinc12"; - } - else if(al::strcasecmp(str, "sinc4") == 0 || al::strcasecmp(str, "sinc8") == 0) - { - WARN("Resampler option \"%s\" is deprecated, using cubic\n", str); - str = "cubic"; - } - - auto iter = std::find_if(std::begin(ResamplerList), std::end(ResamplerList), - [str](const ResamplerEntry &entry) -> bool - { return al::strcasecmp(str, entry.name) == 0; }); - if(iter == std::end(ResamplerList)) - ERR("Invalid resampler: %s\n", str); - else - ResamplerDefault = iter->resampler; - } - - MixHrtfBlendSamples = SelectHrtfBlendMixer(); - MixHrtfSamples = SelectHrtfMixer(); - MixSamples = SelectMixer(); - MixRowSamples = SelectRowMixer(); -} - - -namespace { - -/* A quick'n'dirty lookup table to decode a muLaw-encoded byte sample into a - * signed 16-bit sample */ -constexpr ALshort muLawDecompressionTable[256] = { - -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956, - -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764, - -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412, - -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316, - -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, - -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, - -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, - -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, - -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, - -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, - -876, -844, -812, -780, -748, -716, -684, -652, - -620, -588, -556, -524, -492, -460, -428, -396, - -372, -356, -340, -324, -308, -292, -276, -260, - -244, -228, -212, -196, -180, -164, -148, -132, - -120, -112, -104, -96, -88, -80, -72, -64, - -56, -48, -40, -32, -24, -16, -8, 0, - 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, - 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, - 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, - 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, - 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, - 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, - 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, - 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, - 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, - 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, - 876, 844, 812, 780, 748, 716, 684, 652, - 620, 588, 556, 524, 492, 460, 428, 396, - 372, 356, 340, 324, 308, 292, 276, 260, - 244, 228, 212, 196, 180, 164, 148, 132, - 120, 112, 104, 96, 88, 80, 72, 64, - 56, 48, 40, 32, 24, 16, 8, 0 -}; - -/* A quick'n'dirty lookup table to decode an aLaw-encoded byte sample into a - * signed 16-bit sample */ -constexpr ALshort aLawDecompressionTable[256] = { - -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, - -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, - -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, - -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, - -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944, - -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136, - -11008,-10496,-12032,-11520, -8960, -8448, -9984, -9472, - -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568, - -344, -328, -376, -360, -280, -264, -312, -296, - -472, -456, -504, -488, -408, -392, -440, -424, - -88, -72, -120, -104, -24, -8, -56, -40, - -216, -200, -248, -232, -152, -136, -184, -168, - -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, - -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, - -688, -656, -752, -720, -560, -528, -624, -592, - -944, -912, -1008, -976, -816, -784, -880, -848, - 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, - 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, - 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, - 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, - 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, - 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, - 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, - 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, - 344, 328, 376, 360, 280, 264, 312, 296, - 472, 456, 504, 488, 408, 392, 440, 424, - 88, 72, 120, 104, 24, 8, 56, 40, - 216, 200, 248, 232, 152, 136, 184, 168, - 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, - 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, - 688, 656, 752, 720, 560, 528, 624, 592, - 944, 912, 1008, 976, 816, 784, 880, 848 -}; - -template -struct FmtTypeTraits { }; - -template<> -struct FmtTypeTraits { - using Type = ALubyte; - static constexpr inline float to_float(const Type val) noexcept - { return val*(1.0f/128.0f) - 1.0f; } -}; -template<> -struct FmtTypeTraits { - using Type = ALshort; - static constexpr inline float to_float(const Type val) noexcept { return val*(1.0f/32768.0f); } -}; -template<> -struct FmtTypeTraits { - using Type = ALfloat; - static constexpr inline float to_float(const Type val) noexcept { return val; } -}; -template<> -struct FmtTypeTraits { - using Type = ALdouble; - static constexpr inline float to_float(const Type val) noexcept - { return static_cast(val); } -}; -template<> -struct FmtTypeTraits { - using Type = ALubyte; - static constexpr inline float to_float(const Type val) noexcept - { return muLawDecompressionTable[val] * (1.0f/32768.0f); } -}; -template<> -struct FmtTypeTraits { - using Type = ALubyte; - static constexpr inline float to_float(const Type val) noexcept - { return aLawDecompressionTable[val] * (1.0f/32768.0f); } -}; - - -void SendSourceStoppedEvent(ALCcontext *context, ALuint id) -{ - RingBuffer *ring{context->mAsyncEvents.get()}; - auto evt_vec = ring->getWriteVector(); - if(evt_vec.first.len < 1) return; - - AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_SourceStateChange}}; - evt->u.srcstate.id = id; - evt->u.srcstate.state = AL_STOPPED; - - ring->writeAdvance(1); - context->mEventSem.post(); -} - - -const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, ALfloat *dst, - const ALfloat *src, const size_t numsamples, int type) -{ - switch(type) - { - case AF_None: - lpfilter->clear(); - hpfilter->clear(); - break; - - case AF_LowPass: - lpfilter->process(dst, src, numsamples); - hpfilter->clear(); - return dst; - case AF_HighPass: - lpfilter->clear(); - hpfilter->process(dst, src, numsamples); - return dst; - - case AF_BandPass: - lpfilter->process(dst, src, numsamples); - hpfilter->process(dst, dst, numsamples); - return dst; - } - return src; -} - - -template -inline void LoadSampleArray(ALfloat *RESTRICT dst, const al::byte *src, const size_t srcstep, - const size_t samples) noexcept -{ - using SampleType = typename FmtTypeTraits::Type; - - const SampleType *RESTRICT ssrc{reinterpret_cast(src)}; - for(size_t i{0u};i < samples;i++) - dst[i] = FmtTypeTraits::to_float(ssrc[i*srcstep]); -} - -void LoadSamples(ALfloat *RESTRICT dst, const al::byte *src, const size_t srcstep, FmtType srctype, - const size_t samples) noexcept -{ -#define HANDLE_FMT(T) case T: LoadSampleArray(dst, src, srcstep, samples); break - switch(srctype) - { - HANDLE_FMT(FmtUByte); - HANDLE_FMT(FmtShort); - HANDLE_FMT(FmtFloat); - HANDLE_FMT(FmtDouble); - HANDLE_FMT(FmtMulaw); - HANDLE_FMT(FmtAlaw); - } -#undef HANDLE_FMT -} - -ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&BufferLoopItem, - const size_t NumChannels, const size_t SampleSize, const size_t chan, size_t DataPosInt, - al::span SrcBuffer) -{ - const ALbuffer *Buffer{BufferListItem->mBuffer}; - const ALuint LoopStart{Buffer->LoopStart}; - const ALuint LoopEnd{Buffer->LoopEnd}; - ASSUME(LoopEnd > LoopStart); - - /* If current pos is beyond the loop range, do not loop */ - if(!BufferLoopItem || DataPosInt >= LoopEnd) - { - BufferLoopItem = nullptr; - - /* Load what's left to play from the buffer */ - const size_t DataRem{minz(SrcBuffer.size(), Buffer->SampleLen-DataPosInt)}; - - const al::byte *Data{Buffer->mData.data()}; - Data += (DataPosInt*NumChannels + chan)*SampleSize; - - LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataRem); - SrcBuffer = SrcBuffer.subspan(DataRem); - } - else - { - /* Load what's left of this loop iteration */ - const size_t DataRem{minz(SrcBuffer.size(), LoopEnd-DataPosInt)}; - - const al::byte *Data{Buffer->mData.data()}; - Data += (DataPosInt*NumChannels + chan)*SampleSize; - - LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataRem); - SrcBuffer = SrcBuffer.subspan(DataRem); - - /* Load any repeats of the loop we can to fill the buffer. */ - const auto LoopSize = static_cast(LoopEnd - LoopStart); - while(!SrcBuffer.empty()) - { - const size_t DataSize{minz(SrcBuffer.size(), LoopSize)}; - - Data = Buffer->mData.data() + (LoopStart*NumChannels + chan)*SampleSize; - - LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataSize); - SrcBuffer = SrcBuffer.subspan(DataSize); - } - } - return SrcBuffer.begin(); -} - -ALfloat *LoadBufferQueue(ALbufferlistitem *BufferListItem, ALbufferlistitem *BufferLoopItem, - const size_t NumChannels, const size_t SampleSize, const size_t chan, size_t DataPosInt, - al::span SrcBuffer) -{ - /* Crawl the buffer queue to fill in the temp buffer */ - while(BufferListItem && !SrcBuffer.empty()) - { - ALbuffer *Buffer{BufferListItem->mBuffer}; - if(!(Buffer && DataPosInt < Buffer->SampleLen)) - { - if(Buffer) DataPosInt -= Buffer->SampleLen; - BufferListItem = BufferListItem->mNext.load(std::memory_order_acquire); - if(!BufferListItem) BufferListItem = BufferLoopItem; - continue; - } - - const size_t DataSize{minz(SrcBuffer.size(), Buffer->SampleLen-DataPosInt)}; - - const al::byte *Data{Buffer->mData.data()}; - Data += (DataPosInt*NumChannels + chan)*SampleSize; - - LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataSize); - SrcBuffer = SrcBuffer.subspan(DataSize); - if(SrcBuffer.empty()) break; - - DataPosInt = 0; - BufferListItem = BufferListItem->mNext.load(std::memory_order_acquire); - if(!BufferListItem) BufferListItem = BufferLoopItem; - } - - return SrcBuffer.begin(); -} - - -void DoHrtfMix(ALvoice::DirectData &Direct, const float TargetGain, DirectParams &parms, - const float *samples, const ALuint DstBufferSize, const ALuint Counter, const ALuint OutPos, - const ALuint IrSize, ALCdevice *Device) -{ - const ALuint OutLIdx{GetChannelIdxByName(Device->RealOut, FrontLeft)}; - const ALuint OutRIdx{GetChannelIdxByName(Device->RealOut, FrontRight)}; - auto &HrtfSamples = Device->HrtfSourceData; - auto &AccumSamples = Device->HrtfAccumData; - - /* Copy the HRTF history and new input samples into a temp buffer. */ - auto src_iter = std::copy(parms.Hrtf.State.History.begin(), parms.Hrtf.State.History.end(), - std::begin(HrtfSamples)); - std::copy_n(samples, DstBufferSize, src_iter); - /* Copy the last used samples back into the history buffer for later. */ - std::copy_n(std::begin(HrtfSamples) + DstBufferSize, parms.Hrtf.State.History.size(), - parms.Hrtf.State.History.begin()); - - /* Copy the current filtered values being accumulated into the temp buffer. */ - auto accum_iter = std::copy_n(parms.Hrtf.State.Values.begin(), parms.Hrtf.State.Values.size(), - std::begin(AccumSamples)); - /* Clear the accumulation buffer that will start getting filled in. */ - std::fill_n(accum_iter, DstBufferSize, float2{}); - - /* If fading, the old gain is not silence, and this is the first mixing - * pass, fade between the IRs. - */ - ALuint fademix{0u}; - if(Counter && parms.Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD && OutPos == 0) - { - fademix = minu(DstBufferSize, 128); - - float gain{TargetGain}; - - /* The new coefficients need to fade in completely since they're - * replacing the old ones. To keep the gain fading consistent, - * interpolate between the old and new target gains given how much of - * the fade time this mix handles. - */ - if LIKELY(Counter > fademix) - { - const ALfloat a{static_cast(fademix) / static_cast(Counter)}; - gain = lerp(parms.Hrtf.Old.Gain, TargetGain, a); - } - MixHrtfFilter hrtfparams; - hrtfparams.Coeffs = &parms.Hrtf.Target.Coeffs; - hrtfparams.Delay[0] = parms.Hrtf.Target.Delay[0]; - hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1]; - hrtfparams.Gain = 0.0f; - hrtfparams.GainStep = gain / static_cast(fademix); - - MixHrtfBlendSamples(Direct.Buffer[OutLIdx], Direct.Buffer[OutRIdx], HrtfSamples, - AccumSamples, OutPos, IrSize, &parms.Hrtf.Old, &hrtfparams, fademix); - /* Update the old parameters with the result. */ - parms.Hrtf.Old = parms.Hrtf.Target; - if(fademix < Counter) - parms.Hrtf.Old.Gain = hrtfparams.Gain; - else - parms.Hrtf.Old.Gain = TargetGain; - } - - if LIKELY(fademix < DstBufferSize) - { - const ALuint todo{DstBufferSize - fademix}; - float gain{TargetGain}; - - /* Interpolate the target gain if the gain fading lasts longer than - * this mix. - */ - if(Counter > DstBufferSize) - { - const float a{static_cast(todo) / static_cast(Counter-fademix)}; - gain = lerp(parms.Hrtf.Old.Gain, TargetGain, a); - } - - MixHrtfFilter hrtfparams; - hrtfparams.Coeffs = &parms.Hrtf.Target.Coeffs; - hrtfparams.Delay[0] = parms.Hrtf.Target.Delay[0]; - hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1]; - hrtfparams.Gain = parms.Hrtf.Old.Gain; - hrtfparams.GainStep = (gain - parms.Hrtf.Old.Gain) / static_cast(todo); - MixHrtfSamples(Direct.Buffer[OutLIdx], Direct.Buffer[OutRIdx], HrtfSamples+fademix, - AccumSamples+fademix, OutPos+fademix, IrSize, &hrtfparams, todo); - /* Store the interpolated gain or the final target gain depending if - * the fade is done. - */ - if(DstBufferSize < Counter) - parms.Hrtf.Old.Gain = gain; - else - parms.Hrtf.Old.Gain = TargetGain; - } - - /* Copy the new in-progress accumulation values back for the next mix. */ - std::copy_n(std::begin(AccumSamples) + DstBufferSize, parms.Hrtf.State.Values.size(), - parms.Hrtf.State.Values.begin()); -} - -void DoNfcMix(ALvoice::DirectData &Direct, const float *TargetGains, DirectParams &parms, - const float *samples, const ALuint DstBufferSize, const ALuint Counter, const ALuint OutPos, - ALCdevice *Device) -{ - const size_t outcount{Device->NumChannelsPerOrder[0]}; - MixSamples({samples, DstBufferSize}, Direct.Buffer.first(outcount), - parms.Gains.Current, TargetGains, Counter, OutPos); - - const al::span nfcsamples{Device->NfcSampleData, DstBufferSize}; - size_t chanoffset{outcount}; - using FilterProc = void (NfcFilter::*)(float*,const float*,const size_t); - auto apply_nfc = [&Direct,&parms,samples,TargetGains,Counter,OutPos,&chanoffset,nfcsamples]( - const FilterProc process, const size_t chancount) -> void - { - if(chancount < 1) return; - (parms.NFCtrlFilter.*process)(nfcsamples.data(), samples, nfcsamples.size()); - MixSamples(nfcsamples, Direct.Buffer.subspan(chanoffset, chancount), - parms.Gains.Current+chanoffset, TargetGains+chanoffset, Counter, OutPos); - chanoffset += chancount; - }; - apply_nfc(&NfcFilter::process1, Device->NumChannelsPerOrder[1]); - apply_nfc(&NfcFilter::process2, Device->NumChannelsPerOrder[2]); - apply_nfc(&NfcFilter::process3, Device->NumChannelsPerOrder[3]); -} - -} // namespace - -void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) -{ - static constexpr ALfloat SilentTarget[MAX_OUTPUT_CHANNELS]{}; - - ASSUME(SamplesToDo > 0); - - /* Get voice info */ - const bool isstatic{(mFlags&VOICE_IS_STATIC) != 0}; - ALuint DataPosInt{mPosition.load(std::memory_order_relaxed)}; - ALuint DataPosFrac{mPositionFrac.load(std::memory_order_relaxed)}; - ALbufferlistitem *BufferListItem{mCurrentBuffer.load(std::memory_order_relaxed)}; - ALbufferlistitem *BufferLoopItem{mLoopBuffer.load(std::memory_order_relaxed)}; - const ALuint NumChannels{mNumChannels}; - const ALuint SampleSize{mSampleSize}; - const ALuint increment{mStep}; - if(increment < 1) return; - - ASSUME(NumChannels > 0); - ASSUME(SampleSize > 0); - ASSUME(increment > 0); - - ALCdevice *Device{Context->mDevice.get()}; - const ALuint NumSends{Device->NumAuxSends}; - const ALuint IrSize{Device->mHrtf ? Device->mHrtf->irSize : 0}; - - ResamplerFunc Resample{(increment == FRACTIONONE && DataPosFrac == 0) ? - Resample_ : mResampler}; - - ALuint Counter{(mFlags&VOICE_IS_FADING) ? SamplesToDo : 0}; - if(!Counter) - { - /* No fading, just overwrite the old/current params. */ - for(ALuint chan{0};chan < NumChannels;chan++) - { - ChannelData &chandata = mChans[chan]; - { - DirectParams &parms = chandata.mDryParams; - if(!(mFlags&VOICE_HAS_HRTF)) - std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target), - std::begin(parms.Gains.Current)); - else - parms.Hrtf.Old = parms.Hrtf.Target; - } - for(ALuint send{0};send < NumSends;++send) - { - if(mSend[send].Buffer.empty()) - continue; - - SendParams &parms = chandata.mWetParams[send]; - std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target), - std::begin(parms.Gains.Current)); - } - } - } - else if((mFlags&VOICE_HAS_HRTF)) - { - for(ALuint chan{0};chan < NumChannels;chan++) - { - DirectParams &parms = mChans[chan].mDryParams; - if(!(parms.Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD)) - { - /* The old HRTF params are silent, so overwrite the old - * coefficients with the new, and reset the old gain to 0. The - * future mix will then fade from silence. - */ - parms.Hrtf.Old = parms.Hrtf.Target; - parms.Hrtf.Old.Gain = 0.0f; - } - } - } - - ALuint buffers_done{0u}; - ALuint OutPos{0u}; - do { - /* Figure out how many buffer samples will be needed */ - ALuint DstBufferSize{SamplesToDo - OutPos}; - - /* Calculate the last written dst sample pos. */ - uint64_t DataSize64{DstBufferSize - 1}; - /* Calculate the last read src sample pos. */ - DataSize64 = (DataSize64*increment + DataPosFrac) >> FRACTIONBITS; - /* +1 to get the src sample count, include padding. */ - DataSize64 += 1 + MAX_RESAMPLER_PADDING; - - auto SrcBufferSize = static_cast( - minu64(DataSize64, BUFFERSIZE + MAX_RESAMPLER_PADDING + 1)); - if(SrcBufferSize > BUFFERSIZE + MAX_RESAMPLER_PADDING) - { - SrcBufferSize = BUFFERSIZE + MAX_RESAMPLER_PADDING; - /* If the source buffer got saturated, we can't fill the desired - * dst size. Figure out how many samples we can actually mix from - * this. - */ - DataSize64 = SrcBufferSize - MAX_RESAMPLER_PADDING; - DataSize64 = ((DataSize64<(minu64(DataSize64, DstBufferSize)); - - /* Some mixers like having a multiple of 4, so try to give that - * unless this is the last update. - */ - if(DstBufferSize < SamplesToDo-OutPos) - DstBufferSize &= ~3u; - } - - ASSUME(DstBufferSize > 0); - for(ALuint chan{0};chan < NumChannels;chan++) - { - ChannelData &chandata = mChans[chan]; - const al::span SrcData{Device->SourceData, SrcBufferSize}; - - /* Load the previous samples into the source data first, then load - * what we can from the buffer queue. - */ - auto srciter = std::copy_n(chandata.mPrevSamples.begin(), MAX_RESAMPLER_PADDING>>1, - SrcData.begin()); - - if UNLIKELY(!BufferListItem) - srciter = std::copy(chandata.mPrevSamples.begin()+(MAX_RESAMPLER_PADDING>>1), - chandata.mPrevSamples.end(), srciter); - else if(isstatic) - srciter = LoadBufferStatic(BufferListItem, BufferLoopItem, NumChannels, - SampleSize, chan, DataPosInt, {srciter, SrcData.end()}); - else - srciter = LoadBufferQueue(BufferListItem, BufferLoopItem, NumChannels, - SampleSize, chan, DataPosInt, {srciter, SrcData.end()}); - - if UNLIKELY(srciter != SrcData.end()) - { - /* If the source buffer wasn't filled, copy the last sample for - * the remaining buffer. Ideally it should have ended with - * silence, but if not the gain fading should help avoid clicks - * from sudden amplitude changes. - */ - const ALfloat sample{*(srciter-1)}; - std::fill(srciter, SrcData.end(), sample); - } - - /* Store the last source samples used for next time. */ - std::copy_n(&SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS], - chandata.mPrevSamples.size(), chandata.mPrevSamples.begin()); - - /* Resample, then apply ambisonic upsampling as needed. */ - const ALfloat *ResampledData{Resample(&mResampleState, - &SrcData[MAX_RESAMPLER_PADDING>>1], DataPosFrac, increment, - {Device->ResampledData, DstBufferSize})}; - if((mFlags&VOICE_IS_AMBISONIC)) - { - const ALfloat hfscale{chandata.mAmbiScale}; - /* Beware the evil const_cast. It's safe since it's pointing to - * either SourceData or ResampledData (both non-const), but the - * resample method takes the source as const float* and may - * return it without copying to output, making it currently - * unavoidable. - */ - chandata.mAmbiSplitter.applyHfScale(const_cast(ResampledData), hfscale, - DstBufferSize); - } - - /* Now filter and mix to the appropriate outputs. */ - ALfloat (&FilterBuf)[BUFFERSIZE] = Device->FilteredData; - { - DirectParams &parms = chandata.mDryParams; - const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, FilterBuf, - ResampledData, DstBufferSize, mDirect.FilterType)}; - - if((mFlags&VOICE_HAS_HRTF)) - { - const ALfloat TargetGain{UNLIKELY(vstate == ALvoice::Stopping) ? 0.0f : - parms.Hrtf.Target.Gain}; - DoHrtfMix(mDirect, TargetGain, parms, samples, DstBufferSize, Counter, OutPos, - IrSize, Device); - } - else if((mFlags&VOICE_HAS_NFC)) - { - const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? - SilentTarget : parms.Gains.Target}; - DoNfcMix(mDirect, TargetGains, parms, samples, DstBufferSize, Counter, OutPos, - Device); - } - else - { - const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? - SilentTarget : parms.Gains.Target}; - MixSamples({samples, DstBufferSize}, mDirect.Buffer, parms.Gains.Current, - TargetGains, Counter, OutPos); - } - } - - for(ALuint send{0};send < NumSends;++send) - { - if(mSend[send].Buffer.empty()) - continue; - - SendParams &parms = chandata.mWetParams[send]; - const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, FilterBuf, - ResampledData, DstBufferSize, mSend[send].FilterType)}; - - const ALfloat *TargetGains{UNLIKELY(vstate==ALvoice::Stopping) ? SilentTarget : - parms.Gains.Target}; - MixSamples({samples, DstBufferSize}, mSend[send].Buffer, parms.Gains.Current, - TargetGains, Counter, OutPos); - } - } - /* Update positions */ - DataPosFrac += increment*DstBufferSize; - DataPosInt += DataPosFrac>>FRACTIONBITS; - DataPosFrac &= FRACTIONMASK; - - OutPos += DstBufferSize; - Counter = maxu(DstBufferSize, Counter) - DstBufferSize; - - if UNLIKELY(!BufferListItem) - { - /* Do nothing extra when there's no buffers. */ - } - else if(isstatic) - { - if(BufferLoopItem) - { - /* Handle looping static source */ - const ALbuffer *Buffer{BufferListItem->mBuffer}; - const ALuint LoopStart{Buffer->LoopStart}; - const ALuint LoopEnd{Buffer->LoopEnd}; - if(DataPosInt >= LoopEnd) - { - assert(LoopEnd > LoopStart); - DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart; - } - } - else - { - /* Handle non-looping static source */ - if(DataPosInt >= BufferListItem->mSampleLen) - { - if LIKELY(vstate == ALvoice::Playing) - vstate = ALvoice::Stopped; - BufferListItem = nullptr; - break; - } - } - } - else while(1) - { - /* Handle streaming source */ - if(BufferListItem->mSampleLen > DataPosInt) - break; - - DataPosInt -= BufferListItem->mSampleLen; - - ++buffers_done; - BufferListItem = BufferListItem->mNext.load(std::memory_order_relaxed); - if(!BufferListItem) BufferListItem = BufferLoopItem; - if(!BufferListItem) - { - if LIKELY(vstate == ALvoice::Playing) - vstate = ALvoice::Stopped; - break; - } - } - } while(OutPos < SamplesToDo); - - mFlags |= VOICE_IS_FADING; - - /* Don't update positions and buffers if we were stopping. */ - if UNLIKELY(vstate == ALvoice::Stopping) - { - mPlayState.store(ALvoice::Stopped, std::memory_order_release); - return; - } - - /* Capture the source ID in case it's reset for stopping. */ - const ALuint SourceID{mSourceID.load(std::memory_order_relaxed)}; - - /* Update voice info */ - mPosition.store(DataPosInt, std::memory_order_relaxed); - mPositionFrac.store(DataPosFrac, std::memory_order_relaxed); - mCurrentBuffer.store(BufferListItem, std::memory_order_relaxed); - if(vstate == ALvoice::Stopped) - { - mLoopBuffer.store(nullptr, std::memory_order_relaxed); - mSourceID.store(0u, std::memory_order_relaxed); - } - std::atomic_thread_fence(std::memory_order_release); - - /* Send any events now, after the position/buffer info was updated. */ - const ALbitfieldSOFT enabledevt{Context->mEnabledEvts.load(std::memory_order_acquire)}; - if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) - { - RingBuffer *ring{Context->mAsyncEvents.get()}; - auto evt_vec = ring->getWriteVector(); - if(evt_vec.first.len > 0) - { - AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_BufferCompleted}}; - evt->u.bufcomp.id = SourceID; - evt->u.bufcomp.count = buffers_done; - ring->writeAdvance(1); - Context->mEventSem.post(); - } - } - - if(vstate == ALvoice::Stopped) - { - /* If the voice just ended, set it to Stopping so the next render - * ensures any residual noise fades to 0 amplitude. - */ - mPlayState.store(ALvoice::Stopping, std::memory_order_release); - if((enabledevt&EventType_SourceStateChange)) - SendSourceStoppedEvent(Context, SourceID); - } -} diff --git a/alc/voice.cpp b/alc/voice.cpp new file mode 100644 index 00000000..d6be174e --- /dev/null +++ b/alc/voice.cpp @@ -0,0 +1,881 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" + +#include "al/buffer.h" +#include "al/event.h" +#include "al/source.h" +#include "alcmain.h" +#include "albyte.h" +#include "alconfig.h" +#include "alcontext.h" +#include "alnumeric.h" +#include "aloptional.h" +#include "alspan.h" +#include "alstring.h" +#include "alu.h" +#include "cpu_caps.h" +#include "devformat.h" +#include "filters/biquad.h" +#include "filters/nfc.h" +#include "filters/splitter.h" +#include "hrtf.h" +#include "inprogext.h" +#include "logging.h" +#include "mixer/defs.h" +#include "opthelpers.h" +#include "ringbuffer.h" +#include "threads.h" +#include "vector.h" + + +static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, + "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!"); + + +Resampler ResamplerDefault{Resampler::Linear}; + +MixerFunc MixSamples = Mix_; +RowMixerFunc MixRowSamples = MixRow_; + +namespace { + +HrtfMixerFunc MixHrtfSamples = MixHrtf_; +HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_; + +inline MixerFunc SelectMixer() +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return Mix_; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return Mix_; +#endif + return Mix_; +} + +inline RowMixerFunc SelectRowMixer() +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return MixRow_; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixRow_; +#endif + return MixRow_; +} + +inline HrtfMixerFunc SelectHrtfMixer() +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return MixHrtf_; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixHrtf_; +#endif + return MixHrtf_; +} + +inline HrtfMixerBlendFunc SelectHrtfBlendMixer() +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return MixHrtfBlend_; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixHrtfBlend_; +#endif + return MixHrtfBlend_; +} + +} // namespace + + +void aluInitMixer() +{ + if(auto resopt = ConfigValueStr(nullptr, nullptr, "resampler")) + { + struct ResamplerEntry { + const char name[16]; + const Resampler resampler; + }; + constexpr ResamplerEntry ResamplerList[]{ + { "none", Resampler::Point }, + { "point", Resampler::Point }, + { "cubic", Resampler::Cubic }, + { "bsinc12", Resampler::BSinc12 }, + { "fast_bsinc12", Resampler::FastBSinc12 }, + { "bsinc24", Resampler::BSinc24 }, + { "fast_bsinc24", Resampler::FastBSinc24 }, + }; + + const char *str{resopt->c_str()}; + if(al::strcasecmp(str, "bsinc") == 0) + { + WARN("Resampler option \"%s\" is deprecated, using bsinc12\n", str); + str = "bsinc12"; + } + else if(al::strcasecmp(str, "sinc4") == 0 || al::strcasecmp(str, "sinc8") == 0) + { + WARN("Resampler option \"%s\" is deprecated, using cubic\n", str); + str = "cubic"; + } + + auto iter = std::find_if(std::begin(ResamplerList), std::end(ResamplerList), + [str](const ResamplerEntry &entry) -> bool + { return al::strcasecmp(str, entry.name) == 0; }); + if(iter == std::end(ResamplerList)) + ERR("Invalid resampler: %s\n", str); + else + ResamplerDefault = iter->resampler; + } + + MixHrtfBlendSamples = SelectHrtfBlendMixer(); + MixHrtfSamples = SelectHrtfMixer(); + MixSamples = SelectMixer(); + MixRowSamples = SelectRowMixer(); +} + + +namespace { + +/* A quick'n'dirty lookup table to decode a muLaw-encoded byte sample into a + * signed 16-bit sample */ +constexpr ALshort muLawDecompressionTable[256] = { + -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956, + -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764, + -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412, + -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316, + -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, + -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, + -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, + -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, + -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, + -876, -844, -812, -780, -748, -716, -684, -652, + -620, -588, -556, -524, -492, -460, -428, -396, + -372, -356, -340, -324, -308, -292, -276, -260, + -244, -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, -64, + -56, -48, -40, -32, -24, -16, -8, 0, + 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, + 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, + 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, + 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, + 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, + 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, + 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, + 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, + 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, + 876, 844, 812, 780, 748, 716, 684, 652, + 620, 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, 260, + 244, 228, 212, 196, 180, 164, 148, 132, + 120, 112, 104, 96, 88, 80, 72, 64, + 56, 48, 40, 32, 24, 16, 8, 0 +}; + +/* A quick'n'dirty lookup table to decode an aLaw-encoded byte sample into a + * signed 16-bit sample */ +constexpr ALshort aLawDecompressionTable[256] = { + -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, + -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, + -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, + -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, + -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944, + -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136, + -11008,-10496,-12032,-11520, -8960, -8448, -9984, -9472, + -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568, + -344, -328, -376, -360, -280, -264, -312, -296, + -472, -456, -504, -488, -408, -392, -440, -424, + -88, -72, -120, -104, -24, -8, -56, -40, + -216, -200, -248, -232, -152, -136, -184, -168, + -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, + -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, -592, + -944, -912, -1008, -976, -816, -784, -880, -848, + 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, + 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, + 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, + 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, + 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, + 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, + 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, + 344, 328, 376, 360, 280, 264, 312, 296, + 472, 456, 504, 488, 408, 392, 440, 424, + 88, 72, 120, 104, 24, 8, 56, 40, + 216, 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, + 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, + 688, 656, 752, 720, 560, 528, 624, 592, + 944, 912, 1008, 976, 816, 784, 880, 848 +}; + +template +struct FmtTypeTraits { }; + +template<> +struct FmtTypeTraits { + using Type = ALubyte; + static constexpr inline float to_float(const Type val) noexcept + { return val*(1.0f/128.0f) - 1.0f; } +}; +template<> +struct FmtTypeTraits { + using Type = ALshort; + static constexpr inline float to_float(const Type val) noexcept { return val*(1.0f/32768.0f); } +}; +template<> +struct FmtTypeTraits { + using Type = ALfloat; + static constexpr inline float to_float(const Type val) noexcept { return val; } +}; +template<> +struct FmtTypeTraits { + using Type = ALdouble; + static constexpr inline float to_float(const Type val) noexcept + { return static_cast(val); } +}; +template<> +struct FmtTypeTraits { + using Type = ALubyte; + static constexpr inline float to_float(const Type val) noexcept + { return muLawDecompressionTable[val] * (1.0f/32768.0f); } +}; +template<> +struct FmtTypeTraits { + using Type = ALubyte; + static constexpr inline float to_float(const Type val) noexcept + { return aLawDecompressionTable[val] * (1.0f/32768.0f); } +}; + + +void SendSourceStoppedEvent(ALCcontext *context, ALuint id) +{ + RingBuffer *ring{context->mAsyncEvents.get()}; + auto evt_vec = ring->getWriteVector(); + if(evt_vec.first.len < 1) return; + + AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_SourceStateChange}}; + evt->u.srcstate.id = id; + evt->u.srcstate.state = AL_STOPPED; + + ring->writeAdvance(1); + context->mEventSem.post(); +} + + +const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, ALfloat *dst, + const ALfloat *src, const size_t numsamples, int type) +{ + switch(type) + { + case AF_None: + lpfilter->clear(); + hpfilter->clear(); + break; + + case AF_LowPass: + lpfilter->process(dst, src, numsamples); + hpfilter->clear(); + return dst; + case AF_HighPass: + lpfilter->clear(); + hpfilter->process(dst, src, numsamples); + return dst; + + case AF_BandPass: + lpfilter->process(dst, src, numsamples); + hpfilter->process(dst, dst, numsamples); + return dst; + } + return src; +} + + +template +inline void LoadSampleArray(ALfloat *RESTRICT dst, const al::byte *src, const size_t srcstep, + const size_t samples) noexcept +{ + using SampleType = typename FmtTypeTraits::Type; + + const SampleType *RESTRICT ssrc{reinterpret_cast(src)}; + for(size_t i{0u};i < samples;i++) + dst[i] = FmtTypeTraits::to_float(ssrc[i*srcstep]); +} + +void LoadSamples(ALfloat *RESTRICT dst, const al::byte *src, const size_t srcstep, FmtType srctype, + const size_t samples) noexcept +{ +#define HANDLE_FMT(T) case T: LoadSampleArray(dst, src, srcstep, samples); break + switch(srctype) + { + HANDLE_FMT(FmtUByte); + HANDLE_FMT(FmtShort); + HANDLE_FMT(FmtFloat); + HANDLE_FMT(FmtDouble); + HANDLE_FMT(FmtMulaw); + HANDLE_FMT(FmtAlaw); + } +#undef HANDLE_FMT +} + +ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&BufferLoopItem, + const size_t NumChannels, const size_t SampleSize, const size_t chan, size_t DataPosInt, + al::span SrcBuffer) +{ + const ALbuffer *Buffer{BufferListItem->mBuffer}; + const ALuint LoopStart{Buffer->LoopStart}; + const ALuint LoopEnd{Buffer->LoopEnd}; + ASSUME(LoopEnd > LoopStart); + + /* If current pos is beyond the loop range, do not loop */ + if(!BufferLoopItem || DataPosInt >= LoopEnd) + { + BufferLoopItem = nullptr; + + /* Load what's left to play from the buffer */ + const size_t DataRem{minz(SrcBuffer.size(), Buffer->SampleLen-DataPosInt)}; + + const al::byte *Data{Buffer->mData.data()}; + Data += (DataPosInt*NumChannels + chan)*SampleSize; + + LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataRem); + SrcBuffer = SrcBuffer.subspan(DataRem); + } + else + { + /* Load what's left of this loop iteration */ + const size_t DataRem{minz(SrcBuffer.size(), LoopEnd-DataPosInt)}; + + const al::byte *Data{Buffer->mData.data()}; + Data += (DataPosInt*NumChannels + chan)*SampleSize; + + LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataRem); + SrcBuffer = SrcBuffer.subspan(DataRem); + + /* Load any repeats of the loop we can to fill the buffer. */ + const auto LoopSize = static_cast(LoopEnd - LoopStart); + while(!SrcBuffer.empty()) + { + const size_t DataSize{minz(SrcBuffer.size(), LoopSize)}; + + Data = Buffer->mData.data() + (LoopStart*NumChannels + chan)*SampleSize; + + LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataSize); + SrcBuffer = SrcBuffer.subspan(DataSize); + } + } + return SrcBuffer.begin(); +} + +ALfloat *LoadBufferQueue(ALbufferlistitem *BufferListItem, ALbufferlistitem *BufferLoopItem, + const size_t NumChannels, const size_t SampleSize, const size_t chan, size_t DataPosInt, + al::span SrcBuffer) +{ + /* Crawl the buffer queue to fill in the temp buffer */ + while(BufferListItem && !SrcBuffer.empty()) + { + ALbuffer *Buffer{BufferListItem->mBuffer}; + if(!(Buffer && DataPosInt < Buffer->SampleLen)) + { + if(Buffer) DataPosInt -= Buffer->SampleLen; + BufferListItem = BufferListItem->mNext.load(std::memory_order_acquire); + if(!BufferListItem) BufferListItem = BufferLoopItem; + continue; + } + + const size_t DataSize{minz(SrcBuffer.size(), Buffer->SampleLen-DataPosInt)}; + + const al::byte *Data{Buffer->mData.data()}; + Data += (DataPosInt*NumChannels + chan)*SampleSize; + + LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataSize); + SrcBuffer = SrcBuffer.subspan(DataSize); + if(SrcBuffer.empty()) break; + + DataPosInt = 0; + BufferListItem = BufferListItem->mNext.load(std::memory_order_acquire); + if(!BufferListItem) BufferListItem = BufferLoopItem; + } + + return SrcBuffer.begin(); +} + + +void DoHrtfMix(ALvoice::DirectData &Direct, const float TargetGain, DirectParams &parms, + const float *samples, const ALuint DstBufferSize, const ALuint Counter, const ALuint OutPos, + const ALuint IrSize, ALCdevice *Device) +{ + const ALuint OutLIdx{GetChannelIdxByName(Device->RealOut, FrontLeft)}; + const ALuint OutRIdx{GetChannelIdxByName(Device->RealOut, FrontRight)}; + auto &HrtfSamples = Device->HrtfSourceData; + auto &AccumSamples = Device->HrtfAccumData; + + /* Copy the HRTF history and new input samples into a temp buffer. */ + auto src_iter = std::copy(parms.Hrtf.State.History.begin(), parms.Hrtf.State.History.end(), + std::begin(HrtfSamples)); + std::copy_n(samples, DstBufferSize, src_iter); + /* Copy the last used samples back into the history buffer for later. */ + std::copy_n(std::begin(HrtfSamples) + DstBufferSize, parms.Hrtf.State.History.size(), + parms.Hrtf.State.History.begin()); + + /* Copy the current filtered values being accumulated into the temp buffer. */ + auto accum_iter = std::copy_n(parms.Hrtf.State.Values.begin(), parms.Hrtf.State.Values.size(), + std::begin(AccumSamples)); + /* Clear the accumulation buffer that will start getting filled in. */ + std::fill_n(accum_iter, DstBufferSize, float2{}); + + /* If fading, the old gain is not silence, and this is the first mixing + * pass, fade between the IRs. + */ + ALuint fademix{0u}; + if(Counter && parms.Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD && OutPos == 0) + { + fademix = minu(DstBufferSize, 128); + + float gain{TargetGain}; + + /* The new coefficients need to fade in completely since they're + * replacing the old ones. To keep the gain fading consistent, + * interpolate between the old and new target gains given how much of + * the fade time this mix handles. + */ + if LIKELY(Counter > fademix) + { + const ALfloat a{static_cast(fademix) / static_cast(Counter)}; + gain = lerp(parms.Hrtf.Old.Gain, TargetGain, a); + } + MixHrtfFilter hrtfparams; + hrtfparams.Coeffs = &parms.Hrtf.Target.Coeffs; + hrtfparams.Delay[0] = parms.Hrtf.Target.Delay[0]; + hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1]; + hrtfparams.Gain = 0.0f; + hrtfparams.GainStep = gain / static_cast(fademix); + + MixHrtfBlendSamples(Direct.Buffer[OutLIdx], Direct.Buffer[OutRIdx], HrtfSamples, + AccumSamples, OutPos, IrSize, &parms.Hrtf.Old, &hrtfparams, fademix); + /* Update the old parameters with the result. */ + parms.Hrtf.Old = parms.Hrtf.Target; + if(fademix < Counter) + parms.Hrtf.Old.Gain = hrtfparams.Gain; + else + parms.Hrtf.Old.Gain = TargetGain; + } + + if LIKELY(fademix < DstBufferSize) + { + const ALuint todo{DstBufferSize - fademix}; + float gain{TargetGain}; + + /* Interpolate the target gain if the gain fading lasts longer than + * this mix. + */ + if(Counter > DstBufferSize) + { + const float a{static_cast(todo) / static_cast(Counter-fademix)}; + gain = lerp(parms.Hrtf.Old.Gain, TargetGain, a); + } + + MixHrtfFilter hrtfparams; + hrtfparams.Coeffs = &parms.Hrtf.Target.Coeffs; + hrtfparams.Delay[0] = parms.Hrtf.Target.Delay[0]; + hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1]; + hrtfparams.Gain = parms.Hrtf.Old.Gain; + hrtfparams.GainStep = (gain - parms.Hrtf.Old.Gain) / static_cast(todo); + MixHrtfSamples(Direct.Buffer[OutLIdx], Direct.Buffer[OutRIdx], HrtfSamples+fademix, + AccumSamples+fademix, OutPos+fademix, IrSize, &hrtfparams, todo); + /* Store the interpolated gain or the final target gain depending if + * the fade is done. + */ + if(DstBufferSize < Counter) + parms.Hrtf.Old.Gain = gain; + else + parms.Hrtf.Old.Gain = TargetGain; + } + + /* Copy the new in-progress accumulation values back for the next mix. */ + std::copy_n(std::begin(AccumSamples) + DstBufferSize, parms.Hrtf.State.Values.size(), + parms.Hrtf.State.Values.begin()); +} + +void DoNfcMix(ALvoice::DirectData &Direct, const float *TargetGains, DirectParams &parms, + const float *samples, const ALuint DstBufferSize, const ALuint Counter, const ALuint OutPos, + ALCdevice *Device) +{ + const size_t outcount{Device->NumChannelsPerOrder[0]}; + MixSamples({samples, DstBufferSize}, Direct.Buffer.first(outcount), + parms.Gains.Current, TargetGains, Counter, OutPos); + + const al::span nfcsamples{Device->NfcSampleData, DstBufferSize}; + size_t chanoffset{outcount}; + using FilterProc = void (NfcFilter::*)(float*,const float*,const size_t); + auto apply_nfc = [&Direct,&parms,samples,TargetGains,Counter,OutPos,&chanoffset,nfcsamples]( + const FilterProc process, const size_t chancount) -> void + { + if(chancount < 1) return; + (parms.NFCtrlFilter.*process)(nfcsamples.data(), samples, nfcsamples.size()); + MixSamples(nfcsamples, Direct.Buffer.subspan(chanoffset, chancount), + parms.Gains.Current+chanoffset, TargetGains+chanoffset, Counter, OutPos); + chanoffset += chancount; + }; + apply_nfc(&NfcFilter::process1, Device->NumChannelsPerOrder[1]); + apply_nfc(&NfcFilter::process2, Device->NumChannelsPerOrder[2]); + apply_nfc(&NfcFilter::process3, Device->NumChannelsPerOrder[3]); +} + +} // namespace + +void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) +{ + static constexpr ALfloat SilentTarget[MAX_OUTPUT_CHANNELS]{}; + + ASSUME(SamplesToDo > 0); + + /* Get voice info */ + const bool isstatic{(mFlags&VOICE_IS_STATIC) != 0}; + ALuint DataPosInt{mPosition.load(std::memory_order_relaxed)}; + ALuint DataPosFrac{mPositionFrac.load(std::memory_order_relaxed)}; + ALbufferlistitem *BufferListItem{mCurrentBuffer.load(std::memory_order_relaxed)}; + ALbufferlistitem *BufferLoopItem{mLoopBuffer.load(std::memory_order_relaxed)}; + const ALuint NumChannels{mNumChannels}; + const ALuint SampleSize{mSampleSize}; + const ALuint increment{mStep}; + if(increment < 1) return; + + ASSUME(NumChannels > 0); + ASSUME(SampleSize > 0); + ASSUME(increment > 0); + + ALCdevice *Device{Context->mDevice.get()}; + const ALuint NumSends{Device->NumAuxSends}; + const ALuint IrSize{Device->mHrtf ? Device->mHrtf->irSize : 0}; + + ResamplerFunc Resample{(increment == FRACTIONONE && DataPosFrac == 0) ? + Resample_ : mResampler}; + + ALuint Counter{(mFlags&VOICE_IS_FADING) ? SamplesToDo : 0}; + if(!Counter) + { + /* No fading, just overwrite the old/current params. */ + for(ALuint chan{0};chan < NumChannels;chan++) + { + ChannelData &chandata = mChans[chan]; + { + DirectParams &parms = chandata.mDryParams; + if(!(mFlags&VOICE_HAS_HRTF)) + std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target), + std::begin(parms.Gains.Current)); + else + parms.Hrtf.Old = parms.Hrtf.Target; + } + for(ALuint send{0};send < NumSends;++send) + { + if(mSend[send].Buffer.empty()) + continue; + + SendParams &parms = chandata.mWetParams[send]; + std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target), + std::begin(parms.Gains.Current)); + } + } + } + else if((mFlags&VOICE_HAS_HRTF)) + { + for(ALuint chan{0};chan < NumChannels;chan++) + { + DirectParams &parms = mChans[chan].mDryParams; + if(!(parms.Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD)) + { + /* The old HRTF params are silent, so overwrite the old + * coefficients with the new, and reset the old gain to 0. The + * future mix will then fade from silence. + */ + parms.Hrtf.Old = parms.Hrtf.Target; + parms.Hrtf.Old.Gain = 0.0f; + } + } + } + + ALuint buffers_done{0u}; + ALuint OutPos{0u}; + do { + /* Figure out how many buffer samples will be needed */ + ALuint DstBufferSize{SamplesToDo - OutPos}; + + /* Calculate the last written dst sample pos. */ + uint64_t DataSize64{DstBufferSize - 1}; + /* Calculate the last read src sample pos. */ + DataSize64 = (DataSize64*increment + DataPosFrac) >> FRACTIONBITS; + /* +1 to get the src sample count, include padding. */ + DataSize64 += 1 + MAX_RESAMPLER_PADDING; + + auto SrcBufferSize = static_cast( + minu64(DataSize64, BUFFERSIZE + MAX_RESAMPLER_PADDING + 1)); + if(SrcBufferSize > BUFFERSIZE + MAX_RESAMPLER_PADDING) + { + SrcBufferSize = BUFFERSIZE + MAX_RESAMPLER_PADDING; + /* If the source buffer got saturated, we can't fill the desired + * dst size. Figure out how many samples we can actually mix from + * this. + */ + DataSize64 = SrcBufferSize - MAX_RESAMPLER_PADDING; + DataSize64 = ((DataSize64<(minu64(DataSize64, DstBufferSize)); + + /* Some mixers like having a multiple of 4, so try to give that + * unless this is the last update. + */ + if(DstBufferSize < SamplesToDo-OutPos) + DstBufferSize &= ~3u; + } + + ASSUME(DstBufferSize > 0); + for(ALuint chan{0};chan < NumChannels;chan++) + { + ChannelData &chandata = mChans[chan]; + const al::span SrcData{Device->SourceData, SrcBufferSize}; + + /* Load the previous samples into the source data first, then load + * what we can from the buffer queue. + */ + auto srciter = std::copy_n(chandata.mPrevSamples.begin(), MAX_RESAMPLER_PADDING>>1, + SrcData.begin()); + + if UNLIKELY(!BufferListItem) + srciter = std::copy(chandata.mPrevSamples.begin()+(MAX_RESAMPLER_PADDING>>1), + chandata.mPrevSamples.end(), srciter); + else if(isstatic) + srciter = LoadBufferStatic(BufferListItem, BufferLoopItem, NumChannels, + SampleSize, chan, DataPosInt, {srciter, SrcData.end()}); + else + srciter = LoadBufferQueue(BufferListItem, BufferLoopItem, NumChannels, + SampleSize, chan, DataPosInt, {srciter, SrcData.end()}); + + if UNLIKELY(srciter != SrcData.end()) + { + /* If the source buffer wasn't filled, copy the last sample for + * the remaining buffer. Ideally it should have ended with + * silence, but if not the gain fading should help avoid clicks + * from sudden amplitude changes. + */ + const ALfloat sample{*(srciter-1)}; + std::fill(srciter, SrcData.end(), sample); + } + + /* Store the last source samples used for next time. */ + std::copy_n(&SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS], + chandata.mPrevSamples.size(), chandata.mPrevSamples.begin()); + + /* Resample, then apply ambisonic upsampling as needed. */ + const ALfloat *ResampledData{Resample(&mResampleState, + &SrcData[MAX_RESAMPLER_PADDING>>1], DataPosFrac, increment, + {Device->ResampledData, DstBufferSize})}; + if((mFlags&VOICE_IS_AMBISONIC)) + { + const ALfloat hfscale{chandata.mAmbiScale}; + /* Beware the evil const_cast. It's safe since it's pointing to + * either SourceData or ResampledData (both non-const), but the + * resample method takes the source as const float* and may + * return it without copying to output, making it currently + * unavoidable. + */ + chandata.mAmbiSplitter.applyHfScale(const_cast(ResampledData), hfscale, + DstBufferSize); + } + + /* Now filter and mix to the appropriate outputs. */ + ALfloat (&FilterBuf)[BUFFERSIZE] = Device->FilteredData; + { + DirectParams &parms = chandata.mDryParams; + const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, FilterBuf, + ResampledData, DstBufferSize, mDirect.FilterType)}; + + if((mFlags&VOICE_HAS_HRTF)) + { + const ALfloat TargetGain{UNLIKELY(vstate == ALvoice::Stopping) ? 0.0f : + parms.Hrtf.Target.Gain}; + DoHrtfMix(mDirect, TargetGain, parms, samples, DstBufferSize, Counter, OutPos, + IrSize, Device); + } + else if((mFlags&VOICE_HAS_NFC)) + { + const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? + SilentTarget : parms.Gains.Target}; + DoNfcMix(mDirect, TargetGains, parms, samples, DstBufferSize, Counter, OutPos, + Device); + } + else + { + const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? + SilentTarget : parms.Gains.Target}; + MixSamples({samples, DstBufferSize}, mDirect.Buffer, parms.Gains.Current, + TargetGains, Counter, OutPos); + } + } + + for(ALuint send{0};send < NumSends;++send) + { + if(mSend[send].Buffer.empty()) + continue; + + SendParams &parms = chandata.mWetParams[send]; + const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, FilterBuf, + ResampledData, DstBufferSize, mSend[send].FilterType)}; + + const ALfloat *TargetGains{UNLIKELY(vstate==ALvoice::Stopping) ? SilentTarget : + parms.Gains.Target}; + MixSamples({samples, DstBufferSize}, mSend[send].Buffer, parms.Gains.Current, + TargetGains, Counter, OutPos); + } + } + /* Update positions */ + DataPosFrac += increment*DstBufferSize; + DataPosInt += DataPosFrac>>FRACTIONBITS; + DataPosFrac &= FRACTIONMASK; + + OutPos += DstBufferSize; + Counter = maxu(DstBufferSize, Counter) - DstBufferSize; + + if UNLIKELY(!BufferListItem) + { + /* Do nothing extra when there's no buffers. */ + } + else if(isstatic) + { + if(BufferLoopItem) + { + /* Handle looping static source */ + const ALbuffer *Buffer{BufferListItem->mBuffer}; + const ALuint LoopStart{Buffer->LoopStart}; + const ALuint LoopEnd{Buffer->LoopEnd}; + if(DataPosInt >= LoopEnd) + { + assert(LoopEnd > LoopStart); + DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart; + } + } + else + { + /* Handle non-looping static source */ + if(DataPosInt >= BufferListItem->mSampleLen) + { + if LIKELY(vstate == ALvoice::Playing) + vstate = ALvoice::Stopped; + BufferListItem = nullptr; + break; + } + } + } + else while(1) + { + /* Handle streaming source */ + if(BufferListItem->mSampleLen > DataPosInt) + break; + + DataPosInt -= BufferListItem->mSampleLen; + + ++buffers_done; + BufferListItem = BufferListItem->mNext.load(std::memory_order_relaxed); + if(!BufferListItem) BufferListItem = BufferLoopItem; + if(!BufferListItem) + { + if LIKELY(vstate == ALvoice::Playing) + vstate = ALvoice::Stopped; + break; + } + } + } while(OutPos < SamplesToDo); + + mFlags |= VOICE_IS_FADING; + + /* Don't update positions and buffers if we were stopping. */ + if UNLIKELY(vstate == ALvoice::Stopping) + { + mPlayState.store(ALvoice::Stopped, std::memory_order_release); + return; + } + + /* Capture the source ID in case it's reset for stopping. */ + const ALuint SourceID{mSourceID.load(std::memory_order_relaxed)}; + + /* Update voice info */ + mPosition.store(DataPosInt, std::memory_order_relaxed); + mPositionFrac.store(DataPosFrac, std::memory_order_relaxed); + mCurrentBuffer.store(BufferListItem, std::memory_order_relaxed); + if(vstate == ALvoice::Stopped) + { + mLoopBuffer.store(nullptr, std::memory_order_relaxed); + mSourceID.store(0u, std::memory_order_relaxed); + } + std::atomic_thread_fence(std::memory_order_release); + + /* Send any events now, after the position/buffer info was updated. */ + const ALbitfieldSOFT enabledevt{Context->mEnabledEvts.load(std::memory_order_acquire)}; + if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) + { + RingBuffer *ring{Context->mAsyncEvents.get()}; + auto evt_vec = ring->getWriteVector(); + if(evt_vec.first.len > 0) + { + AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_BufferCompleted}}; + evt->u.bufcomp.id = SourceID; + evt->u.bufcomp.count = buffers_done; + ring->writeAdvance(1); + Context->mEventSem.post(); + } + } + + if(vstate == ALvoice::Stopped) + { + /* If the voice just ended, set it to Stopping so the next render + * ensures any residual noise fades to 0 amplitude. + */ + mPlayState.store(ALvoice::Stopping, std::memory_order_release); + if((enabledevt&EventType_SourceStateChange)) + SendSourceStoppedEvent(Context, SourceID); + } +} -- cgit v1.2.3 From d639935e1975db4276f6ee8c3622684cefa6b269 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 Oct 2019 15:37:33 -0700 Subject: Move a couple types to the source they're used in --- alc/alu.h | 6 ------ alc/voice.cpp | 7 +++++++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/alc/alu.h b/alc/alu.h index 06be1a01..90a28654 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -317,12 +317,6 @@ using MixerFunc = void(*)(const al::span InSamples, const size_t Counter, const size_t OutPos); using RowMixerFunc = void(*)(const al::span OutBuffer, const al::span Gains, const float *InSamples, const size_t InStride); -using HrtfMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, - MixHrtfFilter *hrtfparams, const size_t BufferSize); -using HrtfMixerBlendFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, - const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize); using HrtfDirectMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, const size_t BufferSize); diff --git a/alc/voice.cpp b/alc/voice.cpp index d6be174e..a828e21f 100644 --- a/alc/voice.cpp +++ b/alc/voice.cpp @@ -74,6 +74,13 @@ RowMixerFunc MixRowSamples = MixRow_; namespace { +using HrtfMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, + MixHrtfFilter *hrtfparams, const size_t BufferSize); +using HrtfMixerBlendFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, + const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize); + HrtfMixerFunc MixHrtfSamples = MixHrtf_; HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_; -- cgit v1.2.3 From 64e2c377d865d67efdac675c355e7b1a6b4166e6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 Oct 2019 16:53:23 -0700 Subject: Move ALvoice from alu.h to a separate header --- CMakeLists.txt | 1 + alc/alcontext.h | 1 + alc/alu.cpp | 44 ++++++-- alc/alu.h | 287 +------------------------------------------------ alc/converter.h | 1 + alc/mixer/defs.h | 16 ++- alc/mixer/hrtfbase.h | 1 + alc/voice.cpp | 34 +----- alc/voice.h | 293 +++++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 352 insertions(+), 326 deletions(-) create mode 100644 alc/voice.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 46fb692a..03c60162 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -632,6 +632,7 @@ SET(ALC_OBJS alc/uhjfilter.h alc/uiddefs.cpp alc/voice.cpp + alc/voice.h alc/mixer/defs.h alc/mixer/hrtfbase.h alc/mixer/mixer_c.cpp diff --git a/alc/alcontext.h b/alc/alcontext.h index dd622654..ba3942f5 100644 --- a/alc/alcontext.h +++ b/alc/alcontext.h @@ -22,6 +22,7 @@ #include "logging.h" #include "threads.h" #include "vector.h" +#include "voice.h" struct ALeffectslot; struct ALeffectslotProps; diff --git a/alc/alu.cpp b/alc/alu.cpp index 21eea1db..6d3e5549 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -25,14 +25,12 @@ #include #include #include -#include #include #include #include #include #include #include -#include #include #include #include @@ -78,6 +76,7 @@ #include "threads.h" #include "uhjfilter.h" #include "vecmat.h" +#include "voice.h" #include "bsinc_inc.h" @@ -122,21 +121,50 @@ const ALfloat ConeScale{InitConeScale()}; /* Localized Z scalar for mono sources */ const ALfloat ZScale{InitZScale()}; +MixerFunc MixSamples{Mix_}; +RowMixerFunc MixRowSamples{MixRow_}; namespace { -void ClearArray(ALfloat (&f)[MAX_OUTPUT_CHANNELS]) -{ - std::fill(std::begin(f), std::end(f), 0.0f); -} - struct ChanMap { Channel channel; ALfloat angle; ALfloat elevation; }; +void ClearArray(ALfloat (&f)[MAX_OUTPUT_CHANNELS]) +{ + std::fill(std::begin(f), std::end(f), 0.0f); +} + HrtfDirectMixerFunc MixDirectHrtf = MixDirectHrtf_; + +inline MixerFunc SelectMixer() +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return Mix_; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return Mix_; +#endif + return Mix_; +} + +inline RowMixerFunc SelectRowMixer() +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return MixRow_; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixRow_; +#endif + return MixRow_; +} + inline HrtfDirectMixerFunc SelectHrtfMixer(void) { #ifdef HAVE_NEON @@ -232,6 +260,8 @@ inline ResamplerFunc SelectResampler(Resampler resampler, ALuint increment) void aluInit(void) { + MixSamples = SelectMixer(); + MixRowSamples = SelectRowMixer(); MixDirectHrtf = SelectHrtfMixer(); } diff --git a/alc/alu.h b/alc/alu.h index 90a28654..e10bd7ab 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -25,9 +25,9 @@ struct ALbufferlistitem; struct ALeffectslot; - enum class DistanceModel; + #define MAX_PITCH 255 #define MAX_SENDS 16 @@ -35,283 +35,6 @@ enum class DistanceModel; #define DITHER_RNG_SEED 22222 -enum SpatializeMode { - SpatializeOff = AL_FALSE, - SpatializeOn = AL_TRUE, - SpatializeAuto = AL_AUTO_SOFT -}; - -enum class Resampler { - Point, - Linear, - Cubic, - FastBSinc12, - BSinc12, - FastBSinc24, - BSinc24, - - Max = BSinc24 -}; -extern Resampler ResamplerDefault; - -/* The number of distinct scale and phase intervals within the bsinc filter - * table. - */ -#define BSINC_SCALE_BITS 4 -#define BSINC_SCALE_COUNT (1< dst); - - -enum { - AF_None = 0, - AF_LowPass = 1, - AF_HighPass = 2, - AF_BandPass = AF_LowPass | AF_HighPass -}; - - -struct MixHrtfFilter { - const HrirArray *Coeffs; - ALsizei Delay[2]; - ALfloat Gain; - ALfloat GainStep; -}; - - -struct DirectParams { - BiquadFilter LowPass; - BiquadFilter HighPass; - - NfcFilter NFCtrlFilter; - - struct { - HrtfFilter Old; - HrtfFilter Target; - HrtfState State; - } Hrtf; - - struct { - ALfloat Current[MAX_OUTPUT_CHANNELS]; - ALfloat Target[MAX_OUTPUT_CHANNELS]; - } Gains; -}; - -struct SendParams { - BiquadFilter LowPass; - BiquadFilter HighPass; - - struct { - ALfloat Current[MAX_OUTPUT_CHANNELS]; - ALfloat Target[MAX_OUTPUT_CHANNELS]; - } Gains; -}; - - -struct ALvoicePropsBase { - ALfloat Pitch; - ALfloat Gain; - ALfloat OuterGain; - ALfloat MinGain; - ALfloat MaxGain; - ALfloat InnerAngle; - ALfloat OuterAngle; - ALfloat RefDistance; - ALfloat MaxDistance; - ALfloat RolloffFactor; - std::array Position; - std::array Velocity; - std::array Direction; - std::array OrientAt; - std::array OrientUp; - ALboolean HeadRelative; - DistanceModel mDistanceModel; - Resampler mResampler; - ALboolean DirectChannels; - SpatializeMode mSpatializeMode; - - ALboolean DryGainHFAuto; - ALboolean WetGainAuto; - ALboolean WetGainHFAuto; - ALfloat OuterGainHF; - - ALfloat AirAbsorptionFactor; - ALfloat RoomRolloffFactor; - ALfloat DopplerFactor; - - std::array StereoPan; - - ALfloat Radius; - - /** Direct filter and auxiliary send info. */ - struct { - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - } Direct; - struct SendData { - ALeffectslot *Slot; - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - } Send[MAX_SENDS]; -}; - -struct ALvoiceProps : public ALvoicePropsBase { - std::atomic next{nullptr}; - - DEF_NEWDEL(ALvoiceProps) -}; - -#define VOICE_IS_STATIC (1u<<0) -#define VOICE_IS_FADING (1u<<1) /* Fading sources use gain stepping for smooth transitions. */ -#define VOICE_IS_AMBISONIC (1u<<2) /* Voice needs HF scaling for ambisonic upsampling. */ -#define VOICE_HAS_HRTF (1u<<3) -#define VOICE_HAS_NFC (1u<<4) - -struct ALvoice { - enum State { - Stopped = 0, - Playing = 1, - Stopping = 2 - }; - - std::atomic mUpdate{nullptr}; - - std::atomic mSourceID{0u}; - std::atomic mPlayState{Stopped}; - - ALvoicePropsBase mProps; - - /** - * Source offset in samples, relative to the currently playing buffer, NOT - * the whole queue. - */ - std::atomic mPosition; - /** Fractional (fixed-point) offset to the next sample. */ - std::atomic mPositionFrac; - - /* Current buffer queue item being played. */ - std::atomic mCurrentBuffer; - - /* Buffer queue item to loop to at end of queue (will be NULL for non- - * looping voices). - */ - std::atomic mLoopBuffer; - - /* Properties for the attached buffer(s). */ - FmtChannels mFmtChannels; - ALuint mFrequency; - ALuint mNumChannels; - ALuint mSampleSize; - - /** Current target parameters used for mixing. */ - ALuint mStep; - - ResamplerFunc mResampler; - - InterpState mResampleState; - - ALuint mFlags; - - struct DirectData { - int FilterType; - al::span Buffer; - }; - DirectData mDirect; - - struct SendData { - int FilterType; - al::span Buffer; - }; - std::array mSend; - - struct ChannelData { - alignas(16) std::array mPrevSamples; - - ALfloat mAmbiScale; - BandSplitter mAmbiSplitter; - - DirectParams mDryParams; - std::array mWetParams; - }; - std::array mChans; - - ALvoice() = default; - ALvoice(const ALvoice&) = delete; - ALvoice(ALvoice&& rhs) noexcept { *this = std::move(rhs); } - ~ALvoice() { delete mUpdate.exchange(nullptr, std::memory_order_acq_rel); } - ALvoice& operator=(const ALvoice&) = delete; - ALvoice& operator=(ALvoice&& rhs) noexcept - { - ALvoiceProps *old_update{mUpdate.load(std::memory_order_relaxed)}; - mUpdate.store(rhs.mUpdate.exchange(old_update, std::memory_order_relaxed), - std::memory_order_relaxed); - - mSourceID.store(rhs.mSourceID.load(std::memory_order_relaxed), std::memory_order_relaxed); - mPlayState.store(rhs.mPlayState.load(std::memory_order_relaxed), - std::memory_order_relaxed); - - mProps = rhs.mProps; - - mPosition.store(rhs.mPosition.load(std::memory_order_relaxed), std::memory_order_relaxed); - mPositionFrac.store(rhs.mPositionFrac.load(std::memory_order_relaxed), - std::memory_order_relaxed); - - mCurrentBuffer.store(rhs.mCurrentBuffer.load(std::memory_order_relaxed), - std::memory_order_relaxed); - mLoopBuffer.store(rhs.mLoopBuffer.load(std::memory_order_relaxed), - std::memory_order_relaxed); - - mFmtChannels = rhs.mFmtChannels; - mFrequency = rhs.mFrequency; - mNumChannels = rhs.mNumChannels; - mSampleSize = rhs.mSampleSize; - - mStep = rhs.mStep; - mResampler = rhs.mResampler; - - mResampleState = rhs.mResampleState; - - mFlags = rhs.mFlags; - - mDirect = rhs.mDirect; - mSend = rhs.mSend; - mChans = rhs.mChans; - - return *this; - } - - void mix(ALvoice::State vstate, ALCcontext *Context, const ALuint SamplesToDo); -}; - - using MixerFunc = void(*)(const al::span InSamples, const al::span OutBuffer, float *CurrentGains, const float *TargetGains, const size_t Counter, const size_t OutPos); @@ -321,6 +44,9 @@ using HrtfDirectMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &R const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, const size_t BufferSize); +extern MixerFunc MixSamples; +extern RowMixerFunc MixRowSamples; + #define GAIN_MIX_MAX (1000.0f) /* +60dB */ @@ -369,8 +95,6 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, HrtfRequestMode hrtf_appr void aluInitEffectPanning(ALeffectslot *slot, ALCdevice *device); -ResamplerFunc PrepareResampler(Resampler resampler, ALuint increment, InterpState *state); - /** * Calculates ambisonic encoder coefficients using the X, Y, and Z direction * components, which must represent a normalized (unit length) vector, and the @@ -441,9 +165,6 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, const ALuint NumSamples); /* Caller must lock the device state, and the mixer must not be running. */ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) DECL_FORMAT(printf, 2, 3); -extern MixerFunc MixSamples; -extern RowMixerFunc MixRowSamples; - extern const ALfloat ConeScale; extern const ALfloat ZScale; diff --git a/alc/converter.h b/alc/converter.h index d8fe7ba9..5842df07 100644 --- a/alc/converter.h +++ b/alc/converter.h @@ -11,6 +11,7 @@ #include "alnumeric.h" #include "alu.h" #include "devformat.h" +#include "voice.h" struct SampleConverter { diff --git a/alc/mixer/defs.h b/alc/mixer/defs.h index ce572973..b72b2526 100644 --- a/alc/mixer/defs.h +++ b/alc/mixer/defs.h @@ -5,9 +5,11 @@ #include "alcmain.h" #include "alspan.h" -#include "alu.h" #include "hrtf.h" +union InterpState; +struct MixHrtfFilter; + enum InstSetType { CTag, @@ -39,11 +41,17 @@ void MixRow_(const al::span OutBuffer, const al::span Gains, const float *InSamples, const size_t InStride); template -void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize); +void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, + float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, MixHrtfFilter *hrtfparams, + const size_t BufferSize); template -void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize); +void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, + float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, const HrtfFilter *oldparams, + MixHrtfFilter *newparams, const size_t BufferSize); template -void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, const size_t BufferSize); +void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, + const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, + const size_t BufferSize); /* Vectorized resampler helpers */ inline void InitPosArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, diff --git a/alc/mixer/hrtfbase.h b/alc/mixer/hrtfbase.h index d2432e90..af45a128 100644 --- a/alc/mixer/hrtfbase.h +++ b/alc/mixer/hrtfbase.h @@ -6,6 +6,7 @@ #include "alu.h" #include "../hrtf.h" #include "opthelpers.h" +#include "voice.h" using ApplyCoeffsT = void(size_t Offset, float2 *RESTRICT Values, const ALuint irSize, diff --git a/alc/voice.cpp b/alc/voice.cpp index a828e21f..59360e4e 100644 --- a/alc/voice.cpp +++ b/alc/voice.cpp @@ -20,6 +20,8 @@ #include "config.h" +#include "voice.h" + #include #include #include @@ -30,7 +32,6 @@ #include #include #include -#include #include #include "AL/al.h" @@ -69,9 +70,6 @@ static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, Resampler ResamplerDefault{Resampler::Linear}; -MixerFunc MixSamples = Mix_; -RowMixerFunc MixRowSamples = MixRow_; - namespace { using HrtfMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, @@ -84,32 +82,6 @@ using HrtfMixerBlendFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &Ri HrtfMixerFunc MixHrtfSamples = MixHrtf_; HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_; -inline MixerFunc SelectMixer() -{ -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return Mix_; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return Mix_; -#endif - return Mix_; -} - -inline RowMixerFunc SelectRowMixer() -{ -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return MixRow_; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return MixRow_; -#endif - return MixRow_; -} - inline HrtfMixerFunc SelectHrtfMixer() { #ifdef HAVE_NEON @@ -180,8 +152,6 @@ void aluInitMixer() MixHrtfBlendSamples = SelectHrtfBlendMixer(); MixHrtfSamples = SelectHrtfMixer(); - MixSamples = SelectMixer(); - MixRowSamples = SelectRowMixer(); } diff --git a/alc/voice.h b/alc/voice.h new file mode 100644 index 00000000..c4bea635 --- /dev/null +++ b/alc/voice.h @@ -0,0 +1,293 @@ +#ifndef VOICE_H +#define VOICE_H + +#include "AL/al.h" +#include "AL/alext.h" + +#include "alspan.h" +#include "alu.h" +#include "filters/biquad.h" +#include "filters/nfc.h" +#include "filters/splitter.h" +#include "hrtf.h" + + +enum SpatializeMode { + SpatializeOff = AL_FALSE, + SpatializeOn = AL_TRUE, + SpatializeAuto = AL_AUTO_SOFT +}; + +enum class Resampler { + Point, + Linear, + Cubic, + FastBSinc12, + BSinc12, + FastBSinc24, + BSinc24, + + Max = BSinc24 +}; +extern Resampler ResamplerDefault; + +/* The number of distinct scale and phase intervals within the bsinc filter + * table. + */ +#define BSINC_SCALE_BITS 4 +#define BSINC_SCALE_COUNT (1< dst); + +ResamplerFunc PrepareResampler(Resampler resampler, ALuint increment, InterpState *state); + + +enum { + AF_None = 0, + AF_LowPass = 1, + AF_HighPass = 2, + AF_BandPass = AF_LowPass | AF_HighPass +}; + + +struct MixHrtfFilter { + const HrirArray *Coeffs; + ALsizei Delay[2]; + float Gain; + float GainStep; +}; + + +struct DirectParams { + BiquadFilter LowPass; + BiquadFilter HighPass; + + NfcFilter NFCtrlFilter; + + struct { + HrtfFilter Old; + HrtfFilter Target; + HrtfState State; + } Hrtf; + + struct { + float Current[MAX_OUTPUT_CHANNELS]; + float Target[MAX_OUTPUT_CHANNELS]; + } Gains; +}; + +struct SendParams { + BiquadFilter LowPass; + BiquadFilter HighPass; + + struct { + float Current[MAX_OUTPUT_CHANNELS]; + float Target[MAX_OUTPUT_CHANNELS]; + } Gains; +}; + + +struct ALvoicePropsBase { + float Pitch; + float Gain; + float OuterGain; + float MinGain; + float MaxGain; + float InnerAngle; + float OuterAngle; + float RefDistance; + float MaxDistance; + float RolloffFactor; + std::array Position; + std::array Velocity; + std::array Direction; + std::array OrientAt; + std::array OrientUp; + bool HeadRelative; + DistanceModel mDistanceModel; + Resampler mResampler; + bool DirectChannels; + SpatializeMode mSpatializeMode; + + bool DryGainHFAuto; + bool WetGainAuto; + bool WetGainHFAuto; + float OuterGainHF; + + float AirAbsorptionFactor; + float RoomRolloffFactor; + float DopplerFactor; + + std::array StereoPan; + + float Radius; + + /** Direct filter and auxiliary send info. */ + struct { + float Gain; + float GainHF; + float HFReference; + float GainLF; + float LFReference; + } Direct; + struct SendData { + ALeffectslot *Slot; + float Gain; + float GainHF; + float HFReference; + float GainLF; + float LFReference; + } Send[MAX_SENDS]; +}; + +struct ALvoiceProps : public ALvoicePropsBase { + std::atomic next{nullptr}; + + DEF_NEWDEL(ALvoiceProps) +}; + +#define VOICE_IS_STATIC (1u<<0) +#define VOICE_IS_FADING (1u<<1) /* Fading sources use gain stepping for smooth transitions. */ +#define VOICE_IS_AMBISONIC (1u<<2) /* Voice needs HF scaling for ambisonic upsampling. */ +#define VOICE_HAS_HRTF (1u<<3) +#define VOICE_HAS_NFC (1u<<4) + +struct ALvoice { + enum State { + Stopped = 0, + Playing = 1, + Stopping = 2 + }; + + std::atomic mUpdate{nullptr}; + + std::atomic mSourceID{0u}; + std::atomic mPlayState{Stopped}; + + ALvoicePropsBase mProps; + + /** + * Source offset in samples, relative to the currently playing buffer, NOT + * the whole queue. + */ + std::atomic mPosition; + /** Fractional (fixed-point) offset to the next sample. */ + std::atomic mPositionFrac; + + /* Current buffer queue item being played. */ + std::atomic mCurrentBuffer; + + /* Buffer queue item to loop to at end of queue (will be NULL for non- + * looping voices). + */ + std::atomic mLoopBuffer; + + /* Properties for the attached buffer(s). */ + FmtChannels mFmtChannels; + ALuint mFrequency; + ALuint mNumChannels; + ALuint mSampleSize; + + /** Current target parameters used for mixing. */ + ALuint mStep; + + ResamplerFunc mResampler; + + InterpState mResampleState; + + ALuint mFlags; + + struct DirectData { + int FilterType; + al::span Buffer; + }; + DirectData mDirect; + + struct SendData { + int FilterType; + al::span Buffer; + }; + std::array mSend; + + struct ChannelData { + alignas(16) std::array mPrevSamples; + + ALfloat mAmbiScale; + BandSplitter mAmbiSplitter; + + DirectParams mDryParams; + std::array mWetParams; + }; + std::array mChans; + + ALvoice() = default; + ALvoice(const ALvoice&) = delete; + ALvoice(ALvoice&& rhs) noexcept { *this = std::move(rhs); } + ~ALvoice() { delete mUpdate.exchange(nullptr, std::memory_order_acq_rel); } + ALvoice& operator=(const ALvoice&) = delete; + ALvoice& operator=(ALvoice&& rhs) noexcept + { + ALvoiceProps *old_update{mUpdate.load(std::memory_order_relaxed)}; + mUpdate.store(rhs.mUpdate.exchange(old_update, std::memory_order_relaxed), + std::memory_order_relaxed); + + mSourceID.store(rhs.mSourceID.load(std::memory_order_relaxed), std::memory_order_relaxed); + mPlayState.store(rhs.mPlayState.load(std::memory_order_relaxed), + std::memory_order_relaxed); + + mProps = rhs.mProps; + + mPosition.store(rhs.mPosition.load(std::memory_order_relaxed), std::memory_order_relaxed); + mPositionFrac.store(rhs.mPositionFrac.load(std::memory_order_relaxed), + std::memory_order_relaxed); + + mCurrentBuffer.store(rhs.mCurrentBuffer.load(std::memory_order_relaxed), + std::memory_order_relaxed); + mLoopBuffer.store(rhs.mLoopBuffer.load(std::memory_order_relaxed), + std::memory_order_relaxed); + + mFmtChannels = rhs.mFmtChannels; + mFrequency = rhs.mFrequency; + mNumChannels = rhs.mNumChannels; + mSampleSize = rhs.mSampleSize; + + mStep = rhs.mStep; + mResampler = rhs.mResampler; + + mResampleState = rhs.mResampleState; + + mFlags = rhs.mFlags; + + mDirect = rhs.mDirect; + mSend = rhs.mSend; + mChans = rhs.mChans; + + return *this; + } + + void mix(ALvoice::State vstate, ALCcontext *Context, const ALuint SamplesToDo); +}; + +#endif /* VOICE_H */ -- cgit v1.2.3 From 50198ee30c86f566f538e2ffd763caaaba1c45d4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 Oct 2019 17:07:23 -0700 Subject: Clean up some ALfloat -> float --- alc/mixer/defs.h | 4 ++-- alc/mixer/hrtfbase.h | 40 ++++++++++++++++++++-------------------- alc/mixer/mixer_c.cpp | 48 +++++++++++++++++++++++------------------------- alc/mixer/mixer_neon.cpp | 18 ++++++++---------- alc/mixer/mixer_sse.cpp | 20 +++++++++----------- alc/voice.h | 6 +++--- 6 files changed, 65 insertions(+), 71 deletions(-) diff --git a/alc/mixer/defs.h b/alc/mixer/defs.h index b72b2526..b2535265 100644 --- a/alc/mixer/defs.h +++ b/alc/mixer/defs.h @@ -41,11 +41,11 @@ void MixRow_(const al::span OutBuffer, const al::span Gains, const float *InSamples, const size_t InStride); template -void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, +void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize); template -void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const ALfloat *InSamples, +void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize); template diff --git a/alc/mixer/hrtfbase.h b/alc/mixer/hrtfbase.h index af45a128..58d168ed 100644 --- a/alc/mixer/hrtfbase.h +++ b/alc/mixer/hrtfbase.h @@ -10,29 +10,29 @@ using ApplyCoeffsT = void(size_t Offset, float2 *RESTRICT Values, const ALuint irSize, - const HrirArray &Coeffs, const ALfloat left, const ALfloat right); + const HrirArray &Coeffs, const float left, const float right); template inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *RESTRICT AccumSamples, const size_t OutPos, + const float *InSamples, float2 *RESTRICT AccumSamples, const size_t OutPos, const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) { ASSUME(BufferSize > 0); const HrirArray &Coeffs = *hrtfparams->Coeffs; - const ALfloat gainstep{hrtfparams->GainStep}; - const ALfloat gain{hrtfparams->Gain}; + const float gainstep{hrtfparams->GainStep}; + const float gain{hrtfparams->Gain}; ALsizei Delay[2]{ HRTF_HISTORY_LENGTH - hrtfparams->Delay[0], HRTF_HISTORY_LENGTH - hrtfparams->Delay[1] }; ASSUME(Delay[0] >= 0 && Delay[1] >= 0); - ALfloat stepcount{0.0f}; + float stepcount{0.0f}; for(size_t i{0u};i < BufferSize;++i) { - const ALfloat g{gain + gainstep*stepcount}; - const ALfloat left{InSamples[Delay[0]++] * g}; - const ALfloat right{InSamples[Delay[1]++] * g}; + const float g{gain + gainstep*stepcount}; + const float left{InSamples[Delay[0]++] * g}; + const float right{InSamples[Delay[1]++] * g}; ApplyCoeffs(i, AccumSamples+i, IrSize, Coeffs, left, right); stepcount += 1.0f; @@ -48,15 +48,15 @@ inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *RESTRICT AccumSamples, const size_t OutPos, + const float *InSamples, float2 *RESTRICT AccumSamples, const size_t OutPos, const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { const auto &OldCoeffs = oldparams->Coeffs; - const ALfloat oldGain{oldparams->Gain}; - const ALfloat oldGainStep{-oldGain / static_cast(BufferSize)}; + const float oldGain{oldparams->Gain}; + const float oldGainStep{-oldGain / static_cast(BufferSize)}; const auto &NewCoeffs = *newparams->Coeffs; - const ALfloat newGainStep{newparams->GainStep}; + const float newGainStep{newparams->GainStep}; ASSUME(BufferSize > 0); @@ -64,12 +64,12 @@ inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut HRTF_HISTORY_LENGTH - oldparams->Delay[0], HRTF_HISTORY_LENGTH - oldparams->Delay[1] }; ASSUME(Delay[0] >= 0 && Delay[1] >= 0); - ALfloat stepcount{0.0f}; + float stepcount{0.0f}; for(size_t i{0u};i < BufferSize;++i) { - const ALfloat g{oldGain + oldGainStep*stepcount}; - const ALfloat left{InSamples[Delay[0]++] * g}; - const ALfloat right{InSamples[Delay[1]++] * g}; + const float g{oldGain + oldGainStep*stepcount}; + const float left{InSamples[Delay[0]++] * g}; + const float right{InSamples[Delay[1]++] * g}; ApplyCoeffs(i, AccumSamples+i, IrSize, OldCoeffs, left, right); stepcount += 1.0f; @@ -81,9 +81,9 @@ inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut stepcount = 0.0f; for(size_t i{0u};i < BufferSize;++i) { - const ALfloat g{newGainStep*stepcount}; - const ALfloat left{InSamples[Delay[0]++] * g}; - const ALfloat right{InSamples[Delay[1]++] * g}; + const float g{newGainStep*stepcount}; + const float left{InSamples[Delay[0]++] * g}; + const float right{InSamples[Delay[1]++] * g}; ApplyCoeffs(i, AccumSamples+i, IrSize, NewCoeffs, left, right); stepcount += 1.0f; @@ -115,7 +115,7 @@ inline void MixDirectHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOu const auto &Coeffs = *(coeff_iter++); for(size_t i{0u};i < BufferSize;++i) { - const ALfloat insample{input[i]}; + const float insample{input[i]}; ApplyCoeffs(i, AccumSamples+i, IrSize, Coeffs, insample, insample); } } diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index f2164f53..8aa32e6b 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -13,64 +13,64 @@ namespace { -inline ALfloat do_point(const InterpState&, const ALfloat *RESTRICT vals, const ALuint) +inline float do_point(const InterpState&, const float *RESTRICT vals, const ALuint) { return vals[0]; } -inline ALfloat do_lerp(const InterpState&, const ALfloat *RESTRICT vals, const ALuint frac) +inline float do_lerp(const InterpState&, const float *RESTRICT vals, const ALuint frac) { return lerp(vals[0], vals[1], static_cast(frac)*(1.0f/FRACTIONONE)); } -inline ALfloat do_cubic(const InterpState&, const ALfloat *RESTRICT vals, const ALuint frac) +inline float do_cubic(const InterpState&, const float *RESTRICT vals, const ALuint frac) { return cubic(vals[0], vals[1], vals[2], vals[3], static_cast(frac)*(1.0f/FRACTIONONE)); } -inline ALfloat do_bsinc(const InterpState &istate, const ALfloat *RESTRICT vals, const ALuint frac) +inline float do_bsinc(const InterpState &istate, const float *RESTRICT vals, const ALuint frac) { const size_t m{istate.bsinc.m}; // Calculate the phase index and factor. #define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) const ALuint pi{frac >> FRAC_PHASE_BITDIFF}; - const ALfloat pf{static_cast(frac & ((1<(frac & ((1<> FRAC_PHASE_BITDIFF}; - const ALfloat pf{static_cast(frac & ((1<(frac & ((1< -const ALfloat *DoResample(const InterpState *state, const ALfloat *RESTRICT src, - ALuint frac, ALuint increment, const al::span dst) +const float *DoResample(const InterpState *state, const float *RESTRICT src, ALuint frac, + ALuint increment, const al::span dst) { const InterpState istate{*state}; auto proc_sample = [&src,&frac,istate,increment]() -> ALfloat { - const ALfloat ret{Sampler(istate, src, frac)}; + const float ret{Sampler(istate, src, frac)}; frac += increment; src += frac>>FRACTIONBITS; @@ -125,7 +125,7 @@ const ALfloat *Resample_(const InterpState *state, const ALfl static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const ALuint IrSize, - const HrirArray &Coeffs, const ALfloat left, const ALfloat right) + const HrirArray &Coeffs, const float left, const float right) { ASSUME(IrSize >= 4); for(ALuint c{0};c < IrSize;++c) @@ -137,7 +137,7 @@ static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const template<> void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, + const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) { MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, @@ -146,7 +146,7 @@ void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, + const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, @@ -157,9 +157,7 @@ template<> void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, const size_t BufferSize) -{ - MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, BufferSize); -} +{ MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, BufferSize); } template<> diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index 75faa61f..c0fc1651 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -72,7 +72,7 @@ template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALuint frac, ALuint increment, const al::span dst) { - const ALfloat *const filter{state->bsinc.filter}; + const float *const filter{state->bsinc.filter}; const float32x4_t sf4{vdupq_n_f32(state->bsinc.sf)}; const size_t m{state->bsinc.m}; @@ -82,7 +82,7 @@ const ALfloat *Resample_(const InterpState *state, const ALflo // Calculate the phase index and factor. #define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) const ALuint pi{frac >> FRAC_PHASE_BITDIFF}; - const ALfloat pf{static_cast(frac & ((1<(frac & ((1< const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALuint frac, ALuint increment, const al::span dst) { - const ALfloat *const filter{state->bsinc.filter}; + const float *const filter{state->bsinc.filter}; const size_t m{state->bsinc.m}; src -= state->bsinc.l; @@ -131,7 +131,7 @@ const ALfloat *Resample_(const InterpState *state, // Calculate the phase index and factor. #define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) const ALuint pi{frac >> FRAC_PHASE_BITDIFF}; - const ALfloat pf{static_cast(frac & ((1<(frac & ((1<(const InterpState *state, static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const ALuint IrSize, - const HrirArray &Coeffs, const ALfloat left, const ALfloat right) + const HrirArray &Coeffs, const float left, const float right) { ASSUME(IrSize >= 4); @@ -189,7 +189,7 @@ static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const template<> void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, + const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) { MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, @@ -198,7 +198,7 @@ void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, + const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, @@ -209,9 +209,7 @@ template<> void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, const size_t BufferSize) -{ - MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, BufferSize); -} +{ MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, BufferSize); } template<> diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index 84f651d1..0fb954aa 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -7,8 +7,8 @@ #include "AL/al.h" #include "AL/alc.h" #include "alcmain.h" -#include "alu.h" +#include "alu.h" #include "defs.h" #include "hrtfbase.h" @@ -17,7 +17,7 @@ template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALuint frac, ALuint increment, const al::span dst) { - const ALfloat *const filter{state->bsinc.filter}; + const float *const filter{state->bsinc.filter}; const __m128 sf4{_mm_set1_ps(state->bsinc.sf)}; const size_t m{state->bsinc.m}; @@ -27,7 +27,7 @@ const ALfloat *Resample_(const InterpState *state, const ALfloa // Calculate the phase index and factor. #define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) const ALuint pi{frac >> FRAC_PHASE_BITDIFF}; - const ALfloat pf{static_cast(frac & ((1<(frac & ((1< const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALuint frac, ALuint increment, const al::span dst) { - const ALfloat *const filter{state->bsinc.filter}; + const float *const filter{state->bsinc.filter}; const size_t m{state->bsinc.m}; src -= state->bsinc.l; @@ -79,7 +79,7 @@ const ALfloat *Resample_(const InterpState *state, // Calculate the phase index and factor. #define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) const ALuint pi{frac >> FRAC_PHASE_BITDIFF}; - const ALfloat pf{static_cast(frac & ((1<(frac & ((1<(const InterpState *state, static inline void ApplyCoeffs(size_t Offset, float2 *RESTRICT Values, const ALuint IrSize, - const HrirArray &Coeffs, const ALfloat left, const ALfloat right) + const HrirArray &Coeffs, const float left, const float right) { const __m128 lrlr{_mm_setr_ps(left, right, left, right)}; @@ -159,7 +159,7 @@ static inline void ApplyCoeffs(size_t Offset, float2 *RESTRICT Values, const ALu template<> void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, + const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) { MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, @@ -168,7 +168,7 @@ void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, template<> void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, + const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, @@ -179,9 +179,7 @@ template<> void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, const size_t BufferSize) -{ - MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, BufferSize); -} +{ MixDirectHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, State, BufferSize); } template<> diff --git a/alc/voice.h b/alc/voice.h index c4bea635..de77834e 100644 --- a/alc/voice.h +++ b/alc/voice.h @@ -134,7 +134,7 @@ struct ALvoicePropsBase { bool DryGainHFAuto; bool WetGainAuto; bool WetGainHFAuto; - float OuterGainHF; + float OuterGainHF; float AirAbsorptionFactor; float RoomRolloffFactor; @@ -232,9 +232,9 @@ struct ALvoice { std::array mSend; struct ChannelData { - alignas(16) std::array mPrevSamples; + alignas(16) std::array mPrevSamples; - ALfloat mAmbiScale; + float mAmbiScale; BandSplitter mAmbiSplitter; DirectParams mDryParams; -- cgit v1.2.3 From 58085f1c7b64992065e65858d98acfd2c2db3514 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 Oct 2019 19:13:07 -0700 Subject: Clean up some unnecessary includes --- alc/alc.cpp | 5 ++++- alc/alu.h | 16 ---------------- alc/voice.h | 3 +++ 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index fad43f7b..03ed35cc 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -877,6 +877,9 @@ ALeffect DefaultEffect; */ bool SuspendDefers{true}; +/* Initial seed for dithering. */ +constexpr ALuint DitherRNGSeed{22222u}; + /************************************************ * ALC information @@ -1861,7 +1864,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->FixedLatency = nanoseconds::zero(); device->DitherDepth = 0.0f; - device->DitherSeed = DITHER_RNG_SEED; + device->DitherSeed = DitherRNGSeed; /************************************************************************* * Update device format request if HRTF is requested diff --git a/alc/alu.h b/alc/alu.h index e10bd7ab..f4d1e6b2 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -2,39 +2,23 @@ #define ALU_H #include -#include #include #include #include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" -#include "al/buffer.h" #include "alcmain.h" -#include "almalloc.h" #include "alspan.h" -#include "ambidefs.h" -#include "devformat.h" -#include "filters/biquad.h" -#include "filters/nfc.h" -#include "filters/splitter.h" -#include "hrtf.h" #include "logging.h" struct ALbufferlistitem; struct ALeffectslot; -enum class DistanceModel; - #define MAX_PITCH 255 #define MAX_SENDS 16 -#define DITHER_RNG_SEED 22222 - - using MixerFunc = void(*)(const al::span InSamples, const al::span OutBuffer, float *CurrentGains, const float *TargetGains, const size_t Counter, const size_t OutPos); diff --git a/alc/voice.h b/alc/voice.h index de77834e..3b1675e6 100644 --- a/alc/voice.h +++ b/alc/voice.h @@ -4,6 +4,7 @@ #include "AL/al.h" #include "AL/alext.h" +#include "al/buffer.h" #include "alspan.h" #include "alu.h" #include "filters/biquad.h" @@ -11,6 +12,8 @@ #include "filters/splitter.h" #include "hrtf.h" +enum class DistanceModel; + enum SpatializeMode { SpatializeOff = AL_FALSE, -- cgit v1.2.3 From 324fb8d0b7586a339c79ea57389f232470e0d659 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 Oct 2019 19:22:14 -0700 Subject: Fix a comment --- alc/voice.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alc/voice.h b/alc/voice.h index 3b1675e6..309c901f 100644 --- a/alc/voice.h +++ b/alc/voice.h @@ -50,7 +50,7 @@ struct BsincState { float sf; /* Scale interpolation factor. */ ALuint m; /* Coefficient count. */ ALuint l; /* Left coefficient offset. */ - /* Filter coefficients, followed by the scale, phase, and scale-phase + /* Filter coefficients, followed by the phase, scale, and scale-phase * delta coefficients. Starting at phase index 0, each subsequent phase * index follows contiguously. */ -- cgit v1.2.3 From bce6889173245031cf1440d70858180cc2716adf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 Oct 2019 22:20:34 -0700 Subject: Remove an unnecessary struct specifier --- alc/voice.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alc/voice.h b/alc/voice.h index 309c901f..a2a3309c 100644 --- a/alc/voice.h +++ b/alc/voice.h @@ -290,7 +290,7 @@ struct ALvoice { return *this; } - void mix(ALvoice::State vstate, ALCcontext *Context, const ALuint SamplesToDo); + void mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo); }; #endif /* VOICE_H */ -- cgit v1.2.3 From b350ae3766f0f85183c410b4c77ac9a0eb388511 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 Oct 2019 22:38:19 -0700 Subject: Remove the Offset parameter from ApplyCoeffs --- alc/mixer/hrtfbase.h | 18 +++++----- alc/mixer/mixer_c.cpp | 24 ++++++------- alc/mixer/mixer_neon.cpp | 50 +++++++++++++------------- alc/mixer/mixer_sse.cpp | 93 ++++++++++++++++++++++++++---------------------- 4 files changed, 97 insertions(+), 88 deletions(-) diff --git a/alc/mixer/hrtfbase.h b/alc/mixer/hrtfbase.h index 58d168ed..cbc885c5 100644 --- a/alc/mixer/hrtfbase.h +++ b/alc/mixer/hrtfbase.h @@ -9,10 +9,10 @@ #include "voice.h" -using ApplyCoeffsT = void(size_t Offset, float2 *RESTRICT Values, const ALuint irSize, - const HrirArray &Coeffs, const float left, const float right); +using ApplyCoeffsT = void(&)(float2 *RESTRICT Values, const ALuint irSize, const HrirArray &Coeffs, + const float left, const float right); -template +template inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const float *InSamples, float2 *RESTRICT AccumSamples, const size_t OutPos, const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) @@ -33,7 +33,7 @@ inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const float g{gain + gainstep*stepcount}; const float left{InSamples[Delay[0]++] * g}; const float right{InSamples[Delay[1]++] * g}; - ApplyCoeffs(i, AccumSamples+i, IrSize, Coeffs, left, right); + ApplyCoeffs(AccumSamples+i, IrSize, Coeffs, left, right); stepcount += 1.0f; } @@ -46,7 +46,7 @@ inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, hrtfparams->Gain = gain + gainstep*stepcount; } -template +template inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const float *InSamples, float2 *RESTRICT AccumSamples, const size_t OutPos, const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, @@ -70,7 +70,7 @@ inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut const float g{oldGain + oldGainStep*stepcount}; const float left{InSamples[Delay[0]++] * g}; const float right{InSamples[Delay[1]++] * g}; - ApplyCoeffs(i, AccumSamples+i, IrSize, OldCoeffs, left, right); + ApplyCoeffs(AccumSamples+i, IrSize, OldCoeffs, left, right); stepcount += 1.0f; } @@ -84,7 +84,7 @@ inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut const float g{newGainStep*stepcount}; const float left{InSamples[Delay[0]++] * g}; const float right{InSamples[Delay[1]++] * g}; - ApplyCoeffs(i, AccumSamples+i, IrSize, NewCoeffs, left, right); + ApplyCoeffs(AccumSamples+i, IrSize, NewCoeffs, left, right); stepcount += 1.0f; } @@ -97,7 +97,7 @@ inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut newparams->Gain = newGainStep*stepcount; } -template +template inline void MixDirectHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *RESTRICT AccumSamples, DirectHrtfState *State, const size_t BufferSize) @@ -116,7 +116,7 @@ inline void MixDirectHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOu for(size_t i{0u};i < BufferSize;++i) { const float insample{input[i]}; - ApplyCoeffs(i, AccumSamples+i, IrSize, Coeffs, insample, insample); + ApplyCoeffs(AccumSamples+i, IrSize, Coeffs, insample, insample); } } for(size_t i{0u};i < BufferSize;++i) diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index 8aa32e6b..ffc07acd 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -68,7 +68,7 @@ const float *DoResample(const InterpState *state, const float *RESTRICT src, ALu ALuint increment, const al::span dst) { const InterpState istate{*state}; - auto proc_sample = [&src,&frac,istate,increment]() -> ALfloat + auto proc_sample = [&src,&frac,istate,increment]() -> float { const float ret{Sampler(istate, src, frac)}; @@ -83,6 +83,17 @@ const float *DoResample(const InterpState *state, const float *RESTRICT src, ALu return dst.begin(); } +inline void ApplyCoeffs(float2 *RESTRICT Values, const ALuint IrSize, const HrirArray &Coeffs, + const float left, const float right) +{ + ASSUME(IrSize >= 4); + for(ALuint c{0};c < IrSize;++c) + { + Values[c][0] += Coeffs[c][0] * left; + Values[c][1] += Coeffs[c][1] * right; + } +} + } // namespace template<> @@ -124,17 +135,6 @@ const ALfloat *Resample_(const InterpState *state, const ALfl { return DoResample(state, src-state->bsinc.l, frac, increment, dst); } -static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const ALuint IrSize, - const HrirArray &Coeffs, const float left, const float right) -{ - ASSUME(IrSize >= 4); - for(ALuint c{0};c < IrSize;++c) - { - Values[c][0] += Coeffs[c][0] * left; - Values[c][1] += Coeffs[c][1] * right; - } -} - template<> void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index c0fc1651..ae782897 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -13,6 +13,32 @@ #include "hrtfbase.h" +namespace { + +inline void ApplyCoeffs(float2 *RESTRICT Values, const ALuint IrSize, const HrirArray &Coeffs, + const float left, const float right) +{ + 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); + } + + ASSUME(IrSize >= 4); + for(ALuint c{0};c < IrSize;c += 2) + { + float32x4_t vals = vld1q_f32(&Values[c][0]); + float32x4_t coefs = vld1q_f32(&Coeffs[c][0]); + + vals = vmlaq_f32(vals, coefs, leftright4); + + vst1q_f32(&Values[c][0], vals); + } +} + +} // namespace template<> const ALfloat *Resample_(const InterpState*, const ALfloat *RESTRICT src, @@ -163,30 +189,6 @@ const ALfloat *Resample_(const InterpState *state, } -static inline void ApplyCoeffs(size_t /*Offset*/, float2 *RESTRICT Values, const ALuint IrSize, - const HrirArray &Coeffs, const float left, const float right) -{ - ASSUME(IrSize >= 4); - - 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(ALuint c{0};c < IrSize;c += 2) - { - float32x4_t vals = vld1q_f32(&Values[c][0]); - float32x4_t coefs = vld1q_f32(&Coeffs[c][0]); - - vals = vmlaq_f32(vals, coefs, leftright4); - - vst1q_f32(&Values[c][0], vals); - } -} - template<> void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index 0fb954aa..62ce5eab 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -13,6 +13,56 @@ #include "hrtfbase.h" +namespace { + +inline void ApplyCoeffs(float2 *RESTRICT Values, const ALuint IrSize, const HrirArray &Coeffs, + const float left, const float right) +{ + const __m128 lrlr{_mm_setr_ps(left, right, left, right)}; + + ASSUME(IrSize >= 4); + /* This isn't technically correct to test alignment, but it's true for + * systems that support SSE, which is the only one that needs to know the + * alignment of Values (which alternates between 8- and 16-byte aligned). + */ + if(reinterpret_cast(Values)&0x8) + { + __m128 imp0, imp1; + __m128 coeffs{_mm_load_ps(&Coeffs[0][0])}; + __m128 vals{_mm_loadl_pi(_mm_setzero_ps(), reinterpret_cast<__m64*>(&Values[0][0]))}; + imp0 = _mm_mul_ps(lrlr, coeffs); + vals = _mm_add_ps(imp0, vals); + _mm_storel_pi(reinterpret_cast<__m64*>(&Values[0][0]), vals); + ALuint i{1}; + for(;i < IrSize-1;i += 2) + { + coeffs = _mm_load_ps(&Coeffs[i+1][0]); + vals = _mm_load_ps(&Values[i][0]); + imp1 = _mm_mul_ps(lrlr, coeffs); + imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2)); + vals = _mm_add_ps(imp0, vals); + _mm_store_ps(&Values[i][0], vals); + imp0 = imp1; + } + vals = _mm_loadl_pi(vals, reinterpret_cast<__m64*>(&Values[i][0])); + imp0 = _mm_movehl_ps(imp0, imp0); + vals = _mm_add_ps(imp0, vals); + _mm_storel_pi(reinterpret_cast<__m64*>(&Values[i][0]), vals); + } + else + { + for(ALuint i{0};i < IrSize;i += 2) + { + __m128 coeffs{_mm_load_ps(&Coeffs[i][0])}; + __m128 vals{_mm_load_ps(&Values[i][0])}; + vals = _mm_add_ps(vals, _mm_mul_ps(lrlr, coeffs)); + _mm_store_ps(&Values[i][0], vals); + } + } +} + +} // namespace + template<> const ALfloat *Resample_(const InterpState *state, const ALfloat *RESTRICT src, ALuint frac, ALuint increment, const al::span dst) @@ -114,49 +164,6 @@ const ALfloat *Resample_(const InterpState *state, } -static inline void ApplyCoeffs(size_t Offset, float2 *RESTRICT Values, const ALuint IrSize, - const HrirArray &Coeffs, const float left, const float right) -{ - const __m128 lrlr{_mm_setr_ps(left, right, left, right)}; - - ASSUME(IrSize >= 4); - - if((Offset&1)) - { - __m128 imp0, imp1; - __m128 coeffs{_mm_load_ps(&Coeffs[0][0])}; - __m128 vals{_mm_loadl_pi(_mm_setzero_ps(), reinterpret_cast<__m64*>(&Values[0][0]))}; - imp0 = _mm_mul_ps(lrlr, coeffs); - vals = _mm_add_ps(imp0, vals); - _mm_storel_pi(reinterpret_cast<__m64*>(&Values[0][0]), vals); - ALuint i{1}; - for(;i < IrSize-1;i += 2) - { - coeffs = _mm_load_ps(&Coeffs[i+1][0]); - vals = _mm_load_ps(&Values[i][0]); - imp1 = _mm_mul_ps(lrlr, coeffs); - imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2)); - vals = _mm_add_ps(imp0, vals); - _mm_store_ps(&Values[i][0], vals); - imp0 = imp1; - } - vals = _mm_loadl_pi(vals, reinterpret_cast<__m64*>(&Values[i][0])); - imp0 = _mm_movehl_ps(imp0, imp0); - vals = _mm_add_ps(imp0, vals); - _mm_storel_pi(reinterpret_cast<__m64*>(&Values[i][0]), vals); - } - else - { - for(ALuint i{0};i < IrSize;i += 2) - { - __m128 coeffs{_mm_load_ps(&Coeffs[i][0])}; - __m128 vals{_mm_load_ps(&Values[i][0])}; - vals = _mm_add_ps(vals, _mm_mul_ps(lrlr, coeffs)); - _mm_store_ps(&Values[i][0], vals); - } - } -} - template<> void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, -- cgit v1.2.3 From 1bb93f4fc213e4a93aedd4937ef2a8fa0d160b25 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 3 Oct 2019 04:22:39 -0700 Subject: Avoid direct function template and alias types It's somewhat ambiguous what they mean. Sometimes acting as a pointer, other times having weird behavior. Pointer-to-function types are explicitly defined as such, whereas uses of these tend to be as references (never null and not changeable). --- alc/effects/modulator.cpp | 29 +++++++++++------------------ alc/effects/vmorpher.cpp | 29 +++++++++++------------------ alc/mixer/mixer_c.cpp | 4 ++-- 3 files changed, 24 insertions(+), 38 deletions(-) diff --git a/alc/effects/modulator.cpp b/alc/effects/modulator.cpp index 8042378a..23bae63f 100644 --- a/alc/effects/modulator.cpp +++ b/alc/effects/modulator.cpp @@ -42,29 +42,22 @@ namespace { #define WAVEFORM_FRACONE (1<(index) * - (al::MathDefs::Tau() / ALfloat{WAVEFORM_FRACONE})); + constexpr float scale{al::MathDefs::Tau() / WAVEFORM_FRACONE}; + return std::sin(static_cast(index) * scale); } -inline ALfloat Saw(ALuint index) -{ - return static_cast(index)*(2.0f/WAVEFORM_FRACONE) - 1.0f; -} +inline float Saw(ALuint index) +{ return static_cast(index)*(2.0f/WAVEFORM_FRACONE) - 1.0f; } -inline ALfloat Square(ALuint index) -{ - return static_cast(((index>>(WAVEFORM_FRACBITS-2))&2) - 1); -} +inline float Square(ALuint index) +{ return static_cast(((index>>(WAVEFORM_FRACBITS-2))&2) - 1); } -inline ALfloat One(ALuint) -{ - return 1.0f; -} +inline float One(ALuint) { return 1.0f; } -template -void Modulate(ALfloat *RESTRICT dst, ALuint index, const ALuint step, size_t todo) +template +void Modulate(float *RESTRICT dst, ALuint index, const ALuint step, size_t todo) { for(size_t i{0u};i < todo;i++) { @@ -76,7 +69,7 @@ void Modulate(ALfloat *RESTRICT dst, ALuint index, const ALuint step, size_t tod struct ModulatorState final : public EffectState { - void (*mGetSamples)(ALfloat*RESTRICT, ALuint, const ALuint, size_t){}; + void (*mGetSamples)(float*RESTRICT, ALuint, const ALuint, size_t){}; ALuint mIndex{0}; ALuint mStep{1}; diff --git a/alc/effects/vmorpher.cpp b/alc/effects/vmorpher.cpp index d24d41d6..b1b7cc06 100644 --- a/alc/effects/vmorpher.cpp +++ b/alc/effects/vmorpher.cpp @@ -44,29 +44,22 @@ namespace { #define WAVEFORM_FRACONE (1<::Tau() / ALfloat{WAVEFORM_FRACONE}}; - return std::sin(static_cast(index) * scale)*0.5f + 0.5f; + constexpr float scale{al::MathDefs::Tau() / WAVEFORM_FRACONE}; + return std::sin(static_cast(index) * scale)*0.5f + 0.5f; } -inline ALfloat Saw(ALuint index) -{ - return static_cast(index) / ALfloat{WAVEFORM_FRACONE}; -} +inline float Saw(ALuint index) +{ return static_cast(index) / float{WAVEFORM_FRACONE}; } -inline ALfloat Triangle(ALuint index) -{ - return std::fabs(static_cast(index)*(2.0f/WAVEFORM_FRACONE) - 1.0f); -} +inline float Triangle(ALuint index) +{ return std::fabs(static_cast(index)*(2.0f/WAVEFORM_FRACONE) - 1.0f); } -inline ALfloat Half(ALuint) -{ - return 0.5f; -} +inline float Half(ALuint) { return 0.5f; } -template -void Oscillate(ALfloat *RESTRICT dst, ALuint index, const ALuint step, size_t todo) +template +void Oscillate(float *RESTRICT dst, ALuint index, const ALuint step, size_t todo) { for(size_t i{0u};i < todo;i++) { @@ -133,7 +126,7 @@ struct VmorpherState final : public EffectState { ALfloat TargetGains[MAX_OUTPUT_CHANNELS]{}; } mChans[MAX_AMBI_CHANNELS]; - void (*mGetSamples)(ALfloat* RESTRICT, ALuint, const ALuint, size_t){}; + void (*mGetSamples)(float*RESTRICT, ALuint, const ALuint, size_t){}; ALuint mIndex{0}; ALuint mStep{1}; diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index ffc07acd..8d375de7 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -62,8 +62,8 @@ inline float do_fastbsinc(const InterpState &istate, const float *RESTRICT vals, return r; } -using SamplerT = float(const InterpState&, const float*RESTRICT, const ALuint); -template +using SamplerT = float(&)(const InterpState&, const float*RESTRICT, const ALuint); +template const float *DoResample(const InterpState *state, const float *RESTRICT src, ALuint frac, ALuint increment, const al::span dst) { -- cgit v1.2.3 From 267b79f337f2189542ce2582aeed84b84c6e987e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Oct 2019 16:11:38 -0700 Subject: Avoid duplicate structs --- alc/alc.cpp | 2 +- alc/voice.cpp | 4 ++-- alc/voice.h | 11 +++-------- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index 03ed35cc..792ead3e 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -2193,7 +2193,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) std::fill(std::begin(voice.mProps.Send)+num_sends, std::end(voice.mProps.Send), ALvoiceProps::SendData{}); - std::fill(voice.mSend.begin()+num_sends, voice.mSend.end(), ALvoice::SendData{}); + std::fill(voice.mSend.begin()+num_sends, voice.mSend.end(), ALvoice::TargetData{}); auto clear_chan_sends = [num_sends](ALvoice::ChannelData &chandata) -> void { std::fill(chandata.mWetParams.begin()+num_sends, chandata.mWetParams.end(), diff --git a/alc/voice.cpp b/alc/voice.cpp index 59360e4e..02378fc6 100644 --- a/alc/voice.cpp +++ b/alc/voice.cpp @@ -423,7 +423,7 @@ ALfloat *LoadBufferQueue(ALbufferlistitem *BufferListItem, ALbufferlistitem *Buf } -void DoHrtfMix(ALvoice::DirectData &Direct, const float TargetGain, DirectParams &parms, +void DoHrtfMix(ALvoice::TargetData &Direct, const float TargetGain, DirectParams &parms, const float *samples, const ALuint DstBufferSize, const ALuint Counter, const ALuint OutPos, const ALuint IrSize, ALCdevice *Device) { @@ -519,7 +519,7 @@ void DoHrtfMix(ALvoice::DirectData &Direct, const float TargetGain, DirectParams parms.Hrtf.State.Values.begin()); } -void DoNfcMix(ALvoice::DirectData &Direct, const float *TargetGains, DirectParams &parms, +void DoNfcMix(ALvoice::TargetData &Direct, const float *TargetGains, DirectParams &parms, const float *samples, const ALuint DstBufferSize, const ALuint Counter, const ALuint OutPos, ALCdevice *Device) { diff --git a/alc/voice.h b/alc/voice.h index a2a3309c..0d5d9ca4 100644 --- a/alc/voice.h +++ b/alc/voice.h @@ -222,17 +222,12 @@ struct ALvoice { ALuint mFlags; - struct DirectData { + struct TargetData { int FilterType; al::span Buffer; }; - DirectData mDirect; - - struct SendData { - int FilterType; - al::span Buffer; - }; - std::array mSend; + TargetData mDirect; + std::array mSend; struct ChannelData { alignas(16) std::array mPrevSamples; -- cgit v1.2.3 From eb89faf9632048568c953c21a6b58e4c4664cc05 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Oct 2019 20:00:22 -0700 Subject: Use a span instead of a reference-to-array --- alc/alu.h | 19 +++++++++++-------- alc/panning.cpp | 25 +++++++++++++------------ 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/alc/alu.h b/alc/alu.h index f4d1e6b2..b3cfd840 100644 --- a/alc/alu.h +++ b/alc/alu.h @@ -93,8 +93,8 @@ void aluInitEffectPanning(ALeffectslot *slot, ALCdevice *device); * The components are ordered such that OpenAL's X, Y, and Z are the first, * second, and third parameters respectively -- simply negate X and Z. */ -void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread, - ALfloat (&coeffs)[MAX_AMBI_CHANNELS]); +void CalcAmbiCoeffs(const float y, const float z, const float x, const float spread, + const al::span coeffs); /** * CalcDirectionCoeffs @@ -103,7 +103,8 @@ void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALf * vector must be normalized (unit length), and the spread is the angular width * of the sound (0...tau). */ -inline void CalcDirectionCoeffs(const ALfloat (&dir)[3], ALfloat spread, ALfloat (&coeffs)[MAX_AMBI_CHANNELS]) +inline void CalcDirectionCoeffs(const float (&dir)[3], const float spread, + const al::span coeffs) { /* Convert from OpenAL coords to Ambisonics. */ CalcAmbiCoeffs(-dir[0], dir[1], -dir[2], spread, coeffs); @@ -116,11 +117,12 @@ inline void CalcDirectionCoeffs(const ALfloat (&dir)[3], ALfloat spread, ALfloat * azimuth and elevation parameters are in radians, going right and up * respectively. */ -inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat (&coeffs)[MAX_AMBI_CHANNELS]) +inline void CalcAngleCoeffs(const float azimuth, const float elevation, const float spread, + const al::span coeffs) { - ALfloat x = -std::sin(azimuth) * std::cos(elevation); - ALfloat y = std::sin(elevation); - ALfloat z = std::cos(azimuth) * std::cos(elevation); + const float x{-std::sin(azimuth) * std::cos(elevation)}; + const float y{ std::sin(elevation)}; + const float z{ std::cos(azimuth) * std::cos(elevation)}; CalcAmbiCoeffs(x, y, z, spread, coeffs); } @@ -134,7 +136,8 @@ inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, * coeffs are a 'slice' of a transform matrix for the input channel, used to * scale and orient the sound samples. */ -void ComputePanGains(const MixParams *mix, const ALfloat*RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]); +void ComputePanGains(const MixParams *mix, const float*RESTRICT coeffs, const float ingain, + const al::span gains); inline std::array GetAmbiIdentityRow(size_t i) noexcept diff --git a/alc/panning.cpp b/alc/panning.cpp index c2bcf223..df0b870a 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -874,8 +874,8 @@ void aluInitEffectPanning(ALeffectslot *slot, ALCdevice *device) } -void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread, - ALfloat (&coeffs)[MAX_AMBI_CHANNELS]) +void CalcAmbiCoeffs(const float y, const float z, const float x, const float spread, + const al::span coeffs) { /* Zeroth-order */ coeffs[0] = 1.0f; /* ACN 0 = 1 */ @@ -934,14 +934,14 @@ void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALf * ZH4 = 0.125f * (ca+1.0f)*(7.0f*ca*ca - 3.0f)*ca; * ZH5 = 0.0625f * (ca+1.0f)*(21.0f*ca*ca*ca*ca - 14.0f*ca*ca + 1.0f); */ - ALfloat ca = std::cos(spread * 0.5f); + const float ca{std::cos(spread * 0.5f)}; /* Increase the source volume by up to +3dB for a full spread. */ - ALfloat scale = std::sqrt(1.0f + spread/al::MathDefs::Tau()); + const float scale{std::sqrt(1.0f + spread/al::MathDefs::Tau())}; - ALfloat ZH0_norm = scale; - ALfloat ZH1_norm = 0.5f * (ca+1.f) * scale; - ALfloat ZH2_norm = 0.5f * (ca+1.f)*ca * scale; - ALfloat ZH3_norm = 0.125f * (ca+1.f)*(5.f*ca*ca-1.f) * scale; + const float ZH0_norm{scale}; + const float ZH1_norm{scale * 0.5f * (ca+1.f)}; + const float ZH2_norm{scale * 0.5f * (ca+1.f)*ca}; + const float ZH3_norm{scale * 0.125f * (ca+1.f)*(5.f*ca*ca-1.f)}; /* Zeroth-order */ coeffs[0] *= ZH0_norm; @@ -966,13 +966,14 @@ void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALf } } -void ComputePanGains(const MixParams *mix, const ALfloat *RESTRICT coeffs, ALfloat ingain, ALfloat (&gains)[MAX_OUTPUT_CHANNELS]) +void ComputePanGains(const MixParams *mix, const float*RESTRICT coeffs, const float ingain, + const al::span gains) { auto ambimap = mix->AmbiMap.cbegin(); - auto iter = std::transform(ambimap, ambimap+mix->Buffer.size(), std::begin(gains), - [coeffs,ingain](const BFChannelConfig &chanmap) noexcept -> ALfloat + auto iter = std::transform(ambimap, ambimap+mix->Buffer.size(), gains.begin(), + [coeffs,ingain](const BFChannelConfig &chanmap) noexcept -> float { return chanmap.Scale * coeffs[chanmap.Index] * ingain; } ); - std::fill(iter, std::end(gains), 0.0f); + std::fill(iter, gains.end(), 0.0f); } -- cgit v1.2.3 From acb6baad906912aa7e744552905afcdcec521c14 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Oct 2019 21:23:31 -0700 Subject: Use std::array instead of plain arrays in a couple places --- alc/alu.cpp | 9 ++------- alc/voice.cpp | 32 +++++++++++++++----------------- alc/voice.h | 10 ++++++---- 3 files changed, 23 insertions(+), 28 deletions(-) diff --git a/alc/alu.cpp b/alc/alu.cpp index 6d3e5549..8c2ee164 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -132,11 +132,6 @@ struct ChanMap { ALfloat elevation; }; -void ClearArray(ALfloat (&f)[MAX_OUTPUT_CHANNELS]) -{ - std::fill(std::begin(f), std::end(f), 0.0f); -} - HrtfDirectMixerFunc MixDirectHrtf = MixDirectHrtf_; inline MixerFunc SelectMixer() @@ -633,9 +628,9 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo [NumSends](ALvoice::ChannelData &chandata) -> void { chandata.mDryParams.Hrtf.Target = HrtfFilter{}; - ClearArray(chandata.mDryParams.Gains.Target); + chandata.mDryParams.Gains.Target.fill(0.0f); std::for_each(chandata.mWetParams.begin(), chandata.mWetParams.begin()+NumSends, - [](SendParams ¶ms) -> void { ClearArray(params.Gains.Target); }); + [](SendParams ¶ms) -> void { params.Gains.Target.fill(0.0f); }); }); voice->mFlags &= ~(VOICE_HAS_HRTF | VOICE_HAS_NFC); diff --git a/alc/voice.cpp b/alc/voice.cpp index 02378fc6..7eb791d5 100644 --- a/alc/voice.cpp +++ b/alc/voice.cpp @@ -525,7 +525,7 @@ void DoNfcMix(ALvoice::TargetData &Direct, const float *TargetGains, DirectParam { const size_t outcount{Device->NumChannelsPerOrder[0]}; MixSamples({samples, DstBufferSize}, Direct.Buffer.first(outcount), - parms.Gains.Current, TargetGains, Counter, OutPos); + parms.Gains.Current.data(), TargetGains, Counter, OutPos); const al::span nfcsamples{Device->NfcSampleData, DstBufferSize}; size_t chanoffset{outcount}; @@ -536,7 +536,7 @@ void DoNfcMix(ALvoice::TargetData &Direct, const float *TargetGains, DirectParam if(chancount < 1) return; (parms.NFCtrlFilter.*process)(nfcsamples.data(), samples, nfcsamples.size()); MixSamples(nfcsamples, Direct.Buffer.subspan(chanoffset, chancount), - parms.Gains.Current+chanoffset, TargetGains+chanoffset, Counter, OutPos); + &parms.Gains.Current[chanoffset], &TargetGains[chanoffset], Counter, OutPos); chanoffset += chancount; }; apply_nfc(&NfcFilter::process1, Device->NumChannelsPerOrder[1]); @@ -548,7 +548,7 @@ void DoNfcMix(ALvoice::TargetData &Direct, const float *TargetGains, DirectParam void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) { - static constexpr ALfloat SilentTarget[MAX_OUTPUT_CHANNELS]{}; + static constexpr std::array SilentTarget{}; ASSUME(SamplesToDo > 0); @@ -584,8 +584,7 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) { DirectParams &parms = chandata.mDryParams; if(!(mFlags&VOICE_HAS_HRTF)) - std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target), - std::begin(parms.Gains.Current)); + parms.Gains.Current = parms.Gains.Target; else parms.Hrtf.Old = parms.Hrtf.Target; } @@ -595,8 +594,7 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) continue; SendParams &parms = chandata.mWetParams[send]; - std::copy(std::begin(parms.Gains.Target), std::end(parms.Gains.Target), - std::begin(parms.Gains.Current)); + parms.Gains.Current = parms.Gains.Target; } } } @@ -720,17 +718,17 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) } else if((mFlags&VOICE_HAS_NFC)) { - const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? - SilentTarget : parms.Gains.Target}; + const float *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? + SilentTarget.data() : parms.Gains.Target.data()}; DoNfcMix(mDirect, TargetGains, parms, samples, DstBufferSize, Counter, OutPos, Device); } else { - const ALfloat *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? - SilentTarget : parms.Gains.Target}; - MixSamples({samples, DstBufferSize}, mDirect.Buffer, parms.Gains.Current, - TargetGains, Counter, OutPos); + const float *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? + SilentTarget.data() : parms.Gains.Target.data()}; + MixSamples({samples, DstBufferSize}, mDirect.Buffer, + parms.Gains.Current.data(), TargetGains, Counter, OutPos); } } @@ -743,10 +741,10 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) const ALfloat *samples{DoFilters(&parms.LowPass, &parms.HighPass, FilterBuf, ResampledData, DstBufferSize, mSend[send].FilterType)}; - const ALfloat *TargetGains{UNLIKELY(vstate==ALvoice::Stopping) ? SilentTarget : - parms.Gains.Target}; - MixSamples({samples, DstBufferSize}, mSend[send].Buffer, parms.Gains.Current, - TargetGains, Counter, OutPos); + const float *TargetGains{UNLIKELY(vstate == ALvoice::Stopping) ? + SilentTarget.data() : parms.Gains.Target.data()}; + MixSamples({samples, DstBufferSize}, mSend[send].Buffer, + parms.Gains.Current.data(), TargetGains, Counter, OutPos); } } /* Update positions */ diff --git a/alc/voice.h b/alc/voice.h index 0d5d9ca4..206e2e6b 100644 --- a/alc/voice.h +++ b/alc/voice.h @@ -1,6 +1,8 @@ #ifndef VOICE_H #define VOICE_H +#include + #include "AL/al.h" #include "AL/alext.h" @@ -96,8 +98,8 @@ struct DirectParams { } Hrtf; struct { - float Current[MAX_OUTPUT_CHANNELS]; - float Target[MAX_OUTPUT_CHANNELS]; + std::array Current; + std::array Target; } Gains; }; @@ -106,8 +108,8 @@ struct SendParams { BiquadFilter HighPass; struct { - float Current[MAX_OUTPUT_CHANNELS]; - float Target[MAX_OUTPUT_CHANNELS]; + std::array Current; + std::array Target; } Gains; }; -- cgit v1.2.3 From f52eed060718d5af3fe625bc4b8865eaecf56aab Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Oct 2019 05:01:05 -0700 Subject: Update some wording in the changelog --- ChangeLog | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index edef4331..0582a5fc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -30,18 +30,18 @@ openal-soft-1.20.0: Improved the quality of the bsinc resamplers slightly. - Improved the efficiency of the HRTF mixers. + Improved the efficiency of the HRTF filters. Improved the HRTF B-Format decoder coefficient generation. - Improved reverb fading to be more consistent with pan fading. + Improved reverb feedback fading to be more consistent with pan fading. - Improved handling of sources that end prematurely, to avoid loud clicks. + Improved handling of sources that end prematurely, avoiding loud clicks. Improved the performance of some reverb processing loops. - Added fast_bsinc resamplers that improve efficiency at the cost of some - quality. Notably, when down-sampling with pitch ramping. + Added fast_bsinc12 and 24 resamplers that improve efficiency at the cost of + some quality. Notably, down-sampling has less smooth pitch ramping. Added support for SOFA input files with makemhr. -- cgit v1.2.3 From f8ff4e269bf04aae1c430dbb218b4f4f6605df45 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Oct 2019 15:17:45 -0700 Subject: Put the pragma defines in a separate header --- CMakeLists.txt | 1 + alc/alc.cpp | 3 ++- common/almalloc.h | 23 ++++------------------- common/pragmadefs.h | 21 +++++++++++++++++++++ 4 files changed, 28 insertions(+), 20 deletions(-) create mode 100644 common/pragmadefs.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 03c60162..9cc0c6fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -551,6 +551,7 @@ SET(COMMON_OBJS common/intrusive_ptr.h common/math_defs.h common/opthelpers.h + common/pragmadefs.h common/strutils.cpp common/strutils.h common/threads.cpp diff --git a/alc/alc.cpp b/alc/alc.cpp index 792ead3e..119067fd 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -86,6 +86,7 @@ #include "logging.h" #include "mastering.h" #include "opthelpers.h" +#include "pragmadefs.h" #include "ringbuffer.h" #include "strutils.h" #include "threads.h" @@ -915,7 +916,7 @@ constexpr ALCint alcEFXMinorVersion = 0; * zero objects here, so silence that. */ DIAGNOSTIC_PUSH -MVSDIAGNOSTIC(warning(disable : 4815)) +msc_pragma(warning(disable : 4815)) al::FlexArray EmptyContextArray{0u}; DIAGNOSTIC_POP diff --git a/common/almalloc.h b/common/almalloc.h index b844e5fc..15ec600d 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -10,23 +10,8 @@ #include #include +#include "pragmadefs.h" -#ifdef _MSC_VER -#define DIAGNOSTIC_PUSH __pragma(warning(push)) -#define GNUDIAGNOSTIC(x) -#define MVSDIAGNOSTIC(...) __pragma(__VA_ARGS__) -#define DIAGNOSTIC_POP __pragma(warning(pop)) -#elif defined(__GNUC__) || defined(__clang__) -#define DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") -#define GNUDIAGNOSTIC(x) _Pragma(x) -#define MVSDIAGNOSTIC(...) -#define DIAGNOSTIC_POP _Pragma("GCC diagnostic push") -#else -#define DIAGNOSTIC_PUSH -#define GNUDIAGNOSTIC(x) -#define MVSDIAGNOSTIC(...) -#define DIAGNOSTIC_POP -#endif void *al_malloc(size_t alignment, size_t size); void *al_calloc(size_t alignment, size_t size); @@ -119,7 +104,7 @@ inline T* assume_aligned(T *ptr) noexcept * destructor is trivial (a no-op). So disable that warning for this call. */ DIAGNOSTIC_PUSH -MVSDIAGNOSTIC(warning(disable : 4100)) +msc_pragma(warning(disable : 4100)) template inline void destroy_at(T *ptr) { ptr->~T(); } DIAGNOSTIC_POP @@ -263,8 +248,8 @@ struct FlexArray { const index_type mSize; DIAGNOSTIC_PUSH -GNUDIAGNOSTIC("GCC diagnostic ignored \"-Wpedantic\"") -MVSDIAGNOSTIC(warning(disable : 4200)) +std_pragma("GCC diagnostic ignored \"-Wpedantic\"") +msc_pragma(warning(disable : 4200)) alignas(alignment) element_type mArray[0]; DIAGNOSTIC_POP diff --git a/common/pragmadefs.h b/common/pragmadefs.h new file mode 100644 index 00000000..1d0af066 --- /dev/null +++ b/common/pragmadefs.h @@ -0,0 +1,21 @@ +#ifndef PRAGMADEFS_H +#define PRAGMADEFS_H + +#if defined(_MSC_VER) +#define DIAGNOSTIC_PUSH __pragma(warning(push)) +#define DIAGNOSTIC_POP __pragma(warning(pop)) +#define std_pragma(...) +#define msc_pragma __pragma +#else +#if defined(__GNUC__) || defined(__clang__) +#define DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") +#define DIAGNOSTIC_POP _Pragma("GCC diagnostic push") +#else +#define DIAGNOSTIC_PUSH +#define DIAGNOSTIC_POP +#endif +#define std_pragma _Pragma +#define msc_pragma(...) +#endif + +#endif /* PRAGMADEFS_H */ -- cgit v1.2.3 From 02d80cd74dd7b4517550af2f4ea22c409323a1d9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Oct 2019 21:37:56 -0700 Subject: Use exceptions for backend open failures --- alc/alc.cpp | 32 +++------ alc/backends/alsa.cpp | 35 ++++------ alc/backends/base.cpp | 3 +- alc/backends/base.h | 2 +- alc/backends/coreaudio.cpp | 165 ++++++++++++++++++++++---------------------- alc/backends/dsound.cpp | 122 ++++++++++++++------------------ alc/backends/jack.cpp | 23 +++--- alc/backends/loopback.cpp | 5 +- alc/backends/null.cpp | 9 ++- alc/backends/opensl.cpp | 120 ++++++++++++++++---------------- alc/backends/oss.cpp | 70 +++++++++---------- alc/backends/portaudio.cpp | 129 ++++++++++++++++------------------ alc/backends/pulseaudio.cpp | 96 ++++++++++++-------------- alc/backends/qsa.cpp | 25 +++++-- alc/backends/sdl2.cpp | 50 +++++++------- alc/backends/sndio.cpp | 85 ++++++++++++----------- alc/backends/solaris.cpp | 11 +-- alc/backends/wasapi.cpp | 25 ++++--- alc/backends/wave.cpp | 14 ++-- alc/backends/winmm.cpp | 67 +++++++++--------- 20 files changed, 524 insertions(+), 564 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index 119067fd..025395fe 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -3548,16 +3548,9 @@ START_API_FUNC device->NumAuxSends = DEFAULT_SENDS; try { - /* Create the device backend. */ - device->Backend = PlaybackFactory->createBackend(device.get(), BackendType::Playback); - - /* Find a playback device to open */ - ALCenum err{device->Backend->open(deviceName)}; - if(err != ALC_NO_ERROR) - { - alcSetError(nullptr, err); - return nullptr; - } + auto backend = PlaybackFactory->createBackend(device.get(), BackendType::Playback); + backend->open(deviceName); + device->Backend = std::move(backend); } catch(al::backend_exception &e) { WARN("Failed to open playback device: %s\n", e.what()); @@ -3811,17 +3804,13 @@ START_API_FUNC device->BufferSize = static_cast(samples); try { - device->Backend = CaptureFactory->createBackend(device.get(), BackendType::Capture); - TRACE("Capture format: %s, %s, %uhz, %u / %u buffer\n", DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), device->Frequency, device->UpdateSize, device->BufferSize); - ALCenum err{device->Backend->open(deviceName)}; - if(err != ALC_NO_ERROR) - { - alcSetError(nullptr, err); - return nullptr; - } + + auto backend = CaptureFactory->createBackend(device.get(), BackendType::Capture); + backend->open(deviceName); + device->Backend = std::move(backend); } catch(al::backend_exception &e) { WARN("Failed to open capture device: %s\n", e.what()); @@ -4000,11 +3989,10 @@ START_API_FUNC device->NumMonoSources = device->SourcesMax - device->NumStereoSources; try { - device->Backend = LoopbackBackendFactory::getFactory().createBackend(device.get(), + auto backend = LoopbackBackendFactory::getFactory().createBackend(device.get(), BackendType::Playback); - - // Open the "backend" - device->Backend->open("Loopback"); + backend->open("Loopback"); + device->Backend = std::move(backend); } catch(al::backend_exception &e) { WARN("Failed to open loopback device: %s\n", e.what()); diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index da928171..2e157602 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -40,6 +40,7 @@ #include "albyte.h" #include "alcmain.h" #include "alconfig.h" +#include "alexcpt.h" #include "almalloc.h" #include "alnumeric.h" #include "aloptional.h" @@ -394,7 +395,7 @@ struct AlsaPlayback final : public BackendBase { int mixerProc(); int mixerNoMMapProc(); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool reset() override; bool start() override; void stop() override; @@ -592,7 +593,7 @@ int AlsaPlayback::mixerNoMMapProc() } -ALCenum AlsaPlayback::open(const ALCchar *name) +void AlsaPlayback::open(const ALCchar *name) { const char *driver{}; if(name) @@ -605,7 +606,7 @@ ALCenum AlsaPlayback::open(const ALCchar *name) { return entry.name == name; } ); if(iter == PlaybackDevices.cend()) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; driver = iter->device_name.c_str(); } else @@ -619,15 +620,14 @@ ALCenum AlsaPlayback::open(const ALCchar *name) if(err < 0) { ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(err)); - return ALC_OUT_OF_MEMORY; + throw al::backend_exception{ALC_OUT_OF_MEMORY, "Could not open ALSA playback \"%s\"", + driver}; } /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */ snd_config_update_free_global(); mDevice->DeviceName = name; - - return ALC_NO_ERROR; } bool AlsaPlayback::reset() @@ -868,7 +868,7 @@ struct AlsaCapture final : public BackendBase { AlsaCapture(ALCdevice *device) noexcept : BackendBase{device} { } ~AlsaCapture() override; - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool start() override; void stop() override; ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; @@ -895,7 +895,7 @@ AlsaCapture::~AlsaCapture() } -ALCenum AlsaCapture::open(const ALCchar *name) +void AlsaCapture::open(const ALCchar *name) { const char *driver{}; if(name) @@ -908,7 +908,7 @@ ALCenum AlsaCapture::open(const ALCchar *name) { return entry.name == name; } ); if(iter == CaptureDevices.cend()) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; driver = iter->device_name.c_str(); } else @@ -922,7 +922,8 @@ ALCenum AlsaCapture::open(const ALCchar *name) if(err < 0) { ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err)); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_OUT_OF_MEMORY, "Could not open ALSA capture \"%s\"", + driver}; } /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */ @@ -994,24 +995,16 @@ ALCenum AlsaCapture::open(const ALCchar *name) if(!mRing) { ERR("ring buffer create failed\n"); - goto error2; + throw al::backend_exception{ALC_INVALID_VALUE, "Failed to create ring buffer"}; } } mDevice->DeviceName = name; - - return ALC_NO_ERROR; + return; error: - ERR("%s failed: %s\n", funcerr, snd_strerror(err)); if(hp) snd_pcm_hw_params_free(hp); - -error2: - mRing = nullptr; - snd_pcm_close(mPcmHandle); - mPcmHandle = nullptr; - - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "%s failed: %s", funcerr, snd_strerror(err)}; } diff --git a/alc/backends/base.cpp b/alc/backends/base.cpp index a5f66606..4fce0a67 100644 --- a/alc/backends/base.cpp +++ b/alc/backends/base.cpp @@ -9,6 +9,7 @@ #include "AL/al.h" #include "alcmain.h" +#include "alexcpt.h" #include "alnumeric.h" #include "atomic.h" @@ -29,7 +30,7 @@ BackendBase::BackendBase(ALCdevice *device) noexcept : mDevice{device} BackendBase::~BackendBase() = default; bool BackendBase::reset() -{ return false; } +{ throw al::backend_exception{ALC_INVALID_VALUE, "Invalid BackendVase call"}; } ALCenum BackendBase::captureSamples(al::byte*, ALCuint) { return ALC_INVALID_DEVICE; } diff --git a/alc/backends/base.h b/alc/backends/base.h index 55240fd2..d4856818 100644 --- a/alc/backends/base.h +++ b/alc/backends/base.h @@ -32,7 +32,7 @@ inline std::chrono::nanoseconds GetDeviceClockTime(ALCdevice *device) ClockLatency GetClockLatency(ALCdevice *device); struct BackendBase { - virtual ALCenum open(const ALCchar *name) = 0; + virtual void open(const ALCchar *name) = 0; virtual bool reset(); virtual bool start() = 0; diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 5d004efc..9254dbe0 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -27,6 +27,7 @@ #include #include "alcmain.h" +#include "alexcpt.h" #include "alu.h" #include "ringbuffer.h" #include "converter.h" @@ -48,17 +49,21 @@ struct CoreAudioPlayback final : public BackendBase { static OSStatus MixerProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, - AudioBufferList *ioData); + AudioBufferList *ioData) + { + return static_cast(inRefCon)->MixerProc(ioActionFlags, inTimeStamp, + inBusNumber, inNumberFrames, ioData); + } OSStatus MixerProc(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool reset() override; bool start() override; void stop() override; - AudioUnit mAudioUnit; + AudioUnit mAudioUnit{}; ALuint mFrameSize{0u}; AudioStreamBasicDescription mFormat{}; // This is the OpenAL format as a CoreAudio ASBD @@ -73,14 +78,6 @@ CoreAudioPlayback::~CoreAudioPlayback() } -OSStatus CoreAudioPlayback::MixerProcC(void *inRefCon, - AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) -{ - return static_cast(inRefCon)->MixerProc(ioActionFlags, inTimeStamp, - inBusNumber, inNumberFrames, ioData); -} - OSStatus CoreAudioPlayback::MixerProc(AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32, UInt32, AudioBufferList *ioData) { @@ -91,12 +88,12 @@ OSStatus CoreAudioPlayback::MixerProc(AudioUnitRenderActionFlags*, } -ALCenum CoreAudioPlayback::open(const ALCchar *name) +void CoreAudioPlayback::open(const ALCchar *name) { if(!name) name = ca_device; else if(strcmp(name, ca_device) != 0) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; /* open the default output unit */ AudioComponentDescription desc{}; @@ -114,14 +111,15 @@ ALCenum CoreAudioPlayback::open(const ALCchar *name) if(comp == nullptr) { ERR("AudioComponentFindNext failed\n"); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Could not find audio component"}; } OSStatus err{AudioComponentInstanceNew(comp, &mAudioUnit)}; if(err != noErr) { ERR("AudioComponentInstanceNew failed\n"); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Could not create component instance: %u", + err}; } /* init and start the default audio unit... */ @@ -129,12 +127,10 @@ ALCenum CoreAudioPlayback::open(const ALCchar *name) if(err != noErr) { ERR("AudioUnitInitialize failed\n"); - AudioComponentInstanceDispose(mAudioUnit); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Could not initialize audio unit: %u", err}; } mDevice->DeviceName = name; - return ALC_NO_ERROR; } bool CoreAudioPlayback::reset() @@ -307,12 +303,16 @@ struct CoreAudioCapture final : public BackendBase { static OSStatus RecordProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, - AudioBufferList *ioData); + AudioBufferList *ioData) + { + return static_cast(inRefCon)->RecordProc(ioActionFlags, inTimeStamp, + inBusNumber, inNumberFrames, ioData); + } OSStatus RecordProc(AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool start() override; void stop() override; ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; @@ -338,23 +338,15 @@ CoreAudioCapture::~CoreAudioCapture() } -OSStatus CoreAudioCapture::RecordProcC(void *inRefCon, - AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) -{ - return static_cast(inRefCon)->RecordProc(ioActionFlags, inTimeStamp, - inBusNumber, inNumberFrames, ioData); -} - OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags*, const AudioTimeStamp *inTimeStamp, UInt32, UInt32 inNumberFrames, AudioBufferList*) { AudioUnitRenderActionFlags flags = 0; union { - ALbyte _[sizeof(AudioBufferList) + sizeof(AudioBuffer)*2]; + al::byte _[sizeof(AudioBufferList) + sizeof(AudioBuffer)*2]; AudioBufferList list; - } audiobuf = { { 0 } }; + } audiobuf{}; auto rec_vec = mRing->getWriteVector(); inNumberFrames = static_cast(minz(inNumberFrames, @@ -393,7 +385,7 @@ OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags*, } -ALCenum CoreAudioCapture::open(const ALCchar *name) +void CoreAudioCapture::open(const ALCchar *name) { AudioStreamBasicDescription requestedFormat; // The application requested format AudioStreamBasicDescription hardwareFormat; // The hardware format @@ -412,7 +404,7 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) if(!name) name = ca_device; else if(strcmp(name, ca_device) != 0) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; desc.componentType = kAudioUnitType_Output; #if TARGET_OS_IOS @@ -429,7 +421,7 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) if(comp == NULL) { ERR("AudioComponentFindNext failed\n"); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Could not finda udio component"}; } // Open the component @@ -437,7 +429,8 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) if(err != noErr) { ERR("AudioComponentInstanceNew failed\n"); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Could not create component instance: %u", + err}; } // Turn off AudioUnit output @@ -447,7 +440,8 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, + "Could not disable audio unit output property: %u", err}; } // Turn on AudioUnit input @@ -457,7 +451,8 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, + "Could not enable audio unit input property: %u", err}; } #if !TARGET_OS_IOS @@ -470,16 +465,17 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; propertyAddress.mElement = kAudioObjectPropertyElementMaster; - err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, &inputDevice); + err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, nullptr, + &propertySize, &inputDevice); if(err != noErr) { ERR("AudioObjectGetPropertyData failed\n"); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Could not get input device: %u", err}; } if(inputDevice == kAudioDeviceUnknown) { ERR("No input device found\n"); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Unknown input device"}; } // Track the input device @@ -488,7 +484,7 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Could not set input device: %u", err}; } } #endif @@ -502,7 +498,7 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Could not set capture callback: %u", err}; } // Initialize the device @@ -510,7 +506,7 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) if(err != noErr) { ERR("AudioUnitInitialize failed\n"); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Could not initialize audio unit: %u", err}; } // Get the hardware format @@ -520,52 +516,54 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription)) { ERR("AudioUnitGetProperty failed\n"); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Could not get input format: %u", err}; } // Set up the requested format description switch(mDevice->FmtType) { - case DevFmtUByte: - requestedFormat.mBitsPerChannel = 8; - requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked; - break; - case DevFmtShort: - requestedFormat.mBitsPerChannel = 16; - requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; - break; - case DevFmtInt: - requestedFormat.mBitsPerChannel = 32; - requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; - break; - case DevFmtFloat: - requestedFormat.mBitsPerChannel = 32; - requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked; - break; - case DevFmtByte: - case DevFmtUShort: - case DevFmtUInt: - ERR("%s samples not supported\n", DevFmtTypeString(mDevice->FmtType)); - return ALC_INVALID_VALUE; + case DevFmtUByte: + requestedFormat.mBitsPerChannel = 8; + requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked; + break; + case DevFmtShort: + requestedFormat.mBitsPerChannel = 16; + requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; + break; + case DevFmtInt: + requestedFormat.mBitsPerChannel = 32; + requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; + break; + case DevFmtFloat: + requestedFormat.mBitsPerChannel = 32; + requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked; + break; + case DevFmtByte: + case DevFmtUShort: + case DevFmtUInt: + ERR("%s samples not supported\n", DevFmtTypeString(mDevice->FmtType)); + throw al::backend_exception{ALC_INVALID_VALUE, "%s samples not suppoted", + DevFmtTypeString(mDevice->FmtType)}; } switch(mDevice->FmtChans) { - case DevFmtMono: - requestedFormat.mChannelsPerFrame = 1; - break; - case DevFmtStereo: - requestedFormat.mChannelsPerFrame = 2; - break; + case DevFmtMono: + requestedFormat.mChannelsPerFrame = 1; + break; + case DevFmtStereo: + requestedFormat.mChannelsPerFrame = 2; + break; - case DevFmtQuad: - case DevFmtX51: - case DevFmtX51Rear: - case DevFmtX61: - case DevFmtX71: - case DevFmtAmbi3D: - ERR("%s not supported\n", DevFmtChannelsString(mDevice->FmtChans)); - return ALC_INVALID_VALUE; + case DevFmtQuad: + case DevFmtX51: + case DevFmtX51Rear: + case DevFmtX61: + case DevFmtX71: + case DevFmtAmbi3D: + ERR("%s not supported\n", DevFmtChannelsString(mDevice->FmtChans)); + throw al::backend_exception{ALC_INVALID_VALUE, "%s not supported", + DevFmtChannelsString(mDevice->FmtChans)}; } requestedFormat.mBytesPerFrame = requestedFormat.mChannelsPerFrame * requestedFormat.mBitsPerChannel / 8; @@ -591,7 +589,7 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Could not set input format: %u", err}; } // Set the AudioUnit output format frame count @@ -602,7 +600,8 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) if(FrameCount64 > std::numeric_limits::max()/2) { ERR("FrameCount too large\n"); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, + "Calculated frame count is too lareg: %" PRIu64, FrameCount64}; } outputFrameCount = static_cast(FrameCount64); @@ -611,7 +610,8 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) if(err != noErr) { ERR("AudioUnitSetProperty failed: %d\n", err); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Failed to set capture frame count: %u", + err}; } // Set up sample converter if needed @@ -621,10 +621,9 @@ ALCenum CoreAudioCapture::open(const ALCchar *name) mDevice->Frequency, Resampler::FastBSinc24); mRing = CreateRingBuffer(outputFrameCount, mFrameSize, false); - if(!mRing) return ALC_INVALID_VALUE; + if(!mRing) throw al::backend_exception{ALC_INVALID_VALUE, "Failed to allocate ring buffer"}; mDevice->DeviceName = name; - return ALC_NO_ERROR; } diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index c7014e33..19a3c604 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -45,6 +45,7 @@ #include #include "alcmain.h" +#include "alexcpt.h" #include "alu.h" #include "ringbuffer.h" #include "compat.h" @@ -166,7 +167,7 @@ struct DSoundPlayback final : public BackendBase { int mixerProc(); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool reset() override; bool start() override; void stop() override; @@ -298,7 +299,7 @@ FORCE_ALIGN int DSoundPlayback::mixerProc() return 0; } -ALCenum DSoundPlayback::open(const ALCchar *name) +void DSoundPlayback::open(const ALCchar *name) { HRESULT hr; if(PlaybackDevices.empty()) @@ -325,7 +326,7 @@ ALCenum DSoundPlayback::open(const ALCchar *name) { return entry.name == name; } ); if(iter == PlaybackDevices.cend()) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; guid = &iter->guid; } @@ -341,11 +342,10 @@ ALCenum DSoundPlayback::open(const ALCchar *name) if(FAILED(hr)) { ERR("Device init failed: 0x%08lx\n", hr); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device init failed: 0x%08lx", hr}; } mDevice->DeviceName = name; - return ALC_NO_ERROR; } bool DSoundPlayback::reset() @@ -596,7 +596,7 @@ struct DSoundCapture final : public BackendBase { DSoundCapture(ALCdevice *device) noexcept : BackendBase{device} { } ~DSoundCapture() override; - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool start() override; void stop() override; ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; @@ -627,7 +627,7 @@ DSoundCapture::~DSoundCapture() } -ALCenum DSoundCapture::open(const ALCchar *name) +void DSoundCapture::open(const ALCchar *name) { HRESULT hr; if(CaptureDevices.empty()) @@ -654,79 +654,60 @@ ALCenum DSoundCapture::open(const ALCchar *name) { return entry.name == name; } ); if(iter == CaptureDevices.cend()) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; guid = &iter->guid; } switch(mDevice->FmtType) { - case DevFmtByte: - case DevFmtUShort: - case DevFmtUInt: - WARN("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); - return ALC_INVALID_ENUM; + case DevFmtByte: + case DevFmtUShort: + case DevFmtUInt: + WARN("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); + throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", + DevFmtTypeString(mDevice->FmtType)}; - case DevFmtUByte: - case DevFmtShort: - case DevFmtInt: - case DevFmtFloat: - break; + case DevFmtUByte: + case DevFmtShort: + case DevFmtInt: + case DevFmtFloat: + break; } WAVEFORMATEXTENSIBLE InputType{}; switch(mDevice->FmtChans) { - case DevFmtMono: - InputType.dwChannelMask = SPEAKER_FRONT_CENTER; - break; - case DevFmtStereo: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT; - break; - case DevFmtQuad: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_BACK_LEFT | - SPEAKER_BACK_RIGHT; - break; - case DevFmtX51: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_SIDE_LEFT | - SPEAKER_SIDE_RIGHT; - break; - case DevFmtX51Rear: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_BACK_LEFT | - SPEAKER_BACK_RIGHT; - break; - case DevFmtX61: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_BACK_CENTER | - SPEAKER_SIDE_LEFT | - SPEAKER_SIDE_RIGHT; - break; - case DevFmtX71: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_BACK_LEFT | - SPEAKER_BACK_RIGHT | - SPEAKER_SIDE_LEFT | - SPEAKER_SIDE_RIGHT; - break; - case DevFmtAmbi3D: - WARN("%s capture not supported\n", DevFmtChannelsString(mDevice->FmtChans)); - return ALC_INVALID_ENUM; + case DevFmtMono: + InputType.dwChannelMask = SPEAKER_FRONT_CENTER; + break; + case DevFmtStereo: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; + break; + case DevFmtQuad: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT; + break; + case DevFmtX51: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT; + break; + case DevFmtX51Rear: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; + break; + case DevFmtX61: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_CENTER | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT; + break; + case DevFmtX71: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + break; + case DevFmtAmbi3D: + WARN("%s capture not supported\n", DevFmtChannelsString(mDevice->FmtChans)); + throw al::backend_exception{ALC_INVALID_VALUE, "%s capture not supported", + DevFmtChannelsString(mDevice->FmtChans)}; } InputType.Format.wFormatTag = WAVE_FORMAT_PCM; @@ -781,14 +762,13 @@ ALCenum DSoundCapture::open(const ALCchar *name) mDSC->Release(); mDSC = nullptr; - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device init failed: 0x%08lx", hr}; } mBufferBytes = DSCBDescription.dwBufferBytes; SetDefaultWFXChannelOrder(mDevice); mDevice->DeviceName = name; - return ALC_NO_ERROR; } bool DSoundCapture::start() diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp index 660ea933..c7e2839c 100644 --- a/alc/backends/jack.cpp +++ b/alc/backends/jack.cpp @@ -32,6 +32,7 @@ #include "alcmain.h" #include "alu.h" #include "alconfig.h" +#include "alexcpt.h" #include "dynload.h" #include "ringbuffer.h" #include "threads.h" @@ -153,15 +154,17 @@ struct JackPlayback final : public BackendBase { JackPlayback(ALCdevice *device) noexcept : BackendBase{device} { } ~JackPlayback() override; - static int bufferSizeNotifyC(jack_nframes_t numframes, void *arg); + static int bufferSizeNotifyC(jack_nframes_t numframes, void *arg) + { return static_cast(arg)->bufferSizeNotify(numframes); } int bufferSizeNotify(jack_nframes_t numframes); - static int processC(jack_nframes_t numframes, void *arg); + static int processC(jack_nframes_t numframes, void *arg) + { return static_cast(arg)->process(numframes); } int process(jack_nframes_t numframes); int mixerProc(); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool reset() override; bool start() override; void stop() override; @@ -194,9 +197,6 @@ JackPlayback::~JackPlayback() } -int JackPlayback::bufferSizeNotifyC(jack_nframes_t numframes, void *arg) -{ return static_cast(arg)->bufferSizeNotify(numframes); } - int JackPlayback::bufferSizeNotify(jack_nframes_t numframes) { std::lock_guard _{mDevice->StateLock}; @@ -221,9 +221,6 @@ int JackPlayback::bufferSizeNotify(jack_nframes_t numframes) } -int JackPlayback::processC(jack_nframes_t numframes, void *arg) -{ return static_cast(arg)->process(numframes); } - int JackPlayback::process(jack_nframes_t numframes) { jack_default_audio_sample_t *out[MAX_OUTPUT_CHANNELS]; @@ -329,12 +326,12 @@ int JackPlayback::mixerProc() } -ALCenum JackPlayback::open(const ALCchar *name) +void JackPlayback::open(const ALCchar *name) { if(!name) name = jackDevice; else if(strcmp(name, jackDevice) != 0) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; const char *client_name{"alsoft"}; jack_status_t status; @@ -342,7 +339,8 @@ ALCenum JackPlayback::open(const ALCchar *name) if(mClient == nullptr) { ERR("jack_client_open() failed, status = 0x%02x\n", status); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Failed to connect to JACK server: 0x%02x", + status}; } if((status&JackServerStarted)) TRACE("JACK server started\n"); @@ -356,7 +354,6 @@ ALCenum JackPlayback::open(const ALCchar *name) jack_set_buffer_size_callback(mClient, &JackPlayback::bufferSizeNotifyC, this); mDevice->DeviceName = name; - return ALC_NO_ERROR; } bool JackPlayback::reset() diff --git a/alc/backends/loopback.cpp b/alc/backends/loopback.cpp index 7edc2d40..511061f3 100644 --- a/alc/backends/loopback.cpp +++ b/alc/backends/loopback.cpp @@ -31,7 +31,7 @@ namespace { struct LoopbackBackend final : public BackendBase { LoopbackBackend(ALCdevice *device) noexcept : BackendBase{device} { } - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool reset() override; bool start() override; void stop() override; @@ -40,10 +40,9 @@ struct LoopbackBackend final : public BackendBase { }; -ALCenum LoopbackBackend::open(const ALCchar *name) +void LoopbackBackend::open(const ALCchar *name) { mDevice->DeviceName = name; - return ALC_NO_ERROR; } bool LoopbackBackend::reset() diff --git a/alc/backends/null.cpp b/alc/backends/null.cpp index b6b115f1..aca59605 100644 --- a/alc/backends/null.cpp +++ b/alc/backends/null.cpp @@ -31,6 +31,7 @@ #include #include "alcmain.h" +#include "alexcpt.h" #include "almalloc.h" #include "alu.h" #include "logging.h" @@ -51,7 +52,7 @@ struct NullBackend final : public BackendBase { int mixerProc(); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool reset() override; bool start() override; void stop() override; @@ -108,16 +109,14 @@ int NullBackend::mixerProc() } -ALCenum NullBackend::open(const ALCchar *name) +void NullBackend::open(const ALCchar *name) { if(!name) name = nullDevice; else if(strcmp(name, nullDevice) != 0) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; mDevice->DeviceName = name; - - return ALC_NO_ERROR; } bool NullBackend::reset() diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index 50ea884d..4e4ceb5b 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -28,10 +28,12 @@ #include #include +#include #include #include #include "alcmain.h" +#include "alexcpt.h" #include "alu.h" #include "compat.h" #include "endiantest.h" @@ -58,26 +60,24 @@ SLuint32 GetChannelMask(DevFmtChannels chans) { switch(chans) { - case DevFmtMono: return SL_SPEAKER_FRONT_CENTER; - case DevFmtStereo: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT; - case DevFmtQuad: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; - case DevFmtX51: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; - case DevFmtX51Rear: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; - case DevFmtX61: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_BACK_CENTER| - SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; - case DevFmtX71: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT| - SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; - case DevFmtAmbi3D: - break; + case DevFmtMono: return SL_SPEAKER_FRONT_CENTER; + case DevFmtStereo: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; + case DevFmtQuad: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | + SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT; + case DevFmtX51: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | + SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_SIDE_LEFT | + SL_SPEAKER_SIDE_RIGHT; + case DevFmtX51Rear: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | + SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_LEFT | + SL_SPEAKER_BACK_RIGHT; + case DevFmtX61: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | + SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_CENTER | + SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT; + case DevFmtX71: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | + SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_LEFT | + SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT; + case DevFmtAmbi3D: + break; } return 0; } @@ -87,16 +87,16 @@ SLuint32 GetTypeRepresentation(DevFmtType type) { switch(type) { - case DevFmtUByte: - case DevFmtUShort: - case DevFmtUInt: - return SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT; - case DevFmtByte: - case DevFmtShort: - case DevFmtInt: - return SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT; - case DevFmtFloat: - return SL_ANDROID_PCM_REPRESENTATION_FLOAT; + case DevFmtUByte: + case DevFmtUShort: + case DevFmtUInt: + return SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT; + case DevFmtByte: + case DevFmtShort: + case DevFmtInt: + return SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT; + case DevFmtFloat: + return SL_ANDROID_PCM_REPRESENTATION_FLOAT; } return 0; } @@ -106,31 +106,31 @@ const char *res_str(SLresult result) { switch(result) { - case SL_RESULT_SUCCESS: return "Success"; - case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated"; - case SL_RESULT_PARAMETER_INVALID: return "Parameter invalid"; - case SL_RESULT_MEMORY_FAILURE: return "Memory failure"; - case SL_RESULT_RESOURCE_ERROR: return "Resource error"; - case SL_RESULT_RESOURCE_LOST: return "Resource lost"; - case SL_RESULT_IO_ERROR: return "I/O error"; - case SL_RESULT_BUFFER_INSUFFICIENT: return "Buffer insufficient"; - case SL_RESULT_CONTENT_CORRUPTED: return "Content corrupted"; - case SL_RESULT_CONTENT_UNSUPPORTED: return "Content unsupported"; - case SL_RESULT_CONTENT_NOT_FOUND: return "Content not found"; - case SL_RESULT_PERMISSION_DENIED: return "Permission denied"; - case SL_RESULT_FEATURE_UNSUPPORTED: return "Feature unsupported"; - case SL_RESULT_INTERNAL_ERROR: return "Internal error"; - case SL_RESULT_UNKNOWN_ERROR: return "Unknown error"; - case SL_RESULT_OPERATION_ABORTED: return "Operation aborted"; - case SL_RESULT_CONTROL_LOST: return "Control lost"; + case SL_RESULT_SUCCESS: return "Success"; + case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated"; + case SL_RESULT_PARAMETER_INVALID: return "Parameter invalid"; + case SL_RESULT_MEMORY_FAILURE: return "Memory failure"; + case SL_RESULT_RESOURCE_ERROR: return "Resource error"; + case SL_RESULT_RESOURCE_LOST: return "Resource lost"; + case SL_RESULT_IO_ERROR: return "I/O error"; + case SL_RESULT_BUFFER_INSUFFICIENT: return "Buffer insufficient"; + case SL_RESULT_CONTENT_CORRUPTED: return "Content corrupted"; + case SL_RESULT_CONTENT_UNSUPPORTED: return "Content unsupported"; + case SL_RESULT_CONTENT_NOT_FOUND: return "Content not found"; + case SL_RESULT_PERMISSION_DENIED: return "Permission denied"; + case SL_RESULT_FEATURE_UNSUPPORTED: return "Feature unsupported"; + case SL_RESULT_INTERNAL_ERROR: return "Internal error"; + case SL_RESULT_UNKNOWN_ERROR: return "Unknown error"; + case SL_RESULT_OPERATION_ABORTED: return "Operation aborted"; + case SL_RESULT_CONTROL_LOST: return "Control lost"; #ifdef SL_RESULT_READONLY - case SL_RESULT_READONLY: return "ReadOnly"; + case SL_RESULT_READONLY: return "ReadOnly"; #endif #ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED - case SL_RESULT_ENGINEOPTION_UNSUPPORTED: return "Engine option unsupported"; + case SL_RESULT_ENGINEOPTION_UNSUPPORTED: return "Engine option unsupported"; #endif #ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE - case SL_RESULT_SOURCE_SINK_INCOMPATIBLE: return "Source/Sink incompatible"; + case SL_RESULT_SOURCE_SINK_INCOMPATIBLE: return "Source/Sink incompatible"; #endif } return "Unknown error code"; @@ -152,7 +152,7 @@ struct OpenSLPlayback final : public BackendBase { int mixerProc(); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool reset() override; bool start() override; void stop() override; @@ -298,12 +298,12 @@ int OpenSLPlayback::mixerProc() } -ALCenum OpenSLPlayback::open(const ALCchar *name) +void OpenSLPlayback::open(const ALCchar *name) { if(!name) name = opensl_device; else if(strcmp(name, opensl_device) != 0) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; // create engine SLresult result{slCreateEngine(&mEngineObj, 0, nullptr, 0, nullptr, nullptr)}; @@ -340,11 +340,11 @@ ALCenum OpenSLPlayback::open(const ALCchar *name) mEngineObj = nullptr; mEngine = nullptr; - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Failed to initialize OpenSL: 0x%08x", + result}; } mDevice->DeviceName = name; - return ALC_NO_ERROR; } bool OpenSLPlayback::reset() @@ -635,7 +635,7 @@ struct OpenSLCapture final : public BackendBase { { static_cast(context)->process(bq); } void process(SLAndroidSimpleBufferQueueItf bq); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool start() override; void stop() override; ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; @@ -676,12 +676,12 @@ void OpenSLCapture::process(SLAndroidSimpleBufferQueueItf) } -ALCenum OpenSLCapture::open(const ALCchar* name) +void OpenSLCapture::open(const ALCchar* name) { if(!name) name = opensl_device; else if(strcmp(name, opensl_device) != 0) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; SLresult result{slCreateEngine(&mEngineObj, 0, nullptr, 0, nullptr, nullptr)}; PRINTERR(result, "slCreateEngine"); @@ -841,11 +841,11 @@ ALCenum OpenSLCapture::open(const ALCchar* name) mEngineObj = nullptr; mEngine = nullptr; - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Failed to initialize OpenSL: 0x%08x", + result}; } mDevice->DeviceName = name; - return ALC_NO_ERROR; } bool OpenSLCapture::start() diff --git a/alc/backends/oss.cpp b/alc/backends/oss.cpp index c825ce3e..1e3ad28b 100644 --- a/alc/backends/oss.cpp +++ b/alc/backends/oss.cpp @@ -45,6 +45,7 @@ #include "alcmain.h" #include "alconfig.h" +#include "alexcpt.h" #include "almalloc.h" #include "alnumeric.h" #include "aloptional.h" @@ -248,7 +249,7 @@ struct OSSPlayback final : public BackendBase { int mixerProc(); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool reset() override; bool start() override; void stop() override; @@ -329,7 +330,7 @@ int OSSPlayback::mixerProc() } -ALCenum OSSPlayback::open(const ALCchar *name) +void OSSPlayback::open(const ALCchar *name) { const char *devname{DefaultPlayback.c_str()}; if(!name) @@ -344,7 +345,7 @@ ALCenum OSSPlayback::open(const ALCchar *name) { return entry.name == name; } ); if(iter == PlaybackDevices.cend()) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; devname = iter->device_name.c_str(); } @@ -352,11 +353,11 @@ ALCenum OSSPlayback::open(const ALCchar *name) if(mFd == -1) { ERR("Could not open %s: %s\n", devname, strerror(errno)); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Could not open %s: %s", devname, + strerror(errno)}; } mDevice->DeviceName = name; - return ALC_NO_ERROR; } bool OSSPlayback::reset() @@ -469,7 +470,7 @@ struct OSScapture final : public BackendBase { int recordProc(); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool start() override; void stop() override; ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; @@ -539,7 +540,7 @@ int OSScapture::recordProc() } -ALCenum OSScapture::open(const ALCchar *name) +void OSScapture::open(const ALCchar *name) { const char *devname{DefaultCapture.c_str()}; if(!name) @@ -554,7 +555,7 @@ ALCenum OSScapture::open(const ALCchar *name) { return entry.name == name; } ); if(iter == CaptureDevices.cend()) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; devname = iter->device_name.c_str(); } @@ -562,27 +563,29 @@ ALCenum OSScapture::open(const ALCchar *name) if(mFd == -1) { ERR("Could not open %s: %s\n", devname, strerror(errno)); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Could not open %s: %s", devname, + strerror(errno)}; } int ossFormat{}; switch(mDevice->FmtType) { - case DevFmtByte: - ossFormat = AFMT_S8; - break; - case DevFmtUByte: - ossFormat = AFMT_U8; - break; - case DevFmtShort: - ossFormat = AFMT_S16_NE; - break; - case DevFmtUShort: - case DevFmtInt: - case DevFmtUInt: - case DevFmtFloat: - ERR("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); - return ALC_INVALID_VALUE; + case DevFmtByte: + ossFormat = AFMT_S8; + break; + case DevFmtUByte: + ossFormat = AFMT_U8; + break; + case DevFmtShort: + ossFormat = AFMT_S16_NE; + break; + case DevFmtUShort: + case DevFmtInt: + case DevFmtUInt: + case DevFmtFloat: + ERR("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); + throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", + DevFmtTypeString(mDevice->FmtType)}; } ALuint periods{4}; @@ -608,9 +611,7 @@ ALCenum OSScapture::open(const ALCchar *name) { err: ERR("%s failed: %s\n", err, strerror(errno)); - close(mFd); - mFd = -1; - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "%s failed: %s", err, strerror(errno)}; } #undef CHECKERR @@ -618,9 +619,8 @@ ALCenum OSScapture::open(const ALCchar *name) { ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(mDevice->FmtChans), numChannels); - close(mFd); - mFd = -1; - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Failed to set %s capture", + DevFmtChannelsString(mDevice->FmtChans)}; } if(!((ossFormat == AFMT_S8 && mDevice->FmtType == DevFmtByte) || @@ -628,22 +628,18 @@ ALCenum OSScapture::open(const ALCchar *name) (ossFormat == AFMT_S16_NE && mDevice->FmtType == DevFmtShort))) { ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(mDevice->FmtType), ossFormat); - close(mFd); - mFd = -1; - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Failed to set %s samples", + DevFmtTypeString(mDevice->FmtType)}; } mRing = CreateRingBuffer(mDevice->BufferSize, frameSize, false); if(!mRing) { ERR("Ring buffer create failed\n"); - close(mFd); - mFd = -1; - return ALC_OUT_OF_MEMORY; + throw al::backend_exception{ALC_INVALID_VALUE, "Failed to create ring buffer"}; } mDevice->DeviceName = name; - return ALC_NO_ERROR; } bool OSScapture::start() diff --git a/alc/backends/portaudio.cpp b/alc/backends/portaudio.cpp index 0b77f622..7847f41d 100644 --- a/alc/backends/portaudio.cpp +++ b/alc/backends/portaudio.cpp @@ -27,6 +27,7 @@ #include #include "alcmain.h" +#include "alexcpt.h" #include "alu.h" #include "alconfig.h" #include "dynload.h" @@ -76,11 +77,15 @@ struct PortPlayback final : public BackendBase { static int writeCallbackC(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, - const PaStreamCallbackFlags statusFlags, void *userData); + const PaStreamCallbackFlags statusFlags, void *userData) + { + return static_cast(userData)->writeCallback(inputBuffer, outputBuffer, + framesPerBuffer, timeInfo, statusFlags); + } int writeCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool reset() override; bool start() override; void stop() override; @@ -101,14 +106,6 @@ PortPlayback::~PortPlayback() } -int PortPlayback::writeCallbackC(const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, - const PaStreamCallbackFlags statusFlags, void *userData) -{ - return static_cast(userData)->writeCallback(inputBuffer, outputBuffer, - framesPerBuffer, timeInfo, statusFlags); -} - int PortPlayback::writeCallback(const void*, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo*, const PaStreamCallbackFlags) @@ -120,12 +117,12 @@ int PortPlayback::writeCallback(const void*, void *outputBuffer, } -ALCenum PortPlayback::open(const ALCchar *name) +void PortPlayback::open(const ALCchar *name) { if(!name) name = pa_device; else if(strcmp(name, pa_device) != 0) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; mUpdateSize = mDevice->UpdateSize; @@ -139,25 +136,25 @@ ALCenum PortPlayback::open(const ALCchar *name) switch(mDevice->FmtType) { - case DevFmtByte: - mParams.sampleFormat = paInt8; - break; - case DevFmtUByte: - mParams.sampleFormat = paUInt8; - break; - case DevFmtUShort: - /* fall-through */ - case DevFmtShort: - mParams.sampleFormat = paInt16; - break; - case DevFmtUInt: - /* fall-through */ - case DevFmtInt: - mParams.sampleFormat = paInt32; - break; - case DevFmtFloat: - mParams.sampleFormat = paFloat32; - break; + case DevFmtByte: + mParams.sampleFormat = paInt8; + break; + case DevFmtUByte: + mParams.sampleFormat = paUInt8; + break; + case DevFmtUShort: + /* fall-through */ + case DevFmtShort: + mParams.sampleFormat = paInt16; + break; + case DevFmtUInt: + /* fall-through */ + case DevFmtInt: + mParams.sampleFormat = paInt32; + break; + case DevFmtFloat: + mParams.sampleFormat = paFloat32; + break; } retry_open: @@ -171,12 +168,11 @@ retry_open: goto retry_open; } ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Failed to open stream: %s", + Pa_GetErrorText(err)}; } mDevice->DeviceName = name; - return ALC_NO_ERROR; - } bool PortPlayback::reset() @@ -240,11 +236,15 @@ struct PortCapture final : public BackendBase { static int readCallbackC(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, - const PaStreamCallbackFlags statusFlags, void *userData); + const PaStreamCallbackFlags statusFlags, void *userData) + { + return static_cast(userData)->readCallback(inputBuffer, outputBuffer, + framesPerBuffer, timeInfo, statusFlags); + } int readCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool start() override; void stop() override; ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; @@ -267,14 +267,6 @@ PortCapture::~PortCapture() } -int PortCapture::readCallbackC(const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, - const PaStreamCallbackFlags statusFlags, void* userData) -{ - return static_cast(userData)->readCallback(inputBuffer, outputBuffer, - framesPerBuffer, timeInfo, statusFlags); -} - int PortCapture::readCallback(const void *inputBuffer, void*, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo*, const PaStreamCallbackFlags) @@ -284,19 +276,19 @@ int PortCapture::readCallback(const void *inputBuffer, void*, } -ALCenum PortCapture::open(const ALCchar *name) +void PortCapture::open(const ALCchar *name) { if(!name) name = pa_device; else if(strcmp(name, pa_device) != 0) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; ALuint samples{mDevice->BufferSize}; samples = maxu(samples, 100 * mDevice->Frequency / 1000); ALuint frame_size{mDevice->frameSizeFromFmt()}; mRing = CreateRingBuffer(samples, frame_size, false); - if(!mRing) return ALC_INVALID_VALUE; + if(!mRing) throw al::backend_exception{ALC_INVALID_VALUE, "Failed to create ring buffer"}; auto devidopt = ConfigValueInt(nullptr, "port", "capture"); if(devidopt && *devidopt >= 0) mParams.device = *devidopt; @@ -306,25 +298,26 @@ ALCenum PortCapture::open(const ALCchar *name) switch(mDevice->FmtType) { - case DevFmtByte: - mParams.sampleFormat = paInt8; - break; - case DevFmtUByte: - mParams.sampleFormat = paUInt8; - break; - case DevFmtShort: - mParams.sampleFormat = paInt16; - break; - case DevFmtInt: - mParams.sampleFormat = paInt32; - break; - case DevFmtFloat: - mParams.sampleFormat = paFloat32; - break; - case DevFmtUInt: - case DevFmtUShort: - ERR("%s samples not supported\n", DevFmtTypeString(mDevice->FmtType)); - return ALC_INVALID_VALUE; + case DevFmtByte: + mParams.sampleFormat = paInt8; + break; + case DevFmtUByte: + mParams.sampleFormat = paUInt8; + break; + case DevFmtShort: + mParams.sampleFormat = paInt16; + break; + case DevFmtInt: + mParams.sampleFormat = paInt32; + break; + case DevFmtFloat: + mParams.sampleFormat = paFloat32; + break; + case DevFmtUInt: + case DevFmtUShort: + ERR("%s samples not supported\n", DevFmtTypeString(mDevice->FmtType)); + throw al::backend_exception{ALC_INVALID_VALUE, "%s samples not supported", + DevFmtTypeString(mDevice->FmtType)}; } mParams.channelCount = static_cast(mDevice->channelsFromFmt()); @@ -333,11 +326,11 @@ ALCenum PortCapture::open(const ALCchar *name) if(err != paNoError) { ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Failed to open stream: %s", + Pa_GetErrorText(err)}; } mDevice->DeviceName = name; - return ALC_NO_ERROR; } diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 4d3b34d9..be78ee17 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -663,7 +663,7 @@ struct PulsePlayback final : public BackendBase { static void streamMovedCallbackC(pa_stream *stream, void *pdata); void streamMovedCallback(pa_stream *stream); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool reset() override; bool start() override; void stop() override; @@ -818,7 +818,7 @@ void PulsePlayback::streamMovedCallback(pa_stream *stream) } -ALCenum PulsePlayback::open(const ALCchar *name) +void PulsePlayback::open(const ALCchar *name) { const char *pulse_name{nullptr}; const char *dev_name{nullptr}; @@ -873,8 +873,6 @@ ALCenum PulsePlayback::open(const ALCchar *name) } else mDevice->DeviceName = dev_name; - - return ALC_NO_ERROR; } bool PulsePlayback::reset() @@ -1107,7 +1105,7 @@ struct PulseCapture final : public BackendBase { static void streamMovedCallbackC(pa_stream *stream, void *pdata); void streamMovedCallback(pa_stream *stream); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool start() override; void stop() override; ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; @@ -1192,7 +1190,7 @@ void PulseCapture::streamMovedCallback(pa_stream *stream) } -ALCenum PulseCapture::open(const ALCchar *name) +void PulseCapture::open(const ALCchar *name) { const char *pulse_name{nullptr}; if(name) @@ -1218,53 +1216,53 @@ ALCenum PulseCapture::open(const ALCchar *name) pa_channel_map chanmap{}; switch(mDevice->FmtChans) { - case DevFmtMono: - chanmap = MonoChanMap; - break; - case DevFmtStereo: - chanmap = StereoChanMap; - break; - case DevFmtQuad: - chanmap = QuadChanMap; - break; - case DevFmtX51: - chanmap = X51ChanMap; - break; - case DevFmtX51Rear: - chanmap = X51RearChanMap; - break; - case DevFmtX61: - chanmap = X61ChanMap; - break; - case DevFmtX71: - chanmap = X71ChanMap; - break; - case DevFmtAmbi3D: - throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", - DevFmtChannelsString(mDevice->FmtChans)}; + case DevFmtMono: + chanmap = MonoChanMap; + break; + case DevFmtStereo: + chanmap = StereoChanMap; + break; + case DevFmtQuad: + chanmap = QuadChanMap; + break; + case DevFmtX51: + chanmap = X51ChanMap; + break; + case DevFmtX51Rear: + chanmap = X51RearChanMap; + break; + case DevFmtX61: + chanmap = X61ChanMap; + break; + case DevFmtX71: + chanmap = X71ChanMap; + break; + case DevFmtAmbi3D: + throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", + DevFmtChannelsString(mDevice->FmtChans)}; } SetChannelOrderFromMap(mDevice, chanmap); switch(mDevice->FmtType) { - case DevFmtUByte: - mSilentVal = al::byte(0x80); - mSpec.format = PA_SAMPLE_U8; - break; - case DevFmtShort: - mSpec.format = PA_SAMPLE_S16NE; - break; - case DevFmtInt: - mSpec.format = PA_SAMPLE_S32NE; - break; - case DevFmtFloat: - mSpec.format = PA_SAMPLE_FLOAT32NE; - break; - case DevFmtByte: - case DevFmtUShort: - case DevFmtUInt: - throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", - DevFmtTypeString(mDevice->FmtType)}; + case DevFmtUByte: + mSilentVal = al::byte(0x80); + mSpec.format = PA_SAMPLE_U8; + break; + case DevFmtShort: + mSpec.format = PA_SAMPLE_S16NE; + break; + case DevFmtInt: + mSpec.format = PA_SAMPLE_S32NE; + break; + case DevFmtFloat: + mSpec.format = PA_SAMPLE_FLOAT32NE; + break; + case DevFmtByte: + case DevFmtUShort: + case DevFmtUInt: + throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", + DevFmtTypeString(mDevice->FmtType)}; } mSpec.rate = mDevice->Frequency; mSpec.channels = static_cast(mDevice->channelsFromFmt()); @@ -1297,8 +1295,6 @@ ALCenum PulseCapture::open(const ALCchar *name) &PulseCapture::sourceNameCallbackC, this)}; wait_for_operation(op, plock); } - - return ALC_NO_ERROR; } bool PulseCapture::start() diff --git a/alc/backends/qsa.cpp b/alc/backends/qsa.cpp index 5fee2989..872a8541 100644 --- a/alc/backends/qsa.cpp +++ b/alc/backends/qsa.cpp @@ -34,6 +34,7 @@ #include #include "alcmain.h" +#include "alexcpt.h" #include "alu.h" #include "threads.h" @@ -174,7 +175,7 @@ struct PlaybackWrapper final : public BackendBase { PlaybackWrapper(ALCdevice *device) noexcept : BackendBase{device} { } ~PlaybackWrapper() override; - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool reset() override; bool start() override; void stop() override; @@ -613,11 +614,18 @@ PlaybackWrapper::~PlaybackWrapper() qsa_close_playback(this); } -ALCenum PlaybackWrapper::open(const ALCchar *name) -{ return qsa_open_playback(this, name); } +void PlaybackWrapper::open(const ALCchar *name) +{ + if(auto err = qsa_open_playback(this, name)) + throw al::backend_exception{ALC_INVALID_VALUE, "%d", err}; +} bool PlaybackWrapper::reset() -{ return qsa_reset_playback(this); } +{ + if(!qsa_reset_playback(this)) + throw al::backend_exception{ALC_INVALID_VALUE, ""}; + return true; +} bool PlaybackWrapper::start() { return qsa_start_playback(this); } @@ -634,7 +642,7 @@ struct CaptureWrapper final : public BackendBase { CaptureWrapper(ALCdevice *device) noexcept : BackendBase{device} { } ~CaptureWrapper() override; - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool start() override; void stop() override; ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; @@ -891,8 +899,11 @@ CaptureWrapper::~CaptureWrapper() qsa_close_capture(this); } -ALCenum CaptureWrapper::open(const ALCchar *name) -{ return qsa_open_capture(this, name); } +void CaptureWrapper::open(const ALCchar *name) +{ + if(auto err = qsa_open_capture(this, name)) + throw al::backend_exception{ALC_INVALID_VALUE, "%d", err}; +} bool CaptureWrapper::start() { qsa_start_capture(this); return true; } diff --git a/alc/backends/sdl2.cpp b/alc/backends/sdl2.cpp index 71616906..1063ca7a 100644 --- a/alc/backends/sdl2.cpp +++ b/alc/backends/sdl2.cpp @@ -30,6 +30,7 @@ #include "AL/al.h" #include "alcmain.h" +#include "alexcpt.h" #include "almalloc.h" #include "alu.h" #include "logging.h" @@ -54,7 +55,7 @@ struct Sdl2Backend final : public BackendBase { static void audioCallbackC(void *ptr, Uint8 *stream, int len); void audioCallback(Uint8 *stream, int len); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool reset() override; bool start() override; void stop() override; @@ -89,20 +90,20 @@ void Sdl2Backend::audioCallback(Uint8 *stream, int len) aluMixData(mDevice, stream, ulen / mFrameSize); } -ALCenum Sdl2Backend::open(const ALCchar *name) +void Sdl2Backend::open(const ALCchar *name) { SDL_AudioSpec want{}, have{}; want.freq = static_cast(mDevice->Frequency); switch(mDevice->FmtType) { - case DevFmtUByte: want.format = AUDIO_U8; break; - case DevFmtByte: want.format = AUDIO_S8; break; - case DevFmtUShort: want.format = AUDIO_U16SYS; break; - case DevFmtShort: want.format = AUDIO_S16SYS; break; - case DevFmtUInt: /* fall-through */ - case DevFmtInt: want.format = AUDIO_S32SYS; break; - case DevFmtFloat: want.format = AUDIO_F32; break; + case DevFmtUByte: want.format = AUDIO_U8; break; + case DevFmtByte: want.format = AUDIO_S8; break; + case DevFmtUShort: want.format = AUDIO_U16SYS; break; + case DevFmtShort: want.format = AUDIO_S16SYS; break; + case DevFmtUInt: /* fall-through */ + case DevFmtInt: want.format = AUDIO_S32SYS; break; + case DevFmtFloat: want.format = AUDIO_F32; break; } want.channels = (mDevice->FmtChans == DevFmtMono) ? 1 : 2; want.samples = static_cast(mDevice->UpdateSize); @@ -114,19 +115,19 @@ ALCenum Sdl2Backend::open(const ALCchar *name) */ if(!name || strcmp(name, defaultDeviceName) == 0) mDeviceID = SDL_OpenAudioDevice(nullptr, SDL_FALSE, &want, &have, - SDL_AUDIO_ALLOW_ANY_CHANGE); + SDL_AUDIO_ALLOW_ANY_CHANGE); else { const size_t prefix_len = strlen(DEVNAME_PREFIX); if(strncmp(name, DEVNAME_PREFIX, prefix_len) == 0) mDeviceID = SDL_OpenAudioDevice(name+prefix_len, SDL_FALSE, &want, &have, - SDL_AUDIO_ALLOW_ANY_CHANGE); + SDL_AUDIO_ALLOW_ANY_CHANGE); else mDeviceID = SDL_OpenAudioDevice(name, SDL_FALSE, &want, &have, - SDL_AUDIO_ALLOW_ANY_CHANGE); + SDL_AUDIO_ALLOW_ANY_CHANGE); } if(mDeviceID == 0) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "%s", SDL_GetError()}; mDevice->Frequency = static_cast(have.freq); if(have.channels == 1) @@ -136,19 +137,21 @@ ALCenum Sdl2Backend::open(const ALCchar *name) else { ERR("Got unhandled SDL channel count: %d\n", int{have.channels}); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Unhandled SDL channel count: %d", + int{have.channels}}; } switch(have.format) { - case AUDIO_U8: mDevice->FmtType = DevFmtUByte; break; - case AUDIO_S8: mDevice->FmtType = DevFmtByte; break; - case AUDIO_U16SYS: mDevice->FmtType = DevFmtUShort; break; - case AUDIO_S16SYS: mDevice->FmtType = DevFmtShort; break; - case AUDIO_S32SYS: mDevice->FmtType = DevFmtInt; break; - case AUDIO_F32SYS: mDevice->FmtType = DevFmtFloat; break; - default: - ERR("Got unsupported SDL format: 0x%04x\n", have.format); - return ALC_INVALID_VALUE; + case AUDIO_U8: mDevice->FmtType = DevFmtUByte; break; + case AUDIO_S8: mDevice->FmtType = DevFmtByte; break; + case AUDIO_U16SYS: mDevice->FmtType = DevFmtUShort; break; + case AUDIO_S16SYS: mDevice->FmtType = DevFmtShort; break; + case AUDIO_S32SYS: mDevice->FmtType = DevFmtInt; break; + case AUDIO_F32SYS: mDevice->FmtType = DevFmtFloat; break; + default: + ERR("Got unsupported SDL format: 0x%04x\n", have.format); + throw al::backend_exception{ALC_INVALID_VALUE, "Unhandled SDL format: 0x%04x", + have.format}; } mDevice->UpdateSize = have.samples; mDevice->BufferSize = have.samples * 2; /* SDL always (tries to) use two periods. */ @@ -160,7 +163,6 @@ ALCenum Sdl2Backend::open(const ALCchar *name) mUpdateSize = mDevice->UpdateSize; mDevice->DeviceName = name ? name : defaultDeviceName; - return ALC_NO_ERROR; } bool Sdl2Backend::reset() diff --git a/alc/backends/sndio.cpp b/alc/backends/sndio.cpp index d2654853..e0c70762 100644 --- a/alc/backends/sndio.cpp +++ b/alc/backends/sndio.cpp @@ -30,6 +30,7 @@ #include #include "alcmain.h" +#include "alexcpt.h" #include "alu.h" #include "threads.h" #include "vector.h" @@ -49,7 +50,7 @@ struct SndioPlayback final : public BackendBase { int mixerProc(); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool reset() override; bool start() override; void stop() override; @@ -106,22 +107,21 @@ int SndioPlayback::mixerProc() } -ALCenum SndioPlayback::open(const ALCchar *name) +void SndioPlayback::open(const ALCchar *name) { if(!name) name = sndio_device; else if(strcmp(name, sndio_device) != 0) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; mSndHandle = sio_open(nullptr, SIO_PLAY, 0); if(mSndHandle == nullptr) { ERR("Could not open device\n"); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Could not open sound device"}; } mDevice->DeviceName = name; - return ALC_NO_ERROR; } bool SndioPlayback::reset() @@ -249,7 +249,7 @@ struct SndioCapture final : public BackendBase { int recordProc(); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool start() override; void stop() override; ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; @@ -319,18 +319,18 @@ int SndioCapture::recordProc() } -ALCenum SndioCapture::open(const ALCchar *name) +void SndioCapture::open(const ALCchar *name) { if(!name) name = sndio_device; else if(strcmp(name, sndio_device) != 0) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; mSndHandle = sio_open(nullptr, SIO_REC, 0); if(mSndHandle == nullptr) { ERR("Could not open device\n"); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Could not open sound device"}; } sio_par par; @@ -338,33 +338,34 @@ ALCenum SndioCapture::open(const ALCchar *name) switch(mDevice->FmtType) { - case DevFmtByte: - par.bps = 1; - par.sig = 1; - break; - case DevFmtUByte: - par.bps = 1; - par.sig = 0; - break; - case DevFmtShort: - par.bps = 2; - par.sig = 1; - break; - case DevFmtUShort: - par.bps = 2; - par.sig = 0; - break; - case DevFmtInt: - par.bps = 4; - par.sig = 1; - break; - case DevFmtUInt: - par.bps = 4; - par.sig = 0; - break; - case DevFmtFloat: - ERR("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); - return ALC_INVALID_VALUE; + case DevFmtByte: + par.bps = 1; + par.sig = 1; + break; + case DevFmtUByte: + par.bps = 1; + par.sig = 0; + break; + case DevFmtShort: + par.bps = 2; + par.sig = 1; + break; + case DevFmtUShort: + par.bps = 2; + par.sig = 0; + break; + case DevFmtInt: + par.bps = 4; + par.sig = 1; + break; + case DevFmtUInt: + par.bps = 4; + par.sig = 0; + break; + case DevFmtFloat: + ERR("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); + throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", + DevFmtTypeString(mDevice->FmtType)}; } par.bits = par.bps * 8; par.le = SIO_LE_NATIVE; @@ -381,13 +382,14 @@ ALCenum SndioCapture::open(const ALCchar *name) if(!sio_setpar(mSndHandle, &par) || !sio_getpar(mSndHandle, &par)) { ERR("Failed to set device parameters\n"); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Failed to set device praameters"}; } if(par.bits != par.bps*8) { ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, + "Padded samples not supported (got %u of %u bits)", par.bits, par.bps*8}; } if(!((mDevice->FmtType == DevFmtByte && par.bits == 8 && par.sig != 0) || @@ -401,20 +403,21 @@ ALCenum SndioCapture::open(const ALCchar *name) ERR("Failed to set format %s %s %uhz, got %c%u %u-channel %uhz instead\n", DevFmtTypeString(mDevice->FmtType), DevFmtChannelsString(mDevice->FmtChans), mDevice->Frequency, par.sig?'s':'u', par.bits, par.rchan, par.rate); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Could not set format %s %s %uhz", + DevFmtTypeString(mDevice->FmtType), DevFmtChannelsString(mDevice->FmtChans), + mDevice->Frequency}; } mRing = CreateRingBuffer(mDevice->BufferSize, par.bps*par.rchan, false); if(!mRing) { ERR("Failed to allocate %u-byte ringbuffer\n", mDevice->BufferSize*par.bps*par.rchan); - return ALC_OUT_OF_MEMORY; + throw al::backend_exception{ALC_OUT_OF_MEMORY, "Failed to allocate ring buffer"}; } SetDefaultChannelOrder(mDevice); mDevice->DeviceName = name; - return ALC_NO_ERROR; } bool SndioCapture::start() diff --git a/alc/backends/solaris.cpp b/alc/backends/solaris.cpp index 128924bb..5963a4b2 100644 --- a/alc/backends/solaris.cpp +++ b/alc/backends/solaris.cpp @@ -39,6 +39,7 @@ #include #include "alcmain.h" +#include "alexcpt.h" #include "alu.h" #include "alconfig.h" #include "threads.h" @@ -61,7 +62,7 @@ struct SolarisBackend final : public BackendBase { int mixerProc(); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool reset() override; bool start() override; void stop() override; @@ -142,22 +143,22 @@ int SolarisBackend::mixerProc() } -ALCenum SolarisBackend::open(const ALCchar *name) +void SolarisBackend::open(const ALCchar *name) { if(!name) name = solaris_device; else if(strcmp(name, solaris_device) != 0) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; mFd = ::open(solaris_driver.c_str(), O_WRONLY); if(mFd == -1) { ERR("Could not open %s: %s\n", solaris_driver.c_str(), strerror(errno)); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Could not open %s: %s", + solaris_driver.c_str(), strerror(errno)}; } mDevice->DeviceName = name; - return ALC_NO_ERROR; } bool SolarisBackend::reset() diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 2a610c8d..b6f5b5fb 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -55,6 +55,7 @@ #include #include "alcmain.h" +#include "alexcpt.h" #include "alu.h" #include "ringbuffer.h" #include "compat.h" @@ -610,7 +611,7 @@ struct WasapiPlayback final : public BackendBase, WasapiProxy { int mixerProc(); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; HRESULT openProxy() override; void closeProxy() override; @@ -708,7 +709,7 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() } -ALCenum WasapiPlayback::open(const ALCchar *name) +void WasapiPlayback::open(const ALCchar *name) { HRESULT hr{S_OK}; @@ -762,10 +763,8 @@ ALCenum WasapiPlayback::open(const ALCchar *name) mDevId.clear(); ERR("Device init failed: 0x%08lx\n", hr); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device init failed: 0x%08lx", hr}; } - - return ALC_NO_ERROR; } HRESULT WasapiPlayback::openProxy() @@ -815,7 +814,9 @@ void WasapiPlayback::closeProxy() bool WasapiPlayback::reset() { HRESULT hr{pushMessage(MsgType::ResetDevice).get()}; - return SUCCEEDED(hr) ? true : false; + if(FAILED(hr)) + throw al::backend_exception{ALC_INVALID_VALUE, "0x%08lx", hr}; + return true; } HRESULT WasapiPlayback::resetProxy() @@ -1151,7 +1152,7 @@ struct WasapiCapture final : public BackendBase, WasapiProxy { int recordProc(); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; HRESULT openProxy() override; void closeProxy() override; @@ -1283,7 +1284,7 @@ FORCE_ALIGN int WasapiCapture::recordProc() } -ALCenum WasapiCapture::open(const ALCchar *name) +void WasapiCapture::open(const ALCchar *name) { HRESULT hr{S_OK}; @@ -1337,18 +1338,16 @@ ALCenum WasapiCapture::open(const ALCchar *name) mDevId.clear(); ERR("Device init failed: 0x%08lx\n", hr); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device init failed: 0x%08lx", hr}; } hr = pushMessage(MsgType::ResetDevice).get(); if(FAILED(hr)) { if(hr == E_OUTOFMEMORY) - return ALC_OUT_OF_MEMORY; - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_OUT_OF_MEMORY, "Out of memory"}; + throw al::backend_exception{ALC_INVALID_VALUE, "Device reset failed"}; } - - return ALC_NO_ERROR; } HRESULT WasapiCapture::openProxy() diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp index 797a9fa5..927cb276 100644 --- a/alc/backends/wave.cpp +++ b/alc/backends/wave.cpp @@ -38,6 +38,7 @@ #include "albyte.h" #include "alcmain.h" #include "alconfig.h" +#include "alexcpt.h" #include "almalloc.h" #include "alnumeric.h" #include "alu.h" @@ -96,7 +97,7 @@ struct WaveBackend final : public BackendBase { int mixerProc(); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool reset() override; bool start() override; void stop() override; @@ -202,15 +203,15 @@ int WaveBackend::mixerProc() return 0; } -ALCenum WaveBackend::open(const ALCchar *name) +void WaveBackend::open(const ALCchar *name) { const char *fname{GetConfigValue(nullptr, "wave", "file", "")}; - if(!fname[0]) return ALC_INVALID_VALUE; + if(!fname[0]) throw al::backend_exception{ALC_INVALID_VALUE, "No wave output filename"}; if(!name) name = waveDevice; else if(strcmp(name, waveDevice) != 0) - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; #ifdef _WIN32 { @@ -223,12 +224,11 @@ ALCenum WaveBackend::open(const ALCchar *name) if(!mFile) { ERR("Could not open file '%s': %s\n", fname, strerror(errno)); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "Could not open file '%s': %s", fname, + strerror(errno)}; } mDevice->DeviceName = name; - - return ALC_NO_ERROR; } bool WaveBackend::reset() diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp index d58fa959..c287e136 100644 --- a/alc/backends/winmm.cpp +++ b/alc/backends/winmm.cpp @@ -38,6 +38,7 @@ #include #include "alcmain.h" +#include "alexcpt.h" #include "alu.h" #include "ringbuffer.h" #include "strutils.h" @@ -131,7 +132,7 @@ struct WinMMPlayback final : public BackendBase { int mixerProc(); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool reset() override; bool start() override; void stop() override; @@ -212,7 +213,7 @@ FORCE_ALIGN int WinMMPlayback::mixerProc() } -ALCenum WinMMPlayback::open(const ALCchar *name) +void WinMMPlayback::open(const ALCchar *name) { if(PlaybackDevices.empty()) ProbePlaybackDevices(); @@ -221,7 +222,8 @@ ALCenum WinMMPlayback::open(const ALCchar *name) auto iter = name ? std::find(PlaybackDevices.cbegin(), PlaybackDevices.cend(), name) : PlaybackDevices.cbegin(); - if(iter == PlaybackDevices.cend()) return ALC_INVALID_VALUE; + if(iter == PlaybackDevices.cend()) + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; auto DeviceID = static_cast(std::distance(PlaybackDevices.cbegin(), iter)); retry_open: @@ -256,11 +258,10 @@ retry_open: goto retry_open; } ERR("waveOutOpen failed: %u\n", res); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "waveOutOpen failed: %u", res}; } mDevice->DeviceName = PlaybackDevices[DeviceID]; - return ALC_NO_ERROR; } bool WinMMPlayback::reset() @@ -373,7 +374,7 @@ struct WinMMCapture final : public BackendBase { int captureProc(); - ALCenum open(const ALCchar *name) override; + void open(const ALCchar *name) override; bool start() override; void stop() override; ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; @@ -456,7 +457,7 @@ int WinMMCapture::captureProc() } -ALCenum WinMMCapture::open(const ALCchar *name) +void WinMMCapture::open(const ALCchar *name) { if(CaptureDevices.empty()) ProbeCaptureDevices(); @@ -465,36 +466,39 @@ ALCenum WinMMCapture::open(const ALCchar *name) auto iter = name ? std::find(CaptureDevices.cbegin(), CaptureDevices.cend(), name) : CaptureDevices.cbegin(); - if(iter == CaptureDevices.cend()) return ALC_INVALID_VALUE; + if(iter == CaptureDevices.cend()) + throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name}; auto DeviceID = static_cast(std::distance(CaptureDevices.cbegin(), iter)); switch(mDevice->FmtChans) { - case DevFmtMono: - case DevFmtStereo: - break; - - case DevFmtQuad: - case DevFmtX51: - case DevFmtX51Rear: - case DevFmtX61: - case DevFmtX71: - case DevFmtAmbi3D: - return ALC_INVALID_ENUM; + case DevFmtMono: + case DevFmtStereo: + break; + + case DevFmtQuad: + case DevFmtX51: + case DevFmtX51Rear: + case DevFmtX61: + case DevFmtX71: + case DevFmtAmbi3D: + throw al::backend_exception{ALC_INVALID_VALUE, "%s capture not supported", + DevFmtChannelsString(mDevice->FmtChans)}; } switch(mDevice->FmtType) { - case DevFmtUByte: - case DevFmtShort: - case DevFmtInt: - case DevFmtFloat: - break; - - case DevFmtByte: - case DevFmtUShort: - case DevFmtUInt: - return ALC_INVALID_ENUM; + case DevFmtUByte: + case DevFmtShort: + case DevFmtInt: + case DevFmtFloat: + break; + + case DevFmtByte: + case DevFmtUShort: + case DevFmtUInt: + throw al::backend_exception{ALC_INVALID_VALUE, "%s samples not supported", + DevFmtTypeString(mDevice->FmtType)}; } mFormat = WAVEFORMATEX{}; @@ -513,7 +517,7 @@ ALCenum WinMMCapture::open(const ALCchar *name) if(res != MMSYSERR_NOERROR) { ERR("waveInOpen failed: %u\n", res); - return ALC_INVALID_VALUE; + throw al::backend_exception{ALC_INVALID_VALUE, "waveInOpen failed: %u", res}; } // Ensure each buffer is 50ms each @@ -526,7 +530,7 @@ ALCenum WinMMCapture::open(const ALCchar *name) CapturedDataSize = static_cast(maxz(CapturedDataSize, BufferSize*mWaveBuffer.size())); mRing = CreateRingBuffer(CapturedDataSize, mFormat.nBlockAlign, false); - if(!mRing) return ALC_INVALID_VALUE; + if(!mRing) throw al::backend_exception{ALC_INVALID_VALUE, "Could not create ring buffer"}; al_free(mWaveBuffer[0].lpData); mWaveBuffer[0] = WAVEHDR{}; @@ -540,7 +544,6 @@ ALCenum WinMMCapture::open(const ALCchar *name) } mDevice->DeviceName = CaptureDevices[DeviceID]; - return ALC_NO_ERROR; } bool WinMMCapture::start() -- cgit v1.2.3 From 9b411cfcbefc0e52f4b130dbad6b52bdc3861c13 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Oct 2019 22:25:45 -0700 Subject: Reduce some indentation --- alc/backends/pulseaudio.cpp | 68 ++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index be78ee17..45e28aca 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -1321,47 +1321,51 @@ ALCenum PulseCapture::captureSamples(al::byte *buffer, ALCuint samples) mLastReadable -= static_cast(dstbuf.size()); while(!dstbuf.empty()) { - if(mCapBuffer.empty()) + if(!mCapBuffer.empty()) { - if UNLIKELY(!mDevice->Connected.load(std::memory_order_acquire)) - break; - std::lock_guard _{pulse_lock}; - const pa_stream_state_t state{pa_stream_get_state(mStream)}; - if UNLIKELY(!PA_STREAM_IS_GOOD(state)) - { - aluHandleDisconnect(mDevice, "Bad capture state: %u", state); - break; - } - const void *capbuf; - size_t caplen; - if UNLIKELY(pa_stream_peek(mStream, &capbuf, &caplen) < 0) - { - aluHandleDisconnect(mDevice, "Failed retrieving capture samples: %s", - pa_strerror(pa_context_errno(mContext))); - break; - } - if(caplen == 0) break; - if UNLIKELY(!capbuf) - mCapLen = -static_cast(caplen); + const size_t rem{minz(dstbuf.size(), mCapBuffer.size())}; + if UNLIKELY(mCapLen < 0) + std::fill_n(dstbuf.begin(), rem, mSilentVal); else - mCapLen = static_cast(caplen); - mCapBuffer = {static_cast(capbuf), caplen}; + std::copy_n(mCapBuffer.begin(), rem, dstbuf.begin()); + dstbuf = dstbuf.subspan(rem); + mCapBuffer = mCapBuffer.subspan(rem); + + continue; } - const size_t rem{minz(dstbuf.size(), mCapBuffer.size())}; - if UNLIKELY(mCapLen < 0) - std::fill_n(dstbuf.begin(), rem, mSilentVal); - else - std::copy_n(mCapBuffer.begin(), rem, dstbuf.begin()); - dstbuf = dstbuf.subspan(rem); - mCapBuffer = mCapBuffer.subspan(rem); + if UNLIKELY(!mDevice->Connected.load(std::memory_order_acquire)) + break; - if(mCapBuffer.empty()) + std::unique_lock plock{pulse_lock}; + if(mCapLen != 0) { - std::lock_guard _{pulse_lock}; pa_stream_drop(mStream); + mCapBuffer = {}; mCapLen = 0; } + const pa_stream_state_t state{pa_stream_get_state(mStream)}; + if UNLIKELY(!PA_STREAM_IS_GOOD(state)) + { + aluHandleDisconnect(mDevice, "Bad capture state: %u", state); + break; + } + const void *capbuf; + size_t caplen; + if UNLIKELY(pa_stream_peek(mStream, &capbuf, &caplen) < 0) + { + aluHandleDisconnect(mDevice, "Failed retrieving capture samples: %s", + pa_strerror(pa_context_errno(mContext))); + break; + } + plock.unlock(); + + if(caplen == 0) break; + if UNLIKELY(!capbuf) + mCapLen = -static_cast(caplen); + else + mCapLen = static_cast(caplen); + mCapBuffer = {static_cast(capbuf), caplen}; } if(!dstbuf.empty()) std::fill(dstbuf.begin(), dstbuf.end(), mSilentVal); -- cgit v1.2.3 From f0fa6c6baf673a35337d2f2cb5548dd1e33c11e7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Oct 2019 22:42:54 -0700 Subject: Fix BackendVase typo --- alc/backends/base.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alc/backends/base.cpp b/alc/backends/base.cpp index 4fce0a67..25531cf5 100644 --- a/alc/backends/base.cpp +++ b/alc/backends/base.cpp @@ -30,7 +30,7 @@ BackendBase::BackendBase(ALCdevice *device) noexcept : mDevice{device} BackendBase::~BackendBase() = default; bool BackendBase::reset() -{ throw al::backend_exception{ALC_INVALID_VALUE, "Invalid BackendVase call"}; } +{ throw al::backend_exception{ALC_INVALID_DEVICE, "Invalid BackendBase call"}; } ALCenum BackendBase::captureSamples(al::byte*, ALCuint) { return ALC_INVALID_DEVICE; } -- cgit v1.2.3 From 52a003e9bb7c870f26436b38e62edc96385805dc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Oct 2019 23:22:06 -0700 Subject: Avoid raw lock/unlock calls --- alc/backends/alsa.cpp | 12 ++++-------- alc/backends/coreaudio.cpp | 3 +-- alc/backends/dsound.cpp | 5 +++-- alc/backends/jack.cpp | 10 ++++------ alc/backends/null.cpp | 3 +-- alc/backends/opensl.cpp | 10 ++++------ alc/backends/oss.cpp | 7 +++---- alc/backends/portaudio.cpp | 3 +-- alc/backends/qsa.cpp | 7 +++---- alc/backends/sndio.cpp | 7 ++++--- alc/backends/solaris.cpp | 7 +++---- alc/backends/wasapi.cpp | 7 +++---- alc/backends/wave.cpp | 7 ++++--- alc/backends/winmm.cpp | 14 ++++++-------- 14 files changed, 44 insertions(+), 58 deletions(-) diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index 2e157602..a9eb6d5f 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -471,7 +471,7 @@ int AlsaPlayback::mixerProc() avail -= avail%update_size; // it is possible that contiguous areas are smaller, thus we use a loop - lock(); + std::lock_guard _{*this}; while(avail > 0) { snd_pcm_uframes_t frames{avail}; @@ -498,7 +498,6 @@ int AlsaPlayback::mixerProc() avail -= frames; } - unlock(); } return 0; @@ -551,7 +550,7 @@ int AlsaPlayback::mixerNoMMapProc() continue; } - lock(); + std::lock_guard _{*this}; al::byte *WritePtr{mBuffer.data()}; avail = snd_pcm_bytes_to_frames(mPcmHandle, static_cast(mBuffer.size())); aluMixData(mDevice, WritePtr, static_cast(avail)); @@ -586,7 +585,6 @@ int AlsaPlayback::mixerNoMMapProc() if(ret < 0) break; } } - unlock(); } return 0; @@ -847,7 +845,7 @@ ClockLatency AlsaPlayback::getClockLatency() { ClockLatency ret; - lock(); + std::lock_guard _{*this}; ret.ClockTime = GetDeviceClockTime(mDevice); snd_pcm_sframes_t delay{}; int err{snd_pcm_delay(mPcmHandle, &delay)}; @@ -858,7 +856,6 @@ ClockLatency AlsaPlayback::getClockLatency() } ret.Latency = std::chrono::seconds{std::max(0, delay)}; ret.Latency /= mDevice->Frequency; - unlock(); return ret; } @@ -1188,7 +1185,7 @@ ClockLatency AlsaCapture::getClockLatency() { ClockLatency ret; - lock(); + std::lock_guard _{*this}; ret.ClockTime = GetDeviceClockTime(mDevice); snd_pcm_sframes_t delay{}; int err{snd_pcm_delay(mPcmHandle, &delay)}; @@ -1199,7 +1196,6 @@ ClockLatency AlsaCapture::getClockLatency() } ret.Latency = std::chrono::seconds{std::max(0, delay)}; ret.Latency /= mDevice->Frequency; - unlock(); return ret; } diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 9254dbe0..3a97c105 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -81,9 +81,8 @@ CoreAudioPlayback::~CoreAudioPlayback() OSStatus CoreAudioPlayback::MixerProc(AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32, UInt32, AudioBufferList *ioData) { - lock(); + std::lock_guard _{*this}; aluMixData(mDevice, ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize/mFrameSize); - unlock(); return noErr; } diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index 19a3c604..d48b74e2 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -276,17 +276,18 @@ FORCE_ALIGN int DSoundPlayback::mixerProc() if(SUCCEEDED(err)) { - lock(); + std::unique_lock dlock{*this}; aluMixData(mDevice, WritePtr1, WriteCnt1/FrameSize); if(WriteCnt2 > 0) aluMixData(mDevice, WritePtr2, WriteCnt2/FrameSize); - unlock(); + dlock.unlock(); mBuffer->Unlock(WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); } else { ERR("Buffer lock error: %#lx\n", err); + std::lock_guard _{*this}; aluHandleDisconnect(mDevice, "Failed to lock output buffer: 0x%lx", err); return 1; } diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp index c7e2839c..7c3f1822 100644 --- a/alc/backends/jack.cpp +++ b/alc/backends/jack.cpp @@ -296,15 +296,15 @@ int JackPlayback::mixerProc() SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - lock(); + std::unique_lock dlock{*this}; while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) { if(mRing->writeSpace() < mDevice->UpdateSize) { - unlock(); + dlock.unlock(); mSem.wait(); - lock(); + dlock.lock(); continue; } @@ -320,7 +320,6 @@ int JackPlayback::mixerProc() aluMixData(mDevice, data.second.buf, len2); mRing->writeAdvance(todo); } - unlock(); return 0; } @@ -484,11 +483,10 @@ ClockLatency JackPlayback::getClockLatency() { ClockLatency ret; - lock(); + std::lock_guard _{*this}; ret.ClockTime = GetDeviceClockTime(mDevice); ret.Latency = std::chrono::seconds{mRing->readSpace()}; ret.Latency /= mDevice->Frequency; - unlock(); return ret; } diff --git a/alc/backends/null.cpp b/alc/backends/null.cpp index aca59605..bc2a0c9c 100644 --- a/alc/backends/null.cpp +++ b/alc/backends/null.cpp @@ -86,9 +86,8 @@ int NullBackend::mixerProc() } while(avail-done >= mDevice->UpdateSize) { - lock(); + std::lock_guard _{*this}; aluMixData(mDevice, nullptr, mDevice->UpdateSize); - unlock(); done += mDevice->UpdateSize; } diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index 4e4ceb5b..f546f168 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -228,7 +228,7 @@ int OpenSLPlayback::mixerProc() PRINTERR(result, "bufferQueue->GetInterface SL_IID_PLAY"); } - lock(); + std::unique_lock dlock{*this}; if(SL_RESULT_SUCCESS != result) aluHandleDisconnect(mDevice, "Failed to get playback buffer: 0x%08x", result); @@ -254,9 +254,9 @@ int OpenSLPlayback::mixerProc() if(mRing->writeSpace() == 0) { - unlock(); + dlock.unlock(); mSem.wait(); - lock(); + dlock.lock(); continue; } } @@ -292,7 +292,6 @@ int OpenSLPlayback::mixerProc() data.first.buf += mDevice->UpdateSize*mFrameSize; } } - unlock(); return 0; } @@ -617,11 +616,10 @@ ClockLatency OpenSLPlayback::getClockLatency() { ClockLatency ret; - lock(); + std::lock_guard _{*this}; ret.ClockTime = GetDeviceClockTime(mDevice); ret.Latency = std::chrono::seconds{mRing->readSpace() * mDevice->UpdateSize}; ret.Latency /= mDevice->Frequency; - unlock(); return ret; } diff --git a/alc/backends/oss.cpp b/alc/backends/oss.cpp index 1e3ad28b..5ab07dbe 100644 --- a/alc/backends/oss.cpp +++ b/alc/backends/oss.cpp @@ -279,7 +279,7 @@ int OSSPlayback::mixerProc() const ALuint frame_size{mDevice->frameSizeFromFmt()}; - lock(); + std::unique_lock dlock{*this}; while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) { @@ -287,9 +287,9 @@ int OSSPlayback::mixerProc() pollitem.fd = mFd; pollitem.events = POLLOUT; - unlock(); + dlock.unlock(); int pret{poll(&pollitem, 1, 1000)}; - lock(); + dlock.lock(); if(pret < 0) { if(errno == EINTR || errno == EAGAIN) @@ -324,7 +324,6 @@ int OSSPlayback::mixerProc() write_ptr += wrote; } } - unlock(); return 0; } diff --git a/alc/backends/portaudio.cpp b/alc/backends/portaudio.cpp index 7847f41d..ba8e4984 100644 --- a/alc/backends/portaudio.cpp +++ b/alc/backends/portaudio.cpp @@ -110,9 +110,8 @@ int PortPlayback::writeCallback(const void*, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo*, const PaStreamCallbackFlags) { - lock(); + std::lock_guard _{*this}; aluMixData(mDevice, outputBuffer, static_cast(framesPerBuffer)); - unlock(); return 0; } diff --git a/alc/backends/qsa.cpp b/alc/backends/qsa.cpp index 872a8541..5ed65798 100644 --- a/alc/backends/qsa.cpp +++ b/alc/backends/qsa.cpp @@ -207,7 +207,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) const ALint frame_size = device->frameSizeFromFmt(); - self->lock(); + std::unique_lock dlock{*self}; while(!data->mKillNow.load(std::memory_order_acquire)) { pollfd pollitem{}; @@ -215,9 +215,9 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) pollitem.events = POLLOUT; /* Select also works like time slice to OS */ - self->unlock(); + dlock.unlock(); sret = poll(&pollitem, 1, 2000); - self->lock(); + dlock.lock(); if(sret == -1) { if(errno == EINTR || errno == EAGAIN) @@ -266,7 +266,6 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) } } } - self->unlock(); return 0; } diff --git a/alc/backends/sndio.cpp b/alc/backends/sndio.cpp index e0c70762..5657a241 100644 --- a/alc/backends/sndio.cpp +++ b/alc/backends/sndio.cpp @@ -85,9 +85,10 @@ int SndioPlayback::mixerProc() ALubyte *WritePtr{mBuffer.data()}; size_t len{mBuffer.size()}; - lock(); - aluMixData(mDevice, WritePtr, static_cast(len/frameSize)); - unlock(); + { + std::lock_guard _{*this}; + aluMixData(mDevice, WritePtr, static_cast(len/frameSize)); + } while(len > 0 && !mKillNow.load(std::memory_order_acquire)) { size_t wrote{sio_write(mSndHandle, WritePtr, len)}; diff --git a/alc/backends/solaris.cpp b/alc/backends/solaris.cpp index 5963a4b2..79cc224d 100644 --- a/alc/backends/solaris.cpp +++ b/alc/backends/solaris.cpp @@ -91,7 +91,7 @@ int SolarisBackend::mixerProc() const ALuint frame_size{mDevice->frameSizeFromFmt()}; - lock(); + std::unique_lock dlock{*this}; while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) { @@ -99,9 +99,9 @@ int SolarisBackend::mixerProc() pollitem.fd = mFd; pollitem.events = POLLOUT; - unlock(); + dlock.unlock(); int pret{poll(&pollitem, 1, 1000)}; - lock(); + dlock.lock(); if(pret < 0) { if(errno == EINTR || errno == EAGAIN) @@ -137,7 +137,6 @@ int SolarisBackend::mixerProc() write_ptr += wrote; } } - unlock(); return 0; } diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index b6f5b5fb..181518d0 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -689,10 +689,10 @@ FORCE_ALIGN int WasapiPlayback::mixerProc() hr = mRender->GetBuffer(len, &buffer); if(SUCCEEDED(hr)) { - lock(); + std::unique_lock dlock{*this}; aluMixData(mDevice, buffer, len); mPadding.store(written + len, std::memory_order_relaxed); - unlock(); + dlock.unlock(); hr = mRender->ReleaseBuffer(len, 0); } if(FAILED(hr)) @@ -1136,11 +1136,10 @@ ClockLatency WasapiPlayback::getClockLatency() { ClockLatency ret; - lock(); + std::lock_guard _{*this}; ret.ClockTime = GetDeviceClockTime(mDevice); ret.Latency = std::chrono::seconds{mPadding.load(std::memory_order_relaxed)}; ret.Latency /= mDevice->Frequency; - unlock(); return ret; } diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp index 927cb276..3b0a30d8 100644 --- a/alc/backends/wave.cpp +++ b/alc/backends/wave.cpp @@ -145,9 +145,10 @@ int WaveBackend::mixerProc() } while(avail-done >= mDevice->UpdateSize) { - lock(); - aluMixData(mDevice, mBuffer.data(), mDevice->UpdateSize); - unlock(); + { + std::lock_guard _{*this}; + aluMixData(mDevice, mBuffer.data(), mDevice->UpdateSize); + } done += mDevice->UpdateSize; if(!IS_LITTLE_ENDIAN) diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp index c287e136..8f85f351 100644 --- a/alc/backends/winmm.cpp +++ b/alc/backends/winmm.cpp @@ -183,16 +183,16 @@ FORCE_ALIGN int WinMMPlayback::mixerProc() SetRTPriority(); althrd_setname(MIXER_THREAD_NAME); - lock(); + std::unique_lock dlock{*this}; while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) { ALsizei todo = mWritable.load(std::memory_order_acquire); if(todo < 1) { - unlock(); + dlock.unlock(); mSem.wait(); - lock(); + dlock.lock(); continue; } @@ -207,7 +207,6 @@ FORCE_ALIGN int WinMMPlayback::mixerProc() } while(--todo); mIdx = static_cast(widx); } - unlock(); return 0; } @@ -427,16 +426,16 @@ int WinMMCapture::captureProc() { althrd_setname(RECORD_THREAD_NAME); - lock(); + std::unique_lock dlock{*this}; while(!mKillNow.load(std::memory_order_acquire) && mDevice->Connected.load(std::memory_order_acquire)) { ALuint todo{mReadable.load(std::memory_order_acquire)}; if(todo < 1) { - unlock(); + dlock.unlock(); mSem.wait(); - lock(); + dlock.lock(); continue; } @@ -451,7 +450,6 @@ int WinMMCapture::captureProc() } while(--todo); mIdx = static_cast(widx); } - unlock(); return 0; } -- cgit v1.2.3 From f4bc3d7ab22b90f725b7e80fbf2cb879b4729ed8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 8 Oct 2019 00:21:21 -0700 Subject: Improve logging for Windows --- alc/helpers.cpp | 2 +- alc/logging.h | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/alc/helpers.cpp b/alc/helpers.cpp index 2d532db1..0e2dc067 100644 --- a/alc/helpers.cpp +++ b/alc/helpers.cpp @@ -305,7 +305,7 @@ void al_print(FILE *logfile, const char *fmt, ...) va_end(args); std::wstring wstr{utf8_to_wstr(str)}; - fprintf(logfile, "%ls", wstr.c_str()); + fputws(wstr.c_str(), logfile); fflush(logfile); } diff --git a/alc/logging.h b/alc/logging.h index 24cfda71..ec6023a5 100644 --- a/alc/logging.h +++ b/alc/logging.h @@ -17,9 +17,9 @@ extern FILE *gLogFile; void al_print(FILE *logfile, const char *fmt, ...) DECL_FORMAT(printf, 2,3); #if !defined(_WIN32) -#define AL_PRINT(T, ...) fprintf(gLogFile, "AL lib: " T " " __VA_ARGS__) +#define AL_PRINT fprintf #else -#define AL_PRINT(T, ...) al_print(gLogFile, "AL lib: " T " " __VA_ARGS__) +#define AL_PRINT al_print #endif #ifdef __ANDROID__ @@ -40,19 +40,19 @@ extern LogLevel gLogLevel; #define TRACE(...) do { \ if UNLIKELY(gLogLevel >= LogTrace) \ - AL_PRINT("(II)", __VA_ARGS__); \ + AL_PRINT(gLogFile, "AL lib: (II) " __VA_ARGS__); \ LOG_ANDROID(ANDROID_LOG_DEBUG, __VA_ARGS__); \ } while(0) #define WARN(...) do { \ if UNLIKELY(gLogLevel >= LogWarning) \ - AL_PRINT("(WW)", __VA_ARGS__); \ + AL_PRINT(gLogFile, "AL lib: (WW) " __VA_ARGS__); \ LOG_ANDROID(ANDROID_LOG_WARN, __VA_ARGS__); \ } while(0) #define ERR(...) do { \ if UNLIKELY(gLogLevel >= LogError) \ - AL_PRINT("(EE)", __VA_ARGS__); \ + AL_PRINT(gLogFile, "AL lib: (EE) " __VA_ARGS__); \ LOG_ANDROID(ANDROID_LOG_ERROR, __VA_ARGS__); \ } while(0) -- cgit v1.2.3 From 360330b2add6cf10776c38aaa186b0892b54e300 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 8 Oct 2019 03:41:49 -0700 Subject: Define some simple wrapper methods inline --- alc/backends/pulseaudio.cpp | 93 +++++++++++++++------------------------------ 1 file changed, 30 insertions(+), 63 deletions(-) diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 45e28aca..e4b1baa2 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -642,34 +642,41 @@ struct PulsePlayback final : public BackendBase { PulsePlayback(ALCdevice *device) noexcept : BackendBase{device} { } ~PulsePlayback() override; - static void bufferAttrCallbackC(pa_stream *stream, void *pdata); void bufferAttrCallback(pa_stream *stream); + static void bufferAttrCallbackC(pa_stream *stream, void *pdata) + { static_cast(pdata)->bufferAttrCallback(stream); } - static void contextStateCallbackC(pa_context *context, void *pdata); void contextStateCallback(pa_context *context); + static void contextStateCallbackC(pa_context *context, void *pdata) + { static_cast(pdata)->contextStateCallback(context); } - static void streamStateCallbackC(pa_stream *stream, void *pdata); void streamStateCallback(pa_stream *stream); + static void streamStateCallbackC(pa_stream *stream, void *pdata) + { static_cast(pdata)->streamStateCallback(stream); } - static void streamWriteCallbackC(pa_stream *stream, size_t nbytes, void *pdata); void streamWriteCallback(pa_stream *stream, size_t nbytes); + static void streamWriteCallbackC(pa_stream *stream, size_t nbytes, void *pdata) + { static_cast(pdata)->streamWriteCallback(stream, nbytes); } - static void sinkInfoCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata); void sinkInfoCallback(pa_context *context, const pa_sink_info *info, int eol); + static void sinkInfoCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata) + { static_cast(pdata)->sinkInfoCallback(context, info, eol); } - static void sinkNameCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata); void sinkNameCallback(pa_context *context, const pa_sink_info *info, int eol); + static void sinkNameCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata) + { static_cast(pdata)->sinkNameCallback(context, info, eol); } - static void streamMovedCallbackC(pa_stream *stream, void *pdata); void streamMovedCallback(pa_stream *stream); + static void streamMovedCallbackC(pa_stream *stream, void *pdata) + { static_cast(pdata)->streamMovedCallback(stream); } void open(const ALCchar *name) override; bool reset() override; bool start() override; void stop() override; ClockLatency getClockLatency() override; - void lock() override; - void unlock() override; + void lock() override { pulse_lock.lock(); } + void unlock() override { pulse_lock.unlock(); } std::string mDeviceName; @@ -695,9 +702,6 @@ PulsePlayback::~PulsePlayback() } -void PulsePlayback::bufferAttrCallbackC(pa_stream *stream, void *pdata) -{ static_cast(pdata)->bufferAttrCallback(stream); } - void PulsePlayback::bufferAttrCallback(pa_stream *stream) { /* FIXME: Update the device's UpdateSize (and/or BufferSize) using the new @@ -709,9 +713,6 @@ void PulsePlayback::bufferAttrCallback(pa_stream *stream) TRACE("minreq=%d, tlength=%d, prebuf=%d\n", mAttr.minreq, mAttr.tlength, mAttr.prebuf); } -void PulsePlayback::contextStateCallbackC(pa_context *context, void *pdata) -{ static_cast(pdata)->contextStateCallback(context); } - void PulsePlayback::contextStateCallback(pa_context *context) { if(pa_context_get_state(context) == PA_CONTEXT_FAILED) @@ -722,9 +723,6 @@ void PulsePlayback::contextStateCallback(pa_context *context) pulse_condvar.notify_all(); } -void PulsePlayback::streamStateCallbackC(pa_stream *stream, void *pdata) -{ static_cast(pdata)->streamStateCallback(stream); } - void PulsePlayback::streamStateCallback(pa_stream *stream) { if(pa_stream_get_state(stream) == PA_STREAM_FAILED) @@ -735,9 +733,6 @@ void PulsePlayback::streamStateCallback(pa_stream *stream) pulse_condvar.notify_all(); } -void PulsePlayback::streamWriteCallbackC(pa_stream *stream, size_t nbytes, void *pdata) -{ static_cast(pdata)->streamWriteCallback(stream, nbytes); } - void PulsePlayback::streamWriteCallback(pa_stream *stream, size_t nbytes) { void *buf{pa_xmalloc(nbytes)}; @@ -748,9 +743,6 @@ void PulsePlayback::streamWriteCallback(pa_stream *stream, size_t nbytes) ERR("Failed to write to stream: %d, %s\n", ret, pa_strerror(ret)); } -void PulsePlayback::sinkInfoCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata) -{ static_cast(pdata)->sinkInfoCallback(context, info, eol); } - void PulsePlayback::sinkInfoCallback(pa_context*, const pa_sink_info *info, int eol) { struct ChannelMap { @@ -795,9 +787,6 @@ void PulsePlayback::sinkInfoCallback(pa_context*, const pa_sink_info *info, int info->active_port && strcmp(info->active_port->name, "analog-output-headphones") == 0); } -void PulsePlayback::sinkNameCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata) -{ static_cast(pdata)->sinkNameCallback(context, info, eol); } - void PulsePlayback::sinkNameCallback(pa_context*, const pa_sink_info *info, int eol) { if(eol) @@ -808,9 +797,6 @@ void PulsePlayback::sinkNameCallback(pa_context*, const pa_sink_info *info, int mDevice->DeviceName = info->description; } -void PulsePlayback::streamMovedCallbackC(pa_stream *stream, void *pdata) -{ static_cast(pdata)->streamMovedCallback(stream); } - void PulsePlayback::streamMovedCallback(pa_stream *stream) { mDeviceName = pa_stream_get_device_name(stream); @@ -1058,7 +1044,8 @@ ClockLatency PulsePlayback::getClockLatency() pa_usec_t latency; int neg, err; - { std::lock_guard _{pulse_lock}; + { + std::lock_guard _{pulse_lock}; ret.ClockTime = GetDeviceClockTime(mDevice); err = pa_stream_get_latency(mStream, &latency, &neg); } @@ -1082,28 +1069,25 @@ ClockLatency PulsePlayback::getClockLatency() } -void PulsePlayback::lock() -{ pulse_lock.lock(); } - -void PulsePlayback::unlock() -{ pulse_lock.unlock(); } - - struct PulseCapture final : public BackendBase { PulseCapture(ALCdevice *device) noexcept : BackendBase{device} { } ~PulseCapture() override; - static void contextStateCallbackC(pa_context *context, void *pdata); void contextStateCallback(pa_context *context); + static void contextStateCallbackC(pa_context *context, void *pdata) + { static_cast(pdata)->contextStateCallback(context); } - static void streamStateCallbackC(pa_stream *stream, void *pdata); void streamStateCallback(pa_stream *stream); + static void streamStateCallbackC(pa_stream *stream, void *pdata) + { static_cast(pdata)->streamStateCallback(stream); } - static void sourceNameCallbackC(pa_context *context, const pa_source_info *info, int eol, void *pdata); void sourceNameCallback(pa_context *context, const pa_source_info *info, int eol); + static void sourceNameCallbackC(pa_context *context, const pa_source_info *info, int eol, void *pdata) + { static_cast(pdata)->sourceNameCallback(context, info, eol); } - static void streamMovedCallbackC(pa_stream *stream, void *pdata); void streamMovedCallback(pa_stream *stream); + static void streamMovedCallbackC(pa_stream *stream, void *pdata) + { static_cast(pdata)->streamMovedCallback(stream); } void open(const ALCchar *name) override; bool start() override; @@ -1111,8 +1095,8 @@ struct PulseCapture final : public BackendBase { ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; ALCuint availableSamples() override; ClockLatency getClockLatency() override; - void lock() override; - void unlock() override; + void lock() override { pulse_lock.lock(); } + void unlock() override { pulse_lock.unlock(); } std::string mDeviceName; @@ -1141,8 +1125,6 @@ PulseCapture::~PulseCapture() mStream = nullptr; } -void PulseCapture::contextStateCallbackC(pa_context *context, void *pdata) -{ static_cast(pdata)->contextStateCallback(context); } void PulseCapture::contextStateCallback(pa_context *context) { @@ -1154,9 +1136,6 @@ void PulseCapture::contextStateCallback(pa_context *context) pulse_condvar.notify_all(); } -void PulseCapture::streamStateCallbackC(pa_stream *stream, void *pdata) -{ static_cast(pdata)->streamStateCallback(stream); } - void PulseCapture::streamStateCallback(pa_stream *stream) { if(pa_stream_get_state(stream) == PA_STREAM_FAILED) @@ -1167,9 +1146,6 @@ void PulseCapture::streamStateCallback(pa_stream *stream) pulse_condvar.notify_all(); } -void PulseCapture::sourceNameCallbackC(pa_context *context, const pa_source_info *info, int eol, void *pdata) -{ static_cast(pdata)->sourceNameCallback(context, info, eol); } - void PulseCapture::sourceNameCallback(pa_context*, const pa_source_info *info, int eol) { if(eol) @@ -1180,9 +1156,6 @@ void PulseCapture::sourceNameCallback(pa_context*, const pa_source_info *info, i mDevice->DeviceName = info->description; } -void PulseCapture::streamMovedCallbackC(pa_stream *stream, void *pdata) -{ static_cast(pdata)->streamMovedCallback(stream); } - void PulseCapture::streamMovedCallback(pa_stream *stream) { mDeviceName = pa_stream_get_device_name(stream); @@ -1406,7 +1379,8 @@ ClockLatency PulseCapture::getClockLatency() pa_usec_t latency; int neg, err; - { std::lock_guard _{pulse_lock}; + { + std::lock_guard _{pulse_lock}; ret.ClockTime = GetDeviceClockTime(mDevice); err = pa_stream_get_latency(mStream, &latency, &neg); } @@ -1424,13 +1398,6 @@ ClockLatency PulseCapture::getClockLatency() return ret; } - -void PulseCapture::lock() -{ pulse_lock.lock(); } - -void PulseCapture::unlock() -{ pulse_lock.unlock(); } - } // namespace -- cgit v1.2.3 From 7726a06d26e59dc6a8e109af2e268de878c4f606 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 8 Oct 2019 05:44:38 -0700 Subject: Clean up some exception messages and avoid duplicate log messages --- alc/backends/alsa.cpp | 16 +++----------- alc/backends/coreaudio.cpp | 54 ++------------------------------------------- alc/backends/dsound.cpp | 5 ----- alc/backends/jack.cpp | 6 ++--- alc/backends/opensl.cpp | 12 +++++----- alc/backends/oss.cpp | 46 +++++++++----------------------------- alc/backends/portaudio.cpp | 5 ----- alc/backends/pulseaudio.cpp | 2 +- alc/backends/sdl2.cpp | 12 ++++------ alc/backends/sndio.cpp | 47 +++++++++++---------------------------- alc/backends/solaris.cpp | 3 --- alc/backends/wasapi.cpp | 2 -- alc/backends/wave.cpp | 3 --- alc/backends/winmm.cpp | 17 ++++---------- 14 files changed, 46 insertions(+), 184 deletions(-) diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index a9eb6d5f..7c6ce4f9 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -616,11 +616,8 @@ void AlsaPlayback::open(const ALCchar *name) TRACE("Opening device \"%s\"\n", driver); int err{snd_pcm_open(&mPcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)}; if(err < 0) - { - ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(err)); - throw al::backend_exception{ALC_OUT_OF_MEMORY, "Could not open ALSA playback \"%s\"", + throw al::backend_exception{ALC_OUT_OF_MEMORY, "Could not open ALSA device \"%s\"", driver}; - } /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */ snd_config_update_free_global(); @@ -917,11 +914,8 @@ void AlsaCapture::open(const ALCchar *name) TRACE("Opening device \"%s\"\n", driver); int err{snd_pcm_open(&mPcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)}; if(err < 0) - { - ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err)); - throw al::backend_exception{ALC_OUT_OF_MEMORY, "Could not open ALSA capture \"%s\"", + throw al::backend_exception{ALC_OUT_OF_MEMORY, "Could not open ALSA device \"%s\"", driver}; - } /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */ snd_config_update_free_global(); @@ -989,11 +983,7 @@ void AlsaCapture::open(const ALCchar *name) if(needring) { mRing = CreateRingBuffer(mDevice->BufferSize, mDevice->frameSizeFromFmt(), false); - if(!mRing) - { - ERR("ring buffer create failed\n"); - throw al::backend_exception{ALC_INVALID_VALUE, "Failed to create ring buffer"}; - } + if(!mRing) throw al::backend_exception{ALC_INVALID_VALUE, "Failed to create ring buffer"}; } mDevice->DeviceName = name; diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 3a97c105..9e1d4e47 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -108,26 +108,17 @@ void CoreAudioPlayback::open(const ALCchar *name) AudioComponent comp{AudioComponentFindNext(NULL, &desc)}; if(comp == nullptr) - { - ERR("AudioComponentFindNext failed\n"); throw al::backend_exception{ALC_INVALID_VALUE, "Could not find audio component"}; - } OSStatus err{AudioComponentInstanceNew(comp, &mAudioUnit)}; if(err != noErr) - { - ERR("AudioComponentInstanceNew failed\n"); throw al::backend_exception{ALC_INVALID_VALUE, "Could not create component instance: %u", err}; - } /* init and start the default audio unit... */ err = AudioUnitInitialize(mAudioUnit); if(err != noErr) - { - ERR("AudioUnitInitialize failed\n"); throw al::backend_exception{ALC_INVALID_VALUE, "Could not initialize audio unit: %u", err}; - } mDevice->DeviceName = name; } @@ -418,41 +409,29 @@ void CoreAudioCapture::open(const ALCchar *name) // Search for component with given description comp = AudioComponentFindNext(NULL, &desc); if(comp == NULL) - { - ERR("AudioComponentFindNext failed\n"); - throw al::backend_exception{ALC_INVALID_VALUE, "Could not finda udio component"}; - } + throw al::backend_exception{ALC_INVALID_VALUE, "Could not find audio component"}; // Open the component err = AudioComponentInstanceNew(comp, &mAudioUnit); if(err != noErr) - { - ERR("AudioComponentInstanceNew failed\n"); throw al::backend_exception{ALC_INVALID_VALUE, "Could not create component instance: %u", err}; - } // Turn off AudioUnit output enableIO = 0; err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint)); if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); throw al::backend_exception{ALC_INVALID_VALUE, "Could not disable audio unit output property: %u", err}; - } // Turn on AudioUnit input enableIO = 1; err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint)); if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); throw al::backend_exception{ALC_INVALID_VALUE, "Could not enable audio unit input property: %u", err}; - } #if !TARGET_OS_IOS { @@ -467,24 +446,15 @@ void CoreAudioCapture::open(const ALCchar *name) err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, nullptr, &propertySize, &inputDevice); if(err != noErr) - { - ERR("AudioObjectGetPropertyData failed\n"); throw al::backend_exception{ALC_INVALID_VALUE, "Could not get input device: %u", err}; - } if(inputDevice == kAudioDeviceUnknown) - { - ERR("No input device found\n"); throw al::backend_exception{ALC_INVALID_VALUE, "Unknown input device"}; - } // Track the input device err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID)); if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); throw al::backend_exception{ALC_INVALID_VALUE, "Could not set input device: %u", err}; - } } #endif @@ -495,28 +465,19 @@ void CoreAudioCapture::open(const ALCchar *name) err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct)); if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); throw al::backend_exception{ALC_INVALID_VALUE, "Could not set capture callback: %u", err}; - } // Initialize the device err = AudioUnitInitialize(mAudioUnit); if(err != noErr) - { - ERR("AudioUnitInitialize failed\n"); throw al::backend_exception{ALC_INVALID_VALUE, "Could not initialize audio unit: %u", err}; - } // Get the hardware format propertySize = sizeof(AudioStreamBasicDescription); err = AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize); if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription)) - { - ERR("AudioUnitGetProperty failed\n"); throw al::backend_exception{ALC_INVALID_VALUE, "Could not get input format: %u", err}; - } // Set up the requested format description switch(mDevice->FmtType) @@ -540,7 +501,6 @@ void CoreAudioCapture::open(const ALCchar *name) case DevFmtByte: case DevFmtUShort: case DevFmtUInt: - ERR("%s samples not supported\n", DevFmtTypeString(mDevice->FmtType)); throw al::backend_exception{ALC_INVALID_VALUE, "%s samples not suppoted", DevFmtTypeString(mDevice->FmtType)}; } @@ -560,7 +520,6 @@ void CoreAudioCapture::open(const ALCchar *name) case DevFmtX61: case DevFmtX71: case DevFmtAmbi3D: - ERR("%s not supported\n", DevFmtChannelsString(mDevice->FmtChans)); throw al::backend_exception{ALC_INVALID_VALUE, "%s not supported", DevFmtChannelsString(mDevice->FmtChans)}; } @@ -586,10 +545,7 @@ void CoreAudioCapture::open(const ALCchar *name) err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &outputFormat, sizeof(outputFormat)); if(err != noErr) - { - ERR("AudioUnitSetProperty failed\n"); throw al::backend_exception{ALC_INVALID_VALUE, "Could not set input format: %u", err}; - } // Set the AudioUnit output format frame count uint64_t FrameCount64{mDevice->UpdateSize}; @@ -597,21 +553,15 @@ void CoreAudioCapture::open(const ALCchar *name) mDevice->Frequency; FrameCount64 += MAX_RESAMPLER_PADDING; if(FrameCount64 > std::numeric_limits::max()/2) - { - ERR("FrameCount too large\n"); throw al::backend_exception{ALC_INVALID_VALUE, - "Calculated frame count is too lareg: %" PRIu64, FrameCount64}; - } + "Calculated frame count is too large: %" PRIu64, FrameCount64}; outputFrameCount = static_cast(FrameCount64); err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount)); if(err != noErr) - { - ERR("AudioUnitSetProperty failed: %d\n", err); throw al::backend_exception{ALC_INVALID_VALUE, "Failed to set capture frame count: %u", err}; - } // Set up sample converter if needed if(outputFormat.mSampleRate != mDevice->Frequency) diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index d48b74e2..005c9584 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -341,10 +341,7 @@ void DSoundPlayback::open(const ALCchar *name) if(SUCCEEDED(hr)) hr = mDS->SetCooperativeLevel(GetForegroundWindow(), DSSCL_PRIORITY); if(FAILED(hr)) - { - ERR("Device init failed: 0x%08lx\n", hr); throw al::backend_exception{ALC_INVALID_VALUE, "Device init failed: 0x%08lx", hr}; - } mDevice->DeviceName = name; } @@ -753,8 +750,6 @@ void DSoundCapture::open(const ALCchar *name) if(FAILED(hr)) { - ERR("Device init failed: 0x%08lx\n", hr); - mRing = nullptr; if(mDSCbuffer) mDSCbuffer->Release(); diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp index 7c3f1822..2a22ed84 100644 --- a/alc/backends/jack.cpp +++ b/alc/backends/jack.cpp @@ -336,11 +336,9 @@ void JackPlayback::open(const ALCchar *name) jack_status_t status; mClient = jack_client_open(client_name, ClientOptions, &status, nullptr); if(mClient == nullptr) - { - ERR("jack_client_open() failed, status = 0x%02x\n", status); - throw al::backend_exception{ALC_INVALID_VALUE, "Failed to connect to JACK server: 0x%02x", + throw al::backend_exception{ALC_INVALID_VALUE, "Failed to open client connection: 0x%02x", status}; - } + if((status&JackServerStarted)) TRACE("JACK server started\n"); if((status&JackNameNotUnique)) diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index f546f168..4e68da27 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -146,9 +146,9 @@ struct OpenSLPlayback final : public BackendBase { OpenSLPlayback(ALCdevice *device) noexcept : BackendBase{device} { } ~OpenSLPlayback() override; + void process(SLAndroidSimpleBufferQueueItf bq); static void processC(SLAndroidSimpleBufferQueueItf bq, void *context) { static_cast(context)->process(bq); } - void process(SLAndroidSimpleBufferQueueItf bq); int mixerProc(); @@ -339,8 +339,8 @@ void OpenSLPlayback::open(const ALCchar *name) mEngineObj = nullptr; mEngine = nullptr; - throw al::backend_exception{ALC_INVALID_VALUE, "Failed to initialize OpenSL: 0x%08x", - result}; + throw al::backend_exception{ALC_INVALID_VALUE, + "Failed to initialize OpenSL device: 0x%08x", result}; } mDevice->DeviceName = name; @@ -629,9 +629,9 @@ struct OpenSLCapture final : public BackendBase { OpenSLCapture(ALCdevice *device) noexcept : BackendBase{device} { } ~OpenSLCapture() override; + void process(SLAndroidSimpleBufferQueueItf bq); static void processC(SLAndroidSimpleBufferQueueItf bq, void *context) { static_cast(context)->process(bq); } - void process(SLAndroidSimpleBufferQueueItf bq); void open(const ALCchar *name) override; bool start() override; @@ -839,8 +839,8 @@ void OpenSLCapture::open(const ALCchar* name) mEngineObj = nullptr; mEngine = nullptr; - throw al::backend_exception{ALC_INVALID_VALUE, "Failed to initialize OpenSL: 0x%08x", - result}; + throw al::backend_exception{ALC_INVALID_VALUE, + "Failed to initialize OpenSL device: 0x%08x", result}; } mDevice->DeviceName = name; diff --git a/alc/backends/oss.cpp b/alc/backends/oss.cpp index 5ab07dbe..856aceb0 100644 --- a/alc/backends/oss.cpp +++ b/alc/backends/oss.cpp @@ -350,11 +350,8 @@ void OSSPlayback::open(const ALCchar *name) mFd = ::open(devname, O_WRONLY); if(mFd == -1) - { - ERR("Could not open %s: %s\n", devname, strerror(errno)); throw al::backend_exception{ALC_INVALID_VALUE, "Could not open %s: %s", devname, strerror(errno)}; - } mDevice->DeviceName = name; } @@ -560,11 +557,8 @@ void OSScapture::open(const ALCchar *name) mFd = ::open(devname, O_RDONLY); if(mFd == -1) - { - ERR("Could not open %s: %s\n", devname, strerror(errno)); throw al::backend_exception{ALC_INVALID_VALUE, "Could not open %s: %s", devname, strerror(errno)}; - } int ossFormat{}; switch(mDevice->FmtType) @@ -582,7 +576,6 @@ void OSScapture::open(const ALCchar *name) case DevFmtInt: case DevFmtUInt: case DevFmtFloat: - ERR("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", DevFmtTypeString(mDevice->FmtType)}; } @@ -596,47 +589,30 @@ void OSScapture::open(const ALCchar *name) ALuint numFragmentsLogSize{(periods << 16) | log2FragmentSize}; audio_buf_info info{}; - const char *err; #define CHECKERR(func) if((func) < 0) { \ - err = #func; \ - goto err; \ + throw al::backend_exception{ALC_INVALID_VALUE, #func " failed: %s", strerror(errno)}; \ } CHECKERR(ioctl(mFd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize)); CHECKERR(ioctl(mFd, SNDCTL_DSP_SETFMT, &ossFormat)); CHECKERR(ioctl(mFd, SNDCTL_DSP_CHANNELS, &numChannels)); CHECKERR(ioctl(mFd, SNDCTL_DSP_SPEED, &ossSpeed)); CHECKERR(ioctl(mFd, SNDCTL_DSP_GETISPACE, &info)); - if(0) - { - err: - ERR("%s failed: %s\n", err, strerror(errno)); - throw al::backend_exception{ALC_INVALID_VALUE, "%s failed: %s", err, strerror(errno)}; - } #undef CHECKERR if(mDevice->channelsFromFmt() != numChannels) - { - ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(mDevice->FmtChans), - numChannels); - throw al::backend_exception{ALC_INVALID_VALUE, "Failed to set %s capture", - DevFmtChannelsString(mDevice->FmtChans)}; - } + throw al::backend_exception{ALC_INVALID_VALUE, + "Failed to set %s, got %d channels instead", DevFmtChannelsString(mDevice->FmtChans), + numChannels}; - if(!((ossFormat == AFMT_S8 && mDevice->FmtType == DevFmtByte) || - (ossFormat == AFMT_U8 && mDevice->FmtType == DevFmtUByte) || - (ossFormat == AFMT_S16_NE && mDevice->FmtType == DevFmtShort))) - { - ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(mDevice->FmtType), ossFormat); - throw al::backend_exception{ALC_INVALID_VALUE, "Failed to set %s samples", - DevFmtTypeString(mDevice->FmtType)}; - } + if(!((ossFormat == AFMT_S8 && mDevice->FmtType == DevFmtByte) + || (ossFormat == AFMT_U8 && mDevice->FmtType == DevFmtUByte) + || (ossFormat == AFMT_S16_NE && mDevice->FmtType == DevFmtShort))) + throw al::backend_exception{ALC_INVALID_VALUE, + "Failed to set %s samples, got OSS format %#x", DevFmtTypeString(mDevice->FmtType), + ossFormat}; mRing = CreateRingBuffer(mDevice->BufferSize, frameSize, false); - if(!mRing) - { - ERR("Ring buffer create failed\n"); - throw al::backend_exception{ALC_INVALID_VALUE, "Failed to create ring buffer"}; - } + if(!mRing) throw al::backend_exception{ALC_INVALID_VALUE, "Failed to create ring buffer"}; mDevice->DeviceName = name; } diff --git a/alc/backends/portaudio.cpp b/alc/backends/portaudio.cpp index ba8e4984..7c60d2bb 100644 --- a/alc/backends/portaudio.cpp +++ b/alc/backends/portaudio.cpp @@ -166,7 +166,6 @@ retry_open: mParams.sampleFormat = paInt16; goto retry_open; } - ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); throw al::backend_exception{ALC_INVALID_VALUE, "Failed to open stream: %s", Pa_GetErrorText(err)}; } @@ -314,7 +313,6 @@ void PortCapture::open(const ALCchar *name) break; case DevFmtUInt: case DevFmtUShort: - ERR("%s samples not supported\n", DevFmtTypeString(mDevice->FmtType)); throw al::backend_exception{ALC_INVALID_VALUE, "%s samples not supported", DevFmtTypeString(mDevice->FmtType)}; } @@ -323,11 +321,8 @@ void PortCapture::open(const ALCchar *name) PaError err{Pa_OpenStream(&mStream, &mParams, nullptr, mDevice->Frequency, paFramesPerBufferUnspecified, paNoFlag, &PortCapture::readCallbackC, this)}; if(err != paNoError) - { - ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); throw al::backend_exception{ALC_INVALID_VALUE, "Failed to open stream: %s", Pa_GetErrorText(err)}; - } mDevice->DeviceName = name; } diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index e4b1baa2..2521084d 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -1211,7 +1211,7 @@ void PulseCapture::open(const ALCchar *name) chanmap = X71ChanMap; break; case DevFmtAmbi3D: - throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", + throw al::backend_exception{ALC_INVALID_VALUE, "%s capture not supported", DevFmtChannelsString(mDevice->FmtChans)}; } SetChannelOrderFromMap(mDevice, chanmap); diff --git a/alc/backends/sdl2.cpp b/alc/backends/sdl2.cpp index 1063ca7a..4cdf05b4 100644 --- a/alc/backends/sdl2.cpp +++ b/alc/backends/sdl2.cpp @@ -52,8 +52,9 @@ struct Sdl2Backend final : public BackendBase { Sdl2Backend(ALCdevice *device) noexcept : BackendBase{device} { } ~Sdl2Backend() override; - static void audioCallbackC(void *ptr, Uint8 *stream, int len); void audioCallback(Uint8 *stream, int len); + static void audioCallbackC(void *ptr, Uint8 *stream, int len) + { static_cast(ptr)->audioCallback(stream, len); } void open(const ALCchar *name) override; bool reset() override; @@ -80,9 +81,6 @@ Sdl2Backend::~Sdl2Backend() mDeviceID = 0; } -void Sdl2Backend::audioCallbackC(void *ptr, Uint8 *stream, int len) -{ static_cast(ptr)->audioCallback(stream, len); } - void Sdl2Backend::audioCallback(Uint8 *stream, int len) { const auto ulen = static_cast(len); @@ -130,16 +128,15 @@ void Sdl2Backend::open(const ALCchar *name) throw al::backend_exception{ALC_INVALID_VALUE, "%s", SDL_GetError()}; mDevice->Frequency = static_cast(have.freq); + if(have.channels == 1) mDevice->FmtChans = DevFmtMono; else if(have.channels == 2) mDevice->FmtChans = DevFmtStereo; else - { - ERR("Got unhandled SDL channel count: %d\n", int{have.channels}); throw al::backend_exception{ALC_INVALID_VALUE, "Unhandled SDL channel count: %d", int{have.channels}}; - } + switch(have.format) { case AUDIO_U8: mDevice->FmtType = DevFmtUByte; break; @@ -149,7 +146,6 @@ void Sdl2Backend::open(const ALCchar *name) case AUDIO_S32SYS: mDevice->FmtType = DevFmtInt; break; case AUDIO_F32SYS: mDevice->FmtType = DevFmtFloat; break; default: - ERR("Got unsupported SDL format: 0x%04x\n", have.format); throw al::backend_exception{ALC_INVALID_VALUE, "Unhandled SDL format: 0x%04x", have.format}; } diff --git a/alc/backends/sndio.cpp b/alc/backends/sndio.cpp index 5657a241..026ff2b9 100644 --- a/alc/backends/sndio.cpp +++ b/alc/backends/sndio.cpp @@ -117,10 +117,7 @@ void SndioPlayback::open(const ALCchar *name) mSndHandle = sio_open(nullptr, SIO_PLAY, 0); if(mSndHandle == nullptr) - { - ERR("Could not open device\n"); - throw al::backend_exception{ALC_INVALID_VALUE, "Could not open sound device"}; - } + throw al::backend_exception{ALC_INVALID_VALUE, "Could not open backend device"}; mDevice->DeviceName = name; } @@ -329,10 +326,7 @@ void SndioCapture::open(const ALCchar *name) mSndHandle = sio_open(nullptr, SIO_REC, 0); if(mSndHandle == nullptr) - { - ERR("Could not open device\n"); - throw al::backend_exception{ALC_INVALID_VALUE, "Could not open sound device"}; - } + throw al::backend_exception{ALC_INVALID_VALUE, "Could not open backend device"}; sio_par par; sio_initpar(&par); @@ -364,7 +358,6 @@ void SndioCapture::open(const ALCchar *name) par.sig = 0; break; case DevFmtFloat: - ERR("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType)); throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported", DevFmtTypeString(mDevice->FmtType)}; } @@ -381,40 +374,26 @@ void SndioCapture::open(const ALCchar *name) mDevice->BufferSize = par.appbufsz; if(!sio_setpar(mSndHandle, &par) || !sio_getpar(mSndHandle, &par)) - { - ERR("Failed to set device parameters\n"); throw al::backend_exception{ALC_INVALID_VALUE, "Failed to set device praameters"}; - } if(par.bits != par.bps*8) - { - ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8); throw al::backend_exception{ALC_INVALID_VALUE, "Padded samples not supported (got %u of %u bits)", par.bits, par.bps*8}; - } - if(!((mDevice->FmtType == DevFmtByte && par.bits == 8 && par.sig != 0) || - (mDevice->FmtType == DevFmtUByte && par.bits == 8 && par.sig == 0) || - (mDevice->FmtType == DevFmtShort && par.bits == 16 && par.sig != 0) || - (mDevice->FmtType == DevFmtUShort && par.bits == 16 && par.sig == 0) || - (mDevice->FmtType == DevFmtInt && par.bits == 32 && par.sig != 0) || - (mDevice->FmtType == DevFmtUInt && par.bits == 32 && par.sig == 0)) || - mDevice->channelsFromFmt() != par.rchan || mDevice->Frequency != par.rate) - { - ERR("Failed to set format %s %s %uhz, got %c%u %u-channel %uhz instead\n", - DevFmtTypeString(mDevice->FmtType), DevFmtChannelsString(mDevice->FmtChans), - mDevice->Frequency, par.sig?'s':'u', par.bits, par.rchan, par.rate); - throw al::backend_exception{ALC_INVALID_VALUE, "Could not set format %s %s %uhz", + if(!((mDevice->FmtType == DevFmtByte && par.bits == 8 && par.sig != 0) + || (mDevice->FmtType == DevFmtUByte && par.bits == 8 && par.sig == 0) + || (mDevice->FmtType == DevFmtShort && par.bits == 16 && par.sig != 0) + || (mDevice->FmtType == DevFmtUShort && par.bits == 16 && par.sig == 0) + || (mDevice->FmtType == DevFmtInt && par.bits == 32 && par.sig != 0) + || (mDevice->FmtType == DevFmtUInt && par.bits == 32 && par.sig == 0)) + || mDevice->channelsFromFmt() != par.rchan || mDevice->Frequency != par.rate) + throw al::backend_exception{ALC_INVALID_VALUE, + "Failed to set format %s %s %uhz, got %c%u %u-channel %uhz instead", DevFmtTypeString(mDevice->FmtType), DevFmtChannelsString(mDevice->FmtChans), - mDevice->Frequency}; - } + mDevice->Frequency, par.sig?'s':'u', par.bits, par.rchan, par.rate}; mRing = CreateRingBuffer(mDevice->BufferSize, par.bps*par.rchan, false); - if(!mRing) - { - ERR("Failed to allocate %u-byte ringbuffer\n", mDevice->BufferSize*par.bps*par.rchan); - throw al::backend_exception{ALC_OUT_OF_MEMORY, "Failed to allocate ring buffer"}; - } + if(!mRing) throw al::backend_exception{ALC_OUT_OF_MEMORY, "Failed to allocate ring buffer"}; SetDefaultChannelOrder(mDevice); diff --git a/alc/backends/solaris.cpp b/alc/backends/solaris.cpp index 79cc224d..7cc2606e 100644 --- a/alc/backends/solaris.cpp +++ b/alc/backends/solaris.cpp @@ -151,11 +151,8 @@ void SolarisBackend::open(const ALCchar *name) mFd = ::open(solaris_driver.c_str(), O_WRONLY); if(mFd == -1) - { - ERR("Could not open %s: %s\n", solaris_driver.c_str(), strerror(errno)); throw al::backend_exception{ALC_INVALID_VALUE, "Could not open %s: %s", solaris_driver.c_str(), strerror(errno)}; - } mDevice->DeviceName = name; } diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 181518d0..2c4fe130 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -762,7 +762,6 @@ void WasapiPlayback::open(const ALCchar *name) mDevId.clear(); - ERR("Device init failed: 0x%08lx\n", hr); throw al::backend_exception{ALC_INVALID_VALUE, "Device init failed: 0x%08lx", hr}; } } @@ -1336,7 +1335,6 @@ void WasapiCapture::open(const ALCchar *name) mDevId.clear(); - ERR("Device init failed: 0x%08lx\n", hr); throw al::backend_exception{ALC_INVALID_VALUE, "Device init failed: 0x%08lx", hr}; } diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp index 3b0a30d8..7bcc3436 100644 --- a/alc/backends/wave.cpp +++ b/alc/backends/wave.cpp @@ -223,11 +223,8 @@ void WaveBackend::open(const ALCchar *name) mFile = fopen(fname, "wb"); #endif if(!mFile) - { - ERR("Could not open file '%s': %s\n", fname, strerror(errno)); throw al::backend_exception{ALC_INVALID_VALUE, "Could not open file '%s': %s", fname, strerror(errno)}; - } mDevice->DeviceName = name; } diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp index 8f85f351..dde74304 100644 --- a/alc/backends/winmm.cpp +++ b/alc/backends/winmm.cpp @@ -127,8 +127,9 @@ struct WinMMPlayback final : public BackendBase { WinMMPlayback(ALCdevice *device) noexcept : BackendBase{device} { } ~WinMMPlayback() override; - static void CALLBACK waveOutProcC(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); void CALLBACK waveOutProc(HWAVEOUT device, UINT msg, DWORD_PTR param1, DWORD_PTR param2); + static void CALLBACK waveOutProcC(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2) + { reinterpret_cast(instance)->waveOutProc(device, msg, param1, param2); } int mixerProc(); @@ -162,10 +163,6 @@ WinMMPlayback::~WinMMPlayback() std::fill(mWaveBuffer.begin(), mWaveBuffer.end(), WAVEHDR{}); } - -void CALLBACK WinMMPlayback::waveOutProcC(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2) -{ reinterpret_cast(instance)->waveOutProc(device, msg, param1, param2); } - /* WinMMPlayback::waveOutProc * * Posts a message to 'WinMMPlayback::mixerProc' everytime a WaveOut Buffer is @@ -256,7 +253,6 @@ retry_open: mDevice->FmtType = DevFmtShort; goto retry_open; } - ERR("waveOutOpen failed: %u\n", res); throw al::backend_exception{ALC_INVALID_VALUE, "waveOutOpen failed: %u", res}; } @@ -368,8 +364,9 @@ struct WinMMCapture final : public BackendBase { WinMMCapture(ALCdevice *device) noexcept : BackendBase{device} { } ~WinMMCapture() override; - static void CALLBACK waveInProcC(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); void CALLBACK waveInProc(HWAVEIN device, UINT msg, DWORD_PTR param1, DWORD_PTR param2); + static void CALLBACK waveInProcC(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2) + { reinterpret_cast(instance)->waveInProc(device, msg, param1, param2); } int captureProc(); @@ -407,9 +404,6 @@ WinMMCapture::~WinMMCapture() std::fill(mWaveBuffer.begin(), mWaveBuffer.end(), WAVEHDR{}); } -void CALLBACK WinMMCapture::waveInProcC(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2) -{ reinterpret_cast(instance)->waveInProc(device, msg, param1, param2); } - /* WinMMCapture::waveInProc * * Posts a message to 'WinMMCapture::captureProc' everytime a WaveIn Buffer is @@ -513,10 +507,7 @@ void WinMMCapture::open(const ALCchar *name) reinterpret_cast(&WinMMCapture::waveInProcC), reinterpret_cast(this), CALLBACK_FUNCTION)}; if(res != MMSYSERR_NOERROR) - { - ERR("waveInOpen failed: %u\n", res); throw al::backend_exception{ALC_INVALID_VALUE, "waveInOpen failed: %u", res}; - } // Ensure each buffer is 50ms each DWORD BufferSize{mFormat.nAvgBytesPerSec / 20u}; -- cgit v1.2.3 From 963580c2d503eab7c6d8f60a367498ff103bfa3e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 8 Oct 2019 21:52:08 -0700 Subject: Never return null from CreateRingBuffer Allocation failure would already throw a bad_alloc anyway, now a size overflow throws an exception too. --- alc/backends/alsa.cpp | 3 --- alc/backends/coreaudio.cpp | 1 - alc/backends/dsound.cpp | 3 --- alc/backends/jack.cpp | 11 +---------- alc/backends/opensl.cpp | 21 ++++----------------- alc/backends/oss.cpp | 1 - alc/backends/portaudio.cpp | 1 - alc/backends/sndio.cpp | 1 - alc/backends/wasapi.cpp | 5 ----- alc/backends/winmm.cpp | 1 - alc/ringbuffer.cpp | 4 +++- 11 files changed, 8 insertions(+), 44 deletions(-) diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index 7c6ce4f9..91415c32 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -981,10 +981,7 @@ void AlsaCapture::open(const ALCchar *name) hp = nullptr; if(needring) - { mRing = CreateRingBuffer(mDevice->BufferSize, mDevice->frameSizeFromFmt(), false); - if(!mRing) throw al::backend_exception{ALC_INVALID_VALUE, "Failed to create ring buffer"}; - } mDevice->DeviceName = name; return; diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 9e1d4e47..5a0e4027 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -570,7 +570,6 @@ void CoreAudioCapture::open(const ALCchar *name) mDevice->Frequency, Resampler::FastBSinc24); mRing = CreateRingBuffer(outputFrameCount, mFrameSize, false); - if(!mRing) throw al::backend_exception{ALC_INVALID_VALUE, "Failed to allocate ring buffer"}; mDevice->DeviceName = name; } diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index 005c9584..b74f2d3e 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -743,10 +743,7 @@ void DSoundCapture::open(const ALCchar *name) if(SUCCEEDED(hr)) mDSC->CreateCaptureBuffer(&DSCBDescription, &mDSCbuffer, nullptr); if(SUCCEEDED(hr)) - { mRing = CreateRingBuffer(mDevice->BufferSize, InputType.Format.nBlockAlign, false); - if(!mRing) hr = DSERR_OUTOFMEMORY; - } if(FAILED(hr)) { diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp index 2a22ed84..0814ca8d 100644 --- a/alc/backends/jack.cpp +++ b/alc/backends/jack.cpp @@ -212,11 +212,7 @@ int JackPlayback::bufferSizeNotify(jack_nframes_t numframes) mRing = nullptr; mRing = CreateRingBuffer(bufsize, mDevice->frameSizeFromFmt(), true); - if(!mRing) - { - ERR("Failed to reallocate ringbuffer\n"); - aluHandleDisconnect(mDevice, "Failed to reallocate %u-sample buffer", bufsize); - } + return 0; } @@ -407,11 +403,6 @@ bool JackPlayback::reset() mRing = nullptr; mRing = CreateRingBuffer(bufsize, mDevice->frameSizeFromFmt(), true); - if(!mRing) - { - ERR("Failed to allocate ringbuffer\n"); - return false; - } SetDefaultChannelOrder(mDevice); diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index 4e68da27..258443f2 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -521,14 +521,7 @@ bool OpenSLPlayback::reset() if(SL_RESULT_SUCCESS == result) { const ALuint num_updates{mDevice->BufferSize / mDevice->UpdateSize}; - try { - mRing = CreateRingBuffer(num_updates, mFrameSize*mDevice->UpdateSize, true); - } - catch(std::exception& e) { - ERR("Failed allocating ring buffer %ux%ux%u: %s\n", mDevice->UpdateSize, - num_updates, mFrameSize, e.what()); - result = SL_RESULT_MEMORY_FAILURE; - } + mRing = CreateRingBuffer(num_updates, mFrameSize*mDevice->UpdateSize, true); } if(SL_RESULT_SUCCESS != result) @@ -703,16 +696,10 @@ void OpenSLCapture::open(const ALCchar* name) mDevice->Frequency/100*5)}; ALuint num_updates{(length+update_len-1) / update_len}; - try { - mRing = CreateRingBuffer(num_updates, update_len*mFrameSize, false); + mRing = CreateRingBuffer(num_updates, update_len*mFrameSize, false); - mDevice->UpdateSize = update_len; - mDevice->BufferSize = static_cast(mRing->writeSpace() * update_len); - } - catch(std::exception& e) { - ERR("Failed to allocate ring buffer: %s\n", e.what()); - result = SL_RESULT_MEMORY_FAILURE; - } + mDevice->UpdateSize = update_len; + mDevice->BufferSize = static_cast(mRing->writeSpace() * update_len); } if(SL_RESULT_SUCCESS == result) { diff --git a/alc/backends/oss.cpp b/alc/backends/oss.cpp index 856aceb0..59cc44e4 100644 --- a/alc/backends/oss.cpp +++ b/alc/backends/oss.cpp @@ -612,7 +612,6 @@ void OSScapture::open(const ALCchar *name) ossFormat}; mRing = CreateRingBuffer(mDevice->BufferSize, frameSize, false); - if(!mRing) throw al::backend_exception{ALC_INVALID_VALUE, "Failed to create ring buffer"}; mDevice->DeviceName = name; } diff --git a/alc/backends/portaudio.cpp b/alc/backends/portaudio.cpp index 7c60d2bb..f50f1f16 100644 --- a/alc/backends/portaudio.cpp +++ b/alc/backends/portaudio.cpp @@ -286,7 +286,6 @@ void PortCapture::open(const ALCchar *name) ALuint frame_size{mDevice->frameSizeFromFmt()}; mRing = CreateRingBuffer(samples, frame_size, false); - if(!mRing) throw al::backend_exception{ALC_INVALID_VALUE, "Failed to create ring buffer"}; auto devidopt = ConfigValueInt(nullptr, "port", "capture"); if(devidopt && *devidopt >= 0) mParams.device = *devidopt; diff --git a/alc/backends/sndio.cpp b/alc/backends/sndio.cpp index 026ff2b9..7799316f 100644 --- a/alc/backends/sndio.cpp +++ b/alc/backends/sndio.cpp @@ -393,7 +393,6 @@ void SndioCapture::open(const ALCchar *name) mDevice->Frequency, par.sig?'s':'u', par.bits, par.rchan, par.rate}; mRing = CreateRingBuffer(mDevice->BufferSize, par.bps*par.rchan, false); - if(!mRing) throw al::backend_exception{ALC_OUT_OF_MEMORY, "Failed to allocate ring buffer"}; SetDefaultChannelOrder(mDevice); diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 2c4fe130..37a547af 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -1601,11 +1601,6 @@ HRESULT WasapiCapture::resetProxy() buffer_len = maxu(mDevice->BufferSize, buffer_len); mRing = CreateRingBuffer(buffer_len, mDevice->frameSizeFromFmt(), false); - if(!mRing) - { - ERR("Failed to allocate capture ring buffer\n"); - return E_OUTOFMEMORY; - } hr = mClient->SetEventHandle(mNotifyEvent); if(FAILED(hr)) diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp index dde74304..c2ccbc05 100644 --- a/alc/backends/winmm.cpp +++ b/alc/backends/winmm.cpp @@ -519,7 +519,6 @@ void WinMMCapture::open(const ALCchar *name) CapturedDataSize = static_cast(maxz(CapturedDataSize, BufferSize*mWaveBuffer.size())); mRing = CreateRingBuffer(CapturedDataSize, mFormat.nBlockAlign, false); - if(!mRing) throw al::backend_exception{ALC_INVALID_VALUE, "Could not create ring buffer"}; al_free(mWaveBuffer[0].lpData); mWaveBuffer[0] = WAVEHDR{}; diff --git a/alc/ringbuffer.cpp b/alc/ringbuffer.cpp index d61f6129..1f72f4b1 100644 --- a/alc/ringbuffer.cpp +++ b/alc/ringbuffer.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "almalloc.h" @@ -45,7 +46,8 @@ RingBufferPtr CreateRingBuffer(size_t sz, size_t elem_sz, int limit_writes) #endif } ++power_of_two; - if(power_of_two < sz) return nullptr; + if(power_of_two <= sz || power_of_two > std::numeric_limits::max()/elem_sz) + throw std::overflow_error{"Ring buffer size overflow"}; const size_t bufbytes{power_of_two * elem_sz}; RingBufferPtr rb{new (FamCount{bufbytes}) RingBuffer{bufbytes}}; -- cgit v1.2.3 From 2842df5a02b5a65b9977a64de8ea6bea8adbc964 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Oct 2019 00:11:19 -0700 Subject: Catch exceptions from backend start calls --- alc/alc.cpp | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index 025395fe..7702a147 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -2241,9 +2241,16 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(!device->Flags.get()) { - if(device->Backend->start() == false) + try { + auto backend = device->Backend.get(); + if(!backend->start()) + throw al::backend_exception{ALC_INVALID_DEVICE, "Backend error"}; + device->Flags.set(); + } + catch(al::backend_exception& e) { + WARN("Failed to start playback: %s\n", e.what()); return ALC_INVALID_DEVICE; - device->Flags.set(); + } } return ALC_NO_ERROR; @@ -3874,11 +3881,14 @@ START_API_FUNC alcSetError(dev.get(), ALC_INVALID_DEVICE); else if(!dev->Flags.get()) { - if(dev->Backend->start()) + try { + auto backend = dev->Backend.get(); + if(!backend->start()) + throw al::backend_exception{ALC_INVALID_DEVICE, "Device start failure"}; dev->Flags.set(); - else - { - aluHandleDisconnect(dev.get(), "Device start failure"); + } + catch(al::backend_exception& e) { + aluHandleDisconnect(dev.get(), "%s", e.what()); alcSetError(dev.get(), ALC_INVALID_DEVICE); } } @@ -4101,13 +4111,16 @@ START_API_FUNC if(dev->mContexts.load()->empty()) return; - if(dev->Backend->start() == false) - { - aluHandleDisconnect(dev.get(), "Device start failure"); + try { + auto backend = dev->Backend.get(); + if(!backend->start()) + throw al::backend_exception{ALC_INVALID_DEVICE, "Device start failure"}; + dev->Flags.set(); + } + catch(al::backend_exception& e) { + aluHandleDisconnect(dev.get(), "%s", e.what()); alcSetError(dev.get(), ALC_INVALID_DEVICE); - return; } - dev->Flags.set(); } END_API_FUNC -- cgit v1.2.3 From a7c12453600d4e9ae756b933770c6f42977a2663 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Oct 2019 02:16:08 -0700 Subject: Use smart pointers for ALSA param handles And simplify some related error handling --- alc/backends/alsa.cpp | 260 +++++++++++++++++++++++++------------------------- 1 file changed, 128 insertions(+), 132 deletions(-) diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index 91415c32..1b8c6298 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -216,6 +216,29 @@ ALSA_FUNCS(MAKE_FUNC); #endif +struct HwParamsDeleter { + void operator()(snd_pcm_hw_params_t *ptr) { snd_pcm_hw_params_free(ptr); } +}; +using HwParamsPtr = std::unique_ptr; +HwParamsPtr CreateHwParams() +{ + snd_pcm_hw_params_t *hp{}; + snd_pcm_hw_params_malloc(&hp); + return HwParamsPtr{hp}; +} + +struct SwParamsDeleter { + void operator()(snd_pcm_sw_params_t *ptr) { snd_pcm_sw_params_free(ptr); } +}; +using SwParamsPtr = std::unique_ptr; +SwParamsPtr CreateSwParams() +{ + snd_pcm_sw_params_t *sp{}; + snd_pcm_sw_params_malloc(&sp); + return SwParamsPtr{sp}; +} + + struct DevMap { std::string name; std::string device_name; @@ -630,27 +653,27 @@ bool AlsaPlayback::reset() snd_pcm_format_t format{SND_PCM_FORMAT_UNKNOWN}; switch(mDevice->FmtType) { - case DevFmtByte: - format = SND_PCM_FORMAT_S8; - break; - case DevFmtUByte: - format = SND_PCM_FORMAT_U8; - break; - case DevFmtShort: - format = SND_PCM_FORMAT_S16; - break; - case DevFmtUShort: - format = SND_PCM_FORMAT_U16; - break; - case DevFmtInt: - format = SND_PCM_FORMAT_S32; - break; - case DevFmtUInt: - format = SND_PCM_FORMAT_U32; - break; - case DevFmtFloat: - format = SND_PCM_FORMAT_FLOAT; - break; + case DevFmtByte: + format = SND_PCM_FORMAT_S8; + break; + case DevFmtUByte: + format = SND_PCM_FORMAT_U8; + break; + case DevFmtShort: + format = SND_PCM_FORMAT_S16; + break; + case DevFmtUShort: + format = SND_PCM_FORMAT_U16; + break; + case DevFmtInt: + format = SND_PCM_FORMAT_S32; + break; + case DevFmtUInt: + format = SND_PCM_FORMAT_U32; + break; + case DevFmtFloat: + format = SND_PCM_FORMAT_FLOAT; + break; } bool allowmmap{!!GetConfigValueBool(mDevice->DeviceName.c_str(), "alsa", "mmap", 1)}; @@ -658,25 +681,22 @@ bool AlsaPlayback::reset() ALuint bufferLen{static_cast(mDevice->BufferSize * 1000000_u64 / mDevice->Frequency)}; ALuint rate{mDevice->Frequency}; - snd_pcm_uframes_t periodSizeInFrames{}; - snd_pcm_uframes_t bufferSizeInFrames{}; - snd_pcm_sw_params_t *sp{}; - snd_pcm_hw_params_t *hp{}; - snd_pcm_access_t access{}; - const char *funcerr{}; int err{}; - - snd_pcm_hw_params_malloc(&hp); -#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error - CHECK(snd_pcm_hw_params_any(mPcmHandle, hp)); + HwParamsPtr hp{CreateHwParams()}; +#define CHECK(x) do { \ + if((err=(x)) < 0) \ + throw al::backend_exception{ALC_INVALID_VALUE, #x " failed: %s", snd_strerror(err)}; \ +} while(0) + CHECK(snd_pcm_hw_params_any(mPcmHandle, hp.get())); /* set interleaved access */ - if(!allowmmap || snd_pcm_hw_params_set_access(mPcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) + if(!allowmmap + || snd_pcm_hw_params_set_access(mPcmHandle, hp.get(), SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) { /* No mmap */ - CHECK(snd_pcm_hw_params_set_access(mPcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); + CHECK(snd_pcm_hw_params_set_access(mPcmHandle, hp.get(), SND_PCM_ACCESS_RW_INTERLEAVED)); } /* test and set format (implicitly sets sample bits) */ - if(snd_pcm_hw_params_test_format(mPcmHandle, hp, format) < 0) + if(snd_pcm_hw_params_test_format(mPcmHandle, hp.get(), format) < 0) { static const struct { snd_pcm_format_t format; @@ -694,16 +714,16 @@ bool AlsaPlayback::reset() for(const auto &fmt : formatlist) { format = fmt.format; - if(snd_pcm_hw_params_test_format(mPcmHandle, hp, format) >= 0) + if(snd_pcm_hw_params_test_format(mPcmHandle, hp.get(), format) >= 0) { mDevice->FmtType = fmt.fmttype; break; } } } - CHECK(snd_pcm_hw_params_set_format(mPcmHandle, hp, format)); + CHECK(snd_pcm_hw_params_set_format(mPcmHandle, hp.get(), format)); /* test and set channels (implicitly sets frame bits) */ - if(snd_pcm_hw_params_test_channels(mPcmHandle, hp, mDevice->channelsFromFmt()) < 0) + if(snd_pcm_hw_params_test_channels(mPcmHandle, hp.get(), mDevice->channelsFromFmt()) < 0) { static const DevFmtChannels channellist[] = { DevFmtStereo, @@ -715,7 +735,7 @@ bool AlsaPlayback::reset() for(const auto &chan : channellist) { - if(snd_pcm_hw_params_test_channels(mPcmHandle, hp, ChannelsFromDevFmt(chan, 0)) >= 0) + if(snd_pcm_hw_params_test_channels(mPcmHandle, hp.get(), ChannelsFromDevFmt(chan, 0)) >= 0) { mDevice->FmtChans = chan; mDevice->mAmbiOrder = 0; @@ -723,40 +743,42 @@ bool AlsaPlayback::reset() } } } - CHECK(snd_pcm_hw_params_set_channels(mPcmHandle, hp, mDevice->channelsFromFmt())); + CHECK(snd_pcm_hw_params_set_channels(mPcmHandle, hp.get(), mDevice->channelsFromFmt())); /* set rate (implicitly constrains period/buffer parameters) */ if(!GetConfigValueBool(mDevice->DeviceName.c_str(), "alsa", "allow-resampler", 0) || !mDevice->Flags.get()) { - if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp, 0) < 0) + if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp.get(), 0) < 0) ERR("Failed to disable ALSA resampler\n"); } - else if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp, 1) < 0) + else if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp.get(), 1) < 0) ERR("Failed to enable ALSA resampler\n"); - CHECK(snd_pcm_hw_params_set_rate_near(mPcmHandle, hp, &rate, nullptr)); + CHECK(snd_pcm_hw_params_set_rate_near(mPcmHandle, hp.get(), &rate, nullptr)); /* set period time (implicitly constrains period/buffer parameters) */ - if((err=snd_pcm_hw_params_set_period_time_near(mPcmHandle, hp, &periodLen, nullptr)) < 0) + if((err=snd_pcm_hw_params_set_period_time_near(mPcmHandle, hp.get(), &periodLen, nullptr)) < 0) ERR("snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err)); /* set buffer time (implicitly sets buffer size/bytes/time and period size/bytes) */ - if((err=snd_pcm_hw_params_set_buffer_time_near(mPcmHandle, hp, &bufferLen, nullptr)) < 0) + if((err=snd_pcm_hw_params_set_buffer_time_near(mPcmHandle, hp.get(), &bufferLen, nullptr)) < 0) ERR("snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err)); /* install and prepare hardware configuration */ - CHECK(snd_pcm_hw_params(mPcmHandle, hp)); + CHECK(snd_pcm_hw_params(mPcmHandle, hp.get())); /* retrieve configuration info */ - CHECK(snd_pcm_hw_params_get_access(hp, &access)); - CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, nullptr)); - CHECK(snd_pcm_hw_params_get_buffer_size(hp, &bufferSizeInFrames)); - snd_pcm_hw_params_free(hp); + snd_pcm_uframes_t periodSizeInFrames{}; + snd_pcm_uframes_t bufferSizeInFrames{}; + snd_pcm_access_t access{}; + + CHECK(snd_pcm_hw_params_get_access(hp.get(), &access)); + CHECK(snd_pcm_hw_params_get_period_size(hp.get(), &periodSizeInFrames, nullptr)); + CHECK(snd_pcm_hw_params_get_buffer_size(hp.get(), &bufferSizeInFrames)); hp = nullptr; - snd_pcm_sw_params_malloc(&sp); - CHECK(snd_pcm_sw_params_current(mPcmHandle, sp)); - CHECK(snd_pcm_sw_params_set_avail_min(mPcmHandle, sp, periodSizeInFrames)); - CHECK(snd_pcm_sw_params_set_stop_threshold(mPcmHandle, sp, bufferSizeInFrames)); - CHECK(snd_pcm_sw_params(mPcmHandle, sp)); + SwParamsPtr sp{CreateSwParams()}; + CHECK(snd_pcm_sw_params_current(mPcmHandle, sp.get())); + CHECK(snd_pcm_sw_params_set_avail_min(mPcmHandle, sp.get(), periodSizeInFrames)); + CHECK(snd_pcm_sw_params_set_stop_threshold(mPcmHandle, sp.get(), bufferSizeInFrames)); + CHECK(snd_pcm_sw_params(mPcmHandle, sp.get())); #undef CHECK - snd_pcm_sw_params_free(sp); sp = nullptr; mDevice->BufferSize = static_cast(bufferSizeInFrames); @@ -766,35 +788,21 @@ bool AlsaPlayback::reset() SetDefaultChannelOrder(mDevice); return true; - -error: - ERR("%s failed: %s\n", funcerr, snd_strerror(err)); - if(hp) snd_pcm_hw_params_free(hp); - if(sp) snd_pcm_sw_params_free(sp); - return false; } bool AlsaPlayback::start() { - snd_pcm_hw_params_t *hp{}; - snd_pcm_access_t access; - const char *funcerr; - int err; - - snd_pcm_hw_params_malloc(&hp); -#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error - CHECK(snd_pcm_hw_params_current(mPcmHandle, hp)); + int err{}; + snd_pcm_access_t access{}; + HwParamsPtr hp{CreateHwParams()}; +#define CHECK(x) do { \ + if((err=(x)) < 0) \ + throw al::backend_exception{ALC_INVALID_VALUE, #x " failed: %s", snd_strerror(err)}; \ +} while(0) + CHECK(snd_pcm_hw_params_current(mPcmHandle, hp.get())); /* retrieve configuration info */ - CHECK(snd_pcm_hw_params_get_access(hp, &access)); + CHECK(snd_pcm_hw_params_get_access(hp.get(), &access)); #undef CHECK - if(0) - { - error: - ERR("%s failed: %s\n", funcerr, snd_strerror(err)); - if(hp) snd_pcm_hw_params_free(hp); - return false; - } - snd_pcm_hw_params_free(hp); hp = nullptr; int (AlsaPlayback::*thread_func)(){}; @@ -823,8 +831,6 @@ bool AlsaPlayback::start() catch(std::exception& e) { ERR("Could not create playback thread: %s\n", e.what()); } - catch(...) { - } mBuffer.clear(); return false; } @@ -923,72 +929,67 @@ void AlsaCapture::open(const ALCchar *name) snd_pcm_format_t format{SND_PCM_FORMAT_UNKNOWN}; switch(mDevice->FmtType) { - case DevFmtByte: - format = SND_PCM_FORMAT_S8; - break; - case DevFmtUByte: - format = SND_PCM_FORMAT_U8; - break; - case DevFmtShort: - format = SND_PCM_FORMAT_S16; - break; - case DevFmtUShort: - format = SND_PCM_FORMAT_U16; - break; - case DevFmtInt: - format = SND_PCM_FORMAT_S32; - break; - case DevFmtUInt: - format = SND_PCM_FORMAT_U32; - break; - case DevFmtFloat: - format = SND_PCM_FORMAT_FLOAT; - break; + case DevFmtByte: + format = SND_PCM_FORMAT_S8; + break; + case DevFmtUByte: + format = SND_PCM_FORMAT_U8; + break; + case DevFmtShort: + format = SND_PCM_FORMAT_S16; + break; + case DevFmtUShort: + format = SND_PCM_FORMAT_U16; + break; + case DevFmtInt: + format = SND_PCM_FORMAT_S32; + break; + case DevFmtUInt: + format = SND_PCM_FORMAT_U32; + break; + case DevFmtFloat: + format = SND_PCM_FORMAT_FLOAT; + break; } snd_pcm_uframes_t bufferSizeInFrames{maxu(mDevice->BufferSize, 100*mDevice->Frequency/1000)}; snd_pcm_uframes_t periodSizeInFrames{minu(mDevice->BufferSize, 25*mDevice->Frequency/1000)}; bool needring{false}; - const char *funcerr{}; - snd_pcm_hw_params_t *hp{}; - snd_pcm_hw_params_malloc(&hp); -#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error - CHECK(snd_pcm_hw_params_any(mPcmHandle, hp)); + HwParamsPtr hp{CreateHwParams()}; +#define CHECK(x) do { \ + if((err=(x)) < 0) \ + throw al::backend_exception{ALC_INVALID_VALUE, #x " failed: %s", snd_strerror(err)}; \ +} while(0) + CHECK(snd_pcm_hw_params_any(mPcmHandle, hp.get())); /* set interleaved access */ - CHECK(snd_pcm_hw_params_set_access(mPcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); + CHECK(snd_pcm_hw_params_set_access(mPcmHandle, hp.get(), SND_PCM_ACCESS_RW_INTERLEAVED)); /* set format (implicitly sets sample bits) */ - CHECK(snd_pcm_hw_params_set_format(mPcmHandle, hp, format)); + CHECK(snd_pcm_hw_params_set_format(mPcmHandle, hp.get(), format)); /* set channels (implicitly sets frame bits) */ - CHECK(snd_pcm_hw_params_set_channels(mPcmHandle, hp, mDevice->channelsFromFmt())); + CHECK(snd_pcm_hw_params_set_channels(mPcmHandle, hp.get(), mDevice->channelsFromFmt())); /* set rate (implicitly constrains period/buffer parameters) */ - CHECK(snd_pcm_hw_params_set_rate(mPcmHandle, hp, mDevice->Frequency, 0)); + CHECK(snd_pcm_hw_params_set_rate(mPcmHandle, hp.get(), mDevice->Frequency, 0)); /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ - if(snd_pcm_hw_params_set_buffer_size_min(mPcmHandle, hp, &bufferSizeInFrames) < 0) + if(snd_pcm_hw_params_set_buffer_size_min(mPcmHandle, hp.get(), &bufferSizeInFrames) < 0) { TRACE("Buffer too large, using intermediate ring buffer\n"); needring = true; - CHECK(snd_pcm_hw_params_set_buffer_size_near(mPcmHandle, hp, &bufferSizeInFrames)); + CHECK(snd_pcm_hw_params_set_buffer_size_near(mPcmHandle, hp.get(), &bufferSizeInFrames)); } /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ - CHECK(snd_pcm_hw_params_set_period_size_near(mPcmHandle, hp, &periodSizeInFrames, nullptr)); + CHECK(snd_pcm_hw_params_set_period_size_near(mPcmHandle, hp.get(), &periodSizeInFrames, nullptr)); /* install and prepare hardware configuration */ - CHECK(snd_pcm_hw_params(mPcmHandle, hp)); + CHECK(snd_pcm_hw_params(mPcmHandle, hp.get())); /* retrieve configuration info */ - CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, nullptr)); + CHECK(snd_pcm_hw_params_get_period_size(hp.get(), &periodSizeInFrames, nullptr)); #undef CHECK - snd_pcm_hw_params_free(hp); hp = nullptr; if(needring) mRing = CreateRingBuffer(mDevice->BufferSize, mDevice->frameSizeFromFmt(), false); mDevice->DeviceName = name; - return; - -error: - if(hp) snd_pcm_hw_params_free(hp); - throw al::backend_exception{ALC_INVALID_VALUE, "%s failed: %s", funcerr, snd_strerror(err)}; } @@ -996,18 +997,13 @@ bool AlsaCapture::start() { int err{snd_pcm_prepare(mPcmHandle)}; if(err < 0) - ERR("prepare failed: %s\n", snd_strerror(err)); - else - { - err = snd_pcm_start(mPcmHandle); - if(err < 0) - ERR("start failed: %s\n", snd_strerror(err)); - } + throw al::backend_exception{ALC_INVALID_VALUE, "snd_pcm_prepare failed: %s", + snd_strerror(err)}; + + err = snd_pcm_start(mPcmHandle); if(err < 0) - { - aluHandleDisconnect(mDevice, "Capture state failure: %s", snd_strerror(err)); - return false; - } + throw al::backend_exception{ALC_INVALID_VALUE, "snd_pcm_start failed: %s", + snd_strerror(err)}; mDoCapture = true; return true; -- cgit v1.2.3 From b687e952efa7407e323e8465df41e2e84b277b31 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Oct 2019 03:29:25 -0700 Subject: Make C callbacks noexcept No telling what would happen if exceptions managed to get back into presumably C-based callers. --- alc/backends/coreaudio.cpp | 22 ++++++------- alc/backends/dsound.cpp | 9 +++--- alc/backends/jack.cpp | 12 +++---- alc/backends/opensl.cpp | 12 +++---- alc/backends/portaudio.cpp | 22 ++++++------- alc/backends/pulseaudio.cpp | 78 ++++++++++++++++++++++----------------------- alc/backends/sdl2.cpp | 6 ++-- alc/backends/winmm.cpp | 12 +++---- 8 files changed, 85 insertions(+), 88 deletions(-) diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index 5a0e4027..7c18287b 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -47,16 +47,16 @@ struct CoreAudioPlayback final : public BackendBase { CoreAudioPlayback(ALCdevice *device) noexcept : BackendBase{device} { } ~CoreAudioPlayback() override; + OSStatus MixerProc(AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, + AudioBufferList *ioData) noexcept; static OSStatus MixerProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, - AudioBufferList *ioData) + AudioBufferList *ioData) noexcept { return static_cast(inRefCon)->MixerProc(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); } - OSStatus MixerProc(AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, - AudioBufferList *ioData); void open(const ALCchar *name) override; bool reset() override; @@ -78,8 +78,8 @@ CoreAudioPlayback::~CoreAudioPlayback() } -OSStatus CoreAudioPlayback::MixerProc(AudioUnitRenderActionFlags*, - const AudioTimeStamp*, UInt32, UInt32, AudioBufferList *ioData) +OSStatus CoreAudioPlayback::MixerProc(AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32, + UInt32, AudioBufferList *ioData) noexcept { std::lock_guard _{*this}; aluMixData(mDevice, ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize/mFrameSize); @@ -291,16 +291,16 @@ struct CoreAudioCapture final : public BackendBase { CoreAudioCapture(ALCdevice *device) noexcept : BackendBase{device} { } ~CoreAudioCapture() override; + OSStatus RecordProc(AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, + UInt32 inNumberFrames, AudioBufferList *ioData) noexcept; static OSStatus RecordProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, - AudioBufferList *ioData) + AudioBufferList *ioData) noexcept { return static_cast(inRefCon)->RecordProc(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); } - OSStatus RecordProc(AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, - UInt32 inNumberFrames, AudioBufferList *ioData); void open(const ALCchar *name) override; bool start() override; @@ -330,7 +330,7 @@ CoreAudioCapture::~CoreAudioCapture() OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags*, const AudioTimeStamp *inTimeStamp, UInt32, UInt32 inNumberFrames, - AudioBufferList*) + AudioBufferList*) noexcept { AudioUnitRenderActionFlags flags = 0; union { diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index b74f2d3e..c04ba9e4 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -124,13 +124,12 @@ al::vector CaptureDevices; bool checkName(const al::vector &list, const std::string &name) { - return std::find_if(list.cbegin(), list.cend(), - [&name](const DevMap &entry) -> bool - { return entry.name == name; } - ) != list.cend(); + auto match_name = [&name](const DevMap &entry) -> bool + { return entry.name == name; }; + return std::find_if(list.cbegin(), list.cend(), match_name) != list.cend(); } -BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR*, void *data) +BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR*, void *data) noexcept { if(!guid) return TRUE; diff --git a/alc/backends/jack.cpp b/alc/backends/jack.cpp index 0814ca8d..c7bf8469 100644 --- a/alc/backends/jack.cpp +++ b/alc/backends/jack.cpp @@ -154,13 +154,13 @@ struct JackPlayback final : public BackendBase { JackPlayback(ALCdevice *device) noexcept : BackendBase{device} { } ~JackPlayback() override; - static int bufferSizeNotifyC(jack_nframes_t numframes, void *arg) + int bufferSizeNotify(jack_nframes_t numframes) noexcept; + static int bufferSizeNotifyC(jack_nframes_t numframes, void *arg) noexcept { return static_cast(arg)->bufferSizeNotify(numframes); } - int bufferSizeNotify(jack_nframes_t numframes); - static int processC(jack_nframes_t numframes, void *arg) + int process(jack_nframes_t numframes) noexcept; + static int processC(jack_nframes_t numframes, void *arg) noexcept { return static_cast(arg)->process(numframes); } - int process(jack_nframes_t numframes); int mixerProc(); @@ -197,7 +197,7 @@ JackPlayback::~JackPlayback() } -int JackPlayback::bufferSizeNotify(jack_nframes_t numframes) +int JackPlayback::bufferSizeNotify(jack_nframes_t numframes) noexcept { std::lock_guard _{mDevice->StateLock}; mDevice->UpdateSize = numframes; @@ -217,7 +217,7 @@ int JackPlayback::bufferSizeNotify(jack_nframes_t numframes) } -int JackPlayback::process(jack_nframes_t numframes) +int JackPlayback::process(jack_nframes_t numframes) noexcept { jack_default_audio_sample_t *out[MAX_OUTPUT_CHANNELS]; ALsizei numchans{0}; diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index 258443f2..4bba3455 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -146,8 +146,8 @@ struct OpenSLPlayback final : public BackendBase { OpenSLPlayback(ALCdevice *device) noexcept : BackendBase{device} { } ~OpenSLPlayback() override; - void process(SLAndroidSimpleBufferQueueItf bq); - static void processC(SLAndroidSimpleBufferQueueItf bq, void *context) + void process(SLAndroidSimpleBufferQueueItf bq) noexcept; + static void processC(SLAndroidSimpleBufferQueueItf bq, void *context) noexcept { static_cast(context)->process(bq); } int mixerProc(); @@ -197,7 +197,7 @@ OpenSLPlayback::~OpenSLPlayback() /* this callback handler is called every time a buffer finishes playing */ -void OpenSLPlayback::process(SLAndroidSimpleBufferQueueItf) +void OpenSLPlayback::process(SLAndroidSimpleBufferQueueItf) noexcept { /* A note on the ringbuffer usage: The buffer queue seems to hold on to the * pointer passed to the Enqueue method, rather than copying the audio. @@ -622,8 +622,8 @@ struct OpenSLCapture final : public BackendBase { OpenSLCapture(ALCdevice *device) noexcept : BackendBase{device} { } ~OpenSLCapture() override; - void process(SLAndroidSimpleBufferQueueItf bq); - static void processC(SLAndroidSimpleBufferQueueItf bq, void *context) + void process(SLAndroidSimpleBufferQueueItf bq) noexcept; + static void processC(SLAndroidSimpleBufferQueueItf bq, void *context) noexcept { static_cast(context)->process(bq); } void open(const ALCchar *name) override; @@ -660,7 +660,7 @@ OpenSLCapture::~OpenSLCapture() } -void OpenSLCapture::process(SLAndroidSimpleBufferQueueItf) +void OpenSLCapture::process(SLAndroidSimpleBufferQueueItf) noexcept { /* A new chunk has been written into the ring buffer, advance it. */ mRing->writeAdvance(1); diff --git a/alc/backends/portaudio.cpp b/alc/backends/portaudio.cpp index f50f1f16..1e3d0ce8 100644 --- a/alc/backends/portaudio.cpp +++ b/alc/backends/portaudio.cpp @@ -75,15 +75,15 @@ struct PortPlayback final : public BackendBase { PortPlayback(ALCdevice *device) noexcept : BackendBase{device} { } ~PortPlayback() override; + int writeCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags) noexcept; static int writeCallbackC(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, - const PaStreamCallbackFlags statusFlags, void *userData) + const PaStreamCallbackFlags statusFlags, void *userData) noexcept { return static_cast(userData)->writeCallback(inputBuffer, outputBuffer, framesPerBuffer, timeInfo, statusFlags); } - int writeCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags); void open(const ALCchar *name) override; bool reset() override; @@ -106,9 +106,8 @@ PortPlayback::~PortPlayback() } -int PortPlayback::writeCallback(const void*, void *outputBuffer, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo*, - const PaStreamCallbackFlags) +int PortPlayback::writeCallback(const void*, void *outputBuffer, unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo*, const PaStreamCallbackFlags) noexcept { std::lock_guard _{*this}; aluMixData(mDevice, outputBuffer, static_cast(framesPerBuffer)); @@ -232,15 +231,15 @@ struct PortCapture final : public BackendBase { PortCapture(ALCdevice *device) noexcept : BackendBase{device} { } ~PortCapture() override; + int readCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags) noexcept; static int readCallbackC(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, - const PaStreamCallbackFlags statusFlags, void *userData) + const PaStreamCallbackFlags statusFlags, void *userData) noexcept { return static_cast(userData)->readCallback(inputBuffer, outputBuffer, framesPerBuffer, timeInfo, statusFlags); } - int readCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags); void open(const ALCchar *name) override; bool start() override; @@ -265,9 +264,8 @@ PortCapture::~PortCapture() } -int PortCapture::readCallback(const void *inputBuffer, void*, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo*, - const PaStreamCallbackFlags) +int PortCapture::readCallback(const void *inputBuffer, void*, unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo*, const PaStreamCallbackFlags) noexcept { mRing->write(inputBuffer, framesPerBuffer); return 0; diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 2521084d..95807540 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -313,7 +313,7 @@ pa_mainloop *pulse_mainloop{nullptr}; std::mutex pulse_lock; std::condition_variable pulse_condvar; -int pulse_poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) +int pulse_poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) noexcept { auto plock = static_cast*>(userdata); plock->unlock(); @@ -343,21 +343,21 @@ int pulse_mainloop_thread() /* PulseAudio Event Callbacks */ -void context_state_callback(pa_context *context, void* /*pdata*/) +void context_state_callback(pa_context *context, void* /*pdata*/) noexcept { pa_context_state_t state{pa_context_get_state(context)}; if(state == PA_CONTEXT_READY || !PA_CONTEXT_IS_GOOD(state)) pulse_condvar.notify_all(); } -void stream_state_callback(pa_stream *stream, void* /*pdata*/) +void stream_state_callback(pa_stream *stream, void* /*pdata*/) noexcept { pa_stream_state_t state{pa_stream_get_state(stream)}; if(state == PA_STREAM_READY || !PA_STREAM_IS_GOOD(state)) pulse_condvar.notify_all(); } -void stream_success_callback(pa_stream* /*stream*/, int /*success*/, void* /*pdata*/) +void stream_success_callback(pa_stream* /*stream*/, int /*success*/, void* /*pdata*/) noexcept { pulse_condvar.notify_all(); } @@ -496,7 +496,7 @@ pa_stream *pulse_connect_stream(const char *device_name, std::unique_lock(pdata)->bufferAttrCallback(stream); } - void contextStateCallback(pa_context *context); - static void contextStateCallbackC(pa_context *context, void *pdata) + void contextStateCallback(pa_context *context) noexcept; + static void contextStateCallbackC(pa_context *context, void *pdata) noexcept { static_cast(pdata)->contextStateCallback(context); } - void streamStateCallback(pa_stream *stream); - static void streamStateCallbackC(pa_stream *stream, void *pdata) + void streamStateCallback(pa_stream *stream) noexcept; + static void streamStateCallbackC(pa_stream *stream, void *pdata) noexcept { static_cast(pdata)->streamStateCallback(stream); } - void streamWriteCallback(pa_stream *stream, size_t nbytes); - static void streamWriteCallbackC(pa_stream *stream, size_t nbytes, void *pdata) + void streamWriteCallback(pa_stream *stream, size_t nbytes) noexcept; + static void streamWriteCallbackC(pa_stream *stream, size_t nbytes, void *pdata) noexcept { static_cast(pdata)->streamWriteCallback(stream, nbytes); } - void sinkInfoCallback(pa_context *context, const pa_sink_info *info, int eol); - static void sinkInfoCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata) + void sinkInfoCallback(pa_context *context, const pa_sink_info *info, int eol) noexcept; + static void sinkInfoCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata) noexcept { static_cast(pdata)->sinkInfoCallback(context, info, eol); } - void sinkNameCallback(pa_context *context, const pa_sink_info *info, int eol); - static void sinkNameCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata) + void sinkNameCallback(pa_context *context, const pa_sink_info *info, int eol) noexcept; + static void sinkNameCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata) noexcept { static_cast(pdata)->sinkNameCallback(context, info, eol); } - void streamMovedCallback(pa_stream *stream); - static void streamMovedCallbackC(pa_stream *stream, void *pdata) + void streamMovedCallback(pa_stream *stream) noexcept; + static void streamMovedCallbackC(pa_stream *stream, void *pdata) noexcept { static_cast(pdata)->streamMovedCallback(stream); } void open(const ALCchar *name) override; @@ -702,7 +702,7 @@ PulsePlayback::~PulsePlayback() } -void PulsePlayback::bufferAttrCallback(pa_stream *stream) +void PulsePlayback::bufferAttrCallback(pa_stream *stream) noexcept { /* FIXME: Update the device's UpdateSize (and/or BufferSize) using the new * buffer attributes? Changing UpdateSize will change the ALC_REFRESH @@ -713,7 +713,7 @@ void PulsePlayback::bufferAttrCallback(pa_stream *stream) TRACE("minreq=%d, tlength=%d, prebuf=%d\n", mAttr.minreq, mAttr.tlength, mAttr.prebuf); } -void PulsePlayback::contextStateCallback(pa_context *context) +void PulsePlayback::contextStateCallback(pa_context *context) noexcept { if(pa_context_get_state(context) == PA_CONTEXT_FAILED) { @@ -723,7 +723,7 @@ void PulsePlayback::contextStateCallback(pa_context *context) pulse_condvar.notify_all(); } -void PulsePlayback::streamStateCallback(pa_stream *stream) +void PulsePlayback::streamStateCallback(pa_stream *stream) noexcept { if(pa_stream_get_state(stream) == PA_STREAM_FAILED) { @@ -733,7 +733,7 @@ void PulsePlayback::streamStateCallback(pa_stream *stream) pulse_condvar.notify_all(); } -void PulsePlayback::streamWriteCallback(pa_stream *stream, size_t nbytes) +void PulsePlayback::streamWriteCallback(pa_stream *stream, size_t nbytes) noexcept { void *buf{pa_xmalloc(nbytes)}; aluMixData(mDevice, buf, static_cast(nbytes/mFrameSize)); @@ -743,7 +743,7 @@ void PulsePlayback::streamWriteCallback(pa_stream *stream, size_t nbytes) ERR("Failed to write to stream: %d, %s\n", ret, pa_strerror(ret)); } -void PulsePlayback::sinkInfoCallback(pa_context*, const pa_sink_info *info, int eol) +void PulsePlayback::sinkInfoCallback(pa_context*, const pa_sink_info *info, int eol) noexcept { struct ChannelMap { DevFmtChannels fmt; @@ -787,7 +787,7 @@ void PulsePlayback::sinkInfoCallback(pa_context*, const pa_sink_info *info, int info->active_port && strcmp(info->active_port->name, "analog-output-headphones") == 0); } -void PulsePlayback::sinkNameCallback(pa_context*, const pa_sink_info *info, int eol) +void PulsePlayback::sinkNameCallback(pa_context*, const pa_sink_info *info, int eol) noexcept { if(eol) { @@ -797,7 +797,7 @@ void PulsePlayback::sinkNameCallback(pa_context*, const pa_sink_info *info, int mDevice->DeviceName = info->description; } -void PulsePlayback::streamMovedCallback(pa_stream *stream) +void PulsePlayback::streamMovedCallback(pa_stream *stream) noexcept { mDeviceName = pa_stream_get_device_name(stream); TRACE("Stream moved to %s\n", mDeviceName.c_str()); @@ -1073,20 +1073,20 @@ struct PulseCapture final : public BackendBase { PulseCapture(ALCdevice *device) noexcept : BackendBase{device} { } ~PulseCapture() override; - void contextStateCallback(pa_context *context); - static void contextStateCallbackC(pa_context *context, void *pdata) + void contextStateCallback(pa_context *context) noexcept; + static void contextStateCallbackC(pa_context *context, void *pdata) noexcept { static_cast(pdata)->contextStateCallback(context); } - void streamStateCallback(pa_stream *stream); - static void streamStateCallbackC(pa_stream *stream, void *pdata) + void streamStateCallback(pa_stream *stream) noexcept; + static void streamStateCallbackC(pa_stream *stream, void *pdata) noexcept { static_cast(pdata)->streamStateCallback(stream); } - void sourceNameCallback(pa_context *context, const pa_source_info *info, int eol); - static void sourceNameCallbackC(pa_context *context, const pa_source_info *info, int eol, void *pdata) + void sourceNameCallback(pa_context *context, const pa_source_info *info, int eol) noexcept; + static void sourceNameCallbackC(pa_context *context, const pa_source_info *info, int eol, void *pdata) noexcept { static_cast(pdata)->sourceNameCallback(context, info, eol); } - void streamMovedCallback(pa_stream *stream); - static void streamMovedCallbackC(pa_stream *stream, void *pdata) + void streamMovedCallback(pa_stream *stream) noexcept; + static void streamMovedCallbackC(pa_stream *stream, void *pdata) noexcept { static_cast(pdata)->streamMovedCallback(stream); } void open(const ALCchar *name) override; @@ -1126,7 +1126,7 @@ PulseCapture::~PulseCapture() } -void PulseCapture::contextStateCallback(pa_context *context) +void PulseCapture::contextStateCallback(pa_context *context) noexcept { if(pa_context_get_state(context) == PA_CONTEXT_FAILED) { @@ -1136,7 +1136,7 @@ void PulseCapture::contextStateCallback(pa_context *context) pulse_condvar.notify_all(); } -void PulseCapture::streamStateCallback(pa_stream *stream) +void PulseCapture::streamStateCallback(pa_stream *stream) noexcept { if(pa_stream_get_state(stream) == PA_STREAM_FAILED) { @@ -1146,7 +1146,7 @@ void PulseCapture::streamStateCallback(pa_stream *stream) pulse_condvar.notify_all(); } -void PulseCapture::sourceNameCallback(pa_context*, const pa_source_info *info, int eol) +void PulseCapture::sourceNameCallback(pa_context*, const pa_source_info *info, int eol) noexcept { if(eol) { @@ -1156,7 +1156,7 @@ void PulseCapture::sourceNameCallback(pa_context*, const pa_source_info *info, i mDevice->DeviceName = info->description; } -void PulseCapture::streamMovedCallback(pa_stream *stream) +void PulseCapture::streamMovedCallback(pa_stream *stream) noexcept { mDeviceName = pa_stream_get_device_name(stream); TRACE("Stream moved to %s\n", mDeviceName.c_str()); diff --git a/alc/backends/sdl2.cpp b/alc/backends/sdl2.cpp index 4cdf05b4..25b5d4d9 100644 --- a/alc/backends/sdl2.cpp +++ b/alc/backends/sdl2.cpp @@ -52,8 +52,8 @@ struct Sdl2Backend final : public BackendBase { Sdl2Backend(ALCdevice *device) noexcept : BackendBase{device} { } ~Sdl2Backend() override; - void audioCallback(Uint8 *stream, int len); - static void audioCallbackC(void *ptr, Uint8 *stream, int len) + void audioCallback(Uint8 *stream, int len) noexcept; + static void audioCallbackC(void *ptr, Uint8 *stream, int len) noexcept { static_cast(ptr)->audioCallback(stream, len); } void open(const ALCchar *name) override; @@ -81,7 +81,7 @@ Sdl2Backend::~Sdl2Backend() mDeviceID = 0; } -void Sdl2Backend::audioCallback(Uint8 *stream, int len) +void Sdl2Backend::audioCallback(Uint8 *stream, int len) noexcept { const auto ulen = static_cast(len); assert((ulen % mFrameSize) == 0); diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp index c2ccbc05..649bb345 100644 --- a/alc/backends/winmm.cpp +++ b/alc/backends/winmm.cpp @@ -127,8 +127,8 @@ struct WinMMPlayback final : public BackendBase { WinMMPlayback(ALCdevice *device) noexcept : BackendBase{device} { } ~WinMMPlayback() override; - void CALLBACK waveOutProc(HWAVEOUT device, UINT msg, DWORD_PTR param1, DWORD_PTR param2); - static void CALLBACK waveOutProcC(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2) + void CALLBACK waveOutProc(HWAVEOUT device, UINT msg, DWORD_PTR param1, DWORD_PTR param2) noexcept; + static void CALLBACK waveOutProcC(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2) noexcept { reinterpret_cast(instance)->waveOutProc(device, msg, param1, param2); } int mixerProc(); @@ -168,7 +168,7 @@ WinMMPlayback::~WinMMPlayback() * Posts a message to 'WinMMPlayback::mixerProc' everytime a WaveOut Buffer is * completed and returns to the application (for more data) */ -void CALLBACK WinMMPlayback::waveOutProc(HWAVEOUT, UINT msg, DWORD_PTR, DWORD_PTR) +void CALLBACK WinMMPlayback::waveOutProc(HWAVEOUT, UINT msg, DWORD_PTR, DWORD_PTR) noexcept { if(msg != WOM_DONE) return; mWritable.fetch_add(1, std::memory_order_acq_rel); @@ -364,8 +364,8 @@ struct WinMMCapture final : public BackendBase { WinMMCapture(ALCdevice *device) noexcept : BackendBase{device} { } ~WinMMCapture() override; - void CALLBACK waveInProc(HWAVEIN device, UINT msg, DWORD_PTR param1, DWORD_PTR param2); - static void CALLBACK waveInProcC(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2) + void CALLBACK waveInProc(HWAVEIN device, UINT msg, DWORD_PTR param1, DWORD_PTR param2) noexcept; + static void CALLBACK waveInProcC(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2) noexcept { reinterpret_cast(instance)->waveInProc(device, msg, param1, param2); } int captureProc(); @@ -409,7 +409,7 @@ WinMMCapture::~WinMMCapture() * Posts a message to 'WinMMCapture::captureProc' everytime a WaveIn Buffer is * completed and returns to the application (with more data). */ -void CALLBACK WinMMCapture::waveInProc(HWAVEIN, UINT msg, DWORD_PTR, DWORD_PTR) +void CALLBACK WinMMCapture::waveInProc(HWAVEIN, UINT msg, DWORD_PTR, DWORD_PTR) noexcept { if(msg != WIM_DATA) return; mReadable.fetch_add(1, std::memory_order_acq_rel); -- cgit v1.2.3 From 404f3e2d089bc00e81065621f80c5f5f9fc68949 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Oct 2019 05:01:30 -0700 Subject: Don't track the PulseAudio context state in devices --- alc/backends/pulseaudio.cpp | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 95807540..71cf4b21 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -646,10 +646,6 @@ struct PulsePlayback final : public BackendBase { static void bufferAttrCallbackC(pa_stream *stream, void *pdata) noexcept { static_cast(pdata)->bufferAttrCallback(stream); } - void contextStateCallback(pa_context *context) noexcept; - static void contextStateCallbackC(pa_context *context, void *pdata) noexcept - { static_cast(pdata)->contextStateCallback(context); } - void streamStateCallback(pa_stream *stream) noexcept; static void streamStateCallbackC(pa_stream *stream, void *pdata) noexcept { static_cast(pdata)->streamStateCallback(stream); } @@ -713,16 +709,6 @@ void PulsePlayback::bufferAttrCallback(pa_stream *stream) noexcept TRACE("minreq=%d, tlength=%d, prebuf=%d\n", mAttr.minreq, mAttr.tlength, mAttr.prebuf); } -void PulsePlayback::contextStateCallback(pa_context *context) noexcept -{ - if(pa_context_get_state(context) == PA_CONTEXT_FAILED) - { - ERR("Received context failure!\n"); - aluHandleDisconnect(mDevice, "Playback state failure"); - } - pulse_condvar.notify_all(); -} - void PulsePlayback::streamStateCallback(pa_stream *stream) noexcept { if(pa_stream_get_state(stream) == PA_STREAM_FAILED) @@ -827,7 +813,6 @@ void PulsePlayback::open(const ALCchar *name) std::unique_lock plock{pulse_lock}; mContext = connect_context(plock); - pa_context_set_state_callback(mContext, &PulsePlayback::contextStateCallbackC, this); pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS}; if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 1)) @@ -1073,10 +1058,6 @@ struct PulseCapture final : public BackendBase { PulseCapture(ALCdevice *device) noexcept : BackendBase{device} { } ~PulseCapture() override; - void contextStateCallback(pa_context *context) noexcept; - static void contextStateCallbackC(pa_context *context, void *pdata) noexcept - { static_cast(pdata)->contextStateCallback(context); } - void streamStateCallback(pa_stream *stream) noexcept; static void streamStateCallbackC(pa_stream *stream, void *pdata) noexcept { static_cast(pdata)->streamStateCallback(stream); } @@ -1126,16 +1107,6 @@ PulseCapture::~PulseCapture() } -void PulseCapture::contextStateCallback(pa_context *context) noexcept -{ - if(pa_context_get_state(context) == PA_CONTEXT_FAILED) - { - ERR("Received context failure!\n"); - aluHandleDisconnect(mDevice, "Capture state failure"); - } - pulse_condvar.notify_all(); -} - void PulseCapture::streamStateCallback(pa_stream *stream) noexcept { if(pa_stream_get_state(stream) == PA_STREAM_FAILED) @@ -1184,7 +1155,6 @@ void PulseCapture::open(const ALCchar *name) std::unique_lock plock{pulse_lock}; mContext = connect_context(plock); - pa_context_set_state_callback(mContext, &PulseCapture::contextStateCallbackC, this); pa_channel_map chanmap{}; switch(mDevice->FmtChans) -- cgit v1.2.3 From 57cdac3368e45cdb27a7d4ab699e5045d016dd3c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Oct 2019 09:42:35 -0700 Subject: Create the initial PulseAudio stream corked --- alc/backends/pulseaudio.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 71cf4b21..63d9d8e9 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -814,7 +814,8 @@ void PulsePlayback::open(const ALCchar *name) mContext = connect_context(plock); - pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS}; + pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | + PA_STREAM_FIX_CHANNELS}; if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 1)) flags |= PA_STREAM_DONT_MOVE; -- cgit v1.2.3 From 8bf3da0cd21e2a11d9ae7ef9ba7225dc36a5bbfa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Oct 2019 09:45:02 -0700 Subject: Remove a useless prebuf check with PulseAudio --- alc/backends/pulseaudio.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 63d9d8e9..5f9a64e6 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -986,20 +986,6 @@ bool PulsePlayback::reset() mDevice->BufferSize = mAttr.tlength / mFrameSize; mDevice->UpdateSize = mAttr.minreq / mFrameSize; - /* HACK: prebuf should be 0 as that's what we set it to. However on some - * systems it comes back as non-0, so we have to make sure the device will - * write enough audio to start playback. The lack of manual start control - * may have unintended consequences, but it's better than not starting at - * all. - */ - if(mAttr.prebuf != 0) - { - ALuint len{mAttr.prebuf / mFrameSize}; - if(len <= mDevice->BufferSize) - ERR("Non-0 prebuf, %u samples (%u bytes), device has %u samples\n", - len, mAttr.prebuf, mDevice->BufferSize); - } - return true; } -- cgit v1.2.3 From d2053e678418357faf701acdd49272075f22c1cc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Oct 2019 23:04:05 -0700 Subject: Use one PulseAudio mainloop per device To help avoid devices blocking on each other when handling asynchronous messages. --- alc/backends/pulseaudio.cpp | 491 ++++++++++++++++++++++++-------------------- 1 file changed, 270 insertions(+), 221 deletions(-) diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 5f9a64e6..4e46460b 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "alcmain.h" @@ -53,6 +54,7 @@ namespace { MAGIC(pa_mainloop_free); \ MAGIC(pa_mainloop_set_poll_func); \ MAGIC(pa_mainloop_run); \ + MAGIC(pa_mainloop_quit); \ MAGIC(pa_mainloop_get_api); \ MAGIC(pa_context_new); \ MAGIC(pa_context_unref); \ @@ -119,6 +121,7 @@ PULSE_FUNCS(MAKE_FUNC) #define pa_mainloop_free ppa_mainloop_free #define pa_mainloop_set_poll_func ppa_mainloop_set_poll_func #define pa_mainloop_run ppa_mainloop_run +#define pa_mainloop_quit ppa_mainloop_quit #define pa_mainloop_get_api ppa_mainloop_get_api #define pa_context_new ppa_context_new #define pa_context_unref ppa_context_unref @@ -285,22 +288,22 @@ void SetChannelOrderFromMap(ALCdevice *device, const pa_channel_map &chanmap) /* *grumble* Don't use enums for bitflags. */ -inline pa_stream_flags_t operator|(pa_stream_flags_t lhs, pa_stream_flags_t rhs) +constexpr inline pa_stream_flags_t operator|(pa_stream_flags_t lhs, pa_stream_flags_t rhs) { return pa_stream_flags_t(int(lhs) | int(rhs)); } inline pa_stream_flags_t& operator|=(pa_stream_flags_t &lhs, pa_stream_flags_t rhs) { - lhs = pa_stream_flags_t(int(lhs) | int(rhs)); + lhs = lhs | rhs; return lhs; } -inline pa_context_flags_t& operator|=(pa_context_flags_t &lhs, pa_context_flags_t rhs) +inline pa_stream_flags_t& operator&=(pa_stream_flags_t &lhs, int rhs) { - lhs = pa_context_flags_t(int(lhs) | int(rhs)); + lhs = pa_stream_flags_t(int(lhs) & rhs); return lhs; } -inline pa_stream_flags_t& operator&=(pa_stream_flags_t &lhs, int rhs) +inline pa_context_flags_t& operator|=(pa_context_flags_t &lhs, pa_context_flags_t rhs) { - lhs = pa_stream_flags_t(int(lhs) & rhs); + lhs = pa_context_flags_t(int(lhs) | int(rhs)); return lhs; } @@ -308,11 +311,6 @@ inline pa_stream_flags_t& operator&=(pa_stream_flags_t &lhs, int rhs) /* Global flags and properties */ pa_context_flags_t pulse_ctx_flags; -pa_mainloop *pulse_mainloop{nullptr}; - -std::mutex pulse_lock; -std::condition_variable pulse_condvar; - int pulse_poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) noexcept { auto plock = static_cast*>(userdata); @@ -322,58 +320,90 @@ int pulse_poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void * return r; } -int pulse_mainloop_thread() -{ - SetRTPriority(); +class PulseMainloop { + std::thread mThread; + std::mutex mMutex; + std::condition_variable mCondVar; + pa_mainloop *mMainloop{nullptr}; - std::unique_lock plock{pulse_lock}; - pulse_mainloop = pa_mainloop_new(); +public: + ~PulseMainloop() + { + if(mThread.joinable()) + { + pa_mainloop_quit(mMainloop, 0); + mThread.join(); + } + } - pa_mainloop_set_poll_func(pulse_mainloop, pulse_poll_func, &plock); - pulse_condvar.notify_all(); + int mainloop_thread() + { + SetRTPriority(); - int ret{}; - pa_mainloop_run(pulse_mainloop, &ret); + std::unique_lock plock{mMutex}; + mMainloop = pa_mainloop_new(); - pa_mainloop_free(pulse_mainloop); - pulse_mainloop = nullptr; + pa_mainloop_set_poll_func(mMainloop, pulse_poll_func, &plock); + mCondVar.notify_all(); - return ret; -} + int ret{}; + pa_mainloop_run(mMainloop, &ret); + pa_mainloop_free(mMainloop); + mMainloop = nullptr; -/* PulseAudio Event Callbacks */ -void context_state_callback(pa_context *context, void* /*pdata*/) noexcept -{ - pa_context_state_t state{pa_context_get_state(context)}; - if(state == PA_CONTEXT_READY || !PA_CONTEXT_IS_GOOD(state)) - pulse_condvar.notify_all(); -} + return ret; + } -void stream_state_callback(pa_stream *stream, void* /*pdata*/) noexcept -{ - pa_stream_state_t state{pa_stream_get_state(stream)}; - if(state == PA_STREAM_READY || !PA_STREAM_IS_GOOD(state)) - pulse_condvar.notify_all(); -} + void doLock() { mMutex.lock(); } + void doUnlock() { mMutex.unlock(); } + std::unique_lock getLock() { return std::unique_lock{mMutex}; } + std::condition_variable &getCondVar() noexcept { return mCondVar; } -void stream_success_callback(pa_stream* /*stream*/, int /*success*/, void* /*pdata*/) noexcept -{ - pulse_condvar.notify_all(); -} + void contextStateCallback(pa_context *context) noexcept + { + pa_context_state_t state{pa_context_get_state(context)}; + if(state == PA_CONTEXT_READY || !PA_CONTEXT_IS_GOOD(state)) + mCondVar.notify_all(); + } + static void contextStateCallbackC(pa_context *context, void *pdata) noexcept + { static_cast(pdata)->contextStateCallback(context); } -void wait_for_operation(pa_operation *op, std::unique_lock &plock) -{ - if(op) + void streamStateCallback(pa_stream *stream) noexcept { - while(pa_operation_get_state(op) == PA_OPERATION_RUNNING) - pulse_condvar.wait(plock); - pa_operation_unref(op); + pa_stream_state_t state{pa_stream_get_state(stream)}; + if(state == PA_STREAM_READY || !PA_STREAM_IS_GOOD(state)) + mCondVar.notify_all(); } -} + static void streamStateCallbackC(pa_stream *stream, void *pdata) noexcept + { static_cast(pdata)->streamStateCallback(stream); } + + void streamSuccessCallback(pa_stream*, int) noexcept + { mCondVar.notify_all(); } + static void streamSuccessCallbackC(pa_stream *stream, int success, void *pdata) noexcept + { static_cast(pdata)->streamSuccessCallback(stream, success); } + void waitForOperation(pa_operation *op, std::unique_lock &plock) + { + if(op) + { + while(pa_operation_get_state(op) == PA_OPERATION_RUNNING) + mCondVar.wait(plock); + pa_operation_unref(op); + } + } + + pa_context *connectContext(std::unique_lock &plock); -pa_context *connect_context(std::unique_lock &plock) + pa_stream *connectStream(const char *device_name, std::unique_lock &plock, + pa_context *context, pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, + pa_channel_map *chanmap, BackendType type); + + void close(pa_context *context, pa_stream *stream); +}; + + +pa_context *PulseMainloop::connectContext(std::unique_lock &plock) { const char *name{"OpenAL Soft"}; @@ -381,17 +411,16 @@ pa_context *connect_context(std::unique_lock &plock) if(!binname.fname.empty()) name = binname.fname.c_str(); - if UNLIKELY(!pulse_mainloop) + if(!mMainloop) { - std::thread{pulse_mainloop_thread}.detach(); - while(!pulse_mainloop) - pulse_condvar.wait(plock); + mThread = std::thread{std::mem_fn(&PulseMainloop::mainloop_thread), this}; + while(!mMainloop) mCondVar.wait(plock); } - pa_context *context{pa_context_new(pa_mainloop_get_api(pulse_mainloop), name)}; + pa_context *context{pa_context_new(pa_mainloop_get_api(mMainloop), name)}; if(!context) throw al::backend_exception{ALC_OUT_OF_MEMORY, "pa_context_new() failed"}; - pa_context_set_state_callback(context, context_state_callback, nullptr); + pa_context_set_state_callback(context, &contextStateCallbackC, this); int err; if((err=pa_context_connect(context, nullptr, pulse_ctx_flags, nullptr)) >= 0) @@ -406,7 +435,7 @@ pa_context *connect_context(std::unique_lock &plock) break; } - pulse_condvar.wait(plock); + mCondVar.wait(plock); } } pa_context_set_state_callback(context, nullptr, nullptr); @@ -421,43 +450,9 @@ pa_context *connect_context(std::unique_lock &plock) return context; } - -void pulse_close(pa_context *context, pa_stream *stream) -{ - std::lock_guard _{pulse_lock}; - if(stream) - { - pa_stream_set_state_callback(stream, nullptr, nullptr); - pa_stream_set_moved_callback(stream, nullptr, nullptr); - pa_stream_set_write_callback(stream, nullptr, nullptr); - pa_stream_set_buffer_attr_callback(stream, nullptr, nullptr); - pa_stream_disconnect(stream); - pa_stream_unref(stream); - } - - pa_context_disconnect(context); - pa_context_unref(context); -} - - -struct DevMap { - std::string name; - std::string device_name; -}; - -bool checkName(const al::vector &list, const std::string &name) -{ - auto match_name = [&name](const DevMap &entry) -> bool { return entry.name == name; }; - return std::find_if(list.cbegin(), list.cend(), match_name) != list.cend(); -} - -al::vector PlaybackDevices; -al::vector CaptureDevices; - - -pa_stream *pulse_connect_stream(const char *device_name, std::unique_lock &plock, - pa_context *context, pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, - pa_channel_map *chanmap, BackendType type) +pa_stream *PulseMainloop::connectStream(const char *device_name, + std::unique_lock &plock, pa_context *context, pa_stream_flags_t flags, + pa_buffer_attr *attr, pa_sample_spec *spec, pa_channel_map *chanmap, BackendType type) { const char *stream_id{(type==BackendType::Playback) ? "Playback Stream" : "Capture Stream"}; pa_stream *stream{pa_stream_new(context, stream_id, spec, chanmap)}; @@ -465,7 +460,7 @@ pa_stream *pulse_connect_stream(const char *device_name, std::unique_lock _{mMutex}; + if(stream) + { + pa_stream_set_state_callback(stream, nullptr, nullptr); + pa_stream_set_moved_callback(stream, nullptr, nullptr); + pa_stream_set_write_callback(stream, nullptr, nullptr); + pa_stream_set_buffer_attr_callback(stream, nullptr, nullptr); + pa_stream_disconnect(stream); + pa_stream_unref(stream); + } -void device_sink_callback(pa_context*, const pa_sink_info *info, int eol, void*) noexcept + pa_context_disconnect(context); + pa_context_unref(context); +} + + +/* Used for initial connection test and enumeration. */ +PulseMainloop gGlobalMainloop; + + +struct DevMap { + std::string name; + std::string device_name; +}; + +bool checkName(const al::vector &list, const std::string &name) +{ + auto match_name = [&name](const DevMap &entry) -> bool { return entry.name == name; }; + return std::find_if(list.cbegin(), list.cend(), match_name) != list.cend(); +} + +al::vector PlaybackDevices; +al::vector CaptureDevices; + + +void device_sink_callback(pa_context*, const pa_sink_info *info, int eol, void *pdata) noexcept { if(eol) { - pulse_condvar.notify_all(); + static_cast(pdata)->getCondVar().notify_all(); return; } @@ -528,50 +559,54 @@ void device_sink_callback(pa_context*, const pa_sink_info *info, int eol, void*) TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str()); } -void probePlaybackDevices() +void probePlaybackDevices(PulseMainloop &mainloop) { - PlaybackDevices.clear(); + pa_context *context{}; + pa_stream *stream{}; + PlaybackDevices.clear(); try { - std::unique_lock plock{pulse_lock}; + auto plock = mainloop.getLock(); - pa_context *context{connect_context(plock)}; + context = mainloop.connectContext(plock); - const pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | - PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE}; + constexpr pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | + PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE | PA_STREAM_START_CORKED}; pa_sample_spec spec{}; spec.format = PA_SAMPLE_S16NE; spec.rate = 44100; spec.channels = 2; - pa_stream *stream{pulse_connect_stream(nullptr, plock, context, flags, nullptr, &spec, - nullptr, BackendType::Playback)}; + stream = mainloop.connectStream(nullptr, plock, context, flags, nullptr, &spec, nullptr, + BackendType::Playback); pa_operation *op{pa_context_get_sink_info_by_name(context, - pa_stream_get_device_name(stream), device_sink_callback, nullptr)}; - wait_for_operation(op, plock); + pa_stream_get_device_name(stream), device_sink_callback, &mainloop)}; + mainloop.waitForOperation(op, plock); pa_stream_disconnect(stream); pa_stream_unref(stream); stream = nullptr; - op = pa_context_get_sink_info_list(context, device_sink_callback, nullptr); - wait_for_operation(op, plock); + op = pa_context_get_sink_info_list(context, device_sink_callback, &mainloop); + mainloop.waitForOperation(op, plock); pa_context_disconnect(context); pa_context_unref(context); + context = nullptr; } catch(std::exception &e) { ERR("Error enumerating devices: %s\n", e.what()); + if(context) mainloop.close(context, stream); } } -void device_source_callback(pa_context*, const pa_source_info *info, int eol, void*) noexcept +void device_source_callback(pa_context*, const pa_source_info *info, int eol, void *pdata) noexcept { if(eol) { - pulse_condvar.notify_all(); + static_cast(pdata)->getCondVar().notify_all(); return; } @@ -599,41 +634,45 @@ void device_source_callback(pa_context*, const pa_source_info *info, int eol, vo TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str()); } -void probeCaptureDevices() +void probeCaptureDevices(PulseMainloop &mainloop) { - CaptureDevices.clear(); + pa_context *context{}; + pa_stream *stream{}; + CaptureDevices.clear(); try { - std::unique_lock plock{pulse_lock}; + auto plock = mainloop.getLock(); - pa_context *context{connect_context(plock)}; + context = mainloop.connectContext(plock); - const pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | - PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE}; + constexpr pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | + PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE | PA_STREAM_START_CORKED}; pa_sample_spec spec{}; spec.format = PA_SAMPLE_S16NE; spec.rate = 44100; spec.channels = 1; - pa_stream *stream{pulse_connect_stream(nullptr, plock, context, flags, nullptr, &spec, nullptr, - BackendType::Capture)}; + stream = mainloop.connectStream(nullptr, plock, context, flags, nullptr, &spec, nullptr, + BackendType::Capture); pa_operation *op{pa_context_get_source_info_by_name(context, - pa_stream_get_device_name(stream), device_source_callback, nullptr)}; - wait_for_operation(op, plock); + pa_stream_get_device_name(stream), device_source_callback, &mainloop)}; + mainloop.waitForOperation(op, plock); pa_stream_disconnect(stream); pa_stream_unref(stream); stream = nullptr; - op = pa_context_get_source_info_list(context, device_source_callback, nullptr); - wait_for_operation(op, plock); + op = pa_context_get_source_info_list(context, device_source_callback, &mainloop); + mainloop.waitForOperation(op, plock); pa_context_disconnect(context); pa_context_unref(context); + context = nullptr; } catch(std::exception &e) { ERR("Error enumerating devices: %s\n", e.what()); + if(context) mainloop.close(context, stream); } } @@ -671,8 +710,10 @@ struct PulsePlayback final : public BackendBase { bool start() override; void stop() override; ClockLatency getClockLatency() override; - void lock() override { pulse_lock.lock(); } - void unlock() override { pulse_lock.unlock(); } + void lock() override { mMainloop.doLock(); } + void unlock() override { mMainloop.doUnlock(); } + + PulseMainloop mMainloop; std::string mDeviceName; @@ -692,7 +733,7 @@ PulsePlayback::~PulsePlayback() if(!mContext) return; - pulse_close(mContext, mStream); + mMainloop.close(mContext, mStream); mContext = nullptr; mStream = nullptr; } @@ -716,7 +757,7 @@ void PulsePlayback::streamStateCallback(pa_stream *stream) noexcept ERR("Received stream failure!\n"); aluHandleDisconnect(mDevice, "Playback stream failure"); } - pulse_condvar.notify_all(); + mMainloop.getCondVar().notify_all(); } void PulsePlayback::streamWriteCallback(pa_stream *stream, size_t nbytes) noexcept @@ -747,7 +788,7 @@ void PulsePlayback::sinkInfoCallback(pa_context*, const pa_sink_info *info, int if(eol) { - pulse_condvar.notify_all(); + mMainloop.getCondVar().notify_all(); return; } @@ -777,7 +818,7 @@ void PulsePlayback::sinkNameCallback(pa_context*, const pa_sink_info *info, int { if(eol) { - pulse_condvar.notify_all(); + mMainloop.getCondVar().notify_all(); return; } mDevice->DeviceName = info->description; @@ -798,7 +839,7 @@ void PulsePlayback::open(const ALCchar *name) if(name) { if(PlaybackDevices.empty()) - probePlaybackDevices(); + probePlaybackDevices(mMainloop); auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(), [name](const DevMap &entry) -> bool @@ -810,9 +851,9 @@ void PulsePlayback::open(const ALCchar *name) dev_name = iter->name.c_str(); } - std::unique_lock plock{pulse_lock}; + auto plock = mMainloop.getLock(); - mContext = connect_context(plock); + mContext = mMainloop.connectContext(plock); pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS}; @@ -830,7 +871,7 @@ void PulsePlayback::open(const ALCchar *name) if(defname) pulse_name = defname->c_str(); } TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); - mStream = pulse_connect_stream(pulse_name, plock, mContext, flags, nullptr, &spec, nullptr, + mStream = mMainloop.connectStream(pulse_name, plock, mContext, flags, nullptr, &spec, nullptr, BackendType::Playback); pa_stream_set_moved_callback(mStream, &PulsePlayback::streamMovedCallbackC, this); @@ -841,7 +882,7 @@ void PulsePlayback::open(const ALCchar *name) { pa_operation *op{pa_context_get_sink_info_by_name(mContext, mDeviceName.c_str(), &PulsePlayback::sinkNameCallbackC, this)}; - wait_for_operation(op, plock); + mMainloop.waitForOperation(op, plock); } else mDevice->DeviceName = dev_name; @@ -849,7 +890,7 @@ void PulsePlayback::open(const ALCchar *name) bool PulsePlayback::reset() { - std::unique_lock plock{pulse_lock}; + auto plock = mMainloop.getLock(); if(mStream) { @@ -864,7 +905,7 @@ bool PulsePlayback::reset() pa_operation *op{pa_context_get_sink_info_by_name(mContext, mDeviceName.c_str(), &PulsePlayback::sinkInfoCallbackC, this)}; - wait_for_operation(op, plock); + mMainloop.waitForOperation(op, plock); pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_EARLY_REQUESTS}; @@ -886,56 +927,56 @@ bool PulsePlayback::reset() pa_channel_map chanmap{}; switch(mDevice->FmtChans) { - case DevFmtMono: - chanmap = MonoChanMap; - break; - case DevFmtAmbi3D: - mDevice->FmtChans = DevFmtStereo; - /*fall-through*/ - case DevFmtStereo: - chanmap = StereoChanMap; - break; - case DevFmtQuad: - chanmap = QuadChanMap; - break; - case DevFmtX51: - chanmap = X51ChanMap; - break; - case DevFmtX51Rear: - chanmap = X51RearChanMap; - break; - case DevFmtX61: - chanmap = X61ChanMap; - break; - case DevFmtX71: - chanmap = X71ChanMap; - break; + case DevFmtMono: + chanmap = MonoChanMap; + break; + case DevFmtAmbi3D: + mDevice->FmtChans = DevFmtStereo; + /*fall-through*/ + case DevFmtStereo: + chanmap = StereoChanMap; + break; + case DevFmtQuad: + chanmap = QuadChanMap; + break; + case DevFmtX51: + chanmap = X51ChanMap; + break; + case DevFmtX51Rear: + chanmap = X51RearChanMap; + break; + case DevFmtX61: + chanmap = X61ChanMap; + break; + case DevFmtX71: + chanmap = X71ChanMap; + break; } SetChannelOrderFromMap(mDevice, chanmap); switch(mDevice->FmtType) { - case DevFmtByte: - mDevice->FmtType = DevFmtUByte; - /* fall-through */ - case DevFmtUByte: - mSpec.format = PA_SAMPLE_U8; - break; - case DevFmtUShort: - mDevice->FmtType = DevFmtShort; - /* fall-through */ - case DevFmtShort: - mSpec.format = PA_SAMPLE_S16NE; - break; - case DevFmtUInt: - mDevice->FmtType = DevFmtInt; - /* fall-through */ - case DevFmtInt: - mSpec.format = PA_SAMPLE_S32NE; - break; - case DevFmtFloat: - mSpec.format = PA_SAMPLE_FLOAT32NE; - break; + case DevFmtByte: + mDevice->FmtType = DevFmtUByte; + /* fall-through */ + case DevFmtUByte: + mSpec.format = PA_SAMPLE_U8; + break; + case DevFmtUShort: + mDevice->FmtType = DevFmtShort; + /* fall-through */ + case DevFmtShort: + mSpec.format = PA_SAMPLE_S16NE; + break; + case DevFmtUInt: + mDevice->FmtType = DevFmtInt; + /* fall-through */ + case DevFmtInt: + mSpec.format = PA_SAMPLE_S32NE; + break; + case DevFmtFloat: + mSpec.format = PA_SAMPLE_FLOAT32NE; + break; } mSpec.rate = mDevice->Frequency; mSpec.channels = static_cast(mDevice->channelsFromFmt()); @@ -949,7 +990,7 @@ bool PulsePlayback::reset() mAttr.minreq = mDevice->UpdateSize * frame_size; mAttr.fragsize = ~0u; - mStream = pulse_connect_stream(mDeviceName.c_str(), plock, mContext, flags, &mAttr, &mSpec, + mStream = mMainloop.connectStream(mDeviceName.c_str(), plock, mContext, flags, &mAttr, &mSpec, &chanmap, BackendType::Playback); pa_stream_set_state_callback(mStream, &PulsePlayback::streamStateCallbackC, this); @@ -974,8 +1015,9 @@ bool PulsePlayback::reset() mAttr.prebuf = 0u; mAttr.minreq = perlen * mFrameSize; - op = pa_stream_set_buffer_attr(mStream, &mAttr, stream_success_callback, nullptr); - wait_for_operation(op, plock); + op = pa_stream_set_buffer_attr(mStream, &mAttr, &PulseMainloop::streamSuccessCallbackC, + &mMainloop); + mMainloop.waitForOperation(op, plock); mDevice->Frequency = mSpec.rate; } @@ -991,22 +1033,24 @@ bool PulsePlayback::reset() bool PulsePlayback::start() { - std::unique_lock plock{pulse_lock}; + auto plock = mMainloop.getLock(); pa_stream_set_write_callback(mStream, &PulsePlayback::streamWriteCallbackC, this); - pa_operation *op{pa_stream_cork(mStream, 0, stream_success_callback, nullptr)}; - wait_for_operation(op, plock); + pa_operation *op{pa_stream_cork(mStream, 0, &PulseMainloop::streamSuccessCallbackC, + &mMainloop)}; + mMainloop.waitForOperation(op, plock); return true; } void PulsePlayback::stop() { - std::unique_lock plock{pulse_lock}; + auto plock = mMainloop.getLock(); + pa_operation *op{pa_stream_cork(mStream, 1, &PulseMainloop::streamSuccessCallbackC, + &mMainloop)}; + mMainloop.waitForOperation(op, plock); pa_stream_set_write_callback(mStream, nullptr, nullptr); - pa_operation *op{pa_stream_cork(mStream, 1, stream_success_callback, nullptr)}; - wait_for_operation(op, plock); } @@ -1017,7 +1061,7 @@ ClockLatency PulsePlayback::getClockLatency() int neg, err; { - std::lock_guard _{pulse_lock}; + auto _ = mMainloop.getLock(); ret.ClockTime = GetDeviceClockTime(mDevice); err = pa_stream_get_latency(mStream, &latency, &neg); } @@ -1063,8 +1107,10 @@ struct PulseCapture final : public BackendBase { ALCenum captureSamples(al::byte *buffer, ALCuint samples) override; ALCuint availableSamples() override; ClockLatency getClockLatency() override; - void lock() override { pulse_lock.lock(); } - void unlock() override { pulse_lock.unlock(); } + void lock() override { mMainloop.doLock(); } + void unlock() override { mMainloop.doUnlock(); } + + PulseMainloop mMainloop; std::string mDeviceName; @@ -1088,7 +1134,7 @@ PulseCapture::~PulseCapture() if(!mContext) return; - pulse_close(mContext, mStream); + mMainloop.close(mContext, mStream); mContext = nullptr; mStream = nullptr; } @@ -1101,14 +1147,14 @@ void PulseCapture::streamStateCallback(pa_stream *stream) noexcept ERR("Received stream failure!\n"); aluHandleDisconnect(mDevice, "Capture stream failure"); } - pulse_condvar.notify_all(); + mMainloop.getCondVar().notify_all(); } void PulseCapture::sourceNameCallback(pa_context*, const pa_source_info *info, int eol) noexcept { if(eol) { - pulse_condvar.notify_all(); + mMainloop.getCondVar().notify_all(); return; } mDevice->DeviceName = info->description; @@ -1127,7 +1173,7 @@ void PulseCapture::open(const ALCchar *name) if(name) { if(CaptureDevices.empty()) - probeCaptureDevices(); + probeCaptureDevices(mMainloop); auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(), [name](const DevMap &entry) -> bool @@ -1139,9 +1185,9 @@ void PulseCapture::open(const ALCchar *name) mDevice->DeviceName = iter->name; } - std::unique_lock plock{pulse_lock}; + auto plock = mMainloop.getLock(); - mContext = connect_context(plock); + mContext = mMainloop.connectContext(plock); pa_channel_map chanmap{}; switch(mDevice->FmtChans) @@ -1212,7 +1258,7 @@ void PulseCapture::open(const ALCchar *name) flags |= PA_STREAM_DONT_MOVE; TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); - mStream = pulse_connect_stream(pulse_name, plock, mContext, flags, &mAttr, &mSpec, &chanmap, + mStream = mMainloop.connectStream(pulse_name, plock, mContext, flags, &mAttr, &mSpec, &chanmap, BackendType::Capture); pa_stream_set_moved_callback(mStream, &PulseCapture::streamMovedCallbackC, this); @@ -1223,23 +1269,25 @@ void PulseCapture::open(const ALCchar *name) { pa_operation *op{pa_context_get_source_info_by_name(mContext, mDeviceName.c_str(), &PulseCapture::sourceNameCallbackC, this)}; - wait_for_operation(op, plock); + mMainloop.waitForOperation(op, plock); } } bool PulseCapture::start() { - std::unique_lock plock{pulse_lock}; - pa_operation *op{pa_stream_cork(mStream, 0, stream_success_callback, nullptr)}; - wait_for_operation(op, plock); + auto plock = mMainloop.getLock(); + pa_operation *op{pa_stream_cork(mStream, 0, &PulseMainloop::streamSuccessCallbackC, + &mMainloop)}; + mMainloop.waitForOperation(op, plock); return true; } void PulseCapture::stop() { - std::unique_lock plock{pulse_lock}; - pa_operation *op{pa_stream_cork(mStream, 1, stream_success_callback, nullptr)}; - wait_for_operation(op, plock); + auto plock = mMainloop.getLock(); + pa_operation *op{pa_stream_cork(mStream, 1, &PulseMainloop::streamSuccessCallbackC, + &mMainloop)}; + mMainloop.waitForOperation(op, plock); } ALCenum PulseCapture::captureSamples(al::byte *buffer, ALCuint samples) @@ -1267,7 +1315,7 @@ ALCenum PulseCapture::captureSamples(al::byte *buffer, ALCuint samples) if UNLIKELY(!mDevice->Connected.load(std::memory_order_acquire)) break; - std::unique_lock plock{pulse_lock}; + auto plock = mMainloop.getLock(); if(mCapLen != 0) { pa_stream_drop(mStream); @@ -1309,9 +1357,9 @@ ALCuint PulseCapture::availableSamples() if(mDevice->Connected.load(std::memory_order_acquire)) { - std::lock_guard _{pulse_lock}; + auto _ = mMainloop.getLock(); size_t got{pa_stream_readable_size(mStream)}; - if(static_cast(got) < 0) + if UNLIKELY(static_cast(got) < 0) { const char *err{pa_strerror(static_cast(got))}; ERR("pa_stream_readable_size() failed: %s\n", err); @@ -1337,7 +1385,7 @@ ClockLatency PulseCapture::getClockLatency() int neg, err; { - std::lock_guard _{pulse_lock}; + auto _ = mMainloop.getLock(); ret.ClockTime = GetDeviceClockTime(mDevice); err = pa_stream_get_latency(mStream, &latency, &neg); } @@ -1405,8 +1453,8 @@ bool PulseBackendFactory::init() pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN; try { - std::unique_lock plock{pulse_lock}; - pa_context *context{connect_context(plock)}; + auto plock = gGlobalMainloop.getLock(); + pa_context *context{gGlobalMainloop.connectContext(plock)}; pa_context_disconnect(context); pa_context_unref(context); return true; @@ -1428,17 +1476,18 @@ void PulseBackendFactory::probe(DevProbe type, std::string *outnames) */ outnames->append(entry.name.c_str(), entry.name.length()+1); }; + switch(type) { - case DevProbe::Playback: - probePlaybackDevices(); - std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); - break; + case DevProbe::Playback: + probePlaybackDevices(gGlobalMainloop); + std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); + break; - case DevProbe::Capture: - probeCaptureDevices(); - std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); - break; + case DevProbe::Capture: + probeCaptureDevices(gGlobalMainloop); + std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); + break; } } -- cgit v1.2.3 From 630d4d573dbe09828cb1b161581207ff53af4b52 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Oct 2019 13:33:27 -0700 Subject: Gracefully drain the OpenSL capture buffer on disconnect --- alc/backends/opensl.cpp | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index 4bba3455..a1fdccc7 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -869,9 +869,18 @@ void OpenSLCapture::stop() ALCenum OpenSLCapture::captureSamples(al::byte *buffer, ALCuint samples) { - SLAndroidSimpleBufferQueueItf bufferQueue; - SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue)}; - PRINTERR(result, "recordObj->GetInterface"); + SLAndroidSimpleBufferQueueItf bufferQueue{}; + if LIKELY(mDevice->Connected.load(std::memory_order_acquire)) + { + const SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &bufferQueue)}; + PRINTERR(result, "recordObj->GetInterface"); + if UNLIKELY(SL_RESULT_SUCCESS != result) + { + aluHandleDisconnect(mDevice, "Failed to get capture buffer queue: 0x%08x", result); + bufferQueue = nullptr; + } + } const ALuint update_size{mDevice->UpdateSize}; const ALuint chunk_size{update_size * mFrameSize}; @@ -890,11 +899,19 @@ ALCenum OpenSLCapture::captureSamples(al::byte *buffer, ALCuint samples) { /* Finished a chunk, reset the offset and advance the read pointer. */ mSplOffset = 0; - mRing->readAdvance(1); - result = VCALL(bufferQueue,Enqueue)(data.first.buf, chunk_size); - PRINTERR(result, "bufferQueue->Enqueue"); - if(SL_RESULT_SUCCESS != result) break; + + if LIKELY(bufferQueue) + { + const SLresult result{VCALL(bufferQueue,Enqueue)(data.first.buf, chunk_size)}; + PRINTERR(result, "bufferQueue->Enqueue"); + if UNLIKELY(SL_RESULT_SUCCESS != result) + { + aluHandleDisconnect(mDevice, "Failed to update capture buffer: 0x%08x", + result); + bufferQueue = nullptr; + } + } data.first.len--; if(!data.first.len) @@ -906,12 +923,6 @@ ALCenum OpenSLCapture::captureSamples(al::byte *buffer, ALCuint samples) i += rem; } - if UNLIKELY(SL_RESULT_SUCCESS != result) - { - aluHandleDisconnect(mDevice, "Failed to update capture buffer: 0x%08x", result); - return ALC_INVALID_DEVICE; - } - return ALC_NO_ERROR; } -- cgit v1.2.3 From e70f98c95afc61802b26795dbe8aeb20514a211b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 12 Oct 2019 16:41:13 -0700 Subject: Wrap the cycle amount when passing to sin() --- examples/altonegen.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/altonegen.c b/examples/altonegen.c index 26ae788d..553bc996 100644 --- a/examples/altonegen.c +++ b/examples/altonegen.c @@ -82,7 +82,10 @@ static void ApplySin(ALfloat *data, ALdouble g, ALuint srate, ALuint freq) ALdouble smps_per_cycle = (ALdouble)srate / freq; ALuint i; for(i = 0;i < srate;i++) - data[i] += (ALfloat)(sin(i/smps_per_cycle * 2.0*M_PI) * g); + { + ALdouble ival; + data[i] += (ALfloat)(sin(modf(i/smps_per_cycle, &ival) * 2.0*M_PI) * g); + } } /* Generates waveforms using additive synthesis. Each waveform is constructed -- cgit v1.2.3 From 33fd1f9efd46c056cd4348e76cd9048b37721c8b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 13 Oct 2019 09:37:07 -0700 Subject: Use better types for some specific sizes --- alc/alu.cpp | 30 +++++++++++++++--------------- alc/devformat.h | 17 +++++++++-------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/alc/alu.cpp b/alc/alu.cpp index 8c2ee164..5cd8c918 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -1654,11 +1654,11 @@ void ApplyDither(const al::span Samples, ALuint *dither_seed, * chokes on that given the inline specializations. */ template -inline T SampleConv(ALfloat) noexcept; +inline T SampleConv(float) noexcept; -template<> inline ALfloat SampleConv(ALfloat val) noexcept +template<> inline float SampleConv(float val) noexcept { return val; } -template<> inline ALint SampleConv(ALfloat val) noexcept +template<> inline int32_t SampleConv(float val) noexcept { /* Floats have a 23-bit mantissa, plus an implied 1 bit and a sign bit. * This means a normalized float has at most 25 bits of signed precision. @@ -1667,21 +1667,21 @@ template<> inline ALint SampleConv(ALfloat val) noexcept */ return fastf2i(clampf(val*2147483648.0f, -2147483648.0f, 2147483520.0f)); } -template<> inline ALshort SampleConv(ALfloat val) noexcept -{ return static_cast(fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f))); } -template<> inline ALbyte SampleConv(ALfloat val) noexcept -{ return static_cast(fastf2i(clampf(val*128.0f, -128.0f, 127.0f))); } +template<> inline int16_t SampleConv(float val) noexcept +{ return static_cast(fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f))); } +template<> inline int8_t SampleConv(float val) noexcept +{ return static_cast(fastf2i(clampf(val*128.0f, -128.0f, 127.0f))); } /* Define unsigned output variations. */ -template<> inline ALuint SampleConv(ALfloat val) noexcept -{ return static_cast(SampleConv(val)) + 2147483648u; } -template<> inline ALushort SampleConv(ALfloat val) noexcept -{ return static_cast(SampleConv(val) + 32768); } -template<> inline ALubyte SampleConv(ALfloat val) noexcept -{ return static_cast(SampleConv(val) + 128); } +template<> inline uint32_t SampleConv(float val) noexcept +{ return static_cast(SampleConv(val)) + 2147483648u; } +template<> inline uint16_t SampleConv(float val) noexcept +{ return static_cast(SampleConv(val) + 32768); } +template<> inline uint8_t SampleConv(float val) noexcept +{ return static_cast(SampleConv(val) + 128); } template -void Write(const al::span InBuffer, ALvoid *OutBuffer, const size_t Offset, +void Write(const al::span InBuffer, void *OutBuffer, const size_t Offset, const ALuint SamplesToDo) { using SampleType = typename DevFmtTypeTraits::Type; @@ -1694,7 +1694,7 @@ void Write(const al::span InBuffer, ALvoid *OutBuffer, co { ASSUME(SamplesToDo > 0); SampleType *out{outbase++}; - auto conv_sample = [numchans,&out](const ALfloat s) noexcept -> void + auto conv_sample = [numchans,&out](const float s) noexcept -> void { *out = SampleConv(s); out += numchans; diff --git a/alc/devformat.h b/alc/devformat.h index e7ff2ec4..402fb8bd 100644 --- a/alc/devformat.h +++ b/alc/devformat.h @@ -1,8 +1,9 @@ #ifndef ALC_DEVFORMAT_H #define ALC_DEVFORMAT_H +#include + #include "AL/al.h" -#include "AL/alc.h" #include "AL/alext.h" #include "inprogext.h" @@ -82,19 +83,19 @@ template struct DevFmtTypeTraits { }; template<> -struct DevFmtTypeTraits { using Type = ALbyte; }; +struct DevFmtTypeTraits { using Type = int8_t; }; template<> -struct DevFmtTypeTraits { using Type = ALubyte; }; +struct DevFmtTypeTraits { using Type = uint8_t; }; template<> -struct DevFmtTypeTraits { using Type = ALshort; }; +struct DevFmtTypeTraits { using Type = int16_t; }; template<> -struct DevFmtTypeTraits { using Type = ALushort; }; +struct DevFmtTypeTraits { using Type = uint16_t; }; template<> -struct DevFmtTypeTraits { using Type = ALint; }; +struct DevFmtTypeTraits { using Type = int32_t; }; template<> -struct DevFmtTypeTraits { using Type = ALuint; }; +struct DevFmtTypeTraits { using Type = uint32_t; }; template<> -struct DevFmtTypeTraits { using Type = ALfloat; }; +struct DevFmtTypeTraits { using Type = float; }; ALuint BytesFromDevFmt(DevFmtType type) noexcept; -- cgit v1.2.3 From f58167e72dbc2844a06358ccd78d579feb17532a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 14 Oct 2019 20:45:23 -0700 Subject: More sanely handle the voice state when mixing --- alc/voice.cpp | 30 ++++++++++++------------------ alc/voice.h | 2 +- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/alc/voice.cpp b/alc/voice.cpp index 7eb791d5..0aac0258 100644 --- a/alc/voice.cpp +++ b/alc/voice.cpp @@ -546,7 +546,7 @@ void DoNfcMix(ALvoice::TargetData &Direct, const float *TargetGains, DirectParam } // namespace -void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) +void ALvoice::mix(const State vstate, ALCcontext *Context, const ALuint SamplesToDo) { static constexpr std::array SilentTarget{}; @@ -778,30 +778,24 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) /* Handle non-looping static source */ if(DataPosInt >= BufferListItem->mSampleLen) { - if LIKELY(vstate == ALvoice::Playing) - vstate = ALvoice::Stopped; BufferListItem = nullptr; break; } } } - else while(1) + else { /* Handle streaming source */ - if(BufferListItem->mSampleLen > DataPosInt) - break; + do { + if(BufferListItem->mSampleLen > DataPosInt) + break; - DataPosInt -= BufferListItem->mSampleLen; + DataPosInt -= BufferListItem->mSampleLen; - ++buffers_done; - BufferListItem = BufferListItem->mNext.load(std::memory_order_relaxed); - if(!BufferListItem) BufferListItem = BufferLoopItem; - if(!BufferListItem) - { - if LIKELY(vstate == ALvoice::Playing) - vstate = ALvoice::Stopped; - break; - } + ++buffers_done; + BufferListItem = BufferListItem->mNext.load(std::memory_order_relaxed); + if(!BufferListItem) BufferListItem = BufferLoopItem; + } while(BufferListItem); } } while(OutPos < SamplesToDo); @@ -821,7 +815,7 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) mPosition.store(DataPosInt, std::memory_order_relaxed); mPositionFrac.store(DataPosFrac, std::memory_order_relaxed); mCurrentBuffer.store(BufferListItem, std::memory_order_relaxed); - if(vstate == ALvoice::Stopped) + if(!BufferListItem) { mLoopBuffer.store(nullptr, std::memory_order_relaxed); mSourceID.store(0u, std::memory_order_relaxed); @@ -844,7 +838,7 @@ void ALvoice::mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo) } } - if(vstate == ALvoice::Stopped) + if(!BufferListItem) { /* If the voice just ended, set it to Stopping so the next render * ensures any residual noise fades to 0 amplitude. diff --git a/alc/voice.h b/alc/voice.h index 206e2e6b..d6b624f9 100644 --- a/alc/voice.h +++ b/alc/voice.h @@ -287,7 +287,7 @@ struct ALvoice { return *this; } - void mix(State vstate, ALCcontext *Context, const ALuint SamplesToDo); + void mix(const State vstate, ALCcontext *Context, const ALuint SamplesToDo); }; #endif /* VOICE_H */ -- cgit v1.2.3 From fcde56e1fc2e16b2ac461fdc2e97a89adb82c6c6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 21 Oct 2019 11:30:39 -0700 Subject: Increase the max elevation and azimuth count for HRTFs --- alc/hrtf.cpp | 4 ++-- utils/makemhr/makemhr.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index b23f9d6f..7643ce44 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -88,10 +88,10 @@ using HrtfHandlePtr = std::unique_ptr; #define MAX_FD_DISTANCE (2.5f) #define MIN_EV_COUNT (5) -#define MAX_EV_COUNT (128) +#define MAX_EV_COUNT (181) #define MIN_AZ_COUNT (1) -#define MAX_AZ_COUNT (128) +#define MAX_AZ_COUNT (360) #define MAX_HRIR_DELAY (HRTF_HISTORY_LENGTH-1) diff --git a/utils/makemhr/makemhr.h b/utils/makemhr/makemhr.h index 24520bd2..5125b43c 100644 --- a/utils/makemhr/makemhr.h +++ b/utils/makemhr/makemhr.h @@ -11,13 +11,13 @@ // The limit to the number of 'distances' listed in the data set definition. #define MAX_FD_COUNT (16) -// The limits to the number of 'azimuths' listed in the data set definition. +// The limits to the number of 'elevations' listed in the data set definition. #define MIN_EV_COUNT (5) -#define MAX_EV_COUNT (128) +#define MAX_EV_COUNT (181) // The limits for each of the 'azimuths' listed in the data set definition. #define MIN_AZ_COUNT (1) -#define MAX_AZ_COUNT (128) +#define MAX_AZ_COUNT (360) // The limits for the 'distance' from source to listener for each field in // the definition file. -- cgit v1.2.3 From a8a3acb6f66da6b630e6d71b77cdbc2b23a4f552 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 Oct 2019 15:22:37 -0700 Subject: More consistently use doubles in makemhr and loadsofa --- utils/makemhr/loadsofa.cpp | 69 +++++++++++++++++++++++--------------------- utils/sofa-info.cpp | 71 +++++++++++++++++++++++++--------------------- 2 files changed, 75 insertions(+), 65 deletions(-) diff --git a/utils/makemhr/loadsofa.cpp b/utils/makemhr/loadsofa.cpp index e0c08349..49d16556 100644 --- a/utils/makemhr/loadsofa.cpp +++ b/utils/makemhr/loadsofa.cpp @@ -24,6 +24,7 @@ #include "loadsofa.h" #include +#include #include #include #include @@ -37,6 +38,8 @@ #include "mysofa.h" +using double3 = std::array; + static const char *SofaErrorStr(int err) { switch(err) @@ -57,18 +60,18 @@ static const char *SofaErrorStr(int err) * of other axes as necessary. The epsilons are used to constrain the * equality of unique elements. */ -static uint GetUniquelySortedElems(const uint m, const float *triplets, const uint axis, - const double *const (&filters)[3], const double (&epsilons)[3], float *elems) +static uint GetUniquelySortedElems(const uint m, const double3 *aers, const uint axis, + const double *const (&filters)[3], const double (&epsilons)[3], double *elems) { uint count{0u}; - for(uint i{0u};i < 3*m;i += 3) + for(uint i{0u};i < m;++i) { - const float elem{triplets[i + axis]}; + const double elem{aers[i][axis]}; uint j; for(j = 0;j < 3;j++) { - if(filters[j] && std::fabs(triplets[i + j] - *filters[j]) > epsilons[j]) + if(filters[j] && std::fabs(aers[i][j] - *filters[j]) > epsilons[j]) break; } if(j < 3) @@ -76,7 +79,7 @@ static uint GetUniquelySortedElems(const uint m, const float *triplets, const ui for(j = 0;j < count;j++) { - const float delta{elem - elems[j]}; + const double delta{elem - elems[j]}; if(delta > epsilons[axis]) continue; @@ -104,9 +107,9 @@ static uint GetUniquelySortedElems(const uint m, const float *triplets, const ui * half, but in degenerate cases this can fall to a minimum of 5 (the lower * limit on elevations necessary to build a layout). */ -static float GetUniformStepSize(const double epsilon, const uint m, const float *elems) +static double GetUniformStepSize(const double epsilon, const uint m, const double *elems) { - auto steps = std::vector(m, 0.0f); + auto steps = std::vector(m, 0.0); auto counts = std::vector(m, 0u); uint count{0u}; @@ -114,7 +117,7 @@ static float GetUniformStepSize(const double epsilon, const uint m, const float { for(uint i{0u};i < m-stride;i++) { - const float step{elems[i + stride] - elems[i]}; + const double step{elems[i + stride] - elems[i]}; uint j; for(j = 0;j < count;j++) @@ -151,7 +154,7 @@ static float GetUniformStepSize(const double epsilon, const uint m, const float if(counts[0] > 5) return steps[0]; - return 0.0f; + return 0.0; } /* Attempts to produce a compatible layout. Most data sets tend to be @@ -162,15 +165,16 @@ static float GetUniformStepSize(const double epsilon, const uint m, const float */ static bool PrepareLayout(const uint m, const float *xyzs, HrirDataT *hData) { - std::vector aers(3*m, 0.0f); - std::vector elems(m, 0.0f); + auto aers = std::vector(m, double3{}); + auto elems = std::vector(m, 0.0); - for(uint i{0u};i < 3*m;i += 3) + for(uint i{0u};i < m;++i) { - aers[i] = xyzs[i]; - aers[i + 1] = xyzs[i + 1]; - aers[i + 2] = xyzs[i + 2]; - mysofa_c2s(&aers[i]); + float aer[3]{xyzs[i*3], xyzs[i*3 + 1], xyzs[i*3 + 2]}; + mysofa_c2s(&aer[0]); + aers[i][0] = aer[0]; + aers[i][1] = aer[1]; + aers[i][2] = aer[2]; } const uint fdCount{GetUniquelySortedElems(m, aers.data(), 2, { nullptr, nullptr, nullptr }, @@ -183,7 +187,7 @@ static bool PrepareLayout(const uint m, const float *xyzs, HrirDataT *hData) double distances[MAX_FD_COUNT]{}; uint evCounts[MAX_FD_COUNT]{}; - auto azCounts = std::vector(MAX_FD_COUNT * MAX_EV_COUNT); + auto azCounts = std::vector(MAX_FD_COUNT*MAX_EV_COUNT, 0u); for(uint fi{0u};fi < fdCount;fi++) { distances[fi] = elems[fi]; @@ -211,8 +215,8 @@ static bool PrepareLayout(const uint m, const float *xyzs, HrirDataT *hData) return false; } - float step{GetUniformStepSize(0.1, evCount, elems.data())}; - if(step <= 0.0f) + double step{GetUniformStepSize(0.1, evCount, elems.data())}; + if(step <= 0.0) { fprintf(stderr, "Incompatible layout (non-uniform elevations).\n"); return false; @@ -221,18 +225,18 @@ static bool PrepareLayout(const uint m, const float *xyzs, HrirDataT *hData) uint evStart{0u}; for(uint ei{0u};ei < evCount;ei++) { - float ev{90.0f + elems[ei]}; - float eif{std::round(ev / step)}; + double ev{90.0 + elems[ei]}; + double eif{std::round(ev / step)}; const uint ei_start{static_cast(eif)}; - if(std::fabs(eif - static_cast(ei_start)) < (0.1f/step)) + if(std::fabs(eif - static_cast(ei_start)) < (0.1/step)) { evStart = ei_start; break; } } - evCount = static_cast(std::round(180.0f / step)) + 1; + evCount = static_cast(std::round(180.0 / step)) + 1; if(evCount < 5) { fprintf(stderr, "Incompatible layout (too few uniform elevations).\n"); @@ -247,22 +251,23 @@ static bool PrepareLayout(const uint m, const float *xyzs, HrirDataT *hData) const uint azCount{GetUniquelySortedElems(m, aers.data(), 0, { nullptr, &ev, &dist }, { 0.1, 0.1, 0.001 }, elems.data())}; - if(azCount > MAX_AZ_COUNT) - { - fprintf(stderr, "Incompatible layout (innumerable azimuths).\n"); - return false; - } - if(ei > 0 && ei < (evCount - 1)) { step = GetUniformStepSize(0.1, azCount, elems.data()); - if(step <= 0.0f) + if(step <= 0.0) { fprintf(stderr, "Incompatible layout (non-uniform azimuths).\n"); return false; } - azCounts[fi*MAX_EV_COUNT + ei] = static_cast(std::round(360.0f / step)); + azCounts[fi*MAX_EV_COUNT + ei] = static_cast(std::round(360.0 / step)); + if(azCounts[fi*MAX_EV_COUNT + ei] > MAX_AZ_COUNT) + { + fprintf(stderr, + "Incompatible layout (too many azimuths on elev=%f, rad=%f, %u > %u).\n", + ev, dist, azCounts[fi*MAX_EV_COUNT + ei], MAX_AZ_COUNT); + return false; + } } else if(azCount != 1) { diff --git a/utils/sofa-info.cpp b/utils/sofa-info.cpp index 32bef938..a0ed9ff4 100644 --- a/utils/sofa-info.cpp +++ b/utils/sofa-info.cpp @@ -23,6 +23,7 @@ #include +#include #include #include #include @@ -33,6 +34,7 @@ using uint = unsigned int; +using double3 = std::array; struct MySofaDeleter { void operator()(MYSOFA_HRTF *sofa) { mysofa_free(sofa); } @@ -41,7 +43,7 @@ using MySofaHrtfPtr = std::unique_ptr; // Per-field measurement info. struct HrirFdT { - float mDistance{0.0f}; + double mDistance{0.0}; uint mEvCount{0u}; uint mEvStart{0u}; std::vector mAzCounts; @@ -83,19 +85,18 @@ static void PrintSofaArray(const char *prefix, struct MYSOFA_ARRAY *array) * of other axes as necessary. The epsilons are used to constrain the * equality of unique elements. */ -static uint GetUniquelySortedElems(const uint m, const float *triplets, const uint axis, - const float *const (&filters)[3], const float (&epsilons)[3], - float *elems) +static uint GetUniquelySortedElems(const uint m, const double3 *aers, const uint axis, + const double *const (&filters)[3], const double (&epsilons)[3], double *elems) { uint count{0u}; - for(uint i{0u};i < 3*m;i += 3) + for(uint i{0u};i < m;++i) { - float elem = triplets[i + axis]; + const double elem{aers[i][axis]}; uint j; for(j = 0;j < 3;j++) { - if(filters[j] && std::fabs(triplets[i + j] - *filters[j]) > epsilons[j]) + if(filters[j] && std::fabs(aers[i][j] - *filters[j]) > epsilons[j]) break; } if(j < 3) @@ -103,7 +104,7 @@ static uint GetUniquelySortedElems(const uint m, const float *triplets, const ui for(j = 0;j < count;j++) { - const float delta{elem - elems[j]}; + const double delta{elem - elems[j]}; if(delta > epsilons[axis]) continue; @@ -131,17 +132,17 @@ static uint GetUniquelySortedElems(const uint m, const float *triplets, const ui * half, but in degenerate cases this can fall to a minimum of 5 (the lower * limit on elevations necessary to build a layout). */ -static float GetUniformStepSize(const float epsilon, const uint m, const float *elems) +static double GetUniformStepSize(const double epsilon, const uint m, const double *elems) { - std::vector steps(m, 0.0f); - std::vector counts(m, 0u); + auto steps = std::vector(m, 0.0); + auto counts = std::vector(m, 0u); uint count{0u}; for(uint stride{1u};stride < m/2;stride++) { for(uint i{0u};i < m-stride;i++) { - const float step{elems[i + stride] - elems[i]}; + const double step{elems[i + stride] - elems[i]}; uint j; for(j = 0;j < count;j++) @@ -178,7 +179,7 @@ static float GetUniformStepSize(const float epsilon, const uint m, const float * if(counts[0] > 5) return steps[0]; - return 0.0f; + return 0.0; } /* Attempts to produce a compatible layout. Most data sets tend to be @@ -189,20 +190,22 @@ static float GetUniformStepSize(const float epsilon, const uint m, const float * */ static void PrintCompatibleLayout(const uint m, const float *xyzs) { - std::vector aers(3*m, 0.0f); - std::vector elems(m, 0.0f); + auto aers = std::vector(m, double3{}); + auto elems = std::vector(m, {}); fprintf(stdout, "\n"); - for(uint i{0u};i < 3*m;i += 3) + for(uint i{0u};i < m;++i) { - aers[i] = xyzs[i]; - aers[i + 1] = xyzs[i + 1]; - aers[i + 2] = xyzs[i + 2]; - mysofa_c2s(&aers[i]); + float aer[3]{xyzs[i*3], xyzs[i*3 + 1], xyzs[i*3 + 2]}; + mysofa_c2s(&aer[0]); + aers[i][0] = aer[0]; + aers[i][1] = aer[1]; + aers[i][2] = aer[2]; } - uint fdCount{GetUniquelySortedElems(m, aers.data(), 2, { nullptr, nullptr, nullptr }, { 0.1f, 0.1f, 0.001f }, elems.data())}; + uint fdCount{GetUniquelySortedElems(m, aers.data(), 2, { nullptr, nullptr, nullptr }, + { 0.1, 0.1, 0.001 }, elems.data())}; if(fdCount > (m / 3)) { fprintf(stdout, "Incompatible layout (inumerable radii).\n"); @@ -215,8 +218,9 @@ static void PrintCompatibleLayout(const uint m, const float *xyzs) for(uint fi{0u};fi < fdCount;fi++) { - float dist{fds[fi].mDistance}; - uint evCount{GetUniquelySortedElems(m, aers.data(), 1, { nullptr, nullptr, &dist }, { 0.1f, 0.1f, 0.001f }, elems.data())}; + const double dist{fds[fi].mDistance}; + uint evCount{GetUniquelySortedElems(m, aers.data(), 1, { nullptr, nullptr, &dist }, + { 0.1, 0.1, 0.001 }, elems.data())}; if(evCount > (m / 3)) { @@ -224,8 +228,8 @@ static void PrintCompatibleLayout(const uint m, const float *xyzs) return; } - float step{GetUniformStepSize(0.1f, evCount, elems.data())}; - if(step <= 0.0f) + double step{GetUniformStepSize(0.1, evCount, elems.data())}; + if(step <= 0.0) { fprintf(stdout, "Incompatible layout (non-uniform elevations).\n"); return; @@ -234,18 +238,18 @@ static void PrintCompatibleLayout(const uint m, const float *xyzs) uint evStart{0u}; for(uint ei{0u};ei < evCount;ei++) { - float ev{90.0f + elems[ei]}; - float eif{std::round(ev / step)}; + double ev{90.0 + elems[ei]}; + double eif{std::round(ev / step)}; const uint ev_start{static_cast(eif)}; - if(std::fabs(eif - static_cast(ev_start)) < (0.1f/step)) + if(std::fabs(eif - static_cast(ev_start)) < (0.1/step)) { evStart = ev_start; break; } } - evCount = static_cast(std::round(180.0f / step)) + 1; + evCount = static_cast(std::round(180.0 / step)) + 1; if(evCount < 5) { fprintf(stdout, "Incompatible layout (too few uniform elevations).\n"); @@ -259,8 +263,9 @@ static void PrintCompatibleLayout(const uint m, const float *xyzs) for(uint ei{evStart};ei < evCount;ei++) { - float ev{-90.0f + static_cast(ei)*180.0f/static_cast(evCount - 1)}; - uint azCount{GetUniquelySortedElems(m, aers.data(), 0, { nullptr, &ev, &dist }, { 0.1f, 0.1f, 0.001f }, elems.data())}; + double ev{-90.0 + static_cast(ei)*180.0/static_cast(evCount - 1)}; + uint azCount{GetUniquelySortedElems(m, aers.data(), 0, { nullptr, &ev, &dist }, + { 0.1, 0.1, 0.001 }, elems.data())}; if(azCount > (m / 3)) { @@ -270,8 +275,8 @@ static void PrintCompatibleLayout(const uint m, const float *xyzs) if(ei > 0 && ei < (evCount - 1)) { - step = GetUniformStepSize(0.1f, azCount, elems.data()); - if(step <= 0.0f) + step = GetUniformStepSize(0.1, azCount, elems.data()); + if(step <= 0.0) { fprintf(stdout, "Incompatible layout (non-uniform azimuths).\n"); return; -- cgit v1.2.3 From 4733fc6f1e2ba1bcdaca9d7c1941b2abbf150b67 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 Oct 2019 15:23:17 -0700 Subject: Fix azimuth limit --- alc/hrtf.cpp | 2 +- utils/makemhr/makemhr.cpp | 8 +++++--- utils/makemhr/makemhr.h | 5 ++++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index 7643ce44..bfce69f5 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -91,7 +91,7 @@ using HrtfHandlePtr = std::unique_ptr; #define MAX_EV_COUNT (181) #define MIN_AZ_COUNT (1) -#define MAX_AZ_COUNT (360) +#define MAX_AZ_COUNT (255) #define MAX_HRIR_DELAY (HRTF_HISTORY_LENGTH-1) diff --git a/utils/makemhr/makemhr.cpp b/utils/makemhr/makemhr.cpp index 3659d40b..1e28ca4b 100644 --- a/utils/makemhr/makemhr.cpp +++ b/utils/makemhr/makemhr.cpp @@ -1462,10 +1462,12 @@ static void CalculateHrtds(const HeadModelT model, const double radius, HrirData for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) { - for(ti = 0;ti < channels;ti++) + for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) { - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - hData->mFds[fi].mEvs[ei].mAzs[ai].mDelays[ti] -= minHrtd; + HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; + + for(ti = 0;ti < channels;ti++) + azd->mDelays[ti] -= minHrtd; } } } diff --git a/utils/makemhr/makemhr.h b/utils/makemhr/makemhr.h index 5125b43c..ba19efbe 100644 --- a/utils/makemhr/makemhr.h +++ b/utils/makemhr/makemhr.h @@ -9,15 +9,18 @@ #define MAX_PATH_LEN (256) // The limit to the number of 'distances' listed in the data set definition. +// Must be less than 256 #define MAX_FD_COUNT (16) // The limits to the number of 'elevations' listed in the data set definition. +// Must be less than 256. #define MIN_EV_COUNT (5) #define MAX_EV_COUNT (181) // The limits for each of the 'azimuths' listed in the data set definition. +// Must be less than 256. #define MIN_AZ_COUNT (1) -#define MAX_AZ_COUNT (360) +#define MAX_AZ_COUNT (255) // The limits for the 'distance' from source to listener for each field in // the definition file. -- cgit v1.2.3 From 0dfdebdf6d2a27a7af666a64aab976c3ef2102b0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 Oct 2019 16:30:07 -0700 Subject: Limit the number of azimuths and elevations used in SOFA files --- utils/makemhr/loadsofa.cpp | 10 +++++++++- utils/sofa-info.cpp | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/utils/makemhr/loadsofa.cpp b/utils/makemhr/loadsofa.cpp index 49d16556..c91613c8 100644 --- a/utils/makemhr/loadsofa.cpp +++ b/utils/makemhr/loadsofa.cpp @@ -149,9 +149,17 @@ static double GetUniformStepSize(const double epsilon, const uint m, const doubl count = 1; if(counts[0] > m/2) - return steps[0]; + break; } + if(counts[0] > 255) + { + uint i{2u}; + while(counts[0]/i > 255 && (counts[0]%i) != 0) + ++i; + counts[0] /= i; + steps[0] *= i; + } if(counts[0] > 5) return steps[0]; return 0.0; diff --git a/utils/sofa-info.cpp b/utils/sofa-info.cpp index a0ed9ff4..bc5b709a 100644 --- a/utils/sofa-info.cpp +++ b/utils/sofa-info.cpp @@ -174,9 +174,17 @@ static double GetUniformStepSize(const double epsilon, const uint m, const doubl count = 1; if(counts[0] > m/2) - return steps[0]; + break; } + if(counts[0] > 255) + { + uint i{2u}; + while(counts[0]/i > 255 && (counts[0]%i) != 0) + ++i; + counts[0] /= i; + steps[0] *= i; + } if(counts[0] > 5) return steps[0]; return 0.0; -- cgit v1.2.3 From f40e69f9e3ee0020f3981120e1ce58cad37db746 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 23 Oct 2019 22:53:31 -0700 Subject: Use a 26-point Lebedev grid for the HRTF ambisonic decode --- alc/panning.cpp | 90 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 39 deletions(-) diff --git a/alc/panning.cpp b/alc/panning.cpp index df0b870a..3f42e783 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -523,55 +523,67 @@ void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, void InitHrtfPanning(ALCdevice *device) { static constexpr AngularPoint AmbiPoints[]{ + { Deg2Rad( 0.000000f), Deg2Rad( 0.000000f) }, + { Deg2Rad( 0.000000f), Deg2Rad( 180.000000f) }, + { Deg2Rad( 0.000000f), Deg2Rad( -90.000000f) }, + { Deg2Rad( 0.000000f), Deg2Rad( 90.000000f) }, + { Deg2Rad( 90.000000f), Deg2Rad( 0.000000f) }, + { Deg2Rad(-90.000000f), Deg2Rad( 0.000000f) }, + { Deg2Rad( 45.000000f), Deg2Rad( -90.000000f) }, + { Deg2Rad(-45.000000f), Deg2Rad( -90.000000f) }, + { Deg2Rad( 45.000000f), Deg2Rad( 90.000000f) }, + { Deg2Rad(-45.000000f), Deg2Rad( 90.000000f) }, + { Deg2Rad( 45.000000f), Deg2Rad( 0.000000f) }, + { Deg2Rad(-45.000000f), Deg2Rad( 0.000000f) }, + { Deg2Rad( 45.000000f), Deg2Rad( 180.000000f) }, + { Deg2Rad(-45.000000f), Deg2Rad( 180.000000f) }, + { Deg2Rad( 0.000000f), Deg2Rad( -45.000000f) }, + { Deg2Rad( 0.000000f), Deg2Rad( 45.000000f) }, + { Deg2Rad( 0.000000f), Deg2Rad(-135.000000f) }, + { Deg2Rad( 0.000000f), Deg2Rad( 135.000000f) }, { Deg2Rad( 35.264390f), Deg2Rad( -45.000000f) }, - { Deg2Rad( 35.264390f), Deg2Rad( 45.000000f) }, - { Deg2Rad( 35.264390f), Deg2Rad( 135.000000f) }, - { Deg2Rad( 35.264390f), Deg2Rad(-135.000000f) }, { Deg2Rad(-35.264390f), Deg2Rad( -45.000000f) }, + { Deg2Rad( 35.264390f), Deg2Rad( 45.000000f) }, { Deg2Rad(-35.264390f), Deg2Rad( 45.000000f) }, - { Deg2Rad(-35.264390f), Deg2Rad( 135.000000f) }, + { Deg2Rad( 35.264390f), Deg2Rad(-135.000000f) }, { Deg2Rad(-35.264390f), Deg2Rad(-135.000000f) }, - { Deg2Rad( 0.000000f), Deg2Rad( -20.905157f) }, - { Deg2Rad( 0.000000f), Deg2Rad( 20.905157f) }, - { Deg2Rad( 0.000000f), Deg2Rad( 159.094843f) }, - { Deg2Rad( 0.000000f), Deg2Rad(-159.094843f) }, - { Deg2Rad( 20.905157f), Deg2Rad( -90.000000f) }, - { Deg2Rad(-20.905157f), Deg2Rad( -90.000000f) }, - { Deg2Rad(-20.905157f), Deg2Rad( 90.000000f) }, - { Deg2Rad( 20.905157f), Deg2Rad( 90.000000f) }, - { Deg2Rad( 69.094843f), Deg2Rad( 0.000000f) }, - { Deg2Rad(-69.094843f), Deg2Rad( 0.000000f) }, - { Deg2Rad(-69.094843f), Deg2Rad( 180.000000f) }, - { Deg2Rad( 69.094843f), Deg2Rad( 180.000000f) }, + { Deg2Rad( 35.264390f), Deg2Rad( 135.000000f) }, + { Deg2Rad(-35.264390f), Deg2Rad( 135.000000f) }, }; static constexpr ALfloat AmbiMatrix[][MAX_AMBI_CHANNELS]{ - { 5.00000000e-02f, 5.00000000e-02f, 5.00000000e-02f, 5.00000000e-02f, 6.45497224e-02f, 6.45497224e-02f, 0.00000000e+00f, 6.45497224e-02f, 0.00000000e+00f, 1.48264644e-02f, 6.33865691e-02f, 1.01126676e-01f, -7.36485380e-02f, -1.09260065e-02f, 7.08683387e-02f, -1.01622099e-01f }, - { 5.00000000e-02f, -5.00000000e-02f, 5.00000000e-02f, 5.00000000e-02f, -6.45497224e-02f, -6.45497224e-02f, 0.00000000e+00f, 6.45497224e-02f, 0.00000000e+00f, -1.48264644e-02f, -6.33865691e-02f, -1.01126676e-01f, -7.36485380e-02f, -1.09260065e-02f, 7.08683387e-02f, -1.01622099e-01f }, - { 5.00000000e-02f, -5.00000000e-02f, 5.00000000e-02f, -5.00000000e-02f, 6.45497224e-02f, -6.45497224e-02f, 0.00000000e+00f, -6.45497224e-02f, 0.00000000e+00f, -1.48264644e-02f, 6.33865691e-02f, -1.01126676e-01f, -7.36485380e-02f, 1.09260065e-02f, 7.08683387e-02f, 1.01622099e-01f }, - { 5.00000000e-02f, 5.00000000e-02f, 5.00000000e-02f, -5.00000000e-02f, -6.45497224e-02f, 6.45497224e-02f, 0.00000000e+00f, -6.45497224e-02f, 0.00000000e+00f, 1.48264644e-02f, -6.33865691e-02f, 1.01126676e-01f, -7.36485380e-02f, 1.09260065e-02f, 7.08683387e-02f, 1.01622099e-01f }, - { 5.00000000e-02f, 5.00000000e-02f, -5.00000000e-02f, 5.00000000e-02f, 6.45497224e-02f, -6.45497224e-02f, 0.00000000e+00f, -6.45497224e-02f, 0.00000000e+00f, 1.48264644e-02f, -6.33865691e-02f, 1.01126676e-01f, 7.36485380e-02f, -1.09260065e-02f, -7.08683387e-02f, -1.01622099e-01f }, - { 5.00000000e-02f, -5.00000000e-02f, -5.00000000e-02f, 5.00000000e-02f, -6.45497224e-02f, 6.45497224e-02f, 0.00000000e+00f, -6.45497224e-02f, 0.00000000e+00f, -1.48264644e-02f, 6.33865691e-02f, -1.01126676e-01f, 7.36485380e-02f, -1.09260065e-02f, -7.08683387e-02f, -1.01622099e-01f }, - { 5.00000000e-02f, -5.00000000e-02f, -5.00000000e-02f, -5.00000000e-02f, 6.45497224e-02f, 6.45497224e-02f, 0.00000000e+00f, 6.45497224e-02f, 0.00000000e+00f, -1.48264644e-02f, -6.33865691e-02f, -1.01126676e-01f, 7.36485380e-02f, 1.09260065e-02f, -7.08683387e-02f, 1.01622099e-01f }, - { 5.00000000e-02f, 5.00000000e-02f, -5.00000000e-02f, -5.00000000e-02f, -6.45497224e-02f, -6.45497224e-02f, 0.00000000e+00f, 6.45497224e-02f, 0.00000000e+00f, 1.48264644e-02f, 6.33865691e-02f, 1.01126676e-01f, 7.36485380e-02f, 1.09260065e-02f, -7.08683387e-02f, 1.01622099e-01f }, - { 5.00000000e-02f, 3.09016994e-02f, 0.00000000e+00f, 8.09016994e-02f, 6.45497224e-02f, 0.00000000e+00f, -5.59016994e-02f, 0.00000000e+00f, 7.21687836e-02f, 7.76323754e-02f, 0.00000000e+00f, -1.49775925e-01f, 0.00000000e+00f, -2.95083663e-02f, 0.00000000e+00f, 7.76323754e-02f }, - { 5.00000000e-02f, -3.09016994e-02f, 0.00000000e+00f, 8.09016994e-02f, -6.45497224e-02f, 0.00000000e+00f, -5.59016994e-02f, 0.00000000e+00f, 7.21687836e-02f, -7.76323754e-02f, 0.00000000e+00f, 1.49775925e-01f, 0.00000000e+00f, -2.95083663e-02f, 0.00000000e+00f, 7.76323754e-02f }, - { 5.00000000e-02f, -3.09016994e-02f, 0.00000000e+00f, -8.09016994e-02f, 6.45497224e-02f, 0.00000000e+00f, -5.59016994e-02f, 0.00000000e+00f, 7.21687836e-02f, -7.76323754e-02f, 0.00000000e+00f, 1.49775925e-01f, 0.00000000e+00f, 2.95083663e-02f, 0.00000000e+00f, -7.76323754e-02f }, - { 5.00000000e-02f, 3.09016994e-02f, 0.00000000e+00f, -8.09016994e-02f, -6.45497224e-02f, 0.00000000e+00f, -5.59016994e-02f, 0.00000000e+00f, 7.21687836e-02f, 7.76323754e-02f, 0.00000000e+00f, -1.49775925e-01f, 0.00000000e+00f, 2.95083663e-02f, 0.00000000e+00f, -7.76323754e-02f }, - { 5.00000000e-02f, 8.09016994e-02f, 3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 6.45497224e-02f, -3.45491503e-02f, 0.00000000e+00f, -8.44966837e-02f, -4.79794466e-02f, 0.00000000e+00f, -6.77901327e-02f, 3.03448665e-02f, 0.00000000e+00f, -1.65948192e-01f, 0.00000000e+00f }, - { 5.00000000e-02f, 8.09016994e-02f, -3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, -6.45497224e-02f, -3.45491503e-02f, 0.00000000e+00f, -8.44966837e-02f, -4.79794466e-02f, 0.00000000e+00f, -6.77901327e-02f, -3.03448665e-02f, 0.00000000e+00f, 1.65948192e-01f, 0.00000000e+00f }, - { 5.00000000e-02f, -8.09016994e-02f, -3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 6.45497224e-02f, -3.45491503e-02f, 0.00000000e+00f, -8.44966837e-02f, 4.79794466e-02f, 0.00000000e+00f, 6.77901327e-02f, -3.03448665e-02f, 0.00000000e+00f, 1.65948192e-01f, 0.00000000e+00f }, - { 5.00000000e-02f, -8.09016994e-02f, 3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, -6.45497224e-02f, -3.45491503e-02f, 0.00000000e+00f, -8.44966837e-02f, 4.79794466e-02f, 0.00000000e+00f, 6.77901327e-02f, 3.03448665e-02f, 0.00000000e+00f, -1.65948192e-01f, 0.00000000e+00f }, - { 5.00000000e-02f, 0.00000000e+00f, 8.09016994e-02f, 3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 9.04508497e-02f, 6.45497224e-02f, 1.23279000e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 7.94438918e-02f, 1.12611206e-01f, -2.42115150e-02f, 1.25611822e-01f }, - { 5.00000000e-02f, 0.00000000e+00f, -8.09016994e-02f, 3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 9.04508497e-02f, -6.45497224e-02f, 1.23279000e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -7.94438918e-02f, 1.12611206e-01f, 2.42115150e-02f, 1.25611822e-01f }, - { 5.00000000e-02f, 0.00000000e+00f, -8.09016994e-02f, -3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 9.04508497e-02f, 6.45497224e-02f, 1.23279000e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -7.94438918e-02f, -1.12611206e-01f, 2.42115150e-02f, -1.25611822e-01f }, - { 5.00000000e-02f, 0.00000000e+00f, 8.09016994e-02f, -3.09016994e-02f, 0.00000000e+00f, 0.00000000e+00f, 9.04508497e-02f, -6.45497224e-02f, 1.23279000e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 7.94438918e-02f, -1.12611206e-01f, -2.42115150e-02f, -1.25611822e-01f } + { 3.84615387e-02f, 0.00000000e+00f, 0.00000000e+00f, 8.33950391e-02f, 0.00000000e+00f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 8.60662966e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -7.49473409e-02f, 0.00000000e+00f, 9.67566016e-02f }, + { 3.84615387e-02f, 0.00000000e+00f, 0.00000000e+00f, -8.33950391e-02f, 0.00000000e+00f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 8.60662966e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 7.49473409e-02f, 0.00000000e+00f, -9.67566016e-02f }, + { 3.84615387e-02f, 8.33950391e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, -8.60662966e-02f, -9.67566016e-02f, 0.00000000e+00f, -7.49473409e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + { 3.84615387e-02f, -8.33950391e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, -8.60662966e-02f, 9.67566016e-02f, 0.00000000e+00f, 7.49473409e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + { 3.84615379e-02f, 0.00000000e+00f, 8.33950384e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 9.93807988e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 1.22388497e-01f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + { 3.84615379e-02f, 0.00000000e+00f, -8.33950384e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 9.93807988e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -1.22388497e-01f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + { 3.84615383e-02f, 4.53609209e-02f, 4.53609209e-02f, 0.00000000e+00f, 0.00000000e+00f, 6.83467647e-02f, 2.48451995e-02f, 0.00000000e+00f, -4.30331483e-02f, -3.21963528e-02f, 0.00000000e+00f, 6.23479680e-02f, -1.27267260e-02f, 0.00000000e+00f, -6.90065559e-02f, 0.00000000e+00f }, + { 3.84615383e-02f, 4.53609209e-02f, -4.53609209e-02f, 0.00000000e+00f, 0.00000000e+00f, -6.83467647e-02f, 2.48451995e-02f, 0.00000000e+00f, -4.30331483e-02f, -3.21963528e-02f, 0.00000000e+00f, 6.23479680e-02f, 1.27267260e-02f, 0.00000000e+00f, 6.90065559e-02f, 0.00000000e+00f }, + { 3.84615383e-02f, -4.53609209e-02f, 4.53609209e-02f, 0.00000000e+00f, 0.00000000e+00f, -6.83467647e-02f, 2.48451995e-02f, 0.00000000e+00f, -4.30331483e-02f, 3.21963528e-02f, 0.00000000e+00f, -6.23479680e-02f, -1.27267260e-02f, 0.00000000e+00f, -6.90065559e-02f, 0.00000000e+00f }, + { 3.84615383e-02f, -4.53609209e-02f, -4.53609209e-02f, 0.00000000e+00f, 0.00000000e+00f, 6.83467647e-02f, 2.48451995e-02f, 0.00000000e+00f, -4.30331483e-02f, 3.21963528e-02f, 0.00000000e+00f, -6.23479680e-02f, 1.27267260e-02f, 0.00000000e+00f, 6.90065559e-02f, 0.00000000e+00f }, + { 3.84615383e-02f, 0.00000000e+00f, 4.53609209e-02f, 4.53609209e-02f, 0.00000000e+00f, 0.00000000e+00f, 2.48451995e-02f, 6.83467647e-02f, 4.30331483e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -1.27267260e-02f, 6.23479680e-02f, 6.90065559e-02f, 3.21963528e-02f }, + { 3.84615383e-02f, 0.00000000e+00f, -4.53609209e-02f, 4.53609209e-02f, 0.00000000e+00f, 0.00000000e+00f, 2.48451995e-02f, -6.83467647e-02f, 4.30331483e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 1.27267260e-02f, 6.23479680e-02f, -6.90065559e-02f, 3.21963528e-02f }, + { 3.84615383e-02f, 0.00000000e+00f, 4.53609209e-02f, -4.53609209e-02f, 0.00000000e+00f, 0.00000000e+00f, 2.48451995e-02f, -6.83467647e-02f, 4.30331483e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -1.27267260e-02f, -6.23479680e-02f, 6.90065559e-02f, -3.21963528e-02f }, + { 3.84615383e-02f, 0.00000000e+00f, -4.53609209e-02f, -4.53609209e-02f, 0.00000000e+00f, 0.00000000e+00f, 2.48451995e-02f, 6.83467647e-02f, 4.30331483e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 1.27267260e-02f, -6.23479680e-02f, -6.90065559e-02f, -3.21963528e-02f }, + { 3.84615387e-02f, 4.53609217e-02f, 0.00000000e+00f, 4.53609217e-02f, 6.83467654e-02f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 0.00000000e+00f, 5.23190735e-02f, 0.00000000e+00f, -4.67609766e-02f, 0.00000000e+00f, -4.67609766e-02f, 0.00000000e+00f, -5.23190735e-02f }, + { 3.84615387e-02f, -4.53609217e-02f, 0.00000000e+00f, 4.53609217e-02f, -6.83467654e-02f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 0.00000000e+00f, -5.23190735e-02f, 0.00000000e+00f, 4.67609766e-02f, 0.00000000e+00f, -4.67609766e-02f, 0.00000000e+00f, -5.23190735e-02f }, + { 3.84615387e-02f, 4.53609217e-02f, 0.00000000e+00f, -4.53609217e-02f, -6.83467654e-02f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 0.00000000e+00f, 5.23190735e-02f, 0.00000000e+00f, -4.67609766e-02f, 0.00000000e+00f, 4.67609766e-02f, 0.00000000e+00f, 5.23190735e-02f }, + { 3.84615387e-02f, -4.53609217e-02f, 0.00000000e+00f, -4.53609217e-02f, 6.83467654e-02f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 0.00000000e+00f, -5.23190735e-02f, 0.00000000e+00f, 4.67609766e-02f, 0.00000000e+00f, 4.67609766e-02f, 0.00000000e+00f, 5.23190735e-02f }, + { 3.84615385e-02f, 3.33333332e-02f, 3.33333335e-02f, 3.33333332e-02f, 4.55645099e-02f, 4.55645100e-02f, 5.38752469e-10f, 4.55645100e-02f, 0.00000000e+00f, 2.95742381e-02f, 6.33865691e-02f, 2.29081068e-02f, -3.74087810e-02f, 2.29081068e-02f, 0.00000000e+00f, -2.95742381e-02f }, + { 3.84615385e-02f, 3.33333332e-02f, -3.33333335e-02f, 3.33333332e-02f, 4.55645099e-02f, -4.55645100e-02f, 5.38752469e-10f, -4.55645100e-02f, 0.00000000e+00f, 2.95742381e-02f, -6.33865691e-02f, 2.29081068e-02f, 3.74087810e-02f, 2.29081068e-02f, 4.53051106e-20f, -2.95742381e-02f }, + { 3.84615385e-02f, -3.33333332e-02f, 3.33333335e-02f, 3.33333332e-02f, -4.55645099e-02f, -4.55645100e-02f, 5.38752452e-10f, 4.55645100e-02f, 0.00000000e+00f, -2.95742381e-02f, -6.33865691e-02f, -2.29081068e-02f, -3.74087810e-02f, 2.29081068e-02f, 0.00000000e+00f, -2.95742381e-02f }, + { 3.84615385e-02f, -3.33333332e-02f, -3.33333335e-02f, 3.33333332e-02f, -4.55645099e-02f, 4.55645100e-02f, 5.38752451e-10f, -4.55645100e-02f, 0.00000000e+00f, -2.95742381e-02f, 6.33865691e-02f, -2.29081068e-02f, 3.74087810e-02f, 2.29081068e-02f, 0.00000000e+00f, -2.95742381e-02f }, + { 3.84615385e-02f, 3.33333332e-02f, 3.33333335e-02f, -3.33333332e-02f, -4.55645099e-02f, 4.55645100e-02f, 5.38752451e-10f, -4.55645100e-02f, 0.00000000e+00f, 2.95742381e-02f, -6.33865691e-02f, 2.29081068e-02f, -3.74087810e-02f, -2.29081068e-02f, 0.00000000e+00f, 2.95742381e-02f }, + { 3.84615385e-02f, 3.33333332e-02f, -3.33333335e-02f, -3.33333332e-02f, -4.55645099e-02f, -4.55645100e-02f, 5.38752451e-10f, 4.55645100e-02f, 0.00000000e+00f, 2.95742381e-02f, 6.33865691e-02f, 2.29081068e-02f, 3.74087810e-02f, -2.29081068e-02f, 0.00000000e+00f, 2.95742381e-02f }, + { 3.84615385e-02f, -3.33333332e-02f, 3.33333335e-02f, -3.33333332e-02f, 4.55645099e-02f, -4.55645100e-02f, 5.38752428e-10f, -4.55645100e-02f, 0.00000000e+00f, -2.95742381e-02f, 6.33865691e-02f, -2.29081068e-02f, -3.74087810e-02f, -2.29081068e-02f, 0.00000000e+00f, 2.95742381e-02f }, + { 3.84615385e-02f, -3.33333332e-02f, -3.33333335e-02f, -3.33333332e-02f, 4.55645099e-02f, 4.55645100e-02f, 5.38752429e-10f, 4.55645100e-02f, 0.00000000e+00f, -2.95742381e-02f, -6.33865691e-02f, -2.29081068e-02f, 3.74087810e-02f, -2.29081068e-02f, 0.00000000e+00f, 2.95742381e-02f }, }; static constexpr ALfloat AmbiOrderHFGain1O[MAX_AMBI_ORDER+1]{ - 3.16227766e+00f, 1.82574186e+00f + 3.60555128e+00f, 2.08166600e+00f }, AmbiOrderHFGain2O[MAX_AMBI_ORDER+1]{ - 2.35702260e+00f, 1.82574186e+00f, 9.42809042e-01f + 2.68741925e+00f, 2.08166600e+00f, 1.07496770e+00f }, AmbiOrderHFGain3O[MAX_AMBI_ORDER+1]{ - 1.86508671e+00f, 1.60609389e+00f, 1.14205530e+00f, 5.68379553e-01f + 2.12652604e+00f, 1.83122879e+00f, 1.30214339e+00f, 6.48052398e-01f }; static constexpr ALuint ChansPerOrder[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; const ALfloat *AmbiOrderHFGain{AmbiOrderHFGain1O}; -- cgit v1.2.3 From 7bed2fe7ccd2abaa090a4096bad56f220ce1565e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 24 Oct 2019 14:33:43 -0700 Subject: Report the real ambisonic order set for HRTF rendering --- alc/panning.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/alc/panning.cpp b/alc/panning.cpp index 3f42e783..aa30a71c 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -627,11 +627,12 @@ void InitHrtfPanning(ALCdevice *device) ambi_order = iter->order; } } - TRACE("%s HRTF rendering enabled, using \"%s\"\n", - (device->mRenderMode == HrtfRender) ? "Full" : - (ambi_order >= 3) ? "Third-Order" : - (ambi_order == 2) ? "Second-Order" : - (ambi_order == 1) ? "First-Order" : "Unknown", + TRACE("%u%s order %sHRTF rendering enabled, using \"%s\"\n", ambi_order, + (((ambi_order%100)/10) == 1) ? "th" : + ((ambi_order%10) == 1) ? "st" : + ((ambi_order%10) == 2) ? "nd" : + ((ambi_order%10) == 3) ? "rd" : "th", + (device->mRenderMode == HrtfRender) ? "+ Full " : "", device->HrtfName.c_str()); if(ambi_order >= 3) -- cgit v1.2.3 From f0977e5cc9f89daf707032514ca712586376c312 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 24 Oct 2019 15:10:37 -0700 Subject: Print the found file entries after sorting --- alc/helpers.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/alc/helpers.cpp b/alc/helpers.cpp index 0e2dc067..bd0754b8 100644 --- a/alc/helpers.cpp +++ b/alc/helpers.cpp @@ -71,6 +71,7 @@ #include "alcmain.h" #include "almalloc.h" #include "alfstream.h" +#include "alspan.h" #include "alstring.h" #include "compat.h" #include "cpu_caps.h" @@ -325,18 +326,22 @@ static void DirectorySearch(const char *path, const char *ext, al::vectorsize(); + const auto base = results->cend() - results->cbegin(); + do { results->emplace_back(); std::string &str = results->back(); str = path; str += '\\'; str += wstr_to_utf8(fdata.cFileName); - TRACE(" got %s\n", str.c_str()); } while(FindNextFileW(hdl, &fdata)); FindClose(hdl); - std::sort(results->begin()+base, results->end()); + const al::span newlist{std::addressof(*(results->begin()+base)), + std::addressof(*results->end())}; + std::sort(newlist.begin(), newlist.end()); + for(const auto &name : newlist) + TRACE(" got %s\n", name.c_str()); } } @@ -516,7 +521,7 @@ static void DirectorySearch(const char *path, const char *ext, al::vectorcend() - results->cbegin(); + const auto base = results->cend() - results->cbegin(); const size_t extlen{strlen(ext)}; struct dirent *dirent; @@ -525,7 +530,7 @@ static void DirectorySearch(const char *path, const char *ext, al::vectord_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) continue; - size_t len{strlen(dirent->d_name)}; + const size_t len{strlen(dirent->d_name)}; if(len <= extlen) continue; if(al::strcasecmp(dirent->d_name+len-extlen, ext) != 0) continue; @@ -536,11 +541,14 @@ static void DirectorySearch(const char *path, const char *ext, al::vectord_name; - TRACE(" got %s\n", str.c_str()); } closedir(dir); - std::sort(results->begin()+base, results->end()); + const al::span newlist{std::addressof(*(results->begin()+base)), + std::addressof(*results->end())}; + std::sort(newlist.begin(), newlist.end()); + for(const auto &name : newlist) + TRACE(" got %s\n", name.c_str()); } } -- cgit v1.2.3 From 48347f62b52e4f88fddbe8ca25e662abddb9804e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 24 Oct 2019 15:28:28 -0700 Subject: Don't trace twice for a new HRTF data file --- alc/hrtf.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index bfce69f5..fa0085ff 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -1129,9 +1129,10 @@ void AddFileEntry(al::vector &list, const std::string &filename) break; } + const char *new_mark{""}; if(loaded_entry == LoadedHrtfs.end()) { - TRACE("Got new file \"%s\"\n", filename.c_str()); + new_mark = " (new)"; LoadedHrtfs.emplace_back(HrtfHandle::Create(filename.length()+1)); loaded_entry = LoadedHrtfs.end()-1; @@ -1160,7 +1161,7 @@ void AddFileEntry(al::vector &list, const std::string &filename) list.emplace_back(EnumeratedHrtf{newname, loaded_entry->get()}); const EnumeratedHrtf &entry = list.back(); - TRACE("Adding file entry \"%s\"\n", entry.name.c_str()); + TRACE("Adding file entry \"%s\"%s\n", entry.name.c_str(), new_mark); } /* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer @@ -1188,9 +1189,10 @@ void AddBuiltInEntry(al::vector &list, const std::string &filena break; } + const char *new_mark{""}; if(loaded_entry == LoadedHrtfs.end()) { - TRACE("Got new file \"%s\"\n", filename.c_str()); + new_mark = " (new)"; LoadedHrtfs.emplace_back(HrtfHandle::Create(filename.length()+32)); loaded_entry = LoadedHrtfs.end()-1; @@ -1212,7 +1214,7 @@ void AddBuiltInEntry(al::vector &list, const std::string &filena list.emplace_back(EnumeratedHrtf{newname, loaded_entry->get()}); const EnumeratedHrtf &entry = list.back(); - TRACE("Adding built-in entry \"%s\"\n", entry.name.c_str()); + TRACE("Adding built-in entry \"%s\"%s\n", entry.name.c_str(), new_mark); } -- cgit v1.2.3 From 5ac1f192419a5d1d435a0f8703560823075799af Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 24 Oct 2019 21:58:35 -0700 Subject: Don't dereference the end iterator --- alc/helpers.cpp | 88 +++++++++++++++++++++++++++------------------------------ 1 file changed, 42 insertions(+), 46 deletions(-) diff --git a/alc/helpers.cpp b/alc/helpers.cpp index bd0754b8..25b2e4a2 100644 --- a/alc/helpers.cpp +++ b/alc/helpers.cpp @@ -324,25 +324,23 @@ static void DirectorySearch(const char *path, const char *ext, al::vectorcend() - results->cbegin(); - - do { - results->emplace_back(); - std::string &str = results->back(); - str = path; - str += '\\'; - str += wstr_to_utf8(fdata.cFileName); - } while(FindNextFileW(hdl, &fdata)); - FindClose(hdl); - - const al::span newlist{std::addressof(*(results->begin()+base)), - std::addressof(*results->end())}; - std::sort(newlist.begin(), newlist.end()); - for(const auto &name : newlist) - TRACE(" got %s\n", name.c_str()); - } + if(hdl == INVALID_HANDLE_VALUE) return; + + const auto base = results->size(); + + do { + results->emplace_back(); + std::string &str = results->back(); + str = path; + str += '\\'; + str += wstr_to_utf8(fdata.cFileName); + } while(FindNextFileW(hdl, &fdata)); + FindClose(hdl); + + const al::span newlist{results->data()+base, results->size()-base}; + std::sort(newlist.begin(), newlist.end()); + for(const auto &name : newlist) + TRACE(" got %s\n", name.c_str()); } al::vector SearchDataFiles(const char *ext, const char *subdir) @@ -519,37 +517,35 @@ static void DirectorySearch(const char *path, const char *ext, al::vectorsize(); + const size_t extlen{strlen(ext)}; + + struct dirent *dirent; + while((dirent=readdir(dir)) != nullptr) { - const auto base = results->cend() - results->cbegin(); - const size_t extlen{strlen(ext)}; + if(strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) + continue; - struct dirent *dirent; - while((dirent=readdir(dir)) != nullptr) - { - if(strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) - continue; - - const size_t len{strlen(dirent->d_name)}; - if(len <= extlen) continue; - if(al::strcasecmp(dirent->d_name+len-extlen, ext) != 0) - continue; - - results->emplace_back(); - std::string &str = results->back(); - str = path; - if(str.back() != '/') - str.push_back('/'); - str += dirent->d_name; - } - closedir(dir); + const size_t len{strlen(dirent->d_name)}; + if(len <= extlen) continue; + if(al::strcasecmp(dirent->d_name+len-extlen, ext) != 0) + continue; - const al::span newlist{std::addressof(*(results->begin()+base)), - std::addressof(*results->end())}; - std::sort(newlist.begin(), newlist.end()); - for(const auto &name : newlist) - TRACE(" got %s\n", name.c_str()); + results->emplace_back(); + std::string &str = results->back(); + str = path; + if(str.back() != '/') + str.push_back('/'); + str += dirent->d_name; } + closedir(dir); + + const al::span newlist{results->data()+base, results->size()-base}; + std::sort(newlist.begin(), newlist.end()); + for(const auto &name : newlist) + TRACE(" got %s\n", name.c_str()); } al::vector SearchDataFiles(const char *ext, const char *subdir) -- cgit v1.2.3 From 0cba99ed1bc2712c15c17f0940127e6f84395729 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 25 Oct 2019 01:43:23 -0700 Subject: Avoid static constexpr for arrays iterated over at run-time --- al/buffer.cpp | 2 +- al/source.cpp | 12 +++++------- al/state.cpp | 2 +- alc/alc.cpp | 6 +++--- alc/alu.cpp | 2 +- alc/helpers.cpp | 2 +- alc/hrtf.cpp | 6 +++--- alc/panning.cpp | 20 ++++++++++---------- common/alnumeric.h | 2 +- 9 files changed, 26 insertions(+), 28 deletions(-) diff --git a/al/buffer.cpp b/al/buffer.cpp index c9e195d1..8f4228a8 100644 --- a/al/buffer.cpp +++ b/al/buffer.cpp @@ -557,7 +557,7 @@ al::optional DecomposeUserFormat(ALenum format) UserFmtChannels channels; UserFmtType type; }; - static constexpr std::array UserFmtList{{ + static const std::array UserFmtList{{ { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte }, { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort }, { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat }, diff --git a/al/source.cpp b/al/source.cpp index 6d15f73a..8b8e6382 100644 --- a/al/source.cpp +++ b/al/source.cpp @@ -2808,20 +2808,18 @@ START_API_FUNC const ALuint *OrderFromChan; if(voice->mFmtChannels == FmtBFormat2D) { - static constexpr ALuint Order2DFromChan[MAX_AMBI2D_CHANNELS]{ - 0, 1,1, 2,2, 3,3 - }; + static const ALuint Order2DFromChan[MAX_AMBI2D_CHANNELS]{ + 0, 1,1, 2,2, 3,3,}; OrderFromChan = Order2DFromChan; } else { - static constexpr ALuint Order3DFromChan[MAX_AMBI_CHANNELS]{ - 0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3, - }; + static const ALuint Order3DFromChan[MAX_AMBI_CHANNELS]{ + 0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3,}; OrderFromChan = Order3DFromChan; } - BandSplitter splitter{400.0f / static_cast(device->Frequency)}; + BandSplitter splitter{400.0f / static_cast(device->Frequency)}; const auto scales = BFormatDec::GetHFOrderScales(1, device->mAmbiOrder); auto init_ambi = [scales,&OrderFromChan,&splitter](ALvoice::ChannelData &chandata) -> void diff --git a/al/state.cpp b/al/state.cpp index 3ce09be9..25a0efd1 100644 --- a/al/state.cpp +++ b/al/state.cpp @@ -742,7 +742,7 @@ START_API_FUNC ALbitfieldSOFT enabledevts{context->mEnabledEvts.load(std::memory_order_relaxed)}; if((enabledevts&EventType_Deprecated) && context->mEventCb) { - static constexpr ALCchar msg[] = + static const char msg[] = "alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound"; const ALsizei msglen{sizeof(msg)-1}; (*context->mEventCb)(AL_EVENT_TYPE_DEPRECATED_SOFT, 0, 0, msglen, msg, diff --git a/alc/alc.cpp b/alc/alc.cpp index 7702a147..cd2911f5 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -1988,7 +1988,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) * constexpr variable to avoid a reference on * FrontStablizer::DelayLength... */ - static constexpr size_t StablizerDelay{FrontStablizer::DelayLength}; + constexpr size_t StablizerDelay{FrontStablizer::DelayLength}; device->FixedLatency += nanoseconds{seconds{StablizerDelay}} / device->Frequency; } break; @@ -3568,7 +3568,7 @@ START_API_FUNC deviceName = device->DeviceName.c_str(); if(auto chanopt = ConfigValueStr(deviceName, nullptr, "channels")) { - static constexpr struct ChannelMap { + static const struct ChannelMap { const char name[16]; DevFmtChannels chans; ALuint order; @@ -3601,7 +3601,7 @@ START_API_FUNC } if(auto typeopt = ConfigValueStr(deviceName, nullptr, "sample-type")) { - static constexpr struct TypeMap { + static const struct TypeMap { const char name[16]; DevFmtType type; } typelist[] = { diff --git a/alc/alu.cpp b/alc/alu.cpp index 5cd8c918..9bf052e1 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -509,7 +509,7 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo ALeffectslot *(&SendSlots)[MAX_SENDS], const ALvoicePropsBase *props, const ALlistener &Listener, const ALCdevice *Device) { - static constexpr ChanMap MonoMap[1]{ + static const ChanMap MonoMap[1]{ { FrontCenter, 0.0f, 0.0f } }, RearMap[2]{ { BackLeft, Deg2Rad(-150.0f), Deg2Rad(0.0f) }, diff --git a/alc/helpers.cpp b/alc/helpers.cpp index 25b2e4a2..4ea94c7d 100644 --- a/alc/helpers.cpp +++ b/alc/helpers.cpp @@ -385,7 +385,7 @@ al::vector SearchDataFiles(const char *ext, const char *subdir) DirectorySearch(path.c_str(), ext, &results); /* Search the local and global data dirs. */ - static constexpr int ids[2]{ CSIDL_APPDATA, CSIDL_COMMON_APPDATA }; + static const int ids[2]{ CSIDL_APPDATA, CSIDL_COMMON_APPDATA }; for(int id : ids) { WCHAR buffer[MAX_PATH]; diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index fa0085ff..c22848d6 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -300,7 +300,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, ALuint ldelay, rdelay; }; - static constexpr int OrderFromChan[MAX_AMBI_CHANNELS]{ + static const int OrderFromChan[MAX_AMBI_CHANNELS]{ 0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3, }; /* Set this to true for dual-band HRTF processing. May require better @@ -718,7 +718,7 @@ std::unique_ptr LoadHrtf00(std::istream &data, const char *filename) } } - static constexpr ALfloat distance{0.0f}; + static const ALfloat distance{0.0f}; return CreateHrtfStore(rate, irSize, 1, &evCount, &distance, azCount.data(), evOffset.data(), irCount, &reinterpret_cast(coeffs[0]), &reinterpret_cast(delays[0]), filename); @@ -817,7 +817,7 @@ std::unique_ptr LoadHrtf01(std::istream &data, const char *filename) } } - static constexpr ALfloat distance{0.0f}; + static const ALfloat distance{0.0f}; return CreateHrtfStore(rate, irSize, 1, &evCount, &distance, azCount.data(), evOffset.data(), irCount, &reinterpret_cast(coeffs[0]), &reinterpret_cast(delays[0]), filename); diff --git a/alc/panning.cpp b/alc/panning.cpp index aa30a71c..6056b9d9 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -423,7 +423,7 @@ void InitPanning(ALCdevice *device) ALfloat nfc_delay{ConfigValueFloat(devname, "decoder", "nfc-ref-delay").value_or(0.0f)}; if(nfc_delay > 0.0f) { - static constexpr ALuint chans_per_order[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; + static const ALuint chans_per_order[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; InitNearFieldCtrl(device, nfc_delay * SPEEDOFSOUNDMETRESPERSEC, device->mAmbiOrder, chans_per_order); } @@ -470,8 +470,8 @@ void InitPanning(ALCdevice *device) void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, const ALuint (&speakermap)[MAX_OUTPUT_CHANNELS]) { - static constexpr ALuint chans_per_order2d[MAX_AMBI_ORDER+1] = { 1, 2, 2, 2 }; - static constexpr ALuint chans_per_order3d[MAX_AMBI_ORDER+1] = { 1, 3, 5, 7 }; + static const ALuint chans_per_order2d[MAX_AMBI_ORDER+1] = { 1, 2, 2, 2 }; + static const ALuint chans_per_order3d[MAX_AMBI_ORDER+1] = { 1, 3, 5, 7 }; if(!hqdec && conf->FreqBands != 1) ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n", @@ -522,7 +522,7 @@ void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, void InitHrtfPanning(ALCdevice *device) { - static constexpr AngularPoint AmbiPoints[]{ + static const AngularPoint AmbiPoints[]{ { Deg2Rad( 0.000000f), Deg2Rad( 0.000000f) }, { Deg2Rad( 0.000000f), Deg2Rad( 180.000000f) }, { Deg2Rad( 0.000000f), Deg2Rad( -90.000000f) }, @@ -550,7 +550,7 @@ void InitHrtfPanning(ALCdevice *device) { Deg2Rad( 35.264390f), Deg2Rad( 135.000000f) }, { Deg2Rad(-35.264390f), Deg2Rad( 135.000000f) }, }; - static constexpr ALfloat AmbiMatrix[][MAX_AMBI_CHANNELS]{ + static const float AmbiMatrix[][MAX_AMBI_CHANNELS]{ { 3.84615387e-02f, 0.00000000e+00f, 0.00000000e+00f, 8.33950391e-02f, 0.00000000e+00f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 8.60662966e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -7.49473409e-02f, 0.00000000e+00f, 9.67566016e-02f }, { 3.84615387e-02f, 0.00000000e+00f, 0.00000000e+00f, -8.33950391e-02f, 0.00000000e+00f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 8.60662966e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 7.49473409e-02f, 0.00000000e+00f, -9.67566016e-02f }, { 3.84615387e-02f, 8.33950391e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, -8.60662966e-02f, -9.67566016e-02f, 0.00000000e+00f, -7.49473409e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, @@ -578,15 +578,15 @@ void InitHrtfPanning(ALCdevice *device) { 3.84615385e-02f, -3.33333332e-02f, 3.33333335e-02f, -3.33333332e-02f, 4.55645099e-02f, -4.55645100e-02f, 5.38752428e-10f, -4.55645100e-02f, 0.00000000e+00f, -2.95742381e-02f, 6.33865691e-02f, -2.29081068e-02f, -3.74087810e-02f, -2.29081068e-02f, 0.00000000e+00f, 2.95742381e-02f }, { 3.84615385e-02f, -3.33333332e-02f, -3.33333335e-02f, -3.33333332e-02f, 4.55645099e-02f, 4.55645100e-02f, 5.38752429e-10f, 4.55645100e-02f, 0.00000000e+00f, -2.95742381e-02f, -6.33865691e-02f, -2.29081068e-02f, 3.74087810e-02f, -2.29081068e-02f, 0.00000000e+00f, 2.95742381e-02f }, }; - static constexpr ALfloat AmbiOrderHFGain1O[MAX_AMBI_ORDER+1]{ + static const float AmbiOrderHFGain1O[MAX_AMBI_ORDER+1]{ 3.60555128e+00f, 2.08166600e+00f }, AmbiOrderHFGain2O[MAX_AMBI_ORDER+1]{ 2.68741925e+00f, 2.08166600e+00f, 1.07496770e+00f }, AmbiOrderHFGain3O[MAX_AMBI_ORDER+1]{ 2.12652604e+00f, 1.83122879e+00f, 1.30214339e+00f, 6.48052398e-01f }; - static constexpr ALuint ChansPerOrder[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; - const ALfloat *AmbiOrderHFGain{AmbiOrderHFGain1O}; + static const ALuint ChansPerOrder[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; + const float *AmbiOrderHFGain{AmbiOrderHFGain1O}; static_assert(al::size(AmbiPoints) == al::size(AmbiMatrix), "Ambisonic HRTF mismatch"); @@ -602,7 +602,7 @@ void InitHrtfPanning(ALCdevice *device) RenderMode mode; ALuint order; }; - static constexpr HrtfModeEntry hrtf_modes[]{ + static const HrtfModeEntry hrtf_modes[]{ { "full", HrtfRender, 1 }, { "ambi1", NormalRender, 1 }, { "ambi2", NormalRender, 2 }, @@ -662,7 +662,7 @@ void InitHrtfPanning(ALCdevice *device) void InitUhjPanning(ALCdevice *device) { /* UHJ is always 2D first-order. */ - static constexpr size_t count{Ambi2DChannelsFromOrder(1)}; + constexpr size_t count{Ambi2DChannelsFromOrder(1)}; device->mAmbiOrder = 1; diff --git a/common/alnumeric.h b/common/alnumeric.h index b409ce9c..9158b764 100644 --- a/common/alnumeric.h +++ b/common/alnumeric.h @@ -308,7 +308,7 @@ inline float fast_roundf(float f) noexcept /* Integral limit, where sub-integral precision is not available for * floats. */ - static constexpr float ilim[2] = { + static const float ilim[2]{ 8388608.0f /* 0x1.0p+23 */, -8388608.0f /* -0x1.0p+23 */ }; -- cgit v1.2.3 From cac4072781b577512752607939520e7bb09cb178 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 26 Oct 2019 19:57:17 -0700 Subject: Change a few more really small gain values to 0 --- alc/panning.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/alc/panning.cpp b/alc/panning.cpp index 6056b9d9..832fc202 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -569,14 +569,14 @@ void InitHrtfPanning(ALCdevice *device) { 3.84615387e-02f, -4.53609217e-02f, 0.00000000e+00f, 4.53609217e-02f, -6.83467654e-02f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 0.00000000e+00f, -5.23190735e-02f, 0.00000000e+00f, 4.67609766e-02f, 0.00000000e+00f, -4.67609766e-02f, 0.00000000e+00f, -5.23190735e-02f }, { 3.84615387e-02f, 4.53609217e-02f, 0.00000000e+00f, -4.53609217e-02f, -6.83467654e-02f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 0.00000000e+00f, 5.23190735e-02f, 0.00000000e+00f, -4.67609766e-02f, 0.00000000e+00f, 4.67609766e-02f, 0.00000000e+00f, 5.23190735e-02f }, { 3.84615387e-02f, -4.53609217e-02f, 0.00000000e+00f, -4.53609217e-02f, 6.83467654e-02f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 0.00000000e+00f, -5.23190735e-02f, 0.00000000e+00f, 4.67609766e-02f, 0.00000000e+00f, 4.67609766e-02f, 0.00000000e+00f, 5.23190735e-02f }, - { 3.84615385e-02f, 3.33333332e-02f, 3.33333335e-02f, 3.33333332e-02f, 4.55645099e-02f, 4.55645100e-02f, 5.38752469e-10f, 4.55645100e-02f, 0.00000000e+00f, 2.95742381e-02f, 6.33865691e-02f, 2.29081068e-02f, -3.74087810e-02f, 2.29081068e-02f, 0.00000000e+00f, -2.95742381e-02f }, - { 3.84615385e-02f, 3.33333332e-02f, -3.33333335e-02f, 3.33333332e-02f, 4.55645099e-02f, -4.55645100e-02f, 5.38752469e-10f, -4.55645100e-02f, 0.00000000e+00f, 2.95742381e-02f, -6.33865691e-02f, 2.29081068e-02f, 3.74087810e-02f, 2.29081068e-02f, 4.53051106e-20f, -2.95742381e-02f }, - { 3.84615385e-02f, -3.33333332e-02f, 3.33333335e-02f, 3.33333332e-02f, -4.55645099e-02f, -4.55645100e-02f, 5.38752452e-10f, 4.55645100e-02f, 0.00000000e+00f, -2.95742381e-02f, -6.33865691e-02f, -2.29081068e-02f, -3.74087810e-02f, 2.29081068e-02f, 0.00000000e+00f, -2.95742381e-02f }, - { 3.84615385e-02f, -3.33333332e-02f, -3.33333335e-02f, 3.33333332e-02f, -4.55645099e-02f, 4.55645100e-02f, 5.38752451e-10f, -4.55645100e-02f, 0.00000000e+00f, -2.95742381e-02f, 6.33865691e-02f, -2.29081068e-02f, 3.74087810e-02f, 2.29081068e-02f, 0.00000000e+00f, -2.95742381e-02f }, - { 3.84615385e-02f, 3.33333332e-02f, 3.33333335e-02f, -3.33333332e-02f, -4.55645099e-02f, 4.55645100e-02f, 5.38752451e-10f, -4.55645100e-02f, 0.00000000e+00f, 2.95742381e-02f, -6.33865691e-02f, 2.29081068e-02f, -3.74087810e-02f, -2.29081068e-02f, 0.00000000e+00f, 2.95742381e-02f }, - { 3.84615385e-02f, 3.33333332e-02f, -3.33333335e-02f, -3.33333332e-02f, -4.55645099e-02f, -4.55645100e-02f, 5.38752451e-10f, 4.55645100e-02f, 0.00000000e+00f, 2.95742381e-02f, 6.33865691e-02f, 2.29081068e-02f, 3.74087810e-02f, -2.29081068e-02f, 0.00000000e+00f, 2.95742381e-02f }, - { 3.84615385e-02f, -3.33333332e-02f, 3.33333335e-02f, -3.33333332e-02f, 4.55645099e-02f, -4.55645100e-02f, 5.38752428e-10f, -4.55645100e-02f, 0.00000000e+00f, -2.95742381e-02f, 6.33865691e-02f, -2.29081068e-02f, -3.74087810e-02f, -2.29081068e-02f, 0.00000000e+00f, 2.95742381e-02f }, - { 3.84615385e-02f, -3.33333332e-02f, -3.33333335e-02f, -3.33333332e-02f, 4.55645099e-02f, 4.55645100e-02f, 5.38752429e-10f, 4.55645100e-02f, 0.00000000e+00f, -2.95742381e-02f, -6.33865691e-02f, -2.29081068e-02f, 3.74087810e-02f, -2.29081068e-02f, 0.00000000e+00f, 2.95742381e-02f }, + { 3.84615385e-02f, 3.33333332e-02f, 3.33333335e-02f, 3.33333332e-02f, 4.55645099e-02f, 4.55645100e-02f, 0.00000000e+00f, 4.55645100e-02f, 0.00000000e+00f, 2.95742381e-02f, 6.33865691e-02f, 2.29081068e-02f, -3.74087810e-02f, 2.29081068e-02f, 0.00000000e+00f, -2.95742381e-02f }, + { 3.84615385e-02f, 3.33333332e-02f, -3.33333335e-02f, 3.33333332e-02f, 4.55645099e-02f, -4.55645100e-02f, 0.00000000e+00f, -4.55645100e-02f, 0.00000000e+00f, 2.95742381e-02f, -6.33865691e-02f, 2.29081068e-02f, 3.74087810e-02f, 2.29081068e-02f, 0.00000000e+00f, -2.95742381e-02f }, + { 3.84615385e-02f, -3.33333332e-02f, 3.33333335e-02f, 3.33333332e-02f, -4.55645099e-02f, -4.55645100e-02f, 0.00000000e+00f, 4.55645100e-02f, 0.00000000e+00f, -2.95742381e-02f, -6.33865691e-02f, -2.29081068e-02f, -3.74087810e-02f, 2.29081068e-02f, 0.00000000e+00f, -2.95742381e-02f }, + { 3.84615385e-02f, -3.33333332e-02f, -3.33333335e-02f, 3.33333332e-02f, -4.55645099e-02f, 4.55645100e-02f, 0.00000000e+00f, -4.55645100e-02f, 0.00000000e+00f, -2.95742381e-02f, 6.33865691e-02f, -2.29081068e-02f, 3.74087810e-02f, 2.29081068e-02f, 0.00000000e+00f, -2.95742381e-02f }, + { 3.84615385e-02f, 3.33333332e-02f, 3.33333335e-02f, -3.33333332e-02f, -4.55645099e-02f, 4.55645100e-02f, 0.00000000e+00f, -4.55645100e-02f, 0.00000000e+00f, 2.95742381e-02f, -6.33865691e-02f, 2.29081068e-02f, -3.74087810e-02f, -2.29081068e-02f, 0.00000000e+00f, 2.95742381e-02f }, + { 3.84615385e-02f, 3.33333332e-02f, -3.33333335e-02f, -3.33333332e-02f, -4.55645099e-02f, -4.55645100e-02f, 0.00000000e+00f, 4.55645100e-02f, 0.00000000e+00f, 2.95742381e-02f, 6.33865691e-02f, 2.29081068e-02f, 3.74087810e-02f, -2.29081068e-02f, 0.00000000e+00f, 2.95742381e-02f }, + { 3.84615385e-02f, -3.33333332e-02f, 3.33333335e-02f, -3.33333332e-02f, 4.55645099e-02f, -4.55645100e-02f, 0.00000000e+00f, -4.55645100e-02f, 0.00000000e+00f, -2.95742381e-02f, 6.33865691e-02f, -2.29081068e-02f, -3.74087810e-02f, -2.29081068e-02f, 0.00000000e+00f, 2.95742381e-02f }, + { 3.84615385e-02f, -3.33333332e-02f, -3.33333335e-02f, -3.33333332e-02f, 4.55645099e-02f, 4.55645100e-02f, 0.00000000e+00f, 4.55645100e-02f, 0.00000000e+00f, -2.95742381e-02f, -6.33865691e-02f, -2.29081068e-02f, 3.74087810e-02f, -2.29081068e-02f, 0.00000000e+00f, 2.95742381e-02f }, }; static const float AmbiOrderHFGain1O[MAX_AMBI_ORDER+1]{ 3.60555128e+00f, 2.08166600e+00f -- cgit v1.2.3 From 697da8724fa61a71c6173f54cde0d56a08797852 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 27 Oct 2019 00:47:33 -0700 Subject: Avoid an extraneous macro and use a simplified type alias --- common/alspan.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/alspan.h b/common/alspan.h index 42e3523e..cb34d410 100644 --- a/common/alspan.h +++ b/common/alspan.h @@ -72,15 +72,16 @@ namespace detail_ { struct has_size_and_data())), decltype(al::data(std::declval()))>> : std::true_type { }; + + template + using remove_pointer_t = typename std::remove_pointer::type; } // namespace detail_ #define REQUIRES(...) bool rt_=true, typename std::enable_if::type = true -#define USABLE_CONTAINER_DATA(...) \ - std::is_convertible()))>::type(*)[],element_type(*)[]>::value #define IS_VALID_CONTAINER(C) \ !detail_::is_span::value && !detail_::is_std_array::value && \ !std::is_array::value && detail_::has_size_and_data::value && \ - USABLE_CONTAINER_DATA(C&) + std::is_convertible()))>(*)[],element_type(*)[]>::value template class span { @@ -289,7 +290,6 @@ constexpr inline auto span::subspan(size_t offset, size_t count) const -> s } #undef IS_VALID_CONTAINER -#undef USABLE_CONTAINER_DATA #undef REQUIRES } // namespace al -- cgit v1.2.3 From 101afb1ee4694faf7a2977d768dfeaa3f9137f91 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 27 Oct 2019 15:50:59 -0700 Subject: Convert HRTF field distances to meters when creating storage --- alc/hrtf.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index c22848d6..f353e09b 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -84,8 +84,8 @@ using HrtfHandlePtr = std::unique_ptr; #define MIN_FD_COUNT (1) #define MAX_FD_COUNT (16) -#define MIN_FD_DISTANCE (0.05f) -#define MAX_FD_DISTANCE (2.5f) +#define MIN_FD_DISTANCE (50) +#define MAX_FD_DISTANCE (2500) #define MIN_EV_COUNT (5) #define MAX_EV_COUNT (181) @@ -491,7 +491,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, namespace { std::unique_ptr CreateHrtfStore(ALuint rate, ALushort irSize, const ALuint fdCount, - const ALubyte *evCount, const ALfloat *distance, const ALushort *azCount, + const ALubyte *evCount, const ALushort *distance, const ALushort *azCount, const ALushort *irOffset, ALushort irCount, const ALfloat (*coeffs)[2], const ALubyte (*delays)[2], const char *filename) { @@ -541,7 +541,7 @@ std::unique_ptr CreateHrtfStore(ALuint rate, ALushort irSize, const A /* Copy input data to storage. */ for(ALuint i{0};i < fdCount;i++) { - field_[i].distance = distance[i]; + field_[i].distance = distance[i] / 1000.0f; field_[i].evCount = evCount[i]; } for(ALuint i{0};i < evTotal;i++) @@ -718,7 +718,7 @@ std::unique_ptr LoadHrtf00(std::istream &data, const char *filename) } } - static const ALfloat distance{0.0f}; + static const ALushort distance{0}; return CreateHrtfStore(rate, irSize, 1, &evCount, &distance, azCount.data(), evOffset.data(), irCount, &reinterpret_cast(coeffs[0]), &reinterpret_cast(delays[0]), filename); @@ -817,7 +817,7 @@ std::unique_ptr LoadHrtf01(std::istream &data, const char *filename) } } - static const ALfloat distance{0.0f}; + static const ALushort distance{0}; return CreateHrtfStore(rate, irSize, 1, &evCount, &distance, azCount.data(), evOffset.data(), irCount, &reinterpret_cast(coeffs[0]), &reinterpret_cast(delays[0]), filename); @@ -869,12 +869,12 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) if(failed) return nullptr; - auto distance = al::vector(fdCount); + auto distance = al::vector(fdCount); auto evCount = al::vector(fdCount); auto azCount = al::vector{}; for(size_t f{0};f < fdCount;f++) { - distance[f] = GetLE_ALushort(data) / 1000.0f; + distance[f] = GetLE_ALushort(data); evCount[f] = GetLE_ALubyte(data); if(!data || data.eof()) { @@ -884,13 +884,13 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) if(distance[f] < MIN_FD_DISTANCE || distance[f] > MAX_FD_DISTANCE) { - ERR("Unsupported field distance[%zu]=%f (%f to %f meters)\n", f, distance[f], + ERR("Unsupported field distance[%zu]=%d (%d to %d millimeters)\n", f, distance[f], MIN_FD_DISTANCE, MAX_FD_DISTANCE); failed = AL_TRUE; } if(f > 0 && distance[f] <= distance[f-1]) { - ERR("Field distance[%zu] is not after previous (%f > %f)\n", f, distance[f], + ERR("Field distance[%zu] is not after previous (%d > %d)\n", f, distance[f], distance[f-1]); failed = AL_TRUE; } @@ -1033,7 +1033,7 @@ std::unique_ptr LoadHrtf02(std::istream &data, const char *filename) if(fdCount > 1) { - auto distance_ = al::vector(distance.size()); + auto distance_ = al::vector(distance.size()); auto evCount_ = al::vector(evCount.size()); auto azCount_ = al::vector(azCount.size()); auto evOffset_ = al::vector(evOffset.size()); -- cgit v1.2.3 From 205ff0080edfecb03ddcd24933722851d9fd8206 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 27 Oct 2019 18:02:25 -0700 Subject: Adjust padding in alsoft-config and remove an invalid signal --- utils/alsoft-config/mainwindow.ui | 131 ++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 76 deletions(-) diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 1b73536e..0506304e 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -7,7 +7,7 @@ 0 0 564 - 460 + 469 @@ -21,8 +21,7 @@ - - + .. @@ -31,7 +30,7 @@ 470 405 81 - 21 + 31 @@ -39,8 +38,7 @@ - - + .. @@ -64,8 +62,8 @@ 110 50 - 78 - 21 + 76 + 31 @@ -82,7 +80,7 @@ float and converted to the output sample type as needed. 0 50 101 - 21 + 31 @@ -98,7 +96,7 @@ float and converted to the output sample type as needed. 0 20 101 - 21 + 31 @@ -113,8 +111,8 @@ float and converted to the output sample type as needed. 110 20 - 78 - 21 + 76 + 31 @@ -131,7 +129,7 @@ to stereo output. 380 20 - 95 + 96 31 @@ -194,7 +192,7 @@ to stereo output. 290 20 81 - 21 + 31 @@ -210,7 +208,7 @@ to stereo output. 290 50 81 - 21 + 31 @@ -225,8 +223,8 @@ to stereo output. 380 50 - 78 - 21 + 101 + 31 @@ -256,7 +254,7 @@ otherwise be suitable for speakers. 20 30 511 - 91 + 81 @@ -432,9 +430,9 @@ frames needed for each mixing update. 130 - 130 - 131 - 21 + 120 + 111 + 31 @@ -451,9 +449,9 @@ receiver. 20 - 130 + 120 101 - 21 + 31 @@ -466,23 +464,26 @@ receiver. - 270 - 130 - 111 - 21 + 260 + 120 + 121 + 31 Ambisonic Format: + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + 390 - 130 + 120 131 - 21 + 31 @@ -533,7 +534,7 @@ quantization with low-level whitenoise. 60 - 80 + 90 421 81 @@ -611,7 +612,7 @@ quantization with low-level whitenoise. - 10 + 30 20 181 21 @@ -635,7 +636,7 @@ appropriate speaker configuration you intend to use. - 10 + 30 50 181 21 @@ -834,7 +835,7 @@ configuration file. - 10 + 30 80 181 21 @@ -884,7 +885,7 @@ normal output is created with no near-field simulation. 20 0 - 151 + 171 21 @@ -898,9 +899,9 @@ normal output is created with no near-field simulation. - 180 + 200 0 - 91 + 81 21 @@ -998,8 +999,7 @@ normal output is created with no near-field simulation. - - + .. false @@ -1039,8 +1039,7 @@ listed above. - - + .. @@ -1048,10 +1047,10 @@ listed above. - 40 - 50 + 50 + 60 71 - 21 + 31 @@ -1065,9 +1064,9 @@ listed above. 130 - 50 + 60 161 - 21 + 31 @@ -1096,10 +1095,10 @@ application or system to determine if it should be used. - 20 + 30 20 91 - 21 + 31 @@ -1115,7 +1114,7 @@ application or system to determine if it should be used. 130 20 161 - 21 + 31 @@ -1126,7 +1125,7 @@ application or system to determine if it should be used. 50 - 90 + 100 441 81 @@ -2287,7 +2286,7 @@ added by the ALC_EXT_DEDICATED extension. 10 20 141 - 21 + 31 @@ -2302,7 +2301,7 @@ added by the ALC_EXT_DEDICATED extension. 160 20 - 129 + 131 31 @@ -2453,7 +2452,7 @@ added by the ALC_EXT_DEDICATED extension. 370 405 91 - 21 + 31 @@ -2461,8 +2460,7 @@ added by the ALC_EXT_DEDICATED extension. - - + .. @@ -2496,8 +2494,7 @@ added by the ALC_EXT_DEDICATED extension. - - + .. &Quit @@ -2506,8 +2503,7 @@ added by the ALC_EXT_DEDICATED extension. - - + .. Save &As... @@ -2519,8 +2515,7 @@ added by the ALC_EXT_DEDICATED extension. - - + .. &Load... @@ -2538,22 +2533,6 @@ added by the ALC_EXT_DEDICATED extension. - - actionQuit - activated() - MainWindow - close() - - - -1 - -1 - - - 267 - 181 - - - backendListWidget currentRowChanged(int) -- cgit v1.2.3 From d37a294d4ce66ea3e5816042457923b72d1bc7c1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 27 Oct 2019 19:20:26 -0700 Subject: Add a config option for custom ALSA capture devices --- alc/backends/alsa.cpp | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/alc/backends/alsa.cpp b/alc/backends/alsa.cpp index 1b8c6298..7dc3c3c4 100644 --- a/alc/backends/alsa.cpp +++ b/alc/backends/alsa.cpp @@ -267,27 +267,25 @@ al::vector probe_devices(snd_pcm_stream_t stream) GetConfigValue(nullptr, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ? "device" : "capture", "default")}); - if(stream == SND_PCM_STREAM_PLAYBACK) + const char *customdevs{GetConfigValue(nullptr, "alsa", + (stream == SND_PCM_STREAM_PLAYBACK) ? "custom-devices" : "custom-captures", "")}; + while(const char *curdev{customdevs}) { - const char *customdevs; - const char *next{GetConfigValue(nullptr, "alsa", "custom-devices", "")}; - while((customdevs=next) != nullptr && customdevs[0]) + if(!curdev[0]) break; + customdevs = strchr(curdev, ';'); + const char *sep{strchr(curdev, '=')}; + if(!sep) { - next = strchr(customdevs, ';'); - const char *sep{strchr(customdevs, '=')}; - if(!sep) - { - std::string spec{next ? std::string(customdevs, next++) : std::string(customdevs)}; - ERR("Invalid ALSA device specification \"%s\"\n", spec.c_str()); - continue; - } - - const char *oldsep{sep++}; - devlist.emplace_back(DevMap{std::string(customdevs, oldsep), - next ? std::string(sep, next++) : std::string(sep)}); - const auto &entry = devlist.back(); - TRACE("Got device \"%s\", \"%s\"\n", entry.name.c_str(), entry.device_name.c_str()); + std::string spec{customdevs ? std::string(curdev, customdevs++) : std::string(curdev)}; + ERR("Invalid ALSA device specification \"%s\"\n", spec.c_str()); + continue; } + + const char *oldsep{sep++}; + devlist.emplace_back(DevMap{std::string(curdev, oldsep), + customdevs ? std::string(sep, customdevs++) : std::string(sep)}); + const auto &entry = devlist.back(); + TRACE("Got device \"%s\", \"%s\"\n", entry.name.c_str(), entry.device_name.c_str()); } const std::string main_prefix{ -- cgit v1.2.3 From 2741a94e58ed2f9a17d05fd2499e1a3ea4ac43e8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 28 Oct 2019 23:47:30 -0700 Subject: Use rotate to reorder the default list entry --- alc/hrtf.cpp | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index f353e09b..ac1a19e1 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -1283,8 +1283,6 @@ al::vector EnumerateHrtf(const char *devname) pathlist = next; } } - else if(ConfigValueExists(devname, nullptr, "hrtf_tables")) - ERR("The hrtf_tables option is deprecated, please use hrtf-paths instead.\n"); if(usedefaults) { @@ -1298,23 +1296,15 @@ al::vector EnumerateHrtf(const char *devname) AddBuiltInEntry(list, "Built-In 48000hz", IDR_DEFAULT_48000_MHR); } - if(!list.empty()) + if(auto defhrtfopt = ConfigValueStr(devname, nullptr, "default-hrtf")) { - if(auto defhrtfopt = ConfigValueStr(devname, nullptr, "default-hrtf")) - { - auto iter = std::find_if(list.begin(), list.end(), - [&defhrtfopt](const EnumeratedHrtf &entry) -> bool - { return entry.name == *defhrtfopt; } - ); - if(iter == list.end()) - WARN("Failed to find default HRTF \"%s\"\n", defhrtfopt->c_str()); - else if(iter != list.begin()) - { - EnumeratedHrtf entry{std::move(*iter)}; - list.erase(iter); - list.insert(list.begin(), std::move(entry)); - } - } + auto find_entry = [&defhrtfopt](const EnumeratedHrtf &entry) -> bool + { return entry.name == *defhrtfopt; }; + auto iter = std::find_if(list.begin(), list.end(), find_entry); + if(iter == list.end()) + WARN("Failed to find default HRTF \"%s\"\n", defhrtfopt->c_str()); + else if(iter != list.begin()) + std::rotate(list.begin(), iter, iter+1); } return list; -- cgit v1.2.3 From d2608e4bde41b3005a06346bea99bbe06404ef22 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Nov 2019 00:30:33 -0700 Subject: Avoid holding HRTF accumulation samples per-source It notably simplifies things to mix HRTF sources into an accumulation buffer together, which the Dry buffer's Ambisonic-to-HRTF decode is then added to, before being mixed to the Real output. --- alc/alc.cpp | 2 ++ alc/alcmain.h | 2 ++ alc/hrtf.h | 2 -- alc/mixer/defs.h | 10 ++++------ alc/mixer/hrtfbase.h | 27 ++++++++------------------- alc/mixer/mixer_c.cpp | 15 +++++---------- alc/mixer/mixer_neon.cpp | 15 +++++---------- alc/mixer/mixer_sse.cpp | 15 +++++---------- alc/voice.cpp | 39 +++++++++++++-------------------------- 9 files changed, 44 insertions(+), 83 deletions(-) diff --git a/alc/alc.cpp b/alc/alc.cpp index cd2911f5..bee42fc5 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -1853,6 +1853,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->Limiter = nullptr; device->ChannelDelay.clear(); + std::fill(std::begin(device->HrtfAccumData), std::end(device->HrtfAccumData), float2{}); + device->Dry.AmbiMap.fill(BFChannelConfig{}); device->Dry.Buffer = {}; std::fill(std::begin(device->NumChannelsPerOrder), std::end(device->NumChannelsPerOrder), 0u); diff --git a/alc/alcmain.h b/alc/alcmain.h index c26b3a28..30c5b835 100644 --- a/alc/alcmain.h +++ b/alc/alcmain.h @@ -277,6 +277,8 @@ struct ALCdevice : public al::intrusive_ref { alignas(16) ALfloat HrtfSourceData[BUFFERSIZE + HRTF_HISTORY_LENGTH]; alignas(16) ALfloat NfcSampleData[BUFFERSIZE]; }; + + /* Persistent storage for HRTF mixing. */ alignas(16) float2 HrtfAccumData[BUFFERSIZE + HRIR_LENGTH]; /* Mixing buffer used by the Dry mix and Real output. */ diff --git a/alc/hrtf.h b/alc/hrtf.h index d133133a..a81ebfed 100644 --- a/alc/hrtf.h +++ b/alc/hrtf.h @@ -68,7 +68,6 @@ using HrirArray = std::array; struct HrtfState { alignas(16) std::array History; - alignas(16) HrirArray Values; }; struct HrtfFilter { @@ -80,7 +79,6 @@ struct HrtfFilter { struct DirectHrtfState { /* HRTF filter state for dry buffer content */ ALuint IrSize{0}; - alignas(16) HrirArray Values{}; al::FlexArray Coeffs; DirectHrtfState(size_t numchans) : Coeffs{numchans} { } diff --git a/alc/mixer/defs.h b/alc/mixer/defs.h index b2535265..1e5b40d8 100644 --- a/alc/mixer/defs.h +++ b/alc/mixer/defs.h @@ -41,13 +41,11 @@ void MixRow_(const al::span OutBuffer, const al::span Gains, const float *InSamples, const size_t InStride); template -void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const float *InSamples, - float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, MixHrtfFilter *hrtfparams, - const size_t BufferSize); +void MixHrtf_(const float *InSamples, float2 *AccumSamples, const ALuint IrSize, + MixHrtfFilter *hrtfparams, const size_t BufferSize); template -void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const float *InSamples, - float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, const HrtfFilter *oldparams, - MixHrtfFilter *newparams, const size_t BufferSize); +void MixHrtfBlend_(const float *InSamples, float2 *AccumSamples, const ALuint IrSize, + const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize); template void MixDirectHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, const al::span InSamples, float2 *AccumSamples, DirectHrtfState *State, diff --git a/alc/mixer/hrtfbase.h b/alc/mixer/hrtfbase.h index cbc885c5..4a6eab50 100644 --- a/alc/mixer/hrtfbase.h +++ b/alc/mixer/hrtfbase.h @@ -13,9 +13,8 @@ using ApplyCoeffsT = void(&)(float2 *RESTRICT Values, const ALuint irSize, const const float left, const float right); template -inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const float *InSamples, float2 *RESTRICT AccumSamples, const size_t OutPos, - const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) +inline void MixHrtfBase(const float *InSamples, float2 *RESTRICT AccumSamples, const ALuint IrSize, + MixHrtfFilter *hrtfparams, const size_t BufferSize) { ASSUME(BufferSize > 0); @@ -38,17 +37,11 @@ inline void MixHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, stepcount += 1.0f; } - for(size_t i{0u};i < BufferSize;++i) - LeftOut[OutPos+i] += AccumSamples[i][0]; - for(size_t i{0u};i < BufferSize;++i) - RightOut[OutPos+i] += AccumSamples[i][1]; - hrtfparams->Gain = gain + gainstep*stepcount; } template -inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const float *InSamples, float2 *RESTRICT AccumSamples, const size_t OutPos, +inline void MixHrtfBlendBase(const float *InSamples, float2 *RESTRICT AccumSamples, const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { @@ -89,11 +82,6 @@ inline void MixHrtfBlendBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOut stepcount += 1.0f; } - for(size_t i{0u};i < BufferSize;++i) - LeftOut[OutPos+i] += AccumSamples[i][0]; - for(size_t i{0u};i < BufferSize;++i) - RightOut[OutPos+i] += AccumSamples[i][1]; - newparams->Gain = newGainStep*stepcount; } @@ -106,9 +94,6 @@ inline void MixDirectHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOu const ALuint IrSize{State->IrSize}; - auto accum_iter = std::copy_n(State->Values.begin(), State->Values.size(), AccumSamples); - std::fill_n(accum_iter, BufferSize, float2{}); - auto coeff_iter = State->Coeffs.begin(); for(const FloatBufferLine &input : InSamples) { @@ -124,7 +109,11 @@ inline void MixDirectHrtfBase(FloatBufferLine &LeftOut, FloatBufferLine &RightOu for(size_t i{0u};i < BufferSize;++i) RightOut[i] += AccumSamples[i][1]; - std::copy_n(AccumSamples + BufferSize, State->Values.size(), State->Values.begin()); + /* Copy the new in-progress accumulation values to the front and clear the + * following samples for the next mix. + */ + auto accum_iter = std::copy_n(AccumSamples+BufferSize, HRIR_LENGTH, AccumSamples); + std::fill_n(accum_iter, BufferSize, float2{}); } #endif /* MIXER_HRTFBASE_H */ diff --git a/alc/mixer/mixer_c.cpp b/alc/mixer/mixer_c.cpp index 8d375de7..fad33746 100644 --- a/alc/mixer/mixer_c.cpp +++ b/alc/mixer/mixer_c.cpp @@ -136,21 +136,16 @@ const ALfloat *Resample_(const InterpState *state, const ALfl template<> -void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, +void MixHrtf_(const float *InSamples, float2 *AccumSamples, const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) -{ - MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, - hrtfparams, BufferSize); -} +{ MixHrtfBase(InSamples, AccumSamples, IrSize, hrtfparams, BufferSize); } template<> -void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, +void MixHrtfBlend_(const float *InSamples, float2 *AccumSamples, const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { - MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, - oldparams, newparams, BufferSize); + MixHrtfBlendBase(InSamples, AccumSamples, IrSize, oldparams, newparams, + BufferSize); } template<> diff --git a/alc/mixer/mixer_neon.cpp b/alc/mixer/mixer_neon.cpp index ae782897..67bf9c71 100644 --- a/alc/mixer/mixer_neon.cpp +++ b/alc/mixer/mixer_neon.cpp @@ -190,21 +190,16 @@ const ALfloat *Resample_(const InterpState *state, template<> -void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, +void MixHrtf_(const float *InSamples, float2 *AccumSamples, const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) -{ - MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, - hrtfparams, BufferSize); -} +{ MixHrtfBase(InSamples, AccumSamples, IrSize, hrtfparams, BufferSize); } template<> -void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, +void MixHrtfBlend_(const float *InSamples, float2 *AccumSamples, const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { - MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, - oldparams, newparams, BufferSize); + MixHrtfBlendBase(InSamples, AccumSamples, IrSize, oldparams, newparams, + BufferSize); } template<> diff --git a/alc/mixer/mixer_sse.cpp b/alc/mixer/mixer_sse.cpp index 62ce5eab..aaf37df6 100644 --- a/alc/mixer/mixer_sse.cpp +++ b/alc/mixer/mixer_sse.cpp @@ -165,21 +165,16 @@ const ALfloat *Resample_(const InterpState *state, template<> -void MixHrtf_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, +void MixHrtf_(const float *InSamples, float2 *AccumSamples, const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize) -{ - MixHrtfBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, - hrtfparams, BufferSize); -} +{ MixHrtfBase(InSamples, AccumSamples, IrSize, hrtfparams, BufferSize); } template<> -void MixHrtfBlend_(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const float *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, +void MixHrtfBlend_(const float *InSamples, float2 *AccumSamples, const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize) { - MixHrtfBlendBase(LeftOut, RightOut, InSamples, AccumSamples, OutPos, IrSize, - oldparams, newparams, BufferSize); + MixHrtfBlendBase(InSamples, AccumSamples, IrSize, oldparams, newparams, + BufferSize); } template<> diff --git a/alc/voice.cpp b/alc/voice.cpp index 0aac0258..1c38f36f 100644 --- a/alc/voice.cpp +++ b/alc/voice.cpp @@ -72,12 +72,11 @@ Resampler ResamplerDefault{Resampler::Linear}; namespace { -using HrtfMixerFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, +using HrtfMixerFunc = void(*)(const ALfloat *InSamples, float2 *AccumSamples, const ALuint IrSize, MixHrtfFilter *hrtfparams, const size_t BufferSize); -using HrtfMixerBlendFunc = void(*)(FloatBufferLine &LeftOut, FloatBufferLine &RightOut, - const ALfloat *InSamples, float2 *AccumSamples, const size_t OutPos, const ALuint IrSize, - const HrtfFilter *oldparams, MixHrtfFilter *newparams, const size_t BufferSize); +using HrtfMixerBlendFunc = void(*)(const ALfloat *InSamples, float2 *AccumSamples, + const ALuint IrSize, const HrtfFilter *oldparams, MixHrtfFilter *newparams, + const size_t BufferSize); HrtfMixerFunc MixHrtfSamples = MixHrtf_; HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_; @@ -423,12 +422,10 @@ ALfloat *LoadBufferQueue(ALbufferlistitem *BufferListItem, ALbufferlistitem *Buf } -void DoHrtfMix(ALvoice::TargetData &Direct, const float TargetGain, DirectParams &parms, - const float *samples, const ALuint DstBufferSize, const ALuint Counter, const ALuint OutPos, - const ALuint IrSize, ALCdevice *Device) +void DoHrtfMix(const float TargetGain, DirectParams &parms, const float *samples, + const ALuint DstBufferSize, const ALuint Counter, ALuint OutPos, const ALuint IrSize, + ALCdevice *Device) { - const ALuint OutLIdx{GetChannelIdxByName(Device->RealOut, FrontLeft)}; - const ALuint OutRIdx{GetChannelIdxByName(Device->RealOut, FrontRight)}; auto &HrtfSamples = Device->HrtfSourceData; auto &AccumSamples = Device->HrtfAccumData; @@ -440,12 +437,6 @@ void DoHrtfMix(ALvoice::TargetData &Direct, const float TargetGain, DirectParams std::copy_n(std::begin(HrtfSamples) + DstBufferSize, parms.Hrtf.State.History.size(), parms.Hrtf.State.History.begin()); - /* Copy the current filtered values being accumulated into the temp buffer. */ - auto accum_iter = std::copy_n(parms.Hrtf.State.Values.begin(), parms.Hrtf.State.Values.size(), - std::begin(AccumSamples)); - /* Clear the accumulation buffer that will start getting filled in. */ - std::fill_n(accum_iter, DstBufferSize, float2{}); - /* If fading, the old gain is not silence, and this is the first mixing * pass, fade between the IRs. */ @@ -473,14 +464,15 @@ void DoHrtfMix(ALvoice::TargetData &Direct, const float TargetGain, DirectParams hrtfparams.Gain = 0.0f; hrtfparams.GainStep = gain / static_cast(fademix); - MixHrtfBlendSamples(Direct.Buffer[OutLIdx], Direct.Buffer[OutRIdx], HrtfSamples, - AccumSamples, OutPos, IrSize, &parms.Hrtf.Old, &hrtfparams, fademix); + MixHrtfBlendSamples(HrtfSamples, AccumSamples+OutPos, IrSize, &parms.Hrtf.Old, &hrtfparams, + fademix); /* Update the old parameters with the result. */ parms.Hrtf.Old = parms.Hrtf.Target; if(fademix < Counter) parms.Hrtf.Old.Gain = hrtfparams.Gain; else parms.Hrtf.Old.Gain = TargetGain; + OutPos += fademix; } if LIKELY(fademix < DstBufferSize) @@ -503,8 +495,7 @@ void DoHrtfMix(ALvoice::TargetData &Direct, const float TargetGain, DirectParams hrtfparams.Delay[1] = parms.Hrtf.Target.Delay[1]; hrtfparams.Gain = parms.Hrtf.Old.Gain; hrtfparams.GainStep = (gain - parms.Hrtf.Old.Gain) / static_cast(todo); - MixHrtfSamples(Direct.Buffer[OutLIdx], Direct.Buffer[OutRIdx], HrtfSamples+fademix, - AccumSamples+fademix, OutPos+fademix, IrSize, &hrtfparams, todo); + MixHrtfSamples(HrtfSamples+fademix, AccumSamples+OutPos, IrSize, &hrtfparams, todo); /* Store the interpolated gain or the final target gain depending if * the fade is done. */ @@ -513,10 +504,6 @@ void DoHrtfMix(ALvoice::TargetData &Direct, const float TargetGain, DirectParams else parms.Hrtf.Old.Gain = TargetGain; } - - /* Copy the new in-progress accumulation values back for the next mix. */ - std::copy_n(std::begin(AccumSamples) + DstBufferSize, parms.Hrtf.State.Values.size(), - parms.Hrtf.State.Values.begin()); } void DoNfcMix(ALvoice::TargetData &Direct, const float *TargetGains, DirectParams &parms, @@ -713,8 +700,8 @@ void ALvoice::mix(const State vstate, ALCcontext *Context, const ALuint SamplesT { const ALfloat TargetGain{UNLIKELY(vstate == ALvoice::Stopping) ? 0.0f : parms.Hrtf.Target.Gain}; - DoHrtfMix(mDirect, TargetGain, parms, samples, DstBufferSize, Counter, OutPos, - IrSize, Device); + DoHrtfMix(TargetGain, parms, samples, DstBufferSize, Counter, OutPos, IrSize, + Device); } else if((mFlags&VOICE_HAS_NFC)) { -- cgit v1.2.3 From c5f88ab59fcbda3f6ac1e76b0175a5197624a63a Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Sat, 9 Nov 2019 12:12:53 +0100 Subject: EFX: Add explicit cast to a square function MSVC 2015 and above returns the expression according to its datatype. In this case, returns 4294967295 instead of -1. --- alc/effects/modulator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alc/effects/modulator.cpp b/alc/effects/modulator.cpp index 23bae63f..aee896fb 100644 --- a/alc/effects/modulator.cpp +++ b/alc/effects/modulator.cpp @@ -52,7 +52,7 @@ inline float Saw(ALuint index) { return static_cast(index)*(2.0f/WAVEFORM_FRACONE) - 1.0f; } inline float Square(ALuint index) -{ return static_cast(((index>>(WAVEFORM_FRACBITS-2))&2) - 1); } +{ return static_cast(static_cast((index>>(WAVEFORM_FRACBITS-2))&2) - 1); } inline float One(ALuint) { return 1.0f; } -- cgit v1.2.3 From 74cbba511d6b71634d07d44a822c826400fe967d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 9 Nov 2019 12:51:51 -0800 Subject: Limit HRTF ambisonic decoding to second-order The generated third-order matrix has incorrect first-order coefficients, indicating a wonky decoder. The generated second-order matrix looks more stable. --- alc/panning.cpp | 61 +++++++++++++++++--------------------- utils/alsoft-config/mainwindow.cpp | 12 ++++---- 2 files changed, 35 insertions(+), 38 deletions(-) diff --git a/alc/panning.cpp b/alc/panning.cpp index 832fc202..1288197d 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -551,39 +551,37 @@ void InitHrtfPanning(ALCdevice *device) { Deg2Rad(-35.264390f), Deg2Rad( 135.000000f) }, }; static const float AmbiMatrix[][MAX_AMBI_CHANNELS]{ - { 3.84615387e-02f, 0.00000000e+00f, 0.00000000e+00f, 8.33950391e-02f, 0.00000000e+00f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 8.60662966e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -7.49473409e-02f, 0.00000000e+00f, 9.67566016e-02f }, - { 3.84615387e-02f, 0.00000000e+00f, 0.00000000e+00f, -8.33950391e-02f, 0.00000000e+00f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 8.60662966e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 7.49473409e-02f, 0.00000000e+00f, -9.67566016e-02f }, - { 3.84615387e-02f, 8.33950391e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, -8.60662966e-02f, -9.67566016e-02f, 0.00000000e+00f, -7.49473409e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, - { 3.84615387e-02f, -8.33950391e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, -8.60662966e-02f, 9.67566016e-02f, 0.00000000e+00f, 7.49473409e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, - { 3.84615379e-02f, 0.00000000e+00f, 8.33950384e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 9.93807988e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 1.22388497e-01f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, - { 3.84615379e-02f, 0.00000000e+00f, -8.33950384e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 9.93807988e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -1.22388497e-01f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, - { 3.84615383e-02f, 4.53609209e-02f, 4.53609209e-02f, 0.00000000e+00f, 0.00000000e+00f, 6.83467647e-02f, 2.48451995e-02f, 0.00000000e+00f, -4.30331483e-02f, -3.21963528e-02f, 0.00000000e+00f, 6.23479680e-02f, -1.27267260e-02f, 0.00000000e+00f, -6.90065559e-02f, 0.00000000e+00f }, - { 3.84615383e-02f, 4.53609209e-02f, -4.53609209e-02f, 0.00000000e+00f, 0.00000000e+00f, -6.83467647e-02f, 2.48451995e-02f, 0.00000000e+00f, -4.30331483e-02f, -3.21963528e-02f, 0.00000000e+00f, 6.23479680e-02f, 1.27267260e-02f, 0.00000000e+00f, 6.90065559e-02f, 0.00000000e+00f }, - { 3.84615383e-02f, -4.53609209e-02f, 4.53609209e-02f, 0.00000000e+00f, 0.00000000e+00f, -6.83467647e-02f, 2.48451995e-02f, 0.00000000e+00f, -4.30331483e-02f, 3.21963528e-02f, 0.00000000e+00f, -6.23479680e-02f, -1.27267260e-02f, 0.00000000e+00f, -6.90065559e-02f, 0.00000000e+00f }, - { 3.84615383e-02f, -4.53609209e-02f, -4.53609209e-02f, 0.00000000e+00f, 0.00000000e+00f, 6.83467647e-02f, 2.48451995e-02f, 0.00000000e+00f, -4.30331483e-02f, 3.21963528e-02f, 0.00000000e+00f, -6.23479680e-02f, 1.27267260e-02f, 0.00000000e+00f, 6.90065559e-02f, 0.00000000e+00f }, - { 3.84615383e-02f, 0.00000000e+00f, 4.53609209e-02f, 4.53609209e-02f, 0.00000000e+00f, 0.00000000e+00f, 2.48451995e-02f, 6.83467647e-02f, 4.30331483e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -1.27267260e-02f, 6.23479680e-02f, 6.90065559e-02f, 3.21963528e-02f }, - { 3.84615383e-02f, 0.00000000e+00f, -4.53609209e-02f, 4.53609209e-02f, 0.00000000e+00f, 0.00000000e+00f, 2.48451995e-02f, -6.83467647e-02f, 4.30331483e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 1.27267260e-02f, 6.23479680e-02f, -6.90065559e-02f, 3.21963528e-02f }, - { 3.84615383e-02f, 0.00000000e+00f, 4.53609209e-02f, -4.53609209e-02f, 0.00000000e+00f, 0.00000000e+00f, 2.48451995e-02f, -6.83467647e-02f, 4.30331483e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -1.27267260e-02f, -6.23479680e-02f, 6.90065559e-02f, -3.21963528e-02f }, - { 3.84615383e-02f, 0.00000000e+00f, -4.53609209e-02f, -4.53609209e-02f, 0.00000000e+00f, 0.00000000e+00f, 2.48451995e-02f, 6.83467647e-02f, 4.30331483e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 1.27267260e-02f, -6.23479680e-02f, -6.90065559e-02f, -3.21963528e-02f }, - { 3.84615387e-02f, 4.53609217e-02f, 0.00000000e+00f, 4.53609217e-02f, 6.83467654e-02f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 0.00000000e+00f, 5.23190735e-02f, 0.00000000e+00f, -4.67609766e-02f, 0.00000000e+00f, -4.67609766e-02f, 0.00000000e+00f, -5.23190735e-02f }, - { 3.84615387e-02f, -4.53609217e-02f, 0.00000000e+00f, 4.53609217e-02f, -6.83467654e-02f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 0.00000000e+00f, -5.23190735e-02f, 0.00000000e+00f, 4.67609766e-02f, 0.00000000e+00f, -4.67609766e-02f, 0.00000000e+00f, -5.23190735e-02f }, - { 3.84615387e-02f, 4.53609217e-02f, 0.00000000e+00f, -4.53609217e-02f, -6.83467654e-02f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 0.00000000e+00f, 5.23190735e-02f, 0.00000000e+00f, -4.67609766e-02f, 0.00000000e+00f, 4.67609766e-02f, 0.00000000e+00f, 5.23190735e-02f }, - { 3.84615387e-02f, -4.53609217e-02f, 0.00000000e+00f, -4.53609217e-02f, 6.83467654e-02f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 0.00000000e+00f, -5.23190735e-02f, 0.00000000e+00f, 4.67609766e-02f, 0.00000000e+00f, 4.67609766e-02f, 0.00000000e+00f, 5.23190735e-02f }, - { 3.84615385e-02f, 3.33333332e-02f, 3.33333335e-02f, 3.33333332e-02f, 4.55645099e-02f, 4.55645100e-02f, 0.00000000e+00f, 4.55645100e-02f, 0.00000000e+00f, 2.95742381e-02f, 6.33865691e-02f, 2.29081068e-02f, -3.74087810e-02f, 2.29081068e-02f, 0.00000000e+00f, -2.95742381e-02f }, - { 3.84615385e-02f, 3.33333332e-02f, -3.33333335e-02f, 3.33333332e-02f, 4.55645099e-02f, -4.55645100e-02f, 0.00000000e+00f, -4.55645100e-02f, 0.00000000e+00f, 2.95742381e-02f, -6.33865691e-02f, 2.29081068e-02f, 3.74087810e-02f, 2.29081068e-02f, 0.00000000e+00f, -2.95742381e-02f }, - { 3.84615385e-02f, -3.33333332e-02f, 3.33333335e-02f, 3.33333332e-02f, -4.55645099e-02f, -4.55645100e-02f, 0.00000000e+00f, 4.55645100e-02f, 0.00000000e+00f, -2.95742381e-02f, -6.33865691e-02f, -2.29081068e-02f, -3.74087810e-02f, 2.29081068e-02f, 0.00000000e+00f, -2.95742381e-02f }, - { 3.84615385e-02f, -3.33333332e-02f, -3.33333335e-02f, 3.33333332e-02f, -4.55645099e-02f, 4.55645100e-02f, 0.00000000e+00f, -4.55645100e-02f, 0.00000000e+00f, -2.95742381e-02f, 6.33865691e-02f, -2.29081068e-02f, 3.74087810e-02f, 2.29081068e-02f, 0.00000000e+00f, -2.95742381e-02f }, - { 3.84615385e-02f, 3.33333332e-02f, 3.33333335e-02f, -3.33333332e-02f, -4.55645099e-02f, 4.55645100e-02f, 0.00000000e+00f, -4.55645100e-02f, 0.00000000e+00f, 2.95742381e-02f, -6.33865691e-02f, 2.29081068e-02f, -3.74087810e-02f, -2.29081068e-02f, 0.00000000e+00f, 2.95742381e-02f }, - { 3.84615385e-02f, 3.33333332e-02f, -3.33333335e-02f, -3.33333332e-02f, -4.55645099e-02f, -4.55645100e-02f, 0.00000000e+00f, 4.55645100e-02f, 0.00000000e+00f, 2.95742381e-02f, 6.33865691e-02f, 2.29081068e-02f, 3.74087810e-02f, -2.29081068e-02f, 0.00000000e+00f, 2.95742381e-02f }, - { 3.84615385e-02f, -3.33333332e-02f, 3.33333335e-02f, -3.33333332e-02f, 4.55645099e-02f, -4.55645100e-02f, 0.00000000e+00f, -4.55645100e-02f, 0.00000000e+00f, -2.95742381e-02f, 6.33865691e-02f, -2.29081068e-02f, -3.74087810e-02f, -2.29081068e-02f, 0.00000000e+00f, 2.95742381e-02f }, - { 3.84615385e-02f, -3.33333332e-02f, -3.33333335e-02f, -3.33333332e-02f, 4.55645099e-02f, 4.55645100e-02f, 0.00000000e+00f, 4.55645100e-02f, 0.00000000e+00f, -2.95742381e-02f, -6.33865691e-02f, -2.29081068e-02f, 3.74087810e-02f, -2.29081068e-02f, 0.00000000e+00f, 2.95742381e-02f }, + { 3.84615387e-02f, 0.00000000e+00f, 0.00000000e+00f, 6.66173389e-02f, 0.00000000e+00f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 8.60662966e-02f }, + { 3.84615387e-02f, 0.00000000e+00f, 0.00000000e+00f, -6.66173389e-02f, 0.00000000e+00f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 8.60662966e-02f }, + { 3.84615387e-02f, 6.66173389e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, -8.60662966e-02f }, + { 3.84615387e-02f, -6.66173389e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, -8.60662966e-02f }, + { 3.84615379e-02f, 0.00000000e+00f, 6.66173384e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 9.93807988e-02f, 0.00000000e+00f, 0.00000000e+00f }, + { 3.84615379e-02f, 0.00000000e+00f, -6.66173384e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 9.93807988e-02f, 0.00000000e+00f, 0.00000000e+00f }, + { 3.84615383e-02f, 4.71055721e-02f, 4.71055717e-02f, 0.00000000e+00f, 0.00000000e+00f, 6.83467647e-02f, 2.48451995e-02f, 0.00000000e+00f, -4.30331483e-02f }, + { 3.84615383e-02f, 4.71055721e-02f, -4.71055717e-02f, 0.00000000e+00f, 0.00000000e+00f, -6.83467647e-02f, 2.48451995e-02f, 0.00000000e+00f, -4.30331483e-02f }, + { 3.84615383e-02f, -4.71055721e-02f, 4.71055717e-02f, 0.00000000e+00f, 0.00000000e+00f, -6.83467647e-02f, 2.48451995e-02f, 0.00000000e+00f, -4.30331483e-02f }, + { 3.84615383e-02f, -4.71055721e-02f, -4.71055717e-02f, 0.00000000e+00f, 0.00000000e+00f, 6.83467647e-02f, 2.48451995e-02f, 0.00000000e+00f, -4.30331483e-02f }, + { 3.84615383e-02f, 0.00000000e+00f, 4.71055717e-02f, 4.71055721e-02f, 0.00000000e+00f, 0.00000000e+00f, 2.48451995e-02f, 6.83467647e-02f, 4.30331483e-02f }, + { 3.84615383e-02f, 0.00000000e+00f, -4.71055717e-02f, 4.71055721e-02f, 0.00000000e+00f, 0.00000000e+00f, 2.48451995e-02f, -6.83467647e-02f, 4.30331483e-02f }, + { 3.84615383e-02f, 0.00000000e+00f, 4.71055717e-02f, -4.71055721e-02f, 0.00000000e+00f, 0.00000000e+00f, 2.48451995e-02f, -6.83467647e-02f, 4.30331483e-02f }, + { 3.84615383e-02f, 0.00000000e+00f, -4.71055717e-02f, -4.71055721e-02f, 0.00000000e+00f, 0.00000000e+00f, 2.48451995e-02f, 6.83467647e-02f, 4.30331483e-02f }, + { 3.84615387e-02f, 4.71055721e-02f, 0.00000000e+00f, 4.71055721e-02f, 6.83467654e-02f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 0.00000000e+00f }, + { 3.84615387e-02f, -4.71055721e-02f, 0.00000000e+00f, 4.71055721e-02f, -6.83467654e-02f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 0.00000000e+00f }, + { 3.84615387e-02f, 4.71055721e-02f, 0.00000000e+00f, -4.71055721e-02f, -6.83467654e-02f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 0.00000000e+00f }, + { 3.84615387e-02f, -4.71055721e-02f, 0.00000000e+00f, -4.71055721e-02f, 6.83467654e-02f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 0.00000000e+00f }, + { 3.84615385e-02f, 3.84615384e-02f, 3.84615386e-02f, 3.84615384e-02f, 4.55645099e-02f, 4.55645100e-02f, 0.00000000e+00f, 4.55645100e-02f, 0.00000000e+00f }, + { 3.84615385e-02f, 3.84615384e-02f, -3.84615386e-02f, 3.84615384e-02f, 4.55645099e-02f, -4.55645100e-02f, 0.00000000e+00f, -4.55645100e-02f, 0.00000000e+00f }, + { 3.84615385e-02f, -3.84615384e-02f, 3.84615386e-02f, 3.84615384e-02f, -4.55645099e-02f, -4.55645100e-02f, 0.00000000e+00f, 4.55645100e-02f, 0.00000000e+00f }, + { 3.84615385e-02f, -3.84615384e-02f, -3.84615386e-02f, 3.84615384e-02f, -4.55645099e-02f, 4.55645100e-02f, 0.00000000e+00f, -4.55645100e-02f, 0.00000000e+00f }, + { 3.84615385e-02f, 3.84615384e-02f, 3.84615386e-02f, -3.84615384e-02f, -4.55645099e-02f, 4.55645100e-02f, 0.00000000e+00f, -4.55645100e-02f, 0.00000000e+00f }, + { 3.84615385e-02f, 3.84615384e-02f, -3.84615386e-02f, -3.84615384e-02f, -4.55645099e-02f, -4.55645100e-02f, 0.00000000e+00f, 4.55645100e-02f, 0.00000000e+00f }, + { 3.84615385e-02f, -3.84615384e-02f, 3.84615386e-02f, -3.84615384e-02f, 4.55645099e-02f, -4.55645100e-02f, 0.00000000e+00f, -4.55645100e-02f, 0.00000000e+00f }, + { 3.84615385e-02f, -3.84615384e-02f, -3.84615386e-02f, -3.84615384e-02f, 4.55645099e-02f, 4.55645100e-02f, 0.00000000e+00f, 4.55645100e-02f, 0.00000000e+00f }, }; static const float AmbiOrderHFGain1O[MAX_AMBI_ORDER+1]{ 3.60555128e+00f, 2.08166600e+00f }, AmbiOrderHFGain2O[MAX_AMBI_ORDER+1]{ 2.68741925e+00f, 2.08166600e+00f, 1.07496770e+00f - }, AmbiOrderHFGain3O[MAX_AMBI_ORDER+1]{ - 2.12652604e+00f, 1.83122879e+00f, 1.30214339e+00f, 6.48052398e-01f }; static const ALuint ChansPerOrder[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; const float *AmbiOrderHFGain{AmbiOrderHFGain1O}; @@ -606,11 +604,10 @@ void InitHrtfPanning(ALCdevice *device) { "full", HrtfRender, 1 }, { "ambi1", NormalRender, 1 }, { "ambi2", NormalRender, 2 }, - { "ambi3", NormalRender, 3 }, }; const char *mode{modeopt->c_str()}; - if(al::strcasecmp(mode, "basic") == 0) + if(al::strcasecmp(mode, "basic") == 0 || al::strcasecmp(mode, "ambi3") == 0) { ERR("HRTF mode \"%s\" deprecated, substituting \"%s\"\n", mode, "ambi2"); mode = "ambi2"; @@ -635,9 +632,7 @@ void InitHrtfPanning(ALCdevice *device) (device->mRenderMode == HrtfRender) ? "+ Full " : "", device->HrtfName.c_str()); - if(ambi_order >= 3) - AmbiOrderHFGain = AmbiOrderHFGain3O; - else if(ambi_order == 2) + if(ambi_order >= 2) AmbiOrderHFGain = AmbiOrderHFGain2O; else if(ambi_order == 1) AmbiOrderHFGain = AmbiOrderHFGain1O; diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index f4f5fd45..7b1d8a91 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -129,7 +129,6 @@ static const struct NameValuePair { }, hrtfModeList[] = { { "1st Order Ambisonic", "ambi1" }, { "2nd Order Ambisonic", "ambi2" }, - { "3rd Order Ambisonic", "ambi3" }, { "Default (Full)", "" }, { "Full", "full" }, @@ -742,10 +741,13 @@ void MainWindow::loadConfig(const QString &fname) ui->enableNeonCheckBox->setChecked(!disabledCpuExts.contains("neon", Qt::CaseInsensitive)); QString hrtfmode{settings.value("hrtf-mode").toString().trimmed()}; - ui->hrtfmodeSlider->setValue(3); - ui->hrtfmodeLabel->setText(hrtfModeList[3].name); - /* The "basic" mode name is no longer supported. Use "ambi2" instead. */ - if(hrtfmode == "basic") hrtfmode = "ambi2"; + ui->hrtfmodeSlider->setValue(2); + ui->hrtfmodeLabel->setText(hrtfModeList[2].name); + /* The "basic" mode name is no longer supported, and "ambi3" is temporarily + * disabled. Use "ambi2" instead. + */ + if(hrtfmode == "basic" || hrtfmode == "ambi3") + hrtfmode = "ambi2"; for(int i = 0;hrtfModeList[i].name[0];i++) { if(hrtfmode == hrtfModeList[i].value) -- cgit v1.2.3 From 0ad512dd512599288f181c6da4c9bcea234811c2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 10 Nov 2019 21:56:19 -0800 Subject: Clear the whole response HRIR before blending --- alc/hrtf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index ac1a19e1..5df15859 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -355,7 +355,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, /* Calculate the blended HRIR coefficients. */ double *coeffout{al::assume_aligned<16>(&res.hrir[0][0])}; - std::fill(coeffout, coeffout + irSize*2, 0.0); + std::fill(coeffout, coeffout + HRIR_LENGTH*2, 0.0); for(ALsizei c{0};c < 4;c++) { const ALfloat *srccoeffs{al::assume_aligned<16>(Hrtf->coeffs[idx[c]*irSize])}; -- cgit v1.2.3 From d120e1464f1760b5b231321c0e68963ad633133f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 13 Nov 2019 08:39:27 -0800 Subject: Improve precision of the HRTF ambisonic decoder matrix --- alc/panning.cpp | 110 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 56 insertions(+), 54 deletions(-) diff --git a/alc/panning.cpp b/alc/panning.cpp index 1288197d..56b8cc77 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -522,66 +522,68 @@ void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, void InitHrtfPanning(ALCdevice *device) { + constexpr float PI{al::MathDefs::Pi()}; + const float CornerElev{static_cast(std::atan2(1.0, std::sqrt(2.0)))}; static const AngularPoint AmbiPoints[]{ - { Deg2Rad( 0.000000f), Deg2Rad( 0.000000f) }, - { Deg2Rad( 0.000000f), Deg2Rad( 180.000000f) }, - { Deg2Rad( 0.000000f), Deg2Rad( -90.000000f) }, - { Deg2Rad( 0.000000f), Deg2Rad( 90.000000f) }, - { Deg2Rad( 90.000000f), Deg2Rad( 0.000000f) }, - { Deg2Rad(-90.000000f), Deg2Rad( 0.000000f) }, - { Deg2Rad( 45.000000f), Deg2Rad( -90.000000f) }, - { Deg2Rad(-45.000000f), Deg2Rad( -90.000000f) }, - { Deg2Rad( 45.000000f), Deg2Rad( 90.000000f) }, - { Deg2Rad(-45.000000f), Deg2Rad( 90.000000f) }, - { Deg2Rad( 45.000000f), Deg2Rad( 0.000000f) }, - { Deg2Rad(-45.000000f), Deg2Rad( 0.000000f) }, - { Deg2Rad( 45.000000f), Deg2Rad( 180.000000f) }, - { Deg2Rad(-45.000000f), Deg2Rad( 180.000000f) }, - { Deg2Rad( 0.000000f), Deg2Rad( -45.000000f) }, - { Deg2Rad( 0.000000f), Deg2Rad( 45.000000f) }, - { Deg2Rad( 0.000000f), Deg2Rad(-135.000000f) }, - { Deg2Rad( 0.000000f), Deg2Rad( 135.000000f) }, - { Deg2Rad( 35.264390f), Deg2Rad( -45.000000f) }, - { Deg2Rad(-35.264390f), Deg2Rad( -45.000000f) }, - { Deg2Rad( 35.264390f), Deg2Rad( 45.000000f) }, - { Deg2Rad(-35.264390f), Deg2Rad( 45.000000f) }, - { Deg2Rad( 35.264390f), Deg2Rad(-135.000000f) }, - { Deg2Rad(-35.264390f), Deg2Rad(-135.000000f) }, - { Deg2Rad( 35.264390f), Deg2Rad( 135.000000f) }, - { Deg2Rad(-35.264390f), Deg2Rad( 135.000000f) }, + { 0.0f, 0.0f }, + { 0.0f, PI }, + { 0.0f, -PI/2.0f }, + { 0.0f, PI/2.0f }, + { PI/2.0f, 0.0f }, + { -PI/2.0f, 0.0f }, + { PI/4.0f, -PI/2.0f }, + { -PI/4.0f, -PI/2.0f }, + { PI/4.0f, PI/2.0f }, + { -PI/4.0f, PI/2.0f }, + { PI/4.0f, 0.0f }, + { -PI/4.0f, 0.0f }, + { PI/4.0f, PI }, + { -PI/4.0f, PI }, + { 0.0f, -PI/4.0f }, + { 0.0f, PI/4.0f }, + { 0.0f, -PI*3.0f/4.0f }, + { 0.0f, PI*3.0f/4.0f }, + { CornerElev, -PI/4.0f }, + { -CornerElev, -PI/4.0f }, + { CornerElev, PI/4.0f }, + { -CornerElev, PI/4.0f }, + { CornerElev, -PI*3.0f/4.0f }, + { -CornerElev, -PI*3.0f/4.0f }, + { CornerElev, PI*3.0f/4.0f }, + { -CornerElev, PI*3.0f/4.0f }, }; static const float AmbiMatrix[][MAX_AMBI_CHANNELS]{ - { 3.84615387e-02f, 0.00000000e+00f, 0.00000000e+00f, 6.66173389e-02f, 0.00000000e+00f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 8.60662966e-02f }, - { 3.84615387e-02f, 0.00000000e+00f, 0.00000000e+00f, -6.66173389e-02f, 0.00000000e+00f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 8.60662966e-02f }, - { 3.84615387e-02f, 6.66173389e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, -8.60662966e-02f }, - { 3.84615387e-02f, -6.66173389e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, -8.60662966e-02f }, - { 3.84615379e-02f, 0.00000000e+00f, 6.66173384e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 9.93807988e-02f, 0.00000000e+00f, 0.00000000e+00f }, - { 3.84615379e-02f, 0.00000000e+00f, -6.66173384e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 9.93807988e-02f, 0.00000000e+00f, 0.00000000e+00f }, - { 3.84615383e-02f, 4.71055721e-02f, 4.71055717e-02f, 0.00000000e+00f, 0.00000000e+00f, 6.83467647e-02f, 2.48451995e-02f, 0.00000000e+00f, -4.30331483e-02f }, - { 3.84615383e-02f, 4.71055721e-02f, -4.71055717e-02f, 0.00000000e+00f, 0.00000000e+00f, -6.83467647e-02f, 2.48451995e-02f, 0.00000000e+00f, -4.30331483e-02f }, - { 3.84615383e-02f, -4.71055721e-02f, 4.71055717e-02f, 0.00000000e+00f, 0.00000000e+00f, -6.83467647e-02f, 2.48451995e-02f, 0.00000000e+00f, -4.30331483e-02f }, - { 3.84615383e-02f, -4.71055721e-02f, -4.71055717e-02f, 0.00000000e+00f, 0.00000000e+00f, 6.83467647e-02f, 2.48451995e-02f, 0.00000000e+00f, -4.30331483e-02f }, - { 3.84615383e-02f, 0.00000000e+00f, 4.71055717e-02f, 4.71055721e-02f, 0.00000000e+00f, 0.00000000e+00f, 2.48451995e-02f, 6.83467647e-02f, 4.30331483e-02f }, - { 3.84615383e-02f, 0.00000000e+00f, -4.71055717e-02f, 4.71055721e-02f, 0.00000000e+00f, 0.00000000e+00f, 2.48451995e-02f, -6.83467647e-02f, 4.30331483e-02f }, - { 3.84615383e-02f, 0.00000000e+00f, 4.71055717e-02f, -4.71055721e-02f, 0.00000000e+00f, 0.00000000e+00f, 2.48451995e-02f, -6.83467647e-02f, 4.30331483e-02f }, - { 3.84615383e-02f, 0.00000000e+00f, -4.71055717e-02f, -4.71055721e-02f, 0.00000000e+00f, 0.00000000e+00f, 2.48451995e-02f, 6.83467647e-02f, 4.30331483e-02f }, - { 3.84615387e-02f, 4.71055721e-02f, 0.00000000e+00f, 4.71055721e-02f, 6.83467654e-02f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 0.00000000e+00f }, - { 3.84615387e-02f, -4.71055721e-02f, 0.00000000e+00f, 4.71055721e-02f, -6.83467654e-02f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 0.00000000e+00f }, - { 3.84615387e-02f, 4.71055721e-02f, 0.00000000e+00f, -4.71055721e-02f, -6.83467654e-02f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 0.00000000e+00f }, - { 3.84615387e-02f, -4.71055721e-02f, 0.00000000e+00f, -4.71055721e-02f, 6.83467654e-02f, 0.00000000e+00f, -4.96903997e-02f, 0.00000000e+00f, 0.00000000e+00f }, - { 3.84615385e-02f, 3.84615384e-02f, 3.84615386e-02f, 3.84615384e-02f, 4.55645099e-02f, 4.55645100e-02f, 0.00000000e+00f, 4.55645100e-02f, 0.00000000e+00f }, - { 3.84615385e-02f, 3.84615384e-02f, -3.84615386e-02f, 3.84615384e-02f, 4.55645099e-02f, -4.55645100e-02f, 0.00000000e+00f, -4.55645100e-02f, 0.00000000e+00f }, - { 3.84615385e-02f, -3.84615384e-02f, 3.84615386e-02f, 3.84615384e-02f, -4.55645099e-02f, -4.55645100e-02f, 0.00000000e+00f, 4.55645100e-02f, 0.00000000e+00f }, - { 3.84615385e-02f, -3.84615384e-02f, -3.84615386e-02f, 3.84615384e-02f, -4.55645099e-02f, 4.55645100e-02f, 0.00000000e+00f, -4.55645100e-02f, 0.00000000e+00f }, - { 3.84615385e-02f, 3.84615384e-02f, 3.84615386e-02f, -3.84615384e-02f, -4.55645099e-02f, 4.55645100e-02f, 0.00000000e+00f, -4.55645100e-02f, 0.00000000e+00f }, - { 3.84615385e-02f, 3.84615384e-02f, -3.84615386e-02f, -3.84615384e-02f, -4.55645099e-02f, -4.55645100e-02f, 0.00000000e+00f, 4.55645100e-02f, 0.00000000e+00f }, - { 3.84615385e-02f, -3.84615384e-02f, 3.84615386e-02f, -3.84615384e-02f, 4.55645099e-02f, -4.55645100e-02f, 0.00000000e+00f, -4.55645100e-02f, 0.00000000e+00f }, - { 3.84615385e-02f, -3.84615384e-02f, -3.84615386e-02f, -3.84615384e-02f, 4.55645099e-02f, 4.55645100e-02f, 0.00000000e+00f, 4.55645100e-02f, 0.00000000e+00f }, + { 3.846153846e-02f, 0.000000000e+00f, 0.000000000e+00f, 6.661733875e-02f, 0.000000000e+00f, 0.000000000e+00f, -4.969039950e-02f, 0.000000000e+00f, 8.606629658e-02f }, + { 3.846153846e-02f, 0.000000000e+00f, 0.000000000e+00f, -6.661733875e-02f, 0.000000000e+00f, 0.000000000e+00f, -4.969039950e-02f, 0.000000000e+00f, 8.606629658e-02f }, + { 3.846153846e-02f, 6.661733875e-02f, 0.000000000e+00f, 0.000000000e+00f, 0.000000000e+00f, 0.000000000e+00f, -4.969039950e-02f, 0.000000000e+00f, -8.606629658e-02f }, + { 3.846153846e-02f, -6.661733875e-02f, 0.000000000e+00f, 0.000000000e+00f, 0.000000000e+00f, 0.000000000e+00f, -4.969039950e-02f, 0.000000000e+00f, -8.606629658e-02f }, + { 3.846153846e-02f, 0.000000000e+00f, 6.661733875e-02f, 0.000000000e+00f, 0.000000000e+00f, 0.000000000e+00f, 9.938079900e-02f, 0.000000000e+00f, 0.000000000e+00f }, + { 3.846153846e-02f, 0.000000000e+00f, -6.661733875e-02f, 0.000000000e+00f, 0.000000000e+00f, 0.000000000e+00f, 9.938079900e-02f, 0.000000000e+00f, 0.000000000e+00f }, + { 3.846153846e-02f, 4.710557198e-02f, 4.710557198e-02f, 0.000000000e+00f, 0.000000000e+00f, 6.834676493e-02f, 2.484519975e-02f, 0.000000000e+00f, -4.303314829e-02f }, + { 3.846153846e-02f, 4.710557198e-02f, -4.710557198e-02f, 0.000000000e+00f, 0.000000000e+00f, -6.834676493e-02f, 2.484519975e-02f, 0.000000000e+00f, -4.303314829e-02f }, + { 3.846153846e-02f, -4.710557198e-02f, 4.710557198e-02f, 0.000000000e+00f, 0.000000000e+00f, -6.834676493e-02f, 2.484519975e-02f, 0.000000000e+00f, -4.303314829e-02f }, + { 3.846153846e-02f, -4.710557198e-02f, -4.710557198e-02f, 0.000000000e+00f, 0.000000000e+00f, 6.834676493e-02f, 2.484519975e-02f, 0.000000000e+00f, -4.303314829e-02f }, + { 3.846153846e-02f, 0.000000000e+00f, 4.710557198e-02f, 4.710557198e-02f, 0.000000000e+00f, 0.000000000e+00f, 2.484519975e-02f, 6.834676493e-02f, 4.303314829e-02f }, + { 3.846153846e-02f, 0.000000000e+00f, -4.710557198e-02f, 4.710557198e-02f, 0.000000000e+00f, 0.000000000e+00f, 2.484519975e-02f, -6.834676493e-02f, 4.303314829e-02f }, + { 3.846153846e-02f, 0.000000000e+00f, 4.710557198e-02f, -4.710557198e-02f, 0.000000000e+00f, 0.000000000e+00f, 2.484519975e-02f, -6.834676493e-02f, 4.303314829e-02f }, + { 3.846153846e-02f, 0.000000000e+00f, -4.710557198e-02f, -4.710557198e-02f, 0.000000000e+00f, 0.000000000e+00f, 2.484519975e-02f, 6.834676493e-02f, 4.303314829e-02f }, + { 3.846153846e-02f, 4.710557198e-02f, 0.000000000e+00f, 4.710557198e-02f, 6.834676493e-02f, 0.000000000e+00f, -4.969039950e-02f, 0.000000000e+00f, 0.000000000e+00f }, + { 3.846153846e-02f, -4.710557198e-02f, 0.000000000e+00f, 4.710557198e-02f, -6.834676493e-02f, 0.000000000e+00f, -4.969039950e-02f, 0.000000000e+00f, 0.000000000e+00f }, + { 3.846153846e-02f, 4.710557198e-02f, 0.000000000e+00f, -4.710557198e-02f, -6.834676493e-02f, 0.000000000e+00f, -4.969039950e-02f, 0.000000000e+00f, 0.000000000e+00f }, + { 3.846153846e-02f, -4.710557198e-02f, 0.000000000e+00f, -4.710557198e-02f, 6.834676493e-02f, 0.000000000e+00f, -4.969039950e-02f, 0.000000000e+00f, 0.000000000e+00f }, + { 3.846153846e-02f, 3.846153846e-02f, 3.846153846e-02f, 3.846153846e-02f, 4.556450996e-02f, 4.556450996e-02f, 0.000000000e+00f, 4.556450996e-02f, 0.000000000e+00f }, + { 3.846153846e-02f, 3.846153846e-02f, -3.846153846e-02f, 3.846153846e-02f, 4.556450996e-02f, -4.556450996e-02f, 0.000000000e+00f, -4.556450996e-02f, 0.000000000e+00f }, + { 3.846153846e-02f, -3.846153846e-02f, 3.846153846e-02f, 3.846153846e-02f, -4.556450996e-02f, -4.556450996e-02f, 0.000000000e+00f, 4.556450996e-02f, 0.000000000e+00f }, + { 3.846153846e-02f, -3.846153846e-02f, -3.846153846e-02f, 3.846153846e-02f, -4.556450996e-02f, 4.556450996e-02f, 0.000000000e+00f, -4.556450996e-02f, 0.000000000e+00f }, + { 3.846153846e-02f, 3.846153846e-02f, 3.846153846e-02f, -3.846153846e-02f, -4.556450996e-02f, 4.556450996e-02f, 0.000000000e+00f, -4.556450996e-02f, 0.000000000e+00f }, + { 3.846153846e-02f, 3.846153846e-02f, -3.846153846e-02f, -3.846153846e-02f, -4.556450996e-02f, -4.556450996e-02f, 0.000000000e+00f, 4.556450996e-02f, 0.000000000e+00f }, + { 3.846153846e-02f, -3.846153846e-02f, 3.846153846e-02f, -3.846153846e-02f, 4.556450996e-02f, -4.556450996e-02f, 0.000000000e+00f, -4.556450996e-02f, 0.000000000e+00f }, + { 3.846153846e-02f, -3.846153846e-02f, -3.846153846e-02f, -3.846153846e-02f, 4.556450996e-02f, 4.556450996e-02f, 0.000000000e+00f, 4.556450996e-02f, 0.000000000e+00f }, }; static const float AmbiOrderHFGain1O[MAX_AMBI_ORDER+1]{ - 3.60555128e+00f, 2.08166600e+00f + 3.605551275e+00f, 2.081665999e+00f }, AmbiOrderHFGain2O[MAX_AMBI_ORDER+1]{ - 2.68741925e+00f, 2.08166600e+00f, 1.07496770e+00f + 2.687419249e+00f, 2.081665999e+00f, 1.074967700e+00f }; static const ALuint ChansPerOrder[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; const float *AmbiOrderHFGain{AmbiOrderHFGain1O}; -- cgit v1.2.3 From 6ad252efdaf2f4a9ed569097c35b8b781f9f1d50 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 16 Nov 2019 14:07:31 -0800 Subject: Use wrappers to distinguish elevation and azimuth values --- alc/hrtf.cpp | 6 +++--- alc/hrtf.h | 6 ++++-- alc/panning.cpp | 52 ++++++++++++++++++++++++++-------------------------- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index 5df15859..2137723d 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -319,14 +319,14 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, auto &field = Hrtf->field[0]; /* Calculate the elevation indices. */ - const auto elev0 = CalcEvIndex(field.evCount, pt.Elev); + const auto elev0 = CalcEvIndex(field.evCount, pt.Elev.value); const ALsizei elev1_idx{mini(elev0.idx+1, field.evCount-1)}; const ALsizei ir0offset{Hrtf->elev[elev0.idx].irOffset}; const ALsizei ir1offset{Hrtf->elev[elev1_idx].irOffset}; /* Calculate azimuth indices. */ - const auto az0 = CalcAzIndex(Hrtf->elev[elev0.idx].azCount, pt.Azim); - const auto az1 = CalcAzIndex(Hrtf->elev[elev1_idx].azCount, pt.Azim); + const auto az0 = CalcAzIndex(Hrtf->elev[elev0.idx].azCount, pt.Azim.value); + const auto az1 = CalcAzIndex(Hrtf->elev[elev1_idx].azCount, pt.Azim.value); /* Calculate the HRIR indices to blend. */ const ALuint idx[4]{ diff --git a/alc/hrtf.h b/alc/hrtf.h index a81ebfed..98df801b 100644 --- a/alc/hrtf.h +++ b/alc/hrtf.h @@ -88,9 +88,11 @@ struct DirectHrtfState { DEF_FAM_NEWDEL(DirectHrtfState, Coeffs) }; +struct ElevRadius { float value; }; +struct AzimRadius { float value; }; struct AngularPoint { - ALfloat Elev; - ALfloat Azim; + ElevRadius Elev; + AzimRadius Azim; }; diff --git a/alc/panning.cpp b/alc/panning.cpp index 56b8cc77..b754d18b 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -525,32 +525,32 @@ void InitHrtfPanning(ALCdevice *device) constexpr float PI{al::MathDefs::Pi()}; const float CornerElev{static_cast(std::atan2(1.0, std::sqrt(2.0)))}; static const AngularPoint AmbiPoints[]{ - { 0.0f, 0.0f }, - { 0.0f, PI }, - { 0.0f, -PI/2.0f }, - { 0.0f, PI/2.0f }, - { PI/2.0f, 0.0f }, - { -PI/2.0f, 0.0f }, - { PI/4.0f, -PI/2.0f }, - { -PI/4.0f, -PI/2.0f }, - { PI/4.0f, PI/2.0f }, - { -PI/4.0f, PI/2.0f }, - { PI/4.0f, 0.0f }, - { -PI/4.0f, 0.0f }, - { PI/4.0f, PI }, - { -PI/4.0f, PI }, - { 0.0f, -PI/4.0f }, - { 0.0f, PI/4.0f }, - { 0.0f, -PI*3.0f/4.0f }, - { 0.0f, PI*3.0f/4.0f }, - { CornerElev, -PI/4.0f }, - { -CornerElev, -PI/4.0f }, - { CornerElev, PI/4.0f }, - { -CornerElev, PI/4.0f }, - { CornerElev, -PI*3.0f/4.0f }, - { -CornerElev, -PI*3.0f/4.0f }, - { CornerElev, PI*3.0f/4.0f }, - { -CornerElev, PI*3.0f/4.0f }, + { ElevRadius{ 0.0f}, AzimRadius{ 0.0f} }, + { ElevRadius{ 0.0f}, AzimRadius{ PI} }, + { ElevRadius{ 0.0f}, AzimRadius{ -PI/2.0f} }, + { ElevRadius{ 0.0f}, AzimRadius{ PI/2.0f} }, + { ElevRadius{ PI/2.0f}, AzimRadius{ 0.0f} }, + { ElevRadius{ -PI/2.0f}, AzimRadius{ 0.0f} }, + { ElevRadius{ PI/4.0f}, AzimRadius{ -PI/2.0f} }, + { ElevRadius{ -PI/4.0f}, AzimRadius{ -PI/2.0f} }, + { ElevRadius{ PI/4.0f}, AzimRadius{ PI/2.0f} }, + { ElevRadius{ -PI/4.0f}, AzimRadius{ PI/2.0f} }, + { ElevRadius{ PI/4.0f}, AzimRadius{ 0.0f} }, + { ElevRadius{ -PI/4.0f}, AzimRadius{ 0.0f} }, + { ElevRadius{ PI/4.0f}, AzimRadius{ PI} }, + { ElevRadius{ -PI/4.0f}, AzimRadius{ PI} }, + { ElevRadius{ 0.0f}, AzimRadius{ -PI/4.0f} }, + { ElevRadius{ 0.0f}, AzimRadius{ PI/4.0f} }, + { ElevRadius{ 0.0f}, AzimRadius{-PI*3.0f/4.0f} }, + { ElevRadius{ 0.0f}, AzimRadius{ PI*3.0f/4.0f} }, + { ElevRadius{ CornerElev}, AzimRadius{ -PI/4.0f} }, + { ElevRadius{-CornerElev}, AzimRadius{ -PI/4.0f} }, + { ElevRadius{ CornerElev}, AzimRadius{ PI/4.0f} }, + { ElevRadius{-CornerElev}, AzimRadius{ PI/4.0f} }, + { ElevRadius{ CornerElev}, AzimRadius{-PI*3.0f/4.0f} }, + { ElevRadius{-CornerElev}, AzimRadius{-PI*3.0f/4.0f} }, + { ElevRadius{ CornerElev}, AzimRadius{ PI*3.0f/4.0f} }, + { ElevRadius{-CornerElev}, AzimRadius{ PI*3.0f/4.0f} }, }; static const float AmbiMatrix[][MAX_AMBI_CHANNELS]{ { 3.846153846e-02f, 0.000000000e+00f, 0.000000000e+00f, 6.661733875e-02f, 0.000000000e+00f, 0.000000000e+00f, -4.969039950e-02f, 0.000000000e+00f, 8.606629658e-02f }, -- cgit v1.2.3 From c86a28af5cd88dd3515297fd55a9914718f28d13 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 16 Nov 2019 14:33:09 -0800 Subject: Simplify some pi statements --- alc/panning.cpp | 55 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/alc/panning.cpp b/alc/panning.cpp index b754d18b..893147a0 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -523,34 +523,37 @@ void InitCustomPanning(ALCdevice *device, bool hqdec, const AmbDecConf *conf, void InitHrtfPanning(ALCdevice *device) { constexpr float PI{al::MathDefs::Pi()}; + constexpr float PI_2{al::MathDefs::Pi() / 2.0f}; + constexpr float PI_4{al::MathDefs::Pi() / 4.0f}; + constexpr float PI3_4{al::MathDefs::Pi() * 3.0f / 4.0f}; const float CornerElev{static_cast(std::atan2(1.0, std::sqrt(2.0)))}; static const AngularPoint AmbiPoints[]{ - { ElevRadius{ 0.0f}, AzimRadius{ 0.0f} }, - { ElevRadius{ 0.0f}, AzimRadius{ PI} }, - { ElevRadius{ 0.0f}, AzimRadius{ -PI/2.0f} }, - { ElevRadius{ 0.0f}, AzimRadius{ PI/2.0f} }, - { ElevRadius{ PI/2.0f}, AzimRadius{ 0.0f} }, - { ElevRadius{ -PI/2.0f}, AzimRadius{ 0.0f} }, - { ElevRadius{ PI/4.0f}, AzimRadius{ -PI/2.0f} }, - { ElevRadius{ -PI/4.0f}, AzimRadius{ -PI/2.0f} }, - { ElevRadius{ PI/4.0f}, AzimRadius{ PI/2.0f} }, - { ElevRadius{ -PI/4.0f}, AzimRadius{ PI/2.0f} }, - { ElevRadius{ PI/4.0f}, AzimRadius{ 0.0f} }, - { ElevRadius{ -PI/4.0f}, AzimRadius{ 0.0f} }, - { ElevRadius{ PI/4.0f}, AzimRadius{ PI} }, - { ElevRadius{ -PI/4.0f}, AzimRadius{ PI} }, - { ElevRadius{ 0.0f}, AzimRadius{ -PI/4.0f} }, - { ElevRadius{ 0.0f}, AzimRadius{ PI/4.0f} }, - { ElevRadius{ 0.0f}, AzimRadius{-PI*3.0f/4.0f} }, - { ElevRadius{ 0.0f}, AzimRadius{ PI*3.0f/4.0f} }, - { ElevRadius{ CornerElev}, AzimRadius{ -PI/4.0f} }, - { ElevRadius{-CornerElev}, AzimRadius{ -PI/4.0f} }, - { ElevRadius{ CornerElev}, AzimRadius{ PI/4.0f} }, - { ElevRadius{-CornerElev}, AzimRadius{ PI/4.0f} }, - { ElevRadius{ CornerElev}, AzimRadius{-PI*3.0f/4.0f} }, - { ElevRadius{-CornerElev}, AzimRadius{-PI*3.0f/4.0f} }, - { ElevRadius{ CornerElev}, AzimRadius{ PI*3.0f/4.0f} }, - { ElevRadius{-CornerElev}, AzimRadius{ PI*3.0f/4.0f} }, + { ElevRadius{ 0.0f}, AzimRadius{ 0.0f} }, + { ElevRadius{ 0.0f}, AzimRadius{ PI} }, + { ElevRadius{ 0.0f}, AzimRadius{ -PI_2} }, + { ElevRadius{ 0.0f}, AzimRadius{ PI_2} }, + { ElevRadius{ PI_2}, AzimRadius{ 0.0f} }, + { ElevRadius{ -PI_2}, AzimRadius{ 0.0f} }, + { ElevRadius{ PI_4}, AzimRadius{ -PI_2} }, + { ElevRadius{ -PI_4}, AzimRadius{ -PI_2} }, + { ElevRadius{ PI_4}, AzimRadius{ PI_2} }, + { ElevRadius{ -PI_4}, AzimRadius{ PI_2} }, + { ElevRadius{ PI_4}, AzimRadius{ 0.0f} }, + { ElevRadius{ -PI_4}, AzimRadius{ 0.0f} }, + { ElevRadius{ PI_4}, AzimRadius{ PI} }, + { ElevRadius{ -PI_4}, AzimRadius{ PI} }, + { ElevRadius{ 0.0f}, AzimRadius{ -PI_4} }, + { ElevRadius{ 0.0f}, AzimRadius{ PI_4} }, + { ElevRadius{ 0.0f}, AzimRadius{-PI3_4} }, + { ElevRadius{ 0.0f}, AzimRadius{ PI3_4} }, + { ElevRadius{ CornerElev}, AzimRadius{ -PI_4} }, + { ElevRadius{-CornerElev}, AzimRadius{ -PI_4} }, + { ElevRadius{ CornerElev}, AzimRadius{ PI_4} }, + { ElevRadius{-CornerElev}, AzimRadius{ PI_4} }, + { ElevRadius{ CornerElev}, AzimRadius{-PI3_4} }, + { ElevRadius{-CornerElev}, AzimRadius{-PI3_4} }, + { ElevRadius{ CornerElev}, AzimRadius{ PI3_4} }, + { ElevRadius{-CornerElev}, AzimRadius{ PI3_4} }, }; static const float AmbiMatrix[][MAX_AMBI_CHANNELS]{ { 3.846153846e-02f, 0.000000000e+00f, 0.000000000e+00f, 6.661733875e-02f, 0.000000000e+00f, 0.000000000e+00f, -4.969039950e-02f, 0.000000000e+00f, 8.606629658e-02f }, -- cgit v1.2.3 From 6159b837cf1d5a2217962365db1354b2d7bad476 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 18 Nov 2019 00:32:01 -0800 Subject: Add a first-order ambisonic decoder for HRTF --- alc/panning.cpp | 69 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/alc/panning.cpp b/alc/panning.cpp index 893147a0..e85222bd 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -527,7 +527,16 @@ void InitHrtfPanning(ALCdevice *device) constexpr float PI_4{al::MathDefs::Pi() / 4.0f}; constexpr float PI3_4{al::MathDefs::Pi() * 3.0f / 4.0f}; const float CornerElev{static_cast(std::atan2(1.0, std::sqrt(2.0)))}; - static const AngularPoint AmbiPoints[]{ + static const AngularPoint AmbiPoints1O[]{ + { ElevRadius{ CornerElev}, AzimRadius{ -PI_4} }, + { ElevRadius{ CornerElev}, AzimRadius{-PI3_4} }, + { ElevRadius{ CornerElev}, AzimRadius{ PI_4} }, + { ElevRadius{ CornerElev}, AzimRadius{ PI3_4} }, + { ElevRadius{-CornerElev}, AzimRadius{ -PI_4} }, + { ElevRadius{-CornerElev}, AzimRadius{-PI3_4} }, + { ElevRadius{-CornerElev}, AzimRadius{ PI_4} }, + { ElevRadius{-CornerElev}, AzimRadius{ PI3_4} }, + }, AmbiPoints2O[]{ { ElevRadius{ 0.0f}, AzimRadius{ 0.0f} }, { ElevRadius{ 0.0f}, AzimRadius{ PI} }, { ElevRadius{ 0.0f}, AzimRadius{ -PI_2} }, @@ -535,27 +544,36 @@ void InitHrtfPanning(ALCdevice *device) { ElevRadius{ PI_2}, AzimRadius{ 0.0f} }, { ElevRadius{ -PI_2}, AzimRadius{ 0.0f} }, { ElevRadius{ PI_4}, AzimRadius{ -PI_2} }, - { ElevRadius{ -PI_4}, AzimRadius{ -PI_2} }, { ElevRadius{ PI_4}, AzimRadius{ PI_2} }, + { ElevRadius{ -PI_4}, AzimRadius{ -PI_2} }, { ElevRadius{ -PI_4}, AzimRadius{ PI_2} }, { ElevRadius{ PI_4}, AzimRadius{ 0.0f} }, - { ElevRadius{ -PI_4}, AzimRadius{ 0.0f} }, { ElevRadius{ PI_4}, AzimRadius{ PI} }, + { ElevRadius{ -PI_4}, AzimRadius{ 0.0f} }, { ElevRadius{ -PI_4}, AzimRadius{ PI} }, { ElevRadius{ 0.0f}, AzimRadius{ -PI_4} }, - { ElevRadius{ 0.0f}, AzimRadius{ PI_4} }, { ElevRadius{ 0.0f}, AzimRadius{-PI3_4} }, + { ElevRadius{ 0.0f}, AzimRadius{ PI_4} }, { ElevRadius{ 0.0f}, AzimRadius{ PI3_4} }, { ElevRadius{ CornerElev}, AzimRadius{ -PI_4} }, - { ElevRadius{-CornerElev}, AzimRadius{ -PI_4} }, - { ElevRadius{ CornerElev}, AzimRadius{ PI_4} }, - { ElevRadius{-CornerElev}, AzimRadius{ PI_4} }, { ElevRadius{ CornerElev}, AzimRadius{-PI3_4} }, - { ElevRadius{-CornerElev}, AzimRadius{-PI3_4} }, + { ElevRadius{ CornerElev}, AzimRadius{ PI_4} }, { ElevRadius{ CornerElev}, AzimRadius{ PI3_4} }, + { ElevRadius{-CornerElev}, AzimRadius{ -PI_4} }, + { ElevRadius{-CornerElev}, AzimRadius{-PI3_4} }, + { ElevRadius{-CornerElev}, AzimRadius{ PI_4} }, { ElevRadius{-CornerElev}, AzimRadius{ PI3_4} }, }; - static const float AmbiMatrix[][MAX_AMBI_CHANNELS]{ + static const float AmbiMatrix1O[][MAX_AMBI_CHANNELS]{ + { 1.250000000e-01f, 1.250000000e-01f, 1.250000000e-01f, 1.250000000e-01f }, + { 1.250000000e-01f, 1.250000000e-01f, 1.250000000e-01f, -1.250000000e-01f }, + { 1.250000000e-01f, -1.250000000e-01f, 1.250000000e-01f, 1.250000000e-01f }, + { 1.250000000e-01f, -1.250000000e-01f, 1.250000000e-01f, -1.250000000e-01f }, + { 1.250000000e-01f, 1.250000000e-01f, -1.250000000e-01f, 1.250000000e-01f }, + { 1.250000000e-01f, 1.250000000e-01f, -1.250000000e-01f, -1.250000000e-01f }, + { 1.250000000e-01f, -1.250000000e-01f, -1.250000000e-01f, 1.250000000e-01f }, + { 1.250000000e-01f, -1.250000000e-01f, -1.250000000e-01f, -1.250000000e-01f }, + }, AmbiMatrix2O[][MAX_AMBI_CHANNELS]{ { 3.846153846e-02f, 0.000000000e+00f, 0.000000000e+00f, 6.661733875e-02f, 0.000000000e+00f, 0.000000000e+00f, -4.969039950e-02f, 0.000000000e+00f, 8.606629658e-02f }, { 3.846153846e-02f, 0.000000000e+00f, 0.000000000e+00f, -6.661733875e-02f, 0.000000000e+00f, 0.000000000e+00f, -4.969039950e-02f, 0.000000000e+00f, 8.606629658e-02f }, { 3.846153846e-02f, 6.661733875e-02f, 0.000000000e+00f, 0.000000000e+00f, 0.000000000e+00f, 0.000000000e+00f, -4.969039950e-02f, 0.000000000e+00f, -8.606629658e-02f }, @@ -563,35 +581,35 @@ void InitHrtfPanning(ALCdevice *device) { 3.846153846e-02f, 0.000000000e+00f, 6.661733875e-02f, 0.000000000e+00f, 0.000000000e+00f, 0.000000000e+00f, 9.938079900e-02f, 0.000000000e+00f, 0.000000000e+00f }, { 3.846153846e-02f, 0.000000000e+00f, -6.661733875e-02f, 0.000000000e+00f, 0.000000000e+00f, 0.000000000e+00f, 9.938079900e-02f, 0.000000000e+00f, 0.000000000e+00f }, { 3.846153846e-02f, 4.710557198e-02f, 4.710557198e-02f, 0.000000000e+00f, 0.000000000e+00f, 6.834676493e-02f, 2.484519975e-02f, 0.000000000e+00f, -4.303314829e-02f }, - { 3.846153846e-02f, 4.710557198e-02f, -4.710557198e-02f, 0.000000000e+00f, 0.000000000e+00f, -6.834676493e-02f, 2.484519975e-02f, 0.000000000e+00f, -4.303314829e-02f }, { 3.846153846e-02f, -4.710557198e-02f, 4.710557198e-02f, 0.000000000e+00f, 0.000000000e+00f, -6.834676493e-02f, 2.484519975e-02f, 0.000000000e+00f, -4.303314829e-02f }, + { 3.846153846e-02f, 4.710557198e-02f, -4.710557198e-02f, 0.000000000e+00f, 0.000000000e+00f, -6.834676493e-02f, 2.484519975e-02f, 0.000000000e+00f, -4.303314829e-02f }, { 3.846153846e-02f, -4.710557198e-02f, -4.710557198e-02f, 0.000000000e+00f, 0.000000000e+00f, 6.834676493e-02f, 2.484519975e-02f, 0.000000000e+00f, -4.303314829e-02f }, { 3.846153846e-02f, 0.000000000e+00f, 4.710557198e-02f, 4.710557198e-02f, 0.000000000e+00f, 0.000000000e+00f, 2.484519975e-02f, 6.834676493e-02f, 4.303314829e-02f }, - { 3.846153846e-02f, 0.000000000e+00f, -4.710557198e-02f, 4.710557198e-02f, 0.000000000e+00f, 0.000000000e+00f, 2.484519975e-02f, -6.834676493e-02f, 4.303314829e-02f }, { 3.846153846e-02f, 0.000000000e+00f, 4.710557198e-02f, -4.710557198e-02f, 0.000000000e+00f, 0.000000000e+00f, 2.484519975e-02f, -6.834676493e-02f, 4.303314829e-02f }, + { 3.846153846e-02f, 0.000000000e+00f, -4.710557198e-02f, 4.710557198e-02f, 0.000000000e+00f, 0.000000000e+00f, 2.484519975e-02f, -6.834676493e-02f, 4.303314829e-02f }, { 3.846153846e-02f, 0.000000000e+00f, -4.710557198e-02f, -4.710557198e-02f, 0.000000000e+00f, 0.000000000e+00f, 2.484519975e-02f, 6.834676493e-02f, 4.303314829e-02f }, { 3.846153846e-02f, 4.710557198e-02f, 0.000000000e+00f, 4.710557198e-02f, 6.834676493e-02f, 0.000000000e+00f, -4.969039950e-02f, 0.000000000e+00f, 0.000000000e+00f }, - { 3.846153846e-02f, -4.710557198e-02f, 0.000000000e+00f, 4.710557198e-02f, -6.834676493e-02f, 0.000000000e+00f, -4.969039950e-02f, 0.000000000e+00f, 0.000000000e+00f }, { 3.846153846e-02f, 4.710557198e-02f, 0.000000000e+00f, -4.710557198e-02f, -6.834676493e-02f, 0.000000000e+00f, -4.969039950e-02f, 0.000000000e+00f, 0.000000000e+00f }, + { 3.846153846e-02f, -4.710557198e-02f, 0.000000000e+00f, 4.710557198e-02f, -6.834676493e-02f, 0.000000000e+00f, -4.969039950e-02f, 0.000000000e+00f, 0.000000000e+00f }, { 3.846153846e-02f, -4.710557198e-02f, 0.000000000e+00f, -4.710557198e-02f, 6.834676493e-02f, 0.000000000e+00f, -4.969039950e-02f, 0.000000000e+00f, 0.000000000e+00f }, { 3.846153846e-02f, 3.846153846e-02f, 3.846153846e-02f, 3.846153846e-02f, 4.556450996e-02f, 4.556450996e-02f, 0.000000000e+00f, 4.556450996e-02f, 0.000000000e+00f }, - { 3.846153846e-02f, 3.846153846e-02f, -3.846153846e-02f, 3.846153846e-02f, 4.556450996e-02f, -4.556450996e-02f, 0.000000000e+00f, -4.556450996e-02f, 0.000000000e+00f }, - { 3.846153846e-02f, -3.846153846e-02f, 3.846153846e-02f, 3.846153846e-02f, -4.556450996e-02f, -4.556450996e-02f, 0.000000000e+00f, 4.556450996e-02f, 0.000000000e+00f }, - { 3.846153846e-02f, -3.846153846e-02f, -3.846153846e-02f, 3.846153846e-02f, -4.556450996e-02f, 4.556450996e-02f, 0.000000000e+00f, -4.556450996e-02f, 0.000000000e+00f }, { 3.846153846e-02f, 3.846153846e-02f, 3.846153846e-02f, -3.846153846e-02f, -4.556450996e-02f, 4.556450996e-02f, 0.000000000e+00f, -4.556450996e-02f, 0.000000000e+00f }, - { 3.846153846e-02f, 3.846153846e-02f, -3.846153846e-02f, -3.846153846e-02f, -4.556450996e-02f, -4.556450996e-02f, 0.000000000e+00f, 4.556450996e-02f, 0.000000000e+00f }, + { 3.846153846e-02f, -3.846153846e-02f, 3.846153846e-02f, 3.846153846e-02f, -4.556450996e-02f, -4.556450996e-02f, 0.000000000e+00f, 4.556450996e-02f, 0.000000000e+00f }, { 3.846153846e-02f, -3.846153846e-02f, 3.846153846e-02f, -3.846153846e-02f, 4.556450996e-02f, -4.556450996e-02f, 0.000000000e+00f, -4.556450996e-02f, 0.000000000e+00f }, + { 3.846153846e-02f, 3.846153846e-02f, -3.846153846e-02f, 3.846153846e-02f, 4.556450996e-02f, -4.556450996e-02f, 0.000000000e+00f, -4.556450996e-02f, 0.000000000e+00f }, + { 3.846153846e-02f, 3.846153846e-02f, -3.846153846e-02f, -3.846153846e-02f, -4.556450996e-02f, -4.556450996e-02f, 0.000000000e+00f, 4.556450996e-02f, 0.000000000e+00f }, + { 3.846153846e-02f, -3.846153846e-02f, -3.846153846e-02f, 3.846153846e-02f, -4.556450996e-02f, 4.556450996e-02f, 0.000000000e+00f, -4.556450996e-02f, 0.000000000e+00f }, { 3.846153846e-02f, -3.846153846e-02f, -3.846153846e-02f, -3.846153846e-02f, 4.556450996e-02f, 4.556450996e-02f, 0.000000000e+00f, 4.556450996e-02f, 0.000000000e+00f }, }; static const float AmbiOrderHFGain1O[MAX_AMBI_ORDER+1]{ - 3.605551275e+00f, 2.081665999e+00f + 2.000000000e+00f, 1.154700538e+00f }, AmbiOrderHFGain2O[MAX_AMBI_ORDER+1]{ 2.687419249e+00f, 2.081665999e+00f, 1.074967700e+00f }; static const ALuint ChansPerOrder[MAX_AMBI_ORDER+1]{ 1, 3, 5, 7 }; - const float *AmbiOrderHFGain{AmbiOrderHFGain1O}; - static_assert(al::size(AmbiPoints) == al::size(AmbiMatrix), "Ambisonic HRTF mismatch"); + static_assert(al::size(AmbiPoints1O) == al::size(AmbiMatrix1O), "First-Order Ambisonic HRTF mismatch"); + static_assert(al::size(AmbiPoints2O) == al::size(AmbiMatrix2O), "Second-Order Ambisonic HRTF mismatch"); /* Don't bother with HOA when using full HRTF rendering. Nothing needs it, * and it eases the CPU/memory load. @@ -637,10 +655,21 @@ void InitHrtfPanning(ALCdevice *device) (device->mRenderMode == HrtfRender) ? "+ Full " : "", device->HrtfName.c_str()); + al::span AmbiPoints{}; + const float (*AmbiMatrix)[MAX_AMBI_CHANNELS]{}; + const float *AmbiOrderHFGain{}; if(ambi_order >= 2) + { + AmbiPoints = AmbiPoints2O; + AmbiMatrix = AmbiMatrix2O; AmbiOrderHFGain = AmbiOrderHFGain2O; - else if(ambi_order == 1) + } + else /*if(ambi_order == 1)*/ + { + AmbiPoints = AmbiPoints1O; + AmbiMatrix = AmbiMatrix1O; AmbiOrderHFGain = AmbiOrderHFGain1O; + } device->mAmbiOrder = ambi_order; const size_t count{AmbiChannelsFromOrder(ambi_order)}; -- cgit v1.2.3 From f2eab3e919aa06b72ad467118db3269fe2571bbb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Nov 2019 14:22:04 -0800 Subject: Properly get the AppData path on Windows in alsoft-config --- utils/alsoft-config/mainwindow.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 7b1d8a91..fed9de59 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -14,6 +14,11 @@ #include "ui_mainwindow.h" #include "verstr.h" +#ifdef _WIN32 +#include +#include +#endif + namespace { static const struct { @@ -139,7 +144,14 @@ static QString getDefaultConfigName() { #ifdef Q_OS_WIN32 static const char fname[] = "alsoft.ini"; - QByteArray base = qgetenv("AppData"); + auto get_appdata_path = []() noexcept -> QString + { + WCHAR buffer[MAX_PATH]; + if(SHGetSpecialFolderPathW(nullptr, buffer, CSIDL_APPDATA, FALSE) != FALSE) + return QString::fromWCharArray(buffer); + return QString(); + }; + QString base = get_appdata_path(); #else static const char fname[] = "alsoft.conf"; QByteArray base = qgetenv("XDG_CONFIG_HOME"); @@ -158,7 +170,14 @@ static QString getDefaultConfigName() static QString getBaseDataPath() { #ifdef Q_OS_WIN32 - QByteArray base = qgetenv("AppData"); + auto get_appdata_path = []() noexcept -> QString + { + WCHAR buffer[MAX_PATH]; + if(SHGetSpecialFolderPathW(nullptr, buffer, CSIDL_APPDATA, FALSE) != FALSE) + return QString::fromWCharArray(buffer); + return QString(); + }; + QString base = get_appdata_path(); #else QByteArray base = qgetenv("XDG_DATA_HOME"); if(base.isEmpty()) -- cgit v1.2.3 From 7bc4a27900512749a1b774524dbab5be1e0515ca Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 21 Nov 2019 02:43:34 -0800 Subject: Allocate storage for full HRTF coefficient lengths --- alc/hrtf.cpp | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index 2137723d..0f808466 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -264,16 +264,16 @@ void GetHrtfCoeffs(const HrtfEntry *Hrtf, ALfloat elevation, ALfloat azimuth, AL ASSUME(irSize >= MIN_IR_SIZE); /* Calculate the sample offsets for the HRIR indices. */ - idx[0] *= irSize; - idx[1] *= irSize; - idx[2] *= irSize; - idx[3] *= irSize; + idx[0] *= HRIR_LENGTH; + idx[1] *= HRIR_LENGTH; + idx[2] *= HRIR_LENGTH; + idx[3] *= HRIR_LENGTH; /* Calculate the blended HRIR coefficients. */ ALfloat *coeffout{al::assume_aligned<16>(&coeffs[0][0])}; coeffout[0] = PassthruCoeff * (1.0f-dirfact); coeffout[1] = PassthruCoeff * (1.0f-dirfact); - std::fill(coeffout+2, coeffout + irSize*2, 0.0f); + std::fill(coeffout+2, coeffout + HRIR_LENGTH*2, 0.0f); for(ALsizei c{0};c < 4;c++) { const ALfloat *srccoeffs{al::assume_aligned<16>(Hrtf->coeffs[idx[c]])}; @@ -358,7 +358,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, std::fill(coeffout, coeffout + HRIR_LENGTH*2, 0.0); for(ALsizei c{0};c < 4;c++) { - const ALfloat *srccoeffs{al::assume_aligned<16>(Hrtf->coeffs[idx[c]*irSize])}; + const ALfloat *srccoeffs{al::assume_aligned<16>(Hrtf->coeffs[idx[c]*HRIR_LENGTH])}; const ALfloat mult{blend[c]}; auto blend_coeffs = [mult](const float src, const double coeff) noexcept -> double { return src*mult + coeff; }; @@ -504,7 +504,7 @@ std::unique_ptr CreateHrtfStore(ALuint rate, ALushort irSize, const A total = RoundUp(total, alignof(HrtfEntry::Elevation)); /* Align for elevation infos */ total += sizeof(Hrtf->elev[0])*evTotal; total = RoundUp(total, 16); /* Align for coefficients using SIMD */ - total += sizeof(Hrtf->coeffs[0])*irSize*irCount; + total += sizeof(Hrtf->coeffs[0])*HRIR_LENGTH*irCount; total += sizeof(Hrtf->delays[0])*irCount; Hrtf.reset(new (al_calloc(16, total)) HrtfEntry{}); @@ -531,7 +531,7 @@ std::unique_ptr CreateHrtfStore(ALuint rate, ALushort irSize, const A offset = RoundUp(offset, 16); /* Align for coefficients using SIMD */ auto coeffs_ = reinterpret_cast(base + offset); - offset += sizeof(coeffs_[0])*irSize*irCount; + offset += sizeof(coeffs_[0])*HRIR_LENGTH*irCount; auto delays_ = reinterpret_cast(base + offset); offset += sizeof(delays_[0])*irCount; @@ -549,10 +549,18 @@ std::unique_ptr CreateHrtfStore(ALuint rate, ALushort irSize, const A elev_[i].azCount = azCount[i]; elev_[i].irOffset = irOffset[i]; } - for(ALuint i{0};i < ALuint{irSize}*irCount;i++) + for(ALuint i{0};i < irCount;i++) { - coeffs_[i][0] = coeffs[i][0]; - coeffs_[i][1] = coeffs[i][1]; + for(ALuint j{0};j < ALuint{irSize};j++) + { + coeffs_[i*HRIR_LENGTH + j][0] = coeffs[i*irSize + j][0]; + coeffs_[i*HRIR_LENGTH + j][1] = coeffs[i*irSize + j][1]; + } + for(ALuint j{irSize};j < HRIR_LENGTH;j++) + { + coeffs_[i*HRIR_LENGTH + j][0] = 0.0f; + coeffs_[i*HRIR_LENGTH + j][1] = 0.0f; + } } for(ALuint i{0};i < irCount;i++) { -- cgit v1.2.3 From 2fd8c619b34127d7594d6c7510f7c77ebb5f3a10 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 21 Nov 2019 02:58:35 -0800 Subject: Rename a couple struct fields --- alc/hrtf.cpp | 46 ++++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index 0f808466..add0fb69 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -55,17 +55,15 @@ struct HrtfHandle { - std::unique_ptr entry; - al::FlexArray filename; + std::unique_ptr mEntry; + al::FlexArray mFilename; - HrtfHandle(size_t fname_len) : filename{fname_len} { } - HrtfHandle(const HrtfHandle&) = delete; - HrtfHandle& operator=(const HrtfHandle&) = delete; + HrtfHandle(size_t fname_len) : mFilename{fname_len} { } static std::unique_ptr Create(size_t fname_len) { return std::unique_ptr{new (FamCount{fname_len}) HrtfHandle{fname_len}}; } - DEF_FAM_NEWDEL(HrtfHandle, filename) + DEF_FAM_NEWDEL(HrtfHandle, mFilename) }; namespace { @@ -1120,7 +1118,7 @@ void AddFileEntry(al::vector &list, const std::string &filename) auto loaded_entry = LoadedHrtfs.begin(); for(;loaded_entry != LoadedHrtfs.end();++loaded_entry) { - if(filename != (*loaded_entry)->filename.data()) + if(filename != (*loaded_entry)->mFilename.data()) continue; /* Check if this entry has already been added to the list. */ @@ -1144,8 +1142,8 @@ void AddFileEntry(al::vector &list, const std::string &filename) LoadedHrtfs.emplace_back(HrtfHandle::Create(filename.length()+1)); loaded_entry = LoadedHrtfs.end()-1; - std::copy(filename.begin(), filename.end(), (*loaded_entry)->filename.begin()); - (*loaded_entry)->filename.back() = '\0'; + std::copy(filename.begin(), filename.end(), (*loaded_entry)->mFilename.begin()); + (*loaded_entry)->mFilename.back() = '\0'; } /* TODO: Get a human-readable name from the HRTF data (possibly coming in a @@ -1180,7 +1178,7 @@ void AddBuiltInEntry(al::vector &list, const std::string &filena auto loaded_entry = LoadedHrtfs.begin(); for(;loaded_entry != LoadedHrtfs.end();++loaded_entry) { - if(filename != (*loaded_entry)->filename.data()) + if(filename != (*loaded_entry)->mFilename.data()) continue; /* Check if this entry has already been added to the list. */ @@ -1204,7 +1202,7 @@ void AddBuiltInEntry(al::vector &list, const std::string &filena LoadedHrtfs.emplace_back(HrtfHandle::Create(filename.length()+32)); loaded_entry = LoadedHrtfs.end()-1; - snprintf((*loaded_entry)->filename.data(), (*loaded_entry)->filename.size(), "!%u_%s", + snprintf((*loaded_entry)->mFilename.data(), (*loaded_entry)->mFilename.size(), "!%u_%s", residx, filename.c_str()); } @@ -1322,9 +1320,9 @@ HrtfEntry *GetLoadedHrtf(HrtfHandle *handle) { std::lock_guard _{LoadedHrtfLock}; - if(handle->entry) + if(handle->mEntry) { - HrtfEntry *hrtf{handle->entry.get()}; + HrtfEntry *hrtf{handle->mEntry.get()}; hrtf->IncRef(); return hrtf; } @@ -1333,9 +1331,9 @@ HrtfEntry *GetLoadedHrtf(HrtfHandle *handle) const char *name{""}; ALint residx{}; char ch{}; - if(sscanf(handle->filename.data(), "!%d%c", &residx, &ch) == 2 && ch == '_') + if(sscanf(handle->mFilename.data(), "!%d%c", &residx, &ch) == 2 && ch == '_') { - name = strchr(handle->filename.data(), ch)+1; + name = strchr(handle->mFilename.data(), ch)+1; TRACE("Loading %s...\n", name); ResData res{GetResource(residx)}; @@ -1348,13 +1346,13 @@ HrtfEntry *GetLoadedHrtf(HrtfHandle *handle) } else { - name = handle->filename.data(); + name = handle->mFilename.data(); - TRACE("Loading %s...\n", handle->filename.data()); - auto fstr = al::make_unique(handle->filename.data(), std::ios::binary); + TRACE("Loading %s...\n", handle->mFilename.data()); + auto fstr = al::make_unique(handle->mFilename.data(), std::ios::binary); if(!fstr->is_open()) { - ERR("Could not open %s\n", handle->filename.data()); + ERR("Could not open %s\n", handle->mFilename.data()); return nullptr; } stream = std::move(fstr); @@ -1391,9 +1389,9 @@ HrtfEntry *GetLoadedHrtf(HrtfHandle *handle) } TRACE("Loaded HRTF support for sample rate: %uhz\n", hrtf->sampleRate); - handle->entry = std::move(hrtf); + handle->mEntry = std::move(hrtf); - return handle->entry.get(); + return handle->mEntry.get(); } @@ -1414,11 +1412,11 @@ void HrtfEntry::DecRef() /* Go through and clear all unused HRTFs. */ auto delete_unused = [](HrtfHandlePtr &handle) -> void { - HrtfEntry *entry{handle->entry.get()}; + HrtfEntry *entry{handle->mEntry.get()}; if(entry && ReadRef(entry->mRef) == 0) { - TRACE("Unloading unused HRTF %s\n", handle->filename.data()); - handle->entry = nullptr; + TRACE("Unloading unused HRTF %s\n", handle->mFilename.data()); + handle->mEntry = nullptr; } }; std::for_each(LoadedHrtfs.begin(), LoadedHrtfs.end(), delete_unused); -- cgit v1.2.3 From eb8922596aa3a3a0eee62417c4b663f58444f136 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 21 Nov 2019 23:55:10 -0800 Subject: Apply the full HRIR length for the B-Format decoder --- alc/hrtf.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/alc/hrtf.cpp b/alc/hrtf.cpp index add0fb69..8e416cf1 100644 --- a/alc/hrtf.cpp +++ b/alc/hrtf.cpp @@ -360,7 +360,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALfloat mult{blend[c]}; auto blend_coeffs = [mult](const float src, const double coeff) noexcept -> double { return src*mult + coeff; }; - std::transform(srccoeffs, srccoeffs + irSize*2, coeffout, coeffout, blend_coeffs); + std::transform(srccoeffs, srccoeffs + HRIR_LENGTH*2, coeffout, coeffout, blend_coeffs); } min_delay = minu(min_delay, minu(res.ldelay, res.rdelay)); @@ -391,7 +391,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, for(size_t i{0u};i < state->Coeffs.size();++i) { const double mult{double{AmbiOrderHFGain[OrderFromChan[i]]} * AmbiMatrix[c][i]}; - const ALuint numirs{minu(Hrtf->irSize, HRIR_LENGTH-maxu(ldelay, rdelay))}; + const ALuint numirs{HRIR_LENGTH - maxu(ldelay, rdelay)}; ALuint lidx{ldelay}, ridx{rdelay}; for(ALuint j{0};j < numirs;++j) { @@ -410,7 +410,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, /* Load the (left) HRIR backwards, into a temp buffer with padding. */ std::fill(tmpflt[2].begin(), tmpflt[2].end(), 0.0); - std::transform(hrir.begin(), hrir.begin()+Hrtf->irSize, tmpflt[2].rbegin() + HRIR_LENGTH*3, + std::transform(hrir.cbegin(), hrir.cend(), tmpflt[2].rbegin() + HRIR_LENGTH*3, [](const double2 &ir) noexcept -> double { return ir[0]; }); /* Apply the all-pass on the reversed signal and reverse the resulting @@ -439,7 +439,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, /* Now run the same process on the right HRIR. */ std::fill(tmpflt[2].begin(), tmpflt[2].end(), 0.0); - std::transform(hrir.begin(), hrir.begin()+Hrtf->irSize, tmpflt[2].rbegin() + HRIR_LENGTH*3, + std::transform(hrir.cbegin(), hrir.cend(), tmpflt[2].rbegin() + HRIR_LENGTH*3, [](const double2 &ir) noexcept -> double { return ir[1]; }); splitter.applyAllpass(tmpflt[2].data(), tmpflt[2].size()); @@ -464,7 +464,7 @@ void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, { auto copy_arr = [](const double2 &in) noexcept -> float2 { return float2{{static_cast(in[0]), static_cast(in[1])}}; }; - std::transform(tmpres[i].begin(), tmpres[i].end(), state->Coeffs[i].begin(), + std::transform(tmpres[i].cbegin(), tmpres[i].cend(), state->Coeffs[i].begin(), copy_arr); } tmpres.clear(); -- cgit v1.2.3 From 39e3484dbe8d0608a960a88d57d8dd2f47070b19 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 22 Nov 2019 22:47:36 -0800 Subject: Update ChangeLog --- ChangeLog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0582a5fc..db9ebd92 100644 --- a/ChangeLog +++ b/ChangeLog @@ -52,8 +52,8 @@ openal-soft-1.20.0: Added basic support for multi-field HRTFs. - Added an option for mixing first-, second-, or third-order B-Format with - HRTF output. This can improve HRTF performance given a number of sources. + Added an option for mixing first- or second-order B-Format with HRTF + output. This can improve HRTF performance given a number of sources. Added an RC file for proper DLL version information. -- cgit v1.2.3 From c0cf323e1d56ce605e90927324d2fdafcfbb564a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 28 Nov 2019 00:45:08 -0800 Subject: Release 1.20.0 --- CMakeLists.txt | 4 ++-- appveyor.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9cc0c6fd..98f9ad49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,8 +114,8 @@ IF(NOT LIBTYPE) ENDIF() SET(LIB_MAJOR_VERSION "1") -SET(LIB_MINOR_VERSION "19") -SET(LIB_REVISION "1") +SET(LIB_MINOR_VERSION "20") +SET(LIB_REVISION "0") SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_REVISION}") SET(LIB_VERSION_NUM ${LIB_MAJOR_VERSION},${LIB_MINOR_VERSION},${LIB_REVISION},0) diff --git a/appveyor.yml b/appveyor.yml index e9c52519..81080828 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 1.19.1.{build} +version: 1.20.0.{build} environment: matrix: -- cgit v1.2.3